summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2017-09-26 19:56:36 +0000
committerLuiz Souza <luiz@netgate.com>2018-02-21 15:12:19 -0300
commit1dcd2e8d24b295bc73e513acec2ed1514bb66be4 (patch)
tree4bd13a34c251e980e1a6b13584ca1f63b0dfe670 /contrib/llvm/tools
parentf45541ca2a56a1ba1202f94c080b04e96c1fa239 (diff)
downloadFreeBSD-src-1dcd2e8d24b295bc73e513acec2ed1514bb66be4.zip
FreeBSD-src-1dcd2e8d24b295bc73e513acec2ed1514bb66be4.tar.gz
Merge clang, llvm, lld, lldb, compiler-rt and libc++ 5.0.0 release.
MFC r309126 (by emaste): Correct lld llvm-tblgen dependency file name MFC r309169: Get rid of separate Subversion mergeinfo properties for llvm-dwarfdump and llvm-lto. The mergeinfo confuses Subversion enormously, and these directories will just use the mergeinfo for llvm itself. MFC r312765: Pull in r276136 from upstream llvm trunk (by Wei Mi): Use ValueOffsetPair to enhance value reuse during SCEV expansion. In D12090, the ExprValueMap was added to reuse existing value during SCEV expansion. However, const folding and sext/zext distribution can make the reuse still difficult. A simplified case is: suppose we know S1 expands to V1 in ExprValueMap, and S1 = S2 + C_a S3 = S2 + C_b where C_a and C_b are different SCEVConstants. Then we'd like to expand S3 as V1 - C_a + C_b instead of expanding S2 literally. It is helpful when S2 is a complex SCEV expr and S2 has no entry in ExprValueMap, which is usually caused by the fact that S3 is generated from S1 after const folding. In order to do that, we represent ExprValueMap as a mapping from SCEV to ValueOffsetPair. We will save both S1->{V1, 0} and S2->{V1, C_a} into the ExprValueMap when we create SCEV for V1. When S3 is expanded, it will first expand S2 to V1 - C_a because of S2->{V1, C_a} in the map, then expand S3 to V1 - C_a + C_b. Differential Revision: https://reviews.llvm.org/D21313 This should fix assertion failures when building OpenCV >= 3.1. PR: 215649 MFC r312831: Revert r312765 for now, since it causes assertions when building lang/spidermonkey24. Reported by: antoine PR: 215649 MFC r316511 (by jhb): Add an implementation of __ffssi2() derived from __ffsdi2(). Newer versions of GCC include an __ffssi2() symbol in libgcc and the compiler can emit calls to it in generated code. This is true for at least GCC 6.2 when compiling world for mips and mips64. Reviewed by: jmallett, dim Sponsored by: DARPA / AFRL Differential Revision: https://reviews.freebsd.org/D10086 MFC r318601 (by adrian): [libcompiler-rt] add bswapdi2/bswapsi2 This is required for mips gcc 6.3 userland to build/run. Reviewed by: emaste, dim Approved by: emaste Differential Revision: https://reviews.freebsd.org/D10838 MFC r318884 (by emaste): lldb: map TRAP_CAP to a trace trap In the absense of a more specific handler for TRAP_CAP (generated by ENOTCAPABLE or ECAPMODE while in capability mode) treat it as a trace trap. Example usage (testing the bug in PR219173): % proccontrol -m trapcap lldb usr.bin/hexdump/obj/hexdump -- -Cv -s 1 /bin/ls ... (lldb) run Process 12980 launching Process 12980 launched: '.../usr.bin/hexdump/obj/hexdump' (x86_64) Process 12980 stopped * thread #1, stop reason = trace frame #0: 0x0000004b80c65f1a libc.so.7`__sys_lseek + 10 ... In the future we should have LLDB control the trapcap procctl itself (as it does with ASLR), as well as report a specific stop reason. This change eliminates an assertion failure from LLDB for now. MFC r319796: Remove a few unneeded files from libllvm, libclang and liblldb. MFC r319885 (by emaste): lld: ELF: Fix ICF crash on absolute symbol relocations. If two sections contained relocations to absolute symbols with the same value we would crash when trying to access their sections. Add a check that both symbols point to sections before accessing their sections, and treat absolute symbols as equal if their values are equal. Obtained from: LLD commit r292578 MFC r319918: Revert r319796 for now, it can cause undefined references when linking in some circumstances. Reported by: Shawn Webb <shawn.webb@hardenedbsd.org> MFC r319957 (by emaste): lld: Add armelf emulation mode Obtained from: LLD r305375 MFC r321369: Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to 5.0.0 (trunk r308421). Upstream has branched for the 5.0.0 release, which should be in about a month. Please report bugs and regressions, so we can get them into the release. Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11 support to build; see UPDATING for more information. MFC r321420: Add a few more object files to liblldb, which should solve errors when linking the lldb executable in some cases. In particular, when the -ffunction-sections -fdata-sections options are turned off, or ineffective. Reported by: Shawn Webb, Mark Millard MFC r321433: Cleanup stale Options.inc files from the previous libllvm build for clang 4.0.0. Otherwise, these can get included before the two newly generated ones (which are different) for clang 5.0.0. Reported by: Mark Millard MFC r321439 (by bdrewery): Move llvm Options.inc hack from r321433 for NO_CLEAN to lib/clang/libllvm. The files are only ever generated to .OBJDIR, not to WORLDTMP (as a sysroot) and are only ever included from a compilation. So using a beforebuild target here removes the file before the compilation tries to include it. MFC r321664: Pull in r308891 from upstream llvm trunk (by Benjamin Kramer): [CodeGenPrepare] Cut off FindAllMemoryUses if there are too many uses. This avoids excessive compile time. The case I'm looking at is Function.cpp from an old version of LLVM that still had the giant memcmp string matcher in it. Before r308322 this compiled in about 2 minutes, after it, clang takes infinite* time to compile it. With this patch we're at 5 min, which is still bad but this is a pathological case. The cut off at 20 uses was chosen by looking at other cut-offs in LLVM for user scanning. It's probably too high, but does the job and is very unlikely to regress anything. Fixes PR33900. * I'm impatient and aborted after 15 minutes, on the bug report it was killed after 2h. Pull in r308986 from upstream llvm trunk (by Simon Pilgrim): [X86][CGP] Reduce memcmp() expansion to 2 load pairs (PR33914) D35067/rL308322 attempted to support up to 4 load pairs for memcmp inlining which resulted in regressions for some optimized libc memcmp implementations (PR33914). Until we can match these more optimal cases, this patch reduces the memcmp expansion to a maximum of 2 load pairs (which matches what we do for -Os). This patch should be considered for the 5.0.0 release branch as well Differential Revision: https://reviews.llvm.org/D35830 These fix a hang (or extremely long compile time) when building older LLVM ports. Reported by: antoine PR: 219139 MFC r321719: Pull in r309503 from upstream clang trunk (by Richard Smith): PR33902: Invalidate line number cache when adding more text to existing buffer. This led to crashes as the line number cache would report a bogus line number for a line of code, and we'd try to find a nonexistent column within the line when printing diagnostics. This fixes an assertion when building the graphics/champlain port. Reported by: antoine, kwm PR: 219139 MFC r321723: Upgrade our copies of clang, llvm, lld and lldb to r309439 from the upstream release_50 branch. This is just after upstream's 5.0.0-rc1. MFC r322320: Upgrade our copies of clang, llvm and libc++ to r310316 from the upstream release_50 branch. MFC r322326 (by emaste): lldb: Make i386-*-freebsd expression work on JIT path * Enable i386 ABI creation for freebsd * Added an extra argument in ABISysV_i386::PrepareTrivialCall for mmap syscall * Unlike linux, the last argument of mmap is actually 64-bit(off_t). This requires us to push an additional word for the higher order bits. * Prior to this change, ktrace dump will show mmap failures due to invalid argument coming from the 6th mmap argument. Submitted by: Karnajit Wangkhem Differential Revision: https://reviews.llvm.org/D34776 MFC r322360 (by emaste): lldb: Report inferior signals as signals, not exceptions, on FreeBSD This is the FreeBSD equivalent of LLVM r238549. This serves 2 purposes: * LLDB should handle inferior process signals SIGSEGV/SIGILL/SIGBUS/ SIGFPE the way it is suppose to be handled. Prior to this fix these signals will neither create a coredump, nor exit from the debugger or work for signal handling scenario. * eInvalidCrashReason need not report "unknown crash reason" if we have a valid si_signo llvm.org/pr23699 Patch by Karnajit Wangkhem Differential Revision: https://reviews.llvm.org/D35223 Submitted by: Karnajit Wangkhem Obtained from: LLVM r310591 MFC r322474 (by emaste): lld: Add `-z muldefs` option. Obtained from: LLVM r310757 MFC r322740: Upgrade our copies of clang, llvm, lld and libc++ to r311219 from the upstream release_50 branch. MFC r322855: Upgrade our copies of clang, llvm, lldb and compiler-rt to r311606 from the upstream release_50 branch. As of this version, lib/msun's trig test should also work correctly again (see bug 220989 for more information). PR: 220989 MFC r323112: Upgrade our copies of clang, llvm, lldb and compiler-rt to r312293 from the upstream release_50 branch. This corresponds to 5.0.0 rc4. As of this version, the cad/stepcode port should now compile in a more reasonable time on i386 (see bug 221836 for more information). PR: 221836 MFC r323245: Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to 5.0.0 release (upstream r312559). Release notes for llvm, clang and lld will be available here soon: <http://releases.llvm.org/5.0.0/docs/ReleaseNotes.html> <http://releases.llvm.org/5.0.0/tools/clang/docs/ReleaseNotes.html> <http://releases.llvm.org/5.0.0/tools/lld/docs/ReleaseNotes.html> Relnotes: yes (cherry picked from commit 12cd91cf4c6b96a24427c0de5374916f2808d263)
Diffstat (limited to 'contrib/llvm/tools')
-rw-r--r--contrib/llvm/tools/bugpoint/CrashDebugger.cpp8
-rw-r--r--contrib/llvm/tools/bugpoint/ExtractFunction.cpp4
-rw-r--r--contrib/llvm/tools/bugpoint/FindBugs.cpp6
-rw-r--r--contrib/llvm/tools/bugpoint/ListReducer.h5
-rw-r--r--contrib/llvm/tools/bugpoint/Miscompilation.cpp25
-rw-r--r--contrib/llvm/tools/bugpoint/OptimizerDriver.cpp16
-rw-r--r--contrib/llvm/tools/bugpoint/ToolRunner.cpp69
-rw-r--r--contrib/llvm/tools/bugpoint/bugpoint.cpp11
-rw-r--r--contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang-c/Index.h238
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ASTContext.h235
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ASTStructuralEquivalence.h103
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ASTVector.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def3
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h9
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/CommentSema.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Decl.h147
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclBase.h189
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h263
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h82
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h136
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h43
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Expr.h179
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h95
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ExternalASTMerger.h51
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h11
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/NSAPI.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ODRHash.h84
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h314
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h90
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h54
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Stmt.h25
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h122
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h16
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h266
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h12
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Type.h260
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h53
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def4
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/TypeOrdering.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h22
-rw-r--r--contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h145
-rw-r--r--contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h31
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/CFG.h45
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h558
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h27
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Attr.td310
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td320
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/AttrSubjectMatchRules.h32
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Builtins.def50
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def19
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def92
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def24
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNios2.def70
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsPPC.def11
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsSystemZ.def24
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsWebAssembly.def10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def94
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td1
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h201
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td12
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td14
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td12
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td29
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td3
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td47
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h40
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td42
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.def2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h8
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td137
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td536
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td138
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h31
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def14
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h58
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Linkage.h24
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/MemoryBufferCache.h80
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Module.h44
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/ObjCRuntime.h14
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/OpenCLImageTypes.def2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h9
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def15
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h125
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h70
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h7
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td3
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h47
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TemplateKinds.h14
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def8
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Visibility.h3
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/XRayLists.h55
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td2
-rw-r--r--contrib/llvm/tools/clang/include/clang/CodeGen/BackendUtil.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h17
-rw-r--r--contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h35
-rw-r--r--contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitBuilder.h561
-rw-r--r--contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitFuture.h111
-rw-r--r--contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td68
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td17
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/ClangOptionDocs.td36
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Compilation.h8
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Distro.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Driver.h23
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Job.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Multilib.h9
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Options.h12
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Options.td534
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Tool.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h20
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/XRayArgs.h38
-rw-r--r--contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h23
-rw-r--r--contrib/llvm/tools/clang/include/clang/Format/Format.h937
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/ASTConsumers.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h226
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def34
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h43
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h26
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h83
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h11
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h22
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h96
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h34
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def165
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/PCHContainerOperations.h3
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h248
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h43
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/Utils.h9
-rw-r--r--contrib/llvm/tools/clang/include/clang/Index/IndexSymbol.h13
-rw-r--r--contrib/llvm/tools/clang/include/clang/Index/IndexingAction.h16
-rw-r--r--contrib/llvm/tools/clang/include/clang/Index/USRGeneration.h21
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h24
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/Lexer.h7
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h16
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h75
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h34
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h68
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h16
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h3
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h183
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h22
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/Token.h8
-rw-r--r--contrib/llvm/tools/clang/include/clang/Parse/Parser.h124
-rw-r--r--contrib/llvm/tools/clang/include/clang/Parse/RAIIObjectsForParser.h (renamed from contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h)20
-rw-r--r--contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FrontendActions.h7
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h96
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h14
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h16
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Initialization.h40
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Lookup.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/MultiplexExternalSemaSource.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Overload.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Ownership.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h69
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h83
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Sema.h665
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Template.h34
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h65
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h130
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h40
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/Module.h114
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h34
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td34
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def1
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h22
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h16
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h12
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h17
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h16
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h21
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h283
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h22
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h12
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h59
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h92
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h31
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h64
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/ArgumentsAdjusters.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h17
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/Core/Diagnostic.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/DiagnosticsYaml.h15
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/FixIt.h7
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/AtomicChange.h135
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h122
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h70
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFinder.h50
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h54
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h49
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/RefactoringCallbacks.h50
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h14
-rw-r--r--contrib/llvm/tools/clang/include/clang/module.modulemap3
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ASTContext.cpp263
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp75
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp1617
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp1362
-rw-r--r--contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp126
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Comment.cpp20
-rw-r--r--contrib/llvm/tools/clang/lib/AST/CommentSema.cpp34
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Decl.cpp228
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclBase.cpp84
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp224
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp51
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp42
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp37
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp105
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Expr.cpp60
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp14
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp357
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp182
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp65
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Mangle.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp136
-rw-r--r--contrib/llvm/tools/clang/lib/AST/NSAPI.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ODRHash.cpp636
-rw-r--r--contrib/llvm/tools/clang/lib/AST/OpenMPClause.cpp69
-rw-r--r--contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp35
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Stmt.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/AST/StmtCXX.cpp43
-rw-r--r--contrib/llvm/tools/clang/lib/AST/StmtOpenMP.cpp103
-rw-r--r--contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp32
-rw-r--r--contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp276
-rw-r--r--contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Type.cpp174
-rw-r--r--contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp115
-rw-r--r--contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h20
-rw-r--r--contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp63
-rw-r--r--contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp37
-rw-r--r--contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp64
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/CFG.cpp224
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp1078
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/OSLog.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp19
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Attributes.cpp11
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp191
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp43
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/FileManager.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp22
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/MemoryBufferCache.cpp48
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Module.cpp87
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp95
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp70
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp223
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp12
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Targets.cpp1441
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Version.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp24
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/XRayLists.cpp55
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ABIInfo.h4
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp534
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp28
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp512
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp659
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp39
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h27
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp669
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCall.h49
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp143
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp53
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp590
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp385
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h74
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp143
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp15
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp43
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp765
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp29
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp62
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp16
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp16
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp479
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGGPUBuiltin.cpp (renamed from contrib/llvm/tools/clang/lib/CodeGen/CGCUDABuiltin.cpp)13
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp157
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp140
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp309
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp60
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp1305
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h253
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp1698
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h128
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp24
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp1469
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp25
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGValue.h51
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp16
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp312
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp165
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h440
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp464
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h120
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp39
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.h10
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h10
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp10
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h8
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h444
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ConstantInitBuilder.cpp280
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp10
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/EHScopeStack.h2
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp177
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp208
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h117
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp168
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp10
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp12
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp478
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h29
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Compilation.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp125
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Distro.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Driver.cpp300
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp12
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Job.cpp28
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp892
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/MinGWToolChain.cpp257
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Multilib.cpp10
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp141
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp35
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp5342
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains.h1388
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.cpp45
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.h54
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/AVR.cpp44
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/AVR.h49
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp120
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.h67
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp199
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.h35
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp557
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.h60
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.cpp407
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.h62
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp131
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.h45
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Sparc.cpp100
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Sparc.h42
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp41
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/SystemZ.h32
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.cpp173
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.h37
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.cpp211
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.h91
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.cpp190
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.h79
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp5271
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.h149
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.cpp145
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.h69
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp1025
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.h98
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Contiki.cpp28
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Contiki.h38
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.cpp315
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.h88
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.cpp513
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.h178
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.cpp2033
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.h499
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.cpp197
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.h68
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.cpp395
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.h86
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.cpp286
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.h92
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp2480
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.h352
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Haiku.cpp33
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Haiku.h40
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.cpp492
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.h104
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Lanai.h39
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp860
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.h57
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.cpp1463
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.h146
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVCSetupApi.h514
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.cpp473
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.h103
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.cpp109
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.h66
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/MipsLinux.cpp128
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/MipsLinux.h62
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Myriad.cpp289
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Myriad.h102
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.cpp363
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.h87
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.cpp425
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.h83
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp236
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h76
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.cpp419
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.h93
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.cpp193
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.h75
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/TCE.cpp47
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/TCE.h47
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp168
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.h78
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/XCore.cpp150
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains/XCore.h83
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Tools.cpp12226
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Tools.h1010
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/XRayArgs.cpp114
-rw-r--r--contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp62
-rw-r--r--contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Format/BreakableToken.cpp758
-rw-r--r--contrib/llvm/tools/clang/lib/Format/BreakableToken.h362
-rw-r--r--contrib/llvm/tools/clang/lib/Format/Comments.cpp36
-rw-r--r--contrib/llvm/tools/clang/lib/Format/Comments.h33
-rw-r--r--contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp387
-rw-r--r--contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.h19
-rw-r--r--contrib/llvm/tools/clang/lib/Format/Format.cpp297
-rw-r--r--contrib/llvm/tools/clang/lib/Format/FormatToken.h70
-rw-r--r--contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.cpp51
-rw-r--r--contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.h1
-rw-r--r--contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.cpp207
-rw-r--r--contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.h37
-rw-r--r--contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp444
-rw-r--r--contrib/llvm/tools/clang/lib/Format/TokenAnnotator.h4
-rw-r--r--contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp163
-rw-r--r--contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.h17
-rw-r--r--contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp419
-rw-r--r--contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.h38
-rw-r--r--contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp144
-rw-r--r--contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h37
-rw-r--r--contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp350
-rw-r--r--contrib/llvm/tools/clang/lib/Format/WhitespaceManager.h47
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp41
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp11
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp1083
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp357
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp679
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp196
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp532
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp313
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp36
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp48
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp563
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp154
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp131
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp68
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp18
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp108
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp330
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/altivec.h155
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/arm_acle.h318
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avx2intrin.h3
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avx512bwintrin.h104
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avx512dqintrin.h95
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h369
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avx512vldqintrin.h42
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avx512vlintrin.h45
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avx512vpopcntdqintrin.h70
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avxintrin.h546
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/bmiintrin.h176
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/clzerointrin.h50
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/cpuid.h118
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/emmintrin.h365
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/f16cintrin.h10
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/float.h9
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/htmxlintrin.h14
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/immintrin.h22
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/intrin.h56
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/lwpintrin.h150
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/mmintrin.h105
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/module.modulemap1
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/opencl-c.h898
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/pmmintrin.h20
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/prfchwintrin.h26
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/smmintrin.h1960
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/stdarg.h3
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/stdatomic.h20
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/stdint.h29
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/tgmath.h16
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/tmmintrin.h88
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/vecintrin.h1572
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/x86intrin.h8
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/xmmintrin.h71
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/xopintrin.h4
-rw-r--r--contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Index/IndexBody.cpp102
-rw-r--r--contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp390
-rw-r--r--contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp86
-rw-r--r--contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp69
-rw-r--r--contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp29
-rw-r--r--contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp171
-rw-r--r--contrib/llvm/tools/clang/lib/Index/IndexingContext.h10
-rw-r--r--contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp143
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp47
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/Lexer.cpp199
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp20
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp26
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp23
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp582
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp30
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp395
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp84
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp181
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp18
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/Pragma.cpp306
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp48
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/ScratchBuffer.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp42
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp48
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp452
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp284
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp161
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp152
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp119
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp76
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp785
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp32
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp19
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp100
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp46
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/Parser.cpp153
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp200
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp21
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/CoroutineStmtBuilder.h73
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp19
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/Sema.cpp178
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp260
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp20
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp37
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp146
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp506
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp316
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp1175
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp1421
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp874
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp1429
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp131
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp938
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp521
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp56
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp140
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp397
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp89
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp421
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp238
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp1427
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp750
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp42
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp301
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp27
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp1321
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp504
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp327
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp332
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaType.cpp394
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/TreeTransform.h630
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp1914
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp427
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp130
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp651
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp37
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp86
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp76
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/Module.cpp22
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp255
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp49
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp46
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp70
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp18
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp61
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp32
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp76
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp14
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp105
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp42
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp88
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp833
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp842
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp112
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp172
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp221
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp481
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp146
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp94
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SelectorExtras.h40
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp26
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp55
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp90
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp17
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp18
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp35
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp87
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp12
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp163
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp14
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp62
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp47
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp115
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp102
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp204
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.h (renamed from contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h)69
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp29
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp230
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp110
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp47
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp1618
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp10
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp23
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp50
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/JSONCompilationDatabase.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring.cpp15
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp177
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp134
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp146
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp236
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp451
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/RefactoringCallbacks.cpp154
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp23
-rw-r--r--contrib/llvm/tools/clang/tools/clang-format/ClangFormat.cpp55
-rw-r--r--contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp37
-rw-r--r--contrib/llvm/tools/clang/tools/driver/driver.cpp67
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp672
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp4
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/ClangOptionDocEmitter.cpp392
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/ClangSACheckersEmitter.cpp3
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp35
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h7
-rw-r--r--contrib/llvm/tools/llc/llc.cpp169
-rw-r--r--contrib/llvm/tools/lld/CMakeLists.txt69
-rw-r--r--contrib/llvm/tools/lld/COFF/CMakeLists.txt8
-rw-r--r--contrib/llvm/tools/lld/COFF/Chunks.cpp217
-rw-r--r--contrib/llvm/tools/lld/COFF/Chunks.h68
-rw-r--r--contrib/llvm/tools/lld/COFF/Config.h27
-rw-r--r--contrib/llvm/tools/lld/COFF/DLL.cpp155
-rw-r--r--contrib/llvm/tools/lld/COFF/DLL.h28
-rw-r--r--contrib/llvm/tools/lld/COFF/Driver.cpp476
-rw-r--r--contrib/llvm/tools/lld/COFF/Driver.h16
-rw-r--r--contrib/llvm/tools/lld/COFF/DriverUtils.cpp263
-rw-r--r--contrib/llvm/tools/lld/COFF/Error.cpp74
-rw-r--r--contrib/llvm/tools/lld/COFF/Error.h9
-rw-r--r--contrib/llvm/tools/lld/COFF/ICF.cpp90
-rw-r--r--contrib/llvm/tools/lld/COFF/InputFiles.cpp134
-rw-r--r--contrib/llvm/tools/lld/COFF/InputFiles.h43
-rw-r--r--contrib/llvm/tools/lld/COFF/LTO.cpp140
-rw-r--r--contrib/llvm/tools/lld/COFF/LTO.h56
-rw-r--r--contrib/llvm/tools/lld/COFF/Librarian.cpp494
-rw-r--r--contrib/llvm/tools/lld/COFF/MapFile.cpp125
-rw-r--r--contrib/llvm/tools/lld/COFF/MapFile.h22
-rw-r--r--contrib/llvm/tools/lld/COFF/MarkLive.cpp24
-rw-r--r--contrib/llvm/tools/lld/COFF/ModuleDef.cpp289
-rw-r--r--contrib/llvm/tools/lld/COFF/Options.td10
-rw-r--r--contrib/llvm/tools/lld/COFF/PDB.cpp683
-rw-r--r--contrib/llvm/tools/lld/COFF/PDB.h3
-rw-r--r--contrib/llvm/tools/lld/COFF/Strings.cpp5
-rw-r--r--contrib/llvm/tools/lld/COFF/SymbolTable.cpp183
-rw-r--r--contrib/llvm/tools/lld/COFF/SymbolTable.h25
-rw-r--r--contrib/llvm/tools/lld/COFF/Symbols.cpp32
-rw-r--r--contrib/llvm/tools/lld/COFF/Symbols.h157
-rw-r--r--contrib/llvm/tools/lld/COFF/Writer.cpp246
-rw-r--r--contrib/llvm/tools/lld/COFF/Writer.h51
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp376
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp84
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/ARM.cpp480
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/AVR.cpp80
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/Mips.cpp423
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp (renamed from contrib/llvm/tools/lld/ELF/Mips.cpp)10
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/PPC.cpp65
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp217
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp149
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/X86.cpp364
-rw-r--r--contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp473
-rw-r--r--contrib/llvm/tools/lld/ELF/CMakeLists.txt18
-rw-r--r--contrib/llvm/tools/lld/ELF/Config.h104
-rw-r--r--contrib/llvm/tools/lld/ELF/Driver.cpp675
-rw-r--r--contrib/llvm/tools/lld/ELF/Driver.h7
-rw-r--r--contrib/llvm/tools/lld/ELF/DriverUtils.cpp34
-rw-r--r--contrib/llvm/tools/lld/ELF/EhFrame.cpp32
-rw-r--r--contrib/llvm/tools/lld/ELF/EhFrame.h9
-rw-r--r--contrib/llvm/tools/lld/ELF/Error.cpp52
-rw-r--r--contrib/llvm/tools/lld/ELF/Error.h16
-rw-r--r--contrib/llvm/tools/lld/ELF/Filesystem.cpp77
-rw-r--r--contrib/llvm/tools/lld/ELF/Filesystem.h22
-rw-r--r--contrib/llvm/tools/lld/ELF/GdbIndex.cpp208
-rw-r--r--contrib/llvm/tools/lld/ELF/GdbIndex.h71
-rw-r--r--contrib/llvm/tools/lld/ELF/ICF.cpp166
-rw-r--r--contrib/llvm/tools/lld/ELF/ICF.h2
-rw-r--r--contrib/llvm/tools/lld/ELF/InputFiles.cpp607
-rw-r--r--contrib/llvm/tools/lld/ELF/InputFiles.h80
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.cpp809
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.h287
-rw-r--r--contrib/llvm/tools/lld/ELF/LTO.cpp73
-rw-r--r--contrib/llvm/tools/lld/ELF/LTO.h9
-rw-r--r--contrib/llvm/tools/lld/ELF/LinkerScript.cpp2359
-rw-r--r--contrib/llvm/tools/lld/ELF/LinkerScript.h246
-rw-r--r--contrib/llvm/tools/lld/ELF/MapFile.cpp150
-rw-r--r--contrib/llvm/tools/lld/ELF/MapFile.h23
-rw-r--r--contrib/llvm/tools/lld/ELF/MarkLive.cpp125
-rw-r--r--contrib/llvm/tools/lld/ELF/Memory.h4
-rw-r--r--contrib/llvm/tools/lld/ELF/Options.td90
-rw-r--r--contrib/llvm/tools/lld/ELF/OutputSections.cpp715
-rw-r--r--contrib/llvm/tools/lld/ELF/OutputSections.h241
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.cpp1113
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.h85
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptLexer.cpp285
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptLexer.h56
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptParser.cpp1305
-rw-r--r--contrib/llvm/tools/lld/ELF/ScriptParser.h38
-rw-r--r--contrib/llvm/tools/lld/ELF/Strings.cpp29
-rw-r--r--contrib/llvm/tools/lld/ELF/Strings.h11
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolTable.cpp304
-rw-r--r--contrib/llvm/tools/lld/ELF/SymbolTable.h41
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.cpp290
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.h226
-rw-r--r--contrib/llvm/tools/lld/ELF/SyntheticSections.cpp1939
-rw-r--r--contrib/llvm/tools/lld/ELF/SyntheticSections.h519
-rw-r--r--contrib/llvm/tools/lld/ELF/Target.cpp2322
-rw-r--r--contrib/llvm/tools/lld/ELF/Target.h83
-rw-r--r--contrib/llvm/tools/lld/ELF/Threads.h30
-rw-r--r--contrib/llvm/tools/lld/ELF/Thunks.cpp236
-rw-r--r--contrib/llvm/tools/lld/ELF/Thunks.h43
-rw-r--r--contrib/llvm/tools/lld/ELF/Writer.cpp1830
-rw-r--r--contrib/llvm/tools/lld/ELF/Writer.h25
-rw-r--r--contrib/llvm/tools/lld/README.md1
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Parallel.h336
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/Reader.h5
-rw-r--r--contrib/llvm/tools/lld/include/lld/Core/TargetOptionsCommandFlags.h20
-rw-r--r--contrib/llvm/tools/lld/include/lld/Driver/Driver.h3
-rw-r--r--contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h2
-rw-r--r--contrib/llvm/tools/lld/include/lld/Support/Memory.h63
-rw-r--r--contrib/llvm/tools/lld/lib/Core/CMakeLists.txt13
-rw-r--r--contrib/llvm/tools/lld/lib/Core/Reader.cpp6
-rw-r--r--contrib/llvm/tools/lld/lib/Core/SymbolTable.cpp2
-rw-r--r--contrib/llvm/tools/lld/lib/Core/TargetOptionsCommandFlags.cpp32
-rw-r--r--contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp24
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp13
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp4
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp9
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt2
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h2
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp10
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp2
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h2
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp21
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h2
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp6
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp5
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp10
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp4
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ObjCPass.cpp8
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/MachO/WriterMachO.cpp2
-rw-r--r--contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp2
-rw-r--r--contrib/llvm/tools/lld/tools/lld/lld.cpp6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/LLDB.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBAddress.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBAttachInfo.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBBreakpoint.h16
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBBreakpointLocation.h3
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBDefines.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBError.h13
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBFrame.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBInstruction.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBInstructionList.h9
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBListener.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBPlatform.h3
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBProcess.h29
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBStructuredData.h71
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBTarget.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBTrace.h123
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBTraceOptions.h58
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/API/SBWatchpoint.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/Breakpoint.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointID.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocation.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointOptions.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolver.h11
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverName.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointSite.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/Stoppoint.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/StoppointLocation.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/Watchpoint.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Breakpoint/WatchpointOptions.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Address.h53
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/AddressRange.h18
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/AddressResolver.h20
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverFileLine.h16
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverName.h17
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ArchSpec.h27
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Broadcaster.h36
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Communication.h52
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/DataBufferMemoryMap.h154
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Debugger.h76
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Disassembler.h66
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/DumpDataExtractor.h95
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/EmulateInstruction.h31
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Event.h27
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/FileLineResolver.h14
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/FileSpecList.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/FormatEntity.h47
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/IOHandler.h29
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Listener.h28
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Log.h189
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Mangled.h15
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/MappedHash.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Module.h93
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ModuleChild.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ModuleList.h77
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ModuleSpec.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Opcode.h21
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/PluginManager.h47
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/RangeMap.h63
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/RegisterValue.h42
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Scalar.h25
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/SearchFilter.h55
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Section.h44
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/SourceManager.h25
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/State.h21
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/StreamAsynchronousIO.h11
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/StreamBuffer.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/StreamFile.h15
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/StructuredDataImpl.h156
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/UniqueCStringMap.h42
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/UserSettingsController.h48
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/Value.h48
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObject.h129
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectCast.h15
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectChild.h14
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResult.h34
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultCast.h26
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultChild.h28
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultImpl.h29
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectDynamicValue.h29
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectList.h15
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectMemory.h17
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectRegister.h34
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h28
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectVariable.h34
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Core/dwarf.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/DataFormatters/DataVisualization.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h5
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatCache.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormattersContainer.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/DataFormatters/StringPrinter.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSummary.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSynthetic.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h3
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/DataFormatters/VectorIterator.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/DWARFExpression.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/DiagnosticManager.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/Expression.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionParser.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionVariable.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/IRExecutionUnit.h12
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/IRInterpreter.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/IRMemoryMap.h24
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/LLVMUserExpression.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/Materializer.h20
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/REPL.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/UserExpression.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Expression/UtilityFunction.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/Config.h48
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/Config.h.cmake27
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/Editline.h17
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/File.h53
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/FileCache.h13
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/FileSystem.h42
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/Host.h100
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/HostInfo.h3
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/HostInfoBase.h35
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/HostNativeProcessBase.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThread.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadBase.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadForward.h12
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/HostProcess.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/HostThread.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/LockFileBase.h26
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h103
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/MainLoopBase.h12
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/MonitoringProcessLauncher.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/PipeBase.h33
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/PosixApi.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/ProcessLauncher.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/PseudoTerminal.h (renamed from contrib/llvm/tools/lldb/include/lldb/Utility/PseudoTerminal.h)6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/Socket.h63
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/SocketAddress.h22
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/Symbols.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/ThisThread.h37
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/ThreadLauncher.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/XML.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpoint.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpointList.h29
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/common/NativeProcessProtocol.h309
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/common/NativeRegisterContext.h41
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/common/NativeThreadProtocol.h27
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/common/NativeWatchpointList.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/common/SoftwareBreakpoint.h20
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/common/TCPSocket.h26
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/common/UDPSocket.h15
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/freebsd/Config.h28
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/freebsd/HostInfoFreeBSD.h3
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/freebsd/HostThreadFreeBSD.h29
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/netbsd/Config.h28
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/netbsd/HostInfoNetBSD.h3
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/netbsd/HostThreadNetBSD.h30
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/openbsd/HostInfoOpenBSD.h27
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h28
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/posix/DomainSocket.h14
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/posix/HostInfoPosix.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/posix/HostProcessPosix.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/posix/HostThreadPosix.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/posix/LockFilePosix.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/posix/MainLoopPosix.h104
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/posix/PipePosix.h24
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Host/posix/ProcessLauncherPosixFork.h (renamed from contrib/llvm/tools/lldb/include/lldb/Host/posix/ProcessLauncherPosix.h)13
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/Args.h30
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandCompletions.h12
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandHistory.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandInterpreter.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObject.h5
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObjectRegexCommand.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandReturnObject.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupArchitecture.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupBoolean.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFile.h12
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFormat.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupOutputFile.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupPlatform.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupString.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUInt64.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUUID.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupVariable.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValue.h21
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArch.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArray.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueBoolean.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueChar.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueDictionary.h10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueEnumeration.h17
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpec.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormat.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueLanguage.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValuePathMappings.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueProperties.h19
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueRegex.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueSInt64.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueString.h15
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUInt64.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUUID.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/Options.h32
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/Property.h13
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreter.h58
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/ArmUnwindInfo.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/Block.h5
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/ClangASTContext.h15
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/CompactUnwindInfo.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/CompileUnit.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDecl.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDeclContext.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerType.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h34
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/DebugMacros.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/DeclVendor.h1
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/Declaration.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/FuncUnwinders.h19
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/Function.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/GoASTContext.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/JavaASTContext.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/LineEntry.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/OCamlASTContext.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectContainer.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h64
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/Symbol.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolContext.h25
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolFile.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/Symtab.h1
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/Type.h5
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindPlan.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindTable.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Symbol/Variable.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ABI.h25
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/DynamicLoader.h40
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/FileAction.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntime.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/Language.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/LanguageRuntime.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/Memory.h34
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/MemoryRegionInfo.h23
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ModuleCache.h (renamed from contrib/llvm/tools/lldb/source/Utility/ModuleCache.h)36
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ObjCLanguageRuntime.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/PathMappingList.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/Platform.h142
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/Process.h290
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ProcessInfo.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ProcessLaunchInfo.h9
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ProcessStructReader.h (renamed from contrib/llvm/tools/lldb/include/lldb/Utility/ProcessStructReader.h)15
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/QueueItem.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/QueueList.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/RegisterCheckpoint.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/RegisterContext.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/RegisterNumber.h (renamed from contrib/llvm/tools/lldb/include/lldb/Utility/RegisterNumber.h)4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadList.h3
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/StackFrame.h28
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/StackFrameList.h1
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/StopInfo.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/StructuredDataPlugin.h6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/SystemRuntime.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/Target.h61
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/TargetList.h38
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/Thread.h44
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ThreadList.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlan.h26
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallFunction.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h3
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanPython.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/ThreadSpec.h14
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Target/UnixSignals.h23
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Baton.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/Baton.h)11
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Connection.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/Connection.h)39
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/ConstString.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/ConstString.h)23
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/ConvertEnum.h21
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/DataBuffer.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/DataBuffer.h)0
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/DataBufferHeap.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/DataBufferHeap.h)11
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/DataBufferLLVM.h52
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/DataEncoder.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/DataEncoder.h)12
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/DataExtractor.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/DataExtractor.h)142
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Endian.h (renamed from contrib/llvm/tools/lldb/include/lldb/Host/Endian.h)6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/FastDemangle.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/FastDemangle.h)0
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/FileSpec.h (renamed from contrib/llvm/tools/lldb/include/lldb/Host/FileSpec.h)231
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Flags.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/Flags.h)6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/History.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/History.h)12
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/IOObject.h (renamed from contrib/llvm/tools/lldb/include/lldb/Host/IOObject.h)10
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/JSON.h13
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/LLDBAssert.h5
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Log.h216
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Logging.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/Logging.h)26
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/NameMatches.h14
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/PriorityPointerPair.h86
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Range.h1
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/RegularExpression.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/RegularExpression.h)9
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/SafeMachO.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/SelectHelper.h11
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/SharingPtr.h3
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Status.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/Error.h)114
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Stream.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/Stream.h)46
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/StreamCallback.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/StreamCallback.h)23
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/StreamGDBRemote.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/StreamGDBRemote.h)13
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/StreamString.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/StreamString.h)9
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/StreamTee.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/StreamTee.h)2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/StringExtractor.h11
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/StringLexer.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/StringList.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/StringList.h)22
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/StructuredData.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/StructuredData.h)154
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/TaskPool.h138
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/TildeExpressionResolver.h65
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Timeout.h18
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Timer.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/Timer.h)41
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/TraceOptions.h61
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/UUID.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/UUID.h)17
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/UriParser.h (renamed from contrib/llvm/tools/lldb/source/Utility/UriParser.h)8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/UserID.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/UserID.h)6
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/Utils.h22
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/VASPrintf.h21
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/Utility/VMRange.h (renamed from contrib/llvm/tools/lldb/include/lldb/Core/VMRange.h)14
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h22
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/lldb-forward.h8
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h57
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/lldb-private-forward.h4
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/lldb-private-interfaces.h13
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/lldb-private-types.h2
-rw-r--r--contrib/llvm/tools/lldb/include/lldb/lldb-types.h24
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBAddress.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBBlock.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBBreakpoint.cpp456
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBBreakpointLocation.cpp208
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBBroadcaster.cpp22
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBCommandReturnObject.cpp9
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBCommunication.cpp5
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBCompileUnit.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBData.cpp15
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBDebugger.cpp28
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBDeclaration.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBError.cpp20
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBEvent.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBFileSpec.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBFileSpecList.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBFrame.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBFunction.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBHostOS.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBInstruction.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBInstructionList.cpp28
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBLineEntry.cpp5
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBListener.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfo.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfoList.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBModule.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBModuleSpec.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBPlatform.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBProcess.cpp49
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBQueue.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBQueueItem.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBSection.cpp13
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBSourceManager.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBStream.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBStringList.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBStructuredData.cpp131
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBSymbol.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBSymbolContext.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBTarget.cpp62
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBThread.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBThreadPlan.cpp5
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBTrace.cpp109
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBTraceOptions.cpp94
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBType.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBTypeEnumMember.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBUnixSignals.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBValue.cpp22
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBValueList.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/API/SBWatchpoint.cpp28
-rw-r--r--contrib/llvm/tools/lldb/source/API/SystemInitializerFull.cpp32
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/Breakpoint.cpp34
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointID.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointIDList.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointList.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointOptions.cpp18
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolver.cpp20
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverAddress.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp101
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSite.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSiteList.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/Watchpoint.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Breakpoint/WatchpointOptions.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp305
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.cpp70
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp13
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectBugreport.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp63
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp20
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp111
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.h7
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.cpp88
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.cpp84
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp102
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp65
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp22
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.cpp25
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp107
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.cpp208
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp106
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.cpp32
-rw-r--r--contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Address.cpp96
-rw-r--r--contrib/llvm/tools/lldb/source/Core/AddressRange.cpp17
-rw-r--r--contrib/llvm/tools/lldb/source/Core/AddressResolver.cpp13
-rw-r--r--contrib/llvm/tools/lldb/source/Core/AddressResolverFileLine.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Core/AddressResolverName.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ArchSpec.cpp81
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Broadcaster.cpp29
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Communication.cpp76
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Connection.cpp34
-rw-r--r--contrib/llvm/tools/lldb/source/Core/DataBufferMemoryMap.cpp307
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Debugger.cpp265
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Disassembler.cpp79
-rw-r--r--contrib/llvm/tools/lldb/source/Core/DumpDataExtractor.cpp825
-rw-r--r--contrib/llvm/tools/lldb/source/Core/DynamicLoader.cpp36
-rw-r--r--contrib/llvm/tools/lldb/source/Core/EmulateInstruction.cpp36
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Event.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/Core/FileLineResolver.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/Core/FileSpecList.cpp54
-rw-r--r--contrib/llvm/tools/lldb/source/Core/FormatEntity.cpp115
-rw-r--r--contrib/llvm/tools/lldb/source/Core/IOHandler.cpp43
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Listener.cpp23
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Log.cpp399
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Logging.cpp322
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Mangled.cpp78
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Module.cpp188
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ModuleList.cpp77
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Opcode.cpp20
-rw-r--r--contrib/llvm/tools/lldb/source/Core/PluginManager.cpp159
-rw-r--r--contrib/llvm/tools/lldb/source/Core/RegisterValue.cpp69
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Scalar.cpp39
-rw-r--r--contrib/llvm/tools/lldb/source/Core/SearchFilter.cpp173
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Section.cpp128
-rw-r--r--contrib/llvm/tools/lldb/source/Core/SourceManager.cpp43
-rw-r--r--contrib/llvm/tools/lldb/source/Core/State.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Core/StreamAsynchronousIO.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Core/StreamCallback.cpp50
-rw-r--r--contrib/llvm/tools/lldb/source/Core/StreamFile.cpp5
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Timer.cpp154
-rw-r--r--contrib/llvm/tools/lldb/source/Core/UserSettingsController.cpp53
-rw-r--r--contrib/llvm/tools/lldb/source/Core/Value.cpp39
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObject.cpp144
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectCast.cpp23
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectChild.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectConstResult.cpp29
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultCast.cpp17
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultChild.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultImpl.cpp35
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectDynamicValue.cpp33
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectList.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectMemory.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectRegister.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectSyntheticFilter.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Core/ValueObjectVariable.cpp36
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/CXXFunctionPointer.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/FormatManager.cpp58
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/FormattersHelpers.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/TypeCategory.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/TypeCategoryMap.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/TypeFormat.cpp18
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/TypeSummary.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/TypeSynthetic.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/TypeValidator.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/ValueObjectPrinter.cpp35
-rw-r--r--contrib/llvm/tools/lldb/source/DataFormatters/VectorType.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp24
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/DiagnosticManager.cpp13
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ExpressionSourceCode.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ExpressionVariable.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/FunctionCaller.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp40
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/IRInterpreter.cpp48
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/IRMemoryMap.cpp37
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/LLVMUserExpression.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/Materializer.cpp157
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/REPL.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/UserExpression.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/UtilityFunction.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Editline.cpp31
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/File.cpp154
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp9
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp74
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Host.cpp514
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp92
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/HostProcess.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/HostThread.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/LockFileBase.cpp20
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/MainLoop.cpp387
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp19
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp38
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp237
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp132
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp32
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/PipeBase.cpp5
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/PseudoTerminal.cpp (renamed from contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp)5
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Socket.cpp136
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp70
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp75
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp106
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp274
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp50
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp84
-rw-r--r--contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp217
-rw-r--r--contrib/llvm/tools/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp3
-rw-r--r--contrib/llvm/tools/lldb/source/Host/freebsd/HostThreadFreeBSD.cpp70
-rw-r--r--contrib/llvm/tools/lldb/source/Host/freebsd/ThisThread.cpp35
-rw-r--r--contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp42
-rw-r--r--contrib/llvm/tools/lldb/source/Host/netbsd/HostInfoNetBSD.cpp22
-rw-r--r--contrib/llvm/tools/lldb/source/Host/netbsd/HostThreadNetBSD.cpp43
-rw-r--r--contrib/llvm/tools/lldb/source/Host/netbsd/ThisThread.cpp26
-rw-r--r--contrib/llvm/tools/lldb/source/Host/openbsd/Host.cpp222
-rw-r--r--contrib/llvm/tools/lldb/source/Host/openbsd/HostInfoOpenBSD.cpp65
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp111
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp53
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/FileSystem.cpp208
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/HostInfoPosix.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/HostProcessPosix.cpp18
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/HostThreadPosix.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/LockFilePosix.cpp17
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp182
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/PipePosix.cpp64
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp34
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp234
-rw-r--r--contrib/llvm/tools/lldb/source/Initialization/SystemInitializerCommon.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/Args.cpp41
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/CommandAlias.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/CommandHistory.cpp5
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp51
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/CommandReturnObject.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupArchitecture.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupBoolean.cpp9
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFile.cpp18
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFormat.cpp48
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupOutputFile.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupPlatform.cpp13
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupString.cpp9
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUInt64.cpp9
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUUID.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupVariable.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionGroupWatchpoint.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValue.cpp18
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueArch.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueArray.cpp17
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueBoolean.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueChar.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp24
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp23
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpec.cpp13
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpecLIst.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormat.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormatEntity.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueLanguage.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValuePathMappings.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp46
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueRegex.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueSInt64.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueString.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueUInt64.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/OptionValueUUID.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/Options.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreter.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp41
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp28
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp20
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp22
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp66
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp30
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp22
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp24
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp28
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp28
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp26
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp30
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp96
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h69
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp44
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h11
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp660
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h18
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp37
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp22
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp18
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp28
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp18
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp561
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp13
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp9
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp24
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp18
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp (renamed from contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp)25
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h (renamed from contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h)2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt13
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt13
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp276
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h68
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp (renamed from contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp)109
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h (renamed from contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h)5
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt13
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp343
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h69
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp362
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h33
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp661
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h182
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp166
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h26
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp37
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp78
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp165
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp33
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaFormatterFunctions.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/CMakeLists.txt10
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp157
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp3
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp304
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp256
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSError.cpp17
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSException.cpp15
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.cpp130
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp17
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp57
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp9
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp22
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp81
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp165
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp26
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp208
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp47
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h34
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp299
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h24
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp453
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h99
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp671
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h102
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/CMakeLists.txt9
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp225
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h68
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp332
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h79
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp101
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h56
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp76
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h5
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.cpp30
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.h12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp182
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h109
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp85
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h23
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp338
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h78
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp99
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h20
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h3
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/CMakeLists.txt21
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp939
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h144
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp112
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h74
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp940
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h96
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp218
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h81
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp193
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h78
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp33
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp (renamed from contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp)2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h (renamed from contrib/llvm/tools/lldb/include/lldb/Host/common/NativeRegisterContextRegisterInfo.h)11
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp34
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp97
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp35
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp67
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.h62
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp3
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp86
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp97
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h7
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp285
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp80
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h26
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp107
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h31
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp112
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h15
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h3
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h1
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp (renamed from contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp)38
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h (renamed from contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h)12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp130
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h16
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp22
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp143
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h53
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp83
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h14
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp456
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h76
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp28
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h13
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp94
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h11
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp1131
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h49
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp50
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp365
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h104
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp221
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h19
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp18
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/CMakeLists.txt11
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp24
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.h6
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp50
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.h16
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h7
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp132
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h38
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/CMakeLists.txt11
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp59
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h7
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp131
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp9
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp51
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h3
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp19
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp212
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h47
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp20
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h3
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp147
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h10
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp13
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h1
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp118
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h2
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp5
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h1
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp62
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h5
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/ArmUnwindInfo.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/Block.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp262
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/ClangASTImporter.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp89
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCommon.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/CompactUnwindInfo.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/CompilerType.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp247
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/Declaration.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/FuncUnwinders.cpp153
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/Function.cpp15
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/GoASTContext.cpp49
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/JavaASTContext.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/LineTable.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/OCamlASTContext.cpp9
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/ObjectFile.cpp75
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/Symbol.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/SymbolContext.cpp161
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/SymbolFile.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/SymbolVendor.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/Symtab.cpp125
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/Type.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/UnwindPlan.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/UnwindTable.cpp110
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/Variable.cpp16
-rw-r--r--contrib/llvm/tools/lldb/source/Symbol/VariableList.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ABI.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Target/FileAction.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Target/InstrumentationRuntime.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Target/Language.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Target/LanguageRuntime.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Target/Memory.cpp189
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ModuleCache.cpp (renamed from contrib/llvm/tools/lldb/source/Utility/ModuleCache.cpp)124
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp10
-rw-r--r--contrib/llvm/tools/lldb/source/Target/PathMappingList.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Target/Platform.cpp320
-rw-r--r--contrib/llvm/tools/lldb/source/Target/Process.cpp437
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ProcessInfo.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ProcessLaunchInfo.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Target/RegisterContext.cpp21
-rw-r--r--contrib/llvm/tools/lldb/source/Target/RegisterNumber.cpp (renamed from contrib/llvm/tools/lldb/source/Utility/RegisterNumber.cpp)2
-rw-r--r--contrib/llvm/tools/lldb/source/Target/SectionLoadHistory.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Target/SectionLoadList.cpp45
-rw-r--r--contrib/llvm/tools/lldb/source/Target/StackFrame.cpp102
-rw-r--r--contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp5
-rw-r--r--contrib/llvm/tools/lldb/source/Target/StackID.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Target/StopInfo.cpp26
-rw-r--r--contrib/llvm/tools/lldb/source/Target/Target.cpp143
-rw-r--r--contrib/llvm/tools/lldb/source/Target/TargetList.cpp93
-rw-r--r--contrib/llvm/tools/lldb/source/Target/Thread.cpp213
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadList.cpp15
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlan.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanBase.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunction.cpp11
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanCallUserExpression.cpp15
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanPython.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanRunToAddress.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanShouldStopHere.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInRange.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInstruction.cpp13
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOut.cpp2
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverRange.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanStepRange.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanStepThrough.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanStepUntil.cpp4
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadPlanTracer.cpp8
-rw-r--r--contrib/llvm/tools/lldb/source/Target/ThreadSpec.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Target/UnixSignals.cpp39
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.cpp212
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.h4
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.cpp925
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.h5
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/Baton.cpp (renamed from contrib/llvm/tools/lldb/source/Core/Baton.cpp)15
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/Connection.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/ConstString.cpp (renamed from contrib/llvm/tools/lldb/source/Core/ConstString.cpp)60
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/ConvertEnum.cpp118
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/DataBufferHeap.cpp (renamed from contrib/llvm/tools/lldb/source/Core/DataBufferHeap.cpp)2
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp70
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/DataEncoder.cpp (renamed from contrib/llvm/tools/lldb/source/Core/DataEncoder.cpp)17
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/DataExtractor.cpp (renamed from contrib/llvm/tools/lldb/source/Core/DataExtractor.cpp)948
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/FastDemangle.cpp (renamed from contrib/llvm/tools/lldb/source/Core/FastDemangle.cpp)11
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/FileSpec.cpp (renamed from contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp)729
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/History.cpp (renamed from contrib/llvm/tools/lldb/source/Core/History.cpp)4
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/IOObject.cpp (renamed from contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp)3
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/JSON.cpp50
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp3
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/Log.cpp323
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/Logging.cpp74
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/NameMatches.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/Range.cpp6
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/RegularExpression.cpp (renamed from contrib/llvm/tools/lldb/source/Core/RegularExpression.cpp)22
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp29
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/Status.cpp (renamed from contrib/llvm/tools/lldb/source/Core/Error.cpp)227
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/Stream.cpp (renamed from contrib/llvm/tools/lldb/source/Core/Stream.cpp)132
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/StreamCallback.cpp23
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/StreamGDBRemote.cpp (renamed from contrib/llvm/tools/lldb/source/Core/StreamGDBRemote.cpp)6
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/StreamString.cpp (renamed from contrib/llvm/tools/lldb/source/Core/StreamString.cpp)3
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp19
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp60
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h22
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/StringLexer.cpp7
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/StringList.cpp (renamed from contrib/llvm/tools/lldb/source/Core/StringList.cpp)23
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp (renamed from contrib/llvm/tools/lldb/source/Core/StructuredData.cpp)93
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/TaskPool.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp95
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/Timer.cpp132
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/UUID.cpp (renamed from contrib/llvm/tools/lldb/source/Core/UUID.cpp)31
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/UriParser.cpp12
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/UserID.cpp (renamed from contrib/llvm/tools/lldb/source/Core/UserID.cpp)4
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp56
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/VMRange.cpp (renamed from contrib/llvm/tools/lldb/source/Core/VMRange.cpp)58
-rw-r--r--contrib/llvm/tools/lldb/tools/argdumper/argdumper.cpp2
-rw-r--r--contrib/llvm/tools/lldb/tools/driver/Driver.cpp1
-rw-r--r--contrib/llvm/tools/lldb/tools/driver/Driver.h2
-rw-r--r--contrib/llvm/tools/lldb/tools/driver/Platform.h1
-rw-r--r--contrib/llvm/tools/lldb/tools/intel-mpx/IntelMPXTablePlugin.cpp427
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MICmdBase.cpp2
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdData.h2
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdStack.cpp8
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdVar.cpp32
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.cpp2
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.h2
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebugger.cpp1
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp2
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MIDriver.cpp6
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverBase.cpp2
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverMain.cpp1
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.cpp2
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.h2
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilThreadBaseStd.h3
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-mi/Platform.h1
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.cpp14
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.h10
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-server/LLDBServerUtilities.cpp44
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-server/lldb-gdbserver.cpp73
-rw-r--r--contrib/llvm/tools/lldb/tools/lldb-server/lldb-platform.cpp105
-rw-r--r--contrib/llvm/tools/lli/OrcLazyJIT.cpp101
-rw-r--r--contrib/llvm/tools/lli/OrcLazyJIT.h148
-rw-r--r--contrib/llvm/tools/lli/RemoteJITUtils.h9
-rw-r--r--contrib/llvm/tools/lli/lli.cpp5
-rw-r--r--contrib/llvm/tools/llvm-ar/llvm-ar.cpp45
-rw-r--r--contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp31
-rw-r--r--contrib/llvm/tools/llvm-cov/CodeCoverage.cpp61
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageReport.cpp69
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageReport.h6
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h13
-rw-r--r--contrib/llvm/tools/llvm-cov/TestingSupport.cpp7
-rw-r--r--contrib/llvm/tools/llvm-cov/gcov.cpp2
-rw-r--r--contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp78
-rw-r--r--contrib/llvm/tools/llvm-diff/DiffConsumer.cpp7
-rw-r--r--contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp16
-rw-r--r--contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp64
-rw-r--r--contrib/llvm/tools/llvm-extract/llvm-extract.cpp35
-rw-r--r--contrib/llvm/tools/llvm-link/llvm-link.cpp27
-rw-r--r--contrib/llvm/tools/llvm-lto/llvm-lto.cpp48
-rw-r--r--contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp146
-rw-r--r--contrib/llvm/tools/llvm-mc/llvm-mc.cpp24
-rw-r--r--contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp9
-rw-r--r--contrib/llvm/tools/llvm-nm/llvm-nm.cpp688
-rw-r--r--contrib/llvm/tools/llvm-objdump/MachODump.cpp626
-rw-r--r--contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp141
-rw-r--r--contrib/llvm/tools/llvm-objdump/llvm-objdump.h17
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp960
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h58
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/LinePrinter.cpp123
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/PdbYaml.h174
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp192
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h63
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp98
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp171
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp231
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/YamlSerializationContext.h39
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/YamlSymbolDumper.cpp412
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/YamlSymbolDumper.h66
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp599
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/YamlTypeDumper.h116
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp623
-rw-r--r--contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h83
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/Analyze.cpp148
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/Analyze.h30
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp501
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h67
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/Diff.cpp608
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/Diff.h45
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DiffPrinter.cpp147
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DiffPrinter.h172
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp1043
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h62
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp101
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/FormatUtil.h128
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp312
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/LinePrinter.h (renamed from contrib/llvm/tools/llvm-pdbdump/LinePrinter.h)58
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp772
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h48
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp553
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h63
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/OutputStyle.h (renamed from contrib/llvm/tools/llvm-pdbdump/OutputStyle.h)0
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp (renamed from contrib/llvm/tools/llvm-pdbdump/PdbYaml.cpp)184
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PdbYaml.h125
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.cpp)6
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.h)0
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp108
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h47
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp216
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h58
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyCompilandDumper.cpp)16
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyCompilandDumper.h)2
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyEnumDumper.cpp)2
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyEnumDumper.h)0
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.cpp)0
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.h)0
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp)22
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.h)0
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp255
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyTypeDumper.h)4
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp)9
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.h)2
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp220
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h (renamed from contrib/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h)10
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp152
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/StreamUtil.h30
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp333
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h (renamed from contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h)4
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp1179
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h180
-rw-r--r--contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp192
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp682
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h126
-rw-r--r--contrib/llvm/tools/llvm-readobj/COFFDumper.cpp687
-rw-r--r--contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp2
-rw-r--r--contrib/llvm/tools/llvm-readobj/CodeView.h54
-rw-r--r--contrib/llvm/tools/llvm-readobj/ELFDumper.cpp335
-rw-r--r--contrib/llvm/tools/llvm-readobj/MachODumper.cpp20
-rw-r--r--contrib/llvm/tools/llvm-readobj/ObjDumper.h14
-rw-r--r--contrib/llvm/tools/llvm-readobj/WasmDumper.cpp209
-rw-r--r--contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp79
-rw-r--r--contrib/llvm/tools/llvm-readobj/llvm-readobj.h5
-rw-r--r--contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp26
-rw-r--r--contrib/llvm/tools/llvm-stress/llvm-stress.cpp127
-rw-r--r--contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp5
-rw-r--r--contrib/llvm/tools/llvm-xray/llvm-xray.cc10
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-account.cc96
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-color-helper.cc224
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-color-helper.h89
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-converter.cc69
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-extract.cc263
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-extract.h58
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-graph-diff.cc484
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-graph-diff.h74
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-graph.cc521
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-graph.h233
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-sleds.h32
-rw-r--r--contrib/llvm/tools/opt/BreakpointPrinter.cpp2
-rw-r--r--contrib/llvm/tools/opt/GraphPrinters.cpp2
-rw-r--r--contrib/llvm/tools/opt/NewPMDriver.cpp116
-rw-r--r--contrib/llvm/tools/opt/NewPMDriver.h10
-rw-r--r--contrib/llvm/tools/opt/opt.cpp80
2042 files changed, 146884 insertions, 84072 deletions
diff --git a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp
index 0cae066..2fd8699 100644
--- a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp
+++ b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp
@@ -731,7 +731,8 @@ bool ReduceCrashingInstructions::TestInsts(
for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) {
Instruction *Inst = &*I++;
if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst) &&
- !Inst->isEHPad() && !Inst->getType()->isTokenTy()) {
+ !Inst->isEHPad() && !Inst->getType()->isTokenTy() &&
+ !Inst->isSwiftError()) {
if (!Inst->getType()->isVoidTy())
Inst->replaceAllUsesWith(UndefValue::get(Inst->getType()));
Inst->eraseFromParent();
@@ -1015,7 +1016,8 @@ static Error ReduceInsts(BugDriver &BD,
// TODO: Should this be some kind of interrupted error?
return Error::success();
- if (I->isEHPad() || I->getType()->isTokenTy())
+ if (I->isEHPad() || I->getType()->isTokenTy() ||
+ I->isSwiftError())
continue;
outs() << "Checking instruction: " << *I;
@@ -1111,7 +1113,7 @@ static Error DebugACrash(BugDriver &BD,
BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks");
}
- if (!DisableSimplifyCFG & !BugpointIsInterrupted) {
+ if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
std::vector<const BasicBlock *> Blocks;
for (Function &F : *BD.getProgram())
for (BasicBlock &BB : F)
diff --git a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp
index d57613e..72872e8 100644
--- a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp
+++ b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp
@@ -209,6 +209,7 @@ static void eliminateAliases(GlobalValue *GV) {
void llvm::DeleteGlobalInitializer(GlobalVariable *GV) {
eliminateAliases(GV);
GV->setInitializer(nullptr);
+ GV->setComdat(nullptr);
}
// DeleteFunctionBody - "Remove" the function by deleting all of its basic
@@ -231,8 +232,7 @@ static Constant *GetTorInit(std::vector<std::pair<Function *, int>> &TorList) {
std::vector<Constant *> ArrayElts;
Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext());
- StructType *STy =
- StructType::get(Int32Ty, TorList[0].first->getType(), nullptr);
+ StructType *STy = StructType::get(Int32Ty, TorList[0].first->getType());
for (unsigned i = 0, e = TorList.size(); i != e; ++i) {
Constant *Elts[] = {ConstantInt::get(Int32Ty, TorList[i].second),
TorList[i].first};
diff --git a/contrib/llvm/tools/bugpoint/FindBugs.cpp b/contrib/llvm/tools/bugpoint/FindBugs.cpp
index 156f4d0..3093169 100644
--- a/contrib/llvm/tools/bugpoint/FindBugs.cpp
+++ b/contrib/llvm/tools/bugpoint/FindBugs.cpp
@@ -21,6 +21,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <ctime>
+#include <random>
using namespace llvm;
Error
@@ -39,14 +40,13 @@ BugDriver::runManyPasses(const std::vector<std::string> &AllPasses) {
return E;
}
- srand(time(nullptr));
-
+ std::mt19937 randomness(std::random_device{}());
unsigned num = 1;
while (1) {
//
// Step 1: Randomize the order of the optimizer passes.
//
- std::random_shuffle(PassesToRun.begin(), PassesToRun.end());
+ std::shuffle(PassesToRun.begin(), PassesToRun.end(), randomness);
//
// Step 2: Run optimizer passes on the program and check for success.
diff --git a/contrib/llvm/tools/bugpoint/ListReducer.h b/contrib/llvm/tools/bugpoint/ListReducer.h
index dcfa11d..0f9db02 100644
--- a/contrib/llvm/tools/bugpoint/ListReducer.h
+++ b/contrib/llvm/tools/bugpoint/ListReducer.h
@@ -19,6 +19,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdlib>
+#include <random>
#include <vector>
namespace llvm {
@@ -46,7 +47,7 @@ template <typename ElTy> struct ListReducer {
/// that bugpoint does.
Expected<bool> reduceList(std::vector<ElTy> &TheList) {
std::vector<ElTy> empty;
- std::srand(0x6e5ea738); // Seed the random number generator
+ std::mt19937 randomness(0x6e5ea738); // Seed the random number generator
Expected<TestResult> Result = doTest(TheList, empty);
if (Error E = Result.takeError())
return std::move(E);
@@ -92,7 +93,7 @@ template <typename ElTy> struct ListReducer {
// distribution (improving the speed of convergence).
if (ShufflingEnabled && NumOfIterationsWithoutProgress > MaxIterations) {
std::vector<ElTy> ShuffledList(TheList);
- std::random_shuffle(ShuffledList.begin(), ShuffledList.end());
+ std::shuffle(ShuffledList.begin(), ShuffledList.end(), randomness);
errs() << "\n\n*** Testing shuffled set...\n\n";
// Check that random shuffle doesn't lose the bug
Expected<TestResult> Result = doTest(ShuffledList, empty);
diff --git a/contrib/llvm/tools/bugpoint/Miscompilation.cpp b/contrib/llvm/tools/bugpoint/Miscompilation.cpp
index 792fab0..80f4cea 100644
--- a/contrib/llvm/tools/bugpoint/Miscompilation.cpp
+++ b/contrib/llvm/tools/bugpoint/Miscompilation.cpp
@@ -225,19 +225,22 @@ public:
/// output is different. If the DeleteInputs argument is set to true then this
/// function deletes both input modules before it returns.
///
-static Expected<std::unique_ptr<Module>>
-testMergedProgram(const BugDriver &BD, std::unique_ptr<Module> M1,
- std::unique_ptr<Module> M2, bool &Broken) {
- if (Linker::linkModules(*M1, std::move(M2)))
+static Expected<std::unique_ptr<Module>> testMergedProgram(const BugDriver &BD,
+ const Module &M1,
+ const Module &M2,
+ bool &Broken) {
+ // Resulting merge of M1 and M2.
+ auto Merged = CloneModule(&M1);
+ if (Linker::linkModules(*Merged, CloneModule(&M2)))
// TODO: Shouldn't we thread the error up instead of exiting?
exit(1);
// Execute the program.
- Expected<bool> Diff = BD.diffProgram(M1.get(), "", "", false);
+ Expected<bool> Diff = BD.diffProgram(Merged.get(), "", "", false);
if (Error E = Diff.takeError())
return std::move(E);
Broken = *Diff;
- return std::move(M1);
+ return std::move(Merged);
}
/// TestFuncs - split functions in a Module into two groups: those that are
@@ -335,9 +338,8 @@ ExtractLoops(BugDriver &BD,
// extraction.
AbstractInterpreter *AI = BD.switchToSafeInterpreter();
bool Failure;
- Expected<std::unique_ptr<Module>> New =
- testMergedProgram(BD, std::move(ToOptimizeLoopExtracted),
- std::move(ToNotOptimize), Failure);
+ Expected<std::unique_ptr<Module>> New = testMergedProgram(
+ BD, *ToOptimizeLoopExtracted, *ToNotOptimize, Failure);
if (Error E = New.takeError())
return std::move(E);
if (!*New)
@@ -726,8 +728,7 @@ static Expected<bool> TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test,
outs() << " Checking to see if the merged program executes correctly: ";
bool Broken;
- auto Result =
- testMergedProgram(BD, std::move(Optimized), std::move(Safe), Broken);
+ auto Result = testMergedProgram(BD, *Optimized, *Safe, Broken);
if (Error E = Result.takeError())
return std::move(E);
if (auto New = std::move(*Result)) {
@@ -840,7 +841,7 @@ static void CleanupAndPrepareModules(BugDriver &BD,
// Prototype: void *getPointerToNamedFunction(const char* Name)
Constant *resolverFunc = Safe->getOrInsertFunction(
"getPointerToNamedFunction", Type::getInt8PtrTy(Safe->getContext()),
- Type::getInt8PtrTy(Safe->getContext()), (Type *)nullptr);
+ Type::getInt8PtrTy(Safe->getContext()));
// Use the function we just added to get addresses of functions we need.
for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) {
diff --git a/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
index 246580c..489e50b 100644
--- a/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
+++ b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
@@ -47,14 +47,13 @@ static cl::opt<bool> PreserveBitcodeUseListOrder(
cl::desc("Preserve use-list order when writing LLVM bitcode."),
cl::init(true), cl::Hidden);
-namespace {
// ChildOutput - This option captures the name of the child output file that
// is set up by the parent bugpoint process
-cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden);
-cl::opt<std::string> OptCmd("opt-command", cl::init(""),
- cl::desc("Path to opt. (default: search path "
- "for 'opt'.)"));
-}
+static cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden);
+static cl::opt<std::string>
+ OptCmd("opt-command", cl::init(""),
+ cl::desc("Path to opt. (default: search path "
+ "for 'opt'.)"));
/// writeProgramToFile - This writes the current "Program" to the named bitcode
/// file. If an error occurs, true is returned.
@@ -203,10 +202,11 @@ bool BugDriver::runPasses(Module *Program,
} else
Args.push_back(tool.c_str());
- Args.push_back("-o");
- Args.push_back(OutputFilename.c_str());
for (unsigned i = 0, e = OptArgs.size(); i != e; ++i)
Args.push_back(OptArgs[i].c_str());
+ Args.push_back("-disable-symbolication");
+ Args.push_back("-o");
+ Args.push_back(OutputFilename.c_str());
std::vector<std::string> pass_args;
for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) {
pass_args.push_back(std::string("-load"));
diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.cpp b/contrib/llvm/tools/bugpoint/ToolRunner.cpp
index 4633d64..70b18e3 100644
--- a/contrib/llvm/tools/bugpoint/ToolRunner.cpp
+++ b/contrib/llvm/tools/bugpoint/ToolRunner.cpp
@@ -355,37 +355,62 @@ Expected<int> CustomExecutor::ExecuteProgram(
// Tokenize the CommandLine to the command and the args to allow
// defining a full command line as the command instead of just the
// executed program. We cannot just pass the whole string after the command
-// as a single argument because then program sees only a single
+// as a single argument because then the program sees only a single
// command line argument (with spaces in it: "foo bar" instead
// of "foo" and "bar").
//
-// code borrowed from:
-// http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
+// Spaces are used as a delimiter; however repeated, leading, and trailing
+// whitespace are ignored. Simple escaping is allowed via the '\'
+// character, as seen below:
+//
+// Two consecutive '\' evaluate to a single '\'.
+// A space after a '\' evaluates to a space that is not interpreted as a
+// delimiter.
+// Any other instances of the '\' character are removed.
+//
+// Example:
+// '\\' -> '\'
+// '\ ' -> ' '
+// 'exa\mple' -> 'example'
+//
static void lexCommand(std::string &Message, const std::string &CommandLine,
std::string &CmdPath, std::vector<std::string> &Args) {
- std::string Command = "";
- std::string delimiters = " ";
-
- std::string::size_type lastPos = CommandLine.find_first_not_of(delimiters, 0);
- std::string::size_type pos = CommandLine.find_first_of(delimiters, lastPos);
-
- while (std::string::npos != pos || std::string::npos != lastPos) {
- std::string token = CommandLine.substr(lastPos, pos - lastPos);
- if (Command == "")
- Command = token;
- else
- Args.push_back(token);
- // Skip delimiters. Note the "not_of"
- lastPos = CommandLine.find_first_not_of(delimiters, pos);
- // Find next "non-delimiter"
- pos = CommandLine.find_first_of(delimiters, lastPos);
+ std::string Token;
+ std::string Command;
+ bool FoundPath = false;
+
+ // first argument is the PATH.
+ // Skip repeated whitespace, leading whitespace and trailing whitespace.
+ for (std::size_t Pos = 0u; Pos <= CommandLine.size(); ++Pos) {
+ if ('\\' == CommandLine[Pos]) {
+ if (Pos + 1 < CommandLine.size())
+ Token.push_back(CommandLine[++Pos]);
+
+ continue;
+ }
+ if (' ' == CommandLine[Pos] || CommandLine.size() == Pos) {
+ if (Token.empty())
+ continue;
+
+ if (!FoundPath) {
+ Command = Token;
+ FoundPath = true;
+ Token.clear();
+ continue;
+ }
+
+ Args.push_back(Token);
+ Token.clear();
+ continue;
+ }
+ Token.push_back(CommandLine[Pos]);
}
auto Path = sys::findProgramByName(Command);
if (!Path) {
- Message = std::string("Cannot find '") + Command + "' in PATH: " +
- Path.getError().message() + "\n";
+ Message = std::string("Cannot find '") + Command +
+ "' in PATH: " + Path.getError().message() + "\n";
return;
}
CmdPath = *Path;
@@ -836,7 +861,7 @@ Error CC::MakeSharedObject(const std::string &InputFile, FileType fileType,
errs() << "\n";);
if (RunProgramWithTimeout(CCPath, &CCArgs[0], "", "", ""))
return ProcessFailure(CCPath, &CCArgs[0]);
- return Error::success();;
+ return Error::success();
}
/// create - Try to find the CC executable
diff --git a/contrib/llvm/tools/bugpoint/bugpoint.cpp b/contrib/llvm/tools/bugpoint/bugpoint.cpp
index a5de953..4ddea8d 100644
--- a/contrib/llvm/tools/bugpoint/bugpoint.cpp
+++ b/contrib/llvm/tools/bugpoint/bugpoint.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Valgrind.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
@@ -138,6 +139,13 @@ int main(int argc, char **argv) {
polly::initializePollyPasses(Registry);
#endif
+ if (std::getenv("bar") == (char*) -1) {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+ }
+
cl::ParseCommandLineOptions(argc, argv,
"LLVM automatic testcase reducer. See\nhttp://"
"llvm.org/cmds/bugpoint.html"
@@ -181,7 +189,8 @@ int main(int argc, char **argv) {
if (OptLevelO1)
Builder.Inliner = createAlwaysInlinerLegacyPass();
else if (OptLevelOs || OptLevelO2)
- Builder.Inliner = createFunctionInliningPass(2, OptLevelOs ? 1 : 0);
+ Builder.Inliner = createFunctionInliningPass(
+ 2, OptLevelOs ? 1 : 0, false);
else
Builder.Inliner = createFunctionInliningPass(275);
Builder.populateFunctionPassManager(PM);
diff --git a/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h b/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h
index 9359abf..29f89e5 100644
--- a/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h
+++ b/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h
@@ -7,7 +7,7 @@
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
-|* This header provides a public inferface to use CompilationDatabase without *|
+|* This header provides a public interface to use CompilationDatabase without *|
|* the full Clang C++ API. *|
|* *|
\*===----------------------------------------------------------------------===*/
diff --git a/contrib/llvm/tools/clang/include/clang-c/Index.h b/contrib/llvm/tools/clang/include/clang-c/Index.h
index 15fde19..3b5ea9fa 100644
--- a/contrib/llvm/tools/clang/include/clang-c/Index.h
+++ b/contrib/llvm/tools/clang/include/clang-c/Index.h
@@ -7,7 +7,7 @@
|* *|
|*===----------------------------------------------------------------------===*|
|* *|
-|* This header provides a public inferface to a Clang library for extracting *|
+|* This header provides a public interface to a Clang library for extracting *|
|* high-level symbol information from source files without exposing the full *|
|* Clang C++ API. *|
|* *|
@@ -32,7 +32,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 37
+#define CINDEX_VERSION_MINOR 43
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -81,6 +81,12 @@ extern "C" {
typedef void *CXIndex;
/**
+ * \brief An opaque type representing target information for a given translation
+ * unit.
+ */
+typedef struct CXTargetInfoImpl *CXTargetInfo;
+
+/**
* \brief A single translation unit, which resides in an index.
*/
typedef struct CXTranslationUnitImpl *CXTranslationUnit;
@@ -165,7 +171,60 @@ typedef struct CXVersion {
*/
int Subminor;
} CXVersion;
-
+
+/**
+ * \brief Describes the exception specification of a cursor.
+ *
+ * A negative value indicates that the cursor is not a function declaration.
+ */
+enum CXCursor_ExceptionSpecificationKind {
+
+ /**
+ * \brief The cursor has no exception specification.
+ */
+ CXCursor_ExceptionSpecificationKind_None,
+
+ /**
+ * \brief The cursor has exception specification throw()
+ */
+ CXCursor_ExceptionSpecificationKind_DynamicNone,
+
+ /**
+ * \brief The cursor has exception specification throw(T1, T2)
+ */
+ CXCursor_ExceptionSpecificationKind_Dynamic,
+
+ /**
+ * \brief The cursor has exception specification throw(...).
+ */
+ CXCursor_ExceptionSpecificationKind_MSAny,
+
+ /**
+ * \brief The cursor has exception specification basic noexcept.
+ */
+ CXCursor_ExceptionSpecificationKind_BasicNoexcept,
+
+ /**
+ * \brief The cursor has exception specification computed noexcept.
+ */
+ CXCursor_ExceptionSpecificationKind_ComputedNoexcept,
+
+ /**
+ * \brief The exception specification has not yet been evaluated.
+ */
+ CXCursor_ExceptionSpecificationKind_Unevaluated,
+
+ /**
+ * \brief The exception specification has not yet been instantiated.
+ */
+ CXCursor_ExceptionSpecificationKind_Uninstantiated,
+
+ /**
+ * \brief The exception specification has not been parsed yet.
+ */
+ CXCursor_ExceptionSpecificationKind_Unparsed
+};
+
/**
* \brief Provides a shared context for creating translation units.
*
@@ -478,8 +537,8 @@ CINDEX_LINKAGE void clang_getExpansionLocation(CXSourceLocation location,
unsigned *offset);
/**
- * \brief Retrieve the file, line, column, and offset represented by
- * the given source location, as specified in a # line directive.
+ * \brief Retrieve the file, line and column represented by the given source
+ * location, as specified in a # line directive.
*
* Example: given the following source code in a file somefile.c
*
@@ -1228,7 +1287,12 @@ enum CXTranslationUnit_Flags {
* purposes of an IDE, this is undesirable behavior and as much information
* as possible should be reported. Use this flag to enable this behavior.
*/
- CXTranslationUnit_KeepGoing = 0x200
+ CXTranslationUnit_KeepGoing = 0x200,
+
+ /**
+ * \brief Sets the preprocessor in a mode for parsing a single file only.
+ */
+ CXTranslationUnit_SingleFileParse = 0x400
};
/**
@@ -1413,6 +1477,15 @@ CINDEX_LINKAGE int clang_saveTranslationUnit(CXTranslationUnit TU,
unsigned options);
/**
+ * \brief Suspend a translation unit in order to free memory associated with it.
+ *
+ * A suspended translation unit uses significantly less memory but on the other
+ * side does not support any other calls than \c clang_reparseTranslationUnit
+ * to resume it or \c clang_disposeTranslationUnit to dispose it completely.
+ */
+CINDEX_LINKAGE unsigned clang_suspendTranslationUnit(CXTranslationUnit);
+
+/**
* \brief Destroy the specified CXTranslationUnit object.
*/
CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit);
@@ -1553,6 +1626,36 @@ CINDEX_LINKAGE CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU
CINDEX_LINKAGE void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage);
/**
+ * \brief Get target information for this translation unit.
+ *
+ * The CXTargetInfo object cannot outlive the CXTranslationUnit object.
+ */
+CINDEX_LINKAGE CXTargetInfo
+clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit);
+
+/**
+ * \brief Destroy the CXTargetInfo object.
+ */
+CINDEX_LINKAGE void
+clang_TargetInfo_dispose(CXTargetInfo Info);
+
+/**
+ * \brief Get the normalized target triple as a string.
+ *
+ * Returns the empty string in case of any error.
+ */
+CINDEX_LINKAGE CXString
+clang_TargetInfo_getTriple(CXTargetInfo Info);
+
+/**
+ * \brief Get the pointer width of the target in bits.
+ *
+ * Returns -1 in case of error.
+ */
+CINDEX_LINKAGE int
+clang_TargetInfo_getPointerWidth(CXTargetInfo Info);
+
+/**
* @}
*/
@@ -3011,8 +3114,9 @@ enum CXTypeKind {
CXType_ObjCClass = 28,
CXType_ObjCSel = 29,
CXType_Float128 = 30,
+ CXType_Half = 31,
CXType_FirstBuiltin = CXType_Void,
- CXType_LastBuiltin = CXType_ObjCSel,
+ CXType_LastBuiltin = CXType_Half,
CXType_Complex = 100,
CXType_Pointer = 101,
@@ -3039,7 +3143,52 @@ enum CXTypeKind {
*
* E.g., struct S, or via a qualified name, e.g., N::M::type, or both.
*/
- CXType_Elaborated = 119
+ CXType_Elaborated = 119,
+
+ /* OpenCL PipeType. */
+ CXType_Pipe = 120,
+
+ /* OpenCL builtin types. */
+ CXType_OCLImage1dRO = 121,
+ CXType_OCLImage1dArrayRO = 122,
+ CXType_OCLImage1dBufferRO = 123,
+ CXType_OCLImage2dRO = 124,
+ CXType_OCLImage2dArrayRO = 125,
+ CXType_OCLImage2dDepthRO = 126,
+ CXType_OCLImage2dArrayDepthRO = 127,
+ CXType_OCLImage2dMSAARO = 128,
+ CXType_OCLImage2dArrayMSAARO = 129,
+ CXType_OCLImage2dMSAADepthRO = 130,
+ CXType_OCLImage2dArrayMSAADepthRO = 131,
+ CXType_OCLImage3dRO = 132,
+ CXType_OCLImage1dWO = 133,
+ CXType_OCLImage1dArrayWO = 134,
+ CXType_OCLImage1dBufferWO = 135,
+ CXType_OCLImage2dWO = 136,
+ CXType_OCLImage2dArrayWO = 137,
+ CXType_OCLImage2dDepthWO = 138,
+ CXType_OCLImage2dArrayDepthWO = 139,
+ CXType_OCLImage2dMSAAWO = 140,
+ CXType_OCLImage2dArrayMSAAWO = 141,
+ CXType_OCLImage2dMSAADepthWO = 142,
+ CXType_OCLImage2dArrayMSAADepthWO = 143,
+ CXType_OCLImage3dWO = 144,
+ CXType_OCLImage1dRW = 145,
+ CXType_OCLImage1dArrayRW = 146,
+ CXType_OCLImage1dBufferRW = 147,
+ CXType_OCLImage2dRW = 148,
+ CXType_OCLImage2dArrayRW = 149,
+ CXType_OCLImage2dDepthRW = 150,
+ CXType_OCLImage2dArrayDepthRW = 151,
+ CXType_OCLImage2dMSAARW = 152,
+ CXType_OCLImage2dArrayMSAARW = 153,
+ CXType_OCLImage2dMSAADepthRW = 154,
+ CXType_OCLImage2dArrayMSAADepthRW = 155,
+ CXType_OCLImage3dRW = 156,
+ CXType_OCLSampler = 157,
+ CXType_OCLEvent = 158,
+ CXType_OCLQueue = 159,
+ CXType_OCLReserveID = 160
};
/**
@@ -3056,7 +3205,9 @@ enum CXCallingConv {
CXCallingConv_AAPCS_VFP = 7,
CXCallingConv_X86RegCall = 8,
CXCallingConv_IntelOclBicc = 9,
- CXCallingConv_X86_64Win64 = 10,
+ CXCallingConv_Win64 = 10,
+ /* Alias for compatibility with older versions of API. */
+ CXCallingConv_X86_64Win64 = CXCallingConv_Win64,
CXCallingConv_X86_64SysV = 11,
CXCallingConv_X86VectorCall = 12,
CXCallingConv_Swift = 13,
@@ -3326,6 +3477,16 @@ CINDEX_LINKAGE unsigned clang_isVolatileQualifiedType(CXType T);
CINDEX_LINKAGE unsigned clang_isRestrictQualifiedType(CXType T);
/**
+ * \brief Returns the address space of the given type.
+ */
+CINDEX_LINKAGE unsigned clang_getAddressSpace(CXType T);
+
+/**
+ * \brief Returns the typedef name of the given type.
+ */
+CINDEX_LINKAGE CXString clang_getTypedefName(CXType CT);
+
+/**
* \brief For pointer types, returns the type of the pointee.
*/
CINDEX_LINKAGE CXType clang_getPointeeType(CXType T);
@@ -3365,6 +3526,13 @@ CINDEX_LINKAGE enum CXCallingConv clang_getFunctionTypeCallingConv(CXType T);
CINDEX_LINKAGE CXType clang_getResultType(CXType T);
/**
+ * \brief Retrieve the exception specification type associated with a function type.
+ *
+ * If a non-function type is passed in, an error code of -1 is returned.
+ */
+CINDEX_LINKAGE int clang_getExceptionSpecificationType(CXType T);
+
+/**
* \brief Retrieve the number of non-variadic parameters associated with a
* function type.
*
@@ -3393,6 +3561,13 @@ CINDEX_LINKAGE unsigned clang_isFunctionTypeVariadic(CXType T);
CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C);
/**
+ * \brief Retrieve the exception specification type associated with a given cursor.
+ *
+ * This only returns a valid result if the cursor refers to a function or method.
+ */
+CINDEX_LINKAGE int clang_getCursorExceptionSpecificationType(CXCursor C);
+
+/**
* \brief Return 1 if the CXType is a POD (plain old data) type, and 0
* otherwise.
*/
@@ -3436,6 +3611,16 @@ CINDEX_LINKAGE long long clang_getArraySize(CXType T);
CINDEX_LINKAGE CXType clang_Type_getNamedType(CXType T);
/**
+ * \brief Determine if a typedef is 'transparent' tag.
+ *
+ * A typedef is considered 'transparent' if it shares a name and spelling
+ * location with its underlying tag type, as is the case with the NS_ENUM macro.
+ *
+ * \returns non-zero if transparent and zero otherwise.
+ */
+CINDEX_LINKAGE unsigned clang_Type_isTransparentTagTypedef(CXType T);
+
+/**
* \brief List the possible error codes for \c clang_Type_getSizeOf,
* \c clang_Type_getAlignOf, \c clang_Type_getOffsetOf and
* \c clang_Cursor_getOffsetOf.
@@ -3964,8 +4149,8 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C);
/**
- * \brief Given a cursor pointing to an Objective-C message, returns the CXType
- * of the receiver.
+ * \brief Given a cursor pointing to an Objective-C message or property
+ * reference, or C++ method call, returns the CXType of the receiver.
*/
CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C);
@@ -4023,8 +4208,8 @@ CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C);
/**
* \brief Given a cursor that represents an Objective-C method or property
- * declaration, return non-zero if the declaration was affected by "@optional".
- * Returns zero if the cursor is not such a declaration or it is "@required".
+ * declaration, return non-zero if the declaration was affected by "\@optional".
+ * Returns zero if the cursor is not such a declaration or it is "\@required".
*/
CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C);
@@ -4034,6 +4219,23 @@ CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C);
CINDEX_LINKAGE unsigned clang_Cursor_isVariadic(CXCursor C);
/**
+ * \brief Returns non-zero if the given cursor points to a symbol marked with
+ * external_source_symbol attribute.
+ *
+ * \param language If non-NULL, and the attribute is present, will be set to
+ * the 'language' string from the attribute.
+ *
+ * \param definedIn If non-NULL, and the attribute is present, will be set to
+ * the 'definedIn' string from the attribute.
+ *
+ * \param isGenerated If non-NULL, and the attribute is present, will be set to
+ * non-zero if the 'generated_declaration' is set in the attribute.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isExternalSymbol(CXCursor C,
+ CXString *language, CXString *definedIn,
+ unsigned *isGenerated);
+
+/**
* \brief Given a cursor that represents a declaration, return the associated
* comment's source range. The range may include multiple consecutive comments
* with whitespace in between.
@@ -4217,6 +4419,11 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C);
CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C);
/**
+ * \brief Determine if an enum declaration refers to a scoped enum.
+ */
+CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C);
+
+/**
* \brief Determine if a C++ member function or member function template is
* declared 'const'.
*/
@@ -4700,7 +4907,7 @@ enum CXCompletionChunkKind {
*/
CXCompletionChunk_HorizontalSpace,
/**
- * Vertical space ('\n'), after which it is generally a good idea to
+ * Vertical space ('\\n'), after which it is generally a good idea to
* perform indentation.
*/
CXCompletionChunk_VerticalSpace
@@ -5589,7 +5796,8 @@ typedef enum {
CXIdxEntityLang_None = 0,
CXIdxEntityLang_C = 1,
CXIdxEntityLang_ObjC = 2,
- CXIdxEntityLang_CXX = 3
+ CXIdxEntityLang_CXX = 3,
+ CXIdxEntityLang_Swift = 4
} CXIdxEntityLanguage;
/**
diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h b/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h
index 1c9ce82..703f588 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h
@@ -39,6 +39,7 @@
#include "clang/Basic/SanitizerBlacklist.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/XRayLists.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@@ -66,6 +67,7 @@
#include <memory>
#include <new>
#include <string>
+#include <type_traits>
#include <utility>
#include <vector>
@@ -167,18 +169,20 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<DependentUnaryTransformType>
DependentUnaryTransformTypes;
mutable llvm::FoldingSet<AutoType> AutoTypes;
+ mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
+ DeducedTemplateSpecializationTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;
mutable llvm::FoldingSet<PipeType> PipeTypes;
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
- mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
+ mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
SubstTemplateTemplateParms;
mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
- ASTContext&>
+ ASTContext&>
SubstTemplateTemplateParmPacks;
-
+
/// \brief The set of nested name specifiers.
///
/// This set is managed by the NestedNameSpecifier class.
@@ -200,17 +204,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief A cache mapping from CXXRecordDecls to key functions.
llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr> KeyFunctions;
-
+
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
-
+
/// \brief Mapping from ObjCMethod to its duplicate declaration in the same
/// interface.
llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls;
/// \brief Mapping from __block VarDecls to their copy initialization expr.
llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
-
+
/// \brief Mapping from class scope functions specialization to their
/// template patterns.
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
@@ -226,21 +230,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// is used in canonical template names.
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
TemplateTemplateParmDecl *Parm;
-
+
public:
- CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm)
+ CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm)
: Parm(Parm) { }
-
+
TemplateTemplateParmDecl *getParam() const { return Parm; }
-
+
void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Parm); }
-
- static void Profile(llvm::FoldingSetNodeID &ID,
+
+ static void Profile(llvm::FoldingSetNodeID &ID,
TemplateTemplateParmDecl *Parm);
};
mutable llvm::FoldingSet<CanonicalTemplateTemplateParm>
CanonTemplateTemplateParms;
-
+
TemplateTemplateParmDecl *
getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
@@ -259,7 +263,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief The typedef for the predefined \c id type.
mutable TypedefDecl *ObjCIdDecl;
-
+
/// \brief The typedef for the predefined \c SEL type.
mutable TypedefDecl *ObjCSelDecl;
@@ -268,7 +272,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief The typedef for the predefined \c Protocol class in Objective-C.
mutable ObjCInterfaceDecl *ObjCProtocolClassDecl;
-
+
/// \brief The typedef for the predefined 'BOOL' type.
mutable TypedefDecl *BOOLDecl;
@@ -298,12 +302,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable TypedefDecl *CFConstantStringTypeDecl;
mutable QualType ObjCSuperType;
-
+
QualType ObjCNSStringType;
/// \brief The typedef declaration for the Objective-C "instancetype" type.
TypedefDecl *ObjCInstanceTypeDecl;
-
+
/// \brief The type for the C FILE type.
TypeDecl *FILEDecl;
@@ -451,11 +455,11 @@ private:
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable;
- ParameterIndexTable ParamIndices;
-
+ ParameterIndexTable ParamIndices;
+
ImportDecl *FirstLocalImport;
ImportDecl *LastLocalImport;
-
+
TranslationUnitDecl *TUDecl;
mutable ExternCContextDecl *ExternCContext;
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl;
@@ -472,6 +476,10 @@ private:
/// entities should not be instrumented.
std::unique_ptr<SanitizerBlacklist> SanitizerBL;
+ /// \brief Function filtering mechanism to determine whether a given function
+ /// should be imbued with the XRay "always" or "never" attributes.
+ std::unique_ptr<XRayFunctionFilter> XRayFilter;
+
/// \brief The allocator used to create AST objects.
///
/// AST objects are never destructed; rather, all memory associated with the
@@ -488,7 +496,7 @@ private:
/// \brief The logical -> physical address space map.
const LangAS::Map *AddrSpaceMap;
- /// \brief Address space map mangling must be used with language specific
+ /// \brief Address space map mangling must be used with language specific
/// address spaces (e.g. OpenCL/CUDA)
bool AddrSpaceMapMangling;
@@ -500,7 +508,7 @@ private:
const TargetInfo *Target;
const TargetInfo *AuxTarget;
clang::PrintingPolicy PrintingPolicy;
-
+
public:
IdentifierTable &Idents;
SelectorTable &Selectors;
@@ -604,7 +612,7 @@ public:
void setPrintingPolicy(const clang::PrintingPolicy &Policy) {
PrintingPolicy = Policy;
}
-
+
SourceManager& getSourceManager() { return SourceMgr; }
const SourceManager& getSourceManager() const { return SourceMgr; }
@@ -619,7 +627,7 @@ public:
return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
}
void Deallocate(void *Ptr) const { }
-
+
/// Return the total amount of physical memory allocated for representing
/// AST nodes and type information.
size_t getASTAllocatedMemory() const {
@@ -627,7 +635,7 @@ public:
}
/// Return the total memory used for various side tables.
size_t getSideTableAllocatedMemory() const;
-
+
PartialDiagnostic::StorageAllocator &getDiagAllocator() {
return DiagAllocator;
}
@@ -647,13 +655,17 @@ public:
QualType getRealTypeForBitwidth(unsigned DestWidth) const;
bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const;
-
+
const LangOptions& getLangOpts() const { return LangOpts; }
const SanitizerBlacklist &getSanitizerBlacklist() const {
return *SanitizerBL;
}
+ const XRayFunctionFilter &getXRayFilter() const {
+ return *XRayFilter;
+ }
+
DiagnosticsEngine &getDiagnostics() const;
FullSourceLoc getFullLoc(SourceLocation Loc) const {
@@ -862,7 +874,7 @@ public:
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
-
+
// Access to the set of methods overridden by the given C++ method.
typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator;
overridden_cxx_method_iterator
@@ -878,7 +890,7 @@ public:
/// \brief Note that the given C++ \p Method overrides the given \p
/// Overridden method.
- void addOverriddenMethod(const CXXMethodDecl *Method,
+ void addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden);
/// \brief Return C++ or ObjC overridden methods for the given \p Method.
@@ -891,7 +903,7 @@ public:
void getOverriddenMethods(
const NamedDecl *Method,
SmallVectorImpl<const NamedDecl *> &Overridden) const;
-
+
/// \brief Notify the AST context that a new import declaration has been
/// parsed or implicitly created within this translation unit.
void addedLocalImportDecl(ImportDecl *Import);
@@ -899,7 +911,7 @@ public:
static ImportDecl *getNextLocalImport(ImportDecl *Import) {
return Import->NextLocalImport;
}
-
+
typedef llvm::iterator_range<import_iterator> import_range;
import_range local_imports() const {
return import_range(import_iterator(FirstLocalImport), import_iterator());
@@ -923,7 +935,7 @@ public:
/// \brief Get the additional modules in which the definition \p Def has
/// been merged.
- ArrayRef<Module*> getModulesWithMergedDefinition(NamedDecl *Def) {
+ ArrayRef<Module*> getModulesWithMergedDefinition(const NamedDecl *Def) {
auto MergedIt = MergedDefModules.find(Def);
if (MergedIt == MergedDefModules.end())
return None;
@@ -973,7 +985,7 @@ public:
CanQualType SingletonId;
#include "clang/Basic/OpenCLImageTypes.def"
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
- CanQualType OCLQueueTy, OCLNDRangeTy, OCLReserveIDTy;
+ CanQualType OCLQueueTy, OCLReserveIDTy;
CanQualType OMPArraySectionTy;
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
@@ -1179,15 +1191,15 @@ public:
/// Returns true iff we need copy/dispose helpers for the given type.
bool BlockRequiresCopying(QualType Ty, const VarDecl *D);
-
-
+
+
/// Returns true, if given type has a known lifetime. HasByrefExtendedLayout is set
/// to false in this case. If HasByrefExtendedLayout returns true, byref variable
- /// has extended lifetime.
+ /// has extended lifetime.
bool getByrefLifetime(QualType Ty,
Qualifiers::ObjCLifetime &Lifetime,
bool &HasByrefExtendedLayout) const;
-
+
/// \brief Return the uniqued reference to the type for an lvalue reference
/// to the specified type.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true)
@@ -1231,7 +1243,7 @@ public:
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals) const;
-
+
/// \brief Returns a vla type where known sizes are replaced with [*].
QualType getVariableArrayDecayedType(QualType Ty) const;
@@ -1355,6 +1367,8 @@ public:
ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args) const;
+ TemplateArgument getInjectedTemplateArg(NamedDecl *ParamDecl);
+
/// Get a template argument list with one argument per template parameter
/// in a template parameter list, such as for the injected class name of
/// a class template.
@@ -1380,7 +1394,7 @@ public:
QualType getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
ArrayRef<ObjCProtocolDecl *> protocols,
QualType Canonical = QualType()) const;
-
+
bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
/// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in
/// QT's qualified-id protocol list adopt all protocols in IDecl's list
@@ -1412,6 +1426,11 @@ public:
/// \brief C++11 deduction pattern for 'auto &&' type.
QualType getAutoRRefDeductType() const;
+ /// \brief C++1z deduced class template specialization type.
+ QualType getDeducedTemplateSpecializationType(TemplateName Template,
+ QualType DeducedType,
+ bool IsDependent) const;
+
/// \brief Return the unique reference to the type for the specified TagDecl
/// (struct/union/class/enum) decl.
QualType getTagDeclType(const TagDecl *Decl) const;
@@ -1422,6 +1441,10 @@ public:
/// The sizeof operator requires this (C99 6.5.3.4p4).
CanQualType getSizeType() const;
+ /// \brief Return the unique signed counterpart of
+ /// the integer type corresponding to size_t.
+ CanQualType getSignedSizeType() const;
+
/// \brief Return the unique type for "intmax_t" (C99 7.18.1.5), defined in
/// <stdint.h>.
CanQualType getIntMaxType() const;
@@ -1471,11 +1494,11 @@ public:
/// \brief Return the C structure type used to represent constant CFStrings.
QualType getCFConstantStringType() const;
-
+
/// \brief Returns the C struct type for objc_super
QualType getObjCSuperType() const;
void setObjCSuperType(QualType ST) { ObjCSuperType = ST; }
-
+
/// Get the structure type used to representation CFStrings, or NULL
/// if it hasn't yet been built.
QualType getRawCFConstantStringType() const {
@@ -1496,11 +1519,11 @@ public:
QualType getObjCNSStringType() const {
return ObjCNSStringType;
}
-
+
void setObjCNSStringType(QualType T) {
ObjCNSStringType = T;
}
-
+
/// \brief Retrieve the type that \c id has been defined to, which may be
/// different from the built-in \c id if \c id has been typedef'd.
QualType getObjCIdRedefinitionType() const {
@@ -1508,7 +1531,7 @@ public:
return getObjCIdType();
return ObjCIdRedefinitionType;
}
-
+
/// \brief Set the user-written type that redefines \c id.
void setObjCIdRedefinitionType(QualType RedefType) {
ObjCIdRedefinitionType = RedefType;
@@ -1521,7 +1544,7 @@ public:
return getObjCClassType();
return ObjCClassRedefinitionType;
}
-
+
/// \brief Set the user-written type that redefines 'SEL'.
void setObjCClassRedefinitionType(QualType RedefType) {
ObjCClassRedefinitionType = RedefType;
@@ -1534,7 +1557,7 @@ public:
return getObjCSelType();
return ObjCSelRedefinitionType;
}
-
+
/// \brief Set the user-written type that redefines 'SEL'.
void setObjCSelRedefinitionType(QualType RedefType) {
ObjCSelRedefinitionType = RedefType;
@@ -1586,7 +1609,7 @@ public:
/// \brief Retrieve the typedef declaration corresponding to the Objective-C
/// "instancetype" type.
TypedefDecl *getObjCInstanceTypeDecl();
-
+
/// \brief Set the type for the C FILE type.
void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; }
@@ -1671,7 +1694,7 @@ public:
/// \brief Return the encoded type for this block declaration.
std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const;
-
+
/// getObjCEncodingForPropertyDecl - Return the encoded type for
/// this method declaration. If non-NULL, Container must be either
/// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should
@@ -1681,7 +1704,7 @@ public:
bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
ObjCProtocolDecl *rProto) const;
-
+
ObjCPropertyImplDecl *getObjCPropertyImplDeclForPropertyDecl(
const ObjCPropertyDecl *PD,
const Decl *Container) const;
@@ -1693,7 +1716,7 @@ public:
/// \brief Retrieve the typedef corresponding to the predefined \c id type
/// in Objective-C.
TypedefDecl *getObjCIdDecl() const;
-
+
/// \brief Represents the Objective-CC \c id type.
///
/// This is set up lazily, by Sema. \c id is always a (typedef for a)
@@ -1705,26 +1728,26 @@ public:
/// \brief Retrieve the typedef corresponding to the predefined 'SEL' type
/// in Objective-C.
TypedefDecl *getObjCSelDecl() const;
-
+
/// \brief Retrieve the type that corresponds to the predefined Objective-C
/// 'SEL' type.
- QualType getObjCSelType() const {
+ QualType getObjCSelType() const {
return getTypeDeclType(getObjCSelDecl());
}
/// \brief Retrieve the typedef declaration corresponding to the predefined
/// Objective-C 'Class' type.
TypedefDecl *getObjCClassDecl() const;
-
+
/// \brief Represents the Objective-C \c Class type.
///
/// This is set up lazily, by Sema. \c Class is always a (typedef for a)
/// pointer type, a pointer to a struct.
- QualType getObjCClassType() const {
+ QualType getObjCClassType() const {
return getTypeDeclType(getObjCClassDecl());
}
- /// \brief Retrieve the Objective-C class declaration corresponding to
+ /// \brief Retrieve the Objective-C class declaration corresponding to
/// the predefined \c Protocol class.
ObjCInterfaceDecl *getObjCProtocolDecl() const;
@@ -1742,12 +1765,12 @@ public:
QualType getBOOLType() const {
return getTypeDeclType(getBOOLDecl());
}
-
+
/// \brief Retrieve the type of the Objective-C \c Protocol class.
QualType getObjCProtoType() const {
return getObjCInterfaceType(getObjCProtocolDecl());
}
-
+
/// \brief Retrieve the C type declaration corresponding to the predefined
/// \c __builtin_va_list type.
TypedefDecl *getBuiltinVaListDecl() const;
@@ -1810,7 +1833,7 @@ public:
qs.addObjCLifetime(lifetime);
return getQualifiedType(type, qs);
}
-
+
/// getUnqualifiedObjCPointerType - Returns version of
/// Objective-C pointer type with lifetime qualifier removed.
QualType getUnqualifiedObjCPointerType(QualType type) const {
@@ -1821,7 +1844,7 @@ public:
Qs.removeObjCLifetime();
return getQualifiedType(type.getUnqualifiedType(), Qs);
}
-
+
DeclarationNameInfo getNameForTemplate(TemplateName Name,
SourceLocation NameLoc) const;
@@ -1840,7 +1863,7 @@ public:
TemplateName replacement) const;
TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
const TemplateArgument &ArgPack) const;
-
+
enum GetBuiltinTypeError {
GE_None, ///< No error
GE_Missing_stdio, ///< Missing a type from <stdio.h>
@@ -1905,7 +1928,7 @@ public:
uint64_t getCharWidth() const {
return getTypeSize(CharTy);
}
-
+
/// \brief Convert a size in bits to a size in characters.
CharUnits toCharUnitsFromBits(int64_t BitSize) const;
@@ -1927,11 +1950,11 @@ public:
/// example, from alignment attributes).
unsigned getTypeAlignIfKnown(QualType T) const;
- /// \brief Return the ABI-specified alignment of a (complete) type \p T, in
+ /// \brief Return the ABI-specified alignment of a (complete) type \p T, in
/// characters.
CharUnits getTypeAlignInChars(QualType T) const;
CharUnits getTypeAlignInChars(const Type *T) const;
-
+
// getTypeInfoDataSizeInChars - Return the size of a type, in chars. If the
// type is a record, its data size is returned.
std::pair<CharUnits, CharUnits> getTypeInfoDataSizeInChars(QualType T) const;
@@ -2031,15 +2054,20 @@ public:
/// Get the offset of a FieldDecl or IndirectFieldDecl, in bits.
uint64_t getFieldOffset(const ValueDecl *FD) const;
+ /// Get the offset of an ObjCIvarDecl in bits.
+ uint64_t lookupFieldBitOffset(const ObjCInterfaceDecl *OID,
+ const ObjCImplementationDecl *ID,
+ const ObjCIvarDecl *Ivar) const;
+
bool isNearlyEmpty(const CXXRecordDecl *RD) const;
VTableContextBase *getVTableContext();
MangleContext *createMangleContext();
-
+
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const;
-
+
unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const;
void CollectInheritedProtocols(const Decl *CDecl,
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
@@ -2115,7 +2143,7 @@ public:
*SubTnullability == NullabilityKind::Unspecified ||
*SuperTnullability == NullabilityKind::Unspecified)
return true;
-
+
if (IsParam) {
// Ok for the superclass method parameter to be "nonnull" and the subclass
// method parameter to be "nullable"
@@ -2134,9 +2162,9 @@ public:
bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
const ObjCMethodDecl *MethodImp);
-
+
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);
-
+
/// \brief Retrieves the "canonical" nested name specifier for a
/// given nested name specifier.
///
@@ -2190,7 +2218,7 @@ public:
/// \brief Determine whether the given template names refer to the same
/// template.
bool hasSameTemplateName(TemplateName X, TemplateName Y);
-
+
/// \brief Retrieve the "canonical" template argument.
///
/// The canonical template argument is the simplest template argument
@@ -2217,7 +2245,7 @@ public:
const {
return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T));
}
-
+
/// \brief Return the innermost element type of an array type.
///
/// For example, will return "int" for int[m][n]
@@ -2236,14 +2264,14 @@ public:
/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8],
/// C++ [dcl.fct]p3). The adjusted parameter type is returned.
QualType getAdjustedParameterType(QualType T) const;
-
+
/// \brief Retrieve the parameter type as adjusted for use in the signature
/// of a function, decaying array and function types and removing top-level
/// cv-qualifiers.
QualType getSignatureParameterType(QualType T) const;
-
+
QualType getExceptionObjectType(QualType T) const;
-
+
/// \brief Return the properly qualified result of decaying the specified
/// array type to a pointer.
///
@@ -2269,7 +2297,7 @@ public:
/// promotion occurs.
QualType isPromotableBitField(Expr *E) const;
- /// \brief Return the highest ranked integer type, see C99 6.3.1.8p1.
+ /// \brief Return the highest ranked integer type, see C99 6.3.1.8p1.
///
/// If \p LHS > \p RHS, returns 1. If \p LHS == \p RHS, returns 0. If
/// \p LHS < \p RHS, return -1.
@@ -2298,21 +2326,14 @@ public:
return getTargetAddressSpace(Q.getAddressSpace());
}
- unsigned getTargetAddressSpace(unsigned AS) const {
- if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count)
- return AS;
- else
- return (*AddrSpaceMap)[AS - LangAS::Offset];
- }
+ unsigned getTargetAddressSpace(unsigned AS) const;
/// Get target-dependent integer value for null pointer which is used for
/// constant folding.
uint64_t getTargetNullPointerValue(QualType QT) const;
bool addressSpaceMapManglingFor(unsigned AS) const {
- return AddrSpaceMapMangling ||
- AS < LangAS::Offset ||
- AS >= LangAS::Offset + LangAS::Count;
+ return AddrSpaceMapMangling || AS >= LangAS::FirstTargetAddressSpace;
}
private:
@@ -2325,11 +2346,11 @@ public:
//===--------------------------------------------------------------------===//
/// Compatibility predicates used to check assignment expressions.
- bool typesAreCompatible(QualType T1, QualType T2,
+ bool typesAreCompatible(QualType T1, QualType T2,
bool CompareUnqualified = false); // C99 6.2.7p1
- bool propertyTypesAreCompatible(QualType, QualType);
- bool typesAreBlockPointerCompatible(QualType, QualType);
+ bool propertyTypesAreCompatible(QualType, QualType);
+ bool typesAreBlockPointerCompatible(QualType, QualType);
bool isObjCIdType(QualType T) const {
return T == getObjCIdType();
@@ -2344,7 +2365,7 @@ public:
bool ForCompare);
bool ObjCQualifiedClassTypesAreCompatible(QualType LHS, QualType RHS);
-
+
// Check the safety of assignment from LHS to RHS
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT);
@@ -2370,9 +2391,9 @@ public:
QualType mergeTransparentUnionType(QualType, QualType,
bool OfBlockPointer=false,
bool Unqualified = false);
-
+
QualType mergeObjCGCQualifiers(QualType, QualType);
-
+
bool doFunctionTypesMatchOnExtParameterInfos(
const FunctionProtoType *FromFunctionType,
const FunctionProtoType *ToFunctionType);
@@ -2442,7 +2463,7 @@ public:
/// an Objective-C method/property/ivar etc. that is part of an interface,
/// otherwise returns null.
const ObjCInterfaceDecl *getObjContainingInterface(const NamedDecl *ND) const;
-
+
/// \brief Set the copy inialization expression of a block var decl.
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
/// \brief Get the copy initialization expression of the VarDecl \p VD, or
@@ -2466,10 +2487,10 @@ public:
/// initialized to a given location, which defaults to the empty
/// location.
TypeSourceInfo *
- getTrivialTypeSourceInfo(QualType T,
+ getTrivialTypeSourceInfo(QualType T,
SourceLocation Loc = SourceLocation()) const;
- /// \brief Add a deallocation callback that will be invoked when the
+ /// \brief Add a deallocation callback that will be invoked when the
/// ASTContext is destroyed.
///
/// \param Callback A callback function that will be invoked on destruction.
@@ -2478,6 +2499,16 @@ public:
/// when it is called.
void AddDeallocation(void (*Callback)(void*), void *Data);
+ /// If T isn't trivially destructible, calls AddDeallocation to register it
+ /// for destruction.
+ template <typename T>
+ void addDestruction(T *Ptr) {
+ if (!std::is_trivially_destructible<T>::value) {
+ auto DestroyPtr = [](void *V) { static_cast<T *>(V)->~T(); };
+ AddDeallocation(DestroyPtr, Ptr);
+ }
+ }
+
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const;
GVALinkage GetGVALinkageForVariable(const VarDecl *VD);
@@ -2534,15 +2565,15 @@ public:
/// \brief The number of implicitly-declared default constructors.
static unsigned NumImplicitDefaultConstructors;
-
- /// \brief The number of implicitly-declared default constructors for
+
+ /// \brief The number of implicitly-declared default constructors for
/// which declarations were built.
static unsigned NumImplicitDefaultConstructorsDeclared;
/// \brief The number of implicitly-declared copy constructors.
static unsigned NumImplicitCopyConstructors;
-
- /// \brief The number of implicitly-declared copy constructors for
+
+ /// \brief The number of implicitly-declared copy constructors for
/// which declarations were built.
static unsigned NumImplicitCopyConstructorsDeclared;
@@ -2555,25 +2586,25 @@ public:
/// \brief The number of implicitly-declared copy assignment operators.
static unsigned NumImplicitCopyAssignmentOperators;
-
- /// \brief The number of implicitly-declared copy assignment operators for
+
+ /// \brief The number of implicitly-declared copy assignment operators for
/// which declarations were built.
static unsigned NumImplicitCopyAssignmentOperatorsDeclared;
/// \brief The number of implicitly-declared move assignment operators.
static unsigned NumImplicitMoveAssignmentOperators;
-
- /// \brief The number of implicitly-declared move assignment operators for
+
+ /// \brief The number of implicitly-declared move assignment operators for
/// which declarations were built.
static unsigned NumImplicitMoveAssignmentOperatorsDeclared;
/// \brief The number of implicitly-declared destructors.
static unsigned NumImplicitDestructors;
-
- /// \brief The number of implicitly-declared destructors for which
+
+ /// \brief The number of implicitly-declared destructors for which
/// declarations were built.
static unsigned NumImplicitDestructorsDeclared;
-
+
public:
/// \brief Initialize built-in types.
///
diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTStructuralEquivalence.h b/contrib/llvm/tools/clang/include/clang/AST/ASTStructuralEquivalence.h
new file mode 100644
index 0000000..23674c6
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/AST/ASTStructuralEquivalence.h
@@ -0,0 +1,103 @@
+//===--- ASTStructuralEquivalence.h - ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the StructuralEquivalenceContext class which checks for
+// structural equivalence between types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
+#define LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+#include <deque>
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class DiagnosticBuilder;
+class QualType;
+class RecordDecl;
+class SourceLocation;
+
+struct StructuralEquivalenceContext {
+ /// AST contexts for which we are checking structural equivalence.
+ ASTContext &FromCtx, &ToCtx;
+
+ /// The set of "tentative" equivalences between two canonical
+ /// declarations, mapping from a declaration in the first context to the
+ /// declaration in the second context that we believe to be equivalent.
+ llvm::DenseMap<Decl *, Decl *> TentativeEquivalences;
+
+ /// Queue of declarations in the first context whose equivalence
+ /// with a declaration in the second context still needs to be verified.
+ std::deque<Decl *> DeclsToCheck;
+
+ /// Declaration (from, to) pairs that are known not to be equivalent
+ /// (which we have already complained about).
+ llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls;
+
+ /// Whether we're being strict about the spelling of types when
+ /// unifying two types.
+ bool StrictTypeSpelling;
+
+ /// Whether warn or error on tag type mismatches.
+ bool ErrorOnTagTypeMismatch;
+
+ /// Whether to complain about failures.
+ bool Complain;
+
+ /// \c true if the last diagnostic came from ToCtx.
+ bool LastDiagFromC2;
+
+ StructuralEquivalenceContext(
+ ASTContext &FromCtx, ASTContext &ToCtx,
+ llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls,
+ bool StrictTypeSpelling = false, bool Complain = true,
+ bool ErrorOnTagTypeMismatch = false)
+ : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls),
+ StrictTypeSpelling(StrictTypeSpelling),
+ ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain),
+ LastDiagFromC2(false) {}
+
+ DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID);
+ DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID);
+
+ /// Determine whether the two declarations are structurally
+ /// equivalent.
+ bool IsStructurallyEquivalent(Decl *D1, Decl *D2);
+
+ /// Determine whether the two types are structurally equivalent.
+ bool IsStructurallyEquivalent(QualType T1, QualType T2);
+
+ /// Find the index of the given anonymous struct/union within its
+ /// context.
+ ///
+ /// \returns Returns the index of this anonymous struct/union in its context,
+ /// including the next assigned index (if none of them match). Returns an
+ /// empty option if the context is not a record, i.e.. if the anonymous
+ /// struct/union is at namespace or block scope.
+ ///
+ /// FIXME: This is needed by ASTImporter and ASTStructureEquivalence. It
+ /// probably makes more sense in some other common place then here.
+ static llvm::Optional<unsigned>
+ findUntaggedStructOrUnionIndex(RecordDecl *Anon);
+
+private:
+ /// Finish checking all of the structural equivalences.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool Finish();
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_ASTSTRUCTURALEQUIVALENCE_H
diff --git a/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h b/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h
index 9ae5fd6..717a9e9 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/ASTVector.h
@@ -22,6 +22,7 @@
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/type_traits.h"
#include <algorithm>
+#include <cstddef>
#include <cstring>
#include <memory>
diff --git a/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def b/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def
index c0c6819..181131a 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def
+++ b/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def
@@ -169,9 +169,6 @@ BUILTIN_TYPE(OCLClkEvent, OCLClkEventTy)
// OpenCL queue_t.
BUILTIN_TYPE(OCLQueue, OCLQueueTy)
-// OpenCL ndrange_t.
-BUILTIN_TYPE(OCLNDRange, OCLNDRangeTy)
-
// OpenCL reserve_id_t.
BUILTIN_TYPE(OCLReserveID, OCLReserveIDTy)
diff --git a/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h b/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h
index 3cf058f..9806085 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/CXXInheritance.h
@@ -127,7 +127,11 @@ class CXXBasePaths {
/// class subobjects for that class type. The key of the map is
/// the cv-unqualified canonical type of the base class subobject.
llvm::SmallDenseMap<QualType, std::pair<bool, unsigned>, 8> ClassSubobjects;
-
+
+ /// VisitedDependentRecords - Records the dependent records that have been
+ /// already visited.
+ llvm::SmallDenseSet<const CXXRecordDecl *, 4> VisitedDependentRecords;
+
/// FindAmbiguities - Whether Sema::IsDerivedFrom should try find
/// ambiguous paths while it is looking for a path from a derived
/// type to a base type.
@@ -161,7 +165,8 @@ class CXXBasePaths {
void ComputeDeclsFound();
bool lookupInBases(ASTContext &Context, const CXXRecordDecl *Record,
- CXXRecordDecl::BaseMatchesCallback BaseMatches);
+ CXXRecordDecl::BaseMatchesCallback BaseMatches,
+ bool LookupInDependent = false);
public:
typedef std::list<CXXBasePath>::iterator paths_iterator;
diff --git a/contrib/llvm/tools/clang/include/clang/AST/CommentSema.h b/contrib/llvm/tools/clang/include/clang/AST/CommentSema.h
index 6a80383..230e527 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/CommentSema.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/CommentSema.h
@@ -208,6 +208,10 @@ public:
/// \returns \c true if declaration that this comment is attached to declares
/// a function pointer.
bool isFunctionPointerVarDecl();
+ /// \returns \c true if the declaration that this comment is attached to
+ /// declares a variable or a field whose type is a function or a block
+ /// pointer.
+ bool isFunctionOrBlockPointerVarLikeDecl();
bool isFunctionOrMethodVariadic();
bool isObjCMethodDecl();
bool isObjCPropertyDecl();
diff --git a/contrib/llvm/tools/clang/include/clang/AST/Decl.h b/contrib/llvm/tools/clang/include/clang/AST/Decl.h
index 8b52891..54e6ebc 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Decl.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/Decl.h
@@ -301,16 +301,6 @@ public:
using Decl::isModulePrivate;
using Decl::setModulePrivate;
- /// \brief Determine whether this declaration is hidden from name lookup.
- bool isHidden() const { return Hidden; }
-
- /// \brief Set whether this declaration is hidden from name lookup.
- void setHidden(bool Hide) {
- assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) &&
- "declaration with no owning module can't be hidden");
- Hidden = Hide;
- }
-
/// \brief Determine whether this declaration is a C++ class member.
bool isCXXClassMember() const {
const DeclContext *DC = getDeclContext();
@@ -838,7 +828,7 @@ protected:
/// Describes the kind of default argument for this parameter. By default
/// this is none. If this is normal, then the default argument is stored in
- /// the \c VarDecl initalizer expression unless we were unble to parse
+ /// the \c VarDecl initializer expression unless we were unable to parse
/// (even an invalid) expression for the default argument.
unsigned DefaultArgKind : 2;
@@ -861,6 +851,7 @@ protected:
class NonParmVarDeclBitfields {
friend class VarDecl;
+ friend class ImplicitParamDecl;
friend class ASTDeclReader;
unsigned : NumVarDeclBits;
@@ -904,6 +895,10 @@ protected:
/// declared in the same block scope. This controls whether we should merge
/// the type of this declaration with its previous declaration.
unsigned PreviousDeclInSameBlockScope : 1;
+
+ /// Defines kind of the ImplicitParamDecl: 'this', 'self', 'vtt', '_cmd' or
+ /// something else.
+ unsigned ImplicitParamKind : 3;
};
union {
@@ -966,9 +961,16 @@ public:
/// hasLocalStorage - Returns true if a variable with function scope
/// is a non-static local variable.
bool hasLocalStorage() const {
- if (getStorageClass() == SC_None)
+ if (getStorageClass() == SC_None) {
+ // OpenCL v1.2 s6.5.3: The __constant or constant address space name is
+ // used to describe variables allocated in global memory and which are
+ // accessed inside a kernel(s) as read-only variables. As such, variables
+ // in constant address space cannot have local storage.
+ if (getType().getAddressSpace() == LangAS::opencl_constant)
+ return false;
// Second check is for C++11 [dcl.stc]p4.
return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
+ }
// Global Named Register (GNU extension)
if (getStorageClass() == SC_Register && !isLocalVarDeclOrParm())
@@ -1379,20 +1381,50 @@ public:
class ImplicitParamDecl : public VarDecl {
void anchor() override;
+
public:
+ /// Defines the kind of the implicit parameter: is this an implicit parameter
+ /// with pointer to 'this', 'self', '_cmd', virtual table pointers, captured
+ /// context or something else.
+ enum ImplicitParamKind : unsigned {
+ ObjCSelf, /// Parameter for Objective-C 'self' argument
+ ObjCCmd, /// Parameter for Objective-C '_cmd' argument
+ CXXThis, /// Parameter for C++ 'this' argument
+ CXXVTT, /// Parameter for C++ virtual table pointers
+ CapturedContext, /// Parameter for captured context
+ Other, /// Other implicit parameter
+ };
+
+ /// Create implicit parameter.
static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc, IdentifierInfo *Id,
- QualType T);
+ QualType T, ImplicitParamKind ParamKind);
+ static ImplicitParamDecl *Create(ASTContext &C, QualType T,
+ ImplicitParamKind ParamKind);
static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc,
- IdentifierInfo *Id, QualType Type)
- : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type,
- /*tinfo*/ nullptr, SC_None) {
+ IdentifierInfo *Id, QualType Type,
+ ImplicitParamKind ParamKind)
+ : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type,
+ /*TInfo=*/nullptr, SC_None) {
+ NonParmVarDeclBits.ImplicitParamKind = ParamKind;
+ setImplicit();
+ }
+
+ ImplicitParamDecl(ASTContext &C, QualType Type, ImplicitParamKind ParamKind)
+ : VarDecl(ImplicitParam, C, /*DC=*/nullptr, SourceLocation(),
+ SourceLocation(), /*Id=*/nullptr, Type,
+ /*TInfo=*/nullptr, SC_None) {
+ NonParmVarDeclBits.ImplicitParamKind = ParamKind;
setImplicit();
}
+ /// Returns the implicit parameter kind.
+ ImplicitParamKind getParameterKind() const {
+ return static_cast<ImplicitParamKind>(NonParmVarDeclBits.ImplicitParamKind);
+ }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ImplicitParam; }
@@ -1605,9 +1637,14 @@ private:
// FIXME: This can be packed into the bitfields in DeclContext.
// NOTE: VC++ packs bitfields poorly if the types differ.
- unsigned SClass : 2;
+ unsigned SClass : 3;
unsigned IsInline : 1;
unsigned IsInlineSpecified : 1;
+protected:
+ // This is shared by CXXConstructorDecl, CXXConversionDecl, and
+ // CXXDeductionGuideDecl.
+ unsigned IsExplicitSpecified : 1;
+private:
unsigned IsVirtualAsWritten : 1;
unsigned IsPure : 1;
unsigned HasInheritedPrototype : 1;
@@ -1619,6 +1656,7 @@ private:
unsigned HasImplicitReturnZero : 1;
unsigned IsLateTemplateParsed : 1;
unsigned IsConstexpr : 1;
+ unsigned InstantiationIsPending:1;
/// \brief Indicates if the function uses __try.
unsigned UsesSEHTry : 1;
@@ -1628,8 +1666,7 @@ private:
unsigned HasSkippedBody : 1;
/// Indicates if the function declaration will have a body, once we're done
- /// parsing it. (We don't set it to false when we're done parsing, in the
- /// hopes this is simpler.)
+ /// parsing it.
unsigned WillHaveBody : 1;
/// \brief End part of this FunctionDecl's source range.
@@ -1708,11 +1745,13 @@ protected:
StartLoc),
DeclContext(DK), redeclarable_base(C), ParamInfo(nullptr), Body(),
SClass(S), IsInline(isInlineSpecified),
- IsInlineSpecified(isInlineSpecified), IsVirtualAsWritten(false),
- IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true),
+ IsInlineSpecified(isInlineSpecified), IsExplicitSpecified(false),
+ IsVirtualAsWritten(false), IsPure(false),
+ HasInheritedPrototype(false), HasWrittenPrototype(true),
IsDeleted(false), IsTrivial(false), IsDefaulted(false),
IsExplicitlyDefaulted(false), HasImplicitReturnZero(false),
IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified),
+ InstantiationIsPending(false),
UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false),
EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(),
DNLoc(NameInfo.getInfo()) {}
@@ -1826,14 +1865,15 @@ public:
return getBody(Definition);
}
- /// isThisDeclarationADefinition - Returns whether this specific
- /// declaration of the function is also a definition. This does not
- /// determine whether the function has been defined (e.g., in a
- /// previous definition); for that information, use isDefined. Note
- /// that this returns false for a defaulted function unless that function
- /// has been implicitly defined (possibly as deleted).
+ /// Returns whether this specific declaration of the function is also a
+ /// definition that does not contain uninstantiated body.
+ ///
+ /// This does not determine whether the function has been defined (e.g., in a
+ /// previous definition); for that information, use isDefined.
+ ///
bool isThisDeclarationADefinition() const {
- return IsDeleted || Body || IsLateTemplateParsed;
+ return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
+ WillHaveBody || hasDefiningAttr();
}
/// doesThisDeclarationHaveABody - Returns whether this specific
@@ -1904,6 +1944,15 @@ public:
bool isConstexpr() const { return IsConstexpr; }
void setConstexpr(bool IC) { IsConstexpr = IC; }
+ /// \brief Whether the instantiation of this function is pending.
+ /// This bit is set when the decision to instantiate this function is made
+ /// and unset if and when the function body is created. That leaves out
+ /// cases where instantiation did not happen because the template definition
+ /// was not seen in this TU. This bit remains set in those cases, under the
+ /// assumption that the instantiation will happen in some other TU.
+ bool instantiationIsPending() const { return InstantiationIsPending; }
+ void setInstantiationIsPending(bool IC) { InstantiationIsPending = IC; }
+
/// \brief Indicates the function uses __try.
bool usesSEHTry() const { return UsesSEHTry; }
void setUsesSEHTry(bool UST) { UsesSEHTry = UST; }
@@ -1969,7 +2018,10 @@ public:
/// These functions have special behavior under C++1y [expr.new]:
/// An implementation is allowed to omit a call to a replaceable global
/// allocation function. [...]
- bool isReplaceableGlobalAllocationFunction() const;
+ ///
+ /// If this function is an aligned allocation/deallocation function, return
+ /// true through IsAligned.
+ bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const;
/// Compute the language linkage.
LanguageLinkage getLanguageLinkage() const;
@@ -2076,10 +2128,7 @@ public:
const Attr *getUnusedResultAttr() const;
/// \brief Returns true if this function or its return type has the
- /// warn_unused_result attribute. If the return type has the attribute and
- /// this function is a method of the return type's class, then false will be
- /// returned to avoid spurious warnings on member methods such as assignment
- /// operators.
+ /// warn_unused_result attribute.
bool hasUnusedResultAttr() const { return getUnusedResultAttr() != nullptr; }
/// \brief Returns the storage class as written in the source. For the
@@ -2475,7 +2524,7 @@ public:
void setCapturedVLAType(const VariableArrayType *VLAType);
/// getParent - Returns the parent of this field declaration, which
- /// is the struct in which this method is defined.
+ /// is the struct in which this field is defined.
const RecordDecl *getParent() const {
return cast<RecordDecl>(getDeclContext());
}
@@ -2635,12 +2684,17 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
typedef std::pair<TypeSourceInfo*, QualType> ModedTInfo;
llvm::PointerUnion<TypeSourceInfo*, ModedTInfo*> MaybeModedTInfo;
+ // FIXME: This can be packed into the bitfields in Decl.
+ /// If 0, we have not computed IsTransparentTag.
+ /// Otherwise, IsTransparentTag is (CacheIsTransparentTag >> 1).
+ mutable unsigned CacheIsTransparentTag : 2;
+
protected:
TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo)
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C),
- MaybeModedTInfo(TInfo) {}
+ MaybeModedTInfo(TInfo), CacheIsTransparentTag(0) {}
typedef Redeclarable<TypedefNameDecl> redeclarable_base;
TypedefNameDecl *getNextRedeclarationImpl() override {
@@ -2693,11 +2747,22 @@ public:
/// this typedef declaration.
TagDecl *getAnonDeclWithTypedefName(bool AnyRedecl = false) const;
+ /// Determines if this typedef shares a name and spelling location with its
+ /// underlying tag type, as is the case with the NS_ENUM macro.
+ bool isTransparentTag() const {
+ if (CacheIsTransparentTag)
+ return CacheIsTransparentTag & 0x2;
+ return isTransparentTagSlow();
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstTypedefName && K <= lastTypedefName;
}
+
+private:
+ bool isTransparentTagSlow() const;
};
/// TypedefDecl - Represents the declaration of a typedef-name via the 'typedef'
@@ -3229,6 +3294,18 @@ public:
return isCompleteDefinition() || isFixed();
}
+ /// Returns true if this enum is either annotated with
+ /// enum_extensibility(closed) or isn't annotated with enum_extensibility.
+ bool isClosed() const;
+
+ /// Returns true if this enum is annotated with flag_enum and isn't annotated
+ /// with enum_extensibility(open).
+ bool isClosedFlag() const;
+
+ /// Returns true if this enum is annotated with neither flag_enum nor
+ /// enum_extensibility(open).
+ bool isClosedNonFlag() const;
+
/// \brief Retrieve the enum definition from which this enumeration could
/// be instantiated, if it is an instantiation (rather than a non-template).
EnumDecl *getTemplateInstantiationPattern() const;
diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h
index 5de1d05..041f0fd 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h
@@ -34,6 +34,7 @@ class DeclarationName;
class DependentDiagnostic;
class EnumDecl;
class ExportDecl;
+class ExternalSourceSymbolAttr;
class FunctionDecl;
class FunctionType;
enum Linkage : unsigned char;
@@ -201,26 +202,33 @@ public:
OBJC_TQ_CSNullability = 0x40
};
-protected:
- // Enumeration values used in the bits stored in NextInContextAndBits.
- enum {
- /// \brief Whether this declaration is a top-level declaration (function,
- /// global variable, etc.) that is lexically inside an objc container
- /// definition.
- TopLevelDeclInObjCContainerFlag = 0x01,
-
- /// \brief Whether this declaration is private to the module in which it was
- /// defined.
- ModulePrivateFlag = 0x02
+ /// The kind of ownership a declaration has, for visibility purposes.
+ /// This enumeration is designed such that higher values represent higher
+ /// levels of name hiding.
+ enum class ModuleOwnershipKind : unsigned {
+ /// This declaration is not owned by a module.
+ Unowned,
+ /// This declaration has an owning module, but is globally visible
+ /// (typically because its owning module is visible and we know that
+ /// modules cannot later become hidden in this compilation).
+ /// After serialization and deserialization, this will be converted
+ /// to VisibleWhenImported.
+ Visible,
+ /// This declaration has an owning module, and is visible when that
+ /// module is imported.
+ VisibleWhenImported,
+ /// This declaration has an owning module, but is only visible to
+ /// lookups that occur within that module.
+ ModulePrivate
};
-
+
+protected:
/// \brief The next declaration within the same lexical
/// DeclContext. These pointers form the linked list that is
/// traversed via DeclContext's decls_begin()/decls_end().
///
- /// The extra two bits are used for the TopLevelDeclInObjCContainer and
- /// ModulePrivate bits.
- llvm::PointerIntPair<Decl *, 2, unsigned> NextInContextAndBits;
+ /// The extra two bits are used for the ModuleOwnershipKind.
+ llvm::PointerIntPair<Decl *, 2, ModuleOwnershipKind> NextInContextAndBits;
private:
friend class DeclContext;
@@ -281,6 +289,11 @@ private:
/// are regarded as "referenced" but not "used".
unsigned Referenced : 1;
+ /// \brief Whether this declaration is a top-level declaration (function,
+ /// global variable, etc.) that is lexically inside an objc container
+ /// definition.
+ unsigned TopLevelDeclInObjCContainer : 1;
+
/// \brief Whether statistic collection is enabled.
static bool StatisticsEnabled;
@@ -293,11 +306,6 @@ protected:
/// \brief Whether this declaration was loaded from an AST file.
unsigned FromASTFile : 1;
- /// \brief Whether this declaration is hidden from normal name lookup, e.g.,
- /// because it is was loaded from an AST file is either module-private or
- /// because its submodule has not been made visible.
- unsigned Hidden : 1;
-
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
unsigned IdentifierNamespace : 13;
@@ -331,26 +339,38 @@ protected:
private:
bool AccessDeclContextSanity() const;
-protected:
+ /// Get the module ownership kind to use for a local lexical child of \p DC,
+ /// which may be either a local or (rarely) an imported declaration.
+ static ModuleOwnershipKind getModuleOwnershipKindForChildOf(DeclContext *DC) {
+ if (DC) {
+ auto *D = cast<Decl>(DC);
+ auto MOK = D->getModuleOwnershipKind();
+ if (MOK != ModuleOwnershipKind::Unowned &&
+ (!D->isFromASTFile() || D->hasLocalOwningModuleStorage()))
+ return MOK;
+ // If D is not local and we have no local module storage, then we don't
+ // need to track module ownership at all.
+ }
+ return ModuleOwnershipKind::Unowned;
+ }
+protected:
Decl(Kind DK, DeclContext *DC, SourceLocation L)
- : NextInContextAndBits(), DeclCtx(DC),
- Loc(L), DeclKind(DK), InvalidDecl(0),
- HasAttrs(false), Implicit(false), Used(false), Referenced(false),
- Access(AS_none), FromASTFile(0), Hidden(DC && cast<Decl>(DC)->Hidden),
- IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
- CacheValidAndLinkage(0)
- {
+ : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)),
+ DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
+ Implicit(false), Used(false), Referenced(false),
+ TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
+ IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
+ CacheValidAndLinkage(0) {
if (StatisticsEnabled) add(DK);
}
Decl(Kind DK, EmptyShell Empty)
- : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0),
- HasAttrs(false), Implicit(false), Used(false), Referenced(false),
- Access(AS_none), FromASTFile(0), Hidden(0),
- IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
- CacheValidAndLinkage(0)
- {
+ : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
+ Implicit(false), Used(false), Referenced(false),
+ TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
+ IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
+ CacheValidAndLinkage(0) {
if (StatisticsEnabled) add(DK);
}
@@ -550,22 +570,21 @@ public:
/// global variable, etc.) that is lexically inside an objc container
/// definition.
bool isTopLevelDeclInObjCContainer() const {
- return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag;
+ return TopLevelDeclInObjCContainer;
}
void setTopLevelDeclInObjCContainer(bool V = true) {
- unsigned Bits = NextInContextAndBits.getInt();
- if (V)
- Bits |= TopLevelDeclInObjCContainerFlag;
- else
- Bits &= ~TopLevelDeclInObjCContainerFlag;
- NextInContextAndBits.setInt(Bits);
+ TopLevelDeclInObjCContainer = V;
}
+ /// \brief Looks on this and related declarations for an applicable
+ /// external source symbol attribute.
+ ExternalSourceSymbolAttr *getExternalSourceSymbolAttr() const;
+
/// \brief Whether this declaration was marked as being private to the
/// module in which it was defined.
bool isModulePrivate() const {
- return NextInContextAndBits.getInt() & ModulePrivateFlag;
+ return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate;
}
/// \brief Whether this declaration is exported (by virtue of being lexically
@@ -580,15 +599,14 @@ public:
const Attr *getDefiningAttr() const;
protected:
- /// \brief Specify whether this declaration was marked as being private
+ /// \brief Specify that this declaration was marked as being private
/// to the module in which it was defined.
- void setModulePrivate(bool MP = true) {
- unsigned Bits = NextInContextAndBits.getInt();
- if (MP)
- Bits |= ModulePrivateFlag;
- else
- Bits &= ~ModulePrivateFlag;
- NextInContextAndBits.setInt(Bits);
+ void setModulePrivate() {
+ // The module-private specifier has no effect on unowned declarations.
+ // FIXME: We should track this in some way for source fidelity.
+ if (getModuleOwnershipKind() == ModuleOwnershipKind::Unowned)
+ return;
+ setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate);
}
/// \brief Set the owning module ID.
@@ -616,6 +634,14 @@ public:
getAvailability(std::string *Message = nullptr,
VersionTuple EnclosingVersion = VersionTuple()) const;
+ /// \brief Retrieve the version of the target platform in which this
+ /// declaration was introduced.
+ ///
+ /// \returns An empty version tuple if this declaration has no 'introduced'
+ /// availability attributes, or the version tuple that's specified in the
+ /// attribute otherwise.
+ VersionTuple getVersionIntroduced() const;
+
/// \brief Determine whether this declaration is marked 'deprecated'.
///
/// \param Message If non-NULL and the declaration is deprecated,
@@ -654,20 +680,19 @@ public:
/// a precompiled header or module) rather than having been parsed.
bool isFromASTFile() const { return FromASTFile; }
- /// \brief Retrieve the global declaration ID associated with this
- /// declaration, which specifies where in the
- unsigned getGlobalID() const {
+ /// \brief Retrieve the global declaration ID associated with this
+ /// declaration, which specifies where this Decl was loaded from.
+ unsigned getGlobalID() const {
if (isFromASTFile())
return *((const unsigned*)this - 1);
return 0;
}
-
+
/// \brief Retrieve the global ID of the module that owns this particular
/// declaration.
unsigned getOwningModuleID() const {
if (isFromASTFile())
return *((const unsigned*)this - 2);
-
return 0;
}
@@ -680,7 +705,7 @@ public:
/// \brief Get the imported owning module, if this decl is from an imported
/// (non-local) module.
Module *getImportedOwningModule() const {
- if (!isFromASTFile())
+ if (!isFromASTFile() || !hasOwningModule())
return nullptr;
return getOwningModuleSlow();
@@ -689,16 +714,59 @@ public:
/// \brief Get the local owning module, if known. Returns nullptr if owner is
/// not yet known or declaration is not from a module.
Module *getLocalOwningModule() const {
- if (isFromASTFile() || !Hidden)
+ if (isFromASTFile() || !hasOwningModule())
return nullptr;
+
+ assert(hasLocalOwningModuleStorage() &&
+ "owned local decl but no local module storage");
return reinterpret_cast<Module *const *>(this)[-1];
}
void setLocalOwningModule(Module *M) {
- assert(!isFromASTFile() && Hidden && hasLocalOwningModuleStorage() &&
+ assert(!isFromASTFile() && hasOwningModule() &&
+ hasLocalOwningModuleStorage() &&
"should not have a cached owning module");
reinterpret_cast<Module **>(this)[-1] = M;
}
+ /// Is this declaration owned by some module?
+ bool hasOwningModule() const {
+ return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned;
+ }
+
+ /// Get the module that owns this declaration.
+ Module *getOwningModule() const {
+ return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule();
+ }
+
+ /// \brief Determine whether this declaration might be hidden from name
+ /// lookup. Note that the declaration might be visible even if this returns
+ /// \c false, if the owning module is visible within the query context.
+ // FIXME: Rename this to make it clearer what it does.
+ bool isHidden() const {
+ return (int)getModuleOwnershipKind() > (int)ModuleOwnershipKind::Visible;
+ }
+
+ /// Set that this declaration is globally visible, even if it came from a
+ /// module that is not visible.
+ void setVisibleDespiteOwningModule() {
+ if (isHidden())
+ setModuleOwnershipKind(ModuleOwnershipKind::Visible);
+ }
+
+ /// \brief Get the kind of module ownership for this declaration.
+ ModuleOwnershipKind getModuleOwnershipKind() const {
+ return NextInContextAndBits.getInt();
+ }
+
+ /// \brief Set whether this declaration is hidden from name lookup.
+ void setModuleOwnershipKind(ModuleOwnershipKind MOK) {
+ assert(!(getModuleOwnershipKind() == ModuleOwnershipKind::Unowned &&
+ MOK != ModuleOwnershipKind::Unowned && !isFromASTFile() &&
+ !hasLocalOwningModuleStorage()) &&
+ "no storage available for owning module for this declaration");
+ NextInContextAndBits.setInt(MOK);
+ }
+
unsigned getIdentifierNamespace() const {
return IdentifierNamespace;
}
@@ -1030,7 +1098,7 @@ public:
void dump() const;
// Same as dump(), but forces color printing.
void dumpColor() const;
- void dump(raw_ostream &Out) const;
+ void dump(raw_ostream &Out, bool Deserialize = false) const;
/// \brief Looks through the Decl's underlying type to extract a FunctionType
/// when possible. Will return null if the type underlying the Decl does not
@@ -1811,7 +1879,8 @@ public:
void dumpDeclContext() const;
void dumpLookups() const;
- void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false) const;
+ void dumpLookups(llvm::raw_ostream &OS, bool DumpDecls = false,
+ bool Deserialize = false) const;
private:
void reconcileExternalVisibleStorage() const;
diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h b/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h
index 0ca08db..2f735c5 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h
@@ -203,6 +203,11 @@ public:
SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
+ /// \brief Get the location at which the base class type was written.
+ SourceLocation getBaseTypeLoc() const LLVM_READONLY {
+ return BaseTypeInfo->getTypeLoc().getLocStart();
+ }
+
/// \brief Determines whether the base class is a virtual base class (or not).
bool isVirtual() const { return Virtual; }
@@ -370,6 +375,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief These flags are \c true if a defaulted corresponding special
/// member can't be fully analyzed without performing overload resolution.
/// @{
+ unsigned NeedOverloadResolutionForCopyConstructor : 1;
unsigned NeedOverloadResolutionForMoveConstructor : 1;
unsigned NeedOverloadResolutionForMoveAssignment : 1;
unsigned NeedOverloadResolutionForDestructor : 1;
@@ -378,6 +384,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief These flags are \c true if an implicit defaulted corresponding
/// special member would be defined as deleted.
/// @{
+ unsigned DefaultedCopyConstructorIsDeleted : 1;
unsigned DefaultedMoveConstructorIsDeleted : 1;
unsigned DefaultedMoveAssignmentIsDeleted : 1;
unsigned DefaultedDestructorIsDeleted : 1;
@@ -410,6 +417,12 @@ class CXXRecordDecl : public RecordDecl {
/// constructor.
unsigned HasDefaultedDefaultConstructor : 1;
+ /// \brief True if this class can be passed in a non-address-preserving
+ /// fashion (such as in registers) according to the C++ language rules.
+ /// This does not imply anything about how the ABI in use will actually
+ /// pass an object of this class.
+ unsigned CanPassInRegisters : 1;
+
/// \brief True if a defaulted default constructor for this class would
/// be constexpr.
unsigned DefaultedDefaultConstructorIsConstexpr : 1;
@@ -436,9 +449,10 @@ class CXXRecordDecl : public RecordDecl {
/// either by the user or implicitly.
unsigned DeclaredSpecialMembers : 6;
- /// \brief Whether an implicit copy constructor would have a const-qualified
- /// parameter.
- unsigned ImplicitCopyConstructorHasConstParam : 1;
+ /// \brief Whether an implicit copy constructor could have a const-qualified
+ /// parameter, for initializing virtual bases and for other subobjects.
+ unsigned ImplicitCopyConstructorCanHaveConstParamForVBase : 1;
+ unsigned ImplicitCopyConstructorCanHaveConstParamForNonVBase : 1;
/// \brief Whether an implicit copy assignment operator would have a
/// const-qualified parameter.
@@ -458,6 +472,11 @@ class CXXRecordDecl : public RecordDecl {
/// \brief Whether we are currently parsing base specifiers.
unsigned IsParsingBaseSpecifiers : 1;
+ unsigned HasODRHash : 1;
+
+ /// \brief A hash of parts of the class to help in ODR checking.
+ unsigned ODRHash;
+
/// \brief The number of base class specifiers in Bases.
unsigned NumBases;
@@ -703,6 +722,8 @@ public:
return data().IsParsingBaseSpecifiers;
}
+ unsigned getODRHash() const;
+
/// \brief Sets the base classes of this struct or class.
void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
@@ -798,18 +819,50 @@ public:
return data().FirstFriend.isValid();
}
+ /// \brief \c true if a defaulted copy constructor for this class would be
+ /// deleted.
+ bool defaultedCopyConstructorIsDeleted() const {
+ assert((!needsOverloadResolutionForCopyConstructor() ||
+ (data().DeclaredSpecialMembers & SMF_CopyConstructor)) &&
+ "this property has not yet been computed by Sema");
+ return data().DefaultedCopyConstructorIsDeleted;
+ }
+
+ /// \brief \c true if a defaulted move constructor for this class would be
+ /// deleted.
+ bool defaultedMoveConstructorIsDeleted() const {
+ assert((!needsOverloadResolutionForMoveConstructor() ||
+ (data().DeclaredSpecialMembers & SMF_MoveConstructor)) &&
+ "this property has not yet been computed by Sema");
+ return data().DefaultedMoveConstructorIsDeleted;
+ }
+
+ /// \brief \c true if a defaulted destructor for this class would be deleted.
+ bool defaultedDestructorIsDeleted() const {
+ return !data().DefaultedDestructorIsDeleted;
+ }
+
+ /// \brief \c true if we know for sure that this class has a single,
+ /// accessible, unambiguous copy constructor that is not deleted.
+ bool hasSimpleCopyConstructor() const {
+ return !hasUserDeclaredCopyConstructor() &&
+ !data().DefaultedCopyConstructorIsDeleted;
+ }
+
/// \brief \c true if we know for sure that this class has a single,
/// accessible, unambiguous move constructor that is not deleted.
bool hasSimpleMoveConstructor() const {
return !hasUserDeclaredMoveConstructor() && hasMoveConstructor() &&
!data().DefaultedMoveConstructorIsDeleted;
}
+
/// \brief \c true if we know for sure that this class has a single,
/// accessible, unambiguous move assignment operator that is not deleted.
bool hasSimpleMoveAssignment() const {
return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() &&
!data().DefaultedMoveAssignmentIsDeleted;
}
+
/// \brief \c true if we know for sure that this class has an accessible
/// destructor that is not deleted.
bool hasSimpleDestructor() const {
@@ -865,13 +918,24 @@ public:
/// \brief Determine whether we need to eagerly declare a defaulted copy
/// constructor for this class.
bool needsOverloadResolutionForCopyConstructor() const {
- return data().HasMutableFields;
+ // C++17 [class.copy.ctor]p6:
+ // If the class definition declares a move constructor or move assignment
+ // operator, the implicitly declared copy constructor is defined as
+ // deleted.
+ // In MSVC mode, sometimes a declared move assignment does not delete an
+ // implicit copy constructor, so defer this choice to Sema.
+ if (data().UserDeclaredSpecialMembers &
+ (SMF_MoveConstructor | SMF_MoveAssignment))
+ return true;
+ return data().NeedOverloadResolutionForCopyConstructor;
}
/// \brief Determine whether an implicit copy constructor for this type
/// would have a parameter with a const-qualified reference type.
bool implicitCopyConstructorHasConstParam() const {
- return data().ImplicitCopyConstructorHasConstParam;
+ return data().ImplicitCopyConstructorCanHaveConstParamForNonVBase &&
+ (isAbstract() ||
+ data().ImplicitCopyConstructorCanHaveConstParamForVBase);
}
/// \brief Determine whether this class has a copy constructor with
@@ -904,7 +968,16 @@ public:
needsImplicitMoveConstructor();
}
- /// \brief Set that we attempted to declare an implicitly move
+ /// \brief Set that we attempted to declare an implicit copy
+ /// constructor, but overload resolution failed so we deleted it.
+ void setImplicitCopyConstructorIsDeleted() {
+ assert((data().DefaultedCopyConstructorIsDeleted ||
+ needsOverloadResolutionForCopyConstructor()) &&
+ "Copy constructor should not be deleted");
+ data().DefaultedCopyConstructorIsDeleted = true;
+ }
+
+ /// \brief Set that we attempted to declare an implicit move
/// constructor, but overload resolution failed so we deleted it.
void setImplicitMoveConstructorIsDeleted() {
assert((data().DefaultedMoveConstructorIsDeleted ||
@@ -1301,6 +1374,18 @@ public:
return data().HasIrrelevantDestructor;
}
+ /// \brief Determine whether this class has at least one trivial, non-deleted
+ /// copy or move constructor.
+ bool canPassInRegisters() const {
+ return data().CanPassInRegisters;
+ }
+
+ /// \brief Set that we can pass this RecordDecl in registers.
+ // FIXME: This should be set as part of completeDefinition.
+ void setCanPassInRegisters(bool CanPass) {
+ data().CanPassInRegisters = CanPass;
+ }
+
/// \brief Determine whether this class has a non-literal or/ volatile type
/// non-static data member or base class.
bool hasNonLiteralTypeFieldsOrBases() const {
@@ -1548,10 +1633,13 @@ public:
/// \param Paths used to record the paths from this class to its base class
/// subobjects that match the search criteria.
///
+ /// \param LookupInDependent can be set to true to extend the search to
+ /// dependent base classes.
+ ///
/// \returns true if there exists any path from this class to a base class
/// subobject that matches the search criteria.
- bool lookupInBases(BaseMatchesCallback BaseMatches,
- CXXBasePaths &Paths) const;
+ bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths,
+ bool LookupInDependent = false) const;
/// \brief Base-class lookup callback that determines whether the given
/// base class specifier refers to a specific class declaration.
@@ -1593,6 +1681,16 @@ public:
CXXBasePath &Path, DeclarationName Name);
/// \brief Base-class lookup callback that determines whether there exists
+ /// a member with the given name.
+ ///
+ /// This callback can be used with \c lookupInBases() to find members
+ /// of the given name within a C++ class hierarchy, including dependent
+ /// classes.
+ static bool
+ FindOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path, DeclarationName Name);
+
+ /// \brief Base-class lookup callback that determines whether there exists
/// an OpenMP declare reduction member with the given name.
///
/// This callback can be used with \c lookupInBases() to find members
@@ -1618,6 +1716,14 @@ public:
/// \brief Get the indirect primary bases for this class.
void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const;
+ /// Performs an imprecise lookup of a dependent name in this class.
+ ///
+ /// This function does not follow strict semantic rules and should be used
+ /// only when lookup rules can be relaxed, e.g. indexing.
+ std::vector<const NamedDecl *>
+ lookupDependentName(const DeclarationName &Name,
+ llvm::function_ref<bool(const NamedDecl *ND)> Filter);
+
/// Renders and displays an inheritance diagram
/// for this C++ class and all of its base classes (transitively) using
/// GraphViz.
@@ -1738,6 +1844,58 @@ public:
friend class ASTWriter;
};
+/// \brief Represents a C++ deduction guide declaration.
+///
+/// \code
+/// template<typename T> struct A { A(); A(T); };
+/// A() -> A<int>;
+/// \endcode
+///
+/// In this example, there will be an explicit deduction guide from the
+/// second line, and implicit deduction guide templates synthesized from
+/// the constructors of \c A.
+class CXXDeductionGuideDecl : public FunctionDecl {
+ void anchor() override;
+private:
+ CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+ bool IsExplicit, const DeclarationNameInfo &NameInfo,
+ QualType T, TypeSourceInfo *TInfo,
+ SourceLocation EndLocation)
+ : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
+ SC_None, false, false) {
+ if (EndLocation.isValid())
+ setRangeEnd(EndLocation);
+ IsExplicitSpecified = IsExplicit;
+ }
+
+public:
+ static CXXDeductionGuideDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, bool IsExplicit,
+ const DeclarationNameInfo &NameInfo,
+ QualType T, TypeSourceInfo *TInfo,
+ SourceLocation EndLocation);
+
+ static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ /// Whether this deduction guide is explicit.
+ bool isExplicit() const { return IsExplicitSpecified; }
+
+ /// Whether this deduction guide was declared with the 'explicit' specifier.
+ bool isExplicitSpecified() const { return IsExplicitSpecified; }
+
+ /// Get the template for which this guide performs deduction.
+ TemplateDecl *getDeducedTemplate() const {
+ return getDeclName().getCXXDeductionGuideTemplate();
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == CXXDeductionGuide; }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
/// \brief Represents a static or instance method of a struct/union/class.
///
/// In the terminology of the C++ Standard, these are the (static and
@@ -1798,6 +1956,19 @@ public:
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
}
+ /// If it's possible to devirtualize a call to this method, return the called
+ /// function. Otherwise, return null.
+
+ /// \param Base The object on which this virtual function is called.
+ /// \param IsAppleKext True if we are compiling for Apple kext.
+ CXXMethodDecl *getDevirtualizedMethod(const Expr *Base, bool IsAppleKext);
+
+ const CXXMethodDecl *getDevirtualizedMethod(const Expr *Base,
+ bool IsAppleKext) const {
+ return const_cast<CXXMethodDecl *>(this)->getDevirtualizedMethod(
+ Base, IsAppleKext);
+ }
+
/// \brief Determine whether this is a usual deallocation function
/// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
/// delete or delete[] operator with a particular signature.
@@ -1857,7 +2028,10 @@ public:
/// \brief Returns the type of the \c this pointer.
///
- /// Should only be called for instance (i.e., non-static) methods.
+ /// Should only be called for instance (i.e., non-static) methods. Note
+ /// that for the call operator of a lambda closure type, this returns the
+ /// desugared 'this' type (a pointer to the closure type), not the captured
+ /// 'this' type.
QualType getThisType(ASTContext &C) const;
unsigned getTypeQualifiers() const {
@@ -2161,13 +2335,9 @@ class CXXConstructorDecl final
/// \{
/// \brief The arguments used to initialize the base or member.
LazyCXXCtorInitializersPtr CtorInitializers;
- unsigned NumCtorInitializers : 30;
+ unsigned NumCtorInitializers : 31;
/// \}
- /// \brief Whether this constructor declaration has the \c explicit keyword
- /// specified.
- unsigned IsExplicitSpecified : 1;
-
/// \brief Whether this constructor declaration is an implicitly-declared
/// inheriting constructor.
unsigned IsInheritingConstructor : 1;
@@ -2181,11 +2351,11 @@ class CXXConstructorDecl final
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, isConstexpr, SourceLocation()),
CtorInitializers(nullptr), NumCtorInitializers(0),
- IsExplicitSpecified(isExplicitSpecified),
IsInheritingConstructor((bool)Inherited) {
setImplicit(isImplicitlyDeclared);
if (Inherited)
*getTrailingObjects<InheritedConstructor>() = Inherited;
+ IsExplicitSpecified = isExplicitSpecified;
}
public:
@@ -2198,15 +2368,6 @@ public:
bool isConstexpr,
InheritedConstructor Inherited = InheritedConstructor());
- /// \brief Determine whether this constructor declaration has the
- /// \c explicit keyword specified.
- bool isExplicitSpecified() const { return IsExplicitSpecified; }
-
- /// \brief Determine whether this constructor was marked "explicit" or not.
- bool isExplicit() const {
- return cast<CXXConstructorDecl>(getFirstDecl())->isExplicitSpecified();
- }
-
/// \brief Iterates through the member/base initializer list.
typedef CXXCtorInitializer **init_iterator;
@@ -2270,6 +2431,14 @@ public:
CtorInitializers = Initializers;
}
+ /// Whether this function is marked as explicit explicitly.
+ bool isExplicitSpecified() const { return IsExplicitSpecified; }
+
+ /// Whether this function is explicit.
+ bool isExplicit() const {
+ return getCanonicalDecl()->isExplicitSpecified();
+ }
+
/// \brief Determine whether this constructor is a delegating constructor.
bool isDelegatingConstructor() const {
return (getNumCtorInitializers() == 1) &&
@@ -2405,7 +2574,14 @@ public:
void setOperatorDelete(FunctionDecl *OD);
const FunctionDecl *getOperatorDelete() const {
- return cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete;
+ return getCanonicalDecl()->OperatorDelete;
+ }
+
+ CXXDestructorDecl *getCanonicalDecl() override {
+ return cast<CXXDestructorDecl>(FunctionDecl::getCanonicalDecl());
+ }
+ const CXXDestructorDecl *getCanonicalDecl() const {
+ return const_cast<CXXDestructorDecl*>(this)->getCanonicalDecl();
}
// Implement isa/cast/dyncast/etc.
@@ -2428,19 +2604,16 @@ public:
/// \endcode
class CXXConversionDecl : public CXXMethodDecl {
void anchor() override;
- /// Whether this conversion function declaration is marked
- /// "explicit", meaning that it can only be applied when the user
- /// explicitly wrote a cast. This is a C++11 feature.
- bool IsExplicitSpecified : 1;
CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isExplicitSpecified,
- bool isConstexpr, SourceLocation EndLocation)
- : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
- SC_None, isInline, isConstexpr, EndLocation),
- IsExplicitSpecified(isExplicitSpecified) { }
+ const DeclarationNameInfo &NameInfo, QualType T,
+ TypeSourceInfo *TInfo, bool isInline,
+ bool isExplicitSpecified, bool isConstexpr,
+ SourceLocation EndLocation)
+ : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
+ SC_None, isInline, isConstexpr, EndLocation) {
+ IsExplicitSpecified = isExplicitSpecified;
+ }
public:
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
@@ -2452,17 +2625,12 @@ public:
SourceLocation EndLocation);
static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
- /// Whether this conversion function declaration is marked
- /// "explicit", meaning that it can only be used for direct initialization
- /// (including explitly written casts). This is a C++11 feature.
+ /// Whether this function is marked as explicit explicitly.
bool isExplicitSpecified() const { return IsExplicitSpecified; }
- /// \brief Whether this is an explicit conversion operator (C++11 and later).
- ///
- /// Explicit conversion operators are only considered for direct
- /// initialization, e.g., when the user has explicitly written a cast.
+ /// Whether this function is explicit.
bool isExplicit() const {
- return cast<CXXConversionDecl>(getFirstDecl())->isExplicitSpecified();
+ return getCanonicalDecl()->isExplicitSpecified();
}
/// \brief Returns the type that this conversion function is converting to.
@@ -2474,6 +2642,13 @@ public:
/// a lambda closure type to a block pointer.
bool isLambdaToBlockPointerConversion() const;
+ CXXConversionDecl *getCanonicalDecl() override {
+ return cast<CXXConversionDecl>(FunctionDecl::getCanonicalDecl());
+ }
+ const CXXConversionDecl *getCanonicalDecl() const {
+ return const_cast<CXXConversionDecl*>(this)->getCanonicalDecl();
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == CXXConversion; }
diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h b/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h
index ff37758..eb86526 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/DeclContextInternals.h
@@ -131,7 +131,7 @@ public:
} else {
DeclsTy &Vec = *getAsVector();
Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
- std::mem_fun(&Decl::isFromASTFile)),
+ [](Decl *D) { return D->isFromASTFile(); }),
Vec.end());
// Don't have any external decls any more.
Data = DeclsAndHasExternalTy(&Vec, false);
diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h b/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h
index f5098f0..1cd6e00 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h
@@ -381,15 +381,17 @@ public:
ArrayRef<SourceLocation> SelLocs = llvm::None);
// Iterator access to parameter types.
- typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun;
- typedef llvm::mapped_iterator<param_const_iterator, deref_fun>
- param_type_iterator;
+ struct GetTypeFn {
+ QualType operator()(const ParmVarDecl *PD) const { return PD->getType(); }
+ };
+ typedef llvm::mapped_iterator<param_const_iterator, GetTypeFn>
+ param_type_iterator;
param_type_iterator param_type_begin() const {
- return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType));
+ return llvm::map_iterator(param_begin(), GetTypeFn());
}
param_type_iterator param_type_end() const {
- return llvm::map_iterator(param_end(), deref_fun(&ParmVarDecl::getType));
+ return llvm::map_iterator(param_end(), GetTypeFn());
}
/// createImplicitParams - Used to lazily create the self and cmd
@@ -743,6 +745,8 @@ private:
Selector GetterName; // getter name of NULL if no getter
Selector SetterName; // setter name of NULL if no setter
+ SourceLocation GetterNameLoc; // location of the getter attribute's value
+ SourceLocation SetterNameLoc; // location of the setter attribute's value
ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method
ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method
@@ -855,10 +859,18 @@ public:
}
Selector getGetterName() const { return GetterName; }
- void setGetterName(Selector Sel) { GetterName = Sel; }
+ SourceLocation getGetterNameLoc() const { return GetterNameLoc; }
+ void setGetterName(Selector Sel, SourceLocation Loc = SourceLocation()) {
+ GetterName = Sel;
+ GetterNameLoc = Loc;
+ }
Selector getSetterName() const { return SetterName; }
- void setSetterName(Selector Sel) { SetterName = Sel; }
+ SourceLocation getSetterNameLoc() const { return SetterNameLoc; }
+ void setSetterName(Selector Sel, SourceLocation Loc = SourceLocation()) {
+ SetterName = Sel;
+ SetterNameLoc = Loc;
+ }
ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; }
@@ -1027,10 +1039,9 @@ public:
typedef llvm::DenseMap<std::pair<IdentifierInfo*,
unsigned/*isClassProperty*/>,
ObjCPropertyDecl*> PropertyMap;
-
- typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*>
- ProtocolPropertyMap;
-
+
+ typedef llvm::SmallDenseSet<const ObjCProtocolDecl *, 8> ProtocolPropertySet;
+
typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
/// This routine collects list of properties to be implemented in the class.
@@ -2147,7 +2158,8 @@ public:
PropertyDeclOrder &PO) const override;
void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property,
- ProtocolPropertyMap &PM) const;
+ ProtocolPropertySet &PS,
+ PropertyDeclOrder &PO) const;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCProtocol; }
@@ -2320,11 +2332,9 @@ class ObjCImplDecl : public ObjCContainerDecl {
protected:
ObjCImplDecl(Kind DK, DeclContext *DC,
ObjCInterfaceDecl *classInterface,
+ IdentifierInfo *Id,
SourceLocation nameLoc, SourceLocation atStartLoc)
- : ObjCContainerDecl(DK, DC,
- classInterface? classInterface->getIdentifier()
- : nullptr,
- nameLoc, atStartLoc),
+ : ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc),
ClassInterface(classInterface) {}
public:
@@ -2386,9 +2396,6 @@ public:
class ObjCCategoryImplDecl : public ObjCImplDecl {
void anchor() override;
- // Category name
- IdentifierInfo *Id;
-
// Category name location
SourceLocation CategoryNameLoc;
@@ -2396,8 +2403,9 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
ObjCInterfaceDecl *classInterface,
SourceLocation nameLoc, SourceLocation atStartLoc,
SourceLocation CategoryNameLoc)
- : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, nameLoc, atStartLoc),
- Id(Id), CategoryNameLoc(CategoryNameLoc) {}
+ : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id,
+ nameLoc, atStartLoc),
+ CategoryNameLoc(CategoryNameLoc) {}
public:
static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
@@ -2407,37 +2415,10 @@ public:
SourceLocation CategoryNameLoc);
static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
- /// getIdentifier - Get the identifier that names the category
- /// interface associated with this implementation.
- /// FIXME: This is a bad API, we are hiding NamedDecl::getIdentifier()
- /// with a different meaning. For example:
- /// ((NamedDecl *)SomeCategoryImplDecl)->getIdentifier()
- /// returns the class interface name, whereas
- /// ((ObjCCategoryImplDecl *)SomeCategoryImplDecl)->getIdentifier()
- /// returns the category name.
- IdentifierInfo *getIdentifier() const {
- return Id;
- }
- void setIdentifier(IdentifierInfo *II) { Id = II; }
-
ObjCCategoryDecl *getCategoryDecl() const;
SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; }
- /// getName - Get the name of identifier for the class interface associated
- /// with this implementation as a StringRef.
- //
- // FIXME: This is a bad API, we are hiding NamedDecl::getName with a different
- // meaning.
- StringRef getName() const { return Id ? Id->getName() : StringRef(); }
-
- /// @brief Get the name of the class associated with this interface.
- //
- // FIXME: Deprecated, move clients to getName().
- std::string getNameAsString() const {
- return getName();
- }
-
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
@@ -2493,7 +2474,10 @@ class ObjCImplementationDecl : public ObjCImplDecl {
SourceLocation superLoc = SourceLocation(),
SourceLocation IvarLBraceLoc=SourceLocation(),
SourceLocation IvarRBraceLoc=SourceLocation())
- : ObjCImplDecl(ObjCImplementation, DC, classInterface, nameLoc, atStartLoc),
+ : ObjCImplDecl(ObjCImplementation, DC, classInterface,
+ classInterface ? classInterface->getIdentifier()
+ : nullptr,
+ nameLoc, atStartLoc),
SuperClass(superDecl), SuperLoc(superLoc), IvarLBraceLoc(IvarLBraceLoc),
IvarRBraceLoc(IvarRBraceLoc),
IvarInitializers(nullptr), NumIvarInitializers(0),
diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h b/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h
index dc50a19..2879452 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h
@@ -344,6 +344,32 @@ public:
// Kinds of Templates
//===----------------------------------------------------------------------===//
+/// \brief Stores the template parameter list and associated constraints for
+/// \c TemplateDecl objects that track associated constraints.
+class ConstrainedTemplateDeclInfo {
+ friend TemplateDecl;
+
+public:
+ ConstrainedTemplateDeclInfo() : TemplateParams(), AssociatedConstraints() {}
+
+ TemplateParameterList *getTemplateParameters() const {
+ return TemplateParams;
+ }
+
+ Expr *getAssociatedConstraints() const { return AssociatedConstraints; }
+
+protected:
+ void setTemplateParameters(TemplateParameterList *TParams) {
+ TemplateParams = TParams;
+ }
+
+ void setAssociatedConstraints(Expr *AC) { AssociatedConstraints = AC; }
+
+ TemplateParameterList *TemplateParams;
+ Expr *AssociatedConstraints;
+};
+
+
/// \brief The base class of all kinds of template declarations (e.g.,
/// class, function, etc.).
///
@@ -352,33 +378,53 @@ public:
class TemplateDecl : public NamedDecl {
void anchor() override;
protected:
- // This is probably never used.
- TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name)
+ // Construct a template decl with the given name and parameters.
+ // Used when there is no templated element (e.g., for tt-params).
+ TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
- TemplateParams(nullptr) {}
+ TemplateParams(CTDI) {
+ this->setTemplateParameters(Params);
+ }
- // Construct a template decl with the given name and parameters.
- // Used when there is not templated element (tt-params).
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params)
- : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
- TemplateParams(Params) {}
+ : TemplateDecl(nullptr, DK, DC, L, Name, Params) {}
// Construct a template decl with name, parameters, and templated element.
- TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl, false),
- TemplateParams(Params) {}
+ TemplateParams(CTDI) {
+ this->setTemplateParameters(Params);
+ }
+
+ TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl)
+ : TemplateDecl(nullptr, DK, DC, L, Name, Params, Decl) {}
public:
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- return TemplateParams;
+ const auto *const CTDI =
+ TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
+ return CTDI ? CTDI->getTemplateParameters()
+ : TemplateParams.get<TemplateParameterList *>();
}
/// Get the constraint-expression from the associated requires-clause (if any)
const Expr *getRequiresClause() const {
- return TemplateParams ? TemplateParams->getRequiresClause() : nullptr;
+ const TemplateParameterList *const TP = getTemplateParameters();
+ return TP ? TP->getRequiresClause() : nullptr;
+ }
+
+ Expr *getAssociatedConstraints() const {
+ const TemplateDecl *const C = cast<TemplateDecl>(getCanonicalDecl());
+ const auto *const CTDI =
+ C->TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
+ return CTDI ? CTDI->getAssociatedConstraints() : nullptr;
}
/// Get the underlying, templated declaration.
@@ -391,7 +437,7 @@ public:
}
SourceRange getSourceRange() const override LLVM_READONLY {
- return SourceRange(TemplateParams->getTemplateLoc(),
+ return SourceRange(getTemplateParameters()->getTemplateLoc(),
TemplatedDecl.getPointer()->getSourceRange().getEnd());
}
@@ -407,7 +453,29 @@ protected:
/// (function or variable) is a concept.
llvm::PointerIntPair<NamedDecl *, 1, bool> TemplatedDecl;
- TemplateParameterList* TemplateParams;
+ /// \brief The template parameter list and optional requires-clause
+ /// associated with this declaration; alternatively, a
+ /// \c ConstrainedTemplateDeclInfo if the associated constraints of the
+ /// template are being tracked by this particular declaration.
+ llvm::PointerUnion<TemplateParameterList *,
+ ConstrainedTemplateDeclInfo *>
+ TemplateParams;
+
+ void setTemplateParameters(TemplateParameterList *TParams) {
+ if (auto *const CTDI =
+ TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>()) {
+ CTDI->setTemplateParameters(TParams);
+ } else {
+ TemplateParams = TParams;
+ }
+ }
+
+ void setAssociatedConstraints(Expr *AC) {
+ assert(isCanonicalDecl() &&
+ "Attaching associated constraints to non-canonical Decl");
+ TemplateParams.get<ConstrainedTemplateDeclInfo *>()
+ ->setAssociatedConstraints(AC);
+ }
public:
/// \brief Initialize the underlying templated declaration and
@@ -737,11 +805,17 @@ protected:
virtual CommonBase *newCommon(ASTContext &C) const = 0;
// Construct a template decl with name, parameters, and templated element.
+ RedeclarableTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK,
+ ASTContext &C, DeclContext *DC, SourceLocation L,
+ DeclarationName Name, TemplateParameterList *Params,
+ NamedDecl *Decl)
+ : TemplateDecl(CTDI, DK, DC, L, Name, Params, Decl), redeclarable_base(C),
+ Common() {}
+
RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
- : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C),
- Common() {}
+ : RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {}
public:
template <class decl_type> friend class RedeclarableTemplate;
@@ -863,8 +937,6 @@ SpecEntryTraits<FunctionTemplateSpecializationInfo> {
/// Declaration of a template function.
class FunctionTemplateDecl : public RedeclarableTemplateDecl {
- static void DeallocateCommon(void *Ptr);
-
protected:
/// \brief Data that is common to all of the declarations of a given
/// function template.
@@ -1407,7 +1479,9 @@ public:
unsigned NumExpansions);
using TemplateParmPosition::getDepth;
+ using TemplateParmPosition::setDepth;
using TemplateParmPosition::getPosition;
+ using TemplateParmPosition::setPosition;
using TemplateParmPosition::getIndex;
/// \brief Whether this template template parameter is a template
@@ -1960,8 +2034,6 @@ public:
/// Declaration of a class template.
class ClassTemplateDecl : public RedeclarableTemplateDecl {
- static void DeallocateCommon(void *Ptr);
-
protected:
/// \brief Data that is common to all of the declarations of a given
/// class template.
@@ -1997,10 +2069,16 @@ protected:
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
getPartialSpecializations();
+ ClassTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, ASTContext &C,
+ DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl)
+ : RedeclarableTemplateDecl(CTDI, ClassTemplate, C, DC, L, Name, Params,
+ Decl) {}
+
ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
DeclarationName Name, TemplateParameterList *Params,
NamedDecl *Decl)
- : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {}
+ : ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {}
CommonBase *newCommon(ASTContext &C) const override;
@@ -2023,12 +2101,14 @@ public:
return getTemplatedDecl()->isThisDeclarationADefinition();
}
+ // FIXME: remove default argument for AssociatedConstraints
/// \brief Create a class template node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl);
+ NamedDecl *Decl,
+ Expr *AssociatedConstraints = nullptr);
/// \brief Create an empty class template node.
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2247,8 +2327,6 @@ public:
/// template \<typename T> using V = std::map<T*, int, MyCompare<T>>;
/// \endcode
class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
- static void DeallocateCommon(void *Ptr);
-
protected:
typedef CommonBase Common;
@@ -2773,8 +2851,6 @@ public:
/// Declaration of a variable template.
class VarTemplateDecl : public RedeclarableTemplateDecl {
- static void DeallocateCommon(void *Ptr);
-
protected:
/// \brief Data that is common to all of the declarations of a given
/// variable template.
@@ -2946,6 +3022,16 @@ inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
return P.get<TemplateTemplateParmDecl*>();
}
+inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) {
+ auto *TD = dyn_cast<TemplateDecl>(D);
+ return TD && (isa<ClassTemplateDecl>(TD) ||
+ isa<ClassTemplatePartialSpecializationDecl>(TD) ||
+ isa<TypeAliasTemplateDecl>(TD) ||
+ isa<TemplateTemplateParmDecl>(TD))
+ ? TD
+ : nullptr;
+}
+
} /* end of namespace clang */
#endif
diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h b/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h
index 2d3cfe2..5e773c9 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h
@@ -23,6 +23,7 @@ namespace llvm {
namespace clang {
class ASTContext;
+ class CXXDeductionGuideNameExtra;
class CXXLiteralOperatorIdName;
class CXXOperatorIdName;
class CXXSpecialName;
@@ -32,6 +33,7 @@ namespace clang {
enum OverloadedOperatorKind : int;
struct PrintingPolicy;
class QualType;
+ class TemplateDecl;
class Type;
class TypeSourceInfo;
class UsingDirectiveDecl;
@@ -56,6 +58,7 @@ public:
CXXConstructorName,
CXXDestructorName,
CXXConversionFunctionName,
+ CXXDeductionGuideName,
CXXOperatorName,
CXXLiteralOperatorName,
CXXUsingDirective
@@ -118,42 +121,36 @@ private:
CXXSpecialName *getAsCXXSpecialName() const {
NameKind Kind = getNameKind();
if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName)
- return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
+ return reinterpret_cast<CXXSpecialName *>(getExtra());
+ return nullptr;
+ }
+
+ /// If the stored pointer is actually a CXXDeductionGuideNameExtra, returns a
+ /// pointer to it. Otherwise, returns a NULL pointer.
+ CXXDeductionGuideNameExtra *getAsCXXDeductionGuideNameExtra() const {
+ if (getNameKind() == CXXDeductionGuideName)
+ return reinterpret_cast<CXXDeductionGuideNameExtra *>(getExtra());
return nullptr;
}
/// getAsCXXOperatorIdName
CXXOperatorIdName *getAsCXXOperatorIdName() const {
if (getNameKind() == CXXOperatorName)
- return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
+ return reinterpret_cast<CXXOperatorIdName *>(getExtra());
return nullptr;
}
CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const {
if (getNameKind() == CXXLiteralOperatorName)
- return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask);
+ return reinterpret_cast<CXXLiteralOperatorIdName *>(getExtra());
return nullptr;
}
// Construct a declaration name from the name of a C++ constructor,
// destructor, or conversion function.
- DeclarationName(CXXSpecialName *Name)
- : Ptr(reinterpret_cast<uintptr_t>(Name)) {
- assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
- Ptr |= StoredDeclarationNameExtra;
- }
-
- // Construct a declaration name from the name of a C++ overloaded
- // operator.
- DeclarationName(CXXOperatorIdName *Name)
+ DeclarationName(DeclarationNameExtra *Name)
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
- assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
- Ptr |= StoredDeclarationNameExtra;
- }
-
- DeclarationName(CXXLiteralOperatorIdName *Name)
- : Ptr(reinterpret_cast<uintptr_t>(Name)) {
- assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId");
+ assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra");
Ptr |= StoredDeclarationNameExtra;
}
@@ -252,6 +249,10 @@ public:
/// type associated with that name.
QualType getCXXNameType() const;
+ /// If this name is the name of a C++ deduction guide, return the
+ /// template associated with that name.
+ TemplateDecl *getCXXDeductionGuideTemplate() const;
+
/// getCXXOverloadedOperator - If this name is the name of an
/// overloadable operator in C++ (e.g., @c operator+), retrieve the
/// kind of overloaded operator.
@@ -346,6 +347,7 @@ class DeclarationNameTable {
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
CXXOperatorIdName *CXXOperatorNames; // Operator names
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
+ void *CXXDeductionGuideNames; // FoldingSet<CXXDeductionGuideNameExtra> *
DeclarationNameTable(const DeclarationNameTable&) = delete;
void operator=(const DeclarationNameTable&) = delete;
@@ -368,6 +370,9 @@ public:
/// for the given Type.
DeclarationName getCXXDestructorName(CanQualType Ty);
+ /// Returns the name of a C++ deduction guide for the given template.
+ DeclarationName getCXXDeductionGuideName(TemplateDecl *TD);
+
/// getCXXConversionFunctionName - Returns the name of a C++
/// conversion function for the given Type.
DeclarationName getCXXConversionFunctionName(CanQualType Ty);
diff --git a/contrib/llvm/tools/clang/include/clang/AST/Expr.h b/contrib/llvm/tools/clang/include/clang/AST/Expr.h
index 56b99cc..0cdbd2a 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Expr.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/Expr.h
@@ -115,6 +115,7 @@ protected:
ExprBits.InstantiationDependent = ID;
ExprBits.ValueKind = VK;
ExprBits.ObjectKind = OK;
+ assert(ExprBits.ObjectKind == OK && "truncated kind");
ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
setType(T);
}
@@ -907,6 +908,10 @@ public:
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
/// The source expression of an opaque value expression is the
/// expression which originally generated the value. This is
/// provided as a convenience for analyses that don't wish to
@@ -1167,6 +1172,10 @@ public:
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -1222,6 +1231,9 @@ public:
// Iterators
child_range children() { return child_range(&FnName, &FnName + 1); }
+ const_child_range children() const {
+ return const_child_range(&FnName, &FnName + 1);
+ }
friend class ASTStmtReader;
};
@@ -1315,6 +1327,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
class CharacterLiteral : public Expr {
@@ -1365,6 +1380,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
class FloatingLiteral : public Expr, private APFloatStorage {
@@ -1429,6 +1447,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// ImaginaryLiteral - We support imaginary integer and floating point literals,
@@ -1461,6 +1482,9 @@ public:
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
+ const_child_range children() const {
+ return const_child_range(&Val, &Val + 1);
+ }
};
/// StringLiteral - This represents a string literal expression, e.g. "foo"
@@ -1628,6 +1652,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This
@@ -1669,6 +1696,9 @@ public:
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
+ const_child_range children() const {
+ return const_child_range(&Val, &Val + 1);
+ }
};
/// UnaryOperator - This represents the unary-expression's (except sizeof and
@@ -1778,6 +1808,9 @@ public:
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
+ const_child_range children() const {
+ return const_child_range(&Val, &Val + 1);
+ }
};
/// Helper class for OffsetOfExpr.
@@ -1981,6 +2014,11 @@ public:
Stmt **begin = reinterpret_cast<Stmt **>(getTrailingObjects<Expr *>());
return child_range(begin, begin + NumExprs);
}
+ const_child_range children() const {
+ Stmt *const *begin =
+ reinterpret_cast<Stmt *const *>(getTrailingObjects<Expr *>());
+ return const_child_range(begin, begin + NumExprs);
+ }
friend TrailingObjects;
};
@@ -2069,6 +2107,7 @@ public:
// Iterators
child_range children();
+ const_child_range children() const;
};
//===----------------------------------------------------------------------===//
@@ -2153,6 +2192,9 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
};
/// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
@@ -2313,6 +2355,11 @@ public:
return child_range(&SubExprs[0],
&SubExprs[0]+NumArgs+getNumPreArgs()+PREARGS_START);
}
+
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + NumArgs +
+ getNumPreArgs() + PREARGS_START);
+ }
};
/// Extra data stored in some MemberExpr objects.
@@ -2567,6 +2614,9 @@ public:
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
+ const_child_range children() const {
+ return const_child_range(&Base, &Base + 1);
+ }
friend TrailingObjects;
friend class ASTReader;
@@ -2639,6 +2689,9 @@ public:
// Iterators
child_range children() { return child_range(&Init, &Init+1); }
+ const_child_range children() const {
+ return const_child_range(&Init, &Init + 1);
+ }
};
/// CastExpr - Base class for type casts, including both implicit
@@ -2725,6 +2778,7 @@ public:
// Iterators
child_range children() { return child_range(&Op, &Op+1); }
+ const_child_range children() const { return const_child_range(&Op, &Op + 1); }
};
/// ImplicitCastExpr - Allows us to explicitly represent implicit type
@@ -2917,11 +2971,9 @@ public:
private:
unsigned Opc : 6;
- // Records the FP_CONTRACT pragma status at the point that this binary
- // operator was parsed. This bit is only meaningful for operations on
- // floating point types. For all other types it should default to
- // false.
- unsigned FPContractable : 1;
+ // This is only meaningful for operations on floating point types and 0
+ // otherwise.
+ unsigned FPFeatures : 2;
SourceLocation OpLoc;
enum { LHS, RHS, END_EXPR };
@@ -2930,7 +2982,7 @@ public:
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
ExprValueKind VK, ExprObjectKind OK,
- SourceLocation opLoc, bool fpContractable)
+ SourceLocation opLoc, FPOptions FPFeatures)
: Expr(BinaryOperatorClass, ResTy, VK, OK,
lhs->isTypeDependent() || rhs->isTypeDependent(),
lhs->isValueDependent() || rhs->isValueDependent(),
@@ -2938,7 +2990,7 @@ public:
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())),
- Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
+ Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
assert(!isCompoundAssignmentOp() &&
@@ -3070,19 +3122,26 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
// Set the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
- void setFPContractable(bool FPC) { FPContractable = FPC; }
+ void setFPFeatures(FPOptions F) { FPFeatures = F.getInt(); }
+
+ FPOptions getFPFeatures() const { return FPOptions(FPFeatures); }
// Get the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
- bool isFPContractable() const { return FPContractable; }
+ bool isFPContractableWithinStatement() const {
+ return FPOptions(FPFeatures).allowFPContractWithinStatement();
+ }
protected:
BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
ExprValueKind VK, ExprObjectKind OK,
- SourceLocation opLoc, bool fpContractable, bool dead2)
+ SourceLocation opLoc, FPOptions FPFeatures, bool dead2)
: Expr(CompoundAssignOperatorClass, ResTy, VK, OK,
lhs->isTypeDependent() || rhs->isTypeDependent(),
lhs->isValueDependent() || rhs->isValueDependent(),
@@ -3090,7 +3149,7 @@ protected:
rhs->isInstantiationDependent()),
(lhs->containsUnexpandedParameterPack() ||
rhs->containsUnexpandedParameterPack())),
- Opc(opc), FPContractable(fpContractable), OpLoc(opLoc) {
+ Opc(opc), FPFeatures(FPFeatures.getInt()), OpLoc(opLoc) {
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
}
@@ -3112,8 +3171,8 @@ public:
CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType,
ExprValueKind VK, ExprObjectKind OK,
QualType CompLHSType, QualType CompResultType,
- SourceLocation OpLoc, bool fpContractable)
- : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, fpContractable,
+ SourceLocation OpLoc, FPOptions FPFeatures)
+ : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures,
true),
ComputationLHSType(CompLHSType),
ComputationResultType(CompResultType) {
@@ -3246,6 +3305,9 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
};
/// BinaryConditionalOperator - The GNU extension to the conditional
@@ -3331,6 +3393,9 @@ public:
child_range children() {
return child_range(SubExprs, SubExprs + NUM_SUBEXPRS);
}
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + NUM_SUBEXPRS);
+ }
};
inline Expr *AbstractConditionalOperator::getCond() const {
@@ -3385,6 +3450,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
@@ -3427,6 +3495,9 @@ public:
// Iterators
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
+ const_child_range children() const {
+ return const_child_range(&SubStmt, &SubStmt + 1);
+ }
};
/// ShuffleVectorExpr - clang-specific builtin-in function
@@ -3495,6 +3566,9 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+NumExprs);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + NumExprs);
+ }
};
/// ConvertVectorExpr - Clang builtin function __builtin_convertvector
@@ -3549,6 +3623,9 @@ public:
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
+ const_child_range children() const {
+ return const_child_range(&SrcExpr, &SrcExpr + 1);
+ }
};
/// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
@@ -3629,6 +3706,9 @@ public:
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
}
+ const_child_range children() const {
+ return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR);
+ }
};
/// GNUNullExpr - Implements the GNU __null extension, which is a name
@@ -3665,6 +3745,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// Represents a call to the builtin function \c __builtin_va_arg.
@@ -3712,6 +3795,9 @@ public:
// Iterators
child_range children() { return child_range(&Val, &Val+1); }
+ const_child_range children() const {
+ return const_child_range(&Val, &Val + 1);
+ }
};
/// @brief Describes an C or C++ initializer list.
@@ -3936,10 +4022,16 @@ public:
// Iterators
child_range children() {
+ const_child_range CCR = const_cast<const InitListExpr *>(this)->children();
+ return child_range(cast_away_const(CCR.begin()),
+ cast_away_const(CCR.end()));
+ }
+
+ const_child_range children() const {
// FIXME: This does not include the array filler expression.
if (InitExprs.empty())
- return child_range(child_iterator(), child_iterator());
- return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size());
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ return const_child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size());
}
typedef InitExprsTy::iterator iterator;
@@ -4192,6 +4284,9 @@ public:
}
Designator *getDesignator(unsigned Idx) { return &designators()[Idx]; }
+ const Designator *getDesignator(unsigned Idx) const {
+ return &designators()[Idx];
+ }
void setDesignators(const ASTContext &C, const Designator *Desigs,
unsigned NumDesigs);
@@ -4254,6 +4349,10 @@ public:
Stmt **begin = getTrailingObjects<Stmt *>();
return child_range(begin, begin + NumSubExprs);
}
+ const_child_range children() const {
+ Stmt * const *begin = getTrailingObjects<Stmt *>();
+ return const_child_range(begin, begin + NumSubExprs);
+ }
friend TrailingObjects;
};
@@ -4287,6 +4386,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
// In cases like:
@@ -4332,6 +4434,10 @@ public:
child_range children() {
return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2);
}
+ const_child_range children() const {
+ return const_child_range(&BaseAndUpdaterExprs[0],
+ &BaseAndUpdaterExprs[0] + 2);
+ }
};
/// \brief Represents a loop initializing the elements of an array.
@@ -4393,6 +4499,9 @@ public:
child_range children() {
return child_range(SubExprs, SubExprs + 2);
}
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + 2);
+ }
friend class ASTReader;
friend class ASTStmtReader;
@@ -4421,6 +4530,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
friend class ASTReader;
friend class ASTStmtReader;
@@ -4455,6 +4567,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
class ParenListExpr : public Expr {
@@ -4501,6 +4616,9 @@ public:
child_range children() {
return child_range(&Exprs[0], &Exprs[0]+NumExprs);
}
+ const_child_range children() const {
+ return const_child_range(&Exprs[0], &Exprs[0] + NumExprs);
+ }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -4621,7 +4739,9 @@ public:
child_range children() {
return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs);
}
-
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + END_EXPR + NumAssocs);
+ }
friend class ASTStmtReader;
};
@@ -4690,6 +4810,9 @@ public:
// Iterators
child_range children() { return child_range(&Base, &Base+1); }
+ const_child_range children() const {
+ return const_child_range(&Base, &Base + 1);
+ }
};
/// BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
@@ -4731,6 +4854,9 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
};
/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
@@ -4776,6 +4902,9 @@ public:
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
+ const_child_range children() const {
+ return const_child_range(&SrcExpr, &SrcExpr + 1);
+ }
};
/// PseudoObjectExpr - An expression which accesses a pseudo-object
@@ -4914,8 +5043,15 @@ public:
}
child_range children() {
- Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer());
- return child_range(cs, cs + getNumSubExprs());
+ const_child_range CCR =
+ const_cast<const PseudoObjectExpr *>(this)->children();
+ return child_range(cast_away_const(CCR.begin()),
+ cast_away_const(CCR.end()));
+ }
+ const_child_range children() const {
+ Stmt *const *cs = const_cast<Stmt *const *>(
+ reinterpret_cast<const Stmt *const *>(getSubExprsBuffer()));
+ return const_child_range(cs, cs + getNumSubExprs());
}
static bool classof(const Stmt *T) {
@@ -5021,6 +5157,9 @@ public:
child_range children() {
return child_range(SubExprs, SubExprs+NumSubExprs);
}
+ const_child_range children() const {
+ return const_child_range(SubExprs, SubExprs + NumSubExprs);
+ }
};
/// TypoExpr - Internal placeholder for expressions where typo correction
@@ -5039,6 +5178,10 @@ public:
child_range children() {
return child_range(child_iterator(), child_iterator());
}
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+
SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h b/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h
index 37e5977..79d2c58 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h
@@ -54,18 +54,16 @@ class CXXOperatorCallExpr : public CallExpr {
OverloadedOperatorKind Operator;
SourceRange Range;
- // Record the FP_CONTRACT state that applies to this operator call. Only
- // meaningful for floating point types. For other types this value can be
- // set to false.
- unsigned FPContractable : 1;
+ // Only meaningful for floating point types.
+ FPOptions FPFeatures;
SourceRange getSourceRangeImpl() const LLVM_READONLY;
public:
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
- SourceLocation operatorloc, bool fpContractable)
+ SourceLocation operatorloc, FPOptions FPFeatures)
: CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc),
- Operator(Op), FPContractable(fpContractable) {
+ Operator(Op), FPFeatures(FPFeatures) {
Range = getSourceRangeImpl();
}
explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) :
@@ -113,11 +111,15 @@ public:
// Set the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
- void setFPContractable(bool FPC) { FPContractable = FPC; }
+ void setFPFeatures(FPOptions F) { FPFeatures = F; }
+
+ FPOptions getFPFeatures() const { return FPFeatures; }
// Get the FP contractability status of this operator. Only meaningful for
// operations on floating point types.
- bool isFPContractable() const { return FPContractable; }
+ bool isFPContractableWithinStatement() const {
+ return FPFeatures.allowFPContractWithinStatement();
+ }
friend class ASTStmtReader;
friend class ASTStmtWriter;
@@ -1470,7 +1472,8 @@ class CXXTemporaryObjectExpr : public CXXConstructExpr {
public:
CXXTemporaryObjectExpr(const ASTContext &C,
CXXConstructorDecl *Cons,
- TypeSourceInfo *Type,
+ QualType Type,
+ TypeSourceInfo *TSI,
ArrayRef<Expr *> Args,
SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
@@ -4122,16 +4125,18 @@ class CoroutineSuspendExpr : public Expr {
enum SubExpr { Common, Ready, Suspend, Resume, Count };
Stmt *SubExprs[SubExpr::Count];
+ OpaqueValueExpr *OpaqueValue = nullptr;
friend class ASTStmtReader;
public:
CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Common,
- Expr *Ready, Expr *Suspend, Expr *Resume)
+ Expr *Ready, Expr *Suspend, Expr *Resume,
+ OpaqueValueExpr *OpaqueValue)
: Expr(SC, Resume->getType(), Resume->getValueKind(),
Resume->getObjectKind(), Resume->isTypeDependent(),
Resume->isValueDependent(), Common->isInstantiationDependent(),
Common->containsUnexpandedParameterPack()),
- KeywordLoc(KeywordLoc) {
+ KeywordLoc(KeywordLoc), OpaqueValue(OpaqueValue) {
SubExprs[SubExpr::Common] = Common;
SubExprs[SubExpr::Ready] = Ready;
SubExprs[SubExpr::Suspend] = Suspend;
@@ -4160,6 +4165,8 @@ public:
Expr *getCommonExpr() const {
return static_cast<Expr*>(SubExprs[SubExpr::Common]);
}
+ /// \brief getOpaqueValue - Return the opaque value placeholder.
+ OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; }
Expr *getReadyExpr() const {
return static_cast<Expr*>(SubExprs[SubExpr::Ready]);
@@ -4193,11 +4200,17 @@ class CoawaitExpr : public CoroutineSuspendExpr {
friend class ASTStmtReader;
public:
CoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand, Expr *Ready,
- Expr *Suspend, Expr *Resume)
+ Expr *Suspend, Expr *Resume, OpaqueValueExpr *OpaqueValue,
+ bool IsImplicit = false)
: CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Operand, Ready,
- Suspend, Resume) {}
- CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand)
- : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) {}
+ Suspend, Resume, OpaqueValue) {
+ CoawaitBits.IsImplicit = IsImplicit;
+ }
+ CoawaitExpr(SourceLocation CoawaitLoc, QualType Ty, Expr *Operand,
+ bool IsImplicit = false)
+ : CoroutineSuspendExpr(CoawaitExprClass, CoawaitLoc, Ty, Operand) {
+ CoawaitBits.IsImplicit = IsImplicit;
+ }
CoawaitExpr(EmptyShell Empty)
: CoroutineSuspendExpr(CoawaitExprClass, Empty) {}
@@ -4206,19 +4219,67 @@ public:
return getCommonExpr();
}
+ bool isImplicit() const { return CoawaitBits.IsImplicit; }
+ void setIsImplicit(bool value = true) { CoawaitBits.IsImplicit = value; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CoawaitExprClass;
}
};
+/// \brief Represents a 'co_await' expression while the type of the promise
+/// is dependent.
+class DependentCoawaitExpr : public Expr {
+ SourceLocation KeywordLoc;
+ Stmt *SubExprs[2];
+
+ friend class ASTStmtReader;
+
+public:
+ DependentCoawaitExpr(SourceLocation KeywordLoc, QualType Ty, Expr *Op,
+ UnresolvedLookupExpr *OpCoawait)
+ : Expr(DependentCoawaitExprClass, Ty, VK_RValue, OK_Ordinary,
+ /*TypeDependent*/ true, /*ValueDependent*/ true,
+ /*InstantiationDependent*/ true,
+ Op->containsUnexpandedParameterPack()),
+ KeywordLoc(KeywordLoc) {
+ // NOTE: A co_await expression is dependent on the coroutines promise
+ // type and may be dependent even when the `Op` expression is not.
+ assert(Ty->isDependentType() &&
+ "wrong constructor for non-dependent co_await/co_yield expression");
+ SubExprs[0] = Op;
+ SubExprs[1] = OpCoawait;
+ }
+
+ DependentCoawaitExpr(EmptyShell Empty)
+ : Expr(DependentCoawaitExprClass, Empty) {}
+
+ Expr *getOperand() const { return cast<Expr>(SubExprs[0]); }
+ UnresolvedLookupExpr *getOperatorCoawaitLookup() const {
+ return cast<UnresolvedLookupExpr>(SubExprs[1]);
+ }
+ SourceLocation getKeywordLoc() const { return KeywordLoc; }
+
+ SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getOperand()->getLocEnd();
+ }
+
+ child_range children() { return child_range(SubExprs, SubExprs + 2); }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == DependentCoawaitExprClass;
+ }
+};
+
/// \brief Represents a 'co_yield' expression.
class CoyieldExpr : public CoroutineSuspendExpr {
friend class ASTStmtReader;
public:
CoyieldExpr(SourceLocation CoyieldLoc, Expr *Operand, Expr *Ready,
- Expr *Suspend, Expr *Resume)
+ Expr *Suspend, Expr *Resume, OpaqueValueExpr *OpaqueValue)
: CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Operand, Ready,
- Suspend, Resume) {}
+ Suspend, Resume, OpaqueValue) {}
CoyieldExpr(SourceLocation CoyieldLoc, QualType Ty, Expr *Operand)
: CoroutineSuspendExpr(CoyieldExprClass, CoyieldLoc, Ty, Operand) {}
CoyieldExpr(EmptyShell Empty)
diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExternalASTMerger.h b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTMerger.h
new file mode 100644
index 0000000..51d0c30
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTMerger.h
@@ -0,0 +1,51 @@
+//===--- ExternalASTMerger.h - Merging External AST Interface ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the ExternalASTMerger, which vends a combination of ASTs
+// from several different ASTContext/FileManager pairs
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_EXTERNALASTMERGER_H
+#define LLVM_CLANG_AST_EXTERNALASTMERGER_H
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/ExternalASTSource.h"
+
+namespace clang {
+
+class ExternalASTMerger : public ExternalASTSource {
+public:
+ struct ImporterPair {
+ std::unique_ptr<ASTImporter> Forward;
+ std::unique_ptr<ASTImporter> Reverse;
+ };
+
+private:
+ std::vector<ImporterPair> Importers;
+
+public:
+ struct ImporterEndpoint {
+ ASTContext &AST;
+ FileManager &FM;
+ };
+ ExternalASTMerger(const ImporterEndpoint &Target,
+ llvm::ArrayRef<ImporterEndpoint> Sources);
+
+ bool FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) override;
+
+ void
+ FindExternalLexicalDecls(const DeclContext *DC,
+ llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
+ SmallVectorImpl<Decl *> &Result) override;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h
index 2e99f39..d8dd18e 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h
@@ -16,6 +16,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclBase.h"
+#include "clang/Basic/Module.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
@@ -149,26 +150,30 @@ public:
StringRef PCHModuleName;
StringRef Path;
StringRef ASTFile;
- uint64_t Signature = 0;
+ ASTFileSignature Signature;
const Module *ClangModule = nullptr;
public:
ASTSourceDescriptor(){};
ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile,
- uint64_t Signature)
+ ASTFileSignature Signature)
: PCHModuleName(std::move(Name)), Path(std::move(Path)),
ASTFile(std::move(ASTFile)), Signature(Signature){};
ASTSourceDescriptor(const Module &M);
std::string getModuleName() const;
StringRef getPath() const { return Path; }
StringRef getASTFile() const { return ASTFile; }
- uint64_t getSignature() const { return Signature; }
+ ASTFileSignature getSignature() const { return Signature; }
const Module *getModuleOrNull() const { return ClangModule; }
};
/// Return a descriptor for the corresponding module, if one exists.
virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID);
+ enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
+
+ virtual ExtKind hasExternalDefinitions(const Decl *D);
+
/// \brief Finds all declarations lexically contained within the given
/// DeclContext, after applying an optional filter predicate.
///
diff --git a/contrib/llvm/tools/clang/include/clang/AST/NSAPI.h b/contrib/llvm/tools/clang/include/clang/AST/NSAPI.h
index 583f9d9..3757116 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/NSAPI.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/NSAPI.h
@@ -49,7 +49,7 @@ public:
NSStr_initWithString,
NSStr_initWithUTF8String
};
- static const unsigned NumNSStringMethods = 5;
+ static const unsigned NumNSStringMethods = 6;
IdentifierInfo *getNSClassId(NSClassIdKindKind K) const;
@@ -112,7 +112,7 @@ public:
NSMutableDict_setObjectForKeyedSubscript,
NSMutableDict_setValueForKey
};
- static const unsigned NumNSDictionaryMethods = 14;
+ static const unsigned NumNSDictionaryMethods = 13;
/// \brief The Objective-C NSDictionary selectors.
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
diff --git a/contrib/llvm/tools/clang/include/clang/AST/ODRHash.h b/contrib/llvm/tools/clang/include/clang/AST/ODRHash.h
new file mode 100644
index 0000000..e4cc12d
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/AST/ODRHash.h
@@ -0,0 +1,84 @@
+//===-- ODRHash.h - Hashing to diagnose ODR failures ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the ODRHash class, which calculates
+/// a hash based on AST nodes, which is stable across different runs.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TemplateBase.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+class Decl;
+class IdentifierInfo;
+class NestedNameSpecifier;
+class Stmt;
+class TemplateParameterList;
+
+// ODRHash is used to calculate a hash based on AST node contents that
+// does not rely on pointer addresses. This allows the hash to not vary
+// between runs and is usable to detect ODR problems in modules. To use,
+// construct an ODRHash object, then call Add* methods over the nodes that
+// need to be hashed. Then call CalculateHash to get the hash value.
+// Typically, only one Add* call is needed. clear can be called to reuse the
+// object.
+class ODRHash {
+ // Use DenseMaps to convert between Decl and Type pointers and an index value.
+ llvm::DenseMap<const Decl*, unsigned> DeclMap;
+ llvm::DenseMap<const Type*, unsigned> TypeMap;
+
+ // Save space by processing bools at the end.
+ llvm::SmallVector<bool, 128> Bools;
+
+ llvm::FoldingSetNodeID ID;
+
+public:
+ ODRHash() {}
+
+ // Use this for ODR checking classes between modules. This method compares
+ // more information than the AddDecl class.
+ void AddCXXRecordDecl(const CXXRecordDecl *Record);
+
+ // Process SubDecls of the main Decl. This method calls the DeclVisitor
+ // while AddDecl does not.
+ void AddSubDecl(const Decl *D);
+
+ // Reset the object for reuse.
+ void clear();
+
+ // Add booleans to ID and uses it to calculate the hash.
+ unsigned CalculateHash();
+
+ // Add AST nodes that need to be processed.
+ void AddDecl(const Decl *D);
+ void AddType(const Type *T);
+ void AddQualType(QualType T);
+ void AddStmt(const Stmt *S);
+ void AddIdentifierInfo(const IdentifierInfo *II);
+ void AddNestedNameSpecifier(const NestedNameSpecifier *NNS);
+ void AddTemplateName(TemplateName Name);
+ void AddDeclarationName(DeclarationName Name);
+ void AddTemplateArgument(TemplateArgument TA);
+ void AddTemplateParameterList(const TemplateParameterList *TPL);
+
+ // Save booleans until the end to lower the size of data to process.
+ void AddBoolean(bool value);
+
+ static bool isWhitelistedDecl(const Decl* D, const CXXRecordDecl *Record);
+};
+
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h b/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h
index 3e4c4bc..a1cae8e 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/OpenMPClause.h
@@ -20,6 +20,7 @@
#include "clang/AST/Stmt.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/MapVector.h"
namespace clang {
@@ -76,10 +77,17 @@ class OMPClauseWithPreInit {
friend class OMPClauseReader;
/// Pre-initialization statement for the clause.
Stmt *PreInit;
+ /// Region that captures the associated stmt.
+ OpenMPDirectiveKind CaptureRegion;
+
protected:
/// Set pre-initialization statement for the clause.
- void setPreInitStmt(Stmt *S) { PreInit = S; }
- OMPClauseWithPreInit(const OMPClause *This) : PreInit(nullptr) {
+ void setPreInitStmt(Stmt *S, OpenMPDirectiveKind ThisRegion = OMPD_unknown) {
+ PreInit = S;
+ CaptureRegion = ThisRegion;
+ }
+ OMPClauseWithPreInit(const OMPClause *This)
+ : PreInit(nullptr), CaptureRegion(OMPD_unknown) {
assert(get(This) && "get is not tuned for pre-init.");
}
@@ -88,6 +96,8 @@ public:
const Stmt *getPreInitStmt() const { return PreInit; }
/// Get pre-initialization statement for the clause.
Stmt *getPreInitStmt() { return PreInit; }
+ /// Get capture region for the stmt in the clause.
+ OpenMPDirectiveKind getCaptureRegion() { return CaptureRegion; }
static OMPClauseWithPreInit *get(OMPClause *C);
static const OMPClauseWithPreInit *get(const OMPClause *C);
};
@@ -194,7 +204,7 @@ public:
/// In this example directive '#pragma omp parallel' has simple 'if' clause with
/// condition 'a > 5' and directive name modifier 'parallel'.
///
-class OMPIfClause : public OMPClause {
+class OMPIfClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// \brief Location of '('.
SourceLocation LParenLoc;
@@ -225,26 +235,31 @@ public:
///
/// \param NameModifier [OpenMP 4.1] Directive name modifier of clause.
/// \param Cond Condition of the clause.
+ /// \param HelperCond Helper condition for the clause.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param NameModifierLoc Location of directive name modifier.
/// \param ColonLoc [OpenMP 4.1] Location of ':'.
/// \param EndLoc Ending location of the clause.
///
- OMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Cond,
- SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation NameModifierLoc, SourceLocation ColonLoc,
- SourceLocation EndLoc)
- : OMPClause(OMPC_if, StartLoc, EndLoc), LParenLoc(LParenLoc),
- Condition(Cond), ColonLoc(ColonLoc), NameModifier(NameModifier),
- NameModifierLoc(NameModifierLoc) {}
+ OMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Cond, Stmt *HelperCond,
+ OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation NameModifierLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_if, StartLoc, EndLoc), OMPClauseWithPreInit(this),
+ LParenLoc(LParenLoc), Condition(Cond), ColonLoc(ColonLoc),
+ NameModifier(NameModifier), NameModifierLoc(NameModifierLoc) {
+ setPreInitStmt(HelperCond, CaptureRegion);
+ }
/// \brief Build an empty clause.
///
OMPIfClause()
- : OMPClause(OMPC_if, SourceLocation(), SourceLocation()), LParenLoc(),
- Condition(nullptr), ColonLoc(), NameModifier(OMPD_unknown),
- NameModifierLoc() {}
+ : OMPClause(OMPC_if, SourceLocation(), SourceLocation()),
+ OMPClauseWithPreInit(this), LParenLoc(), Condition(nullptr), ColonLoc(),
+ NameModifier(OMPD_unknown), NameModifierLoc() {}
/// \brief Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
@@ -331,7 +346,7 @@ public:
/// In this example directive '#pragma omp parallel' has simple 'num_threads'
/// clause with number of threads '6'.
///
-class OMPNumThreadsClause : public OMPClause {
+class OMPNumThreadsClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// \brief Location of '('.
SourceLocation LParenLoc;
@@ -346,20 +361,29 @@ public:
/// \brief Build 'num_threads' clause with condition \a NumThreads.
///
/// \param NumThreads Number of threads for the construct.
+ /// \param HelperNumThreads Helper Number of threads for the construct.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
///
- OMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc)
- : OMPClause(OMPC_num_threads, StartLoc, EndLoc), LParenLoc(LParenLoc),
- NumThreads(NumThreads) {}
+ OMPNumThreadsClause(Expr *NumThreads, Stmt *HelperNumThreads,
+ OpenMPDirectiveKind CaptureRegion,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPClause(OMPC_num_threads, StartLoc, EndLoc),
+ OMPClauseWithPreInit(this), LParenLoc(LParenLoc),
+ NumThreads(NumThreads) {
+ setPreInitStmt(HelperNumThreads, CaptureRegion);
+ }
/// \brief Build an empty clause.
///
OMPNumThreadsClause()
: OMPClause(OMPC_num_threads, SourceLocation(), SourceLocation()),
- LParenLoc(SourceLocation()), NumThreads(nullptr) {}
+ OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
+ NumThreads(nullptr) {}
/// \brief Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
@@ -1866,6 +1890,217 @@ public:
}
};
+/// This represents clause 'task_reduction' in the '#pragma omp taskgroup'
+/// directives.
+///
+/// \code
+/// #pragma omp taskgroup task_reduction(+:a,b)
+/// \endcode
+/// In this example directive '#pragma omp taskgroup' has clause
+/// 'task_reduction' with operator '+' and the variables 'a' and 'b'.
+///
+class OMPTaskReductionClause final
+ : public OMPVarListClause<OMPTaskReductionClause>,
+ public OMPClauseWithPostUpdate,
+ private llvm::TrailingObjects<OMPTaskReductionClause, Expr *> {
+ friend TrailingObjects;
+ friend OMPVarListClause;
+ friend class OMPClauseReader;
+ /// Location of ':'.
+ SourceLocation ColonLoc;
+ /// Nested name specifier for C++.
+ NestedNameSpecifierLoc QualifierLoc;
+ /// Name of custom operator.
+ DeclarationNameInfo NameInfo;
+
+ /// Build clause with number of variables \a N.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param EndLoc Ending location of the clause.
+ /// \param ColonLoc Location of ':'.
+ /// \param N Number of the variables in the clause.
+ /// \param QualifierLoc The nested-name qualifier with location information
+ /// \param NameInfo The full name info for reduction identifier.
+ ///
+ OMPTaskReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ unsigned N, NestedNameSpecifierLoc QualifierLoc,
+ const DeclarationNameInfo &NameInfo)
+ : OMPVarListClause<OMPTaskReductionClause>(OMPC_task_reduction, StartLoc,
+ LParenLoc, EndLoc, N),
+ OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc),
+ QualifierLoc(QualifierLoc), NameInfo(NameInfo) {}
+
+ /// Build an empty clause.
+ ///
+ /// \param N Number of variables.
+ ///
+ explicit OMPTaskReductionClause(unsigned N)
+ : OMPVarListClause<OMPTaskReductionClause>(
+ OMPC_task_reduction, SourceLocation(), SourceLocation(),
+ SourceLocation(), N),
+ OMPClauseWithPostUpdate(this), ColonLoc(), QualifierLoc(), NameInfo() {}
+
+ /// Sets location of ':' symbol in clause.
+ void setColonLoc(SourceLocation CL) { ColonLoc = CL; }
+ /// Sets the name info for specified reduction identifier.
+ void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; }
+ /// Sets the nested name specifier.
+ void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
+
+ /// Set list of helper expressions, required for proper codegen of the clause.
+ /// These expressions represent private copy of the reduction variable.
+ void setPrivates(ArrayRef<Expr *> Privates);
+
+ /// Get the list of helper privates.
+ MutableArrayRef<Expr *> getPrivates() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getPrivates() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
+ /// Set list of helper expressions, required for proper codegen of the clause.
+ /// These expressions represent LHS expression in the final reduction
+ /// expression performed by the reduction clause.
+ void setLHSExprs(ArrayRef<Expr *> LHSExprs);
+
+ /// Get the list of helper LHS expressions.
+ MutableArrayRef<Expr *> getLHSExprs() {
+ return MutableArrayRef<Expr *>(getPrivates().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getLHSExprs() const {
+ return llvm::makeArrayRef(getPrivates().end(), varlist_size());
+ }
+
+ /// Set list of helper expressions, required for proper codegen of the clause.
+ /// These expressions represent RHS expression in the final reduction
+ /// expression performed by the reduction clause. Also, variables in these
+ /// expressions are used for proper initialization of reduction copies.
+ void setRHSExprs(ArrayRef<Expr *> RHSExprs);
+
+ /// Get the list of helper destination expressions.
+ MutableArrayRef<Expr *> getRHSExprs() {
+ return MutableArrayRef<Expr *>(getLHSExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getRHSExprs() const {
+ return llvm::makeArrayRef(getLHSExprs().end(), varlist_size());
+ }
+
+ /// Set list of helper reduction expressions, required for proper
+ /// codegen of the clause. These expressions are binary expressions or
+ /// operator/custom reduction call that calculates new value from source
+ /// helper expressions to destination helper expressions.
+ void setReductionOps(ArrayRef<Expr *> ReductionOps);
+
+ /// Get the list of helper reduction expressions.
+ MutableArrayRef<Expr *> getReductionOps() {
+ return MutableArrayRef<Expr *>(getRHSExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getReductionOps() const {
+ return llvm::makeArrayRef(getRHSExprs().end(), varlist_size());
+ }
+
+public:
+ /// Creates clause with a list of variables \a VL.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param ColonLoc Location of ':'.
+ /// \param EndLoc Ending location of the clause.
+ /// \param VL The variables in the clause.
+ /// \param QualifierLoc The nested-name qualifier with location information
+ /// \param NameInfo The full name info for reduction identifier.
+ /// \param Privates List of helper expressions for proper generation of
+ /// private copies.
+ /// \param LHSExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// LHSs of the reduction expressions.
+ /// \param RHSExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// RHSs of the reduction expressions.
+ /// Also, variables in these expressions are used for proper initialization of
+ /// reduction copies.
+ /// \param ReductionOps List of helper expressions that represents reduction
+ /// expressions:
+ /// \code
+ /// LHSExprs binop RHSExprs;
+ /// operator binop(LHSExpr, RHSExpr);
+ /// <CutomReduction>(LHSExpr, RHSExpr);
+ /// \endcode
+ /// Required for proper codegen of final reduction operation performed by the
+ /// reduction clause.
+ /// \param PreInit Statement that must be executed before entering the OpenMP
+ /// region with this clause.
+ /// \param PostUpdate Expression that must be executed after exit from the
+ /// OpenMP region with this clause.
+ ///
+ static OMPTaskReductionClause *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
+ NestedNameSpecifierLoc QualifierLoc,
+ const DeclarationNameInfo &NameInfo, ArrayRef<Expr *> Privates,
+ ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs,
+ ArrayRef<Expr *> ReductionOps, Stmt *PreInit, Expr *PostUpdate);
+
+ /// Creates an empty clause with the place for \a N variables.
+ ///
+ /// \param C AST context.
+ /// \param N The number of variables.
+ ///
+ static OMPTaskReductionClause *CreateEmpty(const ASTContext &C, unsigned N);
+
+ /// Gets location of ':' symbol in clause.
+ SourceLocation getColonLoc() const { return ColonLoc; }
+ /// Gets the name info for specified reduction identifier.
+ const DeclarationNameInfo &getNameInfo() const { return NameInfo; }
+ /// Gets the nested name specifier.
+ NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
+
+ typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
+ typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
+ typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
+ typedef llvm::iterator_range<helper_expr_const_iterator>
+ helper_expr_const_range;
+
+ helper_expr_const_range privates() const {
+ return helper_expr_const_range(getPrivates().begin(), getPrivates().end());
+ }
+ helper_expr_range privates() {
+ return helper_expr_range(getPrivates().begin(), getPrivates().end());
+ }
+ helper_expr_const_range lhs_exprs() const {
+ return helper_expr_const_range(getLHSExprs().begin(), getLHSExprs().end());
+ }
+ helper_expr_range lhs_exprs() {
+ return helper_expr_range(getLHSExprs().begin(), getLHSExprs().end());
+ }
+ helper_expr_const_range rhs_exprs() const {
+ return helper_expr_const_range(getRHSExprs().begin(), getRHSExprs().end());
+ }
+ helper_expr_range rhs_exprs() {
+ return helper_expr_range(getRHSExprs().begin(), getRHSExprs().end());
+ }
+ helper_expr_const_range reduction_ops() const {
+ return helper_expr_const_range(getReductionOps().begin(),
+ getReductionOps().end());
+ }
+ helper_expr_range reduction_ops() {
+ return helper_expr_range(getReductionOps().begin(),
+ getReductionOps().end());
+ }
+
+ child_range children() {
+ return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_task_reduction;
+ }
+};
+
/// \brief This represents clause 'linear' in the '#pragma omp ...'
/// directives.
///
@@ -2978,7 +3213,7 @@ protected:
// Organize the components by declaration and retrieve the original
// expression. Original expressions are always the first component of the
// mappable component list.
- llvm::DenseMap<ValueDecl *, SmallVector<MappableExprComponentListRef, 8>>
+ llvm::MapVector<ValueDecl *, SmallVector<MappableExprComponentListRef, 8>>
ComponentListMap;
{
auto CI = ComponentLists.begin();
@@ -3456,7 +3691,7 @@ public:
/// In this example directive '#pragma omp teams' has clause 'num_teams'
/// with single expression 'n'.
///
-class OMPNumTeamsClause : public OMPClause {
+class OMPNumTeamsClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// \brief Location of '('.
SourceLocation LParenLoc;
@@ -3472,20 +3707,27 @@ public:
/// \brief Build 'num_teams' clause.
///
/// \param E Expression associated with this clause.
+ /// \param HelperE Helper Expression associated with this clause.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
///
- OMPNumTeamsClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
+ OMPNumTeamsClause(Expr *E, Stmt *HelperE, OpenMPDirectiveKind CaptureRegion,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc)
- : OMPClause(OMPC_num_teams, StartLoc, EndLoc), LParenLoc(LParenLoc),
- NumTeams(E) {}
+ : OMPClause(OMPC_num_teams, StartLoc, EndLoc), OMPClauseWithPreInit(this),
+ LParenLoc(LParenLoc), NumTeams(E) {
+ setPreInitStmt(HelperE, CaptureRegion);
+ }
/// \brief Build an empty clause.
///
OMPNumTeamsClause()
- : OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()),
- LParenLoc(SourceLocation()), NumTeams(nullptr) {}
+ : OMPClause(OMPC_num_teams, SourceLocation(), SourceLocation()),
+ OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
+ NumTeams(nullptr) {}
/// \brief Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
/// \brief Returns the location of '('.
@@ -3511,7 +3753,7 @@ public:
/// In this example directive '#pragma omp teams' has clause 'thread_limit'
/// with single expression 'n'.
///
-class OMPThreadLimitClause : public OMPClause {
+class OMPThreadLimitClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// \brief Location of '('.
SourceLocation LParenLoc;
@@ -3527,20 +3769,28 @@ public:
/// \brief Build 'thread_limit' clause.
///
/// \param E Expression associated with this clause.
+ /// \param HelperE Helper Expression associated with this clause.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
///
- OMPThreadLimitClause(Expr *E, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc)
- : OMPClause(OMPC_thread_limit, StartLoc, EndLoc), LParenLoc(LParenLoc),
- ThreadLimit(E) {}
+ OMPThreadLimitClause(Expr *E, Stmt *HelperE,
+ OpenMPDirectiveKind CaptureRegion,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc)
+ : OMPClause(OMPC_thread_limit, StartLoc, EndLoc),
+ OMPClauseWithPreInit(this), LParenLoc(LParenLoc), ThreadLimit(E) {
+ setPreInitStmt(HelperE, CaptureRegion);
+ }
/// \brief Build an empty clause.
///
OMPThreadLimitClause()
: OMPClause(OMPC_thread_limit, SourceLocation(), SourceLocation()),
- LParenLoc(SourceLocation()), ThreadLimit(nullptr) {}
+ OMPClauseWithPreInit(this), LParenLoc(SourceLocation()),
+ ThreadLimit(nullptr) {}
/// \brief Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
/// \brief Returns the location of '('.
diff --git a/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h
index 10a930a..e7f271c 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -593,6 +593,16 @@ bool RecursiveASTVisitor<Derived>::PostVisitStmt(Stmt *S) {
#define STMT(CLASS, PARENT) \
case Stmt::CLASS##Class: \
TRY_TO(WalkUpFrom##CLASS(static_cast<CLASS *>(S))); break;
+#define INITLISTEXPR(CLASS, PARENT) \
+ case Stmt::CLASS##Class: \
+ { \
+ auto ILE = static_cast<CLASS *>(S); \
+ if (auto Syn = ILE->isSemanticForm() ? ILE->getSyntacticForm() : ILE) \
+ TRY_TO(WalkUpFrom##CLASS(Syn)); \
+ if (auto Sem = ILE->isSemanticForm() ? ILE : ILE->getSemanticForm()) \
+ TRY_TO(WalkUpFrom##CLASS(Sem)); \
+ break; \
+ }
#include "clang/AST/StmtNodes.inc"
}
@@ -774,6 +784,11 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc()));
break;
+ case DeclarationName::CXXDeductionGuideName:
+ TRY_TO(TraverseTemplateName(
+ TemplateName(NameInfo.getName().getCXXDeductionGuideTemplate())));
+ break;
+
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
@@ -1008,12 +1023,20 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, {
})
DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
+DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
+ TRY_TO(TraverseTemplateName(T->getTemplateName()));
+ TRY_TO(TraverseType(T->getDeducedType()));
+})
DEF_TRAVERSE_TYPE(RecordType, {})
DEF_TRAVERSE_TYPE(EnumType, {})
DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
-DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {})
-DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {})
+DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
+ TRY_TO(TraverseType(T->getReplacementType()));
+})
+DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
+ TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
+})
DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
TRY_TO(TraverseTemplateName(T->getTemplateName()));
@@ -1232,11 +1255,20 @@ DEF_TRAVERSE_TYPELOC(AutoType, {
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
})
+DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
+ TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName()));
+ TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
+})
+
DEF_TRAVERSE_TYPELOC(RecordType, {})
DEF_TRAVERSE_TYPELOC(EnumType, {})
DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
-DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {})
-DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {})
+DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
+ TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
+})
+DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {
+ TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack()));
+})
// FIXME: use the loc for the template name?
DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
@@ -1767,6 +1799,7 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
\
+ TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); \
if (!getDerived().shouldVisitTemplateInstantiations() && \
D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \
/* Returning from here skips traversing the \
@@ -1932,6 +1965,13 @@ DEF_TRAVERSE_DECL(FunctionDecl, {
ReturnValue = TraverseFunctionHelper(D);
})
+DEF_TRAVERSE_DECL(CXXDeductionGuideDecl, {
+ // We skip decls_begin/decls_end, which are already covered by
+ // TraverseFunctionHelper().
+ ShouldVisitChildren = false;
+ ReturnValue = TraverseFunctionHelper(D);
+})
+
DEF_TRAVERSE_DECL(CXXMethodDecl, {
// We skip decls_begin/decls_end, which are already covered by
// TraverseFunctionHelper().
@@ -2191,13 +2231,15 @@ bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
// the syntactic and the semantic form.
//
// There is no guarantee about which form \p S takes when this method is called.
-DEF_TRAVERSE_STMT(InitListExpr, {
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(
+ InitListExpr *S, DataRecursionQueue *Queue) {
TRY_TO(TraverseSynOrSemInitListExpr(
S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
TRY_TO(TraverseSynOrSemInitListExpr(
S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
- ShouldVisitChildren = false;
-})
+ return true;
+}
// GenericSelectionExpr is a special case because the types and expressions
// are interleaved. We also need to watch out for null types (default
@@ -2305,7 +2347,7 @@ DEF_TRAVERSE_STMT(LambdaExpr, {
}
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
- FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>();
+ FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
// Visit the whole type.
@@ -2495,6 +2537,12 @@ DEF_TRAVERSE_STMT(CoawaitExpr, {
ShouldVisitChildren = false;
}
})
+DEF_TRAVERSE_STMT(DependentCoawaitExpr, {
+ if (!getDerived().shouldVisitImplicitCode()) {
+ TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
+ ShouldVisitChildren = false;
+ }
+})
DEF_TRAVERSE_STMT(CoyieldExpr, {
if (!getDerived().shouldVisitImplicitCode()) {
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand());
@@ -2711,6 +2759,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPClauseWithPostUpdate(
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPIfClause(OMPIfClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getCondition()));
return true;
}
@@ -2724,6 +2773,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPFinalClause(OMPFinalClause *C) {
template <typename Derived>
bool
RecursiveASTVisitor<Derived>::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getNumThreads()));
return true;
}
@@ -2967,6 +3017,28 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) {
}
template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPTaskReductionClause(
+ OMPTaskReductionClause *C) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
+ TRY_TO(VisitOMPClauseList(C));
+ TRY_TO(VisitOMPClauseWithPostUpdate(C));
+ for (auto *E : C->privates()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->lhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->rhs_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->reduction_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ return true;
+}
+
+template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPFlushClause(OMPFlushClause *C) {
TRY_TO(VisitOMPClauseList(C));
return true;
@@ -2993,6 +3065,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
OMPNumTeamsClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getNumTeams()));
return true;
}
@@ -3000,6 +3073,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPThreadLimitClause(
OMPThreadLimitClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getThreadLimit()));
return true;
}
diff --git a/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h b/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h
index cd5f186..89a9d3c 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h
@@ -21,6 +21,60 @@
namespace clang {
class ASTContext;
+// Some notes on redeclarables:
+//
+// - Every redeclarable is on a circular linked list.
+//
+// - Every decl has a pointer to the first element of the chain _and_ a
+// DeclLink that may point to one of 3 possible states:
+// - the "previous" (temporal) element in the chain
+// - the "latest" (temporal) element in the chain
+// - the an "uninitialized-latest" value (when newly-constructed)
+//
+// - The first element is also often called the canonical element. Every
+// element has a pointer to it so that "getCanonical" can be fast.
+//
+// - Most links in the chain point to previous, except the link out of
+// the first; it points to latest.
+//
+// - Elements are called "first", "previous", "latest" or
+// "most-recent" when referring to temporal order: order of addition
+// to the chain.
+//
+// - To make matters confusing, the DeclLink type uses the term "next"
+// for its pointer-storage internally (thus functions like
+// NextIsPrevious). It's easiest to just ignore the implementation of
+// DeclLink when making sense of the redeclaration chain.
+//
+// - There's also a "definition" link for several types of
+// redeclarable, where only one definition should exist at any given
+// time (and the defn pointer is stored in the decl's "data" which
+// is copied to every element on the chain when it's changed).
+//
+// Here is some ASCII art:
+//
+// "first" "latest"
+// "canonical" "most recent"
+// +------------+ first +--------------+
+// | | <--------------------------- | |
+// | | | |
+// | | | |
+// | | +--------------+ | |
+// | | first | | | |
+// | | <---- | | | |
+// | | | | | |
+// | @class A | link | @interface A | link | @class A |
+// | seen first | <---- | seen second | <---- | seen third |
+// | | | | | |
+// +------------+ +--------------+ +--------------+
+// | data | defn | data | defn | data |
+// | | ----> | | <---- | |
+// +------------+ +--------------+ +--------------+
+// | | ^ ^
+// | |defn | |
+// | link +-----+ |
+// +-->-------------------------------------------+
+
/// \brief Provides common interface for the Decls that can be redeclared.
template<typename decl_type>
class Redeclarable {
diff --git a/contrib/llvm/tools/clang/include/clang/AST/Stmt.h b/contrib/llvm/tools/clang/include/clang/AST/Stmt.h
index e28675d..c210bd1 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Stmt.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/Stmt.h
@@ -39,6 +39,7 @@ namespace clang {
class Expr;
class IdentifierInfo;
class LabelDecl;
+ class ODRHash;
class ParmVarDecl;
class PrinterHelper;
struct PrintingPolicy;
@@ -126,13 +127,13 @@ protected:
unsigned : NumStmtBits;
unsigned ValueKind : 2;
- unsigned ObjectKind : 2;
+ unsigned ObjectKind : 3;
unsigned TypeDependent : 1;
unsigned ValueDependent : 1;
unsigned InstantiationDependent : 1;
unsigned ContainsUnexpandedParameterPack : 1;
};
- enum { NumExprBits = 16 };
+ enum { NumExprBits = 17 };
class CharacterLiteralBitfields {
friend class CharacterLiteral;
@@ -252,6 +253,14 @@ protected:
unsigned NumArgs : 32 - 8 - 1 - NumExprBits;
};
+ class CoawaitExprBitfields {
+ friend class CoawaitExpr;
+
+ unsigned : NumExprBits;
+
+ unsigned IsImplicit : 1;
+ };
+
union {
StmtBitfields StmtBits;
CompoundStmtBitfields CompoundStmtBits;
@@ -268,6 +277,7 @@ protected:
ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
InitListExprBitfields InitListExprBits;
TypeTraitExprBitfields TypeTraitExprBits;
+ CoawaitExprBitfields CoawaitBits;
};
friend class ASTStmtReader;
@@ -340,6 +350,8 @@ protected:
public:
Stmt(StmtClass SC) {
+ static_assert(sizeof(*this) == sizeof(void *),
+ "changing bitfields changed sizeof(Stmt)");
static_assert(sizeof(*this) % alignof(void *) == 0,
"Insufficient alignment!");
StmtBits.sClass = SC;
@@ -436,6 +448,15 @@ public:
/// written in the source.
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
bool Canonical) const;
+
+ /// \brief Calculate a unique representation for a statement that is
+ /// stable across compiler invocations.
+ ///
+ /// \param ID profile information will be stored in ID.
+ ///
+ /// \param Hash an ODRHash object which will be called where pointers would
+ /// have been used in the Profile function.
+ void ProcessODRHash(llvm::FoldingSetNodeID &ID, ODRHash& Hash) const;
};
/// DeclStmt - Adaptor class for mixing declarations with statements and
diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h b/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h
index 8eef34c..77f8183 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h
@@ -296,7 +296,9 @@ public:
/// \brief Represents the body of a coroutine. This wraps the normal function
/// body and holds the additional semantic context required to set up and tear
/// down the coroutine frame.
-class CoroutineBodyStmt : public Stmt {
+class CoroutineBodyStmt final
+ : public Stmt,
+ private llvm::TrailingObjects<CoroutineBodyStmt, Stmt *> {
enum SubStmt {
Body, ///< The body of the coroutine.
Promise, ///< The promise statement.
@@ -306,66 +308,109 @@ class CoroutineBodyStmt : public Stmt {
OnFallthrough, ///< Handler for control flow falling off the body.
Allocate, ///< Coroutine frame memory allocation.
Deallocate, ///< Coroutine frame memory deallocation.
- ReturnValue, ///< Return value for thunk function.
+ ReturnValue, ///< Return value for thunk function: p.get_return_object().
+ ResultDecl, ///< Declaration holding the result of get_return_object.
+ ReturnStmt, ///< Return statement for the thunk function.
+ ReturnStmtOnAllocFailure, ///< Return statement if allocation failed.
FirstParamMove ///< First offset for move construction of parameter copies.
};
- Stmt *SubStmts[SubStmt::FirstParamMove];
+ unsigned NumParams;
friend class ASTStmtReader;
+ friend class ASTReader;
+ friend TrailingObjects;
+
+ Stmt **getStoredStmts() { return getTrailingObjects<Stmt *>(); }
+
+ Stmt *const *getStoredStmts() const { return getTrailingObjects<Stmt *>(); }
+
+public:
+
+ struct CtorArgs {
+ Stmt *Body = nullptr;
+ Stmt *Promise = nullptr;
+ Expr *InitialSuspend = nullptr;
+ Expr *FinalSuspend = nullptr;
+ Stmt *OnException = nullptr;
+ Stmt *OnFallthrough = nullptr;
+ Expr *Allocate = nullptr;
+ Expr *Deallocate = nullptr;
+ Expr *ReturnValue = nullptr;
+ Stmt *ResultDecl = nullptr;
+ Stmt *ReturnStmt = nullptr;
+ Stmt *ReturnStmtOnAllocFailure = nullptr;
+ ArrayRef<Stmt *> ParamMoves;
+ };
+
+private:
+
+ CoroutineBodyStmt(CtorArgs const& Args);
+
public:
- CoroutineBodyStmt(Stmt *Body, Stmt *Promise, Stmt *InitSuspend,
- Stmt *FinalSuspend, Stmt *OnException, Stmt *OnFallthrough,
- Expr *Allocate, Stmt *Deallocate,
- Expr *ReturnValue, ArrayRef<Expr *> ParamMoves)
- : Stmt(CoroutineBodyStmtClass) {
- SubStmts[CoroutineBodyStmt::Body] = Body;
- SubStmts[CoroutineBodyStmt::Promise] = Promise;
- SubStmts[CoroutineBodyStmt::InitSuspend] = InitSuspend;
- SubStmts[CoroutineBodyStmt::FinalSuspend] = FinalSuspend;
- SubStmts[CoroutineBodyStmt::OnException] = OnException;
- SubStmts[CoroutineBodyStmt::OnFallthrough] = OnFallthrough;
- SubStmts[CoroutineBodyStmt::Allocate] = Allocate;
- SubStmts[CoroutineBodyStmt::Deallocate] = Deallocate;
- SubStmts[CoroutineBodyStmt::ReturnValue] = ReturnValue;
- // FIXME: Tail-allocate space for parameter move expressions and store them.
- assert(ParamMoves.empty() && "not implemented yet");
+ static CoroutineBodyStmt *Create(const ASTContext &C, CtorArgs const &Args);
+ static CoroutineBodyStmt *Create(const ASTContext &C, EmptyShell,
+ unsigned NumParams);
+
+ bool hasDependentPromiseType() const {
+ return getPromiseDecl()->getType()->isDependentType();
}
/// \brief Retrieve the body of the coroutine as written. This will be either
/// a CompoundStmt or a TryStmt.
Stmt *getBody() const {
- return SubStmts[SubStmt::Body];
+ return getStoredStmts()[SubStmt::Body];
}
- Stmt *getPromiseDeclStmt() const { return SubStmts[SubStmt::Promise]; }
+ Stmt *getPromiseDeclStmt() const {
+ return getStoredStmts()[SubStmt::Promise];
+ }
VarDecl *getPromiseDecl() const {
return cast<VarDecl>(cast<DeclStmt>(getPromiseDeclStmt())->getSingleDecl());
}
- Stmt *getInitSuspendStmt() const { return SubStmts[SubStmt::InitSuspend]; }
- Stmt *getFinalSuspendStmt() const { return SubStmts[SubStmt::FinalSuspend]; }
+ Stmt *getInitSuspendStmt() const {
+ return getStoredStmts()[SubStmt::InitSuspend];
+ }
+ Stmt *getFinalSuspendStmt() const {
+ return getStoredStmts()[SubStmt::FinalSuspend];
+ }
- Stmt *getExceptionHandler() const { return SubStmts[SubStmt::OnException]; }
+ Stmt *getExceptionHandler() const {
+ return getStoredStmts()[SubStmt::OnException];
+ }
Stmt *getFallthroughHandler() const {
- return SubStmts[SubStmt::OnFallthrough];
+ return getStoredStmts()[SubStmt::OnFallthrough];
}
- Expr *getAllocate() const { return cast<Expr>(SubStmts[SubStmt::Allocate]); }
- Stmt *getDeallocate() const { return SubStmts[SubStmt::Deallocate]; }
-
+ Expr *getAllocate() const {
+ return cast_or_null<Expr>(getStoredStmts()[SubStmt::Allocate]);
+ }
+ Expr *getDeallocate() const {
+ return cast_or_null<Expr>(getStoredStmts()[SubStmt::Deallocate]);
+ }
Expr *getReturnValueInit() const {
- return cast<Expr>(SubStmts[SubStmt::ReturnValue]);
+ return cast<Expr>(getStoredStmts()[SubStmt::ReturnValue]);
+ }
+ Stmt *getResultDecl() const { return getStoredStmts()[SubStmt::ResultDecl]; }
+ Stmt *getReturnStmt() const { return getStoredStmts()[SubStmt::ReturnStmt]; }
+ Stmt *getReturnStmtOnAllocFailure() const {
+ return getStoredStmts()[SubStmt::ReturnStmtOnAllocFailure];
+ }
+ ArrayRef<Stmt const *> getParamMoves() const {
+ return {getStoredStmts() + SubStmt::FirstParamMove, NumParams};
}
SourceLocation getLocStart() const LLVM_READONLY {
- return getBody()->getLocStart();
+ return getBody() ? getBody()->getLocStart()
+ : getPromiseDecl()->getLocStart();
}
SourceLocation getLocEnd() const LLVM_READONLY {
- return getBody()->getLocEnd();
+ return getBody() ? getBody()->getLocEnd() : getPromiseDecl()->getLocEnd();
}
child_range children() {
- return child_range(SubStmts, SubStmts + SubStmt::FirstParamMove);
+ return child_range(getStoredStmts(),
+ getStoredStmts() + SubStmt::FirstParamMove + NumParams);
}
static bool classof(const Stmt *T) {
@@ -390,14 +435,20 @@ class CoreturnStmt : public Stmt {
enum SubStmt { Operand, PromiseCall, Count };
Stmt *SubStmts[SubStmt::Count];
+ bool IsImplicit : 1;
+
friend class ASTStmtReader;
public:
- CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall)
- : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc) {
+ CoreturnStmt(SourceLocation CoreturnLoc, Stmt *Operand, Stmt *PromiseCall,
+ bool IsImplicit = false)
+ : Stmt(CoreturnStmtClass), CoreturnLoc(CoreturnLoc),
+ IsImplicit(IsImplicit) {
SubStmts[SubStmt::Operand] = Operand;
SubStmts[SubStmt::PromiseCall] = PromiseCall;
}
+ CoreturnStmt(EmptyShell) : CoreturnStmt({}, {}, {}) {}
+
SourceLocation getKeywordLoc() const { return CoreturnLoc; }
/// \brief Retrieve the operand of the 'co_return' statement. Will be nullptr
@@ -411,6 +462,9 @@ public:
return static_cast<Expr*>(SubStmts[PromiseCall]);
}
+ bool isImplicit() const { return IsImplicit; }
+ void setIsImplicit(bool value = true) { IsImplicit = value; }
+
SourceLocation getLocStart() const LLVM_READONLY { return CoreturnLoc; }
SourceLocation getLocEnd() const LLVM_READONLY {
return getOperand() ? getOperand()->getLocEnd() : getLocStart();
diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h b/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h
index 81f8ad43..5d3bce8 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h
@@ -118,6 +118,8 @@ public:
REFERENCE operator->() const { return operator*(); }
};
+struct ConstStmtIterator;
+
struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {}
@@ -128,6 +130,13 @@ struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> {
StmtIterator(const VariableArrayType *t)
: StmtIteratorImpl<StmtIterator,Stmt*&>(t) {}
+
+private:
+ StmtIterator(const StmtIteratorBase &RHS)
+ : StmtIteratorImpl<StmtIterator, Stmt *&>(RHS) {}
+
+ inline friend StmtIterator
+ cast_away_const(const ConstStmtIterator &RHS);
};
struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
@@ -137,8 +146,15 @@ struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator,
ConstStmtIterator(const StmtIterator& RHS) :
StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {}
+
+ ConstStmtIterator(Stmt * const *S)
+ : StmtIteratorImpl<ConstStmtIterator, const Stmt *>(
+ const_cast<Stmt **>(S)) {}
};
+inline StmtIterator cast_away_const(const ConstStmtIterator &RHS) {
+ return RHS;
+}
} // end namespace clang
#endif
diff --git a/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h b/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h
index ec532ec..09dd87f 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/StmtOpenMP.h
@@ -198,6 +198,26 @@ public:
return const_cast<Stmt *>(*child_begin());
}
+ /// \brief Returns the captured statement associated with the
+ /// component region within the (combined) directive.
+ //
+ // \param RegionKind Component region kind.
+ CapturedStmt *getCapturedStmt(OpenMPDirectiveKind RegionKind) const {
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, getDirectiveKind());
+ assert(std::any_of(
+ CaptureRegions.begin(), CaptureRegions.end(),
+ [=](const OpenMPDirectiveKind K) { return K == RegionKind; }) &&
+ "RegionKind not found in OpenMP CaptureRegions.");
+ auto *CS = cast<CapturedStmt>(getAssociatedStmt());
+ for (auto ThisCaptureRegion : CaptureRegions) {
+ if (ThisCaptureRegion == RegionKind)
+ return CS;
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ }
+ llvm_unreachable("Incorrect RegionKind specified for directive.");
+ }
+
OpenMPDirectiveKind getDirectiveKind() const { return Kind; }
static bool classof(const Stmt *S) {
@@ -298,12 +318,18 @@ class OMPLoopDirective : public OMPExecutableDirective {
/// \brief Offsets to the stored exprs.
/// This enumeration contains offsets to all the pointers to children
/// expressions stored in OMPLoopDirective.
- /// The first 9 children are nesessary for all the loop directives, and
- /// the next 10 are specific to the worksharing ones.
+ /// The first 9 children are necessary for all the loop directives,
+ /// the next 8 are specific to the worksharing ones, and the next 11 are
+ /// used for combined constructs containing two pragmas associated to loops.
/// After the fixed children, three arrays of length CollapsedNum are
/// allocated: loop counters, their updates and final values.
/// PrevLowerBound and PrevUpperBound are used to communicate blocking
/// information in composite constructs which require loop blocking
+ /// DistInc is used to generate the increment expression for the distribute
+ /// loop when combined with a further nested loop
+ /// PrevEnsureUpperBound is used as the EnsureUpperBound expression for the
+ /// for loop when combined with a previous distribute loop in the same pragma
+ /// (e.g. 'distribute parallel for')
///
enum {
AssociatedStmtOffset = 0,
@@ -319,7 +345,7 @@ class OMPLoopDirective : public OMPExecutableDirective {
// specify the offset to the end (and start of the following counters/
// updates/finals arrays).
DefaultEnd = 9,
- // The following 7 exprs are used by worksharing loops only.
+ // The following 8 exprs are used by worksharing and distribute loops only.
IsLastIterVariableOffset = 9,
LowerBoundVariableOffset = 10,
UpperBoundVariableOffset = 11,
@@ -328,11 +354,22 @@ class OMPLoopDirective : public OMPExecutableDirective {
NextLowerBoundOffset = 14,
NextUpperBoundOffset = 15,
NumIterationsOffset = 16,
+ // Offset to the end for worksharing loop directives.
+ WorksharingEnd = 17,
PrevLowerBoundVariableOffset = 17,
PrevUpperBoundVariableOffset = 18,
+ DistIncOffset = 19,
+ PrevEnsureUpperBoundOffset = 20,
+ CombinedLowerBoundVariableOffset = 21,
+ CombinedUpperBoundVariableOffset = 22,
+ CombinedEnsureUpperBoundOffset = 23,
+ CombinedInitOffset = 24,
+ CombinedConditionOffset = 25,
+ CombinedNextLowerBoundOffset = 26,
+ CombinedNextUpperBoundOffset = 27,
// Offset to the end (and start of the following counters/updates/finals
- // arrays) for worksharing loop directives.
- WorksharingEnd = 19,
+ // arrays) for combined distribute loop directives.
+ CombinedDistributeEnd = 28,
};
/// \brief Get the counters storage.
@@ -396,11 +433,12 @@ protected:
/// \brief Offset to the start of children expression arrays.
static unsigned getArraysOffset(OpenMPDirectiveKind Kind) {
- return (isOpenMPWorksharingDirective(Kind) ||
- isOpenMPTaskLoopDirective(Kind) ||
- isOpenMPDistributeDirective(Kind))
- ? WorksharingEnd
- : DefaultEnd;
+ if (isOpenMPLoopBoundSharingDirective(Kind))
+ return CombinedDistributeEnd;
+ if (isOpenMPWorksharingDirective(Kind) || isOpenMPTaskLoopDirective(Kind) ||
+ isOpenMPDistributeDirective(Kind))
+ return WorksharingEnd;
+ return DefaultEnd;
}
/// \brief Children number.
@@ -488,19 +526,60 @@ protected:
*std::next(child_begin(), NumIterationsOffset) = NI;
}
void setPrevLowerBoundVariable(Expr *PrevLB) {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
*std::next(child_begin(), PrevLowerBoundVariableOffset) = PrevLB;
}
void setPrevUpperBoundVariable(Expr *PrevUB) {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
*std::next(child_begin(), PrevUpperBoundVariableOffset) = PrevUB;
}
+ void setDistInc(Expr *DistInc) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), DistIncOffset) = DistInc;
+ }
+ void setPrevEnsureUpperBound(Expr *PrevEUB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), PrevEnsureUpperBoundOffset) = PrevEUB;
+ }
+ void setCombinedLowerBoundVariable(Expr *CombLB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedLowerBoundVariableOffset) = CombLB;
+ }
+ void setCombinedUpperBoundVariable(Expr *CombUB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedUpperBoundVariableOffset) = CombUB;
+ }
+ void setCombinedEnsureUpperBound(Expr *CombEUB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedEnsureUpperBoundOffset) = CombEUB;
+ }
+ void setCombinedInit(Expr *CombInit) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedInitOffset) = CombInit;
+ }
+ void setCombinedCond(Expr *CombCond) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedConditionOffset) = CombCond;
+ }
+ void setCombinedNextLowerBound(Expr *CombNLB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedNextLowerBoundOffset) = CombNLB;
+ }
+ void setCombinedNextUpperBound(Expr *CombNUB) {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ *std::next(child_begin(), CombinedNextUpperBoundOffset) = CombNUB;
+ }
void setCounters(ArrayRef<Expr *> A);
void setPrivateCounters(ArrayRef<Expr *> A);
void setInits(ArrayRef<Expr *> A);
@@ -508,6 +587,33 @@ protected:
void setFinals(ArrayRef<Expr *> A);
public:
+ /// The expressions built to support OpenMP loops in combined/composite
+ /// pragmas (e.g. pragma omp distribute parallel for)
+ struct DistCombinedHelperExprs {
+ /// DistributeLowerBound - used when composing 'omp distribute' with
+ /// 'omp for' in a same construct.
+ Expr *LB;
+ /// DistributeUpperBound - used when composing 'omp distribute' with
+ /// 'omp for' in a same construct.
+ Expr *UB;
+ /// DistributeEnsureUpperBound - used when composing 'omp distribute'
+ /// with 'omp for' in a same construct, EUB depends on DistUB
+ Expr *EUB;
+ /// Distribute loop iteration variable init used when composing 'omp
+ /// distribute'
+ /// with 'omp for' in a same construct
+ Expr *Init;
+ /// Distribute Loop condition used when composing 'omp distribute'
+ /// with 'omp for' in a same construct
+ Expr *Cond;
+ /// Update of LowerBound for statically sheduled omp loops for
+ /// outer loop in combined constructs (e.g. 'distribute parallel for')
+ Expr *NLB;
+ /// Update of UpperBound for statically sheduled omp loops for
+ /// outer loop in combined constructs (e.g. 'distribute parallel for')
+ Expr *NUB;
+ };
+
/// \brief The expressions built for the OpenMP loop CodeGen for the
/// whole collapsed loop nest.
struct HelperExprs {
@@ -535,7 +641,7 @@ public:
Expr *UB;
/// \brief Stride - local variable passed to runtime.
Expr *ST;
- /// \brief EnsureUpperBound -- expression LB = min(LB, NumIterations).
+ /// \brief EnsureUpperBound -- expression UB = min(UB, NumIterations).
Expr *EUB;
/// \brief Update of LowerBound for statically sheduled 'omp for' loops.
Expr *NLB;
@@ -547,6 +653,16 @@ public:
/// \brief PreviousUpperBound - local variable passed to runtime in the
/// enclosing schedule or null if that does not apply.
Expr *PrevUB;
+ /// \brief DistInc - increment expression for distribute loop when found
+ /// combined with a further loop level (e.g. in 'distribute parallel for')
+ /// expression IV = IV + ST
+ Expr *DistInc;
+ /// \brief PrevEUB - expression similar to EUB but to be used when loop
+ /// scheduling uses PrevLB and PrevUB (e.g. in 'distribute parallel for'
+ /// when ensuring that the UB is either the calculated UB by the runtime or
+ /// the end of the assigned distribute chunk)
+ /// expression UB = min (UB, PrevUB)
+ Expr *PrevEUB;
/// \brief Counters Loop counters.
SmallVector<Expr *, 4> Counters;
/// \brief PrivateCounters Loop counters.
@@ -560,6 +676,9 @@ public:
/// Init statement for all captured expressions.
Stmt *PreInits;
+ /// Expressions used when combining OpenMP loop pragmas
+ DistCombinedHelperExprs DistCombinedFields;
+
/// \brief Check if all the expressions are built (does not check the
/// worksharing ones).
bool builtAll() {
@@ -588,6 +707,8 @@ public:
NumIterations = nullptr;
PrevLB = nullptr;
PrevUB = nullptr;
+ DistInc = nullptr;
+ PrevEUB = nullptr;
Counters.resize(Size);
PrivateCounters.resize(Size);
Inits.resize(Size);
@@ -601,6 +722,13 @@ public:
Finals[i] = nullptr;
}
PreInits = nullptr;
+ DistCombinedFields.LB = nullptr;
+ DistCombinedFields.UB = nullptr;
+ DistCombinedFields.EUB = nullptr;
+ DistCombinedFields.Init = nullptr;
+ DistCombinedFields.Cond = nullptr;
+ DistCombinedFields.NLB = nullptr;
+ DistCombinedFields.NUB = nullptr;
}
};
@@ -704,21 +832,71 @@ public:
*std::next(child_begin(), NumIterationsOffset)));
}
Expr *getPrevLowerBoundVariable() const {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), PrevLowerBoundVariableOffset)));
}
Expr *getPrevUpperBoundVariable() const {
- assert((isOpenMPWorksharingDirective(getDirectiveKind()) ||
- isOpenMPTaskLoopDirective(getDirectiveKind()) ||
- isOpenMPDistributeDirective(getDirectiveKind())) &&
- "expected worksharing loop directive");
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
return const_cast<Expr *>(reinterpret_cast<const Expr *>(
*std::next(child_begin(), PrevUpperBoundVariableOffset)));
}
+ Expr *getDistInc() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), DistIncOffset)));
+ }
+ Expr *getPrevEnsureUpperBound() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), PrevEnsureUpperBoundOffset)));
+ }
+ Expr *getCombinedLowerBoundVariable() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedLowerBoundVariableOffset)));
+ }
+ Expr *getCombinedUpperBoundVariable() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedUpperBoundVariableOffset)));
+ }
+ Expr *getCombinedEnsureUpperBound() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedEnsureUpperBoundOffset)));
+ }
+ Expr *getCombinedInit() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedInitOffset)));
+ }
+ Expr *getCombinedCond() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedConditionOffset)));
+ }
+ Expr *getCombinedNextLowerBound() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedNextLowerBoundOffset)));
+ }
+ Expr *getCombinedNextUpperBound() const {
+ assert(isOpenMPLoopBoundSharingDirective(getDirectiveKind()) &&
+ "expected loop bound sharing directive");
+ return const_cast<Expr *>(reinterpret_cast<const Expr *>(
+ *std::next(child_begin(), CombinedNextUpperBoundOffset)));
+ }
const Stmt *getBody() const {
// This relies on the loop form is already checked by Sema.
Stmt *Body = getAssociatedStmt()->IgnoreContainers(true);
@@ -1717,7 +1895,7 @@ public:
}
};
-/// \brief This represents '#pragma omp taskgroup' directive.
+/// This represents '#pragma omp taskgroup' directive.
///
/// \code
/// #pragma omp taskgroup
@@ -1725,39 +1903,45 @@ public:
///
class OMPTaskgroupDirective : public OMPExecutableDirective {
friend class ASTStmtReader;
- /// \brief Build directive with the given start and end location.
+ /// Build directive with the given start and end location.
///
/// \param StartLoc Starting location of the directive kind.
/// \param EndLoc Ending location of the directive.
+ /// \param NumClauses Number of clauses.
///
- OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc)
+ OMPTaskgroupDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned NumClauses)
: OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup,
- StartLoc, EndLoc, 0, 1) {}
+ StartLoc, EndLoc, NumClauses, 1) {}
- /// \brief Build an empty directive.
+ /// Build an empty directive.
+ /// \param NumClauses Number of clauses.
///
- explicit OMPTaskgroupDirective()
+ explicit OMPTaskgroupDirective(unsigned NumClauses)
: OMPExecutableDirective(this, OMPTaskgroupDirectiveClass, OMPD_taskgroup,
- SourceLocation(), SourceLocation(), 0, 1) {}
+ SourceLocation(), SourceLocation(), NumClauses,
+ 1) {}
public:
- /// \brief Creates directive.
+ /// Creates directive.
///
/// \param C AST context.
/// \param StartLoc Starting location of the directive kind.
/// \param EndLoc Ending Location of the directive.
+ /// \param Clauses List of clauses.
/// \param AssociatedStmt Statement, associated with the directive.
///
- static OMPTaskgroupDirective *Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation EndLoc,
- Stmt *AssociatedStmt);
+ static OMPTaskgroupDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt);
- /// \brief Creates an empty directive.
+ /// Creates an empty directive.
///
/// \param C AST context.
+ /// \param NumClauses Number of clauses.
///
- static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C, EmptyShell);
+ static OMPTaskgroupDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell);
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPTaskgroupDirectiveClass;
diff --git a/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h b/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h
index 7f28986..84fbcda 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h
@@ -119,10 +119,7 @@ private:
public:
/// \brief Construct an empty, invalid template argument.
- TemplateArgument() {
- TypeOrValue.Kind = Null;
- TypeOrValue.V = 0;
- }
+ constexpr TemplateArgument() : TypeOrValue({Null, 0}) {}
/// \brief Construct a template type argument.
TemplateArgument(QualType T, bool isNullPtr = false) {
@@ -388,8 +385,8 @@ private:
};
public:
- TemplateArgumentLocInfo();
-
+ constexpr TemplateArgumentLocInfo() : Template({nullptr, nullptr, 0, 0}) {}
+
TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {}
TemplateArgumentLocInfo(Expr *E) : Expression(E) {}
@@ -433,7 +430,7 @@ class TemplateArgumentLoc {
TemplateArgumentLocInfo LocInfo;
public:
- TemplateArgumentLoc() {}
+ constexpr TemplateArgumentLoc() {}
TemplateArgumentLoc(const TemplateArgument &Argument,
TemplateArgumentLocInfo Opaque)
@@ -578,6 +575,7 @@ struct ASTTemplateArgumentListInfo final
TemplateArgumentLoc> {
private:
friend TrailingObjects;
+ friend class ASTNodeImporter;
ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List);
diff --git a/contrib/llvm/tools/clang/include/clang/AST/Type.h b/contrib/llvm/tools/clang/include/clang/AST/Type.h
index a50e054..984096f 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Type.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/Type.h
@@ -333,6 +333,23 @@ public:
bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
+ bool hasTargetSpecificAddressSpace() const {
+ return getAddressSpace() >= LangAS::FirstTargetAddressSpace;
+ }
+ /// Get the address space attribute value to be printed by diagnostics.
+ unsigned getAddressSpaceAttributePrintValue() const {
+ auto Addr = getAddressSpace();
+ // This function is not supposed to be used with language specific
+ // address spaces. If that happens, the diagnostic message should consider
+ // printing the QualType instead of the address space value.
+ assert(Addr == 0 || hasTargetSpecificAddressSpace());
+ if (Addr)
+ return Addr - LangAS::FirstTargetAddressSpace;
+ // TODO: The diagnostic messages where Addr may be 0 should be fixed
+ // since it cannot differentiate the situation where 0 denotes the default
+ // address space or user specified __attribute__((address_space(0))).
+ return 0;
+ }
void setAddressSpace(unsigned space) {
assert(space <= MaxAddressSpace);
Mask = (Mask & ~AddressSpaceMask)
@@ -1020,6 +1037,9 @@ public:
return getQualifiers().hasStrongOrWeakObjCLifetime();
}
+ // true when Type is objc's weak and weak is enabled but ARC isn't.
+ bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const;
+
enum DestructionKind {
DK_none,
DK_cxx_destructor,
@@ -1379,7 +1399,7 @@ protected:
/// Extra information which affects how the function is called, like
/// regparm and the calling convention.
- unsigned ExtInfo : 10;
+ unsigned ExtInfo : 11;
/// Used only by FunctionProtoType, put here to pack with the
/// other bitfields.
@@ -1732,6 +1752,7 @@ public:
bool isTemplateTypeParmType() const; // C++ template type parameter
bool isNullPtrType() const; // C++11 std::nullptr_t
bool isAlignValT() const; // C++17 std::align_val_t
+ bool isStdByteType() const; // C++17 std::byte
bool isAtomicType() const; // C11 _Atomic()
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
@@ -1744,7 +1765,6 @@ public:
bool isEventT() const; // OpenCL event_t
bool isClkEventT() const; // OpenCL clk_event_t
bool isQueueT() const; // OpenCL queue_t
- bool isNDRangeT() const; // OpenCL ndrange_t
bool isReserveIDT() const; // OpenCL reserve_id_t
bool isPipeType() const; // OpenCL pipe type
@@ -1785,7 +1805,8 @@ public:
}
/// \brief Determine whether this type is an undeduced type, meaning that
- /// it somehow involves a C++11 'auto' type which has not yet been deduced.
+ /// it somehow involves a C++11 'auto' type or similar which has not yet been
+ /// deduced.
bool isUndeducedType() const;
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
@@ -1862,10 +1883,22 @@ public:
/// not refer to a CXXRecordDecl, returns NULL.
const CXXRecordDecl *getPointeeCXXRecordDecl() const;
+ /// Get the DeducedType whose type will be deduced for a variable with
+ /// an initializer of this type. This looks through declarators like pointer
+ /// types, but not through decltype or typedefs.
+ DeducedType *getContainedDeducedType() const;
+
/// Get the AutoType whose type will be deduced for a variable with
/// an initializer of this type. This looks through declarators like pointer
/// types, but not through decltype or typedefs.
- AutoType *getContainedAutoType() const;
+ AutoType *getContainedAutoType() const {
+ return dyn_cast_or_null<AutoType>(getContainedDeducedType());
+ }
+
+ /// Determine whether this type was written with a leading 'auto'
+ /// corresponding to a trailing return type (possibly for a nested
+ /// function type within a pointer to function type or similar).
+ bool hasAutoForTrailingReturnType() const;
/// Member-template getAs<specific type>'. Look through sugar for
/// an instance of \<specific type>. This scheme will eventually
@@ -1875,6 +1908,13 @@ public:
/// immediately following this class.
template <typename T> const T *getAs() const;
+ /// Member-template getAsAdjusted<specific type>. Look through specific kinds
+ /// of sugar (parens, attributes, etc) for an instance of \<specific type>.
+ /// This is used when you need to walk over sugar nodes that represent some
+ /// kind of type adjustment from a type that was written as a \<specific type>
+ /// to another type that is still canonically a \<specific type>.
+ template <typename T> const T *getAsAdjusted() const;
+
/// A variant of getAs<> for array types which silently discards
/// qualifiers from the outermost type.
const ArrayType *getAsArrayTypeUnsafe() const;
@@ -1972,10 +2012,11 @@ public:
Optional<NullabilityKind> getNullability(const ASTContext &context) const;
/// Determine whether the given type can have a nullability
- /// specifier applied to it, i.e., if it is any kind of pointer type
- /// or a dependent type that could instantiate to any kind of
- /// pointer type.
- bool canHaveNullability() const;
+ /// specifier applied to it, i.e., if it is any kind of pointer type.
+ ///
+ /// \param ResultIfUnknown The value to return if we don't yet know whether
+ /// this type can have nullability because it is dependent.
+ bool canHaveNullability(bool ResultIfUnknown = true) const;
/// Retrieve the set of substitutions required when accessing a member
/// of the Objective-C receiver type that is declared in the given context.
@@ -2057,7 +2098,7 @@ public:
: Type(Builtin, QualType(), /*Dependent=*/(K == Dependent),
/*InstantiationDependent=*/(K == Dependent),
/*VariablyModified=*/false,
- /*Unexpanded paramter pack=*/false) {
+ /*Unexpanded parameter pack=*/false) {
BuiltinTypeBits.Kind = K;
}
@@ -2905,19 +2946,23 @@ class FunctionType : public Type {
// * AST read and write
// * Codegen
class ExtInfo {
- // Feel free to rearrange or add bits, but if you go over 10,
+ // Feel free to rearrange or add bits, but if you go over 11,
// you'll need to adjust both the Bits field below and
// Type::FunctionTypeBitfields.
- // | CC |noreturn|produces|regparm|
- // |0 .. 4| 5 | 6 | 7 .. 9|
+ // | CC |noreturn|produces|nocallersavedregs|regparm|
+ // |0 .. 4| 5 | 6 | 7 |8 .. 10|
//
// regparm is either 0 (no regparm attribute) or the regparm value+1.
enum { CallConvMask = 0x1F };
enum { NoReturnMask = 0x20 };
enum { ProducesResultMask = 0x40 };
- enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask),
- RegParmOffset = 7 }; // Assumed to be the last field
+ enum { NoCallerSavedRegsMask = 0x80 };
+ enum {
+ RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask |
+ NoCallerSavedRegsMask),
+ RegParmOffset = 8
+ }; // Assumed to be the last field
uint16_t Bits;
@@ -2928,13 +2973,13 @@ class FunctionType : public Type {
public:
// Constructor with no defaults. Use this when you know that you
// have all the elements (when reading an AST file for example).
- ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
- bool producesResult) {
- assert((!hasRegParm || regParm < 7) && "Invalid regparm value");
- Bits = ((unsigned) cc) |
- (noReturn ? NoReturnMask : 0) |
- (producesResult ? ProducesResultMask : 0) |
- (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0);
+ ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
+ bool producesResult, bool noCallerSavedRegs) {
+ assert((!hasRegParm || regParm < 7) && "Invalid regparm value");
+ Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) |
+ (producesResult ? ProducesResultMask : 0) |
+ (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) |
+ (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0);
}
// Constructor with all defaults. Use when for example creating a
@@ -2947,6 +2992,7 @@ class FunctionType : public Type {
bool getNoReturn() const { return Bits & NoReturnMask; }
bool getProducesResult() const { return Bits & ProducesResultMask; }
+ bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; }
bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; }
unsigned getRegParm() const {
unsigned RegParm = Bits >> RegParmOffset;
@@ -2980,6 +3026,13 @@ class FunctionType : public Type {
return ExtInfo(Bits & ~ProducesResultMask);
}
+ ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const {
+ if (noCallerSavedRegs)
+ return ExtInfo(Bits | NoCallerSavedRegsMask);
+ else
+ return ExtInfo(Bits & ~NoCallerSavedRegsMask);
+ }
+
ExtInfo withRegParm(unsigned RegParm) const {
assert(RegParm < 7 && "Invalid regparm value");
return ExtInfo((Bits & ~RegParmMask) |
@@ -3097,9 +3150,11 @@ public:
class ExtParameterInfo {
enum {
ABIMask = 0x0F,
- IsConsumed = 0x10
+ IsConsumed = 0x10,
+ HasPassObjSize = 0x20,
};
unsigned char Data;
+
public:
ExtParameterInfo() : Data(0) {}
@@ -3128,6 +3183,15 @@ public:
return copy;
}
+ bool hasPassObjectSize() const {
+ return Data & HasPassObjSize;
+ }
+ ExtParameterInfo withHasPassObjectSize() const {
+ ExtParameterInfo Copy = *this;
+ Copy.Data |= HasPassObjSize;
+ return Copy;
+ }
+
unsigned char getOpaqueValue() const { return Data; }
static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
ExtParameterInfo result;
@@ -3815,6 +3879,7 @@ public:
attr_sptr,
attr_uptr,
attr_nonnull,
+ attr_ns_returns_retained,
attr_nullable,
attr_null_unspecified,
attr_objc_kindof,
@@ -4089,43 +4154,41 @@ public:
}
};
-/// \brief Represents a C++11 auto or C++14 decltype(auto) type.
+/// \brief Common base class for placeholders for types that get replaced by
+/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced
+/// class template types, and (eventually) constrained type names from the C++
+/// Concepts TS.
///
/// These types are usually a placeholder for a deduced type. However, before
/// the initializer is attached, or (usually) if the initializer is
-/// type-dependent, there is no deduced type and an auto type is canonical. In
+/// type-dependent, there is no deduced type and the type is canonical. In
/// the latter case, it is also a dependent type.
-class AutoType : public Type, public llvm::FoldingSetNode {
- AutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent)
- : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
- /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
- /*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
- if (!DeducedType.isNull()) {
- if (DeducedType->isDependentType())
+class DeducedType : public Type {
+protected:
+ DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent,
+ bool IsInstantiationDependent, bool ContainsParameterPack)
+ : Type(TC,
+ // FIXME: Retain the sugared deduced type?
+ DeducedAsType.isNull() ? QualType(this, 0)
+ : DeducedAsType.getCanonicalType(),
+ IsDependent, IsInstantiationDependent,
+ /*VariablyModified=*/false, ContainsParameterPack) {
+ if (!DeducedAsType.isNull()) {
+ if (DeducedAsType->isDependentType())
setDependent();
- if (DeducedType->isInstantiationDependentType())
+ if (DeducedAsType->isInstantiationDependentType())
setInstantiationDependent();
- if (DeducedType->containsUnexpandedParameterPack())
+ if (DeducedAsType->containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
}
- AutoTypeBits.Keyword = (unsigned)Keyword;
}
- friend class ASTContext; // ASTContext creates these
-
public:
- bool isDecltypeAuto() const {
- return getKeyword() == AutoTypeKeyword::DecltypeAuto;
- }
- AutoTypeKeyword getKeyword() const {
- return (AutoTypeKeyword)AutoTypeBits.Keyword;
- }
-
bool isSugared() const { return !isCanonicalUnqualified(); }
QualType desugar() const { return getCanonicalTypeInternal(); }
- /// \brief Get the type deduced for this auto type, or null if it's either
- /// not been deduced or was deduced to a dependent type.
+ /// \brief Get the type deduced for this placeholder type, or null if it's
+ /// either not been deduced or was deduced to a dependent type.
QualType getDeducedType() const {
return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType();
}
@@ -4133,6 +4196,31 @@ public:
return !isCanonicalUnqualified() || isDependentType();
}
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Auto ||
+ T->getTypeClass() == DeducedTemplateSpecialization;
+ }
+};
+
+/// \brief Represents a C++11 auto or C++14 decltype(auto) type.
+class AutoType : public DeducedType, public llvm::FoldingSetNode {
+ AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
+ bool IsDeducedAsDependent)
+ : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
+ IsDeducedAsDependent, /*ContainsPack=*/false) {
+ AutoTypeBits.Keyword = (unsigned)Keyword;
+ }
+
+ friend class ASTContext; // ASTContext creates these
+
+public:
+ bool isDecltypeAuto() const {
+ return getKeyword() == AutoTypeKeyword::DecltypeAuto;
+ }
+ AutoTypeKeyword getKeyword() const {
+ return (AutoTypeKeyword)AutoTypeBits.Keyword;
+ }
+
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getDeducedType(), getKeyword(), isDependentType());
}
@@ -4149,6 +4237,43 @@ public:
}
};
+/// \brief Represents a C++17 deduced template specialization type.
+class DeducedTemplateSpecializationType : public DeducedType,
+ public llvm::FoldingSetNode {
+ /// The name of the template whose arguments will be deduced.
+ TemplateName Template;
+
+ DeducedTemplateSpecializationType(TemplateName Template,
+ QualType DeducedAsType,
+ bool IsDeducedAsDependent)
+ : DeducedType(DeducedTemplateSpecialization, DeducedAsType,
+ IsDeducedAsDependent || Template.isDependent(),
+ IsDeducedAsDependent || Template.isInstantiationDependent(),
+ Template.containsUnexpandedParameterPack()),
+ Template(Template) {}
+
+ friend class ASTContext; // ASTContext creates these
+
+public:
+ /// Retrieve the name of the template that we are deducing.
+ TemplateName getTemplateName() const { return Template;}
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getTemplateName(), getDeducedType(), isDependentType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template,
+ QualType Deduced, bool IsDependent) {
+ Template.Profile(ID);
+ ID.AddPointer(Deduced.getAsOpaquePtr());
+ ID.AddBoolean(IsDependent);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DeducedTemplateSpecialization;
+ }
+};
+
/// \brief Represents a type template specialization; the template
/// must be a class template, a type alias template, or a template
/// template parameter. A template which cannot be resolved to one of
@@ -4345,6 +4470,9 @@ public:
const TemplateSpecializationType *getInjectedTST() const {
return cast<TemplateSpecializationType>(InjectedType.getTypePtr());
}
+ TemplateName getTemplateName() const {
+ return getInjectedTST()->getTemplateName();
+ }
CXXRecordDecl *getDecl() const;
@@ -5718,10 +5846,6 @@ inline bool Type::isQueueT() const {
return isSpecificBuiltinType(BuiltinType::OCLQueue);
}
-inline bool Type::isNDRangeT() const {
- return isSpecificBuiltinType(BuiltinType::OCLNDRange);
-}
-
inline bool Type::isReserveIDT() const {
return isSpecificBuiltinType(BuiltinType::OCLReserveID);
}
@@ -5739,7 +5863,7 @@ inline bool Type::isPipeType() const {
inline bool Type::isOpenCLSpecificType() const {
return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
- isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType();
+ isQueueT() || isReserveIDT() || isPipeType();
}
inline bool Type::isTemplateTypeParmType() const {
@@ -5849,8 +5973,8 @@ inline bool Type::isBooleanType() const {
}
inline bool Type::isUndeducedType() const {
- const AutoType *AT = getContainedAutoType();
- return AT && !AT->isDeduced();
+ auto *DT = getContainedDeducedType();
+ return DT && !DT->isDeduced();
}
/// \brief Determines whether this is a type for which one can define
@@ -5932,6 +6056,38 @@ template <typename T> const T *Type::getAs() const {
return cast<T>(getUnqualifiedDesugaredType());
}
+template <typename T> const T *Type::getAsAdjusted() const {
+ static_assert(!TypeIsArrayType<T>::value, "ArrayType cannot be used with getAsAdjusted!");
+
+ // If this is directly a T type, return it.
+ if (const T *Ty = dyn_cast<T>(this))
+ return Ty;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<T>(CanonicalType))
+ return nullptr;
+
+ // Strip off type adjustments that do not modify the underlying nature of the
+ // type.
+ const Type *Ty = this;
+ while (Ty) {
+ if (const auto *A = dyn_cast<AttributedType>(Ty))
+ Ty = A->getModifiedType().getTypePtr();
+ else if (const auto *E = dyn_cast<ElaboratedType>(Ty))
+ Ty = E->desugar().getTypePtr();
+ else if (const auto *P = dyn_cast<ParenType>(Ty))
+ Ty = P->desugar().getTypePtr();
+ else if (const auto *A = dyn_cast<AdjustedType>(Ty))
+ Ty = A->desugar().getTypePtr();
+ else
+ break;
+ }
+
+ // Just because the canonical type is correct does not mean we can use cast<>,
+ // since we may not have stripped off all the sugar down to the base type.
+ return dyn_cast<T>(Ty);
+}
+
inline const ArrayType *Type::getAsArrayTypeUnsafe() const {
// If this is directly an array type, return it.
if (const ArrayType *arr = dyn_cast<ArrayType>(this))
diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h b/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h
index 5b7d9e6..ad95f6f 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h
@@ -70,6 +70,13 @@ public:
return t;
}
+ /// \brief Convert to the specified TypeLoc type, returning a null TypeLoc if
+ /// this TypeLock is not of the desired type. It will consider type
+ /// adjustments from a type that wad written as a T to another type that is
+ /// still canonically a T (ignores parens, attributes, elaborated types, etc).
+ template <typename T>
+ T getAsAdjusted() const;
+
/// The kinds of TypeLocs. Equivalent to the Type::TypeClass enum,
/// except it also defines a Qualified enum that corresponds to the
/// QualifiedLoc class.
@@ -1537,7 +1544,11 @@ class DependentSizedArrayTypeLoc :
public InheritingConcreteTypeLoc<ArrayTypeLoc,
DependentSizedArrayTypeLoc,
DependentSizedArrayType> {
-
+public:
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ ArrayTypeLoc::initializeLocal(Context, Loc);
+ setSizeExpr(getTypePtr()->getSizeExpr());
+ }
};
class VariableArrayTypeLoc :
@@ -1827,9 +1838,25 @@ public:
}
};
-class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- AutoTypeLoc,
- AutoType> {
+class DeducedTypeLoc
+ : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DeducedTypeLoc,
+ DeducedType> {};
+
+class AutoTypeLoc
+ : public InheritingConcreteTypeLoc<DeducedTypeLoc, AutoTypeLoc, AutoType> {
+};
+
+class DeducedTemplateSpecializationTypeLoc
+ : public InheritingConcreteTypeLoc<DeducedTypeLoc,
+ DeducedTemplateSpecializationTypeLoc,
+ DeducedTemplateSpecializationType> {
+public:
+ SourceLocation getTemplateNameLoc() const {
+ return getNameLoc();
+ }
+ void setTemplateNameLoc(SourceLocation Loc) {
+ setNameLoc(Loc);
+ }
};
struct ElaboratedLocInfo {
@@ -2172,6 +2199,24 @@ public:
QualType getInnerType() const { return this->getTypePtr()->getElementType(); }
};
+
+template <typename T>
+inline T TypeLoc::getAsAdjusted() const {
+ TypeLoc Cur = *this;
+ while (!T::isKind(Cur)) {
+ if (auto PTL = Cur.getAs<ParenTypeLoc>())
+ Cur = PTL.getInnerLoc();
+ else if (auto ATL = Cur.getAs<AttributedTypeLoc>())
+ Cur = ATL.getModifiedLoc();
+ else if (auto ETL = Cur.getAs<ElaboratedTypeLoc>())
+ Cur = ETL.getNamedTypeLoc();
+ else if (auto ATL = Cur.getAs<AdjustedTypeLoc>())
+ Cur = ATL.getOriginalLoc();
+ else
+ break;
+ }
+ return Cur.getAs<T>();
+}
}
#endif
diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def b/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def
index 27ab21b..9d1d09e 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def
+++ b/contrib/llvm/tools/clang/include/clang/AST/TypeNodes.def
@@ -96,7 +96,9 @@ DEPENDENT_TYPE(TemplateTypeParm, Type)
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
-TYPE(Auto, Type)
+ABSTRACT_TYPE(Deduced, Type)
+TYPE(Auto, DeducedType)
+TYPE(DeducedTemplateSpecialization, DeducedType)
DEPENDENT_TYPE(InjectedClassName, Type)
DEPENDENT_TYPE(DependentName, Type)
DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
diff --git a/contrib/llvm/tools/clang/include/clang/AST/TypeOrdering.h b/contrib/llvm/tools/clang/include/clang/AST/TypeOrdering.h
index 392e544..fa64fae 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/TypeOrdering.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/TypeOrdering.h
@@ -26,7 +26,7 @@
namespace clang {
/// \brief Function object that provides a total ordering on QualType values.
-struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
+struct QualTypeOrdering {
bool operator()(QualType T1, QualType T2) const {
return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr());
}
diff --git a/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h b/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h
index 5cbcf51..b0b71e4 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h
+++ b/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h
@@ -154,6 +154,28 @@ public:
bool isRTTIKind() const { return isRTTIKind(getKind()); }
+ GlobalDecl getGlobalDecl() const {
+ assert(isUsedFunctionPointerKind() &&
+ "GlobalDecl can be created only from virtual function");
+
+ auto *DtorDecl = dyn_cast<CXXDestructorDecl>(getFunctionDecl());
+ switch (getKind()) {
+ case CK_FunctionPointer:
+ return GlobalDecl(getFunctionDecl());
+ case CK_CompleteDtorPointer:
+ return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Complete);
+ case CK_DeletingDtorPointer:
+ return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Deleting);
+ case CK_VCallOffset:
+ case CK_VBaseOffset:
+ case CK_OffsetToTop:
+ case CK_RTTI:
+ case CK_UnusedFunctionPointer:
+ llvm_unreachable("Only function pointers kinds");
+ }
+ llvm_unreachable("Should already return");
+ }
+
private:
static bool isFunctionPointerKind(Kind ComponentKind) {
return isUsedFunctionPointerKind(ComponentKind) ||
diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h
index 6a5224f..c9b496d 100644
--- a/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -180,6 +180,16 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl>
/// matches "using Y = int", but not "typedef int X"
const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl;
+/// \brief Matches type alias template declarations.
+///
+/// typeAliasTemplateDecl() matches
+/// \code
+/// template <typename T>
+/// using Y = X<T>;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasTemplateDecl>
+ typeAliasTemplateDecl;
+
/// \brief Matches AST nodes that were expanded within the main-file.
///
/// Example matches X but not Y
@@ -1118,6 +1128,69 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
ObjCInterfaceDecl> objcInterfaceDecl;
+/// \brief Matches Objective-C protocol declarations.
+///
+/// Example matches FooDelegate
+/// \code
+/// @protocol FooDelegate
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCProtocolDecl> objcProtocolDecl;
+
+/// \brief Matches Objective-C category declarations.
+///
+/// Example matches Foo (Additions)
+/// \code
+/// @interface Foo (Additions)
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCCategoryDecl> objcCategoryDecl;
+
+/// \brief Matches Objective-C method declarations.
+///
+/// Example matches both declaration and definition of -[Foo method]
+/// \code
+/// @interface Foo
+/// - (void)method;
+/// @end
+///
+/// @implementation Foo
+/// - (void)method {}
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCMethodDecl> objcMethodDecl;
+
+/// \brief Matches Objective-C instance variable declarations.
+///
+/// Example matches _enabled
+/// \code
+/// @implementation Foo {
+/// BOOL _enabled;
+/// }
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCIvarDecl> objcIvarDecl;
+
+/// \brief Matches Objective-C property declarations.
+///
+/// Example matches enabled
+/// \code
+/// @interface Foo
+/// @property BOOL enabled;
+/// @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ ObjCPropertyDecl> objcPropertyDecl;
+
/// \brief Matches expressions that introduce cleanups to be run at the end
/// of the sub-expression's evaluation.
///
@@ -1150,6 +1223,20 @@ AST_MATCHER_P(InitListExpr, hasSyntacticForm,
InnerMatcher.matches(*SyntForm, Finder, Builder));
}
+/// \brief Matches C++ initializer list expressions.
+///
+/// Given
+/// \code
+/// std::vector<int> a({ 1, 2, 3 });
+/// std::vector<int> b = { 4, 5 };
+/// int c[] = { 6, 7 };
+/// std::pair<int, int> d = { 8, 9 };
+/// \endcode
+/// cxxStdInitializerListExpr()
+/// matches "{ 1, 2, 3 }" and "{ 4, 5 }"
+const internal::VariadicDynCastAllOfMatcher<Stmt,
+ CXXStdInitializerListExpr> cxxStdInitializerListExpr;
+
/// \brief Matches implicit initializers of init list expressions.
///
/// Given
@@ -1333,7 +1420,7 @@ const internal::VariadicDynCastAllOfMatcher<
///
/// Example: Given
/// \code
-/// struct T {void func()};
+/// struct T {void func();};
/// T f();
/// void g(T);
/// \endcode
@@ -2522,7 +2609,7 @@ AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
/// \brief Matches on the receiver of an ObjectiveC Message expression.
///
/// Example
-/// matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *")));
+/// matcher = objCMessageExpr(hasReceiverType(asString("UIWebView *")));
/// matches the [webView ...] message invocation.
/// \code
/// NSString *webViewJavaScript = ...
@@ -3719,14 +3806,30 @@ AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) {
return Node.size() == N;
}
-/// \brief Matches literals that are equal to the given value.
+/// \brief Matches literals that are equal to the given value of type ValueT.
///
-/// Example matches true (matcher = cxxBoolLiteral(equals(true)))
+/// Given
/// \code
-/// true
+/// f('\0', false, 3.14, 42);
/// \endcode
+/// characterLiteral(equals(0))
+/// matches '\0'
+/// cxxBoolLiteral(equals(false)) and cxxBoolLiteral(equals(0))
+/// match false
+/// floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2))
+/// match 3.14
+/// integerLiteral(equals(42))
+/// matches 42
+///
+/// Note that you cannot directly match a negative numeric literal because the
+/// minus sign is not part of the literal: It is a unary operator whose operand
+/// is the positive numeric literal. Instead, you must use a unaryOperator()
+/// matcher to match the minus sign:
///
-/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteral>,
+/// unaryOperator(hasOperatorName("-"),
+/// hasUnaryOperand(integerLiteral(equals(13))))
+///
+/// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>,
/// Matcher<FloatingLiteral>, Matcher<IntegerLiteral>
template <typename ValueT>
internal::PolymorphicMatcherWithParam1<internal::ValueEqualsMatcher, ValueT>
@@ -3736,6 +3839,34 @@ equals(const ValueT &Value) {
ValueT>(Value);
}
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral,
+ CXXBoolLiteralExpr,
+ IntegerLiteral),
+ bool, Value, 0) {
+ return internal::ValueEqualsMatcher<NodeType, ParamT>(Value)
+ .matchesNode(Node);
+}
+
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral,
+ CXXBoolLiteralExpr,
+ IntegerLiteral),
+ unsigned, Value, 1) {
+ return internal::ValueEqualsMatcher<NodeType, ParamT>(Value)
+ .matchesNode(Node);
+}
+
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CharacterLiteral,
+ CXXBoolLiteralExpr,
+ FloatingLiteral,
+ IntegerLiteral),
+ double, Value, 2) {
+ return internal::ValueEqualsMatcher<NodeType, ParamT>(Value)
+ .matchesNode(Node);
+}
+
/// \brief Matches the operator Name of operator expressions (binary or
/// unary).
///
@@ -5507,7 +5638,7 @@ AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
integerLiteral(equals(0), hasParent(expr(hasType(pointerType())))));
}
-/// \brief Matches declaration of the function the statemenet belongs to
+/// \brief Matches declaration of the function the statement belongs to
///
/// Given:
/// \code
diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h
index 2c76dda..908fa0d 100644
--- a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h
+++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h
@@ -76,7 +76,7 @@ public:
ET_ParserInvalidToken = 106,
ET_ParserMalformedBindExpr = 107,
ET_ParserTrailingCode = 108,
- ET_ParserUnsignedError = 109,
+ ET_ParserNumberError = 109,
ET_ParserOverloadedType = 110
};
diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h
index 76926f0..5ec4a9a 100644
--- a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h
+++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/Parser.h
@@ -19,8 +19,10 @@
/// \code
/// Grammar for the expressions supported:
/// <Expression> := <Literal> | <NamedValue> | <MatcherExpression>
-/// <Literal> := <StringLiteral> | <Unsigned>
+/// <Literal> := <StringLiteral> | <Boolean> | <Double> | <Unsigned>
/// <StringLiteral> := "quoted string"
+/// <Boolean> := true | false
+/// <Double> := [0-9]+.[0-9]* | [0-9]+.[0-9]*[eE][-+]?[0-9]+
/// <Unsigned> := [0-9]+
/// <NamedValue> := <Identifier>
/// <MatcherExpression> := <Identifier>(<ArgumentList>) |
diff --git a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h
index 2c80b51..f9efe0f 100644
--- a/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ b/contrib/llvm/tools/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -35,6 +35,8 @@ class ArgKind {
public:
enum Kind {
AK_Matcher,
+ AK_Boolean,
+ AK_Double,
AK_Unsigned,
AK_String
};
@@ -56,7 +58,7 @@ class ArgKind {
/// \param To the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion.
+ /// conversion.
bool isConvertibleTo(ArgKind To, unsigned *Specificity) const;
bool operator<(const ArgKind &Other) const {
@@ -182,7 +184,7 @@ public:
/// \param Kind the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion.
+ /// conversion.
bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind,
unsigned *Specificity) const {
if (Value)
@@ -241,6 +243,8 @@ struct VariantMatcher::TypedMatcherOps final : VariantMatcher::MatcherOps {
/// copy/assignment.
///
/// Supported types:
+/// - \c bool
+// - \c double
/// - \c unsigned
/// - \c llvm::StringRef
/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher<T>)
@@ -253,14 +257,29 @@ public:
VariantValue &operator=(const VariantValue &Other);
/// \brief Specific constructors for each supported type.
+ VariantValue(bool Boolean);
+ VariantValue(double Double);
VariantValue(unsigned Unsigned);
VariantValue(StringRef String);
VariantValue(const VariantMatcher &Matchers);
+ /// \brief Constructs an \c unsigned value (disambiguation from bool).
+ VariantValue(int Signed) : VariantValue(static_cast<unsigned>(Signed)) {}
+
/// \brief Returns true iff this is not an empty value.
explicit operator bool() const { return hasValue(); }
bool hasValue() const { return Type != VT_Nothing; }
+ /// \brief Boolean value functions.
+ bool isBoolean() const;
+ bool getBoolean() const;
+ void setBoolean(bool Boolean);
+
+ /// \brief Double value functions.
+ bool isDouble() const;
+ double getDouble() const;
+ void setDouble(double Double);
+
/// \brief Unsigned value functions.
bool isUnsigned() const;
unsigned getUnsigned() const;
@@ -281,7 +300,7 @@ public:
/// \param Kind the requested destination type.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion.
+ /// conversion.
bool isConvertibleTo(ArgKind Kind, unsigned* Specificity) const;
/// \brief Determines if the contained value can be converted to any kind
@@ -290,7 +309,7 @@ public:
/// \param Kinds the requested destination types.
///
/// \param Specificity value corresponding to the "specificity" of the
- /// convertion. It is the maximum specificity of all the possible
+ /// conversion. It is the maximum specificity of all the possible
/// conversions.
bool isConvertibleTo(ArrayRef<ArgKind> Kinds, unsigned *Specificity) const;
@@ -303,6 +322,8 @@ private:
/// \brief All supported value types.
enum ValueType {
VT_Nothing,
+ VT_Boolean,
+ VT_Double,
VT_Unsigned,
VT_String,
VT_Matcher
@@ -311,6 +332,8 @@ private:
/// \brief All supported value types.
union AllValues {
unsigned Unsigned;
+ double Double;
+ bool Boolean;
std::string *String;
VariantMatcher *Matcher;
};
diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h
index 1229f8a..38010e1 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h
+++ b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h
@@ -38,15 +38,15 @@ typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode;
class DominatorTree : public ManagedAnalysis {
virtual void anchor();
public:
- llvm::DominatorTreeBase<CFGBlock>* DT;
+ llvm::DomTreeBase<CFGBlock>* DT;
DominatorTree() {
- DT = new llvm::DominatorTreeBase<CFGBlock>(false);
+ DT = new llvm::DomTreeBase<CFGBlock>();
}
~DominatorTree() override { delete DT; }
- llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; }
+ llvm::DomTreeBase<CFGBlock>& getBase() { return *DT; }
/// \brief This method returns the root CFGBlock of the dominators tree.
///
diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h
index f6a47d6..ec7549d 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h
+++ b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h
@@ -426,6 +426,7 @@ public:
bool addImplicitDtors = false,
bool addInitializers = false,
bool addTemporaryDtors = false,
+ bool addLifetime = false,
bool synthesizeBodies = false,
bool addStaticInitBranches = false,
bool addCXXNewAllocator = true,
diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h b/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h
index d23ed77..97639bb 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h
+++ b/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h
@@ -58,6 +58,7 @@ public:
Statement,
Initializer,
NewAllocator,
+ LifetimeEnds,
// dtor kind
AutomaticObjectDtor,
DeleteDtor,
@@ -167,6 +168,28 @@ private:
}
};
+/// Represents the point where the lifetime of an automatic object ends
+class CFGLifetimeEnds : public CFGElement {
+public:
+ explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt)
+ : CFGElement(LifetimeEnds, var, stmt) {}
+
+ const VarDecl *getVarDecl() const {
+ return static_cast<VarDecl *>(Data1.getPointer());
+ }
+
+ const Stmt *getTriggerStmt() const {
+ return static_cast<Stmt *>(Data2.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+ CFGLifetimeEnds() {}
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == LifetimeEnds;
+ }
+};
+
/// CFGImplicitDtor - Represents C++ object destructor implicitly generated
/// by compiler on various occasions.
class CFGImplicitDtor : public CFGElement {
@@ -701,6 +724,10 @@ public:
Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
}
+ void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
+ Elements.push_back(CFGLifetimeEnds(VD, S), C);
+ }
+
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
Elements.push_back(CFGDeleteDtor(RD, DE), C);
}
@@ -717,6 +744,19 @@ public:
*I = CFGAutomaticObjDtor(VD, S);
return ++I;
}
+
+ // Scope leaving must be performed in reversed order. So insertion is in two
+ // steps. First we prepare space for some number of elements, then we insert
+ // the elements beginning at the last position in prepared space.
+ iterator beginLifetimeEndsInsert(iterator I, size_t Cnt,
+ BumpVectorContext &C) {
+ return iterator(
+ Elements.insert(I.base(), Cnt, CFGLifetimeEnds(nullptr, nullptr), C));
+ }
+ iterator insertLifetimeEnds(iterator I, VarDecl *VD, Stmt *S) {
+ *I = CFGLifetimeEnds(VD, S);
+ return ++I;
+ }
};
/// \brief CFGCallback defines methods that should be called when a logical
@@ -753,6 +793,7 @@ public:
bool AddEHEdges;
bool AddInitializers;
bool AddImplicitDtors;
+ bool AddLifetime;
bool AddTemporaryDtors;
bool AddStaticInitBranches;
bool AddCXXNewAllocator;
@@ -774,8 +815,10 @@ public:
BuildOptions()
: forcedBlkExprs(nullptr), Observer(nullptr),
- PruneTriviallyFalseEdges(true), AddEHEdges(false),
+ PruneTriviallyFalseEdges(true),
+ AddEHEdges(false),
AddInitializers(false), AddImplicitDtors(false),
+ AddLifetime(false),
AddTemporaryDtors(false), AddStaticInitBranches(false),
AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {}
};
diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h b/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h
index b8ae67c..a2a27a8 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h
+++ b/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h
@@ -98,7 +98,7 @@ public:
bool VisitFunctionDecl(FunctionDecl *FD) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
- if (includeInGraph(FD)) {
+ if (includeInGraph(FD) && FD->isThisDeclarationADefinition()) {
// Add all blocks declared inside this function to the graph.
addNodesForBlocks(FD);
// If this function has external linkage, anything could call it.
diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h b/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h
index 51cad7a..6339dee 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h
+++ b/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h
@@ -15,10 +15,12 @@
#ifndef LLVM_CLANG_AST_CLONEDETECTION_H
#define LLVM_CLANG_AST_CLONEDETECTION_H
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/StringMap.h"
-
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Regex.h"
#include <vector>
namespace clang {
@@ -29,7 +31,193 @@ class VarDecl;
class ASTContext;
class CompoundStmt;
-/// \brief Identifies a list of statements.
+namespace clone_detection {
+
+/// Returns a string that represents all macro expansions that expanded into the
+/// given SourceLocation.
+///
+/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations
+/// A and B are expanded from the same macros in the same order.
+std::string getMacroStack(SourceLocation Loc, ASTContext &Context);
+
+/// Collects the data of a single Stmt.
+///
+/// This class defines what a code clone is: If it collects for two statements
+/// the same data, then those two statements are considered to be clones of each
+/// other.
+///
+/// All collected data is forwarded to the given data consumer of the type T.
+/// The data consumer class needs to provide a member method with the signature:
+/// update(StringRef Str)
+template <typename T>
+class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector<T>> {
+
+ ASTContext &Context;
+ /// The data sink to which all data is forwarded.
+ T &DataConsumer;
+
+public:
+ /// Collects data of the given Stmt.
+ /// \param S The given statement.
+ /// \param Context The ASTContext of S.
+ /// \param DataConsumer The data sink to which all data is forwarded.
+ StmtDataCollector(const Stmt *S, ASTContext &Context, T &DataConsumer)
+ : Context(Context), DataConsumer(DataConsumer) {
+ this->Visit(S);
+ }
+
+ typedef unsigned DataPiece;
+
+ // Below are utility methods for appending different data to the vector.
+
+ void addData(DataPiece Integer) {
+ DataConsumer.update(
+ StringRef(reinterpret_cast<char *>(&Integer), sizeof(Integer)));
+ }
+
+ void addData(llvm::StringRef Str) { DataConsumer.update(Str); }
+
+ void addData(const QualType &QT) { addData(QT.getAsString()); }
+
+// The functions below collect the class specific data of each Stmt subclass.
+
+// Utility macro for defining a visit method for a given class. This method
+// calls back to the ConstStmtVisitor to visit all parent classes.
+#define DEF_ADD_DATA(CLASS, CODE) \
+ void Visit##CLASS(const CLASS *S) { \
+ CODE; \
+ ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
+ }
+
+ DEF_ADD_DATA(Stmt, {
+ addData(S->getStmtClass());
+ // This ensures that macro generated code isn't identical to macro-generated
+ // code.
+ addData(getMacroStack(S->getLocStart(), Context));
+ addData(getMacroStack(S->getLocEnd(), Context));
+ })
+ DEF_ADD_DATA(Expr, { addData(S->getType()); })
+
+ //--- Builtin functionality ----------------------------------------------//
+ DEF_ADD_DATA(ArrayTypeTraitExpr, { addData(S->getTrait()); })
+ DEF_ADD_DATA(ExpressionTraitExpr, { addData(S->getTrait()); })
+ DEF_ADD_DATA(PredefinedExpr, { addData(S->getIdentType()); })
+ DEF_ADD_DATA(TypeTraitExpr, {
+ addData(S->getTrait());
+ for (unsigned i = 0; i < S->getNumArgs(); ++i)
+ addData(S->getArg(i)->getType());
+ })
+
+ //--- Calls --------------------------------------------------------------//
+ DEF_ADD_DATA(CallExpr, {
+ // Function pointers don't have a callee and we just skip hashing it.
+ if (const FunctionDecl *D = S->getDirectCallee()) {
+ // If the function is a template specialization, we also need to handle
+ // the template arguments as they are not included in the qualified name.
+ if (auto Args = D->getTemplateSpecializationArgs()) {
+ std::string ArgString;
+
+ // Print all template arguments into ArgString
+ llvm::raw_string_ostream OS(ArgString);
+ for (unsigned i = 0; i < Args->size(); ++i) {
+ Args->get(i).print(Context.getLangOpts(), OS);
+ // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'.
+ OS << '\n';
+ }
+ OS.flush();
+
+ addData(ArgString);
+ }
+ addData(D->getQualifiedNameAsString());
+ }
+ })
+
+ //--- Exceptions ---------------------------------------------------------//
+ DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); })
+
+ //--- C++ OOP Stmts ------------------------------------------------------//
+ DEF_ADD_DATA(CXXDeleteExpr, {
+ addData(S->isArrayFormAsWritten());
+ addData(S->isGlobalDelete());
+ })
+
+ //--- Casts --------------------------------------------------------------//
+ DEF_ADD_DATA(ObjCBridgedCastExpr, { addData(S->getBridgeKind()); })
+
+ //--- Miscellaneous Exprs ------------------------------------------------//
+ DEF_ADD_DATA(BinaryOperator, { addData(S->getOpcode()); })
+ DEF_ADD_DATA(UnaryOperator, { addData(S->getOpcode()); })
+
+ //--- Control flow -------------------------------------------------------//
+ DEF_ADD_DATA(GotoStmt, { addData(S->getLabel()->getName()); })
+ DEF_ADD_DATA(IndirectGotoStmt, {
+ if (S->getConstantTarget())
+ addData(S->getConstantTarget()->getName());
+ })
+ DEF_ADD_DATA(LabelStmt, { addData(S->getDecl()->getName()); })
+ DEF_ADD_DATA(MSDependentExistsStmt, { addData(S->isIfExists()); })
+ DEF_ADD_DATA(AddrLabelExpr, { addData(S->getLabel()->getName()); })
+
+ //--- Objective-C --------------------------------------------------------//
+ DEF_ADD_DATA(ObjCIndirectCopyRestoreExpr, { addData(S->shouldCopy()); })
+ DEF_ADD_DATA(ObjCPropertyRefExpr, {
+ addData(S->isSuperReceiver());
+ addData(S->isImplicitProperty());
+ })
+ DEF_ADD_DATA(ObjCAtCatchStmt, { addData(S->hasEllipsis()); })
+
+ //--- Miscellaneous Stmts ------------------------------------------------//
+ DEF_ADD_DATA(CXXFoldExpr, {
+ addData(S->isRightFold());
+ addData(S->getOperator());
+ })
+ DEF_ADD_DATA(GenericSelectionExpr, {
+ for (unsigned i = 0; i < S->getNumAssocs(); ++i) {
+ addData(S->getAssocType(i));
+ }
+ })
+ DEF_ADD_DATA(LambdaExpr, {
+ for (const LambdaCapture &C : S->captures()) {
+ addData(C.isPackExpansion());
+ addData(C.getCaptureKind());
+ if (C.capturesVariable())
+ addData(C.getCapturedVar()->getType());
+ }
+ addData(S->isGenericLambda());
+ addData(S->isMutable());
+ })
+ DEF_ADD_DATA(DeclStmt, {
+ auto numDecls = std::distance(S->decl_begin(), S->decl_end());
+ addData(static_cast<DataPiece>(numDecls));
+ for (const Decl *D : S->decls()) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ addData(VD->getType());
+ }
+ }
+ })
+ DEF_ADD_DATA(AsmStmt, {
+ addData(S->isSimple());
+ addData(S->isVolatile());
+ addData(S->generateAsmString(Context));
+ for (unsigned i = 0; i < S->getNumInputs(); ++i) {
+ addData(S->getInputConstraint(i));
+ }
+ for (unsigned i = 0; i < S->getNumOutputs(); ++i) {
+ addData(S->getOutputConstraint(i));
+ }
+ for (unsigned i = 0; i < S->getNumClobbers(); ++i) {
+ addData(S->getClobber(i));
+ }
+ })
+ DEF_ADD_DATA(AttributedStmt, {
+ for (const Attr *A : S->getAttrs()) {
+ addData(std::string(A->getSpelling()));
+ }
+ })
+};
+} // namespace clone_detection
+
+/// Identifies a list of statements.
///
/// Can either identify a single arbitrary Stmt object, a continuous sequence of
/// child statements inside a CompoundStmt or no statements at all.
@@ -39,8 +227,8 @@ class StmtSequence {
/// Stmt, then S is a pointer to this Stmt.
const Stmt *S;
- /// The related ASTContext for S.
- ASTContext *Context;
+ /// The declaration that contains the statements.
+ const Decl *D;
/// If EndIndex is non-zero, then S is a CompoundStmt and this StmtSequence
/// instance is representing the CompoundStmt children inside the array
@@ -49,7 +237,7 @@ class StmtSequence {
unsigned EndIndex;
public:
- /// \brief Constructs a StmtSequence holding multiple statements.
+ /// Constructs a StmtSequence holding multiple statements.
///
/// The resulting StmtSequence identifies a continuous sequence of statements
/// in the body of the given CompoundStmt. Which statements of the body should
@@ -57,20 +245,20 @@ public:
/// that describe a non-empty sub-array in the body of the given CompoundStmt.
///
/// \param Stmt A CompoundStmt that contains all statements in its body.
- /// \param Context The ASTContext for the given CompoundStmt.
+ /// \param D The Decl containing this Stmt.
/// \param StartIndex The inclusive start index in the children array of
/// \p Stmt
/// \param EndIndex The exclusive end index in the children array of \p Stmt.
- StmtSequence(const CompoundStmt *Stmt, ASTContext &Context,
- unsigned StartIndex, unsigned EndIndex);
+ StmtSequence(const CompoundStmt *Stmt, const Decl *D, unsigned StartIndex,
+ unsigned EndIndex);
- /// \brief Constructs a StmtSequence holding a single statement.
+ /// Constructs a StmtSequence holding a single statement.
///
/// \param Stmt An arbitrary Stmt.
- /// \param Context The ASTContext for the given Stmt.
- StmtSequence(const Stmt *Stmt, ASTContext &Context);
+ /// \param D The Decl containing this Stmt.
+ StmtSequence(const Stmt *Stmt, const Decl *D);
- /// \brief Constructs an empty StmtSequence.
+ /// Constructs an empty StmtSequence.
StmtSequence();
typedef const Stmt *const *iterator;
@@ -110,9 +298,12 @@ public:
bool empty() const { return size() == 0; }
/// Returns the related ASTContext for the stored Stmts.
- ASTContext &getASTContext() const {
- assert(Context);
- return *Context;
+ ASTContext &getASTContext() const;
+
+ /// Returns the declaration that contains the stored Stmts.
+ const Decl *getContainingDecl() const {
+ assert(D);
+ return D;
}
/// Returns true if this objects holds a list of statements.
@@ -150,106 +341,235 @@ public:
bool contains(const StmtSequence &Other) const;
};
-/// \brief Searches for clones in source code.
+/// Searches for similar subtrees in the AST.
+///
+/// First, this class needs several declarations with statement bodies which
+/// can be passed via analyzeCodeBody. Afterwards all statements can be
+/// searched for clones by calling findClones with a given list of constraints
+/// that should specify the wanted properties of the clones.
///
-/// First, this class needs a translation unit which is passed via
-/// \p analyzeTranslationUnit . It will then generate and store search data
-/// for all statements inside the given translation unit.
-/// Afterwards the generated data can be used to find code clones by calling
-/// \p findClones .
+/// The result of findClones can be further constrained with the constrainClones
+/// method.
///
/// This class only searches for clones in exectuable source code
/// (e.g. function bodies). Other clones (e.g. cloned comments or declarations)
/// are not supported.
class CloneDetector {
+
public:
- typedef unsigned DataPiece;
+ /// A collection of StmtSequences that share an arbitrary property.
+ typedef llvm::SmallVector<StmtSequence, 8> CloneGroup;
- /// Holds the data about a StmtSequence that is needed during the search for
- /// code clones.
- struct CloneSignature {
- /// \brief The hash code of the StmtSequence.
- ///
- /// The initial clone groups that are formed during the search for clones
- /// consist only of Sequences that share the same hash code. This makes this
- /// value the central part of this heuristic that is needed to find clones
- /// in a performant way. For this to work, the type of this variable
- /// always needs to be small and fast to compare.
- ///
- /// Also, StmtSequences that are clones of each others have to share
- /// the same hash code. StmtSequences that are not clones of each other
- /// shouldn't share the same hash code, but if they do, it will only
- /// degrade the performance of the hash search but doesn't influence
- /// the correctness of the result.
- size_t Hash;
-
- /// \brief The complexity of the StmtSequence.
- ///
- /// This value gives an approximation on how many direct or indirect child
- /// statements are contained in the related StmtSequence. In general, the
- /// greater this value, the greater the amount of statements. However, this
- /// is only an approximation and the actual amount of statements can be
- /// higher or lower than this value. Statements that are generated by the
- /// compiler (e.g. macro expansions) for example barely influence the
- /// complexity value.
- ///
- /// The main purpose of this value is to filter clones that are too small
- /// and therefore probably not interesting enough for the user.
- unsigned Complexity;
-
- /// \brief Creates an empty CloneSignature without any data.
- CloneSignature() : Complexity(1) {}
-
- CloneSignature(llvm::hash_code Hash, unsigned Complexity)
- : Hash(Hash), Complexity(Complexity) {}
- };
+ /// Generates and stores search data for all statements in the body of
+ /// the given Decl.
+ void analyzeCodeBody(const Decl *D);
- /// Holds group of StmtSequences that are clones of each other and the
- /// complexity value (see CloneSignature::Complexity) that all stored
- /// StmtSequences have in common.
- struct CloneGroup {
- std::vector<StmtSequence> Sequences;
- CloneSignature Signature;
+ /// Constrains the given list of clone groups with the given constraint.
+ ///
+ /// The constraint is expected to have a method with the signature
+ /// `void constrain(std::vector<CloneDetector::CloneGroup> &Sequences)`
+ /// as this is the interface that the CloneDetector uses for applying the
+ /// constraint. The constraint is supposed to directly modify the passed list
+ /// so that all clones in the list fulfill the specific property this
+ /// constraint ensures.
+ template <typename T>
+ static void constrainClones(std::vector<CloneGroup> &CloneGroups, T C) {
+ C.constrain(CloneGroups);
+ }
- CloneGroup() {}
+ /// Constrains the given list of clone groups with the given list of
+ /// constraints.
+ ///
+ /// The constraints are applied in sequence in the order in which they are
+ /// passed to this function.
+ template <typename T1, typename... Ts>
+ static void constrainClones(std::vector<CloneGroup> &CloneGroups, T1 C,
+ Ts... ConstraintList) {
+ constrainClones(CloneGroups, C);
+ constrainClones(CloneGroups, ConstraintList...);
+ }
- CloneGroup(const StmtSequence &Seq, CloneSignature Signature)
- : Signature(Signature) {
- Sequences.push_back(Seq);
+ /// Searches for clones in all previously passed statements.
+ /// \param Result Output parameter to which all created clone groups are
+ /// added.
+ /// \param ConstraintList The constraints that should be applied to the
+ // result.
+ template <typename... Ts>
+ void findClones(std::vector<CloneGroup> &Result, Ts... ConstraintList) {
+ // The initial assumption is that there is only one clone group and every
+ // statement is a clone of the others. This clone group will then be
+ // split up with the help of the constraints.
+ CloneGroup AllClones;
+ AllClones.reserve(Sequences.size());
+ for (const auto &C : Sequences) {
+ AllClones.push_back(C);
}
- /// \brief Returns false if and only if this group should be skipped when
- /// searching for clones.
- bool isValid() const {
- // A clone group with only one member makes no sense, so we skip them.
- return Sequences.size() > 1;
- }
- };
+ Result.push_back(AllClones);
- /// \brief Generates and stores search data for all statements in the body of
- /// the given Decl.
- void analyzeCodeBody(const Decl *D);
+ constrainClones(Result, ConstraintList...);
+ }
+
+private:
+ CloneGroup Sequences;
+};
+
+/// This class is a utility class that contains utility functions for building
+/// custom constraints.
+class CloneConstraint {
+public:
+ /// Removes all groups by using a filter function.
+ /// \param CloneGroups The list of CloneGroups that is supposed to be
+ /// filtered.
+ /// \param Filter The filter function that should return true for all groups
+ /// that should be removed from the list.
+ static void
+ filterGroups(std::vector<CloneDetector::CloneGroup> &CloneGroups,
+ std::function<bool(const CloneDetector::CloneGroup &)> Filter) {
+ CloneGroups.erase(
+ std::remove_if(CloneGroups.begin(), CloneGroups.end(), Filter),
+ CloneGroups.end());
+ }
+
+ /// Splits the given CloneGroups until the given Compare function returns true
+ /// for all clones in a single group.
+ /// \param CloneGroups A list of CloneGroups that should be modified.
+ /// \param Compare The comparison function that all clones are supposed to
+ /// pass. Should return true if and only if two clones belong
+ /// to the same CloneGroup.
+ static void splitCloneGroups(
+ std::vector<CloneDetector::CloneGroup> &CloneGroups,
+ std::function<bool(const StmtSequence &, const StmtSequence &)> Compare);
+};
- /// \brief Stores the CloneSignature to allow future querying.
- void add(const StmtSequence &S, const CloneSignature &Signature);
+/// Searches all children of the given clones for type II clones (i.e. they are
+/// identical in every aspect beside the used variable names).
+class RecursiveCloneTypeIIConstraint {
- /// \brief Searches the provided statements for clones.
+ /// Generates and saves a hash code for the given Stmt.
+ /// \param S The given Stmt.
+ /// \param D The Decl containing S.
+ /// \param StmtsByHash Output parameter that will contain the hash codes for
+ /// each StmtSequence in the given Stmt.
+ /// \return The hash code of the given Stmt.
///
- /// \param Result Output parameter that is filled with a list of found
- /// clone groups. Each group contains multiple StmtSequences
- /// that were identified to be clones of each other.
- /// \param MinGroupComplexity Only return clones which have at least this
- /// complexity value.
- /// \param CheckPatterns Returns only clone groups in which the referenced
- /// variables follow the same pattern.
- void findClones(std::vector<CloneGroup> &Result, unsigned MinGroupComplexity,
- bool CheckPatterns = true);
-
- /// \brief Describes two clones that reference their variables in a different
- /// pattern which could indicate a programming error.
+ /// If the given Stmt is a CompoundStmt, this method will also generate
+ /// hashes for all possible StmtSequences in the children of this Stmt.
+ size_t saveHash(const Stmt *S, const Decl *D,
+ std::vector<std::pair<size_t, StmtSequence>> &StmtsByHash);
+
+public:
+ void constrain(std::vector<CloneDetector::CloneGroup> &Sequences);
+};
+
+/// Ensures that every clone has at least the given complexity.
+///
+/// Complexity is here defined as the total amount of children of a statement.
+/// This constraint assumes the first statement in the group is representative
+/// for all other statements in the group in terms of complexity.
+class MinComplexityConstraint {
+ unsigned MinComplexity;
+
+public:
+ MinComplexityConstraint(unsigned MinComplexity)
+ : MinComplexity(MinComplexity) {}
+
+ size_t calculateStmtComplexity(const StmtSequence &Seq,
+ const std::string &ParentMacroStack = "");
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(
+ CloneGroups, [this](const CloneDetector::CloneGroup &A) {
+ if (!A.empty())
+ return calculateStmtComplexity(A.front()) < MinComplexity;
+ else
+ return false;
+ });
+ }
+};
+
+/// Ensures that all clone groups contain at least the given amount of clones.
+class MinGroupSizeConstraint {
+ unsigned MinGroupSize;
+
+public:
+ MinGroupSizeConstraint(unsigned MinGroupSize = 2)
+ : MinGroupSize(MinGroupSize) {}
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(CloneGroups,
+ [this](const CloneDetector::CloneGroup &A) {
+ return A.size() < MinGroupSize;
+ });
+ }
+};
+
+/// Ensures that no clone group fully contains another clone group.
+struct OnlyLargestCloneConstraint {
+ void constrain(std::vector<CloneDetector::CloneGroup> &Result);
+};
+
+struct FilenamePatternConstraint {
+ StringRef IgnoredFilesPattern;
+ std::shared_ptr<llvm::Regex> IgnoredFilesRegex;
+
+ FilenamePatternConstraint(StringRef IgnoredFilesPattern)
+ : IgnoredFilesPattern(IgnoredFilesPattern) {
+ IgnoredFilesRegex = std::make_shared<llvm::Regex>("^(" +
+ IgnoredFilesPattern.str() + "$)");
+ }
+
+ bool isAutoGenerated(const CloneDetector::CloneGroup &Group);
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(
+ CloneGroups, [this](const CloneDetector::CloneGroup &Group) {
+ return isAutoGenerated(Group);
+ });
+ }
+};
+
+/// Analyzes the pattern of the referenced variables in a statement.
+class VariablePattern {
+
+ /// Describes an occurence of a variable reference in a statement.
+ struct VariableOccurence {
+ /// The index of the associated VarDecl in the Variables vector.
+ size_t KindID;
+ /// The statement in the code where the variable was referenced.
+ const Stmt *Mention;
+
+ VariableOccurence(size_t KindID, const Stmt *Mention)
+ : KindID(KindID), Mention(Mention) {}
+ };
+
+ /// All occurences of referenced variables in the order of appearance.
+ std::vector<VariableOccurence> Occurences;
+ /// List of referenced variables in the order of appearance.
+ /// Every item in this list is unique.
+ std::vector<const VarDecl *> Variables;
+
+ /// Adds a new variable referenced to this pattern.
+ /// \param VarDecl The declaration of the variable that is referenced.
+ /// \param Mention The SourceRange where this variable is referenced.
+ void addVariableOccurence(const VarDecl *VarDecl, const Stmt *Mention);
+
+ /// Adds each referenced variable from the given statement.
+ void addVariables(const Stmt *S);
+
+public:
+ /// Creates an VariablePattern object with information about the given
+ /// StmtSequence.
+ VariablePattern(const StmtSequence &Sequence) {
+ for (const Stmt *S : Sequence)
+ addVariables(S);
+ }
+
+ /// Describes two clones that reference their variables in a different pattern
+ /// which could indicate a programming error.
struct SuspiciousClonePair {
- /// \brief Utility class holding the relevant information about a single
- /// clone in this pair.
+ /// Utility class holding the relevant information about a single
+ /// clone in this pair.
struct SuspiciousCloneInfo {
/// The variable which referencing in this clone was against the pattern.
const VarDecl *Variable;
@@ -270,17 +590,37 @@ public:
SuspiciousCloneInfo SecondCloneInfo;
};
- /// \brief Searches the provided statements for pairs of clones that don't
- /// follow the same pattern when referencing variables.
- /// \param Result Output parameter that will contain the clone pairs.
- /// \param MinGroupComplexity Only clone pairs in which the clones have at
- /// least this complexity value.
- void findSuspiciousClones(std::vector<SuspiciousClonePair> &Result,
- unsigned MinGroupComplexity);
+ /// Counts the differences between this pattern and the given one.
+ /// \param Other The given VariablePattern to compare with.
+ /// \param FirstMismatch Output parameter that will be filled with information
+ /// about the first difference between the two patterns. This parameter
+ /// can be a nullptr, in which case it will be ignored.
+ /// \return Returns the number of differences between the pattern this object
+ /// is following and the given VariablePattern.
+ ///
+ /// For example, the following statements all have the same pattern and this
+ /// function would return zero:
+ ///
+ /// if (a < b) return a; return b;
+ /// if (x < y) return x; return y;
+ /// if (u2 < u1) return u2; return u1;
+ ///
+ /// But the following statement has a different pattern (note the changed
+ /// variables in the return statements) and would have two differences when
+ /// compared with one of the statements above.
+ ///
+ /// if (a < b) return b; return a;
+ ///
+ /// This function should only be called if the related statements of the given
+ /// pattern and the statements of this objects are clones of each other.
+ unsigned countPatternDifferences(
+ const VariablePattern &Other,
+ VariablePattern::SuspiciousClonePair *FirstMismatch = nullptr);
+};
-private:
- /// Stores all encountered StmtSequences alongside their CloneSignature.
- std::vector<std::pair<CloneSignature, StmtSequence>> Sequences;
+/// Ensures that all clones reference variables in the same pattern.
+struct MatchingVariablePatternConstraint {
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups);
};
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h b/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h
index 63df61b..95b9b9c 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/AddressSpaces.h
@@ -20,30 +20,37 @@ namespace clang {
namespace LangAS {
-/// \brief Defines the set of possible language-specific address spaces.
+/// \brief Defines the address space values used by the address space qualifier
+/// of QualType.
///
-/// This uses a high starting offset so as not to conflict with any address
-/// space used by a target.
enum ID {
- Offset = 0x7FFF00,
-
- opencl_global = Offset,
+ // The default value 0 is the value used in QualType for the the situation
+ // where there is no address space qualifier. For most languages, this also
+ // corresponds to the situation where there is no address space qualifier in
+ // the source code, except for OpenCL, where the address space value 0 in
+ // QualType represents private address space in OpenCL source code.
+ Default = 0,
+
+ // OpenCL specific address spaces.
+ opencl_global,
opencl_local,
opencl_constant,
opencl_generic,
+ // CUDA specific address spaces.
cuda_device,
cuda_constant,
cuda_shared,
- Last,
- Count = Last-Offset
+ // This denotes the count of language-specific address spaces and also
+ // the offset added to the target-specific address spaces, which are usually
+ // specified by address space attributes __attribute__(address_space(n))).
+ FirstTargetAddressSpace
};
/// The type of a lookup table which maps from language-specific address spaces
/// to target-specific ones.
-typedef unsigned Map[Count];
-
+typedef unsigned Map[FirstTargetAddressSpace];
}
}
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h b/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h
index 18a2b8a..fc861a1 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h
@@ -28,7 +28,7 @@
namespace clang {
template <size_t SizeOfStr, typename FieldType>
class StringSizerHelper {
- char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
+ static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
public:
enum { Size = SizeOfStr };
};
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Attr.td b/contrib/llvm/tools/clang/include/clang/Basic/Attr.td
index fa60d51..f13e13b 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Attr.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Attr.td
@@ -149,6 +149,9 @@ class ExprArgument<string name, bit opt = 0> : Argument<name, opt>;
class FunctionArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
opt,
fake>;
+class NamedArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
+ opt,
+ fake>;
class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
class VariadicUnsignedArgument<string name> : Argument<name, 1>;
@@ -248,6 +251,8 @@ def COnly : LangOpt<"CPlusPlus", 1>;
def CPlusPlus : LangOpt<"CPlusPlus">;
def OpenCL : LangOpt<"OpenCL">;
def RenderScript : LangOpt<"RenderScript">;
+def ObjC : LangOpt<"ObjC1">;
+def BlocksSupported : LangOpt<"Blocks">;
// Defines targets for target-specific attributes. The list of strings should
// specify architectures for which the target applies, based off the ArchType
@@ -258,6 +263,7 @@ class TargetArch<list<string> arches> {
list<string> CXXABIs;
}
def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>;
+def TargetAVR : TargetArch<["avr"]>;
def TargetMips : TargetArch<["mips", "mipsel"]>;
def TargetMSP430 : TargetArch<["msp430"]>;
def TargetX86 : TargetArch<["x86"]>;
@@ -269,6 +275,112 @@ def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
let CXXABIs = ["Microsoft"];
}
+// Attribute subject match rules that are used for #pragma clang attribute.
+//
+// A instance of AttrSubjectMatcherRule represents an individual match rule.
+// An individual match rule can correspond to a number of different attribute
+// subjects, e.g. "record" matching rule corresponds to the Record and
+// CXXRecord attribute subjects.
+//
+// Match rules are used in the subject list of the #pragma clang attribute.
+// Match rules can have sub-match rules that are instances of
+// AttrSubjectMatcherSubRule. A sub-match rule can correspond to a number
+// of different attribute subjects, and it can have a negated spelling as well.
+// For example, "variable(unless(is_parameter))" matching rule corresponds to
+// the NonParmVar attribute subject.
+class AttrSubjectMatcherSubRule<string name, list<AttrSubject> subjects,
+ bit negated = 0> {
+ string Name = name;
+ list<AttrSubject> Subjects = subjects;
+ bit Negated = negated;
+ // Lists language options, one of which is required to be true for the
+ // attribute to be applicable. If empty, the language options are taken
+ // from the parent matcher rule.
+ list<LangOpt> LangOpts = [];
+}
+class AttrSubjectMatcherRule<string name, list<AttrSubject> subjects,
+ list<AttrSubjectMatcherSubRule> subrules = []> {
+ string Name = name;
+ list<AttrSubject> Subjects = subjects;
+ list<AttrSubjectMatcherSubRule> Constraints = subrules;
+ // Lists language options, one of which is required to be true for the
+ // attribute to be applicable. If empty, no language options are required.
+ list<LangOpt> LangOpts = [];
+}
+
+// function(is_member)
+def SubRuleForCXXMethod : AttrSubjectMatcherSubRule<"is_member", [CXXMethod]> {
+ let LangOpts = [CPlusPlus];
+}
+def SubjectMatcherForFunction : AttrSubjectMatcherRule<"function", [Function], [
+ SubRuleForCXXMethod
+]>;
+// hasType is abstract, it should be used with one of the sub-rules.
+def SubjectMatcherForType : AttrSubjectMatcherRule<"hasType", [], [
+ AttrSubjectMatcherSubRule<"functionType", [FunctionLike]>
+
+ // FIXME: There's a matcher ambiguity with objc methods and blocks since
+ // functionType excludes them but functionProtoType includes them.
+ // AttrSubjectMatcherSubRule<"functionProtoType", [HasFunctionProto]>
+]>;
+def SubjectMatcherForTypedef : AttrSubjectMatcherRule<"type_alias",
+ [TypedefName]>;
+def SubjectMatcherForRecord : AttrSubjectMatcherRule<"record", [Record,
+ CXXRecord], [
+ // unless(is_union)
+ AttrSubjectMatcherSubRule<"is_union", [Struct], 1>
+]>;
+def SubjectMatcherForEnum : AttrSubjectMatcherRule<"enum", [Enum]>;
+def SubjectMatcherForEnumConstant : AttrSubjectMatcherRule<"enum_constant",
+ [EnumConstant]>;
+def SubjectMatcherForVar : AttrSubjectMatcherRule<"variable", [Var], [
+ AttrSubjectMatcherSubRule<"is_thread_local", [TLSVar]>,
+ AttrSubjectMatcherSubRule<"is_global", [GlobalVar]>,
+ AttrSubjectMatcherSubRule<"is_parameter", [ParmVar]>,
+ // unless(is_parameter)
+ AttrSubjectMatcherSubRule<"is_parameter", [NonParmVar], 1>
+]>;
+def SubjectMatcherForField : AttrSubjectMatcherRule<"field", [Field]>;
+def SubjectMatcherForNamespace : AttrSubjectMatcherRule<"namespace",
+ [Namespace]> {
+ let LangOpts = [CPlusPlus];
+}
+def SubjectMatcherForObjCInterface : AttrSubjectMatcherRule<"objc_interface",
+ [ObjCInterface]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCProtocol : AttrSubjectMatcherRule<"objc_protocol",
+ [ObjCProtocol]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCCategory : AttrSubjectMatcherRule<"objc_category",
+ [ObjCCategory]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCMethod : AttrSubjectMatcherRule<"objc_method",
+ [ObjCMethod], [
+ AttrSubjectMatcherSubRule<"is_instance", [ObjCInstanceMethod]>
+]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForObjCProperty : AttrSubjectMatcherRule<"objc_property",
+ [ObjCProperty]> {
+ let LangOpts = [ObjC];
+}
+def SubjectMatcherForBlock : AttrSubjectMatcherRule<"block", [Block]> {
+ let LangOpts = [BlocksSupported];
+}
+
+// Aggregate attribute subject match rules are abstract match rules that can't
+// be used directly in #pragma clang attribute. Instead, users have to use
+// subject match rules that correspond to attribute subjects that derive from
+// the specified subject.
+class AttrSubjectMatcherAggregateRule<AttrSubject subject> {
+ AttrSubject Subject = subject;
+}
+
+def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
+
class Attr {
// The various ways in which an attribute can be spelled in source
list<Spelling> Spellings;
@@ -301,6 +413,17 @@ class Attr {
// Set to true if this attribute can be duplicated on a subject when merging
// attributes. By default, attributes are not merged.
bit DuplicatesAllowedWhileMerging = 0;
+ // Set to true if this attribute meaningful when applied to or inherited
+ // in a class template definition.
+ bit MeaningfulToClassTemplateDefinition = 0;
+ // Set to true if this attribute can be used with '#pragma clang attribute'.
+ // By default, when this value is false, an attribute is supported by the
+ // '#pragma clang attribute' only when:
+ // - It has documentation.
+ // - It has a subject list whose subjects can be represented using subject
+ // match rules.
+ // - It has GNU/CXX11 spelling and doesn't require delayed parsing.
+ bit ForcePragmaAttributeSupport = 0;
// Lists language options, one of which is required to be true for the
// attribute to be applicable. If empty, no language options are required.
list<LangOpt> LangOpts = [];
@@ -340,7 +463,7 @@ class TargetSpecificAttr<TargetArch target> {
// should contain a shared value between the attributes.
//
// Target-specific attributes which use this feature should ensure that the
- // spellings match exactly betweeen the attributes, and if the arguments or
+ // spellings match exactly between the attributes, and if the arguments or
// subjects differ, should specify HasCustomParsing = 1 and implement their
// own parsing and semantic handling requirements as-needed.
string ParseKind;
@@ -372,6 +495,7 @@ def AbiTag : Attr {
let Args = [VariadicStringArgument<"Tags">];
let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag,
"ExpectedStructClassVariableFunctionOrInlineNamespace">;
+ let MeaningfulToClassTemplateDefinition = 1;
let Documentation = [AbiTagsDocs];
}
@@ -449,6 +573,15 @@ def XRayInstrument : InheritableAttr {
let Documentation = [XRayDocs];
}
+def XRayLogArgs : InheritableAttr {
+ let Spellings = [GNU<"xray_log_args">, CXX11<"clang", "xray_log_args">];
+ let Subjects = SubjectList<
+ [CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod"
+ >;
+ let Args = [UnsignedArgument<"ArgumentCount">];
+ let Documentation = [XRayDocs];
+}
+
def TLSModel : InheritableAttr {
let Spellings = [GCC<"tls_model">];
let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">;
@@ -464,6 +597,9 @@ def AnalyzerNoReturn : InheritableAttr {
def Annotate : InheritableParamAttr {
let Spellings = [GNU<"annotate">];
let Args = [StringArgument<"Annotation">];
+ // Ensure that the annotate attribute can be used with
+ // '#pragma clang attribute' even though it has no subject list.
+ let ForcePragmaAttributeSupport = 1;
let Documentation = [Undocumented];
}
@@ -480,6 +616,19 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
let Documentation = [ARMInterruptDocs];
}
+def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> {
+ let Spellings = [GNU<"interrupt">];
+ let Subjects = SubjectList<[Function]>;
+ let ParseKind = "Interrupt";
+ let Documentation = [AVRInterruptDocs];
+}
+
+def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
+ let Spellings = [GNU<"signal">];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [AVRSignalDocs];
+}
+
def AsmLabel : InheritableAttr {
let Spellings = [Keyword<"asm">, Keyword<"__asm__">];
let Args = [StringArgument<"Label">];
@@ -506,13 +655,48 @@ def Availability : InheritableAttr {
.Case("tvos_app_extension", "tvOS (App Extension)")
.Case("watchos_app_extension", "watchOS (App Extension)")
.Default(llvm::StringRef());
+}
+static llvm::StringRef getPlatformNameSourceSpelling(llvm::StringRef Platform) {
+ return llvm::StringSwitch<llvm::StringRef>(Platform)
+ .Case("ios", "iOS")
+ .Case("macos", "macOS")
+ .Case("tvos", "tvOS")
+ .Case("watchos", "watchOS")
+ .Case("ios_app_extension", "iOSApplicationExtension")
+ .Case("macos_app_extension", "macOSApplicationExtension")
+ .Case("tvos_app_extension", "tvOSApplicationExtension")
+ .Case("watchos_app_extension", "watchOSApplicationExtension")
+ .Default(Platform);
+}
+static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
+ return llvm::StringSwitch<llvm::StringRef>(Platform)
+ .Case("iOS", "ios")
+ .Case("macOS", "macos")
+ .Case("tvOS", "tvos")
+ .Case("watchOS", "watchos")
+ .Case("iOSApplicationExtension", "ios_app_extension")
+ .Case("macOSApplicationExtension", "macos_app_extension")
+ .Case("tvOSApplicationExtension", "tvos_app_extension")
+ .Case("watchOSApplicationExtension", "watchos_app_extension")
+ .Default(Platform);
} }];
let HasCustomParsing = 1;
let DuplicatesAllowedWhileMerging = 1;
-// let Subjects = SubjectList<[Named]>;
+ let Subjects = SubjectList<[Named]>;
let Documentation = [AvailabilityDocs];
}
+def ExternalSourceSymbol : InheritableAttr {
+ let Spellings = [GNU<"external_source_symbol">,
+ CXX11<"clang", "external_source_symbol">];
+ let Args = [StringArgument<"language", 1>,
+ StringArgument<"definedIn", 1>,
+ BoolArgument<"generatedDeclaration", 1>];
+ let HasCustomParsing = 1;
+ let Subjects = SubjectList<[Named]>;
+ let Documentation = [ExternalSourceSymbolDocs];
+}
+
def Blocks : InheritableAttr {
let Spellings = [GNU<"blocks">];
let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>];
@@ -707,6 +891,13 @@ def OpenCLUnrollHint : InheritableAttr {
let Documentation = [OpenCLUnrollHintDocs];
}
+def OpenCLIntelReqdSubGroupSize: InheritableAttr {
+ let Spellings = [GNU<"intel_reqd_sub_group_size">];
+ let Args = [UnsignedArgument<"SubGroupSize">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [OpenCLIntelReqdSubGroupSizeDocs];
+}
+
// This attribute is both a type attribute, and a declaration attribute (for
// parameter variables).
def OpenCLAccess : Attr {
@@ -771,6 +962,7 @@ def Deprecated : InheritableAttr {
// An optional string argument that enables us to provide a
// Fix-It.
StringArgument<"Replacement", 1>];
+ let MeaningfulToClassTemplateDefinition = 1;
let Documentation = [DeprecatedDocs];
}
@@ -847,7 +1039,15 @@ def FlagEnum : InheritableAttr {
let Spellings = [GNU<"flag_enum">];
let Subjects = SubjectList<[Enum]>;
let Documentation = [FlagEnumDocs];
- let LangOpts = [COnly];
+}
+
+def EnumExtensibility : InheritableAttr {
+ let Spellings = [GNU<"enum_extensibility">,
+ CXX11<"clang", "enum_extensibility">];
+ let Subjects = SubjectList<[Enum]>;
+ let Args = [EnumArgument<"Extensibility", "Kind",
+ ["closed", "open"], ["Closed", "Open"]>];
+ let Documentation = [EnumExtensibilityDocs];
}
def Flatten : InheritableAttr {
@@ -982,6 +1182,12 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> {
let Documentation = [MipsInterruptDocs];
}
+def MicroMips : InheritableAttr, TargetSpecificAttr<TargetMips> {
+ let Spellings = [GCC<"micromips">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [MicroMipsDocs];
+}
+
def Mode : Attr {
let Spellings = [GCC<"mode">];
let Subjects = SubjectList<[Var, Enum, TypedefName, Field], ErrorDiag,
@@ -1064,6 +1270,12 @@ def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
let Documentation = [Undocumented];
}
+def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips> {
+ let Spellings = [GCC<"nomicromips">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [MicroMipsDocs];
+}
+
// This is not a TargetSpecificAttr so that is silently accepted and
// ignored on other targets as encouraged by the OpenCL spec.
//
@@ -1115,7 +1327,7 @@ def NoSplitStack : InheritableAttr {
let Documentation = [NoSplitStackDocs];
}
-def NonNull : InheritableAttr {
+def NonNull : InheritableParamAttr {
let Spellings = [GCC<"nonnull">];
let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], WarnDiag,
"ExpectedFunctionMethodOrParameter">;
@@ -1178,6 +1390,14 @@ def AssumeAligned : InheritableAttr {
let Documentation = [AssumeAlignedDocs];
}
+def AllocAlign : InheritableAttr {
+ let Spellings = [GCC<"alloc_align">];
+ let Subjects = SubjectList<[HasFunctionProto], WarnDiag,
+ "ExpectedFunctionWithProtoType">;
+ let Args = [IntArgument<"ParamIndex">];
+ let Documentation = [AllocAlignDocs];
+}
+
def NoReturn : InheritableAttr {
let Spellings = [GCC<"noreturn">, Declspec<"noreturn">];
// FIXME: Does GCC allow this on the function instead?
@@ -1463,6 +1683,42 @@ def Section : InheritableAttr {
let Documentation = [SectionDocs];
}
+def PragmaClangBSSSection : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"Name">];
+ let Subjects = SubjectList<[GlobalVar], ErrorDiag,
+ "ExpectedFunctionMethodOrGlobalVar">;
+ let Documentation = [Undocumented];
+}
+
+def PragmaClangDataSection : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"Name">];
+ let Subjects = SubjectList<[GlobalVar], ErrorDiag,
+ "ExpectedFunctionMethodOrGlobalVar">;
+ let Documentation = [Undocumented];
+}
+
+def PragmaClangRodataSection : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"Name">];
+ let Subjects = SubjectList<[GlobalVar], ErrorDiag,
+ "ExpectedFunctionMethodOrGlobalVar">;
+ let Documentation = [Undocumented];
+}
+
+def PragmaClangTextSection : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"Name">];
+ let Subjects = SubjectList<[Function], ErrorDiag,
+ "ExpectedFunctionMethodOrGlobalVar">;
+ let Documentation = [Undocumented];
+}
+
def Sentinel : InheritableAttr {
let Spellings = [GCC<"sentinel">];
let Args = [DefaultIntArgument<"Sentinel", 0>,
@@ -1498,6 +1754,12 @@ def SwiftIndirectResult : ParameterABIAttr {
let Documentation = [SwiftIndirectResultDocs];
}
+def Suppress : StmtAttr {
+ let Spellings = [CXX11<"gsl", "suppress">];
+ let Args = [VariadicStringArgument<"DiagnosticIdentifiers">];
+ let Documentation = [SuppressDocs];
+}
+
def SysVABI : InheritableAttr {
let Spellings = [GCC<"sysv_abi">];
// let Subjects = [Function, ObjCMethod];
@@ -1540,11 +1802,18 @@ def Target : InheritableAttr {
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [TargetDocs];
let AdditionalMembers = [{
- typedef std::pair<std::vector<std::string>, StringRef> ParsedTargetAttr;
+ struct ParsedTargetAttr {
+ std::vector<std::string> Features;
+ StringRef Architecture;
+ bool DuplicateArchitecture = false;
+ };
ParsedTargetAttr parse() const {
+ return parse(getFeaturesStr());
+ }
+ static ParsedTargetAttr parse(StringRef Features) {
ParsedTargetAttr Ret;
SmallVector<StringRef, 1> AttrFeatures;
- getFeaturesStr().split(AttrFeatures, ",");
+ Features.split(AttrFeatures, ",");
// Grab the various features and prepend a "+" to turn on the feature to
// the backend and add them to our existing set of features.
@@ -1561,12 +1830,15 @@ def Target : InheritableAttr {
continue;
// While we're here iterating check for a different target cpu.
- if (Feature.startswith("arch="))
- Ret.second = Feature.split("=").second.trim();
- else if (Feature.startswith("no-"))
- Ret.first.push_back("-" + Feature.split("-").second.str());
+ if (Feature.startswith("arch=")) {
+ if (!Ret.Architecture.empty())
+ Ret.DuplicateArchitecture = true;
+ else
+ Ret.Architecture = Feature.split("=").second.trim();
+ } else if (Feature.startswith("no-"))
+ Ret.Features.push_back("-" + Feature.split("-").second.str());
else
- Ret.first.push_back("+" + Feature.str());
+ Ret.Features.push_back("+" + Feature.str());
}
return Ret;
}
@@ -1596,14 +1868,14 @@ def Unavailable : InheritableAttr {
def DiagnoseIf : InheritableAttr {
let Spellings = [GNU<"diagnose_if">];
- let Subjects = SubjectList<[Function]>;
+ let Subjects = SubjectList<[Function, ObjCMethod, ObjCProperty]>;
let Args = [ExprArgument<"Cond">, StringArgument<"Message">,
EnumArgument<"DiagnosticType",
"DiagnosticType",
["error", "warning"],
["DT_Error", "DT_Warning"]>,
BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
- FunctionArgument<"Parent", 0, /*fake*/ 1>];
+ NamedArgument<"Parent", 0, /*fake*/ 1>];
let DuplicatesAllowedWhileMerging = 1;
let LateParsed = 1;
let AdditionalMembers = [{
@@ -1681,6 +1953,7 @@ def Visibility : InheritableAttr {
let Args = [EnumArgument<"Visibility", "VisibilityType",
["default", "hidden", "internal", "protected"],
["Default", "Hidden", "Hidden", "Protected"]>];
+ let MeaningfulToClassTemplateDefinition = 1;
let Documentation = [Undocumented];
}
@@ -1750,6 +2023,12 @@ def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
let Documentation = [AnyX86InterruptDocs];
}
+def AnyX86NoCallerSavedRegisters : InheritableAttr,
+ TargetSpecificAttr<TargetAnyX86> {
+ let Spellings = [GCC<"no_caller_saved_registers">];
+ let Documentation = [AnyX86NoCallerSavedRegistersDocs];
+}
+
def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> {
let Spellings = [GNU<"force_align_arg_pointer">];
// Technically, this appertains to a FunctionDecl, but the target-specific
@@ -2180,9 +2459,8 @@ def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> {
let Documentation = [DLLImportDocs];
}
-def SelectAny : InheritableAttr {
- let Spellings = [Declspec<"selectany">];
- let LangOpts = [MicrosoftExt];
+def SelectAny : InheritableAttr, TargetSpecificAttr<TargetWindows> {
+ let Spellings = [Declspec<"selectany">, GCC<"selectany">];
let Documentation = [Undocumented];
}
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td b/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td
index 8f6a7ea..33ef3ea 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/AttrDocs.td
@@ -244,6 +244,36 @@ An example of how to use ``alloc_size``
}];
}
+def AllocAlignDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Use ``__attribute__((alloc_align(<alignment>))`` on a function
+declaration to specify that the return value of the function (which must be a
+pointer type) is at least as aligned as the value of the indicated parameter. The
+parameter is given by its index in the list of formal parameters; the first
+parameter has index 1 unless the function is a C++ non-static member function,
+in which case the first parameter has index 2 to account for the implicit ``this``
+parameter.
+
+.. code-block:: c++
+
+ // The returned pointer has the alignment specified by the first parameter.
+ void *a(size_t align) __attribute__((alloc_align(1)));
+
+ // The returned pointer has the alignment specified by the second parameter.
+ void *b(void *v, size_t align) __attribute__((alloc_align(2)));
+
+ // The returned pointer has the alignment specified by the second visible
+ // parameter, however it must be adjusted for the implicit 'this' parameter.
+ void *Foo::b(void *v, size_t align) __attribute__((alloc_align(3)));
+
+Note that this attribute merely informs the compiler that a function always
+returns a sufficiently aligned pointer. It does not cause the compiler to
+emit code to enforce that alignment. The behavior is undefined if the returned
+poitner is not sufficiently aligned.
+ }];
+}
+
def EnableIfDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -575,20 +605,27 @@ semantics:
for ``T`` and ``U`` to be incompatible.
The declaration of ``overloadable`` functions is restricted to function
-declarations and definitions. Most importantly, if any function with a given
-name is given the ``overloadable`` attribute, then all function declarations
-and definitions with that name (and in that scope) must have the
-``overloadable`` attribute. This rule even applies to redeclarations of
-functions whose original declaration had the ``overloadable`` attribute, e.g.,
+declarations and definitions. If a function is marked with the ``overloadable``
+attribute, then all declarations and definitions of functions with that name,
+except for at most one (see the note below about unmarked overloads), must have
+the ``overloadable`` attribute. In addition, redeclarations of a function with
+the ``overloadable`` attribute must have the ``overloadable`` attribute, and
+redeclarations of a function without the ``overloadable`` attribute must *not*
+have the ``overloadable`` attribute. e.g.,
.. code-block:: c
int f(int) __attribute__((overloadable));
float f(float); // error: declaration of "f" must have the "overloadable" attribute
+ int f(int); // error: redeclaration of "f" must have the "overloadable" attribute
int g(int) __attribute__((overloadable));
int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute
+ int h(int);
+ int h(int) __attribute__((overloadable)); // error: declaration of "h" must not
+ // have the "overloadable" attribute
+
Functions marked ``overloadable`` must have prototypes. Therefore, the
following code is ill-formed:
@@ -621,7 +658,28 @@ caveats to this use of name mangling:
linkage specification, it's name *will* be mangled in the same way as it
would in C.
-Query for this feature with ``__has_extension(attribute_overloadable)``.
+For the purpose of backwards compatibility, at most one function with the same
+name as other ``overloadable`` functions may omit the ``overloadable``
+attribute. In this case, the function without the ``overloadable`` attribute
+will not have its name mangled.
+
+For example:
+
+.. code-block:: c
+
+ // Notes with mangled names assume Itanium mangling.
+ int f(int);
+ int f(double) __attribute__((overloadable));
+ void foo() {
+ f(5); // Emits a call to f (not _Z1fi, as it would with an overload that
+ // was marked with overloadable).
+ f(1.0); // Emits a call to _Z1fd.
+ }
+
+Support for unmarked overloads is not present in some versions of clang. You may
+query for it using ``__has_extension(overloadable_unmarked)``.
+
+Query for this attribute with ``__has_attribute(overloadable)``.
}];
}
@@ -852,13 +910,13 @@ the function declaration for a hypothetical function ``f``:
void f(void) __attribute__((availability(macos,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
-The availability attribute states that ``f`` was introduced in Mac OS X 10.4,
-deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information
+The availability attribute states that ``f`` was introduced in macOS 10.4,
+deprecated in macOS 10.6, and obsoleted in macOS 10.7. This information
is used by Clang to determine when it is safe to use ``f``: for example, if
-Clang is instructed to compile code for Mac OS X 10.5, a call to ``f()``
-succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call
+Clang is instructed to compile code for macOS 10.5, a call to ``f()``
+succeeds. If Clang is instructed to compile code for macOS 10.6, the call
succeeds but Clang emits a warning specifying that the function is deprecated.
-Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call
+Finally, if Clang is instructed to compile code for macOS 10.7, the call
fails because ``f()`` is no longer available.
The availability attribute is a comma-separated list starting with the
@@ -903,7 +961,7 @@ are:
command-line arguments.
``macos``
- Apple's Mac OS X operating system. The minimum deployment target is
+ Apple's macOS operating system. The minimum deployment target is
specified by the ``-mmacosx-version-min=*version*`` command-line argument.
``macosx`` is supported for backward-compatibility reasons, but it is
deprecated.
@@ -957,9 +1015,79 @@ When one method overrides another, the overriding method can be more widely avai
- (id)method __attribute__((availability(macos,introduced=10.3))); // okay: method moved into base class later
- (id)method __attribute__((availability(macos,introduced=10.5))); // error: this method was available via the base class in 10.4
@end
+
+Starting with the macOS 10.12 SDK, the ``API_AVAILABLE`` macro from
+``<os/availability.h>`` can simplify the spelling:
+
+.. code-block:: objc
+
+ @interface A
+ - (id)method API_AVAILABLE(macos(10.11)));
+ - (id)otherMethod API_AVAILABLE(macos(10.11), ios(11.0));
+ @end
+
+Also see the documentation for `@available
+<http://clang.llvm.org/docs/LanguageExtensions.html#objective-c-available>`_
}];
}
+def ExternalSourceSymbolDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``external_source_symbol`` attribute specifies that a declaration originates
+from an external source and describes the nature of that source.
+
+The fact that Clang is capable of recognizing declarations that were defined
+externally can be used to provide better tooling support for mixed-language
+projects or projects that rely on auto-generated code. For instance, an IDE that
+uses Clang and that supports mixed-language projects can use this attribute to
+provide a correct 'jump-to-definition' feature. For a concrete example,
+consider a protocol that's defined in a Swift file:
+
+.. code-block:: swift
+
+ @objc public protocol SwiftProtocol {
+ func method()
+ }
+
+This protocol can be used from Objective-C code by including a header file that
+was generated by the Swift compiler. The declarations in that header can use
+the ``external_source_symbol`` attribute to make Clang aware of the fact
+that ``SwiftProtocol`` actually originates from a Swift module:
+
+.. code-block:: objc
+
+ __attribute__((external_source_symbol(language="Swift",defined_in="module")))
+ @protocol SwiftProtocol
+ @required
+ - (void) method;
+ @end
+
+Consequently, when 'jump-to-definition' is performed at a location that
+references ``SwiftProtocol``, the IDE can jump to the original definition in
+the Swift source file rather than jumping to the Objective-C declaration in the
+auto-generated header file.
+
+The ``external_source_symbol`` attribute is a comma-separated list that includes
+clauses that describe the origin and the nature of the particular declaration.
+Those clauses can be:
+
+language=\ *string-literal*
+ The name of the source language in which this declaration was defined.
+
+defined_in=\ *string-literal*
+ The name of the source container in which the declaration was defined. The
+ exact definition of source container is language-specific, e.g. Swift's
+ source containers are modules, so ``defined_in`` should specify the Swift
+ module name.
+
+generated_declaration
+ This declaration was automatically generated by some tool.
+
+The clauses can be specified in any order. The clauses that are listed above are
+all optional, but the attribute has to have at least one clause.
+ }];
+}
def RequireConstantInitDocs : Documentation {
let Category = DocCatVariable;
@@ -1182,6 +1310,46 @@ The semantics are as follows:
}];
}
+def MicroMipsDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Clang supports the GNU style ``__attribute__((micromips))`` and
+``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes
+may be attached to a function definition and instructs the backend to generate
+or not to generate microMIPS code for that function.
+
+These attributes override the `-mmicromips` and `-mno-micromips` options
+on the command line.
+ }];
+}
+
+def AVRInterruptDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Clang supports the GNU style ``__attribute__((interrupt))`` attribute on
+AVR targets. This attribute may be attached to a function definition and instructs
+the backend to generate appropriate function entry/exit code so that it can be used
+directly as an interrupt service routine.
+
+On the AVR, the hardware globally disables interrupts when an interrupt is executed.
+The first instruction of an interrupt handler declared with this attribute is a SEI
+instruction to re-enable interrupts. See also the signal attribute that
+does not insert a SEI instruction.
+ }];
+}
+
+def AVRSignalDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Clang supports the GNU style ``__attribute__((signal))`` attribute on
+AVR targets. This attribute may be attached to a function definition and instructs
+the backend to generate appropriate function entry/exit code so that it can be used
+directly as an interrupt service routine.
+
+Interrupt handler functions defined with the signal attribute do not re-enable interrupts.
+}];
+}
+
def TargetDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -1879,6 +2047,55 @@ manipulating bits of the enumerator when issuing warnings.
}];
}
+def EnumExtensibilityDocs : Documentation {
+ let Category = DocCatType;
+ let Content = [{
+Attribute ``enum_extensibility`` is used to distinguish between enum definitions
+that are extensible and those that are not. The attribute can take either
+``closed`` or ``open`` as an argument. ``closed`` indicates a variable of the
+enum type takes a value that corresponds to one of the enumerators listed in the
+enum definition or, when the enum is annotated with ``flag_enum``, a value that
+can be constructed using values corresponding to the enumerators. ``open``
+indicates a variable of the enum type can take any values allowed by the
+standard and instructs clang to be more lenient when issuing warnings.
+
+.. code-block:: c
+
+ enum __attribute__((enum_extensibility(closed))) ClosedEnum {
+ A0, A1
+ };
+
+ enum __attribute__((enum_extensibility(open))) OpenEnum {
+ B0, B1
+ };
+
+ enum __attribute__((enum_extensibility(closed),flag_enum)) ClosedFlagEnum {
+ C0 = 1 << 0, C1 = 1 << 1
+ };
+
+ enum __attribute__((enum_extensibility(open),flag_enum)) OpenFlagEnum {
+ D0 = 1 << 0, D1 = 1 << 1
+ };
+
+ void foo1() {
+ enum ClosedEnum ce;
+ enum OpenEnum oe;
+ enum ClosedFlagEnum cfe;
+ enum OpenFlagEnum ofe;
+
+ ce = A1; // no warnings
+ ce = 100; // warning issued
+ oe = B1; // no warnings
+ oe = 100; // no warnings
+ cfe = C0 | C1; // no warnings
+ cfe = C0 | C1 | 4; // warning issued
+ ofe = D0 | D1; // no warnings
+ ofe = D0 | D1 | 4; // no warnings
+ }
+
+ }];
+}
+
def EmptyBasesDocs : Documentation {
let Category = DocCatType;
let Content = [{
@@ -2053,6 +2270,21 @@ s6.11.5 for details.
}];
}
+def OpenCLIntelReqdSubGroupSizeDocs : Documentation {
+ let Category = DocCatStmt;
+ let Heading = "__attribute__((intel_reqd_sub_group_size))";
+ let Content = [{
+The optional attribute intel_reqd_sub_group_size can be used to indicate that
+the kernel must be compiled and executed with the specified subgroup size. When
+this attribute is present, get_max_sub_group_size() is guaranteed to return the
+specified integer value. This is important for the correctness of many subgroup
+algorithms, and in some cases may be used by the compiler to generate more optimal
+code. See `cl_intel_required_subgroup_size
+<https://www.khronos.org/registry/OpenCL/extensions/intel/cl_intel_required_subgroup_size.txt>`
+for details.
+ }];
+}
+
def OpenCLAccessDocs : Documentation {
let Category = DocCatStmt;
let Heading = "__read_only, __write_only, __read_write (read_only, write_only, read_write)";
@@ -2494,6 +2726,40 @@ hardware design, touch the red zone.
}];
}
+def AnyX86NoCallerSavedRegistersDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+Use this attribute to indicate that the specified function has no
+caller-saved registers. That is, all registers are callee-saved except for
+registers used for passing parameters to the function or returning parameters
+from the function.
+The compiler saves and restores any modified registers that were not used for
+passing or returning arguments to the function.
+
+The user can call functions specified with the 'no_caller_saved_registers'
+attribute from an interrupt handler without saving and restoring all
+call-clobbered registers.
+
+Note that 'no_caller_saved_registers' attribute is not a calling convention.
+In fact, it only overrides the decision of which registers should be saved by
+the caller, but not how the parameters are passed from the caller to the callee.
+
+For example:
+
+ .. code-block:: c
+
+ __attribute__ ((no_caller_saved_registers, fastcall))
+ void f (int arg1, int arg2) {
+ ...
+ }
+
+ In this case parameters 'arg1' and 'arg2' will be passed in registers.
+ In this case, on 32-bit x86 targets, the function 'f' will use ECX and EDX as
+ register parameters. However, it will not assume any scratch registers and
+ should save and restore any modified registers except for ECX and EDX.
+ }];
+}
+
def SwiftCallDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
@@ -2638,6 +2904,32 @@ optimizations like C++'s named return value optimization (NRVO).
}];
}
+def SuppressDocs : Documentation {
+ let Category = DocCatStmt;
+ let Content = [{
+The ``[[gsl::suppress]]`` attribute suppresses specific
+clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable
+way. The attribute can be attached to declarations, statements, and at
+namespace scope.
+
+.. code-block:: c++
+
+ [[gsl::suppress("Rh-public")]]
+ void f_() {
+ int *p;
+ [[gsl::suppress("type")]] {
+ p = reinterpret_cast<int*>(7);
+ }
+ }
+ namespace N {
+ [[clang::suppress("type", "bounds")]];
+ ...
+ }
+
+.. _`C++ Core Guidelines`: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#inforce-enforcement
+ }];
+}
+
def AbiTagsDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -2777,13 +3069,15 @@ See the RenderScript_ documentation for more information.
def XRayDocs : Documentation {
let Category = DocCatFunction;
- let Heading = "xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument)";
+ let Heading = "xray_always_instrument (clang::xray_always_instrument), xray_never_instrument (clang::xray_never_instrument), xray_log_args (clang::xray_log_args)";
let Content = [{
``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching.
Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points.
If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise.
+
+``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported.
}];
}
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/AttrSubjectMatchRules.h b/contrib/llvm/tools/clang/include/clang/Basic/AttrSubjectMatchRules.h
new file mode 100644
index 0000000..4c88adf
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Basic/AttrSubjectMatchRules.h
@@ -0,0 +1,32 @@
+//===-- AttrSubjectMatchRules.h - Attribute subject match rules -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H
+#define LLVM_CLANG_BASIC_ATTR_SUBJECT_MATCH_RULES_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+namespace attr {
+
+/// \brief A list of all the recognized kinds of attributes.
+enum SubjectMatchRule {
+#define ATTR_MATCH_RULE(X, Spelling, IsAbstract) X,
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+};
+
+const char *getSubjectMatchRuleSpelling(SubjectMatchRule Rule);
+
+using ParsedSubjectMatchRuleSet = llvm::DenseMap<int, SourceRange>;
+
+} // end namespace attr
+} // end namespace clang
+
+#endif
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def
index 326a8fa..1ddb9be 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def
@@ -52,6 +52,7 @@
// LL -> long long
// LLL -> __int128_t (e.g. LLLi)
// W -> int64_t
+// N -> 'int' size if target is LP64, 'L' otherwise.
// S -> signed
// U -> unsigned
// I -> Required to constant fold to an integer constant expression.
@@ -718,11 +719,11 @@ BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
LIBBUILTIN(_byteswap_ushort, "UsUs", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
-LIBBUILTIN(_byteswap_ulong, "ULiULi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
+LIBBUILTIN(_byteswap_ulong, "UNiUNi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
LIBBUILTIN(_byteswap_uint64, "ULLiULLi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(__exception_code, "UNi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_exception_code, "UNi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
@@ -730,49 +731,50 @@ LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedAnd8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedAnd16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedAnd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedAnd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchange8, "ccD*cc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchange16, "ssD*ss", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedCompareExchange, "NiNiD*NiNi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchange64, "LLiLLiD*LLiLLi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedDecrement16, "ssD*", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedDecrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedExchange, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchange8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchange16, "ssD*s", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangeAdd8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangeAdd16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedExchangeAdd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangeSub8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedExchangeSub16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedExchangeSub, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedExchangeSub, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedIncrement16, "ssD*", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedIncrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedOr8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedOr16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedOr, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedOr, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedXor8, "ccD*c", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_InterlockedXor16, "ssD*s", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_InterlockedXor, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_InterlockedXor, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_interlockedbittestandset, "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES)
LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES)
LANGBUILTIN(__popcnt64, "ULLiULLi", "nc", ALL_MS_LANGUAGES)
-LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl8, "UcUcUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl16, "UsUsUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl, "UiUii", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_lrotl, "ULiULii", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_lrotl, "UNiUNii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotl64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr8, "UcUcUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr16, "UsUsUc", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr, "UiUii", "n", ALL_MS_LANGUAGES)
-LANGBUILTIN(_lrotr, "ULiULii", "n", ALL_MS_LANGUAGES)
+LANGBUILTIN(_lrotr, "UNiUNii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(_rotr64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
+LANGBUILTIN(__fastfail, "vUi", "nr", ALL_MS_LANGUAGES)
// Microsoft library builtins.
LIBBUILTIN(_setjmpex, "iJ", "fj", "setjmpex.h", ALL_MS_LANGUAGES)
@@ -1086,9 +1088,11 @@ LIBBUILTIN(ilogb, "id", "fne", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ilogbf, "if", "fne", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ilogbl, "iLd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(lgamma, "dd", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(lgammaf, "ff", "fne", "math.h", ALL_LANGUAGES)
-LIBBUILTIN(lgammal, "LdLd", "fne", "math.h", ALL_LANGUAGES)
+// POSIX math.h declares a global, signgam, that lgamma writes to, so these
+// shouldn't have "e" or "c" attributes
+LIBBUILTIN(lgamma, "dd", "fn", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lgammaf, "ff", "fn", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(lgammal, "LdLd", "fn", "math.h", ALL_LANGUAGES)
LIBBUILTIN(llrint, "LLid", "fne", "math.h", ALL_LANGUAGES)
LIBBUILTIN(llrintf, "LLif", "fne", "math.h", ALL_LANGUAGES)
@@ -1362,7 +1366,7 @@ BUILTIN(__builtin_coro_free, "v*v*", "n")
BUILTIN(__builtin_coro_id, "v*Iiv*v*v*", "n")
BUILTIN(__builtin_coro_alloc, "b", "n")
BUILTIN(__builtin_coro_begin, "v*v*", "n")
-BUILTIN(__builtin_coro_end, "vv*Ib", "n")
+BUILTIN(__builtin_coro_end, "bv*Ib", "n")
BUILTIN(__builtin_coro_suspend, "cIb", "n")
BUILTIN(__builtin_coro_param, "bv*v*", "n")
// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
@@ -1406,6 +1410,14 @@ LANGBUILTIN(to_private, "v*v*", "tn", OCLC20_LANG)
BUILTIN(__builtin_os_log_format_buffer_size, "zcC*.", "p:0:nut")
BUILTIN(__builtin_os_log_format, "v*v*cC*.", "p:0:nt")
+// Builtins for XRay
+BUILTIN(__xray_customevent, "vcC*z", "")
+
+// Win64-compatible va_list functions
+BUILTIN(__builtin_ms_va_start, "vc*&.", "nt")
+BUILTIN(__builtin_ms_va_end, "vc*&", "n")
+BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n")
+
#undef BUILTIN
#undef LIBBUILTIN
#undef LANGBUILTIN
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def
index f0f63fa..6542aca 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsAMDGPU.def
@@ -35,8 +35,15 @@ BUILTIN(__builtin_amdgcn_workitem_id_z, "Ui", "nc")
//===----------------------------------------------------------------------===//
// Instruction builtins.
//===----------------------------------------------------------------------===//
+BUILTIN(__builtin_amdgcn_s_getreg, "UiIi", "n")
+BUILTIN(__builtin_amdgcn_s_getpc, "LUi", "n")
+BUILTIN(__builtin_amdgcn_s_waitcnt, "vIi", "n")
+BUILTIN(__builtin_amdgcn_s_sendmsg, "vIiUi", "n")
+BUILTIN(__builtin_amdgcn_s_sendmsghalt, "vIiUi", "n")
BUILTIN(__builtin_amdgcn_s_barrier, "v", "n")
BUILTIN(__builtin_amdgcn_wave_barrier, "v", "n")
+BUILTIN(__builtin_amdgcn_s_dcache_inv, "v", "n")
+BUILTIN(__builtin_amdgcn_buffer_wbinvl1, "v", "n")
BUILTIN(__builtin_amdgcn_div_scale, "dddbb*", "n")
BUILTIN(__builtin_amdgcn_div_scalef, "fffbb*", "n")
BUILTIN(__builtin_amdgcn_div_fmas, "ddddb", "nc")
@@ -80,6 +87,11 @@ BUILTIN(__builtin_amdgcn_sicmpl, "LUiLiLiIi", "nc")
BUILTIN(__builtin_amdgcn_fcmp, "LUiddIi", "nc")
BUILTIN(__builtin_amdgcn_fcmpf, "LUiffIi", "nc")
BUILTIN(__builtin_amdgcn_ds_swizzle, "iiIi", "nc")
+BUILTIN(__builtin_amdgcn_ds_permute, "iii", "nc")
+BUILTIN(__builtin_amdgcn_ds_bpermute, "iii", "nc")
+BUILTIN(__builtin_amdgcn_readfirstlane, "ii", "nc")
+BUILTIN(__builtin_amdgcn_readlane, "iii", "nc")
+BUILTIN(__builtin_amdgcn_fmed3f, "ffff", "nc")
//===----------------------------------------------------------------------===//
// VI+ only builtins.
@@ -96,6 +108,13 @@ TARGET_BUILTIN(__builtin_amdgcn_frexp_exph, "sh", "nc", "16-bit-insts")
TARGET_BUILTIN(__builtin_amdgcn_fracth, "hh", "nc", "16-bit-insts")
TARGET_BUILTIN(__builtin_amdgcn_classh, "bhi", "nc", "16-bit-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_memrealtime, "LUi", "n", "s-memrealtime")
+TARGET_BUILTIN(__builtin_amdgcn_mov_dpp, "iiIiIiIiIb", "nc", "dpp")
+
+//===----------------------------------------------------------------------===//
+// GFX9+ only builtins.
+//===----------------------------------------------------------------------===//
+
+TARGET_BUILTIN(__builtin_amdgcn_fmed3h, "hhhh", "nc", "gfx9-insts")
//===----------------------------------------------------------------------===//
// Special builtins.
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def
index 6cc7308..4e277f8 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def
@@ -25,11 +25,93 @@
// In libgcc
BUILTIN(__clear_cache, "vv*v*", "i")
+// 16-bit multiplications
+BUILTIN(__builtin_arm_smulbb, "iii", "nc")
+BUILTIN(__builtin_arm_smulbt, "iii", "nc")
+BUILTIN(__builtin_arm_smultb, "iii", "nc")
+BUILTIN(__builtin_arm_smultt, "iii", "nc")
+BUILTIN(__builtin_arm_smulwb, "iii", "nc")
+BUILTIN(__builtin_arm_smulwt, "iii", "nc")
+
// Saturating arithmetic
BUILTIN(__builtin_arm_qadd, "iii", "nc")
BUILTIN(__builtin_arm_qsub, "iii", "nc")
BUILTIN(__builtin_arm_ssat, "iiUi", "nc")
-BUILTIN(__builtin_arm_usat, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usat, "UiiUi", "nc")
+
+BUILTIN(__builtin_arm_smlabb, "iiii", "nc")
+BUILTIN(__builtin_arm_smlabt, "iiii", "nc")
+BUILTIN(__builtin_arm_smlatb, "iiii", "nc")
+BUILTIN(__builtin_arm_smlatt, "iiii", "nc")
+BUILTIN(__builtin_arm_smlawb, "iiii", "nc")
+BUILTIN(__builtin_arm_smlawt, "iiii", "nc")
+
+BUILTIN(__builtin_arm_ssat16, "iii", "nc")
+BUILTIN(__builtin_arm_usat16, "iii", "nc")
+
+BUILTIN(__builtin_arm_sxtab16, "iii", "nc")
+BUILTIN(__builtin_arm_sxtb16, "ii", "nc")
+BUILTIN(__builtin_arm_uxtab16, "iii", "nc")
+BUILTIN(__builtin_arm_uxtb16, "ii", "nc")
+
+BUILTIN(__builtin_arm_sel, "iii", "nc")
+
+BUILTIN(__builtin_arm_qadd8, "iii", "nc")
+BUILTIN(__builtin_arm_qsub8, "iii", "nc")
+BUILTIN(__builtin_arm_sadd8, "iii", "nc")
+BUILTIN(__builtin_arm_shadd8, "iii", "nc")
+BUILTIN(__builtin_arm_shsub8, "iii", "nc")
+BUILTIN(__builtin_arm_ssub8, "iii", "nc")
+BUILTIN(__builtin_arm_uadd8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhadd8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhsub8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqadd8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqsub8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usub8, "UiUiUi", "nc")
+
+// Sum of 8-bit absolute differences
+BUILTIN(__builtin_arm_usad8, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usada8, "UiUiUiUi", "nc")
+
+// Parallel 16-bit addition and subtraction
+BUILTIN(__builtin_arm_qadd16, "iii", "nc")
+BUILTIN(__builtin_arm_qasx, "iii", "nc")
+BUILTIN(__builtin_arm_qsax, "iii", "nc")
+BUILTIN(__builtin_arm_qsub16, "iii", "nc")
+BUILTIN(__builtin_arm_sadd16, "iii", "nc")
+BUILTIN(__builtin_arm_sasx, "iii", "nc")
+BUILTIN(__builtin_arm_shadd16, "iii", "nc")
+BUILTIN(__builtin_arm_shasx, "iii", "nc")
+BUILTIN(__builtin_arm_shsax, "iii", "nc")
+BUILTIN(__builtin_arm_shsub16, "iii", "nc")
+BUILTIN(__builtin_arm_ssax, "iii", "nc")
+BUILTIN(__builtin_arm_ssub16, "iii", "nc")
+BUILTIN(__builtin_arm_uadd16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uasx, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhadd16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhasx, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhsax, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uhsub16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqadd16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqasx, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqsax, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_uqsub16, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usax, "UiUiUi", "nc")
+BUILTIN(__builtin_arm_usub16, "UiUiUi", "nc")
+
+// Parallel 16-bit multiplication
+BUILTIN(__builtin_arm_smlad, "iiii", "nc")
+BUILTIN(__builtin_arm_smladx, "iiii", "nc")
+BUILTIN(__builtin_arm_smlald, "LLiiiLLi", "nc")
+BUILTIN(__builtin_arm_smlaldx, "LLiiiLLi", "nc")
+BUILTIN(__builtin_arm_smlsd, "iiii", "nc")
+BUILTIN(__builtin_arm_smlsdx, "iiii", "nc")
+BUILTIN(__builtin_arm_smlsld, "LLiiiLLi", "nc")
+BUILTIN(__builtin_arm_smlsldx, "LLiiiLLi", "nc")
+BUILTIN(__builtin_arm_smuad, "iii", "nc")
+BUILTIN(__builtin_arm_smuadx, "iii", "nc")
+BUILTIN(__builtin_arm_smusd, "iii", "nc")
+BUILTIN(__builtin_arm_smusdx, "iii", "nc")
// Bit manipulation
BUILTIN(__builtin_arm_rbit, "UiUi", "nc")
@@ -133,10 +215,10 @@ LANGBUILTIN(_MoveFromCoprocessor2, "UiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
LANGBUILTIN(_MoveToCoprocessor, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
LANGBUILTIN(_MoveToCoprocessor2, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
-TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def
index 85936cb..14fc4ad 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def
@@ -882,6 +882,12 @@ BUILTIN(__builtin_HEXAGON_S2_ct0p,"iLLi","")
BUILTIN(__builtin_HEXAGON_S2_ct1p,"iLLi","")
BUILTIN(__builtin_HEXAGON_S2_interleave,"LLiLLi","")
BUILTIN(__builtin_HEXAGON_S2_deinterleave,"LLiLLi","")
+BUILTIN(__builtin_HEXAGON_Y2_dccleana,"vv*","")
+BUILTIN(__builtin_HEXAGON_Y2_dccleaninva,"vv*","")
+BUILTIN(__builtin_HEXAGON_Y2_dcinva,"vv*","")
+BUILTIN(__builtin_HEXAGON_Y2_dczeroa,"vv*","")
+BUILTIN(__builtin_HEXAGON_Y4_l2fetch,"vv*Ui","")
+BUILTIN(__builtin_HEXAGON_Y5_l2fetch,"vv*LLUi","")
BUILTIN(__builtin_HEXAGON_S6_rol_i_r,"iii","v:60:")
BUILTIN(__builtin_HEXAGON_S6_rol_i_p,"LLiLLii","v:60:")
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def
index b6329fb..afea6cb 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNVPTX.def
@@ -64,24 +64,10 @@ BUILTIN(__nvvm_read_ptx_sreg_pm3, "i", "n")
// MISC
-BUILTIN(__nvvm_clz_i, "ii", "")
-BUILTIN(__nvvm_clz_ll, "iLLi", "")
-BUILTIN(__nvvm_popc_i, "ii", "")
-BUILTIN(__nvvm_popc_ll, "iLLi", "")
BUILTIN(__nvvm_prmt, "UiUiUiUi", "")
// Min Max
-BUILTIN(__nvvm_min_i, "iii", "")
-BUILTIN(__nvvm_min_ui, "UiUiUi", "")
-BUILTIN(__nvvm_min_ll, "LLiLLiLLi", "")
-BUILTIN(__nvvm_min_ull, "ULLiULLiULLi", "")
-
-BUILTIN(__nvvm_max_i, "iii", "")
-BUILTIN(__nvvm_max_ui, "UiUiUi", "")
-BUILTIN(__nvvm_max_ll, "LLiLLiLLi", "")
-BUILTIN(__nvvm_max_ull, "ULLiULLiULLi", "")
-
BUILTIN(__nvvm_fmax_ftz_f, "fff", "")
BUILTIN(__nvvm_fmax_f, "fff", "")
BUILTIN(__nvvm_fmin_ftz_f, "fff", "")
@@ -133,11 +119,6 @@ BUILTIN(__nvvm_div_rz_d, "ddd", "")
BUILTIN(__nvvm_div_rm_d, "ddd", "")
BUILTIN(__nvvm_div_rp_d, "ddd", "")
-// Brev
-
-BUILTIN(__nvvm_brev32, "UiUi", "")
-BUILTIN(__nvvm_brev64, "ULLiULLi", "")
-
// Sad
BUILTIN(__nvvm_sad_i, "iiii", "")
@@ -155,9 +136,6 @@ BUILTIN(__nvvm_ceil_d, "dd", "")
// Abs
-BUILTIN(__nvvm_abs_i, "ii", "")
-BUILTIN(__nvvm_abs_ll, "LLiLLi", "")
-
BUILTIN(__nvvm_fabs_ftz_f, "ff", "")
BUILTIN(__nvvm_fabs_f, "ff", "")
BUILTIN(__nvvm_fabs_d, "dd", "")
@@ -385,8 +363,6 @@ BUILTIN(__nvvm_ull2d_rp, "dULLi", "")
BUILTIN(__nvvm_f2h_rn_ftz, "Usf", "")
BUILTIN(__nvvm_f2h_rn, "Usf", "")
-BUILTIN(__nvvm_h2f, "fUs", "")
-
// Bitcast
BUILTIN(__nvvm_bitcast_f2i, "if", "")
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNios2.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNios2.def
new file mode 100644
index 0000000..d9697e7
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsNios2.def
@@ -0,0 +1,70 @@
+//===-- BuiltinsNios2.def - Nios2 Builtin function database --------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Nios2-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// The format of this database matches clang/Basic/Builtins.def.
+
+#if defined(BUILTIN) && !defined(TARGET_BUILTIN)
+# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
+// Nios2 R1 builtins:
+
+//int __builtin_ldbio(volatile const void *);
+BUILTIN(__builtin_ldbio, "ivDC*", "")
+//int __builtin_ldbuio(volatile const void *);
+BUILTIN(__builtin_ldbuio, "ivDC*", "")
+//int __builtin_ldhio(volatile const void *);
+BUILTIN(__builtin_ldhio, "ivDC*", "")
+//int __builtin_ldhuio(volatile const void *);
+BUILTIN(__builtin_ldhuio, "ivDC*", "")
+//int __builtin_ldwio(volatile const void *);
+BUILTIN(__builtin_ldwio, "ivDC*", "")
+//int __builtin_ldwuio(int);
+BUILTIN(__builtin_ldwuio, "ii", "")
+// int __builtin_rdctl(int);
+BUILTIN(__builtin_rdctl, "iIi", "")
+// void __builtin_wrctl(int, int);
+BUILTIN(__builtin_wrctl, "vIii", "")
+// int __builtin_rdprs(int, int);
+BUILTIN(__builtin_rdprs, "iii", "")
+//void __builtin_stbio(volatile void *, int);
+BUILTIN(__builtin_stbio, "vvD*i", "")
+//void __builtin_sthio(volatile void *, int);
+BUILTIN(__builtin_sthio, "vvD*i", "")
+//void __builtin_stwio(volatile void *, int);
+BUILTIN(__builtin_stwio, "vvD*i", "")
+//void __builtin_sync(void);
+BUILTIN(__builtin_sync, "v", "")
+// void __builtin_flushd(volatile void *);
+BUILTIN(__builtin_flushd, "vvD*", "")
+// void __builtin_flushda(volatile void *);
+BUILTIN(__builtin_flushda, "vvD*", "")
+
+// Nios2 R2 builtins:
+
+// int __builtin_wrpie(int);
+TARGET_BUILTIN(__builtin_wrpie, "ii", "", "nios2r2mandatory")
+// void __builtin_eni(int);
+TARGET_BUILTIN(__builtin_eni, "vi", "", "nios2r2mandatory")
+// int __builtin_ldex(volatile const void *);
+TARGET_BUILTIN(__builtin_ldex, "ivDC*", "", "nios2r2mandatory")
+// int __builtin_stex(volatile void *, int);
+TARGET_BUILTIN(__builtin_stex, "ivD*i", "", "nios2r2mandatory")
+// int __builtin_ldsex(volatile const void *);
+TARGET_BUILTIN(__builtin_ldsex, "ivDC*", "", "nios2r2mpx")
+// int __builtin_stsex(volatile void *, int);
+TARGET_BUILTIN(__builtin_stsex, "ivDC*i", "", "nios2r2mpx")
+
+#undef BUILTIN
+#undef TARGET_BUILTIN
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsPPC.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsPPC.def
index f7cddc0..faa70a4 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsPPC.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsPPC.def
@@ -51,10 +51,10 @@ BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "")
BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "")
-BUILTIN(__builtin_altivec_vcfsx, "V4fV4ii", "")
-BUILTIN(__builtin_altivec_vcfux, "V4fV4ii", "")
-BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fi", "")
-BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fi", "")
+BUILTIN(__builtin_altivec_vcfsx, "V4fV4iIi", "")
+BUILTIN(__builtin_altivec_vcfux, "V4fV4iIi", "")
+BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fIi", "")
+BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fIi", "")
BUILTIN(__builtin_altivec_dss, "vUi", "")
BUILTIN(__builtin_altivec_dssall, "v", "")
@@ -420,6 +420,9 @@ BUILTIN(__builtin_vsx_xvtstdcsp, "V4UiV4fIi", "")
BUILTIN(__builtin_vsx_insertword, "V16UcV4UiV16UcIi", "")
BUILTIN(__builtin_vsx_extractuword, "V2ULLiV16UcIi", "")
+BUILTIN(__builtin_vsx_xxpermdi, "v.", "t")
+BUILTIN(__builtin_vsx_xxsldwi, "v.", "t")
+
// HTM builtins
BUILTIN(__builtin_tbegin, "UiUIi", "")
BUILTIN(__builtin_tend, "UiUIi", "")
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsSystemZ.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsSystemZ.def
index fa96e10..ac92286 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsSystemZ.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsSystemZ.def
@@ -253,5 +253,29 @@ TARGET_BUILTIN(__builtin_s390_vfmsdb, "V2dV2dV2dV2d", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vfsqdb, "V2dV2d", "nc", "vector")
TARGET_BUILTIN(__builtin_s390_vftcidb, "V2SLLiV2dIii*", "nc", "vector")
+// Vector-enhancements facility 1 intrinsics.
+TARGET_BUILTIN(__builtin_s390_vlrl, "V16ScUivC*", "", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vstrl, "vV16ScUiv*", "", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vbperm, "V2ULLiV16UcV16Uc", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vmslg, "V16UcV2ULLiV2ULLiV16UcIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmaxdb, "V2dV2dV2dIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmindb, "V2dV2dV2dIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfnmadb, "V2dV2dV2dV2d", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfnmsdb, "V2dV2dV2dV2d", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfcesbs, "V4SiV4fV4fi*", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfchsbs, "V4SiV4fV4fi*", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfchesbs, "V4SiV4fV4fi*", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfisb, "V4fV4fIiIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmaxsb, "V4fV4fV4fIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfminsb, "V4fV4fV4fIi", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vflnsb, "V4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vflpsb, "V4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmasb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfmssb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfnmasb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfnmssb, "V4fV4fV4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vfsqsb, "V4fV4f", "nc", "vector-enhancements-1")
+TARGET_BUILTIN(__builtin_s390_vftcisb, "V4SiV4fIii*", "nc", "vector-enhancements-1")
+
#undef BUILTIN
#undef TARGET_BUILTIN
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsWebAssembly.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsWebAssembly.def
index 97b59a1..19318dc 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsWebAssembly.def
@@ -16,9 +16,13 @@
// The format of this database matches clang/Basic/Builtins.def.
-// Note that current_memory is not "c" (readnone) because it must be sequenced with
-// respect to grow_memory calls.
+// Note that current_memory is not "c" (readnone) because it must be sequenced
+// with respect to grow_memory calls.
BUILTIN(__builtin_wasm_current_memory, "z", "n")
-BUILTIN(__builtin_wasm_grow_memory, "vz", "n")
+BUILTIN(__builtin_wasm_grow_memory, "zz", "n")
+
+// Exception handling builtins.
+BUILTIN(__builtin_wasm_throw, "vUiv*", "r")
+BUILTIN(__builtin_wasm_rethrow, "v", "r")
#undef BUILTIN
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def
index e53992b..6d3a478 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def
@@ -34,11 +34,6 @@
// can use it?
BUILTIN(__builtin_cpu_supports, "bcC*", "nc")
-// Win64-compatible va_list functions
-BUILTIN(__builtin_ms_va_start, "vc*&.", "nt")
-BUILTIN(__builtin_ms_va_end, "vc*&", "n")
-BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n")
-
// Undefined Values
//
TARGET_BUILTIN(__builtin_ia32_undef128, "V2d", "nc", "")
@@ -343,8 +338,8 @@ TARGET_BUILTIN(__builtin_ia32_lfence, "v", "", "sse2")
TARGET_HEADER_BUILTIN(_mm_lfence, "v", "h", "emmintrin.h", ALL_LANGUAGES, "sse2")
TARGET_BUILTIN(__builtin_ia32_mfence, "v", "", "sse2")
TARGET_HEADER_BUILTIN(_mm_mfence, "v", "h", "emmintrin.h", ALL_LANGUAGES, "sse2")
-TARGET_BUILTIN(__builtin_ia32_pause, "v", "", "sse2")
-TARGET_HEADER_BUILTIN(_mm_pause, "v", "h", "emmintrin.h", ALL_LANGUAGES, "sse2")
+TARGET_BUILTIN(__builtin_ia32_pause, "v", "", "")
+TARGET_HEADER_BUILTIN(_mm_pause, "v", "h", "emmintrin.h", ALL_LANGUAGES, "")
TARGET_BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "", "sse2")
TARGET_BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "", "sse2")
@@ -391,7 +386,6 @@ TARGET_BUILTIN(__builtin_ia32_roundsd, "V2dV2dV2dIi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_roundpd, "V2dV2dIi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fIc", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_dppd, "V2dV2dV2dIc", "", "sse4.1")
-TARGET_BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLiC*", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "", "sse4.1")
TARGET_BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "", "sse4.1")
@@ -576,7 +570,6 @@ TARGET_BUILTIN(__builtin_ia32_psrldi256, "V8iV8ii", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_psrld256, "V8iV8iV4i", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_psrlqi256, "V4LLiV4LLii", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_psrlq256, "V4LLiV4LLiV2LLi", "", "avx2")
-TARGET_BUILTIN(__builtin_ia32_movntdqa256, "V4LLiV4LLiC*", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_permvarsi256, "V8iV8iV8i", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8i", "", "avx2")
TARGET_BUILTIN(__builtin_ia32_permti256, "V4LLiV4LLiV4LLiIc", "", "avx2")
@@ -670,6 +663,12 @@ TARGET_BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "", "bmi2")
// TBM
TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "", "tbm")
+// LWP
+TARGET_BUILTIN(__builtin_ia32_llwpcb, "vv*", "", "lwp")
+TARGET_BUILTIN(__builtin_ia32_slwpcb, "v*", "", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpins32, "UcUiUiUi", "", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpval32, "vUiUiUi", "", "lwp")
+
// SHA
TARGET_BUILTIN(__builtin_ia32_sha1rnds4, "V4iV4iV4iIc", "", "sha")
TARGET_BUILTIN(__builtin_ia32_sha1nexte, "V4iV4iV4i", "", "sha")
@@ -832,8 +831,6 @@ TARGET_BUILTIN(__builtin_ia32_vphaddudq, "V2LLiV4i", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vphsubbw, "V8sV16c", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vphsubwd, "V4iV8s", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vphsubdq, "V2LLiV4i", "", "xop")
-TARGET_BUILTIN(__builtin_ia32_vpcmov, "V2LLiV2LLiV2LLiV2LLi", "", "xop")
-TARGET_BUILTIN(__builtin_ia32_vpcmov_256, "V4LLiV4LLiV4LLiV4LLi", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vpperm, "V16cV16cV16cV16c", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vprotb, "V16cV16cV16c", "", "xop")
TARGET_BUILTIN(__builtin_ia32_vprotw, "V8sV8sV8s", "", "xop")
@@ -997,22 +994,22 @@ TARGET_BUILTIN(__builtin_ia32_vpermt2varq512_mask, "V8LLiV8LLiV8LLiV8LLiUc", "",
TARGET_BUILTIN(__builtin_ia32_vpermt2varps512_mask, "V16fV16iV16fV16fUs", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_vpermt2varpd512_mask, "V8dV8LLiV8dV8dUc", "", "avx512f")
-TARGET_BUILTIN(__builtin_ia32_gather3div2df, "V2dV2ddC*V2LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div2di, "V2LLiV2LLiLLiC*V2LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div4df, "V4dV4ddC*V4LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div4di, "V4LLiV4LLiLLiC*V4LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div4sf, "V4fV4ffC*V2LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div4si, "V4iV4iiC*V2LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div8sf, "V4fV4ffC*V4LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3div8si, "V4iV4iiC*V4LLiUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv2df, "V2dV2ddC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv2di, "V2LLiV2LLiLLiC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv4df, "V4dV4ddC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv4di, "V4LLiV4LLiLLiC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv4sf, "V4fV4ffC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv4si, "V4iV4iiC*V4iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv8sf, "V8fV8ffC*V8iUci","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_gather3siv8si, "V8iV8iiC*V8iUci","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div2df, "V2dV2ddC*V2LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div2di, "V2LLiV2LLiLLiC*V2LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div4df, "V4dV4ddC*V4LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div4di, "V4LLiV4LLiLLiC*V4LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div4sf, "V4fV4ffC*V2LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div4si, "V4iV4iiC*V2LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div8sf, "V4fV4ffC*V4LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3div8si, "V4iV4iiC*V4LLiUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv2df, "V2dV2ddC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv2di, "V2LLiV2LLiLLiC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv4df, "V4dV4ddC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv4di, "V4LLiV4LLiLLiC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv4sf, "V4fV4ffC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv4si, "V4iV4iiC*V4iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv8sf, "V8fV8ffC*V8iUcIi","","avx512vl")
+TARGET_BUILTIN(__builtin_ia32_gather3siv8si, "V8iV8iiC*V8iUcIi","","avx512vl")
TARGET_BUILTIN(__builtin_ia32_gathersiv8df, "V8dV8ddC*V8iUcIi", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_gathersiv16sf, "V16fV16ffC*V16fUsIi", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_gatherdiv8df, "V8dV8ddC*V8LLiUcIi", "", "avx512f")
@@ -1068,10 +1065,10 @@ TARGET_BUILTIN(__builtin_ia32_ucmpw512_mask, "UiV32sV32sIiUi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_pabsb512_mask, "V64cV64cV64cULLi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_pabsw512_mask, "V32sV32sV32sUi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_packssdw512_mask, "V32sV16iV16iV32sUi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_packsswb512_mask, "V64cV32sV32sV64cULLi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_packusdw512_mask, "V32sV16iV16iV32sUi", "", "avx512bw")
-TARGET_BUILTIN(__builtin_ia32_packuswb512_mask, "V64cV32sV32sV64cULLi", "", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_packssdw512, "V32sV16iV16i", "", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_packsswb512, "V64cV32sV32s", "", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_packusdw512, "V32sV16iV16i", "", "avx512bw")
+TARGET_BUILTIN(__builtin_ia32_packuswb512, "V64cV32sV32s", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_paddsb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_paddsw512_mask, "V32sV32sV32sV32sUi", "", "avx512bw")
TARGET_BUILTIN(__builtin_ia32_paddusb512_mask, "V64cV64cV64cV64cULLi", "", "avx512bw")
@@ -1105,6 +1102,9 @@ TARGET_BUILTIN(__builtin_ia32_vpconflictsi_512_mask, "V16iV16iV16iUs", "", "avx5
TARGET_BUILTIN(__builtin_ia32_vplzcntd_512_mask, "V16iV16iV16iUs", "", "avx512cd")
TARGET_BUILTIN(__builtin_ia32_vplzcntq_512_mask, "V8LLiV8LLiV8LLiUc", "", "avx512cd")
+TARGET_BUILTIN(__builtin_ia32_vpopcntd_512, "V16iV16i", "", "avx512vpopcntdq")
+TARGET_BUILTIN(__builtin_ia32_vpopcntq_512, "V8LLiV8LLi", "", "avx512vpopcntdq")
+
TARGET_BUILTIN(__builtin_ia32_vpermi2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw")
TARGET_BUILTIN(__builtin_ia32_vpermi2varhi256_mask, "V16sV16sV16sV16sUs", "", "avx512vl,avx512bw")
TARGET_BUILTIN(__builtin_ia32_vpermt2varhi128_mask, "V8sV8sV8sV8sUc", "", "avx512vl,avx512bw")
@@ -1590,27 +1590,15 @@ TARGET_BUILTIN(__builtin_ia32_cvtq2mask128, "UcV2LLi","","avx512dq,avx512vl")
TARGET_BUILTIN(__builtin_ia32_cvtq2mask256, "UcV4LLi","","avx512dq,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastmb512, "V8LLiUc","","avx512cd")
TARGET_BUILTIN(__builtin_ia32_broadcastmw512, "V16iUs","","avx512cd")
-TARGET_BUILTIN(__builtin_ia32_broadcastf32x4_512, "V16fV4fV16fUs","","avx512f")
-TARGET_BUILTIN(__builtin_ia32_broadcastf64x4_512, "V8dV4dV8dUc","","avx512f")
-TARGET_BUILTIN(__builtin_ia32_broadcasti32x4_512, "V16iV4iV16iUs","","avx512f")
-TARGET_BUILTIN(__builtin_ia32_broadcasti64x4_512, "V8LLiV4LLiV8LLiUc","","avx512f")
TARGET_BUILTIN(__builtin_ia32_broadcastmb128, "V2LLiUc","","avx512cd,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastmb256, "V4LLiUc","","avx512cd,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastmw128, "V4iUs","","avx512cd,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastmw256, "V8iUs","","avx512cd,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcastf32x2_512_mask, "V16fV4fV16fUs","","avx512dq")
-TARGET_BUILTIN(__builtin_ia32_broadcastf32x8_512_mask, "V16fV8fV16fUs","","avx512dq")
-TARGET_BUILTIN(__builtin_ia32_broadcastf64x2_512_mask, "V8dV2dV8dUc","","avx512dq")
TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_512_mask, "V16iV4iV16iUs","","avx512dq")
-TARGET_BUILTIN(__builtin_ia32_broadcasti32x8_512_mask, "V16iV8iV16iUs","","avx512dq")
-TARGET_BUILTIN(__builtin_ia32_broadcasti64x2_512_mask, "V8LLiV2LLiV8LLiUc","","avx512dq")
TARGET_BUILTIN(__builtin_ia32_broadcastf32x2_256_mask, "V8fV4fV8fUc","","avx512dq,avx512vl")
-TARGET_BUILTIN(__builtin_ia32_broadcastf64x2_256_mask, "V4dV2dV4dUc","","avx512dq,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_128_mask, "V4iV4iV4iUc","","avx512dq,avx512vl")
TARGET_BUILTIN(__builtin_ia32_broadcasti32x2_256_mask, "V8iV4iV8iUc","","avx512dq,avx512vl")
-TARGET_BUILTIN(__builtin_ia32_broadcasti64x2_256_mask, "V4LLiV2LLiV4LLiUc","","avx512dq,avx512vl")
-TARGET_BUILTIN(__builtin_ia32_broadcastf32x4_256_mask, "V8fV4fV8fUc","","avx512vl")
-TARGET_BUILTIN(__builtin_ia32_broadcasti32x4_256_mask, "V8iV4iV8iUc","","avx512vl")
TARGET_BUILTIN(__builtin_ia32_pbroadcastw512_gpr_mask, "V32shV32sUi","","avx512bw")
TARGET_BUILTIN(__builtin_ia32_pbroadcastw256_gpr_mask, "V16shV16sUs","","avx512bw,avx512vl")
TARGET_BUILTIN(__builtin_ia32_pbroadcastw128_gpr_mask, "V8ssV8sUc","","avx512bw,avx512vl")
@@ -1761,7 +1749,6 @@ TARGET_BUILTIN(__builtin_ia32_kortestzhi, "iUsUs","","avx512f")
TARGET_BUILTIN(__builtin_ia32_kunpckhi, "UsUsUs","","avx512f")
TARGET_BUILTIN(__builtin_ia32_kxnorhi, "UsUsUs","","avx512f")
TARGET_BUILTIN(__builtin_ia32_kxorhi, "UsUsUs","","avx512f")
-TARGET_BUILTIN(__builtin_ia32_movntdqa512, "V8LLiV8LLi*","","avx512f")
TARGET_BUILTIN(__builtin_ia32_palignr512_mask, "V64cV64cV64cIiV64cULLi","","avx512bw")
TARGET_BUILTIN(__builtin_ia32_dbpsadbw128_mask, "V8sV16cV16cIiV8sUc","","avx512bw,avx512vl")
TARGET_BUILTIN(__builtin_ia32_dbpsadbw256_mask, "V16sV32cV32cIiV16sUs","","avx512bw,avx512vl")
@@ -1826,9 +1813,12 @@ TARGET_BUILTIN(__builtin_ia32_selectpd_512, "V8dUcV8dV8d", "", "")
TARGET_BUILTIN(__builtin_ia32_monitorx, "vv*UiUi", "", "mwaitx")
TARGET_BUILTIN(__builtin_ia32_mwaitx, "vUiUiUi", "", "mwaitx")
+// CLZERO
+TARGET_BUILTIN(__builtin_ia32_clzero, "vv*", "", "clzero")
+
// MSVC
-TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_ReadWriteBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_ReadBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -1840,6 +1830,18 @@ TARGET_HEADER_BUILTIN(__emulu, "ULLiUiUi", "nh", "intrin.h", ALL_MS_LANGUAGES, "
TARGET_HEADER_BUILTIN(_AddressOfReturnAddress, "v*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__stosb, "vUc*Ucz", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__int2c, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__ud2, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "")
+
+TARGET_HEADER_BUILTIN(__readfsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readfsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+
+TARGET_HEADER_BUILTIN(__readgsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readgsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readgsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__readgsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
#undef BUILTIN
#undef TARGET_BUILTIN
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def
index d38f522..4cde153 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def
@@ -22,8 +22,8 @@
# define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS)
#endif
-TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__mulh, "LLiLLiLLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -69,6 +69,8 @@ TARGET_BUILTIN(__builtin_ia32_bzhi_di, "ULLiULLiULLi", "", "bmi2")
TARGET_BUILTIN(__builtin_ia32_pdep_di, "ULLiULLiULLi", "", "bmi2")
TARGET_BUILTIN(__builtin_ia32_pext_di, "ULLiULLiULLi", "", "bmi2")
TARGET_BUILTIN(__builtin_ia32_bextri_u64, "ULLiULLiIULLi", "", "tbm")
+TARGET_BUILTIN(__builtin_ia32_lwpins64, "UcULLiUiUi", "", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpval64, "vULLiUiUi", "", "lwp")
TARGET_BUILTIN(__builtin_ia32_pbroadcastq512_gpr_mask, "V8LLiLLiV8LLiUc", "", "avx512f")
TARGET_BUILTIN(__builtin_ia32_pbroadcastq128_gpr_mask, "V2LLiULLiV2LLiUc","","avx512vl")
TARGET_BUILTIN(__builtin_ia32_pbroadcastq256_gpr_mask, "V4LLiULLiV4LLiUc","","avx512vl")
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td b/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td
index 7b581d3..3298a80 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td
@@ -45,6 +45,7 @@ def Named : Decl<1>;
def ObjCAtDefsField : DDecl<Field>;
def MSProperty : DDecl<Declarator>;
def Function : DDecl<Declarator>, DeclContext;
+ def CXXDeductionGuide : DDecl<Function>;
def CXXMethod : DDecl<Function>;
def CXXConstructor : DDecl<CXXMethod>;
def CXXDestructor : DDecl<CXXMethod>;
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h
index b83ef4d..22cded2 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h
@@ -29,6 +29,7 @@
#include <cassert>
#include <cstdint>
#include <list>
+#include <map>
#include <memory>
#include <string>
#include <type_traits>
@@ -177,12 +178,7 @@ public:
private:
unsigned char AllExtensionsSilenced; // Used by __extension__
- bool IgnoreAllWarnings; // Ignore all warnings: -w
- bool WarningsAsErrors; // Treat warnings like errors.
- bool EnableAllWarnings; // Enable all warnings.
- bool ErrorsAsFatal; // Treat errors like fatal errors.
- bool FatalsAsError; // Treat fatal errors like errors.
- bool SuppressSystemWarnings; // Suppress warnings in system headers.
+ bool SuppressAfterFatalError; // Suppress diagnostics after a fatal error?
bool SuppressAllDiagnostics; // Suppress all diagnostics.
bool ElideType; // Elide common types of templates.
bool PrintTemplateTree; // Print a tree when comparing templates.
@@ -193,7 +189,6 @@ private:
// 0 -> no limit.
unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation
// backtrace stack, 0 -> no limit.
- diag::Severity ExtBehavior; // Map extensions to warnings or errors?
IntrusiveRefCntPtr<DiagnosticIDs> Diags;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticConsumer *Client;
@@ -215,6 +210,19 @@ private:
llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap;
public:
+ // "Global" configuration state that can actually vary between modules.
+ unsigned IgnoreAllWarnings : 1; // Ignore all warnings: -w
+ unsigned EnableAllWarnings : 1; // Enable all warnings.
+ unsigned WarningsAsErrors : 1; // Treat warnings like errors.
+ unsigned ErrorsAsFatal : 1; // Treat errors like fatal errors.
+ unsigned SuppressSystemWarnings : 1; // Suppress warnings in system headers.
+ diag::Severity ExtBehavior; // Map extensions to warnings or errors?
+
+ DiagState()
+ : IgnoreAllWarnings(false), EnableAllWarnings(false),
+ WarningsAsErrors(false), ErrorsAsFatal(false),
+ SuppressSystemWarnings(false), ExtBehavior(diag::Severity::Ignored) {}
+
typedef llvm::DenseMap<unsigned, DiagnosticMapping>::iterator iterator;
typedef llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator
const_iterator;
@@ -222,6 +230,9 @@ private:
void setMapping(diag::kind Diag, DiagnosticMapping Info) {
DiagMap[Diag] = Info;
}
+ DiagnosticMapping lookupMapping(diag::kind Diag) const {
+ return DiagMap.lookup(Diag);
+ }
DiagnosticMapping &getOrAddMapping(diag::kind Diag);
@@ -232,59 +243,97 @@ private:
/// \brief Keeps and automatically disposes all DiagStates that we create.
std::list<DiagState> DiagStates;
- /// \brief Represents a point in source where the diagnostic state was
- /// modified because of a pragma.
- ///
- /// 'Loc' can be null if the point represents the diagnostic state
- /// modifications done through the command-line.
- struct DiagStatePoint {
- DiagState *State;
- FullSourceLoc Loc;
- DiagStatePoint(DiagState *State, FullSourceLoc Loc)
- : State(State), Loc(Loc) { }
-
- bool operator<(const DiagStatePoint &RHS) const {
- // If Loc is invalid it means it came from <command-line>, in which case
- // we regard it as coming before any valid source location.
- if (RHS.Loc.isInvalid())
- return false;
- if (Loc.isInvalid())
- return true;
- return Loc.isBeforeInTranslationUnitThan(RHS.Loc);
+ /// A mapping from files to the diagnostic states for those files. Lazily
+ /// built on demand for files in which the diagnostic state has not changed.
+ class DiagStateMap {
+ public:
+ /// Add an initial diagnostic state.
+ void appendFirst(DiagState *State);
+ /// Add a new latest state point.
+ void append(SourceManager &SrcMgr, SourceLocation Loc, DiagState *State);
+ /// Look up the diagnostic state at a given source location.
+ DiagState *lookup(SourceManager &SrcMgr, SourceLocation Loc) const;
+ /// Determine whether this map is empty.
+ bool empty() const { return Files.empty(); }
+ /// Clear out this map.
+ void clear() {
+ Files.clear();
+ FirstDiagState = CurDiagState = nullptr;
+ CurDiagStateLoc = SourceLocation();
}
+
+ /// Grab the most-recently-added state point.
+ DiagState *getCurDiagState() const { return CurDiagState; }
+ /// Get the location at which a diagnostic state was last added.
+ SourceLocation getCurDiagStateLoc() const { return CurDiagStateLoc; }
+
+ private:
+ /// \brief Represents a point in source where the diagnostic state was
+ /// modified because of a pragma.
+ ///
+ /// 'Loc' can be null if the point represents the diagnostic state
+ /// modifications done through the command-line.
+ struct DiagStatePoint {
+ DiagState *State;
+ unsigned Offset;
+ DiagStatePoint(DiagState *State, unsigned Offset)
+ : State(State), Offset(Offset) { }
+ };
+
+ /// Description of the diagnostic states and state transitions for a
+ /// particular FileID.
+ struct File {
+ /// The diagnostic state for the parent file. This is strictly redundant,
+ /// as looking up the DecomposedIncludedLoc for the FileID in the Files
+ /// map would give us this, but we cache it here for performance.
+ File *Parent = nullptr;
+ /// The offset of this file within its parent.
+ unsigned ParentOffset = 0;
+ /// Whether this file has any local (not imported from an AST file)
+ /// diagnostic state transitions.
+ bool HasLocalTransitions = false;
+ /// The points within the file where the state changes. There will always
+ /// be at least one of these (the state on entry to the file).
+ llvm::SmallVector<DiagStatePoint, 4> StateTransitions;
+
+ DiagState *lookup(unsigned Offset) const;
+ };
+
+ /// The diagnostic states for each file.
+ mutable std::map<FileID, File> Files;
+
+ /// The initial diagnostic state.
+ DiagState *FirstDiagState;
+ /// The current diagnostic state.
+ DiagState *CurDiagState;
+ /// The location at which the current diagnostic state was established.
+ SourceLocation CurDiagStateLoc;
+
+ /// Get the diagnostic state information for a file.
+ File *getFile(SourceManager &SrcMgr, FileID ID) const;
+
+ friend class ASTReader;
+ friend class ASTWriter;
};
- /// \brief A sorted vector of all DiagStatePoints representing changes in
- /// diagnostic state due to diagnostic pragmas.
- ///
- /// The vector is always sorted according to the SourceLocation of the
- /// DiagStatePoint.
- typedef std::vector<DiagStatePoint> DiagStatePointsTy;
- mutable DiagStatePointsTy DiagStatePoints;
+ DiagStateMap DiagStatesByLoc;
/// \brief Keeps the DiagState that was active during each diagnostic 'push'
/// so we can get back at it when we 'pop'.
std::vector<DiagState *> DiagStateOnPushStack;
DiagState *GetCurDiagState() const {
- assert(!DiagStatePoints.empty());
- return DiagStatePoints.back().State;
+ return DiagStatesByLoc.getCurDiagState();
}
- void PushDiagStatePoint(DiagState *State, SourceLocation L) {
- FullSourceLoc Loc(L, getSourceManager());
- // Make sure that DiagStatePoints is always sorted according to Loc.
- assert(Loc.isValid() && "Adding invalid loc point");
- assert(!DiagStatePoints.empty() &&
- (DiagStatePoints.back().Loc.isInvalid() ||
- DiagStatePoints.back().Loc.isBeforeInTranslationUnitThan(Loc)) &&
- "Previous point loc comes after or is the same as new one");
- DiagStatePoints.push_back(DiagStatePoint(State, Loc));
- }
+ void PushDiagStatePoint(DiagState *State, SourceLocation L);
/// \brief Finds the DiagStatePoint that contains the diagnostic state of
/// the given source location.
- DiagStatePointsTy::iterator GetDiagStatePointForLoc(SourceLocation Loc) const;
+ DiagState *GetDiagStateForLoc(SourceLocation Loc) const {
+ return SourceMgr ? DiagStatesByLoc.lookup(*SourceMgr, Loc)
+ : DiagStatesByLoc.getCurDiagState();
+ }
/// \brief Sticky flag set to \c true when an error is emitted.
bool ErrorOccurred;
@@ -390,7 +439,11 @@ public:
assert(SourceMgr && "SourceManager not set!");
return *SourceMgr;
}
- void setSourceManager(SourceManager *SrcMgr) { SourceMgr = SrcMgr; }
+ void setSourceManager(SourceManager *SrcMgr) {
+ assert(DiagStatesByLoc.empty() &&
+ "Leftover diag state from a different SourceManager.");
+ SourceMgr = SrcMgr;
+ }
//===--------------------------------------------------------------------===//
// DiagnosticsEngine characterization methods, used by a client to customize
@@ -447,33 +500,47 @@ public:
/// \brief When set to true, any unmapped warnings are ignored.
///
/// If this and WarningsAsErrors are both set, then this one wins.
- void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
- bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }
+ void setIgnoreAllWarnings(bool Val) {
+ GetCurDiagState()->IgnoreAllWarnings = Val;
+ }
+ bool getIgnoreAllWarnings() const {
+ return GetCurDiagState()->IgnoreAllWarnings;
+ }
/// \brief When set to true, any unmapped ignored warnings are no longer
/// ignored.
///
/// If this and IgnoreAllWarnings are both set, then that one wins.
- void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; }
- bool getEnableAllWarnings() const { return EnableAllWarnings; }
+ void setEnableAllWarnings(bool Val) {
+ GetCurDiagState()->EnableAllWarnings = Val;
+ }
+ bool getEnableAllWarnings() const {
+ return GetCurDiagState()->EnableAllWarnings;
+ }
/// \brief When set to true, any warnings reported are issued as errors.
- void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
- bool getWarningsAsErrors() const { return WarningsAsErrors; }
+ void setWarningsAsErrors(bool Val) {
+ GetCurDiagState()->WarningsAsErrors = Val;
+ }
+ bool getWarningsAsErrors() const {
+ return GetCurDiagState()->WarningsAsErrors;
+ }
/// \brief When set to true, any error reported is made a fatal error.
- void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; }
- bool getErrorsAsFatal() const { return ErrorsAsFatal; }
+ void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; }
+ bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; }
- /// \brief When set to true, any fatal error reported is made an error.
- ///
- /// This setting takes precedence over the setErrorsAsFatal setting above.
- void setFatalsAsError(bool Val) { FatalsAsError = Val; }
- bool getFatalsAsError() const { return FatalsAsError; }
+ /// \brief When set to true (the default), suppress further diagnostics after
+ /// a fatal error.
+ void setSuppressAfterFatalError(bool Val) { SuppressAfterFatalError = Val; }
/// \brief When set to true mask warnings that come from system headers.
- void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }
- bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }
+ void setSuppressSystemWarnings(bool Val) {
+ GetCurDiagState()->SuppressSystemWarnings = Val;
+ }
+ bool getSuppressSystemWarnings() const {
+ return GetCurDiagState()->SuppressSystemWarnings;
+ }
/// \brief Suppress all diagnostics, to silence the front end when we
/// know that we don't want any more diagnostics to be passed along to the
@@ -525,11 +592,15 @@ public:
}
/// \brief Controls whether otherwise-unmapped extension diagnostics are
- /// mapped onto ignore/warning/error.
+ /// mapped onto ignore/warning/error.
///
/// This corresponds to the GCC -pedantic and -pedantic-errors option.
- void setExtensionHandlingBehavior(diag::Severity H) { ExtBehavior = H; }
- diag::Severity getExtensionHandlingBehavior() const { return ExtBehavior; }
+ void setExtensionHandlingBehavior(diag::Severity H) {
+ GetCurDiagState()->ExtBehavior = H;
+ }
+ diag::Severity getExtensionHandlingBehavior() const {
+ return GetCurDiagState()->ExtBehavior;
+ }
/// \brief Counter bumped when an __extension__ block is/ encountered.
///
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td
index 39da006..f25068e 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td
@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
+// See the Internals Manual, section The Diagnostics Subsystem for an overview.
+
// Define the diagnostic severities.
class Severity<string N> {
string Name = N;
@@ -100,10 +102,20 @@ class SuppressInSystemHeader {
class Error<string str> : Diagnostic<str, CLASS_ERROR, SEV_Error>, SFINAEFailure {
bit ShowInSystemHeader = 1;
}
+// Warnings default to on (but can be default-off'd with DefaultIgnore).
+// This is used for warnings about questionable code; warnings about
+// accepted language extensions should use Extension or ExtWarn below instead.
class Warning<string str> : Diagnostic<str, CLASS_WARNING, SEV_Warning>;
+// Remarks can be turned on with -R flags and provide commentary, e.g. on
+// optimizer decisions.
class Remark<string str> : Diagnostic<str, CLASS_REMARK, SEV_Ignored>;
+// Extensions are warnings about accepted language extensions.
+// Extension warnings are default-off but enabled by -pedantic.
class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored>;
+// ExtWarns are warnings about accepted language extensions.
+// ExtWarn warnings are default-on.
class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning>;
+// Notes can provide supplementary information on errors, warnings, and remarks.
class Note<string str> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/>;
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td
index 03ed8aa..b3cba206 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -44,7 +44,8 @@ def note_constexpr_non_global : Note<
def note_constexpr_uninitialized : Note<
"%select{|sub}0object of type %1 is not initialized">;
def note_constexpr_array_index : Note<"cannot refer to element %0 of "
- "%select{array of %2 elements|non-array object}1 in a constant expression">;
+ "%select{array of %2 element%plural{1:|:s}2|non-array object}1 "
+ "in a constant expression">;
def note_constexpr_float_arithmetic : Note<
"floating point arithmetic produces %select{an infinity|a NaN}0">;
def note_constexpr_pointer_subtraction_not_same_array : Note<
@@ -199,12 +200,17 @@ def note_odr_defined_here : Note<"also defined here">;
def err_odr_function_type_inconsistent : Error<
"external function %0 declared with incompatible types in different "
"translation units (%1 vs. %2)">;
-def warn_odr_tag_type_inconsistent : Warning<
- "type %0 has incompatible definitions in different translation units">,
- InGroup<DiagGroup<"odr">>;
+def warn_odr_tag_type_inconsistent
+ : Warning<"type %0 has incompatible definitions in different translation "
+ "units">,
+ InGroup<DiagGroup<"odr">>;
+def err_odr_tag_type_inconsistent
+ : Error<"type %0 has incompatible definitions in different translation "
+ "units">;
def note_odr_tag_kind_here: Note<
"%0 is a %select{struct|interface|union|class|enum}1 here">;
def note_odr_field : Note<"field %0 has type %1 here">;
+def note_odr_field_name : Note<"field has name %0 here">;
def note_odr_missing_field : Note<"no corresponding field here">;
def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">;
def note_odr_not_bit_field : Note<"field %0 is not a bit-field">;
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td
index af0612a..98fd3c4 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -45,7 +45,9 @@ def err_expected_colon_after_setter_name : Error<
"must end with ':'">;
def err_expected_string_literal : Error<"expected string literal "
"%select{in %1|for diagnostic message in static_assert|"
- "for optional message in 'availability' attribute}0">;
+ "for optional message in 'availability' attribute|"
+ "for %select{language|source container}1 name in "
+ "'external_source_symbol' attribute}0">;
def err_invalid_string_udl : Error<
"string literal with user-defined suffix cannot be used here">;
def err_invalid_character_udl : Error<
@@ -88,10 +90,10 @@ def err_module_unavailable : Error<
"module '%0' %select{is incompatible with|requires}1 feature '%2'">;
def err_module_header_missing : Error<
"%select{|umbrella }0header '%1' not found">;
-def err_module_lock_failure : Error<
- "could not acquire lock file for module '%0': %1">, DefaultFatal;
-def err_module_lock_timeout : Error<
- "timed out waiting to acquire lock file for module '%0'">, DefaultFatal;
+def remark_module_lock_failure : Remark<
+ "could not acquire lock file for module '%0': %1">, InGroup<ModuleBuild>;
+def remark_module_lock_timeout : Remark<
+ "timed out waiting to acquire lock file for module '%0'">, InGroup<ModuleBuild>;
def err_module_cycle : Error<"cyclic dependency in module '%0': %1">,
DefaultFatal;
def err_module_prebuilt : Error<
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 2fcd3a5..fcef881 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -85,6 +85,8 @@ def err_drv_clang_unsupported : Error<
"the clang compiler does not support '%0'">;
def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error<
"the clang compiler does not support '%0' for C++ on Darwin/i386">;
+def err_drv_clang_unsupported_opt_faltivec : Error<
+ "the clang compiler does not support '%0', %1">;
def err_drv_command_failed : Error<
"%0 command failed with exit code %1 (use -v to see invocation)">;
def err_drv_compilationdatabase : Error<
@@ -92,7 +94,7 @@ def err_drv_compilationdatabase : Error<
def err_drv_command_signalled : Error<
"%0 command failed due to signal (use -v to see invocation)">;
def err_drv_force_crash : Error<
- "failing because environment variable '%0' is set">;
+ "failing because %select{environment variable 'FORCE_CLANG_DIAGNOSTICS_CRASH' is set|'-gen-reproducer' is used}0">;
def err_drv_invalid_mfloat_abi : Error<
"invalid float ABI '%0'">;
def err_drv_invalid_libcxx_deployment : Error<
@@ -133,8 +135,13 @@ def err_drv_invalid_gcc_output_type : Error<
"invalid output type '%0' for use with gcc tool">;
def err_drv_cc_print_options_failure : Error<
"unable to open CC_PRINT_OPTIONS file: %0">;
+def err_drv_lto_without_lld : Error<"LTO requires -fuse-ld=lld">;
def err_drv_preamble_format : Error<
"incorrect format for -preamble-bytes=N,END">;
+def warn_invalid_ios_deployment_target : Warning<
+ "invalid iOS deployment version '%0', iOS 10 is the maximum deployment "
+ "target for 32-bit targets">, InGroup<InvalidIOSDeploymentTarget>,
+ DefaultError;
def err_drv_conflicting_deployment_targets : Error<
"conflicting deployment targets, both '%0' and '%1' are present in environment">;
def err_arc_unsupported_on_runtime : Error<
@@ -172,6 +179,8 @@ def warn_drv_optimization_value : Warning<"optimization level '%0' is not suppor
InGroup<InvalidCommandLineArgument>;
def warn_ignored_gcc_optimization : Warning<"optimization flag '%0' is not supported">,
InGroup<IgnoredOptimizationArgument>;
+def warn_ignored_clang_option : Warning<"the flag '%0' has been deprecated and will be ignored">,
+ InGroup<UnusedCommandLineArgument>;
def warn_drv_unsupported_opt_for_target : Warning<
"optimization flag '%0' is not supported for target '%1'">,
InGroup<IgnoredOptimizationArgument>;
@@ -192,8 +201,8 @@ def warn_drv_unused_argument : Warning<
def warn_drv_empty_joined_argument : Warning<
"joined argument expects additional value: '%0'">,
InGroup<UnusedCommandLineArgument>;
-def warn_drv_fdiagnostics_show_hotness_requires_pgo : Warning<
- "argument '-fdiagnostics-show-hotness' requires profile-guided optimization information">,
+def warn_drv_diagnostics_hotness_requires_pgo : Warning<
+ "argument '%0' requires profile-guided optimization information">,
InGroup<UnusedCommandLineArgument>;
def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
@@ -223,6 +232,9 @@ def warn_drv_enabling_rtti_with_exceptions : Warning<
def warn_drv_disabling_vptr_no_rtti_default : Warning<
"implicitly disabling vptr sanitizer because rtti wasn't enabled">,
InGroup<DiagGroup<"auto-disable-vptr-sanitizer">>;
+def warn_drv_object_size_disabled_O0 : Warning<
+ "the object size sanitizer has no effect at -O0, but is explicitly enabled: %0">,
+ InGroup<InvalidCommandLineArgument>;
def note_drv_command_failed_diag_msg : Note<
"diagnostic msg: %0">;
@@ -230,6 +242,9 @@ def note_drv_t_option_is_global : Note<
"The last /TC or /TP option takes precedence over earlier instances">;
def note_drv_address_sanitizer_debug_runtime : Note<
"AddressSanitizer doesn't support linking with debug runtime libraries yet">;
+def note_drv_use_standard : Note<"use '%0'"
+ "%select{| or '%3'|, '%3', or '%4'|, '%3', '%4', or '%5'}2 "
+ "for '%1' standard">;
def err_analyzer_config_no_value : Error<
"analyzer-config option '%0' has a key but no value">;
@@ -247,6 +262,10 @@ def err_test_module_file_extension_format : Error<
def warn_drv_invoking_fallback : Warning<"falling back to %0">,
InGroup<Fallback>;
+def warn_slash_u_filename : Warning<"'/U%0' treated as the '/U' option">,
+ InGroup<DiagGroup<"slash-u-filename">>;
+def note_use_dashdash : Note<"Use '--' to treat subsequent arguments as filenames">;
+
def err_drv_ropi_rwpi_incompatible_with_pic : Error<
"embedded and GOT-based position independence are incompatible">;
def err_drv_ropi_incompatible_with_cxx : Error<
@@ -277,4 +296,8 @@ def warn_drv_ps4_sdk_dir : Warning<
def err_drv_unsupported_linker : Error<"unsupported value '%0' for -linker option">;
def err_drv_defsym_invalid_format : Error<"defsym must be of the form: sym=value: %0">;
def err_drv_defsym_invalid_symval : Error<"Value is not an integer: %0">;
+def warn_drv_msvc_not_found : Warning<
+ "unable to find a Visual Studio installation; "
+ "try running Clang from a developer command prompt">,
+ InGroup<DiagGroup<"msvc-not-found">>;
}
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 1267f8d..57c24e9 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -179,6 +179,8 @@ def warn_incompatible_analyzer_plugin_api : Warning<
def note_incompatible_analyzer_plugin_api : Note<
"current API version is '%0', but plugin was compiled with version '%1'">;
+def err_module_build_requires_fmodules : Error<
+ "module compilation requires '-fmodules'">;
def err_module_interface_requires_modules_ts : Error<
"module interface compilation requires '-fmodules-ts'">;
def warn_module_config_mismatch : Warning<
@@ -196,6 +198,7 @@ def err_no_submodule_suggest : Error<
"no submodule named %0 in module '%1'; did you mean '%2'?">;
def warn_missing_submodule : Warning<"missing submodule '%0'">,
InGroup<IncompleteUmbrella>;
+def note_module_import_here : Note<"module imported here">;
def err_module_cannot_create_includes : Error<
"cannot create includes file for module %0: %1">;
def warn_module_config_macro_undef : Warning<
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td
index 4173d03..23e4d46 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td
@@ -34,7 +34,11 @@ def CXX14BinaryLiteral : DiagGroup<"c++14-binary-literal">;
def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">;
def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">;
def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">;
+def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">;
def BitFieldWidth : DiagGroup<"bitfield-width">;
+def CoroutineMissingUnhandledException :
+ DiagGroup<"coroutine-missing-unhandled-exception">;
+def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException]>;
def ConstantConversion :
DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >;
def LiteralConversion : DiagGroup<"literal-conversion">;
@@ -94,7 +98,9 @@ def CXX11CompatDeprecatedWritableStr :
def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
-def UnguardedAvailability : DiagGroup<"unguarded-availability">;
+def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">;
+def UnguardedAvailability : DiagGroup<"unguarded-availability",
+ [UnguardedAvailabilityNew]>;
// partial-availability is an alias of unguarded-availability.
def : DiagGroup<"partial-availability", [UnguardedAvailability]>;
def DeprecatedDynamicExceptionSpec
@@ -146,6 +152,13 @@ def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">;
def FormatExtraArgs : DiagGroup<"format-extra-args">;
def FormatZeroLength : DiagGroup<"format-zero-length">;
+def InvalidIOSDeploymentTarget : DiagGroup<"invalid-ios-deployment-target">;
+
+def CXX17CompatMangling : DiagGroup<"c++17-compat-mangling">;
+def : DiagGroup<"c++1z-compat-mangling", [CXX17CompatMangling]>;
+// Name of this warning in GCC.
+def NoexceptType : DiagGroup<"noexcept-type", [CXX17CompatMangling]>;
+
// Warnings for C++1y code which is not compatible with prior C++ standards.
def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">;
def CXXPre14CompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic",
@@ -175,6 +188,8 @@ def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic",
def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
+def CXX11WarnOverrideDestructor :
+ DiagGroup<"inconsistent-missing-destructor-override">;
def CXX11WarnOverrideMethod : DiagGroup<"inconsistent-missing-override">;
// Original name of this warning in Clang
@@ -204,8 +219,10 @@ def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre1zCompat]>;
def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic",
[CXXPre1zCompatPedantic]>;
-def CXX1zCompat : DiagGroup<"c++1z-compat", [DeprecatedRegister,
- DeprecatedIncrementBool]>;
+def CXX17Compat : DiagGroup<"c++17-compat", [DeprecatedRegister,
+ DeprecatedIncrementBool,
+ CXX17CompatMangling]>;
+def : DiagGroup<"c++1z-compat", [CXX17Compat]>;
def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">;
@@ -301,6 +318,7 @@ def : DiagGroup<"nonportable-cfstrings">;
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
def : DiagGroup<"effc++", [NonVirtualDtor]>;
def OveralignedType : DiagGroup<"over-aligned">;
+def AlignedAllocationUnavailable : DiagGroup<"aligned-allocation-unavailable">;
def OldStyleCast : DiagGroup<"old-style-cast">;
def : DiagGroup<"old-style-definition">;
def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">;
@@ -355,6 +373,7 @@ def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
def Sentinel : DiagGroup<"sentinel">;
def MissingMethodReturnType : DiagGroup<"missing-method-return-type">;
+def ShadowField : DiagGroup<"shadow-field">;
def ShadowFieldInConstructorModified : DiagGroup<"shadow-field-in-constructor-modified">;
def ShadowFieldInConstructor : DiagGroup<"shadow-field-in-constructor",
[ShadowFieldInConstructorModified]>;
@@ -366,7 +385,7 @@ def ShadowUncapturedLocal : DiagGroup<"shadow-uncaptured-local">;
def Shadow : DiagGroup<"shadow", [ShadowFieldInConstructorModified,
ShadowIvar]>;
def ShadowAll : DiagGroup<"shadow-all", [Shadow, ShadowFieldInConstructor,
- ShadowUncapturedLocal]>;
+ ShadowUncapturedLocal, ShadowField]>;
def Shorten64To32 : DiagGroup<"shorten-64-to-32">;
def : DiagGroup<"sign-promo">;
@@ -454,7 +473,9 @@ def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes,
def IgnoredPragmaIntrinsic : DiagGroup<"ignored-pragma-intrinsic">;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
def IgnoredPragmas : DiagGroup<"ignored-pragmas", [IgnoredPragmaIntrinsic]>;
-def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas]>;
+def PragmaClangAttribute : DiagGroup<"pragma-clang-attribute">;
+def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas,
+ PragmaClangAttribute]>;
def UnknownWarningOption : DiagGroup<"unknown-warning-option">;
def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">;
@@ -477,9 +498,11 @@ def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">;
def UnneededMemberFunction : DiagGroup<"unneeded-member-function">;
def UnusedPrivateField : DiagGroup<"unused-private-field">;
def UnusedFunction : DiagGroup<"unused-function", [UnneededInternalDecl]>;
+def UnusedTemplate : DiagGroup<"unused-template", [UnneededInternalDecl]>;
def UnusedMemberFunction : DiagGroup<"unused-member-function",
[UnneededMemberFunction]>;
def UnusedLabel : DiagGroup<"unused-label">;
+def UnusedLambdaCapture : DiagGroup<"unused-lambda-capture">;
def UnusedParameter : DiagGroup<"unused-parameter">;
def UnusedResult : DiagGroup<"unused-result">;
def PotentiallyEvaluatedExpression : DiagGroup<"potentially-evaluated-expression">;
@@ -602,6 +625,7 @@ def Conversion : DiagGroup<"conversion",
[BoolConversion,
ConstantConversion,
EnumConversion,
+ BitFieldEnumConversion,
FloatConversion,
Shorten64To32,
IntConversion,
@@ -616,9 +640,11 @@ def Conversion : DiagGroup<"conversion",
def Unused : DiagGroup<"unused",
[UnusedArgument, UnusedFunction, UnusedLabel,
// UnusedParameter, (matches GCC's behavior)
+ // UnusedTemplate, (clean-up libc++ before enabling)
// UnusedMemberFunction, (clean-up llvm before enabling)
- UnusedPrivateField, UnusedLocalTypedef,
- UnusedValue, UnusedVariable, UnusedPropertyIvar]>,
+ UnusedPrivateField, UnusedLambdaCapture,
+ UnusedLocalTypedef, UnusedValue, UnusedVariable,
+ UnusedPropertyIvar]>,
DiagCategory<"Unused Entity Issue">;
// Format settings.
@@ -719,6 +745,7 @@ def Pedantic : DiagGroup<"pedantic">;
// Aliases.
def : DiagGroup<"", [Extra]>; // -W = -Wextra
def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wextra-tokens
+def : DiagGroup<"cpp", [PoundWarning]>; // -Wcpp = -W#warnings
def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
def : DiagGroup<"conversion-null",
[NullConversion]>; // -Wconversion-null = -Wnull-conversion
@@ -747,10 +774,11 @@ def CXX14 : DiagGroup<"c++14-extensions", [CXX14BinaryLiteral]>;
// A warning group for warnings about using C++1z features as extensions in
// earlier C++ versions.
-def CXX1z : DiagGroup<"c++1z-extensions">;
+def CXX17 : DiagGroup<"c++17-extensions">;
def : DiagGroup<"c++0x-extensions", [CXX11]>;
def : DiagGroup<"c++1y-extensions", [CXX14]>;
+def : DiagGroup<"c++1z-extensions", [CXX17]>;
def DelegatingCtorCycles :
DiagGroup<"delegating-ctor-cycles">;
@@ -878,10 +906,11 @@ def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">;
def BackendOptimizationFailure : DiagGroup<"pass-failed">;
// Instrumentation based profiling warnings.
+def ProfileInstrMissing : DiagGroup<"profile-instr-missing">;
def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">;
-// AddressSanitizer frontent instrumentation remarks.
+// AddressSanitizer frontend instrumentation remarks.
def SanitizeAddressRemarks : DiagGroup<"sanitize-address">;
// Issues with serialized diagnostics.
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h
index fcd04a0..cdd35854 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h
@@ -18,6 +18,7 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
+#include <vector>
namespace clang {
class DiagnosticsEngine;
@@ -32,7 +33,7 @@ namespace clang {
DIAG_START_FRONTEND = DIAG_START_DRIVER + 200,
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100,
DIAG_START_LEX = DIAG_START_SERIALIZATION + 120,
- DIAG_START_PARSE = DIAG_START_LEX + 300,
+ DIAG_START_PARSE = DIAG_START_LEX + 400,
DIAG_START_AST = DIAG_START_PARSE + 500,
DIAG_START_COMMENT = DIAG_START_AST + 110,
DIAG_START_SEMA = DIAG_START_COMMENT + 100,
@@ -84,6 +85,7 @@ class DiagnosticMapping {
unsigned IsPragma : 1;
unsigned HasNoWarningAsError : 1;
unsigned HasNoErrorAsFatal : 1;
+ unsigned WasUpgradedFromWarning : 1;
public:
static DiagnosticMapping Make(diag::Severity Severity, bool IsUser,
@@ -94,6 +96,7 @@ public:
Result.IsPragma = IsPragma;
Result.HasNoWarningAsError = 0;
Result.HasNoErrorAsFatal = 0;
+ Result.WasUpgradedFromWarning = 0;
return Result;
}
@@ -103,11 +106,39 @@ public:
bool isUser() const { return IsUser; }
bool isPragma() const { return IsPragma; }
+ bool isErrorOrFatal() const {
+ return getSeverity() == diag::Severity::Error ||
+ getSeverity() == diag::Severity::Fatal;
+ }
+
bool hasNoWarningAsError() const { return HasNoWarningAsError; }
void setNoWarningAsError(bool Value) { HasNoWarningAsError = Value; }
bool hasNoErrorAsFatal() const { return HasNoErrorAsFatal; }
void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; }
+
+ /// Whether this mapping attempted to map the diagnostic to a warning, but
+ /// was overruled because the diagnostic was already mapped to an error or
+ /// fatal error.
+ bool wasUpgradedFromWarning() const { return WasUpgradedFromWarning; }
+ void setUpgradedFromWarning(bool Value) { WasUpgradedFromWarning = Value; }
+
+ /// Serialize this mapping as a raw integer.
+ unsigned serialize() const {
+ return (IsUser << 7) | (IsPragma << 6) | (HasNoWarningAsError << 5) |
+ (HasNoErrorAsFatal << 4) | (WasUpgradedFromWarning << 3) | Severity;
+ }
+ /// Deserialize a mapping.
+ static DiagnosticMapping deserialize(unsigned Bits) {
+ DiagnosticMapping Result;
+ Result.IsUser = (Bits >> 7) & 1;
+ Result.IsPragma = (Bits >> 6) & 1;
+ Result.HasNoWarningAsError = (Bits >> 5) & 1;
+ Result.HasNoErrorAsFatal = (Bits >> 4) & 1;
+ Result.WasUpgradedFromWarning = (Bits >> 3) & 1;
+ Result.Severity = Bits & 0x7;
+ return Result;
+ }
};
/// \brief Used for handling and querying diagnostic IDs.
@@ -233,6 +264,13 @@ public:
/// are not SFINAE errors.
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
+ /// \brief Get the string of all diagnostic flags.
+ ///
+ /// \returns A list of all diagnostics flags as they would be written in a
+ /// command line invocation including their `no-` variants. For example:
+ /// `{"-Wempty-body", "-Wno-empty-body", ...}`
+ static std::vector<std::string> getDiagnosticFlags();
+
/// \brief Get the set of all diagnostic IDs in the group with the given name.
///
/// \param[out] Diags - On return, the diagnostics in the group.
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td
index 7f7022b..706881b 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -181,10 +181,10 @@ def err_hex_constant_requires : Error<
def ext_hex_constant_invalid : Extension<
"hexadecimal floating constants are a C99 feature">, InGroup<C99>;
def ext_hex_literal_invalid : Extension<
- "hexadecimal floating literals are a C++1z feature">, InGroup<CXX1z>;
+ "hexadecimal floating literals are a C++17 feature">, InGroup<CXX17>;
def warn_cxx1z_hex_literal : Warning<
"hexadecimal floating literals are incompatible with "
- "C++ standards before C++1z">,
+ "C++ standards before C++17">,
InGroup<CXXPre1zCompatPedantic>, DefaultIgnore;
def ext_binary_literal : Extension<
"binary integer literals are a GNU extension">, InGroup<GNUBinaryLiteral>;
@@ -208,7 +208,7 @@ def warn_cxx98_compat_unicode_literal : Warning<
"unicode literals are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx14_compat_u8_character_literal : Warning<
- "unicode literals are incompatible with C++ standards before C++1z">,
+ "unicode literals are incompatible with C++ standards before C++17">,
InGroup<CXXPre1zCompat>, DefaultIgnore;
def warn_cxx11_compat_user_defined_literal : Warning<
"identifier after literal will be treated as a user-defined literal suffix "
@@ -242,6 +242,7 @@ def warn_bad_character_encoding : ExtWarn<
"illegal character encoding in character literal">,
InGroup<InvalidSourceEncoding>;
def err_lexing_string : Error<"failure when lexing a string">;
+def err_placeholder_in_source : Error<"editor placeholder in source file">;
//===----------------------------------------------------------------------===//
@@ -502,12 +503,34 @@ def warn_pragma_diagnostic_invalid_token :
InGroup<UnknownPragmas>;
def warn_pragma_diagnostic_unknown_warning :
ExtWarn<"unknown warning group '%0', ignored">,
- InGroup<UnknownPragmas>;
+ InGroup<UnknownWarningOption>;
// - #pragma __debug
def warn_pragma_debug_unexpected_command : Warning<
"unexpected debug command '%0'">, InGroup<IgnoredPragmas>;
def warn_pragma_debug_missing_argument : Warning<
"missing argument to debug command '%0'">, InGroup<IgnoredPragmas>;
+// #pragma module
+def err_pp_expected_module_name : Error<
+ "expected %select{identifier after '.' in |}0module name">;
+def err_pp_module_begin_wrong_module : Error<
+ "must specify '-fmodule-name=%0' to enter %select{|submodule of }1"
+ "this module%select{ (current module is %3)|}2">;
+def err_pp_module_begin_no_module_map : Error<
+ "no module map available for module %0">;
+def err_pp_module_begin_no_submodule : Error<
+ "submodule %0.%1 not declared in module map">;
+def err_pp_module_begin_without_module_end : Error<
+ "no matching '#pragma clang module end' for this "
+ "'#pragma clang module begin'">;
+def err_pp_module_end_without_module_begin : Error<
+ "no matching '#pragma clang module begin' for this "
+ "'#pragma clang module end'">;
+def note_pp_module_begin_here : Note<
+ "entering module '%0' due to this pragma">;
+def err_pp_module_build_pth : Error<
+ "'#pragma clang module build' not supported in pretokenized header">;
+def err_pp_module_build_missing_end : Error<
+ "no matching '#pragma clang module endbuild' for this '#pragma clang module build'">;
def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
def err_paste_at_start : Error<
@@ -594,8 +617,6 @@ def err_mmap_expected_mmap_file : Error<"expected a module map file name">;
def err_mmap_module_redefinition : Error<
"redefinition of module '%0'">;
def note_mmap_prev_definition : Note<"previously defined here">;
-def err_mmap_umbrella_dir_not_found : Error<
- "umbrella directory '%0' not found">;
def err_mmap_umbrella_clash : Error<
"umbrella for module '%0' already covers this directory">;
def err_mmap_module_id : Error<
@@ -647,6 +668,12 @@ def warn_mmap_mismatched_top_level_private : Warning<
InGroup<PrivateModule>;
def note_mmap_rename_top_level_private_as_submodule : Note<
"make '%0' a submodule of '%1' to ensure it can be found by name">;
+def err_mmap_duplicate_header_attribute : Error<
+ "header attribute '%0' specified multiple times">;
+def err_mmap_invalid_header_attribute_value : Error<
+ "expected integer literal as value for header attribute '%0'">;
+def err_mmap_expected_header_attribute : Error<
+ "expected a header attribute name ('size' or 'mtime')">;
def warn_auto_module_import : Warning<
"treating #%select{include|import|include_next|__include_macros}0 as an "
@@ -656,6 +683,9 @@ def note_implicit_top_level_module_import_here : Note<
def warn_uncovered_module_header : Warning<
"umbrella header for module '%0' does not include header '%1'">,
InGroup<IncompleteUmbrella>;
+def warn_mmap_umbrella_dir_not_found : Warning<
+ "umbrella directory '%0' not found">,
+ InGroup<IncompleteUmbrella>;
def err_expected_id_building_module : Error<
"expected a module name in '__building_module' expression">;
def warn_use_of_private_header_outside_module : Warning<
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.def b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.def
index 0ab6724..2467b24 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.def
@@ -87,6 +87,8 @@ VALUE_DIAGOPT(TemplateBacktraceLimit, 32, DefaultTemplateBacktraceLimit)
VALUE_DIAGOPT(ConstexprBacktraceLimit, 32, DefaultConstexprBacktraceLimit)
/// Limit number of times to perform spell checking.
VALUE_DIAGOPT(SpellCheckingLimit, 32, DefaultSpellCheckingLimit)
+/// Limit number of lines shown in a snippet.
+VALUE_DIAGOPT(SnippetLineLimit, 32, DefaultSnippetLineLimit)
VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops.
/// Column limit for formatting message diagnostics, or 0 if unused.
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h
index c9b0c5d..c195003 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticOptions.h
@@ -63,11 +63,15 @@ public:
enum TextDiagnosticFormat { Clang, MSVC, Vi };
// Default values.
- enum { DefaultTabStop = 8, MaxTabStop = 100,
+ enum {
+ DefaultTabStop = 8,
+ MaxTabStop = 100,
DefaultMacroBacktraceLimit = 6,
DefaultTemplateBacktraceLimit = 10,
DefaultConstexprBacktraceLimit = 10,
- DefaultSpellCheckingLimit = 50 };
+ DefaultSpellCheckingLimit = 50,
+ DefaultSnippetLineLimit = 1,
+ };
// Define simple diagnostic options (with no accessors).
#define DIAGOPT(Name, Bits, Default) unsigned Name : Bits;
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td
index 0943fea..5170c07 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -176,6 +176,9 @@ def warn_gcc_attribute_location : Warning<
def warn_attribute_no_decl : Warning<
"attribute %0 ignored, because it is not attached to a declaration">,
InGroup<IgnoredAttributes>;
+def err_ms_attributes_not_enabled : Error<
+ "'__declspec' attributes are not enabled; use '-fdeclspec' or "
+ "'-fms-extensions' to enable support for __declspec attributes">;
def err_expected_method_body : Error<"expected method body">;
def err_declspec_after_virtspec : Error<
"'%0' qualifier may not appear after the virtual specifier '%1'">;
@@ -208,10 +211,10 @@ def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
def err_namespace_nonnamespace_scope : Error<
"namespaces can only be defined in global or namespace scope">;
def ext_nested_namespace_definition : ExtWarn<
- "nested namespace definition is a C++1z extension; "
- "define each namespace separately">, InGroup<CXX1z>;
+ "nested namespace definition is a C++17 extension; "
+ "define each namespace separately">, InGroup<CXX17>;
def warn_cxx14_compat_nested_namespace_definition : Warning<
- "nested namespace definition is incompatible with C++ standards before C++1z">,
+ "nested namespace definition is incompatible with C++ standards before C++17">,
InGroup<CXXPre1zCompat>, DefaultIgnore;
def err_inline_nested_namespace_definition : Error<
"nested namespace definition cannot be 'inline'">;
@@ -355,14 +358,12 @@ def err_expected_coloncolon_after_super : Error<
"expected '::' after '__super'">;
def ext_decomp_decl_empty : ExtWarn<
- "ISO C++1z does not allow a decomposition group to be empty">,
+ "ISO C++17 does not allow a decomposition group to be empty">,
InGroup<DiagGroup<"empty-decomposition">>;
/// Objective-C parser diagnostics
def err_expected_minus_or_plus : Error<
"method type specifier must start with '-' or '+'">;
-def err_objc_no_attributes_on_category : Error<
- "attributes may not be specified on a category">;
def err_objc_missing_end : Error<"missing '@end'">;
def note_objc_container_start : Note<
"%select{class|protocol|category|class extension|implementation"
@@ -435,6 +436,13 @@ def err_declaration_does_not_declare_param : Error<
"declaration does not declare a parameter">;
def err_no_matching_param : Error<"parameter named %0 is missing">;
+/// Objective-C++ parser diagnostics
+def err_expected_token_instead_of_objcxx_keyword : Error<
+ "expected %0; %1 is a keyword in Objective-C++">;
+def err_expected_member_name_or_semi_objcxx_keyword : Error<
+ "expected member name or ';' after declaration specifiers; "
+ "%0 is a keyword in Objective-C++">;
+
/// C++ parser diagnostics
def err_invalid_operator_on_type : Error<
"cannot use %select{dot|arrow}0 operator on a type">;
@@ -514,16 +522,16 @@ def err_function_is_not_record : Error<
def err_super_in_using_declaration : Error<
"'__super' cannot be used with a using declaration">;
def ext_constexpr_if : ExtWarn<
- "constexpr if is a C++1z extension">, InGroup<CXX1z>;
+ "constexpr if is a C++17 extension">, InGroup<CXX17>;
def warn_cxx14_compat_constexpr_if : Warning<
- "constexpr if is incompatible with C++ standards before C++1z">,
+ "constexpr if is incompatible with C++ standards before C++17">,
DefaultIgnore, InGroup<CXXPre1zCompat>;
def ext_init_statement : ExtWarn<
- "'%select{if|switch}0' initialization statements are a C++1z extension">,
- InGroup<CXX1z>;
+ "'%select{if|switch}0' initialization statements are a C++17 extension">,
+ InGroup<CXX17>;
def warn_cxx14_compat_init_statement : Warning<
"%select{if|switch}0 initialization statements are incompatible with "
- "C++ standards before C++1z">, DefaultIgnore, InGroup<CXXPre1zCompat>;
+ "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre1zCompat>;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
@@ -552,7 +560,7 @@ def warn_cxx98_compat_nullptr : Warning<
def warn_cxx14_compat_attribute : Warning<
"attributes on %select{a namespace|an enumerator}0 declaration are "
- "incompatible with C++ standards before C++1z">,
+ "incompatible with C++ standards before C++17">,
InGroup<CXXPre1zCompat>, DefaultIgnore;
def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
@@ -569,10 +577,10 @@ def err_cxx11_attribute_repeated : Error<
"attribute %0 cannot appear multiple times in an attribute specifier">;
def warn_cxx14_compat_using_attribute_ns : Warning<
"default scope specifier for attributes is incompatible with C++ standards "
- "before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "before C++17">, InGroup<CXXPre1zCompat>, DefaultIgnore;
def ext_using_attribute_ns : ExtWarn<
- "default scope specifier for attributes is a C++1z extension">,
- InGroup<CXX1z>;
+ "default scope specifier for attributes is a C++17 extension">,
+ InGroup<CXX17>;
def err_using_attribute_ns_conflict : Error<
"attribute with scope specifier cannot follow default scope specifier">;
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
@@ -609,11 +617,11 @@ def err_expected_comma_greater : Error<
def err_class_on_template_template_param : Error<
"template template parameter requires 'class' after the parameter list">;
def ext_template_template_param_typename : ExtWarn<
- "template template parameter using 'typename' is a C++1z extension">,
- InGroup<CXX1z>;
+ "template template parameter using 'typename' is a C++17 extension">,
+ InGroup<CXX17>;
def warn_cxx14_compat_template_template_param_typename : Warning<
"template template parameter using 'typename' is "
- "incompatible with C++ standards before C++1z">,
+ "incompatible with C++ standards before C++17">,
InGroup<CXXPre1zCompat>, DefaultIgnore;
def err_template_spec_syntax_non_template : Error<
"identifier followed by '<' indicates a class template specialization but "
@@ -669,9 +677,6 @@ def warn_static_inline_explicit_inst_ignored : Warning<
// Constructor template diagnostics.
def err_out_of_line_constructor_template_id : Error<
"out-of-line constructor for %0 cannot have template arguments">;
-def err_out_of_line_template_id_type_names_constructor : Error<
- "qualified reference to %0 is a constructor name rather than a "
- "%select{template name|type}1 wherever a constructor can be declared">;
def err_expected_qualified_after_typename : Error<
"expected a qualified name after 'typename'">;
@@ -690,10 +695,10 @@ def err_default_template_template_parameter_not_template : Error<
"template">;
def ext_fold_expression : ExtWarn<
- "pack fold expression is a C++1z extension">,
- InGroup<CXX1z>;
+ "pack fold expression is a C++17 extension">,
+ InGroup<CXX17>;
def warn_cxx14_compat_fold_expression : Warning<
- "pack fold expression is incompatible with C++ standards before C++1z">,
+ "pack fold expression is incompatible with C++ standards before C++17">,
InGroup<CXXPre1zCompat>, DefaultIgnore;
def err_expected_fold_operator : Error<
"expected a foldable binary operator in fold expression">;
@@ -746,16 +751,16 @@ def err_alias_declaration_pack_expansion : Error<
// C++1z using-declaration pack expansions
def ext_multi_using_declaration : ExtWarn<
"use of multiple declarators in a single using declaration is "
- "a C++1z extension">, InGroup<CXX1z>;
+ "a C++17 extension">, InGroup<CXX17>;
def warn_cxx1z_compat_multi_using_declaration : Warning<
"use of multiple declarators in a single using declaration is "
- "incompatible with C++ standards before C++1z">,
+ "incompatible with C++ standards before C++17">,
InGroup<CXXPre1zCompat>, DefaultIgnore;
def ext_using_declaration_pack : ExtWarn<
- "pack expansion of using declaration is a C++1z extension">, InGroup<CXX1z>;
+ "pack expansion of using declaration is a C++17 extension">, InGroup<CXX17>;
def warn_cxx1z_compat_using_declaration_pack : Warning<
"pack expansion using declaration is incompatible with C++ standards "
- "before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "before C++17">, InGroup<CXXPre1zCompat>, DefaultIgnore;
// C++11 override control
def ext_override_control_keyword : ExtWarn<
@@ -812,10 +817,10 @@ def err_expected_star_this_capture : Error<
// C++1z constexpr lambda expressions
def warn_cxx14_compat_constexpr_on_lambda : Warning<
- "constexpr on lambda expressions is incompatible with C++ standards before C++1z">,
+ "constexpr on lambda expressions is incompatible with C++ standards before C++17">,
InGroup<CXXPre1zCompat>, DefaultIgnore;
def ext_constexpr_on_lambda_cxx1z : ExtWarn<
- "'constexpr' on lambda expressions is a C++1z extension">, InGroup<CXX1z>;
+ "'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>;
// Availability attribute
def err_expected_version : Error<
@@ -859,6 +864,12 @@ def err_availability_query_repeated_platform: Error<
def err_availability_query_repeated_star : Error<
"'*' query has already been specified">;
+// External source symbol attribute
+def err_external_source_symbol_expected_keyword : Error<
+ "expected 'language', 'defined_in', or 'generated_declaration'">;
+def err_external_source_symbol_duplicate_clause : Error<
+ "duplicate %0 clause in an 'external_source_symbol' attribute">;
+
// Type safety attributes
def err_type_safety_unknown_flag : Error<
"invalid comparison flag %0; use 'layout_compatible' or 'must_be_null'">;
@@ -876,9 +887,18 @@ def warn_pragma_expected_rparen : Warning<
"missing ')' after '#pragma %0' - ignoring">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_identifier : Warning<
"expected identifier in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>;
+
+// '#pragma clang section' related errors
+def err_pragma_expected_clang_section_name : Error<
+ "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">;
+def err_pragma_clang_section_expected_equal : Error<
+ "expected '=' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">;
+def err_pragma_clang_section_expected_name_or_clear : Error<
+ "expected section name or '\"\"' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">;
def warn_pragma_expected_section_name : Warning<
"expected a string literal for the section name in '#pragma %0' - ignored">,
InGroup<IgnoredPragmas>;
+
def warn_pragma_expected_section_push_pop_or_name : Warning<
"expected push, pop or a string literal for the section name in '#pragma %0' - ignored">,
InGroup<IgnoredPragmas>;
@@ -968,6 +988,43 @@ def err_pragma_optimize_invalid_argument : Error<
"expected 'on' or 'off'">;
def err_pragma_optimize_extra_argument : Error<
"unexpected extra argument '%0' to '#pragma clang optimize'">;
+// - #pragma clang attribute
+def err_pragma_attribute_expected_push_pop : Error<
+ "expected 'push' or 'pop' after '#pragma clang attribute'">;
+def err_pragma_attribute_invalid_argument : Error<
+ "unexpected argument '%0' to '#pragma clang attribute'; "
+ "expected 'push' or 'pop'">;
+def err_pragma_attribute_expected_attribute : Error<
+ "expected an attribute after '('">;
+def err_pragma_attribute_expected_attribute_name : Error<
+ "expected identifier that represents an attribute name">;
+def err_pragma_attribute_extra_tokens_after_attribute : Error<
+ "extra tokens after attribute in a '#pragma clang attribute push'">;
+def err_pragma_attribute_unsupported_attribute : Error<
+ "attribute %0 is not supported by '#pragma clang attribute'">;
+def err_pragma_attribute_multiple_attributes : Error<
+ "more than one attribute specified in '#pragma clang attribute push'">;
+def err_pragma_attribute_expected_attribute_syntax : Error<
+ "expected an attribute that is specified using the GNU, C++11 or '__declspec'"
+ " syntax">;
+def note_pragma_attribute_use_attribute_kw : Note<"use the GNU '__attribute__' "
+ "syntax">;
+def err_pragma_attribute_invalid_subject_set_specifier : Error<
+ "expected attribute subject set specifier 'apply_to'">;
+def err_pragma_attribute_expected_subject_identifier : Error<
+ "expected an identifier that corresponds to an attribute subject rule">;
+def err_pragma_attribute_unknown_subject_rule : Error<
+ "unknown attribute subject rule '%0'">;
+def err_pragma_attribute_expected_subject_sub_identifier : Error<
+ "expected an identifier that corresponds to an attribute subject matcher "
+ "sub-rule; '%0' matcher %select{does not support sub-rules|supports the "
+ "following sub-rules: %2|}1">;
+def err_pragma_attribute_unknown_subject_sub_rule : Error<
+ "%select{invalid use of|unknown}2 attribute subject matcher sub-rule '%0'; "
+ "'%1' matcher %select{does not support sub-rules|supports the following "
+ "sub-rules: %3}2">;
+def err_pragma_attribute_duplicate_subject : Error<
+ "duplicate attribute subject matcher '%0'">;
def err_opencl_unroll_hint_on_non_loop : Error<
"OpenCL only supports 'opencl_unroll_hint' attribute on for, while, and do statements">;
@@ -1036,6 +1093,16 @@ def err_pragma_loop_missing_argument : Error<
def err_pragma_loop_invalid_option : Error<
"%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
"vectorize_width, interleave, interleave_count, unroll, unroll_count, or distribute">;
+
+def err_pragma_fp_invalid_option : Error<
+ "%select{invalid|missing}0 option%select{ %1|}0; expected contract">;
+def err_pragma_fp_invalid_argument : Error<
+ "unexpected argument '%0' to '#pragma clang fp %1'; "
+ "expected 'on', 'fast' or 'off'">;
+def err_pragma_fp_scope : Error<
+ "'#pragma clang fp' can only appear at file scope or at the start of a "
+ "compound statement">;
+
def err_pragma_invalid_keyword : Error<
"invalid argument; expected 'enable'%select{|, 'full'}0%select{|, 'assume_safety'}1 or 'disable'">;
@@ -1056,14 +1123,12 @@ def err_pragma_cannot_end_force_cuda_host_device : Error<
} // end of Parse Issue category.
let CategoryName = "Modules Issue" in {
-def err_expected_module_interface_decl : Error<
- "expected module declaration at start of module interface">;
def err_unexpected_module_decl : Error<
- "module declaration must be the first declaration in the translation unit">;
+ "module declaration can only appear at the top level">;
def err_module_expected_ident : Error<
- "expected a module name after module%select{| import}0">;
-def err_unexpected_module_kind : Error<
- "unexpected module kind %0; expected 'implementation' or 'partition'">;
+ "expected a module name after '%select{module|import}0'">;
+def err_module_implementation_partition : Error<
+ "module partition must be declared 'export'">;
def err_attribute_not_module_attr : Error<
"%0 attribute cannot be applied to a module">;
def err_attribute_not_import_attr : Error<
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c934351..6456913 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -211,9 +211,9 @@ def warn_auto_storage_class : Warning<
def warn_deprecated_register : Warning<
"'register' storage class specifier is deprecated "
- "and incompatible with C++1z">, InGroup<DeprecatedRegister>;
+ "and incompatible with C++17">, InGroup<DeprecatedRegister>;
def ext_register_storage_class : ExtWarn<
- "ISO C++1z does not allow 'register' storage class specifier">,
+ "ISO C++17 does not allow 'register' storage class specifier">,
DefaultError, InGroup<Register>;
def err_invalid_decl_spec_combination : Error<
@@ -259,6 +259,9 @@ def err_anyx86_interrupt_attribute : Error<
"a pointer as the first parameter|a %2 type as the second parameter}1">;
def err_anyx86_interrupt_called : Error<
"interrupt service routine cannot be called directly">;
+def warn_arm_interrupt_calling_convention : Warning<
+ "call to function without interrupt attribute could clobber interruptee's VFP registers">,
+ InGroup<Extra>;
def warn_mips_interrupt_attribute : Warning<
"MIPS 'interrupt' attribute only applies to functions that have "
"%select{no parameters|a 'void' return type}0">,
@@ -300,6 +303,8 @@ def note_empty_parens_zero_initialize : Note<
"replace parentheses with an initializer to declare a variable">;
def warn_unused_function : Warning<"unused function %0">,
InGroup<UnusedFunction>, DefaultIgnore;
+def warn_unused_template : Warning<"unused %select{function|variable}0 template %1">,
+ InGroup<UnusedTemplate>, DefaultIgnore;
def warn_unused_member_function : Warning<"unused member function %0">,
InGroup<UnusedMemberFunction>, DefaultIgnore;
def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">,
@@ -316,6 +321,9 @@ def warn_unneeded_member_function : Warning<
InGroup<UnneededMemberFunction>, DefaultIgnore;
def warn_unused_private_field: Warning<"private field %0 is not used">,
InGroup<UnusedPrivateField>, DefaultIgnore;
+def warn_unused_lambda_capture: Warning<"lambda capture %0 is not "
+ "%select{used|required to be captured for this use}1">,
+ InGroup<UnusedLambdaCapture>, DefaultIgnore;
def warn_parameter_size: Warning<
"%0 is a large (%1 bytes) pass-by-value argument; "
@@ -363,7 +371,9 @@ def warn_decl_shadow :
"local variable|"
"variable in %2|"
"static data member of %2|"
- "field of %2}1">,
+ "field of %2|"
+ "typedef in %2|"
+ "type alias in %2}1">,
InGroup<Shadow>, DefaultIgnore;
def warn_decl_shadow_uncaptured_local :
Warning<warn_decl_shadow.Text>,
@@ -381,9 +391,9 @@ def err_decomp_decl_context : Error<
"decomposition declaration not permitted in this context">;
def warn_cxx14_compat_decomp_decl : Warning<
"decomposition declarations are incompatible with "
- "C++ standards before C++1z">, DefaultIgnore, InGroup<CXXPre1zCompat>;
+ "C++ standards before C++17">, DefaultIgnore, InGroup<CXXPre1zCompat>;
def ext_decomp_decl : ExtWarn<
- "decomposition declarations are a C++1z extension">, InGroup<CXX1z>;
+ "decomposition declarations are a C++17 extension">, InGroup<CXX17>;
def err_decomp_decl_spec : Error<
"decomposition declaration cannot be declared "
"%plural{1:'%1'|:with '%1' specifiers}0">;
@@ -484,7 +494,7 @@ def err_access_decl : Error<
"ISO C++11 does not allow access declarations; "
"use using declarations instead">;
def ext_dynamic_exception_spec : ExtWarn<
- "ISO C++1z does not allow dynamic exception specifications">,
+ "ISO C++17 does not allow dynamic exception specifications">,
InGroup<DynamicExceptionSpec>, DefaultError;
def warn_exception_spec_deprecated : Warning<
"dynamic exception specifications are deprecated">,
@@ -497,7 +507,7 @@ def warn_deprecated_copy_operation : Warning<
InGroup<Deprecated>, DefaultIgnore;
def warn_cxx1z_compat_exception_spec_in_signature : Warning<
"mangled name of %0 will change in C++17 due to non-throwing exception "
- "specification in function signature">, InGroup<CXX1zCompat>;
+ "specification in function signature">, InGroup<CXX17CompatMangling>;
def warn_global_constructor : Warning<
"declaration requires a global constructor">,
@@ -527,10 +537,10 @@ def err_maybe_falloff_nonvoid_block : Error<
def err_falloff_nonvoid_block : Error<
"control reaches end of non-void block">;
def warn_maybe_falloff_nonvoid_coroutine : Warning<
- "control may reach end of non-void coroutine">,
+ "control may reach end of coroutine; which is undefined behavior because the promise type %0 does not declare 'return_void()'">,
InGroup<ReturnType>;
def warn_falloff_nonvoid_coroutine : Warning<
- "control reaches end of non-void coroutine">,
+ "control reaches end of coroutine; which is undefined behavior because the promise type %0 does not declare 'return_void()'">,
InGroup<ReturnType>;
def warn_suggest_noreturn_function : Warning<
"%select{function|method}0 %1 could be declared with attribute 'noreturn'">,
@@ -722,6 +732,9 @@ def err_super_in_lambda_unsupported : Error<
def warn_pragma_unused_undeclared_var : Warning<
"undeclared variable %0 used as an argument for '#pragma unused'">,
InGroup<IgnoredPragmas>;
+def warn_atl_uuid_deprecated : Warning<
+ "specifying 'uuid' as an ATL attribute is deprecated; use __declspec instead">,
+ InGroup<DeprecatedDeclarations>;
def warn_pragma_unused_expected_var_arg : Warning<
"only variables can be arguments to '#pragma unused'">,
InGroup<IgnoredPragmas>;
@@ -742,6 +755,25 @@ def err_pragma_loop_compatibility : Error<
def err_pragma_loop_precedes_nonloop : Error<
"expected a for, while, or do-while loop to follow '%0'">;
+def err_pragma_attribute_matcher_subrule_contradicts_rule : Error<
+ "redundant attribute subject matcher sub-rule '%0'; '%1' already matches "
+ "those declarations">;
+def err_pragma_attribute_matcher_negated_subrule_contradicts_subrule : Error<
+ "negated attribute subject matcher sub-rule '%0' contradicts sub-rule '%1'">;
+def err_pragma_attribute_invalid_matchers : Error<
+ "attribute %0 can't be applied to %1">;
+def err_pragma_attribute_stack_mismatch : Error<
+ "'#pragma clang attribute pop' with no matching '#pragma clang attribute push'">;
+def warn_pragma_attribute_unused : Warning<
+ "unused attribute %0 in '#pragma clang attribute push' region">,
+ InGroup<PragmaClangAttribute>;
+def note_pragma_attribute_region_ends_here : Note<
+ "'#pragma clang attribute push' regions ends here">;
+def err_pragma_attribute_no_pop_eof : Error<"unterminated "
+ "'#pragma clang attribute push' at end of file">;
+def note_pragma_attribute_applied_decl_here : Note<
+ "when applied to this declaration">;
+
/// Objective-C parser diagnostics
def err_duplicate_class_def : Error<
"duplicate interface definition for class %0">;
@@ -776,8 +808,10 @@ def warn_property_types_are_incompatible : Warning<
"property type %0 is incompatible with type %1 inherited from %2">,
InGroup<DiagGroup<"incompatible-property-type">>;
def warn_protocol_property_mismatch : Warning<
- "property of type %0 was selected for synthesis">,
+ "property %select{of type %1|with attribute '%1'|without attribute '%1'|with "
+ "getter %1|with setter %1}0 was selected for synthesis">,
InGroup<DiagGroup<"protocol-property-synthesis-ambiguity">>;
+def err_protocol_property_mismatch: Error<warn_protocol_property_mismatch.Text>;
def err_undef_interface : Error<"cannot find interface declaration for %0">;
def err_category_forward_interface : Error<
"cannot define %select{category|class extension}0 for undefined class %1">;
@@ -997,6 +1031,8 @@ def warn_auto_synthesizing_protocol_property :Warning<
"auto property synthesis will not synthesize property %0"
" declared in protocol %1">,
InGroup<DiagGroup<"objc-protocol-property-synthesis">>;
+def note_add_synthesize_directive : Note<
+ "add a '@synthesize' directive">;
def warn_no_autosynthesis_shared_ivar_property : Warning <
"auto property synthesis will not synthesize property "
"%0 because it cannot share an ivar with another synthesized property">,
@@ -1054,7 +1090,9 @@ def err_category_property : Error<
def note_property_declare : Note<
"property declared here">;
def note_protocol_property_declare : Note<
- "it could also be property of type %0 declared here">;
+ "it could also be property "
+ "%select{of type %1|without attribute '%1'|with attribute '%1'|with getter "
+ "%1|with setter %1}0 declared here">;
def note_property_synthesize : Note<
"property synthesized here">;
def err_synthesize_category_decl : Error<
@@ -1153,20 +1191,24 @@ def err_objc_kindof_nonobject : Error<
def err_objc_kindof_wrong_position : Error<
"'__kindof' type specifier must precede the declarator">;
+def err_objc_method_unsupported_param_ret_type : Error<
+ "%0 %select{parameter|return}1 type is unsupported; "
+ "support for vector types for this target is introduced in %2">;
+
// C++ declarations
def err_static_assert_expression_is_not_constant : Error<
"static_assert expression is not an integral constant expression">;
def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">;
def ext_static_assert_no_message : ExtWarn<
- "static_assert with no message is a C++1z extension">, InGroup<CXX1z>;
+ "static_assert with no message is a C++17 extension">, InGroup<CXX17>;
def warn_cxx14_compat_static_assert_no_message : Warning<
- "static_assert with no message is incompatible with C++ standards before C++1z">,
+ "static_assert with no message is incompatible with C++ standards before C++17">,
DefaultIgnore, InGroup<CXXPre1zCompat>;
def ext_inline_variable : ExtWarn<
- "inline variables are a C++1z extension">, InGroup<CXX1z>;
+ "inline variables are a C++17 extension">, InGroup<CXX17>;
def warn_cxx14_compat_inline_variable : Warning<
- "inline variables are incompatible with C++ standards before C++1z">,
+ "inline variables are incompatible with C++ standards before C++17">,
DefaultIgnore, InGroup<CXXPre1zCompat>;
def warn_inline_namespace_reopened_noninline : Warning<
@@ -1201,8 +1243,9 @@ def warn_cxx98_compat_unelaborated_friend_type : Warning<
def err_qualified_friend_not_found : Error<
"no function named %0 with type %1 was found in the specified scope">;
def err_introducing_special_friend : Error<
- "must use a qualified name when declaring a %select{constructor|"
- "destructor|conversion operator}0 as a friend">;
+ "%plural{[0,2]:must use a qualified name when declaring|3:cannot declare}0"
+ " a %select{constructor|destructor|conversion operator|deduction guide}0 "
+ "as a friend">;
def err_tagless_friend_type_template : Error<
"friend type templates must use an elaborated type">;
def err_no_matching_local_friend : Error<
@@ -1447,6 +1490,15 @@ def err_nested_name_spec_is_not_class : Error<
def ext_nested_name_spec_is_enum : ExtWarn<
"use of enumeration in a nested name specifier is a C++11 extension">,
InGroup<CXX11>;
+def err_out_of_line_qualified_id_type_names_constructor : Error<
+ "qualified reference to %0 is a constructor name rather than a "
+ "%select{template name|type}1 in this context">;
+def ext_out_of_line_qualified_id_type_names_constructor : ExtWarn<
+ "ISO C++ specifies that "
+ "qualified reference to %0 is a constructor name rather than a "
+ "%select{template name|type}1 in this context, despite preceding "
+ "%select{'typename'|'template'}2 keyword">, SFINAEFailure,
+ InGroup<DiagGroup<"injected-class-name">>;
// C++ class members
def err_storageclass_invalid_for_member : Error<
@@ -1508,11 +1560,9 @@ def note_ivar_decl : Note<"instance variable is declared here">;
def note_bitfield_decl : Note<"bit-field is declared here">;
def note_implicit_param_decl : Note<"%0 is an implicit parameter">;
def note_member_synthesized_at : Note<
- "implicit %select{default constructor|copy constructor|move constructor|copy "
- "assignment operator|move assignment operator|destructor}0 for %1 first "
- "required here">;
-def note_inhctor_synthesized_at : Note<
- "inherited constructor for %0 first required here">;
+ "in implicit %select{default constructor|copy constructor|move constructor|"
+ "copy assignment operator|move assignment operator|destructor}0 for %1 "
+ "first required here">;
def err_missing_default_ctor : Error<
"%select{constructor for %1 must explicitly initialize the|"
"implicit default constructor for %1 must explicitly initialize the|"
@@ -1608,7 +1658,14 @@ def err_covariant_return_type_class_type_more_qualified : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (class type %1 is more qualified than class "
"type %2">;
-
+
+// C++ implicit special member functions
+def note_in_declaration_of_implicit_special_member : Note<
+ "while declaring the implicit "
+ "%select{default constructor|copy constructor|move constructor|"
+ "copy assignment operator|move assignment operator|destructor}1"
+ " for %0">;
+
// C++ constructors
def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
def err_invalid_qualified_constructor : Error<
@@ -1664,8 +1721,8 @@ def err_init_conversion_failed : Error<
"cannot initialize %select{a variable|a parameter|return object|an "
"exception object|a member subobject|an array element|a new value|a value|a "
"base class|a constructor delegation|a vector element|a block element|a "
- "complex element|a lambda capture|a compound literal initializer|a "
- "related result|a parameter of CF audited function}0 "
+ "block element|a complex element|a lambda capture|a compound literal "
+ "initializer|a related result|a parameter of CF audited function}0 "
"%diff{of type $ with an %select{rvalue|lvalue}2 of type $|"
"with an %select{rvalue|lvalue}2 of incompatible type}1,3"
"%select{|: different classes%diff{ ($ vs $)|}5,6"
@@ -1791,8 +1848,9 @@ def note_uninit_fixit_remove_cond : Note<
"remove the %select{'%1' if its condition|condition if it}0 "
"is always %select{false|true}2">;
def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
-def err_list_init_in_parens : Error<"list-initializer for non-class type %0 "
- "must not be parenthesized">;
+def err_list_init_in_parens : Error<
+ "cannot initialize %select{non-class|reference}0 type %1 with a "
+ "parenthesized initializer list">;
def warn_unsequenced_mod_mod : Warning<
"multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
@@ -1833,8 +1891,8 @@ def warn_cxx98_compat_temp_copy : Warning<
InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore;
def err_selected_explicit_constructor : Error<
"chosen constructor is explicit in copy-initialization">;
-def note_constructor_declared_here : Note<
- "constructor declared here">;
+def note_explicit_ctor_deduction_guide_here : Note<
+ "explicit %select{constructor|deduction guide}0 declared here">;
// C++11 decltype
def err_decltype_in_declarator : Error<
@@ -1845,8 +1903,8 @@ def warn_cxx98_compat_auto_type_specifier : Warning<
"'auto' type specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_auto_variable_cannot_appear_in_own_initializer : Error<
- "variable %0 declared with %select{'auto'|'decltype(auto)'|'__auto_type'}1 "
- "type cannot appear in its own initializer">;
+ "variable %0 declared with deduced type %1 "
+ "cannot appear in its own initializer">;
def err_binding_cannot_appear_in_own_initializer : Error<
"binding %0 cannot appear in the initializer of its own "
"decomposition declaration">;
@@ -1855,20 +1913,29 @@ def err_illegal_decl_array_of_auto : Error<
def err_new_array_of_auto : Error<
"cannot allocate array of 'auto'">;
def err_auto_not_allowed : Error<
- "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed "
+ "%select{'auto'|'decltype(auto)'|'__auto_type'|"
+ "use of "
+ "%select{class template|function template|variable template|alias template|"
+ "template template parameter|template}2 %3 requires template arguments; "
+ "argument deduction}0 not allowed "
"%select{in function prototype"
"|in non-static struct member|in struct member"
"|in non-static union member|in union member"
"|in non-static class member|in interface member"
- "|in exception declaration|in template parameter|in block literal"
+ "|in exception declaration|in template parameter until C++17|in block literal"
"|in template argument|in typedef|in type alias|in function return type"
"|in conversion function type|here|in lambda parameter"
- "|in type allocated by 'new'|in K&R-style function parameter}1"
- "%select{|||||||| until C++1z||||||||||}1">;
+ "|in type allocated by 'new'|in K&R-style function parameter"
+ "|in template parameter|in friend declaration}1">;
+def err_dependent_deduced_tst : Error<
+ "typename specifier refers to "
+ "%select{class template|function template|variable template|alias template|"
+ "template template parameter|template}0 member in %1; "
+ "argument deduction not allowed here">;
def err_auto_not_allowed_var_inst : Error<
"'auto' variable template instantiation is not allowed">;
def err_auto_var_requires_init : Error<
- "declaration of variable %0 with type %1 requires an initializer">;
+ "declaration of variable %0 with deduced type %1 requires an initializer">;
def err_auto_new_requires_ctor_arg : Error<
"new expression for type %0 requires a constructor argument">;
def err_auto_new_list_init : Error<
@@ -1898,8 +1965,13 @@ def err_auto_var_deduction_failure_from_init_list : Error<
def err_auto_new_deduction_failure : Error<
"new expression for type %0 has incompatible constructor argument of type %1">;
def err_auto_different_deductions : Error<
- "'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration "
- "of %2 and deduced as %3 in declaration of %4">;
+ "%select{'auto'|'decltype(auto)'|'__auto_type'|template arguments}0 "
+ "deduced as %1 in declaration of %2 and "
+ "deduced as %3 in declaration of %4">;
+def err_auto_non_deduced_not_alone : Error<
+ "%select{function with deduced return type|"
+ "declaration with trailing return type}0 "
+ "must be the only declaration in its group">;
def err_implied_std_initializer_list_not_found : Error<
"cannot deduce type of initializer list because std::initializer_list was "
"not found; include <initializer_list>">;
@@ -1915,6 +1987,8 @@ def err_auto_bitfield : Error<
"cannot pass bit-field as __auto_type initializer in C">;
// C++1y decltype(auto) type
+def err_decltype_auto_invalid : Error<
+ "'decltype(auto)' not allowed here">;
def err_decltype_auto_cannot_be_combined : Error<
"'decltype(auto)' cannot be combined with other type specifiers">;
def err_decltype_auto_function_declarator_not_declaration : Error<
@@ -1925,6 +1999,56 @@ def err_decltype_auto_compound_type : Error<
def err_decltype_auto_initializer_list : Error<
"cannot deduce 'decltype(auto)' from initializer list">;
+// C++1z deduced class template specialization types
+def err_deduced_class_template_compound_type : Error<
+ "cannot %select{form pointer to|form reference to|form array of|"
+ "form function returning|use parentheses when declaring variable with}0 "
+ "deduced class template specialization type">;
+def err_deduced_non_class_template_specialization_type : Error<
+ "%select{<error>|function template|variable template|alias template|"
+ "template template parameter|template}0 %1 requires template arguments; "
+ "argument deduction only allowed for class templates">;
+def err_deduced_class_template_ctor_ambiguous : Error<
+ "ambiguous deduction for template arguments of %0">;
+def err_deduced_class_template_ctor_no_viable : Error<
+ "no viable constructor or deduction guide for deduction of "
+ "template arguments of %0">;
+def err_deduced_class_template_incomplete : Error<
+ "template %0 has no definition and no %select{|viable }1deduction guides "
+ "for deduction of template arguments">;
+def err_deduced_class_template_deleted : Error<
+ "class template argument deduction for %0 selected a deleted constructor">;
+def err_deduced_class_template_explicit : Error<
+ "class template argument deduction for %0 selected an explicit "
+ "%select{constructor|deduction guide}1 for copy-list-initialization">;
+def err_deduction_guide_no_trailing_return_type : Error<
+ "deduction guide declaration without trailing return type">;
+def err_deduction_guide_bad_trailing_return_type : Error<
+ "deduced type %1 of deduction guide is not %select{|written as }2"
+ "a specialization of template %0">;
+def err_deduction_guide_with_complex_decl : Error<
+ "cannot specify any part of a return type in the "
+ "declaration of a deduction guide">;
+def err_deduction_guide_invalid_specifier : Error<
+ "deduction guide cannot be declared '%0'">;
+def err_deduction_guide_name_not_class_template : Error<
+ "cannot specify deduction guide for "
+ "%select{<error>|function template|variable template|alias template|"
+ "template template parameter|dependent template name}0 %1">;
+def err_deduction_guide_wrong_scope : Error<
+ "deduction guide must be declared in the same scope as template %q0">;
+def err_deduction_guide_defines_function : Error<
+ "deduction guide cannot have a function definition">;
+def err_deduction_guide_explicit_mismatch : Error<
+ "deduction guide is %select{not |}0declared 'explicit' but "
+ "previous declaration was%select{ not|}0">;
+def err_deduction_guide_specialized : Error<"deduction guide cannot be "
+ "%select{explicitly instantiated|explicitly specialized}0">;
+def err_deduction_guide_template_not_deducible : Error<
+ "deduction guide template contains "
+ "%select{a template parameter|template parameters}0 that cannot be "
+ "deduced">;
+
// C++1y deduced return types
def err_auto_fn_deduction_failure : Error<
"cannot deduce return type %0 from returned value of type %1">;
@@ -1950,6 +2074,9 @@ def override_keyword_hides_virtual_member_function : Error<
"%select{function|functions}1">;
def err_function_marked_override_not_overriding : Error<
"%0 marked 'override' but does not override any member functions">;
+def warn_destructor_marked_not_override_overriding : Warning <
+ "%0 overrides a destructor but is not marked 'override'">,
+ InGroup<CXX11WarnOverrideDestructor>, DefaultIgnore;
def warn_function_marked_not_override_overriding : Warning <
"%0 overrides a member function but is not marked 'override'">,
InGroup<CXX11WarnOverrideMethod>;
@@ -1970,7 +2097,7 @@ def err_enum_invalid_underlying : Error<
"non-integral type %0 is an invalid underlying type">;
def err_enumerator_too_large : Error<
"enumerator value is not representable in the underlying type %0">;
-def ext_enumerator_too_large : ExtWarn<
+def ext_enumerator_too_large : Extension<
"enumerator value is not representable in the underlying type %0">,
InGroup<MicrosoftEnumValue>;
def err_enumerator_wrapped : Error<
@@ -2020,11 +2147,11 @@ def err_for_range_iter_deduction_failure : Error<
def err_for_range_member_begin_end_mismatch : Error<
"range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">;
def ext_for_range_begin_end_types_differ : ExtWarn<
- "'begin' and 'end' returning different types (%0 and %1) is a C++1z extension">,
- InGroup<CXX1z>;
+ "'begin' and 'end' returning different types (%0 and %1) is a C++17 extension">,
+ InGroup<CXX17>;
def warn_for_range_begin_end_types_differ : Warning<
"'begin' and 'end' returning different types (%0 and %1) is incompatible "
- "with C++ standards before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore;
+ "with C++ standards before C++17">, InGroup<CXXPre1zCompat>, DefaultIgnore;
def note_in_for_range: Note<
"when looking up '%select{begin|end}0' function for range expression "
"of type %1">;
@@ -2215,6 +2342,9 @@ def err_concept_specialized : Error<
"%select{function|variable}0 concept cannot be "
"%select{explicitly instantiated|explicitly specialized|partially specialized}1">;
+def err_template_different_associated_constraints : Error<
+ "associated constraints differ in template redeclaration">;
+
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
"'%0' type specifier is incompatible with C++98">,
@@ -2261,7 +2391,7 @@ def warn_unsupported_target_attribute
InGroup<IgnoredAttributes>;
def err_attribute_unsupported
: Error<"%0 attribute is not supported for this target">;
-// The err_*_attribute_argument_not_int are seperate because they're used by
+// The err_*_attribute_argument_not_int are separate because they're used by
// VerifyIntegerConstantExpression.
def err_aligned_attribute_argument_not_int : Error<
"'aligned' attribute requires integer constant">;
@@ -2339,6 +2469,9 @@ def err_attribute_invalid_size : Error<
"vector size not an integral multiple of component size">;
def err_attribute_zero_size : Error<"zero vector size">;
def err_attribute_size_too_large : Error<"vector size too large">;
+def err_typecheck_vector_not_convertable_implict_truncation : Error<
+ "cannot convert between %select{scalar|vector}0 type %1 and vector type"
+ " %2 as implicit conversion would cause truncation">;
def err_typecheck_vector_not_convertable : Error<
"cannot convert between vector values of different size (%0 and %1)">;
def err_typecheck_vector_not_convertable_non_scalar : Error<
@@ -2361,7 +2494,7 @@ def err_attribute_address_multiple_qualifiers : Error<
def err_attribute_address_function_type : Error<
"function type may not be qualified with an address space">;
def err_as_qualified_auto_decl : Error<
- "automatic variable qualified with an address space">;
+ "automatic variable qualified with an%select{| invalid}0 address space">;
def err_arg_with_address_space : Error<
"parameter may not be qualified with an address space">;
def err_field_with_address_space : Error<
@@ -2640,6 +2773,7 @@ def warn_attribute_wrong_decl_type : Warning<
"|types and namespaces"
"|Objective-C interfaces"
"|methods and properties"
+ "|functions, methods, and properties"
"|struct or union"
"|struct, union or class"
"|types"
@@ -2659,7 +2793,8 @@ def warn_attribute_wrong_decl_type : Warning<
"|functions, methods, enums, and classes"
"|structs, classes, variables, functions, and inline namespaces"
"|variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members"
- "|classes and enumerations}1">,
+ "|classes and enumerations"
+ "|named declarations}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
def warn_type_attribute_wrong_type : Warning<
@@ -2698,9 +2833,9 @@ def warn_cconv_structors : Warning<
def err_regparm_mismatch : Error<"function declared with regparm(%0) "
"attribute was previously declared "
"%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
-def err_returns_retained_mismatch : Error<
- "function declared with the ns_returns_retained attribute "
- "was previously declared without the ns_returns_retained attribute">;
+def err_function_attribute_mismatch : Error<
+ "function declared with %0 attribute "
+ "was previously declared without the %0 attribute">;
def err_objc_precise_lifetime_bad_type : Error<
"objc_precise_lifetime only applies to retainable types; type here is %0">;
def warn_objc_precise_lifetime_meaningless : Error<
@@ -2741,17 +2876,32 @@ def note_protocol_method : Note<
def warn_unguarded_availability :
Warning<"%0 is only available on %1 %2 or newer">,
InGroup<UnguardedAvailability>, DefaultIgnore;
+def warn_unguarded_availability_new :
+ Warning<warn_unguarded_availability.Text>,
+ InGroup<UnguardedAvailabilityNew>;
def warn_partial_availability : Warning<"%0 is only available conditionally">,
InGroup<UnguardedAvailability>, DefaultIgnore;
+def warn_partial_availability_new : Warning<warn_partial_availability.Text>,
+ InGroup<UnguardedAvailabilityNew>;
def note_partial_availability_silence : Note<
- "explicitly redeclare %0 to silence this warning">;
+ "annotate %select{%1|anonymous %1}0 with an availability attribute to silence">;
def note_unguarded_available_silence : Note<
- "enclose %0 in an @available check to silence this warning">;
+ "enclose %0 in %select{an @available|a __builtin_available}1 check to silence"
+ " this warning">;
def warn_partial_message : Warning<"%0 is partial: %1">,
InGroup<UnguardedAvailability>, DefaultIgnore;
+def warn_partial_message_new : Warning<warn_partial_message.Text>,
+ InGroup<UnguardedAvailabilityNew>;
def warn_partial_fwdclass_message : Warning<
"%0 may be partial because the receiver type is unknown">,
InGroup<UnguardedAvailability>, DefaultIgnore;
+def warn_partial_fwdclass_message_new :
+ Warning<warn_partial_fwdclass_message.Text>,
+ InGroup<UnguardedAvailabilityNew>;
+def warn_at_available_unchecked_use : Warning<
+ "%select{@available|__builtin_available}0 does not guard availability here; "
+ "use if (%select{@available|__builtin_available}0) instead">,
+ InGroup<DiagGroup<"unsupported-availability-guard">>;
// Thread Safety Attributes
def warn_invalid_capability_name : Warning<
@@ -3132,7 +3282,8 @@ def err_attribute_regparm_invalid_number : Error<
"'regparm' parameter must be between 0 and %0 inclusive">;
def err_attribute_not_supported_in_lang : Error<
"%0 attribute is not supported in %select{C|C++|Objective-C}1">;
-
+def err_attribute_not_supported_on_arch
+ : Error<"%0 attribute is not supported on '%1'">;
// Clang-Specific Attributes
def warn_attribute_iboutlet : Warning<
@@ -3149,13 +3300,15 @@ def warn_iboutletcollection_property_assign : Warning<
"IBOutletCollection properties should be copy/strong and not assign">,
InGroup<ObjCInvalidIBOutletProperty>;
-def err_attribute_overloadable_missing : Error<
- "%select{overloaded function|redeclaration of}0 %1 must have the "
- "'overloadable' attribute">;
+def err_attribute_overloadable_mismatch : Error<
+ "redeclaration of %0 must %select{not |}1have the 'overloadable' attribute">;
def note_attribute_overloadable_prev_overload : Note<
- "previous overload of function is here">;
+ "previous %select{unmarked |}0overload of function is here">;
def err_attribute_overloadable_no_prototype : Error<
"'overloadable' function %0 must have a prototype">;
+def err_attribute_overloadable_multiple_unmarked_overloads : Error<
+ "at most one overload for a given name may lack the 'overloadable' "
+ "attribute">;
def warn_ns_attribute_wrong_return_type : Warning<
"%0 attribute only applies to %select{functions|methods|properties}1 that "
"return %select{an Objective-C object|a pointer|a non-retainable pointer}2">,
@@ -3369,6 +3522,8 @@ def note_ovl_candidate_substitution_failure : Note<
"candidate template ignored: substitution failure%0%1">;
def note_ovl_candidate_disabled_by_enable_if : Note<
"candidate template ignored: disabled by %0%1">;
+def note_ovl_candidate_disabled_by_requirement : Note<
+ "candidate template ignored: requirement '%0' was not satisfied%1">;
def note_ovl_candidate_has_pass_object_size_params: Note<
"candidate address cannot be taken because parameter %0 has "
"pass_object_size attribute">;
@@ -3380,7 +3535,7 @@ def note_ovl_candidate_disabled_by_function_cond_attr : Note<
def note_ovl_candidate_disabled_by_extension : Note<
"candidate disabled due to OpenCL extension">;
def err_addrof_function_disabled_by_enable_if_attr : Error<
- "cannot take address of function %0 becuase it has one or more "
+ "cannot take address of function %0 because it has one or more "
"non-tautological enable_if conditions">;
def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note<
"candidate function made ineligible by enable_if">;
@@ -3750,7 +3905,7 @@ def err_template_nontype_parm_bad_type : Error<
"a non-type template parameter cannot have type %0">;
def warn_cxx14_compat_template_nontype_parm_auto_type : Warning<
"non-type template parameters declared with %0 are incompatible with C++ "
- "standards before C++1z">,
+ "standards before C++17">,
DefaultIgnore, InGroup<CXXPre1zCompat>;
def err_template_param_default_arg_redefinition : Error<
"template parameter redefines default argument">;
@@ -3789,11 +3944,13 @@ def err_template_decl_ref : Error<
// C++ Template Argument Lists
def err_template_missing_args : Error<
- "use of class template %0 requires template arguments">;
+ "use of "
+ "%select{class template|function template|variable template|alias template|"
+ "template template parameter|template}0 %1 requires template arguments">;
def err_template_arg_list_different_arity : Error<
"%select{too few|too many}0 template arguments for "
- "%select{class template|function template|template template parameter"
- "|template}1 %2">;
+ "%select{class template|function template|variable template|alias template|"
+ "template template parameter|template}1 %2">;
def note_template_decl_here : Note<"template is declared here">;
def err_template_arg_must_be_type : Error<
"template argument for template type parameter must be a type">;
@@ -4063,7 +4220,7 @@ def ext_partial_specs_not_deducible : ExtWarn<
"%select{a template parameter|template parameters}1 that cannot be "
"deduced; this partial specialization will never be used">,
DefaultError, InGroup<DiagGroup<"unusable-partial-specialization">>;
-def note_partial_spec_unused_parameter : Note<
+def note_non_deducible_parameter : Note<
"non-deducible template parameter %0">;
def err_partial_spec_ordering_ambiguous : Error<
"ambiguous partial specializations of %0">;
@@ -4280,12 +4437,17 @@ def err_typename_nested_not_found : Error<"no type named %0 in %1">;
def err_typename_nested_not_found_enable_if : Error<
"no type named 'type' in %0; 'enable_if' cannot be used to disable "
"this declaration">;
+def err_typename_nested_not_found_requirement : Error<
+ "failed requirement '%0'; 'enable_if' cannot be used to disable this "
+ "declaration">;
def err_typename_nested_not_type : Error<
"typename specifier refers to non-type member %0 in %1">;
def note_typename_refers_here : Note<
"referenced member %0 is declared here">;
def err_typename_missing : Error<
"missing 'typename' prior to dependent type name '%0%1'">;
+def err_typename_missing_template : Error<
+ "missing 'typename' prior to dependent type template name '%0%1'">;
def ext_typename_missing : ExtWarn<
"missing 'typename' prior to dependent type name '%0%1'">,
InGroup<DiagGroup<"typename-missing">>;
@@ -4304,7 +4466,7 @@ def err_template_kw_refers_to_non_template : Error<
"%0 following the 'template' keyword does not refer to a template">;
def err_template_kw_refers_to_class_template : Error<
"'%0%1' instantiated to a class template, not a function template">;
-def note_referenced_class_template : Error<
+def note_referenced_class_template : Note<
"class template declared here">;
def err_template_kw_missing : Error<
"missing 'template' keyword prior to dependent template name '%0%1'">;
@@ -4417,8 +4579,11 @@ def warn_deprecated_fwdclass_message : Warning<
"%0 may be deprecated because the receiver type is unknown">,
InGroup<DeprecatedDeclarations>;
def warn_deprecated_def : Warning<
- "Implementing deprecated %select{method|class|category}0">,
- InGroup<DeprecatedImplementations>, DefaultIgnore;
+ "implementing deprecated %select{method|class|category}0">,
+ InGroup<DeprecatedImplementations>, DefaultIgnore;
+def warn_unavailable_def : Warning<
+ "implementing unavailable method">,
+ InGroup<DeprecatedImplementations>, DefaultIgnore;
def err_unavailable : Error<"%0 is unavailable">;
def err_property_method_unavailable :
Error<"property access is using %0 method which is unavailable">;
@@ -4445,7 +4610,7 @@ def warn_missing_prototype : Warning<
def note_declaration_not_a_prototype : Note<
"this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">;
def warn_strict_prototypes : Warning<
- "this %select{function declaration is not|"
+ "this %select{function declaration is not|block declaration is not|"
"old-style function definition is not preceded by}0 a prototype">,
InGroup<DiagGroup<"strict-prototypes">>, DefaultIgnore;
def warn_missing_variable_declarations : Warning<
@@ -4476,6 +4641,8 @@ def err_abi_tag_on_redeclaration : Error<
"cannot add 'abi_tag' attribute in a redeclaration">;
def err_new_abi_tag_on_redeclaration : Error<
"'abi_tag' %0 missing in original declaration">;
+def note_use_ifdef_guards : Note<
+ "unguarded header; consider using #ifdef guards or #pragma once">;
def note_deleted_dtor_no_operator_delete : Note<
"virtual destructor requires an unambiguous, accessible 'operator delete'">;
@@ -4632,7 +4799,7 @@ def ext_forward_ref_enum : Extension<
"ISO C forbids forward references to 'enum' types">;
def err_forward_ref_enum : Error<
"ISO C++ forbids forward references to 'enum' types">;
-def ext_ms_forward_ref_enum : Extension<
+def ext_ms_forward_ref_enum : ExtWarn<
"forward references to 'enum' types are a Microsoft extension">,
InGroup<MicrosoftEnumForwardReference>;
def ext_forward_ref_enum_def : Extension<
@@ -4808,6 +4975,21 @@ def warn_bitfield_width_exceeds_type_width: Warning<
def warn_anon_bitfield_width_exceeds_type_width : Warning<
"width of anonymous bit-field (%0 bits) exceeds width of its type; value "
"will be truncated to %1 bit%s1">, InGroup<BitFieldWidth>;
+def warn_bitfield_too_small_for_enum : Warning<
+ "bit-field %0 is not wide enough to store all enumerators of %1">,
+ InGroup<BitFieldEnumConversion>, DefaultIgnore;
+def note_widen_bitfield : Note<
+ "widen this field to %0 bits to store all values of %1">;
+def warn_unsigned_bitfield_assigned_signed_enum : Warning<
+ "assigning value of signed enum type %1 to unsigned bit-field %0; "
+ "negative enumerators of enum %1 will be converted to positive values">,
+ InGroup<BitFieldEnumConversion>, DefaultIgnore;
+def warn_signed_bitfield_enum_conversion : Warning<
+ "signed bit-field %0 needs an extra bit to represent the largest positive "
+ "enumerators of %1">,
+ InGroup<BitFieldEnumConversion>, DefaultIgnore;
+def note_change_bitfield_sign : Note<
+ "consider making the bitfield type %select{unsigned|signed}0">;
def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,
@@ -4862,6 +5044,8 @@ def note_protected_by_if_available : Note<
"jump enters controlled statement of if available">;
def note_protected_by_vla : Note<
"jump bypasses initialization of variable length array">;
+def note_protected_by_objc_fast_enumeration : Note<
+ "jump enters Objective-C fast enumeration loop">;
def note_protected_by_objc_try : Note<
"jump bypasses initialization of @try block">;
def note_protected_by_objc_catch : Note<
@@ -5164,7 +5348,7 @@ def err_arc_inconsistent_property_ownership : Error<
def warn_block_capture_autoreleasing : Warning<
"block captures an autoreleasing out-parameter, which may result in "
"use-after-free bugs">,
- InGroup<BlockCaptureAutoReleasing>, DefaultIgnore;
+ InGroup<BlockCaptureAutoReleasing>;
def note_declare_parameter_autoreleasing : Note<
"declare the parameter __autoreleasing explicitly to suppress this warning">;
def note_declare_parameter_strong : Note<
@@ -5455,6 +5639,11 @@ def err_enumerator_does_not_exist : Error<
def note_enum_specialized_here : Note<
"enum %0 was explicitly specialized here">;
+def err_specialization_not_primary_template : Error<
+ "cannot reference member of primary template because deduced class "
+ "template specialization %0 is %select{instantiated from a partial|"
+ "an explicit}1 specialization">;
+
def err_member_redeclared : Error<"class member cannot be redeclared">;
def ext_member_redeclared : ExtWarn<"class member cannot be redeclared">,
InGroup<RedeclaredClassMember>;
@@ -5627,6 +5816,9 @@ def err_objc_object_assignment : Error<
"cannot assign to class object (%0 invalid)">;
def err_typecheck_invalid_operands : Error<
"invalid operands to binary expression (%0 and %1)">;
+def err_typecheck_logical_vector_expr_gnu_cpp_restrict : Error<
+ "logical expression with vector %select{type %1 and non-vector type %2|types"
+ " %1 and %2}0 is only supported in C++">;
def err_typecheck_sub_ptr_compatible : Error<
"%diff{$ and $ are not pointers to compatible types|"
"pointers to incompatible types}0,1">;
@@ -5725,8 +5917,8 @@ def err_this_static_member_func : Error<
def err_invalid_member_use_in_static_method : Error<
"invalid use of member %0 in static member function">;
def err_invalid_qualified_function_type : Error<
- "%select{static |non-}0member function %select{of type %2 |}1"
- "cannot have '%3' qualifier">;
+ "%select{non-member function|static member function|deduction guide}0 "
+ "%select{of type %2 |}1cannot have '%3' qualifier">;
def err_compound_qualified_function_type : Error<
"%select{block pointer|pointer|reference}0 to function type %select{%2 |}1"
"cannot have '%3' qualifier">;
@@ -5750,8 +5942,8 @@ def err_builtin_func_cast_more_than_one_arg : Error<
"function-style cast to a builtin type can only take one argument">;
def err_value_init_for_array_type : Error<
"array types cannot be value-initialized">;
-def err_value_init_for_function_type : Error<
- "function types cannot be value-initialized">;
+def err_init_for_function_type : Error<
+ "cannot create object of function type %0">;
def warn_format_nonliteral_noargs : Warning<
"format string is not a string literal (potentially insecure)">,
InGroup<FormatSecurity>;
@@ -5916,6 +6108,12 @@ def warn_objc_circular_container : Warning<
"adding '%0' to '%1' might cause circular dependency in container">,
InGroup<DiagGroup<"objc-circular-container">>;
def note_objc_circular_container_declared_here : Note<"'%0' declared here">;
+def warn_objc_unsafe_perform_selector : Warning<
+ "%0 is incompatible with selectors that return a "
+ "%select{struct|union|vector}1 type">,
+ InGroup<DiagGroup<"objc-unsafe-perform-selector">>;
+def note_objc_unsafe_perform_selector_method_declared_here : Note<
+ "method %0 that returns %1 declared here">;
def warn_setter_getter_impl_required : Warning<
"property %0 requires method %1 to be defined - "
@@ -6134,12 +6332,14 @@ def warn_ambiguous_suitable_delete_function_found : Warning<
InGroup<DiagGroup<"ambiguous-delete">>;
def note_member_declared_here : Note<
"member %0 declared here">;
+def note_member_first_declared_here : Note<
+ "member %0 first declared here">;
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
def warn_increment_bool : Warning<
"incrementing expression of type bool is deprecated and "
- "incompatible with C++1z">, InGroup<DeprecatedIncrementBool>;
+ "incompatible with C++17">, InGroup<DeprecatedIncrementBool>;
def ext_increment_bool : ExtWarn<
- "ISO C++1z does not allow incrementing expression of type bool">,
+ "ISO C++17 does not allow incrementing expression of type bool">,
DefaultError, InGroup<IncrementBool>;
def err_increment_decrement_enum : Error<
"cannot %select{decrement|increment}0 expression of enum type %1">;
@@ -6167,6 +6367,13 @@ def err_exceptions_disabled : Error<
"cannot use '%0' with exceptions disabled">;
def err_objc_exceptions_disabled : Error<
"cannot use '%0' with Objective-C exceptions disabled">;
+def warn_throw_in_noexcept_func : Warning<
+ "%0 has a non-throwing exception specification but can still throw">,
+ InGroup<Exceptions>;
+def note_throw_in_dtor : Note<
+ "%select{destructor|deallocator}0 has a %select{non-throwing|implicit "
+ "non-throwing}1 exception specification">;
+def note_throw_in_function : Note<"function declared non-throwing here">;
def err_seh_try_outside_functions : Error<
"cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">;
def err_mixing_cxx_try_seh_try : Error<
@@ -6212,6 +6419,12 @@ def warn_overaligned_type : Warning<
"type %0 requires %1 bytes of alignment and the default allocator only "
"guarantees %2 bytes">,
InGroup<OveralignedType>, DefaultIgnore;
+def warn_aligned_allocation_unavailable :Warning<
+ "aligned %select{allocation|deallocation}0 function of type '%1' possibly "
+ "unavailable on %2">, InGroup<AlignedAllocationUnavailable>, DefaultError;
+def note_silence_unligned_allocation_unavailable : Note<
+ "if you supply your own aligned allocation functions, use "
+ "-Wno-aligned-allocation-unavailable to silence this diagnostic">;
def err_conditional_void_nonvoid : Error<
"%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "
@@ -6315,10 +6528,10 @@ let CategoryName = "Lambda Issue" in {
// C++1z '*this' captures.
def warn_cxx14_compat_star_this_lambda_capture : Warning<
- "by value capture of '*this' is incompatible with C++ standards before C++1z">,
+ "by value capture of '*this' is incompatible with C++ standards before C++17">,
InGroup<CXXPre1zCompat>, DefaultIgnore;
def ext_star_this_lambda_capture_cxx1z : ExtWarn<
- "capture of '*this' by copy is a C++1z extension">, InGroup<CXX1z>;
+ "capture of '*this' by copy is a C++17 extension">, InGroup<CXX17>;
}
def err_return_in_captured_stmt : Error<
@@ -6987,7 +7200,7 @@ def warn_unused_volatile : Warning<
def ext_cxx14_attr : Extension<
"use of the %0 attribute is a C++14 extension">, InGroup<CXX14>;
def ext_cxx1z_attr : Extension<
- "use of the %0 attribute is a C++1z extension">, InGroup<CXX1z>;
+ "use of the %0 attribute is a C++17 extension">, InGroup<CXX17>;
def warn_unused_comparison : Warning<
"%select{%select{|in}1equality|relational}0 comparison result unused">,
@@ -7001,7 +7214,7 @@ def err_incomplete_type_used_in_type_trait_expr : Error<
def err_require_constant_init_failed : Error<
"variable does not have a constant initializer">;
def note_declared_required_constant_init_here : Note<
- "required by 'require_constant_initializer' attribute here">;
+ "required by 'require_constant_initialization' attribute here">;
def err_dimension_expr_not_constant_integer : Error<
"dimension expression does not evaluate to a constant unsigned int">;
@@ -7099,7 +7312,7 @@ def err_invalid_conversion_between_vector_and_integer : Error<
"invalid conversion between vector type %0 and integer type %1 "
"of different size">;
-def err_opencl_function_pointer_variable : Error<
+def err_opencl_function_pointer : Error<
"pointers to functions are not allowed">;
def err_opencl_taking_function_address : Error<
@@ -7770,7 +7983,11 @@ def warn_empty_switch_body : Warning<
def note_empty_body_on_separate_line : Note<
"put the semicolon on a separate line to silence this warning">;
-def err_va_start_used_in_non_variadic_function : Error<
+def err_va_start_captured_stmt : Error<
+ "'va_start' cannot be used in a captured statement">;
+def err_va_start_outside_function : Error<
+ "'va_start' cannot be used outside a function">;
+def err_va_start_fixed_function : Error<
"'va_start' used in function with fixed args">;
def err_va_start_used_in_wrong_abi_function : Error<
"'va_start' used in %select{System V|Win64}0 ABI function">;
@@ -7841,10 +8058,13 @@ def err_block_on_nonlocal : Error<
def err_block_on_vm : Error<
"__block attribute not allowed on declaration with a variably modified type">;
-def err_shufflevector_non_vector : Error<
- "first two arguments to __builtin_shufflevector must be vectors">;
-def err_shufflevector_incompatible_vector : Error<
- "first two arguments to __builtin_shufflevector must have the same type">;
+def err_vec_builtin_non_vector : Error<
+ "first two arguments to %0 must be vectors">;
+def err_vec_builtin_incompatible_vector : Error<
+ "first two arguments to %0 must have the same type">;
+def err_vsx_builtin_nonconstant_argument : Error<
+ "argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">;
+
def err_shufflevector_nonconstant_argument : Error<
"index for __builtin_shufflevector must be a constant integer">;
def err_shufflevector_argument_too_large : Error<
@@ -7893,12 +8113,14 @@ def err_systemz_invalid_tabort_code : Error<
"invalid transaction abort code">;
def err_64_bit_builtin_32_bit_tgt : Error<
"this builtin is only available on 64-bit targets">;
+def err_builtin_x64_aarch64_only : Error<
+ "this builtin is only available on x86-64 and aarch64 targets">;
def err_ppc_builtin_only_on_pwr7 : Error<
"this builtin is only valid on POWER7 or later CPUs">;
-def err_x86_builtin_32_bit_tgt : Error<
- "this builtin is only available on x86-64 targets">;
def err_x86_builtin_invalid_rounding : Error<
"invalid rounding argument">;
+def err_x86_builtin_invalid_scale : Error<
+ "scale argument must be 1, 2, 4, or 8">;
def err_builtin_longjmp_unsupported : Error<
"__builtin_longjmp is not supported for the current target">;
@@ -8026,9 +8248,20 @@ def err_undeclared_use_suggest : Error<
"use of undeclared %0; did you mean %1?">;
def err_undeclared_var_use_suggest : Error<
"use of undeclared identifier %0; did you mean %1?">;
+def err_no_template : Error<"no template named %0">;
def err_no_template_suggest : Error<"no template named %0; did you mean %1?">;
+def err_no_member_template : Error<"no template named %0 in %1">;
def err_no_member_template_suggest : Error<
"no template named %0 in %1; did you mean %select{|simply }2%3?">;
+def err_non_template_in_template_id : Error<
+ "%0 does not name a template but is followed by template arguments">;
+def err_non_template_in_template_id_suggest : Error<
+ "%0 does not name a template but is followed by template arguments; "
+ "did you mean %1?">;
+def err_non_template_in_member_template_id_suggest : Error<
+ "member %0 of %1 is not a template; did you mean %select{|simply }2%3?">;
+def note_non_template_in_template_id_found : Note<
+ "non-template declaration found by name lookup">;
def err_mem_init_not_member_or_class_suggest : Error<
"initializer %0 does not name a non-static data member or base "
"class; did you mean the %select{base class|member}1 %2?">;
@@ -8113,16 +8346,26 @@ def err_opencl_ptrptr_kernel_param : Error<
def err_kernel_arg_address_space : Error<
"pointer arguments to kernel functions must reside in '__global', "
"'__constant' or '__local' address space">;
+def err_opencl_ext_vector_component_invalid_length : Error<
+ "vector component access has invalid length %0. Supported: 1,2,3,4,8,16.">;
def err_opencl_function_variable : Error<
"%select{non-kernel function|function scope}0 variable cannot be declared in %1 address space">;
+def err_opencl_addrspace_scope : Error<
+ "variables in the %0 address space can only be declared in the outermost "
+ "scope of a kernel function">;
def err_static_function_scope : Error<
"variables in function scope cannot be declared static">;
def err_opencl_bitfields : Error<
"bit-fields are not supported in OpenCL">;
def err_opencl_vla : Error<
"variable length arrays are not supported in OpenCL">;
+def err_opencl_scalar_type_rank_greater_than_vector_type : Error<
+ "scalar operand type has greater rank than the type of the vector "
+ "element. (%0 and %1)">;
def err_bad_kernel_param_type : Error<
"%0 cannot be used as the type of a kernel parameter">;
+def err_opencl_implicit_function_decl : Error<
+ "implicit declaration of function %0 is invalid in OpenCL">;
def err_record_with_pointers_kernel_param : Error<
"%select{struct|union}0 kernel parameters may not contain pointers">;
def note_within_field_of_type : Note<
@@ -8143,6 +8386,8 @@ def err_sampler_argument_required : Error<
"sampler_t variable required - got %0">;
def err_wrong_sampler_addressspace: Error<
"sampler type cannot be used with the __local and __global address space qualifiers">;
+def err_opencl_nonconst_global_sampler : Error<
+ "global sampler requires a const or constant address space qualifier">;
def err_opencl_cast_non_zero_to_event_t : Error<
"cannot cast non-zero value '%0' to 'event_t'">;
def err_opencl_global_invalid_addr_space : Error<
@@ -8158,9 +8403,9 @@ def err_opencl_return_value_with_address_space : Error<
"return value cannot be qualified with address space">;
def err_opencl_constant_no_init : Error<
"variable in constant address space must be initialized">;
-def err_atomic_init_constant : Error<
- "atomic variable can only be assigned to a compile time constant"
- " in the declaration statement in the program scope">;
+def err_opencl_atomic_init: Error<
+ "atomic variable can be %select{assigned|initialized}0 to a variable only "
+ "in global address space">;
def err_opencl_implicit_vector_conversion : Error<
"implicit conversions between vector types (%0 and %1) are not permitted">;
def err_opencl_invalid_type_array : Error<
@@ -8177,7 +8422,7 @@ def warn_opencl_attr_deprecated_ignored : Warning <
def err_opencl_variadic_function : Error<
"invalid prototype, variadic arguments are not allowed in OpenCL">;
def err_opencl_requires_extension : Error<
- "use of %select{type |declaration}0%1 requires %2 extension to be enabled">;
+ "use of %select{type|declaration}0 %1 requires %2 extension to be enabled">;
// OpenCL v2.0 s6.13.6 -- Builtin Pipe Functions
def err_opencl_builtin_pipe_first_arg : Error<
@@ -8210,6 +8455,8 @@ def err_opencl_invalid_block_declaration : Error<
"invalid block variable declaration - must be %select{const qualified|initialized}0">;
def err_opencl_extern_block_declaration : Error<
"invalid block variable declaration - using 'extern' storage class is disallowed">;
+def err_opencl_block_ref_block : Error<
+ "cannot refer to a block inside block">;
// OpenCL v2.0 s6.13.9 - Address space qualifier functions.
def err_opencl_builtin_to_addr_arg_num : Error<
@@ -8220,16 +8467,17 @@ def err_opencl_builtin_to_addr_invalid_arg : Error<
// OpenCL v2.0 s6.13.17 Enqueue kernel restrictions.
def err_opencl_enqueue_kernel_incorrect_args : Error<
"illegal call to enqueue_kernel, incorrect argument types">;
-def err_opencl_enqueue_kernel_expected_type : Error<
- "illegal call to enqueue_kernel, expected %0 argument type">;
def err_opencl_enqueue_kernel_local_size_args : Error<
"mismatch in number of block parameters and local size arguments passed">;
def err_opencl_enqueue_kernel_invalid_local_size_type : Error<
"illegal call to enqueue_kernel, parameter needs to be specified as integer type">;
def err_opencl_enqueue_kernel_blocks_non_local_void_args : Error<
- "blocks used in device side enqueue are expected to have parameters of type 'local void*'">;
+ "blocks used in enqueue_kernel call are expected to have parameters of type 'local void*'">;
def err_opencl_enqueue_kernel_blocks_no_args : Error<
- "blocks in this form of device side enqueue call are expected to have have no parameters">;
+ "blocks with parameters are not accepted in this prototype of enqueue_kernel call">;
+
+def err_opencl_builtin_expected_type : Error<
+ "illegal call to %0, expected %1 argument type">;
// OpenCL v2.2 s2.1.2.3 - Vector Component Access
def ext_opencl_ext_vector_type_rgba_selector: ExtWarn<
@@ -8407,11 +8655,11 @@ def err_omp_unknown_reduction_identifier : Error<
def err_omp_not_resolved_reduction_identifier : Error<
"unable to resolve declare reduction construct for type %0">;
def err_omp_reduction_ref_type_arg : Error<
- "argument of OpenMP clause 'reduction' must reference the same object in all threads">;
+ "argument of OpenMP clause '%0' must reference the same object in all threads">;
def err_omp_clause_not_arithmetic_type_arg : Error<
- "arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of %select{scalar|arithmetic}0 type">;
+ "arguments of OpenMP clause '%0' for 'min' or 'max' must be of %select{scalar|arithmetic}1 type">;
def err_omp_clause_floating_type_arg : Error<
- "arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type">;
+ "arguments of OpenMP clause '%0' with bitwise operators cannot be of floating type">;
def err_omp_once_referenced : Error<
"variable can appear only once in OpenMP '%0' clause">;
def err_omp_once_referenced_in_target_update : Error<
@@ -8549,8 +8797,8 @@ def err_omp_not_mappable_type : Error<
"type %0 is not mappable to target">;
def err_omp_invalid_map_type_for_directive : Error<
"%select{map type '%1' is not allowed|map type must be specified}0 for '#pragma omp %2'">;
-def err_omp_no_map_for_directive : Error<
- "expected at least one map clause for '#pragma omp %0'">;
+def err_omp_no_clause_for_directive : Error<
+ "expected at least one %0 clause for '#pragma omp %1'">;
def note_omp_polymorphic_in_target : Note<
"mappable type cannot be polymorphic">;
def note_omp_static_member_in_target : Note<
@@ -8619,6 +8867,10 @@ def warn_omp_nesting_simd : Warning<
def err_omp_orphaned_device_directive : Error<
"orphaned 'omp %0' directives are prohibited"
"; perhaps you forget to enclose the directive into a %select{|||target |teams }1region?">;
+def err_omp_reduction_non_addressable_expression : Error<
+ "expected addressable reduction item for the task-based directives">;
+def err_omp_reduction_with_nogroup : Error<
+ "'reduction' clause cannot be used with 'nogroup' clause">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
@@ -8649,9 +8901,11 @@ def err_invalid_type_for_program_scope_var : Error<
}
let CategoryName = "Modules Issue" in {
+def err_module_decl_in_module_map_module : Error<
+ "'module' declaration found while building module from module map">;
def err_module_interface_implementation_mismatch : Error<
- "%select{'module'|'module partition'|'module implementation'}0 declaration "
- "found while %select{not |not |}0building module interface">;
+ "missing 'export' specifier in module declaration while "
+ "building module interface">;
def err_current_module_name_mismatch : Error<
"module name '%0' specified on command line does not match name of module">;
def err_module_redefinition : Error<
@@ -8694,22 +8948,31 @@ def err_module_self_import : Error<
"import of module '%0' appears within same top-level module '%1'">;
def err_module_import_in_implementation : Error<
"@import of module '%0' in implementation of '%1'; use #import">;
+
+// C++ Modules TS
def err_export_within_export : Error<
"export declaration appears within another export declaration">;
+def err_export_not_in_module_interface : Error<
+ "export declaration can only be used within a module interface unit after "
+ "the module declaration">;
def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn<
"ambiguous use of internal linkage declaration %0 defined in multiple modules">,
InGroup<DiagGroup<"modules-ambiguous-internal-linkage">>;
def note_equivalent_internal_linkage_decl : Note<
"declared here%select{ in module '%1'|}0">;
+
+def note_redefinition_modules_same_file : Note<
+ "'%0' included multiple times, additional include site in header from module '%1'">;
+def note_redefinition_include_same_file : Note<
+ "'%0' included multiple times, additional include site here">;
}
let CategoryName = "Coroutines Issue" in {
def err_return_in_coroutine : Error<
"return statement not allowed in coroutine; did you mean 'co_return'?">;
def note_declared_coroutine_here : Note<
- "function is a coroutine due to use of "
- "'%select{co_await|co_yield|co_return}0' here">;
+ "function is a coroutine due to use of '%0' here">;
def err_coroutine_objc_method : Error<
"Objective-C methods as coroutines are not yet supported">;
def err_coroutine_unevaluated_context : Error<
@@ -8721,24 +8984,58 @@ def err_coroutine_invalid_func_context : Error<
"|a copy assignment operator|a move assignment operator|the 'main' function"
"|a constexpr function|a function with a deduced return type"
"|a varargs function}0">;
-def err_implied_std_coroutine_traits_not_found : Error<
- "you need to include <experimental/coroutine> before defining a coroutine">;
+def err_implied_coroutine_type_not_found : Error<
+ "%0 type was not found; include <experimental/coroutine> before defining "
+ "a coroutine">;
+def err_implicit_coroutine_std_nothrow_type_not_found : Error<
+ "std::nothrow was not found; include <new> before defining a coroutine which "
+ "uses get_return_object_on_allocation_failure()">;
+def err_malformed_std_nothrow : Error<
+ "std::nothrow must be a valid variable declaration">;
+def err_malformed_std_coroutine_handle : Error<
+ "std::experimental::coroutine_handle must be a class template">;
+def err_coroutine_handle_missing_member : Error<
+ "std::experimental::coroutine_handle missing a member named '%0'">;
def err_malformed_std_coroutine_traits : Error<
"'std::experimental::coroutine_traits' must be a class template">;
def err_implied_std_coroutine_traits_promise_type_not_found : Error<
"this function cannot be a coroutine: %q0 has no member named 'promise_type'">;
def err_implied_std_coroutine_traits_promise_type_not_class : Error<
"this function cannot be a coroutine: %0 is not a class">;
-def err_coroutine_traits_missing_specialization : Error<
+def err_coroutine_promise_type_incomplete : Error<
+ "this function cannot be a coroutine: %0 is an incomplete type">;
+def err_coroutine_type_missing_specialization : Error<
"this function cannot be a coroutine: missing definition of "
"specialization %q0">;
-def err_implied_std_current_exception_not_found : Error<
- "you need to include <exception> before defining a coroutine that implicitly "
- "uses 'set_exception'">;
-def err_malformed_std_current_exception : Error<
- "'std::current_exception' must be a function">;
-def err_coroutine_promise_return_ill_formed : Error<
- "%0 declares both 'return_value' and 'return_void'">;
+def err_coroutine_promise_incompatible_return_functions : Error<
+ "the coroutine promise type %0 declares both 'return_value' and 'return_void'">;
+def err_coroutine_promise_requires_return_function : Error<
+ "the coroutine promise type %0 must declare either 'return_value' or 'return_void'">;
+def note_coroutine_promise_implicit_await_transform_required_here : Note<
+ "call to 'await_transform' implicitly required by 'co_await' here">;
+def note_coroutine_promise_suspend_implicitly_required : Note<
+ "call to '%select{initial_suspend|final_suspend}0' implicitly "
+ "required by the %select{initial suspend point|final suspend point}0">;
+def err_coroutine_promise_unhandled_exception_required : Error<
+ "%0 is required to declare the member 'unhandled_exception()'">;
+def warn_coroutine_promise_unhandled_exception_required_with_exceptions : Warning<
+ "%0 is required to declare the member 'unhandled_exception()' when exceptions are enabled">,
+ InGroup<CoroutineMissingUnhandledException>;
+def err_coroutine_promise_get_return_object_on_allocation_failure : Error<
+ "%0: 'get_return_object_on_allocation_failure()' must be a static member function">;
+def err_seh_in_a_coroutine_with_cxx_exceptions : Error<
+ "cannot use SEH '__try' in a coroutine when C++ exceptions are enabled">;
+def err_coroutine_promise_new_requires_nothrow : Error<
+ "%0 is required to have a non-throwing noexcept specification when the promise "
+ "type declares 'get_return_object_on_allocation_failure()'">;
+def note_coroutine_promise_call_implicitly_required : Note<
+ "call to %0 implicitly required by coroutine function here">;
+def err_await_suspend_invalid_return_type : Error<
+ "return type of 'await_suspend' is required to be 'void' or 'bool' (have %0)"
+>;
+def note_await_ready_no_bool_conversion : Note<
+ "return type of 'await_ready' is required to be contextually convertible to 'bool'"
+>;
}
let CategoryName = "Documentation Issue" in {
@@ -8749,8 +9046,13 @@ def warn_not_a_doxygen_trailing_member_comment : Warning<
let CategoryName = "Instrumentation Issue" in {
def warn_profile_data_out_of_date : Warning<
"profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1"
- " no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">,
+ " mismatched data that will be ignored">,
InGroup<ProfileInstrOutOfDate>;
+def warn_profile_data_missing : Warning<
+ "profile data may be incomplete: of %0 function%s0, %1 %plural{1:has|:have}1"
+ " no data">,
+ InGroup<ProfileInstrMissing>,
+ DefaultIgnore;
def warn_profile_data_unprofiled : Warning<
"no profile data available for file \"%0\"">,
InGroup<ProfileInstrUnprofiled>;
@@ -8780,6 +9082,9 @@ def warn_nullability_lost : Warning<
"implicit conversion from nullable pointer %0 to non-nullable pointer "
"type %1">,
InGroup<NullableToNonNullConversion>, DefaultIgnore;
+def warn_zero_as_null_pointer_constant : Warning<
+ "zero as null pointer constant">,
+ InGroup<DiagGroup<"zero-as-null-pointer-constant">>, DefaultIgnore;
def err_nullability_cs_multilevel : Error<
"nullability keyword %0 cannot be applied to multi-level pointer type %1">;
@@ -8905,4 +9210,9 @@ def ext_warn_gnu_final : ExtWarn<
"__final is a GNU extension, consider using C++11 final">,
InGroup<GccCompat>;
+def warn_shadow_field :
+ Warning<"non-static data member '%0' of '%1' shadows member inherited from type '%2'">,
+ InGroup<ShadowField>, DefaultIgnore;
+def note_shadow_field : Note<"declared here">;
+
} // end of sema component.
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td
index 066a1f5..420cceb 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -112,19 +112,151 @@ def note_module_odr_violation_possible_decl : Note<
def err_module_odr_violation_different_definitions : Error<
"%q0 has different definitions in different modules; "
"%select{definition in module '%2' is here|defined here}1">;
+def note_first_module_difference : Note<
+ "in first definition, possible difference is here">;
def note_module_odr_violation_different_definitions : Note<
"definition in module '%0' is here">;
+def note_second_module_difference : Note<
+ "in second definition, possible difference is here">;
+
def err_module_odr_violation_different_instantiations : Error<
"instantiation of %q0 is different in different modules">;
-def warn_module_uses_date_time : Warning<
- "%select{precompiled header|module}0 uses __DATE__ or __TIME__">,
- InGroup<DiagGroup<"pch-date-time">>;
+def err_module_odr_violation_mismatch_decl : Error<
+ "%q0 has different definitions in different modules; first difference is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{end of class|public access specifier|private access specifier|"
+ "protected access specifier|static assert|field|method|type alias|typedef|"
+ "data member|friend declaration}3">;
+def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
+ "%select{end of class|public access specifier|private access specifier|"
+ "protected access specifier|static assert|field|method|type alias|typedef|"
+ "data member|friend declaration}1">;
+
+def err_module_odr_violation_mismatch_decl_diff : Error<
+ "%q0 has different definitions in different modules; first difference is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "static assert with condition|"
+ "static assert with message|"
+ "static assert with %select{|no }4message|"
+ "field %4|"
+ "field %4 with type %5|"
+ "%select{non-|}5bitfield %4|"
+ "bitfield %4 with one width expression|"
+ "%select{non-|}5mutable field %4|"
+ "field %4 with %select{no|an}5 initalizer|"
+ "field %4 with an initializer|"
+ "%select{method %5|constructor|destructor}4|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not deleted|deleted}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{|pure }6%select{not virtual|virtual}7|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not static|static}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not volatile|volatile}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not const|const}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not inline|inline}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "that has %6 parameter%s6|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter of type %7%select{| decayed from %9}8|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter named %7|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter with%select{out|}7 a default argument|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter with a default argument|"
+ "%select{typedef|type alias}4 name %5|"
+ "%select{typedef|type alias}4 %5 with underlying type %6|"
+ "data member with name %4|"
+ "data member %4 with type %5|"
+ "data member %4 with%select{out|}5 an initializer|"
+ "data member %4 with an initializer|"
+ "data member %4 %select{is constexpr|is not constexpr}5|"
+ "friend %select{class|function}4|"
+ "friend %4|"
+ "friend function %4|"
+ "}3">;
+
+def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
+ "%select{"
+ "static assert with different condition|"
+ "static assert with different message|"
+ "static assert with %select{|no }2message|"
+ "field %2|"
+ "field %2 with type %3|"
+ "%select{non-|}3bitfield %2|"
+ "bitfield %2 with different width expression|"
+ "%select{non-|}3mutable field %2|"
+ "field %2 with %select{no|an}3 initializer|"
+ "field %2 with a different initializer|"
+ "%select{method %3|constructor|destructor}2|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not deleted|deleted}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{|pure }4%select{not virtual|virtual}5|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not static|static}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not volatile|volatile}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not const|const}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not inline|inline}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "that has %4 parameter%s4|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter of type %5%select{| decayed from %7}6|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter named %5|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter with%select{out|}5 a default argument|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter with a different default argument|"
+ "%select{typedef|type alias}2 name %3|"
+ "%select{typedef|type alias}2 %3 with different underlying type %4|"
+ "data member with name %2|"
+ "data member %2 with different type %3|"
+ "data member %2 with%select{out|}3 an initializer|"
+ "data member %2 with a different initializer|"
+ "data member %2 %select{is constexpr|is not constexpr}3|"
+ "friend %select{class|function}2|"
+ "friend %2|"
+ "friend function %2|"
+ "}1">;
+
+def err_module_odr_violation_mismatch_decl_unknown : Error<
+ "%q0 %select{with definition in module '%2'|defined here}1 has different "
+ "definitions in different modules; first difference is this "
+ "%select{||||static assert|field|method|type alias|typedef|data member|"
+ "friend declaration|unexpected decl}3">;
+def note_module_odr_violation_mismatch_decl_unknown : Note<
+ "but in '%0' found "
+ "%select{||||different static assert|different field|different method|"
+ "different type alias|different typedef|different data member|"
+ "different friend declaration|another unexpected decl}1">;
def warn_duplicate_module_file_extension : Warning<
"duplicate module file extension block name '%0'">,
InGroup<ModuleFileExtension>;
+def warn_module_system_bit_conflict : Warning<
+ "module file '%0' was validated as a system module and is now being imported "
+ "as a non-system module; any difference in diagnostic options will be ignored">,
+ InGroup<ModuleConflict>;
+} // let CategoryName
+
+let CategoryName = "AST Serialization Issue" in {
+def warn_module_uses_date_time : Warning<
+ "%select{precompiled header|module}0 uses __DATE__ or __TIME__">,
+ InGroup<DiagGroup<"pch-date-time">>;
+def err_module_no_size_mtime_for_header : Error<
+ "cannot emit module %0: %select{size|mtime}1 must be explicitly specified "
+ "for missing header file \"%2\"">;
} // let CategoryName
} // let Component
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h b/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h
index 3001d0b..f94b2c9 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h
@@ -272,15 +272,15 @@ public:
/// this identifier is a C++ alternate representation of an operator.
void setIsCPlusPlusOperatorKeyword(bool Val = true) {
IsCPPOperatorKeyword = Val;
- if (Val)
- NeedsHandleIdentifier = true;
- else
- RecomputeNeedsHandleIdentifier();
}
bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
/// \brief Return true if this token is a keyword in the specified language.
- bool isKeyword(const LangOptions &LangOpts);
+ bool isKeyword(const LangOptions &LangOpts) const;
+
+ /// \brief Return true if this token is a C++ keyword in the specified
+ /// language.
+ bool isCPlusPlusKeyword(const LangOptions &LangOpts) const;
/// getFETokenInfo/setFETokenInfo - The language front-end is allowed to
/// associate arbitrary metadata with this token.
@@ -351,6 +351,19 @@ public:
RecomputeNeedsHandleIdentifier();
}
+ /// Return true if this identifier is an editor placeholder.
+ ///
+ /// Editor placeholders are produced by the code-completion engine and are
+ /// represented as characters between '<#' and '#>' in the source code. An
+ /// example of auto-completed call with a placeholder parameter is shown
+ /// below:
+ /// \code
+ /// function(<#int x#>);
+ /// \endcode
+ bool isEditorPlaceholder() const {
+ return getName().startswith("<#") && getName().endswith("#>");
+ }
+
/// \brief Provide less than operator for lexicographical sorting.
bool operator<(const IdentifierInfo &RHS) const {
return getName() < RHS.getName();
@@ -364,10 +377,9 @@ private:
/// This method is very tied to the definition of HandleIdentifier. Any
/// change to it should be reflected here.
void RecomputeNeedsHandleIdentifier() {
- NeedsHandleIdentifier =
- (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() |
- isExtensionToken() | isFutureCompatKeyword() || isOutOfDate() ||
- isModulesImport());
+ NeedsHandleIdentifier = isPoisoned() || hasMacroDefinition() ||
+ isExtensionToken() || isFutureCompatKeyword() ||
+ isOutOfDate() || isModulesImport();
}
};
@@ -818,6 +830,7 @@ public:
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
CXXOperator##Name,
#include "clang/Basic/OperatorKinds.def"
+ CXXDeductionGuide,
CXXLiteralOperator,
CXXUsingDirective,
NUM_EXTRA_KINDS
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def
index d944a9d..c9230e0 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def
@@ -90,6 +90,7 @@ LANGOPT(CPlusPlus , 1, 0, "C++")
LANGOPT(CPlusPlus11 , 1, 0, "C++11")
LANGOPT(CPlusPlus14 , 1, 0, "C++14")
LANGOPT(CPlusPlus1z , 1, 0, "C++1z")
+LANGOPT(CPlusPlus2a , 1, 0, "C++2a")
LANGOPT(ObjC1 , 1, 0, "Objective-C 1")
LANGOPT(ObjC2 , 1, 0, "Objective-C 2")
BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0,
@@ -107,7 +108,7 @@ LANGOPT(WChar , 1, CPlusPlus, "wchar_t keyword")
LANGOPT(DeclSpecKeyword , 1, 0, "__declspec keyword")
BENIGN_LANGOPT(DollarIdents , 1, 1, "'$' in identifiers")
BENIGN_LANGOPT(AsmPreprocessor, 1, 0, "preprocessor in asm mode")
-BENIGN_LANGOPT(GNUMode , 1, 1, "GNU extensions")
+LANGOPT(GNUMode , 1, 1, "GNU extensions")
LANGOPT(GNUKeywords , 1, 1, "GNU keywords")
BENIGN_LANGOPT(ImplicitInt, 1, !C99 && !CPlusPlus, "C89 implicit 'int'")
LANGOPT(Digraphs , 1, 0, "digraphs")
@@ -199,8 +200,11 @@ LANGOPT(CUDADeviceApproxTranscendentals, 1, 0, "using approximate transcendental
LANGOPT(SizedDeallocation , 1, 0, "sized deallocation")
LANGOPT(AlignedAllocation , 1, 0, "aligned allocation")
+LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable")
LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'")
LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts")
+BENIGN_LANGOPT(ModulesCodegen , 1, 0, "Modules code generation")
+BENIGN_LANGOPT(ModulesDebugInfo , 1, 0, "Modules debug info")
BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records")
BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form")
@@ -215,7 +219,8 @@ BENIGN_LANGOPT(DebuggerObjCLiteral , 1, 0, "debugger Objective-C literals and su
BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking")
LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants")
LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math")
-LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT")
+/// \brief FP_CONTRACT mode (on/off/fast).
+ENUM_LANGOPT(DefaultFPContractMode, FPContractModeKind, 2, FPC_Off, "FP contraction type")
LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment")
LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility")
LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting")
@@ -261,6 +266,11 @@ LANGOPT(SanitizeAddressFieldPadding, 2, 0, "controls how aggressive is ASan "
"field padding (0: none, 1:least "
"aggressive, 2: more aggressive)")
+LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation")
+
+BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0,
+ "allow editor placeholders in source")
+
#undef LANGOPT
#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h
index 10635b1..8488515 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h
@@ -58,6 +58,7 @@ public:
SOB_Trapping // -ftrapv
};
+ // FIXME: Unify with TUKind.
enum CompilingModuleKind {
CMK_None, ///< Not compiling a module interface at all.
CMK_ModuleMap, ///< Compiling a module from a module map.
@@ -88,6 +89,12 @@ public:
MSVC2015 = 19
};
+ enum FPContractModeKind {
+ FPC_Off, // Form fused FP ops only where result will not be affected.
+ FPC_On, // Form fused FP ops according to FP_CONTRACT rules.
+ FPC_Fast // Aggressively fuse FP ops (E.g. FMA).
+ };
+
public:
/// \brief Set of enabled sanitizers.
SanitizerSet Sanitize;
@@ -96,6 +103,16 @@ public:
/// (files, functions, variables) should not be instrumented.
std::vector<std::string> SanitizerBlacklistFiles;
+ /// \brief Paths to the XRay "always instrument" files specifying which
+ /// objects (files, functions, variables) should be imbued with the XRay
+ /// "always instrument" attribute.
+ std::vector<std::string> XRayAlwaysInstrumentFiles;
+
+ /// \brief Paths to the XRay "never instrument" files specifying which
+ /// objects (files, functions, variables) should be imbued with the XRay
+ /// "never instrument" attribute.
+ std::vector<std::string> XRayNeverInstrumentFiles;
+
clang::ObjCRuntime ObjCRuntime;
std::string ObjCConstantStringClass;
@@ -150,6 +167,11 @@ public:
return getCompilingModule() != CMK_None;
}
+ /// Do we need to track the owning module for a local declaration?
+ bool trackLocalOwningModule() const {
+ return isCompilingModule() || ModulesLocalVisibility || ModulesTS;
+ }
+
bool isSignedOverflowDefined() const {
return getSignedOverflowBehavior() == SOB_Defined;
}
@@ -170,17 +192,45 @@ public:
/// \brief Is this a libc/libm function that is no longer recognized as a
/// builtin because a -fno-builtin-* option has been specified?
bool isNoBuiltinFunc(StringRef Name) const;
+
+ /// \brief True if any ObjC types may have non-trivial lifetime qualifiers.
+ bool allowsNonTrivialObjCLifetimeQualifiers() const {
+ return ObjCAutoRefCount || ObjCWeak;
+ }
};
/// \brief Floating point control options
class FPOptions {
public:
- unsigned fp_contract : 1;
+ FPOptions() : fp_contract(LangOptions::FPC_Off) {}
+
+ // Used for serializing.
+ explicit FPOptions(unsigned I)
+ : fp_contract(static_cast<LangOptions::FPContractModeKind>(I)) {}
+
+ explicit FPOptions(const LangOptions &LangOpts)
+ : fp_contract(LangOpts.getDefaultFPContractMode()) {}
+
+ bool allowFPContractWithinStatement() const {
+ return fp_contract == LangOptions::FPC_On;
+ }
+ bool allowFPContractAcrossStatement() const {
+ return fp_contract == LangOptions::FPC_Fast;
+ }
+ void setAllowFPContractWithinStatement() {
+ fp_contract = LangOptions::FPC_On;
+ }
+ void setAllowFPContractAcrossStatement() {
+ fp_contract = LangOptions::FPC_Fast;
+ }
+ void setDisallowFPContract() { fp_contract = LangOptions::FPC_Off; }
- FPOptions() : fp_contract(0) {}
+ /// Used to serialize this.
+ unsigned getInt() const { return fp_contract; }
- FPOptions(const LangOptions &LangOpts) :
- fp_contract(LangOpts.DefaultFPContract) {}
+private:
+ /// Adjust BinaryOperator::FPFeatures to match the bit-field size of this.
+ unsigned fp_contract : 2;
};
/// \brief Describes the kind of translation unit being processed.
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h b/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h
index e96fb56..6ec8763 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h
@@ -45,6 +45,17 @@ enum Linkage : unsigned char {
/// translation units because of types defined in a inline function.
VisibleNoLinkage,
+ /// \brief Internal linkage according to the Modules TS, but can be referred
+ /// to from other translation units indirectly through inline functions and
+ /// templates in the module interface.
+ ModuleInternalLinkage,
+
+ /// \brief Module linkage, which indicates that the entity can be referred
+ /// to from other translation units within the same module, and indirectly
+ /// from arbitrary other translation units through inline functions and
+ /// templates in the module interface.
+ ModuleLinkage,
+
/// \brief External linkage, which indicates that the entity can
/// be referred to from other translation units.
ExternalLinkage
@@ -74,15 +85,20 @@ inline bool isDiscardableGVALinkage(GVALinkage L) {
}
inline bool isExternallyVisible(Linkage L) {
- return L == ExternalLinkage || L == VisibleNoLinkage;
+ return L >= VisibleNoLinkage;
}
inline Linkage getFormalLinkage(Linkage L) {
- if (L == UniqueExternalLinkage)
+ switch (L) {
+ case UniqueExternalLinkage:
return ExternalLinkage;
- if (L == VisibleNoLinkage)
+ case VisibleNoLinkage:
return NoLinkage;
- return L;
+ case ModuleInternalLinkage:
+ return InternalLinkage;
+ default:
+ return L;
+ }
}
inline bool isExternalFormalLinkage(Linkage L) {
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/MemoryBufferCache.h b/contrib/llvm/tools/clang/include/clang/Basic/MemoryBufferCache.h
new file mode 100644
index 0000000..c79c3c4
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Basic/MemoryBufferCache.h
@@ -0,0 +1,80 @@
+//===- MemoryBufferCache.h - Cache for loaded memory buffers ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_MEMORYBUFFERCACHE_H
+#define LLVM_CLANG_BASIC_MEMORYBUFFERCACHE_H
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringMap.h"
+#include <memory>
+
+namespace llvm {
+class MemoryBuffer;
+} // end namespace llvm
+
+namespace clang {
+
+/// Manage memory buffers across multiple users.
+///
+/// Ensures that multiple users have a consistent view of each buffer. This is
+/// used by \a CompilerInstance when building PCMs to ensure that each \a
+/// ModuleManager sees the same files.
+///
+/// \a finalizeCurrentBuffers() should be called before creating a new user.
+/// This locks in the current buffers, ensuring that no buffer that has already
+/// been accessed can be purged, preventing use-after-frees.
+class MemoryBufferCache : public llvm::RefCountedBase<MemoryBufferCache> {
+ struct BufferEntry {
+ std::unique_ptr<llvm::MemoryBuffer> Buffer;
+
+ /// Track the timeline of when this was added to the cache.
+ unsigned Index;
+ };
+
+ /// Cache of buffers.
+ llvm::StringMap<BufferEntry> Buffers;
+
+ /// Monotonically increasing index.
+ unsigned NextIndex = 0;
+
+ /// Bumped to prevent "older" buffers from being removed.
+ unsigned FirstRemovableIndex = 0;
+
+public:
+ /// Store the Buffer under the Filename.
+ ///
+ /// \pre There is not already buffer is not already in the cache.
+ /// \return a reference to the buffer as a convenience.
+ llvm::MemoryBuffer &addBuffer(llvm::StringRef Filename,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer);
+
+ /// Try to remove a buffer from the cache.
+ ///
+ /// \return false on success, iff \c !isBufferFinal().
+ bool tryToRemoveBuffer(llvm::StringRef Filename);
+
+ /// Get a pointer to the buffer if it exists; else nullptr.
+ llvm::MemoryBuffer *lookupBuffer(llvm::StringRef Filename);
+
+ /// Check whether the buffer is final.
+ ///
+ /// \return true iff \a finalizeCurrentBuffers() has been called since the
+ /// buffer was added. This prevents buffers from being removed.
+ bool isBufferFinal(llvm::StringRef Filename);
+
+ /// Finalize the current buffers in the cache.
+ ///
+ /// Should be called when creating a new user to ensure previous uses aren't
+ /// invalidated.
+ void finalizeCurrentBuffers();
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_BASIC_MEMORYBUFFERCACHE_H
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Module.h b/contrib/llvm/tools/clang/include/clang/Basic/Module.h
index 31c5c7e..177175e 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Module.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Module.h
@@ -42,7 +42,17 @@ class IdentifierInfo;
/// \brief Describes the name of a module.
typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId;
-
+
+/// The signature of a module, which is a hash of the AST content.
+struct ASTFileSignature : std::array<uint32_t, 5> {
+ ASTFileSignature(std::array<uint32_t, 5> S = {{0}})
+ : std::array<uint32_t, 5>(std::move(S)) {}
+
+ explicit operator bool() const {
+ return *this != std::array<uint32_t, 5>({{0}});
+ }
+};
+
/// \brief Describes a module or submodule.
class Module {
public:
@@ -52,6 +62,18 @@ public:
/// \brief The location of the module definition.
SourceLocation DefinitionLoc;
+ enum ModuleKind {
+ /// \brief This is a module that was defined by a module map and built out
+ /// of header files.
+ ModuleMapModule,
+
+ /// \brief This is a C++ Modules TS module interface unit.
+ ModuleInterfaceUnit
+ };
+
+ /// \brief The kind of this module.
+ ModuleKind Kind = ModuleMapModule;
+
/// \brief The parent of this module. This will be NULL for the top-level
/// module.
Module *Parent;
@@ -61,11 +83,15 @@ public:
/// are found.
const DirectoryEntry *Directory;
+ /// \brief The presumed file name for the module map defining this module.
+ /// Only non-empty when building from preprocessed source.
+ std::string PresumedModuleMapFile;
+
/// \brief The umbrella header or directory.
llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella;
/// \brief The module signature.
- uint64_t Signature;
+ ASTFileSignature Signature;
/// \brief The name of the umbrella entry, as written in the module map.
std::string UmbrellaAsWritten;
@@ -128,11 +154,19 @@ public:
/// \brief Stored information about a header directive that was found in the
/// module map file but has not been resolved to a file.
struct UnresolvedHeaderDirective {
+ HeaderKind Kind = HK_Normal;
SourceLocation FileNameLoc;
std::string FileName;
- bool IsUmbrella;
+ bool IsUmbrella = false;
+ bool HasBuiltinHeader = false;
+ Optional<off_t> Size;
+ Optional<time_t> ModTime;
};
+ /// Headers that are mentioned in the module map file but that we have not
+ /// yet attempted to resolve to a file on the file system.
+ SmallVector<UnresolvedHeaderDirective, 1> UnresolvedHeaders;
+
/// \brief Headers that are mentioned in the module map file but could not be
/// found on the file system.
SmallVector<UnresolvedHeaderDirective, 1> MissingHeaders;
@@ -359,7 +393,9 @@ public:
/// \brief Retrieve the full name of this module, including the path from
/// its top-level module.
- std::string getFullModuleName() const;
+ /// \param AllowStringLiterals If \c true, components that might not be
+ /// lexically valid as identifiers will be emitted as string literals.
+ std::string getFullModuleName(bool AllowStringLiterals = false) const;
/// \brief Whether the full name of this module is equal to joining
/// \p nameParts with "."s.
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/ObjCRuntime.h b/contrib/llvm/tools/clang/include/clang/Basic/ObjCRuntime.h
index 78fc899..8dc259c 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/ObjCRuntime.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/ObjCRuntime.h
@@ -326,6 +326,20 @@ public:
}
}
+ /// Are the empty collection symbols available?
+ bool hasEmptyCollections() const {
+ switch (getKind()) {
+ default:
+ return false;
+ case MacOSX:
+ return getVersion() >= VersionTuple(10, 11);
+ case iOS:
+ return getVersion() >= VersionTuple(9);
+ case WatchOS:
+ return getVersion() >= VersionTuple(2);
+ }
+ }
+
/// \brief Try to parse an Objective-C runtime specification from the given
/// string.
///
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OpenCLImageTypes.def b/contrib/llvm/tools/clang/include/clang/Basic/OpenCLImageTypes.def
index 1ca12f6..0efed99 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/OpenCLImageTypes.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/OpenCLImageTypes.def
@@ -66,7 +66,7 @@ IMAGE_WRITE_TYPE(image2d_msaa, OCLImage2dMSAA, "cl_khr_gl_msaa_sharing")
IMAGE_WRITE_TYPE(image2d_array_msaa, OCLImage2dArrayMSAA, "cl_khr_gl_msaa_sharing")
IMAGE_WRITE_TYPE(image2d_msaa_depth, OCLImage2dMSAADepth, "cl_khr_gl_msaa_sharing")
IMAGE_WRITE_TYPE(image2d_array_msaa_depth, OCLImage2dArrayMSAADepth, "cl_khr_gl_msaa_sharing")
-IMAGE_WRITE_TYPE(image3d, OCLImage3d, "")
+IMAGE_WRITE_TYPE(image3d, OCLImage3d, "cl_khr_3d_image_writes")
IMAGE_READ_WRITE_TYPE(image1d, OCLImage1d, "")
IMAGE_READ_WRITE_TYPE(image1d_array, OCLImage1dArray, "")
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def
index 74ec26f..645ed52 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.def
@@ -168,6 +168,9 @@
#ifndef OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE
#define OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(Name)
#endif
+#ifndef OPENMP_TASKGROUP_CLAUSE
+#define OPENMP_TASKGROUP_CLAUSE(Name)
+#endif
// OpenMP directives.
OPENMP_DIRECTIVE(threadprivate)
@@ -270,6 +273,7 @@ OPENMP_CLAUSE(to, OMPToClause)
OPENMP_CLAUSE(from, OMPFromClause)
OPENMP_CLAUSE(use_device_ptr, OMPUseDevicePtrClause)
OPENMP_CLAUSE(is_device_ptr, OMPIsDevicePtrClause)
+OPENMP_CLAUSE(task_reduction, OMPTaskReductionClause)
// Clauses allowed for OpenMP directive 'parallel'.
OPENMP_PARALLEL_CLAUSE(if)
@@ -552,6 +556,7 @@ OPENMP_TASKLOOP_CLAUSE(priority)
OPENMP_TASKLOOP_CLAUSE(grainsize)
OPENMP_TASKLOOP_CLAUSE(nogroup)
OPENMP_TASKLOOP_CLAUSE(num_tasks)
+OPENMP_TASKLOOP_CLAUSE(reduction)
// Clauses allowed for OpenMP directive 'taskloop simd'.
OPENMP_TASKLOOP_SIMD_CLAUSE(if)
@@ -572,6 +577,7 @@ OPENMP_TASKLOOP_SIMD_CLAUSE(simdlen)
OPENMP_TASKLOOP_SIMD_CLAUSE(grainsize)
OPENMP_TASKLOOP_SIMD_CLAUSE(nogroup)
OPENMP_TASKLOOP_SIMD_CLAUSE(num_tasks)
+OPENMP_TASKLOOP_SIMD_CLAUSE(reduction)
// Clauses allowed for OpenMP directive 'critical'.
OPENMP_CRITICAL_CLAUSE(hint)
@@ -846,6 +852,10 @@ OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(aligned)
OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(safelen)
OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(simdlen)
+// Clauses allowed for OpenMP directive 'taskgroup'.
+OPENMP_TASKGROUP_CLAUSE(task_reduction)
+
+#undef OPENMP_TASKGROUP_CLAUSE
#undef OPENMP_TASKLOOP_SIMD_CLAUSE
#undef OPENMP_TASKLOOP_CLAUSE
#undef OPENMP_LINEAR_KIND
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.h b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.h
index 60b9fce..e003331 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/OpenMPKinds.h
@@ -234,6 +234,11 @@ bool isOpenMPTaskingDirective(OpenMPDirectiveKind Kind);
/// directives that need loop bound sharing across loops outlined in nested
/// functions
bool isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind);
+
+/// Return the captured regions of an OpenMP directive.
+void getOpenMPCaptureRegions(
+ llvm::SmallVectorImpl<OpenMPDirectiveKind> &CaptureRegions,
+ OpenMPDirectiveKind DKind);
}
#endif
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h
index 53ce95c..b2f14af 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h
@@ -329,6 +329,15 @@ public:
bool hasStorage() const { return DiagStorage != nullptr; }
+ /// Retrieve the string argument at the given index.
+ StringRef getStringArg(unsigned I) {
+ assert(DiagStorage && "No diagnostic storage?");
+ assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args");
+ assert(DiagStorage->DiagArgumentsKind[I]
+ == DiagnosticsEngine::ak_std_string && "Not a string arg");
+ return DiagStorage->DiagArgumentsStr[I];
+ }
+
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
unsigned I) {
PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def
index c81273e..71b1197 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.def
@@ -47,6 +47,9 @@ SANITIZER("kernel-address", KernelAddress)
// MemorySanitizer
SANITIZER("memory", Memory)
+// libFuzzer
+SANITIZER("fuzzer", Fuzzer)
+
// ThreadSanitizer
SANITIZER("thread", Thread)
@@ -64,7 +67,13 @@ SANITIZER("function", Function)
SANITIZER("integer-divide-by-zero", IntegerDivideByZero)
SANITIZER("nonnull-attribute", NonnullAttribute)
SANITIZER("null", Null)
+SANITIZER("nullability-arg", NullabilityArg)
+SANITIZER("nullability-assign", NullabilityAssign)
+SANITIZER("nullability-return", NullabilityReturn)
+SANITIZER_GROUP("nullability", Nullability,
+ NullabilityArg | NullabilityAssign | NullabilityReturn)
SANITIZER("object-size", ObjectSize)
+SANITIZER("pointer-overflow", PointerOverflow)
SANITIZER("return", Return)
SANITIZER("returns-nonnull-attribute", ReturnsNonnullAttribute)
SANITIZER("shift-base", ShiftBase)
@@ -100,9 +109,9 @@ SANITIZER("safe-stack", SafeStack)
SANITIZER_GROUP("undefined", Undefined,
Alignment | Bool | ArrayBounds | Enum | FloatCastOverflow |
FloatDivideByZero | IntegerDivideByZero | NonnullAttribute |
- Null | ObjectSize | Return | ReturnsNonnullAttribute |
- Shift | SignedIntegerOverflow | Unreachable | VLABound |
- Function | Vptr)
+ Null | ObjectSize | PointerOverflow | Return |
+ ReturnsNonnullAttribute | Shift | SignedIntegerOverflow |
+ Unreachable | VLABound | Function | Vptr)
// -fsanitize=undefined-trap is an alias for -fsanitize=undefined.
SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined)
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h
index bfa8e51..5317720 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Sanitizers.h
@@ -61,8 +61,8 @@ struct SanitizerSet {
Mask = Value ? (Mask | K) : (Mask & ~K);
}
- /// \brief Disable all sanitizers.
- void clear() { Mask = 0; }
+ /// Disable the sanitizers specified in \p K.
+ void clear(SanitizerMask K = SanitizerKind::All) { Mask &= ~K; }
/// \brief Returns true if at least one sanitizer is enabled.
bool empty() const { return Mask == 0; }
@@ -79,6 +79,12 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
/// this group enables.
SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
+/// Return the sanitizers which do not affect preprocessing.
+static inline SanitizerMask getPPTransparentSanitizers() {
+ return SanitizerKind::CFI | SanitizerKind::Integer |
+ SanitizerKind::Nullability | SanitizerKind::Undefined;
+}
+
} // end namespace clang
#endif
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h
index 006cf3d..12aa0e4 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h
@@ -262,6 +262,65 @@ public:
bool isInvalid() const { return !isValid(); }
};
+/// \brief Represents an unpacked "presumed" location which can be presented
+/// to the user.
+///
+/// A 'presumed' location can be modified by \#line and GNU line marker
+/// directives and is always the expansion point of a normal location.
+///
+/// You can get a PresumedLoc from a SourceLocation with SourceManager.
+class PresumedLoc {
+ const char *Filename;
+ unsigned Line, Col;
+ SourceLocation IncludeLoc;
+
+public:
+ PresumedLoc() : Filename(nullptr) {}
+ PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL)
+ : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) {}
+
+ /// \brief Return true if this object is invalid or uninitialized.
+ ///
+ /// This occurs when created with invalid source locations or when walking
+ /// off the top of a \#include stack.
+ bool isInvalid() const { return Filename == nullptr; }
+ bool isValid() const { return Filename != nullptr; }
+
+ /// \brief Return the presumed filename of this location.
+ ///
+ /// This can be affected by \#line etc.
+ const char *getFilename() const {
+ assert(isValid());
+ return Filename;
+ }
+
+ /// \brief Return the presumed line number of this location.
+ ///
+ /// This can be affected by \#line etc.
+ unsigned getLine() const {
+ assert(isValid());
+ return Line;
+ }
+
+ /// \brief Return the presumed column number of this location.
+ ///
+ /// This cannot be affected by \#line, but is packaged here for convenience.
+ unsigned getColumn() const {
+ assert(isValid());
+ return Col;
+ }
+
+ /// \brief Return the presumed include location of this location.
+ ///
+ /// This can be affected by GNU linemarker directives.
+ SourceLocation getIncludeLoc() const {
+ assert(isValid());
+ return IncludeLoc;
+ }
+};
+
+class FileEntry;
+
/// \brief A SourceLocation and its associated SourceManager.
///
/// This is useful for argument passing to functions that expect both objects.
@@ -274,6 +333,12 @@ public:
explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM)
: SourceLocation(Loc), SrcMgr(&SM) {}
+ bool hasManager() const {
+ bool hasSrcMgr = SrcMgr != nullptr;
+ assert(hasSrcMgr == isValid() && "FullSourceLoc has location but no manager");
+ return hasSrcMgr;
+ }
+
/// \pre This FullSourceLoc has an associated SourceManager.
const SourceManager &getManager() const {
assert(SrcMgr && "SourceManager is NULL.");
@@ -284,6 +349,13 @@ public:
FullSourceLoc getExpansionLoc() const;
FullSourceLoc getSpellingLoc() const;
+ FullSourceLoc getFileLoc() const;
+ std::pair<FullSourceLoc, FullSourceLoc> getImmediateExpansionRange() const;
+ PresumedLoc getPresumedLoc(bool UseLineDirectives = true) const;
+ bool isMacroArgExpansion(FullSourceLoc *StartLoc = nullptr) const;
+ FullSourceLoc getImmediateMacroCallerLoc() const;
+ std::pair<FullSourceLoc, StringRef> getModuleImportLoc() const;
+ unsigned getFileOffset() const;
unsigned getExpansionLineNumber(bool *Invalid = nullptr) const;
unsigned getExpansionColumnNumber(bool *Invalid = nullptr) const;
@@ -293,6 +365,12 @@ public:
const char *getCharacterData(bool *Invalid = nullptr) const;
+ unsigned getLineNumber(bool *Invalid = nullptr) const;
+ unsigned getColumnNumber(bool *Invalid = nullptr) const;
+
+ std::pair<FullSourceLoc, FullSourceLoc> getExpansionRange() const;
+
+ const FileEntry *getFileEntry() const;
/// \brief Return a StringRef to the source buffer data for the
/// specified FileID.
@@ -321,8 +399,7 @@ public:
}
/// \brief Comparison function class, useful for sorting FullSourceLocs.
- struct BeforeThanCompare : public std::binary_function<FullSourceLoc,
- FullSourceLoc, bool> {
+ struct BeforeThanCompare {
bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const {
return lhs.isBeforeInTranslationUnitThan(rhs);
}
@@ -346,50 +423,6 @@ public:
};
-/// \brief Represents an unpacked "presumed" location which can be presented
-/// to the user.
-///
-/// A 'presumed' location can be modified by \#line and GNU line marker
-/// directives and is always the expansion point of a normal location.
-///
-/// You can get a PresumedLoc from a SourceLocation with SourceManager.
-class PresumedLoc {
- const char *Filename;
- unsigned Line, Col;
- SourceLocation IncludeLoc;
-public:
- PresumedLoc() : Filename(nullptr) {}
- PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL)
- : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) {
- }
-
- /// \brief Return true if this object is invalid or uninitialized.
- ///
- /// This occurs when created with invalid source locations or when walking
- /// off the top of a \#include stack.
- bool isInvalid() const { return Filename == nullptr; }
- bool isValid() const { return Filename != nullptr; }
-
- /// \brief Return the presumed filename of this location.
- ///
- /// This can be affected by \#line etc.
- const char *getFilename() const { assert(isValid()); return Filename; }
-
- /// \brief Return the presumed line number of this location.
- ///
- /// This can be affected by \#line etc.
- unsigned getLine() const { assert(isValid()); return Line; }
-
- /// \brief Return the presumed column number of this location.
- ///
- /// This cannot be affected by \#line, but is packaged here for convenience.
- unsigned getColumn() const { assert(isValid()); return Col; }
-
- /// \brief Return the presumed include location of this location.
- ///
- /// This can be affected by GNU linemarker directives.
- SourceLocation getIncludeLoc() const { assert(isValid()); return IncludeLoc; }
-};
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h
index c8fe2ab..ed3f8df 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h
@@ -80,9 +80,19 @@ namespace SrcMgr {
/// system_header is seen or in various other cases.
///
enum CharacteristicKind {
- C_User, C_System, C_ExternCSystem
+ C_User, C_System, C_ExternCSystem, C_User_ModuleMap, C_System_ModuleMap
};
+ /// Determine whether a file / directory characteristic is for system code.
+ inline bool isSystem(CharacteristicKind CK) {
+ return CK != C_User && CK != C_User_ModuleMap;
+ }
+
+ /// Determine whether a file characteristic is for a module map.
+ inline bool isModuleMap(CharacteristicKind CK) {
+ return CK == C_User_ModuleMap || CK == C_System_ModuleMap;
+ }
+
/// \brief One instance of this struct is kept for every file loaded or used.
///
/// This object owns the MemoryBuffer object.
@@ -251,12 +261,14 @@ namespace SrcMgr {
/// preprocessing of this \#include, including this SLocEntry.
///
/// Zero means the preprocessor didn't provide such info for this SLocEntry.
- unsigned NumCreatedFIDs;
+ unsigned NumCreatedFIDs : 31;
+
+ /// \brief Whether this FileInfo has any \#line directives.
+ unsigned HasLineDirectives : 1;
- /// \brief Contains the ContentCache* and the bits indicating the
- /// characteristic of the file and whether it has \#line info, all
- /// bitmangled together.
- uintptr_t Data;
+ /// \brief The content cache and the characteristic of the file.
+ llvm::PointerIntPair<const ContentCache*, 3, CharacteristicKind>
+ ContentAndKind;
friend class clang::SourceManager;
friend class clang::ASTWriter;
@@ -269,10 +281,9 @@ namespace SrcMgr {
FileInfo X;
X.IncludeLoc = IL.getRawEncoding();
X.NumCreatedFIDs = 0;
- X.Data = (uintptr_t)Con;
- assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned");
- assert((unsigned)FileCharacter < 4 && "invalid file character");
- X.Data |= (unsigned)FileCharacter;
+ X.HasLineDirectives = false;
+ X.ContentAndKind.setPointer(Con);
+ X.ContentAndKind.setInt(FileCharacter);
return X;
}
@@ -280,22 +291,22 @@ namespace SrcMgr {
return SourceLocation::getFromRawEncoding(IncludeLoc);
}
- const ContentCache* getContentCache() const {
- return reinterpret_cast<const ContentCache*>(Data & ~uintptr_t(7));
+ const ContentCache *getContentCache() const {
+ return ContentAndKind.getPointer();
}
/// \brief Return whether this is a system header or not.
CharacteristicKind getFileCharacteristic() const {
- return (CharacteristicKind)(Data & 3);
+ return ContentAndKind.getInt();
}
/// \brief Return true if this FileID has \#line directives in it.
- bool hasLineDirectives() const { return (Data & 4) != 0; }
+ bool hasLineDirectives() const { return HasLineDirectives; }
/// \brief Set the flag that indicates that this FileID has
/// line table entries associated with it.
void setHasLineDirectives() {
- Data |= 4;
+ HasLineDirectives = true;
}
};
@@ -407,6 +418,8 @@ namespace SrcMgr {
};
public:
+ SLocEntry() : Offset(), IsExpansion(), File() {}
+
unsigned getOffset() const { return Offset; }
bool isExpansion() const { return IsExpansion; }
@@ -722,6 +735,10 @@ public:
void clearIDTables();
+ /// Initialize this source manager suitably to replay the compilation
+ /// described by \p Old. Requires that \p Old outlive \p *this.
+ void initializeForReplay(const SourceManager &Old);
+
DiagnosticsEngine &getDiagnostics() const { return Diag; }
FileManager &getFileManager() const { return FileMgr; }
@@ -785,9 +802,8 @@ public:
FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos,
SrcMgr::CharacteristicKind FileCharacter,
int LoadedID = 0, unsigned LoadedOffset = 0) {
- const SrcMgr::ContentCache *
- IR = getOrCreateContentCache(SourceFile,
- /*isSystemFile=*/FileCharacter != SrcMgr::C_User);
+ const SrcMgr::ContentCache *IR =
+ getOrCreateContentCache(SourceFile, isSystem(FileCharacter));
assert(IR && "getOrCreateContentCache() cannot return NULL");
return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset);
}
@@ -865,7 +881,7 @@ public:
const FileEntry *NewFile);
/// \brief Returns true if the file contents have been overridden.
- bool isFileOverridden(const FileEntry *File) {
+ bool isFileOverridden(const FileEntry *File) const {
if (OverriddenFilesInfo) {
if (OverriddenFilesInfo->OverriddenFilesWithBuffer.count(File))
return true;
@@ -1356,7 +1372,7 @@ public:
/// \brief Returns if a SourceLocation is in a system header.
bool isInSystemHeader(SourceLocation Loc) const {
- return getFileCharacteristic(Loc) != SrcMgr::C_User;
+ return isSystem(getFileCharacteristic(Loc));
}
/// \brief Returns if a SourceLocation is in an "extern C" system header.
@@ -1399,10 +1415,9 @@ public:
/// specified by Loc.
///
/// If FilenameID is -1, it is considered to be unspecified.
- void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID);
void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID,
bool IsFileEntry, bool IsFileExit,
- bool IsSystemHeader, bool IsExternCHeader);
+ SrcMgr::CharacteristicKind FileKind);
/// \brief Determine if the source manager has a line table.
bool hasLineTable() const { return LineTable != nullptr; }
@@ -1474,6 +1489,17 @@ public:
/// \returns true if LHS source location comes before RHS, false otherwise.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const;
+ /// \brief Determines whether the two decomposed source location is in the
+ /// same translation unit. As a byproduct, it also calculates the order
+ /// of the source locations in case they are in the same TU.
+ ///
+ /// \returns Pair of bools the first component is true if the two locations
+ /// are in the same TU. The second bool is true if the first is true
+ /// and \p LOffs is before \p ROffs.
+ std::pair<bool, bool>
+ isInTheSameTranslationUnit(std::pair<FileID, unsigned> &LOffs,
+ std::pair<FileID, unsigned> &ROffs) const;
+
/// \brief Determines the order of 2 source locations in the "source location
/// address space".
bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const {
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h
index e65c97b..9403dea 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/SourceManagerInternals.h
@@ -102,8 +102,6 @@ public:
unsigned getNumFilenames() const { return FilenamesByID.size(); }
void AddLineNote(FileID FID, unsigned Offset,
- unsigned LineNo, int FilenameID);
- void AddLineNote(FileID FID, unsigned Offset,
unsigned LineNo, int FilenameID,
unsigned EntryExit, SrcMgr::CharacteristicKind FileKind);
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h b/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h
index 369a36f..50fb936 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h
@@ -82,11 +82,12 @@ namespace clang {
/// \brief Structure that packs information about the type specifiers that
/// were written in a particular type specifier sequence.
struct WrittenBuiltinSpecs {
- /*DeclSpec::TST*/ unsigned Type : 5;
+ static_assert(TST_error < 1 << 6, "Type bitfield not wide enough for TST");
+ /*DeclSpec::TST*/ unsigned Type : 6;
/*DeclSpec::TSS*/ unsigned Sign : 2;
/*DeclSpec::TSW*/ unsigned Width : 2;
unsigned ModeAttr : 1;
- };
+ };
/// \brief A C++ access specifier (public, private, protected), plus the
/// special value "none" which means different things in different contexts.
@@ -235,7 +236,7 @@ namespace clang {
CC_X86ThisCall, // __attribute__((thiscall))
CC_X86VectorCall, // __attribute__((vectorcall))
CC_X86Pascal, // __attribute__((pascal))
- CC_X86_64Win64, // __attribute__((ms_abi))
+ CC_Win64, // __attribute__((ms_abi))
CC_X86_64SysV, // __attribute__((sysv_abi))
CC_X86RegCall, // __attribute__((regcall))
CC_AAPCS, // __attribute__((pcs("aapcs")))
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td b/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td
index 67a5ab7..0d21845 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td
@@ -43,7 +43,7 @@ def ObjCAtSynchronizedStmt : Stmt;
def ObjCForCollectionStmt : Stmt;
def ObjCAutoreleasePoolStmt : Stmt;
-// C++ statments
+// C++ statements
def CXXCatchStmt : Stmt;
def CXXTryStmt : Stmt;
def CXXForRangeStmt : Stmt;
@@ -150,6 +150,7 @@ def CXXFoldExpr : DStmt<Expr>;
// C++ Coroutines TS expressions
def CoroutineSuspendExpr : DStmt<Expr, 1>;
def CoawaitExpr : DStmt<CoroutineSuspendExpr>;
+def DependentCoawaitExpr : DStmt<Expr>;
def CoyieldExpr : DStmt<CoroutineSuspendExpr>;
// Obj-C Expressions.
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h
index 5d45e16..8f4f5e9 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h
@@ -150,6 +150,16 @@ namespace clang {
};
}
+ /// \brief Nios2 builtins
+ namespace Nios2 {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
+#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+#include "clang/Basic/BuiltinsNios2.def"
+ LastTSBuiltin
+ };
+ }
+
/// \brief MIPS builtins
namespace Mips {
enum {
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h
index 208f8e8..d1a9ea8 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h
@@ -23,6 +23,7 @@
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -154,7 +155,7 @@ public:
/// typedef void* __builtin_va_list;
VoidPtrBuiltinVaList,
- /// __builtin_va_list as defind by the AArch64 ABI
+ /// __builtin_va_list as defined by the AArch64 ABI
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055a/IHI0055A_aapcs64.pdf
AArch64ABIBuiltinVaList,
@@ -168,7 +169,7 @@ public:
PowerABIBuiltinVaList,
/// __builtin_va_list as defined by the x86-64 ABI:
- /// http://www.x86-64.org/documentation/abi.pdf
+ /// http://refspecs.linuxbase.org/elf/x86_64-abi-0.21.pdf
X86_64ABIBuiltinVaList,
/// __builtin_va_list as defined by ARM AAPCS ABI
@@ -225,6 +226,20 @@ protected:
public:
IntType getSizeType() const { return SizeType; }
+ IntType getSignedSizeType() const {
+ switch (SizeType) {
+ case UnsignedShort:
+ return SignedShort;
+ case UnsignedInt:
+ return SignedInt;
+ case UnsignedLong:
+ return SignedLong;
+ case UnsignedLongLong:
+ return SignedLongLong;
+ default:
+ llvm_unreachable("Invalid SizeType");
+ }
+ }
IntType getIntMaxType() const { return IntMaxType; }
IntType getUIntMaxType() const {
return getCorrespondingUnsignedType(IntMaxType);
@@ -823,8 +838,9 @@ public:
/// \brief Set forced language options.
///
/// Apply changes to the target information with respect to certain
- /// language options which change the target configuration.
- virtual void adjust(const LangOptions &Opts);
+ /// language options which change the target configuration and adjust
+ /// the language based on the target options where applicable.
+ virtual void adjust(LangOptions &Opts);
/// \brief Adjust target options based on codegen options.
virtual void adjustTargetOptions(const CodeGenOptions &CGOpts,
@@ -953,6 +969,14 @@ public:
return *AddrSpaceMap;
}
+ /// \brief Return an AST address space which can be used opportunistically
+ /// for constant global memory. It must be possible to convert pointers into
+ /// this address space to LangAS::Default. If no such address space exists,
+ /// this may return None, and such optimizations will be disabled.
+ virtual llvm::Optional<unsigned> getConstantAddressSpace() const {
+ return LangAS::Default;
+ }
+
/// \brief Retrieve the name of the platform as it is used in the
/// availability attribute.
StringRef getPlatformName() const { return PlatformName; }
@@ -1032,6 +1056,21 @@ public:
return LangAS::opencl_global;
}
+ /// \returns Target specific vtbl ptr address space.
+ virtual unsigned getVtblPtrAddressSpace() const {
+ return 0;
+ }
+
+ /// \returns If a target requires an address within a target specific address
+ /// space \p AddressSpace to be converted in order to be used, then return the
+ /// corresponding target specific DWARF address space.
+ ///
+ /// \returns Otherwise return None and no conversion will be emitted in the
+ /// DWARF.
+ virtual Optional<unsigned> getDWARFAddressSpace(unsigned AddressSpace) const {
+ return None;
+ }
+
/// \brief Check the target is valid after it is fully initialized.
virtual bool validateTarget(DiagnosticsEngine &Diags) const {
return true;
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h
index 2889cce..9bb19c7 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/TargetOptions.h
@@ -18,14 +18,14 @@
#include <string>
#include <vector>
#include "clang/Basic/OpenCLOptions.h"
+#include "llvm/Target/TargetOptions.h"
namespace clang {
/// \brief Options for controlling the target.
class TargetOptions {
public:
- /// If given, the name of the target triple to compile for. If not given the
- /// target will be selected to match the host.
+ /// The name of the target triple to compile for.
std::string Triple;
/// When compiling for the device side, contains the triple used to compile
@@ -42,7 +42,7 @@ public:
std::string ABI;
/// The EABI version to use
- std::string EABIVersion;
+ llvm::EABI EABIVersion;
/// If given, the version string of the linker in use.
std::string LinkerVersion;
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TemplateKinds.h b/contrib/llvm/tools/clang/include/clang/Basic/TemplateKinds.h
index aed287b..ac99ad1 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TemplateKinds.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/TemplateKinds.h
@@ -26,13 +26,21 @@ enum TemplateNameKind {
TNK_Function_template,
/// The name refers to a template whose specialization produces a
/// type. The template itself could be a class template, template
- /// template parameter, or C++0x template alias.
+ /// template parameter, or template alias.
TNK_Type_template,
/// The name refers to a variable template whose specialization produces a
/// variable.
TNK_Var_template,
- /// The name refers to a dependent template name. Whether the
- /// template name is assumed to refer to a type template or a
+ /// The name refers to a dependent template name:
+ /// \code
+ /// template<typename MetaFun, typename T1, typename T2> struct apply2 {
+ /// typedef typename MetaFun::template apply<T1, T2>::type type;
+ /// };
+ /// \endcode
+ ///
+ /// Here, "apply" is a dependent template name within the typename
+ /// specifier in the typedef. "apply" is a nested template, and
+ /// whether the template name is assumed to refer to a type template or a
/// function template depends on the context in which the template
/// name occurs.
TNK_Dependent_template_name
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def b/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def
index 104b053..be67663 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def
@@ -411,6 +411,7 @@ TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS)
// MSVC12.0 / VS2013 Type Traits
TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYMS)
+TYPE_TRAIT_1(__is_trivially_destructible, IsTriviallyDestructible, KEYCXX)
TYPE_TRAIT_1(__is_nothrow_destructible, IsNothrowDestructible, KEYMS)
TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX)
TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX)
@@ -432,13 +433,13 @@ TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
TYPE_TRAIT_1(__has_trivial_destructor, HasTrivialDestructor, KEYCXX)
TYPE_TRAIT_1(__has_virtual_destructor, HasVirtualDestructor, KEYCXX)
TYPE_TRAIT_1(__is_abstract, IsAbstract, KEYCXX)
+TYPE_TRAIT_1(__is_aggregate, IsAggregate, KEYCXX)
TYPE_TRAIT_2(__is_base_of, IsBaseOf, KEYCXX)
TYPE_TRAIT_1(__is_class, IsClass, KEYCXX)
TYPE_TRAIT_2(__is_convertible_to, IsConvertibleTo, KEYCXX)
TYPE_TRAIT_1(__is_empty, IsEmpty, KEYCXX)
TYPE_TRAIT_1(__is_enum, IsEnum, KEYCXX)
TYPE_TRAIT_1(__is_final, IsFinal, KEYCXX)
-// Tentative name - there's no implementation of std::is_literal_type yet.
TYPE_TRAIT_1(__is_literal, IsLiteral, KEYCXX)
// Name for GCC 4.6 compatibility - people have already written libraries using
// this name unfortunately.
@@ -787,6 +788,11 @@ ANNOTATION(pragma_openmp_end)
// handles #pragma loop ... directives.
ANNOTATION(pragma_loop_hint)
+ANNOTATION(pragma_fp)
+
+// Annotation for the attribute pragma directives - #pragma clang attribute ...
+ANNOTATION(pragma_attribute)
+
// Annotations for module import translated from #include etc.
ANNOTATION(module_include)
ANNOTATION(module_begin)
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h b/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h
index 730ecba..6aadf79 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h
@@ -31,6 +31,7 @@ namespace clang {
UTT_HasTrivialDestructor,
UTT_HasVirtualDestructor,
UTT_IsAbstract,
+ UTT_IsAggregate,
UTT_IsArithmetic,
UTT_IsArray,
UTT_IsClass,
@@ -64,6 +65,7 @@ namespace clang {
UTT_IsStandardLayout,
UTT_IsTrivial,
UTT_IsTriviallyCopyable,
+ UTT_IsTriviallyDestructible,
UTT_IsUnion,
UTT_IsUnsigned,
UTT_IsVoid,
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h b/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h
index 39dab6c..e52b345 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h
@@ -161,7 +161,7 @@ public:
directory_iterator &increment(std::error_code &EC) {
assert(Impl && "attempting to increment past end");
EC = Impl->increment();
- if (EC || !Impl->CurrentEntry.isStatusKnown())
+ if (!Impl->CurrentEntry.isStatusKnown())
Impl.reset(); // Normalize the end iterator to Impl == nullptr.
return *this;
}
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Visibility.h b/contrib/llvm/tools/clang/include/clang/Basic/Visibility.h
index 6ac52ed..cc839d7 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Visibility.h
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Visibility.h
@@ -75,6 +75,9 @@ public:
static LinkageInfo none() {
return LinkageInfo(NoLinkage, DefaultVisibility, false);
}
+ static LinkageInfo visible_none() {
+ return LinkageInfo(VisibleNoLinkage, DefaultVisibility, false);
+ }
Linkage getLinkage() const { return (Linkage)linkage_; }
Visibility getVisibility() const { return (Visibility)visibility_; }
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/XRayLists.h b/contrib/llvm/tools/clang/include/clang/Basic/XRayLists.h
new file mode 100644
index 0000000..8cfea70
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Basic/XRayLists.h
@@ -0,0 +1,55 @@
+//===--- XRayLists.h - XRay automatic attribution ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters for always/never XRay instrumenting certain functions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_XRAYLISTS_H
+#define LLVM_CLANG_BASIC_XRAYLISTS_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include <memory>
+
+namespace clang {
+
+class XRayFunctionFilter {
+ std::unique_ptr<llvm::SpecialCaseList> AlwaysInstrument;
+ std::unique_ptr<llvm::SpecialCaseList> NeverInstrument;
+ SourceManager &SM;
+
+public:
+ XRayFunctionFilter(ArrayRef<std::string> AlwaysInstrumentPaths,
+ ArrayRef<std::string> NeverInstrumentPaths,
+ SourceManager &SM);
+
+ enum class ImbueAttribute {
+ NONE,
+ ALWAYS,
+ NEVER,
+ ALWAYS_ARG1,
+ };
+
+ ImbueAttribute shouldImbueFunction(StringRef FunctionName) const;
+
+ ImbueAttribute
+ shouldImbueFunctionsInFile(StringRef Filename,
+ StringRef Category = StringRef()) const;
+
+ ImbueAttribute shouldImbueLocation(SourceLocation Loc,
+ StringRef Category = StringRef()) const;
+};
+
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td b/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td
index 5605fc6..ad8d679 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td
@@ -1362,7 +1362,7 @@ def SCALAR_SHL: SInst<"vshl", "sss", "SlSUl">;
def SCALAR_QSHL: SInst<"vqshl", "sss", "ScSsSiSlSUcSUsSUiSUl">;
// Scalar Saturating Rounding Shift Left
def SCALAR_QRSHL: SInst<"vqrshl", "sss", "ScSsSiSlSUcSUsSUiSUl">;
-// Scalar Shift Rouding Left
+// Scalar Shift Rounding Left
def SCALAR_RSHL: SInst<"vrshl", "sss", "SlSUl">;
////////////////////////////////////////////////////////////////////////////////
diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/BackendUtil.h b/contrib/llvm/tools/clang/include/clang/CodeGen/BackendUtil.h
index c6abc6e..bb105cb 100644
--- a/contrib/llvm/tools/clang/include/clang/CodeGen/BackendUtil.h
+++ b/contrib/llvm/tools/clang/include/clang/CodeGen/BackendUtil.h
@@ -15,6 +15,8 @@
#include <memory>
namespace llvm {
+ class BitcodeModule;
+ template <typename T> class Expected;
class Module;
class MemoryBufferRef;
}
@@ -44,6 +46,9 @@ namespace clang {
void EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts,
llvm::MemoryBufferRef Buf);
+
+ llvm::Expected<llvm::BitcodeModule>
+ FindThinLTOModule(llvm::MemoryBufferRef MBRef);
}
#endif
diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h b/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h
index 2703f29..d1f0512 100644
--- a/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h
+++ b/contrib/llvm/tools/clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -461,7 +461,7 @@ class CGFunctionInfo final
unsigned EffectiveCallingConvention : 8;
/// The clang::CallingConv that this was originally created with.
- unsigned ASTCallingConvention : 8;
+ unsigned ASTCallingConvention : 7;
/// Whether this is an instance method.
unsigned InstanceMethod : 1;
@@ -475,6 +475,9 @@ class CGFunctionInfo final
/// Whether this function is returns-retained.
unsigned ReturnsRetained : 1;
+ /// Whether this function saved caller registers.
+ unsigned NoCallerSavedRegs : 1;
+
/// How many arguments to pass inreg.
unsigned HasRegParm : 1;
unsigned RegParm : 3;
@@ -560,6 +563,9 @@ public:
/// is not always reliable for call sites.
bool isReturnsRetained() const { return ReturnsRetained; }
+ /// Whether this function no longer saves caller registers.
+ bool isNoCallerSavedRegs() const { return NoCallerSavedRegs; }
+
/// getASTCallingConvention() - Return the AST-specified calling
/// convention.
CallingConv getASTCallingConvention() const {
@@ -583,10 +589,9 @@ public:
unsigned getRegParm() const { return RegParm; }
FunctionType::ExtInfo getExtInfo() const {
- return FunctionType::ExtInfo(isNoReturn(),
- getHasRegParm(), getRegParm(),
- getASTCallingConvention(),
- isReturnsRetained());
+ return FunctionType::ExtInfo(isNoReturn(), getHasRegParm(), getRegParm(),
+ getASTCallingConvention(), isReturnsRetained(),
+ isNoCallerSavedRegs());
}
CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
@@ -623,6 +628,7 @@ public:
ID.AddBoolean(ChainCall);
ID.AddBoolean(NoReturn);
ID.AddBoolean(ReturnsRetained);
+ ID.AddBoolean(NoCallerSavedRegs);
ID.AddBoolean(HasRegParm);
ID.AddInteger(RegParm);
ID.AddInteger(Required.getOpaqueData());
@@ -648,6 +654,7 @@ public:
ID.AddBoolean(ChainCall);
ID.AddBoolean(info.getNoReturn());
ID.AddBoolean(info.getProducesResult());
+ ID.AddBoolean(info.getNoCallerSavedRegs());
ID.AddBoolean(info.getHasRegParm());
ID.AddInteger(info.getRegParm());
ID.AddInteger(required.getOpaqueData());
diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h
index e7b7435..615e55c 100644
--- a/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h
+++ b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenABITypes.h
@@ -16,7 +16,7 @@
//
// It allows other clients, like LLDB, to determine the LLVM types that are
// actually used in function calls, which makes it possible to then determine
-// the acutal ABI locations (e.g. registers, stack locations, etc.) that
+// the actual ABI locations (e.g. registers, stack locations, etc.) that
// these parameters are stored in.
//
//===----------------------------------------------------------------------===//
@@ -31,6 +31,8 @@
namespace llvm {
class DataLayout;
class Module;
+ class FunctionType;
+ class Type;
}
namespace clang {
@@ -70,6 +72,12 @@ const CGFunctionInfo &arrangeFreeFunctionCall(CodeGenModule &CGM,
FunctionType::ExtInfo info,
RequiredArgs args);
+// Returns null if the function type is incomplete and can't be lowered.
+llvm::FunctionType *convertFreeFunctionType(CodeGenModule &CGM,
+ const FunctionDecl *FD);
+
+llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T);
+
} // end namespace CodeGen
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h
index cc38e24..5a18a9d 100644
--- a/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h
+++ b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h
@@ -23,14 +23,36 @@ class BackendConsumer;
class CodeGenAction : public ASTFrontendAction {
private:
+ // Let BackendConsumer access LinkModule.
+ friend class BackendConsumer;
+
+ /// Info about module to link into a module we're generating.
+ struct LinkModule {
+ /// The module to link in.
+ std::unique_ptr<llvm::Module> Module;
+
+ /// If true, we set attributes on Module's functions according to our
+ /// CodeGenOptions and LangOptions, as though we were generating the
+ /// function ourselves.
+ bool PropagateAttrs;
+
+ /// If true, we use LLVM module internalizer.
+ bool Internalize;
+
+ /// Bitwise combination of llvm::LinkerFlags used when we link the module.
+ unsigned LinkFlags;
+ };
+
unsigned Act;
std::unique_ptr<llvm::Module> TheModule;
- // Vector of {Linker::Flags, Module*} pairs to specify bitcode
- // modules to link in using corresponding linker flags.
- SmallVector<std::pair<unsigned, llvm::Module *>, 4> LinkModules;
+
+ /// Bitcode modules to link in to our module.
+ SmallVector<LinkModule, 4> LinkModules;
llvm::LLVMContext *VMContext;
bool OwnsVMContext;
+ std::unique_ptr<llvm::Module> loadModule(llvm::MemoryBufferRef MBRef);
+
protected:
/// Create a new code generation action. If the optional \p _VMContext
/// parameter is supplied, the action uses it without taking ownership,
@@ -49,13 +71,6 @@ protected:
public:
~CodeGenAction() override;
- /// setLinkModule - Set the link module to be used by this action. If a link
- /// module is not provided, and CodeGenOptions::LinkBitcodeFile is non-empty,
- /// the action will load it from the specified file.
- void addLinkModule(llvm::Module *Mod, unsigned LinkFlags) {
- LinkModules.push_back(std::make_pair(LinkFlags, Mod));
- }
-
/// Take the generated LLVM module, for use after the action has been run.
/// The result may be null on failure.
std::unique_ptr<llvm::Module> takeModule();
diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitBuilder.h b/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitBuilder.h
new file mode 100644
index 0000000..113d86d
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitBuilder.h
@@ -0,0 +1,561 @@
+//===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class provides a convenient interface for building complex
+// global initializers of the sort that are frequently required for
+// language ABIs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
+#define LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalValue.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/CodeGen/ConstantInitFuture.h"
+
+#include <vector>
+
+namespace clang {
+namespace CodeGen {
+
+class CodeGenModule;
+
+/// A convenience builder class for complex constant initializers,
+/// especially for anonymous global structures used by various language
+/// runtimes.
+///
+/// The basic usage pattern is expected to be something like:
+/// ConstantInitBuilder builder(CGM);
+/// auto toplevel = builder.beginStruct();
+/// toplevel.addInt(CGM.SizeTy, widgets.size());
+/// auto widgetArray = builder.beginArray();
+/// for (auto &widget : widgets) {
+/// auto widgetDesc = widgetArray.beginStruct();
+/// widgetDesc.addInt(CGM.SizeTy, widget.getPower());
+/// widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName()));
+/// widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl()));
+/// widgetDesc.finishAndAddTo(widgetArray);
+/// }
+/// widgetArray.finishAndAddTo(toplevel);
+/// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align,
+/// /*constant*/ true);
+class ConstantInitBuilderBase {
+ struct SelfReference {
+ llvm::GlobalVariable *Dummy;
+ llvm::SmallVector<llvm::Constant*, 4> Indices;
+
+ SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {}
+ };
+ CodeGenModule &CGM;
+ llvm::SmallVector<llvm::Constant*, 16> Buffer;
+ std::vector<SelfReference> SelfReferences;
+ bool Frozen = false;
+
+ friend class ConstantInitFuture;
+ friend class ConstantAggregateBuilderBase;
+ template <class, class>
+ friend class ConstantAggregateBuilderTemplateBase;
+
+protected:
+ explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {}
+
+ ~ConstantInitBuilderBase() {
+ assert(Buffer.empty() && "didn't claim all values out of buffer");
+ assert(SelfReferences.empty() && "didn't apply all self-references");
+ }
+
+private:
+ llvm::GlobalVariable *createGlobal(llvm::Constant *initializer,
+ const llvm::Twine &name,
+ CharUnits alignment,
+ bool constant = false,
+ llvm::GlobalValue::LinkageTypes linkage
+ = llvm::GlobalValue::InternalLinkage,
+ unsigned addressSpace = 0);
+
+ ConstantInitFuture createFuture(llvm::Constant *initializer);
+
+ void setGlobalInitializer(llvm::GlobalVariable *GV,
+ llvm::Constant *initializer);
+
+ void resolveSelfReferences(llvm::GlobalVariable *GV);
+
+ void abandon(size_t newEnd);
+};
+
+/// A concrete base class for struct and array aggregate
+/// initializer builders.
+class ConstantAggregateBuilderBase {
+protected:
+ ConstantInitBuilderBase &Builder;
+ ConstantAggregateBuilderBase *Parent;
+ size_t Begin;
+ mutable size_t CachedOffsetEnd = 0;
+ bool Finished = false;
+ bool Frozen = false;
+ bool Packed = false;
+ mutable CharUnits CachedOffsetFromGlobal;
+
+ llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
+ return Builder.Buffer;
+ }
+
+ const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
+ return Builder.Buffer;
+ }
+
+ ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder,
+ ConstantAggregateBuilderBase *parent)
+ : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) {
+ if (parent) {
+ assert(!parent->Frozen && "parent already has child builder active");
+ parent->Frozen = true;
+ } else {
+ assert(!builder.Frozen && "builder already has child builder active");
+ builder.Frozen = true;
+ }
+ }
+
+ ~ConstantAggregateBuilderBase() {
+ assert(Finished && "didn't finish aggregate builder");
+ }
+
+ void markFinished() {
+ assert(!Frozen && "child builder still active");
+ assert(!Finished && "builder already finished");
+ Finished = true;
+ if (Parent) {
+ assert(Parent->Frozen &&
+ "parent not frozen while child builder active");
+ Parent->Frozen = false;
+ } else {
+ assert(Builder.Frozen &&
+ "builder not frozen while child builder active");
+ Builder.Frozen = false;
+ }
+ }
+
+public:
+ // Not copyable.
+ ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &) = delete;
+ ConstantAggregateBuilderBase &operator=(const ConstantAggregateBuilderBase &)
+ = delete;
+
+ // Movable, mostly to allow returning. But we have to write this out
+ // properly to satisfy the assert in the destructor.
+ ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other)
+ : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin),
+ CachedOffsetEnd(other.CachedOffsetEnd),
+ Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed),
+ CachedOffsetFromGlobal(other.CachedOffsetFromGlobal) {
+ other.Finished = true;
+ }
+ ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other)
+ = delete;
+
+ /// Return the number of elements that have been added to
+ /// this struct or array.
+ size_t size() const {
+ assert(!this->Finished && "cannot query after finishing builder");
+ assert(!this->Frozen && "cannot query while sub-builder is active");
+ assert(this->Begin <= this->getBuffer().size());
+ return this->getBuffer().size() - this->Begin;
+ }
+
+ /// Return true if no elements have yet been added to this struct or array.
+ bool empty() const {
+ return size() == 0;
+ }
+
+ /// Abandon this builder completely.
+ void abandon() {
+ markFinished();
+ Builder.abandon(Begin);
+ }
+
+ /// Add a new value to this initializer.
+ void add(llvm::Constant *value) {
+ assert(value && "adding null value to constant initializer");
+ assert(!Finished && "cannot add more values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ Builder.Buffer.push_back(value);
+ }
+
+ /// Add an integer value of type size_t.
+ void addSize(CharUnits size);
+
+ /// Add an integer value of a specific type.
+ void addInt(llvm::IntegerType *intTy, uint64_t value,
+ bool isSigned = false) {
+ add(llvm::ConstantInt::get(intTy, value, isSigned));
+ }
+
+ /// Add a null pointer of a specific type.
+ void addNullPointer(llvm::PointerType *ptrTy) {
+ add(llvm::ConstantPointerNull::get(ptrTy));
+ }
+
+ /// Add a bitcast of a value to a specific type.
+ void addBitCast(llvm::Constant *value, llvm::Type *type) {
+ add(llvm::ConstantExpr::getBitCast(value, type));
+ }
+
+ /// Add a bunch of new values to this initializer.
+ void addAll(llvm::ArrayRef<llvm::Constant *> values) {
+ assert(!Finished && "cannot add more values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ Builder.Buffer.append(values.begin(), values.end());
+ }
+
+ /// Add a relative offset to the given target address, i.e. the
+ /// static difference between the target address and the address
+ /// of the relative offset. The target must be known to be defined
+ /// in the current linkage unit. The offset will have the given
+ /// integer type, which must be no wider than intptr_t. Some
+ /// targets may not fully support this operation.
+ void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) {
+ add(getRelativeOffset(type, target));
+ }
+
+ /// Add a relative offset to the target address, plus a small
+ /// constant offset. This is primarily useful when the relative
+ /// offset is known to be a multiple of (say) four and therefore
+ /// the tag can be used to express an extra two bits of information.
+ void addTaggedRelativeOffset(llvm::IntegerType *type,
+ llvm::Constant *address,
+ unsigned tag) {
+ llvm::Constant *offset = getRelativeOffset(type, address);
+ if (tag) {
+ offset = llvm::ConstantExpr::getAdd(offset,
+ llvm::ConstantInt::get(type, tag));
+ }
+ add(offset);
+ }
+
+ /// Return the offset from the start of the initializer to the
+ /// next position, assuming no padding is required prior to it.
+ ///
+ /// This operation will not succeed if any unsized placeholders are
+ /// currently in place in the initializer.
+ CharUnits getNextOffsetFromGlobal() const {
+ assert(!Finished && "cannot add more values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ return getOffsetFromGlobalTo(Builder.Buffer.size());
+ }
+
+ /// An opaque class to hold the abstract position of a placeholder.
+ class PlaceholderPosition {
+ size_t Index;
+ friend class ConstantAggregateBuilderBase;
+ PlaceholderPosition(size_t index) : Index(index) {}
+ };
+
+ /// Add a placeholder value to the structure. The returned position
+ /// can be used to set the value later; it will not be invalidated by
+ /// any intermediate operations except (1) filling the same position or
+ /// (2) finishing the entire builder.
+ ///
+ /// This is useful for emitting certain kinds of structure which
+ /// contain some sort of summary field, generaly a count, before any
+ /// of the data. By emitting a placeholder first, the structure can
+ /// be emitted eagerly.
+ PlaceholderPosition addPlaceholder() {
+ assert(!Finished && "cannot add more values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ Builder.Buffer.push_back(nullptr);
+ return Builder.Buffer.size() - 1;
+ }
+
+ /// Add a placeholder, giving the expected type that will be filled in.
+ PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType);
+
+ /// Fill a previously-added placeholder.
+ void fillPlaceholderWithInt(PlaceholderPosition position,
+ llvm::IntegerType *type, uint64_t value,
+ bool isSigned = false) {
+ fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned));
+ }
+
+ /// Fill a previously-added placeholder.
+ void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) {
+ assert(!Finished && "cannot change values after finishing builder");
+ assert(!Frozen && "cannot add values while subbuilder is active");
+ llvm::Constant *&slot = Builder.Buffer[position.Index];
+ assert(slot == nullptr && "placeholder already filled");
+ slot = value;
+ }
+
+ /// Produce an address which will eventually point to the the next
+ /// position to be filled. This is computed with an indexed
+ /// getelementptr rather than by computing offsets.
+ ///
+ /// The returned pointer will have type T*, where T is the given
+ /// position.
+ llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type);
+
+ llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition(
+ llvm::SmallVectorImpl<llvm::Constant*> &indices) {
+ getGEPIndicesTo(indices, Builder.Buffer.size());
+ return indices;
+ }
+
+protected:
+ llvm::Constant *finishArray(llvm::Type *eltTy);
+ llvm::Constant *finishStruct(llvm::StructType *structTy);
+
+private:
+ void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
+ size_t position) const;
+
+ llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType,
+ llvm::Constant *target);
+
+ CharUnits getOffsetFromGlobalTo(size_t index) const;
+};
+
+template <class Impl, class Traits>
+class ConstantAggregateBuilderTemplateBase
+ : public Traits::AggregateBuilderBase {
+ using super = typename Traits::AggregateBuilderBase;
+public:
+ using InitBuilder = typename Traits::InitBuilder;
+ using ArrayBuilder = typename Traits::ArrayBuilder;
+ using StructBuilder = typename Traits::StructBuilder;
+ using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
+
+protected:
+ ConstantAggregateBuilderTemplateBase(InitBuilder &builder,
+ AggregateBuilderBase *parent)
+ : super(builder, parent) {}
+
+ Impl &asImpl() { return *static_cast<Impl*>(this); }
+
+public:
+ ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
+ return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy);
+ }
+
+ StructBuilder beginStruct(llvm::StructType *ty = nullptr) {
+ return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty);
+ }
+
+ /// Given that this builder was created by beginning an array or struct
+ /// component on the given parent builder, finish the array/struct
+ /// component and add it to the parent.
+ ///
+ /// It is an intentional choice that the parent is passed in explicitly
+ /// despite it being redundant with information already kept in the
+ /// builder. This aids in readability by making it easier to find the
+ /// places that add components to a builder, as well as "bookending"
+ /// the sub-builder more explicitly.
+ void finishAndAddTo(AggregateBuilderBase &parent) {
+ assert(this->Parent == &parent && "adding to non-parent builder");
+ parent.add(asImpl().finishImpl());
+ }
+
+ /// Given that this builder was created by beginning an array or struct
+ /// directly on a ConstantInitBuilder, finish the array/struct and
+ /// create a global variable with it as the initializer.
+ template <class... As>
+ llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) {
+ assert(!this->Parent && "finishing non-root builder");
+ return this->Builder.createGlobal(asImpl().finishImpl(),
+ std::forward<As>(args)...);
+ }
+
+ /// Given that this builder was created by beginning an array or struct
+ /// directly on a ConstantInitBuilder, finish the array/struct and
+ /// set it as the initializer of the given global variable.
+ void finishAndSetAsInitializer(llvm::GlobalVariable *global) {
+ assert(!this->Parent && "finishing non-root builder");
+ return this->Builder.setGlobalInitializer(global, asImpl().finishImpl());
+ }
+
+ /// Given that this builder was created by beginning an array or struct
+ /// directly on a ConstantInitBuilder, finish the array/struct and
+ /// return a future which can be used to install the initializer in
+ /// a global later.
+ ///
+ /// This is useful for allowing a finished initializer to passed to
+ /// an API which will build the global. However, the "future" preserves
+ /// a dependency on the original builder; it is an error to pass it aside.
+ ConstantInitFuture finishAndCreateFuture() {
+ assert(!this->Parent && "finishing non-root builder");
+ return this->Builder.createFuture(asImpl().finishImpl());
+ }
+};
+
+template <class Traits>
+class ConstantArrayBuilderTemplateBase
+ : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
+ Traits> {
+ using super =
+ ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>;
+
+public:
+ using InitBuilder = typename Traits::InitBuilder;
+ using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
+
+private:
+ llvm::Type *EltTy;
+
+ template <class, class>
+ friend class ConstantAggregateBuilderTemplateBase;
+
+protected:
+ ConstantArrayBuilderTemplateBase(InitBuilder &builder,
+ AggregateBuilderBase *parent,
+ llvm::Type *eltTy)
+ : super(builder, parent), EltTy(eltTy) {}
+
+private:
+ /// Form an array constant from the values that have been added to this
+ /// builder.
+ llvm::Constant *finishImpl() {
+ return AggregateBuilderBase::finishArray(EltTy);
+ }
+};
+
+/// A template class designed to allow other frontends to
+/// easily customize the builder classes used by ConstantInitBuilder,
+/// and thus to extend the API to work with the abstractions they
+/// prefer. This would probably not be necessary if C++ just
+/// supported extension methods.
+template <class Traits>
+class ConstantStructBuilderTemplateBase
+ : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
+ Traits> {
+ using super =
+ ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>;
+
+public:
+ using InitBuilder = typename Traits::InitBuilder;
+ using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
+
+private:
+ llvm::StructType *StructTy;
+
+ template <class, class>
+ friend class ConstantAggregateBuilderTemplateBase;
+
+protected:
+ ConstantStructBuilderTemplateBase(InitBuilder &builder,
+ AggregateBuilderBase *parent,
+ llvm::StructType *structTy)
+ : super(builder, parent), StructTy(structTy) {
+ if (structTy) this->Packed = structTy->isPacked();
+ }
+
+public:
+ void setPacked(bool packed) {
+ this->Packed = packed;
+ }
+
+ /// Use the given type for the struct if its element count is correct.
+ /// Don't add more elements after calling this.
+ void suggestType(llvm::StructType *structTy) {
+ if (this->size() == structTy->getNumElements()) {
+ StructTy = structTy;
+ }
+ }
+
+private:
+ /// Form an array constant from the values that have been added to this
+ /// builder.
+ llvm::Constant *finishImpl() {
+ return AggregateBuilderBase::finishStruct(StructTy);
+ }
+};
+
+/// A template class designed to allow other frontends to
+/// easily customize the builder classes used by ConstantInitBuilder,
+/// and thus to extend the API to work with the abstractions they
+/// prefer. This would probably not be necessary if C++ just
+/// supported extension methods.
+template <class Traits>
+class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase {
+protected:
+ ConstantInitBuilderTemplateBase(CodeGenModule &CGM)
+ : ConstantInitBuilderBase(CGM) {}
+
+public:
+ using InitBuilder = typename Traits::InitBuilder;
+ using ArrayBuilder = typename Traits::ArrayBuilder;
+ using StructBuilder = typename Traits::StructBuilder;
+
+ ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
+ return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy);
+ }
+
+ StructBuilder beginStruct(llvm::StructType *structTy = nullptr) {
+ return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy);
+ }
+};
+
+class ConstantInitBuilder;
+class ConstantStructBuilder;
+class ConstantArrayBuilder;
+
+struct ConstantInitBuilderTraits {
+ using InitBuilder = ConstantInitBuilder;
+ using AggregateBuilderBase = ConstantAggregateBuilderBase;
+ using ArrayBuilder = ConstantArrayBuilder;
+ using StructBuilder = ConstantStructBuilder;
+};
+
+/// The standard implementation of ConstantInitBuilder used in Clang.
+class ConstantInitBuilder
+ : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
+public:
+ explicit ConstantInitBuilder(CodeGenModule &CGM) :
+ ConstantInitBuilderTemplateBase(CGM) {}
+};
+
+/// A helper class of ConstantInitBuilder, used for building constant
+/// array initializers.
+class ConstantArrayBuilder
+ : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> {
+ template <class Traits>
+ friend class ConstantInitBuilderTemplateBase;
+
+ // The use of explicit qualification is a GCC workaround.
+ template <class Impl, class Traits>
+ friend class CodeGen::ConstantAggregateBuilderTemplateBase;
+
+ ConstantArrayBuilder(ConstantInitBuilder &builder,
+ ConstantAggregateBuilderBase *parent,
+ llvm::Type *eltTy)
+ : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {}
+};
+
+/// A helper class of ConstantInitBuilder, used for building constant
+/// struct initializers.
+class ConstantStructBuilder
+ : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> {
+ template <class Traits>
+ friend class ConstantInitBuilderTemplateBase;
+
+ // The use of explicit qualification is a GCC workaround.
+ template <class Impl, class Traits>
+ friend class CodeGen::ConstantAggregateBuilderTemplateBase;
+
+ ConstantStructBuilder(ConstantInitBuilder &builder,
+ ConstantAggregateBuilderBase *parent,
+ llvm::StructType *structTy)
+ : ConstantStructBuilderTemplateBase(builder, parent, structTy) {}
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitFuture.h b/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitFuture.h
new file mode 100644
index 0000000..ef1a5d2
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/CodeGen/ConstantInitFuture.h
@@ -0,0 +1,111 @@
+//===- ConstantInitFuture.h - "Future" constant initializers ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class defines the ConstantInitFuture class. This is split out
+// from ConstantInitBuilder.h in order to allow APIs to work with it
+// without having to include that entire header. This is particularly
+// important because it is often useful to be able to default-construct
+// a future in, say, a default argument.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGEN_CONSTANTINITFUTURE_H
+#define LLVM_CLANG_CODEGEN_CONSTANTINITFUTURE_H
+
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/IR/Constant.h"
+
+// Forward-declare ConstantInitBuilderBase and give it a
+// PointerLikeTypeTraits specialization so that we can safely use it
+// in a PointerUnion below.
+namespace clang {
+namespace CodeGen {
+class ConstantInitBuilderBase;
+}
+}
+namespace llvm {
+template <>
+class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitBuilderBase*> {
+public:
+ using T = ::clang::CodeGen::ConstantInitBuilderBase*;
+
+ static inline void *getAsVoidPointer(T p) { return p; }
+ static inline T getFromVoidPointer(void *p) {return static_cast<T>(p);}
+ enum { NumLowBitsAvailable = 2 };
+};
+}
+
+namespace clang {
+namespace CodeGen {
+
+/// A "future" for a completed constant initializer, which can be passed
+/// around independently of any sub-builders (but not the original parent).
+class ConstantInitFuture {
+ using PairTy = llvm::PointerUnion<ConstantInitBuilderBase*, llvm::Constant*>;
+
+ PairTy Data;
+
+ friend class ConstantInitBuilderBase;
+ explicit ConstantInitFuture(ConstantInitBuilderBase *builder);
+
+public:
+ ConstantInitFuture() {}
+
+ /// A future can be explicitly created from a fixed initializer.
+ explicit ConstantInitFuture(llvm::Constant *initializer) : Data(initializer) {
+ assert(initializer && "creating null future");
+ }
+
+ /// Is this future non-null?
+ explicit operator bool() const { return bool(Data); }
+
+ /// Return the type of the initializer.
+ llvm::Type *getType() const;
+
+ /// Abandon this initializer.
+ void abandon();
+
+ /// Install the initializer into a global variable. This cannot
+ /// be called multiple times.
+ void installInGlobal(llvm::GlobalVariable *global);
+
+ void *getOpaqueValue() const { return Data.getOpaqueValue(); }
+ static ConstantInitFuture getFromOpaqueValue(void *value) {
+ ConstantInitFuture result;
+ result.Data = PairTy::getFromOpaqueValue(value);
+ return result;
+ }
+ enum {
+ NumLowBitsAvailable =
+ llvm::PointerLikeTypeTraits<PairTy>::NumLowBitsAvailable
+ };
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+namespace llvm {
+
+template <>
+class PointerLikeTypeTraits< ::clang::CodeGen::ConstantInitFuture> {
+public:
+ using T = ::clang::CodeGen::ConstantInitFuture;
+
+ static inline void *getAsVoidPointer(T future) {
+ return future.getOpaqueValue();
+ }
+ static inline T getFromVoidPointer(void *p) {
+ return T::getFromOpaqueValue(p);
+ }
+ enum { NumLowBitsAvailable = T::NumLowBitsAvailable };
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h b/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h
index 5863834..6f81ea9 100644
--- a/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h
+++ b/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h
@@ -35,6 +35,7 @@ namespace clang {
namespace CodeGen {
class CodeGenModule;
+ class CGDebugInfo;
}
/// The primary public interface to the Clang code generator.
@@ -65,6 +66,9 @@ public:
/// CodeGenerator after releasing its module.
llvm::Module *ReleaseModule();
+ /// Return debug info code generator.
+ CodeGen::CGDebugInfo *getCGDebugInfo();
+
/// Given a mangled name, return a declaration which mangles that way
/// which has been added to this code generator via a Handle method.
///
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td b/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td
index ab296eb..205f36b 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td
+++ b/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td
@@ -134,28 +134,31 @@ def migrator_no_finalize_removal : Flag<["-"], "no-finalize-removal">,
//===----------------------------------------------------------------------===//
let Flags = [CC1Option, CC1AsOption, NoDriverOption] in {
-
def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">;
+def debug_info_macro : Flag<["-"], "debug-info-macro">,
+ HelpText<"Emit macro debug information">;
def dwarf_version_EQ : Joined<["-"], "dwarf-version=">;
def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">;
def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
HelpText<"The compilation directory to embed in the debug info.">;
def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
+def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">,
+ HelpText<"DWARF debug sections compression">;
+def compress_debug_sections_EQ : Joined<["-"], "compress-debug-sections=">,
+ HelpText<"DWARF debug sections compression type">;
def mno_exec_stack : Flag<["-"], "mnoexecstack">,
HelpText<"Mark the file as not needing an executable stack">;
def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">,
HelpText<"Make assembler warnings fatal">;
def mrelax_relocations : Flag<["--"], "mrelax-relocations">,
HelpText<"Use relaxable elf relocations">;
-def compress_debug_sections : Flag<["-"], "compress-debug-sections">,
- HelpText<"Compress DWARF debug sections using zlib">;
def msave_temp_labels : Flag<["-"], "msave-temp-labels">,
HelpText<"Save temporary labels in the symbol table. "
"Note this may change .s semantics and shouldn't generally be used "
"on compiler-generated code.">;
def mrelocation_model : Separate<["-"], "mrelocation-model">,
- HelpText<"The relocation model to use">;
+ HelpText<"The relocation model to use">, Values<"static,pic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">;
def fno_math_builtin : Flag<["-"], "fno-math-builtin">,
HelpText<"Disable implicit builtin knowledge of math functions">;
}
@@ -170,6 +173,8 @@ def disable_llvm_optzns : Flag<["-"], "disable-llvm-optzns">,
def disable_lifetimemarkers : Flag<["-"], "disable-lifetime-markers">,
HelpText<"Disable lifetime-markers emission even when optimizations are "
"enabled">;
+def disable_O0_optnone : Flag<["-"], "disable-O0-optnone">,
+ HelpText<"Disable adding the optnone attribute to functions at O0">;
def disable_red_zone : Flag<["-"], "disable-red-zone">,
HelpText<"Do not emit code that uses the red zone.">;
def dwarf_column_info : Flag<["-"], "dwarf-column-info">,
@@ -224,7 +229,7 @@ def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">,
def masm_verbose : Flag<["-"], "masm-verbose">,
HelpText<"Generate verbose assembly output">;
def mcode_model : Separate<["-"], "mcode-model">,
- HelpText<"The code model to use">;
+ HelpText<"The code model to use">, Values<"small,kernel,medium,large">;
def mdebug_pass : Separate<["-"], "mdebug-pass">,
HelpText<"Enable additional debug output">;
def mdisable_fp_elim : Flag<["-"], "mdisable-fp-elim">,
@@ -263,8 +268,6 @@ def vectorize_loops : Flag<["-"], "vectorize-loops">,
HelpText<"Run the Loop vectorization passes">;
def vectorize_slp : Flag<["-"], "vectorize-slp">,
HelpText<"Run the SLP vectorization passes">;
-def vectorize_slp_aggressive : Flag<["-"], "vectorize-slp-aggressive">,
- HelpText<"Run the BB vectorization passes">;
def dependent_lib : Joined<["--"], "dependent-lib=">,
HelpText<"Add dependent library">;
def linker_option : Joined<["--"], "linker-option=">,
@@ -289,15 +292,21 @@ def fsanitize_coverage_trace_gep
def fsanitize_coverage_8bit_counters
: Flag<["-"], "fsanitize-coverage-8bit-counters">,
HelpText<"Enable frequency counters in sanitizer coverage">;
+def fsanitize_coverage_inline_8bit_counters
+ : Flag<["-"], "fsanitize-coverage-inline-8bit-counters">,
+ HelpText<"Enable inline 8-bit counters in sanitizer coverage">;
def fsanitize_coverage_trace_pc
: Flag<["-"], "fsanitize-coverage-trace-pc">,
HelpText<"Enable PC tracing in sanitizer coverage">;
def fsanitize_coverage_trace_pc_guard
: Flag<["-"], "fsanitize-coverage-trace-pc-guard">,
HelpText<"Enable PC tracing with guard in sanitizer coverage">;
+def fsanitize_coverage_no_prune
+ : Flag<["-"], "fsanitize-coverage-no-prune">,
+ HelpText<"Disable coverage pruning (i.e. instrument all blocks/edges)">;
def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">,
HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, "
- "or none">;
+ "or none">, Values<"none,clang,llvm">;
def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">,
HelpText<"Generate instrumented code to collect execution counts into "
"<file> (overridden by LLVM_PROFILE_FILE env var)">;
@@ -307,6 +316,15 @@ def fprofile_instrument_use_path_EQ :
def flto_visibility_public_std:
Flag<["-"], "flto-visibility-public-std">,
HelpText<"Use public LTO visibility for classes in std and stdext namespaces">;
+def flto_unit: Flag<["-"], "flto-unit">,
+ HelpText<"Emit IR to support LTO unit features (CFI, whole program vtable opt)">;
+def fno_lto_unit: Flag<["-"], "fno-lto-unit">;
+def fthin_link_bitcode_EQ : Joined<["-"], "fthin-link-bitcode=">,
+ HelpText<"Write minimized bitcode to <file> for the ThinLTO thin link only">;
+def fdebug_pass_manager : Flag<["-"], "fdebug-pass-manager">,
+ HelpText<"Prints debug information for the new pass manager">;
+def fno_debug_pass_manager : Flag<["-"], "fno-debug-pass-manager">,
+ HelpText<"Disables debug printing for the new pass manager">;
//===----------------------------------------------------------------------===//
// Dependency Output Options
@@ -332,9 +350,9 @@ def diagnostic_serialized_file : Separate<["-"], "serialize-diagnostic-file">,
HelpText<"File for serializing diagnostics in a binary format">;
def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">,
- HelpText<"Change diagnostic formatting to match IDE and command line tools">;
+ HelpText<"Change diagnostic formatting to match IDE and command line tools">, Values<"clang,msvc,msvc-fallback,vi">;
def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">,
- HelpText<"Print diagnostic category">;
+ HelpText<"Print diagnostic category">, Values<"none,id,name">;
def fno_diagnostics_use_presumed_location : Flag<["-"], "fno-diagnostics-use-presumed-location">,
HelpText<"Ignore #line directives when displaying diagnostic locations">;
def ftabstop : Separate<["-"], "ftabstop">, MetaVarName<"<N>">,
@@ -349,6 +367,9 @@ def fconstexpr_backtrace_limit : Separate<["-"], "fconstexpr-backtrace-limit">,
HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">;
def fspell_checking_limit : Separate<["-"], "fspell-checking-limit">, MetaVarName<"<N>">,
HelpText<"Set the maximum number of times to perform spell checking on unrecognized identifiers (0 = no limit).">;
+def fcaret_diagnostics_max_lines :
+ Separate<["-"], "fcaret-diagnostics-max-lines">, MetaVarName<"<N>">,
+ HelpText<"Set the maximum number of source lines to show in a caret diagnostic">;
def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
def verify : Flag<["-"], "verify">,
@@ -429,6 +450,14 @@ def fmodules_local_submodule_visibility :
Flag<["-"], "fmodules-local-submodule-visibility">,
HelpText<"Enforce name visibility rules across submodules of the same "
"top-level module.">;
+def fmodules_codegen :
+ Flag<["-"], "fmodules-codegen">,
+ HelpText<"Generate code for uses of this module that assumes an explicit "
+ "object file will be built for the module">;
+def fmodules_debuginfo :
+ Flag<["-"], "fmodules-debuginfo">,
+ HelpText<"Generate debug info for types in an object file built from this "
+ "module and do not generate them elsewhere">;
def fmodule_format_EQ : Joined<["-"], "fmodule-format=">,
HelpText<"Select the container format for clang modules and PCH. "
"Supported options are 'raw' and 'obj'.">;
@@ -466,6 +495,8 @@ def ast_list : Flag<["-"], "ast-list">,
HelpText<"Build ASTs and print the list of declaration node qualified names">;
def ast_dump : Flag<["-"], "ast-dump">,
HelpText<"Build ASTs and then debug dump them">;
+def ast_dump_all : Flag<["-"], "ast-dump-all">,
+ HelpText<"Build ASTs and then debug dump them, forcing deserialization">;
def ast_dump_lookups : Flag<["-"], "ast-dump-lookups">,
HelpText<"Build ASTs and then debug dump their name lookup tables">;
def ast_view : Flag<["-"], "ast-view">,
@@ -539,6 +570,9 @@ def find_pch_source_EQ : Joined<["-"], "find-pch-source=">,
def fno_pch_timestamp : Flag<["-"], "fno-pch-timestamp">,
HelpText<"Disable inclusion of timestamp in precompiled headers">;
+def aligned_alloc_unavailable : Flag<["-"], "faligned-alloc-unavailable">,
+ HelpText<"Aligned allocation/deallocation functions are unavailable">;
+
//===----------------------------------------------------------------------===//
// Language Options
//===----------------------------------------------------------------------===//
@@ -556,6 +590,8 @@ def fblocks_runtime_optional : Flag<["-"], "fblocks-runtime-optional">,
HelpText<"Weakly link in the blocks runtime">;
def fexternc_nounwind : Flag<["-"], "fexternc-nounwind">,
HelpText<"Assume all functions with C linkage do not unwind">;
+def enable_split_dwarf : Flag<["-"], "enable-split-dwarf">,
+ HelpText<"Use split dwarf/Fission">;
def split_dwarf_file : Separate<["-"], "split-dwarf-file">,
HelpText<"File name to use for split dwarf debug info output">;
def fno_wchar : Flag<["-"], "fno-wchar">,
@@ -564,11 +600,11 @@ def fconstant_string_class : Separate<["-"], "fconstant-string-class">,
MetaVarName<"<class name>">,
HelpText<"Specify the class to use for constant Objective-C string objects.">;
def fobjc_arc_cxxlib_EQ : Joined<["-"], "fobjc-arc-cxxlib=">,
- HelpText<"Objective-C++ Automatic Reference Counting standard library kind">;
+ HelpText<"Objective-C++ Automatic Reference Counting standard library kind">, Values<"libc++,libstdc++,none">;
def fobjc_runtime_has_weak : Flag<["-"], "fobjc-runtime-has-weak">,
HelpText<"The target Objective-C runtime supports ARC weak operations">;
def fobjc_dispatch_method_EQ : Joined<["-"], "fobjc-dispatch-method=">,
- HelpText<"Objective-C dispatch method to use">;
+ HelpText<"Objective-C dispatch method to use">, Values<"legacy,non-legacy,mixed">;
def disable_objc_default_synthesize_properties : Flag<["-"], "disable-objc-default-synthesize-properties">,
HelpText<"disable the default synthesis of Objective-C properties">;
def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signature">,
@@ -579,6 +615,8 @@ def pic_is_pie : Flag<["-"], "pic-is-pie">,
HelpText<"File is for a position independent executable">;
def fno_validate_pch : Flag<["-"], "fno-validate-pch">,
HelpText<"Disable validation of precompiled headers">;
+def fallow_pch_with_errors : Flag<["-"], "fallow-pch-with-compiler-errors">,
+ HelpText<"Accept a PCH file that was created with compiler errors">;
def dump_deserialized_pch_decls : Flag<["-"], "dump-deserialized-decls">,
HelpText<"Dump declarations that are deserialized from PCH, for testing">;
def error_on_deserialized_pch_decl : Separate<["-"], "error-on-deserialized-decl">,
@@ -640,9 +678,11 @@ def fnative_half_arguments_and_returns : Flag<["-"], "fnative-half-arguments-and
def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">,
HelpText<"Allow function arguments and returns of type half">;
def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">,
- HelpText<"Set default MS calling convention">;
+ HelpText<"Set default MS calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall">;
def finclude_default_header : Flag<["-"], "finclude-default-header">,
HelpText<"Include the default header file for OpenCL">;
+def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">,
+ HelpText<"Preserve 3-component vector type">;
// FIXME: Remove these entirely once functionality/tests have been excised.
def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>,
@@ -658,6 +698,8 @@ def nostdsysteminc : Flag<["-"], "nostdsysteminc">,
HelpText<"Disable standard system #include directories">;
def fdisable_module_hash : Flag<["-"], "fdisable-module-hash">,
HelpText<"Disable the module hash">;
+def fmodules_hash_content : Flag<["-"], "fmodules-hash-content">,
+ HelpText<"Enable hashing the content of a module file">;
def c_isystem : JoinedOrSeparate<["-"], "c-isystem">, MetaVarName<"<directory>">,
HelpText<"Add directory to the C SYSTEM include search path">;
def objc_isystem : JoinedOrSeparate<["-"], "objc-isystem">,
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td b/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td
index 60048c4..aebb36e 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td
+++ b/contrib/llvm/tools/clang/include/clang/Driver/CLCompatOptions.td
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-def cl_Group : OptionGroup<"<clang-cl options>">,
+def cl_Group : OptionGroup<"<clang-cl options>">, Flags<[CLOption]>,
HelpText<"CL.EXE COMPATIBILITY OPTIONS">;
def cl_compile_Group : OptionGroup<"<clang-cl compile-only options>">,
@@ -61,6 +61,14 @@ def _SLASH_Brepro_ : CLFlag<"Brepro-">,
def _SLASH_C : CLFlag<"C">,
HelpText<"Don't discard comments when preprocessing">, Alias<C>;
def _SLASH_c : CLFlag<"c">, HelpText<"Compile only">, Alias<c>;
+def _SLASH_d1reportAllClassLayout : CLFlag<"d1reportAllClassLayout">,
+ HelpText<"Dump record layout information">, Alias<fdump_record_layouts>;
+def _SLASH_diagnostics_caret : CLFlag<"diagnostics:caret">,
+ HelpText<"Enable caret and column diagnostics (on by default)">;
+def _SLASH_diagnostics_column : CLFlag<"diagnostics:column">,
+ HelpText<"Disable caret diagnostics but keep column info">;
+def _SLASH_diagnostics_classic : CLFlag<"diagnostics:classic">,
+ HelpText<"Disable column and caret diagnostics">;
def _SLASH_D : CLJoinedOrSeparate<"D">, HelpText<"Define macro">,
MetaVarName<"<macro[=value]>">, Alias<D>;
def _SLASH_E : CLFlag<"E">, HelpText<"Preprocess to stdout">, Alias<E>;
@@ -172,6 +180,12 @@ def _SLASH_Zc_trigraphs : CLFlag<"Zc:trigraphs">,
HelpText<"Enable trigraphs">, Alias<ftrigraphs>;
def _SLASH_Zc_trigraphs_off : CLFlag<"Zc:trigraphs-">,
HelpText<"Disable trigraphs (default)">, Alias<fno_trigraphs>;
+def _SLASH_Zc_twoPhase : CLFlag<"Zc:twoPhase">,
+ HelpText<"Enable two-phase name lookup in templates">,
+ Alias<fno_delayed_template_parsing>;
+def _SLASH_Zc_twoPhase_ : CLFlag<"Zc:twoPhase-">,
+ HelpText<"Disable two-phase name lookup in templates">,
+ Alias<fdelayed_template_parsing>;
def _SLASH_Z7 : CLFlag<"Z7">,
HelpText<"Enable CodeView debug information in object files">;
def _SLASH_Zd : CLFlag<"Zd">,
@@ -316,6 +330,7 @@ def _SLASH_Zc_forScope : CLIgnoredFlag<"Zc:forScope">;
def _SLASH_Zc_inline : CLIgnoredFlag<"Zc:inline">;
def _SLASH_Zc_rvalueCast : CLIgnoredFlag<"Zc:rvalueCast">;
def _SLASH_Zc_wchar_t : CLIgnoredFlag<"Zc:wchar_t">;
+def _SLASH_Zc_ternary : CLIgnoredFlag<"Zc:ternary">;
def _SLASH_Zm : CLIgnoredJoined<"Zm">;
def _SLASH_Zo : CLIgnoredFlag<"Zo">;
def _SLASH_Zo_ : CLIgnoredFlag<"Zo-">;
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/ClangOptionDocs.td b/contrib/llvm/tools/clang/include/clang/Driver/ClangOptionDocs.td
new file mode 100644
index 0000000..97c4469
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Driver/ClangOptionDocs.td
@@ -0,0 +1,36 @@
+//==--- ClangOptionDocs.td - Option documentation -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+def GlobalDocumentation {
+ code Intro =[{..
+ -------------------------------------------------------------------
+ NOTE: This file is automatically generated by running clang-tblgen
+ -gen-opt-docs. Do not edit this file by hand!!
+ -------------------------------------------------------------------
+
+=====================================
+Clang command line argument reference
+=====================================
+.. contents::
+ :local:
+
+Introduction
+============
+
+This page lists the command line arguments currently supported by the
+GCC-compatible ``clang`` and ``clang++`` drivers.
+
+}];
+
+ string Program = "clang";
+ list<string> ExcludedFlags = ["HelpHidden", "NoDriverOption",
+ "CLOption", "Unsupported", "Ignored"];
+}
+
+include "Options.td"
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h b/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h
index 114e0b3..036b046 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h
+++ b/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h
@@ -105,10 +105,13 @@ class Compilation {
/// Whether we're compiling for diagnostic purposes.
bool ForDiagnostics;
+ /// Whether an error during the parsing of the input args.
+ bool ContainsError;
+
public:
Compilation(const Driver &D, const ToolChain &DefaultToolChain,
llvm::opt::InputArgList *Args,
- llvm::opt::DerivedArgList *TranslatedArgs);
+ llvm::opt::DerivedArgList *TranslatedArgs, bool ContainsError);
~Compilation();
const Driver &getDriver() const { return TheDriver; }
@@ -275,6 +278,9 @@ public:
/// Return true if we're compiling for diagnostics.
bool isForDiagnostics() const { return ForDiagnostics; }
+ /// Return whether an error during the parsing of the input args.
+ bool containsError() const { return ContainsError; }
+
/// Redirect - Redirect output of this compilation. Can only be done once.
///
/// \param Redirects - array of pointers to paths. The array
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Distro.h b/contrib/llvm/tools/clang/include/clang/Driver/Distro.h
index e2fb8b6..fab4986 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Distro.h
+++ b/contrib/llvm/tools/clang/include/clang/Driver/Distro.h
@@ -57,6 +57,7 @@ public:
UbuntuXenial,
UbuntuYakkety,
UbuntuZesty,
+ UbuntuArtful,
UnknownDistro
};
@@ -110,9 +111,9 @@ public:
}
bool IsUbuntu() const {
- return DistroVal >= UbuntuHardy && DistroVal <= UbuntuZesty;
+ return DistroVal >= UbuntuHardy && DistroVal <= UbuntuArtful;
}
-
+
/// @}
};
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Driver.h b/contrib/llvm/tools/clang/include/clang/Driver/Driver.h
index 0ce461c..5a087ee 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Driver.h
+++ b/contrib/llvm/tools/clang/include/clang/Driver/Driver.h
@@ -14,6 +14,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Phases.h"
+#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/StringMap.h"
@@ -62,7 +63,7 @@ enum LTOKind {
/// Driver - Encapsulate logic for constructing compilation processes
/// from a set of gcc-driver-like command line arguments.
class Driver {
- llvm::opt::OptTable *Opts;
+ std::unique_ptr<llvm::opt::OptTable> Opts;
DiagnosticsEngine &Diags;
@@ -215,6 +216,11 @@ public:
/// Use lazy precompiled headers for PCH support.
unsigned CCCUsePCH : 1;
+ /// Force clang to emit reproducer for driver invocation. This is enabled
+ /// indirectly by setting FORCE_CLANG_DIAGNOSTICS_CRASH environment variable
+ /// or when using the -gen-reproducer driver flag.
+ unsigned GenReproducer : 1;
+
private:
/// Certain options suppress the 'no input files' warning.
unsigned SuppressMissingInputWarning : 1;
@@ -227,7 +233,7 @@ private:
/// This maps from the string representation of a triple to a ToolChain
/// created targeting that triple. The driver owns all the ToolChain objects
/// stored in it, and will clean them up when torn down.
- mutable llvm::StringMap<ToolChain *> ToolChains;
+ mutable llvm::StringMap<std::unique_ptr<ToolChain>> ToolChains;
private:
/// TranslateInputArgs - Create a new derived argument list from the input
@@ -264,7 +270,6 @@ public:
Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
- ~Driver();
/// @name Accessors
/// @{
@@ -304,13 +309,8 @@ public:
bool isSaveTempsObj() const { return SaveTemps == SaveTempsObj; }
bool embedBitcodeEnabled() const { return BitcodeEmbed != EmbedNone; }
- bool embedBitcodeInObject() const {
- // LTO has no object file output so ignore embed bitcode option in LTO.
- return (BitcodeEmbed == EmbedBitcode) && !isUsingLTO();
- }
- bool embedBitcodeMarkerOnly() const {
- return (BitcodeEmbed == EmbedMarker) && !isUsingLTO();
- }
+ bool embedBitcodeInObject() const { return (BitcodeEmbed == EmbedBitcode); }
+ bool embedBitcodeMarkerOnly() const { return (BitcodeEmbed == EmbedMarker); }
/// Compute the desired OpenMP runtime from the flags provided.
OpenMPRuntimeKind getOpenMPRuntime(const llvm::opt::ArgList &Args) const;
@@ -341,7 +341,8 @@ public:
/// ParseArgStrings - Parse the given list of strings into an
/// ArgList.
- llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args);
+ llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args,
+ bool &ContainsError);
/// BuildInputs - Construct the list of inputs and their types from
/// the given arguments.
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Job.h b/contrib/llvm/tools/clang/include/clang/Driver/Job.h
index 54bed09..ff88256 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Job.h
+++ b/contrib/llvm/tools/clang/include/clang/Driver/Job.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_DRIVER_JOB_H
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Option/Option.h"
@@ -69,6 +70,9 @@ class Command {
/// file
std::string ResponseFileFlag;
+ /// See Command::setEnvironment
+ std::vector<const char *> Environment;
+
/// When a response file is needed, we try to put most arguments in an
/// exclusive file, while others remains as regular command line arguments.
/// This functions fills a vector with the regular command line arguments,
@@ -111,6 +115,12 @@ public:
InputFileList = std::move(List);
}
+ /// \brief Sets the environment to be used by the new process.
+ /// \param NewEnvironment An array of environment variables.
+ /// \remark If the environment remains unset, then the environment
+ /// from the parent process will be used.
+ void setEnvironment(llvm::ArrayRef<const char *> NewEnvironment);
+
const char *getExecutable() const { return Executable; }
const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Multilib.h b/contrib/llvm/tools/clang/include/clang/Driver/Multilib.h
index 0419186..36d2493 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Multilib.h
+++ b/contrib/llvm/tools/clang/include/clang/Driver/Multilib.h
@@ -70,13 +70,21 @@ public:
/// All elements begin with either '+' or '-'
const flags_list &flags() const { return Flags; }
flags_list &flags() { return Flags; }
+
/// Add a flag to the flags list
+ /// \p Flag must be a flag accepted by the driver with its leading '-' removed,
+ /// and replaced with either:
+ /// '-' which contraindicates using this multilib with that flag
+ /// or:
+ /// '+' which promotes using this multilib in the presence of that flag
+ /// otherwise '-print-multi-lib' will not emit them correctly.
Multilib &flag(StringRef F) {
assert(F.front() == '+' || F.front() == '-');
Flags.push_back(F);
return *this;
}
+ LLVM_DUMP_METHOD void dump() const;
/// \brief print summary of the Multilib
void print(raw_ostream &OS) const;
@@ -150,6 +158,7 @@ public:
unsigned size() const { return Multilibs.size(); }
+ LLVM_DUMP_METHOD void dump() const;
void print(raw_ostream &OS) const;
MultilibSet &setIncludeDirsCallback(IncludeDirsFunc F) {
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Options.h b/contrib/llvm/tools/clang/include/clang/Driver/Options.h
index 2716fa9..2da3cb4 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Options.h
+++ b/contrib/llvm/tools/clang/include/clang/Driver/Options.h
@@ -10,6 +10,8 @@
#ifndef LLVM_CLANG_DRIVER_OPTIONS_H
#define LLVM_CLANG_DRIVER_OPTIONS_H
+#include <memory>
+
namespace llvm {
namespace opt {
class OptTable;
@@ -31,20 +33,22 @@ enum ClangFlags {
CLOption = (1 << 9),
CC1Option = (1 << 10),
CC1AsOption = (1 << 11),
- NoDriverOption = (1 << 12)
+ NoDriverOption = (1 << 12),
+ Ignored = (1 << 13)
};
enum ID {
OPT_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) OPT_##ID,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
#include "clang/Driver/Options.inc"
LastOption
#undef OPTION
};
}
-llvm::opt::OptTable *createDriverOptTable();
+std::unique_ptr<llvm::opt::OptTable> createDriverOptTable();
}
}
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Options.td b/contrib/llvm/tools/clang/include/clang/Driver/Options.td
index 6be159f..05dc9d7 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Options.td
+++ b/contrib/llvm/tools/clang/include/clang/Driver/Options.td
@@ -33,6 +33,9 @@ def NoArgumentUnused : OptionFlag;
// lines that use it.
def Unsupported : OptionFlag;
+// Ignored - The option is unsupported, and the driver will silently ignore it.
+def Ignored : OptionFlag;
+
// CoreOption - This is considered a "core" Clang option, available in both
// clang and clang-cl modes.
def CoreOption : OptionFlag;
@@ -50,72 +53,160 @@ def CC1AsOption : OptionFlag;
// NoDriverOption - This option should not be accepted by the driver.
def NoDriverOption : OptionFlag;
+// A short name to show in documentation. The name will be interpreted as rST.
+class DocName<string name> { string DocName = name; }
+
+// A brief description to show in documentation, interpreted as rST.
+class DocBrief<code descr> { code DocBrief = descr; }
+
+// Indicates that this group should be flattened into its parent when generating
+// documentation.
+class DocFlatten { bit DocFlatten = 1; }
+
+// Indicates that this warning is ignored, but accepted with a warning for
+// GCC compatibility.
+class IgnoredGCCCompat : Flags<[HelpHidden]> {}
+
/////////
// Groups
+def Action_Group : OptionGroup<"<action group>">, DocName<"Actions">,
+ DocBrief<[{The action to perform on the input.}]>;
+
// Meta-group for options which are only used for compilation,
// and not linking etc.
-def CompileOnly_Group : OptionGroup<"<CompileOnly group>">;
-
-def Action_Group : OptionGroup<"<action group>">;
-
-def I_Group : OptionGroup<"<I group>">, Group<CompileOnly_Group>;
-def M_Group : OptionGroup<"<M group>">, Group<CompileOnly_Group>;
-def T_Group : OptionGroup<"<T group>">;
-def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>;
-def R_Group : OptionGroup<"<R group>">, Group<CompileOnly_Group>;
-def R_value_Group : OptionGroup<"<R (with value) group>">, Group<R_Group>;
-def W_Group : OptionGroup<"<W group>">, Group<CompileOnly_Group>;
-def W_value_Group : OptionGroup<"<W (with value) group>">, Group<W_Group>;
-def d_Group : OptionGroup<"<d group>">;
-def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>;
-def f_clang_Group : OptionGroup<"<f (clang-only) group>">, Group<CompileOnly_Group>;
-def g_Group : OptionGroup<"<g group>">;
-def gN_Group : OptionGroup<"<gN group>">, Group<g_Group>;
-def ggdbN_Group : OptionGroup<"<ggdbN group>">, Group<gN_Group>;
-def gTune_Group : OptionGroup<"<gTune group>">, Group<g_Group>;
-def g_flags_Group : OptionGroup<"<g flags group>">;
-def i_Group : OptionGroup<"<i group>">, Group<CompileOnly_Group>;
-def clang_i_Group : OptionGroup<"<clang i group>">, Group<i_Group>;
-def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>;
-def opencl_Group : OptionGroup<"<opencl group>">, Group<CompileOnly_Group>;
+def CompileOnly_Group : OptionGroup<"<CompileOnly group>">,
+ DocName<"Compilation flags">, DocBrief<[{
+Flags controlling the behavior of Clang during compilation. These flags have
+no effect during actions that do not perform compilation.}]>;
+
+def Preprocessor_Group : OptionGroup<"<Preprocessor group>">,
+ Group<CompileOnly_Group>,
+ DocName<"Preprocessor flags">, DocBrief<[{
+Flags controlling the behavior of the Clang preprocessor.}]>;
+
+def IncludePath_Group : OptionGroup<"<I/i group>">, Group<Preprocessor_Group>,
+ DocName<"Include path management">,
+ DocBrief<[{
+Flags controlling how ``#include``\s are resolved to files.}]>;
+
+def I_Group : OptionGroup<"<I group>">, Group<IncludePath_Group>, DocFlatten;
+def i_Group : OptionGroup<"<i group>">, Group<IncludePath_Group>, DocFlatten;
+def clang_i_Group : OptionGroup<"<clang i group>">, Group<i_Group>, DocFlatten;
+
+def M_Group : OptionGroup<"<M group>">, Group<Preprocessor_Group>,
+ DocName<"Dependency file generation">, DocBrief<[{
+Flags controlling generation of a dependency file for ``make``-like build
+systems.}]>;
+
+def d_Group : OptionGroup<"<d group>">, Group<Preprocessor_Group>,
+ DocName<"Dumping preprocessor state">, DocBrief<[{
+Flags allowing the state of the preprocessor to be dumped in various ways.}]>;
+
+def Diag_Group : OptionGroup<"<W/R group>">, Group<CompileOnly_Group>,
+ DocName<"Diagnostic flags">, DocBrief<[{
+Flags controlling which warnings, errors, and remarks Clang will generate.
+See the :doc:`full list of warning and remark flags <DiagnosticsReference>`.}]>;
+
+def R_Group : OptionGroup<"<R group>">, Group<Diag_Group>, DocFlatten;
+def R_value_Group : OptionGroup<"<R (with value) group>">, Group<R_Group>,
+ DocFlatten;
+def W_Group : OptionGroup<"<W group>">, Group<Diag_Group>, DocFlatten;
+def W_value_Group : OptionGroup<"<W (with value) group>">, Group<W_Group>,
+ DocFlatten;
+
+def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>,
+ DocName<"Target-independent compilation options">;
+
+def f_clang_Group : OptionGroup<"<f (clang-only) group>">,
+ Group<CompileOnly_Group>, DocFlatten;
+def pedantic_Group : OptionGroup<"<pedantic group>">, Group<f_Group>,
+ DocFlatten;
+def opencl_Group : OptionGroup<"<opencl group>">, Group<f_Group>,
+ DocName<"OpenCL flags">;
+
+def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>,
+ DocName<"Target-dependent compilation options">;
// Feature groups - these take command line options that correspond directly to
// target specific features and can be translated directly from command line
// options.
-def m_x86_Features_Group : OptionGroup<"<x86 features group>">,
- Group<m_Group>,
- Flags<[CoreOption]>;
-def m_hexagon_Features_Group : OptionGroup<"<hexagon features group>">,
- Group<m_Group>;
-def m_arm_Features_Group : OptionGroup<"<arm features group>">,
- Group<m_Group>;
def m_aarch64_Features_Group : OptionGroup<"<aarch64 features group>">,
- Group<m_Group>;
+ Group<m_Group>, DocName<"AARCH64">;
+def m_amdgpu_Features_Group : OptionGroup<"<amdgpu features group>">,
+ Group<m_Group>, DocName<"AMDGPU">;
+def m_arm_Features_Group : OptionGroup<"<arm features group>">,
+ Group<m_Group>, DocName<"ARM">;
+def m_hexagon_Features_Group : OptionGroup<"<hexagon features group>">,
+ Group<m_Group>, DocName<"Hexagon">;
def m_ppc_Features_Group : OptionGroup<"<ppc features group>">,
- Group<m_Group>;
+ Group<m_Group>, DocName<"PowerPC">;
def m_wasm_Features_Group : OptionGroup<"<wasm features group>">,
- Group<m_Group>;
-def m_amdgpu_Features_Group : OptionGroup<"<amdgpu features group>">,
- Group<m_Group>;
+ Group<m_Group>, DocName<"WebAssembly">;
+def m_x86_Features_Group : OptionGroup<"<x86 features group>">,
+ Group<m_Group>, Flags<[CoreOption]>, DocName<"X86">;
+
+def m_libc_Group : OptionGroup<"<m libc group>">, Group<m_Group>,
+ Flags<[HelpHidden]>;
+
+def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>,
+ DocName<"Optimization level">, DocBrief<[{
+Flags controlling how much optimization should be performed.}]>;
+
+def DebugInfo_Group : OptionGroup<"<g group>">, Group<CompileOnly_Group>,
+ DocName<"Debug information generation">, DocBrief<[{
+Flags controlling how much and what kind of debug information should be
+generated.}]>;
+
+def g_Group : OptionGroup<"<g group>">, Group<DebugInfo_Group>,
+ DocName<"Kind and level of debug information">;
+def gN_Group : OptionGroup<"<gN group>">, Group<g_Group>,
+ DocName<"Debug level">;
+def ggdbN_Group : OptionGroup<"<ggdbN group>">, Group<gN_Group>, DocFlatten;
+def gTune_Group : OptionGroup<"<gTune group>">, Group<g_Group>,
+ DocName<"Debugger to tune debug information for">;
+def g_flags_Group : OptionGroup<"<g flags group>">, Group<DebugInfo_Group>,
+ DocName<"Debug information flags">;
+
+def StaticAnalyzer_Group : OptionGroup<"<Static analyzer group>">,
+ DocName<"Static analyzer flags">, DocBrief<[{
+Flags controlling the behavior of the Clang Static Analyzer.}]>;
+
+// gfortran options that we recognize in the driver and pass along when
+// invoking GCC to compile Fortran code.
+def gfortran_Group : OptionGroup<"<gfortran group>">,
+ DocName<"Fortran compilation flags">, DocBrief<[{
+Flags that will be passed onto the ``gfortran`` compiler when Clang is given
+a Fortran input.}]>;
-def m_libc_Group : OptionGroup<"<m libc group>">, Group<m_Group>;
-def u_Group : OptionGroup<"<u group>">;
+def Link_Group : OptionGroup<"<T/e/s/t/u group>">, DocName<"Linker flags">,
+ DocBrief<[{Flags that are passed on to the linker}]>;
+def T_Group : OptionGroup<"<T group>">, Group<Link_Group>, DocFlatten;
+def u_Group : OptionGroup<"<u group>">, Group<Link_Group>, DocFlatten;
-def pedantic_Group : OptionGroup<"<pedantic group>">,
- Group<CompileOnly_Group>;
-def reserved_lib_Group : OptionGroup<"<reserved libs group>">;
+def reserved_lib_Group : OptionGroup<"<reserved libs group>">,
+ Flags<[Unsupported]>;
// Temporary groups for clang options which we know we don't support,
// but don't want to verbosely warn the user about.
def clang_ignored_f_Group : OptionGroup<"<clang ignored f group>">,
- Group<f_Group>;
+ Group<f_Group>, Flags<[Ignored]>;
def clang_ignored_m_Group : OptionGroup<"<clang ignored m group>">,
- Group<m_Group>;
+ Group<m_Group>, Flags<[Ignored]>;
+
+// Group for clang options in the process of deprecation.
+// Please include the version that deprecated the flag as comment to allow
+// easier garbage collection.
+def clang_ignored_legacy_options_Group : OptionGroup<"<clang legacy flags>">,
+ Group<f_Group>, Flags<[Ignored]>;
+
+// Retired with clang-5.0
+def : Flag<["-"], "fslp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>;
+def : Flag<["-"], "fno-slp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>;
// Group that ignores all gcc optimizations that won't be implemented
def clang_ignored_gcc_optimization_f_Group : OptionGroup<
- "<clang_ignored_gcc_optimization_f_Group>">, Group<f_Group>;
+ "<clang_ignored_gcc_optimization_f_Group>">, Group<f_Group>, Flags<[Ignored]>;
/////////
// Options
@@ -141,7 +232,7 @@ def clang_ignored_gcc_optimization_f_Group : OptionGroup<
// Developer Driver Options
-def internal_Group : OptionGroup<"<clang internal options>">;
+def internal_Group : OptionGroup<"<clang internal options>">, Flags<[HelpHidden]>;
def internal_driver_Group : OptionGroup<"<clang driver internal options>">,
Group<internal_Group>, HelpText<"DRIVER OPTIONS">;
def internal_debug_Group :
@@ -184,6 +275,8 @@ def arcmt_migrate_report_output : Separate<["-"], "arcmt-migrate-report-output">
def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">,
HelpText<"Emit ARC errors even if the migrator can fix them">,
Flags<[CC1Option]>;
+def gen_reproducer: Flag<["-"], "gen-reproducer">, InternalDebugOpt,
+ HelpText<"Auto-generates preprocessed source files and a reproduction script">;
def _migrate : Flag<["--"], "migrate">, Flags<[DriverOption]>,
HelpText<"Run the migrator">;
@@ -236,23 +329,34 @@ def _HASH_HASH_HASH : Flag<["-"], "###">, Flags<[DriverOption, CoreOption]>,
HelpText<"Print (but do not run) the commands to run for this compilation">;
def _DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>,
Flags<[DriverOption, CoreOption]>;
-def A : JoinedOrSeparate<["-"], "A">, Flags<[RenderJoined]>;
-def B : JoinedOrSeparate<["-"], "B">;
-def CC : Flag<["-"], "CC">, Flags<[CC1Option]>;
-def C : Flag<["-"], "C">, Flags<[CC1Option]>;
-def D : JoinedOrSeparate<["-"], "D">, Group<CompileOnly_Group>, Flags<[CC1Option]>;
+def A : JoinedOrSeparate<["-"], "A">, Flags<[RenderJoined]>, Group<gfortran_Group>;
+def B : JoinedOrSeparate<["-"], "B">, MetaVarName<"<dir>">,
+ HelpText<"Add <dir> to search path for binaries and object files used implicitly">;
+def CC : Flag<["-"], "CC">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
+ HelpText<"Include comments from within macros in preprocessed output">;
+def C : Flag<["-"], "C">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
+ HelpText<"Include comments in preprocessed output">;
+def D : JoinedOrSeparate<["-"], "D">, Group<Preprocessor_Group>,
+ Flags<[CC1Option]>, MetaVarName<"<macro>=<value>">,
+ HelpText<"Define <macro> to <value> (or 1 if <value> omitted)">;
def E : Flag<["-"], "E">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
- HelpText<"Only run the preprocessor">;
+ HelpText<"Only run the preprocessor">;
def F : JoinedOrSeparate<["-"], "F">, Flags<[RenderJoined,CC1Option]>,
HelpText<"Add directory to framework include search path">;
-def G : JoinedOrSeparate<["-"], "G">, Flags<[DriverOption]>;
-def G_EQ : Joined<["-"], "G=">, Flags<[DriverOption]>;
-def H : Flag<["-"], "H">, Flags<[CC1Option]>,
+def G : JoinedOrSeparate<["-"], "G">, Flags<[DriverOption]>, Group<m_Group>,
+ MetaVarName<"<size>">, HelpText<"Put objects of at most <size> bytes "
+ "into small data section (MIPS / Hexagon)">;
+def G_EQ : Joined<["-"], "G=">, Flags<[DriverOption]>, Group<m_Group>, Alias<G>;
+def H : Flag<["-"], "H">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
HelpText<"Show header includes and nesting depth">;
-def I_ : Flag<["-"], "I-">, Group<I_Group>;
-def I : JoinedOrSeparate<["-"], "I">, Group<I_Group>, Flags<[CC1Option,CC1AsOption]>,
+def I_ : Flag<["-"], "I-">, Group<I_Group>,
+ HelpText<"Restrict all prior -I flags to double-quoted inclusion and "
+ "remove current directory from include path">;
+def I : JoinedOrSeparate<["-"], "I">, Group<I_Group>,
+ Flags<[CC1Option,CC1AsOption]>, MetaVarName<"<dir>">,
HelpText<"Add directory to include search path">;
-def L : JoinedOrSeparate<["-"], "L">, Flags<[RenderJoined]>;
+def L : JoinedOrSeparate<["-"], "L">, Flags<[RenderJoined]>, Group<Link_Group>,
+ MetaVarName<"<dir>">, HelpText<"Add directory to library search path">;
def MD : Flag<["-"], "MD">, Group<M_Group>,
HelpText<"Write a depfile containing user and system headers">;
def MMD : Flag<["-"], "MMD">, Group<M_Group>,
@@ -276,9 +380,9 @@ def MT : JoinedOrSeparate<["-"], "MT">, Group<M_Group>, Flags<[CC1Option]>,
HelpText<"Specify name of main file output in depfile">;
def MV : Flag<["-"], "MV">, Group<M_Group>, Flags<[CC1Option]>,
HelpText<"Use NMake/Jom format for the depfile">;
-def Mach : Flag<["-"], "Mach">;
-def O0 : Flag<["-"], "O0">, Group<O_Group>, Flags<[CC1Option]>;
-def O4 : Flag<["-"], "O4">, Group<O_Group>, Flags<[CC1Option]>;
+def Mach : Flag<["-"], "Mach">, Group<Link_Group>;
+def O0 : Flag<["-"], "O0">, Group<O_Group>, Flags<[CC1Option, HelpHidden]>;
+def O4 : Flag<["-"], "O4">, Group<O_Group>, Flags<[CC1Option, HelpHidden]>;
def ObjCXX : Flag<["-"], "ObjC++">, Flags<[DriverOption]>,
HelpText<"Treat source input files as Objective-C++ inputs">;
def ObjC : Flag<["-"], "ObjC">, Flags<[DriverOption]>,
@@ -286,12 +390,12 @@ def ObjC : Flag<["-"], "ObjC">, Flags<[DriverOption]>,
def O : Joined<["-"], "O">, Group<O_Group>, Flags<[CC1Option]>;
def O_flag : Flag<["-"], "O">, Flags<[CC1Option]>, Alias<O>, AliasArgs<["2"]>;
def Ofast : Joined<["-"], "Ofast">, Group<O_Group>, Flags<[CC1Option]>;
-def P : Flag<["-"], "P">, Flags<[CC1Option]>,
+def P : Flag<["-"], "P">, Flags<[CC1Option]>, Group<Preprocessor_Group>,
HelpText<"Disable linemarker output in -E mode">;
-def Qn : Flag<["-"], "Qn">;
+def Qn : Flag<["-"], "Qn">, IgnoredGCCCompat;
def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[DriverOption, CoreOption]>,
HelpText<"Don't emit warning for unused driver arguments">;
-def Q : Flag<["-"], "Q">;
+def Q : Flag<["-"], "Q">, IgnoredGCCCompat;
def Rpass_EQ : Joined<["-"], "Rpass=">, Group<R_value_Group>, Flags<[CC1Option]>,
HelpText<"Report transformations performed by optimization passes whose "
"name matches the given POSIX regular expression">;
@@ -307,23 +411,28 @@ def R_Joined : Joined<["-"], "R">, Group<R_Group>, Flags<[CC1Option, CoreOption]
MetaVarName<"<remark>">, HelpText<"Enable the specified remark">;
def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
HelpText<"Only run preprocess and compilation steps">;
-def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>;
-def Tdata : JoinedOrSeparate<["-"], "Tdata">, Group<T_Group>;
-def Ttext : JoinedOrSeparate<["-"], "Ttext">, Group<T_Group>;
-def T : JoinedOrSeparate<["-"], "T">, Group<T_Group>;
-def U : JoinedOrSeparate<["-"], "U">, Group<CompileOnly_Group>, Flags<[CC1Option]>;
+def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>,
+ MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">;
+def Tdata : JoinedOrSeparate<["-"], "Tdata">, Group<T_Group>,
+ MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">;
+def Ttext : JoinedOrSeparate<["-"], "Ttext">, Group<T_Group>,
+ MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">;
+def T : JoinedOrSeparate<["-"], "T">, Group<T_Group>,
+ MetaVarName<"<script>">, HelpText<"Specify <script> as linker script">;
+def U : JoinedOrSeparate<["-"], "U">, Group<Preprocessor_Group>,
+ Flags<[CC1Option]>, MetaVarName<"<macro>">, HelpText<"Undefine macro <macro>">;
def V : JoinedOrSeparate<["-"], "V">, Flags<[DriverOption, Unsupported]>;
def Wa_COMMA : CommaJoined<["-"], "Wa,">,
HelpText<"Pass the comma separated arguments in <arg> to the assembler">,
MetaVarName<"<arg>">;
-def Wall : Flag<["-"], "Wall">, Group<W_Group>, Flags<[CC1Option]>;
-def WCL4 : Flag<["-"], "WCL4">, Group<W_Group>, Flags<[CC1Option]>;
-def Wdeprecated : Flag<["-"], "Wdeprecated">, Group<W_Group>, Flags<[CC1Option]>;
+def Wall : Flag<["-"], "Wall">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>;
+def WCL4 : Flag<["-"], "WCL4">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>;
+def Wdeprecated : Flag<["-"], "Wdeprecated">, Group<W_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable warnings for deprecated constructs and define __DEPRECATED">;
def Wno_deprecated : Flag<["-"], "Wno-deprecated">, Group<W_Group>, Flags<[CC1Option]>;
-def Wextra : Flag<["-"], "Wextra">, Group<W_Group>, Flags<[CC1Option]>;
def Wl_COMMA : CommaJoined<["-"], "Wl,">, Flags<[LinkerInput, RenderAsInput]>,
HelpText<"Pass the comma separated arguments in <arg> to the linker">,
- MetaVarName<"<arg>">;
+ MetaVarName<"<arg>">, Group<Link_Group>;
// FIXME: This is broken; these should not be Joined arguments.
def Wno_nonportable_cfstrings : Joined<["-"], "Wno-nonportable-cfstrings">, Group<W_Group>,
Flags<[CC1Option]>;
@@ -331,16 +440,18 @@ def Wnonportable_cfstrings : Joined<["-"], "Wnonportable-cfstrings">, Group<W_Gr
Flags<[CC1Option]>;
def Wp_COMMA : CommaJoined<["-"], "Wp,">,
HelpText<"Pass the comma separated arguments in <arg> to the preprocessor">,
- MetaVarName<"<arg>">;
-def Wwrite_strings : Flag<["-"], "Wwrite-strings">, Group<W_Group>, Flags<[CC1Option]>;
-def Wno_write_strings : Flag<["-"], "Wno-write-strings">, Group<W_Group>, Flags<[CC1Option]>;
+ MetaVarName<"<arg>">, Group<Preprocessor_Group>;
+def Wwrite_strings : Flag<["-"], "Wwrite-strings">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>;
+def Wno_write_strings : Flag<["-"], "Wno-write-strings">, Group<W_Group>, Flags<[CC1Option, HelpHidden]>;
def W_Joined : Joined<["-"], "W">, Group<W_Group>, Flags<[CC1Option, CoreOption]>,
MetaVarName<"<warning>">, HelpText<"Enable the specified warning">;
def Xanalyzer : Separate<["-"], "Xanalyzer">,
- HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">;
+ HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">,
+ Group<StaticAnalyzer_Group>;
def Xarch__ : JoinedAndSeparate<["-"], "Xarch_">, Flags<[DriverOption]>;
def Xassembler : Separate<["-"], "Xassembler">,
- HelpText<"Pass <arg> to the assembler">, MetaVarName<"<arg>">;
+ HelpText<"Pass <arg> to the assembler">, MetaVarName<"<arg>">,
+ Group<CompileOnly_Group>;
def Xclang : Separate<["-"], "Xclang">,
HelpText<"Pass <arg> to the clang compiler">, MetaVarName<"<arg>">,
Flags<[DriverOption, CoreOption]>, Group<CompileOnly_Group>;
@@ -349,14 +460,17 @@ def Xcuda_fatbinary : Separate<["-"], "Xcuda-fatbinary">,
def Xcuda_ptxas : Separate<["-"], "Xcuda-ptxas">,
HelpText<"Pass <arg> to the ptxas assembler">, MetaVarName<"<arg>">;
def z : Separate<["-"], "z">, Flags<[LinkerInput, RenderAsInput]>,
- HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">;
+ HelpText<"Pass -z <arg> to the linker">, MetaVarName<"<arg>">,
+ Group<Link_Group>;
def Xlinker : Separate<["-"], "Xlinker">, Flags<[LinkerInput, RenderAsInput]>,
- HelpText<"Pass <arg> to the linker">, MetaVarName<"<arg>">;
-def Xpreprocessor : Separate<["-"], "Xpreprocessor">,
+ HelpText<"Pass <arg> to the linker">, MetaVarName<"<arg>">,
+ Group<Link_Group>;
+def Xpreprocessor : Separate<["-"], "Xpreprocessor">, Group<Preprocessor_Group>,
HelpText<"Pass <arg> to the preprocessor">, MetaVarName<"<arg>">;
-def X_Flag : Flag<["-"], "X">;
-def X_Joined : Joined<["-"], "X">;
-def Z_Flag : Flag<["-"], "Z">;
+def X_Flag : Flag<["-"], "X">, Group<Link_Group>;
+def X_Joined : Joined<["-"], "X">, IgnoredGCCCompat;
+def Z_Flag : Flag<["-"], "Z">, Group<Link_Group>;
+// FIXME: All we do with this is reject it. Remove.
def Z_Joined : Joined<["-"], "Z">;
def all__load : Flag<["-"], "all_load">;
def allowable__client : Separate<["-"], "allowable_client">;
@@ -365,6 +479,7 @@ def arch__errors__fatal : Flag<["-"], "arch_errors_fatal">;
def arch : Separate<["-"], "arch">, Flags<[DriverOption]>;
def arch__only : Separate<["-"], "arch_only">;
def a : Joined<["-"], "a">;
+def autocomplete : Joined<["--"], "autocomplete=">;
def bind__at__load : Flag<["-"], "bind_at_load">;
def bundle__loader : Separate<["-"], "bundle_loader">;
def bundle : Flag<["-"], "bundle">;
@@ -388,7 +503,7 @@ def cl_mad_enable : Flag<["-"], "cl-mad-enable">, Group<opencl_Group>, Flags<[CC
def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group<opencl_Group>, Flags<[CC1Option]>,
HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">;
def cl_std_EQ : Joined<["-"], "cl-std=">, Group<opencl_Group>, Flags<[CC1Option]>,
- HelpText<"OpenCL language standard to compile for.">;
+ HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0">;
def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group<opencl_Group>, Flags<[CC1Option]>,
HelpText<"OpenCL only. Allow denormals to be flushed to zero.">;
def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group<opencl_Group>, Flags<[CC1Option]>,
@@ -402,7 +517,7 @@ def current__version : JoinedOrSeparate<["-"], "current_version">;
def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>,
HelpText<"Add directory to the C++ SYSTEM include search path">, Flags<[CC1Option]>,
MetaVarName<"<directory>">;
-def c : Flag<["-"], "c">, Flags<[DriverOption]>,
+def c : Flag<["-"], "c">, Flags<[DriverOption]>, Group<Action_Group>,
HelpText<"Only run preprocess, compile, and assemble steps">;
def cuda_device_only : Flag<["--"], "cuda-device-only">,
HelpText<"Compile CUDA code for device only">;
@@ -462,7 +577,7 @@ def emit_ast : Flag<["-"], "emit-ast">,
def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Use the LLVM representation for assembler and object files">;
def exported__symbols__list : Separate<["-"], "exported_symbols_list">;
-def e : JoinedOrSeparate<["-"], "e">;
+def e : JoinedOrSeparate<["-"], "e">, Group<Link_Group>;
def fPIC : Flag<["-"], "fPIC">, Group<f_Group>;
def fno_PIC : Flag<["-"], "fno-PIC">, Group<f_Group>;
def fPIE : Flag<["-"], "fPIE">, Group<f_Group>;
@@ -511,14 +626,28 @@ def fno_gnu_inline_asm : Flag<["-"], "fno-gnu-inline-asm">, Group<f_Group>,
Flags<[DriverOption, CC1Option]>,
HelpText<"Disable GNU style inline asm">;
+def fprofile_sample_use : Flag<["-"], "fprofile-sample-use">, Group<f_Group>,
+ Flags<[CoreOption]>;
+def fno_profile_sample_use : Flag<["-"], "fno-profile-sample-use">, Group<f_Group>,
+ Flags<[CoreOption]>;
def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">,
Group<f_Group>, Flags<[DriverOption, CC1Option]>,
HelpText<"Enable sample-based profile guided optimizations">;
+def fauto_profile : Flag<["-"], "fauto-profile">, Group<f_Group>,
+ Alias<fprofile_sample_use>;
+def fno_auto_profile : Flag<["-"], "fno-auto-profile">, Group<f_Group>,
+ Alias<fno_profile_sample_use>;
def fauto_profile_EQ : Joined<["-"], "fauto-profile=">,
Alias<fprofile_sample_use_EQ>;
+def fdebug_info_for_profiling : Flag<["-"], "fdebug-info-for-profiling">, Group<f_Group>,
+ Flags<[CC1Option]>,
+ HelpText<"Emit extra debug info to make sample profile more accurate.">;
+def fno_debug_info_for_profiling : Flag<["-"], "fno-debug-info-for-profiling">, Group<f_Group>,
+ Flags<[DriverOption]>,
+ HelpText<"Do not emit extra debug info for sample profiler.">;
def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
Group<f_Group>, Flags<[CoreOption]>,
- HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overriden by '=' form of option or LLVM_PROFILE_FILE env var)">;
+ HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
def fprofile_instr_generate_EQ : Joined<["-"], "fprofile-instr-generate=">,
Group<f_Group>, Flags<[CoreOption]>, MetaVarName<"<file>">,
HelpText<"Generate instrumented code to collect execution counts into <file> (overridden by LLVM_PROFILE_FILE env var)">;
@@ -565,6 +694,9 @@ def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>;
def fbuiltin_module_map : Flag <["-"], "fbuiltin-module-map">, Group<f_Group>,
Flags<[DriverOption]>, HelpText<"Load the clang builtins module map file.">;
def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group<f_Group>;
+def fclang_abi_compat_EQ : Joined<["-"], "fclang-abi-compat=">, Group<f_clang_Group>,
+ Flags<[CC1Option]>, MetaVarName<"<version>">, Values<"<major>.<minor>,latest">,
+ HelpText<"Attempt to match the ABI of Clang <version>">;
def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>;
def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>,
Flags<[CoreOption, CC1Option]>, HelpText<"Use colors in diagnostics">;
@@ -585,7 +717,8 @@ def fconstexpr_depth_EQ : Joined<["-"], "fconstexpr-depth=">, Group<f_Group>;
def fconstexpr_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group<f_Group>;
def fconstexpr_backtrace_limit_EQ : Joined<["-"], "fconstexpr-backtrace-limit=">,
Group<f_Group>;
-def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>;
+def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>,
+ HelpText<"Disable auto-generation of preprocessed source files and a script for reproduction during a clang crash">;
def fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>;
def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group<f_Group>,
HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>;
@@ -603,6 +736,9 @@ def fdiagnostics_print_source_range_info : Flag<["-"], "fdiagnostics-print-sourc
HelpText<"Print source range spans in numeric form">;
def fdiagnostics_show_hotness : Flag<["-"], "fdiagnostics-show-hotness">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Enable profile hotness information in diagnostic line">;
+def fdiagnostics_hotness_threshold_EQ : Joined<["-"], "fdiagnostics-hotness-threshold=">,
+ Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<number>">,
+ HelpText<"Prevent optimization remarks from being output if they do not have at least this profile count">;
def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Print option name with mappable diagnostics">;
def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">,
@@ -659,65 +795,74 @@ def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>;
def fjump_tables : Flag<["-"], "fjump-tables">, Group<f_Group>;
def fno_jump_tables : Flag<["-"], "fno-jump-tables">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Do not use jump tables for lowering switches">;
+
+// Begin sanitizer flags. These should all be core options exposed in all driver
+// modes.
+let Flags = [CC1Option, CoreOption] in {
+
def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
- Flags<[CC1Option, CoreOption]>, MetaVarName<"<check>">,
+ MetaVarName<"<check>">,
HelpText<"Turn on runtime checks for various forms of undefined "
"or suspicious behavior. See user manual for available checks">;
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>,
- Flags<[CoreOption]>;
+ Flags<[CoreOption, DriverOption]>;
def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">,
- Group<f_clang_Group>, Flags<[CC1Option, CoreOption]>,
+ Group<f_clang_Group>,
HelpText<"Path to blacklist file for sanitizers">;
def fno_sanitize_blacklist : Flag<["-"], "fno-sanitize-blacklist">,
Group<f_clang_Group>,
HelpText<"Don't use blacklist file for sanitizers">;
def fsanitize_coverage
: CommaJoined<["-"], "fsanitize-coverage=">,
- Group<f_clang_Group>, Flags<[CoreOption]>,
+ Group<f_clang_Group>,
HelpText<"Specify the type of coverage instrumentation for Sanitizers">;
def fno_sanitize_coverage
: CommaJoined<["-"], "fno-sanitize-coverage=">,
- Group<f_clang_Group>, Flags<[CoreOption]>,
+ Group<f_clang_Group>, Flags<[CoreOption, DriverOption]>,
HelpText<"Disable specified features of coverage instrumentation for "
- "Sanitizers">;
+ "Sanitizers">, Values<"func,bb,edge,indirect-calls,trace-bb,trace-cmp,trace-div,trace-gep,8bit-counters,trace-pc,trace-pc-guard,no-prune,inline-8bit-counters">;
def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable origins tracking in MemorySanitizer">;
def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable origins tracking in MemorySanitizer">;
def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable origins tracking in MemorySanitizer">;
def fsanitize_memory_use_after_dtor : Flag<["-"], "fsanitize-memory-use-after-dtor">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable use-after-destroy detection in MemorySanitizer">;
def fsanitize_address_field_padding : Joined<["-"], "fsanitize-address-field-padding=">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Level of field padding for AddressSanitizer">;
def fsanitize_address_use_after_scope : Flag<["-"], "fsanitize-address-use-after-scope">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable use-after-scope detection in AddressSanitizer">;
def fno_sanitize_address_use_after_scope : Flag<["-"], "fno-sanitize-address-use-after-scope">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable use-after-scope detection in AddressSanitizer">;
-def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>,
- Flags<[CoreOption]>;
+def fsanitize_address_globals_dead_stripping : Flag<["-"], "fsanitize-address-globals-dead-stripping">,
+ Group<f_clang_Group>,
+ HelpText<"Enable linker dead stripping of globals in AddressSanitizer">;
+def fsanitize_recover : Flag<["-"], "fsanitize-recover">, Group<f_clang_Group>;
def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">,
- Group<f_clang_Group>, Flags<[CoreOption]>;
+ Flags<[CoreOption, DriverOption]>,
+ Group<f_clang_Group>;
def fsanitize_recover_EQ : CommaJoined<["-"], "fsanitize-recover=">,
Group<f_clang_Group>,
- Flags<[CC1Option, CoreOption]>,
HelpText<"Enable recovery for specified sanitizers">;
def fno_sanitize_recover_EQ
: CommaJoined<["-"], "fno-sanitize-recover=">,
- Group<f_clang_Group>, Flags<[CoreOption]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable recovery for specified sanitizers">;
def fsanitize_trap_EQ : CommaJoined<["-"], "fsanitize-trap=">, Group<f_clang_Group>,
- Flags<[CC1Option, CoreOption]>,
HelpText<"Enable trapping for specified sanitizers">;
def fno_sanitize_trap_EQ : CommaJoined<["-"], "fno-sanitize-trap=">, Group<f_clang_Group>,
- Flags<[CoreOption]>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable trapping for specified sanitizers">;
def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">,
Group<f_clang_Group>;
@@ -726,39 +871,47 @@ def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-t
def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">,
Group<f_clang_Group>;
def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable control flow integrity (CFI) checks for cross-DSO calls.">;
def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Flags<[CoreOption, DriverOption]>,
+ Group<f_clang_Group>,
HelpText<"Disable control flow integrity (CFI) checks for cross-DSO calls.">;
def fsanitize_stats : Flag<["-"], "fsanitize-stats">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
HelpText<"Enable sanitizer statistics gathering.">;
def fno_sanitize_stats : Flag<["-"], "fno-sanitize-stats">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable sanitizer statistics gathering.">;
def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">,
Group<f_clang_Group>,
HelpText<"Enable memory access instrumentation in ThreadSanitizer (default)">;
def fno_sanitize_thread_memory_access : Flag<["-"], "fno-sanitize-thread-memory-access">,
Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable memory access instrumentation in ThreadSanitizer">;
def fsanitize_thread_func_entry_exit : Flag<["-"], "fsanitize-thread-func-entry-exit">,
Group<f_clang_Group>,
HelpText<"Enable function entry/exit instrumentation in ThreadSanitizer (default)">;
def fno_sanitize_thread_func_entry_exit : Flag<["-"], "fno-sanitize-thread-func-entry-exit">,
Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable function entry/exit instrumentation in ThreadSanitizer">;
def fsanitize_thread_atomics : Flag<["-"], "fsanitize-thread-atomics">,
Group<f_clang_Group>,
HelpText<"Enable atomic operations instrumentation in ThreadSanitizer (default)">;
def fno_sanitize_thread_atomics : Flag<["-"], "fno-sanitize-thread-atomics">,
Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
HelpText<"Disable atomic operations instrumentation in ThreadSanitizer">;
def fsanitize_undefined_strip_path_components_EQ : Joined<["-"], "fsanitize-undefined-strip-path-components=">,
- Group<f_clang_Group>, Flags<[CC1Option]>, MetaVarName<"<number>">,
+ Group<f_clang_Group>, MetaVarName<"<number>">,
HelpText<"Strip (or keep only, if negative) a given number of path components "
"when emitting check metadata.">;
+
+} // end -f[no-]sanitize* flags
+
def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
Group<f_Group>;
def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,
@@ -786,7 +939,7 @@ def ftrapping_math : Flag<["-"], "ftrapping-math">, Group<f_Group>, Flags<[CC1Op
def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group<f_Group>, Flags<[CC1Option]>;
def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)"
- " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">;
+ " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">, Values<"fast,on,off">;
def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>;
def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>;
@@ -795,6 +948,10 @@ def frewrite_includes : Flag<["-"], "frewrite-includes">, Group<f_Group>,
Flags<[CC1Option]>;
def fno_rewrite_includes : Flag<["-"], "fno-rewrite-includes">, Group<f_Group>;
+def frewrite_imports : Flag<["-"], "frewrite-imports">, Group<f_Group>,
+ Flags<[CC1Option]>;
+def fno_rewrite_imports : Flag<["-"], "fno-rewrite-imports">, Group<f_Group>;
+
def frewrite_map_file : Separate<["-"], "frewrite-map-file">,
Group<f_Group>,
Flags<[ DriverOption, CC1Option ]>;
@@ -816,12 +973,13 @@ def fno_gnu89_inline : Flag<["-"], "fno-gnu89-inline">, Group<f_Group>;
def fgnu_runtime : Flag<["-"], "fgnu-runtime">, Group<f_Group>,
HelpText<"Generate output compatible with the standard GNU Objective-C runtime">;
def fheinous_gnu_extensions : Flag<["-"], "fheinous-gnu-extensions">, Flags<[CC1Option]>;
-def filelist : Separate<["-"], "filelist">, Flags<[LinkerInput]>;
+def filelist : Separate<["-"], "filelist">, Flags<[LinkerInput]>,
+ Group<Link_Group>;
def : Flag<["-"], "findirect-virtual-calls">, Alias<fapple_kext>;
def finline_functions : Flag<["-"], "finline-functions">, Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Inline suitable functions">;
def finline_hint_functions: Flag<["-"], "finline-hint-functions">, Group<f_clang_Group>, Flags<[CC1Option]>,
- HelpText<"Inline functions wich are (explicitly or implicitly) marked inline">;
+ HelpText<"Inline functions which are (explicitly or implicitly) marked inline">;
def finline : Flag<["-"], "finline">, Group<clang_ignored_f_Group>;
def fexperimental_new_pass_manager : Flag<["-"], "fexperimental-new-pass-manager">,
Group<f_clang_Group>, Flags<[CC1Option]>,
@@ -845,11 +1003,20 @@ def fxray_instruction_threshold_ :
JoinedOrSeparate<["-"], "fxray-instruction-threshold">,
Group<f_Group>, Flags<[CC1Option]>;
+def fxray_always_instrument :
+ JoinedOrSeparate<["-"], "fxray-always-instrument=">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Filename defining the whitelist for imbuing the 'always instrument' XRay attribute.">;
+def fxray_never_instrument :
+ JoinedOrSeparate<["-"], "fxray-never-instrument=">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Filename defining the whitelist for imbuing the 'never instrument' XRay attribute.">;
+
def flat__namespace : Flag<["-"], "flat_namespace">;
def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
-def flto_EQ : Joined<["-"], "flto=">, Flags<[CC1Option]>, Group<f_Group>,
- HelpText<"Set LTO mode to either 'full' or 'thin'">;
+def flto_EQ : Joined<["-"], "flto=">, Flags<[CoreOption, CC1Option]>, Group<f_Group>,
+ HelpText<"Set LTO mode to either 'full' or 'thin'">, Values<"thin,full">;
def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option]>, Group<f_Group>,
HelpText<"Enable LTO in 'full' mode">;
def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>,
@@ -1007,7 +1174,7 @@ def fno_experimental_new_pass_manager : Flag<["-"], "fno-experimental-new-pass-m
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Disables an experimental new pass manager in LLVM.">;
def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Use the given vector functions library">;
+ HelpText<"Use the given vector functions library">, Values<"Accelerate,SVML,none">;
def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>,
HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>;
def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>,
@@ -1191,7 +1358,7 @@ def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, Flags<[CC1
HelpText<"Force wchar_t to be an unsigned int">;
def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Which overload candidates to show when overload resolution fails: "
- "best|all; defaults to all">;
+ "best|all; defaults to all">, Values<"best,all">;
def fshow_column : Flag<["-"], "fshow-column">, Group<f_Group>, Flags<[CC1Option]>;
def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>;
def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>;
@@ -1213,6 +1380,10 @@ def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_Group>,
HelpText<"Limit debug information produced to reduce size of debug binary">;
def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Flags<[CoreOption]>, Alias<fno_standalone_debug>;
def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Flags<[CoreOption]>, Alias<fstandalone_debug>;
+def fdebug_macro : Flag<["-"], "fdebug-macro">, Group<f_Group>, Flags<[CoreOption]>,
+ HelpText<"Emit macro debug information">;
+def fno_debug_macro : Flag<["-"], "fno-debug-macro">, Group<f_Group>, Flags<[CoreOption]>,
+ HelpText<"Do not emit macro debug information">;
def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>,
Flags<[DriverOption, CoreOption]>;
def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>,
@@ -1250,9 +1421,6 @@ def : Flag<["-"], "fno-tree-vectorize">, Alias<fno_vectorize>;
def fslp_vectorize : Flag<["-"], "fslp-vectorize">, Group<f_Group>,
HelpText<"Enable the superword-level parallelism vectorization passes">;
def fno_slp_vectorize : Flag<["-"], "fno-slp-vectorize">, Group<f_Group>;
-def fslp_vectorize_aggressive : Flag<["-"], "fslp-vectorize-aggressive">, Group<f_Group>,
- HelpText<"Enable the BB vectorization passes">;
-def fno_slp_vectorize_aggressive : Flag<["-"], "fno-slp-vectorize-aggressive">, Group<f_Group>;
def : Flag<["-"], "ftree-slp-vectorize">, Alias<fslp_vectorize>;
def : Flag<["-"], "fno-tree-slp-vectorize">, Alias<fno_slp_vectorize>;
def Wlarge_by_value_copy_def : Flag<["-"], "Wlarge-by-value-copy">,
@@ -1301,7 +1469,7 @@ def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1
def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group<clang_ignored_f_Group>;
def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>;
def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>,
- HelpText<"Set the default symbol visibility for all global declarations">;
+ HelpText<"Set the default symbol visibility for all global declarations">, Values<"hidden,default">;
def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>,
HelpText<"Give inline C++ member functions default visibility by default">,
Flags<[CC1Option]>;
@@ -1335,11 +1503,17 @@ def fno_unique_section_names : Flag <["-"], "fno-unique-section-names">,
def fstrict_return : Flag<["-"], "fstrict-return">, Group<f_Group>,
Flags<[CC1Option]>,
- HelpText<"Always treat control flow paths that fall off the end of a non-void"
- "function as unreachable">;
+ HelpText<"Always treat control flow paths that fall off the end of a "
+ "non-void function as unreachable">;
def fno_strict_return : Flag<["-"], "fno-strict-return">, Group<f_Group>,
Flags<[CC1Option]>;
+def fallow_editor_placeholders : Flag<["-"], "fallow-editor-placeholders">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Treat editor placeholders as valid source code">;
+def fno_allow_editor_placeholders : Flag<["-"],
+ "fno-allow-editor-placeholders">, Group<f_Group>;
+
def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">;
def fno_debug_types_section: Flag<["-"], "fno-debug-types-section">, Group<f_Group>,
@@ -1402,6 +1576,10 @@ def gdwarf_aranges : Flag<["-"], "gdwarf-aranges">, Group<g_flags_Group>;
def gmodules : Flag <["-"], "gmodules">, Group<gN_Group>,
HelpText<"Generate debug info with external references to clang modules"
" or precompiled headers">;
+def gz : Flag<["-"], "gz">, Group<g_flags_Group>,
+ HelpText<"DWARF debug sections compression type">;
+def gz_EQ : Joined<["-"], "gz=">, Group<g_flags_Group>,
+ HelpText<"DWARF debug sections compression type">;
def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">;
def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption]>,
HelpText<"Display available options">;
@@ -1411,6 +1589,11 @@ def idirafter : JoinedOrSeparate<["-"], "idirafter">, Group<clang_i_Group>, Flag
HelpText<"Add directory to AFTER include search path">;
def iframework : JoinedOrSeparate<["-"], "iframework">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Add directory to SYSTEM framework search path">;
+def iframeworkwithsysroot : JoinedOrSeparate<["-"], "iframeworkwithsysroot">,
+ Group<clang_i_Group>,
+ HelpText<"Add directory to SYSTEM framework search path, "
+ "absolute paths are relative to -isysroot">,
+ MetaVarName<"<directory>">, Flags<[CC1Option]>;
def imacros : JoinedOrSeparate<["-", "--"], "imacros">, Group<clang_i_Group>, Flags<[CC1Option]>,
HelpText<"Include macros from file before parsing">, MetaVarName<"<file>">;
def image__base : Separate<["-"], "image_base">;
@@ -1449,7 +1632,8 @@ def ivfsoverlay : JoinedOrSeparate<["-"], "ivfsoverlay">, Group<clang_i_Group>,
HelpText<"Overlay the virtual filesystem described by file over the real file system">;
def i : Joined<["-"], "i">, Group<i_Group>;
def keep__private__externs : Flag<["-"], "keep_private_externs">;
-def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>;
+def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>,
+ Group<Link_Group>;
def lazy__framework : Separate<["-"], "lazy_framework">, Flags<[LinkerInput]>;
def lazy__library : Separate<["-"], "lazy_library">, Flags<[LinkerInput]>;
def mlittle_endian : Flag<["-"], "mlittle-endian">, Flags<[DriverOption]>;
@@ -1484,15 +1668,17 @@ def mpure_code : Flag<["-"], "mpure-code">, Alias<mexecute_only>; // Alias for G
def mno_pure_code : Flag<["-"], "mno-pure-code">, Alias<mno_execute_only>;
def mtvos_version_min_EQ : Joined<["-"], "mtvos-version-min=">, Group<m_Group>;
def mappletvos_version_min_EQ : Joined<["-"], "mappletvos-version-min=">, Alias<mtvos_version_min_EQ>;
-def mtvos_simulator_version_min_EQ : Joined<["-"], "mtvos-simulator-version-min=">, Alias<mtvos_version_min_EQ>;
-def mappletvsimulator_version_min_EQ : Joined<["-"], "mappletvsimulator-version-min=">, Alias<mtvos_version_min_EQ>;
+def mtvos_simulator_version_min_EQ : Joined<["-"], "mtvos-simulator-version-min=">;
+def mappletvsimulator_version_min_EQ : Joined<["-"], "mappletvsimulator-version-min=">, Alias<mtvos_simulator_version_min_EQ>;
def mwatchos_version_min_EQ : Joined<["-"], "mwatchos-version-min=">, Group<m_Group>;
-def mwatchos_simulator_version_min_EQ : Joined<["-"], "mwatchos-simulator-version-min=">, Alias<mwatchos_version_min_EQ>;
-def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias<mwatchos_version_min_EQ>;
+def mwatchos_simulator_version_min_EQ : Joined<["-"], "mwatchos-simulator-version-min=">;
+def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=">, Alias<mwatchos_simulator_version_min_EQ>;
def march_EQ : Joined<["-"], "march=">, Group<m_Group>;
def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Flags<[DriverOption]>;
def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>;
def mimplicit_it_EQ : Joined<["-"], "mimplicit-it=">, Group<m_Group>;
+def mdefault_build_attributes : Joined<["-"], "mdefault-build-attributes">, Group<m_Group>;
+def mno_default_build_attributes : Joined<["-"], "mno-default-build-attributes">, Group<m_Group>;
def mconstant_cfstrings : Flag<["-"], "mconstant-cfstrings">, Group<clang_ignored_m_Group>;
def mconsole : Joined<["-"], "mconsole">, Group<m_Group>, Flags<[DriverOption]>;
def mwindows : Joined<["-"], "mwindows">, Group<m_Group>, Flags<[DriverOption]>;
@@ -1500,6 +1686,7 @@ def mdll : Joined<["-"], "mdll">, Group<m_Group>, Flags<[DriverOption]>;
def municode : Joined<["-"], "municode">, Group<m_Group>, Flags<[DriverOption]>;
def mthreads : Joined<["-"], "mthreads">, Group<m_Group>, Flags<[DriverOption]>;
def mcpu_EQ : Joined<["-"], "mcpu=">, Group<m_Group>;
+def mmcu_EQ : Joined<["-"], "mmcu=">, Group<m_Group>;
def mdynamic_no_pic : Joined<["-"], "mdynamic-no-pic">, Group<m_Group>;
def mfix_and_continue : Flag<["-"], "mfix-and-continue">, Group<clang_ignored_m_Group>;
def mieee_fp : Flag<["-"], "mieee-fp">, Group<clang_ignored_m_Group>;
@@ -1507,7 +1694,7 @@ def minline_all_stringops : Flag<["-"], "minline-all-stringops">, Group<clang_ig
def mno_inline_all_stringops : Flag<["-"], "mno-inline-all-stringops">, Group<clang_ignored_m_Group>;
def malign_double : Flag<["-"], "malign-double">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Align doubles to two words in structs (x86 only)">;
-def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>;
+def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>, Values<"soft,softfp,hard">;
def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group<m_Group>;
def mfpu_EQ : Joined<["-"], "mfpu=">, Group<m_Group>;
def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group<m_Group>;
@@ -1517,8 +1704,8 @@ def mhard_float : Flag<["-"], "mhard-float">, Group<m_Group>;
def miphoneos_version_min_EQ : Joined<["-"], "miphoneos-version-min=">, Group<m_Group>;
def mios_version_min_EQ : Joined<["-"], "mios-version-min=">,
Alias<miphoneos_version_min_EQ>, HelpText<"Set iOS deployment target">;
-def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">, Alias<miphoneos_version_min_EQ>;
-def miphonesimulator_version_min_EQ : Joined<["-"], "miphonesimulator-version-min=">, Alias<miphoneos_version_min_EQ>;
+def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">;
+def miphonesimulator_version_min_EQ : Joined<["-"], "miphonesimulator-version-min=">, Alias<mios_simulator_version_min_EQ>;
def mkernel : Flag<["-"], "mkernel">, Group<m_Group>;
def mlinker_version_EQ : Joined<["-"], "mlinker-version=">,
Flags<[DriverOption]>;
@@ -1526,6 +1713,8 @@ def mllvm : Separate<["-"], "mllvm">, Flags<[CC1Option,CC1AsOption,CoreOption]>,
HelpText<"Additional arguments to forward to LLVM's option processing">;
def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">,
Group<m_Group>, HelpText<"Set Mac OS X deployment target">;
+def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
+ Group<m_Group>, Alias<mmacosx_version_min_EQ>;
def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">;
def mno_ms_bitfields : Flag<["-"], "mno-ms-bitfields">, Group<m_Group>,
@@ -1537,9 +1726,9 @@ def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group<m_Group>, Flags
def mstack_probe_size : Joined<["-"], "mstack-probe-size=">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Set the stack probe size">;
def mthread_model : Separate<["-"], "mthread-model">, Group<m_Group>, Flags<[CC1Option]>,
- HelpText<"The thread model to use, e.g. posix, single (posix by default)">;
+ HelpText<"The thread model to use, e.g. posix, single (posix by default)">, Values<"posix,single">;
def meabi : Separate<["-"], "meabi">, Group<m_Group>, Flags<[CC1Option]>,
- HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">;
+ HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">, Values<"default,4,5,gnu">;
def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>;
def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>;
@@ -1573,6 +1762,7 @@ def mno_avx : Flag<["-"], "mno-avx">, Group<m_x86_Features_Group>;
def mno_avx2 : Flag<["-"], "mno-avx2">, Group<m_x86_Features_Group>;
def mno_avx512f : Flag<["-"], "mno-avx512f">, Group<m_x86_Features_Group>;
def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group<m_x86_Features_Group>;
+def mno_avx512vpopcntdq : Flag<["-"], "mno-avx512vpopcntdq">, Group<m_x86_Features_Group>;
def mno_avx512er : Flag<["-"], "mno-avx512er">, Group<m_x86_Features_Group>;
def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group<m_x86_Features_Group>;
def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group<m_x86_Features_Group>;
@@ -1588,6 +1778,7 @@ def mno_bmi : Flag<["-"], "mno-bmi">, Group<m_x86_Features_Group>;
def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group<m_x86_Features_Group>;
def mno_popcnt : Flag<["-"], "mno-popcnt">, Group<m_x86_Features_Group>;
def mno_tbm : Flag<["-"], "mno-tbm">, Group<m_x86_Features_Group>;
+def mno_lwp : Flag<["-"], "mno-lwp">, Group<m_x86_Features_Group>;
def mno_fma4 : Flag<["-"], "mno-fma4">, Group<m_x86_Features_Group>;
def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>;
def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>;
@@ -1604,7 +1795,14 @@ def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group<m_x86_Features_Group>;
def mno_xsavec : Flag<["-"], "mno-xsavec">, Group<m_x86_Features_Group>;
def mno_xsaves : Flag<["-"], "mno-xsaves">, Group<m_x86_Features_Group>;
def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group<m_x86_Features_Group>;
+def mno_clzero : Flag<["-"], "mno-clzero">, Group<m_x86_Features_Group>;
def mno_pku : Flag<["-"], "mno-pku">, Group<m_x86_Features_Group>;
+def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group<m_x86_Features_Group>;
+def mno_clwb : Flag<["-"], "mno-clwb">, Group<m_x86_Features_Group>;
+def mno_movbe : Flag<["-"], "mno-movbe">, Group<m_x86_Features_Group>;
+def mno_mpx : Flag<["-"], "mno-mpx">, Group<m_x86_Features_Group>;
+def mno_sgx : Flag<["-"], "mno-sgx">, Group<m_x86_Features_Group>;
+def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group<m_x86_Features_Group>;
def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">;
@@ -1626,6 +1824,8 @@ def mcrc : Flag<["-"], "mcrc">, Group<m_arm_Features_Group>,
HelpText<"Allow use of CRC instructions (ARM only)">;
def mnocrc : Flag<["-"], "mnocrc">, Group<m_arm_Features_Group>,
HelpText<"Disallow use of CRC instructions (ARM only)">;
+def mno_neg_immediates: Flag<["-"], "mno-neg-immediates">, Group<m_arm_Features_Group>,
+ HelpText<"Disallow converting instructions with negative immediates to their negation or inversion.">;
def mgeneral_regs_only : Flag<["-"], "mgeneral-regs-only">, Group<m_aarch64_Features_Group>,
HelpText<"Generate code which only uses the general purpose registers (AArch64 only)">;
@@ -1648,6 +1848,10 @@ def mamdgpu_debugger_abi : Joined<["-"], "mamdgpu-debugger-abi=">,
HelpText<"Generate additional code for specified <version> of debugger ABI (AMDGPU only)">,
MetaVarName<"<version>">;
+def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[DriverOption]>;
+def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[DriverOption]>;
+def maltivec : Flag<["-"], "maltivec">, Group<m_ppc_Features_Group>;
+def mno_altivec : Flag<["-"], "mno-altivec">, Group<m_ppc_Features_Group>;
def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>;
def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>;
def mpower8_vector : Flag<["-"], "mpower8-vector">,
@@ -1698,12 +1902,6 @@ def mlongcall: Flag<["-"], "mlongcall">,
def mno_longcall : Flag<["-"], "mno-longcall">,
Group<m_ppc_Features_Group>;
-def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Enable AltiVec vector initializer syntax">;
-def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[CC1Option]>;
-def maltivec : Flag<["-"], "maltivec">, Alias<faltivec>;
-def mno_altivec : Flag<["-"], "mno-altivec">, Alias<fno_altivec>;
-
def mvx : Flag<["-"], "mvx">, Group<m_Group>;
def mno_vx : Flag<["-"], "mno-vx">, Group<m_Group>;
@@ -1735,7 +1933,8 @@ def mno_incremental_linker_compatible : Flag<["-"], "mno-incremental-linker-comp
HelpText<"(integrated-as) Emit an object file which cannot be used with an incremental linker">;
def mrtd : Flag<["-"], "mrtd">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Make StdCall calling convention the default">;
-def msmall_data_threshold_EQ : Joined <["-"], "msmall-data-threshold=">, Group<m_Group>;
+def msmall_data_threshold_EQ : Joined <["-"], "msmall-data-threshold=">,
+ Group<m_Group>, Alias<G>;
def msoft_float : Flag<["-"], "msoft-float">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Use software floating point">;
def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>,
@@ -1747,6 +1946,8 @@ def mpie_copy_relocations : Flag<["-"], "mpie-copy-relocations">, Group<m_Group>
Flags<[CC1Option]>,
HelpText<"Use copy relocations support for PIE builds">;
def mno_pie_copy_relocations : Flag<["-"], "mno-pie-copy-relocations">, Group<m_Group>;
+def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86 only)">,
+ Flags<[CC1Option]>, Group<m_Group>;
def mx87 : Flag<["-"], "mx87">, Group<m_x86_Features_Group>;
def m80387 : Flag<["-"], "m80387">, Alias<mx87>;
def msse2 : Flag<["-"], "msse2">, Group<m_x86_Features_Group>;
@@ -1762,6 +1963,7 @@ def mavx : Flag<["-"], "mavx">, Group<m_x86_Features_Group>;
def mavx2 : Flag<["-"], "mavx2">, Group<m_x86_Features_Group>;
def mavx512f : Flag<["-"], "mavx512f">, Group<m_x86_Features_Group>;
def mavx512cd : Flag<["-"], "mavx512cd">, Group<m_x86_Features_Group>;
+def mavx512vpopcntdq : Flag<["-"], "mavx512vpopcntdq">, Group<m_x86_Features_Group>;
def mavx512er : Flag<["-"], "mavx512er">, Group<m_x86_Features_Group>;
def mavx512pf : Flag<["-"], "mavx512pf">, Group<m_x86_Features_Group>;
def mavx512dq : Flag<["-"], "mavx512dq">, Group<m_x86_Features_Group>;
@@ -1777,6 +1979,7 @@ def mbmi : Flag<["-"], "mbmi">, Group<m_x86_Features_Group>;
def mbmi2 : Flag<["-"], "mbmi2">, Group<m_x86_Features_Group>;
def mpopcnt : Flag<["-"], "mpopcnt">, Group<m_x86_Features_Group>;
def mtbm : Flag<["-"], "mtbm">, Group<m_x86_Features_Group>;
+def mlwp : Flag<["-"], "mlwp">, Group<m_x86_Features_Group>;
def mfma4 : Flag<["-"], "mfma4">, Group<m_x86_Features_Group>;
def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>;
def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>;
@@ -1794,6 +1997,13 @@ def mxsaveopt : Flag<["-"], "mxsaveopt">, Group<m_x86_Features_Group>;
def mxsavec : Flag<["-"], "mxsavec">, Group<m_x86_Features_Group>;
def mxsaves : Flag<["-"], "mxsaves">, Group<m_x86_Features_Group>;
def mmwaitx : Flag<["-"], "mmwaitx">, Group<m_x86_Features_Group>;
+def mclzero : Flag<["-"], "mclzero">, Group<m_x86_Features_Group>;
+def mclflushopt : Flag<["-"], "mclflushopt">, Group<m_x86_Features_Group>;
+def mclwb : Flag<["-"], "mclwb">, Group<m_x86_Features_Group>;
+def mmovbe : Flag<["-"], "mmovbe">, Group<m_x86_Features_Group>;
+def mmpx : Flag<["-"], "mmpx">, Group<m_x86_Features_Group>;
+def msgx : Flag<["-"], "msgx">, Group<m_x86_Features_Group>;
+def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group<m_x86_Features_Group>;
def mips16 : Flag<["-"], "mips16">, Group<m_Group>;
def mno_mips16 : Flag<["-"], "mno-mips16">, Group<m_Group>;
def mmicromips : Flag<["-"], "mmicromips">, Group<m_Group>;
@@ -1812,10 +2022,18 @@ def mdspr2 : Flag<["-"], "mdspr2">, Group<m_Group>;
def mno_dspr2 : Flag<["-"], "mno-dspr2">, Group<m_Group>;
def msingle_float : Flag<["-"], "msingle-float">, Group<m_Group>;
def mdouble_float : Flag<["-"], "mdouble-float">, Group<m_Group>;
+def mmadd4 : Flag<["-"], "mmadd4">, Group<m_Group>,
+ HelpText<"Enable the generation of 4-operand madd.s, madd.d and related instructions.">;
+def mno_madd4 : Flag<["-"], "mno-madd4">, Group<m_Group>,
+ HelpText<"Disable the generation of 4-operand madd.s, madd.d and related instructions.">;
def mmsa : Flag<["-"], "mmsa">, Group<m_Group>,
HelpText<"Enable MSA ASE (MIPS only)">;
def mno_msa : Flag<["-"], "mno-msa">, Group<m_Group>,
HelpText<"Disable MSA ASE (MIPS only)">;
+def mmt : Flag<["-"], "mmt">, Group<m_Group>,
+ HelpText<"Enable MT ASE (MIPS only)">;
+def mno_mt : Flag<["-"], "mno-mt">, Group<m_Group>,
+ HelpText<"Disable MT ASE (MIPS only)">;
def mfp64 : Flag<["-"], "mfp64">, Group<m_Group>,
HelpText<"Use 64-bit floating point registers (MIPS only)">;
def mfp32 : Flag<["-"], "mfp32">, Group<m_Group>,
@@ -1895,7 +2113,7 @@ def no_cpp_precomp : Flag<["-"], "no-cpp-precomp">, Group<clang_ignored_f_Group>
def no_integrated_cpp : Flag<["-", "--"], "no-integrated-cpp">, Flags<[DriverOption]>;
def no_pedantic : Flag<["-", "--"], "no-pedantic">, Group<pedantic_Group>;
def no__dead__strip__inits__and__terms : Flag<["-"], "no_dead_strip_inits_and_terms">;
-def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option]>,
+def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option, CoreOption]>,
HelpText<"Disable builtin #include directories">;
def nocudainc : Flag<["-"], "nocudainc">;
def nocudalib : Flag<["-"], "nocudalib">;
@@ -1904,10 +2122,11 @@ def nofixprebinding : Flag<["-"], "nofixprebinding">;
def nolibc : Flag<["-"], "nolibc">;
def nomultidefs : Flag<["-"], "nomultidefs">;
def nopie : Flag<["-"], "nopie">;
+def no_pie : Flag<["-"], "no-pie">, Alias<nopie>;
def noprebind : Flag<["-"], "noprebind">;
def noseglinkedit : Flag<["-"], "noseglinkedit">;
def nostartfiles : Flag<["-"], "nostartfiles">;
-def nostdinc : Flag<["-"], "nostdinc">;
+def nostdinc : Flag<["-"], "nostdinc">, Flags<[CoreOption]>;
def nostdlibinc : Flag<["-"], "nostdlibinc">;
def nostdincxx : Flag<["-"], "nostdinc++">, Flags<[CC1Option]>,
HelpText<"Disable standard #include directories for the C++ standard library">;
@@ -1938,6 +2157,8 @@ def print_multi_os_directory : Flag<["-", "--"], "print-multi-os-directory">,
Flags<[Unsupported]>;
def print_prog_name_EQ : Joined<["-", "--"], "print-prog-name=">,
HelpText<"Print the full program path of <name>">, MetaVarName<"<name>">;
+def print_resource_dir : Flag<["-", "--"], "print-resource-dir">,
+ HelpText<"Print the resource directory pathname">;
def print_search_dirs : Flag<["-", "--"], "print-search-dirs">,
HelpText<"Print the paths used for finding libraries and programs">;
def private__bundle : Flag<["-"], "private_bundle">;
@@ -1959,10 +2180,15 @@ def resource_dir : Separate<["-"], "resource-dir">,
HelpText<"The directory which holds the compiler resource files">;
def resource_dir_EQ : Joined<["-"], "resource-dir=">, Flags<[DriverOption, CoreOption]>,
Alias<resource_dir>;
-def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>;
+def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>, Group<Link_Group>;
def rtlib_EQ : Joined<["-", "--"], "rtlib=">,
HelpText<"Compiler runtime library to use">;
-def r : Flag<["-"], "r">, Flags<[LinkerInput,NoArgumentUnused]>;
+def frtlib_add_rpath: Flag<["-"], "frtlib-add-rpath">, Flags<[NoArgumentUnused]>,
+ HelpText<"Add -rpath with architecture-specific resource directory to the linker flags">;
+def fno_rtlib_add_rpath: Flag<["-"], "fno-rtlib-add-rpath">, Flags<[NoArgumentUnused]>,
+ HelpText<"Do not add -rpath with architecture-specific resource directory to the linker flags">;
+def r : Flag<["-"], "r">, Flags<[LinkerInput,NoArgumentUnused]>,
+ Group<Link_Group>;
def save_temps_EQ : Joined<["-", "--"], "save-temps=">, Flags<[DriverOption]>,
HelpText<"Save intermediate compilation results.">;
def save_temps : Flag<["-", "--"], "save-temps">, Flags<[DriverOption]>,
@@ -2001,7 +2227,7 @@ def std_default_EQ : Joined<["-"], "std-default=">;
def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>,
Group<CompileOnly_Group>, HelpText<"Language standard to compile for">;
def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>,
- HelpText<"C++ standard library to use">;
+ HelpText<"C++ standard library to use">, Values<"libc++,libstdc++,platform">;
def sub__library : JoinedOrSeparate<["-"], "sub_library">;
def sub__umbrella : JoinedOrSeparate<["-"], "sub_umbrella">;
def system_header_prefix : Joined<["--"], "system-header-prefix=">,
@@ -2014,7 +2240,7 @@ def no_system_header_prefix : Joined<["--"], "no-system-header-prefix=">,
HelpText<"Treat all #include paths starting with <prefix> as not including a "
"system header.">;
def : Separate<["--"], "no-system-header-prefix">, Alias<no_system_header_prefix>;
-def s : Flag<["-"], "s">;
+def s : Flag<["-"], "s">, Group<Link_Group>;
def target : Joined<["--"], "target=">, Flags<[DriverOption, CoreOption]>,
HelpText<"Generate code for the given target">;
def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[DriverOption]>,
@@ -2028,7 +2254,7 @@ def trigraphs : Flag<["-", "--"], "trigraphs">, Alias<ftrigraphs>,
HelpText<"Process trigraph sequences">;
def twolevel__namespace__hints : Flag<["-"], "twolevel_namespace_hints">;
def twolevel__namespace : Flag<["-"], "twolevel_namespace">;
-def t : Flag<["-"], "t">;
+def t : Flag<["-"], "t">, Group<Link_Group>;
def umbrella : Separate<["-"], "umbrella">;
def undefined : JoinedOrSeparate<["-"], "undefined">, Group<u_Group>;
def undef : Flag<["-"], "undef">, Group<u_Group>, Flags<[CC1Option]>,
@@ -2185,6 +2411,8 @@ def mv55 : Flag<["-"], "mv55">, Group<m_hexagon_Features_Group>,
Alias<mcpu_EQ>, AliasArgs<["hexagonv55"]>;
def mv60 : Flag<["-"], "mv60">, Group<m_hexagon_Features_Group>,
Alias<mcpu_EQ>, AliasArgs<["hexagonv60"]>;
+def mv62 : Flag<["-"], "mv62">, Group<m_hexagon_Features_Group>,
+ Alias<mcpu_EQ>, AliasArgs<["hexagonv62"]>;
def mhexagon_hvx : Flag<["-"], "mhvx">, Group<m_hexagon_Features_Group>,
Flags<[CC1Option]>, HelpText<"Enable Hexagon Vector eXtensions">;
def mno_hexagon_hvx : Flag<["-"], "mno-hvx">, Group<m_hexagon_Features_Group>,
@@ -2322,10 +2550,6 @@ defm devirtualize : BooleanFFlag<"devirtualize">, Group<clang_ignored_gcc_optimi
defm devirtualize_speculatively : BooleanFFlag<"devirtualize-speculatively">,
Group<clang_ignored_gcc_optimization_f_Group>;
-// gfortran options that we recognize in the driver and pass along when
-// invoking GCC to compile Fortran code.
-def gfortran_Group : OptionGroup<"gfortran Group">;
-
// Generic gfortran options.
def A_DASH : Joined<["-"], "A-">, Group<gfortran_Group>;
def J : JoinedOrSeparate<["-"], "J">, Flags<[RenderJoined]>, Group<gfortran_Group>;
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h b/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h
index 6206680..a9645d4 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h
+++ b/contrib/llvm/tools/clang/include/clang/Driver/SanitizerArgs.h
@@ -34,7 +34,8 @@ class SanitizerArgs {
bool CfiCrossDso = false;
int AsanFieldPadding = 0;
bool AsanSharedRuntime = false;
- bool AsanUseAfterScope = false;
+ bool AsanUseAfterScope = true;
+ bool AsanGlobalsDeadStripping = false;
bool LinkCXXRuntimes = false;
bool NeedPIE = false;
bool Stats = false;
@@ -50,6 +51,7 @@ class SanitizerArgs {
bool needsSharedAsanRt() const { return AsanSharedRuntime; }
bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
+ bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); }
bool needsLsanRt() const {
return Sanitizers.has(SanitizerKind::Leak) &&
!Sanitizers.has(SanitizerKind::Address);
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Tool.h b/contrib/llvm/tools/clang/include/clang/Driver/Tool.h
index 5012cc8..8f76e17 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Tool.h
+++ b/contrib/llvm/tools/clang/include/clang/Driver/Tool.h
@@ -35,7 +35,7 @@ class Tool {
public:
// Documents the level of support for response files in this tool.
// Response files are necessary if the command line gets too large,
- // requiring the arguments to be transfered to a file.
+ // requiring the arguments to be transferred to a file.
enum ResponseFileSupport {
// Provides full support for response files, which means we can transfer
// all tool input arguments to a file. E.g.: clang, gcc, binutils and MSVC
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h b/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h
index ffb0d60..6651491 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h
+++ b/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h
@@ -44,6 +44,7 @@ namespace driver {
class RegisterEffectiveTriple;
class SanitizerArgs;
class Tool;
+ class XRayArgs;
/// ToolChain - Access to tools for a single platform.
class ToolChain {
@@ -94,12 +95,15 @@ private:
Tool *getOffloadBundler() const;
mutable std::unique_ptr<SanitizerArgs> SanitizerArguments;
+ mutable std::unique_ptr<XRayArgs> XRayArguments;
/// The effective clang triple for the current Job.
mutable llvm::Triple EffectiveTriple;
/// Set the toolchain's effective clang triple.
- void setEffectiveTriple(llvm::Triple ET) const { EffectiveTriple = ET; }
+ void setEffectiveTriple(llvm::Triple ET) const {
+ EffectiveTriple = std::move(ET);
+ }
friend class RegisterEffectiveTriple;
@@ -175,6 +179,8 @@ public:
const SanitizerArgs& getSanitizerArgs() const;
+ const XRayArgs& getXRayArgs() const;
+
// Returns the Arg * that explicitly turned on/off rtti, or nullptr.
const llvm::opt::Arg *getRTTIArg() const { return CachedRTTIArg; }
@@ -299,12 +305,17 @@ public:
const char *getCompilerRTArgString(const llvm::opt::ArgList &Args,
StringRef Component,
bool Shared = false) const;
+
+ // Returns <ResourceDir>/lib/<OSName>/<arch>. This is used by runtimes (such
+ // as OpenMP) to find arch-specific libraries.
+ std::string getArchSpecificLibPath() const;
+
/// needsProfileRT - returns true if instrumentation profile is on.
static bool needsProfileRT(const llvm::opt::ArgList &Args);
/// IsUnwindTablesDefault - Does this tool chain use -funwind-tables
/// by default.
- virtual bool IsUnwindTablesDefault() const;
+ virtual bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const;
/// \brief Test whether this toolchain defaults to PIC.
virtual bool isPICDefault() const = 0;
@@ -400,7 +411,8 @@ public:
/// \brief Add options that need to be passed to cc1 for this target.
virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const;
/// \brief Add warning options that need to be passed to cc1 for this target.
virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const;
@@ -471,7 +483,7 @@ class RegisterEffectiveTriple {
public:
RegisterEffectiveTriple(const ToolChain &TC, llvm::Triple T) : TC(TC) {
- TC.setEffectiveTriple(T);
+ TC.setEffectiveTriple(std::move(T));
}
~RegisterEffectiveTriple() { TC.setEffectiveTriple(llvm::Triple()); }
diff --git a/contrib/llvm/tools/clang/include/clang/Driver/XRayArgs.h b/contrib/llvm/tools/clang/include/clang/Driver/XRayArgs.h
new file mode 100644
index 0000000..83210d1
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Driver/XRayArgs.h
@@ -0,0 +1,38 @@
+//===--- XRayArgs.h - Arguments for XRay ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_DRIVER_XRAYARGS_H
+#define LLVM_CLANG_DRIVER_XRAYARGS_H
+
+#include "clang/Driver/Types.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+
+namespace clang {
+namespace driver {
+
+class ToolChain;
+
+class XRayArgs {
+ std::vector<std::string> AlwaysInstrumentFiles;
+ std::vector<std::string> NeverInstrumentFiles;
+ std::vector<std::string> ExtraDeps;
+ bool XRayInstrument = false;
+ int InstructionThreshold = 200;
+
+public:
+ /// Parses the XRay arguments from an argument list.
+ XRayArgs(const ToolChain &TC, const llvm::opt::ArgList &Args);
+ void addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const;
+};
+
+} // namespace driver
+} // namespace clang
+
+#endif // LLVM_CLANG_DRIVER_XRAYARGS_H
diff --git a/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h b/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h
index b6ec8b8..d95a0c2 100644
--- a/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h
+++ b/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h
@@ -17,6 +17,7 @@
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/Allocator.h"
#include <map>
+#include <tuple>
namespace clang {
class LangOptions;
@@ -41,9 +42,21 @@ class EditedSource {
typedef std::map<FileOffset, FileEdit> FileEditsTy;
FileEditsTy FileEdits;
- llvm::DenseMap<unsigned, llvm::TinyPtrVector<IdentifierInfo*>>
- ExpansionToArgMap;
- SmallVector<std::pair<SourceLocation, IdentifierInfo*>, 2>
+ struct MacroArgUse {
+ IdentifierInfo *Identifier;
+ SourceLocation ImmediateExpansionLoc;
+ // Location of argument use inside the top-level macro
+ SourceLocation UseLoc;
+
+ bool operator==(const MacroArgUse &Other) const {
+ return std::tie(Identifier, ImmediateExpansionLoc, UseLoc) ==
+ std::tie(Other.Identifier, Other.ImmediateExpansionLoc,
+ Other.UseLoc);
+ }
+ };
+
+ llvm::DenseMap<unsigned, SmallVector<MacroArgUse, 2>> ExpansionToArgMap;
+ SmallVector<std::pair<SourceLocation, MacroArgUse>, 2>
CurrCommitMacroArgExps;
IdentifierTable IdentTable;
@@ -65,7 +78,7 @@ public:
bool commit(const Commit &commit);
- void applyRewrites(EditsReceiver &receiver);
+ void applyRewrites(EditsReceiver &receiver, bool adjustRemovals = true);
void clearRewrites();
StringRef copyString(StringRef str) { return str.copy(StrAlloc); }
@@ -84,7 +97,7 @@ private:
FileEditsTy::iterator getActionForOffset(FileOffset Offs);
void deconstructMacroArgLoc(SourceLocation Loc,
SourceLocation &ExpansionLoc,
- IdentifierInfo *&II);
+ MacroArgUse &ArgUse);
void startingCommit();
void finishedCommit();
diff --git a/contrib/llvm/tools/clang/include/clang/Format/Format.h b/contrib/llvm/tools/clang/include/clang/Format/Format.h
index 6c6458b..99d54e5 100644
--- a/contrib/llvm/tools/clang/include/clang/Format/Format.h
+++ b/contrib/llvm/tools/clang/include/clang/Format/Format.h
@@ -98,9 +98,39 @@ struct FormatStyle {
/// \endcode
bool AlignConsecutiveDeclarations;
- /// \brief If ``true``, aligns escaped newlines as far left as possible.
- /// Otherwise puts them into the right-most column.
- bool AlignEscapedNewlinesLeft;
+ /// \brief Different styles for aligning escaped newlines.
+ enum EscapedNewlineAlignmentStyle {
+ /// \brief Don't align escaped newlines.
+ /// \code
+ /// #define A \
+ /// int aaaa; \
+ /// int b; \
+ /// int dddddddddd;
+ /// \endcode
+ ENAS_DontAlign,
+ /// \brief Align escaped newlines as far left as possible.
+ /// \code
+ /// true:
+ /// #define A \
+ /// int aaaa; \
+ /// int b; \
+ /// int dddddddddd;
+ ///
+ /// false:
+ /// \endcode
+ ENAS_Left,
+ /// \brief Align escaped newlines in the right-most column.
+ /// \code
+ /// #define A \
+ /// int aaaa; \
+ /// int b; \
+ /// int dddddddddd;
+ /// \endcode
+ ENAS_Right,
+ };
+
+ /// \brief Options for aligning backslashes in escaped newlines.
+ EscapedNewlineAlignmentStyle AlignEscapedNewlines;
/// \brief If ``true``, horizontally align operands of binary and ternary
/// expressions.
@@ -114,10 +144,21 @@ struct FormatStyle {
bool AlignOperands;
/// \brief If ``true``, aligns trailing comments.
+ /// \code
+ /// true: false:
+ /// int a; // My comment a vs. int a; // My comment a
+ /// int b = 2; // comment b int b = 2; // comment about b
+ /// \endcode
bool AlignTrailingComments;
/// \brief Allow putting all parameters of a function declaration onto
/// the next line even if ``BinPackParameters`` is ``false``.
+ /// \code
+ /// true: false:
+ /// myFunction(foo, vs. myFunction(foo, bar, plop);
+ /// bar,
+ /// plop);
+ /// \endcode
bool AllowAllParametersOfDeclarationOnNextLine;
/// \brief Allows contracting simple braced statements to a single line.
@@ -126,6 +167,16 @@ struct FormatStyle {
bool AllowShortBlocksOnASingleLine;
/// \brief If ``true``, short case labels will be contracted to a single line.
+ /// \code
+ /// true: false:
+ /// switch (a) { vs. switch (a) {
+ /// case 1: x = 1; break; case 1:
+ /// case 2: return; x = 1;
+ /// } break;
+ /// case 2:
+ /// return;
+ /// }
+ /// \endcode
bool AllowShortCaseLabelsOnASingleLine;
/// \brief Different styles for merging short functions containing at most one
@@ -133,11 +184,46 @@ struct FormatStyle {
enum ShortFunctionStyle {
/// \brief Never merge functions into a single line.
SFS_None,
+ /// \brief Only merge functions defined inside a class. Same as "inline",
+ /// except it does not implies "empty": i.e. top level empty functions
+ /// are not merged either.
+ /// \code
+ /// class Foo {
+ /// void f() { foo(); }
+ /// };
+ /// void f() {
+ /// foo();
+ /// }
+ /// void f() {
+ /// }
+ /// \endcode
+ SFS_InlineOnly,
/// \brief Only merge empty functions.
+ /// \code
+ /// void f() {}
+ /// void f2() {
+ /// bar2();
+ /// }
+ /// \endcode
SFS_Empty,
/// \brief Only merge functions defined inside a class. Implies "empty".
+ /// \code
+ /// class Foo {
+ /// void f() { foo(); }
+ /// };
+ /// void f() {
+ /// foo();
+ /// }
+ /// void f() {}
+ /// \endcode
SFS_Inline,
/// \brief Merge all functions fitting on a single line.
+ /// \code
+ /// class Foo {
+ /// void f() { foo(); }
+ /// };
+ /// void f() { bar(); }
+ /// \endcode
SFS_All,
};
@@ -153,6 +239,7 @@ struct FormatStyle {
bool AllowShortLoopsOnASingleLine;
/// \brief Different ways to break after the function definition return type.
+ /// This option is **deprecated** and is retained for backwards compatibility.
enum DefinitionReturnTypeBreakingStyle {
/// Break after return type automatically.
/// ``PenaltyReturnTypeOnItsOwnLine`` is taken into account.
@@ -168,19 +255,74 @@ struct FormatStyle {
enum ReturnTypeBreakingStyle {
/// Break after return type automatically.
/// ``PenaltyReturnTypeOnItsOwnLine`` is taken into account.
+ /// \code
+ /// class A {
+ /// int f() { return 0; };
+ /// };
+ /// int f();
+ /// int f() { return 1; }
+ /// \endcode
RTBS_None,
/// Always break after the return type.
+ /// \code
+ /// class A {
+ /// int
+ /// f() {
+ /// return 0;
+ /// };
+ /// };
+ /// int
+ /// f();
+ /// int
+ /// f() {
+ /// return 1;
+ /// }
+ /// \endcode
RTBS_All,
/// Always break after the return types of top-level functions.
+ /// \code
+ /// class A {
+ /// int f() { return 0; };
+ /// };
+ /// int
+ /// f();
+ /// int
+ /// f() {
+ /// return 1;
+ /// }
+ /// \endcode
RTBS_TopLevel,
/// Always break after the return type of function definitions.
+ /// \code
+ /// class A {
+ /// int
+ /// f() {
+ /// return 0;
+ /// };
+ /// };
+ /// int f();
+ /// int
+ /// f() {
+ /// return 1;
+ /// }
+ /// \endcode
RTBS_AllDefinitions,
/// Always break after the return type of top-level definitions.
+ /// \code
+ /// class A {
+ /// int f() { return 0; };
+ /// };
+ /// int f();
+ /// int
+ /// f() {
+ /// return 1;
+ /// }
+ /// \endcode
RTBS_TopLevelDefinitions,
};
/// \brief The function definition return type breaking style to use. This
- /// option is deprecated and is retained for backwards compatibility.
+ /// option is **deprecated** and is retained for backwards compatibility.
DefinitionReturnTypeBreakingStyle AlwaysBreakAfterDefinitionReturnType;
/// \brief The function declaration return type breaking style to use.
@@ -192,27 +334,92 @@ struct FormatStyle {
/// in a file look more consistent. Thus, it will only take effect if wrapping
/// the string at that point leads to it being indented
/// ``ContinuationIndentWidth`` spaces from the start of the line.
+ /// \code
+ /// true: false:
+ /// aaaa = vs. aaaa = "bbbb"
+ /// "bbbb" "cccc";
+ /// "cccc";
+ /// \endcode
bool AlwaysBreakBeforeMultilineStrings;
/// \brief If ``true``, always break after the ``template<...>`` of a template
/// declaration.
+ /// \code
+ /// true: false:
+ /// template <typename T> vs. template <typename T> class C {};
+ /// class C {};
+ /// \endcode
bool AlwaysBreakTemplateDeclarations;
/// \brief If ``false``, a function call's arguments will either be all on the
/// same line or will have one line each.
+ /// \code
+ /// true:
+ /// void f() {
+ /// f(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa,
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
+ /// }
+ ///
+ /// false:
+ /// void f() {
+ /// f(aaaaaaaaaaaaaaaaaaaa,
+ /// aaaaaaaaaaaaaaaaaaaa,
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
+ /// }
+ /// \endcode
bool BinPackArguments;
/// \brief If ``false``, a function declaration's or function definition's
/// parameters will either all be on the same line or will have one line each.
+ /// \code
+ /// true:
+ /// void f(int aaaaaaaaaaaaaaaaaaaa, int aaaaaaaaaaaaaaaaaaaa,
+ /// int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}
+ ///
+ /// false:
+ /// void f(int aaaaaaaaaaaaaaaaaaaa,
+ /// int aaaaaaaaaaaaaaaaaaaa,
+ /// int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}
+ /// \endcode
bool BinPackParameters;
/// \brief The style of breaking before or after binary operators.
enum BinaryOperatorStyle {
/// Break after operators.
+ /// \code
+ /// LooooooooooongType loooooooooooooooooooooongVariable =
+ /// someLooooooooooooooooongFunction();
+ ///
+ /// bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ==
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >
+ /// ccccccccccccccccccccccccccccccccccccccccc;
+ /// \endcode
BOS_None,
/// Break before operators that aren't assignments.
+ /// \code
+ /// LooooooooooongType loooooooooooooooooooooongVariable =
+ /// someLooooooooooooooooongFunction();
+ ///
+ /// bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// > ccccccccccccccccccccccccccccccccccccccccc;
+ /// \endcode
BOS_NonAssignment,
/// Break before operators.
+ /// \code
+ /// LooooooooooongType loooooooooooooooooooooongVariable
+ /// = someLooooooooooooooooongFunction();
+ ///
+ /// bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ /// > ccccccccccccccccccccccccccccccccccccccccc;
+ /// \endcode
BOS_All,
};
@@ -222,23 +429,133 @@ struct FormatStyle {
/// \brief Different ways to attach braces to their surrounding context.
enum BraceBreakingStyle {
/// Always attach braces to surrounding context.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo {};
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_Attach,
/// Like ``Attach``, but break before braces on function, namespace and
/// class definitions.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo
+ /// {
+ /// };
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_Linux,
/// Like ``Attach``, but break before braces on enum, function, and record
/// definitions.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo
+ /// {
+ /// };
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_Mozilla,
/// Like ``Attach``, but break before function definitions, ``catch``, and
/// ``else``.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo
+ /// {
+ /// };
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int
+ /// {
+ /// A,
+ /// B
+ /// };
+ /// \endcode
BS_Stroustrup,
/// Always break before braces.
+ /// \code
+ /// try {
+ /// foo();
+ /// }
+ /// catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo {
+ /// };
+ /// if (foo()) {
+ /// }
+ /// else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_Allman,
/// Always break before braces and add an extra level of indentation to
/// braces of control statements, not to those of class, function
/// or other definitions.
+ /// \code
+ /// try
+ /// {
+ /// foo();
+ /// }
+ /// catch ()
+ /// {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo
+ /// {
+ /// };
+ /// if (foo())
+ /// {
+ /// }
+ /// else
+ /// {
+ /// }
+ /// enum X : int
+ /// {
+ /// A,
+ /// B
+ /// };
+ /// \endcode
BS_GNU,
/// Like ``Attach``, but break before functions.
+ /// \code
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo {
+ /// };
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// enum X : int { A, B };
+ /// \endcode
BS_WebKit,
/// Configure each individual brace in `BraceWrapping`.
BS_Custom
@@ -248,29 +565,181 @@ struct FormatStyle {
BraceBreakingStyle BreakBeforeBraces;
/// \brief Precise control over the wrapping of braces.
+ /// \code
+ /// # Should be declared this way:
+ /// BreakBeforeBraces: Custom
+ /// BraceWrapping:
+ /// AfterClass: true
+ /// \endcode
struct BraceWrappingFlags {
/// \brief Wrap class definitions.
+ /// \code
+ /// true:
+ /// class foo {};
+ ///
+ /// false:
+ /// class foo
+ /// {};
+ /// \endcode
bool AfterClass;
/// \brief Wrap control statements (``if``/``for``/``while``/``switch``/..).
+ /// \code
+ /// true:
+ /// if (foo())
+ /// {
+ /// } else
+ /// {}
+ /// for (int i = 0; i < 10; ++i)
+ /// {}
+ ///
+ /// false:
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// for (int i = 0; i < 10; ++i) {
+ /// }
+ /// \endcode
bool AfterControlStatement;
/// \brief Wrap enum definitions.
+ /// \code
+ /// true:
+ /// enum X : int
+ /// {
+ /// B
+ /// };
+ ///
+ /// false:
+ /// enum X : int { B };
+ /// \endcode
bool AfterEnum;
/// \brief Wrap function definitions.
+ /// \code
+ /// true:
+ /// void foo()
+ /// {
+ /// bar();
+ /// bar2();
+ /// }
+ ///
+ /// false:
+ /// void foo() {
+ /// bar();
+ /// bar2();
+ /// }
+ /// \endcode
bool AfterFunction;
/// \brief Wrap namespace definitions.
+ /// \code
+ /// true:
+ /// namespace
+ /// {
+ /// int foo();
+ /// int bar();
+ /// }
+ ///
+ /// false:
+ /// namespace {
+ /// int foo();
+ /// int bar();
+ /// }
+ /// \endcode
bool AfterNamespace;
/// \brief Wrap ObjC definitions (``@autoreleasepool``, interfaces, ..).
bool AfterObjCDeclaration;
/// \brief Wrap struct definitions.
+ /// \code
+ /// true:
+ /// struct foo
+ /// {
+ /// int x;
+ /// };
+ ///
+ /// false:
+ /// struct foo {
+ /// int x;
+ /// };
+ /// \endcode
bool AfterStruct;
/// \brief Wrap union definitions.
+ /// \code
+ /// true:
+ /// union foo
+ /// {
+ /// int x;
+ /// }
+ ///
+ /// false:
+ /// union foo {
+ /// int x;
+ /// }
+ /// \endcode
bool AfterUnion;
/// \brief Wrap before ``catch``.
+ /// \code
+ /// true:
+ /// try {
+ /// foo();
+ /// }
+ /// catch () {
+ /// }
+ ///
+ /// false:
+ /// try {
+ /// foo();
+ /// } catch () {
+ /// }
+ /// \endcode
bool BeforeCatch;
/// \brief Wrap before ``else``.
+ /// \code
+ /// true:
+ /// if (foo()) {
+ /// }
+ /// else {
+ /// }
+ ///
+ /// false:
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// \endcode
bool BeforeElse;
/// \brief Indent the wrapped braces themselves.
bool IndentBraces;
+ /// \brief If ``false``, empty function body can be put on a single line.
+ /// This option is used only if the opening brace of the function has
+ /// already been wrapped, i.e. the `AfterFunction` brace wrapping mode is
+ /// set, and the function could/should not be put on a single line (as per
+ /// `AllowShortFunctionsOnASingleLine` and constructor formatting options).
+ /// \code
+ /// int f() vs. inf f()
+ /// {} {
+ /// }
+ /// \endcode
+ ///
+ bool SplitEmptyFunction;
+ /// \brief If ``false``, empty record (e.g. class, struct or union) body
+ /// can be put on a single line. This option is used only if the opening
+ /// brace of the record has already been wrapped, i.e. the `AfterClass`
+ /// (for classes) brace wrapping mode is set.
+ /// \code
+ /// class Foo vs. class Foo
+ /// {} {
+ /// }
+ /// \endcode
+ ///
+ bool SplitEmptyRecord;
+ /// \brief If ``false``, empty namespace body can be put on a single line.
+ /// This option is used only if the opening brace of the namespace has
+ /// already been wrapped, i.e. the `AfterNamespace` brace wrapping mode is
+ /// set.
+ /// \code
+ /// namespace Foo vs. namespace Foo
+ /// {} {
+ /// }
+ /// \endcode
+ ///
+ bool SplitEmptyNamespace;
};
/// \brief Control of individual brace wrapping cases.
@@ -280,13 +749,55 @@ struct FormatStyle {
BraceWrappingFlags BraceWrapping;
/// \brief If ``true``, ternary operators will be placed after line breaks.
+ /// \code
+ /// true:
+ /// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription
+ /// ? firstValue
+ /// : SecondValueVeryVeryVeryVeryLong;
+ ///
+ /// false:
+ /// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ?
+ /// firstValue :
+ /// SecondValueVeryVeryVeryVeryLong;
+ /// \endcode
bool BreakBeforeTernaryOperators;
- /// \brief Always break constructor initializers before commas and align
- /// the commas with the colon.
- bool BreakConstructorInitializersBeforeComma;
+ /// \brief Different ways to break initializers.
+ enum BreakConstructorInitializersStyle {
+ /// Break constructor initializers before the colon and after the commas.
+ /// \code
+ /// Constructor()
+ /// : initializer1(),
+ /// initializer2()
+ /// \endcode
+ BCIS_BeforeColon,
+ /// Break constructor initializers before the colon and commas, and align
+ /// the commas with the colon.
+ /// \code
+ /// Constructor()
+ /// : initializer1()
+ /// , initializer2()
+ /// \endcode
+ BCIS_BeforeComma,
+ /// Break constructor initializers after the colon and commas.
+ /// \code
+ /// Constructor() :
+ /// initializer1(),
+ /// initializer2()
+ /// \endcode
+ BCIS_AfterColon
+ };
+
+ /// \brief The constructor initializers style to use.
+ BreakConstructorInitializersStyle BreakConstructorInitializers;
/// \brief Break after each annotation on a field in Java files.
+ /// \code{.java}
+ /// true: false:
+ /// @Partial vs. @Partial @Mock DataLoad loader;
+ /// @Mock
+ /// DataLoad loader;
+ /// \endcode
bool BreakAfterJavaFieldAnnotations;
/// \brief Allow breaking string literals when formatting.
@@ -301,10 +812,63 @@ struct FormatStyle {
/// \brief A regular expression that describes comments with special meaning,
/// which should not be split into lines or otherwise changed.
+ /// \code
+ /// // CommentPragmas: '^ FOOBAR pragma:'
+ /// // Will leave the following line unaffected
+ /// #include <vector> // FOOBAR pragma: keep
+ /// \endcode
std::string CommentPragmas;
+ /// \brief If ``true``, in the class inheritance expression clang-format will
+ /// break before ``:`` and ``,`` if there is multiple inheritance.
+ /// \code
+ /// true: false:
+ /// class MyClass vs. class MyClass : public X, public Y {
+ /// : public X };
+ /// , public Y {
+ /// };
+ /// \endcode
+ bool BreakBeforeInheritanceComma;
+
+ /// \brief If ``true``, consecutive namespace declarations will be on the same
+ /// line. If ``false``, each namespace is declared on a new line.
+ /// \code
+ /// true:
+ /// namespace Foo { namespace Bar {
+ /// }}
+ ///
+ /// false:
+ /// namespace Foo {
+ /// namespace Bar {
+ /// }
+ /// }
+ /// \endcode
+ ///
+ /// If it does not fit on a single line, the overflowing namespaces get
+ /// wrapped:
+ /// \code
+ /// namespace Foo { namespace Bar {
+ /// namespace Extra {
+ /// }}}
+ /// \endcode
+ bool CompactNamespaces;
+
/// \brief If the constructor initializers don't fit on a line, put each
/// initializer on its own line.
+ /// \code
+ /// true:
+ /// SomeClass::Constructor()
+ /// : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) {
+ /// return 0;
+ /// }
+ ///
+ /// false:
+ /// SomeClass::Constructor()
+ /// : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa),
+ /// aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) {
+ /// return 0;
+ /// }
+ /// \endcode
bool ConstructorInitializerAllOnOneLineOrOnePerLine;
/// \brief The number of characters to use for indentation of constructor
@@ -312,6 +876,13 @@ struct FormatStyle {
unsigned ConstructorInitializerIndentWidth;
/// \brief Indent width for line continuations.
+ /// \code
+ /// ContinuationIndentWidth: 2
+ ///
+ /// int i = // VeryVeryVeryVeryVeryLongComment
+ /// longFunction( // Again a long comment
+ /// arg);
+ /// \endcode
unsigned ContinuationIndentWidth;
/// \brief If ``true``, format braced lists as best suited for C++11 braced
@@ -327,11 +898,20 @@ struct FormatStyle {
/// (e.g. a type or variable name), clang-format formats as if the ``{}`` were
/// the parentheses of a function call with that name. If there is no name,
/// a zero-length name is assumed.
+ /// \code
+ /// true: false:
+ /// vector<int> x{1, 2, 3, 4}; vs. vector<int> x{ 1, 2, 3, 4 };
+ /// vector<T> x{{}, {}, {}, {}}; vector<T> x{ {}, {}, {}, {} };
+ /// f(MyMap[{composite, key}]); f(MyMap[{ composite, key }]);
+ /// new int[3]{1, 2, 3}; new int[3]{ 1, 2, 3 };
+ /// \endcode
bool Cpp11BracedListStyle;
/// \brief If ``true``, analyze the formatted file for the most common
- /// alignment of ``&`` and ``*``. ``PointerAlignment`` is then used only as
- /// fallback.
+ /// alignment of ``&`` and ``*``.
+ /// Pointer and reference alignment styles are going to be updated according
+ /// to the preferences found in the file.
+ /// ``PointerAlignment`` is then used only as fallback.
bool DerivePointerAlignment;
/// \brief Disables formatting completely.
@@ -349,6 +929,16 @@ struct FormatStyle {
/// not use this in config files, etc. Use at your own risk.
bool ExperimentalAutoDetectBinPacking;
+ /// \brief If ``true``, clang-format adds missing namespace end comments and
+ /// fixes invalid existing ones.
+ /// \code
+ /// true: false:
+ /// namespace a { vs. namespace a {
+ /// foo(); foo();
+ /// } // namespace a; }
+ /// \endcode
+ bool FixNamespaceComments;
+
/// \brief A vector of macros that should be interpreted as foreach loops
/// instead of as function calls.
///
@@ -398,7 +988,7 @@ struct FormatStyle {
/// IncludeCategories:
/// - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
/// Priority: 2
- /// - Regex: '^(<|"(gtest|isl|json)/)'
+ /// - Regex: '^(<|"(gtest|gmock|isl|json)/)'
/// Priority: 3
/// - Regex: '.*'
/// Priority: 1
@@ -422,23 +1012,64 @@ struct FormatStyle {
///
/// When ``false``, use the same indentation level as for the switch statement.
/// Switch statement body is always indented one level more than case labels.
+ /// \code
+ /// false: true:
+ /// switch (fool) { vs. switch (fool) {
+ /// case 1: case 1:
+ /// bar(); bar();
+ /// break; break;
+ /// default: default:
+ /// plop(); plop();
+ /// } }
+ /// \endcode
bool IndentCaseLabels;
/// \brief The number of columns to use for indentation.
+ /// \code
+ /// IndentWidth: 3
+ ///
+ /// void f() {
+ /// someFunction();
+ /// if (true, false) {
+ /// f();
+ /// }
+ /// }
+ /// \endcode
unsigned IndentWidth;
/// \brief Indent if a function definition or declaration is wrapped after the
/// type.
+ /// \code
+ /// true:
+ /// LoooooooooooooooooooooooooooooooooooooooongReturnType
+ /// LoooooooooooooooooooooooooooooooongFunctionDeclaration();
+ ///
+ /// false:
+ /// LoooooooooooooooooooooooooooooooooooooooongReturnType
+ /// LoooooooooooooooooooooooooooooooongFunctionDeclaration();
+ /// \endcode
bool IndentWrappedFunctionNames;
/// \brief Quotation styles for JavaScript strings. Does not affect template
/// strings.
enum JavaScriptQuoteStyle {
/// Leave string quotes as they are.
+ /// \code{.js}
+ /// string1 = "foo";
+ /// string2 = 'bar';
+ /// \endcode
JSQS_Leave,
/// Always use single quotes.
+ /// \code{.js}
+ /// string1 = 'foo';
+ /// string2 = 'bar';
+ /// \endcode
JSQS_Single,
/// Always use double quotes.
+ /// \code{.js}
+ /// string1 = "foo";
+ /// string2 = "bar";
+ /// \endcode
JSQS_Double
};
@@ -446,9 +1077,27 @@ struct FormatStyle {
JavaScriptQuoteStyle JavaScriptQuotes;
/// \brief Whether to wrap JavaScript import/export statements.
+ /// \code{.js}
+ /// true:
+ /// import {
+ /// VeryLongImportsAreAnnoying,
+ /// VeryLongImportsAreAnnoying,
+ /// VeryLongImportsAreAnnoying,
+ /// } from 'some/module.js'
+ ///
+ /// false:
+ /// import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js"
+ /// \endcode
bool JavaScriptWrapImports;
- /// \brief If true, empty lines at the start of blocks are kept.
+ /// \brief If true, the empty line at the start of blocks is kept.
+ /// \code
+ /// true: false:
+ /// if (foo) { vs. if (foo) {
+ /// bar();
+ /// bar(); }
+ /// }
+ /// \endcode
bool KeepEmptyLinesAtTheStartOfBlocks;
/// \brief Supported languages.
@@ -459,40 +1108,103 @@ struct FormatStyle {
enum LanguageKind {
/// Do not use.
LK_None,
- /// Should be used for C, C++, ObjectiveC, ObjectiveC++.
+ /// Should be used for C, C++.
LK_Cpp,
/// Should be used for Java.
LK_Java,
/// Should be used for JavaScript.
LK_JavaScript,
- /// Should be used for ObjC code.
+ /// Should be used for Objective-C, Objective-C++.
LK_ObjC,
/// Should be used for Protocol Buffers
/// (https://developers.google.com/protocol-buffers/).
LK_Proto,
/// Should be used for TableGen code.
- LK_TableGen
+ LK_TableGen,
+ /// Should be used for Protocol Buffer messages in text format
+ /// (https://developers.google.com/protocol-buffers/).
+ LK_TextProto
};
+ bool isCpp() const { return Language == LK_Cpp || Language == LK_ObjC; }
/// \brief Language, this format style is targeted at.
LanguageKind Language;
/// \brief A regular expression matching macros that start a block.
+ /// \code
+ /// # With:
+ /// MacroBlockBegin: "^NS_MAP_BEGIN|\
+ /// NS_TABLE_HEAD$"
+ /// MacroBlockEnd: "^\
+ /// NS_MAP_END|\
+ /// NS_TABLE_.*_END$"
+ ///
+ /// NS_MAP_BEGIN
+ /// foo();
+ /// NS_MAP_END
+ ///
+ /// NS_TABLE_HEAD
+ /// bar();
+ /// NS_TABLE_FOO_END
+ ///
+ /// # Without:
+ /// NS_MAP_BEGIN
+ /// foo();
+ /// NS_MAP_END
+ ///
+ /// NS_TABLE_HEAD
+ /// bar();
+ /// NS_TABLE_FOO_END
+ /// \endcode
std::string MacroBlockBegin;
/// \brief A regular expression matching macros that end a block.
std::string MacroBlockEnd;
/// \brief The maximum number of consecutive empty lines to keep.
+ /// \code
+ /// MaxEmptyLinesToKeep: 1 vs. MaxEmptyLinesToKeep: 0
+ /// int f() { int f() {
+ /// int = 1; int i = 1;
+ /// i = foo();
+ /// i = foo(); return i;
+ /// }
+ /// return i;
+ /// }
+ /// \endcode
unsigned MaxEmptyLinesToKeep;
/// \brief Different ways to indent namespace contents.
enum NamespaceIndentationKind {
/// Don't indent in namespaces.
+ /// \code
+ /// namespace out {
+ /// int i;
+ /// namespace in {
+ /// int i;
+ /// }
+ /// }
+ /// \endcode
NI_None,
/// Indent only in inner namespaces (nested in other namespaces).
+ /// \code
+ /// namespace out {
+ /// int i;
+ /// namespace in {
+ /// int i;
+ /// }
+ /// }
+ /// \endcode
NI_Inner,
/// Indent in all namespaces.
+ /// \code
+ /// namespace out {
+ /// int i;
+ /// namespace in {
+ /// int i;
+ /// }
+ /// }
+ /// \endcode
NI_All
};
@@ -500,6 +1212,13 @@ struct FormatStyle {
NamespaceIndentationKind NamespaceIndentation;
/// \brief The number of characters to use for indentation of ObjC blocks.
+ /// \code{.objc}
+ /// ObjCBlockIndentWidth: 4
+ ///
+ /// [operation setCompletionBlock:^{
+ /// [self onOperationDone];
+ /// }];
+ /// \endcode
unsigned ObjCBlockIndentWidth;
/// \brief Add a space after ``@property`` in Objective-C, i.e. use
@@ -510,6 +1229,9 @@ struct FormatStyle {
/// ``Foo <Protocol>`` instead of ``Foo<Protocol>``.
bool ObjCSpaceBeforeProtocolList;
+ /// \brief The penalty for breaking around an assignment operator.
+ unsigned PenaltyBreakAssignment;
+
/// \brief The penalty for breaking a function call after ``call(``.
unsigned PenaltyBreakBeforeFirstCallParameter;
@@ -532,10 +1254,19 @@ struct FormatStyle {
/// \brief The ``&`` and ``*`` alignment style.
enum PointerAlignmentStyle {
/// Align pointer to the left.
+ /// \code
+ /// int* a;
+ /// \endcode
PAS_Left,
/// Align pointer to the right.
+ /// \code
+ /// int *a;
+ /// \endcode
PAS_Right,
/// Align pointer in the middle.
+ /// \code
+ /// int * a;
+ /// \endcode
PAS_Middle
};
@@ -543,31 +1274,89 @@ struct FormatStyle {
PointerAlignmentStyle PointerAlignment;
/// \brief If ``true``, clang-format will attempt to re-flow comments.
+ /// \code
+ /// false:
+ /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
+ /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
+ ///
+ /// true:
+ /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
+ /// // information
+ /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
+ /// * information */
+ /// \endcode
bool ReflowComments;
/// \brief If ``true``, clang-format will sort ``#includes``.
+ /// \code
+ /// false: true:
+ /// #include "b.h" vs. #include "a.h"
+ /// #include "a.h" #include "b.h"
+ /// \endcode
bool SortIncludes;
- /// \brief If ``true``, a space may be inserted after C style casts.
+ /// \brief If ``true``, clang-format will sort using declarations.
+ /// \code
+ /// false: true:
+ /// using std::cout; vs. using std::cin;
+ /// using std::cin; using std::cout;
+ /// \endcode
+ bool SortUsingDeclarations;
+
+ /// \brief If ``true``, a space is inserted after C style casts.
+ /// \code
+ /// true: false:
+ /// (int)i; vs. (int) i;
+ /// \endcode
bool SpaceAfterCStyleCast;
/// \brief If \c true, a space will be inserted after the 'template' keyword.
+ /// \code
+ /// true: false:
+ /// template <int> void foo(); vs. template<int> void foo();
+ /// \endcode
bool SpaceAfterTemplateKeyword;
/// \brief If ``false``, spaces will be removed before assignment operators.
+ /// \code
+ /// true: false:
+ /// int a = 5; vs. int a=5;
+ /// a += 42 a+=42;
+ /// \endcode
bool SpaceBeforeAssignmentOperators;
/// \brief Different ways to put a space before opening parentheses.
enum SpaceBeforeParensOptions {
/// Never put a space before opening parentheses.
+ /// \code
+ /// void f() {
+ /// if(true) {
+ /// f();
+ /// }
+ /// }
+ /// \endcode
SBPO_Never,
/// Put a space before opening parentheses only after control statement
/// keywords (``for/if/while...``).
+ /// \code
+ /// void f() {
+ /// if (true) {
+ /// f();
+ /// }
+ /// }
+ /// \endcode
SBPO_ControlStatements,
/// Always put a space before opening parentheses, except when it's
/// prohibited by the syntax rules (in function-like macro definitions) or
/// when determined by other style rules (after unary operators, opening
/// parentheses, etc.)
+ /// \code
+ /// void f () {
+ /// if (true) {
+ /// f ();
+ /// }
+ /// }
+ /// \endcode
SBPO_Always
};
@@ -575,6 +1364,15 @@ struct FormatStyle {
SpaceBeforeParensOptions SpaceBeforeParens;
/// \brief If ``true``, spaces may be inserted into ``()``.
+ /// \code
+ /// true: false:
+ /// void f( ) { vs. void f() {
+ /// int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()};
+ /// if (true) { if (true) {
+ /// f( ); f();
+ /// } }
+ /// } }
+ /// \endcode
bool SpaceInEmptyParentheses;
/// \brief The number of spaces before trailing line comments
@@ -583,30 +1381,63 @@ struct FormatStyle {
/// This does not affect trailing block comments (``/*`` - comments) as
/// those commonly have different usage patterns and a number of special
/// cases.
+ /// \code
+ /// SpacesBeforeTrailingComments: 3
+ /// void f() {
+ /// if (true) { // foo1
+ /// f(); // bar
+ /// } // foo
+ /// }
+ /// \endcode
unsigned SpacesBeforeTrailingComments;
/// \brief If ``true``, spaces will be inserted after ``<`` and before ``>``
/// in template argument lists.
+ /// \code
+ /// true: false:
+ /// static_cast< int >(arg); vs. static_cast<int>(arg);
+ /// std::function< void(int) > fct; std::function<void(int)> fct;
+ /// \endcode
bool SpacesInAngles;
/// \brief If ``true``, spaces are inserted inside container literals (e.g.
/// ObjC and Javascript array and dict literals).
+ /// \code{.js}
+ /// true: false:
+ /// var arr = [ 1, 2, 3 ]; vs. var arr = [1, 2, 3];
+ /// f({a : 1, b : 2, c : 3}); f({a: 1, b: 2, c: 3});
+ /// \endcode
bool SpacesInContainerLiterals;
/// \brief If ``true``, spaces may be inserted into C style casts.
+ /// \code
+ /// true: false:
+ /// x = ( int32 )y vs. x = (int32)y
+ /// \endcode
bool SpacesInCStyleCastParentheses;
/// \brief If ``true``, spaces will be inserted after ``(`` and before ``)``.
+ /// \code
+ /// true: false:
+ /// t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
+ /// \endcode
bool SpacesInParentheses;
/// \brief If ``true``, spaces will be inserted after ``[`` and before ``]``.
+ /// Lambdas or unspecified size array declarations will not be affected.
+ /// \code
+ /// true: false:
+ /// int a[ 5 ]; vs. int a[5];
+ /// std::unique_ptr<int[]> foo() {} // Won't be affected
+ /// \endcode
bool SpacesInSquareBrackets;
/// \brief Supported language standards.
enum LanguageStandard {
/// Use C++03-compatible syntax.
LS_Cpp03,
- /// Use features of C++11 (e.g. ``A<A<int>>`` instead of ``A<A<int> >``).
+ /// Use features of C++11, C++14 and C++1z (e.g. ``A<A<int>>`` instead of
+ /// ``A<A<int> >``).
LS_Cpp11,
/// Automatic detection based on the input.
LS_Auto
@@ -640,7 +1471,7 @@ struct FormatStyle {
AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
AlignConsecutiveAssignments == R.AlignConsecutiveAssignments &&
AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations &&
- AlignEscapedNewlinesLeft == R.AlignEscapedNewlinesLeft &&
+ AlignEscapedNewlines == R.AlignEscapedNewlines &&
AlignOperands == R.AlignOperands &&
AlignTrailingComments == R.AlignTrailingComments &&
AllowAllParametersOfDeclarationOnNextLine ==
@@ -663,11 +1494,12 @@ struct FormatStyle {
BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators &&
BreakBeforeBraces == R.BreakBeforeBraces &&
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
- BreakConstructorInitializersBeforeComma ==
- R.BreakConstructorInitializersBeforeComma &&
+ BreakConstructorInitializers == R.BreakConstructorInitializers &&
+ CompactNamespaces == R.CompactNamespaces &&
BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations &&
BreakStringLiterals == R.BreakStringLiterals &&
ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas &&
+ BreakBeforeInheritanceComma == R.BreakBeforeInheritanceComma &&
ConstructorInitializerAllOnOneLineOrOnePerLine ==
R.ConstructorInitializerAllOnOneLineOrOnePerLine &&
ConstructorInitializerIndentWidth ==
@@ -678,6 +1510,7 @@ struct FormatStyle {
DisableFormat == R.DisableFormat &&
ExperimentalAutoDetectBinPacking ==
R.ExperimentalAutoDetectBinPacking &&
+ FixNamespaceComments == R.FixNamespaceComments &&
ForEachMacros == R.ForEachMacros &&
IncludeCategories == R.IncludeCategories &&
IndentCaseLabels == R.IndentCaseLabels &&
@@ -694,6 +1527,8 @@ struct FormatStyle {
ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty &&
ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
+ PenaltyBreakAssignment ==
+ R.PenaltyBreakAssignment &&
PenaltyBreakBeforeFirstCallParameter ==
R.PenaltyBreakBeforeFirstCallParameter &&
PenaltyBreakComment == R.PenaltyBreakComment &&
@@ -803,6 +1638,18 @@ llvm::Expected<tooling::Replacements>
cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
const FormatStyle &Style);
+/// \brief Represents the status of a formatting attempt.
+struct FormattingAttemptStatus {
+ /// \brief A value of ``false`` means that any of the affected ranges were not
+ /// formatted due to a non-recoverable syntax error.
+ bool FormatComplete = true;
+
+ /// \brief If ``FormatComplete`` is false, ``Line`` records a one-based
+ /// original line number at which a syntax error might have occurred. This is
+ /// based on a best-effort analysis and could be imprecise.
+ unsigned Line = 0;
+};
+
/// \brief Reformats the given \p Ranges in \p Code.
///
/// Each range is extended on either end to its next bigger logic unit, i.e.
@@ -812,13 +1659,20 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
/// Returns the ``Replacements`` necessary to make all \p Ranges comply with
/// \p Style.
///
-/// If ``IncompleteFormat`` is non-null, its value will be set to true if any
-/// of the affected ranges were not formatted due to a non-recoverable syntax
-/// error.
+/// If ``Status`` is non-null, its value will be populated with the status of
+/// this formatting attempt. See \c FormattingAttemptStatus.
tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
StringRef FileName = "<stdin>",
- bool *IncompleteFormat = nullptr);
+ FormattingAttemptStatus *Status = nullptr);
+
+/// \brief Same as above, except if ``IncompleteFormat`` is non-null, its value
+/// will be set to true if any of the affected ranges were not formatted due to
+/// a non-recoverable syntax error.
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName,
+ bool *IncompleteFormat);
/// \brief Clean up any erroneous/redundant code in the given \p Ranges in \p
/// Code.
@@ -828,6 +1682,25 @@ tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
StringRef FileName = "<stdin>");
+/// \brief Fix namespace end comments in the given \p Ranges in \p Code.
+///
+/// Returns the ``Replacements`` that fix the namespace comments in all
+/// \p Ranges in \p Code.
+tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
+ StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName = "<stdin>");
+
+/// \brief Sort consecutive using declarations in the given \p Ranges in
+/// \p Code.
+///
+/// Returns the ``Replacements`` that sort the using declarations in all
+/// \p Ranges in \p Code.
+tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
+ StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName = "<stdin>");
+
/// \brief Returns the ``LangOpts`` that the formatter expects you to set.
///
/// \param Style determines specific settings for lexing mode.
@@ -853,29 +1726,35 @@ extern const char *StyleOptionHelpDescription;
/// \param[in] FileName Path to start search for .clang-format if ``StyleName``
/// == "file".
/// \param[in] FallbackStyle The name of a predefined style used to fallback to
-/// in case the style can't be determined from \p StyleName.
+/// in case \p StyleName is "file" and no file can be found.
/// \param[in] Code The actual code to be formatted. Used to determine the
/// language if the filename isn't sufficient.
/// \param[in] FS The underlying file system, in which the file resides. By
/// default, the file system is the real file system.
///
-/// \returns FormatStyle as specified by ``StyleName``. If no style could be
-/// determined, the default is LLVM Style (see ``getLLVMStyle()``).
-FormatStyle getStyle(StringRef StyleName, StringRef FileName,
- StringRef FallbackStyle, StringRef Code = "",
- vfs::FileSystem *FS = nullptr);
+/// \returns FormatStyle as specified by ``StyleName``. If ``StyleName`` is
+/// "file" and no file is found, returns ``FallbackStyle``. If no style could be
+/// determined, returns an Error.
+llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
+ StringRef FallbackStyle,
+ StringRef Code = "",
+ vfs::FileSystem *FS = nullptr);
// \brief Returns a string representation of ``Language``.
inline StringRef getLanguageName(FormatStyle::LanguageKind Language) {
switch (Language) {
case FormatStyle::LK_Cpp:
return "C++";
+ case FormatStyle::LK_ObjC:
+ return "Objective-C";
case FormatStyle::LK_Java:
return "Java";
case FormatStyle::LK_JavaScript:
return "JavaScript";
case FormatStyle::LK_Proto:
return "Proto";
+ case FormatStyle::LK_TextProto:
+ return "TextProto";
default:
return "Unknown";
}
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/ASTConsumers.h b/contrib/llvm/tools/clang/include/clang/Frontend/ASTConsumers.h
index b76bfcb..53975a0 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/ASTConsumers.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/ASTConsumers.h
@@ -37,7 +37,7 @@ std::unique_ptr<ASTConsumer> CreateASTPrinter(std::unique_ptr<raw_ostream> OS,
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
// intended for debugging.
std::unique_ptr<ASTConsumer> CreateASTDumper(StringRef FilterString,
- bool DumpDecls,
+ bool DumpDecls, bool Deserialize,
bool DumpLookups);
// AST Decl node lister: prints qualified names of all filterable AST Decl
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h b/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h
index b1cdb46..1ac4f07 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h
@@ -25,6 +25,7 @@
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Serialization/ASTBitCodes.h"
+#include "clang/Frontend/PrecompiledPreamble.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
@@ -51,16 +52,23 @@ class DiagnosticsEngine;
class FileEntry;
class FileManager;
class HeaderSearch;
+class InputKind;
+class MemoryBufferCache;
class Preprocessor;
+class PreprocessorOptions;
class PCHContainerOperations;
class PCHContainerReader;
class TargetInfo;
class FrontendAction;
class ASTDeserializationListener;
+namespace vfs {
+class FileSystem;
+}
+
/// \brief Utility class for loading a ASTContext from an AST file.
///
-class ASTUnit : public ModuleLoader {
+class ASTUnit {
public:
struct StandaloneFixIt {
std::pair<unsigned, unsigned> RemoveRange;
@@ -84,12 +92,14 @@ private:
IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
IntrusiveRefCntPtr<FileManager> FileMgr;
IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ IntrusiveRefCntPtr<MemoryBufferCache> PCMCache;
std::unique_ptr<HeaderSearch> HeaderInfo;
IntrusiveRefCntPtr<TargetInfo> Target;
std::shared_ptr<Preprocessor> PP;
IntrusiveRefCntPtr<ASTContext> Ctx;
std::shared_ptr<TargetOptions> TargetOpts;
std::shared_ptr<HeaderSearchOptions> HSOpts;
+ std::shared_ptr<PreprocessorOptions> PPOpts;
IntrusiveRefCntPtr<ASTReader> Reader;
bool HadModuleLoaderFatalFailure;
@@ -110,10 +120,13 @@ private:
/// LoadFromCommandLine available.
std::shared_ptr<CompilerInvocation> Invocation;
+ /// Fake module loader: the AST unit doesn't need to load any modules.
+ TrivialModuleLoader ModuleLoader;
+
// OnlyLocalDecls - when true, walking this AST should only visit declarations
// that come from the AST itself, not from included precompiled headers.
// FIXME: This is temporary; eventually, CIndex will always do this.
- bool OnlyLocalDecls;
+ bool OnlyLocalDecls;
/// \brief Whether to capture any diagnostics produced.
bool CaptureDiagnostics;
@@ -179,103 +192,23 @@ private:
/// some number of calls.
unsigned PreambleRebuildCounter;
-public:
- class PreambleData {
- const FileEntry *File;
- std::vector<char> Buffer;
- mutable unsigned NumLines;
-
- public:
- PreambleData() : File(nullptr), NumLines(0) { }
-
- void assign(const FileEntry *F, const char *begin, const char *end) {
- File = F;
- Buffer.assign(begin, end);
- NumLines = 0;
- }
-
- void clear() { Buffer.clear(); File = nullptr; NumLines = 0; }
-
- size_t size() const { return Buffer.size(); }
- bool empty() const { return Buffer.empty(); }
-
- const char *getBufferStart() const { return &Buffer[0]; }
-
- unsigned getNumLines() const {
- if (NumLines)
- return NumLines;
- countLines();
- return NumLines;
- }
-
- SourceRange getSourceRange(const SourceManager &SM) const {
- SourceLocation FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID());
- return SourceRange(FileLoc, FileLoc.getLocWithOffset(size()-1));
- }
-
- private:
- void countLines() const;
- };
-
- const PreambleData &getPreambleData() const {
- return Preamble;
- }
-
- /// Data used to determine if a file used in the preamble has been changed.
- struct PreambleFileHash {
- /// All files have size set.
- off_t Size;
-
- /// Modification time is set for files that are on disk. For memory
- /// buffers it is zero.
- time_t ModTime;
-
- /// Memory buffers have MD5 instead of modification time. We don't
- /// compute MD5 for on-disk files because we hope that modification time is
- /// enough to tell if the file was changed.
- llvm::MD5::MD5Result MD5;
-
- static PreambleFileHash createForFile(off_t Size, time_t ModTime);
- static PreambleFileHash
- createForMemoryBuffer(const llvm::MemoryBuffer *Buffer);
-
- friend bool operator==(const PreambleFileHash &LHS,
- const PreambleFileHash &RHS);
-
- friend bool operator!=(const PreambleFileHash &LHS,
- const PreambleFileHash &RHS) {
- return !(LHS == RHS);
- }
- };
+ /// \brief Cache pairs "filename - source location"
+ ///
+ /// Cache contains only source locations from preamble so it is
+ /// guaranteed that they stay valid when the SourceManager is recreated.
+ /// This cache is used when loading preambule to increase performance
+ /// of that loading. It must be cleared when preamble is recreated.
+ llvm::StringMap<SourceLocation> PreambleSrcLocCache;
private:
- /// \brief The contents of the preamble that has been precompiled to
- /// \c PreambleFile.
- PreambleData Preamble;
-
- /// \brief Whether the preamble ends at the start of a new line.
- ///
- /// Used to inform the lexer as to whether it's starting at the beginning of
- /// a line after skipping the preamble.
- bool PreambleEndsAtStartOfLine;
-
- /// \brief Keeps track of the files that were used when computing the
- /// preamble, with both their buffer size and their modification time.
- ///
- /// If any of the files have changed from one compile to the next,
- /// the preamble must be thrown away.
- llvm::StringMap<PreambleFileHash> FilesInPreamble;
+ /// The contents of the preamble.
+ llvm::Optional<PrecompiledPreamble> Preamble;
/// \brief When non-NULL, this is the buffer used to store the contents of
/// the main file when it has been padded for use with the precompiled
/// preamble.
std::unique_ptr<llvm::MemoryBuffer> SavedMainFileBuffer;
- /// \brief When non-NULL, this is the buffer used to store the
- /// contents of the preamble when it has been padded to build the
- /// precompiled preamble.
- std::unique_ptr<llvm::MemoryBuffer> PreambleBuffer;
-
/// \brief The number of warnings that occurred while parsing the preamble.
///
/// This value will be used to restore the state of the \c DiagnosticsEngine
@@ -299,9 +232,6 @@ private:
/// (likely to change while trying to use them).
bool UserFilesAreVolatile : 1;
- /// \brief The language options used when we load an AST file.
- LangOptions ASTFileLangOpts;
-
static void ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTUnit &AST, bool CaptureDiagnostics);
@@ -417,27 +347,14 @@ private:
explicit ASTUnit(bool MainFileIsAST);
- void CleanTemporaryFiles();
bool Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer);
-
- struct ComputedPreamble {
- llvm::MemoryBuffer *Buffer;
- std::unique_ptr<llvm::MemoryBuffer> Owner;
- unsigned Size;
- bool PreambleEndsAtStartOfLine;
- ComputedPreamble(llvm::MemoryBuffer *Buffer,
- std::unique_ptr<llvm::MemoryBuffer> Owner, unsigned Size,
- bool PreambleEndsAtStartOfLine)
- : Buffer(Buffer), Owner(std::move(Owner)), Size(Size),
- PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
- };
- ComputedPreamble ComputePreamble(CompilerInvocation &Invocation,
- unsigned MaxLines);
+ std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS);
std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild = true,
+ const CompilerInvocation &PreambleInvocationIn,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild = true,
unsigned MaxLines = 0);
void RealizeTopLevelDeclsFromPreamble();
@@ -480,7 +397,7 @@ public:
};
friend class ConcurrencyCheck;
- ~ASTUnit() override;
+ ~ASTUnit();
bool isMainFileAST() const { return MainFileIsAST; }
@@ -510,15 +427,27 @@ public:
}
const LangOptions &getLangOpts() const {
- assert(LangOpts && " ASTUnit does not have language options");
+ assert(LangOpts && "ASTUnit does not have language options");
return *LangOpts;
}
+
+ const HeaderSearchOptions &getHeaderSearchOpts() const {
+ assert(HSOpts && "ASTUnit does not have header search options");
+ return *HSOpts;
+ }
+
+ const PreprocessorOptions &getPreprocessorOpts() const {
+ assert(PPOpts && "ASTUnit does not have preprocessor options");
+ return *PPOpts;
+ }
const FileManager &getFileManager() const { return *FileMgr; }
FileManager &getFileManager() { return *FileMgr; }
const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
+ IntrusiveRefCntPtr<ASTReader> getASTReader() const;
+
StringRef getOriginalSourceFileName() {
return OriginalSourceFile;
}
@@ -526,11 +455,6 @@ public:
ASTMutationListener *getASTMutationListener();
ASTDeserializationListener *getDeserializationListener();
- /// \brief Add a temporary file that the ASTUnit depends on.
- ///
- /// This file will be erased when the ASTUnit is destroyed.
- void addTemporaryFile(StringRef TempFile);
-
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; }
@@ -581,12 +505,6 @@ public:
void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
SmallVectorImpl<Decl *> &Decls);
- /// \brief Add a new top-level declaration, identified by its ID in
- /// the precompiled preamble.
- void addTopLevelDeclFromPreamble(serialization::DeclID D) {
- TopLevelDeclsInPreamble.push_back(D);
- }
-
/// \brief Retrieve a reference to the current top-level name hash value.
///
/// Note: This is used internally by the top-level tracking action
@@ -697,6 +615,9 @@ public:
/// \brief Determine what kind of translation unit this AST represents.
TranslationUnitKind getTranslationUnitKind() const { return TUKind; }
+ /// \brief Determine the input kind this AST unit represents.
+ InputKind getInputKind() const;
+
/// \brief A mapping from a file name to the memory buffer that stores the
/// remapped contents of that file.
typedef std::pair<std::string, llvm::MemoryBuffer *> RemappedFile;
@@ -707,6 +628,15 @@ public:
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, bool CaptureDiagnostics,
bool UserFilesAreVolatile);
+ enum WhatToLoad {
+ /// Load options and the preprocessor state.
+ LoadPreprocessorOnly,
+ /// Load the AST, but do not restore Sema state.
+ LoadASTOnly,
+ /// Load everything, including Sema.
+ LoadEverything
+ };
+
/// \brief Create a ASTUnit from an AST file.
///
/// \param Filename - The AST file to load.
@@ -719,7 +649,7 @@ public:
/// \returns - The initialized ASTUnit or null if the AST failed to load.
static std::unique_ptr<ASTUnit> LoadFromASTFile(
const std::string &Filename, const PCHContainerReader &PCHContainerRdr,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts, bool UseDebugInfo = false,
bool OnlyLocalDecls = false, ArrayRef<RemappedFile> RemappedFiles = None,
bool CaptureDiagnostics = false, bool AllowPCHWithCompilerErrors = false,
@@ -733,11 +663,17 @@ private:
/// of this translation unit should be precompiled, to improve the performance
/// of reparsing. Set to zero to disable preambles.
///
+ /// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that
+ /// preamble is saved to a temporary directory on a RealFileSystem, so in order
+ /// for it to be loaded correctly, VFS should have access to it(i.e., be an
+ /// overlay over RealFileSystem).
+ ///
/// \returns \c true if a catastrophic failure occurred (which means that the
/// \c ASTUnit itself is invalid), or \c false otherwise.
bool LoadFromCompilerInvocation(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- unsigned PrecompilePreambleAfterNParses);
+ unsigned PrecompilePreambleAfterNParses,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS);
public:
@@ -828,6 +764,11 @@ public:
/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit
/// mainly to allow the caller to see the diagnostics.
///
+ /// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that
+ /// preamble is saved to a temporary directory on a RealFileSystem, so in order
+ /// for it to be loaded correctly, VFS should have access to it(i.e., be an
+ /// overlay over RealFileSystem). RealFileSystem will be used if \p VFS is nullptr.
+ ///
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
// shouldn't need to specify them at construction time.
static ASTUnit *LoadFromCommandLine(
@@ -842,17 +783,31 @@ public:
bool CacheCodeCompletionResults = false,
bool IncludeBriefCommentsInCodeCompletion = false,
bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false,
+ bool SingleFileParse = false,
bool UserFilesAreVolatile = false, bool ForSerialization = false,
llvm::Optional<StringRef> ModuleFormat = llvm::None,
- std::unique_ptr<ASTUnit> *ErrAST = nullptr);
+ std::unique_ptr<ASTUnit> *ErrAST = nullptr,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
/// \brief Reparse the source files using the same command-line options that
/// were originally used to produce this translation unit.
///
+ /// \param VFS - A vfs::FileSystem to be used for all file accesses. Note that
+ /// preamble is saved to a temporary directory on a RealFileSystem, so in order
+ /// for it to be loaded correctly, VFS should give an access to this(i.e. be an
+ /// overlay over RealFileSystem). FileMgr->getVirtualFileSystem() will be used if
+ /// \p VFS is nullptr.
+ ///
/// \returns True if a failure occurred that causes the ASTUnit not to
/// contain any translation-unit information, false otherwise.
bool Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- ArrayRef<RemappedFile> RemappedFiles = None);
+ ArrayRef<RemappedFile> RemappedFiles = None,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
+
+ /// \brief Free data that will be re-generated on the next parse.
+ ///
+ /// Preamble-related data is not affected.
+ void ResetForParse();
/// \brief Perform code completion at the given file, line, and
/// column within this translation unit.
@@ -894,21 +849,6 @@ public:
///
/// \returns True if an error occurred, false otherwise.
bool serialize(raw_ostream &OS);
-
- ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) override {
- // ASTUnit doesn't know how to load modules (not that this matters).
- return ModuleLoadResult();
- }
-
- void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) override {}
-
- GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
- { return nullptr; }
- bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
- { return 0; }
};
} // namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def
index 964a6cc..4002415 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.def
@@ -29,7 +29,8 @@ CODEGENOPT(Name, Bits, Default)
#endif
CODEGENOPT(DisableIntegratedAS, 1, 0) ///< -no-integrated-as
-CODEGENOPT(CompressDebugSections, 1, 0) ///< -Wa,-compress-debug-sections
+ENUM_CODEGENOPT(CompressDebugSections, llvm::DebugCompressionType, 2,
+ llvm::DebugCompressionType::None)
CODEGENOPT(RelaxELFRelocations, 1, 0) ///< -Wa,--mrelax-relocations
CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm.
CODEGENOPT(PreserveAsmComments, 1, 1) ///< -dA, -fno-preserve-as-comments.
@@ -53,8 +54,11 @@ CODEGENOPT(DisableLLVMPasses , 1, 0) ///< Don't run any LLVM IR passes to get
///< the pristine IR generated by the
///< frontend.
CODEGENOPT(DisableLifetimeMarkers, 1, 0) ///< Don't emit any lifetime markers
+CODEGENOPT(DisableO0ImplyOptNone , 1, 0) ///< Don't annonate function with optnone at O0
CODEGENOPT(ExperimentalNewPassManager, 1, 0) ///< Enables the new, experimental
///< pass manager.
+CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new
+ ///< pass manager.
CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled.
CODEGENOPT(DisableTailCalls , 1, 0) ///< Do not emit tail calls.
CODEGENOPT(EmitDeclMetadata , 1, 0) ///< Emit special metadata indicating what
@@ -65,8 +69,6 @@ CODEGENOPT(EmitGcovArcs , 1, 0) ///< Emit coverage data files, aka. GCDA.
CODEGENOPT(EmitGcovNotes , 1, 0) ///< Emit coverage "notes" files, aka GCNO.
CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata.
CODEGENOPT(EmulatedTLS , 1, 0) ///< Set when -femulated-tls is enabled.
-/// \brief FP_CONTRACT mode (on/off/fast).
-ENUM_CODEGENOPT(FPContractMode, FPContractModeKind, 2, FPC_On)
/// \brief Embed Bitcode mode (off/all/bitcode/marker).
ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off)
CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
@@ -83,12 +85,15 @@ CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is
VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200)
CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled.
+CODEGENOPT(CallFEntry , 1, 0) ///< Set when -mfentry is enabled.
CODEGENOPT(LessPreciseFPMAD , 1, 0) ///< Enable less precise MAD instructions to
///< be generated.
CODEGENOPT(PrepareForLTO , 1, 0) ///< Set when -flto is enabled on the
///< compile step.
CODEGENOPT(EmitSummaryIndex, 1, 0) ///< Set when -flto=thin is enabled on the
///< compile step.
+CODEGENOPT(LTOUnit, 1, 0) ///< Emit IR to support LTO unit features (CFI, whole
+ ///< program vtable opt).
CODEGENOPT(IncrementalLinkerCompatible, 1, 0) ///< Emit an object file which can
///< be used with an incremental
///< linker.
@@ -115,6 +120,10 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy)
CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
///< enabled.
+
+/// A version of Clang that we should attempt to be ABI-compatible with.
+ENUM_CODEGENOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest)
+
VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
@@ -136,6 +145,8 @@ CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA
CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels.
CODEGENOPT(SanitizeAddressUseAfterScope , 1, 0) ///< Enable use-after-scope detection
///< in AddressSanitizer
+CODEGENOPT(SanitizeAddressGlobalsDeadStripping, 1, 0) ///< Enable linker dead stripping
+ ///< of globals in AddressSanitizer
CODEGENOPT(SanitizeMemoryTrackOrigins, 2, 0) ///< Enable tracking origins in
///< MemorySanitizer
CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detection
@@ -159,6 +170,8 @@ CODEGENOPT(SanitizeCoverageTracePC, 1, 0) ///< Enable PC tracing
///< in sanitizer coverage.
CODEGENOPT(SanitizeCoverageTracePCGuard, 1, 0) ///< Enable PC tracing with guard
///< in sanitizer coverage.
+CODEGENOPT(SanitizeCoverageInline8bitCounters, 1, 0) ///< Use inline 8bit counters.
+CODEGENOPT(SanitizeCoverageNoPrune, 1, 0) ///< Disable coverage pruning.
CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers.
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
@@ -170,7 +183,6 @@ CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled.
CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled.
CODEGENOPT(UnsafeFPMath , 1, 0) ///< Allow unsafe floating point optzns.
CODEGENOPT(UnwindTables , 1, 0) ///< Emit unwind tables.
-CODEGENOPT(VectorizeBB , 1, 0) ///< Run basic block vectorizer.
CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer.
CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer.
@@ -198,6 +210,7 @@ CODEGENOPT(DebugTypeExtRefs, 1, 0) ///< Whether or not debug info should contain
CODEGENOPT(DebugExplicitImport, 1, 0) ///< Whether or not debug info should
///< contain explicit imports for
///< anonymous namespaces
+CODEGENOPT(EnableSplitDwarf, 1, 0) ///< Whether to enable split DWARF
CODEGENOPT(SplitDwarfInlining, 1, 1) ///< Whether to include inlining info in the
///< skeleton CU to allow for symbolication
///< of inline stack frames without .dwo files.
@@ -221,6 +234,9 @@ VALUE_CODEGENOPT(SSPBufferSize, 32, 0)
/// The kind of generated debug info.
ENUM_CODEGENOPT(DebugInfo, codegenoptions::DebugInfoKind, 3, codegenoptions::NoDebugInfo)
+/// Whether to generate macro debug info.
+CODEGENOPT(MacroDebugInfo, 1, 0)
+
/// Tune the debug info for this debugger.
ENUM_CODEGENOPT(DebuggerTuning, llvm::DebuggerKind, 2,
llvm::DebuggerKind::Default)
@@ -249,6 +265,10 @@ VALUE_CODEGENOPT(EmitCheckPathComponentsToStrip, 32, 0)
/// Whether to report the hotness of the code region for optimization remarks.
CODEGENOPT(DiagnosticsWithHotness, 1, 0)
+/// The minimum hotness value a diagnostic needs in order to be included in
+/// optimization diagnostics.
+VALUE_CODEGENOPT(DiagnosticsHotnessThreshold, 32, 0)
+
/// Whether copy relocations support is available when building as PIE.
CODEGENOPT(PIECopyRelocations, 1, 0)
@@ -256,6 +276,12 @@ CODEGENOPT(PIECopyRelocations, 1, 0)
/// paths that reach the end of a function without executing a required return.
CODEGENOPT(StrictReturn, 1, 1)
+/// Whether emit extra debug info for sample pgo profile collection.
+CODEGENOPT(DebugInfoForProfiling, 1, 0)
+
+/// Whether 3-component vector type is preserved.
+CODEGENOPT(PreserveVec3Type, 1, 0)
+
#undef CODEGENOPT
#undef ENUM_CODEGENOPT
#undef VALUE_CODEGENOPT
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h
index 52bd1c5..71730a2 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h
@@ -69,10 +69,21 @@ public:
LocalExecTLSModel
};
- enum FPContractModeKind {
- FPC_Off, // Form fused FP ops only where result will not be affected.
- FPC_On, // Form fused FP ops according to FP_CONTRACT rules.
- FPC_Fast // Aggressively fuse FP ops (E.g. FMA).
+ /// Clang versions with different platform ABI conformance.
+ enum class ClangABI {
+ /// Attempt to be ABI-compatible with code generated by Clang 3.8.x
+ /// (SVN r257626). This causes <1 x long long> to be passed in an
+ /// integer register instead of an SSE register on x64_64.
+ Ver3_8,
+
+ /// Attempt to be ABI-compatible with code generated by Clang 4.0.x
+ /// (SVN r291814). This causes move operations to be ignored when
+ /// determining whether a class type can be passed or returned directly.
+ Ver4,
+
+ /// Conform to the underlying platform's C and C++ ABIs as closely
+ /// as we can.
+ Latest
};
enum StructReturnConventionKind {
@@ -130,8 +141,21 @@ public:
/// The float precision limit to use, if non-empty.
std::string LimitFloatPrecision;
- /// The name of the bitcode file to link before optzns.
- std::vector<std::pair<unsigned, std::string>> LinkBitcodeFiles;
+ struct BitcodeFileToLink {
+ /// The filename of the bitcode file to link in.
+ std::string Filename;
+ /// If true, we set attributes functions in the bitcode library according to
+ /// our CodeGenOptions, much as we set attrs on functions that we generate
+ /// ourselves.
+ bool PropagateAttrs = false;
+ /// If true, we use LLVM module internalizer.
+ bool Internalize = false;
+ /// Bitwise combination of llvm::Linker::Flags, passed to the LLVM linker.
+ unsigned LinkFlags = 0;
+ };
+
+ /// The files specified here are linked in to the module before optimizations.
+ std::vector<BitcodeFileToLink> LinkBitcodeFiles;
/// The user provided name for the "main file", if non-empty. This is useful
/// in situations where the input file name does not match the original input
@@ -175,6 +199,11 @@ public:
/// importing.
std::string ThinLTOIndexFile;
+ /// Name of a file that can optionally be written with minimized bitcode
+ /// to be used as input for the ThinLTO thin link step, which only needs
+ /// the summary and module symbol table (and not, e.g. any debug metadata).
+ std::string ThinLinkBitcodeFile;
+
/// A list of file names passed with -fcuda-include-gpubinary options to
/// forward to CUDA runtime back-end for incorporating them into host-side
/// object file.
@@ -206,7 +235,7 @@ public:
/// flag.
std::shared_ptr<llvm::Regex> OptimizationRemarkAnalysisPattern;
- /// Set of files definining the rules for the symbol rewriting.
+ /// Set of files defining the rules for the symbol rewriting.
std::vector<std::string> RewriteMapFiles;
/// Set of sanitizer checks that are non-fatal (i.e. execution should be
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h
index 3ebbc61..5b5c752 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h
@@ -44,6 +44,7 @@ class ExternalASTSource;
class FileEntry;
class FileManager;
class FrontendAction;
+class MemoryBufferCache;
class Module;
class Preprocessor;
class Sema;
@@ -90,6 +91,9 @@ class CompilerInstance : public ModuleLoader {
/// The source manager.
IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ /// The cache of PCM files.
+ IntrusiveRefCntPtr<MemoryBufferCache> PCMCache;
+
/// The preprocessor.
std::shared_ptr<Preprocessor> PP;
@@ -132,6 +136,13 @@ class CompilerInstance : public ModuleLoader {
/// along with the module map
llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules;
+ /// \brief The set of top-level modules that has already been built on the
+ /// fly as part of this overall compilation action.
+ std::map<std::string, std::string> BuiltModules;
+
+ /// Should we delete the BuiltModules when we're done?
+ bool DeleteBuiltModules = true;
+
/// \brief The location of the module-import keyword for the last module
/// import.
SourceLocation LastModuleImportLoc;
@@ -142,13 +153,13 @@ class CompilerInstance : public ModuleLoader {
/// \brief Whether we should (re)build the global module index once we
/// have finished with this translation unit.
- bool BuildGlobalModuleIndex;
+ bool BuildGlobalModuleIndex = false;
/// \brief We have a full global module index, with all modules.
- bool HaveFullGlobalModuleIndex;
+ bool HaveFullGlobalModuleIndex = false;
/// \brief One or more modules failed to build.
- bool ModuleBuildFailed;
+ bool ModuleBuildFailed = false;
/// \brief Holds information about the output file.
///
@@ -178,7 +189,7 @@ public:
explicit CompilerInstance(
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
std::make_shared<PCHContainerOperations>(),
- bool BuildingModule = false);
+ MemoryBufferCache *SharedPCMCache = nullptr);
~CompilerInstance() override;
/// @name High-Level Operations
@@ -658,6 +669,8 @@ public:
bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
+ DependencyFileGenerator *DependencyFile,
+ ArrayRef<std::shared_ptr<DependencyCollector>> DependencyCollectors,
void *DeserializationListener, bool OwnDeserializationListener,
bool Preamble, bool UseGlobalModuleIndex);
@@ -767,6 +780,9 @@ public:
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) override;
+ void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName,
+ StringRef Source) override;
+
void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) override;
@@ -783,6 +799,8 @@ public:
}
void setExternalSemaSource(IntrusiveRefCntPtr<ExternalSemaSource> ESS);
+
+ MemoryBufferCache &getPCMCache() const { return *PCMCache; }
};
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h
index cef7f73..8c4c932 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h
@@ -225,6 +225,11 @@ IntrusiveRefCntPtr<vfs::FileSystem>
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
DiagnosticsEngine &Diags);
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+ DiagnosticsEngine &Diags,
+ IntrusiveRefCntPtr<vfs::FileSystem> BaseFS);
+
} // end namespace clang
#endif
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h b/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h
index 2588feb..e453d7d 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h
@@ -70,33 +70,27 @@ protected:
DiagnosticOptions *DiagOpts);
virtual ~DiagnosticRenderer();
-
- virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
+
+ virtual void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
StringRef Message,
ArrayRef<CharSourceRange> Ranges,
- const SourceManager *SM,
DiagOrStoredDiag Info) = 0;
-
- virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+
+ virtual void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) = 0;
+ ArrayRef<CharSourceRange> Ranges) = 0;
- virtual void emitCodeContext(SourceLocation Loc,
+ virtual void emitCodeContext(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) = 0;
-
- virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
- const SourceManager &SM) = 0;
- virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) = 0;
- virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) = 0;
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) = 0;
+
+ virtual void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) = 0;
+ virtual void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) = 0;
+ virtual void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) = 0;
virtual void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) {}
@@ -106,25 +100,21 @@ protected:
private:
void emitBasicNote(StringRef Message);
- void emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc,
- DiagnosticsEngine::Level Level, const SourceManager &SM);
- void emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM);
- void emitImportStack(SourceLocation Loc, const SourceManager &SM);
- void emitImportStackRecursively(SourceLocation Loc, StringRef ModuleName,
- const SourceManager &SM);
+ void emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level);
+ void emitIncludeStackRecursively(FullSourceLoc Loc);
+ void emitImportStack(FullSourceLoc Loc);
+ void emitImportStackRecursively(FullSourceLoc Loc, StringRef ModuleName);
void emitModuleBuildStack(const SourceManager &SM);
- void emitCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints,
- const SourceManager &SM);
- void emitSingleMacroExpansion(SourceLocation Loc,
+ void emitCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints);
+ void emitSingleMacroExpansion(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM);
- void emitMacroExpansions(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges);
+ void emitMacroExpansions(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM);
+ ArrayRef<FixItHint> Hints);
+
public:
/// \brief Emit a diagnostic.
///
@@ -138,12 +128,9 @@ public:
/// \param Message The diagnostic message to emit.
/// \param Ranges The underlined ranges for this code snippet.
/// \param FixItHints The FixIt hints active for this diagnostic.
- /// \param SM The SourceManager; will be null if the diagnostic came from the
- /// frontend, thus \p Loc will be invalid.
- void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level,
+ void emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
StringRef Message, ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> FixItHints,
- const SourceManager *SM,
DiagOrStoredDiag D = (Diagnostic *)nullptr);
void emitStoredDiagnostic(StoredDiagnostic &Diag);
@@ -159,19 +146,15 @@ public:
~DiagnosticNoteRenderer() override;
- void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
- const SourceManager &SM) override;
+ void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override;
- void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) override;
+ void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override;
- void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) override;
+ void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override;
- virtual void emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM) = 0;
+ virtual void emitNote(FullSourceLoc Loc, StringRef Message) = 0;
};
} // end clang namespace
#endif
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h
index 384499a..7ae6173 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h
@@ -76,8 +76,7 @@ protected:
///
/// \return True on success; on failure ExecutionAction() and
/// EndSourceFileAction() will not be called.
- virtual bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+ virtual bool BeginSourceFileAction(CompilerInstance &CI) {
return true;
}
@@ -146,6 +145,8 @@ public:
return *CurrentASTUnit;
}
+ Module *getCurrentModule() const;
+
std::unique_ptr<ASTUnit> takeCurrentASTUnit() {
return std::move(CurrentASTUnit);
}
@@ -174,10 +175,10 @@ public:
virtual TranslationUnitKind getTranslationUnitKind() { return TU_Complete; }
/// \brief Does this action support use with PCH?
- virtual bool hasPCHSupport() const { return !usesPreprocessorOnly(); }
+ virtual bool hasPCHSupport() const { return true; }
/// \brief Does this action support use with AST files?
- virtual bool hasASTFileSupport() const { return !usesPreprocessorOnly(); }
+ virtual bool hasASTFileSupport() const { return true; }
/// \brief Does this action support use with IR files?
virtual bool hasIRSupport() const { return false; }
@@ -289,7 +290,7 @@ protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
bool BeginInvocation(CompilerInstance &CI) override;
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
void ExecuteAction() override;
void EndSourceFileAction() override;
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h
index 20fddc4..c45aeaa 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h
@@ -80,6 +80,8 @@ protected:
bool hasASTFileSupport() const override { return false; }
+ bool shouldEraseOutputFiles() override;
+
public:
/// \brief Compute the AST consumer arguments that will be used to
/// create the PCHGenerator instance returned by CreateASTConsumer.
@@ -89,7 +91,7 @@ public:
ComputeASTConsumerArguments(CompilerInstance &CI, StringRef InFile,
std::string &Sysroot, std::string &OutputFile);
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
};
class GenerateModuleAction : public ASTFrontendAction {
@@ -97,8 +99,6 @@ class GenerateModuleAction : public ASTFrontendAction {
CreateOutputFile(CompilerInstance &CI, StringRef InFile) = 0;
protected:
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
-
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
@@ -110,25 +110,16 @@ protected:
};
class GenerateModuleFromModuleMapAction : public GenerateModuleAction {
- clang::Module *Module = nullptr;
- const FileEntry *ModuleMapForUniquing = nullptr;
- bool IsSystem = false;
-
private:
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
-
-public:
- GenerateModuleFromModuleMapAction() {}
- GenerateModuleFromModuleMapAction(const FileEntry *ModuleMap, bool IsSystem)
- : ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem) {}
};
class GenerateModuleInterfaceAction : public GenerateModuleAction {
private:
- bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
std::unique_ptr<raw_pwrite_stream>
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
@@ -190,8 +181,7 @@ protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
- bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
void ExecuteAction() override;
void EndSourceFileAction() override;
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h
index 9c960bb..e757a7e 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h
@@ -23,6 +23,7 @@ class MemoryBuffer;
}
namespace clang {
+class FileEntry;
namespace frontend {
enum ActionKind {
@@ -62,26 +63,66 @@ namespace frontend {
};
}
-enum InputKind {
- IK_None,
- IK_Asm,
- IK_C,
- IK_CXX,
- IK_ObjC,
- IK_ObjCXX,
- IK_PreprocessedC,
- IK_PreprocessedCXX,
- IK_PreprocessedObjC,
- IK_PreprocessedObjCXX,
- IK_OpenCL,
- IK_CUDA,
- IK_PreprocessedCuda,
- IK_RenderScript,
- IK_AST,
- IK_LLVM_IR
+/// The kind of a file that we've been handed as an input.
+class InputKind {
+private:
+ unsigned Lang : 4;
+ unsigned Fmt : 3;
+ unsigned Preprocessed : 1;
+
+public:
+ /// The language for the input, used to select and validate the language
+ /// standard and possible actions.
+ enum Language {
+ Unknown,
+
+ /// Assembly: we accept this only so that we can preprocess it.
+ Asm,
+
+ /// LLVM IR: we accept this so that we can run the optimizer on it,
+ /// and compile it to assembly or object code.
+ LLVM_IR,
+
+ ///@{ Languages that the frontend can parse and compile.
+ C,
+ CXX,
+ ObjC,
+ ObjCXX,
+ OpenCL,
+ CUDA,
+ RenderScript,
+ ///@}
+ };
+
+ /// The input file format.
+ enum Format {
+ Source,
+ ModuleMap,
+ Precompiled
+ };
+
+ constexpr InputKind(Language L = Unknown, Format F = Source,
+ bool PP = false)
+ : Lang(L), Fmt(F), Preprocessed(PP) {}
+
+ Language getLanguage() const { return static_cast<Language>(Lang); }
+ Format getFormat() const { return static_cast<Format>(Fmt); }
+ bool isPreprocessed() const { return Preprocessed; }
+
+ /// Is the input kind fully-unknown?
+ bool isUnknown() const { return Lang == Unknown && Fmt == Source; }
+
+ /// Is the language of the input some dialect of Objective-C?
+ bool isObjectiveC() const { return Lang == ObjC || Lang == ObjCXX; }
+
+ InputKind getPreprocessed() const {
+ return InputKind(getLanguage(), getFormat(), true);
+ }
+ InputKind withFormat(Format F) const {
+ return InputKind(getLanguage(), F, isPreprocessed());
+ }
};
-
/// \brief An input file for the front end.
class FrontendInputFile {
/// \brief The file name, or "-" to read from standard input.
@@ -96,7 +137,7 @@ class FrontendInputFile {
bool IsSystem;
public:
- FrontendInputFile() : Buffer(nullptr), Kind(IK_None), IsSystem(false) { }
+ FrontendInputFile() : Buffer(nullptr), Kind(), IsSystem(false) { }
FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false)
: File(File.str()), Buffer(nullptr), Kind(Kind), IsSystem(IsSystem) { }
FrontendInputFile(llvm::MemoryBuffer *buffer, InputKind Kind,
@@ -109,6 +150,7 @@ public:
bool isEmpty() const { return File.empty() && Buffer == nullptr; }
bool isFile() const { return !isBuffer(); }
bool isBuffer() const { return Buffer != nullptr; }
+ bool isPreprocessed() const { return Kind.isPreprocessed(); }
StringRef getFile() const {
assert(isFile());
@@ -150,6 +192,8 @@ public:
///< global module index if needed.
unsigned ASTDumpDecls : 1; ///< Whether we include declaration
///< dumps in AST dumps.
+ unsigned ASTDumpAll : 1; ///< Whether we deserialize all decls
+ ///< when forming AST dumps.
unsigned ASTDumpLookups : 1; ///< Whether we include lookup table
///< dumps in AST dumps.
unsigned BuildingImplicitModule : 1; ///< Whether we are performing an
@@ -215,6 +259,10 @@ public:
/// The input files and their types.
std::vector<FrontendInputFile> Inputs;
+ /// When the input is a module map, the original module map file from which
+ /// that map was inferred, if any (for umbrella modules).
+ std::string OriginalModuleMap;
+
/// The output file, if any.
std::string OutputFile;
@@ -269,8 +317,8 @@ public:
/// \brief Auxiliary triple for CUDA compilation.
std::string AuxTriple;
- /// \brief If non-empty, search the pch input file as it was a header
- // included by this file.
+ /// \brief If non-empty, search the pch input file as if it was a header
+ /// included by this file.
std::string FindPchSource;
/// Filename to write statistics to.
@@ -290,10 +338,10 @@ public:
{}
/// getInputKindForExtension - Return the appropriate input kind for a file
- /// extension. For example, "c" would return IK_C.
+ /// extension. For example, "c" would return InputKind::C.
///
- /// \return The input kind for the extension, or IK_None if the extension is
- /// not recognized.
+ /// \return The input kind for the extension, or InputKind::Unknown if the
+ /// extension is not recognized.
static InputKind getInputKindForExtension(StringRef Extension);
};
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h
index 8021d08..6731e08 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_FRONTEND_LANGSTANDARD_H
#include "clang/Basic/LLVM.h"
+#include "clang/Frontend/FrontendOptions.h"
#include "llvm/ADT/StringRef.h"
namespace clang {
@@ -19,17 +20,18 @@ namespace frontend {
enum LangFeatures {
LineComment = (1 << 0),
- C89 = (1 << 1),
- C99 = (1 << 2),
- C11 = (1 << 3),
- CPlusPlus = (1 << 4),
- CPlusPlus11 = (1 << 5),
- CPlusPlus14 = (1 << 6),
- CPlusPlus1z = (1 << 7),
+ C99 = (1 << 1),
+ C11 = (1 << 2),
+ CPlusPlus = (1 << 3),
+ CPlusPlus11 = (1 << 4),
+ CPlusPlus14 = (1 << 5),
+ CPlusPlus1z = (1 << 6),
+ CPlusPlus2a = (1 << 7),
Digraphs = (1 << 8),
GNUMode = (1 << 9),
HexFloat = (1 << 10),
- ImplicitInt = (1 << 11)
+ ImplicitInt = (1 << 11),
+ OpenCL = (1 << 12)
};
}
@@ -38,7 +40,7 @@ enum LangFeatures {
/// standard.
struct LangStandard {
enum Kind {
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
lang_##id,
#include "clang/Frontend/LangStandards.def"
lang_unspecified
@@ -47,6 +49,7 @@ struct LangStandard {
const char *ShortName;
const char *Description;
unsigned Flags;
+ InputKind::Language Language;
public:
/// getName - Get the name of this standard.
@@ -55,12 +58,12 @@ public:
/// getDescription - Get the description of this standard.
const char *getDescription() const { return Description; }
+ /// Get the language that this standard describes.
+ InputKind::Language getLanguage() const { return Language; }
+
/// Language supports '//' comments.
bool hasLineComments() const { return Flags & frontend::LineComment; }
- /// isC89 - Language is a superset of C89.
- bool isC89() const { return Flags & frontend::C89; }
-
/// isC99 - Language is a superset of C99.
bool isC99() const { return Flags & frontend::C99; }
@@ -79,6 +82,10 @@ public:
/// isCPlusPlus1z - Language is a C++17 variant (or later).
bool isCPlusPlus1z() const { return Flags & frontend::CPlusPlus1z; }
+ /// isCPlusPlus2a - Language is a post-C++17 variant (or later).
+ bool isCPlusPlus2a() const { return Flags & frontend::CPlusPlus2a; }
+
+
/// hasDigraphs - Language supports digraphs.
bool hasDigraphs() const { return Flags & frontend::Digraphs; }
@@ -91,6 +98,9 @@ public:
/// hasImplicitInt - Language allows variables to be typed as int implicitly.
bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; }
+ /// isOpenCL - Language is a OpenCL variant.
+ bool isOpenCL() const { return Flags & frontend::OpenCL; }
+
static const LangStandard &getLangStandardForKind(Kind K);
static const LangStandard *getLangStandardForName(StringRef Name);
};
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def
index 06fe1a3..a019d63 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def
@@ -11,10 +11,11 @@
#error "LANGSTANDARD must be defined before including this file"
#endif
-/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES)
+/// LANGSTANDARD(IDENT, NAME, LANG, DESC, FEATURES)
///
/// \param IDENT - The name of the standard as a C++ identifier.
/// \param NAME - The name of the standard.
+/// \param LANG - The InputKind::Language for which this is a standard.
/// \param DESC - A short description of the standard.
/// \param FEATURES - The standard features as flags, these are enums from the
/// clang::frontend namespace, which is assumed to be be available.
@@ -23,146 +24,138 @@
/// \param IDENT - The name of the standard as a C++ identifier.
/// \param ALIAS - The alias of the standard.
+/// LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS)
+/// Same as LANGSTANDARD_ALIAS, but for a deprecated alias.
+
#ifndef LANGSTANDARD_ALIAS
#define LANGSTANDARD_ALIAS(IDENT, ALIAS)
#endif
+#ifndef LANGSTANDARD_ALIAS_DEPR
+#define LANGSTANDARD_ALIAS_DEPR(IDENT, ALIAS) LANGSTANDARD_ALIAS(IDENT, ALIAS)
+#endif
+
// C89-ish modes.
LANGSTANDARD(c89, "c89",
- "ISO C 1990",
- C89 | ImplicitInt)
-LANGSTANDARD(c90, "c90",
- "ISO C 1990",
- C89 | ImplicitInt)
-LANGSTANDARD(iso9899_1990, "iso9899:1990",
- "ISO C 1990",
- C89 | ImplicitInt)
+ C, "ISO C 1990",
+ ImplicitInt)
+LANGSTANDARD_ALIAS(c89, "c90")
+LANGSTANDARD_ALIAS(c89, "iso9899:1990")
LANGSTANDARD(c94, "iso9899:199409",
- "ISO C 1990 with amendment 1",
- C89 | Digraphs | ImplicitInt)
+ C, "ISO C 1990 with amendment 1",
+ Digraphs | ImplicitInt)
LANGSTANDARD(gnu89, "gnu89",
- "ISO C 1990 with GNU extensions",
- LineComment | C89 | Digraphs | GNUMode | ImplicitInt)
-LANGSTANDARD(gnu90, "gnu90",
- "ISO C 1990 with GNU extensions",
- LineComment | C89 | Digraphs | GNUMode | ImplicitInt)
+ C, "ISO C 1990 with GNU extensions",
+ LineComment | Digraphs | GNUMode | ImplicitInt)
+LANGSTANDARD_ALIAS(gnu89, "gnu90")
// C99-ish modes
LANGSTANDARD(c99, "c99",
- "ISO C 1999",
- LineComment | C99 | Digraphs | HexFloat)
-LANGSTANDARD(c9x, "c9x",
- "ISO C 1999",
- LineComment | C99 | Digraphs | HexFloat)
-LANGSTANDARD(iso9899_1999,
- "iso9899:1999", "ISO C 1999",
- LineComment | C99 | Digraphs | HexFloat)
-LANGSTANDARD(iso9899_199x,
- "iso9899:199x", "ISO C 1999",
+ C, "ISO C 1999",
LineComment | C99 | Digraphs | HexFloat)
+LANGSTANDARD_ALIAS(c99, "iso9899:1999")
+LANGSTANDARD_ALIAS_DEPR(c99, "c9x")
+LANGSTANDARD_ALIAS_DEPR(c99, "iso9899:199x")
LANGSTANDARD(gnu99, "gnu99",
- "ISO C 1999 with GNU extensions",
- LineComment | C99 | Digraphs | GNUMode | HexFloat)
-LANGSTANDARD(gnu9x, "gnu9x",
- "ISO C 1999 with GNU extensions",
+ C, "ISO C 1999 with GNU extensions",
LineComment | C99 | Digraphs | GNUMode | HexFloat)
+LANGSTANDARD_ALIAS_DEPR(gnu99, "gnu9x")
// C11 modes
LANGSTANDARD(c11, "c11",
- "ISO C 2011",
- LineComment | C99 | C11 | Digraphs | HexFloat)
-LANGSTANDARD(c1x, "c1x",
- "ISO C 2011",
- LineComment | C99 | C11 | Digraphs | HexFloat)
-LANGSTANDARD(iso9899_2011,
- "iso9899:2011", "ISO C 2011",
- LineComment | C99 | C11 | Digraphs | HexFloat)
-LANGSTANDARD(iso9899_201x,
- "iso9899:201x", "ISO C 2011",
+ C, "ISO C 2011",
LineComment | C99 | C11 | Digraphs | HexFloat)
+LANGSTANDARD_ALIAS(c11, "iso9899:2011")
+LANGSTANDARD_ALIAS_DEPR(c11, "c1x")
+LANGSTANDARD_ALIAS_DEPR(c11, "iso9899:201x")
LANGSTANDARD(gnu11, "gnu11",
- "ISO C 2011 with GNU extensions",
- LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
-LANGSTANDARD(gnu1x, "gnu1x",
- "ISO C 2011 with GNU extensions",
+ C, "ISO C 2011 with GNU extensions",
LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat)
+LANGSTANDARD_ALIAS_DEPR(gnu11, "gnu1x")
// C++ modes
LANGSTANDARD(cxx98, "c++98",
- "ISO C++ 1998 with amendments",
- LineComment | CPlusPlus | Digraphs)
-LANGSTANDARD(cxx03, "c++03",
- "ISO C++ 1998 with amendments",
+ CXX, "ISO C++ 1998 with amendments",
LineComment | CPlusPlus | Digraphs)
+LANGSTANDARD_ALIAS(cxx98, "c++03")
+
LANGSTANDARD(gnucxx98, "gnu++98",
- "ISO C++ 1998 with amendments and GNU extensions",
+ CXX, "ISO C++ 1998 with amendments and GNU extensions",
LineComment | CPlusPlus | Digraphs | GNUMode)
+LANGSTANDARD_ALIAS(gnucxx98, "gnu++03")
-LANGSTANDARD(cxx0x, "c++0x",
- "ISO C++ 2011 with amendments",
- LineComment | CPlusPlus | CPlusPlus11 | Digraphs)
LANGSTANDARD(cxx11, "c++11",
- "ISO C++ 2011 with amendments",
+ CXX, "ISO C++ 2011 with amendments",
LineComment | CPlusPlus | CPlusPlus11 | Digraphs)
-LANGSTANDARD(gnucxx0x, "gnu++0x",
- "ISO C++ 2011 with amendments and GNU extensions",
- LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode)
-LANGSTANDARD(gnucxx11, "gnu++11",
+LANGSTANDARD_ALIAS_DEPR(cxx11, "c++0x")
+
+LANGSTANDARD(gnucxx11, "gnu++11", CXX,
"ISO C++ 2011 with amendments and GNU extensions",
LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode)
+LANGSTANDARD_ALIAS_DEPR(gnucxx11, "gnu++0x")
-LANGSTANDARD(cxx1y, "c++1y",
- "ISO C++ 2014 with amendments",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs)
LANGSTANDARD(cxx14, "c++14",
- "ISO C++ 2014 with amendments",
+ CXX, "ISO C++ 2014 with amendments",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs)
-LANGSTANDARD(gnucxx1y, "gnu++1y",
- "ISO C++ 2014 with amendments and GNU extensions",
- LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs |
- GNUMode)
+LANGSTANDARD_ALIAS_DEPR(cxx14, "c++1y")
+
LANGSTANDARD(gnucxx14, "gnu++14",
- "ISO C++ 2014 with amendments and GNU extensions",
+ CXX, "ISO C++ 2014 with amendments and GNU extensions",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs |
GNUMode)
+LANGSTANDARD_ALIAS_DEPR(gnucxx14, "gnu++1y")
-LANGSTANDARD(cxx1z, "c++1z",
- "Working draft for ISO C++ 2017",
+LANGSTANDARD(cxx17, "c++17",
+ CXX, "ISO C++ 2017 with amendments",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
Digraphs | HexFloat)
-LANGSTANDARD(gnucxx1z, "gnu++1z",
- "Working draft for ISO C++ 2017 with GNU extensions",
+LANGSTANDARD_ALIAS_DEPR(cxx17, "c++1z")
+
+LANGSTANDARD(gnucxx17, "gnu++17",
+ CXX, "ISO C++ 2017 with amendments and GNU extensions",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
Digraphs | HexFloat | GNUMode)
+LANGSTANDARD_ALIAS_DEPR(gnucxx17, "gnu++1z")
+
+LANGSTANDARD(cxx2a, "c++2a",
+ CXX, "Working draft for ISO C++ 2020",
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
+ CPlusPlus2a | Digraphs | HexFloat)
+
+LANGSTANDARD(gnucxx2a, "gnu++2a",
+ CXX, "Working draft for ISO C++ 2020 with GNU extensions",
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z |
+ CPlusPlus2a | Digraphs | HexFloat | GNUMode)
// OpenCL
-LANGSTANDARD(opencl, "cl",
- "OpenCL 1.0",
- LineComment | C99 | Digraphs | HexFloat)
+LANGSTANDARD(opencl10, "cl1.0",
+ OpenCL, "OpenCL 1.0",
+ LineComment | C99 | Digraphs | HexFloat | OpenCL)
+LANGSTANDARD_ALIAS_DEPR(opencl10, "cl")
+
LANGSTANDARD(opencl11, "cl1.1",
- "OpenCL 1.1",
- LineComment | C99 | Digraphs | HexFloat)
+ OpenCL, "OpenCL 1.1",
+ LineComment | C99 | Digraphs | HexFloat | OpenCL)
LANGSTANDARD(opencl12, "cl1.2",
- "OpenCL 1.2",
- LineComment | C99 | Digraphs | HexFloat)
+ OpenCL, "OpenCL 1.2",
+ LineComment | C99 | Digraphs | HexFloat | OpenCL)
LANGSTANDARD(opencl20, "cl2.0",
- "OpenCL 2.0",
- LineComment | C99 | Digraphs | HexFloat)
+ OpenCL, "OpenCL 2.0",
+ LineComment | C99 | Digraphs | HexFloat | OpenCL)
-LANGSTANDARD_ALIAS(opencl, "CL")
-LANGSTANDARD_ALIAS(opencl11, "CL1.1")
-LANGSTANDARD_ALIAS(opencl12, "CL1.2")
-LANGSTANDARD_ALIAS(opencl20, "CL2.0")
+LANGSTANDARD_ALIAS_DEPR(opencl10, "CL")
+LANGSTANDARD_ALIAS_DEPR(opencl11, "CL1.1")
+LANGSTANDARD_ALIAS_DEPR(opencl12, "CL1.2")
+LANGSTANDARD_ALIAS_DEPR(opencl20, "CL2.0")
// CUDA
-LANGSTANDARD(cuda, "cuda",
- "NVIDIA CUDA(tm)",
+LANGSTANDARD(cuda, "cuda", CUDA, "NVIDIA CUDA(tm)",
LineComment | CPlusPlus | Digraphs)
#undef LANGSTANDARD
#undef LANGSTANDARD_ALIAS
-
+#undef LANGSTANDARD_ALIAS_DEPR
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/PCHContainerOperations.h b/contrib/llvm/tools/clang/include/clang/Frontend/PCHContainerOperations.h
index d323fb3..f9a7350 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/PCHContainerOperations.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/PCHContainerOperations.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_PCH_CONTAINER_OPERATIONS_H
#define LLVM_CLANG_PCH_CONTAINER_OPERATIONS_H
+#include "clang/Basic/Module.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -29,7 +30,7 @@ class DiagnosticsEngine;
class CompilerInstance;
struct PCHBuffer {
- uint64_t Signature;
+ ASTFileSignature Signature;
llvm::SmallVector<char, 0> Data;
bool IsComplete;
};
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h b/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h
new file mode 100644
index 0000000..8307392
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h
@@ -0,0 +1,248 @@
+//===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper class to build precompiled preamble.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
+#define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
+
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/MD5.h"
+#include <memory>
+#include <system_error>
+#include <type_traits>
+
+namespace llvm {
+class MemoryBuffer;
+}
+
+namespace clang {
+namespace vfs {
+class FileSystem;
+}
+
+class CompilerInstance;
+class CompilerInvocation;
+class DeclGroupRef;
+class PCHContainerOperations;
+
+/// A size of the preamble and a flag required by
+/// PreprocessorOptions::PrecompiledPreambleBytes.
+struct PreambleBounds {
+ PreambleBounds(unsigned Size, bool PreambleEndsAtStartOfLine)
+ : Size(Size), PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
+
+ /// \brief Size of the preamble in bytes.
+ unsigned Size;
+ /// \brief Whether the preamble ends at the start of a new line.
+ ///
+ /// Used to inform the lexer as to whether it's starting at the beginning of
+ /// a line after skipping the preamble.
+ bool PreambleEndsAtStartOfLine;
+};
+
+/// \brief Runs lexer to compute suggested preamble bounds.
+PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
+ llvm::MemoryBuffer *Buffer,
+ unsigned MaxLines);
+
+class PreambleCallbacks;
+
+/// A class holding a PCH and all information to check whether it is valid to
+/// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
+/// CanReusePreamble + AddImplicitPreamble to make use of it.
+class PrecompiledPreamble {
+ class TempPCHFile;
+ struct PreambleFileHash;
+
+public:
+ /// \brief Try to build PrecompiledPreamble for \p Invocation. See
+ /// BuildPreambleError for possible error codes.
+ ///
+ /// \param Invocation Original CompilerInvocation with options to compile the
+ /// file.
+ ///
+ /// \param MainFileBuffer Buffer with the contents of the main file.
+ ///
+ /// \param Bounds Bounds of the preamble, result of calling
+ /// ComputePreambleBounds.
+ ///
+ /// \param Diagnostics Diagnostics engine to be used while building the
+ /// preamble.
+ ///
+ /// \param VFS An instance of vfs::FileSystem to be used for file
+ /// accesses.
+ ///
+ /// \param PCHContainerOps An instance of PCHContainerOperations.
+ ///
+ /// \param Callbacks A set of callbacks to be executed when building
+ /// the preamble.
+ static llvm::ErrorOr<PrecompiledPreamble>
+ Build(const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
+ DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ PreambleCallbacks &Callbacks);
+
+ PrecompiledPreamble(PrecompiledPreamble &&) = default;
+ PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default;
+
+ /// PreambleBounds used to build the preamble
+ PreambleBounds getBounds() const;
+
+ /// Check whether PrecompiledPreamble can be reused for the new contents(\p
+ /// MainFileBuffer) of the main file.
+ bool CanReuse(const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
+ vfs::FileSystem *VFS) const;
+
+ /// Changes options inside \p CI to use PCH from this preamble. Also remaps
+ /// main file to \p MainFileBuffer.
+ void AddImplicitPreamble(CompilerInvocation &CI,
+ llvm::MemoryBuffer *MainFileBuffer) const;
+
+private:
+ PrecompiledPreamble(TempPCHFile PCHFile, std::vector<char> PreambleBytes,
+ bool PreambleEndsAtStartOfLine,
+ llvm::StringMap<PreambleFileHash> FilesInPreamble);
+
+ /// A temp file that would be deleted on destructor call. If destructor is not
+ /// called for any reason, the file will be deleted at static objects'
+ /// destruction.
+ /// An assertion will fire if two TempPCHFiles are created with the same name,
+ /// so it's not intended to be used outside preamble-handling.
+ class TempPCHFile {
+ public:
+ // A main method used to construct TempPCHFile.
+ static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile();
+
+ /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file.
+ static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix,
+ StringRef Suffix);
+ /// Create a new instance of TemporaryFile for file at \p Path. Use with
+ /// extreme caution, there's an assertion checking that there's only a
+ /// single instance of TempPCHFile alive for each path.
+ static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path);
+
+ private:
+ TempPCHFile(std::string FilePath);
+
+ public:
+ TempPCHFile(TempPCHFile &&Other);
+ TempPCHFile &operator=(TempPCHFile &&Other);
+
+ TempPCHFile(const TempPCHFile &) = delete;
+ ~TempPCHFile();
+
+ /// A path where temporary file is stored.
+ llvm::StringRef getFilePath() const;
+
+ private:
+ void RemoveFileIfPresent();
+
+ private:
+ llvm::Optional<std::string> FilePath;
+ };
+
+ /// Data used to determine if a file used in the preamble has been changed.
+ struct PreambleFileHash {
+ /// All files have size set.
+ off_t Size = 0;
+
+ /// Modification time is set for files that are on disk. For memory
+ /// buffers it is zero.
+ time_t ModTime = 0;
+
+ /// Memory buffers have MD5 instead of modification time. We don't
+ /// compute MD5 for on-disk files because we hope that modification time is
+ /// enough to tell if the file was changed.
+ llvm::MD5::MD5Result MD5 = {};
+
+ static PreambleFileHash createForFile(off_t Size, time_t ModTime);
+ static PreambleFileHash
+ createForMemoryBuffer(const llvm::MemoryBuffer *Buffer);
+
+ friend bool operator==(const PreambleFileHash &LHS,
+ const PreambleFileHash &RHS) {
+ return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
+ LHS.MD5 == RHS.MD5;
+ }
+ friend bool operator!=(const PreambleFileHash &LHS,
+ const PreambleFileHash &RHS) {
+ return !(LHS == RHS);
+ }
+ };
+
+ /// Manages the lifetime of temporary file that stores a PCH.
+ TempPCHFile PCHFile;
+ /// Keeps track of the files that were used when computing the
+ /// preamble, with both their buffer size and their modification time.
+ ///
+ /// If any of the files have changed from one compile to the next,
+ /// the preamble must be thrown away.
+ llvm::StringMap<PreambleFileHash> FilesInPreamble;
+ /// The contents of the file that was used to precompile the preamble. Only
+ /// contains first PreambleBounds::Size bytes. Used to compare if the relevant
+ /// part of the file has not changed, so that preamble can be reused.
+ std::vector<char> PreambleBytes;
+ /// See PreambleBounds::PreambleEndsAtStartOfLine
+ bool PreambleEndsAtStartOfLine;
+};
+
+/// A set of callbacks to gather useful information while building a preamble.
+class PreambleCallbacks {
+public:
+ virtual ~PreambleCallbacks() = default;
+
+ /// Called after FrontendAction::Execute(), but before
+ /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
+ /// various CompilerInstance fields before they are destroyed.
+ virtual void AfterExecute(CompilerInstance &CI);
+ /// Called after PCH has been emitted. \p Writer may be used to retrieve
+ /// information about AST, serialized in PCH.
+ virtual void AfterPCHEmitted(ASTWriter &Writer);
+ /// Called for each TopLevelDecl.
+ /// NOTE: To allow more flexibility a custom ASTConsumer could probably be
+ /// used instead, but having only this method allows a simpler API.
+ virtual void HandleTopLevelDecl(DeclGroupRef DG);
+ /// Called for each macro defined in the Preamble.
+ /// NOTE: To allow more flexibility a custom PPCallbacks could probably be
+ /// used instead, but having only this method allows a simpler API.
+ virtual void HandleMacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD);
+};
+
+enum class BuildPreambleError {
+ PreambleIsEmpty = 1,
+ CouldntCreateTempFile,
+ CouldntCreateTargetInfo,
+ CouldntCreateVFSOverlay,
+ BeginSourceFileFailed,
+ CouldntEmitPCH
+};
+
+class BuildPreambleErrorCategory final : public std::error_category {
+public:
+ const char *name() const noexcept override;
+ std::string message(int condition) const override;
+};
+
+std::error_code make_error_code(BuildPreambleError Error);
+} // namespace clang
+
+namespace std {
+template <>
+struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
+} // namespace std
+
+#endif
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h
index 3261b66..94afcd0 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOutputOptions.h
@@ -24,6 +24,7 @@ public:
unsigned ShowMacros : 1; ///< Print macro definitions.
unsigned ShowIncludeDirectives : 1; ///< Print includes, imports etc. within preprocessed output.
unsigned RewriteIncludes : 1; ///< Preprocess include directives only.
+ unsigned RewriteImports : 1; ///< Include contents of transitively-imported modules.
public:
PreprocessorOutputOptions() {
@@ -35,6 +36,7 @@ public:
ShowMacros = 0;
ShowIncludeDirectives = 0;
RewriteIncludes = 0;
+ RewriteImports = 0;
}
};
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h
index 9b108c2..1bbfe9f 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h
@@ -75,44 +75,35 @@ public:
unsigned Columns, bool ShowColors);
protected:
- void emitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
+ void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
ArrayRef<CharSourceRange> Ranges,
- const SourceManager *SM,
DiagOrStoredDiag D) override;
- void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) override;
-
- void emitCodeContext(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) override {
- emitSnippetAndCaret(Loc, Level, Ranges, Hints, SM);
+ ArrayRef<CharSourceRange> Ranges) override;
+
+ void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) override {
+ emitSnippetAndCaret(Loc, Level, Ranges, Hints);
}
- void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
- const SourceManager &SM) override;
+ void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override;
- void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) override;
+ void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override;
- void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) override;
+ void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override;
private:
void emitFilename(StringRef Filename, const SourceManager &SM);
- void emitSnippetAndCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM);
+ void emitSnippetAndCaret(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints);
void emitSnippet(StringRef SourceLine);
diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h b/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h
index 0ee4684..8ccc319 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h
+++ b/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h
@@ -184,10 +184,11 @@ createChainedIncludesSource(CompilerInstance &CI,
///
/// \return A CompilerInvocation, or 0 if none was built for the given
/// argument vector.
-std::unique_ptr<CompilerInvocation>
-createInvocationFromCommandLine(ArrayRef<const char *> Args,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
- IntrusiveRefCntPtr<DiagnosticsEngine>());
+std::unique_ptr<CompilerInvocation> createInvocationFromCommandLine(
+ ArrayRef<const char *> Args,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ IntrusiveRefCntPtr<DiagnosticsEngine>(),
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = nullptr);
/// Return the value of the last argument as an integer, or a default. If Diags
/// is non-null, emits an error if the argument is given, but non-integral.
diff --git a/contrib/llvm/tools/clang/include/clang/Index/IndexSymbol.h b/contrib/llvm/tools/clang/include/clang/Index/IndexSymbol.h
index d19e5eb..abb132f 100644
--- a/contrib/llvm/tools/clang/include/clang/Index/IndexSymbol.h
+++ b/contrib/llvm/tools/clang/include/clang/Index/IndexSymbol.h
@@ -51,12 +51,15 @@ enum class SymbolKind : uint8_t {
Constructor,
Destructor,
ConversionFunction,
+
+ Parameter,
};
enum class SymbolLanguage {
C,
ObjC,
CXX,
+ Swift,
};
/// Language specific sub-kinds.
@@ -77,8 +80,9 @@ enum class SymbolProperty : uint8_t {
IBAnnotated = 1 << 4,
IBOutletCollection = 1 << 5,
GKInspectable = 1 << 6,
+ Local = 1 << 7,
};
-static const unsigned SymbolPropertyBitNum = 7;
+static const unsigned SymbolPropertyBitNum = 8;
typedef unsigned SymbolPropertySet;
/// Set of roles that are attributed to symbol occurrences.
@@ -103,8 +107,9 @@ enum class SymbolRole : uint32_t {
RelationAccessorOf = 1 << 15,
RelationContainedBy = 1 << 16,
RelationIBTypeOf = 1 << 17,
+ RelationSpecializationOf = 1 << 18,
};
-static const unsigned SymbolRoleBitNum = 18;
+static const unsigned SymbolRoleBitNum = 19;
typedef unsigned SymbolRoleSet;
/// Represents a relation to another symbol for a symbol occurrence.
@@ -125,8 +130,12 @@ struct SymbolInfo {
SymbolInfo getSymbolInfo(const Decl *D);
+bool isFunctionLocalSymbol(const Decl *D);
+
void applyForEachSymbolRole(SymbolRoleSet Roles,
llvm::function_ref<void(SymbolRole)> Fn);
+bool applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles,
+ llvm::function_ref<bool(SymbolRole)> Fn);
void printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS);
/// \returns true if no name was printed, false otherwise.
diff --git a/contrib/llvm/tools/clang/include/clang/Index/IndexingAction.h b/contrib/llvm/tools/clang/include/clang/Index/IndexingAction.h
index e2e63dc..fb703be 100644
--- a/contrib/llvm/tools/clang/include/clang/Index/IndexingAction.h
+++ b/contrib/llvm/tools/clang/include/clang/Index/IndexingAction.h
@@ -11,12 +11,20 @@
#define LLVM_CLANG_INDEX_INDEXINGACTION_H
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
#include <memory>
namespace clang {
+ class ASTContext;
+ class ASTReader;
class ASTUnit;
+ class Decl;
class FrontendAction;
+namespace serialization {
+ class ModuleFile;
+}
+
namespace index {
class IndexDataConsumer;
@@ -42,6 +50,14 @@ void indexASTUnit(ASTUnit &Unit,
std::shared_ptr<IndexDataConsumer> DataConsumer,
IndexingOptions Opts);
+void indexTopLevelDecls(ASTContext &Ctx, ArrayRef<const Decl *> Decls,
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ IndexingOptions Opts);
+
+void indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader,
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ IndexingOptions Opts);
+
} // namespace index
} // namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/Index/USRGeneration.h b/contrib/llvm/tools/clang/include/clang/Index/USRGeneration.h
index be89068..8c661bd 100644
--- a/contrib/llvm/tools/clang/include/clang/Index/USRGeneration.h
+++ b/contrib/llvm/tools/clang/include/clang/Index/USRGeneration.h
@@ -16,6 +16,7 @@
namespace clang {
class Decl;
class MacroDefinitionRecord;
+class SourceLocation;
class SourceManager;
namespace index {
@@ -29,10 +30,14 @@ static inline StringRef getUSRSpacePrefix() {
bool generateUSRForDecl(const Decl *D, SmallVectorImpl<char> &Buf);
/// \brief Generate a USR fragment for an Objective-C class.
-void generateUSRForObjCClass(StringRef Cls, raw_ostream &OS);
+void generateUSRForObjCClass(StringRef Cls, raw_ostream &OS,
+ StringRef ExtSymbolDefinedIn = "",
+ StringRef CategoryContextExtSymbolDefinedIn = "");
/// \brief Generate a USR fragment for an Objective-C class category.
-void generateUSRForObjCCategory(StringRef Cls, StringRef Cat, raw_ostream &OS);
+void generateUSRForObjCCategory(StringRef Cls, StringRef Cat, raw_ostream &OS,
+ StringRef ClsExtSymbolDefinedIn = "",
+ StringRef CatExtSymbolDefinedIn = "");
/// \brief Generate a USR fragment for an Objective-C instance variable. The
/// complete USR can be created by concatenating the USR for the
@@ -47,13 +52,23 @@ void generateUSRForObjCMethod(StringRef Sel, bool IsInstanceMethod,
void generateUSRForObjCProperty(StringRef Prop, bool isClassProp, raw_ostream &OS);
/// \brief Generate a USR fragment for an Objective-C protocol.
-void generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS);
+void generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS,
+ StringRef ExtSymbolDefinedIn = "");
+
+/// Generate USR fragment for a global (non-nested) enum.
+void generateUSRForGlobalEnum(StringRef EnumName, raw_ostream &OS,
+ StringRef ExtSymbolDefinedIn = "");
+
+/// Generate a USR fragment for an enum constant.
+void generateUSRForEnumConstant(StringRef EnumConstantName, raw_ostream &OS);
/// \brief Generate a USR for a macro, including the USR prefix.
///
/// \returns true on error, false on success.
bool generateUSRForMacro(const MacroDefinitionRecord *MD,
const SourceManager &SM, SmallVectorImpl<char> &Buf);
+bool generateUSRForMacro(StringRef MacroName, SourceLocation Loc,
+ const SourceManager &SM, SmallVectorImpl<char> &Buf);
} // namespace index
} // namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h
index 51983b9..1b7f80c 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h
@@ -47,7 +47,7 @@ struct HeaderFileInfo {
/// whether it is C++ clean or not. This can be set by the include paths or
/// by \#pragma gcc system_header. This is an instance of
/// SrcMgr::CharacteristicKind.
- unsigned DirInfo : 2;
+ unsigned DirInfo : 3;
/// \brief Whether this header file info was supplied by an external source,
/// and has not changed since.
@@ -375,13 +375,16 @@ public:
/// \param SuggestedModule If non-null, and the file found is semantically
/// part of a known module, this will be set to the module that should
/// be imported instead of preprocessing/parsing the file found.
+ ///
+ /// \param IsMapped If non-null, and the search involved header maps, set to
+ /// true.
const FileEntry *LookupFile(
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache = false, bool BuildSystemModule = false);
+ bool *IsMapped, bool SkipCache = false, bool BuildSystemModule = false);
/// \brief Look up a subframework for the specified \#include file.
///
@@ -535,9 +538,18 @@ public:
///
/// \param File The module map file.
/// \param IsSystem Whether this file is in a system header directory.
- ///
+ /// \param ID If the module map file is already mapped (perhaps as part of
+ /// processing a preprocessed module), the ID of the file.
+ /// \param Offset [inout] An offset within ID to start parsing. On exit,
+ /// filled by the end of the parsed contents (either EOF or the
+ /// location of an end-of-module-map pragma).
+ /// \param OriginalModuleMapFile The original path to the module map file,
+ /// used to resolve paths within the module (this is required when
+ /// building the module from preprocessed source).
/// \returns true if an error occurred, false otherwise.
- bool loadModuleMapFile(const FileEntry *File, bool IsSystem);
+ bool loadModuleMapFile(const FileEntry *File, bool IsSystem,
+ FileID ID = FileID(), unsigned *Offset = nullptr,
+ StringRef OriginalModuleMapFile = StringRef());
/// \brief Collect the set of all known, top-level modules.
///
@@ -683,7 +695,9 @@ private:
LoadModuleMapResult loadModuleMapFileImpl(const FileEntry *File,
bool IsSystem,
- const DirectoryEntry *Dir);
+ const DirectoryEntry *Dir,
+ FileID ID = FileID(),
+ unsigned *Offset = nullptr);
/// \brief Try to load the module map file in the given directory.
///
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h
index e999805..ca3a84e 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearchOptions.h
@@ -178,6 +178,8 @@ public:
unsigned ModulesValidateDiagnosticOptions : 1;
+ unsigned ModulesHashContent : 1;
+
HeaderSearchOptions(StringRef _Sysroot = "/")
: Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(0),
ImplicitModuleMaps(0), ModuleMapFileHomeIsCwd(0),
@@ -186,8 +188,8 @@ public:
UseBuiltinIncludes(true), UseStandardSystemIncludes(true),
UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false),
ModulesValidateOncePerBuildSession(false),
- ModulesValidateSystemHeaders(false),
- UseDebugInfo(false), ModulesValidateDiagnosticOptions(true) {}
+ ModulesValidateSystemHeaders(false), UseDebugInfo(false),
+ ModulesValidateDiagnosticOptions(true), ModulesHashContent(false) {}
/// AddPath - Add the \p Path path to the specified \p Group list.
void AddPath(StringRef Path, frontend::IncludeDirGroup Group,
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h b/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h
index 830c25a..3be7331 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h
@@ -478,6 +478,11 @@ public:
return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
}
+ /// Returns the leading whitespace for line that corresponds to the given
+ /// location \p Loc.
+ static StringRef getIndentationForLine(SourceLocation Loc,
+ const SourceManager &SM);
+
//===--------------------------------------------------------------------===//
// Internal implementation interfaces.
private:
@@ -638,6 +643,8 @@ private:
bool IsStartOfConflictMarker(const char *CurPtr);
bool HandleEndOfConflictMarker(const char *CurPtr);
+ bool lexEditorPlaceholder(Token &Result, const char *CurPtr);
+
bool isCodeCompletionPoint(const char *CurPtr) const;
void cutOffLexing() { BufferPtr = BufferEnd; }
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h b/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h
index 7b2a485..cfe46ce 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/MacroArgs.h
@@ -53,9 +53,12 @@ class MacroArgs {
/// Preprocessor owns which we use to avoid thrashing malloc/free.
MacroArgs *ArgCache;
- MacroArgs(unsigned NumToks, bool varargsElided)
- : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided),
- ArgCache(nullptr) {}
+ /// MacroArgs - The number of arguments the invoked macro expects.
+ unsigned NumMacroArgs;
+
+ MacroArgs(unsigned NumToks, bool varargsElided, unsigned MacroArgs)
+ : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided),
+ ArgCache(nullptr), NumMacroArgs(MacroArgs) {}
~MacroArgs() = default;
public:
@@ -94,10 +97,9 @@ public:
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd);
- /// getNumArguments - Return the number of arguments passed into this macro
- /// invocation.
- unsigned getNumArguments() const { return NumUnexpArgTokens; }
-
+ /// getNumMacroArguments - Return the number of arguments the invoked macro
+ /// expects.
+ unsigned getNumMacroArguments() const { return NumMacroArgs; }
/// isVarargsElidedUse - Return true if this is a C99 style varargs macro
/// invocation and there was no argument specified for the "..." argument. If
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h b/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h
index 6cc3b0b..d25431b 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h
@@ -42,14 +42,14 @@ class MacroInfo {
/// \brief The list of arguments for a function-like macro.
///
- /// ArgumentList points to the first of NumArguments pointers.
+ /// ParameterList points to the first of NumParameters pointers.
///
/// This can be empty, for, e.g. "#define X()". In a C99-style variadic
/// macro, this includes the \c __VA_ARGS__ identifier on the list.
- IdentifierInfo **ArgumentList;
+ IdentifierInfo **ParameterList;
- /// \see ArgumentList
- unsigned NumArguments;
+ /// \see ParameterList
+ unsigned NumParameters;
/// \brief This is the list of tokens that the macro is defined to.
SmallVector<Token, 8> ReplacementTokens;
@@ -105,9 +105,6 @@ class MacroInfo {
/// \brief Must warn if the macro is unused at the end of translation unit.
bool IsWarnIfUnused : 1;
- /// \brief Whether this macro info was loaded from an AST file.
- bool FromASTFile : 1;
-
/// \brief Whether this macro was used as header guard.
bool UsedForHeaderGuard : 1;
@@ -126,7 +123,7 @@ public:
SourceLocation getDefinitionEndLoc() const { return EndLocation; }
/// \brief Get length in characters of the macro definition.
- unsigned getDefinitionLength(SourceManager &SM) const {
+ unsigned getDefinitionLength(const SourceManager &SM) const {
if (IsDefinitionLengthCached)
return DefinitionLength;
return getDefinitionLengthSlow(SM);
@@ -156,37 +153,37 @@ public:
/// \brief Set the value of the IsWarnIfUnused flag.
void setIsWarnIfUnused(bool val) { IsWarnIfUnused = val; }
- /// \brief Set the specified list of identifiers as the argument list for
+ /// \brief Set the specified list of identifiers as the parameter list for
/// this macro.
- void setArgumentList(ArrayRef<IdentifierInfo *> List,
+ void setParameterList(ArrayRef<IdentifierInfo *> List,
llvm::BumpPtrAllocator &PPAllocator) {
- assert(ArgumentList == nullptr && NumArguments == 0 &&
- "Argument list already set!");
+ assert(ParameterList == nullptr && NumParameters == 0 &&
+ "Parameter list already set!");
if (List.empty())
return;
- NumArguments = List.size();
- ArgumentList = PPAllocator.Allocate<IdentifierInfo *>(List.size());
- std::copy(List.begin(), List.end(), ArgumentList);
+ NumParameters = List.size();
+ ParameterList = PPAllocator.Allocate<IdentifierInfo *>(List.size());
+ std::copy(List.begin(), List.end(), ParameterList);
}
- /// Arguments - The list of arguments for a function-like macro. This can be
- /// empty, for, e.g. "#define X()".
- typedef IdentifierInfo *const *arg_iterator;
- bool arg_empty() const { return NumArguments == 0; }
- arg_iterator arg_begin() const { return ArgumentList; }
- arg_iterator arg_end() const { return ArgumentList + NumArguments; }
- unsigned getNumArgs() const { return NumArguments; }
- ArrayRef<const IdentifierInfo *> args() const {
- return ArrayRef<const IdentifierInfo *>(ArgumentList, NumArguments);
+ /// Parameters - The list of parameters for a function-like macro. This can
+ /// be empty, for, e.g. "#define X()".
+ typedef IdentifierInfo *const *param_iterator;
+ bool param_empty() const { return NumParameters == 0; }
+ param_iterator param_begin() const { return ParameterList; }
+ param_iterator param_end() const { return ParameterList + NumParameters; }
+ unsigned getNumParams() const { return NumParameters; }
+ ArrayRef<const IdentifierInfo *> params() const {
+ return ArrayRef<const IdentifierInfo *>(ParameterList, NumParameters);
}
- /// \brief Return the argument number of the specified identifier,
- /// or -1 if the identifier is not a formal argument identifier.
- int getArgumentNum(const IdentifierInfo *Arg) const {
- for (arg_iterator I = arg_begin(), E = arg_end(); I != E; ++I)
+ /// \brief Return the parameter number of the specified identifier,
+ /// or -1 if the identifier is not a formal parameter identifier.
+ int getParameterNum(const IdentifierInfo *Arg) const {
+ for (param_iterator I = param_begin(), E = param_end(); I != E; ++I)
if (*I == Arg)
- return I - arg_begin();
+ return I - param_begin();
return -1;
}
@@ -264,33 +261,15 @@ public:
IsDisabled = true;
}
- /// \brief Determine whether this macro info came from an AST file (such as
- /// a precompiled header or module) rather than having been parsed.
- bool isFromASTFile() const { return FromASTFile; }
-
/// \brief Determine whether this macro was used for a header guard.
bool isUsedForHeaderGuard() const { return UsedForHeaderGuard; }
void setUsedForHeaderGuard(bool Val) { UsedForHeaderGuard = Val; }
- /// \brief Retrieve the global ID of the module that owns this particular
- /// macro info.
- unsigned getOwningModuleID() const {
- if (isFromASTFile())
- return *(const unsigned *)(this + 1);
-
- return 0;
- }
-
void dump() const;
private:
- unsigned getDefinitionLengthSlow(SourceManager &SM) const;
-
- void setOwningModuleID(unsigned ID) {
- assert(isFromASTFile());
- *(unsigned *)(this + 1) = ID;
- }
+ unsigned getDefinitionLengthSlow(const SourceManager &SM) const;
friend class Preprocessor;
};
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h b/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h
index 70770d1..ee0638b 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h
@@ -109,6 +109,16 @@ public:
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) = 0;
+ /// Attempt to load the given module from the specified source buffer. Does
+ /// not make any submodule visible; for that, use loadModule or
+ /// makeModuleVisible.
+ ///
+ /// \param Loc The location at which the module was loaded.
+ /// \param ModuleName The name of the module to build.
+ /// \param Source The source of the module: a (preprocessed) module map.
+ virtual void loadModuleFromSource(SourceLocation Loc, StringRef ModuleName,
+ StringRef Source) = 0;
+
/// \brief Make the given module visible.
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
@@ -136,6 +146,30 @@ public:
bool HadFatalFailure;
};
+
+/// A module loader that doesn't know how to load modules.
+class TrivialModuleLoader : public ModuleLoader {
+public:
+ ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) override {
+ return ModuleLoadResult();
+ }
+
+ void loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName,
+ StringRef Source) override {}
+
+ void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc) override {}
+
+ GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override {
+ return nullptr;
+ }
+ bool lookupMissingImports(StringRef Name,
+ SourceLocation TriggerLoc) override {
+ return 0;
+ }
+};
}
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h b/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h
index 4613672..1150693 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h
@@ -26,6 +26,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/Twine.h"
#include <algorithm>
#include <memory>
@@ -116,6 +117,11 @@ public:
// Adjust ModuleMap::addHeader.
};
+ /// Convert a header kind to a role. Requires Kind to not be HK_Excluded.
+ static ModuleHeaderRole headerKindToRole(Module::HeaderKind Kind);
+ /// Convert a header role to a kind.
+ static Module::HeaderKind headerRoleToKind(ModuleHeaderRole Role);
+
/// \brief A header that is known to reside within a given module,
/// whether it was included or excluded.
class KnownHeader {
@@ -165,7 +171,13 @@ private:
/// \brief Mapping from each header to the module that owns the contents of
/// that header.
HeadersMap Headers;
-
+
+ /// Map from file sizes to modules with lazy header directives of that size.
+ mutable llvm::DenseMap<off_t, llvm::TinyPtrVector<Module*>> LazyHeadersBySize;
+ /// Map from mtimes to modules with lazy header directives with those mtimes.
+ mutable llvm::DenseMap<time_t, llvm::TinyPtrVector<Module*>>
+ LazyHeadersByModTime;
+
/// \brief Mapping from directories with umbrella headers to the module
/// that is generated from the umbrella header.
///
@@ -257,6 +269,31 @@ private:
/// resolved.
Module *resolveModuleId(const ModuleId &Id, Module *Mod, bool Complain) const;
+ /// Add an unresolved header to a module.
+ void addUnresolvedHeader(Module *Mod,
+ Module::UnresolvedHeaderDirective Header);
+
+ /// Look up the given header directive to find an actual header file.
+ ///
+ /// \param M The module in which we're resolving the header directive.
+ /// \param Header The header directive to resolve.
+ /// \param RelativePathName Filled in with the relative path name from the
+ /// module to the resolved header.
+ /// \return The resolved file, if any.
+ const FileEntry *findHeader(Module *M,
+ const Module::UnresolvedHeaderDirective &Header,
+ SmallVectorImpl<char> &RelativePathName);
+
+ /// Resolve the given header directive.
+ void resolveHeader(Module *M,
+ const Module::UnresolvedHeaderDirective &Header);
+
+ /// Attempt to resolve the specified header directive as naming a builtin
+ /// header.
+ /// \return \c true if a corresponding builtin header was found.
+ bool resolveAsBuiltinHeader(Module *M,
+ const Module::UnresolvedHeaderDirective &Header);
+
/// \brief Looks up the modules that \p File corresponds to.
///
/// If \p File represents a builtin header within Clang's builtin include
@@ -351,6 +388,15 @@ public:
/// the preferred module for the header.
ArrayRef<KnownHeader> findAllModulesForHeader(const FileEntry *File) const;
+ /// Resolve all lazy header directives for the specified file.
+ ///
+ /// This ensures that the HeaderFileInfo on HeaderSearch is up to date. This
+ /// is effectively internal, but is exposed so HeaderSearch can call it.
+ void resolveHeaderDirectives(const FileEntry *File) const;
+
+ /// Resolve all lazy header directives for the specified module.
+ void resolveHeaderDirectives(Module *Mod) const;
+
/// \brief Reports errors if a module must not include a specific file.
///
/// \param RequestingModule The module including a file.
@@ -507,16 +553,6 @@ public:
/// false otherwise.
bool resolveConflicts(Module *Mod, bool Complain);
- /// \brief Infers the (sub)module based on the given source location and
- /// source manager.
- ///
- /// \param Loc The location within the source that we are querying, along
- /// with its source manager.
- ///
- /// \returns The module that owns this source location, or null if no
- /// module owns this source location.
- Module *inferModuleFromLocation(FullSourceLoc Loc);
-
/// \brief Sets the umbrella header of the given module to the given
/// header.
void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader,
@@ -546,14 +582,20 @@ public:
/// \param HomeDir The directory in which relative paths within this module
/// map file will be resolved.
///
+ /// \param ID The FileID of the file to process, if we've already entered it.
+ ///
+ /// \param Offset [inout] On input the offset at which to start parsing. On
+ /// output, the offset at which the module map terminated.
+ ///
/// \param ExternModuleLoc The location of the "extern module" declaration
/// that caused us to load this module map file, if any.
///
/// \returns true if an error occurred, false otherwise.
bool parseModuleMapFile(const FileEntry *File, bool IsSystem,
- const DirectoryEntry *HomeDir,
+ const DirectoryEntry *HomeDir, FileID ID = FileID(),
+ unsigned *Offset = nullptr,
SourceLocation ExternModuleLoc = SourceLocation());
-
+
/// \brief Dump the contents of the module map, for debugging purposes.
void dump();
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h b/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h
index 2d027f3..81c3bd7 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h
@@ -247,10 +247,14 @@ public:
}
/// \brief Hook called whenever a macro \#undef is seen.
+ /// \param MacroNameTok The active Token
+ /// \param MD A MacroDefinition for the named macro.
+ /// \param Undef New MacroDirective if the macro was defined, null otherwise.
///
/// MD is released immediately following this callback.
virtual void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) {
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) {
}
/// \brief Hook called whenever the 'defined' operator is seen.
@@ -439,15 +443,17 @@ public:
Second->MacroExpands(MacroNameTok, MD, Range, Args);
}
- void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override {
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
First->MacroDefined(MacroNameTok, MD);
Second->MacroDefined(MacroNameTok, MD);
}
void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) override {
- First->MacroUndefined(MacroNameTok, MD);
- Second->MacroUndefined(MacroNameTok, MD);
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) override {
+ First->MacroUndefined(MacroNameTok, MD, Undef);
+ Second->MacroUndefined(MacroNameTok, MD, Undef);
}
void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h b/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h
index 904be79..f96af66 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/PTHLexer.h
@@ -36,7 +36,7 @@ class PTHLexer : public PreprocessorLexer {
const unsigned char* LastHashTokPtr;
/// PPCond - Pointer to a side table in the PTH file that provides a
- /// a consise summary of the preproccessor conditional block structure.
+ /// a concise summary of the preprocessor conditional block structure.
/// This is used to perform quick skipping of conditional blocks.
const unsigned char* PPCond;
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h
index 826ba33..fc2c507 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h
@@ -488,7 +488,8 @@ namespace clang {
void MacroExpands(const Token &Id, const MacroDefinition &MD,
SourceRange Range, const MacroArgs *Args) override;
void MacroDefined(const Token &Id, const MacroDirective *MD) override;
- void MacroUndefined(const Token &Id, const MacroDefinition &MD) override;
+ void MacroUndefined(const Token &Id, const MacroDefinition &MD,
+ const MacroDirective *Undef) override;
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h
index 7ce1aad..dba4b80 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h
@@ -47,6 +47,7 @@ class ExternalPreprocessorSource;
class FileManager;
class FileEntry;
class HeaderSearch;
+class MemoryBufferCache;
class PragmaNamespace;
class PragmaHandler;
class CommentHandler;
@@ -102,6 +103,7 @@ class Preprocessor {
const TargetInfo *AuxTarget;
FileManager &FileMgr;
SourceManager &SourceMgr;
+ MemoryBufferCache &PCMCache;
std::unique_ptr<ScratchBuffer> ScratchBuf;
HeaderSearch &HeaderInfo;
ModuleLoader &TheModuleLoader;
@@ -281,6 +283,44 @@ class Preprocessor {
/// This is used when loading a precompiled preamble.
std::pair<int, bool> SkipMainFilePreamble;
+ class PreambleConditionalStackStore {
+ enum State {
+ Off = 0,
+ Recording = 1,
+ Replaying = 2,
+ };
+
+ public:
+ PreambleConditionalStackStore() : ConditionalStackState(Off) {}
+
+ void startRecording() { ConditionalStackState = Recording; }
+ void startReplaying() { ConditionalStackState = Replaying; }
+ bool isRecording() const { return ConditionalStackState == Recording; }
+ bool isReplaying() const { return ConditionalStackState == Replaying; }
+
+ ArrayRef<PPConditionalInfo> getStack() const {
+ return ConditionalStack;
+ }
+
+ void doneReplaying() {
+ ConditionalStack.clear();
+ ConditionalStackState = Off;
+ }
+
+ void setStack(ArrayRef<PPConditionalInfo> s) {
+ if (!isRecording() && !isReplaying())
+ return;
+ ConditionalStack.clear();
+ ConditionalStack.append(s.begin(), s.end());
+ }
+
+ bool hasRecordedPreamble() const { return !ConditionalStack.empty(); }
+
+ private:
+ SmallVector<PPConditionalInfo, 4> ConditionalStack;
+ State ConditionalStackState;
+ } PreambleConditionalStack;
+
/// \brief The current top of the stack that we're lexing from if
/// not expanding a macro and we are lexing directly from source code.
///
@@ -322,7 +362,7 @@ class Preprocessor {
/// \brief If the current lexer is for a submodule that is being built, this
/// is that submodule.
- Module *CurSubmodule;
+ Module *CurLexerSubmodule;
/// \brief Keeps track of the stack of files currently
/// \#included, and macros currently being expanded from, not counting
@@ -505,16 +545,19 @@ class Preprocessor {
/// \brief Information about a submodule that we're currently building.
struct BuildingSubmoduleInfo {
- BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc,
+ BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, bool IsPragma,
SubmoduleState *OuterSubmoduleState,
unsigned OuterPendingModuleMacroNames)
- : M(M), ImportLoc(ImportLoc), OuterSubmoduleState(OuterSubmoduleState),
+ : M(M), ImportLoc(ImportLoc), IsPragma(IsPragma),
+ OuterSubmoduleState(OuterSubmoduleState),
OuterPendingModuleMacroNames(OuterPendingModuleMacroNames) {}
/// The module that we are building.
Module *M;
/// The location at which the module was included.
SourceLocation ImportLoc;
+ /// Whether we entered this submodule via a pragma.
+ bool IsPragma;
/// The previous SubmoduleState.
SubmoduleState *OuterSubmoduleState;
/// The number of pending module macro names when we started building this.
@@ -639,19 +682,12 @@ class Preprocessor {
/// of that list.
MacroInfoChain *MIChainHead;
- struct DeserializedMacroInfoChain {
- MacroInfo MI;
- unsigned OwningModuleID; // MUST be immediately after the MacroInfo object
- // so it can be accessed by MacroInfo::getOwningModuleID().
- DeserializedMacroInfoChain *Next;
- };
- DeserializedMacroInfoChain *DeserialMIChainHead;
-
void updateOutOfDateIdentifier(IdentifierInfo &II) const;
public:
Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts, SourceManager &SM,
+ MemoryBufferCache &PCMCache,
HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup = nullptr,
bool OwnsHeaderSearch = false,
@@ -691,6 +727,7 @@ public:
const TargetInfo *getAuxTargetInfo() const { return AuxTarget; }
FileManager &getFileManager() const { return FileMgr; }
SourceManager &getSourceManager() const { return SourceMgr; }
+ MemoryBufferCache &getPCMCache() const { return PCMCache; }
HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; }
IdentifierTable &getIdentifierTable() { return Identifiers; }
@@ -769,8 +806,9 @@ public:
/// expansions going on at the time.
PreprocessorLexer *getCurrentFileLexer() const;
- /// \brief Return the submodule owning the file being lexed.
- Module *getCurrentSubmodule() const { return CurSubmodule; }
+ /// \brief Return the submodule owning the file being lexed. This may not be
+ /// the current module if we have changed modules since entering the file.
+ Module *getCurrentLexerSubmodule() const { return CurLexerSubmodule; }
/// \brief Returns the FileID for the preprocessor predefines.
FileID getPredefinesFileID() const { return PredefinesFileID; }
@@ -1077,6 +1115,24 @@ public:
/// \brief Disable the last EnableBacktrackAtThisPos call.
void CommitBacktrackedTokens();
+ struct CachedTokensRange {
+ CachedTokensTy::size_type Begin, End;
+ };
+
+private:
+ /// \brief A range of cached tokens that should be erased after lexing
+ /// when backtracking requires the erasure of such cached tokens.
+ Optional<CachedTokensRange> CachedTokenRangeToErase;
+
+public:
+ /// \brief Returns the range of cached tokens that were lexed since
+ /// EnableBacktrackAtThisPos() was previously called.
+ CachedTokensRange LastCachedTokenRange();
+
+ /// \brief Erase the range of cached tokens that were lexed since
+ /// EnableBacktrackAtThisPos() was previously called.
+ void EraseCachedTokens(CachedTokensRange TokenRange);
+
/// \brief Make Preprocessor re-lex the tokens that were lexed since
/// EnableBacktrackAtThisPos() was previously called.
void Backtrack();
@@ -1241,6 +1297,10 @@ public:
CachedTokens[CachedLexPos-1] = Tok;
}
+ /// Enter an annotation token into the token stream.
+ void EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind,
+ void *AnnotationVal);
+
/// Update the current token to represent the provided
/// identifier, in order to cache an action performed by typo correction.
void TypoCorrectToken(const Token &Tok) {
@@ -1580,6 +1640,7 @@ private:
*Ident_AbnormalTermination;
const char *getCurLexerEndPos();
+ void diagnoseMissingHeaderInUmbrellaDir(const Module &Mod);
public:
void PoisonSEHIdentifiers(bool Poison = true); // Borland
@@ -1638,10 +1699,6 @@ public:
/// \brief Allocate a new MacroInfo object with the provided SourceLocation.
MacroInfo *AllocateMacroInfo(SourceLocation L);
- /// \brief Allocate a new MacroInfo object loaded from an AST file.
- MacroInfo *AllocateDeserializedMacroInfo(SourceLocation L,
- unsigned SubModuleID);
-
/// \brief Turn the specified lexer token into a fully checked and spelled
/// filename, e.g. as an operand of \#include.
///
@@ -1664,7 +1721,7 @@ public:
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache = false);
+ bool *IsMapped, bool SkipCache = false);
/// \brief Get the DirectoryLookup structure used to find the current
/// FileEntry, if CurLexer is non-null and if applicable.
@@ -1699,13 +1756,16 @@ public:
bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
bool *ShadowFlag = nullptr);
-private:
+ void EnterSubmodule(Module *M, SourceLocation ImportLoc, bool ForPragma);
+ Module *LeaveSubmodule(bool ForPragma);
+private:
void PushIncludeMacroStack() {
assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer");
- IncludeMacroStack.emplace_back(
- CurLexerKind, CurSubmodule, std::move(CurLexer), std::move(CurPTHLexer),
- CurPPLexer, std::move(CurTokenLexer), CurDirLookup);
+ IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule,
+ std::move(CurLexer), std::move(CurPTHLexer),
+ CurPPLexer, std::move(CurTokenLexer),
+ CurDirLookup);
CurPPLexer = nullptr;
}
@@ -1715,16 +1775,13 @@ private:
CurPPLexer = IncludeMacroStack.back().ThePPLexer;
CurTokenLexer = std::move(IncludeMacroStack.back().TheTokenLexer);
CurDirLookup = IncludeMacroStack.back().TheDirLookup;
- CurSubmodule = IncludeMacroStack.back().TheSubmodule;
+ CurLexerSubmodule = IncludeMacroStack.back().TheSubmodule;
CurLexerKind = IncludeMacroStack.back().CurLexerKind;
IncludeMacroStack.pop_back();
}
void PropagateLineStartLeadingSpaceInfo(Token &Result);
- void EnterSubmodule(Module *M, SourceLocation ImportLoc);
- void LeaveSubmodule();
-
/// Determine whether we need to create module macros for #defines in the
/// current context.
bool needModuleMacros() const;
@@ -1733,9 +1790,6 @@ private:
/// macro name.
void updateModuleMacroInfo(const IdentifierInfo *II, ModuleMacroInfo &Info);
- /// \brief Allocate a new MacroInfo object.
- MacroInfo *AllocateMacroInfo();
-
DefMacroDirective *AllocateDefMacroDirective(MacroInfo *MI,
SourceLocation Loc);
UndefMacroDirective *AllocateUndefMacroDirective(SourceLocation UndefLoc);
@@ -1755,11 +1809,24 @@ private:
void ReadMacroName(Token &MacroNameTok, MacroUse IsDefineUndef = MU_Other,
bool *ShadowFlag = nullptr);
+ /// ReadOptionalMacroParameterListAndBody - This consumes all (i.e. the
+ /// entire line) of the macro's tokens and adds them to MacroInfo, and while
+ /// doing so performs certain validity checks including (but not limited to):
+ /// - # (stringization) is followed by a macro parameter
+ /// \param MacroNameTok - Token that represents the macro name
+ /// \param ImmediatelyAfterHeaderGuard - Macro follows an #ifdef header guard
+ ///
+ /// Either returns a pointer to a MacroInfo object OR emits a diagnostic and
+ /// returns a nullptr if an invalid sequence of tokens is encountered.
+
+ MacroInfo *ReadOptionalMacroParameterListAndBody(
+ const Token &MacroNameTok, bool ImmediatelyAfterHeaderGuard);
+
/// The ( starting an argument list of a macro definition has just been read.
- /// Lex the rest of the arguments and the closing ), updating \p MI with
+ /// Lex the rest of the parameters and the closing ), updating \p MI with
/// what we learn and saving in \p LastTok the last token read.
/// Return true if an error occurs parsing the arg list.
- bool ReadMacroDefinitionArgList(MacroInfo *MI, Token& LastTok);
+ bool ReadMacroParameterList(MacroInfo *MI, Token& LastTok);
/// We just read a \#if or related directive and decided that the
/// subsequent tokens are in the \#if'd out portion of the
@@ -1776,11 +1843,20 @@ private:
/// \brief A fast PTH version of SkipExcludedConditionalBlock.
void PTHSkipExcludedConditionalBlock();
+ /// Information about the result for evaluating an expression for a
+ /// preprocessor directive.
+ struct DirectiveEvalResult {
+ /// Whether the expression was evaluated as true or not.
+ bool Conditional;
+ /// True if the expression contained identifiers that were undefined.
+ bool IncludedUndefinedIds;
+ };
+
/// \brief Evaluate an integer constant expression that may occur after a
- /// \#if or \#elif directive and return it as a bool.
+ /// \#if or \#elif directive and return a \p DirectiveEvalResult object.
///
/// If the expression is equivalent to "!defined(X)" return X in IfNDefMacro.
- bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro);
+ DirectiveEvalResult EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro);
/// \brief Install the standard preprocessor pragmas:
/// \#pragma GCC poison/system_header/dependency and \#pragma once.
@@ -1811,7 +1887,7 @@ private:
/// After reading "MACRO(", this method is invoked to read all of the formal
/// arguments specified for the macro invocation. Returns null on error.
- MacroArgs *ReadFunctionLikeMacroArgs(Token &MacroName, MacroInfo *MI,
+ MacroArgs *ReadMacroCallArgumentList(Token &MacroName, MacroInfo *MI,
SourceLocation &ExpansionEnd);
/// \brief If an identifier token is read that is to be expanded
@@ -1895,20 +1971,24 @@ private:
void HandleMicrosoftImportDirective(Token &Tok);
public:
+ /// Check that the given module is available, producing a diagnostic if not.
+ /// \return \c true if the check failed (because the module is not available).
+ /// \c false if the module appears to be usable.
+ static bool checkModuleIsAvailable(const LangOptions &LangOpts,
+ const TargetInfo &TargetInfo,
+ DiagnosticsEngine &Diags, Module *M);
+
// Module inclusion testing.
/// \brief Find the module that owns the source or header file that
/// \p Loc points to. If the location is in a file that was included
/// into a module, or is outside any module, returns nullptr.
Module *getModuleForLocation(SourceLocation Loc);
- /// \brief Find the module that contains the specified location, either
- /// directly or indirectly.
- Module *getModuleContainingLocation(SourceLocation Loc);
-
/// \brief We want to produce a diagnostic at location IncLoc concerning a
/// missing module import.
///
/// \param IncLoc The location at which the missing import was detected.
+ /// \param M The desired module.
/// \param MLoc A location within the desired module at which some desired
/// effect occurred (eg, where a desired entity was declared).
///
@@ -1916,9 +1996,35 @@ public:
/// Null if no such file could be determined or if a #include is not
/// appropriate.
const FileEntry *getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
+ Module *M,
SourceLocation MLoc);
+ bool isRecordingPreamble() const {
+ return PreambleConditionalStack.isRecording();
+ }
+
+ bool hasRecordedPreamble() const {
+ return PreambleConditionalStack.hasRecordedPreamble();
+ }
+
+ ArrayRef<PPConditionalInfo> getPreambleConditionalStack() const {
+ return PreambleConditionalStack.getStack();
+ }
+
+ void setRecordedPreambleConditionalStack(ArrayRef<PPConditionalInfo> s) {
+ PreambleConditionalStack.setStack(s);
+ }
+
+ void setReplayablePreambleConditionalStack(ArrayRef<PPConditionalInfo> s) {
+ PreambleConditionalStack.startReplaying();
+ PreambleConditionalStack.setStack(s);
+ }
+
private:
+ /// \brief After processing predefined file, initialize the conditional stack from
+ /// the preamble.
+ void replayPreambleConditionalStack();
+
// Macro handling.
void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
void HandleUndefDirective();
@@ -1943,6 +2049,7 @@ public:
void HandlePragmaPushMacro(Token &Tok);
void HandlePragmaPopMacro(Token &Tok);
void HandlePragmaIncludeAlias(Token &Tok);
+ void HandlePragmaModuleBuild(Token &Tok);
IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok);
// Return true and store the first token only if any CommentHandler
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h
index 6d6cf05..5c2e4d4 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h
@@ -17,6 +17,7 @@
#include "clang/Lex/MultipleIncludeOpt.h"
#include "clang/Lex/Token.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -176,6 +177,11 @@ public:
conditional_iterator conditional_end() const {
return ConditionalStack.end();
}
+
+ void setConditionalLevels(ArrayRef<PPConditionalInfo> CL) {
+ ConditionalStack.clear();
+ ConditionalStack.append(CL.begin(), CL.end());
+ }
};
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h
index 58d79f7..d91c665 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h
@@ -80,7 +80,14 @@ public:
/// The boolean indicates whether the preamble ends at the start of a new
/// line.
std::pair<unsigned, bool> PrecompiledPreambleBytes;
-
+
+ /// \brief True indicates that a preamble is being generated.
+ ///
+ /// When the lexer is done, one of the things that need to be preserved is the
+ /// conditional #if stack, so the ASTWriter/ASTReader can save/restore it when
+ /// processing the rest of the file.
+ bool GeneratePreamble;
+
/// The implicit PTH input included at the start of the translation unit, or
/// empty.
std::string ImplicitPTHInclude;
@@ -88,6 +95,16 @@ public:
/// If given, a PTH cache file to use for speeding up header parsing.
std::string TokenCache;
+ /// When enabled, preprocessor is in a mode for parsing a single file only.
+ ///
+ /// Disables #includes of other files and if there are unresolved identifiers
+ /// in preprocessor directive conditions it causes all blocks to be parsed so
+ /// that the client can get the maximum amount of information from the parser.
+ bool SingleFileParseMode = false;
+
+ /// When enabled, the preprocessor will construct editor placeholder tokens.
+ bool LexEditorPlaceholders = true;
+
/// \brief True if the SourceManager should report the original file name for
/// contents of files that were remapped to other files. Defaults to true.
bool RemappedFilesKeepOriginalName;
@@ -144,6 +161,7 @@ public:
AllowPCHWithCompilerErrors(false),
DumpDeserializedPCHDecls(false),
PrecompiledPreambleBytes(0, true),
+ GeneratePreamble(false),
RemappedFilesKeepOriginalName(true),
RetainRemappedFileBuffers(false),
ObjCXXARCStandardLibrary(ARCXX_nolib) { }
@@ -173,6 +191,8 @@ public:
ImplicitPCHInclude.clear();
ImplicitPTHInclude.clear();
TokenCache.clear();
+ SingleFileParseMode = false;
+ LexEditorPlaceholders = true;
RetainRemappedFileBuffers = true;
PrecompiledPreambleBytes.first = 0;
PrecompiledPreambleBytes.second = 0;
diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Token.h b/contrib/llvm/tools/clang/include/clang/Lex/Token.h
index 4393e20..02a1fef 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/Token.h
+++ b/contrib/llvm/tools/clang/include/clang/Lex/Token.h
@@ -84,6 +84,7 @@ public:
StringifiedInMacro = 0x100, // This string or character literal is formed by
// macro stringizing or charizing operator.
CommaAfterElided = 0x200, // The comma following this token was elided (MS).
+ IsEditorPlaceholder = 0x400, // This identifier is a placeholder.
};
tok::TokenKind getKind() const { return Kind; }
@@ -298,6 +299,13 @@ public:
/// Returns true if the comma after this token was elided.
bool commaAfterElided() const { return getFlag(CommaAfterElided); }
+
+ /// Returns true if this token is an editor placeholder.
+ ///
+ /// Editor placeholders are produced by the code-completion engine and are
+ /// represented as characters between '<#' and '#>' in the source code. The
+ /// lexer uses identifier tokens to represent placeholders.
+ bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); }
};
/// \brief Information about the conditional stack (\#if directives)
diff --git a/contrib/llvm/tools/clang/include/clang/Parse/Parser.h b/contrib/llvm/tools/clang/include/clang/Parse/Parser.h
index fe15902..21d699e 100644
--- a/contrib/llvm/tools/clang/include/clang/Parse/Parser.h
+++ b/contrib/llvm/tools/clang/include/clang/Parse/Parser.h
@@ -142,6 +142,10 @@ class Parser : public CodeCompletionHandler {
/// \brief Identifier for "replacement".
IdentifierInfo *Ident_replacement;
+ /// Identifiers used by the 'external_source_symbol' attribute.
+ IdentifierInfo *Ident_language, *Ident_defined_in,
+ *Ident_generated_declaration;
+
/// C++0x contextual keywords.
mutable IdentifierInfo *Ident_final;
mutable IdentifierInfo *Ident_GNU_final;
@@ -162,6 +166,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> FPContractHandler;
std::unique_ptr<PragmaHandler> OpenCLExtensionHandler;
std::unique_ptr<PragmaHandler> OpenMPHandler;
+ std::unique_ptr<PragmaHandler> PCSectionHandler;
std::unique_ptr<PragmaHandler> MSCommentHandler;
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
std::unique_ptr<PragmaHandler> MSPointersToMembers;
@@ -179,6 +184,8 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> LoopHintHandler;
std::unique_ptr<PragmaHandler> UnrollHintHandler;
std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
+ std::unique_ptr<PragmaHandler> FPHandler;
+ std::unique_ptr<PragmaHandler> AttributePragmaHandler;
std::unique_ptr<CommentHandler> CommentSemaHandler;
@@ -298,8 +305,9 @@ public:
}
/// ConsumeToken - Consume the current 'peek token' and lex the next one.
- /// This does not work with special tokens: string literals, code completion
- /// and balanced tokens must be handled using the specific consume methods.
+ /// This does not work with special tokens: string literals, code completion,
+ /// annotation tokens and balanced tokens must be handled using the specific
+ /// consume methods.
/// Returns the location of the consumed token.
SourceLocation ConsumeToken() {
assert(!isTokenSpecial() &&
@@ -360,7 +368,7 @@ private:
/// isTokenSpecial - True if this token requires special consumption methods.
bool isTokenSpecial() const {
return isTokenStringLiteral() || isTokenParen() || isTokenBracket() ||
- isTokenBrace() || Tok.is(tok::code_completion);
+ isTokenBrace() || Tok.is(tok::code_completion) || Tok.isAnnotation();
}
/// \brief Returns true if the current token is '=' or is a type of '='.
@@ -391,9 +399,19 @@ private:
if (Tok.is(tok::code_completion))
return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken()
: handleUnexpectedCodeCompletionToken();
+ if (Tok.isAnnotation())
+ return ConsumeAnnotationToken();
return ConsumeToken();
}
+ SourceLocation ConsumeAnnotationToken() {
+ assert(Tok.isAnnotation() && "wrong consume method");
+ SourceLocation Loc = Tok.getLocation();
+ PrevTokLocation = Tok.getAnnotationEndLoc();
+ PP.Lex(Tok);
+ return Loc;
+ }
+
/// ConsumeParen - This consume method keeps the paren count up-to-date.
///
SourceLocation ConsumeParen() {
@@ -545,6 +563,10 @@ private:
void HandlePragmaFPContract();
/// \brief Handle the annotation token produced for
+ /// #pragma clang fp ...
+ void HandlePragmaFP();
+
+ /// \brief Handle the annotation token produced for
/// #pragma OPENCL EXTENSION...
void HandlePragmaOpenCLExtension();
@@ -556,6 +578,12 @@ private:
/// #pragma clang loop and #pragma unroll.
bool HandlePragmaLoopHint(LoopHint &Hint);
+ bool ParsePragmaAttributeSubjectMatchRuleSet(
+ attr::ParsedSubjectMatchRuleSet &SubjectMatchRules,
+ SourceLocation &AnyLoc, SourceLocation &LastMatchRuleEndLoc);
+
+ void HandlePragmaAttribute();
+
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
/// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
/// returns the token after Tok, etc.
@@ -576,7 +604,7 @@ public:
}
/// getTypeAnnotation - Read a parsed type out of an annotation token.
- static ParsedType getTypeAnnotation(Token &Tok) {
+ static ParsedType getTypeAnnotation(const Token &Tok) {
return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue());
}
@@ -587,7 +615,7 @@ private:
/// \brief Read an already-translated primary expression out of an annotation
/// token.
- static ExprResult getExprAnnotation(Token &Tok) {
+ static ExprResult getExprAnnotation(const Token &Tok) {
return ExprResult::getFromOpaquePointer(Tok.getAnnotationValue());
}
@@ -791,6 +819,14 @@ private:
/// \brief Consume any extra semi-colons until the end of the line.
void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified);
+ /// Return false if the next token is an identifier. An 'expected identifier'
+ /// error is emitted otherwise.
+ ///
+ /// The parser tries to recover from the error by checking if the next token
+ /// is a C++ keyword when parsing Objective-C++. Return false if the recovery
+ /// was successful.
+ bool expectIdentifier();
+
public:
//===--------------------------------------------------------------------===//
// Scope manipulation
@@ -1425,6 +1461,8 @@ public:
};
ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast);
+ ExprResult ParseConstantExpressionInExprEvalContext(
+ TypeCastState isTypeCast = NotTypeCast);
ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast);
ExprResult ParseConstraintExpression();
// Expr that doesn't include commas.
@@ -1445,10 +1483,12 @@ private:
ExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
- TypeCastState isTypeCast);
+ TypeCastState isTypeCast,
+ bool isVectorLiteral = false);
ExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand = false,
- TypeCastState isTypeCast = NotTypeCast);
+ TypeCastState isTypeCast = NotTypeCast,
+ bool isVectorLiteral = false);
/// Returns true if the next token cannot start an expression.
bool isNotExpressionStart();
@@ -1462,6 +1502,8 @@ private:
K == tok::plusplus || K == tok::minusminus);
}
+ bool diagnoseUnknownTemplateId(ExprResult TemplateName, SourceLocation Less);
+
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
ExprResult ParseUnaryExprOrTypeTraitExpression();
ExprResult ParseBuiltinPrimaryExpression();
@@ -1530,7 +1572,8 @@ private:
bool EnteringContext,
bool *MayBePseudoDestructor = nullptr,
bool IsTypename = false,
- IdentifierInfo **LastII = nullptr);
+ IdentifierInfo **LastII = nullptr,
+ bool OnlyNamespace = false);
//===--------------------------------------------------------------------===//
// C++0x 5.1.2: Lambda expressions
@@ -1682,7 +1725,7 @@ private:
StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr,
bool AllowOpenMPStandalone = false);
- enum AllowedContsructsKind {
+ enum AllowedConstructsKind {
/// \brief Allow any declarations, statements, OpenMP directives.
ACK_Any,
/// \brief Allow only statements and non-standalone OpenMP directives.
@@ -1691,11 +1734,11 @@ private:
ACK_StatementsOpenMPAnyExecutable
};
StmtResult
- ParseStatementOrDeclaration(StmtVector &Stmts, AllowedContsructsKind Allowed,
+ ParseStatementOrDeclaration(StmtVector &Stmts, AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc = nullptr);
StmtResult ParseStatementOrDeclarationAfterAttributes(
StmtVector &Stmts,
- AllowedContsructsKind Allowed,
+ AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs);
StmtResult ParseExprStatement();
@@ -1724,7 +1767,7 @@ private:
StmtResult ParseAsmStatement(bool &msAsm);
StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc);
StmtResult ParsePragmaLoopHint(StmtVector &Stmts,
- AllowedContsructsKind Allowed,
+ AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs);
@@ -1809,6 +1852,7 @@ private:
DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration
DSC_top_level, // top-level/namespace declaration context
+ DSC_template_param, // template parameter context
DSC_template_type_arg, // template type argument context
DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
DSC_condition // condition declaration context
@@ -1819,6 +1863,7 @@ private:
static bool isTypeSpecifier(DeclSpecContext DSC) {
switch (DSC) {
case DSC_normal:
+ case DSC_template_param:
case DSC_class:
case DSC_top_level:
case DSC_objc_method_result:
@@ -1834,6 +1879,27 @@ private:
llvm_unreachable("Missing DeclSpecContext case");
}
+ /// Is this a context in which we can perform class template argument
+ /// deduction?
+ static bool isClassTemplateDeductionContext(DeclSpecContext DSC) {
+ switch (DSC) {
+ case DSC_normal:
+ case DSC_template_param:
+ case DSC_class:
+ case DSC_top_level:
+ case DSC_condition:
+ case DSC_type_specifier:
+ return true;
+
+ case DSC_objc_method_result:
+ case DSC_template_type_arg:
+ case DSC_trailing:
+ case DSC_alias_declaration:
+ return false;
+ }
+ llvm_unreachable("Missing DeclSpecContext case");
+ }
+
/// Information on a C++0x for-range-initializer found while parsing a
/// declaration which turns out to be a for-range-declaration.
struct ForRangeInit {
@@ -1947,7 +2013,7 @@ private:
/// \brief Starting with a scope specifier, identifier, or
/// template-id that refers to the current class, determine whether
/// this is a constructor declarator.
- bool isConstructorDeclarator(bool Unqualified);
+ bool isConstructorDeclarator(bool Unqualified, bool DeductionGuide = false);
/// \brief Specifies the context in which type-id/expression
/// disambiguation will occur.
@@ -2177,6 +2243,12 @@ private:
Declarator *D);
IdentifierLoc *ParseIdentifierLoc();
+ unsigned
+ ParseClangAttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs, SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax);
+
void MaybeParseCXX11Attributes(Declarator &D) {
if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
@@ -2266,6 +2338,14 @@ private:
Optional<AvailabilitySpec> ParseAvailabilitySpec();
ExprResult ParseAvailabilityCheckExpr(SourceLocation StartLoc);
+ void ParseExternalSourceSymbolAttribute(IdentifierInfo &ExternalSourceSymbol,
+ SourceLocation Loc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax);
+
void ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
SourceLocation ObjCBridgeRelatedLoc,
ParsedAttributes &attrs,
@@ -2365,10 +2445,10 @@ private:
AR_DeclspecAttributesParsed
};
- void ParseTypeQualifierListOpt(DeclSpec &DS,
- unsigned AttrReqs = AR_AllAttributesParsed,
- bool AtomicAllowed = true,
- bool IdentifierRequired = false);
+ void ParseTypeQualifierListOpt(
+ DeclSpec &DS, unsigned AttrReqs = AR_AllAttributesParsed,
+ bool AtomicAllowed = true, bool IdentifierRequired = false,
+ Optional<llvm::function_ref<void()>> CodeCompletionHandler = None);
void ParseDirectDeclarator(Declarator &D);
void ParseDecompositionDeclarator(Declarator &D);
void ParseParenDeclarator(Declarator &D);
@@ -2549,7 +2629,7 @@ private:
/// executable directives are allowed.
///
StmtResult
- ParseOpenMPDeclarativeOrExecutableDirective(AllowedContsructsKind Allowed);
+ ParseOpenMPDeclarativeOrExecutableDirective(AllowedConstructsKind Allowed);
/// \brief Parses clause of kind \a CKind for directive of a kind \a Kind.
///
/// \param DKind Kind of current directive.
@@ -2614,6 +2694,7 @@ public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
+ bool AllowDeductionGuide,
ParsedType ObjectType,
SourceLocation& TemplateKWLoc,
UnqualifiedId &Result);
@@ -2661,10 +2742,7 @@ private:
bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
bool ConsumeLastToken,
bool ObjCGenericList);
- bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
- SourceLocation TemplateNameLoc,
- const CXXScopeSpec &SS,
- bool ConsumeLastToken,
+ bool ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
SourceLocation &LAngleLoc,
TemplateArgList &TemplateArgs,
SourceLocation &RAngleLoc);
@@ -2674,7 +2752,7 @@ private:
SourceLocation TemplateKWLoc,
UnqualifiedId &TemplateName,
bool AllowTypeAnnotation = true);
- void AnnotateTemplateIdTokenAsType();
+ void AnnotateTemplateIdTokenAsType(bool IsClassName = false);
bool IsTemplateArgumentList(unsigned Skip = 0);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
ParsedTemplateArgument ParseTemplateTemplateArgument();
diff --git a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h b/contrib/llvm/tools/clang/include/clang/Parse/RAIIObjectsForParser.h
index 36d87eb..0422b03 100644
--- a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h
+++ b/contrib/llvm/tools/clang/include/clang/Parse/RAIIObjectsForParser.h
@@ -18,6 +18,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Sema.h"
namespace clang {
@@ -442,6 +443,25 @@ namespace clang {
void skipToEnd();
};
+ /// \brief RAIIObject to destroy the contents of a SmallVector of
+ /// TemplateIdAnnotation pointers and clear the vector.
+ class DestroyTemplateIdAnnotationsRAIIObj {
+ SmallVectorImpl<TemplateIdAnnotation *> &Container;
+
+ public:
+ DestroyTemplateIdAnnotationsRAIIObj(
+ SmallVectorImpl<TemplateIdAnnotation *> &Container)
+ : Container(Container) {}
+
+ ~DestroyTemplateIdAnnotationsRAIIObj() {
+ for (SmallVectorImpl<TemplateIdAnnotation *>::iterator I =
+ Container.begin(),
+ E = Container.end();
+ I != E; ++I)
+ (*I)->Destroy();
+ Container.clear();
+ }
+ };
} // end namespace clang
#endif
diff --git a/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FrontendActions.h b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FrontendActions.h
index 27976ea..5f83ac1 100644
--- a/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FrontendActions.h
+++ b/contrib/llvm/tools/clang/include/clang/Rewrite/Frontend/FrontendActions.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_REWRITE_FRONTEND_FRONTENDACTIONS_H
#include "clang/Frontend/FrontendAction.h"
+#include "llvm/Support/raw_ostream.h"
namespace clang {
class FixItRewriter;
@@ -34,8 +35,7 @@ protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
- bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) override;
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
void EndSourceFileAction() override;
@@ -74,7 +74,10 @@ protected:
};
class RewriteIncludesAction : public PreprocessorFrontendAction {
+ std::shared_ptr<raw_ostream> OutputStream;
+ class RewriteImportsListener;
protected:
+ bool BeginSourceFileAction(CompilerInstance &CI) override;
void ExecuteAction() override;
};
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h b/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h
index e74bf6a..6bdd9d5 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_SEMA_ATTRIBUTELIST_H
#define LLVM_CLANG_SEMA_ATTRIBUTELIST_H
+#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/VersionTuple.h"
@@ -509,9 +510,14 @@ public:
unsigned getMaxArgs() const;
bool hasVariadicArg() const;
bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
+ bool appliesToDecl(const Decl *D, attr::SubjectMatchRule MatchRule) const;
+ void getMatchRules(const LangOptions &LangOpts,
+ SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>>
+ &MatchRules) const;
bool diagnoseLangOpts(class Sema &S) const;
bool existsInTarget(const TargetInfo &Target) const;
bool isKnownToGCC() const;
+ bool isSupportedByPragmaAttribute() const;
/// \brief If the parsed attribute has a semantic equivalent, and it would
/// have a semantic Spelling enumeration (due to having semantically-distinct
@@ -774,6 +780,8 @@ public:
void clear() { list = nullptr; pool.clear(); }
AttributeList *getList() const { return list; }
+ void clearListOnly() { list = nullptr; }
+
/// Returns a reference to the attribute list. Try not to introduce
/// dependencies on this method, it may not be long-lived.
AttributeList *&getListRef() { return list; }
@@ -907,6 +915,7 @@ enum AttributeDeclKind {
ExpectedTypeOrNamespace,
ExpectedObjectiveCInterface,
ExpectedMethodOrProperty,
+ ExpectedFunctionOrMethodOrProperty,
ExpectedStructOrUnion,
ExpectedStructOrUnionOrClass,
ExpectedType,
@@ -927,6 +936,7 @@ enum AttributeDeclKind {
ExpectedStructClassVariableFunctionOrInlineNamespace,
ExpectedForMaybeUnused,
ExpectedEnumOrClass,
+ ExpectedNamedDecl,
};
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h b/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h
index 331fd0d..bc81715 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h
@@ -519,7 +519,7 @@ public:
SourceRange getTypeofParensRange() const { return TypeofParensRange; }
void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; }
- bool containsPlaceholderType() const {
+ bool hasAutoTypeSpec() const {
return (TypeSpecType == TST_auto || TypeSpecType == TST_auto_type ||
TypeSpecType == TST_decltype_auto);
}
@@ -819,7 +819,9 @@ public:
: objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr),
Nullability(0), GetterName(nullptr), SetterName(nullptr) { }
- ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; }
+ ObjCDeclQualifier getObjCDeclQualifier() const {
+ return (ObjCDeclQualifier)objcDeclQualifier;
+ }
void setObjCDeclQualifier(ObjCDeclQualifier DQVal) {
objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal);
}
@@ -859,17 +861,25 @@ public:
const IdentifierInfo *getGetterName() const { return GetterName; }
IdentifierInfo *getGetterName() { return GetterName; }
- void setGetterName(IdentifierInfo *name) { GetterName = name; }
+ SourceLocation getGetterNameLoc() const { return GetterNameLoc; }
+ void setGetterName(IdentifierInfo *name, SourceLocation loc) {
+ GetterName = name;
+ GetterNameLoc = loc;
+ }
const IdentifierInfo *getSetterName() const { return SetterName; }
IdentifierInfo *getSetterName() { return SetterName; }
- void setSetterName(IdentifierInfo *name) { SetterName = name; }
+ SourceLocation getSetterNameLoc() const { return SetterNameLoc; }
+ void setSetterName(IdentifierInfo *name, SourceLocation loc) {
+ SetterName = name;
+ SetterNameLoc = loc;
+ }
private:
// FIXME: These two are unrelated and mutually exclusive. So perhaps
// we can put them in a union to reflect their mutual exclusivity
// (space saving is negligible).
- ObjCDeclQualifier objcDeclQualifier : 7;
+ unsigned objcDeclQualifier : 7;
// NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
unsigned PropertyAttributes : 15;
@@ -880,6 +890,9 @@ private:
IdentifierInfo *GetterName; // getter name or NULL if no getter
IdentifierInfo *SetterName; // setter name or NULL if no setter
+ SourceLocation GetterNameLoc; // location of the getter attribute's value
+ SourceLocation SetterNameLoc; // location of the setter attribute's value
+
};
/// \brief Represents a C++ unqualified-id that has been parsed.
@@ -908,7 +921,9 @@ public:
/// \brief A template-id, e.g., f<int>.
IK_TemplateId,
/// \brief An implicit 'self' parameter
- IK_ImplicitSelfParam
+ IK_ImplicitSelfParam,
+ /// \brief A deduction-guide name (a template-name)
+ IK_DeductionGuideName
} Kind;
struct OFI {
@@ -928,8 +943,8 @@ public:
/// \brief Anonymous union that holds extra data associated with the
/// parsed unqualified-id.
union {
- /// \brief When Kind == IK_Identifier, the parsed identifier, or when Kind
- /// == IK_UserLiteralId, the identifier suffix.
+ /// \brief When Kind == IK_Identifier, the parsed identifier, or when
+ /// Kind == IK_UserLiteralId, the identifier suffix.
IdentifierInfo *Identifier;
/// \brief When Kind == IK_OperatorFunctionId, the overloaded operator
@@ -947,6 +962,9 @@ public:
/// \brief When Kind == IK_DestructorName, the type referred to by the
/// class-name.
UnionParsedType DestructorName;
+
+ /// \brief When Kind == IK_DeductionGuideName, the parsed template-name.
+ UnionParsedTemplateTy TemplateName;
/// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId,
/// the template-id annotation that contains the template name and
@@ -1085,6 +1103,18 @@ public:
/// \p TemplateId and will free it on destruction.
void setTemplateId(TemplateIdAnnotation *TemplateId);
+ /// \brief Specify that this unqualified-id was parsed as a template-name for
+ /// a deduction-guide.
+ ///
+ /// \param Template The parsed template-name.
+ /// \param TemplateLoc The location of the parsed template-name.
+ void setDeductionGuideName(ParsedTemplateTy Template,
+ SourceLocation TemplateLoc) {
+ Kind = IK_DeductionGuideName;
+ TemplateName = Template;
+ StartLocation = EndLocation = TemplateLoc;
+ }
+
/// \brief Return the source range that covers this unqualified-id.
SourceRange getSourceRange() const LLVM_READONLY {
return SourceRange(StartLocation, EndLocation);
@@ -1709,6 +1739,7 @@ public:
ObjCParameterContext,// An ObjC method parameter type.
KNRTypeListContext, // K&R type definition list for formals.
TypeNameContext, // Abstract declarator for types.
+ FunctionalCastContext, // Type in a C++ functional cast expression.
MemberContext, // Struct/Union field.
BlockContext, // Declaration within a block in a function.
ForContext, // Declaration within first part of a for loop.
@@ -1911,6 +1942,7 @@ public:
return false;
case TypeNameContext:
+ case FunctionalCastContext:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
@@ -1951,6 +1983,7 @@ public:
return true;
case TypeNameContext:
+ case FunctionalCastContext:
case CXXNewContext:
case AliasDeclContext:
case AliasTemplateContext:
@@ -1966,40 +1999,6 @@ public:
llvm_unreachable("unknown context kind!");
}
- /// diagnoseIdentifier - Return true if the identifier is prohibited and
- /// should be diagnosed (because it cannot be anything else).
- bool diagnoseIdentifier() const {
- switch (Context) {
- case FileContext:
- case KNRTypeListContext:
- case MemberContext:
- case BlockContext:
- case ForContext:
- case InitStmtContext:
- case ConditionContext:
- case PrototypeContext:
- case LambdaExprParameterContext:
- case TemplateParamContext:
- case CXXCatchContext:
- case ObjCCatchContext:
- case TypeNameContext:
- case ConversionIdContext:
- case ObjCParameterContext:
- case ObjCResultContext:
- case BlockLiteralContext:
- case CXXNewContext:
- case LambdaExprContext:
- return false;
-
- case AliasDeclContext:
- case AliasTemplateContext:
- case TemplateTypeArgContext:
- case TrailingReturnContext:
- return true;
- }
- llvm_unreachable("unknown context kind!");
- }
-
/// Return true if the context permits a C++17 decomposition declarator.
bool mayHaveDecompositionDeclarator() const {
switch (Context) {
@@ -2021,6 +2020,7 @@ public:
// These contexts don't allow any kind of non-abstract declarator.
case KNRTypeListContext:
case TypeNameContext:
+ case FunctionalCastContext:
case AliasDeclContext:
case AliasTemplateContext:
case LambdaExprParameterContext:
@@ -2078,6 +2078,7 @@ public:
case CXXCatchContext:
case ObjCCatchContext:
case TypeNameContext:
+ case FunctionalCastContext: // FIXME
case CXXNewContext:
case AliasDeclContext:
case AliasTemplateContext:
@@ -2279,6 +2280,7 @@ public:
case ConditionContext:
case KNRTypeListContext:
case TypeNameContext:
+ case FunctionalCastContext:
case AliasDeclContext:
case AliasTemplateContext:
case PrototypeContext:
@@ -2312,6 +2314,16 @@ public:
return true;
}
+ /// \brief Determine whether a trailing return type was written (at any
+ /// level) within this declarator.
+ bool hasTrailingReturnType() const {
+ for (const auto &Chunk : type_objects())
+ if (Chunk.Kind == DeclaratorChunk::Function &&
+ Chunk.Fun.hasTrailingReturnType())
+ return true;
+ return false;
+ }
+
/// takeAttributes - Takes attributes from the given parsed-attributes
/// set and add them to this declarator.
///
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h
index b73ec08..d65dbf0 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h
@@ -124,7 +124,8 @@ public:
static DelayedDiagnostic makeAvailability(AvailabilityResult AR,
SourceLocation Loc,
- const NamedDecl *D,
+ const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
StringRef Msg,
@@ -164,9 +165,13 @@ public:
return *reinterpret_cast<const AccessedEntity*>(AccessData);
}
- const NamedDecl *getAvailabilityDecl() const {
+ const NamedDecl *getAvailabilityReferringDecl() const {
assert(Kind == Availability && "Not an availability diagnostic.");
- return AvailabilityData.Decl;
+ return AvailabilityData.ReferringDecl;
+ }
+
+ const NamedDecl *getAvailabilityOffendingDecl() const {
+ return AvailabilityData.OffendingDecl;
}
StringRef getAvailabilityMessage() const {
@@ -213,7 +218,8 @@ public:
private:
struct AD {
- const NamedDecl *Decl;
+ const NamedDecl *ReferringDecl;
+ const NamedDecl *OffendingDecl;
const ObjCInterfaceDecl *UnknownObjCClass;
const ObjCPropertyDecl *ObjCProperty;
const char *Message;
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h b/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h
index a07834f..382fe80 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h
@@ -73,12 +73,10 @@ public:
typedef std::input_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
- /// Ptr - There are 3 forms that 'Ptr' represents:
+ /// Ptr - There are 2 forms that 'Ptr' represents:
/// 1) A single NamedDecl. (Ptr & 0x1 == 0)
/// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the
- /// same declaration context. (Ptr & 0x3 == 0x1)
- /// 3) A IdDeclInfo::DeclsTy::iterator that traverses the decls of parent
- /// declaration contexts too. (Ptr & 0x3 == 0x3)
+ /// same declaration context. (Ptr & 0x1 == 0x1)
uintptr_t Ptr;
typedef IdDeclInfo::DeclsTy::iterator BaseIter;
@@ -97,7 +95,7 @@ public:
BaseIter getIterator() const {
assert(isIterator() && "Ptr not an iterator!");
- return reinterpret_cast<BaseIter>(Ptr & ~0x3);
+ return reinterpret_cast<BaseIter>(Ptr & ~0x1);
}
friend class IdentifierResolver;
@@ -128,14 +126,6 @@ public:
incrementSlowCase();
return *this;
}
-
- uintptr_t getAsOpaqueValue() const { return Ptr; }
-
- static iterator getFromOpaqueValue(uintptr_t P) {
- iterator Result;
- Result.Ptr = P;
- return Result;
- }
};
/// begin - Returns an iterator for decls with the name 'Name'.
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h b/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h
index 94be58a..bd07b9e 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h
@@ -70,6 +70,9 @@ public:
/// \brief The entity being initialized is a field of block descriptor for
/// the copied-in c++ object.
EK_BlockElement,
+ /// The entity being initialized is a field of block descriptor for the
+ /// copied-in lambda object that's used in the lambda to block conversion.
+ EK_LambdaToBlockConversionBlockElement,
/// \brief The entity being initialized is the real or imaginary part of a
/// complex number.
EK_ComplexElement,
@@ -260,7 +263,13 @@ public:
QualType Type, bool NRVO) {
return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO);
}
-
+
+ static InitializedEntity InitializeLambdaToBlock(SourceLocation BlockVarLoc,
+ QualType Type, bool NRVO) {
+ return InitializedEntity(EK_LambdaToBlockConversionBlockElement,
+ BlockVarLoc, Type, NRVO);
+ }
+
/// \brief Create the initialization entity for an exception object.
static InitializedEntity InitializeException(SourceLocation ThrowLoc,
QualType Type, bool NRVO) {
@@ -274,15 +283,18 @@ public:
/// \brief Create the initialization entity for a temporary.
static InitializedEntity InitializeTemporary(QualType Type) {
- InitializedEntity Result(EK_Temporary, SourceLocation(), Type);
- Result.TypeInfo = nullptr;
- return Result;
+ return InitializeTemporary(nullptr, Type);
}
/// \brief Create the initialization entity for a temporary.
static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) {
- InitializedEntity Result(EK_Temporary, SourceLocation(),
- TypeInfo->getType());
+ return InitializeTemporary(TypeInfo, TypeInfo->getType());
+ }
+
+ /// \brief Create the initialization entity for a temporary.
+ static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo,
+ QualType Type) {
+ InitializedEntity Result(EK_Temporary, SourceLocation(), Type);
Result.TypeInfo = TypeInfo;
return Result;
}
@@ -579,6 +591,16 @@ public:
return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal,
InitLoc, LParenLoc, RParenLoc);
}
+
+ /// \brief Create an initialization from an initializer (which, for direct
+ /// initialization from a parenthesized list, will be a ParenListExpr).
+ static InitializationKind CreateForInit(SourceLocation Loc, bool DirectInit,
+ Expr *Init) {
+ if (!Init) return CreateDefault(Loc);
+ if (!DirectInit) return CreateCopy(Loc, Init->getLocStart());
+ if (isa<InitListExpr>(Init)) return CreateDirectList(Loc);
+ return CreateDirect(Loc, Init->getLocStart(), Init->getLocEnd());
+ }
/// \brief Determine the initialization kind.
InitKind getKind() const {
@@ -809,6 +831,8 @@ public:
enum FailureKind {
/// \brief Too many initializers provided for a reference.
FK_TooManyInitsForReference,
+ /// \brief Reference initialized from a parenthesized initializer list.
+ FK_ParenthesizedListInitForReference,
/// \brief Array must be initialized with an initializer list.
FK_ArrayNeedsInitList,
/// \brief Array must be initialized with an initializer list or a
@@ -853,6 +877,8 @@ public:
FK_ConversionFromPropertyFailed,
/// \brief Too many initializers for scalar
FK_TooManyInitsForScalar,
+ /// \brief Scalar initialized from a parenthesized initializer list.
+ FK_ParenthesizedListInitForScalar,
/// \brief Reference initialization from an initializer list
FK_ReferenceBindingToInitList,
/// \brief Initialization of some unused destination type with an
@@ -879,7 +905,7 @@ public:
/// having its address taken.
FK_AddressOfUnaddressableFunction,
/// \brief List-copy-initialization chose an explicit constructor.
- FK_ExplicitConstructor
+ FK_ExplicitConstructor,
};
private:
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h b/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h
index 2ed9548..ea32997 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h
@@ -18,6 +18,8 @@
#include "clang/AST/DeclCXX.h"
#include "clang/Sema/Sema.h"
+#include "llvm/ADT/Optional.h"
+
namespace clang {
/// @brief Represents the results of name lookup.
@@ -146,7 +148,7 @@ public:
}
// TODO: consider whether this constructor should be restricted to take
- // as input a const IndentifierInfo* (instead of Name),
+ // as input a const IdentifierInfo* (instead of Name),
// forcing other cases towards the constructor taking a DNInfo.
LookupResult(Sema &SemaRef, DeclarationName Name,
SourceLocation NameLoc, Sema::LookupNameKind LookupKind,
@@ -273,7 +275,7 @@ public:
/// declarations, such as those in modules that have not yet been imported.
bool isHiddenDeclarationVisible(NamedDecl *ND) const {
return AllowHidden ||
- (isForRedeclaration() && ND->isExternallyVisible());
+ (isForRedeclaration() && ND->hasExternalFormalLinkage());
}
/// Sets whether tag declarations should be hidden by non-tag
@@ -465,7 +467,7 @@ public:
Paths = nullptr;
}
} else {
- AmbiguityKind SavedAK;
+ llvm::Optional<AmbiguityKind> SavedAK;
bool WasAmbiguous = false;
if (ResultKind == Ambiguous) {
SavedAK = Ambiguity;
@@ -479,7 +481,7 @@ public:
if (ResultKind == Ambiguous) {
(void)WasAmbiguous;
assert(WasAmbiguous);
- Ambiguity = SavedAK;
+ Ambiguity = SavedAK.getValue();
} else if (Paths) {
deletePaths(Paths);
Paths = nullptr;
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/contrib/llvm/tools/clang/include/clang/Sema/MultiplexExternalSemaSource.h
index 3715720..1d681a0 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -90,6 +90,8 @@ public:
/// initializers themselves.
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
+ ExtKind hasExternalDefinitions(const Decl *D) override;
+
/// \brief Find all declarations with the given name in the
/// given context.
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Overload.h b/contrib/llvm/tools/clang/include/clang/Sema/Overload.h
index 5220d98..ffdf011 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Overload.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/Overload.h
@@ -98,6 +98,7 @@ namespace clang {
ICR_Exact_Match = 0, ///< Exact Match
ICR_Promotion, ///< Promotion
ICR_Conversion, ///< Conversion
+ ICR_OCL_Scalar_Widening, ///< OpenCL Scalar Widening
ICR_Complex_Real_Conversion, ///< Complex <-> Real conversion
ICR_Writeback_Conversion, ///< ObjC ARC writeback conversion
ICR_C_Conversion, ///< Conversion only allowed in the C standard.
@@ -632,12 +633,9 @@ namespace clang {
/// Might be a UsingShadowDecl or a FunctionTemplateDecl.
DeclAccessPair FoundDecl;
- // BuiltinTypes - Provides the return and parameter types of a
- // built-in overload candidate. Only valid when Function is NULL.
- struct {
- QualType ResultTy;
- QualType ParamTypes[3];
- } BuiltinTypes;
+ /// BuiltinParamTypes - Provides the parameter types of a built-in overload
+ /// candidate. Only valid when Function is NULL.
+ QualType BuiltinParamTypes[3];
/// Surrogate - The conversion function for which this candidate
/// is a surrogate, but only if IsSurrogate is true.
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h b/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h
index fd46de8..848837a 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/Ownership.h
@@ -257,6 +257,7 @@ namespace clang {
typedef ActionResult<Decl*> DeclResult;
typedef OpaquePtr<TemplateName> ParsedTemplateTy;
+ typedef UnionOpaquePtr<TemplateName> UnionParsedTemplateTy;
typedef MutableArrayRef<Expr*> MultiExprArg;
typedef MutableArrayRef<Stmt*> MultiStmtArg;
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h b/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h
index 03de9ff..01a4ab3 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h
@@ -145,12 +145,15 @@ namespace clang {
/// expressions, or template names, and the source locations for important
/// tokens. All of the information about template arguments is allocated
/// directly after this structure.
- struct TemplateIdAnnotation {
+ struct TemplateIdAnnotation final
+ : private llvm::TrailingObjects<TemplateIdAnnotation,
+ ParsedTemplateArgument> {
+ friend TrailingObjects;
/// \brief The nested-name-specifier that precedes the template name.
CXXScopeSpec SS;
- /// TemplateKWLoc - The location of the template keyword within the
- /// source.
+ /// TemplateKWLoc - The location of the template keyword.
+ /// For e.g. typename T::template Y<U>
SourceLocation TemplateKWLoc;
/// TemplateNameLoc - The location of the template name within the
@@ -183,34 +186,56 @@ namespace clang {
/// \brief Retrieves a pointer to the template arguments
ParsedTemplateArgument *getTemplateArgs() {
- return reinterpret_cast<ParsedTemplateArgument *>(this + 1);
+ return getTrailingObjects<ParsedTemplateArgument>();
}
/// \brief Creates a new TemplateIdAnnotation with NumArgs arguments and
/// appends it to List.
static TemplateIdAnnotation *
- Allocate(unsigned NumArgs, SmallVectorImpl<TemplateIdAnnotation*> &List) {
- TemplateIdAnnotation *TemplateId
- = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
- sizeof(ParsedTemplateArgument) * NumArgs);
- TemplateId->NumArgs = NumArgs;
-
- // Default-construct nested-name-specifier.
- new (&TemplateId->SS) CXXScopeSpec();
-
- // Default-construct parsed template arguments.
- ParsedTemplateArgument *TemplateArgs = TemplateId->getTemplateArgs();
- for (unsigned I = 0; I != NumArgs; ++I)
- new (TemplateArgs + I) ParsedTemplateArgument();
-
- List.push_back(TemplateId);
+ Create(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
+ SourceLocation TemplateNameLoc, IdentifierInfo *Name,
+ OverloadedOperatorKind OperatorKind,
+ ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind,
+ SourceLocation LAngleLoc, SourceLocation RAngleLoc,
+ ArrayRef<ParsedTemplateArgument> TemplateArgs,
+ SmallVectorImpl<TemplateIdAnnotation *> &CleanupList) {
+
+ TemplateIdAnnotation *TemplateId = new (std::malloc(
+ totalSizeToAlloc<ParsedTemplateArgument>(TemplateArgs.size())))
+ TemplateIdAnnotation(SS, TemplateKWLoc, TemplateNameLoc, Name,
+ OperatorKind, OpaqueTemplateName, TemplateKind,
+ LAngleLoc, RAngleLoc, TemplateArgs);
+ CleanupList.push_back(TemplateId);
return TemplateId;
}
-
- void Destroy() {
- SS.~CXXScopeSpec();
+
+ void Destroy() {
+ std::for_each(
+ getTemplateArgs(), getTemplateArgs() + NumArgs,
+ [](ParsedTemplateArgument &A) { A.~ParsedTemplateArgument(); });
+ this->~TemplateIdAnnotation();
free(this);
}
+ private:
+ TemplateIdAnnotation(const TemplateIdAnnotation &) = delete;
+
+ TemplateIdAnnotation(CXXScopeSpec SS, SourceLocation TemplateKWLoc,
+ SourceLocation TemplateNameLoc, IdentifierInfo *Name,
+ OverloadedOperatorKind OperatorKind,
+ ParsedTemplateTy OpaqueTemplateName,
+ TemplateNameKind TemplateKind,
+ SourceLocation LAngleLoc, SourceLocation RAngleLoc,
+ ArrayRef<ParsedTemplateArgument> TemplateArgs) noexcept
+ : SS(SS), TemplateKWLoc(TemplateKWLoc),
+ TemplateNameLoc(TemplateNameLoc), Name(Name), Operator(OperatorKind),
+ Template(OpaqueTemplateName), Kind(TemplateKind),
+ LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
+ NumArgs(TemplateArgs.size()) {
+
+ std::uninitialized_copy(TemplateArgs.begin(), TemplateArgs.end(),
+ getTemplateArgs());
+ }
+ ~TemplateIdAnnotation() = default;
};
/// Retrieves the range of the given template parameter lists.
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h b/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h
index 4b54807..4251fa6 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSwitch.h"
#include <algorithm>
namespace clang {
@@ -135,6 +136,18 @@ public:
/// false if there is an invocation of an initializer on 'self'.
bool ObjCWarnForNoInitDelegation : 1;
+ /// \brief True only when this function has not already built, or attempted
+ /// to build, the initial and final coroutine suspend points
+ bool NeedsCoroutineSuspends : 1;
+
+ /// \brief An enumeration represeting the kind of the first coroutine statement
+ /// in the function. One of co_return, co_await, or co_yield.
+ unsigned char FirstCoroutineStmtKind : 2;
+
+ /// First coroutine statement in the current function.
+ /// (ex co_return, co_await, co_yield)
+ SourceLocation FirstCoroutineStmtLoc;
+
/// First 'return' statement in the current function.
SourceLocation FirstReturnLoc;
@@ -157,12 +170,10 @@ public:
SmallVector<ReturnStmt*, 4> Returns;
/// \brief The promise object for this coroutine, if any.
- VarDecl *CoroutinePromise;
+ VarDecl *CoroutinePromise = nullptr;
- /// \brief The list of coroutine control flow constructs (co_await, co_yield,
- /// co_return) that occur within the function or block. Empty if and only if
- /// this function or block is not (yet known to be) a coroutine.
- SmallVector<Stmt*, 4> CoroutineStmts;
+ /// \brief The initial and final coroutine suspend points.
+ std::pair<Stmt *, Stmt *> CoroutineSuspends;
/// \brief The stack of currently active compound stamement scopes in the
/// function.
@@ -376,7 +387,49 @@ public:
(HasIndirectGoto ||
(HasBranchProtectedScope && HasBranchIntoScope));
}
-
+
+ bool isCoroutine() const { return !FirstCoroutineStmtLoc.isInvalid(); }
+
+ void setFirstCoroutineStmt(SourceLocation Loc, StringRef Keyword) {
+ assert(FirstCoroutineStmtLoc.isInvalid() &&
+ "first coroutine statement location already set");
+ FirstCoroutineStmtLoc = Loc;
+ FirstCoroutineStmtKind = llvm::StringSwitch<unsigned char>(Keyword)
+ .Case("co_return", 0)
+ .Case("co_await", 1)
+ .Case("co_yield", 2);
+ }
+
+ StringRef getFirstCoroutineStmtKeyword() const {
+ assert(FirstCoroutineStmtLoc.isValid()
+ && "no coroutine statement available");
+ switch (FirstCoroutineStmtKind) {
+ case 0: return "co_return";
+ case 1: return "co_await";
+ case 2: return "co_yield";
+ default:
+ llvm_unreachable("FirstCoroutineStmtKind has an invalid value");
+ };
+ }
+
+ void setNeedsCoroutineSuspends(bool value = true) {
+ assert((!value || CoroutineSuspends.first == nullptr) &&
+ "we already have valid suspend points");
+ NeedsCoroutineSuspends = value;
+ }
+
+ bool hasInvalidCoroutineSuspends() const {
+ return !NeedsCoroutineSuspends && CoroutineSuspends.first == nullptr;
+ }
+
+ void setCoroutineSuspends(Stmt *Initial, Stmt *Final) {
+ assert(Initial && Final && "suspend points cannot be null");
+ assert(CoroutineSuspends.first == nullptr && "suspend points already set");
+ NeedsCoroutineSuspends = false;
+ CoroutineSuspends.first = Initial;
+ CoroutineSuspends.second = Final;
+ }
+
FunctionScopeInfo(DiagnosticsEngine &Diag)
: Kind(SK_Function),
HasBranchProtectedScope(false),
@@ -391,6 +444,7 @@ public:
ObjCWarnForNoDesignatedInitChain(false),
ObjCIsSecondaryInit(false),
ObjCWarnForNoInitDelegation(false),
+ NeedsCoroutineSuspends(true),
ErrorTrap(Diag) { }
virtual ~FunctionScopeInfo();
@@ -452,6 +506,14 @@ public:
/// non-static data member that would hold the capture.
QualType CaptureType;
+ /// \brief Whether an explicit capture has been odr-used in the body of the
+ /// lambda.
+ bool ODRUsed;
+
+ /// \brief Whether an explicit capture has been non-odr-used in the body of
+ /// the lambda.
+ bool NonODRUsed;
+
public:
Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
SourceLocation Loc, SourceLocation EllipsisLoc,
@@ -460,7 +522,8 @@ public:
InitExprAndCaptureKind(
Cpy, !Var ? Cap_VLA : Block ? Cap_Block : ByRef ? Cap_ByRef
: Cap_ByCopy),
- Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {}
+ Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType),
+ ODRUsed(false), NonODRUsed(false) {}
enum IsThisCapture { ThisCapture };
Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
@@ -468,7 +531,8 @@ public:
: VarAndNestedAndThis(
nullptr, (IsThisCaptured | (IsNested ? IsNestedCapture : 0))),
InitExprAndCaptureKind(Cpy, ByCopy ? Cap_ByCopy : Cap_ByRef),
- Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {}
+ Loc(Loc), EllipsisLoc(), CaptureType(CaptureType), ODRUsed(false),
+ NonODRUsed(false) {}
bool isThisCapture() const {
return VarAndNestedAndThis.getInt() & IsThisCaptured;
@@ -491,6 +555,9 @@ public:
bool isNested() const {
return VarAndNestedAndThis.getInt() & IsNestedCapture;
}
+ bool isODRUsed() const { return ODRUsed; }
+ bool isNonODRUsed() const { return NonODRUsed; }
+ void markUsed(bool IsODRUse) { (IsODRUse ? ODRUsed : NonODRUsed) = true; }
VarDecl *getVariable() const {
return VarAndNestedAndThis.getPointer();
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h
index 63d0784..5a70854 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h
@@ -26,6 +26,7 @@
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/NSAPI.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/StmtCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/ExpressionTraits.h"
@@ -101,6 +102,7 @@ namespace clang {
class CodeCompletionAllocator;
class CodeCompletionTUInfo;
class CodeCompletionResult;
+ class CoroutineBodyStmt;
class Decl;
class DeclAccessPair;
class DeclContext;
@@ -334,6 +336,35 @@ public:
/// \brief Source location for newly created implicit MSInheritanceAttrs
SourceLocation ImplicitMSInheritanceAttrLoc;
+ /// \brief pragma clang section kind
+ enum PragmaClangSectionKind {
+ PCSK_Invalid = 0,
+ PCSK_BSS = 1,
+ PCSK_Data = 2,
+ PCSK_Rodata = 3,
+ PCSK_Text = 4
+ };
+
+ enum PragmaClangSectionAction {
+ PCSA_Set = 0,
+ PCSA_Clear = 1
+ };
+
+ struct PragmaClangSection {
+ std::string SectionName;
+ bool Valid = false;
+ SourceLocation PragmaLocation;
+
+ void Act(SourceLocation PragmaLocation,
+ PragmaClangSectionAction Action,
+ StringLiteral* Name);
+ };
+
+ PragmaClangSection PragmaClangBSSSection;
+ PragmaClangSection PragmaClangDataSection;
+ PragmaClangSection PragmaClangRodataSection;
+ PragmaClangSection PragmaClangTextSection;
+
enum PragmaMsStackAction {
PSK_Reset = 0x0, // #pragma ()
PSK_Set = 0x1, // #pragma (value)
@@ -435,6 +466,20 @@ public:
/// VisContext - Manages the stack for \#pragma GCC visibility.
void *VisContext; // Really a "PragmaVisStack*"
+ /// \brief This represents the stack of attributes that were pushed by
+ /// \#pragma clang attribute.
+ struct PragmaAttributeEntry {
+ SourceLocation Loc;
+ AttributeList *Attribute;
+ SmallVector<attr::SubjectMatchRule, 4> MatchRules;
+ bool IsUsed;
+ };
+ SmallVector<PragmaAttributeEntry, 2> PragmaAttributeStack;
+
+ /// \brief The declaration that is currently receiving an attribute from the
+ /// #pragma attribute stack.
+ const Decl *PragmaAttributeCurrentTargetDecl;
+
/// \brief This represents the last location of a "#pragma clang optimize off"
/// directive if such a directive has not been closed by an "on" yet. If
/// optimizations are currently "on", this is set to an invalid location.
@@ -673,16 +718,37 @@ public:
class SynthesizedFunctionScope {
Sema &S;
Sema::ContextRAII SavedContext;
+ bool PushedCodeSynthesisContext = false;
public:
SynthesizedFunctionScope(Sema &S, DeclContext *DC)
- : S(S), SavedContext(S, DC)
- {
+ : S(S), SavedContext(S, DC) {
S.PushFunctionScope();
- S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ S.PushExpressionEvaluationContext(
+ Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ if (auto *FD = dyn_cast<FunctionDecl>(DC))
+ FD->setWillHaveBody(true);
+ else
+ assert(isa<ObjCMethodDecl>(DC));
+ }
+
+ void addContextNote(SourceLocation UseLoc) {
+ assert(!PushedCodeSynthesisContext);
+
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::DefiningSynthesizedFunction;
+ Ctx.PointOfInstantiation = UseLoc;
+ Ctx.Entity = cast<Decl>(S.CurContext);
+ S.pushCodeSynthesisContext(Ctx);
+
+ PushedCodeSynthesisContext = true;
}
~SynthesizedFunctionScope() {
+ if (PushedCodeSynthesisContext)
+ S.popCodeSynthesisContext();
+ if (auto *FD = dyn_cast<FunctionDecl>(S.CurContext))
+ FD->setWillHaveBody(false);
S.PopExpressionEvaluationContext();
S.PopFunctionScopeInfo();
}
@@ -800,7 +866,7 @@ public:
/// \brief Describes how the expressions currently being parsed are
/// evaluated at run-time, if at all.
- enum ExpressionEvaluationContext {
+ enum class ExpressionEvaluationContext {
/// \brief The current expression and its subexpressions occur within an
/// unevaluated operand (C++11 [expr]p7), such as the subexpression of
/// \c sizeof, where the type of the expression may be significant but
@@ -906,8 +972,12 @@ public:
MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx);
bool isUnevaluated() const {
- return Context == Unevaluated || Context == UnevaluatedAbstract ||
- Context == UnevaluatedList;
+ return Context == ExpressionEvaluationContext::Unevaluated ||
+ Context == ExpressionEvaluationContext::UnevaluatedAbstract ||
+ Context == ExpressionEvaluationContext::UnevaluatedList;
+ }
+ bool isConstantEvaluated() const {
+ return Context == ExpressionEvaluationContext::ConstantEvaluated;
}
};
@@ -931,7 +1001,7 @@ public:
///
/// This is basically a wrapper around PointerIntPair. The lowest bits of the
/// integer are used to determine whether overload resolution succeeded.
- class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode {
+ class SpecialMemberOverloadResult {
public:
enum Kind {
NoMemberOrDeleted,
@@ -943,9 +1013,9 @@ public:
llvm::PointerIntPair<CXXMethodDecl*, 2> Pair;
public:
- SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID)
- : FastFoldingSetNode(ID)
- {}
+ SpecialMemberOverloadResult() : Pair() {}
+ SpecialMemberOverloadResult(CXXMethodDecl *MD)
+ : Pair(MD, MD->isDeleted() ? NoMemberOrDeleted : Success) {}
CXXMethodDecl *getMethod() const { return Pair.getPointer(); }
void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); }
@@ -954,9 +1024,18 @@ public:
void setKind(Kind K) { Pair.setInt(K); }
};
+ class SpecialMemberOverloadResultEntry
+ : public llvm::FastFoldingSetNode,
+ public SpecialMemberOverloadResult {
+ public:
+ SpecialMemberOverloadResultEntry(const llvm::FoldingSetNodeID &ID)
+ : FastFoldingSetNode(ID)
+ {}
+ };
+
/// \brief A cache of special member function overload resolution results
/// for C++ records.
- llvm::FoldingSet<SpecialMemberOverloadResult> SpecialMemberCache;
+ llvm::FoldingSet<SpecialMemberOverloadResultEntry> SpecialMemberCache;
/// \brief A cache of the flags available in enumerations with the flag_bits
/// attribute.
@@ -1038,6 +1117,16 @@ public:
/// same special member, we should act as if it is not yet declared.
llvm::SmallSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared;
+ /// The function definitions which were renamed as part of typo-correction
+ /// to match their respective declarations. We want to keep track of them
+ /// to ensure that we don't emit a "redefinition" error if we encounter a
+ /// correctly named definition after the renamed definition.
+ llvm::SmallPtrSet<const NamedDecl *, 4> TypoCorrectedFunctionDefinitions;
+
+ /// Stack of types that correspond to the parameter entities that are
+ /// currently being copy-initialized. Can be empty.
+ llvm::SmallVector<QualType, 4> CurrentParameterCopyTypes;
+
void ReadMethodPool(Selector Sel);
void updateOutOfDateSelector(Selector Sel);
@@ -1054,14 +1143,12 @@ public:
/// statements.
class FPContractStateRAII {
public:
- FPContractStateRAII(Sema& S)
- : S(S), OldFPContractState(S.FPFeatures.fp_contract) {}
- ~FPContractStateRAII() {
- S.FPFeatures.fp_contract = OldFPContractState;
- }
+ FPContractStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {}
+ ~FPContractStateRAII() { S.FPFeatures = OldFPFeaturesState; }
+
private:
Sema& S;
- bool OldFPContractState : 1;
+ FPOptions OldFPFeaturesState;
};
void addImplicitTypedef(StringRef Name, QualType T);
@@ -1179,6 +1266,7 @@ public:
void emitAndClearUnusedLocalTypedefWarnings();
+ void ActOnStartOfTranslationUnit();
void ActOnEndOfTranslationUnit();
void CheckDelegatingCtorCycles();
@@ -1235,9 +1323,11 @@ public:
sema::BlockScopeInfo *getCurBlock();
/// Retrieve the current lambda scope info, if any.
- /// \param IgnoreCapturedRegions true if should find the top-most lambda scope
- /// info ignoring all inner captured regions scope infos.
- sema::LambdaScopeInfo *getCurLambda(bool IgnoreCapturedRegions = false);
+ /// \param IgnoreNonLambdaCapturingScope true if should find the top-most
+ /// lambda scope info ignoring all inner capturing scopes that are not
+ /// lambda scopes.
+ sema::LambdaScopeInfo *
+ getCurLambda(bool IgnoreNonLambdaCapturingScope = false);
/// \brief Retrieve the current generic lambda info, if any.
sema::LambdaScopeInfo *getCurGenericLambda();
@@ -1420,17 +1510,20 @@ private:
/// The modules we're currently parsing.
llvm::SmallVector<ModuleScope, 16> ModuleScopes;
- VisibleModuleSet VisibleModules;
+ /// Get the module whose scope we are currently within.
+ Module *getCurrentModule() const {
+ return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module;
+ }
- Module *CachedFakeTopLevelModule;
+ VisibleModuleSet VisibleModules;
public:
/// \brief Get the module owning an entity.
- Module *getOwningModule(Decl *Entity);
+ Module *getOwningModule(Decl *Entity) { return Entity->getOwningModule(); }
/// \brief Make a merged definition of an existing hidden definition \p ND
/// visible at the specified location.
- void makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc);
+ void makeMergedDefinitionVisible(NamedDecl *ND);
bool isModuleVisible(Module *M) { return VisibleModules.isVisible(M); }
@@ -1449,6 +1542,11 @@ public:
llvm::SmallVectorImpl<Module *> *Modules);
bool hasVisibleMergedDefinition(NamedDecl *Def);
+ bool hasMergedDefinitionInCurrentModule(NamedDecl *Def);
+
+ /// Determine if \p D and \p Suggested have a structurally compatible
+ /// layout as described in C11 6.2.7/1.
+ bool hasStructuralCompatLayout(Decl *D, Decl *Suggested);
/// Determine if \p D has a visible definition. If not, suggest a declaration
/// that should be made visible to expose the definition.
@@ -1464,6 +1562,12 @@ public:
hasVisibleDefaultArgument(const NamedDecl *D,
llvm::SmallVectorImpl<Module *> *Modules = nullptr);
+ /// Determine if there is a visible declaration of \p D that is an explicit
+ /// specialization declaration for a specialization of a template. (For a
+ /// member specialization, use hasVisibleMemberSpecialization.)
+ bool hasVisibleExplicitSpecialization(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules = nullptr);
+
/// Determine if there is a visible declaration of \p D that is a member
/// specialization declaration (as opposed to an instantiated declaration).
bool hasVisibleMemberSpecialization(
@@ -1531,9 +1635,13 @@ public:
//
struct SkipBodyInfo {
- SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {}
+ SkipBodyInfo()
+ : ShouldSkip(false), CheckSameAsPrevious(false), Previous(nullptr),
+ New(nullptr) {}
bool ShouldSkip;
+ bool CheckSameAsPrevious;
NamedDecl *Previous;
+ NamedDecl *New;
};
DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr);
@@ -1548,6 +1656,7 @@ public:
ParsedType ObjectType = nullptr,
bool IsCtorOrDtorName = false,
bool WantNontrivialTypeSourceInfo = false,
+ bool IsClassTemplateDeductionContext = true,
IdentifierInfo **CorrectedII = nullptr);
TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S);
bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S);
@@ -1556,7 +1665,7 @@ public:
Scope *S,
CXXScopeSpec *SS,
ParsedType &SuggestedType,
- bool AllowClassTemplates = false);
+ bool IsTemplateName = false);
/// Attempt to behave like MSVC in situations where lookup of an unqualified
/// type name has failed in a dependent context. In these situations, we
@@ -1689,6 +1798,35 @@ public:
bool IsAddressOfOperand,
std::unique_ptr<CorrectionCandidateCallback> CCC = nullptr);
+ /// Describes the detailed kind of a template name. Used in diagnostics.
+ enum class TemplateNameKindForDiagnostics {
+ ClassTemplate,
+ FunctionTemplate,
+ VarTemplate,
+ AliasTemplate,
+ TemplateTemplateParam,
+ DependentTemplate
+ };
+ TemplateNameKindForDiagnostics
+ getTemplateNameKindForDiagnostics(TemplateName Name);
+
+ /// Determine whether it's plausible that E was intended to be a
+ /// template-name.
+ bool mightBeIntendedToBeTemplateName(ExprResult E) {
+ if (!getLangOpts().CPlusPlus || E.isInvalid())
+ return false;
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E.get()))
+ return !DRE->hasExplicitTemplateArgs();
+ if (auto *ME = dyn_cast<MemberExpr>(E.get()))
+ return !ME->hasExplicitTemplateArgs();
+ // Any additional cases recognized here should also be handled by
+ // diagnoseExprIntendedAsTemplateName.
+ return false;
+ }
+ void diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
+ SourceLocation Less,
+ SourceLocation Greater);
+
Decl *ActOnDeclarator(Scope *S, Declarator &D);
NamedDecl *HandleDeclarator(Scope *S, Declarator &D,
@@ -1709,8 +1847,11 @@ public:
static bool adjustContextForLocalExternDecl(DeclContext *&DC);
void DiagnoseFunctionSpecifiers(const DeclSpec &DS);
+ NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D,
+ const LookupResult &R);
NamedDecl *getShadowedDeclaration(const VarDecl *D, const LookupResult &R);
- void CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl, const LookupResult &R);
+ void CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
+ const LookupResult &R);
void CheckShadow(Scope *S, VarDecl *D);
/// Warn if 'E', which is an expression that is about to be modified, refers
@@ -1747,6 +1888,8 @@ public:
// Returns true if the variable declaration is a redeclaration
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
void CheckVariableDeclarationType(VarDecl *NewVD);
+ bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
+ Expr *Init);
void CheckCompleteVariableDeclaration(VarDecl *VD);
void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD);
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
@@ -1769,7 +1912,7 @@ public:
// Returns true if the function declaration is a redeclaration
bool CheckFunctionDeclaration(Scope *S,
FunctionDecl *NewFD, LookupResult &Previous,
- bool IsExplicitSpecialization);
+ bool IsMemberSpecialization);
bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl);
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
void CheckMSVCRTEntryPoint(FunctionDecl *FD);
@@ -1794,7 +1937,6 @@ public:
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit);
void ActOnUninitializedDecl(Decl *dcl);
void ActOnInitializerError(Decl *Dcl);
- bool canInitializeWithParenthesizedList(QualType TargetType);
void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc);
void ActOnCXXForRangeDecl(Decl *D);
@@ -1887,7 +2029,8 @@ public:
/// The parser has processed a module-declaration that begins the definition
/// of a module interface or implementation.
- DeclGroupPtrTy ActOnModuleDecl(SourceLocation ModuleLoc, ModuleDeclKind MDK,
+ DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc,
+ SourceLocation ModuleLoc, ModuleDeclKind MDK,
ModuleIdPath Path);
/// \brief The parser has processed a module import declaration.
@@ -2012,15 +2155,14 @@ public:
};
Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, CXXScopeSpec &SS,
- IdentifierInfo *Name, SourceLocation NameLoc,
- AttributeList *Attr, AccessSpecifier AS,
- SourceLocation ModulePrivateLoc,
- MultiTemplateParamsArg TemplateParameterLists,
- bool &OwnedDecl, bool &IsDependent,
- SourceLocation ScopedEnumKWLoc,
+ SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name,
+ SourceLocation NameLoc, AttributeList *Attr,
+ AccessSpecifier AS, SourceLocation ModulePrivateLoc,
+ MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl,
+ bool &IsDependent, SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
- bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr);
+ bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+ SkipBodyInfo *SkipBody = nullptr);
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
unsigned TagSpec, SourceLocation TagLoc,
@@ -2085,6 +2227,12 @@ public:
/// struct, or union).
void ActOnTagStartDefinition(Scope *S, Decl *TagDecl);
+ /// Perform ODR-like check for C/ObjC when merging tag types from modules.
+ /// Differently from C++, actually parse the body and reject / error out
+ /// in case of a structural mismatch.
+ bool ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev,
+ SkipBodyInfo &SkipBody);
+
typedef void *SkippedDefinitionContext;
/// \brief Invoked when we enter a tag definition that we're skipping.
@@ -2138,8 +2286,8 @@ public:
Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant,
SourceLocation IdLoc, IdentifierInfo *Id,
- AttributeList *Attrs,
- SourceLocation EqualLoc, Expr *Val);
+ AttributeList *Attrs, SourceLocation EqualLoc,
+ Expr *Val);
void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
Decl *EnumDecl,
ArrayRef<Decl *> Elements,
@@ -2282,6 +2430,7 @@ public:
void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld);
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
bool checkVarDeclRedefinition(VarDecl *OldDefn, VarDecl *NewDefn);
+ void notePreviousDefinition(const NamedDecl *Old, SourceLocation New);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
// AssignmentAction - This is used by all the assignment diagnostic functions
@@ -2593,8 +2742,7 @@ public:
SourceLocation OpLoc, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange = SourceRange());
- void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
- ArrayRef<Expr *> Args,
+ void AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator = false,
unsigned NumContextualBoolArguments = 0);
@@ -2642,7 +2790,7 @@ public:
/// of a function.
///
/// Returns true if any errors were emitted.
- bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
+ bool diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND,
SourceLocation Loc);
/// Returns whether the given function's address can be taken or not,
@@ -2672,7 +2820,8 @@ public:
resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
DeclAccessPair &FoundResult);
- bool resolveAndFixAddressOfOnlyViableOverloadCandidate(ExprResult &SrcExpr);
+ bool resolveAndFixAddressOfOnlyViableOverloadCandidate(
+ ExprResult &SrcExpr, bool DoFunctionPointerConversion = false);
FunctionDecl *
ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
@@ -2876,13 +3025,13 @@ public:
LOLR_StringTemplate
};
- SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D,
- CXXSpecialMember SM,
- bool ConstArg,
- bool VolatileArg,
- bool RValueThis,
- bool ConstThis,
- bool VolatileThis);
+ SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D,
+ CXXSpecialMember SM,
+ bool ConstArg,
+ bool VolatileArg,
+ bool RValueThis,
+ bool ConstThis,
+ bool VolatileThis);
typedef std::function<void(const TypoCorrection &)> TypoDiagnosticGenerator;
typedef std::function<ExprResult(Sema &, TypoExpr *, TypoCorrection)>
@@ -2963,9 +3112,6 @@ public:
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
UnresolvedSetImpl &Functions);
- void addOverloadedOperatorToUnresolvedSet(UnresolvedSetImpl &Functions,
- DeclAccessPair Operator,
- QualType T1, QualType T2);
LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc,
SourceLocation GnuLabelLoc = SourceLocation());
@@ -2998,7 +3144,8 @@ public:
bool IncludeGlobalScope = true);
void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
- bool IncludeGlobalScope = true);
+ bool IncludeGlobalScope = true,
+ bool IncludeDependentBases = false);
enum CorrectTypoKind {
CTK_NonError, // CorrectTypo used in a non error recovery situation.
@@ -3072,6 +3219,8 @@ public:
const PartialDiagnostic &PrevNote,
bool ErrorRecovery = true);
+ void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F);
+
void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc,
ArrayRef<Expr *> Args,
AssociatedNamespaceSet &AssociatedNamespaces,
@@ -3098,6 +3247,8 @@ public:
void ProcessPragmaWeak(Scope *S, Decl *D);
// Decl attributes - this routine is the top level dispatcher.
void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD);
+ // Helper for delayed processing of attributes.
+ void ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL,
bool IncludeCXX11Attributes = true);
bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
@@ -3115,6 +3266,7 @@ public:
bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
const FunctionDecl *FD = nullptr);
bool CheckNoReturnAttr(const AttributeList &attr);
+ bool CheckNoCallerSavedRegsAttr(const AttributeList &attr);
bool checkStringLiteralArgumentAttr(const AttributeList &Attr,
unsigned ArgNum, StringRef &Str,
SourceLocation *ArgLocation = nullptr);
@@ -3184,7 +3336,6 @@ public:
bool IsProtocolMethodDecl);
typedef llvm::SmallPtrSet<Selector, 8> SelectorSet;
- typedef llvm::DenseMap<Selector, ObjCMethodDecl*> ProtocolsMethodsMap;
/// CheckImplementationIvars - This routine checks if the instance variables
/// listed in the implelementation match those listed in the interface.
@@ -3209,9 +3360,10 @@ public:
/// DefaultSynthesizeProperties - This routine default synthesizes all
/// properties which must be synthesized in the class's \@implementation.
- void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
- ObjCInterfaceDecl *IDecl);
- void DefaultSynthesizeProperties(Scope *S, Decl *D);
+ void DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
+ ObjCInterfaceDecl *IDecl,
+ SourceLocation AtEnd);
+ void DefaultSynthesizeProperties(Scope *S, Decl *D, SourceLocation AtEnd);
/// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
/// an ivar synthesized for 'Method' and 'Method' is a property accessor
@@ -3237,7 +3389,9 @@ public:
SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
+ SourceLocation GetterNameLoc,
Selector SetterSel,
+ SourceLocation SetterNameLoc,
const bool isReadWrite,
unsigned &Attributes,
const unsigned AttributesAsWritten,
@@ -3253,7 +3407,9 @@ public:
SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
+ SourceLocation GetterNameLoc,
Selector SetterSel,
+ SourceLocation SetterNameLoc,
const bool isReadWrite,
const unsigned Attributes,
const unsigned AttributesAsWritten,
@@ -3707,6 +3863,9 @@ public:
void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType,
SourceLocation Loc);
+ /// Warn when implicitly casting 0 to nullptr.
+ void diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E);
+
ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) {
return DelayedDiagnostics.push(pool);
}
@@ -3722,11 +3881,10 @@ public:
void redelayDiagnostics(sema::DelayedDiagnosticPool &pool);
- void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D,
- StringRef Message, SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty,
- bool ObjCPropertyAccess);
+ void DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ bool ObjCPropertyAccess,
+ bool AvoidPartialAvailabilityChecks = false);
bool makeUnavailableInSystemHeader(SourceLocation loc,
UnavailableAttr::ImplicitReason reason);
@@ -3739,8 +3897,9 @@ public:
bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid);
bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass=nullptr,
- bool ObjCPropertyAccess=false);
+ const ObjCInterfaceDecl *UnknownObjCClass = nullptr,
+ bool ObjCPropertyAccess = false,
+ bool AvoidPartialAvailabilityChecks = false);
void NoteDeletedFunction(FunctionDecl *FD);
void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD);
std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD);
@@ -3782,7 +3941,7 @@ public:
void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
bool MightBeOdrUse = true);
void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
- void MarkDeclRefReferenced(DeclRefExpr *E);
+ void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr);
void MarkMemberReferenced(MemberExpr *E);
void UpdateMarkingForLValueToRValue(Expr *E);
@@ -4328,7 +4487,7 @@ public:
/// \brief Determine whether Ctor is an initializer-list constructor, as
/// defined in [dcl.init.list]p2.
- bool isInitListConstructor(const CXXConstructorDecl *Ctor);
+ bool isInitListConstructor(const FunctionDecl *Ctor);
Decl *ActOnUsingDirective(Scope *CurScope,
SourceLocation UsingLoc,
@@ -4737,7 +4896,8 @@ public:
ParsedType ObjectType,
bool EnteringContext);
- ParsedType getDestructorType(const DeclSpec& DS, ParsedType ObjectType);
+ ParsedType getDestructorTypeForDecltype(const DeclSpec &DS,
+ ParsedType ObjectType);
// Checks that reinterpret casts don't have undefined behavior.
void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
@@ -4953,7 +5113,7 @@ public:
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc);
- /// ActOnArrayTypeTrait - Parsed one of the bianry type trait support
+ /// ActOnArrayTypeTrait - Parsed one of the binary type trait support
/// pseudo-functions.
ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT,
SourceLocation KWLoc,
@@ -5106,7 +5266,8 @@ public:
CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
- bool *IsCorrectedToColon = nullptr);
+ bool *IsCorrectedToColon = nullptr,
+ bool OnlyNamespace = false);
/// \brief The parser has parsed a nested-name-specifier 'identifier::'.
///
@@ -5130,13 +5291,16 @@ public:
/// are allowed. The bool value pointed by this parameter is set to 'true'
/// if the identifier is treated as if it was followed by ':', not '::'.
///
+ /// \param OnlyNamespace If true, only considers namespaces in lookup.
+ ///
/// \returns true if an error occurred, false otherwise.
bool ActOnCXXNestedNameSpecifier(Scope *S,
NestedNameSpecInfo &IdInfo,
bool EnteringContext,
CXXScopeSpec &SS,
bool ErrorRecoveryLookup = false,
- bool *IsCorrectedToColon = nullptr);
+ bool *IsCorrectedToColon = nullptr,
+ bool OnlyNamespace = false);
ExprResult ActOnDecltypeExpression(Expr *E);
@@ -5312,6 +5476,12 @@ public:
ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope);
+ /// \brief Does copying/destroying the captured variable have side effects?
+ bool CaptureHasSideEffects(const sema::LambdaScopeInfo::Capture &From);
+
+ /// \brief Diagnose if an explicit lambda capture is unused.
+ void DiagnoseUnusedLambdaCapture(const sema::LambdaScopeInfo::Capture &From);
+
/// \brief Complete a lambda-expression having processed and attached the
/// lambda body.
ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
@@ -5604,6 +5774,9 @@ public:
void CheckConversionDeclarator(Declarator &D, QualType &R,
StorageClass& SC);
Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
+ void CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
+ StorageClass &SC);
+ void CheckDeductionGuideTemplate(FunctionTemplateDecl *TD);
void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD,
@@ -5807,6 +5980,12 @@ public:
TemplateTy &Template,
bool &MemberOfUnknownSpecialization);
+ /// Determine whether a particular identifier might be the name in a C++1z
+ /// deduction-guide declaration.
+ bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
+ SourceLocation NameLoc,
+ ParsedTemplateTy *Template = nullptr);
+
bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
@@ -5882,7 +6061,7 @@ public:
SourceLocation DeclStartLoc, SourceLocation DeclLoc,
const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists,
- bool IsFriend, bool &IsExplicitSpecialization, bool &Invalid);
+ bool IsFriend, bool &IsMemberSpecialization, bool &Invalid);
DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, CXXScopeSpec &SS,
@@ -5911,11 +6090,13 @@ public:
TypeResult
ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- TemplateTy Template, SourceLocation TemplateLoc,
+ TemplateTy Template, IdentifierInfo *TemplateII,
+ SourceLocation TemplateIILoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation RAngleLoc,
- bool IsCtorOrDtorName = false);
+ bool IsCtorOrDtorName = false,
+ bool IsClassName = false);
/// \brief Parsed an elaborated-type-specifier that refers to a template-id,
/// such as \c class T::template apply<U>.
@@ -5957,13 +6138,10 @@ public:
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs);
- TemplateNameKind ActOnDependentTemplateName(Scope *S,
- CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- UnqualifiedId &Name,
- ParsedType ObjectType,
- bool EnteringContext,
- TemplateTy &Template);
+ TemplateNameKind ActOnDependentTemplateName(
+ Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext,
+ TemplateTy &Template, bool AllowInjectedClassName = false);
DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
@@ -6003,6 +6181,7 @@ public:
TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
+ void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
DeclResult
ActOnExplicitInstantiation(Scope *S,
@@ -6088,12 +6267,17 @@ public:
/// \param Converted Will receive the converted, canonicalized template
/// arguments.
///
+ /// \param UpdateArgsWithConversions If \c true, update \p TemplateArgs to
+ /// contain the converted forms of the template arguments as written.
+ /// Otherwise, \p TemplateArgs will not be modified.
+ ///
/// \returns true if an error occurred, false otherwise.
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted);
+ SmallVectorImpl<TemplateArgument> &Converted,
+ bool UpdateArgsWithConversions = true);
bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
TemplateArgumentLoc &Arg,
@@ -6182,7 +6366,8 @@ public:
/// \param SS the nested-name-specifier following the typename (e.g., 'T::').
/// \param TemplateLoc the location of the 'template' keyword, if any.
/// \param TemplateName The template name.
- /// \param TemplateNameLoc The location of the template name.
+ /// \param TemplateII The identifier used to name the template.
+ /// \param TemplateIILoc The location of the template name.
/// \param LAngleLoc The location of the opening angle bracket ('<').
/// \param TemplateArgs The template arguments.
/// \param RAngleLoc The location of the closing angle bracket ('>').
@@ -6191,7 +6376,8 @@ public:
const CXXScopeSpec &SS,
SourceLocation TemplateLoc,
TemplateTy TemplateName,
- SourceLocation TemplateNameLoc,
+ IdentifierInfo *TemplateII,
+ SourceLocation TemplateIILoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation RAngleLoc);
@@ -6706,6 +6892,9 @@ public:
/// \brief Substitute Replacement for auto in TypeWithAuto
TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType Replacement);
+ /// \brief Completely replace the \c auto in \p TypeWithAuto by
+ /// \p Replacement. This does not retain any \c auto type sugar.
+ QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement);
/// \brief Result type of DeduceAutoType.
enum DeduceAutoResult {
@@ -6724,6 +6913,15 @@ public:
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
+ /// \brief Declare implicit deduction guides for a class template if we've
+ /// not already done so.
+ void DeclareImplicitDeductionGuides(TemplateDecl *Template,
+ SourceLocation Loc);
+
+ QualType DeduceTemplateSpecializationFromInitializer(
+ TypeSourceInfo *TInfo, const InitializedEntity &Entity,
+ const InitializationKind &Kind, MultiExprArg Init);
+
QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name,
QualType Type, TypeSourceInfo *TSI,
SourceRange Range, bool DirectInit,
@@ -6792,10 +6990,12 @@ public:
bool RelativeToPrimary = false,
const FunctionDecl *Pattern = nullptr);
- /// \brief A template instantiation that is currently in progress.
- struct ActiveTemplateInstantiation {
+ /// A context in which code is being synthesized (where a source location
+ /// alone is not sufficient to identify the context). This covers template
+ /// instantiation and various forms of implicitly-generated functions.
+ struct CodeSynthesisContext {
/// \brief The kind of template instantiation we are performing
- enum InstantiationKind {
+ enum SynthesisKind {
/// We are instantiating a template declaration. The entity is
/// the declaration we're instantiating (e.g., a CXXRecordDecl).
TemplateInstantiation,
@@ -6834,28 +7034,46 @@ public:
/// We are instantiating the exception specification for a function
/// template which was deferred until it was needed.
- ExceptionSpecInstantiation
+ ExceptionSpecInstantiation,
+
+ /// We are declaring an implicit special member function.
+ DeclaringSpecialMember,
+
+ /// We are defining a synthesized function (such as a defaulted special
+ /// member).
+ DefiningSynthesizedFunction,
} Kind;
- /// \brief The point of instantiation within the source code.
+ /// \brief Was the enclosing context a non-instantiation SFINAE context?
+ bool SavedInNonInstantiationSFINAEContext;
+
+ /// \brief The point of instantiation or synthesis within the source code.
SourceLocation PointOfInstantiation;
+ /// \brief The entity that is being synthesized.
+ Decl *Entity;
+
/// \brief The template (or partial specialization) in which we are
/// performing the instantiation, for substitutions of prior template
/// arguments.
NamedDecl *Template;
- /// \brief The entity that is being instantiated.
- Decl *Entity;
-
/// \brief The list of template arguments we are substituting, if they
/// are not part of the entity.
const TemplateArgument *TemplateArgs;
- /// \brief The number of template arguments in TemplateArgs.
- unsigned NumTemplateArgs;
+ // FIXME: Wrap this union around more members, or perhaps store the
+ // kind-specific members in the RAII object owning the context.
+ union {
+ /// \brief The number of template arguments in TemplateArgs.
+ unsigned NumTemplateArgs;
+
+ /// \brief The special member being declared or defined.
+ CXXSpecialMember SpecialMember;
+ };
ArrayRef<TemplateArgument> template_arguments() const {
+ assert(Kind != DeclaringSpecialMember);
return {TemplateArgs, NumTemplateArgs};
}
@@ -6868,56 +7086,20 @@ public:
/// template instantiation.
SourceRange InstantiationRange;
- ActiveTemplateInstantiation()
- : Kind(TemplateInstantiation), Template(nullptr), Entity(nullptr),
+ CodeSynthesisContext()
+ : Kind(TemplateInstantiation), Entity(nullptr), Template(nullptr),
TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {}
/// \brief Determines whether this template is an actual instantiation
/// that should be counted toward the maximum instantiation depth.
bool isInstantiationRecord() const;
-
- friend bool operator==(const ActiveTemplateInstantiation &X,
- const ActiveTemplateInstantiation &Y) {
- if (X.Kind != Y.Kind)
- return false;
-
- if (X.Entity != Y.Entity)
- return false;
-
- switch (X.Kind) {
- case TemplateInstantiation:
- case ExceptionSpecInstantiation:
- return true;
-
- case PriorTemplateArgumentSubstitution:
- case DefaultTemplateArgumentChecking:
- return X.Template == Y.Template && X.TemplateArgs == Y.TemplateArgs;
-
- case DefaultTemplateArgumentInstantiation:
- case ExplicitTemplateArgumentSubstitution:
- case DeducedTemplateArgumentSubstitution:
- case DefaultFunctionArgumentInstantiation:
- return X.TemplateArgs == Y.TemplateArgs;
-
- }
-
- llvm_unreachable("Invalid InstantiationKind!");
- }
-
- friend bool operator!=(const ActiveTemplateInstantiation &X,
- const ActiveTemplateInstantiation &Y) {
- return !(X == Y);
- }
};
- /// \brief List of active template instantiations.
+ /// \brief List of active code synthesis contexts.
///
- /// This vector is treated as a stack. As one template instantiation
- /// requires another template instantiation, additional
- /// instantiations are pushed onto the stack up to a
- /// user-configurable limit LangOptions::InstantiationDepth.
- SmallVector<ActiveTemplateInstantiation, 16>
- ActiveTemplateInstantiations;
+ /// This vector is treated as a stack. As synthesis of one entity requires
+ /// synthesis of another, additional contexts are pushed onto the stack.
+ SmallVector<CodeSynthesisContext, 16> CodeSynthesisContexts;
/// Specializations whose definitions are currently being instantiated.
llvm::DenseSet<std::pair<Decl *, unsigned>> InstantiatingSpecializations;
@@ -6928,7 +7110,7 @@ public:
/// \brief Extra modules inspected when performing a lookup during a template
/// instantiation. Computed lazily.
- SmallVector<Module*, 16> ActiveTemplateInstantiationLookupModules;
+ SmallVector<Module*, 16> CodeSynthesisContextLookupModules;
/// \brief Cache of additional modules that should be used for name lookup
/// within the current template instantiation. Computed lazily; use
@@ -6951,19 +7133,22 @@ public:
/// of a template instantiation or template argument deduction.
bool InNonInstantiationSFINAEContext;
- /// \brief The number of ActiveTemplateInstantiation entries in
- /// \c ActiveTemplateInstantiations that are not actual instantiations and,
- /// therefore, should not be counted as part of the instantiation depth.
+ /// \brief The number of \p CodeSynthesisContexts that are not template
+ /// instantiations and, therefore, should not be counted as part of the
+ /// instantiation depth.
+ ///
+ /// When the instantiation depth reaches the user-configurable limit
+ /// \p LangOptions::InstantiationDepth we will abort instantiation.
+ // FIXME: Should we have a similar limit for other forms of synthesis?
unsigned NonInstantiationEntries;
- /// \brief The last template from which a template instantiation
+ /// \brief The depth of the context stack at the point when the most recent
/// error or warning was produced.
///
- /// This value is used to suppress printing of redundant template
- /// instantiation backtraces when there are multiple errors in the
- /// same instantiation. FIXME: Does this belong in Sema? It's tough
- /// to implement it anywhere else.
- ActiveTemplateInstantiation LastTemplateInstantiationErrorContext;
+ /// This value is used to suppress printing of redundant context stacks
+ /// when there are multiple errors or warnings in the same instantiation.
+ // FIXME: Does this belong in Sema? It's tough to implement it anywhere else.
+ unsigned LastEmittedCodeSynthesisContextDepth = 0;
/// \brief The current index into pack expansion arguments that will be
/// used for substitution of parameter packs.
@@ -7041,7 +7226,7 @@ public:
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
FunctionTemplateDecl *FunctionTemplate,
ArrayRef<TemplateArgument> TemplateArgs,
- ActiveTemplateInstantiation::InstantiationKind Kind,
+ CodeSynthesisContext::SynthesisKind Kind,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange = SourceRange());
@@ -7120,12 +7305,11 @@ public:
Sema &SemaRef;
bool Invalid;
bool AlreadyInstantiating;
- bool SavedInNonInstantiationSFINAEContext;
bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
SourceRange InstantiationRange);
InstantiatingTemplate(
- Sema &SemaRef, ActiveTemplateInstantiation::InstantiationKind Kind,
+ Sema &SemaRef, CodeSynthesisContext::SynthesisKind Kind,
SourceLocation PointOfInstantiation, SourceRange InstantiationRange,
Decl *Entity, NamedDecl *Template = nullptr,
ArrayRef<TemplateArgument> TemplateArgs = None,
@@ -7137,8 +7321,27 @@ public:
operator=(const InstantiatingTemplate&) = delete;
};
+ void pushCodeSynthesisContext(CodeSynthesisContext Ctx);
+ void popCodeSynthesisContext();
+
+ /// Determine whether we are currently performing template instantiation.
+ bool inTemplateInstantiation() const {
+ return CodeSynthesisContexts.size() > NonInstantiationEntries;
+ }
+
+ void PrintContextStack() {
+ if (!CodeSynthesisContexts.empty() &&
+ CodeSynthesisContexts.size() != LastEmittedCodeSynthesisContextDepth) {
+ PrintInstantiationStack();
+ LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size();
+ }
+ if (PragmaAttributeCurrentTargetDecl)
+ PrintPragmaAttributeInstantiationPoint();
+ }
void PrintInstantiationStack();
+ void PrintPragmaAttributeInstantiationPoint();
+
/// \brief Determines whether we are currently in a context where
/// template argument substitution failures are not considered
/// errors.
@@ -7248,9 +7451,9 @@ public:
/// but have not yet been performed.
std::deque<PendingImplicitInstantiation> PendingInstantiations;
- class SavePendingInstantiationsAndVTableUsesRAII {
+ class GlobalEagerInstantiationScope {
public:
- SavePendingInstantiationsAndVTableUsesRAII(Sema &S, bool Enabled)
+ GlobalEagerInstantiationScope(Sema &S, bool Enabled)
: S(S), Enabled(Enabled) {
if (!Enabled) return;
@@ -7258,7 +7461,14 @@ public:
SavedVTableUses.swap(S.VTableUses);
}
- ~SavePendingInstantiationsAndVTableUsesRAII() {
+ void perform() {
+ if (Enabled) {
+ S.DefineUsedVTables();
+ S.PerformPendingInstantiations();
+ }
+ }
+
+ ~GlobalEagerInstantiationScope() {
if (!Enabled) return;
// Restore the set of pending vtables.
@@ -7288,14 +7498,16 @@ public:
/// types, static variables, enumerators, etc.
std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
- class SavePendingLocalImplicitInstantiationsRAII {
+ class LocalEagerInstantiationScope {
public:
- SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) {
+ LocalEagerInstantiationScope(Sema &S) : S(S) {
SavedPendingLocalImplicitInstantiations.swap(
S.PendingLocalImplicitInstantiations);
}
- ~SavePendingLocalImplicitInstantiationsRAII() {
+ void perform() { S.PerformPendingInstantiations(/*LocalOnly=*/true); }
+
+ ~LocalEagerInstantiationScope() {
assert(S.PendingLocalImplicitInstantiations.empty() &&
"there shouldn't be any pending local implicit instantiations");
SavedPendingLocalImplicitInstantiations.swap(
@@ -7305,7 +7517,7 @@ public:
private:
Sema &S;
std::deque<PendingImplicitInstantiation>
- SavedPendingLocalImplicitInstantiations;
+ SavedPendingLocalImplicitInstantiations;
};
/// A helper class for building up ExtParameterInfos.
@@ -7339,7 +7551,8 @@ public:
TypeSourceInfo *SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc, DeclarationName Entity);
+ SourceLocation Loc, DeclarationName Entity,
+ bool AllowDeducedTST = false);
QualType SubstType(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -7357,6 +7570,10 @@ public:
unsigned ThisTypeQuals);
void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
const MultiLevelTemplateArgumentList &Args);
+ bool SubstExceptionSpec(SourceLocation Loc,
+ FunctionProtoType::ExceptionSpecInfo &ESI,
+ SmallVectorImpl<QualType> &ExceptionStorage,
+ const MultiLevelTemplateArgumentList &Args);
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
@@ -7436,6 +7653,15 @@ public:
LateInstantiatedAttrVec *LateAttrs = nullptr,
LocalInstantiationScope *OuterMostScope = nullptr);
+ void
+ InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs,
+ const Decl *Pattern, Decl *Inst,
+ LateInstantiatedAttrVec *LateAttrs = nullptr,
+ LocalInstantiationScope *OuterMostScope = nullptr);
+
+ bool usesPartialOrExplicitSpecialization(
+ SourceLocation Loc, ClassTemplateSpecializationDecl *ClassTemplateSpec);
+
bool
InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
@@ -7510,7 +7736,8 @@ public:
const MultiLevelTemplateArgumentList &TemplateArgs);
NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
- const MultiLevelTemplateArgumentList &TemplateArgs);
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool FindingInstantiatedContext = false);
DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -7597,7 +7824,8 @@ public:
Decl * const *ProtoRefs,
unsigned NumProtoRefs,
const SourceLocation *ProtoLocs,
- SourceLocation EndProtoLoc);
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList);
Decl *ActOnStartClassImplementation(
SourceLocation AtClassImplLoc,
@@ -7941,6 +8169,11 @@ public:
POAK_Reset // #pragma options align=reset
};
+ /// ActOnPragmaClangSection - Called on well formed \#pragma clang section
+ void ActOnPragmaClangSection(SourceLocation PragmaLoc,
+ PragmaClangSectionAction Action,
+ PragmaClangSectionKind SecKind, StringRef SecName);
+
/// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align.
void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc);
@@ -8039,8 +8272,9 @@ public:
SourceLocation AliasNameLoc);
/// ActOnPragmaFPContract - Called on well formed
- /// \#pragma {STDC,OPENCL} FP_CONTRACT
- void ActOnPragmaFPContract(tok::OnOffSwitch OOS);
+ /// \#pragma {STDC,OPENCL} FP_CONTRACT and
+ /// \#pragma clang fp contract
+ void ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC);
/// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to
/// a the record decl, to handle '\#pragma pack' and '\#pragma options align'.
@@ -8073,6 +8307,20 @@ public:
/// the appropriate attribute.
void AddCFAuditedAttribute(Decl *D);
+ /// \brief Called on well-formed '\#pragma clang attribute push'.
+ void ActOnPragmaAttributePush(AttributeList &Attribute,
+ SourceLocation PragmaLoc,
+ attr::ParsedSubjectMatchRuleSet Rules);
+
+ /// \brief Called on well-formed '\#pragma clang attribute pop'.
+ void ActOnPragmaAttributePop(SourceLocation PragmaLoc);
+
+ /// \brief Adds the attributes that have been specified using the
+ /// '\#pragma clang attribute push' directives to the given declaration.
+ void AddPragmaAttributes(Scope *S, Decl *D);
+
+ void DiagnoseUnterminatedPragmaAttribute();
+
/// \brief Called on well formed \#pragma clang optimize.
void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc);
@@ -8103,6 +8351,11 @@ public:
void AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE,
unsigned SpellingListIndex);
+ /// AddAllocAlignAttr - Adds an alloc_align attribute to a particular
+ /// declaration.
+ void AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
+ unsigned SpellingListIndex);
+
/// AddAlignValueAttr - Adds an align_value attribute to a particular
/// declaration.
void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
@@ -8124,17 +8377,26 @@ public:
unsigned SpellingListIndex, bool isNSConsumed,
bool isTemplateInstantiation);
+ bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type);
+
//===--------------------------------------------------------------------===//
// C++ Coroutines TS
//
+ bool ActOnCoroutineBodyStart(Scope *S, SourceLocation KwLoc,
+ StringRef Keyword);
ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E);
ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E);
- StmtResult ActOnCoreturnStmt(SourceLocation KwLoc, Expr *E);
+ StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E);
- ExprResult BuildCoawaitExpr(SourceLocation KwLoc, Expr *E);
+ ExprResult BuildResolvedCoawaitExpr(SourceLocation KwLoc, Expr *E,
+ bool IsImplicit = false);
+ ExprResult BuildUnresolvedCoawaitExpr(SourceLocation KwLoc, Expr *E,
+ UnresolvedLookupExpr* Lookup);
ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E);
- StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E);
-
+ StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E,
+ bool IsImplicit = false);
+ StmtResult BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs);
+ VarDecl *buildCoroutinePromise(SourceLocation Loc);
void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body);
//===--------------------------------------------------------------------===//
@@ -8187,7 +8449,7 @@ public:
/// is disabled due to required OpenCL extensions being disabled. If so,
/// emit diagnostics.
/// \return true if type is disabled.
- bool checkOpenCLDisabledDecl(const Decl &D, const Expr &E);
+ bool checkOpenCLDisabledDecl(const NamedDecl &D, const Expr &E);
//===--------------------------------------------------------------------===//
// OpenMP directives and clauses.
@@ -8205,6 +8467,12 @@ private:
/// Returns OpenMP nesting level for current directive.
unsigned getOpenMPNestingLevel() const;
+ /// Push new OpenMP function region for non-capturing function.
+ void pushOpenMPFunctionRegion();
+
+ /// Pop OpenMP function region for non-capturing function.
+ void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI);
+
/// Checks if a type or a declaration is disabled due to the owning extension
/// being disabled, and emits diagnostic messages if it is disabled.
/// \param D type or declaration to be checked.
@@ -8314,6 +8582,9 @@ public:
return IsInOpenMPDeclareTargetContext;
}
+ /// Return the number of captured regions created for an OpenMP directive.
+ static int getOpenMPCaptureLevels(OpenMPDirectiveKind Kind);
+
/// \brief Initialization of captured region for OpenMP region.
void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope);
/// \brief End of OpenMP region.
@@ -8408,7 +8679,8 @@ public:
StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed '\#pragma omp taskgroup'.
- StmtResult ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc,
+ StmtResult ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed '\#pragma omp flush'.
StmtResult ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
@@ -8750,6 +9022,13 @@ public:
CXXScopeSpec &ReductionIdScopeSpec,
const DeclarationNameInfo &ReductionId,
ArrayRef<Expr *> UnresolvedReductions = llvm::None);
+ /// Called on well-formed 'task_reduction' clause.
+ OMPClause *ActOnOpenMPTaskReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions = llvm::None);
/// \brief Called on well-formed 'linear' clause.
OMPClause *
ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
@@ -9116,6 +9395,8 @@ public:
/// type checking binary operators (subroutines of CreateBuiltinBinOp).
QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS,
ExprResult &RHS);
+ QualType InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS,
+ ExprResult &RHS);
QualType CheckPointerToMemberOperands( // C++ 5.5
ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK,
SourceLocation OpLoc, bool isIndirect);
@@ -9257,7 +9538,7 @@ public:
ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr,
CastKind &Kind);
- ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo,
+ ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, QualType Type,
SourceLocation LParenLoc,
Expr *CastExpr,
SourceLocation RParenLoc);
@@ -9265,14 +9546,14 @@ public:
enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error };
/// \brief Checks for invalid conversions and casts between
- /// retainable pointers and other pointer kinds.
- ARCConversionResult CheckObjCARCConversion(SourceRange castRange,
- QualType castType, Expr *&op,
- CheckedConversionKind CCK,
- bool Diagnose = true,
- bool DiagnoseCFAudited = false,
- BinaryOperatorKind Opc = BO_PtrMemD
- );
+ /// retainable pointers and other pointer kinds for ARC and Weak.
+ ARCConversionResult CheckObjCConversion(SourceRange castRange,
+ QualType castType, Expr *&op,
+ CheckedConversionKind CCK,
+ bool Diagnose = true,
+ bool DiagnoseCFAudited = false,
+ BinaryOperatorKind Opc = BO_PtrMemD
+ );
Expr *stripARCUnbridgedCast(Expr *e);
void diagnoseARCUnbridgedCast(Expr *e);
@@ -9777,6 +10058,8 @@ public:
void CodeCompletePostfixExpression(Scope *S, ExprResult LHS);
void CodeCompleteTag(Scope *S, unsigned TagSpec);
void CodeCompleteTypeQualifiers(DeclSpec &DS);
+ void CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D,
+ const VirtSpecifiers *VS = nullptr);
void CodeCompleteBracketDeclarator(Scope *S);
void CodeCompleteCase(Scope *S);
void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args);
@@ -9863,6 +10146,7 @@ public:
MacroInfo *MacroInfo,
unsigned Argument);
void CodeCompleteNaturalLanguage();
+ void CodeCompleteAvailabilityPlatformName();
void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
SmallVectorImpl<CodeCompletionResult> &Results);
@@ -9922,15 +10206,15 @@ private:
bool CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall);
+ bool CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, CallExpr *TheCall);
bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
- bool SemaBuiltinVAStartImpl(CallExpr *TheCall);
- bool SemaBuiltinVAStart(CallExpr *TheCall);
- bool SemaBuiltinMSVAStart(CallExpr *TheCall);
+ bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall);
bool SemaBuiltinVAStartARM(CallExpr *Call);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs);
+ bool SemaBuiltinVSX(CallExpr *TheCall);
bool SemaBuiltinOSLogFormat(CallExpr *TheCall);
public:
@@ -10028,6 +10312,11 @@ private:
void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field,
Expr *Init);
+ /// Check if there is a field shadowing.
+ void CheckShadowInheritedFields(const SourceLocation &Loc,
+ DeclarationName FieldName,
+ const CXXRecordDecl *RD);
+
/// \brief Check if the given expression contains 'break' or 'continue'
/// statement that produces control flow different from GCC.
void CheckBreakContinueBinding(Expr *E);
@@ -10134,17 +10423,6 @@ public:
return OriginalLexicalContext ? OriginalLexicalContext : CurContext;
}
- /// \brief The diagnostic we should emit for \c D, or \c AR_Available.
- ///
- /// \param D The declaration to check. Note that this may be altered to point
- /// to another declaration that \c D gets it's availability from. i.e., we
- /// walk the list of typedefs to find an availability attribute.
- ///
- /// \param Message If non-null, this will be populated with the message from
- /// the availability attribute that is selected.
- AvailabilityResult ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D,
- std::string *Message);
-
const DeclContext *getCurObjCLexicalContext() const {
const DeclContext *DC = getCurLexicalContext();
// A category implicitly has the attribute of the interface.
@@ -10221,6 +10499,7 @@ class EnterExpressionEvaluationContext {
bool Entered = true;
public:
+
EnterExpressionEvaluationContext(Sema &Actions,
Sema::ExpressionEvaluationContext NewContext,
Decl *LambdaContextDecl = nullptr,
@@ -10251,8 +10530,8 @@ public:
// a context.
if (ShouldEnter && Actions.isUnevaluatedContext() &&
Actions.getLangOpts().CPlusPlus11) {
- Actions.PushExpressionEvaluationContext(Sema::UnevaluatedList, nullptr,
- false);
+ Actions.PushExpressionEvaluationContext(
+ Sema::ExpressionEvaluationContext::UnevaluatedList, nullptr, false);
Entered = true;
}
}
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Template.h b/contrib/llvm/tools/clang/include/clang/Sema/Template.h
index 401bbbf..644d55b 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Template.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/Template.h
@@ -46,6 +46,10 @@ namespace clang {
/// \brief The template argument lists, stored from the innermost template
/// argument list (first) to the outermost template argument list (last).
SmallVector<ArgList, 4> TemplateArgumentLists;
+
+ /// \brief The number of outer levels of template arguments that are not
+ /// being substituted.
+ unsigned NumRetainedOuterLevels = 0;
public:
/// \brief Construct an empty set of template argument lists.
@@ -59,11 +63,19 @@ namespace clang {
/// \brief Determine the number of levels in this template argument
/// list.
- unsigned getNumLevels() const { return TemplateArgumentLists.size(); }
-
+ unsigned getNumLevels() const {
+ return TemplateArgumentLists.size() + NumRetainedOuterLevels;
+ }
+
+ /// \brief Determine the number of substituted levels in this template
+ /// argument list.
+ unsigned getNumSubstitutedLevels() const {
+ return TemplateArgumentLists.size();
+ }
+
/// \brief Retrieve the template argument at a given depth and index.
const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
- assert(Depth < TemplateArgumentLists.size());
+ assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
return TemplateArgumentLists[getNumLevels() - Depth - 1][Index];
}
@@ -73,7 +85,10 @@ namespace clang {
///
/// There must exist a template argument list at the given depth.
bool hasTemplateArgument(unsigned Depth, unsigned Index) const {
- assert(Depth < TemplateArgumentLists.size());
+ assert(Depth < getNumLevels());
+
+ if (Depth < NumRetainedOuterLevels)
+ return false;
if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size())
return false;
@@ -84,7 +99,7 @@ namespace clang {
/// \brief Clear out a specific template argument.
void setArgument(unsigned Depth, unsigned Index,
TemplateArgument Arg) {
- assert(Depth < TemplateArgumentLists.size());
+ assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
const_cast<TemplateArgument&>(
TemplateArgumentLists[getNumLevels() - Depth - 1][Index])
@@ -101,9 +116,18 @@ namespace clang {
/// \brief Add a new outmost level to the multi-level template argument
/// list.
void addOuterTemplateArguments(ArgList Args) {
+ assert(!NumRetainedOuterLevels &&
+ "substituted args outside retained args?");
TemplateArgumentLists.push_back(Args);
}
+ /// \brief Add an outermost level that we are not substituting. We have no
+ /// arguments at this level, and do not remove it from the depth of inner
+ /// template parameters that we instantiate.
+ void addOuterRetainedLevel() {
+ ++NumRetainedOuterLevels;
+ }
+
/// \brief Retrieve the innermost template argument list.
const ArgList &getInnermost() const {
return TemplateArgumentLists.front();
diff --git a/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h b/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h
index d92cbab..cd9ed6a 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h
+++ b/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h
@@ -88,6 +88,12 @@ public:
HasSFINAEDiagnostic = false;
}
+ /// Peek at the SFINAE diagnostic.
+ const PartialDiagnosticAt &peekSFINAEDiagnostic() const {
+ assert(HasSFINAEDiagnostic);
+ return SuppressedDiagnostics.front();
+ }
+
/// \brief Provide a new template argument list that contains the
/// results of template argument deduction.
void reset(TemplateArgumentList *NewDeduced) {
diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h
index acbd6d1..9227b33 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h
@@ -226,7 +226,7 @@ namespace clang {
/// \brief The block containing the detailed preprocessing record.
PREPROCESSOR_DETAIL_BLOCK_ID,
-
+
/// \brief The block containing the submodule structure.
SUBMODULE_BLOCK_ID,
@@ -253,6 +253,12 @@ namespace clang {
/// \brief A block containing a module file extension.
EXTENSION_BLOCK_ID,
+
+ /// A block with unhashed content.
+ ///
+ /// These records should not change the \a ASTFileSignature. See \a
+ /// UnhashedControlBlockRecordTypes for the list of records.
+ UNHASHED_CONTROL_BLOCK_ID,
};
/// \brief Record types that occur within the control block.
@@ -288,9 +294,6 @@ namespace clang {
/// AST file.
MODULE_MAP_FILE,
- /// \brief Record code for the signature that identifiers this AST file.
- SIGNATURE,
-
/// \brief Record code for the module build directory.
MODULE_DIRECTORY,
};
@@ -309,9 +312,6 @@ namespace clang {
/// \brief Record code for the target options table.
TARGET_OPTIONS,
- /// \brief Record code for the diagnostic options table.
- DIAGNOSTIC_OPTIONS,
-
/// \brief Record code for the filesystem options table.
FILE_SYSTEM_OPTIONS,
@@ -322,6 +322,18 @@ namespace clang {
PREPROCESSOR_OPTIONS,
};
+ /// Record codes for the unhashed control block.
+ enum UnhashedControlBlockRecordTypes {
+ /// Record code for the signature that identifiers this AST file.
+ SIGNATURE = 1,
+
+ /// Record code for the diagnostic options table.
+ DIAGNOSTIC_OPTIONS,
+
+ /// Record code for \#pragma diagnostic mappings.
+ DIAG_PRAGMA_MAPPINGS,
+ };
+
/// \brief Record code for extension blocks.
enum ExtensionBlockRecordTypes {
/// Metadata describing this particular extension.
@@ -493,8 +505,7 @@ namespace clang {
// ID 31 used to be a list of offsets to DECL_CXX_BASE_SPECIFIERS records.
- /// \brief Record code for \#pragma diagnostic mappings.
- DIAG_PRAGMA_MAPPINGS = 32,
+ // ID 32 used to be the code for \#pragma diagnostic mappings.
/// \brief Record code for special CUDA declarations.
CUDA_SPECIAL_DECL_REFS = 33,
@@ -591,6 +602,14 @@ namespace clang {
/// \brief Record code for declarations associated with OpenCL extensions.
OPENCL_EXTENSION_DECLS = 59,
+
+ MODULAR_CODEGEN_DECLS = 60,
+
+ /// \brief Record code for \#pragma pack options.
+ PACK_PRAGMA_OPTIONS = 61,
+
+ /// \brief The stack of open #ifs/#ifdefs recorded in a preamble.
+ PP_CONDITIONAL_STACK = 62,
};
/// \brief Record types used within a source manager block.
@@ -801,14 +820,12 @@ namespace clang {
PREDEF_TYPE_SAMPLER_ID = 39,
/// \brief OpenCL queue type.
PREDEF_TYPE_QUEUE_ID = 40,
- /// \brief OpenCL ndrange type.
- PREDEF_TYPE_NDRANGE_ID = 41,
/// \brief OpenCL reserve_id type.
- PREDEF_TYPE_RESERVE_ID_ID = 42,
+ PREDEF_TYPE_RESERVE_ID_ID = 41,
/// \brief The placeholder type for OpenMP array section.
- PREDEF_TYPE_OMP_ARRAY_SECTION = 43,
+ PREDEF_TYPE_OMP_ARRAY_SECTION = 42,
/// \brief The '__float128' type
- PREDEF_TYPE_FLOAT128_ID = 44,
+ PREDEF_TYPE_FLOAT128_ID = 43,
/// \brief OpenCL image types with auto numeration
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
PREDEF_TYPE_##Id##_ID,
@@ -914,7 +931,11 @@ namespace clang {
/// \brief A PipeType record.
TYPE_PIPE = 43,
/// \brief An ObjCTypeParamType record.
- TYPE_OBJC_TYPE_PARAM = 44
+ TYPE_OBJC_TYPE_PARAM = 44,
+ /// \brief A DeducedTemplateSpecializationType record.
+ TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45,
+ /// \brief A DependentSizedExtVectorType record.
+ TYPE_DEPENDENT_SIZED_EXT_VECTOR = 46
};
/// \brief The type IDs for special types constructed by semantic
@@ -1121,6 +1142,8 @@ namespace clang {
DECL_EXPORT,
/// \brief A CXXRecordDecl record.
DECL_CXX_RECORD,
+ /// \brief A CXXDeductionGuideDecl record.
+ DECL_CXX_DEDUCTION_GUIDE,
/// \brief A CXXMethodDecl record.
DECL_CXX_METHOD,
/// \brief A CXXConstructorDecl record.
@@ -1522,9 +1545,14 @@ namespace clang {
// ARC
EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr
-
+
STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt
- EXPR_LAMBDA // LambdaExpr
+ EXPR_LAMBDA, // LambdaExpr
+ STMT_COROUTINE_BODY,
+ STMT_CORETURN,
+ EXPR_COAWAIT,
+ EXPR_COYIELD,
+ EXPR_DEPENDENT_COAWAIT,
};
/// \brief The kinds of designators that can occur in a
@@ -1624,7 +1652,8 @@ namespace clang {
IdentifierInfo *getIdentifier() const {
assert(Kind == DeclarationName::Identifier ||
- Kind == DeclarationName::CXXLiteralOperatorName);
+ Kind == DeclarationName::CXXLiteralOperatorName ||
+ Kind == DeclarationName::CXXDeductionGuideName);
return (IdentifierInfo *)Data;
}
Selector getSelector() const {
diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h
index 4b10c39..c26f3e0 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h
+++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h
@@ -26,6 +26,7 @@ class QualType;
class MacroDefinitionRecord;
class MacroInfo;
class Module;
+class SourceLocation;
class ASTDeserializationListener {
public:
@@ -52,6 +53,9 @@ public:
MacroDefinitionRecord *MD) {}
/// \brief A module definition was read from the AST file.
virtual void ModuleRead(serialization::SubmoduleID ID, Module *Mod) {}
+ /// \brief A module import was read from the AST file.
+ virtual void ModuleImportRead(serialization::SubmoduleID ID,
+ SourceLocation ImportLoc) {}
};
}
diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h
index 93994e2..eafa051 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h
+++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h
@@ -400,7 +400,7 @@ private:
Preprocessor &PP;
/// \brief The AST context into which we'll read the AST files.
- ASTContext &Context;
+ ASTContext *ContextObj = nullptr;
/// \brief The AST consumer.
ASTConsumer *Consumer = nullptr;
@@ -408,6 +408,9 @@ private:
/// \brief The module manager which manages modules and their dependencies
ModuleManager ModuleMgr;
+ /// The cache that manages memory buffers for PCM files.
+ MemoryBufferCache &PCMCache;
+
/// \brief A dummy identifier resolver used to merge TU-scope declarations in
/// C, for the cases where we don't have a Sema object to provide a real
/// identifier resolver.
@@ -475,10 +478,18 @@ private:
/// in the chain.
DeclUpdateOffsetsMap DeclUpdateOffsets;
+ struct PendingUpdateRecord {
+ Decl *D;
+ serialization::GlobalDeclID ID;
+ // Whether the declaration was just deserialized.
+ bool JustLoaded;
+ PendingUpdateRecord(serialization::GlobalDeclID ID, Decl *D,
+ bool JustLoaded)
+ : D(D), ID(ID), JustLoaded(JustLoaded) {}
+ };
/// \brief Declaration updates for already-loaded declarations that we need
/// to apply once we finish processing an import.
- llvm::SmallVector<std::pair<serialization::GlobalDeclID, Decl*>, 16>
- PendingUpdateRecords;
+ llvm::SmallVector<PendingUpdateRecord, 16> PendingUpdateRecords;
enum class PendingFakeDefinitionKind { NotFake, Fake, FakeLoaded };
@@ -700,7 +711,7 @@ private:
/// \brief Mapping from global preprocessing entity IDs to the module in
/// which the preprocessed entity resides along with the offset that should be
- /// added to the global preprocessing entitiy ID to produce a local ID.
+ /// added to the global preprocessing entity ID to produce a local ID.
GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap;
/// \name CodeGen-relevant special data
@@ -808,6 +819,17 @@ private:
int PragmaMSPointersToMembersState = -1;
SourceLocation PointersToMembersPragmaLocation;
+ /// \brief The pragma pack state.
+ Optional<unsigned> PragmaPackCurrentValue;
+ SourceLocation PragmaPackCurrentLocation;
+ struct PragmaPackStackEntry {
+ unsigned Value;
+ SourceLocation Location;
+ StringRef SlotLabel;
+ };
+ llvm::SmallVector<PragmaPackStackEntry, 2> PragmaPackStack;
+ llvm::SmallVector<std::string, 2> PragmaPackStrings;
+
/// \brief The OpenCL extension settings.
OpenCLOptions OpenCLExtensions;
@@ -970,14 +992,26 @@ private:
/// \brief The generation number of each identifier, which keeps track of
/// the last time we loaded information about this identifier.
llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration;
-
- /// \brief Contains declarations and definitions that will be
+
+ class InterestingDecl {
+ Decl *D;
+ bool DeclHasPendingBody;
+
+ public:
+ InterestingDecl(Decl *D, bool HasBody)
+ : D(D), DeclHasPendingBody(HasBody) {}
+ Decl *getDecl() { return D; }
+ /// Whether the declaration has a pending body.
+ bool hasPendingBody() { return DeclHasPendingBody; }
+ };
+
+ /// \brief Contains declarations and definitions that could be
/// "interesting" to the ASTConsumer, when we get that AST consumer.
///
/// "Interesting" declarations are those that have data that may
/// need to be emitted, such as inline function definitions or
/// Objective-C protocols.
- std::deque<Decl *> InterestingDecls;
+ std::deque<InterestingDecl> PotentiallyInterestingDecls;
/// \brief The list of redeclaration chains that still need to be
/// reconstructed, and the local offset to the corresponding list
@@ -1101,6 +1135,8 @@ private:
/// predefines buffer may contain additional definitions.
std::string SuggestedPredefines;
+ llvm::DenseMap<const Decl *, bool> BodySource;
+
/// \brief Reads a statement from the specified cursor.
Stmt *ReadStmtFromStream(ModuleFile &F);
@@ -1110,6 +1146,7 @@ private:
time_t StoredTime;
bool Overridden;
bool Transient;
+ bool TopLevelModuleMap;
};
/// \brief Reads the stored information about an input file.
@@ -1174,7 +1211,7 @@ private:
SourceLocation ImportLoc, ModuleFile *ImportedBy,
SmallVectorImpl<ImportedModule> &Loaded,
off_t ExpectedSize, time_t ExpectedModTime,
- serialization::ASTFileSignature ExpectedSignature,
+ ASTFileSignature ExpectedSignature,
unsigned ClientLoadCapabilities);
ASTReadResult ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
@@ -1183,9 +1220,25 @@ private:
static ASTReadResult ReadOptionsBlock(
llvm::BitstreamCursor &Stream, unsigned ClientLoadCapabilities,
bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener,
- std::string &SuggestedPredefines, bool ValidateDiagnosticOptions);
+ std::string &SuggestedPredefines);
+
+ /// Read the unhashed control block.
+ ///
+ /// This has no effect on \c F.Stream, instead creating a fresh cursor from
+ /// \c F.Data and reading ahead.
+ ASTReadResult readUnhashedControlBlock(ModuleFile &F, bool WasImportedBy,
+ unsigned ClientLoadCapabilities);
+
+ static ASTReadResult
+ readUnhashedControlBlockImpl(ModuleFile *F, llvm::StringRef StreamData,
+ unsigned ClientLoadCapabilities,
+ bool AllowCompatibleConfigurationMismatch,
+ ASTReaderListener *Listener,
+ bool ValidateDiagnosticOptions);
+
ASTReadResult ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities);
ASTReadResult ReadExtensionBlock(ModuleFile &F);
+ void ReadModuleOffsetMap(ModuleFile &F) const;
bool ParseLineTable(ModuleFile &F, const RecordData &Record);
bool ReadSourceManagerBlock(ModuleFile &F);
llvm::BitstreamCursor &SLocCursorForID(int ID);
@@ -1235,7 +1288,7 @@ private:
RecordLocation DeclCursorForID(serialization::DeclID ID,
SourceLocation &Location);
- void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
+ void loadDeclUpdateRecords(PendingUpdateRecord &Record);
void loadPendingDeclChain(Decl *D, uint64_t LocalOffset);
void loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D,
unsigned PreviousGeneration = 0);
@@ -1268,6 +1321,7 @@ private:
llvm::iterator_range<PreprocessingRecord::iterator>
getModulePreprocessedEntities(ModuleFile &Mod) const;
+public:
class ModuleDeclIterator
: public llvm::iterator_adaptor_base<
ModuleDeclIterator, const serialization::LocalDeclID *,
@@ -1298,6 +1352,7 @@ private:
llvm::iterator_range<ModuleDeclIterator>
getModuleFileLevelDecls(ModuleFile &Mod);
+private:
void PassInterestingDeclsToConsumer();
void PassInterestingDeclToConsumer(Decl *D);
@@ -1318,9 +1373,9 @@ private:
///
/// This routine should only be used for fatal errors that have to
/// do with non-routine failures (e.g., corrupted AST file).
- void Error(StringRef Msg);
+ void Error(StringRef Msg) const;
void Error(unsigned DiagID, StringRef Arg1 = StringRef(),
- StringRef Arg2 = StringRef());
+ StringRef Arg2 = StringRef()) const;
ASTReader(const ASTReader &) = delete;
void operator=(const ASTReader &) = delete;
@@ -1332,7 +1387,7 @@ public:
/// precompiled header will be loaded.
///
/// \param Context the AST context that this precompiled header will be
- /// loaded into.
+ /// loaded into, if any.
///
/// \param PCHContainerRdr the PCHContainerOperations to use for loading and
/// creating modules.
@@ -1364,7 +1419,7 @@ public:
///
/// \param ReadTimer If non-null, a timer used to track the time spent
/// deserializing.
- ASTReader(Preprocessor &PP, ASTContext &Context,
+ ASTReader(Preprocessor &PP, ASTContext *Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
StringRef isysroot = "", bool DisableValidation = false,
@@ -1564,7 +1619,7 @@ public:
const LangOptions &LangOpts,
const TargetOptions &TargetOpts,
const PreprocessorOptions &PPOpts,
- std::string ExistingModuleCachePath);
+ StringRef ExistingModuleCachePath);
/// \brief Returns the suggested contents of the predefines buffer,
/// which contains a (typically-empty) subset of the predefines
@@ -1631,11 +1686,8 @@ public:
/// reader.
unsigned getTotalNumPreprocessedEntities() const {
unsigned Result = 0;
- for (ModuleConstIterator I = ModuleMgr.begin(),
- E = ModuleMgr.end(); I != E; ++I) {
- Result += (*I)->NumPreprocessedEntities;
- }
-
+ for (const auto &M : ModuleMgr)
+ Result += M.NumPreprocessedEntities;
return Result;
}
@@ -1904,10 +1956,10 @@ public:
SmallVectorImpl<Decl *> *Decls = nullptr);
/// \brief Report a diagnostic.
- DiagnosticBuilder Diag(unsigned DiagID);
+ DiagnosticBuilder Diag(unsigned DiagID) const;
/// \brief Report a diagnostic.
- DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const;
IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID);
@@ -1968,6 +2020,8 @@ public:
/// \brief Return a descriptor for the corresponding module.
llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
+ ExtKind hasExternalDefinitions(const Decl *D) override;
+
/// \brief Retrieve a selector from the given module with its local ID
/// number.
Selector getLocalSelector(ModuleFile &M, unsigned LocalID);
@@ -2057,6 +2111,8 @@ public:
/// location space into ours.
SourceLocation TranslateSourceLocation(ModuleFile &ModuleFile,
SourceLocation Loc) const {
+ if (!ModuleFile.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(ModuleFile);
assert(ModuleFile.SLocRemap.find(Loc.getOffset()) !=
ModuleFile.SLocRemap.end() &&
"Cannot find offset to remap.");
@@ -2098,8 +2154,7 @@ public:
unsigned &Idx);
/// \brief Reads attributes from the current stream position.
- void ReadAttributes(ModuleFile &F, AttrVec &Attrs,
- const RecordData &Record, unsigned &Idx);
+ void ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs);
/// \brief Reads a statement.
Stmt *ReadStmt(ModuleFile &F);
@@ -2153,7 +2208,10 @@ public:
void completeVisibleDeclsMap(const DeclContext *DC) override;
/// \brief Retrieve the AST context that this AST reader supplements.
- ASTContext &getContext() { return Context; }
+ ASTContext &getContext() {
+ assert(ContextObj && "requested AST context when not loading AST");
+ return *ContextObj;
+ }
// \brief Contains the IDs for declarations that were requested before we have
// access to a Sema object.
@@ -2189,6 +2247,18 @@ public:
/// \brief Loads comments ranges.
void ReadComments() override;
+ /// Visit all the input files of the given module file.
+ void visitInputFiles(serialization::ModuleFile &MF,
+ bool IncludeSystem, bool Complain,
+ llvm::function_ref<void(const serialization::InputFile &IF,
+ bool isSystem)> Visitor);
+
+ /// Visit all the top-level module maps loaded when building the given module
+ /// file.
+ void visitTopLevelModuleMaps(serialization::ModuleFile &MF,
+ llvm::function_ref<
+ void(const FileEntry *)> Visitor);
+
bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; }
};
@@ -2284,6 +2354,14 @@ public:
/// \brief Reads a sub-expression operand during statement reading.
Expr *readSubExpr() { return Reader->ReadSubExpr(); }
+ /// \brief Reads a declaration with the given local ID in the given module.
+ ///
+ /// \returns The requested declaration, casted to the given return type.
+ template<typename T>
+ T *GetLocalDeclAs(uint32_t LocalID) {
+ return cast_or_null<T>(Reader->GetLocalDecl(*F, LocalID));
+ }
+
/// \brief Reads a TemplateArgumentLocInfo appropriate for the
/// given TemplateArgument kind, advancing Idx.
TemplateArgumentLocInfo
@@ -2455,7 +2533,7 @@ public:
/// \brief Reads attributes from the current stream position, advancing Idx.
void readAttributes(AttrVec &Attrs) {
- return Reader->ReadAttributes(*F, Attrs, Record, Idx);
+ return Reader->ReadAttributes(*this, Attrs);
}
/// \brief Reads a token out of a record, advancing Idx.
diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h
index 0d6b026..f14dfc7 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h
+++ b/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h
@@ -54,6 +54,7 @@ class MacroInfo;
class OpaqueValueExpr;
class OpenCLOptions;
class ASTReader;
+class MemoryBufferCache;
class Module;
class ModuleFileExtension;
class ModuleFileExtensionWriter;
@@ -106,6 +107,12 @@ private:
/// \brief The bitstream writer used to emit this precompiled header.
llvm::BitstreamWriter &Stream;
+ /// The buffer associated with the bitstream.
+ const SmallVectorImpl<char> &Buffer;
+
+ /// \brief The PCM manager which manages memory buffers for pcm files.
+ MemoryBufferCache &PCMCache;
+
/// \brief The ASTContext we're writing.
ASTContext *Context = nullptr;
@@ -365,6 +372,7 @@ private:
/// IDs, since they will be written out to an EAGERLY_DESERIALIZED_DECLS
/// record.
SmallVector<uint64_t, 16> EagerlyDeserializedDecls;
+ SmallVector<uint64_t, 16> ModularCodegenDecls;
/// \brief DeclContexts that have received extensions since their serialized
/// form.
@@ -424,8 +432,16 @@ private:
void WriteSubStmt(Stmt *S);
void WriteBlockInfoBlock();
- uint64_t WriteControlBlock(Preprocessor &PP, ASTContext &Context,
- StringRef isysroot, const std::string &OutputFile);
+ void WriteControlBlock(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot, const std::string &OutputFile);
+
+ /// Write out the signature and diagnostic options, and return the signature.
+ ASTFileSignature writeUnhashedControlBlock(Preprocessor &PP,
+ ASTContext &Context);
+
+ /// Calculate hash of the pcm content.
+ static ASTFileSignature createSignature(StringRef Bytes);
+
void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts,
bool Modules);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
@@ -469,6 +485,7 @@ private:
void WriteOptimizePragmaOptions(Sema &SemaRef);
void WriteMSStructPragmaOptions(Sema &SemaRef);
void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef);
+ void WritePackPragmaOptions(Sema &SemaRef);
void WriteModuleFileExtension(Sema &SemaRef,
ModuleFileExtensionWriter &Writer);
@@ -492,14 +509,15 @@ private:
void WriteDeclAbbrevs();
void WriteDecl(ASTContext &Context, Decl *D);
- uint64_t WriteASTCore(Sema &SemaRef,
- StringRef isysroot, const std::string &OutputFile,
- Module *WritingModule);
+ ASTFileSignature WriteASTCore(Sema &SemaRef, StringRef isysroot,
+ const std::string &OutputFile,
+ Module *WritingModule);
public:
/// \brief Create a new precompiled header writer that outputs to
/// the given bitstream.
- ASTWriter(llvm::BitstreamWriter &Stream,
+ ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl<char> &Buffer,
+ MemoryBufferCache &PCMCache,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
bool IncludeTimestamps = true);
~ASTWriter() override;
@@ -525,9 +543,9 @@ public:
///
/// \return the module signature, which eventually will be a hash of
/// the module but currently is merely a random 32-bit number.
- uint64_t WriteAST(Sema &SemaRef, const std::string &OutputFile,
- Module *WritingModule, StringRef isysroot,
- bool hasErrors = false);
+ ASTFileSignature WriteAST(Sema &SemaRef, const std::string &OutputFile,
+ Module *WritingModule, StringRef isysroot,
+ bool hasErrors = false);
/// \brief Emit a token.
void AddToken(const Token &Tok, RecordDataImpl &Record);
@@ -609,10 +627,6 @@ public:
/// \brief Add a version tuple to the given record
void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record);
- /// \brief Infer the submodule ID that contains an entity at the given
- /// source location.
- serialization::SubmoduleID inferSubmoduleIDFromLocation(SourceLocation Loc);
-
/// \brief Retrieve or create a submodule ID for this module, or return 0 if
/// the submodule is neither local (a submodle of the currently-written module)
/// nor from an imported module.
diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/Module.h b/contrib/llvm/tools/clang/include/clang/Serialization/Module.h
index 58b3149..4e4bf44 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/Module.h
+++ b/contrib/llvm/tools/clang/include/clang/Serialization/Module.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_SERIALIZATION_MODULE_H
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ContinuousRangeMap.h"
@@ -89,8 +90,6 @@ public:
bool isNotFound() const { return Val.getInt() == NotFound; }
};
-typedef unsigned ASTFileSignature;
-
/// \brief Information about a module that has been loaded by the ASTReader.
///
/// Each instance of the Module class corresponds to a single AST file, which
@@ -100,13 +99,14 @@ typedef unsigned ASTFileSignature;
/// other modules.
class ModuleFile {
public:
- ModuleFile(ModuleKind Kind, unsigned Generation);
+ ModuleFile(ModuleKind Kind, unsigned Generation)
+ : Kind(Kind), Generation(Generation) {}
~ModuleFile();
// === General information ===
/// \brief The index of this module in the list of modules.
- unsigned Index;
+ unsigned Index = 0;
/// \brief The type of this module.
ModuleKind Kind;
@@ -144,34 +144,34 @@ public:
std::string ModuleMapPath;
/// \brief Whether this precompiled header is a relocatable PCH file.
- bool RelocatablePCH;
+ bool RelocatablePCH = false;
/// \brief Whether timestamps are included in this module file.
- bool HasTimestamps;
+ bool HasTimestamps = false;
/// \brief The file entry for the module file.
- const FileEntry *File;
+ const FileEntry *File = nullptr;
- /// \brief The signature of the module file, which may be used along with size
+ /// The signature of the module file, which may be used instead of the size
/// and modification time to identify this particular file.
ASTFileSignature Signature;
/// \brief Whether this module has been directly imported by the
/// user.
- bool DirectlyImported;
+ bool DirectlyImported = false;
/// \brief The generation of which this module file is a part.
unsigned Generation;
- /// \brief The memory buffer that stores the data associated with
- /// this AST file.
- std::unique_ptr<llvm::MemoryBuffer> Buffer;
+ /// The memory buffer that stores the data associated with
+ /// this AST file, owned by the PCMCache in the ModuleManager.
+ llvm::MemoryBuffer *Buffer;
/// \brief The size of this file, in bits.
- uint64_t SizeInBits;
+ uint64_t SizeInBits = 0;
/// \brief The global bit offset (or base) of this module
- uint64_t GlobalBitOffset;
+ uint64_t GlobalBitOffset = 0;
/// \brief The serialized bitstream data for this file.
StringRef Data;
@@ -200,21 +200,29 @@ public:
/// file.
std::vector<std::unique_ptr<ModuleFileExtensionReader>> ExtensionReaders;
+ /// The module offset map data for this file. If non-empty, the various
+ /// ContinuousRangeMaps described below have not yet been populated.
+ StringRef ModuleOffsetMap;
+
// === Input Files ===
/// \brief The cursor to the start of the input-files block.
llvm::BitstreamCursor InputFilesCursor;
/// \brief Offsets for all of the input file entries in the AST file.
- const llvm::support::unaligned_uint64_t *InputFileOffsets;
+ const llvm::support::unaligned_uint64_t *InputFileOffsets = nullptr;
/// \brief The input files that have been loaded from this AST file.
std::vector<InputFile> InputFilesLoaded;
+ // All user input files reside at the index range [0, NumUserInputFiles), and
+ // system input files reside at [NumUserInputFiles, InputFilesLoaded.size()).
+ unsigned NumUserInputFiles = 0;
+
/// \brief If non-zero, specifies the time when we last validated input
/// files. Zero means we never validated them.
///
/// The time is specified in seconds since the start of the Epoch.
- uint64_t InputFilesValidationTimestamp;
+ uint64_t InputFilesValidationTimestamp = 0;
// === Source Locations ===
@@ -222,17 +230,17 @@ public:
llvm::BitstreamCursor SLocEntryCursor;
/// \brief The number of source location entries in this AST file.
- unsigned LocalNumSLocEntries;
+ unsigned LocalNumSLocEntries = 0;
/// \brief The base ID in the source manager's view of this module.
- int SLocEntryBaseID;
+ int SLocEntryBaseID = 0;
/// \brief The base offset in the source manager's view of this module.
- unsigned SLocEntryBaseOffset;
+ unsigned SLocEntryBaseOffset = 0;
/// \brief Offsets for all of the source location entries in the
/// AST file.
- const uint32_t *SLocEntryOffsets;
+ const uint32_t *SLocEntryOffsets = nullptr;
/// \brief SLocEntries that we're going to preload.
SmallVector<uint64_t, 4> PreloadSLocEntries;
@@ -243,17 +251,17 @@ public:
// === Identifiers ===
/// \brief The number of identifiers in this AST file.
- unsigned LocalNumIdentifiers;
+ unsigned LocalNumIdentifiers = 0;
/// \brief Offsets into the identifier table data.
///
/// This array is indexed by the identifier ID (-1), and provides
/// the offset into IdentifierTableData where the string data is
/// stored.
- const uint32_t *IdentifierOffsets;
+ const uint32_t *IdentifierOffsets = nullptr;
/// \brief Base identifier ID for identifiers local to this module.
- serialization::IdentID BaseIdentifierID;
+ serialization::IdentID BaseIdentifierID = 0;
/// \brief Remapping table for identifier IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> IdentifierRemap;
@@ -262,11 +270,11 @@ public:
///
/// This pointer points into a memory buffer, where the on-disk hash
/// table for identifiers actually lives.
- const char *IdentifierTableData;
+ const char *IdentifierTableData = nullptr;
/// \brief A pointer to an on-disk hash table of opaque type
/// IdentifierHashTable.
- void *IdentifierLookupTable;
+ void *IdentifierLookupTable = nullptr;
/// \brief Offsets of identifiers that we're going to preload within
/// IdentifierTableData.
@@ -279,23 +287,23 @@ public:
llvm::BitstreamCursor MacroCursor;
/// \brief The number of macros in this AST file.
- unsigned LocalNumMacros;
+ unsigned LocalNumMacros = 0;
/// \brief Offsets of macros in the preprocessor block.
///
/// This array is indexed by the macro ID (-1), and provides
/// the offset into the preprocessor block where macro definitions are
/// stored.
- const uint32_t *MacroOffsets;
+ const uint32_t *MacroOffsets = nullptr;
/// \brief Base macro ID for macros local to this module.
- serialization::MacroID BaseMacroID;
+ serialization::MacroID BaseMacroID = 0;
/// \brief Remapping table for macro IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> MacroRemap;
/// \brief The offset of the start of the set of defined macros.
- uint64_t MacroStartOffset;
+ uint64_t MacroStartOffset = 0;
// === Detailed PreprocessingRecord ===
@@ -304,40 +312,40 @@ public:
llvm::BitstreamCursor PreprocessorDetailCursor;
/// \brief The offset of the start of the preprocessor detail cursor.
- uint64_t PreprocessorDetailStartOffset;
+ uint64_t PreprocessorDetailStartOffset = 0;
/// \brief Base preprocessed entity ID for preprocessed entities local to
/// this module.
- serialization::PreprocessedEntityID BasePreprocessedEntityID;
+ serialization::PreprocessedEntityID BasePreprocessedEntityID = 0;
/// \brief Remapping table for preprocessed entity IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> PreprocessedEntityRemap;
- const PPEntityOffset *PreprocessedEntityOffsets;
- unsigned NumPreprocessedEntities;
+ const PPEntityOffset *PreprocessedEntityOffsets = nullptr;
+ unsigned NumPreprocessedEntities = 0;
// === Header search information ===
/// \brief The number of local HeaderFileInfo structures.
- unsigned LocalNumHeaderFileInfos;
+ unsigned LocalNumHeaderFileInfos = 0;
/// \brief Actual data for the on-disk hash table of header file
/// information.
///
/// This pointer points into a memory buffer, where the on-disk hash
/// table for header file information actually lives.
- const char *HeaderFileInfoTableData;
+ const char *HeaderFileInfoTableData = nullptr;
/// \brief The on-disk hash table that contains information about each of
/// the header files.
- void *HeaderFileInfoTable;
+ void *HeaderFileInfoTable = nullptr;
// === Submodule information ===
/// \brief The number of submodules in this module.
- unsigned LocalNumSubmodules;
+ unsigned LocalNumSubmodules = 0;
/// \brief Base submodule ID for submodules local to this module.
- serialization::SubmoduleID BaseSubmoduleID;
+ serialization::SubmoduleID BaseSubmoduleID = 0;
/// \brief Remapping table for submodule IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> SubmoduleRemap;
@@ -347,14 +355,14 @@ public:
/// \brief The number of selectors new to this file.
///
/// This is the number of entries in SelectorOffsets.
- unsigned LocalNumSelectors;
+ unsigned LocalNumSelectors = 0;
/// \brief Offsets into the selector lookup table's data array
/// where each selector resides.
- const uint32_t *SelectorOffsets;
+ const uint32_t *SelectorOffsets = nullptr;
/// \brief Base selector ID for selectors local to this module.
- serialization::SelectorID BaseSelectorID;
+ serialization::SelectorID BaseSelectorID = 0;
/// \brief Remapping table for selector IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> SelectorRemap;
@@ -362,14 +370,14 @@ public:
/// \brief A pointer to the character data that comprises the selector table
///
/// The SelectorOffsets table refers into this memory.
- const unsigned char *SelectorLookupTableData;
+ const unsigned char *SelectorLookupTableData = nullptr;
/// \brief A pointer to an on-disk hash table of opaque type
/// ASTSelectorLookupTable.
///
/// This hash table provides the IDs of all selectors, and the associated
/// instance and factory methods.
- void *SelectorLookupTable;
+ void *SelectorLookupTable = nullptr;
// === Declarations ===
@@ -379,14 +387,14 @@ public:
llvm::BitstreamCursor DeclsCursor;
/// \brief The number of declarations in this AST file.
- unsigned LocalNumDecls;
+ unsigned LocalNumDecls = 0;
/// \brief Offset of each declaration within the bitstream, indexed
/// by the declaration ID (-1).
- const DeclOffset *DeclOffsets;
+ const DeclOffset *DeclOffsets = nullptr;
/// \brief Base declaration ID for declarations local to this module.
- serialization::DeclID BaseDeclID;
+ serialization::DeclID BaseDeclID = 0;
/// \brief Remapping table for declaration IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> DeclRemap;
@@ -401,15 +409,15 @@ public:
llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs;
/// \brief Array of file-level DeclIDs sorted by file.
- const serialization::DeclID *FileSortedDecls;
- unsigned NumFileSortedDecls;
+ const serialization::DeclID *FileSortedDecls = nullptr;
+ unsigned NumFileSortedDecls = 0;
/// \brief Array of category list location information within this
/// module file, sorted by the definition ID.
- const serialization::ObjCCategoriesInfo *ObjCCategoriesMap;
+ const serialization::ObjCCategoriesInfo *ObjCCategoriesMap = nullptr;
/// \brief The number of redeclaration info entries in ObjCCategoriesMap.
- unsigned LocalNumObjCCategoriesInMap;
+ unsigned LocalNumObjCCategoriesInMap = 0;
/// \brief The Objective-C category lists for categories known to this
/// module.
@@ -418,15 +426,15 @@ public:
// === Types ===
/// \brief The number of types in this AST file.
- unsigned LocalNumTypes;
+ unsigned LocalNumTypes = 0;
/// \brief Offset of each type within the bitstream, indexed by the
/// type ID, or the representation of a Type*.
- const uint32_t *TypeOffsets;
+ const uint32_t *TypeOffsets = nullptr;
/// \brief Base type ID for types local to this module as represented in
/// the global type ID space.
- serialization::TypeID BaseTypeIndex;
+ serialization::TypeID BaseTypeIndex = 0;
/// \brief Remapping table for type IDs in this module.
ContinuousRangeMap<uint32_t, int, 2> TypeRemap;
diff --git a/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h b/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h
index 1c4d88e..fae387c 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h
+++ b/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h
@@ -19,10 +19,12 @@
#include "clang/Serialization/Module.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/iterator.h"
namespace clang {
class GlobalModuleIndex;
+class MemoryBufferCache;
class ModuleMap;
class PCHContainerReader;
@@ -32,7 +34,7 @@ namespace serialization {
class ModuleManager {
/// \brief The chain of AST files, in the order in which we started to load
/// them (this order isn't really useful for anything).
- SmallVector<ModuleFile *, 2> Chain;
+ SmallVector<std::unique_ptr<ModuleFile>, 2> Chain;
/// \brief The chain of non-module PCH files. The first entry is the one named
/// by the user, the last one is the one that doesn't depend on anything
@@ -50,6 +52,9 @@ class ModuleManager {
/// FileEntry *.
FileManager &FileMgr;
+ /// Cache of PCM files.
+ IntrusiveRefCntPtr<MemoryBufferCache> PCMCache;
+
/// \brief Knows how to unwrap module containers.
const PCHContainerReader &PCHContainerRdr;
@@ -111,12 +116,18 @@ class ModuleManager {
void returnVisitState(VisitState *State);
public:
- typedef SmallVectorImpl<ModuleFile*>::iterator ModuleIterator;
- typedef SmallVectorImpl<ModuleFile*>::const_iterator ModuleConstIterator;
- typedef SmallVectorImpl<ModuleFile*>::reverse_iterator ModuleReverseIterator;
+ typedef llvm::pointee_iterator<
+ SmallVectorImpl<std::unique_ptr<ModuleFile>>::iterator>
+ ModuleIterator;
+ typedef llvm::pointee_iterator<
+ SmallVectorImpl<std::unique_ptr<ModuleFile>>::const_iterator>
+ ModuleConstIterator;
+ typedef llvm::pointee_iterator<
+ SmallVectorImpl<std::unique_ptr<ModuleFile>>::reverse_iterator>
+ ModuleReverseIterator;
typedef std::pair<uint32_t, StringRef> ModuleOffset;
- explicit ModuleManager(FileManager &FileMgr,
+ explicit ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache,
const PCHContainerReader &PCHContainerRdr);
~ModuleManager();
@@ -136,7 +147,8 @@ public:
ModuleReverseIterator rend() { return Chain.rend(); }
/// \brief A range covering the PCH and preamble module files loaded.
- llvm::iterator_range<ModuleConstIterator> pch_modules() const {
+ llvm::iterator_range<SmallVectorImpl<ModuleFile *>::const_iterator>
+ pch_modules() const {
return llvm::make_range(PCHChain.begin(), PCHChain.end());
}
@@ -152,10 +164,10 @@ public:
ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; }
/// \brief Returns the module associated with the given name
- ModuleFile *lookup(StringRef Name);
+ ModuleFile *lookup(StringRef Name) const;
/// \brief Returns the module associated with the given module file.
- ModuleFile *lookup(const FileEntry *File);
+ ModuleFile *lookup(const FileEntry *File) const;
/// \brief Returns the in-memory (virtual file) buffer with the given name
std::unique_ptr<llvm::MemoryBuffer> lookupBuffer(StringRef Name);
@@ -220,8 +232,8 @@ public:
ModuleFile *&Module,
std::string &ErrorStr);
- /// \brief Remove the given set of modules.
- void removeModules(ModuleIterator first, ModuleIterator last,
+ /// \brief Remove the modules starting from First (to the end).
+ void removeModules(ModuleIterator First,
llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
ModuleMap *modMap);
@@ -282,6 +294,8 @@ public:
/// \brief View the graphviz representation of the module graph.
void viewGraph();
+
+ MemoryBufferCache &getPCMCache() const { return *PCMCache; }
};
} } // end namespace clang::serialization
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 6957891..82ab720 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -38,6 +38,11 @@ def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden;
// default. Such checkers belong in the alpha package.
def OptIn : Package<"optin">;
+// In the Portability package reside checkers for finding code that relies on
+// implementation-defined behavior. Such checks are wanted for cross-platform
+// development, but unwanted for developers who target only a single platform.
+def PortabilityOptIn : Package<"portability">, InPackage<OptIn>;
+
def Nullability : Package<"nullability">;
def Cplusplus : Package<"cplusplus">;
@@ -45,7 +50,6 @@ def CplusplusAlpha : Package<"cplusplus">, InPackage<Alpha>, Hidden;
def CplusplusOptIn : Package<"cplusplus">, InPackage<OptIn>;
def Valist : Package<"valist">;
-def ValistAlpha : Package<"valist">, InPackage<Alpha>, Hidden;
def DeadCode : Package<"deadcode">;
def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
@@ -280,9 +284,14 @@ def VirtualCallChecker : Checker<"VirtualCall">,
let ParentPackage = CplusplusAlpha in {
-def IteratorPastEndChecker : Checker<"IteratorPastEnd">,
- HelpText<"Check iterators used past end">,
- DescFile<"IteratorPastEndChecker.cpp">;
+def IteratorRangeChecker : Checker<"IteratorRange">,
+ HelpText<"Check for iterators used outside their valid ranges">,
+ DescFile<"IteratorChecker.cpp">;
+
+def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">,
+ HelpText<"Method calls on a moved-from object and copying a moved-from "
+ "object will be reported">,
+ DescFile<"MisusedMovedObjectChecker.cpp">;
} // end: "alpha.cplusplus"
@@ -291,7 +300,7 @@ def IteratorPastEndChecker : Checker<"IteratorPastEnd">,
// Valist checkers.
//===----------------------------------------------------------------------===//
-let ParentPackage = ValistAlpha in {
+let ParentPackage = Valist in {
def UninitializedChecker : Checker<"Uninitialized">,
HelpText<"Check for usages of uninitialized (or already released) va_lists.">,
@@ -305,7 +314,7 @@ def CopyToSelfChecker : Checker<"CopyToSelf">,
HelpText<"Check for va_lists which are copied onto itself.">,
DescFile<"ValistChecker.cpp">;
-} // end : "alpha.valist"
+} // end : "valist"
//===----------------------------------------------------------------------===//
// Deadcode checkers.
@@ -412,7 +421,7 @@ def GenericTaintChecker : Checker<"TaintPropagation">,
let ParentPackage = Unix in {
-def UnixAPIChecker : Checker<"API">,
+def UnixAPIMisuseChecker : Checker<"API">,
HelpText<"Check calls to various UNIX/Posix functions">,
DescFile<"UnixAPIChecker.cpp">;
@@ -750,3 +759,14 @@ def CloneChecker : Checker<"CloneChecker">,
} // end "clone"
+//===----------------------------------------------------------------------===//
+// Portability checkers.
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = PortabilityOptIn in {
+
+def UnixAPIPortabilityChecker : Checker<"UnixAPI">,
+ HelpText<"Finds implementation-defined behavior in UNIX/Posix functions">,
+ DescFile<"UnixAPIChecker.cpp">;
+
+} // end optin.portability
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def
index 3355f4b..04bf41b 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def
@@ -22,6 +22,7 @@ ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateR
#endif
ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager)
+ANALYSIS_CONSTRAINTS(Z3Constraints, "z3", "Use Z3 contraint solver", CreateZ3ConstraintManager)
#ifndef ANALYSIS_DIAGNOSTICS
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN)
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index 4fb50de..5dd6bdf 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -205,9 +205,15 @@ private:
/// Controls which C++ member functions will be considered for inlining.
CXXInlineableMemberKind CXXMemberInliningMode;
+ /// \sa includeImplicitDtorsInCFG
+ Optional<bool> IncludeImplicitDtorsInCFG;
+
/// \sa includeTemporaryDtorsInCFG
Optional<bool> IncludeTemporaryDtorsInCFG;
-
+
+ /// \sa IncludeLifetimeInCFG
+ Optional<bool> IncludeLifetimeInCFG;
+
/// \sa mayInlineCXXStandardLibrary
Optional<bool> InlineCXXStandardLibrary;
@@ -395,6 +401,20 @@ public:
/// accepts the values "true" and "false".
bool includeTemporaryDtorsInCFG();
+ /// Returns whether or not implicit destructors for C++ objects should
+ /// be included in the CFG.
+ ///
+ /// This is controlled by the 'cfg-implicit-dtors' config option, which
+ /// accepts the values "true" and "false".
+ bool includeImplicitDtorsInCFG();
+
+ /// Returns whether or not end-of-lifetime information should be included in
+ /// the CFG.
+ ///
+ /// This is controlled by the 'cfg-lifetime' config option, which accepts
+ /// the values "true" and "false".
+ bool includeLifetimeInCFG();
+
/// Returns whether or not C++ standard library functions may be considered
/// for inlining.
///
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
index 8df2bc3..0e80e7b 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
@@ -17,6 +17,7 @@ namespace clang {
extern const char * const CoreFoundationObjectiveC;
extern const char * const LogicError;
extern const char * const MemoryCoreFoundationObjectiveC;
+ extern const char * const MemoryError;
extern const char * const UnixAPI;
}
}
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index dc6e54a..a07cd88 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -550,13 +550,15 @@ public:
class PathDiagnosticCallPiece : public PathDiagnosticPiece {
PathDiagnosticCallPiece(const Decl *callerD,
const PathDiagnosticLocation &callReturnPos)
- : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr),
- NoExit(false), callReturn(callReturnPos) {}
+ : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr),
+ NoExit(false), IsCalleeAnAutosynthesizedPropertyAccessor(false),
+ callReturn(callReturnPos) {}
PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
- : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr),
- NoExit(true), path(oldPath) {}
-
+ : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr),
+ NoExit(true), IsCalleeAnAutosynthesizedPropertyAccessor(false),
+ path(oldPath) {}
+
const Decl *Caller;
const Decl *Callee;
@@ -564,6 +566,10 @@ class PathDiagnosticCallPiece : public PathDiagnosticPiece {
// call exit.
bool NoExit;
+ // Flag signifying that the callee function is an Objective-C autosynthesized
+ // property getter or setter.
+ bool IsCalleeAnAutosynthesizedPropertyAccessor;
+
// The custom string, which should appear after the call Return Diagnostic.
// TODO: Should we allow multiple diagnostics?
std::string CallStackMessage;
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h
index dd7a6c8..f947776 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h
@@ -321,9 +321,11 @@ class RegionChanges {
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) {
- return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated,
- Explicits, Regions, Call);
+ return ((const CHECKER *) checker)->checkRegionChanges(state, invalidated,
+ Explicits, Regions,
+ LCtx, Call);
}
public:
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 0316c8f..88cb08a 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -286,7 +286,7 @@ public:
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
- /// \brief Run checkers on begining of function.
+ /// \brief Run checkers on beginning of function.
void runCheckersForBeginFunction(ExplodedNodeSet &Dst,
const BlockEdge &L,
ExplodedNode *Pred,
@@ -338,6 +338,7 @@ public:
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call);
/// \brief Run checkers when pointers escape.
@@ -443,10 +444,11 @@ public:
typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc;
typedef CheckerFn<ProgramStateRef (ProgramStateRef,
- const InvalidatedSymbols *symbols,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call)>
+ const InvalidatedSymbols *symbols,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
+ const CallEvent *Call)>
CheckRegionChangesFunc;
typedef CheckerFn<ProgramStateRef (ProgramStateRef,
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 0d1a120..4aa8744 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
namespace clang {
namespace ento {
@@ -29,8 +30,9 @@ class CompoundValData : public llvm::FoldingSetNode {
llvm::ImmutableList<SVal> L;
public:
- CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
- : T(t), L(l) {}
+ CompoundValData(QualType t, llvm::ImmutableList<SVal> l) : T(t), L(l) {
+ assert(NonLoc::isCompoundType(t));
+ }
typedef llvm::ImmutableList<SVal>::iterator iterator;
iterator begin() const { return L.begin(); }
@@ -47,7 +49,9 @@ class LazyCompoundValData : public llvm::FoldingSetNode {
const TypedValueRegion *region;
public:
LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r)
- : store(st), region(r) {}
+ : store(st), region(r) {
+ assert(NonLoc::isCompoundType(r->getValueType()));
+ }
const void *getStore() const { return store.getStore(); }
const TypedValueRegion *getRegion() const { return region; }
@@ -120,7 +124,7 @@ public:
/// Returns the type of the APSInt used to store values of the given QualType.
APSIntType getAPSIntType(QualType T) const {
assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T));
- return APSIntType(Ctx.getTypeSize(T),
+ return APSIntType(Ctx.getIntWidth(T),
!T->isSignedIntegerOrEnumerationType());
}
@@ -176,6 +180,11 @@ public:
return getValue(X);
}
+ inline const llvm::APSInt& getZeroWithTypeSize(QualType T) {
+ assert(T->isScalarType());
+ return getValue(0, Ctx.getTypeSize(T), true);
+ }
+
inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
}
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 89610ef..fa7ee62 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -55,6 +55,7 @@ class CallEventManager;
class CallDescription {
friend CallEvent;
mutable IdentifierInfo *II;
+ mutable bool IsLookupDone;
StringRef FuncName;
unsigned RequiredArgs;
@@ -68,7 +69,8 @@ public:
/// call. Omit this parameter to match every occurance of call with a given
/// name regardless the number of arguments.
CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement)
- : II(nullptr), FuncName(FuncName), RequiredArgs(RequiredArgs) {}
+ : II(nullptr), IsLookupDone(false), FuncName(FuncName),
+ RequiredArgs(RequiredArgs) {}
/// \brief Get the name of the function that this object matches.
StringRef getFunctionName() const { return FuncName; }
@@ -381,7 +383,9 @@ public:
// Iterator access to formal parameters and their types.
private:
- typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun;
+ struct GetTypeFn {
+ QualType operator()(ParmVarDecl *PD) const { return PD->getType(); }
+ };
public:
/// Return call's formal parameters.
@@ -391,7 +395,7 @@ public:
/// correspond with the argument value returned by \c getArgSVal(0).
virtual ArrayRef<ParmVarDecl*> parameters() const = 0;
- typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, get_type_fun>
+ typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, GetTypeFn>
param_type_iterator;
/// Returns an iterator over the types of the call's formal parameters.
@@ -400,13 +404,11 @@ public:
/// definition because it represents a public interface, and probably has
/// more annotations.
param_type_iterator param_type_begin() const {
- return llvm::map_iterator(parameters().begin(),
- get_type_fun(&ParmVarDecl::getType));
+ return llvm::map_iterator(parameters().begin(), GetTypeFn());
}
/// \sa param_type_begin()
param_type_iterator param_type_end() const {
- return llvm::map_iterator(parameters().end(),
- get_type_fun(&ParmVarDecl::getType));
+ return llvm::map_iterator(parameters().end(), GetTypeFn());
}
// For debugging purposes only
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 6651382..c01600d 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -139,6 +139,8 @@ public:
return nullptr;
}
+ /// Scan all symbols referenced by the constraints. If the symbol is not
+ /// alive, remove it.
virtual ProgramStateRef removeDeadBindings(ProgramStateRef state,
SymbolReaper& SymReaper) = 0;
@@ -182,6 +184,9 @@ std::unique_ptr<ConstraintManager>
CreateRangeConstraintManager(ProgramStateManager &statemgr,
SubEngine *subengine);
+std::unique_ptr<ConstraintManager>
+CreateZ3ConstraintManager(ProgramStateManager &statemgr, SubEngine *subengine);
+
} // end GR namespace
} // end clang namespace
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 591b112..067d706 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -237,7 +237,7 @@ public:
const CFGBlock *DstF) override;
/// Called by CoreEngine. Used to processing branching behavior
- /// at static initalizers.
+ /// at static initializers.
void processStaticInitializer(const DeclStmt *DS,
NodeBuilderContext& BuilderCtx,
ExplodedNode *Pred,
@@ -293,6 +293,7 @@ public:
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) override;
/// printState - Called by ProgramStateManager to print checker-specific data.
@@ -522,7 +523,9 @@ protected:
/// Call PointerEscape callback when a value escapes as a result of bind.
ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State,
- SVal Loc, SVal Val) override;
+ SVal Loc,
+ SVal Val,
+ const LocationContext *LCtx) override;
/// Call PointerEscape callback when a value escapes as a result of
/// region invalidation.
/// \param[in] ITraits Specifies invalidation traits for regions/symbols.
@@ -618,16 +621,16 @@ private:
void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
const CallEvent &Call);
- /// If the value of the given expression is a NonLoc, copy it into a new
- /// temporary object region, and replace the value of the expression with
- /// that.
+ /// If the value of the given expression \p InitWithAdjustments is a NonLoc,
+ /// copy it into a new temporary object region, and replace the value of the
+ /// expression with that.
///
- /// If \p ResultE is provided, the new region will be bound to this expression
- /// instead of \p E.
+ /// If \p Result is provided, the new region will be bound to this expression
+ /// instead of \p InitWithAdjustments.
ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
const LocationContext *LC,
- const Expr *E,
- const Expr *ResultE = nullptr);
+ const Expr *InitWithAdjustments,
+ const Expr *Result = nullptr);
/// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG
/// block to find the constructor expression that directly constructed into
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index da4b964..29b1c4c 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -182,6 +182,7 @@ protected:
MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) {
assert(classof(this));
+ assert(mgr);
}
MemRegionManager* getMemRegionManager() const override { return Mgr; }
@@ -215,9 +216,12 @@ public:
class GlobalsSpaceRegion : public MemSpaceRegion {
virtual void anchor();
+
protected:
- GlobalsSpaceRegion(MemRegionManager *mgr, Kind k)
- : MemSpaceRegion(mgr, k) {}
+ GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) : MemSpaceRegion(mgr, k) {
+ assert(classof(this));
+ }
+
public:
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
@@ -236,7 +240,9 @@ class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
const CodeTextRegion *CR;
StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr)
- : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {}
+ : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {
+ assert(cr);
+ }
public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
@@ -257,9 +263,13 @@ public:
/// RegionStoreManager::invalidateRegions (instead of finding all the dependent
/// globals, we invalidate the whole parent region).
class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
+ virtual void anchor() override;
+
protected:
NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k)
- : GlobalsSpaceRegion(mgr, k) {}
+ : GlobalsSpaceRegion(mgr, k) {
+ assert(classof(this));
+ }
public:
@@ -326,7 +336,6 @@ public:
};
class HeapSpaceRegion : public MemSpaceRegion {
- virtual void anchor();
friend class MemRegionManager;
HeapSpaceRegion(MemRegionManager *mgr)
@@ -341,10 +350,10 @@ public:
};
class UnknownSpaceRegion : public MemSpaceRegion {
- virtual void anchor();
friend class MemRegionManager;
UnknownSpaceRegion(MemRegionManager *mgr)
- : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
+ : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
+
public:
void dumpToStream(raw_ostream &os) const override;
@@ -355,13 +364,15 @@ public:
};
class StackSpaceRegion : public MemSpaceRegion {
-private:
+ virtual void anchor();
+
const StackFrameContext *SFC;
protected:
StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc)
: MemSpaceRegion(mgr, k), SFC(sfc) {
assert(classof(this));
+ assert(sfc);
}
public:
@@ -376,7 +387,6 @@ public:
};
class StackLocalsSpaceRegion : public StackSpaceRegion {
- virtual void anchor();
friend class MemRegionManager;
StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
: StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
@@ -391,7 +401,6 @@ public:
class StackArgumentsSpaceRegion : public StackSpaceRegion {
private:
- virtual void anchor();
friend class MemRegionManager;
StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
: StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
@@ -408,11 +417,15 @@ public:
/// SubRegion - A region that subsets another larger region. Most regions
/// are subclasses of SubRegion.
class SubRegion : public MemRegion {
-private:
virtual void anchor();
+
protected:
const MemRegion* superRegion;
- SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
+ SubRegion(const MemRegion *sReg, Kind k) : MemRegion(k), superRegion(sReg) {
+ assert(classof(this));
+ assert(sReg);
+ }
+
public:
const MemRegion* getSuperRegion() const {
return superRegion;
@@ -440,13 +453,18 @@ public:
/// by a call to 'alloca'.
class AllocaRegion : public SubRegion {
friend class MemRegionManager;
-protected:
+
unsigned Cnt; // Block counter. Used to distinguish different pieces of
// memory allocated by alloca at the same call site.
const Expr *Ex;
- AllocaRegion(const Expr *ex, unsigned cnt, const MemRegion *superRegion)
- : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
+ AllocaRegion(const Expr *ex, unsigned cnt, const MemSpaceRegion *superRegion)
+ : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {
+ assert(Ex);
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex,
+ unsigned Cnt, const MemRegion *superRegion);
public:
@@ -458,9 +476,6 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex,
- unsigned Cnt, const MemRegion *superRegion);
-
void dumpToStream(raw_ostream &os) const override;
static bool classof(const MemRegion* R) {
@@ -470,10 +485,12 @@ public:
/// TypedRegion - An abstract class representing regions that are typed.
class TypedRegion : public SubRegion {
-public:
- void anchor() override;
+ virtual void anchor() override;
+
protected:
- TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
+ TypedRegion(const MemRegion *sReg, Kind k) : SubRegion(sReg, k) {
+ assert(classof(this));
+ }
public:
virtual QualType getLocationType() const = 0;
@@ -492,10 +509,12 @@ public:
/// TypedValueRegion - An abstract class representing regions having a typed value.
class TypedValueRegion : public TypedRegion {
-public:
- void anchor() override;
+ virtual void anchor() override;
+
protected:
- TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {}
+ TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {
+ assert(classof(this));
+ }
public:
virtual QualType getValueType() const = 0;
@@ -524,10 +543,13 @@ public:
class CodeTextRegion : public TypedRegion {
-public:
- void anchor() override;
+ virtual void anchor() override;
+
protected:
- CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {}
+ CodeTextRegion(const MemSpaceRegion *sreg, Kind k) : TypedRegion(sreg, k) {
+ assert(classof(this));
+ }
+
public:
bool isBoundable() const override { return false; }
@@ -539,13 +561,19 @@ public:
/// FunctionCodeRegion - A region that represents code texts of function.
class FunctionCodeRegion : public CodeTextRegion {
+ friend class MemRegionManager;
+
const NamedDecl *FD;
-public:
- FunctionCodeRegion(const NamedDecl *fd, const MemRegion* sreg)
+
+ FunctionCodeRegion(const NamedDecl *fd, const CodeSpaceRegion* sreg)
: CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) {
assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd));
}
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD,
+ const MemRegion*);
+
+public:
QualType getLocationType() const override {
const ASTContext &Ctx = getContext();
if (const FunctionDecl *D = dyn_cast<FunctionDecl>(FD)) {
@@ -568,9 +596,6 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD,
- const MemRegion*);
-
static bool classof(const MemRegion* R) {
return R->getKind() == FunctionCodeRegionKind;
}
@@ -591,8 +616,16 @@ class BlockCodeRegion : public CodeTextRegion {
CanQualType locTy;
BlockCodeRegion(const BlockDecl *bd, CanQualType lTy,
- AnalysisDeclContext *ac, const MemRegion* sreg)
- : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {}
+ AnalysisDeclContext *ac, const CodeSpaceRegion* sreg)
+ : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {
+ assert(bd);
+ assert(ac);
+ assert(lTy->getTypePtr()->isBlockPointerType());
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD,
+ CanQualType, const AnalysisDeclContext*,
+ const MemRegion*);
public:
QualType getLocationType() const override {
@@ -609,10 +642,6 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD,
- CanQualType, const AnalysisDeclContext*,
- const MemRegion*);
-
static bool classof(const MemRegion* R) {
return R->getKind() == BlockCodeRegionKind;
}
@@ -626,6 +655,7 @@ public:
/// variables.
class BlockDataRegion : public TypedRegion {
friend class MemRegionManager;
+
const BlockCodeRegion *BC;
const LocationContext *LC; // Can be null */
unsigned BlockCount;
@@ -633,10 +663,19 @@ class BlockDataRegion : public TypedRegion {
void *OriginalVars;
BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc,
- unsigned count, const MemRegion *sreg)
- : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
- BlockCount(count),
- ReferencedVars(nullptr), OriginalVars(nullptr) {}
+ unsigned count, const MemSpaceRegion *sreg)
+ : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
+ BlockCount(count), ReferencedVars(nullptr), OriginalVars(nullptr) {
+ assert(bc);
+ assert(lc);
+ assert(isa<GlobalImmutableSpaceRegion>(sreg) ||
+ isa<StackLocalsSpaceRegion>(sreg) ||
+ isa<UnknownSpaceRegion>(sreg));
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *,
+ const LocationContext *, unsigned,
+ const MemRegion *);
public:
const BlockCodeRegion *getCodeRegion() const { return BC; }
@@ -686,10 +725,6 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *,
- const LocationContext *, unsigned,
- const MemRegion *);
-
static bool classof(const MemRegion* R) {
return R->getKind() == BlockDataRegionKind;
}
@@ -705,13 +740,20 @@ private:
/// map the concept of symbolic values into the domain of regions. Symbolic
/// regions do not need to be typed.
class SymbolicRegion : public SubRegion {
-protected:
+ friend class MemRegionManager;
+
const SymbolRef sym;
-public:
- SymbolicRegion(const SymbolRef s, const MemRegion* sreg)
- : SubRegion(sreg, SymbolicRegionKind), sym(s) {}
+ SymbolicRegion(const SymbolRef s, const MemSpaceRegion *sreg)
+ : SubRegion(sreg, SymbolicRegionKind), sym(s) {
+ assert(s);
+ assert(s->getType()->isAnyPointerType() ||
+ s->getType()->isReferenceType() ||
+ s->getType()->isBlockPointerType());
+ assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg));
+ }
+public:
SymbolRef getSymbol() const {
return sym;
}
@@ -736,11 +778,13 @@ public:
/// StringRegion - Region associated with a StringLiteral.
class StringRegion : public TypedValueRegion {
friend class MemRegionManager;
+
const StringLiteral* Str;
-protected:
- StringRegion(const StringLiteral* str, const MemRegion* sreg)
- : TypedValueRegion(sreg, StringRegionKind), Str(str) {}
+ StringRegion(const StringLiteral *str, const GlobalInternalSpaceRegion *sreg)
+ : TypedValueRegion(sreg, StringRegionKind), Str(str) {
+ assert(str);
+ }
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const StringLiteral* Str,
@@ -772,12 +816,15 @@ public:
/// The region associated with an ObjCStringLiteral.
class ObjCStringRegion : public TypedValueRegion {
friend class MemRegionManager;
+
const ObjCStringLiteral* Str;
-protected:
-
- ObjCStringRegion(const ObjCStringLiteral* str, const MemRegion* sreg)
- : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {}
-
+
+ ObjCStringRegion(const ObjCStringLiteral *str,
+ const GlobalInternalSpaceRegion *sreg)
+ : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {
+ assert(str);
+ }
+
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const ObjCStringLiteral* Str,
const MemRegion* superRegion);
@@ -807,12 +854,17 @@ public:
/// Compound literals are essentially temporaries that are stack allocated
/// or in the global constant pool.
class CompoundLiteralRegion : public TypedValueRegion {
-private:
friend class MemRegionManager;
+
const CompoundLiteralExpr *CL;
- CompoundLiteralRegion(const CompoundLiteralExpr *cl, const MemRegion* sReg)
- : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
+ CompoundLiteralRegion(const CompoundLiteralExpr *cl,
+ const MemSpaceRegion *sReg)
+ : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {
+ assert(cl);
+ assert(isa<GlobalInternalSpaceRegion>(sReg) ||
+ isa<StackLocalsSpaceRegion>(sReg));
+ }
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const CompoundLiteralExpr *CL,
@@ -839,8 +891,11 @@ class DeclRegion : public TypedValueRegion {
protected:
const Decl *D;
- DeclRegion(const Decl *d, const MemRegion* sReg, Kind k)
- : TypedValueRegion(sReg, k), D(d) {}
+ DeclRegion(const Decl *d, const MemRegion *sReg, Kind k)
+ : TypedValueRegion(sReg, k), D(d) {
+ assert(classof(this));
+ assert(d);
+ }
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
const MemRegion* superRegion, Kind k);
@@ -859,17 +914,24 @@ class VarRegion : public DeclRegion {
friend class MemRegionManager;
// Constructors and private methods.
- VarRegion(const VarDecl *vd, const MemRegion* sReg)
- : DeclRegion(vd, sReg, VarRegionKind) {}
+ VarRegion(const VarDecl *vd, const MemRegion *sReg)
+ : DeclRegion(vd, sReg, VarRegionKind) {
+ // VarRegion appears in unknown space when it's a block variable as seen
+ // from a block using it, when this block is analyzed at top-level.
+ // Other block variables appear within block data regions,
+ // which, unlike everything else on this list, are not memory spaces.
+ assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) ||
+ isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg));
+ }
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD,
const MemRegion *superRegion) {
DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
}
+public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
-public:
const VarDecl *getDecl() const { return cast<VarDecl>(D); }
const StackFrameContext *getStackFrame() const;
@@ -895,17 +957,19 @@ public:
/// referred to by 'this', but rather 'this' itself.
class CXXThisRegion : public TypedValueRegion {
friend class MemRegionManager;
+
CXXThisRegion(const PointerType *thisPointerTy,
- const MemRegion *sReg)
- : TypedValueRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
+ const StackArgumentsSpaceRegion *sReg)
+ : TypedValueRegion(sReg, CXXThisRegionKind),
+ ThisPointerTy(thisPointerTy) {}
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
const PointerType *PT,
const MemRegion *sReg);
+public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
-public:
QualType getValueType() const override {
return QualType(ThisPointerTy, 0);
}
@@ -923,9 +987,14 @@ private:
class FieldRegion : public DeclRegion {
friend class MemRegionManager;
- FieldRegion(const FieldDecl *fd, const MemRegion* sReg)
+ FieldRegion(const FieldDecl *fd, const SubRegion* sReg)
: DeclRegion(fd, sReg, FieldRegionKind) {}
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
+ }
+
public:
const FieldDecl *getDecl() const { return cast<FieldDecl>(D); }
@@ -936,11 +1005,6 @@ public:
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
- const MemRegion* superRegion) {
- DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
- }
-
static bool classof(const MemRegion* R) {
return R->getKind() == FieldRegionKind;
}
@@ -954,10 +1018,9 @@ public:
};
class ObjCIvarRegion : public DeclRegion {
-
friend class MemRegionManager;
- ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg);
+ ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg);
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd,
const MemRegion* superRegion);
@@ -982,7 +1045,6 @@ public:
class ElementRegion;
class RegionRawOffset {
-private:
friend class ElementRegion;
const MemRegion *Region;
@@ -1007,9 +1069,9 @@ class ElementRegion : public TypedValueRegion {
QualType ElementType;
NonLoc Index;
- ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg)
- : TypedValueRegion(sReg, ElementRegionKind),
- ElementType(elementType), Index(Idx) {
+ ElementRegion(QualType elementType, NonLoc Idx, const SubRegion *sReg)
+ : TypedValueRegion(sReg, ElementRegionKind),
+ ElementType(elementType), Index(Idx) {
assert((!Idx.getAs<nonloc::ConcreteInt>() ||
Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) &&
"The index must be signed");
@@ -1047,12 +1109,16 @@ class CXXTempObjectRegion : public TypedValueRegion {
Expr const *Ex;
- CXXTempObjectRegion(Expr const *E, MemRegion const *sReg)
- : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {}
+ CXXTempObjectRegion(Expr const *E, MemSpaceRegion const *sReg)
+ : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {
+ assert(E);
+ assert(isa<StackLocalsSpaceRegion>(sReg) ||
+ isa<GlobalInternalSpaceRegion>(sReg));
+ }
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
Expr const *E, const MemRegion *sReg);
-
+
public:
const Expr *getExpr() const { return Ex; }
@@ -1077,8 +1143,10 @@ class CXXBaseObjectRegion : public TypedValueRegion {
llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data;
CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual,
- const MemRegion *SReg)
- : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {}
+ const SubRegion *SReg)
+ : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {
+ assert(RD);
+ }
static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD,
bool IsVirtual, const MemRegion *SReg);
@@ -1204,16 +1272,16 @@ public:
/// getVarRegion - Retrieve or create the memory region associated with
/// a specified VarDecl and super region.
- const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR);
-
+ const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR);
+
/// getElementRegion - Retrieve the memory region associated with the
/// associated element type, index, and super region.
const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx,
- const MemRegion *superRegion,
+ const SubRegion *superRegion,
ASTContext &Ctx);
const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER,
- const MemRegion *superRegion) {
+ const SubRegion *superRegion) {
return getElementRegion(ER->getElementType(), ER->getIndex(),
superRegion, ER->getContext());
}
@@ -1223,10 +1291,10 @@ public:
/// memory region (which typically represents the memory representing
/// a structure or class).
const FieldRegion *getFieldRegion(const FieldDecl *fd,
- const MemRegion* superRegion);
+ const SubRegion* superRegion);
const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
- const MemRegion *superRegion) {
+ const SubRegion *superRegion) {
return getFieldRegion(FR->getDecl(), superRegion);
}
@@ -1235,7 +1303,7 @@ public:
/// to the containing region (which typically represents the Objective-C
/// object).
const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd,
- const MemRegion* superRegion);
+ const SubRegion* superRegion);
const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
LocationContext const *LC);
@@ -1245,14 +1313,14 @@ public:
///
/// The type of \p Super is assumed be a class deriving from \p BaseClass.
const CXXBaseObjectRegion *
- getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super,
+ getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const SubRegion *Super,
bool IsVirtual);
/// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different
/// super region.
const CXXBaseObjectRegion *
getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg,
- const MemRegion *superRegion) {
+ const SubRegion *superRegion) {
return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion,
baseReg->isVirtual());
}
@@ -1276,17 +1344,22 @@ public:
const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex);
private:
- template <typename RegionTy, typename A1>
- RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion);
-
- template <typename RegionTy, typename A1, typename A2>
- RegionTy* getSubRegion(const A1 a1, const A2 a2,
- const MemRegion* superRegion);
+ template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty>
+ RegionTy* getSubRegion(const Arg1Ty arg1,
+ const SuperTy* superRegion);
+
+ template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty, typename Arg2Ty>
+ RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const SuperTy* superRegion);
+
+ template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty, typename Arg2Ty, typename Arg3Ty>
+ RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const Arg3Ty arg3,
+ const SuperTy* superRegion);
- template <typename RegionTy, typename A1, typename A2, typename A3>
- RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3,
- const MemRegion* superRegion);
-
template <typename REG>
const REG* LazyAllocate(REG*& region);
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 463b375..e3a2164 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -43,6 +43,7 @@ typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)(
ProgramStateManager &, SubEngine *);
typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)(
ProgramStateManager &);
+typedef llvm::ImmutableMap<const SubRegion*, TaintTagType> TaintedSubRegions;
//===----------------------------------------------------------------------===//
// ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState.
@@ -229,11 +230,12 @@ public:
ProgramStateRef bindLoc(Loc location,
SVal V,
+ const LocationContext *LCtx,
bool notifyChanges = true) const;
- ProgramStateRef bindLoc(SVal location, SVal V) const;
+ ProgramStateRef bindLoc(SVal location, SVal V, const LocationContext *LCtx) const;
- ProgramStateRef bindDefault(SVal loc, SVal V) const;
+ ProgramStateRef bindDefault(SVal loc, SVal V, const LocationContext *LCtx) const;
ProgramStateRef killBinding(Loc LV) const;
@@ -342,6 +344,9 @@ public:
ProgramStateRef addTaint(const Stmt *S, const LocationContext *LCtx,
TaintTagType Kind = TaintTagGeneric) const;
+ /// Create a new state in which the value is marked as tainted.
+ ProgramStateRef addTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const;
+
/// Create a new state in which the symbol is marked as tainted.
ProgramStateRef addTaint(SymbolRef S,
TaintTagType Kind = TaintTagGeneric) const;
@@ -350,6 +355,14 @@ public:
ProgramStateRef addTaint(const MemRegion *R,
TaintTagType Kind = TaintTagGeneric) const;
+ /// Create a new state in a which a sub-region of a given symbol is tainted.
+ /// This might be necessary when referring to regions that can not have an
+ /// individual symbol, e.g. if they are represented by the default binding of
+ /// a LazyCompoundVal.
+ ProgramStateRef addPartialTaint(SymbolRef ParentSym,
+ const SubRegion *SubRegion,
+ TaintTagType Kind = TaintTagGeneric) const;
+
/// Check if the statement is tainted in the current state.
bool isTainted(const Stmt *S, const LocationContext *LCtx,
TaintTagType Kind = TaintTagGeneric) const;
@@ -452,6 +465,7 @@ private:
std::unique_ptr<ConstraintManager> ConstraintMgr;
ProgramState::GenericDataMap::Factory GDMFactory;
+ TaintedSubRegions::Factory TSRFactory;
typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
GDMContextsTy GDMContexts;
@@ -681,9 +695,9 @@ ProgramState::assumeInclusiveRange(DefinedOrUnknownSVal Val,
this, Val.castAs<NonLoc>(), From, To);
}
-inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const {
+inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V, const LocationContext *LCtx) const {
if (Optional<Loc> L = LV.getAs<Loc>())
- return bindLoc(*L, V);
+ return bindLoc(*L, V, LCtx);
return this;
}
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index a4c01fc..d58d0a6 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -112,6 +112,11 @@ public:
/// Evaluates a given SVal. If the SVal has only one possible (integer) value,
/// that value is returned. Otherwise, returns NULL.
virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0;
+
+ /// Simplify symbolic expressions within a given SVal. Return an SVal
+ /// that represents the same value, but is hopefully easier to work with
+ /// than the original SVal.
+ virtual SVal simplifySVal(ProgramStateRef State, SVal Val) = 0;
/// Constructs a symbolic expression for two non-location values.
SVal makeSymExprValNN(ProgramStateRef state, BinaryOperator::Opcode op,
@@ -310,6 +315,13 @@ public:
return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
}
+ /// Create NULL pointer, with proper pointer bit-width for given address
+ /// space.
+ /// \param type pointer type.
+ Loc makeNullWithType(QualType type) {
+ return loc::ConcreteInt(BasicVals.getZeroWithTypeSize(type));
+ }
+
Loc makeNull() {
return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
}
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index cc3c02a..935f001 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -41,6 +41,22 @@ class MemRegionManager;
class ProgramStateManager;
class SValBuilder;
+namespace nonloc {
+/// Sub-kinds for NonLoc values.
+enum Kind {
+#define NONLOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
+}
+
+namespace loc {
+/// Sub-kinds for Loc values.
+enum Kind {
+#define LOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
+}
+
/// SVal - This represents a symbolic expression, which can be either
/// an L-value or an R-value.
///
@@ -75,10 +91,7 @@ public:
template<typename T>
T castAs() const {
assert(T::isKind(*this));
- T t;
- SVal& sv = t;
- sv = *this;
- return t;
+ return *static_cast<const T *>(this);
}
/// \brief Convert to the specified SVal type, returning None if this SVal is
@@ -87,10 +100,7 @@ public:
Optional<T> getAs() const {
if (!T::isKind(*this))
return None;
- T t;
- SVal& sv = t;
- sv = *this;
- return t;
+ return *static_cast<const T *>(this);
}
/// BufferTy - A temporary buffer to hold a set of SVals.
@@ -273,6 +283,11 @@ protected:
public:
void dumpToStream(raw_ostream &Out) const;
+ static inline bool isCompoundType(QualType T) {
+ return T->isArrayType() || T->isRecordType() ||
+ T->isComplexType() || T->isVectorType();
+ }
+
private:
friend class SVal;
static bool isKind(const SVal& V) {
@@ -307,15 +322,11 @@ private:
namespace nonloc {
-enum Kind {
-#define NONLOC_SVAL(Id, Parent) Id ## Kind,
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
-};
-
/// \brief Represents symbolic expression.
class SymbolVal : public NonLoc {
public:
- SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}
+ SymbolVal() = delete;
+ SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) { assert(sym); }
SymbolRef getSymbol() const {
return (const SymExpr*) Data;
@@ -327,7 +338,6 @@ public:
private:
friend class SVal;
- SymbolVal() {}
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind &&
V.getSubKind() == SymbolValKind;
@@ -373,7 +383,11 @@ class LocAsInteger : public NonLoc {
explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data)
: NonLoc(LocAsIntegerKind, &data) {
- assert (data.first.getAs<Loc>());
+ // We do not need to represent loc::ConcreteInt as LocAsInteger,
+ // as it'd collapse into a nonloc::ConcreteInt instead.
+ assert(data.first.getBaseKind() == LocKind &&
+ (data.first.getSubKind() == loc::MemRegionValKind ||
+ data.first.getSubKind() == loc::GotoLabelKind));
}
public:
@@ -513,14 +527,11 @@ private:
namespace loc {
-enum Kind {
-#define LOC_SVAL(Id, Parent) Id ## Kind,
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
-};
-
class GotoLabel : public Loc {
public:
- explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {}
+ explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) {
+ assert(Label);
+ }
const LabelDecl *getLabel() const {
return static_cast<const LabelDecl*>(Data);
@@ -541,7 +552,9 @@ private:
class MemRegionVal : public Loc {
public:
- explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {}
+ explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {
+ assert(r);
+ }
/// \brief Get the underlining region.
const MemRegion* getRegion() const {
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h
new file mode 100644
index 0000000..2c9802b
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h
@@ -0,0 +1,92 @@
+//== SimpleConstraintManager.h ----------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simplified constraint manager backend.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SIMPLECONSTRAINTMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SIMPLECONSTRAINTMANAGER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+
+namespace clang {
+
+namespace ento {
+
+class SimpleConstraintManager : public ConstraintManager {
+ SubEngine *SU;
+ SValBuilder &SVB;
+
+public:
+ SimpleConstraintManager(SubEngine *subengine, SValBuilder &SB)
+ : SU(subengine), SVB(SB) {}
+
+ ~SimpleConstraintManager() override;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from ConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ /// Ensures that the DefinedSVal conditional is expressed as a NonLoc by
+ /// creating boolean casts to handle Loc's.
+ ProgramStateRef assume(ProgramStateRef State, DefinedSVal Cond,
+ bool Assumption) override;
+
+ ProgramStateRef assumeInclusiveRange(ProgramStateRef State, NonLoc Value,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) override;
+
+protected:
+ //===------------------------------------------------------------------===//
+ // Interface that subclasses must implement.
+ //===------------------------------------------------------------------===//
+
+ /// Given a symbolic expression that can be reasoned about, assume that it is
+ /// true/false and generate the new program state.
+ virtual ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) = 0;
+
+ /// Given a symbolic expression within the range [From, To], assume that it is
+ /// true/false and generate the new program state.
+ /// This function is used to handle case ranges produced by a language
+ /// extension for switch case statements.
+ virtual ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State,
+ SymbolRef Sym,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) = 0;
+
+ /// Given a symbolic expression that cannot be reasoned about, assume that
+ /// it is zero/nonzero and add it directly to the solver state.
+ virtual ProgramStateRef assumeSymUnsupported(ProgramStateRef State,
+ SymbolRef Sym,
+ bool Assumption) = 0;
+
+ //===------------------------------------------------------------------===//
+ // Internal implementation.
+ //===------------------------------------------------------------------===//
+
+ BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); }
+ SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); }
+
+private:
+ ProgramStateRef assume(ProgramStateRef State, NonLoc Cond, bool Assumption);
+
+ ProgramStateRef assumeAux(ProgramStateRef State, NonLoc Cond,
+ bool Assumption);
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index fa7d3f7..7619f22 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -59,6 +59,30 @@ public:
/// \return The value bound to the location \c loc.
virtual SVal getBinding(Store store, Loc loc, QualType T = QualType()) = 0;
+ /// Return the default value bound to a region in a given store. The default
+ /// binding is the value of sub-regions that were not initialized separately
+ /// from their base region. For example, if the structure is zero-initialized
+ /// upon construction, this method retrieves the concrete zero value, even if
+ /// some or all fields were later overwritten manually. Default binding may be
+ /// an unknown, undefined, concrete, or symbolic value.
+ /// \param[in] store The store in which to make the lookup.
+ /// \param[in] R The region to find the default binding for.
+ /// \return The default value bound to the region in the store, if a default
+ /// binding exists.
+ virtual Optional<SVal> getDefaultBinding(Store store, const MemRegion *R) = 0;
+
+ /// Return the default value bound to a LazyCompoundVal. The default binding
+ /// is used to represent the value of any fields or elements within the
+ /// structure represented by the LazyCompoundVal which were not initialized
+ /// explicitly separately from the whole structure. Default binding may be an
+ /// unknown, undefined, concrete, or symbolic value.
+ /// \param[in] lcv The lazy compound value.
+ /// \return The default value bound to the LazyCompoundVal \c lcv, if a
+ /// default binding exists.
+ Optional<SVal> getDefaultBinding(nonloc::LazyCompoundVal lcv) {
+ return getDefaultBinding(lcv.getStore(), lcv.getRegion());
+ }
+
/// Return a state with the specified value bound to the given location.
/// \param[in] store The analysis state.
/// \param[in] loc The symbolic memory location.
@@ -136,7 +160,7 @@ public:
/// valid only if Failed flag is set to false.
SVal attemptDownCast(SVal Base, QualType DerivedPtrType, bool &Failed);
- const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
+ const ElementRegion *GetElementZeroRegion(const SubRegion *R, QualType T);
/// castRegion - Used by ExprEngine::VisitCast to handle casts from
/// a MemRegion* to a specific location type. 'R' is the region being
@@ -235,8 +259,9 @@ public:
virtual void iterBindings(Store store, BindingsHandler& f) = 0;
protected:
- const MemRegion *MakeElementRegion(const MemRegion *baseRegion,
- QualType pointeeTy, uint64_t index = 0);
+ const ElementRegion *MakeElementRegion(const SubRegion *baseRegion,
+ QualType pointeeTy,
+ uint64_t index = 0);
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 581ef20..8ccd347 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -83,7 +83,7 @@ public:
const CFGBlock *DstF) = 0;
/// Called by CoreEngine. Used to processing branching behavior
- /// at static initalizers.
+ /// at static initializers.
virtual void processStaticInitializer(const DeclStmt *DS,
NodeBuilderContext& BuilderCtx,
ExplodedNode *Pred,
@@ -131,17 +131,19 @@ public:
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) = 0;
inline ProgramStateRef
processRegionChange(ProgramStateRef state,
- const MemRegion* MR) {
- return processRegionChanges(state, nullptr, MR, MR, nullptr);
+ const MemRegion* MR,
+ const LocationContext *LCtx) {
+ return processRegionChanges(state, nullptr, MR, MR, LCtx, nullptr);
}
virtual ProgramStateRef
- processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val) = 0;
+ processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val, const LocationContext *LCtx) = 0;
virtual ProgramStateRef
notifyCheckersOfPointerEscape(ProgramStateRef State,
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
index 18bc607..f720339 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
@@ -42,6 +42,12 @@ private:
protected:
SymExpr(Kind k) : K(k) {}
+ static bool isValidTypeForSymbol(QualType T) {
+ // FIXME: Depending on whether we choose to deprecate structural symbols,
+ // this may become much stricter.
+ return !T.isNull() && !T->isVoidType();
+ }
+
public:
virtual ~SymExpr() {}
@@ -103,7 +109,9 @@ class SymbolData : public SymExpr {
const SymbolID Sym;
protected:
- SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
+ SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {
+ assert(classof(this));
+ }
public:
~SymbolData() override {}
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index f00dce5..e970114 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -44,7 +44,10 @@ class SymbolRegionValue : public SymbolData {
public:
SymbolRegionValue(SymbolID sym, const TypedValueRegion *r)
- : SymbolData(SymbolRegionValueKind, sym), R(r) {}
+ : SymbolData(SymbolRegionValueKind, sym), R(r) {
+ assert(r);
+ assert(isValidTypeForSymbol(r->getValueType()));
+ }
const TypedValueRegion* getRegion() const { return R; }
@@ -81,7 +84,15 @@ public:
SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx,
QualType t, unsigned count, const void *symbolTag)
: SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count),
- LCtx(lctx), SymbolTag(symbolTag) {}
+ LCtx(lctx), SymbolTag(symbolTag) {
+ // FIXME: 's' might be a nullptr if we're conducting invalidation
+ // that was caused by a destructor call on a temporary object,
+ // which has no statement associated with it.
+ // Due to this, we might be creating the same invalidation symbol for
+ // two different invalidation passes (for two different temporaries).
+ assert(lctx);
+ assert(isValidTypeForSymbol(t));
+ }
const Stmt *getStmt() const { return S; }
unsigned getCount() const { return Count; }
@@ -120,7 +131,11 @@ class SymbolDerived : public SymbolData {
public:
SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r)
- : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {}
+ : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {
+ assert(parent);
+ assert(r);
+ assert(isValidTypeForSymbol(r->getValueType()));
+ }
SymbolRef getParentSymbol() const { return parentSymbol; }
const TypedValueRegion *getRegion() const { return R; }
@@ -155,7 +170,9 @@ class SymbolExtent : public SymbolData {
public:
SymbolExtent(SymbolID sym, const SubRegion *r)
- : SymbolData(SymbolExtentKind, sym), R(r) {}
+ : SymbolData(SymbolExtentKind, sym), R(r) {
+ assert(r);
+ }
const SubRegion *getRegion() const { return R; }
@@ -193,7 +210,13 @@ public:
SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t,
const LocationContext *LCtx, unsigned count, const void *tag)
: SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), LCtx(LCtx),
- Count(count), Tag(tag) {}
+ Count(count), Tag(tag) {
+ assert(r);
+ assert(s);
+ assert(isValidTypeForSymbol(t));
+ assert(LCtx);
+ assert(tag);
+ }
const MemRegion *getRegion() const { return R; }
const Stmt *getStmt() const { return S; }
@@ -236,8 +259,13 @@ class SymbolCast : public SymExpr {
QualType ToTy;
public:
- SymbolCast(const SymExpr *In, QualType From, QualType To) :
- SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) { }
+ SymbolCast(const SymExpr *In, QualType From, QualType To)
+ : SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) {
+ assert(In);
+ assert(isValidTypeForSymbol(From));
+ // FIXME: GenericTaintChecker creates symbols of void type.
+ // Otherwise, 'To' should also be a valid type.
+ }
QualType getType() const override { return ToTy; }
@@ -270,7 +298,10 @@ class BinarySymExpr : public SymExpr {
protected:
BinarySymExpr(Kind k, BinaryOperator::Opcode op, QualType t)
- : SymExpr(k), Op(op), T(t) {}
+ : SymExpr(k), Op(op), T(t) {
+ assert(classof(this));
+ assert(isValidTypeForSymbol(t));
+ }
public:
// FIXME: We probably need to make this out-of-line to avoid redundant
@@ -293,8 +324,10 @@ class SymIntExpr : public BinarySymExpr {
public:
SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
- const llvm::APSInt& rhs, QualType t)
- : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {}
+ const llvm::APSInt &rhs, QualType t)
+ : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {
+ assert(lhs);
+ }
void dumpToStream(raw_ostream &os) const override;
@@ -327,9 +360,11 @@ class IntSymExpr : public BinarySymExpr {
const SymExpr *RHS;
public:
- IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op,
+ IntSymExpr(const llvm::APSInt &lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType t)
- : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {
+ assert(rhs);
+ }
void dumpToStream(raw_ostream &os) const override;
@@ -364,7 +399,10 @@ class SymSymExpr : public BinarySymExpr {
public:
SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs,
QualType t)
- : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) {
+ assert(lhs);
+ assert(rhs);
+ }
const SymExpr *getLHS() const { return LHS; }
const SymExpr *getRHS() const { return RHS; }
diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
index d39b501..7b76263 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
+++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -35,6 +35,16 @@ template<> struct ProgramStateTrait<TaintMap>
static void *GDMIndex() { static int index = 0; return &index; }
};
+/// The GDM component mapping derived symbols' parent symbols to their
+/// underlying regions. This is used to efficiently check whether a symbol is
+/// tainted when it represents a sub-region of a tainted symbol.
+struct DerivedSymTaint {};
+typedef llvm::ImmutableMap<SymbolRef, TaintedSubRegions> DerivedSymTaintImpl;
+template<> struct ProgramStateTrait<DerivedSymTaint>
+ : public ProgramStatePartialTrait<DerivedSymTaintImpl> {
+ static void *GDMIndex() { static int index; return &index; }
+};
+
class TaintManager {
TaintManager() {}
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/ArgumentsAdjusters.h b/contrib/llvm/tools/clang/include/clang/Tooling/ArgumentsAdjusters.h
index 1fd7be6..4eb0225 100644
--- a/contrib/llvm/tools/clang/include/clang/Tooling/ArgumentsAdjusters.h
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/ArgumentsAdjusters.h
@@ -44,6 +44,10 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster();
/// arguments.
ArgumentsAdjuster getClangStripOutputAdjuster();
+/// \brief Gets an argument adjuster which removes dependency-file
+/// related command line arguments.
+ArgumentsAdjuster getClangStripDependencyFileAdjuster();
+
enum class ArgumentInsertPosition { BEGIN, END };
/// \brief Gets an argument adjuster which inserts \p Extra arguments in the
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h b/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h
index 4611d3c..e988b84 100644
--- a/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h
@@ -60,16 +60,6 @@ struct CompileCommand {
/// The output file associated with the command.
std::string Output;
-
- /// \brief An optional mapping from each file's path to its content for all
- /// files needed for the compilation that are not available via the file
- /// system.
- ///
- /// Note that a tool implementation is required to fall back to the file
- /// system if a source file is not provided in the mapped sources, as
- /// compilation databases will usually not provide all files in mapped sources
- /// for performance reasons.
- std::vector<std::pair<std::string, std::string> > MappedSources;
};
/// \brief Interface for compilation databases.
@@ -186,10 +176,11 @@ public:
/// the number of arguments before "--", if "--" was found in the argument
/// list.
/// \param Argv Points to the command line arguments.
+ /// \param ErrorMsg Contains error text if the function returns null pointer.
/// \param Directory The base directory used in the FixedCompilationDatabase.
- static FixedCompilationDatabase *loadFromCommandLine(int &Argc,
- const char *const *Argv,
- Twine Directory = ".");
+ static std::unique_ptr<FixedCompilationDatabase> loadFromCommandLine(
+ int &Argc, const char *const *Argv, std::string &ErrorMsg,
+ Twine Directory = ".");
/// \brief Constructs a compilation data base from a specified directory
/// and command line.
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Core/Diagnostic.h b/contrib/llvm/tools/clang/include/clang/Tooling/Core/Diagnostic.h
index d657f16..b4920d4 100644
--- a/contrib/llvm/tools/clang/include/clang/Tooling/Core/Diagnostic.h
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/Core/Diagnostic.h
@@ -58,9 +58,9 @@ struct Diagnostic {
Diagnostic(llvm::StringRef DiagnosticName, Level DiagLevel,
StringRef BuildDirectory);
- Diagnostic(llvm::StringRef DiagnosticName, DiagnosticMessage &Message,
- llvm::StringMap<Replacements> &Fix,
- SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel,
+ Diagnostic(llvm::StringRef DiagnosticName, const DiagnosticMessage &Message,
+ const llvm::StringMap<Replacements> &Fix,
+ const SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel,
llvm::StringRef BuildDirectory);
/// \brief Name identifying the Diagnostic.
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/DiagnosticsYaml.h b/contrib/llvm/tools/clang/include/clang/Tooling/DiagnosticsYaml.h
index f32b9fa..4d6ff06 100644
--- a/contrib/llvm/tools/clang/include/clang/Tooling/DiagnosticsYaml.h
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/DiagnosticsYaml.h
@@ -56,6 +56,9 @@ template <> struct MappingTraits<clang::tooling::Diagnostic> {
MappingNormalization<NormalizedDiagnostic, clang::tooling::Diagnostic> Keys(
Io, D);
Io.mapRequired("DiagnosticName", Keys->DiagnosticName);
+ Io.mapRequired("Message", Keys->Message.Message);
+ Io.mapRequired("FileOffset", Keys->Message.FileOffset);
+ Io.mapRequired("FilePath", Keys->Message.FilePath);
// FIXME: Export properly all the different fields.
@@ -82,17 +85,7 @@ template <> struct MappingTraits<clang::tooling::Diagnostic> {
template <> struct MappingTraits<clang::tooling::TranslationUnitDiagnostics> {
static void mapping(IO &Io, clang::tooling::TranslationUnitDiagnostics &Doc) {
Io.mapRequired("MainSourceFile", Doc.MainSourceFile);
-
- std::vector<clang::tooling::Diagnostic> Diagnostics;
- for (auto &Diagnostic : Doc.Diagnostics) {
- // FIXME: Export all diagnostics, not just the ones with fixes.
- // Update MappingTraits<clang::tooling::Diagnostic>::mapping.
- if (Diagnostic.Fix.size() > 0) {
- Diagnostics.push_back(Diagnostic);
- }
- }
- Io.mapRequired("Diagnostics", Diagnostics);
- Doc.Diagnostics = Diagnostics;
+ Io.mapRequired("Diagnostics", Doc.Diagnostics);
}
};
} // end namespace yaml
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/FixIt.h b/contrib/llvm/tools/clang/include/clang/Tooling/FixIt.h
index e2259d4..c1e5088 100644
--- a/contrib/llvm/tools/clang/include/clang/Tooling/FixIt.h
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/FixIt.h
@@ -65,6 +65,13 @@ FixItHint createReplacement(const D &Destination, const S &Source,
getText(Source, Context));
}
+// \brief Returns a FixItHint to replace \p Destination by \p Source.
+template <typename D>
+FixItHint createReplacement(const D &Destination, StringRef Source) {
+ return FixItHint::CreateReplacement(internal::getSourceRange(Destination),
+ Source);
+}
+
} // end namespace fixit
} // end namespace tooling
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/AtomicChange.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/AtomicChange.h
new file mode 100644
index 0000000..9cccd78
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/AtomicChange.h
@@ -0,0 +1,135 @@
+//===--- AtomicChange.h - AtomicChange class --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines AtomicChange which is used to create a set of source
+// changes, e.g. replacements and header insertions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
+#define LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace tooling {
+
+/// \brief An atomic change is used to create and group a set of source edits,
+/// e.g. replacements or header insertions. Edits in an AtomicChange should be
+/// related, e.g. replacements for the same type reference and the corresponding
+/// header insertion/deletion.
+///
+/// An AtomicChange is uniquely identified by a key and will either be fully
+/// applied or not applied at all.
+///
+/// Calling setError on an AtomicChange stores the error message and marks it as
+/// bad, i.e. none of its source edits will be applied.
+class AtomicChange {
+public:
+ /// \brief Creates an atomic change around \p KeyPosition with the key being a
+ /// concatenation of the file name and the offset of \p KeyPosition.
+ /// \p KeyPosition should be the location of the key syntactical element that
+ /// is being changed, e.g. the call to a refactored method.
+ AtomicChange(const SourceManager &SM, SourceLocation KeyPosition);
+
+ /// \brief Creates an atomic change for \p FilePath with a customized key.
+ AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key)
+ : Key(Key), FilePath(FilePath) {}
+
+ /// \brief Returns the atomic change as a YAML string.
+ std::string toYAMLString();
+
+ /// \brief Converts a YAML-encoded automic change to AtomicChange.
+ static AtomicChange convertFromYAML(llvm::StringRef YAMLContent);
+
+ /// \brief Returns the key of this change, which is a concatenation of the
+ /// file name and offset of the key position.
+ const std::string &getKey() const { return Key; }
+
+ /// \brief Returns the path of the file containing this atomic change.
+ const std::string &getFilePath() const { return FilePath; }
+
+ /// \brief If this change could not be created successfully, e.g. because of
+ /// conflicts among replacements, use this to set an error description.
+ /// Thereby, places that cannot be fixed automatically can be gathered when
+ /// applying changes.
+ void setError(llvm::StringRef Error) { this->Error = Error; }
+
+ /// \brief Returns whether an error has been set on this list.
+ bool hasError() const { return !Error.empty(); }
+
+ /// \brief Returns the error message or an empty string if it does not exist.
+ const std::string &getError() const { return Error; }
+
+ /// \brief Adds a replacement that replaces the given Range with
+ /// ReplacementText.
+ /// \returns An llvm::Error carrying ReplacementError on error.
+ llvm::Error replace(const SourceManager &SM, const CharSourceRange &Range,
+ llvm::StringRef ReplacementText);
+
+ /// \brief Adds a replacement that replaces range [Loc, Loc+Length) with
+ /// \p Text.
+ /// \returns An llvm::Error carrying ReplacementError on error.
+ llvm::Error replace(const SourceManager &SM, SourceLocation Loc,
+ unsigned Length, llvm::StringRef Text);
+
+ /// \brief Adds a replacement that inserts \p Text at \p Loc. If this
+ /// insertion conflicts with an existing insertion (at the same position),
+ /// this will be inserted before/after the existing insertion depending on
+ /// \p InsertAfter. Users should use `replace` with `Length=0` instead if they
+ /// do not want conflict resolving by default. If the conflicting replacement
+ /// is not an insertion, an error is returned.
+ ///
+ /// \returns An llvm::Error carrying ReplacementError on error.
+ llvm::Error insert(const SourceManager &SM, SourceLocation Loc,
+ llvm::StringRef Text, bool InsertAfter = true);
+
+ /// \brief Adds a header into the file that contains the key position.
+ /// Header can be in angle brackets or double quotation marks. By default
+ /// (header is not quoted), header will be surrounded with double quotes.
+ void addHeader(llvm::StringRef Header);
+
+ /// \brief Removes a header from the file that contains the key position.
+ void removeHeader(llvm::StringRef Header);
+
+ /// \brief Returns a const reference to existing replacements.
+ const Replacements &getReplacements() const { return Replaces; }
+
+ llvm::ArrayRef<std::string> getInsertedHeaders() const {
+ return InsertedHeaders;
+ }
+
+ llvm::ArrayRef<std::string> getRemovedHeaders() const {
+ return RemovedHeaders;
+ }
+
+private:
+ AtomicChange() {}
+
+ AtomicChange(std::string Key, std::string FilePath, std::string Error,
+ std::vector<std::string> InsertedHeaders,
+ std::vector<std::string> RemovedHeaders,
+ clang::tooling::Replacements Replaces);
+
+ // This uniquely identifies an AtomicChange.
+ std::string Key;
+ std::string FilePath;
+ std::string Error;
+ std::vector<std::string> InsertedHeaders;
+ std::vector<std::string> RemovedHeaders;
+ tooling::Replacements Replaces;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
new file mode 100644
index 0000000..8b01a61
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
@@ -0,0 +1,122 @@
+//===--- RecursiveSymbolVisitor.h - Clang refactoring library -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief A wrapper class around \c RecursiveASTVisitor that visits each
+/// occurrences of a named symbol.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
+
+#include "clang/AST/AST.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace tooling {
+
+/// Traverses the AST and visits the occurrence of each named symbol in the
+/// given nodes.
+template <typename T>
+class RecursiveSymbolVisitor
+ : public RecursiveASTVisitor<RecursiveSymbolVisitor<T>> {
+ using BaseType = RecursiveASTVisitor<RecursiveSymbolVisitor<T>>;
+
+public:
+ RecursiveSymbolVisitor(const SourceManager &SM, const LangOptions &LangOpts)
+ : SM(SM), LangOpts(LangOpts) {}
+
+ bool visitSymbolOccurrence(const NamedDecl *ND,
+ ArrayRef<SourceRange> NameRanges) {
+ return true;
+ }
+
+ // Declaration visitors:
+
+ bool VisitNamedDecl(const NamedDecl *D) {
+ return isa<CXXConversionDecl>(D) ? true : visit(D, D->getLocation());
+ }
+
+ bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
+ for (const auto *Initializer : CD->inits()) {
+ // Ignore implicit initializers.
+ if (!Initializer->isWritten())
+ continue;
+ if (const FieldDecl *FD = Initializer->getMember()) {
+ if (!visit(FD, Initializer->getSourceLocation(),
+ Lexer::getLocForEndOfToken(Initializer->getSourceLocation(),
+ 0, SM, LangOpts)))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Expression visitors:
+
+ bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
+ return visit(Expr->getFoundDecl(), Expr->getLocation());
+ }
+
+ bool VisitMemberExpr(const MemberExpr *Expr) {
+ return visit(Expr->getFoundDecl().getDecl(), Expr->getMemberLoc());
+ }
+
+ // Other visitors:
+
+ bool VisitTypeLoc(const TypeLoc Loc) {
+ const SourceLocation TypeBeginLoc = Loc.getBeginLoc();
+ const SourceLocation TypeEndLoc =
+ Lexer::getLocForEndOfToken(TypeBeginLoc, 0, SM, LangOpts);
+ if (const auto *TemplateTypeParm =
+ dyn_cast<TemplateTypeParmType>(Loc.getType())) {
+ if (!visit(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc))
+ return false;
+ }
+ if (const auto *TemplateSpecType =
+ dyn_cast<TemplateSpecializationType>(Loc.getType())) {
+ if (!visit(TemplateSpecType->getTemplateName().getAsTemplateDecl(),
+ TypeBeginLoc, TypeEndLoc))
+ return false;
+ }
+ return visit(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc);
+ }
+
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ // The base visitor will visit NNSL prefixes, so we should only look at
+ // the current NNS.
+ if (NNS) {
+ const NamespaceDecl *ND = NNS.getNestedNameSpecifier()->getAsNamespace();
+ if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc()))
+ return false;
+ }
+ return BaseType::TraverseNestedNameSpecifierLoc(NNS);
+ }
+
+private:
+ const SourceManager &SM;
+ const LangOptions &LangOpts;
+
+ bool visit(const NamedDecl *ND, SourceLocation BeginLoc,
+ SourceLocation EndLoc) {
+ return static_cast<T *>(this)->visitSymbolOccurrence(
+ ND, SourceRange(BeginLoc, EndLoc));
+ }
+ bool visit(const NamedDecl *ND, SourceLocation Loc) {
+ return visit(ND, Loc,
+ Loc.getLocWithOffset(ND->getNameAsString().length() - 1));
+ }
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RECURSIVE_SYMBOL_VISITOR_H
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
new file mode 100644
index 0000000..099eaca
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
@@ -0,0 +1,70 @@
+//===--- RenamingAction.h - Clang refactoring library ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to rename every symbol at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
+
+#include "clang/Tooling/Refactoring.h"
+
+namespace clang {
+class ASTConsumer;
+class CompilerInstance;
+
+namespace tooling {
+
+class RenamingAction {
+public:
+ RenamingAction(const std::vector<std::string> &NewNames,
+ const std::vector<std::string> &PrevNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces,
+ bool PrintLocations = false)
+ : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
+ FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {}
+
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+
+private:
+ const std::vector<std::string> &NewNames, &PrevNames;
+ const std::vector<std::vector<std::string>> &USRList;
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+ bool PrintLocations;
+};
+
+/// Rename all symbols identified by the given USRs.
+class QualifiedRenamingAction {
+public:
+ QualifiedRenamingAction(
+ const std::vector<std::string> &NewNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces)
+ : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {}
+
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+
+private:
+ /// New symbol names.
+ const std::vector<std::string> &NewNames;
+
+ /// A list of USRs. Each element represents USRs of a symbol being renamed.
+ const std::vector<std::vector<std::string>> &USRList;
+
+ /// A file path to replacements map.
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_RENAMING_ACTION_H
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFinder.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFinder.h
new file mode 100644
index 0000000..b74a5d7
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFinder.h
@@ -0,0 +1,50 @@
+//===--- USRFinder.h - Clang refactoring library --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Methods for determining the USR of a symbol at a location in source
+/// code.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
+
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTContext.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class SourceLocation;
+class NamedDecl;
+
+namespace tooling {
+
+// Given an AST context and a point, returns a NamedDecl identifying the symbol
+// at the point. Returns null if nothing is found at the point.
+const NamedDecl *getNamedDeclAt(const ASTContext &Context,
+ const SourceLocation Point);
+
+// Given an AST context and a fully qualified name, returns a NamedDecl
+// identifying the symbol with a matching name. Returns null if nothing is
+// found for the name.
+const NamedDecl *getNamedDeclFor(const ASTContext &Context,
+ const std::string &Name);
+
+// Converts a Decl into a USR.
+std::string getUSRForDecl(const Decl *Decl);
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDER_H
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
new file mode 100644
index 0000000..8aafee9
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRFindingAction.h
@@ -0,0 +1,54 @@
+//===--- USRFindingAction.h - Clang refactoring library -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to find all relevant USRs at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+
+#include <string>
+#include <vector>
+
+namespace clang {
+class ASTConsumer;
+class CompilerInstance;
+class NamedDecl;
+
+namespace tooling {
+
+struct USRFindingAction {
+ USRFindingAction(ArrayRef<unsigned> SymbolOffsets,
+ ArrayRef<std::string> QualifiedNames, bool Force)
+ : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
+ ErrorOccurred(false), Force(Force) {}
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+
+ ArrayRef<std::string> getUSRSpellings() { return SpellingNames; }
+ ArrayRef<std::vector<std::string>> getUSRList() { return USRList; }
+ bool errorOccurred() { return ErrorOccurred; }
+
+private:
+ std::vector<unsigned> SymbolOffsets;
+ std::vector<std::string> QualifiedNames;
+ std::vector<std::string> SpellingNames;
+ std::vector<std::vector<std::string>> USRList;
+ bool ErrorOccurred;
+ bool Force;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_FINDING_ACTION_H
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
new file mode 100644
index 0000000..733ea1a
--- /dev/null
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/Refactoring/Rename/USRLocFinder.h
@@ -0,0 +1,49 @@
+//===--- USRLocFinder.h - Clang refactoring library -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides functionality for finding all instances of a USR in a given
+/// AST.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
+#define LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
+
+#include "clang/AST/AST.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+/// Create atomic changes for renaming all symbol references which are
+/// identified by the USRs set to a given new name.
+///
+/// \param USRs The set containing USRs of a particular old symbol.
+/// \param NewName The new name to replace old symbol name.
+/// \param TranslationUnitDecl The translation unit declaration.
+///
+/// \return Atomic changes for renaming.
+std::vector<tooling::AtomicChange>
+createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
+ llvm::StringRef NewName, Decl *TranslationUnitDecl);
+
+// FIXME: make this an AST matcher. Wouldn't that be awesome??? I agree!
+std::vector<SourceLocation>
+getLocationsOfUSRs(const std::vector<std::string> &USRs,
+ llvm::StringRef PrevName, Decl *Decl);
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_RENAME_USR_LOC_FINDER_H
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/RefactoringCallbacks.h b/contrib/llvm/tools/clang/include/clang/Tooling/RefactoringCallbacks.h
index 6ef9ea1..9862951 100644
--- a/contrib/llvm/tools/clang/include/clang/Tooling/RefactoringCallbacks.h
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/RefactoringCallbacks.h
@@ -47,6 +47,33 @@ protected:
Replacements Replace;
};
+/// \brief Adaptor between \c ast_matchers::MatchFinder and \c
+/// tooling::RefactoringTool.
+///
+/// Runs AST matchers and stores the \c tooling::Replacements in a map.
+class ASTMatchRefactorer {
+public:
+ explicit ASTMatchRefactorer(
+ std::map<std::string, Replacements> &FileToReplaces);
+
+ template <typename T>
+ void addMatcher(const T &Matcher, RefactoringCallback *Callback) {
+ MatchFinder.addMatcher(Matcher, Callback);
+ Callbacks.push_back(Callback);
+ }
+
+ void addDynamicMatcher(const ast_matchers::internal::DynTypedMatcher &Matcher,
+ RefactoringCallback *Callback);
+
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+
+private:
+ friend class RefactoringASTConsumer;
+ std::vector<RefactoringCallback *> Callbacks;
+ ast_matchers::MatchFinder MatchFinder;
+ std::map<std::string, Replacements> &FileToReplaces;
+};
+
/// \brief Replace the text of the statement bound to \c FromId with the text in
/// \c ToText.
class ReplaceStmtWithText : public RefactoringCallback {
@@ -59,6 +86,29 @@ private:
std::string ToText;
};
+/// \brief Replace the text of an AST node bound to \c FromId with the result of
+/// evaluating the template in \c ToTemplate.
+///
+/// Expressions of the form ${NodeName} in \c ToTemplate will be
+/// replaced by the text of the node bound to ${NodeName}. The string
+/// "$$" will be replaced by "$".
+class ReplaceNodeWithTemplate : public RefactoringCallback {
+public:
+ static llvm::Expected<std::unique_ptr<ReplaceNodeWithTemplate>>
+ create(StringRef FromId, StringRef ToTemplate);
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ struct TemplateElement {
+ enum { Literal, Identifier } Type;
+ std::string Value;
+ };
+ ReplaceNodeWithTemplate(llvm::StringRef FromId,
+ std::vector<TemplateElement> Template);
+ std::string FromId;
+ std::vector<TemplateElement> Template;
+};
+
/// \brief Replace the text of the statement bound to \c FromId with the text of
/// the statement bound to \c ToId.
class ReplaceStmtWithStmt : public RefactoringCallback {
diff --git a/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h b/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h
index 10e26ac..6f9bc9e 100644
--- a/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h
+++ b/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h
@@ -116,7 +116,7 @@ public:
/// \brief Called before a source file is processed by a FrontEndAction.
/// \see clang::FrontendAction::BeginSourceFileAction
- virtual bool handleBeginSource(CompilerInstance &CI, StringRef Filename) {
+ virtual bool handleBeginSource(CompilerInstance &CI) {
return true;
}
@@ -202,12 +202,15 @@ buildASTFromCode(const Twine &Code, const Twine &FileName = "input.cc",
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
/// clang modules.
///
+/// \param Adjuster A function to filter the command line arguments as specified.
+///
/// \return The resulting AST or null if an error occurred.
std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
const Twine &Code, const std::vector<std::string> &Args,
const Twine &FileName = "input.cc", const Twine &ToolName = "clang-tool",
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
- std::make_shared<PCHContainerOperations>());
+ std::make_shared<PCHContainerOperations>(),
+ ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster());
/// \brief Utility to run a FrontendAction in a single clang invocation.
class ToolInvocation {
@@ -388,12 +391,11 @@ inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
}
protected:
- bool BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) override {
- if (!clang::ASTFrontendAction::BeginSourceFileAction(CI, Filename))
+ bool BeginSourceFileAction(CompilerInstance &CI) override {
+ if (!clang::ASTFrontendAction::BeginSourceFileAction(CI))
return false;
if (Callbacks)
- return Callbacks->handleBeginSource(CI, Filename);
+ return Callbacks->handleBeginSource(CI);
return true;
}
void EndSourceFileAction() override {
diff --git a/contrib/llvm/tools/clang/include/clang/module.modulemap b/contrib/llvm/tools/clang/include/clang/module.modulemap
index 3b423811..d850bd5 100644
--- a/contrib/llvm/tools/clang/include/clang/module.modulemap
+++ b/contrib/llvm/tools/clang/include/clang/module.modulemap
@@ -33,6 +33,7 @@ module Clang_Basic {
textual header "Basic/BuiltinsLe64.def"
textual header "Basic/BuiltinsMips.def"
textual header "Basic/BuiltinsNEON.def"
+ textual header "Basic/BuiltinsNios2.def"
textual header "Basic/BuiltinsNVPTX.def"
textual header "Basic/BuiltinsPPC.def"
textual header "Basic/BuiltinsSystemZ.def"
@@ -132,7 +133,7 @@ module Clang_StaticAnalyzer_Frontend {
module Clang_Tooling {
requires cplusplus umbrella "Tooling" module * { export * }
- // FIXME: Exclude this header to avoid pulling all of the AST matchers
+ // FIXME: Exclude these headers to avoid pulling all of the AST matchers
// library into clang-format. Due to inline key functions in the headers,
// importing the AST matchers library gives a link dependency on the AST
// matchers (and thus the AST), which clang-format should not have.
diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp
index 241a724..fcc67da 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp
+++ b/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp
@@ -2189,7 +2189,7 @@ static std::string applyEditsToTemp(const FileEntry *FE,
Rewriter rewriter(SM, LangOpts);
RewritesReceiver Rec(rewriter);
- Editor.applyRewrites(Rec);
+ Editor.applyRewrites(Rec, /*adjustRemovals=*/false);
const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID);
SmallString<512> NewText;
diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index f81133f..389f365 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -78,6 +78,7 @@ public:
}
}
// Pass through.
+ LLVM_FALLTHROUGH;
case OMF_retain:
case OMF_release:
if (E->getReceiverKind() == ObjCMessageExpr::Instance)
diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp
index c628b54..4f3fb58 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp
+++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp
@@ -539,6 +539,7 @@ void TransformActionsImpl::addRemoval(CharSourceRange range) {
return;
case Range_Contains:
RI->End = newRange.End;
+ LLVM_FALLTHROUGH;
case Range_ExtendsBegin:
newRange.End = RI->End;
Removals.erase(RI);
diff --git a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp
index b531a66..c60373c 100644
--- a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp
@@ -703,6 +703,7 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
// The fake address space map must have a distinct entry for each
// language-specific address space.
static const unsigned FakeAddrSpaceMap[] = {
+ 0, // Default
1, // opencl_global
3, // opencl_local
2, // opencl_constant
@@ -748,6 +749,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
ExternCContext(nullptr), MakeIntegerSeqDecl(nullptr),
TypePackElementDecl(nullptr), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
+ XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles,
+ LangOpts.XRayNeverInstrumentFiles, SM)),
AddrSpaceMap(nullptr), Target(nullptr), AuxTarget(nullptr),
PrintingPolicy(LOpts), Idents(idents), Selectors(sels),
BuiltinInfo(builtins), DeclarationNames(*this), ExternalSource(nullptr),
@@ -891,7 +894,7 @@ void ASTContext::mergeDefinitionIntoModule(NamedDecl *ND, Module *M,
if (getLangOpts().ModulesLocalVisibility)
MergedDefModules[ND].push_back(M);
else
- ND->setHidden(false);
+ ND->setVisibleDespiteOwningModule();
}
void ASTContext::deduplicateMergedDefinitonsFor(NamedDecl *ND) {
@@ -1167,7 +1170,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
InitBuiltinType(OCLEventTy, BuiltinType::OCLEvent);
InitBuiltinType(OCLClkEventTy, BuiltinType::OCLClkEvent);
InitBuiltinType(OCLQueueTy, BuiltinType::OCLQueue);
- InitBuiltinType(OCLNDRangeTy, BuiltinType::OCLNDRange);
InitBuiltinType(OCLReserveIDTy, BuiltinType::OCLReserveID);
}
@@ -1474,6 +1476,8 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
}
}
Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
+ if (BaseT.getQualifiers().hasUnaligned())
+ Align = Target->getCharWidth();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasGlobalStorage() && !ForAlignof)
Align = std::max(Align, getTargetInfo().getMinGlobalAlign());
@@ -1775,7 +1779,6 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
// Currently these types are pointers to opaque types.
Width = Target->getPointerWidth(0);
@@ -1877,8 +1880,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
return getTypeInfo(cast<SubstTemplateTypeParmType>(T)->
getReplacementType().getTypePtr());
- case Type::Auto: {
- const AutoType *A = cast<AutoType>(T);
+ case Type::Auto:
+ case Type::DeducedTemplateSpecialization: {
+ const DeducedType *A = cast<DeducedType>(T);
assert(!A->getDeducedType().isNull() &&
"cannot request the size of an undeduced or dependent auto type");
return getTypeInfo(A->getDeducedType().getTypePtr());
@@ -1935,9 +1939,8 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
break;
case Type::Pipe: {
- TypeInfo Info = getTypeInfo(cast<PipeType>(T)->getElementType());
- Width = Info.Width;
- Align = Info.Align;
+ Width = Target->getPointerWidth(getTargetAddressSpace(LangAS::opencl_global));
+ Align = Target->getPointerAlign(getTargetAddressSpace(LangAS::opencl_global));
}
}
@@ -2691,8 +2694,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
// Convert the array size into a canonical width matching the pointer size for
// the target.
llvm::APInt ArySize(ArySizeIn);
- ArySize =
- ArySize.zextOrTrunc(Target->getPointerWidth(getTargetAddressSpace(EltTy)));
+ ArySize = ArySize.zextOrTrunc(Target->getMaxPointerWidth());
llvm::FoldingSetNodeID ID;
ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
@@ -2765,6 +2767,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
case Type::PackExpansion:
llvm_unreachable("type should never be variably-modified");
@@ -3562,7 +3565,7 @@ QualType ASTContext::getSubstTemplateTypeParmPackType(
= new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon,
ArgPack);
Types.push_back(SubstParm);
- SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
+ SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos);
return QualType(SubstParm, 0);
}
@@ -3785,12 +3788,8 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
QualType Canon) const {
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
- ElaboratedTypeKeyword CanonKeyword = Keyword;
- if (Keyword == ETK_None)
- CanonKeyword = ETK_Typename;
-
- if (CanonNNS != NNS || CanonKeyword != Keyword)
- Canon = getDependentNameType(CanonKeyword, CanonNNS, Name);
+ if (CanonNNS != NNS)
+ Canon = getDependentNameType(Keyword, CanonNNS, Name);
}
llvm::FoldingSetNodeID ID;
@@ -3874,42 +3873,45 @@ ASTContext::getDependentTemplateSpecializationType(
return QualType(T, 0);
}
+TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
+ TemplateArgument Arg;
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ QualType ArgType = getTypeDeclType(TTP);
+ if (TTP->isParameterPack())
+ ArgType = getPackExpansionType(ArgType, None);
+
+ Arg = TemplateArgument(ArgType);
+ } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ Expr *E = new (*this) DeclRefExpr(
+ NTTP, /*enclosing*/false,
+ NTTP->getType().getNonLValueExprType(*this),
+ Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation());
+
+ if (NTTP->isParameterPack())
+ E = new (*this) PackExpansionExpr(DependentTy, E, NTTP->getLocation(),
+ None);
+ Arg = TemplateArgument(E);
+ } else {
+ auto *TTP = cast<TemplateTemplateParmDecl>(Param);
+ if (TTP->isParameterPack())
+ Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
+ else
+ Arg = TemplateArgument(TemplateName(TTP));
+ }
+
+ if (Param->isTemplateParameterPack())
+ Arg = TemplateArgument::CreatePackCopy(*this, Arg);
+
+ return Arg;
+}
+
void
ASTContext::getInjectedTemplateArgs(const TemplateParameterList *Params,
SmallVectorImpl<TemplateArgument> &Args) {
Args.reserve(Args.size() + Params->size());
- for (NamedDecl *Param : *Params) {
- TemplateArgument Arg;
- if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
- QualType ArgType = getTypeDeclType(TTP);
- if (TTP->isParameterPack())
- ArgType = getPackExpansionType(ArgType, None);
-
- Arg = TemplateArgument(ArgType);
- } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- Expr *E = new (*this) DeclRefExpr(
- NTTP, /*enclosing*/false,
- NTTP->getType().getNonLValueExprType(*this),
- Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation());
-
- if (NTTP->isParameterPack())
- E = new (*this) PackExpansionExpr(DependentTy, E, NTTP->getLocation(),
- None);
- Arg = TemplateArgument(E);
- } else {
- auto *TTP = cast<TemplateTemplateParmDecl>(Param);
- if (TTP->isParameterPack())
- Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
- else
- Arg = TemplateArgument(TemplateName(TTP));
- }
-
- if (Param->isTemplateParameterPack())
- Arg = TemplateArgument::CreatePackCopy(*this, Arg);
-
- Args.push_back(Arg);
- }
+ for (NamedDecl *Param : *Params)
+ Args.push_back(getInjectedTemplateArg(Param));
}
QualType ASTContext::getPackExpansionType(QualType Pattern,
@@ -4439,6 +4441,28 @@ QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
return QualType(AT, 0);
}
+/// Return the uniqued reference to the deduced template specialization type
+/// which has been deduced to the given type, or to the canonical undeduced
+/// such type, or the canonical deduced-but-dependent such type.
+QualType ASTContext::getDeducedTemplateSpecializationType(
+ TemplateName Template, QualType DeducedType, bool IsDependent) const {
+ // Look in the folding set for an existing type.
+ void *InsertPos = nullptr;
+ llvm::FoldingSetNodeID ID;
+ DeducedTemplateSpecializationType::Profile(ID, Template, DeducedType,
+ IsDependent);
+ if (DeducedTemplateSpecializationType *DTST =
+ DeducedTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(DTST, 0);
+
+ DeducedTemplateSpecializationType *DTST = new (*this, TypeAlignment)
+ DeducedTemplateSpecializationType(Template, DeducedType, IsDependent);
+ Types.push_back(DTST);
+ if (InsertPos)
+ DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos);
+ return QualType(DTST, 0);
+}
+
/// getAtomicType - Return the uniqued reference to the atomic type for
/// the given value type.
QualType ASTContext::getAtomicType(QualType T) const {
@@ -4501,6 +4525,12 @@ CanQualType ASTContext::getSizeType() const {
return getFromTargetType(Target->getSizeType());
}
+/// Return the unique signed counterpart of the integer type
+/// corresponding to size_t.
+CanQualType ASTContext::getSignedSizeType() const {
+ return getFromTargetType(Target->getSignedSizeType());
+}
+
/// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5).
CanQualType ASTContext::getIntMaxType() const {
return getFromTargetType(Target->getIntMaxType());
@@ -5922,7 +5952,6 @@ static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
case BuiltinType::OCLSampler:
case BuiltinType::Dependent:
@@ -5967,9 +5996,19 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
// compatibility with GCC, although providing it breaks anything that
// actually uses runtime introspection and wants to work on both runtimes...
if (Ctx->getLangOpts().ObjCRuntime.isGNUFamily()) {
- const RecordDecl *RD = FD->getParent();
- const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD);
- S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex()));
+ uint64_t Offset;
+
+ if (const auto *IVD = dyn_cast<ObjCIvarDecl>(FD)) {
+ Offset = Ctx->lookupFieldBitOffset(IVD->getContainingInterface(), nullptr,
+ IVD);
+ } else {
+ const RecordDecl *RD = FD->getParent();
+ const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD);
+ Offset = RL.getFieldOffset(FD->getFieldIndex());
+ }
+
+ S += llvm::utostr(Offset);
+
if (const EnumType *ET = T->getAs<EnumType>())
S += ObjCEncodingForEnumType(Ctx, ET);
else {
@@ -6216,6 +6255,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += "{objc_class=}";
return;
}
+ // TODO: Double check to make sure this intentially falls through.
+ LLVM_FALLTHROUGH;
}
case Type::ObjCInterface: {
@@ -6337,6 +6378,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// We could see an undeduced auto type here during error recovery.
// Just ignore it.
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
return;
case Type::Pipe:
@@ -7893,6 +7935,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult())
return QualType();
+ if (lbaseInfo.getNoCallerSavedRegs() != rbaseInfo.getNoCallerSavedRegs())
+ return QualType();
// FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
@@ -8043,20 +8087,12 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
Qualifiers LQuals = LHSCan.getLocalQualifiers();
Qualifiers RQuals = RHSCan.getLocalQualifiers();
if (LQuals != RQuals) {
- if (getLangOpts().OpenCL) {
- if (LHSCan.getUnqualifiedType() != RHSCan.getUnqualifiedType() ||
- LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers())
- return QualType();
- if (LQuals.isAddressSpaceSupersetOf(RQuals))
- return LHS;
- if (RQuals.isAddressSpaceSupersetOf(LQuals))
- return RHS;
- }
// If any of these qualifiers are different, we have a type
// mismatch.
if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() ||
LQuals.getAddressSpace() != RQuals.getAddressSpace() ||
- LQuals.getObjCLifetime() != RQuals.getObjCLifetime())
+ LQuals.getObjCLifetime() != RQuals.getObjCLifetime() ||
+ LQuals.hasUnaligned() != RQuals.hasUnaligned())
return QualType();
// Exactly one GC qualifier difference is allowed: __strong is
@@ -8136,6 +8172,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
llvm_unreachable("Non-canonical and dependent types shouldn't get here");
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
case Type::LValueReference:
case Type::RValueReference:
case Type::MemberPointer:
@@ -8175,6 +8212,20 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
LHSPointee = LHSPointee.getUnqualifiedType();
RHSPointee = RHSPointee.getUnqualifiedType();
}
+ if (getLangOpts().OpenCL) {
+ Qualifiers LHSPteeQual = LHSPointee.getQualifiers();
+ Qualifiers RHSPteeQual = RHSPointee.getQualifiers();
+ // Blocks can't be an expression in a ternary operator (OpenCL v2.0
+ // 6.12.5) thus the following check is asymmetric.
+ if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual))
+ return QualType();
+ LHSPteeQual.removeAddressSpace();
+ RHSPteeQual.removeAddressSpace();
+ LHSPointee =
+ QualType(LHSPointee.getTypePtr(), LHSPteeQual.getAsOpaqueValue());
+ RHSPointee =
+ QualType(RHSPointee.getTypePtr(), RHSPteeQual.getAsOpaqueValue());
+ }
QualType ResultType = mergeTypes(LHSPointee, RHSPointee, OfBlockPointer,
Unqualified);
if (ResultType.isNull()) return QualType();
@@ -8479,6 +8530,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
// Read the prefixed modifiers first.
bool Done = false;
+ #ifndef NDEBUG
+ bool IsSpecialLong = false;
+ #endif
while (!Done) {
switch (*Str++) {
default: Done = true; --Str; break;
@@ -8496,12 +8550,28 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
Unsigned = true;
break;
case 'L':
+ assert(!IsSpecialLong && "Can't use 'L' with 'W' or 'N' modifiers");
assert(HowLong <= 2 && "Can't have LLLL modifier");
++HowLong;
break;
+ case 'N': {
+ // 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise.
+ assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!");
+ assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!");
+ #ifndef NDEBUG
+ IsSpecialLong = true;
+ #endif
+ if (Context.getTargetInfo().getLongWidth() == 32)
+ ++HowLong;
+ break;
+ }
case 'W':
// This modifier represents int64 type.
+ assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!");
assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!");
+ #ifndef NDEBUG
+ IsSpecialLong = true;
+ #endif
switch (Context.getTargetInfo().getInt64Type()) {
default:
llvm_unreachable("Unexpected integer type");
@@ -8512,6 +8582,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
HowLong = 2;
break;
}
+ break;
}
}
@@ -8696,7 +8767,8 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
char *End;
unsigned AddrSpace = strtoul(Str, &End, 10);
if (End != Str && AddrSpace != 0) {
- Type = Context.getAddrSpaceQualType(Type, AddrSpace);
+ Type = Context.getAddrSpaceQualType(
+ Type, AddrSpace + LangAS::FirstTargetAddressSpace);
Str = End;
}
if (c == '*')
@@ -8788,7 +8860,7 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
if (!FD->isExternallyVisible())
return GVA_Internal;
- GVALinkage External = GVA_StrongExternal;
+ GVALinkage External;
switch (FD->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
@@ -8860,8 +8932,22 @@ static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context,
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
- return adjustGVALinkageForAttributes(
+ auto L = adjustGVALinkageForAttributes(
*this, basicGVALinkageForFunction(*this, FD), FD);
+ auto EK = ExternalASTSource::EK_ReplyHazy;
+ if (auto *Ext = getExternalSource())
+ EK = Ext->hasExternalDefinitions(FD);
+ switch (EK) {
+ case ExternalASTSource::EK_Never:
+ if (L == GVA_DiscardableODR)
+ return GVA_StrongODR;
+ break;
+ case ExternalASTSource::EK_Always:
+ return GVA_AvailableExternally;
+ case ExternalASTSource::EK_ReplyHazy:
+ break;
+ }
+ return L;
}
static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
@@ -8870,22 +8956,30 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
return GVA_Internal;
if (VD->isStaticLocal()) {
- GVALinkage StaticLocalLinkage = GVA_DiscardableODR;
const DeclContext *LexicalContext = VD->getParentFunctionOrMethod();
while (LexicalContext && !isa<FunctionDecl>(LexicalContext))
LexicalContext = LexicalContext->getLexicalParent();
- // Let the static local variable inherit its linkage from the nearest
- // enclosing function.
- if (LexicalContext)
- StaticLocalLinkage =
- Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
+ // ObjC Blocks can create local variables that don't have a FunctionDecl
+ // LexicalContext.
+ if (!LexicalContext)
+ return GVA_DiscardableODR;
+
+ // Otherwise, let the static local variable inherit its linkage from the
+ // nearest enclosing function.
+ auto StaticLocalLinkage =
+ Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
- // GVA_StrongODR function linkage is stronger than what we need,
- // downgrade to GVA_DiscardableODR.
- // This allows us to discard the variable if we never end up needing it.
- return StaticLocalLinkage == GVA_StrongODR ? GVA_DiscardableODR
- : StaticLocalLinkage;
+ // Itanium ABI 5.2.2: "Each COMDAT group [for a static local variable] must
+ // be emitted in any object with references to the symbol for the object it
+ // contains, whether inline or out-of-line."
+ // Similar behavior is observed with MSVC. An alternative ABI could use
+ // StrongODR/AvailableExternally to match the function, but none are
+ // known/supported currently.
+ if (StaticLocalLinkage == GVA_StrongODR ||
+ StaticLocalLinkage == GVA_AvailableExternally)
+ return GVA_DiscardableODR;
+ return StaticLocalLinkage;
}
// MSVC treats in-class initialized static data members as definitions.
@@ -9002,10 +9096,12 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
}
}
+ GVALinkage Linkage = GetGVALinkageForFunction(FD);
+
// static, static inline, always_inline, and extern inline functions can
// always be deferred. Normal inline functions can be deferred in C99/C++.
// Implicit template instantiations can also be deferred in C++.
- return !isDiscardableGVALinkage(GetGVALinkageForFunction(FD));
+ return !isDiscardableGVALinkage(Linkage);
}
const VarDecl *VD = cast<VarDecl>(D);
@@ -9357,10 +9453,8 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) {
if (!NodeOrVector.template is<ASTContext::ParentVector *>()) {
auto *Vector = new ASTContext::ParentVector(
1, getSingleDynTypedNodeFromParentMap(NodeOrVector));
- if (auto *Node =
- NodeOrVector
- .template dyn_cast<ast_type_traits::DynTypedNode *>())
- delete Node;
+ delete NodeOrVector
+ .template dyn_cast<ast_type_traits::DynTypedNode *>();
NodeOrVector = Vector;
}
@@ -9488,6 +9582,13 @@ uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
return getTargetInfo().getNullPointerValue(AS);
}
+unsigned ASTContext::getTargetAddressSpace(unsigned AS) const {
+ if (AS >= LangAS::FirstTargetAddressSpace)
+ return AS - LangAS::FirstTargetAddressSpace;
+ else
+ return (*AddrSpaceMap)[AS];
+}
+
// Explicitly instantiate this in case a Redeclarable<T> is used from a TU that
// doesn't include ASTContext.h
template
diff --git a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp
index 03e6115..b43c28d 100644
--- a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp
@@ -360,6 +360,7 @@ void clang::FormatASTNodeDiagnosticArgument(
Modifier = StringRef();
Argument = StringRef();
// Fall through
+ LLVM_FALLTHROUGH;
}
case DiagnosticsEngine::ak_qualtype: {
assert(Modifier.empty() && Argument.empty() &&
diff --git a/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp
index 62261cc..92ed7da 100644
--- a/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp
@@ -102,22 +102,26 @@ namespace {
/// Pending[i] is an action to dump an entity at level i.
llvm::SmallVector<std::function<void(bool isLastChild)>, 32> Pending;
+ /// Indicates whether we should trigger deserialization of nodes that had
+ /// not already been loaded.
+ bool Deserialize = false;
+
/// Indicates whether we're at the top level.
- bool TopLevel;
+ bool TopLevel = true;
/// Indicates if we're handling the first child after entering a new depth.
- bool FirstChild;
+ bool FirstChild = true;
/// Prefix for currently-being-dumped entity.
std::string Prefix;
/// Keep track of the last location we print out so that we can
/// print out deltas from then on out.
- const char *LastLocFilename;
- unsigned LastLocLine;
+ const char *LastLocFilename = "";
+ unsigned LastLocLine = ~0U;
/// The \c FullComment parent of the comment being dumped.
- const FullComment *FC;
+ const FullComment *FC = nullptr;
bool ShowColors;
@@ -203,15 +207,14 @@ namespace {
public:
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM)
- : OS(OS), Traits(Traits), SM(SM), TopLevel(true), FirstChild(true),
- LastLocFilename(""), LastLocLine(~0U), FC(nullptr),
+ : OS(OS), Traits(Traits), SM(SM),
ShowColors(SM && SM->getDiagnostics().getShowColors()) { }
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM, bool ShowColors)
- : OS(OS), Traits(Traits), SM(SM), TopLevel(true), FirstChild(true),
- LastLocFilename(""), LastLocLine(~0U),
- ShowColors(ShowColors) { }
+ : OS(OS), Traits(Traits), SM(SM), ShowColors(ShowColors) {}
+
+ void setDeserialize(bool D) { Deserialize = D; }
void dumpDecl(const Decl *D);
void dumpStmt(const Stmt *S);
@@ -764,14 +767,15 @@ bool ASTDumper::hasNodes(const DeclContext *DC) {
return false;
return DC->hasExternalLexicalStorage() ||
- DC->noload_decls_begin() != DC->noload_decls_end();
+ (Deserialize ? DC->decls_begin() != DC->decls_end()
+ : DC->noload_decls_begin() != DC->noload_decls_end());
}
void ASTDumper::dumpDeclContext(const DeclContext *DC) {
if (!DC)
return;
- for (auto *D : DC->noload_decls())
+ for (auto *D : (Deserialize ? DC->decls() : DC->noload_decls()))
dumpDecl(D);
if (DC->hasExternalLexicalStorage()) {
@@ -795,11 +799,13 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
- DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(),
- E = Primary->noload_lookups_end();
- while (I != E) {
+ for (auto I = Deserialize ? Primary->lookups_begin()
+ : Primary->noload_lookups_begin(),
+ E = Deserialize ? Primary->lookups_end()
+ : Primary->noload_lookups_end();
+ I != E; ++I) {
DeclarationName Name = I.getLookupName();
- DeclContextLookupResult R = *I++;
+ DeclContextLookupResult R = *I;
dumpChild([=] {
OS << "DeclarationName ";
@@ -1032,10 +1038,10 @@ void ASTDumper::dumpDecl(const Decl *D) {
dumpSourceRange(D->getSourceRange());
OS << ' ';
dumpLocation(D->getLocation());
- if (Module *M = D->getImportedOwningModule())
+ if (D->isFromASTFile())
+ OS << " imported";
+ if (Module *M = D->getOwningModule())
OS << " in " << M->getFullModuleName();
- else if (Module *M = D->getLocalOwningModule())
- OS << " in (local) " << M->getFullModuleName();
if (auto *ND = dyn_cast<NamedDecl>(D))
for (Module *M : D->getASTContext().getModulesWithMergedDefinition(
const_cast<NamedDecl *>(ND)))
@@ -1178,6 +1184,27 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
I != E; ++I)
dumpCXXCtorInitializer(*I);
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D))
+ if (MD->size_overridden_methods() != 0) {
+ auto dumpOverride =
+ [=](const CXXMethodDecl *D) {
+ SplitQualType T_split = D->getType().split();
+ OS << D << " " << D->getParent()->getName() << "::"
+ << D->getNameAsString() << " '" << QualType::getAsString(T_split) << "'";
+ };
+
+ dumpChild([=] {
+ auto FirstOverrideItr = MD->begin_overridden_methods();
+ OS << "Overrides: [ ";
+ dumpOverride(*FirstOverrideItr);
+ for (const auto *Override :
+ llvm::make_range(FirstOverrideItr + 1,
+ MD->end_overridden_methods()))
+ dumpOverride(Override);
+ OS << " ]";
+ });
+ }
+
if (D->doesThisDeclarationHaveABody())
dumpStmt(D->getBody());
}
@@ -1463,6 +1490,7 @@ void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
OS << " typename";
else
OS << " class";
+ OS << " depth " << D->getDepth() << " index " << D->getIndex();
if (D->isParameterPack())
OS << " ...";
dumpName(D);
@@ -1472,6 +1500,7 @@ void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
dumpType(D->getType());
+ OS << " depth " << D->getDepth() << " index " << D->getIndex();
if (D->isParameterPack())
OS << " ...";
dumpName(D);
@@ -1481,6 +1510,7 @@ void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
void ASTDumper::VisitTemplateTemplateParmDecl(
const TemplateTemplateParmDecl *D) {
+ OS << " depth " << D->getDepth() << " index " << D->getIndex();
if (D->isParameterPack())
OS << " ...";
dumpName(D);
@@ -2504,9 +2534,10 @@ LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const {
LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
-LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS) const {
+LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const {
ASTDumper P(OS, &getASTContext().getCommentCommandTraits(),
&getASTContext().getSourceManager());
+ P.setDeserialize(Deserialize);
P.dumpDecl(this);
}
@@ -2521,12 +2552,14 @@ LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
}
LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS,
- bool DumpDecls) const {
+ bool DumpDecls,
+ bool Deserialize) const {
const DeclContext *DC = this;
while (!DC->isTranslationUnit())
DC = DC->getParent();
ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager());
+ P.setDeserialize(Deserialize);
P.dumpLookups(this, DumpDecls);
}
diff --git a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp
index 1ccb746..2c0bb11 100644
--- a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ASTImporter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
@@ -72,7 +73,7 @@ namespace clang {
QualType VisitEnumType(const EnumType *T);
QualType VisitAttributedType(const AttributedType *T);
QualType VisitTemplateTypeParmType(const TemplateTypeParmType *T);
- // FIXME: SubstTemplateTypeParmType
+ QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
QualType VisitElaboratedType(const ElaboratedType *T);
// FIXME: DependentNameType
@@ -278,6 +279,8 @@ namespace clang {
Expr *VisitArrayInitIndexExpr(ArrayInitIndexExpr *E);
Expr *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E);
Expr *VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
+ Expr *VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E);
+
template<typename IIter, typename OIter>
void ImportArray(IIter Ibegin, IIter Iend, OIter Obegin) {
@@ -316,1287 +319,18 @@ namespace clang {
bool ImportArrayChecked(const InContainerTy &InContainer, OIter Obegin) {
return ImportArrayChecked(InContainer.begin(), InContainer.end(), Obegin);
}
- };
-}
-
-using namespace clang;
-
-//----------------------------------------------------------------------------
-// Structural Equivalence
-//----------------------------------------------------------------------------
-
-namespace {
- struct StructuralEquivalenceContext {
- /// \brief AST contexts for which we are checking structural equivalence.
- ASTContext &C1, &C2;
-
- /// \brief The set of "tentative" equivalences between two canonical
- /// declarations, mapping from a declaration in the first context to the
- /// declaration in the second context that we believe to be equivalent.
- llvm::DenseMap<Decl *, Decl *> TentativeEquivalences;
-
- /// \brief Queue of declarations in the first context whose equivalence
- /// with a declaration in the second context still needs to be verified.
- std::deque<Decl *> DeclsToCheck;
-
- /// \brief Declaration (from, to) pairs that are known not to be equivalent
- /// (which we have already complained about).
- llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls;
-
- /// \brief Whether we're being strict about the spelling of types when
- /// unifying two types.
- bool StrictTypeSpelling;
-
- /// \brief Whether to complain about failures.
- bool Complain;
-
- /// \brief \c true if the last diagnostic came from C2.
- bool LastDiagFromC2;
-
- StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2,
- llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls,
- bool StrictTypeSpelling = false,
- bool Complain = true)
- : C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls),
- StrictTypeSpelling(StrictTypeSpelling), Complain(Complain),
- LastDiagFromC2(false) {}
-
- /// \brief Determine whether the two declarations are structurally
- /// equivalent.
- bool IsStructurallyEquivalent(Decl *D1, Decl *D2);
-
- /// \brief Determine whether the two types are structurally equivalent.
- bool IsStructurallyEquivalent(QualType T1, QualType T2);
-
- private:
- /// \brief Finish checking all of the structural equivalences.
- ///
- /// \returns true if an error occurred, false otherwise.
- bool Finish();
-
- public:
- DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
- assert(Complain && "Not allowed to complain");
- if (LastDiagFromC2)
- C1.getDiagnostics().notePriorDiagnosticFrom(C2.getDiagnostics());
- LastDiagFromC2 = false;
- return C1.getDiagnostics().Report(Loc, DiagID);
- }
- DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
- assert(Complain && "Not allowed to complain");
- if (!LastDiagFromC2)
- C2.getDiagnostics().notePriorDiagnosticFrom(C1.getDiagnostics());
- LastDiagFromC2 = true;
- return C2.getDiagnostics().Report(Loc, DiagID);
- }
+ // Importing overrides.
+ void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod);
};
}
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- QualType T1, QualType T2);
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- Decl *D1, Decl *D2);
-
-/// \brief Determine structural equivalence of two expressions.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- Expr *E1, Expr *E2) {
- if (!E1 || !E2)
- return E1 == E2;
-
- // FIXME: Actually perform a structural comparison!
- return true;
-}
-
-/// \brief Determine whether two identifiers are equivalent.
-static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
- const IdentifierInfo *Name2) {
- if (!Name1 || !Name2)
- return Name1 == Name2;
-
- return Name1->getName() == Name2->getName();
-}
-
-/// \brief Determine whether two nested-name-specifiers are equivalent.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- NestedNameSpecifier *NNS1,
- NestedNameSpecifier *NNS2) {
- // FIXME: Implement!
- return true;
-}
-
-/// \brief Determine whether two template arguments are equivalent.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const TemplateArgument &Arg1,
- const TemplateArgument &Arg2) {
- if (Arg1.getKind() != Arg2.getKind())
- return false;
-
- switch (Arg1.getKind()) {
- case TemplateArgument::Null:
- return true;
-
- case TemplateArgument::Type:
- return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType());
-
- case TemplateArgument::Integral:
- if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(),
- Arg2.getIntegralType()))
- return false;
-
- return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral());
-
- case TemplateArgument::Declaration:
- return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl());
-
- case TemplateArgument::NullPtr:
- return true; // FIXME: Is this correct?
-
- case TemplateArgument::Template:
- return IsStructurallyEquivalent(Context,
- Arg1.getAsTemplate(),
- Arg2.getAsTemplate());
-
- case TemplateArgument::TemplateExpansion:
- return IsStructurallyEquivalent(Context,
- Arg1.getAsTemplateOrTemplatePattern(),
- Arg2.getAsTemplateOrTemplatePattern());
-
- case TemplateArgument::Expression:
- return IsStructurallyEquivalent(Context,
- Arg1.getAsExpr(), Arg2.getAsExpr());
-
- case TemplateArgument::Pack:
- if (Arg1.pack_size() != Arg2.pack_size())
- return false;
-
- for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I)
- if (!IsStructurallyEquivalent(Context,
- Arg1.pack_begin()[I],
- Arg2.pack_begin()[I]))
- return false;
-
- return true;
- }
-
- llvm_unreachable("Invalid template argument kind");
-}
-
-/// \brief Determine structural equivalence for the common part of array
-/// types.
-static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
- const ArrayType *Array1,
- const ArrayType *Array2) {
- if (!IsStructurallyEquivalent(Context,
- Array1->getElementType(),
- Array2->getElementType()))
- return false;
- if (Array1->getSizeModifier() != Array2->getSizeModifier())
- return false;
- if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
- return false;
-
- return true;
-}
-
-/// \brief Determine structural equivalence of two types.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- QualType T1, QualType T2) {
- if (T1.isNull() || T2.isNull())
- return T1.isNull() && T2.isNull();
-
- if (!Context.StrictTypeSpelling) {
- // We aren't being strict about token-to-token equivalence of types,
- // so map down to the canonical type.
- T1 = Context.C1.getCanonicalType(T1);
- T2 = Context.C2.getCanonicalType(T2);
- }
-
- if (T1.getQualifiers() != T2.getQualifiers())
- return false;
-
- Type::TypeClass TC = T1->getTypeClass();
-
- if (T1->getTypeClass() != T2->getTypeClass()) {
- // Compare function types with prototypes vs. without prototypes as if
- // both did not have prototypes.
- if (T1->getTypeClass() == Type::FunctionProto &&
- T2->getTypeClass() == Type::FunctionNoProto)
- TC = Type::FunctionNoProto;
- else if (T1->getTypeClass() == Type::FunctionNoProto &&
- T2->getTypeClass() == Type::FunctionProto)
- TC = Type::FunctionNoProto;
- else
- return false;
- }
-
- switch (TC) {
- case Type::Builtin:
- // FIXME: Deal with Char_S/Char_U.
- if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
- return false;
- break;
-
- case Type::Complex:
- if (!IsStructurallyEquivalent(Context,
- cast<ComplexType>(T1)->getElementType(),
- cast<ComplexType>(T2)->getElementType()))
- return false;
- break;
-
- case Type::Adjusted:
- case Type::Decayed:
- if (!IsStructurallyEquivalent(Context,
- cast<AdjustedType>(T1)->getOriginalType(),
- cast<AdjustedType>(T2)->getOriginalType()))
- return false;
- break;
-
- case Type::Pointer:
- if (!IsStructurallyEquivalent(Context,
- cast<PointerType>(T1)->getPointeeType(),
- cast<PointerType>(T2)->getPointeeType()))
- return false;
- break;
-
- case Type::BlockPointer:
- if (!IsStructurallyEquivalent(Context,
- cast<BlockPointerType>(T1)->getPointeeType(),
- cast<BlockPointerType>(T2)->getPointeeType()))
- return false;
- break;
-
- case Type::LValueReference:
- case Type::RValueReference: {
- const ReferenceType *Ref1 = cast<ReferenceType>(T1);
- const ReferenceType *Ref2 = cast<ReferenceType>(T2);
- if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
- return false;
- if (Ref1->isInnerRef() != Ref2->isInnerRef())
- return false;
- if (!IsStructurallyEquivalent(Context,
- Ref1->getPointeeTypeAsWritten(),
- Ref2->getPointeeTypeAsWritten()))
- return false;
- break;
- }
-
- case Type::MemberPointer: {
- const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1);
- const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2);
- if (!IsStructurallyEquivalent(Context,
- MemPtr1->getPointeeType(),
- MemPtr2->getPointeeType()))
- return false;
- if (!IsStructurallyEquivalent(Context,
- QualType(MemPtr1->getClass(), 0),
- QualType(MemPtr2->getClass(), 0)))
- return false;
- break;
- }
-
- case Type::ConstantArray: {
- const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1);
- const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2);
- if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))
- return false;
-
- if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
- return false;
- break;
- }
-
- case Type::IncompleteArray:
- if (!IsArrayStructurallyEquivalent(Context,
- cast<ArrayType>(T1),
- cast<ArrayType>(T2)))
- return false;
- break;
-
- case Type::VariableArray: {
- const VariableArrayType *Array1 = cast<VariableArrayType>(T1);
- const VariableArrayType *Array2 = cast<VariableArrayType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Array1->getSizeExpr(), Array2->getSizeExpr()))
- return false;
-
- if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
- return false;
-
- break;
- }
-
- case Type::DependentSizedArray: {
- const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1);
- const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Array1->getSizeExpr(), Array2->getSizeExpr()))
- return false;
-
- if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
- return false;
-
- break;
- }
-
- case Type::DependentSizedExtVector: {
- const DependentSizedExtVectorType *Vec1
- = cast<DependentSizedExtVectorType>(T1);
- const DependentSizedExtVectorType *Vec2
- = cast<DependentSizedExtVectorType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Vec1->getSizeExpr(), Vec2->getSizeExpr()))
- return false;
- if (!IsStructurallyEquivalent(Context,
- Vec1->getElementType(),
- Vec2->getElementType()))
- return false;
- break;
- }
-
- case Type::Vector:
- case Type::ExtVector: {
- const VectorType *Vec1 = cast<VectorType>(T1);
- const VectorType *Vec2 = cast<VectorType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Vec1->getElementType(),
- Vec2->getElementType()))
- return false;
- if (Vec1->getNumElements() != Vec2->getNumElements())
- return false;
- if (Vec1->getVectorKind() != Vec2->getVectorKind())
- return false;
- break;
- }
-
- case Type::FunctionProto: {
- const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1);
- const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2);
- if (Proto1->getNumParams() != Proto2->getNumParams())
- return false;
- for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),
- Proto2->getParamType(I)))
- return false;
- }
- if (Proto1->isVariadic() != Proto2->isVariadic())
- return false;
- if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType())
- return false;
- if (Proto1->getExceptionSpecType() == EST_Dynamic) {
- if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
- return false;
- for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Proto1->getExceptionType(I),
- Proto2->getExceptionType(I)))
- return false;
- }
- } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) {
- if (!IsStructurallyEquivalent(Context,
- Proto1->getNoexceptExpr(),
- Proto2->getNoexceptExpr()))
- return false;
- }
- if (Proto1->getTypeQuals() != Proto2->getTypeQuals())
- return false;
-
- // Fall through to check the bits common with FunctionNoProtoType.
- }
-
- case Type::FunctionNoProto: {
- const FunctionType *Function1 = cast<FunctionType>(T1);
- const FunctionType *Function2 = cast<FunctionType>(T2);
- if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
- Function2->getReturnType()))
- return false;
- if (Function1->getExtInfo() != Function2->getExtInfo())
- return false;
- break;
- }
-
- case Type::UnresolvedUsing:
- if (!IsStructurallyEquivalent(Context,
- cast<UnresolvedUsingType>(T1)->getDecl(),
- cast<UnresolvedUsingType>(T2)->getDecl()))
- return false;
-
- break;
-
- case Type::Attributed:
- if (!IsStructurallyEquivalent(Context,
- cast<AttributedType>(T1)->getModifiedType(),
- cast<AttributedType>(T2)->getModifiedType()))
- return false;
- if (!IsStructurallyEquivalent(Context,
- cast<AttributedType>(T1)->getEquivalentType(),
- cast<AttributedType>(T2)->getEquivalentType()))
- return false;
- break;
-
- case Type::Paren:
- if (!IsStructurallyEquivalent(Context,
- cast<ParenType>(T1)->getInnerType(),
- cast<ParenType>(T2)->getInnerType()))
- return false;
- break;
-
- case Type::Typedef:
- if (!IsStructurallyEquivalent(Context,
- cast<TypedefType>(T1)->getDecl(),
- cast<TypedefType>(T2)->getDecl()))
- return false;
- break;
-
- case Type::TypeOfExpr:
- if (!IsStructurallyEquivalent(Context,
- cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
- cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
- return false;
- break;
-
- case Type::TypeOf:
- if (!IsStructurallyEquivalent(Context,
- cast<TypeOfType>(T1)->getUnderlyingType(),
- cast<TypeOfType>(T2)->getUnderlyingType()))
- return false;
- break;
-
- case Type::UnaryTransform:
- if (!IsStructurallyEquivalent(Context,
- cast<UnaryTransformType>(T1)->getUnderlyingType(),
- cast<UnaryTransformType>(T1)->getUnderlyingType()))
- return false;
- break;
-
- case Type::Decltype:
- if (!IsStructurallyEquivalent(Context,
- cast<DecltypeType>(T1)->getUnderlyingExpr(),
- cast<DecltypeType>(T2)->getUnderlyingExpr()))
- return false;
- break;
-
- case Type::Auto:
- if (!IsStructurallyEquivalent(Context,
- cast<AutoType>(T1)->getDeducedType(),
- cast<AutoType>(T2)->getDeducedType()))
- return false;
- break;
-
- case Type::Record:
- case Type::Enum:
- if (!IsStructurallyEquivalent(Context,
- cast<TagType>(T1)->getDecl(),
- cast<TagType>(T2)->getDecl()))
- return false;
- break;
-
- case Type::TemplateTypeParm: {
- const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1);
- const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2);
- if (Parm1->getDepth() != Parm2->getDepth())
- return false;
- if (Parm1->getIndex() != Parm2->getIndex())
- return false;
- if (Parm1->isParameterPack() != Parm2->isParameterPack())
- return false;
-
- // Names of template type parameters are never significant.
- break;
- }
-
- case Type::SubstTemplateTypeParm: {
- const SubstTemplateTypeParmType *Subst1
- = cast<SubstTemplateTypeParmType>(T1);
- const SubstTemplateTypeParmType *Subst2
- = cast<SubstTemplateTypeParmType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
- return false;
- if (!IsStructurallyEquivalent(Context,
- Subst1->getReplacementType(),
- Subst2->getReplacementType()))
- return false;
- break;
- }
-
- case Type::SubstTemplateTypeParmPack: {
- const SubstTemplateTypeParmPackType *Subst1
- = cast<SubstTemplateTypeParmPackType>(T1);
- const SubstTemplateTypeParmPackType *Subst2
- = cast<SubstTemplateTypeParmPackType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
- return false;
- if (!IsStructurallyEquivalent(Context,
- Subst1->getArgumentPack(),
- Subst2->getArgumentPack()))
- return false;
- break;
- }
- case Type::TemplateSpecialization: {
- const TemplateSpecializationType *Spec1
- = cast<TemplateSpecializationType>(T1);
- const TemplateSpecializationType *Spec2
- = cast<TemplateSpecializationType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Spec1->getTemplateName(),
- Spec2->getTemplateName()))
- return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
- return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Spec1->getArg(I), Spec2->getArg(I)))
- return false;
- }
- break;
- }
-
- case Type::Elaborated: {
- const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
- const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
- // CHECKME: what if a keyword is ETK_None or ETK_typename ?
- if (Elab1->getKeyword() != Elab2->getKeyword())
- return false;
- if (!IsStructurallyEquivalent(Context,
- Elab1->getQualifier(),
- Elab2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Context,
- Elab1->getNamedType(),
- Elab2->getNamedType()))
- return false;
- break;
- }
-
- case Type::InjectedClassName: {
- const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1);
- const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Inj1->getInjectedSpecializationType(),
- Inj2->getInjectedSpecializationType()))
- return false;
- break;
- }
-
- case Type::DependentName: {
- const DependentNameType *Typename1 = cast<DependentNameType>(T1);
- const DependentNameType *Typename2 = cast<DependentNameType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Typename1->getQualifier(),
- Typename2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
- Typename2->getIdentifier()))
- return false;
-
- break;
- }
-
- case Type::DependentTemplateSpecialization: {
- const DependentTemplateSpecializationType *Spec1 =
- cast<DependentTemplateSpecializationType>(T1);
- const DependentTemplateSpecializationType *Spec2 =
- cast<DependentTemplateSpecializationType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Spec1->getQualifier(),
- Spec2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
- Spec2->getIdentifier()))
- return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
- return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Spec1->getArg(I), Spec2->getArg(I)))
- return false;
- }
- break;
- }
-
- case Type::PackExpansion:
- if (!IsStructurallyEquivalent(Context,
- cast<PackExpansionType>(T1)->getPattern(),
- cast<PackExpansionType>(T2)->getPattern()))
- return false;
- break;
-
- case Type::ObjCInterface: {
- const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1);
- const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Iface1->getDecl(), Iface2->getDecl()))
- return false;
- break;
- }
-
- case Type::ObjCTypeParam: {
- const ObjCTypeParamType *Obj1 = cast<ObjCTypeParamType>(T1);
- const ObjCTypeParamType *Obj2 = cast<ObjCTypeParamType>(T2);
- if (!IsStructurallyEquivalent(Context, Obj1->getDecl(),
- Obj2->getDecl()))
- return false;
-
- if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
- return false;
- for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Obj1->getProtocol(I),
- Obj2->getProtocol(I)))
- return false;
- }
- break;
- }
- case Type::ObjCObject: {
- const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1);
- const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Obj1->getBaseType(),
- Obj2->getBaseType()))
- return false;
- if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
- return false;
- for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Obj1->getProtocol(I),
- Obj2->getProtocol(I)))
- return false;
- }
- break;
- }
-
- case Type::ObjCObjectPointer: {
- const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1);
- const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Ptr1->getPointeeType(),
- Ptr2->getPointeeType()))
- return false;
- break;
- }
-
- case Type::Atomic: {
- if (!IsStructurallyEquivalent(Context,
- cast<AtomicType>(T1)->getValueType(),
- cast<AtomicType>(T2)->getValueType()))
- return false;
- break;
- }
-
- case Type::Pipe: {
- if (!IsStructurallyEquivalent(Context,
- cast<PipeType>(T1)->getElementType(),
- cast<PipeType>(T2)->getElementType()))
- return false;
- break;
- }
-
- } // end switch
-
- return true;
-}
-
-/// \brief Determine structural equivalence of two fields.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- FieldDecl *Field1, FieldDecl *Field2) {
- RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
-
- // For anonymous structs/unions, match up the anonymous struct/union type
- // declarations directly, so that we don't go off searching for anonymous
- // types
- if (Field1->isAnonymousStructOrUnion() &&
- Field2->isAnonymousStructOrUnion()) {
- RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
- RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
- return IsStructurallyEquivalent(Context, D1, D2);
- }
-
- // Check for equivalent field names.
- IdentifierInfo *Name1 = Field1->getIdentifier();
- IdentifierInfo *Name2 = Field2->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2))
- return false;
-
- if (!IsStructurallyEquivalent(Context,
- Field1->getType(), Field2->getType())) {
- if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
- }
- return false;
- }
-
- if (Field1->isBitField() != Field2->isBitField()) {
- if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- if (Field1->isBitField()) {
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType()
- << Field1->getBitWidthValue(Context.C1);
- Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
- << Field2->getDeclName();
- } else {
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType()
- << Field2->getBitWidthValue(Context.C2);
- Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
- << Field1->getDeclName();
- }
- }
- return false;
- }
-
- if (Field1->isBitField()) {
- // Make sure that the bit-fields are the same length.
- unsigned Bits1 = Field1->getBitWidthValue(Context.C1);
- unsigned Bits2 = Field2->getBitWidthValue(Context.C2);
-
- if (Bits1 != Bits2) {
- if (Context.Complain) {
- Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(Owner2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
- << Field2->getDeclName() << Field2->getType() << Bits2;
- Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
- << Field1->getDeclName() << Field1->getType() << Bits1;
- }
- return false;
- }
- }
-
- return true;
-}
-
-/// \brief Find the index of the given anonymous struct/union within its
-/// context.
-///
-/// \returns Returns the index of this anonymous struct/union in its context,
-/// including the next assigned index (if none of them match). Returns an
-/// empty option if the context is not a record, i.e.. if the anonymous
-/// struct/union is at namespace or block scope.
-static Optional<unsigned> findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
- ASTContext &Context = Anon->getASTContext();
- QualType AnonTy = Context.getRecordType(Anon);
-
- RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
- if (!Owner)
- return None;
-
- unsigned Index = 0;
- for (const auto *D : Owner->noload_decls()) {
- const auto *F = dyn_cast<FieldDecl>(D);
- if (!F)
- continue;
-
- if (F->isAnonymousStructOrUnion()) {
- if (Context.hasSameType(F->getType(), AnonTy))
- break;
- ++Index;
- continue;
- }
-
- // If the field looks like this:
- // struct { ... } A;
- QualType FieldType = F->getType();
- if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
- const RecordDecl *RecDecl = RecType->getDecl();
- if (RecDecl->getDeclContext() == Owner &&
- !RecDecl->getIdentifier()) {
- if (Context.hasSameType(FieldType, AnonTy))
- break;
- ++Index;
- continue;
- }
- }
- }
-
- return Index;
-}
-
-/// \brief Determine structural equivalence of two records.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- RecordDecl *D1, RecordDecl *D2) {
- if (D1->isUnion() != D2->isUnion()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
- << D1->getDeclName() << (unsigned)D1->getTagKind();
- }
- return false;
- }
-
- if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) {
- // If both anonymous structs/unions are in a record context, make sure
- // they occur in the same location in the context records.
- if (Optional<unsigned> Index1 = findUntaggedStructOrUnionIndex(D1)) {
- if (Optional<unsigned> Index2 = findUntaggedStructOrUnionIndex(D2)) {
- if (*Index1 != *Index2)
- return false;
- }
- }
- }
-
- // If both declarations are class template specializations, we know
- // the ODR applies, so check the template and template arguments.
- ClassTemplateSpecializationDecl *Spec1
- = dyn_cast<ClassTemplateSpecializationDecl>(D1);
- ClassTemplateSpecializationDecl *Spec2
- = dyn_cast<ClassTemplateSpecializationDecl>(D2);
- if (Spec1 && Spec2) {
- // Check that the specialized templates are the same.
- if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),
- Spec2->getSpecializedTemplate()))
- return false;
-
- // Check that the template arguments are the same.
- if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
- return false;
-
- for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I)
- if (!IsStructurallyEquivalent(Context,
- Spec1->getTemplateArgs().get(I),
- Spec2->getTemplateArgs().get(I)))
- return false;
- }
- // If one is a class template specialization and the other is not, these
- // structures are different.
- else if (Spec1 || Spec2)
- return false;
-
- // Compare the definitions of these two records. If either or both are
- // incomplete, we assume that they are equivalent.
- D1 = D1->getDefinition();
- D2 = D2->getDefinition();
- if (!D1 || !D2)
- return true;
-
- if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
- if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
- if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
- << D2CXX->getNumBases();
- Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
- << D1CXX->getNumBases();
- }
- return false;
- }
-
- // Check the base classes.
- for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
- BaseEnd1 = D1CXX->bases_end(),
- Base2 = D2CXX->bases_begin();
- Base1 != BaseEnd1;
- ++Base1, ++Base2) {
- if (!IsStructurallyEquivalent(Context,
- Base1->getType(), Base2->getType())) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getLocStart(), diag::note_odr_base)
- << Base2->getType()
- << Base2->getSourceRange();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->getType()
- << Base1->getSourceRange();
- }
- return false;
- }
-
- // Check virtual vs. non-virtual inheritance mismatch.
- if (Base1->isVirtual() != Base2->isVirtual()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Base2->getLocStart(),
- diag::note_odr_virtual_base)
- << Base2->isVirtual() << Base2->getSourceRange();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->isVirtual()
- << Base1->getSourceRange();
- }
- return false;
- }
- }
- } else if (D1CXX->getNumBases() > 0) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
- Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
- << Base1->getType()
- << Base1->getSourceRange();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
- }
- return false;
- }
- }
-
- // Check the fields for consistency.
- RecordDecl::field_iterator Field2 = D2->field_begin(),
- Field2End = D2->field_end();
- for (RecordDecl::field_iterator Field1 = D1->field_begin(),
- Field1End = D1->field_end();
- Field1 != Field1End;
- ++Field1, ++Field2) {
- if (Field2 == Field2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(Field1->getLocation(), diag::note_odr_field)
- << Field1->getDeclName() << Field1->getType();
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
- }
- return false;
- }
-
- if (!IsStructurallyEquivalent(Context, *Field1, *Field2))
- return false;
- }
-
- if (Field2 != Field2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(Field2->getLocation(), diag::note_odr_field)
- << Field2->getDeclName() << Field2->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
- }
- return false;
- }
-
- return true;
-}
-
-/// \brief Determine structural equivalence of two enums.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- EnumDecl *D1, EnumDecl *D2) {
- EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
- EC2End = D2->enumerator_end();
- for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
- EC1End = D1->enumerator_end();
- EC1 != EC1End; ++EC1, ++EC2) {
- if (EC2 == EC2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName()
- << EC1->getInitVal().toString(10);
- Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
- }
- return false;
- }
-
- llvm::APSInt Val1 = EC1->getInitVal();
- llvm::APSInt Val2 = EC2->getInitVal();
- if (!llvm::APSInt::isSameValue(Val1, Val2) ||
- !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
- << EC2->getDeclName()
- << EC2->getInitVal().toString(10);
- Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
- << EC1->getDeclName()
- << EC1->getInitVal().toString(10);
- }
- return false;
- }
- }
-
- if (EC2 != EC2End) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
- Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
- << EC2->getDeclName()
- << EC2->getInitVal().toString(10);
- Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
- }
- return false;
- }
-
- return true;
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- TemplateParameterList *Params1,
- TemplateParameterList *Params2) {
- if (Params1->size() != Params2->size()) {
- if (Context.Complain) {
- Context.Diag2(Params2->getTemplateLoc(),
- diag::err_odr_different_num_template_parameters)
- << Params1->size() << Params2->size();
- Context.Diag1(Params1->getTemplateLoc(),
- diag::note_odr_template_parameter_list);
- }
- return false;
- }
-
- for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
- if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
- if (Context.Complain) {
- Context.Diag2(Params2->getParam(I)->getLocation(),
- diag::err_odr_different_template_parameter_kind);
- Context.Diag1(Params1->getParam(I)->getLocation(),
- diag::note_odr_template_parameter_here);
- }
- return false;
- }
-
- if (!Context.IsStructurallyEquivalent(Params1->getParam(I),
- Params2->getParam(I))) {
-
- return false;
- }
- }
-
- return true;
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- TemplateTypeParmDecl *D1,
- TemplateTypeParmDecl *D2) {
- if (D1->isParameterPack() != D2->isParameterPack()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
- }
- return false;
- }
-
- return true;
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- NonTypeTemplateParmDecl *D1,
- NonTypeTemplateParmDecl *D2) {
- if (D1->isParameterPack() != D2->isParameterPack()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
- }
- return false;
- }
-
- // Check types.
- if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(),
- diag::err_odr_non_type_parameter_type_inconsistent)
- << D2->getType() << D1->getType();
- Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
- << D1->getType();
- }
- return false;
- }
-
- return true;
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- TemplateTemplateParmDecl *D1,
- TemplateTemplateParmDecl *D2) {
- if (D1->isParameterPack() != D2->isParameterPack()) {
- if (Context.Complain) {
- Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
- << D2->isParameterPack();
- Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
- << D1->isParameterPack();
- }
- return false;
- }
-
- // Check template parameter lists.
- return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
- D2->getTemplateParameters());
-}
-
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- ClassTemplateDecl *D1,
- ClassTemplateDecl *D2) {
- // Check template parameters.
- if (!IsStructurallyEquivalent(Context,
- D1->getTemplateParameters(),
- D2->getTemplateParameters()))
- return false;
-
- // Check the templated declaration.
- return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(),
- D2->getTemplatedDecl());
-}
-
-/// \brief Determine structural equivalence of two declarations.
-static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- Decl *D1, Decl *D2) {
- // FIXME: Check for known structural equivalences via a callback of some sort.
-
- // Check whether we already know that these two declarations are not
- // structurally equivalent.
- if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(),
- D2->getCanonicalDecl())))
- return false;
-
- // Determine whether we've already produced a tentative equivalence for D1.
- Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
- if (EquivToD1)
- return EquivToD1 == D2->getCanonicalDecl();
-
- // Produce a tentative equivalence D1 <-> D2, which will be checked later.
- EquivToD1 = D2->getCanonicalDecl();
- Context.DeclsToCheck.push_back(D1->getCanonicalDecl());
- return true;
-}
-
-bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1,
- Decl *D2) {
- if (!::IsStructurallyEquivalent(*this, D1, D2))
- return false;
-
- return !Finish();
-}
-
-bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1,
- QualType T2) {
- if (!::IsStructurallyEquivalent(*this, T1, T2))
- return false;
-
- return !Finish();
-}
-
-bool StructuralEquivalenceContext::Finish() {
- while (!DeclsToCheck.empty()) {
- // Check the next declaration.
- Decl *D1 = DeclsToCheck.front();
- DeclsToCheck.pop_front();
-
- Decl *D2 = TentativeEquivalences[D1];
- assert(D2 && "Unrecorded tentative equivalence?");
-
- bool Equivalent = true;
-
- // FIXME: Switch on all declaration kinds. For now, we're just going to
- // check the obvious ones.
- if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) {
- if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) {
- // Check for equivalent structure names.
- IdentifierInfo *Name1 = Record1->getIdentifier();
- if (!Name1 && Record1->getTypedefNameForAnonDecl())
- Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier();
- IdentifierInfo *Name2 = Record2->getIdentifier();
- if (!Name2 && Record2->getTypedefNameForAnonDecl())
- Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2) ||
- !::IsStructurallyEquivalent(*this, Record1, Record2))
- Equivalent = false;
- } else {
- // Record/non-record mismatch.
- Equivalent = false;
- }
- } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) {
- if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
- // Check for equivalent enum names.
- IdentifierInfo *Name1 = Enum1->getIdentifier();
- if (!Name1 && Enum1->getTypedefNameForAnonDecl())
- Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier();
- IdentifierInfo *Name2 = Enum2->getIdentifier();
- if (!Name2 && Enum2->getTypedefNameForAnonDecl())
- Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier();
- if (!::IsStructurallyEquivalent(Name1, Name2) ||
- !::IsStructurallyEquivalent(*this, Enum1, Enum2))
- Equivalent = false;
- } else {
- // Enum/non-enum mismatch
- Equivalent = false;
- }
- } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) {
- if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) {
- if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
- Typedef2->getIdentifier()) ||
- !::IsStructurallyEquivalent(*this,
- Typedef1->getUnderlyingType(),
- Typedef2->getUnderlyingType()))
- Equivalent = false;
- } else {
- // Typedef/non-typedef mismatch.
- Equivalent = false;
- }
- } else if (ClassTemplateDecl *ClassTemplate1
- = dyn_cast<ClassTemplateDecl>(D1)) {
- if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) {
- if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(),
- ClassTemplate2->getIdentifier()) ||
- !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2))
- Equivalent = false;
- } else {
- // Class template/non-class-template mismatch.
- Equivalent = false;
- }
- } else if (TemplateTypeParmDecl *TTP1= dyn_cast<TemplateTypeParmDecl>(D1)) {
- if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
- Equivalent = false;
- } else {
- // Kind mismatch.
- Equivalent = false;
- }
- } else if (NonTypeTemplateParmDecl *NTTP1
- = dyn_cast<NonTypeTemplateParmDecl>(D1)) {
- if (NonTypeTemplateParmDecl *NTTP2
- = dyn_cast<NonTypeTemplateParmDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2))
- Equivalent = false;
- } else {
- // Kind mismatch.
- Equivalent = false;
- }
- } else if (TemplateTemplateParmDecl *TTP1
- = dyn_cast<TemplateTemplateParmDecl>(D1)) {
- if (TemplateTemplateParmDecl *TTP2
- = dyn_cast<TemplateTemplateParmDecl>(D2)) {
- if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
- Equivalent = false;
- } else {
- // Kind mismatch.
- Equivalent = false;
- }
- }
-
- if (!Equivalent) {
- // Note that these two declarations are not equivalent (and we already
- // know about it).
- NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(),
- D2->getCanonicalDecl()));
- return true;
- }
- // FIXME: Check other declaration kinds!
- }
-
- return false;
-}
-
//----------------------------------------------------------------------------
// Import Types
//----------------------------------------------------------------------------
+using namespace clang;
+
QualType ASTNodeImporter::VisitType(const Type *T) {
Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node)
<< T->getTypeClassName();
@@ -1976,6 +710,23 @@ QualType ASTNodeImporter::VisitTemplateTypeParmType(
T->getDepth(), T->getIndex(), T->isParameterPack(), ParmDecl);
}
+QualType ASTNodeImporter::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *T) {
+ const TemplateTypeParmType *Replaced =
+ cast_or_null<TemplateTypeParmType>(Importer.Import(
+ QualType(T->getReplacedParameter(), 0)).getTypePtr());
+ if (!Replaced)
+ return QualType();
+
+ QualType Replacement = Importer.Import(T->getReplacementType());
+ if (Replacement.isNull())
+ return QualType();
+ Replacement = Replacement.getCanonicalType();
+
+ return Importer.getToContext().getSubstTemplateTypeParmType(
+ Replaced, Replacement);
+}
+
QualType ASTNodeImporter::VisitTemplateSpecializationType(
const TemplateSpecializationType *T) {
TemplateName ToTemplate = Importer.Import(T->getTemplateName());
@@ -2133,6 +884,7 @@ ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From,
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
return;
case DeclarationName::CXXOperatorName: {
@@ -2204,12 +956,16 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToData.HasUninitializedFields = FromData.HasUninitializedFields;
ToData.HasInheritedConstructor = FromData.HasInheritedConstructor;
ToData.HasInheritedAssignment = FromData.HasInheritedAssignment;
+ ToData.NeedOverloadResolutionForCopyConstructor
+ = FromData.NeedOverloadResolutionForCopyConstructor;
ToData.NeedOverloadResolutionForMoveConstructor
= FromData.NeedOverloadResolutionForMoveConstructor;
ToData.NeedOverloadResolutionForMoveAssignment
= FromData.NeedOverloadResolutionForMoveAssignment;
ToData.NeedOverloadResolutionForDestructor
= FromData.NeedOverloadResolutionForDestructor;
+ ToData.DefaultedCopyConstructorIsDeleted
+ = FromData.DefaultedCopyConstructorIsDeleted;
ToData.DefaultedMoveConstructorIsDeleted
= FromData.DefaultedMoveConstructorIsDeleted;
ToData.DefaultedMoveAssignmentIsDeleted
@@ -2221,6 +977,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
= FromData.HasConstexprNonCopyMoveConstructor;
ToData.HasDefaultedDefaultConstructor
= FromData.HasDefaultedDefaultConstructor;
+ ToData.CanPassInRegisters = FromData.CanPassInRegisters;
ToData.DefaultedDefaultConstructorIsConstexpr
= FromData.DefaultedDefaultConstructorIsConstexpr;
ToData.HasConstexprDefaultConstructor
@@ -2231,8 +988,10 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToData.UserProvidedDefaultConstructor
= FromData.UserProvidedDefaultConstructor;
ToData.DeclaredSpecialMembers = FromData.DeclaredSpecialMembers;
- ToData.ImplicitCopyConstructorHasConstParam
- = FromData.ImplicitCopyConstructorHasConstParam;
+ ToData.ImplicitCopyConstructorCanHaveConstParamForVBase
+ = FromData.ImplicitCopyConstructorCanHaveConstParamForVBase;
+ ToData.ImplicitCopyConstructorCanHaveConstParamForNonVBase
+ = FromData.ImplicitCopyConstructorCanHaveConstParamForNonVBase;
ToData.ImplicitCopyAssignmentHasConstParam
= FromData.ImplicitCopyAssignmentHasConstParam;
ToData.HasDeclaredCopyConstructorWithConstParam
@@ -2500,7 +1259,7 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
Importer.getNonEquivalentDecls());
- return Ctx.IsStructurallyEquivalent(From, To);
+ return Ctx.IsStructurallyEquivalent(From, To);
}
bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From,
@@ -2679,10 +1438,10 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
FoundTypedef->getUnderlyingType()))
return Importer.Imported(D, FoundTypedef);
}
-
+
ConflictingDecls.push_back(FoundDecls[I]);
}
-
+
if (!ConflictingDecls.empty()) {
Name = Importer.HandleNameConflict(Name, DC, IDNS,
ConflictingDecls.data(),
@@ -2691,7 +1450,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
return nullptr;
}
}
-
+
// Import the underlying type of this typedef;
QualType T = Importer.Import(D->getUnderlyingType());
if (T.isNull())
@@ -2711,12 +1470,12 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
StartL, Loc,
Name.getAsIdentifierInfo(),
TInfo);
-
+
ToTypedef->setAccess(D->getAccess());
ToTypedef->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToTypedef);
LexicalDC->addDeclInternal(ToTypedef);
-
+
return ToTypedef;
}
@@ -2785,7 +1544,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
if (!DC->isFunctionOrMethod() && SearchName) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(SearchName, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -2871,10 +1630,18 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// We may already have a record of the same name; try to find and match it.
RecordDecl *AdoptDecl = nullptr;
+ RecordDecl *PrevDecl = nullptr;
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
- DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
+ DC->getRedeclContext()->localUncachedLookup(SearchName, FoundDecls);
+
+ if (!FoundDecls.empty()) {
+ // We're going to have to compare D against potentially conflicting Decls, so complete it.
+ if (D->hasExternalLexicalStorage() && !D->isCompleteDefinition())
+ D->getASTContext().getExternalSource()->CompleteType(D);
+ }
+
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
@@ -2890,9 +1657,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
FoundRecord->isAnonymousStructOrUnion()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (Optional<unsigned> Index1
- = findUntaggedStructOrUnionIndex(D)) {
- if (Optional<unsigned> Index2 =
+ if (Optional<unsigned> Index1 =
+ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
+ D)) {
+ if (Optional<unsigned> Index2 = StructuralEquivalenceContext::
findUntaggedStructOrUnionIndex(FoundRecord)) {
if (*Index1 != *Index2)
continue;
@@ -2900,6 +1668,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
}
}
+ PrevDecl = FoundRecord;
+
if (RecordDecl *FoundDef = FoundRecord->getDefinition()) {
if ((SearchName && !D->isCompleteDefinition())
|| (D->isCompleteDefinition() &&
@@ -2992,6 +1762,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
LexicalDC->addDeclInternal(D2);
if (D->isAnonymousStructOrUnion())
D2->setAnonymousStructOrUnion(true);
+ if (PrevDecl) {
+ // FIXME: do this for all Redeclarables, not just RecordDecls.
+ D2->setPreviousDecl(PrevDecl);
+ }
}
Importer.Imported(D, D2);
@@ -3082,7 +1856,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
-
+
if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) {
if (FoundFunction->hasExternalFormalLinkage() &&
D->hasExternalFormalLinkage()) {
@@ -3091,14 +1865,14 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// FIXME: Actually try to merge the body and other attributes.
return Importer.Imported(D, FoundFunction);
}
-
+
// FIXME: Check for overloading more carefully, e.g., by boosting
// Sema::IsOverload out to the AST library.
-
+
// Function overloading is okay in C++.
if (Importer.getToContext().getLangOpts().CPlusPlus)
continue;
-
+
// Complain about inconsistent function types.
Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent)
<< Name << D->getType() << FoundFunction->getType();
@@ -3107,10 +1881,10 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
<< FoundFunction->getType();
}
}
-
+
ConflictingDecls.push_back(FoundDecls[I]);
}
-
+
if (!ConflictingDecls.empty()) {
Name = Importer.HandleNameConflict(Name, DC, IDNS,
ConflictingDecls.data(),
@@ -3259,6 +2033,9 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Add this function to the lexical context.
LexicalDC->addDeclInternal(ToFunction);
+ if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
+ ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod);
+
return ToFunction;
}
@@ -3315,12 +2092,12 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
continue;
- if (Importer.IsStructurallyEquivalent(D->getType(),
+ if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType())) {
Importer.Imported(D, FoundField);
return FoundField;
}
-
+
Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent)
<< Name << D->getType() << FoundField->getType();
Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here)
@@ -3380,7 +2157,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
continue;
- if (Importer.IsStructurallyEquivalent(D->getType(),
+ if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType(),
!Name.isEmpty())) {
Importer.Imported(D, FoundField);
@@ -3504,12 +2281,12 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
if (ToD)
return ToD;
- // Determine whether we've already imported this ivar
+ // Determine whether we've already imported this ivar
SmallVector<NamedDecl *, 2> FoundDecls;
DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) {
- if (Importer.IsStructurallyEquivalent(D->getType(),
+ if (Importer.IsStructurallyEquivalent(D->getType(),
FoundIvar->getType())) {
Importer.Imported(D, FoundIvar);
return FoundIvar;
@@ -3568,12 +2345,12 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
-
+
if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) {
// We have found a variable that we may need to merge with. Check it.
if (FoundVar->hasExternalFormalLinkage() &&
D->hasExternalFormalLinkage()) {
- if (Importer.IsStructurallyEquivalent(D->getType(),
+ if (Importer.IsStructurallyEquivalent(D->getType(),
FoundVar->getType())) {
MergeWithVar = FoundVar;
break;
@@ -3671,6 +2448,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
if (ImportDefinition(D, ToVar))
return nullptr;
+ if (D->isConstexpr())
+ ToVar->setConstexpr(true);
+
return ToVar;
}
@@ -3693,10 +2473,9 @@ Decl *ASTNodeImporter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
return nullptr;
// Create the imported parameter.
- ImplicitParamDecl *ToParm
- = ImplicitParamDecl::Create(Importer.getToContext(), DC,
- Loc, Name.getAsIdentifierInfo(),
- T);
+ auto *ToParm = ImplicitParamDecl::Create(Importer.getToContext(), DC, Loc,
+ Name.getAsIdentifierInfo(), T,
+ D->getParameterKind());
return Importer.Imported(D, ToParm);
}
@@ -3724,8 +2503,27 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
- /*FIXME: Default argument*/nullptr);
+ /*DefaultArg*/ nullptr);
+
+ // Set the default argument.
ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
+ ToParm->setKNRPromoted(D->isKNRPromoted());
+
+ Expr *ToDefArg = nullptr;
+ Expr *FromDefArg = nullptr;
+ if (D->hasUninstantiatedDefaultArg()) {
+ FromDefArg = D->getUninstantiatedDefaultArg();
+ ToDefArg = Importer.Import(FromDefArg);
+ ToParm->setUninstantiatedDefaultArg(ToDefArg);
+ } else if (D->hasUnparsedDefaultArg()) {
+ ToParm->setUnparsedDefaultArg();
+ } else if (D->hasDefaultArg()) {
+ FromDefArg = D->getDefaultArg();
+ ToDefArg = Importer.Import(FromDefArg);
+ ToParm->setDefaultArg(ToDefArg);
+ }
+ if (FromDefArg && !ToDefArg)
+ return nullptr;
if (D->isUsed())
ToParm->setIsUsed();
@@ -3775,12 +2573,12 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
}
// Check parameter types.
- for (ObjCMethodDecl::param_iterator P = D->param_begin(),
+ for (ObjCMethodDecl::param_iterator P = D->param_begin(),
PEnd = D->param_end(), FoundP = FoundMethod->param_begin();
P != PEnd; ++P, ++FoundP) {
- if (!Importer.IsStructurallyEquivalent((*P)->getType(),
+ if (!Importer.IsStructurallyEquivalent((*P)->getType(),
(*FoundP)->getType())) {
- Importer.FromDiag((*P)->getLocation(),
+ Importer.FromDiag((*P)->getLocation(),
diag::err_odr_objc_method_param_type_inconsistent)
<< D->isInstanceMethod() << Name
<< (*P)->getType() << (*FoundP)->getType();
@@ -4386,7 +3184,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
if (ObjCPropertyDecl *FoundProp
= dyn_cast<ObjCPropertyDecl>(FoundDecls[I])) {
// Check property types.
- if (!Importer.IsStructurallyEquivalent(D->getType(),
+ if (!Importer.IsStructurallyEquivalent(D->getType(),
FoundProp->getType())) {
Importer.ToDiag(Loc, diag::err_odr_objc_property_type_inconsistent)
<< Name << D->getType() << FoundProp->getType();
@@ -4424,8 +3222,10 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
ToProperty->setPropertyAttributes(D->getPropertyAttributes());
ToProperty->setPropertyAttributesAsWritten(
D->getPropertyAttributesAsWritten());
- ToProperty->setGetterName(Importer.Import(D->getGetterName()));
- ToProperty->setSetterName(Importer.Import(D->getSetterName()));
+ ToProperty->setGetterName(Importer.Import(D->getGetterName()),
+ Importer.Import(D->getGetterNameLoc()));
+ ToProperty->setSetterName(Importer.Import(D->getSetterName()),
+ Importer.Import(D->getSetterNameLoc()));
ToProperty->setGetterMethodDecl(
cast_or_null<ObjCMethodDecl>(Importer.Import(D->getGetterMethodDecl())));
ToProperty->setSetterMethodDecl(
@@ -4753,12 +3553,46 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
}
} else {
// Create a new specialization.
- D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(),
- D->getTagKind(), DC,
- StartLoc, IdLoc,
- ClassTemplate,
- TemplateArgs,
- /*PrevDecl=*/nullptr);
+ if (ClassTemplatePartialSpecializationDecl *PartialSpec =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
+
+ // Import TemplateArgumentListInfo
+ TemplateArgumentListInfo ToTAInfo;
+ auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten();
+ for (unsigned I = 0, E = ASTTemplateArgs.NumTemplateArgs; I < E; ++I) {
+ bool Error = false;
+ auto ToLoc = ImportTemplateArgumentLoc(ASTTemplateArgs[I], Error);
+ if (Error)
+ return nullptr;
+ ToTAInfo.addArgument(ToLoc);
+ }
+
+ QualType CanonInjType = Importer.Import(
+ PartialSpec->getInjectedSpecializationType());
+ if (CanonInjType.isNull())
+ return nullptr;
+ CanonInjType = CanonInjType.getCanonicalType();
+
+ TemplateParameterList *ToTPList = ImportTemplateParameterList(
+ PartialSpec->getTemplateParameters());
+ if (!ToTPList && PartialSpec->getTemplateParameters())
+ return nullptr;
+
+ D2 = ClassTemplatePartialSpecializationDecl::Create(
+ Importer.getToContext(), D->getTagKind(), DC, StartLoc, IdLoc,
+ ToTPList, ClassTemplate,
+ llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
+ ToTAInfo, CanonInjType, nullptr);
+
+ } else {
+ D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(),
+ D->getTagKind(), DC,
+ StartLoc, IdLoc,
+ ClassTemplate,
+ TemplateArgs,
+ /*PrevDecl=*/nullptr);
+ }
+
D2->setSpecializationKind(D->getSpecializationKind());
// Add this specialization to the class template.
@@ -4766,13 +3600,31 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Import the qualifier, if any.
D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
-
+
+ Importer.Imported(D, D2);
+
+ if (auto *TSI = D->getTypeAsWritten()) {
+ TypeSourceInfo *TInfo = Importer.Import(TSI);
+ if (!TInfo)
+ return nullptr;
+ D2->setTypeAsWritten(TInfo);
+ D2->setTemplateKeywordLoc(Importer.Import(D->getTemplateKeywordLoc()));
+ D2->setExternLoc(Importer.Import(D->getExternLoc()));
+ }
+
+ SourceLocation POI = Importer.Import(D->getPointOfInstantiation());
+ if (POI.isValid())
+ D2->setPointOfInstantiation(POI);
+ else if (D->getPointOfInstantiation().isValid())
+ return nullptr;
+
+ D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind());
+
// Add the specialization to this context.
D2->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(D2);
}
Importer.Imported(D, D2);
-
if (D->isCompleteDefinition() && ImportDefinition(D, D2))
return nullptr;
@@ -5010,13 +3862,17 @@ Stmt *ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
SmallVector<IdentifierInfo *, 4> Names;
for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) {
IdentifierInfo *ToII = Importer.Import(S->getOutputIdentifier(I));
- if (!ToII)
+ // ToII is nullptr when no symbolic name is given for output operand
+ // see ParseStmtAsm::ParseAsmOperandsOpt
+ if (!ToII && S->getOutputIdentifier(I))
return nullptr;
Names.push_back(ToII);
}
for (unsigned I = 0, E = S->getNumInputs(); I != E; I++) {
IdentifierInfo *ToII = Importer.Import(S->getInputIdentifier(I));
- if (!ToII)
+ // ToII is nullptr when no symbolic name is given for input operand
+ // see ParseStmtAsm::ParseAsmOperandsOpt
+ if (!ToII && S->getInputIdentifier(I))
return nullptr;
Names.push_back(ToII);
}
@@ -5860,7 +4716,7 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
T, E->getValueKind(),
E->getObjectKind(),
Importer.Import(E->getOperatorLoc()),
- E->isFPContractable());
+ E->getFPFeatures());
}
Expr *ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) {
@@ -6010,7 +4866,7 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
E->getObjectKind(),
CompLHSType, CompResultType,
Importer.Import(E->getOperatorLoc()),
- E->isFPContractable());
+ E->getFPFeatures());
}
bool ASTNodeImporter::ImportCastPath(CastExpr *CE, CXXCastPath &Path) {
@@ -6633,6 +5489,35 @@ Expr *ASTNodeImporter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
}
}
+
+Expr *ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ QualType T = Importer.Import(E->getType());
+ if (T.isNull())
+ return nullptr;
+
+ NonTypeTemplateParmDecl *Param = cast_or_null<NonTypeTemplateParmDecl>(
+ Importer.Import(E->getParameter()));
+ if (!Param)
+ return nullptr;
+
+ Expr *Replacement = Importer.Import(E->getReplacement());
+ if (!Replacement)
+ return nullptr;
+
+ return new (Importer.getToContext()) SubstNonTypeTemplateParmExpr(
+ T, E->getValueKind(), Importer.Import(E->getExprLoc()), Param,
+ Replacement);
+}
+
+void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod,
+ CXXMethodDecl *FromMethod) {
+ for (auto *FromOverriddenMethod : FromMethod->overridden_methods())
+ ToMethod->addOverriddenMethod(
+ cast<CXXMethodDecl>(Importer.Import(const_cast<CXXMethodDecl*>(
+ FromOverriddenMethod))));
+}
+
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
ASTContext &FromContext, FileManager &FromFileManager,
bool MinimalImport)
@@ -6839,14 +5724,14 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
case NestedNameSpecifier::Namespace:
if (NamespaceDecl *NS =
- cast<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) {
+ cast_or_null<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) {
return NestedNameSpecifier::Create(ToContext, prefix, NS);
}
return nullptr;
case NestedNameSpecifier::NamespaceAlias:
if (NamespaceAliasDecl *NSAD =
- cast<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) {
+ cast_or_null<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) {
return NestedNameSpecifier::Create(ToContext, prefix, NSAD);
}
return nullptr;
@@ -6856,7 +5741,7 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
case NestedNameSpecifier::Super:
if (CXXRecordDecl *RD =
- cast<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) {
+ cast_or_null<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) {
return NestedNameSpecifier::SuperSpecifier(ToContext, RD);
}
return nullptr;
@@ -6878,8 +5763,74 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
}
NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
- // FIXME: Implement!
- return NestedNameSpecifierLoc();
+ // Copied from NestedNameSpecifier mostly.
+ SmallVector<NestedNameSpecifierLoc , 8> NestedNames;
+ NestedNameSpecifierLoc NNS = FromNNS;
+
+ // Push each of the nested-name-specifiers's onto a stack for
+ // serialization in reverse order.
+ while (NNS) {
+ NestedNames.push_back(NNS);
+ NNS = NNS.getPrefix();
+ }
+
+ NestedNameSpecifierLocBuilder Builder;
+
+ while (!NestedNames.empty()) {
+ NNS = NestedNames.pop_back_val();
+ NestedNameSpecifier *Spec = Import(NNS.getNestedNameSpecifier());
+ if (!Spec)
+ return NestedNameSpecifierLoc();
+
+ NestedNameSpecifier::SpecifierKind Kind = Spec->getKind();
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier:
+ Builder.Extend(getToContext(),
+ Spec->getAsIdentifier(),
+ Import(NNS.getLocalBeginLoc()),
+ Import(NNS.getLocalEndLoc()));
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ Builder.Extend(getToContext(),
+ Spec->getAsNamespace(),
+ Import(NNS.getLocalBeginLoc()),
+ Import(NNS.getLocalEndLoc()));
+ break;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ Builder.Extend(getToContext(),
+ Spec->getAsNamespaceAlias(),
+ Import(NNS.getLocalBeginLoc()),
+ Import(NNS.getLocalEndLoc()));
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo(
+ QualType(Spec->getAsType(), 0));
+ Builder.Extend(getToContext(),
+ Import(NNS.getLocalBeginLoc()),
+ TSI->getTypeLoc(),
+ Import(NNS.getLocalEndLoc()));
+ break;
+ }
+
+ case NestedNameSpecifier::Global:
+ Builder.MakeGlobal(getToContext(), Import(NNS.getLocalBeginLoc()));
+ break;
+
+ case NestedNameSpecifier::Super: {
+ SourceRange ToRange = Import(NNS.getSourceRange());
+ Builder.MakeSuper(getToContext(),
+ Spec->getAsRecordDecl(),
+ ToRange.getBegin(),
+ ToRange.getEnd());
+ }
+ }
+ }
+
+ return Builder.getWithLocInContext(getToContext());
}
TemplateName ASTImporter::Import(TemplateName From) {
@@ -7175,6 +6126,14 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) {
ToContext.getCanonicalType(T));
}
+ case DeclarationName::CXXDeductionGuideName: {
+ TemplateDecl *Template = cast_or_null<TemplateDecl>(
+ Import(FromName.getCXXDeductionGuideTemplate()));
+ if (!Template)
+ return DeclarationName();
+ return ToContext.DeclarationNames.getCXXDeductionGuideName(Template);
+ }
+
case DeclarationName::CXXConversionFunctionName: {
QualType T = Import(FromName.getCXXNameType());
if (T.isNull())
@@ -7288,7 +6247,7 @@ bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To,
= ImportedTypes.find(From.getTypePtr());
if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To))
return true;
-
+
StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls,
false, Complain);
return Ctx.IsStructurallyEquivalent(From, To);
diff --git a/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp b/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp
new file mode 100644
index 0000000..ea7faab
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -0,0 +1,1362 @@
+//===--- ASTStructuralEquivalence.cpp - -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implement StructuralEquivalenceContext class and helper functions
+// for layout matching.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTStructuralEquivalence.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/SourceManager.h"
+
+namespace {
+
+using namespace clang;
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ QualType T1, QualType T2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Decl *D1, Decl *D2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgument &Arg1,
+ const TemplateArgument &Arg2);
+
+/// Determine structural equivalence of two expressions.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Expr *E1, Expr *E2) {
+ if (!E1 || !E2)
+ return E1 == E2;
+
+ // FIXME: Actually perform a structural comparison!
+ return true;
+}
+
+/// Determine whether two identifiers are equivalent.
+static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
+ const IdentifierInfo *Name2) {
+ if (!Name1 || !Name2)
+ return Name1 == Name2;
+
+ return Name1->getName() == Name2->getName();
+}
+
+/// Determine whether two nested-name-specifiers are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ NestedNameSpecifier *NNS1,
+ NestedNameSpecifier *NNS2) {
+ if (NNS1->getKind() != NNS2->getKind())
+ return false;
+
+ NestedNameSpecifier *Prefix1 = NNS1->getPrefix(),
+ *Prefix2 = NNS2->getPrefix();
+ if ((bool)Prefix1 != (bool)Prefix2)
+ return false;
+
+ if (Prefix1)
+ if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2))
+ return false;
+
+ switch (NNS1->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ return IsStructurallyEquivalent(NNS1->getAsIdentifier(),
+ NNS2->getAsIdentifier());
+ case NestedNameSpecifier::Namespace:
+ return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(),
+ NNS2->getAsNamespace());
+ case NestedNameSpecifier::NamespaceAlias:
+ return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(),
+ NNS2->getAsNamespaceAlias());
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),
+ QualType(NNS2->getAsType(), 0));
+ case NestedNameSpecifier::Global:
+ return true;
+ case NestedNameSpecifier::Super:
+ return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(),
+ NNS2->getAsRecordDecl());
+ }
+ return false;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateName &N1,
+ const TemplateName &N2) {
+ if (N1.getKind() != N2.getKind())
+ return false;
+ switch (N1.getKind()) {
+ case TemplateName::Template:
+ return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(),
+ N2.getAsTemplateDecl());
+
+ case TemplateName::OverloadedTemplate: {
+ OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),
+ *OS2 = N2.getAsOverloadedTemplate();
+ OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(),
+ E1 = OS1->end(), E2 = OS2->end();
+ for (; I1 != E1 && I2 != E2; ++I1, ++I2)
+ if (!IsStructurallyEquivalent(Context, *I1, *I2))
+ return false;
+ return I1 == E1 && I2 == E2;
+ }
+
+ case TemplateName::QualifiedTemplate: {
+ QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(),
+ *QN2 = N2.getAsQualifiedTemplateName();
+ return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) &&
+ IsStructurallyEquivalent(Context, QN1->getQualifier(),
+ QN2->getQualifier());
+ }
+
+ case TemplateName::DependentTemplate: {
+ DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
+ *DN2 = N2.getAsDependentTemplateName();
+ if (!IsStructurallyEquivalent(Context, DN1->getQualifier(),
+ DN2->getQualifier()))
+ return false;
+ if (DN1->isIdentifier() && DN2->isIdentifier())
+ return IsStructurallyEquivalent(DN1->getIdentifier(),
+ DN2->getIdentifier());
+ else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator())
+ return DN1->getOperator() == DN2->getOperator();
+ return false;
+ }
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(),
+ *TS2 = N2.getAsSubstTemplateTemplateParm();
+ return IsStructurallyEquivalent(Context, TS1->getParameter(),
+ TS2->getParameter()) &&
+ IsStructurallyEquivalent(Context, TS1->getReplacement(),
+ TS2->getReplacement());
+ }
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ SubstTemplateTemplateParmPackStorage
+ *P1 = N1.getAsSubstTemplateTemplateParmPack(),
+ *P2 = N2.getAsSubstTemplateTemplateParmPack();
+ return IsStructurallyEquivalent(Context, P1->getArgumentPack(),
+ P2->getArgumentPack()) &&
+ IsStructurallyEquivalent(Context, P1->getParameterPack(),
+ P2->getParameterPack());
+ }
+ }
+ return false;
+}
+
+/// Determine whether two template arguments are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgument &Arg1,
+ const TemplateArgument &Arg2) {
+ if (Arg1.getKind() != Arg2.getKind())
+ return false;
+
+ switch (Arg1.getKind()) {
+ case TemplateArgument::Null:
+ return true;
+
+ case TemplateArgument::Type:
+ return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType());
+
+ case TemplateArgument::Integral:
+ if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(),
+ Arg2.getIntegralType()))
+ return false;
+
+ return llvm::APSInt::isSameValue(Arg1.getAsIntegral(),
+ Arg2.getAsIntegral());
+
+ case TemplateArgument::Declaration:
+ return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl());
+
+ case TemplateArgument::NullPtr:
+ return true; // FIXME: Is this correct?
+
+ case TemplateArgument::Template:
+ return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(),
+ Arg2.getAsTemplate());
+
+ case TemplateArgument::TemplateExpansion:
+ return IsStructurallyEquivalent(Context,
+ Arg1.getAsTemplateOrTemplatePattern(),
+ Arg2.getAsTemplateOrTemplatePattern());
+
+ case TemplateArgument::Expression:
+ return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
+ Arg2.getAsExpr());
+
+ case TemplateArgument::Pack:
+ if (Arg1.pack_size() != Arg2.pack_size())
+ return false;
+
+ for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I)
+ if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I],
+ Arg2.pack_begin()[I]))
+ return false;
+
+ return true;
+ }
+
+ llvm_unreachable("Invalid template argument kind");
+}
+
+/// Determine structural equivalence for the common part of array
+/// types.
+static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const ArrayType *Array1,
+ const ArrayType *Array2) {
+ if (!IsStructurallyEquivalent(Context, Array1->getElementType(),
+ Array2->getElementType()))
+ return false;
+ if (Array1->getSizeModifier() != Array2->getSizeModifier())
+ return false;
+ if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers())
+ return false;
+
+ return true;
+}
+
+/// Determine structural equivalence of two types.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ QualType T1, QualType T2) {
+ if (T1.isNull() || T2.isNull())
+ return T1.isNull() && T2.isNull();
+
+ if (!Context.StrictTypeSpelling) {
+ // We aren't being strict about token-to-token equivalence of types,
+ // so map down to the canonical type.
+ T1 = Context.FromCtx.getCanonicalType(T1);
+ T2 = Context.ToCtx.getCanonicalType(T2);
+ }
+
+ if (T1.getQualifiers() != T2.getQualifiers())
+ return false;
+
+ Type::TypeClass TC = T1->getTypeClass();
+
+ if (T1->getTypeClass() != T2->getTypeClass()) {
+ // Compare function types with prototypes vs. without prototypes as if
+ // both did not have prototypes.
+ if (T1->getTypeClass() == Type::FunctionProto &&
+ T2->getTypeClass() == Type::FunctionNoProto)
+ TC = Type::FunctionNoProto;
+ else if (T1->getTypeClass() == Type::FunctionNoProto &&
+ T2->getTypeClass() == Type::FunctionProto)
+ TC = Type::FunctionNoProto;
+ else
+ return false;
+ }
+
+ switch (TC) {
+ case Type::Builtin:
+ // FIXME: Deal with Char_S/Char_U.
+ if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
+ return false;
+ break;
+
+ case Type::Complex:
+ if (!IsStructurallyEquivalent(Context,
+ cast<ComplexType>(T1)->getElementType(),
+ cast<ComplexType>(T2)->getElementType()))
+ return false;
+ break;
+
+ case Type::Adjusted:
+ case Type::Decayed:
+ if (!IsStructurallyEquivalent(Context,
+ cast<AdjustedType>(T1)->getOriginalType(),
+ cast<AdjustedType>(T2)->getOriginalType()))
+ return false;
+ break;
+
+ case Type::Pointer:
+ if (!IsStructurallyEquivalent(Context,
+ cast<PointerType>(T1)->getPointeeType(),
+ cast<PointerType>(T2)->getPointeeType()))
+ return false;
+ break;
+
+ case Type::BlockPointer:
+ if (!IsStructurallyEquivalent(Context,
+ cast<BlockPointerType>(T1)->getPointeeType(),
+ cast<BlockPointerType>(T2)->getPointeeType()))
+ return false;
+ break;
+
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ const ReferenceType *Ref1 = cast<ReferenceType>(T1);
+ const ReferenceType *Ref2 = cast<ReferenceType>(T2);
+ if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue())
+ return false;
+ if (Ref1->isInnerRef() != Ref2->isInnerRef())
+ return false;
+ if (!IsStructurallyEquivalent(Context, Ref1->getPointeeTypeAsWritten(),
+ Ref2->getPointeeTypeAsWritten()))
+ return false;
+ break;
+ }
+
+ case Type::MemberPointer: {
+ const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1);
+ const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2);
+ if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(),
+ MemPtr2->getPointeeType()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, QualType(MemPtr1->getClass(), 0),
+ QualType(MemPtr2->getClass(), 0)))
+ return false;
+ break;
+ }
+
+ case Type::ConstantArray: {
+ const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1);
+ const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2);
+ if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+ break;
+ }
+
+ case Type::IncompleteArray:
+ if (!IsArrayStructurallyEquivalent(Context, cast<ArrayType>(T1),
+ cast<ArrayType>(T2)))
+ return false;
+ break;
+
+ case Type::VariableArray: {
+ const VariableArrayType *Array1 = cast<VariableArrayType>(T1);
+ const VariableArrayType *Array2 = cast<VariableArrayType>(T2);
+ if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
+ Array2->getSizeExpr()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentSizedArray: {
+ const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1);
+ const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2);
+ if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(),
+ Array2->getSizeExpr()))
+ return false;
+
+ if (!IsArrayStructurallyEquivalent(Context, Array1, Array2))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentSizedExtVector: {
+ const DependentSizedExtVectorType *Vec1 =
+ cast<DependentSizedExtVectorType>(T1);
+ const DependentSizedExtVectorType *Vec2 =
+ cast<DependentSizedExtVectorType>(T2);
+ if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(),
+ Vec2->getSizeExpr()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
+ Vec2->getElementType()))
+ return false;
+ break;
+ }
+
+ case Type::Vector:
+ case Type::ExtVector: {
+ const VectorType *Vec1 = cast<VectorType>(T1);
+ const VectorType *Vec2 = cast<VectorType>(T2);
+ if (!IsStructurallyEquivalent(Context, Vec1->getElementType(),
+ Vec2->getElementType()))
+ return false;
+ if (Vec1->getNumElements() != Vec2->getNumElements())
+ return false;
+ if (Vec1->getVectorKind() != Vec2->getVectorKind())
+ return false;
+ break;
+ }
+
+ case Type::FunctionProto: {
+ const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1);
+ const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2);
+ if (Proto1->getNumParams() != Proto2->getNumParams())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),
+ Proto2->getParamType(I)))
+ return false;
+ }
+ if (Proto1->isVariadic() != Proto2->isVariadic())
+ return false;
+ if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType())
+ return false;
+ if (Proto1->getExceptionSpecType() == EST_Dynamic) {
+ if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
+ return false;
+ for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I),
+ Proto2->getExceptionType(I)))
+ return false;
+ }
+ } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) {
+ if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),
+ Proto2->getNoexceptExpr()))
+ return false;
+ }
+ if (Proto1->getTypeQuals() != Proto2->getTypeQuals())
+ return false;
+
+ // Fall through to check the bits common with FunctionNoProtoType.
+ LLVM_FALLTHROUGH;
+ }
+
+ case Type::FunctionNoProto: {
+ const FunctionType *Function1 = cast<FunctionType>(T1);
+ const FunctionType *Function2 = cast<FunctionType>(T2);
+ if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
+ Function2->getReturnType()))
+ return false;
+ if (Function1->getExtInfo() != Function2->getExtInfo())
+ return false;
+ break;
+ }
+
+ case Type::UnresolvedUsing:
+ if (!IsStructurallyEquivalent(Context,
+ cast<UnresolvedUsingType>(T1)->getDecl(),
+ cast<UnresolvedUsingType>(T2)->getDecl()))
+ return false;
+
+ break;
+
+ case Type::Attributed:
+ if (!IsStructurallyEquivalent(Context,
+ cast<AttributedType>(T1)->getModifiedType(),
+ cast<AttributedType>(T2)->getModifiedType()))
+ return false;
+ if (!IsStructurallyEquivalent(
+ Context, cast<AttributedType>(T1)->getEquivalentType(),
+ cast<AttributedType>(T2)->getEquivalentType()))
+ return false;
+ break;
+
+ case Type::Paren:
+ if (!IsStructurallyEquivalent(Context, cast<ParenType>(T1)->getInnerType(),
+ cast<ParenType>(T2)->getInnerType()))
+ return false;
+ break;
+
+ case Type::Typedef:
+ if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
+ cast<TypedefType>(T2)->getDecl()))
+ return false;
+ break;
+
+ case Type::TypeOfExpr:
+ if (!IsStructurallyEquivalent(
+ Context, cast<TypeOfExprType>(T1)->getUnderlyingExpr(),
+ cast<TypeOfExprType>(T2)->getUnderlyingExpr()))
+ return false;
+ break;
+
+ case Type::TypeOf:
+ if (!IsStructurallyEquivalent(Context,
+ cast<TypeOfType>(T1)->getUnderlyingType(),
+ cast<TypeOfType>(T2)->getUnderlyingType()))
+ return false;
+ break;
+
+ case Type::UnaryTransform:
+ if (!IsStructurallyEquivalent(
+ Context, cast<UnaryTransformType>(T1)->getUnderlyingType(),
+ cast<UnaryTransformType>(T1)->getUnderlyingType()))
+ return false;
+ break;
+
+ case Type::Decltype:
+ if (!IsStructurallyEquivalent(Context,
+ cast<DecltypeType>(T1)->getUnderlyingExpr(),
+ cast<DecltypeType>(T2)->getUnderlyingExpr()))
+ return false;
+ break;
+
+ case Type::Auto:
+ if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(),
+ cast<AutoType>(T2)->getDeducedType()))
+ return false;
+ break;
+
+ case Type::DeducedTemplateSpecialization: {
+ auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
+ auto *DT2 = cast<DeducedTemplateSpecializationType>(T2);
+ if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(),
+ DT2->getTemplateName()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, DT1->getDeducedType(),
+ DT2->getDeducedType()))
+ return false;
+ break;
+ }
+
+ case Type::Record:
+ case Type::Enum:
+ if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(),
+ cast<TagType>(T2)->getDecl()))
+ return false;
+ break;
+
+ case Type::TemplateTypeParm: {
+ const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1);
+ const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2);
+ if (Parm1->getDepth() != Parm2->getDepth())
+ return false;
+ if (Parm1->getIndex() != Parm2->getIndex())
+ return false;
+ if (Parm1->isParameterPack() != Parm2->isParameterPack())
+ return false;
+
+ // Names of template type parameters are never significant.
+ break;
+ }
+
+ case Type::SubstTemplateTypeParm: {
+ const SubstTemplateTypeParmType *Subst1 =
+ cast<SubstTemplateTypeParmType>(T1);
+ const SubstTemplateTypeParmType *Subst2 =
+ cast<SubstTemplateTypeParmType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ QualType(Subst1->getReplacedParameter(), 0),
+ QualType(Subst2->getReplacedParameter(), 0)))
+ return false;
+ if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
+ Subst2->getReplacementType()))
+ return false;
+ break;
+ }
+
+ case Type::SubstTemplateTypeParmPack: {
+ const SubstTemplateTypeParmPackType *Subst1 =
+ cast<SubstTemplateTypeParmPackType>(T1);
+ const SubstTemplateTypeParmPackType *Subst2 =
+ cast<SubstTemplateTypeParmPackType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ QualType(Subst1->getReplacedParameter(), 0),
+ QualType(Subst2->getReplacedParameter(), 0)))
+ return false;
+ if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
+ Subst2->getArgumentPack()))
+ return false;
+ break;
+ }
+ case Type::TemplateSpecialization: {
+ const TemplateSpecializationType *Spec1 =
+ cast<TemplateSpecializationType>(T1);
+ const TemplateSpecializationType *Spec2 =
+ cast<TemplateSpecializationType>(T2);
+ if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
+ Spec2->getTemplateName()))
+ return false;
+ if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ return false;
+ for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
+ Spec2->getArg(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::Elaborated: {
+ const ElaboratedType *Elab1 = cast<ElaboratedType>(T1);
+ const ElaboratedType *Elab2 = cast<ElaboratedType>(T2);
+ // CHECKME: what if a keyword is ETK_None or ETK_typename ?
+ if (Elab1->getKeyword() != Elab2->getKeyword())
+ return false;
+ if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(),
+ Elab2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(),
+ Elab2->getNamedType()))
+ return false;
+ break;
+ }
+
+ case Type::InjectedClassName: {
+ const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1);
+ const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ Inj1->getInjectedSpecializationType(),
+ Inj2->getInjectedSpecializationType()))
+ return false;
+ break;
+ }
+
+ case Type::DependentName: {
+ const DependentNameType *Typename1 = cast<DependentNameType>(T1);
+ const DependentNameType *Typename2 = cast<DependentNameType>(T2);
+ if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(),
+ Typename2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Typename1->getIdentifier(),
+ Typename2->getIdentifier()))
+ return false;
+
+ break;
+ }
+
+ case Type::DependentTemplateSpecialization: {
+ const DependentTemplateSpecializationType *Spec1 =
+ cast<DependentTemplateSpecializationType>(T1);
+ const DependentTemplateSpecializationType *Spec2 =
+ cast<DependentTemplateSpecializationType>(T2);
+ if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(),
+ Spec2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
+ Spec2->getIdentifier()))
+ return false;
+ if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ return false;
+ for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
+ Spec2->getArg(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::PackExpansion:
+ if (!IsStructurallyEquivalent(Context,
+ cast<PackExpansionType>(T1)->getPattern(),
+ cast<PackExpansionType>(T2)->getPattern()))
+ return false;
+ break;
+
+ case Type::ObjCInterface: {
+ const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1);
+ const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2);
+ if (!IsStructurallyEquivalent(Context, Iface1->getDecl(),
+ Iface2->getDecl()))
+ return false;
+ break;
+ }
+
+ case Type::ObjCTypeParam: {
+ const ObjCTypeParamType *Obj1 = cast<ObjCTypeParamType>(T1);
+ const ObjCTypeParamType *Obj2 = cast<ObjCTypeParamType>(T2);
+ if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl()))
+ return false;
+
+ if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
+ return false;
+ for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
+ Obj2->getProtocol(I)))
+ return false;
+ }
+ break;
+ }
+ case Type::ObjCObject: {
+ const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1);
+ const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2);
+ if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(),
+ Obj2->getBaseType()))
+ return false;
+ if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
+ return false;
+ for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Obj1->getProtocol(I),
+ Obj2->getProtocol(I)))
+ return false;
+ }
+ break;
+ }
+
+ case Type::ObjCObjectPointer: {
+ const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1);
+ const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2);
+ if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(),
+ Ptr2->getPointeeType()))
+ return false;
+ break;
+ }
+
+ case Type::Atomic: {
+ if (!IsStructurallyEquivalent(Context, cast<AtomicType>(T1)->getValueType(),
+ cast<AtomicType>(T2)->getValueType()))
+ return false;
+ break;
+ }
+
+ case Type::Pipe: {
+ if (!IsStructurallyEquivalent(Context, cast<PipeType>(T1)->getElementType(),
+ cast<PipeType>(T2)->getElementType()))
+ return false;
+ break;
+ }
+
+ } // end switch
+
+ return true;
+}
+
+/// Determine structural equivalence of two fields.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ FieldDecl *Field1, FieldDecl *Field2) {
+ RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
+
+ // For anonymous structs/unions, match up the anonymous struct/union type
+ // declarations directly, so that we don't go off searching for anonymous
+ // types
+ if (Field1->isAnonymousStructOrUnion() &&
+ Field2->isAnonymousStructOrUnion()) {
+ RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
+ return IsStructurallyEquivalent(Context, D1, D2);
+ }
+
+ // Check for equivalent field names.
+ IdentifierInfo *Name1 = Field1->getIdentifier();
+ IdentifierInfo *Name2 = Field2->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2)) {
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field_name)
+ << Field2->getDeclName();
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field_name)
+ << Field1->getDeclName();
+ }
+ return false;
+ }
+
+ if (!IsStructurallyEquivalent(Context, Field1->getType(),
+ Field2->getType())) {
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ }
+ return false;
+ }
+
+ if (Field1->isBitField() != Field2->isBitField()) {
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(Owner2);
+ if (Field1->isBitField()) {
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType()
+ << Field1->getBitWidthValue(Context.FromCtx);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field)
+ << Field2->getDeclName();
+ } else {
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType()
+ << Field2->getBitWidthValue(Context.ToCtx);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field)
+ << Field1->getDeclName();
+ }
+ }
+ return false;
+ }
+
+ if (Field1->isBitField()) {
+ // Make sure that the bit-fields are the same length.
+ unsigned Bits1 = Field1->getBitWidthValue(Context.FromCtx);
+ unsigned Bits2 = Field2->getBitWidthValue(Context.ToCtx);
+
+ if (Bits1 != Bits2) {
+ if (Context.Complain) {
+ Context.Diag2(Owner2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(Owner2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field)
+ << Field2->getDeclName() << Field2->getType() << Bits2;
+ Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field)
+ << Field1->getDeclName() << Field1->getType() << Bits1;
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/// Determine structural equivalence of two records.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ RecordDecl *D1, RecordDecl *D2) {
+ if (D1->isUnion() != D2->isUnion()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
+ << D1->getDeclName() << (unsigned)D1->getTagKind();
+ }
+ return false;
+ }
+
+ if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) {
+ // If both anonymous structs/unions are in a record context, make sure
+ // they occur in the same location in the context records.
+ if (Optional<unsigned> Index1 =
+ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) {
+ if (Optional<unsigned> Index2 =
+ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
+ D2)) {
+ if (*Index1 != *Index2)
+ return false;
+ }
+ }
+ }
+
+ // If both declarations are class template specializations, we know
+ // the ODR applies, so check the template and template arguments.
+ ClassTemplateSpecializationDecl *Spec1 =
+ dyn_cast<ClassTemplateSpecializationDecl>(D1);
+ ClassTemplateSpecializationDecl *Spec2 =
+ dyn_cast<ClassTemplateSpecializationDecl>(D2);
+ if (Spec1 && Spec2) {
+ // Check that the specialized templates are the same.
+ if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),
+ Spec2->getSpecializedTemplate()))
+ return false;
+
+ // Check that the template arguments are the same.
+ if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
+ return false;
+
+ for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I)
+ if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs().get(I),
+ Spec2->getTemplateArgs().get(I)))
+ return false;
+ }
+ // If one is a class template specialization and the other is not, these
+ // structures are different.
+ else if (Spec1 || Spec2)
+ return false;
+
+ // Compare the definitions of these two records. If either or both are
+ // incomplete, we assume that they are equivalent.
+ D1 = D1->getDefinition();
+ D2 = D2->getDefinition();
+ if (!D1 || !D2)
+ return true;
+
+ if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
+ if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
+ if (D1CXX->hasExternalLexicalStorage() &&
+ !D1CXX->isCompleteDefinition()) {
+ D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX);
+ }
+
+ if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
+ << D2CXX->getNumBases();
+ Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
+ << D1CXX->getNumBases();
+ }
+ return false;
+ }
+
+ // Check the base classes.
+ for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(),
+ BaseEnd1 = D1CXX->bases_end(),
+ Base2 = D2CXX->bases_begin();
+ Base1 != BaseEnd1; ++Base1, ++Base2) {
+ if (!IsStructurallyEquivalent(Context, Base1->getType(),
+ Base2->getType())) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(Base2->getLocStart(), diag::note_odr_base)
+ << Base2->getType() << Base2->getSourceRange();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->getType() << Base1->getSourceRange();
+ }
+ return false;
+ }
+
+ // Check virtual vs. non-virtual inheritance mismatch.
+ if (Base1->isVirtual() != Base2->isVirtual()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(Base2->getLocStart(), diag::note_odr_virtual_base)
+ << Base2->isVirtual() << Base2->getSourceRange();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->isVirtual() << Base1->getSourceRange();
+ }
+ return false;
+ }
+ }
+ } else if (D1CXX->getNumBases() > 0) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
+ Context.Diag1(Base1->getLocStart(), diag::note_odr_base)
+ << Base1->getType() << Base1->getSourceRange();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_base);
+ }
+ return false;
+ }
+ }
+
+ // Check the fields for consistency.
+ RecordDecl::field_iterator Field2 = D2->field_begin(),
+ Field2End = D2->field_end();
+ for (RecordDecl::field_iterator Field1 = D1->field_begin(),
+ Field1End = D1->field_end();
+ Field1 != Field1End; ++Field1, ++Field2) {
+ if (Field2 == Field2End) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag1(Field1->getLocation(), diag::note_odr_field)
+ << Field1->getDeclName() << Field1->getType();
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_field);
+ }
+ return false;
+ }
+
+ if (!IsStructurallyEquivalent(Context, *Field1, *Field2))
+ return false;
+ }
+
+ if (Field2 != Field2End) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(Field2->getLocation(), diag::note_odr_field)
+ << Field2->getDeclName() << Field2->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_field);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+/// Determine structural equivalence of two enums.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ EnumDecl *D1, EnumDecl *D2) {
+ EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(),
+ EC2End = D2->enumerator_end();
+ for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(),
+ EC1End = D1->enumerator_end();
+ EC1 != EC1End; ++EC1, ++EC2) {
+ if (EC2 == EC2End) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName() << EC1->getInitVal().toString(10);
+ Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator);
+ }
+ return false;
+ }
+
+ llvm::APSInt Val1 = EC1->getInitVal();
+ llvm::APSInt Val2 = EC2->getInitVal();
+ if (!llvm::APSInt::isSameValue(Val1, Val2) ||
+ !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName() << EC2->getInitVal().toString(10);
+ Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator)
+ << EC1->getDeclName() << EC1->getInitVal().toString(10);
+ }
+ return false;
+ }
+ }
+
+ if (EC2 != EC2End) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ Context.ErrorOnTagTypeMismatch
+ ? diag::err_odr_tag_type_inconsistent
+ : diag::warn_odr_tag_type_inconsistent)
+ << Context.ToCtx.getTypeDeclType(D2);
+ Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator)
+ << EC2->getDeclName() << EC2->getInitVal().toString(10);
+ Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ TemplateParameterList *Params1,
+ TemplateParameterList *Params2) {
+ if (Params1->size() != Params2->size()) {
+ if (Context.Complain) {
+ Context.Diag2(Params2->getTemplateLoc(),
+ diag::err_odr_different_num_template_parameters)
+ << Params1->size() << Params2->size();
+ Context.Diag1(Params1->getTemplateLoc(),
+ diag::note_odr_template_parameter_list);
+ }
+ return false;
+ }
+
+ for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
+ if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
+ if (Context.Complain) {
+ Context.Diag2(Params2->getParam(I)->getLocation(),
+ diag::err_odr_different_template_parameter_kind);
+ Context.Diag1(Params1->getParam(I)->getLocation(),
+ diag::note_odr_template_parameter_here);
+ }
+ return false;
+ }
+
+ if (!Context.IsStructurallyEquivalent(Params1->getParam(I),
+ Params2->getParam(I))) {
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ TemplateTypeParmDecl *D1,
+ TemplateTypeParmDecl *D2) {
+ if (D1->isParameterPack() != D2->isParameterPack()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ NonTypeTemplateParmDecl *D1,
+ NonTypeTemplateParmDecl *D2) {
+ if (D1->isParameterPack() != D2->isParameterPack()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
+ return false;
+ }
+
+ // Check types.
+ if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(),
+ diag::err_odr_non_type_parameter_type_inconsistent)
+ << D2->getType() << D1->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
+ << D1->getType();
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ TemplateTemplateParmDecl *D1,
+ TemplateTemplateParmDecl *D2) {
+ if (D1->isParameterPack() != D2->isParameterPack()) {
+ if (Context.Complain) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ }
+ return false;
+ }
+
+ // Check template parameter lists.
+ return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
+ D2->getTemplateParameters());
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ ClassTemplateDecl *D1,
+ ClassTemplateDecl *D2) {
+ // Check template parameters.
+ if (!IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
+ D2->getTemplateParameters()))
+ return false;
+
+ // Check the templated declaration.
+ return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(),
+ D2->getTemplatedDecl());
+}
+
+/// Determine structural equivalence of two declarations.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ Decl *D1, Decl *D2) {
+ // FIXME: Check for known structural equivalences via a callback of some sort.
+
+ // Check whether we already know that these two declarations are not
+ // structurally equivalent.
+ if (Context.NonEquivalentDecls.count(
+ std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl())))
+ return false;
+
+ // Determine whether we've already produced a tentative equivalence for D1.
+ Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
+ if (EquivToD1)
+ return EquivToD1 == D2->getCanonicalDecl();
+
+ // Produce a tentative equivalence D1 <-> D2, which will be checked later.
+ EquivToD1 = D2->getCanonicalDecl();
+ Context.DeclsToCheck.push_back(D1->getCanonicalDecl());
+ return true;
+}
+} // namespace
+
+namespace clang {
+
+DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc,
+ unsigned DiagID) {
+ assert(Complain && "Not allowed to complain");
+ if (LastDiagFromC2)
+ FromCtx.getDiagnostics().notePriorDiagnosticFrom(ToCtx.getDiagnostics());
+ LastDiagFromC2 = false;
+ return FromCtx.getDiagnostics().Report(Loc, DiagID);
+}
+
+DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,
+ unsigned DiagID) {
+ assert(Complain && "Not allowed to complain");
+ if (!LastDiagFromC2)
+ ToCtx.getDiagnostics().notePriorDiagnosticFrom(FromCtx.getDiagnostics());
+ LastDiagFromC2 = true;
+ return ToCtx.getDiagnostics().Report(Loc, DiagID);
+}
+
+Optional<unsigned>
+StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
+ ASTContext &Context = Anon->getASTContext();
+ QualType AnonTy = Context.getRecordType(Anon);
+
+ RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
+ if (!Owner)
+ return None;
+
+ unsigned Index = 0;
+ for (const auto *D : Owner->noload_decls()) {
+ const auto *F = dyn_cast<FieldDecl>(D);
+ if (!F)
+ continue;
+
+ if (F->isAnonymousStructOrUnion()) {
+ if (Context.hasSameType(F->getType(), AnonTy))
+ break;
+ ++Index;
+ continue;
+ }
+
+ // If the field looks like this:
+ // struct { ... } A;
+ QualType FieldType = F->getType();
+ if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
+ const RecordDecl *RecDecl = RecType->getDecl();
+ if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) {
+ if (Context.hasSameType(FieldType, AnonTy))
+ break;
+ ++Index;
+ continue;
+ }
+ }
+ }
+
+ return Index;
+}
+
+bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1,
+ Decl *D2) {
+ if (!::IsStructurallyEquivalent(*this, D1, D2))
+ return false;
+
+ return !Finish();
+}
+
+bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1,
+ QualType T2) {
+ if (!::IsStructurallyEquivalent(*this, T1, T2))
+ return false;
+
+ return !Finish();
+}
+
+bool StructuralEquivalenceContext::Finish() {
+ while (!DeclsToCheck.empty()) {
+ // Check the next declaration.
+ Decl *D1 = DeclsToCheck.front();
+ DeclsToCheck.pop_front();
+
+ Decl *D2 = TentativeEquivalences[D1];
+ assert(D2 && "Unrecorded tentative equivalence?");
+
+ bool Equivalent = true;
+
+ // FIXME: Switch on all declaration kinds. For now, we're just going to
+ // check the obvious ones.
+ if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) {
+ if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) {
+ // Check for equivalent structure names.
+ IdentifierInfo *Name1 = Record1->getIdentifier();
+ if (!Name1 && Record1->getTypedefNameForAnonDecl())
+ Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier();
+ IdentifierInfo *Name2 = Record2->getIdentifier();
+ if (!Name2 && Record2->getTypedefNameForAnonDecl())
+ Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2) ||
+ !::IsStructurallyEquivalent(*this, Record1, Record2))
+ Equivalent = false;
+ } else {
+ // Record/non-record mismatch.
+ Equivalent = false;
+ }
+ } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) {
+ if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
+ // Check for equivalent enum names.
+ IdentifierInfo *Name1 = Enum1->getIdentifier();
+ if (!Name1 && Enum1->getTypedefNameForAnonDecl())
+ Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier();
+ IdentifierInfo *Name2 = Enum2->getIdentifier();
+ if (!Name2 && Enum2->getTypedefNameForAnonDecl())
+ Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier();
+ if (!::IsStructurallyEquivalent(Name1, Name2) ||
+ !::IsStructurallyEquivalent(*this, Enum1, Enum2))
+ Equivalent = false;
+ } else {
+ // Enum/non-enum mismatch
+ Equivalent = false;
+ }
+ } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) {
+ if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
+ Typedef2->getIdentifier()) ||
+ !::IsStructurallyEquivalent(*this, Typedef1->getUnderlyingType(),
+ Typedef2->getUnderlyingType()))
+ Equivalent = false;
+ } else {
+ // Typedef/non-typedef mismatch.
+ Equivalent = false;
+ }
+ } else if (ClassTemplateDecl *ClassTemplate1 =
+ dyn_cast<ClassTemplateDecl>(D1)) {
+ if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(),
+ ClassTemplate2->getIdentifier()) ||
+ !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2))
+ Equivalent = false;
+ } else {
+ // Class template/non-class-template mismatch.
+ Equivalent = false;
+ }
+ } else if (TemplateTypeParmDecl *TTP1 =
+ dyn_cast<TemplateTypeParmDecl>(D1)) {
+ if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
+ Equivalent = false;
+ } else {
+ // Kind mismatch.
+ Equivalent = false;
+ }
+ } else if (NonTypeTemplateParmDecl *NTTP1 =
+ dyn_cast<NonTypeTemplateParmDecl>(D1)) {
+ if (NonTypeTemplateParmDecl *NTTP2 =
+ dyn_cast<NonTypeTemplateParmDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2))
+ Equivalent = false;
+ } else {
+ // Kind mismatch.
+ Equivalent = false;
+ }
+ } else if (TemplateTemplateParmDecl *TTP1 =
+ dyn_cast<TemplateTemplateParmDecl>(D1)) {
+ if (TemplateTemplateParmDecl *TTP2 =
+ dyn_cast<TemplateTemplateParmDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
+ Equivalent = false;
+ } else {
+ // Kind mismatch.
+ Equivalent = false;
+ }
+ }
+
+ if (!Equivalent) {
+ // Note that these two declarations are not equivalent (and we already
+ // know about it).
+ NonEquivalentDecls.insert(
+ std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl()));
+ return true;
+ }
+ // FIXME: Check other declaration kinds!
+ }
+
+ return false;
+}
+} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp
index a97d6a2..fc4d8b1 100644
--- a/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/SetVector.h"
#include <algorithm>
@@ -56,6 +57,7 @@ bool CXXBasePaths::isAmbiguous(CanQualType BaseType) {
void CXXBasePaths::clear() {
Paths.clear();
ClassSubobjects.clear();
+ VisitedDependentRecords.clear();
ScratchPath.clear();
DetectedVirtual = nullptr;
}
@@ -66,6 +68,7 @@ void CXXBasePaths::swap(CXXBasePaths &Other) {
std::swap(Origin, Other.Origin);
Paths.swap(Other.Paths);
ClassSubobjects.swap(Other.ClassSubobjects);
+ VisitedDependentRecords.swap(Other.VisitedDependentRecords);
std::swap(FindAmbiguities, Other.FindAmbiguities);
std::swap(RecordPaths, Other.RecordPaths);
std::swap(DetectVirtual, Other.DetectVirtual);
@@ -88,7 +91,7 @@ bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base,
const CXXRecordDecl *BaseDecl = Base->getCanonicalDecl();
// FIXME: Capturing 'this' is a workaround for name lookup bugs in GCC 4.7.
return lookupInBases(
- [this, BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
+ [BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
return FindBaseClass(Specifier, Path, BaseDecl);
},
Paths);
@@ -109,7 +112,7 @@ bool CXXRecordDecl::isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const {
const CXXRecordDecl *BaseDecl = Base->getCanonicalDecl();
// FIXME: Capturing 'this' is a workaround for name lookup bugs in GCC 4.7.
return lookupInBases(
- [this, BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
+ [BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
return FindVirtualBaseClass(Specifier, Path, BaseDecl);
},
Paths);
@@ -174,9 +177,10 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches,
return AllMatches;
}
-bool CXXBasePaths::lookupInBases(
- ASTContext &Context, const CXXRecordDecl *Record,
- CXXRecordDecl::BaseMatchesCallback BaseMatches) {
+bool CXXBasePaths::lookupInBases(ASTContext &Context,
+ const CXXRecordDecl *Record,
+ CXXRecordDecl::BaseMatchesCallback BaseMatches,
+ bool LookupInDependent) {
bool FoundPath = false;
// The access of the path down to this record.
@@ -194,7 +198,7 @@ bool CXXBasePaths::lookupInBases(
// the base class scope is not examined during unqualified name lookup
// either at the point of definition of the class template or member or
// during an instantiation of the class tem- plate or member.
- if (BaseType->isDependentType())
+ if (!LookupInDependent && BaseType->isDependentType())
continue;
// Determine whether we need to visit this base class at all,
@@ -262,10 +266,34 @@ bool CXXBasePaths::lookupInBases(
return FoundPath;
}
} else if (VisitBase) {
- CXXRecordDecl *BaseRecord
- = cast<CXXRecordDecl>(BaseSpec.getType()->castAs<RecordType>()
- ->getDecl());
- if (lookupInBases(Context, BaseRecord, BaseMatches)) {
+ CXXRecordDecl *BaseRecord;
+ if (LookupInDependent) {
+ BaseRecord = nullptr;
+ const TemplateSpecializationType *TST =
+ BaseSpec.getType()->getAs<TemplateSpecializationType>();
+ if (!TST) {
+ if (auto *RT = BaseSpec.getType()->getAs<RecordType>())
+ BaseRecord = cast<CXXRecordDecl>(RT->getDecl());
+ } else {
+ TemplateName TN = TST->getTemplateName();
+ if (auto *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()))
+ BaseRecord = TD->getTemplatedDecl();
+ }
+ if (BaseRecord) {
+ if (!BaseRecord->hasDefinition() ||
+ VisitedDependentRecords.count(BaseRecord)) {
+ BaseRecord = nullptr;
+ } else {
+ VisitedDependentRecords.insert(BaseRecord);
+ }
+ }
+ } else {
+ BaseRecord = cast<CXXRecordDecl>(
+ BaseSpec.getType()->castAs<RecordType>()->getDecl());
+ }
+ if (BaseRecord &&
+ lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {
// C++ [class.member.lookup]p2:
// A member name f in one sub-object B hides a member name f in
// a sub-object A if A is a base class sub-object of B. Any
@@ -299,9 +327,11 @@ bool CXXBasePaths::lookupInBases(
}
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches,
- CXXBasePaths &Paths) const {
+ CXXBasePaths &Paths,
+ bool LookupInDependent) const {
// If we didn't find anything, report that.
- if (!Paths.lookupInBases(getASTContext(), this, BaseMatches))
+ if (!Paths.lookupInBases(getASTContext(), this, BaseMatches,
+ LookupInDependent))
return false;
// If we're not recording paths or we won't ever find ambiguities,
@@ -387,23 +417,49 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
return false;
}
-bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
- CXXBasePath &Path,
- DeclarationName Name) {
- RecordDecl *BaseRecord =
- Specifier->getType()->castAs<RecordType>()->getDecl();
-
- const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
+static bool findOrdinaryMember(RecordDecl *BaseRecord, CXXBasePath &Path,
+ DeclarationName Name) {
+ const unsigned IDNS = clang::Decl::IDNS_Ordinary | clang::Decl::IDNS_Tag |
+ clang::Decl::IDNS_Member;
for (Path.Decls = BaseRecord->lookup(Name);
!Path.Decls.empty();
Path.Decls = Path.Decls.slice(1)) {
if (Path.Decls.front()->isInIdentifierNamespace(IDNS))
return true;
}
-
+
return false;
}
+bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ DeclarationName Name) {
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
+ return findOrdinaryMember(BaseRecord, Path, Name);
+}
+
+bool CXXRecordDecl::FindOrdinaryMemberInDependentClasses(
+ const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
+ DeclarationName Name) {
+ const TemplateSpecializationType *TST =
+ Specifier->getType()->getAs<TemplateSpecializationType>();
+ if (!TST) {
+ auto *RT = Specifier->getType()->getAs<RecordType>();
+ if (!RT)
+ return false;
+ return findOrdinaryMember(RT->getDecl(), Path, Name);
+ }
+ TemplateName TN = TST->getTemplateName();
+ const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ return false;
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ if (!RD)
+ return false;
+ return findOrdinaryMember(RD, Path, Name);
+}
+
bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) {
@@ -438,6 +494,36 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
return false;
}
+std::vector<const NamedDecl *> CXXRecordDecl::lookupDependentName(
+ const DeclarationName &Name,
+ llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
+ std::vector<const NamedDecl *> Results;
+ // Lookup in the class.
+ DeclContext::lookup_result DirectResult = lookup(Name);
+ if (!DirectResult.empty()) {
+ for (const NamedDecl *ND : DirectResult) {
+ if (Filter(ND))
+ Results.push_back(ND);
+ }
+ return Results;
+ }
+ // Perform lookup into our base classes.
+ CXXBasePaths Paths;
+ Paths.setOrigin(this);
+ if (!lookupInBases(
+ [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
+ return CXXRecordDecl::FindOrdinaryMemberInDependentClasses(
+ Specifier, Path, Name);
+ },
+ Paths, /*LookupInDependent=*/true))
+ return Results;
+ for (const NamedDecl *ND : Paths.front().Decls) {
+ if (Filter(ND))
+ Results.push_back(ND);
+ }
+ return Results;
+}
+
void OverridingMethods::add(unsigned OverriddenSubobject,
UniqueVirtualMethod Overriding) {
SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides
diff --git a/contrib/llvm/tools/clang/lib/AST/Comment.cpp b/contrib/llvm/tools/clang/lib/AST/Comment.cpp
index 7a7d3dd..dfa2a16 100644
--- a/contrib/llvm/tools/clang/lib/AST/Comment.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/Comment.cpp
@@ -116,6 +116,9 @@ bool ParagraphComment::isWhitespaceNoCache() const {
static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) {
TypeLoc TL = SrcTL.IgnoreParens();
+ // Look through attribute types.
+ if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>())
+ return AttributeTL.getModifiedLoc();
// Look through qualified types.
if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>())
return QualifiedTL.getUnqualifiedLoc();
@@ -280,8 +283,25 @@ void DeclInfo::fill() {
case Decl::EnumConstant:
case Decl::ObjCIvar:
case Decl::ObjCAtDefsField:
+ case Decl::ObjCProperty: {
+ const TypeSourceInfo *TSI;
+ if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl))
+ TSI = VD->getTypeSourceInfo();
+ else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl))
+ TSI = PD->getTypeSourceInfo();
+ else
+ TSI = nullptr;
+ if (TSI) {
+ TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
+ FunctionTypeLoc FTL;
+ if (getFunctionTypeLoc(TL, FTL)) {
+ ParamVars = FTL.getParams();
+ ReturnType = FTL.getReturnLoc().getType();
+ }
+ }
Kind = VariableKind;
break;
+ }
case Decl::Namespace:
Kind = NamespaceKind;
break;
diff --git a/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp b/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp
index d39a9b2..403454d 100644
--- a/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/CommentSema.cpp
@@ -86,7 +86,7 @@ ParamCommandComment *Sema::actOnParamCommandStart(
new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
CommandMarker);
- if (!isFunctionDecl())
+ if (!isFunctionDecl() && !isFunctionOrBlockPointerVarLikeDecl())
Diag(Command->getLocation(),
diag::warn_doc_param_not_attached_to_a_function_decl)
<< CommandMarker
@@ -584,7 +584,11 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
assert(ThisDeclInfo && "should not call this check on a bare comment");
- if (isFunctionDecl()) {
+ // We allow the return command for all @properties because it can be used
+ // to document the value that the property getter returns.
+ if (isObjCPropertyDecl())
+ return;
+ if (isFunctionDecl() || isFunctionOrBlockPointerVarLikeDecl()) {
if (ThisDeclInfo->ReturnType->isVoidType()) {
unsigned DiagKind;
switch (ThisDeclInfo->CommentDecl->getKind()) {
@@ -610,8 +614,6 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
return;
}
- else if (isObjCPropertyDecl())
- return;
Diag(Command->getLocation(),
diag::warn_doc_returns_not_attached_to_a_function_decl)
@@ -844,6 +846,30 @@ bool Sema::isFunctionPointerVarDecl() {
return false;
}
+bool Sema::isFunctionOrBlockPointerVarLikeDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (ThisDeclInfo->getKind() != DeclInfo::VariableKind ||
+ !ThisDeclInfo->CurrentDecl)
+ return false;
+ QualType QT;
+ if (const auto *VD = dyn_cast<DeclaratorDecl>(ThisDeclInfo->CurrentDecl))
+ QT = VD->getType();
+ else if (const auto *PD =
+ dyn_cast<ObjCPropertyDecl>(ThisDeclInfo->CurrentDecl))
+ QT = PD->getType();
+ else
+ return false;
+ // We would like to warn about the 'returns'/'param' commands for
+ // variables that don't directly specify the function type, so type aliases
+ // can be ignored.
+ if (QT->getAs<TypedefType>())
+ return false;
+ return QT->isFunctionPointerType() || QT->isBlockPointerType();
+}
+
bool Sema::isObjCPropertyDecl() {
if (!ThisDeclInfo)
return false;
diff --git a/contrib/llvm/tools/clang/lib/AST/Decl.cpp b/contrib/llvm/tools/clang/lib/AST/Decl.cpp
index 81f0878..573a98e 100644
--- a/contrib/llvm/tools/clang/lib/AST/Decl.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/Decl.cpp
@@ -47,9 +47,7 @@ bool Decl::isOutOfLine() const {
TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx)
: Decl(TranslationUnit, nullptr, SourceLocation()),
- DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {
- Hidden = Ctx.getLangOpts().ModulesLocalVisibility;
-}
+ DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {}
//===----------------------------------------------------------------------===//
// NamedDecl Implementation
@@ -575,6 +573,44 @@ static bool isSingleLineLanguageLinkage(const Decl &D) {
return false;
}
+static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) {
+ switch (D->getModuleOwnershipKind()) {
+ case Decl::ModuleOwnershipKind::Unowned:
+ case Decl::ModuleOwnershipKind::ModulePrivate:
+ return false;
+ case Decl::ModuleOwnershipKind::Visible:
+ case Decl::ModuleOwnershipKind::VisibleWhenImported:
+ if (auto *M = D->getOwningModule())
+ return M->Kind == Module::ModuleInterfaceUnit;
+ }
+ llvm_unreachable("unexpected module ownership kind");
+}
+
+static LinkageInfo getInternalLinkageFor(const NamedDecl *D) {
+ // Internal linkage declarations within a module interface unit are modeled
+ // as "module-internal linkage", which means that they have internal linkage
+ // formally but can be indirectly accessed from outside the module via inline
+ // functions and templates defined within the module.
+ if (auto *M = D->getOwningModule())
+ if (M->Kind == Module::ModuleInterfaceUnit)
+ return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false);
+
+ return LinkageInfo::internal();
+}
+
+static LinkageInfo getExternalLinkageFor(const NamedDecl *D) {
+ // C++ Modules TS [basic.link]/6.8:
+ // - A name declared at namespace scope that does not have internal linkage
+ // by the previous rules and that is introduced by a non-exported
+ // declaration has module linkage.
+ if (auto *M = D->getOwningModule())
+ if (M->Kind == Module::ModuleInterfaceUnit)
+ if (!isExportedFromModuleIntefaceUnit(D))
+ return LinkageInfo(ModuleLinkage, DefaultVisibility, false);
+
+ return LinkageInfo::external();
+}
+
static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
LVComputationKind computation) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
@@ -590,16 +626,18 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (const auto *Var = dyn_cast<VarDecl>(D)) {
// Explicitly declared static.
if (Var->getStorageClass() == SC_Static)
- return LinkageInfo::internal();
+ return getInternalLinkageFor(Var);
// - a non-inline, non-volatile object or reference that is explicitly
// declared const or constexpr and neither explicitly declared extern
// nor previously declared to have external linkage; or (there is no
// equivalent in C99)
+ // The C++ modules TS adds "non-exported" to this list.
if (Context.getLangOpts().CPlusPlus &&
Var->getType().isConstQualified() &&
!Var->getType().isVolatileQualified() &&
- !Var->isInline()) {
+ !Var->isInline() &&
+ !isExportedFromModuleIntefaceUnit(Var)) {
const VarDecl *PrevVar = Var->getPreviousDecl();
if (PrevVar)
return getLVForDecl(PrevVar, computation);
@@ -607,7 +645,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Var->getStorageClass() != SC_Extern &&
Var->getStorageClass() != SC_PrivateExtern &&
!isSingleLineLanguageLinkage(*Var))
- return LinkageInfo::internal();
+ return getInternalLinkageFor(Var);
}
for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar;
@@ -617,7 +655,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
return PrevVar->getLinkageAndVisibility();
// Explicitly declared static.
if (PrevVar->getStorageClass() == SC_Static)
- return LinkageInfo::internal();
+ return getInternalLinkageFor(Var);
}
} else if (const FunctionDecl *Function = D->getAsFunction()) {
// C++ [temp]p4:
@@ -626,7 +664,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Explicitly declared static.
if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
- return LinkageInfo(InternalLinkage, DefaultVisibility, false);
+ return getInternalLinkageFor(Function);
} else if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) {
// - a data member of an anonymous union.
const VarDecl *VD = IFD->getVarDecl();
@@ -639,7 +677,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
const auto *Var = dyn_cast<VarDecl>(D);
const auto *Func = dyn_cast<FunctionDecl>(D);
// FIXME: In C++11 onwards, anonymous namespaces should give decls
- // within them internal linkage, not unique external linkage.
+ // within them (including those inside extern "C" contexts) internal
+ // linkage, not unique external linkage:
+ //
+ // C++11 [basic.link]p4:
+ // An unnamed namespace or a namespace declared directly or indirectly
+ // within an unnamed namespace has internal linkage.
if ((!Var || !isFirstInExternCContext(Var)) &&
(!Func || !isFirstInExternCContext(Func)))
return LinkageInfo::uniqueExternal();
@@ -720,7 +763,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// because of this, but unique-external linkage suits us.
if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) {
LinkageInfo TypeLV = getLVForType(*Var->getType(), computation);
- if (TypeLV.getLinkage() != ExternalLinkage)
+ if (TypeLV.getLinkage() != ExternalLinkage &&
+ TypeLV.getLinkage() != ModuleLinkage)
return LinkageInfo::uniqueExternal();
if (!LV.isVisibilityExplicit())
LV.mergeVisibility(TypeLV);
@@ -818,7 +862,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
- } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
+ //
+ // We handled names in anonymous namespaces above.
+ } else if (isa<NamespaceDecl>(D)) {
return LV;
// By extension, we assign external linkage to Objective-C
@@ -1127,6 +1173,8 @@ static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl,
if (const auto *ND = dyn_cast<NamedDecl>(DC))
return getLVForDecl(ND, computation);
+ // FIXME: We have a closure at TU scope with no context declaration. This
+ // should probably have no linkage.
return LinkageInfo::external();
}
@@ -1139,7 +1187,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
// This is a "void f();" which got merged with a file static.
if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
- return LinkageInfo::internal();
+ return getInternalLinkageFor(Function);
LinkageInfo LV;
if (!hasExplicitVisibilityAlready(computation)) {
@@ -1228,7 +1276,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
LVComputationKind computation) {
// Internal_linkage attribute overrides other considerations.
if (D->hasAttr<InternalLinkageAttr>())
- return LinkageInfo::internal();
+ return getInternalLinkageFor(D);
// Objective-C: treat all Objective-C declarations as having external
// linkage.
@@ -1253,14 +1301,15 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
case Decl::EnumConstant:
// C++ [basic.link]p4: an enumerator has the linkage of its enumeration.
- return getLVForDecl(cast<EnumDecl>(D->getDeclContext()), computation);
+ if (D->getASTContext().getLangOpts().CPlusPlus)
+ return getLVForDecl(cast<EnumDecl>(D->getDeclContext()), computation);
+ return LinkageInfo::visible_none();
case Decl::Typedef:
case Decl::TypeAlias:
// A typedef declaration has linkage if it gives a type a name for
// linkage purposes.
- if (!D->getASTContext().getLangOpts().CPlusPlus ||
- !cast<TypedefNameDecl>(D)
+ if (!cast<TypedefNameDecl>(D)
->getAnonDeclWithTypedefName(/*AnyRedecl*/true))
return LinkageInfo::none();
break;
@@ -1276,14 +1325,14 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
case Decl::ObjCProperty:
case Decl::ObjCPropertyImpl:
case Decl::ObjCProtocol:
- return LinkageInfo::external();
+ return getExternalLinkageFor(D);
case Decl::CXXRecord: {
const auto *Record = cast<CXXRecordDecl>(D);
if (Record->isLambda()) {
if (!Record->getLambdaManglingNumber()) {
// This lambda has no mangling number, so it's internal.
- return LinkageInfo::internal();
+ return getInternalLinkageFor(D);
}
// This lambda has its linkage/visibility determined:
@@ -1299,7 +1348,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D,
const CXXRecordDecl *OuterMostLambda =
getOutermostEnclosingLambda(Record);
if (!OuterMostLambda->getLambdaManglingNumber())
- return LinkageInfo::internal();
+ return getInternalLinkageFor(D);
return getLVForClosure(
OuterMostLambda->getDeclContext()->getRedeclContext(),
@@ -1350,7 +1399,7 @@ public:
LVComputationKind computation) {
// Internal_linkage attribute overrides other considerations.
if (D->hasAttr<InternalLinkageAttr>())
- return LinkageInfo::internal();
+ return getInternalLinkageFor(D);
if (computation == LVForLinkageOnly && D->hasCachedLinkage())
return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
@@ -1414,6 +1463,11 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
const PrintingPolicy &P) const {
const DeclContext *Ctx = getDeclContext();
+ // For ObjC methods, look through categories and use the interface as context.
+ if (auto *MD = dyn_cast<ObjCMethodDecl>(this))
+ if (auto *ID = MD->getClassInterface())
+ Ctx = ID;
+
if (Ctx->isFunctionOrMethod()) {
printName(OS);
return;
@@ -2143,13 +2197,6 @@ APValue *VarDecl::evaluateValue() const {
return evaluateValue(Notes);
}
-namespace {
-// Destroy an APValue that was allocated in an ASTContext.
-void DestroyAPValue(void* UntypedValue) {
- static_cast<APValue*>(UntypedValue)->~APValue();
-}
-} // namespace
-
APValue *VarDecl::evaluateValue(
SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
@@ -2181,7 +2228,7 @@ APValue *VarDecl::evaluateValue(
if (!Result)
Eval->Evaluated = APValue();
else if (Eval->Evaluated.needsCleanup())
- getASTContext().AddDeallocation(DestroyAPValue, &Eval->Evaluated);
+ getASTContext().addDestruction(&Eval->Evaluated);
Eval->IsEvaluating = false;
Eval->WasEvaluated = true;
@@ -2253,6 +2300,14 @@ bool VarDecl::checkInitIsICE() const {
return Eval->IsICE;
}
+template<typename DeclT>
+static DeclT *getDefinitionOrSelf(DeclT *D) {
+ assert(D);
+ if (auto *Def = D->getDefinition())
+ return Def;
+ return D;
+}
+
VarDecl *VarDecl::getTemplateInstantiationPattern() const {
// If it's a variable template specialization, find the template or partial
// specialization from which it was instantiated.
@@ -2264,7 +2319,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
break;
VTD = NewVTD;
}
- return VTD->getTemplatedDecl()->getDefinition();
+ return getDefinitionOrSelf(VTD->getTemplatedDecl());
}
if (auto *VTPSD =
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
@@ -2273,7 +2328,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
break;
VTPSD = NewVTPSD;
}
- return VTPSD->getDefinition();
+ return getDefinitionOrSelf<VarDecl>(VTPSD);
}
}
@@ -2282,23 +2337,18 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
VarDecl *VD = getInstantiatedFromStaticDataMember();
while (auto *NewVD = VD->getInstantiatedFromStaticDataMember())
VD = NewVD;
- return VD->getDefinition();
+ return getDefinitionOrSelf(VD);
}
}
if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) {
-
while (VarTemplate->getInstantiatedFromMemberTemplate()) {
if (VarTemplate->isMemberSpecialization())
break;
VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate();
}
- assert((!VarTemplate->getTemplatedDecl() ||
- !isTemplateInstantiation(getTemplateSpecializationKind())) &&
- "couldn't find pattern for variable instantiation");
-
- return VarTemplate->getTemplatedDecl();
+ return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
}
return nullptr;
}
@@ -2510,7 +2560,7 @@ bool FunctionDecl::isVariadic() const {
bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
for (auto I : redecls()) {
- if (I->Body || I->IsLateTemplateParsed) {
+ if (I->doesThisDeclarationHaveABody()) {
Definition = I;
return true;
}
@@ -2535,9 +2585,8 @@ bool FunctionDecl::hasTrivialBody() const
bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
for (auto I : redecls()) {
- if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
- I->hasDefiningAttr()) {
- Definition = I->IsDeleted ? I->getCanonicalDecl() : I;
+ if (I->isThisDeclarationADefinition()) {
+ Definition = I;
return true;
}
}
@@ -2632,7 +2681,7 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
return (proto->getParamType(1).getCanonicalType() == Context.VoidPtrTy);
}
-bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
+bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const {
if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
return false;
if (getDeclName().getCXXOverloadedOperator() != OO_New &&
@@ -2678,8 +2727,11 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
// In C++17, the next parameter can be a 'std::align_val_t' for aligned
// new/delete.
- if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT())
+ if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT()) {
+ if (IsAligned)
+ *IsAligned = true;
Consume();
+ }
// Finally, if this is not a sized delete, the final parameter can
// be a 'const std::nothrow_t&'.
@@ -3005,9 +3057,7 @@ SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
const Attr *FunctionDecl::getUnusedResultAttr() const {
QualType RetType = getReturnType();
if (RetType->isRecordType()) {
- const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl();
- const auto *MD = dyn_cast<CXXMethodDecl>(this);
- if (Ret && !(MD && MD->getCorrespondingMethodInClass(Ret, true))) {
+ if (const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl()) {
if (const auto *R = Ret->getAttr<WarnUnusedResultAttr>())
return R;
}
@@ -3202,9 +3252,12 @@ bool FunctionDecl::isTemplateInstantiation() const {
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
// Handle class scope explicit specialization special case.
- if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- return getClassScopeSpecializationPattern();
-
+ if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+ if (auto *Spec = getClassScopeSpecializationPattern())
+ return getDefinitionOrSelf(Spec);
+ return nullptr;
+ }
+
// If this is a generic lambda call operator specialization, its
// instantiation pattern is always its primary template's pattern
// even if its primary template was instantiated from another
@@ -3216,16 +3269,10 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
if (isGenericLambdaCallOperatorSpecialization(
dyn_cast<CXXMethodDecl>(this))) {
- assert(getPrimaryTemplate() && "A generic lambda specialization must be "
- "generated from a primary call operator "
- "template");
- assert(getPrimaryTemplate()->getTemplatedDecl()->getBody() &&
- "A generic lambda call operator template must always have a body - "
- "even if instantiated from a prototype (i.e. as written) member "
- "template");
- return getPrimaryTemplate()->getTemplatedDecl();
+ assert(getPrimaryTemplate() && "not a generic lambda call operator?");
+ return getDefinitionOrSelf(getPrimaryTemplate()->getTemplatedDecl());
}
-
+
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
while (Primary->getInstantiatedFromMemberTemplate()) {
// If we have hit a point where the user provided a specialization of
@@ -3234,11 +3281,14 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
break;
Primary = Primary->getInstantiatedFromMemberTemplate();
}
-
- return Primary->getTemplatedDecl();
+
+ return getDefinitionOrSelf(Primary->getTemplatedDecl());
}
-
- return getInstantiatedFromMemberFunction();
+
+ if (auto *MFD = getInstantiatedFromMemberFunction())
+ return getDefinitionOrSelf(MFD);
+
+ return nullptr;
}
FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
@@ -3744,6 +3794,20 @@ void EnumDecl::completeDefinition(QualType NewType,
TagDecl::completeDefinition();
}
+bool EnumDecl::isClosed() const {
+ if (const auto *A = getAttr<EnumExtensibilityAttr>())
+ return A->getExtensibility() == EnumExtensibilityAttr::Closed;
+ return true;
+}
+
+bool EnumDecl::isClosedFlag() const {
+ return isClosed() && hasAttr<FlagEnumAttr>();
+}
+
+bool EnumDecl::isClosedNonFlag() const {
+ return isClosed() && !hasAttr<FlagEnumAttr>();
+}
+
TemplateSpecializationKind EnumDecl::getTemplateSpecializationKind() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return MSI->getTemplateSpecializationKind();
@@ -3768,7 +3832,7 @@ EnumDecl *EnumDecl::getTemplateInstantiationPattern() const {
EnumDecl *ED = getInstantiatedFromMemberEnum();
while (auto *NewED = ED->getInstantiatedFromMemberEnum())
ED = NewED;
- return ED;
+ return getDefinitionOrSelf(ED);
}
}
@@ -4096,15 +4160,19 @@ void ImplicitParamDecl::anchor() { }
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc,
- IdentifierInfo *Id,
- QualType Type) {
- return new (C, DC) ImplicitParamDecl(C, DC, IdLoc, Id, Type);
+ IdentifierInfo *Id, QualType Type,
+ ImplicitParamKind ParamKind) {
+ return new (C, DC) ImplicitParamDecl(C, DC, IdLoc, Id, Type, ParamKind);
+}
+
+ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, QualType Type,
+ ImplicitParamKind ParamKind) {
+ return new (C, nullptr) ImplicitParamDecl(C, Type, ParamKind);
}
ImplicitParamDecl *ImplicitParamDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- return new (C, ID) ImplicitParamDecl(C, nullptr, SourceLocation(), nullptr,
- QualType());
+ return new (C, ID) ImplicitParamDecl(C, QualType(), ImplicitParamKind::Other);
}
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
@@ -4230,6 +4298,30 @@ TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const {
return nullptr;
}
+bool TypedefNameDecl::isTransparentTagSlow() const {
+ auto determineIsTransparent = [&]() {
+ if (auto *TT = getUnderlyingType()->getAs<TagType>()) {
+ if (auto *TD = TT->getDecl()) {
+ if (TD->getName() != getName())
+ return false;
+ SourceLocation TTLoc = getLocation();
+ SourceLocation TDLoc = TD->getLocation();
+ if (!TTLoc.isMacroID() || !TDLoc.isMacroID())
+ return false;
+ SourceManager &SM = getASTContext().getSourceManager();
+ return SM.getSpellingLoc(TTLoc) == SM.getSpellingLoc(TDLoc);
+ }
+ }
+ return false;
+ };
+
+ bool isTransparent = determineIsTransparent();
+ CacheIsTransparentTag = 1;
+ if (isTransparent)
+ CacheIsTransparentTag |= 0x2;
+ return isTransparent;
+}
+
TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(),
nullptr, nullptr);
diff --git a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp
index 6111aba..cd2c83a 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp
@@ -75,7 +75,7 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
assert(!Parent || &Parent->getParentASTContext() == &Ctx);
// With local visibility enabled, we track the owning module even for local
// declarations.
- if (Ctx.getLangOpts().ModulesLocalVisibility) {
+ if (Ctx.getLangOpts().trackLocalOwningModule()) {
// Ensure required alignment of the resulting object by adding extra
// padding at the start if required.
size_t ExtraAlign =
@@ -83,7 +83,9 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
char *Buffer = reinterpret_cast<char *>(
::operator new(ExtraAlign + sizeof(Module *) + Size + Extra, Ctx));
Buffer += ExtraAlign;
- return new (Buffer) Module*(nullptr) + 1;
+ auto *ParentModule =
+ Parent ? cast<Decl>(Parent)->getOwningModule() : nullptr;
+ return new (Buffer) Module*(ParentModule) + 1;
}
return ::operator new(Size + Extra, Ctx);
}
@@ -94,7 +96,7 @@ Module *Decl::getOwningModuleSlow() const {
}
bool Decl::hasLocalOwningModuleStorage() const {
- return getASTContext().getLangOpts().ModulesLocalVisibility;
+ return getASTContext().getLangOpts().trackLocalOwningModule();
}
const char *Decl::getDeclKindName() const {
@@ -272,7 +274,19 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
} else {
getMultipleDC()->LexicalDC = DC;
}
- Hidden = cast<Decl>(DC)->Hidden;
+
+ // FIXME: We shouldn't be changing the lexical context of declarations
+ // imported from AST files.
+ if (!isFromASTFile()) {
+ setModuleOwnershipKind(getModuleOwnershipKindForChildOf(DC));
+ if (hasOwningModule())
+ setLocalOwningModule(cast<Decl>(DC)->getOwningModule());
+ }
+
+ assert(
+ (getModuleOwnershipKind() != ModuleOwnershipKind::VisibleWhenImported ||
+ getOwningModule()) &&
+ "hidden declaration has no owning module");
}
void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
@@ -403,6 +417,27 @@ bool Decl::isExported() const {
return false;
}
+ExternalSourceSymbolAttr *Decl::getExternalSourceSymbolAttr() const {
+ const Decl *Definition = nullptr;
+ if (auto ID = dyn_cast<ObjCInterfaceDecl>(this)) {
+ Definition = ID->getDefinition();
+ } else if (auto PD = dyn_cast<ObjCProtocolDecl>(this)) {
+ Definition = PD->getDefinition();
+ } else if (auto TD = dyn_cast<TagDecl>(this)) {
+ Definition = TD->getDefinition();
+ }
+ if (!Definition)
+ Definition = this;
+
+ if (auto *attr = Definition->getAttr<ExternalSourceSymbolAttr>())
+ return attr;
+ if (auto *dcd = dyn_cast<Decl>(getDeclContext())) {
+ return dcd->getAttr<ExternalSourceSymbolAttr>();
+ }
+
+ return nullptr;
+}
+
bool Decl::hasDefiningAttr() const {
return hasAttr<AliasAttr>() || hasAttr<IFuncAttr>();
}
@@ -415,6 +450,19 @@ const Attr *Decl::getDefiningAttr() const {
return nullptr;
}
+static StringRef getRealizedPlatform(const AvailabilityAttr *A,
+ const ASTContext &Context) {
+ // Check if this is an App Extension "platform", and if so chop off
+ // the suffix for matching with the actual platform.
+ StringRef RealizedPlatform = A->getPlatform()->getName();
+ if (!Context.getLangOpts().AppExt)
+ return RealizedPlatform;
+ size_t suffix = RealizedPlatform.rfind("_app_extension");
+ if (suffix != StringRef::npos)
+ return RealizedPlatform.slice(0, suffix);
+ return RealizedPlatform;
+}
+
/// \brief Determine the availability of the given declaration based on
/// the target platform.
///
@@ -434,20 +482,11 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
if (EnclosingVersion.empty())
return AR_Available;
- // Check if this is an App Extension "platform", and if so chop off
- // the suffix for matching with the actual platform.
StringRef ActualPlatform = A->getPlatform()->getName();
- StringRef RealizedPlatform = ActualPlatform;
- if (Context.getLangOpts().AppExt) {
- size_t suffix = RealizedPlatform.rfind("_app_extension");
- if (suffix != StringRef::npos)
- RealizedPlatform = RealizedPlatform.slice(0, suffix);
- }
-
StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
// Match the platform name.
- if (RealizedPlatform != TargetPlatform)
+ if (getRealizedPlatform(A, Context) != TargetPlatform)
return AR_Available;
StringRef PrettyPlatformName
@@ -567,6 +606,20 @@ AvailabilityResult Decl::getAvailability(std::string *Message,
return Result;
}
+VersionTuple Decl::getVersionIntroduced() const {
+ const ASTContext &Context = getASTContext();
+ StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
+ for (const auto *A : attrs()) {
+ if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
+ if (getRealizedPlatform(Availability, Context) != TargetPlatform)
+ continue;
+ if (!Availability->getIntroduced().empty())
+ return Availability->getIntroduced();
+ }
+ }
+ return VersionTuple();
+}
+
bool Decl::canBeWeakImported(bool &IsDefinition) const {
IsDefinition = false;
@@ -619,6 +672,7 @@ bool Decl::isWeakImported() const {
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
case Function:
+ case CXXDeductionGuide:
case CXXMethod:
case CXXConstructor:
case ConstructorUsingShadow:
@@ -1300,7 +1354,7 @@ void DeclContext::removeDecl(Decl *D) {
// Remove only decls that have a name
if (!ND->getDeclName()) return;
- auto *DC = this;
+ auto *DC = D->getDeclContext();
do {
StoredDeclsMap *Map = DC->getPrimaryContext()->LookupPtr;
if (Map) {
diff --git a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp
index a9db65a..5782b7b 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ODRHash.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
@@ -54,25 +55,30 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
HasOnlyCMembers(true), HasInClassInitializer(false),
HasUninitializedReferenceMember(false), HasUninitializedFields(false),
HasInheritedConstructor(false), HasInheritedAssignment(false),
+ NeedOverloadResolutionForCopyConstructor(false),
NeedOverloadResolutionForMoveConstructor(false),
NeedOverloadResolutionForMoveAssignment(false),
NeedOverloadResolutionForDestructor(false),
+ DefaultedCopyConstructorIsDeleted(false),
DefaultedMoveConstructorIsDeleted(false),
DefaultedMoveAssignmentIsDeleted(false),
DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All),
DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true),
HasConstexprNonCopyMoveConstructor(false),
HasDefaultedDefaultConstructor(false),
+ CanPassInRegisters(true),
DefaultedDefaultConstructorIsConstexpr(true),
HasConstexprDefaultConstructor(false),
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
- ImplicitCopyConstructorHasConstParam(true),
+ ImplicitCopyConstructorCanHaveConstParamForVBase(true),
+ ImplicitCopyConstructorCanHaveConstParamForNonVBase(true),
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
- IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0), Bases(),
- VBases(), Definition(D), FirstFriend() {}
+ IsParsingBaseSpecifiers(false), HasODRHash(false), ODRHash(0),
+ NumBases(0), NumVBases(0), Bases(), VBases(), Definition(D),
+ FirstFriend() {}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
return Bases.get(Definition->getASTContext().getExternalSource());
@@ -226,7 +232,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// 'const B&' or 'const volatile B&' [...]
if (CXXRecordDecl *VBaseDecl = VBase.getType()->getAsCXXRecordDecl())
if (!VBaseDecl->hasCopyConstructorWithConstParam())
- data().ImplicitCopyConstructorHasConstParam = false;
+ data().ImplicitCopyConstructorCanHaveConstParamForVBase = false;
// C++1z [dcl.init.agg]p1:
// An aggregate is a class with [...] no virtual base classes
@@ -263,6 +269,14 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// In the definition of a constexpr constructor [...]
// -- the class shall not have any virtual base classes
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++1z [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if each potentially constructed subobject
+ // has a copy constructor whose first parameter is of type
+ // 'const B&' or 'const volatile B&' [...]
+ if (!BaseClassDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorCanHaveConstParamForVBase = false;
} else {
// C++ [class.ctor]p5:
// A default constructor is trivial [...] if:
@@ -305,6 +319,14 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// default constructor is constexpr.
if (!BaseClassDecl->hasConstexprDefaultConstructor())
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++1z [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if each potentially constructed subobject
+ // has a copy constructor whose first parameter is of type
+ // 'const B&' or 'const volatile B&' [...]
+ if (!BaseClassDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorCanHaveConstParamForNonVBase = false;
}
// C++ [class.ctor]p3:
@@ -324,14 +346,6 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (!BaseClassDecl->hasCopyAssignmentWithConstParam())
data().ImplicitCopyAssignmentHasConstParam = false;
- // C++11 [class.copy]p8:
- // The implicitly-declared copy constructor for a class X will have
- // the form 'X::X(const X&)' if each direct [...] base class B of X
- // has a copy constructor whose first parameter is of type
- // 'const B&' or 'const volatile B&' [...]
- if (!BaseClassDecl->hasCopyConstructorWithConstParam())
- data().ImplicitCopyConstructorHasConstParam = false;
-
// A class has an Objective-C object member if... or any of its bases
// has an Objective-C object member.
if (BaseClassDecl->hasObjectMember())
@@ -341,8 +355,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
setHasVolatileMember(true);
// Keep track of the presence of mutable fields.
- if (BaseClassDecl->hasMutableFields())
+ if (BaseClassDecl->hasMutableFields()) {
data().HasMutableFields = true;
+ data().NeedOverloadResolutionForCopyConstructor = true;
+ }
if (BaseClassDecl->hasUninitializedReferenceMember())
data().HasUninitializedReferenceMember = true;
@@ -371,6 +387,23 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().IsParsingBaseSpecifiers = false;
}
+unsigned CXXRecordDecl::getODRHash() const {
+ assert(hasDefinition() && "ODRHash only for records with definitions");
+
+ // Previously calculated hash is stored in DefinitionData.
+ if (DefinitionData->HasODRHash)
+ return DefinitionData->ODRHash;
+
+ // Only calculate hash on first call of getODRHash per record.
+ ODRHash Hash;
+ Hash.AddCXXRecordDecl(getDefinition());
+ DefinitionData->HasODRHash = true;
+ DefinitionData->ODRHash = Hash.CalculateHash();
+
+ return DefinitionData->ODRHash;
+}
+
+
void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
// C++11 [class.copy]p11:
// A defaulted copy/move constructor for a class X is defined as
@@ -378,6 +411,8 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
// -- a direct or virtual base class B that cannot be copied/moved [...]
// -- a non-static data member of class type M (or array thereof)
// that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleCopyConstructor())
+ data().NeedOverloadResolutionForCopyConstructor = true;
if (!Subobj->hasSimpleMoveConstructor())
data().NeedOverloadResolutionForMoveConstructor = true;
@@ -398,6 +433,7 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
// -- any non-static data member has a type with a destructor
// that is deleted or inaccessible from the defaulted [ctor or dtor].
if (!Subobj->hasSimpleDestructor()) {
+ data().NeedOverloadResolutionForCopyConstructor = true;
data().NeedOverloadResolutionForMoveConstructor = true;
data().NeedOverloadResolutionForDestructor = true;
}
@@ -683,8 +719,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().IsStandardLayout = false;
// Keep track of the presence of mutable fields.
- if (Field->isMutable())
+ if (Field->isMutable()) {
data().HasMutableFields = true;
+ data().NeedOverloadResolutionForCopyConstructor = true;
+ }
// C++11 [class.union]p8, DR1460:
// If X is a union, a non-static data member of X that is not an anonymous
@@ -702,9 +740,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
ASTContext &Context = getASTContext();
QualType T = Context.getBaseElementType(Field->getType());
if (T->isObjCRetainableType() || T.isObjCGCStrong()) {
- if (!Context.getLangOpts().ObjCAutoRefCount) {
- setHasObjectMember(true);
- } else if (T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
+ if (T.hasNonTrivialObjCLifetime()) {
// Objective-C Automatic Reference Counting:
// If a class has a non-static data member of Objective-C pointer
// type (or array thereof), it is a non-POD type and its
@@ -716,6 +752,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
Data.PlainOldData = false;
Data.HasTrivialSpecialMembers = 0;
Data.HasIrrelevantDestructor = false;
+ } else if (!Context.getLangOpts().ObjCAutoRefCount) {
+ setHasObjectMember(true);
}
} else if (!T.isCXX98PODType(Context))
data().PlainOldData = false;
@@ -728,6 +766,12 @@ void CXXRecordDecl::addedMember(Decl *D) {
// A standard-layout class is a class that:
// -- has no non-static data members of type [...] reference,
data().IsStandardLayout = false;
+
+ // C++1z [class.copy.ctor]p10:
+ // A defaulted copy constructor for a class X is defined as deleted if X has:
+ // -- a non-static data member of rvalue reference type
+ if (T->isRValueReferenceType())
+ data().DefaultedCopyConstructorIsDeleted = true;
}
if (!Field->hasInClassInitializer() && !Field->isMutable()) {
@@ -781,6 +825,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
// We may need to perform overload resolution to determine whether a
// field can be moved if it's const or volatile qualified.
if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) {
+ // We need to care about 'const' for the copy constructor because an
+ // implicit copy constructor might be declared with a non-const
+ // parameter.
+ data().NeedOverloadResolutionForCopyConstructor = true;
data().NeedOverloadResolutionForMoveConstructor = true;
data().NeedOverloadResolutionForMoveAssignment = true;
}
@@ -791,6 +839,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
// -- X is a union-like class that has a variant member with a
// non-trivial [corresponding special member]
if (isUnion()) {
+ if (FieldRec->hasNonTrivialCopyConstructor())
+ data().DefaultedCopyConstructorIsDeleted = true;
if (FieldRec->hasNonTrivialMoveConstructor())
data().DefaultedMoveConstructorIsDeleted = true;
if (FieldRec->hasNonTrivialMoveAssignment())
@@ -802,6 +852,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
// For an anonymous union member, our overload resolution will perform
// overload resolution for its members.
if (Field->isAnonymousStructOrUnion()) {
+ data().NeedOverloadResolutionForCopyConstructor |=
+ FieldRec->data().NeedOverloadResolutionForCopyConstructor;
data().NeedOverloadResolutionForMoveConstructor |=
FieldRec->data().NeedOverloadResolutionForMoveConstructor;
data().NeedOverloadResolutionForMoveAssignment |=
@@ -887,8 +939,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
}
// Keep track of the presence of mutable fields.
- if (FieldRec->hasMutableFields())
+ if (FieldRec->hasMutableFields()) {
data().HasMutableFields = true;
+ data().NeedOverloadResolutionForCopyConstructor = true;
+ }
// C++11 [class.copy]p13:
// If the implicitly-defined constructor would satisfy the
@@ -905,12 +959,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
// C++11 [class.copy]p8:
// The implicitly-declared copy constructor for a class X will have
- // the form 'X::X(const X&)' if [...] for all the non-static data
- // members of X that are of a class type M (or array thereof), each
- // such class type has a copy constructor whose first parameter is
- // of type 'const M&' or 'const volatile M&'.
+ // the form 'X::X(const X&)' if each potentially constructed subobject
+ // of a class type M (or array thereof) has a copy constructor whose
+ // first parameter is of type 'const M&' or 'const volatile M&'.
if (!FieldRec->hasCopyConstructorWithConstParam())
- data().ImplicitCopyConstructorHasConstParam = false;
+ data().ImplicitCopyConstructorCanHaveConstParamForNonVBase = false;
// C++11 [class.copy]p18:
// The implicitly-declared copy assignment oeprator for a class X will
@@ -1337,6 +1390,13 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
}
const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
+ auto GetDefinitionOrSelf =
+ [](const CXXRecordDecl *D) -> const CXXRecordDecl * {
+ if (auto *Def = D->getDefinition())
+ return Def;
+ return D;
+ };
+
// If it's a class template specialization, find the template or partial
// specialization from which it was instantiated.
if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
@@ -1347,7 +1407,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
break;
CTD = NewCTD;
}
- return CTD->getTemplatedDecl()->getDefinition();
+ return GetDefinitionOrSelf(CTD->getTemplatedDecl());
}
if (auto *CTPSD =
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
@@ -1356,7 +1416,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
break;
CTPSD = NewCTPSD;
}
- return CTPSD->getDefinition();
+ return GetDefinitionOrSelf(CTPSD);
}
}
@@ -1365,7 +1425,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
const CXXRecordDecl *RD = this;
while (auto *NewRD = RD->getInstantiatedFromMemberClass())
RD = NewRD;
- return RD->getDefinition();
+ return GetDefinitionOrSelf(RD);
}
}
@@ -1383,11 +1443,8 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
Context.getCanonicalType(ClassType));
DeclContext::lookup_result R = lookup(Name);
- if (R.empty())
- return nullptr;
- CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(R.front());
- return Dtor;
+ return R.empty() ? nullptr : dyn_cast<CXXDestructorDecl>(R.front());
}
bool CXXRecordDecl::isAnyDestructorNoReturn() const {
@@ -1398,8 +1455,9 @@ bool CXXRecordDecl::isAnyDestructorNoReturn() const {
// Check base classes destructor for noreturn.
for (const auto &Base : bases())
- if (Base.getType()->getAsCXXRecordDecl()->isAnyDestructorNoReturn())
- return true;
+ if (const CXXRecordDecl *RD = Base.getType()->getAsCXXRecordDecl())
+ if (RD->isAnyDestructorNoReturn())
+ return true;
// Check fields for noreturn.
for (const auto *Field : fields())
@@ -1418,7 +1476,7 @@ void CXXRecordDecl::completeDefinition() {
void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
RecordDecl::completeDefinition();
-
+
// If the class may be abstract (but hasn't been marked as such), check for
// any pure final overriders.
if (mayBeAbstract()) {
@@ -1472,6 +1530,23 @@ bool CXXRecordDecl::mayBeAbstract() const {
return false;
}
+void CXXDeductionGuideDecl::anchor() { }
+
+CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
+ ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit,
+ const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
+ SourceLocation EndLocation) {
+ return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, IsExplicit,
+ NameInfo, T, TInfo, EndLocation);
+}
+
+CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ return new (C, ID) CXXDeductionGuideDecl(C, nullptr, SourceLocation(), false,
+ DeclarationNameInfo(), QualType(),
+ nullptr, SourceLocation());
+}
+
void CXXMethodDecl::anchor() { }
bool CXXMethodDecl::isStatic() const {
@@ -1556,6 +1631,84 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
SC_None, false, false, SourceLocation());
}
+CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
+ bool IsAppleKext) {
+ assert(isVirtual() && "this method is expected to be virtual");
+
+ // When building with -fapple-kext, all calls must go through the vtable since
+ // the kernel linker can do runtime patching of vtables.
+ if (IsAppleKext)
+ return nullptr;
+
+ // If the member function is marked 'final', we know that it can't be
+ // overridden and can therefore devirtualize it unless it's pure virtual.
+ if (hasAttr<FinalAttr>())
+ return isPure() ? nullptr : this;
+
+ // If Base is unknown, we cannot devirtualize.
+ if (!Base)
+ return nullptr;
+
+ // If the base expression (after skipping derived-to-base conversions) is a
+ // class prvalue, then we can devirtualize.
+ Base = Base->getBestDynamicClassTypeExpr();
+ if (Base->isRValue() && Base->getType()->isRecordType())
+ return this;
+
+ // If we don't even know what we would call, we can't devirtualize.
+ const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
+ if (!BestDynamicDecl)
+ return nullptr;
+
+ // There may be a method corresponding to MD in a derived class.
+ CXXMethodDecl *DevirtualizedMethod =
+ getCorrespondingMethodInClass(BestDynamicDecl);
+
+ // If that method is pure virtual, we can't devirtualize. If this code is
+ // reached, the result would be UB, not a direct call to the derived class
+ // function, and we can't assume the derived class function is defined.
+ if (DevirtualizedMethod->isPure())
+ return nullptr;
+
+ // If that method is marked final, we can devirtualize it.
+ if (DevirtualizedMethod->hasAttr<FinalAttr>())
+ return DevirtualizedMethod;
+
+ // Similarly, if the class itself is marked 'final' it can't be overridden
+ // and we can therefore devirtualize the member function call.
+ if (BestDynamicDecl->hasAttr<FinalAttr>())
+ return DevirtualizedMethod;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (VD->getType()->isRecordType())
+ // This is a record decl. We know the type and can devirtualize it.
+ return DevirtualizedMethod;
+
+ return nullptr;
+ }
+
+ // We can devirtualize calls on an object accessed by a class member access
+ // expression, since by C++11 [basic.life]p6 we know that it can't refer to
+ // a derived class object constructed in the same location.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base))
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl()))
+ return VD->getType()->isRecordType() ? DevirtualizedMethod : nullptr;
+
+ // Likewise for calls on an object accessed by a (non-reference) pointer to
+ // member access.
+ if (auto *BO = dyn_cast<BinaryOperator>(Base)) {
+ if (BO->isPtrMemOp()) {
+ auto *MPT = BO->getRHS()->getType()->castAs<MemberPointerType>();
+ if (MPT->getPointeeType()->isRecordType())
+ return DevirtualizedMethod;
+ }
+ }
+
+ // We can't devirtualize the call.
+ return nullptr;
+}
+
bool CXXMethodDecl::isUsualDeallocationFunction() const {
if (getOverloadedOperator() != OO_Delete &&
getOverloadedOperator() != OO_Array_Delete)
@@ -1710,9 +1863,10 @@ bool CXXMethodDecl::hasInlineBody() const {
const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
if (!CheckFn)
CheckFn = this;
-
+
const FunctionDecl *fn;
- return CheckFn->hasBody(fn) && !fn->isOutOfLine();
+ return CheckFn->isDefined(fn) && !fn->isOutOfLine() &&
+ (fn->doesThisDeclarationHaveABody() || fn->willHaveBody());
}
bool CXXMethodDecl::isLambdaStaticInvoker() const {
diff --git a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp
index 60d05f6..d8bdb63 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp
@@ -162,10 +162,10 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
return nullptr;
}
- // If context is class, then lookup property in its extensions.
+ // If context is class, then lookup property in its visible extensions.
// This comes before property is looked up in primary class.
if (auto *IDecl = dyn_cast<ObjCInterfaceDecl>(DC)) {
- for (const auto *Ext : IDecl->known_extensions())
+ for (const auto *Ext : IDecl->visible_extensions())
if (ObjCPropertyDecl *PD = ObjCPropertyDecl::findPropertyDecl(Ext,
propertyID,
queryKind))
@@ -539,9 +539,18 @@ void ObjCInterfaceDecl::getDesignatedInitializers(
bool ObjCInterfaceDecl::isDesignatedInitializer(Selector Sel,
const ObjCMethodDecl **InitMethod) const {
+ bool HasCompleteDef = isThisDeclarationADefinition();
+ // During deserialization the data record for the ObjCInterfaceDecl could
+ // be made invariant by reusing the canonical decl. Take this into account
+ // when checking for the complete definition.
+ if (!HasCompleteDef && getCanonicalDecl()->hasDefinition() &&
+ getCanonicalDecl()->getDefinition() == getDefinition())
+ HasCompleteDef = true;
+
// Check for a complete definition and recover if not so.
- if (!isThisDeclarationADefinition())
+ if (!HasCompleteDef)
return false;
+
if (data().ExternallyCompleted)
LoadExternalDefinition();
@@ -1061,20 +1070,20 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
bool selfIsPseudoStrong, selfIsConsumed;
QualType selfTy =
getSelfType(Context, OID, selfIsPseudoStrong, selfIsConsumed);
- ImplicitParamDecl *self
- = ImplicitParamDecl::Create(Context, this, SourceLocation(),
- &Context.Idents.get("self"), selfTy);
- setSelfDecl(self);
+ auto *Self = ImplicitParamDecl::Create(Context, this, SourceLocation(),
+ &Context.Idents.get("self"), selfTy,
+ ImplicitParamDecl::ObjCSelf);
+ setSelfDecl(Self);
if (selfIsConsumed)
- self->addAttr(NSConsumedAttr::CreateImplicit(Context));
+ Self->addAttr(NSConsumedAttr::CreateImplicit(Context));
if (selfIsPseudoStrong)
- self->setARCPseudoStrong(true);
+ Self->setARCPseudoStrong(true);
- setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
- &Context.Idents.get("_cmd"),
- Context.getObjCSelType()));
+ setCmdDecl(ImplicitParamDecl::Create(
+ Context, this, SourceLocation(), &Context.Idents.get("_cmd"),
+ Context.getObjCSelType(), ImplicitParamDecl::ObjCCmd));
}
ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
@@ -1880,25 +1889,23 @@ void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
}
}
-
void ObjCProtocolDecl::collectInheritedProtocolProperties(
- const ObjCPropertyDecl *Property,
- ProtocolPropertyMap &PM) const {
+ const ObjCPropertyDecl *Property, ProtocolPropertySet &PS,
+ PropertyDeclOrder &PO) const {
if (const ObjCProtocolDecl *PDecl = getDefinition()) {
- bool MatchFound = false;
+ if (!PS.insert(PDecl).second)
+ return;
for (auto *Prop : PDecl->properties()) {
if (Prop == Property)
continue;
if (Prop->getIdentifier() == Property->getIdentifier()) {
- PM[PDecl] = Prop;
- MatchFound = true;
- break;
+ PO.push_back(Prop);
+ return;
}
}
// Scan through protocol's protocols which did not have a matching property.
- if (!MatchFound)
- for (const auto *PI : PDecl->protocols())
- PI->collectInheritedProtocolProperties(Property, PM);
+ for (const auto *PI : PDecl->protocols())
+ PI->collectInheritedProtocolProperties(Property, PS, PO);
}
}
diff --git a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp
index b8ebe1c..6eeba88 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp
@@ -464,6 +464,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
Out << *D;
+ prettyPrintAttributes(D);
if (Expr *Init = D->getInitExpr()) {
Out << " = ";
Init->printPretty(Out, nullptr, Policy, Indentation);
@@ -477,9 +478,15 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isFunctionTemplateSpecialization())
Out << "template<> ";
+ else if (!D->getDescribedFunctionTemplate()) {
+ for (unsigned I = 0, NumTemplateParams = D->getNumTemplateParameterLists();
+ I < NumTemplateParams; ++I)
+ printTemplateParameters(D->getTemplateParameterList(I));
+ }
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
+ CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D);
if (!Policy.SuppressSpecifiers) {
switch (D->getStorageClass()) {
case SC_None: break;
@@ -495,13 +502,23 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isModulePrivate()) Out << "__module_private__ ";
if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
if ((CDecl && CDecl->isExplicitSpecified()) ||
- (ConversionDecl && ConversionDecl->isExplicit()))
+ (ConversionDecl && ConversionDecl->isExplicitSpecified()) ||
+ (GuideDecl && GuideDecl->isExplicitSpecified()))
Out << "explicit ";
}
PrintingPolicy SubPolicy(Policy);
SubPolicy.SuppressSpecifiers = false;
- std::string Proto = D->getNameInfo().getAsString();
+ std::string Proto;
+ if (!Policy.SuppressScope) {
+ if (const NestedNameSpecifier *NS = D->getQualifier()) {
+ llvm::raw_string_ostream OS(Proto);
+ NS->print(OS, Policy);
+ }
+ }
+ Proto += D->getNameInfo().getAsString();
+ if (GuideDecl)
+ Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString();
if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) {
llvm::raw_string_ostream POut(Proto);
DeclPrinter TArgPrinter(POut, SubPolicy, Indentation);
@@ -651,7 +668,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
} else if (!ConversionDecl && !isa<CXXDestructorDecl>(D)) {
if (FT && FT->hasTrailingReturn()) {
- Out << "auto " << Proto << " -> ";
+ if (!GuideDecl)
+ Out << "auto ";
+ Out << Proto << " -> ";
Proto.clear();
}
AFT->getReturnType().print(Out, Policy, Proto);
@@ -1041,9 +1060,18 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
prettyPrintPragmas(D->getTemplatedDecl());
+ // Print any leading template parameter lists.
+ if (const FunctionDecl *FD = D->getTemplatedDecl()) {
+ for (unsigned I = 0, NumTemplateParams = FD->getNumTemplateParameterLists();
+ I < NumTemplateParams; ++I)
+ printTemplateParameters(FD->getTemplateParameterList(I));
+ }
VisitRedeclarableTemplateDecl(D);
- if (PrintInstantiation) {
+ // Never print "instantiations" for deduction guides (they don't really
+ // have them).
+ if (PrintInstantiation &&
+ !isa<CXXDeductionGuideDecl>(D->getTemplatedDecl())) {
FunctionDecl *PrevDecl = D->getTemplatedDecl();
const FunctionDecl *Def;
if (PrevDecl->isDefined(Def) && Def != PrevDecl)
@@ -1161,7 +1189,9 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
for (const auto *PI : OMD->parameters()) {
// FIXME: selector is missing here!
pos = name.find_first_of(':', lastPos);
- Out << " " << name.substr(lastPos, pos - lastPos) << ':';
+ if (lastPos != 0)
+ Out << " ";
+ Out << name.substr(lastPos, pos - lastPos) << ':';
PrintObjCMethodType(OMD->getASTContext(),
PI->getObjCDeclQualifier(),
PI->getType());
@@ -1170,7 +1200,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
}
if (OMD->param_begin() == OMD->param_end())
- Out << " " << name;
+ Out << name;
if (OMD->isVariadic())
Out << ", ...";
diff --git a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp
index a5fbb0a..00a6739 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp
@@ -208,10 +208,6 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
// FunctionTemplateDecl Implementation
//===----------------------------------------------------------------------===//
-void FunctionTemplateDecl::DeallocateCommon(void *Ptr) {
- static_cast<Common *>(Ptr)->~Common();
-}
-
FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
@@ -231,7 +227,7 @@ FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C,
RedeclarableTemplateDecl::CommonBase *
FunctionTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
- C.AddDeallocation(DeallocateCommon, CommonPtr);
+ C.addDestruction(CommonPtr);
return CommonPtr;
}
@@ -288,19 +284,23 @@ ArrayRef<TemplateArgument> FunctionTemplateDecl::getInjectedTemplateArgs() {
// ClassTemplateDecl Implementation
//===----------------------------------------------------------------------===//
-void ClassTemplateDecl::DeallocateCommon(void *Ptr) {
- static_cast<Common *>(Ptr)->~Common();
-}
-
ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl) {
+ NamedDecl *Decl,
+ Expr *AssociatedConstraints) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
- ClassTemplateDecl *New = new (C, DC) ClassTemplateDecl(C, DC, L, Name,
- Params, Decl);
+
+ if (!AssociatedConstraints) {
+ return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl);
+ }
+
+ ConstrainedTemplateDeclInfo *const CTDI = new (C) ConstrainedTemplateDeclInfo;
+ ClassTemplateDecl *const New =
+ new (C, DC) ClassTemplateDecl(CTDI, C, DC, L, Name, Params, Decl);
+ New->setAssociatedConstraints(AssociatedConstraints);
return New;
}
@@ -340,7 +340,7 @@ ClassTemplateDecl::getPartialSpecializations() {
RedeclarableTemplateDecl::CommonBase *
ClassTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
- C.AddDeallocation(DeallocateCommon, CommonPtr);
+ C.addDestruction(CommonPtr);
return CommonPtr;
}
@@ -880,13 +880,10 @@ TypeAliasTemplateDecl *TypeAliasTemplateDecl::CreateDeserialized(ASTContext &C,
DeclarationName(), nullptr, nullptr);
}
-void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
- static_cast<Common *>(Ptr)->~Common();
-}
RedeclarableTemplateDecl::CommonBase *
TypeAliasTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
- C.AddDeallocation(DeallocateCommon, CommonPtr);
+ C.addDestruction(CommonPtr);
return CommonPtr;
}
@@ -907,10 +904,6 @@ ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
// VarTemplateDecl Implementation
//===----------------------------------------------------------------------===//
-void VarTemplateDecl::DeallocateCommon(void *Ptr) {
- static_cast<Common *>(Ptr)->~Common();
-}
-
VarTemplateDecl *VarTemplateDecl::getDefinition() {
VarTemplateDecl *CurD = this;
while (CurD) {
@@ -966,7 +959,7 @@ VarTemplateDecl::getPartialSpecializations() {
RedeclarableTemplateDecl::CommonBase *
VarTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
- C.AddDeallocation(DeallocateCommon, CommonPtr);
+ C.addDestruction(CommonPtr);
return CommonPtr;
}
diff --git a/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp b/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp
index 52791e5..1f8e26d 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
@@ -43,6 +44,22 @@ public:
}
};
+/// Contains extra information for the name of a C++ deduction guide.
+class CXXDeductionGuideNameExtra : public DeclarationNameExtra,
+ public llvm::FoldingSetNode {
+public:
+ /// The template named by the deduction guide.
+ TemplateDecl *Template;
+
+ /// FETokenInfo - Extra information associated with this operator
+ /// name that can be used by the front end.
+ void *FETokenInfo;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ ID.AddPointer(Template);
+ }
+};
+
/// CXXOperatorIdName - Contains extra information for the name of an
/// overloaded operator in C++, such as "operator+.
class CXXOperatorIdName : public DeclarationNameExtra {
@@ -122,7 +139,13 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType()))
return 1;
return 0;
-
+
+ case DeclarationName::CXXDeductionGuideName:
+ // We never want to compare deduction guide names for templates from
+ // different scopes, so just compare the template-name.
+ return compare(LHS.getCXXDeductionGuideTemplate()->getDeclName(),
+ RHS.getCXXDeductionGuideTemplate()->getDeclName());
+
case DeclarationName::CXXOperatorName:
return compareInt(LHS.getCXXOverloadedOperator(),
RHS.getCXXOverloadedOperator());
@@ -179,6 +202,12 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) {
return printCXXConstructorDestructorName(N.getCXXNameType(), OS, Policy);
}
+ case DeclarationName::CXXDeductionGuideName:
+ OS << "<deduction guide for ";
+ getCXXDeductionGuideTemplate()->getDeclName().print(OS, Policy);
+ OS << '>';
+ return;
+
case DeclarationName::CXXOperatorName: {
static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
nullptr,
@@ -243,6 +272,9 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
case DeclarationNameExtra::CXXDestructor:
return CXXDestructorName;
+ case DeclarationNameExtra::CXXDeductionGuide:
+ return CXXDeductionGuideName;
+
case DeclarationNameExtra::CXXConversionFunction:
return CXXConversionFunctionName;
@@ -268,7 +300,15 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
bool DeclarationName::isDependentName() const {
QualType T = getCXXNameType();
- return !T.isNull() && T->isDependentType();
+ if (!T.isNull() && T->isDependentType())
+ return true;
+
+ // A class-scope deduction guide in a dependent context has a dependent name.
+ auto *TD = getCXXDeductionGuideTemplate();
+ if (TD && TD->getDeclContext()->isDependentContext())
+ return true;
+
+ return false;
}
std::string DeclarationName::getAsString() const {
@@ -285,6 +325,12 @@ QualType DeclarationName::getCXXNameType() const {
return QualType();
}
+TemplateDecl *DeclarationName::getCXXDeductionGuideTemplate() const {
+ if (auto *Guide = getAsCXXDeductionGuideNameExtra())
+ return Guide->Template;
+ return nullptr;
+}
+
OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const {
if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) {
unsigned value
@@ -312,6 +358,9 @@ void *DeclarationName::getFETokenInfoAsVoidSlow() const {
case CXXConversionFunctionName:
return getAsCXXSpecialName()->FETokenInfo;
+ case CXXDeductionGuideName:
+ return getAsCXXDeductionGuideNameExtra()->FETokenInfo;
+
case CXXOperatorName:
return getAsCXXOperatorIdName()->FETokenInfo;
@@ -335,6 +384,10 @@ void DeclarationName::setFETokenInfo(void *T) {
getAsCXXSpecialName()->FETokenInfo = T;
break;
+ case CXXDeductionGuideName:
+ getAsCXXDeductionGuideNameExtra()->FETokenInfo = T;
+ break;
+
case CXXOperatorName:
getAsCXXOperatorIdName()->FETokenInfo = T;
break;
@@ -366,6 +419,7 @@ LLVM_DUMP_METHOD void DeclarationName::dump() const {
DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>;
+ CXXDeductionGuideNames = new llvm::FoldingSet<CXXDeductionGuideNameExtra>;
// Initialize the overloaded operator names.
CXXOperatorNames = new (Ctx) CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
@@ -377,14 +431,18 @@ DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
}
DeclarationNameTable::~DeclarationNameTable() {
- llvm::FoldingSet<CXXSpecialName> *SpecialNames =
- static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
- llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
- = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
- (CXXLiteralOperatorNames);
+ auto *SpecialNames =
+ static_cast<llvm::FoldingSet<CXXSpecialName> *>(CXXSpecialNamesImpl);
+ auto *LiteralNames =
+ static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName> *>(
+ CXXLiteralOperatorNames);
+ auto *DeductionGuideNames =
+ static_cast<llvm::FoldingSet<CXXDeductionGuideNameExtra> *>(
+ CXXDeductionGuideNames);
delete SpecialNames;
delete LiteralNames;
+ delete DeductionGuideNames;
}
DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) {
@@ -398,6 +456,30 @@ DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) {
}
DeclarationName
+DeclarationNameTable::getCXXDeductionGuideName(TemplateDecl *Template) {
+ Template = cast<TemplateDecl>(Template->getCanonicalDecl());
+
+ auto *DeductionGuideNames =
+ static_cast<llvm::FoldingSet<CXXDeductionGuideNameExtra> *>(
+ CXXDeductionGuideNames);
+
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(Template);
+
+ void *InsertPos = nullptr;
+ if (auto *Name = DeductionGuideNames->FindNodeOrInsertPos(ID, InsertPos))
+ return DeclarationName(Name);
+
+ auto *Name = new (Ctx) CXXDeductionGuideNameExtra;
+ Name->ExtraKindOrNumArgs = DeclarationNameExtra::CXXDeductionGuide;
+ Name->Template = Template;
+ Name->FETokenInfo = nullptr;
+
+ DeductionGuideNames->InsertNode(Name, InsertPos);
+ return DeclarationName(Name);
+}
+
+DeclarationName
DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) {
return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
}
@@ -477,6 +559,7 @@ DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
+ case DeclarationName::CXXDeductionGuideName:
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
@@ -509,6 +592,7 @@ bool DeclarationNameInfo::containsUnexpandedParameterPack() const {
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
return false;
case DeclarationName::CXXConstructorName:
@@ -531,6 +615,7 @@ bool DeclarationNameInfo::isInstantiationDependent() const {
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
return false;
case DeclarationName::CXXConstructorName:
@@ -560,6 +645,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
OS << Name;
return;
@@ -574,7 +660,9 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
LangOptions LO;
LO.CPlusPlus = true;
LO.Bool = true;
- OS << TInfo->getType().getAsString(PrintingPolicy(LO));
+ PrintingPolicy PP(LO);
+ PP.SuppressScope = true;
+ OS << TInfo->getType().getAsString(PP);
} else
OS << Name;
return;
@@ -585,6 +673,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
SourceLocation DeclarationNameInfo::getEndLoc() const {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
+ case DeclarationName::CXXDeductionGuideName:
return NameLoc;
case DeclarationName::CXXOperatorName: {
diff --git a/contrib/llvm/tools/clang/lib/AST/Expr.cpp b/contrib/llvm/tools/clang/lib/AST/Expr.cpp
index 14f31d0..afc7fa8 100644
--- a/contrib/llvm/tools/clang/lib/AST/Expr.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/Expr.cpp
@@ -987,7 +987,7 @@ void StringLiteral::outputString(raw_ostream &OS) const {
void StringLiteral::setString(const ASTContext &C, StringRef Str,
StringKind Kind, bool IsPascal) {
//FIXME: we assume that the string data comes from a target that uses the same
- // code unit size and endianess for the type of string.
+ // code unit size and endianness for the type of string.
this->Kind = Kind;
this->IsPascal = IsPascal;
@@ -1571,10 +1571,12 @@ bool CastExpr::CastConsistency() const {
goto CheckNoBasePath;
case CK_AddressSpaceConversion:
- assert(getType()->isPointerType());
- assert(getSubExpr()->getType()->isPointerType());
+ assert(getType()->isPointerType() || getType()->isBlockPointerType());
+ assert(getSubExpr()->getType()->isPointerType() ||
+ getSubExpr()->getType()->isBlockPointerType());
assert(getType()->getPointeeType().getAddressSpace() !=
getSubExpr()->getType()->getPointeeType().getAddressSpace());
+ LLVM_FALLTHROUGH;
// These should not have an inheritance path.
case CK_Dynamic:
case CK_ToUnion:
@@ -1639,25 +1641,32 @@ const char *CastExpr::getCastKindName() const {
llvm_unreachable("Unhandled cast kind!");
}
+namespace {
+ Expr *skipImplicitTemporary(Expr *expr) {
+ // Skip through reference binding to temporary.
+ if (MaterializeTemporaryExpr *Materialize
+ = dyn_cast<MaterializeTemporaryExpr>(expr))
+ expr = Materialize->GetTemporaryExpr();
+
+ // Skip any temporary bindings; they're implicit.
+ if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(expr))
+ expr = Binder->getSubExpr();
+
+ return expr;
+ }
+}
+
Expr *CastExpr::getSubExprAsWritten() {
Expr *SubExpr = nullptr;
CastExpr *E = this;
do {
- SubExpr = E->getSubExpr();
+ SubExpr = skipImplicitTemporary(E->getSubExpr());
- // Skip through reference binding to temporary.
- if (MaterializeTemporaryExpr *Materialize
- = dyn_cast<MaterializeTemporaryExpr>(SubExpr))
- SubExpr = Materialize->GetTemporaryExpr();
-
- // Skip any temporary bindings; they're implicit.
- if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr))
- SubExpr = Binder->getSubExpr();
-
// Conversions by constructor and conversion functions have a
// subexpression describing the call; strip it off.
if (E->getCastKind() == CK_ConstructorConversion)
- SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0);
+ SubExpr =
+ skipImplicitTemporary(cast<CXXConstructExpr>(SubExpr)->getArg(0));
else if (E->getCastKind() == CK_UserDefinedConversion) {
assert((isa<CXXMemberCallExpr>(SubExpr) ||
isa<BlockExpr>(SubExpr)) &&
@@ -1881,6 +1890,11 @@ bool InitListExpr::isTransparent() const {
if (getNumInits() != 1 || !getInit(0))
return false;
+ // Don't confuse aggregate initialization of a struct X { X &x; }; with a
+ // transparent struct copy.
+ if (!getInit(0)->isRValue() && getType()->isRecordType())
+ return false;
+
return getType().getCanonicalType() ==
getInit(0)->getType().getCanonicalType();
}
@@ -2096,6 +2110,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
}
// Fallthrough for generic call handling.
+ LLVM_FALLTHROUGH;
}
case CallExprClass:
case CXXMemberCallExprClass:
@@ -2952,6 +2967,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case CXXNewExprClass:
case CXXDeleteExprClass:
case CoawaitExprClass:
+ case DependentCoawaitExprClass:
case CoyieldExprClass:
// These always have a side-effect.
return true;
@@ -3880,16 +3896,22 @@ PseudoObjectExpr::PseudoObjectExpr(QualType type, ExprValueKind VK,
// UnaryExprOrTypeTraitExpr
Stmt::child_range UnaryExprOrTypeTraitExpr::children() {
+ const_child_range CCR =
+ const_cast<const UnaryExprOrTypeTraitExpr *>(this)->children();
+ return child_range(cast_away_const(CCR.begin()), cast_away_const(CCR.end()));
+}
+
+Stmt::const_child_range UnaryExprOrTypeTraitExpr::children() const {
// If this is of a type and the type is a VLA type (and not a typedef), the
// size expression of the VLA needs to be treated as an executable expression.
// Why isn't this weirdness documented better in StmtIterator?
if (isArgumentType()) {
- if (const VariableArrayType* T = dyn_cast<VariableArrayType>(
- getArgumentType().getTypePtr()))
- return child_range(child_iterator(T), child_iterator());
- return child_range(child_iterator(), child_iterator());
+ if (const VariableArrayType *T =
+ dyn_cast<VariableArrayType>(getArgumentType().getTypePtr()))
+ return const_child_range(const_child_iterator(T), const_child_iterator());
+ return const_child_range(const_child_iterator(), const_child_iterator());
}
- return child_range(&Argument.Ex, &Argument.Ex + 1);
+ return const_child_range(&Argument.Ex, &Argument.Ex + 1);
}
AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args,
diff --git a/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp
index ad510e0..fe45b5e 100644
--- a/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp
@@ -734,23 +734,23 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(const ASTContext &C,
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
CXXConstructorDecl *Cons,
- TypeSourceInfo *Type,
+ QualType Type,
+ TypeSourceInfo *TSI,
ArrayRef<Expr*> Args,
SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
bool ListInitialization,
bool StdInitListInitialization,
bool ZeroInitialization)
- : CXXConstructExpr(C, CXXTemporaryObjectExprClass,
- Type->getType().getNonReferenceType(),
- Type->getTypeLoc().getBeginLoc(),
+ : CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type,
+ TSI->getTypeLoc().getBeginLoc(),
Cons, false, Args,
HadMultipleCandidates,
ListInitialization,
StdInitListInitialization,
ZeroInitialization,
CXXConstructExpr::CK_Complete, ParenOrBraceRange),
- Type(Type) {
+ Type(TSI) {
}
SourceLocation CXXTemporaryObjectExpr::getLocStart() const {
@@ -1052,7 +1052,9 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
:Type->getType()->isRValueReferenceType()? VK_XValue
:VK_RValue),
OK_Ordinary,
- Type->getType()->isDependentType(), true, true,
+ Type->getType()->isDependentType() ||
+ Type->getType()->getContainedDeducedType(),
+ true, true,
Type->getType()->containsUnexpandedParameterPack()),
Type(Type),
LParenLoc(LParenLoc),
diff --git a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp
index adb74b8..d149bdd 100644
--- a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp
@@ -129,6 +129,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
case Expr::TypoExprClass:
+ case Expr::DependentCoawaitExprClass:
case Expr::CXXDependentScopeMemberExprClass:
case Expr::DependentScopeDeclRefExprClass:
// ObjC instance variables are lvalues
@@ -189,7 +190,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
- case Expr::CoyieldExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
@@ -413,7 +413,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0));
case Expr::CoawaitExprClass:
- return ClassifyInternal(Ctx, cast<CoawaitExpr>(E)->getResumeExpr());
+ case Expr::CoyieldExprClass:
+ return ClassifyInternal(Ctx, cast<CoroutineSuspendExpr>(E)->getResumeExpr());
}
llvm_unreachable("unhandled expression kind in classification");
@@ -626,7 +627,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// Const stuff is obviously not modifiable.
if (CT.isConstQualified())
return Cl::CM_ConstQualified;
- if (CT.getQualifiers().getAddressSpace() == LangAS::opencl_constant)
+ if (Ctx.getLangOpts().OpenCL &&
+ CT.getQualifiers().getAddressSpace() == LangAS::opencl_constant)
return Cl::CM_ConstAddrSpace;
// Arrays are not modifiable, only their elements are.
diff --git a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp
index 2c0fce9..df02e10 100644
--- a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp
@@ -350,36 +350,49 @@ namespace {
MostDerivedArraySize = 2;
MostDerivedPathLength = Entries.size();
}
- void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, uint64_t N);
+ void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &N);
/// Add N to the address of this subobject.
- void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
- if (Invalid) return;
+ void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) {
+ if (Invalid || !N) return;
+ uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue();
if (isMostDerivedAnUnsizedArray()) {
// Can't verify -- trust that the user is doing the right thing (or if
// not, trust that the caller will catch the bad behavior).
- Entries.back().ArrayIndex += N;
- return;
- }
- if (MostDerivedPathLength == Entries.size() &&
- MostDerivedIsArrayElement) {
- Entries.back().ArrayIndex += N;
- if (Entries.back().ArrayIndex > getMostDerivedArraySize()) {
- diagnosePointerArithmetic(Info, E, Entries.back().ArrayIndex);
- setInvalid();
- }
+ // FIXME: Should we reject if this overflows, at least?
+ Entries.back().ArrayIndex += TruncatedN;
return;
}
+
// [expr.add]p4: For the purposes of these operators, a pointer to a
// nonarray object behaves the same as a pointer to the first element of
// an array of length one with the type of the object as its element type.
- if (IsOnePastTheEnd && N == (uint64_t)-1)
- IsOnePastTheEnd = false;
- else if (!IsOnePastTheEnd && N == 1)
- IsOnePastTheEnd = true;
- else if (N != 0) {
- diagnosePointerArithmetic(Info, E, uint64_t(IsOnePastTheEnd) + N);
+ bool IsArray = MostDerivedPathLength == Entries.size() &&
+ MostDerivedIsArrayElement;
+ uint64_t ArrayIndex =
+ IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd;
+ uint64_t ArraySize =
+ IsArray ? getMostDerivedArraySize() : (uint64_t)1;
+
+ if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) {
+ // Calculate the actual index in a wide enough type, so we can include
+ // it in the note.
+ N = N.extend(std::max<unsigned>(N.getBitWidth() + 1, 65));
+ (llvm::APInt&)N += ArrayIndex;
+ assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index");
+ diagnosePointerArithmetic(Info, E, N);
setInvalid();
+ return;
}
+
+ ArrayIndex += TruncatedN;
+ assert(ArrayIndex <= ArraySize &&
+ "bounds check succeeded for out-of-bounds index");
+
+ if (IsArray)
+ Entries.back().ArrayIndex = ArrayIndex;
+ else
+ IsOnePastTheEnd = (ArrayIndex != 0);
}
};
@@ -413,6 +426,17 @@ namespace {
/// Index - The call index of this call.
unsigned Index;
+ // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
+ // on the overall stack usage of deeply-recursing constexpr evaluataions.
+ // (We should cache this map rather than recomputing it repeatedly.)
+ // But let's try this and see how it goes; we can look into caching the map
+ // as a later change.
+
+ /// LambdaCaptureFields - Mapping from captured variables/this to
+ /// corresponding data members in the closure class.
+ llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+ FieldDecl *LambdaThisCaptureField;
+
CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
const FunctionDecl *Callee, const LValue *This,
APValue *Arguments);
@@ -712,6 +736,7 @@ namespace {
if (!HasFoldFailureDiagnostic)
break;
// We've already failed to fold something. Keep that diagnostic.
+ LLVM_FALLTHROUGH;
case EM_ConstantExpression:
case EM_PotentialConstantExpression:
case EM_ConstantExpressionUnevaluated:
@@ -1048,16 +1073,17 @@ bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
}
void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
- const Expr *E, uint64_t N) {
+ const Expr *E,
+ const APSInt &N) {
// If we're complaining, we must be able to statically determine the size of
// the most derived array.
if (MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement)
Info.CCEDiag(E, diag::note_constexpr_array_index)
- << static_cast<int>(N) << /*array*/ 0
+ << N << /*array*/ 0
<< static_cast<unsigned>(getMostDerivedArraySize());
else
Info.CCEDiag(E, diag::note_constexpr_array_index)
- << static_cast<int>(N) << /*non-array*/ 1;
+ << N << /*non-array*/ 1;
setInvalid();
}
@@ -1205,8 +1231,7 @@ namespace {
IsNullPtr = V.isNullPointer();
}
- void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false,
- bool IsNullPtr_ = false, uint64_t Offset_ = 0) {
+ void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) {
#ifndef NDEBUG
// We only allow a few types of invalid bases. Enforce that here.
if (BInvalid) {
@@ -1217,11 +1242,20 @@ namespace {
#endif
Base = B;
- Offset = CharUnits::fromQuantity(Offset_);
+ Offset = CharUnits::fromQuantity(0);
InvalidBase = BInvalid;
CallIndex = I;
Designator = SubobjectDesignator(getType(B));
- IsNullPtr = IsNullPtr_;
+ IsNullPtr = false;
+ }
+
+ void setNull(QualType PointerTy, uint64_t TargetVal) {
+ Base = (Expr *)nullptr;
+ Offset = CharUnits::fromQuantity(TargetVal);
+ InvalidBase = false;
+ CallIndex = 0;
+ Designator = SubobjectDesignator(PointerTy->getPointeeType());
+ IsNullPtr = true;
}
void setInvalid(APValue::LValueBase B, unsigned I = 0) {
@@ -1273,14 +1307,24 @@ namespace {
void clearIsNullPointer() {
IsNullPtr = false;
}
- void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, uint64_t Index,
- CharUnits ElementSize) {
- // Compute the new offset in the appropriate width.
- Offset += Index * ElementSize;
- if (Index && checkNullPointer(Info, E, CSK_ArrayIndex))
+ void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E,
+ const APSInt &Index, CharUnits ElementSize) {
+ // An index of 0 has no effect. (In C, adding 0 to a null pointer is UB,
+ // but we're not required to diagnose it and it's valid in C++.)
+ if (!Index)
+ return;
+
+ // Compute the new offset in the appropriate width, wrapping at 64 bits.
+ // FIXME: When compiling for a 32-bit target, we should use 32-bit
+ // offsets.
+ uint64_t Offset64 = Offset.getQuantity();
+ uint64_t ElemSize64 = ElementSize.getQuantity();
+ uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
+ Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64);
+
+ if (checkNullPointer(Info, E, CSK_ArrayIndex))
Designator.adjustIndex(Info, E, Index);
- if (Index)
- clearIsNullPointer();
+ clearIsNullPointer();
}
void adjustOffset(CharUnits N) {
Offset += N;
@@ -1411,6 +1455,16 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result);
// Misc utilities
//===----------------------------------------------------------------------===//
+/// Negate an APSInt in place, converting it to a signed form if necessary, and
+/// preserving its value (by extending by up to one bit as needed).
+static void negateAsSigned(APSInt &Int) {
+ if (Int.isUnsigned() || Int.isMinSignedValue()) {
+ Int = Int.extend(Int.getBitWidth() + 1);
+ Int.setIsSigned(true);
+ }
+ Int = -Int;
+}
+
/// Produce a string describing the given constexpr call.
static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
unsigned ArgIndex = 0;
@@ -1458,13 +1512,6 @@ static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
return true;
}
-/// Sign- or zero-extend a value to 64 bits. If it's already 64 bits, just
-/// return its existing value.
-static int64_t getExtValue(const APSInt &Value) {
- return Value.isSigned() ? Value.getSExtValue()
- : static_cast<int64_t>(Value.getZExtValue());
-}
-
/// Should this call expression be treated as a string literal?
static bool IsStringLiteralCall(const CallExpr *E) {
unsigned Builtin = E->getBuiltinCallee();
@@ -1617,6 +1664,19 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
return true;
}
+/// Member pointers are constant expressions unless they point to a
+/// non-virtual dllimport member function.
+static bool CheckMemberPointerConstantExpression(EvalInfo &Info,
+ SourceLocation Loc,
+ QualType Type,
+ const APValue &Value) {
+ const ValueDecl *Member = Value.getMemberPointerDecl();
+ const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member);
+ if (!FD)
+ return true;
+ return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>();
+}
+
/// Check that this core constant expression is of literal type, and if not,
/// produce an appropriate diagnostic.
static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
@@ -1709,6 +1769,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal);
}
+ if (Value.isMemberPointer())
+ return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value);
+
// Everything else is fine.
return true;
}
@@ -2220,7 +2283,7 @@ static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc,
/// \param Adjustment - The adjustment, in objects of type EltTy, to add.
static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E,
LValue &LVal, QualType EltTy,
- int64_t Adjustment) {
+ APSInt Adjustment) {
CharUnits SizeOfPointee;
if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfPointee))
return false;
@@ -2229,6 +2292,13 @@ static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E,
return true;
}
+static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E,
+ LValue &LVal, QualType EltTy,
+ int64_t Adjustment) {
+ return HandleLValueArrayAdjustment(Info, E, LVal, EltTy,
+ APSInt::get(Adjustment));
+}
+
/// Update an lvalue to refer to a component of a complex number.
/// \param Info - Information about the ongoing evaluation.
/// \param LVal - The lvalue to be updated.
@@ -2247,6 +2317,10 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
return true;
}
+static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
+ QualType Type, const LValue &LVal,
+ APValue &RVal);
+
/// Try to evaluate the initializer for a variable declaration.
///
/// \param Info Information about the ongoing evaluation.
@@ -2258,6 +2332,7 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
const VarDecl *VD, CallStackFrame *Frame,
APValue *&Result) {
+
// If this is a parameter to an active constexpr function call, perform
// argument substitution.
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
@@ -3191,9 +3266,9 @@ struct CompoundAssignSubobjectHandler {
return false;
}
- int64_t Offset = getExtValue(RHS.getInt());
+ APSInt Offset = RHS.getInt();
if (Opcode == BO_Sub)
- Offset = -Offset;
+ negateAsSigned(Offset);
LValue LVal;
LVal.setFrom(Info.Ctx, Subobj);
@@ -4148,6 +4223,10 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
return false;
This->moveInto(Result);
return true;
+ } else if (MD && isLambdaCallOperator(MD)) {
+ // We're in a lambda; determine the lambda capture field maps.
+ MD->getParent()->getCaptureFields(Frame.LambdaCaptureFields,
+ Frame.LambdaThisCaptureField);
}
StmtResult Ret = {Result, ResultSlot};
@@ -4363,8 +4442,14 @@ private:
bool HandleConditionalOperator(const ConditionalOperator *E) {
bool BoolResult;
if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
- if (Info.checkingPotentialConstantExpression() && Info.noteFailure())
+ if (Info.checkingPotentialConstantExpression() && Info.noteFailure()) {
CheckPotentialConstantConditional(E);
+ return false;
+ }
+ if (Info.noteFailure()) {
+ StmtVisitorTy::Visit(E->getTrueExpr());
+ StmtVisitorTy::Visit(E->getFalseExpr());
+ }
return false;
}
@@ -5009,6 +5094,33 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
+
+ // If we are within a lambda's call operator, check whether the 'VD' referred
+ // to within 'E' actually represents a lambda-capture that maps to a
+ // data-member/field within the closure object, and if so, evaluate to the
+ // field or what the field refers to.
+ if (Info.CurrentCall && isLambdaCallOperator(Info.CurrentCall->Callee)) {
+ if (auto *FD = Info.CurrentCall->LambdaCaptureFields.lookup(VD)) {
+ if (Info.checkingPotentialConstantExpression())
+ return false;
+ // Start with 'Result' referring to the complete closure object...
+ Result = *Info.CurrentCall->This;
+ // ... then update it to refer to the field of the closure object
+ // that represents the capture.
+ if (!HandleLValueMember(Info, E, Result, FD))
+ return false;
+ // And if the field is of reference type, update 'Result' to refer to what
+ // the field refers to.
+ if (FD->getType()->isReferenceType()) {
+ APValue RVal;
+ if (!handleLValueToRValueConversion(Info, E, FD->getType(), Result,
+ RVal))
+ return false;
+ Result.setFrom(Info.Ctx, RVal);
+ }
+ return true;
+ }
+ }
CallStackFrame *Frame = nullptr;
if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) {
// Only if a local variable was declared in the function currently being
@@ -5155,15 +5267,19 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
if (E->getBase()->getType()->isVectorType())
return Error(E);
- if (!evaluatePointer(E->getBase(), Result))
- return false;
+ bool Success = true;
+ if (!evaluatePointer(E->getBase(), Result)) {
+ if (!Info.noteFailure())
+ return false;
+ Success = false;
+ }
APSInt Index;
if (!EvaluateInteger(E->getIdx(), Index, Info))
return false;
- return HandleLValueArrayAdjustment(Info, E, Result, E->getType(),
- getExtValue(Index));
+ return Success &&
+ HandleLValueArrayAdjustment(Info, E, Result, E->getType(), Index);
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
@@ -5376,8 +5492,8 @@ public:
return true;
}
bool ZeroInitialization(const Expr *E) {
- auto Offset = Info.Ctx.getTargetNullPointerValue(E->getType());
- Result.set((Expr*)nullptr, 0, false, true, Offset);
+ auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType());
+ Result.setNull(E->getType(), TargetVal);
return true;
}
@@ -5386,8 +5502,11 @@ public:
bool VisitUnaryAddrOf(const UnaryOperator *E);
bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
{ return Success(E); }
- bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E)
- { return Success(E); }
+ bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
+ if (Info.noteFailure())
+ EvaluateIgnoredValue(Info, E->getSubExpr());
+ return Error(E);
+ }
bool VisitAddrLabelExpr(const AddrLabelExpr *E)
{ return Success(E); }
bool VisitCallExpr(const CallExpr *E);
@@ -5409,6 +5528,27 @@ public:
return false;
}
Result = *Info.CurrentCall->This;
+ // If we are inside a lambda's call operator, the 'this' expression refers
+ // to the enclosing '*this' object (either by value or reference) which is
+ // either copied into the closure object's field that represents the '*this'
+ // or refers to '*this'.
+ if (isLambdaCallOperator(Info.CurrentCall->Callee)) {
+ // Update 'Result' to refer to the data member/field of the closure object
+ // that represents the '*this' capture.
+ if (!HandleLValueMember(Info, E, Result,
+ Info.CurrentCall->LambdaThisCaptureField))
+ return false;
+ // If we captured '*this' by reference, replace the field with its referent.
+ if (Info.CurrentCall->LambdaThisCaptureField->getType()
+ ->isPointerType()) {
+ APValue RVal;
+ if (!handleLValueToRValueConversion(Info, E, E->getType(), Result,
+ RVal))
+ return false;
+
+ Result.setFrom(Info.Ctx, RVal);
+ }
+ }
return true;
}
@@ -5440,13 +5580,11 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK)
return false;
- int64_t AdditionalOffset = getExtValue(Offset);
if (E->getOpcode() == BO_Sub)
- AdditionalOffset = -AdditionalOffset;
+ negateAsSigned(Offset);
QualType Pointee = PExp->getType()->castAs<PointerType>()->getPointeeType();
- return HandleLValueArrayAdjustment(Info, E, Result, Pointee,
- AdditionalOffset);
+ return HandleLValueArrayAdjustment(Info, E, Result, Pointee, Offset);
}
bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
@@ -5576,6 +5714,8 @@ static CharUnits GetAlignOfType(EvalInfo &Info, QualType T) {
T = Ref->getPointeeType();
// __alignof is defined to return the preferred alignment.
+ if (T.getQualifiers().hasUnaligned())
+ return CharUnits::One();
return Info.Ctx.toCharUnitsFromBits(
Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
}
@@ -5640,14 +5780,14 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
APSInt Alignment;
if (!EvaluateInteger(E->getArg(1), Alignment, Info))
return false;
- CharUnits Align = CharUnits::fromQuantity(getExtValue(Alignment));
+ CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue());
if (E->getNumArgs() > 2) {
APSInt Offset;
if (!EvaluateInteger(E->getArg(2), Offset, Info))
return false;
- int64_t AdditionalOffset = -getExtValue(Offset);
+ int64_t AdditionalOffset = -Offset.getZExtValue();
OffsetResult.Offset += CharUnits::fromQuantity(AdditionalOffset);
}
@@ -5664,12 +5804,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (BaseAlignment < Align) {
Result.Designator.setInvalid();
- // FIXME: Quantities here cast to integers because the plural modifier
- // does not work on APSInts yet.
+ // FIXME: Add support to Diagnostic for long / long long.
CCEDiag(E->getArg(0),
diag::note_constexpr_baa_insufficient_alignment) << 0
- << (int) BaseAlignment.getQuantity()
- << (unsigned) getExtValue(Alignment);
+ << (unsigned)BaseAlignment.getQuantity()
+ << (unsigned)Align.getQuantity();
return false;
}
}
@@ -5677,18 +5816,14 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// The offset must also have the correct alignment.
if (OffsetResult.Offset.alignTo(Align) != OffsetResult.Offset) {
Result.Designator.setInvalid();
- APSInt Offset(64, false);
- Offset = OffsetResult.Offset.getQuantity();
-
- if (OffsetResult.Base)
- CCEDiag(E->getArg(0),
- diag::note_constexpr_baa_insufficient_alignment) << 1
- << (int) getExtValue(Offset) << (unsigned) getExtValue(Alignment);
- else
- CCEDiag(E->getArg(0),
- diag::note_constexpr_baa_value_insufficient_alignment)
- << Offset << (unsigned) getExtValue(Alignment);
+ (OffsetResult.Base
+ ? CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_insufficient_alignment) << 1
+ : CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_value_insufficient_alignment))
+ << (int)OffsetResult.Offset.getQuantity()
+ << (unsigned)Align.getQuantity();
return false;
}
@@ -6245,14 +6380,40 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
if (ClosureClass->isInvalidDecl()) return false;
if (Info.checkingPotentialConstantExpression()) return true;
- if (E->capture_size()) {
- Info.FFDiag(E, diag::note_unimplemented_constexpr_lambda_feature_ast)
- << "can not evaluate lambda expressions with captures";
- return false;
+
+ const size_t NumFields =
+ std::distance(ClosureClass->field_begin(), ClosureClass->field_end());
+
+ assert(NumFields == (size_t)std::distance(E->capture_init_begin(),
+ E->capture_init_end()) &&
+ "The number of lambda capture initializers should equal the number of "
+ "fields within the closure type");
+
+ Result = APValue(APValue::UninitStruct(), /*NumBases*/0, NumFields);
+ // Iterate through all the lambda's closure object's fields and initialize
+ // them.
+ auto *CaptureInitIt = E->capture_init_begin();
+ const LambdaCapture *CaptureIt = ClosureClass->captures_begin();
+ bool Success = true;
+ for (const auto *Field : ClosureClass->fields()) {
+ assert(CaptureInitIt != E->capture_init_end());
+ // Get the initializer for this field
+ Expr *const CurFieldInit = *CaptureInitIt++;
+
+ // If there is no initializer, either this is a VLA or an error has
+ // occurred.
+ if (!CurFieldInit)
+ return Error(E);
+
+ APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
+ if (!EvaluateInPlace(FieldVal, Info, This, CurFieldInit)) {
+ if (!Info.keepEvaluatingAfterFailure())
+ return false;
+ Success = false;
+ }
+ ++CaptureIt;
}
- // FIXME: Implement captures.
- Result = APValue(APValue::UninitStruct(), /*NumBases*/0, /*NumFields*/0);
- return true;
+ return Success;
}
static bool EvaluateRecord(const Expr *E, const LValue &This,
@@ -6971,7 +7132,6 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E,
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
case BuiltinType::Dependent:
llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
@@ -7030,6 +7190,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E,
case Type::Vector:
case Type::ExtVector:
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
@@ -7948,6 +8109,19 @@ bool DataRecursiveIntBinOpEvaluator::
return true;
}
+static void addOrSubLValueAsInteger(APValue &LVal, const APSInt &Index,
+ bool IsSub) {
+ // Compute the new offset in the appropriate width, wrapping at 64 bits.
+ // FIXME: When compiling for a 32-bit target, we should use 32-bit
+ // offsets.
+ assert(!LVal.hasLValuePath() && "have designator for integer lvalue");
+ CharUnits &Offset = LVal.getLValueOffset();
+ uint64_t Offset64 = Offset.getQuantity();
+ uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
+ Offset = CharUnits::fromQuantity(IsSub ? Offset64 - Index64
+ : Offset64 + Index64);
+}
+
bool DataRecursiveIntBinOpEvaluator::
VisitBinOp(const EvalResult &LHSResult, const EvalResult &RHSResult,
const BinaryOperator *E, APValue &Result) {
@@ -7994,12 +8168,7 @@ bool DataRecursiveIntBinOpEvaluator::
// Handle cases like (unsigned long)&a + 4.
if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) {
Result = LHSVal;
- CharUnits AdditionalOffset =
- CharUnits::fromQuantity(RHSVal.getInt().getZExtValue());
- if (E->getOpcode() == BO_Add)
- Result.getLValueOffset() += AdditionalOffset;
- else
- Result.getLValueOffset() -= AdditionalOffset;
+ addOrSubLValueAsInteger(Result, RHSVal.getInt(), E->getOpcode() == BO_Sub);
return true;
}
@@ -8007,8 +8176,7 @@ bool DataRecursiveIntBinOpEvaluator::
if (E->getOpcode() == BO_Add &&
RHSVal.isLValue() && LHSVal.isInt()) {
Result = RHSVal;
- Result.getLValueOffset() +=
- CharUnits::fromQuantity(LHSVal.getInt().getZExtValue());
+ addOrSubLValueAsInteger(Result, LHSVal.getInt(), /*IsSub*/false);
return true;
}
@@ -9352,7 +9520,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
case BO_Mul:
if (Result.isComplexFloat()) {
// This is an implementation of complex multiplication according to the
- // constraints laid out in C11 Annex G. The implemantion uses the
+ // constraints laid out in C11 Annex G. The implemention uses the
// following naming scheme:
// (a + ib) * (c + id)
ComplexValue LHS = Result;
@@ -9433,7 +9601,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
case BO_Div:
if (Result.isComplexFloat()) {
// This is an implementation of complex division according to the
- // constraints laid out in C11 Annex G. The implemantion uses the
+ // constraints laid out in C11 Annex G. The implemention uses the
// following naming scheme:
// (a + ib) / (c + id)
ComplexValue LHS = Result;
@@ -9610,6 +9778,8 @@ public:
bool Success(const APValue &V, const Expr *e) { return true; }
+ bool ZeroInitialization(const Expr *E) { return true; }
+
bool VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
@@ -9945,7 +10115,7 @@ bool Expr::EvalResult::isGlobalLValue() const {
// Note that to reduce code duplication, this helper does no evaluation
// itself; the caller checks whether the expression is evaluatable, and
// in the rare cases where CheckICE actually cares about the evaluated
-// value, it calls into Evalute.
+// value, it calls into Evaluate.
namespace {
@@ -10067,6 +10237,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::LambdaExprClass:
case Expr::CXXFoldExprClass:
case Expr::CoawaitExprClass:
+ case Expr::DependentCoawaitExprClass:
case Expr::CoyieldExprClass:
return ICEDiag(IK_NotICE, E->getLocStart());
@@ -10169,6 +10340,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
}
// OffsetOf falls through here.
+ LLVM_FALLTHROUGH;
}
case Expr::OffsetOfExprClass: {
// Note that per C99, offsetof must be an ICE. And AFAIK, using
@@ -10271,6 +10443,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
return Worst(LHSResult, RHSResult);
}
}
+ LLVM_FALLTHROUGH;
}
case Expr::ImplicitCastExprClass:
case Expr::CStyleCastExprClass:
diff --git a/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp
new file mode 100644
index 0000000..4f4a997
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp
@@ -0,0 +1,182 @@
+//===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the ExternalASTMerger, which vends a combination of
+// ASTs from several different ASTContext/FileManager pairs
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExternalASTMerger.h"
+
+using namespace clang;
+
+namespace {
+
+template <typename T> struct Source {
+ T t;
+ Source(T t) : t(t) {}
+ operator T() { return t; }
+ template <typename U = T> U &get() { return t; }
+ template <typename U = T> const U &get() const { return t; }
+ template <typename U> operator Source<U>() { return Source<U>(t); }
+};
+
+typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate;
+
+class LazyASTImporter : public ASTImporter {
+public:
+ LazyASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager)
+ : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
+ /*MinimalImport=*/true) {}
+ Decl *Imported(Decl *From, Decl *To) override {
+ if (auto ToTag = dyn_cast<TagDecl>(To)) {
+ ToTag->setHasExternalLexicalStorage();
+ ToTag->setMustBuildLookupTable();
+ } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) {
+ ToNamespace->setHasExternalVisibleStorage();
+ }
+ return ASTImporter::Imported(From, To);
+ }
+};
+
+Source<const DeclContext *>
+LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
+ ASTImporter &ReverseImporter) {
+ if (DC->isTranslationUnit()) {
+ return SourceTU;
+ }
+ Source<const DeclContext *> SourceParentDC =
+ LookupSameContext(SourceTU, DC->getParent(), ReverseImporter);
+ if (!SourceParentDC) {
+ // If we couldn't find the parent DC in this TranslationUnit, give up.
+ return nullptr;
+ }
+ auto ND = cast<NamedDecl>(DC);
+ DeclarationName Name = ND->getDeclName();
+ Source<DeclarationName> SourceName = ReverseImporter.Import(Name);
+ DeclContext::lookup_result SearchResult =
+ SourceParentDC.get()->lookup(SourceName.get());
+ size_t SearchResultSize = SearchResult.size();
+ // Handle multiple candidates once we have a test for it.
+ // This may turn up when we import template specializations correctly.
+ assert(SearchResultSize < 2);
+ if (SearchResultSize == 0) {
+ // couldn't find the name, so we have to give up
+ return nullptr;
+ } else {
+ NamedDecl *SearchResultDecl = SearchResult[0];
+ return dyn_cast<DeclContext>(SearchResultDecl);
+ }
+}
+
+bool IsForwardDeclaration(Decl *D) {
+ assert(!isa<ObjCInterfaceDecl>(D)); // TODO handle this case
+ if (auto TD = dyn_cast<TagDecl>(D)) {
+ return !TD->isThisDeclarationADefinition();
+ } else if (auto FD = dyn_cast<FunctionDecl>(D)) {
+ return !FD->isThisDeclarationADefinition();
+ } else {
+ return false;
+ }
+}
+
+template <typename CallbackType>
+void ForEachMatchingDC(
+ const DeclContext *DC,
+ llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers,
+ CallbackType Callback) {
+ for (const ExternalASTMerger::ImporterPair &IP : Importers) {
+ Source<TranslationUnitDecl *> SourceTU =
+ IP.Forward->getFromContext().getTranslationUnitDecl();
+ if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse))
+ Callback(IP, SourceDC);
+ }
+}
+
+bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
+ return llvm::any_of(Decls, [&](const Candidate &D) {
+ return C.first.get()->getKind() == D.first.get()->getKind();
+ });
+}
+} // end namespace
+
+ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target,
+ llvm::ArrayRef<ImporterEndpoint> Sources) {
+ for (const ImporterEndpoint &S : Sources) {
+ Importers.push_back(
+ {llvm::make_unique<LazyASTImporter>(Target.AST, Target.FM, S.AST, S.FM),
+ llvm::make_unique<ASTImporter>(S.AST, S.FM, Target.AST, Target.FM,
+ /*MinimalImport=*/true)});
+ }
+}
+
+bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+ llvm::SmallVector<NamedDecl *, 1> Decls;
+ llvm::SmallVector<Candidate, 4> CompleteDecls;
+ llvm::SmallVector<Candidate, 4> ForwardDecls;
+
+ auto FilterFoundDecl = [&CompleteDecls, &ForwardDecls](const Candidate &C) {
+ if (IsForwardDeclaration(C.first.get())) {
+ if (!HasDeclOfSameType(ForwardDecls, C)) {
+ ForwardDecls.push_back(C);
+ }
+ } else {
+ CompleteDecls.push_back(C);
+ }
+ };
+
+ ForEachMatchingDC(
+ DC, Importers,
+ [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) {
+ DeclarationName FromName = IP.Reverse->Import(Name);
+ DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
+ for (NamedDecl *FromD : Result) {
+ FilterFoundDecl(std::make_pair(FromD, IP.Forward.get()));
+ }
+ });
+
+ llvm::ArrayRef<Candidate> DeclsToReport =
+ CompleteDecls.empty() ? ForwardDecls : CompleteDecls;
+
+ if (DeclsToReport.empty()) {
+ return false;
+ }
+
+ Decls.reserve(DeclsToReport.size());
+ for (const Candidate &C : DeclsToReport) {
+ NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get()));
+ assert(d);
+ Decls.push_back(d);
+ }
+ SetExternalVisibleDeclsForName(DC, Name, Decls);
+ return true;
+}
+
+void ExternalASTMerger::FindExternalLexicalDecls(
+ const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
+ SmallVectorImpl<Decl *> &Result) {
+ ForEachMatchingDC(
+ DC, Importers,
+ [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) {
+ for (const Decl *SourceDecl : SourceDC.get()->decls()) {
+ if (IsKindWeWant(SourceDecl->getKind())) {
+ Decl *ImportedDecl =
+ IP.Forward->Import(const_cast<Decl *>(SourceDecl));
+ assert(ImportedDecl->getDeclContext() == DC);
+ (void)ImportedDecl;
+ }
+ }
+ });
+}
+
diff --git a/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp
index e3de8c5..182d382 100644
--- a/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp
@@ -28,6 +28,11 @@ ExternalASTSource::getSourceDescriptor(unsigned ID) {
return None;
}
+ExternalASTSource::ExtKind
+ExternalASTSource::hasExternalDefinitions(const Decl *D) {
+ return EK_ReplyHazy;
+}
+
ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(const Module &M)
: Signature(M.Signature), ClangModule(&M) {
if (M.Directory)
diff --git a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp
index ab3e49d..4e7c6c4 100644
--- a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp
@@ -982,9 +982,8 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
unsigned digitBitIndex = 4 * (numCharacters - stringIndex - 1);
// Project out 4 bits starting at 'digitIndex'.
- llvm::integerPart hexDigit
- = valueBits.getRawData()[digitBitIndex / llvm::integerPartWidth];
- hexDigit >>= (digitBitIndex % llvm::integerPartWidth);
+ uint64_t hexDigit = valueBits.getRawData()[digitBitIndex / 64];
+ hexDigit >>= (digitBitIndex % 64);
hexDigit &= 0xF;
// Map that over to a lowercase hex digit.
@@ -1190,6 +1189,8 @@ void CXXNameMangler::mangleUnresolvedName(
llvm_unreachable("Can't mangle a constructor name!");
case DeclarationName::CXXUsingDirective:
llvm_unreachable("Can't mangle a using directive name!");
+ case DeclarationName::CXXDeductionGuideName:
+ llvm_unreachable("Can't mangle a deduction guide name!");
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCZeroArgSelector:
@@ -1419,6 +1420,9 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
writeAbiTags(ND, AdditionalAbiTags);
break;
+ case DeclarationName::CXXDeductionGuideName:
+ llvm_unreachable("Can't mangle a deduction guide name!");
+
case DeclarationName::CXXUsingDirective:
llvm_unreachable("Can't mangle a using directive name!");
}
@@ -1451,7 +1455,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
Out << 'N';
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) {
Qualifiers MethodQuals =
- Qualifiers::fromCVRMask(Method->getTypeQualifiers());
+ Qualifiers::fromCVRUMask(Method->getTypeQualifiers());
// We do not consider restrict a distinguishing attribute for overloading
// purposes so we must not mangle it.
MethodQuals.removeRestrict();
@@ -1870,6 +1874,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::Paren:
case Type::Attributed:
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
case Type::PackExpansion:
case Type::ObjCObject:
case Type::ObjCInterface:
@@ -1996,6 +2001,7 @@ void CXXNameMangler::mangleOperatorName(DeclarationName Name, unsigned Arity) {
switch (Name.getNameKind()) {
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXDeductionGuideName:
case DeclarationName::CXXUsingDirective:
case DeclarationName::Identifier:
case DeclarationName::ObjCMultiArgSelector:
@@ -2132,7 +2138,8 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
}
void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
- // Vendor qualifiers come first.
+ // Vendor qualifiers come first and if they are order-insensitive they must
+ // be emitted in reversed alphabetical order, see Itanium ABI 5.1.5.
// Address space qualifiers start with an ordinary letter.
if (Quals.hasAddressSpace()) {
@@ -2152,10 +2159,12 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
} else {
switch (AS) {
default: llvm_unreachable("Not a language specific address space");
- // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" ]
+ // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant |
+ // "generic" ]
case LangAS::opencl_global: ASString = "CLglobal"; break;
case LangAS::opencl_local: ASString = "CLlocal"; break;
case LangAS::opencl_constant: ASString = "CLconstant"; break;
+ case LangAS::opencl_generic: ASString = "CLgeneric"; break;
// <CUDA-addrspace> ::= "CU" [ "device" | "constant" | "shared" ]
case LangAS::cuda_device: ASString = "CUdevice"; break;
case LangAS::cuda_constant: ASString = "CUconstant"; break;
@@ -2166,17 +2175,28 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
}
// The ARC ownership qualifiers start with underscores.
- switch (Quals.getObjCLifetime()) {
// Objective-C ARC Extension:
//
// <type> ::= U "__strong"
// <type> ::= U "__weak"
// <type> ::= U "__autoreleasing"
+ //
+ // Note: we emit __weak first to preserve the order as
+ // required by the Itanium ABI.
+ if (Quals.getObjCLifetime() == Qualifiers::OCL_Weak)
+ mangleVendorQualifier("__weak");
+
+ // __unaligned (from -fms-extensions)
+ if (Quals.hasUnaligned())
+ mangleVendorQualifier("__unaligned");
+
+ // Remaining ARC ownership qualifiers.
+ switch (Quals.getObjCLifetime()) {
case Qualifiers::OCL_None:
break;
case Qualifiers::OCL_Weak:
- mangleVendorQualifier("__weak");
+ // Do nothing as we already handled this case above.
break;
case Qualifiers::OCL_Strong:
@@ -2493,9 +2513,6 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::OCLQueue:
Out << "9ocl_queue";
break;
- case BuiltinType::OCLNDRange:
- Out << "11ocl_ndrange";
- break;
case BuiltinType::OCLReserveID:
Out << "13ocl_reserveid";
break;
@@ -2512,7 +2529,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
case CC_X86ThisCall:
case CC_X86VectorCall:
case CC_X86Pascal:
- case CC_X86_64Win64:
+ case CC_Win64:
case CC_X86_64SysV:
case CC_X86RegCall:
case CC_AAPCS:
@@ -3043,6 +3060,7 @@ void CXXNameMangler::mangleType(const DependentNameType *T) {
// ::= Te <name> # dependent elaborated type specifier using
// # 'enum'
switch (T->getKeyword()) {
+ case ETK_None:
case ETK_Typename:
break;
case ETK_Struct:
@@ -3056,8 +3074,6 @@ void CXXNameMangler::mangleType(const DependentNameType *T) {
case ETK_Enum:
Out << "Te";
break;
- default:
- llvm_unreachable("unexpected keyword for dependent type name");
}
// Typename types are always nested
Out << 'N';
@@ -3146,6 +3162,16 @@ void CXXNameMangler::mangleType(const AutoType *T) {
mangleType(D);
}
+void CXXNameMangler::mangleType(const DeducedTemplateSpecializationType *T) {
+ // FIXME: This is not the right mangling. We also need to include a scope
+ // here in some cases.
+ QualType D = T->getDeducedType();
+ if (D.isNull())
+ mangleUnscopedTemplateName(T->getTemplateName(), nullptr);
+ else
+ mangleType(D);
+}
+
void CXXNameMangler::mangleType(const AtomicType *T) {
// <type> ::= U <source-name> <type> # vendor extended type qualifier
// (Until there's a standardized mangling...)
@@ -3759,6 +3785,7 @@ recurse:
Out << "v1U" << Kind.size() << Kind;
}
// Fall through to mangle the cast itself.
+ LLVM_FALLTHROUGH;
case Expr::CStyleCastExprClass:
mangleCastExpression(E, "cv");
@@ -4021,6 +4048,12 @@ recurse:
mangleExpression(cast<CoawaitExpr>(E)->getOperand());
break;
+ case Expr::DependentCoawaitExprClass:
+ // FIXME: Propose a non-vendor mangling.
+ Out << "v18co_await";
+ mangleExpression(cast<DependentCoawaitExpr>(E)->getOperand());
+ break;
+
case Expr::CoyieldExprClass:
// FIXME: Propose a non-vendor mangling.
Out << "v18co_yield";
@@ -4305,7 +4338,7 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
/// substitutions.
static bool hasMangledSubstitutionQualifiers(QualType T) {
Qualifiers Qs = T.getQualifiers();
- return Qs.getCVRQualifiers() || Qs.hasAddressSpace();
+ return Qs.getCVRQualifiers() || Qs.hasAddressSpace() || Qs.hasUnaligned();
}
bool CXXNameMangler::mangleSubstitution(QualType T) {
@@ -4517,9 +4550,11 @@ CXXNameMangler::makeFunctionReturnTypeTags(const FunctionDecl *FD) {
const FunctionProtoType *Proto =
cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
+ FunctionTypeDepthState saved = TrackReturnTypeTags.FunctionTypeDepth.push();
TrackReturnTypeTags.FunctionTypeDepth.enterResultType();
TrackReturnTypeTags.mangleType(Proto->getReturnType());
TrackReturnTypeTags.FunctionTypeDepth.leaveResultType();
+ TrackReturnTypeTags.FunctionTypeDepth.pop(saved);
return TrackReturnTypeTags.AbiTagsRoot.getSortedUniqueUsedAbiTags();
}
diff --git a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp
index 05dd886..00d50c0 100644
--- a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp
@@ -262,9 +262,13 @@ void MangleContext::mangleObjCMethodNameWithoutSize(const ObjCMethodDecl *MD,
const ObjCContainerDecl *CD =
dyn_cast<ObjCContainerDecl>(MD->getDeclContext());
assert (CD && "Missing container decl in GetNameForMethod");
- OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
- if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
+ OS << (MD->isInstanceMethod() ? '-' : '+') << '[';
+ if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD)) {
+ OS << CID->getClassInterface()->getName();
OS << '(' << *CID << ')';
+ } else {
+ OS << CD->getName();
+ }
OS << ' ';
MD->getSelector().print(OS);
OS << ']';
diff --git a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp
index 76c368d..24b16f8 100644
--- a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp
@@ -942,6 +942,9 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
break;
}
+ case DeclarationName::CXXDeductionGuideName:
+ llvm_unreachable("Can't mangle a deduction guide name!");
+
case DeclarationName::CXXUsingDirective:
llvm_unreachable("Can't mangle a using directive name!");
}
@@ -963,16 +966,71 @@ void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) {
}
if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID =
- Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle a local inside this block yet");
- Diags.Report(BD->getLocation(), DiagID);
-
- // FIXME: This is completely, utterly, wrong; see ItaniumMangle
- // for how this should be done.
- Out << "__block_invoke" << Context.getBlockId(BD, false);
- Out << '@';
+ auto Discriminate =
+ [](StringRef Name, const unsigned Discriminator,
+ const unsigned ParameterDiscriminator) -> std::string {
+ std::string Buffer;
+ llvm::raw_string_ostream Stream(Buffer);
+ Stream << Name;
+ if (Discriminator)
+ Stream << '_' << Discriminator;
+ if (ParameterDiscriminator)
+ Stream << '_' << ParameterDiscriminator;
+ return Stream.str();
+ };
+
+ unsigned Discriminator = BD->getBlockManglingNumber();
+ if (!Discriminator)
+ Discriminator = Context.getBlockId(BD, /*Local=*/false);
+
+ // Mangle the parameter position as a discriminator to deal with unnamed
+ // parameters. Rather than mangling the unqualified parameter name,
+ // always use the position to give a uniform mangling.
+ unsigned ParameterDiscriminator = 0;
+ if (const auto *MC = BD->getBlockManglingContextDecl())
+ if (const auto *P = dyn_cast<ParmVarDecl>(MC))
+ if (const auto *F = dyn_cast<FunctionDecl>(P->getDeclContext()))
+ ParameterDiscriminator =
+ F->getNumParams() - P->getFunctionScopeIndex();
+
+ DC = getEffectiveDeclContext(BD);
+
+ Out << '?';
+ mangleSourceName(Discriminate("_block_invoke", Discriminator,
+ ParameterDiscriminator));
+ // If we have a block mangling context, encode that now. This allows us
+ // to discriminate between named static data initializers in the same
+ // scope. This is handled differently from parameters, which use
+ // positions to discriminate between multiple instances.
+ if (const auto *MC = BD->getBlockManglingContextDecl())
+ if (!isa<ParmVarDecl>(MC))
+ if (const auto *ND = dyn_cast<NamedDecl>(MC))
+ mangleUnqualifiedName(ND);
+ // MS ABI and Itanium manglings are in inverted scopes. In the case of a
+ // RecordDecl, mangle the entire scope hierachy at this point rather than
+ // just the unqualified name to get the ordering correct.
+ if (const auto *RD = dyn_cast<RecordDecl>(DC))
+ mangleName(RD);
+ else
+ Out << '@';
+ // void __cdecl
+ Out << "YAX";
+ // struct __block_literal *
+ Out << 'P';
+ // __ptr64
+ if (PointersAre64Bit)
+ Out << 'E';
+ Out << 'A';
+ mangleArtificalTagType(TTK_Struct,
+ Discriminate("__block_literal", Discriminator,
+ ParameterDiscriminator));
+ Out << "@Z";
+
+ // If the effective context was a Record, we have fully mangled the
+ // qualified name and do not need to continue.
+ if (isa<RecordDecl>(DC))
+ break;
+ continue;
} else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) {
mangleObjCMethodName(Method);
} else if (isa<NamedDecl>(DC)) {
@@ -1686,6 +1744,8 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
// ::= _N # bool
// _O # <array in parameter>
// ::= _T # __float80 (Intel)
+ // ::= _S # char16_t
+ // ::= _U # char32_t
// ::= _W # wchar_t
// ::= _Z # __float80 (Digital Mars)
switch (T->getKind()) {
@@ -1797,10 +1857,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
Out << "PA";
mangleArtificalTagType(TTK_Struct, "ocl_queue");
break;
- case BuiltinType::OCLNDRange:
- Out << "PA";
- mangleArtificalTagType(TTK_Struct, "ocl_ndrange");
- break;
case BuiltinType::OCLReserveID:
Out << "PA";
mangleArtificalTagType(TTK_Struct, "ocl_reserveid");
@@ -1887,14 +1943,18 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
if (IsStructor) {
- if (isa<CXXDestructorDecl>(D) && isStructorDecl(D) &&
- StructorType == Dtor_Deleting) {
- // The scalar deleting destructor takes an extra int argument.
- // However, the FunctionType generated has 0 arguments.
- // FIXME: This is a temporary hack.
- // Maybe should fix the FunctionType creation instead?
- Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z");
- return;
+ if (isa<CXXDestructorDecl>(D) && isStructorDecl(D)) {
+ // The scalar deleting destructor takes an extra int argument which is not
+ // reflected in the AST.
+ if (StructorType == Dtor_Deleting) {
+ Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z");
+ return;
+ }
+ // The vbase destructor returns void which is not reflected in the AST.
+ if (StructorType == Dtor_Complete) {
+ Out << "XXZ";
+ return;
+ }
}
if (IsCtorClosure) {
// Default constructor closure and copy constructor closure both return
@@ -1954,7 +2014,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// Happens for function pointer type arguments for example.
for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
mangleArgumentType(Proto->getParamType(I), Range);
- // Mangle each pass_object_size parameter as if it's a paramater of enum
+ // Mangle each pass_object_size parameter as if it's a parameter of enum
// type passed directly after the parameter with the pass_object_size
// attribute. The aforementioned enum's name is __pass_object_size, and we
// pretend it resides in a top-level namespace called __clang.
@@ -2002,13 +2062,20 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
// <global-function> ::= Y # global near
// ::= Z # global far
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ bool IsVirtual = MD->isVirtual();
+ // When mangling vbase destructor variants, ignore whether or not the
+ // underlying destructor was defined to be virtual.
+ if (isa<CXXDestructorDecl>(MD) && isStructorDecl(MD) &&
+ StructorType == Dtor_Complete) {
+ IsVirtual = false;
+ }
switch (MD->getAccess()) {
case AS_none:
llvm_unreachable("Unsupported access specifier");
case AS_private:
if (MD->isStatic())
Out << 'C';
- else if (MD->isVirtual())
+ else if (IsVirtual)
Out << 'E';
else
Out << 'A';
@@ -2016,7 +2083,7 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
case AS_protected:
if (MD->isStatic())
Out << 'K';
- else if (MD->isVirtual())
+ else if (IsVirtual)
Out << 'M';
else
Out << 'I';
@@ -2024,7 +2091,7 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
case AS_public:
if (MD->isStatic())
Out << 'S';
- else if (MD->isVirtual())
+ else if (IsVirtual)
Out << 'U';
else
Out << 'Q';
@@ -2055,7 +2122,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) {
switch (CC) {
default:
llvm_unreachable("Unsupported CC for mangling");
- case CC_X86_64Win64:
+ case CC_Win64:
case CC_X86_64SysV:
case CC_C: Out << 'A'; break;
case CC_X86Pascal: Out << 'C'; break;
@@ -2474,6 +2541,17 @@ void MicrosoftCXXNameMangler::mangleType(const AutoType *T, Qualifiers,
<< Range;
}
+void MicrosoftCXXNameMangler::mangleType(
+ const DeducedTemplateSpecializationType *T, Qualifiers, SourceRange Range) {
+ assert(T->getDeducedType().isNull() && "expecting a dependent type!");
+
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this deduced class template specialization type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers,
SourceRange Range) {
QualType ValueType = T->getValueType();
@@ -2997,14 +3075,14 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
// N.B. The length is in terms of bytes, not characters.
Mangler.mangleNumber(SL->getByteLength() + SL->getCharByteWidth());
- auto GetLittleEndianByte = [&Mangler, &SL](unsigned Index) {
+ auto GetLittleEndianByte = [&SL](unsigned Index) {
unsigned CharByteWidth = SL->getCharByteWidth();
uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth);
unsigned OffsetInCodeUnit = Index % CharByteWidth;
return static_cast<char>((CodeUnit >> (8 * OffsetInCodeUnit)) & 0xff);
};
- auto GetBigEndianByte = [&Mangler, &SL](unsigned Index) {
+ auto GetBigEndianByte = [&SL](unsigned Index) {
unsigned CharByteWidth = SL->getCharByteWidth();
uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth);
unsigned OffsetInCodeUnit = (CharByteWidth - 1) - (Index % CharByteWidth);
diff --git a/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp b/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp
index ac2a8d3..e7c8c16 100644
--- a/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp
@@ -453,7 +453,6 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
case BuiltinType::BoundMember:
case BuiltinType::Dependent:
diff --git a/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp
index 514c7c9..e2e0dbe 100644
--- a/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp
@@ -290,6 +290,7 @@ NestedNameSpecifier::print(raw_ostream &OS,
case TypeSpecWithTemplate:
OS << "template ";
// Fall through to print the type.
+ LLVM_FALLTHROUGH;
case TypeSpec: {
const Type *T = getAsType();
diff --git a/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp b/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp
new file mode 100644
index 0000000..121724a
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/AST/ODRHash.cpp
@@ -0,0 +1,636 @@
+//===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the ODRHash class, which calculates a hash based
+/// on AST nodes, which is stable across different runs.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ODRHash.h"
+
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeVisitor.h"
+
+using namespace clang;
+
+void ODRHash::AddStmt(const Stmt *S) {
+ assert(S && "Expecting non-null pointer.");
+ S->ProcessODRHash(ID, *this);
+}
+
+void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) {
+ assert(II && "Expecting non-null pointer.");
+ ID.AddString(II->getName());
+}
+
+void ODRHash::AddDeclarationName(DeclarationName Name) {
+ AddBoolean(Name.isEmpty());
+ if (Name.isEmpty())
+ return;
+
+ auto Kind = Name.getNameKind();
+ ID.AddInteger(Kind);
+ switch (Kind) {
+ case DeclarationName::Identifier:
+ AddIdentifierInfo(Name.getAsIdentifierInfo());
+ break;
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector: {
+ Selector S = Name.getObjCSelector();
+ AddBoolean(S.isNull());
+ AddBoolean(S.isKeywordSelector());
+ AddBoolean(S.isUnarySelector());
+ unsigned NumArgs = S.getNumArgs();
+ for (unsigned i = 0; i < NumArgs; ++i) {
+ AddIdentifierInfo(S.getIdentifierInfoForSlot(i));
+ }
+ break;
+ }
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ AddQualType(Name.getCXXNameType());
+ break;
+ case DeclarationName::CXXOperatorName:
+ ID.AddInteger(Name.getCXXOverloadedOperator());
+ break;
+ case DeclarationName::CXXLiteralOperatorName:
+ AddIdentifierInfo(Name.getCXXLiteralIdentifier());
+ break;
+ case DeclarationName::CXXConversionFunctionName:
+ AddQualType(Name.getCXXNameType());
+ break;
+ case DeclarationName::CXXUsingDirective:
+ break;
+ case DeclarationName::CXXDeductionGuideName: {
+ auto *Template = Name.getCXXDeductionGuideTemplate();
+ AddBoolean(Template);
+ if (Template) {
+ AddDecl(Template);
+ }
+ }
+ }
+}
+
+void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
+ assert(NNS && "Expecting non-null pointer.");
+ const auto *Prefix = NNS->getPrefix();
+ AddBoolean(Prefix);
+ if (Prefix) {
+ AddNestedNameSpecifier(Prefix);
+ }
+ auto Kind = NNS->getKind();
+ ID.AddInteger(Kind);
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier:
+ AddIdentifierInfo(NNS->getAsIdentifier());
+ break;
+ case NestedNameSpecifier::Namespace:
+ AddDecl(NNS->getAsNamespace());
+ break;
+ case NestedNameSpecifier::NamespaceAlias:
+ AddDecl(NNS->getAsNamespaceAlias());
+ break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ AddType(NNS->getAsType());
+ break;
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super:
+ break;
+ }
+}
+
+void ODRHash::AddTemplateName(TemplateName Name) {
+ auto Kind = Name.getKind();
+ ID.AddInteger(Kind);
+
+ switch (Kind) {
+ case TemplateName::Template:
+ AddDecl(Name.getAsTemplateDecl());
+ break;
+ // TODO: Support these cases.
+ case TemplateName::OverloadedTemplate:
+ case TemplateName::QualifiedTemplate:
+ case TemplateName::DependentTemplate:
+ case TemplateName::SubstTemplateTemplateParm:
+ case TemplateName::SubstTemplateTemplateParmPack:
+ break;
+ }
+}
+
+void ODRHash::AddTemplateArgument(TemplateArgument TA) {
+ const auto Kind = TA.getKind();
+ ID.AddInteger(Kind);
+
+ switch (Kind) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Expected valid TemplateArgument");
+ case TemplateArgument::Type:
+ AddQualType(TA.getAsType());
+ break;
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Integral:
+ break;
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ AddTemplateName(TA.getAsTemplateOrTemplatePattern());
+ break;
+ case TemplateArgument::Expression:
+ AddStmt(TA.getAsExpr());
+ break;
+ case TemplateArgument::Pack:
+ ID.AddInteger(TA.pack_size());
+ for (auto SubTA : TA.pack_elements()) {
+ AddTemplateArgument(SubTA);
+ }
+ break;
+ }
+}
+
+void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {}
+
+void ODRHash::clear() {
+ DeclMap.clear();
+ TypeMap.clear();
+ Bools.clear();
+ ID.clear();
+}
+
+unsigned ODRHash::CalculateHash() {
+ // Append the bools to the end of the data segment backwards. This allows
+ // for the bools data to be compressed 32 times smaller compared to using
+ // ID.AddBoolean
+ const unsigned unsigned_bits = sizeof(unsigned) * CHAR_BIT;
+ const unsigned size = Bools.size();
+ const unsigned remainder = size % unsigned_bits;
+ const unsigned loops = size / unsigned_bits;
+ auto I = Bools.rbegin();
+ unsigned value = 0;
+ for (unsigned i = 0; i < remainder; ++i) {
+ value <<= 1;
+ value |= *I;
+ ++I;
+ }
+ ID.AddInteger(value);
+
+ for (unsigned i = 0; i < loops; ++i) {
+ value = 0;
+ for (unsigned j = 0; j < unsigned_bits; ++j) {
+ value <<= 1;
+ value |= *I;
+ ++I;
+ }
+ ID.AddInteger(value);
+ }
+
+ assert(I == Bools.rend());
+ Bools.clear();
+ return ID.ComputeHash();
+}
+
+// Process a Decl pointer. Add* methods call back into ODRHash while Visit*
+// methods process the relevant parts of the Decl.
+class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
+ typedef ConstDeclVisitor<ODRDeclVisitor> Inherited;
+ llvm::FoldingSetNodeID &ID;
+ ODRHash &Hash;
+
+public:
+ ODRDeclVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash)
+ : ID(ID), Hash(Hash) {}
+
+ void AddStmt(const Stmt *S) {
+ Hash.AddBoolean(S);
+ if (S) {
+ Hash.AddStmt(S);
+ }
+ }
+
+ void AddIdentifierInfo(const IdentifierInfo *II) {
+ Hash.AddBoolean(II);
+ if (II) {
+ Hash.AddIdentifierInfo(II);
+ }
+ }
+
+ void AddQualType(QualType T) {
+ Hash.AddQualType(T);
+ }
+
+ void AddDecl(const Decl *D) {
+ Hash.AddBoolean(D);
+ if (D) {
+ Hash.AddDecl(D);
+ }
+ }
+
+ void Visit(const Decl *D) {
+ ID.AddInteger(D->getKind());
+ Inherited::Visit(D);
+ }
+
+ void VisitNamedDecl(const NamedDecl *D) {
+ Hash.AddDeclarationName(D->getDeclName());
+ Inherited::VisitNamedDecl(D);
+ }
+
+ void VisitValueDecl(const ValueDecl *D) {
+ if (!isa<FunctionDecl>(D)) {
+ AddQualType(D->getType());
+ }
+ Inherited::VisitValueDecl(D);
+ }
+
+ void VisitVarDecl(const VarDecl *D) {
+ Hash.AddBoolean(D->isStaticLocal());
+ Hash.AddBoolean(D->isConstexpr());
+ const bool HasInit = D->hasInit();
+ Hash.AddBoolean(HasInit);
+ if (HasInit) {
+ AddStmt(D->getInit());
+ }
+ Inherited::VisitVarDecl(D);
+ }
+
+ void VisitParmVarDecl(const ParmVarDecl *D) {
+ // TODO: Handle default arguments.
+ Inherited::VisitParmVarDecl(D);
+ }
+
+ void VisitAccessSpecDecl(const AccessSpecDecl *D) {
+ ID.AddInteger(D->getAccess());
+ Inherited::VisitAccessSpecDecl(D);
+ }
+
+ void VisitStaticAssertDecl(const StaticAssertDecl *D) {
+ AddStmt(D->getAssertExpr());
+ AddStmt(D->getMessage());
+
+ Inherited::VisitStaticAssertDecl(D);
+ }
+
+ void VisitFieldDecl(const FieldDecl *D) {
+ const bool IsBitfield = D->isBitField();
+ Hash.AddBoolean(IsBitfield);
+
+ if (IsBitfield) {
+ AddStmt(D->getBitWidth());
+ }
+
+ Hash.AddBoolean(D->isMutable());
+ AddStmt(D->getInClassInitializer());
+
+ Inherited::VisitFieldDecl(D);
+ }
+
+ void VisitFunctionDecl(const FunctionDecl *D) {
+ ID.AddInteger(D->getStorageClass());
+ Hash.AddBoolean(D->isInlineSpecified());
+ Hash.AddBoolean(D->isVirtualAsWritten());
+ Hash.AddBoolean(D->isPure());
+ Hash.AddBoolean(D->isDeletedAsWritten());
+
+ ID.AddInteger(D->param_size());
+
+ for (auto *Param : D->parameters()) {
+ Hash.AddSubDecl(Param);
+ }
+
+ AddQualType(D->getReturnType());
+
+ Inherited::VisitFunctionDecl(D);
+ }
+
+ void VisitCXXMethodDecl(const CXXMethodDecl *D) {
+ Hash.AddBoolean(D->isConst());
+ Hash.AddBoolean(D->isVolatile());
+
+ Inherited::VisitCXXMethodDecl(D);
+ }
+
+ void VisitTypedefNameDecl(const TypedefNameDecl *D) {
+ AddQualType(D->getUnderlyingType());
+
+ Inherited::VisitTypedefNameDecl(D);
+ }
+
+ void VisitTypedefDecl(const TypedefDecl *D) {
+ Inherited::VisitTypedefDecl(D);
+ }
+
+ void VisitTypeAliasDecl(const TypeAliasDecl *D) {
+ Inherited::VisitTypeAliasDecl(D);
+ }
+
+ void VisitFriendDecl(const FriendDecl *D) {
+ TypeSourceInfo *TSI = D->getFriendType();
+ Hash.AddBoolean(TSI);
+ if (TSI) {
+ AddQualType(TSI->getType());
+ } else {
+ AddDecl(D->getFriendDecl());
+ }
+ }
+};
+
+// Only allow a small portion of Decl's to be processed. Remove this once
+// all Decl's can be handled.
+bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
+ if (D->isImplicit()) return false;
+ if (D->getDeclContext() != Parent) return false;
+
+ switch (D->getKind()) {
+ default:
+ return false;
+ case Decl::AccessSpec:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXMethod:
+ case Decl::Field:
+ case Decl::Friend:
+ case Decl::StaticAssert:
+ case Decl::TypeAlias:
+ case Decl::Typedef:
+ case Decl::Var:
+ return true;
+ }
+}
+
+void ODRHash::AddSubDecl(const Decl *D) {
+ assert(D && "Expecting non-null pointer.");
+ AddDecl(D);
+
+ ODRDeclVisitor(ID, *this).Visit(D);
+}
+
+void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
+ assert(Record && Record->hasDefinition() &&
+ "Expected non-null record to be a definition.");
+
+ const DeclContext *DC = Record;
+ while (DC) {
+ if (isa<ClassTemplateSpecializationDecl>(DC)) {
+ return;
+ }
+ DC = DC->getParent();
+ }
+
+ AddDecl(Record);
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (const Decl *SubDecl : Record->decls()) {
+ if (isWhitelistedDecl(SubDecl, Record)) {
+ Decls.push_back(SubDecl);
+ }
+ }
+
+ ID.AddInteger(Decls.size());
+ for (auto SubDecl : Decls) {
+ AddSubDecl(SubDecl);
+ }
+}
+
+void ODRHash::AddDecl(const Decl *D) {
+ assert(D && "Expecting non-null pointer.");
+ auto Result = DeclMap.insert(std::make_pair(D, DeclMap.size()));
+ ID.AddInteger(Result.first->second);
+ // On first encounter of a Decl pointer, process it. Every time afterwards,
+ // only the index value is needed.
+ if (!Result.second) {
+ return;
+ }
+
+ ID.AddInteger(D->getKind());
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ AddDeclarationName(ND->getDeclName());
+ }
+}
+
+// Process a Type pointer. Add* methods call back into ODRHash while Visit*
+// methods process the relevant parts of the Type.
+class ODRTypeVisitor : public TypeVisitor<ODRTypeVisitor> {
+ typedef TypeVisitor<ODRTypeVisitor> Inherited;
+ llvm::FoldingSetNodeID &ID;
+ ODRHash &Hash;
+
+public:
+ ODRTypeVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash)
+ : ID(ID), Hash(Hash) {}
+
+ void AddStmt(Stmt *S) {
+ Hash.AddBoolean(S);
+ if (S) {
+ Hash.AddStmt(S);
+ }
+ }
+
+ void AddDecl(Decl *D) {
+ Hash.AddBoolean(D);
+ if (D) {
+ Hash.AddDecl(D);
+ }
+ }
+
+ void AddQualType(QualType T) {
+ Hash.AddQualType(T);
+ }
+
+ void AddType(const Type *T) {
+ Hash.AddBoolean(T);
+ if (T) {
+ Hash.AddType(T);
+ }
+ }
+
+ void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
+ Hash.AddBoolean(NNS);
+ if (NNS) {
+ Hash.AddNestedNameSpecifier(NNS);
+ }
+ }
+
+ void AddIdentifierInfo(const IdentifierInfo *II) {
+ Hash.AddBoolean(II);
+ if (II) {
+ Hash.AddIdentifierInfo(II);
+ }
+ }
+
+ void VisitQualifiers(Qualifiers Quals) {
+ ID.AddInteger(Quals.getAsOpaqueValue());
+ }
+
+ void Visit(const Type *T) {
+ ID.AddInteger(T->getTypeClass());
+ Inherited::Visit(T);
+ }
+
+ void VisitType(const Type *T) {}
+
+ void VisitAdjustedType(const AdjustedType *T) {
+ AddQualType(T->getOriginalType());
+ AddQualType(T->getAdjustedType());
+ VisitType(T);
+ }
+
+ void VisitDecayedType(const DecayedType *T) {
+ AddQualType(T->getDecayedType());
+ AddQualType(T->getPointeeType());
+ VisitAdjustedType(T);
+ }
+
+ void VisitArrayType(const ArrayType *T) {
+ AddQualType(T->getElementType());
+ ID.AddInteger(T->getSizeModifier());
+ VisitQualifiers(T->getIndexTypeQualifiers());
+ VisitType(T);
+ }
+ void VisitConstantArrayType(const ConstantArrayType *T) {
+ T->getSize().Profile(ID);
+ VisitArrayType(T);
+ }
+
+ void VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
+ AddStmt(T->getSizeExpr());
+ VisitArrayType(T);
+ }
+
+ void VisitIncompleteArrayType(const IncompleteArrayType *T) {
+ VisitArrayType(T);
+ }
+
+ void VisitVariableArrayType(const VariableArrayType *T) {
+ AddStmt(T->getSizeExpr());
+ VisitArrayType(T);
+ }
+
+ void VisitBuiltinType(const BuiltinType *T) {
+ ID.AddInteger(T->getKind());
+ VisitType(T);
+ }
+
+ void VisitFunctionType(const FunctionType *T) {
+ AddQualType(T->getReturnType());
+ T->getExtInfo().Profile(ID);
+ Hash.AddBoolean(T->isConst());
+ Hash.AddBoolean(T->isVolatile());
+ Hash.AddBoolean(T->isRestrict());
+ VisitType(T);
+ }
+
+ void VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
+ VisitFunctionType(T);
+ }
+
+ void VisitFunctionProtoType(const FunctionProtoType *T) {
+ ID.AddInteger(T->getNumParams());
+ for (auto ParamType : T->getParamTypes())
+ AddQualType(ParamType);
+
+ VisitFunctionType(T);
+ }
+
+ void VisitTypedefType(const TypedefType *T) {
+ AddDecl(T->getDecl());
+ QualType UnderlyingType = T->getDecl()->getUnderlyingType();
+ VisitQualifiers(UnderlyingType.getQualifiers());
+ while (const TypedefType *Underlying =
+ dyn_cast<TypedefType>(UnderlyingType.getTypePtr())) {
+ UnderlyingType = Underlying->getDecl()->getUnderlyingType();
+ }
+ AddType(UnderlyingType.getTypePtr());
+ VisitType(T);
+ }
+
+ void VisitTagType(const TagType *T) {
+ AddDecl(T->getDecl());
+ VisitType(T);
+ }
+
+ void VisitRecordType(const RecordType *T) { VisitTagType(T); }
+ void VisitEnumType(const EnumType *T) { VisitTagType(T); }
+
+ void VisitTypeWithKeyword(const TypeWithKeyword *T) {
+ ID.AddInteger(T->getKeyword());
+ VisitType(T);
+ };
+
+ void VisitDependentNameType(const DependentNameType *T) {
+ AddNestedNameSpecifier(T->getQualifier());
+ AddIdentifierInfo(T->getIdentifier());
+ VisitTypeWithKeyword(T);
+ }
+
+ void VisitDependentTemplateSpecializationType(
+ const DependentTemplateSpecializationType *T) {
+ AddIdentifierInfo(T->getIdentifier());
+ AddNestedNameSpecifier(T->getQualifier());
+ ID.AddInteger(T->getNumArgs());
+ for (const auto &TA : T->template_arguments()) {
+ Hash.AddTemplateArgument(TA);
+ }
+ VisitTypeWithKeyword(T);
+ }
+
+ void VisitElaboratedType(const ElaboratedType *T) {
+ AddNestedNameSpecifier(T->getQualifier());
+ AddQualType(T->getNamedType());
+ VisitTypeWithKeyword(T);
+ }
+
+ void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
+ ID.AddInteger(T->getNumArgs());
+ for (const auto &TA : T->template_arguments()) {
+ Hash.AddTemplateArgument(TA);
+ }
+ Hash.AddTemplateName(T->getTemplateName());
+ VisitType(T);
+ }
+
+ void VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
+ ID.AddInteger(T->getDepth());
+ ID.AddInteger(T->getIndex());
+ Hash.AddBoolean(T->isParameterPack());
+ AddDecl(T->getDecl());
+ }
+};
+
+void ODRHash::AddType(const Type *T) {
+ assert(T && "Expecting non-null pointer.");
+ auto Result = TypeMap.insert(std::make_pair(T, TypeMap.size()));
+ ID.AddInteger(Result.first->second);
+ // On first encounter of a Type pointer, process it. Every time afterwards,
+ // only the index value is needed.
+ if (!Result.second) {
+ return;
+ }
+
+ ODRTypeVisitor(ID, *this).Visit(T);
+}
+
+void ODRHash::AddQualType(QualType T) {
+ AddBoolean(T.isNull());
+ if (T.isNull())
+ return;
+ SplitQualType split = T.split();
+ ID.AddInteger(split.Quals.getAsOpaqueValue());
+ AddType(split.Ty);
+}
+
+void ODRHash::AddBoolean(bool Value) {
+ Bools.push_back(Value);
+}
diff --git a/contrib/llvm/tools/clang/lib/AST/OpenMPClause.cpp b/contrib/llvm/tools/clang/lib/AST/OpenMPClause.cpp
index a28b9f3..2c4d159 100644
--- a/contrib/llvm/tools/clang/lib/AST/OpenMPClause.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/OpenMPClause.cpp
@@ -46,13 +46,21 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
return static_cast<const OMPLastprivateClause *>(C);
case OMPC_reduction:
return static_cast<const OMPReductionClause *>(C);
+ case OMPC_task_reduction:
+ return static_cast<const OMPTaskReductionClause *>(C);
case OMPC_linear:
return static_cast<const OMPLinearClause *>(C);
+ case OMPC_if:
+ return static_cast<const OMPIfClause *>(C);
+ case OMPC_num_threads:
+ return static_cast<const OMPNumThreadsClause *>(C);
+ case OMPC_num_teams:
+ return static_cast<const OMPNumTeamsClause *>(C);
+ case OMPC_thread_limit:
+ return static_cast<const OMPThreadLimitClause *>(C);
case OMPC_default:
case OMPC_proc_bind:
- case OMPC_if:
case OMPC_final:
- case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
@@ -77,8 +85,6 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
- case OMPC_num_teams:
- case OMPC_thread_limit:
case OMPC_priority:
case OMPC_grainsize:
case OMPC_nogroup:
@@ -108,6 +114,8 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
return static_cast<const OMPLastprivateClause *>(C);
case OMPC_reduction:
return static_cast<const OMPReductionClause *>(C);
+ case OMPC_task_reduction:
+ return static_cast<const OMPTaskReductionClause *>(C);
case OMPC_linear:
return static_cast<const OMPLinearClause *>(C);
case OMPC_schedule:
@@ -501,6 +509,59 @@ OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPReductionClause(N);
}
+void OMPTaskReductionClause::setPrivates(ArrayRef<Expr *> Privates) {
+ assert(Privates.size() == varlist_size() &&
+ "Number of private copies is not the same as the preallocated buffer");
+ std::copy(Privates.begin(), Privates.end(), varlist_end());
+}
+
+void OMPTaskReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) {
+ assert(
+ LHSExprs.size() == varlist_size() &&
+ "Number of LHS expressions is not the same as the preallocated buffer");
+ std::copy(LHSExprs.begin(), LHSExprs.end(), getPrivates().end());
+}
+
+void OMPTaskReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) {
+ assert(
+ RHSExprs.size() == varlist_size() &&
+ "Number of RHS expressions is not the same as the preallocated buffer");
+ std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end());
+}
+
+void OMPTaskReductionClause::setReductionOps(ArrayRef<Expr *> ReductionOps) {
+ assert(ReductionOps.size() == varlist_size() && "Number of task reduction "
+ "expressions is not the same "
+ "as the preallocated buffer");
+ std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end());
+}
+
+OMPTaskReductionClause *OMPTaskReductionClause::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
+ NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
+ ArrayRef<Expr *> Privates, ArrayRef<Expr *> LHSExprs,
+ ArrayRef<Expr *> RHSExprs, ArrayRef<Expr *> ReductionOps, Stmt *PreInit,
+ Expr *PostUpdate) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size()));
+ OMPTaskReductionClause *Clause = new (Mem) OMPTaskReductionClause(
+ StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
+ Clause->setVarRefs(VL);
+ Clause->setPrivates(Privates);
+ Clause->setLHSExprs(LHSExprs);
+ Clause->setRHSExprs(RHSExprs);
+ Clause->setReductionOps(ReductionOps);
+ Clause->setPreInitStmt(PreInit);
+ Clause->setPostUpdateExpr(PostUpdate);
+ return Clause;
+}
+
+OMPTaskReductionClause *OMPTaskReductionClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * N));
+ return new (Mem) OMPTaskReductionClause(N);
+}
+
OMPFlushClause *OMPFlushClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
diff --git a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp
index cf981be..c0b9cad 100644
--- a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -3073,6 +3073,41 @@ uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const {
return OffsetInBits;
}
+uint64_t ASTContext::lookupFieldBitOffset(const ObjCInterfaceDecl *OID,
+ const ObjCImplementationDecl *ID,
+ const ObjCIvarDecl *Ivar) const {
+ const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
+
+ // FIXME: We should eliminate the need to have ObjCImplementationDecl passed
+ // in here; it should never be necessary because that should be the lexical
+ // decl context for the ivar.
+
+ // If we know have an implementation (and the ivar is in it) then
+ // look up in the implementation layout.
+ const ASTRecordLayout *RL;
+ if (ID && declaresSameEntity(ID->getClassInterface(), Container))
+ RL = &getASTObjCImplementationLayout(ID);
+ else
+ RL = &getASTObjCInterfaceLayout(Container);
+
+ // Compute field index.
+ //
+ // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is
+ // implemented. This should be fixed to get the information from the layout
+ // directly.
+ unsigned Index = 0;
+
+ for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar()) {
+ if (Ivar == IVD)
+ break;
+ ++Index;
+ }
+ assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!");
+
+ return RL->getFieldOffset(Index);
+}
+
/// getObjCLayout - Get or compute information about the layout of the
/// given interface.
///
diff --git a/contrib/llvm/tools/clang/lib/AST/Stmt.cpp b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp
index 697cdc3..2367cad 100644
--- a/contrib/llvm/tools/clang/lib/AST/Stmt.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp
@@ -1083,7 +1083,7 @@ CapturedStmt *CapturedStmt::CreateDeserialized(const ASTContext &Context,
}
Stmt::child_range CapturedStmt::children() {
- // Children are captured field initilizers.
+ // Children are captured field initializers.
return child_range(getStoredStmts(), getStoredStmts() + NumCaptures);
}
@@ -1112,7 +1112,7 @@ void CapturedStmt::setCapturedRegionKind(CapturedRegionKind Kind) {
bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
for (const auto &I : captures()) {
- if (!I.capturesVariable())
+ if (!I.capturesVariable() && !I.capturesVariableByCopy())
continue;
// This does not handle variable redeclarations. This should be
diff --git a/contrib/llvm/tools/clang/lib/AST/StmtCXX.cpp b/contrib/llvm/tools/clang/lib/AST/StmtCXX.cpp
index 4a04fc2..666f5dc 100644
--- a/contrib/llvm/tools/clang/lib/AST/StmtCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/StmtCXX.cpp
@@ -86,3 +86,46 @@ VarDecl *CXXForRangeStmt::getLoopVariable() {
const VarDecl *CXXForRangeStmt::getLoopVariable() const {
return const_cast<CXXForRangeStmt *>(this)->getLoopVariable();
}
+
+CoroutineBodyStmt *CoroutineBodyStmt::Create(
+ const ASTContext &C, CoroutineBodyStmt::CtorArgs const &Args) {
+ std::size_t Size = totalSizeToAlloc<Stmt *>(
+ CoroutineBodyStmt::FirstParamMove + Args.ParamMoves.size());
+
+ void *Mem = C.Allocate(Size, alignof(CoroutineBodyStmt));
+ return new (Mem) CoroutineBodyStmt(Args);
+}
+
+CoroutineBodyStmt *CoroutineBodyStmt::Create(const ASTContext &C, EmptyShell,
+ unsigned NumParams) {
+ std::size_t Size = totalSizeToAlloc<Stmt *>(
+ CoroutineBodyStmt::FirstParamMove + NumParams);
+
+ void *Mem = C.Allocate(Size, alignof(CoroutineBodyStmt));
+ auto *Result = new (Mem) CoroutineBodyStmt(CtorArgs());
+ Result->NumParams = NumParams;
+ auto *ParamBegin = Result->getStoredStmts() + SubStmt::FirstParamMove;
+ std::uninitialized_fill(ParamBegin, ParamBegin + NumParams,
+ static_cast<Stmt *>(nullptr));
+ return Result;
+}
+
+CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
+ : Stmt(CoroutineBodyStmtClass), NumParams(Args.ParamMoves.size()) {
+ Stmt **SubStmts = getStoredStmts();
+ SubStmts[CoroutineBodyStmt::Body] = Args.Body;
+ SubStmts[CoroutineBodyStmt::Promise] = Args.Promise;
+ SubStmts[CoroutineBodyStmt::InitSuspend] = Args.InitialSuspend;
+ SubStmts[CoroutineBodyStmt::FinalSuspend] = Args.FinalSuspend;
+ SubStmts[CoroutineBodyStmt::OnException] = Args.OnException;
+ SubStmts[CoroutineBodyStmt::OnFallthrough] = Args.OnFallthrough;
+ SubStmts[CoroutineBodyStmt::Allocate] = Args.Allocate;
+ SubStmts[CoroutineBodyStmt::Deallocate] = Args.Deallocate;
+ SubStmts[CoroutineBodyStmt::ReturnValue] = Args.ReturnValue;
+ SubStmts[CoroutineBodyStmt::ResultDecl] = Args.ResultDecl;
+ SubStmts[CoroutineBodyStmt::ReturnStmt] = Args.ReturnStmt;
+ SubStmts[CoroutineBodyStmt::ReturnStmtOnAllocFailure] =
+ Args.ReturnStmtOnAllocFailure;
+ std::copy(Args.ParamMoves.begin(), Args.ParamMoves.end(),
+ const_cast<Stmt **>(getParamMoves().data()));
+}
diff --git a/contrib/llvm/tools/clang/lib/AST/StmtOpenMP.cpp b/contrib/llvm/tools/clang/lib/AST/StmtOpenMP.cpp
index 880817a..1dcb4fd 100644
--- a/contrib/llvm/tools/clang/lib/AST/StmtOpenMP.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/StmtOpenMP.cpp
@@ -147,8 +147,6 @@ OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -199,8 +197,6 @@ OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -364,8 +360,6 @@ OMPParallelForDirective *OMPParallelForDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -415,8 +409,6 @@ OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -530,23 +522,28 @@ OMPTaskwaitDirective *OMPTaskwaitDirective::CreateEmpty(const ASTContext &C,
return new (Mem) OMPTaskwaitDirective();
}
-OMPTaskgroupDirective *OMPTaskgroupDirective::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation EndLoc,
- Stmt *AssociatedStmt) {
- unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective), alignof(Stmt *));
+OMPTaskgroupDirective *OMPTaskgroupDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective) +
+ sizeof(OMPClause *) * Clauses.size(),
+ alignof(Stmt *));
void *Mem = C.Allocate(Size + sizeof(Stmt *));
OMPTaskgroupDirective *Dir =
- new (Mem) OMPTaskgroupDirective(StartLoc, EndLoc);
+ new (Mem) OMPTaskgroupDirective(StartLoc, EndLoc, Clauses.size());
Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setClauses(Clauses);
return Dir;
}
OMPTaskgroupDirective *OMPTaskgroupDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
EmptyShell) {
- unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective), alignof(Stmt *));
+ unsigned Size = llvm::alignTo(sizeof(OMPTaskgroupDirective) +
+ sizeof(OMPClause *) * NumClauses,
+ alignof(Stmt *));
void *Mem = C.Allocate(Size + sizeof(Stmt *));
- return new (Mem) OMPTaskgroupDirective();
+ return new (Mem) OMPTaskgroupDirective(NumClauses);
}
OMPCancellationPointDirective *OMPCancellationPointDirective::Create(
@@ -751,8 +748,6 @@ OMPTargetParallelForDirective *OMPTargetParallelForDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -894,8 +889,6 @@ OMPTaskLoopDirective *OMPTaskLoopDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -945,8 +938,6 @@ OMPTaskLoopSimdDirective *OMPTaskLoopSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -995,8 +986,6 @@ OMPDistributeDirective *OMPDistributeDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1071,12 +1060,21 @@ OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create(
Dir->setNumIterations(Exprs.NumIterations);
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
+ Dir->setDistInc(Exprs.DistInc);
+ Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1127,12 +1125,21 @@ OMPDistributeParallelForSimdDirective::Create(
Dir->setNumIterations(Exprs.NumIterations);
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
+ Dir->setDistInc(Exprs.DistInc);
+ Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1180,8 +1187,6 @@ OMPDistributeSimdDirective *OMPDistributeSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1234,8 +1239,6 @@ OMPTargetParallelForSimdDirective *OMPTargetParallelForSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1328,8 +1331,6 @@ OMPTeamsDistributeDirective *OMPTeamsDistributeDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1381,8 +1382,6 @@ OMPTeamsDistributeSimdDirective *OMPTeamsDistributeSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1438,12 +1437,21 @@ OMPTeamsDistributeParallelForSimdDirective::Create(
Dir->setNumIterations(Exprs.NumIterations);
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
+ Dir->setDistInc(Exprs.DistInc);
+ Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1496,12 +1504,21 @@ OMPTeamsDistributeParallelForDirective::Create(
Dir->setNumIterations(Exprs.NumIterations);
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
+ Dir->setDistInc(Exprs.DistInc);
+ Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1574,8 +1591,6 @@ OMPTargetTeamsDistributeDirective *OMPTargetTeamsDistributeDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
@@ -1634,12 +1649,21 @@ OMPTargetTeamsDistributeParallelForDirective::Create(
Dir->setNumIterations(Exprs.NumIterations);
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
+ Dir->setDistInc(Exprs.DistInc);
+ Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1695,12 +1719,21 @@ OMPTargetTeamsDistributeParallelForSimdDirective::Create(
Dir->setNumIterations(Exprs.NumIterations);
Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
+ Dir->setDistInc(Exprs.DistInc);
+ Dir->setPrevEnsureUpperBound(Exprs.PrevEUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
Dir->setPreInits(Exprs.PreInits);
+ Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
+ Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
+ Dir->setCombinedEnsureUpperBound(Exprs.DistCombinedFields.EUB);
+ Dir->setCombinedInit(Exprs.DistCombinedFields.Init);
+ Dir->setCombinedCond(Exprs.DistCombinedFields.Cond);
+ Dir->setCombinedNextLowerBound(Exprs.DistCombinedFields.NLB);
+ Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
return Dir;
}
@@ -1751,8 +1784,6 @@ OMPTargetTeamsDistributeSimdDirective::Create(
Dir->setNextLowerBound(Exprs.NLB);
Dir->setNextUpperBound(Exprs.NUB);
Dir->setNumIterations(Exprs.NumIterations);
- Dir->setPrevLowerBoundVariable(Exprs.PrevLB);
- Dir->setPrevUpperBoundVariable(Exprs.PrevUB);
Dir->setCounters(Exprs.Counters);
Dir->setPrivateCounters(Exprs.PrivateCounters);
Dir->setInits(Exprs.Inits);
diff --git a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp
index 1ba1aa4..5ebaa32 100644
--- a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp
@@ -836,6 +836,29 @@ void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPTaskReductionClause(
+ OMPTaskReductionClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "task_reduction(";
+ NestedNameSpecifier *QualifierLoc =
+ Node->getQualifierLoc().getNestedNameSpecifier();
+ OverloadedOperatorKind OOK =
+ Node->getNameInfo().getName().getCXXOverloadedOperator();
+ if (QualifierLoc == nullptr && OOK != OO_None) {
+ // Print reduction identifier in C format
+ OS << getOperatorSpelling(OOK);
+ } else {
+ // Use C++ format
+ if (QualifierLoc != nullptr)
+ QualifierLoc->print(OS, Policy);
+ OS << Node->getNameInfo();
+ }
+ OS << ":";
+ VisitOMPClauseList(Node, ' ');
+ OS << ")";
+ }
+}
+
void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) {
if (!Node->varlist_empty()) {
OS << "linear";
@@ -1081,7 +1104,7 @@ void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) {
}
void StmtPrinter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *Node) {
- Indent() << "#pragma omp taskgroup";
+ Indent() << "#pragma omp taskgroup ";
PrintOMPExecutableDirective(Node);
}
@@ -2475,6 +2498,13 @@ void StmtPrinter::VisitCoawaitExpr(CoawaitExpr *S) {
PrintExpr(S->getOperand());
}
+
+void StmtPrinter::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) {
+ OS << "co_await ";
+ PrintExpr(S->getOperand());
+}
+
+
void StmtPrinter::VisitCoyieldExpr(CoyieldExpr *S) {
OS << "co_yield ";
PrintExpr(S->getOperand());
diff --git a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp
index bcd2e96..7ec0d1d 100644
--- a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp
@@ -19,20 +19,22 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
+#include "clang/AST/ODRHash.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/ADT/FoldingSet.h"
using namespace clang;
namespace {
class StmtProfiler : public ConstStmtVisitor<StmtProfiler> {
+ protected:
llvm::FoldingSetNodeID &ID;
- const ASTContext &Context;
bool Canonical;
public:
- StmtProfiler(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- bool Canonical)
- : ID(ID), Context(Context), Canonical(Canonical) { }
+ StmtProfiler(llvm::FoldingSetNodeID &ID, bool Canonical)
+ : ID(ID), Canonical(Canonical) {}
+
+ virtual ~StmtProfiler() {}
void VisitStmt(const Stmt *S);
@@ -41,22 +43,25 @@ namespace {
/// \brief Visit a declaration that is referenced within an expression
/// or statement.
- void VisitDecl(const Decl *D);
+ virtual void VisitDecl(const Decl *D) = 0;
/// \brief Visit a type that is referenced within an expression or
/// statement.
- void VisitType(QualType T);
+ virtual void VisitType(QualType T) = 0;
/// \brief Visit a name that occurs within an expression or statement.
- void VisitName(DeclarationName Name);
+ virtual void VisitName(DeclarationName Name) = 0;
+
+ /// \brief Visit identifiers that are not in Decl's or Type's.
+ virtual void VisitIdentifierInfo(IdentifierInfo *II) = 0;
/// \brief Visit a nested-name-specifier that occurs within an expression
/// or statement.
- void VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
+ virtual void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) = 0;
/// \brief Visit a template name that occurs within an expression or
/// statement.
- void VisitTemplateName(TemplateName Name);
+ virtual void VisitTemplateName(TemplateName Name) = 0;
/// \brief Visit template arguments that occur within an expression or
/// statement.
@@ -66,6 +71,127 @@ namespace {
/// \brief Visit a single template argument.
void VisitTemplateArgument(const TemplateArgument &Arg);
};
+
+ class StmtProfilerWithPointers : public StmtProfiler {
+ const ASTContext &Context;
+
+ public:
+ StmtProfilerWithPointers(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Context, bool Canonical)
+ : StmtProfiler(ID, Canonical), Context(Context) {}
+ private:
+ void VisitDecl(const Decl *D) override {
+ ID.AddInteger(D ? D->getKind() : 0);
+
+ if (Canonical && D) {
+ if (const NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ ID.AddInteger(NTTP->getDepth());
+ ID.AddInteger(NTTP->getIndex());
+ ID.AddBoolean(NTTP->isParameterPack());
+ VisitType(NTTP->getType());
+ return;
+ }
+
+ if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
+ // The Itanium C++ ABI uses the type, scope depth, and scope
+ // index of a parameter when mangling expressions that involve
+ // function parameters, so we will use the parameter's type for
+ // establishing function parameter identity. That way, our
+ // definition of "equivalent" (per C++ [temp.over.link]) is at
+ // least as strong as the definition of "equivalent" used for
+ // name mangling.
+ VisitType(Parm->getType());
+ ID.AddInteger(Parm->getFunctionScopeDepth());
+ ID.AddInteger(Parm->getFunctionScopeIndex());
+ return;
+ }
+
+ if (const TemplateTypeParmDecl *TTP =
+ dyn_cast<TemplateTypeParmDecl>(D)) {
+ ID.AddInteger(TTP->getDepth());
+ ID.AddInteger(TTP->getIndex());
+ ID.AddBoolean(TTP->isParameterPack());
+ return;
+ }
+
+ if (const TemplateTemplateParmDecl *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(D)) {
+ ID.AddInteger(TTP->getDepth());
+ ID.AddInteger(TTP->getIndex());
+ ID.AddBoolean(TTP->isParameterPack());
+ return;
+ }
+ }
+
+ ID.AddPointer(D ? D->getCanonicalDecl() : nullptr);
+ }
+
+ void VisitType(QualType T) override {
+ if (Canonical && !T.isNull())
+ T = Context.getCanonicalType(T);
+
+ ID.AddPointer(T.getAsOpaquePtr());
+ }
+
+ void VisitName(DeclarationName Name) override {
+ ID.AddPointer(Name.getAsOpaquePtr());
+ }
+
+ void VisitIdentifierInfo(IdentifierInfo *II) override {
+ ID.AddPointer(II);
+ }
+
+ void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override {
+ if (Canonical)
+ NNS = Context.getCanonicalNestedNameSpecifier(NNS);
+ ID.AddPointer(NNS);
+ }
+
+ void VisitTemplateName(TemplateName Name) override {
+ if (Canonical)
+ Name = Context.getCanonicalTemplateName(Name);
+
+ Name.Profile(ID);
+ }
+ };
+
+ class StmtProfilerWithoutPointers : public StmtProfiler {
+ ODRHash &Hash;
+ public:
+ StmtProfilerWithoutPointers(llvm::FoldingSetNodeID &ID, ODRHash &Hash)
+ : StmtProfiler(ID, false), Hash(Hash) {}
+
+ private:
+ void VisitType(QualType T) override {
+ Hash.AddQualType(T);
+ }
+
+ void VisitName(DeclarationName Name) override {
+ Hash.AddDeclarationName(Name);
+ }
+ void VisitIdentifierInfo(IdentifierInfo *II) override {
+ ID.AddBoolean(II);
+ if (II) {
+ Hash.AddIdentifierInfo(II);
+ }
+ }
+ void VisitDecl(const Decl *D) override {
+ ID.AddBoolean(D);
+ if (D) {
+ Hash.AddDecl(D);
+ }
+ }
+ void VisitTemplateName(TemplateName Name) override {
+ Hash.AddTemplateName(Name);
+ }
+ void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override {
+ ID.AddBoolean(NNS);
+ if (NNS) {
+ Hash.AddNestedNameSpecifier(NNS);
+ }
+ }
+ };
}
void StmtProfiler::VisitStmt(const Stmt *S) {
@@ -283,6 +409,7 @@ void OMPClauseProfiler::VistOMPClauseWithPostUpdate(
}
void OMPClauseProfiler::VisitOMPIfClause(const OMPIfClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getCondition())
Profiler->VisitStmt(C->getCondition());
}
@@ -293,6 +420,7 @@ void OMPClauseProfiler::VisitOMPFinalClause(const OMPFinalClause *C) {
}
void OMPClauseProfiler::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getNumThreads())
Profiler->VisitStmt(C->getNumThreads());
}
@@ -421,6 +549,30 @@ void OMPClauseProfiler::VisitOMPReductionClause(
Profiler->VisitStmt(E);
}
}
+void OMPClauseProfiler::VisitOMPTaskReductionClause(
+ const OMPTaskReductionClause *C) {
+ Profiler->VisitNestedNameSpecifier(
+ C->getQualifierLoc().getNestedNameSpecifier());
+ Profiler->VisitName(C->getNameInfo().getName());
+ VisitOMPClauseList(C);
+ VistOMPClauseWithPostUpdate(C);
+ for (auto *E : C->privates()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->lhs_exprs()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->rhs_exprs()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->reduction_ops()) {
+ if (E)
+ Profiler->VisitStmt(E);
+ }
+}
void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
VisitOMPClauseList(C);
VistOMPClauseWithPostUpdate(C);
@@ -495,11 +647,13 @@ void OMPClauseProfiler::VisitOMPMapClause(const OMPMapClause *C) {
VisitOMPClauseList(C);
}
void OMPClauseProfiler::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getNumTeams())
Profiler->VisitStmt(C->getNumTeams());
}
void OMPClauseProfiler::VisitOMPThreadLimitClause(
const OMPThreadLimitClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getThreadLimit())
Profiler->VisitStmt(C->getThreadLimit());
}
@@ -849,7 +1003,7 @@ void StmtProfiler::VisitOffsetOfExpr(const OffsetOfExpr *S) {
break;
case OffsetOfNode::Identifier:
- ID.AddPointer(ON.getFieldName());
+ VisitIdentifierInfo(ON.getFieldName());
break;
case OffsetOfNode::Base:
@@ -857,7 +1011,7 @@ void StmtProfiler::VisitOffsetOfExpr(const OffsetOfExpr *S) {
break;
}
}
-
+
VisitExpr(S);
}
@@ -1234,6 +1388,15 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
llvm_unreachable("Invalid overloaded operator expression");
}
+#if defined(_MSC_VER)
+#if _MSC_VER == 1911
+// Work around https://developercommunity.visualstudio.com/content/problem/84002/clang-cl-when-built-with-vc-2017-crashes-cause-vc.html
+// MSVC 2017 update 3 miscompiles this function, and a clang built with it
+// will crash in stage 2 of a bootstrap build.
+#pragma optimize("", off)
+#endif
+#endif
+
void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
if (S->isTypeDependent()) {
// Type-dependent operator calls are profiled like their underlying
@@ -1266,6 +1429,12 @@ void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
ID.AddInteger(S->getOperator());
}
+#if defined(_MSC_VER)
+#if _MSC_VER == 1911
+#pragma optimize("", on)
+#endif
+#endif
+
void StmtProfiler::VisitCXXMemberCallExpr(const CXXMemberCallExpr *S) {
VisitCallExpr(S);
}
@@ -1447,7 +1616,7 @@ StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {
if (S->getDestroyedTypeInfo())
VisitType(S->getDestroyedType());
else
- ID.AddPointer(S->getDestroyedTypeIdentifier());
+ VisitIdentifierInfo(S->getDestroyedTypeIdentifier());
}
void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) {
@@ -1595,6 +1764,10 @@ void StmtProfiler::VisitCoawaitExpr(const CoawaitExpr *S) {
VisitExpr(S);
}
+void StmtProfiler::VisitDependentCoawaitExpr(const DependentCoawaitExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCoyieldExpr(const CoyieldExpr *S) {
VisitExpr(S);
}
@@ -1697,77 +1870,6 @@ void StmtProfiler::VisitObjCAvailabilityCheckExpr(
VisitExpr(S);
}
-void StmtProfiler::VisitDecl(const Decl *D) {
- ID.AddInteger(D? D->getKind() : 0);
-
- if (Canonical && D) {
- if (const NonTypeTemplateParmDecl *NTTP =
- dyn_cast<NonTypeTemplateParmDecl>(D)) {
- ID.AddInteger(NTTP->getDepth());
- ID.AddInteger(NTTP->getIndex());
- ID.AddBoolean(NTTP->isParameterPack());
- VisitType(NTTP->getType());
- return;
- }
-
- if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
- // The Itanium C++ ABI uses the type, scope depth, and scope
- // index of a parameter when mangling expressions that involve
- // function parameters, so we will use the parameter's type for
- // establishing function parameter identity. That way, our
- // definition of "equivalent" (per C++ [temp.over.link]) is at
- // least as strong as the definition of "equivalent" used for
- // name mangling.
- VisitType(Parm->getType());
- ID.AddInteger(Parm->getFunctionScopeDepth());
- ID.AddInteger(Parm->getFunctionScopeIndex());
- return;
- }
-
- if (const TemplateTypeParmDecl *TTP =
- dyn_cast<TemplateTypeParmDecl>(D)) {
- ID.AddInteger(TTP->getDepth());
- ID.AddInteger(TTP->getIndex());
- ID.AddBoolean(TTP->isParameterPack());
- return;
- }
-
- if (const TemplateTemplateParmDecl *TTP =
- dyn_cast<TemplateTemplateParmDecl>(D)) {
- ID.AddInteger(TTP->getDepth());
- ID.AddInteger(TTP->getIndex());
- ID.AddBoolean(TTP->isParameterPack());
- return;
- }
- }
-
- ID.AddPointer(D? D->getCanonicalDecl() : nullptr);
-}
-
-void StmtProfiler::VisitType(QualType T) {
- if (Canonical)
- T = Context.getCanonicalType(T);
-
- ID.AddPointer(T.getAsOpaquePtr());
-}
-
-void StmtProfiler::VisitName(DeclarationName Name) {
- ID.AddPointer(Name.getAsOpaquePtr());
-}
-
-void StmtProfiler::VisitNestedNameSpecifier(NestedNameSpecifier *NNS) {
- if (Canonical)
- NNS = Context.getCanonicalNestedNameSpecifier(NNS);
- ID.AddPointer(NNS);
-}
-
-void StmtProfiler::VisitTemplateName(TemplateName Name) {
- if (Canonical)
- Name = Context.getCanonicalTemplateName(Name);
-
- Name.Profile(ID);
-}
-
void StmtProfiler::VisitTemplateArguments(const TemplateArgumentLoc *Args,
unsigned NumArgs) {
ID.AddInteger(NumArgs);
@@ -1817,6 +1919,12 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
bool Canonical) const {
- StmtProfiler Profiler(ID, Context, Canonical);
+ StmtProfilerWithPointers Profiler(ID, Context, Canonical);
+ Profiler.Visit(this);
+}
+
+void Stmt::ProcessODRHash(llvm::FoldingSetNodeID &ID,
+ class ODRHash &Hash) const {
+ StmtProfilerWithoutPointers Profiler(ID, Hash);
Profiler.Visit(this);
}
diff --git a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp
index 099f939..e4998c3 100644
--- a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp
@@ -453,10 +453,6 @@ LLVM_DUMP_METHOD void TemplateArgument::dump() const { dump(llvm::errs()); }
// TemplateArgumentLoc Implementation
//===----------------------------------------------------------------------===//
-TemplateArgumentLocInfo::TemplateArgumentLocInfo() {
- memset((void*)this, 0, sizeof(TemplateArgumentLocInfo));
-}
-
SourceRange TemplateArgumentLoc::getSourceRange() const {
switch (Argument.getKind()) {
case TemplateArgument::Expression:
diff --git a/contrib/llvm/tools/clang/lib/AST/Type.cpp b/contrib/llvm/tools/clang/lib/AST/Type.cpp
index 0d0cd2e..d21781d 100644
--- a/contrib/llvm/tools/clang/lib/AST/Type.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/Type.cpp
@@ -1344,7 +1344,7 @@ Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
} else if (getAs<BlockPointerType>()) {
ASTContext &ctx = dc->getParentASTContext();
objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, { })
- ->castAs<ObjCObjectType>();;
+ ->castAs<ObjCObjectType>();
} else {
objectType = getAs<ObjCObjectType>();
}
@@ -1559,61 +1559,79 @@ TagDecl *Type::getAsTagDecl() const {
}
namespace {
- class GetContainedAutoVisitor :
- public TypeVisitor<GetContainedAutoVisitor, AutoType*> {
+ class GetContainedDeducedTypeVisitor :
+ public TypeVisitor<GetContainedDeducedTypeVisitor, Type*> {
+ bool Syntactic;
public:
- using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit;
- AutoType *Visit(QualType T) {
+ GetContainedDeducedTypeVisitor(bool Syntactic = false)
+ : Syntactic(Syntactic) {}
+
+ using TypeVisitor<GetContainedDeducedTypeVisitor, Type*>::Visit;
+ Type *Visit(QualType T) {
if (T.isNull())
return nullptr;
return Visit(T.getTypePtr());
}
- // The 'auto' type itself.
- AutoType *VisitAutoType(const AutoType *AT) {
- return const_cast<AutoType*>(AT);
+ // The deduced type itself.
+ Type *VisitDeducedType(const DeducedType *AT) {
+ return const_cast<DeducedType*>(AT);
}
// Only these types can contain the desired 'auto' type.
- AutoType *VisitPointerType(const PointerType *T) {
+ Type *VisitElaboratedType(const ElaboratedType *T) {
+ return Visit(T->getNamedType());
+ }
+ Type *VisitPointerType(const PointerType *T) {
return Visit(T->getPointeeType());
}
- AutoType *VisitBlockPointerType(const BlockPointerType *T) {
+ Type *VisitBlockPointerType(const BlockPointerType *T) {
return Visit(T->getPointeeType());
}
- AutoType *VisitReferenceType(const ReferenceType *T) {
+ Type *VisitReferenceType(const ReferenceType *T) {
return Visit(T->getPointeeTypeAsWritten());
}
- AutoType *VisitMemberPointerType(const MemberPointerType *T) {
+ Type *VisitMemberPointerType(const MemberPointerType *T) {
return Visit(T->getPointeeType());
}
- AutoType *VisitArrayType(const ArrayType *T) {
+ Type *VisitArrayType(const ArrayType *T) {
return Visit(T->getElementType());
}
- AutoType *VisitDependentSizedExtVectorType(
+ Type *VisitDependentSizedExtVectorType(
const DependentSizedExtVectorType *T) {
return Visit(T->getElementType());
}
- AutoType *VisitVectorType(const VectorType *T) {
+ Type *VisitVectorType(const VectorType *T) {
return Visit(T->getElementType());
}
- AutoType *VisitFunctionType(const FunctionType *T) {
+ Type *VisitFunctionProtoType(const FunctionProtoType *T) {
+ if (Syntactic && T->hasTrailingReturn())
+ return const_cast<FunctionProtoType*>(T);
+ return VisitFunctionType(T);
+ }
+ Type *VisitFunctionType(const FunctionType *T) {
return Visit(T->getReturnType());
}
- AutoType *VisitParenType(const ParenType *T) {
+ Type *VisitParenType(const ParenType *T) {
return Visit(T->getInnerType());
}
- AutoType *VisitAttributedType(const AttributedType *T) {
+ Type *VisitAttributedType(const AttributedType *T) {
return Visit(T->getModifiedType());
}
- AutoType *VisitAdjustedType(const AdjustedType *T) {
+ Type *VisitAdjustedType(const AdjustedType *T) {
return Visit(T->getOriginalType());
}
};
}
-AutoType *Type::getContainedAutoType() const {
- return GetContainedAutoVisitor().Visit(this);
+DeducedType *Type::getContainedDeducedType() const {
+ return cast_or_null<DeducedType>(
+ GetContainedDeducedTypeVisitor().Visit(this));
+}
+
+bool Type::hasAutoForTrailingReturnType() const {
+ return dyn_cast_or_null<FunctionType>(
+ GetContainedDeducedTypeVisitor(true).Visit(this));
}
bool Type::hasIntegerRepresentation() const {
@@ -2005,20 +2023,8 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const {
if ((*this)->isIncompleteType())
return false;
- if (Context.getLangOpts().ObjCAutoRefCount) {
- switch (getObjCLifetime()) {
- case Qualifiers::OCL_ExplicitNone:
- return true;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Autoreleasing:
- return false;
-
- case Qualifiers::OCL_None:
- break;
- }
- }
+ if (hasNonTrivialObjCLifetime())
+ return false;
QualType CanonicalType = getTypePtr()->CanonicalType;
switch (CanonicalType->getTypeClass()) {
@@ -2067,22 +2073,8 @@ bool QualType::isTrivialType(const ASTContext &Context) const {
if ((*this)->isIncompleteType())
return false;
- if (Context.getLangOpts().ObjCAutoRefCount) {
- switch (getObjCLifetime()) {
- case Qualifiers::OCL_ExplicitNone:
- return true;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Autoreleasing:
- return false;
-
- case Qualifiers::OCL_None:
- if ((*this)->isObjCLifetimeType())
- return false;
- break;
- }
- }
+ if (hasNonTrivialObjCLifetime())
+ return false;
QualType CanonicalType = getTypePtr()->CanonicalType;
if (CanonicalType->isDependentType())
@@ -2119,35 +2111,18 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
if ((*this)->isArrayType())
return Context.getBaseElementType(*this).isTriviallyCopyableType(Context);
- if (Context.getLangOpts().ObjCAutoRefCount) {
- switch (getObjCLifetime()) {
- case Qualifiers::OCL_ExplicitNone:
- return true;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Autoreleasing:
- return false;
-
- case Qualifiers::OCL_None:
- if ((*this)->isObjCLifetimeType())
- return false;
- break;
- }
- }
+ if (hasNonTrivialObjCLifetime())
+ return false;
- // C++11 [basic.types]p9
+ // C++11 [basic.types]p9 - See Core 2094
// Scalar types, trivially copyable class types, arrays of such types, and
- // non-volatile const-qualified versions of these types are collectively
+ // cv-qualified versions of these types are collectively
// called trivially copyable types.
QualType CanonicalType = getCanonicalType();
if (CanonicalType->isDependentType())
return false;
- if (CanonicalType.isVolatileQualified())
- return false;
-
// Return false for incomplete types after skipping any incomplete array types
// which are expressly allowed by the standard and thus our API.
if (CanonicalType->isIncompleteType())
@@ -2170,7 +2145,11 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
return false;
}
-
+bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const {
+ return !Context.getLangOpts().ObjCAutoRefCount &&
+ Context.getLangOpts().ObjCWeak &&
+ getObjCLifetime() != Qualifiers::OCL_Weak;
+}
bool Type::isLiteralType(const ASTContext &Ctx) const {
if (isDependentType())
@@ -2280,20 +2259,8 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const {
if (ty->isDependentType())
return false;
- if (Context.getLangOpts().ObjCAutoRefCount) {
- switch (getObjCLifetime()) {
- case Qualifiers::OCL_ExplicitNone:
- return true;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Autoreleasing:
- return false;
-
- case Qualifiers::OCL_None:
- break;
- }
- }
+ if (hasNonTrivialObjCLifetime())
+ return false;
// C++11 [basic.types]p9:
// Scalar types, POD classes, arrays of such types, and cv-qualified
@@ -2346,6 +2313,15 @@ bool Type::isAlignValT() const {
return false;
}
+bool Type::isStdByteType() const {
+ if (auto *ET = getAs<EnumType>()) {
+ auto *II = ET->getDecl()->getIdentifier();
+ if (II && II->isStr("byte") && ET->getDecl()->isInStdNamespace())
+ return true;
+ }
+ return false;
+}
+
bool Type::isPromotableIntegerType() const {
if (const BuiltinType *BT = getAs<BuiltinType>())
switch (BT->getKind()) {
@@ -2630,8 +2606,6 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
return "clk_event_t";
case OCLQueue:
return "queue_t";
- case OCLNDRange:
- return "ndrange_t";
case OCLReserveID:
return "reserve_id_t";
case OMPArraySection:
@@ -2665,7 +2639,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_X86ThisCall: return "thiscall";
case CC_X86Pascal: return "pascal";
case CC_X86VectorCall: return "vectorcall";
- case CC_X86_64Win64: return "ms_abi";
+ case CC_Win64: return "ms_abi";
case CC_X86_64SysV: return "sysv_abi";
case CC_X86RegCall : return "regcall";
case CC_AAPCS: return "aapcs";
@@ -3058,6 +3032,7 @@ bool AttributedType::isQualifier() const {
case AttributedType::attr_sptr:
case AttributedType::attr_uptr:
case AttributedType::attr_objc_kindof:
+ case AttributedType::attr_ns_returns_retained:
return false;
}
llvm_unreachable("bad attributed type kind");
@@ -3091,6 +3066,7 @@ bool AttributedType::isCallingConv() const {
case attr_objc_inert_unsafe_unretained:
case attr_noreturn:
case attr_nonnull:
+ case attr_ns_returns_retained:
case attr_nullable:
case attr_null_unspecified:
case attr_objc_kindof:
@@ -3365,6 +3341,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
return CachedProperties(ExternalLinkage, false);
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
// Give non-deduced 'auto' types external linkage. We should only see them
// here in error recovery.
return CachedProperties(ExternalLinkage, false);
@@ -3472,6 +3449,7 @@ static LinkageInfo computeLinkageInfo(const Type *T) {
return LinkageInfo::external();
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
return LinkageInfo::external();
case Type::Record:
@@ -3564,7 +3542,7 @@ Optional<NullabilityKind> Type::getNullability(const ASTContext &context) const
} while (true);
}
-bool Type::canHaveNullability() const {
+bool Type::canHaveNullability(bool ResultIfUnknown) const {
QualType type = getCanonicalTypeInternal();
switch (type->getTypeClass()) {
@@ -3592,7 +3570,8 @@ bool Type::canHaveNullability() const {
case Type::SubstTemplateTypeParmPack:
case Type::DependentName:
case Type::DependentTemplateSpecialization:
- return true;
+ case Type::Auto:
+ return ResultIfUnknown;
// Dependent template specializations can instantiate to pointer
// types unless they're known to be specializations of a class
@@ -3604,11 +3583,7 @@ bool Type::canHaveNullability() const {
if (isa<ClassTemplateDecl>(templateDecl))
return false;
}
- return true;
-
- // auto is considered dependent when it isn't deduced.
- case Type::Auto:
- return !cast<AutoType>(type.getTypePtr())->isDeduced();
+ return ResultIfUnknown;
case Type::Builtin:
switch (cast<BuiltinType>(type.getTypePtr())->getKind()) {
@@ -3627,7 +3602,7 @@ bool Type::canHaveNullability() const {
case BuiltinType::PseudoObject:
case BuiltinType::UnknownAny:
case BuiltinType::ARCUnbridgedCast:
- return true;
+ return ResultIfUnknown;
case BuiltinType::Void:
case BuiltinType::ObjCId:
@@ -3640,13 +3615,13 @@ bool Type::canHaveNullability() const {
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
case BuiltinType::BuiltinFn:
case BuiltinType::NullPtr:
case BuiltinType::OMPArraySection:
return false;
}
+ llvm_unreachable("unknown builtin type");
// Non-pointer types.
case Type::Complex:
@@ -3662,6 +3637,7 @@ bool Type::canHaveNullability() const {
case Type::FunctionProto:
case Type::FunctionNoProto:
case Type::Record:
+ case Type::DeducedTemplateSpecialization:
case Type::Enum:
case Type::InjectedClassName:
case Type::PackExpansion:
diff --git a/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp
index 7242858..c9a2686 100644
--- a/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp
@@ -340,7 +340,6 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
case BuiltinType::BuiltinFn:
case BuiltinType::OMPArraySection:
diff --git a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp
index cccc908..15c63bf 100644
--- a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp
+++ b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp
@@ -96,7 +96,7 @@ namespace {
static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier);
void spaceBeforePlaceHolder(raw_ostream &OS);
- void printTypeSpec(const NamedDecl *D, raw_ostream &OS);
+ void printTypeSpec(NamedDecl *D, raw_ostream &OS);
void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
void printBefore(QualType T, raw_ostream &OS);
@@ -104,6 +104,7 @@ namespace {
void printAfter(QualType T, raw_ostream &OS);
void AppendScope(DeclContext *DC, raw_ostream &OS);
void printTag(TagDecl *T, raw_ostream &OS);
+ void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) \
void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \
@@ -189,6 +190,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::Elaborated:
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
+ case Type::DeducedTemplateSpecialization:
case Type::TemplateSpecialization:
case Type::InjectedClassName:
case Type::DependentName:
@@ -684,6 +686,36 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
FunctionType::ExtInfo Info = T->getExtInfo();
+ printFunctionAfter(Info, OS);
+
+ if (unsigned quals = T->getTypeQuals()) {
+ OS << ' ';
+ AppendTypeQualList(OS, quals, Policy.Restrict);
+ }
+
+ switch (T->getRefQualifier()) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ OS << " &";
+ break;
+
+ case RQ_RValue:
+ OS << " &&";
+ break;
+ }
+ T->printExceptionSpecification(OS, Policy);
+
+ if (T->hasTrailingReturn()) {
+ OS << " -> ";
+ print(T->getReturnType(), OS, StringRef());
+ } else
+ printAfter(T->getReturnType(), OS);
+}
+
+void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
+ raw_ostream &OS) {
if (!InsideCCAttribute) {
switch (Info.getCC()) {
case CC_C:
@@ -719,7 +751,7 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
case CC_IntelOclBicc:
OS << " __attribute__((intel_ocl_bicc))";
break;
- case CC_X86_64Win64:
+ case CC_Win64:
OS << " __attribute__((ms_abi))";
break;
case CC_X86_64SysV:
@@ -746,34 +778,13 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
+ if (Info.getProducesResult())
+ OS << " __attribute__((ns_returns_retained))";
if (Info.getRegParm())
OS << " __attribute__((regparm ("
<< Info.getRegParm() << ")))";
-
- if (unsigned quals = T->getTypeQuals()) {
- OS << ' ';
- AppendTypeQualList(OS, quals, Policy.Restrict);
- }
-
- switch (T->getRefQualifier()) {
- case RQ_None:
- break;
-
- case RQ_LValue:
- OS << " &";
- break;
-
- case RQ_RValue:
- OS << " &&";
- break;
- }
- T->printExceptionSpecification(OS, Policy);
-
- if (T->hasTrailingReturn()) {
- OS << " -> ";
- print(T->getReturnType(), OS, StringRef());
- } else
- printAfter(T->getReturnType(), OS);
+ if (Info.getNoCallerSavedRegs())
+ OS << " __attribute__((no_caller_saved_registers))";
}
void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T,
@@ -792,12 +803,18 @@ void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T,
SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
OS << "()";
- if (T->getNoReturnAttr())
- OS << " __attribute__((noreturn))";
+ printFunctionAfter(T->getExtInfo(), OS);
printAfter(T->getReturnType(), OS);
}
-void TypePrinter::printTypeSpec(const NamedDecl *D, raw_ostream &OS) {
+void TypePrinter::printTypeSpec(NamedDecl *D, raw_ostream &OS) {
+
+ // Compute the full nested-name-specifier for this type.
+ // In C, this will always be empty except when the type
+ // being printed is anonymous within other Record.
+ if (!Policy.SuppressScope)
+ AppendScope(D->getDeclContext(), OS);
+
IdentifierInfo *II = D->getIdentifier();
OS << II->getName();
spaceBeforePlaceHolder(OS);
@@ -888,6 +905,24 @@ void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) {
printAfter(T->getDeducedType(), OS);
}
+void TypePrinter::printDeducedTemplateSpecializationBefore(
+ const DeducedTemplateSpecializationType *T, raw_ostream &OS) {
+ // If the type has been deduced, print the deduced type.
+ if (!T->getDeducedType().isNull()) {
+ printBefore(T->getDeducedType(), OS);
+ } else {
+ IncludeStrongLifetimeRAII Strong(Policy);
+ T->getTemplateName().print(OS, Policy);
+ spaceBeforePlaceHolder(OS);
+ }
+}
+void TypePrinter::printDeducedTemplateSpecializationAfter(
+ const DeducedTemplateSpecializationType *T, raw_ostream &OS) {
+ // If the type has been deduced, print the deduced type.
+ if (!T->getDeducedType().isNull())
+ printAfter(T->getDeducedType(), OS);
+}
+
void TypePrinter::printAtomicBefore(const AtomicType *T, raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
@@ -1242,6 +1277,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
if (T->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained)
return;
+ // Don't print ns_returns_retained unless it had an effect.
+ if (T->getAttrKind() == AttributedType::attr_ns_returns_retained &&
+ !T->getEquivalentType()->castAs<FunctionType>()
+ ->getExtInfo().getProducesResult())
+ return;
+
// Print nullability type specifiers that occur after
if (T->getAttrKind() == AttributedType::attr_nonnull ||
T->getAttrKind() == AttributedType::attr_nullable ||
@@ -1333,6 +1374,10 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << ')';
break;
+ case AttributedType::attr_ns_returns_retained:
+ OS << "ns_returns_retained";
+ break;
+
// FIXME: When Sema learns to form this AttributedType, avoid printing the
// attribute again in printFunctionProtoAfter.
case AttributedType::attr_noreturn: OS << "noreturn"; break;
@@ -1627,14 +1672,22 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
OS << "__local";
break;
case LangAS::opencl_constant:
+ case LangAS::cuda_constant:
OS << "__constant";
break;
case LangAS::opencl_generic:
OS << "__generic";
break;
+ case LangAS::cuda_device:
+ OS << "__device";
+ break;
+ case LangAS::cuda_shared:
+ OS << "__shared";
+ break;
default:
+ assert(addrspace >= LangAS::FirstTargetAddressSpace);
OS << "__attribute__((address_space(";
- OS << addrspace;
+ OS << addrspace - LangAS::FirstTargetAddressSpace;
OS << ")))";
}
}
diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
index 787b780..9cddcf9 100644
--- a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
+++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -118,8 +118,8 @@ static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
return "Malformed bind() expression.";
case Diagnostics::ET_ParserTrailingCode:
return "Expected end of code.";
- case Diagnostics::ET_ParserUnsignedError:
- return "Error parsing unsigned token: <$0>";
+ case Diagnostics::ET_ParserNumberError:
+ return "Error parsing numeric literal: <$0>";
case Diagnostics::ET_ParserOverloadedType:
return "Input value has unresolved overloaded type: $0";
diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h
index fb6b349..c557ff1 100644
--- a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -65,6 +65,26 @@ template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
}
};
+template <> struct ArgTypeTraits<bool> {
+ static bool is(const VariantValue &Value) { return Value.isBoolean(); }
+ static bool get(const VariantValue &Value) {
+ return Value.getBoolean();
+ }
+ static ArgKind getKind() {
+ return ArgKind(ArgKind::AK_Boolean);
+ }
+};
+
+template <> struct ArgTypeTraits<double> {
+ static bool is(const VariantValue &Value) { return Value.isDouble(); }
+ static double get(const VariantValue &Value) {
+ return Value.getDouble();
+ }
+ static ArgKind getKind() {
+ return ArgKind(ArgKind::AK_Double);
+ }
+};
+
template <> struct ArgTypeTraits<unsigned> {
static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
static unsigned get(const VariantValue &Value) {
diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp
index ce8d0a9..f5bd296 100644
--- a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -130,8 +130,8 @@ private:
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- // Parse an unsigned literal.
- consumeUnsignedLiteral(&Result);
+ // Parse an unsigned and float literal.
+ consumeNumberLiteral(&Result);
break;
default:
@@ -153,8 +153,16 @@ private:
break;
++TokenLength;
}
- Result.Kind = TokenInfo::TK_Ident;
- Result.Text = Code.substr(0, TokenLength);
+ if (TokenLength == 4 && Code.startswith("true")) {
+ Result.Kind = TokenInfo::TK_Literal;
+ Result.Value = true;
+ } else if (TokenLength == 5 && Code.startswith("false")) {
+ Result.Kind = TokenInfo::TK_Literal;
+ Result.Value = false;
+ } else {
+ Result.Kind = TokenInfo::TK_Ident;
+ Result.Text = Code.substr(0, TokenLength);
+ }
Code = Code.drop_front(TokenLength);
} else {
Result.Kind = TokenInfo::TK_InvalidChar;
@@ -168,8 +176,9 @@ private:
return Result;
}
- /// \brief Consume an unsigned literal.
- void consumeUnsignedLiteral(TokenInfo *Result) {
+ /// \brief Consume an unsigned and float literal.
+ void consumeNumberLiteral(TokenInfo *Result) {
+ bool isFloatingLiteral = false;
unsigned Length = 1;
if (Code.size() > 1) {
// Consume the 'x' or 'b' radix modifier, if present.
@@ -180,20 +189,44 @@ private:
while (Length < Code.size() && isHexDigit(Code[Length]))
++Length;
+ // Try to recognize a floating point literal.
+ while (Length < Code.size()) {
+ char c = Code[Length];
+ if (c == '-' || c == '+' || c == '.' || isHexDigit(c)) {
+ isFloatingLiteral = true;
+ Length++;
+ } else {
+ break;
+ }
+ }
+
Result->Text = Code.substr(0, Length);
Code = Code.drop_front(Length);
- unsigned Value;
- if (!Result->Text.getAsInteger(0, Value)) {
- Result->Kind = TokenInfo::TK_Literal;
- Result->Value = Value;
+ if (isFloatingLiteral) {
+ char *end;
+ errno = 0;
+ std::string Text = Result->Text.str();
+ double doubleValue = strtod(Text.c_str(), &end);
+ if (*end == 0 && errno == 0) {
+ Result->Kind = TokenInfo::TK_Literal;
+ Result->Value = doubleValue;
+ return;
+ }
} else {
- SourceRange Range;
- Range.Start = Result->Range.Start;
- Range.End = currentLocation();
- Error->addError(Range, Error->ET_ParserUnsignedError) << Result->Text;
- Result->Kind = TokenInfo::TK_Error;
+ unsigned Value;
+ if (!Result->Text.getAsInteger(0, Value)) {
+ Result->Kind = TokenInfo::TK_Literal;
+ Result->Value = Value;
+ return;
+ }
}
+
+ SourceRange Range;
+ Range.Start = Result->Range.Start;
+ Range.End = currentLocation();
+ Error->addError(Range, Error->ET_ParserNumberError) << Result->Text;
+ Result->Kind = TokenInfo::TK_Error;
}
/// \brief Consume a string literal.
diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index d1cab80..031ceb3 100644
--- a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -56,20 +56,24 @@ void RegistryMaps::registerMatcher(
registerMatcher(#name, internal::makeMatcherAutoMarshall( \
::clang::ast_matchers::name, #name));
+#define REGISTER_MATCHER_OVERLOAD(name) \
+ registerMatcher(#name, \
+ llvm::make_unique<internal::OverloadedMatcherDescriptor>(name##Callbacks))
+
#define SPECIFIC_MATCHER_OVERLOAD(name, Id) \
static_cast<::clang::ast_matchers::name##_Type##Id>( \
::clang::ast_matchers::name)
+#define MATCHER_OVERLOAD_ENTRY(name, Id) \
+ internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, Id), \
+ #name)
+
#define REGISTER_OVERLOADED_2(name) \
do { \
- std::unique_ptr<MatcherDescriptor> Callbacks[] = { \
- internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 0), \
- #name), \
- internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 1), \
- #name)}; \
- registerMatcher( \
- #name, \
- llvm::make_unique<internal::OverloadedMatcherDescriptor>(Callbacks)); \
+ std::unique_ptr<MatcherDescriptor> name##Callbacks[] = { \
+ MATCHER_OVERLOAD_ENTRY(name, 0), \
+ MATCHER_OVERLOAD_ENTRY(name, 1)}; \
+ REGISTER_MATCHER_OVERLOAD(name); \
} while (0)
/// \brief Generate a registry map with all the known matchers.
@@ -83,7 +87,6 @@ RegistryMaps::RegistryMaps() {
// findAll
//
// Other:
- // equals
// equalsNode
REGISTER_OVERLOADED_2(callee);
@@ -96,6 +99,13 @@ RegistryMaps::RegistryMaps() {
REGISTER_OVERLOADED_2(references);
REGISTER_OVERLOADED_2(thisPointerType);
+ std::unique_ptr<MatcherDescriptor> equalsCallbacks[] = {
+ MATCHER_OVERLOAD_ENTRY(equals, 0),
+ MATCHER_OVERLOAD_ENTRY(equals, 1),
+ MATCHER_OVERLOAD_ENTRY(equals, 2),
+ };
+ REGISTER_MATCHER_OVERLOAD(equals);
+
REGISTER_MATCHER(accessSpecDecl);
REGISTER_MATCHER(addrLabelExpr);
REGISTER_MATCHER(alignOfExpr);
@@ -153,6 +163,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(cxxRecordDecl);
REGISTER_MATCHER(cxxReinterpretCastExpr);
REGISTER_MATCHER(cxxStaticCastExpr);
+ REGISTER_MATCHER(cxxStdInitializerListExpr);
REGISTER_MATCHER(cxxTemporaryObjectExpr);
REGISTER_MATCHER(cxxThisExpr);
REGISTER_MATCHER(cxxThrowExpr);
@@ -296,6 +307,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isCatchAll);
REGISTER_MATCHER(isClass);
REGISTER_MATCHER(isConst);
+ REGISTER_MATCHER(isConstexpr);
REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isCopyAssignmentOperator);
REGISTER_MATCHER(isCopyConstructor);
@@ -330,6 +342,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isPublic);
REGISTER_MATCHER(isPure);
REGISTER_MATCHER(isSignedInteger);
+ REGISTER_MATCHER(isStaticStorageClass);
REGISTER_MATCHER(isStruct);
REGISTER_MATCHER(isTemplateInstantiation);
REGISTER_MATCHER(isUnion);
@@ -359,9 +372,14 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(nullStmt);
REGISTER_MATCHER(numSelectorArgs);
REGISTER_MATCHER(ofClass);
+ REGISTER_MATCHER(objcCategoryDecl);
REGISTER_MATCHER(objcInterfaceDecl);
+ REGISTER_MATCHER(objcIvarDecl);
REGISTER_MATCHER(objcMessageExpr);
+ REGISTER_MATCHER(objcMethodDecl);
REGISTER_MATCHER(objcObjectPointerType);
+ REGISTER_MATCHER(objcPropertyDecl);
+ REGISTER_MATCHER(objcProtocolDecl);
REGISTER_MATCHER(on);
REGISTER_MATCHER(onImplicitObjectArgument);
REGISTER_MATCHER(opaqueValueExpr);
@@ -412,6 +430,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(typedefNameDecl);
REGISTER_MATCHER(typedefType);
REGISTER_MATCHER(typeAliasDecl);
+ REGISTER_MATCHER(typeAliasTemplateDecl);
REGISTER_MATCHER(typeLoc);
REGISTER_MATCHER(unaryExprOrTypeTraitExpr);
REGISTER_MATCHER(unaryOperator);
diff --git a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
index f0339ed..57858d0 100644
--- a/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ b/contrib/llvm/tools/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -24,6 +24,10 @@ std::string ArgKind::asString() const {
switch (getArgKind()) {
case AK_Matcher:
return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
+ case AK_Boolean:
+ return "boolean";
+ case AK_Double:
+ return "double";
case AK_Unsigned:
return "unsigned";
case AK_String:
@@ -247,6 +251,14 @@ VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {
*this = Other;
}
+VariantValue::VariantValue(bool Boolean) : Type(VT_Nothing) {
+ setBoolean(Boolean);
+}
+
+VariantValue::VariantValue(double Double) : Type(VT_Nothing) {
+ setDouble(Double);
+}
+
VariantValue::VariantValue(unsigned Unsigned) : Type(VT_Nothing) {
setUnsigned(Unsigned);
}
@@ -265,6 +277,12 @@ VariantValue &VariantValue::operator=(const VariantValue &Other) {
if (this == &Other) return *this;
reset();
switch (Other.Type) {
+ case VT_Boolean:
+ setBoolean(Other.getBoolean());
+ break;
+ case VT_Double:
+ setDouble(Other.getDouble());
+ break;
case VT_Unsigned:
setUnsigned(Other.getUnsigned());
break;
@@ -290,6 +308,8 @@ void VariantValue::reset() {
delete Value.Matcher;
break;
// Cases that do nothing.
+ case VT_Boolean:
+ case VT_Double:
case VT_Unsigned:
case VT_Nothing:
break;
@@ -297,6 +317,36 @@ void VariantValue::reset() {
Type = VT_Nothing;
}
+bool VariantValue::isBoolean() const {
+ return Type == VT_Boolean;
+}
+
+bool VariantValue::getBoolean() const {
+ assert(isBoolean());
+ return Value.Boolean;
+}
+
+void VariantValue::setBoolean(bool NewValue) {
+ reset();
+ Type = VT_Boolean;
+ Value.Boolean = NewValue;
+}
+
+bool VariantValue::isDouble() const {
+ return Type == VT_Double;
+}
+
+double VariantValue::getDouble() const {
+ assert(isDouble());
+ return Value.Double;
+}
+
+void VariantValue::setDouble(double NewValue) {
+ reset();
+ Type = VT_Double;
+ Value.Double = NewValue;
+}
+
bool VariantValue::isUnsigned() const {
return Type == VT_Unsigned;
}
@@ -344,6 +394,18 @@ void VariantValue::setMatcher(const VariantMatcher &NewValue) {
bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const {
switch (Kind.getArgKind()) {
+ case ArgKind::AK_Boolean:
+ if (!isBoolean())
+ return false;
+ *Specificity = 1;
+ return true;
+
+ case ArgKind::AK_Double:
+ if (!isDouble())
+ return false;
+ *Specificity = 1;
+ return true;
+
case ArgKind::AK_Unsigned:
if (!isUnsigned())
return false;
@@ -383,6 +445,8 @@ std::string VariantValue::getTypeAsString() const {
switch (Type) {
case VT_String: return "String";
case VT_Matcher: return getMatcher().getTypeAsString();
+ case VT_Boolean: return "Boolean";
+ case VT_Double: return "Double";
case VT_Unsigned: return "Unsigned";
case VT_Nothing: return "Nothing";
}
diff --git a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp
index 6b58916..ec15f34 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -67,6 +67,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
bool addImplicitDtors,
bool addInitializers,
bool addTemporaryDtors,
+ bool addLifetime,
bool synthesizeBodies,
bool addStaticInitBranch,
bool addCXXNewAllocator,
@@ -77,6 +78,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
cfgBuildOptions.AddInitializers = addInitializers;
cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
+ cfgBuildOptions.AddLifetime = addLifetime;
cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
}
@@ -92,6 +94,8 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
IsAutosynthesized = false;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Stmt *Body = FD->getBody();
+ if (auto *CoroBody = dyn_cast_or_null<CoroutineBodyStmt>(Body))
+ Body = CoroBody->getBody();
if (Manager && Manager->synthesizeBodies()) {
Stmt *SynthesizedBody =
getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD);
diff --git a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp
index 56c812c..5912724 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp
@@ -87,7 +87,7 @@ BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
QualType Ty) {
return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
BO_Assign, Ty, VK_RValue,
- OK_Ordinary, SourceLocation(), false);
+ OK_Ordinary, SourceLocation(), FPOptions());
}
BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
@@ -99,7 +99,7 @@ BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
Op,
C.getLogicalOperationType(),
VK_RValue,
- OK_Ordinary, SourceLocation(), false);
+ OK_Ordinary, SourceLocation(), FPOptions());
}
CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
diff --git a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp
index d56e0e8..6a77455 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp
@@ -233,6 +233,7 @@ public:
}
int distance(const_iterator L);
+ const_iterator shared_parent(const_iterator L);
};
friend class const_iterator;
@@ -275,6 +276,30 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
return D;
}
+/// Calculates the closest parent of this iterator
+/// that is in a scope reachable through the parents of L.
+/// I.e. when using 'goto' from this to L, the lifetime of all variables
+/// between this and shared_parent(L) end.
+LocalScope::const_iterator
+LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
+ llvm::SmallPtrSet<const LocalScope *, 4> ScopesOfL;
+ while (true) {
+ ScopesOfL.insert(L.Scope);
+ if (L == const_iterator())
+ break;
+ L = L.Scope->Prev;
+ }
+
+ const_iterator F = *this;
+ while (true) {
+ if (ScopesOfL.count(F.Scope))
+ return F;
+ assert(F != const_iterator() &&
+ "L iterator is not reachable from F iterator.");
+ F = F.Scope->Prev;
+ }
+}
+
/// Structure for specifying position in CFG during its build process. It
/// consists of CFGBlock that specifies position in CFG and
/// LocalScope::const_iterator that specifies position in LocalScope graph.
@@ -579,6 +604,10 @@ private:
CFGBlock *addInitializer(CXXCtorInitializer *I);
void addAutomaticObjDtors(LocalScope::const_iterator B,
LocalScope::const_iterator E, Stmt *S);
+ void addLifetimeEnds(LocalScope::const_iterator B,
+ LocalScope::const_iterator E, Stmt *S);
+ void addAutomaticObjHandling(LocalScope::const_iterator B,
+ LocalScope::const_iterator E, Stmt *S);
void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD);
// Local scopes creation.
@@ -619,6 +648,10 @@ private:
B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
}
+ void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) {
+ B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext());
+ }
+
void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext());
}
@@ -626,6 +659,10 @@ private:
void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
LocalScope::const_iterator B, LocalScope::const_iterator E);
+ void prependAutomaticObjLifetimeWithTerminator(CFGBlock *Blk,
+ LocalScope::const_iterator B,
+ LocalScope::const_iterator E);
+
void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) {
B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable),
cfg->getBumpVectorContext());
@@ -957,7 +994,8 @@ private:
return TryResult();
}
-
+
+ bool hasTrivialDestructor(VarDecl *VD);
};
inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
@@ -1031,6 +1069,9 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
assert(Succ == &cfg->getExit());
Block = nullptr; // the EXIT block is empty. Create all other blocks lazily.
+ assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) &&
+ "AddImplicitDtors and AddLifetime cannot be used at the same time");
+
if (BuildOpts.AddImplicitDtors)
if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
addImplicitDtorsForDestructor(DD);
@@ -1067,6 +1108,8 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
if (LI == LabelMap.end()) continue;
JumpTarget JT = LI->second;
+ prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition,
+ JT.scopePosition);
prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
JT.scopePosition);
addSuccessor(B, JT.block);
@@ -1209,7 +1252,61 @@ static QualType getReferenceInitTemporaryType(ASTContext &Context,
return Init->getType();
}
-
+
+void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
+ LocalScope::const_iterator E,
+ Stmt *S) {
+ if (BuildOpts.AddImplicitDtors)
+ addAutomaticObjDtors(B, E, S);
+ if (BuildOpts.AddLifetime)
+ addLifetimeEnds(B, E, S);
+}
+
+/// Add to current block automatic objects that leave the scope.
+void CFGBuilder::addLifetimeEnds(LocalScope::const_iterator B,
+ LocalScope::const_iterator E, Stmt *S) {
+ if (!BuildOpts.AddLifetime)
+ return;
+
+ if (B == E)
+ return;
+
+ // To go from B to E, one first goes up the scopes from B to P
+ // then sideways in one scope from P to P' and then down
+ // the scopes from P' to E.
+ // The lifetime of all objects between B and P end.
+ LocalScope::const_iterator P = B.shared_parent(E);
+ int dist = B.distance(P);
+ if (dist <= 0)
+ return;
+
+ // We need to perform the scope leaving in reverse order
+ SmallVector<VarDecl *, 10> DeclsTrivial;
+ SmallVector<VarDecl *, 10> DeclsNonTrivial;
+ DeclsTrivial.reserve(dist);
+ DeclsNonTrivial.reserve(dist);
+
+ for (LocalScope::const_iterator I = B; I != P; ++I)
+ if (hasTrivialDestructor(*I))
+ DeclsTrivial.push_back(*I);
+ else
+ DeclsNonTrivial.push_back(*I);
+
+ autoCreateBlock();
+ // object with trivial destructor end their lifetime last (when storage
+ // duration ends)
+ for (SmallVectorImpl<VarDecl *>::reverse_iterator I = DeclsTrivial.rbegin(),
+ E = DeclsTrivial.rend();
+ I != E; ++I)
+ appendLifetimeEnds(Block, *I, S);
+
+ for (SmallVectorImpl<VarDecl *>::reverse_iterator
+ I = DeclsNonTrivial.rbegin(),
+ E = DeclsNonTrivial.rend();
+ I != E; ++I)
+ appendLifetimeEnds(Block, *I, S);
+}
+
/// addAutomaticObjDtors - Add to current block automatic objects destructors
/// for objects in range of local scope positions. Use S as trigger statement
/// for destructors.
@@ -1309,7 +1406,7 @@ LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
/// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement
/// that should create implicit scope (e.g. if/else substatements).
void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
- if (!BuildOpts.AddImplicitDtors)
+ if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
return;
LocalScope *Scope = nullptr;
@@ -1334,7 +1431,7 @@ void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
/// reuse Scope if not NULL.
LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
LocalScope* Scope) {
- if (!BuildOpts.AddImplicitDtors)
+ if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
return Scope;
for (auto *DI : DS->decls())
@@ -1343,23 +1440,7 @@ LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
return Scope;
}
-/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will
-/// create add scope for automatic objects and temporary objects bound to
-/// const reference. Will reuse Scope if not NULL.
-LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
- LocalScope* Scope) {
- if (!BuildOpts.AddImplicitDtors)
- return Scope;
-
- // Check if variable is local.
- switch (VD->getStorageClass()) {
- case SC_None:
- case SC_Auto:
- case SC_Register:
- break;
- default: return Scope;
- }
-
+bool CFGBuilder::hasTrivialDestructor(VarDecl *VD) {
// Check for const references bound to temporary. Set type to pointee.
QualType QT = VD->getType();
if (QT.getTypePtr()->isReferenceType()) {
@@ -1370,44 +1451,74 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
// temporaries, and a single declaration can extend multiple temporaries.
// We should look at the storage duration on each nested
// MaterializeTemporaryExpr instead.
+
const Expr *Init = VD->getInit();
if (!Init)
- return Scope;
+ return true;
// Lifetime-extending a temporary.
bool FoundMTE = false;
QT = getReferenceInitTemporaryType(*Context, Init, &FoundMTE);
if (!FoundMTE)
- return Scope;
+ return true;
}
// Check for constant size array. Set type to array element type.
while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
if (AT->getSize() == 0)
- return Scope;
+ return true;
QT = AT->getElementType();
}
// Check if type is a C++ class with non-trivial destructor.
if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl())
- if (!CD->hasTrivialDestructor()) {
+ return !CD->hasDefinition() || CD->hasTrivialDestructor();
+ return true;
+}
+
+/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will
+/// create add scope for automatic objects and temporary objects bound to
+/// const reference. Will reuse Scope if not NULL.
+LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
+ LocalScope* Scope) {
+ assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) &&
+ "AddImplicitDtors and AddLifetime cannot be used at the same time");
+ if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime)
+ return Scope;
+
+ // Check if variable is local.
+ switch (VD->getStorageClass()) {
+ case SC_None:
+ case SC_Auto:
+ case SC_Register:
+ break;
+ default: return Scope;
+ }
+
+ if (BuildOpts.AddImplicitDtors) {
+ if (!hasTrivialDestructor(VD)) {
// Add the variable to scope
Scope = createOrReuseLocalScope(Scope);
Scope->addVar(VD);
ScopePos = Scope->begin();
}
+ return Scope;
+ }
+
+ assert(BuildOpts.AddLifetime);
+ // Add the variable to scope
+ Scope = createOrReuseLocalScope(Scope);
+ Scope->addVar(VD);
+ ScopePos = Scope->begin();
return Scope;
}
/// addLocalScopeAndDtors - For given statement add local scope for it and
/// add destructors that will cleanup the scope. Will reuse Scope if not NULL.
void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
- if (!BuildOpts.AddImplicitDtors)
- return;
-
LocalScope::const_iterator scopeBeginPos = ScopePos;
addLocalScopeForStmt(S);
- addAutomaticObjDtors(ScopePos, scopeBeginPos, S);
+ addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
}
/// prependAutomaticObjDtorsWithTerminator - Prepend destructor CFGElements for
@@ -1419,6 +1530,8 @@ void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
/// no-return destructors properly.
void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
LocalScope::const_iterator B, LocalScope::const_iterator E) {
+ if (!BuildOpts.AddImplicitDtors)
+ return;
BumpVectorContext &C = cfg->getBumpVectorContext();
CFGBlock::iterator InsertPos
= Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C);
@@ -1427,6 +1540,21 @@ void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
Blk->getTerminator());
}
+/// prependAutomaticObjLifetimeWithTerminator - Prepend lifetime CFGElements for
+/// variables with automatic storage duration to CFGBlock's elements vector.
+/// Elements will be prepended to physical beginning of the vector which
+/// happens to be logical end. Use blocks terminator as statement that specifies
+/// where lifetime ends.
+void CFGBuilder::prependAutomaticObjLifetimeWithTerminator(
+ CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) {
+ if (!BuildOpts.AddLifetime)
+ return;
+ BumpVectorContext &C = cfg->getBumpVectorContext();
+ CFGBlock::iterator InsertPos =
+ Blk->beginLifetimeEndsInsert(Blk->end(), B.distance(E), C);
+ for (LocalScope::const_iterator I = B; I != E; ++I)
+ InsertPos = Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminator());
+}
/// Visit - Walk the subtree of a statement and add extra
/// blocks for ternary operators, &&, and ||. We also process "," and
/// DeclStmts (which may contain nested control-flow).
@@ -1815,7 +1943,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
// If there is no target for the break, then we are looking at an incomplete
// AST. This means that the CFG cannot be constructed.
if (BreakJumpTarget.block) {
- addAutomaticObjDtors(ScopePos, BreakJumpTarget.scopePosition, B);
+ addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
addSuccessor(Block, BreakJumpTarget.block);
} else
badCFG = true;
@@ -1947,13 +2075,12 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
LocalScope::const_iterator scopeBeginPos = ScopePos;
- if (BuildOpts.AddImplicitDtors) {
- addLocalScopeForStmt(C);
- }
+ addLocalScopeForStmt(C);
+
if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) {
// If the body ends with a ReturnStmt, the dtors will be added in
// VisitReturnStmt.
- addAutomaticObjDtors(ScopePos, scopeBeginPos, C);
+ addAutomaticObjHandling(ScopePos, scopeBeginPos, C);
}
CFGBlock *LastBlock = Block;
@@ -2183,7 +2310,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
if (VarDecl *VD = I->getConditionVariable())
addLocalScopeForVarDecl(VD);
- addAutomaticObjDtors(ScopePos, save_scope_pos.get(), I);
+ addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
// The block we were processing is now finished. Make it the successor
// block.
@@ -2308,7 +2435,7 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
// Create the new block.
Block = createBlock(false);
- addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R);
+ addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R);
// If the one of the destructors does not return, we already have the Exit
// block as a successor.
@@ -2389,7 +2516,7 @@ CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
BackpatchBlocks.push_back(JumpSource(Block, ScopePos));
else {
JumpTarget JT = I->second;
- addAutomaticObjDtors(ScopePos, JT.scopePosition, G);
+ addAutomaticObjHandling(ScopePos, JT.scopePosition, G);
addSuccessor(Block, JT.block);
}
@@ -2414,7 +2541,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
addLocalScopeForVarDecl(VD);
LocalScope::const_iterator ContinueScopePos = ScopePos;
- addAutomaticObjDtors(ScopePos, save_scope_pos.get(), F);
+ addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
// "for" is a control-flow statement. Thus we stop processing the current
// block.
@@ -2466,7 +2593,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
ContinueJumpTarget.block->setLoopTarget(F);
// Loop body should end with destructor of Condition variable (if any).
- addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F);
+ addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -2753,7 +2880,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
LocalScope::const_iterator LoopBeginScopePos = ScopePos;
if (VarDecl *VD = W->getConditionVariable()) {
addLocalScopeForVarDecl(VD);
- addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W);
+ addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
}
// "while" is a control-flow statement. Thus we stop processing the current
@@ -2788,7 +2915,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
// Loop body should end with destructor of Condition variable (if any).
- addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W);
+ addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -3030,7 +3157,7 @@ CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) {
// If there is no target for the continue, then we are looking at an
// incomplete AST. This means the CFG cannot be constructed.
if (ContinueJumpTarget.block) {
- addAutomaticObjDtors(ScopePos, ContinueJumpTarget.scopePosition, C);
+ addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition, C);
addSuccessor(Block, ContinueJumpTarget.block);
} else
badCFG = true;
@@ -3085,7 +3212,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
if (VarDecl *VD = Terminator->getConditionVariable())
addLocalScopeForVarDecl(VD);
- addAutomaticObjDtors(ScopePos, save_scope_pos.get(), Terminator);
+ addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
if (Block) {
if (badCFG)
@@ -3373,7 +3500,7 @@ CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
if (VarDecl *VD = CS->getExceptionDecl()) {
LocalScope::const_iterator BeginScopePos = ScopePos;
addLocalScopeForVarDecl(VD);
- addAutomaticObjDtors(ScopePos, BeginScopePos, CS);
+ addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
}
if (CS->getHandlerBlock())
@@ -3427,7 +3554,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
addLocalScopeForStmt(Begin);
if (Stmt *End = S->getEndStmt())
addLocalScopeForStmt(End);
- addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
+ addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
LocalScope::const_iterator ContinueScopePos = ScopePos;
@@ -3898,6 +4025,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
case CFGElement::Statement:
case CFGElement::Initializer:
case CFGElement::NewAllocator:
+ case CFGElement::LifetimeEnds:
llvm_unreachable("getDestructorDecl should only be used with "
"ImplicitDtors");
case CFGElement::AutomaticObjectDtor: {
@@ -4308,6 +4436,12 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
OS << " (Implicit destructor)\n";
+ } else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) {
+ const VarDecl *VD = DE->getVarDecl();
+ Helper.handleDecl(VD, OS);
+
+ OS << " (Lifetime ends)\n";
+
} else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
OS << "CFGNewAllocator(";
if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr())
diff --git a/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp b/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp
index 8c126b0..6d9530b 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp
@@ -62,6 +62,7 @@ public:
void VisitCallExpr(CallExpr *CE) {
if (Decl *D = getDeclFromCall(CE))
addCalledDecl(D);
+ VisitChildren(CE);
}
// Adds may-call edges for the ObjC message sends.
diff --git a/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp b/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp
index e761738..5ea7498 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp
@@ -16,35 +16,35 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Path.h"
using namespace clang;
+using namespace clang::clone_detection;
-StmtSequence::StmtSequence(const CompoundStmt *Stmt, ASTContext &Context,
+StmtSequence::StmtSequence(const CompoundStmt *Stmt, const Decl *D,
unsigned StartIndex, unsigned EndIndex)
- : S(Stmt), Context(&Context), StartIndex(StartIndex), EndIndex(EndIndex) {
+ : S(Stmt), D(D), StartIndex(StartIndex), EndIndex(EndIndex) {
assert(Stmt && "Stmt must not be a nullptr");
assert(StartIndex < EndIndex && "Given array should not be empty");
assert(EndIndex <= Stmt->size() && "Given array too big for this Stmt");
}
-StmtSequence::StmtSequence(const Stmt *Stmt, ASTContext &Context)
- : S(Stmt), Context(&Context), StartIndex(0), EndIndex(0) {}
+StmtSequence::StmtSequence(const Stmt *Stmt, const Decl *D)
+ : S(Stmt), D(D), StartIndex(0), EndIndex(0) {}
StmtSequence::StmtSequence()
- : S(nullptr), Context(nullptr), StartIndex(0), EndIndex(0) {}
+ : S(nullptr), D(nullptr), StartIndex(0), EndIndex(0) {}
bool StmtSequence::contains(const StmtSequence &Other) const {
- // If both sequences reside in different translation units, they can never
- // contain each other.
- if (Context != Other.Context)
+ // If both sequences reside in different declarations, they can never contain
+ // each other.
+ if (D != Other.D)
return false;
- const SourceManager &SM = Context->getSourceManager();
+ const SourceManager &SM = getASTContext().getSourceManager();
// Otherwise check if the start and end locations of the current sequence
// surround the other sequence.
@@ -76,6 +76,11 @@ StmtSequence::iterator StmtSequence::end() const {
return CS->body_begin() + EndIndex;
}
+ASTContext &StmtSequence::getASTContext() const {
+ assert(D);
+ return D->getASTContext();
+}
+
SourceLocation StmtSequence::getStartLoc() const {
return front()->getLocStart();
}
@@ -86,168 +91,8 @@ SourceRange StmtSequence::getSourceRange() const {
return SourceRange(getStartLoc(), getEndLoc());
}
-namespace {
-
-/// \brief Analyzes the pattern of the referenced variables in a statement.
-class VariablePattern {
-
- /// \brief Describes an occurence of a variable reference in a statement.
- struct VariableOccurence {
- /// The index of the associated VarDecl in the Variables vector.
- size_t KindID;
- /// The statement in the code where the variable was referenced.
- const Stmt *Mention;
-
- VariableOccurence(size_t KindID, const Stmt *Mention)
- : KindID(KindID), Mention(Mention) {}
- };
-
- /// All occurences of referenced variables in the order of appearance.
- std::vector<VariableOccurence> Occurences;
- /// List of referenced variables in the order of appearance.
- /// Every item in this list is unique.
- std::vector<const VarDecl *> Variables;
-
- /// \brief Adds a new variable referenced to this pattern.
- /// \param VarDecl The declaration of the variable that is referenced.
- /// \param Mention The SourceRange where this variable is referenced.
- void addVariableOccurence(const VarDecl *VarDecl, const Stmt *Mention) {
- // First check if we already reference this variable
- for (size_t KindIndex = 0; KindIndex < Variables.size(); ++KindIndex) {
- if (Variables[KindIndex] == VarDecl) {
- // If yes, add a new occurence that points to the existing entry in
- // the Variables vector.
- Occurences.emplace_back(KindIndex, Mention);
- return;
- }
- }
- // If this variable wasn't already referenced, add it to the list of
- // referenced variables and add a occurence that points to this new entry.
- Occurences.emplace_back(Variables.size(), Mention);
- Variables.push_back(VarDecl);
- }
-
- /// \brief Adds each referenced variable from the given statement.
- void addVariables(const Stmt *S) {
- // Sometimes we get a nullptr (such as from IfStmts which often have nullptr
- // children). We skip such statements as they don't reference any
- // variables.
- if (!S)
- return;
-
- // Check if S is a reference to a variable. If yes, add it to the pattern.
- if (auto D = dyn_cast<DeclRefExpr>(S)) {
- if (auto VD = dyn_cast<VarDecl>(D->getDecl()->getCanonicalDecl()))
- addVariableOccurence(VD, D);
- }
-
- // Recursively check all children of the given statement.
- for (const Stmt *Child : S->children()) {
- addVariables(Child);
- }
- }
-
-public:
- /// \brief Creates an VariablePattern object with information about the given
- /// StmtSequence.
- VariablePattern(const StmtSequence &Sequence) {
- for (const Stmt *S : Sequence)
- addVariables(S);
- }
-
- /// \brief Counts the differences between this pattern and the given one.
- /// \param Other The given VariablePattern to compare with.
- /// \param FirstMismatch Output parameter that will be filled with information
- /// about the first difference between the two patterns. This parameter
- /// can be a nullptr, in which case it will be ignored.
- /// \return Returns the number of differences between the pattern this object
- /// is following and the given VariablePattern.
- ///
- /// For example, the following statements all have the same pattern and this
- /// function would return zero:
- ///
- /// if (a < b) return a; return b;
- /// if (x < y) return x; return y;
- /// if (u2 < u1) return u2; return u1;
- ///
- /// But the following statement has a different pattern (note the changed
- /// variables in the return statements) and would have two differences when
- /// compared with one of the statements above.
- ///
- /// if (a < b) return b; return a;
- ///
- /// This function should only be called if the related statements of the given
- /// pattern and the statements of this objects are clones of each other.
- unsigned countPatternDifferences(
- const VariablePattern &Other,
- CloneDetector::SuspiciousClonePair *FirstMismatch = nullptr) {
- unsigned NumberOfDifferences = 0;
-
- assert(Other.Occurences.size() == Occurences.size());
- for (unsigned i = 0; i < Occurences.size(); ++i) {
- auto ThisOccurence = Occurences[i];
- auto OtherOccurence = Other.Occurences[i];
- if (ThisOccurence.KindID == OtherOccurence.KindID)
- continue;
-
- ++NumberOfDifferences;
-
- // If FirstMismatch is not a nullptr, we need to store information about
- // the first difference between the two patterns.
- if (FirstMismatch == nullptr)
- continue;
-
- // Only proceed if we just found the first difference as we only store
- // information about the first difference.
- if (NumberOfDifferences != 1)
- continue;
-
- const VarDecl *FirstSuggestion = nullptr;
- // If there is a variable available in the list of referenced variables
- // which wouldn't break the pattern if it is used in place of the
- // current variable, we provide this variable as the suggested fix.
- if (OtherOccurence.KindID < Variables.size())
- FirstSuggestion = Variables[OtherOccurence.KindID];
-
- // Store information about the first clone.
- FirstMismatch->FirstCloneInfo =
- CloneDetector::SuspiciousClonePair::SuspiciousCloneInfo(
- Variables[ThisOccurence.KindID], ThisOccurence.Mention,
- FirstSuggestion);
-
- // Same as above but with the other clone. We do this for both clones as
- // we don't know which clone is the one containing the unintended
- // pattern error.
- const VarDecl *SecondSuggestion = nullptr;
- if (ThisOccurence.KindID < Other.Variables.size())
- SecondSuggestion = Other.Variables[ThisOccurence.KindID];
-
- // Store information about the second clone.
- FirstMismatch->SecondCloneInfo =
- CloneDetector::SuspiciousClonePair::SuspiciousCloneInfo(
- Other.Variables[OtherOccurence.KindID], OtherOccurence.Mention,
- SecondSuggestion);
-
- // SuspiciousClonePair guarantees that the first clone always has a
- // suggested variable associated with it. As we know that one of the two
- // clones in the pair always has suggestion, we swap the two clones
- // in case the first clone has no suggested variable which means that
- // the second clone has a suggested variable and should be first.
- if (!FirstMismatch->FirstCloneInfo.Suggestion)
- std::swap(FirstMismatch->FirstCloneInfo,
- FirstMismatch->SecondCloneInfo);
-
- // This ensures that we always have at least one suggestion in a pair.
- assert(FirstMismatch->FirstCloneInfo.Suggestion);
- }
-
- return NumberOfDifferences;
- }
-};
-}
-
-/// \brief Prints the macro name that contains the given SourceLocation into
-/// the given raw_string_ostream.
+/// Prints the macro name that contains the given SourceLocation into the given
+/// raw_string_ostream.
static void printMacroName(llvm::raw_string_ostream &MacroStack,
ASTContext &Context, SourceLocation Loc) {
MacroStack << Lexer::getImmediateMacroName(Loc, Context.getSourceManager(),
@@ -258,12 +103,8 @@ static void printMacroName(llvm::raw_string_ostream &MacroStack,
MacroStack << " ";
}
-/// \brief Returns a string that represents all macro expansions that
-/// expanded into the given SourceLocation.
-///
-/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations
-/// A and B are expanded from the same macros in the same order.
-static std::string getMacroStack(SourceLocation Loc, ASTContext &Context) {
+std::string clone_detection::getMacroStack(SourceLocation Loc,
+ ASTContext &Context) {
std::string MacroStack;
llvm::raw_string_ostream MacroStackStream(MacroStack);
SourceManager &SM = Context.getSourceManager();
@@ -278,375 +119,159 @@ static std::string getMacroStack(SourceLocation Loc, ASTContext &Context) {
return MacroStack;
}
-namespace {
-/// \brief Collects the data of a single Stmt.
-///
-/// This class defines what a code clone is: If it collects for two statements
-/// the same data, then those two statements are considered to be clones of each
-/// other.
-///
-/// All collected data is forwarded to the given data consumer of the type T.
-/// The data consumer class needs to provide a member method with the signature:
-/// update(StringRef Str)
-template <typename T>
-class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector<T>> {
+void CloneDetector::analyzeCodeBody(const Decl *D) {
+ assert(D);
+ assert(D->hasBody());
- ASTContext &Context;
- /// \brief The data sink to which all data is forwarded.
- T &DataConsumer;
+ Sequences.push_back(StmtSequence(D->getBody(), D));
+}
-public:
- /// \brief Collects data of the given Stmt.
- /// \param S The given statement.
- /// \param Context The ASTContext of S.
- /// \param DataConsumer The data sink to which all data is forwarded.
- StmtDataCollector(const Stmt *S, ASTContext &Context, T &DataConsumer)
- : Context(Context), DataConsumer(DataConsumer) {
- this->Visit(S);
+/// Returns true if and only if \p Stmt contains at least one other
+/// sequence in the \p Group.
+static bool containsAnyInGroup(StmtSequence &Seq,
+ CloneDetector::CloneGroup &Group) {
+ for (StmtSequence &GroupSeq : Group) {
+ if (Seq.contains(GroupSeq))
+ return true;
}
+ return false;
+}
- // Below are utility methods for appending different data to the vector.
+/// Returns true if and only if all sequences in \p OtherGroup are
+/// contained by a sequence in \p Group.
+static bool containsGroup(CloneDetector::CloneGroup &Group,
+ CloneDetector::CloneGroup &OtherGroup) {
+ // We have less sequences in the current group than we have in the other,
+ // so we will never fulfill the requirement for returning true. This is only
+ // possible because we know that a sequence in Group can contain at most
+ // one sequence in OtherGroup.
+ if (Group.size() < OtherGroup.size())
+ return false;
- void addData(CloneDetector::DataPiece Integer) {
- DataConsumer.update(
- StringRef(reinterpret_cast<char *>(&Integer), sizeof(Integer)));
+ for (StmtSequence &Stmt : Group) {
+ if (!containsAnyInGroup(Stmt, OtherGroup))
+ return false;
}
+ return true;
+}
- void addData(llvm::StringRef Str) { DataConsumer.update(Str); }
-
- void addData(const QualType &QT) { addData(QT.getAsString()); }
-
-// The functions below collect the class specific data of each Stmt subclass.
-
-// Utility macro for defining a visit method for a given class. This method
-// calls back to the ConstStmtVisitor to visit all parent classes.
-#define DEF_ADD_DATA(CLASS, CODE) \
- void Visit##CLASS(const CLASS *S) { \
- CODE; \
- ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
- }
+void OnlyLargestCloneConstraint::constrain(
+ std::vector<CloneDetector::CloneGroup> &Result) {
+ std::vector<unsigned> IndexesToRemove;
- DEF_ADD_DATA(Stmt, {
- addData(S->getStmtClass());
- // This ensures that macro generated code isn't identical to macro-generated
- // code.
- addData(getMacroStack(S->getLocStart(), Context));
- addData(getMacroStack(S->getLocEnd(), Context));
- })
- DEF_ADD_DATA(Expr, { addData(S->getType()); })
-
- //--- Builtin functionality ----------------------------------------------//
- DEF_ADD_DATA(ArrayTypeTraitExpr, { addData(S->getTrait()); })
- DEF_ADD_DATA(ExpressionTraitExpr, { addData(S->getTrait()); })
- DEF_ADD_DATA(PredefinedExpr, { addData(S->getIdentType()); })
- DEF_ADD_DATA(TypeTraitExpr, {
- addData(S->getTrait());
- for (unsigned i = 0; i < S->getNumArgs(); ++i)
- addData(S->getArg(i)->getType());
- })
-
- //--- Calls --------------------------------------------------------------//
- DEF_ADD_DATA(CallExpr, {
- // Function pointers don't have a callee and we just skip hashing it.
- if (const FunctionDecl *D = S->getDirectCallee()) {
- // If the function is a template specialization, we also need to handle
- // the template arguments as they are not included in the qualified name.
- if (auto Args = D->getTemplateSpecializationArgs()) {
- std::string ArgString;
-
- // Print all template arguments into ArgString
- llvm::raw_string_ostream OS(ArgString);
- for (unsigned i = 0; i < Args->size(); ++i) {
- Args->get(i).print(Context.getLangOpts(), OS);
- // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'.
- OS << '\n';
- }
- OS.flush();
+ // Compare every group in the result with the rest. If one groups contains
+ // another group, we only need to return the bigger group.
+ // Note: This doesn't scale well, so if possible avoid calling any heavy
+ // function from this loop to minimize the performance impact.
+ for (unsigned i = 0; i < Result.size(); ++i) {
+ for (unsigned j = 0; j < Result.size(); ++j) {
+ // Don't compare a group with itself.
+ if (i == j)
+ continue;
- addData(ArgString);
- }
- addData(D->getQualifiedNameAsString());
- }
- })
-
- //--- Exceptions ---------------------------------------------------------//
- DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); })
-
- //--- C++ OOP Stmts ------------------------------------------------------//
- DEF_ADD_DATA(CXXDeleteExpr, {
- addData(S->isArrayFormAsWritten());
- addData(S->isGlobalDelete());
- })
-
- //--- Casts --------------------------------------------------------------//
- DEF_ADD_DATA(ObjCBridgedCastExpr, { addData(S->getBridgeKind()); })
-
- //--- Miscellaneous Exprs ------------------------------------------------//
- DEF_ADD_DATA(BinaryOperator, { addData(S->getOpcode()); })
- DEF_ADD_DATA(UnaryOperator, { addData(S->getOpcode()); })
-
- //--- Control flow -------------------------------------------------------//
- DEF_ADD_DATA(GotoStmt, { addData(S->getLabel()->getName()); })
- DEF_ADD_DATA(IndirectGotoStmt, {
- if (S->getConstantTarget())
- addData(S->getConstantTarget()->getName());
- })
- DEF_ADD_DATA(LabelStmt, { addData(S->getDecl()->getName()); })
- DEF_ADD_DATA(MSDependentExistsStmt, { addData(S->isIfExists()); })
- DEF_ADD_DATA(AddrLabelExpr, { addData(S->getLabel()->getName()); })
-
- //--- Objective-C --------------------------------------------------------//
- DEF_ADD_DATA(ObjCIndirectCopyRestoreExpr, { addData(S->shouldCopy()); })
- DEF_ADD_DATA(ObjCPropertyRefExpr, {
- addData(S->isSuperReceiver());
- addData(S->isImplicitProperty());
- })
- DEF_ADD_DATA(ObjCAtCatchStmt, { addData(S->hasEllipsis()); })
-
- //--- Miscellaneous Stmts ------------------------------------------------//
- DEF_ADD_DATA(CXXFoldExpr, {
- addData(S->isRightFold());
- addData(S->getOperator());
- })
- DEF_ADD_DATA(GenericSelectionExpr, {
- for (unsigned i = 0; i < S->getNumAssocs(); ++i) {
- addData(S->getAssocType(i));
- }
- })
- DEF_ADD_DATA(LambdaExpr, {
- for (const LambdaCapture &C : S->captures()) {
- addData(C.isPackExpansion());
- addData(C.getCaptureKind());
- if (C.capturesVariable())
- addData(C.getCapturedVar()->getType());
- }
- addData(S->isGenericLambda());
- addData(S->isMutable());
- })
- DEF_ADD_DATA(DeclStmt, {
- auto numDecls = std::distance(S->decl_begin(), S->decl_end());
- addData(static_cast<CloneDetector::DataPiece>(numDecls));
- for (const Decl *D : S->decls()) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- addData(VD->getType());
+ if (containsGroup(Result[j], Result[i])) {
+ IndexesToRemove.push_back(i);
+ break;
}
}
- })
- DEF_ADD_DATA(AsmStmt, {
- addData(S->isSimple());
- addData(S->isVolatile());
- addData(S->generateAsmString(Context));
- for (unsigned i = 0; i < S->getNumInputs(); ++i) {
- addData(S->getInputConstraint(i));
- }
- for (unsigned i = 0; i < S->getNumOutputs(); ++i) {
- addData(S->getOutputConstraint(i));
- }
- for (unsigned i = 0; i < S->getNumClobbers(); ++i) {
- addData(S->getClobber(i));
- }
- })
- DEF_ADD_DATA(AttributedStmt, {
- for (const Attr *A : S->getAttrs()) {
- addData(std::string(A->getSpelling()));
- }
- })
-};
-} // end anonymous namespace
+ }
-namespace {
-/// Generates CloneSignatures for a set of statements and stores the results in
-/// a CloneDetector object.
-class CloneSignatureGenerator {
-
- CloneDetector &CD;
- ASTContext &Context;
-
- /// \brief Generates CloneSignatures for all statements in the given statement
- /// tree and stores them in the CloneDetector.
- ///
- /// \param S The root of the given statement tree.
- /// \param ParentMacroStack A string representing the macros that generated
- /// the parent statement or an empty string if no
- /// macros generated the parent statement.
- /// See getMacroStack() for generating such a string.
- /// \return The CloneSignature of the root statement.
- CloneDetector::CloneSignature
- generateSignatures(const Stmt *S, const std::string &ParentMacroStack) {
- // Create an empty signature that will be filled in this method.
- CloneDetector::CloneSignature Signature;
-
- llvm::MD5 Hash;
-
- // Collect all relevant data from S and hash it.
- StmtDataCollector<llvm::MD5>(S, Context, Hash);
-
- // Look up what macros expanded into the current statement.
- std::string StartMacroStack = getMacroStack(S->getLocStart(), Context);
- std::string EndMacroStack = getMacroStack(S->getLocEnd(), Context);
-
- // First, check if ParentMacroStack is not empty which means we are currently
- // dealing with a parent statement which was expanded from a macro.
- // If this parent statement was expanded from the same macros as this
- // statement, we reduce the initial complexity of this statement to zero.
- // This causes that a group of statements that were generated by a single
- // macro expansion will only increase the total complexity by one.
- // Note: This is not the final complexity of this statement as we still
- // add the complexity of the child statements to the complexity value.
- if (!ParentMacroStack.empty() && (StartMacroStack == ParentMacroStack &&
- EndMacroStack == ParentMacroStack)) {
- Signature.Complexity = 0;
- }
+ // Erasing a list of indexes from the vector should be done with decreasing
+ // indexes. As IndexesToRemove is constructed with increasing values, we just
+ // reverse iterate over it to get the desired order.
+ for (auto I = IndexesToRemove.rbegin(); I != IndexesToRemove.rend(); ++I) {
+ Result.erase(Result.begin() + *I);
+ }
+}
- // Storage for the signatures of the direct child statements. This is only
- // needed if the current statement is a CompoundStmt.
- std::vector<CloneDetector::CloneSignature> ChildSignatures;
- const CompoundStmt *CS = dyn_cast<const CompoundStmt>(S);
+bool FilenamePatternConstraint::isAutoGenerated(const CloneDetector::CloneGroup &Group) {
+ std::string Error;
+ if (IgnoredFilesPattern.empty() || Group.empty() ||
+ !IgnoredFilesRegex->isValid(Error))
+ return false;
- // The signature of a statement includes the signatures of its children.
- // Therefore we create the signatures for every child and add them to the
- // current signature.
- for (const Stmt *Child : S->children()) {
- // Some statements like 'if' can have nullptr children that we will skip.
- if (!Child)
- continue;
+ for (const StmtSequence &S : Group) {
+ const SourceManager &SM = S.getASTContext().getSourceManager();
+ StringRef Filename = llvm::sys::path::filename(SM.getFilename(
+ S.getContainingDecl()->getLocation()));
+ if (IgnoredFilesRegex->match(Filename))
+ return true;
+ }
- // Recursive call to create the signature of the child statement. This
- // will also create and store all clone groups in this child statement.
- // We pass only the StartMacroStack along to keep things simple.
- auto ChildSignature = generateSignatures(Child, StartMacroStack);
+ return false;
+}
- // Add the collected data to the signature of the current statement.
- Signature.Complexity += ChildSignature.Complexity;
- Hash.update(StringRef(reinterpret_cast<char *>(&ChildSignature.Hash),
- sizeof(ChildSignature.Hash)));
+static size_t createHash(llvm::MD5 &Hash) {
+ size_t HashCode;
- // If the current statement is a CompoundStatement, we need to store the
- // signature for the generation of the sub-sequences.
- if (CS)
- ChildSignatures.push_back(ChildSignature);
- }
+ // Create the final hash code for the current Stmt.
+ llvm::MD5::MD5Result HashResult;
+ Hash.final(HashResult);
- // If the current statement is a CompoundStmt, we also need to create the
- // clone groups from the sub-sequences inside the children.
- if (CS)
- handleSubSequences(CS, ChildSignatures);
+ // Copy as much as possible of the generated hash code to the Stmt's hash
+ // code.
+ std::memcpy(&HashCode, &HashResult,
+ std::min(sizeof(HashCode), sizeof(HashResult)));
- // Create the final hash code for the current signature.
- llvm::MD5::MD5Result HashResult;
- Hash.final(HashResult);
+ return HashCode;
+}
+
+size_t RecursiveCloneTypeIIConstraint::saveHash(
+ const Stmt *S, const Decl *D,
+ std::vector<std::pair<size_t, StmtSequence>> &StmtsByHash) {
+ llvm::MD5 Hash;
+ ASTContext &Context = D->getASTContext();
- // Copy as much of the generated hash code to the signature's hash code.
- std::memcpy(&Signature.Hash, &HashResult,
- std::min(sizeof(Signature.Hash), sizeof(HashResult)));
+ StmtDataCollector<llvm::MD5>(S, Context, Hash);
- // Save the signature for the current statement in the CloneDetector object.
- CD.add(StmtSequence(S, Context), Signature);
+ auto CS = dyn_cast<CompoundStmt>(S);
+ SmallVector<size_t, 8> ChildHashes;
- return Signature;
+ for (const Stmt *Child : S->children()) {
+ if (Child == nullptr) {
+ ChildHashes.push_back(0);
+ continue;
+ }
+ size_t ChildHash = saveHash(Child, D, StmtsByHash);
+ Hash.update(
+ StringRef(reinterpret_cast<char *>(&ChildHash), sizeof(ChildHash)));
+ ChildHashes.push_back(ChildHash);
}
- /// \brief Adds all possible sub-sequences in the child array of the given
- /// CompoundStmt to the CloneDetector.
- /// \param CS The given CompoundStmt.
- /// \param ChildSignatures A list of calculated signatures for each child in
- /// the given CompoundStmt.
- void handleSubSequences(
- const CompoundStmt *CS,
- const std::vector<CloneDetector::CloneSignature> &ChildSignatures) {
-
- // FIXME: This function has quadratic runtime right now. Check if skipping
- // this function for too long CompoundStmts is an option.
-
- // The length of the sub-sequence. We don't need to handle sequences with
- // the length 1 as they are already handled in CollectData().
- for (unsigned Length = 2; Length <= CS->size(); ++Length) {
- // The start index in the body of the CompoundStmt. We increase the
- // position until the end of the sub-sequence reaches the end of the
- // CompoundStmt body.
- for (unsigned Pos = 0; Pos <= CS->size() - Length; ++Pos) {
- // Create an empty signature and add the signatures of all selected
- // child statements to it.
- CloneDetector::CloneSignature SubSignature;
- llvm::MD5 SubHash;
-
- for (unsigned i = Pos; i < Pos + Length; ++i) {
- SubSignature.Complexity += ChildSignatures[i].Complexity;
- size_t ChildHash = ChildSignatures[i].Hash;
-
- SubHash.update(StringRef(reinterpret_cast<char *>(&ChildHash),
- sizeof(ChildHash)));
+ if (CS) {
+ // If we're in a CompoundStmt, we hash all possible combinations of child
+ // statements to find clones in those subsequences.
+ // We first go through every possible starting position of a subsequence.
+ for (unsigned Pos = 0; Pos < CS->size(); ++Pos) {
+ // Then we try all possible lengths this subsequence could have and
+ // reuse the same hash object to make sure we only hash every child
+ // hash exactly once.
+ llvm::MD5 Hash;
+ for (unsigned Length = 1; Length <= CS->size() - Pos; ++Length) {
+ // Grab the current child hash and put it into our hash. We do
+ // -1 on the index because we start counting the length at 1.
+ size_t ChildHash = ChildHashes[Pos + Length - 1];
+ Hash.update(
+ StringRef(reinterpret_cast<char *>(&ChildHash), sizeof(ChildHash)));
+ // If we have at least two elements in our subsequence, we can start
+ // saving it.
+ if (Length > 1) {
+ llvm::MD5 SubHash = Hash;
+ StmtsByHash.push_back(std::make_pair(
+ createHash(SubHash), StmtSequence(CS, D, Pos, Pos + Length)));
}
-
- // Create the final hash code for the current signature.
- llvm::MD5::MD5Result HashResult;
- SubHash.final(HashResult);
-
- // Copy as much of the generated hash code to the signature's hash code.
- std::memcpy(&SubSignature.Hash, &HashResult,
- std::min(sizeof(SubSignature.Hash), sizeof(HashResult)));
-
- // Save the signature together with the information about what children
- // sequence we selected.
- CD.add(StmtSequence(CS, Context, Pos, Pos + Length), SubSignature);
}
}
}
-public:
- explicit CloneSignatureGenerator(CloneDetector &CD, ASTContext &Context)
- : CD(CD), Context(Context) {}
-
- /// \brief Generates signatures for all statements in the given function body.
- void consumeCodeBody(const Stmt *S) { generateSignatures(S, ""); }
-};
-} // end anonymous namespace
-
-void CloneDetector::analyzeCodeBody(const Decl *D) {
- assert(D);
- assert(D->hasBody());
- CloneSignatureGenerator Generator(*this, D->getASTContext());
- Generator.consumeCodeBody(D->getBody());
-}
-
-void CloneDetector::add(const StmtSequence &S,
- const CloneSignature &Signature) {
- Sequences.push_back(std::make_pair(Signature, S));
+ size_t HashCode = createHash(Hash);
+ StmtsByHash.push_back(std::make_pair(HashCode, StmtSequence(S, D)));
+ return HashCode;
}
namespace {
-/// \brief Returns true if and only if \p Stmt contains at least one other
-/// sequence in the \p Group.
-bool containsAnyInGroup(StmtSequence &Stmt, CloneDetector::CloneGroup &Group) {
- for (StmtSequence &GroupStmt : Group.Sequences) {
- if (Stmt.contains(GroupStmt))
- return true;
- }
- return false;
-}
-
-/// \brief Returns true if and only if all sequences in \p OtherGroup are
-/// contained by a sequence in \p Group.
-bool containsGroup(CloneDetector::CloneGroup &Group,
- CloneDetector::CloneGroup &OtherGroup) {
- // We have less sequences in the current group than we have in the other,
- // so we will never fulfill the requirement for returning true. This is only
- // possible because we know that a sequence in Group can contain at most
- // one sequence in OtherGroup.
- if (Group.Sequences.size() < OtherGroup.Sequences.size())
- return false;
-
- for (StmtSequence &Stmt : Group.Sequences) {
- if (!containsAnyInGroup(Stmt, OtherGroup))
- return false;
- }
- return true;
-}
-} // end anonymous namespace
-
-namespace {
-/// \brief Wrapper around FoldingSetNodeID that it can be used as the template
-/// argument of the StmtDataCollector.
+/// Wrapper around FoldingSetNodeID that it can be used as the template
+/// argument of the StmtDataCollector.
class FoldingSetNodeIDWrapper {
llvm::FoldingSetNodeID &FS;
@@ -658,8 +283,8 @@ public:
};
} // end anonymous namespace
-/// \brief Writes the relevant data from all statements and child statements
-/// in the given StmtSequence into the given FoldingSetNodeID.
+/// Writes the relevant data from all statements and child statements
+/// in the given StmtSequence into the given FoldingSetNodeID.
static void CollectStmtSequenceData(const StmtSequence &Sequence,
FoldingSetNodeIDWrapper &OutputData) {
for (const Stmt *S : Sequence) {
@@ -670,13 +295,13 @@ static void CollectStmtSequenceData(const StmtSequence &Sequence,
if (!Child)
continue;
- CollectStmtSequenceData(StmtSequence(Child, Sequence.getASTContext()),
+ CollectStmtSequenceData(StmtSequence(Child, Sequence.getContainingDecl()),
OutputData);
}
}
}
-/// \brief Returns true if both sequences are clones of each other.
+/// Returns true if both sequences are clones of each other.
static bool areSequencesClones(const StmtSequence &LHS,
const StmtSequence &RHS) {
// We collect the data from all statements in the sequence as we did before
@@ -693,202 +318,271 @@ static bool areSequencesClones(const StmtSequence &LHS,
return DataLHS == DataRHS;
}
-/// \brief Finds all actual clone groups in a single group of presumed clones.
-/// \param Result Output parameter to which all found groups are added.
-/// \param Group A group of presumed clones. The clones are allowed to have a
-/// different variable pattern and may not be actual clones of each
-/// other.
-/// \param CheckVariablePattern If true, every clone in a group that was added
-/// to the output follows the same variable pattern as the other
-/// clones in its group.
-static void createCloneGroups(std::vector<CloneDetector::CloneGroup> &Result,
- const CloneDetector::CloneGroup &Group,
- bool CheckVariablePattern) {
- // We remove the Sequences one by one, so a list is more appropriate.
- std::list<StmtSequence> UnassignedSequences(Group.Sequences.begin(),
- Group.Sequences.end());
-
- // Search for clones as long as there could be clones in UnassignedSequences.
- while (UnassignedSequences.size() > 1) {
-
- // Pick the first Sequence as a protoype for a new clone group.
- StmtSequence Prototype = UnassignedSequences.front();
- UnassignedSequences.pop_front();
-
- CloneDetector::CloneGroup FilteredGroup(Prototype, Group.Signature);
-
- // Analyze the variable pattern of the prototype. Every other StmtSequence
- // needs to have the same pattern to get into the new clone group.
- VariablePattern PrototypeFeatures(Prototype);
-
- // Search all remaining StmtSequences for an identical variable pattern
- // and assign them to our new clone group.
- auto I = UnassignedSequences.begin(), E = UnassignedSequences.end();
- while (I != E) {
- // If the sequence doesn't fit to the prototype, we have encountered
- // an unintended hash code collision and we skip it.
- if (!areSequencesClones(Prototype, *I)) {
- ++I;
- continue;
- }
+void RecursiveCloneTypeIIConstraint::constrain(
+ std::vector<CloneDetector::CloneGroup> &Sequences) {
+ // FIXME: Maybe we can do this in-place and don't need this additional vector.
+ std::vector<CloneDetector::CloneGroup> Result;
- // If we weren't asked to check for a matching variable pattern in clone
- // groups we can add the sequence now to the new clone group.
- // If we were asked to check for matching variable pattern, we first have
- // to check that there are no differences between the two patterns and
- // only proceed if they match.
- if (!CheckVariablePattern ||
- VariablePattern(*I).countPatternDifferences(PrototypeFeatures) == 0) {
- FilteredGroup.Sequences.push_back(*I);
- I = UnassignedSequences.erase(I);
- continue;
- }
+ for (CloneDetector::CloneGroup &Group : Sequences) {
+ // We assume in the following code that the Group is non-empty, so we
+ // skip all empty groups.
+ if (Group.empty())
+ continue;
+
+ std::vector<std::pair<size_t, StmtSequence>> StmtsByHash;
- // We didn't found a matching variable pattern, so we continue with the
- // next sequence.
- ++I;
+ // Generate hash codes for all children of S and save them in StmtsByHash.
+ for (const StmtSequence &S : Group) {
+ saveHash(S.front(), S.getContainingDecl(), StmtsByHash);
}
- // Add a valid clone group to the list of found clone groups.
- if (!FilteredGroup.isValid())
- continue;
+ // Sort hash_codes in StmtsByHash.
+ std::stable_sort(StmtsByHash.begin(), StmtsByHash.end(),
+ [](std::pair<size_t, StmtSequence> LHS,
+ std::pair<size_t, StmtSequence> RHS) {
+ return LHS.first < RHS.first;
+ });
+
+ // Check for each StmtSequence if its successor has the same hash value.
+ // We don't check the last StmtSequence as it has no successor.
+ // Note: The 'size - 1 ' in the condition is safe because we check for an
+ // empty Group vector at the beginning of this function.
+ for (unsigned i = 0; i < StmtsByHash.size() - 1; ++i) {
+ const auto Current = StmtsByHash[i];
+
+ // It's likely that we just found an sequence of StmtSequences that
+ // represent a CloneGroup, so we create a new group and start checking and
+ // adding the StmtSequences in this sequence.
+ CloneDetector::CloneGroup NewGroup;
+
+ size_t PrototypeHash = Current.first;
+
+ for (; i < StmtsByHash.size(); ++i) {
+ // A different hash value means we have reached the end of the sequence.
+ if (PrototypeHash != StmtsByHash[i].first ||
+ !areSequencesClones(StmtsByHash[i].second, Current.second)) {
+ // The current sequence could be the start of a new CloneGroup. So we
+ // decrement i so that we visit it again in the outer loop.
+ // Note: i can never be 0 at this point because we are just comparing
+ // the hash of the Current StmtSequence with itself in the 'if' above.
+ assert(i != 0);
+ --i;
+ break;
+ }
+ // Same hash value means we should add the StmtSequence to the current
+ // group.
+ NewGroup.push_back(StmtsByHash[i].second);
+ }
- Result.push_back(FilteredGroup);
+ // We created a new clone group with matching hash codes and move it to
+ // the result vector.
+ Result.push_back(NewGroup);
+ }
}
+ // Sequences is the output parameter, so we copy our result into it.
+ Sequences = Result;
}
-void CloneDetector::findClones(std::vector<CloneGroup> &Result,
- unsigned MinGroupComplexity,
- bool CheckPatterns) {
- // A shortcut (and necessary for the for-loop later in this function).
- if (Sequences.empty())
- return;
+size_t MinComplexityConstraint::calculateStmtComplexity(
+ const StmtSequence &Seq, const std::string &ParentMacroStack) {
+ if (Seq.empty())
+ return 0;
+
+ size_t Complexity = 1;
+
+ ASTContext &Context = Seq.getASTContext();
+
+ // Look up what macros expanded into the current statement.
+ std::string StartMacroStack = getMacroStack(Seq.getStartLoc(), Context);
+ std::string EndMacroStack = getMacroStack(Seq.getEndLoc(), Context);
+
+ // First, check if ParentMacroStack is not empty which means we are currently
+ // dealing with a parent statement which was expanded from a macro.
+ // If this parent statement was expanded from the same macros as this
+ // statement, we reduce the initial complexity of this statement to zero.
+ // This causes that a group of statements that were generated by a single
+ // macro expansion will only increase the total complexity by one.
+ // Note: This is not the final complexity of this statement as we still
+ // add the complexity of the child statements to the complexity value.
+ if (!ParentMacroStack.empty() && (StartMacroStack == ParentMacroStack &&
+ EndMacroStack == ParentMacroStack)) {
+ Complexity = 0;
+ }
- // We need to search for groups of StmtSequences with the same hash code to
- // create our initial clone groups. By sorting all known StmtSequences by
- // their hash value we make sure that StmtSequences with the same hash code
- // are grouped together in the Sequences vector.
- // Note: We stable sort here because the StmtSequences are added in the order
- // in which they appear in the source file. We want to preserve that order
- // because we also want to report them in that order in the CloneChecker.
- std::stable_sort(Sequences.begin(), Sequences.end(),
- [](std::pair<CloneSignature, StmtSequence> LHS,
- std::pair<CloneSignature, StmtSequence> RHS) {
- return LHS.first.Hash < RHS.first.Hash;
- });
-
- std::vector<CloneGroup> CloneGroups;
-
- // Check for each CloneSignature if its successor has the same hash value.
- // We don't check the last CloneSignature as it has no successor.
- // Note: The 'size - 1' in the condition is safe because we check for an empty
- // Sequences vector at the beginning of this function.
- for (unsigned i = 0; i < Sequences.size() - 1; ++i) {
- const auto Current = Sequences[i];
- const auto Next = Sequences[i + 1];
-
- if (Current.first.Hash != Next.first.Hash)
- continue;
+ // Iterate over the Stmts in the StmtSequence and add their complexity values
+ // to the current complexity value.
+ if (Seq.holdsSequence()) {
+ for (const Stmt *S : Seq) {
+ Complexity += calculateStmtComplexity(
+ StmtSequence(S, Seq.getContainingDecl()), StartMacroStack);
+ }
+ } else {
+ for (const Stmt *S : Seq.front()->children()) {
+ Complexity += calculateStmtComplexity(
+ StmtSequence(S, Seq.getContainingDecl()), StartMacroStack);
+ }
+ }
+ return Complexity;
+}
- // It's likely that we just found an sequence of CloneSignatures that
- // represent a CloneGroup, so we create a new group and start checking and
- // adding the CloneSignatures in this sequence.
- CloneGroup Group;
- Group.Signature = Current.first;
-
- for (; i < Sequences.size(); ++i) {
- const auto &Signature = Sequences[i];
-
- // A different hash value means we have reached the end of the sequence.
- if (Current.first.Hash != Signature.first.Hash) {
- // The current Signature could be the start of a new CloneGroup. So we
- // decrement i so that we visit it again in the outer loop.
- // Note: i can never be 0 at this point because we are just comparing
- // the hash of the Current CloneSignature with itself in the 'if' above.
- assert(i != 0);
- --i;
- break;
- }
+void MatchingVariablePatternConstraint::constrain(
+ std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::splitCloneGroups(
+ CloneGroups, [](const StmtSequence &A, const StmtSequence &B) {
+ VariablePattern PatternA(A);
+ VariablePattern PatternB(B);
+ return PatternA.countPatternDifferences(PatternB) == 0;
+ });
+}
- // Skip CloneSignatures that won't pass the complexity requirement.
- if (Signature.first.Complexity < MinGroupComplexity)
+void CloneConstraint::splitCloneGroups(
+ std::vector<CloneDetector::CloneGroup> &CloneGroups,
+ std::function<bool(const StmtSequence &, const StmtSequence &)> Compare) {
+ std::vector<CloneDetector::CloneGroup> Result;
+ for (auto &HashGroup : CloneGroups) {
+ // Contains all indexes in HashGroup that were already added to a
+ // CloneGroup.
+ std::vector<char> Indexes;
+ Indexes.resize(HashGroup.size());
+
+ for (unsigned i = 0; i < HashGroup.size(); ++i) {
+ // Skip indexes that are already part of a CloneGroup.
+ if (Indexes[i])
continue;
- Group.Sequences.push_back(Signature.second);
- }
+ // Pick the first unhandled StmtSequence and consider it as the
+ // beginning
+ // of a new CloneGroup for now.
+ // We don't add i to Indexes because we never iterate back.
+ StmtSequence Prototype = HashGroup[i];
+ CloneDetector::CloneGroup PotentialGroup = {Prototype};
+ ++Indexes[i];
+
+ // Check all following StmtSequences for clones.
+ for (unsigned j = i + 1; j < HashGroup.size(); ++j) {
+ // Skip indexes that are already part of a CloneGroup.
+ if (Indexes[j])
+ continue;
+
+ // If a following StmtSequence belongs to our CloneGroup, we add it.
+ const StmtSequence &Candidate = HashGroup[j];
+
+ if (!Compare(Prototype, Candidate))
+ continue;
+
+ PotentialGroup.push_back(Candidate);
+ // Make sure we never visit this StmtSequence again.
+ ++Indexes[j];
+ }
- // There is a chance that we haven't found more than two fitting
- // CloneSignature because not enough CloneSignatures passed the complexity
- // requirement. As a CloneGroup with less than two members makes no sense,
- // we ignore this CloneGroup and won't add it to the result.
- if (!Group.isValid())
- continue;
+ // Otherwise, add it to the result and continue searching for more
+ // groups.
+ Result.push_back(PotentialGroup);
+ }
- CloneGroups.push_back(Group);
+ assert(std::all_of(Indexes.begin(), Indexes.end(),
+ [](char c) { return c == 1; }));
}
+ CloneGroups = Result;
+}
- // Add every valid clone group that fulfills the complexity requirement.
- for (const CloneGroup &Group : CloneGroups) {
- createCloneGroups(Result, Group, CheckPatterns);
+void VariablePattern::addVariableOccurence(const VarDecl *VarDecl,
+ const Stmt *Mention) {
+ // First check if we already reference this variable
+ for (size_t KindIndex = 0; KindIndex < Variables.size(); ++KindIndex) {
+ if (Variables[KindIndex] == VarDecl) {
+ // If yes, add a new occurence that points to the existing entry in
+ // the Variables vector.
+ Occurences.emplace_back(KindIndex, Mention);
+ return;
+ }
}
+ // If this variable wasn't already referenced, add it to the list of
+ // referenced variables and add a occurence that points to this new entry.
+ Occurences.emplace_back(Variables.size(), Mention);
+ Variables.push_back(VarDecl);
+}
- std::vector<unsigned> IndexesToRemove;
-
- // Compare every group in the result with the rest. If one groups contains
- // another group, we only need to return the bigger group.
- // Note: This doesn't scale well, so if possible avoid calling any heavy
- // function from this loop to minimize the performance impact.
- for (unsigned i = 0; i < Result.size(); ++i) {
- for (unsigned j = 0; j < Result.size(); ++j) {
- // Don't compare a group with itself.
- if (i == j)
- continue;
+void VariablePattern::addVariables(const Stmt *S) {
+ // Sometimes we get a nullptr (such as from IfStmts which often have nullptr
+ // children). We skip such statements as they don't reference any
+ // variables.
+ if (!S)
+ return;
- if (containsGroup(Result[j], Result[i])) {
- IndexesToRemove.push_back(i);
- break;
- }
- }
+ // Check if S is a reference to a variable. If yes, add it to the pattern.
+ if (auto D = dyn_cast<DeclRefExpr>(S)) {
+ if (auto VD = dyn_cast<VarDecl>(D->getDecl()->getCanonicalDecl()))
+ addVariableOccurence(VD, D);
}
- // Erasing a list of indexes from the vector should be done with decreasing
- // indexes. As IndexesToRemove is constructed with increasing values, we just
- // reverse iterate over it to get the desired order.
- for (auto I = IndexesToRemove.rbegin(); I != IndexesToRemove.rend(); ++I) {
- Result.erase(Result.begin() + *I);
+ // Recursively check all children of the given statement.
+ for (const Stmt *Child : S->children()) {
+ addVariables(Child);
}
}
-void CloneDetector::findSuspiciousClones(
- std::vector<CloneDetector::SuspiciousClonePair> &Result,
- unsigned MinGroupComplexity) {
- std::vector<CloneGroup> Clones;
- // Reuse the normal search for clones but specify that the clone groups don't
- // need to have a common referenced variable pattern so that we can manually
- // search for the kind of pattern errors this function is supposed to find.
- findClones(Clones, MinGroupComplexity, false);
-
- for (const CloneGroup &Group : Clones) {
- for (unsigned i = 0; i < Group.Sequences.size(); ++i) {
- VariablePattern PatternA(Group.Sequences[i]);
-
- for (unsigned j = i + 1; j < Group.Sequences.size(); ++j) {
- VariablePattern PatternB(Group.Sequences[j]);
-
- CloneDetector::SuspiciousClonePair ClonePair;
- // For now, we only report clones which break the variable pattern just
- // once because multiple differences in a pattern are an indicator that
- // those differences are maybe intended (e.g. because it's actually
- // a different algorithm).
- // TODO: In very big clones even multiple variables can be unintended,
- // so replacing this number with a percentage could better handle such
- // cases. On the other hand it could increase the false-positive rate
- // for all clones if the percentage is too high.
- if (PatternA.countPatternDifferences(PatternB, &ClonePair) == 1) {
- Result.push_back(ClonePair);
- break;
- }
- }
- }
+unsigned VariablePattern::countPatternDifferences(
+ const VariablePattern &Other,
+ VariablePattern::SuspiciousClonePair *FirstMismatch) {
+ unsigned NumberOfDifferences = 0;
+
+ assert(Other.Occurences.size() == Occurences.size());
+ for (unsigned i = 0; i < Occurences.size(); ++i) {
+ auto ThisOccurence = Occurences[i];
+ auto OtherOccurence = Other.Occurences[i];
+ if (ThisOccurence.KindID == OtherOccurence.KindID)
+ continue;
+
+ ++NumberOfDifferences;
+
+ // If FirstMismatch is not a nullptr, we need to store information about
+ // the first difference between the two patterns.
+ if (FirstMismatch == nullptr)
+ continue;
+
+ // Only proceed if we just found the first difference as we only store
+ // information about the first difference.
+ if (NumberOfDifferences != 1)
+ continue;
+
+ const VarDecl *FirstSuggestion = nullptr;
+ // If there is a variable available in the list of referenced variables
+ // which wouldn't break the pattern if it is used in place of the
+ // current variable, we provide this variable as the suggested fix.
+ if (OtherOccurence.KindID < Variables.size())
+ FirstSuggestion = Variables[OtherOccurence.KindID];
+
+ // Store information about the first clone.
+ FirstMismatch->FirstCloneInfo =
+ VariablePattern::SuspiciousClonePair::SuspiciousCloneInfo(
+ Variables[ThisOccurence.KindID], ThisOccurence.Mention,
+ FirstSuggestion);
+
+ // Same as above but with the other clone. We do this for both clones as
+ // we don't know which clone is the one containing the unintended
+ // pattern error.
+ const VarDecl *SecondSuggestion = nullptr;
+ if (ThisOccurence.KindID < Other.Variables.size())
+ SecondSuggestion = Other.Variables[ThisOccurence.KindID];
+
+ // Store information about the second clone.
+ FirstMismatch->SecondCloneInfo =
+ VariablePattern::SuspiciousClonePair::SuspiciousCloneInfo(
+ Other.Variables[OtherOccurence.KindID], OtherOccurence.Mention,
+ SecondSuggestion);
+
+ // SuspiciousClonePair guarantees that the first clone always has a
+ // suggested variable associated with it. As we know that one of the two
+ // clones in the pair always has suggestion, we swap the two clones
+ // in case the first clone has no suggested variable which means that
+ // the second clone has a suggested variable and should be first.
+ if (!FirstMismatch->FirstCloneInfo.Suggestion)
+ std::swap(FirstMismatch->FirstCloneInfo, FirstMismatch->SecondCloneInfo);
+
+ // This ensures that we always have at least one suggestion in a pair.
+ assert(FirstMismatch->FirstCloneInfo.Suggestion);
}
+
+ return NumberOfDifferences;
}
diff --git a/contrib/llvm/tools/clang/lib/Analysis/OSLog.cpp b/contrib/llvm/tools/clang/lib/Analysis/OSLog.cpp
index 3e13a15..b298393 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/OSLog.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/OSLog.cpp
@@ -10,11 +10,11 @@
#include "llvm/ADT/SmallBitVector.h"
using namespace clang;
-using llvm::APInt;
using clang::analyze_os_log::OSLogBufferItem;
using clang::analyze_os_log::OSLogBufferLayout;
+namespace {
class OSLogFormatStringHandler
: public analyze_format_string::FormatStringHandler {
private:
@@ -166,6 +166,7 @@ public:
}
}
};
+} // end anonymous namespace
bool clang::analyze_os_log::computeOSLogBufferLayout(
ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
diff --git a/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp
index ed7193e..50a3aa2 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp
@@ -441,6 +441,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return Ctx.IntTy;
+ LLVM_FALLTHROUGH;
default:
return ArgType::Invalid();
}
@@ -465,8 +466,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case LengthModifier::AsIntMax:
return ArgType(Ctx.getIntMaxType(), "intmax_t");
case LengthModifier::AsSizeT:
- // FIXME: How to get the corresponding signed version of size_t?
- return ArgType();
+ return ArgType(Ctx.getSignedSizeType(), "ssize_t");
case LengthModifier::AsInt3264:
return Ctx.getTargetInfo().getTriple().isArch64Bit()
? ArgType(Ctx.LongLongTy, "__int64")
@@ -536,7 +536,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case LengthModifier::AsIntMax:
return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
case LengthModifier::AsSizeT:
- return ArgType(); // FIXME: ssize_t
+ return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
case LengthModifier::AsPtrDiff:
return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
case LengthModifier::AsLongDouble:
diff --git a/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp b/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp
index 614f676..83b545a 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp
@@ -109,6 +109,7 @@ void PseudoConstantAnalysis::RunAnalysis() {
// Do not visit the children
continue;
+ LLVM_FALLTHROUGH;
}
case BO_AddAssign:
case BO_SubAssign:
diff --git a/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp b/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp
index a2f3203..60724ea 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp
@@ -58,6 +58,14 @@ static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S) {
return false;
}
+static bool isBuiltinUnreachable(const Stmt *S) {
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
+ if (const auto *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
+ return FDecl->getIdentifier() &&
+ FDecl->getBuiltinID() == Builtin::BI__builtin_unreachable;
+ return false;
+}
+
static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
// Look to see if the current control flow ends with a 'return', and see if
// 'S' is a substatement. The 'return' may not be the last element in the
@@ -132,15 +140,21 @@ static bool isExpandedFromConfigurationMacro(const Stmt *S,
// so that we can refine it later.
SourceLocation L = S->getLocStart();
if (L.isMacroID()) {
+ SourceManager &SM = PP.getSourceManager();
if (IgnoreYES_NO) {
// The Objective-C constant 'YES' and 'NO'
// are defined as macros. Do not treat them
// as configuration values.
- SourceManager &SM = PP.getSourceManager();
SourceLocation TopL = getTopMostMacro(L, SM);
StringRef MacroName = PP.getImmediateMacroName(TopL);
if (MacroName == "YES" || MacroName == "NO")
return false;
+ } else if (!PP.getLangOpts().CPlusPlus) {
+ // Do not treat C 'false' and 'true' macros as configuration values.
+ SourceLocation TopL = getTopMostMacro(L, SM);
+ StringRef MacroName = PP.getImmediateMacroName(TopL);
+ if (MacroName == "false" || MacroName == "true")
+ return false;
}
return true;
}
@@ -586,8 +600,7 @@ void DeadCodeScan::reportDeadCode(const CFGBlock *B,
if (isa<BreakStmt>(S)) {
UK = reachable_code::UK_Break;
- }
- else if (isTrivialDoWhile(B, S)) {
+ } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S)) {
return;
}
else if (isDeadReturn(B, S)) {
diff --git a/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp
index 3b93f1a..5342259 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp
@@ -341,6 +341,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return ArgType::PtrTo(ArgType::AnyCharTy);
+ LLVM_FALLTHROUGH;
default:
return ArgType::Invalid();
}
@@ -357,6 +358,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return ArgType::PtrTo(ArgType::AnyCharTy);
+ LLVM_FALLTHROUGH;
default:
return ArgType::Invalid();
}
diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp
index 2923f7e6..83aa904 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyTIL.cpp
@@ -186,8 +186,8 @@ int BasicBlock::topologicalSort(SimpleArray<BasicBlock*>& Blocks, int ID) {
//
// This sort assumes that (1) dominators have been computed, (2) there are no
// critical edges, and (3) the entry block is reachable from the exit block
-// and no blocks are accessable via traversal of back-edges from the exit that
-// weren't accessable via forward edges from the entry.
+// and no blocks are accessible via traversal of back-edges from the exit that
+// weren't accessible via forward edges from the entry.
int BasicBlock::topologicalFinalSort(SimpleArray<BasicBlock*>& Blocks, int ID) {
// Visited is assumed to have been set by the topologicalSort. This pass
// assumes !Visited means that we've visited this node before.
diff --git a/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp b/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp
index c215366..b7570d0 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp
@@ -1,4 +1,5 @@
#include "clang/Basic/Attributes.h"
+#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -15,3 +16,13 @@ int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
return 0;
}
+
+const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
+ switch (Rule) {
+#define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract) \
+ case attr::NAME: \
+ return SPELLING;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+ llvm_unreachable("Invalid subject match rule");
+}
diff --git a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp
index 7529c47..c355445d 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp
@@ -16,6 +16,7 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
@@ -66,18 +67,12 @@ DiagnosticsEngine::DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> diags,
ArgToStringCookie = nullptr;
AllExtensionsSilenced = 0;
- IgnoreAllWarnings = false;
- WarningsAsErrors = false;
- EnableAllWarnings = false;
- ErrorsAsFatal = false;
- FatalsAsError = false;
- SuppressSystemWarnings = false;
+ SuppressAfterFatalError = true;
SuppressAllDiagnostics = false;
ElideType = true;
PrintTemplateTree = false;
ShowColors = false;
ShowOverloads = Ovl_All;
- ExtBehavior = diag::Severity::Ignored;
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
@@ -131,13 +126,13 @@ void DiagnosticsEngine::Reset() {
// Clear state related to #pragma diagnostic.
DiagStates.clear();
- DiagStatePoints.clear();
+ DiagStatesByLoc.clear();
DiagStateOnPushStack.clear();
// Create a DiagState and DiagStatePoint representing diagnostic changes
// through command-line.
DiagStates.emplace_back();
- DiagStatePoints.push_back(DiagStatePoint(&DiagStates.back(), FullSourceLoc()));
+ DiagStatesByLoc.appendFirst(&DiagStates.back());
}
void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
@@ -151,33 +146,99 @@ 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;
}
-DiagnosticsEngine::DiagStatePointsTy::iterator
-DiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const {
- assert(!DiagStatePoints.empty());
- assert(DiagStatePoints.front().Loc.isInvalid() &&
- "Should have created a DiagStatePoint for command-line");
+void DiagnosticsEngine::DiagStateMap::appendFirst(
+ DiagState *State) {
+ assert(Files.empty() && "not first");
+ FirstDiagState = CurDiagState = State;
+ CurDiagStateLoc = SourceLocation();
+}
+
+void DiagnosticsEngine::DiagStateMap::append(SourceManager &SrcMgr,
+ SourceLocation Loc,
+ DiagState *State) {
+ CurDiagState = State;
+ CurDiagStateLoc = Loc;
+
+ std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
+ unsigned Offset = Decomp.second;
+ for (File *F = getFile(SrcMgr, Decomp.first); F;
+ Offset = F->ParentOffset, F = F->Parent) {
+ F->HasLocalTransitions = true;
+ auto &Last = F->StateTransitions.back();
+ assert(Last.Offset <= Offset && "state transitions added out of order");
+
+ if (Last.Offset == Offset) {
+ if (Last.State == State)
+ break;
+ Last.State = State;
+ continue;
+ }
+
+ F->StateTransitions.push_back({State, Offset});
+ }
+}
- if (!SourceMgr)
- return DiagStatePoints.end() - 1;
+DiagnosticsEngine::DiagState *
+DiagnosticsEngine::DiagStateMap::lookup(SourceManager &SrcMgr,
+ SourceLocation Loc) const {
+ // Common case: we have not seen any diagnostic pragmas.
+ if (Files.empty())
+ return FirstDiagState;
- FullSourceLoc Loc(L, *SourceMgr);
- if (Loc.isInvalid())
- return DiagStatePoints.end() - 1;
+ std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
+ const File *F = getFile(SrcMgr, Decomp.first);
+ return F->lookup(Decomp.second);
+}
+
+DiagnosticsEngine::DiagState *
+DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const {
+ auto OnePastIt = std::upper_bound(
+ StateTransitions.begin(), StateTransitions.end(), Offset,
+ [](unsigned Offset, const DiagStatePoint &P) {
+ return Offset < P.Offset;
+ });
+ assert(OnePastIt != StateTransitions.begin() && "missing initial state");
+ return OnePastIt[-1].State;
+}
+
+DiagnosticsEngine::DiagStateMap::File *
+DiagnosticsEngine::DiagStateMap::getFile(SourceManager &SrcMgr,
+ FileID ID) const {
+ // Get or insert the File for this ID.
+ auto Range = Files.equal_range(ID);
+ if (Range.first != Range.second)
+ return &Range.first->second;
+ auto &F = Files.insert(Range.first, std::make_pair(ID, File()))->second;
+
+ // We created a new File; look up the diagnostic state at the start of it and
+ // initialize it.
+ if (ID.isValid()) {
+ std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedIncludedLoc(ID);
+ F.Parent = getFile(SrcMgr, Decomp.first);
+ F.ParentOffset = Decomp.second;
+ F.StateTransitions.push_back({F.Parent->lookup(Decomp.second), 0});
+ } else {
+ // This is the (imaginary) root file into which we pretend all top-level
+ // files are included; it descends from the initial state.
+ //
+ // FIXME: This doesn't guarantee that we use the same ordering as
+ // isBeforeInTranslationUnit in the cases where someone invented another
+ // top-level file and added diagnostic pragmas to it. See the code at the
+ // end of isBeforeInTranslationUnit for the quirks it deals with.
+ F.StateTransitions.push_back({FirstDiagState, 0});
+ }
+ return &F;
+}
- DiagStatePointsTy::iterator Pos = DiagStatePoints.end();
- FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
- if (LastStateChangePos.isValid() &&
- Loc.isBeforeInTranslationUnitThan(LastStateChangePos))
- Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(),
- DiagStatePoint(nullptr, Loc));
- --Pos;
- return Pos;
+void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,
+ SourceLocation Loc) {
+ assert(Loc.isValid() && "Adding invalid loc point");
+ DiagStatesByLoc.append(*SourceMgr, Loc, State);
}
void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
@@ -187,65 +248,38 @@ void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
assert((Diags->isBuiltinWarningOrExtension(Diag) ||
(Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
"Cannot map errors into warnings!");
- assert(!DiagStatePoints.empty());
assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
- FullSourceLoc Loc = SourceMgr? FullSourceLoc(L, *SourceMgr) : FullSourceLoc();
- FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
// Don't allow a mapping to a warning override an error/fatal mapping.
+ bool WasUpgradedFromWarning = false;
if (Map == diag::Severity::Warning) {
DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
if (Info.getSeverity() == diag::Severity::Error ||
- Info.getSeverity() == diag::Severity::Fatal)
+ Info.getSeverity() == diag::Severity::Fatal) {
Map = Info.getSeverity();
+ WasUpgradedFromWarning = true;
+ }
}
DiagnosticMapping Mapping = makeUserMapping(Map, L);
+ Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
// Common case; setting all the diagnostics of a group in one place.
- if (Loc.isInvalid() || Loc == LastStateChangePos) {
- GetCurDiagState()->setMapping(Diag, Mapping);
+ if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) &&
+ DiagStatesByLoc.getCurDiagState()) {
+ // FIXME: This is theoretically wrong: if the current state is shared with
+ // some other location (via push/pop) we will change the state for that
+ // other location as well. This cannot currently happen, as we can't update
+ // the diagnostic state at the same location at which we pop.
+ DiagStatesByLoc.getCurDiagState()->setMapping(Diag, Mapping);
return;
}
- // Another common case; modifying diagnostic state in a source location
- // after the previous one.
- if ((Loc.isValid() && LastStateChangePos.isInvalid()) ||
- LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) {
- // A diagnostic pragma occurred, create a new DiagState initialized with
- // the current one and a new DiagStatePoint to record at which location
- // the new state became active.
- DiagStates.push_back(*GetCurDiagState());
- PushDiagStatePoint(&DiagStates.back(), Loc);
- GetCurDiagState()->setMapping(Diag, Mapping);
- return;
- }
-
- // We allow setting the diagnostic state in random source order for
- // completeness but it should not be actually happening in normal practice.
-
- DiagStatePointsTy::iterator Pos = GetDiagStatePointForLoc(Loc);
- assert(Pos != DiagStatePoints.end());
-
- // Update all diagnostic states that are active after the given location.
- for (DiagStatePointsTy::iterator
- I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
- I->State->setMapping(Diag, Mapping);
- }
-
- // If the location corresponds to an existing point, just update its state.
- if (Pos->Loc == Loc) {
- Pos->State->setMapping(Diag, Mapping);
- return;
- }
-
- // Create a new state/point and fit it into the vector of DiagStatePoints
- // so that the vector is always ordered according to location.
- assert(Pos->Loc.isBeforeInTranslationUnitThan(Loc));
- DiagStates.push_back(*Pos->State);
- DiagState *NewState = &DiagStates.back();
- NewState->setMapping(Diag, Mapping);
- DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
- FullSourceLoc(Loc, *SourceMgr)));
+ // A diagnostic pragma occurred, create a new DiagState initialized with
+ // the current one and a new DiagStatePoint to record at which location
+ // the new state became active.
+ DiagStates.push_back(*GetCurDiagState());
+ DiagStates.back().setMapping(Diag, Mapping);
+ PushDiagStatePoint(&DiagStates.back(), L);
}
bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
@@ -302,8 +336,8 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
diag::Severity::Fatal);
- // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
- // potentially downgrade anything already mapped to be an error.
+ // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
+ // and potentially downgrade anything already mapped to be a fatal error.
// Get the diagnostics in this group.
SmallVector<diag::kind, 8> GroupDiags;
@@ -385,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/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp
index 3c370f6..0cdaf8e 100644
--- a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp
@@ -411,11 +411,8 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// to error. Errors can only be mapped to fatal.
diag::Severity Result = diag::Severity::Fatal;
- DiagnosticsEngine::DiagStatePointsTy::iterator
- Pos = Diag.GetDiagStatePointForLoc(Loc);
- DiagnosticsEngine::DiagState *State = Pos->State;
-
// Get the mapping information, or compute it lazily.
+ DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc);
DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
// TODO: Can a null severity really get here?
@@ -423,7 +420,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
Result = Mapping.getSeverity();
// Upgrade ignored diagnostics if -Weverything is enabled.
- if (Diag.EnableAllWarnings && Result == diag::Severity::Ignored &&
+ if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
!Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
Result = diag::Severity::Warning;
@@ -438,7 +435,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// For extension diagnostics that haven't been explicitly mapped, check if we
// should upgrade the diagnostic.
if (IsExtensionDiag && !Mapping.isUser())
- Result = std::max(Result, Diag.ExtBehavior);
+ Result = std::max(Result, State->ExtBehavior);
// At this point, ignored errors can no longer be upgraded.
if (Result == diag::Severity::Ignored)
@@ -446,28 +443,24 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// Honor -w, which is lower in priority than pedantic-errors, but higher than
// -Werror.
- if (Result == diag::Severity::Warning && Diag.IgnoreAllWarnings)
+ // FIXME: Under GCC, this also suppresses warnings that have been mapped to
+ // errors by -W flags and #pragma diagnostic.
+ if (Result == diag::Severity::Warning && State->IgnoreAllWarnings)
return diag::Severity::Ignored;
// If -Werror is enabled, map warnings to errors unless explicitly disabled.
if (Result == diag::Severity::Warning) {
- if (Diag.WarningsAsErrors && !Mapping.hasNoWarningAsError())
+ if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
Result = diag::Severity::Error;
}
// If -Wfatal-errors is enabled, map errors to fatal unless explicity
// disabled.
if (Result == diag::Severity::Error) {
- if (Diag.ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
+ if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
Result = diag::Severity::Fatal;
}
- // If explicitly requested, map fatal errors to errors.
- if (Result == diag::Severity::Fatal) {
- if (Diag.FatalsAsError)
- Result = diag::Severity::Error;
- }
-
// Custom diagnostics always are emitted in system headers.
bool ShowInSystemHeader =
!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
@@ -475,7 +468,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
// If we are in a system header, we ignore it. We look at the diagnostic class
// because we also want to ignore extensions and warnings in -Werror and
// -pedantic-errors modes, which *map* warnings/extensions to errors.
- if (Diag.SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
+ if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
Diag.getSourceManager().isInSystemHeader(
Diag.getSourceManager().getExpansionLoc(Loc)))
return diag::Severity::Ignored;
@@ -517,6 +510,18 @@ StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
return StringRef();
}
+std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
+ std::vector<std::string> Res;
+ for (size_t I = 1; DiagGroupNames[I] != '\0';) {
+ std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);
+ I += DiagGroupNames[I] + 1;
+ Res.push_back("-W" + Diag);
+ Res.push_back("-Wno-" + Diag);
+ }
+
+ return Res;
+}
+
/// Return \c true if any diagnostics were found in this group, even if they
/// were filtered out due to having the wrong flavor.
static bool getDiagnosticsInGroup(diag::Flavor Flavor,
@@ -635,7 +640,7 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
// If a fatal error has already been emitted, silence all subsequent
// diagnostics.
- if (Diag.FatalErrorOccurred) {
+ if (Diag.FatalErrorOccurred && Diag.SuppressAfterFatalError) {
if (DiagLevel >= DiagnosticIDs::Error &&
Diag.Client->IncludeInDiagnosticCounts()) {
++Diag.NumErrors;
@@ -673,6 +678,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/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp
index 50050d0..0c10b5f 100644
--- a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp
@@ -50,14 +50,14 @@ using namespace clang;
FileManager::FileManager(const FileSystemOptions &FSO,
IntrusiveRefCntPtr<vfs::FileSystem> FS)
- : FS(FS), FileSystemOpts(FSO),
- SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) {
+ : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64),
+ SeenFileEntries(64), NextFileUID(0) {
NumDirLookups = NumFileLookups = 0;
NumDirCacheMisses = NumFileCacheMisses = 0;
// If the caller doesn't provide a virtual file system, just grab the real
// file system.
- if (!FS)
+ if (!this->FS)
this->FS = vfs::getRealFileSystem();
}
@@ -386,6 +386,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
UFE->ModTime = ModificationTime;
UFE->Dir = DirInfo;
UFE->UID = NextFileUID++;
+ UFE->IsValid = true;
UFE->File.reset();
return UFE;
}
diff --git a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp
index af424cd..372e0c4 100644
--- a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp
@@ -244,7 +244,7 @@ static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts,
/// \brief Returns true if the identifier represents a keyword in the
/// specified language.
-bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) {
+bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const {
switch (getTokenKwStatus(LangOpts, getTokenID())) {
case KS_Enabled:
case KS_Extension:
@@ -254,6 +254,19 @@ bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) {
}
}
+/// \brief Returns true if the identifier represents a C++ keyword in the
+/// specified language.
+bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const {
+ if (!LangOpts.CPlusPlus || !isKeyword(LangOpts))
+ return false;
+ // This is a C++ keyword if this identifier is not a keyword when checked
+ // using LangOptions without C++ support.
+ LangOptions LangOptsNoCPP = LangOpts;
+ LangOptsNoCPP.CPlusPlus = false;
+ LangOptsNoCPP.CPlusPlus11 = false;
+ return !isKeyword(LangOptsNoCPP);
+}
+
tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
// We use a perfect hash function here involving the length of the keyword,
// the first and third character. For preprocessor ID's there are no
@@ -487,8 +500,10 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
if (name == "self") return OMF_self;
if (name == "initialize") return OMF_initialize;
}
-
- if (name == "performSelector") return OMF_performSelector;
+
+ if (name == "performSelector" || name == "performSelectorInBackground" ||
+ name == "performSelectorOnMainThread")
+ return OMF_performSelector;
// The other method families may begin with a prefix of underscores.
while (!name.empty() && name.front() == '_')
@@ -536,6 +551,7 @@ ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
case 's':
if (startsWithWord(name, "shared")) return OIT_ReturnsSelf;
if (startsWithWord(name, "standard")) return OIT_Singleton;
+ break;
case 'i':
if (startsWithWord(name, "init")) return OIT_Init;
default:
diff --git a/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp b/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp
index ff10a77..db81507 100644
--- a/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp
@@ -29,10 +29,10 @@ void LangOptions::resetNonModularOptions() {
Name = Default;
#include "clang/Basic/LangOptions.def"
- // FIXME: This should not be reset; modules can be different with different
- // sanitizer options (this affects __has_feature(address_sanitizer) etc).
- Sanitize.clear();
+ // These options do not affect AST generation.
SanitizerBlacklistFiles.clear();
+ XRayAlwaysInstrumentFiles.clear();
+ XRayNeverInstrumentFiles.clear();
CurrentModule.clear();
IsHeaderFile = false;
diff --git a/contrib/llvm/tools/clang/lib/Basic/MemoryBufferCache.cpp b/contrib/llvm/tools/clang/lib/Basic/MemoryBufferCache.cpp
new file mode 100644
index 0000000..c1fc571
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Basic/MemoryBufferCache.cpp
@@ -0,0 +1,48 @@
+//===- MemoryBufferCache.cpp - Cache for loaded memory buffers ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/MemoryBufferCache.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace clang;
+
+llvm::MemoryBuffer &
+MemoryBufferCache::addBuffer(llvm::StringRef Filename,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+ auto Insertion =
+ Buffers.insert({Filename, BufferEntry{std::move(Buffer), NextIndex++}});
+ assert(Insertion.second && "Already has a buffer");
+ return *Insertion.first->second.Buffer;
+}
+
+llvm::MemoryBuffer *MemoryBufferCache::lookupBuffer(llvm::StringRef Filename) {
+ auto I = Buffers.find(Filename);
+ if (I == Buffers.end())
+ return nullptr;
+ return I->second.Buffer.get();
+}
+
+bool MemoryBufferCache::isBufferFinal(llvm::StringRef Filename) {
+ auto I = Buffers.find(Filename);
+ if (I == Buffers.end())
+ return false;
+ return I->second.Index < FirstRemovableIndex;
+}
+
+bool MemoryBufferCache::tryToRemoveBuffer(llvm::StringRef Filename) {
+ auto I = Buffers.find(Filename);
+ assert(I != Buffers.end() && "No buffer to remove...");
+ if (I->second.Index < FirstRemovableIndex)
+ return true;
+
+ Buffers.erase(I);
+ return false;
+}
+
+void MemoryBufferCache::finalizeCurrentBuffers() { FirstRemovableIndex = NextIndex; }
diff --git a/contrib/llvm/tools/clang/lib/Basic/Module.cpp b/contrib/llvm/tools/clang/lib/Basic/Module.cpp
index 80bbc24..1d96afd 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Module.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/Module.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Module.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
@@ -27,7 +28,7 @@ using namespace clang;
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
bool IsFramework, bool IsExplicit, unsigned VisibilityID)
: Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), Directory(),
- Umbrella(), Signature(0), ASTFile(nullptr), VisibilityID(VisibilityID),
+ Umbrella(), ASTFile(nullptr), VisibilityID(VisibilityID),
IsMissingRequirement(false), HasIncompatibleModuleFile(false),
IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework),
IsExplicit(IsExplicit), IsSystem(false), IsExternC(false),
@@ -64,6 +65,7 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
bool HasFeature = llvm::StringSwitch<bool>(Feature)
.Case("altivec", LangOpts.AltiVec)
.Case("blocks", LangOpts.Blocks)
+ .Case("coroutines", LangOpts.CoroutinesTS)
.Case("cplusplus", LangOpts.CPlusPlus)
.Case("cplusplus11", LangOpts.CPlusPlus11)
.Case("freestanding", LangOpts.Freestanding)
@@ -124,7 +126,36 @@ const Module *Module::getTopLevelModule() const {
return Result;
}
-std::string Module::getFullModuleName() const {
+static StringRef getModuleNameFromComponent(
+ const std::pair<std::string, SourceLocation> &IdComponent) {
+ return IdComponent.first;
+}
+static StringRef getModuleNameFromComponent(StringRef R) { return R; }
+
+template<typename InputIter>
+static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End,
+ bool AllowStringLiterals = true) {
+ for (InputIter It = Begin; It != End; ++It) {
+ if (It != Begin)
+ OS << ".";
+
+ StringRef Name = getModuleNameFromComponent(*It);
+ if (!AllowStringLiterals || isValidIdentifier(Name))
+ OS << Name;
+ else {
+ OS << '"';
+ OS.write_escaped(Name);
+ OS << '"';
+ }
+ }
+}
+
+template<typename Container>
+static void printModuleId(raw_ostream &OS, const Container &C) {
+ return printModuleId(OS, C.begin(), C.end());
+}
+
+std::string Module::getFullModuleName(bool AllowStringLiterals) const {
SmallVector<StringRef, 2> Names;
// Build up the set of module names (from innermost to outermost).
@@ -132,15 +163,11 @@ std::string Module::getFullModuleName() const {
Names.push_back(M->Name);
std::string Result;
- for (SmallVectorImpl<StringRef>::reverse_iterator I = Names.rbegin(),
- IEnd = Names.rend();
- I != IEnd; ++I) {
- if (!Result.empty())
- Result += '.';
-
- Result += *I;
- }
-
+
+ llvm::raw_string_ostream Out(Result);
+ printModuleId(Out, Names.rbegin(), Names.rend(), AllowStringLiterals);
+ Out.flush();
+
return Result;
}
@@ -239,14 +266,6 @@ Module *Module::findSubmodule(StringRef Name) const {
return SubModules[Pos->getValue()];
}
-static void printModuleId(raw_ostream &OS, const ModuleId &Id) {
- for (unsigned I = 0, N = Id.size(); I != N; ++I) {
- if (I)
- OS << ".";
- OS << Id[I].first;
- }
-}
-
void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
// All non-explicit submodules are exported.
for (std::vector<Module *>::const_iterator I = SubModules.begin(),
@@ -333,7 +352,8 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS << "framework ";
if (IsExplicit)
OS << "explicit ";
- OS << "module " << Name;
+ OS << "module ";
+ printModuleId(OS, &Name, &Name + 1);
if (IsSystem || IsExternC) {
OS.indent(Indent + 2);
@@ -393,11 +413,30 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
{"exclude ", HK_Excluded}};
for (auto &K : Kinds) {
+ assert(&K == &Kinds[K.Kind] && "kinds in wrong order");
for (auto &H : Headers[K.Kind]) {
OS.indent(Indent + 2);
OS << K.Prefix << "header \"";
OS.write_escaped(H.NameAsWritten);
- OS << "\"\n";
+ OS << "\" { size " << H.Entry->getSize()
+ << " mtime " << H.Entry->getModificationTime() << " }\n";
+ }
+ }
+ for (auto *Unresolved : {&UnresolvedHeaders, &MissingHeaders}) {
+ for (auto &U : *Unresolved) {
+ OS.indent(Indent + 2);
+ OS << Kinds[U.Kind].Prefix << "header \"";
+ OS.write_escaped(U.FileName);
+ OS << "\"";
+ if (U.Size || U.ModTime) {
+ OS << " {";
+ if (U.Size)
+ OS << " size " << *U.Size;
+ if (U.ModTime)
+ OS << " mtime " << *U.ModTime;
+ OS << " }";
+ }
+ OS << "\n";
}
}
@@ -414,7 +453,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS.indent(Indent + 2);
OS << "export ";
if (Module *Restriction = Exports[I].getPointer()) {
- OS << Restriction->getFullModuleName();
+ OS << Restriction->getFullModuleName(true);
if (Exports[I].getInt())
OS << ".*";
} else {
@@ -435,7 +474,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) {
OS.indent(Indent + 2);
OS << "use ";
- OS << DirectUses[I]->getFullModuleName();
+ OS << DirectUses[I]->getFullModuleName(true);
OS << "\n";
}
@@ -468,7 +507,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) {
OS.indent(Indent + 2);
OS << "conflict ";
- OS << Conflicts[I].Other->getFullModuleName();
+ OS << Conflicts[I].Other->getFullModuleName(true);
OS << ", \"";
OS.write_escaped(Conflicts[I].Message);
OS << "\"\n";
diff --git a/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp b/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp
index 905c369..050c0cc 100644
--- a/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp
@@ -138,6 +138,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
@@ -277,6 +278,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
@@ -710,6 +712,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
}
break;
+ case OMPD_taskgroup:
+ switch (CKind) {
+#define OPENMP_TASKGROUP_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_unknown:
@@ -719,7 +731,6 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
- case OMPD_taskgroup:
case OMPD_cancellation_point:
case OMPD_declare_reduction:
break;
@@ -840,7 +851,8 @@ bool clang::isOpenMPDistributeDirective(OpenMPDirectiveKind Kind) {
bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) {
return Kind == OMPC_private || Kind == OMPC_firstprivate ||
Kind == OMPC_lastprivate || Kind == OMPC_linear ||
- Kind == OMPC_reduction; // TODO add next clauses like 'reduction'.
+ Kind == OMPC_reduction ||
+ Kind == OMPC_task_reduction; // TODO add next clauses like 'reduction'.
}
bool clang::isOpenMPThreadPrivate(OpenMPClauseKind Kind) {
@@ -854,12 +866,81 @@ bool clang::isOpenMPTaskingDirective(OpenMPDirectiveKind Kind) {
bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) {
return Kind == OMPD_distribute_parallel_for ||
Kind == OMPD_distribute_parallel_for_simd ||
- Kind == OMPD_distribute_simd || Kind == OMPD_teams_distribute ||
- Kind == OMPD_teams_distribute_simd ||
Kind == OMPD_teams_distribute_parallel_for_simd ||
Kind == OMPD_teams_distribute_parallel_for ||
- Kind == OMPD_target_teams_distribute ||
Kind == OMPD_target_teams_distribute_parallel_for ||
- Kind == OMPD_target_teams_distribute_parallel_for_simd ||
- Kind == OMPD_target_teams_distribute_simd;
+ Kind == OMPD_target_teams_distribute_parallel_for_simd;
+}
+
+void clang::getOpenMPCaptureRegions(
+ SmallVectorImpl<OpenMPDirectiveKind> &CaptureRegions,
+ OpenMPDirectiveKind DKind) {
+ assert(DKind <= OMPD_unknown);
+ switch (DKind) {
+ case OMPD_parallel:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_parallel_sections:
+ case OMPD_distribute_parallel_for:
+ CaptureRegions.push_back(OMPD_parallel);
+ break;
+ case OMPD_target_teams:
+ CaptureRegions.push_back(OMPD_target);
+ CaptureRegions.push_back(OMPD_teams);
+ break;
+ case OMPD_teams:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_target_data:
+ case OMPD_target:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_simd:
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_distribute_simd:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_teams_distribute_simd:
+ CaptureRegions.push_back(DKind);
+ break;
+ case OMPD_target_parallel:
+ CaptureRegions.push_back(OMPD_target);
+ CaptureRegions.push_back(OMPD_parallel);
+ break;
+ case OMPD_threadprivate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_cancel:
+ case OMPD_flush:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_target_update:
+ llvm_unreachable("OpenMP Directive is not allowed");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
}
diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp
index a58d046..89ddbc9 100644
--- a/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp
@@ -92,6 +92,76 @@ FullSourceLoc FullSourceLoc::getSpellingLoc() const {
return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr);
}
+FullSourceLoc FullSourceLoc::getFileLoc() const {
+ assert(isValid());
+ return FullSourceLoc(SrcMgr->getFileLoc(*this), *SrcMgr);
+}
+
+std::pair<FullSourceLoc, FullSourceLoc>
+FullSourceLoc::getImmediateExpansionRange() const {
+ assert(isValid());
+ std::pair<SourceLocation, SourceLocation> Range =
+ SrcMgr->getImmediateExpansionRange(*this);
+ return std::make_pair(FullSourceLoc(Range.first, *SrcMgr),
+ FullSourceLoc(Range.second, *SrcMgr));
+}
+
+PresumedLoc FullSourceLoc::getPresumedLoc(bool UseLineDirectives) const {
+ if (!isValid())
+ return PresumedLoc();
+
+ return SrcMgr->getPresumedLoc(*this, UseLineDirectives);
+}
+
+bool FullSourceLoc::isMacroArgExpansion(FullSourceLoc *StartLoc) const {
+ assert(isValid());
+ return SrcMgr->isMacroArgExpansion(*this, StartLoc);
+}
+
+FullSourceLoc FullSourceLoc::getImmediateMacroCallerLoc() const {
+ assert(isValid());
+ return FullSourceLoc(SrcMgr->getImmediateMacroCallerLoc(*this), *SrcMgr);
+}
+
+std::pair<FullSourceLoc, StringRef> FullSourceLoc::getModuleImportLoc() const {
+ if (!isValid())
+ return std::make_pair(FullSourceLoc(), StringRef());
+
+ std::pair<SourceLocation, StringRef> ImportLoc =
+ SrcMgr->getModuleImportLoc(*this);
+ return std::make_pair(FullSourceLoc(ImportLoc.first, *SrcMgr),
+ ImportLoc.second);
+}
+
+unsigned FullSourceLoc::getFileOffset() const {
+ assert(isValid());
+ return SrcMgr->getFileOffset(*this);
+}
+
+unsigned FullSourceLoc::getLineNumber(bool *Invalid) const {
+ assert(isValid());
+ return SrcMgr->getLineNumber(getFileID(), getFileOffset(), Invalid);
+}
+
+unsigned FullSourceLoc::getColumnNumber(bool *Invalid) const {
+ assert(isValid());
+ return SrcMgr->getColumnNumber(getFileID(), getFileOffset(), Invalid);
+}
+
+std::pair<FullSourceLoc, FullSourceLoc>
+FullSourceLoc::getExpansionRange() const {
+ assert(isValid());
+ std::pair<SourceLocation, SourceLocation> Range =
+ SrcMgr->getExpansionRange(*this);
+ return std::make_pair(FullSourceLoc(Range.first, *SrcMgr),
+ FullSourceLoc(Range.second, *SrcMgr));
+}
+
+const FileEntry *FullSourceLoc::getFileEntry() const {
+ assert(isValid());
+ return SrcMgr->getFileEntryForID(getFileID());
+}
+
unsigned FullSourceLoc::getExpansionLineNumber(bool *Invalid) const {
assert(isValid());
return SrcMgr->getExpansionLineNumber(*this, Invalid);
diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp
index 380ca37..f0b53b4 100644
--- a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp
@@ -73,11 +73,11 @@ void ContentCache::replaceBuffer(llvm::MemoryBuffer *B, bool DoNotFree) {
Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
return;
}
-
+
if (shouldFreeBuffer())
delete Buffer.getPointer();
Buffer.setPointer(B);
- Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
+ Buffer.setInt((B && DoNotFree) ? DoNotFreeFlag : 0);
}
llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
@@ -183,48 +183,22 @@ unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) {
return IterBool.first->second;
}
-/// AddLineNote - Add a line note to the line table that indicates that there
-/// is a \#line at the specified FID/Offset location which changes the presumed
-/// location to LineNo/FilenameID.
-void LineTableInfo::AddLineNote(FileID FID, unsigned Offset,
- unsigned LineNo, int FilenameID) {
- std::vector<LineEntry> &Entries = LineEntries[FID];
-
- assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
- "Adding line entries out of order!");
-
- SrcMgr::CharacteristicKind Kind = SrcMgr::C_User;
- unsigned IncludeOffset = 0;
-
- if (!Entries.empty()) {
- // If this is a '#line 4' after '#line 42 "foo.h"', make sure to remember
- // that we are still in "foo.h".
- if (FilenameID == -1)
- FilenameID = Entries.back().FilenameID;
-
- // If we are after a line marker that switched us to system header mode, or
- // that set #include information, preserve it.
- Kind = Entries.back().FileKind;
- IncludeOffset = Entries.back().IncludeOffset;
- }
-
- Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind,
- IncludeOffset));
-}
-
-/// AddLineNote This is the same as the previous version of AddLineNote, but is
-/// used for GNU line markers. If EntryExit is 0, then this doesn't change the
-/// presumed \#include stack. If it is 1, this is a file entry, if it is 2 then
-/// this is a file exit. FileKind specifies whether this is a system header or
-/// extern C system header.
-void LineTableInfo::AddLineNote(FileID FID, unsigned Offset,
- unsigned LineNo, int FilenameID,
- unsigned EntryExit,
+/// Add a line note to the line table that indicates that there is a \#line or
+/// GNU line marker at the specified FID/Offset location which changes the
+/// presumed location to LineNo/FilenameID. If EntryExit is 0, then this doesn't
+/// change the presumed \#include stack. If it is 1, this is a file entry, if
+/// it is 2 then this is a file exit. FileKind specifies whether this is a
+/// system header or extern C system header.
+void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo,
+ int FilenameID, unsigned EntryExit,
SrcMgr::CharacteristicKind FileKind) {
- assert(FilenameID != -1 && "Unspecified filename should use other accessor");
-
std::vector<LineEntry> &Entries = LineEntries[FID];
+ // An unspecified FilenameID means use the last filename if available, or the
+ // main source file otherwise.
+ if (FilenameID == -1 && !Entries.empty())
+ FilenameID = Entries.back().FilenameID;
+
assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
"Adding line entries out of order!");
@@ -281,47 +255,20 @@ unsigned SourceManager::getLineTableFilenameID(StringRef Name) {
return getLineTable().getLineTableFilenameID(Name);
}
-
/// AddLineNote - Add a line note to the line table for the FileID and offset
/// specified by Loc. If FilenameID is -1, it is considered to be
/// unspecified.
void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
- int FilenameID) {
- std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
-
- bool Invalid = false;
- const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
- if (!Entry.isFile() || Invalid)
- return;
-
- const SrcMgr::FileInfo &FileInfo = Entry.getFile();
-
- // Remember that this file has #line directives now if it doesn't already.
- const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
-
- getLineTable().AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID);
-}
-
-/// AddLineNote - Add a GNU line marker to the line table.
-void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
int FilenameID, bool IsFileEntry,
- bool IsFileExit, bool IsSystemHeader,
- bool IsExternCHeader) {
- // If there is no filename and no flags, this is treated just like a #line,
- // which does not change the flags of the previous line marker.
- if (FilenameID == -1) {
- assert(!IsFileEntry && !IsFileExit && !IsSystemHeader && !IsExternCHeader &&
- "Can't set flags without setting the filename!");
- return AddLineNote(Loc, LineNo, FilenameID);
- }
-
+ bool IsFileExit,
+ SrcMgr::CharacteristicKind FileKind) {
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
bool Invalid = false;
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
if (!Entry.isFile() || Invalid)
return;
-
+
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
// Remember that this file has #line directives now if it doesn't already.
@@ -329,14 +276,6 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
(void) getLineTable();
- SrcMgr::CharacteristicKind FileKind;
- if (IsExternCHeader)
- FileKind = SrcMgr::C_ExternCSystem;
- else if (IsSystemHeader)
- FileKind = SrcMgr::C_System;
- else
- FileKind = SrcMgr::C_User;
-
unsigned EntryExit = 0;
if (IsFileEntry)
EntryExit = 1;
@@ -406,6 +345,34 @@ void SourceManager::clearIDTables() {
createExpansionLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1);
}
+void SourceManager::initializeForReplay(const SourceManager &Old) {
+ assert(MainFileID.isInvalid() && "expected uninitialized SourceManager");
+
+ auto CloneContentCache = [&](const ContentCache *Cache) -> ContentCache * {
+ auto *Clone = new (ContentCacheAlloc.Allocate<ContentCache>()) ContentCache;
+ Clone->OrigEntry = Cache->OrigEntry;
+ Clone->ContentsEntry = Cache->ContentsEntry;
+ Clone->BufferOverridden = Cache->BufferOverridden;
+ Clone->IsSystemFile = Cache->IsSystemFile;
+ Clone->IsTransient = Cache->IsTransient;
+ Clone->replaceBuffer(Cache->getRawBuffer(), /*DoNotFree*/true);
+ return Clone;
+ };
+
+ // Ensure all SLocEntries are loaded from the external source.
+ for (unsigned I = 0, N = Old.LoadedSLocEntryTable.size(); I != N; ++I)
+ if (!Old.SLocEntryLoaded[I])
+ Old.loadSLocEntry(I, nullptr);
+
+ // Inherit any content cache data from the old source manager.
+ for (auto &FileInfo : Old.FileInfos) {
+ SrcMgr::ContentCache *&Slot = FileInfos[FileInfo.first];
+ if (Slot)
+ continue;
+ Slot = CloneContentCache(FileInfo.second);
+ }
+}
+
/// getOrCreateContentCache - Create or return a cached ContentCache for the
/// specified file.
const ContentCache *
@@ -1136,6 +1103,7 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
return 1;
}
+ const char *Buf = MemBuf->getBufferStart();
// See if we just calculated the line number for this FilePos and can use
// that to lookup the start of the line instead of searching for it.
if (LastLineNoFileIDQuery == FID &&
@@ -1144,11 +1112,19 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache;
unsigned LineStart = SourceLineCache[LastLineNoResult - 1];
unsigned LineEnd = SourceLineCache[LastLineNoResult];
- if (FilePos >= LineStart && FilePos < LineEnd)
+ if (FilePos >= LineStart && FilePos < LineEnd) {
+ // LineEnd is the LineStart of the next line.
+ // A line ends with separator LF or CR+LF on Windows.
+ // FilePos might point to the last separator,
+ // but we need a column number at most 1 + the last column.
+ if (FilePos + 1 == LineEnd && FilePos > LineStart) {
+ if (Buf[FilePos - 1] == '\r' || Buf[FilePos - 1] == '\n')
+ --FilePos;
+ }
return FilePos - LineStart + 1;
+ }
}
- const char *Buf = MemBuf->getBufferStart();
unsigned LineStart = FilePos;
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
--LineStart;
@@ -2042,9 +2018,51 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
if (LOffs.first.isInvalid() || ROffs.first.isInvalid())
return LOffs.first.isInvalid() && !ROffs.first.isInvalid();
+ std::pair<bool, bool> InSameTU = isInTheSameTranslationUnit(LOffs, ROffs);
+ if (InSameTU.first)
+ return InSameTU.second;
+
+ // If we arrived here, the location is either in a built-ins buffer or
+ // associated with global inline asm. PR5662 and PR22576 are examples.
+
+ StringRef LB = getBuffer(LOffs.first)->getBufferIdentifier();
+ StringRef RB = getBuffer(ROffs.first)->getBufferIdentifier();
+ bool LIsBuiltins = LB == "<built-in>";
+ bool RIsBuiltins = RB == "<built-in>";
+ // Sort built-in before non-built-in.
+ if (LIsBuiltins || RIsBuiltins) {
+ if (LIsBuiltins != RIsBuiltins)
+ return LIsBuiltins;
+ // Both are in built-in buffers, but from different files. We just claim that
+ // lower IDs come first.
+ return LOffs.first < ROffs.first;
+ }
+ bool LIsAsm = LB == "<inline asm>";
+ bool RIsAsm = RB == "<inline asm>";
+ // Sort assembler after built-ins, but before the rest.
+ if (LIsAsm || RIsAsm) {
+ if (LIsAsm != RIsAsm)
+ return RIsAsm;
+ assert(LOffs.first == ROffs.first);
+ return false;
+ }
+ bool LIsScratch = LB == "<scratch space>";
+ bool RIsScratch = RB == "<scratch space>";
+ // Sort scratch after inline asm, but before the rest.
+ if (LIsScratch || RIsScratch) {
+ if (LIsScratch != RIsScratch)
+ return LIsScratch;
+ return LOffs.second < ROffs.second;
+ }
+ llvm_unreachable("Unsortable locations found");
+}
+
+std::pair<bool, bool> SourceManager::isInTheSameTranslationUnit(
+ std::pair<FileID, unsigned> &LOffs,
+ std::pair<FileID, unsigned> &ROffs) const {
// If the source locations are in the same file, just compare offsets.
if (LOffs.first == ROffs.first)
- return LOffs.second < ROffs.second;
+ return std::make_pair(true, LOffs.second < ROffs.second);
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
@@ -2054,7 +2072,8 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first))
- return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
+ return std::make_pair(
+ true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
// Okay, we missed in the cache, start updating the cache for this query.
IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first,
@@ -2084,44 +2103,12 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
// locations within the common file and cache them.
if (LOffs.first == ROffs.first) {
IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second);
- return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
+ return std::make_pair(
+ true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
}
-
- // If we arrived here, the location is either in a built-ins buffer or
- // associated with global inline asm. PR5662 and PR22576 are examples.
-
// Clear the lookup cache, it depends on a common location.
IsBeforeInTUCache.clear();
- StringRef LB = getBuffer(LOffs.first)->getBufferIdentifier();
- StringRef RB = getBuffer(ROffs.first)->getBufferIdentifier();
- bool LIsBuiltins = LB == "<built-in>";
- bool RIsBuiltins = RB == "<built-in>";
- // Sort built-in before non-built-in.
- if (LIsBuiltins || RIsBuiltins) {
- if (LIsBuiltins != RIsBuiltins)
- return LIsBuiltins;
- // Both are in built-in buffers, but from different files. We just claim that
- // lower IDs come first.
- return LOffs.first < ROffs.first;
- }
- bool LIsAsm = LB == "<inline asm>";
- bool RIsAsm = RB == "<inline asm>";
- // Sort assembler after built-ins, but before the rest.
- if (LIsAsm || RIsAsm) {
- if (LIsAsm != RIsAsm)
- return RIsAsm;
- assert(LOffs.first == ROffs.first);
- return false;
- }
- bool LIsScratch = LB == "<scratch space>";
- bool RIsScratch = RB == "<scratch space>";
- // Sort scratch after inline asm, but before the rest.
- if (LIsScratch || RIsScratch) {
- if (LIsScratch != RIsScratch)
- return LIsScratch;
- return LOffs.second < ROffs.second;
- }
- llvm_unreachable("Unsortable locations found");
+ return std::make_pair(false, false);
}
void SourceManager::PrintStats() const {
diff --git a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp
index b1b01e5..4bcebad 100644
--- a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp
@@ -143,9 +143,11 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) const {
case UnsignedChar:
if (getCharWidth() < getIntWidth())
return "";
+ LLVM_FALLTHROUGH;
case UnsignedShort:
if (getShortWidth() < getIntWidth())
return "";
+ LLVM_FALLTHROUGH;
case UnsignedInt: return "U";
case UnsignedLong: return "UL";
case UnsignedLongLong: return "ULL";
@@ -282,8 +284,9 @@ bool TargetInfo::isTypeSigned(IntType T) {
/// adjust - Set forced language options.
/// Apply changes to the target information with respect to certain
-/// language options which change the target configuration.
-void TargetInfo::adjust(const LangOptions &Opts) {
+/// language options which change the target configuration and adjust
+/// the language based on the target options where applicable.
+void TargetInfo::adjust(LangOptions &Opts) {
if (Opts.NoBitFieldTypeAlign)
UseBitFieldTypeAlignment = false;
if (Opts.ShortWChar)
@@ -504,6 +507,11 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
case '?': // Disparage slightly code.
case '!': // Disparage severely.
case '*': // Ignore for choosing register preferences.
+ case 'i': // Ignore i,n,E,F as output constraints (match from the other
+ // chars)
+ case 'n':
+ case 'E':
+ case 'F':
break; // Pass them.
}
diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp
index 1a95ff2..5d75aa5 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp
@@ -111,12 +111,28 @@ public:
: OSTargetInfo<Target>(Triple, Opts) {}
};
+// Ananas target
+template<typename Target>
+class AnanasTargetInfo : public OSTargetInfo<Target> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ // Ananas defines
+ Builder.defineMacro("__Ananas__");
+ Builder.defineMacro("__ELF__");
+ }
+public:
+ AnanasTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : OSTargetInfo<Target>(Triple, Opts) {}
+};
+
static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
const llvm::Triple &Triple,
StringRef &PlatformName,
VersionTuple &PlatformMinVersion) {
Builder.defineMacro("__APPLE_CC__", "6000");
Builder.defineMacro("__APPLE__");
+ Builder.defineMacro("__STDC_NO_THREADS__");
Builder.defineMacro("OBJC_NEW_PROPERTIES");
// AddressSanitizer doesn't play well with source fortification, which is on
// by default on Darwin.
@@ -483,6 +499,10 @@ public:
switch (Triple.getArch()) {
default:
break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
@@ -545,18 +565,18 @@ protected:
Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
+ if (this->HasFloat128)
+ Builder.defineMacro("__FLOAT128__");
}
public:
OpenBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: OSTargetInfo<Target>(Triple, Opts) {
- this->TLSSupported = false;
-
switch (Triple.getArch()) {
- default:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
- case llvm::Triple::arm:
- case llvm::Triple::sparc:
+ this->HasFloat128 = true;
+ // FALLTHROUGH
+ default:
this->MCountName = "__mcount";
break;
case llvm::Triple::mips64:
@@ -886,6 +906,7 @@ class PPCTargetInfo : public TargetInfo {
std::string CPU;
// Target cpu features.
+ bool HasAltivec;
bool HasVSX;
bool HasP8Vector;
bool HasP8Crypto;
@@ -901,9 +922,10 @@ protected:
public:
PPCTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple), HasVSX(false), HasP8Vector(false),
+ : TargetInfo(Triple), HasAltivec(false), HasVSX(false), HasP8Vector(false),
HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false),
HasBPERMD(false), HasExtDiv(false), HasP9Vector(false) {
+ SuitableAlign = 128;
SimdDefaultAlign = 128;
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble();
@@ -930,6 +952,13 @@ public:
ArchDefineA2q = 1 << 15
} ArchDefineTypes;
+ // Set the language option for altivec based on our value.
+ void adjust(LangOptions &Opts) override {
+ if (HasAltivec)
+ Opts.AltiVec = 1;
+ TargetInfo::adjust(Opts);
+ }
+
// Note: GCC recognizes the following additional cpus:
// 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801,
// 821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell,
@@ -1164,7 +1193,9 @@ const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
DiagnosticsEngine &Diags) {
for (const auto &Feature : Features) {
- if (Feature == "+vsx") {
+ if (Feature == "+altivec") {
+ HasAltivec = true;
+ } else if (Feature == "+vsx") {
HasVSX = true;
} else if (Feature == "+bpermd") {
HasBPERMD = true;
@@ -1224,82 +1255,100 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
if (ABI == "elfv2")
Builder.defineMacro("_CALL_ELF", "2");
+ // This typically is only for a new enough linker (bfd >= 2.16.2 or gold), but
+ // our suppport post-dates this and it should work on all 64-bit ppc linux
+ // platforms. It is guaranteed to work on all elfv2 platforms.
+ if (getTriple().getOS() == llvm::Triple::Linux && PointerWidth == 64)
+ Builder.defineMacro("_CALL_LINUX", "1");
+
// Subtarget options.
Builder.defineMacro("__NATURAL_ALIGNMENT__");
Builder.defineMacro("__REGISTER_PREFIX__", "");
// FIXME: Should be controlled by command line option.
- if (LongDoubleWidth == 128)
+ if (LongDoubleWidth == 128) {
Builder.defineMacro("__LONG_DOUBLE_128__");
-
- if (Opts.AltiVec) {
- Builder.defineMacro("__VEC__", "10206");
- Builder.defineMacro("__ALTIVEC__");
+ Builder.defineMacro("__LONGDOUBLE128");
}
+ // Define this for elfv2 (64-bit only) or 64-bit darwin.
+ if (ABI == "elfv2" ||
+ (getTriple().getOS() == llvm::Triple::Darwin && PointerWidth == 64))
+ Builder.defineMacro("__STRUCT_PARM_ALIGN__", "16");
+
// CPU identification.
- ArchDefineTypes defs = (ArchDefineTypes)llvm::StringSwitch<int>(CPU)
- .Case("440", ArchDefineName)
- .Case("450", ArchDefineName | ArchDefine440)
- .Case("601", ArchDefineName)
- .Case("602", ArchDefineName | ArchDefinePpcgr)
- .Case("603", ArchDefineName | ArchDefinePpcgr)
- .Case("603e", ArchDefineName | ArchDefine603 | ArchDefinePpcgr)
- .Case("603ev", ArchDefineName | ArchDefine603 | ArchDefinePpcgr)
- .Case("604", ArchDefineName | ArchDefinePpcgr)
- .Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr)
- .Case("620", ArchDefineName | ArchDefinePpcgr)
- .Case("630", ArchDefineName | ArchDefinePpcgr)
- .Case("7400", ArchDefineName | ArchDefinePpcgr)
- .Case("7450", ArchDefineName | ArchDefinePpcgr)
- .Case("750", ArchDefineName | ArchDefinePpcgr)
- .Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr
- | ArchDefinePpcsq)
- .Case("a2", ArchDefineA2)
- .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q)
- .Case("pwr3", ArchDefinePpcgr)
- .Case("pwr4", ArchDefineName | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("pwr5", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr
- | ArchDefinePpcsq)
- .Case("pwr5x", ArchDefineName | ArchDefinePwr5 | ArchDefinePwr4
- | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("pwr6", ArchDefineName | ArchDefinePwr5x | ArchDefinePwr5
- | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("pwr6x", ArchDefineName | ArchDefinePwr6 | ArchDefinePwr5x
- | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
- | ArchDefinePpcsq)
- .Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6
- | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
- | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("pwr8", ArchDefineName | ArchDefinePwr7 | ArchDefinePwr6x
- | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5
- | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("pwr9", ArchDefineName | ArchDefinePwr8 | ArchDefinePwr7
- | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x
- | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
- | ArchDefinePpcsq)
- .Case("power3", ArchDefinePpcgr)
- .Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
- | ArchDefinePpcsq)
- .Case("power5x", ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
- | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("power6", ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5
- | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("power6x", ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x
- | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
- | ArchDefinePpcsq)
- .Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6
- | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
- | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("power8", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x
- | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5
- | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("power9", ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7
- | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x
- | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
- | ArchDefinePpcsq)
- .Default(ArchDefineNone);
+ ArchDefineTypes defs =
+ (ArchDefineTypes)llvm::StringSwitch<int>(CPU)
+ .Case("440", ArchDefineName)
+ .Case("450", ArchDefineName | ArchDefine440)
+ .Case("601", ArchDefineName)
+ .Case("602", ArchDefineName | ArchDefinePpcgr)
+ .Case("603", ArchDefineName | ArchDefinePpcgr)
+ .Case("603e", ArchDefineName | ArchDefine603 | ArchDefinePpcgr)
+ .Case("603ev", ArchDefineName | ArchDefine603 | ArchDefinePpcgr)
+ .Case("604", ArchDefineName | ArchDefinePpcgr)
+ .Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr)
+ .Case("620", ArchDefineName | ArchDefinePpcgr)
+ .Case("630", ArchDefineName | ArchDefinePpcgr)
+ .Case("7400", ArchDefineName | ArchDefinePpcgr)
+ .Case("7450", ArchDefineName | ArchDefinePpcgr)
+ .Case("750", ArchDefineName | ArchDefinePpcgr)
+ .Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr |
+ ArchDefinePpcsq)
+ .Case("a2", ArchDefineA2)
+ .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q)
+ .Case("pwr3", ArchDefinePpcgr)
+ .Case("pwr4", ArchDefineName | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr5", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr |
+ ArchDefinePpcsq)
+ .Case("pwr5x", ArchDefineName | ArchDefinePwr5 | ArchDefinePwr4 |
+ ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr6", ArchDefineName | ArchDefinePwr5x | ArchDefinePwr5 |
+ ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr6x", ArchDefineName | ArchDefinePwr6 | ArchDefinePwr5x |
+ ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr |
+ ArchDefinePpcsq)
+ .Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6 |
+ ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 |
+ ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr8", ArchDefineName | ArchDefinePwr7 | ArchDefinePwr6x |
+ ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 |
+ ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr9", ArchDefineName | ArchDefinePwr8 | ArchDefinePwr7 |
+ ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x |
+ ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr |
+ ArchDefinePpcsq)
+ .Case("power3", ArchDefinePpcgr)
+ .Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr |
+ ArchDefinePpcsq)
+ .Case("power5x", ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 |
+ ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power6", ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 |
+ ArchDefinePwr4 | ArchDefinePpcgr |
+ ArchDefinePpcsq)
+ .Case("power6x", ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x |
+ ArchDefinePwr5 | ArchDefinePwr4 |
+ ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 |
+ ArchDefinePwr5x | ArchDefinePwr5 |
+ ArchDefinePwr4 | ArchDefinePpcgr |
+ ArchDefinePpcsq)
+ .Case("power8", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x |
+ ArchDefinePwr6 | ArchDefinePwr5x |
+ ArchDefinePwr5 | ArchDefinePwr4 |
+ ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power9", ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 |
+ ArchDefinePwr6x | ArchDefinePwr6 |
+ ArchDefinePwr5x | ArchDefinePwr5 |
+ ArchDefinePwr4 | ArchDefinePpcgr |
+ ArchDefinePpcsq)
+ // powerpc64le automatically defaults to at least power8.
+ .Case("ppc64le", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x |
+ ArchDefinePwr6 | ArchDefinePwr5x |
+ ArchDefinePwr5 | ArchDefinePwr4 |
+ ArchDefinePpcgr | ArchDefinePpcsq)
+ .Default(ArchDefineNone);
if (defs & ArchDefineName)
Builder.defineMacro(Twine("_ARCH_", StringRef(CPU).upper()));
@@ -1343,6 +1392,10 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__TOS_BGQ__");
}
+ if (HasAltivec) {
+ Builder.defineMacro("__VEC__", "10206");
+ Builder.defineMacro("__ALTIVEC__");
+ }
if (HasVSX)
Builder.defineMacro("__VSX__");
if (HasP8Vector)
@@ -1362,6 +1415,9 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
if (PointerWidth == 64)
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+ // We have support for the bswap intrinsics so we can define this.
+ Builder.defineMacro("__HAVE_BSWAP__", "1");
+
// FIXME: The following are not yet generated here by Clang, but are
// generated by GCC:
//
@@ -1374,8 +1430,6 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
// __RSQRTEF__
// _SOFT_DOUBLE_
// __NO_LWSYNC__
- // __HAVE_BSWAP__
- // __LONGDOUBLE128
// __CMODEL_MEDIUM__
// __CMODEL_LARGE__
// _CALL_SYSV
@@ -1481,6 +1535,11 @@ bool PPCTargetInfo::initFeatureMap(
.Case("pwr8", true)
.Case("pwr7", true)
.Default(false);
+ Features["htm"] = llvm::StringSwitch<bool>(CPU)
+ .Case("ppc64le", true)
+ .Case("pwr9", true)
+ .Case("pwr8", true)
+ .Default(false);
if (!ppcUserFeaturesCheck(Diags, FeaturesVec))
return false;
@@ -1490,44 +1549,47 @@ bool PPCTargetInfo::initFeatureMap(
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
- .Case("powerpc", true)
- .Case("vsx", HasVSX)
- .Case("power8-vector", HasP8Vector)
- .Case("crypto", HasP8Crypto)
- .Case("direct-move", HasDirectMove)
- .Case("qpx", HasQPX)
- .Case("htm", HasHTM)
- .Case("bpermd", HasBPERMD)
- .Case("extdiv", HasExtDiv)
- .Case("float128", HasFloat128)
- .Case("power9-vector", HasP9Vector)
- .Default(false);
+ .Case("powerpc", true)
+ .Case("altivec", HasAltivec)
+ .Case("vsx", HasVSX)
+ .Case("power8-vector", HasP8Vector)
+ .Case("crypto", HasP8Crypto)
+ .Case("direct-move", HasDirectMove)
+ .Case("qpx", HasQPX)
+ .Case("htm", HasHTM)
+ .Case("bpermd", HasBPERMD)
+ .Case("extdiv", HasExtDiv)
+ .Case("float128", HasFloat128)
+ .Case("power9-vector", HasP9Vector)
+ .Default(false);
}
void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
StringRef Name, bool Enabled) const {
- // If we're enabling direct-move or power8-vector go ahead and enable vsx
- // as well. Do the inverse if we're disabling vsx. We'll diagnose any user
- // incompatible options.
if (Enabled) {
- if (Name == "direct-move" ||
- Name == "power8-vector" ||
- Name == "float128" ||
- Name == "power9-vector") {
- // power9-vector is really a superset of power8-vector so encode that.
- Features[Name] = Features["vsx"] = true;
- if (Name == "power9-vector")
- Features["power8-vector"] = true;
- } else {
- Features[Name] = true;
- }
+ // If we're enabling any of the vsx based features then enable vsx and
+ // altivec. We'll diagnose any problems later.
+ bool FeatureHasVSX = llvm::StringSwitch<bool>(Name)
+ .Case("vsx", true)
+ .Case("direct-move", true)
+ .Case("power8-vector", true)
+ .Case("power9-vector", true)
+ .Case("float128", true)
+ .Default(false);
+ if (FeatureHasVSX)
+ Features["vsx"] = Features["altivec"] = true;
+ if (Name == "power9-vector")
+ Features["power8-vector"] = true;
+ Features[Name] = true;
} else {
- if (Name == "vsx") {
- Features[Name] = Features["direct-move"] = Features["power8-vector"] =
+ // If we're disabling altivec or vsx go ahead and disable all of the vsx
+ // features.
+ if ((Name == "altivec") || (Name == "vsx"))
+ Features["vsx"] = Features["direct-move"] = Features["power8-vector"] =
Features["float128"] = Features["power9-vector"] = false;
- } else {
- Features[Name] = false;
- }
+ if (Name == "power8-vector")
+ Features["power9-vector"] = false;
+ Features[Name] = false;
}
}
@@ -1718,7 +1780,6 @@ public:
BoolWidth = BoolAlign = 32; //XXX support -mone-byte-bool?
PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726
LongLongAlign = 32;
- SuitableAlign = 128;
resetDataLayout("E-m:o-p:32:32-f64:32:64-n32");
}
BuiltinVaListKind getBuiltinVaListKind() const override {
@@ -1731,12 +1792,12 @@ public:
DarwinPPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: DarwinTargetInfo<PPC64TargetInfo>(Triple, Opts) {
HasAlignMac68kSupport = true;
- SuitableAlign = 128;
resetDataLayout("E-m:o-i64:64-n32:64");
}
};
static const unsigned NVPTXAddrSpaceMap[] = {
+ 0, // Default
1, // opencl_global
3, // opencl_local
4, // opencl_constant
@@ -1990,14 +2051,45 @@ ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const {
return llvm::makeArrayRef(GCCRegNames);
}
-static const unsigned AMDGPUAddrSpaceMap[] = {
- 1, // opencl_global
- 3, // opencl_local
- 2, // opencl_constant
- 4, // opencl_generic
- 1, // cuda_device
- 2, // cuda_constant
- 3 // cuda_shared
+static const LangAS::Map AMDGPUPrivIsZeroDefIsGenMap = {
+ 4, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 4, // opencl_generic
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
+};
+static const LangAS::Map AMDGPUGenIsZeroDefIsGenMap = {
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // opencl_generic
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
+};
+static const LangAS::Map AMDGPUPrivIsZeroDefIsPrivMap = {
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 4, // opencl_generic
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
+};
+static const LangAS::Map AMDGPUGenIsZeroDefIsPrivMap = {
+ 5, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // opencl_generic
+ 1, // cuda_device
+ 2, // cuda_constant
+ 3 // cuda_shared
};
// If you edit the description strings, make sure you update
@@ -2007,15 +2099,39 @@ static const char *const DataLayoutStringR600 =
"e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
"-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64";
-static const char *const DataLayoutStringSI =
+static const char *const DataLayoutStringSIPrivateIsZero =
"e-p:32:32-p1:64:64-p2:64:64-p3:32:32-p4:64:64-p5:32:32"
"-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
"-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64";
+static const char *const DataLayoutStringSIGenericIsZero =
+ "e-p:64:64-p1:64:64-p2:64:64-p3:32:32-p4:32:32-p5:32:32"
+ "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
+ "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-A5";
+
class AMDGPUTargetInfo final : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
static const char * const GCCRegNames[];
+ struct AddrSpace {
+ unsigned Generic, Global, Local, Constant, Private;
+ AddrSpace(bool IsGenericZero_ = false){
+ if (IsGenericZero_) {
+ Generic = 0;
+ Global = 1;
+ Local = 3;
+ Constant = 2;
+ Private = 5;
+ } else {
+ Generic = 4;
+ Global = 1;
+ Local = 3;
+ Constant = 2;
+ Private = 0;
+ }
+ }
+ };
+
/// \brief The GPU profiles supported by the AMDGPU target.
enum GPUKind {
GK_NONE,
@@ -2029,18 +2145,27 @@ class AMDGPUTargetInfo final : public TargetInfo {
GK_CAYMAN,
GK_GFX6,
GK_GFX7,
- GK_GFX8
+ GK_GFX8,
+ GK_GFX9
} GPU;
bool hasFP64:1;
bool hasFMAF:1;
bool hasLDEXPF:1;
- bool hasFullSpeedFP32Denorms:1;
+ const AddrSpace AS;
+
+ static bool hasFullSpeedFMAF32(StringRef GPUName) {
+ return parseAMDGCNName(GPUName) >= GK_GFX9;
+ }
static bool isAMDGCN(const llvm::Triple &TT) {
return TT.getArch() == llvm::Triple::amdgcn;
}
+ static bool isGenericZero(const llvm::Triple &TT) {
+ return TT.getEnvironmentName() == "amdgiz" ||
+ TT.getEnvironmentName() == "amdgizcl";
+ }
public:
AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: TargetInfo(Triple) ,
@@ -2048,32 +2173,62 @@ public:
hasFP64(false),
hasFMAF(false),
hasLDEXPF(false),
- hasFullSpeedFP32Denorms(false){
+ AS(isGenericZero(Triple)){
if (getTriple().getArch() == llvm::Triple::amdgcn) {
hasFP64 = true;
hasFMAF = true;
hasLDEXPF = true;
}
-
+ auto IsGenericZero = isGenericZero(Triple);
resetDataLayout(getTriple().getArch() == llvm::Triple::amdgcn ?
- DataLayoutStringSI : DataLayoutStringR600);
-
- AddrSpaceMap = &AMDGPUAddrSpaceMap;
+ (IsGenericZero ? DataLayoutStringSIGenericIsZero :
+ DataLayoutStringSIPrivateIsZero)
+ : DataLayoutStringR600);
+ assert(DataLayout->getAllocaAddrSpace() == AS.Private);
+
+ setAddressSpaceMap(Triple.getOS() == llvm::Triple::Mesa3D ||
+ Triple.getEnvironment() == llvm::Triple::OpenCL ||
+ Triple.getEnvironmentName() == "amdgizcl" ||
+ !isAMDGCN(Triple));
UseAddrSpaceMapMangling = true;
+
+ // Set pointer width and alignment for target address space 0.
+ PointerWidth = PointerAlign = DataLayout->getPointerSizeInBits();
+ if (getMaxPointerWidth() == 64) {
+ LongWidth = LongAlign = 64;
+ SizeType = UnsignedLong;
+ PtrDiffType = SignedLong;
+ IntPtrType = SignedLong;
+ }
+ }
+
+ void setAddressSpaceMap(bool DefaultIsPrivate) {
+ if (isGenericZero(getTriple())) {
+ AddrSpaceMap = DefaultIsPrivate ? &AMDGPUGenIsZeroDefIsPrivMap
+ : &AMDGPUGenIsZeroDefIsGenMap;
+ } else {
+ AddrSpaceMap = DefaultIsPrivate ? &AMDGPUPrivIsZeroDefIsPrivMap
+ : &AMDGPUPrivIsZeroDefIsGenMap;
+ }
+ }
+
+ void adjust(LangOptions &Opts) override {
+ TargetInfo::adjust(Opts);
+ setAddressSpaceMap(Opts.OpenCL || !isAMDGCN(getTriple()));
}
uint64_t getPointerWidthV(unsigned AddrSpace) const override {
if (GPU <= GK_CAYMAN)
return 32;
- switch(AddrSpace) {
- default:
- return 64;
- case 0:
- case 3:
- case 5:
- return 32;
+ if (AddrSpace == AS.Private || AddrSpace == AS.Local) {
+ return 32;
}
+ return 64;
+ }
+
+ uint64_t getPointerAlignV(unsigned AddrSpace) const override {
+ return getPointerWidthV(AddrSpace);
}
uint64_t getMaxPointerWidth() const override {
@@ -2113,15 +2268,16 @@ public:
for (auto &I : TargetOpts.FeaturesAsWritten) {
if (I == "+fp32-denormals" || I == "-fp32-denormals")
hasFP32Denormals = true;
- if (I == "+fp64-denormals" || I == "-fp64-denormals")
+ if (I == "+fp64-fp16-denormals" || I == "-fp64-fp16-denormals")
hasFP64Denormals = true;
}
if (!hasFP32Denormals)
- TargetOpts.Features.push_back((Twine(hasFullSpeedFP32Denorms &&
+ TargetOpts.Features.push_back(
+ (Twine(hasFullSpeedFMAF32(TargetOpts.CPU) &&
!CGOpts.FlushDenorm ? '+' : '-') + Twine("fp32-denormals")).str());
- // Always do not flush fp64 denorms.
+ // Always do not flush fp64 or fp16 denorms.
if (!hasFP64Denormals && hasFP64)
- TargetOpts.Features.push_back("+fp64-denormals");
+ TargetOpts.Features.push_back("+fp64-fp16-denormals");
}
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
@@ -2206,6 +2362,8 @@ public:
.Case("gfx803", GK_GFX8)
.Case("gfx804", GK_GFX8)
.Case("gfx810", GK_GFX8)
+ .Case("gfx900", GK_GFX9)
+ .Case("gfx901", GK_GFX9)
.Default(GK_NONE);
}
@@ -2248,6 +2406,32 @@ public:
return LangAS::opencl_constant;
}
+ llvm::Optional<unsigned> getConstantAddressSpace() const override {
+ return LangAS::FirstTargetAddressSpace + AS.Constant;
+ }
+
+ /// \returns Target specific vtbl ptr address space.
+ unsigned getVtblPtrAddressSpace() const override { return AS.Constant; }
+
+ /// \returns If a target requires an address within a target specific address
+ /// space \p AddressSpace to be converted in order to be used, then return the
+ /// corresponding target specific DWARF address space.
+ ///
+ /// \returns Otherwise return None and no conversion will be emitted in the
+ /// DWARF.
+ Optional<unsigned> getDWARFAddressSpace(
+ unsigned AddressSpace) const override {
+ const unsigned DWARF_Private = 1;
+ const unsigned DWARF_Local = 2;
+ if (AddressSpace == AS.Private) {
+ return DWARF_Private;
+ } else if (AddressSpace == AS.Local) {
+ return DWARF_Local;
+ } else {
+ return None;
+ }
+ }
+
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
switch (CC) {
default:
@@ -2262,7 +2446,7 @@ public:
// address space has value 0 but in private and local address space has
// value ~0.
uint64_t getNullPointerValue(unsigned AS) const override {
- return AS != LangAS::opencl_local && AS != 0 ? 0 : ~0;
+ return AS == LangAS::opencl_local ? ~0 : 0;
}
};
@@ -2345,9 +2529,13 @@ bool AMDGPUTargetInfo::initFeatureMap(
case GK_GFX7:
break;
+ case GK_GFX9:
+ Features["gfx9-insts"] = true;
+ LLVM_FALLTHROUGH;
case GK_GFX8:
Features["s-memrealtime"] = true;
Features["16-bit-insts"] = true;
+ Features["dpp"] = true;
break;
case GK_NONE:
@@ -2469,9 +2657,11 @@ 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;
+ bool HasAVX512VPOPCNTDQ = false;
bool HasAVX512ER = false;
bool HasAVX512PF = false;
bool HasAVX512DQ = false;
@@ -2489,11 +2679,10 @@ class X86TargetInfo : public TargetInfo {
bool HasXSAVEC = false;
bool HasXSAVES = false;
bool HasMWAITX = false;
+ bool HasCLZERO = false;
bool HasPKU = false;
bool HasCLFLUSHOPT = false;
- bool HasPCOMMIT = false;
bool HasCLWB = false;
- bool HasUMIP = false;
bool HasMOVBE = false;
bool HasPREFETCHWT1 = false;
@@ -2539,7 +2728,7 @@ class X86TargetInfo : public TargetInfo {
CK_C3_2,
/// This enumerator is a bit odd, as GCC no longer accepts -march=yonah.
- /// Clang however has some logic to suport this.
+ /// Clang however has some logic to support this.
// FIXME: Warn, deprecate, and potentially remove this.
CK_Yonah,
//@}
@@ -2570,6 +2759,7 @@ class X86TargetInfo : public TargetInfo {
//@{
CK_Bonnell,
CK_Silvermont,
+ CK_Goldmont,
//@}
/// \name Nehalem
@@ -2711,6 +2901,7 @@ class X86TargetInfo : public TargetInfo {
.Case("atom", CK_Bonnell) // Legacy name.
.Case("silvermont", CK_Silvermont)
.Case("slm", CK_Silvermont) // Legacy name.
+ .Case("goldmont", CK_Goldmont)
.Case("nehalem", CK_Nehalem)
.Case("corei7", CK_Nehalem) // Legacy name.
.Case("westmere", CK_Westmere)
@@ -2926,6 +3117,7 @@ public:
case CK_Penryn:
case CK_Bonnell:
case CK_Silvermont:
+ case CK_Goldmont:
case CK_Nehalem:
case CK_Westmere:
case CK_SandyBridge:
@@ -2971,6 +3163,7 @@ public:
case CC_Swift:
case CC_X86Pascal:
case CC_IntelOclBicc:
+ case CC_OpenCLKernel:
return CCCR_OK;
default:
return CCCR_Warning;
@@ -3053,7 +3246,6 @@ bool X86TargetInfo::initFeatureMap(
setFeatureEnabledImpl(Features, "cx16", true);
break;
case CK_Core2:
- case CK_Bonnell:
setFeatureEnabledImpl(Features, "ssse3", true);
setFeatureEnabledImpl(Features, "fxsr", true);
setFeatureEnabledImpl(Features, "cx16", true);
@@ -3067,8 +3259,7 @@ bool X86TargetInfo::initFeatureMap(
setFeatureEnabledImpl(Features, "avx512ifma", true);
setFeatureEnabledImpl(Features, "avx512vbmi", true);
setFeatureEnabledImpl(Features, "sha", true);
- setFeatureEnabledImpl(Features, "umip", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_SkylakeServer:
setFeatureEnabledImpl(Features, "avx512f", true);
setFeatureEnabledImpl(Features, "avx512cd", true);
@@ -3076,49 +3267,69 @@ bool X86TargetInfo::initFeatureMap(
setFeatureEnabledImpl(Features, "avx512bw", true);
setFeatureEnabledImpl(Features, "avx512vl", true);
setFeatureEnabledImpl(Features, "pku", true);
- setFeatureEnabledImpl(Features, "pcommit", true);
setFeatureEnabledImpl(Features, "clwb", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_SkylakeClient:
setFeatureEnabledImpl(Features, "xsavec", true);
setFeatureEnabledImpl(Features, "xsaves", true);
setFeatureEnabledImpl(Features, "mpx", true);
setFeatureEnabledImpl(Features, "sgx", true);
setFeatureEnabledImpl(Features, "clflushopt", true);
- // FALLTHROUGH
+ setFeatureEnabledImpl(Features, "rtm", true);
+ LLVM_FALLTHROUGH;
case CK_Broadwell:
setFeatureEnabledImpl(Features, "rdseed", true);
setFeatureEnabledImpl(Features, "adx", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_Haswell:
setFeatureEnabledImpl(Features, "avx2", true);
setFeatureEnabledImpl(Features, "lzcnt", true);
setFeatureEnabledImpl(Features, "bmi", true);
setFeatureEnabledImpl(Features, "bmi2", true);
- setFeatureEnabledImpl(Features, "rtm", true);
setFeatureEnabledImpl(Features, "fma", true);
setFeatureEnabledImpl(Features, "movbe", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_IvyBridge:
setFeatureEnabledImpl(Features, "rdrnd", true);
setFeatureEnabledImpl(Features, "f16c", true);
setFeatureEnabledImpl(Features, "fsgsbase", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_SandyBridge:
setFeatureEnabledImpl(Features, "avx", true);
setFeatureEnabledImpl(Features, "xsave", true);
setFeatureEnabledImpl(Features, "xsaveopt", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_Westmere:
- case CK_Silvermont:
setFeatureEnabledImpl(Features, "aes", true);
setFeatureEnabledImpl(Features, "pclmul", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_Nehalem:
setFeatureEnabledImpl(Features, "sse4.2", true);
setFeatureEnabledImpl(Features, "fxsr", true);
setFeatureEnabledImpl(Features, "cx16", true);
break;
+ case CK_Goldmont:
+ setFeatureEnabledImpl(Features, "sha", true);
+ setFeatureEnabledImpl(Features, "rdrnd", true);
+ setFeatureEnabledImpl(Features, "rdseed", true);
+ setFeatureEnabledImpl(Features, "xsave", true);
+ setFeatureEnabledImpl(Features, "xsaveopt", true);
+ setFeatureEnabledImpl(Features, "xsavec", true);
+ setFeatureEnabledImpl(Features, "xsaves", true);
+ setFeatureEnabledImpl(Features, "clflushopt", true);
+ setFeatureEnabledImpl(Features, "mpx", true);
+ LLVM_FALLTHROUGH;
+ case CK_Silvermont:
+ setFeatureEnabledImpl(Features, "aes", true);
+ setFeatureEnabledImpl(Features, "pclmul", true);
+ setFeatureEnabledImpl(Features, "sse4.2", true);
+ LLVM_FALLTHROUGH;
+ case CK_Bonnell:
+ setFeatureEnabledImpl(Features, "movbe", true);
+ setFeatureEnabledImpl(Features, "ssse3", true);
+ setFeatureEnabledImpl(Features, "fxsr", true);
+ setFeatureEnabledImpl(Features, "cx16", true);
+ break;
case CK_KNL:
setFeatureEnabledImpl(Features, "avx512f", true);
setFeatureEnabledImpl(Features, "avx512cd", true);
@@ -3173,7 +3384,7 @@ bool X86TargetInfo::initFeatureMap(
setFeatureEnabledImpl(Features, "sse4a", true);
setFeatureEnabledImpl(Features, "lzcnt", true);
setFeatureEnabledImpl(Features, "popcnt", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_K8SSE3:
case CK_OpteronSSE3:
case CK_Athlon64SSE3:
@@ -3188,7 +3399,8 @@ bool X86TargetInfo::initFeatureMap(
setFeatureEnabledImpl(Features, "bmi", true);
setFeatureEnabledImpl(Features, "f16c", true);
setFeatureEnabledImpl(Features, "xsaveopt", true);
- // FALLTHROUGH
+ setFeatureEnabledImpl(Features, "movbe", true);
+ LLVM_FALLTHROUGH;
case CK_BTVER1:
setFeatureEnabledImpl(Features, "ssse3", true);
setFeatureEnabledImpl(Features, "sse4a", true);
@@ -3205,6 +3417,7 @@ bool X86TargetInfo::initFeatureMap(
setFeatureEnabledImpl(Features, "bmi", true);
setFeatureEnabledImpl(Features, "bmi2", true);
setFeatureEnabledImpl(Features, "clflushopt", true);
+ setFeatureEnabledImpl(Features, "clzero", true);
setFeatureEnabledImpl(Features, "cx16", true);
setFeatureEnabledImpl(Features, "f16c", true);
setFeatureEnabledImpl(Features, "fma", true);
@@ -3229,20 +3442,21 @@ bool X86TargetInfo::initFeatureMap(
setFeatureEnabledImpl(Features, "avx2", true);
setFeatureEnabledImpl(Features, "bmi2", true);
setFeatureEnabledImpl(Features, "mwaitx", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_BDVER3:
setFeatureEnabledImpl(Features, "fsgsbase", true);
setFeatureEnabledImpl(Features, "xsaveopt", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
case CK_BDVER2:
setFeatureEnabledImpl(Features, "bmi", true);
setFeatureEnabledImpl(Features, "fma", true);
setFeatureEnabledImpl(Features, "f16c", true);
setFeatureEnabledImpl(Features, "tbm", true);
- // FALLTHROUGH
+ LLVM_FALLTHROUGH;
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);
@@ -3289,23 +3503,32 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features,
switch (Level) {
case AVX512F:
Features["avx512f"] = true;
+ LLVM_FALLTHROUGH;
case AVX2:
Features["avx2"] = true;
+ LLVM_FALLTHROUGH;
case AVX:
Features["avx"] = true;
Features["xsave"] = true;
+ LLVM_FALLTHROUGH;
case SSE42:
Features["sse4.2"] = true;
+ LLVM_FALLTHROUGH;
case SSE41:
Features["sse4.1"] = true;
+ LLVM_FALLTHROUGH;
case SSSE3:
Features["ssse3"] = true;
+ LLVM_FALLTHROUGH;
case SSE3:
Features["sse3"] = true;
+ LLVM_FALLTHROUGH;
case SSE2:
Features["sse2"] = true;
+ LLVM_FALLTHROUGH;
case SSE1:
Features["sse"] = true;
+ LLVM_FALLTHROUGH;
case NoSSE:
break;
}
@@ -3316,29 +3539,38 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features,
case NoSSE:
case SSE1:
Features["sse"] = false;
+ LLVM_FALLTHROUGH;
case SSE2:
Features["sse2"] = Features["pclmul"] = Features["aes"] =
Features["sha"] = false;
+ LLVM_FALLTHROUGH;
case SSE3:
Features["sse3"] = false;
setXOPLevel(Features, NoXOP, false);
+ LLVM_FALLTHROUGH;
case SSSE3:
Features["ssse3"] = false;
+ LLVM_FALLTHROUGH;
case SSE41:
Features["sse4.1"] = false;
+ LLVM_FALLTHROUGH;
case SSE42:
Features["sse4.2"] = false;
+ LLVM_FALLTHROUGH;
case AVX:
Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] =
Features["xsaveopt"] = false;
setXOPLevel(Features, FMA4, false);
+ LLVM_FALLTHROUGH;
case AVX2:
Features["avx2"] = false;
+ LLVM_FALLTHROUGH;
case AVX512F:
Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] =
- Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] =
- Features["avx512vl"] = Features["avx512vbmi"] =
- Features["avx512ifma"] = false;
+ Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] =
+ Features["avx512vl"] = Features["avx512vbmi"] =
+ Features["avx512ifma"] = Features["avx512vpopcntdq"] = false;
+ break;
}
}
@@ -3348,10 +3580,13 @@ void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features,
switch (Level) {
case AMD3DNowAthlon:
Features["3dnowa"] = true;
+ LLVM_FALLTHROUGH;
case AMD3DNow:
Features["3dnow"] = true;
+ LLVM_FALLTHROUGH;
case MMX:
Features["mmx"] = true;
+ LLVM_FALLTHROUGH;
case NoMMX3DNow:
break;
}
@@ -3362,10 +3597,13 @@ void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features,
case NoMMX3DNow:
case MMX:
Features["mmx"] = false;
+ LLVM_FALLTHROUGH;
case AMD3DNow:
Features["3dnow"] = false;
+ LLVM_FALLTHROUGH;
case AMD3DNowAthlon:
Features["3dnowa"] = false;
+ break;
}
}
@@ -3375,12 +3613,15 @@ void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level,
switch (Level) {
case XOP:
Features["xop"] = true;
+ LLVM_FALLTHROUGH;
case FMA4:
Features["fma4"] = true;
setSSELevel(Features, AVX, true);
+ LLVM_FALLTHROUGH;
case SSE4A:
Features["sse4a"] = true;
setSSELevel(Features, SSE3, true);
+ LLVM_FALLTHROUGH;
case NoXOP:
break;
}
@@ -3391,10 +3632,13 @@ void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level,
case NoXOP:
case SSE4A:
Features["sse4a"] = false;
+ LLVM_FALLTHROUGH;
case FMA4:
Features["fma4"] = false;
+ LLVM_FALLTHROUGH;
case XOP:
Features["xop"] = false;
+ break;
}
}
@@ -3438,7 +3682,8 @@ void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
setSSELevel(Features, AVX512F, Enabled);
} else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf" ||
Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl" ||
- Name == "avx512vbmi" || Name == "avx512ifma") {
+ Name == "avx512vbmi" || Name == "avx512ifma" ||
+ Name == "avx512vpopcntdq") {
if (Enabled)
setSSELevel(Features, AVX512F, Enabled);
// Enable BWI instruction if VBMI is being enabled.
@@ -3514,12 +3759,16 @@ 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") {
HasF16C = true;
} else if (Feature == "+avx512cd") {
HasAVX512CD = true;
+ } else if (Feature == "+avx512vpopcntdq") {
+ HasAVX512VPOPCNTDQ = true;
} else if (Feature == "+avx512er") {
HasAVX512ER = true;
} else if (Feature == "+avx512pf") {
@@ -3560,14 +3809,12 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasPKU = true;
} else if (Feature == "+clflushopt") {
HasCLFLUSHOPT = true;
- } else if (Feature == "+pcommit") {
- HasPCOMMIT = true;
} else if (Feature == "+clwb") {
HasCLWB = true;
- } else if (Feature == "+umip") {
- HasUMIP = true;
} else if (Feature == "+prefetchwt1") {
HasPREFETCHWT1 = true;
+ } else if (Feature == "+clzero") {
+ HasCLZERO = true;
}
X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature)
@@ -3650,7 +3897,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_PentiumMMX:
Builder.defineMacro("__pentium_mmx__");
Builder.defineMacro("__tune_pentium_mmx__");
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CK_i586:
case CK_Pentium:
defineCPUMacros(Builder, "i586");
@@ -3660,15 +3907,15 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_Pentium3M:
case CK_PentiumM:
Builder.defineMacro("__tune_pentium3__");
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CK_Pentium2:
case CK_C3_2:
Builder.defineMacro("__tune_pentium2__");
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CK_PentiumPro:
Builder.defineMacro("__tune_i686__");
Builder.defineMacro("__tune_pentiumpro__");
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CK_i686:
Builder.defineMacro("__i686");
Builder.defineMacro("__i686__");
@@ -3695,6 +3942,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_Silvermont:
defineCPUMacros(Builder, "slm");
break;
+ case CK_Goldmont:
+ defineCPUMacros(Builder, "goldmont");
+ break;
case CK_Nehalem:
case CK_Westmere:
case CK_SandyBridge:
@@ -3721,7 +3971,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_K6_2:
Builder.defineMacro("__k6_2__");
Builder.defineMacro("__tune_k6_2__");
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CK_K6_3:
if (CPU != CK_K6_2) { // In case of fallthrough
// FIXME: GCC may be enabling these in cases where some other k6
@@ -3730,7 +3980,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__k6_3__");
Builder.defineMacro("__tune_k6_3__");
}
- // Fallthrough
+ LLVM_FALLTHROUGH;
case CK_K6:
defineCPUMacros(Builder, "k6");
break;
@@ -3831,16 +4081,22 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasTBM)
Builder.defineMacro("__TBM__");
+ if (HasLWP)
+ Builder.defineMacro("__LWP__");
+
if (HasMWAITX)
Builder.defineMacro("__MWAITX__");
switch (XOPLevel) {
case XOP:
Builder.defineMacro("__XOP__");
+ LLVM_FALLTHROUGH;
case FMA4:
Builder.defineMacro("__FMA4__");
+ LLVM_FALLTHROUGH;
case SSE4A:
Builder.defineMacro("__SSE4A__");
+ LLVM_FALLTHROUGH;
case NoXOP:
break;
}
@@ -3853,6 +4109,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasAVX512CD)
Builder.defineMacro("__AVX512CD__");
+ if (HasAVX512VPOPCNTDQ)
+ Builder.defineMacro("__AVX512VPOPCNTDQ__");
if (HasAVX512ER)
Builder.defineMacro("__AVX512ER__");
if (HasAVX512PF)
@@ -3885,29 +4143,50 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__PKU__");
if (HasCX16)
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16");
+ if (HasCLFLUSHOPT)
+ Builder.defineMacro("__CLFLUSHOPT__");
+ if (HasCLWB)
+ Builder.defineMacro("__CLWB__");
+ if (HasMPX)
+ Builder.defineMacro("__MPX__");
+ if (HasSGX)
+ Builder.defineMacro("__SGX__");
+ if (HasPREFETCHWT1)
+ Builder.defineMacro("__PREFETCHWT1__");
+ if (HasCLZERO)
+ Builder.defineMacro("__CLZERO__");
// Each case falls through to the previous one here.
switch (SSELevel) {
case AVX512F:
Builder.defineMacro("__AVX512F__");
+ LLVM_FALLTHROUGH;
case AVX2:
Builder.defineMacro("__AVX2__");
+ LLVM_FALLTHROUGH;
case AVX:
Builder.defineMacro("__AVX__");
+ LLVM_FALLTHROUGH;
case SSE42:
Builder.defineMacro("__SSE4_2__");
+ LLVM_FALLTHROUGH;
case SSE41:
Builder.defineMacro("__SSE4_1__");
+ LLVM_FALLTHROUGH;
case SSSE3:
Builder.defineMacro("__SSSE3__");
+ LLVM_FALLTHROUGH;
case SSE3:
Builder.defineMacro("__SSE3__");
+ LLVM_FALLTHROUGH;
case SSE2:
Builder.defineMacro("__SSE2__");
Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied.
+ LLVM_FALLTHROUGH;
case SSE1:
Builder.defineMacro("__SSE__");
Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied.
+ LLVM_FALLTHROUGH;
case NoSSE:
break;
}
@@ -3929,6 +4208,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
break;
default:
Builder.defineMacro("_M_IX86_FP", Twine(0));
+ break;
}
}
@@ -3936,10 +4216,13 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
switch (MMX3DNowLevel) {
case AMD3DNowAthlon:
Builder.defineMacro("__3dNOW_A__");
+ LLVM_FALLTHROUGH;
case AMD3DNow:
Builder.defineMacro("__3dNOW__");
+ LLVM_FALLTHROUGH;
case MMX:
Builder.defineMacro("__MMX__");
+ LLVM_FALLTHROUGH;
case NoMMX3DNow:
break;
}
@@ -3951,6 +4234,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
}
if (CPU >= CK_i586)
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+
+ if (HasFloat128)
+ Builder.defineMacro("__SIZEOF_FLOAT128__", "16");
}
bool X86TargetInfo::hasFeature(StringRef Feature) const {
@@ -3960,6 +4246,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("avx2", SSELevel >= AVX2)
.Case("avx512f", SSELevel >= AVX512F)
.Case("avx512cd", HasAVX512CD)
+ .Case("avx512vpopcntdq", HasAVX512VPOPCNTDQ)
.Case("avx512er", HasAVX512ER)
.Case("avx512pf", HasAVX512PF)
.Case("avx512dq", HasAVX512DQ)
@@ -3971,6 +4258,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("bmi2", HasBMI2)
.Case("clflushopt", HasCLFLUSHOPT)
.Case("clwb", HasCLWB)
+ .Case("clzero", HasCLZERO)
.Case("cx16", HasCX16)
.Case("f16c", HasF16C)
.Case("fma", HasFMA)
@@ -3984,7 +4272,6 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("movbe", HasMOVBE)
.Case("mpx", HasMPX)
.Case("pclmul", HasPCLMUL)
- .Case("pcommit", HasPCOMMIT)
.Case("pku", HasPKU)
.Case("popcnt", HasPOPCNT)
.Case("prefetchwt1", HasPREFETCHWT1)
@@ -4002,7 +4289,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("sse4.2", SSELevel >= SSE42)
.Case("sse4a", XOPLevel >= SSE4A)
.Case("tbm", HasTBM)
- .Case("umip", HasUMIP)
+ .Case("lwp", HasLWP)
.Case("x86", true)
.Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
.Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
@@ -4045,6 +4332,7 @@ bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
.Case("avx512bw", true)
.Case("avx512dq", true)
.Case("avx512cd", true)
+ .Case("avx512vpopcntdq", true)
.Case("avx512er", true)
.Case("avx512pf", true)
.Case("avx512vbmi", true)
@@ -4428,7 +4716,9 @@ static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) {
class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : WindowsX86_32TargetInfo(Triple, Opts) {}
+ : WindowsX86_32TargetInfo(Triple, Opts) {
+ HasFloat128 = true;
+ }
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
@@ -4609,10 +4899,11 @@ public:
case CC_Swift:
case CC_X86VectorCall:
case CC_IntelOclBicc:
- case CC_X86_64Win64:
+ case CC_Win64:
case CC_PreserveMost:
case CC_PreserveAll:
case CC_X86RegCall:
+ case CC_OpenCLKernel:
return CCCR_OK;
default:
return CCCR_Warning;
@@ -4686,6 +4977,7 @@ public:
case CC_X86_64SysV:
case CC_Swift:
case CC_X86RegCall:
+ case CC_OpenCLKernel:
return CCCR_OK;
default:
return CCCR_Warning;
@@ -4720,6 +5012,7 @@ public:
// with x86 FP ops. Weird.
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
+ HasFloat128 = true;
}
void getTargetDefines(const LangOptions &Opts,
@@ -5056,6 +5349,8 @@ class ARMTargetInfo : public TargetInfo {
return "7M";
case llvm::ARM::AK_ARMV7EM:
return "7EM";
+ case llvm::ARM::AK_ARMV7VE:
+ return "7VE";
case llvm::ARM::AK_ARMV8A:
return "8A";
case llvm::ARM::AK_ARMV8_1A:
@@ -5144,6 +5439,8 @@ public:
default:
if (Triple.getOS() == llvm::Triple::NetBSD)
setABI("apcs-gnu");
+ else if (Triple.getOS() == llvm::Triple::OpenBSD)
+ setABI("aapcs-linux");
else
setABI("aapcs");
break;
@@ -5156,6 +5453,10 @@ public:
// ARM has atomics up to 8 bytes
setAtomic();
+ // Maximum alignment for ARM NEON data types should be 64-bits (AAPCS)
+ if (IsAAPCS && (Triple.getEnvironment() != llvm::Triple::Android))
+ MaxVectorAlign = 64;
+
// Do force alignment of members that follow zero length bitfields. If
// the alignment of the zero-length bitfield is greater than the member
// that follows it, `bar', `bar' will be aligned as the type of the
@@ -5165,7 +5466,7 @@ public:
if (Triple.getOS() == llvm::Triple::Linux ||
Triple.getOS() == llvm::Triple::UnknownOS)
this->MCountName =
- Opts.EABIVersion == "gnu" ? "\01__gnu_mcount_nc" : "\01mcount";
+ Opts.EABIVersion == llvm::EABI::GNU ? "\01__gnu_mcount_nc" : "\01mcount";
}
StringRef getABI() const override { return ABI; }
@@ -5209,7 +5510,24 @@ public:
if (Feature[0] == '+')
Features[Feature.drop_front(1)] = true;
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+ // Enable or disable thumb-mode explicitly per function to enable mixed
+ // ARM and Thumb code generation.
+ if (isThumb())
+ Features["thumb-mode"] = true;
+ else
+ Features["thumb-mode"] = false;
+
+ // Convert user-provided arm and thumb GNU target attributes to
+ // [-|+]thumb-mode target features respectively.
+ std::vector<std::string> UpdatedFeaturesVec(FeaturesVec);
+ for (auto &Feature : UpdatedFeaturesVec) {
+ if (Feature.compare("+arm") == 0)
+ Feature = "-thumb-mode";
+ else if (Feature.compare("+thumb") == 0)
+ Feature = "+thumb-mode";
+ }
+
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec);
}
bool handleTargetFeatures(std::vector<std::string> &Features,
@@ -5310,6 +5628,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);
@@ -5328,6 +5647,17 @@ public:
bool setFPMath(StringRef Name) override;
+ void getTargetDefinesARMV81A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
+ }
+
+ void getTargetDefinesARMV82A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Also include the ARMv8.1-A defines
+ getTargetDefinesARMV81A(Opts, Builder);
+ }
+
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
// Target identification.
@@ -5335,9 +5665,11 @@ public:
Builder.defineMacro("__arm__");
// For bare-metal none-eabi.
if (getTriple().getOS() == llvm::Triple::UnknownOS &&
- getTriple().getEnvironment() == llvm::Triple::EABI)
+ (getTriple().getEnvironment() == llvm::Triple::EABI ||
+ getTriple().getEnvironment() == llvm::Triple::EABIHF))
Builder.defineMacro("__ELF__");
+
// Target properties.
Builder.defineMacro("__REGISTER_PREFIX__", "");
@@ -5524,8 +5856,15 @@ public:
if (Opts.UnsafeFPMath)
Builder.defineMacro("__ARM_FP_FAST", "1");
- if (ArchKind == llvm::ARM::AK_ARMV8_1A)
- Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
+ switch(ArchKind) {
+ default: break;
+ case llvm::ARM::AK_ARMV8_1A:
+ getTargetDefinesARMV81A(Opts, Builder);
+ break;
+ case llvm::ARM::AK_ARMV8_2A:
+ getTargetDefinesARMV82A(Opts, Builder);
+ break;
+ }
}
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
@@ -5631,6 +5970,7 @@ public:
case CC_AAPCS:
case CC_AAPCS_VFP:
case CC_Swift:
+ case CC_OpenCLKernel:
return CCCR_OK;
default:
return CCCR_Warning;
@@ -5790,6 +6130,7 @@ public:
case CC_X86VectorCall:
return CCCR_Ignore;
case CC_C:
+ case CC_OpenCLKernel:
return CCCR_OK;
default:
return CCCR_Warning;
@@ -5909,14 +6250,16 @@ class AArch64TargetInfo : public TargetInfo {
enum FPUModeEnum {
FPUMode,
- NeonMode
+ NeonMode = (1 << 0),
+ SveMode = (1 << 1)
};
unsigned FPU;
unsigned CRC;
unsigned Crypto;
unsigned Unaligned;
- unsigned V8_1A;
+ unsigned HasFullFP16;
+ llvm::AArch64::ArchKind ArchKind;
static const Builtin::Info BuiltinInfo[];
@@ -5925,7 +6268,8 @@ class AArch64TargetInfo : public TargetInfo {
public:
AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: TargetInfo(Triple), ABI("aapcs") {
- if (getTriple().getOS() == llvm::Triple::NetBSD) {
+ if (getTriple().getOS() == llvm::Triple::NetBSD ||
+ getTriple().getOS() == llvm::Triple::OpenBSD) {
WCharType = SignedInt;
// NetBSD apparently prefers consistency across ARM targets to consistency
@@ -5946,6 +6290,9 @@ public:
LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad();
+ // Make __builtin_ms_va_list available.
+ HasBuiltinMSVaList = true;
+
// {} in inline assembly are neon specifiers, not assembly variant
// specifiers.
NoAsmVariants = true;
@@ -5960,9 +6307,10 @@ public:
// AArch64 targets default to using the ARM C++ ABI.
TheCXXABI.set(TargetCXXABI::GenericAArch64);
- if (Triple.getOS() == llvm::Triple::Linux ||
- Triple.getOS() == llvm::Triple::UnknownOS)
- this->MCountName = Opts.EABIVersion == "gnu" ? "\01_mcount" : "mcount";
+ if (Triple.getOS() == llvm::Triple::Linux)
+ this->MCountName = "\01_mcount";
+ else if (Triple.getOS() == llvm::Triple::UnknownOS)
+ this->MCountName = Opts.EABIVersion == llvm::EABI::GNU ? "\01_mcount" : "mcount";
}
StringRef getABI() const override { return ABI; }
@@ -5980,10 +6328,26 @@ public:
static_cast<unsigned>(llvm::AArch64::ArchKind::AK_INVALID);
}
+ void getTargetDefinesARMV81A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
+ }
+
+ void getTargetDefinesARMV82A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Also include the ARMv8.1 defines
+ getTargetDefinesARMV81A(Opts, Builder);
+ }
+
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
// Target identification.
Builder.defineMacro("__aarch64__");
+ // For bare-metal none-eabi.
+ if (getTriple().getOS() == llvm::Triple::UnknownOS &&
+ (getTriple().getEnvironment() == llvm::Triple::EABI ||
+ getTriple().getEnvironment() == llvm::Triple::EABIHF))
+ Builder.defineMacro("__ELF__");
// Target properties.
Builder.defineMacro("_LP64");
@@ -6024,12 +6388,15 @@ public:
Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM",
Opts.ShortEnums ? "1" : "4");
- if (FPU == NeonMode) {
+ if (FPU & NeonMode) {
Builder.defineMacro("__ARM_NEON", "1");
// 64-bit NEON supports half, single and double precision operations.
Builder.defineMacro("__ARM_NEON_FP", "0xE");
}
+ if (FPU & SveMode)
+ Builder.defineMacro("__ARM_FEATURE_SVE", "1");
+
if (CRC)
Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
@@ -6039,8 +6406,15 @@ public:
if (Unaligned)
Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
- if (V8_1A)
- Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
+ switch(ArchKind) {
+ default: break;
+ case llvm::AArch64::ArchKind::AK_ARMV8_1A:
+ getTargetDefinesARMV81A(Opts, Builder);
+ break;
+ case llvm::AArch64::ArchKind::AK_ARMV8_2A:
+ getTargetDefinesARMV82A(Opts, Builder);
+ break;
+ }
// All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work.
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
@@ -6058,7 +6432,8 @@ public:
return Feature == "aarch64" ||
Feature == "arm64" ||
Feature == "arm" ||
- (Feature == "neon" && FPU == NeonMode);
+ (Feature == "neon" && (FPU & NeonMode)) ||
+ (Feature == "sve" && (FPU & SveMode));
}
bool handleTargetFeatures(std::vector<std::string> &Features,
@@ -6067,11 +6442,14 @@ public:
CRC = 0;
Crypto = 0;
Unaligned = 1;
- V8_1A = 0;
+ HasFullFP16 = 0;
+ ArchKind = llvm::AArch64::ArchKind::AK_ARMV8A;
for (const auto &Feature : Features) {
if (Feature == "+neon")
- FPU = NeonMode;
+ FPU |= NeonMode;
+ if (Feature == "+sve")
+ FPU |= SveMode;
if (Feature == "+crc")
CRC = 1;
if (Feature == "+crypto")
@@ -6079,7 +6457,11 @@ public:
if (Feature == "+strict-align")
Unaligned = 0;
if (Feature == "+v8.1a")
- V8_1A = 1;
+ ArchKind = llvm::AArch64::ArchKind::AK_ARMV8_1A;
+ if (Feature == "+v8.2a")
+ ArchKind = llvm::AArch64::ArchKind::AK_ARMV8_2A;
+ if (Feature == "+fullfp16")
+ HasFullFP16 = 1;
}
setDataLayout();
@@ -6093,6 +6475,8 @@ public:
case CC_Swift:
case CC_PreserveMost:
case CC_PreserveAll:
+ case CC_OpenCLKernel:
+ case CC_Win64:
return CCCR_OK;
default:
return CCCR_Warning;
@@ -6262,6 +6646,56 @@ public:
}
};
+class MicrosoftARM64TargetInfo
+ : public WindowsTargetInfo<AArch64leTargetInfo> {
+ const llvm::Triple Triple;
+
+public:
+ MicrosoftARM64TargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsTargetInfo<AArch64leTargetInfo>(Triple, Opts), Triple(Triple) {
+
+ // This is an LLP64 platform.
+ // int:4, long:4, long long:8, long double:8.
+ WCharType = UnsignedShort;
+ IntWidth = IntAlign = 32;
+ LongWidth = LongAlign = 32;
+ DoubleAlign = LongLongAlign = 64;
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+ IntMaxType = SignedLongLong;
+ Int64Type = SignedLongLong;
+ SizeType = UnsignedLongLong;
+ PtrDiffType = SignedLongLong;
+ IntPtrType = SignedLongLong;
+
+ TheCXXABI.set(TargetCXXABI::Microsoft);
+ }
+
+ void setDataLayout() override {
+ resetDataLayout("e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128");
+ }
+
+ void getVisualStudioDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WindowsTargetInfo<AArch64leTargetInfo>::getVisualStudioDefines(Opts,
+ Builder);
+ Builder.defineMacro("_WIN32", "1");
+ Builder.defineMacro("_WIN64", "1");
+ Builder.defineMacro("_M_ARM64", "1");
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsTargetInfo::getTargetDefines(Opts, Builder);
+ getVisualStudioDefines(Opts, Builder);
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+};
+
class AArch64beTargetInfo : public AArch64TargetInfo {
void setDataLayout() override {
assert(!getTriple().isOSBinFormatMachO());
@@ -6408,6 +6842,7 @@ public:
.Case("hexagonv5", "5")
.Case("hexagonv55", "55")
.Case("hexagonv60", "60")
+ .Case("hexagonv62", "62")
.Default(nullptr);
}
@@ -6452,6 +6887,9 @@ void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__HEXAGON_ARCH__", "60");
Builder.defineMacro("__QDSP6_V60__");
Builder.defineMacro("__QDSP6_ARCH__", "60");
+ } else if (CPU == "hexagonv62") {
+ Builder.defineMacro("__HEXAGON_V62__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "62");
}
if (hasFeature("hvx")) {
@@ -6707,6 +7145,11 @@ public:
case 'N': // Same as 'K' but zext (required for SIMode)
case 'O': // The constant 4096
return true;
+
+ case 'f':
+ case 'e':
+ info.setAllowsRegister();
+ return true;
}
return false;
}
@@ -7009,13 +7452,14 @@ class SystemZTargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
static const char *const GCCRegNames[];
std::string CPU;
+ int ISARevision;
bool HasTransactionalExecution;
bool HasVector;
public:
SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
- : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false),
- HasVector(false) {
+ : TargetInfo(Triple), CPU("z10"), ISARevision(8),
+ HasTransactionalExecution(false), HasVector(false) {
IntMaxType = SignedLong;
Int64Type = SignedLong;
TLSSupported = true;
@@ -7037,6 +7481,8 @@ public:
Builder.defineMacro("__zarch__");
Builder.defineMacro("__LONG_DOUBLE_128__");
+ Builder.defineMacro("__ARCH__", Twine(ISARevision));
+
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
@@ -7044,8 +7490,10 @@ public:
if (HasTransactionalExecution)
Builder.defineMacro("__HTM__");
+ if (HasVector)
+ Builder.defineMacro("__VX__");
if (Opts.ZVector)
- Builder.defineMacro("__VEC__", "10301");
+ Builder.defineMacro("__VEC__", "10302");
}
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
return llvm::makeArrayRef(BuiltinInfo,
@@ -7066,37 +7514,38 @@ public:
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::SystemZBuiltinVaList;
}
+ int getISARevision(const StringRef &Name) const {
+ return llvm::StringSwitch<int>(Name)
+ .Cases("arch8", "z10", 8)
+ .Cases("arch9", "z196", 9)
+ .Cases("arch10", "zEC12", 10)
+ .Cases("arch11", "z13", 11)
+ .Cases("arch12", "z14", 12)
+ .Default(-1);
+ }
bool setCPU(const std::string &Name) override {
CPU = Name;
- bool CPUKnown = llvm::StringSwitch<bool>(Name)
- .Case("z10", true)
- .Case("arch8", true)
- .Case("z196", true)
- .Case("arch9", true)
- .Case("zEC12", true)
- .Case("arch10", true)
- .Case("z13", true)
- .Case("arch11", true)
- .Default(false);
-
- return CPUKnown;
+ ISARevision = getISARevision(CPU);
+ return ISARevision != -1;
}
bool
initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
StringRef CPU,
const std::vector<std::string> &FeaturesVec) const override {
- if (CPU == "zEC12" || CPU == "arch10")
- Features["transactional-execution"] = true;
- if (CPU == "z13" || CPU == "arch11") {
+ int ISARevision = getISARevision(CPU);
+ if (ISARevision >= 10)
Features["transactional-execution"] = true;
+ if (ISARevision >= 11)
Features["vector"] = true;
- }
+ if (ISARevision >= 12)
+ Features["vector-enhancements-1"] = true;
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
}
bool handleTargetFeatures(std::vector<std::string> &Features,
DiagnosticsEngine &Diags) override {
HasTransactionalExecution = false;
+ HasVector = false;
for (const auto &Feature : Features) {
if (Feature == "+transactional-execution")
HasTransactionalExecution = true;
@@ -7115,6 +7564,11 @@ public:
bool hasFeature(StringRef Feature) const override {
return llvm::StringSwitch<bool>(Feature)
.Case("systemz", true)
+ .Case("arch8", ISARevision >= 8)
+ .Case("arch9", ISARevision >= 9)
+ .Case("arch10", ISARevision >= 10)
+ .Case("arch11", ISARevision >= 11)
+ .Case("arch12", ISARevision >= 12)
.Case("htm", HasTransactionalExecution)
.Case("vx", HasVector)
.Default(false);
@@ -7124,6 +7578,7 @@ public:
switch (CC) {
case CC_C:
case CC_Swift:
+ case CC_OpenCLKernel:
return CCCR_OK;
default:
return CCCR_Warning;
@@ -7209,7 +7664,7 @@ public:
IntPtrType = SignedInt;
PtrDiffType = SignedInt;
SigAtomicType = SignedLong;
- resetDataLayout("e-m:e-p:16:16-i32:16:32-a:16-n8:16");
+ resetDataLayout("e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16");
}
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
@@ -7268,6 +7723,7 @@ ArrayRef<const char *> MSP430TargetInfo::getGCCRegNames() const {
// publicly available in http://tce.cs.tut.fi
static const unsigned TCEOpenCLAddrSpaceMap[] = {
+ 0, // Default
3, // opencl_global
4, // opencl_local
5, // opencl_constant
@@ -7406,6 +7862,157 @@ public:
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
return None;
}
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
+ switch (CC) {
+ default:
+ return CCCR_Warning;
+ case CC_C:
+ case CC_OpenCLKernel:
+ return CCCR_OK;
+ }
+ }
+};
+
+class Nios2TargetInfo : public TargetInfo {
+ void setDataLayout() {
+ if (BigEndian)
+ resetDataLayout("E-p:32:32:32-i8:8:32-i16:16:32-n32");
+ else
+ resetDataLayout("e-p:32:32:32-i8:8:32-i16:16:32-n32");
+ }
+
+ static const Builtin::Info BuiltinInfo[];
+ std::string CPU;
+ std::string ABI;
+
+public:
+ Nios2TargetInfo(const llvm::Triple &triple, const TargetOptions &opts)
+ : TargetInfo(triple), CPU(opts.CPU), ABI(opts.ABI) {
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
+ setDataLayout();
+ }
+
+ StringRef getABI() const override { return ABI; }
+ bool setABI(const std::string &Name) override {
+ if (Name == "o32" || Name == "eabi") {
+ ABI = Name;
+ return true;
+ }
+ return false;
+ }
+
+ bool setCPU(const std::string &Name) override {
+ if (Name == "nios2r1" || Name == "nios2r2") {
+ CPU = Name;
+ return true;
+ }
+ return false;
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ DefineStd(Builder, "nios2", Opts);
+ DefineStd(Builder, "NIOS2", Opts);
+
+ Builder.defineMacro("__nios2");
+ Builder.defineMacro("__NIOS2");
+ Builder.defineMacro("__nios2__");
+ Builder.defineMacro("__NIOS2__");
+ }
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ return llvm::makeArrayRef(BuiltinInfo, clang::Nios2::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+ }
+
+ bool isFeatureSupportedByCPU(StringRef Feature, StringRef CPU) const {
+ const bool isR2 = CPU == "nios2r2";
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("nios2r2mandatory", isR2)
+ .Case("nios2r2bmx", isR2)
+ .Case("nios2r2mpx", isR2)
+ .Case("nios2r2cdx", isR2)
+ .Default(false);
+ }
+
+ bool initFeatureMap(llvm::StringMap<bool> &Features,
+ DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeatureVec) const override {
+ static const char *allFeatures[] = {
+ "nios2r2mandatory", "nios2r2bmx", "nios2r2mpx", "nios2r2cdx"
+ };
+ for (const char *feature : allFeatures) {
+ Features[feature] = isFeatureSupportedByCPU(feature, CPU);
+ }
+ return true;
+ }
+
+ bool hasFeature(StringRef Feature) const override {
+ return isFeatureSupportedByCPU(Feature, CPU);
+ }
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ ArrayRef<const char *> getGCCRegNames() const override {
+ static const char *const GCCRegNames[] = {
+ // CPU register names
+ // Must match second column of GCCRegAliases
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20",
+ "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30",
+ "r31",
+ // Floating point register names
+ "ctl0", "ctl1", "ctl2", "ctl3", "ctl4", "ctl5", "ctl6", "ctl7", "ctl8",
+ "ctl9", "ctl10", "ctl11", "ctl12", "ctl13", "ctl14", "ctl15"
+ };
+ return llvm::makeArrayRef(GCCRegNames);
+ }
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
+ switch (*Name) {
+ default:
+ return false;
+
+ case 'r': // CPU registers.
+ case 'd': // Equivalent to "r" unless generating MIPS16 code.
+ case 'y': // Equivalent to "r", backwards compatibility only.
+ case 'f': // floating-point registers.
+ case 'c': // $25 for indirect jumps
+ case 'l': // lo register
+ case 'x': // hilo register pair
+ Info.setAllowsRegister();
+ return true;
+ }
+ }
+
+ const char *getClobbers() const override { return ""; }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
+ static const TargetInfo::GCCRegAlias aliases[] = {
+ {{"zero"}, "r0"}, {{"at"}, "r1"}, {{"et"}, "r24"},
+ {{"bt"}, "r25"}, {{"gp"}, "r26"}, {{"sp"}, "r27"},
+ {{"fp"}, "r28"}, {{"ea"}, "r29"}, {{"ba"}, "r30"},
+ {{"ra"}, "r31"}, {{"status"}, "ctl0"}, {{"estatus"}, "ctl1"},
+ {{"bstatus"}, "ctl2"}, {{"ienable"}, "ctl3"}, {{"ipending"}, "ctl4"},
+ {{"cpuid"}, "ctl5"}, {{"exception"}, "ctl7"}, {{"pteaddr"}, "ctl8"},
+ {{"tlbacc"}, "ctl9"}, {{"tlbmisc"}, "ctl10"}, {{"badaddr"}, "ctl12"},
+ {{"config"}, "ctl13"}, {{"mpubase"}, "ctl14"}, {{"mpuacc"}, "ctl15"},
+ };
+ return llvm::makeArrayRef(aliases);
+ }
+};
+
+const Builtin::Info Nios2TargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+#include "clang/Basic/BuiltinsNios2.def"
};
class MipsTargetInfo : public TargetInfo {
@@ -7434,6 +8041,8 @@ class MipsTargetInfo : public TargetInfo {
bool IsMicromips;
bool IsNan2008;
bool IsSingleFloat;
+ bool IsNoABICalls;
+ bool CanUseBSDABICalls;
enum MipsFloatABI {
HardFloat, SoftFloat
} FloatABI;
@@ -7441,6 +8050,7 @@ class MipsTargetInfo : public TargetInfo {
NoDSP, DSP1, DSP2
} DspRev;
bool HasMSA;
+ bool DisableMadd4;
protected:
bool HasFP64;
@@ -7449,8 +8059,9 @@ protected:
public:
MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
: TargetInfo(Triple), IsMips16(false), IsMicromips(false),
- IsNan2008(false), IsSingleFloat(false), FloatABI(HardFloat),
- DspRev(NoDSP), HasMSA(false), HasFP64(false) {
+ IsNan2008(false), IsSingleFloat(false), IsNoABICalls(false),
+ CanUseBSDABICalls(false), FloatABI(HardFloat), DspRev(NoDSP),
+ HasMSA(false), DisableMadd4(false), HasFP64(false) {
TheCXXABI.set(TargetCXXABI::GenericMIPS);
setABI((getTriple().getArch() == llvm::Triple::mips ||
@@ -7459,6 +8070,9 @@ public:
: "n64");
CPU = ABI == "o32" ? "mips32r2" : "mips64r2";
+
+ CanUseBSDABICalls = Triple.getOS() == llvm::Triple::FreeBSD ||
+ Triple.getOS() == llvm::Triple::OpenBSD;
}
bool isNaN2008Default() const {
@@ -7535,7 +8149,11 @@ public:
void setN64ABITypes() {
setN32N64ABITypes();
- Int64Type = SignedLong;
+ if (getTriple().getOS() == llvm::Triple::OpenBSD) {
+ Int64Type = SignedLongLong;
+ } else {
+ Int64Type = SignedLong;
+ }
IntMaxType = Int64Type;
LongWidth = LongAlign = 64;
PointerWidth = PointerAlign = 64;
@@ -7639,6 +8257,12 @@ public:
} else
llvm_unreachable("Invalid ABI.");
+ if (!IsNoABICalls) {
+ Builder.defineMacro("__mips_abicalls");
+ if (CanUseBSDABICalls)
+ Builder.defineMacro("__ABICALLS__");
+ }
+
Builder.defineMacro("__REGISTER_PREFIX__", "");
switch (FloatABI) {
@@ -7683,6 +8307,9 @@ public:
if (HasMSA)
Builder.defineMacro("__mips_msa", Twine(1));
+ if (DisableMadd4)
+ Builder.defineMacro("__mips_no_madd4", Twine(1));
+
Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0)));
Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth()));
Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth()));
@@ -7845,6 +8472,8 @@ public:
DspRev = std::max(DspRev, DSP2);
else if (Feature == "+msa")
HasMSA = true;
+ else if (Feature == "+nomadd4")
+ DisableMadd4 = true;
else if (Feature == "+fp64")
HasFP64 = true;
else if (Feature == "-fp64")
@@ -7853,6 +8482,8 @@ public:
IsNan2008 = true;
else if (Feature == "-nan2008")
IsNan2008 = false;
+ else if (Feature == "+noabicalls")
+ IsNoABICalls = true;
}
setDataLayout();
@@ -8175,7 +8806,7 @@ public:
explicit WebAssembly32TargetInfo(const llvm::Triple &T,
const TargetOptions &Opts)
: WebAssemblyTargetInfo(T, Opts) {
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128");
}
@@ -8216,6 +8847,7 @@ const Builtin::Info Le64TargetInfo::BuiltinInfo[] = {
};
static const unsigned SPIRAddrSpaceMap[] = {
+ 0, // Default
1, // opencl_global
3, // opencl_local
2, // opencl_constant
@@ -8435,6 +9067,254 @@ public:
}
};
+/// Information about a specific microcontroller.
+struct MCUInfo {
+ const char *Name;
+ const char *DefineName;
+};
+
+// This list should be kept up-to-date with AVRDevices.td in LLVM.
+static ArrayRef<MCUInfo> AVRMcus = {
+ { "at90s1200", "__AVR_AT90S1200__" },
+ { "attiny11", "__AVR_ATtiny11__" },
+ { "attiny12", "__AVR_ATtiny12__" },
+ { "attiny15", "__AVR_ATtiny15__" },
+ { "attiny28", "__AVR_ATtiny28__" },
+ { "at90s2313", "__AVR_AT90S2313__" },
+ { "at90s2323", "__AVR_AT90S2323__" },
+ { "at90s2333", "__AVR_AT90S2333__" },
+ { "at90s2343", "__AVR_AT90S2343__" },
+ { "attiny22", "__AVR_ATtiny22__" },
+ { "attiny26", "__AVR_ATtiny26__" },
+ { "at86rf401", "__AVR_AT86RF401__" },
+ { "at90s4414", "__AVR_AT90S4414__" },
+ { "at90s4433", "__AVR_AT90S4433__" },
+ { "at90s4434", "__AVR_AT90S4434__" },
+ { "at90s8515", "__AVR_AT90S8515__" },
+ { "at90c8534", "__AVR_AT90c8534__" },
+ { "at90s8535", "__AVR_AT90S8535__" },
+ { "ata5272", "__AVR_ATA5272__" },
+ { "attiny13", "__AVR_ATtiny13__" },
+ { "attiny13a", "__AVR_ATtiny13A__" },
+ { "attiny2313", "__AVR_ATtiny2313__" },
+ { "attiny2313a", "__AVR_ATtiny2313A__" },
+ { "attiny24", "__AVR_ATtiny24__" },
+ { "attiny24a", "__AVR_ATtiny24A__" },
+ { "attiny4313", "__AVR_ATtiny4313__" },
+ { "attiny44", "__AVR_ATtiny44__" },
+ { "attiny44a", "__AVR_ATtiny44A__" },
+ { "attiny84", "__AVR_ATtiny84__" },
+ { "attiny84a", "__AVR_ATtiny84A__" },
+ { "attiny25", "__AVR_ATtiny25__" },
+ { "attiny45", "__AVR_ATtiny45__" },
+ { "attiny85", "__AVR_ATtiny85__" },
+ { "attiny261", "__AVR_ATtiny261__" },
+ { "attiny261a", "__AVR_ATtiny261A__" },
+ { "attiny461", "__AVR_ATtiny461__" },
+ { "attiny461a", "__AVR_ATtiny461A__" },
+ { "attiny861", "__AVR_ATtiny861__" },
+ { "attiny861a", "__AVR_ATtiny861A__" },
+ { "attiny87", "__AVR_ATtiny87__" },
+ { "attiny43u", "__AVR_ATtiny43U__" },
+ { "attiny48", "__AVR_ATtiny48__" },
+ { "attiny88", "__AVR_ATtiny88__" },
+ { "attiny828", "__AVR_ATtiny828__" },
+ { "at43usb355", "__AVR_AT43USB355__" },
+ { "at76c711", "__AVR_AT76C711__" },
+ { "atmega103", "__AVR_ATmega103__" },
+ { "at43usb320", "__AVR_AT43USB320__" },
+ { "attiny167", "__AVR_ATtiny167__" },
+ { "at90usb82", "__AVR_AT90USB82__" },
+ { "at90usb162", "__AVR_AT90USB162__" },
+ { "ata5505", "__AVR_ATA5505__" },
+ { "atmega8u2", "__AVR_ATmega8U2__" },
+ { "atmega16u2", "__AVR_ATmega16U2__" },
+ { "atmega32u2", "__AVR_ATmega32U2__" },
+ { "attiny1634", "__AVR_ATtiny1634__" },
+ { "atmega8", "__AVR_ATmega8__" },
+ { "ata6289", "__AVR_ATA6289__" },
+ { "atmega8a", "__AVR_ATmega8A__" },
+ { "ata6285", "__AVR_ATA6285__" },
+ { "ata6286", "__AVR_ATA6286__" },
+ { "atmega48", "__AVR_ATmega48__" },
+ { "atmega48a", "__AVR_ATmega48A__" },
+ { "atmega48pa", "__AVR_ATmega48PA__" },
+ { "atmega48p", "__AVR_ATmega48P__" },
+ { "atmega88", "__AVR_ATmega88__" },
+ { "atmega88a", "__AVR_ATmega88A__" },
+ { "atmega88p", "__AVR_ATmega88P__" },
+ { "atmega88pa", "__AVR_ATmega88PA__" },
+ { "atmega8515", "__AVR_ATmega8515__" },
+ { "atmega8535", "__AVR_ATmega8535__" },
+ { "atmega8hva", "__AVR_ATmega8HVA__" },
+ { "at90pwm1", "__AVR_AT90PWM1__" },
+ { "at90pwm2", "__AVR_AT90PWM2__" },
+ { "at90pwm2b", "__AVR_AT90PWM2B__" },
+ { "at90pwm3", "__AVR_AT90PWM3__" },
+ { "at90pwm3b", "__AVR_AT90PWM3B__" },
+ { "at90pwm81", "__AVR_AT90PWM81__" },
+ { "ata5790", "__AVR_ATA5790__" },
+ { "ata5795", "__AVR_ATA5795__" },
+ { "atmega16", "__AVR_ATmega16__" },
+ { "atmega16a", "__AVR_ATmega16A__" },
+ { "atmega161", "__AVR_ATmega161__" },
+ { "atmega162", "__AVR_ATmega162__" },
+ { "atmega163", "__AVR_ATmega163__" },
+ { "atmega164a", "__AVR_ATmega164A__" },
+ { "atmega164p", "__AVR_ATmega164P__" },
+ { "atmega164pa", "__AVR_ATmega164PA__" },
+ { "atmega165", "__AVR_ATmega165__" },
+ { "atmega165a", "__AVR_ATmega165A__" },
+ { "atmega165p", "__AVR_ATmega165P__" },
+ { "atmega165pa", "__AVR_ATmega165PA__" },
+ { "atmega168", "__AVR_ATmega168__" },
+ { "atmega168a", "__AVR_ATmega168A__" },
+ { "atmega168p", "__AVR_ATmega168P__" },
+ { "atmega168pa", "__AVR_ATmega168PA__" },
+ { "atmega169", "__AVR_ATmega169__" },
+ { "atmega169a", "__AVR_ATmega169A__" },
+ { "atmega169p", "__AVR_ATmega169P__" },
+ { "atmega169pa", "__AVR_ATmega169PA__" },
+ { "atmega32", "__AVR_ATmega32__" },
+ { "atmega32a", "__AVR_ATmega32A__" },
+ { "atmega323", "__AVR_ATmega323__" },
+ { "atmega324a", "__AVR_ATmega324A__" },
+ { "atmega324p", "__AVR_ATmega324P__" },
+ { "atmega324pa", "__AVR_ATmega324PA__" },
+ { "atmega325", "__AVR_ATmega325__" },
+ { "atmega325a", "__AVR_ATmega325A__" },
+ { "atmega325p", "__AVR_ATmega325P__" },
+ { "atmega325pa", "__AVR_ATmega325PA__" },
+ { "atmega3250", "__AVR_ATmega3250__" },
+ { "atmega3250a", "__AVR_ATmega3250A__" },
+ { "atmega3250p", "__AVR_ATmega3250P__" },
+ { "atmega3250pa", "__AVR_ATmega3250PA__" },
+ { "atmega328", "__AVR_ATmega328__" },
+ { "atmega328p", "__AVR_ATmega328P__" },
+ { "atmega329", "__AVR_ATmega329__" },
+ { "atmega329a", "__AVR_ATmega329A__" },
+ { "atmega329p", "__AVR_ATmega329P__" },
+ { "atmega329pa", "__AVR_ATmega329PA__" },
+ { "atmega3290", "__AVR_ATmega3290__" },
+ { "atmega3290a", "__AVR_ATmega3290A__" },
+ { "atmega3290p", "__AVR_ATmega3290P__" },
+ { "atmega3290pa", "__AVR_ATmega3290PA__" },
+ { "atmega406", "__AVR_ATmega406__" },
+ { "atmega64", "__AVR_ATmega64__" },
+ { "atmega64a", "__AVR_ATmega64A__" },
+ { "atmega640", "__AVR_ATmega640__" },
+ { "atmega644", "__AVR_ATmega644__" },
+ { "atmega644a", "__AVR_ATmega644A__" },
+ { "atmega644p", "__AVR_ATmega644P__" },
+ { "atmega644pa", "__AVR_ATmega644PA__" },
+ { "atmega645", "__AVR_ATmega645__" },
+ { "atmega645a", "__AVR_ATmega645A__" },
+ { "atmega645p", "__AVR_ATmega645P__" },
+ { "atmega649", "__AVR_ATmega649__" },
+ { "atmega649a", "__AVR_ATmega649A__" },
+ { "atmega649p", "__AVR_ATmega649P__" },
+ { "atmega6450", "__AVR_ATmega6450__" },
+ { "atmega6450a", "__AVR_ATmega6450A__" },
+ { "atmega6450p", "__AVR_ATmega6450P__" },
+ { "atmega6490", "__AVR_ATmega6490__" },
+ { "atmega6490a", "__AVR_ATmega6490A__" },
+ { "atmega6490p", "__AVR_ATmega6490P__" },
+ { "atmega64rfr2", "__AVR_ATmega64RFR2__" },
+ { "atmega644rfr2", "__AVR_ATmega644RFR2__" },
+ { "atmega16hva", "__AVR_ATmega16HVA__" },
+ { "atmega16hva2", "__AVR_ATmega16HVA2__" },
+ { "atmega16hvb", "__AVR_ATmega16HVB__" },
+ { "atmega16hvbrevb", "__AVR_ATmega16HVBREVB__" },
+ { "atmega32hvb", "__AVR_ATmega32HVB__" },
+ { "atmega32hvbrevb", "__AVR_ATmega32HVBREVB__" },
+ { "atmega64hve", "__AVR_ATmega64HVE__" },
+ { "at90can32", "__AVR_AT90CAN32__" },
+ { "at90can64", "__AVR_AT90CAN64__" },
+ { "at90pwm161", "__AVR_AT90PWM161__" },
+ { "at90pwm216", "__AVR_AT90PWM216__" },
+ { "at90pwm316", "__AVR_AT90PWM316__" },
+ { "atmega32c1", "__AVR_ATmega32C1__" },
+ { "atmega64c1", "__AVR_ATmega64C1__" },
+ { "atmega16m1", "__AVR_ATmega16M1__" },
+ { "atmega32m1", "__AVR_ATmega32M1__" },
+ { "atmega64m1", "__AVR_ATmega64M1__" },
+ { "atmega16u4", "__AVR_ATmega16U4__" },
+ { "atmega32u4", "__AVR_ATmega32U4__" },
+ { "atmega32u6", "__AVR_ATmega32U6__" },
+ { "at90usb646", "__AVR_AT90USB646__" },
+ { "at90usb647", "__AVR_AT90USB647__" },
+ { "at90scr100", "__AVR_AT90SCR100__" },
+ { "at94k", "__AVR_AT94K__" },
+ { "m3000", "__AVR_AT000__" },
+ { "atmega128", "__AVR_ATmega128__" },
+ { "atmega128a", "__AVR_ATmega128A__" },
+ { "atmega1280", "__AVR_ATmega1280__" },
+ { "atmega1281", "__AVR_ATmega1281__" },
+ { "atmega1284", "__AVR_ATmega1284__" },
+ { "atmega1284p", "__AVR_ATmega1284P__" },
+ { "atmega128rfa1", "__AVR_ATmega128RFA1__" },
+ { "atmega128rfr2", "__AVR_ATmega128RFR2__" },
+ { "atmega1284rfr2", "__AVR_ATmega1284RFR2__" },
+ { "at90can128", "__AVR_AT90CAN128__" },
+ { "at90usb1286", "__AVR_AT90USB1286__" },
+ { "at90usb1287", "__AVR_AT90USB1287__" },
+ { "atmega2560", "__AVR_ATmega2560__" },
+ { "atmega2561", "__AVR_ATmega2561__" },
+ { "atmega256rfr2", "__AVR_ATmega256RFR2__" },
+ { "atmega2564rfr2", "__AVR_ATmega2564RFR2__" },
+ { "atxmega16a4", "__AVR_ATxmega16A4__" },
+ { "atxmega16a4u", "__AVR_ATxmega16a4U__" },
+ { "atxmega16c4", "__AVR_ATxmega16C4__" },
+ { "atxmega16d4", "__AVR_ATxmega16D4__" },
+ { "atxmega32a4", "__AVR_ATxmega32A4__" },
+ { "atxmega32a4u", "__AVR_ATxmega32A4U__" },
+ { "atxmega32c4", "__AVR_ATxmega32C4__" },
+ { "atxmega32d4", "__AVR_ATxmega32D4__" },
+ { "atxmega32e5", "__AVR_ATxmega32E5__" },
+ { "atxmega16e5", "__AVR_ATxmega16E5__" },
+ { "atxmega8e5", "__AVR_ATxmega8E5__" },
+ { "atxmega32x1", "__AVR_ATxmega32X1__" },
+ { "atxmega64a3", "__AVR_ATxmega64A3__" },
+ { "atxmega64a3u", "__AVR_ATxmega64A3U__" },
+ { "atxmega64a4u", "__AVR_ATxmega64A4U__" },
+ { "atxmega64b1", "__AVR_ATxmega64B1__" },
+ { "atxmega64b3", "__AVR_ATxmega64B3__" },
+ { "atxmega64c3", "__AVR_ATxmega64C3__" },
+ { "atxmega64d3", "__AVR_ATxmega64D3__" },
+ { "atxmega64d4", "__AVR_ATxmega64D4__" },
+ { "atxmega64a1", "__AVR_ATxmega64A1__" },
+ { "atxmega64a1u", "__AVR_ATxmega64A1U__" },
+ { "atxmega128a3", "__AVR_ATxmega128A3__" },
+ { "atxmega128a3u", "__AVR_ATxmega128A3U__" },
+ { "atxmega128b1", "__AVR_ATxmega128B1__" },
+ { "atxmega128b3", "__AVR_ATxmega128B3__" },
+ { "atxmega128c3", "__AVR_ATxmega128C3__" },
+ { "atxmega128d3", "__AVR_ATxmega128D3__" },
+ { "atxmega128d4", "__AVR_ATxmega128D4__" },
+ { "atxmega192a3", "__AVR_ATxmega192A3__" },
+ { "atxmega192a3u", "__AVR_ATxmega192A3U__" },
+ { "atxmega192c3", "__AVR_ATxmega192C3__" },
+ { "atxmega192d3", "__AVR_ATxmega192D3__" },
+ { "atxmega256a3", "__AVR_ATxmega256A3__" },
+ { "atxmega256a3u", "__AVR_ATxmega256A3U__" },
+ { "atxmega256a3b", "__AVR_ATxmega256A3B__" },
+ { "atxmega256a3bu", "__AVR_ATxmega256A3BU__" },
+ { "atxmega256c3", "__AVR_ATxmega256C3__" },
+ { "atxmega256d3", "__AVR_ATxmega256D3__" },
+ { "atxmega384c3", "__AVR_ATxmega384C3__" },
+ { "atxmega384d3", "__AVR_ATxmega384D3__" },
+ { "atxmega128a1", "__AVR_ATxmega128A1__" },
+ { "atxmega128a1u", "__AVR_ATxmega128A1U__" },
+ { "atxmega128a4u", "__AVR_ATxmega128a4U__" },
+ { "attiny4", "__AVR_ATtiny4__" },
+ { "attiny5", "__AVR_ATtiny5__" },
+ { "attiny9", "__AVR_ATtiny9__" },
+ { "attiny10", "__AVR_ATtiny10__" },
+ { "attiny20", "__AVR_ATtiny20__" },
+ { "attiny40", "__AVR_ATtiny40__" },
+ { "attiny102", "__AVR_ATtiny102__" },
+ { "attiny104", "__AVR_ATtiny104__" },
+};
// AVR Target
class AVRTargetInfo : public TargetInfo {
@@ -8476,7 +9356,17 @@ public:
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
+ Builder.defineMacro("AVR");
+ Builder.defineMacro("__AVR");
Builder.defineMacro("__AVR__");
+
+ if (!this->CPU.empty()) {
+ auto It = std::find_if(AVRMcus.begin(), AVRMcus.end(),
+ [&](const MCUInfo &Info) { return Info.Name == this->CPU; });
+
+ if (It != AVRMcus.end())
+ Builder.defineMacro(It->DefineName);
+ }
}
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
@@ -8517,6 +9407,57 @@ public:
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const override {
+ // There aren't any multi-character AVR specific constraints.
+ if (StringRef(Name).size() > 1) return false;
+
+ switch (*Name) {
+ default: return false;
+ case 'a': // Simple upper registers
+ case 'b': // Base pointer registers pairs
+ case 'd': // Upper register
+ case 'l': // Lower registers
+ case 'e': // Pointer register pairs
+ case 'q': // Stack pointer register
+ case 'r': // Any register
+ case 'w': // Special upper register pairs
+ case 't': // Temporary register
+ case 'x': case 'X': // Pointer register pair X
+ case 'y': case 'Y': // Pointer register pair Y
+ case 'z': case 'Z': // Pointer register pair Z
+ Info.setAllowsRegister();
+ return true;
+ case 'I': // 6-bit positive integer constant
+ Info.setRequiresImmediate(0, 63);
+ return true;
+ case 'J': // 6-bit negative integer constant
+ Info.setRequiresImmediate(-63, 0);
+ return true;
+ case 'K': // Integer constant (Range: 2)
+ Info.setRequiresImmediate(2);
+ return true;
+ case 'L': // Integer constant (Range: 0)
+ Info.setRequiresImmediate(0);
+ return true;
+ case 'M': // 8-bit integer constant
+ Info.setRequiresImmediate(0, 0xff);
+ return true;
+ case 'N': // Integer constant (Range: -1)
+ Info.setRequiresImmediate(-1);
+ return true;
+ case 'O': // Integer constant (Range: 8, 16, 24)
+ Info.setRequiresImmediate({8, 16, 24});
+ return true;
+ case 'P': // Integer constant (Range: 1)
+ Info.setRequiresImmediate(1);
+ return true;
+ case 'R': // Integer constant (Range: -6 to 5)
+ Info.setRequiresImmediate(-6, 5);
+ return true;
+ case 'G': // Floating point constant
+ case 'Q': // A memory address based on Y or Z pointer with displacement.
+ return true;
+ }
+
return false;
}
@@ -8534,6 +9475,41 @@ public:
? (IsSigned ? SignedInt : UnsignedInt)
: TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned);
}
+
+ bool setCPU(const std::string &Name) override {
+ bool IsFamily = llvm::StringSwitch<bool>(Name)
+ .Case("avr1", true)
+ .Case("avr2", true)
+ .Case("avr25", true)
+ .Case("avr3", true)
+ .Case("avr31", true)
+ .Case("avr35", true)
+ .Case("avr4", true)
+ .Case("avr5", true)
+ .Case("avr51", true)
+ .Case("avr6", true)
+ .Case("avrxmega1", true)
+ .Case("avrxmega2", true)
+ .Case("avrxmega3", true)
+ .Case("avrxmega4", true)
+ .Case("avrxmega5", true)
+ .Case("avrxmega6", true)
+ .Case("avrxmega7", true)
+ .Case("avrtiny", true)
+ .Default(false);
+
+ if (IsFamily) this->CPU = Name;
+
+ bool IsMCU = std::find_if(AVRMcus.begin(), AVRMcus.end(),
+ [&](const MCUInfo &Info) { return Info.Name == Name; }) != AVRMcus.end();
+
+ if (IsMCU) this->CPU = Name;
+
+ return IsFamily || IsMCU;
+ }
+
+protected:
+ std::string CPU;
};
} // end anonymous namespace
@@ -8574,6 +9550,10 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new LinuxTargetInfo<AArch64leTargetInfo>(Triple, Opts);
case llvm::Triple::NetBSD:
return new NetBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts);
+ case llvm::Triple::OpenBSD:
+ return new OpenBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts);
+ case llvm::Triple::Win32:
+ return new MicrosoftARM64TargetInfo(Triple, Opts);
default:
return new AArch64leTargetInfo(Triple, Opts);
}
@@ -8604,8 +9584,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new LinuxTargetInfo<ARMleTargetInfo>(Triple, Opts);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<ARMleTargetInfo>(Triple, Opts);
- case llvm::Triple::Fuchsia:
- return new FuchsiaTargetInfo<ARMleTargetInfo>(Triple, Opts);
case llvm::Triple::NetBSD:
return new NetBSDTargetInfo<ARMleTargetInfo>(Triple, Opts);
case llvm::Triple::OpenBSD:
@@ -8642,8 +9620,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new LinuxTargetInfo<ARMbeTargetInfo>(Triple, Opts);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<ARMbeTargetInfo>(Triple, Opts);
- case llvm::Triple::Fuchsia:
- return new FuchsiaTargetInfo<ARMbeTargetInfo>(Triple, Opts);
case llvm::Triple::NetBSD:
return new NetBSDTargetInfo<ARMbeTargetInfo>(Triple, Opts);
case llvm::Triple::OpenBSD:
@@ -8667,6 +9643,9 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
case llvm::Triple::msp430:
return new MSP430TargetInfo(Triple, Opts);
+ case llvm::Triple::nios2:
+ return new LinuxTargetInfo<Nios2TargetInfo>(Triple, Opts);
+
case llvm::Triple::mips:
switch (os) {
case llvm::Triple::Linux:
@@ -8859,6 +9838,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new DarwinI386TargetInfo(Triple, Opts);
switch (os) {
+ case llvm::Triple::Ananas:
+ return new AnanasTargetInfo<X86_32TargetInfo>(Triple, Opts);
case llvm::Triple::CloudABI:
return new CloudABITargetInfo<X86_32TargetInfo>(Triple, Opts);
case llvm::Triple::Linux: {
@@ -8879,8 +9860,6 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new BitrigI386TargetInfo(Triple, Opts);
case llvm::Triple::FreeBSD:
return new FreeBSDTargetInfo<X86_32TargetInfo>(Triple, Opts);
- case llvm::Triple::Fuchsia:
- return new FuchsiaTargetInfo<X86_32TargetInfo>(Triple, Opts);
case llvm::Triple::KFreeBSD:
return new KFreeBSDTargetInfo<X86_32TargetInfo>(Triple, Opts);
case llvm::Triple::Minix:
@@ -8916,6 +9895,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new DarwinX86_64TargetInfo(Triple, Opts);
switch (os) {
+ case llvm::Triple::Ananas:
+ return new AnanasTargetInfo<X86_64TargetInfo>(Triple, Opts);
case llvm::Triple::CloudABI:
return new CloudABITargetInfo<X86_64TargetInfo>(Triple, Opts);
case llvm::Triple::Linux: {
@@ -8976,11 +9957,19 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new SPIR64TargetInfo(Triple, Opts);
}
case llvm::Triple::wasm32:
- if (!(Triple == llvm::Triple("wasm32-unknown-unknown")))
+ if (Triple.getSubArch() != llvm::Triple::NoSubArch ||
+ Triple.getVendor() != llvm::Triple::UnknownVendor ||
+ Triple.getOS() != llvm::Triple::UnknownOS ||
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment ||
+ !(Triple.isOSBinFormatELF() || Triple.isOSBinFormatWasm()))
return nullptr;
return new WebAssemblyOSTargetInfo<WebAssembly32TargetInfo>(Triple, Opts);
case llvm::Triple::wasm64:
- if (!(Triple == llvm::Triple("wasm64-unknown-unknown")))
+ if (Triple.getSubArch() != llvm::Triple::NoSubArch ||
+ Triple.getVendor() != llvm::Triple::UnknownVendor ||
+ Triple.getOS() != llvm::Triple::UnknownOS ||
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment ||
+ !(Triple.isOSBinFormatELF() || Triple.isOSBinFormatWasm()))
return nullptr;
return new WebAssemblyOSTargetInfo<WebAssembly64TargetInfo>(Triple, Opts);
diff --git a/contrib/llvm/tools/clang/lib/Basic/Version.cpp b/contrib/llvm/tools/clang/lib/Basic/Version.cpp
index 97e75a9..509c4a9 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Version.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/Version.cpp
@@ -36,7 +36,7 @@ std::string getClangRepositoryPath() {
// If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
// pick up a tag in an SVN export, for example.
- StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_400/final/lib/Basic/Version.cpp $");
+ StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_500/final/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
diff --git a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp
index 50fcb22..f5db717 100644
--- a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp
+++ b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp
@@ -27,13 +27,6 @@
#include <memory>
#include <utility>
-// For chdir.
-#ifdef LLVM_ON_WIN32
-# include <direct.h>
-#else
-# include <unistd.h>
-#endif
-
using namespace clang;
using namespace clang::vfs;
using namespace llvm;
@@ -235,11 +228,7 @@ std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
// difference for example on network filesystems, where symlinks might be
// switched during runtime of the tool. Fixing this depends on having a
// file system abstraction that allows openat() style interactions.
- SmallString<256> Storage;
- StringRef Dir = Path.toNullTerminatedStringRef(Storage);
- if (int Err = ::chdir(Dir.data()))
- return std::error_code(Err, std::generic_category());
- return std::error_code();
+ return llvm::sys::fs::set_current_path(Path);
}
IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
@@ -249,16 +238,13 @@ IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
namespace {
class RealFSDirIter : public clang::vfs::detail::DirIterImpl {
- std::string Path;
llvm::sys::fs::directory_iterator Iter;
public:
- RealFSDirIter(const Twine &_Path, std::error_code &EC)
- : Path(_Path.str()), Iter(Path, EC) {
+ RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
llvm::sys::fs::file_status S;
EC = Iter->status(S);
- if (!EC)
- CurrentEntry = Status::copyWithNewName(S, Iter->path());
+ CurrentEntry = Status::copyWithNewName(S, Iter->path());
}
}
@@ -1869,7 +1855,7 @@ vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,
std::error_code &EC)
: FS(&FS_) {
directory_iterator I = FS->dir_begin(Path, EC);
- if (!EC && I != directory_iterator()) {
+ if (I != directory_iterator()) {
State = std::make_shared<IterState>();
State->push(I);
}
@@ -1882,8 +1868,6 @@ recursive_directory_iterator::increment(std::error_code &EC) {
vfs::directory_iterator End;
if (State->top()->isDirectory()) {
vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
- if (EC)
- return *this;
if (I != End) {
State->push(I);
return *this;
diff --git a/contrib/llvm/tools/clang/lib/Basic/XRayLists.cpp b/contrib/llvm/tools/clang/lib/Basic/XRayLists.cpp
new file mode 100644
index 0000000..0a439c7
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Basic/XRayLists.cpp
@@ -0,0 +1,55 @@
+//===--- XRayFunctionFilter.cpp - XRay automatic-attribution --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided filters for always/never XRay instrumenting certain functions.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/XRayLists.h"
+
+using namespace clang;
+
+XRayFunctionFilter::XRayFunctionFilter(
+ ArrayRef<std::string> AlwaysInstrumentPaths,
+ ArrayRef<std::string> NeverInstrumentPaths, SourceManager &SM)
+ : AlwaysInstrument(
+ llvm::SpecialCaseList::createOrDie(AlwaysInstrumentPaths)),
+ NeverInstrument(llvm::SpecialCaseList::createOrDie(NeverInstrumentPaths)),
+ SM(SM) {}
+
+XRayFunctionFilter::ImbueAttribute
+XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const {
+ // First apply the always instrument list, than if it isn't an "always" see
+ // whether it's treated as a "never" instrument function.
+ if (AlwaysInstrument->inSection("fun", FunctionName, "arg1"))
+ return ImbueAttribute::ALWAYS_ARG1;
+ if (AlwaysInstrument->inSection("fun", FunctionName))
+ return ImbueAttribute::ALWAYS;
+ if (NeverInstrument->inSection("fun", FunctionName))
+ return ImbueAttribute::NEVER;
+ return ImbueAttribute::NONE;
+}
+
+XRayFunctionFilter::ImbueAttribute
+XRayFunctionFilter::shouldImbueFunctionsInFile(StringRef Filename,
+ StringRef Category) const {
+ if (AlwaysInstrument->inSection("src", Filename, Category))
+ return ImbueAttribute::ALWAYS;
+ if (NeverInstrument->inSection("src", Filename, Category))
+ return ImbueAttribute::NEVER;
+ return ImbueAttribute::NONE;
+}
+
+XRayFunctionFilter::ImbueAttribute
+XRayFunctionFilter::shouldImbueLocation(SourceLocation Loc,
+ StringRef Category) const {
+ if (!Loc.isValid())
+ return ImbueAttribute::NONE;
+ return this->shouldImbueFunctionsInFile(SM.getFilename(SM.getFileLoc(Loc)),
+ Category);
+}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ABIInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/ABIInfo.h
index ac31dfd..575506d 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/ABIInfo.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/ABIInfo.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_ABIINFO_H
#define LLVM_CLANG_LIB_CODEGEN_ABIINFO_H
+#include "clang/AST/CharUnits.h"
#include "clang/AST/Type.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Type.h"
@@ -23,6 +24,7 @@ namespace llvm {
namespace clang {
class ASTContext;
+ class CodeGenOptions;
class TargetInfo;
namespace CodeGen {
@@ -67,6 +69,7 @@ namespace swiftcall {
llvm::LLVMContext &getVMContext() const;
const llvm::DataLayout &getDataLayout() const;
const TargetInfo &getTarget() const;
+ const CodeGenOptions &getCodeGenOpts() const;
/// Return the calling convention to use for system runtime
/// functions.
@@ -148,7 +151,6 @@ namespace swiftcall {
return info->supportsSwift();
}
};
-
} // end namespace CodeGen
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp
index d2ce6ea..513896d 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp
@@ -35,7 +35,6 @@
#include "llvm/LTO/LTOBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/SubtargetFeature.h"
-#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -50,10 +49,12 @@
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
+#include "llvm/Transforms/Utils/NameAnonGlobals.h"
#include "llvm/Transforms/Utils/SymbolRewriter.h"
#include <memory>
using namespace clang;
@@ -61,6 +62,9 @@ using namespace llvm;
namespace {
+// Default filename used for profile generation.
+static constexpr StringLiteral DefaultProfileGenName = "default_%m.profraw";
+
class EmitAssemblyHelper {
DiagnosticsEngine &Diags;
const HeaderSearchOptions &HSOpts;
@@ -73,7 +77,6 @@ class EmitAssemblyHelper {
std::unique_ptr<raw_pwrite_stream> OS;
-private:
TargetIRAnalysis getTargetIRAnalysis() const {
if (TM)
return TM->getTargetIRAnalysis();
@@ -81,9 +84,6 @@ private:
return TargetIRAnalysis();
}
- /// Set LLVM command line options passed through -backend-option.
- void setCommandLineOpts();
-
void CreatePasses(legacy::PassManager &MPM, legacy::FunctionPassManager &FPM);
/// Generates the TargetMachine.
@@ -130,16 +130,20 @@ public:
// that we add to the PassManagerBuilder.
class PassManagerBuilderWrapper : public PassManagerBuilder {
public:
- PassManagerBuilderWrapper(const CodeGenOptions &CGOpts,
+ PassManagerBuilderWrapper(const Triple &TargetTriple,
+ const CodeGenOptions &CGOpts,
const LangOptions &LangOpts)
- : PassManagerBuilder(), CGOpts(CGOpts), LangOpts(LangOpts) {}
+ : PassManagerBuilder(), TargetTriple(TargetTriple), CGOpts(CGOpts),
+ LangOpts(LangOpts) {}
+ const Triple &getTargetTriple() const { return TargetTriple; }
const CodeGenOptions &getCGOpts() const { return CGOpts; }
const LangOptions &getLangOpts() const { return LangOpts; }
+
private:
+ const Triple &TargetTriple;
const CodeGenOptions &CGOpts;
const LangOptions &LangOpts;
};
-
}
static void addObjCARCAPElimPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
@@ -183,19 +187,42 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
Opts.Use8bitCounters = CGOpts.SanitizeCoverage8bitCounters;
Opts.TracePC = CGOpts.SanitizeCoverageTracePC;
Opts.TracePCGuard = CGOpts.SanitizeCoverageTracePCGuard;
+ Opts.NoPrune = CGOpts.SanitizeCoverageNoPrune;
+ Opts.Inline8bitCounters = CGOpts.SanitizeCoverageInline8bitCounters;
PM.add(createSanitizerCoverageModulePass(Opts));
}
+// Check if ASan should use GC-friendly instrumentation for globals.
+// First of all, there is no point if -fdata-sections is off (expect for MachO,
+// where this is not a factor). Also, on ELF this feature requires an assembler
+// extension that only works with -integrated-as at the moment.
+static bool asanUseGlobalsGC(const Triple &T, const CodeGenOptions &CGOpts) {
+ if (!CGOpts.SanitizeAddressGlobalsDeadStripping)
+ return false;
+ switch (T.getObjectFormat()) {
+ case Triple::MachO:
+ case Triple::COFF:
+ return true;
+ case Triple::ELF:
+ return CGOpts.DataSections && !CGOpts.DisableIntegratedAS;
+ default:
+ return false;
+ }
+}
+
static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) {
const PassManagerBuilderWrapper &BuilderWrapper =
static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const Triple &T = BuilderWrapper.getTargetTriple();
const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Address);
bool UseAfterScope = CGOpts.SanitizeAddressUseAfterScope;
+ bool UseGlobalsGC = asanUseGlobalsGC(T, CGOpts);
PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/ false, Recover,
UseAfterScope));
- PM.add(createAddressSanitizerModulePass(/*CompileKernel*/false, Recover));
+ PM.add(createAddressSanitizerModulePass(/*CompileKernel*/ false, Recover,
+ UseGlobalsGC));
}
static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder,
@@ -262,7 +289,7 @@ static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple,
TLII->disableAllFunctions();
else {
// Disable individual libc/libm calls in TargetLibraryInfo.
- LibFunc::Func F;
+ LibFunc F;
for (auto &FuncName : CodeGenOpts.getNoBuiltinFuncs())
if (TLII->getLibFunc(FuncName, F))
TLII->setUnavailable(F);
@@ -292,6 +319,140 @@ static void addSymbolRewriterPass(const CodeGenOptions &Opts,
MPM->add(createRewriteSymbolsPass(DL));
}
+static CodeGenOpt::Level getCGOptLevel(const CodeGenOptions &CodeGenOpts) {
+ switch (CodeGenOpts.OptimizationLevel) {
+ default:
+ llvm_unreachable("Invalid optimization level!");
+ case 0:
+ return CodeGenOpt::None;
+ case 1:
+ return CodeGenOpt::Less;
+ case 2:
+ return CodeGenOpt::Default; // O2/Os/Oz
+ case 3:
+ return CodeGenOpt::Aggressive;
+ }
+}
+
+static llvm::CodeModel::Model getCodeModel(const CodeGenOptions &CodeGenOpts) {
+ unsigned CodeModel =
+ llvm::StringSwitch<unsigned>(CodeGenOpts.CodeModel)
+ .Case("small", llvm::CodeModel::Small)
+ .Case("kernel", llvm::CodeModel::Kernel)
+ .Case("medium", llvm::CodeModel::Medium)
+ .Case("large", llvm::CodeModel::Large)
+ .Case("default", llvm::CodeModel::Default)
+ .Default(~0u);
+ assert(CodeModel != ~0u && "invalid code model!");
+ return static_cast<llvm::CodeModel::Model>(CodeModel);
+}
+
+static llvm::Reloc::Model getRelocModel(const CodeGenOptions &CodeGenOpts) {
+ // Keep this synced with the equivalent code in
+ // lib/Frontend/CompilerInvocation.cpp
+ llvm::Optional<llvm::Reloc::Model> RM;
+ RM = llvm::StringSwitch<llvm::Reloc::Model>(CodeGenOpts.RelocationModel)
+ .Case("static", llvm::Reloc::Static)
+ .Case("pic", llvm::Reloc::PIC_)
+ .Case("ropi", llvm::Reloc::ROPI)
+ .Case("rwpi", llvm::Reloc::RWPI)
+ .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI)
+ .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC);
+ assert(RM.hasValue() && "invalid PIC model!");
+ return *RM;
+}
+
+static TargetMachine::CodeGenFileType getCodeGenFileType(BackendAction Action) {
+ if (Action == Backend_EmitObj)
+ return TargetMachine::CGFT_ObjectFile;
+ else if (Action == Backend_EmitMCNull)
+ return TargetMachine::CGFT_Null;
+ else {
+ assert(Action == Backend_EmitAssembly && "Invalid action!");
+ return TargetMachine::CGFT_AssemblyFile;
+ }
+}
+
+static void initTargetOptions(llvm::TargetOptions &Options,
+ const CodeGenOptions &CodeGenOpts,
+ const clang::TargetOptions &TargetOpts,
+ const LangOptions &LangOpts,
+ const HeaderSearchOptions &HSOpts) {
+ Options.ThreadModel =
+ llvm::StringSwitch<llvm::ThreadModel::Model>(CodeGenOpts.ThreadModel)
+ .Case("posix", llvm::ThreadModel::POSIX)
+ .Case("single", llvm::ThreadModel::Single);
+
+ // Set float ABI type.
+ assert((CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp" ||
+ CodeGenOpts.FloatABI == "hard" || CodeGenOpts.FloatABI.empty()) &&
+ "Invalid Floating Point ABI!");
+ Options.FloatABIType =
+ llvm::StringSwitch<llvm::FloatABI::ABIType>(CodeGenOpts.FloatABI)
+ .Case("soft", llvm::FloatABI::Soft)
+ .Case("softfp", llvm::FloatABI::Soft)
+ .Case("hard", llvm::FloatABI::Hard)
+ .Default(llvm::FloatABI::Default);
+
+ // Set FP fusion mode.
+ switch (LangOpts.getDefaultFPContractMode()) {
+ case LangOptions::FPC_Off:
+ // Preserve any contraction performed by the front-end. (Strict performs
+ // splitting of the muladd instrinsic in the backend.)
+ Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
+ break;
+ case LangOptions::FPC_On:
+ Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
+ break;
+ case LangOptions::FPC_Fast:
+ Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
+ break;
+ }
+
+ Options.UseInitArray = CodeGenOpts.UseInitArray;
+ Options.DisableIntegratedAS = CodeGenOpts.DisableIntegratedAS;
+ Options.CompressDebugSections = CodeGenOpts.getCompressDebugSections();
+ Options.RelaxELFRelocations = CodeGenOpts.RelaxELFRelocations;
+
+ // Set EABI version.
+ Options.EABIVersion = TargetOpts.EABIVersion;
+
+ if (LangOpts.SjLjExceptions)
+ Options.ExceptionModel = llvm::ExceptionHandling::SjLj;
+
+ Options.NoInfsFPMath = CodeGenOpts.NoInfsFPMath;
+ Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath;
+ Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
+ Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath;
+ Options.StackAlignmentOverride = CodeGenOpts.StackAlignment;
+ Options.FunctionSections = CodeGenOpts.FunctionSections;
+ Options.DataSections = CodeGenOpts.DataSections;
+ Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames;
+ Options.EmulatedTLS = CodeGenOpts.EmulatedTLS;
+ Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning();
+
+ if (CodeGenOpts.EnableSplitDwarf)
+ Options.MCOptions.SplitDwarfFile = CodeGenOpts.SplitDwarfFile;
+ Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
+ Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
+ Options.MCOptions.MCUseDwarfDirectory = !CodeGenOpts.NoDwarfDirectoryAsm;
+ Options.MCOptions.MCNoExecStack = CodeGenOpts.NoExecStack;
+ Options.MCOptions.MCIncrementalLinkerCompatible =
+ CodeGenOpts.IncrementalLinkerCompatible;
+ Options.MCOptions.MCPIECopyRelocations = CodeGenOpts.PIECopyRelocations;
+ Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings;
+ Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
+ Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments;
+ Options.MCOptions.ABIName = TargetOpts.ABI;
+ for (const auto &Entry : HSOpts.UserEntries)
+ if (!Entry.IsFramework &&
+ (Entry.Group == frontend::IncludeDirGroup::Quoted ||
+ Entry.Group == frontend::IncludeDirGroup::Angled ||
+ Entry.Group == frontend::IncludeDirGroup::System))
+ Options.MCOptions.IASSearchPaths.push_back(
+ Entry.IgnoreSysRoot ? Entry.Path : HSOpts.Sysroot + Entry.Path);
+}
+
void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
legacy::FunctionPassManager &FPM) {
// Handle disabling of all LLVM passes, where we want to preserve the
@@ -299,8 +460,6 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
if (CodeGenOpts.DisableLLVMPasses)
return;
- PassManagerBuilderWrapper PMBuilder(CodeGenOpts, LangOpts);
-
// Figure out TargetLibraryInfo. This needs to be added to MPM and FPM
// manually (and not via PMBuilder), since some passes (eg. InstrProfiling)
// are inserted before PMBuilder ones - they'd get the default-constructed
@@ -309,6 +468,8 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
std::unique_ptr<TargetLibraryInfoImpl> TLII(
createTLII(TargetTriple, CodeGenOpts));
+ PassManagerBuilderWrapper PMBuilder(TargetTriple, CodeGenOpts, LangOpts);
+
// At O0 and O1 we only run the always inliner which is more efficient. At
// higher optimization levels we run the normal inliner.
if (CodeGenOpts.OptimizationLevel <= 1) {
@@ -316,13 +477,17 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
!CodeGenOpts.DisableLifetimeMarkers);
PMBuilder.Inliner = createAlwaysInlinerLegacyPass(InsertLifetimeIntrinsics);
} else {
+ // We do not want to inline hot callsites for SamplePGO module-summary build
+ // because profile annotation will happen again in ThinLTO backend, and we
+ // want the IR of the hot path to match the profile.
PMBuilder.Inliner = createFunctionInliningPass(
- CodeGenOpts.OptimizationLevel, CodeGenOpts.OptimizeSize);
+ CodeGenOpts.OptimizationLevel, CodeGenOpts.OptimizeSize,
+ (!CodeGenOpts.SampleProfileFile.empty() &&
+ CodeGenOpts.EmitSummaryIndex));
}
PMBuilder.OptLevel = CodeGenOpts.OptimizationLevel;
PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
- PMBuilder.BBVectorize = CodeGenOpts.VectorizeBB;
PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP;
PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop;
@@ -334,16 +499,13 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
MPM.add(new TargetLibraryInfoWrapperPass(*TLII));
- // Add target-specific passes that need to run as early as possible.
if (TM)
- PMBuilder.addExtension(
- PassManagerBuilder::EP_EarlyAsPossible,
- [&](const PassManagerBuilder &, legacy::PassManagerBase &PM) {
- TM->addEarlyAsPossiblePasses(PM);
- });
+ TM->adjustPassManager(PMBuilder);
- PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
- addAddDiscriminatorsPass);
+ if (CodeGenOpts.DebugInfoForProfiling ||
+ !CodeGenOpts.SampleProfileFile.empty())
+ PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
+ addAddDiscriminatorsPass);
// In ObjC ARC mode, add the main ARC optimization passes.
if (LangOpts.ObjCAutoRefCount) {
@@ -454,7 +616,7 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
if (!CodeGenOpts.InstrProfileOutput.empty())
PMBuilder.PGOInstrGen = CodeGenOpts.InstrProfileOutput;
else
- PMBuilder.PGOInstrGen = "default_%m.profraw";
+ PMBuilder.PGOInstrGen = DefaultProfileGenName;
}
if (CodeGenOpts.hasProfileIRUse())
PMBuilder.PGOInstrUse = CodeGenOpts.ProfileInstrumentUsePath;
@@ -466,7 +628,7 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
PMBuilder.populateModulePassManager(MPM);
}
-void EmitAssemblyHelper::setCommandLineOpts() {
+static void setCommandLineOpts(const CodeGenOptions &CodeGenOpts) {
SmallVector<const char *, 16> BackendArgs;
BackendArgs.push_back("clang"); // Fake program name.
if (!CodeGenOpts.DebugPass.empty()) {
@@ -495,126 +657,14 @@ void EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
return;
}
- unsigned CodeModel =
- llvm::StringSwitch<unsigned>(CodeGenOpts.CodeModel)
- .Case("small", llvm::CodeModel::Small)
- .Case("kernel", llvm::CodeModel::Kernel)
- .Case("medium", llvm::CodeModel::Medium)
- .Case("large", llvm::CodeModel::Large)
- .Case("default", llvm::CodeModel::Default)
- .Default(~0u);
- assert(CodeModel != ~0u && "invalid code model!");
- llvm::CodeModel::Model CM = static_cast<llvm::CodeModel::Model>(CodeModel);
-
+ llvm::CodeModel::Model CM = getCodeModel(CodeGenOpts);
std::string FeaturesStr =
llvm::join(TargetOpts.Features.begin(), TargetOpts.Features.end(), ",");
-
- // Keep this synced with the equivalent code in tools/driver/cc1as_main.cpp.
- llvm::Optional<llvm::Reloc::Model> RM;
- RM = llvm::StringSwitch<llvm::Reloc::Model>(CodeGenOpts.RelocationModel)
- .Case("static", llvm::Reloc::Static)
- .Case("pic", llvm::Reloc::PIC_)
- .Case("ropi", llvm::Reloc::ROPI)
- .Case("rwpi", llvm::Reloc::RWPI)
- .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI)
- .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC);
- assert(RM.hasValue() && "invalid PIC model!");
-
- CodeGenOpt::Level OptLevel;
- switch (CodeGenOpts.OptimizationLevel) {
- default:
- llvm_unreachable("Invalid optimization level!");
- case 0:
- OptLevel = CodeGenOpt::None;
- break;
- case 1:
- OptLevel = CodeGenOpt::Less;
- break;
- case 2:
- OptLevel = CodeGenOpt::Default;
- break; // O2/Os/Oz
- case 3:
- OptLevel = CodeGenOpt::Aggressive;
- break;
- }
+ llvm::Reloc::Model RM = getRelocModel(CodeGenOpts);
+ CodeGenOpt::Level OptLevel = getCGOptLevel(CodeGenOpts);
llvm::TargetOptions Options;
-
- Options.ThreadModel =
- llvm::StringSwitch<llvm::ThreadModel::Model>(CodeGenOpts.ThreadModel)
- .Case("posix", llvm::ThreadModel::POSIX)
- .Case("single", llvm::ThreadModel::Single);
-
- // Set float ABI type.
- assert((CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp" ||
- CodeGenOpts.FloatABI == "hard" || CodeGenOpts.FloatABI.empty()) &&
- "Invalid Floating Point ABI!");
- Options.FloatABIType =
- llvm::StringSwitch<llvm::FloatABI::ABIType>(CodeGenOpts.FloatABI)
- .Case("soft", llvm::FloatABI::Soft)
- .Case("softfp", llvm::FloatABI::Soft)
- .Case("hard", llvm::FloatABI::Hard)
- .Default(llvm::FloatABI::Default);
-
- // Set FP fusion mode.
- switch (CodeGenOpts.getFPContractMode()) {
- case CodeGenOptions::FPC_Off:
- Options.AllowFPOpFusion = llvm::FPOpFusion::Strict;
- break;
- case CodeGenOptions::FPC_On:
- Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
- break;
- case CodeGenOptions::FPC_Fast:
- Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
- break;
- }
-
- Options.UseInitArray = CodeGenOpts.UseInitArray;
- Options.DisableIntegratedAS = CodeGenOpts.DisableIntegratedAS;
- Options.CompressDebugSections = CodeGenOpts.CompressDebugSections;
- Options.RelaxELFRelocations = CodeGenOpts.RelaxELFRelocations;
-
- // Set EABI version.
- Options.EABIVersion = llvm::StringSwitch<llvm::EABI>(TargetOpts.EABIVersion)
- .Case("4", llvm::EABI::EABI4)
- .Case("5", llvm::EABI::EABI5)
- .Case("gnu", llvm::EABI::GNU)
- .Default(llvm::EABI::Default);
-
- if (LangOpts.SjLjExceptions)
- Options.ExceptionModel = llvm::ExceptionHandling::SjLj;
-
- Options.LessPreciseFPMADOption = CodeGenOpts.LessPreciseFPMAD;
- Options.NoInfsFPMath = CodeGenOpts.NoInfsFPMath;
- Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath;
- Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
- Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath;
- Options.StackAlignmentOverride = CodeGenOpts.StackAlignment;
- Options.FunctionSections = CodeGenOpts.FunctionSections;
- Options.DataSections = CodeGenOpts.DataSections;
- Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames;
- Options.EmulatedTLS = CodeGenOpts.EmulatedTLS;
- Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning();
-
- Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
- Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
- Options.MCOptions.MCUseDwarfDirectory = !CodeGenOpts.NoDwarfDirectoryAsm;
- Options.MCOptions.MCNoExecStack = CodeGenOpts.NoExecStack;
- Options.MCOptions.MCIncrementalLinkerCompatible =
- CodeGenOpts.IncrementalLinkerCompatible;
- Options.MCOptions.MCPIECopyRelocations = CodeGenOpts.PIECopyRelocations;
- Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings;
- Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
- Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments;
- Options.MCOptions.ABIName = TargetOpts.ABI;
- for (const auto &Entry : HSOpts.UserEntries)
- if (!Entry.IsFramework &&
- (Entry.Group == frontend::IncludeDirGroup::Quoted ||
- Entry.Group == frontend::IncludeDirGroup::Angled ||
- Entry.Group == frontend::IncludeDirGroup::System))
- Options.MCOptions.IASSearchPaths.push_back(
- Entry.IgnoreSysRoot ? Entry.Path : HSOpts.Sysroot + Entry.Path);
-
+ initTargetOptions(Options, CodeGenOpts, TargetOpts, LangOpts, HSOpts);
TM.reset(TheTarget->createTargetMachine(Triple, TargetOpts.CPU, FeaturesStr,
Options, RM, CM, OptLevel));
}
@@ -630,13 +680,7 @@ bool EmitAssemblyHelper::AddEmitPasses(legacy::PassManager &CodeGenPasses,
// Normal mode, emit a .s or .o file by running the code generator. Note,
// this also adds codegenerator level optimization passes.
- TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile;
- if (Action == Backend_EmitObj)
- CGFT = TargetMachine::CGFT_ObjectFile;
- else if (Action == Backend_EmitMCNull)
- CGFT = TargetMachine::CGFT_Null;
- else
- assert(Action == Backend_EmitAssembly && "Invalid action!");
+ TargetMachine::CodeGenFileType CGFT = getCodeGenFileType(Action);
// Add ObjC ARC final-cleanup optimizations. This is done as part of the
// "codegen" passes so that it isn't run multiple times when there is
@@ -657,7 +701,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
std::unique_ptr<raw_pwrite_stream> OS) {
TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr);
- setCommandLineOpts();
+ setCommandLineOpts(CodeGenOpts);
bool UsesCodeGen = (Action != Backend_EmitNothing &&
Action != Backend_EmitBC &&
@@ -683,14 +727,31 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
CodeGenPasses.add(
createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
+ std::unique_ptr<raw_fd_ostream> ThinLinkOS;
+
switch (Action) {
case Backend_EmitNothing:
break;
case Backend_EmitBC:
- PerModulePasses.add(createBitcodeWriterPass(
- *OS, CodeGenOpts.EmitLLVMUseLists, CodeGenOpts.EmitSummaryIndex,
- CodeGenOpts.EmitSummaryIndex));
+ if (CodeGenOpts.EmitSummaryIndex) {
+ if (!CodeGenOpts.ThinLinkBitcodeFile.empty()) {
+ std::error_code EC;
+ ThinLinkOS.reset(new llvm::raw_fd_ostream(
+ CodeGenOpts.ThinLinkBitcodeFile, EC,
+ llvm::sys::fs::F_None));
+ if (EC) {
+ Diags.Report(diag::err_fe_unable_to_open_output) << CodeGenOpts.ThinLinkBitcodeFile
+ << EC.message();
+ return;
+ }
+ }
+ PerModulePasses.add(
+ createWriteThinLTOBitcodePass(*OS, ThinLinkOS.get()));
+ }
+ else
+ PerModulePasses.add(
+ createBitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists));
break;
case Backend_EmitLL:
@@ -769,7 +830,7 @@ static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) {
void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) {
TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr);
- setCommandLineOpts();
+ setCommandLineOpts(CodeGenOpts);
// The new pass manager always makes a target machine available to passes
// during construction.
@@ -779,7 +840,28 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
return;
TheModule->setDataLayout(TM->createDataLayout());
- PassBuilder PB(TM.get());
+ PGOOptions PGOOpt;
+
+ // -fprofile-generate.
+ PGOOpt.RunProfileGen = CodeGenOpts.hasProfileIRInstr();
+ if (PGOOpt.RunProfileGen)
+ PGOOpt.ProfileGenFile = CodeGenOpts.InstrProfileOutput.empty() ?
+ DefaultProfileGenName : CodeGenOpts.InstrProfileOutput;
+
+ // -fprofile-use.
+ if (CodeGenOpts.hasProfileIRUse())
+ PGOOpt.ProfileUseFile = CodeGenOpts.ProfileInstrumentUsePath;
+
+ if (!CodeGenOpts.SampleProfileFile.empty())
+ PGOOpt.SampleProfileFile = CodeGenOpts.SampleProfileFile;
+
+ // Only pass a PGO options struct if -fprofile-generate or
+ // -fprofile-use were passed on the cmdline.
+ PassBuilder PB(TM.get(),
+ (PGOOpt.RunProfileGen ||
+ !PGOOpt.ProfileUseFile.empty() ||
+ !PGOOpt.SampleProfileFile.empty()) ?
+ Optional<PGOOptions>(PGOOpt) : None);
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
@@ -796,20 +878,34 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
PB.registerLoopAnalyses(LAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
- ModulePassManager MPM;
+ ModulePassManager MPM(CodeGenOpts.DebugPassManager);
if (!CodeGenOpts.DisableLLVMPasses) {
+ bool IsThinLTO = CodeGenOpts.EmitSummaryIndex;
+ bool IsLTO = CodeGenOpts.PrepareForLTO;
+
if (CodeGenOpts.OptimizationLevel == 0) {
// Build a minimal pipeline based on the semantics required by Clang,
// which is just that always inlining occurs.
MPM.addPass(AlwaysInlinerPass());
+ if (IsThinLTO)
+ MPM.addPass(NameAnonGlobalPass());
} else {
- // Otherwise, use the default pass pipeline. We also have to map our
- // optimization levels into one of the distinct levels used to configure
- // the pipeline.
+ // Map our optimization levels into one of the distinct levels used to
+ // configure the pipeline.
PassBuilder::OptimizationLevel Level = mapToLevel(CodeGenOpts);
- MPM = PB.buildPerModuleDefaultPipeline(Level);
+ if (IsThinLTO) {
+ MPM = PB.buildThinLTOPreLinkDefaultPipeline(
+ Level, CodeGenOpts.DebugPassManager);
+ MPM.addPass(NameAnonGlobalPass());
+ } else if (IsLTO) {
+ MPM = PB.buildLTOPreLinkDefaultPipeline(Level,
+ CodeGenOpts.DebugPassManager);
+ } else {
+ MPM = PB.buildPerModuleDefaultPipeline(Level,
+ CodeGenOpts.DebugPassManager);
+ }
}
}
@@ -817,6 +913,7 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
// create that pass manager here and use it as needed below.
legacy::PassManager CodeGenPasses;
bool NeedCodeGen = false;
+ Optional<raw_fd_ostream> ThinLinkOS;
// Append any output we need to the pass manager.
switch (Action) {
@@ -824,9 +921,24 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
break;
case Backend_EmitBC:
- MPM.addPass(BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists,
- CodeGenOpts.EmitSummaryIndex,
- CodeGenOpts.EmitSummaryIndex));
+ if (CodeGenOpts.EmitSummaryIndex) {
+ if (!CodeGenOpts.ThinLinkBitcodeFile.empty()) {
+ std::error_code EC;
+ ThinLinkOS.emplace(CodeGenOpts.ThinLinkBitcodeFile, EC,
+ llvm::sys::fs::F_None);
+ if (EC) {
+ Diags.Report(diag::err_fe_unable_to_open_output)
+ << CodeGenOpts.ThinLinkBitcodeFile << EC.message();
+ return;
+ }
+ }
+ MPM.addPass(
+ ThinLTOBitcodeWriterPass(*OS, ThinLinkOS ? &*ThinLinkOS : nullptr));
+ } else {
+ MPM.addPass(BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists,
+ CodeGenOpts.EmitSummaryIndex,
+ CodeGenOpts.EmitSummaryIndex));
+ }
break;
case Backend_EmitLL:
@@ -861,21 +973,50 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
}
}
+Expected<BitcodeModule> clang::FindThinLTOModule(MemoryBufferRef MBRef) {
+ Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(MBRef);
+ if (!BMsOrErr)
+ return BMsOrErr.takeError();
+
+ // The bitcode file may contain multiple modules, we want the one that is
+ // marked as being the ThinLTO module.
+ for (BitcodeModule &BM : *BMsOrErr) {
+ Expected<BitcodeLTOInfo> LTOInfo = BM.getLTOInfo();
+ if (LTOInfo && LTOInfo->IsThinLTO)
+ return BM;
+ }
+
+ return make_error<StringError>("Could not find module summary",
+ inconvertibleErrorCode());
+}
+
static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
- std::unique_ptr<raw_pwrite_stream> OS) {
- StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
+ const HeaderSearchOptions &HeaderOpts,
+ const CodeGenOptions &CGOpts,
+ const clang::TargetOptions &TOpts,
+ const LangOptions &LOpts,
+ std::unique_ptr<raw_pwrite_stream> OS,
+ std::string SampleProfile,
+ BackendAction Action) {
+ StringMap<DenseMap<GlobalValue::GUID, GlobalValueSummary *>>
ModuleToDefinedGVSummaries;
CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
+ setCommandLineOpts(CGOpts);
+
// We can simply import the values mentioned in the combined index, since
// we should only invoke this using the individual indexes written out
// 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())
@@ -897,32 +1038,15 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
return;
}
- Expected<std::vector<BitcodeModule>> BMsOrErr =
- getBitcodeModuleList(**MBOrErr);
- if (!BMsOrErr) {
- handleAllErrors(BMsOrErr.takeError(), [&](ErrorInfoBase &EIB) {
+ Expected<BitcodeModule> BMOrErr = FindThinLTOModule(**MBOrErr);
+ if (!BMOrErr) {
+ handleAllErrors(BMOrErr.takeError(), [&](ErrorInfoBase &EIB) {
errs() << "Error loading imported file '" << I.first()
<< "': " << EIB.message() << '\n';
});
return;
}
-
- // The bitcode file may contain multiple modules, we want the one with a
- // summary.
- bool FoundModule = false;
- for (BitcodeModule &BM : *BMsOrErr) {
- Expected<bool> HasSummary = BM.hasSummary();
- if (HasSummary && *HasSummary) {
- ModuleMap.insert({I.first(), BM});
- FoundModule = true;
- break;
- }
- }
- if (!FoundModule) {
- errs() << "Error loading imported file '" << I.first()
- << "': Could not find module summary\n";
- return;
- }
+ ModuleMap.insert({I.first(), *BMOrErr});
OwnedImports.push_back(std::move(*MBOrErr));
}
@@ -930,6 +1054,36 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
return llvm::make_unique<lto::NativeObjectStream>(std::move(OS));
};
lto::Config Conf;
+ Conf.CPU = TOpts.CPU;
+ Conf.CodeModel = getCodeModel(CGOpts);
+ Conf.MAttrs = TOpts.Features;
+ Conf.RelocModel = getRelocModel(CGOpts);
+ Conf.CGOptLevel = getCGOptLevel(CGOpts);
+ initTargetOptions(Conf.Options, CGOpts, TOpts, LOpts, HeaderOpts);
+ Conf.SampleProfile = std::move(SampleProfile);
+ Conf.UseNewPM = CGOpts.ExperimentalNewPassManager;
+ switch (Action) {
+ case Backend_EmitNothing:
+ Conf.PreCodeGenModuleHook = [](size_t Task, const Module &Mod) {
+ return false;
+ };
+ break;
+ case Backend_EmitLL:
+ Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) {
+ M->print(*OS, nullptr, CGOpts.EmitLLVMUseLists);
+ return false;
+ };
+ break;
+ case Backend_EmitBC:
+ Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) {
+ WriteBitcodeToFile(M, *OS, CGOpts.EmitLLVMUseLists);
+ return false;
+ };
+ break;
+ default:
+ Conf.CGFileType = getCodeGenFileType(Action);
+ break;
+ }
if (Error E = thinBackend(
Conf, 0, AddStream, *M, *CombinedIndex, ImportList,
ModuleToDefinedGVSummaries[M->getModuleIdentifier()], ModuleMap)) {
@@ -952,7 +1106,8 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
// into memory and pass it into runThinLTOBackend, which will run the
// function importer and invoke LTO passes.
Expected<std::unique_ptr<ModuleSummaryIndex>> IndexOrErr =
- llvm::getModuleSummaryIndexForFile(CGOpts.ThinLTOIndexFile);
+ llvm::getModuleSummaryIndexForFile(CGOpts.ThinLTOIndexFile,
+ /*IgnoreEmptyThinLTOIndexFile*/true);
if (!IndexOrErr) {
logAllUnhandledErrors(IndexOrErr.takeError(), errs(),
"Error loading index file '" +
@@ -965,7 +1120,8 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
// of an error).
bool DoThinLTOBackend = CombinedIndex != nullptr;
if (DoThinLTOBackend) {
- runThinLTOBackend(CombinedIndex.get(), M, std::move(OS));
+ runThinLTOBackend(CombinedIndex.get(), M, HeaderOpts, CGOpts, TOpts,
+ LOpts, std::move(OS), CGOpts.SampleProfileFile, Action);
return;
}
}
@@ -996,6 +1152,7 @@ static const char* getSectionNameForBitcode(const Triple &T) {
return "__LLVM,__bitcode";
case Triple::COFF:
case Triple::ELF:
+ case Triple::Wasm:
case Triple::UnknownObjectFormat:
return ".llvmbc";
}
@@ -1008,6 +1165,7 @@ static const char* getSectionNameForCommandline(const Triple &T) {
return "__LLVM,__cmdline";
case Triple::COFF:
case Triple::ELF:
+ case Triple::Wasm:
case Triple::UnknownObjectFormat:
return ".llvmcmd";
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp
index 9287e46..a6e6fec 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGAtomic.cpp
@@ -95,7 +95,7 @@ namespace {
BFI.StorageOffset += OffsetInChars;
LVal = LValue::MakeBitfield(Address(Addr, lvalue.getAlignment()),
BFI, lvalue.getType(),
- lvalue.getAlignmentSource());
+ lvalue.getBaseInfo());
LVal.setTBAAInfo(lvalue.getTBAAInfo());
AtomicTy = C.getIntTypeForBitwidth(AtomicSizeInBits, OrigBFI.IsSigned);
if (AtomicTy.isNull()) {
@@ -203,7 +203,7 @@ namespace {
addr = CGF.Builder.CreateStructGEP(addr, 0, CharUnits());
return LValue::MakeAddr(addr, getValueType(), CGF.getContext(),
- LVal.getAlignmentSource(), LVal.getTBAAInfo());
+ LVal.getBaseInfo(), LVal.getTBAAInfo());
}
/// \brief Emits atomic load.
@@ -1181,15 +1181,15 @@ RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
if (LVal.isBitField())
return CGF.EmitLoadOfBitfieldLValue(
LValue::MakeBitfield(addr, LVal.getBitFieldInfo(), LVal.getType(),
- LVal.getAlignmentSource()));
+ LVal.getBaseInfo()), loc);
if (LVal.isVectorElt())
return CGF.EmitLoadOfLValue(
LValue::MakeVectorElt(addr, LVal.getVectorIdx(), LVal.getType(),
- LVal.getAlignmentSource()), loc);
+ LVal.getBaseInfo()), loc);
assert(LVal.isExtVectorElt());
return CGF.EmitLoadOfExtVectorElementLValue(LValue::MakeExtVectorElt(
addr, LVal.getExtVectorElts(), LVal.getType(),
- LVal.getAlignmentSource()));
+ LVal.getBaseInfo()));
}
RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal,
@@ -1506,26 +1506,26 @@ EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics, RValue OldRVal,
UpdateLVal =
LValue::MakeBitfield(Ptr, AtomicLVal.getBitFieldInfo(),
AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo());
DesiredLVal =
LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo());
} else if (AtomicLVal.isVectorElt()) {
UpdateLVal = LValue::MakeVectorElt(Ptr, AtomicLVal.getVectorIdx(),
AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo());
DesiredLVal = LValue::MakeVectorElt(
DesiredAddr, AtomicLVal.getVectorIdx(), AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo());
} else {
assert(AtomicLVal.isExtVectorElt());
UpdateLVal = LValue::MakeExtVectorElt(Ptr, AtomicLVal.getExtVectorElts(),
AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo());
DesiredLVal = LValue::MakeExtVectorElt(
DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo());
}
UpdateLVal.setTBAAInfo(AtomicLVal.getTBAAInfo());
DesiredLVal.setTBAAInfo(AtomicLVal.getTBAAInfo());
@@ -1612,17 +1612,17 @@ static void EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics,
DesiredLVal =
LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo());
} else if (AtomicLVal.isVectorElt()) {
DesiredLVal =
LValue::MakeVectorElt(DesiredAddr, AtomicLVal.getVectorIdx(),
AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo());
} else {
assert(AtomicLVal.isExtVectorElt());
DesiredLVal = LValue::MakeExtVectorElt(
DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
- AtomicLVal.getAlignmentSource());
+ AtomicLVal.getBaseInfo());
}
DesiredLVal.setTBAAInfo(AtomicLVal.getTBAAInfo());
// Store new value in the corresponding memory area
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp
index b250b9a..1810489 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp
@@ -16,7 +16,7 @@
#include "CGObjCRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "ConstantBuilder.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/IR/CallSite.h"
@@ -266,7 +266,7 @@ static bool isSafeForCXXConstantCapture(QualType type) {
static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
CodeGenFunction *CGF,
const VarDecl *var) {
- // Return if this is a function paramter. We shouldn't try to
+ // Return if this is a function parameter. We shouldn't try to
// rematerialize default arguments of function parameters.
if (isa<ParmVarDecl>(var))
return nullptr;
@@ -318,6 +318,19 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
elementTypes.push_back(CGM.getBlockDescriptorType());
}
+static QualType getCaptureFieldType(const CodeGenFunction &CGF,
+ const BlockDecl::Capture &CI) {
+ const VarDecl *VD = CI.getVariable();
+
+ // If the variable is captured by an enclosing block or lambda expression,
+ // use the type of the capture field.
+ if (CGF.BlockInfo && CI.isNested())
+ return CGF.BlockInfo->getCapture(VD).fieldType();
+ if (auto *FD = CGF.LambdaCaptureFields.lookup(VD))
+ return FD->getType();
+ return VD->getType();
+}
+
/// Compute the layout of the given block. Attempts to lay the block
/// out with minimal space requirements.
static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
@@ -432,15 +445,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
}
}
- QualType VT = variable->getType();
-
- // If the variable is captured by an enclosing block or lambda expression,
- // use the type of the capture field.
- if (CGF->BlockInfo && CI.isNested())
- VT = CGF->BlockInfo->getCapture(variable).fieldType();
- else if (auto *FD = CGF->LambdaCaptureFields.lookup(variable))
- VT = FD->getType();
-
+ QualType VT = getCaptureFieldType(*CGF, CI);
CharUnits size = C.getTypeSizeInChars(VT);
CharUnits align = C.getDeclAlign(variable);
@@ -606,15 +611,25 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
if (capture.isConstant()) continue;
// Ignore objects that aren't destructed.
- QualType::DestructionKind dtorKind =
- variable->getType().isDestructedType();
+ QualType VT = getCaptureFieldType(CGF, CI);
+ QualType::DestructionKind dtorKind = VT.isDestructedType();
if (dtorKind == QualType::DK_none) continue;
CodeGenFunction::Destroyer *destroyer;
// Block captures count as local values and have imprecise semantics.
// They also can't be arrays, so need to worry about that.
- if (dtorKind == QualType::DK_objc_strong_lifetime) {
+ //
+ // 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 &&
+ 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) {
destroyer = CodeGenFunction::destroyARCStrongImprecise;
} else {
destroyer = CGF.getDestroyer(dtorKind);
@@ -634,7 +649,7 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
if (useArrayEHCleanup)
cleanupKind = InactiveNormalAndEHCleanup;
- CGF.pushDestroy(cleanupKind, addr, variable->getType(),
+ CGF.pushDestroy(cleanupKind, addr, VT,
destroyer, useArrayEHCleanup);
// Remember where that cleanup was.
@@ -718,7 +733,12 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// Otherwise, we have to emit this as a local block.
- llvm::Constant *isa = CGM.getNSConcreteStackBlock();
+ llvm::Constant *isa =
+ (!CGM.getContext().getLangOpts().OpenCL)
+ ? CGM.getNSConcreteStackBlock()
+ : CGM.getNullPointer(VoidPtrPtrTy,
+ CGM.getContext().getPointerType(
+ QualType(CGM.getContext().VoidPtrTy)));
isa = llvm::ConstantExpr::getBitCast(isa, VoidPtrTy);
// Build the block descriptor.
@@ -856,6 +876,13 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
} else if (type->isReferenceType()) {
Builder.CreateStore(src.getPointer(), blockField);
+ // If type is const-qualified, copy the value into the block field.
+ } else if (type.isConstQualified() &&
+ type.getObjCLifetime() == Qualifiers::OCL_Strong &&
+ CGM.getCodeGenOpts().OptimizationLevel != 0) {
+ llvm::Value *value = Builder.CreateLoad(src, "captured");
+ Builder.CreateStore(value, blockField);
+
// If this is an ARC __strong block-pointer variable, don't do a
// block copy.
//
@@ -876,9 +903,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
} else {
// Fake up a new variable so that EmitScalarInit doesn't think
// we're referring to the variable in its own initializer.
- ImplicitParamDecl blockFieldPseudoVar(getContext(), /*DC*/ nullptr,
- SourceLocation(), /*name*/ nullptr,
- type);
+ ImplicitParamDecl BlockFieldPseudoVar(getContext(), type,
+ ImplicitParamDecl::Other);
// We use one of these or the other depending on whether the
// reference is nested.
@@ -891,8 +917,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// FIXME: Pass a specific location for the expr init so that the store is
// attributed to a reasonable location - otherwise it may be attributed to
// locations of subexpressions in the initialization.
- EmitExprAsInit(&l2r, &blockFieldPseudoVar,
- MakeAddrLValue(blockField, type, AlignmentSource::Decl),
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
+ EmitExprAsInit(&l2r, &BlockFieldPseudoVar,
+ MakeAddrLValue(blockField, type, BaseInfo),
/*captured by init*/ false);
}
@@ -906,9 +933,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// Cast to the converted block-pointer type, which happens (somewhat
// unfortunately) to be a pointer to function type.
- llvm::Value *result =
- Builder.CreateBitCast(blockAddr.getPointer(),
- ConvertType(blockInfo.getBlockExpr()->getType()));
+ llvm::Value *result = Builder.CreatePointerCast(
+ blockAddr.getPointer(), ConvertType(blockInfo.getBlockExpr()->getType()));
return result;
}
@@ -935,9 +961,8 @@ llvm::Type *CodeGenModule::getBlockDescriptorType() {
// const char *signature; // the block signature
// const char *layout; // reserved
// };
- BlockDescriptorType =
- llvm::StructType::create("struct.__block_descriptor",
- UnsignedLongTy, UnsignedLongTy, nullptr);
+ BlockDescriptorType = llvm::StructType::create(
+ "struct.__block_descriptor", UnsignedLongTy, UnsignedLongTy);
// Now form a pointer to that.
unsigned AddrSpace = 0;
@@ -961,9 +986,8 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
// struct __block_descriptor *__descriptor;
// };
GenericBlockLiteralType =
- llvm::StructType::create("struct.__block_literal_generic",
- VoidPtrTy, IntTy, IntTy, VoidPtrTy,
- BlockDescPtrTy, nullptr);
+ llvm::StructType::create("struct.__block_literal_generic", VoidPtrTy,
+ IntTy, IntTy, VoidPtrTy, BlockDescPtrTy);
return GenericBlockLiteralType;
}
@@ -976,21 +1000,41 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
llvm::Value *BlockPtr = EmitScalarExpr(E->getCallee());
// Get a pointer to the generic block literal.
+ // For OpenCL we generate generic AS void ptr to be able to reuse the same
+ // block definition for blocks with captures generated as private AS local
+ // variables and without captures generated as global AS program scope
+ // variables.
+ unsigned AddrSpace = 0;
+ if (getLangOpts().OpenCL)
+ AddrSpace = getContext().getTargetAddressSpace(LangAS::opencl_generic);
+
llvm::Type *BlockLiteralTy =
- llvm::PointerType::getUnqual(CGM.getGenericBlockLiteralType());
+ llvm::PointerType::get(CGM.getGenericBlockLiteralType(), AddrSpace);
// Bitcast the callee to a block literal.
- BlockPtr = Builder.CreateBitCast(BlockPtr, BlockLiteralTy, "block.literal");
+ BlockPtr =
+ Builder.CreatePointerCast(BlockPtr, BlockLiteralTy, "block.literal");
// Get the function pointer from the literal.
llvm::Value *FuncPtr =
Builder.CreateStructGEP(CGM.getGenericBlockLiteralType(), BlockPtr, 3);
- BlockPtr = Builder.CreateBitCast(BlockPtr, VoidPtrTy);
// Add the block literal.
CallArgList Args;
- Args.add(RValue::get(BlockPtr), getContext().VoidPtrTy);
+
+ QualType VoidPtrQualTy = getContext().VoidPtrTy;
+ llvm::Type *GenericVoidPtrTy = VoidPtrTy;
+ if (getLangOpts().OpenCL) {
+ GenericVoidPtrTy = Builder.getInt8PtrTy(
+ getContext().getTargetAddressSpace(LangAS::opencl_generic));
+ VoidPtrQualTy =
+ getContext().getPointerType(getContext().getAddrSpaceQualType(
+ getContext().VoidTy, LangAS::opencl_generic));
+ }
+
+ BlockPtr = Builder.CreatePointerCast(BlockPtr, GenericVoidPtrTy);
+ Args.add(RValue::get(BlockPtr), VoidPtrQualTy);
QualType FnType = BPT->getPointeeType();
@@ -1097,7 +1141,11 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
auto fields = builder.beginStruct();
// isa
- fields.add(CGM.getNSConcreteGlobalBlock());
+ fields.add((!CGM.getContext().getLangOpts().OpenCL)
+ ? CGM.getNSConcreteGlobalBlock()
+ : CGM.getNullPointer(CGM.VoidPtrPtrTy,
+ CGM.getContext().getPointerType(QualType(
+ CGM.getContext().VoidPtrTy))));
// __flags
BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE;
@@ -1114,16 +1162,19 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
// Descriptor
fields.add(buildBlockDescriptor(CGM, blockInfo));
- llvm::Constant *literal =
- fields.finishAndCreateGlobal("__block_literal_global",
- blockInfo.BlockAlign,
- /*constant*/ true);
+ unsigned AddrSpace = 0;
+ if (CGM.getContext().getLangOpts().OpenCL)
+ AddrSpace = CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
+
+ llvm::Constant *literal = fields.finishAndCreateGlobal(
+ "__block_literal_global", blockInfo.BlockAlign,
+ /*constant*/ true, llvm::GlobalVariable::InternalLinkage, AddrSpace);
// Return a constant of the appropriately-casted type.
llvm::Type *RequiredType =
CGM.getTypes().ConvertType(blockInfo.getBlockExpr()->getType());
llvm::Constant *Result =
- llvm::ConstantExpr::getBitCast(literal, RequiredType);
+ llvm::ConstantExpr::getPointerCast(literal, RequiredType);
CGM.setAddrOfGlobalBlock(blockInfo.BlockExpression, Result);
return Result;
}
@@ -1155,9 +1206,13 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D,
// Instead of messing around with LocalDeclMap, just set the value
// directly as BlockPointer.
- BlockPointer = Builder.CreateBitCast(arg,
- BlockInfo->StructureType->getPointerTo(),
- "block");
+ BlockPointer = Builder.CreatePointerCast(
+ arg,
+ BlockInfo->StructureType->getPointerTo(
+ getContext().getLangOpts().OpenCL
+ ? getContext().getTargetAddressSpace(LangAS::opencl_generic)
+ : 0),
+ "block");
}
Address CodeGenFunction::LoadBlockStruct() {
@@ -1196,11 +1251,21 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
// The first argument is the block pointer. Just take it as a void*
// and cast it later.
QualType selfTy = getContext().VoidPtrTy;
+
+ // For OpenCL passed block pointer can be private AS local variable or
+ // global AS program scope variable (for the case with and without captures).
+ // Generic AS is used therefore to be able to accommodate both private and
+ // generic AS in one implementation.
+ if (getLangOpts().OpenCL)
+ selfTy = getContext().getPointerType(getContext().getAddrSpaceQualType(
+ getContext().VoidTy, LangAS::opencl_generic));
+
IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
- ImplicitParamDecl selfDecl(getContext(), const_cast<BlockDecl*>(blockDecl),
- SourceLocation(), II, selfTy);
- args.push_back(&selfDecl);
+ ImplicitParamDecl SelfDecl(getContext(), const_cast<BlockDecl *>(blockDecl),
+ SourceLocation(), II, selfTy,
+ ImplicitParamDecl::ObjCSelf);
+ args.push_back(&SelfDecl);
// Now add the rest of the parameters.
args.append(blockDecl->param_begin(), blockDecl->param_end());
@@ -1323,23 +1388,102 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
return fn;
}
-/*
- notes.push_back(HelperInfo());
- HelperInfo &note = notes.back();
- note.index = capture.getIndex();
- note.RequiresCopying = (ci->hasCopyExpr() || BlockRequiresCopying(type));
- note.cxxbar_import = ci->getCopyExpr();
-
- if (ci->isByRef()) {
- note.flag = BLOCK_FIELD_IS_BYREF;
- if (type.isObjCGCWeak())
- note.flag |= BLOCK_FIELD_IS_WEAK;
- } else if (type->isBlockPointerType()) {
- note.flag = BLOCK_FIELD_IS_BLOCK;
- } else {
- note.flag = BLOCK_FIELD_IS_OBJECT;
- }
- */
+namespace {
+
+/// Represents a type of copy/destroy operation that should be performed for an
+/// entity that's captured by a block.
+enum class BlockCaptureEntityKind {
+ CXXRecord, // Copy or destroy
+ ARCWeak,
+ ARCStrong,
+ BlockObject, // Assign or release
+ None
+};
+
+/// Represents a captured entity that requires extra operations in order for
+/// this entity to be copied or destroyed correctly.
+struct BlockCaptureManagedEntity {
+ BlockCaptureEntityKind Kind;
+ BlockFieldFlags Flags;
+ const BlockDecl::Capture &CI;
+ const CGBlockInfo::Capture &Capture;
+
+ BlockCaptureManagedEntity(BlockCaptureEntityKind Type, BlockFieldFlags Flags,
+ const BlockDecl::Capture &CI,
+ const CGBlockInfo::Capture &Capture)
+ : Kind(Type), Flags(Flags), CI(CI), Capture(Capture) {}
+};
+
+} // end anonymous namespace
+
+static std::pair<BlockCaptureEntityKind, BlockFieldFlags>
+computeCopyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
+ const LangOptions &LangOpts) {
+ if (CI.getCopyExpr()) {
+ assert(!CI.isByRef());
+ // don't bother computing flags
+ return std::make_pair(BlockCaptureEntityKind::CXXRecord, BlockFieldFlags());
+ }
+ BlockFieldFlags Flags;
+ if (CI.isByRef()) {
+ Flags = BLOCK_FIELD_IS_BYREF;
+ if (T.isObjCGCWeak())
+ Flags |= BLOCK_FIELD_IS_WEAK;
+ return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
+ }
+ if (!T->isObjCRetainableType())
+ // For all other types, the memcpy is fine.
+ return std::make_pair(BlockCaptureEntityKind::None, Flags);
+
+ Flags = BLOCK_FIELD_IS_OBJECT;
+ bool isBlockPointer = T->isBlockPointerType();
+ if (isBlockPointer)
+ Flags = BLOCK_FIELD_IS_BLOCK;
+
+ // Special rules for ARC captures:
+ Qualifiers QS = T.getQualifiers();
+
+ // We need to register __weak direct captures with the runtime.
+ if (QS.getObjCLifetime() == Qualifiers::OCL_Weak)
+ return std::make_pair(BlockCaptureEntityKind::ARCWeak, Flags);
+
+ // We need to retain the copied value for __strong direct captures.
+ if (QS.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // If it's a block pointer, we have to copy the block and
+ // assign that to the destination pointer, so we might as
+ // well use _Block_object_assign. Otherwise we can avoid that.
+ return std::make_pair(!isBlockPointer ? BlockCaptureEntityKind::ARCStrong
+ : BlockCaptureEntityKind::BlockObject,
+ Flags);
+ }
+
+ // Non-ARC captures of retainable pointers are strong and
+ // therefore require a call to _Block_object_assign.
+ if (!QS.getObjCLifetime() && !LangOpts.ObjCAutoRefCount)
+ return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
+
+ // Otherwise the memcpy is fine.
+ return std::make_pair(BlockCaptureEntityKind::None, Flags);
+}
+
+/// Find the set of block captures that need to be explicitly copied or destroy.
+static void findBlockCapturedManagedEntities(
+ const CGBlockInfo &BlockInfo, const LangOptions &LangOpts,
+ SmallVectorImpl<BlockCaptureManagedEntity> &ManagedCaptures,
+ llvm::function_ref<std::pair<BlockCaptureEntityKind, BlockFieldFlags>(
+ const BlockDecl::Capture &, QualType, const LangOptions &)>
+ Predicate) {
+ for (const auto &CI : BlockInfo.getBlockDecl()->captures()) {
+ const VarDecl *Variable = CI.getVariable();
+ const CGBlockInfo::Capture &Capture = BlockInfo.getCapture(Variable);
+ if (Capture.isConstant())
+ continue;
+
+ auto Info = Predicate(CI, Variable->getType(), LangOpts);
+ if (Info.first != BlockCaptureEntityKind::None)
+ ManagedCaptures.emplace_back(Info.first, Info.second, CI, Capture);
+ }
+}
/// Generate the copy-helper function for a block closure object:
/// static void block_copy_helper(block_t *dst, block_t *src);
@@ -1354,12 +1498,12 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- ImplicitParamDecl dstDecl(getContext(), nullptr, SourceLocation(), nullptr,
- C.VoidPtrTy);
- args.push_back(&dstDecl);
- ImplicitParamDecl srcDecl(getContext(), nullptr, SourceLocation(), nullptr,
- C.VoidPtrTy);
- args.push_back(&srcDecl);
+ ImplicitParamDecl DstDecl(getContext(), C.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&DstDecl);
+ ImplicitParamDecl SrcDecl(getContext(), C.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
@@ -1391,86 +1535,36 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
auto AL = ApplyDebugLocation::CreateArtificial(*this);
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
- Address src = GetAddrOfLocalVar(&srcDecl);
+ Address src = GetAddrOfLocalVar(&SrcDecl);
src = Address(Builder.CreateLoad(src), blockInfo.BlockAlign);
src = Builder.CreateBitCast(src, structPtrTy, "block.source");
- Address dst = GetAddrOfLocalVar(&dstDecl);
+ Address dst = GetAddrOfLocalVar(&DstDecl);
dst = Address(Builder.CreateLoad(dst), blockInfo.BlockAlign);
dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest");
- const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
- for (const auto &CI : blockDecl->captures()) {
- const VarDecl *variable = CI.getVariable();
- QualType type = variable->getType();
-
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
- if (capture.isConstant()) continue;
-
- const Expr *copyExpr = CI.getCopyExpr();
- BlockFieldFlags flags;
-
- bool useARCWeakCopy = false;
- bool useARCStrongCopy = false;
-
- if (copyExpr) {
- assert(!CI.isByRef());
- // don't bother computing flags
+ SmallVector<BlockCaptureManagedEntity, 4> CopiedCaptures;
+ findBlockCapturedManagedEntities(blockInfo, getLangOpts(), CopiedCaptures,
+ computeCopyInfoForBlockCapture);
- } else if (CI.isByRef()) {
- flags = BLOCK_FIELD_IS_BYREF;
- if (type.isObjCGCWeak())
- flags |= BLOCK_FIELD_IS_WEAK;
-
- } else if (type->isObjCRetainableType()) {
- flags = BLOCK_FIELD_IS_OBJECT;
- bool isBlockPointer = type->isBlockPointerType();
- if (isBlockPointer)
- flags = BLOCK_FIELD_IS_BLOCK;
-
- // Special rules for ARC captures:
- Qualifiers qs = type.getQualifiers();
-
- // We need to register __weak direct captures with the runtime.
- if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) {
- useARCWeakCopy = true;
-
- // We need to retain the copied value for __strong direct captures.
- } else if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) {
- // If it's a block pointer, we have to copy the block and
- // assign that to the destination pointer, so we might as
- // well use _Block_object_assign. Otherwise we can avoid that.
- if (!isBlockPointer)
- useARCStrongCopy = true;
-
- // Non-ARC captures of retainable pointers are strong and
- // therefore require a call to _Block_object_assign.
- } else if (!qs.getObjCLifetime() && !getLangOpts().ObjCAutoRefCount) {
- // fall through
-
- // Otherwise the memcpy is fine.
- } else {
- continue;
- }
-
- // For all other types, the memcpy is fine.
- } else {
- continue;
- }
+ for (const auto &CopiedCapture : CopiedCaptures) {
+ const BlockDecl::Capture &CI = CopiedCapture.CI;
+ const CGBlockInfo::Capture &capture = CopiedCapture.Capture;
+ BlockFieldFlags flags = CopiedCapture.Flags;
unsigned index = capture.getIndex();
Address srcField = Builder.CreateStructGEP(src, index, capture.getOffset());
Address dstField = Builder.CreateStructGEP(dst, index, capture.getOffset());
// If there's an explicit copy expression, we do that.
- if (copyExpr) {
- EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr);
- } else if (useARCWeakCopy) {
+ if (CI.getCopyExpr()) {
+ assert(CopiedCapture.Kind == BlockCaptureEntityKind::CXXRecord);
+ EmitSynthesizedCXXCopyCtor(dstField, srcField, CI.getCopyExpr());
+ } else if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCWeak) {
EmitARCCopyWeak(dstField, srcField);
} else {
llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
- if (useARCStrongCopy) {
+ if (CopiedCapture.Kind == BlockCaptureEntityKind::ARCStrong) {
// At -O0, store null into the destination field (so that the
// storeStrong doesn't over-release) and then call storeStrong.
// This is a workaround to not having an initStrong call.
@@ -1491,6 +1585,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
cast<llvm::Instruction>(dstField.getPointer())->eraseFromParent();
}
} else {
+ assert(CopiedCapture.Kind == BlockCaptureEntityKind::BlockObject);
srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
llvm::Value *dstAddr =
Builder.CreateBitCast(dstField.getPointer(), VoidPtrTy);
@@ -1498,6 +1593,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
};
+ const VarDecl *variable = CI.getVariable();
bool copyCanThrow = false;
if (CI.isByRef() && variable->getType()->getAsCXXRecordDecl()) {
const Expr *copyExpr =
@@ -1521,6 +1617,52 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
}
+static std::pair<BlockCaptureEntityKind, BlockFieldFlags>
+computeDestroyInfoForBlockCapture(const BlockDecl::Capture &CI, QualType T,
+ const LangOptions &LangOpts) {
+ BlockFieldFlags Flags;
+ if (CI.isByRef()) {
+ Flags = BLOCK_FIELD_IS_BYREF;
+ if (T.isObjCGCWeak())
+ Flags |= BLOCK_FIELD_IS_WEAK;
+ return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
+ }
+
+ if (const CXXRecordDecl *Record = T->getAsCXXRecordDecl()) {
+ if (Record->hasTrivialDestructor())
+ return std::make_pair(BlockCaptureEntityKind::None, BlockFieldFlags());
+ return std::make_pair(BlockCaptureEntityKind::CXXRecord, BlockFieldFlags());
+ }
+
+ // Other types don't need to be destroy explicitly.
+ if (!T->isObjCRetainableType())
+ return std::make_pair(BlockCaptureEntityKind::None, Flags);
+
+ Flags = BLOCK_FIELD_IS_OBJECT;
+ if (T->isBlockPointerType())
+ Flags = BLOCK_FIELD_IS_BLOCK;
+
+ // Special rules for ARC captures.
+ Qualifiers QS = T.getQualifiers();
+
+ // Use objc_storeStrong for __strong direct captures; the
+ // dynamic tools really like it when we do this.
+ if (QS.getObjCLifetime() == Qualifiers::OCL_Strong)
+ return std::make_pair(BlockCaptureEntityKind::ARCStrong, Flags);
+
+ // Support __weak direct captures.
+ if (QS.getObjCLifetime() == Qualifiers::OCL_Weak)
+ return std::make_pair(BlockCaptureEntityKind::ARCWeak, Flags);
+
+ // Non-ARC captures are strong, and we need to use
+ // _Block_object_dispose.
+ if (!QS.hasObjCLifetime() && !LangOpts.ObjCAutoRefCount)
+ return std::make_pair(BlockCaptureEntityKind::BlockObject, Flags);
+
+ // Otherwise, we have nothing to do.
+ return std::make_pair(BlockCaptureEntityKind::None, Flags);
+}
+
/// Generate the destroy-helper function for a block closure object:
/// static void block_destroy_helper(block_t *theBlock);
///
@@ -1533,9 +1675,9 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- ImplicitParamDecl srcDecl(getContext(), nullptr, SourceLocation(), nullptr,
- C.VoidPtrTy);
- args.push_back(&srcDecl);
+ ImplicitParamDecl SrcDecl(getContext(), C.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
@@ -1566,83 +1708,43 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
- Address src = GetAddrOfLocalVar(&srcDecl);
+ Address src = GetAddrOfLocalVar(&SrcDecl);
src = Address(Builder.CreateLoad(src), blockInfo.BlockAlign);
src = Builder.CreateBitCast(src, structPtrTy, "block");
- const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
CodeGenFunction::RunCleanupsScope cleanups(*this);
- for (const auto &CI : blockDecl->captures()) {
- const VarDecl *variable = CI.getVariable();
- QualType type = variable->getType();
+ SmallVector<BlockCaptureManagedEntity, 4> DestroyedCaptures;
+ findBlockCapturedManagedEntities(blockInfo, getLangOpts(), DestroyedCaptures,
+ computeDestroyInfoForBlockCapture);
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
- if (capture.isConstant()) continue;
-
- BlockFieldFlags flags;
- const CXXDestructorDecl *dtor = nullptr;
-
- bool useARCWeakDestroy = false;
- bool useARCStrongDestroy = false;
-
- if (CI.isByRef()) {
- flags = BLOCK_FIELD_IS_BYREF;
- if (type.isObjCGCWeak())
- flags |= BLOCK_FIELD_IS_WEAK;
- } else if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
- if (record->hasTrivialDestructor())
- continue;
- dtor = record->getDestructor();
- } else if (type->isObjCRetainableType()) {
- flags = BLOCK_FIELD_IS_OBJECT;
- if (type->isBlockPointerType())
- flags = BLOCK_FIELD_IS_BLOCK;
-
- // Special rules for ARC captures.
- Qualifiers qs = type.getQualifiers();
-
- // Use objc_storeStrong for __strong direct captures; the
- // dynamic tools really like it when we do this.
- if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) {
- useARCStrongDestroy = true;
-
- // Support __weak direct captures.
- } else if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) {
- useARCWeakDestroy = true;
-
- // Non-ARC captures are strong, and we need to use _Block_object_dispose.
- } else if (!qs.hasObjCLifetime() && !getLangOpts().ObjCAutoRefCount) {
- // fall through
-
- // Otherwise, we have nothing to do.
- } else {
- continue;
- }
- } else {
- continue;
- }
+ for (const auto &DestroyedCapture : DestroyedCaptures) {
+ const BlockDecl::Capture &CI = DestroyedCapture.CI;
+ const CGBlockInfo::Capture &capture = DestroyedCapture.Capture;
+ BlockFieldFlags flags = DestroyedCapture.Flags;
Address srcField =
Builder.CreateStructGEP(src, capture.getIndex(), capture.getOffset());
- // If there's an explicit copy expression, we do that.
- if (dtor) {
- PushDestructorCleanup(dtor, srcField);
+ // If the captured record has a destructor then call it.
+ if (DestroyedCapture.Kind == BlockCaptureEntityKind::CXXRecord) {
+ const auto *Dtor =
+ CI.getVariable()->getType()->getAsCXXRecordDecl()->getDestructor();
+ PushDestructorCleanup(Dtor, srcField);
- // If this is a __weak capture, emit the release directly.
- } else if (useARCWeakDestroy) {
+ // If this is a __weak capture, emit the release directly.
+ } else if (DestroyedCapture.Kind == BlockCaptureEntityKind::ARCWeak) {
EmitARCDestroyWeak(srcField);
// Destroy strong objects with a call if requested.
- } else if (useARCStrongDestroy) {
+ } else if (DestroyedCapture.Kind == BlockCaptureEntityKind::ARCStrong) {
EmitARCDestroyStrong(srcField, ARCImpreciseLifetime);
// Otherwise we call _Block_object_dispose. It wouldn't be too
// hard to just emit this as a cleanup if we wanted to make sure
// that things were done in reverse.
} else {
+ assert(DestroyedCapture.Kind == BlockCaptureEntityKind::BlockObject);
llvm::Value *value = Builder.CreateLoad(srcField);
value = Builder.CreateBitCast(value, VoidPtrTy);
BuildBlockRelease(value, flags);
@@ -1815,13 +1917,13 @@ generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo,
QualType R = Context.VoidTy;
FunctionArgList args;
- ImplicitParamDecl dst(CGF.getContext(), nullptr, SourceLocation(), nullptr,
- Context.VoidPtrTy);
- args.push_back(&dst);
+ ImplicitParamDecl Dst(CGF.getContext(), Context.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&Dst);
- ImplicitParamDecl src(CGF.getContext(), nullptr, SourceLocation(), nullptr,
- Context.VoidPtrTy);
- args.push_back(&src);
+ ImplicitParamDecl Src(CGF.getContext(), Context.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&Src);
const CGFunctionInfo &FI =
CGF.CGM.getTypes().arrangeBuiltinFunctionDeclaration(R, args);
@@ -1852,7 +1954,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo,
llvm::Type *byrefPtrType = byrefInfo.Type->getPointerTo(0);
// dst->x
- Address destField = CGF.GetAddrOfLocalVar(&dst);
+ Address destField = CGF.GetAddrOfLocalVar(&Dst);
destField = Address(CGF.Builder.CreateLoad(destField),
byrefInfo.ByrefAlignment);
destField = CGF.Builder.CreateBitCast(destField, byrefPtrType);
@@ -1860,7 +1962,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF, const BlockByrefInfo &byrefInfo,
"dest-object");
// src->x
- Address srcField = CGF.GetAddrOfLocalVar(&src);
+ Address srcField = CGF.GetAddrOfLocalVar(&Src);
srcField = Address(CGF.Builder.CreateLoad(srcField),
byrefInfo.ByrefAlignment);
srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType);
@@ -1892,9 +1994,9 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
QualType R = Context.VoidTy;
FunctionArgList args;
- ImplicitParamDecl src(CGF.getContext(), nullptr, SourceLocation(), nullptr,
- Context.VoidPtrTy);
- args.push_back(&src);
+ ImplicitParamDecl Src(CGF.getContext(), Context.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&Src);
const CGFunctionInfo &FI =
CGF.CGM.getTypes().arrangeBuiltinFunctionDeclaration(R, args);
@@ -1923,7 +2025,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
CGF.StartFunction(FD, R, Fn, FI, args);
if (generator.needsDispose()) {
- Address addr = CGF.GetAddrOfLocalVar(&src);
+ Address addr = CGF.GetAddrOfLocalVar(&Src);
addr = Address(CGF.Builder.CreateLoad(addr), byrefInfo.ByrefAlignment);
auto byrefPtrType = byrefInfo.Type->getPointerTo(0);
addr = CGF.Builder.CreateBitCast(addr, byrefPtrType);
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp
index b3d02f1..f3527b0 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp
@@ -420,10 +420,11 @@ getDefaultBuiltinObjectSizeResult(unsigned Type, llvm::IntegerType *ResType) {
llvm::Value *
CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType) {
+ llvm::IntegerType *ResType,
+ llvm::Value *EmittedE) {
uint64_t ObjectSize;
if (!E->tryEvaluateObjectSize(ObjectSize, getContext(), Type))
- return emitBuiltinObjectSize(E, Type, ResType);
+ return emitBuiltinObjectSize(E, Type, ResType, EmittedE);
return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
}
@@ -432,9 +433,14 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
/// - A llvm::Argument (if E is a param with the pass_object_size attribute on
/// it)
/// - A call to the @llvm.objectsize intrinsic
+///
+/// EmittedE is the result of emitting `E` as a scalar expr. If it's non-null
+/// and we wouldn't otherwise try to reference a pass_object_size parameter,
+/// we'll call @llvm.objectsize on EmittedE, rather than emitting E.
llvm::Value *
CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType) {
+ llvm::IntegerType *ResType,
+ llvm::Value *EmittedE) {
// We need to reference an argument if the pointer is a parameter with the
// pass_object_size attribute.
if (auto *D = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
@@ -457,16 +463,20 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
// LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't
// evaluate E for side-effects. In either case, we shouldn't lower to
// @llvm.objectsize.
- if (Type == 3 || E->HasSideEffects(getContext()))
+ if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext())))
return getDefaultBuiltinObjectSizeResult(Type, ResType);
- // LLVM only supports 0 and 2, make sure that we pass along that
- // as a boolean.
- auto *CI = ConstantInt::get(Builder.getInt1Ty(), (Type & 2) >> 1);
- // FIXME: Get right address space.
- llvm::Type *Tys[] = {ResType, Builder.getInt8PtrTy(0)};
- Value *F = CGM.getIntrinsic(Intrinsic::objectsize, Tys);
- return Builder.CreateCall(F, {EmitScalarExpr(E), CI});
+ Value *Ptr = EmittedE ? EmittedE : EmitScalarExpr(E);
+ assert(Ptr->getType()->isPointerTy() &&
+ "Non-pointer passed to __builtin_object_size?");
+
+ Value *F = CGM.getIntrinsic(Intrinsic::objectsize, {ResType, Ptr->getType()});
+
+ // LLVM only supports 0 and 2, make sure that we pass along that as a boolean.
+ Value *Min = Builder.getInt1((Type & 2) != 0);
+ // For GCC compatability, __builtin_object_size treat NULL as unknown size.
+ Value *NullIsUnknown = Builder.getTrue();
+ return Builder.CreateCall(F, {Ptr, Min, NullIsUnknown});
}
// Many of MSVC builtins are on both x64 and ARM; to avoid repeating code, we
@@ -482,10 +492,12 @@ enum class CodeGenFunction::MSVCIntrin {
_InterlockedIncrement,
_InterlockedOr,
_InterlockedXor,
+ _interlockedbittestandset,
+ __fastfail,
};
Value *CodeGenFunction::EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID,
- const CallExpr *E) {
+ const CallExpr *E) {
switch (BuiltinID) {
case MSVCIntrin::_BitScanForward:
case MSVCIntrin::_BitScanReverse: {
@@ -548,6 +560,22 @@ Value *CodeGenFunction::EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID,
case MSVCIntrin::_InterlockedXor:
return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xor, E);
+ case MSVCIntrin::_interlockedbittestandset: {
+ llvm::Value *Addr = EmitScalarExpr(E->getArg(0));
+ llvm::Value *Bit = EmitScalarExpr(E->getArg(1));
+ AtomicRMWInst *RMWI = Builder.CreateAtomicRMW(
+ AtomicRMWInst::Or, Addr,
+ Builder.CreateShl(ConstantInt::get(Bit->getType(), 1), Bit),
+ llvm::AtomicOrdering::SequentiallyConsistent);
+ // Shift the relevant bit to the least significant position, truncate to
+ // the result type, and test the low bit.
+ llvm::Value *Shifted = Builder.CreateLShr(RMWI, Bit);
+ llvm::Value *Truncated =
+ Builder.CreateTrunc(Shifted, ConvertType(E->getType()));
+ return Builder.CreateAnd(Truncated,
+ ConstantInt::get(Truncated->getType(), 1));
+ }
+
case MSVCIntrin::_InterlockedDecrement: {
llvm::Type *IntTy = ConvertType(E->getType());
AtomicRMWInst *RMWI = Builder.CreateAtomicRMW(
@@ -566,6 +594,37 @@ Value *CodeGenFunction::EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID,
llvm::AtomicOrdering::SequentiallyConsistent);
return Builder.CreateAdd(RMWI, ConstantInt::get(IntTy, 1));
}
+
+ case MSVCIntrin::__fastfail: {
+ // Request immediate process termination from the kernel. The instruction
+ // sequences to do this are documented on MSDN:
+ // https://msdn.microsoft.com/en-us/library/dn774154.aspx
+ llvm::Triple::ArchType ISA = getTarget().getTriple().getArch();
+ StringRef Asm, Constraints;
+ switch (ISA) {
+ default:
+ ErrorUnsupported(E, "__fastfail call for this architecture");
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ Asm = "int $$0x29";
+ Constraints = "{cx}";
+ break;
+ case llvm::Triple::thumb:
+ Asm = "udf #251";
+ Constraints = "{r0}";
+ break;
+ }
+ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, {Int32Ty}, false);
+ llvm::InlineAsm *IA =
+ llvm::InlineAsm::get(FTy, Asm, Constraints, /*SideEffects=*/true);
+ llvm::AttributeList NoReturnAttr = llvm::AttributeList::get(
+ getLLVMContext(), llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoReturn);
+ CallSite CS = Builder.CreateCall(IA, EmitScalarExpr(E->getArg(0)));
+ CS.setAttributes(NoReturnAttr);
+ return CS.getInstruction();
+ }
}
llvm_unreachable("Incorrect MSVC intrinsic!");
}
@@ -932,7 +991,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// We pass this builtin onto the optimizer so that it can figure out the
// object size in more complex cases.
- return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType));
+ return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
+ /*EmittedE=*/nullptr));
}
case Builtin::BI__builtin_prefetch: {
Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
@@ -1750,12 +1810,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__atomic_signal_fence:
case Builtin::BI__c11_atomic_thread_fence:
case Builtin::BI__c11_atomic_signal_fence: {
- llvm::SynchronizationScope Scope;
+ llvm::SyncScope::ID SSID;
if (BuiltinID == Builtin::BI__atomic_signal_fence ||
BuiltinID == Builtin::BI__c11_atomic_signal_fence)
- Scope = llvm::SingleThread;
+ SSID = llvm::SyncScope::SingleThread;
else
- Scope = llvm::CrossThread;
+ SSID = llvm::SyncScope::System;
Value *Order = EmitScalarExpr(E->getArg(0));
if (isa<llvm::ConstantInt>(Order)) {
int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
@@ -1765,17 +1825,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
break;
case 1: // memory_order_consume
case 2: // memory_order_acquire
- Builder.CreateFence(llvm::AtomicOrdering::Acquire, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID);
break;
case 3: // memory_order_release
- Builder.CreateFence(llvm::AtomicOrdering::Release, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::Release, SSID);
break;
case 4: // memory_order_acq_rel
- Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID);
break;
case 5: // memory_order_seq_cst
- Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
- Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID);
break;
}
return RValue::get(nullptr);
@@ -1792,23 +1851,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::SwitchInst *SI = Builder.CreateSwitch(Order, ContBB);
Builder.SetInsertPoint(AcquireBB);
- Builder.CreateFence(llvm::AtomicOrdering::Acquire, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32(1), AcquireBB);
SI->addCase(Builder.getInt32(2), AcquireBB);
Builder.SetInsertPoint(ReleaseBB);
- Builder.CreateFence(llvm::AtomicOrdering::Release, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::Release, SSID);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32(3), ReleaseBB);
Builder.SetInsertPoint(AcqRelBB);
- Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32(4), AcqRelBB);
Builder.SetInsertPoint(SeqCstBB);
- Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, Scope);
+ Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID);
Builder.CreateBr(ContBB);
SI->addCase(Builder.getInt32(5), SeqCstBB);
@@ -2195,16 +2254,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI_InterlockedXor16:
case Builtin::BI_InterlockedXor:
return RValue::get(EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor, E));
- case Builtin::BI__readfsdword: {
- llvm::Type *IntTy = ConvertType(E->getType());
- Value *IntToPtr =
- Builder.CreateIntToPtr(EmitScalarExpr(E->getArg(0)),
- llvm::PointerType::get(IntTy, 257));
- LoadInst *Load = Builder.CreateAlignedLoad(
- IntTy, IntToPtr, getContext().getTypeAlignInChars(E->getType()));
- Load->setVolatile(true);
- return RValue::get(Load);
- }
+ case Builtin::BI_interlockedbittestandset:
+ return RValue::get(
+ EmitMSVCBuiltinExpr(MSVCIntrin::_interlockedbittestandset, E));
case Builtin::BI__exception_code:
case Builtin::BI_exception_code:
@@ -2218,9 +2270,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI_setjmpex: {
if (getTarget().getTriple().isOSMSVCRT()) {
llvm::Type *ArgTypes[] = {Int8PtrTy, Int8PtrTy};
- llvm::AttributeSet ReturnsTwiceAttr =
- AttributeSet::get(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::ReturnsTwice);
+ llvm::AttributeList ReturnsTwiceAttr = llvm::AttributeList::get(
+ getLLVMContext(), llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::ReturnsTwice);
llvm::Constant *SetJmpEx = CGM.CreateRuntimeFunction(
llvm::FunctionType::get(IntTy, ArgTypes, /*isVarArg=*/false),
"_setjmpex", ReturnsTwiceAttr, /*Local=*/true);
@@ -2238,9 +2290,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI_setjmp: {
if (getTarget().getTriple().isOSMSVCRT()) {
- llvm::AttributeSet ReturnsTwiceAttr =
- AttributeSet::get(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::ReturnsTwice);
+ llvm::AttributeList ReturnsTwiceAttr = llvm::AttributeList::get(
+ getLLVMContext(), llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::ReturnsTwice);
llvm::Value *Buf = Builder.CreateBitOrPointerCast(
EmitScalarExpr(E->getArg(0)), Int8PtrTy);
llvm::CallSite CS;
@@ -2276,6 +2328,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
break;
}
+ case Builtin::BI__fastfail:
+ return RValue::get(EmitMSVCBuiltinExpr(MSVCIntrin::__fastfail, E));
+
case Builtin::BI__builtin_coro_size: {
auto & Context = getContext();
auto SizeTy = Context.getSizeType();
@@ -2492,25 +2547,36 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned NumArgs = E->getNumArgs();
llvm::Type *QueueTy = ConvertType(getContext().OCLQueueTy);
- llvm::Type *RangeTy = ConvertType(getContext().OCLNDRangeTy);
+ llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
+ getContext().getTargetAddressSpace(LangAS::opencl_generic));
llvm::Value *Queue = EmitScalarExpr(E->getArg(0));
llvm::Value *Flags = EmitScalarExpr(E->getArg(1));
- llvm::Value *Range = EmitScalarExpr(E->getArg(2));
+ LValue NDRangeL = EmitAggExprToLValue(E->getArg(2));
+ llvm::Value *Range = NDRangeL.getAddress().getPointer();
+ llvm::Type *RangeTy = NDRangeL.getAddress().getType();
if (NumArgs == 4) {
// The most basic form of the call with parameters:
// queue_t, kernel_enqueue_flags_t, ndrange_t, block(void)
Name = "__enqueue_kernel_basic";
- llvm::Type *ArgTys[] = {QueueTy, Int32Ty, RangeTy, Int8PtrTy};
+ llvm::Type *ArgTys[] = {QueueTy, Int32Ty, RangeTy, GenericVoidPtrTy};
llvm::FunctionType *FTy = llvm::FunctionType::get(
Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys, 4), false);
- llvm::Value *Block =
- Builder.CreateBitCast(EmitScalarExpr(E->getArg(3)), Int8PtrTy);
+ llvm::Value *Block = Builder.CreatePointerCast(
+ EmitScalarExpr(E->getArg(3)), GenericVoidPtrTy);
- return RValue::get(Builder.CreateCall(
- CGM.CreateRuntimeFunction(FTy, Name), {Queue, Flags, Range, Block}));
+ AttrBuilder B;
+ B.addAttribute(Attribute::ByVal);
+ llvm::AttributeList ByValAttrSet =
+ llvm::AttributeList::get(CGM.getModule().getContext(), 3U, B);
+
+ auto RTCall =
+ Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name, ByValAttrSet),
+ {Queue, Flags, Range, Block});
+ RTCall->setAttributes(ByValAttrSet);
+ return RValue::get(RTCall);
}
assert(NumArgs >= 5 && "Invalid enqueue_kernel signature");
@@ -2518,14 +2584,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
if (E->getArg(3)->getType()->isBlockPointerType()) {
// No events passed, but has variadic arguments.
Name = "__enqueue_kernel_vaargs";
- llvm::Value *Block =
- Builder.CreateBitCast(EmitScalarExpr(E->getArg(3)), Int8PtrTy);
+ llvm::Value *Block = Builder.CreatePointerCast(
+ EmitScalarExpr(E->getArg(3)), GenericVoidPtrTy);
// Create a vector of the arguments, as well as a constant value to
// express to the runtime the number of variadic arguments.
std::vector<llvm::Value *> Args = {Queue, Flags, Range, Block,
ConstantInt::get(IntTy, NumArgs - 4)};
- std::vector<llvm::Type *> ArgTys = {QueueTy, IntTy, RangeTy, Int8PtrTy,
- IntTy};
+ std::vector<llvm::Type *> ArgTys = {QueueTy, IntTy, RangeTy,
+ GenericVoidPtrTy, IntTy};
// Each of the following arguments specifies the size of the corresponding
// argument passed to the enqueued block.
@@ -2555,12 +2621,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// Convert to generic address space.
EventList = Builder.CreatePointerCast(EventList, EventPtrTy);
ClkEvent = Builder.CreatePointerCast(ClkEvent, EventPtrTy);
- llvm::Value *Block =
- Builder.CreateBitCast(EmitScalarExpr(E->getArg(6)), Int8PtrTy);
+ llvm::Value *Block = Builder.CreatePointerCast(
+ EmitScalarExpr(E->getArg(6)), GenericVoidPtrTy);
- std::vector<llvm::Type *> ArgTys = {QueueTy, Int32Ty, RangeTy,
- Int32Ty, EventPtrTy, EventPtrTy,
- Int8PtrTy};
+ std::vector<llvm::Type *> ArgTys = {
+ QueueTy, Int32Ty, RangeTy, Int32Ty,
+ EventPtrTy, EventPtrTy, GenericVoidPtrTy};
std::vector<llvm::Value *> Args = {Queue, Flags, Range, NumEvents,
EventList, ClkEvent, Block};
@@ -2592,30 +2658,35 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name),
llvm::ArrayRef<llvm::Value *>(Args)));
}
+ LLVM_FALLTHROUGH;
}
// OpenCL v2.0 s6.13.17.6 - Kernel query functions need bitcast of block
// parameter.
case Builtin::BIget_kernel_work_group_size: {
+ llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
+ getContext().getTargetAddressSpace(LangAS::opencl_generic));
Value *Arg = EmitScalarExpr(E->getArg(0));
- Arg = Builder.CreateBitCast(Arg, Int8PtrTy);
- return RValue::get(
- Builder.CreateCall(CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, Int8PtrTy, false),
- "__get_kernel_work_group_size_impl"),
- Arg));
+ Arg = Builder.CreatePointerCast(Arg, GenericVoidPtrTy);
+ return RValue::get(Builder.CreateCall(
+ CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(IntTy, GenericVoidPtrTy, false),
+ "__get_kernel_work_group_size_impl"),
+ Arg));
}
case Builtin::BIget_kernel_preferred_work_group_size_multiple: {
+ llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy(
+ getContext().getTargetAddressSpace(LangAS::opencl_generic));
Value *Arg = EmitScalarExpr(E->getArg(0));
- Arg = Builder.CreateBitCast(Arg, Int8PtrTy);
+ Arg = Builder.CreatePointerCast(Arg, GenericVoidPtrTy);
return RValue::get(Builder.CreateCall(
CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(IntTy, Int8PtrTy, false),
+ llvm::FunctionType::get(IntTy, GenericVoidPtrTy, false),
"__get_kernel_preferred_work_group_multiple_impl"),
Arg));
}
case Builtin::BIprintf:
- if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice)
- return EmitCUDADevicePrintfCallExpr(E, ReturnValue);
+ if (getTarget().getTriple().isNVPTX())
+ return EmitNVPTXDevicePrintfCallExpr(E, ReturnValue);
break;
case Builtin::BI__builtin_canonicalize:
case Builtin::BI__builtin_canonicalizef:
@@ -2680,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.
@@ -2698,6 +2769,59 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(ConstantInt::get(ConvertType(E->getType()),
Layout.size().getQuantity()));
}
+
+ case Builtin::BI__xray_customevent: {
+ if (!ShouldXRayInstrumentFunction())
+ return RValue::getIgnored();
+ if (const auto *XRayAttr = CurFuncDecl->getAttr<XRayInstrumentAttr>()) {
+ if (XRayAttr->neverXRayInstrument())
+ return RValue::getIgnored();
+ }
+ Function *F = CGM.getIntrinsic(Intrinsic::xray_customevent);
+ auto FTy = F->getFunctionType();
+ auto Arg0 = E->getArg(0);
+ auto Arg0Val = EmitScalarExpr(Arg0);
+ auto Arg0Ty = Arg0->getType();
+ auto PTy0 = FTy->getParamType(0);
+ if (PTy0 != Arg0Val->getType()) {
+ if (Arg0Ty->isArrayType())
+ Arg0Val = EmitArrayToPointerDecay(Arg0).getPointer();
+ else
+ Arg0Val = Builder.CreatePointerCast(Arg0Val, PTy0);
+ }
+ auto Arg1 = EmitScalarExpr(E->getArg(1));
+ auto PTy1 = FTy->getParamType(1);
+ if (PTy1 != Arg1->getType())
+ Arg1 = Builder.CreateTruncOrBitCast(Arg1, PTy1);
+ return RValue::get(Builder.CreateCall(F, {Arg0Val, Arg1}));
+ }
+
+ case Builtin::BI__builtin_ms_va_start:
+ case Builtin::BI__builtin_ms_va_end:
+ return RValue::get(
+ EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(),
+ BuiltinID == Builtin::BI__builtin_ms_va_start));
+
+ case Builtin::BI__builtin_ms_va_copy: {
+ // Lower this manually. We can't reliably determine whether or not any
+ // given va_copy() is for a Win64 va_list from the calling convention
+ // alone, because it's legal to do this from a System V ABI function.
+ // With opaque pointer types, we won't have enough information in LLVM
+ // IR to determine this from the argument types, either. Best to do it
+ // now, while we have enough information.
+ Address DestAddr = EmitMSVAListRef(E->getArg(0));
+ Address SrcAddr = EmitMSVAListRef(E->getArg(1));
+
+ llvm::Type *BPP = Int8PtrPtrTy;
+
+ DestAddr = Address(Builder.CreateBitCast(DestAddr.getPointer(), BPP, "cp"),
+ DestAddr.getAlignment());
+ SrcAddr = Address(Builder.CreateBitCast(SrcAddr.getPointer(), BPP, "ap"),
+ SrcAddr.getAlignment());
+
+ Value *ArgPtr = Builder.CreateLoad(SrcAddr, "ap.val");
+ return RValue::get(Builder.CreateStore(ArgPtr, DestAddr));
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
@@ -3716,6 +3840,7 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
case NEON::BI__builtin_neon_vcalt_v:
case NEON::BI__builtin_neon_vcaltq_v:
std::swap(Ops[0], Ops[1]);
+ LLVM_FALLTHROUGH;
case NEON::BI__builtin_neon_vcage_v:
case NEON::BI__builtin_neon_vcageq_v:
case NEON::BI__builtin_neon_vcagt_v:
@@ -4474,7 +4599,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex
? Intrinsic::arm_stlexd
: Intrinsic::arm_strexd);
- llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, nullptr);
+ llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty);
Address Tmp = CreateMemTemp(E->getArg(0)->getType());
Value *Val = EmitScalarExpr(E->getArg(0));
@@ -4959,6 +5084,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vsri_n_v:
case NEON::BI__builtin_neon_vsriq_n_v:
rightShift = true;
+ LLVM_FALLTHROUGH;
case NEON::BI__builtin_neon_vsli_n_v:
case NEON::BI__builtin_neon_vsliq_n_v:
Ops[2] = EmitNeonShiftVector(Ops[2], Ty, rightShift);
@@ -5304,7 +5430,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex
? Intrinsic::aarch64_stlxp
: Intrinsic::aarch64_stxp);
- llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty, nullptr);
+ llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty);
Address Tmp = CreateMemTemp(E->getArg(0)->getType());
EmitAnyExprToMem(E->getArg(0), Tmp, Qualifiers(), /*init*/ true);
@@ -7115,33 +7241,15 @@ static Value *EmitX86MinMax(CodeGenFunction &CGF, ICmpInst::Predicate Pred,
return EmitX86Select(CGF, Ops[3], Res, Ops[2]);
}
+static Value *EmitX86SExtMask(CodeGenFunction &CGF, Value *Op,
+ llvm::Type *DstTy) {
+ unsigned NumberOfElements = DstTy->getVectorNumElements();
+ Value *Mask = getMaskVecValue(CGF, Op, NumberOfElements);
+ return CGF.Builder.CreateSExt(Mask, DstTy, "vpmovm2");
+}
+
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
- if (BuiltinID == X86::BI__builtin_ms_va_start ||
- BuiltinID == X86::BI__builtin_ms_va_end)
- return EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(),
- BuiltinID == X86::BI__builtin_ms_va_start);
- if (BuiltinID == X86::BI__builtin_ms_va_copy) {
- // Lower this manually. We can't reliably determine whether or not any
- // given va_copy() is for a Win64 va_list from the calling convention
- // alone, because it's legal to do this from a System V ABI function.
- // With opaque pointer types, we won't have enough information in LLVM
- // IR to determine this from the argument types, either. Best to do it
- // now, while we have enough information.
- Address DestAddr = EmitMSVAListRef(E->getArg(0));
- Address SrcAddr = EmitMSVAListRef(E->getArg(1));
-
- llvm::Type *BPP = Int8PtrPtrTy;
-
- DestAddr = Address(Builder.CreateBitCast(DestAddr.getPointer(), BPP, "cp"),
- DestAddr.getAlignment());
- SrcAddr = Address(Builder.CreateBitCast(SrcAddr.getPointer(), BPP, "ap"),
- SrcAddr.getAlignment());
-
- Value *ArgPtr = Builder.CreateLoad(SrcAddr, "ap.val");
- return Builder.CreateStore(ArgPtr, DestAddr);
- }
-
SmallVector<Value*, 4> Ops;
// Find out if any arguments are required to be integer constant expressions.
@@ -7228,39 +7336,44 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
AVX512PF,
AVX512VBMI,
AVX512IFMA,
+ AVX5124VNNIW, // TODO implement this fully
+ AVX5124FMAPS, // TODO implement this fully
+ AVX512VPOPCNTDQ,
MAX
};
- X86Features Feature = StringSwitch<X86Features>(FeatureStr)
- .Case("cmov", X86Features::CMOV)
- .Case("mmx", X86Features::MMX)
- .Case("popcnt", X86Features::POPCNT)
- .Case("sse", X86Features::SSE)
- .Case("sse2", X86Features::SSE2)
- .Case("sse3", X86Features::SSE3)
- .Case("ssse3", X86Features::SSSE3)
- .Case("sse4.1", X86Features::SSE4_1)
- .Case("sse4.2", X86Features::SSE4_2)
- .Case("avx", X86Features::AVX)
- .Case("avx2", X86Features::AVX2)
- .Case("sse4a", X86Features::SSE4_A)
- .Case("fma4", X86Features::FMA4)
- .Case("xop", X86Features::XOP)
- .Case("fma", X86Features::FMA)
- .Case("avx512f", X86Features::AVX512F)
- .Case("bmi", X86Features::BMI)
- .Case("bmi2", X86Features::BMI2)
- .Case("aes", X86Features::AES)
- .Case("pclmul", X86Features::PCLMUL)
- .Case("avx512vl", X86Features::AVX512VL)
- .Case("avx512bw", X86Features::AVX512BW)
- .Case("avx512dq", X86Features::AVX512DQ)
- .Case("avx512cd", X86Features::AVX512CD)
- .Case("avx512er", X86Features::AVX512ER)
- .Case("avx512pf", X86Features::AVX512PF)
- .Case("avx512vbmi", X86Features::AVX512VBMI)
- .Case("avx512ifma", X86Features::AVX512IFMA)
- .Default(X86Features::MAX);
+ X86Features Feature =
+ StringSwitch<X86Features>(FeatureStr)
+ .Case("cmov", X86Features::CMOV)
+ .Case("mmx", X86Features::MMX)
+ .Case("popcnt", X86Features::POPCNT)
+ .Case("sse", X86Features::SSE)
+ .Case("sse2", X86Features::SSE2)
+ .Case("sse3", X86Features::SSE3)
+ .Case("ssse3", X86Features::SSSE3)
+ .Case("sse4.1", X86Features::SSE4_1)
+ .Case("sse4.2", X86Features::SSE4_2)
+ .Case("avx", X86Features::AVX)
+ .Case("avx2", X86Features::AVX2)
+ .Case("sse4a", X86Features::SSE4_A)
+ .Case("fma4", X86Features::FMA4)
+ .Case("xop", X86Features::XOP)
+ .Case("fma", X86Features::FMA)
+ .Case("avx512f", X86Features::AVX512F)
+ .Case("bmi", X86Features::BMI)
+ .Case("bmi2", X86Features::BMI2)
+ .Case("aes", X86Features::AES)
+ .Case("pclmul", X86Features::PCLMUL)
+ .Case("avx512vl", X86Features::AVX512VL)
+ .Case("avx512bw", X86Features::AVX512BW)
+ .Case("avx512dq", X86Features::AVX512DQ)
+ .Case("avx512cd", X86Features::AVX512CD)
+ .Case("avx512er", X86Features::AVX512ER)
+ .Case("avx512pf", X86Features::AVX512PF)
+ .Case("avx512vbmi", X86Features::AVX512VBMI)
+ .Case("avx512ifma", X86Features::AVX512IFMA)
+ .Case("avx512vpopcntdq", X86Features::AVX512VPOPCNTDQ)
+ .Default(X86Features::MAX);
assert(Feature != X86Features::MAX && "Invalid feature!");
// Matching the struct layout from the compiler-rt/libgcc structure that is
@@ -7269,8 +7382,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// unsigned int __cpu_type;
// unsigned int __cpu_subtype;
// unsigned int __cpu_features[1];
- llvm::Type *STy = llvm::StructType::get(
- Int32Ty, Int32Ty, Int32Ty, llvm::ArrayType::get(Int32Ty, 1), nullptr);
+ llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty,
+ llvm::ArrayType::get(Int32Ty, 1));
// Grab the global __cpu_model.
llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model");
@@ -7321,7 +7434,12 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_undef128:
case X86::BI__builtin_ia32_undef256:
case X86::BI__builtin_ia32_undef512:
- return UndefValue::get(ConvertType(E->getType()));
+ // The x86 definition of "undef" is not the same as the LLVM definition
+ // (PR32176). We leave optimizing away an unnecessary zero constant to the
+ // IR optimizer and backend.
+ // TODO: If we had a "freeze" IR instruction to generate a fixed undef
+ // value, we should use that here instead of a zero.
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
case X86::BI__builtin_ia32_vec_init_v8qi:
case X86::BI__builtin_ia32_vec_init_v4hi:
case X86::BI__builtin_ia32_vec_init_v2si:
@@ -7408,6 +7526,26 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_storesd128_mask: {
return EmitX86MaskedStore(*this, Ops, 16);
}
+ case X86::BI__builtin_ia32_vpopcntd_512:
+ case X86::BI__builtin_ia32_vpopcntq_512: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ResultType);
+ return Builder.CreateCall(F, Ops);
+ }
+ case X86::BI__builtin_ia32_cvtmask2b128:
+ case X86::BI__builtin_ia32_cvtmask2b256:
+ case X86::BI__builtin_ia32_cvtmask2b512:
+ case X86::BI__builtin_ia32_cvtmask2w128:
+ case X86::BI__builtin_ia32_cvtmask2w256:
+ case X86::BI__builtin_ia32_cvtmask2w512:
+ case X86::BI__builtin_ia32_cvtmask2d128:
+ case X86::BI__builtin_ia32_cvtmask2d256:
+ case X86::BI__builtin_ia32_cvtmask2d512:
+ case X86::BI__builtin_ia32_cvtmask2q128:
+ case X86::BI__builtin_ia32_cvtmask2q256:
+ case X86::BI__builtin_ia32_cvtmask2q512:
+ return EmitX86SExtMask(*this, Ops[0], ConvertType(E->getType()));
+
case X86::BI__builtin_ia32_movdqa32store128_mask:
case X86::BI__builtin_ia32_movdqa64store128_mask:
case X86::BI__builtin_ia32_storeaps128_mask:
@@ -7788,6 +7926,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
// We can't handle 8-31 immediates with native IR, use the intrinsic.
+ // Except for predicates that create constants.
Intrinsic::ID ID;
switch (BuiltinID) {
default: llvm_unreachable("Unsupported intrinsic!");
@@ -7795,12 +7934,32 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
ID = Intrinsic::x86_sse_cmp_ps;
break;
case X86::BI__builtin_ia32_cmpps256:
+ // _CMP_TRUE_UQ, _CMP_TRUE_US produce -1,-1... vector
+ // on any input and _CMP_FALSE_OQ, _CMP_FALSE_OS produce 0, 0...
+ if (CC == 0xf || CC == 0xb || CC == 0x1b || CC == 0x1f) {
+ Value *Constant = (CC == 0xf || CC == 0x1f) ?
+ llvm::Constant::getAllOnesValue(Builder.getInt32Ty()) :
+ llvm::Constant::getNullValue(Builder.getInt32Ty());
+ Value *Vec = Builder.CreateVectorSplat(
+ Ops[0]->getType()->getVectorNumElements(), Constant);
+ return Builder.CreateBitCast(Vec, Ops[0]->getType());
+ }
ID = Intrinsic::x86_avx_cmp_ps_256;
break;
case X86::BI__builtin_ia32_cmppd:
ID = Intrinsic::x86_sse2_cmp_pd;
break;
case X86::BI__builtin_ia32_cmppd256:
+ // _CMP_TRUE_UQ, _CMP_TRUE_US produce -1,-1... vector
+ // on any input and _CMP_FALSE_OQ, _CMP_FALSE_OS produce 0, 0...
+ if (CC == 0xf || CC == 0xb || CC == 0x1b || CC == 0x1f) {
+ Value *Constant = (CC == 0xf || CC == 0x1f) ?
+ llvm::Constant::getAllOnesValue(Builder.getInt64Ty()) :
+ llvm::Constant::getNullValue(Builder.getInt64Ty());
+ Value *Vec = Builder.CreateVectorSplat(
+ Ops[0]->getType()->getVectorNumElements(), Constant);
+ return Builder.CreateBitCast(Vec, Ops[0]->getType());
+ }
ID = Intrinsic::x86_avx_cmp_pd_256;
break;
}
@@ -7881,13 +8040,13 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__faststorefence: {
return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::CrossThread);
+ llvm::SyncScope::System);
}
case X86::BI_ReadWriteBarrier:
case X86::BI_ReadBarrier:
case X86::BI_WriteBarrier: {
return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::SingleThread);
+ llvm::SyncScope::SingleThread);
}
case X86::BI_BitScanForward:
case X86::BI_BitScanForward64:
@@ -7922,6 +8081,45 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// instruction, but it will create a memset that won't be optimized away.
return Builder.CreateMemSet(Ops[0], Ops[1], Ops[2], 1, true);
}
+ case X86::BI__ud2:
+ // llvm.trap makes a ud2a instruction on x86.
+ return EmitTrapCall(Intrinsic::trap);
+ case X86::BI__int2c: {
+ // This syscall signals a driver assertion failure in x86 NT kernels.
+ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+ llvm::InlineAsm *IA =
+ llvm::InlineAsm::get(FTy, "int $$0x2c", "", /*SideEffects=*/true);
+ llvm::AttributeList NoReturnAttr = llvm::AttributeList::get(
+ getLLVMContext(), llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoReturn);
+ CallSite CS = Builder.CreateCall(IA);
+ CS.setAttributes(NoReturnAttr);
+ return CS.getInstruction();
+ }
+ case X86::BI__readfsbyte:
+ case X86::BI__readfsword:
+ case X86::BI__readfsdword:
+ case X86::BI__readfsqword: {
+ llvm::Type *IntTy = ConvertType(E->getType());
+ Value *Ptr = Builder.CreateIntToPtr(EmitScalarExpr(E->getArg(0)),
+ llvm::PointerType::get(IntTy, 257));
+ LoadInst *Load = Builder.CreateAlignedLoad(
+ IntTy, Ptr, getContext().getTypeAlignInChars(E->getType()));
+ Load->setVolatile(true);
+ return Load;
+ }
+ case X86::BI__readgsbyte:
+ case X86::BI__readgsword:
+ case X86::BI__readgsdword:
+ case X86::BI__readgsqword: {
+ llvm::Type *IntTy = ConvertType(E->getType());
+ Value *Ptr = Builder.CreateIntToPtr(EmitScalarExpr(E->getArg(0)),
+ llvm::PointerType::get(IntTy, 256));
+ LoadInst *Load = Builder.CreateAlignedLoad(
+ IntTy, Ptr, getContext().getTypeAlignInChars(E->getType()));
+ Load->setVolatile(true);
+ return Load;
+ }
}
}
@@ -8279,6 +8477,80 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, Ops);
}
}
+
+ case PPC::BI__builtin_vsx_xxpermdi: {
+ ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]);
+ assert(ArgCI && "Third arg must be constant integer!");
+
+ unsigned Index = ArgCI->getZExtValue();
+ Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 2));
+ Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int64Ty, 2));
+
+ // Element zero comes from the first input vector and element one comes from
+ // the second. The element indices within each vector are numbered in big
+ // endian order so the shuffle mask must be adjusted for this on little
+ // endian platforms (i.e. index is complemented and source vector reversed).
+ unsigned ElemIdx0;
+ unsigned ElemIdx1;
+ if (getTarget().isLittleEndian()) {
+ ElemIdx0 = (~Index & 1) + 2;
+ ElemIdx1 = (~Index & 2) >> 1;
+ } else { // BigEndian
+ ElemIdx0 = (Index & 2) >> 1;
+ ElemIdx1 = 2 + (Index & 1);
+ }
+
+ Constant *ShuffleElts[2] = {ConstantInt::get(Int32Ty, ElemIdx0),
+ ConstantInt::get(Int32Ty, ElemIdx1)};
+ Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
+
+ Value *ShuffleCall =
+ Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask);
+ QualType BIRetType = E->getType();
+ auto RetTy = ConvertType(BIRetType);
+ return Builder.CreateBitCast(ShuffleCall, RetTy);
+ }
+
+ case PPC::BI__builtin_vsx_xxsldwi: {
+ ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]);
+ assert(ArgCI && "Third argument must be a compile time constant");
+ unsigned Index = ArgCI->getZExtValue() & 0x3;
+ Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int32Ty, 4));
+ Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int32Ty, 4));
+
+ // Create a shuffle mask
+ unsigned ElemIdx0;
+ unsigned ElemIdx1;
+ unsigned ElemIdx2;
+ unsigned ElemIdx3;
+ if (getTarget().isLittleEndian()) {
+ // Little endian element N comes from element 8+N-Index of the
+ // concatenated wide vector (of course, using modulo arithmetic on
+ // the total number of elements).
+ ElemIdx0 = (8 - Index) % 8;
+ ElemIdx1 = (9 - Index) % 8;
+ ElemIdx2 = (10 - Index) % 8;
+ ElemIdx3 = (11 - Index) % 8;
+ } else {
+ // Big endian ElemIdx<N> = Index + N
+ ElemIdx0 = Index;
+ ElemIdx1 = Index + 1;
+ ElemIdx2 = Index + 2;
+ ElemIdx3 = Index + 3;
+ }
+
+ Constant *ShuffleElts[4] = {ConstantInt::get(Int32Ty, ElemIdx0),
+ ConstantInt::get(Int32Ty, ElemIdx1),
+ ConstantInt::get(Int32Ty, ElemIdx2),
+ ConstantInt::get(Int32Ty, ElemIdx3)};
+
+ Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts);
+ Value *ShuffleCall =
+ Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask);
+ QualType BIRetType = E->getType();
+ auto RetTy = ConvertType(BIRetType);
+ return Builder.CreateBitCast(ShuffleCall, RetTy);
+ }
}
}
@@ -8326,6 +8598,14 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
case AMDGPU::BI__builtin_amdgcn_ds_swizzle:
return emitBinaryBuiltin(*this, E, Intrinsic::amdgcn_ds_swizzle);
+ case AMDGPU::BI__builtin_amdgcn_mov_dpp: {
+ llvm::SmallVector<llvm::Value *, 5> Args;
+ for (unsigned I = 0; I != 5; ++I)
+ Args.push_back(EmitScalarExpr(E->getArg(I)));
+ Value *F = CGM.getIntrinsic(Intrinsic::amdgcn_mov_dpp,
+ Args[0]->getType());
+ return Builder.CreateCall(F, Args);
+ }
case AMDGPU::BI__builtin_amdgcn_div_fixup:
case AMDGPU::BI__builtin_amdgcn_div_fixupf:
case AMDGPU::BI__builtin_amdgcn_div_fixuph:
@@ -8391,7 +8671,9 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
case AMDGPU::BI__builtin_amdgcn_classf:
case AMDGPU::BI__builtin_amdgcn_classh:
return emitFPIntBuiltin(*this, E, Intrinsic::amdgcn_class);
-
+ case AMDGPU::BI__builtin_amdgcn_fmed3f:
+ case AMDGPU::BI__builtin_amdgcn_fmed3h:
+ return emitTernaryBuiltin(*this, E, Intrinsic::amdgcn_fmed3);
case AMDGPU::BI__builtin_amdgcn_read_exec: {
CallInst *CI = cast<CallInst>(
EmitSpecialRegisterBuiltin(*this, E, Int64Ty, Int64Ty, true, "exec"));
@@ -8510,12 +8792,14 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, {X, Undef});
}
+ case SystemZ::BI__builtin_s390_vfsqsb:
case SystemZ::BI__builtin_s390_vfsqdb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
Function *F = CGM.getIntrinsic(Intrinsic::sqrt, ResultType);
return Builder.CreateCall(F, X);
}
+ case SystemZ::BI__builtin_s390_vfmasb:
case SystemZ::BI__builtin_s390_vfmadb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
@@ -8524,6 +8808,7 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
return Builder.CreateCall(F, {X, Y, Z});
}
+ case SystemZ::BI__builtin_s390_vfmssb:
case SystemZ::BI__builtin_s390_vfmsdb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
@@ -8533,12 +8818,35 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
return Builder.CreateCall(F, {X, Y, Builder.CreateFSub(Zero, Z, "sub")});
}
+ case SystemZ::BI__builtin_s390_vfnmasb:
+ case SystemZ::BI__builtin_s390_vfnmadb: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ Value *Z = EmitScalarExpr(E->getArg(2));
+ Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
+ Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
+ return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, Z}), "sub");
+ }
+ case SystemZ::BI__builtin_s390_vfnmssb:
+ case SystemZ::BI__builtin_s390_vfnmsdb: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ Value *Z = EmitScalarExpr(E->getArg(2));
+ Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType);
+ Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
+ Value *NegZ = Builder.CreateFSub(Zero, Z, "sub");
+ return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, NegZ}));
+ }
+ case SystemZ::BI__builtin_s390_vflpsb:
case SystemZ::BI__builtin_s390_vflpdb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
return Builder.CreateCall(F, X);
}
+ case SystemZ::BI__builtin_s390_vflnsb:
case SystemZ::BI__builtin_s390_vflndb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
@@ -8546,6 +8854,7 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
return Builder.CreateFSub(Zero, Builder.CreateCall(F, X), "sub");
}
+ case SystemZ::BI__builtin_s390_vfisb:
case SystemZ::BI__builtin_s390_vfidb: {
llvm::Type *ResultType = ConvertType(E->getType());
Value *X = EmitScalarExpr(E->getArg(0));
@@ -8555,8 +8864,8 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
bool IsConstM5 = E->getArg(2)->isIntegerConstantExpr(M5, getContext());
assert(IsConstM4 && IsConstM5 && "Constant arg isn't actually constant?");
(void)IsConstM4; (void)IsConstM5;
- // Check whether this instance of vfidb can be represented via a LLVM
- // standard intrinsic. We only support some combinations of M4 and M5.
+ // Check whether this instance can be represented via a LLVM standard
+ // intrinsic. We only support some combinations of M4 and M5.
Intrinsic::ID ID = Intrinsic::not_intrinsic;
switch (M4.getZExtValue()) {
default: break;
@@ -8581,11 +8890,76 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(ID, ResultType);
return Builder.CreateCall(F, X);
}
- Function *F = CGM.getIntrinsic(Intrinsic::s390_vfidb);
+ switch (BuiltinID) {
+ case SystemZ::BI__builtin_s390_vfisb: ID = Intrinsic::s390_vfisb; break;
+ case SystemZ::BI__builtin_s390_vfidb: ID = Intrinsic::s390_vfidb; break;
+ default: llvm_unreachable("Unknown BuiltinID");
+ }
+ Function *F = CGM.getIntrinsic(ID);
Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
Value *M5Value = llvm::ConstantInt::get(getLLVMContext(), M5);
return Builder.CreateCall(F, {X, M4Value, M5Value});
}
+ case SystemZ::BI__builtin_s390_vfmaxsb:
+ case SystemZ::BI__builtin_s390_vfmaxdb: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ // Constant-fold the M4 mask argument.
+ llvm::APSInt M4;
+ bool IsConstM4 = E->getArg(2)->isIntegerConstantExpr(M4, getContext());
+ assert(IsConstM4 && "Constant arg isn't actually constant?");
+ (void)IsConstM4;
+ // Check whether this instance can be represented via a LLVM standard
+ // intrinsic. We only support some values of M4.
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+ switch (M4.getZExtValue()) {
+ default: break;
+ case 4: ID = Intrinsic::maxnum; break;
+ }
+ if (ID != Intrinsic::not_intrinsic) {
+ Function *F = CGM.getIntrinsic(ID, ResultType);
+ return Builder.CreateCall(F, {X, Y});
+ }
+ switch (BuiltinID) {
+ case SystemZ::BI__builtin_s390_vfmaxsb: ID = Intrinsic::s390_vfmaxsb; break;
+ case SystemZ::BI__builtin_s390_vfmaxdb: ID = Intrinsic::s390_vfmaxdb; break;
+ default: llvm_unreachable("Unknown BuiltinID");
+ }
+ Function *F = CGM.getIntrinsic(ID);
+ Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
+ return Builder.CreateCall(F, {X, Y, M4Value});
+ }
+ case SystemZ::BI__builtin_s390_vfminsb:
+ case SystemZ::BI__builtin_s390_vfmindb: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ // Constant-fold the M4 mask argument.
+ llvm::APSInt M4;
+ bool IsConstM4 = E->getArg(2)->isIntegerConstantExpr(M4, getContext());
+ assert(IsConstM4 && "Constant arg isn't actually constant?");
+ (void)IsConstM4;
+ // Check whether this instance can be represented via a LLVM standard
+ // intrinsic. We only support some values of M4.
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+ switch (M4.getZExtValue()) {
+ default: break;
+ case 4: ID = Intrinsic::minnum; break;
+ }
+ if (ID != Intrinsic::not_intrinsic) {
+ Function *F = CGM.getIntrinsic(ID, ResultType);
+ return Builder.CreateCall(F, {X, Y});
+ }
+ switch (BuiltinID) {
+ case SystemZ::BI__builtin_s390_vfminsb: ID = Intrinsic::s390_vfminsb; break;
+ case SystemZ::BI__builtin_s390_vfmindb: ID = Intrinsic::s390_vfmindb; break;
+ default: llvm_unreachable("Unknown BuiltinID");
+ }
+ Function *F = CGM.getIntrinsic(ID);
+ Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
+ return Builder.CreateCall(F, {X, Y, M4Value});
+ }
// Vector intrisincs that output the post-instruction CC value.
@@ -8652,10 +9026,14 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
INTRINSIC_WITH_CC(s390_vstrczhs);
INTRINSIC_WITH_CC(s390_vstrczfs);
+ INTRINSIC_WITH_CC(s390_vfcesbs);
INTRINSIC_WITH_CC(s390_vfcedbs);
+ INTRINSIC_WITH_CC(s390_vfchsbs);
INTRINSIC_WITH_CC(s390_vfchdbs);
+ INTRINSIC_WITH_CC(s390_vfchesbs);
INTRINSIC_WITH_CC(s390_vfchedbs);
+ INTRINSIC_WITH_CC(s390_vftcisb);
INTRINSIC_WITH_CC(s390_vftcidb);
#undef INTRINSIC_WITH_CC
@@ -8669,9 +9047,8 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
auto MakeLdg = [&](unsigned IntrinsicID) {
Value *Ptr = EmitScalarExpr(E->getArg(0));
- AlignmentSource AlignSource;
clang::CharUnits Align =
- getNaturalPointeeTypeAlignment(E->getArg(0)->getType(), &AlignSource);
+ getNaturalPointeeTypeAlignment(E->getArg(0)->getType());
return Builder.CreateCall(
CGM.getIntrinsic(IntrinsicID, {Ptr->getType()->getPointerElementType(),
Ptr->getType()}),
@@ -8923,6 +9300,16 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_grow_memory, X->getType());
return Builder.CreateCall(Callee, X);
}
+ case WebAssembly::BI__builtin_wasm_throw: {
+ Value *Tag = EmitScalarExpr(E->getArg(0));
+ Value *Obj = EmitScalarExpr(E->getArg(1));
+ Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_throw);
+ return Builder.CreateCall(Callee, {Tag, Obj});
+ }
+ case WebAssembly::BI__builtin_wasm_rethrow: {
+ Value *Callee = CGM.getIntrinsic(Intrinsic::wasm_rethrow);
+ return Builder.CreateCall(Callee);
+ }
default:
return nullptr;
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp
index 83febcb..d24ef0a 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCUDANV.cpp
@@ -15,7 +15,7 @@
#include "CGCUDARuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "ConstantBuilder.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/Decl.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallSite.h"
@@ -265,7 +265,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
"__cudaRegisterFatBinary");
// struct { int magic, int version, void * gpu_binary, void * dont_care };
llvm::StructType *FatbinWrapperTy =
- llvm::StructType::get(IntTy, IntTy, VoidPtrTy, VoidPtrTy, nullptr);
+ llvm::StructType::get(IntTy, IntTy, VoidPtrTy, VoidPtrTy);
llvm::Function *ModuleCtorFunc = llvm::Function::Create(
llvm::FunctionType::get(VoidTy, VoidPtrTy, false),
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp
index 59010f4..0f3141a 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp
@@ -256,7 +256,7 @@ llvm::Constant *CodeGenModule::getAddrOfCXXStructor(
return GetOrCreateLLVMFunction(
getMangledName(GD), FnType, GD, /*ForVTable=*/false, DontDefer,
- /*isThunk=*/false, /*ExtraAttrs=*/llvm::AttributeSet(), IsForDefinition);
+ /*isThunk=*/false, /*ExtraAttrs=*/llvm::AttributeList(), IsForDefinition);
}
static CGCallee BuildAppleKextVirtualCall(CodeGenFunction &CGF,
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp
index df75a7d..0332586 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp
@@ -30,38 +30,9 @@ void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) {
}
bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const {
- // If RD has a non-trivial move or copy constructor, we cannot copy the
- // argument.
- if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialMoveConstructor())
- return false;
-
- // If RD has a non-trivial destructor, we cannot copy the argument.
- if (RD->hasNonTrivialDestructor())
- return false;
-
// We can only copy the argument if there exists at least one trivial,
// non-deleted copy or move constructor.
- // FIXME: This assumes that all lazily declared copy and move constructors are
- // not deleted. This assumption might not be true in some corner cases.
- bool CopyDeleted = false;
- bool MoveDeleted = false;
- for (const CXXConstructorDecl *CD : RD->ctors()) {
- if (CD->isCopyConstructor() || CD->isMoveConstructor()) {
- assert(CD->isTrivial());
- // We had at least one undeleted trivial copy or move ctor. Return
- // directly.
- if (!CD->isDeleted())
- return true;
- if (CD->isCopyConstructor())
- CopyDeleted = true;
- else
- MoveDeleted = true;
- }
- }
-
- // If all trivial copy and move constructors are deleted, we cannot copy the
- // argument.
- return !(CopyDeleted && MoveDeleted);
+ return RD->canPassInRegisters();
}
llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
@@ -159,10 +130,10 @@ void CGCXXABI::buildThisParam(CodeGenFunction &CGF, FunctionArgList &params) {
// FIXME: I'm not entirely sure I like using a fake decl just for code
// generation. Maybe we can come up with a better way?
- ImplicitParamDecl *ThisDecl
- = ImplicitParamDecl::Create(CGM.getContext(), nullptr, MD->getLocation(),
- &CGM.getContext().Idents.get("this"),
- MD->getThisType(CGM.getContext()));
+ auto *ThisDecl = ImplicitParamDecl::Create(
+ CGM.getContext(), nullptr, MD->getLocation(),
+ &CGM.getContext().Idents.get("this"), MD->getThisType(CGM.getContext()),
+ ImplicitParamDecl::CXXThis);
params.push_back(ThisDecl);
CGF.CXXABIThisDecl = ThisDecl;
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h
index d53fd4c..7b912e3 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h
@@ -291,11 +291,26 @@ public:
/// Emit constructor variants required by this ABI.
virtual void EmitCXXConstructors(const CXXConstructorDecl *D) = 0;
+ /// Notes how many arguments were added to the beginning (Prefix) and ending
+ /// (Suffix) of an arg list.
+ ///
+ /// Note that Prefix actually refers to the number of args *after* the first
+ /// one: `this` arguments always come first.
+ struct AddedStructorArgs {
+ unsigned Prefix = 0;
+ unsigned Suffix = 0;
+ AddedStructorArgs() = default;
+ AddedStructorArgs(unsigned P, unsigned S) : Prefix(P), Suffix(S) {}
+ static AddedStructorArgs prefix(unsigned N) { return {N, 0}; }
+ static AddedStructorArgs suffix(unsigned N) { return {0, N}; }
+ };
+
/// Build the signature of the given constructor or destructor variant by
/// adding any required parameters. For convenience, ArgTys has been
/// initialized with the type of 'this'.
- virtual void buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
- SmallVectorImpl<CanQualType> &ArgTys) = 0;
+ virtual AddedStructorArgs
+ buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
+ SmallVectorImpl<CanQualType> &ArgTys) = 0;
/// Returns true if the given destructor type should be emitted as a linkonce
/// delegating thunk, regardless of whether the dtor is defined in this TU or
@@ -355,9 +370,9 @@ public:
/// Add any ABI-specific implicit arguments needed to call a constructor.
///
- /// \return The number of args added to the call, which is typically zero or
- /// one.
- virtual unsigned
+ /// \return The number of arguments added at the beginning and end of the
+ /// call, which is typically zero or one.
+ virtual AddedStructorArgs
addImplicitConstructorArgs(CodeGenFunction &CGF, const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating, CallArgList &Args) = 0;
@@ -377,7 +392,7 @@ public:
isVirtualOffsetNeededForVTableField(CodeGenFunction &CGF,
CodeGenFunction::VPtr Vptr) = 0;
- /// Checks if ABI requires to initilize vptrs for given dynamic class.
+ /// Checks if ABI requires to initialize vptrs for given dynamic class.
virtual bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) = 0;
/// Get the address point of the vtable for the given base subobject.
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp
index c7c61e0..316bf44 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp
@@ -50,7 +50,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_X86FastCall: return llvm::CallingConv::X86_FastCall;
case CC_X86RegCall: return llvm::CallingConv::X86_RegCall;
case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall;
- case CC_X86_64Win64: return llvm::CallingConv::X86_64_Win64;
+ case CC_Win64: return llvm::CallingConv::Win64;
case CC_X86_64SysV: return llvm::CallingConv::X86_64_SysV;
case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS;
case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
@@ -101,39 +101,64 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
FTNP->getExtInfo(), {}, RequiredArgs(0));
}
-/// Adds the formal paramaters in FPT to the given prefix. If any parameter in
+static void addExtParameterInfosForCall(
+ llvm::SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &paramInfos,
+ const FunctionProtoType *proto,
+ unsigned prefixArgs,
+ unsigned totalArgs) {
+ assert(proto->hasExtParameterInfos());
+ assert(paramInfos.size() <= prefixArgs);
+ assert(proto->getNumParams() + prefixArgs <= totalArgs);
+
+ paramInfos.reserve(totalArgs);
+
+ // Add default infos for any prefix args that don't already have infos.
+ paramInfos.resize(prefixArgs);
+
+ // Add infos for the prototype.
+ for (const auto &ParamInfo : proto->getExtParameterInfos()) {
+ paramInfos.push_back(ParamInfo);
+ // pass_object_size params have no parameter info.
+ if (ParamInfo.hasPassObjectSize())
+ paramInfos.emplace_back();
+ }
+
+ assert(paramInfos.size() <= totalArgs &&
+ "Did we forget to insert pass_object_size args?");
+ // Add default infos for the variadic and/or suffix arguments.
+ paramInfos.resize(totalArgs);
+}
+
+/// Adds the formal parameters in FPT to the given prefix. If any parameter in
/// FPT has pass_object_size attrs, then we'll add parameters for those, too.
static void appendParameterTypes(const CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &prefix,
SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &paramInfos,
- CanQual<FunctionProtoType> FPT,
- const FunctionDecl *FD) {
- // Fill out paramInfos.
- if (FPT->hasExtParameterInfos() || !paramInfos.empty()) {
- assert(paramInfos.size() <= prefix.size());
- auto protoParamInfos = FPT->getExtParameterInfos();
- paramInfos.reserve(prefix.size() + protoParamInfos.size());
- paramInfos.resize(prefix.size());
- paramInfos.append(protoParamInfos.begin(), protoParamInfos.end());
- }
-
- // Fast path: unknown target.
- if (FD == nullptr) {
+ CanQual<FunctionProtoType> FPT) {
+ // Fast path: don't touch param info if we don't need to.
+ if (!FPT->hasExtParameterInfos()) {
+ assert(paramInfos.empty() &&
+ "We have paramInfos, but the prototype doesn't?");
prefix.append(FPT->param_type_begin(), FPT->param_type_end());
return;
}
- // In the vast majority cases, we'll have precisely FPT->getNumParams()
+ unsigned PrefixSize = prefix.size();
+ // In the vast majority of cases, we'll have precisely FPT->getNumParams()
// parameters; the only thing that can change this is the presence of
// pass_object_size. So, we preallocate for the common case.
prefix.reserve(prefix.size() + FPT->getNumParams());
- assert(FD->getNumParams() == FPT->getNumParams());
+ auto ExtInfos = FPT->getExtParameterInfos();
+ assert(ExtInfos.size() == FPT->getNumParams());
for (unsigned I = 0, E = FPT->getNumParams(); I != E; ++I) {
prefix.push_back(FPT->getParamType(I));
- if (FD->getParamDecl(I)->hasAttr<PassObjectSizeAttr>())
+ if (ExtInfos[I].hasPassObjectSize())
prefix.push_back(CGT.getContext().getSizeType());
}
+
+ addExtParameterInfosForCall(paramInfos, FPT.getTypePtr(), PrefixSize,
+ prefix.size());
}
/// Arrange the LLVM function layout for a value of the given function
@@ -147,7 +172,7 @@ arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod,
RequiredArgs Required =
RequiredArgs::forPrototypePlus(FTP, prefix.size(), FD);
// FIXME: Kill copy.
- appendParameterTypes(CGT, prefix, paramInfos, FTP, FD);
+ appendParameterTypes(CGT, prefix, paramInfos, FTP);
CanQualType resultType = FTP->getReturnType().getUnqualifiedType();
return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod,
@@ -193,7 +218,7 @@ static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
return CC_IntelOclBicc;
if (D->hasAttr<MSABIAttr>())
- return IsWindows ? CC_C : CC_X86_64Win64;
+ return IsWindows ? CC_C : CC_Win64;
if (D->hasAttr<SysVABIAttr>())
return IsWindows ? CC_X86_64SysV : CC_C;
@@ -286,9 +311,19 @@ CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
// Add the formal parameters.
if (PassParams)
- appendParameterTypes(*this, argTypes, paramInfos, FTP, MD);
-
- TheCXXABI.buildStructorSignature(MD, Type, argTypes);
+ appendParameterTypes(*this, argTypes, paramInfos, FTP);
+
+ CGCXXABI::AddedStructorArgs AddedArgs =
+ TheCXXABI.buildStructorSignature(MD, Type, argTypes);
+ if (!paramInfos.empty()) {
+ // Note: prefix implies after the first param.
+ if (AddedArgs.Prefix)
+ paramInfos.insert(paramInfos.begin() + 1, AddedArgs.Prefix,
+ FunctionProtoType::ExtParameterInfo{});
+ if (AddedArgs.Suffix)
+ paramInfos.append(AddedArgs.Suffix,
+ FunctionProtoType::ExtParameterInfo{});
+ }
RequiredArgs required =
(PassParams && MD->isVariadic() ? RequiredArgs(argTypes.size())
@@ -321,26 +356,6 @@ getArgTypesForDeclaration(ASTContext &ctx, const FunctionArgList &args) {
return argTypes;
}
-static void addExtParameterInfosForCall(
- llvm::SmallVectorImpl<FunctionProtoType::ExtParameterInfo> &paramInfos,
- const FunctionProtoType *proto,
- unsigned prefixArgs,
- unsigned totalArgs) {
- assert(proto->hasExtParameterInfos());
- assert(paramInfos.size() <= prefixArgs);
- assert(proto->getNumParams() + prefixArgs <= totalArgs);
-
- // Add default infos for any prefix args that don't already have infos.
- paramInfos.resize(prefixArgs);
-
- // Add infos for the prototype.
- auto protoInfos = proto->getExtParameterInfos();
- paramInfos.append(protoInfos.begin(), protoInfos.end());
-
- // Add default infos for the variadic arguments.
- paramInfos.resize(totalArgs);
-}
-
static llvm::SmallVector<FunctionProtoType::ExtParameterInfo, 16>
getExtParameterInfosForCall(const FunctionProtoType *proto,
unsigned prefixArgs, unsigned totalArgs) {
@@ -352,18 +367,31 @@ getExtParameterInfosForCall(const FunctionProtoType *proto,
}
/// Arrange a call to a C++ method, passing the given arguments.
+///
+/// ExtraPrefixArgs is the number of ABI-specific args passed after the `this`
+/// parameter.
+/// ExtraSuffixArgs is the number of ABI-specific args passed at the end of
+/// args.
+/// PassProtoArgs indicates whether `args` has args for the parameters in the
+/// given CXXConstructorDecl.
const CGFunctionInfo &
CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
const CXXConstructorDecl *D,
CXXCtorType CtorKind,
- unsigned ExtraArgs) {
+ unsigned ExtraPrefixArgs,
+ unsigned ExtraSuffixArgs,
+ bool PassProtoArgs) {
// FIXME: Kill copy.
SmallVector<CanQualType, 16> ArgTypes;
for (const auto &Arg : args)
ArgTypes.push_back(Context.getCanonicalParamType(Arg.Ty));
+ // +1 for implicit this, which should always be args[0].
+ unsigned TotalPrefixArgs = 1 + ExtraPrefixArgs;
+
CanQual<FunctionProtoType> FPT = GetFormalType(D);
- RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs, D);
+ RequiredArgs Required =
+ RequiredArgs::forPrototypePlus(FPT, TotalPrefixArgs + ExtraSuffixArgs, D);
GlobalDecl GD(D, CtorKind);
CanQualType ResultType = TheCXXABI.HasThisReturn(GD)
? ArgTypes.front()
@@ -372,8 +400,14 @@ CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
: Context.VoidTy;
FunctionType::ExtInfo Info = FPT->getExtInfo();
- auto ParamInfos = getExtParameterInfosForCall(FPT.getTypePtr(), 1 + ExtraArgs,
- ArgTypes.size());
+ llvm::SmallVector<FunctionProtoType::ExtParameterInfo, 16> ParamInfos;
+ // If the prototype args are elided, we should only have ABI-specific args,
+ // which never have param info.
+ if (PassProtoArgs && FPT->hasExtParameterInfos()) {
+ // ABI-specific suffix arguments are treated the same as variadic arguments.
+ addExtParameterInfosForCall(ParamInfos, FPT.getTypePtr(), TotalPrefixArgs,
+ ArgTypes.size());
+ }
return arrangeLLVMFunctionInfo(ResultType, /*instanceMethod=*/true,
/*chainCall=*/false, ArgTypes, Info,
ParamInfos, Required);
@@ -617,15 +651,20 @@ CodeGenTypes::arrangeBuiltinFunctionDeclaration(CanQualType resultType,
}
/// Arrange a call to a C++ method, passing the given arguments.
+///
+/// numPrefixArgs is the number of ABI-specific prefix arguments we have. It
+/// does not count `this`.
const CGFunctionInfo &
CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
const FunctionProtoType *proto,
- RequiredArgs required) {
- unsigned numRequiredArgs =
- (proto->isVariadic() ? required.getNumRequiredArgs() : args.size());
- unsigned numPrefixArgs = numRequiredArgs - proto->getNumParams();
+ RequiredArgs required,
+ unsigned numPrefixArgs) {
+ assert(numPrefixArgs + 1 <= args.size() &&
+ "Emitting a call with less args than the required prefix?");
+ // Add one to account for `this`. It's a bit awkward here, but we don't count
+ // `this` in similar places elsewhere.
auto paramInfos =
- getExtParameterInfosForCall(proto, numPrefixArgs, args.size());
+ getExtParameterInfosForCall(proto, numPrefixArgs + 1, args.size());
// FIXME: Kill copy.
auto argTypes = getArgTypesForCall(Context, args);
@@ -668,6 +707,12 @@ CodeGenTypes::arrangeCall(const CGFunctionInfo &signature,
signature.getRequiredArgs());
}
+namespace clang {
+namespace CodeGen {
+void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI);
+}
+}
+
/// Arrange the argument and result information for an abstract value
/// of a given function type. This is the method which all of the
/// above functions ultimately defer to.
@@ -680,7 +725,7 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
ArrayRef<FunctionProtoType::ExtParameterInfo> paramInfos,
RequiredArgs required) {
assert(std::all_of(argTypes.begin(), argTypes.end(),
- std::mem_fun_ref(&CanQualType::isCanonicalAsParam)));
+ [](CanQualType T) { return T.isCanonicalAsParam(); }));
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
@@ -702,12 +747,16 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
bool inserted = FunctionsBeingProcessed.insert(FI).second;
(void)inserted;
assert(inserted && "Recursively being processed?");
-
+
// Compute ABI information.
- if (info.getCC() != CC_Swift) {
- getABIInfo().computeInfo(*FI);
- } else {
+ if (CC == llvm::CallingConv::SPIR_KERNEL) {
+ // Force target independent argument handling for the host visible
+ // kernel functions.
+ computeSPIRKernelABIInfo(CGM, *FI);
+ } else if (info.getCC() == CC_Swift) {
swiftcall::computeABIInfo(CGM, *FI);
+ } else {
+ getABIInfo().computeInfo(*FI);
}
// Loop over all of the computed argument and return value info. If any of
@@ -749,6 +798,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
FI->ChainCall = chainCall;
FI->NoReturn = info.getNoReturn();
FI->ReturnsRetained = info.getProducesResult();
+ FI->NoCallerSavedRegs = info.getNoCallerSavedRegs();
FI->Required = required;
FI->HasRegParm = info.getHasRegParm();
FI->RegParm = info.getRegParm();
@@ -1247,7 +1297,7 @@ static void CreateCoercedStore(llvm::Value *Src,
// If store is legal, just bitcast the src pointer.
if (SrcSize <= DstSize) {
- Dst = CGF.Builder.CreateBitCast(Dst, llvm::PointerType::getUnqual(SrcTy));
+ Dst = CGF.Builder.CreateElementBitCast(Dst, SrcTy);
BuildAggStore(CGF, Src, Dst, DstIsVolatile);
} else {
// Otherwise do coercion through memory. This is stupid, but
@@ -1547,9 +1597,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
case ABIArgInfo::Indirect: {
assert(NumIRArgs == 1);
- // indirect arguments are always on the stack, which is addr space #0.
+ // indirect arguments are always on the stack, which is alloca addr space.
llvm::Type *LTy = ConvertTypeForMem(it->type);
- ArgTypes[FirstIRArg] = LTy->getPointerTo();
+ ArgTypes[FirstIRArg] = LTy->getPointerTo(
+ CGM.getDataLayout().getAllocaAddrSpace());
break;
}
@@ -1620,15 +1671,111 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
}
+void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
+ bool AttrOnCallSite,
+ llvm::AttrBuilder &FuncAttrs) {
+ // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed.
+ if (!HasOptnone) {
+ if (CodeGenOpts.OptimizeSize)
+ FuncAttrs.addAttribute(llvm::Attribute::OptimizeForSize);
+ if (CodeGenOpts.OptimizeSize == 2)
+ FuncAttrs.addAttribute(llvm::Attribute::MinSize);
+ }
+
+ if (CodeGenOpts.DisableRedZone)
+ FuncAttrs.addAttribute(llvm::Attribute::NoRedZone);
+ if (CodeGenOpts.NoImplicitFloat)
+ FuncAttrs.addAttribute(llvm::Attribute::NoImplicitFloat);
+
+ if (AttrOnCallSite) {
+ // Attributes that should go on the call site only.
+ if (!CodeGenOpts.SimplifyLibCalls ||
+ CodeGenOpts.isNoBuiltinFunc(Name.data()))
+ FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin);
+ if (!CodeGenOpts.TrapFuncName.empty())
+ FuncAttrs.addAttribute("trap-func-name", CodeGenOpts.TrapFuncName);
+ } else {
+ // Attributes that should go on the function, but not the call site.
+ if (!CodeGenOpts.DisableFPElim) {
+ FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
+ } else if (CodeGenOpts.OmitLeafFramePointer) {
+ FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
+ } else {
+ FuncAttrs.addAttribute("no-frame-pointer-elim", "true");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
+ }
+
+ FuncAttrs.addAttribute("less-precise-fpmad",
+ llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD));
+
+ if (!CodeGenOpts.FPDenormalMode.empty())
+ FuncAttrs.addAttribute("denormal-fp-math", CodeGenOpts.FPDenormalMode);
+
+ FuncAttrs.addAttribute("no-trapping-math",
+ llvm::toStringRef(CodeGenOpts.NoTrappingMath));
+
+ // TODO: Are these all needed?
+ // unsafe/inf/nan/nsz are handled by instruction-level FastMathFlags.
+ FuncAttrs.addAttribute("no-infs-fp-math",
+ llvm::toStringRef(CodeGenOpts.NoInfsFPMath));
+ FuncAttrs.addAttribute("no-nans-fp-math",
+ llvm::toStringRef(CodeGenOpts.NoNaNsFPMath));
+ FuncAttrs.addAttribute("unsafe-fp-math",
+ llvm::toStringRef(CodeGenOpts.UnsafeFPMath));
+ FuncAttrs.addAttribute("use-soft-float",
+ llvm::toStringRef(CodeGenOpts.SoftFloat));
+ FuncAttrs.addAttribute("stack-protector-buffer-size",
+ llvm::utostr(CodeGenOpts.SSPBufferSize));
+ FuncAttrs.addAttribute("no-signed-zeros-fp-math",
+ llvm::toStringRef(CodeGenOpts.NoSignedZeros));
+ FuncAttrs.addAttribute(
+ "correctly-rounded-divide-sqrt-fp-math",
+ llvm::toStringRef(CodeGenOpts.CorrectlyRoundedDivSqrt));
+
+ // TODO: Reciprocal estimate codegen options should apply to instructions?
+ std::vector<std::string> &Recips = getTarget().getTargetOpts().Reciprocals;
+ if (!Recips.empty())
+ FuncAttrs.addAttribute("reciprocal-estimates",
+ llvm::join(Recips.begin(), Recips.end(), ","));
+
+ if (CodeGenOpts.StackRealignment)
+ FuncAttrs.addAttribute("stackrealign");
+ if (CodeGenOpts.Backchain)
+ FuncAttrs.addAttribute("backchain");
+ }
+
+ if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
+ // Conservatively, mark all functions and calls in CUDA as convergent
+ // (meaning, they may call an intrinsically convergent op, such as
+ // __syncthreads(), and so can't have certain optimizations applied around
+ // them). LLVM will remove this attribute where it safely can.
+ FuncAttrs.addAttribute(llvm::Attribute::Convergent);
+
+ // Exceptions aren't supported in CUDA device code.
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+
+ // Respect -fcuda-flush-denormals-to-zero.
+ if (getLangOpts().CUDADeviceFlushDenormalsToZero)
+ FuncAttrs.addAttribute("nvptx-f32ftz", "true");
+ }
+}
+
+void CodeGenModule::AddDefaultFnAttrs(llvm::Function &F) {
+ llvm::AttrBuilder FuncAttrs;
+ ConstructDefaultFnAttrList(F.getName(),
+ F.hasFnAttribute(llvm::Attribute::OptimizeNone),
+ /* AttrOnCallsite = */ false, FuncAttrs);
+ F.addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs);
+}
+
void CodeGenModule::ConstructAttributeList(
StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo,
- AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite) {
+ llvm::AttributeList &AttrList, unsigned &CallingConv, bool AttrOnCallSite) {
llvm::AttrBuilder FuncAttrs;
llvm::AttrBuilder RetAttrs;
- bool HasOptnone = false;
CallingConv = FI.getEffectiveCallingConvention();
-
if (FI.isNoReturn())
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
@@ -1639,7 +1786,7 @@ void CodeGenModule::ConstructAttributeList(
const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
- bool HasAnyX86InterruptAttr = false;
+ bool HasOptnone = false;
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
@@ -1648,6 +1795,8 @@ void CodeGenModule::ConstructAttributeList(
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
if (TargetDecl->hasAttr<NoReturnAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
+ if (TargetDecl->hasAttr<ColdAttr>())
+ FuncAttrs.addAttribute(llvm::Attribute::Cold);
if (TargetDecl->hasAttr<NoDuplicateAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (TargetDecl->hasAttr<ConvergentAttr>())
@@ -1678,8 +1827,9 @@ void CodeGenModule::ConstructAttributeList(
RetAttrs.addAttribute(llvm::Attribute::NoAlias);
if (TargetDecl->hasAttr<ReturnsNonNullAttr>())
RetAttrs.addAttribute(llvm::Attribute::NonNull);
+ if (TargetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>())
+ FuncAttrs.addAttribute("no_caller_saved_registers");
- HasAnyX86InterruptAttr = TargetDecl->hasAttr<AnyX86InterruptAttr>();
HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) {
Optional<unsigned> NumElemsParam;
@@ -1691,86 +1841,19 @@ void CodeGenModule::ConstructAttributeList(
}
}
- // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed.
- if (!HasOptnone) {
- if (CodeGenOpts.OptimizeSize)
- FuncAttrs.addAttribute(llvm::Attribute::OptimizeForSize);
- if (CodeGenOpts.OptimizeSize == 2)
- FuncAttrs.addAttribute(llvm::Attribute::MinSize);
- }
+ ConstructDefaultFnAttrList(Name, HasOptnone, AttrOnCallSite, FuncAttrs);
- if (CodeGenOpts.DisableRedZone)
- FuncAttrs.addAttribute(llvm::Attribute::NoRedZone);
- if (CodeGenOpts.NoImplicitFloat)
- FuncAttrs.addAttribute(llvm::Attribute::NoImplicitFloat);
if (CodeGenOpts.EnableSegmentedStacks &&
!(TargetDecl && TargetDecl->hasAttr<NoSplitStackAttr>()))
FuncAttrs.addAttribute("split-stack");
- if (AttrOnCallSite) {
- // Attributes that should go on the call site only.
- if (!CodeGenOpts.SimplifyLibCalls ||
- CodeGenOpts.isNoBuiltinFunc(Name.data()))
- FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin);
- if (!CodeGenOpts.TrapFuncName.empty())
- FuncAttrs.addAttribute("trap-func-name", CodeGenOpts.TrapFuncName);
- } else {
- // Attributes that should go on the function, but not the call site.
- if (!CodeGenOpts.DisableFPElim) {
- FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
- } else if (CodeGenOpts.OmitLeafFramePointer) {
- FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
- FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
- } else {
- FuncAttrs.addAttribute("no-frame-pointer-elim", "true");
- FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
- }
-
+ if (!AttrOnCallSite) {
bool DisableTailCalls =
- CodeGenOpts.DisableTailCalls || HasAnyX86InterruptAttr ||
- (TargetDecl && TargetDecl->hasAttr<DisableTailCallsAttr>());
- FuncAttrs.addAttribute(
- "disable-tail-calls",
- llvm::toStringRef(DisableTailCalls));
-
- FuncAttrs.addAttribute("less-precise-fpmad",
- llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD));
-
- if (!CodeGenOpts.FPDenormalMode.empty())
- FuncAttrs.addAttribute("denormal-fp-math",
- CodeGenOpts.FPDenormalMode);
-
- FuncAttrs.addAttribute("no-trapping-math",
- llvm::toStringRef(CodeGenOpts.NoTrappingMath));
-
- // TODO: Are these all needed?
- // unsafe/inf/nan/nsz are handled by instruction-level FastMathFlags.
- FuncAttrs.addAttribute("no-infs-fp-math",
- llvm::toStringRef(CodeGenOpts.NoInfsFPMath));
- FuncAttrs.addAttribute("no-nans-fp-math",
- llvm::toStringRef(CodeGenOpts.NoNaNsFPMath));
- FuncAttrs.addAttribute("unsafe-fp-math",
- llvm::toStringRef(CodeGenOpts.UnsafeFPMath));
- FuncAttrs.addAttribute("use-soft-float",
- llvm::toStringRef(CodeGenOpts.SoftFloat));
- FuncAttrs.addAttribute("stack-protector-buffer-size",
- llvm::utostr(CodeGenOpts.SSPBufferSize));
- FuncAttrs.addAttribute("no-signed-zeros-fp-math",
- llvm::toStringRef(CodeGenOpts.NoSignedZeros));
- FuncAttrs.addAttribute(
- "correctly-rounded-divide-sqrt-fp-math",
- llvm::toStringRef(CodeGenOpts.CorrectlyRoundedDivSqrt));
-
- // TODO: Reciprocal estimate codegen options should apply to instructions?
- std::vector<std::string> &Recips = getTarget().getTargetOpts().Reciprocals;
- if (!Recips.empty())
- FuncAttrs.addAttribute("reciprocal-estimates",
- llvm::join(Recips.begin(), Recips.end(), ","));
-
- if (CodeGenOpts.StackRealignment)
- FuncAttrs.addAttribute("stackrealign");
- if (CodeGenOpts.Backchain)
- FuncAttrs.addAttribute("backchain");
+ CodeGenOpts.DisableTailCalls ||
+ (TargetDecl && (TargetDecl->hasAttr<DisableTailCallsAttr>() ||
+ TargetDecl->hasAttr<AnyX86InterruptAttr>()));
+ FuncAttrs.addAttribute("disable-tail-calls",
+ llvm::toStringRef(DisableTailCalls));
// Add target-cpu and target-features attributes to functions. If
// we have a decl for the function and it has a target attribute then
@@ -1794,8 +1877,8 @@ void CodeGenModule::ConstructAttributeList(
// the function.
const auto *TD = FD->getAttr<TargetAttr>();
TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
- if (ParsedAttr.second != "")
- TargetCPU = ParsedAttr.second;
+ if (ParsedAttr.Architecture != "")
+ TargetCPU = ParsedAttr.Architecture;
if (TargetCPU != "")
FuncAttrs.addAttribute("target-cpu", TargetCPU);
if (!Features.empty()) {
@@ -1819,21 +1902,6 @@ void CodeGenModule::ConstructAttributeList(
}
}
- if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
- // Conservatively, mark all functions and calls in CUDA as convergent
- // (meaning, they may call an intrinsically convergent op, such as
- // __syncthreads(), and so can't have certain optimizations applied around
- // them). LLVM will remove this attribute where it safely can.
- FuncAttrs.addAttribute(llvm::Attribute::Convergent);
-
- // Exceptions aren't supported in CUDA device code.
- FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
-
- // Respect -fcuda-flush-denormals-to-zero.
- if (getLangOpts().CUDADeviceFlushDenormalsToZero)
- FuncAttrs.addAttribute("nvptx-f32ftz", "true");
- }
-
ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI);
QualType RetTy = FI.getReturnType();
@@ -1876,13 +1944,8 @@ void CodeGenModule::ConstructAttributeList(
RetAttrs.addAttribute(llvm::Attribute::NonNull);
}
- // Attach return attributes.
- if (RetAttrs.hasAttributes()) {
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), llvm::AttributeSet::ReturnIndex, RetAttrs));
- }
-
bool hasUsedSRet = false;
+ SmallVector<llvm::AttributeSet, 4> ArgAttrs(IRFunctionArgs.totalIRArgs());
// Attach attributes to sret.
if (IRFunctionArgs.hasSRetArg()) {
@@ -1891,16 +1954,16 @@ void CodeGenModule::ConstructAttributeList(
hasUsedSRet = true;
if (RetAI.getInReg())
SRETAttrs.addAttribute(llvm::Attribute::InReg);
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), IRFunctionArgs.getSRetArgNo() + 1, SRETAttrs));
+ ArgAttrs[IRFunctionArgs.getSRetArgNo()] =
+ llvm::AttributeSet::get(getLLVMContext(), SRETAttrs);
}
// Attach attributes to inalloca argument.
if (IRFunctionArgs.hasInallocaArg()) {
llvm::AttrBuilder Attrs;
Attrs.addAttribute(llvm::Attribute::InAlloca);
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs));
+ ArgAttrs[IRFunctionArgs.getInallocaArgNo()] =
+ llvm::AttributeSet::get(getLLVMContext(), Attrs);
}
unsigned ArgNo = 0;
@@ -1913,10 +1976,12 @@ void CodeGenModule::ConstructAttributeList(
// Add attribute for padding argument, if necessary.
if (IRFunctionArgs.hasPaddingArg(ArgNo)) {
- if (AI.getPaddingInReg())
- PAL.push_back(llvm::AttributeSet::get(
- getLLVMContext(), IRFunctionArgs.getPaddingArgNo(ArgNo) + 1,
- llvm::Attribute::InReg));
+ if (AI.getPaddingInReg()) {
+ ArgAttrs[IRFunctionArgs.getPaddingArgNo(ArgNo)] =
+ llvm::AttributeSet::get(
+ getLLVMContext(),
+ llvm::AttrBuilder().addAttribute(llvm::Attribute::InReg));
+ }
}
// 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
@@ -2031,17 +2096,15 @@ void CodeGenModule::ConstructAttributeList(
unsigned FirstIRArg, NumIRArgs;
std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
for (unsigned i = 0; i < NumIRArgs; i++)
- PAL.push_back(llvm::AttributeSet::get(getLLVMContext(),
- FirstIRArg + i + 1, Attrs));
+ ArgAttrs[FirstIRArg + i] =
+ llvm::AttributeSet::get(getLLVMContext(), Attrs);
}
}
assert(ArgNo == FI.arg_size());
- if (FuncAttrs.hasAttributes())
- PAL.push_back(llvm::
- AttributeSet::get(getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- FuncAttrs));
+ AttrList = llvm::AttributeList::get(
+ getLLVMContext(), llvm::AttributeSet::get(getLLVMContext(), FuncAttrs),
+ llvm::AttributeSet::get(getLLVMContext(), RetAttrs), ArgAttrs);
}
/// An argument came in as a promoted argument; demote it back to its
@@ -2152,8 +2215,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (IRFunctionArgs.hasSRetArg()) {
auto AI = cast<llvm::Argument>(FnArgs[IRFunctionArgs.getSRetArgNo()]);
AI->setName("agg.result");
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(), AI->getArgNo() + 1,
- llvm::Attribute::NoAlias));
+ AI->addAttr(llvm::Attribute::NoAlias);
}
// Track if we received the parameter as a pointer (indirect, byval, or
@@ -2244,9 +2306,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) {
if (getNonNullAttr(CurCodeDecl, PVD, PVD->getType(),
PVD->getFunctionScopeIndex()))
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NonNull));
+ AI->addAttr(llvm::Attribute::NonNull);
QualType OTy = PVD->getOriginalType();
if (const auto *ArrTy =
@@ -2263,12 +2323,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::AttrBuilder Attrs;
Attrs.addDereferenceableAttr(
getContext().getTypeSizeInChars(ETy).getQuantity()*ArrSize);
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1, Attrs));
+ AI->addAttrs(Attrs);
} else if (getContext().getTargetAddressSpace(ETy) == 0) {
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NonNull));
+ AI->addAttr(llvm::Attribute::NonNull);
}
}
} else if (const auto *ArrTy =
@@ -2278,35 +2335,26 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// we know that it must be nonnull.
if (ArrTy->getSizeModifier() == VariableArrayType::Static &&
!getContext().getTargetAddressSpace(ArrTy->getElementType()))
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NonNull));
+ AI->addAttr(llvm::Attribute::NonNull);
}
const auto *AVAttr = PVD->getAttr<AlignValueAttr>();
if (!AVAttr)
if (const auto *TOTy = dyn_cast<TypedefType>(OTy))
AVAttr = TOTy->getDecl()->getAttr<AlignValueAttr>();
- if (AVAttr) {
+ if (AVAttr) {
llvm::Value *AlignmentValue =
EmitScalarExpr(AVAttr->getAlignment());
llvm::ConstantInt *AlignmentCI =
cast<llvm::ConstantInt>(AlignmentValue);
- unsigned Alignment =
- std::min((unsigned) AlignmentCI->getZExtValue(),
- +llvm::Value::MaximumAlignment);
-
- llvm::AttrBuilder Attrs;
- Attrs.addAlignmentAttr(Alignment);
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1, Attrs));
+ unsigned Alignment = std::min((unsigned)AlignmentCI->getZExtValue(),
+ +llvm::Value::MaximumAlignment);
+ AI->addAttrs(llvm::AttrBuilder().addAlignmentAttr(Alignment));
}
}
if (Arg->getType().isRestrictQualified())
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
- llvm::Attribute::NoAlias));
+ AI->addAttr(llvm::Attribute::NoAlias);
// LLVM expects swifterror parameters to be used in very restricted
// ways. Copy the value into a less-restricted temporary.
@@ -2364,8 +2412,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
Address AddrToStoreInto = Address::invalid();
if (SrcSize <= DstSize) {
- AddrToStoreInto =
- Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy));
+ AddrToStoreInto = Builder.CreateElementBitCast(Ptr, STy);
} else {
AddrToStoreInto =
CreateTempAlloca(STy, Alloca.getAlignment(), "coerce");
@@ -2858,19 +2905,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
llvm::Instruction *Ret;
if (RV) {
- if (CurCodeDecl && SanOpts.has(SanitizerKind::ReturnsNonnullAttribute)) {
- if (auto RetNNAttr = CurCodeDecl->getAttr<ReturnsNonNullAttr>()) {
- SanitizerScope SanScope(this);
- llvm::Value *Cond = Builder.CreateICmpNE(
- RV, llvm::Constant::getNullValue(RV->getType()));
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(EndLoc),
- EmitCheckSourceLocation(RetNNAttr->getLocation()),
- };
- EmitCheck(std::make_pair(Cond, SanitizerKind::ReturnsNonnullAttribute),
- SanitizerHandler::NonnullReturn, StaticData, None);
- }
- }
+ EmitReturnValueCheck(RV);
Ret = Builder.CreateRet(RV);
} else {
Ret = Builder.CreateRetVoid();
@@ -2880,6 +2915,65 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
Ret->setDebugLoc(std::move(RetDbgLoc));
}
+void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV) {
+ // A current decl may not be available when emitting vtable thunks.
+ if (!CurCodeDecl)
+ return;
+
+ ReturnsNonNullAttr *RetNNAttr = nullptr;
+ if (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute))
+ RetNNAttr = CurCodeDecl->getAttr<ReturnsNonNullAttr>();
+
+ if (!RetNNAttr && !requiresReturnValueNullabilityCheck())
+ return;
+
+ // Prefer the returns_nonnull attribute if it's present.
+ SourceLocation AttrLoc;
+ SanitizerMask CheckKind;
+ SanitizerHandler Handler;
+ if (RetNNAttr) {
+ assert(!requiresReturnValueNullabilityCheck() &&
+ "Cannot check nullability and the nonnull attribute");
+ AttrLoc = RetNNAttr->getLocation();
+ CheckKind = SanitizerKind::ReturnsNonnullAttribute;
+ Handler = SanitizerHandler::NonnullReturn;
+ } else {
+ if (auto *DD = dyn_cast<DeclaratorDecl>(CurCodeDecl))
+ if (auto *TSI = DD->getTypeSourceInfo())
+ if (auto FTL = TSI->getTypeLoc().castAs<FunctionTypeLoc>())
+ AttrLoc = FTL.getReturnLoc().findNullabilityLoc();
+ CheckKind = SanitizerKind::NullabilityReturn;
+ Handler = SanitizerHandler::NullabilityReturn;
+ }
+
+ SanitizerScope SanScope(this);
+
+ // Make sure the "return" source location is valid. If we're checking a
+ // nullability annotation, make sure the preconditions for the check are met.
+ llvm::BasicBlock *Check = createBasicBlock("nullcheck");
+ llvm::BasicBlock *NoCheck = createBasicBlock("no.nullcheck");
+ llvm::Value *SLocPtr = Builder.CreateLoad(ReturnLocation, "return.sloc.load");
+ llvm::Value *CanNullCheck = Builder.CreateIsNotNull(SLocPtr);
+ if (requiresReturnValueNullabilityCheck())
+ CanNullCheck =
+ Builder.CreateAnd(CanNullCheck, RetValNullabilityPrecondition);
+ Builder.CreateCondBr(CanNullCheck, Check, NoCheck);
+ EmitBlock(Check);
+
+ // Now do the null check.
+ llvm::Value *Cond = Builder.CreateIsNotNull(RV);
+ llvm::Constant *StaticData[] = {EmitCheckSourceLocation(AttrLoc)};
+ llvm::Value *DynamicData[] = {SLocPtr};
+ EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, DynamicData);
+
+ EmitBlock(NoCheck);
+
+#ifndef NDEBUG
+ // The return location should not be used after the check has been emitted.
+ ReturnLocation = Address::invalid();
+#endif
+}
+
static bool isInAllocaArgument(CGCXXABI &ABI, QualType type) {
const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
return RD && ABI.getRecordArgABI(RD) == CGCXXABI::RAA_DirectInMemory;
@@ -3188,50 +3282,63 @@ void CallArgList::freeArgumentMemory(CodeGenFunction &CGF) const {
void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
SourceLocation ArgLoc,
- const FunctionDecl *FD,
+ AbstractCallee AC,
unsigned ParmNum) {
- if (!SanOpts.has(SanitizerKind::NonnullAttribute) || !FD)
+ if (!AC.getDecl() || !(SanOpts.has(SanitizerKind::NonnullAttribute) ||
+ SanOpts.has(SanitizerKind::NullabilityArg)))
return;
- auto PVD = ParmNum < FD->getNumParams() ? FD->getParamDecl(ParmNum) : nullptr;
+
+ // The param decl may be missing in a variadic function.
+ auto PVD = ParmNum < AC.getNumParams() ? AC.getParamDecl(ParmNum) : nullptr;
unsigned ArgNo = PVD ? PVD->getFunctionScopeIndex() : ParmNum;
- auto NNAttr = getNonNullAttr(FD, PVD, ArgType, ArgNo);
- if (!NNAttr)
+
+ // Prefer the nonnull attribute if it's present.
+ const NonNullAttr *NNAttr = nullptr;
+ if (SanOpts.has(SanitizerKind::NonnullAttribute))
+ NNAttr = getNonNullAttr(AC.getDecl(), PVD, ArgType, ArgNo);
+
+ bool CanCheckNullability = false;
+ if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD) {
+ auto Nullability = PVD->getType()->getNullability(getContext());
+ CanCheckNullability = Nullability &&
+ *Nullability == NullabilityKind::NonNull &&
+ PVD->getTypeSourceInfo();
+ }
+
+ if (!NNAttr && !CanCheckNullability)
return;
+
+ SourceLocation AttrLoc;
+ SanitizerMask CheckKind;
+ SanitizerHandler Handler;
+ if (NNAttr) {
+ AttrLoc = NNAttr->getLocation();
+ CheckKind = SanitizerKind::NonnullAttribute;
+ Handler = SanitizerHandler::NonnullArg;
+ } else {
+ AttrLoc = PVD->getTypeSourceInfo()->getTypeLoc().findNullabilityLoc();
+ CheckKind = SanitizerKind::NullabilityArg;
+ Handler = SanitizerHandler::NullabilityArg;
+ }
+
SanitizerScope SanScope(this);
assert(RV.isScalar());
llvm::Value *V = RV.getScalarVal();
llvm::Value *Cond =
Builder.CreateICmpNE(V, llvm::Constant::getNullValue(V->getType()));
llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(ArgLoc),
- EmitCheckSourceLocation(NNAttr->getLocation()),
+ EmitCheckSourceLocation(ArgLoc), EmitCheckSourceLocation(AttrLoc),
llvm::ConstantInt::get(Int32Ty, ArgNo + 1),
};
- EmitCheck(std::make_pair(Cond, SanitizerKind::NonnullAttribute),
- SanitizerHandler::NonnullArg, StaticData, None);
+ EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None);
}
void CodeGenFunction::EmitCallArgs(
CallArgList &Args, ArrayRef<QualType> ArgTypes,
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
- const FunctionDecl *CalleeDecl, unsigned ParamsToSkip,
- EvaluationOrder Order) {
+ AbstractCallee AC, unsigned ParamsToSkip, EvaluationOrder Order) {
assert((int)ArgTypes.size() == (ArgRange.end() - ArgRange.begin()));
- auto MaybeEmitImplicitObjectSize = [&](unsigned I, const Expr *Arg) {
- if (CalleeDecl == nullptr || I >= CalleeDecl->getNumParams())
- return;
- auto *PS = CalleeDecl->getParamDecl(I)->getAttr<PassObjectSizeAttr>();
- if (PS == nullptr)
- return;
-
- const auto &Context = getContext();
- auto SizeTy = Context.getSizeType();
- auto T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
- llvm::Value *V = evaluateOrEmitBuiltinObjectSize(Arg, PS->getType(), T);
- Args.add(RValue::get(V), SizeTy);
- };
-
// We *have* to evaluate arguments from right to left in the MS C++ ABI,
// because arguments are destroyed left to right in the callee. As a special
// case, there are certain language constructs that require left-to-right
@@ -3242,6 +3349,27 @@ void CodeGenFunction::EmitCallArgs(
? Order == EvaluationOrder::ForceLeftToRight
: Order != EvaluationOrder::ForceRightToLeft;
+ auto MaybeEmitImplicitObjectSize = [&](unsigned I, const Expr *Arg,
+ RValue EmittedArg) {
+ if (!AC.hasFunctionDecl() || I >= AC.getNumParams())
+ return;
+ auto *PS = AC.getParamDecl(I)->getAttr<PassObjectSizeAttr>();
+ if (PS == nullptr)
+ return;
+
+ const auto &Context = getContext();
+ auto SizeTy = Context.getSizeType();
+ auto T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
+ assert(EmittedArg.getScalarVal() && "We emitted nothing for the arg?");
+ llvm::Value *V = evaluateOrEmitBuiltinObjectSize(Arg, PS->getType(), T,
+ EmittedArg.getScalarVal());
+ Args.add(RValue::get(V), SizeTy);
+ // If we're emitting args in reverse, be sure to do so with
+ // pass_object_size, as well.
+ if (!LeftToRight)
+ std::swap(Args.back(), *(&Args.back() - 1));
+ };
+
// Insert a stack save if we're going to need any inalloca args.
bool HasInAllocaArgs = false;
if (CGM.getTarget().getCXXABI().isMicrosoft()) {
@@ -3259,11 +3387,28 @@ void CodeGenFunction::EmitCallArgs(
for (unsigned I = 0, E = ArgTypes.size(); I != E; ++I) {
unsigned Idx = LeftToRight ? I : E - I - 1;
CallExpr::const_arg_iterator Arg = ArgRange.begin() + Idx;
- if (!LeftToRight) MaybeEmitImplicitObjectSize(Idx, *Arg);
+ unsigned InitialArgSize = Args.size();
+ // If *Arg is an ObjCIndirectCopyRestoreExpr, check that either the types of
+ // the argument and parameter match or the objc method is parameterized.
+ assert((!isa<ObjCIndirectCopyRestoreExpr>(*Arg) ||
+ getContext().hasSameUnqualifiedType((*Arg)->getType(),
+ ArgTypes[Idx]) ||
+ (isa<ObjCMethodDecl>(AC.getDecl()) &&
+ isObjCMethodWithTypeParams(cast<ObjCMethodDecl>(AC.getDecl())))) &&
+ "Argument and parameter types don't match");
EmitCallArg(Args, *Arg, ArgTypes[Idx]);
- EmitNonNullArgCheck(Args.back().RV, ArgTypes[Idx], (*Arg)->getExprLoc(),
- CalleeDecl, ParamsToSkip + Idx);
- if (LeftToRight) MaybeEmitImplicitObjectSize(Idx, *Arg);
+ // In particular, we depend on it being the last arg in Args, and the
+ // objectsize bits depend on there only being one arg if !LeftToRight.
+ assert(InitialArgSize + 1 == Args.size() &&
+ "The code below depends on only adding one arg per EmitCallArg");
+ (void)InitialArgSize;
+ RValue RVArg = Args.back().RV;
+ EmitNonNullArgCheck(RVArg, ArgTypes[Idx], (*Arg)->getExprLoc(), AC,
+ ParamsToSkip + Idx);
+ // @llvm.objectsize should never have side-effects and shouldn't need
+ // destruction/cleanups, so we can safely "emit" it after its arg,
+ // regardless of right-to-leftness
+ MaybeEmitImplicitObjectSize(Idx, *Arg, RVArg);
}
if (!LeftToRight) {
@@ -3311,7 +3456,6 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
if (const ObjCIndirectCopyRestoreExpr *CRE
= dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) {
assert(getLangOpts().ObjCAutoRefCount);
- assert(getContext().hasSameUnqualifiedType(E->getType(), type));
return emitWritebackArg(*this, args, CRE);
}
@@ -3571,12 +3715,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Address ArgMemory = Address::invalid();
const llvm::StructLayout *ArgMemoryLayout = nullptr;
if (llvm::StructType *ArgStruct = CallInfo.getArgStruct()) {
- ArgMemoryLayout = CGM.getDataLayout().getStructLayout(ArgStruct);
+ const llvm::DataLayout &DL = CGM.getDataLayout();
+ ArgMemoryLayout = DL.getStructLayout(ArgStruct);
llvm::Instruction *IP = CallArgs.getStackBase();
llvm::AllocaInst *AI;
if (IP) {
IP = IP->getNextNode();
- AI = new llvm::AllocaInst(ArgStruct, "argmem", IP);
+ AI = new llvm::AllocaInst(ArgStruct, DL.getAllocaAddrSpace(),
+ "argmem", IP);
} else {
AI = CreateTempAlloca(ArgStruct, "argmem");
}
@@ -3675,7 +3821,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
assert(NumIRArgs == 1);
if (RV.isScalar() || RV.isComplex()) {
// Make a temporary alloca to pass the argument.
- Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign());
+ Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(),
+ "indirect-arg-temp", false);
IRCallArgs[FirstIRArg] = Addr.getPointer();
LValue argLV = MakeAddrLValue(Addr, I->Ty);
@@ -3704,7 +3851,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
< Align.getQuantity()) ||
(ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) {
// Create an aligned temporary, and copy to it.
- Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign());
+ Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(),
+ "byval-temp", false);
IRCallArgs[FirstIRArg] = AI.getPointer();
EmitAggregateCopy(AI, Addr, I->Ty, RV.isVolatileQualified());
} else {
@@ -3972,13 +4120,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Compute the calling convention and attributes.
unsigned CallingConv;
- CodeGen::AttributeListType AttributeList;
+ llvm::AttributeList Attrs;
CGM.ConstructAttributeList(CalleePtr->getName(), CallInfo,
- Callee.getAbstractInfo(),
- AttributeList, CallingConv,
+ Callee.getAbstractInfo(), Attrs, CallingConv,
/*AttrOnCallSite=*/true);
- llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(),
- AttributeList);
// Apply some call-site-specific attributes.
// TODO: work this into building the attribute set.
@@ -3989,15 +4134,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
!(Callee.getAbstractInfo().getCalleeDecl() &&
Callee.getAbstractInfo().getCalleeDecl()->hasAttr<NoInlineAttr>())) {
Attrs =
- Attrs.addAttribute(getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
+ Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
llvm::Attribute::AlwaysInline);
}
// Disable inlining inside SEH __try blocks.
if (isSEHTryScope()) {
Attrs =
- Attrs.addAttribute(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
+ Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoInline);
}
@@ -4014,7 +4158,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
CannotThrow = true;
} else {
// Otherwise, nounwind call sites will never throw.
- CannotThrow = Attrs.hasAttribute(llvm::AttributeSet::FunctionIndex,
+ CannotThrow = Attrs.hasAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoUnwind);
}
llvm::BasicBlock *InvokeDest = CannotThrow ? nullptr : getInvokeDest();
@@ -4127,6 +4271,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Builder.CreateStore(elt, eltAddr);
}
// FALLTHROUGH
+ LLVM_FALLTHROUGH;
}
case ABIArgInfo::InAlloca:
@@ -4210,6 +4355,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(Alignment);
EmitAlignmentAssumption(Ret.getScalarVal(), AlignmentCI->getZExtValue(),
OffsetValue);
+ } else if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) {
+ llvm::Value *ParamVal =
+ CallArgs[AA->getParamIndex() - 1].RV.getScalarVal();
+ EmitAlignmentAssumption(Ret.getScalarVal(), ParamVal);
}
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h
index 031ce83..7e10407 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h
@@ -25,10 +25,10 @@
#include "ABIInfo.h"
namespace llvm {
- class AttributeSet;
- class Function;
- class Type;
- class Value;
+class AttributeList;
+class Function;
+class Type;
+class Value;
}
namespace clang {
@@ -39,28 +39,27 @@ namespace clang {
class VarDecl;
namespace CodeGen {
- typedef SmallVector<llvm::AttributeSet, 8> AttributeListType;
- /// Abstract information about a function or function prototype.
- class CGCalleeInfo {
- /// \brief The function prototype of the callee.
- const FunctionProtoType *CalleeProtoTy;
- /// \brief The function declaration of the callee.
- const Decl *CalleeDecl;
-
- public:
- explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl(nullptr) {}
- CGCalleeInfo(const FunctionProtoType *calleeProtoTy, const Decl *calleeDecl)
- : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {}
- CGCalleeInfo(const FunctionProtoType *calleeProtoTy)
- : CalleeProtoTy(calleeProtoTy), CalleeDecl(nullptr) {}
- CGCalleeInfo(const Decl *calleeDecl)
- : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {}
-
- const FunctionProtoType *getCalleeFunctionProtoType() const {
- return CalleeProtoTy;
- }
- const Decl *getCalleeDecl() const { return CalleeDecl; }
+/// Abstract information about a function or function prototype.
+class CGCalleeInfo {
+ /// \brief The function prototype of the callee.
+ const FunctionProtoType *CalleeProtoTy;
+ /// \brief The function declaration of the callee.
+ const Decl *CalleeDecl;
+
+public:
+ explicit CGCalleeInfo() : CalleeProtoTy(nullptr), CalleeDecl(nullptr) {}
+ CGCalleeInfo(const FunctionProtoType *calleeProtoTy, const Decl *calleeDecl)
+ : CalleeProtoTy(calleeProtoTy), CalleeDecl(calleeDecl) {}
+ CGCalleeInfo(const FunctionProtoType *calleeProtoTy)
+ : CalleeProtoTy(calleeProtoTy), CalleeDecl(nullptr) {}
+ CGCalleeInfo(const Decl *calleeDecl)
+ : CalleeProtoTy(nullptr), CalleeDecl(calleeDecl) {}
+
+ const FunctionProtoType *getCalleeFunctionProtoType() const {
+ return CalleeProtoTy;
+ }
+ const Decl *getCalleeDecl() const { return CalleeDecl; }
};
/// All available information about a concrete callee.
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp
index 05d0567..50d702c 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp
@@ -129,14 +129,14 @@ Address
CodeGenFunction::EmitCXXMemberDataPointerAddress(const Expr *E, Address base,
llvm::Value *memberPtr,
const MemberPointerType *memberPtrType,
- AlignmentSource *alignSource) {
+ LValueBaseInfo *BaseInfo) {
// Ask the ABI to compute the actual address.
llvm::Value *ptr =
CGM.getCXXABI().EmitMemberDataPointerAddress(*this, E, base,
memberPtr, memberPtrType);
QualType memberType = memberPtrType->getPointeeType();
- CharUnits memberAlign = getNaturalTypeAlignment(memberType, alignSource);
+ CharUnits memberAlign = getNaturalTypeAlignment(memberType, BaseInfo);
memberAlign =
CGM.getDynamicOffsetAlignment(base.getAlignment(),
memberPtrType->getClass()->getAsCXXRecordDecl(),
@@ -309,8 +309,10 @@ Address CodeGenFunction::GetAddressOfBaseClass(
// just do a bitcast; null checks are unnecessary.
if (NonVirtualOffset.isZero() && !VBase) {
if (sanitizePerformTypeCheck()) {
+ SanitizerSet SkippedChecks;
+ SkippedChecks.set(SanitizerKind::Null, !NullCheckValue);
EmitTypeCheck(TCK_Upcast, Loc, Value.getPointer(),
- DerivedTy, DerivedAlign, !NullCheckValue);
+ DerivedTy, DerivedAlign, SkippedChecks);
}
return Builder.CreateBitCast(Value, BasePtrTy);
}
@@ -331,8 +333,10 @@ Address CodeGenFunction::GetAddressOfBaseClass(
}
if (sanitizePerformTypeCheck()) {
+ SanitizerSet SkippedChecks;
+ SkippedChecks.set(SanitizerKind::Null, true);
EmitTypeCheck(VBase ? TCK_UpcastToVirtualBase : TCK_Upcast, Loc,
- Value.getPointer(), DerivedTy, DerivedAlign, true);
+ Value.getPointer(), DerivedTy, DerivedAlign, SkippedChecks);
}
// Compute the virtual offset.
@@ -685,7 +689,8 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS,
/// complete-to-base constructor delegation optimization, i.e.
/// emitting the complete constructor as a simple call to the base
/// constructor.
-static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor) {
+bool CodeGenFunction::IsConstructorDelegationValid(
+ const CXXConstructorDecl *Ctor) {
// Currently we disable the optimization for classes with virtual
// bases because (1) the addresses of parameter variables need to be
@@ -1131,10 +1136,11 @@ namespace {
RHS = EC->getSubExpr();
if (!RHS)
return nullptr;
- MemberExpr *ME2 = dyn_cast<MemberExpr>(RHS);
- if (dyn_cast<FieldDecl>(ME2->getMemberDecl()) != Field)
- return nullptr;
- return Field;
+ if (MemberExpr *ME2 = dyn_cast<MemberExpr>(RHS)) {
+ if (ME2->getMemberDecl() == Field)
+ return Field;
+ }
+ return nullptr;
} else if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(S)) {
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MCE->getCalleeDecl());
if (!(MD && isMemcpyEquivalentSpecialMember(MD)))
@@ -1384,6 +1390,20 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl());
CXXDtorType DtorType = CurGD.getDtorType();
+ // For an abstract class, non-base destructors are never used (and can't
+ // be emitted in general, because vbase dtors may not have been validated
+ // by Sema), but the Itanium ABI doesn't make them optional and Clang may
+ // in fact emit references to them from other compilations, so emit them
+ // as functions containing a trap instruction.
+ if (DtorType != Dtor_Base && Dtor->getParent()->isAbstract()) {
+ llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
+ TrapCall->setDoesNotReturn();
+ TrapCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
+ return;
+ }
+
Stmt *Body = Dtor->getBody();
if (Body)
incrementProfileCounter(Body);
@@ -1416,9 +1436,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// we'd introduce *two* handler blocks. In the Microsoft ABI, we
// always delegate because we might not have a definition in this TU.
switch (DtorType) {
- case Dtor_Comdat:
- llvm_unreachable("not expecting a COMDAT");
-
+ case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT");
case Dtor_Deleting: llvm_unreachable("already handled deleting case");
case Dtor_Complete:
@@ -1433,7 +1451,9 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
/*Delegating=*/false, LoadCXXThisAddress());
break;
}
+
// Fallthrough: act like we're in the base variant.
+ LLVM_FALLTHROUGH;
case Dtor_Base:
assert(Body);
@@ -1950,7 +1970,11 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
// Add the rest of the user-supplied arguments.
const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
- EmitCallArgs(Args, FPT, E->arguments(), E->getConstructor());
+ EvaluationOrder Order = E->isListInitialization()
+ ? EvaluationOrder::ForceLeftToRight
+ : EvaluationOrder::Default;
+ EmitCallArgs(Args, FPT, E->arguments(), E->getConstructor(),
+ /*ParamsToSkip*/ 0, Order);
EmitCXXConstructorCall(D, Type, ForVirtualBase, Delegating, This, Args);
}
@@ -1970,7 +1994,7 @@ static bool canEmitDelegateCallArgs(CodeGenFunction &CGF,
// Likewise if they're inalloca.
const CGFunctionInfo &Info =
- CGF.CGM.getTypes().arrangeCXXConstructorCall(Args, Ctor, Type, 0);
+ CGF.CGM.getTypes().arrangeCXXConstructorCall(Args, Ctor, Type, 0, 0);
if (Info.usesInAlloca())
return false;
}
@@ -2012,10 +2036,11 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
return;
}
+ bool PassPrototypeArgs = true;
// Check whether we can actually emit the constructor before trying to do so.
if (auto Inherited = D->getInheritedConstructor()) {
- if (getTypes().inheritingCtorHasParams(Inherited, Type) &&
- !canEmitDelegateCallArgs(*this, D, Type, Args)) {
+ PassPrototypeArgs = getTypes().inheritingCtorHasParams(Inherited, Type);
+ if (PassPrototypeArgs && !canEmitDelegateCallArgs(*this, D, Type, Args)) {
EmitInlinedInheritingCXXConstructorCall(D, Type, ForVirtualBase,
Delegating, Args);
return;
@@ -2023,14 +2048,15 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
}
// Insert any ABI-specific implicit constructor arguments.
- unsigned ExtraArgs = CGM.getCXXABI().addImplicitConstructorArgs(
- *this, D, Type, ForVirtualBase, Delegating, Args);
+ CGCXXABI::AddedStructorArgs ExtraArgs =
+ CGM.getCXXABI().addImplicitConstructorArgs(*this, D, Type, ForVirtualBase,
+ Delegating, Args);
// Emit the call.
llvm::Constant *CalleePtr =
CGM.getAddrOfCXXStructor(D, getFromCtorType(Type));
- const CGFunctionInfo &Info =
- CGM.getTypes().arrangeCXXConstructorCall(Args, D, Type, ExtraArgs);
+ const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall(
+ Args, D, Type, ExtraArgs.Prefix, ExtraArgs.Suffix, PassPrototypeArgs);
CGCallee Callee = CGCallee::forDirect(CalleePtr, D);
EmitCall(Info, Callee, ReturnValueSlot(), Args);
@@ -2102,7 +2128,9 @@ void CodeGenFunction::EmitInheritedCXXConstructorCall(
void CodeGenFunction::EmitInlinedInheritingCXXConstructorCall(
const CXXConstructorDecl *Ctor, CXXCtorType CtorType, bool ForVirtualBase,
bool Delegating, CallArgList &Args) {
- InlinedInheritingConstructorScope Scope(*this, GlobalDecl(Ctor, CtorType));
+ GlobalDecl GD(Ctor, CtorType);
+ InlinedInheritingConstructorScope Scope(*this, GD);
+ ApplyInlineDebugLocation DebugScope(*this, GD);
// Save the arguments to be passed to the inherited constructor.
CXXInheritedCtorInitExprArgs = Args;
@@ -2688,79 +2716,6 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
cast<llvm::PointerType>(VTable->getType())->getElementType());
}
-bool
-CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base,
- const CXXMethodDecl *MD) {
- // When building with -fapple-kext, all calls must go through the vtable since
- // the kernel linker can do runtime patching of vtables.
- if (getLangOpts().AppleKext)
- return false;
-
- // If the member function is marked 'final', we know that it can't be
- // overridden and can therefore devirtualize it unless it's pure virtual.
- if (MD->hasAttr<FinalAttr>())
- return !MD->isPure();
-
- // If the base expression (after skipping derived-to-base conversions) is a
- // class prvalue, then we can devirtualize.
- Base = Base->getBestDynamicClassTypeExpr();
- if (Base->isRValue() && Base->getType()->isRecordType())
- return true;
-
- // If we don't even know what we would call, we can't devirtualize.
- const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
- if (!BestDynamicDecl)
- return false;
-
- // There may be a method corresponding to MD in a derived class.
- const CXXMethodDecl *DevirtualizedMethod =
- MD->getCorrespondingMethodInClass(BestDynamicDecl);
-
- // If that method is pure virtual, we can't devirtualize. If this code is
- // reached, the result would be UB, not a direct call to the derived class
- // function, and we can't assume the derived class function is defined.
- if (DevirtualizedMethod->isPure())
- return false;
-
- // If that method is marked final, we can devirtualize it.
- if (DevirtualizedMethod->hasAttr<FinalAttr>())
- return true;
-
- // Similarly, if the class itself is marked 'final' it can't be overridden
- // and we can therefore devirtualize the member function call.
- if (BestDynamicDecl->hasAttr<FinalAttr>())
- return true;
-
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- // This is a record decl. We know the type and can devirtualize it.
- return VD->getType()->isRecordType();
- }
-
- return false;
- }
-
- // We can devirtualize calls on an object accessed by a class member access
- // expression, since by C++11 [basic.life]p6 we know that it can't refer to
- // a derived class object constructed in the same location.
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base))
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl()))
- return VD->getType()->isRecordType();
-
- // Likewise for calls on an object accessed by a (non-reference) pointer to
- // member access.
- if (auto *BO = dyn_cast<BinaryOperator>(Base)) {
- if (BO->isPtrMemOp()) {
- auto *MPT = BO->getRHS()->getType()->castAs<MemberPointerType>();
- if (MPT->getPointeeType()->isRecordType())
- return true;
- }
- }
-
- // We can't devirtualize the call.
- return false;
-}
-
void CodeGenFunction::EmitForwardingCallToLambda(
const CXXMethodDecl *callOperator,
CallArgList &callArgs) {
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp
index 3666858..b5453bc 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp
@@ -51,8 +51,7 @@ DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
if (rv.isComplex()) {
CodeGenFunction::ComplexPairTy V = rv.getComplexVal();
llvm::Type *ComplexTy =
- llvm::StructType::get(V.first->getType(), V.second->getType(),
- (void*) nullptr);
+ llvm::StructType::get(V.first->getType(), V.second->getType());
Address addr = CGF.CreateDefaultAlignTempAlloca(ComplexTy, "saved-complex");
CGF.Builder.CreateStore(V.first,
CGF.Builder.CreateStructGEP(addr, 0, CharUnits()));
@@ -418,11 +417,15 @@ void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) {
}
/// Pops cleanup blocks until the given savepoint is reached.
-void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) {
+void CodeGenFunction::PopCleanupBlocks(
+ EHScopeStack::stable_iterator Old,
+ std::initializer_list<llvm::Value **> ValuesToReload) {
assert(Old.isValid());
+ bool HadBranches = false;
while (EHStack.stable_begin() != Old) {
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
+ HadBranches |= Scope.hasBranches();
// As long as Old strictly encloses the scope's enclosing normal
// cleanup, we're going to emit another normal cleanup which
@@ -432,14 +435,48 @@ void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) {
PopCleanupBlock(FallThroughIsBranchThrough);
}
+
+ // If we didn't have any branches, the insertion point before cleanups must
+ // dominate the current insertion point and we don't need to reload any
+ // values.
+ if (!HadBranches)
+ return;
+
+ // Spill and reload all values that the caller wants to be live at the current
+ // insertion point.
+ for (llvm::Value **ReloadedValue : ValuesToReload) {
+ auto *Inst = dyn_cast_or_null<llvm::Instruction>(*ReloadedValue);
+ if (!Inst)
+ continue;
+
+ // Don't spill static allocas, they dominate all cleanups. These are created
+ // by binding a reference to a local variable or temporary.
+ auto *AI = dyn_cast<llvm::AllocaInst>(Inst);
+ if (AI && AI->isStaticAlloca())
+ continue;
+
+ Address Tmp =
+ CreateDefaultAlignTempAlloca(Inst->getType(), "tmp.exprcleanup");
+
+ // Find an insertion point after Inst and spill it to the temporary.
+ llvm::BasicBlock::iterator InsertBefore;
+ if (auto *Invoke = dyn_cast<llvm::InvokeInst>(Inst))
+ InsertBefore = Invoke->getNormalDest()->getFirstInsertionPt();
+ else
+ InsertBefore = std::next(Inst->getIterator());
+ CGBuilderTy(CGM, &*InsertBefore).CreateStore(Inst, Tmp);
+
+ // Reload the value at the current insertion point.
+ *ReloadedValue = Builder.CreateLoad(Tmp);
+ }
}
/// Pops cleanup blocks until the given savepoint is reached, then add the
/// cleanups from the given savepoint in the lifetime-extended cleanups stack.
-void
-CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old,
- size_t OldLifetimeExtendedSize) {
- PopCleanupBlocks(Old);
+void CodeGenFunction::PopCleanupBlocks(
+ EHScopeStack::stable_iterator Old, size_t OldLifetimeExtendedSize,
+ std::initializer_list<llvm::Value **> ValuesToReload) {
+ PopCleanupBlocks(Old, ValuesToReload);
// Move our deferred cleanups onto the EH stack.
for (size_t I = OldLifetimeExtendedSize,
@@ -578,7 +615,7 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
llvm::SwitchInst *si = cast<llvm::SwitchInst>(use.getUser());
if (si->getNumCases() == 1 && si->getDefaultDest() == unreachableBB) {
// Replace the switch with a branch.
- llvm::BranchInst::Create(si->case_begin().getCaseSuccessor(), si);
+ llvm::BranchInst::Create(si->case_begin()->getCaseSuccessor(), si);
// The switch operand is a load from the cleanup-dest alloca.
llvm::LoadInst *condition = cast<llvm::LoadInst>(si->getCondition());
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp
index 2fdb127..a65faa6 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCoroutine.cpp
@@ -11,29 +11,70 @@
//
//===----------------------------------------------------------------------===//
+#include "CGCleanup.h"
#include "CodeGenFunction.h"
+#include "llvm/ADT/ScopeExit.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtVisitor.h"
using namespace clang;
using namespace CodeGen;
-namespace clang {
-namespace CodeGen {
+using llvm::Value;
+using llvm::BasicBlock;
+
+namespace {
+enum class AwaitKind { Init, Normal, Yield, Final };
+static constexpr llvm::StringLiteral AwaitKindStr[] = {"init", "await", "yield",
+ "final"};
+}
+
+struct clang::CodeGen::CGCoroData {
+ // What is the current await expression kind and how many
+ // await/yield expressions were encountered so far.
+ // These are used to generate pretty labels for await expressions in LLVM IR.
+ AwaitKind CurrentAwaitKind = AwaitKind::Init;
+ unsigned AwaitNum = 0;
+ unsigned YieldNum = 0;
+
+ // How many co_return statements are in the coroutine. Used to decide whether
+ // we need to add co_return; equivalent at the end of the user authored body.
+ unsigned CoreturnCount = 0;
+
+ // A branch to this block is emitted when coroutine needs to suspend.
+ llvm::BasicBlock *SuspendBB = nullptr;
+
+ // Stores the jump destination just before the coroutine memory is freed.
+ // This is the destination that every suspend point jumps to for the cleanup
+ // branch.
+ CodeGenFunction::JumpDest CleanupJD;
+
+ // Stores the jump destination just before the final suspend. The co_return
+ // statements jumps to this point after calling return_xxx promise member.
+ CodeGenFunction::JumpDest FinalJD;
-struct CGCoroData {
// Stores the llvm.coro.id emitted in the function so that we can supply it
// as the first argument to coro.begin, coro.alloc and coro.free intrinsics.
// Note: llvm.coro.id returns a token that cannot be directly expressed in a
// builtin.
llvm::CallInst *CoroId = nullptr;
+
+ // Stores the llvm.coro.begin emitted in the function so that we can replace
+ // all coro.frame intrinsics with direct SSA value of coro.begin that returns
+ // the address of the coroutine frame of the current coroutine.
+ llvm::CallInst *CoroBegin = nullptr;
+
+ // Stores the last emitted coro.free for the deallocate expressions, we use it
+ // to wrap dealloc code with if(auto mem = coro.free) dealloc(mem).
+ llvm::CallInst *LastCoroFree = nullptr;
+
// If coro.id came from the builtin, remember the expression to give better
// diagnostic. If CoroIdExpr is nullptr, the coro.id was created by
// EmitCoroutineBody.
CallExpr const *CoroIdExpr = nullptr;
};
-}
-}
+// Defining these here allows to keep CGCoroData private to this file.
clang::CodeGen::CodeGenFunction::CGCoroInfo::CGCoroInfo() {}
CodeGenFunction::CGCoroInfo::~CGCoroInfo() {}
@@ -59,19 +100,528 @@ static void createCoroData(CodeGenFunction &CGF,
CurCoro.Data->CoroIdExpr = CoroIdExpr;
}
+// Synthesize a pretty name for a suspend point.
+static SmallString<32> buildSuspendPrefixStr(CGCoroData &Coro, AwaitKind Kind) {
+ unsigned No = 0;
+ switch (Kind) {
+ case AwaitKind::Init:
+ case AwaitKind::Final:
+ break;
+ case AwaitKind::Normal:
+ No = ++Coro.AwaitNum;
+ break;
+ case AwaitKind::Yield:
+ No = ++Coro.YieldNum;
+ break;
+ }
+ SmallString<32> Prefix(AwaitKindStr[static_cast<unsigned>(Kind)]);
+ if (No > 1) {
+ Twine(No).toVector(Prefix);
+ }
+ return Prefix;
+}
+
+// Emit suspend expression which roughly looks like:
+//
+// auto && x = CommonExpr();
+// if (!x.await_ready()) {
+// llvm_coro_save();
+// x.await_suspend(...); (*)
+// llvm_coro_suspend(); (**)
+// }
+// x.await_resume();
+//
+// where the result of the entire expression is the result of x.await_resume()
+//
+// (*) If x.await_suspend return type is bool, it allows to veto a suspend:
+// if (x.await_suspend(...))
+// llvm_coro_suspend();
+//
+// (**) llvm_coro_suspend() encodes three possible continuations as
+// a switch instruction:
+//
+// %where-to = call i8 @llvm.coro.suspend(...)
+// switch i8 %where-to, label %coro.ret [ ; jump to epilogue to suspend
+// i8 0, label %yield.ready ; go here when resumed
+// i8 1, label %yield.cleanup ; go here when destroyed
+// ]
+//
+// See llvm's docs/Coroutines.rst for more details.
+//
+namespace {
+ struct LValueOrRValue {
+ LValue LV;
+ RValue RV;
+ };
+}
+static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Coro,
+ CoroutineSuspendExpr const &S,
+ AwaitKind Kind, AggValueSlot aggSlot,
+ bool ignoreResult, bool forLValue) {
+ auto *E = S.getCommonExpr();
+
+ auto Binder =
+ CodeGenFunction::OpaqueValueMappingData::bind(CGF, S.getOpaqueValue(), E);
+ auto UnbindOnExit = llvm::make_scope_exit([&] { Binder.unbind(CGF); });
+
+ auto Prefix = buildSuspendPrefixStr(Coro, Kind);
+ BasicBlock *ReadyBlock = CGF.createBasicBlock(Prefix + Twine(".ready"));
+ BasicBlock *SuspendBlock = CGF.createBasicBlock(Prefix + Twine(".suspend"));
+ BasicBlock *CleanupBlock = CGF.createBasicBlock(Prefix + Twine(".cleanup"));
+
+ // If expression is ready, no need to suspend.
+ CGF.EmitBranchOnBoolExpr(S.getReadyExpr(), ReadyBlock, SuspendBlock, 0);
+
+ // Otherwise, emit suspend logic.
+ CGF.EmitBlock(SuspendBlock);
+
+ auto &Builder = CGF.Builder;
+ llvm::Function *CoroSave = CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_save);
+ auto *NullPtr = llvm::ConstantPointerNull::get(CGF.CGM.Int8PtrTy);
+ auto *SaveCall = Builder.CreateCall(CoroSave, {NullPtr});
+
+ auto *SuspendRet = CGF.EmitScalarExpr(S.getSuspendExpr());
+ if (SuspendRet != nullptr) {
+ // Veto suspension if requested by bool returning await_suspend.
+ assert(SuspendRet->getType()->isIntegerTy(1) &&
+ "Sema should have already checked that it is void or bool");
+ BasicBlock *RealSuspendBlock =
+ CGF.createBasicBlock(Prefix + Twine(".suspend.bool"));
+ CGF.Builder.CreateCondBr(SuspendRet, RealSuspendBlock, ReadyBlock);
+ SuspendBlock = RealSuspendBlock;
+ CGF.EmitBlock(RealSuspendBlock);
+ }
+
+ // Emit the suspend point.
+ const bool IsFinalSuspend = (Kind == AwaitKind::Final);
+ llvm::Function *CoroSuspend =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::coro_suspend);
+ auto *SuspendResult = Builder.CreateCall(
+ CoroSuspend, {SaveCall, Builder.getInt1(IsFinalSuspend)});
+
+ // Create a switch capturing three possible continuations.
+ auto *Switch = Builder.CreateSwitch(SuspendResult, Coro.SuspendBB, 2);
+ Switch->addCase(Builder.getInt8(0), ReadyBlock);
+ Switch->addCase(Builder.getInt8(1), CleanupBlock);
+
+ // Emit cleanup for this suspend point.
+ CGF.EmitBlock(CleanupBlock);
+ CGF.EmitBranchThroughCleanup(Coro.CleanupJD);
+
+ // Emit await_resume expression.
+ CGF.EmitBlock(ReadyBlock);
+ LValueOrRValue Res;
+ if (forLValue)
+ Res.LV = CGF.EmitLValue(S.getResumeExpr());
+ else
+ Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
+ return Res;
+}
+
+RValue CodeGenFunction::EmitCoawaitExpr(const CoawaitExpr &E,
+ AggValueSlot aggSlot,
+ bool ignoreResult) {
+ return emitSuspendExpression(*this, *CurCoro.Data, E,
+ CurCoro.Data->CurrentAwaitKind, aggSlot,
+ ignoreResult, /*forLValue*/false).RV;
+}
+RValue CodeGenFunction::EmitCoyieldExpr(const CoyieldExpr &E,
+ AggValueSlot aggSlot,
+ bool ignoreResult) {
+ return emitSuspendExpression(*this, *CurCoro.Data, E, AwaitKind::Yield,
+ aggSlot, ignoreResult, /*forLValue*/false).RV;
+}
+
+void CodeGenFunction::EmitCoreturnStmt(CoreturnStmt const &S) {
+ ++CurCoro.Data->CoreturnCount;
+ EmitStmt(S.getPromiseCall());
+ EmitBranchThroughCleanup(CurCoro.Data->FinalJD);
+}
+
+
+#ifndef NDEBUG
+static QualType getCoroutineSuspendExprReturnType(const ASTContext &Ctx,
+ const CoroutineSuspendExpr *E) {
+ const auto *RE = E->getResumeExpr();
+ // Is it possible for RE to be a CXXBindTemporaryExpr wrapping
+ // a MemberCallExpr?
+ assert(isa<CallExpr>(RE) && "unexpected suspend expression type");
+ return cast<CallExpr>(RE)->getCallReturnType(Ctx);
+}
+#endif
+
+LValue
+CodeGenFunction::EmitCoawaitLValue(const CoawaitExpr *E) {
+ assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
+ "Can't have a scalar return unless the return type is a "
+ "reference type!");
+ return emitSuspendExpression(*this, *CurCoro.Data, *E,
+ CurCoro.Data->CurrentAwaitKind, AggValueSlot::ignored(),
+ /*ignoreResult*/false, /*forLValue*/true).LV;
+}
+
+LValue
+CodeGenFunction::EmitCoyieldLValue(const CoyieldExpr *E) {
+ assert(getCoroutineSuspendExprReturnType(getContext(), E)->isReferenceType() &&
+ "Can't have a scalar return unless the return type is a "
+ "reference type!");
+ return emitSuspendExpression(*this, *CurCoro.Data, *E,
+ AwaitKind::Yield, AggValueSlot::ignored(),
+ /*ignoreResult*/false, /*forLValue*/true).LV;
+}
+
+// Hunts for the parameter reference in the parameter copy/move declaration.
+namespace {
+struct GetParamRef : public StmtVisitor<GetParamRef> {
+public:
+ DeclRefExpr *Expr = nullptr;
+ GetParamRef() {}
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ assert(Expr == nullptr && "multilple declref in param move");
+ Expr = E;
+ }
+ void VisitStmt(Stmt *S) {
+ for (auto *C : S->children()) {
+ if (C)
+ Visit(C);
+ }
+ }
+};
+}
+
+// This class replaces references to parameters to their copies by changing
+// the addresses in CGF.LocalDeclMap and restoring back the original values in
+// its destructor.
+
+namespace {
+ struct ParamReferenceReplacerRAII {
+ CodeGenFunction::DeclMapTy SavedLocals;
+ CodeGenFunction::DeclMapTy& LocalDeclMap;
+
+ ParamReferenceReplacerRAII(CodeGenFunction::DeclMapTy &LocalDeclMap)
+ : LocalDeclMap(LocalDeclMap) {}
+
+ void addCopy(DeclStmt const *PM) {
+ // Figure out what param it refers to.
+
+ assert(PM->isSingleDecl());
+ VarDecl const*VD = static_cast<VarDecl const*>(PM->getSingleDecl());
+ Expr const *InitExpr = VD->getInit();
+ GetParamRef Visitor;
+ Visitor.Visit(const_cast<Expr*>(InitExpr));
+ assert(Visitor.Expr);
+ auto *DREOrig = cast<DeclRefExpr>(Visitor.Expr);
+ auto *PD = DREOrig->getDecl();
+
+ auto it = LocalDeclMap.find(PD);
+ assert(it != LocalDeclMap.end() && "parameter is not found");
+ SavedLocals.insert({ PD, it->second });
+
+ auto copyIt = LocalDeclMap.find(VD);
+ assert(copyIt != LocalDeclMap.end() && "parameter copy is not found");
+ it->second = copyIt->getSecond();
+ }
+
+ ~ParamReferenceReplacerRAII() {
+ for (auto&& SavedLocal : SavedLocals) {
+ LocalDeclMap.insert({SavedLocal.first, SavedLocal.second});
+ }
+ }
+ };
+}
+
+// For WinEH exception representation backend needs to know what funclet coro.end
+// belongs to. That information is passed in a funclet bundle.
+static SmallVector<llvm::OperandBundleDef, 1>
+getBundlesForCoroEnd(CodeGenFunction &CGF) {
+ SmallVector<llvm::OperandBundleDef, 1> BundleList;
+
+ if (llvm::Instruction *EHPad = CGF.CurrentFuncletPad)
+ BundleList.emplace_back("funclet", EHPad);
+
+ return BundleList;
+}
+
+namespace {
+// We will insert coro.end to cut any of the destructors for objects that
+// do not need to be destroyed once the coroutine is resumed.
+// See llvm/docs/Coroutines.rst for more details about coro.end.
+struct CallCoroEnd final : public EHScopeStack::Cleanup {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ auto &CGM = CGF.CGM;
+ auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
+ llvm::Function *CoroEndFn = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
+ // See if we have a funclet bundle to associate coro.end with. (WinEH)
+ auto Bundles = getBundlesForCoroEnd(CGF);
+ auto *CoroEnd = CGF.Builder.CreateCall(
+ CoroEndFn, {NullPtr, CGF.Builder.getTrue()}, Bundles);
+ if (Bundles.empty()) {
+ // Otherwise, (landingpad model), create a conditional branch that leads
+ // either to a cleanup block or a block with EH resume instruction.
+ auto *ResumeBB = CGF.getEHResumeBlock(/*cleanup=*/true);
+ auto *CleanupContBB = CGF.createBasicBlock("cleanup.cont");
+ CGF.Builder.CreateCondBr(CoroEnd, ResumeBB, CleanupContBB);
+ CGF.EmitBlock(CleanupContBB);
+ }
+ }
+};
+}
+
+namespace {
+// Make sure to call coro.delete on scope exit.
+struct CallCoroDelete final : public EHScopeStack::Cleanup {
+ Stmt *Deallocate;
+
+ // Emit "if (coro.free(CoroId, CoroBegin)) Deallocate;"
+
+ // Note: That deallocation will be emitted twice: once for a normal exit and
+ // once for exceptional exit. This usage is safe because Deallocate does not
+ // contain any declarations. The SubStmtBuilder::makeNewAndDeleteExpr()
+ // builds a single call to a deallocation function which is safe to emit
+ // multiple times.
+ void Emit(CodeGenFunction &CGF, Flags) override {
+ // Remember the current point, as we are going to emit deallocation code
+ // first to get to coro.free instruction that is an argument to a delete
+ // call.
+ BasicBlock *SaveInsertBlock = CGF.Builder.GetInsertBlock();
+
+ auto *FreeBB = CGF.createBasicBlock("coro.free");
+ CGF.EmitBlock(FreeBB);
+ CGF.EmitStmt(Deallocate);
+
+ auto *AfterFreeBB = CGF.createBasicBlock("after.coro.free");
+ CGF.EmitBlock(AfterFreeBB);
+
+ // We should have captured coro.free from the emission of deallocate.
+ auto *CoroFree = CGF.CurCoro.Data->LastCoroFree;
+ if (!CoroFree) {
+ CGF.CGM.Error(Deallocate->getLocStart(),
+ "Deallocation expressoin does not refer to coro.free");
+ return;
+ }
+
+ // Get back to the block we were originally and move coro.free there.
+ auto *InsertPt = SaveInsertBlock->getTerminator();
+ CoroFree->moveBefore(InsertPt);
+ CGF.Builder.SetInsertPoint(InsertPt);
+
+ // Add if (auto *mem = coro.free) Deallocate;
+ auto *NullPtr = llvm::ConstantPointerNull::get(CGF.Int8PtrTy);
+ auto *Cond = CGF.Builder.CreateICmpNE(CoroFree, NullPtr);
+ CGF.Builder.CreateCondBr(Cond, FreeBB, AfterFreeBB);
+
+ // No longer need old terminator.
+ InsertPt->eraseFromParent();
+ CGF.Builder.SetInsertPoint(AfterFreeBB);
+ }
+ explicit CallCoroDelete(Stmt *DeallocStmt) : Deallocate(DeallocStmt) {}
+};
+}
+
+namespace {
+struct GetReturnObjectManager {
+ CodeGenFunction &CGF;
+ CGBuilderTy &Builder;
+ const CoroutineBodyStmt &S;
+
+ Address GroActiveFlag;
+ CodeGenFunction::AutoVarEmission GroEmission;
+
+ GetReturnObjectManager(CodeGenFunction &CGF, const CoroutineBodyStmt &S)
+ : CGF(CGF), Builder(CGF.Builder), S(S), GroActiveFlag(Address::invalid()),
+ GroEmission(CodeGenFunction::AutoVarEmission::invalid()) {}
+
+ // The gro variable has to outlive coroutine frame and coroutine promise, but,
+ // it can only be initialized after coroutine promise was created, thus, we
+ // split its emission in two parts. EmitGroAlloca emits an alloca and sets up
+ // cleanups. Later when coroutine promise is available we initialize the gro
+ // and sets the flag that the cleanup is now active.
+
+ void EmitGroAlloca() {
+ auto *GroDeclStmt = dyn_cast<DeclStmt>(S.getResultDecl());
+ if (!GroDeclStmt) {
+ // If get_return_object returns void, no need to do an alloca.
+ return;
+ }
+
+ auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl());
+
+ // Set GRO flag that it is not initialized yet
+ GroActiveFlag =
+ CGF.CreateTempAlloca(Builder.getInt1Ty(), CharUnits::One(), "gro.active");
+ Builder.CreateStore(Builder.getFalse(), GroActiveFlag);
+
+ GroEmission = CGF.EmitAutoVarAlloca(*GroVarDecl);
+
+ // Remember the top of EHStack before emitting the cleanup.
+ auto old_top = CGF.EHStack.stable_begin();
+ CGF.EmitAutoVarCleanups(GroEmission);
+ auto top = CGF.EHStack.stable_begin();
+
+ // Make the cleanup conditional on gro.active
+ for (auto b = CGF.EHStack.find(top), e = CGF.EHStack.find(old_top);
+ b != e; b++) {
+ if (auto *Cleanup = dyn_cast<EHCleanupScope>(&*b)) {
+ assert(!Cleanup->hasActiveFlag() && "cleanup already has active flag?");
+ Cleanup->setActiveFlag(GroActiveFlag);
+ Cleanup->setTestFlagInEHCleanup();
+ Cleanup->setTestFlagInNormalCleanup();
+ }
+ }
+ }
+
+ void EmitGroInit() {
+ if (!GroActiveFlag.isValid()) {
+ // No Gro variable was allocated. Simply emit the call to
+ // get_return_object.
+ CGF.EmitStmt(S.getResultDecl());
+ return;
+ }
+
+ CGF.EmitAutoVarInit(GroEmission);
+ Builder.CreateStore(Builder.getTrue(), GroActiveFlag);
+ }
+};
+}
+
+static void emitBodyAndFallthrough(CodeGenFunction &CGF,
+ const CoroutineBodyStmt &S, Stmt *Body) {
+ CGF.EmitStmt(Body);
+ const bool CanFallthrough = CGF.Builder.GetInsertBlock();
+ if (CanFallthrough)
+ if (Stmt *OnFallthrough = S.getFallthroughHandler())
+ CGF.EmitStmt(OnFallthrough);
+}
+
void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
auto *NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
auto &TI = CGM.getContext().getTargetInfo();
unsigned NewAlign = TI.getNewAlign() / TI.getCharWidth();
+ auto *EntryBB = Builder.GetInsertBlock();
+ auto *AllocBB = createBasicBlock("coro.alloc");
+ auto *InitBB = createBasicBlock("coro.init");
+ auto *FinalBB = createBasicBlock("coro.final");
+ auto *RetBB = createBasicBlock("coro.ret");
+
auto *CoroId = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::coro_id),
{Builder.getInt32(NewAlign), NullPtr, NullPtr, NullPtr});
createCoroData(*this, CurCoro, CoroId);
+ CurCoro.Data->SuspendBB = RetBB;
+
+ // Backend is allowed to elide memory allocations, to help it, emit
+ // auto mem = coro.alloc() ? 0 : ... allocation code ...;
+ auto *CoroAlloc = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::coro_alloc), {CoroId});
+
+ Builder.CreateCondBr(CoroAlloc, AllocBB, InitBB);
+
+ EmitBlock(AllocBB);
+ auto *AllocateCall = EmitScalarExpr(S.getAllocate());
+ auto *AllocOrInvokeContBB = Builder.GetInsertBlock();
+
+ // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
+ if (auto *RetOnAllocFailure = S.getReturnStmtOnAllocFailure()) {
+ auto *RetOnFailureBB = createBasicBlock("coro.ret.on.failure");
+
+ // See if allocation was successful.
+ auto *NullPtr = llvm::ConstantPointerNull::get(Int8PtrTy);
+ auto *Cond = Builder.CreateICmpNE(AllocateCall, NullPtr);
+ Builder.CreateCondBr(Cond, InitBB, RetOnFailureBB);
+
+ // If not, return OnAllocFailure object.
+ EmitBlock(RetOnFailureBB);
+ EmitStmt(RetOnAllocFailure);
+ }
+ else {
+ Builder.CreateBr(InitBB);
+ }
+
+ EmitBlock(InitBB);
+
+ // Pass the result of the allocation to coro.begin.
+ auto *Phi = Builder.CreatePHI(VoidPtrTy, 2);
+ Phi->addIncoming(NullPtr, EntryBB);
+ Phi->addIncoming(AllocateCall, AllocOrInvokeContBB);
+ auto *CoroBegin = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::coro_begin), {CoroId, Phi});
+ CurCoro.Data->CoroBegin = CoroBegin;
+
+ GetReturnObjectManager GroManager(*this, S);
+ GroManager.EmitGroAlloca();
+
+ CurCoro.Data->CleanupJD = getJumpDestInCurrentScope(RetBB);
+ {
+ ParamReferenceReplacerRAII ParamReplacer(LocalDeclMap);
+ CodeGenFunction::RunCleanupsScope ResumeScope(*this);
+ EHStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, S.getDeallocate());
+
+ // Create parameter copies. We do it before creating a promise, since an
+ // evolution of coroutine TS may allow promise constructor to observe
+ // parameter copies.
+ for (auto *PM : S.getParamMoves()) {
+ EmitStmt(PM);
+ ParamReplacer.addCopy(cast<DeclStmt>(PM));
+ // TODO: if(CoroParam(...)) need to surround ctor and dtor
+ // for the copy, so that llvm can elide it if the copy is
+ // not needed.
+ }
- EmitScalarExpr(S.getAllocate());
- // FIXME: Emit the rest of the coroutine.
- EmitStmt(S.getDeallocate());
+ EmitStmt(S.getPromiseDeclStmt());
+
+ Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl());
+ auto *PromiseAddrVoidPtr =
+ new llvm::BitCastInst(PromiseAddr.getPointer(), VoidPtrTy, "", CoroId);
+ // Update CoroId to refer to the promise. We could not do it earlier because
+ // promise local variable was not emitted yet.
+ CoroId->setArgOperand(1, PromiseAddrVoidPtr);
+
+ // Now we have the promise, initialize the GRO
+ GroManager.EmitGroInit();
+
+ EHStack.pushCleanup<CallCoroEnd>(EHCleanup);
+
+ CurCoro.Data->CurrentAwaitKind = AwaitKind::Init;
+ EmitStmt(S.getInitSuspendStmt());
+ CurCoro.Data->FinalJD = getJumpDestInCurrentScope(FinalBB);
+
+ CurCoro.Data->CurrentAwaitKind = AwaitKind::Normal;
+
+ if (auto *OnException = S.getExceptionHandler()) {
+ auto Loc = S.getLocStart();
+ CXXCatchStmt Catch(Loc, /*exDecl=*/nullptr, OnException);
+ auto *TryStmt = CXXTryStmt::Create(getContext(), Loc, S.getBody(), &Catch);
+
+ EnterCXXTryStmt(*TryStmt);
+ emitBodyAndFallthrough(*this, S, TryStmt->getTryBlock());
+ ExitCXXTryStmt(*TryStmt);
+ }
+ else {
+ emitBodyAndFallthrough(*this, S, S.getBody());
+ }
+
+ // See if we need to generate final suspend.
+ const bool CanFallthrough = Builder.GetInsertBlock();
+ const bool HasCoreturns = CurCoro.Data->CoreturnCount > 0;
+ if (CanFallthrough || HasCoreturns) {
+ EmitBlock(FinalBB);
+ CurCoro.Data->CurrentAwaitKind = AwaitKind::Final;
+ EmitStmt(S.getFinalSuspendStmt());
+ } else {
+ // We don't need FinalBB. Emit it to make sure the block is deleted.
+ EmitBlock(FinalBB, /*IsFinished=*/true);
+ }
+ }
+
+ EmitBlock(RetBB);
+ // Emit coro.end before getReturnStmt (and parameter destructors), since
+ // resume and destroy parts of the coroutine should not include them.
+ llvm::Function *CoroEnd = CGM.getIntrinsic(llvm::Intrinsic::coro_end);
+ Builder.CreateCall(CoroEnd, {NullPtr, Builder.getFalse()});
+
+ if (Stmt *Ret = S.getReturnStmt())
+ EmitStmt(Ret);
}
// Emit coroutine intrinsic and patch up arguments of the token type.
@@ -81,6 +631,17 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
switch (IID) {
default:
break;
+ // The coro.frame builtin is replaced with an SSA value of the coro.begin
+ // intrinsic.
+ case llvm::Intrinsic::coro_frame: {
+ if (CurCoro.Data && CurCoro.Data->CoroBegin) {
+ return RValue::get(CurCoro.Data->CoroBegin);
+ }
+ CGM.Error(E->getLocStart(), "this builtin expect that __builtin_coro_begin "
+ "has been used earlier in this function");
+ auto NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
+ return RValue::get(NullPtr);
+ }
// The following three intrinsics take a token parameter referring to a token
// returned by earlier call to @llvm.coro.id. Since we cannot represent it in
// builtins, we patch it up here.
@@ -94,6 +655,7 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
CGM.Error(E->getLocStart(), "this builtin expect that __builtin_coro_id has"
" been used earlier in this function");
// Fallthrough to the next case to add TokenNone as the first argument.
+ LLVM_FALLTHROUGH;
}
// @llvm.coro.suspend takes a token parameter. Add token 'none' as the first
// argument.
@@ -107,10 +669,22 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
llvm::Value *F = CGM.getIntrinsic(IID);
llvm::CallInst *Call = Builder.CreateCall(F, Args);
+ // Note: The following code is to enable to emit coro.id and coro.begin by
+ // hand to experiment with coroutines in C.
// If we see @llvm.coro.id remember it in the CoroData. We will update
// coro.alloc, coro.begin and coro.free intrinsics to refer to it.
if (IID == llvm::Intrinsic::coro_id) {
createCoroData(*this, CurCoro, Call, E);
}
+ else if (IID == llvm::Intrinsic::coro_begin) {
+ if (CurCoro.Data)
+ CurCoro.Data->CoroBegin = Call;
+ }
+ else if (IID == llvm::Intrinsic::coro_free) {
+ // Remember the last coro_free as we need it to build the conditional
+ // deletion of the coroutine frame.
+ if (CurCoro.Data)
+ CurCoro.Data->LastCoroFree = Call;
+ }
return RValue::get(Call);
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp
index 12a6803..18b1d10 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -107,8 +107,8 @@ void ApplyDebugLocation::init(SourceLocation TemporaryLocation,
// Construct a location that has a valid scope, but no line info.
assert(!DI->LexicalBlockStack.empty());
- CGF->Builder.SetCurrentDebugLocation(
- llvm::DebugLoc::get(0, 0, DI->LexicalBlockStack.back()));
+ CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(
+ 0, 0, DI->LexicalBlockStack.back(), DI->getInlinedAt()));
}
ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E)
@@ -134,6 +134,30 @@ ApplyDebugLocation::~ApplyDebugLocation() {
CGF->Builder.SetCurrentDebugLocation(std::move(OriginalLocation));
}
+ApplyInlineDebugLocation::ApplyInlineDebugLocation(CodeGenFunction &CGF,
+ GlobalDecl InlinedFn)
+ : CGF(&CGF) {
+ if (!CGF.getDebugInfo()) {
+ this->CGF = nullptr;
+ return;
+ }
+ auto &DI = *CGF.getDebugInfo();
+ SavedLocation = DI.getLocation();
+ assert((DI.getInlinedAt() ==
+ CGF.Builder.getCurrentDebugLocation()->getInlinedAt()) &&
+ "CGDebugInfo and IRBuilder are out of sync");
+
+ DI.EmitInlineFunctionStart(CGF.Builder, InlinedFn);
+}
+
+ApplyInlineDebugLocation::~ApplyInlineDebugLocation() {
+ if (!CGF)
+ return;
+ auto &DI = *CGF->getDebugInfo();
+ DI.EmitInlineFunctionEnd(CGF->Builder);
+ DI.EmitLocation(CGF->Builder, SavedLocation);
+}
+
void CGDebugInfo::setLocation(SourceLocation Loc) {
// If the new location isn't valid return.
if (Loc.isInvalid())
@@ -185,7 +209,7 @@ llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context,
// Check namespace.
if (const auto *NSDecl = dyn_cast<NamespaceDecl>(Context))
- return getOrCreateNameSpace(NSDecl);
+ return getOrCreateNamespace(NSDecl);
if (const auto *RDecl = dyn_cast<RecordDecl>(Context))
if (!RDecl->isDependentType())
@@ -249,8 +273,8 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
<< OC->getIdentifier()->getNameStart() << ')';
}
} else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
- OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '('
- << OCD->getIdentifier()->getNameStart() << ')';
+ OS << OCD->getClassInterface()->getName() << '('
+ << OCD->getName() << ')';
} else if (isa<ObjCProtocolDecl>(DC)) {
// We can extract the type of the class from the self pointer.
if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) {
@@ -504,12 +528,15 @@ void CGDebugInfo::CreateCompileUnit() {
// Create new compile unit.
// FIXME - Eliminate TheCU.
TheCU = DBuilder.createCompileUnit(
- LangTag, DBuilder.createFile(remapDIPath(MainFileName),
- remapDIPath(getCurrentDirname()), CSKind,
- Checksum),
+ LangTag,
+ DBuilder.createFile(remapDIPath(MainFileName),
+ remapDIPath(getCurrentDirname()), CSKind, Checksum),
Producer, LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers,
- CGM.getCodeGenOpts().SplitDwarfFile, EmissionKind, 0 /* DWOid */,
- CGM.getCodeGenOpts().SplitDwarfInlining);
+ CGM.getCodeGenOpts().EnableSplitDwarf
+ ? ""
+ : CGM.getCodeGenOpts().SplitDwarfFile,
+ EmissionKind, 0 /* DWOid */, CGM.getCodeGenOpts().SplitDwarfInlining,
+ CGM.getCodeGenOpts().DebugInfoForProfiling);
}
llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
@@ -581,8 +608,6 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
return getOrCreateStructPtrType("opencl_clk_event_t", OCLClkEventDITy);
case BuiltinType::OCLQueue:
return getOrCreateStructPtrType("opencl_queue_t", OCLQueueDITy);
- case BuiltinType::OCLNDRange:
- return getOrCreateStructPtrType("opencl_ndrange_t", OCLNDRangeDITy);
case BuiltinType::OCLReserveID:
return getOrCreateStructPtrType("opencl_reserve_id_t", OCLReserveIDDITy);
@@ -793,17 +818,19 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
// Bit size, align and offset of the type.
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
- unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getTarget().getPointerWidth(AS);
+ unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(PointeeTy);
+ uint64_t Size = CGM.getTarget().getPointerWidth(AddressSpace);
auto Align = getTypeAlignIfRequired(Ty, CGM.getContext());
+ Optional<unsigned> DWARFAddressSpace =
+ CGM.getTarget().getDWARFAddressSpace(AddressSpace);
if (Tag == llvm::dwarf::DW_TAG_reference_type ||
Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit),
- Size, Align);
+ Size, Align, DWARFAddressSpace);
else
return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size,
- Align);
+ Align, DWARFAddressSpace);
}
llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name,
@@ -929,7 +956,7 @@ static unsigned getDwarfCC(CallingConv CC) {
return llvm::dwarf::DW_CC_BORLAND_pascal;
// FIXME: Create new DW_CC_ codes for these calling conventions.
- case CC_X86_64Win64:
+ case CC_Win64:
case CC_X86_64SysV:
case CC_AAPCS:
case CC_AAPCS_VFP:
@@ -1014,7 +1041,13 @@ llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl,
assert(SizeInBits > 0 && "found named 0-width bitfield");
uint64_t StorageOffsetInBits =
CGM.getContext().toBits(BitFieldInfo.StorageOffset);
- uint64_t OffsetInBits = StorageOffsetInBits + BitFieldInfo.Offset;
+ uint64_t Offset = BitFieldInfo.Offset;
+ // The bit offsets for big endian machines are reversed for big
+ // endian target, compensate for that as the DIDerivedType requires
+ // un-reversed offsets.
+ if (CGM.getDataLayout().isBigEndian())
+ Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset;
+ uint64_t OffsetInBits = StorageOffsetInBits + Offset;
llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD);
return DBuilder.createBitFieldMemberType(
RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits,
@@ -1608,8 +1641,13 @@ llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) {
llvm::DITypeRefArray SElements = DBuilder.getOrCreateTypeArray(STy);
llvm::DIType *SubTy = DBuilder.createSubroutineType(SElements);
unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
+ unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace();
+ Optional<unsigned> DWARFAddressSpace =
+ CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace);
+
llvm::DIType *vtbl_ptr_type =
- DBuilder.createPointerType(SubTy, Size, 0, "__vtbl_ptr_type");
+ DBuilder.createPointerType(SubTy, Size, 0, DWARFAddressSpace,
+ "__vtbl_ptr_type");
VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size);
return VTablePtrType;
}
@@ -1648,10 +1686,14 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
unsigned VSlotCount =
VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData;
unsigned VTableWidth = PtrWidth * VSlotCount;
+ unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace();
+ Optional<unsigned> DWARFAddressSpace =
+ CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace);
// Create a very wide void* type and insert it directly in the element list.
llvm::DIType *VTableType =
- DBuilder.createPointerType(nullptr, VTableWidth, 0, "__vtbl_ptr_type");
+ DBuilder.createPointerType(nullptr, VTableWidth, 0, DWARFAddressSpace,
+ "__vtbl_ptr_type");
EltTys.push_back(VTableType);
// The vptr is a pointer to this special vtable type.
@@ -1714,7 +1756,27 @@ void CGDebugInfo::completeType(const RecordDecl *RD) {
completeRequiredType(RD);
}
+/// Return true if the class or any of its methods are marked dllimport.
+static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) {
+ if (RD->hasAttr<DLLImportAttr>())
+ return true;
+ for (const CXXMethodDecl *MD : RD->methods())
+ if (MD->hasAttr<DLLImportAttr>())
+ return true;
+ return false;
+}
+
void CGDebugInfo::completeClassData(const RecordDecl *RD) {
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ if (CXXRD->isDynamicClass() &&
+ CGM.getVTableLinkage(CXXRD) ==
+ llvm::GlobalValue::AvailableExternallyLinkage &&
+ !isClassOrMethodDLLImport(CXXRD))
+ return;
+ completeClass(RD);
+}
+
+void CGDebugInfo::completeClass(const RecordDecl *RD) {
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
QualType Ty = CGM.getContext().getRecordType(RD);
@@ -1760,22 +1822,16 @@ static bool isDefinedInClangModule(const RecordDecl *RD) {
return true;
}
-/// Return true if the class or any of its methods are marked dllimport.
-static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) {
- if (RD->hasAttr<DLLImportAttr>())
- return true;
- for (const CXXMethodDecl *MD : RD->methods())
- if (MD->hasAttr<DLLImportAttr>())
- return true;
- return false;
-}
-
static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind,
bool DebugTypeExtRefs, const RecordDecl *RD,
const LangOptions &LangOpts) {
if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition()))
return true;
+ if (auto *ES = RD->getASTContext().getExternalSource())
+ if (ES->hasExternalDefinitions(RD) == ExternalASTSource::EK_Always)
+ return true;
+
if (DebugKind > codegenoptions::LimitedDebugInfo)
return false;
@@ -2009,7 +2065,11 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod,
if (CreateSkeletonCU && IsRootModule) {
// PCH files don't have a signature field in the control block,
// but LLVM detects skeleton CUs by looking for a non-zero DWO id.
- uint64_t Signature = Mod.getSignature() ? Mod.getSignature() : ~1ULL;
+ // We use the lower 64 bits for debug info.
+ uint64_t Signature =
+ Mod.getSignature()
+ ? (uint64_t)Mod.getSignature()[1] << 32 | Mod.getSignature()[0]
+ : ~1ULL;
llvm::DIBuilder DIB(CGM.getModule());
DIB.createCompileUnit(TheCU->getSourceLanguage(),
DIB.createFile(Mod.getModuleName(), Mod.getPath()),
@@ -2408,6 +2468,21 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) {
FullName);
}
+llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent,
+ unsigned MType, SourceLocation LineLoc,
+ StringRef Name, StringRef Value) {
+ unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
+ return DBuilder.createMacro(Parent, Line, MType, Name, Value);
+}
+
+llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent,
+ SourceLocation LineLoc,
+ SourceLocation FileLoc) {
+ llvm::DIFile *FName = getOrCreateFile(FileLoc);
+ unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
+ return DBuilder.createTempMacroFile(Parent, Line, FName);
+}
+
static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
Qualifiers Quals;
do {
@@ -2451,8 +2526,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
case Type::SubstTemplateTypeParm:
T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
break;
- case Type::Auto: {
- QualType DT = cast<AutoType>(T)->getDeducedType();
+ case Type::Auto:
+ case Type::DeducedTemplateSpecialization: {
+ QualType DT = cast<DeducedType>(T)->getDeducedType();
assert(!DT.isNull() && "Undeduced types shouldn't reach here.");
T = DT;
break;
@@ -2488,11 +2564,17 @@ void CGDebugInfo::completeTemplateDefinition(
const ClassTemplateSpecializationDecl &SD) {
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
+ completeUnusedClass(SD);
+}
- completeClassData(&SD);
+void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) {
+ if (DebugKind <= codegenoptions::DebugLineTablesOnly)
+ return;
+
+ completeClassData(&D);
// In case this type has no member function definitions being emitted, ensure
// it is retained
- RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr());
+ RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr());
}
llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
@@ -2537,7 +2619,7 @@ llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) {
// best to make this behavior a command line or debugger tuning
// option.
FullSourceLoc Loc(D->getLocation(), CGM.getContext().getSourceManager());
- if (Module *M = ClangModuleMap->inferModuleFromLocation(Loc)) {
+ if (Module *M = D->getOwningModule()) {
// This is a (sub-)module.
auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
return getOrCreateModuleRef(Info, /*SkeletonCU=*/false);
@@ -2618,6 +2700,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
case Type::Attributed:
case Type::Adjusted:
case Type::Decayed:
+ case Type::DeducedTemplateSpecialization:
case Type::Elaborated:
case Type::Paren:
case Type::SubstTemplateTypeParm:
@@ -2704,6 +2787,7 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
// them distinct if they are ODR-uniqued.
if (FullName.empty())
break;
+ LLVM_FALLTHROUGH;
case llvm::dwarf::DW_TAG_structure_type:
case llvm::dwarf::DW_TAG_union_type:
@@ -2774,16 +2858,17 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
}
// No need to replicate the linkage name if it isn't different from the
// subprogram name, no need to have it at all unless coverage is enabled or
- // debug is set to more than just line tables.
+ // debug is set to more than just line tables or extra debug info is needed.
if (LinkageName == Name || (!CGM.getCodeGenOpts().EmitGcovArcs &&
!CGM.getCodeGenOpts().EmitGcovNotes &&
+ !CGM.getCodeGenOpts().DebugInfoForProfiling &&
DebugKind <= codegenoptions::DebugLineTablesOnly))
LinkageName = StringRef();
if (DebugKind >= codegenoptions::LimitedDebugInfo) {
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
- FDContext = getOrCreateNameSpace(NSDecl);
+ FDContext = getOrCreateNamespace(NSDecl);
else if (const RecordDecl *RDecl =
dyn_cast_or_null<RecordDecl>(FD->getDeclContext())) {
llvm::DIScope *Mod = getParentModuleOrNull(RDecl);
@@ -2844,28 +2929,40 @@ void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit,
VDContext = getContextDescriptor(cast<Decl>(DC), Mod ? Mod : TheCU);
}
-llvm::DISubprogram *
-CGDebugInfo::getFunctionForwardDeclaration(const FunctionDecl *FD) {
+llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD,
+ bool Stub) {
llvm::DINodeArray TParamsArray;
StringRef Name, LinkageName;
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
- SourceLocation Loc = FD->getLocation();
+ SourceLocation Loc = GD.getDecl()->getLocation();
llvm::DIFile *Unit = getOrCreateFile(Loc);
llvm::DIScope *DContext = Unit;
unsigned Line = getLineNumber(Loc);
-
- collectFunctionDeclProps(FD, Unit, Name, LinkageName, DContext,
+ collectFunctionDeclProps(GD, Unit, Name, LinkageName, DContext,
TParamsArray, Flags);
+ auto *FD = dyn_cast<FunctionDecl>(GD.getDecl());
+
// Build function type.
SmallVector<QualType, 16> ArgTypes;
- for (const ParmVarDecl *Parm: FD->parameters())
- ArgTypes.push_back(Parm->getType());
+ if (FD)
+ for (const ParmVarDecl *Parm : FD->parameters())
+ ArgTypes.push_back(Parm->getType());
CallingConv CC = FD->getType()->castAs<FunctionType>()->getCallConv();
QualType FnType = CGM.getContext().getFunctionType(
FD->getReturnType(), ArgTypes, FunctionProtoType::ExtProtoInfo(CC));
+ if (Stub) {
+ return DBuilder.createFunction(
+ DContext, Name, LinkageName, Unit, Line,
+ getOrCreateFunctionType(GD.getDecl(), FnType, Unit),
+ !FD->isExternallyVisible(),
+ /* isDefinition = */ true, 0, Flags, CGM.getLangOpts().Optimize,
+ TParamsArray.get(), getFunctionDeclaration(FD));
+ }
+
llvm::DISubprogram *SP = DBuilder.createTempFunctionFwdDecl(
DContext, Name, LinkageName, Unit, Line,
- getOrCreateFunctionType(FD, FnType, Unit), !FD->isExternallyVisible(),
+ getOrCreateFunctionType(GD.getDecl(), FnType, Unit),
+ !FD->isExternallyVisible(),
/* isDefinition = */ false, 0, Flags, CGM.getLangOpts().Optimize,
TParamsArray.get(), getFunctionDeclaration(FD));
const auto *CanonDecl = cast<FunctionDecl>(FD->getCanonicalDecl());
@@ -2875,6 +2972,16 @@ CGDebugInfo::getFunctionForwardDeclaration(const FunctionDecl *FD) {
return SP;
}
+llvm::DISubprogram *
+CGDebugInfo::getFunctionForwardDeclaration(GlobalDecl GD) {
+ return getFunctionFwdDeclOrStub(GD, /* Stub = */ false);
+}
+
+llvm::DISubprogram *
+CGDebugInfo::getFunctionStub(GlobalDecl GD) {
+ return getFunctionFwdDeclOrStub(GD, /* Stub = */ true);
+}
+
llvm::DIGlobalVariable *
CGDebugInfo::getGlobalVariableForwardDeclaration(const VarDecl *VD) {
QualType T;
@@ -3146,6 +3253,27 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
TParamsArray.get(), getFunctionDeclaration(D)));
}
+void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) {
+ const auto *FD = cast<FunctionDecl>(GD.getDecl());
+ // If there is a subprogram for this function available then use it.
+ auto FI = SPCache.find(FD->getCanonicalDecl());
+ llvm::DISubprogram *SP = nullptr;
+ if (FI != SPCache.end())
+ SP = dyn_cast_or_null<llvm::DISubprogram>(FI->second);
+ if (!SP || !SP->isDefinition())
+ SP = getFunctionStub(GD);
+ FnBeginRegionCount.push_back(LexicalBlockStack.size());
+ LexicalBlockStack.emplace_back(SP);
+ setInlinedAt(Builder.getCurrentDebugLocation());
+ EmitLocation(Builder, FD->getLocation());
+}
+
+void CGDebugInfo::EmitInlineFunctionEnd(CGBuilderTy &Builder) {
+ assert(CurInlinedAt && "unbalanced inline scope stack");
+ EmitFunctionEnd(Builder, nullptr);
+ setInlinedAt(llvm::DebugLoc(CurInlinedAt).getInlinedAt());
+}
+
void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
// Update our current location
setLocation(Loc);
@@ -3155,7 +3283,7 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
llvm::MDNode *Scope = LexicalBlockStack.back();
Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(
- getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope));
+ getLineNumber(CurLoc), getColumnNumber(CurLoc), Scope, CurInlinedAt));
}
void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
@@ -3167,14 +3295,29 @@ void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
getColumnNumber(CurLoc)));
}
+void CGDebugInfo::AppendAddressSpaceXDeref(
+ unsigned AddressSpace,
+ SmallVectorImpl<int64_t> &Expr) const {
+ Optional<unsigned> DWARFAddressSpace =
+ CGM.getTarget().getDWARFAddressSpace(AddressSpace);
+ if (!DWARFAddressSpace)
+ return;
+
+ Expr.push_back(llvm::dwarf::DW_OP_constu);
+ Expr.push_back(DWARFAddressSpace.getValue());
+ Expr.push_back(llvm::dwarf::DW_OP_swap);
+ Expr.push_back(llvm::dwarf::DW_OP_xderef);
+}
+
void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder,
SourceLocation Loc) {
// Set our current location.
setLocation(Loc);
// Emit a line table change for the current location inside the new scope.
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(
- getLineNumber(Loc), getColumnNumber(Loc), LexicalBlockStack.back()));
+ Builder.SetCurrentDebugLocation(
+ llvm::DebugLoc::get(getLineNumber(Loc), getColumnNumber(Loc),
+ LexicalBlockStack.back(), CurInlinedAt));
if (DebugKind <= codegenoptions::DebugLineTablesOnly)
return;
@@ -3196,7 +3339,7 @@ void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder,
LexicalBlockStack.pop_back();
}
-void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
+void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn) {
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
unsigned RCount = FnBeginRegionCount.back();
assert(RCount <= LexicalBlockStack.size() && "Region stack mismatch");
@@ -3208,6 +3351,9 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
LexicalBlockStack.pop_back();
}
FnBeginRegionCount.pop_back();
+
+ if (Fn && Fn->getSubprogram())
+ DBuilder.finalizeSubprogram(Fn->getSubprogram());
}
llvm::DIType *CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
@@ -3316,56 +3462,45 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage,
Line = getLineNumber(VD->getLocation());
Column = getColumnNumber(VD->getLocation());
}
- SmallVector<int64_t, 9> Expr;
+ SmallVector<int64_t, 13> Expr;
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
if (VD->isImplicit())
Flags |= llvm::DINode::FlagArtificial;
auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
- // If this is the first argument and it is implicit then
- // give it an object pointer flag.
- // FIXME: There has to be a better way to do this, but for static
- // functions there won't be an implicit param at arg1 and
- // otherwise it is 'self' or 'this'.
- if (isa<ImplicitParamDecl>(VD) && ArgNo && *ArgNo == 1)
- Flags |= llvm::DINode::FlagObjectPointer;
- if (auto *Arg = dyn_cast<llvm::Argument>(Storage))
- if (Arg->getType()->isPointerTy() && !Arg->hasByValAttr() &&
- !VD->getType()->isPointerType())
- Expr.push_back(llvm::dwarf::DW_OP_deref);
+ unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType());
+ AppendAddressSpaceXDeref(AddressSpace, Expr);
- auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back());
+ // If this is implicit parameter of CXXThis or ObjCSelf kind, then give it an
+ // object pointer flag.
+ if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD)) {
+ if (IPD->getParameterKind() == ImplicitParamDecl::CXXThis ||
+ IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf)
+ Flags |= llvm::DINode::FlagObjectPointer;
+ }
+ // Note: Older versions of clang used to emit byval references with an extra
+ // DW_OP_deref, because they referenced the IR arg directly instead of
+ // referencing an alloca. Newer versions of LLVM don't treat allocas
+ // differently from other function arguments when used in a dbg.declare.
+ auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back());
StringRef Name = VD->getName();
if (!Name.empty()) {
if (VD->hasAttr<BlocksAttr>()) {
+ // Here, we need an offset *into* the alloca.
CharUnits offset = CharUnits::fromQuantity(32);
- Expr.push_back(llvm::dwarf::DW_OP_plus);
+ Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of __forwarding field
offset = CGM.getContext().toCharUnitsFromBits(
CGM.getTarget().getPointerWidth(0));
Expr.push_back(offset.getQuantity());
Expr.push_back(llvm::dwarf::DW_OP_deref);
- Expr.push_back(llvm::dwarf::DW_OP_plus);
+ Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of x field
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
Expr.push_back(offset.getQuantity());
-
- // Create the descriptor for the variable.
- auto *D = ArgNo
- ? DBuilder.createParameterVariable(Scope, VD->getName(),
- *ArgNo, Unit, Line, Ty)
- : DBuilder.createAutoVariable(Scope, VD->getName(), Unit,
- Line, Ty, Align);
-
- // Insert an llvm.dbg.declare into the current block.
- DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
- llvm::DebugLoc::get(Line, Column, Scope),
- Builder.GetInsertBlock());
- return;
- } else if (isa<VariableArrayType>(VD->getType()))
- Expr.push_back(llvm::dwarf::DW_OP_deref);
+ }
} else if (const auto *RT = dyn_cast<RecordType>(VD->getType())) {
// If VD is an anonymous union then Storage represents value for
// all union fields.
@@ -3393,9 +3528,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage,
Flags | llvm::DINode::FlagArtificial, FieldAlign);
// Insert an llvm.dbg.declare into the current block.
- DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
- llvm::DebugLoc::get(Line, Column, Scope),
- Builder.GetInsertBlock());
+ DBuilder.insertDeclare(
+ Storage, D, DBuilder.createExpression(Expr),
+ llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
+ Builder.GetInsertBlock());
}
}
}
@@ -3411,7 +3547,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage,
// Insert an llvm.dbg.declare into the current block.
DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr),
- llvm::DebugLoc::get(Line, Column, Scope),
+ llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt),
Builder.GetInsertBlock());
}
@@ -3453,8 +3589,9 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
// Self is passed along as an implicit non-arg variable in a
// block. Mark it as the object pointer.
- if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self")
- Ty = CreateSelfType(VD->getType(), Ty);
+ if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD))
+ if (IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf)
+ Ty = CreateSelfType(VD->getType(), Ty);
// Get location information.
unsigned Line = getLineNumber(VD->getLocation());
@@ -3467,19 +3604,18 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
->getElementOffset(blockInfo.getCapture(VD).getIndex()));
SmallVector<int64_t, 9> addr;
- if (isa<llvm::AllocaInst>(Storage))
- addr.push_back(llvm::dwarf::DW_OP_deref);
- addr.push_back(llvm::dwarf::DW_OP_plus);
+ addr.push_back(llvm::dwarf::DW_OP_deref);
+ addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
addr.push_back(offset.getQuantity());
if (isByRef) {
addr.push_back(llvm::dwarf::DW_OP_deref);
- addr.push_back(llvm::dwarf::DW_OP_plus);
+ addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of __forwarding field
offset =
CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits(0));
addr.push_back(offset.getQuantity());
addr.push_back(llvm::dwarf::DW_OP_deref);
- addr.push_back(llvm::dwarf::DW_OP_plus);
+ addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of x field
offset = CGM.getContext().toCharUnitsFromBits(XOffset);
addr.push_back(offset.getQuantity());
@@ -3492,13 +3628,13 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(
Line, Ty, false, llvm::DINode::FlagZero, Align);
// Insert an llvm.dbg.declare into the current block.
- auto DL = llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back());
+ auto DL =
+ llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back(), CurInlinedAt);
+ auto *Expr = DBuilder.createExpression(addr);
if (InsertPoint)
- DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL,
- InsertPoint);
+ DBuilder.insertDeclare(Storage, D, Expr, DL, InsertPoint);
else
- DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(addr), DL,
- Builder.GetInsertBlock());
+ DBuilder.insertDeclare(Storage, D, Expr, DL, Builder.GetInsertBlock());
}
void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI,
@@ -3660,12 +3796,13 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
// Insert an llvm.dbg.value into the current block.
DBuilder.insertDbgValueIntrinsic(
LocalAddr, 0, debugVar, DBuilder.createExpression(),
- llvm::DebugLoc::get(line, column, scope), Builder.GetInsertBlock());
+ llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
+ Builder.GetInsertBlock());
}
// Insert an llvm.dbg.declare into the current block.
DBuilder.insertDeclare(Arg, debugVar, DBuilder.createExpression(),
- llvm::DebugLoc::get(line, column, scope),
+ llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
Builder.GetInsertBlock());
}
@@ -3747,9 +3884,16 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
GVE = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext);
} else {
auto Align = getDeclAlignIfRequired(D, CGM.getContext());
+
+ SmallVector<int64_t, 4> Expr;
+ unsigned AddressSpace =
+ CGM.getContext().getTargetAddressSpace(D->getType());
+ AppendAddressSpaceXDeref(AddressSpace, Expr);
+
GVE = DBuilder.createGlobalVariableExpression(
DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
- Var->hasLocalLinkage(), /*Expr=*/nullptr,
+ Var->hasLocalLinkage(),
+ Expr.empty() ? nullptr : DBuilder.createExpression(Expr),
getOrCreateStaticDataMemberDeclarationOrNull(D), Align);
Var->addDebugInfo(GVE);
}
@@ -3826,10 +3970,10 @@ void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) {
const NamespaceDecl *NSDecl = UD.getNominatedNamespace();
if (!NSDecl->isAnonymousNamespace() ||
CGM.getCodeGenOpts().DebugExplicitImport) {
+ auto Loc = UD.getLocation();
DBuilder.createImportedModule(
getCurrentContextDescriptor(cast<Decl>(UD.getDeclContext())),
- getOrCreateNameSpace(NSDecl),
- getLineNumber(UD.getLocation()));
+ getOrCreateNamespace(NSDecl), getOrCreateFile(Loc), getLineNumber(Loc));
}
}
@@ -3852,10 +3996,12 @@ void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
if (AT->getDeducedType().isNull())
return;
if (llvm::DINode *Target =
- getDeclarationOrDefinition(USD.getUnderlyingDecl()))
+ getDeclarationOrDefinition(USD.getUnderlyingDecl())) {
+ auto Loc = USD.getLocation();
DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(USD.getDeclContext())), Target,
- getLineNumber(USD.getLocation()));
+ getOrCreateFile(Loc), getLineNumber(Loc));
+ }
}
void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) {
@@ -3863,10 +4009,11 @@ void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) {
return;
if (Module *M = ID.getImportedModule()) {
auto Info = ExternalASTSource::ASTSourceDescriptor(*M);
+ auto Loc = ID.getLocation();
DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(ID.getDeclContext())),
- getOrCreateModuleRef(Info, DebugTypeExtRefs),
- getLineNumber(ID.getLocation()));
+ getOrCreateModuleRef(Info, DebugTypeExtRefs), getOrCreateFile(Loc),
+ getLineNumber(Loc));
}
}
@@ -3878,35 +4025,37 @@ CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
if (VH)
return cast<llvm::DIImportedEntity>(VH);
llvm::DIImportedEntity *R;
+ auto Loc = NA.getLocation();
if (const auto *Underlying =
dyn_cast<NamespaceAliasDecl>(NA.getAliasedNamespace()))
// This could cache & dedup here rather than relying on metadata deduping.
R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
- EmitNamespaceAlias(*Underlying), getLineNumber(NA.getLocation()),
- NA.getName());
+ EmitNamespaceAlias(*Underlying), getOrCreateFile(Loc),
+ getLineNumber(Loc), NA.getName());
else
R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
- getOrCreateNameSpace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
- getLineNumber(NA.getLocation()), NA.getName());
+ getOrCreateNamespace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
+ getOrCreateFile(Loc), getLineNumber(Loc), NA.getName());
VH.reset(R);
return R;
}
llvm::DINamespace *
-CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
- NSDecl = NSDecl->getCanonicalDecl();
- auto I = NameSpaceCache.find(NSDecl);
- if (I != NameSpaceCache.end())
+CGDebugInfo::getOrCreateNamespace(const NamespaceDecl *NSDecl) {
+ // Don't canonicalize the NamespaceDecl here: The DINamespace will be uniqued
+ // if necessary, and this way multiple declarations of the same namespace in
+ // different parent modules stay distinct.
+ auto I = NamespaceCache.find(NSDecl);
+ if (I != NamespaceCache.end())
return cast<llvm::DINamespace>(I->second);
- unsigned LineNo = getLineNumber(NSDecl->getLocation());
- llvm::DIFile *FileD = getOrCreateFile(NSDecl->getLocation());
llvm::DIScope *Context = getDeclContextDescriptor(NSDecl);
- llvm::DINamespace *NS = DBuilder.createNameSpace(
- Context, NSDecl->getName(), FileD, LineNo, NSDecl->isInline());
- NameSpaceCache[NSDecl].reset(NS);
+ // Don't trust the context if it is a DIModule (see comment above).
+ llvm::DINamespace *NS =
+ DBuilder.createNameSpace(Context, NSDecl->getName(), NSDecl->isInline());
+ NamespaceCache[NSDecl].reset(NS);
return NS;
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h
index ac2e8dd..39249c7 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h
@@ -61,6 +61,7 @@ class CGDebugInfo {
ModuleMap *ClangModuleMap = nullptr;
ExternalASTSource::ASTSourceDescriptor PCHDescriptor;
SourceLocation CurLoc;
+ llvm::MDNode *CurInlinedAt = nullptr;
llvm::DIType *VTablePtrType = nullptr;
llvm::DIType *ClassTy = nullptr;
llvm::DICompositeType *ObjTy = nullptr;
@@ -124,7 +125,7 @@ class CGDebugInfo {
/// Cache declarations relevant to DW_TAG_imported_declarations (C++
/// using declarations) that aren't covered by other more specific caches.
llvm::DenseMap<const Decl *, llvm::TrackingMDRef> DeclCache;
- llvm::DenseMap<const NamespaceDecl *, llvm::TrackingMDRef> NameSpaceCache;
+ llvm::DenseMap<const NamespaceDecl *, llvm::TrackingMDRef> NamespaceCache;
llvm::DenseMap<const NamespaceAliasDecl *, llvm::TrackingMDRef>
NamespaceAliasCache;
llvm::DenseMap<const Decl *, llvm::TypedTrackingMDRef<llvm::DIDerivedType>>
@@ -193,8 +194,9 @@ class CGDebugInfo {
getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F);
/// \return debug info descriptor for vtable.
llvm::DIType *getOrCreateVTablePtrType(llvm::DIFile *F);
+
/// \return namespace descriptor for the given namespace decl.
- llvm::DINamespace *getOrCreateNameSpace(const NamespaceDecl *N);
+ llvm::DINamespace *getOrCreateNamespace(const NamespaceDecl *N);
llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty,
QualType PointeeTy, llvm::DIFile *F);
llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache);
@@ -292,6 +294,15 @@ class CGDebugInfo {
/// Create a new lexical block node and push it on the stack.
void CreateLexicalBlock(SourceLocation Loc);
+ /// If target-specific LLVM \p AddressSpace directly maps to target-specific
+ /// DWARF address space, appends extended dereferencing mechanism to complex
+ /// expression \p Expr. Otherwise, does nothing.
+ ///
+ /// Extended dereferencing mechanism is has the following format:
+ /// DW_OP_constu <DWARF Address Space> DW_OP_swap DW_OP_xderef
+ void AppendAddressSpaceXDeref(unsigned AddressSpace,
+ SmallVectorImpl<int64_t> &Expr) const;
+
public:
CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
@@ -320,6 +331,17 @@ public:
/// ignored.
void setLocation(SourceLocation Loc);
+ /// Return the current source location. This does not necessarily correspond
+ /// to the IRBuilder's current DebugLoc.
+ SourceLocation getLocation() const { return CurLoc; }
+
+ /// Update the current inline scope. All subsequent calls to \p EmitLocation
+ /// will create a location with this inlinedAt field.
+ void setInlinedAt(llvm::MDNode *InlinedAt) { CurInlinedAt = InlinedAt; }
+
+ /// \return the current inline scope.
+ llvm::MDNode *getInlinedAt() const { return CurInlinedAt; }
+
// Converts a SourceLocation to a DebugLoc
llvm::DebugLoc SourceLocToDebugLoc(SourceLocation Loc);
@@ -336,11 +358,16 @@ public:
SourceLocation ScopeLoc, QualType FnType,
llvm::Function *Fn, CGBuilderTy &Builder);
+ /// Start a new scope for an inlined function.
+ void EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD);
+ /// End an inlined function scope.
+ void EmitInlineFunctionEnd(CGBuilderTy &Builder);
+
/// Emit debug info for a function declaration.
void EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, QualType FnType);
/// Constructs the debug code for exiting a function.
- void EmitFunctionEnd(CGBuilderTy &Builder);
+ void EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn);
/// Emit metadata to indicate the beginning of a new lexical block
/// and push the block onto the stack.
@@ -409,9 +436,21 @@ public:
void completeType(const RecordDecl *RD);
void completeRequiredType(const RecordDecl *RD);
void completeClassData(const RecordDecl *RD);
+ void completeClass(const RecordDecl *RD);
void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
-
+ void completeUnusedClass(const CXXRecordDecl &D);
+
+ /// Create debug info for a macro defined by a #define directive or a macro
+ /// undefined by a #undef directive.
+ llvm::DIMacro *CreateMacro(llvm::DIMacroFile *Parent, unsigned MType,
+ SourceLocation LineLoc, StringRef Name,
+ StringRef Value);
+
+ /// Create debug info for a file referenced by an #include directive.
+ llvm::DIMacroFile *CreateTempMacroFile(llvm::DIMacroFile *Parent,
+ SourceLocation LineLoc,
+ SourceLocation FileLoc);
private:
/// Emit call to llvm.dbg.declare for a variable declaration.
void EmitDeclare(const VarDecl *decl, llvm::Value *AI,
@@ -491,11 +530,18 @@ private:
llvm::DIDerivedType *
getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D);
+ /// Helper that either creates a forward declaration or a stub.
+ llvm::DISubprogram *getFunctionFwdDeclOrStub(GlobalDecl GD, bool Stub);
+
/// Create a subprogram describing the forward declaration
- /// represented in the given FunctionDecl.
- llvm::DISubprogram *getFunctionForwardDeclaration(const FunctionDecl *FD);
+ /// represented in the given FunctionDecl wrapped in a GlobalDecl.
+ llvm::DISubprogram *getFunctionForwardDeclaration(GlobalDecl GD);
+
+ /// Create a DISubprogram describing the function
+ /// represented in the given FunctionDecl wrapped in a GlobalDecl.
+ llvm::DISubprogram *getFunctionStub(GlobalDecl GD);
- /// Create a global variable describing the forward decalration
+ /// Create a global variable describing the forward declaration
/// represented in the given VarDecl.
llvm::DIGlobalVariable *
getGlobalVariableForwardDeclaration(const VarDecl *VD);
@@ -622,6 +668,20 @@ public:
};
+/// A scoped helper to set the current debug location to an inlined location.
+class ApplyInlineDebugLocation {
+ SourceLocation SavedLocation;
+ CodeGenFunction *CGF;
+
+public:
+ /// Set up the CodeGenFunction's DebugInfo to produce inline locations for the
+ /// function \p InlinedFn. The current debug location becomes the inlined call
+ /// site of the inlined function.
+ ApplyInlineDebugLocation(CodeGenFunction &CGF, GlobalDecl InlinedFn);
+ /// Restore everything back to the orginial state.
+ ~ApplyInlineDebugLocation();
+};
+
} // namespace CodeGen
} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp
index 0a88b23..2351786 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp
@@ -11,14 +11,15 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenFunction.h"
#include "CGBlocks.h"
#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGDebugInfo.h"
#include "CGOpenCLRuntime.h"
#include "CGOpenMPRuntime.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
+#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
@@ -50,6 +51,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::TemplateTypeParm:
case Decl::UnresolvedUsingValue:
case Decl::NonTypeTemplateParm:
+ case Decl::CXXDeductionGuide:
case Decl::CXXMethod:
case Decl::CXXConstructor:
case Decl::CXXDestructor:
@@ -151,7 +153,14 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
/// EmitVarDecl - This method handles emission of any variable declaration
/// inside a function, including static vars etc.
void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
- if (D.isStaticLocal()) {
+ if (D.hasExternalStorage())
+ // Don't emit it now, allow it to be emitted lazily on its first use.
+ return;
+
+ // Some function-scope variable does not have static storage but still
+ // needs to be emitted like a static variable, e.g. a function-scope
+ // variable in constant address space in OpenCL.
+ if (D.getStorageDuration() != SD_Automatic) {
llvm::GlobalValue::LinkageTypes Linkage =
CGM.getLLVMLinkageVarDefinition(&D, /*isConstant=*/false);
@@ -162,10 +171,6 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
return EmitStaticVarDecl(D, Linkage);
}
- if (D.hasExternalStorage())
- // Don't emit it now, allow it to be emitted lazily on its first use.
- return;
-
if (D.getType().getAddressSpace() == LangAS::opencl_local)
return CGM.getOpenCLRuntime().EmitWorkGroupLocalVarDecl(*this, D);
@@ -216,8 +221,8 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
Name = getStaticDeclName(*this, D);
llvm::Type *LTy = getTypes().ConvertTypeForMem(Ty);
- unsigned AddrSpace =
- GetGlobalVarAddressSpace(&D, getContext().getTargetAddressSpace(Ty));
+ unsigned AS = GetGlobalVarAddressSpace(&D);
+ unsigned TargetAS = getContext().getTargetAddressSpace(AS);
// Local address space cannot have an initializer.
llvm::Constant *Init = nullptr;
@@ -226,12 +231,9 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
else
Init = llvm::UndefValue::get(LTy);
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(getModule(), LTy,
- Ty.isConstant(getContext()), Linkage,
- Init, Name, nullptr,
- llvm::GlobalVariable::NotThreadLocal,
- AddrSpace);
+ llvm::GlobalVariable *GV = new llvm::GlobalVariable(
+ getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name,
+ nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
setGlobalVisibility(GV, &D);
@@ -249,11 +251,12 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
}
// Make sure the result is of the correct type.
- unsigned ExpectedAddrSpace = getContext().getTargetAddressSpace(Ty);
+ unsigned ExpectedAS = Ty.getAddressSpace();
llvm::Constant *Addr = GV;
- if (AddrSpace != ExpectedAddrSpace) {
- llvm::PointerType *PTy = llvm::PointerType::get(LTy, ExpectedAddrSpace);
- Addr = llvm::ConstantExpr::getAddrSpaceCast(GV, PTy);
+ if (AS != ExpectedAS) {
+ Addr = getTargetCodeGenInfo().performAddrSpaceCast(
+ *this, GV, AS, ExpectedAS,
+ LTy->getPointerTo(getContext().getTargetAddressSpace(ExpectedAS)));
}
setStaticLocalDeclAddress(&D, Addr);
@@ -401,6 +404,13 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
if (D.hasAttr<AnnotateAttr>())
CGM.AddGlobalAnnotations(&D, var);
+ if (auto *SA = D.getAttr<PragmaClangBSSSectionAttr>())
+ var->addAttribute("bss-section", SA->getName());
+ if (auto *SA = D.getAttr<PragmaClangDataSectionAttr>())
+ var->addAttribute("data-section", SA->getName());
+ if (auto *SA = D.getAttr<PragmaClangRodataSectionAttr>())
+ var->addAttribute("rodata-section", SA->getName());
+
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
var->setSection(SA->getName());
@@ -671,6 +681,27 @@ static void drillIntoBlockVariable(CodeGenFunction &CGF,
lvalue.setAddress(CGF.emitBlockByrefAddress(lvalue.getAddress(), var));
}
+void CodeGenFunction::EmitNullabilityCheck(LValue LHS, llvm::Value *RHS,
+ SourceLocation Loc) {
+ if (!SanOpts.has(SanitizerKind::NullabilityAssign))
+ return;
+
+ auto Nullability = LHS.getType()->getNullability(getContext());
+ if (!Nullability || *Nullability != NullabilityKind::NonNull)
+ return;
+
+ // Check if the right hand side of the assignment is nonnull, if the left
+ // hand side must be nonnull.
+ SanitizerScope SanScope(this);
+ llvm::Value *IsNotNull = Builder.CreateIsNotNull(RHS);
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(LHS.getType()),
+ llvm::ConstantInt::get(Int8Ty, 0), // The LogAlignment info is unused.
+ llvm::ConstantInt::get(Int8Ty, TCK_NonnullAssign)};
+ EmitCheck({{IsNotNull, SanitizerKind::NullabilityAssign}},
+ SanitizerHandler::TypeMismatch, StaticData, RHS);
+}
+
void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
LValue lvalue, bool capturedByInit) {
Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
@@ -678,6 +709,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
llvm::Value *value = EmitScalarExpr(init);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
+ EmitNullabilityCheck(lvalue, value, init->getExprLoc());
EmitStoreThroughLValue(RValue::get(value), lvalue, true);
return;
}
@@ -766,6 +798,8 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
+ EmitNullabilityCheck(lvalue, value, init->getExprLoc());
+
// If the variable might have been accessed by its initializer, we
// might have to initialize with a barrier. We have to do this for
// both __weak and __strong, but __weak got filtered out above.
@@ -899,7 +933,7 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size,
return nullptr;
llvm::Value *SizeV = llvm::ConstantInt::get(Int64Ty, Size);
- Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
+ Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy);
llvm::CallInst *C =
Builder.CreateCall(CGM.getLLVMLifetimeStartFn(), {SizeV, Addr});
C->setDoesNotThrow();
@@ -907,7 +941,7 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size,
}
void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) {
- Addr = Builder.CreateBitCast(Addr, Int8PtrTy);
+ Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy);
llvm::CallInst *C =
Builder.CreateCall(CGM.getLLVMLifetimeEndFn(), {Size, Addr});
C->setDoesNotThrow();
@@ -918,6 +952,7 @@ void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) {
CodeGenFunction::AutoVarEmission
CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
QualType Ty = D.getType();
+ assert(Ty.getAddressSpace() == LangAS::Default);
AutoVarEmission emission(D);
@@ -1010,8 +1045,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// Create the alloca. Note that we set the name separately from
// building the instruction so that it's there even in no-asserts
// builds.
- address = CreateTempAlloca(allocaTy, allocaAlignment);
- address.getPointer()->setName(D.getName());
+ address = CreateTempAlloca(allocaTy, allocaAlignment, D.getName());
// Don't emit lifetime markers for MSVC catch parameters. The lifetime of
// the catch parameter starts in the catchpad instruction, and we can't
@@ -1022,11 +1056,21 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// Emit a lifetime intrinsic if meaningful. There's no point in doing this
// if we don't have a valid insertion point (?).
if (HaveInsertPoint() && !IsMSCatchParam) {
- // goto or switch-case statements can break lifetime into several
- // regions which need more efforts to handle them correctly. PR28267
- // This is rare case, but it's better just omit intrinsics than have
- // them incorrectly placed.
- if (!Bypasses.IsBypassed(&D)) {
+ // If there's a jump into the lifetime of this variable, its lifetime
+ // gets broken up into several regions in IR, which requires more work
+ // to handle correctly. For now, just omit the intrinsics; this is a
+ // rare case, and it's better to just be conservatively correct.
+ // PR28267.
+ //
+ // We have to do this in all language modes if there's a jump past the
+ // declaration. We also have to do it in C if there's a jump to an
+ // earlier point in the current block because non-VLA lifetimes begin as
+ // soon as the containing block is entered, not when its variables
+ // actually come into scope; suppressing the lifetime annotations
+ // completely in this case is unnecessarily pessimistic, but again, this
+ // is rare.
+ if (!Bypasses.IsBypassed(&D) &&
+ !(!getLangOpts().CPlusPlus && hasLabelBeenSeenInCurrentScope())) {
uint64_t size = CGM.getDataLayout().getTypeAllocSize(allocaTy);
emission.SizeForLifetimeMarkers =
EmitLifetimeStart(size, address.getPointer());
@@ -1061,10 +1105,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
llvm::Type *llvmTy = ConvertTypeForMem(elementType);
// Allocate memory for the array.
- llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla");
- vla->setAlignment(alignment.getQuantity());
-
- address = Address(vla, alignment);
+ address = CreateTempAlloca(llvmTy, alignment, "vla", elementCount);
}
setAddrOfLocalVar(&D, address);
@@ -1083,6 +1124,12 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
if (D.hasAttr<AnnotateAttr>())
EmitVarAnnotations(&D, address.getPointer());
+ // Make sure we call @llvm.lifetime.end.
+ if (emission.useLifetimeMarkers())
+ EHStack.pushCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker,
+ emission.getAllocatedAddress(),
+ emission.getSizeForLifetimeMarkers());
+
return emission;
}
@@ -1373,13 +1420,6 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
const VarDecl &D = *emission.Variable;
- // Make sure we call @llvm.lifetime.end. This needs to happen
- // *last*, so the cleanup needs to be pushed *first*.
- if (emission.useLifetimeMarkers())
- EHStack.pushCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker,
- emission.getAllocatedAddress(),
- emission.getSizeForLifetimeMarkers());
-
// Check the type for a cleanup.
if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
emitAutoVarTypeCleanup(emission, dtorKind);
@@ -1691,17 +1731,19 @@ void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
/// Lazily declare the @llvm.lifetime.start intrinsic.
llvm::Constant *CodeGenModule::getLLVMLifetimeStartFn() {
- if (LifetimeStartFn) return LifetimeStartFn;
+ if (LifetimeStartFn)
+ return LifetimeStartFn;
LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(),
- llvm::Intrinsic::lifetime_start);
+ llvm::Intrinsic::lifetime_start, AllocaInt8PtrTy);
return LifetimeStartFn;
}
/// Lazily declare the @llvm.lifetime.end intrinsic.
llvm::Constant *CodeGenModule::getLLVMLifetimeEndFn() {
- if (LifetimeEndFn) return LifetimeEndFn;
+ if (LifetimeEndFn)
+ return LifetimeEndFn;
LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(),
- llvm::Intrinsic::lifetime_end);
+ llvm::Intrinsic::lifetime_end, AllocaInt8PtrTy);
return LifetimeEndFn;
}
@@ -1816,6 +1858,10 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
lt = Qualifiers::OCL_ExplicitNone;
}
+ // Load objects passed indirectly.
+ if (Arg.isIndirect() && !ArgVal)
+ ArgVal = Builder.CreateLoad(DeclPtr);
+
if (lt == Qualifiers::OCL_Strong) {
if (!isConsumed) {
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
@@ -1869,6 +1915,19 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
if (D.hasAttr<AnnotateAttr>())
EmitVarAnnotations(&D, DeclPtr.getPointer());
+
+ // We can only check return value nullability if all arguments to the
+ // function satisfy their nullability preconditions. This makes it necessary
+ // to emit null checks for args in the function body itself.
+ if (requiresReturnValueNullabilityCheck()) {
+ auto Nullability = Ty->getNullability(getContext());
+ if (Nullability && *Nullability == NullabilityKind::NonNull) {
+ SanitizerScope SanScope(this);
+ RetValNullabilityPrecondition =
+ Builder.CreateAnd(RetValNullabilityPrecondition,
+ Builder.CreateIsNotNull(Arg.getAnyValue()));
+ }
+ }
}
void CodeGenModule::EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D,
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp
index f56e182..d8768be 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -237,7 +237,7 @@ void CodeGenFunction::registerGlobalDtorWithAtExit(const VarDecl &VD,
llvm::FunctionType::get(IntTy, dtorStub->getType(), false);
llvm::Constant *atexit =
- CGM.CreateRuntimeFunction(atexitTy, "atexit", llvm::AttributeSet(),
+ CGM.CreateRuntimeFunction(atexitTy, "atexit", llvm::AttributeList(),
/*Local=*/true);
if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit))
atexitFn->setDoesNotThrow();
@@ -571,9 +571,10 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
FinishFunction();
}
-void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
- const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
- &DtorsAndObjects) {
+void CodeGenFunction::GenerateCXXGlobalDtorsFunc(
+ llvm::Function *Fn,
+ const std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>>
+ &DtorsAndObjects) {
{
auto NL = ApplyDebugLocation::CreateEmpty(*this);
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
@@ -602,9 +603,9 @@ llvm::Function *CodeGenFunction::generateDestroyHelper(
Address addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray, const VarDecl *VD) {
FunctionArgList args;
- ImplicitParamDecl dst(getContext(), nullptr, SourceLocation(), nullptr,
- getContext().VoidPtrTy);
- args.push_back(&dst);
+ ImplicitParamDecl Dst(getContext(), getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
+ args.push_back(&Dst);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(getContext().VoidTy, args);
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp
index f908bf2..40ae092 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp
@@ -180,8 +180,8 @@ static const EHPersonality &getObjCXXPersonality(const llvm::Triple &T,
// The GCC runtime's personality function inherently doesn't support
// mixed EH. Use the C++ personality just to avoid returning null.
case ObjCRuntime::GCC:
- case ObjCRuntime::ObjFW: // XXX: this will change soon
- return EHPersonality::GNU_ObjC;
+ case ObjCRuntime::ObjFW:
+ return getObjCPersonality(T, L);
case ObjCRuntime::GNUstep:
return EHPersonality::GNU_ObjCXX;
}
@@ -231,7 +231,7 @@ static llvm::Constant *getPersonalityFn(CodeGenModule &CGM,
const EHPersonality &Personality) {
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true),
Personality.PersonalityFn,
- llvm::AttributeSet(), /*Local=*/true);
+ llvm::AttributeList(), /*Local=*/true);
}
static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM,
@@ -765,8 +765,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
llvm::BasicBlock *lpad = createBasicBlock("lpad");
EmitBlock(lpad);
- llvm::LandingPadInst *LPadInst = Builder.CreateLandingPad(
- llvm::StructType::get(Int8PtrTy, Int32Ty, nullptr), 0);
+ llvm::LandingPadInst *LPadInst =
+ Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0);
llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0);
Builder.CreateStore(LPadExn, getExceptionSlot());
@@ -1310,8 +1310,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
if (!CurFn->hasPersonalityFn())
CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality));
- llvm::LandingPadInst *LPadInst = Builder.CreateLandingPad(
- llvm::StructType::get(Int8PtrTy, Int32Ty, nullptr), 0);
+ llvm::LandingPadInst *LPadInst =
+ Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0);
LPadInst->addClause(getCatchAllValue(*this));
llvm::Value *Exn = nullptr;
@@ -1387,8 +1387,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
llvm::Value *Exn = getExceptionFromSlot();
llvm::Value *Sel = getSelectorFromSlot();
- llvm::Type *LPadType = llvm::StructType::get(Exn->getType(),
- Sel->getType(), nullptr);
+ llvm::Type *LPadType = llvm::StructType::get(Exn->getType(), Sel->getType());
llvm::Value *LPadVal = llvm::UndefValue::get(LPadType);
LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val");
LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val");
@@ -1650,39 +1649,29 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
// parameters. Win32 filters take no parameters.
if (IsFilter) {
Args.push_back(ImplicitParamDecl::Create(
- getContext(), nullptr, StartLoc,
+ getContext(), /*DC=*/nullptr, StartLoc,
&getContext().Idents.get("exception_pointers"),
- getContext().VoidPtrTy));
+ getContext().VoidPtrTy, ImplicitParamDecl::Other));
} else {
Args.push_back(ImplicitParamDecl::Create(
- getContext(), nullptr, StartLoc,
+ getContext(), /*DC=*/nullptr, StartLoc,
&getContext().Idents.get("abnormal_termination"),
- getContext().UnsignedCharTy));
+ getContext().UnsignedCharTy, ImplicitParamDecl::Other));
}
Args.push_back(ImplicitParamDecl::Create(
- getContext(), nullptr, StartLoc,
- &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
+ getContext(), /*DC=*/nullptr, StartLoc,
+ &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy,
+ ImplicitParamDecl::Other));
}
QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy;
- llvm::Function *ParentFn = ParentCGF.CurFn;
const CGFunctionInfo &FnInfo =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args);
llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
llvm::Function *Fn = llvm::Function::Create(
FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule());
- // The filter is either in the same comdat as the function, or it's internal.
- if (llvm::Comdat *C = ParentFn->getComdat()) {
- Fn->setComdat(C);
- } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {
- llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());
- ParentFn->setComdat(C);
- Fn->setComdat(C);
- } else {
- Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
- }
IsOutlinedSEHHelper = true;
@@ -1758,7 +1747,7 @@ void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF,
// };
// int exceptioncode = exception_pointers->ExceptionRecord->ExceptionCode;
llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
- llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy, nullptr);
+ llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy);
llvm::Value *Ptrs = Builder.CreateBitCast(SEHInfo, PtrsTy->getPointerTo());
llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, Ptrs, 0);
Rec = Builder.CreateAlignedLoad(Rec, getPointerAlign());
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp
index e5e34a5..9572bd3 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp
@@ -61,17 +61,39 @@ llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) {
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
/// block.
Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
- const Twine &Name) {
- auto Alloca = CreateTempAlloca(Ty, Name);
+ const Twine &Name,
+ llvm::Value *ArraySize,
+ bool CastToDefaultAddrSpace) {
+ auto Alloca = CreateTempAlloca(Ty, Name, ArraySize);
Alloca->setAlignment(Align.getQuantity());
- return Address(Alloca, Align);
-}
-
-/// CreateTempAlloca - This creates a alloca and inserts it into the entry
-/// block.
+ llvm::Value *V = Alloca;
+ // Alloca always returns a pointer in alloca address space, which may
+ // be different from the type defined by the language. For example,
+ // in C++ the auto variables are in the default address space. Therefore
+ // cast alloca to the default address space when necessary.
+ if (CastToDefaultAddrSpace && getASTAllocaAddressSpace() != LangAS::Default) {
+ auto DestAddrSpace = getContext().getTargetAddressSpace(LangAS::Default);
+ auto CurIP = Builder.saveIP();
+ Builder.SetInsertPoint(AllocaInsertPt);
+ V = getTargetHooks().performAddrSpaceCast(
+ *this, V, getASTAllocaAddressSpace(), LangAS::Default,
+ Ty->getPointerTo(DestAddrSpace), /*non-null*/ true);
+ Builder.restoreIP(CurIP);
+ }
+
+ return Address(V, Align);
+}
+
+/// CreateTempAlloca - This creates an alloca and inserts it into the entry
+/// block if \p ArraySize is nullptr, otherwise inserts it at the current
+/// insertion point of the builder.
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
- const Twine &Name) {
- return new llvm::AllocaInst(Ty, nullptr, Name, AllocaInsertPt);
+ const Twine &Name,
+ llvm::Value *ArraySize) {
+ if (ArraySize)
+ return Builder.CreateAlloca(Ty, ArraySize, Name);
+ return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
+ ArraySize, Name, AllocaInsertPt);
}
/// CreateDefaultAlignTempAlloca - This creates an alloca with the
@@ -98,14 +120,18 @@ Address CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) {
return CreateTempAlloca(ConvertType(Ty), Align, Name);
}
-Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name) {
+Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name,
+ bool CastToDefaultAddrSpace) {
// FIXME: Should we prefer the preferred type alignment here?
- return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name);
+ return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name,
+ CastToDefaultAddrSpace);
}
Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align,
- const Twine &Name) {
- return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name);
+ const Twine &Name,
+ bool CastToDefaultAddrSpace) {
+ return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, nullptr,
+ CastToDefaultAddrSpace);
}
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
@@ -315,9 +341,10 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
}
}
-static Address
-createReferenceTemporary(CodeGenFunction &CGF,
- const MaterializeTemporaryExpr *M, const Expr *Inner) {
+static Address createReferenceTemporary(CodeGenFunction &CGF,
+ const MaterializeTemporaryExpr *M,
+ const Expr *Inner) {
+ auto &TCG = CGF.getTargetHooks();
switch (M->getStorageDuration()) {
case SD_FullExpression:
case SD_Automatic: {
@@ -330,13 +357,24 @@ createReferenceTemporary(CodeGenFunction &CGF,
(Ty->isArrayType() || Ty->isRecordType()) &&
CGF.CGM.isTypeConstant(Ty, true))
if (llvm::Constant *Init = CGF.CGM.EmitConstantExpr(Inner, Ty, &CGF)) {
- auto *GV = new llvm::GlobalVariable(
- CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp");
- CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty);
- GV->setAlignment(alignment.getQuantity());
- // FIXME: Should we put the new global into a COMDAT?
- return Address(GV, alignment);
+ if (auto AddrSpace = CGF.getTarget().getConstantAddressSpace()) {
+ auto AS = AddrSpace.getValue();
+ auto *GV = new llvm::GlobalVariable(
+ CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp", nullptr,
+ llvm::GlobalValue::NotThreadLocal,
+ CGF.getContext().getTargetAddressSpace(AS));
+ CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty);
+ GV->setAlignment(alignment.getQuantity());
+ llvm::Constant *C = GV;
+ if (AS != LangAS::Default)
+ C = TCG.performAddrSpaceCast(
+ CGF.CGM, GV, AS, LangAS::Default,
+ GV->getValueType()->getPointerTo(
+ CGF.getContext().getTargetAddressSpace(LangAS::Default)));
+ // FIXME: Should we put the new global into a COMDAT?
+ return Address(C, alignment);
+ }
}
return CGF.CreateMemTemp(Ty, "ref.tmp");
}
@@ -373,12 +411,14 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
// dynamic initialization or a cleanup and we can just return the address
// of the temporary.
if (Var->hasInitializer())
- return MakeAddrLValue(Object, M->getType(), AlignmentSource::Decl);
+ return MakeAddrLValue(Object, M->getType(),
+ LValueBaseInfo(AlignmentSource::Decl, false));
Var->setInitializer(CGM.EmitNullConstant(E->getType()));
}
LValue RefTempDst = MakeAddrLValue(Object, M->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl,
+ false));
switch (getEvaluationKind(E->getType())) {
default: llvm_unreachable("expected scalar or aggregate expression");
@@ -415,9 +455,11 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
// Create and initialize the reference temporary.
Address Object = createReferenceTemporary(*this, M, E);
- if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object.getPointer())) {
+ if (auto *Var = dyn_cast<llvm::GlobalVariable>(
+ Object.getPointer()->stripPointerCasts())) {
Object = Address(llvm::ConstantExpr::getBitCast(
- Var, ConvertTypeForMem(E->getType())->getPointerTo()),
+ cast<llvm::Constant>(Object.getPointer()),
+ ConvertTypeForMem(E->getType())->getPointerTo()),
Object.getAlignment());
// If the temporary is a global and has a constant initializer or is a
// constant temporary that we promoted to a global, we may have already
@@ -464,7 +506,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
case SubobjectAdjustment::FieldAdjustment: {
LValue LV = MakeAddrLValue(Object, E->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
LV = EmitLValueForField(LV, Adjustment.Field);
assert(LV.isSimple() &&
"materialized temporary field is not a simple lvalue");
@@ -481,7 +523,8 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
}
}
- return MakeAddrLValue(Object, M->getType(), AlignmentSource::Decl);
+ return MakeAddrLValue(Object, M->getType(),
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
RValue
@@ -534,7 +577,8 @@ bool CodeGenFunction::sanitizePerformTypeCheck() const {
void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::Value *Ptr, QualType Ty,
- CharUnits Alignment, bool SkipNullCheck) {
+ CharUnits Alignment,
+ SanitizerSet SkippedChecks) {
if (!sanitizePerformTypeCheck())
return;
@@ -544,31 +588,52 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
if (Ptr->getType()->getPointerAddressSpace())
return;
+ // Don't check pointers to volatile data. The behavior here is implementation-
+ // defined.
+ if (Ty.isVolatileQualified())
+ return;
+
SanitizerScope SanScope(this);
SmallVector<std::pair<llvm::Value *, SanitizerMask>, 3> Checks;
llvm::BasicBlock *Done = nullptr;
+ // Quickly determine whether we have a pointer to an alloca. It's possible
+ // to skip null checks, and some alignment checks, for these pointers. This
+ // can reduce compile-time significantly.
+ auto PtrToAlloca =
+ dyn_cast<llvm::AllocaInst>(Ptr->stripPointerCastsNoFollowAliases());
+
bool AllowNullPointers = TCK == TCK_DowncastPointer || TCK == TCK_Upcast ||
TCK == TCK_UpcastToVirtualBase;
if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
- !SkipNullCheck) {
+ !SkippedChecks.has(SanitizerKind::Null) && !PtrToAlloca) {
// The glvalue must not be an empty glvalue.
llvm::Value *IsNonNull = Builder.CreateIsNotNull(Ptr);
- if (AllowNullPointers) {
- // When performing pointer casts, it's OK if the value is null.
- // Skip the remaining checks in that case.
- Done = createBasicBlock("null");
- llvm::BasicBlock *Rest = createBasicBlock("not.null");
- Builder.CreateCondBr(IsNonNull, Rest, Done);
- EmitBlock(Rest);
- } else {
- Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null));
+ // The IR builder can constant-fold the null check if the pointer points to
+ // a constant.
+ bool PtrIsNonNull =
+ IsNonNull == llvm::ConstantInt::getTrue(getLLVMContext());
+
+ // Skip the null check if the pointer is known to be non-null.
+ if (!PtrIsNonNull) {
+ if (AllowNullPointers) {
+ // When performing pointer casts, it's OK if the value is null.
+ // Skip the remaining checks in that case.
+ Done = createBasicBlock("null");
+ llvm::BasicBlock *Rest = createBasicBlock("not.null");
+ Builder.CreateCondBr(IsNonNull, Rest, Done);
+ EmitBlock(Rest);
+ } else {
+ Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::Null));
+ }
}
}
- if (SanOpts.has(SanitizerKind::ObjectSize) && !Ty->isIncompleteType()) {
+ if (SanOpts.has(SanitizerKind::ObjectSize) &&
+ !SkippedChecks.has(SanitizerKind::ObjectSize) &&
+ !Ty->isIncompleteType()) {
uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity();
// The glvalue must refer to a large enough storage region.
@@ -578,22 +643,25 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::Type *Tys[2] = { IntPtrTy, Int8PtrTy };
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, Tys);
llvm::Value *Min = Builder.getFalse();
+ llvm::Value *NullIsUnknown = Builder.getFalse();
llvm::Value *CastAddr = Builder.CreateBitCast(Ptr, Int8PtrTy);
- llvm::Value *LargeEnough =
- Builder.CreateICmpUGE(Builder.CreateCall(F, {CastAddr, Min}),
- llvm::ConstantInt::get(IntPtrTy, Size));
+ llvm::Value *LargeEnough = Builder.CreateICmpUGE(
+ Builder.CreateCall(F, {CastAddr, Min, NullIsUnknown}),
+ llvm::ConstantInt::get(IntPtrTy, Size));
Checks.push_back(std::make_pair(LargeEnough, SanitizerKind::ObjectSize));
}
uint64_t AlignVal = 0;
- if (SanOpts.has(SanitizerKind::Alignment)) {
+ if (SanOpts.has(SanitizerKind::Alignment) &&
+ !SkippedChecks.has(SanitizerKind::Alignment)) {
AlignVal = Alignment.getQuantity();
if (!Ty->isIncompleteType() && !AlignVal)
AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
// The glvalue must be suitably aligned.
- if (AlignVal) {
+ if (AlignVal > 1 &&
+ (!PtrToAlloca || PtrToAlloca->getAlignment() < AlignVal)) {
llvm::Value *Align =
Builder.CreateAnd(Builder.CreatePtrToInt(Ptr, IntPtrTy),
llvm::ConstantInt::get(IntPtrTy, AlignVal - 1));
@@ -624,6 +692,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
// or call a non-static member function
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
if (SanOpts.has(SanitizerKind::Vptr) &&
+ !SkippedChecks.has(SanitizerKind::Vptr) &&
(TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference ||
TCK == TCK_UpcastToVirtualBase) &&
@@ -825,7 +894,7 @@ void CodeGenModule::EmitExplicitCastExprType(const ExplicitCastExpr *E,
/// EmitPointerWithAlignment - Given an expression of pointer type, try to
/// derive a more accurate bound on the alignment of the pointer.
Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
- AlignmentSource *Source) {
+ LValueBaseInfo *BaseInfo) {
// We allow this with ObjC object pointers because of fragile ABIs.
assert(E->getType()->isPointerType() ||
E->getType()->isObjCObjectPointerType());
@@ -844,16 +913,20 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
if (PtrTy->getPointeeType()->isVoidType())
break;
- AlignmentSource InnerSource;
- Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), &InnerSource);
- if (Source) *Source = InnerSource;
+ LValueBaseInfo InnerInfo;
+ Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), &InnerInfo);
+ if (BaseInfo) *BaseInfo = InnerInfo;
// If this is an explicit bitcast, and the source l-value is
// opaque, honor the alignment of the casted-to type.
if (isa<ExplicitCastExpr>(CE) &&
- InnerSource != AlignmentSource::Decl) {
- Addr = Address(Addr.getPointer(),
- getNaturalPointeeTypeAlignment(E->getType(), Source));
+ InnerInfo.getAlignmentSource() != AlignmentSource::Decl) {
+ LValueBaseInfo ExpInfo;
+ CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(),
+ &ExpInfo);
+ if (BaseInfo)
+ BaseInfo->mergeForCast(ExpInfo);
+ Addr = Address(Addr.getPointer(), Align);
}
if (SanOpts.has(SanitizerKind::CFIUnrelatedCast) &&
@@ -871,12 +944,12 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
// Array-to-pointer decay.
case CK_ArrayToPointerDecay:
- return EmitArrayToPointerDecay(CE->getSubExpr(), Source);
+ return EmitArrayToPointerDecay(CE->getSubExpr(), BaseInfo);
// Derived-to-base conversions.
case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
- Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), Source);
+ Address Addr = EmitPointerWithAlignment(CE->getSubExpr(), BaseInfo);
auto Derived = CE->getSubExpr()->getType()->getPointeeCXXRecordDecl();
return GetAddressOfBaseClass(Addr, Derived,
CE->path_begin(), CE->path_end(),
@@ -895,7 +968,7 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
if (UO->getOpcode() == UO_AddrOf) {
LValue LV = EmitLValue(UO->getSubExpr());
- if (Source) *Source = LV.getAlignmentSource();
+ if (BaseInfo) *BaseInfo = LV.getBaseInfo();
return LV.getAddress();
}
}
@@ -903,7 +976,7 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E,
// TODO: conditional operators, comma.
// Otherwise, use the alignment of the type.
- CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(), Source);
+ CharUnits Align = getNaturalPointeeTypeAlignment(E->getType(), BaseInfo);
return Address(EmitScalarExpr(E), Align);
}
@@ -947,15 +1020,47 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
E->getType());
}
+bool CodeGenFunction::IsWrappedCXXThis(const Expr *Obj) {
+ const Expr *Base = Obj;
+ while (!isa<CXXThisExpr>(Base)) {
+ // The result of a dynamic_cast can be null.
+ if (isa<CXXDynamicCastExpr>(Base))
+ return false;
+
+ if (const auto *CE = dyn_cast<CastExpr>(Base)) {
+ Base = CE->getSubExpr();
+ } else if (const auto *PE = dyn_cast<ParenExpr>(Base)) {
+ Base = PE->getSubExpr();
+ } else if (const auto *UO = dyn_cast<UnaryOperator>(Base)) {
+ if (UO->getOpcode() == UO_Extension)
+ Base = UO->getSubExpr();
+ else
+ return false;
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
LValue LV;
if (SanOpts.has(SanitizerKind::ArrayBounds) && isa<ArraySubscriptExpr>(E))
LV = EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E), /*Accessed*/true);
else
LV = EmitLValue(E);
- if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple())
+ if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple()) {
+ SanitizerSet SkippedChecks;
+ if (const auto *ME = dyn_cast<MemberExpr>(E)) {
+ bool IsBaseCXXThis = IsWrappedCXXThis(ME->getBase());
+ if (IsBaseCXXThis)
+ SkippedChecks.set(SanitizerKind::Alignment, true);
+ if (IsBaseCXXThis || isa<DeclRefExpr>(ME->getBase()))
+ SkippedChecks.set(SanitizerKind::Null, true);
+ }
EmitTypeCheck(TCK, E->getExprLoc(), LV.getPointer(),
- E->getType(), LV.getAlignment());
+ E->getType(), LV.getAlignment(), SkippedChecks);
+ }
return LV;
}
@@ -1033,7 +1138,19 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
const auto *cleanups = cast<ExprWithCleanups>(E);
enterFullExpression(cleanups);
RunCleanupsScope Scope(*this);
- return EmitLValue(cleanups->getSubExpr());
+ LValue LV = EmitLValue(cleanups->getSubExpr());
+ if (LV.isSimple()) {
+ // Defend against branches out of gnu statement expressions surrounded by
+ // cleanups.
+ llvm::Value *V = LV.getPointer();
+ Scope.ForceCleanup({&V});
+ return LValue::MakeAddr(Address(V, LV.getAlignment()), LV.getType(),
+ getContext(), LV.getBaseInfo(),
+ LV.getTBAAInfo());
+ }
+ // FIXME: Is it possible to create an ExprWithCleanups that produces a
+ // bitfield lvalue or some other non-simple lvalue?
+ return LV;
}
case Expr::CXXDefaultArgExprClass:
@@ -1085,6 +1202,11 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::MaterializeTemporaryExprClass:
return EmitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(E));
+
+ case Expr::CoawaitExprClass:
+ return EmitCoawaitLValue(cast<CoawaitExpr>(E));
+ case Expr::CoyieldExprClass:
+ return EmitCoyieldLValue(cast<CoyieldExpr>(E));
}
}
@@ -1203,7 +1325,7 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue,
SourceLocation Loc) {
return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
- lvalue.getType(), Loc, lvalue.getAlignmentSource(),
+ lvalue.getType(), Loc, lvalue.getBaseInfo(),
lvalue.getTBAAInfo(),
lvalue.getTBAABaseType(), lvalue.getTBAAOffset(),
lvalue.isNontemporal());
@@ -1265,40 +1387,89 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
return MDHelper.createRange(Min, End);
}
+bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
+ SourceLocation Loc) {
+ bool HasBoolCheck = SanOpts.has(SanitizerKind::Bool);
+ bool HasEnumCheck = SanOpts.has(SanitizerKind::Enum);
+ if (!HasBoolCheck && !HasEnumCheck)
+ return false;
+
+ bool IsBool = hasBooleanRepresentation(Ty) ||
+ NSAPI(CGM.getContext()).isObjCBOOLType(Ty);
+ bool NeedsBoolCheck = HasBoolCheck && IsBool;
+ bool NeedsEnumCheck = HasEnumCheck && Ty->getAs<EnumType>();
+ if (!NeedsBoolCheck && !NeedsEnumCheck)
+ return false;
+
+ // Single-bit booleans don't need to be checked. Special-case this to avoid
+ // a bit width mismatch when handling bitfield values. This is handled by
+ // EmitFromMemory for the non-bitfield case.
+ if (IsBool &&
+ cast<llvm::IntegerType>(Value->getType())->getBitWidth() == 1)
+ return false;
+
+ llvm::APInt Min, End;
+ if (!getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true, IsBool))
+ return true;
+
+ SanitizerScope SanScope(this);
+ llvm::Value *Check;
+ --End;
+ if (!Min) {
+ Check = Builder.CreateICmpULE(
+ Value, llvm::ConstantInt::get(getLLVMContext(), End));
+ } else {
+ llvm::Value *Upper = Builder.CreateICmpSLE(
+ Value, llvm::ConstantInt::get(getLLVMContext(), End));
+ llvm::Value *Lower = Builder.CreateICmpSGE(
+ Value, llvm::ConstantInt::get(getLLVMContext(), Min));
+ Check = Builder.CreateAnd(Upper, Lower);
+ }
+ llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(Ty)};
+ SanitizerMask Kind =
+ NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool;
+ EmitCheck(std::make_pair(Check, Kind), SanitizerHandler::LoadInvalidValue,
+ StaticArgs, EmitCheckValue(Value));
+ return true;
+}
+
llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
QualType Ty,
SourceLocation Loc,
- AlignmentSource AlignSource,
+ LValueBaseInfo BaseInfo,
llvm::MDNode *TBAAInfo,
QualType TBAABaseType,
uint64_t TBAAOffset,
bool isNontemporal) {
- // For better performance, handle vector loads differently.
- if (Ty->isVectorType()) {
- const llvm::Type *EltTy = Addr.getElementType();
-
- const auto *VTy = cast<llvm::VectorType>(EltTy);
-
- // Handle vectors of size 3 like size 4 for better performance.
- if (VTy->getNumElements() == 3) {
-
- // Bitcast to vec4 type.
- llvm::VectorType *vec4Ty = llvm::VectorType::get(VTy->getElementType(),
- 4);
- Address Cast = Builder.CreateElementBitCast(Addr, vec4Ty, "castToVec4");
- // Now load value.
- llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4");
-
- // Shuffle vector to get vec3.
- V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty),
- {0, 1, 2}, "extractVec");
- return EmitFromMemory(V, Ty);
+ if (!CGM.getCodeGenOpts().PreserveVec3Type) {
+ // For better performance, handle vector loads differently.
+ if (Ty->isVectorType()) {
+ const llvm::Type *EltTy = Addr.getElementType();
+
+ const auto *VTy = cast<llvm::VectorType>(EltTy);
+
+ // Handle vectors of size 3 like size 4 for better performance.
+ if (VTy->getNumElements() == 3) {
+
+ // Bitcast to vec4 type.
+ llvm::VectorType *vec4Ty =
+ llvm::VectorType::get(VTy->getElementType(), 4);
+ Address Cast = Builder.CreateElementBitCast(Addr, vec4Ty, "castToVec4");
+ // Now load value.
+ llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4");
+
+ // Shuffle vector to get vec3.
+ V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty),
+ {0, 1, 2}, "extractVec");
+ return EmitFromMemory(V, Ty);
+ }
}
}
// Atomic operations have to be done on integral types.
LValue AtomicLValue =
- LValue::MakeAddr(Addr, Ty, getContext(), AlignSource, TBAAInfo);
+ LValue::MakeAddr(Addr, Ty, getContext(), BaseInfo, TBAAInfo);
if (Ty->isAtomicType() || LValueIsSuitableForInlineAtomic(AtomicLValue)) {
return EmitAtomicLoad(AtomicLValue, Loc).getScalarVal();
}
@@ -1310,42 +1481,17 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
Load->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
}
if (TBAAInfo) {
- llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
- TBAAOffset);
- if (TBAAPath)
- CGM.DecorateInstructionWithTBAA(Load, TBAAPath,
- false /*ConvertTypeToTag*/);
+ bool MayAlias = BaseInfo.getMayAlias();
+ llvm::MDNode *TBAA = MayAlias
+ ? CGM.getTBAAInfo(getContext().CharTy)
+ : CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset);
+ if (TBAA)
+ CGM.DecorateInstructionWithTBAA(Load, TBAA, MayAlias);
}
- bool IsBool = hasBooleanRepresentation(Ty) ||
- NSAPI(CGM.getContext()).isObjCBOOLType(Ty);
- bool NeedsBoolCheck = SanOpts.has(SanitizerKind::Bool) && IsBool;
- bool NeedsEnumCheck =
- SanOpts.has(SanitizerKind::Enum) && Ty->getAs<EnumType>();
- if (NeedsBoolCheck || NeedsEnumCheck) {
- SanitizerScope SanScope(this);
- llvm::APInt Min, End;
- if (getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true, IsBool)) {
- --End;
- llvm::Value *Check;
- if (!Min)
- Check = Builder.CreateICmpULE(
- Load, llvm::ConstantInt::get(getLLVMContext(), End));
- else {
- llvm::Value *Upper = Builder.CreateICmpSLE(
- Load, llvm::ConstantInt::get(getLLVMContext(), End));
- llvm::Value *Lower = Builder.CreateICmpSGE(
- Load, llvm::ConstantInt::get(getLLVMContext(), Min));
- Check = Builder.CreateAnd(Upper, Lower);
- }
- llvm::Constant *StaticArgs[] = {
- EmitCheckSourceLocation(Loc),
- EmitCheckTypeDescriptor(Ty)
- };
- SanitizerMask Kind = NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool;
- EmitCheck(std::make_pair(Check, Kind), SanitizerHandler::LoadInvalidValue,
- StaticArgs, EmitCheckValue(Load));
- }
+ if (EmitScalarRangeCheck(Load, Ty, Loc)) {
+ // In order to prevent the optimizer from throwing away the check, don't
+ // attach range metadata to the load.
} else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
@@ -1380,37 +1526,38 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
bool Volatile, QualType Ty,
- AlignmentSource AlignSource,
+ LValueBaseInfo BaseInfo,
llvm::MDNode *TBAAInfo,
bool isInit, QualType TBAABaseType,
uint64_t TBAAOffset,
bool isNontemporal) {
- // Handle vectors differently to get better performance.
- if (Ty->isVectorType()) {
- llvm::Type *SrcTy = Value->getType();
- auto *VecTy = cast<llvm::VectorType>(SrcTy);
- // Handle vec3 special.
- if (VecTy->getNumElements() == 3) {
- // Our source is a vec3, do a shuffle vector to make it a vec4.
- llvm::Constant *Mask[] = {Builder.getInt32(0), Builder.getInt32(1),
- Builder.getInt32(2),
- llvm::UndefValue::get(Builder.getInt32Ty())};
- llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
- Value = Builder.CreateShuffleVector(Value,
- llvm::UndefValue::get(VecTy),
- MaskV, "extractVec");
- SrcTy = llvm::VectorType::get(VecTy->getElementType(), 4);
- }
- if (Addr.getElementType() != SrcTy) {
- Addr = Builder.CreateElementBitCast(Addr, SrcTy, "storetmp");
+ if (!CGM.getCodeGenOpts().PreserveVec3Type) {
+ // Handle vectors differently to get better performance.
+ if (Ty->isVectorType()) {
+ llvm::Type *SrcTy = Value->getType();
+ auto *VecTy = dyn_cast<llvm::VectorType>(SrcTy);
+ // Handle vec3 special.
+ if (VecTy && VecTy->getNumElements() == 3) {
+ // Our source is a vec3, do a shuffle vector to make it a vec4.
+ llvm::Constant *Mask[] = {Builder.getInt32(0), Builder.getInt32(1),
+ Builder.getInt32(2),
+ llvm::UndefValue::get(Builder.getInt32Ty())};
+ llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
+ Value = Builder.CreateShuffleVector(Value, llvm::UndefValue::get(VecTy),
+ MaskV, "extractVec");
+ SrcTy = llvm::VectorType::get(VecTy->getElementType(), 4);
+ }
+ if (Addr.getElementType() != SrcTy) {
+ Addr = Builder.CreateElementBitCast(Addr, SrcTy, "storetmp");
+ }
}
}
Value = EmitToMemory(Value, Ty);
LValue AtomicLValue =
- LValue::MakeAddr(Addr, Ty, getContext(), AlignSource, TBAAInfo);
+ LValue::MakeAddr(Addr, Ty, getContext(), BaseInfo, TBAAInfo);
if (Ty->isAtomicType() ||
(!isInit && LValueIsSuitableForInlineAtomic(AtomicLValue))) {
EmitAtomicStore(RValue::get(Value), AtomicLValue, isInit);
@@ -1425,18 +1572,19 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
Store->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
}
if (TBAAInfo) {
- llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
- TBAAOffset);
- if (TBAAPath)
- CGM.DecorateInstructionWithTBAA(Store, TBAAPath,
- false /*ConvertTypeToTag*/);
+ bool MayAlias = BaseInfo.getMayAlias();
+ llvm::MDNode *TBAA = MayAlias
+ ? CGM.getTBAAInfo(getContext().CharTy)
+ : CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset);
+ if (TBAA)
+ CGM.DecorateInstructionWithTBAA(Store, TBAA, MayAlias);
}
}
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
bool isInit) {
EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
- lvalue.getType(), lvalue.getAlignmentSource(),
+ lvalue.getType(), lvalue.getBaseInfo(),
lvalue.getTBAAInfo(), isInit, lvalue.getTBAABaseType(),
lvalue.getTBAAOffset(), lvalue.isNontemporal());
}
@@ -1487,10 +1635,11 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
return EmitLoadOfGlobalRegLValue(LV);
assert(LV.isBitField() && "Unknown LValue type!");
- return EmitLoadOfBitfieldLValue(LV);
+ return EmitLoadOfBitfieldLValue(LV, Loc);
}
-RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
+RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
+ SourceLocation Loc) {
const CGBitFieldInfo &Info = LV.getBitFieldInfo();
// Get the output type.
@@ -1515,7 +1664,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
"bf.clear");
}
Val = Builder.CreateIntCast(Val, ResLTy, Info.IsSigned, "bf.cast");
-
+ EmitScalarRangeCheck(Val, LV.getType(), Loc);
return RValue::get(Val);
}
@@ -1967,38 +2116,39 @@ static LValue EmitThreadPrivateVarDeclLValue(
llvm::Type *RealVarTy, SourceLocation Loc) {
Addr = CGF.CGM.getOpenMPRuntime().getAddrOfThreadPrivate(CGF, VD, Addr, Loc);
Addr = CGF.Builder.CreateElementBitCast(Addr, RealVarTy);
- return CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
+ return CGF.MakeAddrLValue(Addr, T, BaseInfo);
}
Address CodeGenFunction::EmitLoadOfReference(Address Addr,
const ReferenceType *RefTy,
- AlignmentSource *Source) {
+ LValueBaseInfo *BaseInfo) {
llvm::Value *Ptr = Builder.CreateLoad(Addr);
return Address(Ptr, getNaturalTypeAlignment(RefTy->getPointeeType(),
- Source, /*forPointee*/ true));
-
+ BaseInfo, /*forPointee*/ true));
}
LValue CodeGenFunction::EmitLoadOfReferenceLValue(Address RefAddr,
const ReferenceType *RefTy) {
- AlignmentSource Source;
- Address Addr = EmitLoadOfReference(RefAddr, RefTy, &Source);
- return MakeAddrLValue(Addr, RefTy->getPointeeType(), Source);
+ LValueBaseInfo BaseInfo;
+ Address Addr = EmitLoadOfReference(RefAddr, RefTy, &BaseInfo);
+ return MakeAddrLValue(Addr, RefTy->getPointeeType(), BaseInfo);
}
Address CodeGenFunction::EmitLoadOfPointer(Address Ptr,
const PointerType *PtrTy,
- AlignmentSource *Source) {
+ LValueBaseInfo *BaseInfo) {
llvm::Value *Addr = Builder.CreateLoad(Ptr);
- return Address(Addr, getNaturalTypeAlignment(PtrTy->getPointeeType(), Source,
+ return Address(Addr, getNaturalTypeAlignment(PtrTy->getPointeeType(),
+ BaseInfo,
/*forPointeeType=*/true));
}
LValue CodeGenFunction::EmitLoadOfPointerLValue(Address PtrAddr,
const PointerType *PtrTy) {
- AlignmentSource Source;
- Address Addr = EmitLoadOfPointer(PtrAddr, PtrTy, &Source);
- return MakeAddrLValue(Addr, PtrTy->getPointeeType(), Source);
+ LValueBaseInfo BaseInfo;
+ Address Addr = EmitLoadOfPointer(PtrAddr, PtrTy, &BaseInfo);
+ return MakeAddrLValue(Addr, PtrTy->getPointeeType(), BaseInfo);
}
static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
@@ -2024,7 +2174,8 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
if (auto RefTy = VD->getType()->getAs<ReferenceType>()) {
LV = CGF.EmitLoadOfReferenceLValue(Addr, RefTy);
} else {
- LV = CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
+ LV = CGF.MakeAddrLValue(Addr, T, BaseInfo);
}
setObjCGCLValueClass(CGF.getContext(), E, LV);
return LV;
@@ -2058,7 +2209,8 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
const Expr *E, const FunctionDecl *FD) {
llvm::Value *V = EmitFunctionDeclPointer(CGF.CGM, FD);
CharUnits Alignment = CGF.getContext().getDeclAlign(FD);
- return CGF.MakeAddrLValue(V, E->getType(), Alignment, AlignmentSource::Decl);
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
+ return CGF.MakeAddrLValue(V, E->getType(), Alignment, BaseInfo);
}
static LValue EmitCapturedFieldLValue(CodeGenFunction &CGF, const FieldDecl *FD,
@@ -2123,8 +2275,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
// Should we be using the alignment of the constant pointer we emitted?
CharUnits Alignment = getNaturalTypeAlignment(E->getType(), nullptr,
/*pointee*/ true);
-
- return MakeAddrLValue(Address(Val, Alignment), T, AlignmentSource::Decl);
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
+ return MakeAddrLValue(Address(Val, Alignment), T, BaseInfo);
}
// Check for captured variables.
@@ -2141,14 +2293,16 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
LValue CapLVal =
EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD),
CapturedStmtInfo->getContextValue());
+ bool MayAlias = CapLVal.getBaseInfo().getMayAlias();
return MakeAddrLValue(
Address(CapLVal.getPointer(), getContext().getDeclAlign(VD)),
- CapLVal.getType(), AlignmentSource::Decl);
+ CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl, MayAlias));
}
assert(isa<BlockDecl>(CurCodeDecl));
Address addr = GetAddrOfBlockDecl(VD, VD->hasAttr<BlocksAttr>());
- return MakeAddrLValue(addr, T, AlignmentSource::Decl);
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
+ return MakeAddrLValue(addr, T, BaseInfo);
}
}
@@ -2162,7 +2316,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (ND->hasAttr<WeakRefAttr>()) {
const auto *VD = cast<ValueDecl>(ND);
ConstantAddress Aliasee = CGM.GetWeakRefReference(VD);
- return MakeAddrLValue(Aliasee, T, AlignmentSource::Decl);
+ return MakeAddrLValue(Aliasee, T,
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
if (const auto *VD = dyn_cast<VarDecl>(ND)) {
@@ -2208,7 +2363,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (auto RefTy = VD->getType()->getAs<ReferenceType>()) {
LV = EmitLoadOfReferenceLValue(addr, RefTy);
} else {
- LV = MakeAddrLValue(addr, T, AlignmentSource::Decl);
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
+ LV = MakeAddrLValue(addr, T, BaseInfo);
}
bool isLocalStorage = VD->hasLocalStorage();
@@ -2253,9 +2409,9 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
QualType T = E->getSubExpr()->getType()->getPointeeType();
assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type");
- AlignmentSource AlignSource;
- Address Addr = EmitPointerWithAlignment(E->getSubExpr(), &AlignSource);
- LValue LV = MakeAddrLValue(Addr, T, AlignSource);
+ LValueBaseInfo BaseInfo;
+ Address Addr = EmitPointerWithAlignment(E->getSubExpr(), &BaseInfo);
+ LValue LV = MakeAddrLValue(Addr, T, BaseInfo);
LV.getQuals().setAddressSpace(ExprTy.getAddressSpace());
// We should not generate __weak write barrier on indirect reference
@@ -2287,7 +2443,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
(E->getOpcode() == UO_Real
? emitAddrOfRealComponent(LV.getAddress(), LV.getType())
: emitAddrOfImagComponent(LV.getAddress(), LV.getType()));
- LValue ElemLV = MakeAddrLValue(Component, T, LV.getAlignmentSource());
+ LValue ElemLV = MakeAddrLValue(Component, T, LV.getBaseInfo());
ElemLV.getQuals().addQualifiers(LV.getQuals());
return ElemLV;
}
@@ -2307,12 +2463,14 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
return MakeAddrLValue(CGM.GetAddrOfConstantStringFromLiteral(E),
- E->getType(), AlignmentSource::Decl);
+ E->getType(),
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) {
return MakeAddrLValue(CGM.GetAddrOfConstantStringFromObjCEncode(E),
- E->getType(), AlignmentSource::Decl);
+ E->getType(),
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
@@ -2324,6 +2482,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
StringRef NameItems[] = {
PredefinedExpr::getIdentTypeName(E->getIdentType()), FnName};
std::string GVName = llvm::join(NameItems, NameItems + 2, ".");
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
if (auto *BD = dyn_cast<BlockDecl>(CurCodeDecl)) {
std::string Name = SL->getString();
if (!Name.empty()) {
@@ -2332,14 +2491,14 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
if (Discriminator)
Name += "_" + Twine(Discriminator + 1).str();
auto C = CGM.GetAddrOfConstantCString(Name, GVName.c_str());
- return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl);
+ return MakeAddrLValue(C, E->getType(), BaseInfo);
} else {
auto C = CGM.GetAddrOfConstantCString(FnName, GVName.c_str());
- return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl);
+ return MakeAddrLValue(C, E->getType(), BaseInfo);
}
}
auto C = CGM.GetAddrOfConstantStringFromLiteral(SL, GVName);
- return MakeAddrLValue(C, E->getType(), AlignmentSource::Decl);
+ return MakeAddrLValue(C, E->getType(), BaseInfo);
}
/// Emit a type description suitable for use by a runtime sanitizer library. The
@@ -2545,8 +2704,8 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(
FnType, FnName,
- llvm::AttributeSet::get(CGF.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex, B),
+ llvm::AttributeList::get(CGF.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex, B),
/*Local=*/true);
llvm::CallInst *HandlerCall = CGF.EmitNounwindRuntimeCall(Fn, FnArgs);
if (!MayReturn) {
@@ -2709,6 +2868,24 @@ void CodeGenFunction::EmitCfiSlowPathCheck(
EmitBlock(Cont);
}
+// Emit a stub for __cfi_check function so that the linker knows about this
+// symbol in LTO mode.
+void CodeGenFunction::EmitCfiCheckStub() {
+ llvm::Module *M = &CGM.getModule();
+ auto &Ctx = M->getContext();
+ llvm::Function *F = llvm::Function::Create(
+ llvm::FunctionType::get(VoidTy, {Int64Ty, Int8PtrTy, Int8PtrTy}, false),
+ llvm::GlobalValue::WeakAnyLinkage, "__cfi_check", M);
+ llvm::BasicBlock *BB = llvm::BasicBlock::Create(Ctx, "entry", F);
+ // FIXME: consider emitting an intrinsic call like
+ // call void @llvm.cfi_check(i64 %0, i8* %1, i8* %2)
+ // which can be lowered in CrossDSOCFI pass to the actual contents of
+ // __cfi_check. This would allow inlining of __cfi_check calls.
+ llvm::CallInst::Create(
+ llvm::Intrinsic::getDeclaration(M, llvm::Intrinsic::trap), "", BB);
+ llvm::ReturnInst::Create(Ctx, nullptr, BB);
+}
+
// This function is basically a switch over the CFI failure kind, which is
// extracted from CFICheckFailData (1st function argument). Each case is either
// llvm.trap or a call to one of the two runtime handlers, based on
@@ -2719,10 +2896,10 @@ void CodeGenFunction::EmitCfiSlowPathCheck(
void CodeGenFunction::EmitCfiCheckFail() {
SanitizerScope SanScope(this);
FunctionArgList Args;
- ImplicitParamDecl ArgData(getContext(), nullptr, SourceLocation(), nullptr,
- getContext().VoidPtrTy);
- ImplicitParamDecl ArgAddr(getContext(), nullptr, SourceLocation(), nullptr,
- getContext().VoidPtrTy);
+ ImplicitParamDecl ArgData(getContext(), getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl ArgAddr(getContext(), getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
Args.push_back(&ArgData);
Args.push_back(&ArgAddr);
@@ -2750,9 +2927,9 @@ void CodeGenFunction::EmitCfiCheckFail() {
EmitTrapCheck(DataIsNotNullPtr);
llvm::StructType *SourceLocationTy =
- llvm::StructType::get(VoidPtrTy, Int32Ty, Int32Ty, nullptr);
+ llvm::StructType::get(VoidPtrTy, Int32Ty, Int32Ty);
llvm::StructType *CfiCheckFailDataTy =
- llvm::StructType::get(Int8Ty, SourceLocationTy, VoidPtrTy, nullptr);
+ llvm::StructType::get(Int8Ty, SourceLocationTy, VoidPtrTy);
llvm::Value *V = Builder.CreateConstGEP2_32(
CfiCheckFailDataTy,
@@ -2821,21 +2998,21 @@ llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) {
if (!CGM.getCodeGenOpts().TrapFuncName.empty()) {
auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name",
CGM.getCodeGenOpts().TrapFuncName);
- TrapCall->addAttribute(llvm::AttributeSet::FunctionIndex, A);
+ TrapCall->addAttribute(llvm::AttributeList::FunctionIndex, A);
}
return TrapCall;
}
Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E,
- AlignmentSource *AlignSource) {
+ LValueBaseInfo *BaseInfo) {
assert(E->getType()->isArrayType() &&
"Array to pointer decay must have array source type!");
// Expressions of array type can't be bitfields or vector elements.
LValue LV = EmitLValue(E);
Address Addr = LV.getAddress();
- if (AlignSource) *AlignSource = LV.getAlignmentSource();
+ if (BaseInfo) *BaseInfo = LV.getBaseInfo();
// If the array type was an incomplete type, we need to make sure
// the decay ends up being the right type.
@@ -2874,9 +3051,13 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF,
llvm::Value *ptr,
ArrayRef<llvm::Value*> indices,
bool inbounds,
+ bool signedIndices,
+ SourceLocation loc,
const llvm::Twine &name = "arrayidx") {
if (inbounds) {
- return CGF.Builder.CreateInBoundsGEP(ptr, indices, name);
+ return CGF.EmitCheckedInBoundsGEP(ptr, indices, signedIndices,
+ CodeGenFunction::NotSubtraction, loc,
+ name);
} else {
return CGF.Builder.CreateGEP(ptr, indices, name);
}
@@ -2907,8 +3088,9 @@ static QualType getFixedSizeElementType(const ASTContext &ctx,
}
static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
- ArrayRef<llvm::Value*> indices,
+ ArrayRef<llvm::Value *> indices,
QualType eltType, bool inbounds,
+ bool signedIndices, SourceLocation loc,
const llvm::Twine &name = "arrayidx") {
// All the indices except that last must be zero.
#ifndef NDEBUG
@@ -2928,8 +3110,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
CharUnits eltAlign =
getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize);
- llvm::Value *eltPtr =
- emitArraySubscriptGEP(CGF, addr.getPointer(), indices, inbounds, name);
+ llvm::Value *eltPtr = emitArraySubscriptGEP(
+ CGF, addr.getPointer(), indices, inbounds, signedIndices, loc, name);
return Address(eltPtr, eltAlign);
}
@@ -2939,6 +3121,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// in lexical order (this complexity is, sadly, required by C++17).
llvm::Value *IdxPre =
(E->getLHS() == E->getIdx()) ? EmitScalarExpr(E->getIdx()) : nullptr;
+ bool SignedIndices = false;
auto EmitIdxAfterBase = [&, IdxPre](bool Promote) -> llvm::Value * {
auto *Idx = IdxPre;
if (E->getLHS() != E->getIdx()) {
@@ -2948,6 +3131,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
QualType IdxTy = E->getIdx()->getType();
bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
+ SignedIndices |= IdxSigned;
if (SanOpts.has(SanitizerKind::ArrayBounds))
EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed);
@@ -2970,7 +3154,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
return LValue::MakeVectorElt(LHS.getAddress(), Idx,
E->getBase()->getType(),
- LHS.getAlignmentSource());
+ LHS.getBaseInfo());
}
// All the other cases basically behave like simple offsetting.
@@ -2982,18 +3166,19 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
Address Addr = EmitExtVectorElementLValue(LV);
QualType EltType = LV.getType()->castAs<VectorType>()->getElementType();
- Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true);
- return MakeAddrLValue(Addr, EltType, LV.getAlignmentSource());
+ Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true,
+ SignedIndices, E->getExprLoc());
+ return MakeAddrLValue(Addr, EltType, LV.getBaseInfo());
}
- AlignmentSource AlignSource;
+ LValueBaseInfo BaseInfo;
Address Addr = Address::invalid();
if (const VariableArrayType *vla =
getContext().getAsVariableArrayType(E->getType())) {
// The base must be a pointer, which is not an aggregate. Emit
// it. It needs to be emitted first in case it's what captures
// the VLA bounds.
- Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource);
+ Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo);
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
// The element count here is the total number of non-VLA elements.
@@ -3010,13 +3195,14 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
}
Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(),
- !getLangOpts().isSignedOverflowDefined());
+ !getLangOpts().isSignedOverflowDefined(),
+ SignedIndices, E->getExprLoc());
} else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){
// Indexing over an interface, as in "NSString *P; P[4];"
// Emit the base pointer.
- Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource);
+ Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo);
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
CharUnits InterfaceSize = getContext().getTypeSizeInChars(OIT);
@@ -3036,7 +3222,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
CharUnits EltAlign =
getArrayElementAlign(Addr.getAlignment(), Idx, InterfaceSize);
llvm::Value *EltPtr =
- emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false);
+ emitArraySubscriptGEP(*this, Addr.getPointer(), ScaledIdx, false,
+ SignedIndices, E->getExprLoc());
Addr = Address(EltPtr, EltAlign);
// Cast back.
@@ -3058,20 +3245,21 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
// Propagate the alignment from the array itself to the result.
- Addr = emitArraySubscriptGEP(*this, ArrayLV.getAddress(),
- {CGM.getSize(CharUnits::Zero()), Idx},
- E->getType(),
- !getLangOpts().isSignedOverflowDefined());
- AlignSource = ArrayLV.getAlignmentSource();
+ Addr = emitArraySubscriptGEP(
+ *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
+ E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
+ E->getExprLoc());
+ BaseInfo = ArrayLV.getBaseInfo();
} else {
// The base must be a pointer; emit it with an estimate of its alignment.
- Addr = EmitPointerWithAlignment(E->getBase(), &AlignSource);
+ Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo);
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
- !getLangOpts().isSignedOverflowDefined());
+ !getLangOpts().isSignedOverflowDefined(),
+ SignedIndices, E->getExprLoc());
}
- LValue LV = MakeAddrLValue(Addr, E->getType(), AlignSource);
+ LValue LV = MakeAddrLValue(Addr, E->getType(), BaseInfo);
// TODO: Preserve/extend path TBAA metadata?
@@ -3084,7 +3272,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
}
static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
- AlignmentSource &AlignSource,
+ LValueBaseInfo &BaseInfo,
QualType BaseTy, QualType ElTy,
bool IsLowerBound) {
LValue BaseLVal;
@@ -3092,7 +3280,7 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
BaseLVal = CGF.EmitOMPArraySectionExpr(ASE, IsLowerBound);
if (BaseTy->isArrayType()) {
Address Addr = BaseLVal.getAddress();
- AlignSource = BaseLVal.getAlignmentSource();
+ BaseInfo = BaseLVal.getBaseInfo();
// If the array type was an incomplete type, we need to make sure
// the decay ends up being the right type.
@@ -3111,10 +3299,12 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
return CGF.Builder.CreateElementBitCast(Addr,
CGF.ConvertTypeForMem(ElTy));
}
- CharUnits Align = CGF.getNaturalTypeAlignment(ElTy, &AlignSource);
+ LValueBaseInfo TypeInfo;
+ CharUnits Align = CGF.getNaturalTypeAlignment(ElTy, &TypeInfo);
+ BaseInfo.mergeForCast(TypeInfo);
return Address(CGF.Builder.CreateLoad(BaseLVal.getAddress()), Align);
}
- return CGF.EmitPointerWithAlignment(Base, &AlignSource);
+ return CGF.EmitPointerWithAlignment(Base, &BaseInfo);
}
LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
@@ -3218,13 +3408,13 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
assert(Idx);
Address EltPtr = Address::invalid();
- AlignmentSource AlignSource;
+ LValueBaseInfo BaseInfo;
if (auto *VLA = getContext().getAsVariableArrayType(ResultExprTy)) {
// The base must be a pointer, which is not an aggregate. Emit
// it. It needs to be emitted first in case it's what captures
// the VLA bounds.
Address Base =
- emitOMPArraySectionBase(*this, E->getBase(), AlignSource, BaseTy,
+ emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, BaseTy,
VLA->getElementType(), IsLowerBound);
// The element count here is the total number of non-VLA elements.
llvm::Value *NumElements = getVLASize(VLA).first;
@@ -3238,7 +3428,8 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
else
Idx = Builder.CreateNSWMul(Idx, NumElements);
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(),
- !getLangOpts().isSignedOverflowDefined());
+ !getLangOpts().isSignedOverflowDefined(),
+ /*SignedIndices=*/false, E->getExprLoc());
} else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) {
// If this is A[i] where A is an array, the frontend will have decayed the
// base to be a ArrayToPointerDecay implicit cast. While correct, it is
@@ -3257,16 +3448,18 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
// Propagate the alignment from the array itself to the result.
EltPtr = emitArraySubscriptGEP(
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
- ResultExprTy, !getLangOpts().isSignedOverflowDefined());
- AlignSource = ArrayLV.getAlignmentSource();
+ ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
+ /*SignedIndices=*/false, E->getExprLoc());
+ BaseInfo = ArrayLV.getBaseInfo();
} else {
- Address Base = emitOMPArraySectionBase(*this, E->getBase(), AlignSource,
+ Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo,
BaseTy, ResultExprTy, IsLowerBound);
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy,
- !getLangOpts().isSignedOverflowDefined());
+ !getLangOpts().isSignedOverflowDefined(),
+ /*SignedIndices=*/false, E->getExprLoc());
}
- return MakeAddrLValue(EltPtr, ResultExprTy, AlignSource);
+ return MakeAddrLValue(EltPtr, ResultExprTy, BaseInfo);
}
LValue CodeGenFunction::
@@ -3278,10 +3471,10 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
if (E->isArrow()) {
// If it is a pointer to a vector, emit the address and form an lvalue with
// it.
- AlignmentSource AlignSource;
- Address Ptr = EmitPointerWithAlignment(E->getBase(), &AlignSource);
+ LValueBaseInfo BaseInfo;
+ Address Ptr = EmitPointerWithAlignment(E->getBase(), &BaseInfo);
const PointerType *PT = E->getBase()->getType()->getAs<PointerType>();
- Base = MakeAddrLValue(Ptr, PT->getPointeeType(), AlignSource);
+ Base = MakeAddrLValue(Ptr, PT->getPointeeType(), BaseInfo);
Base.getQuals().removeObjCGCAttr();
} else if (E->getBase()->isGLValue()) {
// Otherwise, if the base is an lvalue ( as in the case of foo.x.x),
@@ -3298,7 +3491,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
Address VecMem = CreateMemTemp(E->getBase()->getType());
Builder.CreateStore(Vec, VecMem);
Base = MakeAddrLValue(VecMem, E->getBase()->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
QualType type =
@@ -3312,7 +3505,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
llvm::Constant *CV =
llvm::ConstantDataVector::get(getLLVMContext(), Indices);
return LValue::MakeExtVectorElt(Base.getAddress(), CV, type,
- Base.getAlignmentSource());
+ Base.getBaseInfo());
}
assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!");
@@ -3323,20 +3516,26 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
CElts.push_back(BaseElts->getAggregateElement(Indices[i]));
llvm::Constant *CV = llvm::ConstantVector::get(CElts);
return LValue::MakeExtVectorElt(Base.getExtVectorAddress(), CV, type,
- Base.getAlignmentSource());
+ Base.getBaseInfo());
}
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
Expr *BaseExpr = E->getBase();
-
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
LValue BaseLV;
if (E->isArrow()) {
- AlignmentSource AlignSource;
- Address Addr = EmitPointerWithAlignment(BaseExpr, &AlignSource);
+ LValueBaseInfo BaseInfo;
+ Address Addr = EmitPointerWithAlignment(BaseExpr, &BaseInfo);
QualType PtrTy = BaseExpr->getType()->getPointeeType();
- EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy);
- BaseLV = MakeAddrLValue(Addr, PtrTy, AlignSource);
+ SanitizerSet SkippedChecks;
+ bool IsBaseCXXThis = IsWrappedCXXThis(BaseExpr);
+ if (IsBaseCXXThis)
+ SkippedChecks.set(SanitizerKind::Alignment, true);
+ if (IsBaseCXXThis || isa<DeclRefExpr>(BaseExpr))
+ SkippedChecks.set(SanitizerKind::Null, true);
+ EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy,
+ /*Alignment=*/CharUnits::Zero(), SkippedChecks);
+ BaseLV = MakeAddrLValue(Addr, PtrTy, BaseInfo);
} else
BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);
@@ -3394,10 +3593,36 @@ static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
return CGF.Builder.CreateStructGEP(base, idx, offset, field->getName());
}
+static bool hasAnyVptr(const QualType Type, const ASTContext &Context) {
+ const auto *RD = Type.getTypePtr()->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+
+ if (RD->isDynamicClass())
+ return true;
+
+ for (const auto &Base : RD->bases())
+ if (hasAnyVptr(Base.getType(), Context))
+ return true;
+
+ for (const FieldDecl *Field : RD->fields())
+ if (hasAnyVptr(Field->getType(), Context))
+ return true;
+
+ return false;
+}
+
LValue CodeGenFunction::EmitLValueForField(LValue base,
const FieldDecl *field) {
+ LValueBaseInfo BaseInfo = base.getBaseInfo();
AlignmentSource fieldAlignSource =
- getFieldAlignmentSource(base.getAlignmentSource());
+ getFieldAlignmentSource(BaseInfo.getAlignmentSource());
+ LValueBaseInfo FieldBaseInfo(fieldAlignSource, BaseInfo.getMayAlias());
+
+ const RecordDecl *rec = field->getParent();
+ if (rec->isUnion() || rec->hasAttr<MayAliasAttr>())
+ FieldBaseInfo.setMayAlias(true);
+ bool mayAlias = FieldBaseInfo.getMayAlias();
if (field->isBitField()) {
const CGRecordLayout &RL =
@@ -3417,14 +3642,10 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
QualType fieldType =
field->getType().withCVRQualifiers(base.getVRQualifiers());
- return LValue::MakeBitfield(Addr, Info, fieldType, fieldAlignSource);
+ return LValue::MakeBitfield(Addr, Info, fieldType, FieldBaseInfo);
}
- const RecordDecl *rec = field->getParent();
QualType type = field->getType();
-
- bool mayAlias = rec->hasAttr<MayAliasAttr>();
-
Address addr = base.getAddress();
unsigned cvr = base.getVRQualifiers();
bool TBAAPath = CGM.getCodeGenOpts().StructPathTBAA;
@@ -3433,6 +3654,14 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
assert(!type->isReferenceType() && "union has reference member");
// TODO: handle path-aware TBAA for union.
TBAAPath = false;
+
+ const auto FieldType = field->getType();
+ if (CGM.getCodeGenOpts().StrictVTablePointers &&
+ hasAnyVptr(FieldType, getContext()))
+ // Because unions can easily skip invariant.barriers, we need to add
+ // a barrier every time CXXRecord field with vptr is referenced.
+ addr = Address(Builder.CreateInvariantGroupBarrier(addr.getPointer()),
+ addr.getAlignment());
} else {
// For structs, we GEP to the field that the record layout suggests.
addr = emitAddrOfFieldStorage(*this, addr, field);
@@ -3458,7 +3687,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
type = refType->getPointeeType();
CharUnits alignment =
- getNaturalTypeAlignment(type, &fieldAlignSource, /*pointee*/ true);
+ getNaturalTypeAlignment(type, &FieldBaseInfo, /*pointee*/ true);
+ FieldBaseInfo.setMayAlias(false);
addr = Address(load, alignment);
// Qualifiers on the struct don't apply to the referencee, and
@@ -3479,7 +3709,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
if (field->hasAttr<AnnotateAttr>())
addr = EmitFieldAnnotations(field, addr);
- LValue LV = MakeAddrLValue(addr, type, fieldAlignSource);
+ LValue LV = MakeAddrLValue(addr, type, FieldBaseInfo);
LV.getQuals().addCVRQualifiers(cvr);
if (TBAAPath) {
const ASTRecordLayout &Layout =
@@ -3520,14 +3750,18 @@ CodeGenFunction::EmitLValueForFieldInitialization(LValue Base,
V = Builder.CreateElementBitCast(V, llvmType, Field->getName());
// TODO: access-path TBAA?
- auto FieldAlignSource = getFieldAlignmentSource(Base.getAlignmentSource());
- return MakeAddrLValue(V, FieldType, FieldAlignSource);
+ LValueBaseInfo BaseInfo = Base.getBaseInfo();
+ LValueBaseInfo FieldBaseInfo(
+ getFieldAlignmentSource(BaseInfo.getAlignmentSource()),
+ BaseInfo.getMayAlias());
+ return MakeAddrLValue(V, FieldType, FieldBaseInfo);
}
LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
if (E->isFileScope()) {
ConstantAddress GlobalPtr = CGM.GetAddrOfConstantCompoundLiteral(E);
- return MakeAddrLValue(GlobalPtr, E->getType(), AlignmentSource::Decl);
+ return MakeAddrLValue(GlobalPtr, E->getType(), BaseInfo);
}
if (E->getType()->isVariablyModifiedType())
// make sure to emit the VLA size.
@@ -3535,7 +3769,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
Address DeclPtr = CreateMemTemp(E->getType(), ".compoundliteral");
const Expr *InitExpr = E->getInitializer();
- LValue Result = MakeAddrLValue(DeclPtr, E->getType(), AlignmentSource::Decl);
+ LValue Result = MakeAddrLValue(DeclPtr, E->getType(), BaseInfo);
EmitAnyExprToMem(InitExpr, DeclPtr, E->getType().getQualifiers(),
/*Init*/ true);
@@ -3632,8 +3866,12 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
phi->addIncoming(rhs->getPointer(), rhsBlock);
Address result(phi, std::min(lhs->getAlignment(), rhs->getAlignment()));
AlignmentSource alignSource =
- std::max(lhs->getAlignmentSource(), rhs->getAlignmentSource());
- return MakeAddrLValue(result, expr->getType(), alignSource);
+ std::max(lhs->getBaseInfo().getAlignmentSource(),
+ rhs->getBaseInfo().getAlignmentSource());
+ bool MayAlias = lhs->getBaseInfo().getMayAlias() ||
+ rhs->getBaseInfo().getMayAlias();
+ return MakeAddrLValue(result, expr->getType(),
+ LValueBaseInfo(alignSource, MayAlias));
} else {
assert((lhs || rhs) &&
"both operands of glvalue conditional are throw-expressions?");
@@ -3731,7 +3969,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
This, DerivedClassDecl, E->path_begin(), E->path_end(),
/*NullCheckValue=*/false, E->getExprLoc());
- return MakeAddrLValue(Base, E->getType(), LV.getAlignmentSource());
+ return MakeAddrLValue(Base, E->getType(), LV.getBaseInfo());
}
case CK_ToUnion:
return EmitAggExprToLValue(E);
@@ -3758,7 +3996,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
/*MayBeNull=*/false,
CFITCK_DerivedCast, E->getLocStart());
- return MakeAddrLValue(Derived, E->getType(), LV.getAlignmentSource());
+ return MakeAddrLValue(Derived, E->getType(), LV.getBaseInfo());
}
case CK_LValueBitCast: {
// This must be a reinterpret_cast (or c-style equivalent).
@@ -3774,13 +4012,13 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
/*MayBeNull=*/false,
CFITCK_UnrelatedCast, E->getLocStart());
- return MakeAddrLValue(V, E->getType(), LV.getAlignmentSource());
+ return MakeAddrLValue(V, E->getType(), LV.getBaseInfo());
}
case CK_ObjCObjectLValueCast: {
LValue LV = EmitLValue(E->getSubExpr());
Address V = Builder.CreateElementBitCast(LV.getAddress(),
ConvertType(E->getType()));
- return MakeAddrLValue(V, E->getType(), LV.getAlignmentSource());
+ return MakeAddrLValue(V, E->getType(), LV.getBaseInfo());
}
case CK_ZeroToOCLQueue:
llvm_unreachable("NULL to OpenCL queue lvalue cast is not valid");
@@ -3949,6 +4187,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
RValue RV = EmitAnyExpr(E->getRHS());
LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
+ if (RV.isScalar())
+ EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc());
EmitStoreThroughLValue(RV, LV);
return LV;
}
@@ -3967,7 +4207,7 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
if (!RV.isScalar())
return MakeAddrLValue(RV.getAggregateAddress(), E->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
assert(E->getCallReturnType(getContext())->isReferenceType() &&
"Can't have a scalar return unless the return type is a "
@@ -3987,7 +4227,7 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
AggValueSlot Slot = CreateAggTemp(E->getType());
EmitCXXConstructExpr(E, Slot);
return MakeAddrLValue(Slot.getAddress(), E->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
LValue
@@ -4002,7 +4242,7 @@ Address CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) {
LValue CodeGenFunction::EmitCXXUuidofLValue(const CXXUuidofExpr *E) {
return MakeAddrLValue(EmitCXXUuidofExpr(E), E->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
LValue
@@ -4012,7 +4252,7 @@ CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
EmitAggExpr(E->getSubExpr(), Slot);
EmitCXXTemporary(E->getTemporary(), E->getType(), Slot.getAddress());
return MakeAddrLValue(Slot.getAddress(), E->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
LValue
@@ -4020,7 +4260,7 @@ CodeGenFunction::EmitLambdaLValue(const LambdaExpr *E) {
AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue");
EmitLambdaExpr(E, Slot);
return MakeAddrLValue(Slot.getAddress(), E->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
@@ -4028,7 +4268,7 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
if (!RV.isScalar())
return MakeAddrLValue(RV.getAggregateAddress(), E->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
assert(E->getMethodDecl()->getReturnType()->isReferenceType() &&
"Can't have a scalar return unless the return type is a "
@@ -4040,7 +4280,8 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
LValue CodeGenFunction::EmitObjCSelectorLValue(const ObjCSelectorExpr *E) {
Address V =
CGM.getObjCRuntime().GetAddrOfSelector(*this, E->getSelector());
- return MakeAddrLValue(V, E->getType(), AlignmentSource::Decl);
+ return MakeAddrLValue(V, E->getType(),
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface,
@@ -4084,7 +4325,7 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
// Can only get l-value for message expression returning aggregate type
RValue RV = EmitAnyExprToTemp(E);
return MakeAddrLValue(RV.getAggregateAddress(), E->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee,
@@ -4276,12 +4517,11 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
const MemberPointerType *MPT
= E->getRHS()->getType()->getAs<MemberPointerType>();
- AlignmentSource AlignSource;
+ LValueBaseInfo BaseInfo;
Address MemberAddr =
- EmitCXXMemberDataPointerAddress(E, BaseAddr, OffsetV, MPT,
- &AlignSource);
+ EmitCXXMemberDataPointerAddress(E, BaseAddr, OffsetV, MPT, &BaseInfo);
- return MakeAddrLValue(MemberAddr, MPT->getPointeeType(), AlignSource);
+ return MakeAddrLValue(MemberAddr, MPT->getPointeeType(), BaseInfo);
}
/// Given the address of a temporary variable, produce an r-value of
@@ -4289,7 +4529,8 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
RValue CodeGenFunction::convertTempToRValue(Address addr,
QualType type,
SourceLocation loc) {
- LValue lvalue = MakeAddrLValue(addr, type, AlignmentSource::Decl);
+ LValue lvalue = MakeAddrLValue(addr, type,
+ LValueBaseInfo(AlignmentSource::Decl, false));
switch (getEvaluationKind(type)) {
case TEK_Complex:
return RValue::getComplex(EmitLoadOfComplex(lvalue, loc));
@@ -4344,9 +4585,9 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
if (ov == resultExpr && ov->isRValue() && !forLValue &&
CodeGenFunction::hasAggregateEvaluationKind(ov->getType())) {
CGF.EmitAggExpr(ov->getSourceExpr(), slot);
-
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
LValue LV = CGF.MakeAddrLValue(slot.getAddress(), ov->getType(),
- AlignmentSource::Decl);
+ BaseInfo);
opaqueData = OVMA::bind(CGF, ov, LV);
result.RV = slot.asRValue();
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp
index 0092447..a05a088 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp
@@ -111,6 +111,13 @@ public:
void VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
Visit(GE->getResultExpr());
}
+ void VisitCoawaitExpr(CoawaitExpr *E) {
+ CGF.EmitCoawaitExpr(*E, Dest, IsResultUnused);
+ }
+ void VisitCoyieldExpr(CoyieldExpr *E) {
+ CGF.EmitCoyieldExpr(*E, Dest, IsResultUnused);
+ }
+ void VisitUnaryCoawait(UnaryOperator *E) { Visit(E->getSubExpr()); }
void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); }
void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
return Visit(E->getReplacement());
@@ -505,12 +512,20 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
currentElement->addIncoming(element, entryBB);
// Emit the actual filler expression.
- LValue elementLV =
- CGF.MakeAddrLValue(Address(currentElement, elementAlign), elementType);
- if (filler)
- EmitInitializationToLValue(filler, elementLV);
- else
- EmitNullInitializationToLValue(elementLV);
+ {
+ // C++1z [class.temporary]p5:
+ // when a default constructor is called to initialize an element of
+ // an array with no corresponding initializer [...] the destruction of
+ // every temporary created in a default argument is sequenced before
+ // the construction of the next array element, if any
+ CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
+ LValue elementLV =
+ CGF.MakeAddrLValue(Address(currentElement, elementAlign), elementType);
+ if (filler)
+ EmitInitializationToLValue(filler, elementLV);
+ else
+ EmitNullInitializationToLValue(elementLV);
+ }
// Move on to the next element.
llvm::Value *nextElement =
@@ -1267,7 +1282,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// Store the initializer into the field.
EmitInitializationToLValue(E->getInit(curInitIndex++), LV);
} else {
- // We're out of initalizers; default-initialize to null
+ // We're out of initializers; default-initialize to null
EmitNullInitializationToLValue(LV);
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp
index 71c8fb8..ab17024 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp
@@ -24,7 +24,15 @@
using namespace clang;
using namespace CodeGen;
-static RequiredArgs
+namespace {
+struct MemberCallInfo {
+ RequiredArgs ReqArgs;
+ // Number of prefix arguments for the call. Ignores the `this` pointer.
+ unsigned PrefixSize;
+};
+}
+
+static MemberCallInfo
commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
llvm::Value *This, llvm::Value *ImplicitParam,
QualType ImplicitParamTy, const CallExpr *CE,
@@ -48,6 +56,7 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size(), MD);
+ unsigned PrefixSize = Args.size() - 1;
// And the rest of the call args.
if (RtlArgs) {
@@ -65,7 +74,7 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
FPT->getNumParams() == 0 &&
"No CallExpr specified for function with non-zero number of arguments");
}
- return required;
+ return {required, PrefixSize};
}
RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
@@ -75,9 +84,10 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
const CallExpr *CE, CallArgList *RtlArgs) {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
CallArgList Args;
- RequiredArgs required = commonEmitCXXMemberOrOperatorCall(
+ MemberCallInfo CallInfo = commonEmitCXXMemberOrOperatorCall(
*this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs);
- auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required);
+ auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall(
+ Args, FPT, CallInfo.ReqArgs, CallInfo.PrefixSize);
return EmitCall(FnInfo, Callee, ReturnValue, Args);
}
@@ -189,7 +199,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
bool CanUseVirtualCall = MD->isVirtual() && !HasQualifier;
const CXXMethodDecl *DevirtualizedMethod = nullptr;
- if (CanUseVirtualCall && CanDevirtualizeMemberFunctionCall(Base, MD)) {
+ if (CanUseVirtualCall &&
+ MD->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) {
const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
DevirtualizedMethod = MD->getCorrespondingMethodInClass(BestDynamicDecl);
assert(DevirtualizedMethod);
@@ -290,10 +301,20 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
if (CE)
CallLoc = CE->getExprLoc();
- EmitTypeCheck(isa<CXXConstructorDecl>(CalleeDecl)
- ? CodeGenFunction::TCK_ConstructorCall
- : CodeGenFunction::TCK_MemberCall,
- CallLoc, This.getPointer(), C.getRecordType(CalleeDecl->getParent()));
+ SanitizerSet SkippedChecks;
+ if (const auto *CMCE = dyn_cast<CXXMemberCallExpr>(CE)) {
+ auto *IOA = CMCE->getImplicitObjectArgument();
+ bool IsImplicitObjectCXXThis = IsWrappedCXXThis(IOA);
+ if (IsImplicitObjectCXXThis)
+ SkippedChecks.set(SanitizerKind::Alignment, true);
+ if (IsImplicitObjectCXXThis || isa<DeclRefExpr>(IOA))
+ SkippedChecks.set(SanitizerKind::Null, true);
+ }
+ EmitTypeCheck(
+ isa<CXXConstructorDecl>(CalleeDecl) ? CodeGenFunction::TCK_ConstructorCall
+ : CodeGenFunction::TCK_MemberCall,
+ CallLoc, This.getPointer(), C.getRecordType(CalleeDecl->getParent()),
+ /*Alignment=*/CharUnits::Zero(), SkippedChecks);
// FIXME: Uses of 'MD' past this point need to be audited. We may need to use
// 'CalleeDecl' instead.
@@ -420,7 +441,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
// And the rest of the call args
EmitCallArgs(Args, FPT, E->arguments());
- return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required),
+ return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required,
+ /*PrefixSize=*/0),
Callee, ReturnValue, Args);
}
@@ -659,7 +681,10 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// Emit the array size expression.
// We multiply the size of all dimensions for NumElements.
// e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6.
- numElements = CGF.EmitScalarExpr(e->getArraySize());
+ numElements = CGF.CGM.EmitConstantExpr(e->getArraySize(),
+ CGF.getContext().getSizeType(), &CGF);
+ if (!numElements)
+ numElements = CGF.EmitScalarExpr(e->getArraySize());
assert(isa<llvm::IntegerType>(numElements->getType()));
// The number of elements can be have an arbitrary integer type;
@@ -1256,10 +1281,10 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
Fn && Fn->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
// FIXME: Add addAttribute to CallSite.
if (llvm::CallInst *CI = dyn_cast<llvm::CallInst>(CallOrInvoke))
- CI->addAttribute(llvm::AttributeSet::FunctionIndex,
+ CI->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::Builtin);
else if (llvm::InvokeInst *II = dyn_cast<llvm::InvokeInst>(CallOrInvoke))
- II->addAttribute(llvm::AttributeSet::FunctionIndex,
+ II->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::Builtin);
else
llvm_unreachable("unexpected kind of call instruction");
@@ -1507,13 +1532,13 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
assert(E->getNumPlacementArgs() == 1);
const Expr *arg = *E->placement_arguments().begin();
- AlignmentSource alignSource;
- allocation = EmitPointerWithAlignment(arg, &alignSource);
+ LValueBaseInfo BaseInfo;
+ allocation = EmitPointerWithAlignment(arg, &BaseInfo);
// The pointer expression will, in many cases, be an opaque void*.
// In these cases, discard the computed alignment and use the
// formal alignment of the allocated type.
- if (alignSource != AlignmentSource::Decl)
+ if (BaseInfo.getAlignmentSource() != AlignmentSource::Decl)
allocation = Address(allocation.getPointer(), allocAlign);
// Set up allocatorArgs for the call to operator delete if it's not
@@ -1560,7 +1585,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// FIXME: Why do we not pass a CalleeDecl here?
EmitCallArgs(allocatorArgs, allocatorType, E->placement_arguments(),
- /*CalleeDecl*/nullptr, /*ParamsToSkip*/ParamsToSkip);
+ /*AC*/AbstractCallee(), /*ParamsToSkip*/ParamsToSkip);
RValue RV =
EmitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs);
@@ -1634,8 +1659,9 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// Passing pointer through invariant.group.barrier to avoid propagation of
// vptrs information which may be included in previous type.
+ // To not break LTO with different optimizations levels, we do it regardless
+ // of optimization level.
if (CGM.getCodeGenOpts().StrictVTablePointers &&
- CGM.getCodeGenOpts().OptimizationLevel > 0 &&
allocator->isReservedGlobalPlacementOperator())
result = Address(Builder.CreateInvariantGroupBarrier(result.getPointer()),
result.getAlignment());
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
index 59bc9cd..9809723 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
@@ -110,6 +110,16 @@ public:
VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE) {
return Visit(PE->getReplacement());
}
+ ComplexPairTy VisitCoawaitExpr(CoawaitExpr *S) {
+ return CGF.EmitCoawaitExpr(*S).getComplexVal();
+ }
+ ComplexPairTy VisitCoyieldExpr(CoyieldExpr *S) {
+ return CGF.EmitCoyieldExpr(*S).getComplexVal();
+ }
+ ComplexPairTy VisitUnaryCoawait(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
+
// l-values.
ComplexPairTy VisitDeclRefExpr(DeclRefExpr *E) {
@@ -198,7 +208,11 @@ public:
ComplexPairTy VisitExprWithCleanups(ExprWithCleanups *E) {
CGF.enterFullExpression(E);
CodeGenFunction::RunCleanupsScope Scope(CGF);
- return Visit(E->getSubExpr());
+ ComplexPairTy Vals = Visit(E->getSubExpr());
+ // Defend against dominance problems caused by jumps out of expression
+ // evaluation through the shared cleanup block.
+ Scope.ForceCleanup({&Vals.first, &Vals.second});
+ return Vals;
}
ComplexPairTy VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp
index 3db15c6..6b72774 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp
@@ -201,7 +201,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
if (CGM.getDataLayout().isBigEndian()) {
- Tmp = Tmp.lshr(NewFieldWidth);
+ Tmp.lshrInPlace(NewFieldWidth);
Tmp = Tmp.trunc(BitsInPreviousByte);
// We want the remaining high bits.
@@ -210,7 +210,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
Tmp = Tmp.trunc(BitsInPreviousByte);
// We want the remaining low bits.
- FieldValue = FieldValue.lshr(BitsInPreviousByte);
+ FieldValue.lshrInPlace(BitsInPreviousByte);
FieldValue = FieldValue.trunc(NewFieldWidth);
}
}
@@ -273,7 +273,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field,
// We want the low bits.
Tmp = FieldValue.trunc(CharWidth);
- FieldValue = FieldValue.lshr(CharWidth);
+ FieldValue.lshrInPlace(CharWidth);
}
Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
@@ -1361,9 +1361,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
Value.getComplexIntImag());
// FIXME: the target may want to specify that this is packed.
- llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
- Complex[1]->getType(),
- nullptr);
+ llvm::StructType *STy =
+ llvm::StructType::get(Complex[0]->getType(), Complex[1]->getType());
return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Float: {
@@ -1384,9 +1383,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
Value.getComplexFloatImag());
// FIXME: the target may want to specify that this is packed.
- llvm::StructType *STy = llvm::StructType::get(Complex[0]->getType(),
- Complex[1]->getType(),
- nullptr);
+ llvm::StructType *STy =
+ llvm::StructType::get(Complex[0]->getType(), Complex[1]->getType());
return llvm::ConstantStruct::get(STy, Complex);
}
case APValue::Vector: {
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp
index 1b85c45..1170b01 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
+#include "CGCleanup.h"
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
@@ -24,10 +25,12 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
@@ -42,13 +45,85 @@ using llvm::Value;
//===----------------------------------------------------------------------===//
namespace {
+
+/// Determine whether the given binary operation may overflow.
+/// Sets \p Result to the value of the operation for BO_Add, BO_Sub, BO_Mul,
+/// and signed BO_{Div,Rem}. For these opcodes, and for unsigned BO_{Div,Rem},
+/// the returned overflow check is precise. The returned value is 'true' for
+/// all other opcodes, to be conservative.
+bool mayHaveIntegerOverflow(llvm::ConstantInt *LHS, llvm::ConstantInt *RHS,
+ BinaryOperator::Opcode Opcode, bool Signed,
+ llvm::APInt &Result) {
+ // Assume overflow is possible, unless we can prove otherwise.
+ bool Overflow = true;
+ const auto &LHSAP = LHS->getValue();
+ const auto &RHSAP = RHS->getValue();
+ if (Opcode == BO_Add) {
+ if (Signed)
+ Result = LHSAP.sadd_ov(RHSAP, Overflow);
+ else
+ Result = LHSAP.uadd_ov(RHSAP, Overflow);
+ } else if (Opcode == BO_Sub) {
+ if (Signed)
+ Result = LHSAP.ssub_ov(RHSAP, Overflow);
+ else
+ Result = LHSAP.usub_ov(RHSAP, Overflow);
+ } else if (Opcode == BO_Mul) {
+ if (Signed)
+ Result = LHSAP.smul_ov(RHSAP, Overflow);
+ else
+ Result = LHSAP.umul_ov(RHSAP, Overflow);
+ } else if (Opcode == BO_Div || Opcode == BO_Rem) {
+ if (Signed && !RHS->isZero())
+ Result = LHSAP.sdiv_ov(RHSAP, Overflow);
+ else
+ return false;
+ }
+ return Overflow;
+}
+
struct BinOpInfo {
Value *LHS;
Value *RHS;
QualType Ty; // Computation Type.
BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform
- bool FPContractable;
+ FPOptions FPFeatures;
const Expr *E; // Entire expr, for error unsupported. May not be binop.
+
+ /// Check if the binop can result in integer overflow.
+ bool mayHaveIntegerOverflow() const {
+ // Without constant input, we can't rule out overflow.
+ auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS);
+ auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS);
+ if (!LHSCI || !RHSCI)
+ return true;
+
+ llvm::APInt Result;
+ return ::mayHaveIntegerOverflow(
+ LHSCI, RHSCI, Opcode, Ty->hasSignedIntegerRepresentation(), Result);
+ }
+
+ /// Check if the binop computes a division or a remainder.
+ bool isDivremOp() const {
+ return Opcode == BO_Div || Opcode == BO_Rem || Opcode == BO_DivAssign ||
+ Opcode == BO_RemAssign;
+ }
+
+ /// Check if the binop can result in an integer division by zero.
+ bool mayHaveIntegerDivisionByZero() const {
+ if (isDivremOp())
+ if (auto *CI = dyn_cast<llvm::ConstantInt>(RHS))
+ return CI->isZero();
+ return true;
+ }
+
+ /// Check if the binop can result in a float division by zero.
+ bool mayHaveFloatDivisionByZero() const {
+ if (isDivremOp())
+ if (auto *CFP = dyn_cast<llvm::ConstantFP>(RHS))
+ return CFP->isZero();
+ return true;
+ }
};
static bool MustVisitNullValue(const Expr *E) {
@@ -58,6 +133,83 @@ static bool MustVisitNullValue(const Expr *E) {
return E->getType()->isNullPtrType();
}
+/// If \p E is a widened promoted integer, get its base (unpromoted) type.
+static llvm::Optional<QualType> getUnwidenedIntegerType(const ASTContext &Ctx,
+ const Expr *E) {
+ const Expr *Base = E->IgnoreImpCasts();
+ if (E == Base)
+ return llvm::None;
+
+ QualType BaseTy = Base->getType();
+ if (!BaseTy->isPromotableIntegerType() ||
+ Ctx.getTypeSize(BaseTy) >= Ctx.getTypeSize(E->getType()))
+ return llvm::None;
+
+ return BaseTy;
+}
+
+/// Check if \p E is a widened promoted integer.
+static bool IsWidenedIntegerOp(const ASTContext &Ctx, const Expr *E) {
+ return getUnwidenedIntegerType(Ctx, E).hasValue();
+}
+
+/// Check if we can skip the overflow check for \p Op.
+static bool CanElideOverflowCheck(const ASTContext &Ctx, const BinOpInfo &Op) {
+ assert((isa<UnaryOperator>(Op.E) || isa<BinaryOperator>(Op.E)) &&
+ "Expected a unary or binary operator");
+
+ // If the binop has constant inputs and we can prove there is no overflow,
+ // we can elide the overflow check.
+ if (!Op.mayHaveIntegerOverflow())
+ return true;
+
+ // If a unary op has a widened operand, the op cannot overflow.
+ if (const auto *UO = dyn_cast<UnaryOperator>(Op.E))
+ return IsWidenedIntegerOp(Ctx, UO->getSubExpr());
+
+ // We usually don't need overflow checks for binops with widened operands.
+ // Multiplication with promoted unsigned operands is a special case.
+ const auto *BO = cast<BinaryOperator>(Op.E);
+ auto OptionalLHSTy = getUnwidenedIntegerType(Ctx, BO->getLHS());
+ if (!OptionalLHSTy)
+ return false;
+
+ auto OptionalRHSTy = getUnwidenedIntegerType(Ctx, BO->getRHS());
+ if (!OptionalRHSTy)
+ return false;
+
+ QualType LHSTy = *OptionalLHSTy;
+ QualType RHSTy = *OptionalRHSTy;
+
+ // This is the simple case: binops without unsigned multiplication, and with
+ // widened operands. No overflow check is needed here.
+ if ((Op.Opcode != BO_Mul && Op.Opcode != BO_MulAssign) ||
+ !LHSTy->isUnsignedIntegerType() || !RHSTy->isUnsignedIntegerType())
+ return true;
+
+ // For unsigned multiplication the overflow check can be elided if either one
+ // of the unpromoted types are less than half the size of the promoted type.
+ unsigned PromotedSize = Ctx.getTypeSize(Op.E->getType());
+ return (2 * Ctx.getTypeSize(LHSTy)) < PromotedSize ||
+ (2 * Ctx.getTypeSize(RHSTy)) < PromotedSize;
+}
+
+/// Update the FastMathFlags of LLVM IR from the FPOptions in LangOptions.
+static void updateFastMathFlags(llvm::FastMathFlags &FMF,
+ FPOptions FPFeatures) {
+ FMF.setAllowContract(FPFeatures.allowFPContractAcrossStatement());
+}
+
+/// Propagate fast-math flags from \p Op to the instruction in \p V.
+static Value *propagateFMFlags(Value *V, const BinOpInfo &Op) {
+ if (auto *I = dyn_cast<llvm::Instruction>(V)) {
+ llvm::FastMathFlags FMF = I->getFastMathFlags();
+ updateFastMathFlags(FMF, Op.FPFeatures);
+ I->setFastMathFlags(FMF);
+ }
+ return V;
+}
+
class ScalarExprEmitter
: public StmtVisitor<ScalarExprEmitter, Value*> {
CodeGenFunction &CGF;
@@ -221,6 +373,15 @@ public:
Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
}
+ Value *VisitCoawaitExpr(CoawaitExpr *S) {
+ return CGF.EmitCoawaitExpr(*S).getScalarVal();
+ }
+ Value *VisitCoyieldExpr(CoyieldExpr *S) {
+ return CGF.EmitCoyieldExpr(*S).getScalarVal();
+ }
+ Value *VisitUnaryCoawait(const UnaryOperator *E) {
+ return Visit(E->getSubExpr());
+ }
// Leaves.
Value *VisitIntegerLiteral(const IntegerLiteral *E) {
@@ -300,6 +461,24 @@ public:
return V;
}
+ Value *VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
+ VersionTuple Version = E->getVersion();
+
+ // If we're checking for a platform older than our minimum deployment
+ // target, we can fold the check away.
+ if (Version <= CGF.CGM.getTarget().getPlatformMinVersion())
+ return llvm::ConstantInt::get(Builder.getInt1Ty(), 1);
+
+ Optional<unsigned> Min = Version.getMinor(), SMin = Version.getSubminor();
+ llvm::Value *Args[] = {
+ llvm::ConstantInt::get(CGF.CGM.Int32Ty, Version.getMajor()),
+ llvm::ConstantInt::get(CGF.CGM.Int32Ty, Min ? *Min : 0),
+ llvm::ConstantInt::get(CGF.CGM.Int32Ty, SMin ? *SMin : 0),
+ };
+
+ return CGF.EmitBuiltinAvailable(Args);
+ }
+
Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
Value *VisitConvertVectorExpr(ConvertVectorExpr *E);
@@ -405,11 +584,7 @@ public:
return CGF.LoadCXXThis();
}
- Value *VisitExprWithCleanups(ExprWithCleanups *E) {
- CGF.enterFullExpression(E);
- CodeGenFunction::RunCleanupsScope Scope(CGF);
- return Visit(E->getSubExpr());
- }
+ Value *VisitExprWithCleanups(ExprWithCleanups *E);
Value *VisitCXXNewExpr(const CXXNewExpr *E) {
return CGF.EmitCXXNewExpr(E);
}
@@ -464,16 +639,21 @@ public:
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
// Fall through.
case LangOptions::SOB_Trapping:
+ if (CanElideOverflowCheck(CGF.getContext(), Ops))
+ return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
return EmitOverflowCheckedBinOp(Ops);
}
}
if (Ops.Ty->isUnsignedIntegerType() &&
- CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow))
+ CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
+ !CanElideOverflowCheck(CGF.getContext(), Ops))
return EmitOverflowCheckedBinOp(Ops);
- if (Ops.LHS->getType()->isFPOrFPVectorTy())
- return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
+ if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
+ Value *V = Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
+ return propagateFMFlags(V, Ops);
+ }
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
}
/// Create a binary op that checks for overflow.
@@ -1414,10 +1594,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}
// Since target may map different address spaces in AST to the same address
// space, an address space conversion may end up as a bitcast.
- auto *Src = Visit(E);
- return CGF.CGM.getTargetCodeGenInfo().performAddrSpaceCast(CGF, Src,
- E->getType(),
- DestTy);
+ return CGF.CGM.getTargetCodeGenInfo().performAddrSpaceCast(
+ CGF, Visit(E), E->getType()->getPointeeType().getAddressSpace(),
+ DestTy->getPointeeType().getAddressSpace(), ConvertType(DestTy));
}
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
@@ -1616,6 +1795,16 @@ Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
E->getExprLoc());
}
+Value *ScalarExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
+ CGF.enterFullExpression(E);
+ CodeGenFunction::RunCleanupsScope Scope(CGF);
+ Value *V = Visit(E->getSubExpr());
+ // Defend against dominance problems caused by jumps out of expression
+ // evaluation through the shared cleanup block.
+ Scope.ForceCleanup({&V});
+ return V;
+}
+
//===----------------------------------------------------------------------===//
// Unary Operators
//===----------------------------------------------------------------------===//
@@ -1627,7 +1816,7 @@ static BinOpInfo createBinOpInfoFromIncDec(const UnaryOperator *E,
BinOp.RHS = llvm::ConstantInt::get(InVal->getType(), 1, false);
BinOp.Ty = E->getType();
BinOp.Opcode = IsInc ? BO_Add : BO_Sub;
- BinOp.FPContractable = false;
+ // FIXME: once UnaryOperator carries FPFeatures, copy it here.
BinOp.E = E;
return BinOp;
}
@@ -1645,6 +1834,8 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
return Builder.CreateNSWAdd(InVal, Amount, Name);
// Fall through.
case LangOptions::SOB_Trapping:
+ if (IsWidenedIntegerOp(CGF.getContext(), E->getSubExpr()))
+ return Builder.CreateNSWAdd(InVal, Amount, Name);
return EmitOverflowCheckedBinOp(createBinOpInfoFromIncDec(E, InVal, IsInc));
}
llvm_unreachable("Unknown SignedOverflowBehaviorTy");
@@ -1660,6 +1851,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::Value *input;
int amount = (isInc ? 1 : -1);
+ bool isSubtraction = !isInc;
if (const AtomicType *atomicTy = type->getAs<AtomicType>()) {
type = atomicTy->getValueType();
@@ -1749,7 +1941,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, numElts, "vla.inc");
else
- value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc");
+ value = CGF.EmitCheckedInBoundsGEP(
+ value, numElts, /*SignedIndices=*/false, isSubtraction,
+ E->getExprLoc(), "vla.inc");
// Arithmetic on function pointers (!) is just +-1.
} else if (type->isFunctionType()) {
@@ -1759,7 +1953,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.funcptr");
else
- value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr");
+ value = CGF.EmitCheckedInBoundsGEP(value, amt, /*SignedIndices=*/false,
+ isSubtraction, E->getExprLoc(),
+ "incdec.funcptr");
value = Builder.CreateBitCast(value, input->getType());
// For everything else, we can just do a simple increment.
@@ -1768,7 +1964,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, amt, "incdec.ptr");
else
- value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr");
+ value = CGF.EmitCheckedInBoundsGEP(value, amt, /*SignedIndices=*/false,
+ isSubtraction, E->getExprLoc(),
+ "incdec.ptr");
}
// Vector increment/decrement.
@@ -1849,7 +2047,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (CGF.getLangOpts().isSignedOverflowDefined())
value = Builder.CreateGEP(value, sizeValue, "incdec.objptr");
else
- value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr");
+ value = CGF.EmitCheckedInBoundsGEP(value, sizeValue,
+ /*SignedIndices=*/false, isSubtraction,
+ E->getExprLoc(), "incdec.objptr");
value = Builder.CreateBitCast(value, input->getType());
}
@@ -1891,7 +2091,7 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
BinOp.Ty = E->getType();
BinOp.Opcode = BO_Sub;
- BinOp.FPContractable = false;
+ // FIXME: once UnaryOperator carries FPFeatures, copy it here.
BinOp.E = E;
return EmitSub(BinOp);
}
@@ -2112,7 +2312,7 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
Result.RHS = Visit(E->getRHS());
Result.Ty = E->getType();
Result.Opcode = E->getOpcode();
- Result.FPContractable = E->isFPContractable();
+ Result.FPFeatures = E->getFPFeatures();
Result.E = E;
return Result;
}
@@ -2132,7 +2332,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
OpInfo.RHS = Visit(E->getRHS());
OpInfo.Ty = E->getComputationResultType();
OpInfo.Opcode = E->getOpcode();
- OpInfo.FPContractable = E->isFPContractable();
+ OpInfo.FPFeatures = E->getFPFeatures();
OpInfo.E = E;
// Load/convert the LHS.
LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
@@ -2263,8 +2463,11 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
SanitizerKind::IntegerDivideByZero));
}
+ const auto *BO = cast<BinaryOperator>(Ops.E);
if (CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) &&
- Ops.Ty->hasSignedIntegerRepresentation()) {
+ Ops.Ty->hasSignedIntegerRepresentation() &&
+ !IsWidenedIntegerOp(CGF.getContext(), BO->getLHS()) &&
+ Ops.mayHaveIntegerOverflow()) {
llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
llvm::Value *IntMin =
@@ -2287,11 +2490,13 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) ||
CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) &&
- Ops.Ty->isIntegerType()) {
+ Ops.Ty->isIntegerType() &&
+ (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
} else if (CGF.SanOpts.has(SanitizerKind::FloatDivideByZero) &&
- Ops.Ty->isRealFloatingType()) {
+ Ops.Ty->isRealFloatingType() &&
+ Ops.mayHaveFloatDivisionByZero()) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
llvm::Value *NonZero = Builder.CreateFCmpUNE(Ops.RHS, Zero);
EmitBinOpCheck(std::make_pair(NonZero, SanitizerKind::FloatDivideByZero),
@@ -2324,12 +2529,13 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
// Rem in C can't be a floating point type: C99 6.5.5p2.
- if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) {
+ if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) ||
+ CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) &&
+ Ops.Ty->isIntegerType() &&
+ (Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
-
- if (Ops.Ty->isIntegerType())
- EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false);
+ EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false);
}
if (Ops.Ty->hasUnsignedIntegerRepresentation())
@@ -2369,6 +2575,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
if (isSigned)
OpID |= 1;
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, opTy);
@@ -2384,7 +2591,6 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
// If the signed-integer-overflow sanitizer is enabled, emit a call to its
// runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *NotOverflow = Builder.CreateNot(overflow);
SanitizerMask Kind = isSigned ? SanitizerKind::SignedIntegerOverflow
: SanitizerKind::UnsignedIntegerOverflow;
@@ -2460,13 +2666,14 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
std::swap(pointerOperand, indexOperand);
}
+ bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
+
unsigned width = cast<llvm::IntegerType>(index->getType())->getBitWidth();
auto &DL = CGF.CGM.getDataLayout();
auto PtrTy = cast<llvm::PointerType>(pointer->getType());
if (width != DL.getTypeSizeInBits(PtrTy)) {
// Zero-extend or sign-extend the pointer value according to
// whether the index is signed or not.
- bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType();
index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned,
"idx.ext");
}
@@ -2510,7 +2717,9 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr");
} else {
index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index");
- pointer = CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
+ pointer =
+ CGF.EmitCheckedInBoundsGEP(pointer, index, isSigned, isSubtraction,
+ op.E->getExprLoc(), "add.ptr");
}
return pointer;
}
@@ -2527,7 +2736,8 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
if (CGF.getLangOpts().isSignedOverflowDefined())
return CGF.Builder.CreateGEP(pointer, index, "add.ptr");
- return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr");
+ return CGF.EmitCheckedInBoundsGEP(pointer, index, isSigned, isSubtraction,
+ op.E->getExprLoc(), "add.ptr");
}
// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and
@@ -2577,12 +2787,7 @@ static Value* tryEmitFMulAdd(const BinOpInfo &op,
"Only fadd/fsub can be the root of an fmuladd.");
// Check whether this op is marked as fusable.
- if (!op.FPContractable)
- return nullptr;
-
- // Check whether -ffp-contract=on. (If -ffp-contract=off/fast, fusing is
- // either disabled, or handled entirely by the LLVM backend).
- if (CGF.CGM.getCodeGenOpts().getFPContractMode() != CodeGenOptions::FPC_On)
+ if (!op.FPFeatures.allowFPContractWithinStatement())
return nullptr;
// We have a potentially fusable op. Look for a mul on one of the operands.
@@ -2605,7 +2810,7 @@ static Value* tryEmitFMulAdd(const BinOpInfo &op,
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
if (op.LHS->getType()->isPointerTy() ||
op.RHS->getType()->isPointerTy())
- return emitPointerArithmetic(CGF, op, /*subtraction*/ false);
+ return emitPointerArithmetic(CGF, op, CodeGenFunction::NotSubtraction);
if (op.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
@@ -2616,12 +2821,15 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
// Fall through.
case LangOptions::SOB_Trapping:
+ if (CanElideOverflowCheck(CGF.getContext(), op))
+ return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
return EmitOverflowCheckedBinOp(op);
}
}
if (op.Ty->isUnsignedIntegerType() &&
- CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow))
+ CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
+ !CanElideOverflowCheck(CGF.getContext(), op))
return EmitOverflowCheckedBinOp(op);
if (op.LHS->getType()->isFPOrFPVectorTy()) {
@@ -2629,7 +2837,8 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
return FMulAdd;
- return Builder.CreateFAdd(op.LHS, op.RHS, "add");
+ Value *V = Builder.CreateFAdd(op.LHS, op.RHS, "add");
+ return propagateFMFlags(V, op);
}
return Builder.CreateAdd(op.LHS, op.RHS, "add");
@@ -2647,19 +2856,23 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
// Fall through.
case LangOptions::SOB_Trapping:
+ if (CanElideOverflowCheck(CGF.getContext(), op))
+ return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
return EmitOverflowCheckedBinOp(op);
}
}
if (op.Ty->isUnsignedIntegerType() &&
- CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow))
+ CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow) &&
+ !CanElideOverflowCheck(CGF.getContext(), op))
return EmitOverflowCheckedBinOp(op);
if (op.LHS->getType()->isFPOrFPVectorTy()) {
// Try to form an fmuladd.
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
return FMulAdd;
- return Builder.CreateFSub(op.LHS, op.RHS, "sub");
+ Value *V = Builder.CreateFSub(op.LHS, op.RHS, "sub");
+ return propagateFMFlags(V, op);
}
return Builder.CreateSub(op.LHS, op.RHS, "sub");
@@ -2668,7 +2881,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
// If the RHS is not a pointer, then we have normal pointer
// arithmetic.
if (!op.RHS->getType()->isPointerTy())
- return emitPointerArithmetic(CGF, op, /*subtraction*/ true);
+ return emitPointerArithmetic(CGF, op, CodeGenFunction::IsSubtraction);
// Otherwise, this is a pointer subtraction.
@@ -2751,8 +2964,8 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
SmallVector<std::pair<Value *, SanitizerMask>, 2> Checks;
- llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS);
- llvm::Value *ValidExponent = Builder.CreateICmpULE(RHS, WidthMinusOne);
+ llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, Ops.RHS);
+ llvm::Value *ValidExponent = Builder.CreateICmpULE(Ops.RHS, WidthMinusOne);
if (SanitizeExponent) {
Checks.push_back(
@@ -2767,12 +2980,14 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
llvm::BasicBlock *CheckShiftBase = CGF.createBasicBlock("check");
Builder.CreateCondBr(ValidExponent, CheckShiftBase, Cont);
+ llvm::Value *PromotedWidthMinusOne =
+ (RHS == Ops.RHS) ? WidthMinusOne
+ : GetWidthMinusOneValue(Ops.LHS, RHS);
CGF.EmitBlock(CheckShiftBase);
- llvm::Value *BitsShiftedOff =
- Builder.CreateLShr(Ops.LHS,
- Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros",
- /*NUW*/true, /*NSW*/true),
- "shl.check");
+ llvm::Value *BitsShiftedOff = Builder.CreateLShr(
+ Ops.LHS, Builder.CreateSub(PromotedWidthMinusOne, RHS, "shl.zeros",
+ /*NUW*/ true, /*NSW*/ true),
+ "shl.check");
if (CGF.getLangOpts().CPlusPlus) {
// In C99, we are not permitted to shift a 1 bit into the sign bit.
// Under C++11's rules, shifting a 1 bit into the sign bit is
@@ -3038,10 +3253,12 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// because the result is altered by the store, i.e., [C99 6.5.16p1]
// 'An assignment expression has the value of the left operand after
// the assignment...'.
- if (LHS.isBitField())
+ if (LHS.isBitField()) {
CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, &RHS);
- else
+ } else {
+ CGF.EmitNullabilityCheck(LHS, RHS, E->getExprLoc());
CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS);
+ }
}
// If the result is clearly ignored, return now.
@@ -3327,9 +3544,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// safe to evaluate the LHS and RHS unconditionally.
if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, CGF) &&
isCheapEnoughToEvaluateUnconditionally(rhsExpr, CGF)) {
- CGF.incrementProfileCounter(E);
-
llvm::Value *CondV = CGF.EvaluateExprAsBool(condExpr);
+ llvm::Value *StepV = Builder.CreateZExtOrBitCast(CondV, CGF.Int64Ty);
+
+ CGF.incrementProfileCounter(E, StepV);
+
llvm::Value *LHS = Visit(lhsExpr);
llvm::Value *RHS = Visit(rhsExpr);
if (!LHS) {
@@ -3491,8 +3710,12 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
// vector to get a vec4, then a bitcast if the target type is different.
if (NumElementsSrc == 3 && NumElementsDst != 3) {
Src = ConvertVec3AndVec4(Builder, CGF, Src, 4);
- Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src,
- DstTy);
+
+ if (!CGF.CGM.getCodeGenOpts().PreserveVec3Type) {
+ Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src,
+ DstTy);
+ }
+
Src->setName("astype");
return Src;
}
@@ -3501,9 +3724,12 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
// to vec4 if the original type is not vec4, then a shuffle vector to
// get a vec3.
if (NumElementsSrc != 3 && NumElementsDst == 3) {
- auto Vec4Ty = llvm::VectorType::get(DstTy->getVectorElementType(), 4);
- Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src,
- Vec4Ty);
+ if (!CGF.CGM.getCodeGenOpts().PreserveVec3Type) {
+ auto Vec4Ty = llvm::VectorType::get(DstTy->getVectorElementType(), 4);
+ Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src,
+ Vec4Ty);
+ }
+
Src = ConvertVec3AndVec4(Builder, CGF, Src, 3);
Src->setName("astype");
return Src;
@@ -3626,3 +3852,136 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
llvm_unreachable("Unhandled compound assignment operator");
}
+
+Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
+ ArrayRef<Value *> IdxList,
+ bool SignedIndices,
+ bool IsSubtraction,
+ SourceLocation Loc,
+ const Twine &Name) {
+ Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);
+
+ // If the pointer overflow sanitizer isn't enabled, do nothing.
+ if (!SanOpts.has(SanitizerKind::PointerOverflow))
+ return GEPVal;
+
+ // If the GEP has already been reduced to a constant, leave it be.
+ if (isa<llvm::Constant>(GEPVal))
+ return GEPVal;
+
+ // Only check for overflows in the default address space.
+ if (GEPVal->getType()->getPointerAddressSpace())
+ return GEPVal;
+
+ auto *GEP = cast<llvm::GEPOperator>(GEPVal);
+ assert(GEP->isInBounds() && "Expected inbounds GEP");
+
+ SanitizerScope SanScope(this);
+ auto &VMContext = getLLVMContext();
+ const auto &DL = CGM.getDataLayout();
+ auto *IntPtrTy = DL.getIntPtrType(GEP->getPointerOperandType());
+
+ // Grab references to the signed add/mul overflow intrinsics for intptr_t.
+ auto *Zero = llvm::ConstantInt::getNullValue(IntPtrTy);
+ auto *SAddIntrinsic =
+ CGM.getIntrinsic(llvm::Intrinsic::sadd_with_overflow, IntPtrTy);
+ auto *SMulIntrinsic =
+ CGM.getIntrinsic(llvm::Intrinsic::smul_with_overflow, IntPtrTy);
+
+ // The total (signed) byte offset for the GEP.
+ llvm::Value *TotalOffset = nullptr;
+ // The offset overflow flag - true if the total offset overflows.
+ llvm::Value *OffsetOverflows = Builder.getFalse();
+
+ /// Return the result of the given binary operation.
+ auto eval = [&](BinaryOperator::Opcode Opcode, llvm::Value *LHS,
+ llvm::Value *RHS) -> llvm::Value * {
+ assert((Opcode == BO_Add || Opcode == BO_Mul) && "Can't eval binop");
+
+ // If the operands are constants, return a constant result.
+ if (auto *LHSCI = dyn_cast<llvm::ConstantInt>(LHS)) {
+ if (auto *RHSCI = dyn_cast<llvm::ConstantInt>(RHS)) {
+ llvm::APInt N;
+ bool HasOverflow = mayHaveIntegerOverflow(LHSCI, RHSCI, Opcode,
+ /*Signed=*/true, N);
+ if (HasOverflow)
+ OffsetOverflows = Builder.getTrue();
+ return llvm::ConstantInt::get(VMContext, N);
+ }
+ }
+
+ // Otherwise, compute the result with checked arithmetic.
+ auto *ResultAndOverflow = Builder.CreateCall(
+ (Opcode == BO_Add) ? SAddIntrinsic : SMulIntrinsic, {LHS, RHS});
+ OffsetOverflows = Builder.CreateOr(
+ Builder.CreateExtractValue(ResultAndOverflow, 1), OffsetOverflows);
+ return Builder.CreateExtractValue(ResultAndOverflow, 0);
+ };
+
+ // Determine the total byte offset by looking at each GEP operand.
+ for (auto GTI = llvm::gep_type_begin(GEP), GTE = llvm::gep_type_end(GEP);
+ GTI != GTE; ++GTI) {
+ llvm::Value *LocalOffset;
+ auto *Index = GTI.getOperand();
+ // Compute the local offset contributed by this indexing step:
+ if (auto *STy = GTI.getStructTypeOrNull()) {
+ // For struct indexing, the local offset is the byte position of the
+ // specified field.
+ unsigned FieldNo = cast<llvm::ConstantInt>(Index)->getZExtValue();
+ LocalOffset = llvm::ConstantInt::get(
+ IntPtrTy, DL.getStructLayout(STy)->getElementOffset(FieldNo));
+ } else {
+ // Otherwise this is array-like indexing. The local offset is the index
+ // multiplied by the element size.
+ auto *ElementSize = llvm::ConstantInt::get(
+ IntPtrTy, DL.getTypeAllocSize(GTI.getIndexedType()));
+ auto *IndexS = Builder.CreateIntCast(Index, IntPtrTy, /*isSigned=*/true);
+ LocalOffset = eval(BO_Mul, ElementSize, IndexS);
+ }
+
+ // If this is the first offset, set it as the total offset. Otherwise, add
+ // the local offset into the running total.
+ if (!TotalOffset || TotalOffset == Zero)
+ TotalOffset = LocalOffset;
+ else
+ TotalOffset = eval(BO_Add, TotalOffset, LocalOffset);
+ }
+
+ // Common case: if the total offset is zero, don't emit a check.
+ if (TotalOffset == Zero)
+ return GEPVal;
+
+ // Now that we've computed the total offset, add it to the base pointer (with
+ // wrapping semantics).
+ auto *IntPtr = Builder.CreatePtrToInt(GEP->getPointerOperand(), IntPtrTy);
+ auto *ComputedGEP = Builder.CreateAdd(IntPtr, TotalOffset);
+
+ // The GEP is valid if:
+ // 1) The total offset doesn't overflow, and
+ // 2) The sign of the difference between the computed address and the base
+ // pointer matches the sign of the total offset.
+ llvm::Value *ValidGEP;
+ auto *NoOffsetOverflow = Builder.CreateNot(OffsetOverflows);
+ if (SignedIndices) {
+ auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
+ auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero);
+ llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr);
+ ValidGEP = Builder.CreateAnd(
+ Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid),
+ NoOffsetOverflow);
+ } else if (!SignedIndices && !IsSubtraction) {
+ auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
+ ValidGEP = Builder.CreateAnd(PosOrZeroValid, NoOffsetOverflow);
+ } else {
+ auto *NegOrZeroValid = Builder.CreateICmpULE(ComputedGEP, IntPtr);
+ ValidGEP = Builder.CreateAnd(NegOrZeroValid, NoOffsetOverflow);
+ }
+
+ llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)};
+ // Pass the computed GEP to the runtime to avoid emitting poisoned arguments.
+ llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};
+ EmitCheck(std::make_pair(ValidGEP, SanitizerKind::PointerOverflow),
+ SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs);
+
+ return GEPVal;
+}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCUDABuiltin.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGGPUBuiltin.cpp
index 44dd003..48156b1 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCUDABuiltin.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGGPUBuiltin.cpp
@@ -1,4 +1,4 @@
-//===----- CGCUDABuiltin.cpp - Codegen for CUDA builtins ------------------===//
+//===------ CGGPUBuiltin.cpp - Codegen for GPU builtins -------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// Generates code for built-in CUDA calls which are not runtime-specific.
-// (Runtime-specific codegen lives in CGCUDARuntime.)
+// Generates code for built-in GPU calls which are not runtime-specific.
+// (Runtime-specific codegen lives in programming model specific files.)
//
//===----------------------------------------------------------------------===//
@@ -67,10 +67,9 @@ static llvm::Function *GetVprintfDeclaration(llvm::Module &M) {
// Note that by the time this function runs, E's args have already undergone the
// standard C vararg promotion (short -> int, float -> double, etc.).
RValue
-CodeGenFunction::EmitCUDADevicePrintfCallExpr(const CallExpr *E,
- ReturnValueSlot ReturnValue) {
- assert(getLangOpts().CUDA);
- assert(getLangOpts().CUDAIsDevice);
+CodeGenFunction::EmitNVPTXDevicePrintfCallExpr(const CallExpr *E,
+ ReturnValueSlot ReturnValue) {
+ assert(getTarget().getTriple().isNVPTX());
assert(E->getBuiltinCallee() == Builtin::BIprintf);
assert(E->getNumArgs() >= 1); // printf always has at least one arg.
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
index 932b8a1..90fcad26 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
@@ -1,4 +1,4 @@
-//===---- CGBuiltin.cpp - Emit LLVM Code for builtins ---------------------===//
+//===---- CGObjC.cpp - Emit LLVM Code for Objective-C ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -117,10 +117,24 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
const ObjCArrayLiteral *ALE = dyn_cast<ObjCArrayLiteral>(E);
if (!ALE)
DLE = cast<ObjCDictionaryLiteral>(E);
-
- // Compute the type of the array we're initializing.
+
+ // Optimize empty collections by referencing constants, when available.
uint64_t NumElements =
ALE ? ALE->getNumElements() : DLE->getNumElements();
+ if (NumElements == 0 && CGM.getLangOpts().ObjCRuntime.hasEmptyCollections()) {
+ StringRef ConstantName = ALE ? "__NSArray0__" : "__NSDictionary0__";
+ QualType IdTy(CGM.getContext().getObjCIdType());
+ llvm::Constant *Constant =
+ CGM.CreateRuntimeVariable(ConvertType(IdTy), ConstantName);
+ LValue LV = MakeNaturalAlignAddrLValue(Constant, IdTy);
+ llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getLocStart());
+ cast<llvm::LoadInst>(Ptr)->setMetadata(
+ CGM.getModule().getMDKindID("invariant.load"),
+ llvm::MDNode::get(getLLVMContext(), None));
+ return Builder.CreateBitCast(Ptr, ConvertType(E->getType()));
+ }
+
+ // Compute the type of the array we're initializing.
llvm::APInt APNumElements(Context.getTypeSize(Context.getSizeType()),
NumElements);
QualType ElementType = Context.getObjCIdType().withConst();
@@ -148,7 +162,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
const Expr *Rhs = ALE->getElement(i);
LValue LV = MakeAddrLValue(
Builder.CreateConstArrayGEP(Objects, i, getPointerSize()),
- ElementType, AlignmentSource::Decl);
+ ElementType, LValueBaseInfo(AlignmentSource::Decl, false));
llvm::Value *value = EmitScalarExpr(Rhs);
EmitStoreThroughLValue(RValue::get(value), LV, true);
@@ -160,7 +174,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
const Expr *Key = DLE->getKeyValueElement(i).Key;
LValue KeyLV = MakeAddrLValue(
Builder.CreateConstArrayGEP(Keys, i, getPointerSize()),
- ElementType, AlignmentSource::Decl);
+ ElementType, LValueBaseInfo(AlignmentSource::Decl, false));
llvm::Value *keyValue = EmitScalarExpr(Key);
EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true);
@@ -168,7 +182,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
const Expr *Value = DLE->getKeyValueElement(i).Value;
LValue ValueLV = MakeAddrLValue(
Builder.CreateConstArrayGEP(Objects, i, getPointerSize()),
- ElementType, AlignmentSource::Decl);
+ ElementType, LValueBaseInfo(AlignmentSource::Decl, false));
llvm::Value *valueValue = EmitScalarExpr(Value);
EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true);
if (TrackNeededObjects) {
@@ -427,7 +441,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
QualType ResultType = method ? method->getReturnType() : E->getType();
CallArgList Args;
- EmitCallArgs(Args, method, E->arguments());
+ EmitCallArgs(Args, method, E->arguments(), /*AC*/AbstractCallee(method));
// For delegate init calls in ARC, do an unsafe store of null into
// self. This represents the call taking direct ownership of that
@@ -1316,7 +1330,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
BinaryOperator assign(&ivarRef, finalArg, BO_Assign,
ivarRef.getType(), VK_RValue, OK_Ordinary,
- SourceLocation(), false);
+ SourceLocation(), FPOptions());
EmitStmt(&assign);
}
@@ -1469,6 +1483,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
if (DI)
DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
+ RunCleanupsScope ForScope(*this);
+
// The local variable comes into scope immediately.
AutoVarEmission variable = AutoVarEmission::invalid();
if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement()))
@@ -1499,8 +1515,6 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
ArrayType::Normal, 0);
Address ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr");
- RunCleanupsScope ForScope(*this);
-
// Emit the collection pointer. In ARC, we do a retain.
llvm::Value *Collection;
if (getLangOpts().ObjCAutoRefCount) {
@@ -1802,26 +1816,45 @@ void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
}
+static bool IsForwarding(StringRef Name) {
+ return llvm::StringSwitch<bool>(Name)
+ .Cases("objc_autoreleaseReturnValue", // ARCInstKind::AutoreleaseRV
+ "objc_autorelease", // ARCInstKind::Autorelease
+ "objc_retainAutoreleaseReturnValue", // ARCInstKind::FusedRetainAutoreleaseRV
+ "objc_retainAutoreleasedReturnValue", // ARCInstKind::RetainRV
+ "objc_retainAutorelease", // ARCInstKind::FusedRetainAutorelease
+ "objc_retainedObject", // ARCInstKind::NoopCast
+ "objc_retain", // ARCInstKind::Retain
+ "objc_unretainedObject", // ARCInstKind::NoopCast
+ "objc_unretainedPointer", // ARCInstKind::NoopCast
+ "objc_unsafeClaimAutoreleasedReturnValue", // ARCInstKind::ClaimRV
+ true)
+ .Default(false);
+}
+
static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
- llvm::FunctionType *type,
- StringRef fnName) {
- llvm::Constant *fn = CGM.CreateRuntimeFunction(type, fnName);
+ llvm::FunctionType *FTy,
+ StringRef Name) {
+ llvm::Constant *RTF = CGM.CreateRuntimeFunction(FTy, Name);
- if (llvm::Function *f = dyn_cast<llvm::Function>(fn)) {
+ if (auto *F = dyn_cast<llvm::Function>(RTF)) {
// If the target runtime doesn't naturally support ARC, emit weak
// references to the runtime support library. We don't really
// permit this to fail, but we need a particular relocation style.
if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC() &&
!CGM.getTriple().isOSBinFormatCOFF()) {
- f->setLinkage(llvm::Function::ExternalWeakLinkage);
- } else if (fnName == "objc_retain" || fnName == "objc_release") {
+ F->setLinkage(llvm::Function::ExternalWeakLinkage);
+ } else if (Name == "objc_retain" || Name == "objc_release") {
// If we have Native ARC, set nonlazybind attribute for these APIs for
// performance.
- f->addFnAttr(llvm::Attribute::NonLazyBind);
+ F->addFnAttr(llvm::Attribute::NonLazyBind);
}
+
+ if (IsForwarding(Name))
+ F->arg_begin()->addAttr(llvm::Attribute::Returned);
}
- return fn;
+ return RTF;
}
/// Perform an operation having the signature
@@ -1832,7 +1865,8 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
llvm::Constant *&fn,
StringRef fnName,
bool isTailCall = false) {
- if (isa<llvm::ConstantPointerNull>(value)) return value;
+ if (isa<llvm::ConstantPointerNull>(value))
+ return value;
if (!fn) {
llvm::FunctionType *fnType =
@@ -2381,6 +2415,12 @@ void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
CGF.EmitARCDestroyWeak(addr);
}
+void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr,
+ QualType type) {
+ llvm::Value *value = CGF.Builder.CreateLoad(addr);
+ CGF.EmitARCIntrinsicUse(value);
+}
+
namespace {
struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup {
llvm::Value *Token;
@@ -3206,10 +3246,12 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
SrcTy = C.getPointerType(SrcTy);
FunctionArgList args;
- ImplicitParamDecl dstDecl(getContext(), FD, SourceLocation(), nullptr,DestTy);
- args.push_back(&dstDecl);
- ImplicitParamDecl srcDecl(getContext(), FD, SourceLocation(), nullptr, SrcTy);
- args.push_back(&srcDecl);
+ ImplicitParamDecl DstDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
+ DestTy, ImplicitParamDecl::Other);
+ args.push_back(&DstDecl);
+ ImplicitParamDecl SrcDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
+ SrcTy, ImplicitParamDecl::Other);
+ args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
@@ -3225,12 +3267,12 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
StartFunction(FD, C.VoidTy, Fn, FI, args);
- DeclRefExpr DstExpr(&dstDecl, false, DestTy,
+ DeclRefExpr DstExpr(&DstDecl, false, DestTy,
VK_RValue, SourceLocation());
UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation());
- DeclRefExpr SrcExpr(&srcDecl, false, SrcTy,
+ DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy,
VK_RValue, SourceLocation());
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation());
@@ -3239,7 +3281,7 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
CXXOperatorCallExpr TheCall(C, OO_Equal, CalleeExp->getCallee(),
Args, DestTy->getPointeeType(),
- VK_LValue, SourceLocation(), false);
+ VK_LValue, SourceLocation(), FPOptions());
EmitStmt(&TheCall);
@@ -3287,10 +3329,12 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
SrcTy = C.getPointerType(SrcTy);
FunctionArgList args;
- ImplicitParamDecl dstDecl(getContext(), FD, SourceLocation(), nullptr,DestTy);
- args.push_back(&dstDecl);
- ImplicitParamDecl srcDecl(getContext(), FD, SourceLocation(), nullptr, SrcTy);
- args.push_back(&srcDecl);
+ ImplicitParamDecl DstDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
+ DestTy, ImplicitParamDecl::Other);
+ args.push_back(&DstDecl);
+ ImplicitParamDecl SrcDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
+ SrcTy, ImplicitParamDecl::Other);
+ args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
@@ -3305,7 +3349,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
StartFunction(FD, C.VoidTy, Fn, FI, args);
- DeclRefExpr SrcExpr(&srcDecl, false, SrcTy,
+ DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy,
VK_RValue, SourceLocation());
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
@@ -3331,7 +3375,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
CXXConstExpr->getConstructionKind(),
SourceRange());
- DeclRefExpr DstExpr(&dstDecl, false, DestTy,
+ DeclRefExpr DstExpr(&DstDecl, false, DestTy,
VK_RValue, SourceLocation());
RValue DV = EmitAnyExpr(&DstExpr);
@@ -3375,5 +3419,54 @@ CodeGenFunction::EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty) {
return Val;
}
+llvm::Value *
+CodeGenFunction::EmitBuiltinAvailable(ArrayRef<llvm::Value *> Args) {
+ assert(Args.size() == 3 && "Expected 3 argument here!");
+
+ if (!CGM.IsOSVersionAtLeastFn) {
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(Int32Ty, {Int32Ty, Int32Ty, Int32Ty}, false);
+ CGM.IsOSVersionAtLeastFn =
+ CGM.CreateRuntimeFunction(FTy, "__isOSVersionAtLeast");
+ }
+
+ llvm::Value *CallRes =
+ EmitNounwindRuntimeCall(CGM.IsOSVersionAtLeastFn, Args);
+
+ return Builder.CreateICmpNE(CallRes, llvm::Constant::getNullValue(Int32Ty));
+}
+
+void CodeGenModule::emitAtAvailableLinkGuard() {
+ if (!IsOSVersionAtLeastFn)
+ return;
+ // @available requires CoreFoundation only on Darwin.
+ if (!Target.getTriple().isOSDarwin())
+ return;
+ // Add -framework CoreFoundation to the linker commands. We still want to
+ // emit the core foundation reference down below because otherwise if
+ // CoreFoundation is not used in the code, the linker won't link the
+ // framework.
+ auto &Context = getLLVMContext();
+ llvm::Metadata *Args[2] = {llvm::MDString::get(Context, "-framework"),
+ llvm::MDString::get(Context, "CoreFoundation")};
+ LinkerOptionsMetadata.push_back(llvm::MDNode::get(Context, Args));
+ // Emit a reference to a symbol from CoreFoundation to ensure that
+ // CoreFoundation is linked into the final binary.
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(Int32Ty, {VoidPtrTy}, false);
+ llvm::Constant *CFFunc =
+ CreateRuntimeFunction(FTy, "CFBundleGetVersionNumber");
+
+ llvm::FunctionType *CheckFTy = llvm::FunctionType::get(VoidTy, {}, false);
+ llvm::Function *CFLinkCheckFunc = cast<llvm::Function>(CreateBuiltinFunction(
+ CheckFTy, "__clang_at_available_requires_core_foundation_framework"));
+ CFLinkCheckFunc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+ CFLinkCheckFunc->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ CodeGenFunction CGF(*this);
+ CGF.Builder.SetInsertPoint(CGF.createBasicBlock("", CFLinkCheckFunc));
+ CGF.EmitNounwindRuntimeCall(CFFunc, llvm::Constant::getNullValue(VoidPtrTy));
+ CGF.Builder.CreateUnreachable();
+ addCompilerUsedGlobal(CFLinkCheckFunc);
+}
CGObjCRuntime::~CGObjCRuntime() {}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp
index fa2b3d8..c8b8be7 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -18,7 +18,7 @@
#include "CGCleanup.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "ConstantBuilder.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -34,7 +34,6 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Compiler.h"
-#include <cstdarg>
using namespace clang;
using namespace CodeGen;
@@ -58,18 +57,19 @@ public:
/// Initialises the lazy function with the name, return type, and the types
/// of the arguments.
- LLVM_END_WITH_NULL
- void init(CodeGenModule *Mod, const char *name, llvm::Type *RetTy, ...) {
+ template <typename... Tys>
+ void init(CodeGenModule *Mod, const char *name, llvm::Type *RetTy,
+ Tys *... Types) {
CGM = Mod;
FunctionName = name;
Function = nullptr;
- std::vector<llvm::Type *> ArgTys;
- va_list Args;
- va_start(Args, RetTy);
- while (llvm::Type *ArgTy = va_arg(Args, llvm::Type *))
- ArgTys.push_back(ArgTy);
- va_end(Args);
- FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
+ if(sizeof...(Tys)) {
+ SmallVector<llvm::Type *, 8> ArgTys({Types...});
+ FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
+ }
+ else {
+ FTy = llvm::FunctionType::get(RetTy, None, false);
+ }
}
llvm::FunctionType *getType() { return FTy; }
@@ -603,11 +603,10 @@ protected:
public:
CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) {
// IMP objc_msg_lookup(id, SEL);
- MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy,
- nullptr);
+ MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy);
// IMP objc_msg_lookup_super(struct objc_super*, SEL);
MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
- PtrToObjCSuperTy, SelectorTy, nullptr);
+ PtrToObjCSuperTy, SelectorTy);
}
};
@@ -663,7 +662,7 @@ class CGObjCGNUstep : public CGObjCGNU {
}
// The lookup function is guaranteed not to capture the receiver pointer.
- LookupFn->setDoesNotCapture(1);
+ LookupFn->addParamAttr(0, llvm::Attribute::NoCapture);
llvm::Value *args[] = {
EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy),
@@ -702,52 +701,51 @@ class CGObjCGNUstep : public CGObjCGNU {
CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) {
const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
- llvm::StructType *SlotStructTy = llvm::StructType::get(PtrTy,
- PtrTy, PtrTy, IntTy, IMPTy, nullptr);
+ llvm::StructType *SlotStructTy =
+ llvm::StructType::get(PtrTy, PtrTy, PtrTy, IntTy, IMPTy);
SlotTy = llvm::PointerType::getUnqual(SlotStructTy);
// Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
SlotLookupFn.init(&CGM, "objc_msg_lookup_sender", SlotTy, PtrToIdTy,
- SelectorTy, IdTy, nullptr);
+ SelectorTy, IdTy);
// Slot_t objc_msg_lookup_super(struct objc_super*, SEL);
SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
- PtrToObjCSuperTy, SelectorTy, nullptr);
+ PtrToObjCSuperTy, SelectorTy);
// If we're in ObjC++ mode, then we want to make
if (CGM.getLangOpts().CPlusPlus) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void *__cxa_begin_catch(void *e)
- EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, nullptr);
+ EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy);
// void __cxa_end_catch(void)
- ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, nullptr);
+ ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy);
// void _Unwind_Resume_or_Rethrow(void*)
ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy,
- PtrTy, nullptr);
+ PtrTy);
} else if (R.getVersion() >= VersionTuple(1, 7)) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// id objc_begin_catch(void *e)
- EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy, nullptr);
+ EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy);
// void objc_end_catch(void)
- ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy, nullptr);
+ ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy);
// void _Unwind_Resume_or_Rethrow(void*)
- ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy,
- PtrTy, nullptr);
+ ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, PtrTy);
}
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy,
- SelectorTy, IdTy, PtrDiffTy, nullptr);
+ SelectorTy, IdTy, PtrDiffTy);
SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy,
- IdTy, SelectorTy, IdTy, PtrDiffTy, nullptr);
+ IdTy, SelectorTy, IdTy, PtrDiffTy);
SetPropertyNonAtomic.init(&CGM, "objc_setProperty_nonatomic", VoidTy,
- IdTy, SelectorTy, IdTy, PtrDiffTy, nullptr);
+ IdTy, SelectorTy, IdTy, PtrDiffTy);
SetPropertyNonAtomicCopy.init(&CGM, "objc_setProperty_nonatomic_copy",
- VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy, nullptr);
+ VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy);
// void objc_setCppObjectAtomic(void *dest, const void *src, void
// *helper);
CxxAtomicObjectSetFn.init(&CGM, "objc_setCppObjectAtomic", VoidTy, PtrTy,
- PtrTy, PtrTy, nullptr);
+ PtrTy, PtrTy);
// void objc_getCppObjectAtomic(void *dest, const void *src, void
// *helper);
CxxAtomicObjectGetFn.init(&CGM, "objc_getCppObjectAtomic", VoidTy, PtrTy,
- PtrTy, PtrTy, nullptr);
+ PtrTy, PtrTy);
}
llvm::Constant *GetCppAtomicObjectGetFunction() override {
@@ -849,14 +847,14 @@ protected:
public:
CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
// IMP objc_msg_lookup(id, SEL);
- MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, nullptr);
+ MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy);
MsgLookupFnSRet.init(&CGM, "objc_msg_lookup_stret", IMPTy, IdTy,
- SelectorTy, nullptr);
+ SelectorTy);
// IMP objc_msg_lookup_super(struct objc_super*, SEL);
MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
- PtrToObjCSuperTy, SelectorTy, nullptr);
+ PtrToObjCSuperTy, SelectorTy);
MsgLookupSuperFnSRet.init(&CGM, "objc_msg_lookup_super_stret", IMPTy,
- PtrToObjCSuperTy, SelectorTy, nullptr);
+ PtrToObjCSuperTy, SelectorTy);
}
};
} // end anonymous namespace
@@ -945,35 +943,34 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
}
PtrToIdTy = llvm::PointerType::getUnqual(IdTy);
- ObjCSuperTy = llvm::StructType::get(IdTy, IdTy, nullptr);
+ ObjCSuperTy = llvm::StructType::get(IdTy, IdTy);
PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy);
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void objc_exception_throw(id);
- ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, nullptr);
- ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, nullptr);
+ ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
+ ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy);
// int objc_sync_enter(id);
- SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy, nullptr);
+ SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy);
// int objc_sync_exit(id);
- SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy, nullptr);
+ SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy);
// void objc_enumerationMutation (id)
- EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy,
- IdTy, nullptr);
+ EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy, IdTy);
// id objc_getProperty(id, SEL, ptrdiff_t, BOOL)
GetPropertyFn.init(&CGM, "objc_getProperty", IdTy, IdTy, SelectorTy,
- PtrDiffTy, BoolTy, nullptr);
+ PtrDiffTy, BoolTy);
// void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL)
SetPropertyFn.init(&CGM, "objc_setProperty", VoidTy, IdTy, SelectorTy,
- PtrDiffTy, IdTy, BoolTy, BoolTy, nullptr);
+ PtrDiffTy, IdTy, BoolTy, BoolTy);
// void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
- GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy,
- PtrDiffTy, BoolTy, BoolTy, nullptr);
+ GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy,
+ PtrDiffTy, BoolTy, BoolTy);
// void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
- SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy,
- PtrDiffTy, BoolTy, BoolTy, nullptr);
+ SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy,
+ PtrDiffTy, BoolTy, BoolTy);
// IMP type
llvm::Type *IMPArgs[] = { IdTy, SelectorTy };
@@ -997,21 +994,19 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
// Get functions needed in GC mode
// id objc_assign_ivar(id, id, ptrdiff_t);
- IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy,
- nullptr);
+ IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy);
// id objc_assign_strongCast (id, id*)
StrongCastAssignFn.init(&CGM, "objc_assign_strongCast", IdTy, IdTy,
- PtrToIdTy, nullptr);
+ PtrToIdTy);
// id objc_assign_global(id, id*);
- GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy,
- nullptr);
+ GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy);
// id objc_assign_weak(id, id*);
- WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy, nullptr);
+ WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy);
// id objc_read_weak(id*);
- WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy, nullptr);
+ WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy);
// void *objc_memmove_collectable(void*, void *, size_t);
MemMoveFn.init(&CGM, "objc_memmove_collectable", PtrTy, PtrTy, PtrTy,
- SizeTy, nullptr);
+ SizeTy);
}
}
@@ -1317,7 +1312,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
}
}
// Cast the pointer to a simplified version of the class structure
- llvm::Type *CastTy = llvm::StructType::get(IdTy, IdTy, nullptr);
+ llvm::Type *CastTy = llvm::StructType::get(IdTy, IdTy);
ReceiverClass = Builder.CreateBitCast(ReceiverClass,
llvm::PointerType::getUnqual(CastTy));
// Get the superclass pointer
@@ -1326,8 +1321,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
ReceiverClass =
Builder.CreateAlignedLoad(ReceiverClass, CGF.getPointerAlign());
// Construct the structure used to look up the IMP
- llvm::StructType *ObjCSuperTy = llvm::StructType::get(
- Receiver->getType(), IdTy, nullptr);
+ llvm::StructType *ObjCSuperTy =
+ llvm::StructType::get(Receiver->getType(), IdTy);
// FIXME: Is this really supposed to be a dynamic alloca?
Address ObjCSuper = Address(Builder.CreateAlloca(ObjCSuperTy),
@@ -1565,11 +1560,8 @@ GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
IvarList.addInt(IntTy, (int)IvarNames.size());
// Get the ivar structure type.
- llvm::StructType *ObjCIvarTy = llvm::StructType::get(
- PtrToInt8Ty,
- PtrToInt8Ty,
- IntTy,
- nullptr);
+ llvm::StructType *ObjCIvarTy =
+ llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy);
// Array of ivar structures.
auto Ivars = IvarList.beginArray(ObjCIvarTy);
@@ -1611,7 +1603,7 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
// anyway; the classes will still work with the GNU runtime, they will just
// be ignored.
llvm::StructType *ClassTy = llvm::StructType::get(
- PtrToInt8Ty, // isa
+ PtrToInt8Ty, // isa
PtrToInt8Ty, // super_class
PtrToInt8Ty, // name
LongTy, // version
@@ -1620,18 +1612,18 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
IVars->getType(), // ivars
Methods->getType(), // methods
// These are all filled in by the runtime, so we pretend
- PtrTy, // dtable
- PtrTy, // subclass_list
- PtrTy, // sibling_class
- PtrTy, // protocols
- PtrTy, // gc_object_type
+ PtrTy, // dtable
+ PtrTy, // subclass_list
+ PtrTy, // sibling_class
+ PtrTy, // protocols
+ PtrTy, // gc_object_type
// New ABI:
LongTy, // abi_version
IvarOffsets->getType(), // ivar_offsets
Properties->getType(), // properties
IntPtrTy, // strong_pointers
- IntPtrTy, // weak_pointers
- nullptr);
+ IntPtrTy // weak_pointers
+ );
ConstantInitBuilder Builder(CGM);
auto Elements = Builder.beginStruct(ClassTy);
@@ -2207,7 +2199,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
IvarNames.push_back(MakeConstantString(IVD->getNameAsString()));
// Get the type encoding for this ivar
std::string TypeStr;
- Context.getObjCEncodingForType(IVD->getType(), TypeStr);
+ Context.getObjCEncodingForType(IVD->getType(), TypeStr, IVD);
IvarTypes.push_back(MakeConstantString(TypeStr));
// Get the offset
uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD);
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
index 7219592..98435fe 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
@@ -17,7 +17,7 @@
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "ConstantBuilder.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -64,13 +64,11 @@ private:
// Add the non-lazy-bind attribute, since objc_msgSend is likely to
// be called a lot.
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSend",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NonLazyBind));
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(ObjectPtrTy, params, true), "objc_msgSend",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NonLazyBind));
}
/// void objc_msgSend_stret (id, SEL, ...)
@@ -107,8 +105,8 @@ private:
llvm::Constant *getMessageSendFp2retFn() const {
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
llvm::Type *longDoubleType = llvm::Type::getX86_FP80Ty(VMContext);
- llvm::Type *resultType =
- llvm::StructType::get(longDoubleType, longDoubleType, nullptr);
+ llvm::Type *resultType =
+ llvm::StructType::get(longDoubleType, longDoubleType);
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(resultType,
params, true),
@@ -310,7 +308,7 @@ public:
SmallVector<CanQualType,5> Params;
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
- Params.push_back(Ctx.LongTy);
+ Params.push_back(Ctx.getSizeType());
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
@@ -589,13 +587,11 @@ public:
llvm::Constant *getSetJmpFn() {
// This is specifically the prototype for x86.
llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
- params, false),
- "_setjmp",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NonLazyBind));
+ return CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(CGM.Int32Ty, params, false), "_setjmp",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NonLazyBind));
}
public:
@@ -890,7 +886,7 @@ protected:
/// Cached reference to the class for constant strings. This value has type
/// int * but is actually an Obj-C class pointer.
- llvm::WeakVH ConstantStringClassRef;
+ llvm::WeakTrackingVH ConstantStringClassRef;
/// \brief The LLVM type corresponding to NSConstantString.
llvm::StructType *NSConstantStringType = nullptr;
@@ -1008,6 +1004,8 @@ protected:
const ObjCInterfaceDecl *ID,
ObjCCommonTypesHelper &ObjCTypes);
+ std::string GetSectionName(StringRef Section, StringRef MachOAttributes);
+
public:
/// CreateMetadataVar - Create a global variable with internal
/// linkage for use by the Objective-C runtime.
@@ -1680,7 +1678,10 @@ struct NullReturnState {
/// Complete the null-return operation. It is valid to call this
/// regardless of whether 'init' has been called.
- RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType,
+ RValue complete(CodeGenFunction &CGF,
+ ReturnValueSlot returnSlot,
+ RValue result,
+ QualType resultType,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
// If we never had to do a null-check, just use the raw result.
@@ -1747,7 +1748,8 @@ struct NullReturnState {
// memory or (2) agg values in registers.
if (result.isAggregate()) {
assert(result.isAggregate() && "null init of non-aggregate result?");
- CGF.EmitNullInitialization(result.getAggregateAddress(), resultType);
+ if (!returnSlot.isUnused())
+ CGF.EmitNullInitialization(result.getAggregateAddress(), resultType);
if (contBB) CGF.EmitBlock(contBB);
return result;
}
@@ -2119,11 +2121,11 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
}
}
- NullReturnState nullReturn;
+ bool RequiresNullCheck = false;
llvm::Constant *Fn = nullptr;
if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
- if (ReceiverCanBeNull) nullReturn.init(CGF, Arg0);
+ if (ReceiverCanBeNull) RequiresNullCheck = true;
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
@@ -2136,23 +2138,30 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
// arm64 uses objc_msgSend for stret methods and yet null receiver check
// must be made for it.
if (ReceiverCanBeNull && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
- nullReturn.init(CGF, Arg0);
+ RequiresNullCheck = true;
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
}
+ // We don't need to emit a null check to zero out an indirect result if the
+ // result is ignored.
+ if (Return.isUnused())
+ RequiresNullCheck = false;
+
// Emit a null-check if there's a consumed argument other than the receiver.
- bool RequiresNullCheck = false;
- if (ReceiverCanBeNull && CGM.getLangOpts().ObjCAutoRefCount && Method) {
+ if (!RequiresNullCheck && CGM.getLangOpts().ObjCAutoRefCount && Method) {
for (const auto *ParamDecl : Method->parameters()) {
if (ParamDecl->hasAttr<NSConsumedAttr>()) {
- if (!nullReturn.NullBB)
- nullReturn.init(CGF, Arg0);
RequiresNullCheck = true;
break;
}
}
}
+
+ NullReturnState nullReturn;
+ if (RequiresNullCheck) {
+ nullReturn.init(CGF, Arg0);
+ }
llvm::Instruction *CallSite;
Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType);
@@ -2166,7 +2175,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
llvm::CallSite(CallSite).setDoesNotReturn();
}
- return nullReturn.complete(CGF, rvalue, ResultType, CallArgs,
+ return nullReturn.complete(CGF, Return, rvalue, ResultType, CallArgs,
RequiresNullCheck ? Method : nullptr);
}
@@ -4790,6 +4799,27 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
/* *** Private Interface *** */
+std::string CGObjCCommonMac::GetSectionName(StringRef Section,
+ StringRef MachOAttributes) {
+ switch (CGM.getTriple().getObjectFormat()) {
+ default:
+ llvm_unreachable("unexpected object file format");
+ case llvm::Triple::MachO: {
+ if (MachOAttributes.empty())
+ return ("__DATA," + Section).str();
+ return ("__DATA," + Section + "," + MachOAttributes).str();
+ }
+ case llvm::Triple::ELF:
+ assert(Section.substr(0, 2) == "__" &&
+ "expected the name to begin with __");
+ return Section.substr(2).str();
+ case llvm::Triple::COFF:
+ assert(Section.substr(0, 2) == "__" &&
+ "expected the name to begin with __");
+ return ("." + Section.substr(2) + "$B").str();
+ }
+}
+
/// EmitImageInfo - Emit the image info marker used to encode some module
/// level information.
///
@@ -4813,9 +4843,10 @@ enum ImageInfoFlags {
void CGObjCCommonMac::EmitImageInfo() {
unsigned version = 0; // Version is unused?
- const char *Section = (ObjCABI == 1) ?
- "__OBJC, __image_info,regular" :
- "__DATA, __objc_imageinfo, regular, no_dead_strip";
+ std::string Section =
+ (ObjCABI == 1)
+ ? "__OBJC,__image_info,regular"
+ : GetSectionName("__objc_imageinfo", "regular,no_dead_strip");
// Generate module-level named metadata to convey this information to the
// linker and code-gen.
@@ -4826,7 +4857,7 @@ void CGObjCCommonMac::EmitImageInfo() {
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Version",
version);
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Image Info Section",
- llvm::MDString::get(VMContext,Section));
+ llvm::MDString::get(VMContext, Section));
if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
// Non-GC overrides those files which specify GC.
@@ -5510,17 +5541,15 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *name;
// char *attributes;
// }
- PropertyTy = llvm::StructType::create("struct._prop_t",
- Int8PtrTy, Int8PtrTy, nullptr);
+ PropertyTy = llvm::StructType::create("struct._prop_t", Int8PtrTy, Int8PtrTy);
// struct _prop_list_t {
// uint32_t entsize; // sizeof(struct _prop_t)
// uint32_t count_of_properties;
// struct _prop_t prop_list[count_of_properties];
// }
- PropertyListTy =
- llvm::StructType::create("struct._prop_list_t", IntTy, IntTy,
- llvm::ArrayType::get(PropertyTy, 0), nullptr);
+ PropertyListTy = llvm::StructType::create(
+ "struct._prop_list_t", IntTy, IntTy, llvm::ArrayType::get(PropertyTy, 0));
// struct _prop_list_t *
PropertyListPtrTy = llvm::PointerType::getUnqual(PropertyListTy);
@@ -5529,9 +5558,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *method_type;
// char *_imp;
// }
- MethodTy = llvm::StructType::create("struct._objc_method",
- SelectorPtrTy, Int8PtrTy, Int8PtrTy,
- nullptr);
+ MethodTy = llvm::StructType::create("struct._objc_method", SelectorPtrTy,
+ Int8PtrTy, Int8PtrTy);
// struct _objc_cache *
CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
@@ -5544,17 +5572,16 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// SEL name;
// char *types;
// }
- MethodDescriptionTy =
- llvm::StructType::create("struct._objc_method_description",
- SelectorPtrTy, Int8PtrTy, nullptr);
+ MethodDescriptionTy = llvm::StructType::create(
+ "struct._objc_method_description", SelectorPtrTy, Int8PtrTy);
// struct _objc_method_description_list {
// int count;
// struct _objc_method_description[1];
// }
- MethodDescriptionListTy = llvm::StructType::create(
- "struct._objc_method_description_list", IntTy,
- llvm::ArrayType::get(MethodDescriptionTy, 0), nullptr);
+ MethodDescriptionListTy =
+ llvm::StructType::create("struct._objc_method_description_list", IntTy,
+ llvm::ArrayType::get(MethodDescriptionTy, 0));
// struct _objc_method_description_list *
MethodDescriptionListPtrTy =
@@ -5570,11 +5597,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// const char ** extendedMethodTypes;
// struct _objc_property_list *class_properties;
// }
- ProtocolExtensionTy =
- llvm::StructType::create("struct._objc_protocol_extension",
- IntTy, MethodDescriptionListPtrTy,
- MethodDescriptionListPtrTy, PropertyListPtrTy,
- Int8PtrPtrTy, PropertyListPtrTy, nullptr);
+ ProtocolExtensionTy = llvm::StructType::create(
+ "struct._objc_protocol_extension", IntTy, MethodDescriptionListPtrTy,
+ MethodDescriptionListPtrTy, PropertyListPtrTy, Int8PtrPtrTy,
+ PropertyListPtrTy);
// struct _objc_protocol_extension *
ProtocolExtensionPtrTy = llvm::PointerType::getUnqual(ProtocolExtensionTy);
@@ -5586,10 +5612,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
ProtocolListTy =
llvm::StructType::create(VMContext, "struct._objc_protocol_list");
- ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy),
- LongTy,
- llvm::ArrayType::get(ProtocolTy, 0),
- nullptr);
+ ProtocolListTy->setBody(llvm::PointerType::getUnqual(ProtocolListTy), LongTy,
+ llvm::ArrayType::get(ProtocolTy, 0));
// struct _objc_protocol {
// struct _objc_protocol_extension *isa;
@@ -5600,9 +5624,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// }
ProtocolTy->setBody(ProtocolExtensionPtrTy, Int8PtrTy,
llvm::PointerType::getUnqual(ProtocolListTy),
- MethodDescriptionListPtrTy,
- MethodDescriptionListPtrTy,
- nullptr);
+ MethodDescriptionListPtrTy, MethodDescriptionListPtrTy);
// struct _objc_protocol_list *
ProtocolListPtrTy = llvm::PointerType::getUnqual(ProtocolListTy);
@@ -5616,8 +5638,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *ivar_type;
// int ivar_offset;
// }
- IvarTy = llvm::StructType::create("struct._objc_ivar",
- Int8PtrTy, Int8PtrTy, IntTy, nullptr);
+ IvarTy = llvm::StructType::create("struct._objc_ivar", Int8PtrTy, Int8PtrTy,
+ IntTy);
// struct _objc_ivar_list *
IvarListTy =
@@ -5630,9 +5652,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
MethodListPtrTy = llvm::PointerType::getUnqual(MethodListTy);
// struct _objc_class_extension *
- ClassExtensionTy =
- llvm::StructType::create("struct._objc_class_extension",
- IntTy, Int8PtrTy, PropertyListPtrTy, nullptr);
+ ClassExtensionTy = llvm::StructType::create(
+ "struct._objc_class_extension", IntTy, Int8PtrTy, PropertyListPtrTy);
ClassExtensionPtrTy = llvm::PointerType::getUnqual(ClassExtensionTy);
ClassTy = llvm::StructType::create(VMContext, "struct._objc_class");
@@ -5652,18 +5673,9 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_class_ext *ext;
// };
ClassTy->setBody(llvm::PointerType::getUnqual(ClassTy),
- llvm::PointerType::getUnqual(ClassTy),
- Int8PtrTy,
- LongTy,
- LongTy,
- LongTy,
- IvarListPtrTy,
- MethodListPtrTy,
- CachePtrTy,
- ProtocolListPtrTy,
- Int8PtrTy,
- ClassExtensionPtrTy,
- nullptr);
+ llvm::PointerType::getUnqual(ClassTy), Int8PtrTy, LongTy,
+ LongTy, LongTy, IvarListPtrTy, MethodListPtrTy, CachePtrTy,
+ ProtocolListPtrTy, Int8PtrTy, ClassExtensionPtrTy);
ClassPtrTy = llvm::PointerType::getUnqual(ClassTy);
@@ -5677,12 +5689,10 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// struct _objc_property_list *instance_properties;// category's @property
// struct _objc_property_list *class_properties;
// }
- CategoryTy =
- llvm::StructType::create("struct._objc_category",
- Int8PtrTy, Int8PtrTy, MethodListPtrTy,
- MethodListPtrTy, ProtocolListPtrTy,
- IntTy, PropertyListPtrTy, PropertyListPtrTy,
- nullptr);
+ CategoryTy = llvm::StructType::create(
+ "struct._objc_category", Int8PtrTy, Int8PtrTy, MethodListPtrTy,
+ MethodListPtrTy, ProtocolListPtrTy, IntTy, PropertyListPtrTy,
+ PropertyListPtrTy);
// Global metadata structures
@@ -5693,10 +5703,9 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// short cat_def_cnt;
// char *defs[cls_def_cnt + cat_def_cnt];
// }
- SymtabTy =
- llvm::StructType::create("struct._objc_symtab",
- LongTy, SelectorPtrTy, ShortTy, ShortTy,
- llvm::ArrayType::get(Int8PtrTy, 0), nullptr);
+ SymtabTy = llvm::StructType::create("struct._objc_symtab", LongTy,
+ SelectorPtrTy, ShortTy, ShortTy,
+ llvm::ArrayType::get(Int8PtrTy, 0));
SymtabPtrTy = llvm::PointerType::getUnqual(SymtabTy);
// struct _objc_module {
@@ -5705,10 +5714,8 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// char *name;
// struct _objc_symtab* symtab;
// }
- ModuleTy =
- llvm::StructType::create("struct._objc_module",
- LongTy, LongTy, Int8PtrTy, SymtabPtrTy, nullptr);
-
+ ModuleTy = llvm::StructType::create("struct._objc_module", LongTy, LongTy,
+ Int8PtrTy, SymtabPtrTy);
// FIXME: This is the size of the setjmp buffer and should be target
// specific. 18 is what's used on 32-bit X86.
@@ -5717,10 +5724,9 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
// Exceptions
llvm::Type *StackPtrTy = llvm::ArrayType::get(CGM.Int8PtrTy, 4);
- ExceptionDataTy =
- llvm::StructType::create("struct._objc_exception_data",
- llvm::ArrayType::get(CGM.Int32Ty,SetJmpBufferSize),
- StackPtrTy, nullptr);
+ ExceptionDataTy = llvm::StructType::create(
+ "struct._objc_exception_data",
+ llvm::ArrayType::get(CGM.Int32Ty, SetJmpBufferSize), StackPtrTy);
}
ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm)
@@ -5731,8 +5737,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct _objc_method method_list[method_count];
// }
MethodListnfABITy =
- llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
- llvm::ArrayType::get(MethodTy, 0), nullptr);
+ llvm::StructType::create("struct.__method_list_t", IntTy, IntTy,
+ llvm::ArrayType::get(MethodTy, 0));
// struct method_list_t *
MethodListnfABIPtrTy = llvm::PointerType::getUnqual(MethodListnfABITy);
@@ -5756,14 +5762,12 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
ProtocolListnfABITy =
llvm::StructType::create(VMContext, "struct._objc_protocol_list");
- ProtocolnfABITy =
- llvm::StructType::create("struct._protocol_t", ObjectPtrTy, Int8PtrTy,
- llvm::PointerType::getUnqual(ProtocolListnfABITy),
- MethodListnfABIPtrTy, MethodListnfABIPtrTy,
- MethodListnfABIPtrTy, MethodListnfABIPtrTy,
- PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy,
- Int8PtrTy, PropertyListPtrTy,
- nullptr);
+ ProtocolnfABITy = llvm::StructType::create(
+ "struct._protocol_t", ObjectPtrTy, Int8PtrTy,
+ llvm::PointerType::getUnqual(ProtocolListnfABITy), MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy, MethodListnfABIPtrTy, MethodListnfABIPtrTy,
+ PropertyListPtrTy, IntTy, IntTy, Int8PtrPtrTy, Int8PtrTy,
+ PropertyListPtrTy);
// struct _protocol_t*
ProtocolnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolnfABITy);
@@ -5773,8 +5777,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct _protocol_t *[protocol_count];
// }
ProtocolListnfABITy->setBody(LongTy,
- llvm::ArrayType::get(ProtocolnfABIPtrTy, 0),
- nullptr);
+ llvm::ArrayType::get(ProtocolnfABIPtrTy, 0));
// struct _objc_protocol_list*
ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
@@ -5788,7 +5791,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
IvarnfABITy = llvm::StructType::create(
"struct._ivar_t", llvm::PointerType::getUnqual(IvarOffsetVarTy),
- Int8PtrTy, Int8PtrTy, IntTy, IntTy, nullptr);
+ Int8PtrTy, Int8PtrTy, IntTy, IntTy);
// struct _ivar_list_t {
// uint32 entsize; // sizeof(struct _ivar_t)
@@ -5796,8 +5799,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// struct _iver_t list[count];
// }
IvarListnfABITy =
- llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
- llvm::ArrayType::get(IvarnfABITy, 0), nullptr);
+ llvm::StructType::create("struct._ivar_list_t", IntTy, IntTy,
+ llvm::ArrayType::get(IvarnfABITy, 0));
IvarListnfABIPtrTy = llvm::PointerType::getUnqual(IvarListnfABITy);
@@ -5816,13 +5819,10 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// }
// FIXME. Add 'reserved' field in 64bit abi mode!
- ClassRonfABITy = llvm::StructType::create("struct._class_ro_t",
- IntTy, IntTy, IntTy, Int8PtrTy,
- Int8PtrTy, MethodListnfABIPtrTy,
- ProtocolListnfABIPtrTy,
- IvarListnfABIPtrTy,
- Int8PtrTy, PropertyListPtrTy,
- nullptr);
+ ClassRonfABITy = llvm::StructType::create(
+ "struct._class_ro_t", IntTy, IntTy, IntTy, Int8PtrTy, Int8PtrTy,
+ MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, IvarListnfABIPtrTy,
+ Int8PtrTy, PropertyListPtrTy);
// ImpnfABITy - LLVM for id (*)(id, SEL, ...)
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
@@ -5839,11 +5839,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
ClassnfABITy = llvm::StructType::create(VMContext, "struct._class_t");
ClassnfABITy->setBody(llvm::PointerType::getUnqual(ClassnfABITy),
- llvm::PointerType::getUnqual(ClassnfABITy),
- CachePtrTy,
+ llvm::PointerType::getUnqual(ClassnfABITy), CachePtrTy,
llvm::PointerType::getUnqual(ImpnfABITy),
- llvm::PointerType::getUnqual(ClassRonfABITy),
- nullptr);
+ llvm::PointerType::getUnqual(ClassRonfABITy));
// LLVM for struct _class_t *
ClassnfABIPtrTy = llvm::PointerType::getUnqual(ClassnfABITy);
@@ -5858,15 +5856,10 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// const struct _prop_list_t * const class_properties;
// const uint32_t size;
// }
- CategorynfABITy = llvm::StructType::create("struct._category_t",
- Int8PtrTy, ClassnfABIPtrTy,
- MethodListnfABIPtrTy,
- MethodListnfABIPtrTy,
- ProtocolListnfABIPtrTy,
- PropertyListPtrTy,
- PropertyListPtrTy,
- IntTy,
- nullptr);
+ CategorynfABITy = llvm::StructType::create(
+ "struct._category_t", Int8PtrTy, ClassnfABIPtrTy, MethodListnfABIPtrTy,
+ MethodListnfABIPtrTy, ProtocolListnfABIPtrTy, PropertyListPtrTy,
+ PropertyListPtrTy, IntTy);
// New types for nonfragile abi messaging.
CodeGen::CodeGenTypes &Types = CGM.getTypes();
@@ -5903,9 +5896,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// SUPER_IMP messenger;
// SEL name;
// };
- SuperMessageRefTy =
- llvm::StructType::create("struct._super_message_ref_t",
- ImpnfABITy, SelectorPtrTy, nullptr);
+ SuperMessageRefTy = llvm::StructType::create("struct._super_message_ref_t",
+ ImpnfABITy, SelectorPtrTy);
// SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
SuperMessageRefPtrTy = llvm::PointerType::getUnqual(SuperMessageRefTy);
@@ -5916,10 +5908,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// const char* name; // c++ typeinfo string
// Class cls;
// };
- EHTypeTy =
- llvm::StructType::create("struct._objc_typeinfo",
- llvm::PointerType::getUnqual(Int8PtrTy),
- Int8PtrTy, ClassnfABIPtrTy, nullptr);
+ EHTypeTy = llvm::StructType::create("struct._objc_typeinfo",
+ llvm::PointerType::getUnqual(Int8PtrTy),
+ Int8PtrTy, ClassnfABIPtrTy);
EHTypePtrTy = llvm::PointerType::getUnqual(EHTypeTy);
}
@@ -5974,17 +5965,21 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
}
AddModuleClassList(DefinedClasses, "OBJC_LABEL_CLASS_$",
- "__DATA, __objc_classlist, regular, no_dead_strip");
+ GetSectionName("__objc_classlist",
+ "regular,no_dead_strip"));
AddModuleClassList(DefinedNonLazyClasses, "OBJC_LABEL_NONLAZY_CLASS_$",
- "__DATA, __objc_nlclslist, regular, no_dead_strip");
+ GetSectionName("__objc_nlclslist",
+ "regular,no_dead_strip"));
// Build list of all implemented category addresses in array
// L_OBJC_LABEL_CATEGORY_$.
AddModuleClassList(DefinedCategories, "OBJC_LABEL_CATEGORY_$",
- "__DATA, __objc_catlist, regular, no_dead_strip");
+ GetSectionName("__objc_catlist",
+ "regular,no_dead_strip"));
AddModuleClassList(DefinedNonLazyCategories, "OBJC_LABEL_NONLAZY_CATEGORY_$",
- "__DATA, __objc_nlcatlist, regular, no_dead_strip");
+ GetSectionName("__objc_nlcatlist",
+ "regular,no_dead_strip"));
EmitImageInfo();
}
@@ -6397,15 +6392,15 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
return CGF.Builder.CreateAlignedLoad(PTGV, Align);
- PTGV = new llvm::GlobalVariable(
- CGM.getModule(),
- Init->getType(), false,
- llvm::GlobalValue::WeakAnyLinkage,
- Init,
- ProtocolName);
- PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
+ PTGV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
+ llvm::GlobalValue::WeakAnyLinkage, Init,
+ ProtocolName);
+ PTGV->setSection(GetSectionName("__objc_protorefs",
+ "coalesced,no_dead_strip"));
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
PTGV->setAlignment(Align.getQuantity());
+ if (!CGM.getTriple().isOSBinFormatMachO())
+ PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolName));
CGM.addCompilerUsedGlobal(PTGV);
return CGF.Builder.CreateAlignedLoad(PTGV, Align);
}
@@ -6862,8 +6857,8 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolRef));
PTGV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
- if (CGM.getTriple().isOSBinFormatMachO())
- PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
+ PTGV->setSection(GetSectionName("__objc_protolist",
+ "coalesced,no_dead_strip"));
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.addCompilerUsedGlobal(PTGV);
return Entry;
@@ -7059,7 +7054,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
/*constant*/ false,
llvm::GlobalValue::WeakAnyLinkage);
messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility);
- messageRef->setSection("__DATA, __objc_msgrefs, coalesced");
+ messageRef->setSection(GetSectionName("__objc_msgrefs", "coalesced"));
}
bool requiresnullCheck = false;
@@ -7089,7 +7084,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
CGCallee callee(CGCalleeInfo(), calleePtr);
RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args);
- return nullReturn.complete(CGF, result, resultType, formalArgs,
+ return nullReturn.complete(CGF, returnSlot, result, resultType, formalArgs,
requiresnullCheck ? method : nullptr);
}
@@ -7170,7 +7165,8 @@ CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
false, llvm::GlobalValue::PrivateLinkage,
ClassGV, "OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(Align.getQuantity());
- Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
+ Entry->setSection(GetSectionName("__objc_classrefs",
+ "regular,no_dead_strip"));
CGM.addCompilerUsedGlobal(Entry);
}
return CGF.Builder.CreateAlignedLoad(Entry, Align);
@@ -7204,7 +7200,8 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
false, llvm::GlobalValue::PrivateLinkage,
ClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(Align.getQuantity());
- Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
+ Entry->setSection(GetSectionName("__objc_superrefs",
+ "regular,no_dead_strip"));
CGM.addCompilerUsedGlobal(Entry);
}
return CGF.Builder.CreateAlignedLoad(Entry, Align);
@@ -7226,7 +7223,8 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
MetaClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(Align.getQuantity());
- Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
+ Entry->setSection(GetSectionName("__objc_superrefs",
+ "regular,no_dead_strip"));
CGM.addCompilerUsedGlobal(Entry);
}
@@ -7322,7 +7320,8 @@ Address CGObjCNonFragileABIMac::EmitSelectorAddr(CodeGenFunction &CGF,
false, llvm::GlobalValue::PrivateLinkage,
Casted, "OBJC_SELECTOR_REFERENCES_");
Entry->setExternallyInitialized(true);
- Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
+ Entry->setSection(GetSectionName("__objc_selrefs",
+ "literal_pointers,no_dead_strip"));
Entry->setAlignment(Align.getQuantity());
CGM.addCompilerUsedGlobal(Entry);
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp
index 3da7ed2..4cfddcb 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp
@@ -26,61 +26,27 @@
using namespace clang;
using namespace CodeGen;
-static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
- const ObjCInterfaceDecl *OID,
- const ObjCImplementationDecl *ID,
- const ObjCIvarDecl *Ivar) {
- const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
-
- // FIXME: We should eliminate the need to have ObjCImplementationDecl passed
- // in here; it should never be necessary because that should be the lexical
- // decl context for the ivar.
-
- // If we know have an implementation (and the ivar is in it) then
- // look up in the implementation layout.
- const ASTRecordLayout *RL;
- if (ID && declaresSameEntity(ID->getClassInterface(), Container))
- RL = &CGM.getContext().getASTObjCImplementationLayout(ID);
- else
- RL = &CGM.getContext().getASTObjCInterfaceLayout(Container);
-
- // Compute field index.
- //
- // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is
- // implemented. This should be fixed to get the information from the layout
- // directly.
- unsigned Index = 0;
-
- for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin();
- IVD; IVD = IVD->getNextIvar()) {
- if (Ivar == IVD)
- break;
- ++Index;
- }
- assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!");
-
- return RL->getFieldOffset(Index);
-}
-
uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
const ObjCInterfaceDecl *OID,
const ObjCIvarDecl *Ivar) {
- return LookupFieldBitOffset(CGM, OID, nullptr, Ivar) /
- CGM.getContext().getCharWidth();
+ return CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar) /
+ CGM.getContext().getCharWidth();
}
uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
const ObjCImplementationDecl *OID,
const ObjCIvarDecl *Ivar) {
- return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) /
- CGM.getContext().getCharWidth();
+ return CGM.getContext().lookupFieldBitOffset(OID->getClassInterface(), OID,
+ Ivar) /
+ CGM.getContext().getCharWidth();
}
unsigned CGObjCRuntime::ComputeBitfieldBitOffset(
CodeGen::CodeGenModule &CGM,
const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar) {
- return LookupFieldBitOffset(CGM, ID, ID->getImplementation(), Ivar);
+ return CGM.getContext().lookupFieldBitOffset(ID, ID->getImplementation(),
+ Ivar);
}
LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
@@ -90,7 +56,11 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
unsigned CVRQualifiers,
llvm::Value *Offset) {
// Compute (type*) ( (char *) BaseValue + Offset)
- QualType IvarTy = Ivar->getType().withCVRQualifiers(CVRQualifiers);
+ QualType InterfaceTy{OID->getTypeForDecl(), 0};
+ QualType ObjectPtrTy =
+ CGF.CGM.getContext().getObjCObjectPointerType(InterfaceTy);
+ QualType IvarTy =
+ Ivar->getUsageType(ObjectPtrTy).withCVRQualifiers(CVRQualifiers);
llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy);
V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr");
@@ -115,7 +85,8 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
// Note, there is a subtle invariant here: we can only call this routine on
// non-synthesized ivars but we may be called for synthesized ivars. However,
// a synthesized ivar can never be a bit-field, so this is safe.
- uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, nullptr, Ivar);
+ uint64_t FieldBitOffset =
+ CGF.CGM.getContext().lookupFieldBitOffset(OID, nullptr, Ivar);
uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign();
uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
@@ -138,7 +109,8 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
Addr = CGF.Builder.CreateElementBitCast(Addr,
llvm::Type::getIntNTy(CGF.getLLVMContext(),
Info->StorageSize));
- return LValue::MakeBitfield(Addr, *Info, IvarTy, AlignmentSource::Decl);
+ return LValue::MakeBitfield(Addr, *Info, IvarTy,
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
namespace {
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp
index 9062936..db02c63 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -58,9 +58,6 @@ llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
case BuiltinType::OCLQueue:
return llvm::PointerType::get(
llvm::StructType::create(Ctx, "opencl.queue_t"), 0);
- case BuiltinType::OCLNDRange:
- return llvm::PointerType::get(
- llvm::StructType::create(Ctx, "opencl.ndrange_t"), 0);
case BuiltinType::OCLReserveID:
return llvm::PointerType::get(
llvm::StructType::create(Ctx, "opencl.reserve_id_t"), 0);
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 4025217..d488bd4 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -15,7 +15,7 @@
#include "CGCleanup.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
-#include "ConstantBuilder.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/Decl.h"
#include "clang/AST/StmtOpenMP.h"
#include "llvm/ADT/ArrayRef.h"
@@ -643,6 +643,12 @@ enum OpenMPRTLFunction {
// Call to void __kmpc_doacross_wait(ident_t *loc, kmp_int32 gtid, kmp_int64
// *vec);
OMPRTL__kmpc_doacross_wait,
+ // Call to void *__kmpc_task_reduction_init(int gtid, int num_data, void
+ // *data);
+ OMPRTL__kmpc_task_reduction_init,
+ // Call to void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
+ // *d);
+ OMPRTL__kmpc_task_reduction_get_th_data,
//
// Offloading related calls
@@ -697,6 +703,414 @@ void RegionCodeGenTy::operator()(CodeGenFunction &CGF) const {
}
}
+/// Check if the combiner is a call to UDR combiner and if it is so return the
+/// UDR decl used for reduction.
+static const OMPDeclareReductionDecl *
+getReductionInit(const Expr *ReductionOp) {
+ if (auto *CE = dyn_cast<CallExpr>(ReductionOp))
+ if (auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
+ if (auto *DRE =
+ dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
+ if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl()))
+ return DRD;
+ return nullptr;
+}
+
+static void emitInitWithReductionInitializer(CodeGenFunction &CGF,
+ const OMPDeclareReductionDecl *DRD,
+ const Expr *InitOp,
+ Address Private, Address Original,
+ QualType Ty) {
+ if (DRD->getInitializer()) {
+ std::pair<llvm::Function *, llvm::Function *> Reduction =
+ CGF.CGM.getOpenMPRuntime().getUserDefinedReduction(DRD);
+ auto *CE = cast<CallExpr>(InitOp);
+ auto *OVE = cast<OpaqueValueExpr>(CE->getCallee());
+ const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
+ const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
+ auto *LHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(LHS)->getSubExpr());
+ auto *RHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(RHS)->getSubExpr());
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ PrivateScope.addPrivate(cast<VarDecl>(LHSDRE->getDecl()),
+ [=]() -> Address { return Private; });
+ PrivateScope.addPrivate(cast<VarDecl>(RHSDRE->getDecl()),
+ [=]() -> Address { return Original; });
+ (void)PrivateScope.Privatize();
+ RValue Func = RValue::get(Reduction.second);
+ CodeGenFunction::OpaqueValueMapping Map(CGF, OVE, Func);
+ CGF.EmitIgnoredExpr(InitOp);
+ } else {
+ llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty);
+ auto *GV = new llvm::GlobalVariable(
+ CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, Init, ".init");
+ LValue LV = CGF.MakeNaturalAlignAddrLValue(GV, Ty);
+ RValue InitRVal;
+ switch (CGF.getEvaluationKind(Ty)) {
+ case TEK_Scalar:
+ InitRVal = CGF.EmitLoadOfLValue(LV, SourceLocation());
+ break;
+ case TEK_Complex:
+ InitRVal =
+ RValue::getComplex(CGF.EmitLoadOfComplex(LV, SourceLocation()));
+ break;
+ case TEK_Aggregate:
+ InitRVal = RValue::getAggregate(LV.getAddress());
+ break;
+ }
+ OpaqueValueExpr OVE(SourceLocation(), Ty, VK_RValue);
+ CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal);
+ CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
+ /*IsInitializer=*/false);
+ }
+}
+
+/// \brief Emit initialization of arrays of complex types.
+/// \param DestAddr Address of the array.
+/// \param Type Type of array.
+/// \param Init Initial expression of array.
+/// \param SrcAddr Address of the original array.
+static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
+ QualType Type, const Expr *Init,
+ const OMPDeclareReductionDecl *DRD,
+ Address SrcAddr = Address::invalid()) {
+ // Perform element-by-element initialization.
+ QualType ElementTy;
+
+ // Drill down to the base element type on both arrays.
+ auto ArrayTy = Type->getAsArrayTypeUnsafe();
+ auto NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
+ DestAddr =
+ CGF.Builder.CreateElementBitCast(DestAddr, DestAddr.getElementType());
+ if (DRD)
+ SrcAddr =
+ CGF.Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType());
+
+ llvm::Value *SrcBegin = nullptr;
+ if (DRD)
+ SrcBegin = SrcAddr.getPointer();
+ auto DestBegin = DestAddr.getPointer();
+ // Cast from pointer to array type to pointer to single element.
+ auto DestEnd = CGF.Builder.CreateGEP(DestBegin, NumElements);
+ // The basic structure here is a while-do loop.
+ auto BodyBB = CGF.createBasicBlock("omp.arrayinit.body");
+ auto DoneBB = CGF.createBasicBlock("omp.arrayinit.done");
+ auto IsEmpty =
+ CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty");
+ CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
+
+ // Enter the loop body, making that address the current address.
+ auto EntryBB = CGF.Builder.GetInsertBlock();
+ CGF.EmitBlock(BodyBB);
+
+ CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
+
+ llvm::PHINode *SrcElementPHI = nullptr;
+ Address SrcElementCurrent = Address::invalid();
+ if (DRD) {
+ SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2,
+ "omp.arraycpy.srcElementPast");
+ SrcElementPHI->addIncoming(SrcBegin, EntryBB);
+ SrcElementCurrent =
+ Address(SrcElementPHI,
+ SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
+ }
+ llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
+ DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
+ DestElementPHI->addIncoming(DestBegin, EntryBB);
+ Address DestElementCurrent =
+ Address(DestElementPHI,
+ DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
+
+ // Emit copy.
+ {
+ CodeGenFunction::RunCleanupsScope InitScope(CGF);
+ if (DRD && (DRD->getInitializer() || !Init)) {
+ emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent,
+ SrcElementCurrent, ElementTy);
+ } else
+ CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
+ /*IsInitializer=*/false);
+ }
+
+ if (DRD) {
+ // Shift the address forward by one element.
+ auto SrcElementNext = CGF.Builder.CreateConstGEP1_32(
+ SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
+ SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock());
+ }
+
+ // Shift the address forward by one element.
+ auto DestElementNext = CGF.Builder.CreateConstGEP1_32(
+ DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
+ // Check whether we've reached the end.
+ auto Done =
+ CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
+ CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
+ DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock());
+
+ // Done.
+ CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
+}
+
+LValue ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, const Expr *E) {
+ if (const auto *OASE = dyn_cast<OMPArraySectionExpr>(E))
+ return CGF.EmitOMPArraySectionExpr(OASE);
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
+ return CGF.EmitLValue(ASE);
+ auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
+ DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD),
+ CGF.CapturedStmtInfo &&
+ CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr,
+ E->getType(), VK_LValue, E->getExprLoc());
+ // Store the address of the original variable associated with the LHS
+ // implicit variable.
+ return CGF.EmitLValue(&DRE);
+}
+
+LValue ReductionCodeGen::emitSharedLValueUB(CodeGenFunction &CGF,
+ const Expr *E) {
+ if (const auto *OASE = dyn_cast<OMPArraySectionExpr>(E))
+ return CGF.EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false);
+ return LValue();
+}
+
+void ReductionCodeGen::emitAggregateInitialization(
+ CodeGenFunction &CGF, unsigned N, Address PrivateAddr, LValue SharedLVal,
+ const OMPDeclareReductionDecl *DRD) {
+ // Emit VarDecl with copy init for arrays.
+ // Get the address of the original variable captured in current
+ // captured region.
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ EmitOMPAggregateInit(CGF, PrivateAddr, PrivateVD->getType(),
+ DRD ? ClausesData[N].ReductionOp : PrivateVD->getInit(),
+ DRD, SharedLVal.getAddress());
+}
+
+ReductionCodeGen::ReductionCodeGen(ArrayRef<const Expr *> Shareds,
+ ArrayRef<const Expr *> Privates,
+ ArrayRef<const Expr *> ReductionOps) {
+ ClausesData.reserve(Shareds.size());
+ SharedAddresses.reserve(Shareds.size());
+ Sizes.reserve(Shareds.size());
+ BaseDecls.reserve(Shareds.size());
+ auto IPriv = Privates.begin();
+ auto IRed = ReductionOps.begin();
+ for (const auto *Ref : Shareds) {
+ ClausesData.emplace_back(Ref, *IPriv, *IRed);
+ std::advance(IPriv, 1);
+ std::advance(IRed, 1);
+ }
+}
+
+void ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, unsigned N) {
+ assert(SharedAddresses.size() == N &&
+ "Number of generated lvalues must be exactly N.");
+ SharedAddresses.emplace_back(emitSharedLValue(CGF, ClausesData[N].Ref),
+ emitSharedLValueUB(CGF, ClausesData[N].Ref));
+}
+
+void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) {
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ QualType PrivateType = PrivateVD->getType();
+ bool AsArraySection = isa<OMPArraySectionExpr>(ClausesData[N].Ref);
+ if (!AsArraySection && !PrivateType->isVariablyModifiedType()) {
+ Sizes.emplace_back(
+ CGF.getTypeSize(
+ SharedAddresses[N].first.getType().getNonReferenceType()),
+ nullptr);
+ return;
+ }
+ llvm::Value *Size;
+ llvm::Value *SizeInChars;
+ llvm::Type *ElemType =
+ cast<llvm::PointerType>(SharedAddresses[N].first.getPointer()->getType())
+ ->getElementType();
+ auto *ElemSizeOf = llvm::ConstantExpr::getSizeOf(ElemType);
+ if (AsArraySection) {
+ Size = CGF.Builder.CreatePtrDiff(SharedAddresses[N].second.getPointer(),
+ SharedAddresses[N].first.getPointer());
+ Size = CGF.Builder.CreateNUWAdd(
+ Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
+ SizeInChars = CGF.Builder.CreateNUWMul(Size, ElemSizeOf);
+ } else {
+ SizeInChars = CGF.getTypeSize(
+ SharedAddresses[N].first.getType().getNonReferenceType());
+ Size = CGF.Builder.CreateExactUDiv(SizeInChars, ElemSizeOf);
+ }
+ Sizes.emplace_back(SizeInChars, Size);
+ CodeGenFunction::OpaqueValueMapping OpaqueMap(
+ CGF,
+ cast<OpaqueValueExpr>(
+ CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
+ RValue::get(Size));
+ CGF.EmitVariablyModifiedType(PrivateType);
+}
+
+void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N,
+ llvm::Value *Size) {
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ QualType PrivateType = PrivateVD->getType();
+ bool AsArraySection = isa<OMPArraySectionExpr>(ClausesData[N].Ref);
+ if (!AsArraySection && !PrivateType->isVariablyModifiedType()) {
+ assert(!Size && !Sizes[N].second &&
+ "Size should be nullptr for non-variably modified redution "
+ "items.");
+ return;
+ }
+ CodeGenFunction::OpaqueValueMapping OpaqueMap(
+ CGF,
+ cast<OpaqueValueExpr>(
+ CGF.getContext().getAsVariableArrayType(PrivateType)->getSizeExpr()),
+ RValue::get(Size));
+ CGF.EmitVariablyModifiedType(PrivateType);
+}
+
+void ReductionCodeGen::emitInitialization(
+ CodeGenFunction &CGF, unsigned N, Address PrivateAddr, LValue SharedLVal,
+ llvm::function_ref<bool(CodeGenFunction &)> DefaultInit) {
+ assert(SharedAddresses.size() > N && "No variable was generated");
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ auto *DRD = getReductionInit(ClausesData[N].ReductionOp);
+ QualType PrivateType = PrivateVD->getType();
+ PrivateAddr = CGF.Builder.CreateElementBitCast(
+ PrivateAddr, CGF.ConvertTypeForMem(PrivateType));
+ QualType SharedType = SharedAddresses[N].first.getType();
+ SharedLVal = CGF.MakeAddrLValue(
+ CGF.Builder.CreateElementBitCast(SharedLVal.getAddress(),
+ CGF.ConvertTypeForMem(SharedType)),
+ SharedType, SharedAddresses[N].first.getBaseInfo());
+ if (isa<OMPArraySectionExpr>(ClausesData[N].Ref) ||
+ CGF.getContext().getAsArrayType(PrivateVD->getType())) {
+ emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD);
+ } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
+ emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp,
+ PrivateAddr, SharedLVal.getAddress(),
+ SharedLVal.getType());
+ } else if (!DefaultInit(CGF) && PrivateVD->hasInit() &&
+ !CGF.isTrivialInitializer(PrivateVD->getInit())) {
+ CGF.EmitAnyExprToMem(PrivateVD->getInit(), PrivateAddr,
+ PrivateVD->getType().getQualifiers(),
+ /*IsInitializer=*/false);
+ }
+}
+
+bool ReductionCodeGen::needCleanups(unsigned N) {
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ QualType PrivateType = PrivateVD->getType();
+ QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
+ return DTorKind != QualType::DK_none;
+}
+
+void ReductionCodeGen::emitCleanups(CodeGenFunction &CGF, unsigned N,
+ Address PrivateAddr) {
+ auto *PrivateVD =
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Private)->getDecl());
+ QualType PrivateType = PrivateVD->getType();
+ QualType::DestructionKind DTorKind = PrivateType.isDestructedType();
+ if (needCleanups(N)) {
+ PrivateAddr = CGF.Builder.CreateElementBitCast(
+ PrivateAddr, CGF.ConvertTypeForMem(PrivateType));
+ CGF.pushDestroy(DTorKind, PrivateAddr, PrivateType);
+ }
+}
+
+static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
+ LValue BaseLV) {
+ BaseTy = BaseTy.getNonReferenceType();
+ while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
+ !CGF.getContext().hasSameType(BaseTy, ElTy)) {
+ if (auto *PtrTy = BaseTy->getAs<PointerType>())
+ BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
+ else {
+ BaseLV = CGF.EmitLoadOfReferenceLValue(BaseLV.getAddress(),
+ BaseTy->castAs<ReferenceType>());
+ }
+ BaseTy = BaseTy->getPointeeType();
+ }
+ return CGF.MakeAddrLValue(
+ CGF.Builder.CreateElementBitCast(BaseLV.getAddress(),
+ CGF.ConvertTypeForMem(ElTy)),
+ BaseLV.getType(), BaseLV.getBaseInfo());
+}
+
+static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
+ llvm::Type *BaseLVType, CharUnits BaseLVAlignment,
+ llvm::Value *Addr) {
+ Address Tmp = Address::invalid();
+ Address TopTmp = Address::invalid();
+ Address MostTopTmp = Address::invalid();
+ BaseTy = BaseTy.getNonReferenceType();
+ while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
+ !CGF.getContext().hasSameType(BaseTy, ElTy)) {
+ Tmp = CGF.CreateMemTemp(BaseTy);
+ if (TopTmp.isValid())
+ CGF.Builder.CreateStore(Tmp.getPointer(), TopTmp);
+ else
+ MostTopTmp = Tmp;
+ TopTmp = Tmp;
+ BaseTy = BaseTy->getPointeeType();
+ }
+ llvm::Type *Ty = BaseLVType;
+ if (Tmp.isValid())
+ Ty = Tmp.getElementType();
+ Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Ty);
+ if (Tmp.isValid()) {
+ CGF.Builder.CreateStore(Addr, Tmp);
+ return MostTopTmp;
+ }
+ return Address(Addr, BaseLVAlignment);
+}
+
+Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N,
+ Address PrivateAddr) {
+ const DeclRefExpr *DE;
+ const VarDecl *OrigVD = nullptr;
+ if (auto *OASE = dyn_cast<OMPArraySectionExpr>(ClausesData[N].Ref)) {
+ auto *Base = OASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
+ Base = TempOASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ DE = cast<DeclRefExpr>(Base);
+ OrigVD = cast<VarDecl>(DE->getDecl());
+ } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(ClausesData[N].Ref)) {
+ auto *Base = ASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ DE = cast<DeclRefExpr>(Base);
+ OrigVD = cast<VarDecl>(DE->getDecl());
+ }
+ if (OrigVD) {
+ BaseDecls.emplace_back(OrigVD);
+ auto OriginalBaseLValue = CGF.EmitLValue(DE);
+ LValue BaseLValue =
+ loadToBegin(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(),
+ OriginalBaseLValue);
+ llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff(
+ BaseLValue.getPointer(), SharedAddresses[N].first.getPointer());
+ llvm::Value *Ptr =
+ CGF.Builder.CreateGEP(PrivateAddr.getPointer(), Adjustment);
+ return castToBase(CGF, OrigVD->getType(),
+ SharedAddresses[N].first.getType(),
+ OriginalBaseLValue.getPointer()->getType(),
+ OriginalBaseLValue.getAlignment(), Ptr);
+ }
+ BaseDecls.emplace_back(
+ cast<VarDecl>(cast<DeclRefExpr>(ClausesData[N].Ref)->getDecl()));
+ return PrivateAddr;
+}
+
+bool ReductionCodeGen::usesReductionInitializer(unsigned N) const {
+ auto *DRD = getReductionInit(ClausesData[N].ReductionOp);
+ return DRD && DRD->getInitializer();
+}
+
LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) {
return CGF.EmitLoadOfPointerLValue(
CGF.GetAddrOfLocalVar(getThreadIDVariable()),
@@ -720,7 +1134,7 @@ LValue CGOpenMPTaskOutlinedRegionInfo::getThreadIDVariableLValue(
CodeGenFunction &CGF) {
return CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(getThreadIDVariable()),
getThreadIDVariable()->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
}
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
@@ -728,7 +1142,7 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
IdentTy = llvm::StructType::create(
"ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */,
CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */,
- CGM.Int8PtrTy /* psource */, nullptr);
+ CGM.Int8PtrTy /* psource */);
KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
loadOffloadInfoMetadata();
@@ -747,9 +1161,9 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
QualType PtrTy = C.getPointerType(Ty).withRestrict();
FunctionArgList Args;
ImplicitParamDecl OmpOutParm(C, /*DC=*/nullptr, Out->getLocation(),
- /*Id=*/nullptr, PtrTy);
+ /*Id=*/nullptr, PtrTy, ImplicitParamDecl::Other);
ImplicitParamDecl OmpInParm(C, /*DC=*/nullptr, In->getLocation(),
- /*Id=*/nullptr, PtrTy);
+ /*Id=*/nullptr, PtrTy, ImplicitParamDecl::Other);
Args.push_back(&OmpOutParm);
Args.push_back(&OmpInParm);
auto &FnInfo =
@@ -760,6 +1174,7 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
IsCombiner ? ".omp_combiner." : ".omp_initializer.", &CGM.getModule());
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
Fn->removeFnAttr(llvm::Attribute::NoInline);
+ Fn->removeFnAttr(llvm::Attribute::OptimizeNone);
Fn->addFnAttr(llvm::Attribute::AlwaysInline);
CodeGenFunction CGF(CGM);
// Map "T omp_in;" variable to "*omp_in_parm" value in all expressions.
@@ -842,12 +1257,12 @@ static Address createIdentFieldGEP(CodeGenFunction &CGF, Address Addr,
return CGF.Builder.CreateStructGEP(Addr, Field, Offset, Name);
}
-llvm::Value *CGOpenMPRuntime::emitParallelOrTeamsOutlinedFunction(
- const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
+static llvm::Value *emitParallelOrTeamsOutlinedFunction(
+ CodeGenModule &CGM, const OMPExecutableDirective &D, const CapturedStmt *CS,
+ const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind,
+ const StringRef OutlinedHelperName, const RegionCodeGenTy &CodeGen) {
assert(ThreadIDVar->getType()->isPointerType() &&
"thread id variable must be of type kmp_int32 *");
- const CapturedStmt *CS = cast<CapturedStmt>(D.getAssociatedStmt());
CodeGenFunction CGF(CGM, true);
bool HasCancel = false;
if (auto *OPD = dyn_cast<OMPParallelDirective>(&D))
@@ -857,11 +1272,27 @@ llvm::Value *CGOpenMPRuntime::emitParallelOrTeamsOutlinedFunction(
else if (auto *OPFD = dyn_cast<OMPParallelForDirective>(&D))
HasCancel = OPFD->hasCancel();
CGOpenMPOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen, InnermostKind,
- HasCancel, getOutlinedHelperName());
+ HasCancel, OutlinedHelperName);
CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
return CGF.GenerateOpenMPCapturedStmtFunction(*CS);
}
+llvm::Value *CGOpenMPRuntime::emitParallelOutlinedFunction(
+ const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
+ OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
+ const CapturedStmt *CS = D.getCapturedStmt(OMPD_parallel);
+ return emitParallelOrTeamsOutlinedFunction(
+ CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(), CodeGen);
+}
+
+llvm::Value *CGOpenMPRuntime::emitTeamsOutlinedFunction(
+ const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
+ OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
+ const CapturedStmt *CS = D.getCapturedStmt(OMPD_teams);
+ return emitParallelOrTeamsOutlinedFunction(
+ CGM, D, CS, ThreadIDVar, InnermostKind, getOutlinedHelperName(), CodeGen);
+}
+
llvm::Value *CGOpenMPRuntime::emitTaskOutlinedFunction(
const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
const VarDecl *PartIDVar, const VarDecl *TaskTVar,
@@ -1537,6 +1968,26 @@ CGOpenMPRuntime::createRuntimeFunction(unsigned Function) {
RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_doacross_wait");
break;
}
+ case OMPRTL__kmpc_task_reduction_init: {
+ // Build void *__kmpc_task_reduction_init(int gtid, int num_data, void
+ // *data);
+ llvm::Type *TypeParams[] = {CGM.IntTy, CGM.IntTy, CGM.VoidPtrTy};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg=*/false);
+ RTLFn =
+ CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_task_reduction_init");
+ break;
+ }
+ case OMPRTL__kmpc_task_reduction_get_th_data: {
+ // Build void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
+ // *d);
+ llvm::Type *TypeParams[] = {CGM.IntTy, CGM.VoidPtrTy, CGM.VoidPtrTy};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(
+ FnTy, /*Name=*/"__kmpc_task_reduction_get_th_data");
+ break;
+ }
case OMPRTL__tgt_target: {
// Build int32_t __tgt_target(int32_t device_id, void *host_ptr, int32_t
// arg_num, void** args_base, void **args, size_t *arg_sizes, int32_t
@@ -1791,8 +2242,8 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
// threadprivate copy of the variable VD
CodeGenFunction CtorCGF(CGM);
FunctionArgList Args;
- ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, CGM.getContext().VoidPtrTy);
+ ImplicitParamDecl Dst(CGM.getContext(), CGM.getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
Args.push_back(&Dst);
auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
@@ -1822,8 +2273,8 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
// of the variable VD
CodeGenFunction DtorCGF(CGM);
FunctionArgList Args;
- ImplicitParamDecl Dst(CGM.getContext(), /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, CGM.getContext().VoidPtrTy);
+ ImplicitParamDecl Dst(CGM.getContext(), CGM.getContext().VoidPtrTy,
+ ImplicitParamDecl::Other);
Args.push_back(&Dst);
auto &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
@@ -1887,6 +2338,27 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
return nullptr;
}
+Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
+ QualType VarType,
+ StringRef Name) {
+ llvm::Twine VarName(Name, ".artificial.");
+ llvm::Type *VarLVType = CGF.ConvertTypeForMem(VarType);
+ llvm::Value *GAddr = getOrCreateInternalVariable(VarLVType, VarName);
+ llvm::Value *Args[] = {
+ emitUpdateLocation(CGF, SourceLocation()),
+ getThreadID(CGF, SourceLocation()),
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(GAddr, CGM.VoidPtrTy),
+ CGF.Builder.CreateIntCast(CGF.getTypeSize(VarType), CGM.SizeTy,
+ /*IsSigned=*/false),
+ getOrCreateInternalVariable(CGM.VoidPtrPtrTy, VarName + ".cache.")};
+ return Address(
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__kmpc_threadprivate_cached), Args),
+ VarLVType->getPointerTo(/*AddrSpace=*/0)),
+ CGM.getPointerAlign());
+}
+
/// \brief Emits code for OpenMP 'if' clause using specified \a CodeGen
/// function. Here is the logic:
/// if (Cond) {
@@ -2174,10 +2646,8 @@ static llvm::Value *emitCopyprivateCopyFunction(
auto &C = CGM.getContext();
// void copy_func(void *LHSArg, void *RHSArg);
FunctionArgList Args;
- ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
- C.VoidPtrTy);
- ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
- C.VoidPtrTy);
+ ImplicitParamDecl LHSArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl RHSArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
Args.push_back(&LHSArg);
Args.push_back(&RHSArg);
auto &CGFI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
@@ -2450,16 +2920,14 @@ static int addMonoNonMonoModifier(OpenMPSchedType Schedule,
return Schedule | Modifier;
}
-void CGOpenMPRuntime::emitForDispatchInit(CodeGenFunction &CGF,
- SourceLocation Loc,
- const OpenMPScheduleTy &ScheduleKind,
- unsigned IVSize, bool IVSigned,
- bool Ordered, llvm::Value *UB,
- llvm::Value *Chunk) {
+void CGOpenMPRuntime::emitForDispatchInit(
+ CodeGenFunction &CGF, SourceLocation Loc,
+ const OpenMPScheduleTy &ScheduleKind, unsigned IVSize, bool IVSigned,
+ bool Ordered, const DispatchRTInput &DispatchValues) {
if (!CGF.HaveInsertPoint())
return;
- OpenMPSchedType Schedule =
- getRuntimeSchedule(ScheduleKind.Schedule, Chunk != nullptr, Ordered);
+ OpenMPSchedType Schedule = getRuntimeSchedule(
+ ScheduleKind.Schedule, DispatchValues.Chunk != nullptr, Ordered);
assert(Ordered ||
(Schedule != OMP_sch_static && Schedule != OMP_sch_static_chunked &&
Schedule != OMP_ord_static && Schedule != OMP_ord_static_chunked &&
@@ -2470,14 +2938,14 @@ void CGOpenMPRuntime::emitForDispatchInit(CodeGenFunction &CGF,
// kmp_int[32|64] stride, kmp_int[32|64] chunk);
// If the Chunk was not specified in the clause - use default value 1.
- if (Chunk == nullptr)
- Chunk = CGF.Builder.getIntN(IVSize, 1);
+ llvm::Value *Chunk = DispatchValues.Chunk ? DispatchValues.Chunk
+ : CGF.Builder.getIntN(IVSize, 1);
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
CGF.Builder.getInt32(addMonoNonMonoModifier(
Schedule, ScheduleKind.M1, ScheduleKind.M2)), // Schedule type
- CGF.Builder.getIntN(IVSize, 0), // Lower
- UB, // Upper
+ DispatchValues.LB, // Lower
+ DispatchValues.UB, // Upper
CGF.Builder.getIntN(IVSize, 1), // Stride
Chunk // Chunk
};
@@ -2686,6 +3154,8 @@ enum KmpTaskTFields {
KmpTaskTStride,
/// (Taskloops only) Is last iteration flag.
KmpTaskTLastIter,
+ /// (Taskloops only) Reduction data.
+ KmpTaskTReductions,
};
} // anonymous namespace
@@ -2770,8 +3240,7 @@ createOffloadingBinaryDescriptorFunction(CodeGenModule &CGM, StringRef Name,
const RegionCodeGenTy &Codegen) {
auto &C = CGM.getContext();
FunctionArgList Args;
- ImplicitParamDecl DummyPtr(C, /*DC=*/nullptr, SourceLocation(),
- /*Id=*/nullptr, C.VoidPtrTy);
+ ImplicitParamDecl DummyPtr(C, C.VoidPtrTy, ImplicitParamDecl::Other);
Args.push_back(&DummyPtr);
CodeGenFunction CGF(CGM);
@@ -2874,7 +3343,7 @@ CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() {
// descriptor, so we can reuse the logic that emits Ctors and Dtors.
auto *IdentInfo = &C.Idents.get(".omp_offloading.reg_unreg_var");
ImplicitParamDecl RegUnregVar(C, C.getTranslationUnitDecl(), SourceLocation(),
- IdentInfo, C.CharTy);
+ IdentInfo, C.CharTy, ImplicitParamDecl::Other);
auto *UnRegFn = createOffloadingBinaryDescriptorFunction(
CGM, ".omp_offloading.descriptor_unreg",
@@ -2889,6 +3358,19 @@ CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() {
Desc);
CGM.getCXXABI().registerGlobalDtor(CGF, RegUnregVar, UnRegFn, Desc);
});
+ if (CGM.supportsCOMDAT()) {
+ // It is sufficient to call registration function only once, so create a
+ // COMDAT group for registration/unregistration functions and associated
+ // data. That would reduce startup time and code size. Registration
+ // function serves as a COMDAT group key.
+ auto ComdatKey = M.getOrInsertComdat(RegFn->getName());
+ RegFn->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
+ RegFn->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ RegFn->setComdat(ComdatKey);
+ UnRegFn->setComdat(ComdatKey);
+ DeviceImages->setComdat(ComdatKey);
+ Desc->setComdat(ComdatKey);
+ }
return RegFn;
}
@@ -2958,7 +3440,7 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
// Create the offloading info metadata node.
llvm::NamedMDNode *MD = M.getOrInsertNamedMetadata("omp_offload.info");
- // Auxiliar methods to create metadata values and strings.
+ // Auxiliary methods to create metadata values and strings.
auto getMDInt = [&](unsigned v) {
return llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(llvm::Type::getInt32Ty(C), v));
@@ -3225,6 +3707,7 @@ createKmpTaskTRecordDecl(CodeGenModule &CGM, OpenMPDirectiveKind Kind,
// kmp_uint64 ub;
// kmp_int64 st;
// kmp_int32 liter;
+ // void * reductions;
// };
auto *UD = C.buildImplicitRecord("kmp_cmplrdata_t", TTK_Union);
UD->startDefinition();
@@ -3248,6 +3731,7 @@ createKmpTaskTRecordDecl(CodeGenModule &CGM, OpenMPDirectiveKind Kind,
addFieldToRecordDecl(C, RD, KmpUInt64Ty);
addFieldToRecordDecl(C, RD, KmpInt64Ty);
addFieldToRecordDecl(C, RD, KmpInt32Ty);
+ addFieldToRecordDecl(C, RD, C.VoidPtrTy);
}
RD->completeDefinition();
return RD;
@@ -3278,7 +3762,7 @@ createKmpTaskTWithPrivatesRecordDecl(CodeGenModule &CGM, QualType KmpTaskTQTy,
/// TaskFunction(gtid, tt->part_id, &tt->privates, task_privates_map, tt,
/// For taskloops:
/// tt->task_data.lb, tt->task_data.ub, tt->task_data.st, tt->task_data.liter,
-/// tt->shareds);
+/// tt->reductions, tt->shareds);
/// return 0;
/// }
/// \endcode
@@ -3291,10 +3775,11 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
llvm::Value *TaskPrivatesMap) {
auto &C = CGM.getContext();
FunctionArgList Args;
- ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty);
- ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr,
- KmpTaskTWithPrivatesPtrQTy.withRestrict());
+ ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ KmpTaskTWithPrivatesPtrQTy.withRestrict(),
+ ImplicitParamDecl::Other);
Args.push_back(&GtidArg);
Args.push_back(&TaskTypeArg);
auto &TaskEntryFnInfo =
@@ -3363,10 +3848,14 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc,
auto LIFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTLastIter);
auto LILVal = CGF.EmitLValueForField(Base, *LIFI);
auto *LIParam = CGF.EmitLoadOfLValue(LILVal, Loc).getScalarVal();
+ auto RFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTReductions);
+ auto RLVal = CGF.EmitLValueForField(Base, *RFI);
+ auto *RParam = CGF.EmitLoadOfLValue(RLVal, Loc).getScalarVal();
CallArgs.push_back(LBParam);
CallArgs.push_back(UBParam);
CallArgs.push_back(StParam);
CallArgs.push_back(LIParam);
+ CallArgs.push_back(RParam);
}
CallArgs.push_back(SharedsParam);
@@ -3385,10 +3874,11 @@ static llvm::Value *emitDestructorsFunction(CodeGenModule &CGM,
QualType KmpTaskTWithPrivatesQTy) {
auto &C = CGM.getContext();
FunctionArgList Args;
- ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty);
- ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr,
- KmpTaskTWithPrivatesPtrQTy.withRestrict());
+ ImplicitParamDecl GtidArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, KmpInt32Ty,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl TaskTypeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ KmpTaskTWithPrivatesPtrQTy.withRestrict(),
+ ImplicitParamDecl::Other);
Args.push_back(&GtidArg);
Args.push_back(&TaskTypeArg);
FunctionType::ExtInfo Info;
@@ -3444,36 +3934,40 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc,
FunctionArgList Args;
ImplicitParamDecl TaskPrivatesArg(
C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
- C.getPointerType(PrivatesQTy).withConst().withRestrict());
+ C.getPointerType(PrivatesQTy).withConst().withRestrict(),
+ ImplicitParamDecl::Other);
Args.push_back(&TaskPrivatesArg);
llvm::DenseMap<const VarDecl *, unsigned> PrivateVarsPos;
unsigned Counter = 1;
for (auto *E: PrivateVars) {
Args.push_back(ImplicitParamDecl::Create(
- C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, C.getPointerType(C.getPointerType(E->getType()))
- .withConst()
- .withRestrict()));
+ C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ C.getPointerType(C.getPointerType(E->getType()))
+ .withConst()
+ .withRestrict(),
+ ImplicitParamDecl::Other));
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
PrivateVarsPos[VD] = Counter;
++Counter;
}
for (auto *E : FirstprivateVars) {
Args.push_back(ImplicitParamDecl::Create(
- C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, C.getPointerType(C.getPointerType(E->getType()))
- .withConst()
- .withRestrict()));
+ C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ C.getPointerType(C.getPointerType(E->getType()))
+ .withConst()
+ .withRestrict(),
+ ImplicitParamDecl::Other));
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
PrivateVarsPos[VD] = Counter;
++Counter;
}
for (auto *E: LastprivateVars) {
Args.push_back(ImplicitParamDecl::Create(
- C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, C.getPointerType(C.getPointerType(E->getType()))
- .withConst()
- .withRestrict()));
+ C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ C.getPointerType(C.getPointerType(E->getType()))
+ .withConst()
+ .withRestrict(),
+ ImplicitParamDecl::Other));
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
PrivateVarsPos[VD] = Counter;
++Counter;
@@ -3488,6 +3982,7 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc,
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, TaskPrivatesMap,
TaskPrivatesMapFnInfo);
TaskPrivatesMap->removeFnAttr(llvm::Attribute::NoInline);
+ TaskPrivatesMap->removeFnAttr(llvm::Attribute::OptimizeNone);
TaskPrivatesMap->addFnAttr(llvm::Attribute::AlwaysInline);
CodeGenFunction CGF(CGM);
CGF.disableDebugInfo();
@@ -3551,7 +4046,9 @@ static void emitPrivatesInit(CodeGenFunction &CGF,
auto SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField);
SharedRefLValue = CGF.MakeAddrLValue(
Address(SharedRefLValue.getPointer(), C.getDeclAlign(OriginalVD)),
- SharedRefLValue.getType(), AlignmentSource::Decl);
+ SharedRefLValue.getType(),
+ LValueBaseInfo(AlignmentSource::Decl,
+ SharedRefLValue.getBaseInfo().getMayAlias()));
QualType Type = OriginalVD->getType();
if (Type->isArrayType()) {
// Initialize firstprivate array.
@@ -3561,7 +4058,7 @@ static void emitPrivatesInit(CodeGenFunction &CGF,
SharedRefLValue.getAddress(), Type);
} else {
// Initialize firstprivate array using element-by-element
- // intialization.
+ // initialization.
CGF.EmitOMPAggregateAssign(
PrivateLValue.getAddress(), SharedRefLValue.getAddress(), Type,
[&CGF, Elem, Init, &CapturesInfo](Address DestElement,
@@ -3630,12 +4127,14 @@ emitTaskDupFunction(CodeGenModule &CGM, SourceLocation Loc,
ArrayRef<PrivateDataTy> Privates, bool WithLastIter) {
auto &C = CGM.getContext();
FunctionArgList Args;
- ImplicitParamDecl DstArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy);
- ImplicitParamDecl SrcArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, KmpTaskTWithPrivatesPtrQTy);
- ImplicitParamDecl LastprivArg(C, /*DC=*/nullptr, Loc,
- /*Id=*/nullptr, C.IntTy);
+ ImplicitParamDecl DstArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ KmpTaskTWithPrivatesPtrQTy,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl SrcArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ KmpTaskTWithPrivatesPtrQTy,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl LastprivArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy,
+ ImplicitParamDecl::Other);
Args.push_back(&DstArg);
Args.push_back(&SrcArg);
Args.push_back(&LastprivArg);
@@ -3764,9 +4263,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc,
// Emit initial values for private copies (if any).
llvm::Value *TaskPrivatesMap = nullptr;
auto *TaskPrivatesMapTy =
- std::next(cast<llvm::Function>(TaskFunction)->getArgumentList().begin(),
- 3)
- ->getType();
+ std::next(cast<llvm::Function>(TaskFunction)->arg_begin(), 3)->getType();
if (!Privates.empty()) {
auto FI = std::next(KmpTaskTWithPrivatesQTyRD->field_begin());
TaskPrivatesMap = emitTaskPrivateMappingFunction(
@@ -4006,8 +4503,8 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
DepTaskArgs[5] = CGF.Builder.getInt32(0);
DepTaskArgs[6] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
}
- auto &&ThenCodeGen = [this, Loc, &Data, TDBase, KmpTaskTQTyRD,
- NumDependencies, &TaskArgs,
+ auto &&ThenCodeGen = [this, &Data, TDBase, KmpTaskTQTyRD, NumDependencies,
+ &TaskArgs,
&DepTaskArgs](CodeGenFunction &CGF, PrePostActionTy &) {
if (!Data.Tied) {
auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId);
@@ -4121,11 +4618,27 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
cast<VarDecl>(cast<DeclRefExpr>(D.getStrideVariable())->getDecl());
CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(), StLVal.getQuals(),
/*IsInitializer=*/true);
+ // Store reductions address.
+ LValue RedLVal = CGF.EmitLValueForField(
+ Result.TDBase,
+ *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTReductions));
+ if (Data.Reductions)
+ CGF.EmitStoreOfScalar(Data.Reductions, RedLVal);
+ else {
+ CGF.EmitNullInitialization(RedLVal.getAddress(),
+ CGF.getContext().VoidPtrTy);
+ }
enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 };
llvm::Value *TaskArgs[] = {
- UpLoc, ThreadID, Result.NewTask, IfVal, LBLVal.getPointer(),
- UBLVal.getPointer(), CGF.EmitLoadOfScalar(StLVal, SourceLocation()),
- llvm::ConstantInt::getSigned(CGF.IntTy, Data.Nogroup ? 1 : 0),
+ UpLoc,
+ ThreadID,
+ Result.NewTask,
+ IfVal,
+ LBLVal.getPointer(),
+ UBLVal.getPointer(),
+ CGF.EmitLoadOfScalar(StLVal, SourceLocation()),
+ llvm::ConstantInt::getNullValue(
+ CGF.IntTy), // Always 0 because taskgroup emitted by the compiler
llvm::ConstantInt::getSigned(
CGF.IntTy, Data.Schedule.getPointer()
? Data.Schedule.getInt() ? NumTasks : Grainsize
@@ -4134,10 +4647,9 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty,
/*isSigned=*/false)
: llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0),
- Result.TaskDupFn
- ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Result.TaskDupFn,
- CGF.VoidPtrTy)
- : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)};
+ Result.TaskDupFn ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ Result.TaskDupFn, CGF.VoidPtrTy)
+ : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)};
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_taskloop), TaskArgs);
}
@@ -4241,20 +4753,16 @@ static void emitReductionCombiner(CodeGenFunction &CGF,
CGF.EmitIgnoredExpr(ReductionOp);
}
-static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
- llvm::Type *ArgsType,
- ArrayRef<const Expr *> Privates,
- ArrayRef<const Expr *> LHSExprs,
- ArrayRef<const Expr *> RHSExprs,
- ArrayRef<const Expr *> ReductionOps) {
+llvm::Value *CGOpenMPRuntime::emitReductionFunction(
+ CodeGenModule &CGM, llvm::Type *ArgsType, ArrayRef<const Expr *> Privates,
+ ArrayRef<const Expr *> LHSExprs, ArrayRef<const Expr *> RHSExprs,
+ ArrayRef<const Expr *> ReductionOps) {
auto &C = CGM.getContext();
// void reduction_func(void *LHSArg, void *RHSArg);
FunctionArgList Args;
- ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
- C.VoidPtrTy);
- ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
- C.VoidPtrTy);
+ ImplicitParamDecl LHSArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl RHSArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
Args.push_back(&LHSArg);
Args.push_back(&RHSArg);
auto &CGFI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
@@ -4329,11 +4837,11 @@ static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
return Fn;
}
-static void emitSingleReductionCombiner(CodeGenFunction &CGF,
- const Expr *ReductionOp,
- const Expr *PrivateRef,
- const DeclRefExpr *LHS,
- const DeclRefExpr *RHS) {
+void CGOpenMPRuntime::emitSingleReductionCombiner(CodeGenFunction &CGF,
+ const Expr *ReductionOp,
+ const Expr *PrivateRef,
+ const DeclRefExpr *LHS,
+ const DeclRefExpr *RHS) {
if (PrivateRef->getType()->isArrayType()) {
// Emit reduction for array section.
auto *LHSVar = cast<VarDecl>(LHS->getDecl());
@@ -4353,9 +4861,13 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
ArrayRef<const Expr *> LHSExprs,
ArrayRef<const Expr *> RHSExprs,
ArrayRef<const Expr *> ReductionOps,
- bool WithNowait, bool SimpleReduction) {
+ ReductionOptionsTy Options) {
if (!CGF.HaveInsertPoint())
return;
+
+ bool WithNowait = Options.WithNowait;
+ bool SimpleReduction = Options.SimpleReduction;
+
// Next code should be emitted for reduction:
//
// static kmp_critical_name lock = { 0 };
@@ -4497,12 +5009,13 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
};
auto &&CodeGen = [&Privates, &LHSExprs, &RHSExprs, &ReductionOps](
CodeGenFunction &CGF, PrePostActionTy &Action) {
+ auto &RT = CGF.CGM.getOpenMPRuntime();
auto IPriv = Privates.begin();
auto ILHS = LHSExprs.begin();
auto IRHS = RHSExprs.begin();
for (auto *E : ReductionOps) {
- emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
- cast<DeclRefExpr>(*IRHS));
+ RT.emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
+ cast<DeclRefExpr>(*IRHS));
++IPriv;
++ILHS;
++IRHS;
@@ -4562,7 +5075,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
}
if (XExpr) {
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
- auto &&AtomicRedGen = [BO, VD, IPriv,
+ auto &&AtomicRedGen = [BO, VD,
Loc](CodeGenFunction &CGF, const Expr *XExpr,
const Expr *EExpr, const Expr *UpExpr) {
LValue X = CGF.EmitLValue(XExpr);
@@ -4572,7 +5085,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
CGF.EmitOMPAtomicSimpleUpdateExpr(
X, E, BO, /*IsXLHSInRHSPart=*/true,
llvm::AtomicOrdering::Monotonic, Loc,
- [&CGF, UpExpr, VD, IPriv, Loc](RValue XRValue) {
+ [&CGF, UpExpr, VD, Loc](RValue XRValue) {
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
PrivateScope.addPrivate(
VD, [&CGF, VD, XRValue, Loc]() -> Address {
@@ -4640,6 +5153,353 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
}
+/// Generates unique name for artificial threadprivate variables.
+/// Format is: <Prefix> "." <Loc_raw_encoding> "_" <N>
+static std::string generateUniqueName(StringRef Prefix, SourceLocation Loc,
+ unsigned N) {
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ Out << Prefix << "." << Loc.getRawEncoding() << "_" << N;
+ return Out.str();
+}
+
+/// Emits reduction initializer function:
+/// \code
+/// void @.red_init(void* %arg) {
+/// %0 = bitcast void* %arg to <type>*
+/// store <type> <init>, <type>* %0
+/// ret void
+/// }
+/// \endcode
+static llvm::Value *emitReduceInitFunction(CodeGenModule &CGM,
+ SourceLocation Loc,
+ ReductionCodeGen &RCG, unsigned N) {
+ auto &C = CGM.getContext();
+ FunctionArgList Args;
+ ImplicitParamDecl Param(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ Args.emplace_back(&Param);
+ auto &FnInfo =
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
+ ".red_init.", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
+ CodeGenFunction CGF(CGM);
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args);
+ Address PrivateAddr = CGF.EmitLoadOfPointer(
+ CGF.GetAddrOfLocalVar(&Param),
+ C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
+ llvm::Value *Size = nullptr;
+ // If the size of the reduction item is non-constant, load it from global
+ // threadprivate variable.
+ if (RCG.getSizes(N).second) {
+ Address SizeAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().getSizeType(),
+ generateUniqueName("reduction_size", Loc, N));
+ Size =
+ CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
+ CGM.getContext().getSizeType(), SourceLocation());
+ }
+ RCG.emitAggregateType(CGF, N, Size);
+ LValue SharedLVal;
+ // If initializer uses initializer from declare reduction construct, emit a
+ // pointer to the address of the original reduction item (reuired by reduction
+ // initializer)
+ if (RCG.usesReductionInitializer(N)) {
+ Address SharedAddr =
+ CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().VoidPtrTy,
+ generateUniqueName("reduction", Loc, N));
+ SharedLVal = CGF.MakeAddrLValue(SharedAddr, CGM.getContext().VoidPtrTy);
+ } else {
+ SharedLVal = CGF.MakeNaturalAlignAddrLValue(
+ llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
+ CGM.getContext().VoidPtrTy);
+ }
+ // Emit the initializer:
+ // %0 = bitcast void* %arg to <type>*
+ // store <type> <init>, <type>* %0
+ RCG.emitInitialization(CGF, N, PrivateAddr, SharedLVal,
+ [](CodeGenFunction &) { return false; });
+ CGF.FinishFunction();
+ return Fn;
+}
+
+/// Emits reduction combiner function:
+/// \code
+/// void @.red_comb(void* %arg0, void* %arg1) {
+/// %lhs = bitcast void* %arg0 to <type>*
+/// %rhs = bitcast void* %arg1 to <type>*
+/// %2 = <ReductionOp>(<type>* %lhs, <type>* %rhs)
+/// store <type> %2, <type>* %lhs
+/// ret void
+/// }
+/// \endcode
+static llvm::Value *emitReduceCombFunction(CodeGenModule &CGM,
+ SourceLocation Loc,
+ ReductionCodeGen &RCG, unsigned N,
+ const Expr *ReductionOp,
+ const Expr *LHS, const Expr *RHS,
+ const Expr *PrivateRef) {
+ auto &C = CGM.getContext();
+ auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(LHS)->getDecl());
+ auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(RHS)->getDecl());
+ FunctionArgList Args;
+ ImplicitParamDecl ParamInOut(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl ParamIn(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ Args.emplace_back(&ParamInOut);
+ Args.emplace_back(&ParamIn);
+ auto &FnInfo =
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
+ ".red_comb.", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
+ CodeGenFunction CGF(CGM);
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args);
+ llvm::Value *Size = nullptr;
+ // If the size of the reduction item is non-constant, load it from global
+ // threadprivate variable.
+ if (RCG.getSizes(N).second) {
+ Address SizeAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().getSizeType(),
+ generateUniqueName("reduction_size", Loc, N));
+ Size =
+ CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
+ CGM.getContext().getSizeType(), SourceLocation());
+ }
+ RCG.emitAggregateType(CGF, N, Size);
+ // Remap lhs and rhs variables to the addresses of the function arguments.
+ // %lhs = bitcast void* %arg0 to <type>*
+ // %rhs = bitcast void* %arg1 to <type>*
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ PrivateScope.addPrivate(LHSVD, [&C, &CGF, &ParamInOut, LHSVD]() -> Address {
+ // Pull out the pointer to the variable.
+ Address PtrAddr = CGF.EmitLoadOfPointer(
+ CGF.GetAddrOfLocalVar(&ParamInOut),
+ C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
+ return CGF.Builder.CreateElementBitCast(
+ PtrAddr, CGF.ConvertTypeForMem(LHSVD->getType()));
+ });
+ PrivateScope.addPrivate(RHSVD, [&C, &CGF, &ParamIn, RHSVD]() -> Address {
+ // Pull out the pointer to the variable.
+ Address PtrAddr = CGF.EmitLoadOfPointer(
+ CGF.GetAddrOfLocalVar(&ParamIn),
+ C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
+ return CGF.Builder.CreateElementBitCast(
+ PtrAddr, CGF.ConvertTypeForMem(RHSVD->getType()));
+ });
+ PrivateScope.Privatize();
+ // Emit the combiner body:
+ // %2 = <ReductionOp>(<type> *%lhs, <type> *%rhs)
+ // store <type> %2, <type>* %lhs
+ CGM.getOpenMPRuntime().emitSingleReductionCombiner(
+ CGF, ReductionOp, PrivateRef, cast<DeclRefExpr>(LHS),
+ cast<DeclRefExpr>(RHS));
+ CGF.FinishFunction();
+ return Fn;
+}
+
+/// Emits reduction finalizer function:
+/// \code
+/// void @.red_fini(void* %arg) {
+/// %0 = bitcast void* %arg to <type>*
+/// <destroy>(<type>* %0)
+/// ret void
+/// }
+/// \endcode
+static llvm::Value *emitReduceFiniFunction(CodeGenModule &CGM,
+ SourceLocation Loc,
+ ReductionCodeGen &RCG, unsigned N) {
+ if (!RCG.needCleanups(N))
+ return nullptr;
+ auto &C = CGM.getContext();
+ FunctionArgList Args;
+ ImplicitParamDecl Param(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ Args.emplace_back(&Param);
+ auto &FnInfo =
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
+ ".red_fini.", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
+ CodeGenFunction CGF(CGM);
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args);
+ Address PrivateAddr = CGF.EmitLoadOfPointer(
+ CGF.GetAddrOfLocalVar(&Param),
+ C.getPointerType(C.VoidPtrTy).castAs<PointerType>());
+ llvm::Value *Size = nullptr;
+ // If the size of the reduction item is non-constant, load it from global
+ // threadprivate variable.
+ if (RCG.getSizes(N).second) {
+ Address SizeAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().getSizeType(),
+ generateUniqueName("reduction_size", Loc, N));
+ Size =
+ CGF.EmitLoadOfScalar(SizeAddr, /*Volatile=*/false,
+ CGM.getContext().getSizeType(), SourceLocation());
+ }
+ RCG.emitAggregateType(CGF, N, Size);
+ // Emit the finalizer body:
+ // <destroy>(<type>* %0)
+ RCG.emitCleanups(CGF, N, PrivateAddr);
+ CGF.FinishFunction();
+ return Fn;
+}
+
+llvm::Value *CGOpenMPRuntime::emitTaskReductionInit(
+ CodeGenFunction &CGF, SourceLocation Loc, ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs, const OMPTaskDataTy &Data) {
+ if (!CGF.HaveInsertPoint() || Data.ReductionVars.empty())
+ return nullptr;
+
+ // Build typedef struct:
+ // kmp_task_red_input {
+ // void *reduce_shar; // shared reduction item
+ // size_t reduce_size; // size of data item
+ // void *reduce_init; // data initialization routine
+ // void *reduce_fini; // data finalization routine
+ // void *reduce_comb; // data combiner routine
+ // kmp_task_red_flags_t flags; // flags for additional info from compiler
+ // } kmp_task_red_input_t;
+ ASTContext &C = CGM.getContext();
+ auto *RD = C.buildImplicitRecord("kmp_task_red_input_t");
+ RD->startDefinition();
+ const FieldDecl *SharedFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ const FieldDecl *SizeFD = addFieldToRecordDecl(C, RD, C.getSizeType());
+ const FieldDecl *InitFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ const FieldDecl *FiniFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ const FieldDecl *CombFD = addFieldToRecordDecl(C, RD, C.VoidPtrTy);
+ const FieldDecl *FlagsFD = addFieldToRecordDecl(
+ C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/false));
+ RD->completeDefinition();
+ QualType RDType = C.getRecordType(RD);
+ unsigned Size = Data.ReductionVars.size();
+ llvm::APInt ArraySize(/*numBits=*/64, Size);
+ QualType ArrayRDType = C.getConstantArrayType(
+ RDType, ArraySize, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ // kmp_task_red_input_t .rd_input.[Size];
+ Address TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input.");
+ ReductionCodeGen RCG(Data.ReductionVars, Data.ReductionCopies,
+ Data.ReductionOps);
+ for (unsigned Cnt = 0; Cnt < Size; ++Cnt) {
+ // kmp_task_red_input_t &ElemLVal = .rd_input.[Cnt];
+ llvm::Value *Idxs[] = {llvm::ConstantInt::get(CGM.SizeTy, /*V=*/0),
+ llvm::ConstantInt::get(CGM.SizeTy, Cnt)};
+ llvm::Value *GEP = CGF.EmitCheckedInBoundsGEP(
+ TaskRedInput.getPointer(), Idxs,
+ /*SignedIndices=*/false, /*IsSubtraction=*/false, Loc,
+ ".rd_input.gep.");
+ LValue ElemLVal = CGF.MakeNaturalAlignAddrLValue(GEP, RDType);
+ // ElemLVal.reduce_shar = &Shareds[Cnt];
+ LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD);
+ RCG.emitSharedLValue(CGF, Cnt);
+ llvm::Value *CastedShared =
+ CGF.EmitCastToVoidPtr(RCG.getSharedLValue(Cnt).getPointer());
+ CGF.EmitStoreOfScalar(CastedShared, SharedLVal);
+ RCG.emitAggregateType(CGF, Cnt);
+ llvm::Value *SizeValInChars;
+ llvm::Value *SizeVal;
+ std::tie(SizeValInChars, SizeVal) = RCG.getSizes(Cnt);
+ // We use delayed creation/initialization for VLAs, array sections and
+ // custom reduction initializations. It is required because runtime does not
+ // provide the way to pass the sizes of VLAs/array sections to
+ // initializer/combiner/finalizer functions and does not pass the pointer to
+ // original reduction item to the initializer. Instead threadprivate global
+ // variables are used to store these values and use them in the functions.
+ bool DelayedCreation = !!SizeVal;
+ SizeValInChars = CGF.Builder.CreateIntCast(SizeValInChars, CGM.SizeTy,
+ /*isSigned=*/false);
+ LValue SizeLVal = CGF.EmitLValueForField(ElemLVal, SizeFD);
+ CGF.EmitStoreOfScalar(SizeValInChars, SizeLVal);
+ // ElemLVal.reduce_init = init;
+ LValue InitLVal = CGF.EmitLValueForField(ElemLVal, InitFD);
+ llvm::Value *InitAddr =
+ CGF.EmitCastToVoidPtr(emitReduceInitFunction(CGM, Loc, RCG, Cnt));
+ CGF.EmitStoreOfScalar(InitAddr, InitLVal);
+ DelayedCreation = DelayedCreation || RCG.usesReductionInitializer(Cnt);
+ // ElemLVal.reduce_fini = fini;
+ LValue FiniLVal = CGF.EmitLValueForField(ElemLVal, FiniFD);
+ llvm::Value *Fini = emitReduceFiniFunction(CGM, Loc, RCG, Cnt);
+ llvm::Value *FiniAddr = Fini
+ ? CGF.EmitCastToVoidPtr(Fini)
+ : llvm::ConstantPointerNull::get(CGM.VoidPtrTy);
+ CGF.EmitStoreOfScalar(FiniAddr, FiniLVal);
+ // ElemLVal.reduce_comb = comb;
+ LValue CombLVal = CGF.EmitLValueForField(ElemLVal, CombFD);
+ llvm::Value *CombAddr = CGF.EmitCastToVoidPtr(emitReduceCombFunction(
+ CGM, Loc, RCG, Cnt, Data.ReductionOps[Cnt], LHSExprs[Cnt],
+ RHSExprs[Cnt], Data.ReductionCopies[Cnt]));
+ CGF.EmitStoreOfScalar(CombAddr, CombLVal);
+ // ElemLVal.flags = 0;
+ LValue FlagsLVal = CGF.EmitLValueForField(ElemLVal, FlagsFD);
+ if (DelayedCreation) {
+ CGF.EmitStoreOfScalar(
+ llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1, /*IsSigned=*/true),
+ FlagsLVal);
+ } else
+ CGF.EmitNullInitialization(FlagsLVal.getAddress(), FlagsLVal.getType());
+ }
+ // Build call void *__kmpc_task_reduction_init(int gtid, int num_data, void
+ // *data);
+ llvm::Value *Args[] = {
+ CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
+ /*isSigned=*/true),
+ llvm::ConstantInt::get(CGM.IntTy, Size, /*isSigned=*/true),
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(TaskRedInput.getPointer(),
+ CGM.VoidPtrTy)};
+ return CGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__kmpc_task_reduction_init), Args);
+}
+
+void CGOpenMPRuntime::emitTaskReductionFixups(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ ReductionCodeGen &RCG,
+ unsigned N) {
+ auto Sizes = RCG.getSizes(N);
+ // Emit threadprivate global variable if the type is non-constant
+ // (Sizes.second = nullptr).
+ if (Sizes.second) {
+ llvm::Value *SizeVal = CGF.Builder.CreateIntCast(Sizes.second, CGM.SizeTy,
+ /*isSigned=*/false);
+ Address SizeAddr = getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().getSizeType(),
+ generateUniqueName("reduction_size", Loc, N));
+ CGF.Builder.CreateStore(SizeVal, SizeAddr, /*IsVolatile=*/false);
+ }
+ // Store address of the original reduction item if custom initializer is used.
+ if (RCG.usesReductionInitializer(N)) {
+ Address SharedAddr = getAddrOfArtificialThreadPrivate(
+ CGF, CGM.getContext().VoidPtrTy,
+ generateUniqueName("reduction", Loc, N));
+ CGF.Builder.CreateStore(
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ RCG.getSharedLValue(N).getPointer(), CGM.VoidPtrTy),
+ SharedAddr, /*IsVolatile=*/false);
+ }
+}
+
+Address CGOpenMPRuntime::getTaskReductionItem(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ llvm::Value *ReductionsPtr,
+ LValue SharedLVal) {
+ // Build call void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void
+ // *d);
+ llvm::Value *Args[] = {
+ CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy,
+ /*isSigned=*/true),
+ ReductionsPtr,
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(SharedLVal.getPointer(),
+ CGM.VoidPtrTy)};
+ return Address(
+ CGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__kmpc_task_reduction_get_th_data), Args),
+ SharedLVal.getAlignment());
+}
+
void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF,
SourceLocation Loc) {
if (!CGF.HaveInsertPoint())
@@ -4874,25 +5734,45 @@ static const Stmt *ignoreCompoundStmts(const Stmt *Body) {
return Body;
}
-/// \brief Emit the num_teams clause of an enclosed teams directive at the
-/// target region scope. If there is no teams directive associated with the
-/// target directive, or if there is no num_teams clause associated with the
-/// enclosed teams directive, return nullptr.
+/// Emit the number of teams for a target directive. Inspect the num_teams
+/// clause associated with a teams construct combined or closely nested
+/// with the target directive.
+///
+/// Emit a team of size one for directives such as 'target parallel' that
+/// have no associated teams construct.
+///
+/// Otherwise, return nullptr.
static llvm::Value *
-emitNumTeamsClauseForTargetDirective(CGOpenMPRuntime &OMPRuntime,
- CodeGenFunction &CGF,
- const OMPExecutableDirective &D) {
+emitNumTeamsForTargetDirective(CGOpenMPRuntime &OMPRuntime,
+ CodeGenFunction &CGF,
+ const OMPExecutableDirective &D) {
assert(!CGF.getLangOpts().OpenMPIsDevice && "Clauses associated with the "
"teams directive expected to be "
"emitted only for the host!");
- // FIXME: For the moment we do not support combined directives with target and
- // teams, so we do not expect to get any num_teams clause in the provided
- // directive. Once we support that, this assertion can be replaced by the
- // actual emission of the clause expression.
- assert(D.getSingleClause<OMPNumTeamsClause>() == nullptr &&
- "Not expecting clause in directive.");
+ auto &Bld = CGF.Builder;
+
+ // If the target directive is combined with a teams directive:
+ // Return the value in the num_teams clause, if any.
+ // Otherwise, return 0 to denote the runtime default.
+ if (isOpenMPTeamsDirective(D.getDirectiveKind())) {
+ if (const auto *NumTeamsClause = D.getSingleClause<OMPNumTeamsClause>()) {
+ CodeGenFunction::RunCleanupsScope NumTeamsScope(CGF);
+ auto NumTeams = CGF.EmitScalarExpr(NumTeamsClause->getNumTeams(),
+ /*IgnoreResultAssign*/ true);
+ return Bld.CreateIntCast(NumTeams, CGF.Int32Ty,
+ /*IsSigned=*/true);
+ }
+
+ // The default value is 0.
+ return Bld.getInt32(0);
+ }
+
+ // If the target directive is combined with a parallel directive but not a
+ // teams directive, start one team.
+ if (isOpenMPParallelDirective(D.getDirectiveKind()))
+ return Bld.getInt32(1);
// If the current target region has a teams region enclosed, we need to get
// the number of teams to pass to the runtime function call. This is done
@@ -4910,38 +5790,92 @@ emitNumTeamsClauseForTargetDirective(CGOpenMPRuntime &OMPRuntime,
CGOpenMPInnerExprInfo CGInfo(CGF, CS);
CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
llvm::Value *NumTeams = CGF.EmitScalarExpr(NTE->getNumTeams());
- return CGF.Builder.CreateIntCast(NumTeams, CGF.Int32Ty,
- /*IsSigned=*/true);
+ return Bld.CreateIntCast(NumTeams, CGF.Int32Ty,
+ /*IsSigned=*/true);
}
// If we have an enclosed teams directive but no num_teams clause we use
// the default value 0.
- return CGF.Builder.getInt32(0);
+ return Bld.getInt32(0);
}
// No teams associated with the directive.
return nullptr;
}
-/// \brief Emit the thread_limit clause of an enclosed teams directive at the
-/// target region scope. If there is no teams directive associated with the
-/// target directive, or if there is no thread_limit clause associated with the
-/// enclosed teams directive, return nullptr.
+/// Emit the number of threads for a target directive. Inspect the
+/// thread_limit clause associated with a teams construct combined or closely
+/// nested with the target directive.
+///
+/// Emit the num_threads clause for directives such as 'target parallel' that
+/// have no associated teams construct.
+///
+/// Otherwise, return nullptr.
static llvm::Value *
-emitThreadLimitClauseForTargetDirective(CGOpenMPRuntime &OMPRuntime,
- CodeGenFunction &CGF,
- const OMPExecutableDirective &D) {
+emitNumThreadsForTargetDirective(CGOpenMPRuntime &OMPRuntime,
+ CodeGenFunction &CGF,
+ const OMPExecutableDirective &D) {
assert(!CGF.getLangOpts().OpenMPIsDevice && "Clauses associated with the "
"teams directive expected to be "
"emitted only for the host!");
- // FIXME: For the moment we do not support combined directives with target and
- // teams, so we do not expect to get any thread_limit clause in the provided
- // directive. Once we support that, this assertion can be replaced by the
- // actual emission of the clause expression.
- assert(D.getSingleClause<OMPThreadLimitClause>() == nullptr &&
- "Not expecting clause in directive.");
+ auto &Bld = CGF.Builder;
+
+ //
+ // If the target directive is combined with a teams directive:
+ // Return the value in the thread_limit clause, if any.
+ //
+ // If the target directive is combined with a parallel directive:
+ // Return the value in the num_threads clause, if any.
+ //
+ // If both clauses are set, select the minimum of the two.
+ //
+ // If neither teams or parallel combined directives set the number of threads
+ // in a team, return 0 to denote the runtime default.
+ //
+ // If this is not a teams directive return nullptr.
+
+ if (isOpenMPTeamsDirective(D.getDirectiveKind()) ||
+ isOpenMPParallelDirective(D.getDirectiveKind())) {
+ llvm::Value *DefaultThreadLimitVal = Bld.getInt32(0);
+ llvm::Value *NumThreadsVal = nullptr;
+ llvm::Value *ThreadLimitVal = nullptr;
+
+ if (const auto *ThreadLimitClause =
+ D.getSingleClause<OMPThreadLimitClause>()) {
+ CodeGenFunction::RunCleanupsScope ThreadLimitScope(CGF);
+ auto ThreadLimit = CGF.EmitScalarExpr(ThreadLimitClause->getThreadLimit(),
+ /*IgnoreResultAssign*/ true);
+ ThreadLimitVal = Bld.CreateIntCast(ThreadLimit, CGF.Int32Ty,
+ /*IsSigned=*/true);
+ }
+
+ if (const auto *NumThreadsClause =
+ D.getSingleClause<OMPNumThreadsClause>()) {
+ CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
+ llvm::Value *NumThreads =
+ CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
+ /*IgnoreResultAssign*/ true);
+ NumThreadsVal =
+ Bld.CreateIntCast(NumThreads, CGF.Int32Ty, /*IsSigned=*/true);
+ }
+
+ // Select the lesser of thread_limit and num_threads.
+ if (NumThreadsVal)
+ ThreadLimitVal = ThreadLimitVal
+ ? Bld.CreateSelect(Bld.CreateICmpSLT(NumThreadsVal,
+ ThreadLimitVal),
+ NumThreadsVal, ThreadLimitVal)
+ : NumThreadsVal;
+
+ // Set default value passed to the runtime if either teams or a target
+ // parallel type directive is found but no clause is specified.
+ if (!ThreadLimitVal)
+ ThreadLimitVal = DefaultThreadLimitVal;
+
+ return ThreadLimitVal;
+ }
// If the current target region has a teams region enclosed, we need to get
// the thread limit to pass to the runtime function call. This is done
@@ -5494,7 +6428,7 @@ public:
// We have to process the component lists that relate with the same
// declaration in a single chunk so that we can generate the map flags
// correctly. Therefore, we organize all lists in a map.
- llvm::DenseMap<const ValueDecl *, SmallVector<MapInfo, 8>> Info;
+ llvm::MapVector<const ValueDecl *, SmallVector<MapInfo, 8>> Info;
// Helper function to fill the information map for the different supported
// clauses.
@@ -5818,16 +6752,11 @@ emitOffloadingArrays(CodeGenFunction &CGF,
for (unsigned i = 0; i < Info.NumberOfPtrs; ++i) {
llvm::Value *BPVal = *BasePointers[i];
- if (BPVal->getType()->isPointerTy())
- BPVal = CGF.Builder.CreateBitCast(BPVal, CGM.VoidPtrTy);
- else {
- assert(BPVal->getType()->isIntegerTy() &&
- "If not a pointer, the value type must be an integer.");
- BPVal = CGF.Builder.CreateIntToPtr(BPVal, CGM.VoidPtrTy);
- }
llvm::Value *BP = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
Info.BasePointersArray, 0, i);
+ BP = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ BP, BPVal->getType()->getPointerTo(/*AddrSpace=*/0));
Address BPAddr(BP, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy));
CGF.Builder.CreateStore(BPVal, BPAddr);
@@ -5836,16 +6765,11 @@ emitOffloadingArrays(CodeGenFunction &CGF,
Info.CaptureDeviceAddrMap.insert(std::make_pair(DevVD, BPAddr));
llvm::Value *PVal = Pointers[i];
- if (PVal->getType()->isPointerTy())
- PVal = CGF.Builder.CreateBitCast(PVal, CGM.VoidPtrTy);
- else {
- assert(PVal->getType()->isIntegerTy() &&
- "If not a pointer, the value type must be an integer.");
- PVal = CGF.Builder.CreateIntToPtr(PVal, CGM.VoidPtrTy);
- }
llvm::Value *P = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
Info.PointersArray, 0, i);
+ P = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ P, PVal->getType()->getPointerTo(/*AddrSpace=*/0));
Address PAddr(P, Ctx.getTypeAlignInChars(Ctx.VoidPtrTy));
CGF.Builder.CreateStore(PVal, PAddr);
@@ -5984,8 +6908,8 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
OffloadError);
// Fill up the pointer arrays and transfer execution to the device.
- auto &&ThenGen = [&Ctx, &BasePointers, &Pointers, &Sizes, &MapTypes, Device,
- OutlinedFnID, OffloadError, OffloadErrorQType,
+ auto &&ThenGen = [&BasePointers, &Pointers, &Sizes, &MapTypes, Device,
+ OutlinedFnID, OffloadError,
&D](CodeGenFunction &CGF, PrePostActionTy &) {
auto &RT = CGF.CGM.getOpenMPRuntime();
// Emit the offloading arrays.
@@ -6021,24 +6945,50 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
// Return value of the runtime offloading call.
llvm::Value *Return;
- auto *NumTeams = emitNumTeamsClauseForTargetDirective(RT, CGF, D);
- auto *ThreadLimit = emitThreadLimitClauseForTargetDirective(RT, CGF, D);
+ auto *NumTeams = emitNumTeamsForTargetDirective(RT, CGF, D);
+ auto *NumThreads = emitNumThreadsForTargetDirective(RT, CGF, D);
- // If we have NumTeams defined this means that we have an enclosed teams
- // region. Therefore we also expect to have ThreadLimit defined. These two
- // values should be defined in the presence of a teams directive, regardless
- // of having any clauses associated. If the user is using teams but no
- // clauses, these two values will be the default that should be passed to
- // the runtime library - a 32-bit integer with the value zero.
+ // The target region is an outlined function launched by the runtime
+ // via calls __tgt_target() or __tgt_target_teams().
+ //
+ // __tgt_target() launches a target region with one team and one thread,
+ // executing a serial region. This master thread may in turn launch
+ // more threads within its team upon encountering a parallel region,
+ // however, no additional teams can be launched on the device.
+ //
+ // __tgt_target_teams() launches a target region with one or more teams,
+ // each with one or more threads. This call is required for target
+ // constructs such as:
+ // 'target teams'
+ // 'target' / 'teams'
+ // 'target teams distribute parallel for'
+ // 'target parallel'
+ // and so on.
+ //
+ // Note that on the host and CPU targets, the runtime implementation of
+ // these calls simply call the outlined function without forking threads.
+ // The outlined functions themselves have runtime calls to
+ // __kmpc_fork_teams() and __kmpc_fork() for this purpose, codegen'd by
+ // the compiler in emitTeamsCall() and emitParallelCall().
+ //
+ // In contrast, on the NVPTX target, the implementation of
+ // __tgt_target_teams() launches a GPU kernel with the requested number
+ // of teams and threads so no additional calls to the runtime are required.
if (NumTeams) {
- assert(ThreadLimit && "Thread limit expression should be available along "
- "with number of teams.");
+ // If we have NumTeams defined this means that we have an enclosed teams
+ // region. Therefore we also expect to have NumThreads defined. These two
+ // values should be defined in the presence of a teams directive,
+ // regardless of having any clauses associated. If the user is using teams
+ // but no clauses, these two values will be the default that should be
+ // passed to the runtime library - a 32-bit integer with the value zero.
+ assert(NumThreads && "Thread limit expression should be available along "
+ "with number of teams.");
llvm::Value *OffloadingArgs[] = {
DeviceID, OutlinedFnID,
PointerNum, Info.BasePointersArray,
Info.PointersArray, Info.SizesArray,
Info.MapTypesArray, NumTeams,
- ThreadLimit};
+ NumThreads};
Return = CGF.EmitRuntimeCall(
RT.createRuntimeFunction(OMPRTL__tgt_target_teams), OffloadingArgs);
} else {
@@ -6095,17 +7045,18 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
if (!S)
return;
- // If we find a OMP target directive, codegen the outline function and
- // register the result.
- // FIXME: Add other directives with target when they become supported.
- bool isTargetDirective = isa<OMPTargetDirective>(S);
+ // Codegen OMP target directives that offload compute to the device.
+ bool requiresDeviceCodegen =
+ isa<OMPExecutableDirective>(S) &&
+ isOpenMPTargetExecutionDirective(
+ cast<OMPExecutableDirective>(S)->getDirectiveKind());
- if (isTargetDirective) {
- auto *E = cast<OMPExecutableDirective>(S);
+ if (requiresDeviceCodegen) {
+ auto &E = *cast<OMPExecutableDirective>(S);
unsigned DeviceID;
unsigned FileID;
unsigned Line;
- getTargetEntryUniqueInfo(CGM.getContext(), E->getLocStart(), DeviceID,
+ getTargetEntryUniqueInfo(CGM.getContext(), E.getLocStart(), DeviceID,
FileID, Line);
// Is this a target region that should not be emitted as an entry point? If
@@ -6114,13 +7065,22 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
ParentName, Line))
return;
- llvm::Function *Fn;
- llvm::Constant *Addr;
- std::tie(Fn, Addr) =
- CodeGenFunction::EmitOMPTargetDirectiveOutlinedFunction(
- CGM, cast<OMPTargetDirective>(*E), ParentName,
- /*isOffloadEntry=*/true);
- assert(Fn && Addr && "Target region emission failed.");
+ switch (S->getStmtClass()) {
+ case Stmt::OMPTargetDirectiveClass:
+ CodeGenFunction::EmitOMPTargetDeviceFunction(
+ CGM, ParentName, cast<OMPTargetDirective>(*S));
+ break;
+ case Stmt::OMPTargetParallelDirectiveClass:
+ CodeGenFunction::EmitOMPTargetParallelDeviceFunction(
+ CGM, ParentName, cast<OMPTargetParallelDirective>(*S));
+ break;
+ case Stmt::OMPTargetTeamsDirectiveClass:
+ CodeGenFunction::EmitOMPTargetTeamsDeviceFunction(
+ CGM, ParentName, cast<OMPTargetTeamsDirective>(*S));
+ break;
+ default:
+ llvm_unreachable("Unknown target directive for OpenMP device codegen.");
+ }
return;
}
@@ -6182,7 +7142,7 @@ bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
}
}
- // If we are in target mode we do not emit any global (declare target is not
+ // If we are in target mode, we do not emit any global (declare target is not
// implemented yet). Therefore we signal that GD was processed in this case.
return true;
}
@@ -6271,8 +7231,8 @@ void CGOpenMPRuntime::emitTargetDataCalls(
// Generate the code for the opening of the data environment. Capture all the
// arguments of the runtime call by reference because they are used in the
// closing of the region.
- auto &&BeginThenGen = [&D, &CGF, Device, &Info, &CodeGen, &NoPrivAction](
- CodeGenFunction &CGF, PrePostActionTy &) {
+ auto &&BeginThenGen = [&D, Device, &Info, &CodeGen](CodeGenFunction &CGF,
+ PrePostActionTy &) {
// Fill up the arrays with all the mapped variables.
MappableExprsHandler::MapBaseValuesArrayTy BasePointers;
MappableExprsHandler::MapValuesArrayTy Pointers;
@@ -6318,8 +7278,7 @@ void CGOpenMPRuntime::emitTargetDataCalls(
};
// Generate code for the closing of the data region.
- auto &&EndThenGen = [&CGF, Device, &Info](CodeGenFunction &CGF,
- PrePostActionTy &) {
+ auto &&EndThenGen = [Device, &Info](CodeGenFunction &CGF, PrePostActionTy &) {
assert(Info.isValid() && "Invalid data environment closing arguments.");
llvm::Value *BasePointersArrayArg = nullptr;
@@ -6397,7 +7356,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
"Expecting either target enter, exit data, or update directives.");
// Generate the code for the opening of the data environment.
- auto &&ThenGen = [&D, &CGF, Device](CodeGenFunction &CGF, PrePostActionTy &) {
+ auto &&ThenGen = [&D, Device](CodeGenFunction &CGF, PrePostActionTy &) {
// Fill up the arrays with all the mapped variables.
MappableExprsHandler::MapBaseValuesArrayTy BasePointers;
MappableExprsHandler::MapValuesArrayTy Pointers;
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h
index 61ddc70..5dcf999 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntime.h
@@ -96,15 +96,106 @@ struct OMPTaskDataTy final {
SmallVector<const Expr *, 4> FirstprivateInits;
SmallVector<const Expr *, 4> LastprivateVars;
SmallVector<const Expr *, 4> LastprivateCopies;
+ SmallVector<const Expr *, 4> ReductionVars;
+ SmallVector<const Expr *, 4> ReductionCopies;
+ SmallVector<const Expr *, 4> ReductionOps;
SmallVector<std::pair<OpenMPDependClauseKind, const Expr *>, 4> Dependences;
llvm::PointerIntPair<llvm::Value *, 1, bool> Final;
llvm::PointerIntPair<llvm::Value *, 1, bool> Schedule;
llvm::PointerIntPair<llvm::Value *, 1, bool> Priority;
+ llvm::Value *Reductions = nullptr;
unsigned NumberOfParts = 0;
bool Tied = true;
bool Nogroup = false;
};
+/// Class intended to support codegen of all kind of the reduction clauses.
+class ReductionCodeGen {
+private:
+ /// Data required for codegen of reduction clauses.
+ struct ReductionData {
+ /// Reference to the original shared item.
+ const Expr *Ref = nullptr;
+ /// Helper expression for generation of private copy.
+ const Expr *Private = nullptr;
+ /// Helper expression for generation reduction operation.
+ const Expr *ReductionOp = nullptr;
+ ReductionData(const Expr *Ref, const Expr *Private, const Expr *ReductionOp)
+ : Ref(Ref), Private(Private), ReductionOp(ReductionOp) {}
+ };
+ /// List of reduction-based clauses.
+ SmallVector<ReductionData, 4> ClausesData;
+
+ /// List of addresses of original shared variables/expressions.
+ SmallVector<std::pair<LValue, LValue>, 4> SharedAddresses;
+ /// Sizes of the reduction items in chars.
+ SmallVector<std::pair<llvm::Value *, llvm::Value *>, 4> Sizes;
+ /// Base declarations for the reduction items.
+ SmallVector<const VarDecl *, 4> BaseDecls;
+
+ /// Emits lvalue for shared expresion.
+ LValue emitSharedLValue(CodeGenFunction &CGF, const Expr *E);
+ /// Emits upper bound for shared expression (if array section).
+ LValue emitSharedLValueUB(CodeGenFunction &CGF, const Expr *E);
+ /// Performs aggregate initialization.
+ /// \param N Number of reduction item in the common list.
+ /// \param PrivateAddr Address of the corresponding private item.
+ /// \param SharedLVal Address of the original shared variable.
+ /// \param DRD Declare reduction construct used for reduction item.
+ void emitAggregateInitialization(CodeGenFunction &CGF, unsigned N,
+ Address PrivateAddr, LValue SharedLVal,
+ const OMPDeclareReductionDecl *DRD);
+
+public:
+ ReductionCodeGen(ArrayRef<const Expr *> Shareds,
+ ArrayRef<const Expr *> Privates,
+ ArrayRef<const Expr *> ReductionOps);
+ /// Emits lvalue for a reduction item.
+ /// \param N Number of the reduction item.
+ void emitSharedLValue(CodeGenFunction &CGF, unsigned N);
+ /// Emits the code for the variable-modified type, if required.
+ /// \param N Number of the reduction item.
+ void emitAggregateType(CodeGenFunction &CGF, unsigned N);
+ /// Emits the code for the variable-modified type, if required.
+ /// \param N Number of the reduction item.
+ /// \param Size Size of the type in chars.
+ void emitAggregateType(CodeGenFunction &CGF, unsigned N, llvm::Value *Size);
+ /// Performs initialization of the private copy for the reduction item.
+ /// \param N Number of the reduction item.
+ /// \param PrivateAddr Address of the corresponding private item.
+ /// \param DefaultInit Default initialization sequence that should be
+ /// performed if no reduction specific initialization is found.
+ /// \param SharedLVal Address of the original shared variable.
+ void
+ emitInitialization(CodeGenFunction &CGF, unsigned N, Address PrivateAddr,
+ LValue SharedLVal,
+ llvm::function_ref<bool(CodeGenFunction &)> DefaultInit);
+ /// Returns true if the private copy requires cleanups.
+ bool needCleanups(unsigned N);
+ /// Emits cleanup code for the reduction item.
+ /// \param N Number of the reduction item.
+ /// \param PrivateAddr Address of the corresponding private item.
+ void emitCleanups(CodeGenFunction &CGF, unsigned N, Address PrivateAddr);
+ /// Adjusts \p PrivatedAddr for using instead of the original variable
+ /// address in normal operations.
+ /// \param N Number of the reduction item.
+ /// \param PrivateAddr Address of the corresponding private item.
+ Address adjustPrivateAddress(CodeGenFunction &CGF, unsigned N,
+ Address PrivateAddr);
+ /// Returns LValue for the reduction item.
+ LValue getSharedLValue(unsigned N) const { return SharedAddresses[N].first; }
+ /// Returns the size of the reduction item (in chars and total number of
+ /// elements in the item), or nullptr, if the size is a constant.
+ std::pair<llvm::Value *, llvm::Value *> getSizes(unsigned N) const {
+ return Sizes[N];
+ }
+ /// Returns the base declaration of the reduction item.
+ const VarDecl *getBaseDecl(unsigned N) const { return BaseDecls[N]; }
+ /// Returns true if the initialization of the reduction item uses initializer
+ /// from declare reduction construct.
+ bool usesReductionInitializer(unsigned N) const;
+};
+
class CGOpenMPRuntime {
protected:
CodeGenModule &CGM;
@@ -121,7 +212,7 @@ protected:
/// \param OutlinedFnID Outlined function ID value to be defined by this call.
/// \param IsOffloadEntry True if the outlined function is an offload entry.
/// \param CodeGen Lambda codegen specific to an accelerator device.
- /// An oulined function may not be an entry if, e.g. the if clause always
+ /// An outlined function may not be an entry if, e.g. the if clause always
/// evaluates to false.
virtual void emitTargetOutlinedFunctionHelper(const OMPExecutableDirective &D,
StringRef ParentName,
@@ -527,6 +618,7 @@ public:
/// Get combiner/initializer for the specified user-defined reduction, if any.
virtual std::pair<llvm::Function *, llvm::Function *>
getUserDefinedReduction(const OMPDeclareReductionDecl *D);
+
/// \brief Emits outlined function for the specified OpenMP parallel directive
/// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
/// kmp_int32 BoundID, struct context_vars*).
@@ -535,7 +627,19 @@ public:
/// \param InnermostKind Kind of innermost directive (for simple directives it
/// is a directive itself, for combined - its innermost directive).
/// \param CodeGen Code generation sequence for the \a D directive.
- virtual llvm::Value *emitParallelOrTeamsOutlinedFunction(
+ virtual llvm::Value *emitParallelOutlinedFunction(
+ const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
+ OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen);
+
+ /// \brief Emits outlined function for the specified OpenMP teams directive
+ /// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
+ /// kmp_int32 BoundID, struct context_vars*).
+ /// \param D OpenMP directive.
+ /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
+ /// \param InnermostKind Kind of innermost directive (for simple directives it
+ /// is a directive itself, for combined - its innermost directive).
+ /// \param CodeGen Code generation sequence for the \a D directive.
+ virtual llvm::Value *emitTeamsOutlinedFunction(
const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen);
@@ -659,16 +763,50 @@ public:
///
virtual bool isDynamic(OpenMPScheduleClauseKind ScheduleKind) const;
+ /// struct with the values to be passed to the dispatch runtime function
+ struct DispatchRTInput {
+ /// Loop lower bound
+ llvm::Value *LB = nullptr;
+ /// Loop upper bound
+ llvm::Value *UB = nullptr;
+ /// Chunk size specified using 'schedule' clause (nullptr if chunk
+ /// was not specified)
+ llvm::Value *Chunk = nullptr;
+ DispatchRTInput() = default;
+ DispatchRTInput(llvm::Value *LB, llvm::Value *UB, llvm::Value *Chunk)
+ : LB(LB), UB(UB), Chunk(Chunk) {}
+ };
+
+ /// Call the appropriate runtime routine to initialize it before start
+ /// of loop.
+
+ /// This is used for non static scheduled types and when the ordered
+ /// clause is present on the loop construct.
+ /// Depending on the loop schedule, it is necessary to call some runtime
+ /// routine before start of the OpenMP loop to get the loop upper / lower
+ /// bounds \a LB and \a UB and stride \a ST.
+ ///
+ /// \param CGF Reference to current CodeGenFunction.
+ /// \param Loc Clang source location.
+ /// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
+ /// \param IVSize Size of the iteration variable in bits.
+ /// \param IVSigned Sign of the iteration variable.
+ /// \param Ordered true if loop is ordered, false otherwise.
+ /// \param DispatchValues struct containing llvm values for lower bound, upper
+ /// bound, and chunk expression.
+ /// For the default (nullptr) value, the chunk 1 will be used.
+ ///
virtual void emitForDispatchInit(CodeGenFunction &CGF, SourceLocation Loc,
const OpenMPScheduleTy &ScheduleKind,
unsigned IVSize, bool IVSigned, bool Ordered,
- llvm::Value *UB,
- llvm::Value *Chunk = nullptr);
+ const DispatchRTInput &DispatchValues);
/// \brief Call the appropriate runtime routine to initialize it before start
/// of loop.
///
- /// Depending on the loop schedule, it is nesessary to call some runtime
+ /// This is used only in case of static schedule, when the user did not
+ /// specify a ordered clause on the loop construct.
+ /// Depending on the loop schedule, it is necessary to call some runtime
/// routine before start of the OpenMP loop to get the loop upper / lower
/// bounds \a LB and \a UB and stride \a ST.
///
@@ -676,7 +814,7 @@ public:
/// \param Loc Clang source location.
/// \param ScheduleKind Schedule kind, specified by the 'schedule' clause.
/// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the interation variable.
+ /// \param IVSigned Sign of the iteration variable.
/// \param Ordered true if loop is ordered, false otherwise.
/// \param IL Address of the output variable in which the flag of the
/// last iteration is returned.
@@ -685,7 +823,7 @@ public:
/// \param UB Address of the output variable in which the upper iteration
/// number is returned.
/// \param ST Address of the output variable in which the stride value is
- /// returned nesessary to generated the static_chunked scheduled loop.
+ /// returned necessary to generated the static_chunked scheduled loop.
/// \param Chunk Value of the chunk for the static_chunked scheduled loop.
/// For the default (nullptr) value, the chunk 1 will be used.
///
@@ -700,7 +838,7 @@ public:
/// \param Loc Clang source location.
/// \param SchedKind Schedule kind, specified by the 'dist_schedule' clause.
/// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the interation variable.
+ /// \param IVSigned Sign of the iteration variable.
/// \param Ordered true if loop is ordered, false otherwise.
/// \param IL Address of the output variable in which the flag of the
/// last iteration is returned.
@@ -709,7 +847,7 @@ public:
/// \param UB Address of the output variable in which the upper iteration
/// number is returned.
/// \param ST Address of the output variable in which the stride value is
- /// returned nesessary to generated the static_chunked scheduled loop.
+ /// returned necessary to generated the static_chunked scheduled loop.
/// \param Chunk Value of the chunk for the static_chunked scheduled loop.
/// For the default (nullptr) value, the chunk 1 will be used.
///
@@ -726,7 +864,7 @@ public:
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
/// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the interation variable.
+ /// \param IVSigned Sign of the iteration variable.
///
virtual void emitForOrderedIterationEnd(CodeGenFunction &CGF,
SourceLocation Loc, unsigned IVSize,
@@ -745,7 +883,7 @@ public:
/// kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper,
/// kmp_int[32|64] *p_stride);
/// \param IVSize Size of the iteration variable in bits.
- /// \param IVSigned Sign of the interation variable.
+ /// \param IVSigned Sign of the iteration variable.
/// \param IL Address of the output variable in which the flag of the
/// last iteration is returned.
/// \param LB Address of the output variable in which the lower iteration
@@ -797,6 +935,14 @@ public:
SourceLocation Loc, bool PerformInit,
CodeGenFunction *CGF = nullptr);
+ /// Creates artificial threadprivate variable with name \p Name and type \p
+ /// VarType.
+ /// \param VarType Type of the artificial threadprivate variable.
+ /// \param Name Name of the artificial threadprivate variable.
+ virtual Address getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
+ QualType VarType,
+ StringRef Name);
+
/// \brief Emit flush of the variables specified in 'omp flush' directive.
/// \param Vars List of variables to flush.
virtual void emitFlush(CodeGenFunction &CGF, ArrayRef<const Expr *> Vars,
@@ -880,6 +1026,32 @@ public:
OpenMPDirectiveKind InnermostKind,
const RegionCodeGenTy &CodeGen,
bool HasCancel = false);
+
+ /// Emits reduction function.
+ /// \param ArgsType Array type containing pointers to reduction variables.
+ /// \param Privates List of private copies for original reduction arguments.
+ /// \param LHSExprs List of LHS in \a ReductionOps reduction operations.
+ /// \param RHSExprs List of RHS in \a ReductionOps reduction operations.
+ /// \param ReductionOps List of reduction operations in form 'LHS binop RHS'
+ /// or 'operator binop(LHS, RHS)'.
+ llvm::Value *emitReductionFunction(CodeGenModule &CGM, llvm::Type *ArgsType,
+ ArrayRef<const Expr *> Privates,
+ ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs,
+ ArrayRef<const Expr *> ReductionOps);
+
+ /// Emits single reduction combiner
+ void emitSingleReductionCombiner(CodeGenFunction &CGF,
+ const Expr *ReductionOp,
+ const Expr *PrivateRef,
+ const DeclRefExpr *LHS,
+ const DeclRefExpr *RHS);
+
+ struct ReductionOptionsTy {
+ bool WithNowait;
+ bool SimpleReduction;
+ OpenMPDirectiveKind ReductionKind;
+ };
/// \brief Emit a code for reduction clause. Next code should be emitted for
/// reduction:
/// \code
@@ -916,14 +1088,63 @@ public:
/// \param RHSExprs List of RHS in \a ReductionOps reduction operations.
/// \param ReductionOps List of reduction operations in form 'LHS binop RHS'
/// or 'operator binop(LHS, RHS)'.
- /// \param WithNowait true if parent directive has also nowait clause, false
- /// otherwise.
+ /// \param Options List of options for reduction codegen:
+ /// WithNowait true if parent directive has also nowait clause, false
+ /// otherwise.
+ /// SimpleReduction Emit reduction operation only. Used for omp simd
+ /// directive on the host.
+ /// ReductionKind The kind of reduction to perform.
virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
ArrayRef<const Expr *> Privates,
ArrayRef<const Expr *> LHSExprs,
ArrayRef<const Expr *> RHSExprs,
ArrayRef<const Expr *> ReductionOps,
- bool WithNowait, bool SimpleReduction);
+ ReductionOptionsTy Options);
+
+ /// Emit a code for initialization of task reduction clause. Next code
+ /// should be emitted for reduction:
+ /// \code
+ ///
+ /// _task_red_item_t red_data[n];
+ /// ...
+ /// red_data[i].shar = &origs[i];
+ /// red_data[i].size = sizeof(origs[i]);
+ /// red_data[i].f_init = (void*)RedInit<i>;
+ /// red_data[i].f_fini = (void*)RedDest<i>;
+ /// red_data[i].f_comb = (void*)RedOp<i>;
+ /// red_data[i].flags = <Flag_i>;
+ /// ...
+ /// void* tg1 = __kmpc_task_reduction_init(gtid, n, red_data);
+ /// \endcode
+ ///
+ /// \param LHSExprs List of LHS in \a Data.ReductionOps reduction operations.
+ /// \param RHSExprs List of RHS in \a Data.ReductionOps reduction operations.
+ /// \param Data Additional data for task generation like tiedness, final
+ /// state, list of privates, reductions etc.
+ virtual llvm::Value *emitTaskReductionInit(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs,
+ const OMPTaskDataTy &Data);
+
+ /// Required to resolve existing problems in the runtime. Emits threadprivate
+ /// variables to store the size of the VLAs/array sections for
+ /// initializer/combiner/finalizer functions + emits threadprivate variable to
+ /// store the pointer to the original reduction item for the custom
+ /// initializer defined by declare reduction construct.
+ /// \param RCG Allows to reuse an existing data for the reductions.
+ /// \param N Reduction item for which fixups must be emitted.
+ virtual void emitTaskReductionFixups(CodeGenFunction &CGF, SourceLocation Loc,
+ ReductionCodeGen &RCG, unsigned N);
+
+ /// Get the address of `void *` type of the privatue copy of the reduction
+ /// item specified by the \p SharedLVal.
+ /// \param ReductionsPtr Pointer to the reduction data returned by the
+ /// emitTaskReductionInit function.
+ /// \param SharedLVal Address of the original reduction item.
+ virtual Address getTaskReductionItem(CodeGenFunction &CGF, SourceLocation Loc,
+ llvm::Value *ReductionsPtr,
+ LValue SharedLVal);
/// \brief Emit code for 'taskwait' directive.
virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc);
@@ -952,7 +1173,7 @@ public:
/// \param OutlinedFnID Outlined function ID value to be defined by this call.
/// \param IsOffloadEntry True if the outlined function is an offload entry.
/// \param CodeGen Code generation sequence for the \a D directive.
- /// An oulined function may not be an entry if, e.g. the if clause always
+ /// An outlined function may not be an entry if, e.g. the if clause always
/// evaluates to false.
virtual void emitTargetOutlinedFunction(const OMPExecutableDirective &D,
StringRef ParentName,
@@ -991,7 +1212,7 @@ public:
virtual bool emitTargetGlobalVariable(GlobalDecl GD);
/// \brief Emit the global \a GD if it is meaningful for the target. Returns
- /// if it was emitted succesfully.
+ /// if it was emitted successfully.
/// \param GD Global to scan.
virtual bool emitTargetGlobal(GlobalDecl GD);
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
index 6a6d832..3ced05d 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
@@ -26,6 +26,11 @@ enum OpenMPRTLFunctionNVPTX {
OMPRTL_NVPTX__kmpc_kernel_init,
/// \brief Call to void __kmpc_kernel_deinit();
OMPRTL_NVPTX__kmpc_kernel_deinit,
+ /// \brief Call to void __kmpc_spmd_kernel_init(kmp_int32 thread_limit,
+ /// short RequiresOMPRuntime, short RequiresDataSharing);
+ OMPRTL_NVPTX__kmpc_spmd_kernel_init,
+ /// \brief Call to void __kmpc_spmd_kernel_deinit();
+ OMPRTL_NVPTX__kmpc_spmd_kernel_deinit,
/// \brief Call to void __kmpc_kernel_prepare_parallel(void
/// *outlined_function);
OMPRTL_NVPTX__kmpc_kernel_prepare_parallel,
@@ -39,6 +44,30 @@ enum OpenMPRTLFunctionNVPTX {
/// Call to void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32
/// global_tid);
OMPRTL_NVPTX__kmpc_end_serialized_parallel,
+ /// \brief Call to int32_t __kmpc_shuffle_int32(int32_t element,
+ /// int16_t lane_offset, int16_t warp_size);
+ OMPRTL_NVPTX__kmpc_shuffle_int32,
+ /// \brief Call to int64_t __kmpc_shuffle_int64(int64_t element,
+ /// int16_t lane_offset, int16_t warp_size);
+ OMPRTL_NVPTX__kmpc_shuffle_int64,
+ /// \brief Call to __kmpc_nvptx_parallel_reduce_nowait(kmp_int32
+ /// global_tid, kmp_int32 num_vars, size_t reduce_size, void* reduce_data,
+ /// void (*kmp_ShuffleReductFctPtr)(void *rhsData, int16_t lane_id, int16_t
+ /// lane_offset, int16_t shortCircuit),
+ /// void (*kmp_InterWarpCopyFctPtr)(void* src, int32_t warp_num));
+ OMPRTL_NVPTX__kmpc_parallel_reduce_nowait,
+ /// \brief Call to __kmpc_nvptx_teams_reduce_nowait(int32_t global_tid,
+ /// int32_t num_vars, size_t reduce_size, void *reduce_data,
+ /// void (*kmp_ShuffleReductFctPtr)(void *rhs, int16_t lane_id, int16_t
+ /// lane_offset, int16_t shortCircuit),
+ /// void (*kmp_InterWarpCopyFctPtr)(void* src, int32_t warp_num),
+ /// void (*kmp_CopyToScratchpadFctPtr)(void *reduce_data, void * scratchpad,
+ /// int32_t index, int32_t width),
+ /// void (*kmp_LoadReduceFctPtr)(void *reduce_data, void * scratchpad, int32_t
+ /// index, int32_t width, int32_t reduce))
+ OMPRTL_NVPTX__kmpc_teams_reduce_nowait,
+ /// \brief Call to __kmpc_nvptx_end_reduce_nowait(int32_t global_tid);
+ OMPRTL_NVPTX__kmpc_end_reduce_nowait
};
/// Pre(post)-action for different OpenMP constructs specialized for NVPTX.
@@ -76,6 +105,47 @@ public:
CGF.EmitRuntimeCall(ExitCallee, ExitArgs);
}
};
+
+// A class to track the execution mode when codegening directives within
+// a target region. The appropriate mode (generic/spmd) is set on entry
+// to the target region and used by containing directives such as 'parallel'
+// to emit optimized code.
+class ExecutionModeRAII {
+private:
+ CGOpenMPRuntimeNVPTX::ExecutionMode SavedMode;
+ CGOpenMPRuntimeNVPTX::ExecutionMode &Mode;
+
+public:
+ ExecutionModeRAII(CGOpenMPRuntimeNVPTX::ExecutionMode &Mode,
+ CGOpenMPRuntimeNVPTX::ExecutionMode NewMode)
+ : Mode(Mode) {
+ SavedMode = Mode;
+ Mode = NewMode;
+ }
+ ~ExecutionModeRAII() { Mode = SavedMode; }
+};
+
+/// GPU Configuration: This information can be derived from cuda registers,
+/// however, providing compile time constants helps generate more efficient
+/// code. For all practical purposes this is fine because the configuration
+/// is the same for all known NVPTX architectures.
+enum MachineConfiguration : unsigned {
+ WarpSize = 32,
+ /// Number of bits required to represent a lane identifier, which is
+ /// computed as log_2(WarpSize).
+ LaneIDBits = 5,
+ LaneIDMask = WarpSize - 1,
+
+ /// Global memory alignment for performance.
+ GlobalMemoryAlignment = 256,
+};
+
+enum NamedBarrier : unsigned {
+ /// Synchronize on this barrier #ID using a named barrier primitive.
+ /// Only the subset of active threads in a parallel region arrive at the
+ /// barrier.
+ NB_Parallel = 1,
+};
} // anonymous namespace
/// Get the GPU warp size.
@@ -96,6 +166,23 @@ static llvm::Value *getNVPTXThreadID(CodeGenFunction &CGF) {
llvm::None, "nvptx_tid");
}
+/// Get the id of the warp in the block.
+/// We assume that the warp size is 32, which is always the case
+/// on the NVPTX device, to generate more efficient code.
+static llvm::Value *getNVPTXWarpID(CodeGenFunction &CGF) {
+ CGBuilderTy &Bld = CGF.Builder;
+ return Bld.CreateAShr(getNVPTXThreadID(CGF), LaneIDBits, "nvptx_warp_id");
+}
+
+/// Get the id of the current lane in the Warp.
+/// We assume that the warp size is 32, which is always the case
+/// on the NVPTX device, to generate more efficient code.
+static llvm::Value *getNVPTXLaneID(CodeGenFunction &CGF) {
+ CGBuilderTy &Bld = CGF.Builder;
+ return Bld.CreateAnd(getNVPTXThreadID(CGF), Bld.getInt32(LaneIDMask),
+ "nvptx_lane_id");
+}
+
/// Get the maximum number of threads in a block of the GPU.
static llvm::Value *getNVPTXNumThreads(CodeGenFunction &CGF) {
CGBuilderTy &Bld = CGF.Builder;
@@ -112,16 +199,37 @@ static void getNVPTXCTABarrier(CodeGenFunction &CGF) {
&CGF.CGM.getModule(), llvm::Intrinsic::nvvm_barrier0));
}
+/// Get barrier #ID to synchronize selected (multiple of warp size) threads in
+/// a CTA.
+static void getNVPTXBarrier(CodeGenFunction &CGF, int ID,
+ llvm::Value *NumThreads) {
+ CGBuilderTy &Bld = CGF.Builder;
+ llvm::Value *Args[] = {Bld.getInt32(ID), NumThreads};
+ Bld.CreateCall(llvm::Intrinsic::getDeclaration(&CGF.CGM.getModule(),
+ llvm::Intrinsic::nvvm_barrier),
+ Args);
+}
+
/// Synchronize all GPU threads in a block.
static void syncCTAThreads(CodeGenFunction &CGF) { getNVPTXCTABarrier(CGF); }
+/// Synchronize worker threads in a parallel region.
+static void syncParallelThreads(CodeGenFunction &CGF, llvm::Value *NumThreads) {
+ return getNVPTXBarrier(CGF, NB_Parallel, NumThreads);
+}
+
/// Get the value of the thread_limit clause in the teams directive.
-/// The runtime encodes thread_limit in the launch parameter, always starting
-/// thread_limit+warpSize threads per team.
-static llvm::Value *getThreadLimit(CodeGenFunction &CGF) {
+/// For the 'generic' execution mode, the runtime encodes thread_limit in
+/// the launch parameters, always starting thread_limit+warpSize threads per
+/// CTA. The threads in the last warp are reserved for master execution.
+/// For the 'spmd' execution mode, all threads in a CTA are part of the team.
+static llvm::Value *getThreadLimit(CodeGenFunction &CGF,
+ bool IsInSpmdExecutionMode = false) {
CGBuilderTy &Bld = CGF.Builder;
- return Bld.CreateSub(getNVPTXNumThreads(CGF), getNVPTXWarpSize(CGF),
- "thread_limit");
+ return IsInSpmdExecutionMode
+ ? getNVPTXNumThreads(CGF)
+ : Bld.CreateSub(getNVPTXNumThreads(CGF), getNVPTXWarpSize(CGF),
+ "thread_limit");
}
/// Get the thread id of the OMP master thread.
@@ -159,12 +267,34 @@ void CGOpenMPRuntimeNVPTX::WorkerFunctionState::createWorkerFunction(
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, WorkerFn, *CGFI);
}
+bool CGOpenMPRuntimeNVPTX::isInSpmdExecutionMode() const {
+ return CurrentExecutionMode == CGOpenMPRuntimeNVPTX::ExecutionMode::Spmd;
+}
+
+static CGOpenMPRuntimeNVPTX::ExecutionMode
+getExecutionModeForDirective(CodeGenModule &CGM,
+ const OMPExecutableDirective &D) {
+ OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
+ switch (DirectiveKind) {
+ case OMPD_target:
+ case OMPD_target_teams:
+ return CGOpenMPRuntimeNVPTX::ExecutionMode::Generic;
+ case OMPD_target_parallel:
+ return CGOpenMPRuntimeNVPTX::ExecutionMode::Spmd;
+ default:
+ llvm_unreachable("Unsupported directive on NVPTX device.");
+ }
+ llvm_unreachable("Unsupported directive on NVPTX device.");
+}
+
void CGOpenMPRuntimeNVPTX::emitGenericKernel(const OMPExecutableDirective &D,
StringRef ParentName,
llvm::Function *&OutlinedFn,
llvm::Constant *&OutlinedFnID,
bool IsOffloadEntry,
const RegionCodeGenTy &CodeGen) {
+ ExecutionModeRAII ModeRAII(CurrentExecutionMode,
+ CGOpenMPRuntimeNVPTX::ExecutionMode::Generic);
EntryFunctionState EST;
WorkerFunctionState WST(CGM);
Work.clear();
@@ -252,6 +382,94 @@ void CGOpenMPRuntimeNVPTX::emitGenericEntryFooter(CodeGenFunction &CGF,
EST.ExitBB = nullptr;
}
+void CGOpenMPRuntimeNVPTX::emitSpmdKernel(const OMPExecutableDirective &D,
+ StringRef ParentName,
+ llvm::Function *&OutlinedFn,
+ llvm::Constant *&OutlinedFnID,
+ bool IsOffloadEntry,
+ const RegionCodeGenTy &CodeGen) {
+ ExecutionModeRAII ModeRAII(CurrentExecutionMode,
+ CGOpenMPRuntimeNVPTX::ExecutionMode::Spmd);
+ EntryFunctionState EST;
+
+ // Emit target region as a standalone region.
+ class NVPTXPrePostActionTy : public PrePostActionTy {
+ CGOpenMPRuntimeNVPTX &RT;
+ CGOpenMPRuntimeNVPTX::EntryFunctionState &EST;
+ const OMPExecutableDirective &D;
+
+ public:
+ NVPTXPrePostActionTy(CGOpenMPRuntimeNVPTX &RT,
+ CGOpenMPRuntimeNVPTX::EntryFunctionState &EST,
+ const OMPExecutableDirective &D)
+ : RT(RT), EST(EST), D(D) {}
+ void Enter(CodeGenFunction &CGF) override {
+ RT.emitSpmdEntryHeader(CGF, EST, D);
+ }
+ void Exit(CodeGenFunction &CGF) override {
+ RT.emitSpmdEntryFooter(CGF, EST);
+ }
+ } Action(*this, EST, D);
+ CodeGen.setAction(Action);
+ emitTargetOutlinedFunctionHelper(D, ParentName, OutlinedFn, OutlinedFnID,
+ IsOffloadEntry, CodeGen);
+ return;
+}
+
+void CGOpenMPRuntimeNVPTX::emitSpmdEntryHeader(
+ CodeGenFunction &CGF, EntryFunctionState &EST,
+ const OMPExecutableDirective &D) {
+ auto &Bld = CGF.Builder;
+
+ // Setup BBs in entry function.
+ llvm::BasicBlock *ExecuteBB = CGF.createBasicBlock(".execute");
+ EST.ExitBB = CGF.createBasicBlock(".exit");
+
+ // Initialize the OMP state in the runtime; called by all active threads.
+ // TODO: Set RequiresOMPRuntime and RequiresDataSharing parameters
+ // based on code analysis of the target region.
+ llvm::Value *Args[] = {getThreadLimit(CGF, /*IsInSpmdExecutionMode=*/true),
+ /*RequiresOMPRuntime=*/Bld.getInt16(1),
+ /*RequiresDataSharing=*/Bld.getInt16(1)};
+ CGF.EmitRuntimeCall(
+ createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_spmd_kernel_init), Args);
+ CGF.EmitBranch(ExecuteBB);
+
+ CGF.EmitBlock(ExecuteBB);
+}
+
+void CGOpenMPRuntimeNVPTX::emitSpmdEntryFooter(CodeGenFunction &CGF,
+ EntryFunctionState &EST) {
+ if (!EST.ExitBB)
+ EST.ExitBB = CGF.createBasicBlock(".exit");
+
+ llvm::BasicBlock *OMPDeInitBB = CGF.createBasicBlock(".omp.deinit");
+ CGF.EmitBranch(OMPDeInitBB);
+
+ CGF.EmitBlock(OMPDeInitBB);
+ // DeInitialize the OMP state in the runtime; called by all active threads.
+ CGF.EmitRuntimeCall(
+ createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_spmd_kernel_deinit), None);
+ CGF.EmitBranch(EST.ExitBB);
+
+ CGF.EmitBlock(EST.ExitBB);
+ EST.ExitBB = nullptr;
+}
+
+// Create a unique global variable to indicate the execution mode of this target
+// region. The execution mode is either 'generic', or 'spmd' depending on the
+// target directive. This variable is picked up by the offload library to setup
+// the device appropriately before kernel launch. If the execution mode is
+// 'generic', the runtime reserves one warp for the master, otherwise, all
+// warps participate in parallel work.
+static void setPropertyExecutionMode(CodeGenModule &CGM, StringRef Name,
+ CGOpenMPRuntimeNVPTX::ExecutionMode Mode) {
+ (void)new llvm::GlobalVariable(
+ CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true,
+ llvm::GlobalValue::WeakAnyLinkage,
+ llvm::ConstantInt::get(CGM.Int8Ty, Mode), Name + Twine("_exec_mode"));
+}
+
void CGOpenMPRuntimeNVPTX::emitWorkerFunction(WorkerFunctionState &WST) {
auto &Ctx = CGM.getContext();
@@ -385,6 +603,22 @@ CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) {
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_kernel_deinit");
break;
}
+ case OMPRTL_NVPTX__kmpc_spmd_kernel_init: {
+ // Build void __kmpc_spmd_kernel_init(kmp_int32 thread_limit,
+ // short RequiresOMPRuntime, short RequiresDataSharing);
+ llvm::Type *TypeParams[] = {CGM.Int32Ty, CGM.Int16Ty, CGM.Int16Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_spmd_kernel_init");
+ break;
+ }
+ case OMPRTL_NVPTX__kmpc_spmd_kernel_deinit: {
+ // Build void __kmpc_spmd_kernel_deinit();
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, llvm::None, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_spmd_kernel_deinit");
+ break;
+ }
case OMPRTL_NVPTX__kmpc_kernel_prepare_parallel: {
/// Build void __kmpc_kernel_prepare_parallel(
/// void *outlined_function);
@@ -428,6 +662,103 @@ CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) {
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_serialized_parallel");
break;
}
+ case OMPRTL_NVPTX__kmpc_shuffle_int32: {
+ // Build int32_t __kmpc_shuffle_int32(int32_t element,
+ // int16_t lane_offset, int16_t warp_size);
+ llvm::Type *TypeParams[] = {CGM.Int32Ty, CGM.Int16Ty, CGM.Int16Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_shuffle_int32");
+ break;
+ }
+ case OMPRTL_NVPTX__kmpc_shuffle_int64: {
+ // Build int64_t __kmpc_shuffle_int64(int64_t element,
+ // int16_t lane_offset, int16_t warp_size);
+ llvm::Type *TypeParams[] = {CGM.Int64Ty, CGM.Int16Ty, CGM.Int16Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int64Ty, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_shuffle_int64");
+ break;
+ }
+ case OMPRTL_NVPTX__kmpc_parallel_reduce_nowait: {
+ // Build int32_t kmpc_nvptx_parallel_reduce_nowait(kmp_int32 global_tid,
+ // kmp_int32 num_vars, size_t reduce_size, void* reduce_data,
+ // void (*kmp_ShuffleReductFctPtr)(void *rhsData, int16_t lane_id, int16_t
+ // lane_offset, int16_t Algorithm Version),
+ // void (*kmp_InterWarpCopyFctPtr)(void* src, int warp_num));
+ llvm::Type *ShuffleReduceTypeParams[] = {CGM.VoidPtrTy, CGM.Int16Ty,
+ CGM.Int16Ty, CGM.Int16Ty};
+ auto *ShuffleReduceFnTy =
+ llvm::FunctionType::get(CGM.VoidTy, ShuffleReduceTypeParams,
+ /*isVarArg=*/false);
+ llvm::Type *InterWarpCopyTypeParams[] = {CGM.VoidPtrTy, CGM.Int32Ty};
+ auto *InterWarpCopyFnTy =
+ llvm::FunctionType::get(CGM.VoidTy, InterWarpCopyTypeParams,
+ /*isVarArg=*/false);
+ llvm::Type *TypeParams[] = {CGM.Int32Ty,
+ CGM.Int32Ty,
+ CGM.SizeTy,
+ CGM.VoidPtrTy,
+ ShuffleReduceFnTy->getPointerTo(),
+ InterWarpCopyFnTy->getPointerTo()};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(
+ FnTy, /*Name=*/"__kmpc_nvptx_parallel_reduce_nowait");
+ break;
+ }
+ case OMPRTL_NVPTX__kmpc_teams_reduce_nowait: {
+ // Build int32_t __kmpc_nvptx_teams_reduce_nowait(int32_t global_tid,
+ // int32_t num_vars, size_t reduce_size, void *reduce_data,
+ // void (*kmp_ShuffleReductFctPtr)(void *rhsData, int16_t lane_id, int16_t
+ // lane_offset, int16_t shortCircuit),
+ // void (*kmp_InterWarpCopyFctPtr)(void* src, int32_t warp_num),
+ // void (*kmp_CopyToScratchpadFctPtr)(void *reduce_data, void * scratchpad,
+ // int32_t index, int32_t width),
+ // void (*kmp_LoadReduceFctPtr)(void *reduce_data, void * scratchpad,
+ // int32_t index, int32_t width, int32_t reduce))
+ llvm::Type *ShuffleReduceTypeParams[] = {CGM.VoidPtrTy, CGM.Int16Ty,
+ CGM.Int16Ty, CGM.Int16Ty};
+ auto *ShuffleReduceFnTy =
+ llvm::FunctionType::get(CGM.VoidTy, ShuffleReduceTypeParams,
+ /*isVarArg=*/false);
+ llvm::Type *InterWarpCopyTypeParams[] = {CGM.VoidPtrTy, CGM.Int32Ty};
+ auto *InterWarpCopyFnTy =
+ llvm::FunctionType::get(CGM.VoidTy, InterWarpCopyTypeParams,
+ /*isVarArg=*/false);
+ llvm::Type *CopyToScratchpadTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy,
+ CGM.Int32Ty, CGM.Int32Ty};
+ auto *CopyToScratchpadFnTy =
+ llvm::FunctionType::get(CGM.VoidTy, CopyToScratchpadTypeParams,
+ /*isVarArg=*/false);
+ llvm::Type *LoadReduceTypeParams[] = {
+ CGM.VoidPtrTy, CGM.VoidPtrTy, CGM.Int32Ty, CGM.Int32Ty, CGM.Int32Ty};
+ auto *LoadReduceFnTy =
+ llvm::FunctionType::get(CGM.VoidTy, LoadReduceTypeParams,
+ /*isVarArg=*/false);
+ llvm::Type *TypeParams[] = {CGM.Int32Ty,
+ CGM.Int32Ty,
+ CGM.SizeTy,
+ CGM.VoidPtrTy,
+ ShuffleReduceFnTy->getPointerTo(),
+ InterWarpCopyFnTy->getPointerTo(),
+ CopyToScratchpadFnTy->getPointerTo(),
+ LoadReduceFnTy->getPointerTo()};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(
+ FnTy, /*Name=*/"__kmpc_nvptx_teams_reduce_nowait");
+ break;
+ }
+ case OMPRTL_NVPTX__kmpc_end_reduce_nowait: {
+ // Build __kmpc_end_reduce_nowait(kmp_int32 global_tid);
+ llvm::Type *TypeParams[] = {CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(
+ FnTy, /*Name=*/"__kmpc_nvptx_end_reduce_nowait");
+ break;
+ }
}
return RTLFn;
}
@@ -463,39 +794,75 @@ void CGOpenMPRuntimeNVPTX::emitTargetOutlinedFunction(
assert(!ParentName.empty() && "Invalid target region parent name!");
- emitGenericKernel(D, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry,
- CodeGen);
+ CGOpenMPRuntimeNVPTX::ExecutionMode Mode =
+ getExecutionModeForDirective(CGM, D);
+ switch (Mode) {
+ case CGOpenMPRuntimeNVPTX::ExecutionMode::Generic:
+ emitGenericKernel(D, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry,
+ CodeGen);
+ break;
+ case CGOpenMPRuntimeNVPTX::ExecutionMode::Spmd:
+ emitSpmdKernel(D, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry,
+ CodeGen);
+ break;
+ case CGOpenMPRuntimeNVPTX::ExecutionMode::Unknown:
+ llvm_unreachable(
+ "Unknown programming model for OpenMP directive on NVPTX target.");
+ }
+
+ setPropertyExecutionMode(CGM, OutlinedFn->getName(), Mode);
}
CGOpenMPRuntimeNVPTX::CGOpenMPRuntimeNVPTX(CodeGenModule &CGM)
- : CGOpenMPRuntime(CGM) {
+ : CGOpenMPRuntime(CGM), CurrentExecutionMode(ExecutionMode::Unknown) {
if (!CGM.getLangOpts().OpenMPIsDevice)
llvm_unreachable("OpenMP NVPTX can only handle device code.");
}
+void CGOpenMPRuntimeNVPTX::emitProcBindClause(CodeGenFunction &CGF,
+ OpenMPProcBindClauseKind ProcBind,
+ SourceLocation Loc) {
+ // Do nothing in case of Spmd mode and L0 parallel.
+ // TODO: If in Spmd mode and L1 parallel emit the clause.
+ if (isInSpmdExecutionMode())
+ return;
+
+ CGOpenMPRuntime::emitProcBindClause(CGF, ProcBind, Loc);
+}
+
+void CGOpenMPRuntimeNVPTX::emitNumThreadsClause(CodeGenFunction &CGF,
+ llvm::Value *NumThreads,
+ SourceLocation Loc) {
+ // Do nothing in case of Spmd mode and L0 parallel.
+ // TODO: If in Spmd mode and L1 parallel emit the clause.
+ if (isInSpmdExecutionMode())
+ return;
+
+ CGOpenMPRuntime::emitNumThreadsClause(CGF, NumThreads, Loc);
+}
+
void CGOpenMPRuntimeNVPTX::emitNumTeamsClause(CodeGenFunction &CGF,
const Expr *NumTeams,
const Expr *ThreadLimit,
SourceLocation Loc) {}
-llvm::Value *CGOpenMPRuntimeNVPTX::emitParallelOrTeamsOutlinedFunction(
+llvm::Value *CGOpenMPRuntimeNVPTX::emitParallelOutlinedFunction(
const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
+ return CGOpenMPRuntime::emitParallelOutlinedFunction(D, ThreadIDVar,
+ InnermostKind, CodeGen);
+}
- llvm::Function *OutlinedFun = nullptr;
- if (isa<OMPTeamsDirective>(D)) {
- llvm::Value *OutlinedFunVal =
- CGOpenMPRuntime::emitParallelOrTeamsOutlinedFunction(
- D, ThreadIDVar, InnermostKind, CodeGen);
- OutlinedFun = cast<llvm::Function>(OutlinedFunVal);
- OutlinedFun->removeFnAttr(llvm::Attribute::NoInline);
- OutlinedFun->addFnAttr(llvm::Attribute::AlwaysInline);
- } else {
- llvm::Value *OutlinedFunVal =
- CGOpenMPRuntime::emitParallelOrTeamsOutlinedFunction(
- D, ThreadIDVar, InnermostKind, CodeGen);
- OutlinedFun = cast<llvm::Function>(OutlinedFunVal);
- }
+llvm::Value *CGOpenMPRuntimeNVPTX::emitTeamsOutlinedFunction(
+ const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
+ OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
+
+ llvm::Value *OutlinedFunVal = CGOpenMPRuntime::emitTeamsOutlinedFunction(
+ D, ThreadIDVar, InnermostKind, CodeGen);
+ llvm::Function *OutlinedFun = cast<llvm::Function>(OutlinedFunVal);
+ OutlinedFun->removeFnAttr(llvm::Attribute::NoInline);
+ OutlinedFun->removeFnAttr(llvm::Attribute::OptimizeNone);
+ OutlinedFun->addFnAttr(llvm::Attribute::AlwaysInline);
return OutlinedFun;
}
@@ -525,7 +892,10 @@ void CGOpenMPRuntimeNVPTX::emitParallelCall(
if (!CGF.HaveInsertPoint())
return;
- emitGenericParallelCall(CGF, Loc, OutlinedFn, CapturedVars, IfCond);
+ if (isInSpmdExecutionMode())
+ emitSpmdParallelCall(CGF, Loc, OutlinedFn, CapturedVars, IfCond);
+ else
+ emitGenericParallelCall(CGF, Loc, OutlinedFn, CapturedVars, IfCond);
}
void CGOpenMPRuntimeNVPTX::emitGenericParallelCall(
@@ -533,8 +903,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericParallelCall(
ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond) {
llvm::Function *Fn = cast<llvm::Function>(OutlinedFn);
- auto &&L0ParallelGen = [this, Fn, &CapturedVars](CodeGenFunction &CGF,
- PrePostActionTy &) {
+ auto &&L0ParallelGen = [this, Fn](CodeGenFunction &CGF, PrePostActionTy &) {
CGBuilderTy &Bld = CGF.Builder;
// Prepare for parallel region. Indicate the outlined function.
@@ -565,8 +934,8 @@ void CGOpenMPRuntimeNVPTX::emitGenericParallelCall(
auto &&SeqGen = [this, Fn, &CapturedVars, &Args](CodeGenFunction &CGF,
PrePostActionTy &) {
- auto &&CodeGen = [this, Fn, &CapturedVars, &Args](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
+ auto &&CodeGen = [this, Fn, &CapturedVars](CodeGenFunction &CGF,
+ PrePostActionTy &Action) {
Action.Enter(CGF);
llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
@@ -596,3 +965,1276 @@ void CGOpenMPRuntimeNVPTX::emitGenericParallelCall(
ThenRCG(CGF);
}
}
+
+void CGOpenMPRuntimeNVPTX::emitSpmdParallelCall(
+ CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *OutlinedFn,
+ ArrayRef<llvm::Value *> CapturedVars, const Expr *IfCond) {
+ // Just call the outlined function to execute the parallel region.
+ // OutlinedFn(&GTid, &zero, CapturedStruct);
+ //
+ // TODO: Do something with IfCond when support for the 'if' clause
+ // is added on Spmd target directives.
+ llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
+ OutlinedFnArgs.push_back(
+ llvm::ConstantPointerNull::get(CGM.Int32Ty->getPointerTo()));
+ OutlinedFnArgs.push_back(
+ llvm::ConstantPointerNull::get(CGM.Int32Ty->getPointerTo()));
+ OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
+ CGF.EmitCallOrInvoke(OutlinedFn, OutlinedFnArgs);
+}
+
+/// This function creates calls to one of two shuffle functions to copy
+/// variables between lanes in a warp.
+static llvm::Value *createRuntimeShuffleFunction(CodeGenFunction &CGF,
+ QualType ElemTy,
+ llvm::Value *Elem,
+ llvm::Value *Offset) {
+ auto &CGM = CGF.CGM;
+ auto &C = CGM.getContext();
+ auto &Bld = CGF.Builder;
+ CGOpenMPRuntimeNVPTX &RT =
+ *(static_cast<CGOpenMPRuntimeNVPTX *>(&CGM.getOpenMPRuntime()));
+
+ unsigned Size = CGM.getContext().getTypeSizeInChars(ElemTy).getQuantity();
+ assert(Size <= 8 && "Unsupported bitwidth in shuffle instruction.");
+
+ OpenMPRTLFunctionNVPTX ShuffleFn = Size <= 4
+ ? OMPRTL_NVPTX__kmpc_shuffle_int32
+ : OMPRTL_NVPTX__kmpc_shuffle_int64;
+
+ // Cast all types to 32- or 64-bit values before calling shuffle routines.
+ auto CastTy = Size <= 4 ? CGM.Int32Ty : CGM.Int64Ty;
+ auto *ElemCast = Bld.CreateSExtOrBitCast(Elem, CastTy);
+ auto *WarpSize = CGF.EmitScalarConversion(
+ getNVPTXWarpSize(CGF), C.getIntTypeForBitwidth(32, /* Signed */ true),
+ C.getIntTypeForBitwidth(16, /* Signed */ true), SourceLocation());
+
+ auto *ShuffledVal =
+ CGF.EmitRuntimeCall(RT.createNVPTXRuntimeFunction(ShuffleFn),
+ {ElemCast, Offset, WarpSize});
+
+ return Bld.CreateTruncOrBitCast(ShuffledVal, CGF.ConvertTypeForMem(ElemTy));
+}
+
+namespace {
+enum CopyAction : unsigned {
+ // RemoteLaneToThread: Copy over a Reduce list from a remote lane in
+ // the warp using shuffle instructions.
+ RemoteLaneToThread,
+ // ThreadCopy: Make a copy of a Reduce list on the thread's stack.
+ ThreadCopy,
+ // ThreadToScratchpad: Copy a team-reduced array to the scratchpad.
+ ThreadToScratchpad,
+ // ScratchpadToThread: Copy from a scratchpad array in global memory
+ // containing team-reduced data to a thread's stack.
+ ScratchpadToThread,
+};
+} // namespace
+
+struct CopyOptionsTy {
+ llvm::Value *RemoteLaneOffset;
+ llvm::Value *ScratchpadIndex;
+ llvm::Value *ScratchpadWidth;
+};
+
+/// Emit instructions to copy a Reduce list, which contains partially
+/// aggregated values, in the specified direction.
+static void emitReductionListCopy(
+ CopyAction Action, CodeGenFunction &CGF, QualType ReductionArrayTy,
+ ArrayRef<const Expr *> Privates, Address SrcBase, Address DestBase,
+ CopyOptionsTy CopyOptions = {nullptr, nullptr, nullptr}) {
+
+ auto &CGM = CGF.CGM;
+ auto &C = CGM.getContext();
+ auto &Bld = CGF.Builder;
+
+ auto *RemoteLaneOffset = CopyOptions.RemoteLaneOffset;
+ auto *ScratchpadIndex = CopyOptions.ScratchpadIndex;
+ auto *ScratchpadWidth = CopyOptions.ScratchpadWidth;
+
+ // Iterates, element-by-element, through the source Reduce list and
+ // make a copy.
+ unsigned Idx = 0;
+ unsigned Size = Privates.size();
+ for (auto &Private : Privates) {
+ Address SrcElementAddr = Address::invalid();
+ Address DestElementAddr = Address::invalid();
+ Address DestElementPtrAddr = Address::invalid();
+ // Should we shuffle in an element from a remote lane?
+ bool ShuffleInElement = false;
+ // Set to true to update the pointer in the dest Reduce list to a
+ // newly created element.
+ bool UpdateDestListPtr = false;
+ // Increment the src or dest pointer to the scratchpad, for each
+ // new element.
+ bool IncrScratchpadSrc = false;
+ bool IncrScratchpadDest = false;
+
+ switch (Action) {
+ case RemoteLaneToThread: {
+ // Step 1.1: Get the address for the src element in the Reduce list.
+ Address SrcElementPtrAddr =
+ Bld.CreateConstArrayGEP(SrcBase, Idx, CGF.getPointerSize());
+ llvm::Value *SrcElementPtrPtr = CGF.EmitLoadOfScalar(
+ SrcElementPtrAddr, /*Volatile=*/false, C.VoidPtrTy, SourceLocation());
+ SrcElementAddr =
+ Address(SrcElementPtrPtr, C.getTypeAlignInChars(Private->getType()));
+
+ // Step 1.2: Create a temporary to store the element in the destination
+ // Reduce list.
+ DestElementPtrAddr =
+ Bld.CreateConstArrayGEP(DestBase, Idx, CGF.getPointerSize());
+ DestElementAddr =
+ CGF.CreateMemTemp(Private->getType(), ".omp.reduction.element");
+ ShuffleInElement = true;
+ UpdateDestListPtr = true;
+ break;
+ }
+ case ThreadCopy: {
+ // Step 1.1: Get the address for the src element in the Reduce list.
+ Address SrcElementPtrAddr =
+ Bld.CreateConstArrayGEP(SrcBase, Idx, CGF.getPointerSize());
+ llvm::Value *SrcElementPtrPtr = CGF.EmitLoadOfScalar(
+ SrcElementPtrAddr, /*Volatile=*/false, C.VoidPtrTy, SourceLocation());
+ SrcElementAddr =
+ Address(SrcElementPtrPtr, C.getTypeAlignInChars(Private->getType()));
+
+ // Step 1.2: Get the address for dest element. The destination
+ // element has already been created on the thread's stack.
+ DestElementPtrAddr =
+ Bld.CreateConstArrayGEP(DestBase, Idx, CGF.getPointerSize());
+ llvm::Value *DestElementPtr =
+ CGF.EmitLoadOfScalar(DestElementPtrAddr, /*Volatile=*/false,
+ C.VoidPtrTy, SourceLocation());
+ Address DestElemAddr =
+ Address(DestElementPtr, C.getTypeAlignInChars(Private->getType()));
+ DestElementAddr = Bld.CreateElementBitCast(
+ DestElemAddr, CGF.ConvertTypeForMem(Private->getType()));
+ break;
+ }
+ case ThreadToScratchpad: {
+ // Step 1.1: Get the address for the src element in the Reduce list.
+ Address SrcElementPtrAddr =
+ Bld.CreateConstArrayGEP(SrcBase, Idx, CGF.getPointerSize());
+ llvm::Value *SrcElementPtrPtr = CGF.EmitLoadOfScalar(
+ SrcElementPtrAddr, /*Volatile=*/false, C.VoidPtrTy, SourceLocation());
+ SrcElementAddr =
+ Address(SrcElementPtrPtr, C.getTypeAlignInChars(Private->getType()));
+
+ // Step 1.2: Get the address for dest element:
+ // address = base + index * ElementSizeInChars.
+ unsigned ElementSizeInChars =
+ C.getTypeSizeInChars(Private->getType()).getQuantity();
+ auto *CurrentOffset =
+ Bld.CreateMul(llvm::ConstantInt::get(CGM.SizeTy, ElementSizeInChars),
+ ScratchpadIndex);
+ auto *ScratchPadElemAbsolutePtrVal =
+ Bld.CreateAdd(DestBase.getPointer(), CurrentOffset);
+ ScratchPadElemAbsolutePtrVal =
+ Bld.CreateIntToPtr(ScratchPadElemAbsolutePtrVal, CGF.VoidPtrTy);
+ Address ScratchpadPtr =
+ Address(ScratchPadElemAbsolutePtrVal,
+ C.getTypeAlignInChars(Private->getType()));
+ DestElementAddr = Bld.CreateElementBitCast(
+ ScratchpadPtr, CGF.ConvertTypeForMem(Private->getType()));
+ IncrScratchpadDest = true;
+ break;
+ }
+ case ScratchpadToThread: {
+ // Step 1.1: Get the address for the src element in the scratchpad.
+ // address = base + index * ElementSizeInChars.
+ unsigned ElementSizeInChars =
+ C.getTypeSizeInChars(Private->getType()).getQuantity();
+ auto *CurrentOffset =
+ Bld.CreateMul(llvm::ConstantInt::get(CGM.SizeTy, ElementSizeInChars),
+ ScratchpadIndex);
+ auto *ScratchPadElemAbsolutePtrVal =
+ Bld.CreateAdd(SrcBase.getPointer(), CurrentOffset);
+ ScratchPadElemAbsolutePtrVal =
+ Bld.CreateIntToPtr(ScratchPadElemAbsolutePtrVal, CGF.VoidPtrTy);
+ SrcElementAddr = Address(ScratchPadElemAbsolutePtrVal,
+ C.getTypeAlignInChars(Private->getType()));
+ IncrScratchpadSrc = true;
+
+ // Step 1.2: Create a temporary to store the element in the destination
+ // Reduce list.
+ DestElementPtrAddr =
+ Bld.CreateConstArrayGEP(DestBase, Idx, CGF.getPointerSize());
+ DestElementAddr =
+ CGF.CreateMemTemp(Private->getType(), ".omp.reduction.element");
+ UpdateDestListPtr = true;
+ break;
+ }
+ }
+
+ // Regardless of src and dest of copy, we emit the load of src
+ // element as this is required in all directions
+ SrcElementAddr = Bld.CreateElementBitCast(
+ SrcElementAddr, CGF.ConvertTypeForMem(Private->getType()));
+ llvm::Value *Elem =
+ CGF.EmitLoadOfScalar(SrcElementAddr, /*Volatile=*/false,
+ Private->getType(), SourceLocation());
+
+ // Now that all active lanes have read the element in the
+ // Reduce list, shuffle over the value from the remote lane.
+ if (ShuffleInElement) {
+ Elem = createRuntimeShuffleFunction(CGF, Private->getType(), Elem,
+ RemoteLaneOffset);
+ }
+
+ // Store the source element value to the dest element address.
+ CGF.EmitStoreOfScalar(Elem, DestElementAddr, /*Volatile=*/false,
+ Private->getType());
+
+ // Step 3.1: Modify reference in dest Reduce list as needed.
+ // Modifying the reference in Reduce list to point to the newly
+ // created element. The element is live in the current function
+ // scope and that of functions it invokes (i.e., reduce_function).
+ // RemoteReduceData[i] = (void*)&RemoteElem
+ if (UpdateDestListPtr) {
+ CGF.EmitStoreOfScalar(Bld.CreatePointerBitCastOrAddrSpaceCast(
+ DestElementAddr.getPointer(), CGF.VoidPtrTy),
+ DestElementPtrAddr, /*Volatile=*/false,
+ C.VoidPtrTy);
+ }
+
+ // Step 4.1: Increment SrcBase/DestBase so that it points to the starting
+ // address of the next element in scratchpad memory, unless we're currently
+ // processing the last one. Memory alignment is also taken care of here.
+ if ((IncrScratchpadDest || IncrScratchpadSrc) && (Idx + 1 < Size)) {
+ llvm::Value *ScratchpadBasePtr =
+ IncrScratchpadDest ? DestBase.getPointer() : SrcBase.getPointer();
+ unsigned ElementSizeInChars =
+ C.getTypeSizeInChars(Private->getType()).getQuantity();
+ ScratchpadBasePtr = Bld.CreateAdd(
+ ScratchpadBasePtr,
+ Bld.CreateMul(ScratchpadWidth, llvm::ConstantInt::get(
+ CGM.SizeTy, ElementSizeInChars)));
+
+ // Take care of global memory alignment for performance
+ ScratchpadBasePtr = Bld.CreateSub(ScratchpadBasePtr,
+ llvm::ConstantInt::get(CGM.SizeTy, 1));
+ ScratchpadBasePtr = Bld.CreateSDiv(
+ ScratchpadBasePtr,
+ llvm::ConstantInt::get(CGM.SizeTy, GlobalMemoryAlignment));
+ ScratchpadBasePtr = Bld.CreateAdd(ScratchpadBasePtr,
+ llvm::ConstantInt::get(CGM.SizeTy, 1));
+ ScratchpadBasePtr = Bld.CreateMul(
+ ScratchpadBasePtr,
+ llvm::ConstantInt::get(CGM.SizeTy, GlobalMemoryAlignment));
+
+ if (IncrScratchpadDest)
+ DestBase = Address(ScratchpadBasePtr, CGF.getPointerAlign());
+ else /* IncrScratchpadSrc = true */
+ SrcBase = Address(ScratchpadBasePtr, CGF.getPointerAlign());
+ }
+
+ Idx++;
+ }
+}
+
+/// This function emits a helper that loads data from the scratchpad array
+/// and (optionally) reduces it with the input operand.
+///
+/// load_and_reduce(local, scratchpad, index, width, should_reduce)
+/// reduce_data remote;
+/// for elem in remote:
+/// remote.elem = Scratchpad[elem_id][index]
+/// if (should_reduce)
+/// local = local @ remote
+/// else
+/// local = remote
+static llvm::Value *
+emitReduceScratchpadFunction(CodeGenModule &CGM,
+ ArrayRef<const Expr *> Privates,
+ QualType ReductionArrayTy, llvm::Value *ReduceFn) {
+ auto &C = CGM.getContext();
+ auto Int32Ty = C.getIntTypeForBitwidth(32, /* Signed */ true);
+
+ // Destination of the copy.
+ ImplicitParamDecl ReduceListArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ // Base address of the scratchpad array, with each element storing a
+ // Reduce list per team.
+ ImplicitParamDecl ScratchPadArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ // A source index into the scratchpad array.
+ ImplicitParamDecl IndexArg(C, Int32Ty, ImplicitParamDecl::Other);
+ // Row width of an element in the scratchpad array, typically
+ // the number of teams.
+ ImplicitParamDecl WidthArg(C, Int32Ty, ImplicitParamDecl::Other);
+ // If should_reduce == 1, then it's load AND reduce,
+ // If should_reduce == 0 (or otherwise), then it only loads (+ copy).
+ // The latter case is used for initialization.
+ ImplicitParamDecl ShouldReduceArg(C, Int32Ty, ImplicitParamDecl::Other);
+
+ FunctionArgList Args;
+ Args.push_back(&ReduceListArg);
+ Args.push_back(&ScratchPadArg);
+ Args.push_back(&IndexArg);
+ Args.push_back(&WidthArg);
+ Args.push_back(&ShouldReduceArg);
+
+ auto &CGFI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *Fn = llvm::Function::Create(
+ CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
+ "_omp_reduction_load_and_reduce", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*DC=*/nullptr, Fn, CGFI);
+ CodeGenFunction CGF(CGM);
+ // We don't need debug information in this function as nothing here refers to
+ // user code.
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args);
+
+ auto &Bld = CGF.Builder;
+
+ // Get local Reduce list pointer.
+ Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg);
+ Address ReduceListAddr(
+ Bld.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false,
+ C.VoidPtrTy, SourceLocation()),
+ CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo()),
+ CGF.getPointerAlign());
+
+ Address AddrScratchPadArg = CGF.GetAddrOfLocalVar(&ScratchPadArg);
+ llvm::Value *ScratchPadBase = CGF.EmitLoadOfScalar(
+ AddrScratchPadArg, /*Volatile=*/false, C.VoidPtrTy, SourceLocation());
+
+ Address AddrIndexArg = CGF.GetAddrOfLocalVar(&IndexArg);
+ llvm::Value *IndexVal =
+ Bld.CreateIntCast(CGF.EmitLoadOfScalar(AddrIndexArg, /*Volatile=*/false,
+ Int32Ty, SourceLocation()),
+ CGM.SizeTy, /*isSigned=*/true);
+
+ Address AddrWidthArg = CGF.GetAddrOfLocalVar(&WidthArg);
+ llvm::Value *WidthVal =
+ Bld.CreateIntCast(CGF.EmitLoadOfScalar(AddrWidthArg, /*Volatile=*/false,
+ Int32Ty, SourceLocation()),
+ CGM.SizeTy, /*isSigned=*/true);
+
+ Address AddrShouldReduceArg = CGF.GetAddrOfLocalVar(&ShouldReduceArg);
+ llvm::Value *ShouldReduceVal = CGF.EmitLoadOfScalar(
+ AddrShouldReduceArg, /*Volatile=*/false, Int32Ty, SourceLocation());
+
+ // The absolute ptr address to the base addr of the next element to copy.
+ llvm::Value *CumulativeElemBasePtr =
+ Bld.CreatePtrToInt(ScratchPadBase, CGM.SizeTy);
+ Address SrcDataAddr(CumulativeElemBasePtr, CGF.getPointerAlign());
+
+ // Create a Remote Reduce list to store the elements read from the
+ // scratchpad array.
+ Address RemoteReduceList =
+ CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.remote_red_list");
+
+ // Assemble remote Reduce list from scratchpad array.
+ emitReductionListCopy(ScratchpadToThread, CGF, ReductionArrayTy, Privates,
+ SrcDataAddr, RemoteReduceList,
+ {/*RemoteLaneOffset=*/nullptr,
+ /*ScratchpadIndex=*/IndexVal,
+ /*ScratchpadWidth=*/WidthVal});
+
+ llvm::BasicBlock *ThenBB = CGF.createBasicBlock("then");
+ llvm::BasicBlock *ElseBB = CGF.createBasicBlock("else");
+ llvm::BasicBlock *MergeBB = CGF.createBasicBlock("ifcont");
+
+ auto CondReduce = Bld.CreateICmpEQ(ShouldReduceVal, Bld.getInt32(1));
+ Bld.CreateCondBr(CondReduce, ThenBB, ElseBB);
+
+ CGF.EmitBlock(ThenBB);
+ // We should reduce with the local Reduce list.
+ // reduce_function(LocalReduceList, RemoteReduceList)
+ llvm::Value *LocalDataPtr = Bld.CreatePointerBitCastOrAddrSpaceCast(
+ ReduceListAddr.getPointer(), CGF.VoidPtrTy);
+ llvm::Value *RemoteDataPtr = Bld.CreatePointerBitCastOrAddrSpaceCast(
+ RemoteReduceList.getPointer(), CGF.VoidPtrTy);
+ CGF.EmitCallOrInvoke(ReduceFn, {LocalDataPtr, RemoteDataPtr});
+ Bld.CreateBr(MergeBB);
+
+ CGF.EmitBlock(ElseBB);
+ // No reduction; just copy:
+ // Local Reduce list = Remote Reduce list.
+ emitReductionListCopy(ThreadCopy, CGF, ReductionArrayTy, Privates,
+ RemoteReduceList, ReduceListAddr);
+ Bld.CreateBr(MergeBB);
+
+ CGF.EmitBlock(MergeBB);
+
+ CGF.FinishFunction();
+ return Fn;
+}
+
+/// This function emits a helper that stores reduced data from the team
+/// master to a scratchpad array in global memory.
+///
+/// for elem in Reduce List:
+/// scratchpad[elem_id][index] = elem
+///
+static llvm::Value *emitCopyToScratchpad(CodeGenModule &CGM,
+ ArrayRef<const Expr *> Privates,
+ QualType ReductionArrayTy) {
+
+ auto &C = CGM.getContext();
+ auto Int32Ty = C.getIntTypeForBitwidth(32, /* Signed */ true);
+
+ // Source of the copy.
+ ImplicitParamDecl ReduceListArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ // Base address of the scratchpad array, with each element storing a
+ // Reduce list per team.
+ ImplicitParamDecl ScratchPadArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ // A destination index into the scratchpad array, typically the team
+ // identifier.
+ ImplicitParamDecl IndexArg(C, Int32Ty, ImplicitParamDecl::Other);
+ // Row width of an element in the scratchpad array, typically
+ // the number of teams.
+ ImplicitParamDecl WidthArg(C, Int32Ty, ImplicitParamDecl::Other);
+
+ FunctionArgList Args;
+ Args.push_back(&ReduceListArg);
+ Args.push_back(&ScratchPadArg);
+ Args.push_back(&IndexArg);
+ Args.push_back(&WidthArg);
+
+ auto &CGFI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *Fn = llvm::Function::Create(
+ CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
+ "_omp_reduction_copy_to_scratchpad", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*DC=*/nullptr, Fn, CGFI);
+ CodeGenFunction CGF(CGM);
+ // We don't need debug information in this function as nothing here refers to
+ // user code.
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args);
+
+ auto &Bld = CGF.Builder;
+
+ Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg);
+ Address SrcDataAddr(
+ Bld.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false,
+ C.VoidPtrTy, SourceLocation()),
+ CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo()),
+ CGF.getPointerAlign());
+
+ Address AddrScratchPadArg = CGF.GetAddrOfLocalVar(&ScratchPadArg);
+ llvm::Value *ScratchPadBase = CGF.EmitLoadOfScalar(
+ AddrScratchPadArg, /*Volatile=*/false, C.VoidPtrTy, SourceLocation());
+
+ Address AddrIndexArg = CGF.GetAddrOfLocalVar(&IndexArg);
+ llvm::Value *IndexVal =
+ Bld.CreateIntCast(CGF.EmitLoadOfScalar(AddrIndexArg, /*Volatile=*/false,
+ Int32Ty, SourceLocation()),
+ CGF.SizeTy, /*isSigned=*/true);
+
+ Address AddrWidthArg = CGF.GetAddrOfLocalVar(&WidthArg);
+ llvm::Value *WidthVal =
+ Bld.CreateIntCast(CGF.EmitLoadOfScalar(AddrWidthArg, /*Volatile=*/false,
+ Int32Ty, SourceLocation()),
+ CGF.SizeTy, /*isSigned=*/true);
+
+ // The absolute ptr address to the base addr of the next element to copy.
+ llvm::Value *CumulativeElemBasePtr =
+ Bld.CreatePtrToInt(ScratchPadBase, CGM.SizeTy);
+ Address DestDataAddr(CumulativeElemBasePtr, CGF.getPointerAlign());
+
+ emitReductionListCopy(ThreadToScratchpad, CGF, ReductionArrayTy, Privates,
+ SrcDataAddr, DestDataAddr,
+ {/*RemoteLaneOffset=*/nullptr,
+ /*ScratchpadIndex=*/IndexVal,
+ /*ScratchpadWidth=*/WidthVal});
+
+ CGF.FinishFunction();
+ return Fn;
+}
+
+/// This function emits a helper that gathers Reduce lists from the first
+/// lane of every active warp to lanes in the first warp.
+///
+/// void inter_warp_copy_func(void* reduce_data, num_warps)
+/// shared smem[warp_size];
+/// For all data entries D in reduce_data:
+/// If (I am the first lane in each warp)
+/// Copy my local D to smem[warp_id]
+/// sync
+/// if (I am the first warp)
+/// Copy smem[thread_id] to my local D
+/// sync
+static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM,
+ ArrayRef<const Expr *> Privates,
+ QualType ReductionArrayTy) {
+ auto &C = CGM.getContext();
+ auto &M = CGM.getModule();
+
+ // ReduceList: thread local Reduce list.
+ // At the stage of the computation when this function is called, partially
+ // aggregated values reside in the first lane of every active warp.
+ ImplicitParamDecl ReduceListArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ // NumWarps: number of warps active in the parallel region. This could
+ // be smaller than 32 (max warps in a CTA) for partial block reduction.
+ ImplicitParamDecl NumWarpsArg(C,
+ C.getIntTypeForBitwidth(32, /* Signed */ true),
+ ImplicitParamDecl::Other);
+ FunctionArgList Args;
+ Args.push_back(&ReduceListArg);
+ Args.push_back(&NumWarpsArg);
+
+ auto &CGFI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *Fn = llvm::Function::Create(
+ CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
+ "_omp_reduction_inter_warp_copy_func", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*DC=*/nullptr, Fn, CGFI);
+ CodeGenFunction CGF(CGM);
+ // We don't need debug information in this function as nothing here refers to
+ // user code.
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args);
+
+ auto &Bld = CGF.Builder;
+
+ // This array is used as a medium to transfer, one reduce element at a time,
+ // the data from the first lane of every warp to lanes in the first warp
+ // in order to perform the final step of a reduction in a parallel region
+ // (reduction across warps). The array is placed in NVPTX __shared__ memory
+ // for reduced latency, as well as to have a distinct copy for concurrently
+ // executing target regions. The array is declared with common linkage so
+ // as to be shared across compilation units.
+ const char *TransferMediumName =
+ "__openmp_nvptx_data_transfer_temporary_storage";
+ llvm::GlobalVariable *TransferMedium =
+ M.getGlobalVariable(TransferMediumName);
+ if (!TransferMedium) {
+ auto *Ty = llvm::ArrayType::get(CGM.Int64Ty, WarpSize);
+ unsigned SharedAddressSpace = C.getTargetAddressSpace(LangAS::cuda_shared);
+ TransferMedium = new llvm::GlobalVariable(
+ M, Ty,
+ /*isConstant=*/false, llvm::GlobalVariable::CommonLinkage,
+ llvm::Constant::getNullValue(Ty), TransferMediumName,
+ /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal,
+ SharedAddressSpace);
+ }
+
+ // Get the CUDA thread id of the current OpenMP thread on the GPU.
+ auto *ThreadID = getNVPTXThreadID(CGF);
+ // nvptx_lane_id = nvptx_id % warpsize
+ auto *LaneID = getNVPTXLaneID(CGF);
+ // nvptx_warp_id = nvptx_id / warpsize
+ auto *WarpID = getNVPTXWarpID(CGF);
+
+ Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg);
+ Address LocalReduceList(
+ Bld.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false,
+ C.VoidPtrTy, SourceLocation()),
+ CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo()),
+ CGF.getPointerAlign());
+
+ unsigned Idx = 0;
+ for (auto &Private : Privates) {
+ //
+ // Warp master copies reduce element to transfer medium in __shared__
+ // memory.
+ //
+ llvm::BasicBlock *ThenBB = CGF.createBasicBlock("then");
+ llvm::BasicBlock *ElseBB = CGF.createBasicBlock("else");
+ llvm::BasicBlock *MergeBB = CGF.createBasicBlock("ifcont");
+
+ // if (lane_id == 0)
+ auto IsWarpMaster =
+ Bld.CreateICmpEQ(LaneID, Bld.getInt32(0), "warp_master");
+ Bld.CreateCondBr(IsWarpMaster, ThenBB, ElseBB);
+ CGF.EmitBlock(ThenBB);
+
+ // Reduce element = LocalReduceList[i]
+ Address ElemPtrPtrAddr =
+ Bld.CreateConstArrayGEP(LocalReduceList, Idx, CGF.getPointerSize());
+ llvm::Value *ElemPtrPtr = CGF.EmitLoadOfScalar(
+ ElemPtrPtrAddr, /*Volatile=*/false, C.VoidPtrTy, SourceLocation());
+ // elemptr = (type[i]*)(elemptrptr)
+ Address ElemPtr =
+ Address(ElemPtrPtr, C.getTypeAlignInChars(Private->getType()));
+ ElemPtr = Bld.CreateElementBitCast(
+ ElemPtr, CGF.ConvertTypeForMem(Private->getType()));
+ // elem = *elemptr
+ llvm::Value *Elem = CGF.EmitLoadOfScalar(
+ ElemPtr, /*Volatile=*/false, Private->getType(), SourceLocation());
+
+ // Get pointer to location in transfer medium.
+ // MediumPtr = &medium[warp_id]
+ llvm::Value *MediumPtrVal = Bld.CreateInBoundsGEP(
+ TransferMedium, {llvm::Constant::getNullValue(CGM.Int64Ty), WarpID});
+ Address MediumPtr(MediumPtrVal, C.getTypeAlignInChars(Private->getType()));
+ // Casting to actual data type.
+ // MediumPtr = (type[i]*)MediumPtrAddr;
+ MediumPtr = Bld.CreateElementBitCast(
+ MediumPtr, CGF.ConvertTypeForMem(Private->getType()));
+
+ //*MediumPtr = elem
+ Bld.CreateStore(Elem, MediumPtr);
+
+ Bld.CreateBr(MergeBB);
+
+ CGF.EmitBlock(ElseBB);
+ Bld.CreateBr(MergeBB);
+
+ CGF.EmitBlock(MergeBB);
+
+ Address AddrNumWarpsArg = CGF.GetAddrOfLocalVar(&NumWarpsArg);
+ llvm::Value *NumWarpsVal = CGF.EmitLoadOfScalar(
+ AddrNumWarpsArg, /*Volatile=*/false, C.IntTy, SourceLocation());
+
+ auto *NumActiveThreads = Bld.CreateNSWMul(
+ NumWarpsVal, getNVPTXWarpSize(CGF), "num_active_threads");
+ // named_barrier_sync(ParallelBarrierID, num_active_threads)
+ syncParallelThreads(CGF, NumActiveThreads);
+
+ //
+ // Warp 0 copies reduce element from transfer medium.
+ //
+ llvm::BasicBlock *W0ThenBB = CGF.createBasicBlock("then");
+ llvm::BasicBlock *W0ElseBB = CGF.createBasicBlock("else");
+ llvm::BasicBlock *W0MergeBB = CGF.createBasicBlock("ifcont");
+
+ // Up to 32 threads in warp 0 are active.
+ auto IsActiveThread =
+ Bld.CreateICmpULT(ThreadID, NumWarpsVal, "is_active_thread");
+ Bld.CreateCondBr(IsActiveThread, W0ThenBB, W0ElseBB);
+
+ CGF.EmitBlock(W0ThenBB);
+
+ // SrcMediumPtr = &medium[tid]
+ llvm::Value *SrcMediumPtrVal = Bld.CreateInBoundsGEP(
+ TransferMedium, {llvm::Constant::getNullValue(CGM.Int64Ty), ThreadID});
+ Address SrcMediumPtr(SrcMediumPtrVal,
+ C.getTypeAlignInChars(Private->getType()));
+ // SrcMediumVal = *SrcMediumPtr;
+ SrcMediumPtr = Bld.CreateElementBitCast(
+ SrcMediumPtr, CGF.ConvertTypeForMem(Private->getType()));
+ llvm::Value *SrcMediumValue = CGF.EmitLoadOfScalar(
+ SrcMediumPtr, /*Volatile=*/false, Private->getType(), SourceLocation());
+
+ // TargetElemPtr = (type[i]*)(SrcDataAddr[i])
+ Address TargetElemPtrPtr =
+ Bld.CreateConstArrayGEP(LocalReduceList, Idx, CGF.getPointerSize());
+ llvm::Value *TargetElemPtrVal = CGF.EmitLoadOfScalar(
+ TargetElemPtrPtr, /*Volatile=*/false, C.VoidPtrTy, SourceLocation());
+ Address TargetElemPtr =
+ Address(TargetElemPtrVal, C.getTypeAlignInChars(Private->getType()));
+ TargetElemPtr = Bld.CreateElementBitCast(
+ TargetElemPtr, CGF.ConvertTypeForMem(Private->getType()));
+
+ // *TargetElemPtr = SrcMediumVal;
+ CGF.EmitStoreOfScalar(SrcMediumValue, TargetElemPtr, /*Volatile=*/false,
+ Private->getType());
+ Bld.CreateBr(W0MergeBB);
+
+ CGF.EmitBlock(W0ElseBB);
+ Bld.CreateBr(W0MergeBB);
+
+ CGF.EmitBlock(W0MergeBB);
+
+ // While warp 0 copies values from transfer medium, all other warps must
+ // wait.
+ syncParallelThreads(CGF, NumActiveThreads);
+ Idx++;
+ }
+
+ CGF.FinishFunction();
+ return Fn;
+}
+
+/// Emit a helper that reduces data across two OpenMP threads (lanes)
+/// in the same warp. It uses shuffle instructions to copy over data from
+/// a remote lane's stack. The reduction algorithm performed is specified
+/// by the fourth parameter.
+///
+/// Algorithm Versions.
+/// Full Warp Reduce (argument value 0):
+/// This algorithm assumes that all 32 lanes are active and gathers
+/// data from these 32 lanes, producing a single resultant value.
+/// Contiguous Partial Warp Reduce (argument value 1):
+/// This algorithm assumes that only a *contiguous* subset of lanes
+/// are active. This happens for the last warp in a parallel region
+/// when the user specified num_threads is not an integer multiple of
+/// 32. This contiguous subset always starts with the zeroth lane.
+/// Partial Warp Reduce (argument value 2):
+/// This algorithm gathers data from any number of lanes at any position.
+/// All reduced values are stored in the lowest possible lane. The set
+/// of problems every algorithm addresses is a super set of those
+/// addressable by algorithms with a lower version number. Overhead
+/// increases as algorithm version increases.
+///
+/// Terminology
+/// Reduce element:
+/// Reduce element refers to the individual data field with primitive
+/// data types to be combined and reduced across threads.
+/// Reduce list:
+/// Reduce list refers to a collection of local, thread-private
+/// reduce elements.
+/// Remote Reduce list:
+/// Remote Reduce list refers to a collection of remote (relative to
+/// the current thread) reduce elements.
+///
+/// We distinguish between three states of threads that are important to
+/// the implementation of this function.
+/// Alive threads:
+/// Threads in a warp executing the SIMT instruction, as distinguished from
+/// threads that are inactive due to divergent control flow.
+/// Active threads:
+/// The minimal set of threads that has to be alive upon entry to this
+/// function. The computation is correct iff active threads are alive.
+/// Some threads are alive but they are not active because they do not
+/// contribute to the computation in any useful manner. Turning them off
+/// may introduce control flow overheads without any tangible benefits.
+/// Effective threads:
+/// In order to comply with the argument requirements of the shuffle
+/// function, we must keep all lanes holding data alive. But at most
+/// half of them perform value aggregation; we refer to this half of
+/// threads as effective. The other half is simply handing off their
+/// data.
+///
+/// Procedure
+/// Value shuffle:
+/// In this step active threads transfer data from higher lane positions
+/// in the warp to lower lane positions, creating Remote Reduce list.
+/// Value aggregation:
+/// In this step, effective threads combine their thread local Reduce list
+/// with Remote Reduce list and store the result in the thread local
+/// Reduce list.
+/// Value copy:
+/// In this step, we deal with the assumption made by algorithm 2
+/// (i.e. contiguity assumption). When we have an odd number of lanes
+/// active, say 2k+1, only k threads will be effective and therefore k
+/// new values will be produced. However, the Reduce list owned by the
+/// (2k+1)th thread is ignored in the value aggregation. Therefore
+/// we copy the Reduce list from the (2k+1)th lane to (k+1)th lane so
+/// that the contiguity assumption still holds.
+static llvm::Value *
+emitShuffleAndReduceFunction(CodeGenModule &CGM,
+ ArrayRef<const Expr *> Privates,
+ QualType ReductionArrayTy, llvm::Value *ReduceFn) {
+ auto &C = CGM.getContext();
+
+ // Thread local Reduce list used to host the values of data to be reduced.
+ ImplicitParamDecl ReduceListArg(C, C.VoidPtrTy, ImplicitParamDecl::Other);
+ // Current lane id; could be logical.
+ ImplicitParamDecl LaneIDArg(C, C.ShortTy, ImplicitParamDecl::Other);
+ // Offset of the remote source lane relative to the current lane.
+ ImplicitParamDecl RemoteLaneOffsetArg(C, C.ShortTy,
+ ImplicitParamDecl::Other);
+ // Algorithm version. This is expected to be known at compile time.
+ ImplicitParamDecl AlgoVerArg(C, C.ShortTy, ImplicitParamDecl::Other);
+ FunctionArgList Args;
+ Args.push_back(&ReduceListArg);
+ Args.push_back(&LaneIDArg);
+ Args.push_back(&RemoteLaneOffsetArg);
+ Args.push_back(&AlgoVerArg);
+
+ auto &CGFI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ auto *Fn = llvm::Function::Create(
+ CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
+ "_omp_reduction_shuffle_and_reduce_func", &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, CGFI);
+ CodeGenFunction CGF(CGM);
+ // We don't need debug information in this function as nothing here refers to
+ // user code.
+ CGF.disableDebugInfo();
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args);
+
+ auto &Bld = CGF.Builder;
+
+ Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg);
+ Address LocalReduceList(
+ Bld.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false,
+ C.VoidPtrTy, SourceLocation()),
+ CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo()),
+ CGF.getPointerAlign());
+
+ Address AddrLaneIDArg = CGF.GetAddrOfLocalVar(&LaneIDArg);
+ llvm::Value *LaneIDArgVal = CGF.EmitLoadOfScalar(
+ AddrLaneIDArg, /*Volatile=*/false, C.ShortTy, SourceLocation());
+
+ Address AddrRemoteLaneOffsetArg = CGF.GetAddrOfLocalVar(&RemoteLaneOffsetArg);
+ llvm::Value *RemoteLaneOffsetArgVal = CGF.EmitLoadOfScalar(
+ AddrRemoteLaneOffsetArg, /*Volatile=*/false, C.ShortTy, SourceLocation());
+
+ Address AddrAlgoVerArg = CGF.GetAddrOfLocalVar(&AlgoVerArg);
+ llvm::Value *AlgoVerArgVal = CGF.EmitLoadOfScalar(
+ AddrAlgoVerArg, /*Volatile=*/false, C.ShortTy, SourceLocation());
+
+ // Create a local thread-private variable to host the Reduce list
+ // from a remote lane.
+ Address RemoteReduceList =
+ CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.remote_reduce_list");
+
+ // This loop iterates through the list of reduce elements and copies,
+ // element by element, from a remote lane in the warp to RemoteReduceList,
+ // hosted on the thread's stack.
+ emitReductionListCopy(RemoteLaneToThread, CGF, ReductionArrayTy, Privates,
+ LocalReduceList, RemoteReduceList,
+ {/*RemoteLaneOffset=*/RemoteLaneOffsetArgVal,
+ /*ScratchpadIndex=*/nullptr,
+ /*ScratchpadWidth=*/nullptr});
+
+ // The actions to be performed on the Remote Reduce list is dependent
+ // on the algorithm version.
+ //
+ // if (AlgoVer==0) || (AlgoVer==1 && (LaneId < Offset)) || (AlgoVer==2 &&
+ // LaneId % 2 == 0 && Offset > 0):
+ // do the reduction value aggregation
+ //
+ // The thread local variable Reduce list is mutated in place to host the
+ // reduced data, which is the aggregated value produced from local and
+ // remote lanes.
+ //
+ // Note that AlgoVer is expected to be a constant integer known at compile
+ // time.
+ // When AlgoVer==0, the first conjunction evaluates to true, making
+ // the entire predicate true during compile time.
+ // When AlgoVer==1, the second conjunction has only the second part to be
+ // evaluated during runtime. Other conjunctions evaluates to false
+ // during compile time.
+ // When AlgoVer==2, the third conjunction has only the second part to be
+ // evaluated during runtime. Other conjunctions evaluates to false
+ // during compile time.
+ auto CondAlgo0 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(0));
+
+ auto Algo1 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(1));
+ auto CondAlgo1 = Bld.CreateAnd(
+ Algo1, Bld.CreateICmpULT(LaneIDArgVal, RemoteLaneOffsetArgVal));
+
+ auto Algo2 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(2));
+ auto CondAlgo2 = Bld.CreateAnd(
+ Algo2,
+ Bld.CreateICmpEQ(Bld.CreateAnd(LaneIDArgVal, Bld.getInt16(1)),
+ Bld.getInt16(0)));
+ CondAlgo2 = Bld.CreateAnd(
+ CondAlgo2, Bld.CreateICmpSGT(RemoteLaneOffsetArgVal, Bld.getInt16(0)));
+
+ auto CondReduce = Bld.CreateOr(CondAlgo0, CondAlgo1);
+ CondReduce = Bld.CreateOr(CondReduce, CondAlgo2);
+
+ llvm::BasicBlock *ThenBB = CGF.createBasicBlock("then");
+ llvm::BasicBlock *ElseBB = CGF.createBasicBlock("else");
+ llvm::BasicBlock *MergeBB = CGF.createBasicBlock("ifcont");
+ Bld.CreateCondBr(CondReduce, ThenBB, ElseBB);
+
+ CGF.EmitBlock(ThenBB);
+ // reduce_function(LocalReduceList, RemoteReduceList)
+ llvm::Value *LocalReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast(
+ LocalReduceList.getPointer(), CGF.VoidPtrTy);
+ llvm::Value *RemoteReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast(
+ RemoteReduceList.getPointer(), CGF.VoidPtrTy);
+ CGF.EmitCallOrInvoke(ReduceFn, {LocalReduceListPtr, RemoteReduceListPtr});
+ Bld.CreateBr(MergeBB);
+
+ CGF.EmitBlock(ElseBB);
+ Bld.CreateBr(MergeBB);
+
+ CGF.EmitBlock(MergeBB);
+
+ // if (AlgoVer==1 && (LaneId >= Offset)) copy Remote Reduce list to local
+ // Reduce list.
+ Algo1 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(1));
+ auto CondCopy = Bld.CreateAnd(
+ Algo1, Bld.CreateICmpUGE(LaneIDArgVal, RemoteLaneOffsetArgVal));
+
+ llvm::BasicBlock *CpyThenBB = CGF.createBasicBlock("then");
+ llvm::BasicBlock *CpyElseBB = CGF.createBasicBlock("else");
+ llvm::BasicBlock *CpyMergeBB = CGF.createBasicBlock("ifcont");
+ Bld.CreateCondBr(CondCopy, CpyThenBB, CpyElseBB);
+
+ CGF.EmitBlock(CpyThenBB);
+ emitReductionListCopy(ThreadCopy, CGF, ReductionArrayTy, Privates,
+ RemoteReduceList, LocalReduceList);
+ Bld.CreateBr(CpyMergeBB);
+
+ CGF.EmitBlock(CpyElseBB);
+ Bld.CreateBr(CpyMergeBB);
+
+ CGF.EmitBlock(CpyMergeBB);
+
+ CGF.FinishFunction();
+ return Fn;
+}
+
+///
+/// Design of OpenMP reductions on the GPU
+///
+/// Consider a typical OpenMP program with one or more reduction
+/// clauses:
+///
+/// float foo;
+/// double bar;
+/// #pragma omp target teams distribute parallel for \
+/// reduction(+:foo) reduction(*:bar)
+/// for (int i = 0; i < N; i++) {
+/// foo += A[i]; bar *= B[i];
+/// }
+///
+/// where 'foo' and 'bar' are reduced across all OpenMP threads in
+/// all teams. In our OpenMP implementation on the NVPTX device an
+/// OpenMP team is mapped to a CUDA threadblock and OpenMP threads
+/// within a team are mapped to CUDA threads within a threadblock.
+/// Our goal is to efficiently aggregate values across all OpenMP
+/// threads such that:
+///
+/// - the compiler and runtime are logically concise, and
+/// - the reduction is performed efficiently in a hierarchical
+/// manner as follows: within OpenMP threads in the same warp,
+/// across warps in a threadblock, and finally across teams on
+/// the NVPTX device.
+///
+/// Introduction to Decoupling
+///
+/// We would like to decouple the compiler and the runtime so that the
+/// latter is ignorant of the reduction variables (number, data types)
+/// and the reduction operators. This allows a simpler interface
+/// and implementation while still attaining good performance.
+///
+/// Pseudocode for the aforementioned OpenMP program generated by the
+/// compiler is as follows:
+///
+/// 1. Create private copies of reduction variables on each OpenMP
+/// thread: 'foo_private', 'bar_private'
+/// 2. Each OpenMP thread reduces the chunk of 'A' and 'B' assigned
+/// to it and writes the result in 'foo_private' and 'bar_private'
+/// respectively.
+/// 3. Call the OpenMP runtime on the GPU to reduce within a team
+/// and store the result on the team master:
+///
+/// __kmpc_nvptx_parallel_reduce_nowait(...,
+/// reduceData, shuffleReduceFn, interWarpCpyFn)
+///
+/// where:
+/// struct ReduceData {
+/// double *foo;
+/// double *bar;
+/// } reduceData
+/// reduceData.foo = &foo_private
+/// reduceData.bar = &bar_private
+///
+/// 'shuffleReduceFn' and 'interWarpCpyFn' are pointers to two
+/// auxiliary functions generated by the compiler that operate on
+/// variables of type 'ReduceData'. They aid the runtime perform
+/// algorithmic steps in a data agnostic manner.
+///
+/// 'shuffleReduceFn' is a pointer to a function that reduces data
+/// of type 'ReduceData' across two OpenMP threads (lanes) in the
+/// same warp. It takes the following arguments as input:
+///
+/// a. variable of type 'ReduceData' on the calling lane,
+/// b. its lane_id,
+/// c. an offset relative to the current lane_id to generate a
+/// remote_lane_id. The remote lane contains the second
+/// variable of type 'ReduceData' that is to be reduced.
+/// d. an algorithm version parameter determining which reduction
+/// algorithm to use.
+///
+/// 'shuffleReduceFn' retrieves data from the remote lane using
+/// efficient GPU shuffle intrinsics and reduces, using the
+/// algorithm specified by the 4th parameter, the two operands
+/// element-wise. The result is written to the first operand.
+///
+/// Different reduction algorithms are implemented in different
+/// runtime functions, all calling 'shuffleReduceFn' to perform
+/// the essential reduction step. Therefore, based on the 4th
+/// parameter, this function behaves slightly differently to
+/// cooperate with the runtime to ensure correctness under
+/// different circumstances.
+///
+/// 'InterWarpCpyFn' is a pointer to a function that transfers
+/// reduced variables across warps. It tunnels, through CUDA
+/// shared memory, the thread-private data of type 'ReduceData'
+/// from lane 0 of each warp to a lane in the first warp.
+/// 4. Call the OpenMP runtime on the GPU to reduce across teams.
+/// The last team writes the global reduced value to memory.
+///
+/// ret = __kmpc_nvptx_teams_reduce_nowait(...,
+/// reduceData, shuffleReduceFn, interWarpCpyFn,
+/// scratchpadCopyFn, loadAndReduceFn)
+///
+/// 'scratchpadCopyFn' is a helper that stores reduced
+/// data from the team master to a scratchpad array in
+/// global memory.
+///
+/// 'loadAndReduceFn' is a helper that loads data from
+/// the scratchpad array and reduces it with the input
+/// operand.
+///
+/// These compiler generated functions hide address
+/// calculation and alignment information from the runtime.
+/// 5. if ret == 1:
+/// The team master of the last team stores the reduced
+/// result to the globals in memory.
+/// foo += reduceData.foo; bar *= reduceData.bar
+///
+///
+/// Warp Reduction Algorithms
+///
+/// On the warp level, we have three algorithms implemented in the
+/// OpenMP runtime depending on the number of active lanes:
+///
+/// Full Warp Reduction
+///
+/// The reduce algorithm within a warp where all lanes are active
+/// is implemented in the runtime as follows:
+///
+/// full_warp_reduce(void *reduce_data,
+/// kmp_ShuffleReductFctPtr ShuffleReduceFn) {
+/// for (int offset = WARPSIZE/2; offset > 0; offset /= 2)
+/// ShuffleReduceFn(reduce_data, 0, offset, 0);
+/// }
+///
+/// The algorithm completes in log(2, WARPSIZE) steps.
+///
+/// 'ShuffleReduceFn' is used here with lane_id set to 0 because it is
+/// not used therefore we save instructions by not retrieving lane_id
+/// from the corresponding special registers. The 4th parameter, which
+/// represents the version of the algorithm being used, is set to 0 to
+/// signify full warp reduction.
+///
+/// In this version, 'ShuffleReduceFn' behaves, per element, as follows:
+///
+/// #reduce_elem refers to an element in the local lane's data structure
+/// #remote_elem is retrieved from a remote lane
+/// remote_elem = shuffle_down(reduce_elem, offset, WARPSIZE);
+/// reduce_elem = reduce_elem REDUCE_OP remote_elem;
+///
+/// Contiguous Partial Warp Reduction
+///
+/// This reduce algorithm is used within a warp where only the first
+/// 'n' (n <= WARPSIZE) lanes are active. It is typically used when the
+/// number of OpenMP threads in a parallel region is not a multiple of
+/// WARPSIZE. The algorithm is implemented in the runtime as follows:
+///
+/// void
+/// contiguous_partial_reduce(void *reduce_data,
+/// kmp_ShuffleReductFctPtr ShuffleReduceFn,
+/// int size, int lane_id) {
+/// int curr_size;
+/// int offset;
+/// curr_size = size;
+/// mask = curr_size/2;
+/// while (offset>0) {
+/// ShuffleReduceFn(reduce_data, lane_id, offset, 1);
+/// curr_size = (curr_size+1)/2;
+/// offset = curr_size/2;
+/// }
+/// }
+///
+/// In this version, 'ShuffleReduceFn' behaves, per element, as follows:
+///
+/// remote_elem = shuffle_down(reduce_elem, offset, WARPSIZE);
+/// if (lane_id < offset)
+/// reduce_elem = reduce_elem REDUCE_OP remote_elem
+/// else
+/// reduce_elem = remote_elem
+///
+/// This algorithm assumes that the data to be reduced are located in a
+/// contiguous subset of lanes starting from the first. When there is
+/// an odd number of active lanes, the data in the last lane is not
+/// aggregated with any other lane's dat but is instead copied over.
+///
+/// Dispersed Partial Warp Reduction
+///
+/// This algorithm is used within a warp when any discontiguous subset of
+/// lanes are active. It is used to implement the reduction operation
+/// across lanes in an OpenMP simd region or in a nested parallel region.
+///
+/// void
+/// dispersed_partial_reduce(void *reduce_data,
+/// kmp_ShuffleReductFctPtr ShuffleReduceFn) {
+/// int size, remote_id;
+/// int logical_lane_id = number_of_active_lanes_before_me() * 2;
+/// do {
+/// remote_id = next_active_lane_id_right_after_me();
+/// # the above function returns 0 of no active lane
+/// # is present right after the current lane.
+/// size = number_of_active_lanes_in_this_warp();
+/// logical_lane_id /= 2;
+/// ShuffleReduceFn(reduce_data, logical_lane_id,
+/// remote_id-1-threadIdx.x, 2);
+/// } while (logical_lane_id % 2 == 0 && size > 1);
+/// }
+///
+/// There is no assumption made about the initial state of the reduction.
+/// Any number of lanes (>=1) could be active at any position. The reduction
+/// result is returned in the first active lane.
+///
+/// In this version, 'ShuffleReduceFn' behaves, per element, as follows:
+///
+/// remote_elem = shuffle_down(reduce_elem, offset, WARPSIZE);
+/// if (lane_id % 2 == 0 && offset > 0)
+/// reduce_elem = reduce_elem REDUCE_OP remote_elem
+/// else
+/// reduce_elem = remote_elem
+///
+///
+/// Intra-Team Reduction
+///
+/// This function, as implemented in the runtime call
+/// '__kmpc_nvptx_parallel_reduce_nowait', aggregates data across OpenMP
+/// threads in a team. It first reduces within a warp using the
+/// aforementioned algorithms. We then proceed to gather all such
+/// reduced values at the first warp.
+///
+/// The runtime makes use of the function 'InterWarpCpyFn', which copies
+/// data from each of the "warp master" (zeroth lane of each warp, where
+/// warp-reduced data is held) to the zeroth warp. This step reduces (in
+/// a mathematical sense) the problem of reduction across warp masters in
+/// a block to the problem of warp reduction.
+///
+///
+/// Inter-Team Reduction
+///
+/// Once a team has reduced its data to a single value, it is stored in
+/// a global scratchpad array. Since each team has a distinct slot, this
+/// can be done without locking.
+///
+/// The last team to write to the scratchpad array proceeds to reduce the
+/// scratchpad array. One or more workers in the last team use the helper
+/// 'loadAndReduceDataFn' to load and reduce values from the array, i.e.,
+/// the k'th worker reduces every k'th element.
+///
+/// Finally, a call is made to '__kmpc_nvptx_parallel_reduce_nowait' to
+/// reduce across workers and compute a globally reduced value.
+///
+void CGOpenMPRuntimeNVPTX::emitReduction(
+ CodeGenFunction &CGF, SourceLocation Loc, ArrayRef<const Expr *> Privates,
+ ArrayRef<const Expr *> LHSExprs, ArrayRef<const Expr *> RHSExprs,
+ ArrayRef<const Expr *> ReductionOps, ReductionOptionsTy Options) {
+ if (!CGF.HaveInsertPoint())
+ return;
+
+ bool ParallelReduction = isOpenMPParallelDirective(Options.ReductionKind);
+ bool TeamsReduction = isOpenMPTeamsDirective(Options.ReductionKind);
+ // FIXME: Add support for simd reduction.
+ assert((TeamsReduction || ParallelReduction) &&
+ "Invalid reduction selection in emitReduction.");
+
+ auto &C = CGM.getContext();
+
+ // 1. Build a list of reduction variables.
+ // void *RedList[<n>] = {<ReductionVars>[0], ..., <ReductionVars>[<n>-1]};
+ auto Size = RHSExprs.size();
+ for (auto *E : Privates) {
+ if (E->getType()->isVariablyModifiedType())
+ // Reserve place for array size.
+ ++Size;
+ }
+ llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size);
+ QualType ReductionArrayTy =
+ C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
+ Address ReductionList =
+ CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
+ auto IPriv = Privates.begin();
+ unsigned Idx = 0;
+ for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I, ++IPriv, ++Idx) {
+ Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx,
+ CGF.getPointerSize());
+ CGF.Builder.CreateStore(
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitLValue(RHSExprs[I]).getPointer(), CGF.VoidPtrTy),
+ Elem);
+ if ((*IPriv)->getType()->isVariablyModifiedType()) {
+ // Store array size.
+ ++Idx;
+ Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx,
+ CGF.getPointerSize());
+ llvm::Value *Size = CGF.Builder.CreateIntCast(
+ CGF.getVLASize(
+ CGF.getContext().getAsVariableArrayType((*IPriv)->getType()))
+ .first,
+ CGF.SizeTy, /*isSigned=*/false);
+ CGF.Builder.CreateStore(CGF.Builder.CreateIntToPtr(Size, CGF.VoidPtrTy),
+ Elem);
+ }
+ }
+
+ // 2. Emit reduce_func().
+ auto *ReductionFn = emitReductionFunction(
+ CGM, CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo(), Privates,
+ LHSExprs, RHSExprs, ReductionOps);
+
+ // 4. Build res = __kmpc_reduce{_nowait}(<gtid>, <n>, sizeof(RedList),
+ // RedList, shuffle_reduce_func, interwarp_copy_func);
+ auto *ThreadId = getThreadID(CGF, Loc);
+ auto *ReductionArrayTySize = CGF.getTypeSize(ReductionArrayTy);
+ auto *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ ReductionList.getPointer(), CGF.VoidPtrTy);
+
+ auto *ShuffleAndReduceFn = emitShuffleAndReduceFunction(
+ CGM, Privates, ReductionArrayTy, ReductionFn);
+ auto *InterWarpCopyFn =
+ emitInterWarpCopyFunction(CGM, Privates, ReductionArrayTy);
+
+ llvm::Value *Res = nullptr;
+ if (ParallelReduction) {
+ llvm::Value *Args[] = {ThreadId,
+ CGF.Builder.getInt32(RHSExprs.size()),
+ ReductionArrayTySize,
+ RL,
+ ShuffleAndReduceFn,
+ InterWarpCopyFn};
+
+ Res = CGF.EmitRuntimeCall(
+ createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_parallel_reduce_nowait),
+ Args);
+ }
+
+ if (TeamsReduction) {
+ auto *ScratchPadCopyFn =
+ emitCopyToScratchpad(CGM, Privates, ReductionArrayTy);
+ auto *LoadAndReduceFn = emitReduceScratchpadFunction(
+ CGM, Privates, ReductionArrayTy, ReductionFn);
+
+ llvm::Value *Args[] = {ThreadId,
+ CGF.Builder.getInt32(RHSExprs.size()),
+ ReductionArrayTySize,
+ RL,
+ ShuffleAndReduceFn,
+ InterWarpCopyFn,
+ ScratchPadCopyFn,
+ LoadAndReduceFn};
+ Res = CGF.EmitRuntimeCall(
+ createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_teams_reduce_nowait),
+ Args);
+ }
+
+ // 5. Build switch(res)
+ auto *DefaultBB = CGF.createBasicBlock(".omp.reduction.default");
+ auto *SwInst = CGF.Builder.CreateSwitch(Res, DefaultBB, /*NumCases=*/1);
+
+ // 6. Build case 1: where we have reduced values in the master
+ // thread in each team.
+ // __kmpc_end_reduce{_nowait}(<gtid>);
+ // break;
+ auto *Case1BB = CGF.createBasicBlock(".omp.reduction.case1");
+ SwInst->addCase(CGF.Builder.getInt32(1), Case1BB);
+ CGF.EmitBlock(Case1BB);
+
+ // Add emission of __kmpc_end_reduce{_nowait}(<gtid>);
+ llvm::Value *EndArgs[] = {ThreadId};
+ auto &&CodeGen = [&Privates, &LHSExprs, &RHSExprs, &ReductionOps,
+ this](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ auto IPriv = Privates.begin();
+ auto ILHS = LHSExprs.begin();
+ auto IRHS = RHSExprs.begin();
+ for (auto *E : ReductionOps) {
+ emitSingleReductionCombiner(CGF, E, *IPriv, cast<DeclRefExpr>(*ILHS),
+ cast<DeclRefExpr>(*IRHS));
+ ++IPriv;
+ ++ILHS;
+ ++IRHS;
+ }
+ };
+ RegionCodeGenTy RCG(CodeGen);
+ NVPTXActionTy Action(
+ nullptr, llvm::None,
+ createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_end_reduce_nowait),
+ EndArgs);
+ RCG.setAction(Action);
+ RCG(CGF);
+ CGF.EmitBranch(DefaultBB);
+ CGF.EmitBlock(DefaultBB, /*IsFinished=*/true);
+}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
index 4010b46..ae25e94 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
@@ -43,6 +43,8 @@ private:
void createWorkerFunction(CodeGenModule &CGM);
};
+ bool isInSpmdExecutionMode() const;
+
/// \brief Emit the worker function for the current target region.
void emitWorkerFunction(WorkerFunctionState &WST);
@@ -58,11 +60,12 @@ private:
/// function.
void emitGenericEntryFooter(CodeGenFunction &CGF, EntryFunctionState &EST);
- /// \brief Returns specified OpenMP runtime function for the current OpenMP
- /// implementation. Specialized for the NVPTX device.
- /// \param Function OpenMP runtime function.
- /// \return Specified function.
- llvm::Constant *createNVPTXRuntimeFunction(unsigned Function);
+ /// \brief Helper for Spmd mode target directive's entry function.
+ void emitSpmdEntryHeader(CodeGenFunction &CGF, EntryFunctionState &EST,
+ const OMPExecutableDirective &D);
+
+ /// \brief Signal termination of Spmd mode execution.
+ void emitSpmdEntryFooter(CodeGenFunction &CGF, EntryFunctionState &EST);
//
// Base class overrides.
@@ -87,6 +90,22 @@ private:
llvm::Constant *&OutlinedFnID, bool IsOffloadEntry,
const RegionCodeGenTy &CodeGen);
+ /// \brief Emit outlined function specialized for the Single Program
+ /// Multiple Data programming model for applicable target directives on the
+ /// NVPTX device.
+ /// \param D Directive to emit.
+ /// \param ParentName Name of the function that encloses the target region.
+ /// \param OutlinedFn Outlined function value to be defined by this call.
+ /// \param OutlinedFnID Outlined function ID value to be defined by this call.
+ /// \param IsOffloadEntry True if the outlined function is an offload entry.
+ /// \param CodeGen Object containing the target statements.
+ /// An outlined function may not be an entry if, e.g. the if clause always
+ /// evaluates to false.
+ void emitSpmdKernel(const OMPExecutableDirective &D, StringRef ParentName,
+ llvm::Function *&OutlinedFn,
+ llvm::Constant *&OutlinedFnID, bool IsOffloadEntry,
+ const RegionCodeGenTy &CodeGen);
+
/// \brief Emit outlined function for 'target' directive on the NVPTX
/// device.
/// \param D Directive to emit.
@@ -118,6 +137,22 @@ private:
ArrayRef<llvm::Value *> CapturedVars,
const Expr *IfCond);
+ /// \brief Emits code for parallel or serial call of the \a OutlinedFn with
+ /// variables captured in a record which address is stored in \a
+ /// CapturedStruct.
+ /// This call is for a parallel directive within an SPMD target directive.
+ /// \param OutlinedFn Outlined function to be run in parallel threads. Type of
+ /// this function is void(*)(kmp_int32 *, kmp_int32, struct context_vars*).
+ /// \param CapturedVars A pointer to the record with the references to
+ /// variables used in \a OutlinedFn function.
+ /// \param IfCond Condition in the associated 'if' clause, if it was
+ /// specified, nullptr otherwise.
+ ///
+ void emitSpmdParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
+ llvm::Value *OutlinedFn,
+ ArrayRef<llvm::Value *> CapturedVars,
+ const Expr *IfCond);
+
protected:
/// \brief Get the function name of an outlined region.
// The name can be customized depending on the target.
@@ -129,6 +164,20 @@ protected:
public:
explicit CGOpenMPRuntimeNVPTX(CodeGenModule &CGM);
+ /// \brief Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
+ /// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
+ virtual void emitProcBindClause(CodeGenFunction &CGF,
+ OpenMPProcBindClauseKind ProcBind,
+ SourceLocation Loc) override;
+
+ /// \brief Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
+ /// global_tid, kmp_int32 num_threads) to generate code for 'num_threads'
+ /// clause.
+ /// \param NumThreads An integer value of threads.
+ virtual void emitNumThreadsClause(CodeGenFunction &CGF,
+ llvm::Value *NumThreads,
+ SourceLocation Loc) override;
+
/// \brief This function ought to emit, in the general case, a call to
// the openmp runtime kmpc_push_num_teams. In NVPTX backend it is not needed
// as these numbers are obtained through the PTX grid and block configuration.
@@ -138,7 +187,22 @@ public:
const Expr *ThreadLimit, SourceLocation Loc) override;
/// \brief Emits inlined function for the specified OpenMP parallel
- // directive but an inlined function for teams.
+ // directive.
+ /// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
+ /// kmp_int32 BoundID, struct context_vars*).
+ /// \param D OpenMP directive.
+ /// \param ThreadIDVar Variable for thread id in the current OpenMP region.
+ /// \param InnermostKind Kind of innermost directive (for simple directives it
+ /// is a directive itself, for combined - its innermost directive).
+ /// \param CodeGen Code generation sequence for the \a D directive.
+ llvm::Value *
+ emitParallelOutlinedFunction(const OMPExecutableDirective &D,
+ const VarDecl *ThreadIDVar,
+ OpenMPDirectiveKind InnermostKind,
+ const RegionCodeGenTy &CodeGen) override;
+
+ /// \brief Emits inlined function for the specified OpenMP teams
+ // directive.
/// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
/// kmp_int32 BoundID, struct context_vars*).
/// \param D OpenMP directive.
@@ -147,10 +211,10 @@ public:
/// is a directive itself, for combined - its innermost directive).
/// \param CodeGen Code generation sequence for the \a D directive.
llvm::Value *
- emitParallelOrTeamsOutlinedFunction(const OMPExecutableDirective &D,
- const VarDecl *ThreadIDVar,
- OpenMPDirectiveKind InnermostKind,
- const RegionCodeGenTy &CodeGen) override;
+ emitTeamsOutlinedFunction(const OMPExecutableDirective &D,
+ const VarDecl *ThreadIDVar,
+ OpenMPDirectiveKind InnermostKind,
+ const RegionCodeGenTy &CodeGen) override;
/// \brief Emits code for teams call of the \a OutlinedFn with
/// variables captured in a record which address is stored in \a
@@ -177,6 +241,50 @@ public:
llvm::Value *OutlinedFn,
ArrayRef<llvm::Value *> CapturedVars,
const Expr *IfCond) override;
+
+ /// Emit a code for reduction clause.
+ ///
+ /// \param Privates List of private copies for original reduction arguments.
+ /// \param LHSExprs List of LHS in \a ReductionOps reduction operations.
+ /// \param RHSExprs List of RHS in \a ReductionOps reduction operations.
+ /// \param ReductionOps List of reduction operations in form 'LHS binop RHS'
+ /// or 'operator binop(LHS, RHS)'.
+ /// \param Options List of options for reduction codegen:
+ /// WithNowait true if parent directive has also nowait clause, false
+ /// otherwise.
+ /// SimpleReduction Emit reduction operation only. Used for omp simd
+ /// directive on the host.
+ /// ReductionKind The kind of reduction to perform.
+ virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
+ ArrayRef<const Expr *> Privates,
+ ArrayRef<const Expr *> LHSExprs,
+ ArrayRef<const Expr *> RHSExprs,
+ ArrayRef<const Expr *> ReductionOps,
+ ReductionOptionsTy Options) override;
+
+ /// Returns specified OpenMP runtime function for the current OpenMP
+ /// implementation. Specialized for the NVPTX device.
+ /// \param Function OpenMP runtime function.
+ /// \return Specified function.
+ llvm::Constant *createNVPTXRuntimeFunction(unsigned Function);
+
+ /// Target codegen is specialized based on two programming models: the
+ /// 'generic' fork-join model of OpenMP, and a more GPU efficient 'spmd'
+ /// model for constructs like 'target parallel' that support it.
+ enum ExecutionMode {
+ /// Single Program Multiple Data.
+ Spmd,
+ /// Generic codegen to support fork-join model.
+ Generic,
+ Unknown,
+ };
+
+private:
+ // Track the execution mode when codegening directives within a target
+ // region. The appropriate mode (generic/spmd) is set on entry to the
+ // target region and used by containing directives such as 'parallel'
+ // to emit optimized code.
+ ExecutionMode CurrentExecutionMode;
};
} // CodeGen namespace.
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp
index 8370607..a13c386 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp
@@ -145,7 +145,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
EmitCoroutineBody(cast<CoroutineBodyStmt>(*S));
break;
case Stmt::CoreturnStmtClass:
- CGM.ErrorUnsupported(S, "coroutine");
+ EmitCoreturnStmt(cast<CoreturnStmt>(*S));
break;
case Stmt::CapturedStmtClass: {
const CapturedStmt *CS = cast<CapturedStmt>(S);
@@ -1024,6 +1024,18 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
/// if the function returns void, or may be missing one if the function returns
/// non-void. Fun stuff :).
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
+ if (requiresReturnValueCheck()) {
+ llvm::Constant *SLoc = EmitCheckSourceLocation(S.getLocStart());
+ auto *SLocPtr =
+ new llvm::GlobalVariable(CGM.getModule(), SLoc->getType(), false,
+ llvm::GlobalVariable::PrivateLinkage, SLoc);
+ SLocPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
+ CGM.getSanitizerMetadata()->disableSanitizerForGlobal(SLocPtr);
+ assert(ReturnLocation.isValid() && "No valid return location");
+ Builder.CreateStore(Builder.CreateBitCast(SLocPtr, Int8PtrTy),
+ ReturnLocation);
+ }
+
// Returning from an outlined SEH helper is UB, and we already warn on it.
if (IsOutlinedSEHHelper) {
Builder.CreateUnreachable();
@@ -1166,7 +1178,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
if (Rem)
Rem--;
SwitchInsn->addCase(Builder.getInt(LHS), CaseDest);
- LHS++;
+ ++LHS;
}
return;
}
@@ -2127,16 +2139,16 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect,
/* IsAlignStack */ false, AsmDialect);
llvm::CallInst *Result = Builder.CreateCall(IA, Args);
- Result->addAttribute(llvm::AttributeSet::FunctionIndex,
+ Result->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoUnwind);
// Attach readnone and readonly attributes.
if (!HasSideEffect) {
if (ReadNone)
- Result->addAttribute(llvm::AttributeSet::FunctionIndex,
+ Result->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::ReadNone);
else if (ReadOnly)
- Result->addAttribute(llvm::AttributeSet::FunctionIndex,
+ Result->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::ReadOnly);
}
@@ -2157,7 +2169,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Conservatively, mark all inline asm blocks in CUDA as convergent
// (meaning, they may call an intrinsically convergent op, such as bar.sync,
// and so can't have certain optimizations applied around them).
- Result->addAttribute(llvm::AttributeSet::FunctionIndex,
+ Result->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::Convergent);
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 39e1cdf..6135cf3 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -26,7 +26,7 @@ using namespace CodeGen;
namespace {
/// Lexical scope for OpenMP executable constructs, that handles correct codegen
/// for captured expressions.
-class OMPLexicalScope final : public CodeGenFunction::LexicalScope {
+class OMPLexicalScope : public CodeGenFunction::LexicalScope {
void emitPreInitStmt(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
for (const auto *C : S.clauses()) {
if (auto *CPI = OMPClauseWithPreInit::get(C)) {
@@ -54,10 +54,11 @@ class OMPLexicalScope final : public CodeGenFunction::LexicalScope {
public:
OMPLexicalScope(CodeGenFunction &CGF, const OMPExecutableDirective &S,
- bool AsInlined = false)
+ bool AsInlined = false, bool EmitPreInitStmt = true)
: CodeGenFunction::LexicalScope(CGF, S.getSourceRange()),
InlinedShareds(CGF) {
- emitPreInitStmt(CGF, S);
+ if (EmitPreInitStmt)
+ emitPreInitStmt(CGF, S);
if (AsInlined) {
if (S.hasAssociatedStmt()) {
auto *CS = cast<CapturedStmt>(S.getAssociatedStmt());
@@ -81,6 +82,39 @@ public:
}
};
+/// Lexical scope for OpenMP parallel construct, that handles correct codegen
+/// for captured expressions.
+class OMPParallelScope final : public OMPLexicalScope {
+ bool EmitPreInitStmt(const OMPExecutableDirective &S) {
+ OpenMPDirectiveKind Kind = S.getDirectiveKind();
+ return !(isOpenMPTargetExecutionDirective(Kind) ||
+ isOpenMPLoopBoundSharingDirective(Kind)) &&
+ isOpenMPParallelDirective(Kind);
+ }
+
+public:
+ OMPParallelScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
+ : OMPLexicalScope(CGF, S,
+ /*AsInlined=*/false,
+ /*EmitPreInitStmt=*/EmitPreInitStmt(S)) {}
+};
+
+/// Lexical scope for OpenMP teams construct, that handles correct codegen
+/// for captured expressions.
+class OMPTeamsScope final : public OMPLexicalScope {
+ bool EmitPreInitStmt(const OMPExecutableDirective &S) {
+ OpenMPDirectiveKind Kind = S.getDirectiveKind();
+ return !isOpenMPTargetExecutionDirective(Kind) &&
+ isOpenMPTeamsDirective(Kind);
+ }
+
+public:
+ OMPTeamsScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
+ : OMPLexicalScope(CGF, S,
+ /*AsInlined=*/false,
+ /*EmitPreInitStmt=*/EmitPreInitStmt(S)) {}
+};
+
/// Private scope for OpenMP loop-based directives, that supports capturing
/// of used expression from loop statement.
class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
@@ -194,21 +228,58 @@ static Address castValueFromUintptr(CodeGenFunction &CGF, QualType DstType,
return TmpAddr;
}
-llvm::Function *
-CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
- assert(
- CapturedStmtInfo &&
- "CapturedStmtInfo should be set when generating the captured function");
- const CapturedDecl *CD = S.getCapturedDecl();
- const RecordDecl *RD = S.getCapturedRecordDecl();
+static QualType getCanonicalParamType(ASTContext &C, QualType T) {
+ if (T->isLValueReferenceType()) {
+ return C.getLValueReferenceType(
+ getCanonicalParamType(C, T.getNonReferenceType()),
+ /*SpelledAsLValue=*/false);
+ }
+ if (T->isPointerType())
+ return C.getPointerType(getCanonicalParamType(C, T->getPointeeType()));
+ return C.getCanonicalParamType(T);
+}
+
+namespace {
+ /// Contains required data for proper outlined function codegen.
+ struct FunctionOptions {
+ /// Captured statement for which the function is generated.
+ const CapturedStmt *S = nullptr;
+ /// true if cast to/from UIntPtr is required for variables captured by
+ /// value.
+ bool UIntPtrCastRequired = true;
+ /// true if only casted argumefnts must be registered as local args or VLA
+ /// sizes.
+ bool RegisterCastedArgsOnly = false;
+ /// Name of the generated function.
+ StringRef FunctionName;
+ explicit FunctionOptions(const CapturedStmt *S, bool UIntPtrCastRequired,
+ bool RegisterCastedArgsOnly,
+ StringRef FunctionName)
+ : S(S), UIntPtrCastRequired(UIntPtrCastRequired),
+ RegisterCastedArgsOnly(UIntPtrCastRequired && RegisterCastedArgsOnly),
+ FunctionName(FunctionName) {}
+ };
+}
+
+static std::pair<llvm::Function *, bool> emitOutlinedFunctionPrologue(
+ CodeGenFunction &CGF, FunctionArgList &Args,
+ llvm::DenseMap<const Decl *, std::pair<const VarDecl *, Address>>
+ &LocalAddrs,
+ llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>>
+ &VLASizes,
+ llvm::Value *&CXXThisValue, const FunctionOptions &FO) {
+ const CapturedDecl *CD = FO.S->getCapturedDecl();
+ const RecordDecl *RD = FO.S->getCapturedRecordDecl();
assert(CD->hasBody() && "missing CapturedDecl body");
+ CXXThisValue = nullptr;
// Build the argument list.
+ CodeGenModule &CGM = CGF.CGM;
ASTContext &Ctx = CGM.getContext();
- FunctionArgList Args;
+ bool HasUIntPtrArgs = false;
Args.append(CD->param_begin(),
std::next(CD->param_begin(), CD->getContextParamPosition()));
- auto I = S.captures().begin();
+ auto I = FO.S->captures().begin();
for (auto *FD : RD->fields()) {
QualType ArgType = FD->getType();
IdentifierInfo *II = nullptr;
@@ -220,29 +291,26 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
// deal with pointers. We can pass in the same way the VLA type sizes to the
// outlined function.
if ((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) ||
- I->capturesVariableArrayType())
- ArgType = Ctx.getUIntPtrType();
+ I->capturesVariableArrayType()) {
+ HasUIntPtrArgs = true;
+ if (FO.UIntPtrCastRequired)
+ ArgType = Ctx.getUIntPtrType();
+ }
if (I->capturesVariable() || I->capturesVariableByCopy()) {
CapVar = I->getCapturedVar();
II = CapVar->getIdentifier();
} else if (I->capturesThis())
- II = &getContext().Idents.get("this");
+ II = &Ctx.Idents.get("this");
else {
assert(I->capturesVariableArrayType());
- II = &getContext().Idents.get("vla");
- }
- if (ArgType->isVariablyModifiedType()) {
- bool IsReference = ArgType->isLValueReferenceType();
- ArgType =
- getContext().getCanonicalParamType(ArgType.getNonReferenceType());
- if (IsReference && !ArgType->isPointerType()) {
- ArgType = getContext().getLValueReferenceType(
- ArgType, /*SpelledAsLValue=*/false);
- }
+ II = &Ctx.Idents.get("vla");
}
- Args.push_back(ImplicitParamDecl::Create(getContext(), nullptr,
- FD->getLocation(), II, ArgType));
+ if (ArgType->isVariablyModifiedType())
+ ArgType = getCanonicalParamType(Ctx, ArgType.getNonReferenceType());
+ Args.push_back(ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr,
+ FD->getLocation(), II, ArgType,
+ ImplicitParamDecl::Other));
++I;
}
Args.append(
@@ -255,89 +323,166 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
- llvm::Function *F = llvm::Function::Create(
- FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
- CapturedStmtInfo->getHelperName(), &CGM.getModule());
+ llvm::Function *F =
+ llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
+ FO.FunctionName, &CGM.getModule());
CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
if (CD->isNothrow())
F->addFnAttr(llvm::Attribute::NoUnwind);
// Generate the function.
- StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(),
- CD->getBody()->getLocStart());
+ CGF.StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(),
+ CD->getBody()->getLocStart());
unsigned Cnt = CD->getContextParamPosition();
- I = S.captures().begin();
+ I = FO.S->captures().begin();
for (auto *FD : RD->fields()) {
// If we are capturing a pointer by copy we don't need to do anything, just
// use the value that we get from the arguments.
if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) {
const VarDecl *CurVD = I->getCapturedVar();
- Address LocalAddr = GetAddrOfLocalVar(Args[Cnt]);
+ Address LocalAddr = CGF.GetAddrOfLocalVar(Args[Cnt]);
// If the variable is a reference we need to materialize it here.
if (CurVD->getType()->isReferenceType()) {
- Address RefAddr = CreateMemTemp(CurVD->getType(), getPointerAlign(),
- ".materialized_ref");
- EmitStoreOfScalar(LocalAddr.getPointer(), RefAddr, /*Volatile=*/false,
- CurVD->getType());
+ Address RefAddr = CGF.CreateMemTemp(
+ CurVD->getType(), CGM.getPointerAlign(), ".materialized_ref");
+ CGF.EmitStoreOfScalar(LocalAddr.getPointer(), RefAddr,
+ /*Volatile=*/false, CurVD->getType());
LocalAddr = RefAddr;
}
- setAddrOfLocalVar(CurVD, LocalAddr);
+ if (!FO.RegisterCastedArgsOnly)
+ LocalAddrs.insert({Args[Cnt], {CurVD, LocalAddr}});
++Cnt;
++I;
continue;
}
- LValue ArgLVal =
- MakeAddrLValue(GetAddrOfLocalVar(Args[Cnt]), Args[Cnt]->getType(),
- AlignmentSource::Decl);
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
+ LValue ArgLVal = CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(Args[Cnt]),
+ Args[Cnt]->getType(), BaseInfo);
if (FD->hasCapturedVLAType()) {
- LValue CastedArgLVal =
- MakeAddrLValue(castValueFromUintptr(*this, FD->getType(),
- Args[Cnt]->getName(), ArgLVal),
- FD->getType(), AlignmentSource::Decl);
+ if (FO.UIntPtrCastRequired) {
+ ArgLVal = CGF.MakeAddrLValue(castValueFromUintptr(CGF, FD->getType(),
+ Args[Cnt]->getName(),
+ ArgLVal),
+ FD->getType(), BaseInfo);
+ }
auto *ExprArg =
- EmitLoadOfLValue(CastedArgLVal, SourceLocation()).getScalarVal();
+ CGF.EmitLoadOfLValue(ArgLVal, SourceLocation()).getScalarVal();
auto VAT = FD->getCapturedVLAType();
- VLASizeMap[VAT->getSizeExpr()] = ExprArg;
+ VLASizes.insert({Args[Cnt], {VAT->getSizeExpr(), ExprArg}});
} else if (I->capturesVariable()) {
auto *Var = I->getCapturedVar();
QualType VarTy = Var->getType();
Address ArgAddr = ArgLVal.getAddress();
if (!VarTy->isReferenceType()) {
if (ArgLVal.getType()->isLValueReferenceType()) {
- ArgAddr = EmitLoadOfReference(
+ ArgAddr = CGF.EmitLoadOfReference(
ArgAddr, ArgLVal.getType()->castAs<ReferenceType>());
} else if (!VarTy->isVariablyModifiedType() || !VarTy->isPointerType()) {
assert(ArgLVal.getType()->isPointerType());
- ArgAddr = EmitLoadOfPointer(
+ ArgAddr = CGF.EmitLoadOfPointer(
ArgAddr, ArgLVal.getType()->castAs<PointerType>());
}
}
- setAddrOfLocalVar(
- Var, Address(ArgAddr.getPointer(), getContext().getDeclAlign(Var)));
+ if (!FO.RegisterCastedArgsOnly) {
+ LocalAddrs.insert(
+ {Args[Cnt],
+ {Var, Address(ArgAddr.getPointer(), Ctx.getDeclAlign(Var))}});
+ }
} else if (I->capturesVariableByCopy()) {
assert(!FD->getType()->isAnyPointerType() &&
"Not expecting a captured pointer.");
auto *Var = I->getCapturedVar();
QualType VarTy = Var->getType();
- setAddrOfLocalVar(Var, castValueFromUintptr(*this, FD->getType(),
- Args[Cnt]->getName(), ArgLVal,
- VarTy->isReferenceType()));
+ LocalAddrs.insert(
+ {Args[Cnt],
+ {Var,
+ FO.UIntPtrCastRequired
+ ? castValueFromUintptr(CGF, FD->getType(), Args[Cnt]->getName(),
+ ArgLVal, VarTy->isReferenceType())
+ : ArgLVal.getAddress()}});
} else {
// If 'this' is captured, load it into CXXThisValue.
assert(I->capturesThis());
- CXXThisValue =
- EmitLoadOfLValue(ArgLVal, Args[Cnt]->getLocation()).getScalarVal();
+ CXXThisValue = CGF.EmitLoadOfLValue(ArgLVal, Args[Cnt]->getLocation())
+ .getScalarVal();
+ LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress()}});
}
++Cnt;
++I;
}
+ return {F, HasUIntPtrArgs};
+}
+
+llvm::Function *
+CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) {
+ assert(
+ CapturedStmtInfo &&
+ "CapturedStmtInfo should be set when generating the captured function");
+ const CapturedDecl *CD = S.getCapturedDecl();
+ // Build the argument list.
+ bool NeedWrapperFunction =
+ getDebugInfo() &&
+ CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo;
+ FunctionArgList Args;
+ llvm::DenseMap<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs;
+ llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> VLASizes;
+ FunctionOptions FO(&S, !NeedWrapperFunction, /*RegisterCastedArgsOnly=*/false,
+ CapturedStmtInfo->getHelperName());
+ llvm::Function *F;
+ bool HasUIntPtrArgs;
+ std::tie(F, HasUIntPtrArgs) = emitOutlinedFunctionPrologue(
+ *this, Args, LocalAddrs, VLASizes, CXXThisValue, FO);
+ for (const auto &LocalAddrPair : LocalAddrs) {
+ if (LocalAddrPair.second.first) {
+ setAddrOfLocalVar(LocalAddrPair.second.first,
+ LocalAddrPair.second.second);
+ }
+ }
+ for (const auto &VLASizePair : VLASizes)
+ VLASizeMap[VLASizePair.second.first] = VLASizePair.second.second;
PGO.assignRegionCounters(GlobalDecl(CD), F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
-
- return F;
+ if (!NeedWrapperFunction || !HasUIntPtrArgs)
+ return F;
+
+ FunctionOptions WrapperFO(&S, /*UIntPtrCastRequired=*/true,
+ /*RegisterCastedArgsOnly=*/true,
+ ".nondebug_wrapper.");
+ CodeGenFunction WrapperCGF(CGM, /*suppressNewContext=*/true);
+ WrapperCGF.disableDebugInfo();
+ Args.clear();
+ LocalAddrs.clear();
+ VLASizes.clear();
+ llvm::Function *WrapperF =
+ emitOutlinedFunctionPrologue(WrapperCGF, Args, LocalAddrs, VLASizes,
+ WrapperCGF.CXXThisValue, WrapperFO).first;
+ LValueBaseInfo BaseInfo(AlignmentSource::Decl, false);
+ llvm::SmallVector<llvm::Value *, 4> CallArgs;
+ for (const auto *Arg : Args) {
+ llvm::Value *CallArg;
+ auto I = LocalAddrs.find(Arg);
+ if (I != LocalAddrs.end()) {
+ LValue LV =
+ WrapperCGF.MakeAddrLValue(I->second.second, Arg->getType(), BaseInfo);
+ CallArg = WrapperCGF.EmitLoadOfScalar(LV, SourceLocation());
+ } else {
+ auto EI = VLASizes.find(Arg);
+ if (EI != VLASizes.end())
+ CallArg = EI->second.second;
+ else {
+ LValue LV = WrapperCGF.MakeAddrLValue(WrapperCGF.GetAddrOfLocalVar(Arg),
+ Arg->getType(), BaseInfo);
+ CallArg = WrapperCGF.EmitLoadOfScalar(LV, SourceLocation());
+ }
+ }
+ CallArgs.emplace_back(CallArg);
+ }
+ WrapperCGF.Builder.CreateCall(F, CallArgs);
+ WrapperCGF.FinishFunction();
+ return WrapperF;
}
//===----------------------------------------------------------------------===//
@@ -404,156 +549,6 @@ void CodeGenFunction::EmitOMPAggregateAssign(
EmitBlock(DoneBB, /*IsFinished=*/true);
}
-/// Check if the combiner is a call to UDR combiner and if it is so return the
-/// UDR decl used for reduction.
-static const OMPDeclareReductionDecl *
-getReductionInit(const Expr *ReductionOp) {
- if (auto *CE = dyn_cast<CallExpr>(ReductionOp))
- if (auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
- if (auto *DRE =
- dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
- if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl()))
- return DRD;
- return nullptr;
-}
-
-static void emitInitWithReductionInitializer(CodeGenFunction &CGF,
- const OMPDeclareReductionDecl *DRD,
- const Expr *InitOp,
- Address Private, Address Original,
- QualType Ty) {
- if (DRD->getInitializer()) {
- std::pair<llvm::Function *, llvm::Function *> Reduction =
- CGF.CGM.getOpenMPRuntime().getUserDefinedReduction(DRD);
- auto *CE = cast<CallExpr>(InitOp);
- auto *OVE = cast<OpaqueValueExpr>(CE->getCallee());
- const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
- const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
- auto *LHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(LHS)->getSubExpr());
- auto *RHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(RHS)->getSubExpr());
- CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
- PrivateScope.addPrivate(cast<VarDecl>(LHSDRE->getDecl()),
- [=]() -> Address { return Private; });
- PrivateScope.addPrivate(cast<VarDecl>(RHSDRE->getDecl()),
- [=]() -> Address { return Original; });
- (void)PrivateScope.Privatize();
- RValue Func = RValue::get(Reduction.second);
- CodeGenFunction::OpaqueValueMapping Map(CGF, OVE, Func);
- CGF.EmitIgnoredExpr(InitOp);
- } else {
- llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty);
- auto *GV = new llvm::GlobalVariable(
- CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
- llvm::GlobalValue::PrivateLinkage, Init, ".init");
- LValue LV = CGF.MakeNaturalAlignAddrLValue(GV, Ty);
- RValue InitRVal;
- switch (CGF.getEvaluationKind(Ty)) {
- case TEK_Scalar:
- InitRVal = CGF.EmitLoadOfLValue(LV, SourceLocation());
- break;
- case TEK_Complex:
- InitRVal =
- RValue::getComplex(CGF.EmitLoadOfComplex(LV, SourceLocation()));
- break;
- case TEK_Aggregate:
- InitRVal = RValue::getAggregate(LV.getAddress());
- break;
- }
- OpaqueValueExpr OVE(SourceLocation(), Ty, VK_RValue);
- CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal);
- CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
- /*IsInitializer=*/false);
- }
-}
-
-/// \brief Emit initialization of arrays of complex types.
-/// \param DestAddr Address of the array.
-/// \param Type Type of array.
-/// \param Init Initial expression of array.
-/// \param SrcAddr Address of the original array.
-static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
- QualType Type, const Expr *Init,
- Address SrcAddr = Address::invalid()) {
- auto *DRD = getReductionInit(Init);
- // Perform element-by-element initialization.
- QualType ElementTy;
-
- // Drill down to the base element type on both arrays.
- auto ArrayTy = Type->getAsArrayTypeUnsafe();
- auto NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
- DestAddr =
- CGF.Builder.CreateElementBitCast(DestAddr, DestAddr.getElementType());
- if (DRD)
- SrcAddr =
- CGF.Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType());
-
- llvm::Value *SrcBegin = nullptr;
- if (DRD)
- SrcBegin = SrcAddr.getPointer();
- auto DestBegin = DestAddr.getPointer();
- // Cast from pointer to array type to pointer to single element.
- auto DestEnd = CGF.Builder.CreateGEP(DestBegin, NumElements);
- // The basic structure here is a while-do loop.
- auto BodyBB = CGF.createBasicBlock("omp.arrayinit.body");
- auto DoneBB = CGF.createBasicBlock("omp.arrayinit.done");
- auto IsEmpty =
- CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty");
- CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
-
- // Enter the loop body, making that address the current address.
- auto EntryBB = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(BodyBB);
-
- CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
-
- llvm::PHINode *SrcElementPHI = nullptr;
- Address SrcElementCurrent = Address::invalid();
- if (DRD) {
- SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2,
- "omp.arraycpy.srcElementPast");
- SrcElementPHI->addIncoming(SrcBegin, EntryBB);
- SrcElementCurrent =
- Address(SrcElementPHI,
- SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
- }
- llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
- DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
- DestElementPHI->addIncoming(DestBegin, EntryBB);
- Address DestElementCurrent =
- Address(DestElementPHI,
- DestAddr.getAlignment().alignmentOfArrayElement(ElementSize));
-
- // Emit copy.
- {
- CodeGenFunction::RunCleanupsScope InitScope(CGF);
- if (DRD && (DRD->getInitializer() || !Init)) {
- emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent,
- SrcElementCurrent, ElementTy);
- } else
- CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
- /*IsInitializer=*/false);
- }
-
- if (DRD) {
- // Shift the address forward by one element.
- auto SrcElementNext = CGF.Builder.CreateConstGEP1_32(
- SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
- SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock());
- }
-
- // Shift the address forward by one element.
- auto DestElementNext = CGF.Builder.CreateConstGEP1_32(
- DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
- // Check whether we've reached the end.
- auto Done =
- CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done");
- CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB);
- DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock());
-
- // Done.
- CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
-}
-
void CodeGenFunction::EmitOMPCopy(QualType OriginalType, Address DestAddr,
Address SrcAddr, const VarDecl *DestVD,
const VarDecl *SrcVD, const Expr *Copy) {
@@ -906,259 +901,111 @@ void CodeGenFunction::EmitOMPLastprivateClauseFinal(
EmitBlock(DoneBB, /*IsFinished=*/true);
}
-static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
- LValue BaseLV, llvm::Value *Addr) {
- Address Tmp = Address::invalid();
- Address TopTmp = Address::invalid();
- Address MostTopTmp = Address::invalid();
- BaseTy = BaseTy.getNonReferenceType();
- while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
- !CGF.getContext().hasSameType(BaseTy, ElTy)) {
- Tmp = CGF.CreateMemTemp(BaseTy);
- if (TopTmp.isValid())
- CGF.Builder.CreateStore(Tmp.getPointer(), TopTmp);
- else
- MostTopTmp = Tmp;
- TopTmp = Tmp;
- BaseTy = BaseTy->getPointeeType();
- }
- llvm::Type *Ty = BaseLV.getPointer()->getType();
- if (Tmp.isValid())
- Ty = Tmp.getElementType();
- Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Ty);
- if (Tmp.isValid()) {
- CGF.Builder.CreateStore(Addr, Tmp);
- return MostTopTmp;
- }
- return Address(Addr, BaseLV.getAlignment());
-}
-
-static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
- LValue BaseLV) {
- BaseTy = BaseTy.getNonReferenceType();
- while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) &&
- !CGF.getContext().hasSameType(BaseTy, ElTy)) {
- if (auto *PtrTy = BaseTy->getAs<PointerType>())
- BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
- else {
- BaseLV = CGF.EmitLoadOfReferenceLValue(BaseLV.getAddress(),
- BaseTy->castAs<ReferenceType>());
- }
- BaseTy = BaseTy->getPointeeType();
- }
- return CGF.MakeAddrLValue(
- Address(
- CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
- BaseLV.getPointer(), CGF.ConvertTypeForMem(ElTy)->getPointerTo()),
- BaseLV.getAlignment()),
- BaseLV.getType(), BaseLV.getAlignmentSource());
-}
-
void CodeGenFunction::EmitOMPReductionClauseInit(
const OMPExecutableDirective &D,
CodeGenFunction::OMPPrivateScope &PrivateScope) {
if (!HaveInsertPoint())
return;
+ SmallVector<const Expr *, 4> Shareds;
+ SmallVector<const Expr *, 4> Privates;
+ SmallVector<const Expr *, 4> ReductionOps;
+ SmallVector<const Expr *, 4> LHSs;
+ SmallVector<const Expr *, 4> RHSs;
for (const auto *C : D.getClausesOfKind<OMPReductionClause>()) {
- auto ILHS = C->lhs_exprs().begin();
- auto IRHS = C->rhs_exprs().begin();
auto IPriv = C->privates().begin();
auto IRed = C->reduction_ops().begin();
- for (auto IRef : C->varlists()) {
- auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
- auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
- auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IPriv)->getDecl());
- auto *DRD = getReductionInit(*IRed);
- if (auto *OASE = dyn_cast<OMPArraySectionExpr>(IRef)) {
- auto *Base = OASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
- Base = TempOASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- auto *DE = cast<DeclRefExpr>(Base);
- auto *OrigVD = cast<VarDecl>(DE->getDecl());
- auto OASELValueLB = EmitOMPArraySectionExpr(OASE);
- auto OASELValueUB =
- EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false);
- auto OriginalBaseLValue = EmitLValue(DE);
- LValue BaseLValue =
- loadToBegin(*this, OrigVD->getType(), OASELValueLB.getType(),
- OriginalBaseLValue);
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- PrivateScope.addPrivate(LHSVD, [this, OASELValueLB]() -> Address {
- return OASELValueLB.getAddress();
- });
- // Emit reduction copy.
- bool IsRegistered = PrivateScope.addPrivate(
- OrigVD, [this, OrigVD, PrivateVD, BaseLValue, OASELValueLB,
- OASELValueUB, OriginalBaseLValue, DRD, IRed]() -> Address {
- // Emit VarDecl with copy init for arrays.
- // Get the address of the original variable captured in current
- // captured region.
- auto *Size = Builder.CreatePtrDiff(OASELValueUB.getPointer(),
- OASELValueLB.getPointer());
- Size = Builder.CreateNUWAdd(
- Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1));
- CodeGenFunction::OpaqueValueMapping OpaqueMap(
- *this, cast<OpaqueValueExpr>(
- getContext()
- .getAsVariableArrayType(PrivateVD->getType())
- ->getSizeExpr()),
- RValue::get(Size));
- EmitVariablyModifiedType(PrivateVD->getType());
- auto Emission = EmitAutoVarAlloca(*PrivateVD);
- auto Addr = Emission.getAllocatedAddress();
- auto *Init = PrivateVD->getInit();
- EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(),
- DRD ? *IRed : Init,
- OASELValueLB.getAddress());
- EmitAutoVarCleanups(Emission);
- // Emit private VarDecl with reduction init.
- auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(),
- OASELValueLB.getPointer());
- auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset);
- return castToBase(*this, OrigVD->getType(),
- OASELValueLB.getType(), OriginalBaseLValue,
- Ptr);
- });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address {
- return GetAddrOfLocalVar(PrivateVD);
- });
- } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(IRef)) {
- auto *Base = ASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- auto *DE = cast<DeclRefExpr>(Base);
- auto *OrigVD = cast<VarDecl>(DE->getDecl());
- auto ASELValue = EmitLValue(ASE);
- auto OriginalBaseLValue = EmitLValue(DE);
- LValue BaseLValue = loadToBegin(
- *this, OrigVD->getType(), ASELValue.getType(), OriginalBaseLValue);
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- PrivateScope.addPrivate(LHSVD, [this, ASELValue]() -> Address {
- return ASELValue.getAddress();
- });
- // Emit reduction copy.
- bool IsRegistered = PrivateScope.addPrivate(
- OrigVD, [this, OrigVD, PrivateVD, BaseLValue, ASELValue,
- OriginalBaseLValue, DRD, IRed]() -> Address {
- // Emit private VarDecl with reduction init.
- AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD);
- auto Addr = Emission.getAllocatedAddress();
- if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
- emitInitWithReductionInitializer(*this, DRD, *IRed, Addr,
- ASELValue.getAddress(),
- ASELValue.getType());
- } else
- EmitAutoVarInit(Emission);
- EmitAutoVarCleanups(Emission);
- auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(),
- ASELValue.getPointer());
- auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset);
- return castToBase(*this, OrigVD->getType(), ASELValue.getType(),
- OriginalBaseLValue, Ptr);
- });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() -> Address {
- return Builder.CreateElementBitCast(
- GetAddrOfLocalVar(PrivateVD), ConvertTypeForMem(RHSVD->getType()),
- "rhs.begin");
- });
- } else {
- auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
- QualType Type = PrivateVD->getType();
- if (getContext().getAsArrayType(Type)) {
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD),
- CapturedStmtInfo->lookup(OrigVD) != nullptr,
- IRef->getType(), VK_LValue, IRef->getExprLoc());
- Address OriginalAddr = EmitLValue(&DRE).getAddress();
- PrivateScope.addPrivate(LHSVD, [this, &OriginalAddr,
- LHSVD]() -> Address {
- OriginalAddr = Builder.CreateElementBitCast(
- OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin");
- return OriginalAddr;
- });
- bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address {
- if (Type->isVariablyModifiedType()) {
- CodeGenFunction::OpaqueValueMapping OpaqueMap(
- *this, cast<OpaqueValueExpr>(
- getContext()
- .getAsVariableArrayType(PrivateVD->getType())
- ->getSizeExpr()),
- RValue::get(
- getTypeSize(OrigVD->getType().getNonReferenceType())));
- EmitVariablyModifiedType(Type);
- }
- auto Emission = EmitAutoVarAlloca(*PrivateVD);
- auto Addr = Emission.getAllocatedAddress();
- auto *Init = PrivateVD->getInit();
- EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(),
- DRD ? *IRed : Init, OriginalAddr);
- EmitAutoVarCleanups(Emission);
- return Emission.getAllocatedAddress();
- });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() -> Address {
- return Builder.CreateElementBitCast(
- GetAddrOfLocalVar(PrivateVD),
- ConvertTypeForMem(RHSVD->getType()), "rhs.begin");
- });
- } else {
- // Store the address of the original variable associated with the LHS
- // implicit variable.
- Address OriginalAddr = Address::invalid();
- PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef,
- &OriginalAddr]() -> Address {
- DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD),
- CapturedStmtInfo->lookup(OrigVD) != nullptr,
- IRef->getType(), VK_LValue, IRef->getExprLoc());
- OriginalAddr = EmitLValue(&DRE).getAddress();
- return OriginalAddr;
- });
- // Emit reduction copy.
- bool IsRegistered = PrivateScope.addPrivate(
- OrigVD, [this, PrivateVD, OriginalAddr, DRD, IRed]() -> Address {
- // Emit private VarDecl with reduction init.
- AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD);
- auto Addr = Emission.getAllocatedAddress();
- if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
- emitInitWithReductionInitializer(*this, DRD, *IRed, Addr,
- OriginalAddr,
- PrivateVD->getType());
- } else
- EmitAutoVarInit(Emission);
- EmitAutoVarCleanups(Emission);
- return Addr;
- });
- assert(IsRegistered && "private var already registered as private");
- // Silence the warning about unused variable.
- (void)IsRegistered;
- PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address {
- return GetAddrOfLocalVar(PrivateVD);
- });
- }
+ auto ILHS = C->lhs_exprs().begin();
+ auto IRHS = C->rhs_exprs().begin();
+ for (const auto *Ref : C->varlists()) {
+ Shareds.emplace_back(Ref);
+ Privates.emplace_back(*IPriv);
+ ReductionOps.emplace_back(*IRed);
+ LHSs.emplace_back(*ILHS);
+ RHSs.emplace_back(*IRHS);
+ std::advance(IPriv, 1);
+ std::advance(IRed, 1);
+ std::advance(ILHS, 1);
+ std::advance(IRHS, 1);
+ }
+ }
+ ReductionCodeGen RedCG(Shareds, Privates, ReductionOps);
+ unsigned Count = 0;
+ auto ILHS = LHSs.begin();
+ auto IRHS = RHSs.begin();
+ auto IPriv = Privates.begin();
+ for (const auto *IRef : Shareds) {
+ auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IPriv)->getDecl());
+ // Emit private VarDecl with reduction init.
+ RedCG.emitSharedLValue(*this, Count);
+ RedCG.emitAggregateType(*this, Count);
+ auto Emission = EmitAutoVarAlloca(*PrivateVD);
+ RedCG.emitInitialization(*this, Count, Emission.getAllocatedAddress(),
+ RedCG.getSharedLValue(Count),
+ [&Emission](CodeGenFunction &CGF) {
+ CGF.EmitAutoVarInit(Emission);
+ return true;
+ });
+ EmitAutoVarCleanups(Emission);
+ Address BaseAddr = RedCG.adjustPrivateAddress(
+ *this, Count, Emission.getAllocatedAddress());
+ bool IsRegistered = PrivateScope.addPrivate(
+ RedCG.getBaseDecl(Count), [BaseAddr]() -> Address { return BaseAddr; });
+ assert(IsRegistered && "private var already registered as private");
+ // Silence the warning about unused variable.
+ (void)IsRegistered;
+
+ auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
+ auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
+ if (isa<OMPArraySectionExpr>(IRef)) {
+ // Store the address of the original variable associated with the LHS
+ // implicit variable.
+ PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address {
+ return RedCG.getSharedLValue(Count).getAddress();
+ });
+ PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address {
+ return GetAddrOfLocalVar(PrivateVD);
+ });
+ } else if (isa<ArraySubscriptExpr>(IRef)) {
+ // Store the address of the original variable associated with the LHS
+ // implicit variable.
+ PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address {
+ return RedCG.getSharedLValue(Count).getAddress();
+ });
+ PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() -> Address {
+ return Builder.CreateElementBitCast(GetAddrOfLocalVar(PrivateVD),
+ ConvertTypeForMem(RHSVD->getType()),
+ "rhs.begin");
+ });
+ } else {
+ QualType Type = PrivateVD->getType();
+ bool IsArray = getContext().getAsArrayType(Type) != nullptr;
+ Address OriginalAddr = RedCG.getSharedLValue(Count).getAddress();
+ // Store the address of the original variable associated with the LHS
+ // implicit variable.
+ if (IsArray) {
+ OriginalAddr = Builder.CreateElementBitCast(
+ OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin");
}
- ++ILHS;
- ++IRHS;
- ++IPriv;
- ++IRed;
+ PrivateScope.addPrivate(
+ LHSVD, [OriginalAddr]() -> Address { return OriginalAddr; });
+ PrivateScope.addPrivate(
+ RHSVD, [this, PrivateVD, RHSVD, IsArray]() -> Address {
+ return IsArray
+ ? Builder.CreateElementBitCast(
+ GetAddrOfLocalVar(PrivateVD),
+ ConvertTypeForMem(RHSVD->getType()), "rhs.begin")
+ : GetAddrOfLocalVar(PrivateVD);
+ });
}
+ ++ILHS;
+ ++IRHS;
+ ++IPriv;
+ ++Count;
}
}
void CodeGenFunction::EmitOMPReductionClauseFinal(
- const OMPExecutableDirective &D) {
+ const OMPExecutableDirective &D, const OpenMPDirectiveKind ReductionKind) {
if (!HaveInsertPoint())
return;
llvm::SmallVector<const Expr *, 8> Privates;
@@ -1174,14 +1021,15 @@ void CodeGenFunction::EmitOMPReductionClauseFinal(
ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end());
}
if (HasAtLeastOneReduction) {
+ bool WithNowait = D.getSingleClause<OMPNowaitClause>() ||
+ isOpenMPParallelDirective(D.getDirectiveKind()) ||
+ D.getDirectiveKind() == OMPD_simd;
+ bool SimpleReduction = D.getDirectiveKind() == OMPD_simd;
// Emit nowait reduction if nowait clause is present or directive is a
// parallel directive (it always has implicit barrier).
CGM.getOpenMPRuntime().emitReduction(
*this, D.getLocEnd(), Privates, LHSExprs, RHSExprs, ReductionOps,
- D.getSingleClause<OMPNowaitClause>() ||
- isOpenMPParallelDirective(D.getDirectiveKind()) ||
- D.getDirectiveKind() == OMPD_simd,
- D.getDirectiveKind() == OMPD_simd);
+ {WithNowait, SimpleReduction, ReductionKind});
}
}
@@ -1210,14 +1058,23 @@ static void emitPostUpdateForReductionClause(
CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
}
-static void emitCommonOMPParallelDirective(CodeGenFunction &CGF,
- const OMPExecutableDirective &S,
- OpenMPDirectiveKind InnermostKind,
- const RegionCodeGenTy &CodeGen) {
- auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
- auto OutlinedFn = CGF.CGM.getOpenMPRuntime().
- emitParallelOrTeamsOutlinedFunction(S,
- *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
+namespace {
+/// Codegen lambda for appending distribute lower and upper bounds to outlined
+/// parallel function. This is necessary for combined constructs such as
+/// 'distribute parallel for'
+typedef llvm::function_ref<void(CodeGenFunction &,
+ const OMPExecutableDirective &,
+ llvm::SmallVectorImpl<llvm::Value *> &)>
+ CodeGenBoundParametersTy;
+} // anonymous namespace
+
+static void emitCommonOMPParallelDirective(
+ CodeGenFunction &CGF, const OMPExecutableDirective &S,
+ OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen,
+ const CodeGenBoundParametersTy &CodeGenBoundParameters) {
+ const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel);
+ auto OutlinedFn = CGF.CGM.getOpenMPRuntime().emitParallelOutlinedFunction(
+ S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>()) {
CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
auto NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
@@ -1239,13 +1096,22 @@ static void emitCommonOMPParallelDirective(CodeGenFunction &CGF,
}
}
- OMPLexicalScope Scope(CGF, S);
+ OMPParallelScope Scope(CGF, S);
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
+ // Combining 'distribute' with 'for' requires sharing each 'distribute' chunk
+ // lower and upper bounds with the pragma 'for' chunking mechanism.
+ // The following lambda takes care of appending the lower and upper bound
+ // parameters when necessary
+ CodeGenBoundParameters(CGF, S, CapturedVars);
CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getLocStart(), OutlinedFn,
CapturedVars, IfCond);
}
+static void emitEmptyBoundParameters(CodeGenFunction &,
+ const OMPExecutableDirective &,
+ llvm::SmallVectorImpl<llvm::Value *> &) {}
+
void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
// Emit parallel region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
@@ -1264,9 +1130,10 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- CGF.EmitOMPReductionClauseFinal(S);
+ CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
};
- emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen);
+ emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen,
+ emitEmptyBoundParameters);
emitPostUpdateForReductionClause(
*this, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; });
}
@@ -1611,6 +1478,13 @@ void CodeGenFunction::EmitOMPSimdFinal(
EmitBlock(DoneBB, /*IsFinished=*/true);
}
+static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF,
+ const OMPLoopDirective &S,
+ CodeGenFunction::JumpDest LoopExit) {
+ CGF.EmitOMPLoopBody(S, LoopExit);
+ CGF.EmitStopPoint(&S);
+}
+
void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
OMPLoopScope PreInitScope(CGF, S);
@@ -1677,7 +1551,7 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
// Emit final copy of the lastprivate variables at the end of loops.
if (HasLastprivateClause)
CGF.EmitOMPLastprivateClauseFinal(S, /*NoFinals=*/true);
- CGF.EmitOMPReductionClauseFinal(S);
+ CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_simd);
emitPostUpdateForReductionClause(
CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; });
}
@@ -1693,9 +1567,12 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen);
}
-void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
- const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) {
+void CodeGenFunction::EmitOMPOuterLoop(
+ bool DynamicOrOrdered, bool IsMonotonic, const OMPLoopDirective &S,
+ CodeGenFunction::OMPPrivateScope &LoopScope,
+ const CodeGenFunction::OMPLoopArguments &LoopArgs,
+ const CodeGenFunction::CodeGenLoopTy &CodeGenLoop,
+ const CodeGenFunction::CodeGenOrderedTy &CodeGenOrdered) {
auto &RT = CGM.getOpenMPRuntime();
const Expr *IVExpr = S.getIterationVariable();
@@ -1713,15 +1590,18 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
llvm::Value *BoolCondVal = nullptr;
if (!DynamicOrOrdered) {
- // UB = min(UB, GlobalUB)
- EmitIgnoredExpr(S.getEnsureUpperBound());
+ // UB = min(UB, GlobalUB) or
+ // UB = min(UB, PrevUB) for combined loop sharing constructs (e.g.
+ // 'distribute parallel for')
+ EmitIgnoredExpr(LoopArgs.EUB);
// IV = LB
- EmitIgnoredExpr(S.getInit());
+ EmitIgnoredExpr(LoopArgs.Init);
// IV < UB
- BoolCondVal = EvaluateExprAsBool(S.getCond());
+ BoolCondVal = EvaluateExprAsBool(LoopArgs.Cond);
} else {
- BoolCondVal = RT.emitForNext(*this, S.getLocStart(), IVSize, IVSigned, IL,
- LB, UB, ST);
+ BoolCondVal =
+ RT.emitForNext(*this, S.getLocStart(), IVSize, IVSigned, LoopArgs.IL,
+ LoopArgs.LB, LoopArgs.UB, LoopArgs.ST);
}
// If there are any cleanups between here and the loop-exit scope,
@@ -1741,7 +1621,7 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
// Emit "IV = LB" (in case of static schedule, we have already calculated new
// LB for loop condition and emitted it above).
if (DynamicOrOrdered)
- EmitIgnoredExpr(S.getInit());
+ EmitIgnoredExpr(LoopArgs.Init);
// Create a block for the increment.
auto Continue = getJumpDestInCurrentScope("omp.dispatch.inc");
@@ -1755,24 +1635,27 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
EmitOMPSimdInit(S, IsMonotonic);
SourceLocation Loc = S.getLocStart();
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(),
- [&S, LoopExit](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, LoopExit);
- CGF.EmitStopPoint(&S);
- },
- [Ordered, IVSize, IVSigned, Loc](CodeGenFunction &CGF) {
- if (Ordered) {
- CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd(
- CGF, Loc, IVSize, IVSigned);
- }
- });
+
+ // when 'distribute' is not combined with a 'for':
+ // while (idx <= UB) { BODY; ++idx; }
+ // when 'distribute' is combined with a 'for'
+ // (e.g. 'distribute parallel for')
+ // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
+ EmitOMPInnerLoop(
+ S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr,
+ [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
+ CodeGenLoop(CGF, S, LoopExit);
+ },
+ [IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) {
+ CodeGenOrdered(CGF, Loc, IVSize, IVSigned);
+ });
EmitBlock(Continue.getBlock());
BreakContinueStack.pop_back();
if (!DynamicOrOrdered) {
// Emit "LB = LB + Stride", "UB = UB + Stride".
- EmitIgnoredExpr(S.getNextLowerBound());
- EmitIgnoredExpr(S.getNextUpperBound());
+ EmitIgnoredExpr(LoopArgs.NextLB);
+ EmitIgnoredExpr(LoopArgs.NextUB);
}
EmitBranch(CondBlock);
@@ -1791,7 +1674,8 @@ void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
void CodeGenFunction::EmitOMPForOuterLoop(
const OpenMPScheduleTy &ScheduleKind, bool IsMonotonic,
const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) {
+ const OMPLoopArguments &LoopArgs,
+ const CodeGenDispatchBoundsTy &CGDispatchBounds) {
auto &RT = CGM.getOpenMPRuntime();
// Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime).
@@ -1800,7 +1684,7 @@ void CodeGenFunction::EmitOMPForOuterLoop(
assert((Ordered ||
!RT.isStaticNonchunked(ScheduleKind.Schedule,
- /*Chunked=*/Chunk != nullptr)) &&
+ LoopArgs.Chunk != nullptr)) &&
"static non-chunked schedule does not need outer loop");
// Emit outer loop.
@@ -1858,22 +1742,46 @@ void CodeGenFunction::EmitOMPForOuterLoop(
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
if (DynamicOrOrdered) {
- llvm::Value *UBVal = EmitScalarExpr(S.getLastIteration());
+ auto DispatchBounds = CGDispatchBounds(*this, S, LoopArgs.LB, LoopArgs.UB);
+ llvm::Value *LBVal = DispatchBounds.first;
+ llvm::Value *UBVal = DispatchBounds.second;
+ CGOpenMPRuntime::DispatchRTInput DipatchRTInputValues = {LBVal, UBVal,
+ LoopArgs.Chunk};
RT.emitForDispatchInit(*this, S.getLocStart(), ScheduleKind, IVSize,
- IVSigned, Ordered, UBVal, Chunk);
+ IVSigned, Ordered, DipatchRTInputValues);
} else {
RT.emitForStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned,
- Ordered, IL, LB, UB, ST, Chunk);
+ Ordered, LoopArgs.IL, LoopArgs.LB, LoopArgs.UB,
+ LoopArgs.ST, LoopArgs.Chunk);
}
- EmitOMPOuterLoop(DynamicOrOrdered, IsMonotonic, S, LoopScope, Ordered, LB, UB,
- ST, IL, Chunk);
+ auto &&CodeGenOrdered = [Ordered](CodeGenFunction &CGF, SourceLocation Loc,
+ const unsigned IVSize,
+ const bool IVSigned) {
+ if (Ordered) {
+ CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd(CGF, Loc, IVSize,
+ IVSigned);
+ }
+ };
+
+ OMPLoopArguments OuterLoopArgs(LoopArgs.LB, LoopArgs.UB, LoopArgs.ST,
+ LoopArgs.IL, LoopArgs.Chunk, LoopArgs.EUB);
+ OuterLoopArgs.IncExpr = S.getInc();
+ OuterLoopArgs.Init = S.getInit();
+ OuterLoopArgs.Cond = S.getCond();
+ OuterLoopArgs.NextLB = S.getNextLowerBound();
+ OuterLoopArgs.NextUB = S.getNextUpperBound();
+ EmitOMPOuterLoop(DynamicOrOrdered, IsMonotonic, S, LoopScope, OuterLoopArgs,
+ emitOMPLoopBodyWithStopPoint, CodeGenOrdered);
}
+static void emitEmptyOrdered(CodeGenFunction &, SourceLocation Loc,
+ const unsigned IVSize, const bool IVSigned) {}
+
void CodeGenFunction::EmitOMPDistributeOuterLoop(
- OpenMPDistScheduleClauseKind ScheduleKind,
- const OMPDistributeDirective &S, OMPPrivateScope &LoopScope,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) {
+ OpenMPDistScheduleClauseKind ScheduleKind, const OMPLoopDirective &S,
+ OMPPrivateScope &LoopScope, const OMPLoopArguments &LoopArgs,
+ const CodeGenLoopTy &CodeGenLoopContent) {
auto &RT = CGM.getOpenMPRuntime();
@@ -1886,26 +1794,159 @@ void CodeGenFunction::EmitOMPDistributeOuterLoop(
const unsigned IVSize = getContext().getTypeSize(IVExpr->getType());
const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation();
- RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind,
- IVSize, IVSigned, /* Ordered = */ false,
- IL, LB, UB, ST, Chunk);
+ RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize,
+ IVSigned, /* Ordered = */ false, LoopArgs.IL,
+ LoopArgs.LB, LoopArgs.UB, LoopArgs.ST,
+ LoopArgs.Chunk);
- EmitOMPOuterLoop(/* DynamicOrOrdered = */ false, /* IsMonotonic = */ false,
- S, LoopScope, /* Ordered = */ false, LB, UB, ST, IL, Chunk);
+ // for combined 'distribute' and 'for' the increment expression of distribute
+ // is store in DistInc. For 'distribute' alone, it is in Inc.
+ Expr *IncExpr;
+ if (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind()))
+ IncExpr = S.getDistInc();
+ else
+ IncExpr = S.getInc();
+
+ // this routine is shared by 'omp distribute parallel for' and
+ // 'omp distribute': select the right EUB expression depending on the
+ // directive
+ OMPLoopArguments OuterLoopArgs;
+ OuterLoopArgs.LB = LoopArgs.LB;
+ OuterLoopArgs.UB = LoopArgs.UB;
+ OuterLoopArgs.ST = LoopArgs.ST;
+ OuterLoopArgs.IL = LoopArgs.IL;
+ OuterLoopArgs.Chunk = LoopArgs.Chunk;
+ OuterLoopArgs.EUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedEnsureUpperBound()
+ : S.getEnsureUpperBound();
+ OuterLoopArgs.IncExpr = IncExpr;
+ OuterLoopArgs.Init = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedInit()
+ : S.getInit();
+ OuterLoopArgs.Cond = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedCond()
+ : S.getCond();
+ OuterLoopArgs.NextLB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedNextLowerBound()
+ : S.getNextLowerBound();
+ OuterLoopArgs.NextUB = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedNextUpperBound()
+ : S.getNextUpperBound();
+
+ EmitOMPOuterLoop(/* DynamicOrOrdered = */ false, /* IsMonotonic = */ false, S,
+ LoopScope, OuterLoopArgs, CodeGenLoopContent,
+ emitEmptyOrdered);
+}
+
+/// Emit a helper variable and return corresponding lvalue.
+static LValue EmitOMPHelperVar(CodeGenFunction &CGF,
+ const DeclRefExpr *Helper) {
+ auto VDecl = cast<VarDecl>(Helper->getDecl());
+ CGF.EmitVarDecl(*VDecl);
+ return CGF.EmitLValue(Helper);
+}
+
+static std::pair<LValue, LValue>
+emitDistributeParallelForInnerBounds(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S) {
+ const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
+ LValue LB =
+ EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
+ LValue UB =
+ EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
+
+ // When composing 'distribute' with 'for' (e.g. as in 'distribute
+ // parallel for') we need to use the 'distribute'
+ // chunk lower and upper bounds rather than the whole loop iteration
+ // space. These are parameters to the outlined function for 'parallel'
+ // and we copy the bounds of the previous schedule into the
+ // the current ones.
+ LValue PrevLB = CGF.EmitLValue(LS.getPrevLowerBoundVariable());
+ LValue PrevUB = CGF.EmitLValue(LS.getPrevUpperBoundVariable());
+ llvm::Value *PrevLBVal = CGF.EmitLoadOfScalar(PrevLB, SourceLocation());
+ PrevLBVal = CGF.EmitScalarConversion(
+ PrevLBVal, LS.getPrevLowerBoundVariable()->getType(),
+ LS.getIterationVariable()->getType(), SourceLocation());
+ llvm::Value *PrevUBVal = CGF.EmitLoadOfScalar(PrevUB, SourceLocation());
+ PrevUBVal = CGF.EmitScalarConversion(
+ PrevUBVal, LS.getPrevUpperBoundVariable()->getType(),
+ LS.getIterationVariable()->getType(), SourceLocation());
+
+ CGF.EmitStoreOfScalar(PrevLBVal, LB);
+ CGF.EmitStoreOfScalar(PrevUBVal, UB);
+
+ return {LB, UB};
+}
+
+/// if the 'for' loop has a dispatch schedule (e.g. dynamic, guided) then
+/// we need to use the LB and UB expressions generated by the worksharing
+/// code generation support, whereas in non combined situations we would
+/// just emit 0 and the LastIteration expression
+/// This function is necessary due to the difference of the LB and UB
+/// types for the RT emission routines for 'for_static_init' and
+/// 'for_dispatch_init'
+static std::pair<llvm::Value *, llvm::Value *>
+emitDistributeParallelForDispatchBounds(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S,
+ Address LB, Address UB) {
+ const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
+ const Expr *IVExpr = LS.getIterationVariable();
+ // when implementing a dynamic schedule for a 'for' combined with a
+ // 'distribute' (e.g. 'distribute parallel for'), the 'for' loop
+ // is not normalized as each team only executes its own assigned
+ // distribute chunk
+ QualType IteratorTy = IVExpr->getType();
+ llvm::Value *LBVal = CGF.EmitLoadOfScalar(LB, /*Volatile=*/false, IteratorTy,
+ SourceLocation());
+ llvm::Value *UBVal = CGF.EmitLoadOfScalar(UB, /*Volatile=*/false, IteratorTy,
+ SourceLocation());
+ return {LBVal, UBVal};
+}
+
+static void emitDistributeParallelForDistributeInnerBoundParams(
+ CodeGenFunction &CGF, const OMPExecutableDirective &S,
+ llvm::SmallVectorImpl<llvm::Value *> &CapturedVars) {
+ const auto &Dir = cast<OMPLoopDirective>(S);
+ LValue LB =
+ CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedLowerBoundVariable()));
+ auto LBCast = CGF.Builder.CreateIntCast(
+ CGF.Builder.CreateLoad(LB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
+ CapturedVars.push_back(LBCast);
+ LValue UB =
+ CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedUpperBoundVariable()));
+
+ auto UBCast = CGF.Builder.CreateIntCast(
+ CGF.Builder.CreateLoad(UB.getAddress()), CGF.SizeTy, /*isSigned=*/false);
+ CapturedVars.push_back(UBCast);
+}
+
+static void
+emitInnerParallelForWhenCombined(CodeGenFunction &CGF,
+ const OMPLoopDirective &S,
+ CodeGenFunction::JumpDest LoopExit) {
+ auto &&CGInlinedWorksharingLoop = [&S](CodeGenFunction &CGF,
+ PrePostActionTy &) {
+ CGF.EmitOMPWorksharingLoop(S, S.getPrevEnsureUpperBound(),
+ emitDistributeParallelForInnerBounds,
+ emitDistributeParallelForDispatchBounds);
+ };
+
+ emitCommonOMPParallelDirective(
+ CGF, S, OMPD_for, CGInlinedWorksharingLoop,
+ emitDistributeParallelForDistributeInnerBoundParams);
}
void CodeGenFunction::EmitOMPDistributeParallelForDirective(
const OMPDistributeParallelForDirective &S) {
+ auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
+ CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
+ S.getDistInc());
+ };
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
- CGM.getOpenMPRuntime().emitInlinedDirective(
- *this, OMPD_distribute_parallel_for,
- [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- OMPLoopScope PreInitScope(CGF, S);
- OMPCancelStackRAII CancelRegion(CGF, OMPD_distribute_parallel_for,
- /*HasCancel=*/false);
- CGF.EmitStmt(
- cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- });
+ OMPCancelStackRAII CancelRegion(*this, OMPD_distribute_parallel_for,
+ /*HasCancel=*/false);
+ CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen,
+ /*HasCancel=*/false);
}
void CodeGenFunction::EmitOMPDistributeParallelForSimdDirective(
@@ -2003,15 +2044,6 @@ void CodeGenFunction::EmitOMPTeamsDistributeParallelForDirective(
});
}
-void CodeGenFunction::EmitOMPTargetTeamsDirective(
- const OMPTargetTeamsDirective &S) {
- CGM.getOpenMPRuntime().emitInlinedDirective(
- *this, OMPD_target_teams, [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitStmt(
- cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- });
-}
-
void CodeGenFunction::EmitOMPTargetTeamsDistributeDirective(
const OMPTargetTeamsDistributeDirective &S) {
CGM.getOpenMPRuntime().emitInlinedDirective(
@@ -2052,14 +2084,6 @@ void CodeGenFunction::EmitOMPTargetTeamsDistributeSimdDirective(
});
}
-/// \brief Emit a helper variable and return corresponding lvalue.
-static LValue EmitOMPHelperVar(CodeGenFunction &CGF,
- const DeclRefExpr *Helper) {
- auto VDecl = cast<VarDecl>(Helper->getDecl());
- CGF.EmitVarDecl(*VDecl);
- return CGF.EmitLValue(Helper);
-}
-
namespace {
struct ScheduleKindModifiersTy {
OpenMPScheduleClauseKind Kind;
@@ -2072,7 +2096,10 @@ namespace {
};
} // namespace
-bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
+bool CodeGenFunction::EmitOMPWorksharingLoop(
+ const OMPLoopDirective &S, Expr *EUB,
+ const CodeGenLoopBoundsTy &CodeGenLoopBounds,
+ const CodeGenDispatchBoundsTy &CGDispatchBounds) {
// Emit the loop iteration variable.
auto IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
auto IVDecl = cast<VarDecl>(IVExpr->getDecl());
@@ -2122,10 +2149,10 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
emitAlignedClause(*this, S);
EmitOMPLinearClauseInit(S);
// Emit helper vars inits.
- LValue LB =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getLowerBoundVariable()));
- LValue UB =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getUpperBoundVariable()));
+
+ std::pair<LValue, LValue> Bounds = CodeGenLoopBounds(*this, S);
+ LValue LB = Bounds.first;
+ LValue UB = Bounds.second;
LValue ST =
EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
LValue IL =
@@ -2211,9 +2238,11 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_monotonic;
// Emit the outer loop, which requests its work chunk [LB..UB] from
// runtime and runs the inner loop to process it.
+ const OMPLoopArguments LoopArguments(LB.getAddress(), UB.getAddress(),
+ ST.getAddress(), IL.getAddress(),
+ Chunk, EUB);
EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered,
- LB.getAddress(), UB.getAddress(), ST.getAddress(),
- IL.getAddress(), Chunk);
+ LoopArguments, CGDispatchBounds);
}
if (isOpenMPSimdDirective(S.getDirectiveKind())) {
EmitOMPSimdFinal(S,
@@ -2222,7 +2251,10 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
CGF.EmitLoadOfScalar(IL, S.getLocStart()));
});
}
- EmitOMPReductionClauseFinal(S);
+ EmitOMPReductionClauseFinal(
+ S, /*ReductionKind=*/isOpenMPSimdDirective(S.getDirectiveKind())
+ ? /*Parallel and Simd*/ OMPD_parallel_for_simd
+ : /*Parallel only*/ OMPD_parallel);
// Emit post-update of the reduction variables if IsLastIter != 0.
emitPostUpdateForReductionClause(
*this, S, [&](CodeGenFunction &CGF) -> llvm::Value * {
@@ -2248,12 +2280,42 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) {
return HasLastprivateClause;
}
+/// The following two functions generate expressions for the loop lower
+/// and upper bounds in case of static and dynamic (dispatch) schedule
+/// of the associated 'for' or 'distribute' loop.
+static std::pair<LValue, LValue>
+emitForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
+ const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
+ LValue LB =
+ EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getLowerBoundVariable()));
+ LValue UB =
+ EmitOMPHelperVar(CGF, cast<DeclRefExpr>(LS.getUpperBoundVariable()));
+ return {LB, UB};
+}
+
+/// When dealing with dispatch schedules (e.g. dynamic, guided) we do not
+/// consider the lower and upper bound expressions generated by the
+/// worksharing loop support, but we use 0 and the iteration space size as
+/// constants
+static std::pair<llvm::Value *, llvm::Value *>
+emitDispatchForLoopBounds(CodeGenFunction &CGF, const OMPExecutableDirective &S,
+ Address LB, Address UB) {
+ const OMPLoopDirective &LS = cast<OMPLoopDirective>(S);
+ const Expr *IVExpr = LS.getIterationVariable();
+ const unsigned IVSize = CGF.getContext().getTypeSize(IVExpr->getType());
+ llvm::Value *LBVal = CGF.Builder.getIntN(IVSize, 0);
+ llvm::Value *UBVal = CGF.EmitScalarExpr(LS.getLastIteration());
+ return {LBVal, UBVal};
+}
+
void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) {
bool HasLastprivates = false;
auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
PrePostActionTy &) {
OMPCancelStackRAII CancelRegion(CGF, OMPD_for, S.hasCancel());
- HasLastprivates = CGF.EmitOMPWorksharingLoop(S);
+ HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
+ emitForLoopBounds,
+ emitDispatchForLoopBounds);
};
{
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
@@ -2271,7 +2333,9 @@ void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &S) {
bool HasLastprivates = false;
auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF,
PrePostActionTy &) {
- HasLastprivates = CGF.EmitOMPWorksharingLoop(S);
+ HasLastprivates = CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(),
+ emitForLoopBounds,
+ emitDispatchForLoopBounds);
};
{
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
@@ -2320,8 +2384,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
// Generate condition for loop.
BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
- OK_Ordinary, S.getLocStart(),
- /*fpContractable=*/false);
+ OK_Ordinary, S.getLocStart(), FPOptions());
// Increment for loop counter.
UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
S.getLocStart());
@@ -2397,7 +2460,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) {
CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd());
};
CGF.OMPCancelStack.emitExit(CGF, S.getDirectiveKind(), CodeGen);
- CGF.EmitOMPReductionClauseFinal(S);
+ CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
// Emit post-update of the reduction variables if IsLastIter != 0.
emitPostUpdateForReductionClause(
CGF, S, [&](CodeGenFunction &CGF) -> llvm::Value * {
@@ -2523,9 +2586,11 @@ void CodeGenFunction::EmitOMPParallelForDirective(
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
OMPCancelStackRAII CancelRegion(CGF, OMPD_parallel_for, S.hasCancel());
- CGF.EmitOMPWorksharingLoop(S);
+ CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
+ emitDispatchForLoopBounds);
};
- emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen);
+ emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen,
+ emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPParallelForSimdDirective(
@@ -2533,9 +2598,11 @@ void CodeGenFunction::EmitOMPParallelForSimdDirective(
// Emit directive as a combined directive that consists of two implicit
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPWorksharingLoop(S);
+ CGF.EmitOMPWorksharingLoop(S, S.getEnsureUpperBound(), emitForLoopBounds,
+ emitDispatchForLoopBounds);
};
- emitCommonOMPParallelDirective(*this, S, OMPD_simd, CodeGen);
+ emitCommonOMPParallelDirective(*this, S, OMPD_simd, CodeGen,
+ emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPParallelSectionsDirective(
@@ -2545,7 +2612,8 @@ void CodeGenFunction::EmitOMPParallelSectionsDirective(
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
CGF.EmitSections(S);
};
- emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen);
+ emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen,
+ emitEmptyBoundParameters);
}
void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S,
@@ -2629,11 +2697,32 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S,
++ID;
}
}
+ SmallVector<const Expr *, 4> LHSs;
+ SmallVector<const Expr *, 4> RHSs;
+ for (const auto *C : S.getClausesOfKind<OMPReductionClause>()) {
+ auto IPriv = C->privates().begin();
+ auto IRed = C->reduction_ops().begin();
+ auto ILHS = C->lhs_exprs().begin();
+ auto IRHS = C->rhs_exprs().begin();
+ for (const auto *Ref : C->varlists()) {
+ Data.ReductionVars.emplace_back(Ref);
+ Data.ReductionCopies.emplace_back(*IPriv);
+ Data.ReductionOps.emplace_back(*IRed);
+ LHSs.emplace_back(*ILHS);
+ RHSs.emplace_back(*IRHS);
+ std::advance(IPriv, 1);
+ std::advance(IRed, 1);
+ std::advance(ILHS, 1);
+ std::advance(IRHS, 1);
+ }
+ }
+ Data.Reductions = CGM.getOpenMPRuntime().emitTaskReductionInit(
+ *this, S.getLocStart(), LHSs, RHSs, Data);
// Build list of dependences.
for (const auto *C : S.getClausesOfKind<OMPDependClause>())
for (auto *IRef : C->varlists())
Data.Dependences.push_back(std::make_pair(C->getDependencyKind(), IRef));
- auto &&CodeGen = [PartId, &S, &Data, CS, &BodyGen, &LastprivateDstsOrigs](
+ auto &&CodeGen = [&Data, &S, CS, &BodyGen, &LastprivateDstsOrigs](
CodeGenFunction &CGF, PrePostActionTy &Action) {
// Set proper addresses for generated private copies.
OMPPrivateScope Scope(CGF);
@@ -2688,6 +2777,34 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S,
Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; });
}
}
+ if (Data.Reductions) {
+ OMPLexicalScope LexScope(CGF, S, /*AsInlined=*/true);
+ ReductionCodeGen RedCG(Data.ReductionVars, Data.ReductionCopies,
+ Data.ReductionOps);
+ llvm::Value *ReductionsPtr = CGF.Builder.CreateLoad(
+ CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(9)));
+ for (unsigned Cnt = 0, E = Data.ReductionVars.size(); Cnt < E; ++Cnt) {
+ RedCG.emitSharedLValue(CGF, Cnt);
+ RedCG.emitAggregateType(CGF, Cnt);
+ Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem(
+ CGF, S.getLocStart(), ReductionsPtr, RedCG.getSharedLValue(Cnt));
+ Replacement =
+ Address(CGF.EmitScalarConversion(
+ Replacement.getPointer(), CGF.getContext().VoidPtrTy,
+ CGF.getContext().getPointerType(
+ Data.ReductionCopies[Cnt]->getType()),
+ SourceLocation()),
+ Replacement.getAlignment());
+ Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement);
+ Scope.addPrivate(RedCG.getBaseDecl(Cnt),
+ [Replacement]() { return Replacement; });
+ // FIXME: This must removed once the runtime library is fixed.
+ // Emit required threadprivate variables for
+ // initilizer/combiner/finalizer.
+ CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getLocStart(),
+ RedCG, Cnt);
+ }
+ }
(void)Scope.Privatize();
Action.Enter(CGF);
@@ -2763,7 +2880,9 @@ void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) {
}(), S.getLocStart());
}
-void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) {
+void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S,
+ const CodeGenLoopTy &CodeGenLoop,
+ Expr *IncExpr) {
// Emit the loop iteration variable.
auto IVExpr = cast<DeclRefExpr>(S.getIterationVariable());
auto IVDecl = cast<VarDecl>(IVExpr->getDecl());
@@ -2804,10 +2923,17 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) {
// Emit 'then' code.
{
// Emit helper vars inits.
- LValue LB =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getLowerBoundVariable()));
- LValue UB =
- EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getUpperBoundVariable()));
+
+ LValue LB = EmitOMPHelperVar(
+ *this, cast<DeclRefExpr>(
+ (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedLowerBoundVariable()
+ : S.getLowerBoundVariable())));
+ LValue UB = EmitOMPHelperVar(
+ *this, cast<DeclRefExpr>(
+ (isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedUpperBoundVariable()
+ : S.getUpperBoundVariable())));
LValue ST =
EmitOMPHelperVar(*this, cast<DeclRefExpr>(S.getStrideVariable()));
LValue IL =
@@ -2859,15 +2985,25 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) {
auto LoopExit =
getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit"));
// UB = min(UB, GlobalUB);
- EmitIgnoredExpr(S.getEnsureUpperBound());
+ EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedEnsureUpperBound()
+ : S.getEnsureUpperBound());
// IV = LB;
- EmitIgnoredExpr(S.getInit());
+ EmitIgnoredExpr(isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedInit()
+ : S.getInit());
+
+ Expr *Cond = isOpenMPLoopBoundSharingDirective(S.getDirectiveKind())
+ ? S.getCombinedCond()
+ : S.getCond();
+
+ // for distribute alone, codegen
// while (idx <= UB) { BODY; ++idx; }
- EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(),
- S.getInc(),
- [&S, LoopExit](CodeGenFunction &CGF) {
- CGF.EmitOMPLoopBody(S, LoopExit);
- CGF.EmitStopPoint(&S);
+ // when combined with 'for' (e.g. as in 'distribute parallel for')
+ // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; }
+ EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), Cond, IncExpr,
+ [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) {
+ CodeGenLoop(CGF, S, LoopExit);
},
[](CodeGenFunction &) {});
EmitBlock(LoopExit.getBlock());
@@ -2876,9 +3012,11 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) {
} else {
// Emit the outer loop, which requests its work chunk [LB..UB] from
// runtime and runs the inner loop to process it.
- EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope,
- LB.getAddress(), UB.getAddress(), ST.getAddress(),
- IL.getAddress(), Chunk);
+ const OMPLoopArguments LoopArguments = {
+ LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(),
+ Chunk};
+ EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LoopArguments,
+ CodeGenLoop);
}
// Emit final copy of the lastprivate variables if IsLastIter != 0.
@@ -2900,7 +3038,8 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) {
void CodeGenFunction::EmitOMPDistributeDirective(
const OMPDistributeDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S);
+
+ CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
OMPLexicalScope Scope(*this, S, /*AsInlined=*/true);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen,
@@ -3250,7 +3389,7 @@ static void EmitOMPAtomicCaptureExpr(CodeGenFunction &CGF, bool IsSeqCst,
NewVValType = XRValExpr->getType();
auto *ERValExpr = IsXLHSInRHSPart ? RHS : LHS;
auto &&Gen = [&CGF, &NewVVal, UE, ExprRValue, XRValExpr, ERValExpr,
- IsSeqCst, IsPostfixUpdate](RValue XRValue) -> RValue {
+ IsPostfixUpdate](RValue XRValue) -> RValue {
CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue);
CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue);
RValue Res = CGF.EmitAnyExpr(UE);
@@ -3277,7 +3416,7 @@ static void EmitOMPAtomicCaptureExpr(CodeGenFunction &CGF, bool IsSeqCst,
NewVValType = X->getType().getNonReferenceType();
ExprRValue = convertToType(CGF, ExprRValue, E->getType(),
X->getType().getNonReferenceType(), Loc);
- auto &&Gen = [&CGF, &NewVVal, ExprRValue](RValue XRValue) -> RValue {
+ auto &&Gen = [&NewVVal, ExprRValue](RValue XRValue) -> RValue {
NewVVal = XRValue;
return ExprRValue;
};
@@ -3327,6 +3466,7 @@ static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_reduction:
+ case OMPC_task_reduction:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_collapse:
@@ -3404,41 +3544,24 @@ void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_atomic, CodeGen);
}
-std::pair<llvm::Function * /*OutlinedFn*/, llvm::Constant * /*OutlinedFnID*/>
-CodeGenFunction::EmitOMPTargetDirectiveOutlinedFunction(
- CodeGenModule &CGM, const OMPTargetDirective &S, StringRef ParentName,
- bool IsOffloadEntry) {
- llvm::Function *OutlinedFn = nullptr;
- llvm::Constant *OutlinedFnID = nullptr;
- auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- OMPPrivateScope PrivateScope(CGF);
- (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
- CGF.EmitOMPPrivateClause(S, PrivateScope);
- (void)PrivateScope.Privatize();
-
- Action.Enter(CGF);
- CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
- };
- // Emit target region as a standalone region.
- CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
- S, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry, CodeGen);
- return std::make_pair(OutlinedFn, OutlinedFnID);
-}
-
-void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &S) {
+static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S,
+ const RegionCodeGenTy &CodeGen) {
+ assert(isOpenMPTargetExecutionDirective(S.getDirectiveKind()));
+ CodeGenModule &CGM = CGF.CGM;
const CapturedStmt &CS = *cast<CapturedStmt>(S.getAssociatedStmt());
- llvm::SmallVector<llvm::Value *, 16> CapturedVars;
- GenerateOpenMPCapturedVars(CS, CapturedVars);
-
llvm::Function *Fn = nullptr;
llvm::Constant *FnID = nullptr;
- // Check if we have any if clause associated with the directive.
const Expr *IfCond = nullptr;
-
- if (auto *C = S.getSingleClause<OMPIfClause>()) {
- IfCond = C->getCondition();
+ // Check for the at most one if clause associated with the target region.
+ for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
+ if (C->getNameModifier() == OMPD_unknown ||
+ C->getNameModifier() == OMPD_target) {
+ IfCond = C->getCondition();
+ break;
+ }
}
// Check if we have any device clause associated with the directive.
@@ -3453,43 +3576,76 @@ void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &S) {
bool IsOffloadEntry = true;
if (IfCond) {
bool Val;
- if (ConstantFoldsToSimpleInteger(IfCond, Val) && !Val)
+ if (CGF.ConstantFoldsToSimpleInteger(IfCond, Val) && !Val)
IsOffloadEntry = false;
}
if (CGM.getLangOpts().OMPTargetTriples.empty())
IsOffloadEntry = false;
- assert(CurFuncDecl && "No parent declaration for target region!");
+ assert(CGF.CurFuncDecl && "No parent declaration for target region!");
StringRef ParentName;
// In case we have Ctors/Dtors we use the complete type variant to produce
// the mangling of the device outlined kernel.
- if (auto *D = dyn_cast<CXXConstructorDecl>(CurFuncDecl))
+ if (auto *D = dyn_cast<CXXConstructorDecl>(CGF.CurFuncDecl))
ParentName = CGM.getMangledName(GlobalDecl(D, Ctor_Complete));
- else if (auto *D = dyn_cast<CXXDestructorDecl>(CurFuncDecl))
+ else if (auto *D = dyn_cast<CXXDestructorDecl>(CGF.CurFuncDecl))
ParentName = CGM.getMangledName(GlobalDecl(D, Dtor_Complete));
else
ParentName =
- CGM.getMangledName(GlobalDecl(cast<FunctionDecl>(CurFuncDecl)));
+ CGM.getMangledName(GlobalDecl(cast<FunctionDecl>(CGF.CurFuncDecl)));
- std::tie(Fn, FnID) = EmitOMPTargetDirectiveOutlinedFunction(
- CGM, S, ParentName, IsOffloadEntry);
- OMPLexicalScope Scope(*this, S);
- CGM.getOpenMPRuntime().emitTargetCall(*this, S, Fn, FnID, IfCond, Device,
+ // Emit target region as a standalone region.
+ CGM.getOpenMPRuntime().emitTargetOutlinedFunction(S, ParentName, Fn, FnID,
+ IsOffloadEntry, CodeGen);
+ OMPLexicalScope Scope(CGF, S);
+ llvm::SmallVector<llvm::Value *, 16> CapturedVars;
+ CGF.GenerateOpenMPCapturedVars(CS, CapturedVars);
+ CGM.getOpenMPRuntime().emitTargetCall(CGF, S, Fn, FnID, IfCond, Device,
CapturedVars);
}
+static void emitTargetRegion(CodeGenFunction &CGF, const OMPTargetDirective &S,
+ PrePostActionTy &Action) {
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
+ CGF.EmitOMPPrivateClause(S, PrivateScope);
+ (void)PrivateScope.Privatize();
+
+ Action.Enter(CGF);
+ CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+}
+
+void CodeGenFunction::EmitOMPTargetDeviceFunction(CodeGenModule &CGM,
+ StringRef ParentName,
+ const OMPTargetDirective &S) {
+ auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ emitTargetRegion(CGF, S, Action);
+ };
+ llvm::Function *Fn;
+ llvm::Constant *Addr;
+ // Emit target region as a standalone region.
+ CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
+ S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
+ assert(Fn && Addr && "Target device function emission failed.");
+}
+
+void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &S) {
+ auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ emitTargetRegion(CGF, S, Action);
+ };
+ emitCommonOMPTargetDirective(*this, S, CodeGen);
+}
+
static void emitCommonOMPTeamsDirective(CodeGenFunction &CGF,
const OMPExecutableDirective &S,
OpenMPDirectiveKind InnermostKind,
const RegionCodeGenTy &CodeGen) {
- auto CS = cast<CapturedStmt>(S.getAssociatedStmt());
- auto OutlinedFn = CGF.CGM.getOpenMPRuntime().
- emitParallelOrTeamsOutlinedFunction(S,
- *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
+ const CapturedStmt *CS = S.getCapturedStmt(OMPD_teams);
+ auto OutlinedFn = CGF.CGM.getOpenMPRuntime().emitTeamsOutlinedFunction(
+ S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen);
- const OMPTeamsDirective &TD = *dyn_cast<OMPTeamsDirective>(&S);
- const OMPNumTeamsClause *NT = TD.getSingleClause<OMPNumTeamsClause>();
- const OMPThreadLimitClause *TL = TD.getSingleClause<OMPThreadLimitClause>();
+ const OMPNumTeamsClause *NT = S.getSingleClause<OMPNumTeamsClause>();
+ const OMPThreadLimitClause *TL = S.getSingleClause<OMPThreadLimitClause>();
if (NT || TL) {
Expr *NumTeams = (NT) ? NT->getNumTeams() : nullptr;
Expr *ThreadLimit = (TL) ? TL->getThreadLimit() : nullptr;
@@ -3498,7 +3654,7 @@ static void emitCommonOMPTeamsDirective(CodeGenFunction &CGF,
S.getLocStart());
}
- OMPLexicalScope Scope(CGF, S);
+ OMPTeamsScope Scope(CGF, S);
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
CGF.CGM.getOpenMPRuntime().emitTeamsCall(CGF, S, S.getLocStart(), OutlinedFn,
@@ -3511,10 +3667,47 @@ void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &S) {
OMPPrivateScope PrivateScope(CGF);
(void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
CGF.EmitOMPPrivateClause(S, PrivateScope);
+ CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
emitCommonOMPTeamsDirective(*this, S, OMPD_teams, CodeGen);
+ emitPostUpdateForReductionClause(
+ *this, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; });
+}
+
+static void emitTargetTeamsRegion(CodeGenFunction &CGF, PrePostActionTy &Action,
+ const OMPTargetTeamsDirective &S) {
+ auto *CS = S.getCapturedStmt(OMPD_teams);
+ Action.Enter(CGF);
+ auto &&CodeGen = [CS](CodeGenFunction &CGF, PrePostActionTy &) {
+ // TODO: Add support for clauses.
+ CGF.EmitStmt(CS->getCapturedStmt());
+ };
+ emitCommonOMPTeamsDirective(CGF, S, OMPD_teams, CodeGen);
+}
+
+void CodeGenFunction::EmitOMPTargetTeamsDeviceFunction(
+ CodeGenModule &CGM, StringRef ParentName,
+ const OMPTargetTeamsDirective &S) {
+ auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ emitTargetTeamsRegion(CGF, Action, S);
+ };
+ llvm::Function *Fn;
+ llvm::Constant *Addr;
+ // Emit target region as a standalone region.
+ CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
+ S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
+ assert(Fn && Addr && "Target device function emission failed.");
+}
+
+void CodeGenFunction::EmitOMPTargetTeamsDirective(
+ const OMPTargetTeamsDirective &S) {
+ auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ emitTargetTeamsRegion(CGF, Action, S);
+ };
+ emitCommonOMPTargetDirective(*this, S, CodeGen);
}
void CodeGenFunction::EmitOMPCancellationPointDirective(
@@ -3740,9 +3933,48 @@ void CodeGenFunction::EmitOMPTargetExitDataDirective(
CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device);
}
+static void emitTargetParallelRegion(CodeGenFunction &CGF,
+ const OMPTargetParallelDirective &S,
+ PrePostActionTy &Action) {
+ // Get the captured statement associated with the 'parallel' region.
+ auto *CS = S.getCapturedStmt(OMPD_parallel);
+ Action.Enter(CGF);
+ auto &&CodeGen = [&S, CS](CodeGenFunction &CGF, PrePostActionTy &) {
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
+ CGF.EmitOMPPrivateClause(S, PrivateScope);
+ CGF.EmitOMPReductionClauseInit(S, PrivateScope);
+ (void)PrivateScope.Privatize();
+ // TODO: Add support for clauses.
+ CGF.EmitStmt(CS->getCapturedStmt());
+ CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel);
+ };
+ emitCommonOMPParallelDirective(CGF, S, OMPD_parallel, CodeGen,
+ emitEmptyBoundParameters);
+ emitPostUpdateForReductionClause(
+ CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; });
+}
+
+void CodeGenFunction::EmitOMPTargetParallelDeviceFunction(
+ CodeGenModule &CGM, StringRef ParentName,
+ const OMPTargetParallelDirective &S) {
+ auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ emitTargetParallelRegion(CGF, S, Action);
+ };
+ llvm::Function *Fn;
+ llvm::Constant *Addr;
+ // Emit target region as a standalone region.
+ CGM.getOpenMPRuntime().emitTargetOutlinedFunction(
+ S, ParentName, Fn, Addr, /*IsOffloadEntry=*/true, CodeGen);
+ assert(Fn && Addr && "Target device function emission failed.");
+}
+
void CodeGenFunction::EmitOMPTargetParallelDirective(
const OMPTargetParallelDirective &S) {
- // TODO: codegen for target parallel.
+ auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ emitTargetParallelRegion(CGF, S, Action);
+ };
+ emitCommonOMPTargetDirective(*this, S, CodeGen);
}
void CodeGenFunction::EmitOMPTargetParallelForDirective(
@@ -3884,7 +4116,18 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_taskloop,
CodeGen);
};
- EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data);
+ if (Data.Nogroup)
+ EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data);
+ else {
+ CGM.getOpenMPRuntime().emitTaskgroupRegion(
+ *this,
+ [&S, &BodyGen, &TaskGen, &Data](CodeGenFunction &CGF,
+ PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ CGF.EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data);
+ },
+ S.getLocStart());
+ }
}
void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) {
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp
index 1a09830..64b6d0d 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp
@@ -14,7 +14,7 @@
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "ConstantBuilder.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "clang/CodeGen/CGFunctionInfo.h"
@@ -284,6 +284,9 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::Constant *CalleePtr,
if (isa<CXXDestructorDecl>(MD))
CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, CurGD, CallArgs);
+#ifndef NDEBUG
+ unsigned PrefixArgs = CallArgs.size() - 1;
+#endif
// Add the rest of the arguments.
for (const ParmVarDecl *PD : MD->parameters())
EmitDelegateCallArg(CallArgs, PD, SourceLocation());
@@ -292,7 +295,7 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::Constant *CalleePtr,
#ifndef NDEBUG
const CGFunctionInfo &CallFnInfo = CGM.getTypes().arrangeCXXMethodCall(
- CallArgs, FPT, RequiredArgs::forPrototypePlus(FPT, 1, MD));
+ CallArgs, FPT, RequiredArgs::forPrototypePlus(FPT, 1, MD), PrefixArgs);
assert(CallFnInfo.getRegParm() == CurFnInfo->getRegParm() &&
CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() &&
CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention());
@@ -376,12 +379,9 @@ void CodeGenFunction::EmitMustTailThunk(const CXXMethodDecl *MD,
// Apply the standard set of call attributes.
unsigned CallingConv;
- CodeGen::AttributeListType AttributeList;
- CGM.ConstructAttributeList(CalleePtr->getName(),
- *CurFnInfo, MD, AttributeList,
+ llvm::AttributeList Attrs;
+ CGM.ConstructAttributeList(CalleePtr->getName(), *CurFnInfo, MD, Attrs,
CallingConv, /*AttrOnCallSite=*/true);
- llvm::AttributeSet Attrs =
- llvm::AttributeSet::get(getLLVMContext(), AttributeList);
Call->setAttributes(Attrs);
Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
@@ -744,9 +744,10 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
switch (keyFunction->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
- assert((def || CodeGenOpts.OptimizationLevel > 0) &&
- "Shouldn't query vtable linkage without key function or "
- "optimizations");
+ assert((def || CodeGenOpts.OptimizationLevel > 0 ||
+ CodeGenOpts.getDebugInfo() != codegenoptions::NoDebugInfo) &&
+ "Shouldn't query vtable linkage without key function, "
+ "optimizations, or debug info");
if (!def && CodeGenOpts.OptimizationLevel > 0)
return llvm::GlobalVariable::AvailableExternallyLinkage;
@@ -900,6 +901,8 @@ void CodeGenModule::EmitDeferredVTables() {
for (const CXXRecordDecl *RD : DeferredVTables)
if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD))
VTables.GenerateClassData(RD);
+ else if (shouldOpportunisticallyEmitVTables())
+ OpportunisticVTables.push_back(RD);
assert(savedSize == DeferredVTables.size() &&
"deferred extra vtables during vtable emission?");
@@ -942,7 +945,7 @@ bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) {
void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout) {
- if (!getCodeGenOpts().PrepareForLTO)
+ if (!getCodeGenOpts().LTOUnit)
return;
CharUnits PointerWidth =
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h b/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h
index 53a376d..b768eb8 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h
@@ -146,6 +146,25 @@ static inline AlignmentSource getFieldAlignmentSource(AlignmentSource Source) {
return AlignmentSource::Decl;
}
+class LValueBaseInfo {
+ AlignmentSource AlignSource;
+ bool MayAlias;
+
+public:
+ explicit LValueBaseInfo(AlignmentSource Source = AlignmentSource::Type,
+ bool Alias = false)
+ : AlignSource(Source), MayAlias(Alias) {}
+ AlignmentSource getAlignmentSource() const { return AlignSource; }
+ void setAlignmentSource(AlignmentSource Source) { AlignSource = Source; }
+ bool getMayAlias() const { return MayAlias; }
+ void setMayAlias(bool Alias) { MayAlias = Alias; }
+
+ void mergeForCast(const LValueBaseInfo &Info) {
+ setAlignmentSource(Info.getAlignmentSource());
+ setMayAlias(getMayAlias() || Info.getMayAlias());
+ }
+};
+
/// LValue - This represents an lvalue references. Because C/C++ allow
/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
/// bitrange.
@@ -200,7 +219,7 @@ class LValue {
// to make the default bitfield pattern all-zeroes.
bool ImpreciseLifetime : 1;
- unsigned AlignSource : 2;
+ LValueBaseInfo BaseInfo;
// This flag shows if a nontemporal load/stores should be used when accessing
// this lvalue.
@@ -218,7 +237,7 @@ class LValue {
private:
void Initialize(QualType Type, Qualifiers Quals,
- CharUnits Alignment, AlignmentSource AlignSource,
+ CharUnits Alignment, LValueBaseInfo BaseInfo,
llvm::MDNode *TBAAInfo = nullptr) {
assert((!Alignment.isZero() || Type->isIncompleteType()) &&
"initializing l-value with zero alignment!");
@@ -227,7 +246,7 @@ private:
this->Alignment = Alignment.getQuantity();
assert(this->Alignment == Alignment.getQuantity() &&
"Alignment exceeds allowed max!");
- this->AlignSource = unsigned(AlignSource);
+ this->BaseInfo = BaseInfo;
// Initialize Objective-C flags.
this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
@@ -316,12 +335,8 @@ public:
CharUnits getAlignment() const { return CharUnits::fromQuantity(Alignment); }
void setAlignment(CharUnits A) { Alignment = A.getQuantity(); }
- AlignmentSource getAlignmentSource() const {
- return AlignmentSource(AlignSource);
- }
- void setAlignmentSource(AlignmentSource Source) {
- AlignSource = unsigned(Source);
- }
+ LValueBaseInfo getBaseInfo() const { return BaseInfo; }
+ void setBaseInfo(LValueBaseInfo Info) { BaseInfo = Info; }
// simple lvalue
llvm::Value *getPointer() const {
@@ -370,7 +385,7 @@ public:
static LValue MakeAddr(Address address, QualType type,
ASTContext &Context,
- AlignmentSource alignSource,
+ LValueBaseInfo BaseInfo,
llvm::MDNode *TBAAInfo = nullptr) {
Qualifiers qs = type.getQualifiers();
qs.setObjCGCAttr(Context.getObjCGCAttrKind(type));
@@ -379,29 +394,29 @@ public:
R.LVType = Simple;
assert(address.getPointer()->getType()->isPointerTy());
R.V = address.getPointer();
- R.Initialize(type, qs, address.getAlignment(), alignSource, TBAAInfo);
+ R.Initialize(type, qs, address.getAlignment(), BaseInfo, TBAAInfo);
return R;
}
static LValue MakeVectorElt(Address vecAddress, llvm::Value *Idx,
- QualType type, AlignmentSource alignSource) {
+ QualType type, LValueBaseInfo BaseInfo) {
LValue R;
R.LVType = VectorElt;
R.V = vecAddress.getPointer();
R.VectorIdx = Idx;
R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(),
- alignSource);
+ BaseInfo);
return R;
}
static LValue MakeExtVectorElt(Address vecAddress, llvm::Constant *Elts,
- QualType type, AlignmentSource alignSource) {
+ QualType type, LValueBaseInfo BaseInfo) {
LValue R;
R.LVType = ExtVectorElt;
R.V = vecAddress.getPointer();
R.VectorElts = Elts;
R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(),
- alignSource);
+ BaseInfo);
return R;
}
@@ -414,12 +429,12 @@ public:
static LValue MakeBitfield(Address Addr,
const CGBitFieldInfo &Info,
QualType type,
- AlignmentSource alignSource) {
+ LValueBaseInfo BaseInfo) {
LValue R;
R.LVType = BitField;
R.V = Addr.getPointer();
R.BitFieldInfo = &Info;
- R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), alignSource);
+ R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), BaseInfo);
return R;
}
@@ -428,7 +443,7 @@ public:
R.LVType = GlobalReg;
R.V = Reg.getPointer();
R.Initialize(type, type.getQualifiers(), Reg.getAlignment(),
- AlignmentSource::Decl);
+ LValueBaseInfo(AlignmentSource::Decl, false));
return R;
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp
index 166f44f..0735a9c 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenABITypes.cpp
@@ -64,3 +64,19 @@ CodeGen::arrangeFreeFunctionCall(CodeGenModule &CGM,
returnType, /*IsInstanceMethod=*/false, /*IsChainCall=*/false, argTypes,
info, {}, args);
}
+
+llvm::FunctionType *
+CodeGen::convertFreeFunctionType(CodeGenModule &CGM, const FunctionDecl *FD) {
+ assert(FD != nullptr && "Expected a non-null function declaration!");
+ llvm::Type *T = CGM.getTypes().ConvertFunctionType(FD->getType(), FD);
+
+ if (auto FT = dyn_cast<llvm::FunctionType>(T))
+ return FT;
+
+ return nullptr;
+}
+
+llvm::Type *
+CodeGen::convertTypeForMemory(CodeGenModule &CGM, QualType T) {
+ return CGM.getTypes().ConvertTypeForMem(T);
+}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp
index 5f74141..4f03de5 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp
@@ -7,7 +7,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/CodeGen/CodeGenAction.h"
+#include "CodeGenModule.h"
#include "CoverageMappingGen.h"
+#include "MacroPPCallbacks.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
@@ -16,15 +19,16 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/BackendUtil.h"
-#include "clang/CodeGen/CodeGenAction.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
@@ -35,12 +39,16 @@
#include "llvm/Support/Timer.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Transforms/IPO/Internalize.h"
+
#include <memory>
using namespace clang;
using namespace llvm;
namespace clang {
class BackendConsumer : public ASTConsumer {
+ using LinkModule = CodeGenAction::LinkModule;
+
virtual void anchor();
DiagnosticsEngine &Diags;
BackendAction Action;
@@ -61,43 +69,39 @@ namespace clang {
std::unique_ptr<CodeGenerator> Gen;
- SmallVector<std::pair<unsigned, std::unique_ptr<llvm::Module>>, 4>
- LinkModules;
+ SmallVector<LinkModule, 4> LinkModules;
// This is here so that the diagnostic printer knows the module a diagnostic
// refers to.
llvm::Module *CurLinkModule = nullptr;
public:
- BackendConsumer(
- BackendAction Action, DiagnosticsEngine &Diags,
- const HeaderSearchOptions &HeaderSearchOpts,
- const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts,
- const TargetOptions &TargetOpts, const LangOptions &LangOpts,
- bool TimePasses, const std::string &InFile,
- const SmallVectorImpl<std::pair<unsigned, llvm::Module *>> &LinkModules,
- std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C,
- CoverageSourceInfo *CoverageInfo = nullptr)
+ BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
+ const HeaderSearchOptions &HeaderSearchOpts,
+ const PreprocessorOptions &PPOpts,
+ const CodeGenOptions &CodeGenOpts,
+ const TargetOptions &TargetOpts,
+ const LangOptions &LangOpts, bool TimePasses,
+ const std::string &InFile,
+ SmallVector<LinkModule, 4> LinkModules,
+ std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C,
+ CoverageSourceInfo *CoverageInfo = nullptr)
: Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts),
AsmOutStream(std::move(OS)), Context(nullptr),
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
LLVMIRGenerationRefCount(0),
Gen(CreateLLVMCodeGen(Diags, InFile, HeaderSearchOpts, PPOpts,
- CodeGenOpts, C, CoverageInfo)) {
+ CodeGenOpts, C, CoverageInfo)),
+ LinkModules(std::move(LinkModules)) {
llvm::TimePassesIsEnabled = TimePasses;
- for (auto &I : LinkModules)
- this->LinkModules.push_back(
- std::make_pair(I.first, std::unique_ptr<llvm::Module>(I.second)));
}
llvm::Module *getModule() const { return Gen->GetModule(); }
std::unique_ptr<llvm::Module> takeModule() {
return std::unique_ptr<llvm::Module>(Gen->ReleaseModule());
}
- void releaseLinkModules() {
- for (auto &I : LinkModules)
- I.second.release();
- }
+
+ CodeGenerator *getCodeGenerator() { return Gen.get(); }
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
Gen->HandleCXXStaticMemberVarInstantiation(VD);
@@ -159,6 +163,35 @@ namespace clang {
HandleTopLevelDecl(D);
}
+ // Links each entry in LinkModules into our module. Returns true on error.
+ bool LinkInModules() {
+ for (auto &LM : LinkModules) {
+ if (LM.PropagateAttrs)
+ for (Function &F : *LM.Module)
+ Gen->CGM().AddDefaultFnAttrs(F);
+
+ CurLinkModule = LM.Module.get();
+
+ bool Err;
+ if (LM.Internalize) {
+ Err = Linker::linkModules(
+ *getModule(), std::move(LM.Module), LM.LinkFlags,
+ [](llvm::Module &M, const llvm::StringSet<> &GVS) {
+ internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) {
+ return !GV.hasName() || (GVS.count(GV.getName()) == 0);
+ });
+ });
+ } else {
+ Err = Linker::linkModules(*getModule(), std::move(LM.Module),
+ LM.LinkFlags);
+ }
+
+ if (Err)
+ return true;
+ }
+ return false; // success
+ }
+
void HandleTranslationUnit(ASTContext &C) override {
{
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
@@ -195,7 +228,10 @@ namespace clang {
Ctx.getDiagnosticHandler();
void *OldDiagnosticContext = Ctx.getDiagnosticContext();
Ctx.setDiagnosticHandler(DiagnosticHandler, this);
- Ctx.setDiagnosticHotnessRequested(CodeGenOpts.DiagnosticsWithHotness);
+ Ctx.setDiagnosticsHotnessRequested(CodeGenOpts.DiagnosticsWithHotness);
+ if (CodeGenOpts.DiagnosticsHotnessThreshold != 0)
+ Ctx.setDiagnosticsHotnessThreshold(
+ CodeGenOpts.DiagnosticsHotnessThreshold);
std::unique_ptr<llvm::tool_output_file> OptRecordFile;
if (!CodeGenOpts.OptRecordFile.empty()) {
@@ -213,16 +249,12 @@ namespace clang {
llvm::make_unique<yaml::Output>(OptRecordFile->os()));
if (CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone)
- Ctx.setDiagnosticHotnessRequested(true);
+ Ctx.setDiagnosticsHotnessRequested(true);
}
- // Link LinkModule into this module if present, preserving its validity.
- for (auto &I : LinkModules) {
- unsigned LinkFlags = I.first;
- CurLinkModule = I.second.get();
- if (Linker::linkModules(*getModule(), std::move(I.second), LinkFlags))
- return;
- }
+ // Link each LinkModule into our module.
+ if (LinkInModules())
+ return;
EmbedBitcode(getModule(), CodeGenOpts, llvm::MemoryBufferRef());
@@ -275,7 +307,7 @@ namespace clang {
/// Get the best possible source location to represent a diagnostic that
/// may have associated debug info.
const FullSourceLoc
- getBestLocationFromDebugLoc(const llvm::DiagnosticInfoWithDebugLocBase &D,
+ getBestLocationFromDebugLoc(const llvm::DiagnosticInfoWithLocationBase &D,
bool &BadDebugInfo, StringRef &Filename,
unsigned &Line, unsigned &Column) const;
@@ -298,9 +330,8 @@ namespace clang {
/// them.
void EmitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &D,
unsigned DiagID);
- void OptimizationRemarkHandler(const llvm::OptimizationRemark &D);
- void OptimizationRemarkHandler(const llvm::OptimizationRemarkMissed &D);
- void OptimizationRemarkHandler(const llvm::OptimizationRemarkAnalysis &D);
+ void
+ OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationBase &D);
void OptimizationRemarkHandler(
const llvm::OptimizationRemarkAnalysisFPCommute &D);
void OptimizationRemarkHandler(
@@ -308,7 +339,7 @@ namespace clang {
void OptimizationFailureHandler(
const llvm::DiagnosticInfoOptimizationFailure &D);
};
-
+
void BackendConsumer::anchor() {}
}
@@ -377,7 +408,7 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
// code.
if (LocCookie.isValid()) {
Diags.Report(LocCookie, DiagID).AddString(Message);
-
+
if (D.getLoc().isValid()) {
DiagnosticBuilder B = Diags.Report(Loc, diag::note_fe_inline_asm_here);
// Convert the SMDiagnostic ranges into SourceRange and attach them
@@ -390,7 +421,7 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
}
return;
}
-
+
// Otherwise, report the backend issue as occurring in the generated .s file.
// If Loc is invalid, we still need to report the issue, it just gets no
// location info.
@@ -477,8 +508,8 @@ BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) {
}
const FullSourceLoc BackendConsumer::getBestLocationFromDebugLoc(
- const llvm::DiagnosticInfoWithDebugLocBase &D, bool &BadDebugInfo, StringRef &Filename,
- unsigned &Line, unsigned &Column) const {
+ const llvm::DiagnosticInfoWithLocationBase &D, bool &BadDebugInfo,
+ StringRef &Filename, unsigned &Line, unsigned &Column) const {
SourceManager &SourceMgr = Context->getSourceManager();
FileManager &FileMgr = SourceMgr.getFileManager();
SourceLocation DILoc;
@@ -520,9 +551,9 @@ void BackendConsumer::UnsupportedDiagHandler(
StringRef Filename;
unsigned Line, Column;
- bool BadDebugInfo;
- FullSourceLoc Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename,
- Line, Column);
+ bool BadDebugInfo = false;
+ FullSourceLoc Loc =
+ getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
Diags.Report(Loc, diag::err_fe_backend_unsupported) << D.getMessage().str();
@@ -544,8 +575,8 @@ void BackendConsumer::EmitOptimizationMessage(
StringRef Filename;
unsigned Line, Column;
bool BadDebugInfo = false;
- FullSourceLoc Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename,
- Line, Column);
+ FullSourceLoc Loc =
+ getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
std::string Msg;
raw_string_ostream MsgStream(Msg);
@@ -568,36 +599,34 @@ void BackendConsumer::EmitOptimizationMessage(
}
void BackendConsumer::OptimizationRemarkHandler(
- const llvm::OptimizationRemark &D) {
- // Optimization remarks are active only if the -Rpass flag has a regular
- // expression that matches the name of the pass name in \p D.
- if (CodeGenOpts.OptimizationRemarkPattern &&
- CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName()))
- EmitOptimizationMessage(D, diag::remark_fe_backend_optimization_remark);
-}
-
-void BackendConsumer::OptimizationRemarkHandler(
- const llvm::OptimizationRemarkMissed &D) {
- // Missed optimization remarks are active only if the -Rpass-missed
- // flag has a regular expression that matches the name of the pass
- // name in \p D.
- if (CodeGenOpts.OptimizationRemarkMissedPattern &&
- CodeGenOpts.OptimizationRemarkMissedPattern->match(D.getPassName()))
- EmitOptimizationMessage(D,
- diag::remark_fe_backend_optimization_remark_missed);
-}
-
-void BackendConsumer::OptimizationRemarkHandler(
- const llvm::OptimizationRemarkAnalysis &D) {
- // Optimization analysis remarks are active if the pass name is set to
- // llvm::DiagnosticInfo::AlwasyPrint or if the -Rpass-analysis flag has a
- // regular expression that matches the name of the pass name in \p D.
-
- if (D.shouldAlwaysPrint() ||
- (CodeGenOpts.OptimizationRemarkAnalysisPattern &&
- CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName())))
- EmitOptimizationMessage(
- D, diag::remark_fe_backend_optimization_remark_analysis);
+ const llvm::DiagnosticInfoOptimizationBase &D) {
+ if (D.isPassed()) {
+ // Optimization remarks are active only if the -Rpass flag has a regular
+ // expression that matches the name of the pass name in \p D.
+ if (CodeGenOpts.OptimizationRemarkPattern &&
+ CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName()))
+ EmitOptimizationMessage(D, diag::remark_fe_backend_optimization_remark);
+ } else if (D.isMissed()) {
+ // Missed optimization remarks are active only if the -Rpass-missed
+ // flag has a regular expression that matches the name of the pass
+ // name in \p D.
+ if (CodeGenOpts.OptimizationRemarkMissedPattern &&
+ CodeGenOpts.OptimizationRemarkMissedPattern->match(D.getPassName()))
+ EmitOptimizationMessage(
+ D, diag::remark_fe_backend_optimization_remark_missed);
+ } else {
+ assert(D.isAnalysis() && "Unknown remark type");
+
+ bool ShouldAlwaysPrint = false;
+ if (auto *ORA = dyn_cast<llvm::OptimizationRemarkAnalysis>(&D))
+ ShouldAlwaysPrint = ORA->shouldAlwaysPrint();
+
+ if (ShouldAlwaysPrint ||
+ (CodeGenOpts.OptimizationRemarkAnalysisPattern &&
+ CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName())))
+ EmitOptimizationMessage(
+ D, diag::remark_fe_backend_optimization_remark_analysis);
+ }
}
void BackendConsumer::OptimizationRemarkHandler(
@@ -680,6 +709,21 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
// handler. There is no generic way of emitting them.
OptimizationRemarkHandler(cast<OptimizationRemarkAnalysisAliasing>(DI));
return;
+ case llvm::DK_MachineOptimizationRemark:
+ // Optimization remarks are always handled completely by this
+ // handler. There is no generic way of emitting them.
+ OptimizationRemarkHandler(cast<MachineOptimizationRemark>(DI));
+ return;
+ case llvm::DK_MachineOptimizationRemarkMissed:
+ // Optimization remarks are always handled completely by this
+ // handler. There is no generic way of emitting them.
+ OptimizationRemarkHandler(cast<MachineOptimizationRemarkMissed>(DI));
+ return;
+ case llvm::DK_MachineOptimizationRemarkAnalysis:
+ // Optimization remarks are always handled completely by this
+ // handler. There is no generic way of emitting them.
+ OptimizationRemarkHandler(cast<MachineOptimizationRemarkAnalysis>(DI));
+ return;
case llvm::DK_OptimizationFailure:
// Optimization failures are always handled completely by this
// handler.
@@ -729,10 +773,6 @@ void CodeGenAction::EndSourceFileAction() {
if (!getCompilerInstance().hasASTConsumer())
return;
- // Take back ownership of link modules we passed to consumer.
- if (!LinkModules.empty())
- BEConsumer->releaseLinkModules();
-
// Steal the module from the consumer.
TheModule = BEConsumer->takeModule();
}
@@ -775,13 +815,12 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
// Load bitcode modules to link with, if we need to.
if (LinkModules.empty())
- for (auto &I : CI.getCodeGenOpts().LinkBitcodeFiles) {
- const std::string &LinkBCFile = I.second;
-
- auto BCBuf = CI.getFileManager().getBufferForFile(LinkBCFile);
+ for (const CodeGenOptions::BitcodeFileToLink &F :
+ CI.getCodeGenOpts().LinkBitcodeFiles) {
+ auto BCBuf = CI.getFileManager().getBufferForFile(F.Filename);
if (!BCBuf) {
CI.getDiagnostics().Report(diag::err_cannot_open_file)
- << LinkBCFile << BCBuf.getError().message();
+ << F.Filename << BCBuf.getError().message();
LinkModules.clear();
return nullptr;
}
@@ -791,12 +830,13 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
if (!ModuleOrErr) {
handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
CI.getDiagnostics().Report(diag::err_cannot_open_file)
- << LinkBCFile << EIB.message();
+ << F.Filename << EIB.message();
});
LinkModules.clear();
return nullptr;
}
- addLinkModule(ModuleOrErr.get().release(), I.first);
+ LinkModules.push_back({std::move(ModuleOrErr.get()), F.PropagateAttrs,
+ F.Internalize, F.LinkFlags});
}
CoverageSourceInfo *CoverageInfo = nullptr;
@@ -810,9 +850,20 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
- CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, InFile, LinkModules,
- std::move(OS), *VMContext, CoverageInfo));
+ CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, InFile,
+ std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo));
BEConsumer = Result.get();
+
+ // Enable generating macro debug info only when debug info is not disabled and
+ // also macro debug info is enabled.
+ if (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo &&
+ CI.getCodeGenOpts().MacroDebugInfo) {
+ std::unique_ptr<PPCallbacks> Callbacks =
+ llvm::make_unique<MacroPPCallbacks>(BEConsumer->getCodeGenerator(),
+ CI.getPreprocessor());
+ CI.getPreprocessor().addPPCallbacks(std::move(Callbacks));
+ }
+
return std::move(Result);
}
@@ -838,9 +889,65 @@ static void BitcodeInlineAsmDiagHandler(const llvm::SMDiagnostic &SM,
Diags->Report(DiagID).AddString("cannot compile inline asm");
}
+std::unique_ptr<llvm::Module> CodeGenAction::loadModule(MemoryBufferRef MBRef) {
+ CompilerInstance &CI = getCompilerInstance();
+ SourceManager &SM = CI.getSourceManager();
+
+ // For ThinLTO backend invocations, ensure that the context
+ // merges types based on ODR identifiers. We also need to read
+ // the correct module out of a multi-module bitcode file.
+ if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty()) {
+ VMContext->enableDebugTypeODRUniquing();
+
+ auto DiagErrors = [&](Error E) -> std::unique_ptr<llvm::Module> {
+ unsigned DiagID =
+ CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
+ handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
+ CI.getDiagnostics().Report(DiagID) << EIB.message();
+ });
+ return {};
+ };
+
+ Expected<llvm::BitcodeModule> BMOrErr = FindThinLTOModule(MBRef);
+ if (!BMOrErr)
+ return DiagErrors(BMOrErr.takeError());
+
+ Expected<std::unique_ptr<llvm::Module>> MOrErr =
+ BMOrErr->parseModule(*VMContext);
+ if (!MOrErr)
+ return DiagErrors(MOrErr.takeError());
+ return std::move(*MOrErr);
+ }
+
+ llvm::SMDiagnostic Err;
+ if (std::unique_ptr<llvm::Module> M = parseIR(MBRef, Err, *VMContext))
+ return M;
+
+ // Translate from the diagnostic info to the SourceManager location if
+ // available.
+ // TODO: Unify this with ConvertBackendLocation()
+ SourceLocation Loc;
+ if (Err.getLineNo() > 0) {
+ assert(Err.getColumnNo() >= 0);
+ Loc = SM.translateFileLineCol(SM.getFileEntryForID(SM.getMainFileID()),
+ Err.getLineNo(), Err.getColumnNo() + 1);
+ }
+
+ // Strip off a leading diagnostic code if there is one.
+ StringRef Msg = Err.getMessage();
+ if (Msg.startswith("error: "))
+ Msg = Msg.substr(7);
+
+ unsigned DiagID =
+ CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
+
+ CI.getDiagnostics().Report(Loc, DiagID) << Msg;
+ return {};
+}
+
void CodeGenAction::ExecuteAction() {
// If this is an IR file, we have to treat it specially.
- if (getCurrentFileKind() == IK_LLVM_IR) {
+ if (getCurrentFileKind().getLanguage() == InputKind::LLVM_IR) {
BackendAction BA = static_cast<BackendAction>(Act);
CompilerInstance &CI = getCompilerInstance();
std::unique_ptr<raw_pwrite_stream> OS =
@@ -855,35 +962,10 @@ void CodeGenAction::ExecuteAction() {
if (Invalid)
return;
- // For ThinLTO backend invocations, ensure that the context
- // merges types based on ODR identifiers.
- if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty())
- VMContext->enableDebugTypeODRUniquing();
-
- llvm::SMDiagnostic Err;
- TheModule = parseIR(MainFile->getMemBufferRef(), Err, *VMContext);
- if (!TheModule) {
- // Translate from the diagnostic info to the SourceManager location if
- // available.
- // TODO: Unify this with ConvertBackendLocation()
- SourceLocation Loc;
- if (Err.getLineNo() > 0) {
- assert(Err.getColumnNo() >= 0);
- Loc = SM.translateFileLineCol(SM.getFileEntryForID(FID),
- Err.getLineNo(), Err.getColumnNo() + 1);
- }
-
- // Strip off a leading diagnostic code if there is one.
- StringRef Msg = Err.getMessage();
- if (Msg.startswith("error: "))
- Msg = Msg.substr(7);
-
- unsigned DiagID =
- CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
-
- CI.getDiagnostics().Report(Loc, DiagID) << Msg;
+ TheModule = loadModule(*MainFile);
+ if (!TheModule)
return;
- }
+
const TargetOptions &TargetOpts = CI.getTargetOpts();
if (TheModule->getTargetTriple() != TargetOpts.Triple) {
CI.getDiagnostics().Report(SourceLocation(),
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp
index e142a21..c23b25e 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -22,6 +22,7 @@
#include "CodeGenPGO.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
@@ -45,15 +46,15 @@ static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts,
if (CGOpts.DisableLifetimeMarkers)
return false;
- // Asan uses markers for use-after-scope checks.
- if (CGOpts.SanitizeAddressUseAfterScope)
- return true;
-
// Disable lifetime markers in msan builds.
// FIXME: Remove this when msan works with lifetime markers.
if (LangOpts.Sanitize.has(SanitizerKind::Memory))
return false;
+ // Asan uses markers for use-after-scope checks.
+ if (CGOpts.SanitizeAddressUseAfterScope)
+ return true;
+
// For now, only in optimized builds.
return CGOpts.OptimizationLevel != 0;
}
@@ -117,25 +118,27 @@ CodeGenFunction::~CodeGenFunction() {
}
CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T,
- AlignmentSource *Source) {
- return getNaturalTypeAlignment(T->getPointeeType(), Source,
+ LValueBaseInfo *BaseInfo) {
+ return getNaturalTypeAlignment(T->getPointeeType(), BaseInfo,
/*forPointee*/ true);
}
CharUnits CodeGenFunction::getNaturalTypeAlignment(QualType T,
- AlignmentSource *Source,
+ LValueBaseInfo *BaseInfo,
bool forPointeeType) {
// Honor alignment typedef attributes even on incomplete types.
// We also honor them straight for C++ class types, even as pointees;
// there's an expressivity gap here.
if (auto TT = T->getAs<TypedefType>()) {
if (auto Align = TT->getDecl()->getMaxAlignment()) {
- if (Source) *Source = AlignmentSource::AttributedType;
+ if (BaseInfo)
+ *BaseInfo = LValueBaseInfo(AlignmentSource::AttributedType, false);
return getContext().toCharUnitsFromBits(Align);
}
}
- if (Source) *Source = AlignmentSource::Type;
+ if (BaseInfo)
+ *BaseInfo = LValueBaseInfo(AlignmentSource::Type, false);
CharUnits Alignment;
if (T->isIncompleteType()) {
@@ -149,6 +152,8 @@ CharUnits CodeGenFunction::getNaturalTypeAlignment(QualType T,
Alignment = CGM.getClassPointerAlignment(RD);
} else {
Alignment = getContext().getTypeAlignInChars(T);
+ if (T.getQualifiers().hasUnaligned())
+ Alignment = CharUnits::One();
}
// Cap to the global maximum type alignment unless the alignment
@@ -163,9 +168,9 @@ CharUnits CodeGenFunction::getNaturalTypeAlignment(QualType T,
}
LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) {
- AlignmentSource AlignSource;
- CharUnits Alignment = getNaturalTypeAlignment(T, &AlignSource);
- return LValue::MakeAddr(Address(V, Alignment), T, getContext(), AlignSource,
+ LValueBaseInfo BaseInfo;
+ CharUnits Alignment = getNaturalTypeAlignment(T, &BaseInfo);
+ return LValue::MakeAddr(Address(V, Alignment), T, getContext(), BaseInfo,
CGM.getTBAAInfo(T));
}
@@ -173,9 +178,9 @@ LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) {
/// construct an l-value with the natural pointee alignment of T.
LValue
CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T) {
- AlignmentSource AlignSource;
- CharUnits Align = getNaturalTypeAlignment(T, &AlignSource, /*pointee*/ true);
- return MakeAddrLValue(Address(V, Align), T, AlignSource);
+ LValueBaseInfo BaseInfo;
+ CharUnits Align = getNaturalTypeAlignment(T, &BaseInfo, /*pointee*/ true);
+ return MakeAddrLValue(Address(V, Align), T, BaseInfo);
}
@@ -200,7 +205,8 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
llvm_unreachable("non-canonical or dependent type in IR-generation");
case Type::Auto:
- llvm_unreachable("undeduced auto type in IR-generation");
+ case Type::DeducedTemplateSpecialization:
+ llvm_unreachable("undeduced type in IR-generation");
// Various scalar types.
case Type::Builtin:
@@ -343,7 +349,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
// Emit debug descriptor for function end.
if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitFunctionEnd(Builder);
+ DI->EmitFunctionEnd(Builder, CurFn);
// Reset the debug location to that of the simple 'return' expression, if any
// rather than that of the end of the function's scope '}'.
@@ -607,11 +613,6 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
argBaseTypeNames.push_back(llvm::MDString::get(Context, baseTypeName));
- // Get argument type qualifiers:
- if (ty.isConstQualified())
- typeQuals = "const";
- if (ty.isVolatileQualified())
- typeQuals += typeQuals.empty() ? "volatile" : " volatile";
if (isPipe)
typeQuals = "pipe";
}
@@ -660,34 +661,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));
}
}
@@ -707,6 +716,11 @@ static bool endsWithReturn(const Decl* F) {
return false;
}
+static void markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn) {
+ Fn->addFnAttr("sanitize_thread_no_checking_at_run_time");
+ Fn->removeFnAttr(llvm::Attribute::SanitizeThread);
+}
+
void CodeGenFunction::StartFunction(GlobalDecl GD,
QualType RetTy,
llvm::Function *Fn,
@@ -750,16 +764,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
Fn->addFnAttr(llvm::Attribute::SafeStack);
// Ignore TSan memory acesses from within ObjC/ObjC++ dealloc, initialize,
- // .cxx_destruct and all of their calees at run time.
+ // .cxx_destruct, __destroy_helper_block_ and all of their calees at run time.
if (SanOpts.has(SanitizerKind::Thread)) {
if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
IdentifierInfo *II = OMD->getSelector().getIdentifierInfoForSlot(0);
if (OMD->getMethodFamily() == OMF_dealloc ||
OMD->getMethodFamily() == OMF_initialize ||
(OMD->getSelector().isUnarySelector() && II->isStr(".cxx_destruct"))) {
- Fn->addFnAttr("sanitize_thread_no_checking_at_run_time");
- Fn->removeFnAttr(llvm::Attribute::SanitizeThread);
+ markAsIgnoreThreadCheckingAtRuntime(Fn);
}
+ } else if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ IdentifierInfo *II = FD->getIdentifier();
+ if (II && II->isStr("__destroy_helper_block_"))
+ markAsIgnoreThreadCheckingAtRuntime(Fn);
}
}
@@ -770,10 +787,15 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
Fn->addFnAttr("function-instrument", "xray-always");
if (XRayAttr->neverXRayInstrument())
Fn->addFnAttr("function-instrument", "xray-never");
+ if (const auto *LogArgs = D->getAttr<XRayLogArgsAttr>()) {
+ Fn->addFnAttr("xray-log-args",
+ llvm::utostr(LogArgs->getArgumentCount()));
+ }
} else {
- Fn->addFnAttr(
- "xray-instruction-threshold",
- llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold));
+ if (!CGM.imbueXRayAttrs(Fn, Loc))
+ Fn->addFnAttr(
+ "xray-instruction-threshold",
+ llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold));
}
}
@@ -807,6 +829,18 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
}
}
+ // If we're checking nullability, we need to know whether we can check the
+ // return value. Initialize the flag to 'true' and refine it in EmitParmDecl.
+ if (SanOpts.has(SanitizerKind::NullabilityReturn)) {
+ auto Nullability = FnRetTy->getNullability(getContext());
+ if (Nullability && *Nullability == NullabilityKind::NonNull) {
+ if (!(SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
+ CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>()))
+ RetValNullabilityPrecondition =
+ llvm::ConstantInt::getTrue(getLLVMContext());
+ }
+ }
+
// If we're in C++ mode and the function name is "main", it is guaranteed
// to be norecurse by the standard (3.6.1.3 "The function main shall not be
// used within a program").
@@ -827,6 +861,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
Builder.SetInsertPoint(EntryBB);
+ // If we're checking the return value, allocate space for a pointer to a
+ // precise source location of the checked return statement.
+ if (requiresReturnValueCheck()) {
+ ReturnLocation = CreateDefaultAlignTempAlloca(Int8PtrTy, "return.sloc.ptr");
+ InitTempAlloca(ReturnLocation, llvm::ConstantPointerNull::get(Int8PtrTy));
+ }
+
// Emit subprogram debug descriptor.
if (CGDebugInfo *DI = getDebugInfo()) {
// Reconstruct the type from the argument list so that implicit parameters,
@@ -851,8 +892,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
// inlining, we just add an attribute to insert a mcount call in backend.
// The attribute "counting-function" is set to mcount function name which is
// architecture dependent.
- if (CGM.getCodeGenOpts().InstrumentForProfiling)
- Fn->addFnAttr("counting-function", getTarget().getMCountName());
+ if (CGM.getCodeGenOpts().InstrumentForProfiling) {
+ if (CGM.getCodeGenOpts().CallFEntry)
+ Fn->addFnAttr("fentry-call", "true");
+ else {
+ if (!CurFuncDecl || !CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
+ Fn->addFnAttr("counting-function", getTarget().getMCountName());
+ }
+ }
if (RetTy->isVoidType()) {
// Void type; nothing to return.
@@ -935,6 +982,27 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
// fast register allocator would be happier...
CXXThisValue = CXXABIThisValue;
}
+
+ // Check the 'this' pointer once per function, if it's available.
+ if (CXXABIThisValue) {
+ SanitizerSet SkippedChecks;
+ SkippedChecks.set(SanitizerKind::ObjectSize, true);
+ QualType ThisTy = MD->getThisType(getContext());
+
+ // If this is the call operator of a lambda with no capture-default, it
+ // may have a static invoker function, which may call this operator with
+ // a null 'this' pointer.
+ if (isLambdaCallOperator(MD) &&
+ cast<CXXRecordDecl>(MD->getParent())->getLambdaCaptureDefault() ==
+ LCD_None)
+ SkippedChecks.set(SanitizerKind::Null, true);
+
+ EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall
+ : TCK_MemberCall,
+ Loc, CXXABIThisValue, ThisTy,
+ getContext().getTypeAlignInChars(ThisTy->getPointeeType()),
+ SkippedChecks);
+ }
}
// If any of the arguments have a variably modified type, make sure to
@@ -1036,10 +1104,9 @@ QualType CodeGenFunction::BuildFunctionArgList(GlobalDecl GD,
if (!Param->hasAttr<PassObjectSizeAttr>())
continue;
- IdentifierInfo *NoID = nullptr;
auto *Implicit = ImplicitParamDecl::Create(
- getContext(), Param->getDeclContext(), Param->getLocation(), NoID,
- getContext().getSizeType());
+ getContext(), Param->getDeclContext(), Param->getLocation(),
+ /*Id=*/nullptr, getContext().getSizeType(), ImplicitParamDecl::Other);
SizeArguments[Param] = Implicit;
Args.push_back(Implicit);
}
@@ -1076,8 +1143,13 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
if (FD->hasAttr<NoDebugAttr>())
DebugInfo = nullptr; // disable debug info indefinitely for this function
+ // The function might not have a body if we're generating thunks for a
+ // function declaration.
SourceRange BodyRange;
- if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
+ if (Stmt *Body = FD->getBody())
+ BodyRange = Body->getSourceRange();
+ else
+ BodyRange = FD->getLocation();
CurEHLocation = BodyRange.getEnd();
// Use the location of the start of the function to determine where
@@ -1891,6 +1963,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::Typedef:
case Type::Decltype:
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
// Stop walking: nothing to do.
return;
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h
index 5861340..753dd92 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h
@@ -115,9 +115,12 @@ enum TypeEvaluationKind {
SANITIZER_CHECK(MissingReturn, missing_return, 0) \
SANITIZER_CHECK(MulOverflow, mul_overflow, 0) \
SANITIZER_CHECK(NegateOverflow, negate_overflow, 0) \
+ SANITIZER_CHECK(NullabilityArg, nullability_arg, 0) \
+ SANITIZER_CHECK(NullabilityReturn, nullability_return, 1) \
SANITIZER_CHECK(NonnullArg, nonnull_arg, 0) \
- SANITIZER_CHECK(NonnullReturn, nonnull_return, 0) \
+ SANITIZER_CHECK(NonnullReturn, nonnull_return, 1) \
SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0) \
+ SANITIZER_CHECK(PointerOverflow, pointer_overflow, 0) \
SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0) \
SANITIZER_CHECK(SubOverflow, sub_overflow, 0) \
SANITIZER_CHECK(TypeMismatch, type_mismatch, 1) \
@@ -173,6 +176,25 @@ public:
// because of jumps.
VarBypassDetector Bypasses;
+ // CodeGen lambda for loops and support for ordered clause
+ typedef llvm::function_ref<void(CodeGenFunction &, const OMPLoopDirective &,
+ JumpDest)>
+ CodeGenLoopTy;
+ typedef llvm::function_ref<void(CodeGenFunction &, SourceLocation,
+ const unsigned, const bool)>
+ CodeGenOrderedTy;
+
+ // Codegen lambda for loop bounds in worksharing loop constructs
+ typedef llvm::function_ref<std::pair<LValue, LValue>(
+ CodeGenFunction &, const OMPExecutableDirective &S)>
+ CodeGenLoopBoundsTy;
+
+ // Codegen lambda for loop bounds in dispatch-based loop implementation
+ typedef llvm::function_ref<std::pair<llvm::Value *, llvm::Value *>(
+ CodeGenFunction &, const OMPExecutableDirective &S, Address LB,
+ Address UB)>
+ CodeGenDispatchBoundsTy;
+
/// \brief CGBuilder insert helper. This function is called after an
/// instruction is created using Builder.
void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
@@ -212,6 +234,13 @@ public:
/// value. This is invalid iff the function has no return value.
Address ReturnValue;
+ /// Return true if a label was seen in the current scope.
+ bool hasLabelBeenSeenInCurrentScope() const {
+ if (CurLexicalScope)
+ return CurLexicalScope->hasLabels();
+ return !LabelMap.empty();
+ }
+
/// AllocaInsertPoint - This is an instruction in the entry block before which
/// we prefer to insert allocas.
llvm::AssertingVH<llvm::Instruction> AllocaInsertPt;
@@ -298,6 +327,31 @@ public:
~CGCapturedStmtRAII() { CGF.CapturedStmtInfo = PrevCapturedStmtInfo; }
};
+ /// An abstract representation of regular/ObjC call/message targets.
+ class AbstractCallee {
+ /// The function declaration of the callee.
+ const Decl *CalleeDecl;
+
+ public:
+ AbstractCallee() : CalleeDecl(nullptr) {}
+ AbstractCallee(const FunctionDecl *FD) : CalleeDecl(FD) {}
+ AbstractCallee(const ObjCMethodDecl *OMD) : CalleeDecl(OMD) {}
+ bool hasFunctionDecl() const {
+ return dyn_cast_or_null<FunctionDecl>(CalleeDecl);
+ }
+ const Decl *getDecl() const { return CalleeDecl; }
+ unsigned getNumParams() const {
+ if (const auto *FD = dyn_cast<FunctionDecl>(CalleeDecl))
+ return FD->getNumParams();
+ return cast<ObjCMethodDecl>(CalleeDecl)->param_size();
+ }
+ const ParmVarDecl *getParamDecl(unsigned I) const {
+ if (const auto *FD = dyn_cast<FunctionDecl>(CalleeDecl))
+ return FD->getParamDecl(I);
+ return *(cast<ObjCMethodDecl>(CalleeDecl)->param_begin() + I);
+ }
+ };
+
/// \brief Sanitizers enabled for this function.
SanitizerSet SanOpts;
@@ -548,14 +602,10 @@ public:
CGF.DidCallStackSave = false;
}
- /// \brief Exit this cleanup scope, emitting any accumulated
- /// cleanups.
+ /// \brief Exit this cleanup scope, emitting any accumulated cleanups.
~RunCleanupsScope() {
- if (PerformCleanup) {
- CGF.DidCallStackSave = OldDidCallStackSave;
- CGF.PopCleanupBlocks(CleanupStackDepth,
- LifetimeExtendedCleanupStackSize);
- }
+ if (PerformCleanup)
+ ForceCleanup();
}
/// \brief Determine whether this scope requires any cleanups.
@@ -565,11 +615,15 @@ public:
/// \brief Force the emission of cleanups now, instead of waiting
/// until this object is destroyed.
- void ForceCleanup() {
+ /// \param ValuesToReload - A list of values that need to be available at
+ /// the insertion point after cleanup emission. If cleanup emission created
+ /// a shared cleanup block, these value pointers will be rewritten.
+ /// Otherwise, they not will be modified.
+ void ForceCleanup(std::initializer_list<llvm::Value**> ValuesToReload = {}) {
assert(PerformCleanup && "Already forced cleanup");
CGF.DidCallStackSave = OldDidCallStackSave;
- CGF.PopCleanupBlocks(CleanupStackDepth,
- LifetimeExtendedCleanupStackSize);
+ CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize,
+ ValuesToReload);
PerformCleanup = false;
}
};
@@ -620,6 +674,10 @@ public:
rescopeLabels();
}
+ bool hasLabels() const {
+ return !Labels.empty();
+ }
+
void rescopeLabels();
};
@@ -727,13 +785,17 @@ public:
/// \brief Takes the old cleanup stack size and emits the cleanup blocks
/// that have been added.
- void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize);
+ void
+ PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize,
+ std::initializer_list<llvm::Value **> ValuesToReload = {});
/// \brief Takes the old cleanup stack size and emits the cleanup blocks
/// that have been added, then adds all lifetime-extended cleanups from
/// the given position to the stack.
- void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize,
- size_t OldLifetimeExtendedStackSize);
+ void
+ PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize,
+ size_t OldLifetimeExtendedStackSize,
+ std::initializer_list<llvm::Value **> ValuesToReload = {});
void ResolveBranchFixups(llvm::BasicBlock *Target);
@@ -1116,10 +1178,11 @@ private:
uint64_t LoopCount);
public:
- /// Increment the profiler's counter for the given statement.
- void incrementProfileCounter(const Stmt *S) {
+ /// Increment the profiler's counter for the given statement by \p StepV.
+ /// If \p StepV is null, the default increment is 1.
+ void incrementProfileCounter(const Stmt *S, llvm::Value *StepV = nullptr) {
if (CGM.getCodeGenOpts().hasProfileClangInstr())
- PGO.emitCounterIncrement(Builder, S);
+ PGO.emitCounterIncrement(Builder, S, StepV);
PGO.setCurrentStmt(S);
}
@@ -1334,6 +1397,27 @@ private:
/// information about the layout of the variable.
llvm::DenseMap<const ValueDecl *, BlockByrefInfo> BlockByrefInfos;
+ /// Used by -fsanitize=nullability-return to determine whether the return
+ /// value can be checked.
+ llvm::Value *RetValNullabilityPrecondition = nullptr;
+
+ /// Check if -fsanitize=nullability-return instrumentation is required for
+ /// this function.
+ bool requiresReturnValueNullabilityCheck() const {
+ return RetValNullabilityPrecondition;
+ }
+
+ /// Used to store precise source locations for return statements by the
+ /// runtime return value checks.
+ Address ReturnLocation = Address::invalid();
+
+ /// Check if the return value of this function requires sanitization.
+ bool requiresReturnValueCheck() const {
+ return requiresReturnValueNullabilityCheck() ||
+ (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
+ CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>());
+ }
+
llvm::BasicBlock *TerminateLandingPad;
llvm::BasicBlock *TerminateHandler;
llvm::BasicBlock *TrapBB;
@@ -1341,16 +1425,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);
@@ -1403,6 +1479,9 @@ public:
const TargetInfo &getTarget() const { return Target; }
llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); }
+ const TargetCodeGenInfo &getTargetHooks() const {
+ return CGM.getTargetCodeGenInfo();
+ }
//===--------------------------------------------------------------------===//
// Cleanups
@@ -1553,6 +1632,8 @@ public:
SourceLocation Loc = SourceLocation(),
SourceLocation StartLoc = SourceLocation());
+ static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor);
+
void EmitConstructorBody(FunctionArgList &Args);
void EmitDestructorBody(FunctionArgList &Args);
void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
@@ -1671,11 +1752,6 @@ public:
llvm::Value *EmitVTableTypeCheckedLoad(const CXXRecordDecl *RD, llvm::Value *VTable,
uint64_t VTableByteOffset);
- /// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
- /// expr can be devirtualized.
- bool CanDevirtualizeMemberFunctionCall(const Expr *Base,
- const CXXMethodDecl *MD);
-
/// EnterDtorCleanups - Enter the cleanups necessary to complete the
/// given phase of destruction for a destructor. The end result
/// should call destructors on members and base classes in reverse
@@ -1710,6 +1786,9 @@ public:
void EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc,
SourceLocation EndLoc);
+ /// Emit a test that checks if the return value \p RV is nonnull.
+ void EmitReturnValueCheck(llvm::Value *RV);
+
/// EmitStartEHSpec - Emit the start of the exception spec.
void EmitStartEHSpec(const Decl *D);
@@ -1817,40 +1896,65 @@ public:
//===--------------------------------------------------------------------===//
LValue MakeAddrLValue(Address Addr, QualType T,
- AlignmentSource AlignSource = AlignmentSource::Type) {
- return LValue::MakeAddr(Addr, T, getContext(), AlignSource,
+ LValueBaseInfo BaseInfo =
+ LValueBaseInfo(AlignmentSource::Type)) {
+ return LValue::MakeAddr(Addr, T, getContext(), BaseInfo,
CGM.getTBAAInfo(T));
}
LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment,
- AlignmentSource AlignSource = AlignmentSource::Type) {
+ LValueBaseInfo BaseInfo =
+ LValueBaseInfo(AlignmentSource::Type)) {
return LValue::MakeAddr(Address(V, Alignment), T, getContext(),
- AlignSource, CGM.getTBAAInfo(T));
+ BaseInfo, CGM.getTBAAInfo(T));
}
LValue MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T);
LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T);
CharUnits getNaturalTypeAlignment(QualType T,
- AlignmentSource *Source = nullptr,
+ LValueBaseInfo *BaseInfo = nullptr,
bool forPointeeType = false);
CharUnits getNaturalPointeeTypeAlignment(QualType T,
- AlignmentSource *Source = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr);
Address EmitLoadOfReference(Address Ref, const ReferenceType *RefTy,
- AlignmentSource *Source = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr);
LValue EmitLoadOfReferenceLValue(Address Ref, const ReferenceType *RefTy);
Address EmitLoadOfPointer(Address Ptr, const PointerType *PtrTy,
- AlignmentSource *Source = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr);
LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy);
- /// CreateTempAlloca - This creates a alloca and inserts it into the entry
- /// block. The caller is responsible for setting an appropriate alignment on
+ /// CreateTempAlloca - This creates an alloca and inserts it into the entry
+ /// block if \p ArraySize is nullptr, otherwise inserts it at the current
+ /// insertion point of the builder. The caller is responsible for setting an
+ /// appropriate alignment on
/// the alloca.
- llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty,
- const Twine &Name = "tmp");
+ ///
+ /// \p ArraySize is the number of array elements to be allocated if it
+ /// is not nullptr.
+ ///
+ /// LangAS::Default is the address space of pointers to local variables and
+ /// temporaries, as exposed in the source language. In certain
+ /// configurations, this is not the same as the alloca address space, and a
+ /// cast is needed to lift the pointer from the alloca AS into
+ /// LangAS::Default. This can happen when the target uses a restricted
+ /// address space for the stack but the source language requires
+ /// LangAS::Default to be a generic address space. The latter condition is
+ /// common for most programming languages; OpenCL is an exception in that
+ /// LangAS::Default is the private address space, which naturally maps
+ /// to the stack.
+ ///
+ /// Because the address of a temporary is often exposed to the program in
+ /// various ways, this function will perform the cast by default. The cast
+ /// may be avoided by passing false as \p CastToDefaultAddrSpace; this is
+ /// more efficient if the caller knows that the address will not be exposed.
+ llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp",
+ llvm::Value *ArraySize = nullptr);
Address CreateTempAlloca(llvm::Type *Ty, CharUnits align,
- const Twine &Name = "tmp");
+ const Twine &Name = "tmp",
+ llvm::Value *ArraySize = nullptr,
+ bool CastToDefaultAddrSpace = true);
/// CreateDefaultAlignedTempAlloca - This creates an alloca with the
/// default ABI alignment of the given LLVM type.
@@ -1885,9 +1989,12 @@ public:
Address CreateIRTemp(QualType T, const Twine &Name = "tmp");
/// CreateMemTemp - Create a temporary memory object of the given type, with
- /// appropriate alignment.
- Address CreateMemTemp(QualType T, const Twine &Name = "tmp");
- Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp");
+ /// appropriate alignment. Cast it to the default address space if
+ /// \p CastToDefaultAddrSpace is true.
+ Address CreateMemTemp(QualType T, const Twine &Name = "tmp",
+ bool CastToDefaultAddrSpace = true);
+ Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp",
+ bool CastToDefaultAddrSpace = true);
/// CreateAggTemp - Create a temporary memory object for the given
/// aggregate type.
@@ -1928,7 +2035,7 @@ public:
/// pointer to a char.
Address EmitMSVAListRef(const Expr *E);
- /// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
+ /// EmitAnyExprToTemp - Similarly to EmitAnyExpr(), however, the result will
/// always be accessible even if no aggregate location is provided.
RValue EmitAnyExprToTemp(const Expr *E);
@@ -2019,6 +2126,9 @@ public:
llvm::BlockAddress *GetAddrOfLabel(const LabelDecl *L);
llvm::BasicBlock *GetIndirectGotoBlock();
+ /// Check if \p E is a C++ "this" pointer wrapped in value-preserving casts.
+ static bool IsWrappedCXXThis(const Expr *E);
+
/// EmitNullInitialization - Generate code to set a value of the given type to
/// null, If the type contains data member pointers, they will be initialized
/// to -1 in accordance with the Itanium C++ ABI.
@@ -2230,7 +2340,9 @@ public:
TCK_Upcast,
/// Checking the operand of a cast to a virtual base object. Must be an
/// object within its lifetime.
- TCK_UpcastToVirtualBase
+ TCK_UpcastToVirtualBase,
+ /// Checking the value assigned to a _Nonnull pointer. Must not be null.
+ TCK_NonnullAssign
};
/// \brief Whether any type-checking sanitizers are enabled. If \c false,
@@ -2241,7 +2353,7 @@ public:
/// appropriate size and alignment for an object of type \p Type.
void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
QualType Type, CharUnits Alignment = CharUnits::Zero(),
- bool SkipNullCheck = false);
+ SanitizerSet SkippedChecks = SanitizerSet());
/// \brief Emit a check that \p Base points into an array object, which
/// we can access at index \p Index. \p Accessed should be \c false if we
@@ -2401,6 +2513,12 @@ public:
PeepholeProtection protectFromPeepholes(RValue rvalue);
void unprotectFromPeepholes(PeepholeProtection protection);
+ void EmitAlignmentAssumption(llvm::Value *PtrValue, llvm::Value *Alignment,
+ llvm::Value *OffsetValue = nullptr) {
+ Builder.CreateAlignmentAssumption(CGM.getDataLayout(), PtrValue, Alignment,
+ OffsetValue);
+ }
+
//===--------------------------------------------------------------------===//
// Statement Emission
//===--------------------------------------------------------------------===//
@@ -2463,6 +2581,15 @@ public:
void EmitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt &S);
void EmitCoroutineBody(const CoroutineBodyStmt &S);
+ void EmitCoreturnStmt(const CoreturnStmt &S);
+ RValue EmitCoawaitExpr(const CoawaitExpr &E,
+ AggValueSlot aggSlot = AggValueSlot::ignored(),
+ bool ignoreResult = false);
+ LValue EmitCoawaitLValue(const CoawaitExpr *E);
+ RValue EmitCoyieldExpr(const CoyieldExpr &E,
+ AggValueSlot aggSlot = AggValueSlot::ignored(),
+ bool ignoreResult = false);
+ LValue EmitCoyieldLValue(const CoyieldExpr *E);
RValue EmitCoroutineIntrinsic(const CallExpr *E, unsigned int IID);
void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
@@ -2627,7 +2754,9 @@ public:
/// the end of the directive.
///
/// \param D Directive that has at least one 'reduction' directives.
- void EmitOMPReductionClauseFinal(const OMPExecutableDirective &D);
+ /// \param ReductionKind The kind of reduction to perform.
+ void EmitOMPReductionClauseFinal(const OMPExecutableDirective &D,
+ const OpenMPDirectiveKind ReductionKind);
/// \brief Emit initial code for linear variables. Creates private copies
/// and initializes them with the values according to OpenMP standard.
///
@@ -2678,7 +2807,6 @@ public:
void EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S);
void EmitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective &S);
void EmitOMPDistributeDirective(const OMPDistributeDirective &S);
- void EmitOMPDistributeLoop(const OMPDistributeDirective &S);
void EmitOMPDistributeParallelForDirective(
const OMPDistributeParallelForDirective &S);
void EmitOMPDistributeParallelForSimdDirective(
@@ -2704,13 +2832,16 @@ public:
void EmitOMPTargetTeamsDistributeSimdDirective(
const OMPTargetTeamsDistributeSimdDirective &S);
- /// Emit outlined function for the target directive.
- static std::pair<llvm::Function * /*OutlinedFn*/,
- llvm::Constant * /*OutlinedFnID*/>
- EmitOMPTargetDirectiveOutlinedFunction(CodeGenModule &CGM,
- const OMPTargetDirective &S,
- StringRef ParentName,
- bool IsOffloadEntry);
+ /// Emit device code for the target directive.
+ static void EmitOMPTargetDeviceFunction(CodeGenModule &CGM,
+ StringRef ParentName,
+ const OMPTargetDirective &S);
+ static void
+ EmitOMPTargetParallelDeviceFunction(CodeGenModule &CGM, StringRef ParentName,
+ const OMPTargetParallelDirective &S);
+ static void
+ EmitOMPTargetTeamsDeviceFunction(CodeGenModule &CGM, StringRef ParentName,
+ const OMPTargetTeamsDirective &S);
/// \brief Emit inner loop of the worksharing/simd construct.
///
/// \param S Directive, for which the inner loop must be emitted.
@@ -2732,32 +2863,78 @@ public:
void EmitOMPPrivateLoopCounters(const OMPLoopDirective &S,
OMPPrivateScope &LoopScope);
+ /// Helper for the OpenMP loop directives.
+ void EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit);
+
+ /// \brief Emit code for the worksharing loop-based directive.
+ /// \return true, if this construct has any lastprivate clause, false -
+ /// otherwise.
+ bool EmitOMPWorksharingLoop(const OMPLoopDirective &S, Expr *EUB,
+ const CodeGenLoopBoundsTy &CodeGenLoopBounds,
+ const CodeGenDispatchBoundsTy &CGDispatchBounds);
+
private:
/// Helpers for blocks
llvm::Value *EmitBlockLiteral(const CGBlockInfo &Info);
/// Helpers for the OpenMP loop directives.
- void EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit);
void EmitOMPSimdInit(const OMPLoopDirective &D, bool IsMonotonic = false);
void EmitOMPSimdFinal(
const OMPLoopDirective &D,
const llvm::function_ref<llvm::Value *(CodeGenFunction &)> &CondGen);
- /// \brief Emit code for the worksharing loop-based directive.
- /// \return true, if this construct has any lastprivate clause, false -
- /// otherwise.
- bool EmitOMPWorksharingLoop(const OMPLoopDirective &S);
- void EmitOMPOuterLoop(bool IsMonotonic, bool DynamicOrOrdered,
- const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk);
+
+ void EmitOMPDistributeLoop(const OMPLoopDirective &S,
+ const CodeGenLoopTy &CodeGenLoop, Expr *IncExpr);
+
+ /// struct with the values to be passed to the OpenMP loop-related functions
+ struct OMPLoopArguments {
+ /// loop lower bound
+ Address LB = Address::invalid();
+ /// loop upper bound
+ Address UB = Address::invalid();
+ /// loop stride
+ Address ST = Address::invalid();
+ /// isLastIteration argument for runtime functions
+ Address IL = Address::invalid();
+ /// Chunk value generated by sema
+ llvm::Value *Chunk = nullptr;
+ /// EnsureUpperBound
+ Expr *EUB = nullptr;
+ /// IncrementExpression
+ Expr *IncExpr = nullptr;
+ /// Loop initialization
+ Expr *Init = nullptr;
+ /// Loop exit condition
+ Expr *Cond = nullptr;
+ /// Update of LB after a whole chunk has been executed
+ Expr *NextLB = nullptr;
+ /// Update of UB after a whole chunk has been executed
+ Expr *NextUB = nullptr;
+ OMPLoopArguments() = default;
+ OMPLoopArguments(Address LB, Address UB, Address ST, Address IL,
+ llvm::Value *Chunk = nullptr, Expr *EUB = nullptr,
+ Expr *IncExpr = nullptr, Expr *Init = nullptr,
+ Expr *Cond = nullptr, Expr *NextLB = nullptr,
+ Expr *NextUB = nullptr)
+ : LB(LB), UB(UB), ST(ST), IL(IL), Chunk(Chunk), EUB(EUB),
+ IncExpr(IncExpr), Init(Init), Cond(Cond), NextLB(NextLB),
+ NextUB(NextUB) {}
+ };
+ void EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic,
+ const OMPLoopDirective &S, OMPPrivateScope &LoopScope,
+ const OMPLoopArguments &LoopArgs,
+ const CodeGenLoopTy &CodeGenLoop,
+ const CodeGenOrderedTy &CodeGenOrdered);
void EmitOMPForOuterLoop(const OpenMPScheduleTy &ScheduleKind,
bool IsMonotonic, const OMPLoopDirective &S,
- OMPPrivateScope &LoopScope, bool Ordered, Address LB,
- Address UB, Address ST, Address IL,
- llvm::Value *Chunk);
- void EmitOMPDistributeOuterLoop(
- OpenMPDistScheduleClauseKind ScheduleKind,
- const OMPDistributeDirective &S, OMPPrivateScope &LoopScope,
- Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk);
+ OMPPrivateScope &LoopScope, bool Ordered,
+ const OMPLoopArguments &LoopArgs,
+ const CodeGenDispatchBoundsTy &CGDispatchBounds);
+ void EmitOMPDistributeOuterLoop(OpenMPDistScheduleClauseKind ScheduleKind,
+ const OMPLoopDirective &S,
+ OMPPrivateScope &LoopScope,
+ const OMPLoopArguments &LoopArgs,
+ const CodeGenLoopTy &CodeGenLoopContent);
/// \brief Emit code for sections directive.
void EmitSections(const OMPExecutableDirective &S);
@@ -2843,13 +3020,20 @@ public:
/// representation to its value representation.
llvm::Value *EmitFromMemory(llvm::Value *Value, QualType Ty);
+ /// Check if the scalar \p Value is within the valid range for the given
+ /// type \p Ty.
+ ///
+ /// Returns true if a check is needed (even if the range is unknown).
+ bool EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
+ SourceLocation Loc);
+
/// EmitLoadOfScalar - Load a scalar value from an address, taking
/// care to appropriately convert from the memory representation to
/// the LLVM value representation.
llvm::Value *EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty,
SourceLocation Loc,
- AlignmentSource AlignSource =
- AlignmentSource::Type,
+ LValueBaseInfo BaseInfo =
+ LValueBaseInfo(AlignmentSource::Type),
llvm::MDNode *TBAAInfo = nullptr,
QualType TBAABaseTy = QualType(),
uint64_t TBAAOffset = 0,
@@ -2866,7 +3050,8 @@ public:
/// the LLVM value representation.
void EmitStoreOfScalar(llvm::Value *Value, Address Addr,
bool Volatile, QualType Ty,
- AlignmentSource AlignSource = AlignmentSource::Type,
+ LValueBaseInfo BaseInfo =
+ LValueBaseInfo(AlignmentSource::Type),
llvm::MDNode *TBAAInfo = nullptr, bool isInit = false,
QualType TBAABaseTy = QualType(),
uint64_t TBAAOffset = 0, bool isNontemporal = false);
@@ -2883,7 +3068,7 @@ public:
/// rvalue, returning the rvalue.
RValue EmitLoadOfLValue(LValue V, SourceLocation Loc);
RValue EmitLoadOfExtVectorElementLValue(LValue V);
- RValue EmitLoadOfBitfieldLValue(LValue LV);
+ RValue EmitLoadOfBitfieldLValue(LValue LV, SourceLocation Loc);
RValue EmitLoadOfGlobalRegLValue(LValue LV);
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
@@ -2939,7 +3124,7 @@ public:
RValue EmitRValueForField(LValue LV, const FieldDecl *FD, SourceLocation Loc);
Address EmitArrayToPointerDecay(const Expr *Array,
- AlignmentSource *AlignSource = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr);
class ConstantEmission {
llvm::PointerIntPair<llvm::Constant*, 1, bool> ValueAndIsReference;
@@ -3080,7 +3265,7 @@ public:
Address EmitCXXMemberDataPointerAddress(const Expr *E, Address base,
llvm::Value *memberPtr,
const MemberPointerType *memberPtrType,
- AlignmentSource *AlignSource = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr);
RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
ReturnValueSlot ReturnValue);
@@ -3092,8 +3277,8 @@ public:
RValue EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
ReturnValueSlot ReturnValue);
- RValue EmitCUDADevicePrintfCallExpr(const CallExpr *E,
- ReturnValueSlot ReturnValue);
+ RValue EmitNVPTXDevicePrintfCallExpr(const CallExpr *E,
+ ReturnValueSlot ReturnValue);
RValue EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E,
@@ -3149,6 +3334,8 @@ private:
public:
llvm::Value *EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID, const CallExpr *E);
+ llvm::Value *EmitBuiltinAvailable(ArrayRef<llvm::Value *> Args);
+
llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
llvm::Value *EmitObjCBoxedExpr(const ObjCBoxedExpr *E);
@@ -3215,6 +3402,7 @@ public:
static Destroyer destroyARCStrongImprecise;
static Destroyer destroyARCStrongPrecise;
static Destroyer destroyARCWeak;
+ static Destroyer emitARCIntrinsicUse;
void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr);
llvm::Value *EmitObjCAutoreleasePoolPush();
@@ -3316,9 +3504,10 @@ public:
/// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
/// variables.
- void GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
- const std::vector<std::pair<llvm::WeakVH,
- llvm::Constant*> > &DtorsAndObjects);
+ void GenerateCXXGlobalDtorsFunc(
+ llvm::Function *Fn,
+ const std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>>
+ &DtorsAndObjects);
void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D,
@@ -3396,6 +3585,26 @@ public:
void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock, uint64_t TrueCount);
+ /// Given an assignment `*LHS = RHS`, emit a test that checks if \p RHS is
+ /// nonnull, if \p LHS is marked _Nonnull.
+ void EmitNullabilityCheck(LValue LHS, llvm::Value *RHS, SourceLocation Loc);
+
+ /// An enumeration which makes it easier to specify whether or not an
+ /// operation is a subtraction.
+ enum { NotSubtraction = false, IsSubtraction = true };
+
+ /// Same as IRBuilder::CreateInBoundsGEP, but additionally emits a check to
+ /// detect undefined behavior when the pointer overflow sanitizer is enabled.
+ /// \p SignedIndices indicates whether any of the GEP indices are signed.
+ /// \p IsSubtraction indicates whether the expression used to form the GEP
+ /// is a subtraction.
+ llvm::Value *EmitCheckedInBoundsGEP(llvm::Value *Ptr,
+ ArrayRef<llvm::Value *> IdxList,
+ bool SignedIndices,
+ bool IsSubtraction,
+ SourceLocation Loc,
+ const Twine &Name = "");
+
/// \brief Emit a description of a type in a format suitable for passing to
/// a runtime sanitizer handler.
llvm::Constant *EmitCheckTypeDescriptor(QualType T);
@@ -3429,13 +3638,16 @@ public:
/// "trap-func-name" if specified.
llvm::CallInst *EmitTrapCall(llvm::Intrinsic::ID IntrID);
+ /// \brief Emit a stub for the cross-DSO CFI check function.
+ void EmitCfiCheckStub();
+
/// \brief Emit a cross-DSO CFI failure handling function.
void EmitCfiCheckFail();
/// \brief Create a check for a function parameter that may potentially be
/// declared as non-null.
void EmitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc,
- const FunctionDecl *FD, unsigned ParmNum);
+ AbstractCallee AC, unsigned ParmNum);
/// EmitCallArg - Emit a single call argument.
void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
@@ -3490,14 +3702,18 @@ private:
/// \brief Attempts to statically evaluate the object size of E. If that
/// fails, emits code to figure the size of E out for us. This is
/// pass_object_size aware.
+ ///
+ /// If EmittedExpr is non-null, this will use that instead of re-emitting E.
llvm::Value *evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType);
+ llvm::IntegerType *ResType,
+ llvm::Value *EmittedE);
/// \brief Emits the size of E, as required by __builtin_object_size. This
/// function is aware of pass_object_size parameters, and will act accordingly
/// if E is a parameter with the pass_object_size attribute.
llvm::Value *emitBuiltinObjectSize(const Expr *E, unsigned Type,
- llvm::IntegerType *ResType);
+ llvm::IntegerType *ResType,
+ llvm::Value *EmittedE);
public:
#ifndef NDEBUG
@@ -3533,7 +3749,7 @@ public:
template <typename T>
void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
- const FunctionDecl *CalleeDecl = nullptr,
+ AbstractCallee AC = AbstractCallee(),
unsigned ParamsToSkip = 0,
EvaluationOrder Order = EvaluationOrder::Default) {
SmallVector<QualType, 16> ArgTypes;
@@ -3575,48 +3791,40 @@ public:
for (auto *A : llvm::make_range(Arg, ArgRange.end()))
ArgTypes.push_back(CallArgTypeInfo ? getVarArgType(A) : A->getType());
- EmitCallArgs(Args, ArgTypes, ArgRange, CalleeDecl, ParamsToSkip, Order);
+ EmitCallArgs(Args, ArgTypes, ArgRange, AC, ParamsToSkip, Order);
}
void EmitCallArgs(CallArgList &Args, ArrayRef<QualType> ArgTypes,
llvm::iterator_range<CallExpr::const_arg_iterator> ArgRange,
- const FunctionDecl *CalleeDecl = nullptr,
+ AbstractCallee AC = AbstractCallee(),
unsigned ParamsToSkip = 0,
EvaluationOrder Order = EvaluationOrder::Default);
- /// EmitPointerWithAlignment - Given an expression with a pointer
- /// type, emit the value and compute our best estimate of the
- /// alignment of the pointee.
+ /// EmitPointerWithAlignment - Given an expression with a pointer type,
+ /// emit the value and compute our best estimate of the alignment of the
+ /// pointee.
///
- /// Note that this function will conservatively fall back on the type
- /// when it doesn't
+ /// \param BaseInfo - If non-null, this will be initialized with
+ /// information about the source of the alignment and the may-alias
+ /// attribute. Note that this function will conservatively fall back on
+ /// the type when it doesn't recognize the expression and may-alias will
+ /// be set to false.
///
- /// \param Source - If non-null, this will be initialized with
- /// information about the source of the alignment. Note that this
- /// function will conservatively fall back on the type when it
- /// doesn't recognize the expression, which means that sometimes
- ///
- /// a worst-case One
- /// reasonable way to use this information is when there's a
- /// language guarantee that the pointer must be aligned to some
- /// stricter value, and we're simply trying to ensure that
- /// sufficiently obvious uses of under-aligned objects don't get
- /// miscompiled; for example, a placement new into the address of
- /// a local variable. In such a case, it's quite reasonable to
- /// just ignore the returned alignment when it isn't from an
- /// explicit source.
+ /// One reasonable way to use this information is when there's a language
+ /// guarantee that the pointer must be aligned to some stricter value, and
+ /// we're simply trying to ensure that sufficiently obvious uses of under-
+ /// aligned objects don't get miscompiled; for example, a placement new
+ /// into the address of a local variable. In such a case, it's quite
+ /// reasonable to just ignore the returned alignment when it isn't from an
+ /// explicit source.
Address EmitPointerWithAlignment(const Expr *Addr,
- AlignmentSource *Source = nullptr);
+ LValueBaseInfo *BaseInfo = nullptr);
void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK);
private:
QualType getVarArgType(const Expr *Arg);
- const TargetCodeGenInfo &getTargetHooks() const {
- return CGM.getTargetCodeGenInfo();
- }
-
void EmitDeclMetadata();
BlockByrefHelpers *buildByrefHelpers(llvm::StructType &byrefType,
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp
index 3600543..5561d45 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp
@@ -24,7 +24,6 @@
#include "CodeGenFunction.h"
#include "CodeGenPGO.h"
#include "CodeGenTBAA.h"
-#include "ConstantBuilder.h"
#include "CoverageMappingGen.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
@@ -42,9 +41,11 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/DataLayout.h"
@@ -111,6 +112,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
C.getTargetInfo().getMaxPointerWidth());
Int8PtrTy = Int8Ty->getPointerTo(0);
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
+ AllocaInt8PtrTy = Int8Ty->getPointerTo(
+ M.getDataLayout().getAllocaAddrSpace());
+ ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace();
RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC();
BuiltinCC = getTargetCodeGenInfo().getABIInfo().getBuiltinCC();
@@ -367,13 +371,18 @@ void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags,
if (MainFile.empty())
MainFile = "<stdin>";
Diags.Report(diag::warn_profile_data_unprofiled) << MainFile;
- } else
- Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Missing
- << Mismatched;
+ } else {
+ if (Mismatched > 0)
+ Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Mismatched;
+
+ if (Missing > 0)
+ Diags.Report(diag::warn_profile_data_missing) << Visited << Missing;
+ }
}
void CodeGenModule::Release() {
EmitDeferred();
+ EmitVTablesOpportunistically();
applyGlobalValReplacements();
applyReplacements();
checkAliases();
@@ -392,8 +401,11 @@ void CodeGenModule::Release() {
}
if (OpenMPRuntime)
if (llvm::Function *OpenMPRegistrationFunction =
- OpenMPRuntime->emitRegistrationFunction())
- AddGlobalCtor(OpenMPRegistrationFunction, 0);
+ OpenMPRuntime->emitRegistrationFunction()) {
+ auto ComdatKey = OpenMPRegistrationFunction->hasComdat() ?
+ OpenMPRegistrationFunction : nullptr;
+ AddGlobalCtor(OpenMPRegistrationFunction, 0, ComdatKey);
+ }
if (PGOReader) {
getModule().setProfileSummary(PGOReader->getSummary().getMD(VMContext));
if (PGOStats.hasDiagnostics())
@@ -406,8 +418,11 @@ void CodeGenModule::Release() {
EmitDeferredUnusedCoverageMappings();
if (CoverageMapping)
CoverageMapping->emit();
- if (CodeGenOpts.SanitizeCfiCrossDso)
+ if (CodeGenOpts.SanitizeCfiCrossDso) {
CodeGenFunction(*this).EmitCfiCheckFail();
+ CodeGenFunction(*this).EmitCfiCheckStub();
+ }
+ emitAtAvailableLinkGuard();
emitLLVMUsed();
if (SanStats)
SanStats->finish();
@@ -416,6 +431,12 @@ void CodeGenModule::Release() {
(Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) {
EmitModuleLinkOptions();
}
+
+ // Record mregparm value now so it is visible through rest of codegen.
+ if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
+ getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters",
+ CodeGenOpts.NumRegisterParameters);
+
if (CodeGenOpts.DwarfVersion) {
// We actually want the latest version when there are conflicts.
// We can change from Warning to Latest if such mode is supported.
@@ -449,18 +470,24 @@ void CodeGenModule::Release() {
getModule().addModuleFlag(llvm::Module::Warning, "Debug Info Version",
llvm::DEBUG_METADATA_VERSION);
+ // Width of wchar_t in bytes
+ uint64_t WCharWidth =
+ Context.getTypeSizeInChars(Context.getWideCharType()).getQuantity();
+ assert((LangOpts.ShortWChar ||
+ llvm::TargetLibraryInfoImpl::getTargetWCharSize(Target.getTriple()) ==
+ Target.getWCharWidth() / 8) &&
+ "LLVM wchar_t size out of sync");
+
// We need to record the widths of enums and wchar_t, so that we can generate
- // the correct build attributes in the ARM backend.
+ // the correct build attributes in the ARM backend. wchar_size is also used by
+ // TargetLibraryInfo.
+ getModule().addModuleFlag(llvm::Module::Error, "wchar_size", WCharWidth);
+
llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
if ( Arch == llvm::Triple::arm
|| Arch == llvm::Triple::armeb
|| Arch == llvm::Triple::thumb
|| Arch == llvm::Triple::thumbeb) {
- // Width of wchar_t in bytes
- uint64_t WCharWidth =
- Context.getTypeSizeInChars(Context.getWideCharType()).getQuantity();
- getModule().addModuleFlag(llvm::Module::Error, "wchar_size", WCharWidth);
-
// The minimum width of an enum in bytes
uint64_t EnumWidth = Context.getLangOpts().ShortEnums ? 1 : 4;
getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth);
@@ -479,6 +506,26 @@ void CodeGenModule::Release() {
LangOpts.CUDADeviceFlushDenormalsToZero ? 1 : 0);
}
+ // Emit OpenCL specific module metadata: OpenCL/SPIR version.
+ if (LangOpts.OpenCL) {
+ EmitOpenCLMetadata();
+ // Emit SPIR version.
+ if (getTriple().getArch() == llvm::Triple::spir ||
+ getTriple().getArch() == llvm::Triple::spir64) {
+ // SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the
+ // opencl.spir.version named metadata.
+ llvm::Metadata *SPIRVerElts[] = {
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ Int32Ty, LangOpts.OpenCLVersion / 100)),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ Int32Ty, (LangOpts.OpenCLVersion / 100 > 1) ? 0 : 2))};
+ llvm::NamedMDNode *SPIRVerMD =
+ TheModule.getOrInsertNamedMetadata("opencl.spir.version");
+ llvm::LLVMContext &Ctx = TheModule.getContext();
+ SPIRVerMD->addOperand(llvm::MDNode::get(Ctx, SPIRVerElts));
+ }
+ }
+
if (uint32_t PLevel = Context.getLangOpts().PICLevel) {
assert(PLevel < 3 && "Invalid PIC Level");
getModule().setPICLevel(static_cast<llvm::PICLevel::Level>(PLevel));
@@ -502,6 +549,20 @@ void CodeGenModule::Release() {
EmitTargetMetadata();
}
+void CodeGenModule::EmitOpenCLMetadata() {
+ // SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the
+ // opencl.ocl.version named metadata node.
+ llvm::Metadata *OCLVerElts[] = {
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ Int32Ty, LangOpts.OpenCLVersion / 100)),
+ llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
+ Int32Ty, (LangOpts.OpenCLVersion % 100) / 10))};
+ llvm::NamedMDNode *OCLVerMD =
+ TheModule.getOrInsertNamedMetadata("opencl.ocl.version");
+ llvm::LLVMContext &Ctx = TheModule.getContext();
+ OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts));
+}
+
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
// Make sure that this type is translated.
Types.UpdateCompletedType(TD);
@@ -554,12 +615,8 @@ void CodeGenModule::DecorateInstructionWithTBAA(llvm::Instruction *Inst,
void CodeGenModule::DecorateInstructionWithInvariantGroup(
llvm::Instruction *I, const CXXRecordDecl *RD) {
- llvm::Metadata *MD = CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
- auto *MetaDataNode = dyn_cast<llvm::MDNode>(MD);
- // Check if we have to wrap MDString in MDNode.
- if (!MetaDataNode)
- MetaDataNode = llvm::MDNode::get(getLLVMContext(), MD);
- I->setMetadata(llvm::LLVMContext::MD_invariant_group, MetaDataNode);
+ I->setMetadata(llvm::LLVMContext::MD_invariant_group,
+ llvm::MDNode::get(getLLVMContext(), {}));
}
void CodeGenModule::Error(SourceLocation loc, StringRef message) {
@@ -740,7 +797,7 @@ void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) {
// Get the type of a ctor entry, { i32, void ()*, i8* }.
llvm::StructType *CtorStructTy = llvm::StructType::get(
- Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy, nullptr);
+ Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy);
// Construct the constructor and destructor arrays.
ConstantInitBuilder builder(*this);
@@ -830,10 +887,9 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
const CGFunctionInfo &Info,
llvm::Function *F) {
unsigned CallingConv;
- AttributeListType AttributeList;
- ConstructAttributeList(F->getName(), Info, D, AttributeList, CallingConv,
- false);
- F->setAttributes(llvm::AttributeSet::get(getLLVMContext(), AttributeList));
+ llvm::AttributeList PAL;
+ ConstructAttributeList(F->getName(), Info, D, PAL, CallingConv, false);
+ F->setAttributes(PAL);
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
@@ -882,14 +938,20 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining)
B.addAttribute(llvm::Attribute::NoInline);
- F->addAttributes(llvm::AttributeSet::FunctionIndex,
- llvm::AttributeSet::get(
- F->getContext(),
- llvm::AttributeSet::FunctionIndex, B));
+ F->addAttributes(llvm::AttributeList::FunctionIndex, B);
return;
}
- if (D->hasAttr<OptimizeNoneAttr>()) {
+ // Track whether we need to add the optnone LLVM attribute,
+ // starting with the default for this optimization level.
+ bool ShouldAddOptNone =
+ !CodeGenOpts.DisableO0ImplyOptNone && CodeGenOpts.OptimizationLevel == 0;
+ // We can't add optnone in the following cases, it won't pass the verifier.
+ ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>();
+ ShouldAddOptNone &= !F->hasFnAttribute(llvm::Attribute::AlwaysInline);
+ ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>();
+
+ if (ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) {
B.addAttribute(llvm::Attribute::OptimizeNone);
// OptimizeNone implies noinline; we should not be inlining such functions.
@@ -943,7 +1005,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// function.
if (!D->hasAttr<OptimizeNoneAttr>()) {
if (D->hasAttr<ColdAttr>()) {
- B.addAttribute(llvm::Attribute::OptimizeForSize);
+ if (!ShouldAddOptNone)
+ B.addAttribute(llvm::Attribute::OptimizeForSize);
B.addAttribute(llvm::Attribute::Cold);
}
@@ -951,9 +1014,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute(llvm::Attribute::MinSize);
}
- F->addAttributes(llvm::AttributeSet::FunctionIndex,
- llvm::AttributeSet::get(
- F->getContext(), llvm::AttributeSet::FunctionIndex, B));
+ F->addAttributes(llvm::AttributeList::FunctionIndex, B);
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
if (alignment)
@@ -999,9 +1060,25 @@ void CodeGenModule::setNonAliasAttributes(const Decl *D,
llvm::GlobalObject *GO) {
SetCommonAttributes(D, GO);
- if (D)
+ if (D) {
+ if (auto *GV = dyn_cast<llvm::GlobalVariable>(GO)) {
+ if (auto *SA = D->getAttr<PragmaClangBSSSectionAttr>())
+ GV->addAttribute("bss-section", SA->getName());
+ if (auto *SA = D->getAttr<PragmaClangDataSectionAttr>())
+ GV->addAttribute("data-section", SA->getName());
+ if (auto *SA = D->getAttr<PragmaClangRodataSectionAttr>())
+ GV->addAttribute("rodata-section", SA->getName());
+ }
+
+ if (auto *F = dyn_cast<llvm::Function>(GO)) {
+ if (auto *SA = D->getAttr<PragmaClangTextSectionAttr>())
+ if (!D->getAttr<SectionAttr>())
+ F->addFnAttr("implicit-section-name", SA->getName());
+ }
+
if (const SectionAttr *SA = D->getAttr<SectionAttr>())
GO->setSection(SA->getName());
+ }
getTargetCodeGenInfo().setTargetAttributes(D, GO, *this);
}
@@ -1021,7 +1098,7 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV,
const NamedDecl *ND) {
// Set linkage and visibility in case we never see a definition.
LinkageInfo LV = ND->getLinkageAndVisibility();
- if (LV.getLinkage() != ExternalLinkage) {
+ if (!isExternallyVisible(LV.getLinkage())) {
// Don't set internal linkage on declarations.
} else {
if (ND->hasAttr<DLLImportAttr>()) {
@@ -1029,7 +1106,6 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV,
GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
} else if (ND->hasAttr<DLLExportAttr>()) {
GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
} else if (ND->hasAttr<WeakAttr>() || ND->isWeakImported()) {
// "extern_weak" is overloaded in LLVM; we probably should have
// separate linkage types for this.
@@ -1101,13 +1177,17 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
setLinkageAndVisibilityForGV(F, FD);
+ if (FD->getAttr<PragmaClangTextSectionAttr>()) {
+ F->addFnAttr("implicit-section-name");
+ }
+
if (const SectionAttr *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());
if (FD->isReplaceableGlobalAllocationFunction()) {
// A replaceable global allocation function does not act like a builtin by
// default, only if it is invoked by a new-expression or delete-expression.
- F->addAttribute(llvm::AttributeSet::FunctionIndex,
+ F->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoBuiltin);
// A sane operator new returns a non-aliasing pointer.
@@ -1116,7 +1196,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
auto Kind = FD->getDeclName().getCXXOverloadedOperator();
if (getCodeGenOpts().AssumeSaneOperatorNew &&
(Kind == OO_New || Kind == OO_Array_New))
- F->addAttribute(llvm::AttributeSet::ReturnIndex,
+ F->addAttribute(llvm::AttributeList::ReturnIndex,
llvm::Attribute::NoAlias);
}
@@ -1145,7 +1225,7 @@ void CodeGenModule::addCompilerUsedGlobal(llvm::GlobalValue *GV) {
}
static void emitUsed(CodeGenModule &CGM, StringRef Name,
- std::vector<llvm::WeakVH> &List) {
+ std::vector<llvm::WeakTrackingVH> &List) {
// Don't create llvm.used if there is no need.
if (List.empty())
return;
@@ -1197,7 +1277,7 @@ void CodeGenModule::AddDependentLib(StringRef Lib) {
/// \brief Add link options implied by the given module, including modules
/// it depends on, using a postorder walk.
static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod,
- SmallVectorImpl<llvm::Metadata *> &Metadata,
+ SmallVectorImpl<llvm::MDNode *> &Metadata,
llvm::SmallPtrSet<Module *, 16> &Visited) {
// Import this module's parent.
if (Mod->Parent && Visited.insert(Mod->Parent).second) {
@@ -1285,7 +1365,7 @@ void CodeGenModule::EmitModuleLinkOptions() {
// Add link options for all of the imported modules in reverse topological
// order. We don't do anything to try to order import link flags with respect
// to linker options inserted by things like #pragma comment().
- SmallVector<llvm::Metadata *, 16> MetadataArgs;
+ SmallVector<llvm::MDNode *, 16> MetadataArgs;
Visited.clear();
for (Module *M : LinkModules)
if (Visited.insert(M).second)
@@ -1294,9 +1374,9 @@ void CodeGenModule::EmitModuleLinkOptions() {
LinkerOptionsMetadata.append(MetadataArgs.begin(), MetadataArgs.end());
// Add the linker options metadata flag.
- getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options",
- llvm::MDNode::get(getLLVMContext(),
- LinkerOptionsMetadata));
+ auto *NMD = getModule().getOrInsertNamedMetadata("llvm.linker.options");
+ for (auto *MD : LinkerOptionsMetadata)
+ NMD->addOperand(MD);
}
void CodeGenModule::EmitDeferred() {
@@ -1319,13 +1399,10 @@ void CodeGenModule::EmitDeferred() {
// Grab the list of decls to emit. If EmitGlobalDefinition schedules more
// work, it will not interfere with this.
- std::vector<DeferredGlobal> CurDeclsToEmit;
+ std::vector<GlobalDecl> CurDeclsToEmit;
CurDeclsToEmit.swap(DeferredDeclsToEmit);
- for (DeferredGlobal &G : CurDeclsToEmit) {
- GlobalDecl D = G.GD;
- G.GV = nullptr;
-
+ for (GlobalDecl &D : CurDeclsToEmit) {
// We should call GetAddrOfGlobal with IsForDefinition set to true in order
// to get GlobalValue with exactly the type we need, not something that
// might had been created for another decl with the same mangled name but
@@ -1364,6 +1441,24 @@ void CodeGenModule::EmitDeferred() {
}
}
+void CodeGenModule::EmitVTablesOpportunistically() {
+ // Try to emit external vtables as available_externally if they have emitted
+ // all inlined virtual functions. It runs after EmitDeferred() and therefore
+ // is not allowed to create new references to things that need to be emitted
+ // lazily. Note that it also uses fact that we eagerly emitting RTTI.
+
+ assert((OpportunisticVTables.empty() || shouldOpportunisticallyEmitVTables())
+ && "Only emit opportunistic vtables with optimizations");
+
+ for (const CXXRecordDecl *RD : OpportunisticVTables) {
+ assert(getVTables().isVTableExternal(RD) &&
+ "This queue should only contain external vtables");
+ if (getCXXABI().canSpeculativelyEmitVTable(RD))
+ VTables.GenerateClassData(RD);
+ }
+ OpportunisticVTables.clear();
+}
+
void CodeGenModule::EmitGlobalAnnotations() {
if (Annotations.empty())
return;
@@ -1482,6 +1577,34 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
return false;
}
+bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
+ StringRef Category) const {
+ if (!LangOpts.XRayInstrument)
+ return false;
+ const auto &XRayFilter = getContext().getXRayFilter();
+ using ImbueAttr = XRayFunctionFilter::ImbueAttribute;
+ auto Attr = XRayFunctionFilter::ImbueAttribute::NONE;
+ if (Loc.isValid())
+ Attr = XRayFilter.shouldImbueLocation(Loc, Category);
+ if (Attr == ImbueAttr::NONE)
+ Attr = XRayFilter.shouldImbueFunction(Fn->getName());
+ switch (Attr) {
+ case ImbueAttr::NONE:
+ return false;
+ case ImbueAttr::ALWAYS:
+ Fn->addFnAttr("function-instrument", "xray-always");
+ break;
+ case ImbueAttr::ALWAYS_ARG1:
+ Fn->addFnAttr("function-instrument", "xray-always");
+ Fn->addFnAttr("xray-log-args", "1");
+ break;
+ case ImbueAttr::NEVER:
+ Fn->addFnAttr("function-instrument", "xray-never");
+ break;
+ }
+ return true;
+}
+
bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
// Never defer when EmitAllDecls is specified.
if (LangOpts.EmitAllDecls)
@@ -1678,13 +1801,13 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
}
StringRef MangledName = getMangledName(GD);
- if (llvm::GlobalValue *GV = GetGlobalValue(MangledName)) {
+ if (GetGlobalValue(MangledName) != nullptr) {
// The value has already been used and should therefore be emitted.
- addDeferredDeclToEmit(GV, GD);
+ addDeferredDeclToEmit(GD);
} else if (MustBeEmitted(Global)) {
// The value must be emitted, but cannot be emitted eagerly.
assert(!MayBeEmittedEagerly(Global));
- addDeferredDeclToEmit(/*GV=*/nullptr, GD);
+ addDeferredDeclToEmit(GD);
} else {
// Otherwise, remember that we saw a deferred decl with this name. The
// first use of the mangled name will cause it to move into
@@ -1693,6 +1816,16 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
}
}
+// Check if T is a class type with a destructor that's not dllimport.
+static bool HasNonDllImportDtor(QualType T) {
+ if (const auto *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>())
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ if (RD->getDestructor() && !RD->getDestructor()->hasAttr<DLLImportAttr>())
+ return true;
+
+ return false;
+}
+
namespace {
struct FunctionIsDirectlyRecursive :
public RecursiveASTVisitor<FunctionIsDirectlyRecursive> {
@@ -1726,6 +1859,7 @@ namespace {
}
};
+ // Make sure we're not referencing non-imported vars or functions.
struct DLLImportFunctionVisitor
: public RecursiveASTVisitor<DLLImportFunctionVisitor> {
bool SafeToInline = true;
@@ -1733,12 +1867,25 @@ namespace {
bool shouldVisitImplicitCode() const { return true; }
bool VisitVarDecl(VarDecl *VD) {
- // A thread-local variable cannot be imported.
- SafeToInline = !VD->getTLSKind();
+ if (VD->getTLSKind()) {
+ // A thread-local variable cannot be imported.
+ SafeToInline = false;
+ return SafeToInline;
+ }
+
+ // A variable definition might imply a destructor call.
+ if (VD->isThisDeclarationADefinition())
+ SafeToInline = !HasNonDllImportDtor(VD->getType());
+
+ return SafeToInline;
+ }
+
+ bool VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ if (const auto *D = E->getTemporary()->getDestructor())
+ SafeToInline = D->hasAttr<DLLImportAttr>();
return SafeToInline;
}
- // Make sure we're not referencing non-imported vars or functions.
bool VisitDeclRefExpr(DeclRefExpr *E) {
ValueDecl *VD = E->getDecl();
if (isa<FunctionDecl>(VD))
@@ -1747,14 +1894,28 @@ namespace {
SafeToInline = !V->hasGlobalStorage() || V->hasAttr<DLLImportAttr>();
return SafeToInline;
}
+
bool VisitCXXConstructExpr(CXXConstructExpr *E) {
SafeToInline = E->getConstructor()->hasAttr<DLLImportAttr>();
return SafeToInline;
}
+
+ bool VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ CXXMethodDecl *M = E->getMethodDecl();
+ if (!M) {
+ // Call through a pointer to member function. This is safe to inline.
+ SafeToInline = true;
+ } else {
+ SafeToInline = M->hasAttr<DLLImportAttr>();
+ }
+ return SafeToInline;
+ }
+
bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {
SafeToInline = E->getOperatorDelete()->hasAttr<DLLImportAttr>();
return SafeToInline;
}
+
bool VisitCXXNewExpr(CXXNewExpr *E) {
SafeToInline = E->getOperatorNew()->hasAttr<DLLImportAttr>();
return SafeToInline;
@@ -1783,16 +1944,6 @@ CodeGenModule::isTriviallyRecursive(const FunctionDecl *FD) {
return Walker.Result;
}
-// Check if T is a class type with a destructor that's not dllimport.
-static bool HasNonDllImportDtor(QualType T) {
- if (const RecordType *RT = dyn_cast<RecordType>(T))
- if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- if (RD->getDestructor() && !RD->getDestructor()->hasAttr<DLLImportAttr>())
- return true;
-
- return false;
-}
-
bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage)
return true;
@@ -1828,20 +1979,8 @@ bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
return !isTriviallyRecursive(F);
}
-/// If the type for the method's class was generated by
-/// CGDebugInfo::createContextChain(), the cache contains only a
-/// limited DIType without any declarations. Since EmitFunctionStart()
-/// needs to find the canonical declaration for each method, we need
-/// to construct the complete type prior to emitting the method.
-void CodeGenModule::CompleteDIClassType(const CXXMethodDecl* D) {
- if (!D->isInstance())
- return;
-
- if (CGDebugInfo *DI = getModuleDebugInfo())
- if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) {
- const auto *ThisPtr = cast<PointerType>(D->getThisType(getContext()));
- DI->getOrCreateRecordType(ThisPtr->getPointeeType(), D->getLocation());
- }
+bool CodeGenModule::shouldOpportunisticallyEmitVTables() {
+ return CodeGenOpts.OptimizationLevel > 0;
}
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
@@ -1858,7 +1997,6 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
return;
if (const auto *Method = dyn_cast<CXXMethodDecl>(D)) {
- CompleteDIClassType(Method);
// Make sure to emit the definition(s) before we emit the thunks.
// This is necessary for the generation of certain thunks.
if (const auto *CD = dyn_cast<CXXConstructorDecl>(Method))
@@ -1893,13 +2031,10 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
///
/// If D is non-null, it specifies a decl that correspond to this. This is used
/// to set the attributes on the function when it is first created.
-llvm::Constant *
-CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
- llvm::Type *Ty,
- GlobalDecl GD, bool ForVTable,
- bool DontDefer, bool IsThunk,
- llvm::AttributeSet ExtraAttrs,
- ForDefinition_t IsForDefinition) {
+llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
+ StringRef MangledName, llvm::Type *Ty, GlobalDecl GD, bool ForVTable,
+ bool DontDefer, bool IsThunk, llvm::AttributeList ExtraAttrs,
+ ForDefinition_t IsForDefinition) {
const Decl *D = GD.getDecl();
// Lookup the entry, lazily creating it if necessary.
@@ -1989,12 +2124,9 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
assert(F->getName() == MangledName && "name was uniqued!");
if (D)
SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk);
- if (ExtraAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex)) {
- llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeSet::FunctionIndex);
- F->addAttributes(llvm::AttributeSet::FunctionIndex,
- llvm::AttributeSet::get(VMContext,
- llvm::AttributeSet::FunctionIndex,
- B));
+ if (ExtraAttrs.hasAttributes(llvm::AttributeList::FunctionIndex)) {
+ llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex);
+ F->addAttributes(llvm::AttributeList::FunctionIndex, B);
}
if (!DontDefer) {
@@ -2004,7 +2136,7 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
if (D && isa<CXXDestructorDecl>(D) &&
getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
GD.getDtorType()))
- addDeferredDeclToEmit(F, GD);
+ addDeferredDeclToEmit(GD);
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
@@ -2014,7 +2146,7 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
// Move the potentially referenced deferred decl to the
// DeferredDeclsToEmit list, and remove it from DeferredDecls (since we
// don't need it anymore).
- addDeferredDeclToEmit(F, DDI->second);
+ addDeferredDeclToEmit(DDI->second);
DeferredDecls.erase(DDI);
// Otherwise, there are cases we have to worry about where we're
@@ -2034,7 +2166,7 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
FD = FD->getPreviousDecl()) {
if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
if (FD->doesThisDeclarationHaveABody()) {
- addDeferredDeclToEmit(F, GD.getWithDecl(FD));
+ addDeferredDeclToEmit(GD.getWithDecl(FD));
break;
}
}
@@ -2069,7 +2201,7 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
StringRef MangledName = getMangledName(GD);
return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable, DontDefer,
- /*IsThunk=*/false, llvm::AttributeSet(),
+ /*IsThunk=*/false, llvm::AttributeList(),
IsForDefinition);
}
@@ -2115,7 +2247,7 @@ GetRuntimeFunctionDecl(ASTContext &C, StringRef Name) {
/// type and name.
llvm::Constant *
CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name,
- llvm::AttributeSet ExtraAttrs,
+ llvm::AttributeList ExtraAttrs,
bool Local) {
llvm::Constant *C =
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
@@ -2143,9 +2275,8 @@ CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name,
/// CreateBuiltinFunction - Create a new builtin function with the specified
/// type and name.
llvm::Constant *
-CodeGenModule::CreateBuiltinFunction(llvm::FunctionType *FTy,
- StringRef Name,
- llvm::AttributeSet ExtraAttrs) {
+CodeGenModule::CreateBuiltinFunction(llvm::FunctionType *FTy, StringRef Name,
+ llvm::AttributeList ExtraAttrs) {
llvm::Constant *C =
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
/*DontDefer=*/false, /*IsThunk=*/false, ExtraAttrs);
@@ -2236,11 +2367,13 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
return llvm::ConstantExpr::getBitCast(Entry, Ty);
}
- unsigned AddrSpace = GetGlobalVarAddressSpace(D, Ty->getAddressSpace());
+ auto AddrSpace = GetGlobalVarAddressSpace(D);
+ auto TargetAddrSpace = getContext().getTargetAddressSpace(AddrSpace);
+
auto *GV = new llvm::GlobalVariable(
getModule(), Ty->getElementType(), false,
llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr,
- llvm::GlobalVariable::NotThreadLocal, AddrSpace);
+ llvm::GlobalVariable::NotThreadLocal, TargetAddrSpace);
// If we already created a global with the same mangled name (but different
// type) before, take its name and remove it from its parent.
@@ -2263,7 +2396,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
if (DDI != DeferredDecls.end()) {
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
// list, and remove it from DeferredDecls (since we don't need it anymore).
- addDeferredDeclToEmit(GV, DDI->second);
+ addDeferredDeclToEmit(DDI->second);
DeferredDecls.erase(DDI);
}
@@ -2297,8 +2430,15 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
GV->setSection(".cp.rodata");
}
- if (AddrSpace != Ty->getAddressSpace())
- return llvm::ConstantExpr::getAddrSpaceCast(GV, Ty);
+ auto ExpectedAS =
+ D ? D->getType().getAddressSpace()
+ : static_cast<unsigned>(LangOpts.OpenCL ? LangAS::opencl_global
+ : LangAS::Default);
+ assert(getContext().getTargetAddressSpace(ExpectedAS) ==
+ Ty->getPointerAddressSpace());
+ if (AddrSpace != ExpectedAS)
+ return getTargetCodeGenInfo().performAddrSpaceCast(*this, GV, AddrSpace,
+ ExpectedAS, Ty);
return GV;
}
@@ -2432,18 +2572,28 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
getDataLayout().getTypeStoreSizeInBits(Ty));
}
-unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D,
- unsigned AddrSpace) {
- if (D && LangOpts.CUDA && LangOpts.CUDAIsDevice) {
- if (D->hasAttr<CUDAConstantAttr>())
- AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_constant);
- else if (D->hasAttr<CUDASharedAttr>())
- AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_shared);
+unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) {
+ unsigned AddrSpace;
+ if (LangOpts.OpenCL) {
+ AddrSpace = D ? D->getType().getAddressSpace()
+ : static_cast<unsigned>(LangAS::opencl_global);
+ assert(AddrSpace == LangAS::opencl_global ||
+ AddrSpace == LangAS::opencl_constant ||
+ AddrSpace == LangAS::opencl_local ||
+ AddrSpace >= LangAS::FirstTargetAddressSpace);
+ return AddrSpace;
+ }
+
+ if (LangOpts.CUDA && LangOpts.CUDAIsDevice) {
+ if (D && D->hasAttr<CUDAConstantAttr>())
+ return LangAS::cuda_constant;
+ else if (D && D->hasAttr<CUDASharedAttr>())
+ return LangAS::cuda_shared;
else
- AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_device);
+ return LangAS::cuda_device;
}
- return AddrSpace;
+ return getTargetCodeGenInfo().getGlobalVarAddressSpace(*this, D);
}
template<typename SomeDecl>
@@ -2596,10 +2746,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
// "extern int x[];") and then a definition of a different type (e.g.
// "int x[10];"). This also happens when an initializer has a different type
// from the type of the global (this happens with unions).
- if (!GV ||
- GV->getType()->getElementType() != InitType ||
+ if (!GV || GV->getType()->getElementType() != InitType ||
GV->getType()->getAddressSpace() !=
- GetGlobalVarAddressSpace(D, getContext().getTargetAddressSpace(ASTTy))) {
+ getContext().getTargetAddressSpace(GetGlobalVarAddressSpace(D))) {
// Move the old entry aside so that we'll create a new one.
Entry->setName(StringRef());
@@ -2751,6 +2900,14 @@ static bool isVarDeclStrongDefinition(const ASTContext &Context,
if (D->hasAttr<SectionAttr>())
return true;
+ // A variable cannot be both common and exist in a section.
+ // We dont try to determine which is the right section in the front-end.
+ // If no specialized section name is applicable, it will resort to default.
+ if (D->hasAttr<PragmaClangBSSSectionAttr>() ||
+ D->hasAttr<PragmaClangDataSectionAttr>() ||
+ D->hasAttr<PragmaClangRodataSectionAttr>())
+ return true;
+
// Thread local vars aren't considered common linkage.
if (D->getTLSKind())
return true;
@@ -2803,7 +2960,7 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator(
// We are guaranteed to have a strong definition somewhere else,
// so we can use available_externally linkage.
if (Linkage == GVA_AvailableExternally)
- return llvm::Function::AvailableExternallyLinkage;
+ return llvm::GlobalValue::AvailableExternallyLinkage;
// Note that Apple's kernel linker doesn't support symbol
// coalescing, so we need to avoid linkonce and weak linkages there.
@@ -2897,14 +3054,8 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
continue;
// Get the call site's attribute list.
- SmallVector<llvm::AttributeSet, 8> newAttrs;
- llvm::AttributeSet oldAttrs = callSite.getAttributes();
-
- // Collect any return attributes from the call.
- if (oldAttrs.hasAttributes(llvm::AttributeSet::ReturnIndex))
- newAttrs.push_back(
- llvm::AttributeSet::get(newFn->getContext(),
- oldAttrs.getRetAttributes()));
+ SmallVector<llvm::AttributeSet, 8> newArgAttrs;
+ llvm::AttributeList oldAttrs = callSite.getAttributes();
// If the function was passed too few arguments, don't transform.
unsigned newNumArgs = newFn->arg_size();
@@ -2914,27 +3065,19 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
// If any of the types mismatch, we don't transform.
unsigned argNo = 0;
bool dontTransform = false;
- for (llvm::Function::arg_iterator ai = newFn->arg_begin(),
- ae = newFn->arg_end(); ai != ae; ++ai, ++argNo) {
- if (callSite.getArgument(argNo)->getType() != ai->getType()) {
+ for (llvm::Argument &A : newFn->args()) {
+ if (callSite.getArgument(argNo)->getType() != A.getType()) {
dontTransform = true;
break;
}
// Add any parameter attributes.
- if (oldAttrs.hasAttributes(argNo + 1))
- newAttrs.
- push_back(llvm::
- AttributeSet::get(newFn->getContext(),
- oldAttrs.getParamAttributes(argNo + 1)));
+ newArgAttrs.push_back(oldAttrs.getParamAttributes(argNo));
+ argNo++;
}
if (dontTransform)
continue;
- if (oldAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex))
- newAttrs.push_back(llvm::AttributeSet::get(newFn->getContext(),
- oldAttrs.getFnAttributes()));
-
// Okay, we can transform this. Create the new call instruction and copy
// over the required information.
newArgs.append(callSite.arg_begin(), callSite.arg_begin() + argNo);
@@ -2958,8 +3101,9 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
if (!newCall->getType()->isVoidTy())
newCall->takeName(callSite.getInstruction());
- newCall.setAttributes(
- llvm::AttributeSet::get(newFn->getContext(), newAttrs));
+ newCall.setAttributes(llvm::AttributeList::get(
+ newFn->getContext(), oldAttrs.getFnAttributes(),
+ oldAttrs.getRetAttributes(), newArgAttrs));
newCall.setCallingConv(callSite.getCallingConv());
// Finally, remove the old call, replacing any uses with the new one.
@@ -3341,6 +3485,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm_unreachable("unknown file format");
case llvm::Triple::COFF:
case llvm::Triple::ELF:
+ case llvm::Triple::Wasm:
GV->setSection("cfstring");
break;
case llvm::Triple::MachO:
@@ -3612,20 +3757,26 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
Linkage = llvm::GlobalVariable::InternalLinkage;
}
}
- unsigned AddrSpace = GetGlobalVarAddressSpace(
- VD, getContext().getTargetAddressSpace(MaterializedType));
+ unsigned AddrSpace =
+ VD ? GetGlobalVarAddressSpace(VD) : MaterializedType.getAddressSpace();
+ auto TargetAS = getContext().getTargetAddressSpace(AddrSpace);
auto *GV = new llvm::GlobalVariable(
getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(),
- /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal,
- AddrSpace);
+ /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
setGlobalVisibility(GV, VD);
GV->setAlignment(Align.getQuantity());
if (supportsCOMDAT() && GV->isWeakForLinker())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
if (VD->getTLSKind())
setTLSMode(GV, *VD);
- MaterializedGlobalTemporaryMap[E] = GV;
- return ConstantAddress(GV, Align);
+ llvm::Constant *CV = GV;
+ if (AddrSpace != LangAS::Default)
+ CV = getTargetCodeGenInfo().performAddrSpaceCast(
+ *this, GV, AddrSpace, LangAS::Default,
+ Type->getPointerTo(
+ getContext().getTargetAddressSpace(LangAS::Default)));
+ MaterializedGlobalTemporaryMap[E] = CV;
+ return ConstantAddress(CV, Align);
}
/// EmitObjCPropertyImplementations - Emit information for synthesized
@@ -3767,11 +3918,16 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
AddDeferredUnusedCoverageMapping(D);
break;
+ case Decl::CXXDeductionGuide:
+ // Function-like, but does not result in code emission.
+ break;
+
case Decl::Var:
case Decl::Decomposition:
// Skip variable templates
if (cast<VarDecl>(D)->getDescribedVarTemplate())
return;
+ LLVM_FALLTHROUGH;
case Decl::VarTemplateSpecialization:
EmitGlobal(cast<VarDecl>(D));
if (auto *DD = dyn_cast<DecompositionDecl>(D))
@@ -3790,6 +3946,11 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
EmitDeclContext(cast<NamespaceDecl>(D));
break;
case Decl::CXXRecord:
+ if (DebugInfo) {
+ if (auto *ES = D->getASTContext().getExternalSource())
+ if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never)
+ DebugInfo->completeUnusedClass(cast<CXXRecordDecl>(*D));
+ }
// Emit any static data members, they may be definitions.
for (auto *I : cast<CXXRecordDecl>(D)->decls())
if (isa<VarDecl>(I) || isa<CXXRecordDecl>(I))
@@ -4338,18 +4499,19 @@ void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
// Make a copy of the features as passed on the command line into the
// beginning of the additional features from the function to override.
- ParsedAttr.first.insert(ParsedAttr.first.begin(),
+ ParsedAttr.Features.insert(ParsedAttr.Features.begin(),
Target.getTargetOpts().FeaturesAsWritten.begin(),
Target.getTargetOpts().FeaturesAsWritten.end());
- if (ParsedAttr.second != "")
- TargetCPU = ParsedAttr.second;
+ if (ParsedAttr.Architecture != "")
+ TargetCPU = ParsedAttr.Architecture ;
// Now populate the feature map, first with the TargetCPU which is either
// the default or a new one from the target attribute string. Then we'll use
// the passed in features (FeaturesAsWritten) along with the new ones from
// the attribute.
- Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, ParsedAttr.first);
+ Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU,
+ ParsedAttr.Features);
} else {
Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU,
Target.getTargetOpts().Features);
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h
index 36f6785..b162e72 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h
@@ -28,6 +28,7 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SanitizerBlacklist.h"
+#include "clang/Basic/XRayLists.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -314,14 +315,9 @@ private:
/// This is a list of deferred decls which we have seen that *are* actually
/// referenced. These get code generated when the module is done.
- struct DeferredGlobal {
- DeferredGlobal(llvm::GlobalValue *GV, GlobalDecl GD) : GV(GV), GD(GD) {}
- llvm::TrackingVH<llvm::GlobalValue> GV;
- GlobalDecl GD;
- };
- std::vector<DeferredGlobal> DeferredDeclsToEmit;
- void addDeferredDeclToEmit(llvm::GlobalValue *GV, GlobalDecl GD) {
- DeferredDeclsToEmit.emplace_back(GV, GD);
+ std::vector<GlobalDecl> DeferredDeclsToEmit;
+ void addDeferredDeclToEmit(GlobalDecl GD) {
+ DeferredDeclsToEmit.emplace_back(GD);
}
/// List of alias we have emitted. Used to make sure that what they point to
@@ -345,11 +341,14 @@ private:
/// A queue of (optional) vtables to consider emitting.
std::vector<const CXXRecordDecl*> DeferredVTables;
+ /// A queue of (optional) vtables that may be emitted opportunistically.
+ std::vector<const CXXRecordDecl *> OpportunisticVTables;
+
/// List of global values which are required to be present in the object file;
/// bitcast to i8*. This is used for forcing visibility of symbols which may
/// otherwise be optimized out.
- std::vector<llvm::WeakVH> LLVMUsed;
- std::vector<llvm::WeakVH> LLVMCompilerUsed;
+ std::vector<llvm::WeakTrackingVH> LLVMUsed;
+ std::vector<llvm::WeakTrackingVH> LLVMCompilerUsed;
/// Store the list of global constructors and their respective priorities to
/// be emitted when the translation unit is complete.
@@ -420,7 +419,7 @@ private:
SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits;
/// Global destructor functions and arguments that need to run on termination.
- std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors;
+ std::vector<std::pair<llvm::WeakTrackingVH, llvm::Constant *>> CXXGlobalDtors;
/// \brief The complete set of modules that has been imported.
llvm::SetVector<clang::Module *> ImportedModules;
@@ -430,14 +429,14 @@ private:
llvm::SmallPtrSet<clang::Module *, 16> EmittedModuleInitializers;
/// \brief A vector of metadata strings.
- SmallVector<llvm::Metadata *, 16> LinkerOptionsMetadata;
+ SmallVector<llvm::MDNode *, 16> LinkerOptionsMetadata;
/// @name Cache for Objective-C runtime types
/// @{
/// Cached reference to the class for constant strings. This value has type
/// int * but is actually an Obj-C class pointer.
- llvm::WeakVH CFConstantStringClassRef;
+ llvm::WeakTrackingVH CFConstantStringClassRef;
/// \brief The type used to describe the state of a fast enumeration in
/// Objective-C's for..in loop.
@@ -454,7 +453,7 @@ private:
bool isTriviallyRecursive(const FunctionDecl *F);
bool shouldEmitFunction(GlobalDecl GD);
-
+ bool shouldOpportunisticallyEmitVTables();
/// Map used to be sure we don't emit the same CompoundLiteral twice.
llvm::DenseMap<const CompoundLiteralExpr *, llvm::GlobalVariable *>
EmittedCompoundLiterals;
@@ -546,6 +545,10 @@ public:
return *ObjCData;
}
+ // Version checking function, used to implement ObjC's @available:
+ // i32 @__isOSVersionAtLeast(i32, i32, i32)
+ llvm::Constant *IsOSVersionAtLeastFn = nullptr;
+
InstrProfStats &getPGOStats() { return PGOStats; }
llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); }
@@ -707,11 +710,15 @@ public:
SourceLocation Loc = SourceLocation(),
bool TLS = false);
- /// Return the address space of the underlying global variable for D, as
+ /// Return the AST address space of the underlying global variable for D, as
/// determined by its declaration. Normally this is the same as the address
/// space of D's type, but in CUDA, address spaces are associated with
- /// declarations, not types.
- unsigned GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace);
+ /// declarations, not types. If D is nullptr, return the default address
+ /// space for global variable.
+ ///
+ /// For languages without explicit address spaces, if D has default address
+ /// space, target-specific global or constant address space may be returned.
+ unsigned GetGlobalVarAddressSpace(const VarDecl *D);
/// Return the llvm::Constant for the address of the given global variable.
/// If Ty is non-null and if the global doesn't exist, then it will be created
@@ -906,14 +913,13 @@ public:
/// Create a new runtime function with the specified type and name.
llvm::Constant *
CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name,
- llvm::AttributeSet ExtraAttrs = llvm::AttributeSet(),
+ llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
bool Local = false);
/// Create a new compiler builtin function with the specified type and name.
- llvm::Constant *CreateBuiltinFunction(llvm::FunctionType *Ty,
- StringRef Name,
- llvm::AttributeSet ExtraAttrs =
- llvm::AttributeSet());
+ llvm::Constant *
+ CreateBuiltinFunction(llvm::FunctionType *Ty, StringRef Name,
+ llvm::AttributeList ExtraAttrs = llvm::AttributeList());
/// Create a new runtime global variable with the specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
StringRef Name);
@@ -1016,11 +1022,31 @@ public:
/// \param CalleeInfo - The callee information these attributes are being
/// constructed for. If valid, the attributes applied to this decl may
/// contribute to the function attributes and calling convention.
- /// \param PAL [out] - On return, the attribute list to use.
+ /// \param Attrs [out] - On return, the attribute list to use.
/// \param CallingConv [out] - On return, the LLVM calling convention to use.
void ConstructAttributeList(StringRef Name, const CGFunctionInfo &Info,
- CGCalleeInfo CalleeInfo, AttributeListType &PAL,
- unsigned &CallingConv, bool AttrOnCallSite);
+ CGCalleeInfo CalleeInfo,
+ llvm::AttributeList &Attrs, unsigned &CallingConv,
+ bool AttrOnCallSite);
+
+ /// Adds attributes to F according to our CodeGenOptions and LangOptions, as
+ /// though we had emitted it ourselves. We remove any attributes on F that
+ /// conflict with the attributes we add here.
+ ///
+ /// This is useful for adding attrs to bitcode modules that you want to link
+ /// with but don't control, such as CUDA's libdevice. When linking with such
+ /// a bitcode library, you might want to set e.g. its functions'
+ /// "unsafe-fp-math" attribute to match the attr of the functions you're
+ /// codegen'ing. Otherwise, LLVM will interpret the bitcode module's lack of
+ /// unsafe-fp-math attrs as tantamount to unsafe-fp-math=false, and then LLVM
+ /// will propagate unsafe-fp-math=false up to every transitive caller of a
+ /// function in the bitcode library!
+ ///
+ /// With the exception of fast-math attrs, this will only make the attributes
+ /// on the function more conservative. But it's unsafe to call this on a
+ /// function which relies on particular fast-math attributes for correctness.
+ /// It's up to you to ensure that this is safe.
+ void AddDefaultFnAttrs(llvm::Function &F);
// Fills in the supplied string map with the set of target features for the
// passed in function.
@@ -1036,13 +1062,14 @@ public:
void RefreshTypeCacheForClass(const CXXRecordDecl *Class);
- /// \brief Appends Opts to the "Linker Options" metadata value.
+ /// \brief Appends Opts to the "llvm.linker.options" metadata value.
void AppendLinkerOptions(StringRef Opts);
/// \brief Appends a detect mismatch command to the linker options.
void AddDetectMismatch(StringRef Name, StringRef Value);
- /// \brief Appends a dependent lib to the "Linker Options" metadata value.
+ /// \brief Appends a dependent lib to the "llvm.linker.options" metadata
+ /// value.
void AddDependentLib(StringRef Lib);
llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD);
@@ -1103,6 +1130,12 @@ public:
QualType Ty,
StringRef Category = StringRef()) const;
+ /// Imbue XRay attributes to a function, applying the always/never attribute
+ /// lists in the process. Returns true if we did imbue attributes this way,
+ /// false otherwise.
+ bool imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
+ StringRef Category = StringRef()) const;
+
SanitizerMetadata *getSanitizerMetadata() {
return SanitizerMD.get();
}
@@ -1176,7 +1209,7 @@ public:
void AddVTableTypeMetadata(llvm::GlobalVariable *VTable, CharUnits Offset,
const CXXRecordDecl *RD);
- /// \breif Get the declaration of std::terminate for the platform.
+ /// \brief Get the declaration of std::terminate for the platform.
llvm::Constant *getTerminateFn();
llvm::SanitizerStatReport &getSanStats();
@@ -1190,12 +1223,11 @@ public:
llvm::Constant *getNullPointer(llvm::PointerType *T, QualType QT);
private:
- llvm::Constant *
- GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
- bool ForVTable, bool DontDefer = false,
- bool IsThunk = false,
- llvm::AttributeSet ExtraAttrs = llvm::AttributeSet(),
- ForDefinition_t IsForDefinition = NotForDefinition);
+ llvm::Constant *GetOrCreateLLVMFunction(
+ StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable,
+ bool DontDefer = false, bool IsThunk = false,
+ llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
+ ForDefinition_t IsForDefinition = NotForDefinition);
llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *PTy,
@@ -1222,7 +1254,6 @@ private:
void EmitDeclContext(const DeclContext *DC);
void EmitLinkageSpec(const LinkageSpecDecl *D);
- void CompleteDIClassType(const CXXMethodDecl* D);
/// \brief Emit the function that initializes C++ thread_local variables.
void EmitCXXThreadLocalInitFunc();
@@ -1255,6 +1286,12 @@ private:
/// Emit any needed decls for which code generation was deferred.
void EmitDeferred();
+ /// Try to emit external vtables as available_externally if they have emitted
+ /// all inlined virtual functions. It runs after EmitDeferred() and therefore
+ /// is not allowed to create new references to things that need to be emitted
+ /// lazily.
+ void EmitVTablesOpportunistically();
+
/// Call replaceAllUsesWith on all pairs in Replacements.
void applyReplacements();
@@ -1266,6 +1303,10 @@ private:
/// Emit any vtables which we deferred and still have a use for.
void EmitDeferredVTables();
+ /// Emit a dummy function that reference a CoreFoundation symbol when
+ /// @available is used on Darwin.
+ void emitAtAvailableLinkGuard();
+
/// Emit the llvm.used and llvm.compiler.used metadata.
void emitLLVMUsed();
@@ -1284,6 +1325,9 @@ private:
/// Emits target specific Metadata for global declarations.
void EmitTargetMetadata();
+ /// Emits OpenCL specific Metadata e.g. OpenCL version.
+ void EmitOpenCLMetadata();
+
/// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and
/// .gcda files in a way that persists in .bc files.
void EmitCoverageFile();
@@ -1304,6 +1348,12 @@ private:
/// Check whether we can use a "simpler", more core exceptions personality
/// function.
void SimplifyPersonality();
+
+ /// Helper function for ConstructAttributeList and AddDefaultFnAttrs.
+ /// Constructs an AttrList for a function with the given properties.
+ void ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
+ bool AttrOnCallSite,
+ llvm::AttrBuilder &FuncAttrs);
};
} // end namespace CodeGen
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp
index c6c3fa4..c3d66c1 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -612,11 +612,14 @@ uint64_t PGOHash::finalize() {
llvm::MD5::MD5Result Result;
MD5.final(Result);
using namespace llvm::support;
- return endian::read<uint64_t, little, unaligned>(Result);
+ return Result.low();
}
void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) {
const Decl *D = GD.getDecl();
+ if (!D->hasBody())
+ return;
+
bool InstrumentRegions = CGM.getCodeGenOpts().hasProfileClangInstr();
llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();
if (!InstrumentRegions && !PGOReader)
@@ -626,12 +629,14 @@ void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) {
// Constructors and destructors may be represented by several functions in IR.
// If so, instrument only base variant, others are implemented by delegation
// to the base one, it would be counted twice otherwise.
- if (CGM.getTarget().getCXXABI().hasConstructorVariants() &&
- ((isa<CXXConstructorDecl>(GD.getDecl()) &&
- GD.getCtorType() != Ctor_Base) ||
- (isa<CXXDestructorDecl>(GD.getDecl()) &&
- GD.getDtorType() != Dtor_Base))) {
+ if (CGM.getTarget().getCXXABI().hasConstructorVariants()) {
+ if (isa<CXXDestructorDecl>(D) && GD.getDtorType() != Dtor_Base)
return;
+
+ if (const auto *CCD = dyn_cast<CXXConstructorDecl>(D))
+ if (GD.getCtorType() != Ctor_Base &&
+ CodeGenFunction::IsConstructorDelegationValid(CCD))
+ return;
}
CGM.ClearUnusedCoverageMapping(D);
setFuncName(Fn);
@@ -664,7 +669,7 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
}
bool CodeGenPGO::skipRegionMappingForDecl(const Decl *D) {
- if (SkipCoverageMapping)
+ if (!D->getBody())
return true;
// Don't map the functions in system headers.
@@ -737,7 +742,8 @@ CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
Fn->setEntryCount(FunctionCount);
}
-void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S) {
+void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S,
+ llvm::Value *StepV) {
if (!CGM.getCodeGenOpts().hasProfileClangInstr() || !RegionCounterMap)
return;
if (!Builder.GetInsertBlock())
@@ -745,11 +751,18 @@ void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S) {
unsigned Counter = (*RegionCounterMap)[S];
auto *I8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment),
- {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
- Builder.getInt64(FunctionHash),
- Builder.getInt32(NumRegionCounters),
- Builder.getInt32(Counter)});
+
+ llvm::Value *Args[] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
+ Builder.getInt64(FunctionHash),
+ Builder.getInt32(NumRegionCounters),
+ Builder.getInt32(Counter), StepV};
+ if (!StepV)
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment),
+ makeArrayRef(Args, 4));
+ else
+ Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment_step),
+ makeArrayRef(Args));
}
// This method either inserts a call to the profile run-time during
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.h
index 4f229cd..0759e65 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenPGO.h
@@ -40,14 +40,11 @@ private:
std::unique_ptr<llvm::InstrProfRecord> ProfRecord;
std::vector<uint64_t> RegionCounts;
uint64_t CurrentRegionCount;
- /// \brief A flag that is set to true when this function doesn't need
- /// to have coverage mapping data.
- bool SkipCoverageMapping;
public:
CodeGenPGO(CodeGenModule &CGM)
- : CGM(CGM), NumValueSites({{0}}), NumRegionCounters(0),
- FunctionHash(0), CurrentRegionCount(0), SkipCoverageMapping(false) {}
+ : CGM(CGM), NumValueSites({{0}}), NumRegionCounters(0), FunctionHash(0),
+ CurrentRegionCount(0) {}
/// Whether or not we have PGO region data for the current function. This is
/// false both when we have no data at all and when our data has been
@@ -105,7 +102,8 @@ private:
void emitCounterRegionMapping(const Decl *D);
public:
- void emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S);
+ void emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S,
+ llvm::Value *StepV);
/// Return the region count for the counter at the given index.
uint64_t getRegionCount(const Stmt *S) {
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp
index 04224e7..8a75a55 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp
@@ -139,6 +139,12 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
}
}
+ // C++1z [basic.lval]p10: "If a program attempts to access the stored value of
+ // an object through a glvalue of other than one of the following types the
+ // behavior is undefined: [...] a char, unsigned char, or std::byte type."
+ if (Ty->isStdByteType())
+ return MetadataCache[Ty] = getChar();
+
// Handle pointers.
// TODO: Implement C++'s type "similarity" and consider dis-"similar"
// pointers distinct.
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h
index 47e26bc..450eab4 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h
@@ -60,6 +60,12 @@ struct CodeGenTypeCache {
llvm::PointerType *Int8PtrPtrTy;
};
+ /// void* in alloca address space
+ union {
+ llvm::PointerType *AllocaVoidPtrTy;
+ llvm::PointerType *AllocaInt8PtrTy;
+ };
+
/// The size and alignment of the builtin C type 'int'. This comes
/// up enough in various ABI lowering tasks to be worth pre-computing.
union {
@@ -88,6 +94,8 @@ struct CodeGenTypeCache {
unsigned char SizeAlignInBytes;
};
+ unsigned ASTAllocaAddressSpace;
+
CharUnits getSizeSize() const {
return CharUnits::fromQuantity(SizeSizeInBytes);
}
@@ -105,6 +113,8 @@ struct CodeGenTypeCache {
llvm::CallingConv::ID getRuntimeCC() const { return RuntimeCC; }
llvm::CallingConv::ID BuiltinCC;
llvm::CallingConv::ID getBuiltinCC() const { return BuiltinCC; }
+
+ unsigned getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; }
};
} // end namespace CodeGen
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp
index adb40c8..9306c4f 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -44,6 +44,10 @@ CodeGenTypes::~CodeGenTypes() {
delete &*I++;
}
+const CodeGenOptions &CodeGenTypes::getCodeGenOpts() const {
+ return CGM.getCodeGenOpts();
+}
+
void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
llvm::StructType *Ty,
StringRef suffix) {
@@ -472,7 +476,6 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(Ty);
break;
@@ -487,10 +490,11 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
break;
}
case Type::Auto:
- llvm_unreachable("Unexpected undeduced auto type!");
+ case Type::DeducedTemplateSpecialization:
+ llvm_unreachable("Unexpected undeduced type!");
case Type::Complex: {
llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType());
- ResultType = llvm::StructType::get(EltTy, EltTy, nullptr);
+ ResultType = llvm::StructType::get(EltTy, EltTy);
break;
}
case Type::LValueReference:
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h
index 2ce6591..9d0e3de 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h
@@ -178,6 +178,7 @@ public:
const TargetInfo &getTarget() const { return Target; }
CGCXXABI &getCXXABI() const { return TheCXXABI; }
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
+ const CodeGenOptions &getCodeGenOpts() const;
/// ConvertType - Convert type T into a llvm::Type.
llvm::Type *ConvertType(QualType T);
@@ -303,11 +304,14 @@ public:
const CGFunctionInfo &arrangeCXXConstructorCall(const CallArgList &Args,
const CXXConstructorDecl *D,
CXXCtorType CtorKind,
- unsigned ExtraArgs);
+ unsigned ExtraPrefixArgs,
+ unsigned ExtraSuffixArgs,
+ bool PassProtoArgs = true);
const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
const FunctionProtoType *type,
- RequiredArgs required);
+ RequiredArgs required,
+ unsigned numPrefixArgs);
const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD,
CXXCtorType CT);
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h b/contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h
deleted file mode 100644
index 40b34a9..0000000
--- a/contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h
+++ /dev/null
@@ -1,444 +0,0 @@
-//===----- ConstantBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class provides a convenient interface for building complex
-// global initializers.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_CODEGEN_CONSTANTBUILDER_H
-#define LLVM_CLANG_LIB_CODEGEN_CONSTANTBUILDER_H
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/IR/Constants.h"
-
-#include "CodeGenModule.h"
-
-#include <vector>
-
-namespace clang {
-namespace CodeGen {
-
-class ConstantStructBuilder;
-class ConstantArrayBuilder;
-
-/// A convenience builder class for complex constant initializers,
-/// especially for anonymous global structures used by various language
-/// runtimes.
-///
-/// The basic usage pattern is expected to be something like:
-/// ConstantInitBuilder builder(CGM);
-/// auto toplevel = builder.beginStruct();
-/// toplevel.addInt(CGM.SizeTy, widgets.size());
-/// auto widgetArray = builder.beginArray();
-/// for (auto &widget : widgets) {
-/// auto widgetDesc = widgetArray.beginStruct();
-/// widgetDesc.addInt(CGM.SizeTy, widget.getPower());
-/// widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName()));
-/// widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl()));
-/// widgetArray.add(widgetDesc.finish());
-/// }
-/// toplevel.add(widgetArray.finish());
-/// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align,
-/// /*constant*/ true);
-class ConstantInitBuilder {
- struct SelfReference {
- llvm::GlobalVariable *Dummy;
- llvm::SmallVector<llvm::Constant*, 4> Indices;
-
- SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {}
- };
- CodeGenModule &CGM;
- llvm::SmallVector<llvm::Constant*, 16> Buffer;
- std::vector<SelfReference> SelfReferences;
- bool Frozen = false;
-
-public:
- explicit ConstantInitBuilder(CodeGenModule &CGM) : CGM(CGM) {}
-
- ~ConstantInitBuilder() {
- assert(Buffer.empty() && "didn't claim all values out of buffer");
- }
-
- class AggregateBuilderBase {
- protected:
- ConstantInitBuilder &Builder;
- AggregateBuilderBase *Parent;
- size_t Begin;
- bool Finished = false;
- bool Frozen = false;
-
- llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
- return Builder.Buffer;
- }
-
- const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
- return Builder.Buffer;
- }
-
- AggregateBuilderBase(ConstantInitBuilder &builder,
- AggregateBuilderBase *parent)
- : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) {
- if (parent) {
- assert(!parent->Frozen && "parent already has child builder active");
- parent->Frozen = true;
- } else {
- assert(!builder.Frozen && "builder already has child builder active");
- builder.Frozen = true;
- }
- }
-
- ~AggregateBuilderBase() {
- assert(Finished && "didn't finish aggregate builder");
- }
-
- void markFinished() {
- assert(!Frozen && "child builder still active");
- assert(!Finished && "builder already finished");
- Finished = true;
- if (Parent) {
- assert(Parent->Frozen &&
- "parent not frozen while child builder active");
- Parent->Frozen = false;
- } else {
- assert(Builder.Frozen &&
- "builder not frozen while child builder active");
- Builder.Frozen = false;
- }
- }
-
- public:
- // Not copyable.
- AggregateBuilderBase(const AggregateBuilderBase &) = delete;
- AggregateBuilderBase &operator=(const AggregateBuilderBase &) = delete;
-
- // Movable, mostly to allow returning. But we have to write this out
- // properly to satisfy the assert in the destructor.
- AggregateBuilderBase(AggregateBuilderBase &&other)
- : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin),
- Finished(other.Finished), Frozen(other.Frozen) {
- other.Finished = false;
- }
- AggregateBuilderBase &operator=(AggregateBuilderBase &&other) = delete;
-
- /// Abandon this builder completely.
- void abandon() {
- markFinished();
- auto &buffer = Builder.Buffer;
- buffer.erase(buffer.begin() + Begin, buffer.end());
- }
-
- /// Add a new value to this initializer.
- void add(llvm::Constant *value) {
- assert(value && "adding null value to constant initializer");
- assert(!Finished && "cannot add more values after finishing builder");
- assert(!Frozen && "cannot add values while subbuilder is active");
- Builder.Buffer.push_back(value);
- }
-
- /// Add an integer value of type size_t.
- void addSize(CharUnits size) {
- add(Builder.CGM.getSize(size));
- }
-
- /// Add an integer value of a specific type.
- void addInt(llvm::IntegerType *intTy, uint64_t value,
- bool isSigned = false) {
- add(llvm::ConstantInt::get(intTy, value, isSigned));
- }
-
- /// Add a null pointer of a specific type.
- void addNullPointer(llvm::PointerType *ptrTy) {
- add(llvm::ConstantPointerNull::get(ptrTy));
- }
-
- /// Add a bitcast of a value to a specific type.
- void addBitCast(llvm::Constant *value, llvm::Type *type) {
- add(llvm::ConstantExpr::getBitCast(value, type));
- }
-
- /// Add a bunch of new values to this initializer.
- void addAll(ArrayRef<llvm::Constant *> values) {
- assert(!Finished && "cannot add more values after finishing builder");
- assert(!Frozen && "cannot add values while subbuilder is active");
- Builder.Buffer.append(values.begin(), values.end());
- }
-
- /// An opaque class to hold the abstract position of a placeholder.
- class PlaceholderPosition {
- size_t Index;
- friend class AggregateBuilderBase;
- PlaceholderPosition(size_t index) : Index(index) {}
- };
-
- /// Add a placeholder value to the structure. The returned position
- /// can be used to set the value later; it will not be invalidated by
- /// any intermediate operations except (1) filling the same position or
- /// (2) finishing the entire builder.
- ///
- /// This is useful for emitting certain kinds of structure which
- /// contain some sort of summary field, generaly a count, before any
- /// of the data. By emitting a placeholder first, the structure can
- /// be emitted eagerly.
- PlaceholderPosition addPlaceholder() {
- assert(!Finished && "cannot add more values after finishing builder");
- assert(!Frozen && "cannot add values while subbuilder is active");
- Builder.Buffer.push_back(nullptr);
- return Builder.Buffer.size() - 1;
- }
-
- /// Fill a previously-added placeholder.
- void fillPlaceholderWithInt(PlaceholderPosition position,
- llvm::IntegerType *type, uint64_t value,
- bool isSigned = false) {
- fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned));
- }
-
- /// Fill a previously-added placeholder.
- void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) {
- assert(!Finished && "cannot change values after finishing builder");
- assert(!Frozen && "cannot add values while subbuilder is active");
- llvm::Constant *&slot = Builder.Buffer[position.Index];
- assert(slot == nullptr && "placeholder already filled");
- slot = value;
- }
-
- /// Produce an address which will eventually point to the the next
- /// position to be filled. This is computed with an indexed
- /// getelementptr rather than by computing offsets.
- ///
- /// The returned pointer will have type T*, where T is the given
- /// position.
- llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type) {
- // Make a global variable. We will replace this with a GEP to this
- // position after installing the initializer.
- auto dummy =
- new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
- llvm::GlobalVariable::PrivateLinkage,
- nullptr, "");
- Builder.SelfReferences.emplace_back(dummy);
- auto &entry = Builder.SelfReferences.back();
- (void) getGEPIndicesToCurrentPosition(entry.Indices);
- return dummy;
- }
-
- ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition(
- llvm::SmallVectorImpl<llvm::Constant*> &indices) {
- getGEPIndicesTo(indices, Builder.Buffer.size());
- return indices;
- }
-
- ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr);
- ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr);
-
- private:
- void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
- size_t position) const {
- // Recurse on the parent builder if present.
- if (Parent) {
- Parent->getGEPIndicesTo(indices, Begin);
-
- // Otherwise, add an index to drill into the first level of pointer.
- } else {
- assert(indices.empty());
- indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
- }
-
- assert(position >= Begin);
- // We have to use i32 here because struct GEPs demand i32 indices.
- // It's rather unlikely to matter in practice.
- indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
- position - Begin));
- }
- };
-
- template <class Impl>
- class AggregateBuilder : public AggregateBuilderBase {
- protected:
- AggregateBuilder(ConstantInitBuilder &builder,
- AggregateBuilderBase *parent)
- : AggregateBuilderBase(builder, parent) {}
-
- Impl &asImpl() { return *static_cast<Impl*>(this); }
-
- public:
- /// Given that this builder was created by beginning an array or struct
- /// component on the given parent builder, finish the array/struct
- /// component and add it to the parent.
- ///
- /// It is an intentional choice that the parent is passed in explicitly
- /// despite it being redundant with information already kept in the
- /// builder. This aids in readability by making it easier to find the
- /// places that add components to a builder, as well as "bookending"
- /// the sub-builder more explicitly.
- void finishAndAddTo(AggregateBuilderBase &parent) {
- assert(Parent == &parent && "adding to non-parent builder");
- parent.add(asImpl().finishImpl());
- }
-
- /// Given that this builder was created by beginning an array or struct
- /// directly on a ConstantInitBuilder, finish the array/struct and
- /// create a global variable with it as the initializer.
- template <class... As>
- llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) {
- assert(!Parent && "finishing non-root builder");
- return Builder.createGlobal(asImpl().finishImpl(),
- std::forward<As>(args)...);
- }
-
- /// Given that this builder was created by beginning an array or struct
- /// directly on a ConstantInitBuilder, finish the array/struct and
- /// set it as the initializer of the given global variable.
- void finishAndSetAsInitializer(llvm::GlobalVariable *global) {
- assert(!Parent && "finishing non-root builder");
- return Builder.setGlobalInitializer(global, asImpl().finishImpl());
- }
- };
-
- ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr);
-
- ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr);
-
-private:
- llvm::GlobalVariable *createGlobal(llvm::Constant *initializer,
- const llvm::Twine &name,
- CharUnits alignment,
- bool constant = false,
- llvm::GlobalValue::LinkageTypes linkage
- = llvm::GlobalValue::InternalLinkage,
- unsigned addressSpace = 0) {
- auto GV = new llvm::GlobalVariable(CGM.getModule(),
- initializer->getType(),
- constant,
- linkage,
- initializer,
- name,
- /*insert before*/ nullptr,
- llvm::GlobalValue::NotThreadLocal,
- addressSpace);
- GV->setAlignment(alignment.getQuantity());
- resolveSelfReferences(GV);
- return GV;
- }
-
- void setGlobalInitializer(llvm::GlobalVariable *GV,
- llvm::Constant *initializer) {
- GV->setInitializer(initializer);
- resolveSelfReferences(GV);
- }
-
- void resolveSelfReferences(llvm::GlobalVariable *GV) {
- for (auto &entry : SelfReferences) {
- llvm::Constant *resolvedReference =
- llvm::ConstantExpr::getInBoundsGetElementPtr(
- GV->getValueType(), GV, entry.Indices);
- entry.Dummy->replaceAllUsesWith(resolvedReference);
- entry.Dummy->eraseFromParent();
- }
- }
-};
-
-/// A helper class of ConstantInitBuilder, used for building constant
-/// array initializers.
-class ConstantArrayBuilder
- : public ConstantInitBuilder::AggregateBuilder<ConstantArrayBuilder> {
- llvm::Type *EltTy;
- friend class ConstantInitBuilder;
- template <class Impl> friend class ConstantInitBuilder::AggregateBuilder;
- ConstantArrayBuilder(ConstantInitBuilder &builder,
- AggregateBuilderBase *parent, llvm::Type *eltTy)
- : AggregateBuilder(builder, parent), EltTy(eltTy) {}
-public:
- size_t size() const {
- assert(!Finished);
- assert(!Frozen);
- assert(Begin <= getBuffer().size());
- return getBuffer().size() - Begin;
- }
-
- bool empty() const {
- return size() == 0;
- }
-
-private:
- /// Form an array constant from the values that have been added to this
- /// builder.
- llvm::Constant *finishImpl() {
- markFinished();
-
- auto &buffer = getBuffer();
- assert((Begin < buffer.size() ||
- (Begin == buffer.size() && EltTy))
- && "didn't add any array elements without element type");
- auto elts = llvm::makeArrayRef(buffer).slice(Begin);
- auto eltTy = EltTy ? EltTy : elts[0]->getType();
- auto type = llvm::ArrayType::get(eltTy, elts.size());
- auto constant = llvm::ConstantArray::get(type, elts);
- buffer.erase(buffer.begin() + Begin, buffer.end());
- return constant;
- }
-};
-
-inline ConstantArrayBuilder
-ConstantInitBuilder::beginArray(llvm::Type *eltTy) {
- return ConstantArrayBuilder(*this, nullptr, eltTy);
-}
-
-inline ConstantArrayBuilder
-ConstantInitBuilder::AggregateBuilderBase::beginArray(llvm::Type *eltTy) {
- return ConstantArrayBuilder(Builder, this, eltTy);
-}
-
-/// A helper class of ConstantInitBuilder, used for building constant
-/// struct initializers.
-class ConstantStructBuilder
- : public ConstantInitBuilder::AggregateBuilder<ConstantStructBuilder> {
- llvm::StructType *Ty;
- friend class ConstantInitBuilder;
- template <class Impl> friend class ConstantInitBuilder::AggregateBuilder;
- ConstantStructBuilder(ConstantInitBuilder &builder,
- AggregateBuilderBase *parent, llvm::StructType *ty)
- : AggregateBuilder(builder, parent), Ty(ty) {}
-
- /// Finish the struct.
- llvm::Constant *finishImpl() {
- markFinished();
-
- auto &buffer = getBuffer();
- assert(Begin < buffer.size() && "didn't add any struct elements?");
- auto elts = llvm::makeArrayRef(buffer).slice(Begin);
-
- llvm::Constant *constant;
- if (Ty) {
- constant = llvm::ConstantStruct::get(Ty, elts);
- } else {
- constant = llvm::ConstantStruct::getAnon(elts, /*packed*/ false);
- }
-
- buffer.erase(buffer.begin() + Begin, buffer.end());
- return constant;
- }
-};
-
-inline ConstantStructBuilder
-ConstantInitBuilder::beginStruct(llvm::StructType *structTy) {
- return ConstantStructBuilder(*this, nullptr, structTy);
-}
-
-inline ConstantStructBuilder
-ConstantInitBuilder::AggregateBuilderBase::beginStruct(
- llvm::StructType *structTy) {
- return ConstantStructBuilder(Builder, this, structTy);
-}
-
-} // end namespace CodeGen
-} // end namespace clang
-
-#endif
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ConstantInitBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ConstantInitBuilder.cpp
new file mode 100644
index 0000000..7f8d809
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/CodeGen/ConstantInitBuilder.cpp
@@ -0,0 +1,280 @@
+//===--- ConstantInitBuilder.cpp - Global initializer builder -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines out-of-line routines for building initializers for
+// global variables, in particular the kind of globals that are implicitly
+// introduced by various language ABIs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "CodeGenModule.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+llvm::Type *ConstantInitFuture::getType() const {
+ assert(Data && "dereferencing null future");
+ if (Data.is<llvm::Constant*>()) {
+ return Data.get<llvm::Constant*>()->getType();
+ } else {
+ return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType();
+ }
+}
+
+void ConstantInitFuture::abandon() {
+ assert(Data && "abandoning null future");
+ if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) {
+ builder->abandon(0);
+ }
+ Data = nullptr;
+}
+
+void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {
+ assert(Data && "installing null future");
+ if (Data.is<llvm::Constant*>()) {
+ GV->setInitializer(Data.get<llvm::Constant*>());
+ } else {
+ auto &builder = *Data.get<ConstantInitBuilderBase*>();
+ assert(builder.Buffer.size() == 1);
+ builder.setGlobalInitializer(GV, builder.Buffer[0]);
+ builder.Buffer.clear();
+ Data = nullptr;
+ }
+}
+
+ConstantInitFuture
+ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) {
+ assert(Buffer.empty() && "buffer not current empty");
+ Buffer.push_back(initializer);
+ return ConstantInitFuture(this);
+}
+
+// Only used in this file.
+inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder)
+ : Data(builder) {
+ assert(!builder->Frozen);
+ assert(builder->Buffer.size() == 1);
+ assert(builder->Buffer[0] != nullptr);
+}
+
+llvm::GlobalVariable *
+ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
+ const llvm::Twine &name,
+ CharUnits alignment,
+ bool constant,
+ llvm::GlobalValue::LinkageTypes linkage,
+ unsigned addressSpace) {
+ auto GV = new llvm::GlobalVariable(CGM.getModule(),
+ initializer->getType(),
+ constant,
+ linkage,
+ initializer,
+ name,
+ /*insert before*/ nullptr,
+ llvm::GlobalValue::NotThreadLocal,
+ addressSpace);
+ GV->setAlignment(alignment.getQuantity());
+ resolveSelfReferences(GV);
+ return GV;
+}
+
+void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
+ llvm::Constant *initializer){
+ GV->setInitializer(initializer);
+
+ if (!SelfReferences.empty())
+ resolveSelfReferences(GV);
+}
+
+void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {
+ for (auto &entry : SelfReferences) {
+ llvm::Constant *resolvedReference =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(
+ GV->getValueType(), GV, entry.Indices);
+ auto dummy = entry.Dummy;
+ dummy->replaceAllUsesWith(resolvedReference);
+ dummy->eraseFromParent();
+ }
+ SelfReferences.clear();
+}
+
+void ConstantInitBuilderBase::abandon(size_t newEnd) {
+ // Remove all the entries we've added.
+ Buffer.erase(Buffer.begin() + newEnd, Buffer.end());
+
+ // If we're abandoning all the way to the beginning, destroy
+ // all the self-references, because we might not get another
+ // opportunity.
+ if (newEnd == 0) {
+ for (auto &entry : SelfReferences) {
+ auto dummy = entry.Dummy;
+ dummy->replaceAllUsesWith(llvm::UndefValue::get(dummy->getType()));
+ dummy->eraseFromParent();
+ }
+ SelfReferences.clear();
+ }
+}
+
+void ConstantAggregateBuilderBase::addSize(CharUnits size) {
+ add(Builder.CGM.getSize(size));
+}
+
+llvm::Constant *
+ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
+ llvm::Constant *target) {
+ // Compute the address of the relative-address slot.
+ auto base = getAddrOfCurrentPosition(offsetType);
+
+ // Subtract.
+ base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
+ target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
+ llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
+
+ // Truncate to the relative-address type if necessary.
+ if (Builder.CGM.IntPtrTy != offsetType) {
+ offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
+ }
+
+ return offset;
+}
+
+llvm::Constant *
+ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) {
+ // Make a global variable. We will replace this with a GEP to this
+ // position after installing the initializer.
+ auto dummy =
+ new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
+ llvm::GlobalVariable::PrivateLinkage,
+ nullptr, "");
+ Builder.SelfReferences.emplace_back(dummy);
+ auto &entry = Builder.SelfReferences.back();
+ (void) getGEPIndicesToCurrentPosition(entry.Indices);
+ return dummy;
+}
+
+void ConstantAggregateBuilderBase::getGEPIndicesTo(
+ llvm::SmallVectorImpl<llvm::Constant*> &indices,
+ size_t position) const {
+ // Recurse on the parent builder if present.
+ if (Parent) {
+ Parent->getGEPIndicesTo(indices, Begin);
+
+ // Otherwise, add an index to drill into the first level of pointer.
+ } else {
+ assert(indices.empty());
+ indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
+ }
+
+ assert(position >= Begin);
+ // We have to use i32 here because struct GEPs demand i32 indices.
+ // It's rather unlikely to matter in practice.
+ indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
+ position - Begin));
+}
+
+ConstantAggregateBuilderBase::PlaceholderPosition
+ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) {
+ // Bring the offset up to the last field.
+ CharUnits offset = getNextOffsetFromGlobal();
+
+ // Create the placeholder.
+ auto position = addPlaceholder();
+
+ // Advance the offset past that field.
+ auto &layout = Builder.CGM.getDataLayout();
+ if (!Packed)
+ offset = offset.alignTo(CharUnits::fromQuantity(
+ layout.getABITypeAlignment(type)));
+ offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
+
+ CachedOffsetEnd = Builder.Buffer.size();
+ CachedOffsetFromGlobal = offset;
+
+ return position;
+}
+
+CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
+ size_t cacheEnd = CachedOffsetEnd;
+ assert(cacheEnd <= end);
+
+ // Fast path: if the cache is valid, just use it.
+ if (cacheEnd == end) {
+ return CachedOffsetFromGlobal;
+ }
+
+ // If the cached range ends before the index at which the current
+ // aggregate starts, recurse for the parent.
+ CharUnits offset;
+ if (cacheEnd < Begin) {
+ assert(cacheEnd == 0);
+ assert(Parent && "Begin != 0 for root builder");
+ cacheEnd = Begin;
+ offset = Parent->getOffsetFromGlobalTo(Begin);
+ } else {
+ offset = CachedOffsetFromGlobal;
+ }
+
+ // Perform simple layout on the elements in cacheEnd..<end.
+ if (cacheEnd != end) {
+ auto &layout = Builder.CGM.getDataLayout();
+ do {
+ llvm::Constant *element = Builder.Buffer[cacheEnd];
+ assert(element != nullptr &&
+ "cannot compute offset when a placeholder is present");
+ llvm::Type *elementType = element->getType();
+ if (!Packed)
+ offset = offset.alignTo(CharUnits::fromQuantity(
+ layout.getABITypeAlignment(elementType)));
+ offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
+ } while (++cacheEnd != end);
+ }
+
+ // Cache and return.
+ CachedOffsetEnd = cacheEnd;
+ CachedOffsetFromGlobal = offset;
+ return offset;
+}
+
+llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {
+ markFinished();
+
+ auto &buffer = getBuffer();
+ assert((Begin < buffer.size() ||
+ (Begin == buffer.size() && eltTy))
+ && "didn't add any array elements without element type");
+ auto elts = llvm::makeArrayRef(buffer).slice(Begin);
+ if (!eltTy) eltTy = elts[0]->getType();
+ auto type = llvm::ArrayType::get(eltTy, elts.size());
+ auto constant = llvm::ConstantArray::get(type, elts);
+ buffer.erase(buffer.begin() + Begin, buffer.end());
+ return constant;
+}
+
+llvm::Constant *
+ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
+ markFinished();
+
+ auto &buffer = getBuffer();
+ auto elts = llvm::makeArrayRef(buffer).slice(Begin);
+
+ if (ty == nullptr && elts.empty())
+ ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
+
+ llvm::Constant *constant;
+ if (ty) {
+ assert(ty->isPacked() == Packed);
+ constant = llvm::ConstantStruct::get(ty, elts);
+ } else {
+ constant = llvm::ConstantStruct::getAnon(elts, Packed);
+ }
+
+ buffer.erase(buffer.begin() + Begin, buffer.end());
+ return constant;
+}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp
index 5bc9e50..a102347 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -961,12 +961,10 @@ struct CounterCoverageMappingBuilder
}
};
-bool isMachO(const CodeGenModule &CGM) {
- return CGM.getTarget().getTriple().isOSBinFormatMachO();
-}
-
-StringRef getCoverageSection(const CodeGenModule &CGM) {
- return llvm::getInstrProfCoverageSectionName(isMachO(CGM));
+std::string getCoverageSection(const CodeGenModule &CGM) {
+ return llvm::getInstrProfSectionName(
+ llvm::IPSK_covmap,
+ CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
}
std::string normalizeFilename(StringRef Filename) {
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/EHScopeStack.h b/contrib/llvm/tools/clang/lib/CodeGen/EHScopeStack.h
index 2435830..c7bdeac 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/EHScopeStack.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/EHScopeStack.h
@@ -202,7 +202,7 @@ public:
template <std::size_t... Is>
T restore(CodeGenFunction &CGF, llvm::index_sequence<Is...>) {
// It's important that the restores are emitted in order. The braced init
- // list guarentees that.
+ // list guarantees that.
return T{DominatingValue<As>::restore(CGF, std::get<Is>(Saved))...};
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
index f7a8dd6..bd4cb9a 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -24,8 +24,8 @@
#include "CGVTables.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "ConstantBuilder.h"
#include "TargetInfo.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/Type.h"
#include "clang/AST/StmtCXX.h"
@@ -62,12 +62,20 @@ public:
bool classifyReturnType(CGFunctionInfo &FI) const override;
+ bool passClassIndirect(const CXXRecordDecl *RD) const {
+ // Clang <= 4 used the pre-C++11 rule, which ignores move operations.
+ // The PS4 platform ABI follows the behavior of Clang 3.2.
+ if (CGM.getCodeGenOpts().getClangABICompat() <=
+ CodeGenOptions::ClangABI::Ver4 ||
+ CGM.getTriple().getOS() == llvm::Triple::PS4)
+ return RD->hasNonTrivialDestructor() ||
+ RD->hasNonTrivialCopyConstructor();
+ return !canCopyArgument(RD);
+ }
+
RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared
- // special members.
- if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor())
+ // If C++ prohibits us from making a copy, pass by address.
+ if (passClassIndirect(RD))
return RAA_Indirect;
return RAA_Default;
}
@@ -207,8 +215,9 @@ public:
void EmitCXXConstructors(const CXXConstructorDecl *D) override;
- void buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
- SmallVectorImpl<CanQualType> &ArgTys) override;
+ AddedStructorArgs
+ buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
+ SmallVectorImpl<CanQualType> &ArgTys) override;
bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
CXXDtorType DT) const override {
@@ -225,11 +234,10 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF) override;
- unsigned addImplicitConstructorArgs(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
- CallArgList &Args) override;
+ AddedStructorArgs
+ addImplicitConstructorArgs(CodeGenFunction &CGF, const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating, CallArgList &Args) override;
void EmitDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *DD,
CXXDtorType Type, bool ForVirtualBase,
@@ -366,20 +374,30 @@ public:
void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
private:
- bool hasAnyVirtualInlineFunction(const CXXRecordDecl *RD) const {
- const auto &VtableLayout =
- CGM.getItaniumVTableContext().getVTableLayout(RD);
-
- for (const auto &VtableComponent : VtableLayout.vtable_components()) {
- // Skip empty slot.
- if (!VtableComponent.isUsedFunctionPointerKind())
- continue;
-
- const CXXMethodDecl *Method = VtableComponent.getFunctionDecl();
- if (Method->getCanonicalDecl()->isInlined())
- return true;
- }
- return false;
+ bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const {
+ const auto &VtableLayout =
+ CGM.getItaniumVTableContext().getVTableLayout(RD);
+
+ for (const auto &VtableComponent : VtableLayout.vtable_components()) {
+ // Skip empty slot.
+ if (!VtableComponent.isUsedFunctionPointerKind())
+ continue;
+
+ const CXXMethodDecl *Method = VtableComponent.getFunctionDecl();
+ if (!Method->getCanonicalDecl()->isInlined())
+ continue;
+
+ StringRef Name = CGM.getMangledName(VtableComponent.getGlobalDecl());
+ auto *Entry = CGM.GetGlobalValue(Name);
+ // This checks if virtual inline function has already been emitted.
+ // Note that it is possible that this inline function would be emitted
+ // after trying to emit vtable speculatively. Because of this we do
+ // an extra pass after emitting all deferred vtables to find and emit
+ // these vtables opportunistically.
+ if (!Entry || Entry->isDeclaration())
+ return true;
+ }
+ return false;
}
bool isVTableHidden(const CXXRecordDecl *RD) const {
@@ -499,7 +517,7 @@ llvm::Type *
ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
if (MPT->isMemberDataPointer())
return CGM.PtrDiffTy;
- return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy, nullptr);
+ return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy);
}
/// In the Itanium and ARM ABIs, method pointers have the form:
@@ -988,10 +1006,8 @@ bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
if (!RD)
return false;
- // Return indirectly if we have a non-trivial copy ctor or non-trivial dtor.
- // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared
- // special members.
- if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor()) {
+ // If C++ prohibits us from making a copy, return by address.
+ if (passClassIndirect(RD)) {
auto Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType());
FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
return true;
@@ -1134,8 +1150,8 @@ static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
// Mark the function as nounwind readonly.
llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,
llvm::Attribute::ReadOnly };
- llvm::AttributeSet Attrs = llvm::AttributeSet::get(
- CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex, FuncAttrs);
+ llvm::AttributeList Attrs = llvm::AttributeList::get(
+ CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs);
return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);
}
@@ -1353,7 +1369,7 @@ void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
}
}
-void
+CGCXXABI::AddedStructorArgs
ItaniumCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext();
@@ -1362,9 +1378,12 @@ ItaniumCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
// These are Clang types, so we don't need to worry about sret yet.
// Check if we need to add a VTT parameter (which has type void **).
- if (T == StructorType::Base && MD->getParent()->getNumVBases() != 0)
+ if (T == StructorType::Base && MD->getParent()->getNumVBases() != 0) {
ArgTys.insert(ArgTys.begin() + 1,
Context.getPointerType(Context.VoidPtrTy));
+ return AddedStructorArgs::prefix(1);
+ }
+ return AddedStructorArgs{};
}
void ItaniumCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
@@ -1395,9 +1414,9 @@ void ItaniumCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
// FIXME: avoid the fake decl
QualType T = Context.getPointerType(Context.VoidPtrTy);
- ImplicitParamDecl *VTTDecl
- = ImplicitParamDecl::Create(Context, nullptr, MD->getLocation(),
- &Context.Idents.get("vtt"), T);
+ auto *VTTDecl = ImplicitParamDecl::Create(
+ Context, /*DC=*/nullptr, MD->getLocation(), &Context.Idents.get("vtt"),
+ T, ImplicitParamDecl::CXXVTT);
Params.insert(Params.begin() + 1, VTTDecl);
getStructorImplicitParamDecl(CGF) = VTTDecl;
}
@@ -1429,11 +1448,11 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
-unsigned ItaniumCXXABI::addImplicitConstructorArgs(
+CGCXXABI::AddedStructorArgs ItaniumCXXABI::addImplicitConstructorArgs(
CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type,
bool ForVirtualBase, bool Delegating, CallArgList &Args) {
if (!NeedsVTTParameter(GlobalDecl(D, Type)))
- return 0;
+ return AddedStructorArgs{};
// Insert the implicit 'vtt' argument as the second argument.
llvm::Value *VTT =
@@ -1441,7 +1460,7 @@ unsigned ItaniumCXXABI::addImplicitConstructorArgs(
QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy);
Args.insert(Args.begin() + 1,
CallArg(RValue::get(VTT), VTTTy, /*needscopy=*/false));
- return 1; // Added one arg.
+ return AddedStructorArgs::prefix(1); // Added one arg.
}
void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
@@ -1684,11 +1703,11 @@ bool ItaniumCXXABI::canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const {
if (CGM.getLangOpts().AppleKext)
return false;
- // If we don't have any inline virtual functions, and if vtable is not hidden,
- // then we are safe to emit available_externally copy of vtable.
+ // If we don't have any not emitted inline virtual function, and if vtable is
+ // not hidden, then we are safe to emit available_externally copy of vtable.
// FIXME we can still emit a copy of the vtable if we
// can emit definition of the inline functions.
- return !hasAnyVirtualInlineFunction(RD) && !isVTableHidden(RD);
+ return !hasAnyUnusedVirtualInlineFunction(RD) && !isVTableHidden(RD);
}
static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
Address InitialPtr,
@@ -1907,10 +1926,11 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
GuardPtrTy, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind));
+ return CGM.CreateRuntimeFunction(
+ FTy, "__cxa_guard_acquire",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind));
}
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
@@ -1918,10 +1938,11 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
// void __cxa_guard_release(__guard *guard_object);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind));
+ return CGM.CreateRuntimeFunction(
+ FTy, "__cxa_guard_release",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind));
}
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
@@ -1929,10 +1950,11 @@ static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
// void __cxa_guard_abort(__guard *guard_object);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
- return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind));
+ return CGM.CreateRuntimeFunction(
+ FTy, "__cxa_guard_abort",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind));
}
namespace {
@@ -2015,10 +2037,11 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// The ABI says: "It is suggested that it be emitted in the same COMDAT
// group as the associated data object." In practice, this doesn't work for
- // non-ELF object formats, so only do it for ELF.
+ // non-ELF and non-Wasm object formats, so only do it for ELF and Wasm.
llvm::Comdat *C = var->getComdat();
if (!D.isLocalVarDecl() && C &&
- CGM.getTarget().getTriple().isOSBinFormatELF()) {
+ (CGM.getTarget().getTriple().isOSBinFormatELF() ||
+ CGM.getTarget().getTriple().isOSBinFormatWasm())) {
guard->setComdat(C);
// An inline variable's guard function is run from the per-TU
// initialization function, not via a dedicated global ctor function, so
@@ -2161,7 +2184,9 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
// Create a variable that binds the atexit to this shared object.
llvm::Constant *handle =
- CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle");
+ CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle");
+ auto *GV = cast<llvm::GlobalValue>(handle->stripPointerCasts());
+ GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
llvm::Value *args[] = {
llvm::ConstantExpr::getBitCast(dtor, dtorTy),
@@ -2567,6 +2592,9 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
if (!GV) {
// Create a new global variable.
+ // Note for the future: If we would ever like to do deferred emission of
+ // RTTI, check if emitting vtables opportunistically need any adjustment.
+
GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
/*Constant=*/true,
llvm::GlobalValue::ExternalLinkage, nullptr,
@@ -2634,7 +2662,6 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
return false;
@@ -2711,7 +2738,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
// function.
bool IsDLLImport = RD->hasAttr<DLLImportAttr>();
if (CGM.getVTables().isVTableExternal(RD))
- return IsDLLImport ? false : true;
+ return IsDLLImport && !CGM.getTriple().isWindowsItaniumEnvironment()
+ ? false
+ : true;
if (IsDLLImport)
return true;
@@ -2814,7 +2843,8 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
llvm_unreachable("References shouldn't get here");
case Type::Auto:
- llvm_unreachable("Undeduced auto type shouldn't get here");
+ case Type::DeducedTemplateSpecialization:
+ llvm_unreachable("Undeduced type shouldn't get here");
case Type::Pipe:
llvm_unreachable("Pipe types shouldn't get here");
@@ -2935,6 +2965,8 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
return llvm::GlobalValue::InternalLinkage;
case VisibleNoLinkage:
+ case ModuleInternalLinkage:
+ case ModuleLinkage:
case ExternalLinkage:
// RTTI is not enabled, which means that this type info struct is going
// to be used for exception handling. Give it linkonce_odr linkage.
@@ -2946,7 +2978,8 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
if (RD->hasAttr<WeakAttr>())
return llvm::GlobalValue::WeakODRLinkage;
if (CGM.getTriple().isWindowsItaniumEnvironment())
- if (RD->hasAttr<DLLImportAttr>())
+ if (RD->hasAttr<DLLImportAttr>() &&
+ ShouldUseExternalRTTIDescriptor(CGM, Ty))
return llvm::GlobalValue::ExternalLinkage;
if (RD->isDynamicClass()) {
llvm::GlobalValue::LinkageTypes LT = CGM.getVTableLinkage(RD);
@@ -3044,7 +3077,8 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force,
llvm_unreachable("References shouldn't get here");
case Type::Auto:
- llvm_unreachable("Undeduced auto type shouldn't get here");
+ case Type::DeducedTemplateSpecialization:
+ llvm_unreachable("Undeduced type shouldn't get here");
case Type::Pipe:
llvm_unreachable("Pipe type shouldn't get here");
@@ -3158,7 +3192,8 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force,
if (DLLExport || (RD && RD->hasAttr<DLLExportAttr>())) {
TypeName->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
- } else if (CGM.getLangOpts().RTTI && RD && RD->hasAttr<DLLImportAttr>()) {
+ } else if (RD && RD->hasAttr<DLLImportAttr>() &&
+ ShouldUseExternalRTTIDescriptor(CGM, Ty)) {
TypeName->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
@@ -3534,8 +3569,9 @@ static StructorCodegen getCodegenToUse(CodeGenModule &CGM,
return StructorCodegen::RAUW;
if (llvm::GlobalValue::isWeakForLinker(Linkage)) {
- // Only ELF supports COMDATs with arbitrary names (C5/D5).
- if (CGM.getTarget().getTriple().isOSBinFormatELF())
+ // Only ELF and wasm support COMDATs with arbitrary names (C5/D5).
+ if (CGM.getTarget().getTriple().isOSBinFormatELF() ||
+ CGM.getTarget().getTriple().isOSBinFormatWasm())
return StructorCodegen::COMDAT;
return StructorCodegen::Emit;
}
@@ -3919,9 +3955,8 @@ void ItaniumCXXABI::emitBeginCatch(CodeGenFunction &CGF,
static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {
llvm::FunctionType *fnTy =
llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- llvm::Constant *fnRef =
- CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate",
- llvm::AttributeSet(), /*Local=*/true);
+ llvm::Constant *fnRef = CGM.CreateRuntimeFunction(
+ fnTy, "__clang_call_terminate", llvm::AttributeList(), /*Local=*/true);
llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);
if (fn && fn->empty()) {
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp b/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp
new file mode 100644
index 0000000..a6f21d8
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.cpp
@@ -0,0 +1,208 @@
+//===--- MacroPPCallbacks.cpp ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains implementation for the macro preprocessors callbacks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MacroPPCallbacks.h"
+#include "CGDebugInfo.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Parse/Parser.h"
+
+using namespace clang;
+
+void MacroPPCallbacks::writeMacroDefinition(const IdentifierInfo &II,
+ const MacroInfo &MI,
+ Preprocessor &PP, raw_ostream &Name,
+ raw_ostream &Value) {
+ Name << II.getName();
+
+ if (MI.isFunctionLike()) {
+ Name << '(';
+ if (!MI.param_empty()) {
+ MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
+ for (; AI + 1 != E; ++AI) {
+ Name << (*AI)->getName();
+ Name << ',';
+ }
+
+ // Last argument.
+ if ((*AI)->getName() == "__VA_ARGS__")
+ Name << "...";
+ else
+ Name << (*AI)->getName();
+ }
+
+ if (MI.isGNUVarargs())
+ // #define foo(x...)
+ Name << "...";
+
+ Name << ')';
+ }
+
+ SmallString<128> SpellingBuffer;
+ bool First = true;
+ for (const auto &T : MI.tokens()) {
+ if (!First && T.hasLeadingSpace())
+ Value << ' ';
+
+ Value << PP.getSpelling(T, SpellingBuffer);
+ First = false;
+ }
+}
+
+MacroPPCallbacks::MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP)
+ : Gen(Gen), PP(PP), Status(NoScope) {}
+
+// This is the expected flow of enter/exit compiler and user files:
+// - Main File Enter
+// - <built-in> file enter
+// {Compiler macro definitions} - (Line=0, no scope)
+// - (Optional) <command line> file enter
+// {Command line macro definitions} - (Line=0, no scope)
+// - (Optional) <command line> file exit
+// {Command line file includes} - (Line=0, Main file scope)
+// {macro definitions and file includes} - (Line!=0, Parent scope)
+// - <built-in> file exit
+// {User code macro definitions and file includes} - (Line!=0, Parent scope)
+
+llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
+ if (Status == MainFileScope || Status == CommandLineIncludeScope)
+ return Scopes.back();
+ return nullptr;
+}
+
+SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) {
+ if (Status == MainFileScope || EnteredCommandLineIncludeFiles)
+ return Loc;
+
+ // While parsing skipped files, location of macros is invalid.
+ // Invalid location represents line zero.
+ return SourceLocation();
+}
+
+static bool isBuiltinFile(SourceManager &SM, SourceLocation Loc) {
+ StringRef Filename(SM.getPresumedLoc(Loc).getFilename());
+ return Filename.equals("<built-in>");
+}
+
+static bool isCommandLineFile(SourceManager &SM, SourceLocation Loc) {
+ StringRef Filename(SM.getPresumedLoc(Loc).getFilename());
+ return Filename.equals("<command line>");
+}
+
+void MacroPPCallbacks::updateStatusToNextScope() {
+ switch (Status) {
+ case NoScope:
+ Status = InitializedScope;
+ break;
+ case InitializedScope:
+ Status = BuiltinScope;
+ break;
+ case BuiltinScope:
+ Status = CommandLineIncludeScope;
+ break;
+ case CommandLineIncludeScope:
+ Status = MainFileScope;
+ break;
+ case MainFileScope:
+ llvm_unreachable("There is no next scope, already in the final scope");
+ }
+}
+
+void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
+ SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
+ switch (Status) {
+ case NoScope:
+ updateStatusToNextScope();
+ break;
+ case InitializedScope:
+ updateStatusToNextScope();
+ return;
+ case BuiltinScope:
+ if (isCommandLineFile(PP.getSourceManager(), Loc))
+ return;
+ updateStatusToNextScope();
+ LLVM_FALLTHROUGH;
+ case CommandLineIncludeScope:
+ EnteredCommandLineIncludeFiles++;
+ break;
+ case MainFileScope:
+ break;
+ }
+
+ Scopes.push_back(Gen->getCGDebugInfo()->CreateTempMacroFile(getCurrentScope(),
+ LineLoc, Loc));
+}
+
+void MacroPPCallbacks::FileExited(SourceLocation Loc) {
+ switch (Status) {
+ default:
+ llvm_unreachable("Do not expect to exit a file from current scope");
+ case BuiltinScope:
+ if (!isBuiltinFile(PP.getSourceManager(), Loc))
+ // Skip next scope and change status to MainFileScope.
+ Status = MainFileScope;
+ return;
+ case CommandLineIncludeScope:
+ if (!EnteredCommandLineIncludeFiles) {
+ updateStatusToNextScope();
+ return;
+ }
+ EnteredCommandLineIncludeFiles--;
+ break;
+ case MainFileScope:
+ break;
+ }
+
+ Scopes.pop_back();
+}
+
+void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) {
+ // Only care about enter file or exit file changes.
+ if (Reason == EnterFile)
+ FileEntered(Loc);
+ else if (Reason == ExitFile)
+ FileExited(Loc);
+}
+
+void MacroPPCallbacks::InclusionDirective(
+ SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+ bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath, const Module *Imported) {
+
+ // Record the line location of the current included file.
+ LastHashLoc = HashLoc;
+}
+
+void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
+ SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
+ std::string NameBuffer, ValueBuffer;
+ llvm::raw_string_ostream Name(NameBuffer);
+ llvm::raw_string_ostream Value(ValueBuffer);
+ writeMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
+ Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
+ llvm::dwarf::DW_MACINFO_define, location,
+ Name.str(), Value.str());
+}
+
+void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) {
+ IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
+ SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
+ Gen->getCGDebugInfo()->CreateMacro(getCurrentScope(),
+ llvm::dwarf::DW_MACINFO_undef, location,
+ Id->getName(), "");
+}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h b/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h
new file mode 100644
index 0000000..e117f96
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/CodeGen/MacroPPCallbacks.h
@@ -0,0 +1,117 @@
+//===--- MacroPPCallbacks.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines implementation for the macro preprocessors callbacks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/PPCallbacks.h"
+
+namespace llvm {
+class DIMacroFile;
+class DIMacroNode;
+}
+namespace clang {
+class Preprocessor;
+class MacroInfo;
+class CodeGenerator;
+
+class MacroPPCallbacks : public PPCallbacks {
+ /// A pointer to code generator, where debug info generator can be found.
+ CodeGenerator *Gen;
+
+ /// Preprocessor.
+ Preprocessor &PP;
+
+ /// Location of recent included file, used for line number.
+ SourceLocation LastHashLoc;
+
+ /// Counts current number of command line included files, which were entered
+ /// and were not exited yet.
+ int EnteredCommandLineIncludeFiles = 0;
+
+ enum FileScopeStatus {
+ NoScope = 0, // Scope is not initialized yet.
+ InitializedScope, // Main file scope is initialized but not set yet.
+ BuiltinScope, // <built-in> and <command line> file scopes.
+ CommandLineIncludeScope, // Included file, from <command line> file, scope.
+ MainFileScope // Main file scope.
+ };
+ FileScopeStatus Status;
+
+ /// Parent contains all entered files that were not exited yet according to
+ /// the inclusion order.
+ llvm::SmallVector<llvm::DIMacroFile *, 4> Scopes;
+
+ /// Get current DIMacroFile scope.
+ /// \return current DIMacroFile scope or nullptr if there is no such scope.
+ llvm::DIMacroFile *getCurrentScope();
+
+ /// Get current line location or invalid location.
+ /// \param Loc current line location.
+ /// \return current line location \p `Loc`, or invalid location if it's in a
+ /// skipped file scope.
+ SourceLocation getCorrectLocation(SourceLocation Loc);
+
+ /// Use the passed preprocessor to write the macro name and value from the
+ /// given macro info and identifier info into the given \p `Name` and \p
+ /// `Value` output streams.
+ ///
+ /// \param II Identifier info, used to get the Macro name.
+ /// \param MI Macro info, used to get the Macro argumets and values.
+ /// \param PP Preprocessor.
+ /// \param [out] Name Place holder for returned macro name and arguments.
+ /// \param [out] Value Place holder for returned macro value.
+ static void writeMacroDefinition(const IdentifierInfo &II,
+ const MacroInfo &MI, Preprocessor &PP,
+ raw_ostream &Name, raw_ostream &Value);
+
+ /// Update current file scope status to next file scope.
+ void updateStatusToNextScope();
+
+ /// Handle the case when entering a file.
+ ///
+ /// \param Loc Indicates the new location.
+ void FileEntered(SourceLocation Loc);
+
+ /// Handle the case when exiting a file.
+ ///
+ /// \param Loc Indicates the new location.
+ void FileExited(SourceLocation Loc);
+
+public:
+ MacroPPCallbacks(CodeGenerator *Gen, Preprocessor &PP);
+
+ /// Callback invoked whenever a source file is entered or exited.
+ ///
+ /// \param Loc Indicates the new location.
+ /// \param PrevFID the file that was exited if \p Reason is ExitFile.
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID = FileID()) override;
+
+ /// Callback invoked whenever a directive (#xxx) is processed.
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported) override;
+
+ /// Hook called whenever a macro definition is seen.
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override;
+
+ /// Hook called whenever a macro \#undef is seen.
+ ///
+ /// MD is released immediately following this callback.
+ void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
+ const MacroDirective *Undef) override;
+};
+
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 38df455..1bd2937 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -19,8 +19,8 @@
#include "CGVTables.h"
#include "CodeGenModule.h"
#include "CodeGenTypes.h"
-#include "ConstantBuilder.h"
#include "TargetInfo.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
@@ -206,8 +206,9 @@ public:
// lacks a definition for the destructor, non-base destructors must always
// delegate to or alias the base destructor.
- void buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
- SmallVectorImpl<CanQualType> &ArgTys) override;
+ AddedStructorArgs
+ buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
+ SmallVectorImpl<CanQualType> &ArgTys) override;
/// Non-base dtors should be emitted as delegating thunks in this ABI.
bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
@@ -248,11 +249,10 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF) override;
- unsigned addImplicitConstructorArgs(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
- CallArgList &Args) override;
+ AddedStructorArgs
+ addImplicitConstructorArgs(CodeGenFunction &CGF, const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating, CallArgList &Args) override;
void EmitDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *DD,
CXXDtorType Type, bool ForVirtualBase,
@@ -819,46 +819,44 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
return RAA_Default;
case llvm::Triple::x86_64:
- // Win64 passes objects with non-trivial copy ctors indirectly.
- if (RD->hasNonTrivialCopyConstructor())
- return RAA_Indirect;
-
- // If an object has a destructor, we'd really like to pass it indirectly
+ // If a class has a destructor, we'd really like to pass it indirectly
// because it allows us to elide copies. Unfortunately, MSVC makes that
// impossible for small types, which it will pass in a single register or
// stack slot. Most objects with dtors are large-ish, so handle that early.
// We can't call out all large objects as being indirect because there are
// multiple x64 calling conventions and the C++ ABI code shouldn't dictate
// how we pass large POD types.
+ //
+ // Note: This permits small classes with nontrivial destructors to be
+ // passed in registers, which is non-conforming.
if (RD->hasNonTrivialDestructor() &&
getContext().getTypeSize(RD->getTypeForDecl()) > 64)
return RAA_Indirect;
- // If this is true, the implicit copy constructor that Sema would have
- // created would not be deleted. FIXME: We should provide a more direct way
- // for CodeGen to ask whether the constructor was deleted.
- if (!RD->hasUserDeclaredCopyConstructor() &&
- !RD->hasUserDeclaredMoveConstructor() &&
- !RD->needsOverloadResolutionForMoveConstructor() &&
- !RD->hasUserDeclaredMoveAssignment() &&
- !RD->needsOverloadResolutionForMoveAssignment())
- return RAA_Default;
-
- // Otherwise, Sema should have created an implicit copy constructor if
- // needed.
- assert(!RD->needsImplicitCopyConstructor());
-
- // We have to make sure the trivial copy constructor isn't deleted.
- for (const CXXConstructorDecl *CD : RD->ctors()) {
- if (CD->isCopyConstructor()) {
- assert(CD->isTrivial());
- // We had at least one undeleted trivial copy ctor. Return directly.
- if (!CD->isDeleted())
- return RAA_Default;
+ // If a class has at least one non-deleted, trivial copy constructor, it
+ // is passed according to the C ABI. Otherwise, it is passed indirectly.
+ //
+ // Note: This permits classes with non-trivial copy or move ctors to be
+ // passed in registers, so long as they *also* have a trivial copy ctor,
+ // which is non-conforming.
+ if (RD->needsImplicitCopyConstructor()) {
+ // If the copy ctor has not yet been declared, we can read its triviality
+ // off the AST.
+ if (!RD->defaultedCopyConstructorIsDeleted() &&
+ RD->hasTrivialCopyConstructor())
+ return RAA_Default;
+ } else {
+ // Otherwise, we need to find the copy constructor(s) and ask.
+ for (const CXXConstructorDecl *CD : RD->ctors()) {
+ if (CD->isCopyConstructor()) {
+ // We had at least one nondeleted trivial copy ctor. Return directly.
+ if (!CD->isDeleted() && CD->isTrivial())
+ return RAA_Default;
+ }
}
}
- // The trivial copy constructor was deleted. Return indirectly.
+ // We have no trivial, non-deleted copy constructor.
return RAA_Indirect;
}
@@ -1261,17 +1259,19 @@ void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF,
}
}
-void
+CGCXXABI::AddedStructorArgs
MicrosoftCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
SmallVectorImpl<CanQualType> &ArgTys) {
+ AddedStructorArgs Added;
// TODO: 'for base' flag
if (T == StructorType::Deleting) {
// The scalar deleting destructor takes an implicit int parameter.
ArgTys.push_back(getContext().IntTy);
+ ++Added.Suffix;
}
auto *CD = dyn_cast<CXXConstructorDecl>(MD);
if (!CD)
- return;
+ return Added;
// All parameters are already in place except is_most_derived, which goes
// after 'this' if it's variadic and last if it's not.
@@ -1279,11 +1279,16 @@ MicrosoftCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
const CXXRecordDecl *Class = CD->getParent();
const FunctionProtoType *FPT = CD->getType()->castAs<FunctionProtoType>();
if (Class->getNumVBases()) {
- if (FPT->isVariadic())
+ if (FPT->isVariadic()) {
ArgTys.insert(ArgTys.begin() + 1, getContext().IntTy);
- else
+ ++Added.Prefix;
+ } else {
ArgTys.push_back(getContext().IntTy);
+ ++Added.Suffix;
+ }
}
+
+ return Added;
}
void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
@@ -1406,11 +1411,10 @@ void MicrosoftCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
assert(isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD));
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
- ImplicitParamDecl *IsMostDerived
- = ImplicitParamDecl::Create(Context, nullptr,
- CGF.CurGD.getDecl()->getLocation(),
- &Context.Idents.get("is_most_derived"),
- Context.IntTy);
+ auto *IsMostDerived = ImplicitParamDecl::Create(
+ Context, /*DC=*/nullptr, CGF.CurGD.getDecl()->getLocation(),
+ &Context.Idents.get("is_most_derived"), Context.IntTy,
+ ImplicitParamDecl::Other);
// The 'most_derived' parameter goes second if the ctor is variadic and last
// if it's not. Dtors can't be variadic.
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
@@ -1420,11 +1424,10 @@ void MicrosoftCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
Params.push_back(IsMostDerived);
getStructorImplicitParamDecl(CGF) = IsMostDerived;
} else if (isDeletingDtor(CGF.CurGD)) {
- ImplicitParamDecl *ShouldDelete
- = ImplicitParamDecl::Create(Context, nullptr,
- CGF.CurGD.getDecl()->getLocation(),
- &Context.Idents.get("should_call_delete"),
- Context.IntTy);
+ auto *ShouldDelete = ImplicitParamDecl::Create(
+ Context, /*DC=*/nullptr, CGF.CurGD.getDecl()->getLocation(),
+ &Context.Idents.get("should_call_delete"), Context.IntTy,
+ ImplicitParamDecl::Other);
Params.push_back(ShouldDelete);
getStructorImplicitParamDecl(CGF) = ShouldDelete;
}
@@ -1493,14 +1496,14 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
}
}
-unsigned MicrosoftCXXABI::addImplicitConstructorArgs(
+CGCXXABI::AddedStructorArgs MicrosoftCXXABI::addImplicitConstructorArgs(
CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type,
bool ForVirtualBase, bool Delegating, CallArgList &Args) {
assert(Type == Ctor_Complete || Type == Ctor_Base);
// Check if we need a 'most_derived' parameter.
if (!D->getParent()->getNumVBases())
- return 0;
+ return AddedStructorArgs{};
// Add the 'most_derived' argument second if we are variadic or last if not.
const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
@@ -1511,13 +1514,13 @@ unsigned MicrosoftCXXABI::addImplicitConstructorArgs(
MostDerivedArg = llvm::ConstantInt::get(CGM.Int32Ty, Type == Ctor_Complete);
}
RValue RV = RValue::get(MostDerivedArg);
- if (FPT->isVariadic())
+ if (FPT->isVariadic()) {
Args.insert(Args.begin() + 1,
CallArg(RV, getContext().IntTy, /*needscopy=*/false));
- else
- Args.add(RV, getContext().IntTy);
-
- return 1; // Added one arg.
+ return AddedStructorArgs::prefix(1);
+ }
+ Args.add(RV, getContext().IntTy);
+ return AddedStructorArgs::suffix(1);
}
void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
@@ -1554,7 +1557,7 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
void MicrosoftCXXABI::emitVTableTypeMetadata(const VPtrInfo &Info,
const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable) {
- if (!CGM.getCodeGenOpts().PrepareForLTO)
+ if (!CGM.getCodeGenOpts().LTOUnit)
return;
// The location of the first virtual function pointer in the virtual table,
@@ -2203,9 +2206,8 @@ static void emitGlobalDtorWithTLRegDtor(CodeGenFunction &CGF, const VarDecl &VD,
llvm::FunctionType *TLRegDtorTy = llvm::FunctionType::get(
CGF.IntTy, DtorStub->getType(), /*IsVarArg=*/false);
- llvm::Constant *TLRegDtor =
- CGF.CGM.CreateRuntimeFunction(TLRegDtorTy, "__tlregdtor",
- llvm::AttributeSet(), /*Local=*/true);
+ llvm::Constant *TLRegDtor = CGF.CGM.CreateRuntimeFunction(
+ TLRegDtorTy, "__tlregdtor", llvm::AttributeList(), /*Local=*/true);
if (llvm::Function *TLRegDtorFn = dyn_cast<llvm::Function>(TLRegDtor))
TLRegDtorFn->setDoesNotThrow();
@@ -2301,9 +2303,9 @@ static llvm::Constant *getInitThreadHeaderFn(CodeGenModule &CGM) {
CGM.IntTy->getPointerTo(), /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(
FTy, "_Init_thread_header",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind),
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind),
/*Local=*/true);
}
@@ -2313,9 +2315,9 @@ static llvm::Constant *getInitThreadFooterFn(CodeGenModule &CGM) {
CGM.IntTy->getPointerTo(), /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(
FTy, "_Init_thread_footer",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind),
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind),
/*Local=*/true);
}
@@ -2325,9 +2327,9 @@ static llvm::Constant *getInitThreadAbortFn(CodeGenModule &CGM) {
CGM.IntTy->getPointerTo(), /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(
FTy, "_Init_thread_abort",
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::NoUnwind),
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind),
/*Local=*/true);
}
@@ -3421,6 +3423,8 @@ static llvm::GlobalValue::LinkageTypes getLinkageForRTTI(QualType Ty) {
return llvm::GlobalValue::InternalLinkage;
case VisibleNoLinkage:
+ case ModuleInternalLinkage:
+ case ModuleLinkage:
case ExternalLinkage:
return llvm::GlobalValue::LinkOnceODRLinkage;
}
@@ -3713,7 +3717,7 @@ CatchTypeInfo
MicrosoftCXXABI::getAddrOfCXXCatchHandlerType(QualType Type,
QualType CatchHandlerType) {
// TypeDescriptors for exceptions never have qualified pointer types,
- // qualifiers are stored seperately in order to support qualification
+ // qualifiers are stored separately in order to support qualification
// conversions.
bool IsConst, IsVolatile, IsUnaligned;
Type =
@@ -3750,6 +3754,9 @@ llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type) {
if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+ // Note for the future: If we would ever like to do deferred emission of
+ // RTTI, check if emitting vtables opportunistically need any adjustment.
+
// Compute the fields for the TypeDescriptor.
SmallString<256> TypeInfoString;
{
@@ -3866,18 +3873,21 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
// Following the 'this' pointer is a reference to the source object that we
// are copying from.
ImplicitParamDecl SrcParam(
- getContext(), nullptr, SourceLocation(), &getContext().Idents.get("src"),
+ getContext(), /*DC=*/nullptr, SourceLocation(),
+ &getContext().Idents.get("src"),
getContext().getLValueReferenceType(RecordTy,
- /*SpelledAsLValue=*/true));
+ /*SpelledAsLValue=*/true),
+ ImplicitParamDecl::Other);
if (IsCopy)
FunctionArgs.push_back(&SrcParam);
// Constructors for classes which utilize virtual bases have an additional
// parameter which indicates whether or not it is being delegated to by a more
// derived constructor.
- ImplicitParamDecl IsMostDerived(getContext(), nullptr, SourceLocation(),
+ ImplicitParamDecl IsMostDerived(getContext(), /*DC=*/nullptr,
+ SourceLocation(),
&getContext().Idents.get("is_most_derived"),
- getContext().IntTy);
+ getContext().IntTy, ImplicitParamDecl::Other);
// Only add the parameter to the list if thie class has virtual bases.
if (RD->getNumVBases() > 0)
FunctionArgs.push_back(&IsMostDerived);
@@ -3918,16 +3928,16 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
CGF.EmitCallArgs(Args, FPT, llvm::makeArrayRef(ArgVec), CD, IsCopy ? 1 : 0);
// Insert any ABI-specific implicit constructor arguments.
- unsigned ExtraArgs = addImplicitConstructorArgs(CGF, CD, Ctor_Complete,
- /*ForVirtualBase=*/false,
- /*Delegating=*/false, Args);
-
+ AddedStructorArgs ExtraArgs =
+ addImplicitConstructorArgs(CGF, CD, Ctor_Complete,
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/false, Args);
// Call the destructor with our arguments.
llvm::Constant *CalleePtr =
CGM.getAddrOfCXXStructor(CD, StructorType::Complete);
CGCallee Callee = CGCallee::forDirect(CalleePtr, CD);
const CGFunctionInfo &CalleeInfo = CGM.getTypes().arrangeCXXConstructorCall(
- Args, CD, Ctor_Complete, ExtraArgs);
+ Args, CD, Ctor_Complete, ExtraArgs.Prefix, ExtraArgs.Suffix);
CGF.EmitCall(CalleeInfo, Callee, ReturnValueSlot(), Args);
Cleanups.ForceCleanup();
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp
index f925c25..fc64285 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -92,6 +92,10 @@ namespace {
return M.get();
}
+ CGDebugInfo *getCGDebugInfo() {
+ return Builder->getModuleDebugInfo();
+ }
+
llvm::Module *ReleaseModule() {
return M.release();
}
@@ -193,7 +197,7 @@ namespace {
// Provide some coverage mapping even for methods that aren't emitted.
// Don't do this for templated classes though, as they may not be
// instantiable.
- if (!MD->getParent()->getDescribedClassTemplate())
+ if (!MD->getParent()->isDependentContext())
Builder->AddDeferredUnusedCoverageMapping(MD);
}
@@ -299,6 +303,10 @@ llvm::Module *CodeGenerator::ReleaseModule() {
return static_cast<CodeGeneratorImpl*>(this)->ReleaseModule();
}
+CGDebugInfo *CodeGenerator::getCGDebugInfo() {
+ return static_cast<CodeGeneratorImpl*>(this)->getCGDebugInfo();
+}
+
const Decl *CodeGenerator::GetDeclForMangledName(llvm::StringRef name) {
return static_cast<CodeGeneratorImpl*>(this)->GetDeclForMangledName(name);
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index 754f996..d0760b9 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -152,6 +152,9 @@ public:
CodeGenOpts.CodeModel = "default";
CodeGenOpts.ThreadModel = "single";
CodeGenOpts.DebugTypeExtRefs = true;
+ // When building a module MainFileName is the name of the modulemap file.
+ CodeGenOpts.MainFileName =
+ LangOpts.CurrentModule.empty() ? MainFileName : LangOpts.CurrentModule;
CodeGenOpts.setDebugInfo(codegenoptions::FullDebugInfo);
CodeGenOpts.setDebuggerTuning(CI.getCodeGenOpts().getDebuggerTuning());
}
@@ -171,7 +174,8 @@ public:
// Prepare CGDebugInfo to emit debug info for a clang module.
auto *DI = Builder->getModuleDebugInfo();
StringRef ModuleName = llvm::sys::path::filename(MainFileName);
- DI->setPCHDescriptor({ModuleName, "", OutputFileName, ~1ULL});
+ DI->setPCHDescriptor({ModuleName, "", OutputFileName,
+ ASTFileSignature{{{~0U, ~0U, ~0U, ~0U, ~1U}}}});
DI->setModuleMap(MMap);
}
@@ -241,7 +245,11 @@ public:
// PCH files don't have a signature field in the control block,
// but LLVM detects DWO CUs by looking for a non-zero DWO id.
- uint64_t Signature = Buffer->Signature ? Buffer->Signature : ~1ULL;
+ // We use the lower 64 bits for debug info.
+ uint64_t Signature =
+ Buffer->Signature
+ ? (uint64_t)Buffer->Signature[1] << 32 | Buffer->Signature[0]
+ : ~1ULL;
Builder->getModuleDebugInfo()->setDwoId(Signature);
// Finalize the Builder.
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp b/contrib/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp
index 0bfe30a..fc8e36d 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp
@@ -57,6 +57,10 @@ static CharUnits getTypeStoreSize(CodeGenModule &CGM, llvm::Type *type) {
return CharUnits::fromQuantity(CGM.getDataLayout().getTypeStoreSize(type));
}
+static CharUnits getTypeAllocSize(CodeGenModule &CGM, llvm::Type *type) {
+ return CharUnits::fromQuantity(CGM.getDataLayout().getTypeAllocSize(type));
+}
+
void SwiftAggLowering::addTypedData(QualType type, CharUnits begin) {
// Deal with various aggregate types as special cases:
@@ -542,7 +546,9 @@ SwiftAggLowering::getCoerceAndExpandTypes() const {
packed = true;
elts.push_back(entry.Type);
- lastEnd = entry.End;
+
+ lastEnd = entry.Begin + getTypeAllocSize(CGM, entry.Type);
+ assert(entry.End <= lastEnd);
}
// We don't need to adjust 'packed' to deal with possible tail padding
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp
index d2fc388..ece3a40 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp
@@ -183,7 +183,11 @@ const TargetInfo &ABIInfo::getTarget() const {
return CGT.getTarget();
}
-bool ABIInfo:: isAndroid() const { return getTarget().getTriple().isAndroid(); }
+const CodeGenOptions &ABIInfo::getCodeGenOpts() const {
+ return CGT.getCodeGenOpts();
+}
+
+bool ABIInfo::isAndroid() const { return getTarget().getTriple().isAndroid(); }
bool ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
return false;
@@ -398,7 +402,17 @@ TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib,
}
unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const {
- return llvm::CallingConv::C;
+ // OpenCL kernels are called via an explicit runtime API with arguments
+ // set with clSetKernelArg(), not as normal sub-functions.
+ // Return SPIR_KERNEL by default as the kernel calling convention to
+ // ensure the fingerprint is fixed such way that each OpenCL argument
+ // gets one matching argument in the produced kernel function argument
+ // list to enable feasible implementation of clSetKernelArg() with
+ // aggregates etc. In case we would use the default C calling conv here,
+ // clSetKernelArg() might break depending on the target-specific
+ // conventions; different targets might split structs passed as values
+ // to multiple function arguments etc.
+ return llvm::CallingConv::SPIR_KERNEL;
}
llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
@@ -406,13 +420,32 @@ llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &
return llvm::ConstantPointerNull::get(T);
}
+unsigned TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
+ const VarDecl *D) const {
+ assert(!CGM.getLangOpts().OpenCL &&
+ !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
+ "Address space agnostic languages only");
+ return D ? D->getType().getAddressSpace()
+ : static_cast<unsigned>(LangAS::Default);
+}
+
llvm::Value *TargetCodeGenInfo::performAddrSpaceCast(
- CodeGen::CodeGenFunction &CGF, llvm::Value *Src, QualType SrcTy,
- QualType DestTy) const {
+ CodeGen::CodeGenFunction &CGF, llvm::Value *Src, unsigned SrcAddr,
+ unsigned DestAddr, llvm::Type *DestTy, bool isNonNull) const {
+ // Since target may map different address spaces in AST to the same address
+ // space, an address space conversion may end up as a bitcast.
+ if (auto *C = dyn_cast<llvm::Constant>(Src))
+ return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestAddr, DestTy);
+ return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DestTy);
+}
+
+llvm::Constant *
+TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src,
+ unsigned SrcAddr, unsigned DestAddr,
+ llvm::Type *DestTy) const {
// Since target may map different address spaces in AST to the same address
// space, an address space conversion may end up as a bitcast.
- return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src,
- CGF.ConvertType(DestTy));
+ return llvm::ConstantExpr::getPointerCast(Src, DestTy);
}
static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
@@ -942,8 +975,7 @@ class X86_32ABIInfo : public SwiftABIInfo {
Class classify(QualType Ty) const;
ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
- ABIArgInfo reclassifyHvaArgType(QualType RetTy, CCState &State,
- const ABIArgInfo& current) const;
+
/// \brief Updates the number of available free registers, returns
/// true if any registers were allocated.
bool updateFreeRegs(QualType Ty, CCState &State) const;
@@ -1197,6 +1229,39 @@ static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
return Size == 32 || Size == 64;
}
+static bool addFieldSizes(ASTContext &Context, const RecordDecl *RD,
+ uint64_t &Size) {
+ for (const auto *FD : RD->fields()) {
+ // Scalar arguments on the stack get 4 byte alignment on x86. If the
+ // argument is smaller than 32-bits, expanding the struct will create
+ // alignment padding.
+ if (!is32Or64BitBasicType(FD->getType(), Context))
+ return false;
+
+ // FIXME: Reject bit-fields wholesale; there are two problems, we don't know
+ // how to expand them yet, and the predicate for telling if a bitfield still
+ // counts as "basic" is more complicated than what we were doing previously.
+ if (FD->isBitField())
+ return false;
+
+ Size += Context.getTypeSize(FD->getType());
+ }
+ return true;
+}
+
+static bool addBaseAndFieldSizes(ASTContext &Context, const CXXRecordDecl *RD,
+ uint64_t &Size) {
+ // Don't do this if there are any non-empty bases.
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ if (!addBaseAndFieldSizes(Context, Base.getType()->getAsCXXRecordDecl(),
+ Size))
+ return false;
+ }
+ if (!addFieldSizes(Context, RD, Size))
+ return false;
+ return true;
+}
+
/// Test whether an argument type which is to be passed indirectly (on the
/// stack) would have the equivalent layout if it was expanded into separate
/// arguments. If so, we prefer to do the latter to avoid inhibiting
@@ -1207,8 +1272,9 @@ bool X86_32ABIInfo::canExpandIndirectArgument(QualType Ty) const {
if (!RT)
return false;
const RecordDecl *RD = RT->getDecl();
+ uint64_t Size = 0;
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- if (!IsWin32StructABI ) {
+ if (!IsWin32StructABI) {
// On non-Windows, we have to conservatively match our old bitcode
// prototypes in order to be ABI-compatible at the bitcode level.
if (!CXXRD->isCLike())
@@ -1217,30 +1283,12 @@ bool X86_32ABIInfo::canExpandIndirectArgument(QualType Ty) const {
// Don't do this for dynamic classes.
if (CXXRD->isDynamicClass())
return false;
- // Don't do this if there are any non-empty bases.
- for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
- if (!isEmptyRecord(getContext(), Base.getType(), /*AllowArrays=*/true))
- return false;
- }
}
- }
-
- uint64_t Size = 0;
-
- for (const auto *FD : RD->fields()) {
- // Scalar arguments on the stack get 4 byte alignment on x86. If the
- // argument is smaller than 32-bits, expanding the struct will create
- // alignment padding.
- if (!is32Or64BitBasicType(FD->getType(), getContext()))
+ if (!addBaseAndFieldSizes(getContext(), CXXRD, Size))
return false;
-
- // FIXME: Reject bit-fields wholesale; there are two problems, we don't know
- // how to expand them yet, and the predicate for telling if a bitfield still
- // counts as "basic" is more complicated than what we were doing previously.
- if (FD->isBitField())
+ } else {
+ if (!addFieldSizes(getContext(), RD, Size))
return false;
-
- Size += getContext().getTypeSize(FD->getType());
}
// We can do this if there was no alignment padding.
@@ -1511,27 +1559,6 @@ bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const {
return true;
}
-ABIArgInfo
-X86_32ABIInfo::reclassifyHvaArgType(QualType Ty, CCState &State,
- const ABIArgInfo &current) const {
- // Assumes vectorCall calling convention.
- const Type *Base = nullptr;
- uint64_t NumElts = 0;
-
- if (!Ty->isBuiltinType() && !Ty->isVectorType() &&
- isHomogeneousAggregate(Ty, Base, NumElts)) {
- if (State.FreeSSERegs >= NumElts) {
- // HVA types get passed directly in registers if there is room.
- State.FreeSSERegs -= NumElts;
- return getDirectX86Hva();
- }
- // If there's no room, the HVA gets passed as normal indirect
- // structure.
- return getIndirectResult(Ty, /*ByVal=*/false, State);
- }
- return current;
-}
-
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
CCState &State) const {
// FIXME: Set alignment on indirect arguments.
@@ -1550,35 +1577,20 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
}
}
- // vectorcall adds the concept of a homogenous vector aggregate, similar
- // to other targets, regcall uses some of the HVA rules.
+ // Regcall uses the concept of a homogenous vector aggregate, similar
+ // to other targets.
const Type *Base = nullptr;
uint64_t NumElts = 0;
- if ((State.CC == llvm::CallingConv::X86_VectorCall ||
- State.CC == llvm::CallingConv::X86_RegCall) &&
+ if (State.CC == llvm::CallingConv::X86_RegCall &&
isHomogeneousAggregate(Ty, Base, NumElts)) {
- if (State.CC == llvm::CallingConv::X86_RegCall) {
- if (State.FreeSSERegs >= NumElts) {
- State.FreeSSERegs -= NumElts;
- if (Ty->isBuiltinType() || Ty->isVectorType())
- return ABIArgInfo::getDirect();
- return ABIArgInfo::getExpand();
-
- }
- return getIndirectResult(Ty, /*ByVal=*/false, State);
- } else if (State.CC == llvm::CallingConv::X86_VectorCall) {
- if (State.FreeSSERegs >= NumElts && (Ty->isBuiltinType() || Ty->isVectorType())) {
- // Actual floating-point types get registers first time through if
- // there is registers available
- State.FreeSSERegs -= NumElts;
+ if (State.FreeSSERegs >= NumElts) {
+ State.FreeSSERegs -= NumElts;
+ if (Ty->isBuiltinType() || Ty->isVectorType())
return ABIArgInfo::getDirect();
- } else if (!Ty->isBuiltinType() && !Ty->isVectorType()) {
- // HVA Types only get registers after everything else has been
- // set, so it gets set as indirect for now.
- return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty));
- }
+ return ABIArgInfo::getExpand();
}
+ return getIndirectResult(Ty, /*ByVal=*/false, State);
}
if (isAggregateTypeForABI(Ty)) {
@@ -1659,31 +1671,53 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
void X86_32ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, CCState &State,
bool &UsedInAlloca) const {
- // Vectorcall only allows the first 6 parameters to be passed in registers,
- // and homogeneous vector aggregates are only put into registers as a second
- // priority.
- unsigned Count = 0;
- CCState ZeroState = State;
- ZeroState.FreeRegs = ZeroState.FreeSSERegs = 0;
- // HVAs must be done as a second priority for registers, so the deferred
- // items are dealt with by going through the pattern a second time.
+ // Vectorcall x86 works subtly different than in x64, so the format is
+ // a bit different than the x64 version. First, all vector types (not HVAs)
+ // are assigned, with the first 6 ending up in the YMM0-5 or XMM0-5 registers.
+ // This differs from the x64 implementation, where the first 6 by INDEX get
+ // registers.
+ // After that, integers AND HVAs are assigned Left to Right in the same pass.
+ // Integers are passed as ECX/EDX if one is available (in order). HVAs will
+ // first take up the remaining YMM/XMM registers. If insufficient registers
+ // remain but an integer register (ECX/EDX) is available, it will be passed
+ // in that, else, on the stack.
for (auto &I : FI.arguments()) {
- if (Count < VectorcallMaxParamNumAsReg)
- I.info = classifyArgumentType(I.type, State);
- else
- // Parameters after the 6th cannot be passed in registers,
- // so pretend there are no registers left for them.
- I.info = classifyArgumentType(I.type, ZeroState);
- UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
- ++Count;
+ // First pass do all the vector types.
+ const Type *Base = nullptr;
+ uint64_t NumElts = 0;
+ const QualType& Ty = I.type;
+ if ((Ty->isVectorType() || Ty->isBuiltinType()) &&
+ isHomogeneousAggregate(Ty, Base, NumElts)) {
+ if (State.FreeSSERegs >= NumElts) {
+ State.FreeSSERegs -= NumElts;
+ I.info = ABIArgInfo::getDirect();
+ } else {
+ I.info = classifyArgumentType(Ty, State);
+ }
+ UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
+ }
}
- Count = 0;
- // Go through the arguments a second time to get HVAs registers if there
- // are still some available.
+
for (auto &I : FI.arguments()) {
- if (Count < VectorcallMaxParamNumAsReg)
- I.info = reclassifyHvaArgType(I.type, State, I.info);
- ++Count;
+ // Second pass, do the rest!
+ const Type *Base = nullptr;
+ uint64_t NumElts = 0;
+ const QualType& Ty = I.type;
+ bool IsHva = isHomogeneousAggregate(Ty, Base, NumElts);
+
+ if (IsHva && !Ty->isVectorType() && !Ty->isBuiltinType()) {
+ // Assign true HVAs (non vector/native FP types).
+ if (State.FreeSSERegs >= NumElts) {
+ State.FreeSSERegs -= NumElts;
+ I.info = getDirectX86Hva();
+ } else {
+ I.info = getIndirectResult(Ty, /*ByVal=*/false, State);
+ }
+ } else if (!IsHva) {
+ // Assign all Non-HVAs, so this will exclude Vector/FP args.
+ I.info = classifyArgumentType(Ty, State);
+ UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
+ }
}
}
@@ -1885,10 +1919,7 @@ void X86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D,
// Now add the 'alignstack' attribute with a value of 16.
llvm::AttrBuilder B;
B.addStackAlignmentAttr(16);
- Fn->addAttributes(llvm::AttributeSet::FunctionIndex,
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- B));
+ Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
}
if (FD->hasAttr<AnyX86InterruptAttr>()) {
llvm::Function *Fn = cast<llvm::Function>(GV);
@@ -2068,9 +2099,14 @@ class X86_64ABIInfo : public SwiftABIInfo {
return !getTarget().getTriple().isOSDarwin();
}
- /// GCC classifies <1 x long long> as SSE but compatibility with older clang
- // compilers require us to classify it as INTEGER.
+ /// GCC classifies <1 x long long> as SSE but some platform ABIs choose to
+ /// classify it as INTEGER (for compatibility with older clang compilers).
bool classifyIntegerMMXAsSSE() const {
+ // Clang <= 3.8 did not do this.
+ if (getCodeGenOpts().getClangABICompat() <=
+ CodeGenOptions::ClangABI::Ver3_8)
+ return false;
+
const llvm::Triple &Triple = getTarget().getTriple();
if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::PS4)
return false;
@@ -3146,8 +3182,7 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
}
}
- llvm::StructType *Result = llvm::StructType::get(Lo, Hi, nullptr);
-
+ llvm::StructType *Result = llvm::StructType::get(Lo, Hi);
// Verify that the second element is at an 8-byte offset.
assert(TD.getStructLayout(Result)->getElementOffset(1) == 8 &&
@@ -3222,8 +3257,7 @@ classifyReturnType(QualType RetTy) const {
case ComplexX87:
assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
ResType = llvm::StructType::get(llvm::Type::getX86_FP80Ty(getVMContext()),
- llvm::Type::getX86_FP80Ty(getVMContext()),
- nullptr);
+ llvm::Type::getX86_FP80Ty(getVMContext()));
break;
}
@@ -3719,7 +3753,7 @@ Address X86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
CGF.Builder.CreateConstInBoundsByteGEP(RegAddrLo,
CharUnits::fromQuantity(16));
llvm::Type *DoubleTy = CGF.DoubleTy;
- llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy, nullptr);
+ llvm::StructType *ST = llvm::StructType::get(DoubleTy, DoubleTy);
llvm::Value *V;
Address Tmp = CGF.CreateMemTemp(Ty);
Tmp = CGF.Builder.CreateElementBitCast(Tmp, ST);
@@ -3881,6 +3915,8 @@ void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI,
bool IsRegCall) const {
unsigned Count = 0;
for (auto &I : FI.arguments()) {
+ // Vectorcall in x64 only permits the first 6 arguments to be passed
+ // as XMM/YMM registers.
if (Count < VectorcallMaxParamNumAsReg)
I.info = classify(I.type, FreeSSERegs, false, IsVectorCall, IsRegCall);
else {
@@ -3893,11 +3929,8 @@ void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI,
++Count;
}
- Count = 0;
for (auto &I : FI.arguments()) {
- if (Count < VectorcallMaxParamNumAsReg)
- I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info);
- ++Count;
+ I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info);
}
}
@@ -4624,7 +4657,7 @@ PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
llvm::Type *CoerceTy;
if (Bits > GPRBits) {
CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
- CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy, nullptr);
+ CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy);
} else
CoerceTy =
llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8));
@@ -4761,7 +4794,8 @@ class AArch64ABIInfo : public SwiftABIInfo {
public:
enum ABIKind {
AAPCS = 0,
- DarwinPCS
+ DarwinPCS,
+ Win64
};
private:
@@ -4799,10 +4833,14 @@ private:
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const override {
- return isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
- : EmitAAPCSVAArg(VAListAddr, Ty, CGF);
+ return Kind == Win64 ? EmitMSVAArg(CGF, VAListAddr, Ty)
+ : isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
+ : EmitAAPCSVAArg(VAListAddr, Ty, CGF);
}
+ Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const override;
+
bool shouldPassIndirectlyForSwift(CharUnits totalSize,
ArrayRef<llvm::Type*> scalars,
bool asReturnValue) const override {
@@ -4811,6 +4849,9 @@ private:
bool isSwiftErrorInRegister() const override {
return true;
}
+
+ bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
+ unsigned elts) const override;
};
class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
@@ -4819,7 +4860,7 @@ public:
: TargetCodeGenInfo(new AArch64ABIInfo(CGT, Kind)) {}
StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
- return "mov\tfp, fp\t\t; marker for objc_retainAutoreleaseReturnValue";
+ return "mov\tfp, fp\t\t# marker for objc_retainAutoreleaseReturnValue";
}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
@@ -4877,10 +4918,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()));
}
@@ -4893,7 +4940,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.
@@ -4901,7 +4947,7 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const {
return coerceToIntArray(Ty, getContext(), getVMContext());
}
unsigned Alignment = getContext().getTypeAlign(Ty);
- Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes
+ Size = llvm::alignTo(Size, 64); // round up to multiple of 8 bytes
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
// For aggregates with 16-byte alignment, we use i128.
@@ -4933,7 +4979,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;
@@ -4943,7 +4990,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.
@@ -4951,7 +4997,7 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const {
return coerceToIntArray(RetTy, getContext(), getVMContext());
}
unsigned Alignment = getContext().getTypeAlign(RetTy);
- Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes
+ Size = llvm::alignTo(Size, 64); // round up to multiple of 8 bytes
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
// For aggregates with 16-byte alignment, we use i128.
@@ -4979,6 +5025,17 @@ bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const {
return false;
}
+bool AArch64ABIInfo::isLegalVectorTypeForSwift(CharUnits totalSize,
+ llvm::Type *eltTy,
+ unsigned elts) const {
+ if (!llvm::isPowerOf2_32(elts))
+ return false;
+ if (totalSize.getQuantity() != 8 &&
+ (totalSize.getQuantity() != 16 || elts == 1))
+ return false;
+ return true;
+}
+
bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
// Homogeneous aggregates for AAPCS64 must have base types of a floating
// point type or a short-vector type. This is the same as the 32-bit ABI,
@@ -5289,6 +5346,14 @@ Address AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty,
TyInfo, SlotSize, /*AllowHigherAlign*/ true);
}
+Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const {
+ return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
+ CGF.getContext().getTypeInfoInChars(Ty),
+ CharUnits::fromQuantity(8),
+ /*allowHigherAlign*/ false);
+}
+
//===----------------------------------------------------------------------===//
// ARM ABI Implementation
//===----------------------------------------------------------------------===//
@@ -5367,6 +5432,8 @@ private:
bool isSwiftErrorInRegister() const override {
return true;
}
+ bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
+ unsigned elts) const override;
};
class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -5433,10 +5500,7 @@ public:
// the backend to perform a realignment as part of the function prologue.
llvm::AttrBuilder B;
B.addStackAlignmentAttr(8);
- Fn->addAttributes(llvm::AttributeSet::FunctionIndex,
- llvm::AttributeSet::get(CGM.getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- B));
+ Fn->addAttributes(llvm::AttributeList::FunctionIndex, B);
}
};
@@ -5518,17 +5582,14 @@ void ARMABIInfo::setCCs() {
// AAPCS apparently requires runtime support functions to be soft-float, but
// that's almost certainly for historic reasons (Thumb1 not supporting VFP
// most likely). It's more convenient for AAPCS16_VFP to be hard-float.
- switch (getABIKind()) {
- case APCS:
- case AAPCS16_VFP:
- if (abiCC != getLLVMDefaultCC())
+
+ // The Run-time ABI for the ARM Architecture section 4.1.2 requires
+ // AEABI-complying FP helper functions to use the base AAPCS.
+ // These AEABI functions are expanded in the ARM llvm backend, all the builtin
+ // support functions emitted by clang such as the _Complex helpers follow the
+ // abiCC.
+ if (abiCC != getLLVMDefaultCC())
BuiltinCC = abiCC;
- break;
- case AAPCS:
- case AAPCS_VFP:
- BuiltinCC = llvm::CallingConv::ARM_AAPCS;
- break;
- }
}
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
@@ -5882,6 +5943,20 @@ bool ARMABIInfo::isIllegalVectorType(QualType Ty) const {
return false;
}
+bool ARMABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize,
+ llvm::Type *eltTy,
+ unsigned numElts) const {
+ if (!llvm::isPowerOf2_32(numElts))
+ return false;
+ unsigned size = getDataLayout().getTypeStoreSizeInBits(eltTy);
+ if (size > 64)
+ return false;
+ if (vectorSize.getQuantity() != 8 &&
+ (vectorSize.getQuantity() != 16 || numElts == 1))
+ return false;
+ return true;
+}
+
bool ARMABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
// Homogeneous aggregates for AAPCS-VFP must have base types of float,
// double, or 64-bit or 128-bit vectors.
@@ -6545,6 +6620,11 @@ public:
Fn->addFnAttr("nomips16");
}
+ if (FD->hasAttr<MicroMipsAttr>())
+ Fn->addFnAttr("micromips");
+ else if (FD->hasAttr<NoMicroMipsAttr>())
+ Fn->addFnAttr("nomicromips");
+
const MipsInterruptAttr *Attr = FD->getAttr<MipsInterruptAttr>();
if (!Attr)
return;
@@ -6884,6 +6964,31 @@ MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
}
//===----------------------------------------------------------------------===//
+// AVR ABI Implementation.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class AVRTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ AVRTargetCodeGenInfo(CodeGenTypes &CGT)
+ : TargetCodeGenInfo(new DefaultABIInfo(CGT)) { }
+
+ void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const override {
+ const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
+ if (!FD) return;
+ auto *Fn = cast<llvm::Function>(GV);
+
+ if (FD->getAttr<AVRInterruptAttr>())
+ Fn->addFnAttr("interrupt");
+
+ if (FD->getAttr<AVRSignalAttr>())
+ Fn->addFnAttr("signal");
+ }
+};
+}
+
+//===----------------------------------------------------------------------===//
// TCE ABI Implementation (see http://tce.cs.tut.fi). Uses mostly the defaults.
// Currently subclassed only to implement custom OpenCL C function attribute
// handling.
@@ -6997,13 +7102,13 @@ ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
+ return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
+
// Ignore empty records.
if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
- return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
-
uint64_t Size = getContext().getTypeSize(Ty);
if (Size > 64)
return getNaturalAlignIndirect(Ty, /*ByVal=*/true);
@@ -7246,11 +7351,16 @@ public:
llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *T, QualType QT) const override;
+
+ unsigned getASTAllocaAddressSpace() const override {
+ return LangAS::FirstTargetAddressSpace +
+ getABIInfo().getDataLayout().getAllocaAddrSpace();
+ }
+ unsigned getGlobalVarAddressSpace(CodeGenModule &CGM,
+ const VarDecl *D) const override;
};
}
-static void appendOpenCLVersionMD (CodeGen::CodeGenModule &CGM);
-
void AMDGPUTargetCodeGenInfo::setTargetAttributes(
const Decl *D,
llvm::GlobalValue *GV,
@@ -7261,9 +7371,14 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
llvm::Function *F = cast<llvm::Function>(GV);
- if (const auto *Attr = FD->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) {
- unsigned Min = Attr->getMin();
- unsigned Max = Attr->getMax();
+ const auto *ReqdWGS = M.getLangOpts().OpenCL ?
+ FD->getAttr<ReqdWorkGroupSizeAttr>() : nullptr;
+ const auto *FlatWGS = FD->getAttr<AMDGPUFlatWorkGroupSizeAttr>();
+ if (ReqdWGS || FlatWGS) {
+ unsigned Min = FlatWGS ? FlatWGS->getMin() : 0;
+ unsigned Max = FlatWGS ? FlatWGS->getMax() : 0;
+ if (ReqdWGS && Min == 0 && Max == 0)
+ Min = Max = ReqdWGS->getXDim() * ReqdWGS->getYDim() * ReqdWGS->getZDim();
if (Min != 0) {
assert(Min <= Max && "Min must be less than or equal Max");
@@ -7302,8 +7417,6 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
if (NumVGPR != 0)
F->addFnAttr("amdgpu-num-vgpr", llvm::utostr(NumVGPR));
}
-
- appendOpenCLVersionMD(M);
}
unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv() const {
@@ -7328,6 +7441,31 @@ llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer(
llvm::ConstantPointerNull::get(NPT), PT);
}
+unsigned
+AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
+ const VarDecl *D) const {
+ assert(!CGM.getLangOpts().OpenCL &&
+ !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
+ "Address space agnostic languages only");
+ unsigned DefaultGlobalAS =
+ LangAS::FirstTargetAddressSpace +
+ CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
+ if (!D)
+ return DefaultGlobalAS;
+
+ unsigned AddrSpace = D->getType().getAddressSpace();
+ assert(AddrSpace == LangAS::Default ||
+ AddrSpace >= LangAS::FirstTargetAddressSpace);
+ if (AddrSpace != LangAS::Default)
+ return AddrSpace;
+
+ if (CGM.isTypeConstant(D->getType(), false)) {
+ if (auto ConstAS = CGM.getTarget().getConstantAddressSpace())
+ return ConstAS.getValue();
+ }
+ return DefaultGlobalAS;
+}
+
//===----------------------------------------------------------------------===//
// SPARC v8 ABI Implementation.
// Based on the SPARC Compliance Definition version 2.4.1.
@@ -7974,45 +8112,18 @@ class SPIRTargetCodeGenInfo : public TargetCodeGenInfo {
public:
SPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
: TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
- void emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const override;
unsigned getOpenCLKernelCallingConv() const override;
};
+
} // End anonymous namespace.
-/// Emit SPIR specific metadata: OpenCL and SPIR version.
-void SPIRTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const {
- llvm::LLVMContext &Ctx = CGM.getModule().getContext();
- llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Ctx);
- llvm::Module &M = CGM.getModule();
- // SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the
- // opencl.spir.version named metadata.
- llvm::Metadata *SPIRVerElts[] = {
- llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(Int32Ty, CGM.getLangOpts().OpenCLVersion / 100)),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, (CGM.getLangOpts().OpenCLVersion / 100 > 1) ? 0 : 2))};
- llvm::NamedMDNode *SPIRVerMD =
- M.getOrInsertNamedMetadata("opencl.spir.version");
- SPIRVerMD->addOperand(llvm::MDNode::get(Ctx, SPIRVerElts));
- appendOpenCLVersionMD(CGM);
-}
-
-static void appendOpenCLVersionMD(CodeGen::CodeGenModule &CGM) {
- llvm::LLVMContext &Ctx = CGM.getModule().getContext();
- llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Ctx);
- llvm::Module &M = CGM.getModule();
- // SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the
- // opencl.ocl.version named metadata node.
- llvm::Metadata *OCLVerElts[] = {
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, CGM.getLangOpts().OpenCLVersion / 100)),
- llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
- Int32Ty, (CGM.getLangOpts().OpenCLVersion % 100) / 10))};
- llvm::NamedMDNode *OCLVerMD =
- M.getOrInsertNamedMetadata("opencl.ocl.version");
- OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts));
+namespace clang {
+namespace CodeGen {
+void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) {
+ DefaultABIInfo SPIRABI(CGM.getTypes());
+ SPIRABI.computeInfo(FI);
+}
+}
}
unsigned SPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const {
@@ -8386,11 +8497,16 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::mips64el:
return SetCGInfo(new MIPSTargetCodeGenInfo(Types, false));
+ case llvm::Triple::avr:
+ return SetCGInfo(new AVRTargetCodeGenInfo(Types));
+
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be: {
AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS;
if (getTarget().getABI() == "darwinpcs")
Kind = AArch64ABIInfo::DarwinPCS;
+ else if (Triple.isOSWindows())
+ Kind = AArch64ABIInfo::Win64;
return SetCGInfo(new AArch64TargetCodeGenInfo(Types, Kind));
}
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h
index 223d6d0..952ef96 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h
+++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h
@@ -229,13 +229,36 @@ public:
virtual llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *T, QualType QT) const;
+ /// Get target favored AST address space of a global variable for languages
+ /// other than OpenCL and CUDA.
+ /// If \p D is nullptr, returns the default target favored address space
+ /// for global variable.
+ virtual unsigned getGlobalVarAddressSpace(CodeGenModule &CGM,
+ const VarDecl *D) const;
+
+ /// Get the AST address space for alloca.
+ virtual unsigned getASTAllocaAddressSpace() const { return LangAS::Default; }
+
/// Perform address space cast of an expression of pointer type.
/// \param V is the LLVM value to be casted to another address space.
- /// \param SrcTy is the QualType of \p V.
- /// \param DestTy is the destination QualType.
+ /// \param SrcAddr is the language address space of \p V.
+ /// \param DestAddr is the targeted language address space.
+ /// \param DestTy is the destination LLVM pointer type.
+ /// \param IsNonNull is the flag indicating \p V is known to be non null.
virtual llvm::Value *performAddrSpaceCast(CodeGen::CodeGenFunction &CGF,
- llvm::Value *V, QualType SrcTy, QualType DestTy) const;
+ llvm::Value *V, unsigned SrcAddr,
+ unsigned DestAddr,
+ llvm::Type *DestTy,
+ bool IsNonNull = false) const;
+ /// Perform address space cast of a constant expression of pointer type.
+ /// \param V is the LLVM constant to be casted to another address space.
+ /// \param SrcAddr is the language address space of \p V.
+ /// \param DestAddr is the targeted language address space.
+ /// \param DestTy is the destination LLVM pointer type.
+ virtual llvm::Constant *
+ performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *V, unsigned SrcAddr,
+ unsigned DestAddr, llvm::Type *DestTy) const;
};
} // namespace CodeGen
diff --git a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp
index 5c13e59..cf86644 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp
+++ b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp
@@ -23,10 +23,11 @@ using namespace clang;
using namespace llvm::opt;
Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
- InputArgList *_Args, DerivedArgList *_TranslatedArgs)
+ InputArgList *_Args, DerivedArgList *_TranslatedArgs,
+ bool ContainsError)
: TheDriver(D), DefaultToolChain(_DefaultToolChain), ActiveOffloadMask(0u),
Args(_Args), TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
- ForDiagnostics(false) {
+ ForDiagnostics(false), ContainsError(ContainsError) {
// The offloading host toolchain is the default tool chain.
OrderedOffloadingToolchains.insert(
std::make_pair(Action::OFK_Host, &DefaultToolChain));
diff --git a/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp
deleted file mode 100644
index 28036ea..0000000
--- a/contrib/llvm/tools/clang/lib/Driver/CrossWindowsToolChain.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-//===--- CrossWindowsToolChain.cpp - Cross Windows Tool Chain -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ToolChains.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/Options.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/Path.h"
-
-using namespace clang::driver;
-using namespace clang::driver::toolchains;
-
-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) {
- const std::string &SysRoot = D.SysRoot;
-
- // libstdc++ resides in /usr/lib, but depends on libgcc which is placed in
- // /usr/lib/gcc.
- getFilePaths().push_back(SysRoot + "/usr/lib");
- getFilePaths().push_back(SysRoot + "/usr/lib/gcc");
- }
-}
-
-bool CrossWindowsToolChain::IsUnwindTablesDefault() const {
- // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does
- // not know how to emit them.
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool CrossWindowsToolChain::isPICDefault() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool CrossWindowsToolChain::isPIEDefault() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool CrossWindowsToolChain::isPICDefaultForced() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-void CrossWindowsToolChain::
-AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- const Driver &D = getDriver();
- const std::string &SysRoot = D.SysRoot;
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- SmallString<128> ResourceDir(D.ResourceDir);
- llvm::sys::path::append(ResourceDir, "include");
- addSystemInclude(DriverArgs, CC1Args, ResourceDir);
- }
- for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after))
- addSystemInclude(DriverArgs, CC1Args, P);
- addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
-}
-
-void CrossWindowsToolChain::
-AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- const llvm::Triple &Triple = getTriple();
- const std::string &SysRoot = getDriver().SysRoot;
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
- return;
-
- switch (GetCXXStdlibType(DriverArgs)) {
- case ToolChain::CST_Libcxx:
- addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++/v1");
- break;
-
- case ToolChain::CST_Libstdcxx:
- addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++");
- addSystemInclude(DriverArgs, CC1Args,
- SysRoot + "/usr/include/c++/" + Triple.str());
- addSystemInclude(DriverArgs, CC1Args,
- SysRoot + "/usr/include/c++/backwards");
- }
-}
-
-void CrossWindowsToolChain::
-AddCXXStdlibLibArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- switch (GetCXXStdlibType(DriverArgs)) {
- case ToolChain::CST_Libcxx:
- CC1Args.push_back("-lc++");
- break;
- case ToolChain::CST_Libstdcxx:
- CC1Args.push_back("-lstdc++");
- CC1Args.push_back("-lmingw32");
- CC1Args.push_back("-lmingwex");
- CC1Args.push_back("-lgcc");
- CC1Args.push_back("-lmoldname");
- CC1Args.push_back("-lmingw32");
- break;
- }
-}
-
-clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const {
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- Res |= SanitizerKind::Address;
- return Res;
-}
-
-Tool *CrossWindowsToolChain::buildLinker() const {
- return new tools::CrossWindows::Linker(*this);
-}
-
-Tool *CrossWindowsToolChain::buildAssembler() const {
- return new tools::CrossWindows::Assembler(*this);
-}
diff --git a/contrib/llvm/tools/clang/lib/Driver/Distro.cpp b/contrib/llvm/tools/clang/lib/Driver/Distro.cpp
index d305b17..2df297f 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Distro.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp
index 15f830d..ba4d0e8 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp
+++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp
@@ -9,7 +9,38 @@
#include "clang/Driver/Driver.h"
#include "InputInfo.h"
-#include "ToolChains.h"
+#include "ToolChains/AMDGPU.h"
+#include "ToolChains/AVR.h"
+#include "ToolChains/Ananas.h"
+#include "ToolChains/Bitrig.h"
+#include "ToolChains/Clang.h"
+#include "ToolChains/CloudABI.h"
+#include "ToolChains/Contiki.h"
+#include "ToolChains/CrossWindows.h"
+#include "ToolChains/Cuda.h"
+#include "ToolChains/Darwin.h"
+#include "ToolChains/DragonFly.h"
+#include "ToolChains/FreeBSD.h"
+#include "ToolChains/Fuchsia.h"
+#include "ToolChains/Gnu.h"
+#include "ToolChains/BareMetal.h"
+#include "ToolChains/Haiku.h"
+#include "ToolChains/Hexagon.h"
+#include "ToolChains/Lanai.h"
+#include "ToolChains/Linux.h"
+#include "ToolChains/MinGW.h"
+#include "ToolChains/Minix.h"
+#include "ToolChains/MipsLinux.h"
+#include "ToolChains/MSVC.h"
+#include "ToolChains/Myriad.h"
+#include "ToolChains/NaCl.h"
+#include "ToolChains/NetBSD.h"
+#include "ToolChains/OpenBSD.h"
+#include "ToolChains/PS4CPU.h"
+#include "ToolChains/Solaris.h"
+#include "ToolChains/TCE.h"
+#include "ToolChains/WebAssembly.h"
+#include "ToolChains/XCore.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VirtualFileSystem.h"
#include "clang/Config/config.h"
@@ -62,7 +93,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
CCCPrintBindings(false), CCPrintHeaders(false), CCLogDiagnostics(false),
CCGenDiagnostics(false), DefaultTargetTriple(DefaultTargetTriple),
CCCGenericGCCName(""), CheckInputsExist(true), CCCUsePCH(true),
- SuppressMissingInputWarning(false) {
+ GenReproducer(false), SuppressMissingInputWarning(false) {
// Provide a sane fallback if no VFS is specified.
if (!this->VFS)
@@ -79,18 +110,13 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
llvm::sys::path::append(P, ClangResourceDir);
} else {
StringRef ClangLibdirSuffix(CLANG_LIBDIR_SUFFIX);
- llvm::sys::path::append(P, "..", Twine("lib") + ClangLibdirSuffix, "clang",
+ P = llvm::sys::path::parent_path(Dir);
+ llvm::sys::path::append(P, Twine("lib") + ClangLibdirSuffix, "clang",
CLANG_VERSION_STRING);
}
ResourceDir = P.str();
}
-Driver::~Driver() {
- delete Opts;
-
- llvm::DeleteContainerSeconds(ToolChains);
-}
-
void Driver::ParseDriverMode(StringRef ProgramName,
ArrayRef<const char *> Args) {
auto Default = ToolChain::getTargetAndModeFromProgramName(ProgramName);
@@ -126,8 +152,10 @@ void Driver::setDriverModeFromOption(StringRef Opt) {
Diag(diag::err_drv_unsupported_option_argument) << OptName << Value;
}
-InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) {
+InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
+ bool &ContainsError) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
+ ContainsError = false;
unsigned IncludedFlagsBitmask;
unsigned ExcludedFlagsBitmask;
@@ -140,27 +168,41 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) {
IncludedFlagsBitmask, ExcludedFlagsBitmask);
// Check for missing argument error.
- if (MissingArgCount)
- Diag(clang::diag::err_drv_missing_argument)
+ if (MissingArgCount) {
+ Diag(diag::err_drv_missing_argument)
<< Args.getArgString(MissingArgIndex) << MissingArgCount;
+ ContainsError |=
+ Diags.getDiagnosticLevel(diag::err_drv_missing_argument,
+ SourceLocation()) > DiagnosticsEngine::Warning;
+ }
// Check for unsupported options.
for (const Arg *A : Args) {
if (A->getOption().hasFlag(options::Unsupported)) {
- Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(Args);
+ Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args);
+ ContainsError |= Diags.getDiagnosticLevel(diag::err_drv_unsupported_opt,
+ SourceLocation()) >
+ DiagnosticsEngine::Warning;
continue;
}
// Warn about -mcpu= without an argument.
if (A->getOption().matches(options::OPT_mcpu_EQ) && A->containsValue("")) {
- Diag(clang::diag::warn_drv_empty_joined_argument) << A->getAsString(Args);
+ Diag(diag::warn_drv_empty_joined_argument) << A->getAsString(Args);
+ ContainsError |= Diags.getDiagnosticLevel(
+ diag::warn_drv_empty_joined_argument,
+ SourceLocation()) > DiagnosticsEngine::Warning;
}
}
- for (const Arg *A : Args.filtered(options::OPT_UNKNOWN))
- Diags.Report(IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl :
- diag::err_drv_unknown_argument)
- << A->getAsString(Args);
+ for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) {
+ auto ID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl
+ : diag::err_drv_unknown_argument;
+
+ Diags.Report(ID) << A->getAsString(Args);
+ ContainsError |= Diags.getDiagnosticLevel(ID, SourceLocation()) >
+ DiagnosticsEngine::Warning;
+ }
return Args;
}
@@ -214,9 +256,9 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
return FinalPhase;
}
-static Arg *MakeInputArg(DerivedArgList &Args, OptTable *Opts,
+static Arg *MakeInputArg(DerivedArgList &Args, OptTable &Opts,
StringRef Value) {
- Arg *A = new Arg(Opts->getOption(options::OPT_INPUT), Value,
+ Arg *A = new Arg(Opts.getOption(options::OPT_INPUT), Value,
Args.getBaseArgs().MakeIndex(Value), Value.data());
Args.AddSynthesizedArg(A);
A->claim();
@@ -287,7 +329,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
if (A->getOption().matches(options::OPT__DASH_DASH)) {
A->claim();
for (StringRef Val : A->getValues())
- DAL->append(MakeInputArg(*DAL, Opts, Val));
+ DAL->append(MakeInputArg(*DAL, *Opts, Val));
continue;
}
@@ -479,12 +521,12 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
: "nvptx-nvidia-cuda");
// Use the CUDA and host triples as the key into the ToolChains map, because
// the device toolchain we create depends on both.
- ToolChain *&CudaTC = ToolChains[CudaTriple.str() + "/" + HostTriple.str()];
+ auto &CudaTC = ToolChains[CudaTriple.str() + "/" + HostTriple.str()];
if (!CudaTC) {
- CudaTC = new toolchains::CudaToolChain(*this, CudaTriple, *HostTC,
- C.getInputArgs());
+ CudaTC = llvm::make_unique<toolchains::CudaToolChain>(
+ *this, CudaTriple, *HostTC, C.getInputArgs());
}
- C.addOffloadDeviceToolChain(CudaTC, Action::OFK_Cuda);
+ C.addOffloadDeviceToolChain(CudaTC.get(), Action::OFK_Cuda);
}
//
@@ -529,8 +571,22 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
if (TT.getArch() == llvm::Triple::UnknownArch)
Diag(clang::diag::err_drv_invalid_omp_target) << Val;
else {
- const ToolChain &TC = getToolChain(C.getInputArgs(), TT);
- C.addOffloadDeviceToolChain(&TC, Action::OFK_OpenMP);
+ const ToolChain *TC;
+ // CUDA toolchains have to be selected differently. They pair host
+ // and device in their implementation.
+ if (TT.isNVPTX()) {
+ const ToolChain *HostTC =
+ C.getSingleOffloadToolChain<Action::OFK_Host>();
+ assert(HostTC && "Host toolchain should be always defined.");
+ auto &CudaTC =
+ ToolChains[TT.str() + "/" + HostTC->getTriple().str()];
+ if (!CudaTC)
+ CudaTC = llvm::make_unique<toolchains::CudaToolChain>(
+ *this, TT, *HostTC, C.getInputArgs());
+ TC = CudaTC.get();
+ } else
+ TC = &getToolChain(C.getInputArgs(), TT);
+ C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP);
}
}
} else
@@ -573,7 +629,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// FIXME: This stuff needs to go into the Compilation, not the driver.
bool CCCPrintPhases;
- InputArgList Args = ParseArgStrings(ArgList.slice(1));
+ bool ContainsError;
+ InputArgList Args = ParseArgStrings(ArgList.slice(1), ContainsError);
// Silence driver warnings if requested
Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
@@ -596,6 +653,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
CCCGenericGCCName = A->getValue();
CCCUsePCH =
Args.hasFlag(options::OPT_ccc_pch_is_pch, options::OPT_ccc_pch_is_pth);
+ GenReproducer = Args.hasFlag(options::OPT_gen_reproducer,
+ options::OPT_fno_crash_diagnostics,
+ !!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"));
// FIXME: DefaultTargetTriple is used by the target-prefixed calls to as/ld
// and getToolChain is const.
if (IsCLMode()) {
@@ -660,7 +720,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
*UArgs, computeTargetTriple(*this, DefaultTargetTriple, *UArgs));
// The compilation takes ownership of Args.
- Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs);
+ Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs,
+ ContainsError);
if (!HandleImmediateArgs(*C))
return C;
@@ -1145,6 +1206,11 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
if (C.getArgs().hasArg(options::OPT_v))
TC.printVerboseInfo(llvm::errs());
+ if (C.getArgs().hasArg(options::OPT_print_resource_dir)) {
+ llvm::outs() << ResourceDir << '\n';
+ return false;
+ }
+
if (C.getArgs().hasArg(options::OPT_print_search_dirs)) {
llvm::outs() << "programs: =";
bool separator = false;
@@ -1184,6 +1250,54 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
return false;
}
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) {
+ // Print out all options that start with a given argument. This is used for
+ // shell autocompletion.
+ StringRef PassedFlags = A->getValue();
+ std::vector<std::string> SuggestedCompletions;
+
+ unsigned short DisableFlags = options::NoDriverOption | options::Unsupported | options::Ignored;
+ // We want to show cc1-only options only when clang is invoked as "clang -cc1".
+ // When clang is invoked as "clang -cc1", we add "#" to the beginning of an --autocomplete
+ // option so that the clang driver can distinguish whether it is requested to show cc1-only options or not.
+ if (PassedFlags[0] == '#') {
+ DisableFlags &= ~options::NoDriverOption;
+ PassedFlags = PassedFlags.substr(1);
+ }
+
+ if (PassedFlags.find(',') == StringRef::npos) {
+ // If the flag is in the form of "--autocomplete=-foo",
+ // we were requested to print out all option names that start with "-foo".
+ // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only".
+ SuggestedCompletions = Opts->findByPrefix(PassedFlags, DisableFlags);
+
+ // We have to query the -W flags manually as they're not in the OptTable.
+ // TODO: Find a good way to add them to OptTable instead and them remove
+ // this code.
+ for (StringRef S : DiagnosticIDs::getDiagnosticFlags())
+ if (S.startswith(PassedFlags))
+ SuggestedCompletions.push_back(S);
+ } else {
+ // If the flag is in the form of "--autocomplete=foo,bar", we were
+ // requested to print out all option values for "-foo" that start with
+ // "bar". For example,
+ // "--autocomplete=-stdlib=,l" is expanded to "libc++" and "libstdc++".
+ StringRef Option, Arg;
+ std::tie(Option, Arg) = PassedFlags.split(',');
+ SuggestedCompletions = Opts->suggestValueCompletions(Option, Arg);
+ }
+
+ // Sort the autocomplete candidates so that shells print them out in a
+ // deterministic order. We could sort in any way, but we chose
+ // case-insensitive sorting for consistency with the -help option
+ // which prints out options in the case-insensitive alphabetical order.
+ std::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(),
+ [](StringRef A, StringRef B) { return A.compare_lower(B) < 0; });
+
+ llvm::outs() << llvm::join(SuggestedCompletions, "\n") << '\n';
+ return false;
+ }
+
if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) {
ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(C.getArgs());
switch (RLT) {
@@ -1462,16 +1576,15 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
? types::TY_C
: types::TY_CXX;
- arg_iterator it =
- Args.filtered_begin(options::OPT__SLASH_TC, options::OPT__SLASH_TP);
- const arg_iterator ie = Args.filtered_end();
- Arg *Previous = *it++;
+ Arg *Previous = nullptr;
bool ShowNote = false;
- while (it != ie) {
- Diag(clang::diag::warn_drv_overriding_flag_option)
- << Previous->getSpelling() << (*it)->getSpelling();
- Previous = *it++;
- ShowNote = true;
+ for (Arg *A : Args.filtered(options::OPT__SLASH_TC, options::OPT__SLASH_TP)) {
+ if (Previous) {
+ Diag(clang::diag::warn_drv_overriding_flag_option)
+ << Previous->getSpelling() << A->getSpelling();
+ ShowNote = true;
+ }
+ Previous = A;
}
if (ShowNote)
Diag(clang::diag::note_drv_t_option_is_global);
@@ -1561,14 +1674,14 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
} else if (A->getOption().matches(options::OPT__SLASH_Tc)) {
StringRef Value = A->getValue();
if (DiagnoseInputExistence(*this, Args, Value, types::TY_C)) {
- Arg *InputArg = MakeInputArg(Args, Opts, A->getValue());
+ Arg *InputArg = MakeInputArg(Args, *Opts, A->getValue());
Inputs.push_back(std::make_pair(types::TY_C, InputArg));
}
A->claim();
} else if (A->getOption().matches(options::OPT__SLASH_Tp)) {
StringRef Value = A->getValue();
if (DiagnoseInputExistence(*this, Args, Value, types::TY_CXX)) {
- Arg *InputArg = MakeInputArg(Args, Opts, A->getValue());
+ Arg *InputArg = MakeInputArg(Args, *Opts, A->getValue());
Inputs.push_back(std::make_pair(types::TY_CXX, InputArg));
}
A->claim();
@@ -1589,12 +1702,20 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
Diag(clang::diag::err_drv_unknown_language) << A->getValue();
InputType = types::TY_Object;
}
+ } else if (A->getOption().getID() == options::OPT__SLASH_U) {
+ assert(A->getNumValues() == 1 && "The /U option has one value.");
+ StringRef Val = A->getValue(0);
+ if (Val.find_first_of("/\\") != StringRef::npos) {
+ // Warn about e.g. "/Users/me/myfile.c".
+ Diag(diag::warn_slash_u_filename) << Val;
+ Diag(diag::note_use_dashdash);
+ }
}
}
if (CCCIsCPP() && Inputs.empty()) {
// If called as standalone preprocessor, stdin is processed
// if no other input is present.
- Arg *A = MakeInputArg(Args, Opts, "-");
+ Arg *A = MakeInputArg(Args, *Opts, "-");
Inputs.push_back(std::make_pair(types::TY_C, A));
}
}
@@ -2351,8 +2472,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
Arg *FinalPhaseArg;
phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg);
- if (FinalPhase == phases::Link && Args.hasArg(options::OPT_emit_llvm)) {
- Diag(clang::diag::err_drv_emit_llvm_link);
+ if (FinalPhase == phases::Link) {
+ if (Args.hasArg(options::OPT_emit_llvm))
+ Diag(clang::diag::err_drv_emit_llvm_link);
+ if (IsCLMode() && LTOMode != LTOK_None &&
+ !Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_lower("lld"))
+ Diag(clang::diag::err_drv_lto_without_lld);
}
// Reject -Z* at the top level, these options should never have been exposed
@@ -2497,7 +2622,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
const types::ID HeaderType = lookupHeaderTypeForSourceType(InputType);
llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PCHPL;
types::getCompilationPhases(HeaderType, PCHPL);
- Arg *PchInputArg = MakeInputArg(Args, Opts, YcArg->getValue());
+ Arg *PchInputArg = MakeInputArg(Args, *Opts, YcArg->getValue());
// Build the pipeline for the pch file.
Action *ClangClPch =
@@ -2614,6 +2739,8 @@ Action *Driver::ConstructPhaseAction(Compilation &C, const ArgList &Args,
OutputTy = Input->getType();
if (!Args.hasFlag(options::OPT_frewrite_includes,
options::OPT_fno_rewrite_includes, false) &&
+ !Args.hasFlag(options::OPT_frewrite_imports,
+ options::OPT_fno_rewrite_imports, false) &&
!CCGenDiagnostics)
OutputTy = types::getPreprocessedType(OutputTy);
assert(OutputTy != types::TY_INVALID &&
@@ -3186,7 +3313,8 @@ InputInfo Driver::BuildJobsForActionNoCache(
const JobAction *JA = cast<JobAction>(A);
ActionList CollapsedOffloadActions;
- ToolSelector TS(JA, *TC, C, isSaveTempsEnabled(), embedBitcodeInObject());
+ ToolSelector TS(JA, *TC, C, isSaveTempsEnabled(),
+ embedBitcodeInObject() && !isUsingLTO());
const Tool *T = TS.getTool(Inputs, CollapsedOffloadActions);
if (!T)
@@ -3657,125 +3785,135 @@ std::string Driver::GetClPchPath(Compilation &C, StringRef BaseName) const {
const ToolChain &Driver::getToolChain(const ArgList &Args,
const llvm::Triple &Target) const {
- ToolChain *&TC = ToolChains[Target.str()];
+ auto &TC = ToolChains[Target.str()];
if (!TC) {
switch (Target.getOS()) {
case llvm::Triple::Haiku:
- TC = new toolchains::Haiku(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Haiku>(*this, Target, Args);
+ break;
+ case llvm::Triple::Ananas:
+ TC = llvm::make_unique<toolchains::Ananas>(*this, Target, Args);
break;
case llvm::Triple::CloudABI:
- TC = new toolchains::CloudABI(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::CloudABI>(*this, Target, Args);
break;
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
case llvm::Triple::IOS:
case llvm::Triple::TvOS:
case llvm::Triple::WatchOS:
- TC = new toolchains::DarwinClang(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::DarwinClang>(*this, Target, Args);
break;
case llvm::Triple::DragonFly:
- TC = new toolchains::DragonFly(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::DragonFly>(*this, Target, Args);
break;
case llvm::Triple::OpenBSD:
- TC = new toolchains::OpenBSD(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::OpenBSD>(*this, Target, Args);
break;
case llvm::Triple::Bitrig:
- TC = new toolchains::Bitrig(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Bitrig>(*this, Target, Args);
break;
case llvm::Triple::NetBSD:
- TC = new toolchains::NetBSD(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::NetBSD>(*this, Target, Args);
break;
case llvm::Triple::FreeBSD:
- TC = new toolchains::FreeBSD(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::FreeBSD>(*this, Target, Args);
break;
case llvm::Triple::Minix:
- TC = new toolchains::Minix(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Minix>(*this, Target, Args);
break;
case llvm::Triple::Linux:
case llvm::Triple::ELFIAMCU:
if (Target.getArch() == llvm::Triple::hexagon)
- TC = new toolchains::HexagonToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::HexagonToolChain>(*this, Target,
+ Args);
else if ((Target.getVendor() == llvm::Triple::MipsTechnologies) &&
!Target.hasEnvironment())
- TC = new toolchains::MipsLLVMToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::MipsLLVMToolChain>(*this, Target,
+ Args);
else
- TC = new toolchains::Linux(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Linux>(*this, Target, Args);
break;
case llvm::Triple::NaCl:
- TC = new toolchains::NaClToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::NaClToolChain>(*this, Target, Args);
break;
case llvm::Triple::Fuchsia:
- TC = new toolchains::Fuchsia(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Fuchsia>(*this, Target, Args);
break;
case llvm::Triple::Solaris:
- TC = new toolchains::Solaris(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Solaris>(*this, Target, Args);
break;
case llvm::Triple::AMDHSA:
- TC = new toolchains::AMDGPUToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::AMDGPUToolChain>(*this, Target, Args);
break;
case llvm::Triple::Win32:
switch (Target.getEnvironment()) {
default:
if (Target.isOSBinFormatELF())
- TC = new toolchains::Generic_ELF(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
else if (Target.isOSBinFormatMachO())
- TC = new toolchains::MachO(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::MachO>(*this, Target, Args);
else
- TC = new toolchains::Generic_GCC(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Generic_GCC>(*this, Target, Args);
break;
case llvm::Triple::GNU:
- TC = new toolchains::MinGW(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::MinGW>(*this, Target, Args);
break;
case llvm::Triple::Itanium:
- TC = new toolchains::CrossWindowsToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::CrossWindowsToolChain>(*this, Target,
+ Args);
break;
case llvm::Triple::MSVC:
case llvm::Triple::UnknownEnvironment:
- TC = new toolchains::MSVCToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::MSVCToolChain>(*this, Target, Args);
break;
}
break;
case llvm::Triple::PS4:
- TC = new toolchains::PS4CPU(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::PS4CPU>(*this, Target, Args);
break;
case llvm::Triple::Contiki:
- TC = new toolchains::Contiki(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Contiki>(*this, Target, Args);
break;
default:
// Of these targets, Hexagon is the only one that might have
// an OS of Linux, in which case it got handled above already.
switch (Target.getArch()) {
case llvm::Triple::tce:
- TC = new toolchains::TCEToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::TCEToolChain>(*this, Target, Args);
break;
case llvm::Triple::tcele:
- TC = new toolchains::TCELEToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::TCELEToolChain>(*this, Target, Args);
break;
case llvm::Triple::hexagon:
- TC = new toolchains::HexagonToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::HexagonToolChain>(*this, Target,
+ Args);
break;
case llvm::Triple::lanai:
- TC = new toolchains::LanaiToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::LanaiToolChain>(*this, Target, Args);
break;
case llvm::Triple::xcore:
- TC = new toolchains::XCoreToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::XCoreToolChain>(*this, Target, Args);
break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
- TC = new toolchains::WebAssembly(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::WebAssembly>(*this, Target, Args);
break;
case llvm::Triple::avr:
- TC = new toolchains::AVRToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::AVRToolChain>(*this, Target, Args);
break;
default:
if (Target.getVendor() == llvm::Triple::Myriad)
- TC = new toolchains::MyriadToolChain(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::MyriadToolChain>(*this, Target,
+ Args);
+ else if (toolchains::BareMetal::handlesTarget(Target))
+ TC = llvm::make_unique<toolchains::BareMetal>(*this, Target, Args);
else if (Target.isOSBinFormatELF())
- TC = new toolchains::Generic_ELF(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
else if (Target.isOSBinFormatMachO())
- TC = new toolchains::MachO(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::MachO>(*this, Target, Args);
else
- TC = new toolchains::Generic_GCC(*this, Target, Args);
+ TC = llvm::make_unique<toolchains::Generic_GCC>(*this, Target, Args);
}
}
}
diff --git a/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp b/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp
index 8d5332b..ac63b96 100644
--- a/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp
+++ b/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp
@@ -21,10 +21,10 @@ using namespace llvm::opt;
#undef PREFIX
static const OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) \
- { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
- FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
#include "clang/Driver/Options.inc"
#undef OPTION
};
@@ -39,6 +39,6 @@ public:
}
-OptTable *clang::driver::createDriverOptTable() {
- return new DriverOptTable();
+std::unique_ptr<OptTable> clang::driver::createDriverOptTable() {
+ return llvm::make_unique<DriverOptTable>();
}
diff --git a/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp
index 9fd8808..8b85680 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp
+++ b/contrib/llvm/tools/clang/lib/Driver/Job.cpp
@@ -49,7 +49,7 @@ static bool skipArgs(const char *Flag, bool HaveCrashVFS, int &SkipNum,
// arguments. Therefore, we need to skip the flag and the next argument.
bool ShouldSkip = llvm::StringSwitch<bool>(Flag)
.Cases("-MF", "-MT", "-MQ", "-serialize-diagnostic-file", true)
- .Cases("-o", "-coverage-file", "-dependency-file", true)
+ .Cases("-o", "-dependency-file", true)
.Cases("-fdebug-compilation-dir", "-diagnostic-log-file", true)
.Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
.Default(false);
@@ -301,19 +301,33 @@ void Command::setResponseFile(const char *FileName) {
ResponseFileFlag += FileName;
}
+void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
+ Environment.reserve(NewEnvironment.size() + 1);
+ Environment.assign(NewEnvironment.begin(), NewEnvironment.end());
+ Environment.push_back(nullptr);
+}
+
int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
bool *ExecutionFailed) const {
SmallVector<const char*, 128> Argv;
+ const char **Envp;
+ if (Environment.empty()) {
+ Envp = nullptr;
+ } else {
+ assert(Environment.back() == nullptr &&
+ "Environment vector should be null-terminated by now");
+ Envp = const_cast<const char **>(Environment.data());
+ }
+
if (ResponseFile == nullptr) {
Argv.push_back(Executable);
Argv.append(Arguments.begin(), Arguments.end());
Argv.push_back(nullptr);
- return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
- Redirects, /*secondsToWait*/ 0,
- /*memoryLimit*/ 0, ErrMsg,
- ExecutionFailed);
+ return llvm::sys::ExecuteAndWait(
+ Executable, Argv.data(), Envp, Redirects, /*secondsToWait*/ 0,
+ /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
}
// We need to put arguments in a response file (command is too large)
@@ -337,8 +351,8 @@ int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
return -1;
}
- return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
- Redirects, /*secondsToWait*/ 0,
+ return llvm::sys::ExecuteAndWait(Executable, Argv.data(), Envp, Redirects,
+ /*secondsToWait*/ 0,
/*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
}
diff --git a/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp
deleted file mode 100644
index 17fd6ac..0000000
--- a/contrib/llvm/tools/clang/lib/Driver/MSVCToolChain.cpp
+++ /dev/null
@@ -1,892 +0,0 @@
-//===--- ToolChains.cpp - ToolChain Implementations -----------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ToolChains.h"
-#include "Tools.h"
-#include "clang/Basic/CharInfo.h"
-#include "clang/Basic/Version.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Options.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Config/llvm-config.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-#include <cstdio>
-
-// Include the necessary headers to interface with the Windows registry and
-// environment.
-#if defined(LLVM_ON_WIN32)
-#define USE_WIN32
-#endif
-
-#ifdef USE_WIN32
- #define WIN32_LEAN_AND_MEAN
- #define NOGDI
- #ifndef NOMINMAX
- #define NOMINMAX
- #endif
- #include <windows.h>
-#endif
-
-using namespace clang::driver;
-using namespace clang::driver::toolchains;
-using namespace clang;
-using namespace llvm::opt;
-
-MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) {
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir)
- getProgramPaths().push_back(getDriver().Dir);
-}
-
-Tool *MSVCToolChain::buildLinker() const {
- return new tools::visualstudio::Linker(*this);
-}
-
-Tool *MSVCToolChain::buildAssembler() const {
- if (getTriple().isOSBinFormatMachO())
- return new tools::darwin::Assembler(*this);
- getDriver().Diag(clang::diag::err_no_external_assembler);
- return nullptr;
-}
-
-bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
- return true;
-}
-
-bool MSVCToolChain::IsUnwindTablesDefault() const {
- // Emit unwind tables by default on Win64. All non-x86_32 Windows platforms
- // such as ARM and PPC actually require unwind tables, but LLVM doesn't know
- // how to generate them yet.
-
- // Don't emit unwind tables by default for MachO targets.
- if (getTriple().isOSBinFormatMachO())
- return false;
-
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool MSVCToolChain::isPICDefault() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool MSVCToolChain::isPIEDefault() const {
- return false;
-}
-
-bool MSVCToolChain::isPICDefaultForced() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
-}
-
-void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
- CudaInstallation.print(OS);
-}
-
-#ifdef USE_WIN32
-static bool readFullStringValue(HKEY hkey, const char *valueName,
- std::string &value) {
- std::wstring WideValueName;
- if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
- return false;
-
- DWORD result = 0;
- DWORD valueSize = 0;
- DWORD type = 0;
- // First just query for the required size.
- result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
- &valueSize);
- if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
- return false;
- std::vector<BYTE> buffer(valueSize);
- result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
- &valueSize);
- if (result == ERROR_SUCCESS) {
- std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
- valueSize / sizeof(wchar_t));
- if (valueSize && WideValue.back() == L'\0') {
- WideValue.pop_back();
- }
- // The destination buffer must be empty as an invariant of the conversion
- // function; but this function is sometimes called in a loop that passes in
- // the same buffer, however. Simply clear it out so we can overwrite it.
- value.clear();
- return llvm::convertWideToUTF8(WideValue, value);
- }
- return false;
-}
-#endif
-
-/// \brief Read registry string.
-/// This also supports a means to look for high-versioned keys by use
-/// of a $VERSION placeholder in the key path.
-/// $VERSION in the key path is a placeholder for the version number,
-/// causing the highest value path to be searched for and used.
-/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
-/// There can be additional characters in the component. Only the numeric
-/// characters are compared. This function only searches HKLM.
-static bool getSystemRegistryString(const char *keyPath, const char *valueName,
- std::string &value, std::string *phValue) {
-#ifndef USE_WIN32
- return false;
-#else
- HKEY hRootKey = HKEY_LOCAL_MACHINE;
- HKEY hKey = NULL;
- long lResult;
- bool returnValue = false;
-
- const char *placeHolder = strstr(keyPath, "$VERSION");
- std::string bestName;
- // If we have a $VERSION placeholder, do the highest-version search.
- if (placeHolder) {
- const char *keyEnd = placeHolder - 1;
- const char *nextKey = placeHolder;
- // Find end of previous key.
- while ((keyEnd > keyPath) && (*keyEnd != '\\'))
- keyEnd--;
- // Find end of key containing $VERSION.
- while (*nextKey && (*nextKey != '\\'))
- nextKey++;
- size_t partialKeyLength = keyEnd - keyPath;
- char partialKey[256];
- if (partialKeyLength >= sizeof(partialKey))
- partialKeyLength = sizeof(partialKey) - 1;
- strncpy(partialKey, keyPath, partialKeyLength);
- partialKey[partialKeyLength] = '\0';
- HKEY hTopKey = NULL;
- lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
- &hTopKey);
- if (lResult == ERROR_SUCCESS) {
- char keyName[256];
- double bestValue = 0.0;
- DWORD index, size = sizeof(keyName) - 1;
- for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
- NULL, NULL) == ERROR_SUCCESS;
- index++) {
- const char *sp = keyName;
- while (*sp && !isDigit(*sp))
- sp++;
- if (!*sp)
- continue;
- const char *ep = sp + 1;
- while (*ep && (isDigit(*ep) || (*ep == '.')))
- ep++;
- char numBuf[32];
- strncpy(numBuf, sp, sizeof(numBuf) - 1);
- numBuf[sizeof(numBuf) - 1] = '\0';
- double dvalue = strtod(numBuf, NULL);
- if (dvalue > bestValue) {
- // Test that InstallDir is indeed there before keeping this index.
- // Open the chosen key path remainder.
- bestName = keyName;
- // Append rest of key.
- bestName.append(nextKey);
- lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
- KEY_READ | KEY_WOW64_32KEY, &hKey);
- if (lResult == ERROR_SUCCESS) {
- if (readFullStringValue(hKey, valueName, value)) {
- bestValue = dvalue;
- if (phValue)
- *phValue = bestName;
- returnValue = true;
- }
- RegCloseKey(hKey);
- }
- }
- size = sizeof(keyName) - 1;
- }
- RegCloseKey(hTopKey);
- }
- } else {
- lResult =
- RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
- if (lResult == ERROR_SUCCESS) {
- if (readFullStringValue(hKey, valueName, value))
- returnValue = true;
- if (phValue)
- phValue->clear();
- RegCloseKey(hKey);
- }
- }
- return returnValue;
-#endif // USE_WIN32
-}
-
-// Convert LLVM's ArchType
-// to the corresponding name of Windows SDK libraries subfolder
-static StringRef getWindowsSDKArch(llvm::Triple::ArchType Arch) {
- switch (Arch) {
- case llvm::Triple::x86:
- return "x86";
- case llvm::Triple::x86_64:
- return "x64";
- case llvm::Triple::arm:
- return "arm";
- default:
- return "";
- }
-}
-
-// Find the most recent version of Universal CRT or Windows 10 SDK.
-// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
-// directory by name and uses the last one of the list.
-// So we compare entry names lexicographically to find the greatest one.
-static bool getWindows10SDKVersion(const std::string &SDKPath,
- std::string &SDKVersion) {
- SDKVersion.clear();
-
- std::error_code EC;
- llvm::SmallString<128> IncludePath(SDKPath);
- llvm::sys::path::append(IncludePath, "Include");
- for (llvm::sys::fs::directory_iterator DirIt(IncludePath, EC), DirEnd;
- DirIt != DirEnd && !EC; DirIt.increment(EC)) {
- if (!llvm::sys::fs::is_directory(DirIt->path()))
- continue;
- StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
- // If WDK is installed, there could be subfolders like "wdf" in the
- // "Include" directory.
- // Allow only directories which names start with "10.".
- if (!CandidateName.startswith("10."))
- continue;
- if (CandidateName > SDKVersion)
- SDKVersion = CandidateName;
- }
-
- return !SDKVersion.empty();
-}
-
-/// \brief Get Windows SDK installation directory.
-bool MSVCToolChain::getWindowsSDKDir(std::string &Path, int &Major,
- std::string &WindowsSDKIncludeVersion,
- std::string &WindowsSDKLibVersion) const {
- std::string RegistrySDKVersion;
- // Try the Windows registry.
- if (!getSystemRegistryString(
- "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
- "InstallationFolder", Path, &RegistrySDKVersion))
- return false;
- if (Path.empty() || RegistrySDKVersion.empty())
- return false;
-
- WindowsSDKIncludeVersion.clear();
- WindowsSDKLibVersion.clear();
- Major = 0;
- std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
- if (Major <= 7)
- return true;
- if (Major == 8) {
- // Windows SDK 8.x installs libraries in a folder whose names depend on the
- // version of the OS you're targeting. By default choose the newest, which
- // usually corresponds to the version of the OS you've installed the SDK on.
- const char *Tests[] = {"winv6.3", "win8", "win7"};
- for (const char *Test : Tests) {
- llvm::SmallString<128> TestPath(Path);
- llvm::sys::path::append(TestPath, "Lib", Test);
- if (llvm::sys::fs::exists(TestPath.c_str())) {
- WindowsSDKLibVersion = Test;
- break;
- }
- }
- return !WindowsSDKLibVersion.empty();
- }
- if (Major == 10) {
- if (!getWindows10SDKVersion(Path, WindowsSDKIncludeVersion))
- return false;
- WindowsSDKLibVersion = WindowsSDKIncludeVersion;
- return true;
- }
- // Unsupported SDK version
- return false;
-}
-
-// Gets the library path required to link against the Windows SDK.
-bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
- std::string sdkPath;
- int sdkMajor = 0;
- std::string windowsSDKIncludeVersion;
- std::string windowsSDKLibVersion;
-
- path.clear();
- if (!getWindowsSDKDir(sdkPath, sdkMajor, windowsSDKIncludeVersion,
- windowsSDKLibVersion))
- return false;
-
- llvm::SmallString<128> libPath(sdkPath);
- llvm::sys::path::append(libPath, "Lib");
- if (sdkMajor <= 7) {
- switch (getArch()) {
- // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
- case llvm::Triple::x86:
- break;
- case llvm::Triple::x86_64:
- llvm::sys::path::append(libPath, "x64");
- break;
- case llvm::Triple::arm:
- // It is not necessary to link against Windows SDK 7.x when targeting ARM.
- return false;
- default:
- return false;
- }
- } else {
- const StringRef archName = getWindowsSDKArch(getArch());
- if (archName.empty())
- return false;
- llvm::sys::path::append(libPath, windowsSDKLibVersion, "um", archName);
- }
-
- path = libPath.str();
- return true;
-}
-
-// Check if the Include path of a specified version of Visual Studio contains
-// specific header files. If not, they are probably shipped with Universal CRT.
-bool clang::driver::toolchains::MSVCToolChain::useUniversalCRT(
- std::string &VisualStudioDir) const {
- llvm::SmallString<128> TestPath(VisualStudioDir);
- llvm::sys::path::append(TestPath, "VC\\include\\stdlib.h");
-
- return !llvm::sys::fs::exists(TestPath);
-}
-
-bool MSVCToolChain::getUniversalCRTSdkDir(std::string &Path,
- std::string &UCRTVersion) const {
- // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
- // for the specific key "KitsRoot10". So do we.
- if (!getSystemRegistryString(
- "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
- Path, nullptr))
- return false;
-
- return getWindows10SDKVersion(Path, UCRTVersion);
-}
-
-bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
- std::string UniversalCRTSdkPath;
- std::string UCRTVersion;
-
- Path.clear();
- if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion))
- return false;
-
- StringRef ArchName = getWindowsSDKArch(getArch());
- if (ArchName.empty())
- return false;
-
- llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
- llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
-
- Path = LibPath.str();
- return true;
-}
-
-// Get the location to use for Visual Studio binaries. The location priority
-// is: %VCINSTALLDIR% > %PATH% > newest copy of Visual Studio installed on
-// system (as reported by the registry).
-bool MSVCToolChain::getVisualStudioBinariesFolder(const char *clangProgramPath,
- std::string &path) const {
- path.clear();
-
- SmallString<128> BinDir;
-
- // First check the environment variables that vsvars32.bat sets.
- llvm::Optional<std::string> VcInstallDir =
- llvm::sys::Process::GetEnv("VCINSTALLDIR");
- if (VcInstallDir.hasValue()) {
- BinDir = VcInstallDir.getValue();
- llvm::sys::path::append(BinDir, "bin");
- } else {
- // Next walk the PATH, trying to find a cl.exe in the path. If we find one,
- // use that. However, make sure it's not clang's cl.exe.
- llvm::Optional<std::string> OptPath = llvm::sys::Process::GetEnv("PATH");
- if (OptPath.hasValue()) {
- const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
- SmallVector<StringRef, 8> PathSegments;
- llvm::SplitString(OptPath.getValue(), PathSegments, EnvPathSeparatorStr);
-
- for (StringRef PathSegment : PathSegments) {
- if (PathSegment.empty())
- continue;
-
- SmallString<128> FilePath(PathSegment);
- llvm::sys::path::append(FilePath, "cl.exe");
- // Checking if cl.exe exists is a small optimization over calling
- // can_execute, which really only checks for existence but will also do
- // extra checks for cl.exe.exe. These add up when walking a long path.
- if (llvm::sys::fs::exists(FilePath.c_str()) &&
- !llvm::sys::fs::equivalent(FilePath.c_str(), clangProgramPath)) {
- // If we found it on the PATH, use it exactly as is with no
- // modifications.
- path = PathSegment;
- return true;
- }
- }
- }
-
- std::string installDir;
- // With no VCINSTALLDIR and nothing on the PATH, if we can't find it in the
- // registry then we have no choice but to fail.
- if (!getVisualStudioInstallDir(installDir))
- return false;
-
- // Regardless of what binary we're ultimately trying to find, we make sure
- // that this is a Visual Studio directory by checking for cl.exe. We use
- // cl.exe instead of other binaries like link.exe because programs such as
- // GnuWin32 also have a utility called link.exe, so cl.exe is the least
- // ambiguous.
- BinDir = installDir;
- llvm::sys::path::append(BinDir, "VC", "bin");
- SmallString<128> ClPath(BinDir);
- llvm::sys::path::append(ClPath, "cl.exe");
-
- if (!llvm::sys::fs::can_execute(ClPath.c_str()))
- return false;
- }
-
- if (BinDir.empty())
- return false;
-
- switch (getArch()) {
- case llvm::Triple::x86:
- break;
- case llvm::Triple::x86_64:
- llvm::sys::path::append(BinDir, "amd64");
- break;
- case llvm::Triple::arm:
- llvm::sys::path::append(BinDir, "arm");
- break;
- default:
- // Whatever this is, Visual Studio doesn't have a toolchain for it.
- return false;
- }
- path = BinDir.str();
- return true;
-}
-
-VersionTuple MSVCToolChain::getMSVCVersionFromTriple() const {
- unsigned Major, Minor, Micro;
- getTriple().getEnvironmentVersion(Major, Minor, Micro);
- if (Major || Minor || Micro)
- return VersionTuple(Major, Minor, Micro);
- return VersionTuple();
-}
-
-VersionTuple MSVCToolChain::getMSVCVersionFromExe() const {
- VersionTuple Version;
-#ifdef USE_WIN32
- std::string BinPath;
- if (!getVisualStudioBinariesFolder("", BinPath))
- return Version;
- SmallString<128> ClExe(BinPath);
- llvm::sys::path::append(ClExe, "cl.exe");
-
- std::wstring ClExeWide;
- if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))
- return Version;
-
- const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
- nullptr);
- if (VersionSize == 0)
- return Version;
-
- SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);
- if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,
- VersionBlock.data()))
- return Version;
-
- VS_FIXEDFILEINFO *FileInfo = nullptr;
- UINT FileInfoSize = 0;
- if (!::VerQueryValueW(VersionBlock.data(), L"\\",
- reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) ||
- FileInfoSize < sizeof(*FileInfo))
- return Version;
-
- const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;
- const unsigned Minor = (FileInfo->dwFileVersionMS ) & 0xFFFF;
- const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;
-
- Version = VersionTuple(Major, Minor, Micro);
-#endif
- return Version;
-}
-
-// Get Visual Studio installation directory.
-bool MSVCToolChain::getVisualStudioInstallDir(std::string &path) const {
- // First check the environment variables that vsvars32.bat sets.
- if (llvm::Optional<std::string> VcInstallDir =
- llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
- path = std::move(*VcInstallDir);
- path = path.substr(0, path.find("\\VC"));
- return true;
- }
-
- std::string vsIDEInstallDir;
- std::string vsExpressIDEInstallDir;
- // Then try the windows registry.
- bool hasVCDir =
- getSystemRegistryString("SOFTWARE\\Microsoft\\VisualStudio\\$VERSION",
- "InstallDir", vsIDEInstallDir, nullptr);
- if (hasVCDir && !vsIDEInstallDir.empty()) {
- path = vsIDEInstallDir.substr(0, vsIDEInstallDir.find("\\Common7\\IDE"));
- return true;
- }
-
- bool hasVCExpressDir =
- getSystemRegistryString("SOFTWARE\\Microsoft\\VCExpress\\$VERSION",
- "InstallDir", vsExpressIDEInstallDir, nullptr);
- if (hasVCExpressDir && !vsExpressIDEInstallDir.empty()) {
- path = vsExpressIDEInstallDir.substr(
- 0, vsIDEInstallDir.find("\\Common7\\IDE"));
- return true;
- }
-
- // Try the environment.
- std::string vcomntools;
- if (llvm::Optional<std::string> vs120comntools =
- llvm::sys::Process::GetEnv("VS120COMNTOOLS"))
- vcomntools = std::move(*vs120comntools);
- else if (llvm::Optional<std::string> vs100comntools =
- llvm::sys::Process::GetEnv("VS100COMNTOOLS"))
- vcomntools = std::move(*vs100comntools);
- else if (llvm::Optional<std::string> vs90comntools =
- llvm::sys::Process::GetEnv("VS90COMNTOOLS"))
- vcomntools = std::move(*vs90comntools);
- else if (llvm::Optional<std::string> vs80comntools =
- llvm::sys::Process::GetEnv("VS80COMNTOOLS"))
- vcomntools = std::move(*vs80comntools);
-
- // Find any version we can.
- if (!vcomntools.empty()) {
- size_t p = vcomntools.find("\\Common7\\Tools");
- if (p != std::string::npos)
- vcomntools.resize(p);
- path = std::move(vcomntools);
- return true;
- }
- return false;
-}
-
-void MSVCToolChain::AddSystemIncludeWithSubfolder(
- const ArgList &DriverArgs, ArgStringList &CC1Args,
- const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,
- const Twine &subfolder3) const {
- llvm::SmallString<128> path(folder);
- llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3);
- addSystemInclude(DriverArgs, CC1Args, path);
-}
-
-void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc))
- return;
-
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,
- "include");
- }
-
- // Add %INCLUDE%-like directories from the -imsvc flag.
- for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
- addSystemInclude(DriverArgs, CC1Args, Path);
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
- if (llvm::Optional<std::string> cl_include_dir =
- llvm::sys::Process::GetEnv("INCLUDE")) {
- SmallVector<StringRef, 8> Dirs;
- StringRef(*cl_include_dir)
- .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- for (StringRef Dir : Dirs)
- addSystemInclude(DriverArgs, CC1Args, Dir);
- if (!Dirs.empty())
- return;
- }
-
- std::string VSDir;
-
- // When built with access to the proper Windows APIs, try to actually find
- // the correct include paths first.
- if (getVisualStudioInstallDir(VSDir)) {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, VSDir, "VC\\include");
-
- if (useUniversalCRT(VSDir)) {
- std::string UniversalCRTSdkPath;
- std::string UCRTVersion;
- if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
- "Include", UCRTVersion, "ucrt");
- }
- }
-
- std::string WindowsSDKDir;
- int major;
- std::string windowsSDKIncludeVersion;
- std::string windowsSDKLibVersion;
- if (getWindowsSDKDir(WindowsSDKDir, major, windowsSDKIncludeVersion,
- windowsSDKLibVersion)) {
- if (major >= 8) {
- // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
- // Anyway, llvm::sys::path::append is able to manage it.
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
- "include", windowsSDKIncludeVersion,
- "shared");
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
- "include", windowsSDKIncludeVersion,
- "um");
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
- "include", windowsSDKIncludeVersion,
- "winrt");
- } else {
- AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
- "include");
- }
- } else {
- addSystemInclude(DriverArgs, CC1Args, VSDir);
- }
- return;
- }
-
-#if defined(LLVM_ON_WIN32)
- // As a fallback, select default install paths.
- // FIXME: Don't guess drives and paths like this on Windows.
- const StringRef Paths[] = {
- "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
- "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
- "C:/Program Files/Microsoft Visual Studio 8/VC/include",
- "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
- };
- addSystemIncludes(DriverArgs, CC1Args, Paths);
-#endif
-}
-
-void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- // FIXME: There should probably be logic here to find libc++ on Windows.
-}
-
-VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
- const ArgList &Args) const {
- bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
- VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
- if (MSVT.empty()) MSVT = getMSVCVersionFromTriple();
- if (MSVT.empty() && IsWindowsMSVC) MSVT = getMSVCVersionFromExe();
- if (MSVT.empty() &&
- Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
- IsWindowsMSVC)) {
- // -fms-compatibility-version=18.00 is default.
- // FIXME: Consider bumping this to 19 (MSVC2015) soon.
- MSVT = VersionTuple(18);
- }
- return MSVT;
-}
-
-std::string
-MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
- types::ID InputType) const {
- // The MSVC version doesn't care about the architecture, even though it
- // may look at the triple internally.
- VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);
- MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0),
- MSVT.getSubminor().getValueOr(0));
-
- // For the rest of the triple, however, a computed architecture name may
- // be needed.
- llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));
- if (Triple.getEnvironment() == llvm::Triple::MSVC) {
- StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;
- if (ObjFmt.empty())
- Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());
- else
- Triple.setEnvironmentName(
- (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str());
- }
- return Triple.getTriple();
-}
-
-SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- Res |= SanitizerKind::Address;
- return Res;
-}
-
-static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
- bool SupportsForcingFramePointer,
- const char *ExpandChar, const OptTable &Opts) {
- assert(A->getOption().matches(options::OPT__SLASH_O));
-
- StringRef OptStr = A->getValue();
- for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
- const char &OptChar = *(OptStr.data() + I);
- switch (OptChar) {
- default:
- break;
- case '1':
- case '2':
- case 'x':
- case 'd':
- if (&OptChar == ExpandChar) {
- if (OptChar == 'd') {
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
- } else {
- if (OptChar == '1') {
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
- } else if (OptChar == '2' || OptChar == 'x') {
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
- }
- if (SupportsForcingFramePointer &&
- !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))
- DAL.AddFlagArg(A,
- Opts.getOption(options::OPT_fomit_frame_pointer));
- if (OptChar == '1' || OptChar == '2')
- DAL.AddFlagArg(A,
- Opts.getOption(options::OPT_ffunction_sections));
- }
- }
- break;
- case 'b':
- if (I + 1 != E && isdigit(OptStr[I + 1])) {
- switch (OptStr[I + 1]) {
- case '0':
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
- break;
- case '1':
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
- break;
- case '2':
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));
- break;
- }
- ++I;
- }
- break;
- case 'g':
- break;
- case 'i':
- if (I + 1 != E && OptStr[I + 1] == '-') {
- ++I;
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
- } else {
- DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
- }
- break;
- case 's':
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
- break;
- case 't':
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
- break;
- case 'y': {
- bool OmitFramePointer = true;
- if (I + 1 != E && OptStr[I + 1] == '-') {
- OmitFramePointer = false;
- ++I;
- }
- if (SupportsForcingFramePointer) {
- if (OmitFramePointer)
- DAL.AddFlagArg(A,
- Opts.getOption(options::OPT_fomit_frame_pointer));
- else
- DAL.AddFlagArg(
- A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
- } else {
- // Don't warn about /Oy- in 64-bit builds (where
- // SupportsForcingFramePointer is false). The flag having no effect
- // there is a compiler-internal optimization, and people shouldn't have
- // to special-case their build files for 64-bit clang-cl.
- A->claim();
- }
- break;
- }
- }
- }
-}
-
-static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
- const OptTable &Opts) {
- assert(A->getOption().matches(options::OPT_D));
-
- StringRef Val = A->getValue();
- size_t Hash = Val.find('#');
- if (Hash == StringRef::npos || Hash > Val.find('=')) {
- DAL.append(A);
- return;
- }
-
- std::string NewVal = Val;
- NewVal[Hash] = '=';
- DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
-}
-
-llvm::opt::DerivedArgList *
-MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
- StringRef BoundArch, Action::OffloadKind) const {
- DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
- const OptTable &Opts = getDriver().getOpts();
-
- // /Oy and /Oy- only has an effect under X86-32.
- bool SupportsForcingFramePointer = getArch() == llvm::Triple::x86;
-
- // The -O[12xd] flag actually expands to several flags. We must desugar the
- // flags so that options embedded can be negated. For example, the '-O2' flag
- // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to
- // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single
- // aspect of '-O2'.
- //
- // Note that this expansion logic only applies to the *last* of '[12xd]'.
-
- // First step is to search for the character we'd like to expand.
- const char *ExpandChar = nullptr;
- for (Arg *A : Args) {
- if (!A->getOption().matches(options::OPT__SLASH_O))
- continue;
- StringRef OptStr = A->getValue();
- for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
- char OptChar = OptStr[I];
- char PrevChar = I > 0 ? OptStr[I - 1] : '0';
- if (PrevChar == 'b') {
- // OptChar does not expand; it's an argument to the previous char.
- continue;
- }
- if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')
- ExpandChar = OptStr.data() + I;
- }
- }
-
- for (Arg *A : Args) {
- if (A->getOption().matches(options::OPT__SLASH_O)) {
- // The -O flag actually takes an amalgam of other options. For example,
- // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
- TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
- } else if (A->getOption().matches(options::OPT_D)) {
- // Translate -Dfoo#bar into -Dfoo=bar.
- TranslateDArg(A, *DAL, Opts);
- } else {
- DAL->append(A);
- }
- }
-
- return DAL;
-}
diff --git a/contrib/llvm/tools/clang/lib/Driver/MinGWToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/MinGWToolChain.cpp
deleted file mode 100644
index e971869..0000000
--- a/contrib/llvm/tools/clang/lib/Driver/MinGWToolChain.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-//===--- MinGWToolChain.cpp - MinGWToolChain Implementation ---------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ToolChains.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/Options.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-
-using namespace clang::diag;
-using namespace clang::driver;
-using namespace clang::driver::toolchains;
-using namespace clang;
-using namespace llvm::opt;
-
-// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
-static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
- std::string &Ver) {
- Generic_GCC::GCCVersion Version = Generic_GCC::GCCVersion::Parse("0.0.0");
- std::error_code EC;
- for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
- LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->path());
- Generic_GCC::GCCVersion CandidateVersion =
- Generic_GCC::GCCVersion::Parse(VersionText);
- if (CandidateVersion.Major == -1)
- continue;
- if (CandidateVersion <= Version)
- continue;
- Ver = VersionText;
- GccLibDir = LI->path();
- }
- return Ver.size();
-}
-
-void MinGW::findGccLibDir() {
- llvm::SmallVector<llvm::SmallString<32>, 2> Archs;
- Archs.emplace_back(getTriple().getArchName());
- Archs[0] += "-w64-mingw32";
- Archs.emplace_back("mingw32");
- Arch = Archs[0].str();
- // lib: Arch Linux, Ubuntu, Windows
- // lib64: openSUSE Linux
- for (StringRef CandidateLib : {"lib", "lib64"}) {
- for (StringRef CandidateArch : Archs) {
- llvm::SmallString<1024> LibDir(Base);
- llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch);
- if (findGccVersion(LibDir, GccLibDir, Ver)) {
- Arch = CandidateArch;
- return;
- }
- }
- }
-}
-
-MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) {
- getProgramPaths().push_back(getDriver().getInstalledDir());
-
-// In Windows there aren't any standard install locations, we search
-// for gcc on the PATH. In Linux the base is always /usr.
-#ifdef LLVM_ON_WIN32
- if (getDriver().SysRoot.size())
- Base = getDriver().SysRoot;
- else if (llvm::ErrorOr<std::string> GPPName =
- llvm::sys::findProgramByName("gcc"))
- Base = llvm::sys::path::parent_path(
- llvm::sys::path::parent_path(GPPName.get()));
- else
- Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
-#else
- if (getDriver().SysRoot.size())
- Base = getDriver().SysRoot;
- else
- Base = "/usr";
-#endif
-
- Base += llvm::sys::path::get_separator();
- findGccLibDir();
- // GccLibDir must precede Base/lib so that the
- // correct crtbegin.o ,cetend.o would be found.
- getFilePaths().push_back(GccLibDir);
- getFilePaths().push_back(
- (Base + Arch + llvm::sys::path::get_separator() + "lib").str());
- getFilePaths().push_back(Base + "lib");
- // openSUSE
- getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib");
-}
-
-bool MinGW::IsIntegratedAssemblerDefault() const { return true; }
-
-Tool *MinGW::getTool(Action::ActionClass AC) const {
- switch (AC) {
- case Action::PreprocessJobClass:
- if (!Preprocessor)
- Preprocessor.reset(new tools::gcc::Preprocessor(*this));
- return Preprocessor.get();
- case Action::CompileJobClass:
- if (!Compiler)
- Compiler.reset(new tools::gcc::Compiler(*this));
- return Compiler.get();
- default:
- return ToolChain::getTool(AC);
- }
-}
-
-Tool *MinGW::buildAssembler() const {
- return new tools::MinGW::Assembler(*this);
-}
-
-Tool *MinGW::buildLinker() const { return new tools::MinGW::Linker(*this); }
-
-bool MinGW::IsUnwindTablesDefault() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool MinGW::isPICDefault() const { return getArch() == llvm::Triple::x86_64; }
-
-bool MinGW::isPIEDefault() const { return false; }
-
-bool MinGW::isPICDefaultForced() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool MinGW::UseSEHExceptions() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-void MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
-}
-
-void MinGW::printVerboseInfo(raw_ostream &OS) const {
- CudaInstallation.print(OS);
-}
-
-// Include directories for various hosts:
-
-// Windows, mingw.org
-// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++
-// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32
-// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward
-// c:\mingw\lib\gcc\mingw32\4.8.1\include
-// c:\mingw\include
-// c:\mingw\lib\gcc\mingw32\4.8.1\include-fixed
-// c:\mingw\mingw32\include
-
-// Windows, mingw-w64 mingw-builds
-// c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include
-// c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include-fixed
-// c:\mingw32\i686-w64-mingw32\include
-// c:\mingw32\i686-w64-mingw32\include\c++
-// c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32
-// c:\mingw32\i686-w64-mingw32\include\c++\backward
-
-// Windows, mingw-w64 msys2
-// c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include
-// c:\msys64\mingw32\include
-// c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include-fixed
-// c:\msys64\mingw32\i686-w64-mingw32\include
-// c:\msys64\mingw32\include\c++\4.9.2
-// c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32
-// c:\msys64\mingw32\include\c++\4.9.2\backward
-
-// openSUSE
-// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++
-// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32
-// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward
-// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include
-// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include-fixed
-// /usr/x86_64-w64-mingw32/sys-root/mingw/include
-
-// Arch Linux
-// /usr/i686-w64-mingw32/include/c++/5.1.0
-// /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32
-// /usr/i686-w64-mingw32/include/c++/5.1.0/backward
-// /usr/lib/gcc/i686-w64-mingw32/5.1.0/include
-// /usr/lib/gcc/i686-w64-mingw32/5.1.0/include-fixed
-// /usr/i686-w64-mingw32/include
-
-// Ubuntu
-// /usr/include/c++/4.8
-// /usr/include/c++/4.8/x86_64-w64-mingw32
-// /usr/include/c++/4.8/backward
-// /usr/lib/gcc/x86_64-w64-mingw32/4.8/include
-// /usr/lib/gcc/x86_64-w64-mingw32/4.8/include-fixed
-// /usr/x86_64-w64-mingw32/include
-
-void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc))
- return;
-
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- SmallString<1024> P(getDriver().ResourceDir);
- llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
- }
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) {
- llvm::SmallString<1024> IncludeDir(GccLibDir);
- llvm::sys::path::append(IncludeDir, "include");
- addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
- IncludeDir += "-fixed";
- // openSUSE
- addSystemInclude(DriverArgs, CC1Args,
- Base + Arch + "/sys-root/mingw/include");
- addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
- }
- addSystemInclude(DriverArgs, CC1Args,
- Base + Arch + llvm::sys::path::get_separator() + "include");
- addSystemInclude(DriverArgs, CC1Args, Base + "include");
-}
-
-void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
- return;
-
- switch (GetCXXStdlibType(DriverArgs)) {
- case ToolChain::CST_Libcxx:
- addSystemInclude(DriverArgs, CC1Args,
- Base + "include" + llvm::sys::path::get_separator() +
- "c++" + llvm::sys::path::get_separator() + "v1");
- break;
-
- case ToolChain::CST_Libstdcxx:
- llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
- CppIncludeBases.emplace_back(Base);
- llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++");
- CppIncludeBases.emplace_back(Base);
- llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver);
- CppIncludeBases.emplace_back(Base);
- llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
- CppIncludeBases.emplace_back(GccLibDir);
- llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
- for (auto &CppIncludeBase : CppIncludeBases) {
- addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
- CppIncludeBase += llvm::sys::path::get_separator();
- addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch);
- addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
- }
- break;
- }
-}
diff --git a/contrib/llvm/tools/clang/lib/Driver/Multilib.cpp b/contrib/llvm/tools/clang/lib/Driver/Multilib.cpp
index a88edf7..16a8160 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Multilib.cpp
+++ b/contrib/llvm/tools/clang/lib/Driver/Multilib.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Multilib.h"
-#include "Tools.h"
+#include "ToolChains/CommonArgs.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -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/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp
index f4f6dad..7a442c8 100644
--- a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp
+++ b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/SanitizerArgs.h"
-#include "Tools.h"
+#include "ToolChains/CommonArgs.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
@@ -26,18 +26,19 @@ using namespace clang::driver;
using namespace llvm::opt;
enum : SanitizerMask {
- NeedsUbsanRt = Undefined | Integer | CFI,
+ NeedsUbsanRt = Undefined | Integer | Nullability | CFI,
NeedsUbsanCxxRt = Vptr | CFI,
NotAllowedWithTrap = Vptr,
RequiresPIE = DataFlow,
NeedsUnwindTables = Address | Thread | Memory | DataFlow,
- SupportsCoverage = Address | Memory | Leak | Undefined | Integer | DataFlow,
- RecoverableByDefault = Undefined | Integer,
+ SupportsCoverage = Address | KernelAddress | Memory | Leak | Undefined |
+ Integer | Nullability | DataFlow | Fuzzer,
+ RecoverableByDefault = Undefined | Integer | Nullability,
Unrecoverable = Unreachable | Return,
LegacyFsanitizeRecoverMask = Undefined | Integer,
NeedsLTO = CFI,
- TrappingSupported =
- (Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI,
+ TrappingSupported = (Undefined & ~Vptr) | UnsignedIntegerOverflow |
+ Nullability | LocalBounds | CFI,
TrappingDefault = CFI,
CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast,
};
@@ -47,13 +48,15 @@ enum CoverageFeature {
CoverageBB = 1 << 1,
CoverageEdge = 1 << 2,
CoverageIndirCall = 1 << 3,
- CoverageTraceBB = 1 << 4,
+ CoverageTraceBB = 1 << 4, // Deprecated.
CoverageTraceCmp = 1 << 5,
CoverageTraceDiv = 1 << 6,
CoverageTraceGep = 1 << 7,
- Coverage8bitCounters = 1 << 8,
+ Coverage8bitCounters = 1 << 8, // Deprecated.
CoverageTracePC = 1 << 9,
CoverageTracePCGuard = 1 << 10,
+ CoverageInline8bitCounters = 1 << 12,
+ CoverageNoPrune = 1 << 11,
};
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
@@ -205,12 +208,28 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args);
SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap;
+ // The object size sanitizer should not be enabled at -O0.
+ Arg *OptLevel = Args.getLastArg(options::OPT_O_Group);
+ bool RemoveObjectSizeAtO0 =
+ !OptLevel || OptLevel->getOption().matches(options::OPT_O0);
+
for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
I != E; ++I) {
const auto *Arg = *I;
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
Arg->claim();
- SanitizerMask Add = parseArgValues(D, Arg, true);
+ SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true);
+
+ if (RemoveObjectSizeAtO0) {
+ AllRemove |= SanitizerKind::ObjectSize;
+
+ // The user explicitly enabled the object size sanitizer. Warn that
+ // that this does nothing at -O0.
+ if (Add & SanitizerKind::ObjectSize)
+ D.Diag(diag::warn_drv_object_size_disabled_O0)
+ << Arg->getAsString(Args);
+ }
+
AllAddedKinds |= expandSanitizerGroups(Add);
// Avoid diagnosing any sanitizer which is disabled later.
@@ -264,6 +283,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Add &= ~InvalidTrappingKinds;
Add &= Supported;
+ // Enable coverage if the fuzzing flag is set.
+ if (Add & Fuzzer)
+ CoverageFeatures |= CoverageTracePCGuard | CoverageIndirCall | CoverageTraceCmp;
+
Kinds |= Add;
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) {
Arg->claim();
@@ -468,34 +491,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
int LegacySanitizeCoverage;
if (Arg->getNumValues() == 1 &&
!StringRef(Arg->getValue(0))
- .getAsInteger(0, LegacySanitizeCoverage) &&
- LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) {
- switch (LegacySanitizeCoverage) {
- case 0:
- CoverageFeatures = 0;
- Arg->claim();
- break;
- case 1:
- D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
- << "-fsanitize-coverage=func";
- CoverageFeatures = CoverageFunc;
- break;
- case 2:
- D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
- << "-fsanitize-coverage=bb";
- CoverageFeatures = CoverageBB;
- break;
- case 3:
- D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args)
- << "-fsanitize-coverage=edge";
- CoverageFeatures = CoverageEdge;
- break;
- case 4:
+ .getAsInteger(0, LegacySanitizeCoverage)) {
+ CoverageFeatures = 0;
+ Arg->claim();
+ if (LegacySanitizeCoverage != 0) {
D.Diag(diag::warn_drv_deprecated_arg)
- << Arg->getAsString(Args)
- << "-fsanitize-coverage=edge,indirect-calls";
- CoverageFeatures = CoverageEdge | CoverageIndirCall;
- break;
+ << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard";
}
continue;
}
@@ -528,20 +529,27 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
<< "-fsanitize-coverage=edge";
// Basic block tracing and 8-bit counters require some type of coverage
// enabled.
- int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge;
- if ((CoverageFeatures & CoverageTraceBB) &&
- !(CoverageFeatures & CoverageTypes))
- D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ if (CoverageFeatures & CoverageTraceBB)
+ D.Diag(clang::diag::warn_drv_deprecated_arg)
<< "-fsanitize-coverage=trace-bb"
- << "-fsanitize-coverage=(func|bb|edge)";
- if ((CoverageFeatures & Coverage8bitCounters) &&
- !(CoverageFeatures & CoverageTypes))
- D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << "-fsanitize-coverage=trace-pc-guard";
+ if (CoverageFeatures & Coverage8bitCounters)
+ D.Diag(clang::diag::warn_drv_deprecated_arg)
<< "-fsanitize-coverage=8bit-counters"
- << "-fsanitize-coverage=(func|bb|edge)";
+ << "-fsanitize-coverage=trace-pc-guard";
+
+ int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge;
+ if ((CoverageFeatures & InsertionPointTypes) &&
+ !(CoverageFeatures &(CoverageTracePC | CoverageTracePCGuard))) {
+ D.Diag(clang::diag::warn_drv_deprecated_arg)
+ << "-fsanitize-coverage=[func|bb|edge]"
+ << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]";
+ }
+
// trace-pc w/o func/bb/edge implies edge.
- if ((CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard)) &&
- !(CoverageFeatures & CoverageTypes))
+ if ((CoverageFeatures &
+ (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters)) &&
+ !(CoverageFeatures & InsertionPointTypes))
CoverageFeatures |= CoverageEdge;
if (AllAddedKinds & Address) {
@@ -573,12 +581,18 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
}
}
- if (Arg *A = Args.getLastArg(
- options::OPT_fsanitize_address_use_after_scope,
- options::OPT_fno_sanitize_address_use_after_scope)) {
- AsanUseAfterScope = A->getOption().getID() ==
- options::OPT_fsanitize_address_use_after_scope;
- }
+ AsanUseAfterScope = Args.hasFlag(
+ options::OPT_fsanitize_address_use_after_scope,
+ options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope);
+
+ // As a workaround for a bug in gold 2.26 and earlier, dead stripping of
+ // globals in ASan is disabled by default on ELF targets.
+ // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002
+ AsanGlobalsDeadStripping =
+ !TC.getTriple().isOSBinFormatELF() ||
+ Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping);
+ } else {
+ AsanUseAfterScope = false;
}
// Parse -link-cxx-sanitizer flag.
@@ -640,10 +654,12 @@ 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(CoverageInline8bitCounters, "-fsanitize-coverage-inline-8bit-counters"),
+ std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune")};
for (auto F : CoverageFlags) {
if (CoverageFeatures & F.first)
- CmdArgs.push_back(Args.MakeArgString(F.second));
+ CmdArgs.push_back(F.second);
}
if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
@@ -696,7 +712,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::utostr(MsanTrackOrigins)));
if (MsanUseAfterDtor)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-use-after-dtor"));
+ CmdArgs.push_back("-fsanitize-memory-use-after-dtor");
// FIXME: Pass these parameters as function attributes, not as -llvm flags.
if (!TsanMemoryAccess) {
@@ -715,17 +731,20 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
}
if (CfiCrossDso)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso"));
+ CmdArgs.push_back("-fsanitize-cfi-cross-dso");
if (Stats)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-stats"));
+ CmdArgs.push_back("-fsanitize-stats");
if (AsanFieldPadding)
CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" +
llvm::utostr(AsanFieldPadding)));
if (AsanUseAfterScope)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-use-after-scope"));
+ CmdArgs.push_back("-fsanitize-address-use-after-scope");
+
+ if (AsanGlobalsDeadStripping)
+ CmdArgs.push_back("-fsanitize-address-globals-dead-stripping");
// MSan: Workaround for PR16386.
// ASan: This is mainly to help LSan with cases such as
@@ -733,7 +752,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
// We can't make this conditional on -fsanitize=leak, as that flag shouldn't
// affect compilation.
if (Sanitizers.has(Memory) || Sanitizers.has(Address))
- CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
+ CmdArgs.push_back("-fno-assume-sane-operator-new");
// Require -fvisibility= flag on non-Windows when compiling if vptr CFI is
// enabled.
@@ -797,6 +816,8 @@ 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)
+ .Case("inline-8bit-counters", CoverageInline8bitCounters)
.Default(0);
if (F == 0)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp
index 6adc038..9a858df 100644
--- a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp
@@ -8,14 +8,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/ToolChain.h"
-#include "Tools.h"
+#include "ToolChains/CommonArgs.h"
+#include "ToolChains/Arch/ARM.h"
+#include "ToolChains/Clang.h"
#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/VirtualFileSystem.h"
#include "clang/Config/config.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
+#include "clang/Driver/XRayArgs.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
@@ -74,6 +78,10 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
if (!isThreadModelSupported(A->getValue()))
D.Diag(diag::err_drv_invalid_thread_model_for_target)
<< A->getValue() << A->getAsString(Args);
+
+ std::string CandidateLibPath = getArchSpecificLibPath();
+ if (getVFS().exists(CandidateLibPath))
+ getFilePaths().push_back(CandidateLibPath);
}
ToolChain::~ToolChain() {
@@ -93,6 +101,12 @@ const SanitizerArgs& ToolChain::getSanitizerArgs() const {
return *SanitizerArguments.get();
}
+const XRayArgs& ToolChain::getXRayArgs() const {
+ if (!XRayArguments.get())
+ XRayArguments.reset(new XRayArgs(*this, Args));
+ return *XRayArguments.get();
+}
+
namespace {
struct DriverSuffix {
const char *Suffix;
@@ -203,7 +217,7 @@ StringRef ToolChain::getDefaultUniversalArchName() const {
}
}
-bool ToolChain::IsUnwindTablesDefault() const {
+bool ToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
return false;
}
@@ -320,6 +334,14 @@ const char *ToolChain::getCompilerRTArgString(const llvm::opt::ArgList &Args,
return Args.MakeArgString(getCompilerRT(Args, Component, Shared));
}
+std::string ToolChain::getArchSpecificLibPath() const {
+ SmallString<128> Path(getDriver().ResourceDir);
+ StringRef OSLibName = getTriple().isOSFreeBSD() ? "freebsd" : getOS();
+ llvm::sys::path::append(Path, "lib", OSLibName,
+ llvm::Triple::getArchTypeName(getArch()));
+ return Path.str();
+}
+
bool ToolChain::needsProfileRT(const ArgList &Args) {
if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
false) ||
@@ -522,9 +544,9 @@ void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// Each toolchain should provide the appropriate include flags.
}
-void ToolChain::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
-}
+void ToolChain::addClangTargetOptions(
+ const ArgList &DriverArgs, ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const {}
void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {}
@@ -682,7 +704,8 @@ SanitizerMask ToolChain::getSupportedSanitizers() const {
// platform dependent.
using namespace SanitizerKind;
SanitizerMask Res = (Undefined & ~Vptr & ~Function) | (CFI & ~CFIICall) |
- CFICastStrict | UnsignedIntegerOverflow | LocalBounds;
+ CFICastStrict | UnsignedIntegerOverflow | Nullability |
+ LocalBounds;
if (getTriple().getArch() == llvm::Triple::x86 ||
getTriple().getArch() == llvm::Triple::x86_64 ||
getTriple().getArch() == llvm::Triple::arm ||
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp
deleted file mode 100644
index 9bc9ae4..0000000
--- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp
+++ /dev/null
@@ -1,5342 +0,0 @@
-//===--- ToolChains.cpp - ToolChain Implementations -------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ToolChains.h"
-#include "clang/Basic/Cuda.h"
-#include "clang/Basic/ObjCRuntime.h"
-#include "clang/Basic/Version.h"
-#include "clang/Basic/VirtualFileSystem.h"
-#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Distro.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Options.h"
-#include "clang/Driver/SanitizerArgs.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Option/OptTable.h"
-#include "llvm/Option/Option.h"
-#include "llvm/ProfileData/InstrProf.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/TargetParser.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cstdlib> // ::getenv
-#include <system_error>
-
-using namespace clang::driver;
-using namespace clang::driver::toolchains;
-using namespace clang;
-using namespace llvm::opt;
-
-MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : ToolChain(D, Triple, Args) {
- // We expect 'as', 'ld', etc. to be adjacent to our install dir.
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir)
- getProgramPaths().push_back(getDriver().Dir);
-}
-
-/// Darwin - Darwin tool chain for i386 and x86_64.
-Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : MachO(D, Triple, Args), TargetInitialized(false),
- CudaInstallation(D, Triple, Args) {}
-
-types::ID MachO::LookupTypeForExtension(StringRef Ext) const {
- types::ID Ty = types::lookupTypeForExtension(Ext);
-
- // Darwin always preprocesses assembly files (unless -x is used explicitly).
- if (Ty == types::TY_PP_Asm)
- return types::TY_Asm;
-
- return Ty;
-}
-
-bool MachO::HasNativeLLVMSupport() const { return true; }
-
-ToolChain::CXXStdlibType Darwin::GetDefaultCXXStdlibType() const {
- // Default to use libc++ on OS X 10.9+ and iOS 7+.
- if ((isTargetMacOS() && !isMacosxVersionLT(10, 9)) ||
- (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) ||
- isTargetWatchOSBased())
- return ToolChain::CST_Libcxx;
-
- return ToolChain::CST_Libstdcxx;
-}
-
-/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
-ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const {
- if (isTargetWatchOSBased())
- return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion);
- if (isTargetIOSBased())
- return ObjCRuntime(ObjCRuntime::iOS, TargetVersion);
- if (isNonFragile)
- return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion);
- return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion);
-}
-
-/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2.
-bool Darwin::hasBlocksRuntime() const {
- if (isTargetWatchOSBased())
- return true;
- else if (isTargetIOSBased())
- return !isIPhoneOSVersionLT(3, 2);
- else {
- assert(isTargetMacOS() && "unexpected darwin target");
- return !isMacosxVersionLT(10, 6);
- }
-}
-
-void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
-}
-
-// This is just a MachO name translation routine and there's no
-// way to join this into ARMTargetParser without breaking all
-// other assumptions. Maybe MachO should consider standardising
-// their nomenclature.
-static const char *ArmMachOArchName(StringRef Arch) {
- return llvm::StringSwitch<const char *>(Arch)
- .Case("armv6k", "armv6")
- .Case("armv6m", "armv6m")
- .Case("armv5tej", "armv5")
- .Case("xscale", "xscale")
- .Case("armv4t", "armv4t")
- .Case("armv7", "armv7")
- .Cases("armv7a", "armv7-a", "armv7")
- .Cases("armv7r", "armv7-r", "armv7")
- .Cases("armv7em", "armv7e-m", "armv7em")
- .Cases("armv7k", "armv7-k", "armv7k")
- .Cases("armv7m", "armv7-m", "armv7m")
- .Cases("armv7s", "armv7-s", "armv7s")
- .Default(nullptr);
-}
-
-static const char *ArmMachOArchNameCPU(StringRef CPU) {
- unsigned ArchKind = llvm::ARM::parseCPUArch(CPU);
- if (ArchKind == llvm::ARM::AK_INVALID)
- return nullptr;
- StringRef Arch = llvm::ARM::getArchName(ArchKind);
-
- // FIXME: Make sure this MachO triple mangling is really necessary.
- // ARMv5* normalises to ARMv5.
- if (Arch.startswith("armv5"))
- Arch = Arch.substr(0, 5);
- // ARMv6*, except ARMv6M, normalises to ARMv6.
- else if (Arch.startswith("armv6") && !Arch.endswith("6m"))
- Arch = Arch.substr(0, 5);
- // ARMv7A normalises to ARMv7.
- else if (Arch.endswith("v7a"))
- Arch = Arch.substr(0, 5);
- return Arch.data();
-}
-
-static bool isSoftFloatABI(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
- options::OPT_mfloat_abi_EQ);
- if (!A)
- return false;
-
- return A->getOption().matches(options::OPT_msoft_float) ||
- (A->getOption().matches(options::OPT_mfloat_abi_EQ) &&
- A->getValue() == StringRef("soft"));
-}
-
-StringRef MachO::getMachOArchName(const ArgList &Args) const {
- switch (getTriple().getArch()) {
- default:
- return getDefaultUniversalArchName();
-
- case llvm::Triple::aarch64:
- return "arm64";
-
- case llvm::Triple::thumb:
- case llvm::Triple::arm:
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
- if (const char *Arch = ArmMachOArchName(A->getValue()))
- return Arch;
-
- if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- if (const char *Arch = ArmMachOArchNameCPU(A->getValue()))
- return Arch;
-
- return "arm";
- }
-}
-
-Darwin::~Darwin() {}
-
-MachO::~MachO() {}
-
-std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
- types::ID InputType) const {
- llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
-
- // If the target isn't initialized (e.g., an unknown Darwin platform, return
- // the default triple).
- if (!isTargetInitialized())
- return Triple.getTriple();
-
- SmallString<16> Str;
- if (isTargetWatchOSBased())
- Str += "watchos";
- else if (isTargetTvOSBased())
- Str += "tvos";
- else if (isTargetIOSBased())
- Str += "ios";
- else
- Str += "macosx";
- Str += getTargetVersion().getAsString();
- Triple.setOSName(Str);
-
- return Triple.getTriple();
-}
-
-void Generic_ELF::anchor() {}
-
-Tool *MachO::getTool(Action::ActionClass AC) const {
- switch (AC) {
- case Action::LipoJobClass:
- if (!Lipo)
- Lipo.reset(new tools::darwin::Lipo(*this));
- return Lipo.get();
- case Action::DsymutilJobClass:
- if (!Dsymutil)
- Dsymutil.reset(new tools::darwin::Dsymutil(*this));
- return Dsymutil.get();
- case Action::VerifyDebugInfoJobClass:
- if (!VerifyDebug)
- VerifyDebug.reset(new tools::darwin::VerifyDebug(*this));
- return VerifyDebug.get();
- default:
- return ToolChain::getTool(AC);
- }
-}
-
-Tool *MachO::buildLinker() const { return new tools::darwin::Linker(*this); }
-
-Tool *MachO::buildAssembler() const {
- return new tools::darwin::Assembler(*this);
-}
-
-DarwinClang::DarwinClang(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Darwin(D, Triple, Args) {}
-
-void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const {
- // For modern targets, promote certain warnings to errors.
- if (isTargetWatchOSBased() || getTriple().isArch64Bit()) {
- // Always enable -Wdeprecated-objc-isa-usage and promote it
- // to an error.
- CC1Args.push_back("-Wdeprecated-objc-isa-usage");
- CC1Args.push_back("-Werror=deprecated-objc-isa-usage");
-
- // For iOS and watchOS, also error about implicit function declarations,
- // as that can impact calling conventions.
- if (!isTargetMacOS())
- CC1Args.push_back("-Werror=implicit-function-declaration");
- }
-}
-
-/// \brief Determine whether Objective-C automated reference counting is
-/// enabled.
-static bool isObjCAutoRefCount(const ArgList &Args) {
- return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false);
-}
-
-void DarwinClang::AddLinkARCArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Avoid linking compatibility stubs on i386 mac.
- if (isTargetMacOS() && getArch() == llvm::Triple::x86)
- return;
-
- ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true);
-
- if ((runtime.hasNativeARC() || !isObjCAutoRefCount(Args)) &&
- runtime.hasSubscripting())
- return;
-
- CmdArgs.push_back("-force_load");
- SmallString<128> P(getDriver().ClangExecutable);
- llvm::sys::path::remove_filename(P); // 'clang'
- llvm::sys::path::remove_filename(P); // 'bin'
- llvm::sys::path::append(P, "lib", "arc", "libarclite_");
- // Mash in the platform.
- if (isTargetWatchOSSimulator())
- P += "watchsimulator";
- else if (isTargetWatchOS())
- P += "watchos";
- else if (isTargetTvOSSimulator())
- P += "appletvsimulator";
- else if (isTargetTvOS())
- P += "appletvos";
- else if (isTargetIOSSimulator())
- P += "iphonesimulator";
- else if (isTargetIPhoneOS())
- P += "iphoneos";
- else
- P += "macosx";
- P += ".a";
-
- CmdArgs.push_back(Args.MakeArgString(P));
-}
-
-unsigned DarwinClang::GetDefaultDwarfVersion() const {
- // Default to use DWARF 2 on OS X 10.10 / iOS 8 and lower.
- if ((isTargetMacOS() && isMacosxVersionLT(10, 11)) ||
- (isTargetIOSBased() && isIPhoneOSVersionLT(9)))
- return 2;
- return 4;
-}
-
-void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
- StringRef DarwinLibName, bool AlwaysLink,
- bool IsEmbedded, bool AddRPath) const {
- SmallString<128> Dir(getDriver().ResourceDir);
- llvm::sys::path::append(Dir, "lib", IsEmbedded ? "macho_embedded" : "darwin");
-
- SmallString<128> P(Dir);
- llvm::sys::path::append(P, DarwinLibName);
-
- // For now, allow missing resource libraries to support developers who may
- // not have compiler-rt checked out or integrated into their build (unless
- // we explicitly force linking with this library).
- if (AlwaysLink || getVFS().exists(P))
- CmdArgs.push_back(Args.MakeArgString(P));
-
- // Adding the rpaths might negatively interact when other rpaths are involved,
- // so we should make sure we add the rpaths last, after all user-specified
- // rpaths. This is currently true from this place, but we need to be
- // careful if this function is ever called before user's rpaths are emitted.
- if (AddRPath) {
- assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library");
-
- // Add @executable_path to rpath to support having the dylib copied with
- // the executable.
- CmdArgs.push_back("-rpath");
- CmdArgs.push_back("@executable_path");
-
- // Add the path to the resource dir to rpath to support using the dylib
- // from the default location without copying.
- CmdArgs.push_back("-rpath");
- CmdArgs.push_back(Args.MakeArgString(Dir));
- }
-}
-
-StringRef Darwin::getPlatformFamily() const {
- switch (TargetPlatform) {
- case DarwinPlatformKind::MacOS:
- return "MacOSX";
- case DarwinPlatformKind::IPhoneOS:
- case DarwinPlatformKind::IPhoneOSSimulator:
- return "iPhone";
- case DarwinPlatformKind::TvOS:
- case DarwinPlatformKind::TvOSSimulator:
- return "AppleTV";
- case DarwinPlatformKind::WatchOS:
- case DarwinPlatformKind::WatchOSSimulator:
- return "Watch";
- }
- llvm_unreachable("Unsupported platform");
-}
-
-StringRef Darwin::getSDKName(StringRef isysroot) {
- // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk
- llvm::sys::path::const_iterator SDKDir;
- auto BeginSDK = llvm::sys::path::begin(isysroot);
- auto EndSDK = llvm::sys::path::end(isysroot);
- for (auto IT = BeginSDK; IT != EndSDK; ++IT) {
- StringRef SDK = *IT;
- if (SDK.endswith(".sdk"))
- return SDK.slice(0, SDK.size() - 4);
- }
- return "";
-}
-
-StringRef Darwin::getOSLibraryNameSuffix() const {
- switch(TargetPlatform) {
- case DarwinPlatformKind::MacOS:
- return "osx";
- case DarwinPlatformKind::IPhoneOS:
- return "ios";
- case DarwinPlatformKind::IPhoneOSSimulator:
- return "iossim";
- case DarwinPlatformKind::TvOS:
- return "tvos";
- case DarwinPlatformKind::TvOSSimulator:
- return "tvossim";
- case DarwinPlatformKind::WatchOS:
- return "watchos";
- case DarwinPlatformKind::WatchOSSimulator:
- return "watchossim";
- }
- llvm_unreachable("Unsupported platform");
-}
-
-void Darwin::addProfileRTLibs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- if (!needsProfileRT(Args)) return;
-
- AddLinkRuntimeLib(Args, CmdArgs, (Twine("libclang_rt.profile_") +
- getOSLibraryNameSuffix() + ".a").str(),
- /*AlwaysLink*/ true);
-}
-
-void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs,
- StringRef Sanitizer) const {
- AddLinkRuntimeLib(
- Args, CmdArgs,
- (Twine("libclang_rt.") + Sanitizer + "_" +
- getOSLibraryNameSuffix() + "_dynamic.dylib").str(),
- /*AlwaysLink*/ true, /*IsEmbedded*/ false,
- /*AddRPath*/ true);
-}
-
-ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType(
- const ArgList &Args) const {
- if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) {
- StringRef Value = A->getValue();
- if (Value != "compiler-rt")
- getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform)
- << Value << "darwin";
- }
-
- return ToolChain::RLT_CompilerRT;
-}
-
-void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Call once to ensure diagnostic is printed if wrong value was specified
- GetRuntimeLibType(Args);
-
- // Darwin doesn't support real static executables, don't link any runtime
- // libraries with -static.
- if (Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_fapple_kext) ||
- Args.hasArg(options::OPT_mkernel))
- return;
-
- // Reject -static-libgcc for now, we can deal with this when and if someone
- // cares. This is useful in situations where someone wants to statically link
- // something like libstdc++, and needs its runtime support routines.
- if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) {
- getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args);
- return;
- }
-
- const SanitizerArgs &Sanitize = getSanitizerArgs();
- if (Sanitize.needsAsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
- if (Sanitize.needsUbsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan");
- if (Sanitize.needsTsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
- if (Sanitize.needsStatsRt()) {
- StringRef OS = isTargetMacOS() ? "osx" : "iossim";
- AddLinkRuntimeLib(Args, CmdArgs,
- (Twine("libclang_rt.stats_client_") + OS + ".a").str(),
- /*AlwaysLink=*/true);
- AddLinkSanitizerLibArgs(Args, CmdArgs, "stats");
- }
- if (Sanitize.needsEsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs, "esan");
-
- // Otherwise link libSystem, then the dynamic runtime library, and finally any
- // target specific static runtime library.
- CmdArgs.push_back("-lSystem");
-
- // Select the dynamic runtime library and the target specific static library.
- if (isTargetWatchOSBased()) {
- // We currently always need a static runtime library for watchOS.
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.watchos.a");
- } else if (isTargetTvOSBased()) {
- // We currently always need a static runtime library for tvOS.
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.tvos.a");
- } else if (isTargetIOSBased()) {
- // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1,
- // it never went into the SDK.
- // Linking against libgcc_s.1 isn't needed for iOS 5.0+
- if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator() &&
- getTriple().getArch() != llvm::Triple::aarch64)
- CmdArgs.push_back("-lgcc_s.1");
-
- // We currently always need a static runtime library for iOS.
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a");
- } else {
- assert(isTargetMacOS() && "unexpected non MacOS platform");
- // The dynamic runtime library was merged with libSystem for 10.6 and
- // beyond; only 10.4 and 10.5 need an additional runtime library.
- if (isMacosxVersionLT(10, 5))
- CmdArgs.push_back("-lgcc_s.10.4");
- else if (isMacosxVersionLT(10, 6))
- CmdArgs.push_back("-lgcc_s.10.5");
-
- // Originally for OS X, we thought we would only need a static runtime
- // library when targeting 10.4, to provide versions of the static functions
- // which were omitted from 10.4.dylib. This led to the creation of the 10.4
- // builtins library.
- //
- // Unfortunately, that turned out to not be true, because Darwin system
- // headers can still use eprintf on i386, and it is not exported from
- // libSystem. Therefore, we still must provide a runtime library just for
- // the tiny tiny handful of projects that *might* use that symbol.
- //
- // Then over time, we figured out it was useful to add more things to the
- // runtime so we created libclang_rt.osx.a to provide new functions when
- // deploying to old OS builds, and for a long time we had both eprintf and
- // osx builtin libraries. Which just seems excessive. So with PR 28855, we
- // are removing the eprintf library and expecting eprintf to be provided by
- // the OS X builtins library.
- if (isMacosxVersionLT(10, 5))
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.10.4.a");
- else
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.osx.a");
- }
-}
-
-void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
- const OptTable &Opts = getDriver().getOpts();
-
- // Support allowing the SDKROOT environment variable used by xcrun and other
- // Xcode tools to define the default sysroot, by making it the default for
- // isysroot.
- if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- // Warn if the path does not exist.
- if (!getVFS().exists(A->getValue()))
- getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue();
- } else {
- if (char *env = ::getenv("SDKROOT")) {
- // We only use this value as the default if it is an absolute path,
- // exists, and it is not the root path.
- if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) &&
- StringRef(env) != "/") {
- Args.append(Args.MakeSeparateArg(
- nullptr, Opts.getOption(options::OPT_isysroot), env));
- }
- }
- }
-
- Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
- Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
- Arg *TvOSVersion = Args.getLastArg(options::OPT_mtvos_version_min_EQ);
- Arg *WatchOSVersion = Args.getLastArg(options::OPT_mwatchos_version_min_EQ);
-
- if (OSXVersion && (iOSVersion || TvOSVersion || WatchOSVersion)) {
- getDriver().Diag(diag::err_drv_argument_not_allowed_with)
- << OSXVersion->getAsString(Args)
- << (iOSVersion ? iOSVersion :
- TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args);
- iOSVersion = TvOSVersion = WatchOSVersion = nullptr;
- } else if (iOSVersion && (TvOSVersion || WatchOSVersion)) {
- getDriver().Diag(diag::err_drv_argument_not_allowed_with)
- << iOSVersion->getAsString(Args)
- << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args);
- TvOSVersion = WatchOSVersion = nullptr;
- } else if (TvOSVersion && WatchOSVersion) {
- getDriver().Diag(diag::err_drv_argument_not_allowed_with)
- << TvOSVersion->getAsString(Args)
- << WatchOSVersion->getAsString(Args);
- WatchOSVersion = nullptr;
- } else if (!OSXVersion && !iOSVersion && !TvOSVersion && !WatchOSVersion) {
- // If no deployment target was specified on the command line, check for
- // environment defines.
- std::string OSXTarget;
- std::string iOSTarget;
- std::string TvOSTarget;
- std::string WatchOSTarget;
-
- if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET"))
- OSXTarget = env;
- if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET"))
- iOSTarget = env;
- if (char *env = ::getenv("TVOS_DEPLOYMENT_TARGET"))
- TvOSTarget = env;
- if (char *env = ::getenv("WATCHOS_DEPLOYMENT_TARGET"))
- WatchOSTarget = env;
-
- // If there is no command-line argument to specify the Target version and
- // no environment variable defined, see if we can set the default based
- // on -isysroot.
- if (OSXTarget.empty() && iOSTarget.empty() && WatchOSTarget.empty() &&
- TvOSTarget.empty() && Args.hasArg(options::OPT_isysroot)) {
- if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- StringRef isysroot = A->getValue();
- StringRef SDK = getSDKName(isysroot);
- if (SDK.size() > 0) {
- // Slice the version number out.
- // Version number is between the first and the last number.
- size_t StartVer = SDK.find_first_of("0123456789");
- size_t EndVer = SDK.find_last_of("0123456789");
- if (StartVer != StringRef::npos && EndVer > StartVer) {
- StringRef Version = SDK.slice(StartVer, EndVer + 1);
- if (SDK.startswith("iPhoneOS") ||
- SDK.startswith("iPhoneSimulator"))
- iOSTarget = Version;
- else if (SDK.startswith("MacOSX"))
- OSXTarget = Version;
- else if (SDK.startswith("WatchOS") ||
- SDK.startswith("WatchSimulator"))
- WatchOSTarget = Version;
- else if (SDK.startswith("AppleTVOS") ||
- SDK.startswith("AppleTVSimulator"))
- TvOSTarget = Version;
- }
- }
- }
- }
-
- // If no OSX or iOS target has been specified, try to guess platform
- // from arch name and compute the version from the triple.
- if (OSXTarget.empty() && iOSTarget.empty() && TvOSTarget.empty() &&
- WatchOSTarget.empty()) {
- StringRef MachOArchName = getMachOArchName(Args);
- unsigned Major, Minor, Micro;
- if (MachOArchName == "armv7" || MachOArchName == "armv7s" ||
- MachOArchName == "arm64") {
- getTriple().getiOSVersion(Major, Minor, Micro);
- llvm::raw_string_ostream(iOSTarget) << Major << '.' << Minor << '.'
- << Micro;
- } else if (MachOArchName == "armv7k") {
- getTriple().getWatchOSVersion(Major, Minor, Micro);
- llvm::raw_string_ostream(WatchOSTarget) << Major << '.' << Minor << '.'
- << Micro;
- } else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
- MachOArchName != "armv7em") {
- if (!getTriple().getMacOSXVersion(Major, Minor, Micro)) {
- getDriver().Diag(diag::err_drv_invalid_darwin_version)
- << getTriple().getOSName();
- }
- llvm::raw_string_ostream(OSXTarget) << Major << '.' << Minor << '.'
- << Micro;
- }
- }
-
- // Do not allow conflicts with the watchOS target.
- if (!WatchOSTarget.empty() && (!iOSTarget.empty() || !TvOSTarget.empty())) {
- getDriver().Diag(diag::err_drv_conflicting_deployment_targets)
- << "WATCHOS_DEPLOYMENT_TARGET"
- << (!iOSTarget.empty() ? "IPHONEOS_DEPLOYMENT_TARGET" :
- "TVOS_DEPLOYMENT_TARGET");
- }
-
- // Do not allow conflicts with the tvOS target.
- if (!TvOSTarget.empty() && !iOSTarget.empty()) {
- getDriver().Diag(diag::err_drv_conflicting_deployment_targets)
- << "TVOS_DEPLOYMENT_TARGET"
- << "IPHONEOS_DEPLOYMENT_TARGET";
- }
-
- // Allow conflicts among OSX and iOS for historical reasons, but choose the
- // default platform.
- if (!OSXTarget.empty() && (!iOSTarget.empty() ||
- !WatchOSTarget.empty() ||
- !TvOSTarget.empty())) {
- if (getTriple().getArch() == llvm::Triple::arm ||
- getTriple().getArch() == llvm::Triple::aarch64 ||
- getTriple().getArch() == llvm::Triple::thumb)
- OSXTarget = "";
- else
- iOSTarget = WatchOSTarget = TvOSTarget = "";
- }
-
- if (!OSXTarget.empty()) {
- const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
- OSXVersion = Args.MakeJoinedArg(nullptr, O, OSXTarget);
- Args.append(OSXVersion);
- } else if (!iOSTarget.empty()) {
- const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
- iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget);
- Args.append(iOSVersion);
- } else if (!TvOSTarget.empty()) {
- const Option O = Opts.getOption(options::OPT_mtvos_version_min_EQ);
- TvOSVersion = Args.MakeJoinedArg(nullptr, O, TvOSTarget);
- Args.append(TvOSVersion);
- } else if (!WatchOSTarget.empty()) {
- const Option O = Opts.getOption(options::OPT_mwatchos_version_min_EQ);
- WatchOSVersion = Args.MakeJoinedArg(nullptr, O, WatchOSTarget);
- Args.append(WatchOSVersion);
- }
- }
-
- DarwinPlatformKind Platform;
- if (OSXVersion)
- Platform = MacOS;
- else if (iOSVersion)
- Platform = IPhoneOS;
- else if (TvOSVersion)
- Platform = TvOS;
- else if (WatchOSVersion)
- Platform = WatchOS;
- else
- llvm_unreachable("Unable to infer Darwin variant");
-
- // Set the tool chain target information.
- unsigned Major, Minor, Micro;
- bool HadExtra;
- if (Platform == MacOS) {
- assert((!iOSVersion && !TvOSVersion && !WatchOSVersion) &&
- "Unknown target platform!");
- if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro,
- HadExtra) ||
- HadExtra || Major != 10 || Minor >= 100 || Micro >= 100)
- getDriver().Diag(diag::err_drv_invalid_version_number)
- << OSXVersion->getAsString(Args);
- } else if (Platform == IPhoneOS) {
- assert(iOSVersion && "Unknown target platform!");
- if (!Driver::GetReleaseVersion(iOSVersion->getValue(), Major, Minor, Micro,
- HadExtra) ||
- HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100)
- getDriver().Diag(diag::err_drv_invalid_version_number)
- << iOSVersion->getAsString(Args);
- } else if (Platform == TvOS) {
- if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor,
- Micro, HadExtra) || HadExtra ||
- Major >= 100 || Minor >= 100 || Micro >= 100)
- getDriver().Diag(diag::err_drv_invalid_version_number)
- << TvOSVersion->getAsString(Args);
- } else if (Platform == WatchOS) {
- if (!Driver::GetReleaseVersion(WatchOSVersion->getValue(), Major, Minor,
- Micro, HadExtra) || HadExtra ||
- Major >= 10 || Minor >= 100 || Micro >= 100)
- getDriver().Diag(diag::err_drv_invalid_version_number)
- << WatchOSVersion->getAsString(Args);
- } else
- llvm_unreachable("unknown kind of Darwin platform");
-
- // Recognize iOS targets with an x86 architecture as the iOS simulator.
- if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 ||
- getTriple().getArch() == llvm::Triple::x86_64))
- Platform = IPhoneOSSimulator;
- if (TvOSVersion && (getTriple().getArch() == llvm::Triple::x86 ||
- getTriple().getArch() == llvm::Triple::x86_64))
- Platform = TvOSSimulator;
- if (WatchOSVersion && (getTriple().getArch() == llvm::Triple::x86 ||
- getTriple().getArch() == llvm::Triple::x86_64))
- Platform = WatchOSSimulator;
-
- setTarget(Platform, Major, Minor, Micro);
-
- if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- StringRef SDK = getSDKName(A->getValue());
- if (SDK.size() > 0) {
- size_t StartVer = SDK.find_first_of("0123456789");
- StringRef SDKName = SDK.slice(0, StartVer);
- if (!SDKName.startswith(getPlatformFamily()))
- getDriver().Diag(diag::warn_incompatible_sysroot)
- << SDKName << getPlatformFamily();
- }
- }
-}
-
-void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- CXXStdlibType Type = GetCXXStdlibType(Args);
-
- switch (Type) {
- case ToolChain::CST_Libcxx:
- CmdArgs.push_back("-lc++");
- break;
-
- case ToolChain::CST_Libstdcxx:
- // Unfortunately, -lstdc++ doesn't always exist in the standard search path;
- // it was previously found in the gcc lib dir. However, for all the Darwin
- // platforms we care about it was -lstdc++.6, so we search for that
- // explicitly if we can't see an obvious -lstdc++ candidate.
-
- // Check in the sysroot first.
- if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- SmallString<128> P(A->getValue());
- llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib");
-
- if (!getVFS().exists(P)) {
- llvm::sys::path::remove_filename(P);
- llvm::sys::path::append(P, "libstdc++.6.dylib");
- if (getVFS().exists(P)) {
- CmdArgs.push_back(Args.MakeArgString(P));
- return;
- }
- }
- }
-
- // Otherwise, look in the root.
- // FIXME: This should be removed someday when we don't have to care about
- // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist.
- if (!getVFS().exists("/usr/lib/libstdc++.dylib") &&
- getVFS().exists("/usr/lib/libstdc++.6.dylib")) {
- CmdArgs.push_back("/usr/lib/libstdc++.6.dylib");
- return;
- }
-
- // Otherwise, let the linker search.
- CmdArgs.push_back("-lstdc++");
- break;
- }
-}
-
-void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // For Darwin platforms, use the compiler-rt-based support library
- // instead of the gcc-provided one (which is also incidentally
- // only present in the gcc lib dir, which makes it hard to find).
-
- SmallString<128> P(getDriver().ResourceDir);
- llvm::sys::path::append(P, "lib", "darwin");
-
- // Use the newer cc_kext for iOS ARM after 6.0.
- if (isTargetWatchOS()) {
- llvm::sys::path::append(P, "libclang_rt.cc_kext_watchos.a");
- } else if (isTargetTvOS()) {
- llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a");
- } else if (isTargetIPhoneOS()) {
- llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a");
- } else {
- llvm::sys::path::append(P, "libclang_rt.cc_kext.a");
- }
-
- // For now, allow missing resource libraries to support developers who may
- // not have compiler-rt checked out or integrated into their build.
- if (getVFS().exists(P))
- CmdArgs.push_back(Args.MakeArgString(P));
-}
-
-DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args,
- StringRef BoundArch,
- Action::OffloadKind) const {
- DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
- const OptTable &Opts = getDriver().getOpts();
-
- // FIXME: We really want to get out of the tool chain level argument
- // translation business, as it makes the driver functionality much
- // more opaque. For now, we follow gcc closely solely for the
- // purpose of easily achieving feature parity & testability. Once we
- // have something that works, we should reevaluate each translation
- // and try to push it down into tool specific logic.
-
- for (Arg *A : Args) {
- if (A->getOption().matches(options::OPT_Xarch__)) {
- // Skip this argument unless the architecture matches either the toolchain
- // triple arch, or the arch being bound.
- llvm::Triple::ArchType XarchArch =
- tools::darwin::getArchTypeForMachOArchName(A->getValue(0));
- if (!(XarchArch == getArch() ||
- (!BoundArch.empty() &&
- XarchArch ==
- tools::darwin::getArchTypeForMachOArchName(BoundArch))))
- continue;
-
- Arg *OriginalArg = A;
- unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
- unsigned Prev = Index;
- std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index));
-
- // If the argument parsing failed or more than one argument was
- // consumed, the -Xarch_ argument's parameter tried to consume
- // extra arguments. Emit an error and ignore.
- //
- // We also want to disallow any options which would alter the
- // driver behavior; that isn't going to work in our model. We
- // use isDriverOption() as an approximation, although things
- // like -O4 are going to slip through.
- if (!XarchArg || Index > Prev + 1) {
- getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args)
- << A->getAsString(Args);
- continue;
- } else if (XarchArg->getOption().hasFlag(options::DriverOption)) {
- getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver)
- << A->getAsString(Args);
- continue;
- }
-
- XarchArg->setBaseArg(A);
-
- A = XarchArg.release();
- DAL->AddSynthesizedArg(A);
-
- // Linker input arguments require custom handling. The problem is that we
- // have already constructed the phase actions, so we can not treat them as
- // "input arguments".
- if (A->getOption().hasFlag(options::LinkerInput)) {
- // Convert the argument into individual Zlinker_input_args.
- for (const char *Value : A->getValues()) {
- DAL->AddSeparateArg(
- OriginalArg, Opts.getOption(options::OPT_Zlinker_input), Value);
- }
- continue;
- }
- }
-
- // Sob. These is strictly gcc compatible for the time being. Apple
- // gcc translates options twice, which means that self-expanding
- // options add duplicates.
- switch ((options::ID)A->getOption().getID()) {
- default:
- DAL->append(A);
- break;
-
- case options::OPT_mkernel:
- case options::OPT_fapple_kext:
- DAL->append(A);
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_static));
- break;
-
- case options::OPT_dependency_file:
- DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue());
- break;
-
- case options::OPT_gfull:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag));
- DAL->AddFlagArg(
- A, Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols));
- break;
-
- case options::OPT_gused:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag));
- DAL->AddFlagArg(
- A, Opts.getOption(options::OPT_feliminate_unused_debug_symbols));
- break;
-
- case options::OPT_shared:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib));
- break;
-
- case options::OPT_fconstant_cfstrings:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_mconstant_cfstrings));
- break;
-
- case options::OPT_fno_constant_cfstrings:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_constant_cfstrings));
- break;
-
- case options::OPT_Wnonportable_cfstrings:
- DAL->AddFlagArg(A,
- Opts.getOption(options::OPT_mwarn_nonportable_cfstrings));
- break;
-
- case options::OPT_Wno_nonportable_cfstrings:
- DAL->AddFlagArg(
- A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings));
- break;
-
- case options::OPT_fpascal_strings:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings));
- break;
-
- case options::OPT_fno_pascal_strings:
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings));
- break;
- }
- }
-
- if (getTriple().getArch() == llvm::Triple::x86 ||
- getTriple().getArch() == llvm::Triple::x86_64)
- if (!Args.hasArgNoClaim(options::OPT_mtune_EQ))
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ),
- "core2");
-
- // Add the arch options based on the particular spelling of -arch, to match
- // how the driver driver works.
- if (!BoundArch.empty()) {
- StringRef Name = BoundArch;
- const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ);
- const Option MArch = Opts.getOption(options::OPT_march_EQ);
-
- // This code must be kept in sync with LLVM's getArchTypeForDarwinArch,
- // which defines the list of which architectures we accept.
- if (Name == "ppc")
- ;
- else if (Name == "ppc601")
- DAL->AddJoinedArg(nullptr, MCpu, "601");
- else if (Name == "ppc603")
- DAL->AddJoinedArg(nullptr, MCpu, "603");
- else if (Name == "ppc604")
- DAL->AddJoinedArg(nullptr, MCpu, "604");
- else if (Name == "ppc604e")
- DAL->AddJoinedArg(nullptr, MCpu, "604e");
- else if (Name == "ppc750")
- DAL->AddJoinedArg(nullptr, MCpu, "750");
- else if (Name == "ppc7400")
- DAL->AddJoinedArg(nullptr, MCpu, "7400");
- else if (Name == "ppc7450")
- DAL->AddJoinedArg(nullptr, MCpu, "7450");
- else if (Name == "ppc970")
- DAL->AddJoinedArg(nullptr, MCpu, "970");
-
- else if (Name == "ppc64" || Name == "ppc64le")
- DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64));
-
- else if (Name == "i386")
- ;
- else if (Name == "i486")
- DAL->AddJoinedArg(nullptr, MArch, "i486");
- else if (Name == "i586")
- DAL->AddJoinedArg(nullptr, MArch, "i586");
- else if (Name == "i686")
- DAL->AddJoinedArg(nullptr, MArch, "i686");
- else if (Name == "pentium")
- DAL->AddJoinedArg(nullptr, MArch, "pentium");
- else if (Name == "pentium2")
- DAL->AddJoinedArg(nullptr, MArch, "pentium2");
- else if (Name == "pentpro")
- DAL->AddJoinedArg(nullptr, MArch, "pentiumpro");
- else if (Name == "pentIIm3")
- DAL->AddJoinedArg(nullptr, MArch, "pentium2");
-
- else if (Name == "x86_64")
- DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64));
- else if (Name == "x86_64h") {
- DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64));
- DAL->AddJoinedArg(nullptr, MArch, "x86_64h");
- }
-
- else if (Name == "arm")
- DAL->AddJoinedArg(nullptr, MArch, "armv4t");
- else if (Name == "armv4t")
- DAL->AddJoinedArg(nullptr, MArch, "armv4t");
- else if (Name == "armv5")
- DAL->AddJoinedArg(nullptr, MArch, "armv5tej");
- else if (Name == "xscale")
- DAL->AddJoinedArg(nullptr, MArch, "xscale");
- else if (Name == "armv6")
- DAL->AddJoinedArg(nullptr, MArch, "armv6k");
- else if (Name == "armv6m")
- DAL->AddJoinedArg(nullptr, MArch, "armv6m");
- else if (Name == "armv7")
- DAL->AddJoinedArg(nullptr, MArch, "armv7a");
- else if (Name == "armv7em")
- DAL->AddJoinedArg(nullptr, MArch, "armv7em");
- else if (Name == "armv7k")
- DAL->AddJoinedArg(nullptr, MArch, "armv7k");
- else if (Name == "armv7m")
- DAL->AddJoinedArg(nullptr, MArch, "armv7m");
- else if (Name == "armv7s")
- DAL->AddJoinedArg(nullptr, MArch, "armv7s");
- }
-
- return DAL;
-}
-
-void MachO::AddLinkRuntimeLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Embedded targets are simple at the moment, not supporting sanitizers and
- // with different libraries for each member of the product { static, PIC } x
- // { hard-float, soft-float }
- llvm::SmallString<32> CompilerRT = StringRef("libclang_rt.");
- CompilerRT +=
- (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)
- ? "hard"
- : "soft";
- CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a";
-
- AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true);
-}
-
-DerivedArgList *
-Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
- Action::OffloadKind DeviceOffloadKind) const {
- // First get the generic Apple args, before moving onto Darwin-specific ones.
- DerivedArgList *DAL =
- MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
- const OptTable &Opts = getDriver().getOpts();
-
- // If no architecture is bound, none of the translations here are relevant.
- if (BoundArch.empty())
- return DAL;
-
- // Add an explicit version min argument for the deployment target. We do this
- // after argument translation because -Xarch_ arguments may add a version min
- // argument.
- AddDeploymentTarget(*DAL);
-
- // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext.
- // FIXME: It would be far better to avoid inserting those -static arguments,
- // but we can't check the deployment target in the translation code until
- // it is set here.
- if (isTargetWatchOSBased() ||
- (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) {
- for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) {
- Arg *A = *it;
- ++it;
- if (A->getOption().getID() != options::OPT_mkernel &&
- A->getOption().getID() != options::OPT_fapple_kext)
- continue;
- assert(it != ie && "unexpected argument translation");
- A = *it;
- assert(A->getOption().getID() == options::OPT_static &&
- "missing expected -static argument");
- it = DAL->getArgs().erase(it);
- }
- }
-
- if (!Args.getLastArg(options::OPT_stdlib_EQ) &&
- GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ),
- "libc++");
-
- // Validate the C++ standard library choice.
- CXXStdlibType Type = GetCXXStdlibType(*DAL);
- if (Type == ToolChain::CST_Libcxx) {
- // Check whether the target provides libc++.
- StringRef where;
-
- // Complain about targeting iOS < 5.0 in any way.
- if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0))
- where = "iOS 5.0";
-
- if (where != StringRef()) {
- getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where;
- }
- }
-
- auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch);
- if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) {
- if (Args.hasFlag(options::OPT_fomit_frame_pointer,
- options::OPT_fno_omit_frame_pointer, false))
- getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target)
- << "-fomit-frame-pointer" << BoundArch;
- if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
- options::OPT_mno_omit_leaf_frame_pointer, false))
- getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target)
- << "-momit-leaf-frame-pointer" << BoundArch;
- }
-
- return DAL;
-}
-
-bool MachO::IsUnwindTablesDefault() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool MachO::UseDwarfDebugFlags() const {
- if (const char *S = ::getenv("RC_DEBUG_OPTIONS"))
- return S[0] != '\0';
- return false;
-}
-
-bool Darwin::UseSjLjExceptions(const ArgList &Args) const {
- // Darwin uses SjLj exceptions on ARM.
- if (getTriple().getArch() != llvm::Triple::arm &&
- getTriple().getArch() != llvm::Triple::thumb)
- return false;
-
- // Only watchOS uses the new DWARF/Compact unwinding method.
- llvm::Triple Triple(ComputeLLVMTriple(Args));
- return !Triple.isWatchABI();
-}
-
-bool Darwin::SupportsEmbeddedBitcode() const {
- assert(TargetInitialized && "Target not initialized!");
- if (isTargetIPhoneOS() && isIPhoneOSVersionLT(6, 0))
- return false;
- return true;
-}
-
-bool MachO::isPICDefault() const { return true; }
-
-bool MachO::isPIEDefault() const { return false; }
-
-bool MachO::isPICDefaultForced() const {
- return (getArch() == llvm::Triple::x86_64 ||
- getArch() == llvm::Triple::aarch64);
-}
-
-bool MachO::SupportsProfiling() const {
- // Profiling instrumentation is only supported on x86.
- return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64;
-}
-
-void Darwin::addMinVersionArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- VersionTuple TargetVersion = getTargetVersion();
-
- if (isTargetWatchOS())
- CmdArgs.push_back("-watchos_version_min");
- else if (isTargetWatchOSSimulator())
- CmdArgs.push_back("-watchos_simulator_version_min");
- else if (isTargetTvOS())
- CmdArgs.push_back("-tvos_version_min");
- else if (isTargetTvOSSimulator())
- CmdArgs.push_back("-tvos_simulator_version_min");
- else if (isTargetIOSSimulator())
- CmdArgs.push_back("-ios_simulator_version_min");
- else if (isTargetIOSBased())
- CmdArgs.push_back("-iphoneos_version_min");
- else {
- assert(isTargetMacOS() && "unexpected target");
- CmdArgs.push_back("-macosx_version_min");
- }
-
- CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
-}
-
-void Darwin::addStartObjectFileArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Derived from startfile spec.
- if (Args.hasArg(options::OPT_dynamiclib)) {
- // Derived from darwin_dylib1 spec.
- if (isTargetWatchOSBased()) {
- ; // watchOS does not need dylib1.o.
- } else if (isTargetIOSSimulator()) {
- ; // iOS simulator does not need dylib1.o.
- } else if (isTargetIPhoneOS()) {
- if (isIPhoneOSVersionLT(3, 1))
- CmdArgs.push_back("-ldylib1.o");
- } else {
- if (isMacosxVersionLT(10, 5))
- CmdArgs.push_back("-ldylib1.o");
- else if (isMacosxVersionLT(10, 6))
- CmdArgs.push_back("-ldylib1.10.5.o");
- }
- } else {
- if (Args.hasArg(options::OPT_bundle)) {
- if (!Args.hasArg(options::OPT_static)) {
- // Derived from darwin_bundle1 spec.
- if (isTargetWatchOSBased()) {
- ; // watchOS does not need bundle1.o.
- } else if (isTargetIOSSimulator()) {
- ; // iOS simulator does not need bundle1.o.
- } else if (isTargetIPhoneOS()) {
- if (isIPhoneOSVersionLT(3, 1))
- CmdArgs.push_back("-lbundle1.o");
- } else {
- if (isMacosxVersionLT(10, 6))
- CmdArgs.push_back("-lbundle1.o");
- }
- }
- } else {
- if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) {
- if (Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_object) ||
- Args.hasArg(options::OPT_preload)) {
- CmdArgs.push_back("-lgcrt0.o");
- } else {
- CmdArgs.push_back("-lgcrt1.o");
-
- // darwin_crt2 spec is empty.
- }
- // By default on OS X 10.8 and later, we don't link with a crt1.o
- // file and the linker knows to use _main as the entry point. But,
- // when compiling with -pg, we need to link with the gcrt1.o file,
- // so pass the -no_new_main option to tell the linker to use the
- // "start" symbol as the entry point.
- if (isTargetMacOS() && !isMacosxVersionLT(10, 8))
- CmdArgs.push_back("-no_new_main");
- } else {
- if (Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_object) ||
- Args.hasArg(options::OPT_preload)) {
- CmdArgs.push_back("-lcrt0.o");
- } else {
- // Derived from darwin_crt1 spec.
- if (isTargetWatchOSBased()) {
- ; // watchOS does not need crt1.o.
- } else if (isTargetIOSSimulator()) {
- ; // iOS simulator does not need crt1.o.
- } else if (isTargetIPhoneOS()) {
- if (getArch() == llvm::Triple::aarch64)
- ; // iOS does not need any crt1 files for arm64
- else if (isIPhoneOSVersionLT(3, 1))
- CmdArgs.push_back("-lcrt1.o");
- else if (isIPhoneOSVersionLT(6, 0))
- CmdArgs.push_back("-lcrt1.3.1.o");
- } else {
- if (isMacosxVersionLT(10, 5))
- CmdArgs.push_back("-lcrt1.o");
- else if (isMacosxVersionLT(10, 6))
- CmdArgs.push_back("-lcrt1.10.5.o");
- else if (isMacosxVersionLT(10, 8))
- CmdArgs.push_back("-lcrt1.10.6.o");
-
- // darwin_crt2 spec is empty.
- }
- }
- }
- }
- }
-
- if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) &&
- !isTargetWatchOS() &&
- isMacosxVersionLT(10, 5)) {
- const char *Str = Args.MakeArgString(GetFilePath("crt3.o"));
- CmdArgs.push_back(Str);
- }
-}
-
-bool Darwin::SupportsObjCGC() const { return isTargetMacOS(); }
-
-void Darwin::CheckObjCARC() const {
- if (isTargetIOSBased() || isTargetWatchOSBased() ||
- (isTargetMacOS() && !isMacosxVersionLT(10, 6)))
- return;
- getDriver().Diag(diag::err_arc_unsupported_on_toolchain);
-}
-
-SanitizerMask Darwin::getSupportedSanitizers() const {
- const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- Res |= SanitizerKind::Address;
- if (isTargetMacOS()) {
- if (!isMacosxVersionLT(10, 9))
- Res |= SanitizerKind::Vptr;
- Res |= SanitizerKind::SafeStack;
- if (IsX86_64)
- Res |= SanitizerKind::Thread;
- } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) {
- if (IsX86_64)
- Res |= SanitizerKind::Thread;
- }
- return Res;
-}
-
-void Darwin::printVerboseInfo(raw_ostream &OS) const {
- CudaInstallation.print(OS);
-}
-
-/// Generic_GCC - A tool chain using the 'gcc' command to perform
-/// all subcommands; this relies on gcc translating the majority of
-/// command line options.
-
-/// \brief Parse a GCCVersion object out of a string of text.
-///
-/// This is the primary means of forming GCCVersion objects.
-/*static*/
-Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
- const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
- std::pair<StringRef, StringRef> First = VersionText.split('.');
- std::pair<StringRef, StringRef> Second = First.second.split('.');
-
- GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
- if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0)
- return BadVersion;
- GoodVersion.MajorStr = First.first.str();
- if (First.second.empty())
- return GoodVersion;
- if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0)
- return BadVersion;
- GoodVersion.MinorStr = Second.first.str();
-
- // First look for a number prefix and parse that if present. Otherwise just
- // stash the entire patch string in the suffix, and leave the number
- // unspecified. This covers versions strings such as:
- // 5 (handled above)
- // 4.4
- // 4.4.0
- // 4.4.x
- // 4.4.2-rc4
- // 4.4.x-patched
- // And retains any patch number it finds.
- StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
- if (!PatchText.empty()) {
- if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
- // Try to parse the number and any suffix.
- if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
- GoodVersion.Patch < 0)
- return BadVersion;
- GoodVersion.PatchSuffix = PatchText.substr(EndNumber);
- }
- }
-
- return GoodVersion;
-}
-
-/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering.
-bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,
- int RHSPatch,
- StringRef RHSPatchSuffix) const {
- if (Major != RHSMajor)
- return Major < RHSMajor;
- if (Minor != RHSMinor)
- return Minor < RHSMinor;
- if (Patch != RHSPatch) {
- // Note that versions without a specified patch sort higher than those with
- // a patch.
- if (RHSPatch == -1)
- return true;
- if (Patch == -1)
- return false;
-
- // Otherwise just sort on the patch itself.
- return Patch < RHSPatch;
- }
- if (PatchSuffix != RHSPatchSuffix) {
- // Sort empty suffixes higher.
- if (RHSPatchSuffix.empty())
- return true;
- if (PatchSuffix.empty())
- return false;
-
- // Provide a lexicographic sort to make this a total ordering.
- return PatchSuffix < RHSPatchSuffix;
- }
-
- // The versions are equal.
- return false;
-}
-
-static llvm::StringRef getGCCToolchainDir(const ArgList &Args) {
- const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain);
- if (A)
- return A->getValue();
- return GCC_INSTALL_PREFIX;
-}
-
-/// \brief Initialize a GCCInstallationDetector from the driver.
-///
-/// This performs all of the autodetection and sets up the various paths.
-/// Once constructed, a GCCInstallationDetector is essentially immutable.
-///
-/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and
-/// should instead pull the target out of the driver. This is currently
-/// necessary because the driver doesn't store the final version of the target
-/// triple.
-void Generic_GCC::GCCInstallationDetector::init(
- const llvm::Triple &TargetTriple, const ArgList &Args,
- ArrayRef<std::string> ExtraTripleAliases) {
- llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit()
- ? TargetTriple.get64BitArchVariant()
- : TargetTriple.get32BitArchVariant();
- // The library directories which may contain GCC installations.
- SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs;
- // The compatible GCC triples for this particular architecture.
- SmallVector<StringRef, 16> CandidateTripleAliases;
- SmallVector<StringRef, 16> CandidateBiarchTripleAliases;
- CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs,
- CandidateTripleAliases, CandidateBiarchLibDirs,
- CandidateBiarchTripleAliases);
-
- // Compute the set of prefixes for our search.
- SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(),
- D.PrefixDirs.end());
-
- StringRef GCCToolchainDir = getGCCToolchainDir(Args);
- if (GCCToolchainDir != "") {
- if (GCCToolchainDir.back() == '/')
- GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the /
-
- Prefixes.push_back(GCCToolchainDir);
- } else {
- // If we have a SysRoot, try that first.
- if (!D.SysRoot.empty()) {
- Prefixes.push_back(D.SysRoot);
- Prefixes.push_back(D.SysRoot + "/usr");
- }
-
- // Then look for gcc installed alongside clang.
- Prefixes.push_back(D.InstalledDir + "/..");
-
- // Then look for distribution supplied gcc installations.
- if (D.SysRoot.empty()) {
- // Look for RHEL devtoolsets.
- Prefixes.push_back("/opt/rh/devtoolset-4/root/usr");
- Prefixes.push_back("/opt/rh/devtoolset-3/root/usr");
- Prefixes.push_back("/opt/rh/devtoolset-2/root/usr");
- Prefixes.push_back("/opt/rh/devtoolset-1.1/root/usr");
- Prefixes.push_back("/opt/rh/devtoolset-1.0/root/usr");
- // And finally in /usr.
- Prefixes.push_back("/usr");
- }
- }
-
- // Try to respect gcc-config on Gentoo. However, do that only
- // if --gcc-toolchain is not provided or equal to the Gentoo install
- // in /usr. This avoids accidentally enforcing the system GCC version
- // when using a custom toolchain.
- if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") {
- for (StringRef CandidateTriple : ExtraTripleAliases) {
- if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple))
- return;
- }
- for (StringRef CandidateTriple : CandidateTripleAliases) {
- if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple))
- return;
- }
- for (StringRef CandidateTriple : CandidateBiarchTripleAliases) {
- if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true))
- return;
- }
- }
-
- // Loop over the various components which exist and select the best GCC
- // installation available. GCC installs are ranked by version number.
- Version = GCCVersion::Parse("0.0.0");
- for (const std::string &Prefix : Prefixes) {
- if (!D.getVFS().exists(Prefix))
- continue;
- for (StringRef Suffix : CandidateLibDirs) {
- const std::string LibDir = Prefix + Suffix.str();
- if (!D.getVFS().exists(LibDir))
- continue;
- for (StringRef Candidate : ExtraTripleAliases) // Try these first.
- ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate);
- for (StringRef Candidate : CandidateTripleAliases)
- ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate);
- }
- for (StringRef Suffix : CandidateBiarchLibDirs) {
- const std::string LibDir = Prefix + Suffix.str();
- if (!D.getVFS().exists(LibDir))
- continue;
- for (StringRef Candidate : CandidateBiarchTripleAliases)
- ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate,
- /*NeedsBiarchSuffix=*/ true);
- }
- }
-}
-
-void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
- for (const auto &InstallPath : CandidateGCCInstallPaths)
- OS << "Found candidate GCC installation: " << InstallPath << "\n";
-
- if (!GCCInstallPath.empty())
- OS << "Selected GCC installation: " << GCCInstallPath << "\n";
-
- for (const auto &Multilib : Multilibs)
- OS << "Candidate multilib: " << Multilib << "\n";
-
- if (Multilibs.size() != 0 || !SelectedMultilib.isDefault())
- OS << "Selected multilib: " << SelectedMultilib << "\n";
-}
-
-bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
- if (BiarchSibling.hasValue()) {
- M = BiarchSibling.getValue();
- return true;
- }
- return false;
-}
-
-/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
- const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple,
- SmallVectorImpl<StringRef> &LibDirs,
- SmallVectorImpl<StringRef> &TripleAliases,
- SmallVectorImpl<StringRef> &BiarchLibDirs,
- SmallVectorImpl<StringRef> &BiarchTripleAliases) {
- // Declare a bunch of static data sets that we'll select between below. These
- // are specifically designed to always refer to string literals to avoid any
- // lifetime or initialization issues.
- static const char *const AArch64LibDirs[] = {"/lib64", "/lib"};
- static const char *const AArch64Triples[] = {
- "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android",
- "aarch64-redhat-linux", "aarch64-suse-linux"};
- static const char *const AArch64beLibDirs[] = {"/lib"};
- static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu",
- "aarch64_be-linux-gnu"};
-
- static const char *const ARMLibDirs[] = {"/lib"};
- static const char *const ARMTriples[] = {"arm-linux-gnueabi",
- "arm-linux-androideabi"};
- static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf",
- "armv7hl-redhat-linux-gnueabi"};
- static const char *const ARMebLibDirs[] = {"/lib"};
- static const char *const ARMebTriples[] = {"armeb-linux-gnueabi",
- "armeb-linux-androideabi"};
- static const char *const ARMebHFTriples[] = {
- "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"};
-
- static const char *const X86_64LibDirs[] = {"/lib64", "/lib"};
- static const char *const X86_64Triples[] = {
- "x86_64-linux-gnu", "x86_64-unknown-linux-gnu",
- "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E",
- "x86_64-redhat-linux", "x86_64-suse-linux",
- "x86_64-manbo-linux-gnu", "x86_64-linux-gnu",
- "x86_64-slackware-linux", "x86_64-linux-android",
- "x86_64-unknown-linux"};
- static const char *const X32LibDirs[] = {"/libx32"};
- static const char *const X86LibDirs[] = {"/lib32", "/lib"};
- static const char *const X86Triples[] = {
- "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu",
- "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux",
- "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux",
- "i486-slackware-linux", "i686-montavista-linux", "i686-linux-android",
- "i586-linux-gnu"};
-
- static const char *const MIPSLibDirs[] = {"/lib"};
- static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux",
- "mips-mti-linux-gnu",
- "mips-img-linux-gnu"};
- static const char *const MIPSELLibDirs[] = {"/lib"};
- static const char *const MIPSELTriples[] = {"mipsel-linux-gnu",
- "mips-img-linux-gnu"};
-
- static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"};
- static const char *const MIPS64Triples[] = {
- "mips64-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu",
- "mips64-linux-gnuabi64"};
- static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"};
- static const char *const MIPS64ELTriples[] = {
- "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu",
- "mips64el-linux-gnuabi64"};
-
- static const char *const MIPSELAndroidLibDirs[] = {"/lib", "/libr2",
- "/libr6"};
- static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"};
- static const char *const MIPS64ELAndroidLibDirs[] = {"/lib64", "/lib",
- "/libr2", "/libr6"};
- static const char *const MIPS64ELAndroidTriples[] = {
- "mips64el-linux-android"};
-
- static const char *const PPCLibDirs[] = {"/lib32", "/lib"};
- static const char *const PPCTriples[] = {
- "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe",
- "powerpc-suse-linux", "powerpc-montavista-linuxspe"};
- static const char *const PPC64LibDirs[] = {"/lib64", "/lib"};
- static const char *const PPC64Triples[] = {
- "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu",
- "powerpc64-suse-linux", "ppc64-redhat-linux"};
- static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"};
- static const char *const PPC64LETriples[] = {
- "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu",
- "powerpc64le-suse-linux", "ppc64le-redhat-linux"};
-
- static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"};
- static const char *const SPARCv8Triples[] = {"sparc-linux-gnu",
- "sparcv8-linux-gnu"};
- static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"};
- static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu",
- "sparcv9-linux-gnu"};
-
- static const char *const SystemZLibDirs[] = {"/lib64", "/lib"};
- static const char *const SystemZTriples[] = {
- "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu",
- "s390x-suse-linux", "s390x-redhat-linux"};
-
- // Solaris.
- static const char *const SolarisSPARCLibDirs[] = {"/gcc"};
- static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11",
- "i386-pc-solaris2.11"};
-
- using std::begin;
- using std::end;
-
- if (TargetTriple.getOS() == llvm::Triple::Solaris) {
- LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs));
- TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples));
- return;
- }
-
- switch (TargetTriple.getArch()) {
- case llvm::Triple::aarch64:
- LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
- TripleAliases.append(begin(AArch64Triples), end(AArch64Triples));
- BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
- BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples));
- break;
- case llvm::Triple::aarch64_be:
- LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs));
- TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples));
- BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs));
- BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples));
- break;
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs));
- if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
- TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples));
- } else {
- TripleAliases.append(begin(ARMTriples), end(ARMTriples));
- }
- break;
- case llvm::Triple::armeb:
- case llvm::Triple::thumbeb:
- LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs));
- if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
- TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples));
- } else {
- TripleAliases.append(begin(ARMebTriples), end(ARMebTriples));
- }
- break;
- case llvm::Triple::x86_64:
- LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
- TripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
- // x32 is always available when x86_64 is available, so adding it as
- // secondary arch with x86_64 triples
- if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) {
- BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs));
- BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
- } else {
- BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs));
- BiarchTripleAliases.append(begin(X86Triples), end(X86Triples));
- }
- break;
- case llvm::Triple::x86:
- LibDirs.append(begin(X86LibDirs), end(X86LibDirs));
- // MCU toolchain is 32 bit only and its triple alias is TargetTriple
- // itself, which will be appended below.
- if (!TargetTriple.isOSIAMCU()) {
- TripleAliases.append(begin(X86Triples), end(X86Triples));
- BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
- BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
- }
- break;
- case llvm::Triple::mips:
- LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs));
- TripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
- BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs));
- BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples));
- break;
- case llvm::Triple::mipsel:
- if (TargetTriple.isAndroid()) {
- LibDirs.append(begin(MIPSELAndroidLibDirs), end(MIPSELAndroidLibDirs));
- TripleAliases.append(begin(MIPSELAndroidTriples),
- end(MIPSELAndroidTriples));
- BiarchLibDirs.append(begin(MIPS64ELAndroidLibDirs),
- end(MIPS64ELAndroidLibDirs));
- BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples),
- end(MIPS64ELAndroidTriples));
-
- } else {
- LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
- TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples));
- TripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
- BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
- BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples));
- }
- break;
- case llvm::Triple::mips64:
- LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs));
- TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples));
- BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs));
- BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
- break;
- case llvm::Triple::mips64el:
- if (TargetTriple.isAndroid()) {
- LibDirs.append(begin(MIPS64ELAndroidLibDirs),
- end(MIPS64ELAndroidLibDirs));
- TripleAliases.append(begin(MIPS64ELAndroidTriples),
- end(MIPS64ELAndroidTriples));
- BiarchLibDirs.append(begin(MIPSELAndroidLibDirs),
- end(MIPSELAndroidLibDirs));
- BiarchTripleAliases.append(begin(MIPSELAndroidTriples),
- end(MIPSELAndroidTriples));
-
- } else {
- LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
- TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples));
- BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
- BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples));
- BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
- }
- break;
- case llvm::Triple::ppc:
- LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs));
- TripleAliases.append(begin(PPCTriples), end(PPCTriples));
- BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs));
- BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples));
- break;
- case llvm::Triple::ppc64:
- LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs));
- TripleAliases.append(begin(PPC64Triples), end(PPC64Triples));
- BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs));
- BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples));
- break;
- case llvm::Triple::ppc64le:
- LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs));
- TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples));
- break;
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs));
- TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples));
- BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs));
- BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples));
- break;
- case llvm::Triple::sparcv9:
- LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs));
- TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples));
- BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs));
- BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples));
- break;
- case llvm::Triple::systemz:
- LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs));
- TripleAliases.append(begin(SystemZTriples), end(SystemZTriples));
- break;
- default:
- // By default, just rely on the standard lib directories and the original
- // triple.
- break;
- }
-
- // Always append the drivers target triple to the end, in case it doesn't
- // match any of our aliases.
- TripleAliases.push_back(TargetTriple.str());
-
- // Also include the multiarch variant if it's different.
- if (TargetTriple.str() != BiarchTriple.str())
- BiarchTripleAliases.push_back(BiarchTriple.str());
-}
-
-// Parses the contents of version.txt in an CUDA installation. It should
-// contain one line of the from e.g. "CUDA Version 7.5.2".
-static CudaVersion ParseCudaVersionFile(llvm::StringRef V) {
- if (!V.startswith("CUDA Version "))
- return CudaVersion::UNKNOWN;
- V = V.substr(strlen("CUDA Version "));
- int Major = -1, Minor = -1;
- auto First = V.split('.');
- auto Second = First.second.split('.');
- if (First.first.getAsInteger(10, Major) ||
- Second.first.getAsInteger(10, Minor))
- return CudaVersion::UNKNOWN;
-
- if (Major == 7 && Minor == 0) {
- // This doesn't appear to ever happen -- version.txt doesn't exist in the
- // CUDA 7 installs I've seen. But no harm in checking.
- return CudaVersion::CUDA_70;
- }
- if (Major == 7 && Minor == 5)
- return CudaVersion::CUDA_75;
- if (Major == 8 && Minor == 0)
- return CudaVersion::CUDA_80;
- return CudaVersion::UNKNOWN;
-}
-
-CudaInstallationDetector::CudaInstallationDetector(
- const Driver &D, const llvm::Triple &HostTriple,
- const llvm::opt::ArgList &Args)
- : D(D) {
- SmallVector<std::string, 4> CudaPathCandidates;
-
- // In decreasing order so we prefer newer versions to older versions.
- std::initializer_list<const char *> Versions = {"8.0", "7.5", "7.0"};
-
- if (Args.hasArg(options::OPT_cuda_path_EQ)) {
- CudaPathCandidates.push_back(
- Args.getLastArgValue(options::OPT_cuda_path_EQ));
- } else if (HostTriple.isOSWindows()) {
- for (const char *Ver : Versions)
- CudaPathCandidates.push_back(
- D.SysRoot + "/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v" +
- Ver);
- } else {
- CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda");
- for (const char *Ver : Versions)
- CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-" + Ver);
- }
-
- for (const auto &CudaPath : CudaPathCandidates) {
- if (CudaPath.empty() || !D.getVFS().exists(CudaPath))
- continue;
-
- InstallPath = CudaPath;
- BinPath = CudaPath + "/bin";
- IncludePath = InstallPath + "/include";
- LibDevicePath = InstallPath + "/nvvm/libdevice";
-
- auto &FS = D.getVFS();
- if (!(FS.exists(IncludePath) && FS.exists(BinPath) &&
- FS.exists(LibDevicePath)))
- continue;
-
- // On Linux, we have both lib and lib64 directories, and we need to choose
- // based on our triple. On MacOS, we have only a lib directory.
- //
- // It's sufficient for our purposes to be flexible: If both lib and lib64
- // exist, we choose whichever one matches our triple. Otherwise, if only
- // lib exists, we use it.
- if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64"))
- LibPath = InstallPath + "/lib64";
- else if (FS.exists(InstallPath + "/lib"))
- LibPath = InstallPath + "/lib";
- else
- continue;
-
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
- FS.getBufferForFile(InstallPath + "/version.txt");
- if (!VersionFile) {
- // CUDA 7.0 doesn't have a version.txt, so guess that's our version if
- // version.txt isn't present.
- Version = CudaVersion::CUDA_70;
- } else {
- Version = ParseCudaVersionFile((*VersionFile)->getBuffer());
- }
-
- std::error_code EC;
- for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE;
- !EC && LI != LE; LI = LI.increment(EC)) {
- StringRef FilePath = LI->path();
- StringRef FileName = llvm::sys::path::filename(FilePath);
- // Process all bitcode filenames that look like libdevice.compute_XX.YY.bc
- const StringRef LibDeviceName = "libdevice.";
- if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc")))
- continue;
- StringRef GpuArch = FileName.slice(
- LibDeviceName.size(), FileName.find('.', LibDeviceName.size()));
- LibDeviceMap[GpuArch] = FilePath.str();
- // Insert map entries for specifc devices with this compute
- // capability. NVCC's choice of the libdevice library version is
- // rather peculiar and depends on the CUDA version.
- if (GpuArch == "compute_20") {
- LibDeviceMap["sm_20"] = FilePath;
- LibDeviceMap["sm_21"] = FilePath;
- LibDeviceMap["sm_32"] = FilePath;
- } else if (GpuArch == "compute_30") {
- LibDeviceMap["sm_30"] = FilePath;
- if (Version < CudaVersion::CUDA_80) {
- LibDeviceMap["sm_50"] = FilePath;
- LibDeviceMap["sm_52"] = FilePath;
- LibDeviceMap["sm_53"] = FilePath;
- }
- LibDeviceMap["sm_60"] = FilePath;
- LibDeviceMap["sm_61"] = FilePath;
- LibDeviceMap["sm_62"] = FilePath;
- } else if (GpuArch == "compute_35") {
- LibDeviceMap["sm_35"] = FilePath;
- LibDeviceMap["sm_37"] = FilePath;
- } else if (GpuArch == "compute_50") {
- if (Version >= CudaVersion::CUDA_80) {
- LibDeviceMap["sm_50"] = FilePath;
- LibDeviceMap["sm_52"] = FilePath;
- LibDeviceMap["sm_53"] = FilePath;
- }
- }
- }
-
- IsValid = true;
- break;
- }
-}
-
-void CudaInstallationDetector::AddCudaIncludeArgs(
- const ArgList &DriverArgs, ArgStringList &CC1Args) const {
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- // Add cuda_wrappers/* to our system include path. This lets us wrap
- // standard library headers.
- SmallString<128> P(D.ResourceDir);
- llvm::sys::path::append(P, "include");
- llvm::sys::path::append(P, "cuda_wrappers");
- CC1Args.push_back("-internal-isystem");
- CC1Args.push_back(DriverArgs.MakeArgString(P));
- }
-
- if (DriverArgs.hasArg(options::OPT_nocudainc))
- return;
-
- if (!isValid()) {
- D.Diag(diag::err_drv_no_cuda_installation);
- return;
- }
-
- CC1Args.push_back("-internal-isystem");
- CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath()));
- CC1Args.push_back("-include");
- CC1Args.push_back("__clang_cuda_runtime_wrapper.h");
-}
-
-void CudaInstallationDetector::CheckCudaVersionSupportsArch(
- CudaArch Arch) const {
- if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN ||
- ArchsWithVersionTooLowErrors.count(Arch) > 0)
- return;
-
- auto RequiredVersion = MinVersionForCudaArch(Arch);
- if (Version < RequiredVersion) {
- ArchsWithVersionTooLowErrors.insert(Arch);
- D.Diag(diag::err_drv_cuda_version_too_low)
- << InstallPath << CudaArchToString(Arch) << CudaVersionToString(Version)
- << CudaVersionToString(RequiredVersion);
- }
-}
-
-void CudaInstallationDetector::print(raw_ostream &OS) const {
- if (isValid())
- OS << "Found CUDA installation: " << InstallPath << ", version "
- << CudaVersionToString(Version) << "\n";
-}
-
-namespace {
-// Filter to remove Multilibs that don't exist as a suffix to Path
-class FilterNonExistent {
- StringRef Base, File;
- vfs::FileSystem &VFS;
-
-public:
- FilterNonExistent(StringRef Base, StringRef File, vfs::FileSystem &VFS)
- : Base(Base), File(File), VFS(VFS) {}
- bool operator()(const Multilib &M) {
- return !VFS.exists(Base + M.gccSuffix() + File);
- }
-};
-} // end anonymous namespace
-
-static void addMultilibFlag(bool Enabled, const char *const Flag,
- std::vector<std::string> &Flags) {
- if (Enabled)
- Flags.push_back(std::string("+") + Flag);
- else
- Flags.push_back(std::string("-") + Flag);
-}
-
-static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) {
- return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb;
-}
-
-static bool isMipsArch(llvm::Triple::ArchType Arch) {
- return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel ||
- Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el;
-}
-
-static bool isMips32(llvm::Triple::ArchType Arch) {
- return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel;
-}
-
-static bool isMips64(llvm::Triple::ArchType Arch) {
- return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el;
-}
-
-static bool isMipsEL(llvm::Triple::ArchType Arch) {
- return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el;
-}
-
-static bool isMips16(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16);
- return A && A->getOption().matches(options::OPT_mips16);
-}
-
-static bool isMicroMips(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips);
- return A && A->getOption().matches(options::OPT_mmicromips);
-}
-
-namespace {
-struct DetectedMultilibs {
- /// The set of multilibs that the detected installation supports.
- MultilibSet Multilibs;
-
- /// The primary multilib appropriate for the given flags.
- Multilib SelectedMultilib;
-
- /// On Biarch systems, this corresponds to the default multilib when
- /// targeting the non-default multilib. Otherwise, it is empty.
- llvm::Optional<Multilib> BiarchSibling;
-};
-} // end anonymous namespace
-
-static Multilib makeMultilib(StringRef commonSuffix) {
- return Multilib(commonSuffix, commonSuffix, commonSuffix);
-}
-
-static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
- FilterNonExistent &NonExistent,
- DetectedMultilibs &Result) {
- // Check for Code Sourcery toolchain multilibs
- MultilibSet CSMipsMultilibs;
- {
- auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16");
-
- auto MArchMicroMips =
- makeMultilib("/micromips").flag("+m32").flag("+mmicromips");
-
- auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips");
-
- auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
-
- auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float");
-
- auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
-
- auto DefaultFloat =
- makeMultilib("").flag("-msoft-float").flag("-mnan=2008");
-
- auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
-
- auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
-
- // Note that this one's osSuffix is ""
- auto MAbi64 = makeMultilib("")
- .gccSuffix("/64")
- .includeSuffix("/64")
- .flag("+mabi=n64")
- .flag("-mabi=n32")
- .flag("-m32");
-
- CSMipsMultilibs =
- MultilibSet()
- .Either(MArchMips16, MArchMicroMips, MArchDefault)
- .Maybe(UCLibc)
- .Either(SoftFloat, Nan2008, DefaultFloat)
- .FilterOut("/micromips/nan2008")
- .FilterOut("/mips16/nan2008")
- .Either(BigEndian, LittleEndian)
- .Maybe(MAbi64)
- .FilterOut("/mips16.*/64")
- .FilterOut("/micromips.*/64")
- .FilterOut(NonExistent)
- .setIncludeDirsCallback([](const Multilib &M) {
- std::vector<std::string> Dirs({"/include"});
- if (StringRef(M.includeSuffix()).startswith("/uclibc"))
- Dirs.push_back(
- "/../../../../mips-linux-gnu/libc/uclibc/usr/include");
- else
- Dirs.push_back("/../../../../mips-linux-gnu/libc/usr/include");
- return Dirs;
- });
- }
-
- MultilibSet DebianMipsMultilibs;
- {
- Multilib MAbiN32 =
- Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32");
-
- Multilib M64 = Multilib()
- .gccSuffix("/64")
- .includeSuffix("/64")
- .flag("+m64")
- .flag("-m32")
- .flag("-mabi=n32");
-
- Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32");
-
- DebianMipsMultilibs =
- MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent);
- }
-
- // Sort candidates. Toolchain that best meets the directories tree goes first.
- // Then select the first toolchains matches command line flags.
- MultilibSet *Candidates[] = {&CSMipsMultilibs, &DebianMipsMultilibs};
- if (CSMipsMultilibs.size() < DebianMipsMultilibs.size())
- std::iter_swap(Candidates, Candidates + 1);
- for (const MultilibSet *Candidate : Candidates) {
- if (Candidate->select(Flags, Result.SelectedMultilib)) {
- if (Candidate == &DebianMipsMultilibs)
- Result.BiarchSibling = Multilib();
- Result.Multilibs = *Candidate;
- return true;
- }
- }
- return false;
-}
-
-static bool findMipsAndroidMultilibs(vfs::FileSystem &VFS, StringRef Path,
- const Multilib::flags_list &Flags,
- FilterNonExistent &NonExistent,
- DetectedMultilibs &Result) {
-
- MultilibSet AndroidMipsMultilibs =
- MultilibSet()
- .Maybe(Multilib("/mips-r2").flag("+march=mips32r2"))
- .Maybe(Multilib("/mips-r6").flag("+march=mips32r6"))
- .FilterOut(NonExistent);
-
- MultilibSet AndroidMipselMultilibs =
- MultilibSet()
- .Either(Multilib().flag("+march=mips32"),
- Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
- Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
- .FilterOut(NonExistent);
-
- MultilibSet AndroidMips64elMultilibs =
- MultilibSet()
- .Either(
- Multilib().flag("+march=mips64r6"),
- Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"),
- Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
- Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
- .FilterOut(NonExistent);
-
- MultilibSet *MS = &AndroidMipsMultilibs;
- if (VFS.exists(Path + "/mips-r6"))
- MS = &AndroidMipselMultilibs;
- else if (VFS.exists(Path + "/32"))
- MS = &AndroidMips64elMultilibs;
- if (MS->select(Flags, Result.SelectedMultilib)) {
- Result.Multilibs = *MS;
- return true;
- }
- return false;
-}
-
-static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags,
- FilterNonExistent &NonExistent,
- DetectedMultilibs &Result) {
- // Musl toolchain multilibs
- MultilibSet MuslMipsMultilibs;
- {
- auto MArchMipsR2 = makeMultilib("")
- .osSuffix("/mips-r2-hard-musl")
- .flag("+EB")
- .flag("-EL")
- .flag("+march=mips32r2");
-
- auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl")
- .flag("-EB")
- .flag("+EL")
- .flag("+march=mips32r2");
-
- MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2);
-
- // Specify the callback that computes the include directories.
- MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) {
- return std::vector<std::string>(
- {"/../sysroot" + M.osSuffix() + "/usr/include"});
- });
- }
- if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) {
- Result.Multilibs = MuslMipsMultilibs;
- return true;
- }
- return false;
-}
-
-static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
- FilterNonExistent &NonExistent,
- DetectedMultilibs &Result) {
- // CodeScape MTI toolchain v1.2 and early.
- MultilibSet MtiMipsMultilibsV1;
- {
- auto MArchMips32 = makeMultilib("/mips32")
- .flag("+m32")
- .flag("-m64")
- .flag("-mmicromips")
- .flag("+march=mips32");
-
- auto MArchMicroMips = makeMultilib("/micromips")
- .flag("+m32")
- .flag("-m64")
- .flag("+mmicromips");
-
- auto MArchMips64r2 = makeMultilib("/mips64r2")
- .flag("-m32")
- .flag("+m64")
- .flag("+march=mips64r2");
-
- auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag(
- "-march=mips64r2");
-
- auto MArchDefault = makeMultilib("")
- .flag("+m32")
- .flag("-m64")
- .flag("-mmicromips")
- .flag("+march=mips32r2");
-
- auto Mips16 = makeMultilib("/mips16").flag("+mips16");
-
- auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
-
- auto MAbi64 =
- makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
-
- auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
-
- auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
-
- auto SoftFloat = makeMultilib("/sof").flag("+msoft-float");
-
- auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
-
- MtiMipsMultilibsV1 =
- MultilibSet()
- .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64,
- MArchDefault)
- .Maybe(UCLibc)
- .Maybe(Mips16)
- .FilterOut("/mips64/mips16")
- .FilterOut("/mips64r2/mips16")
- .FilterOut("/micromips/mips16")
- .Maybe(MAbi64)
- .FilterOut("/micromips/64")
- .FilterOut("/mips32/64")
- .FilterOut("^/64")
- .FilterOut("/mips16/64")
- .Either(BigEndian, LittleEndian)
- .Maybe(SoftFloat)
- .Maybe(Nan2008)
- .FilterOut(".*sof/nan2008")
- .FilterOut(NonExistent)
- .setIncludeDirsCallback([](const Multilib &M) {
- std::vector<std::string> Dirs({"/include"});
- if (StringRef(M.includeSuffix()).startswith("/uclibc"))
- Dirs.push_back("/../../../../sysroot/uclibc/usr/include");
- else
- Dirs.push_back("/../../../../sysroot/usr/include");
- return Dirs;
- });
- }
-
- // CodeScape IMG toolchain starting from v1.3.
- MultilibSet MtiMipsMultilibsV2;
- {
- auto BeHard = makeMultilib("/mips-r2-hard")
- .flag("+EB")
- .flag("-msoft-float")
- .flag("-mnan=2008")
- .flag("-muclibc");
- auto BeSoft = makeMultilib("/mips-r2-soft")
- .flag("+EB")
- .flag("+msoft-float")
- .flag("-mnan=2008");
- auto ElHard = makeMultilib("/mipsel-r2-hard")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("-mnan=2008")
- .flag("-muclibc");
- auto ElSoft = makeMultilib("/mipsel-r2-soft")
- .flag("+EL")
- .flag("+msoft-float")
- .flag("-mnan=2008")
- .flag("-mmicromips");
- auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008")
- .flag("+EB")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("-muclibc");
- auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("-muclibc")
- .flag("-mmicromips");
- auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc")
- .flag("+EB")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("+muclibc");
- auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("+muclibc");
- auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc")
- .flag("+EB")
- .flag("-msoft-float")
- .flag("-mnan=2008")
- .flag("+muclibc");
- auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("-mnan=2008")
- .flag("+muclibc");
- auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("+mnan=2008")
- .flag("+mmicromips");
- auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft")
- .flag("+EL")
- .flag("+msoft-float")
- .flag("-mnan=2008")
- .flag("+mmicromips");
-
- auto O32 =
- makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
- auto N32 =
- makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
- auto N64 =
- makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
-
- MtiMipsMultilibsV2 =
- MultilibSet()
- .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan,
- BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc,
- ElHardUclibc, ElMicroHardNan, ElMicroSoft})
- .Either(O32, N32, N64)
- .FilterOut(NonExistent)
- .setIncludeDirsCallback([](const Multilib &M) {
- return std::vector<std::string>({"/../../../../sysroot" +
- M.includeSuffix() +
- "/../usr/include"});
- })
- .setFilePathsCallback([](const Multilib &M) {
- return std::vector<std::string>(
- {"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()});
- });
- }
- for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) {
- if (Candidate->select(Flags, Result.SelectedMultilib)) {
- Result.Multilibs = *Candidate;
- return true;
- }
- }
- return false;
-}
-
-static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
- FilterNonExistent &NonExistent,
- DetectedMultilibs &Result) {
- // CodeScape IMG toolchain v1.2 and early.
- MultilibSet ImgMultilibsV1;
- {
- auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32");
-
- auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
-
- auto MAbi64 =
- makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
-
- ImgMultilibsV1 =
- MultilibSet()
- .Maybe(Mips64r6)
- .Maybe(MAbi64)
- .Maybe(LittleEndian)
- .FilterOut(NonExistent)
- .setIncludeDirsCallback([](const Multilib &M) {
- return std::vector<std::string>(
- {"/include", "/../../../../sysroot/usr/include"});
- });
- }
-
- // CodeScape IMG toolchain starting from v1.3.
- MultilibSet ImgMultilibsV2;
- {
- auto BeHard = makeMultilib("/mips-r6-hard")
- .flag("+EB")
- .flag("-msoft-float")
- .flag("-mmicromips");
- auto BeSoft = makeMultilib("/mips-r6-soft")
- .flag("+EB")
- .flag("+msoft-float")
- .flag("-mmicromips");
- auto ElHard = makeMultilib("/mipsel-r6-hard")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("-mmicromips");
- auto ElSoft = makeMultilib("/mipsel-r6-soft")
- .flag("+EL")
- .flag("+msoft-float")
- .flag("-mmicromips");
- auto BeMicroHard = makeMultilib("/micromips-r6-hard")
- .flag("+EB")
- .flag("-msoft-float")
- .flag("+mmicromips");
- auto BeMicroSoft = makeMultilib("/micromips-r6-soft")
- .flag("+EB")
- .flag("+msoft-float")
- .flag("+mmicromips");
- auto ElMicroHard = makeMultilib("/micromipsel-r6-hard")
- .flag("+EL")
- .flag("-msoft-float")
- .flag("+mmicromips");
- auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft")
- .flag("+EL")
- .flag("+msoft-float")
- .flag("+mmicromips");
-
- auto O32 =
- makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
- auto N32 =
- makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
- auto N64 =
- makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
-
- ImgMultilibsV2 =
- MultilibSet()
- .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft,
- ElMicroHard, ElMicroSoft})
- .Either(O32, N32, N64)
- .FilterOut(NonExistent)
- .setIncludeDirsCallback([](const Multilib &M) {
- return std::vector<std::string>({"/../../../../sysroot" +
- M.includeSuffix() +
- "/../usr/include"});
- })
- .setFilePathsCallback([](const Multilib &M) {
- return std::vector<std::string>(
- {"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()});
- });
- }
- for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) {
- if (Candidate->select(Flags, Result.SelectedMultilib)) {
- Result.Multilibs = *Candidate;
- return true;
- }
- }
- return false;
-}
-
-static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
- StringRef Path, const ArgList &Args,
- DetectedMultilibs &Result) {
- FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
-
- StringRef CPUName;
- StringRef ABIName;
- tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName);
-
- llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
-
- Multilib::flags_list Flags;
- addMultilibFlag(isMips32(TargetArch), "m32", Flags);
- addMultilibFlag(isMips64(TargetArch), "m64", Flags);
- addMultilibFlag(isMips16(Args), "mips16", Flags);
- addMultilibFlag(CPUName == "mips32", "march=mips32", Flags);
- addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" ||
- CPUName == "mips32r5" || CPUName == "p5600",
- "march=mips32r2", Flags);
- addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags);
- addMultilibFlag(CPUName == "mips64", "march=mips64", Flags);
- addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" ||
- CPUName == "mips64r5" || CPUName == "octeon",
- "march=mips64r2", Flags);
- addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags);
- addMultilibFlag(isMicroMips(Args), "mmicromips", Flags);
- addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags);
- addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008",
- Flags);
- addMultilibFlag(ABIName == "n32", "mabi=n32", Flags);
- addMultilibFlag(ABIName == "n64", "mabi=n64", Flags);
- addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags);
- addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags);
- addMultilibFlag(isMipsEL(TargetArch), "EL", Flags);
- addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags);
-
- if (TargetTriple.isAndroid())
- return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent,
- Result);
-
- if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies &&
- TargetTriple.getOS() == llvm::Triple::Linux &&
- TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment)
- return findMipsMuslMultilibs(Flags, NonExistent, Result);
-
- if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies &&
- TargetTriple.getOS() == llvm::Triple::Linux &&
- TargetTriple.getEnvironment() == llvm::Triple::GNU)
- return findMipsMtiMultilibs(Flags, NonExistent, Result);
-
- if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies &&
- TargetTriple.getOS() == llvm::Triple::Linux &&
- TargetTriple.getEnvironment() == llvm::Triple::GNU)
- return findMipsImgMultilibs(Flags, NonExistent, Result);
-
- if (findMipsCsMultilibs(Flags, NonExistent, Result))
- return true;
-
- // Fallback to the regular toolchain-tree structure.
- Multilib Default;
- Result.Multilibs.push_back(Default);
- Result.Multilibs.FilterOut(NonExistent);
-
- if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) {
- Result.BiarchSibling = Multilib();
- return true;
- }
-
- return false;
-}
-
-static void findAndroidArmMultilibs(const Driver &D,
- const llvm::Triple &TargetTriple,
- StringRef Path, const ArgList &Args,
- DetectedMultilibs &Result) {
- // 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");
- Multilib ThumbMultilib = makeMultilib("/thumb")
- .flag("-armv7")
- .flag("+thumb");
- Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb")
- .flag("+armv7")
- .flag("+thumb");
- Multilib DefaultMultilib = makeMultilib("")
- .flag("-armv7")
- .flag("-thumb");
- MultilibSet AndroidArmMultilibs =
- MultilibSet()
- .Either(ThumbMultilib, ArmV7Multilib,
- ArmV7ThumbMultilib, DefaultMultilib)
- .FilterOut(NonExistent);
-
- Multilib::flags_list Flags;
- llvm::StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ);
- bool IsArmArch = TargetTriple.getArch() == llvm::Triple::arm;
- bool IsThumbArch = TargetTriple.getArch() == llvm::Triple::thumb;
- bool IsV7SubArch = TargetTriple.getSubArch() == llvm::Triple::ARMSubArch_v7;
- bool IsThumbMode = IsThumbArch ||
- Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, false) ||
- (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::IK_THUMB);
- bool IsArmV7Mode = (IsArmArch || IsThumbArch) &&
- (llvm::ARM::parseArchVersion(Arch) == 7 ||
- (IsArmArch && Arch == "" && IsV7SubArch));
- addMultilibFlag(IsArmV7Mode, "armv7", Flags);
- addMultilibFlag(IsThumbMode, "thumb", Flags);
-
- if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib))
- Result.Multilibs = AndroidArmMultilibs;
-}
-
-static bool findBiarchMultilibs(const Driver &D,
- const llvm::Triple &TargetTriple,
- StringRef Path, const ArgList &Args,
- bool NeedsBiarchSuffix,
- DetectedMultilibs &Result) {
- // Some versions of SUSE and Fedora on ppc64 put 32-bit libs
- // in what would normally be GCCInstallPath and put the 64-bit
- // libs in a subdirectory named 64. The simple logic we follow is that
- // *if* there is a subdirectory of the right name with crtbegin.o in it,
- // we use that. If not, and if not a biarch triple alias, we look for
- // crtbegin.o without the subdirectory.
-
- Multilib Default;
- Multilib Alt64 = Multilib()
- .gccSuffix("/64")
- .includeSuffix("/64")
- .flag("-m32")
- .flag("+m64")
- .flag("-mx32");
- Multilib Alt32 = Multilib()
- .gccSuffix("/32")
- .includeSuffix("/32")
- .flag("+m32")
- .flag("-m64")
- .flag("-mx32");
- Multilib Altx32 = Multilib()
- .gccSuffix("/x32")
- .includeSuffix("/x32")
- .flag("-m32")
- .flag("-m64")
- .flag("+mx32");
-
- // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a.
- FilterNonExistent NonExistent(
- Path, TargetTriple.isOSIAMCU() ? "/libgcc.a" : "/crtbegin.o", D.getVFS());
-
- // Determine default multilib from: 32, 64, x32
- // Also handle cases such as 64 on 32, 32 on 64, etc.
- enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN;
- const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32;
- if (TargetTriple.isArch32Bit() && !NonExistent(Alt32))
- Want = WANT64;
- else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32))
- Want = WANT64;
- else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64))
- Want = WANT32;
- else {
- if (TargetTriple.isArch32Bit())
- Want = NeedsBiarchSuffix ? WANT64 : WANT32;
- else if (IsX32)
- Want = NeedsBiarchSuffix ? WANT64 : WANTX32;
- else
- Want = NeedsBiarchSuffix ? WANT32 : WANT64;
- }
-
- if (Want == WANT32)
- Default.flag("+m32").flag("-m64").flag("-mx32");
- else if (Want == WANT64)
- Default.flag("-m32").flag("+m64").flag("-mx32");
- else if (Want == WANTX32)
- Default.flag("-m32").flag("-m64").flag("+mx32");
- else
- return false;
-
- Result.Multilibs.push_back(Default);
- Result.Multilibs.push_back(Alt64);
- Result.Multilibs.push_back(Alt32);
- Result.Multilibs.push_back(Altx32);
-
- Result.Multilibs.FilterOut(NonExistent);
-
- Multilib::flags_list Flags;
- addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags);
- addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags);
- addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags);
-
- if (!Result.Multilibs.select(Flags, Result.SelectedMultilib))
- return false;
-
- if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 ||
- Result.SelectedMultilib == Altx32)
- Result.BiarchSibling = Default;
-
- return true;
-}
-
-void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris(
- const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args,
- const std::string &LibDir, StringRef CandidateTriple,
- bool NeedsBiarchSuffix) {
- // Solaris is a special case. The GCC installation is under
- // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/, so we
- // need to iterate twice.
- std::error_code EC;
- for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE;
- !EC && LI != LE; LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->getName());
- GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
-
- if (CandidateVersion.Major != -1) // Filter obviously bad entries.
- if (!CandidateGCCInstallPaths.insert(LI->getName()).second)
- continue; // Saw this path before; no need to look at it again.
- if (CandidateVersion.isOlderThan(4, 1, 1))
- continue;
- if (CandidateVersion <= Version)
- continue;
-
- GCCInstallPath =
- LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str();
- if (!D.getVFS().exists(GCCInstallPath))
- continue;
-
- // If we make it here there has to be at least one GCC version, let's just
- // use the latest one.
- std::error_code EEC;
- for (vfs::directory_iterator
- LLI = D.getVFS().dir_begin(GCCInstallPath, EEC),
- LLE;
- !EEC && LLI != LLE; LLI = LLI.increment(EEC)) {
-
- StringRef SubVersionText = llvm::sys::path::filename(LLI->getName());
- GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText);
-
- if (CandidateSubVersion > Version)
- Version = CandidateSubVersion;
- }
-
- GCCTriple.setTriple(CandidateTriple);
-
- GCCInstallPath += "/" + Version.Text;
- GCCParentLibPath = GCCInstallPath + "/../../../../";
-
- IsValid = true;
- }
-}
-
-bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
- const llvm::Triple &TargetTriple, const ArgList &Args,
- StringRef Path, bool NeedsBiarchSuffix) {
- llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
- DetectedMultilibs Detected;
-
- // Android standalone toolchain could have multilibs for ARM and Thumb.
- // Debian mips multilibs behave more like the rest of the biarch ones,
- // so handle them there
- if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) {
- // It should also work without multilibs in a simplified toolchain.
- findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected);
- } else if (isMipsArch(TargetArch)) {
- if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected))
- return false;
- } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args,
- NeedsBiarchSuffix, Detected)) {
- return false;
- }
-
- Multilibs = Detected.Multilibs;
- SelectedMultilib = Detected.SelectedMultilib;
- BiarchSibling = Detected.BiarchSibling;
-
- return true;
-}
-
-void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
- const llvm::Triple &TargetTriple, const ArgList &Args,
- const std::string &LibDir, StringRef CandidateTriple,
- bool NeedsBiarchSuffix) {
- llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
- // There are various different suffixes involving the triple we
- // check for. We also record what is necessary to walk from each back
- // up to the lib directory. Specifically, the number of "up" steps
- // in the second half of each row is 1 + the number of path separators
- // in the first half.
- const std::string LibAndInstallSuffixes[][2] = {
- {"/gcc/" + CandidateTriple.str(), "/../../.."},
-
- // Debian puts cross-compilers in gcc-cross
- {"/gcc-cross/" + CandidateTriple.str(), "/../../.."},
-
- {"/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(),
- "/../../../.."},
-
- // The Freescale PPC SDK has the gcc libraries in
- // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well.
- {"/" + CandidateTriple.str(), "/../.."},
-
- // Ubuntu has a strange mis-matched pair of triples that this happens to
- // match.
- // FIXME: It may be worthwhile to generalize this and look for a second
- // triple.
- {"/i386-linux-gnu/gcc/" + CandidateTriple.str(), "/../../../.."}};
-
- if (TargetTriple.getOS() == llvm::Triple::Solaris) {
- scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple,
- NeedsBiarchSuffix);
- return;
- }
-
- // Only look at the final, weird Ubuntu suffix for i386-linux-gnu.
- const unsigned NumLibSuffixes = (llvm::array_lengthof(LibAndInstallSuffixes) -
- (TargetArch != llvm::Triple::x86));
- for (unsigned i = 0; i < NumLibSuffixes; ++i) {
- StringRef LibSuffix = LibAndInstallSuffixes[i][0];
- std::error_code EC;
- for (vfs::directory_iterator
- LI = D.getVFS().dir_begin(LibDir + LibSuffix, EC),
- LE;
- !EC && LI != LE; LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->getName());
- GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
- if (CandidateVersion.Major != -1) // Filter obviously bad entries.
- if (!CandidateGCCInstallPaths.insert(LI->getName()).second)
- continue; // Saw this path before; no need to look at it again.
- if (CandidateVersion.isOlderThan(4, 1, 1))
- continue;
- if (CandidateVersion <= Version)
- continue;
-
- if (!ScanGCCForMultilibs(TargetTriple, Args, LI->getName(),
- NeedsBiarchSuffix))
- continue;
-
- Version = CandidateVersion;
- GCCTriple.setTriple(CandidateTriple);
- // FIXME: We hack together the directory name here instead of
- // using LI to ensure stable path separators across Windows and
- // Linux.
- GCCInstallPath =
- LibDir + LibAndInstallSuffixes[i][0] + "/" + VersionText.str();
- GCCParentLibPath = GCCInstallPath + LibAndInstallSuffixes[i][1];
- IsValid = true;
- }
- }
-}
-
-bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
- const llvm::Triple &TargetTriple, const ArgList &Args,
- StringRef CandidateTriple, bool NeedsBiarchSuffix) {
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
- D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" +
- CandidateTriple.str());
- if (File) {
- SmallVector<StringRef, 2> Lines;
- File.get()->getBuffer().split(Lines, "\n");
- for (StringRef Line : Lines) {
- // CURRENT=triple-version
- if (Line.consume_front("CURRENT=")) {
- const std::pair<StringRef, StringRef> ActiveVersion =
- Line.rsplit('-');
- // Note: Strictly speaking, we should be reading
- // /etc/env.d/gcc/${CURRENT} now. However, the file doesn't
- // contain anything new or especially useful to us.
- const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" +
- ActiveVersion.first.str() + "/" +
- ActiveVersion.second.str();
- if (D.getVFS().exists(GentooPath + "/crtbegin.o")) {
- if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath,
- NeedsBiarchSuffix))
- return false;
-
- Version = GCCVersion::Parse(ActiveVersion.second);
- GCCInstallPath = GentooPath;
- GCCParentLibPath = GentooPath + "/../../..";
- GCCTriple.setTriple(ActiveVersion.first);
- IsValid = true;
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : ToolChain(D, Triple, Args), GCCInstallation(D),
- CudaInstallation(D, Triple, Args) {
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir)
- getProgramPaths().push_back(getDriver().Dir);
-}
-
-Generic_GCC::~Generic_GCC() {}
-
-Tool *Generic_GCC::getTool(Action::ActionClass AC) const {
- switch (AC) {
- case Action::PreprocessJobClass:
- if (!Preprocess)
- Preprocess.reset(new tools::gcc::Preprocessor(*this));
- return Preprocess.get();
- case Action::CompileJobClass:
- if (!Compile)
- Compile.reset(new tools::gcc::Compiler(*this));
- return Compile.get();
- default:
- return ToolChain::getTool(AC);
- }
-}
-
-Tool *Generic_GCC::buildAssembler() const {
- return new tools::gnutools::Assembler(*this);
-}
-
-Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); }
-
-void Generic_GCC::printVerboseInfo(raw_ostream &OS) const {
- // Print the information about how we detected the GCC installation.
- GCCInstallation.print(OS);
- CudaInstallation.print(OS);
-}
-
-bool Generic_GCC::IsUnwindTablesDefault() const {
- return getArch() == llvm::Triple::x86_64;
-}
-
-bool Generic_GCC::isPICDefault() const {
- switch (getArch()) {
- case llvm::Triple::x86_64:
- return getTriple().isOSWindows();
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX();
- default:
- return false;
- }
-}
-
-bool Generic_GCC::isPIEDefault() const { return false; }
-
-bool Generic_GCC::isPICDefaultForced() const {
- return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows();
-}
-
-bool Generic_GCC::IsIntegratedAssemblerDefault() const {
- switch (getTriple().getArch()) {
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::bpfel:
- case llvm::Triple::bpfeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::systemz:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- return true;
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- // Enabled for Debian mips64/mips64el only. Other targets are unable to
- // distinguish N32 from N64.
- if (getTriple().getEnvironment() == llvm::Triple::GNUABI64)
- return true;
- return false;
- default:
- return false;
- }
-}
-
-void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
- return;
-
- switch (GetCXXStdlibType(DriverArgs)) {
- case ToolChain::CST_Libcxx: {
- std::string Path = findLibCxxIncludePath();
- if (!Path.empty())
- addSystemInclude(DriverArgs, CC1Args, Path);
- break;
- }
-
- case ToolChain::CST_Libstdcxx:
- addLibStdCxxIncludePaths(DriverArgs, CC1Args);
- break;
- }
-}
-
-std::string Generic_GCC::findLibCxxIncludePath() const {
- // FIXME: The Linux behavior would probaby be a better approach here.
- return getDriver().SysRoot + "/usr/include/c++/v1";
-}
-
-void
-Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- // By default, we don't assume we know where libstdc++ might be installed.
- // FIXME: If we have a valid GCCInstallation, use it.
-}
-
-/// \brief Helper to add the variant paths of a libstdc++ installation.
-bool Generic_GCC::addLibStdCXXIncludePaths(
- Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple,
- StringRef TargetMultiarchTriple, Twine IncludeSuffix,
- const ArgList &DriverArgs, ArgStringList &CC1Args) const {
- if (!getVFS().exists(Base + Suffix))
- return false;
-
- addSystemInclude(DriverArgs, CC1Args, Base + Suffix);
-
- // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If
- // that path exists or we have neither a GCC nor target multiarch triple, use
- // this vanilla search path.
- if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) ||
- getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) {
- addSystemInclude(DriverArgs, CC1Args,
- Base + Suffix + "/" + GCCTriple + IncludeSuffix);
- } else {
- // Otherwise try to use multiarch naming schemes which have normalized the
- // triples and put the triple before the suffix.
- //
- // GCC surprisingly uses *both* the GCC triple with a multilib suffix and
- // the target triple, so we support that here.
- addSystemInclude(DriverArgs, CC1Args,
- Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix);
- addSystemInclude(DriverArgs, CC1Args,
- Base + "/" + TargetMultiarchTriple + Suffix);
- }
-
- addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward");
- return true;
-}
-
-llvm::opt::DerivedArgList *
-Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef,
- Action::OffloadKind DeviceOffloadKind) const {
-
- // If this tool chain is used for an OpenMP offloading device we have to make
- // sure we always generate a shared library regardless of the commands the
- // user passed to the host. This is required because the runtime library
- // is required to load the device image dynamically at run time.
- if (DeviceOffloadKind == Action::OFK_OpenMP) {
- DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
- const OptTable &Opts = getDriver().getOpts();
-
- // Request the shared library. Given that these options are decided
- // implicitly, they do not refer to any base argument.
- DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_shared));
- DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_fPIC));
-
- // Filter all the arguments we don't care passing to the offloading
- // toolchain as they can mess up with the creation of a shared library.
- for (auto *A : Args) {
- switch ((options::ID)A->getOption().getID()) {
- default:
- DAL->append(A);
- break;
- case options::OPT_shared:
- case options::OPT_dynamic:
- case options::OPT_static:
- case options::OPT_fPIC:
- case options::OPT_fno_PIC:
- case options::OPT_fpic:
- case options::OPT_fno_pic:
- case options::OPT_fPIE:
- case options::OPT_fno_PIE:
- case options::OPT_fpie:
- case options::OPT_fno_pie:
- break;
- }
- }
- return DAL;
- }
- return nullptr;
-}
-
-void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion();
- bool UseInitArrayDefault =
- getTriple().getArch() == llvm::Triple::aarch64 ||
- getTriple().getArch() == llvm::Triple::aarch64_be ||
- (getTriple().getOS() == llvm::Triple::Linux &&
- (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) ||
- getTriple().getOS() == llvm::Triple::NaCl ||
- (getTriple().getVendor() == llvm::Triple::MipsTechnologies &&
- !getTriple().hasEnvironment());
-
- if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
- options::OPT_fno_use_init_array, UseInitArrayDefault))
- CC1Args.push_back("-fuse-init-array");
-}
-
-/// Mips Toolchain
-MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D,
- const llvm::Triple &Triple,
- const ArgList &Args)
- : Linux(D, Triple, Args) {
- // Select the correct multilib according to the given arguments.
- DetectedMultilibs Result;
- findMIPSMultilibs(D, Triple, "", Args, Result);
- Multilibs = Result.Multilibs;
- SelectedMultilib = Result.SelectedMultilib;
-
- // Find out the library suffix based on the ABI.
- LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple);
- getFilePaths().clear();
- getFilePaths().push_back(computeSysRoot() + "/usr/lib" + LibSuffix);
-}
-
-void MipsLLVMToolChain::AddClangSystemIncludeArgs(
- const ArgList &DriverArgs, ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc))
- return;
-
- const Driver &D = getDriver();
-
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- SmallString<128> P(D.ResourceDir);
- llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P);
- }
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- const auto &Callback = Multilibs.includeDirsCallback();
- if (Callback) {
- for (const auto &Path : Callback(SelectedMultilib))
- addExternCSystemIncludeIfExists(DriverArgs, CC1Args,
- D.getInstalledDir() + Path);
- }
-}
-
-Tool *MipsLLVMToolChain::buildLinker() const {
- return new tools::gnutools::Linker(*this);
-}
-
-std::string MipsLLVMToolChain::computeSysRoot() const {
- if (!getDriver().SysRoot.empty())
- return getDriver().SysRoot + SelectedMultilib.osSuffix();
-
- const std::string InstalledDir(getDriver().getInstalledDir());
- std::string SysRootPath =
- InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix();
- if (llvm::sys::fs::exists(SysRootPath))
- return SysRootPath;
-
- return std::string();
-}
-
-ToolChain::CXXStdlibType
-MipsLLVMToolChain::GetCXXStdlibType(const ArgList &Args) const {
- Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
- if (A) {
- StringRef Value = A->getValue();
- if (Value != "libc++")
- getDriver().Diag(diag::err_drv_invalid_stdlib_name)
- << A->getAsString(Args);
- }
-
- return ToolChain::CST_Libcxx;
-}
-
-std::string MipsLLVMToolChain::findLibCxxIncludePath() const {
- if (const auto &Callback = Multilibs.includeDirsCallback()) {
- for (std::string Path : Callback(SelectedMultilib)) {
- Path = getDriver().getInstalledDir() + Path + "/c++/v1";
- if (llvm::sys::fs::exists(Path)) {
- return Path;
- }
- }
- }
- return "";
-}
-
-void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) &&
- "Only -lc++ (aka libxx) is suported in this toolchain.");
-
- CmdArgs.push_back("-lc++");
- CmdArgs.push_back("-lc++abi");
- CmdArgs.push_back("-lunwind");
-}
-
-std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args,
- StringRef Component,
- bool Shared) const {
- SmallString<128> Path(getDriver().ResourceDir);
- llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix,
- getOS());
- llvm::sys::path::append(Path, Twine("libclang_rt." + Component + "-" +
- "mips" + (Shared ? ".so" : ".a")));
- return Path.str();
-}
-
-/// Hexagon Toolchain
-
-std::string HexagonToolChain::getHexagonTargetDir(
- const std::string &InstalledDir,
- const SmallVectorImpl<std::string> &PrefixDirs) const {
- std::string InstallRelDir;
- const Driver &D = getDriver();
-
- // Locate the rest of the toolchain ...
- for (auto &I : PrefixDirs)
- if (D.getVFS().exists(I))
- return I;
-
- if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
- return InstallRelDir;
-
- return InstalledDir;
-}
-
-Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
- const ArgList &Args) {
- StringRef Gn = "";
- if (Arg *A = Args.getLastArg(options::OPT_G, options::OPT_G_EQ,
- options::OPT_msmall_data_threshold_EQ)) {
- Gn = A->getValue();
- } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
- options::OPT_fPIC)) {
- Gn = "0";
- }
-
- unsigned G;
- if (!Gn.getAsInteger(10, G))
- return G;
-
- return None;
-}
-
-void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
- ToolChain::path_list &LibPaths) const {
- const Driver &D = getDriver();
-
- //----------------------------------------------------------------------------
- // -L Args
- //----------------------------------------------------------------------------
- for (Arg *A : Args.filtered(options::OPT_L))
- for (const char *Value : A->getValues())
- LibPaths.push_back(Value);
-
- //----------------------------------------------------------------------------
- // Other standard paths
- //----------------------------------------------------------------------------
- std::vector<std::string> RootDirs;
- std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
- std::back_inserter(RootDirs));
-
- std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
- D.PrefixDirs);
- if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end())
- RootDirs.push_back(TargetDir);
-
- bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
- // Assume G0 with -shared.
- bool HasG0 = Args.hasArg(options::OPT_shared);
- if (auto G = getSmallDataThreshold(Args))
- HasG0 = G.getValue() == 0;
-
- const std::string CpuVer = GetTargetCPUVersion(Args).str();
- for (auto &Dir : RootDirs) {
- std::string LibDir = Dir + "/hexagon/lib";
- std::string LibDirCpu = LibDir + '/' + CpuVer;
- if (HasG0) {
- if (HasPIC)
- LibPaths.push_back(LibDirCpu + "/G0/pic");
- LibPaths.push_back(LibDirCpu + "/G0");
- }
- LibPaths.push_back(LibDirCpu);
- LibPaths.push_back(LibDir);
- }
-}
-
-HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args)
- : Linux(D, Triple, Args) {
- const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
- D.PrefixDirs);
-
- // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
- // program paths
- const std::string BinDir(TargetDir + "/bin");
- if (D.getVFS().exists(BinDir))
- getProgramPaths().push_back(BinDir);
-
- ToolChain::path_list &LibPaths = getFilePaths();
-
- // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
- // 'elf' OS type, so the Linux paths are not appropriate. When we actually
- // support 'linux' we'll need to fix this up
- LibPaths.clear();
- getHexagonLibraryPaths(Args, LibPaths);
-}
-
-HexagonToolChain::~HexagonToolChain() {}
-
-Tool *HexagonToolChain::buildAssembler() const {
- return new tools::hexagon::Assembler(*this);
-}
-
-Tool *HexagonToolChain::buildLinker() const {
- return new tools::hexagon::Linker(*this);
-}
-
-void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc) ||
- DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- const Driver &D = getDriver();
- std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
- D.PrefixDirs);
- addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
-}
-
-
-void HexagonToolChain::addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- const Driver &D = getDriver();
- std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
- addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "",
- DriverArgs, CC1Args);
-}
-
-ToolChain::CXXStdlibType
-HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
- Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
- if (!A)
- return ToolChain::CST_Libstdcxx;
-
- StringRef Value = A->getValue();
- if (Value != "libstdc++")
- getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
-
- return ToolChain::CST_Libstdcxx;
-}
-
-//
-// Returns the default CPU for Hexagon. This is the default compilation target
-// if no Hexagon processor is selected at the command-line.
-//
-const StringRef HexagonToolChain::GetDefaultCPU() {
- return "hexagonv60";
-}
-
-const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
- Arg *CpuArg = nullptr;
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
- CpuArg = A;
-
- StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
- if (CPU.startswith("hexagon"))
- return CPU.substr(sizeof("hexagon") - 1);
- return CPU;
-}
-// End Hexagon
-
-/// AMDGPU Toolchain
-AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) { }
-
-Tool *AMDGPUToolChain::buildLinker() const {
- return new tools::amdgpu::Linker(*this);
-}
-// End AMDGPU
-
-/// NaCl Toolchain
-NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
-
- // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the
- // default paths, and must instead only use the paths provided
- // with this toolchain based on architecture.
- path_list &file_paths = getFilePaths();
- path_list &prog_paths = getProgramPaths();
-
- file_paths.clear();
- prog_paths.clear();
-
- // Path for library files (libc.a, ...)
- std::string FilePath(getDriver().Dir + "/../");
-
- // Path for tools (clang, ld, etc..)
- std::string ProgPath(getDriver().Dir + "/../");
-
- // Path for toolchain libraries (libgcc.a, ...)
- std::string ToolPath(getDriver().ResourceDir + "/lib/");
-
- switch (Triple.getArch()) {
- case llvm::Triple::x86:
- file_paths.push_back(FilePath + "x86_64-nacl/lib32");
- file_paths.push_back(FilePath + "i686-nacl/usr/lib");
- prog_paths.push_back(ProgPath + "x86_64-nacl/bin");
- file_paths.push_back(ToolPath + "i686-nacl");
- break;
- case llvm::Triple::x86_64:
- file_paths.push_back(FilePath + "x86_64-nacl/lib");
- file_paths.push_back(FilePath + "x86_64-nacl/usr/lib");
- prog_paths.push_back(ProgPath + "x86_64-nacl/bin");
- file_paths.push_back(ToolPath + "x86_64-nacl");
- break;
- case llvm::Triple::arm:
- file_paths.push_back(FilePath + "arm-nacl/lib");
- file_paths.push_back(FilePath + "arm-nacl/usr/lib");
- prog_paths.push_back(ProgPath + "arm-nacl/bin");
- file_paths.push_back(ToolPath + "arm-nacl");
- break;
- case llvm::Triple::mipsel:
- file_paths.push_back(FilePath + "mipsel-nacl/lib");
- file_paths.push_back(FilePath + "mipsel-nacl/usr/lib");
- prog_paths.push_back(ProgPath + "bin");
- file_paths.push_back(ToolPath + "mipsel-nacl");
- break;
- default:
- break;
- }
-
- NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s");
-}
-
-void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- const Driver &D = getDriver();
- if (DriverArgs.hasArg(options::OPT_nostdinc))
- return;
-
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- SmallString<128> P(D.ResourceDir);
- llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
- }
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- SmallString<128> P(D.Dir + "/../");
- switch (getTriple().getArch()) {
- case llvm::Triple::x86:
- // x86 is special because multilib style uses x86_64-nacl/include for libc
- // headers but the SDK wants i686-nacl/usr/include. The other architectures
- // have the same substring.
- llvm::sys::path::append(P, "i686-nacl/usr/include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
- llvm::sys::path::remove_filename(P);
- llvm::sys::path::remove_filename(P);
- llvm::sys::path::remove_filename(P);
- llvm::sys::path::append(P, "x86_64-nacl/include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
- return;
- case llvm::Triple::arm:
- llvm::sys::path::append(P, "arm-nacl/usr/include");
- break;
- case llvm::Triple::x86_64:
- llvm::sys::path::append(P, "x86_64-nacl/usr/include");
- break;
- case llvm::Triple::mipsel:
- llvm::sys::path::append(P, "mipsel-nacl/usr/include");
- break;
- default:
- return;
- }
-
- addSystemInclude(DriverArgs, CC1Args, P.str());
- llvm::sys::path::remove_filename(P);
- llvm::sys::path::remove_filename(P);
- llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P.str());
-}
-
-void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Check for -stdlib= flags. We only support libc++ but this consumes the arg
- // if the value is libc++, and emits an error for other values.
- GetCXXStdlibType(Args);
- CmdArgs.push_back("-lc++");
-}
-
-std::string NaClToolChain::findLibCxxIncludePath() const {
- const Driver &D = getDriver();
-
- SmallString<128> P(D.Dir + "/../");
- switch (getTriple().getArch()) {
- case llvm::Triple::arm:
- llvm::sys::path::append(P, "arm-nacl/include/c++/v1");
- return P.str();
- case llvm::Triple::x86:
- llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1");
- return P.str();
- case llvm::Triple::x86_64:
- llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1");
- return P.str();
- case llvm::Triple::mipsel:
- llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1");
- return P.str();
- default:
- return "";
- }
-}
-
-ToolChain::CXXStdlibType
-NaClToolChain::GetCXXStdlibType(const ArgList &Args) const {
- if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
- StringRef Value = A->getValue();
- if (Value == "libc++")
- return ToolChain::CST_Libcxx;
- getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
- }
-
- return ToolChain::CST_Libcxx;
-}
-
-std::string
-NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
- types::ID InputType) const {
- llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType));
- if (TheTriple.getArch() == llvm::Triple::arm &&
- TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment)
- TheTriple.setEnvironment(llvm::Triple::GNUEABIHF);
- return TheTriple.getTriple();
-}
-
-Tool *NaClToolChain::buildLinker() const {
- return new tools::nacltools::Linker(*this);
-}
-
-Tool *NaClToolChain::buildAssembler() const {
- if (getTriple().getArch() == llvm::Triple::arm)
- return new tools::nacltools::AssemblerARM(*this);
- return new tools::gnutools::Assembler(*this);
-}
-// End NaCl
-
-/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
-/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
-/// Currently does not support anything else but compilation.
-
-TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : ToolChain(D, Triple, Args) {
- // Path mangling to find libexec
- std::string Path(getDriver().Dir);
-
- Path += "/../libexec";
- getProgramPaths().push_back(Path);
-}
-
-TCEToolChain::~TCEToolChain() {}
-
-bool TCEToolChain::IsMathErrnoDefault() const { return true; }
-
-bool TCEToolChain::isPICDefault() const { return false; }
-
-bool TCEToolChain::isPIEDefault() const { return false; }
-
-bool TCEToolChain::isPICDefaultForced() const { return false; }
-
-TCELEToolChain::TCELEToolChain(const Driver &D, const llvm::Triple& Triple,
- const ArgList &Args)
- : TCEToolChain(D, Triple, Args) {
-}
-
-TCELEToolChain::~TCELEToolChain() {}
-
-// CloudABI - CloudABI tool chain which can call ld(1) directly.
-
-CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- SmallString<128> P(getDriver().Dir);
- llvm::sys::path::append(P, "..", getTriple().str(), "lib");
- getFilePaths().push_back(P.str());
-}
-
-std::string CloudABI::findLibCxxIncludePath() const {
- SmallString<128> P(getDriver().Dir);
- llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1");
- return P.str();
-}
-
-void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- CmdArgs.push_back("-lc++");
- CmdArgs.push_back("-lc++abi");
- CmdArgs.push_back("-lunwind");
-}
-
-Tool *CloudABI::buildLinker() const {
- return new tools::cloudabi::Linker(*this);
-}
-
-bool CloudABI::isPIEDefault() const {
- // Only enable PIE on architectures that support PC-relative
- // addressing. PC-relative addressing is required, as the process
- // startup code must be able to relocate itself.
- switch (getTriple().getArch()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::x86_64:
- return true;
- default:
- return false;
- }
-}
-
-SanitizerMask CloudABI::getSupportedSanitizers() const {
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- Res |= SanitizerKind::SafeStack;
- return Res;
-}
-
-SanitizerMask CloudABI::getDefaultSanitizers() const {
- return SanitizerKind::SafeStack;
-}
-
-/// Haiku - Haiku tool chain which can call as(1) and ld(1) directly.
-
-Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
-
-}
-
-std::string Haiku::findLibCxxIncludePath() const {
- return getDriver().SysRoot + "/system/develop/headers/c++/v1";
-}
-
-void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- addLibStdCXXIncludePaths(getDriver().SysRoot, "/system/develop/headers/c++",
- getTriple().str(), "", "", "", DriverArgs, CC1Args);
-}
-
-/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.
-
-OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- getFilePaths().push_back(getDriver().Dir + "/../lib");
- getFilePaths().push_back("/usr/lib");
-}
-
-Tool *OpenBSD::buildAssembler() const {
- return new tools::openbsd::Assembler(*this);
-}
-
-Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
-
-/// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly.
-
-Bitrig::Bitrig(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- getFilePaths().push_back(getDriver().Dir + "/../lib");
- getFilePaths().push_back("/usr/lib");
-}
-
-Tool *Bitrig::buildAssembler() const {
- return new tools::bitrig::Assembler(*this);
-}
-
-Tool *Bitrig::buildLinker() const { return new tools::bitrig::Linker(*this); }
-
-ToolChain::CXXStdlibType Bitrig::GetDefaultCXXStdlibType() const {
- return ToolChain::CST_Libcxx;
-}
-
-void Bitrig::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- std::string Triple = getTriple().str();
- if (StringRef(Triple).startswith("amd64"))
- Triple = "x86_64" + Triple.substr(5);
- addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/stdc++",
- Triple, "", "", "", DriverArgs, CC1Args);
-}
-
-void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- switch (GetCXXStdlibType(Args)) {
- case ToolChain::CST_Libcxx:
- CmdArgs.push_back("-lc++");
- CmdArgs.push_back("-lc++abi");
- CmdArgs.push_back("-lpthread");
- break;
- case ToolChain::CST_Libstdcxx:
- CmdArgs.push_back("-lstdc++");
- break;
- }
-}
-
-/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.
-
-FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
-
- // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall
- // back to '/usr/lib' if it doesn't exist.
- if ((Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::ppc) &&
- D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o"))
- getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32");
- else
- getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
-}
-
-ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const {
- if (getTriple().getOSMajorVersion() >= 10)
- return ToolChain::CST_Libcxx;
- return ToolChain::CST_Libstdcxx;
-}
-
-void FreeBSD::addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/4.2", "", "",
- "", "", DriverArgs, CC1Args);
-}
-
-void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- CXXStdlibType Type = GetCXXStdlibType(Args);
- bool Profiling = Args.hasArg(options::OPT_pg);
-
- switch (Type) {
- case ToolChain::CST_Libcxx:
- CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
- break;
-
- case ToolChain::CST_Libstdcxx:
- CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++");
- break;
- }
-}
-
-Tool *FreeBSD::buildAssembler() const {
- return new tools::freebsd::Assembler(*this);
-}
-
-Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); }
-
-bool FreeBSD::UseSjLjExceptions(const ArgList &Args) const {
- // FreeBSD uses SjLj exceptions on ARM oabi.
- switch (getTriple().getEnvironment()) {
- case llvm::Triple::GNUEABIHF:
- case llvm::Triple::GNUEABI:
- case llvm::Triple::EABI:
- return false;
-
- default:
- return (getTriple().getArch() == llvm::Triple::arm ||
- getTriple().getArch() == llvm::Triple::thumb);
- }
-}
-
-bool FreeBSD::HasNativeLLVMSupport() const { return true; }
-
-bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
-
-SanitizerMask FreeBSD::getSupportedSanitizers() const {
- const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
- const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
- const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 ||
- getTriple().getArch() == llvm::Triple::mips64el;
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- Res |= SanitizerKind::Address;
- Res |= SanitizerKind::Vptr;
- if (IsX86_64 || IsMIPS64) {
- Res |= SanitizerKind::Leak;
- Res |= SanitizerKind::Thread;
- }
- if (IsX86 || IsX86_64) {
- Res |= SanitizerKind::SafeStack;
- }
- return Res;
-}
-
-/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
-
-NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- if (getDriver().UseStdLib) {
- // When targeting a 32-bit platform, try the special directory used on
- // 64-bit hosts, and only fall back to the main library directory if that
- // doesn't work.
- // FIXME: It'd be nicer to test if this directory exists, but I'm not sure
- // what all logic is needed to emulate the '=' prefix here.
- switch (Triple.getArch()) {
- case llvm::Triple::x86:
- getFilePaths().push_back("=/usr/lib/i386");
- break;
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- switch (Triple.getEnvironment()) {
- case llvm::Triple::EABI:
- case llvm::Triple::GNUEABI:
- getFilePaths().push_back("=/usr/lib/eabi");
- break;
- case llvm::Triple::EABIHF:
- case llvm::Triple::GNUEABIHF:
- getFilePaths().push_back("=/usr/lib/eabihf");
- break;
- default:
- getFilePaths().push_back("=/usr/lib/oabi");
- break;
- }
- break;
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- if (tools::mips::hasMipsAbiArg(Args, "o32"))
- getFilePaths().push_back("=/usr/lib/o32");
- else if (tools::mips::hasMipsAbiArg(Args, "64"))
- getFilePaths().push_back("=/usr/lib/64");
- break;
- case llvm::Triple::ppc:
- getFilePaths().push_back("=/usr/lib/powerpc");
- break;
- case llvm::Triple::sparc:
- getFilePaths().push_back("=/usr/lib/sparc");
- break;
- default:
- break;
- }
-
- getFilePaths().push_back("=/usr/lib");
- }
-}
-
-Tool *NetBSD::buildAssembler() const {
- return new tools::netbsd::Assembler(*this);
-}
-
-Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); }
-
-ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const {
- unsigned Major, Minor, Micro;
- getTriple().getOSVersion(Major, Minor, Micro);
- if (Major >= 7 || Major == 0) {
- switch (getArch()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::sparc:
- case llvm::Triple::sparcv9:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- return ToolChain::CST_Libcxx;
- default:
- break;
- }
- }
- return ToolChain::CST_Libstdcxx;
-}
-
-std::string NetBSD::findLibCxxIncludePath() const {
- return getDriver().SysRoot + "/usr/include/c++/";
-}
-
-void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "",
- "", DriverArgs, CC1Args);
-}
-
-/// Minix - Minix tool chain which can call as(1) and ld(1) directly.
-
-Minix::Minix(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- getFilePaths().push_back(getDriver().Dir + "/../lib");
- getFilePaths().push_back("/usr/lib");
-}
-
-Tool *Minix::buildAssembler() const {
- return new tools::minix::Assembler(*this);
-}
-
-Tool *Minix::buildLinker() const { return new tools::minix::Linker(*this); }
-
-static void addPathIfExists(const Driver &D, const Twine &Path,
- ToolChain::path_list &Paths) {
- if (D.getVFS().exists(Path))
- Paths.push_back(Path.str());
-}
-
-/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
-
-Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_GCC(D, Triple, Args) {
-
- GCCInstallation.init(Triple, Args);
-
- path_list &Paths = getFilePaths();
- if (GCCInstallation.isValid())
- addPathIfExists(D, GCCInstallation.getInstallPath(), Paths);
-
- addPathIfExists(D, getDriver().getInstalledDir(), Paths);
- if (getDriver().getInstalledDir() != getDriver().Dir)
- addPathIfExists(D, getDriver().Dir, Paths);
-
- addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib", Paths);
-
- std::string LibPath = "/usr/lib/";
- switch (Triple.getArch()) {
- case llvm::Triple::x86:
- case llvm::Triple::sparc:
- break;
- case llvm::Triple::x86_64:
- LibPath += "amd64/";
- break;
- case llvm::Triple::sparcv9:
- LibPath += "sparcv9/";
- break;
- default:
- llvm_unreachable("Unsupported architecture");
- }
-
- addPathIfExists(D, getDriver().SysRoot + LibPath, Paths);
-}
-
-Tool *Solaris::buildAssembler() const {
- return new tools::solaris::Assembler(*this);
-}
-
-Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); }
-
-void Solaris::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
- return;
-
- // Include the support directory for things like xlocale and fudged system
- // headers.
- // FIXME: This is a weird mix of libc++ and libstdc++. We should also be
- // checking the value of -stdlib= here and adding the includes for libc++
- // rather than libstdc++ if it's requested.
- addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/v1/support/solaris");
-
- if (GCCInstallation.isValid()) {
- GCCVersion Version = GCCInstallation.getVersion();
- addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/usr/gcc/" +
- Version.MajorStr + "." +
- Version.MinorStr +
- "/include/c++/" + Version.Text);
- addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/usr/gcc/" + Version.MajorStr +
- "." + Version.MinorStr + "/include/c++/" +
- Version.Text + "/" +
- GCCInstallation.getTriple().str());
- }
-}
-
-/// \brief Get our best guess at the multiarch triple for a target.
-///
-/// Debian-based systems are starting to use a multiarch setup where they use
-/// a target-triple directory in the library and header search paths.
-/// Unfortunately, this triple does not align with the vanilla target triple,
-/// so we provide a rough mapping here.
-static std::string getMultiarchTriple(const Driver &D,
- const llvm::Triple &TargetTriple,
- StringRef SysRoot) {
- llvm::Triple::EnvironmentType TargetEnvironment =
- TargetTriple.getEnvironment();
-
- // For most architectures, just use whatever we have rather than trying to be
- // clever.
- switch (TargetTriple.getArch()) {
- default:
- break;
-
- // We use the existence of '/lib/<triple>' as a directory to detect some
- // common linux triples that don't quite match the Clang triple for both
- // 32-bit and 64-bit targets. Multiarch fixes its install triples to these
- // regardless of what the actual target triple is.
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- if (TargetEnvironment == llvm::Triple::GNUEABIHF) {
- if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabihf"))
- return "arm-linux-gnueabihf";
- } else {
- if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabi"))
- return "arm-linux-gnueabi";
- }
- break;
- case llvm::Triple::armeb:
- case llvm::Triple::thumbeb:
- if (TargetEnvironment == llvm::Triple::GNUEABIHF) {
- if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabihf"))
- return "armeb-linux-gnueabihf";
- } else {
- if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabi"))
- return "armeb-linux-gnueabi";
- }
- break;
- case llvm::Triple::x86:
- if (D.getVFS().exists(SysRoot + "/lib/i386-linux-gnu"))
- return "i386-linux-gnu";
- break;
- case llvm::Triple::x86_64:
- // We don't want this for x32, otherwise it will match x86_64 libs
- if (TargetEnvironment != llvm::Triple::GNUX32 &&
- D.getVFS().exists(SysRoot + "/lib/x86_64-linux-gnu"))
- return "x86_64-linux-gnu";
- break;
- case llvm::Triple::aarch64:
- if (D.getVFS().exists(SysRoot + "/lib/aarch64-linux-gnu"))
- return "aarch64-linux-gnu";
- break;
- case llvm::Triple::aarch64_be:
- if (D.getVFS().exists(SysRoot + "/lib/aarch64_be-linux-gnu"))
- return "aarch64_be-linux-gnu";
- break;
- case llvm::Triple::mips:
- if (D.getVFS().exists(SysRoot + "/lib/mips-linux-gnu"))
- return "mips-linux-gnu";
- break;
- case llvm::Triple::mipsel:
- if (D.getVFS().exists(SysRoot + "/lib/mipsel-linux-gnu"))
- return "mipsel-linux-gnu";
- break;
- case llvm::Triple::mips64:
- if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu"))
- return "mips64-linux-gnu";
- if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnuabi64"))
- return "mips64-linux-gnuabi64";
- break;
- case llvm::Triple::mips64el:
- if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu"))
- return "mips64el-linux-gnu";
- if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnuabi64"))
- return "mips64el-linux-gnuabi64";
- break;
- case llvm::Triple::ppc:
- if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe"))
- return "powerpc-linux-gnuspe";
- if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnu"))
- return "powerpc-linux-gnu";
- break;
- case llvm::Triple::ppc64:
- if (D.getVFS().exists(SysRoot + "/lib/powerpc64-linux-gnu"))
- return "powerpc64-linux-gnu";
- break;
- case llvm::Triple::ppc64le:
- if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu"))
- return "powerpc64le-linux-gnu";
- break;
- case llvm::Triple::sparc:
- if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu"))
- return "sparc-linux-gnu";
- break;
- case llvm::Triple::sparcv9:
- if (D.getVFS().exists(SysRoot + "/lib/sparc64-linux-gnu"))
- return "sparc64-linux-gnu";
- break;
- case llvm::Triple::systemz:
- if (D.getVFS().exists(SysRoot + "/lib/s390x-linux-gnu"))
- return "s390x-linux-gnu";
- break;
- }
- return TargetTriple.str();
-}
-
-static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
- if (isMipsArch(Triple.getArch())) {
- if (Triple.isAndroid()) {
- StringRef CPUName;
- StringRef ABIName;
- tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
- if (CPUName == "mips32r6")
- return "libr6";
- if (CPUName == "mips32r2")
- return "libr2";
- }
- // lib32 directory has a special meaning on MIPS targets.
- // It contains N32 ABI binaries. Use this folder if produce
- // code for N32 ABI only.
- if (tools::mips::hasMipsAbiArg(Args, "n32"))
- return "lib32";
- return Triple.isArch32Bit() ? "lib" : "lib64";
- }
-
- // It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and
- // using that variant while targeting other architectures causes problems
- // because the libraries are laid out in shared system roots that can't cope
- // with a 'lib32' library search path being considered. So we only enable
- // them when we know we may need it.
- //
- // FIXME: This is a bit of a hack. We should really unify this code for
- // reasoning about oslibdir spellings with the lib dir spellings in the
- // GCCInstallationDetector, but that is a more significant refactoring.
- if (Triple.getArch() == llvm::Triple::x86 ||
- Triple.getArch() == llvm::Triple::ppc)
- return "lib32";
-
- if (Triple.getArch() == llvm::Triple::x86_64 &&
- Triple.getEnvironment() == llvm::Triple::GNUX32)
- return "libx32";
-
- return Triple.isArch32Bit() ? "lib" : "lib64";
-}
-
-static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
- const Multilib &Multilib,
- StringRef InstallPath,
- ToolChain::path_list &Paths) {
- if (const auto &PathsCallback = Multilibs.filePathsCallback())
- for (const auto &Path : PathsCallback(Multilib))
- addPathIfExists(D, InstallPath + Path, Paths);
-}
-
-Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- GCCInstallation.init(Triple, Args);
- Multilibs = GCCInstallation.getMultilibs();
- llvm::Triple::ArchType Arch = Triple.getArch();
- std::string SysRoot = computeSysRoot();
-
- // Cross-compiling binutils and GCC installations (vanilla and openSUSE at
- // least) put various tools in a triple-prefixed directory off of the parent
- // of the GCC installation. We use the GCC triple here to ensure that we end
- // up with tools that support the same amount of cross compiling as the
- // detected GCC installation. For example, if we find a GCC installation
- // targeting x86_64, but it is a bi-arch GCC installation, it can also be
- // used to target i386.
- // FIXME: This seems unlikely to be Linux-specific.
- ToolChain::path_list &PPaths = getProgramPaths();
- PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
- GCCInstallation.getTriple().str() + "/bin")
- .str());
-
- Distro Distro(D.getVFS());
-
- if (Distro.IsOpenSUSE() || Distro.IsUbuntu()) {
- ExtraOpts.push_back("-z");
- ExtraOpts.push_back("relro");
- }
-
- if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
- ExtraOpts.push_back("-X");
-
- const bool IsAndroid = Triple.isAndroid();
- const bool IsMips = isMipsArch(Arch);
-
- if (IsMips && !SysRoot.empty())
- ExtraOpts.push_back("--sysroot=" + SysRoot);
-
- // Do not use 'gnu' hash style for Mips targets because .gnu.hash
- // and the MIPS ABI require .dynsym to be sorted in different ways.
- // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS
- // ABI requires a mapping between the GOT and the symbol table.
- // Android loader does not support .gnu.hash.
- if (!IsMips && !IsAndroid) {
- if (Distro.IsRedhat() || Distro.IsOpenSUSE() ||
- (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick))
- ExtraOpts.push_back("--hash-style=gnu");
-
- if (Distro.IsDebian() || Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid ||
- Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic)
- ExtraOpts.push_back("--hash-style=both");
- }
-
- if (Distro.IsRedhat() && Distro != Distro::RHEL5 && Distro != Distro::RHEL6)
- ExtraOpts.push_back("--no-add-needed");
-
-#ifdef ENABLE_LINKER_BUILD_ID
- ExtraOpts.push_back("--build-id");
-#endif
-
- if (Distro.IsOpenSUSE())
- ExtraOpts.push_back("--enable-new-dtags");
-
- // The selection of paths to try here is designed to match the patterns which
- // the GCC driver itself uses, as this is part of the GCC-compatible driver.
- // This was determined by running GCC in a fake filesystem, creating all
- // possible permutations of these directories, and seeing which ones it added
- // to the link paths.
- path_list &Paths = getFilePaths();
-
- const std::string OSLibDir = getOSLibDir(Triple, Args);
- const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot);
-
- // Add the multilib suffixed paths where they are available.
- if (GCCInstallation.isValid()) {
- const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
- const std::string &LibPath = GCCInstallation.getParentLibPath();
- const Multilib &Multilib = GCCInstallation.getMultilib();
- const MultilibSet &Multilibs = GCCInstallation.getMultilibs();
-
- // Add toolchain / multilib specific file paths.
- addMultilibsFilePaths(D, Multilibs, Multilib,
- GCCInstallation.getInstallPath(), Paths);
-
- // Sourcery CodeBench MIPS toolchain holds some libraries under
- // a biarch-like suffix of the GCC installation.
- addPathIfExists(D, GCCInstallation.getInstallPath() + Multilib.gccSuffix(),
- Paths);
-
- // GCC cross compiling toolchains will install target libraries which ship
- // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as
- // any part of the GCC installation in
- // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat
- // debatable, but is the reality today. We need to search this tree even
- // when we have a sysroot somewhere else. It is the responsibility of
- // whomever is doing the cross build targeting a sysroot using a GCC
- // installation that is *not* within the system root to ensure two things:
- //
- // 1) Any DSOs that are linked in from this tree or from the install path
- // above must be present on the system root and found via an
- // appropriate rpath.
- // 2) There must not be libraries installed into
- // <prefix>/<triple>/<libdir> unless they should be preferred over
- // those within the system root.
- //
- // Note that this matches the GCC behavior. See the below comment for where
- // Clang diverges from GCC's behavior.
- addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" +
- OSLibDir + Multilib.osSuffix(),
- Paths);
-
- // If the GCC installation we found is inside of the sysroot, we want to
- // prefer libraries installed in the parent prefix of the GCC installation.
- // It is important to *not* use these paths when the GCC installation is
- // outside of the system root as that can pick up unintended libraries.
- // This usually happens when there is an external cross compiler on the
- // host system, and a more minimal sysroot available that is the target of
- // the cross. Note that GCC does include some of these directories in some
- // configurations but this seems somewhere between questionable and simply
- // a bug.
- if (StringRef(LibPath).startswith(SysRoot)) {
- addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths);
- addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths);
- }
- }
-
- // Similar to the logic for GCC above, if we currently running Clang inside
- // of the requested system root, add its parent library paths to
- // those searched.
- // FIXME: It's not clear whether we should use the driver's installed
- // directory ('Dir' below) or the ResourceDir.
- if (StringRef(D.Dir).startswith(SysRoot)) {
- addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths);
- addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths);
- }
-
- addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths);
- addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths);
- addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths);
- addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths);
-
- // Try walking via the GCC triple path in case of biarch or multiarch GCC
- // installations with strange symlinks.
- if (GCCInstallation.isValid()) {
- addPathIfExists(D,
- SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() +
- "/../../" + OSLibDir,
- Paths);
-
- // Add the 'other' biarch variant path
- Multilib BiarchSibling;
- if (GCCInstallation.getBiarchSibling(BiarchSibling)) {
- addPathIfExists(D, GCCInstallation.getInstallPath() +
- BiarchSibling.gccSuffix(),
- Paths);
- }
-
- // See comments above on the multilib variant for details of why this is
- // included even from outside the sysroot.
- const std::string &LibPath = GCCInstallation.getParentLibPath();
- const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
- const Multilib &Multilib = GCCInstallation.getMultilib();
- addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" +
- Multilib.osSuffix(),
- Paths);
-
- // See comments above on the multilib variant for details of why this is
- // only included from within the sysroot.
- if (StringRef(LibPath).startswith(SysRoot))
- addPathIfExists(D, LibPath, Paths);
- }
-
- // Similar to the logic for GCC above, if we are currently running Clang
- // inside of the requested system root, add its parent library path to those
- // searched.
- // FIXME: It's not clear whether we should use the driver's installed
- // directory ('Dir' below) or the ResourceDir.
- if (StringRef(D.Dir).startswith(SysRoot))
- addPathIfExists(D, D.Dir + "/../lib", Paths);
-
- addPathIfExists(D, SysRoot + "/lib", Paths);
- addPathIfExists(D, SysRoot + "/usr/lib", Paths);
-}
-
-bool Linux::HasNativeLLVMSupport() const { return true; }
-
-Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); }
-
-Tool *Linux::buildAssembler() const {
- return new tools::gnutools::Assembler(*this);
-}
-
-std::string Linux::computeSysRoot() const {
- if (!getDriver().SysRoot.empty())
- return getDriver().SysRoot;
-
- if (!GCCInstallation.isValid() || !isMipsArch(getTriple().getArch()))
- return std::string();
-
- // Standalone MIPS toolchains use different names for sysroot folder
- // and put it into different places. Here we try to check some known
- // variants.
-
- const StringRef InstallDir = GCCInstallation.getInstallPath();
- const StringRef TripleStr = GCCInstallation.getTriple().str();
- const Multilib &Multilib = GCCInstallation.getMultilib();
-
- std::string Path =
- (InstallDir + "/../../../../" + TripleStr + "/libc" + Multilib.osSuffix())
- .str();
-
- if (getVFS().exists(Path))
- return Path;
-
- Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str();
-
- if (getVFS().exists(Path))
- return Path;
-
- return std::string();
-}
-
-std::string Linux::getDynamicLinker(const ArgList &Args) const {
- const llvm::Triple::ArchType Arch = getArch();
- const llvm::Triple &Triple = getTriple();
-
- const Distro Distro(getDriver().getVFS());
-
- if (Triple.isAndroid())
- return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker";
-
- if (Triple.isMusl()) {
- std::string ArchName;
- bool IsArm = false;
-
- switch (Arch) {
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- ArchName = "arm";
- IsArm = true;
- break;
- case llvm::Triple::armeb:
- case llvm::Triple::thumbeb:
- ArchName = "armeb";
- IsArm = true;
- break;
- default:
- ArchName = Triple.getArchName().str();
- }
- if (IsArm &&
- (Triple.getEnvironment() == llvm::Triple::MuslEABIHF ||
- tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard))
- ArchName += "hf";
-
- return "/lib/ld-musl-" + ArchName + ".so.1";
- }
-
- std::string LibDir;
- std::string Loader;
-
- switch (Arch) {
- default:
- llvm_unreachable("unsupported architecture");
-
- case llvm::Triple::aarch64:
- LibDir = "lib";
- Loader = "ld-linux-aarch64.so.1";
- break;
- case llvm::Triple::aarch64_be:
- LibDir = "lib";
- Loader = "ld-linux-aarch64_be.so.1";
- break;
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- case llvm::Triple::armeb:
- case llvm::Triple::thumbeb: {
- const bool HF =
- Triple.getEnvironment() == llvm::Triple::GNUEABIHF ||
- tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard;
-
- LibDir = "lib";
- Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3";
- break;
- }
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el: {
- bool LE = (Triple.getArch() == llvm::Triple::mipsel) ||
- (Triple.getArch() == llvm::Triple::mips64el);
- bool IsNaN2008 = tools::mips::isNaN2008(Args, Triple);
-
- LibDir = "lib" + tools::mips::getMipsABILibSuffix(Args, Triple);
-
- if (tools::mips::isUCLibc(Args))
- Loader = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0";
- else if (!Triple.hasEnvironment() &&
- Triple.getVendor() == llvm::Triple::VendorType::MipsTechnologies)
- Loader = LE ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1";
- else
- Loader = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1";
-
- break;
- }
- case llvm::Triple::ppc:
- LibDir = "lib";
- Loader = "ld.so.1";
- break;
- case llvm::Triple::ppc64:
- LibDir = "lib64";
- Loader =
- (tools::ppc::hasPPCAbiArg(Args, "elfv2")) ? "ld64.so.2" : "ld64.so.1";
- break;
- case llvm::Triple::ppc64le:
- LibDir = "lib64";
- Loader =
- (tools::ppc::hasPPCAbiArg(Args, "elfv1")) ? "ld64.so.1" : "ld64.so.2";
- break;
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- LibDir = "lib";
- Loader = "ld-linux.so.2";
- break;
- case llvm::Triple::sparcv9:
- LibDir = "lib64";
- Loader = "ld-linux.so.2";
- break;
- case llvm::Triple::systemz:
- LibDir = "lib";
- Loader = "ld64.so.1";
- break;
- case llvm::Triple::x86:
- LibDir = "lib";
- Loader = "ld-linux.so.2";
- break;
- case llvm::Triple::x86_64: {
- bool X32 = Triple.getEnvironment() == llvm::Triple::GNUX32;
-
- LibDir = X32 ? "libx32" : "lib64";
- Loader = X32 ? "ld-linux-x32.so.2" : "ld-linux-x86-64.so.2";
- break;
- }
- }
-
- if (Distro == Distro::Exherbo && (Triple.getVendor() == llvm::Triple::UnknownVendor ||
- Triple.getVendor() == llvm::Triple::PC))
- return "/usr/" + Triple.str() + "/lib/" + Loader;
- return "/" + LibDir + "/" + Loader;
-}
-
-void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- const Driver &D = getDriver();
- std::string SysRoot = computeSysRoot();
-
- if (DriverArgs.hasArg(options::OPT_nostdinc))
- return;
-
- if (!DriverArgs.hasArg(options::OPT_nostdlibinc))
- addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
-
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- SmallString<128> P(D.ResourceDir);
- llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P);
- }
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- // Check for configure-time C include directories.
- StringRef CIncludeDirs(C_INCLUDE_DIRS);
- if (CIncludeDirs != "") {
- SmallVector<StringRef, 5> dirs;
- CIncludeDirs.split(dirs, ":");
- for (StringRef dir : dirs) {
- StringRef Prefix =
- llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : "";
- addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
- }
- return;
- }
-
- // Lacking those, try to detect the correct set of system includes for the
- // target triple.
-
- // Add include directories specific to the selected multilib set and multilib.
- if (GCCInstallation.isValid()) {
- const auto &Callback = Multilibs.includeDirsCallback();
- if (Callback) {
- for (const auto &Path : Callback(GCCInstallation.getMultilib()))
- addExternCSystemIncludeIfExists(
- DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path);
- }
- }
-
- // Implement generic Debian multiarch support.
- const StringRef X86_64MultiarchIncludeDirs[] = {
- "/usr/include/x86_64-linux-gnu",
-
- // FIXME: These are older forms of multiarch. It's not clear that they're
- // in use in any released version of Debian, so we should consider
- // removing them.
- "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64"};
- const StringRef X86MultiarchIncludeDirs[] = {
- "/usr/include/i386-linux-gnu",
-
- // FIXME: These are older forms of multiarch. It's not clear that they're
- // in use in any released version of Debian, so we should consider
- // removing them.
- "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu",
- "/usr/include/i486-linux-gnu"};
- const StringRef AArch64MultiarchIncludeDirs[] = {
- "/usr/include/aarch64-linux-gnu"};
- const StringRef ARMMultiarchIncludeDirs[] = {
- "/usr/include/arm-linux-gnueabi"};
- const StringRef ARMHFMultiarchIncludeDirs[] = {
- "/usr/include/arm-linux-gnueabihf"};
- const StringRef ARMEBMultiarchIncludeDirs[] = {
- "/usr/include/armeb-linux-gnueabi"};
- const StringRef ARMEBHFMultiarchIncludeDirs[] = {
- "/usr/include/armeb-linux-gnueabihf"};
- const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"};
- const StringRef MIPSELMultiarchIncludeDirs[] = {
- "/usr/include/mipsel-linux-gnu"};
- const StringRef MIPS64MultiarchIncludeDirs[] = {
- "/usr/include/mips64-linux-gnu", "/usr/include/mips64-linux-gnuabi64"};
- const StringRef MIPS64ELMultiarchIncludeDirs[] = {
- "/usr/include/mips64el-linux-gnu",
- "/usr/include/mips64el-linux-gnuabi64"};
- const StringRef PPCMultiarchIncludeDirs[] = {
- "/usr/include/powerpc-linux-gnu"};
- const StringRef PPC64MultiarchIncludeDirs[] = {
- "/usr/include/powerpc64-linux-gnu"};
- const StringRef PPC64LEMultiarchIncludeDirs[] = {
- "/usr/include/powerpc64le-linux-gnu"};
- const StringRef SparcMultiarchIncludeDirs[] = {
- "/usr/include/sparc-linux-gnu"};
- const StringRef Sparc64MultiarchIncludeDirs[] = {
- "/usr/include/sparc64-linux-gnu"};
- const StringRef SYSTEMZMultiarchIncludeDirs[] = {
- "/usr/include/s390x-linux-gnu"};
- ArrayRef<StringRef> MultiarchIncludeDirs;
- switch (getTriple().getArch()) {
- case llvm::Triple::x86_64:
- MultiarchIncludeDirs = X86_64MultiarchIncludeDirs;
- break;
- case llvm::Triple::x86:
- MultiarchIncludeDirs = X86MultiarchIncludeDirs;
- break;
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- MultiarchIncludeDirs = AArch64MultiarchIncludeDirs;
- break;
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
- MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs;
- else
- MultiarchIncludeDirs = ARMMultiarchIncludeDirs;
- break;
- case llvm::Triple::armeb:
- case llvm::Triple::thumbeb:
- if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
- MultiarchIncludeDirs = ARMEBHFMultiarchIncludeDirs;
- else
- MultiarchIncludeDirs = ARMEBMultiarchIncludeDirs;
- break;
- case llvm::Triple::mips:
- MultiarchIncludeDirs = MIPSMultiarchIncludeDirs;
- break;
- case llvm::Triple::mipsel:
- MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs;
- break;
- case llvm::Triple::mips64:
- MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs;
- break;
- case llvm::Triple::mips64el:
- MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs;
- break;
- case llvm::Triple::ppc:
- MultiarchIncludeDirs = PPCMultiarchIncludeDirs;
- break;
- case llvm::Triple::ppc64:
- MultiarchIncludeDirs = PPC64MultiarchIncludeDirs;
- break;
- case llvm::Triple::ppc64le:
- MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs;
- break;
- case llvm::Triple::sparc:
- MultiarchIncludeDirs = SparcMultiarchIncludeDirs;
- break;
- case llvm::Triple::sparcv9:
- MultiarchIncludeDirs = Sparc64MultiarchIncludeDirs;
- break;
- case llvm::Triple::systemz:
- MultiarchIncludeDirs = SYSTEMZMultiarchIncludeDirs;
- break;
- default:
- break;
- }
- for (StringRef Dir : MultiarchIncludeDirs) {
- if (D.getVFS().exists(SysRoot + Dir)) {
- addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir);
- break;
- }
- }
-
- if (getTriple().getOS() == llvm::Triple::RTEMS)
- return;
-
- // Add an include of '/include' directly. This isn't provided by default by
- // system GCCs, but is often used with cross-compiling GCCs, and harmless to
- // add even when Clang is acting as-if it were a system compiler.
- addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
-
- addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
-}
-
-static std::string DetectLibcxxIncludePath(StringRef base) {
- std::error_code EC;
- int MaxVersion = 0;
- std::string MaxVersionString = "";
- for (llvm::sys::fs::directory_iterator LI(base, EC), LE; !EC && LI != LE;
- LI = LI.increment(EC)) {
- StringRef VersionText = llvm::sys::path::filename(LI->path());
- int Version;
- if (VersionText[0] == 'v' &&
- !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) {
- if (Version > MaxVersion) {
- MaxVersion = Version;
- MaxVersionString = VersionText;
- }
- }
- }
- return MaxVersion ? (base + "/" + MaxVersionString).str() : "";
-}
-
-std::string Linux::findLibCxxIncludePath() const {
- const std::string LibCXXIncludePathCandidates[] = {
- DetectLibcxxIncludePath(getDriver().Dir + "/../include/c++"),
- // If this is a development, non-installed, clang, libcxx will
- // not be found at ../include/c++ but it likely to be found at
- // one of the following two locations:
- DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/local/include/c++"),
- DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/include/c++") };
- for (const auto &IncludePath : LibCXXIncludePathCandidates) {
- if (IncludePath.empty() || !getVFS().exists(IncludePath))
- continue;
- // Use the first candidate that exists.
- return IncludePath;
- }
- return "";
-}
-
-void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- // We need a detected GCC installation on Linux to provide libstdc++'s
- // headers.
- if (!GCCInstallation.isValid())
- return;
-
- // By default, look for the C++ headers in an include directory adjacent to
- // the lib directory of the GCC installation. Note that this is expect to be
- // equivalent to '/usr/include/c++/X.Y' in almost all cases.
- StringRef LibDir = GCCInstallation.getParentLibPath();
- StringRef InstallDir = GCCInstallation.getInstallPath();
- StringRef TripleStr = GCCInstallation.getTriple().str();
- const Multilib &Multilib = GCCInstallation.getMultilib();
- const std::string GCCMultiarchTriple = getMultiarchTriple(
- getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot);
- const std::string TargetMultiarchTriple =
- getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot);
- const GCCVersion &Version = GCCInstallation.getVersion();
-
- // The primary search for libstdc++ supports multiarch variants.
- if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
- "/c++/" + Version.Text, TripleStr,
- GCCMultiarchTriple, TargetMultiarchTriple,
- Multilib.includeSuffix(), DriverArgs, CC1Args))
- return;
-
- // Otherwise, fall back on a bunch of options which don't use multiarch
- // layouts for simplicity.
- const std::string LibStdCXXIncludePathCandidates[] = {
- // Gentoo is weird and places its headers inside the GCC install,
- // so if the first attempt to find the headers fails, try these patterns.
- InstallDir.str() + "/include/g++-v" + Version.Text,
- InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." +
- Version.MinorStr,
- InstallDir.str() + "/include/g++-v" + Version.MajorStr,
- // Android standalone toolchain has C++ headers in yet another place.
- LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
- // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++,
- // without a subdirectory corresponding to the gcc version.
- LibDir.str() + "/../include/c++",
- };
-
- for (const auto &IncludePath : LibStdCXXIncludePathCandidates) {
- if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr,
- /*GCCMultiarchTriple*/ "",
- /*TargetMultiarchTriple*/ "",
- Multilib.includeSuffix(), DriverArgs, CC1Args))
- break;
- }
-}
-
-void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
-}
-
-void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (GCCInstallation.isValid()) {
- CC1Args.push_back("-isystem");
- CC1Args.push_back(DriverArgs.MakeArgString(
- GCCInstallation.getParentLibPath() + "/../" +
- GCCInstallation.getTriple().str() + "/include"));
- }
-}
-
-bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
-
-SanitizerMask Linux::getSupportedSanitizers() const {
- const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
- const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
- const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 ||
- getTriple().getArch() == llvm::Triple::mips64el;
- const bool IsPowerPC64 = getTriple().getArch() == llvm::Triple::ppc64 ||
- getTriple().getArch() == llvm::Triple::ppc64le;
- const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
- getTriple().getArch() == llvm::Triple::aarch64_be;
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- Res |= SanitizerKind::Address;
- Res |= SanitizerKind::KernelAddress;
- Res |= SanitizerKind::Vptr;
- Res |= SanitizerKind::SafeStack;
- if (IsX86_64 || IsMIPS64 || IsAArch64)
- Res |= SanitizerKind::DataFlow;
- if (IsX86_64 || IsMIPS64 || IsAArch64)
- Res |= SanitizerKind::Leak;
- if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64)
- Res |= SanitizerKind::Thread;
- if (IsX86_64 || IsMIPS64 || IsPowerPC64 || IsAArch64)
- Res |= SanitizerKind::Memory;
- if (IsX86_64 || IsMIPS64)
- Res |= SanitizerKind::Efficiency;
- if (IsX86 || IsX86_64) {
- Res |= SanitizerKind::Function;
- }
- return Res;
-}
-
-void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const {
- if (!needsProfileRT(Args)) return;
-
- // Add linker option -u__llvm_runtime_variable to cause runtime
- // initialization module to be linked in.
- if (!Args.hasArg(options::OPT_coverage))
- CmdArgs.push_back(Args.MakeArgString(
- Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
- ToolChain::addProfileRTLibs(Args, CmdArgs);
-}
-
-/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.
-
-Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
-
- getFilePaths().push_back(D.SysRoot + "/lib");
- getFilePaths().push_back(D.ResourceDir + "/lib/fuchsia");
-}
-
-Tool *Fuchsia::buildAssembler() const {
- return new tools::gnutools::Assembler(*this);
-}
-
-Tool *Fuchsia::buildLinker() const {
- return new tools::fuchsia::Linker(*this);
-}
-
-ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType(
- const ArgList &Args) const {
- if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) {
- StringRef Value = A->getValue();
- if (Value != "compiler-rt")
- getDriver().Diag(diag::err_drv_invalid_rtlib_name)
- << A->getAsString(Args);
- }
-
- return ToolChain::RLT_CompilerRT;
-}
-
-ToolChain::CXXStdlibType
-Fuchsia::GetCXXStdlibType(const ArgList &Args) const {
- if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
- StringRef Value = A->getValue();
- if (Value != "libc++")
- getDriver().Diag(diag::err_drv_invalid_stdlib_name)
- << A->getAsString(Args);
- }
-
- return ToolChain::CST_Libcxx;
-}
-
-void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
- options::OPT_fno_use_init_array, true))
- CC1Args.push_back("-fuse-init-array");
-}
-
-void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- const Driver &D = getDriver();
-
- if (DriverArgs.hasArg(options::OPT_nostdinc))
- return;
-
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- SmallString<128> P(D.ResourceDir);
- llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P);
- }
-
- if (DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
-
- // Check for configure-time C include directories.
- StringRef CIncludeDirs(C_INCLUDE_DIRS);
- if (CIncludeDirs != "") {
- SmallVector<StringRef, 5> dirs;
- CIncludeDirs.split(dirs, ":");
- for (StringRef dir : dirs) {
- StringRef Prefix =
- llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
- addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
- }
- return;
- }
-
- addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include");
-}
-
-std::string Fuchsia::findLibCxxIncludePath() const {
- return getDriver().SysRoot + "/include/c++/v1";
-}
-
-void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- (void) GetCXXStdlibType(Args);
- CmdArgs.push_back("-lc++");
- CmdArgs.push_back("-lc++abi");
- CmdArgs.push_back("-lunwind");
-}
-
-/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.
-
-DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
-
- // Path mangling to find libexec
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir)
- getProgramPaths().push_back(getDriver().Dir);
-
- getFilePaths().push_back(getDriver().Dir + "/../lib");
- getFilePaths().push_back("/usr/lib");
- getFilePaths().push_back("/usr/lib/gcc50");
-}
-
-Tool *DragonFly::buildAssembler() const {
- return new tools::dragonfly::Assembler(*this);
-}
-
-Tool *DragonFly::buildLinker() const {
- return new tools::dragonfly::Linker(*this);
-}
-
-/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary,
-/// which isn't properly a linker but nonetheless performs the step of stitching
-/// together object files from the assembler into a single blob.
-
-CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple,
- const ToolChain &HostTC, const ArgList &Args)
- : ToolChain(D, Triple, Args), HostTC(HostTC),
- CudaInstallation(D, HostTC.getTriple(), Args) {
- if (CudaInstallation.isValid())
- getProgramPaths().push_back(CudaInstallation.getBinPath());
-}
-
-void CudaToolChain::addClangTargetOptions(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- HostTC.addClangTargetOptions(DriverArgs, CC1Args);
-
- CC1Args.push_back("-fcuda-is-device");
-
- if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero,
- options::OPT_fno_cuda_flush_denormals_to_zero, false))
- CC1Args.push_back("-fcuda-flush-denormals-to-zero");
-
- if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
- options::OPT_fno_cuda_approx_transcendentals, false))
- CC1Args.push_back("-fcuda-approx-transcendentals");
-
- if (DriverArgs.hasArg(options::OPT_nocudalib))
- return;
-
- StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
- assert(!GpuArch.empty() && "Must have an explicit GPU arch.");
- std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch);
-
- if (LibDeviceFile.empty()) {
- getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch;
- return;
- }
-
- CC1Args.push_back("-mlink-cuda-bitcode");
- CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile));
-
- // Libdevice in CUDA-7.0 requires PTX version that's more recent
- // than LLVM defaults to. Use PTX4.2 which is the PTX version that
- // came with CUDA-7.0.
- CC1Args.push_back("-target-feature");
- CC1Args.push_back("+ptx42");
-}
-
-void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- // Check our CUDA version if we're going to include the CUDA headers.
- if (!DriverArgs.hasArg(options::OPT_nocudainc) &&
- !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) {
- StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
- assert(!Arch.empty() && "Must have an explicit GPU arch.");
- CudaInstallation.CheckCudaVersionSupportsArch(StringToCudaArch(Arch));
- }
- CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
-}
-
-llvm::opt::DerivedArgList *
-CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
- StringRef BoundArch,
- Action::OffloadKind DeviceOffloadKind) const {
- DerivedArgList *DAL =
- HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
- if (!DAL)
- DAL = new DerivedArgList(Args.getBaseArgs());
-
- const OptTable &Opts = getDriver().getOpts();
-
- for (Arg *A : Args) {
- if (A->getOption().matches(options::OPT_Xarch__)) {
- // Skip this argument unless the architecture matches BoundArch
- if (BoundArch.empty() || A->getValue(0) != BoundArch)
- continue;
-
- unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
- unsigned Prev = Index;
- std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index));
-
- // If the argument parsing failed or more than one argument was
- // consumed, the -Xarch_ argument's parameter tried to consume
- // extra arguments. Emit an error and ignore.
- //
- // We also want to disallow any options which would alter the
- // driver behavior; that isn't going to work in our model. We
- // use isDriverOption() as an approximation, although things
- // like -O4 are going to slip through.
- if (!XarchArg || Index > Prev + 1) {
- getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args)
- << A->getAsString(Args);
- continue;
- } else if (XarchArg->getOption().hasFlag(options::DriverOption)) {
- getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver)
- << A->getAsString(Args);
- continue;
- }
- XarchArg->setBaseArg(A);
- A = XarchArg.release();
- DAL->AddSynthesizedArg(A);
- }
- DAL->append(A);
- }
-
- if (!BoundArch.empty()) {
- DAL->eraseArg(options::OPT_march_EQ);
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch);
- }
- return DAL;
-}
-
-Tool *CudaToolChain::buildAssembler() const {
- return new tools::NVPTX::Assembler(*this);
-}
-
-Tool *CudaToolChain::buildLinker() const {
- return new tools::NVPTX::Linker(*this);
-}
-
-void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
- HostTC.addClangWarningOptions(CC1Args);
-}
-
-ToolChain::CXXStdlibType
-CudaToolChain::GetCXXStdlibType(const ArgList &Args) const {
- return HostTC.GetCXXStdlibType(Args);
-}
-
-void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
-}
-
-void CudaToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
- ArgStringList &CC1Args) const {
- HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
-}
-
-void CudaToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
- ArgStringList &CC1Args) const {
- HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
-}
-
-SanitizerMask CudaToolChain::getSupportedSanitizers() const {
- // The CudaToolChain only supports sanitizers in the sense that it allows
- // sanitizer arguments on the command line if they are supported by the host
- // toolchain. The CudaToolChain will actually ignore any command line
- // arguments for any of these "supported" sanitizers. That means that no
- // sanitization of device code is actually supported at this time.
- //
- // This behavior is necessary because the host and device toolchains
- // invocations often share the command line, so the device toolchain must
- // tolerate flags meant only for the host toolchain.
- return HostTC.getSupportedSanitizers();
-}
-
-VersionTuple CudaToolChain::computeMSVCVersion(const Driver *D,
- const ArgList &Args) const {
- return HostTC.computeMSVCVersion(D, Args);
-}
-
-/// XCore tool chain
-XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : ToolChain(D, Triple, Args) {
- // ProgramPaths are found via 'PATH' environment variable.
-}
-
-Tool *XCoreToolChain::buildAssembler() const {
- return new tools::XCore::Assembler(*this);
-}
-
-Tool *XCoreToolChain::buildLinker() const {
- return new tools::XCore::Linker(*this);
-}
-
-bool XCoreToolChain::isPICDefault() const { return false; }
-
-bool XCoreToolChain::isPIEDefault() const { return false; }
-
-bool XCoreToolChain::isPICDefaultForced() const { return false; }
-
-bool XCoreToolChain::SupportsProfiling() const { return false; }
-
-bool XCoreToolChain::hasBlocksRuntime() const { return false; }
-
-void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc) ||
- DriverArgs.hasArg(options::OPT_nostdlibinc))
- return;
- if (const char *cl_include_dir = getenv("XCC_C_INCLUDE_PATH")) {
- SmallVector<StringRef, 4> Dirs;
- const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
- StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr));
- ArrayRef<StringRef> DirVec(Dirs);
- addSystemIncludes(DriverArgs, CC1Args, DirVec);
- }
-}
-
-void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- CC1Args.push_back("-nostdsysteminc");
-}
-
-void XCoreToolChain::AddClangCXXStdlibIncludeArgs(
- const ArgList &DriverArgs, ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdinc) ||
- DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
- return;
- if (const char *cl_include_dir = getenv("XCC_CPLUS_INCLUDE_PATH")) {
- SmallVector<StringRef, 4> Dirs;
- const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
- StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr));
- ArrayRef<StringRef> DirVec(Dirs);
- addSystemIncludes(DriverArgs, CC1Args, DirVec);
- }
-}
-
-void XCoreToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // We don't output any lib args. This is handled by xcc.
-}
-
-MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use
- // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple.
- // This won't work to find gcc. Instead we give the installation detector an
- // extra triple, which is preferable to further hacks of the logic that at
- // present is based solely on getArch(). In particular, it would be wrong to
- // choose the myriad installation when targeting a non-myriad sparc install.
- switch (Triple.getArch()) {
- default:
- D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName()
- << "myriad";
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::shave:
- GCCInstallation.init(Triple, Args, {"sparc-myriad-elf"});
- }
-
- if (GCCInstallation.isValid()) {
- // This directory contains crt{i,n,begin,end}.o as well as libgcc.
- // These files are tied to a particular version of gcc.
- SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath());
- addPathIfExists(D, CompilerSupportDir, getFilePaths());
- }
- // libstd++ and libc++ must both be found in this one place.
- addPathIfExists(D, D.Dir + "/../sparc-myriad-elf/lib", getFilePaths());
-}
-
-MyriadToolChain::~MyriadToolChain() {}
-
-void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (!DriverArgs.hasArg(options::OPT_nostdinc))
- addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include");
-}
-
-std::string MyriadToolChain::findLibCxxIncludePath() const {
- std::string Path(getDriver().getInstalledDir());
- return Path + "/../include/c++/v1";
-}
-
-void MyriadToolChain::addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- StringRef LibDir = GCCInstallation.getParentLibPath();
- const GCCVersion &Version = GCCInstallation.getVersion();
- StringRef TripleStr = GCCInstallation.getTriple().str();
- const Multilib &Multilib = GCCInstallation.getMultilib();
- addLibStdCXXIncludePaths(
- LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
- "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args);
-}
-
-// MyriadToolChain handles several triples:
-// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf
-Tool *MyriadToolChain::SelectTool(const JobAction &JA) const {
- // The inherited method works fine if not targeting the SHAVE.
- if (!isShaveCompilation(getTriple()))
- return ToolChain::SelectTool(JA);
- switch (JA.getKind()) {
- case Action::PreprocessJobClass:
- case Action::CompileJobClass:
- if (!Compiler)
- Compiler.reset(new tools::SHAVE::Compiler(*this));
- return Compiler.get();
- case Action::AssembleJobClass:
- if (!Assembler)
- Assembler.reset(new tools::SHAVE::Assembler(*this));
- return Assembler.get();
- default:
- return ToolChain::getTool(JA.getKind());
- }
-}
-
-Tool *MyriadToolChain::buildLinker() const {
- return new tools::Myriad::Linker(*this);
-}
-
-SanitizerMask MyriadToolChain::getSupportedSanitizers() const {
- return SanitizerKind::Address;
-}
-
-WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args)
- : ToolChain(D, Triple, Args) {
-
- assert(Triple.isArch32Bit() != Triple.isArch64Bit());
- getFilePaths().push_back(
- getDriver().SysRoot + "/lib" + (Triple.isArch32Bit() ? "32" : "64"));
-}
-
-bool WebAssembly::IsMathErrnoDefault() const { return false; }
-
-bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; }
-
-bool WebAssembly::UseObjCMixedDispatch() const { return true; }
-
-bool WebAssembly::isPICDefault() const { return false; }
-
-bool WebAssembly::isPIEDefault() const { return false; }
-
-bool WebAssembly::isPICDefaultForced() const { return false; }
-
-bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; }
-
-// TODO: Support Objective C stuff.
-bool WebAssembly::SupportsObjCGC() const { return false; }
-
-bool WebAssembly::hasBlocksRuntime() const { return false; }
-
-// TODO: Support profiling.
-bool WebAssembly::SupportsProfiling() const { return false; }
-
-bool WebAssembly::HasNativeLLVMSupport() const { return true; }
-
-void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
- options::OPT_fno_use_init_array, true))
- CC1Args.push_back("-fuse-init-array");
-}
-
-ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const {
- return ToolChain::RLT_CompilerRT;
-}
-
-ToolChain::CXXStdlibType WebAssembly::GetCXXStdlibType(const ArgList &Args) const {
- return ToolChain::CST_Libcxx;
-}
-
-void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (!DriverArgs.hasArg(options::OPT_nostdinc))
- addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include");
-}
-
-void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
- ArgStringList &CC1Args) const {
- if (!DriverArgs.hasArg(options::OPT_nostdlibinc) &&
- !DriverArgs.hasArg(options::OPT_nostdincxx))
- addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/include/c++/v1");
-}
-
-Tool *WebAssembly::buildLinker() const {
- return new tools::wasm::Linker(*this);
-}
-
-PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {
- if (Args.hasArg(options::OPT_static))
- D.Diag(diag::err_drv_unsupported_opt_for_target) << "-static" << "PS4";
-
- // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR
- // if it exists; otherwise use the driver's installation path, which
- // should be <SDK_DIR>/host_tools/bin.
-
- SmallString<512> PS4SDKDir;
- if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) {
- if (!llvm::sys::fs::exists(EnvValue))
- getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue;
- PS4SDKDir = EnvValue;
- } else {
- PS4SDKDir = getDriver().Dir;
- llvm::sys::path::append(PS4SDKDir, "/../../");
- }
-
- // By default, the driver won't report a warning if it can't find
- // PS4's include or lib directories. This behavior could be changed if
- // -Weverything or -Winvalid-or-nonexistent-directory options are passed.
- // If -isysroot was passed, use that as the SDK base path.
- std::string PrefixDir;
- if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- PrefixDir = A->getValue();
- if (!llvm::sys::fs::exists(PrefixDir))
- getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir;
- } else
- PrefixDir = PS4SDKDir.str();
-
- SmallString<512> PS4SDKIncludeDir(PrefixDir);
- llvm::sys::path::append(PS4SDKIncludeDir, "target/include");
- if (!Args.hasArg(options::OPT_nostdinc) &&
- !Args.hasArg(options::OPT_nostdlibinc) &&
- !Args.hasArg(options::OPT_isysroot) &&
- !Args.hasArg(options::OPT__sysroot_EQ) &&
- !llvm::sys::fs::exists(PS4SDKIncludeDir)) {
- getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
- << "PS4 system headers" << PS4SDKIncludeDir;
- }
-
- SmallString<512> PS4SDKLibDir(PS4SDKDir);
- llvm::sys::path::append(PS4SDKLibDir, "target/lib");
- if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs) &&
- !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) &&
- !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) &&
- !Args.hasArg(options::OPT_emit_ast) &&
- !llvm::sys::fs::exists(PS4SDKLibDir)) {
- getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
- << "PS4 system libraries" << PS4SDKLibDir;
- return;
- }
- getFilePaths().push_back(PS4SDKLibDir.str());
-}
-
-Tool *PS4CPU::buildAssembler() const {
- return new tools::PS4cpu::Assemble(*this);
-}
-
-Tool *PS4CPU::buildLinker() const { return new tools::PS4cpu::Link(*this); }
-
-bool PS4CPU::isPICDefault() const { return true; }
-
-bool PS4CPU::HasNativeLLVMSupport() const { return true; }
-
-SanitizerMask PS4CPU::getSupportedSanitizers() const {
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- Res |= SanitizerKind::Address;
- Res |= SanitizerKind::Vptr;
- return Res;
-}
-
-Contiki::Contiki(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
- : Generic_ELF(D, Triple, Args) {}
-
-SanitizerMask Contiki::getSupportedSanitizers() const {
- const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
- SanitizerMask Res = ToolChain::getSupportedSanitizers();
- if (IsX86)
- Res |= SanitizerKind::SafeStack;
- return Res;
-}
-
-/// AVR Toolchain
-AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : Generic_ELF(D, Triple, Args) { }
-Tool *AVRToolChain::buildLinker() const {
- return new tools::AVR::Linker(*this);
-}
-// End AVR
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h
deleted file mode 100644
index 3240357..0000000
--- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h
+++ /dev/null
@@ -1,1388 +0,0 @@
-//===--- ToolChains.h - ToolChain Implementations ---------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H
-#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H
-
-#include "Tools.h"
-#include "clang/Basic/Cuda.h"
-#include "clang/Basic/VersionTuple.h"
-#include "clang/Driver/Action.h"
-#include "clang/Driver/Multilib.h"
-#include "clang/Driver/ToolChain.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/Support/Compiler.h"
-#include <set>
-#include <vector>
-
-namespace clang {
-namespace driver {
-
-/// A class to find a viable CUDA installation
-class CudaInstallationDetector {
-private:
- const Driver &D;
- bool IsValid = false;
- CudaVersion Version = CudaVersion::UNKNOWN;
- std::string InstallPath;
- std::string BinPath;
- std::string LibPath;
- std::string LibDevicePath;
- std::string IncludePath;
- llvm::StringMap<std::string> LibDeviceMap;
-
- // CUDA architectures for which we have raised an error in
- // CheckCudaVersionSupportsArch.
- mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors;
-
-public:
- CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple,
- const llvm::opt::ArgList &Args);
-
- void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
-
- /// \brief Emit an error if Version does not support the given Arch.
- ///
- /// If either Version or Arch is unknown, does not emit an error. Emits at
- /// most one error per Arch.
- void CheckCudaVersionSupportsArch(CudaArch Arch) const;
-
- /// \brief Check whether we detected a valid Cuda install.
- bool isValid() const { return IsValid; }
- /// \brief Print information about the detected CUDA installation.
- void print(raw_ostream &OS) const;
-
- /// \brief Get the detected Cuda install's version.
- CudaVersion version() const { return Version; }
- /// \brief Get the detected Cuda installation path.
- StringRef getInstallPath() const { return InstallPath; }
- /// \brief Get the detected path to Cuda's bin directory.
- StringRef getBinPath() const { return BinPath; }
- /// \brief Get the detected Cuda Include path.
- StringRef getIncludePath() const { return IncludePath; }
- /// \brief Get the detected Cuda library path.
- StringRef getLibPath() const { return LibPath; }
- /// \brief Get the detected Cuda device library path.
- StringRef getLibDevicePath() const { return LibDevicePath; }
- /// \brief Get libdevice file for given architecture
- std::string getLibDeviceFile(StringRef Gpu) const {
- return LibDeviceMap.lookup(Gpu);
- }
-};
-
-namespace toolchains {
-
-/// Generic_GCC - A tool chain using the 'gcc' command to perform
-/// all subcommands; this relies on gcc translating the majority of
-/// command line options.
-class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain {
-public:
- /// \brief Struct to store and manipulate GCC versions.
- ///
- /// We rely on assumptions about the form and structure of GCC version
- /// numbers: they consist of at most three '.'-separated components, and each
- /// component is a non-negative integer except for the last component. For
- /// the last component we are very flexible in order to tolerate release
- /// candidates or 'x' wildcards.
- ///
- /// Note that the ordering established among GCCVersions is based on the
- /// preferred version string to use. For example we prefer versions without
- /// a hard-coded patch number to those with a hard coded patch number.
- ///
- /// Currently this doesn't provide any logic for textual suffixes to patches
- /// in the way that (for example) Debian's version format does. If that ever
- /// becomes necessary, it can be added.
- struct GCCVersion {
- /// \brief The unparsed text of the version.
- std::string Text;
-
- /// \brief The parsed major, minor, and patch numbers.
- int Major, Minor, Patch;
-
- /// \brief The text of the parsed major, and major+minor versions.
- std::string MajorStr, MinorStr;
-
- /// \brief Any textual suffix on the patch number.
- std::string PatchSuffix;
-
- static GCCVersion Parse(StringRef VersionText);
- bool isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch,
- StringRef RHSPatchSuffix = StringRef()) const;
- bool operator<(const GCCVersion &RHS) const {
- return isOlderThan(RHS.Major, RHS.Minor, RHS.Patch, RHS.PatchSuffix);
- }
- bool operator>(const GCCVersion &RHS) const { return RHS < *this; }
- bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); }
- bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
- };
-
- /// \brief This is a class to find a viable GCC installation for Clang to
- /// use.
- ///
- /// This class tries to find a GCC installation on the system, and report
- /// information about it. It starts from the host information provided to the
- /// Driver, and has logic for fuzzing that where appropriate.
- class GCCInstallationDetector {
- bool IsValid;
- llvm::Triple GCCTriple;
- const Driver &D;
-
- // FIXME: These might be better as path objects.
- std::string GCCInstallPath;
- std::string GCCParentLibPath;
-
- /// The primary multilib appropriate for the given flags.
- Multilib SelectedMultilib;
- /// On Biarch systems, this corresponds to the default multilib when
- /// targeting the non-default multilib. Otherwise, it is empty.
- llvm::Optional<Multilib> BiarchSibling;
-
- GCCVersion Version;
-
- // We retain the list of install paths that were considered and rejected in
- // order to print out detailed information in verbose mode.
- std::set<std::string> CandidateGCCInstallPaths;
-
- /// The set of multilibs that the detected installation supports.
- MultilibSet Multilibs;
-
- public:
- explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
- void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args,
- ArrayRef<std::string> ExtraTripleAliases = None);
-
- /// \brief Check whether we detected a valid GCC install.
- bool isValid() const { return IsValid; }
-
- /// \brief Get the GCC triple for the detected install.
- const llvm::Triple &getTriple() const { return GCCTriple; }
-
- /// \brief Get the detected GCC installation path.
- StringRef getInstallPath() const { return GCCInstallPath; }
-
- /// \brief Get the detected GCC parent lib path.
- StringRef getParentLibPath() const { return GCCParentLibPath; }
-
- /// \brief Get the detected Multilib
- const Multilib &getMultilib() const { return SelectedMultilib; }
-
- /// \brief Get the whole MultilibSet
- const MultilibSet &getMultilibs() const { return Multilibs; }
-
- /// Get the biarch sibling multilib (if it exists).
- /// \return true iff such a sibling exists
- bool getBiarchSibling(Multilib &M) const;
-
- /// \brief Get the detected GCC version string.
- const GCCVersion &getVersion() const { return Version; }
-
- /// \brief Print information about the detected GCC installation.
- void print(raw_ostream &OS) const;
-
- private:
- static void
- CollectLibDirsAndTriples(const llvm::Triple &TargetTriple,
- const llvm::Triple &BiarchTriple,
- SmallVectorImpl<StringRef> &LibDirs,
- SmallVectorImpl<StringRef> &TripleAliases,
- SmallVectorImpl<StringRef> &BiarchLibDirs,
- SmallVectorImpl<StringRef> &BiarchTripleAliases);
-
- bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple,
- const llvm::opt::ArgList &Args,
- StringRef Path,
- bool NeedsBiarchSuffix = false);
-
- void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch,
- const llvm::opt::ArgList &Args,
- const std::string &LibDir,
- StringRef CandidateTriple,
- bool NeedsBiarchSuffix = false);
-
- void scanLibDirForGCCTripleSolaris(const llvm::Triple &TargetArch,
- const llvm::opt::ArgList &Args,
- const std::string &LibDir,
- StringRef CandidateTriple,
- bool NeedsBiarchSuffix = false);
-
- bool ScanGentooGccConfig(const llvm::Triple &TargetTriple,
- const llvm::opt::ArgList &Args,
- StringRef CandidateTriple,
- bool NeedsBiarchSuffix = false);
- };
-
-protected:
- GCCInstallationDetector GCCInstallation;
- CudaInstallationDetector CudaInstallation;
-
-public:
- Generic_GCC(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- ~Generic_GCC() override;
-
- void printVerboseInfo(raw_ostream &OS) const override;
-
- bool IsUnwindTablesDefault() const override;
- bool isPICDefault() const override;
- bool isPIEDefault() const override;
- bool isPICDefaultForced() const override;
- bool IsIntegratedAssemblerDefault() const override;
- llvm::opt::DerivedArgList *
- TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
- Action::OffloadKind DeviceOffloadKind) const override;
-
-protected:
- Tool *getTool(Action::ActionClass AC) const override;
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-
- /// \name ToolChain Implementation Helper Functions
- /// @{
-
- /// \brief Check whether the target triple's architecture is 64-bits.
- bool isTarget64Bit() const { return getTriple().isArch64Bit(); }
-
- /// \brief Check whether the target triple's architecture is 32-bits.
- bool isTarget32Bit() const { return getTriple().isArch32Bit(); }
-
- // FIXME: This should be final, but the Solaris tool chain does weird
- // things we can't easily represent.
- void AddClangCXXStdlibIncludeArgs(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- virtual std::string findLibCxxIncludePath() const;
- virtual void
- addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
-
- bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple,
- StringRef GCCMultiarchTriple,
- StringRef TargetMultiarchTriple,
- Twine IncludeSuffix,
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
-
- /// @}
-
-private:
- mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocess;
- mutable std::unique_ptr<tools::gcc::Compiler> Compile;
-};
-
-class LLVM_LIBRARY_VISIBILITY MachO : public ToolChain {
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
- Tool *getTool(Action::ActionClass AC) const override;
-
-private:
- mutable std::unique_ptr<tools::darwin::Lipo> Lipo;
- mutable std::unique_ptr<tools::darwin::Dsymutil> Dsymutil;
- mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug;
-
-public:
- MachO(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- ~MachO() override;
-
- /// @name MachO specific toolchain API
- /// {
-
- /// Get the "MachO" arch name for a particular compiler invocation. For
- /// example, Apple treats different ARM variations as distinct architectures.
- StringRef getMachOArchName(const llvm::opt::ArgList &Args) const;
-
- /// Add the linker arguments to link the ARC runtime library.
- virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const {}
-
- /// Add the linker arguments to link the compiler runtime library.
- virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
-
- virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const {
- }
-
- virtual void addMinVersionArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const {}
-
- /// On some iOS platforms, kernel and kernel modules were built statically. Is
- /// this such a target?
- virtual bool isKernelStatic() const { return false; }
-
- /// Is the target either iOS or an iOS simulator?
- bool isTargetIOSBased() const { return false; }
-
- void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
- StringRef DarwinLibName, bool AlwaysLink = false,
- bool IsEmbedded = false, bool AddRPath = false) const;
-
- /// Add any profiling runtime libraries that are needed. This is essentially a
- /// MachO specific version of addProfileRT in Tools.cpp.
- void addProfileRTLibs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override {
- // There aren't any profiling libs for embedded targets currently.
- }
-
- /// }
- /// @name ToolChain Implementation
- /// {
-
- types::ID LookupTypeForExtension(StringRef Ext) const override;
-
- bool HasNativeLLVMSupport() const override;
-
- llvm::opt::DerivedArgList *
- TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
- Action::OffloadKind DeviceOffloadKind) const override;
-
- bool IsBlocksDefault() const override {
- // Always allow blocks on Apple; users interested in versioning are
- // expected to use /usr/include/Block.h.
- return true;
- }
- bool IsIntegratedAssemblerDefault() const override {
- // Default integrated assembler to on for Apple's MachO targets.
- return true;
- }
-
- bool IsMathErrnoDefault() const override { return false; }
-
- bool IsEncodeExtendedBlockSignatureDefault() const override { return true; }
-
- bool IsObjCNonFragileABIDefault() const override {
- // Non-fragile ABI is default for everything but i386.
- return getTriple().getArch() != llvm::Triple::x86;
- }
-
- bool UseObjCMixedDispatch() const override { return true; }
-
- bool IsUnwindTablesDefault() const override;
-
- RuntimeLibType GetDefaultRuntimeLibType() const override {
- return ToolChain::RLT_CompilerRT;
- }
-
- bool isPICDefault() const override;
- bool isPIEDefault() const override;
- bool isPICDefaultForced() const override;
-
- bool SupportsProfiling() const override;
-
- bool SupportsObjCGC() const override { return false; }
-
- bool UseDwarfDebugFlags() const override;
-
- bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override {
- return false;
- }
-
- /// }
-};
-
-/// Darwin - The base Darwin tool chain.
-class LLVM_LIBRARY_VISIBILITY Darwin : public MachO {
-public:
- /// Whether the information on the target has been initialized.
- //
- // FIXME: This should be eliminated. What we want to do is make this part of
- // the "default target for arguments" selection process, once we get out of
- // the argument translation business.
- mutable bool TargetInitialized;
-
- enum DarwinPlatformKind {
- MacOS,
- IPhoneOS,
- IPhoneOSSimulator,
- TvOS,
- TvOSSimulator,
- WatchOS,
- WatchOSSimulator
- };
-
- mutable DarwinPlatformKind TargetPlatform;
-
- /// The OS version we are targeting.
- mutable VersionTuple TargetVersion;
-
- CudaInstallationDetector CudaInstallation;
-
-private:
- void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const;
-
-public:
- Darwin(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- ~Darwin() override;
-
- std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
- types::ID InputType) const override;
-
- /// @name Apple Specific Toolchain Implementation
- /// {
-
- void addMinVersionArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- void addStartObjectFileArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- bool isKernelStatic() const override {
- return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) &&
- !isTargetWatchOS());
- }
-
- void addProfileRTLibs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
-protected:
- /// }
- /// @name Darwin specific Toolchain functions
- /// {
-
- // FIXME: Eliminate these ...Target functions and derive separate tool chains
- // for these targets and put version in constructor.
- void setTarget(DarwinPlatformKind Platform, unsigned Major, unsigned Minor,
- unsigned Micro) const {
- // FIXME: For now, allow reinitialization as long as values don't
- // change. This will go away when we move away from argument translation.
- if (TargetInitialized && TargetPlatform == Platform &&
- TargetVersion == VersionTuple(Major, Minor, Micro))
- return;
-
- assert(!TargetInitialized && "Target already initialized!");
- TargetInitialized = true;
- TargetPlatform = Platform;
- TargetVersion = VersionTuple(Major, Minor, Micro);
- }
-
- bool isTargetIPhoneOS() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetPlatform == IPhoneOS || TargetPlatform == TvOS;
- }
-
- bool isTargetIOSSimulator() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetPlatform == IPhoneOSSimulator ||
- TargetPlatform == TvOSSimulator;
- }
-
- bool isTargetIOSBased() const {
- assert(TargetInitialized && "Target not initialized!");
- return isTargetIPhoneOS() || isTargetIOSSimulator();
- }
-
- bool isTargetTvOS() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetPlatform == TvOS;
- }
-
- bool isTargetTvOSSimulator() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetPlatform == TvOSSimulator;
- }
-
- bool isTargetTvOSBased() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetPlatform == TvOS || TargetPlatform == TvOSSimulator;
- }
-
- bool isTargetWatchOS() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetPlatform == WatchOS;
- }
-
- bool isTargetWatchOSSimulator() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetPlatform == WatchOSSimulator;
- }
-
- bool isTargetWatchOSBased() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetPlatform == WatchOS || TargetPlatform == WatchOSSimulator;
- }
-
- bool isTargetMacOS() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetPlatform == MacOS;
- }
-
- bool isTargetInitialized() const { return TargetInitialized; }
-
- VersionTuple getTargetVersion() const {
- assert(TargetInitialized && "Target not initialized!");
- return TargetVersion;
- }
-
- bool isIPhoneOSVersionLT(unsigned V0, unsigned V1 = 0,
- unsigned V2 = 0) const {
- assert(isTargetIOSBased() && "Unexpected call for non iOS target!");
- return TargetVersion < VersionTuple(V0, V1, V2);
- }
-
- bool isMacosxVersionLT(unsigned V0, unsigned V1 = 0, unsigned V2 = 0) const {
- assert(isTargetMacOS() && "Unexpected call for non OS X target!");
- return TargetVersion < VersionTuple(V0, V1, V2);
- }
-
- StringRef getPlatformFamily() const;
- static StringRef getSDKName(StringRef isysroot);
- StringRef getOSLibraryNameSuffix() const;
-
-public:
- /// }
- /// @name ToolChain Implementation
- /// {
-
- // Darwin tools support multiple architecture (e.g., i386 and x86_64) and
- // most development is done against SDKs, so compiling for a different
- // architecture should not get any special treatment.
- bool isCrossCompiling() const override { return false; }
-
- llvm::opt::DerivedArgList *
- TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
- Action::OffloadKind DeviceOffloadKind) const override;
-
- CXXStdlibType GetDefaultCXXStdlibType() const override;
- ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override;
- bool hasBlocksRuntime() const override;
-
- void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- bool UseObjCMixedDispatch() const override {
- // This is only used with the non-fragile ABI and non-legacy dispatch.
-
- // Mixed dispatch is used everywhere except OS X before 10.6.
- return !(isTargetMacOS() && isMacosxVersionLT(10, 6));
- }
-
- unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
- // Stack protectors default to on for user code on 10.5,
- // and for everything in 10.6 and beyond
- if (isTargetIOSBased() || isTargetWatchOSBased())
- return 1;
- else if (isTargetMacOS() && !isMacosxVersionLT(10, 6))
- return 1;
- else if (isTargetMacOS() && !isMacosxVersionLT(10, 5) && !KernelOrKext)
- return 1;
-
- return 0;
- }
-
- bool SupportsObjCGC() const override;
-
- void CheckObjCARC() const override;
-
- bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override;
-
- bool SupportsEmbeddedBitcode() const override;
-
- SanitizerMask getSupportedSanitizers() const override;
-
- void printVerboseInfo(raw_ostream &OS) const override;
-};
-
-/// DarwinClang - The Darwin toolchain used by Clang.
-class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
-public:
- DarwinClang(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- /// @name Apple ToolChain Implementation
- /// {
-
- RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
-
- void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- void AddCCKextLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override;
-
- void AddLinkARCArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- unsigned GetDefaultDwarfVersion() const override;
- // Until dtrace (via CTF) and LLDB can deal with distributed debug info,
- // Darwin defaults to standalone/full debug info.
- bool GetDefaultStandaloneDebug() const override { return true; }
- llvm::DebuggerKind getDefaultDebuggerTuning() const override {
- return llvm::DebuggerKind::LLDB;
- }
-
- /// }
-
-private:
- void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
- StringRef Sanitizer) const;
-};
-
-class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
- virtual void anchor();
-
-public:
- Generic_ELF(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args)
- : Generic_GCC(D, Triple, Args) {}
-
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF {
-public:
- CloudABI(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- bool HasNativeLLVMSupport() const override { return true; }
-
- bool IsMathErrnoDefault() const override { return false; }
- bool IsObjCNonFragileABIDefault() const override { return true; }
-
- CXXStdlibType
- GetCXXStdlibType(const llvm::opt::ArgList &Args) const override {
- return ToolChain::CST_Libcxx;
- }
- std::string findLibCxxIncludePath() const override;
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- bool isPIEDefault() const override;
- SanitizerMask getSupportedSanitizers() const override;
- SanitizerMask getDefaultSanitizers() const override;
-
-protected:
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
-public:
- Solaris(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- bool IsIntegratedAssemblerDefault() const override { return true; }
-
- void AddClangCXXStdlibIncludeArgs(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- unsigned GetDefaultDwarfVersion() const override { return 2; }
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain {
-public:
- MinGW(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- bool IsIntegratedAssemblerDefault() const override;
- bool IsUnwindTablesDefault() const override;
- bool isPICDefault() const override;
- bool isPIEDefault() const override;
- bool isPICDefaultForced() const override;
- bool UseSEHExceptions() const;
-
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddClangCXXStdlibIncludeArgs(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- void printVerboseInfo(raw_ostream &OS) const override;
-
-protected:
- Tool *getTool(Action::ActionClass AC) const override;
- Tool *buildLinker() const override;
- Tool *buildAssembler() const override;
-
-private:
- CudaInstallationDetector CudaInstallation;
-
- std::string Base;
- std::string GccLibDir;
- std::string Ver;
- std::string Arch;
- mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor;
- mutable std::unique_ptr<tools::gcc::Compiler> Compiler;
- void findGccLibDir();
-};
-
-class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF {
-public:
- Haiku(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- bool isPIEDefault() const override {
- return getTriple().getArch() == llvm::Triple::x86_64;
- }
-
- std::string findLibCxxIncludePath() const override;
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF {
-public:
- OpenBSD(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- bool IsMathErrnoDefault() const override { return false; }
- bool IsObjCNonFragileABIDefault() const override { return true; }
- bool isPIEDefault() const override { return true; }
-
- unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
- return 2;
- }
- unsigned GetDefaultDwarfVersion() const override { return 2; }
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF {
-public:
- Bitrig(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- bool IsMathErrnoDefault() const override { return false; }
- bool IsObjCNonFragileABIDefault() const override { return true; }
-
- CXXStdlibType GetDefaultCXXStdlibType() const override;
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
- unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
- return 1;
- }
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF {
-public:
- FreeBSD(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- bool HasNativeLLVMSupport() const override;
-
- bool IsMathErrnoDefault() const override { return false; }
- bool IsObjCNonFragileABIDefault() const override { return true; }
-
- CXXStdlibType GetDefaultCXXStdlibType() const override;
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override;
- bool isPIEDefault() const override;
- SanitizerMask getSupportedSanitizers() const override;
- unsigned GetDefaultDwarfVersion() const override { return 2; }
- // Until dtrace (via CTF) and LLDB can deal with distributed debug info,
- // FreeBSD defaults to standalone/full debug info.
- bool GetDefaultStandaloneDebug() const override { return true; }
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
-public:
- NetBSD(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- bool IsMathErrnoDefault() const override { return false; }
- bool IsObjCNonFragileABIDefault() const override { return true; }
-
- CXXStdlibType GetDefaultCXXStdlibType() const override;
-
- std::string findLibCxxIncludePath() const override;
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- bool IsUnwindTablesDefault() const override { return true; }
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF {
-public:
- Minix(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF {
-public:
- DragonFly(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- bool IsMathErrnoDefault() const override { return false; }
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {
-public:
- Linux(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- bool HasNativeLLVMSupport() const override;
-
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- std::string findLibCxxIncludePath() const override;
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- bool isPIEDefault() const override;
- SanitizerMask getSupportedSanitizers() const override;
- void addProfileRTLibs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
- virtual std::string computeSysRoot() const;
-
- virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const;
-
- std::vector<std::string> ExtraOpts;
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain {
-public:
- CudaToolChain(const Driver &D, const llvm::Triple &Triple,
- const ToolChain &HostTC, const llvm::opt::ArgList &Args);
-
- virtual const llvm::Triple *getAuxTriple() const override {
- return &HostTC.getTriple();
- }
-
- llvm::opt::DerivedArgList *
- TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
- Action::OffloadKind DeviceOffloadKind) const override;
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- // Never try to use the integrated assembler with CUDA; always fork out to
- // ptxas.
- bool useIntegratedAs() const override { return false; }
- bool isCrossCompiling() const override { return true; }
- bool isPICDefault() const override { return false; }
- bool isPIEDefault() const override { return false; }
- bool isPICDefaultForced() const override { return false; }
- bool SupportsProfiling() const override { return false; }
- bool SupportsObjCGC() const override { return false; }
-
- void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override;
- CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddClangCXXStdlibIncludeArgs(
- const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- SanitizerMask getSupportedSanitizers() const override;
-
- VersionTuple
- computeMSVCVersion(const Driver *D,
- const llvm::opt::ArgList &Args) const override;
-
- const ToolChain &HostTC;
- CudaInstallationDetector CudaInstallation;
-
-protected:
- Tool *buildAssembler() const override; // ptxas
- Tool *buildLinker() const override; // fatbinary (ok, not really a linker)
-};
-
-class LLVM_LIBRARY_VISIBILITY MipsLLVMToolChain : public Linux {
-protected:
- Tool *buildLinker() const override;
-
-public:
- MipsLLVMToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
-
- std::string findLibCxxIncludePath() const override;
-
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
- bool Shared = false) const override;
-
- std::string computeSysRoot() const override;
-
- RuntimeLibType GetDefaultRuntimeLibType() const override {
- return GCCInstallation.isValid() ? RuntimeLibType::RLT_Libgcc
- : RuntimeLibType::RLT_CompilerRT;
- }
-
- const char *getDefaultLinker() const override {
- return "lld";
- }
-
-private:
- Multilib SelectedMultilib;
- std::string LibSuffix;
-};
-
-class LLVM_LIBRARY_VISIBILITY LanaiToolChain : public Generic_ELF {
-public:
- LanaiToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args)
- : Generic_ELF(D, Triple, Args) {}
-
- // No support for finding a C++ standard library yet.
- std::string findLibCxxIncludePath() const override { return ""; }
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override {}
-
- bool IsIntegratedAssemblerDefault() const override { return true; }
-};
-
-class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux {
-protected:
- GCCVersion GCCLibAndIncVersion;
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-
-public:
- HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- ~HexagonToolChain() override;
-
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
-
- StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; }
- bool IsIntegratedAssemblerDefault() const override {
- return true;
- }
-
- std::string getHexagonTargetDir(
- const std::string &InstalledDir,
- const SmallVectorImpl<std::string> &PrefixDirs) const;
- void getHexagonLibraryPaths(const llvm::opt::ArgList &Args,
- ToolChain::path_list &LibPaths) const;
-
- static const StringRef GetDefaultCPU();
- static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args);
-
- static Optional<unsigned> getSmallDataThreshold(
- const llvm::opt::ArgList &Args);
-};
-
-class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF {
-protected:
- Tool *buildLinker() const override;
-
-public:
- AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- unsigned GetDefaultDwarfVersion() const override { return 2; }
- bool IsIntegratedAssemblerDefault() const override { return true; }
-};
-
-class LLVM_LIBRARY_VISIBILITY NaClToolChain : public Generic_ELF {
-public:
- NaClToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- std::string findLibCxxIncludePath() const override;
-
- CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
-
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- bool IsIntegratedAssemblerDefault() const override {
- return getTriple().getArch() == llvm::Triple::mipsel;
- }
-
- // Get the path to the file containing NaCl's ARM macros.
- // It lives in NaClToolChain because the ARMAssembler tool needs a
- // const char * that it can pass around,
- const char *GetNaClArmMacrosPath() const { return NaClArmMacrosPath.c_str(); }
-
- std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
- types::ID InputType) const override;
-
-protected:
- Tool *buildLinker() const override;
- Tool *buildAssembler() const override;
-
-private:
- std::string NaClArmMacrosPath;
-};
-
-class LLVM_LIBRARY_VISIBILITY Fuchsia : public Generic_ELF {
-public:
- Fuchsia(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- bool isPIEDefault() const override { return true; }
- bool HasNativeLLVMSupport() const override { return true; }
- bool IsIntegratedAssemblerDefault() const override { return true; }
- llvm::DebuggerKind getDefaultDebuggerTuning() const override {
- return llvm::DebuggerKind::GDB;
- }
-
- RuntimeLibType
- GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
- CXXStdlibType
- GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
-
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- std::string findLibCxxIncludePath() const override;
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- const char *getDefaultLinker() const override {
- return "lld";
- }
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
-/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
-class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain {
-public:
- TCEToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- ~TCEToolChain() override;
-
- bool IsMathErrnoDefault() const override;
- bool isPICDefault() const override;
- bool isPIEDefault() const override;
- bool isPICDefaultForced() const override;
-};
-
-/// Toolchain for little endian TCE cores.
-class LLVM_LIBRARY_VISIBILITY TCELEToolChain : public TCEToolChain {
-public:
- TCELEToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- ~TCELEToolChain() override;
-};
-
-class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
-public:
- MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- llvm::opt::DerivedArgList *
- TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
- Action::OffloadKind DeviceOffloadKind) const override;
-
- bool IsIntegratedAssemblerDefault() const override;
- bool IsUnwindTablesDefault() const override;
- bool isPICDefault() const override;
- bool isPIEDefault() const override;
- bool isPICDefaultForced() const override;
-
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddClangCXXStdlibIncludeArgs(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- bool getWindowsSDKDir(std::string &path, int &major,
- std::string &windowsSDKIncludeVersion,
- std::string &windowsSDKLibVersion) const;
- bool getWindowsSDKLibraryPath(std::string &path) const;
- /// \brief Check if Universal CRT should be used if available
- bool useUniversalCRT(std::string &visualStudioDir) const;
- bool getUniversalCRTSdkDir(std::string &path, std::string &ucrtVersion) const;
- bool getUniversalCRTLibraryPath(std::string &path) const;
- bool getVisualStudioInstallDir(std::string &path) const;
- bool getVisualStudioBinariesFolder(const char *clangProgramPath,
- std::string &path) const;
- VersionTuple
- computeMSVCVersion(const Driver *D,
- const llvm::opt::ArgList &Args) const override;
-
- std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
- types::ID InputType) const override;
- SanitizerMask getSupportedSanitizers() const override;
-
- void printVerboseInfo(raw_ostream &OS) const override;
-
-protected:
- void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- const std::string &folder,
- const Twine &subfolder1,
- const Twine &subfolder2 = "",
- const Twine &subfolder3 = "") const;
-
- Tool *buildLinker() const override;
- Tool *buildAssembler() const override;
-private:
- VersionTuple getMSVCVersionFromTriple() const;
- VersionTuple getMSVCVersionFromExe() const;
-
- CudaInstallationDetector CudaInstallation;
-};
-
-class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC {
-public:
- CrossWindowsToolChain(const Driver &D, const llvm::Triple &T,
- const llvm::opt::ArgList &Args);
-
- bool IsIntegratedAssemblerDefault() const override { return true; }
- bool IsUnwindTablesDefault() const override;
- bool isPICDefault() const override;
- bool isPIEDefault() const override;
- bool isPICDefaultForced() const override;
-
- unsigned int GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
- return 0;
- }
-
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddClangCXXStdlibIncludeArgs(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-
- SanitizerMask getSupportedSanitizers() const override;
-
-protected:
- Tool *buildLinker() const override;
- Tool *buildAssembler() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY XCoreToolChain : public ToolChain {
-public:
- XCoreToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-
-public:
- bool isPICDefault() const override;
- bool isPIEDefault() const override;
- bool isPICDefaultForced() const override;
- bool SupportsProfiling() const override;
- bool hasBlocksRuntime() const override;
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddClangCXXStdlibIncludeArgs(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const override;
-};
-
-/// MyriadToolChain - A tool chain using either clang or the external compiler
-/// installed by the Movidius SDK to perform all subcommands.
-class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_ELF {
-public:
- MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- ~MyriadToolChain() override;
-
- void
- AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- std::string findLibCxxIncludePath() const override;
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- Tool *SelectTool(const JobAction &JA) const override;
- unsigned GetDefaultDwarfVersion() const override { return 2; }
- SanitizerMask getSupportedSanitizers() const override;
-
-protected:
- Tool *buildLinker() const override;
- bool isShaveCompilation(const llvm::Triple &T) const {
- return T.getArch() == llvm::Triple::shave;
- }
-
-private:
- mutable std::unique_ptr<Tool> Compiler;
- mutable std::unique_ptr<Tool> Assembler;
-};
-
-class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain {
-public:
- WebAssembly(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
-private:
- bool IsMathErrnoDefault() const override;
- bool IsObjCNonFragileABIDefault() const override;
- bool UseObjCMixedDispatch() const override;
- bool isPICDefault() const override;
- bool isPIEDefault() const override;
- bool isPICDefaultForced() const override;
- bool IsIntegratedAssemblerDefault() const override;
- bool hasBlocksRuntime() const override;
- bool SupportsObjCGC() const override;
- bool SupportsProfiling() const override;
- bool HasNativeLLVMSupport() const override;
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- RuntimeLibType GetDefaultRuntimeLibType() const override;
- CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
- void AddClangSystemIncludeArgs(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void AddClangCXXStdlibIncludeArgs(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
- const char *getDefaultLinker() const override {
- return "lld";
- }
-
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF {
-public:
- PS4CPU(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- // No support for finding a C++ standard library yet.
- std::string findLibCxxIncludePath() const override { return ""; }
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override {}
-
- bool IsMathErrnoDefault() const override { return false; }
- bool IsObjCNonFragileABIDefault() const override { return true; }
- bool HasNativeLLVMSupport() const override;
- bool isPICDefault() const override;
-
- unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
- return 2; // SSPStrong
- }
-
- llvm::DebuggerKind getDefaultDebuggerTuning() const override {
- return llvm::DebuggerKind::SCE;
- }
-
- SanitizerMask getSupportedSanitizers() const override;
-
-protected:
- Tool *buildAssembler() const override;
- Tool *buildLinker() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Contiki : public Generic_ELF {
-public:
- Contiki(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
-
- // No support for finding a C++ standard library yet.
- std::string findLibCxxIncludePath() const override { return ""; }
- void addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override {}
-
- SanitizerMask getSupportedSanitizers() const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY AVRToolChain : public Generic_ELF {
-protected:
- Tool *buildLinker() const override;
-public:
- AVRToolChain(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args);
- bool IsIntegratedAssemblerDefault() const override { return true; }
-};
-
-
-} // end namespace toolchains
-} // end namespace driver
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.cpp
new file mode 100644
index 0000000..63e1749
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -0,0 +1,45 @@
+//===--- AMDGPU.cpp - AMDGPU ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPU.h"
+#include "InputInfo.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+
+ std::string Linker = getToolChain().GetProgramPath(getShortName());
+ ArgStringList CmdArgs;
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+ CmdArgs.push_back("-shared");
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
+ CmdArgs, Inputs));
+}
+
+/// AMDGPU Toolchain
+AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) { }
+
+Tool *AMDGPUToolChain::buildLinker() const {
+ return new tools::amdgpu::Linker(*this);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.h
new file mode 100644
index 0000000..9af1e96
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AMDGPU.h
@@ -0,0 +1,54 @@
+//===--- AMDGPU.h - AMDGPU ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+namespace amdgpu {
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "ld.lld", TC) {}
+ bool isLinkJob() const override { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+} // end namespace amdgpu
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF {
+protected:
+ Tool *buildLinker() const override;
+
+public:
+ AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ unsigned GetDefaultDwarfVersion() const override { return 2; }
+ bool IsIntegratedAssemblerDefault() const override { return true; }
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/AVR.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AVR.cpp
new file mode 100644
index 0000000..877009a
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AVR.cpp
@@ -0,0 +1,44 @@
+//===--- AVR.cpp - AVR ToolChain Implementations ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AVR.h"
+#include "CommonArgs.h"
+#include "InputInfo.h"
+#include "clang/Driver/Compilation.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+/// AVR Toolchain
+AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) { }
+Tool *AVRToolChain::buildLinker() const {
+ return new tools::AVR::Linker(*this);
+}
+
+void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+
+ std::string Linker = getToolChain().GetProgramPath(getShortName());
+ ArgStringList CmdArgs;
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
+ CmdArgs, Inputs));
+}
+// AVR tools end.
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/AVR.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AVR.h
new file mode 100644
index 0000000..a7479a7
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/AVR.h
@@ -0,0 +1,49 @@
+//===--- AVR.h - AVR Tool and ToolChain Implementations ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H
+
+#include "Gnu.h"
+#include "InputInfo.h"
+#include "clang/Driver/ToolChain.h"
+#include "clang/Driver/Tool.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY AVRToolChain : public Generic_ELF {
+protected:
+ Tool *buildLinker() const override;
+public:
+ AVRToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+};
+
+} // end namespace toolchains
+
+namespace tools {
+namespace AVR {
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("AVR::Linker", "avr-ld", TC) {}
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace AVR
+} // end namespace tools
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp
new file mode 100644
index 0000000..a67e1d2
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp
@@ -0,0 +1,120 @@
+//===--- Ananas.cpp - Ananas ToolChain Implementations ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Ananas.h"
+#include "InputInfo.h"
+#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const ToolChain &ToolChain = getToolChain();
+ const Driver &D = ToolChain.getDriver();
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ // Ananas only supports static linkage for now.
+ CmdArgs.push_back("-Bstatic");
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+ Args.AddAllArgs(CmdArgs,
+ {options::OPT_T_Group, options::OPT_e, options::OPT_s,
+ options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
+
+ if (D.isUsingLTO())
+ AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX())
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lc");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+ }
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+// Ananas - Ananas tool chain which can call as(1) and ld(1) directly.
+
+Ananas::Ananas(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
+}
+
+Tool *Ananas::buildAssembler() const {
+ return new tools::ananas::Assembler(*this);
+}
+
+Tool *Ananas::buildLinker() const { return new tools::ananas::Linker(*this); }
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.h
new file mode 100644
index 0000000..2563dd2
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.h
@@ -0,0 +1,67 @@
+//===--- Ananas.h - Ananas ToolChain Implementations --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// ananas -- Directly call GNU Binutils assembler and linker
+namespace ananas {
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
+public:
+ Assembler(const ToolChain &TC)
+ : GnuTool("ananas::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("ananas::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace ananas
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Ananas : public Generic_ELF {
+public:
+ Ananas(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
new file mode 100644
index 0000000..554d051
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -0,0 +1,199 @@
+//===--- AArch64.cpp - AArch64 (not ARM) Helpers for Tools ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AArch64.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/TargetParser.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are
+/// targeting. Set \p A to the Arg corresponding to the -mcpu or -mtune
+/// arguments if they are provided, or to nullptr otherwise.
+std::string aarch64::getAArch64TargetCPU(const ArgList &Args, Arg *&A) {
+ std::string CPU;
+ // If we have -mtune or -mcpu, use that.
+ if ((A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) {
+ CPU = StringRef(A->getValue()).lower();
+ } else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) {
+ StringRef Mcpu = A->getValue();
+ CPU = Mcpu.split("+").first.lower();
+ }
+
+ // Handle CPU name is 'native'.
+ if (CPU == "native")
+ return llvm::sys::getHostCPUName();
+ else if (CPU.size())
+ return CPU;
+
+ // Make sure we pick "cyclone" if -arch is used.
+ // FIXME: Should this be picked by checking the target triple instead?
+ if (Args.getLastArg(options::OPT_arch))
+ return "cyclone";
+
+ return "generic";
+}
+
+// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
+static bool DecodeAArch64Features(const Driver &D, StringRef text,
+ std::vector<StringRef> &Features) {
+ SmallVector<StringRef, 8> Split;
+ text.split(Split, StringRef("+"), -1, false);
+
+ for (StringRef Feature : Split) {
+ StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
+ if (!FeatureName.empty())
+ Features.push_back(FeatureName);
+ else if (Feature == "neon" || Feature == "noneon")
+ D.Diag(clang::diag::err_drv_no_neon_modifier);
+ else
+ return false;
+ }
+ return true;
+}
+
+// Check if the CPU name and feature modifiers in -mcpu are legal. If yes,
+// decode CPU and feature.
+static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
+ std::vector<StringRef> &Features) {
+ std::pair<StringRef, StringRef> Split = Mcpu.split("+");
+ CPU = Split.first;
+
+ if (CPU == "generic") {
+ Features.push_back("+neon");
+ } else {
+ unsigned ArchKind = llvm::AArch64::parseCPUArch(CPU);
+ if (!llvm::AArch64::getArchFeatures(ArchKind, Features))
+ return false;
+
+ unsigned Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind);
+ if (!llvm::AArch64::getExtensionFeatures(Extension, Features))
+ return false;
+ }
+
+ if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))
+ return false;
+
+ return true;
+}
+
+static bool
+getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ std::string MarchLowerCase = March.lower();
+ std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
+
+ unsigned ArchKind = llvm::AArch64::parseArch(Split.first);
+ if (ArchKind == static_cast<unsigned>(llvm::AArch64::ArchKind::AK_INVALID) ||
+ !llvm::AArch64::getArchFeatures(ArchKind, Features) ||
+ (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)))
+ return false;
+
+ return true;
+}
+
+static bool
+getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ StringRef CPU;
+ std::string McpuLowerCase = Mcpu.lower();
+ if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features))
+ return false;
+
+ return true;
+}
+
+static bool
+getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ std::string MtuneLowerCase = Mtune.lower();
+ // Handle CPU name is 'native'.
+ if (MtuneLowerCase == "native")
+ MtuneLowerCase = llvm::sys::getHostCPUName();
+ if (MtuneLowerCase == "cyclone") {
+ Features.push_back("+zcm");
+ Features.push_back("+zcz");
+ }
+ return true;
+}
+
+static bool
+getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ StringRef CPU;
+ std::vector<StringRef> DecodedFeature;
+ std::string McpuLowerCase = Mcpu.lower();
+ if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature))
+ return false;
+
+ return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
+}
+
+void aarch64::getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ Arg *A;
+ bool success = true;
+ // Enable NEON by default.
+ Features.push_back("+neon");
+ if ((A = Args.getLastArg(options::OPT_march_EQ)))
+ success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features);
+ else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
+ success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
+ else if (Args.hasArg(options::OPT_arch))
+ success = getAArch64ArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args, A),
+ Args, Features);
+
+ if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)))
+ success =
+ getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features);
+ else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
+ success =
+ getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
+ else if (success && Args.hasArg(options::OPT_arch))
+ success = getAArch64MicroArchFeaturesFromMcpu(
+ D, getAArch64TargetCPU(Args, A), Args, Features);
+
+ if (!success)
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+
+ if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
+ Features.push_back("-fp-armv8");
+ Features.push_back("-crypto");
+ Features.push_back("-neon");
+ }
+
+ // En/disable crc
+ if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
+ if (A->getOption().matches(options::OPT_mcrc))
+ Features.push_back("+crc");
+ else
+ Features.push_back("-crc");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
+ options::OPT_munaligned_access))
+ if (A->getOption().matches(options::OPT_mno_unaligned_access))
+ Features.push_back("+strict-align");
+
+ if (Args.hasArg(options::OPT_ffixed_x18))
+ Features.push_back("+reserve-x18");
+
+ if (Args.hasArg(options::OPT_mno_neg_immediates))
+ Features.push_back("+no-neg-immediates");
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.h
new file mode 100644
index 0000000..62e419c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/AArch64.h
@@ -0,0 +1,35 @@
+//===--- AArch64.h - AArch64-specific (not ARM) Tool Helpers ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_AARCH64_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_AARCH64_H
+
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Option.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace aarch64 {
+
+void getAArch64TargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
+ std::vector<llvm::StringRef> &Features);
+
+std::string getAArch64TargetCPU(const llvm::opt::ArgList &Args,
+ llvm::opt::Arg *&A);
+
+} // end namespace aarch64
+} // end namespace target
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_AARCH64_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp
new file mode 100644
index 0000000..95b86f7
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -0,0 +1,557 @@
+//===--- ARM.cpp - ARM (not AArch64) Helpers for Tools ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARM.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/TargetParser.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+// Get SubArch (vN).
+int arm::getARMSubArchVersionNumber(const llvm::Triple &Triple) {
+ llvm::StringRef Arch = Triple.getArchName();
+ return llvm::ARM::parseArchVersion(Arch);
+}
+
+// True if M-profile.
+bool arm::isARMMProfile(const llvm::Triple &Triple) {
+ llvm::StringRef Arch = Triple.getArchName();
+ unsigned Profile = llvm::ARM::parseArchProfile(Arch);
+ return Profile == llvm::ARM::PK_M;
+}
+
+// Get Arch/CPU from args.
+void arm::getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch,
+ llvm::StringRef &CPU, bool FromAs) {
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ))
+ CPU = A->getValue();
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ Arch = A->getValue();
+ if (!FromAs)
+ return;
+
+ for (const Arg *A :
+ Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
+ StringRef Value = A->getValue();
+ if (Value.startswith("-mcpu="))
+ CPU = Value.substr(6);
+ if (Value.startswith("-march="))
+ Arch = Value.substr(7);
+ }
+}
+
+// Handle -mhwdiv=.
+// FIXME: Use ARMTargetParser.
+static void getARMHWDivFeatures(const Driver &D, const Arg *A,
+ const ArgList &Args, StringRef HWDiv,
+ std::vector<StringRef> &Features) {
+ unsigned HWDivID = llvm::ARM::parseHWDiv(HWDiv);
+ if (!llvm::ARM::getHWDivFeatures(HWDivID, Features))
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+}
+
+// Handle -mfpu=.
+static void getARMFPUFeatures(const Driver &D, const Arg *A,
+ const ArgList &Args, StringRef FPU,
+ std::vector<StringRef> &Features) {
+ unsigned FPUID = llvm::ARM::parseFPU(FPU);
+ if (!llvm::ARM::getFPUFeatures(FPUID, Features))
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+}
+
+// Decode ARM features from string like +[no]featureA+[no]featureB+...
+static bool DecodeARMFeatures(const Driver &D, StringRef text,
+ std::vector<StringRef> &Features) {
+ SmallVector<StringRef, 8> Split;
+ text.split(Split, StringRef("+"), -1, false);
+
+ for (StringRef Feature : Split) {
+ StringRef FeatureName = llvm::ARM::getArchExtFeature(Feature);
+ if (!FeatureName.empty())
+ Features.push_back(FeatureName);
+ else
+ return false;
+ }
+ return true;
+}
+
+// Check if -march is valid by checking if it can be canonicalised and parsed.
+// getARMArch is used here instead of just checking the -march value in order
+// to handle -march=native correctly.
+static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args,
+ llvm::StringRef ArchName,
+ std::vector<StringRef> &Features,
+ const llvm::Triple &Triple) {
+ std::pair<StringRef, StringRef> Split = ArchName.split("+");
+
+ std::string MArch = arm::getARMArch(ArchName, Triple);
+ if (llvm::ARM::parseArch(MArch) == llvm::ARM::AK_INVALID ||
+ (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+}
+
+// Check -mcpu=. Needs ArchName to handle -mcpu=generic.
+static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args,
+ llvm::StringRef CPUName, llvm::StringRef ArchName,
+ std::vector<StringRef> &Features,
+ const llvm::Triple &Triple) {
+ std::pair<StringRef, StringRef> Split = CPUName.split("+");
+
+ std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
+ if (arm::getLLVMArchSuffixForARM(CPU, ArchName, Triple).empty() ||
+ (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+}
+
+bool arm::useAAPCSForMachO(const llvm::Triple &T) {
+ // The backend is hardwired to assume AAPCS for M-class processors, ensure
+ // the frontend matches that.
+ return T.getEnvironment() == llvm::Triple::EABI ||
+ T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T);
+}
+
+// Select the float ABI as determined by -msoft-float, -mhard-float, and
+// -mfloat-abi=.
+arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) {
+ const Driver &D = TC.getDriver();
+ const llvm::Triple &Triple = TC.getEffectiveTriple();
+ auto SubArch = getARMSubArchVersionNumber(Triple);
+ arm::FloatABI ABI = FloatABI::Invalid;
+ if (Arg *A =
+ Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ)) {
+ if (A->getOption().matches(options::OPT_msoft_float)) {
+ ABI = FloatABI::Soft;
+ } else if (A->getOption().matches(options::OPT_mhard_float)) {
+ ABI = FloatABI::Hard;
+ } else {
+ ABI = llvm::StringSwitch<arm::FloatABI>(A->getValue())
+ .Case("soft", FloatABI::Soft)
+ .Case("softfp", FloatABI::SoftFP)
+ .Case("hard", FloatABI::Hard)
+ .Default(FloatABI::Invalid);
+ if (ABI == FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
+ D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
+ ABI = FloatABI::Soft;
+ }
+ }
+
+ // It is incorrect to select hard float ABI on MachO platforms if the ABI is
+ // "apcs-gnu".
+ if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(Triple) &&
+ ABI == FloatABI::Hard) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args)
+ << Triple.getArchName();
+ }
+ }
+
+ // If unspecified, choose the default based on the platform.
+ if (ABI == FloatABI::Invalid) {
+ switch (Triple.getOS()) {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ case llvm::Triple::TvOS: {
+ // Darwin defaults to "softfp" for v6 and v7.
+ ABI = (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft;
+ ABI = Triple.isWatchABI() ? FloatABI::Hard : ABI;
+ break;
+ }
+ case llvm::Triple::WatchOS:
+ ABI = FloatABI::Hard;
+ break;
+
+ // FIXME: this is invalid for WindowsCE
+ case llvm::Triple::Win32:
+ ABI = FloatABI::Hard;
+ break;
+
+ case llvm::Triple::NetBSD:
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ ABI = FloatABI::Hard;
+ break;
+ default:
+ ABI = FloatABI::Soft;
+ break;
+ }
+ break;
+
+ case llvm::Triple::FreeBSD:
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::GNUEABIHF:
+ ABI = FloatABI::Hard;
+ break;
+ default:
+ // FreeBSD defaults to soft float
+ ABI = FloatABI::Soft;
+ break;
+ }
+ break;
+
+ case llvm::Triple::OpenBSD:
+ ABI = FloatABI::Soft;
+ break;
+
+ default:
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::GNUEABIHF:
+ case llvm::Triple::MuslEABIHF:
+ case llvm::Triple::EABIHF:
+ ABI = FloatABI::Hard;
+ break;
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::MuslEABI:
+ case llvm::Triple::EABI:
+ // EABI is always AAPCS, and if it was not marked 'hard', it's softfp
+ ABI = FloatABI::SoftFP;
+ break;
+ case llvm::Triple::Android:
+ ABI = (SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft;
+ break;
+ default:
+ // Assume "soft", but warn the user we are guessing.
+ if (Triple.isOSBinFormatMachO() &&
+ Triple.getSubArch() == llvm::Triple::ARMSubArch_v7em)
+ ABI = FloatABI::Hard;
+ else
+ ABI = FloatABI::Soft;
+
+ if (Triple.getOS() != llvm::Triple::UnknownOS ||
+ !Triple.isOSBinFormatMachO())
+ D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
+ break;
+ }
+ }
+ }
+
+ assert(ABI != FloatABI::Invalid && "must select an ABI");
+ return ABI;
+}
+
+void arm::getARMTargetFeatures(const ToolChain &TC,
+ const llvm::Triple &Triple,
+ const ArgList &Args,
+ ArgStringList &CmdArgs,
+ std::vector<StringRef> &Features,
+ bool ForAS) {
+ const Driver &D = TC.getDriver();
+
+ bool KernelOrKext =
+ Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
+ arm::FloatABI ABI = arm::getARMFloatABI(TC, Args);
+ const Arg *WaCPU = nullptr, *WaFPU = nullptr;
+ const Arg *WaHDiv = nullptr, *WaArch = nullptr;
+
+ if (!ForAS) {
+ // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
+ // yet (it uses the -mfloat-abi and -msoft-float options), and it is
+ // stripped out by the ARM target. We should probably pass this a new
+ // -target-option, which is handled by the -cc1/-cc1as invocation.
+ //
+ // FIXME2: For consistency, it would be ideal if we set up the target
+ // machine state the same when using the frontend or the assembler. We don't
+ // currently do that for the assembler, we pass the options directly to the
+ // backend and never even instantiate the frontend TargetInfo. If we did,
+ // and used its handleTargetFeatures hook, then we could ensure the
+ // assembler and the frontend behave the same.
+
+ // Use software floating point operations?
+ if (ABI == arm::FloatABI::Soft)
+ Features.push_back("+soft-float");
+
+ // Use software floating point argument passing?
+ if (ABI != arm::FloatABI::Hard)
+ Features.push_back("+soft-float-abi");
+ } else {
+ // Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down
+ // to the assembler correctly.
+ for (const Arg *A :
+ Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
+ StringRef Value = A->getValue();
+ if (Value.startswith("-mfpu=")) {
+ WaFPU = A;
+ } else if (Value.startswith("-mcpu=")) {
+ WaCPU = A;
+ } else if (Value.startswith("-mhwdiv=")) {
+ WaHDiv = A;
+ } else if (Value.startswith("-march=")) {
+ WaArch = A;
+ }
+ }
+ }
+
+ // Check -march. ClangAs gives preference to -Wa,-march=.
+ const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ);
+ StringRef ArchName;
+ if (WaArch) {
+ if (ArchArg)
+ D.Diag(clang::diag::warn_drv_unused_argument)
+ << ArchArg->getAsString(Args);
+ ArchName = StringRef(WaArch->getValue()).substr(7);
+ checkARMArchName(D, WaArch, Args, ArchName, Features, Triple);
+ // FIXME: Set Arch.
+ D.Diag(clang::diag::warn_drv_unused_argument) << WaArch->getAsString(Args);
+ } else if (ArchArg) {
+ ArchName = ArchArg->getValue();
+ checkARMArchName(D, ArchArg, Args, ArchName, Features, Triple);
+ }
+
+ // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=.
+ const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ);
+ StringRef CPUName;
+ if (WaCPU) {
+ if (CPUArg)
+ D.Diag(clang::diag::warn_drv_unused_argument)
+ << CPUArg->getAsString(Args);
+ CPUName = StringRef(WaCPU->getValue()).substr(6);
+ checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Features, Triple);
+ } else if (CPUArg) {
+ CPUName = CPUArg->getValue();
+ checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Features, Triple);
+ }
+
+ // Add CPU features for generic CPUs
+ if (CPUName == "native") {
+ llvm::StringMap<bool> HostFeatures;
+ if (llvm::sys::getHostCPUFeatures(HostFeatures))
+ for (auto &F : HostFeatures)
+ Features.push_back(
+ Args.MakeArgString((F.second ? "+" : "-") + F.first()));
+ }
+
+ // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
+ const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
+ if (WaFPU) {
+ if (FPUArg)
+ D.Diag(clang::diag::warn_drv_unused_argument)
+ << FPUArg->getAsString(Args);
+ getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6),
+ Features);
+ } else if (FPUArg) {
+ getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
+ }
+
+ // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=.
+ const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ);
+ if (WaHDiv) {
+ if (HDivArg)
+ D.Diag(clang::diag::warn_drv_unused_argument)
+ << HDivArg->getAsString(Args);
+ getARMHWDivFeatures(D, WaHDiv, Args,
+ StringRef(WaHDiv->getValue()).substr(8), Features);
+ } else if (HDivArg)
+ getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features);
+
+ // Setting -msoft-float effectively disables NEON because of the GCC
+ // implementation, although the same isn't true of VFP or VFP3.
+ if (ABI == arm::FloatABI::Soft) {
+ Features.push_back("-neon");
+ // Also need to explicitly disable features which imply NEON.
+ Features.push_back("-crypto");
+ }
+
+ // En/disable crc code generation.
+ if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
+ if (A->getOption().matches(options::OPT_mcrc))
+ Features.push_back("+crc");
+ else
+ Features.push_back("-crc");
+ }
+
+ // Look for the last occurrence of -mlong-calls or -mno-long-calls. If
+ // neither options are specified, see if we are compiling for kernel/kext and
+ // decide whether to pass "+long-calls" based on the OS and its version.
+ if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
+ options::OPT_mno_long_calls)) {
+ if (A->getOption().matches(options::OPT_mlong_calls))
+ Features.push_back("+long-calls");
+ } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) &&
+ !Triple.isWatchOS()) {
+ Features.push_back("+long-calls");
+ }
+
+ // Generate execute-only output (no data access to code sections).
+ // This only makes sense for the compiler, not for the assembler.
+ if (!ForAS) {
+ // Supported only on ARMv6T2 and ARMv7 and above.
+ // Cannot be combined with -mno-movt or -mlong-calls
+ if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) {
+ if (A->getOption().matches(options::OPT_mexecute_only)) {
+ if (getARMSubArchVersionNumber(Triple) < 7 &&
+ llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::AK_ARMV6T2)
+ D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName();
+ else if (Arg *B = Args.getLastArg(options::OPT_mno_movt))
+ D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
+ // Long calls create constant pool entries and have not yet been fixed up
+ // to play nicely with execute-only. Hence, they cannot be used in
+ // execute-only code for now
+ else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) {
+ if (B->getOption().matches(options::OPT_mlong_calls))
+ D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
+ }
+ Features.push_back("+execute-only");
+ }
+ }
+ }
+
+ // Kernel code has more strict alignment requirements.
+ if (KernelOrKext)
+ Features.push_back("+strict-align");
+ else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
+ options::OPT_munaligned_access)) {
+ if (A->getOption().matches(options::OPT_munaligned_access)) {
+ // No v6M core supports unaligned memory access (v6M ARM ARM A3.2).
+ if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
+ D.Diag(diag::err_target_unsupported_unaligned) << "v6m";
+ // v8M Baseline follows on from v6M, so doesn't support unaligned memory
+ // access either.
+ else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline)
+ D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base";
+ } else
+ Features.push_back("+strict-align");
+ } else {
+ // Assume pre-ARMv6 doesn't support unaligned accesses.
+ //
+ // ARMv6 may or may not support unaligned accesses depending on the
+ // SCTLR.U bit, which is architecture-specific. We assume ARMv6
+ // Darwin and NetBSD targets support unaligned accesses, and others don't.
+ //
+ // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit
+ // which raises an alignment fault on unaligned accesses. Linux
+ // defaults this bit to 0 and handles it as a system-wide (not
+ // per-process) setting. It is therefore safe to assume that ARMv7+
+ // Linux targets support unaligned accesses. The same goes for NaCl.
+ //
+ // The above behavior is consistent with GCC.
+ int VersionNum = getARMSubArchVersionNumber(Triple);
+ if (Triple.isOSDarwin() || Triple.isOSNetBSD()) {
+ if (VersionNum < 6 ||
+ Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
+ Features.push_back("+strict-align");
+ } else if (Triple.isOSLinux() || Triple.isOSNaCl()) {
+ if (VersionNum < 7)
+ Features.push_back("+strict-align");
+ } else
+ Features.push_back("+strict-align");
+ }
+
+ // llvm does not support reserving registers in general. There is support
+ // for reserving r9 on ARM though (defined as a platform-specific register
+ // in ARM EABI).
+ if (Args.hasArg(options::OPT_ffixed_r9))
+ Features.push_back("+reserve-r9");
+
+ // The kext linker doesn't know how to deal with movw/movt.
+ if (KernelOrKext || Args.hasArg(options::OPT_mno_movt))
+ Features.push_back("+no-movt");
+
+ if (Args.hasArg(options::OPT_mno_neg_immediates))
+ Features.push_back("+no-neg-immediates");
+}
+
+const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) {
+ std::string MArch;
+ if (!Arch.empty())
+ MArch = Arch;
+ else
+ MArch = Triple.getArchName();
+ MArch = StringRef(MArch).split("+").first.lower();
+
+ // Handle -march=native.
+ if (MArch == "native") {
+ std::string CPU = llvm::sys::getHostCPUName();
+ if (CPU != "generic") {
+ // Translate the native cpu into the architecture suffix for that CPU.
+ StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch, Triple);
+ // If there is no valid architecture suffix for this CPU we don't know how
+ // to handle it, so return no architecture.
+ if (Suffix.empty())
+ MArch = "";
+ else
+ MArch = std::string("arm") + Suffix.str();
+ }
+ }
+
+ return MArch;
+}
+
+/// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting.
+StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) {
+ std::string MArch = getARMArch(Arch, Triple);
+ // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch
+ // here means an -march=native that we can't handle, so instead return no CPU.
+ if (MArch.empty())
+ return StringRef();
+
+ // We need to return an empty string here on invalid MArch values as the
+ // various places that call this function can't cope with a null result.
+ return Triple.getARMCPUForArch(MArch);
+}
+
+/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
+std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch,
+ const llvm::Triple &Triple) {
+ // FIXME: Warn on inconsistent use of -mcpu and -march.
+ // If we have -mcpu=, use that.
+ if (!CPU.empty()) {
+ std::string MCPU = StringRef(CPU).split("+").first.lower();
+ // Handle -mcpu=native.
+ if (MCPU == "native")
+ return llvm::sys::getHostCPUName();
+ else
+ return MCPU;
+ }
+
+ return getARMCPUForMArch(Arch, Triple);
+}
+
+/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
+/// CPU (or Arch, if CPU is generic).
+// FIXME: This is redundant with -mcpu, why does LLVM use this.
+StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch,
+ const llvm::Triple &Triple) {
+ unsigned ArchKind;
+ if (CPU == "generic") {
+ std::string ARMArch = tools::arm::getARMArch(Arch, Triple);
+ ArchKind = llvm::ARM::parseArch(ARMArch);
+ if (ArchKind == llvm::ARM::AK_INVALID)
+ // In case of generic Arch, i.e. "arm",
+ // extract arch from default cpu of the Triple
+ ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch));
+ } else {
+ // FIXME: horrible hack to get around the fact that Cortex-A7 is only an
+ // armv7k triple if it's actually been specified via "-arch armv7k".
+ ArchKind = (Arch == "armv7k" || Arch == "thumbv7k")
+ ? (unsigned)llvm::ARM::AK_ARMV7K
+ : llvm::ARM::parseCPUArch(CPU);
+ }
+ if (ArchKind == llvm::ARM::AK_INVALID)
+ return "";
+ return llvm::ARM::getSubArch(ArchKind);
+}
+
+void arm::appendEBLinkFlags(const ArgList &Args, ArgStringList &CmdArgs,
+ const llvm::Triple &Triple) {
+ if (Args.hasArg(options::OPT_r))
+ return;
+
+ // ARMv7 (and later) and ARMv6-M do not support BE-32, so instruct the linker
+ // to generate BE-8 executables.
+ if (arm::getARMSubArchVersionNumber(Triple) >= 7 || arm::isARMMProfile(Triple))
+ CmdArgs.push_back("--be8");
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.h
new file mode 100644
index 0000000..52afaab
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/ARM.h
@@ -0,0 +1,60 @@
+//===--- ARM.h - ARM-specific (not AArch64) Tool Helpers --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_ARM_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_ARM_H
+
+#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Option.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace arm {
+
+std::string getARMTargetCPU(StringRef CPU, llvm::StringRef Arch,
+ const llvm::Triple &Triple);
+const std::string getARMArch(llvm::StringRef Arch, const llvm::Triple &Triple);
+StringRef getARMCPUForMArch(llvm::StringRef Arch, const llvm::Triple &Triple);
+StringRef getLLVMArchSuffixForARM(llvm::StringRef CPU, llvm::StringRef Arch,
+ const llvm::Triple &Triple);
+
+void appendEBLinkFlags(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ const llvm::Triple &Triple);
+enum class FloatABI {
+ Invalid,
+ Soft,
+ SoftFP,
+ Hard,
+};
+
+FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args);
+
+bool useAAPCSForMachO(const llvm::Triple &T);
+void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args,
+ llvm::StringRef &Arch, llvm::StringRef &CPU,
+ bool FromAs = false);
+void getARMTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ std::vector<llvm::StringRef> &Features, bool ForAS);
+int getARMSubArchVersionNumber(const llvm::Triple &Triple);
+bool isARMMProfile(const llvm::Triple &Triple);
+
+} // end namespace arm
+} // end namespace tools
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_ARM_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.cpp
new file mode 100644
index 0000000..b45dcd6
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.cpp
@@ -0,0 +1,407 @@
+//===--- Mips.cpp - Tools Implementations -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Mips.h"
+#include "ToolChains/CommonArgs.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+bool tools::isMipsArch(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel ||
+ Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el;
+}
+
+// Get CPU and ABI names. They are not independent
+// so we have to calculate them together.
+void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple,
+ StringRef &CPUName, StringRef &ABIName) {
+ const char *DefMips32CPU = "mips32r2";
+ const char *DefMips64CPU = "mips64r2";
+
+ // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the
+ // default for mips64(el)?-img-linux-gnu.
+ if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies &&
+ Triple.getEnvironment() == llvm::Triple::GNU) {
+ DefMips32CPU = "mips32r6";
+ DefMips64CPU = "mips64r6";
+ }
+
+ // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android).
+ if (Triple.isAndroid()) {
+ DefMips32CPU = "mips32";
+ DefMips64CPU = "mips64r6";
+ }
+
+ // MIPS3 is the default for mips64*-unknown-openbsd.
+ if (Triple.getOS() == llvm::Triple::OpenBSD)
+ DefMips64CPU = "mips3";
+
+ if (Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ,
+ options::OPT_mcpu_EQ))
+ CPUName = A->getValue();
+
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+ ABIName = A->getValue();
+ // Convert a GNU style Mips ABI name to the name
+ // accepted by LLVM Mips backend.
+ ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName)
+ .Case("32", "o32")
+ .Case("64", "n64")
+ .Default(ABIName);
+ }
+
+ // Setup default CPU and ABI names.
+ if (CPUName.empty() && ABIName.empty()) {
+ switch (Triple.getArch()) {
+ default:
+ llvm_unreachable("Unexpected triple arch name");
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ CPUName = DefMips32CPU;
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ CPUName = DefMips64CPU;
+ break;
+ }
+ }
+
+ if (ABIName.empty() &&
+ (Triple.getVendor() == llvm::Triple::MipsTechnologies ||
+ Triple.getVendor() == llvm::Triple::ImaginationTechnologies)) {
+ ABIName = llvm::StringSwitch<const char *>(CPUName)
+ .Case("mips1", "o32")
+ .Case("mips2", "o32")
+ .Case("mips3", "n64")
+ .Case("mips4", "n64")
+ .Case("mips5", "n64")
+ .Case("mips32", "o32")
+ .Case("mips32r2", "o32")
+ .Case("mips32r3", "o32")
+ .Case("mips32r5", "o32")
+ .Case("mips32r6", "o32")
+ .Case("mips64", "n64")
+ .Case("mips64r2", "n64")
+ .Case("mips64r3", "n64")
+ .Case("mips64r5", "n64")
+ .Case("mips64r6", "n64")
+ .Case("octeon", "n64")
+ .Case("p5600", "o32")
+ .Default("");
+ }
+
+ if (ABIName.empty()) {
+ // Deduce ABI name from the target triple.
+ if (Triple.getArch() == llvm::Triple::mips ||
+ Triple.getArch() == llvm::Triple::mipsel)
+ ABIName = "o32";
+ else
+ ABIName = "n64";
+ }
+
+ if (CPUName.empty()) {
+ // Deduce CPU name from ABI name.
+ CPUName = llvm::StringSwitch<const char *>(ABIName)
+ .Case("o32", DefMips32CPU)
+ .Cases("n32", "n64", DefMips64CPU)
+ .Default("");
+ }
+
+ // FIXME: Warn on inconsistent use of -march and -mabi.
+}
+
+std::string mips::getMipsABILibSuffix(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ StringRef CPUName, ABIName;
+ tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
+ return llvm::StringSwitch<std::string>(ABIName)
+ .Case("o32", "")
+ .Case("n32", "32")
+ .Case("n64", "64");
+}
+
+// Convert ABI name to the GNU tools acceptable variant.
+StringRef mips::getGnuCompatibleMipsABIName(StringRef ABI) {
+ return llvm::StringSwitch<llvm::StringRef>(ABI)
+ .Case("o32", "32")
+ .Case("n64", "64")
+ .Default(ABI);
+}
+
+// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
+// and -mfloat-abi=.
+mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args) {
+ mips::FloatABI ABI = mips::FloatABI::Invalid;
+ if (Arg *A =
+ Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ)) {
+ if (A->getOption().matches(options::OPT_msoft_float))
+ ABI = mips::FloatABI::Soft;
+ else if (A->getOption().matches(options::OPT_mhard_float))
+ ABI = mips::FloatABI::Hard;
+ else {
+ ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue())
+ .Case("soft", mips::FloatABI::Soft)
+ .Case("hard", mips::FloatABI::Hard)
+ .Default(mips::FloatABI::Invalid);
+ if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
+ D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
+ ABI = mips::FloatABI::Hard;
+ }
+ }
+ }
+
+ // If unspecified, choose the default based on the platform.
+ if (ABI == mips::FloatABI::Invalid) {
+ // Assume "hard", because it's a default value used by gcc.
+ // When we start to recognize specific target MIPS processors,
+ // we will be able to select the default more correctly.
+ ABI = mips::FloatABI::Hard;
+ }
+
+ assert(ABI != mips::FloatABI::Invalid && "must select an ABI");
+ return ABI;
+}
+
+void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ StringRef CPUName;
+ StringRef ABIName;
+ getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
+ ABIName = getGnuCompatibleMipsABIName(ABIName);
+
+ // Historically, PIC code for MIPS was associated with -mabicalls, a.k.a
+ // SVR4 abicalls. Static code does not use SVR4 calling sequences. An ABI
+ // extension was developed by Richard Sandiford & Code Sourcery to support
+ // static code calling PIC code (CPIC). For O32 and N32 this means we have
+ // several combinations of PIC/static and abicalls. Pure static, static
+ // with the CPIC extension, and pure PIC code.
+
+ // At final link time, O32 and N32 with CPIC will have another section
+ // added to the binary which contains the stub functions to perform
+ // any fixups required for PIC code.
+
+ // For N64, the situation is more regular: code can either be static
+ // (non-abicalls) or PIC (abicalls). GCC has traditionally picked PIC code
+ // code for N64. Since Clang has already built the relocation model portion
+ // of the commandline, we pick add +noabicalls feature in the N64 static
+ // case.
+
+ // The is another case to be accounted for: -msym32, which enforces that all
+ // symbols have 32 bits in size. In this case, N64 can in theory use CPIC
+ // but it is unsupported.
+
+ // The combinations for N64 are:
+ // a) Static without abicalls and 64bit symbols.
+ // b) Static with abicalls and 32bit symbols.
+ // c) PIC with abicalls and 64bit symbols.
+
+ // For case (a) we need to add +noabicalls for N64.
+
+ bool IsN64 = ABIName == "64";
+ bool NonPIC = false;
+
+ Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie);
+ if (LastPICArg) {
+ Option O = LastPICArg->getOption();
+ NonPIC =
+ (O.matches(options::OPT_fno_PIC) || O.matches(options::OPT_fno_pic) ||
+ O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie));
+ }
+
+ if (IsN64 && NonPIC)
+ Features.push_back("+noabicalls");
+ else
+ AddTargetFeature(Args, Features, options::OPT_mno_abicalls,
+ options::OPT_mabicalls, "noabicalls");
+
+ mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args);
+ if (FloatABI == mips::FloatABI::Soft) {
+ // FIXME: Note, this is a hack. We need to pass the selected float
+ // mode to the MipsTargetInfoBase to define appropriate macros there.
+ // Now it is the only method.
+ Features.push_back("+soft-float");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
+ StringRef Val = StringRef(A->getValue());
+ if (Val == "2008") {
+ if (mips::getSupportedNanEncoding(CPUName) & mips::Nan2008)
+ Features.push_back("+nan2008");
+ else {
+ Features.push_back("-nan2008");
+ D.Diag(diag::warn_target_unsupported_nan2008) << CPUName;
+ }
+ } else if (Val == "legacy") {
+ if (mips::getSupportedNanEncoding(CPUName) & mips::NanLegacy)
+ Features.push_back("-nan2008");
+ else {
+ Features.push_back("+nan2008");
+ D.Diag(diag::warn_target_unsupported_nanlegacy) << CPUName;
+ }
+ } else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Val;
+ }
+
+ AddTargetFeature(Args, Features, options::OPT_msingle_float,
+ options::OPT_mdouble_float, "single-float");
+ AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16,
+ "mips16");
+ AddTargetFeature(Args, Features, options::OPT_mmicromips,
+ options::OPT_mno_micromips, "micromips");
+ AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp,
+ "dsp");
+ AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2,
+ "dspr2");
+ AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa,
+ "msa");
+
+ // Add the last -mfp32/-mfpxx/-mfp64, if none are given and the ABI is O32
+ // pass -mfpxx, or if none are given and fp64a is default, pass fp64 and
+ // nooddspreg.
+ if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
+ options::OPT_mfp64)) {
+ if (A->getOption().matches(options::OPT_mfp32))
+ Features.push_back("-fp64");
+ else if (A->getOption().matches(options::OPT_mfpxx)) {
+ Features.push_back("+fpxx");
+ Features.push_back("+nooddspreg");
+ } else
+ Features.push_back("+fp64");
+ } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) {
+ Features.push_back("+fpxx");
+ Features.push_back("+nooddspreg");
+ } else if (mips::isFP64ADefault(Triple, CPUName)) {
+ Features.push_back("+fp64");
+ Features.push_back("+nooddspreg");
+ }
+
+ AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg,
+ options::OPT_modd_spreg, "nooddspreg");
+ AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4,
+ "nomadd4");
+ AddTargetFeature(Args, Features, options::OPT_mlong_calls,
+ options::OPT_mno_long_calls, "long-calls");
+ AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt,"mt");
+}
+
+mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) {
+ // Strictly speaking, mips32r2 and mips64r2 are NanLegacy-only since Nan2008
+ // was first introduced in Release 3. However, other compilers have
+ // traditionally allowed it for Release 2 so we should do the same.
+ return (NanEncoding)llvm::StringSwitch<int>(CPU)
+ .Case("mips1", NanLegacy)
+ .Case("mips2", NanLegacy)
+ .Case("mips3", NanLegacy)
+ .Case("mips4", NanLegacy)
+ .Case("mips5", NanLegacy)
+ .Case("mips32", NanLegacy)
+ .Case("mips32r2", NanLegacy | Nan2008)
+ .Case("mips32r3", NanLegacy | Nan2008)
+ .Case("mips32r5", NanLegacy | Nan2008)
+ .Case("mips32r6", Nan2008)
+ .Case("mips64", NanLegacy)
+ .Case("mips64r2", NanLegacy | Nan2008)
+ .Case("mips64r3", NanLegacy | Nan2008)
+ .Case("mips64r5", NanLegacy | Nan2008)
+ .Case("mips64r6", Nan2008)
+ .Default(NanLegacy);
+}
+
+bool mips::hasCompactBranches(StringRef &CPU) {
+ // mips32r6 and mips64r6 have compact branches.
+ return llvm::StringSwitch<bool>(CPU)
+ .Case("mips32r6", true)
+ .Case("mips64r6", true)
+ .Default(false);
+}
+
+bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) {
+ Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
+ return A && (A->getValue() == StringRef(Value));
+}
+
+bool mips::isUCLibc(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_m_libc_Group);
+ return A && A->getOption().matches(options::OPT_muclibc);
+}
+
+bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) {
+ if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ))
+ return llvm::StringSwitch<bool>(NaNArg->getValue())
+ .Case("2008", true)
+ .Case("legacy", false)
+ .Default(false);
+
+ // NaN2008 is the default for MIPS32r6/MIPS64r6.
+ return llvm::StringSwitch<bool>(getCPUName(Args, Triple))
+ .Cases("mips32r6", "mips64r6", true)
+ .Default(false);
+
+ return false;
+}
+
+bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) {
+ if (!Triple.isAndroid())
+ return false;
+
+ // Android MIPS32R6 defaults to FP64A.
+ return llvm::StringSwitch<bool>(CPUName)
+ .Case("mips32r6", true)
+ .Default(false);
+}
+
+bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
+ StringRef ABIName, mips::FloatABI FloatABI) {
+ if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies &&
+ Triple.getVendor() != llvm::Triple::MipsTechnologies &&
+ !Triple.isAndroid())
+ return false;
+
+ if (ABIName != "32")
+ return false;
+
+ // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is
+ // present.
+ if (FloatABI == mips::FloatABI::Soft)
+ return false;
+
+ return llvm::StringSwitch<bool>(CPUName)
+ .Cases("mips2", "mips3", "mips4", "mips5", true)
+ .Cases("mips32", "mips32r2", "mips32r3", "mips32r5", true)
+ .Cases("mips64", "mips64r2", "mips64r3", "mips64r5", true)
+ .Default(false);
+}
+
+bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple,
+ StringRef CPUName, StringRef ABIName,
+ mips::FloatABI FloatABI) {
+ bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI);
+
+ // FPXX shouldn't be used if -msingle-float is present.
+ if (Arg *A = Args.getLastArg(options::OPT_msingle_float,
+ options::OPT_mdouble_float))
+ if (A->getOption().matches(options::OPT_msingle_float))
+ UseFPXX = false;
+
+ return UseFPXX;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.h
new file mode 100644
index 0000000..0b78866
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Mips.h
@@ -0,0 +1,62 @@
+//===--- Mips.h - Mips-specific Tool Helpers ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_MIPS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_MIPS_H
+
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Option.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+bool isMipsArch(llvm::Triple::ArchType Arch);
+
+namespace mips {
+typedef enum { NanLegacy = 1, Nan2008 = 2 } NanEncoding;
+
+enum class FloatABI {
+ Invalid,
+ Soft,
+ Hard,
+};
+
+NanEncoding getSupportedNanEncoding(StringRef &CPU);
+bool hasCompactBranches(StringRef &CPU);
+void getMipsCPUAndABI(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple, StringRef &CPUName,
+ StringRef &ABIName);
+void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ std::vector<StringRef> &Features);
+StringRef getGnuCompatibleMipsABIName(StringRef ABI);
+mips::FloatABI getMipsFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
+std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value);
+bool isUCLibc(const llvm::opt::ArgList &Args);
+bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple);
+bool isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName);
+bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
+ StringRef ABIName, mips::FloatABI FloatABI);
+bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple,
+ StringRef CPUName, StringRef ABIName,
+ mips::FloatABI FloatABI);
+
+} // end namespace mips
+} // end namespace target
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_MIPS_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp
new file mode 100644
index 0000000..5413231
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.cpp
@@ -0,0 +1,131 @@
+//===--- PPC.cpp - PPC Helpers for Tools ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PPC.h"
+#include "ToolChains/CommonArgs.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting.
+std::string ppc::getPPCTargetCPU(const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
+ StringRef CPUName = A->getValue();
+
+ if (CPUName == "native") {
+ std::string CPU = llvm::sys::getHostCPUName();
+ if (!CPU.empty() && CPU != "generic")
+ return CPU;
+ else
+ return "";
+ }
+
+ return llvm::StringSwitch<const char *>(CPUName)
+ .Case("common", "generic")
+ .Case("440", "440")
+ .Case("440fp", "440")
+ .Case("450", "450")
+ .Case("601", "601")
+ .Case("602", "602")
+ .Case("603", "603")
+ .Case("603e", "603e")
+ .Case("603ev", "603ev")
+ .Case("604", "604")
+ .Case("604e", "604e")
+ .Case("620", "620")
+ .Case("630", "pwr3")
+ .Case("G3", "g3")
+ .Case("7400", "7400")
+ .Case("G4", "g4")
+ .Case("7450", "7450")
+ .Case("G4+", "g4+")
+ .Case("750", "750")
+ .Case("970", "970")
+ .Case("G5", "g5")
+ .Case("a2", "a2")
+ .Case("a2q", "a2q")
+ .Case("e500mc", "e500mc")
+ .Case("e5500", "e5500")
+ .Case("power3", "pwr3")
+ .Case("power4", "pwr4")
+ .Case("power5", "pwr5")
+ .Case("power5x", "pwr5x")
+ .Case("power6", "pwr6")
+ .Case("power6x", "pwr6x")
+ .Case("power7", "pwr7")
+ .Case("power8", "pwr8")
+ .Case("power9", "pwr9")
+ .Case("pwr3", "pwr3")
+ .Case("pwr4", "pwr4")
+ .Case("pwr5", "pwr5")
+ .Case("pwr5x", "pwr5x")
+ .Case("pwr6", "pwr6")
+ .Case("pwr6x", "pwr6x")
+ .Case("pwr7", "pwr7")
+ .Case("pwr8", "pwr8")
+ .Case("pwr9", "pwr9")
+ .Case("powerpc", "ppc")
+ .Case("powerpc64", "ppc64")
+ .Case("powerpc64le", "ppc64le")
+ .Default("");
+ }
+
+ return "";
+}
+
+void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group);
+
+ ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args);
+ if (FloatABI == ppc::FloatABI::Soft)
+ Features.push_back("-hard-float");
+}
+
+ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) {
+ ppc::FloatABI ABI = ppc::FloatABI::Invalid;
+ if (Arg *A =
+ Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ)) {
+ if (A->getOption().matches(options::OPT_msoft_float))
+ ABI = ppc::FloatABI::Soft;
+ else if (A->getOption().matches(options::OPT_mhard_float))
+ ABI = ppc::FloatABI::Hard;
+ else {
+ ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue())
+ .Case("soft", ppc::FloatABI::Soft)
+ .Case("hard", ppc::FloatABI::Hard)
+ .Default(ppc::FloatABI::Invalid);
+ if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
+ D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
+ ABI = ppc::FloatABI::Hard;
+ }
+ }
+ }
+
+ // If unspecified, choose the default based on the platform.
+ if (ABI == ppc::FloatABI::Invalid) {
+ ABI = ppc::FloatABI::Hard;
+ }
+
+ return ABI;
+}
+
+bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) {
+ Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
+ return A && (A->getValue() == StringRef(Value));
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.h
new file mode 100644
index 0000000..892eb2c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/PPC.h
@@ -0,0 +1,45 @@
+//===--- PPC.h - PPC-specific Tool Helpers ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_PPC_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_PPC_H
+
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Option.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace ppc {
+
+bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value);
+
+enum class FloatABI {
+ Invalid,
+ Soft,
+ Hard,
+};
+
+FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
+
+std::string getPPCTargetCPU(const llvm::opt::ArgList &Args);
+
+void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ std::vector<llvm::StringRef> &Features);
+
+} // end namespace ppc
+} // end namespace target
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_PPC_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Sparc.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Sparc.cpp
new file mode 100644
index 0000000..594ec99
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Sparc.cpp
@@ -0,0 +1,100 @@
+//===--- Sparc.cpp - Tools Implementations ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sparc.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+const char *sparc::getSparcAsmModeForCPU(StringRef Name,
+ const llvm::Triple &Triple) {
+ if (Triple.getArch() == llvm::Triple::sparcv9) {
+ return llvm::StringSwitch<const char *>(Name)
+ .Case("niagara", "-Av9b")
+ .Case("niagara2", "-Av9b")
+ .Case("niagara3", "-Av9d")
+ .Case("niagara4", "-Av9d")
+ .Default("-Av9");
+ } else {
+ return llvm::StringSwitch<const char *>(Name)
+ .Case("v8", "-Av8")
+ .Case("supersparc", "-Av8")
+ .Case("sparclite", "-Asparclite")
+ .Case("f934", "-Asparclite")
+ .Case("hypersparc", "-Av8")
+ .Case("sparclite86x", "-Asparclite")
+ .Case("sparclet", "-Asparclet")
+ .Case("tsc701", "-Asparclet")
+ .Case("v9", "-Av8plus")
+ .Case("ultrasparc", "-Av8plus")
+ .Case("ultrasparc3", "-Av8plus")
+ .Case("niagara", "-Av8plusb")
+ .Case("niagara2", "-Av8plusb")
+ .Case("niagara3", "-Av8plusd")
+ .Case("niagara4", "-Av8plusd")
+ .Case("leon2", "-Av8")
+ .Case("at697e", "-Av8")
+ .Case("at697f", "-Av8")
+ .Case("leon3", "-Av8")
+ .Case("ut699", "-Av8")
+ .Case("gr712rc", "-Av8")
+ .Case("leon4", "-Av8")
+ .Case("gr740", "-Av8")
+ .Default("-Av8");
+ }
+}
+
+sparc::FloatABI sparc::getSparcFloatABI(const Driver &D,
+ const ArgList &Args) {
+ sparc::FloatABI ABI = sparc::FloatABI::Invalid;
+ if (Arg *A = Args.getLastArg(clang::driver::options::OPT_msoft_float,
+ options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ)) {
+ if (A->getOption().matches(clang::driver::options::OPT_msoft_float))
+ ABI = sparc::FloatABI::Soft;
+ else if (A->getOption().matches(options::OPT_mhard_float))
+ ABI = sparc::FloatABI::Hard;
+ else {
+ ABI = llvm::StringSwitch<sparc::FloatABI>(A->getValue())
+ .Case("soft", sparc::FloatABI::Soft)
+ .Case("hard", sparc::FloatABI::Hard)
+ .Default(sparc::FloatABI::Invalid);
+ if (ABI == sparc::FloatABI::Invalid &&
+ !StringRef(A->getValue()).empty()) {
+ D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
+ ABI = sparc::FloatABI::Hard;
+ }
+ }
+ }
+
+ // If unspecified, choose the default based on the platform.
+ // Only the hard-float ABI on Sparc is standardized, and it is the
+ // default. GCC also supports a nonstandard soft-float ABI mode, also
+ // implemented in LLVM. However as this is not standard we set the default
+ // to be hard-float.
+ if (ABI == sparc::FloatABI::Invalid) {
+ ABI = sparc::FloatABI::Hard;
+ }
+
+ return ABI;
+}
+
+void sparc::getSparcTargetFeatures(const Driver &D, const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ sparc::FloatABI FloatABI = sparc::getSparcFloatABI(D, Args);
+ if (FloatABI == sparc::FloatABI::Soft)
+ Features.push_back("+soft-float");
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Sparc.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Sparc.h
new file mode 100644
index 0000000..082b280
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/Sparc.h
@@ -0,0 +1,42 @@
+//===--- Sparc.h - Sparc-specific Tool Helpers ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SPARC_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SPARC_H
+
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Option.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace sparc {
+
+enum class FloatABI {
+ Invalid,
+ Soft,
+ Hard,
+};
+
+FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
+
+void getSparcTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
+ std::vector<llvm::StringRef> &Features);
+const char *getSparcAsmModeForCPU(llvm::StringRef Name,
+ const llvm::Triple &Triple);
+
+} // end namespace sparc
+} // end namespace target
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SPARC_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
new file mode 100644
index 0000000..6ee724d
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp
@@ -0,0 +1,41 @@
+//===--- SystemZ.cpp - SystemZ Helpers for Tools ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SystemZ.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+const char *systemz::getSystemZTargetCPU(const ArgList &Args) {
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ))
+ return A->getValue();
+ return "z10";
+}
+
+void systemz::getSystemZTargetFeatures(const ArgList &Args,
+ std::vector<llvm::StringRef> &Features) {
+ // -m(no-)htm overrides use of the transactional-execution facility.
+ if (Arg *A = Args.getLastArg(options::OPT_mhtm, options::OPT_mno_htm)) {
+ if (A->getOption().matches(options::OPT_mhtm))
+ Features.push_back("+transactional-execution");
+ else
+ Features.push_back("-transactional-execution");
+ }
+ // -m(no-)vx overrides use of the vector facility.
+ if (Arg *A = Args.getLastArg(options::OPT_mvx, options::OPT_mno_vx)) {
+ if (A->getOption().matches(options::OPT_mvx))
+ Features.push_back("+vector");
+ else
+ Features.push_back("-vector");
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/SystemZ.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/SystemZ.h
new file mode 100644
index 0000000..521f8c2
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/SystemZ.h
@@ -0,0 +1,32 @@
+//===--- SystemZ.h - SystemZ-specific Tool Helpers --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Option.h"
+#include <vector>
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace systemz {
+
+const char *getSystemZTargetCPU(const llvm::opt::ArgList &Args);
+
+void getSystemZTargetFeatures(const llvm::opt::ArgList &Args,
+ std::vector<llvm::StringRef> &Features);
+
+} // end namespace systemz
+} // end namespace target
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.cpp
new file mode 100644
index 0000000..a85a7f1
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.cpp
@@ -0,0 +1,173 @@
+//===--- X86.cpp - X86 Helpers for Tools ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86.h"
+#include "ToolChains/CommonArgs.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+const char *x86::getX86TargetCPU(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
+ if (StringRef(A->getValue()) != "native") {
+ if (Triple.isOSDarwin() && Triple.getArchName() == "x86_64h")
+ return "core-avx2";
+
+ return A->getValue();
+ }
+
+ // FIXME: Reject attempts to use -march=native unless the target matches
+ // the host.
+ //
+ // FIXME: We should also incorporate the detected target features for use
+ // with -native.
+ std::string CPU = llvm::sys::getHostCPUName();
+ if (!CPU.empty() && CPU != "generic")
+ return Args.MakeArgString(CPU);
+ }
+
+ if (const Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
+ // Mapping built by referring to X86TargetInfo::getDefaultFeatures().
+ StringRef Arch = A->getValue();
+ const char *CPU;
+ if (Triple.getArch() == llvm::Triple::x86) {
+ CPU = llvm::StringSwitch<const char *>(Arch)
+ .Case("IA32", "i386")
+ .Case("SSE", "pentium3")
+ .Case("SSE2", "pentium4")
+ .Case("AVX", "sandybridge")
+ .Case("AVX2", "haswell")
+ .Default(nullptr);
+ } else {
+ CPU = llvm::StringSwitch<const char *>(Arch)
+ .Case("AVX", "sandybridge")
+ .Case("AVX2", "haswell")
+ .Default(nullptr);
+ }
+ if (CPU)
+ return CPU;
+ }
+
+ // Select the default CPU if none was given (or detection failed).
+
+ if (Triple.getArch() != llvm::Triple::x86_64 &&
+ Triple.getArch() != llvm::Triple::x86)
+ return nullptr; // This routine is only handling x86 targets.
+
+ bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
+
+ // FIXME: Need target hooks.
+ if (Triple.isOSDarwin()) {
+ if (Triple.getArchName() == "x86_64h")
+ return "core-avx2";
+ // macosx10.12 drops support for all pre-Penryn Macs.
+ // Simulators can still run on 10.11 though, like Xcode.
+ if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12))
+ return "penryn";
+ // The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah.
+ return Is64Bit ? "core2" : "yonah";
+ }
+
+ // Set up default CPU name for PS4 compilers.
+ if (Triple.isPS4CPU())
+ return "btver2";
+
+ // On Android use targets compatible with gcc
+ if (Triple.isAndroid())
+ return Is64Bit ? "x86-64" : "i686";
+
+ // Everything else goes to x86-64 in 64-bit mode.
+ if (Is64Bit)
+ return "x86-64";
+
+ switch (Triple.getOS()) {
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
+ case llvm::Triple::OpenBSD:
+ return "i486";
+ case llvm::Triple::Haiku:
+ return "i586";
+ case llvm::Triple::Bitrig:
+ return "i686";
+ default:
+ // Fallback to p4.
+ return "pentium4";
+ }
+}
+
+void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ // If -march=native, autodetect the feature list.
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
+ if (StringRef(A->getValue()) == "native") {
+ llvm::StringMap<bool> HostFeatures;
+ if (llvm::sys::getHostCPUFeatures(HostFeatures))
+ for (auto &F : HostFeatures)
+ Features.push_back(
+ Args.MakeArgString((F.second ? "+" : "-") + F.first()));
+ }
+ }
+
+ if (Triple.getArchName() == "x86_64h") {
+ // x86_64h implies quite a few of the more modern subtarget features
+ // for Haswell class CPUs, but not all of them. Opt-out of a few.
+ Features.push_back("-rdrnd");
+ Features.push_back("-aes");
+ Features.push_back("-pclmul");
+ Features.push_back("-rtm");
+ Features.push_back("-fsgsbase");
+ }
+
+ const llvm::Triple::ArchType ArchType = Triple.getArch();
+ // Add features to be compatible with gcc for Android.
+ if (Triple.isAndroid()) {
+ if (ArchType == llvm::Triple::x86_64) {
+ Features.push_back("+sse4.2");
+ Features.push_back("+popcnt");
+ } else
+ Features.push_back("+ssse3");
+ }
+
+ // Set features according to the -arch flag on MSVC.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
+ StringRef Arch = A->getValue();
+ bool ArchUsed = false;
+ // First, look for flags that are shared in x86 and x86-64.
+ if (ArchType == llvm::Triple::x86_64 || ArchType == llvm::Triple::x86) {
+ if (Arch == "AVX" || Arch == "AVX2") {
+ ArchUsed = true;
+ Features.push_back(Args.MakeArgString("+" + Arch.lower()));
+ }
+ }
+ // Then, look for x86-specific flags.
+ if (ArchType == llvm::Triple::x86) {
+ if (Arch == "IA32") {
+ ArchUsed = true;
+ } else if (Arch == "SSE" || Arch == "SSE2") {
+ ArchUsed = true;
+ Features.push_back(Args.MakeArgString("+" + Arch.lower()));
+ }
+ }
+ if (!ArchUsed)
+ D.Diag(clang::diag::warn_drv_unused_argument) << A->getAsString(Args);
+ }
+
+ // Now add any that the user explicitly requested on the command line,
+ // which may override the defaults.
+ handleTargetFeaturesGroup(Args, Features, options::OPT_m_x86_Features_Group);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.h
new file mode 100644
index 0000000..20bf27a
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Arch/X86.h
@@ -0,0 +1,37 @@
+//===--- X86.h - X86-specific Tool Helpers ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_X86_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_X86_H
+
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Option.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace x86 {
+
+const char *getX86TargetCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+
+void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ std::vector<llvm::StringRef> &Features);
+
+} // end namespace x86
+} // end namespace target
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_X86_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.cpp
new file mode 100644
index 0000000..5dc6dfa
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -0,0 +1,211 @@
+//===--- BaremMetal.cpp - Bare Metal ToolChain ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BareMetal.h"
+
+#include "CommonArgs.h"
+#include "InputInfo.h"
+#include "Gnu.h"
+
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::opt;
+using namespace clang;
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+
+BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+}
+
+BareMetal::~BareMetal() {}
+
+/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
+static bool isARMBareMetal(const llvm::Triple &Triple) {
+ if (Triple.getArch() != llvm::Triple::arm &&
+ Triple.getArch() != llvm::Triple::thumb)
+ return false;
+
+ if (Triple.getVendor() != llvm::Triple::UnknownVendor)
+ return false;
+
+ if (Triple.getOS() != llvm::Triple::UnknownOS)
+ return false;
+
+ if (Triple.getEnvironment() != llvm::Triple::EABI &&
+ Triple.getEnvironment() != llvm::Triple::EABIHF)
+ return false;
+
+ return true;
+}
+
+bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
+ return isARMBareMetal(Triple);
+}
+
+Tool *BareMetal::buildLinker() const {
+ return new tools::baremetal::Linker(*this);
+}
+
+std::string BareMetal::getThreadModel() const {
+ return "single";
+}
+
+bool BareMetal::isThreadModelSupported(const StringRef Model) const {
+ return Model == "single";
+}
+
+std::string BareMetal::getRuntimesDir() const {
+ SmallString<128> Dir(getDriver().ResourceDir);
+ llvm::sys::path::append(Dir, "lib", "baremetal");
+ return Dir.str();
+}
+
+void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(getDriver().ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
+ if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
+ SmallString<128> Dir(getDriver().SysRoot);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+}
+
+void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ CC1Args.push_back("-nostdsysteminc");
+}
+
+std::string BareMetal::findLibCxxIncludePath(CXXStdlibType LibType) const {
+ StringRef SysRoot = getDriver().SysRoot;
+ if (SysRoot.empty())
+ return "";
+
+ switch (LibType) {
+ case ToolChain::CST_Libcxx: {
+ SmallString<128> Dir(SysRoot);
+ llvm::sys::path::append(Dir, "include", "c++", "v1");
+ return Dir.str();
+ }
+ case ToolChain::CST_Libstdcxx: {
+ SmallString<128> Dir(SysRoot);
+ llvm::sys::path::append(Dir, "include", "c++");
+ std::error_code EC;
+ Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
+ // Walk the subdirs, and find the one with the newest gcc version:
+ for (vfs::directory_iterator LI =
+ getDriver().getVFS().dir_begin(Dir.str(), EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->getName());
+ auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
+ if (CandidateVersion.Major == -1)
+ continue;
+ if (CandidateVersion <= Version)
+ continue;
+ Version = CandidateVersion;
+ }
+ if (Version.Major == -1)
+ return "";
+ llvm::sys::path::append(Dir, Version.Text);
+ return Dir.str();
+ }
+ }
+ llvm_unreachable("unhandled LibType");
+}
+
+void BareMetal::AddClangCXXStdlibIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ std::string Path = findLibCxxIncludePath(GetCXXStdlibType(DriverArgs));
+ if (!Path.empty())
+ addSystemInclude(DriverArgs, CC1Args, Path);
+}
+
+void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ CmdArgs.push_back("-lstdc++");
+ CmdArgs.push_back("-lsupc++");
+ break;
+ }
+ CmdArgs.push_back("-lunwind");
+}
+
+void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CmdArgs.push_back(Args.MakeArgString("-lclang_rt.builtins-" +
+ getTriple().getArchName() + ".a"));
+}
+
+void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain());
+
+ AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
+
+ CmdArgs.push_back("-Bstatic");
+
+ CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir()));
+
+ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_e, options::OPT_s, options::OPT_t,
+ options::OPT_Z_Flag, options::OPT_r});
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (C.getDriver().CCCIsCXX())
+ TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lm");
+
+ TC.AddLinkRuntimeLib(Args, CmdArgs);
+ }
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this,
+ Args.MakeArgString(TC.GetLinkerPath()),
+ CmdArgs, Inputs));
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.h
new file mode 100644
index 0000000..4b74899
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/BareMetal.h
@@ -0,0 +1,91 @@
+//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+#include <string>
+
+namespace clang {
+namespace driver {
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain {
+public:
+ BareMetal(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~BareMetal() override;
+
+ static bool handlesTarget(const llvm::Triple &Triple);
+protected:
+ Tool *buildLinker() const override;
+
+public:
+ bool useIntegratedAs() const override { return true; }
+ bool isCrossCompiling() const override { return true; }
+ bool isPICDefault() const override { return false; }
+ bool isPIEDefault() const override { return false; }
+ bool isPICDefaultForced() const override { return false; }
+ bool SupportsProfiling() const override { return false; }
+ bool SupportsObjCGC() const override { return false; }
+ std::string getThreadModel() const override;
+ bool isThreadModelSupported(const StringRef Model) const override;
+
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return ToolChain::RLT_CompilerRT;
+ }
+ CXXStdlibType GetDefaultCXXStdlibType() const override {
+ return ToolChain::CST_Libcxx;
+ }
+
+ const char *getDefaultLinker() const override { return "ld.lld"; }
+
+ std::string getRuntimesDir() const;
+ void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ std::string findLibCxxIncludePath(ToolChain::CXXStdlibType LibType) const;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+ void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+};
+
+} // namespace toolchains
+
+namespace tools {
+namespace baremetal {
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {}
+ bool isLinkJob() const override { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+} // namespace baremetal
+} // namespace tools
+
+} // namespace driver
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.cpp
new file mode 100644
index 0000000..d8f541d
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.cpp
@@ -0,0 +1,190 @@
+//===--- Bitrig.cpp - Bitrig ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Bitrig.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+void bitrig::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
+ CmdArgs.push_back("-e");
+ CmdArgs.push_back("__start");
+ }
+
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ CmdArgs.push_back("--eh-frame-hdr");
+ CmdArgs.push_back("-Bdynamic");
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-shared");
+ } else {
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/usr/libexec/ld.so");
+ }
+ }
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("gcrt0.o")));
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crt0.o")));
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ } else {
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
+ }
+ }
+
+ Args.AddAllArgs(CmdArgs,
+ {options::OPT_L, options::OPT_T_Group, options::OPT_e});
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX()) {
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lm_p");
+ else
+ CmdArgs.push_back("-lm");
+ }
+
+ if (Args.hasArg(options::OPT_pthread)) {
+ if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lpthread_p");
+ else
+ CmdArgs.push_back("-lpthread");
+ }
+
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lc_p");
+ else
+ CmdArgs.push_back("-lc");
+ }
+
+ StringRef MyArch;
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::arm:
+ MyArch = "arm";
+ break;
+ case llvm::Triple::x86:
+ MyArch = "i386";
+ break;
+ case llvm::Triple::x86_64:
+ MyArch = "amd64";
+ break;
+ default:
+ llvm_unreachable("Unsupported architecture");
+ }
+ CmdArgs.push_back(Args.MakeArgString("-lclang_rt." + MyArch));
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
+ }
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly.
+
+Bitrig::Bitrig(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ getFilePaths().push_back(getDriver().Dir + "/../lib");
+ getFilePaths().push_back("/usr/lib");
+}
+
+Tool *Bitrig::buildAssembler() const {
+ return new tools::bitrig::Assembler(*this);
+}
+
+Tool *Bitrig::buildLinker() const { return new tools::bitrig::Linker(*this); }
+
+ToolChain::CXXStdlibType Bitrig::GetDefaultCXXStdlibType() const {
+ return ToolChain::CST_Libcxx;
+}
+
+void Bitrig::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ std::string Triple = getTriple().str();
+ if (StringRef(Triple).startswith("amd64"))
+ Triple = "x86_64" + Triple.substr(5);
+ addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/stdc++",
+ Triple, "", "", "", DriverArgs, CC1Args);
+}
+
+void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ CmdArgs.push_back("-lpthread");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ CmdArgs.push_back("-lstdc++");
+ break;
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.h
new file mode 100644
index 0000000..6edb2e8
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Bitrig.h
@@ -0,0 +1,79 @@
+//===--- Bitrig.h - Bitrig ToolChain Implementations ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H
+
+#include "Gnu.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+/// bitrig -- Directly call GNU Binutils assembler and linker
+namespace bitrig {
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
+public:
+ Assembler(const ToolChain &TC)
+ : GnuTool("bitrig::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("bitrig::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace bitrig
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF {
+public:
+ Bitrig(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
+
+ CXXStdlibType GetDefaultCXXStdlibType() const override;
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+ unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
+ return 1;
+ }
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp
new file mode 100644
index 0000000..6a6b90f
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp
@@ -0,0 +1,5271 @@
+//===--- LLVM.cpp - Clang+LLVM ToolChain Implementations --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Clang.h"
+#include "Arch/AArch64.h"
+#include "Arch/ARM.h"
+#include "Arch/Mips.h"
+#include "Arch/PPC.h"
+#include "Arch/Sparc.h"
+#include "Arch/SystemZ.h"
+#include "Arch/X86.h"
+#include "CommonArgs.h"
+#include "Hexagon.h"
+#include "InputInfo.h"
+#include "PS4CPU.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/Version.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "clang/Driver/XRayArgs.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/YAMLParser.h"
+
+#ifdef LLVM_ON_UNIX
+#include <unistd.h> // For getuid().
+#endif
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
+ if (Arg *A =
+ Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC)) {
+ if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) &&
+ !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) {
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << A->getBaseArg().getAsString(Args)
+ << (D.IsCLMode() ? "/E, /P or /EP" : "-E");
+ }
+ }
+}
+
+static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) {
+ // In gcc, only ARM checks this, but it seems reasonable to check universally.
+ if (Args.hasArg(options::OPT_static))
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_dynamic, options::OPT_mdynamic_no_pic))
+ D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args)
+ << "-static";
+}
+
+// Add backslashes to escape spaces and other backslashes.
+// This is used for the space-separated argument list specified with
+// the -dwarf-debug-flags option.
+static void EscapeSpacesAndBackslashes(const char *Arg,
+ SmallVectorImpl<char> &Res) {
+ for (; *Arg; ++Arg) {
+ switch (*Arg) {
+ default:
+ break;
+ case ' ':
+ case '\\':
+ Res.push_back('\\');
+ break;
+ }
+ Res.push_back(*Arg);
+ }
+}
+
+// Quote target names for inclusion in GNU Make dependency files.
+// Only the characters '$', '#', ' ', '\t' are quoted.
+static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) {
+ for (unsigned i = 0, e = Target.size(); i != e; ++i) {
+ switch (Target[i]) {
+ case ' ':
+ case '\t':
+ // Escape the preceding backslashes
+ for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
+ Res.push_back('\\');
+
+ // Escape the space/tab
+ Res.push_back('\\');
+ break;
+ case '$':
+ Res.push_back('$');
+ break;
+ case '#':
+ Res.push_back('\\');
+ break;
+ default:
+ break;
+ }
+
+ Res.push_back(Target[i]);
+ }
+}
+
+/// Apply \a Work on the current tool chain \a RegularToolChain and any other
+/// offloading tool chain that is associated with the current action \a JA.
+static void
+forAllAssociatedToolChains(Compilation &C, const JobAction &JA,
+ const ToolChain &RegularToolChain,
+ llvm::function_ref<void(const ToolChain &)> Work) {
+ // Apply Work on the current/regular tool chain.
+ Work(RegularToolChain);
+
+ // Apply Work on all the offloading tool chains associated with the current
+ // action.
+ if (JA.isHostOffloading(Action::OFK_Cuda))
+ Work(*C.getSingleOffloadToolChain<Action::OFK_Cuda>());
+ else if (JA.isDeviceOffloading(Action::OFK_Cuda))
+ Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
+
+ if (JA.isHostOffloading(Action::OFK_OpenMP)) {
+ auto TCs = C.getOffloadToolChains<Action::OFK_OpenMP>();
+ for (auto II = TCs.first, IE = TCs.second; II != IE; ++II)
+ Work(*II->second);
+ } else if (JA.isDeviceOffloading(Action::OFK_OpenMP))
+ Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
+
+ //
+ // TODO: Add support for other offloading programming models here.
+ //
+}
+
+/// This is a helper function for validating the optional refinement step
+/// parameter in reciprocal argument strings. Return false if there is an error
+/// parsing the refinement step. Otherwise, return true and set the Position
+/// of the refinement step in the input string.
+static bool getRefinementStep(StringRef In, const Driver &D,
+ const Arg &A, size_t &Position) {
+ const char RefinementStepToken = ':';
+ Position = In.find(RefinementStepToken);
+ if (Position != StringRef::npos) {
+ StringRef Option = A.getOption().getName();
+ StringRef RefStep = In.substr(Position + 1);
+ // Allow exactly one numeric character for the additional refinement
+ // step parameter. This is reasonable for all currently-supported
+ // operations and architectures because we would expect that a larger value
+ // of refinement steps would cause the estimate "optimization" to
+ // under-perform the native operation. Also, if the estimate does not
+ // converge quickly, it probably will not ever converge, so further
+ // refinement steps will not produce a better answer.
+ if (RefStep.size() != 1) {
+ D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
+ return false;
+ }
+ char RefStepChar = RefStep[0];
+ if (RefStepChar < '0' || RefStepChar > '9') {
+ D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
+ return false;
+ }
+ }
+ return true;
+}
+
+/// The -mrecip flag requires processing of many optional parameters.
+static void ParseMRecip(const Driver &D, const ArgList &Args,
+ ArgStringList &OutStrings) {
+ StringRef DisabledPrefixIn = "!";
+ StringRef DisabledPrefixOut = "!";
+ StringRef EnabledPrefixOut = "";
+ StringRef Out = "-mrecip=";
+
+ Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ);
+ if (!A)
+ return;
+
+ unsigned NumOptions = A->getNumValues();
+ if (NumOptions == 0) {
+ // No option is the same as "all".
+ OutStrings.push_back(Args.MakeArgString(Out + "all"));
+ return;
+ }
+
+ // Pass through "all", "none", or "default" with an optional refinement step.
+ if (NumOptions == 1) {
+ StringRef Val = A->getValue(0);
+ size_t RefStepLoc;
+ if (!getRefinementStep(Val, D, *A, RefStepLoc))
+ return;
+ StringRef ValBase = Val.slice(0, RefStepLoc);
+ if (ValBase == "all" || ValBase == "none" || ValBase == "default") {
+ OutStrings.push_back(Args.MakeArgString(Out + Val));
+ return;
+ }
+ }
+
+ // Each reciprocal type may be enabled or disabled individually.
+ // Check each input value for validity, concatenate them all back together,
+ // and pass through.
+
+ llvm::StringMap<bool> OptionStrings;
+ OptionStrings.insert(std::make_pair("divd", false));
+ OptionStrings.insert(std::make_pair("divf", false));
+ OptionStrings.insert(std::make_pair("vec-divd", false));
+ OptionStrings.insert(std::make_pair("vec-divf", false));
+ OptionStrings.insert(std::make_pair("sqrtd", false));
+ OptionStrings.insert(std::make_pair("sqrtf", false));
+ OptionStrings.insert(std::make_pair("vec-sqrtd", false));
+ OptionStrings.insert(std::make_pair("vec-sqrtf", false));
+
+ for (unsigned i = 0; i != NumOptions; ++i) {
+ StringRef Val = A->getValue(i);
+
+ bool IsDisabled = Val.startswith(DisabledPrefixIn);
+ // Ignore the disablement token for string matching.
+ if (IsDisabled)
+ Val = Val.substr(1);
+
+ size_t RefStep;
+ if (!getRefinementStep(Val, D, *A, RefStep))
+ return;
+
+ StringRef ValBase = Val.slice(0, RefStep);
+ llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase);
+ if (OptionIter == OptionStrings.end()) {
+ // Try again specifying float suffix.
+ OptionIter = OptionStrings.find(ValBase.str() + 'f');
+ if (OptionIter == OptionStrings.end()) {
+ // The input name did not match any known option string.
+ D.Diag(diag::err_drv_unknown_argument) << Val;
+ return;
+ }
+ // The option was specified without a float or double suffix.
+ // Make sure that the double entry was not already specified.
+ // The float entry will be checked below.
+ if (OptionStrings[ValBase.str() + 'd']) {
+ D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
+ return;
+ }
+ }
+
+ if (OptionIter->second == true) {
+ // Duplicate option specified.
+ D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
+ return;
+ }
+
+ // Mark the matched option as found. Do not allow duplicate specifiers.
+ OptionIter->second = true;
+
+ // If the precision was not specified, also mark the double entry as found.
+ if (ValBase.back() != 'f' && ValBase.back() != 'd')
+ OptionStrings[ValBase.str() + 'd'] = true;
+
+ // Build the output string.
+ StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;
+ Out = Args.MakeArgString(Out + Prefix + Val);
+ if (i != NumOptions - 1)
+ Out = Args.MakeArgString(Out + ",");
+ }
+
+ OutStrings.push_back(Args.MakeArgString(Out));
+}
+
+static void getHexagonTargetFeatures(const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ handleTargetFeaturesGroup(Args, Features,
+ options::OPT_m_hexagon_Features_Group);
+
+ bool UseLongCalls = false;
+ if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
+ options::OPT_mno_long_calls)) {
+ if (A->getOption().matches(options::OPT_mlong_calls))
+ UseLongCalls = true;
+ }
+
+ Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls");
+}
+
+static void getWebAssemblyTargetFeatures(const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group);
+}
+
+static void getAMDGPUTargetFeatures(const Driver &D, const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) {
+ StringRef value = dAbi->getValue();
+ if (value == "1.0") {
+ Features.push_back("+amdgpu-debugger-insert-nops");
+ Features.push_back("+amdgpu-debugger-reserve-regs");
+ Features.push_back("+amdgpu-debugger-emit-prologue");
+ } else {
+ D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args);
+ }
+ }
+
+ handleTargetFeaturesGroup(
+ Args, Features, options::OPT_m_amdgpu_Features_Group);
+}
+
+static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
+ const ArgList &Args, ArgStringList &CmdArgs,
+ bool ForAS) {
+ const Driver &D = TC.getDriver();
+ std::vector<StringRef> Features;
+ switch (Triple.getArch()) {
+ default:
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ mips::getMIPSTargetFeatures(D, Triple, Args, Features);
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS);
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ ppc::getPPCTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::systemz:
+ systemz::getSystemZTargetFeatures(Args, Features);
+ break;
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ aarch64::getAArch64TargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ x86::getX86TargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::hexagon:
+ getHexagonTargetFeatures(Args, Features);
+ break;
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ getWebAssemblyTargetFeatures(Args, Features);
+ break;
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9:
+ sparc::getSparcTargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::r600:
+ case llvm::Triple::amdgcn:
+ getAMDGPUTargetFeatures(D, Args, Features);
+ break;
+ }
+
+ // Find the last of each feature.
+ llvm::StringMap<unsigned> LastOpt;
+ for (unsigned I = 0, N = Features.size(); I < N; ++I) {
+ StringRef Name = Features[I];
+ assert(Name[0] == '-' || Name[0] == '+');
+ LastOpt[Name.drop_front(1)] = I;
+ }
+
+ for (unsigned I = 0, N = Features.size(); I < N; ++I) {
+ // If this feature was overridden, ignore it.
+ StringRef Name = Features[I];
+ llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1));
+ assert(LastI != LastOpt.end());
+ unsigned Last = LastI->second;
+ if (Last != I)
+ continue;
+
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(Name.data());
+ }
+}
+
+static bool
+shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
+ const llvm::Triple &Triple) {
+ // We use the zero-cost exception tables for Objective-C if the non-fragile
+ // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and
+ // later.
+ if (runtime.isNonFragile())
+ return true;
+
+ if (!Triple.isMacOSX())
+ return false;
+
+ return (!Triple.isMacOSXVersionLT(10, 5) &&
+ (Triple.getArch() == llvm::Triple::x86_64 ||
+ Triple.getArch() == llvm::Triple::arm));
+}
+
+/// Adds exception related arguments to the driver command arguments. There's a
+/// master flag, -fexceptions and also language specific flags to enable/disable
+/// C++ and Objective-C exceptions. This makes it possible to for example
+/// disable C++ exceptions but enable Objective-C exceptions.
+static void addExceptionArgs(const ArgList &Args, types::ID InputType,
+ const ToolChain &TC, bool KernelOrKext,
+ const ObjCRuntime &objcRuntime,
+ ArgStringList &CmdArgs) {
+ const Driver &D = TC.getDriver();
+ const llvm::Triple &Triple = TC.getTriple();
+
+ if (KernelOrKext) {
+ // -mkernel and -fapple-kext imply no exceptions, so claim exception related
+ // arguments now to avoid warnings about unused arguments.
+ Args.ClaimAllArgs(options::OPT_fexceptions);
+ Args.ClaimAllArgs(options::OPT_fno_exceptions);
+ Args.ClaimAllArgs(options::OPT_fobjc_exceptions);
+ Args.ClaimAllArgs(options::OPT_fno_objc_exceptions);
+ Args.ClaimAllArgs(options::OPT_fcxx_exceptions);
+ Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions);
+ return;
+ }
+
+ // See if the user explicitly enabled exceptions.
+ bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
+ false);
+
+ // Obj-C exceptions are enabled by default, regardless of -fexceptions. This
+ // is not necessarily sensible, but follows GCC.
+ if (types::isObjC(InputType) &&
+ Args.hasFlag(options::OPT_fobjc_exceptions,
+ options::OPT_fno_objc_exceptions, true)) {
+ CmdArgs.push_back("-fobjc-exceptions");
+
+ EH |= shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple);
+ }
+
+ if (types::isCXX(InputType)) {
+ // Disable C++ EH by default on XCore and PS4.
+ bool CXXExceptionsEnabled =
+ Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU();
+ Arg *ExceptionArg = Args.getLastArg(
+ options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions,
+ options::OPT_fexceptions, options::OPT_fno_exceptions);
+ if (ExceptionArg)
+ CXXExceptionsEnabled =
+ ExceptionArg->getOption().matches(options::OPT_fcxx_exceptions) ||
+ ExceptionArg->getOption().matches(options::OPT_fexceptions);
+
+ if (CXXExceptionsEnabled) {
+ if (Triple.isPS4CPU()) {
+ ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
+ assert(ExceptionArg &&
+ "On the PS4 exceptions should only be enabled if passing "
+ "an argument");
+ if (RTTIMode == ToolChain::RM_DisabledExplicitly) {
+ const Arg *RTTIArg = TC.getRTTIArg();
+ assert(RTTIArg && "RTTI disabled explicitly but no RTTIArg!");
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << RTTIArg->getAsString(Args) << ExceptionArg->getAsString(Args);
+ } else if (RTTIMode == ToolChain::RM_EnabledImplicitly)
+ D.Diag(diag::warn_drv_enabling_rtti_with_exceptions);
+ } else
+ assert(TC.getRTTIMode() != ToolChain::RM_DisabledImplicitly);
+
+ CmdArgs.push_back("-fcxx-exceptions");
+
+ EH = true;
+ }
+ }
+
+ if (EH)
+ CmdArgs.push_back("-fexceptions");
+}
+
+static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) {
+ bool Default = true;
+ if (TC.getTriple().isOSDarwin()) {
+ // The native darwin assembler doesn't support the linker_option directives,
+ // so we disable them if we think the .s file will be passed to it.
+ Default = TC.useIntegratedAs();
+ }
+ return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink,
+ Default);
+}
+
+static bool ShouldDisableDwarfDirectory(const ArgList &Args,
+ const ToolChain &TC) {
+ bool UseDwarfDirectory =
+ Args.hasFlag(options::OPT_fdwarf_directory_asm,
+ options::OPT_fno_dwarf_directory_asm, TC.useIntegratedAs());
+ return !UseDwarfDirectory;
+}
+
+// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases
+// to the corresponding DebugInfoKind.
+static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) {
+ assert(A.getOption().matches(options::OPT_gN_Group) &&
+ "Not a -g option that specifies a debug-info level");
+ if (A.getOption().matches(options::OPT_g0) ||
+ A.getOption().matches(options::OPT_ggdb0))
+ return codegenoptions::NoDebugInfo;
+ if (A.getOption().matches(options::OPT_gline_tables_only) ||
+ A.getOption().matches(options::OPT_ggdb1))
+ return codegenoptions::DebugLineTablesOnly;
+ return codegenoptions::LimitedDebugInfo;
+}
+
+static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
+ switch (Triple.getArch()){
+ default:
+ return false;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // ARM Darwin targets require a frame pointer to be always present to aid
+ // offline debugging via backtraces.
+ return Triple.isOSDarwin();
+ }
+}
+
+static bool useFramePointerForTargetByDefault(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ case llvm::Triple::xcore:
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ // XCore never wants frame pointers, regardless of OS.
+ // WebAssembly never wants frame pointers.
+ return false;
+ default:
+ break;
+ }
+
+ if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI) {
+ switch (Triple.getArch()) {
+ // Don't use a frame pointer on linux if optimizing for certain targets.
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::systemz:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return !areOptimizationsEnabled(Args);
+ default:
+ return true;
+ }
+ }
+
+ if (Triple.isOSWindows()) {
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86:
+ return !areOptimizationsEnabled(Args);
+ case llvm::Triple::x86_64:
+ return Triple.isOSBinFormatMachO();
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // Windows on ARM builds with FPO disabled to aid fast stack walking
+ return true;
+ default:
+ // All other supported Windows ISAs use xdata unwind information, so frame
+ // pointers are not generally useful.
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool shouldUseFramePointer(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
+ options::OPT_fomit_frame_pointer))
+ return A->getOption().matches(options::OPT_fno_omit_frame_pointer) ||
+ mustUseNonLeafFramePointerForTarget(Triple);
+
+ if (Args.hasArg(options::OPT_pg))
+ return true;
+
+ return useFramePointerForTargetByDefault(Args, Triple);
+}
+
+static bool shouldUseLeafFramePointer(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer,
+ options::OPT_momit_leaf_frame_pointer))
+ return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer);
+
+ if (Args.hasArg(options::OPT_pg))
+ return true;
+
+ if (Triple.isPS4CPU())
+ return false;
+
+ return useFramePointerForTargetByDefault(Args, Triple);
+}
+
+/// Add a CC1 option to specify the debug compilation directory.
+static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) {
+ SmallString<128> cwd;
+ if (!llvm::sys::fs::current_path(cwd)) {
+ CmdArgs.push_back("-fdebug-compilation-dir");
+ CmdArgs.push_back(Args.MakeArgString(cwd));
+ }
+}
+
+/// \brief Vectorize at all optimization levels greater than 1 except for -Oz.
+/// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled.
+static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) {
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ if (A->getOption().matches(options::OPT_O4) ||
+ A->getOption().matches(options::OPT_Ofast))
+ return true;
+
+ if (A->getOption().matches(options::OPT_O0))
+ return false;
+
+ assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag");
+
+ // Vectorize -Os.
+ StringRef S(A->getValue());
+ if (S == "s")
+ return true;
+
+ // Don't vectorize -Oz, unless it's the slp vectorizer.
+ if (S == "z")
+ return isSlpVec;
+
+ unsigned OptLevel = 0;
+ if (S.getAsInteger(10, OptLevel))
+ return false;
+
+ return OptLevel > 1;
+ }
+
+ return false;
+}
+
+/// Add -x lang to \p CmdArgs for \p Input.
+static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
+ ArgStringList &CmdArgs) {
+ // When using -verify-pch, we don't want to provide the type
+ // 'precompiled-header' if it was inferred from the file extension
+ if (Args.hasArg(options::OPT_verify_pch) && Input.getType() == types::TY_PCH)
+ return;
+
+ CmdArgs.push_back("-x");
+ if (Args.hasArg(options::OPT_rewrite_objc))
+ CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX));
+ else {
+ // Map the driver type to the frontend type. This is mostly an identity
+ // mapping, except that the distinction between module interface units
+ // and other source files does not exist at the frontend layer.
+ const char *ClangType;
+ switch (Input.getType()) {
+ case types::TY_CXXModule:
+ ClangType = "c++";
+ break;
+ case types::TY_PP_CXXModule:
+ ClangType = "c++-cpp-output";
+ break;
+ default:
+ ClangType = types::getTypeName(Input.getType());
+ break;
+ }
+ CmdArgs.push_back(ClangType);
+ }
+}
+
+static void appendUserToPath(SmallVectorImpl<char> &Result) {
+#ifdef LLVM_ON_UNIX
+ const char *Username = getenv("LOGNAME");
+#else
+ const char *Username = getenv("USERNAME");
+#endif
+ if (Username) {
+ // Validate that LoginName can be used in a path, and get its length.
+ size_t Len = 0;
+ for (const char *P = Username; *P; ++P, ++Len) {
+ if (!clang::isAlphanumeric(*P) && *P != '_') {
+ Username = nullptr;
+ break;
+ }
+ }
+
+ if (Username && Len > 0) {
+ Result.append(Username, Username + Len);
+ return;
+ }
+ }
+
+// Fallback to user id.
+#ifdef LLVM_ON_UNIX
+ std::string UID = llvm::utostr(getuid());
+#else
+ // FIXME: Windows seems to have an 'SID' that might work.
+ std::string UID = "9999";
+#endif
+ Result.append(UID.begin(), UID.end());
+}
+
+static void addPGOAndCoverageFlags(Compilation &C, const Driver &D,
+ const InputInfo &Output, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+
+ auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate,
+ options::OPT_fprofile_generate_EQ,
+ options::OPT_fno_profile_generate);
+ if (PGOGenerateArg &&
+ PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
+ PGOGenerateArg = nullptr;
+
+ auto *ProfileGenerateArg = Args.getLastArg(
+ options::OPT_fprofile_instr_generate,
+ options::OPT_fprofile_instr_generate_EQ,
+ options::OPT_fno_profile_instr_generate);
+ if (ProfileGenerateArg &&
+ ProfileGenerateArg->getOption().matches(
+ options::OPT_fno_profile_instr_generate))
+ ProfileGenerateArg = nullptr;
+
+ if (PGOGenerateArg && ProfileGenerateArg)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << PGOGenerateArg->getSpelling() << ProfileGenerateArg->getSpelling();
+
+ auto *ProfileUseArg = getLastProfileUseArg(Args);
+
+ if (PGOGenerateArg && ProfileUseArg)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << ProfileUseArg->getSpelling() << PGOGenerateArg->getSpelling();
+
+ if (ProfileGenerateArg && ProfileUseArg)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << ProfileGenerateArg->getSpelling() << ProfileUseArg->getSpelling();
+
+ if (ProfileGenerateArg) {
+ if (ProfileGenerateArg->getOption().matches(
+ options::OPT_fprofile_instr_generate_EQ))
+ CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instrument-path=") +
+ ProfileGenerateArg->getValue()));
+ // The default is to use Clang Instrumentation.
+ CmdArgs.push_back("-fprofile-instrument=clang");
+ }
+
+ if (PGOGenerateArg) {
+ CmdArgs.push_back("-fprofile-instrument=llvm");
+ if (PGOGenerateArg->getOption().matches(
+ options::OPT_fprofile_generate_EQ)) {
+ SmallString<128> Path(PGOGenerateArg->getValue());
+ llvm::sys::path::append(Path, "default_%m.profraw");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-fprofile-instrument-path=") + Path));
+ }
+ }
+
+ if (ProfileUseArg) {
+ if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ))
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-fprofile-instrument-use-path=") + ProfileUseArg->getValue()));
+ else if ((ProfileUseArg->getOption().matches(
+ options::OPT_fprofile_use_EQ) ||
+ ProfileUseArg->getOption().matches(
+ options::OPT_fprofile_instr_use))) {
+ SmallString<128> Path(
+ ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue());
+ if (Path.empty() || llvm::sys::fs::is_directory(Path))
+ llvm::sys::path::append(Path, "default.profdata");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-fprofile-instrument-use-path=") + Path));
+ }
+ }
+
+ if (Args.hasArg(options::OPT_ftest_coverage) ||
+ Args.hasArg(options::OPT_coverage))
+ CmdArgs.push_back("-femit-coverage-notes");
+ if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
+ false) ||
+ Args.hasArg(options::OPT_coverage))
+ CmdArgs.push_back("-femit-coverage-data");
+
+ if (Args.hasFlag(options::OPT_fcoverage_mapping,
+ options::OPT_fno_coverage_mapping, false)) {
+ if (!ProfileGenerateArg)
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << "-fcoverage-mapping"
+ << "-fprofile-instr-generate";
+
+ CmdArgs.push_back("-fcoverage-mapping");
+ }
+
+ if (C.getArgs().hasArg(options::OPT_c) ||
+ C.getArgs().hasArg(options::OPT_S)) {
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-coverage-notes-file");
+ SmallString<128> OutputFilename;
+ if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
+ OutputFilename = FinalOutput->getValue();
+ else
+ OutputFilename = llvm::sys::path::filename(Output.getBaseInput());
+ SmallString<128> CoverageFilename = OutputFilename;
+ if (llvm::sys::path::is_relative(CoverageFilename)) {
+ SmallString<128> Pwd;
+ if (!llvm::sys::fs::current_path(Pwd)) {
+ llvm::sys::path::append(Pwd, CoverageFilename);
+ CoverageFilename.swap(Pwd);
+ }
+ }
+ llvm::sys::path::replace_extension(CoverageFilename, "gcno");
+ CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
+
+ // Leave -fprofile-dir= an unused argument unless .gcda emission is
+ // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider
+ // the flag used. There is no -fno-profile-dir, so the user has no
+ // targeted way to suppress the warning.
+ if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_coverage)) {
+ CmdArgs.push_back("-coverage-data-file");
+ if (Arg *FProfileDir = Args.getLastArg(options::OPT_fprofile_dir)) {
+ CoverageFilename = FProfileDir->getValue();
+ llvm::sys::path::append(CoverageFilename, OutputFilename);
+ }
+ llvm::sys::path::replace_extension(CoverageFilename, "gcda");
+ CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
+ }
+ }
+ }
+}
+
+/// \brief Check whether the given input tree contains any compilation actions.
+static bool ContainsCompileAction(const Action *A) {
+ if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A))
+ return true;
+
+ for (const auto &AI : A->inputs())
+ if (ContainsCompileAction(AI))
+ return true;
+
+ return false;
+}
+
+/// \brief Check if -relax-all should be passed to the internal assembler.
+/// This is done by default when compiling non-assembler source with -O0.
+static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
+ bool RelaxDefault = true;
+
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ RelaxDefault = A->getOption().matches(options::OPT_O0);
+
+ if (RelaxDefault) {
+ RelaxDefault = false;
+ for (const auto &Act : C.getActions()) {
+ if (ContainsCompileAction(Act)) {
+ RelaxDefault = true;
+ break;
+ }
+ }
+ }
+
+ return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all,
+ RelaxDefault);
+}
+
+// Extract the integer N from a string spelled "-dwarf-N", returning 0
+// on mismatch. The StringRef input (rather than an Arg) allows
+// for use by the "-Xassembler" option parser.
+static unsigned DwarfVersionNum(StringRef ArgValue) {
+ return llvm::StringSwitch<unsigned>(ArgValue)
+ .Case("-gdwarf-2", 2)
+ .Case("-gdwarf-3", 3)
+ .Case("-gdwarf-4", 4)
+ .Case("-gdwarf-5", 5)
+ .Default(0);
+}
+
+static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
+ codegenoptions::DebugInfoKind DebugInfoKind,
+ unsigned DwarfVersion,
+ llvm::DebuggerKind DebuggerTuning) {
+ switch (DebugInfoKind) {
+ case codegenoptions::DebugLineTablesOnly:
+ CmdArgs.push_back("-debug-info-kind=line-tables-only");
+ break;
+ case codegenoptions::LimitedDebugInfo:
+ CmdArgs.push_back("-debug-info-kind=limited");
+ break;
+ case codegenoptions::FullDebugInfo:
+ CmdArgs.push_back("-debug-info-kind=standalone");
+ break;
+ default:
+ break;
+ }
+ if (DwarfVersion > 0)
+ CmdArgs.push_back(
+ Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion)));
+ switch (DebuggerTuning) {
+ case llvm::DebuggerKind::GDB:
+ CmdArgs.push_back("-debugger-tuning=gdb");
+ break;
+ case llvm::DebuggerKind::LLDB:
+ CmdArgs.push_back("-debugger-tuning=lldb");
+ break;
+ case llvm::DebuggerKind::SCE:
+ CmdArgs.push_back("-debugger-tuning=sce");
+ break;
+ default:
+ break;
+ }
+}
+
+static void RenderDebugInfoCompressionArgs(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const Driver &D) {
+ const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ);
+ if (!A)
+ return;
+
+ if (A->getOption().getID() == options::OPT_gz) {
+ if (llvm::zlib::isAvailable())
+ CmdArgs.push_back("-compress-debug-sections");
+ else
+ D.Diag(diag::warn_debug_compression_unavailable);
+ return;
+ }
+
+ StringRef Value = A->getValue();
+ if (Value == "none") {
+ CmdArgs.push_back("-compress-debug-sections=none");
+ } else if (Value == "zlib" || Value == "zlib-gnu") {
+ if (llvm::zlib::isAvailable()) {
+ CmdArgs.push_back(
+ Args.MakeArgString("-compress-debug-sections=" + Twine(Value)));
+ } else {
+ D.Diag(diag::warn_debug_compression_unavailable);
+ }
+ } else {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+}
+
+static const char *RelocationModelName(llvm::Reloc::Model Model) {
+ switch (Model) {
+ case llvm::Reloc::Static:
+ return "static";
+ case llvm::Reloc::PIC_:
+ return "pic";
+ case llvm::Reloc::DynamicNoPIC:
+ return "dynamic-no-pic";
+ case llvm::Reloc::ROPI:
+ return "ropi";
+ case llvm::Reloc::RWPI:
+ return "rwpi";
+ case llvm::Reloc::ROPI_RWPI:
+ return "ropi-rwpi";
+ }
+ llvm_unreachable("Unknown Reloc::Model kind");
+}
+
+void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
+ const Driver &D, const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs) const {
+ Arg *A;
+ const bool IsIAMCU = getToolChain().getTriple().isOSIAMCU();
+
+ CheckPreprocessingOptions(D, Args);
+
+ Args.AddLastArg(CmdArgs, options::OPT_C);
+ Args.AddLastArg(CmdArgs, options::OPT_CC);
+
+ // Handle dependency file generation.
+ if ((A = Args.getLastArg(options::OPT_M, options::OPT_MM)) ||
+ (A = Args.getLastArg(options::OPT_MD)) ||
+ (A = Args.getLastArg(options::OPT_MMD))) {
+ // Determine the output location.
+ const char *DepFile;
+ if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
+ DepFile = MF->getValue();
+ C.addFailureResultFile(DepFile, &JA);
+ } else if (Output.getType() == types::TY_Dependencies) {
+ DepFile = Output.getFilename();
+ } else if (A->getOption().matches(options::OPT_M) ||
+ A->getOption().matches(options::OPT_MM)) {
+ DepFile = "-";
+ } else {
+ DepFile = getDependencyFileName(Args, Inputs);
+ C.addFailureResultFile(DepFile, &JA);
+ }
+ CmdArgs.push_back("-dependency-file");
+ CmdArgs.push_back(DepFile);
+
+ // Add a default target if one wasn't specified.
+ if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) {
+ const char *DepTarget;
+
+ // If user provided -o, that is the dependency target, except
+ // when we are only generating a dependency file.
+ Arg *OutputOpt = Args.getLastArg(options::OPT_o);
+ if (OutputOpt && Output.getType() != types::TY_Dependencies) {
+ DepTarget = OutputOpt->getValue();
+ } else {
+ // Otherwise derive from the base input.
+ //
+ // FIXME: This should use the computed output file location.
+ SmallString<128> P(Inputs[0].getBaseInput());
+ llvm::sys::path::replace_extension(P, "o");
+ DepTarget = Args.MakeArgString(llvm::sys::path::filename(P));
+ }
+
+ if (!A->getOption().matches(options::OPT_MD) && !A->getOption().matches(options::OPT_MMD)) {
+ CmdArgs.push_back("-w");
+ }
+ CmdArgs.push_back("-MT");
+ SmallString<128> Quoted;
+ QuoteTarget(DepTarget, Quoted);
+ CmdArgs.push_back(Args.MakeArgString(Quoted));
+ }
+
+ if (A->getOption().matches(options::OPT_M) ||
+ A->getOption().matches(options::OPT_MD))
+ CmdArgs.push_back("-sys-header-deps");
+ if ((isa<PrecompileJobAction>(JA) &&
+ !Args.hasArg(options::OPT_fno_module_file_deps)) ||
+ Args.hasArg(options::OPT_fmodule_file_deps))
+ CmdArgs.push_back("-module-file-deps");
+ }
+
+ if (Args.hasArg(options::OPT_MG)) {
+ if (!A || A->getOption().matches(options::OPT_MD) ||
+ A->getOption().matches(options::OPT_MMD))
+ D.Diag(diag::err_drv_mg_requires_m_or_mm);
+ CmdArgs.push_back("-MG");
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_MP);
+ Args.AddLastArg(CmdArgs, options::OPT_MV);
+
+ // Convert all -MQ <target> args to -MT <quoted target>
+ for (const Arg *A : Args.filtered(options::OPT_MT, options::OPT_MQ)) {
+ A->claim();
+
+ if (A->getOption().matches(options::OPT_MQ)) {
+ CmdArgs.push_back("-MT");
+ SmallString<128> Quoted;
+ QuoteTarget(A->getValue(), Quoted);
+ CmdArgs.push_back(Args.MakeArgString(Quoted));
+
+ // -MT flag - no change
+ } else {
+ A->render(Args, CmdArgs);
+ }
+ }
+
+ // Add offload include arguments specific for CUDA. This must happen before
+ // we -I or -include anything else, because we must pick up the CUDA headers
+ // from the particular CUDA installation, rather than from e.g.
+ // /usr/local/include.
+ if (JA.isOffloading(Action::OFK_Cuda))
+ getToolChain().AddCudaIncludeArgs(Args, CmdArgs);
+
+ // Add -i* options, and automatically translate to
+ // -include-pch/-include-pth for transparent PCH support. It's
+ // wonky, but we include looking for .gch so we can support seamless
+ // replacement into a build system already set up to be generating
+ // .gch files.
+ int YcIndex = -1, YuIndex = -1;
+ {
+ int AI = -1;
+ const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc);
+ const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu);
+ for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) {
+ // Walk the whole i_Group and skip non "-include" flags so that the index
+ // here matches the index in the next loop below.
+ ++AI;
+ if (!A->getOption().matches(options::OPT_include))
+ continue;
+ if (YcArg && strcmp(A->getValue(), YcArg->getValue()) == 0)
+ YcIndex = AI;
+ if (YuArg && strcmp(A->getValue(), YuArg->getValue()) == 0)
+ YuIndex = AI;
+ }
+ }
+ if (isa<PrecompileJobAction>(JA) && YcIndex != -1) {
+ Driver::InputList Inputs;
+ D.BuildInputs(getToolChain(), C.getArgs(), Inputs);
+ assert(Inputs.size() == 1 && "Need one input when building pch");
+ CmdArgs.push_back(Args.MakeArgString(Twine("-find-pch-source=") +
+ Inputs[0].second->getValue()));
+ }
+
+ bool RenderedImplicitInclude = false;
+ int AI = -1;
+ for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) {
+ ++AI;
+
+ if (getToolChain().getDriver().IsCLMode() &&
+ A->getOption().matches(options::OPT_include)) {
+ // In clang-cl mode, /Ycfoo.h means that all code up to a foo.h
+ // include is compiled into foo.h, and everything after goes into
+ // the .obj file. /Yufoo.h means that all includes prior to and including
+ // foo.h are completely skipped and replaced with a use of the pch file
+ // for foo.h. (Each flag can have at most one value, multiple /Yc flags
+ // just mean that the last one wins.) If /Yc and /Yu are both present
+ // and refer to the same file, /Yc wins.
+ // Note that OPT__SLASH_FI gets mapped to OPT_include.
+ // FIXME: The code here assumes that /Yc and /Yu refer to the same file.
+ // cl.exe seems to support both flags with different values, but that
+ // seems strange (which flag does /Fp now refer to?), so don't implement
+ // that until someone needs it.
+ int PchIndex = YcIndex != -1 ? YcIndex : YuIndex;
+ if (PchIndex != -1) {
+ if (isa<PrecompileJobAction>(JA)) {
+ // When building the pch, skip all includes after the pch.
+ assert(YcIndex != -1 && PchIndex == YcIndex);
+ if (AI >= YcIndex)
+ continue;
+ } else {
+ // When using the pch, skip all includes prior to the pch.
+ if (AI < PchIndex) {
+ A->claim();
+ continue;
+ }
+ if (AI == PchIndex) {
+ A->claim();
+ CmdArgs.push_back("-include-pch");
+ CmdArgs.push_back(
+ Args.MakeArgString(D.GetClPchPath(C, A->getValue())));
+ continue;
+ }
+ }
+ }
+ } else if (A->getOption().matches(options::OPT_include)) {
+ // Handling of gcc-style gch precompiled headers.
+ bool IsFirstImplicitInclude = !RenderedImplicitInclude;
+ RenderedImplicitInclude = true;
+
+ // Use PCH if the user requested it.
+ bool UsePCH = D.CCCUsePCH;
+
+ bool FoundPTH = false;
+ bool FoundPCH = false;
+ SmallString<128> P(A->getValue());
+ // We want the files to have a name like foo.h.pch. Add a dummy extension
+ // so that replace_extension does the right thing.
+ P += ".dummy";
+ if (UsePCH) {
+ llvm::sys::path::replace_extension(P, "pch");
+ if (llvm::sys::fs::exists(P))
+ FoundPCH = true;
+ }
+
+ if (!FoundPCH) {
+ llvm::sys::path::replace_extension(P, "pth");
+ if (llvm::sys::fs::exists(P))
+ FoundPTH = true;
+ }
+
+ if (!FoundPCH && !FoundPTH) {
+ llvm::sys::path::replace_extension(P, "gch");
+ if (llvm::sys::fs::exists(P)) {
+ FoundPCH = UsePCH;
+ FoundPTH = !UsePCH;
+ }
+ }
+
+ if (FoundPCH || FoundPTH) {
+ if (IsFirstImplicitInclude) {
+ A->claim();
+ if (UsePCH)
+ CmdArgs.push_back("-include-pch");
+ else
+ CmdArgs.push_back("-include-pth");
+ CmdArgs.push_back(Args.MakeArgString(P));
+ continue;
+ } else {
+ // Ignore the PCH if not first on command line and emit warning.
+ D.Diag(diag::warn_drv_pch_not_first_include) << P
+ << A->getAsString(Args);
+ }
+ }
+ } else if (A->getOption().matches(options::OPT_isystem_after)) {
+ // Handling of paths which must come late. These entries are handled by
+ // the toolchain itself after the resource dir is inserted in the right
+ // search order.
+ // Do not claim the argument so that the use of the argument does not
+ // silently go unnoticed on toolchains which do not honour the option.
+ continue;
+ }
+
+ // Not translated, render as usual.
+ A->claim();
+ A->render(Args, CmdArgs);
+ }
+
+ Args.AddAllArgs(CmdArgs,
+ {options::OPT_D, options::OPT_U, options::OPT_I_Group,
+ options::OPT_F, options::OPT_index_header_map});
+
+ // Add -Wp, and -Xpreprocessor if using the preprocessor.
+
+ // FIXME: There is a very unfortunate problem here, some troubled
+ // souls abuse -Wp, to pass preprocessor options in gcc syntax. To
+ // really support that we would have to parse and then translate
+ // those options. :(
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA,
+ options::OPT_Xpreprocessor);
+
+ // -I- is a deprecated GCC feature, reject it.
+ if (Arg *A = Args.getLastArg(options::OPT_I_))
+ D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args);
+
+ // If we have a --sysroot, and don't have an explicit -isysroot flag, add an
+ // -isysroot to the CC1 invocation.
+ StringRef sysroot = C.getSysRoot();
+ if (sysroot != "") {
+ if (!Args.hasArg(options::OPT_isysroot)) {
+ CmdArgs.push_back("-isysroot");
+ CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
+ }
+ }
+
+ // Parse additional include paths from environment variables.
+ // FIXME: We should probably sink the logic for handling these from the
+ // frontend into the driver. It will allow deleting 4 otherwise unused flags.
+ // CPATH - included following the user specified includes (but prior to
+ // builtin and standard includes).
+ addDirectoryList(Args, CmdArgs, "-I", "CPATH");
+ // C_INCLUDE_PATH - system includes enabled when compiling C.
+ addDirectoryList(Args, CmdArgs, "-c-isystem", "C_INCLUDE_PATH");
+ // CPLUS_INCLUDE_PATH - system includes enabled when compiling C++.
+ addDirectoryList(Args, CmdArgs, "-cxx-isystem", "CPLUS_INCLUDE_PATH");
+ // OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC.
+ addDirectoryList(Args, CmdArgs, "-objc-isystem", "OBJC_INCLUDE_PATH");
+ // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++.
+ addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH");
+
+ // While adding the include arguments, we also attempt to retrieve the
+ // arguments of related offloading toolchains or arguments that are specific
+ // of an offloading programming model.
+
+ // Add C++ include arguments, if needed.
+ if (types::isCXX(Inputs[0].getType()))
+ forAllAssociatedToolChains(C, JA, getToolChain(),
+ [&Args, &CmdArgs](const ToolChain &TC) {
+ TC.AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
+ });
+
+ // Add system include arguments for all targets but IAMCU.
+ if (!IsIAMCU)
+ forAllAssociatedToolChains(C, JA, getToolChain(),
+ [&Args, &CmdArgs](const ToolChain &TC) {
+ TC.AddClangSystemIncludeArgs(Args, CmdArgs);
+ });
+ else {
+ // For IAMCU add special include arguments.
+ getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs);
+ }
+}
+
+// FIXME: Move to target hook.
+static bool isSignedCharDefault(const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ default:
+ return true;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ if (Triple.isOSDarwin() || Triple.isOSWindows())
+ return true;
+ return false;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ if (Triple.isOSDarwin())
+ return true;
+ return false;
+
+ case llvm::Triple::hexagon:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::systemz:
+ case llvm::Triple::xcore:
+ return false;
+ }
+}
+
+static bool isNoCommonDefault(const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ default:
+ return false;
+
+ case llvm::Triple::xcore:
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ return true;
+ }
+}
+
+void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
+ ArgStringList &CmdArgs, bool KernelOrKext) const {
+ // Select the ABI to use.
+ // FIXME: Support -meabi.
+ // FIXME: Parts of this are duplicated in the backend, unify this somehow.
+ const char *ABIName = nullptr;
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
+ ABIName = A->getValue();
+ else {
+ std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false);
+ ABIName = llvm::ARM::computeDefaultTargetABI(Triple, CPU).data();
+ }
+
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(ABIName);
+
+ // Determine floating point ABI from the options & target defaults.
+ arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args);
+ if (ABI == arm::FloatABI::Soft) {
+ // Floating point operations and argument passing are soft.
+ // FIXME: This changes CPP defines, we need -target-soft-float.
+ CmdArgs.push_back("-msoft-float");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
+ } else if (ABI == arm::FloatABI::SoftFP) {
+ // Floating point operations are hard, but argument passing is soft.
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
+ } else {
+ // Floating point operations and argument passing are hard.
+ assert(ABI == arm::FloatABI::Hard && "Invalid float abi!");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("hard");
+ }
+
+ // Forward the -mglobal-merge option for explicit control over the pass.
+ if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
+ options::OPT_mno_global_merge)) {
+ CmdArgs.push_back("-backend-option");
+ if (A->getOption().matches(options::OPT_mno_global_merge))
+ CmdArgs.push_back("-arm-global-merge=false");
+ else
+ CmdArgs.push_back("-arm-global-merge=true");
+ }
+
+ if (!Args.hasFlag(options::OPT_mimplicit_float,
+ options::OPT_mno_implicit_float, true))
+ CmdArgs.push_back("-no-implicit-float");
+}
+
+void Clang::AddAArch64TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
+
+ if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) ||
+ Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext))
+ CmdArgs.push_back("-disable-red-zone");
+
+ if (!Args.hasFlag(options::OPT_mimplicit_float,
+ options::OPT_mno_implicit_float, true))
+ CmdArgs.push_back("-no-implicit-float");
+
+ const char *ABIName = nullptr;
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
+ ABIName = A->getValue();
+ else if (Triple.isOSDarwin())
+ ABIName = "darwinpcs";
+ else
+ ABIName = "aapcs";
+
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(ABIName);
+
+ if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769,
+ options::OPT_mno_fix_cortex_a53_835769)) {
+ CmdArgs.push_back("-backend-option");
+ if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769))
+ CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1");
+ else
+ CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0");
+ } else if (Triple.isAndroid()) {
+ // Enabled A53 errata (835769) workaround by default on android
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1");
+ }
+
+ // Forward the -mglobal-merge option for explicit control over the pass.
+ if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
+ options::OPT_mno_global_merge)) {
+ CmdArgs.push_back("-backend-option");
+ if (A->getOption().matches(options::OPT_mno_global_merge))
+ CmdArgs.push_back("-aarch64-enable-global-merge=false");
+ else
+ CmdArgs.push_back("-aarch64-enable-global-merge=true");
+ }
+}
+
+void Clang::AddMIPSTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getDriver();
+ StringRef CPUName;
+ StringRef ABIName;
+ const llvm::Triple &Triple = getToolChain().getTriple();
+ mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
+
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(ABIName.data());
+
+ mips::FloatABI ABI = mips::getMipsFloatABI(D, Args);
+ if (ABI == mips::FloatABI::Soft) {
+ // Floating point operations and argument passing are soft.
+ CmdArgs.push_back("-msoft-float");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
+ } else {
+ // Floating point operations and argument passing are hard.
+ assert(ABI == mips::FloatABI::Hard && "Invalid float abi!");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("hard");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
+ if (A->getOption().matches(options::OPT_mxgot)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mxgot");
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1,
+ options::OPT_mno_ldc1_sdc1)) {
+ if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mno-ldc1-sdc1");
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division,
+ options::OPT_mno_check_zero_division)) {
+ if (A->getOption().matches(options::OPT_mno_check_zero_division)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mno-check-zero-division");
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_G)) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v));
+ A->claim();
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mcompact_branches_EQ)) {
+ StringRef Val = StringRef(A->getValue());
+ if (mips::hasCompactBranches(CPUName)) {
+ if (Val == "never" || Val == "always" || Val == "optimal") {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val));
+ } else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Val;
+ } else
+ D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName;
+ }
+}
+
+void Clang::AddPPCTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Select the ABI to use.
+ const char *ABIName = nullptr;
+ if (getToolChain().getTriple().isOSLinux())
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::ppc64: {
+ // When targeting a processor that supports QPX, or if QPX is
+ // specifically enabled, default to using the ABI that supports QPX (so
+ // long as it is not specifically disabled).
+ bool HasQPX = false;
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ HasQPX = A->getValue() == StringRef("a2q");
+ HasQPX = Args.hasFlag(options::OPT_mqpx, options::OPT_mno_qpx, HasQPX);
+ if (HasQPX) {
+ ABIName = "elfv1-qpx";
+ break;
+ }
+
+ ABIName = "elfv1";
+ break;
+ }
+ case llvm::Triple::ppc64le:
+ ABIName = "elfv2";
+ break;
+ default:
+ break;
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
+ // The ppc64 linux abis are all "altivec" abis by default. Accept and ignore
+ // the option if given as we don't have backend support for any targets
+ // that don't use the altivec abi.
+ if (StringRef(A->getValue()) != "altivec")
+ ABIName = A->getValue();
+
+ ppc::FloatABI FloatABI =
+ ppc::getPPCFloatABI(getToolChain().getDriver(), Args);
+
+ if (FloatABI == ppc::FloatABI::Soft) {
+ // Floating point operations and argument passing are soft.
+ CmdArgs.push_back("-msoft-float");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
+ } else {
+ // Floating point operations and argument passing are hard.
+ assert(FloatABI == ppc::FloatABI::Hard && "Invalid float abi!");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("hard");
+ }
+
+ if (ABIName) {
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(ABIName);
+ }
+}
+
+void Clang::AddSparcTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ sparc::FloatABI FloatABI =
+ sparc::getSparcFloatABI(getToolChain().getDriver(), Args);
+
+ if (FloatABI == sparc::FloatABI::Soft) {
+ // Floating point operations and argument passing are soft.
+ CmdArgs.push_back("-msoft-float");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
+ } else {
+ // Floating point operations and argument passing are hard.
+ assert(FloatABI == sparc::FloatABI::Hard && "Invalid float abi!");
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("hard");
+ }
+}
+
+void Clang::AddSystemZTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ if (Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false))
+ CmdArgs.push_back("-mbackchain");
+}
+
+void Clang::AddX86TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) ||
+ Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext))
+ CmdArgs.push_back("-disable-red-zone");
+
+ // Default to avoid implicit floating-point for kernel/kext code, but allow
+ // that to be overridden with -mno-soft-float.
+ bool NoImplicitFloat = (Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext));
+ if (Arg *A = Args.getLastArg(
+ options::OPT_msoft_float, options::OPT_mno_soft_float,
+ options::OPT_mimplicit_float, options::OPT_mno_implicit_float)) {
+ const Option &O = A->getOption();
+ NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) ||
+ O.matches(options::OPT_msoft_float));
+ }
+ if (NoImplicitFloat)
+ CmdArgs.push_back("-no-implicit-float");
+
+ if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value == "intel" || Value == "att") {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
+ } else {
+ getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+ }
+
+ // Set flags to support MCU ABI.
+ if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) {
+ CmdArgs.push_back("-mfloat-abi");
+ CmdArgs.push_back("soft");
+ CmdArgs.push_back("-mstack-alignment=4");
+ }
+}
+
+void Clang::AddHexagonTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-mqdsp6-compat");
+ CmdArgs.push_back("-Wreturn-type");
+
+ if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
+ std::string N = llvm::utostr(G.getValue());
+ std::string Opt = std::string("-hexagon-small-data-threshold=") + N;
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString(Opt));
+ }
+
+ if (!Args.hasArg(options::OPT_fno_short_enums))
+ CmdArgs.push_back("-fshort-enums");
+ if (Args.getLastArg(options::OPT_mieee_rnd_near)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-enable-hexagon-ieee-rnd-near");
+ }
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-machine-sink-split=0");
+}
+
+void Clang::AddLanaiTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ StringRef CPUName = A->getValue();
+
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString(CPUName));
+ }
+ if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
+ StringRef Value = A->getValue();
+ // Only support mregparm=4 to support old usage. Report error for all other
+ // cases.
+ int Mregparm;
+ if (Value.getAsInteger(10, Mregparm)) {
+ if (Mregparm != 4) {
+ getToolChain().getDriver().Diag(
+ diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+ }
+ }
+}
+
+void Clang::AddWebAssemblyTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Default to "hidden" visibility.
+ if (!Args.hasArg(options::OPT_fvisibility_EQ,
+ options::OPT_fvisibility_ms_compat)) {
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back("hidden");
+ }
+}
+
+void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
+ StringRef Target, const InputInfo &Output,
+ const InputInfo &Input, const ArgList &Args) const {
+ // If this is a dry run, do not create the compilation database file.
+ if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
+ return;
+
+ using llvm::yaml::escape;
+ const Driver &D = getToolChain().getDriver();
+
+ if (!CompilationDatabase) {
+ std::error_code EC;
+ auto File = llvm::make_unique<llvm::raw_fd_ostream>(Filename, EC, llvm::sys::fs::F_Text);
+ if (EC) {
+ D.Diag(clang::diag::err_drv_compilationdatabase) << Filename
+ << EC.message();
+ return;
+ }
+ CompilationDatabase = std::move(File);
+ }
+ auto &CDB = *CompilationDatabase;
+ SmallString<128> Buf;
+ if (llvm::sys::fs::current_path(Buf))
+ Buf = ".";
+ CDB << "{ \"directory\": \"" << escape(Buf) << "\"";
+ CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\"";
+ CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\"";
+ CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\"";
+ Buf = "-x";
+ Buf += types::getTypeName(Input.getType());
+ CDB << ", \"" << escape(Buf) << "\"";
+ if (!D.SysRoot.empty() && !Args.hasArg(options::OPT__sysroot_EQ)) {
+ Buf = "--sysroot=";
+ Buf += D.SysRoot;
+ CDB << ", \"" << escape(Buf) << "\"";
+ }
+ CDB << ", \"" << escape(Input.getFilename()) << "\"";
+ for (auto &A: Args) {
+ auto &O = A->getOption();
+ // Skip language selection, which is positional.
+ if (O.getID() == options::OPT_x)
+ continue;
+ // Skip writing dependency output and the compilation database itself.
+ if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group)
+ continue;
+ // Skip inputs.
+ if (O.getKind() == Option::InputClass)
+ continue;
+ // All other arguments are quoted and appended.
+ ArgStringList ASL;
+ A->render(Args, ASL);
+ for (auto &it: ASL)
+ CDB << ", \"" << escape(it) << "\"";
+ }
+ Buf = "--target=";
+ Buf += Target;
+ CDB << ", \"" << escape(Buf) << "\"]},\n";
+}
+
+static void CollectArgsForIntegratedAssembler(Compilation &C,
+ const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const Driver &D) {
+ if (UseRelaxAll(C, Args))
+ CmdArgs.push_back("-mrelax-all");
+
+ // Only default to -mincremental-linker-compatible if we think we are
+ // targeting the MSVC linker.
+ bool DefaultIncrementalLinkerCompatible =
+ C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
+ if (Args.hasFlag(options::OPT_mincremental_linker_compatible,
+ options::OPT_mno_incremental_linker_compatible,
+ DefaultIncrementalLinkerCompatible))
+ CmdArgs.push_back("-mincremental-linker-compatible");
+
+ switch (C.getDefaultToolChain().getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ if (Arg *A = Args.getLastArg(options::OPT_mimplicit_it_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value == "always" || Value == "never" || Value == "arm" ||
+ Value == "thumb") {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-arm-implicit-it=" + Value));
+ } else {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // When passing -I arguments to the assembler we sometimes need to
+ // unconditionally take the next argument. For example, when parsing
+ // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the
+ // -Wa,-I arg and when parsing '-Wa,-I,foo' we need to accept the 'foo'
+ // arg after parsing the '-I' arg.
+ bool TakeNextArg = false;
+
+ bool UseRelaxRelocations = ENABLE_X86_RELAX_RELOCATIONS;
+ const char *MipsTargetFeature = nullptr;
+ for (const Arg *A :
+ Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
+ A->claim();
+
+ for (StringRef Value : A->getValues()) {
+ if (TakeNextArg) {
+ CmdArgs.push_back(Value.data());
+ TakeNextArg = false;
+ continue;
+ }
+
+ if (C.getDefaultToolChain().getTriple().isOSBinFormatCOFF() &&
+ Value == "-mbig-obj")
+ continue; // LLVM handles bigobj automatically
+
+ switch (C.getDefaultToolChain().getArch()) {
+ default:
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ if (Value == "--trap") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+use-tcc-in-div");
+ continue;
+ }
+ if (Value == "--break") {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-use-tcc-in-div");
+ continue;
+ }
+ if (Value.startswith("-msoft-float")) {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+soft-float");
+ continue;
+ }
+ if (Value.startswith("-mhard-float")) {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-soft-float");
+ continue;
+ }
+
+ MipsTargetFeature = llvm::StringSwitch<const char *>(Value)
+ .Case("-mips1", "+mips1")
+ .Case("-mips2", "+mips2")
+ .Case("-mips3", "+mips3")
+ .Case("-mips4", "+mips4")
+ .Case("-mips5", "+mips5")
+ .Case("-mips32", "+mips32")
+ .Case("-mips32r2", "+mips32r2")
+ .Case("-mips32r3", "+mips32r3")
+ .Case("-mips32r5", "+mips32r5")
+ .Case("-mips32r6", "+mips32r6")
+ .Case("-mips64", "+mips64")
+ .Case("-mips64r2", "+mips64r2")
+ .Case("-mips64r3", "+mips64r3")
+ .Case("-mips64r5", "+mips64r5")
+ .Case("-mips64r6", "+mips64r6")
+ .Default(nullptr);
+ if (MipsTargetFeature)
+ continue;
+ }
+
+ if (Value == "-force_cpusubtype_ALL") {
+ // Do nothing, this is the default and we don't support anything else.
+ } else if (Value == "-L") {
+ CmdArgs.push_back("-msave-temp-labels");
+ } else if (Value == "--fatal-warnings") {
+ CmdArgs.push_back("-massembler-fatal-warnings");
+ } else if (Value == "--noexecstack") {
+ CmdArgs.push_back("-mnoexecstack");
+ } else if (Value.startswith("-compress-debug-sections") ||
+ Value.startswith("--compress-debug-sections") ||
+ Value == "-nocompress-debug-sections" ||
+ Value == "--nocompress-debug-sections") {
+ CmdArgs.push_back(Value.data());
+ } else if (Value == "-mrelax-relocations=yes" ||
+ Value == "--mrelax-relocations=yes") {
+ UseRelaxRelocations = true;
+ } else if (Value == "-mrelax-relocations=no" ||
+ Value == "--mrelax-relocations=no") {
+ UseRelaxRelocations = false;
+ } else if (Value.startswith("-I")) {
+ CmdArgs.push_back(Value.data());
+ // We need to consume the next argument if the current arg is a plain
+ // -I. The next arg will be the include directory.
+ if (Value == "-I")
+ TakeNextArg = true;
+ } else if (Value.startswith("-gdwarf-")) {
+ // "-gdwarf-N" options are not cc1as options.
+ unsigned DwarfVersion = DwarfVersionNum(Value);
+ if (DwarfVersion == 0) { // Send it onward, and let cc1as complain.
+ CmdArgs.push_back(Value.data());
+ } else {
+ RenderDebugEnablingArgs(Args, CmdArgs,
+ codegenoptions::LimitedDebugInfo,
+ DwarfVersion, llvm::DebuggerKind::Default);
+ }
+ } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") ||
+ Value.startswith("-mhwdiv") || Value.startswith("-march")) {
+ // Do nothing, we'll validate it later.
+ } else if (Value == "-defsym") {
+ if (A->getNumValues() != 2) {
+ D.Diag(diag::err_drv_defsym_invalid_format) << Value;
+ break;
+ }
+ const char *S = A->getValue(1);
+ auto Pair = StringRef(S).split('=');
+ auto Sym = Pair.first;
+ auto SVal = Pair.second;
+
+ if (Sym.empty() || SVal.empty()) {
+ D.Diag(diag::err_drv_defsym_invalid_format) << S;
+ break;
+ }
+ int64_t IVal;
+ if (SVal.getAsInteger(0, IVal)) {
+ D.Diag(diag::err_drv_defsym_invalid_symval) << SVal;
+ break;
+ }
+ CmdArgs.push_back(Value.data());
+ TakeNextArg = true;
+ } else {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+ }
+ }
+ if (UseRelaxRelocations)
+ CmdArgs.push_back("--mrelax-relocations");
+ if (MipsTargetFeature != nullptr) {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(MipsTargetFeature);
+ }
+}
+
+void Clang::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const ArgList &Args, const char *LinkingOutput) const {
+ const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
+ const std::string &TripleStr = Triple.getTriple();
+
+ bool KernelOrKext =
+ Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ // Check number of inputs for sanity. We need at least one input.
+ assert(Inputs.size() >= 1 && "Must have at least one input.");
+ const InputInfo &Input = Inputs[0];
+ // CUDA compilation may have multiple inputs (source file + results of
+ // device-side compilations). OpenMP device jobs also take the host IR as a
+ // second input. All other jobs are expected to have exactly one
+ // input.
+ bool IsCuda = JA.isOffloading(Action::OFK_Cuda);
+ bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
+ assert((IsCuda || (IsOpenMPDevice && Inputs.size() == 2) ||
+ Inputs.size() == 1) &&
+ "Unable to handle multiple inputs.");
+
+ bool IsWindowsGNU = getToolChain().getTriple().isWindowsGNUEnvironment();
+ bool IsWindowsCygnus =
+ getToolChain().getTriple().isWindowsCygwinEnvironment();
+ bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment();
+ bool IsPS4CPU = getToolChain().getTriple().isPS4CPU();
+ bool IsIAMCU = getToolChain().getTriple().isOSIAMCU();
+
+ // Adjust IsWindowsXYZ for CUDA compilations. Even when compiling in device
+ // mode (i.e., getToolchain().getTriple() is NVPTX, not Windows), we need to
+ // pass Windows-specific flags to cc1.
+ if (IsCuda) {
+ const llvm::Triple *AuxTriple = getToolChain().getAuxTriple();
+ IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment();
+ IsWindowsGNU |= AuxTriple && AuxTriple->isWindowsGNUEnvironment();
+ IsWindowsCygnus |= AuxTriple && AuxTriple->isWindowsCygwinEnvironment();
+ }
+
+ // C++ is not supported for IAMCU.
+ if (IsIAMCU && types::isCXX(Input.getType()))
+ D.Diag(diag::err_drv_clang_unsupported) << "C++ for IAMCU";
+
+ // Invoke ourselves in -cc1 mode.
+ //
+ // FIXME: Implement custom jobs for internal actions.
+ CmdArgs.push_back("-cc1");
+
+ // Add the "effective" target triple.
+ CmdArgs.push_back("-triple");
+ CmdArgs.push_back(Args.MakeArgString(TripleStr));
+
+ if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) {
+ DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args);
+ Args.ClaimAllArgs(options::OPT_MJ);
+ }
+
+ if (IsCuda) {
+ // We have to pass the triple of the host if compiling for a CUDA device and
+ // vice-versa.
+ std::string NormalizedTriple;
+ if (JA.isDeviceOffloading(Action::OFK_Cuda))
+ NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>()
+ ->getTriple()
+ .normalize();
+ else
+ NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Cuda>()
+ ->getTriple()
+ .normalize();
+
+ CmdArgs.push_back("-aux-triple");
+ CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
+ }
+
+ if (IsOpenMPDevice) {
+ // We have to pass the triple of the host if compiling for an OpenMP device.
+ std::string NormalizedTriple =
+ C.getSingleOffloadToolChain<Action::OFK_Host>()
+ ->getTriple()
+ .normalize();
+ CmdArgs.push_back("-aux-triple");
+ CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
+ }
+
+ if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm ||
+ Triple.getArch() == llvm::Triple::thumb)) {
+ unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
+ unsigned Version;
+ Triple.getArchName().substr(Offset).getAsInteger(10, Version);
+ if (Version < 7)
+ D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName()
+ << TripleStr;
+ }
+
+ // Push all default warning arguments that are specific to
+ // the given target. These come before user provided warning options
+ // are provided.
+ getToolChain().addClangWarningOptions(CmdArgs);
+
+ // Select the appropriate action.
+ RewriteKind rewriteKind = RK_None;
+
+ if (isa<AnalyzeJobAction>(JA)) {
+ assert(JA.getType() == types::TY_Plist && "Invalid output type.");
+ CmdArgs.push_back("-analyze");
+ } else if (isa<MigrateJobAction>(JA)) {
+ CmdArgs.push_back("-migrate");
+ } else if (isa<PreprocessJobAction>(JA)) {
+ if (Output.getType() == types::TY_Dependencies)
+ CmdArgs.push_back("-Eonly");
+ else {
+ CmdArgs.push_back("-E");
+ if (Args.hasArg(options::OPT_rewrite_objc) &&
+ !Args.hasArg(options::OPT_g_Group))
+ CmdArgs.push_back("-P");
+ }
+ } else if (isa<AssembleJobAction>(JA)) {
+ CmdArgs.push_back("-emit-obj");
+
+ CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D);
+
+ // Also ignore explicit -force_cpusubtype_ALL option.
+ (void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
+ } else if (isa<PrecompileJobAction>(JA)) {
+ // Use PCH if the user requested it.
+ bool UsePCH = D.CCCUsePCH;
+
+ if (JA.getType() == types::TY_Nothing)
+ CmdArgs.push_back("-fsyntax-only");
+ else if (JA.getType() == types::TY_ModuleFile)
+ CmdArgs.push_back("-emit-module-interface");
+ else if (UsePCH)
+ CmdArgs.push_back("-emit-pch");
+ else
+ CmdArgs.push_back("-emit-pth");
+ } else if (isa<VerifyPCHJobAction>(JA)) {
+ CmdArgs.push_back("-verify-pch");
+ } else {
+ assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
+ "Invalid action for clang tool.");
+ if (JA.getType() == types::TY_Nothing) {
+ CmdArgs.push_back("-fsyntax-only");
+ } else if (JA.getType() == types::TY_LLVM_IR ||
+ JA.getType() == types::TY_LTO_IR) {
+ CmdArgs.push_back("-emit-llvm");
+ } else if (JA.getType() == types::TY_LLVM_BC ||
+ JA.getType() == types::TY_LTO_BC) {
+ CmdArgs.push_back("-emit-llvm-bc");
+ } else if (JA.getType() == types::TY_PP_Asm) {
+ CmdArgs.push_back("-S");
+ } else if (JA.getType() == types::TY_AST) {
+ CmdArgs.push_back("-emit-pch");
+ } else if (JA.getType() == types::TY_ModuleFile) {
+ CmdArgs.push_back("-module-file-info");
+ } else if (JA.getType() == types::TY_RewrittenObjC) {
+ CmdArgs.push_back("-rewrite-objc");
+ rewriteKind = RK_NonFragile;
+ } else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
+ CmdArgs.push_back("-rewrite-objc");
+ rewriteKind = RK_Fragile;
+ } else {
+ assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
+ }
+
+ // Preserve use-list order by default when emitting bitcode, so that
+ // loading the bitcode up in 'opt' or 'llc' and running passes gives the
+ // same result as running passes here. For LTO, we don't need to preserve
+ // the use-list order, since serialization to bitcode is part of the flow.
+ if (JA.getType() == types::TY_LLVM_BC)
+ CmdArgs.push_back("-emit-llvm-uselists");
+
+ if (D.isUsingLTO()) {
+ Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ);
+
+ // The Darwin and PS4 linkers currently use the legacy LTO API, which
+ // does not support LTO unit features (CFI, whole program vtable opt)
+ // under ThinLTO.
+ if (!(getToolChain().getTriple().isOSDarwin() ||
+ getToolChain().getTriple().isPS4()) ||
+ D.getLTOMode() == LTOK_Full)
+ CmdArgs.push_back("-flto-unit");
+ }
+ }
+
+ if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) {
+ if (!types::isLLVMIR(Input.getType()))
+ D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args)
+ << "-x ir";
+ Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ);
+ }
+
+ // Embed-bitcode option.
+ if (C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO() &&
+ (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) {
+ // Add flags implied by -fembed-bitcode.
+ Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ);
+ // Disable all llvm IR level optimizations.
+ CmdArgs.push_back("-disable-llvm-passes");
+ }
+ if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO())
+ CmdArgs.push_back("-fembed-bitcode=marker");
+
+ // We normally speed up the clang process a bit by skipping destructors at
+ // exit, but when we're generating diagnostics we can rely on some of the
+ // cleanup.
+ if (!C.isForDiagnostics())
+ CmdArgs.push_back("-disable-free");
+
+// Disable the verification pass in -asserts builds.
+#ifdef NDEBUG
+ CmdArgs.push_back("-disable-llvm-verifier");
+ // Discard LLVM value names in -asserts builds.
+ CmdArgs.push_back("-discard-value-names");
+#endif
+
+ // Set the main file name, so that debug info works even with
+ // -save-temps.
+ CmdArgs.push_back("-main-file-name");
+ CmdArgs.push_back(getBaseInputName(Args, Input));
+
+ // Some flags which affect the language (via preprocessor
+ // defines).
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-static-define");
+
+ if (isa<AnalyzeJobAction>(JA)) {
+ // Enable region store model by default.
+ CmdArgs.push_back("-analyzer-store=region");
+
+ // Treat blocks as analysis entry points.
+ CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks");
+
+ CmdArgs.push_back("-analyzer-eagerly-assume");
+
+ // Add default argument set.
+ if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
+ CmdArgs.push_back("-analyzer-checker=core");
+ CmdArgs.push_back("-analyzer-checker=apiModeling");
+
+ if (!IsWindowsMSVC) {
+ CmdArgs.push_back("-analyzer-checker=unix");
+ } else {
+ // Enable "unix" checkers that also work on Windows.
+ CmdArgs.push_back("-analyzer-checker=unix.API");
+ CmdArgs.push_back("-analyzer-checker=unix.Malloc");
+ CmdArgs.push_back("-analyzer-checker=unix.MallocSizeof");
+ CmdArgs.push_back("-analyzer-checker=unix.MismatchedDeallocator");
+ CmdArgs.push_back("-analyzer-checker=unix.cstring.BadSizeArg");
+ CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg");
+ }
+
+ // Disable some unix checkers for PS4.
+ if (IsPS4CPU) {
+ CmdArgs.push_back("-analyzer-disable-checker=unix.API");
+ CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork");
+ }
+
+ if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
+ CmdArgs.push_back("-analyzer-checker=osx");
+
+ CmdArgs.push_back("-analyzer-checker=deadcode");
+
+ if (types::isCXX(Input.getType()))
+ CmdArgs.push_back("-analyzer-checker=cplusplus");
+
+ if (!IsPS4CPU) {
+ CmdArgs.push_back(
+ "-analyzer-checker=security.insecureAPI.UncheckedReturn");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp");
+ CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork");
+ }
+
+ // Default nullability checks.
+ CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull");
+ CmdArgs.push_back(
+ "-analyzer-checker=nullability.NullReturnedFromNonnull");
+ }
+
+ // Set the output format. The default is plist, for (lame) historical
+ // reasons.
+ CmdArgs.push_back("-analyzer-output");
+ if (Arg *A = Args.getLastArg(options::OPT__analyzer_output))
+ CmdArgs.push_back(A->getValue());
+ else
+ CmdArgs.push_back("plist");
+
+ // Disable the presentation of standard compiler warnings when
+ // using --analyze. We only want to show static analyzer diagnostics
+ // or frontend errors.
+ CmdArgs.push_back("-w");
+
+ // Add -Xanalyzer arguments when running as analyzer.
+ Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
+ }
+
+ CheckCodeGenerationOptions(D, Args);
+
+ llvm::Reloc::Model RelocationModel;
+ unsigned PICLevel;
+ bool IsPIE;
+ std::tie(RelocationModel, PICLevel, IsPIE) =
+ ParsePICArgs(getToolChain(), Args);
+
+ const char *RMName = RelocationModelName(RelocationModel);
+
+ if ((RelocationModel == llvm::Reloc::ROPI ||
+ RelocationModel == llvm::Reloc::ROPI_RWPI) &&
+ types::isCXX(Input.getType()) &&
+ !Args.hasArg(options::OPT_fallow_unsupported))
+ D.Diag(diag::err_drv_ropi_incompatible_with_cxx);
+
+ if (RMName) {
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back(RMName);
+ }
+ if (PICLevel > 0) {
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
+ if (IsPIE)
+ CmdArgs.push_back("-pic-is-pie");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_meabi)) {
+ CmdArgs.push_back("-meabi");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ CmdArgs.push_back("-mthread-model");
+ if (Arg *A = Args.getLastArg(options::OPT_mthread_model))
+ CmdArgs.push_back(A->getValue());
+ else
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().getThreadModel()));
+
+ Args.AddLastArg(CmdArgs, options::OPT_fveclib);
+
+ if (!Args.hasFlag(options::OPT_fmerge_all_constants,
+ options::OPT_fno_merge_all_constants))
+ CmdArgs.push_back("-fno-merge-all-constants");
+
+ // LLVM Code Generator Options.
+
+ if (Args.hasArg(options::OPT_frewrite_map_file) ||
+ Args.hasArg(options::OPT_frewrite_map_file_EQ)) {
+ for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file,
+ options::OPT_frewrite_map_file_EQ)) {
+ StringRef Map = A->getValue();
+ if (!llvm::sys::fs::exists(Map)) {
+ D.Diag(diag::err_drv_no_such_file) << Map;
+ } else {
+ CmdArgs.push_back("-frewrite-map-file");
+ CmdArgs.push_back(A->getValue());
+ A->claim();
+ }
+ }
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-warn-stack-size=" + v));
+ A->claim();
+ }
+
+ if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables,
+ true))
+ CmdArgs.push_back("-fno-jump-tables");
+
+ if (!Args.hasFlag(options::OPT_fpreserve_as_comments,
+ options::OPT_fno_preserve_as_comments, true))
+ CmdArgs.push_back("-fno-preserve-as-comments");
+
+ if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
+ CmdArgs.push_back("-mregparm");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return,
+ options::OPT_freg_struct_return)) {
+ if (getToolChain().getArch() != llvm::Triple::x86) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << getToolChain().getTriple().str();
+ } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) {
+ CmdArgs.push_back("-fpcc-struct-return");
+ } else {
+ assert(A->getOption().matches(options::OPT_freg_struct_return));
+ CmdArgs.push_back("-freg-struct-return");
+ }
+ }
+
+ if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
+ CmdArgs.push_back("-fdefault-calling-conv=stdcall");
+
+ if (shouldUseFramePointer(Args, getToolChain().getTriple()))
+ CmdArgs.push_back("-mdisable-fp-elim");
+ if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
+ options::OPT_fno_zero_initialized_in_bss))
+ CmdArgs.push_back("-mno-zero-initialized-in-bss");
+
+ bool OFastEnabled = isOptimizationLevelFast(Args);
+ // If -Ofast is the optimization level, then -fstrict-aliasing should be
+ // enabled. This alias option is being used to simplify the hasFlag logic.
+ OptSpecifier StrictAliasingAliasOption =
+ OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing;
+ // We turn strict aliasing off by default if we're in CL mode, since MSVC
+ // doesn't do any TBAA.
+ bool TBAAOnByDefault = !getToolChain().getDriver().IsCLMode();
+ if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
+ options::OPT_fno_strict_aliasing, TBAAOnByDefault))
+ CmdArgs.push_back("-relaxed-aliasing");
+ if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
+ options::OPT_fno_struct_path_tbaa))
+ CmdArgs.push_back("-no-struct-path-tbaa");
+ if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
+ false))
+ CmdArgs.push_back("-fstrict-enums");
+ if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
+ true))
+ CmdArgs.push_back("-fno-strict-return");
+ if (Args.hasFlag(options::OPT_fallow_editor_placeholders,
+ options::OPT_fno_allow_editor_placeholders, false))
+ CmdArgs.push_back("-fallow-editor-placeholders");
+ if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
+ options::OPT_fno_strict_vtable_pointers,
+ false))
+ CmdArgs.push_back("-fstrict-vtable-pointers");
+ if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
+ options::OPT_fno_optimize_sibling_calls))
+ CmdArgs.push_back("-mdisable-tail-calls");
+
+ // Handle segmented stacks.
+ if (Args.hasArg(options::OPT_fsplit_stack))
+ CmdArgs.push_back("-split-stacks");
+
+ // Handle various floating point optimization flags, mapping them to the
+ // appropriate LLVM code generation flags. This is complicated by several
+ // "umbrella" flags, so we do this by stepping through the flags incrementally
+ // adjusting what we think is enabled/disabled, then at the end settting the
+ // LLVM flags based on the final state.
+ bool HonorInfs = true;
+ bool HonorNans = true;
+ // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes.
+ bool MathErrno = getToolChain().IsMathErrnoDefault();
+ bool AssociativeMath = false;
+ bool ReciprocalMath = false;
+ bool SignedZeros = true;
+ bool TrappingMath = true;
+ StringRef DenormalFpMath = "";
+ StringRef FpContract = "";
+
+ for (Arg *A : Args) {
+ switch (A->getOption().getID()) {
+ // If this isn't an FP option skip the claim below
+ default:
+ continue;
+
+ // Options controlling individual features
+ case options::OPT_fhonor_infinities: HonorInfs = true; break;
+ case options::OPT_fno_honor_infinities: HonorInfs = false; break;
+ case options::OPT_fhonor_nans: HonorNans = true; break;
+ case options::OPT_fno_honor_nans: HonorNans = false; break;
+ case options::OPT_fmath_errno: MathErrno = true; break;
+ case options::OPT_fno_math_errno: MathErrno = false; break;
+ case options::OPT_fassociative_math: AssociativeMath = true; break;
+ case options::OPT_fno_associative_math: AssociativeMath = false; break;
+ case options::OPT_freciprocal_math: ReciprocalMath = true; break;
+ case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break;
+ case options::OPT_fsigned_zeros: SignedZeros = true; break;
+ case options::OPT_fno_signed_zeros: SignedZeros = false; break;
+ case options::OPT_ftrapping_math: TrappingMath = true; break;
+ case options::OPT_fno_trapping_math: TrappingMath = false; break;
+
+ case options::OPT_fdenormal_fp_math_EQ:
+ DenormalFpMath = A->getValue();
+ break;
+
+ // Validate and pass through -fp-contract option.
+ case options::OPT_ffp_contract: {
+ StringRef Val = A->getValue();
+ if (Val == "fast" || Val == "on" || Val == "off") {
+ FpContract = Val;
+ } else {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Val;
+ }
+ break;
+ }
+
+ case options::OPT_ffinite_math_only:
+ HonorInfs = false;
+ HonorNans = false;
+ break;
+ case options::OPT_fno_finite_math_only:
+ HonorInfs = true;
+ HonorNans = true;
+ break;
+
+ case options::OPT_funsafe_math_optimizations:
+ AssociativeMath = true;
+ ReciprocalMath = true;
+ SignedZeros = false;
+ TrappingMath = false;
+ break;
+ case options::OPT_fno_unsafe_math_optimizations:
+ AssociativeMath = false;
+ ReciprocalMath = false;
+ SignedZeros = true;
+ TrappingMath = true;
+ // -fno_unsafe_math_optimizations restores default denormal handling
+ DenormalFpMath = "";
+ break;
+
+ case options::OPT_Ofast:
+ // If -Ofast is the optimization level, then -ffast-math should be enabled
+ if (!OFastEnabled)
+ continue;
+ LLVM_FALLTHROUGH;
+ case options::OPT_ffast_math:
+ HonorInfs = false;
+ HonorNans = false;
+ MathErrno = false;
+ AssociativeMath = true;
+ ReciprocalMath = true;
+ SignedZeros = false;
+ TrappingMath = false;
+ // If fast-math is set then set the fp-contract mode to fast.
+ FpContract = "fast";
+ break;
+ case options::OPT_fno_fast_math:
+ HonorInfs = true;
+ HonorNans = true;
+ // Turning on -ffast-math (with either flag) removes the need for
+ // MathErrno. However, turning *off* -ffast-math merely restores the
+ // toolchain default (which may be false).
+ MathErrno = getToolChain().IsMathErrnoDefault();
+ AssociativeMath = false;
+ ReciprocalMath = false;
+ SignedZeros = true;
+ TrappingMath = true;
+ // -fno_fast_math restores default denormal and fpcontract handling
+ DenormalFpMath = "";
+ FpContract = "";
+ break;
+ }
+ // If we handled this option claim it
+ A->claim();
+ }
+
+ if (!HonorInfs)
+ CmdArgs.push_back("-menable-no-infs");
+
+ if (!HonorNans)
+ CmdArgs.push_back("-menable-no-nans");
+
+ if (MathErrno)
+ CmdArgs.push_back("-fmath-errno");
+
+ if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
+ !TrappingMath)
+ CmdArgs.push_back("-menable-unsafe-fp-math");
+
+ if (!SignedZeros)
+ CmdArgs.push_back("-fno-signed-zeros");
+
+ if (ReciprocalMath)
+ CmdArgs.push_back("-freciprocal-math");
+
+ if (!TrappingMath)
+ CmdArgs.push_back("-fno-trapping-math");
+
+ if (!DenormalFpMath.empty())
+ CmdArgs.push_back(Args.MakeArgString("-fdenormal-fp-math="+DenormalFpMath));
+
+ if (!FpContract.empty())
+ CmdArgs.push_back(Args.MakeArgString("-ffp-contract="+FpContract));
+
+ ParseMRecip(getToolChain().getDriver(), Args, CmdArgs);
+
+ // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the
+ // individual features enabled by -ffast-math instead of the option itself as
+ // that's consistent with gcc's behaviour.
+ if (!HonorInfs && !HonorNans && !MathErrno && AssociativeMath &&
+ ReciprocalMath && !SignedZeros && !TrappingMath)
+ CmdArgs.push_back("-ffast-math");
+
+ // Handle __FINITE_MATH_ONLY__ similarly.
+ if (!HonorInfs && !HonorNans)
+ CmdArgs.push_back("-ffinite-math-only");
+
+ // Decide whether to use verbose asm. Verbose assembly is the default on
+ // toolchains which have the integrated assembler on by default.
+ bool IsIntegratedAssemblerDefault =
+ getToolChain().IsIntegratedAssemblerDefault();
+ if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
+ IsIntegratedAssemblerDefault) ||
+ Args.hasArg(options::OPT_dA))
+ CmdArgs.push_back("-masm-verbose");
+
+ if (!Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as,
+ IsIntegratedAssemblerDefault))
+ CmdArgs.push_back("-no-integrated-as");
+
+ if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
+ CmdArgs.push_back("-mdebug-pass");
+ CmdArgs.push_back("Structure");
+ }
+ if (Args.hasArg(options::OPT_fdebug_pass_arguments)) {
+ CmdArgs.push_back("-mdebug-pass");
+ CmdArgs.push_back("Arguments");
+ }
+
+ // Enable -mconstructor-aliases except on darwin, where we have to work around
+ // a linker bug (see <rdar://problem/7651567>), and CUDA device code, where
+ // aliases aren't supported.
+ if (!getToolChain().getTriple().isOSDarwin() &&
+ !getToolChain().getTriple().isNVPTX())
+ CmdArgs.push_back("-mconstructor-aliases");
+
+ // Darwin's kernel doesn't support guard variables; just die if we
+ // try to use them.
+ if (KernelOrKext && getToolChain().getTriple().isOSDarwin())
+ CmdArgs.push_back("-fforbid-guard-variables");
+
+ if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields,
+ false)) {
+ CmdArgs.push_back("-mms-bitfields");
+ }
+
+ if (Args.hasFlag(options::OPT_mpie_copy_relocations,
+ options::OPT_mno_pie_copy_relocations,
+ false)) {
+ CmdArgs.push_back("-mpie-copy-relocations");
+ }
+
+ // This is a coarse approximation of what llvm-gcc actually does, both
+ // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
+ // complicated ways.
+ bool AsynchronousUnwindTables =
+ Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
+ options::OPT_fno_asynchronous_unwind_tables,
+ (getToolChain().IsUnwindTablesDefault(Args) ||
+ getToolChain().getSanitizerArgs().needsUnwindTables()) &&
+ !KernelOrKext);
+ if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
+ AsynchronousUnwindTables))
+ CmdArgs.push_back("-munwind-tables");
+
+ getToolChain().addClangTargetOptions(Args, CmdArgs,
+ JA.getOffloadingDeviceKind());
+
+ if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
+ CmdArgs.push_back("-mlimit-float-precision");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ // FIXME: Handle -mtune=.
+ (void)Args.hasArg(options::OPT_mtune_EQ);
+
+ if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
+ CmdArgs.push_back("-mcode-model");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ // Add the target cpu
+ std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false);
+ if (!CPU.empty()) {
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString(CPU));
+ }
+
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) {
+ CmdArgs.push_back("-mfpmath");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ // Add the target features
+ getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, false);
+
+ // Add target specific flags.
+ switch (getToolChain().getArch()) {
+ default:
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ // Use the effective triple, which takes into account the deployment target.
+ AddARMTargetArgs(Triple, Args, CmdArgs, KernelOrKext);
+ break;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ AddAArch64TargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ AddMIPSTargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ AddPPCTargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9:
+ AddSparcTargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::systemz:
+ AddSystemZTargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ AddX86TargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::lanai:
+ AddLanaiTargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::hexagon:
+ AddHexagonTargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ AddWebAssemblyTargetArgs(Args, CmdArgs);
+ break;
+ }
+
+ // The 'g' groups options involve a somewhat intricate sequence of decisions
+ // about what to pass from the driver to the frontend, but by the time they
+ // reach cc1 they've been factored into three well-defined orthogonal choices:
+ // * what level of debug info to generate
+ // * what dwarf version to write
+ // * what debugger tuning to use
+ // This avoids having to monkey around further in cc1 other than to disable
+ // codeview if not running in a Windows environment. Perhaps even that
+ // decision should be made in the driver as well though.
+ unsigned DwarfVersion = 0;
+ llvm::DebuggerKind DebuggerTuning = getToolChain().getDefaultDebuggerTuning();
+ // These two are potentially updated by AddClangCLArgs.
+ codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
+ bool EmitCodeView = false;
+
+ // Add clang-cl arguments.
+ types::ID InputType = Input.getType();
+ if (getToolChain().getDriver().IsCLMode())
+ AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView);
+
+ // Pass the linker version in use.
+ if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
+ CmdArgs.push_back("-target-linker-version");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (!shouldUseLeafFramePointer(Args, getToolChain().getTriple()))
+ CmdArgs.push_back("-momit-leaf-frame-pointer");
+
+ // Explicitly error on some things we know we don't support and can't just
+ // ignore.
+ if (!Args.hasArg(options::OPT_fallow_unsupported)) {
+ Arg *Unsupported;
+ if (types::isCXX(InputType) && getToolChain().getTriple().isOSDarwin() &&
+ getToolChain().getArch() == llvm::Triple::x86) {
+ if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) ||
+ (Unsupported = Args.getLastArg(options::OPT_mkernel)))
+ D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386)
+ << Unsupported->getOption().getName();
+ }
+ // The faltivec option has been superseded by the maltivec option.
+ if ((Unsupported = Args.getLastArg(options::OPT_faltivec)))
+ D.Diag(diag::err_drv_clang_unsupported_opt_faltivec)
+ << Unsupported->getOption().getName()
+ << "please use -maltivec and include altivec.h explicitly";
+ if ((Unsupported = Args.getLastArg(options::OPT_fno_altivec)))
+ D.Diag(diag::err_drv_clang_unsupported_opt_faltivec)
+ << Unsupported->getOption().getName() << "please use -mno-altivec";
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_v);
+ Args.AddLastArg(CmdArgs, options::OPT_H);
+ if (D.CCPrintHeaders && !D.CCGenDiagnostics) {
+ CmdArgs.push_back("-header-include-file");
+ CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename
+ : "-");
+ }
+ Args.AddLastArg(CmdArgs, options::OPT_P);
+ Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
+
+ if (D.CCLogDiagnostics && !D.CCGenDiagnostics) {
+ CmdArgs.push_back("-diagnostic-log-file");
+ CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename
+ : "-");
+ }
+
+ bool splitDwarfInlining =
+ Args.hasFlag(options::OPT_fsplit_dwarf_inlining,
+ options::OPT_fno_split_dwarf_inlining, true);
+
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ Arg *SplitDwarfArg = Args.getLastArg(options::OPT_gsplit_dwarf);
+ if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
+ // If the last option explicitly specified a debug-info level, use it.
+ if (A->getOption().matches(options::OPT_gN_Group)) {
+ DebugInfoKind = DebugLevelToInfoKind(*A);
+ // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses.
+ // But -gsplit-dwarf is not a g_group option, hence we have to check the
+ // order explicitly. (If -gsplit-dwarf wins, we fix DebugInfoKind later.)
+ // This gets a bit more complicated if you've disabled inline info in the
+ // skeleton CUs (splitDwarfInlining) - then there's value in composing
+ // split-dwarf and line-tables-only, so let those compose naturally in
+ // that case.
+ // And if you just turned off debug info, (-gsplit-dwarf -g0) - do that.
+ if (SplitDwarfArg) {
+ if (A->getIndex() > SplitDwarfArg->getIndex()) {
+ if (DebugInfoKind == codegenoptions::NoDebugInfo ||
+ (DebugInfoKind == codegenoptions::DebugLineTablesOnly &&
+ splitDwarfInlining))
+ SplitDwarfArg = nullptr;
+ } else if (splitDwarfInlining)
+ DebugInfoKind = codegenoptions::NoDebugInfo;
+ }
+ } else
+ // For any other 'g' option, use Limited.
+ DebugInfoKind = codegenoptions::LimitedDebugInfo;
+ }
+
+ // If a debugger tuning argument appeared, remember it.
+ if (Arg *A = Args.getLastArg(options::OPT_gTune_Group,
+ options::OPT_ggdbN_Group)) {
+ if (A->getOption().matches(options::OPT_glldb))
+ DebuggerTuning = llvm::DebuggerKind::LLDB;
+ else if (A->getOption().matches(options::OPT_gsce))
+ DebuggerTuning = llvm::DebuggerKind::SCE;
+ else
+ DebuggerTuning = llvm::DebuggerKind::GDB;
+ }
+
+ // If a -gdwarf argument appeared, remember it.
+ if (Arg *A = Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3,
+ options::OPT_gdwarf_4, options::OPT_gdwarf_5))
+ DwarfVersion = DwarfVersionNum(A->getSpelling());
+
+ // Forward -gcodeview. EmitCodeView might have been set by CL-compatibility
+ // argument parsing.
+ if (Args.hasArg(options::OPT_gcodeview) || EmitCodeView) {
+ // DwarfVersion remains at 0 if no explicit choice was made.
+ CmdArgs.push_back("-gcodeview");
+ } else if (DwarfVersion == 0 &&
+ DebugInfoKind != codegenoptions::NoDebugInfo) {
+ DwarfVersion = getToolChain().GetDefaultDwarfVersion();
+ }
+
+ // We ignore flag -gstrict-dwarf for now.
+ // And we handle flag -grecord-gcc-switches later with DwarfDebugFlags.
+ Args.ClaimAllArgs(options::OPT_g_flags_Group);
+
+ // Column info is included by default for everything except PS4 and CodeView.
+ // Clang doesn't track end columns, just starting columns, which, in theory,
+ // is fine for CodeView (and PDB). In practice, however, the Microsoft
+ // debuggers don't handle missing end columns well, so it's better not to
+ // include any column info.
+ if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info,
+ /*Default=*/ !IsPS4CPU && !(IsWindowsMSVC && EmitCodeView)))
+ CmdArgs.push_back("-dwarf-column-info");
+
+ // FIXME: Move backend command line options to the module.
+ // If -gline-tables-only is the last option it wins.
+ if (DebugInfoKind != codegenoptions::DebugLineTablesOnly &&
+ Args.hasArg(options::OPT_gmodules)) {
+ DebugInfoKind = codegenoptions::LimitedDebugInfo;
+ CmdArgs.push_back("-dwarf-ext-refs");
+ CmdArgs.push_back("-fmodule-format=obj");
+ }
+
+ // -gsplit-dwarf should turn on -g and enable the backend dwarf
+ // splitting and extraction.
+ // FIXME: Currently only works on Linux.
+ if (getToolChain().getTriple().isOSLinux()) {
+ if (!splitDwarfInlining)
+ CmdArgs.push_back("-fno-split-dwarf-inlining");
+ if (SplitDwarfArg) {
+ if (DebugInfoKind == codegenoptions::NoDebugInfo)
+ DebugInfoKind = codegenoptions::LimitedDebugInfo;
+ CmdArgs.push_back("-enable-split-dwarf");
+ }
+ }
+
+ // After we've dealt with all combinations of things that could
+ // make DebugInfoKind be other than None or DebugLineTablesOnly,
+ // figure out if we need to "upgrade" it to standalone debug info.
+ // We parse these two '-f' options whether or not they will be used,
+ // to claim them even if you wrote "-fstandalone-debug -gline-tables-only"
+ bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug,
+ options::OPT_fno_standalone_debug,
+ getToolChain().GetDefaultStandaloneDebug());
+ if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug)
+ DebugInfoKind = codegenoptions::FullDebugInfo;
+ RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
+ DebuggerTuning);
+
+ // -fdebug-macro turns on macro debug info generation.
+ if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro,
+ false))
+ CmdArgs.push_back("-debug-info-macro");
+
+ // -ggnu-pubnames turns on gnu style pubnames in the backend.
+ if (Args.hasArg(options::OPT_ggnu_pubnames)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-generate-gnu-dwarf-pub-sections");
+ }
+
+ // -gdwarf-aranges turns on the emission of the aranges section in the
+ // backend.
+ // Always enabled on the PS4.
+ if (Args.hasArg(options::OPT_gdwarf_aranges) || IsPS4CPU) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-generate-arange-section");
+ }
+
+ if (Args.hasFlag(options::OPT_fdebug_types_section,
+ options::OPT_fno_debug_types_section, false)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-generate-type-units");
+ }
+
+ RenderDebugInfoCompressionArgs(Args, CmdArgs, D);
+
+ bool UseSeparateSections = isUseSeparateSections(Triple);
+
+ if (Args.hasFlag(options::OPT_ffunction_sections,
+ options::OPT_fno_function_sections, UseSeparateSections)) {
+ CmdArgs.push_back("-ffunction-sections");
+ }
+
+ if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
+ UseSeparateSections)) {
+ CmdArgs.push_back("-fdata-sections");
+ }
+
+ if (!Args.hasFlag(options::OPT_funique_section_names,
+ options::OPT_fno_unique_section_names, true))
+ CmdArgs.push_back("-fno-unique-section-names");
+
+ Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions);
+
+ addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs);
+
+ if (auto *ABICompatArg = Args.getLastArg(options::OPT_fclang_abi_compat_EQ))
+ ABICompatArg->render(Args, CmdArgs);
+
+ // Add runtime flag for PS4 when PGO or Coverage are enabled.
+ if (getToolChain().getTriple().isPS4CPU())
+ PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs);
+
+ // Pass options for controlling the default header search paths.
+ if (Args.hasArg(options::OPT_nostdinc)) {
+ CmdArgs.push_back("-nostdsysteminc");
+ CmdArgs.push_back("-nobuiltininc");
+ } else {
+ if (Args.hasArg(options::OPT_nostdlibinc))
+ CmdArgs.push_back("-nostdsysteminc");
+ Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
+ Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
+ }
+
+ // Pass the path to compiler resource files.
+ CmdArgs.push_back("-resource-dir");
+ CmdArgs.push_back(D.ResourceDir.c_str());
+
+ Args.AddLastArg(CmdArgs, options::OPT_working_directory);
+
+ bool ARCMTEnabled = false;
+ if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) {
+ if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check,
+ options::OPT_ccc_arcmt_modify,
+ options::OPT_ccc_arcmt_migrate)) {
+ ARCMTEnabled = true;
+ switch (A->getOption().getID()) {
+ default:
+ llvm_unreachable("missed a case");
+ case options::OPT_ccc_arcmt_check:
+ CmdArgs.push_back("-arcmt-check");
+ break;
+ case options::OPT_ccc_arcmt_modify:
+ CmdArgs.push_back("-arcmt-modify");
+ break;
+ case options::OPT_ccc_arcmt_migrate:
+ CmdArgs.push_back("-arcmt-migrate");
+ CmdArgs.push_back("-mt-migrate-directory");
+ CmdArgs.push_back(A->getValue());
+
+ Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output);
+ Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors);
+ break;
+ }
+ }
+ } else {
+ Args.ClaimAllArgs(options::OPT_ccc_arcmt_check);
+ Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify);
+ Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate);
+ }
+
+ if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) {
+ if (ARCMTEnabled) {
+ D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args)
+ << "-ccc-arcmt-migrate";
+ }
+ CmdArgs.push_back("-mt-migrate-directory");
+ CmdArgs.push_back(A->getValue());
+
+ if (!Args.hasArg(options::OPT_objcmt_migrate_literals,
+ options::OPT_objcmt_migrate_subscripting,
+ options::OPT_objcmt_migrate_property)) {
+ // None specified, means enable them all.
+ CmdArgs.push_back("-objcmt-migrate-literals");
+ CmdArgs.push_back("-objcmt-migrate-subscripting");
+ CmdArgs.push_back("-objcmt-migrate-property");
+ } else {
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property);
+ }
+ } else {
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property_dot_syntax);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path);
+ }
+
+ // Add preprocessing options like -I, -D, etc. if we are using the
+ // preprocessor.
+ //
+ // FIXME: Support -fpreprocessed
+ if (types::getPreprocessedType(InputType) != types::TY_INVALID)
+ AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs);
+
+ // Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes
+ // that "The compiler can only warn and ignore the option if not recognized".
+ // When building with ccache, it will pass -D options to clang even on
+ // preprocessed inputs and configure concludes that -fPIC is not supported.
+ Args.ClaimAllArgs(options::OPT_D);
+
+ // Manually translate -O4 to -O3; let clang reject others.
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ if (A->getOption().matches(options::OPT_O4)) {
+ CmdArgs.push_back("-O3");
+ D.Diag(diag::warn_O4_is_O3);
+ } else {
+ A->render(Args, CmdArgs);
+ }
+ }
+
+ // Warn about ignored options to clang.
+ for (const Arg *A :
+ Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) {
+ D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args);
+ A->claim();
+ }
+
+ for (const Arg *A :
+ Args.filtered(options::OPT_clang_ignored_legacy_options_Group)) {
+ D.Diag(diag::warn_ignored_clang_option) << A->getAsString(Args);
+ A->claim();
+ }
+
+ claimNoWarnArgs(Args);
+
+ Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
+
+ Args.AddAllArgs(CmdArgs, options::OPT_W_Group);
+ if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
+ CmdArgs.push_back("-pedantic");
+ Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors);
+ Args.AddLastArg(CmdArgs, options::OPT_w);
+
+ // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi}
+ // (-ansi is equivalent to -std=c89 or -std=c++98).
+ //
+ // If a std is supplied, only add -trigraphs if it follows the
+ // option.
+ bool ImplyVCPPCXXVer = false;
+ if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
+ if (Std->getOption().matches(options::OPT_ansi))
+ if (types::isCXX(InputType))
+ CmdArgs.push_back("-std=c++98");
+ else
+ CmdArgs.push_back("-std=c89");
+ else
+ Std->render(Args, CmdArgs);
+
+ // If -f(no-)trigraphs appears after the language standard flag, honor it.
+ if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi,
+ options::OPT_ftrigraphs,
+ options::OPT_fno_trigraphs))
+ if (A != Std)
+ A->render(Args, CmdArgs);
+ } else {
+ // Honor -std-default.
+ //
+ // FIXME: Clang doesn't correctly handle -std= when the input language
+ // doesn't match. For the time being just ignore this for C++ inputs;
+ // eventually we want to do all the standard defaulting here instead of
+ // splitting it between the driver and clang -cc1.
+ if (!types::isCXX(InputType))
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=",
+ /*Joined=*/true);
+ else if (IsWindowsMSVC)
+ ImplyVCPPCXXVer = true;
+
+ Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs,
+ options::OPT_fno_trigraphs);
+ }
+
+ // GCC's behavior for -Wwrite-strings is a bit strange:
+ // * In C, this "warning flag" changes the types of string literals from
+ // 'char[N]' to 'const char[N]', and thus triggers an unrelated warning
+ // for the discarded qualifier.
+ // * In C++, this is just a normal warning flag.
+ //
+ // Implementing this warning correctly in C is hard, so we follow GCC's
+ // behavior for now. FIXME: Directly diagnose uses of a string literal as
+ // a non-const char* in C, rather than using this crude hack.
+ if (!types::isCXX(InputType)) {
+ // FIXME: This should behave just like a warning flag, and thus should also
+ // respect -Weverything, -Wno-everything, -Werror=write-strings, and so on.
+ Arg *WriteStrings =
+ Args.getLastArg(options::OPT_Wwrite_strings,
+ options::OPT_Wno_write_strings, options::OPT_w);
+ if (WriteStrings &&
+ WriteStrings->getOption().matches(options::OPT_Wwrite_strings))
+ CmdArgs.push_back("-fconst-strings");
+ }
+
+ // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active
+ // during C++ compilation, which it is by default. GCC keeps this define even
+ // in the presence of '-w', match this behavior bug-for-bug.
+ if (types::isCXX(InputType) &&
+ Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated,
+ true)) {
+ CmdArgs.push_back("-fdeprecated-macro");
+ }
+
+ // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'.
+ if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) {
+ if (Asm->getOption().matches(options::OPT_fasm))
+ CmdArgs.push_back("-fgnu-keywords");
+ else
+ CmdArgs.push_back("-fno-gnu-keywords");
+ }
+
+ if (ShouldDisableDwarfDirectory(Args, getToolChain()))
+ CmdArgs.push_back("-fno-dwarf-directory-asm");
+
+ if (ShouldDisableAutolink(Args, getToolChain()))
+ CmdArgs.push_back("-fno-autolink");
+
+ // Add in -fdebug-compilation-dir if necessary.
+ addDebugCompDirArg(Args, CmdArgs);
+
+ for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) {
+ StringRef Map = A->getValue();
+ if (Map.find('=') == StringRef::npos)
+ D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map;
+ else
+ CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map));
+ A->claim();
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
+ options::OPT_ftemplate_depth_EQ)) {
+ CmdArgs.push_back("-ftemplate-depth");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) {
+ CmdArgs.push_back("-foperator-arrow-depth");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) {
+ CmdArgs.push_back("-fconstexpr-depth");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) {
+ CmdArgs.push_back("-fconstexpr-steps");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
+ CmdArgs.push_back("-fbracket-depth");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
+ options::OPT_Wlarge_by_value_copy_def)) {
+ if (A->getNumValues()) {
+ StringRef bytes = A->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes));
+ } else
+ CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value
+ }
+
+ if (Args.hasArg(options::OPT_relocatable_pch))
+ CmdArgs.push_back("-relocatable-pch");
+
+ if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
+ CmdArgs.push_back("-fconstant-string-class");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) {
+ CmdArgs.push_back("-ftabstop");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ CmdArgs.push_back("-ferror-limit");
+ if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
+ CmdArgs.push_back(A->getValue());
+ else
+ CmdArgs.push_back("19");
+
+ if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) {
+ CmdArgs.push_back("-fmacro-backtrace-limit");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) {
+ CmdArgs.push_back("-ftemplate-backtrace-limit");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) {
+ CmdArgs.push_back("-fconstexpr-backtrace-limit");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) {
+ CmdArgs.push_back("-fspell-checking-limit");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ // Pass -fmessage-length=.
+ CmdArgs.push_back("-fmessage-length");
+ if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
+ CmdArgs.push_back(A->getValue());
+ } else {
+ // If -fmessage-length=N was not specified, determine whether this is a
+ // terminal and, if so, implicitly define -fmessage-length appropriately.
+ unsigned N = llvm::sys::Process::StandardErrColumns();
+ CmdArgs.push_back(Args.MakeArgString(Twine(N)));
+ }
+
+ // -fvisibility= and -fvisibility-ms-compat are of a piece.
+ if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
+ options::OPT_fvisibility_ms_compat)) {
+ if (A->getOption().matches(options::OPT_fvisibility_EQ)) {
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back(A->getValue());
+ } else {
+ assert(A->getOption().matches(options::OPT_fvisibility_ms_compat));
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back("hidden");
+ CmdArgs.push_back("-ftype-visibility");
+ CmdArgs.push_back("default");
+ }
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden);
+
+ Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
+
+ // -fhosted is default.
+ bool IsHosted = true;
+ if (Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) ||
+ KernelOrKext) {
+ CmdArgs.push_back("-ffreestanding");
+ IsHosted = false;
+ }
+
+ // Forward -f (flag) options which we can pass directly.
+ Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
+ Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
+ Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
+ // Emulated TLS is enabled by default on Android and OpenBSD, and can be enabled
+ // manually with -femulated-tls.
+ bool EmulatedTLSDefault = Triple.isAndroid() || Triple.isOSOpenBSD() ||
+ Triple.isWindowsCygwinEnvironment();
+ if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls,
+ EmulatedTLSDefault))
+ CmdArgs.push_back("-femulated-tls");
+ // AltiVec-like language extensions aren't relevant for assembling.
+ if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm)
+ Args.AddLastArg(CmdArgs, options::OPT_fzvector);
+
+ Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
+ Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
+
+ // Forward flags for OpenMP. We don't do this if the current action is an
+ // device offloading action other than OpenMP.
+ if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
+ options::OPT_fno_openmp, false) &&
+ (JA.isDeviceOffloading(Action::OFK_None) ||
+ JA.isDeviceOffloading(Action::OFK_OpenMP))) {
+ switch (getToolChain().getDriver().getOpenMPRuntime(Args)) {
+ case Driver::OMPRT_OMP:
+ case Driver::OMPRT_IOMP5:
+ // Clang can generate useful OpenMP code for these two runtime libraries.
+ CmdArgs.push_back("-fopenmp");
+
+ // If no option regarding the use of TLS in OpenMP codegeneration is
+ // given, decide a default based on the target. Otherwise rely on the
+ // options and pass the right information to the frontend.
+ if (!Args.hasFlag(options::OPT_fopenmp_use_tls,
+ options::OPT_fnoopenmp_use_tls, /*Default=*/true))
+ CmdArgs.push_back("-fnoopenmp-use-tls");
+ Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
+ break;
+ default:
+ // By default, if Clang doesn't know how to generate useful OpenMP code
+ // for a specific runtime library, we just don't pass the '-fopenmp' flag
+ // down to the actual compilation.
+ // FIXME: It would be better to have a mode which *only* omits IR
+ // generation based on the OpenMP support so that we get consistent
+ // semantic analysis, etc.
+ break;
+ }
+ }
+
+ const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs();
+ Sanitize.addArgs(getToolChain(), Args, CmdArgs, InputType);
+
+ const XRayArgs &XRay = getToolChain().getXRayArgs();
+ XRay.addArgs(getToolChain(), Args, CmdArgs, InputType);
+
+ if (getToolChain().SupportsProfiling())
+ Args.AddLastArg(CmdArgs, options::OPT_pg);
+
+ if (getToolChain().SupportsProfiling())
+ Args.AddLastArg(CmdArgs, options::OPT_mfentry);
+
+ // -flax-vector-conversions is default.
+ if (!Args.hasFlag(options::OPT_flax_vector_conversions,
+ options::OPT_fno_lax_vector_conversions))
+ CmdArgs.push_back("-fno-lax-vector-conversions");
+
+ if (Args.getLastArg(options::OPT_fapple_kext) ||
+ (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType)))
+ CmdArgs.push_back("-fapple-kext");
+
+ Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
+ Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
+ Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
+ Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
+ Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
+
+ if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
+ CmdArgs.push_back("-ftrapv-handler");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);
+
+ // -fno-strict-overflow implies -fwrapv if it isn't disabled, but
+ // -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
+ if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) {
+ if (A->getOption().matches(options::OPT_fwrapv))
+ CmdArgs.push_back("-fwrapv");
+ } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
+ options::OPT_fno_strict_overflow)) {
+ if (A->getOption().matches(options::OPT_fno_strict_overflow))
+ CmdArgs.push_back("-fwrapv");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_freroll_loops,
+ options::OPT_fno_reroll_loops))
+ if (A->getOption().matches(options::OPT_freroll_loops))
+ CmdArgs.push_back("-freroll-loops");
+
+ Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
+ Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
+ options::OPT_fno_unroll_loops);
+
+ Args.AddLastArg(CmdArgs, options::OPT_pthread);
+
+ // -stack-protector=0 is default.
+ unsigned StackProtectorLevel = 0;
+ // NVPTX doesn't support stack protectors; from the compiler's perspective, it
+ // doesn't even have a stack!
+ if (!Triple.isNVPTX()) {
+ if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
+ options::OPT_fstack_protector_all,
+ options::OPT_fstack_protector_strong,
+ options::OPT_fstack_protector)) {
+ if (A->getOption().matches(options::OPT_fstack_protector)) {
+ StackProtectorLevel = std::max<unsigned>(
+ LangOptions::SSPOn,
+ getToolChain().GetDefaultStackProtectorLevel(KernelOrKext));
+ } else if (A->getOption().matches(options::OPT_fstack_protector_strong))
+ StackProtectorLevel = LangOptions::SSPStrong;
+ else if (A->getOption().matches(options::OPT_fstack_protector_all))
+ StackProtectorLevel = LangOptions::SSPReq;
+ } else {
+ StackProtectorLevel =
+ getToolChain().GetDefaultStackProtectorLevel(KernelOrKext);
+ // Only use a default stack protector on Darwin in case -ffreestanding
+ // is not specified.
+ if (Triple.isOSDarwin() && !IsHosted)
+ StackProtectorLevel = 0;
+ }
+ }
+ if (StackProtectorLevel) {
+ CmdArgs.push_back("-stack-protector");
+ CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel)));
+ }
+
+ // --param ssp-buffer-size=
+ for (const Arg *A : Args.filtered(options::OPT__param)) {
+ StringRef Str(A->getValue());
+ if (Str.startswith("ssp-buffer-size=")) {
+ if (StackProtectorLevel) {
+ CmdArgs.push_back("-stack-protector-buffer-size");
+ // FIXME: Verify the argument is a valid integer.
+ CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16)));
+ }
+ A->claim();
+ }
+ }
+
+ // Translate -mstackrealign
+ if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
+ false))
+ CmdArgs.push_back(Args.MakeArgString("-mstackrealign"));
+
+ if (Args.hasArg(options::OPT_mstack_alignment)) {
+ StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
+ CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
+ }
+
+ if (Args.hasArg(options::OPT_mstack_probe_size)) {
+ StringRef Size = Args.getLastArgValue(options::OPT_mstack_probe_size);
+
+ if (!Size.empty())
+ CmdArgs.push_back(Args.MakeArgString("-mstack-probe-size=" + Size));
+ else
+ CmdArgs.push_back("-mstack-probe-size=0");
+ }
+
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ CmdArgs.push_back("-fallow-half-arguments-and-returns");
+ break;
+
+ default:
+ break;
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
+ options::OPT_mno_restrict_it)) {
+ if (A->getOption().matches(options::OPT_mrestrict_it)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-restrict-it");
+ } else {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-no-restrict-it");
+ }
+ } else if (Triple.isOSWindows() &&
+ (Triple.getArch() == llvm::Triple::arm ||
+ Triple.getArch() == llvm::Triple::thumb)) {
+ // Windows on ARM expects restricted IT blocks
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-restrict-it");
+ }
+
+ // Forward -cl options to -cc1
+ if (Args.getLastArg(options::OPT_cl_opt_disable)) {
+ CmdArgs.push_back("-cl-opt-disable");
+ }
+ if (Args.getLastArg(options::OPT_cl_strict_aliasing)) {
+ CmdArgs.push_back("-cl-strict-aliasing");
+ }
+ if (Args.getLastArg(options::OPT_cl_single_precision_constant)) {
+ CmdArgs.push_back("-cl-single-precision-constant");
+ }
+ if (Args.getLastArg(options::OPT_cl_finite_math_only)) {
+ CmdArgs.push_back("-cl-finite-math-only");
+ }
+ if (Args.getLastArg(options::OPT_cl_kernel_arg_info)) {
+ CmdArgs.push_back("-cl-kernel-arg-info");
+ }
+ if (Args.getLastArg(options::OPT_cl_unsafe_math_optimizations)) {
+ CmdArgs.push_back("-cl-unsafe-math-optimizations");
+ }
+ if (Args.getLastArg(options::OPT_cl_fast_relaxed_math)) {
+ CmdArgs.push_back("-cl-fast-relaxed-math");
+ }
+ if (Args.getLastArg(options::OPT_cl_mad_enable)) {
+ CmdArgs.push_back("-cl-mad-enable");
+ }
+ if (Args.getLastArg(options::OPT_cl_no_signed_zeros)) {
+ CmdArgs.push_back("-cl-no-signed-zeros");
+ }
+ if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) {
+ std::string CLStdStr = "-cl-std=";
+ CLStdStr += A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(CLStdStr));
+ }
+ if (Args.getLastArg(options::OPT_cl_denorms_are_zero)) {
+ CmdArgs.push_back("-cl-denorms-are-zero");
+ }
+ if (Args.getLastArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt)) {
+ CmdArgs.push_back("-cl-fp32-correctly-rounded-divide-sqrt");
+ }
+
+ // Forward -f options with positive and negative forms; we translate
+ // these by hand.
+ if (Arg *A = getLastProfileSampleUseArg(Args)) {
+ StringRef fname = A->getValue();
+ if (!llvm::sys::fs::exists(fname))
+ D.Diag(diag::err_drv_no_such_file) << fname;
+ else
+ A->render(Args, CmdArgs);
+ }
+
+ if (Args.hasFlag(options::OPT_fdebug_info_for_profiling,
+ options::OPT_fno_debug_info_for_profiling, false))
+ CmdArgs.push_back("-fdebug-info-for-profiling");
+
+ // -fbuiltin is default unless -mkernel is used.
+ bool UseBuiltins =
+ Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin,
+ !Args.hasArg(options::OPT_mkernel));
+ if (!UseBuiltins)
+ CmdArgs.push_back("-fno-builtin");
+
+ // -ffreestanding implies -fno-builtin.
+ if (Args.hasArg(options::OPT_ffreestanding))
+ UseBuiltins = false;
+
+ // Process the -fno-builtin-* options.
+ for (const auto &Arg : Args) {
+ const Option &O = Arg->getOption();
+ if (!O.matches(options::OPT_fno_builtin_))
+ continue;
+
+ Arg->claim();
+ // If -fno-builtin is specified, then there's no need to pass the option to
+ // the frontend.
+ if (!UseBuiltins)
+ continue;
+
+ StringRef FuncName = Arg->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName));
+ }
+
+ if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
+ options::OPT_fno_assume_sane_operator_new))
+ CmdArgs.push_back("-fno-assume-sane-operator-new");
+
+ // -fblocks=0 is default.
+ if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
+ getToolChain().IsBlocksDefault()) ||
+ (Args.hasArg(options::OPT_fgnu_runtime) &&
+ Args.hasArg(options::OPT_fobjc_nonfragile_abi) &&
+ !Args.hasArg(options::OPT_fno_blocks))) {
+ CmdArgs.push_back("-fblocks");
+
+ if (!Args.hasArg(options::OPT_fgnu_runtime) &&
+ !getToolChain().hasBlocksRuntime())
+ CmdArgs.push_back("-fblocks-runtime-optional");
+ }
+
+ if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts,
+ false) &&
+ types::isCXX(InputType)) {
+ CmdArgs.push_back("-fcoroutines-ts");
+ }
+
+ // -fmodules enables the use of precompiled modules (off by default).
+ // Users can pass -fno-cxx-modules to turn off modules support for
+ // C++/Objective-C++ programs.
+ bool HaveClangModules = false;
+ if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
+ bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
+ options::OPT_fno_cxx_modules, true);
+ if (AllowedInCXX || !types::isCXX(InputType)) {
+ CmdArgs.push_back("-fmodules");
+ HaveClangModules = true;
+ }
+ }
+
+ bool HaveAnyModules = HaveClangModules;
+ if (Args.hasArg(options::OPT_fmodules_ts)) {
+ CmdArgs.push_back("-fmodules-ts");
+ HaveAnyModules = true;
+ }
+
+ // -fmodule-maps enables implicit reading of module map files. By default,
+ // this is enabled if we are using Clang's flavor of precompiled modules.
+ if (Args.hasFlag(options::OPT_fimplicit_module_maps,
+ options::OPT_fno_implicit_module_maps, HaveClangModules)) {
+ CmdArgs.push_back("-fimplicit-module-maps");
+ }
+
+ // -fmodules-decluse checks that modules used are declared so (off by
+ // default).
+ if (Args.hasFlag(options::OPT_fmodules_decluse,
+ options::OPT_fno_modules_decluse, false)) {
+ CmdArgs.push_back("-fmodules-decluse");
+ }
+
+ // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that
+ // all #included headers are part of modules.
+ if (Args.hasFlag(options::OPT_fmodules_strict_decluse,
+ options::OPT_fno_modules_strict_decluse, false)) {
+ CmdArgs.push_back("-fmodules-strict-decluse");
+ }
+
+ // -fno-implicit-modules turns off implicitly compiling modules on demand.
+ if (!Args.hasFlag(options::OPT_fimplicit_modules,
+ options::OPT_fno_implicit_modules, HaveClangModules)) {
+ if (HaveAnyModules)
+ CmdArgs.push_back("-fno-implicit-modules");
+ } else if (HaveAnyModules) {
+ // -fmodule-cache-path specifies where our implicitly-built module files
+ // should be written.
+ SmallString<128> Path;
+ if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path))
+ Path = A->getValue();
+ if (C.isForDiagnostics()) {
+ // When generating crash reports, we want to emit the modules along with
+ // the reproduction sources, so we ignore any provided module path.
+ Path = Output.getFilename();
+ llvm::sys::path::replace_extension(Path, ".cache");
+ llvm::sys::path::append(Path, "modules");
+ } else if (Path.empty()) {
+ // No module path was provided: use the default.
+ llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Path);
+ llvm::sys::path::append(Path, "org.llvm.clang.");
+ appendUserToPath(Path);
+ llvm::sys::path::append(Path, "ModuleCache");
+ }
+ const char Arg[] = "-fmodules-cache-path=";
+ Path.insert(Path.begin(), Arg, Arg + strlen(Arg));
+ CmdArgs.push_back(Args.MakeArgString(Path));
+ }
+
+ if (HaveAnyModules) {
+ // -fprebuilt-module-path specifies where to load the prebuilt module files.
+ for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path))
+ CmdArgs.push_back(Args.MakeArgString(
+ std::string("-fprebuilt-module-path=") + A->getValue()));
+ }
+
+ // -fmodule-name specifies the module that is currently being built (or
+ // used for header checking by -fmodule-maps).
+ Args.AddLastArg(CmdArgs, options::OPT_fmodule_name_EQ);
+
+ // -fmodule-map-file can be used to specify files containing module
+ // definitions.
+ Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file);
+
+ // -fbuiltin-module-map can be used to load the clang
+ // builtin headers modulemap file.
+ if (Args.hasArg(options::OPT_fbuiltin_module_map)) {
+ SmallString<128> BuiltinModuleMap(getToolChain().getDriver().ResourceDir);
+ llvm::sys::path::append(BuiltinModuleMap, "include");
+ llvm::sys::path::append(BuiltinModuleMap, "module.modulemap");
+ if (llvm::sys::fs::exists(BuiltinModuleMap)) {
+ CmdArgs.push_back(Args.MakeArgString("-fmodule-map-file=" +
+ BuiltinModuleMap));
+ }
+ }
+
+ // -fmodule-file can be used to specify files containing precompiled modules.
+ if (HaveAnyModules)
+ Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file);
+ else
+ Args.ClaimAllArgs(options::OPT_fmodule_file);
+
+ // When building modules and generating crashdumps, we need to dump a module
+ // dependency VFS alongside the output.
+ if (HaveClangModules && C.isForDiagnostics()) {
+ SmallString<128> VFSDir(Output.getFilename());
+ llvm::sys::path::replace_extension(VFSDir, ".cache");
+ // Add the cache directory as a temp so the crash diagnostics pick it up.
+ C.addTempFile(Args.MakeArgString(VFSDir));
+
+ llvm::sys::path::append(VFSDir, "vfs");
+ CmdArgs.push_back("-module-dependency-dir");
+ CmdArgs.push_back(Args.MakeArgString(VFSDir));
+ }
+
+ if (HaveClangModules)
+ Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path);
+
+ // Pass through all -fmodules-ignore-macro arguments.
+ Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro);
+ Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval);
+ Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after);
+
+ Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
+
+ if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
+ if (Args.hasArg(options::OPT_fbuild_session_timestamp))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "-fbuild-session-timestamp";
+
+ llvm::sys::fs::file_status Status;
+ if (llvm::sys::fs::status(A->getValue(), Status))
+ D.Diag(diag::err_drv_no_such_file) << A->getValue();
+ CmdArgs.push_back(
+ Args.MakeArgString("-fbuild-session-timestamp=" +
+ Twine((uint64_t)Status.getLastModificationTime()
+ .time_since_epoch()
+ .count())));
+ }
+
+ if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) {
+ if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
+ options::OPT_fbuild_session_file))
+ D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
+
+ Args.AddLastArg(CmdArgs,
+ options::OPT_fmodules_validate_once_per_build_session);
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers);
+ Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation);
+
+ // -faccess-control is default.
+ if (Args.hasFlag(options::OPT_fno_access_control,
+ options::OPT_faccess_control, false))
+ CmdArgs.push_back("-fno-access-control");
+
+ // -felide-constructors is the default.
+ if (Args.hasFlag(options::OPT_fno_elide_constructors,
+ options::OPT_felide_constructors, false))
+ CmdArgs.push_back("-fno-elide-constructors");
+
+ ToolChain::RTTIMode RTTIMode = getToolChain().getRTTIMode();
+
+ if (KernelOrKext || (types::isCXX(InputType) &&
+ (RTTIMode == ToolChain::RM_DisabledExplicitly ||
+ RTTIMode == ToolChain::RM_DisabledImplicitly)))
+ CmdArgs.push_back("-fno-rtti");
+
+ // -fshort-enums=0 is default for all architectures except Hexagon.
+ if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums,
+ getToolChain().getArch() == llvm::Triple::hexagon))
+ CmdArgs.push_back("-fshort-enums");
+
+ // -fsigned-char is default.
+ if (Arg *A = Args.getLastArg(
+ options::OPT_fsigned_char, options::OPT_fno_signed_char,
+ options::OPT_funsigned_char, options::OPT_fno_unsigned_char)) {
+ if (A->getOption().matches(options::OPT_funsigned_char) ||
+ A->getOption().matches(options::OPT_fno_signed_char)) {
+ CmdArgs.push_back("-fno-signed-char");
+ }
+ } else if (!isSignedCharDefault(getToolChain().getTriple())) {
+ CmdArgs.push_back("-fno-signed-char");
+ }
+
+ // -fuse-cxa-atexit is default.
+ if (!Args.hasFlag(
+ options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
+ !IsWindowsCygnus && !IsWindowsGNU &&
+ getToolChain().getTriple().getOS() != llvm::Triple::Solaris &&
+ getToolChain().getArch() != llvm::Triple::hexagon &&
+ getToolChain().getArch() != llvm::Triple::xcore &&
+ ((getToolChain().getTriple().getVendor() !=
+ llvm::Triple::MipsTechnologies) ||
+ getToolChain().getTriple().hasEnvironment())) ||
+ KernelOrKext)
+ CmdArgs.push_back("-fno-use-cxa-atexit");
+
+ // -fms-extensions=0 is default.
+ if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
+ IsWindowsMSVC))
+ CmdArgs.push_back("-fms-extensions");
+
+ // -fno-use-line-directives is default.
+ if (Args.hasFlag(options::OPT_fuse_line_directives,
+ options::OPT_fno_use_line_directives, false))
+ CmdArgs.push_back("-fuse-line-directives");
+
+ // -fms-compatibility=0 is default.
+ if (Args.hasFlag(options::OPT_fms_compatibility,
+ options::OPT_fno_ms_compatibility,
+ (IsWindowsMSVC &&
+ Args.hasFlag(options::OPT_fms_extensions,
+ options::OPT_fno_ms_extensions, true))))
+ CmdArgs.push_back("-fms-compatibility");
+
+ VersionTuple MSVT =
+ getToolChain().computeMSVCVersion(&getToolChain().getDriver(), Args);
+ if (!MSVT.empty())
+ CmdArgs.push_back(
+ Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString()));
+
+ bool IsMSVC2015Compatible = MSVT.getMajor() >= 19;
+ if (ImplyVCPPCXXVer) {
+ StringRef LanguageStandard;
+ if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) {
+ LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue())
+ .Case("c++14", "-std=c++14")
+ .Case("c++latest", "-std=c++1z")
+ .Default("");
+ if (LanguageStandard.empty())
+ D.Diag(clang::diag::warn_drv_unused_argument)
+ << StdArg->getAsString(Args);
+ }
+
+ if (LanguageStandard.empty()) {
+ if (IsMSVC2015Compatible)
+ LanguageStandard = "-std=c++14";
+ else
+ LanguageStandard = "-std=c++11";
+ }
+
+ CmdArgs.push_back(LanguageStandard.data());
+ }
+
+ // -fno-borland-extensions is default.
+ if (Args.hasFlag(options::OPT_fborland_extensions,
+ options::OPT_fno_borland_extensions, false))
+ CmdArgs.push_back("-fborland-extensions");
+
+ // -fno-declspec is default, except for PS4.
+ if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec,
+ getToolChain().getTriple().isPS4()))
+ CmdArgs.push_back("-fdeclspec");
+ else if (Args.hasArg(options::OPT_fno_declspec))
+ CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec.
+
+ // -fthreadsafe-static is default, except for MSVC compatibility versions less
+ // than 19.
+ if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
+ options::OPT_fno_threadsafe_statics,
+ !IsWindowsMSVC || IsMSVC2015Compatible))
+ CmdArgs.push_back("-fno-threadsafe-statics");
+
+ // -fno-delayed-template-parsing is default, except for Windows where MSVC STL
+ // needs it.
+ if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
+ options::OPT_fno_delayed_template_parsing, IsWindowsMSVC))
+ CmdArgs.push_back("-fdelayed-template-parsing");
+
+ // -fgnu-keywords default varies depending on language; only pass if
+ // specified.
+ if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords,
+ options::OPT_fno_gnu_keywords))
+ A->render(Args, CmdArgs);
+
+ if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline,
+ false))
+ CmdArgs.push_back("-fgnu89-inline");
+
+ if (Args.hasArg(options::OPT_fno_inline))
+ CmdArgs.push_back("-fno-inline");
+
+ if (Arg* InlineArg = Args.getLastArg(options::OPT_finline_functions,
+ options::OPT_finline_hint_functions,
+ options::OPT_fno_inline_functions))
+ InlineArg->render(Args, CmdArgs);
+
+ Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager,
+ options::OPT_fno_experimental_new_pass_manager);
+
+ ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind);
+
+ // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
+ // legacy is the default. Except for deployment target of 10.5,
+ // next runtime is always legacy dispatch and -fno-objc-legacy-dispatch
+ // gets ignored silently.
+ if (objcRuntime.isNonFragile()) {
+ if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
+ options::OPT_fno_objc_legacy_dispatch,
+ objcRuntime.isLegacyDispatchDefaultForArch(
+ getToolChain().getArch()))) {
+ if (getToolChain().UseObjCMixedDispatch())
+ CmdArgs.push_back("-fobjc-dispatch-method=mixed");
+ else
+ CmdArgs.push_back("-fobjc-dispatch-method=non-legacy");
+ }
+ }
+
+ // When ObjectiveC legacy runtime is in effect on MacOSX,
+ // turn on the option to do Array/Dictionary subscripting
+ // by default.
+ if (getToolChain().getArch() == llvm::Triple::x86 &&
+ getToolChain().getTriple().isMacOSX() &&
+ !getToolChain().getTriple().isMacOSXVersionLT(10, 7) &&
+ objcRuntime.getKind() == ObjCRuntime::FragileMacOSX &&
+ objcRuntime.isNeXTFamily())
+ CmdArgs.push_back("-fobjc-subscripting-legacy-runtime");
+
+ // -fencode-extended-block-signature=1 is default.
+ if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) {
+ CmdArgs.push_back("-fencode-extended-block-signature");
+ }
+
+ // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
+ // NOTE: This logic is duplicated in ToolChains.cpp.
+ bool ARC = isObjCAutoRefCount(Args);
+ if (ARC) {
+ getToolChain().CheckObjCARC();
+
+ CmdArgs.push_back("-fobjc-arc");
+
+ // FIXME: It seems like this entire block, and several around it should be
+ // wrapped in isObjC, but for now we just use it here as this is where it
+ // was being used previously.
+ if (types::isCXX(InputType) && types::isObjC(InputType)) {
+ if (getToolChain().GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
+ CmdArgs.push_back("-fobjc-arc-cxxlib=libc++");
+ else
+ CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++");
+ }
+
+ // Allow the user to enable full exceptions code emission.
+ // We define off for Objective-CC, on for Objective-C++.
+ if (Args.hasFlag(options::OPT_fobjc_arc_exceptions,
+ options::OPT_fno_objc_arc_exceptions,
+ /*default*/ types::isCXX(InputType)))
+ CmdArgs.push_back("-fobjc-arc-exceptions");
+ }
+
+ // Silence warning for full exception code emission options when explicitly
+ // set to use no ARC.
+ if (Args.hasArg(options::OPT_fno_objc_arc)) {
+ Args.ClaimAllArgs(options::OPT_fobjc_arc_exceptions);
+ Args.ClaimAllArgs(options::OPT_fno_objc_arc_exceptions);
+ }
+
+ // -fobjc-infer-related-result-type is the default, except in the Objective-C
+ // rewriter.
+ if (rewriteKind != RK_None)
+ CmdArgs.push_back("-fno-objc-infer-related-result-type");
+
+ // Pass down -fobjc-weak or -fno-objc-weak if present.
+ if (types::isObjC(InputType)) {
+ auto WeakArg = Args.getLastArg(options::OPT_fobjc_weak,
+ options::OPT_fno_objc_weak);
+ if (!WeakArg) {
+ // nothing to do
+ } else if (!objcRuntime.allowsWeak()) {
+ if (WeakArg->getOption().matches(options::OPT_fobjc_weak))
+ D.Diag(diag::err_objc_weak_unsupported);
+ } else {
+ WeakArg->render(Args, CmdArgs);
+ }
+ }
+
+ if (Args.hasFlag(options::OPT_fapplication_extension,
+ options::OPT_fno_application_extension, false))
+ CmdArgs.push_back("-fapplication-extension");
+
+ // Handle GCC-style exception args.
+ if (!C.getDriver().IsCLMode())
+ addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, objcRuntime,
+ CmdArgs);
+
+ if (Args.hasArg(options::OPT_fsjlj_exceptions) ||
+ getToolChain().UseSjLjExceptions(Args))
+ CmdArgs.push_back("-fsjlj-exceptions");
+
+ // C++ "sane" operator new.
+ if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
+ options::OPT_fno_assume_sane_operator_new))
+ CmdArgs.push_back("-fno-assume-sane-operator-new");
+
+ // -frelaxed-template-template-args is off by default, as it is a severe
+ // breaking change until a corresponding change to template partial ordering
+ // is provided.
+ if (Args.hasFlag(options::OPT_frelaxed_template_template_args,
+ options::OPT_fno_relaxed_template_template_args, false))
+ CmdArgs.push_back("-frelaxed-template-template-args");
+
+ // -fsized-deallocation is off by default, as it is an ABI-breaking change for
+ // most platforms.
+ if (Args.hasFlag(options::OPT_fsized_deallocation,
+ options::OPT_fno_sized_deallocation, false))
+ CmdArgs.push_back("-fsized-deallocation");
+
+ // -faligned-allocation is on by default in C++17 onwards and otherwise off
+ // by default.
+ if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation,
+ options::OPT_fno_aligned_allocation,
+ options::OPT_faligned_new_EQ)) {
+ if (A->getOption().matches(options::OPT_fno_aligned_allocation))
+ CmdArgs.push_back("-fno-aligned-allocation");
+ else
+ CmdArgs.push_back("-faligned-allocation");
+ }
+
+ // The default new alignment can be specified using a dedicated option or via
+ // a GCC-compatible option that also turns on aligned allocation.
+ if (Arg *A = Args.getLastArg(options::OPT_fnew_alignment_EQ,
+ options::OPT_faligned_new_EQ))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-fnew-alignment=") + A->getValue()));
+
+ // -fconstant-cfstrings is default, and may be subject to argument translation
+ // on Darwin.
+ if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
+ options::OPT_fno_constant_cfstrings) ||
+ !Args.hasFlag(options::OPT_mconstant_cfstrings,
+ options::OPT_mno_constant_cfstrings))
+ CmdArgs.push_back("-fno-constant-cfstrings");
+
+ // -fshort-wchar default varies depending on platform; only
+ // pass if specified.
+ if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar,
+ options::OPT_fno_short_wchar))
+ A->render(Args, CmdArgs);
+
+ // -fno-pascal-strings is default, only pass non-default.
+ if (Args.hasFlag(options::OPT_fpascal_strings,
+ options::OPT_fno_pascal_strings, false))
+ CmdArgs.push_back("-fpascal-strings");
+
+ // Honor -fpack-struct= and -fpack-struct, if given. Note that
+ // -fno-pack-struct doesn't apply to -fpack-struct=.
+ if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) {
+ std::string PackStructStr = "-fpack-struct=";
+ PackStructStr += A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(PackStructStr));
+ } else if (Args.hasFlag(options::OPT_fpack_struct,
+ options::OPT_fno_pack_struct, false)) {
+ CmdArgs.push_back("-fpack-struct=1");
+ }
+
+ // Handle -fmax-type-align=N and -fno-type-align
+ bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align);
+ if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) {
+ if (!SkipMaxTypeAlign) {
+ std::string MaxTypeAlignStr = "-fmax-type-align=";
+ MaxTypeAlignStr += A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
+ }
+ } else if (getToolChain().getTriple().isOSDarwin()) {
+ if (!SkipMaxTypeAlign) {
+ std::string MaxTypeAlignStr = "-fmax-type-align=16";
+ CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
+ }
+ }
+
+ // -fcommon is the default unless compiling kernel code or the target says so
+ bool NoCommonDefault =
+ KernelOrKext || isNoCommonDefault(getToolChain().getTriple());
+ if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common,
+ !NoCommonDefault))
+ CmdArgs.push_back("-fno-common");
+
+ // -fsigned-bitfields is default, and clang doesn't yet support
+ // -funsigned-bitfields.
+ if (!Args.hasFlag(options::OPT_fsigned_bitfields,
+ options::OPT_funsigned_bitfields))
+ D.Diag(diag::warn_drv_clang_unsupported)
+ << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args);
+
+ // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope.
+ if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope))
+ D.Diag(diag::err_drv_clang_unsupported)
+ << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args);
+
+ // -finput_charset=UTF-8 is default. Reject others
+ if (Arg *inputCharset = Args.getLastArg(options::OPT_finput_charset_EQ)) {
+ StringRef value = inputCharset->getValue();
+ if (!value.equals_lower("utf-8"))
+ D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args)
+ << value;
+ }
+
+ // -fexec_charset=UTF-8 is default. Reject others
+ if (Arg *execCharset = Args.getLastArg(options::OPT_fexec_charset_EQ)) {
+ StringRef value = execCharset->getValue();
+ if (!value.equals_lower("utf-8"))
+ D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args)
+ << value;
+ }
+
+ bool CaretDefault = true;
+ bool ColumnDefault = true;
+ if (Arg *DiagArg = Args.getLastArg(options::OPT__SLASH_diagnostics_classic,
+ options::OPT__SLASH_diagnostics_column,
+ options::OPT__SLASH_diagnostics_caret)) {
+ switch (DiagArg->getOption().getID()) {
+ case options::OPT__SLASH_diagnostics_caret:
+ CaretDefault = true;
+ ColumnDefault = true;
+ break;
+ case options::OPT__SLASH_diagnostics_column:
+ CaretDefault = false;
+ ColumnDefault = true;
+ break;
+ case options::OPT__SLASH_diagnostics_classic:
+ CaretDefault = false;
+ ColumnDefault = false;
+ break;
+ }
+ }
+
+ // -fcaret-diagnostics is default.
+ if (!Args.hasFlag(options::OPT_fcaret_diagnostics,
+ options::OPT_fno_caret_diagnostics, CaretDefault))
+ CmdArgs.push_back("-fno-caret-diagnostics");
+
+ // -fdiagnostics-fixit-info is default, only pass non-default.
+ if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info,
+ options::OPT_fno_diagnostics_fixit_info))
+ CmdArgs.push_back("-fno-diagnostics-fixit-info");
+
+ // Enable -fdiagnostics-show-option by default.
+ if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
+ options::OPT_fno_diagnostics_show_option))
+ CmdArgs.push_back("-fdiagnostics-show-option");
+
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) {
+ CmdArgs.push_back("-fdiagnostics-show-category");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness,
+ options::OPT_fno_diagnostics_show_hotness, false))
+ CmdArgs.push_back("-fdiagnostics-show-hotness");
+
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) {
+ std::string Opt = std::string("-fdiagnostics-hotness-threshold=") + A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(Opt));
+ }
+
+ if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
+ CmdArgs.push_back("-fdiagnostics-format");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ if (Arg *A = Args.getLastArg(
+ options::OPT_fdiagnostics_show_note_include_stack,
+ options::OPT_fno_diagnostics_show_note_include_stack)) {
+ if (A->getOption().matches(
+ options::OPT_fdiagnostics_show_note_include_stack))
+ CmdArgs.push_back("-fdiagnostics-show-note-include-stack");
+ else
+ CmdArgs.push_back("-fno-diagnostics-show-note-include-stack");
+ }
+
+ // Color diagnostics are parsed by the driver directly from argv
+ // and later re-parsed to construct this job; claim any possible
+ // color diagnostic here to avoid warn_drv_unused_argument and
+ // diagnose bad OPT_fdiagnostics_color_EQ values.
+ for (Arg *A : Args) {
+ const Option &O = A->getOption();
+ if (!O.matches(options::OPT_fcolor_diagnostics) &&
+ !O.matches(options::OPT_fdiagnostics_color) &&
+ !O.matches(options::OPT_fno_color_diagnostics) &&
+ !O.matches(options::OPT_fno_diagnostics_color) &&
+ !O.matches(options::OPT_fdiagnostics_color_EQ))
+ continue;
+ if (O.matches(options::OPT_fdiagnostics_color_EQ)) {
+ StringRef Value(A->getValue());
+ if (Value != "always" && Value != "never" && Value != "auto")
+ getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported)
+ << ("-fdiagnostics-color=" + Value).str();
+ }
+ A->claim();
+ }
+ if (D.getDiags().getDiagnosticOptions().ShowColors)
+ CmdArgs.push_back("-fcolor-diagnostics");
+
+ if (Args.hasArg(options::OPT_fansi_escape_codes))
+ CmdArgs.push_back("-fansi-escape-codes");
+
+ if (!Args.hasFlag(options::OPT_fshow_source_location,
+ options::OPT_fno_show_source_location))
+ CmdArgs.push_back("-fno-show-source-location");
+
+ if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths))
+ CmdArgs.push_back("-fdiagnostics-absolute-paths");
+
+ if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column,
+ ColumnDefault))
+ CmdArgs.push_back("-fno-show-column");
+
+ if (!Args.hasFlag(options::OPT_fspell_checking,
+ options::OPT_fno_spell_checking))
+ CmdArgs.push_back("-fno-spell-checking");
+
+ // -fno-asm-blocks is default.
+ if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
+ false))
+ CmdArgs.push_back("-fasm-blocks");
+
+ // -fgnu-inline-asm is default.
+ if (!Args.hasFlag(options::OPT_fgnu_inline_asm,
+ options::OPT_fno_gnu_inline_asm, true))
+ CmdArgs.push_back("-fno-gnu-inline-asm");
+
+ // Enable vectorization per default according to the optimization level
+ // selected. For optimization levels that want vectorization we use the alias
+ // option to simplify the hasFlag logic.
+ bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false);
+ OptSpecifier VectorizeAliasOption =
+ EnableVec ? options::OPT_O_Group : options::OPT_fvectorize;
+ if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption,
+ options::OPT_fno_vectorize, EnableVec))
+ CmdArgs.push_back("-vectorize-loops");
+
+ // -fslp-vectorize is enabled based on the optimization level selected.
+ bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true);
+ OptSpecifier SLPVectAliasOption =
+ EnableSLPVec ? options::OPT_O_Group : options::OPT_fslp_vectorize;
+ if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption,
+ options::OPT_fno_slp_vectorize, EnableSLPVec))
+ CmdArgs.push_back("-vectorize-slp");
+
+ if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ))
+ A->render(Args, CmdArgs);
+
+ if (Arg *A = Args.getLastArg(
+ options::OPT_fsanitize_undefined_strip_path_components_EQ))
+ A->render(Args, CmdArgs);
+
+ // -fdollars-in-identifiers default varies depending on platform and
+ // language; only pass if specified.
+ if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers,
+ options::OPT_fno_dollars_in_identifiers)) {
+ if (A->getOption().matches(options::OPT_fdollars_in_identifiers))
+ CmdArgs.push_back("-fdollars-in-identifiers");
+ else
+ CmdArgs.push_back("-fno-dollars-in-identifiers");
+ }
+
+ // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for
+ // practical purposes.
+ if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time,
+ options::OPT_fno_unit_at_a_time)) {
+ if (A->getOption().matches(options::OPT_fno_unit_at_a_time))
+ D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
+ }
+
+ if (Args.hasFlag(options::OPT_fapple_pragma_pack,
+ options::OPT_fno_apple_pragma_pack, false))
+ CmdArgs.push_back("-fapple-pragma-pack");
+
+ // le32-specific flags:
+ // -fno-math-builtin: clang should not convert math builtins to intrinsics
+ // by default.
+ if (getToolChain().getArch() == llvm::Triple::le32) {
+ CmdArgs.push_back("-fno-math-builtin");
+ }
+
+ if (Args.hasFlag(options::OPT_fsave_optimization_record,
+ options::OPT_fno_save_optimization_record, false)) {
+ CmdArgs.push_back("-opt-record-file");
+
+ const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ);
+ if (A) {
+ CmdArgs.push_back(A->getValue());
+ } else {
+ SmallString<128> F;
+ if (Output.isFilename() && (Args.hasArg(options::OPT_c) ||
+ Args.hasArg(options::OPT_S))) {
+ F = Output.getFilename();
+ } else {
+ // Use the input filename.
+ F = llvm::sys::path::stem(Input.getBaseInput());
+
+ // If we're compiling for an offload architecture (i.e. a CUDA device),
+ // we need to make the file name for the device compilation different
+ // from the host compilation.
+ if (!JA.isDeviceOffloading(Action::OFK_None) &&
+ !JA.isDeviceOffloading(Action::OFK_Host)) {
+ llvm::sys::path::replace_extension(F, "");
+ F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(),
+ Triple.normalize());
+ F += "-";
+ F += JA.getOffloadingArch();
+ }
+ }
+
+ llvm::sys::path::replace_extension(F, "opt.yaml");
+ CmdArgs.push_back(Args.MakeArgString(F));
+ }
+ }
+
+// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM.
+//
+// FIXME: Now that PR4941 has been fixed this can be enabled.
+#if 0
+ if (getToolChain().getTriple().isOSDarwin() &&
+ (getToolChain().getArch() == llvm::Triple::arm ||
+ getToolChain().getArch() == llvm::Triple::thumb)) {
+ if (!Args.hasArg(options::OPT_fbuiltin_strcat))
+ CmdArgs.push_back("-fno-builtin-strcat");
+ if (!Args.hasArg(options::OPT_fbuiltin_strcpy))
+ CmdArgs.push_back("-fno-builtin-strcpy");
+ }
+#endif
+
+ bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports,
+ options::OPT_fno_rewrite_imports, false);
+ if (RewriteImports)
+ CmdArgs.push_back("-frewrite-imports");
+
+ // Enable rewrite includes if the user's asked for it or if we're generating
+ // diagnostics.
+ // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be
+ // nice to enable this when doing a crashdump for modules as well.
+ if (Args.hasFlag(options::OPT_frewrite_includes,
+ options::OPT_fno_rewrite_includes, false) ||
+ (C.isForDiagnostics() && (RewriteImports || !HaveAnyModules)))
+ CmdArgs.push_back("-frewrite-includes");
+
+ // Only allow -traditional or -traditional-cpp outside in preprocessing modes.
+ if (Arg *A = Args.getLastArg(options::OPT_traditional,
+ options::OPT_traditional_cpp)) {
+ if (isa<PreprocessJobAction>(JA))
+ CmdArgs.push_back("-traditional-cpp");
+ else
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_dM);
+ Args.AddLastArg(CmdArgs, options::OPT_dD);
+
+ // Handle serialized diagnostics.
+ if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
+ CmdArgs.push_back("-serialize-diagnostic-file");
+ CmdArgs.push_back(Args.MakeArgString(A->getValue()));
+ }
+
+ if (Args.hasArg(options::OPT_fretain_comments_from_system_headers))
+ CmdArgs.push_back("-fretain-comments-from-system-headers");
+
+ // Forward -fcomment-block-commands to -cc1.
+ Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands);
+ // Forward -fparse-all-comments to -cc1.
+ Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments);
+
+ // Turn -fplugin=name.so into -load name.so
+ for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) {
+ CmdArgs.push_back("-load");
+ CmdArgs.push_back(A->getValue());
+ A->claim();
+ }
+
+ // Setup statistics file output.
+ if (const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ)) {
+ StringRef SaveStats = A->getValue();
+
+ SmallString<128> StatsFile;
+ bool DoSaveStats = false;
+ if (SaveStats == "obj") {
+ if (Output.isFilename()) {
+ StatsFile.assign(Output.getFilename());
+ llvm::sys::path::remove_filename(StatsFile);
+ }
+ DoSaveStats = true;
+ } else if (SaveStats == "cwd") {
+ DoSaveStats = true;
+ } else {
+ D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats;
+ }
+
+ if (DoSaveStats) {
+ StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput());
+ llvm::sys::path::append(StatsFile, BaseName);
+ llvm::sys::path::replace_extension(StatsFile, "stats");
+ CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") +
+ StatsFile));
+ }
+ }
+
+ // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
+ // parser.
+ // -finclude-default-header flag is for preprocessor,
+ // do not pass it to other cc1 commands when save-temps is enabled
+ if (C.getDriver().isSaveTempsEnabled() &&
+ !isa<PreprocessJobAction>(JA)) {
+ for (auto Arg : Args.filtered(options::OPT_Xclang)) {
+ Arg->claim();
+ if (StringRef(Arg->getValue()) != "-finclude-default-header")
+ CmdArgs.push_back(Arg->getValue());
+ }
+ }
+ else {
+ Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
+ }
+ for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
+ A->claim();
+
+ // We translate this by hand to the -cc1 argument, since nightly test uses
+ // it and developers have been trained to spell it with -mllvm. Both
+ // spellings are now deprecated and should be removed.
+ if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") {
+ CmdArgs.push_back("-disable-llvm-optzns");
+ } else {
+ A->render(Args, CmdArgs);
+ }
+ }
+
+ // With -save-temps, we want to save the unoptimized bitcode output from the
+ // CompileJobAction, use -disable-llvm-passes to get pristine IR generated
+ // by the frontend.
+ // When -fembed-bitcode is enabled, optimized bitcode is emitted because it
+ // has slightly different breakdown between stages.
+ // FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of
+ // pristine IR generated by the frontend. Ideally, a new compile action should
+ // be added so both IR can be captured.
+ if (C.getDriver().isSaveTempsEnabled() &&
+ !(C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO()) &&
+ isa<CompileJobAction>(JA))
+ CmdArgs.push_back("-disable-llvm-passes");
+
+ if (Output.getType() == types::TY_Dependencies) {
+ // Handled with other dependency code.
+ } else if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ addDashXForInput(Args, Input, CmdArgs);
+
+ if (Input.isFilename())
+ CmdArgs.push_back(Input.getFilename());
+ else
+ Input.getInputArg().renderAsInput(Args, CmdArgs);
+
+ Args.AddAllArgs(CmdArgs, options::OPT_undef);
+
+ const char *Exec = getToolChain().getDriver().getClangProgramPath();
+
+ // Optionally embed the -cc1 level arguments into the debug info, for build
+ // analysis.
+ // Also record command line arguments into the debug info if
+ // -grecord-gcc-switches options is set on.
+ // By default, -gno-record-gcc-switches is set on and no recording.
+ if (getToolChain().UseDwarfDebugFlags() ||
+ Args.hasFlag(options::OPT_grecord_gcc_switches,
+ options::OPT_gno_record_gcc_switches, false)) {
+ ArgStringList OriginalArgs;
+ for (const auto &Arg : Args)
+ Arg->render(Args, OriginalArgs);
+
+ SmallString<256> Flags;
+ Flags += Exec;
+ for (const char *OriginalArg : OriginalArgs) {
+ SmallString<128> EscapedArg;
+ EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
+ Flags += " ";
+ Flags += EscapedArg;
+ }
+ CmdArgs.push_back("-dwarf-debug-flags");
+ CmdArgs.push_back(Args.MakeArgString(Flags));
+ }
+
+ // Add the split debug info name to the command lines here so we
+ // can propagate it to the backend.
+ bool SplitDwarf = SplitDwarfArg && getToolChain().getTriple().isOSLinux() &&
+ (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
+ isa<BackendJobAction>(JA));
+ const char *SplitDwarfOut;
+ if (SplitDwarf) {
+ CmdArgs.push_back("-split-dwarf-file");
+ SplitDwarfOut = SplitDebugName(Args, Input);
+ CmdArgs.push_back(SplitDwarfOut);
+ }
+
+ // Host-side cuda compilation receives device-side outputs as Inputs[1...].
+ // Include them with -fcuda-include-gpubinary.
+ if (IsCuda && Inputs.size() > 1)
+ for (auto I = std::next(Inputs.begin()), E = Inputs.end(); I != E; ++I) {
+ CmdArgs.push_back("-fcuda-include-gpubinary");
+ CmdArgs.push_back(I->getFilename());
+ }
+
+ // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path
+ // to specify the result of the compile phase on the host, so the meaningful
+ // device declarations can be identified. Also, -fopenmp-is-device is passed
+ // along to tell the frontend that it is generating code for a device, so that
+ // only the relevant declarations are emitted.
+ if (IsOpenMPDevice) {
+ CmdArgs.push_back("-fopenmp-is-device");
+ if (Inputs.size() == 2) {
+ CmdArgs.push_back("-fopenmp-host-ir-file-path");
+ CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename()));
+ }
+ }
+
+ // For all the host OpenMP offloading compile jobs we need to pass the targets
+ // information using -fopenmp-targets= option.
+ if (isa<CompileJobAction>(JA) && JA.isHostOffloading(Action::OFK_OpenMP)) {
+ SmallString<128> TargetInfo("-fopenmp-targets=");
+
+ Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ);
+ assert(Tgts && Tgts->getNumValues() &&
+ "OpenMP offloading has to have targets specified.");
+ for (unsigned i = 0; i < Tgts->getNumValues(); ++i) {
+ if (i)
+ TargetInfo += ',';
+ // We need to get the string from the triple because it may be not exactly
+ // the same as the one we get directly from the arguments.
+ llvm::Triple T(Tgts->getValue(i));
+ TargetInfo += T.getTriple();
+ }
+ CmdArgs.push_back(Args.MakeArgString(TargetInfo.str()));
+ }
+
+ bool WholeProgramVTables =
+ Args.hasFlag(options::OPT_fwhole_program_vtables,
+ options::OPT_fno_whole_program_vtables, false);
+ if (WholeProgramVTables) {
+ if (!D.isUsingLTO())
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << "-fwhole-program-vtables"
+ << "-flto";
+ CmdArgs.push_back("-fwhole-program-vtables");
+ }
+
+ // Finally add the compile command to the compilation.
+ if (Args.hasArg(options::OPT__SLASH_fallback) &&
+ Output.getType() == types::TY_Object &&
+ (InputType == types::TY_C || InputType == types::TY_CXX)) {
+ auto CLCommand =
+ getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput);
+ C.addCommand(llvm::make_unique<FallbackCommand>(
+ JA, *this, Exec, CmdArgs, Inputs, std::move(CLCommand)));
+ } else if (Args.hasArg(options::OPT__SLASH_fallback) &&
+ isa<PrecompileJobAction>(JA)) {
+ // In /fallback builds, run the main compilation even if the pch generation
+ // fails, so that the main compilation's fallback to cl.exe runs.
+ C.addCommand(llvm::make_unique<ForceSuccessCommand>(JA, *this, Exec,
+ CmdArgs, Inputs));
+ } else {
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ }
+
+ // Handle the debug info splitting at object creation time if we're
+ // creating an object.
+ // TODO: Currently only works on linux with newer objcopy.
+ if (SplitDwarf && Output.getType() == types::TY_Object)
+ SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut);
+
+ if (Arg *A = Args.getLastArg(options::OPT_pg))
+ if (Args.hasArg(options::OPT_fomit_frame_pointer))
+ D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer"
+ << A->getAsString(Args);
+
+ // Claim some arguments which clang supports automatically.
+
+ // -fpch-preprocess is used with gcc to add a special marker in the output to
+ // include the PCH file. Clang's PTH solution is completely transparent, so we
+ // do not need to deal with it at all.
+ Args.ClaimAllArgs(options::OPT_fpch_preprocess);
+
+ // Claim some arguments which clang doesn't support, but we don't
+ // care to warn the user about.
+ Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group);
+ Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);
+
+ // Disable warnings for clang -E -emit-llvm foo.c
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+}
+
+Clang::Clang(const ToolChain &TC)
+ // CAUTION! The first constructor argument ("clang") is not arbitrary,
+ // as it is for other tools. Some operations on a Tool actually test
+ // whether that tool is Clang based on the Tool's Name as a string.
+ : Tool("clang", "clang frontend", TC, RF_Full) {}
+
+Clang::~Clang() {}
+
+/// Add options related to the Objective-C runtime/ABI.
+///
+/// Returns true if the runtime is non-fragile.
+ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
+ ArgStringList &cmdArgs,
+ RewriteKind rewriteKind) const {
+ // Look for the controlling runtime option.
+ Arg *runtimeArg =
+ args.getLastArg(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
+ options::OPT_fobjc_runtime_EQ);
+
+ // Just forward -fobjc-runtime= to the frontend. This supercedes
+ // options about fragility.
+ if (runtimeArg &&
+ runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) {
+ ObjCRuntime runtime;
+ StringRef value = runtimeArg->getValue();
+ if (runtime.tryParse(value)) {
+ getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime)
+ << value;
+ }
+
+ runtimeArg->render(args, cmdArgs);
+ return runtime;
+ }
+
+ // Otherwise, we'll need the ABI "version". Version numbers are
+ // slightly confusing for historical reasons:
+ // 1 - Traditional "fragile" ABI
+ // 2 - Non-fragile ABI, version 1
+ // 3 - Non-fragile ABI, version 2
+ unsigned objcABIVersion = 1;
+ // If -fobjc-abi-version= is present, use that to set the version.
+ if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
+ StringRef value = abiArg->getValue();
+ if (value == "1")
+ objcABIVersion = 1;
+ else if (value == "2")
+ objcABIVersion = 2;
+ else if (value == "3")
+ objcABIVersion = 3;
+ else
+ getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) << value;
+ } else {
+ // Otherwise, determine if we are using the non-fragile ABI.
+ bool nonFragileABIIsDefault =
+ (rewriteKind == RK_NonFragile ||
+ (rewriteKind == RK_None &&
+ getToolChain().IsObjCNonFragileABIDefault()));
+ if (args.hasFlag(options::OPT_fobjc_nonfragile_abi,
+ options::OPT_fno_objc_nonfragile_abi,
+ nonFragileABIIsDefault)) {
+// Determine the non-fragile ABI version to use.
+#ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO
+ unsigned nonFragileABIVersion = 1;
+#else
+ unsigned nonFragileABIVersion = 2;
+#endif
+
+ if (Arg *abiArg =
+ args.getLastArg(options::OPT_fobjc_nonfragile_abi_version_EQ)) {
+ StringRef value = abiArg->getValue();
+ if (value == "1")
+ nonFragileABIVersion = 1;
+ else if (value == "2")
+ nonFragileABIVersion = 2;
+ else
+ getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported)
+ << value;
+ }
+
+ objcABIVersion = 1 + nonFragileABIVersion;
+ } else {
+ objcABIVersion = 1;
+ }
+ }
+
+ // We don't actually care about the ABI version other than whether
+ // it's non-fragile.
+ bool isNonFragile = objcABIVersion != 1;
+
+ // If we have no runtime argument, ask the toolchain for its default runtime.
+ // However, the rewriter only really supports the Mac runtime, so assume that.
+ ObjCRuntime runtime;
+ if (!runtimeArg) {
+ switch (rewriteKind) {
+ case RK_None:
+ runtime = getToolChain().getDefaultObjCRuntime(isNonFragile);
+ break;
+ case RK_Fragile:
+ runtime = ObjCRuntime(ObjCRuntime::FragileMacOSX, VersionTuple());
+ break;
+ case RK_NonFragile:
+ runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple());
+ break;
+ }
+
+ // -fnext-runtime
+ } else if (runtimeArg->getOption().matches(options::OPT_fnext_runtime)) {
+ // On Darwin, make this use the default behavior for the toolchain.
+ if (getToolChain().getTriple().isOSDarwin()) {
+ runtime = getToolChain().getDefaultObjCRuntime(isNonFragile);
+
+ // Otherwise, build for a generic macosx port.
+ } else {
+ runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple());
+ }
+
+ // -fgnu-runtime
+ } else {
+ assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime));
+ // Legacy behaviour is to target the gnustep runtime if we are in
+ // non-fragile mode or the GCC runtime in fragile mode.
+ if (isNonFragile)
+ runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1, 6));
+ else
+ runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple());
+ }
+
+ cmdArgs.push_back(
+ args.MakeArgString("-fobjc-runtime=" + runtime.getAsString()));
+ return runtime;
+}
+
+static bool maybeConsumeDash(const std::string &EH, size_t &I) {
+ bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-');
+ I += HaveDash;
+ return !HaveDash;
+}
+
+namespace {
+struct EHFlags {
+ bool Synch = false;
+ bool Asynch = false;
+ bool NoUnwindC = false;
+};
+} // end anonymous namespace
+
+/// /EH controls whether to run destructor cleanups when exceptions are
+/// thrown. There are three modifiers:
+/// - s: Cleanup after "synchronous" exceptions, aka C++ exceptions.
+/// - a: Cleanup after "asynchronous" exceptions, aka structured exceptions.
+/// The 'a' modifier is unimplemented and fundamentally hard in LLVM IR.
+/// - c: Assume that extern "C" functions are implicitly nounwind.
+/// The default is /EHs-c-, meaning cleanups are disabled.
+static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
+ EHFlags EH;
+
+ std::vector<std::string> EHArgs =
+ Args.getAllArgValues(options::OPT__SLASH_EH);
+ for (auto EHVal : EHArgs) {
+ for (size_t I = 0, E = EHVal.size(); I != E; ++I) {
+ switch (EHVal[I]) {
+ case 'a':
+ EH.Asynch = maybeConsumeDash(EHVal, I);
+ if (EH.Asynch)
+ EH.Synch = false;
+ continue;
+ case 'c':
+ EH.NoUnwindC = maybeConsumeDash(EHVal, I);
+ continue;
+ case 's':
+ EH.Synch = maybeConsumeDash(EHVal, I);
+ if (EH.Synch)
+ EH.Asynch = false;
+ continue;
+ default:
+ break;
+ }
+ D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal;
+ break;
+ }
+ }
+ // The /GX, /GX- flags are only processed if there are not /EH flags.
+ // The default is that /GX is not specified.
+ if (EHArgs.empty() &&
+ Args.hasFlag(options::OPT__SLASH_GX, options::OPT__SLASH_GX_,
+ /*default=*/false)) {
+ EH.Synch = true;
+ EH.NoUnwindC = true;
+ }
+
+ return EH;
+}
+
+void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
+ ArgStringList &CmdArgs,
+ codegenoptions::DebugInfoKind *DebugInfoKind,
+ bool *EmitCodeView) const {
+ unsigned RTOptionID = options::OPT__SLASH_MT;
+
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ // The /LDd option implies /MTd. The dependent lib part can be overridden,
+ // but defining _DEBUG is sticky.
+ RTOptionID = options::OPT__SLASH_MTd;
+
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group))
+ RTOptionID = A->getOption().getID();
+
+ StringRef FlagForCRT;
+ switch (RTOptionID) {
+ case options::OPT__SLASH_MD:
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DLL");
+ FlagForCRT = "--dependent-lib=msvcrt";
+ break;
+ case options::OPT__SLASH_MDd:
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DLL");
+ FlagForCRT = "--dependent-lib=msvcrtd";
+ break;
+ case options::OPT__SLASH_MT:
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-flto-visibility-public-std");
+ FlagForCRT = "--dependent-lib=libcmt";
+ break;
+ case options::OPT__SLASH_MTd:
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-flto-visibility-public-std");
+ FlagForCRT = "--dependent-lib=libcmtd";
+ break;
+ default:
+ llvm_unreachable("Unexpected option ID.");
+ }
+
+ if (Args.hasArg(options::OPT__SLASH_Zl)) {
+ CmdArgs.push_back("-D_VC_NODEFAULTLIB");
+ } else {
+ CmdArgs.push_back(FlagForCRT.data());
+
+ // This provides POSIX compatibility (maps 'open' to '_open'), which most
+ // users want. The /Za flag to cl.exe turns this off, but it's not
+ // implemented in clang.
+ CmdArgs.push_back("--dependent-lib=oldnames");
+ }
+
+ // Both /showIncludes and /E (and /EP) write to stdout. Allowing both
+ // would produce interleaved output, so ignore /showIncludes in such cases.
+ if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP))
+ if (Arg *A = Args.getLastArg(options::OPT_show_includes))
+ A->render(Args, CmdArgs);
+
+ // This controls whether or not we emit RTTI data for polymorphic types.
+ if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR,
+ /*default=*/false))
+ CmdArgs.push_back("-fno-rtti-data");
+
+ // This controls whether or not we emit stack-protector instrumentation.
+ // In MSVC, Buffer Security Check (/GS) is on by default.
+ if (Args.hasFlag(options::OPT__SLASH_GS, options::OPT__SLASH_GS_,
+ /*default=*/true)) {
+ CmdArgs.push_back("-stack-protector");
+ CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong)));
+ }
+
+ // Emit CodeView if -Z7, -Zd, or -gline-tables-only are present.
+ if (Arg *DebugInfoArg =
+ Args.getLastArg(options::OPT__SLASH_Z7, options::OPT__SLASH_Zd,
+ options::OPT_gline_tables_only)) {
+ *EmitCodeView = true;
+ if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7))
+ *DebugInfoKind = codegenoptions::LimitedDebugInfo;
+ else
+ *DebugInfoKind = codegenoptions::DebugLineTablesOnly;
+ CmdArgs.push_back("-gcodeview");
+ } else {
+ *EmitCodeView = false;
+ }
+
+ const Driver &D = getToolChain().getDriver();
+ EHFlags EH = parseClangCLEHFlags(D, Args);
+ if (EH.Synch || EH.Asynch) {
+ if (types::isCXX(InputType))
+ CmdArgs.push_back("-fcxx-exceptions");
+ CmdArgs.push_back("-fexceptions");
+ }
+ if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC)
+ CmdArgs.push_back("-fexternc-nounwind");
+
+ // /EP should expand to -E -P.
+ if (Args.hasArg(options::OPT__SLASH_EP)) {
+ CmdArgs.push_back("-E");
+ CmdArgs.push_back("-P");
+ }
+
+ unsigned VolatileOptionID;
+ if (getToolChain().getArch() == llvm::Triple::x86_64 ||
+ getToolChain().getArch() == llvm::Triple::x86)
+ VolatileOptionID = options::OPT__SLASH_volatile_ms;
+ else
+ VolatileOptionID = options::OPT__SLASH_volatile_iso;
+
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group))
+ VolatileOptionID = A->getOption().getID();
+
+ if (VolatileOptionID == options::OPT__SLASH_volatile_ms)
+ CmdArgs.push_back("-fms-volatile");
+
+ Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg);
+ Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb);
+ if (MostGeneralArg && BestCaseArg)
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << MostGeneralArg->getAsString(Args) << BestCaseArg->getAsString(Args);
+
+ if (MostGeneralArg) {
+ Arg *SingleArg = Args.getLastArg(options::OPT__SLASH_vms);
+ Arg *MultipleArg = Args.getLastArg(options::OPT__SLASH_vmm);
+ Arg *VirtualArg = Args.getLastArg(options::OPT__SLASH_vmv);
+
+ Arg *FirstConflict = SingleArg ? SingleArg : MultipleArg;
+ Arg *SecondConflict = VirtualArg ? VirtualArg : MultipleArg;
+ if (FirstConflict && SecondConflict && FirstConflict != SecondConflict)
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << FirstConflict->getAsString(Args)
+ << SecondConflict->getAsString(Args);
+
+ if (SingleArg)
+ CmdArgs.push_back("-fms-memptr-rep=single");
+ else if (MultipleArg)
+ CmdArgs.push_back("-fms-memptr-rep=multiple");
+ else
+ CmdArgs.push_back("-fms-memptr-rep=virtual");
+ }
+
+ // Parse the default calling convention options.
+ if (Arg *CCArg =
+ Args.getLastArg(options::OPT__SLASH_Gd, options::OPT__SLASH_Gr,
+ options::OPT__SLASH_Gz, options::OPT__SLASH_Gv)) {
+ unsigned DCCOptId = CCArg->getOption().getID();
+ const char *DCCFlag = nullptr;
+ bool ArchSupported = true;
+ llvm::Triple::ArchType Arch = getToolChain().getArch();
+ switch (DCCOptId) {
+ case options::OPT__SLASH_Gd:
+ DCCFlag = "-fdefault-calling-conv=cdecl";
+ break;
+ case options::OPT__SLASH_Gr:
+ ArchSupported = Arch == llvm::Triple::x86;
+ DCCFlag = "-fdefault-calling-conv=fastcall";
+ break;
+ case options::OPT__SLASH_Gz:
+ ArchSupported = Arch == llvm::Triple::x86;
+ DCCFlag = "-fdefault-calling-conv=stdcall";
+ break;
+ case options::OPT__SLASH_Gv:
+ ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64;
+ DCCFlag = "-fdefault-calling-conv=vectorcall";
+ break;
+ }
+
+ // MSVC doesn't warn if /Gr or /Gz is used on x64, so we don't either.
+ if (ArchSupported && DCCFlag)
+ CmdArgs.push_back(DCCFlag);
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ))
+ A->render(Args, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) {
+ CmdArgs.push_back("-fdiagnostics-format");
+ if (Args.hasArg(options::OPT__SLASH_fallback))
+ CmdArgs.push_back("msvc-fallback");
+ else
+ CmdArgs.push_back("msvc");
+ }
+}
+
+visualstudio::Compiler *Clang::getCLFallback() const {
+ if (!CLFallback)
+ CLFallback.reset(new visualstudio::Compiler(getToolChain()));
+ return CLFallback.get();
+}
+
+
+const char *Clang::getBaseInputName(const ArgList &Args,
+ const InputInfo &Input) {
+ return Args.MakeArgString(llvm::sys::path::filename(Input.getBaseInput()));
+}
+
+const char *Clang::getBaseInputStem(const ArgList &Args,
+ const InputInfoList &Inputs) {
+ const char *Str = getBaseInputName(Args, Inputs[0]);
+
+ if (const char *End = strrchr(Str, '.'))
+ return Args.MakeArgString(std::string(Str, End));
+
+ return Str;
+}
+
+const char *Clang::getDependencyFileName(const ArgList &Args,
+ const InputInfoList &Inputs) {
+ // FIXME: Think about this more.
+ std::string Res;
+
+ if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
+ std::string Str(OutputOpt->getValue());
+ Res = Str.substr(0, Str.rfind('.'));
+ } else {
+ Res = getBaseInputStem(Args, Inputs);
+ }
+ return Args.MakeArgString(Res + ".d");
+}
+
+// Begin ClangAs
+
+void ClangAs::AddMIPSTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ StringRef CPUName;
+ StringRef ABIName;
+ const llvm::Triple &Triple = getToolChain().getTriple();
+ mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
+
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(ABIName.data());
+}
+
+void ClangAs::AddX86TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value == "intel" || Value == "att") {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
+ } else {
+ getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+ }
+}
+
+void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ assert(Inputs.size() == 1 && "Unexpected number of inputs.");
+ const InputInfo &Input = Inputs[0];
+
+ const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
+ const std::string &TripleStr = Triple.getTriple();
+ const auto &D = getToolChain().getDriver();
+
+ // Don't warn about "clang -w -c foo.s"
+ Args.ClaimAllArgs(options::OPT_w);
+ // and "clang -emit-llvm -c foo.s"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+
+ claimNoWarnArgs(Args);
+
+ // Invoke ourselves in -cc1as mode.
+ //
+ // FIXME: Implement custom jobs for internal actions.
+ CmdArgs.push_back("-cc1as");
+
+ // Add the "effective" target triple.
+ CmdArgs.push_back("-triple");
+ CmdArgs.push_back(Args.MakeArgString(TripleStr));
+
+ // Set the output mode, we currently only expect to be used as a real
+ // assembler.
+ CmdArgs.push_back("-filetype");
+ CmdArgs.push_back("obj");
+
+ // Set the main file name, so that debug info works even with
+ // -save-temps or preprocessed assembly.
+ CmdArgs.push_back("-main-file-name");
+ CmdArgs.push_back(Clang::getBaseInputName(Args, Input));
+
+ // Add the target cpu
+ std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true);
+ if (!CPU.empty()) {
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString(CPU));
+ }
+
+ // Add the target features
+ getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, true);
+
+ // Ignore explicit -force_cpusubtype_ALL option.
+ (void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
+
+ // Pass along any -I options so we get proper .include search paths.
+ Args.AddAllArgs(CmdArgs, options::OPT_I_Group);
+
+ // Determine the original source input.
+ const Action *SourceAction = &JA;
+ while (SourceAction->getKind() != Action::InputClass) {
+ assert(!SourceAction->getInputs().empty() && "unexpected root action!");
+ SourceAction = SourceAction->getInputs()[0];
+ }
+
+ // Forward -g and handle debug info related flags, assuming we are dealing
+ // with an actual assembly file.
+ bool WantDebug = false;
+ unsigned DwarfVersion = 0;
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
+ WantDebug = !A->getOption().matches(options::OPT_g0) &&
+ !A->getOption().matches(options::OPT_ggdb0);
+ if (WantDebug)
+ DwarfVersion = DwarfVersionNum(A->getSpelling());
+ }
+ if (DwarfVersion == 0)
+ DwarfVersion = getToolChain().GetDefaultDwarfVersion();
+
+ codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
+
+ if (SourceAction->getType() == types::TY_Asm ||
+ SourceAction->getType() == types::TY_PP_Asm) {
+ // You might think that it would be ok to set DebugInfoKind outside of
+ // the guard for source type, however there is a test which asserts
+ // that some assembler invocation receives no -debug-info-kind,
+ // and it's not clear whether that test is just overly restrictive.
+ DebugInfoKind = (WantDebug ? codegenoptions::LimitedDebugInfo
+ : codegenoptions::NoDebugInfo);
+ // Add the -fdebug-compilation-dir flag if needed.
+ addDebugCompDirArg(Args, CmdArgs);
+
+ // Set the AT_producer to the clang version when using the integrated
+ // assembler on assembly source files.
+ CmdArgs.push_back("-dwarf-debug-producer");
+ CmdArgs.push_back(Args.MakeArgString(getClangFullVersion()));
+
+ // And pass along -I options
+ Args.AddAllArgs(CmdArgs, options::OPT_I);
+ }
+ RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
+ llvm::DebuggerKind::Default);
+ RenderDebugInfoCompressionArgs(Args, CmdArgs, D);
+
+
+ // Handle -fPIC et al -- the relocation-model affects the assembler
+ // for some targets.
+ llvm::Reloc::Model RelocationModel;
+ unsigned PICLevel;
+ bool IsPIE;
+ std::tie(RelocationModel, PICLevel, IsPIE) =
+ ParsePICArgs(getToolChain(), Args);
+
+ const char *RMName = RelocationModelName(RelocationModel);
+ if (RMName) {
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back(RMName);
+ }
+
+ // Optionally embed the -cc1as level arguments into the debug info, for build
+ // analysis.
+ if (getToolChain().UseDwarfDebugFlags()) {
+ ArgStringList OriginalArgs;
+ for (const auto &Arg : Args)
+ Arg->render(Args, OriginalArgs);
+
+ SmallString<256> Flags;
+ const char *Exec = getToolChain().getDriver().getClangProgramPath();
+ Flags += Exec;
+ for (const char *OriginalArg : OriginalArgs) {
+ SmallString<128> EscapedArg;
+ EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
+ Flags += " ";
+ Flags += EscapedArg;
+ }
+ CmdArgs.push_back("-dwarf-debug-flags");
+ CmdArgs.push_back(Args.MakeArgString(Flags));
+ }
+
+ // FIXME: Add -static support, once we have it.
+
+ // Add target specific flags.
+ switch (getToolChain().getArch()) {
+ default:
+ break;
+
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ AddMIPSTargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ AddX86TargetArgs(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ // This isn't in AddARMTargetArgs because we want to do this for assembly
+ // only, not C/C++.
+ if (Args.hasFlag(options::OPT_mdefault_build_attributes,
+ options::OPT_mno_default_build_attributes, true)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-arm-add-build-attributes");
+ }
+ break;
+ }
+
+ // Consume all the warning flags. Usually this would be handled more
+ // gracefully by -cc1 (warning about unknown warning flags, etc) but -cc1as
+ // doesn't handle that so rather than warning about unused flags that are
+ // actually used, we'll lie by omission instead.
+ // FIXME: Stop lying and consume only the appropriate driver flags
+ Args.ClaimAllArgs(options::OPT_W_Group);
+
+ CollectArgsForIntegratedAssembler(C, Args, CmdArgs,
+ getToolChain().getDriver());
+
+ Args.AddAllArgs(CmdArgs, options::OPT_mllvm);
+
+ assert(Output.isFilename() && "Unexpected lipo output.");
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ assert(Input.isFilename() && "Invalid input.");
+ CmdArgs.push_back(Input.getFilename());
+
+ const char *Exec = getToolChain().getDriver().getClangProgramPath();
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+
+ // Handle the debug info splitting at object creation time if we're
+ // creating an object.
+ // TODO: Currently only works on linux with newer objcopy.
+ if (Args.hasArg(options::OPT_gsplit_dwarf) &&
+ getToolChain().getTriple().isOSLinux())
+ SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
+ SplitDebugName(Args, Input));
+}
+
+// Begin OffloadBundler
+
+void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const {
+ // The version with only one output is expected to refer to a bundling job.
+ assert(isa<OffloadBundlingJobAction>(JA) && "Expecting bundling job!");
+
+ // The bundling command looks like this:
+ // clang-offload-bundler -type=bc
+ // -targets=host-triple,openmp-triple1,openmp-triple2
+ // -outputs=input_file
+ // -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2"
+
+ ArgStringList CmdArgs;
+
+ // Get the type.
+ CmdArgs.push_back(TCArgs.MakeArgString(
+ Twine("-type=") + types::getTypeTempSuffix(Output.getType())));
+
+ assert(JA.getInputs().size() == Inputs.size() &&
+ "Not have inputs for all dependence actions??");
+
+ // Get the targets.
+ SmallString<128> Triples;
+ Triples += "-targets=";
+ for (unsigned I = 0; I < Inputs.size(); ++I) {
+ if (I)
+ Triples += ',';
+
+ Action::OffloadKind CurKind = Action::OFK_Host;
+ const ToolChain *CurTC = &getToolChain();
+ const Action *CurDep = JA.getInputs()[I];
+
+ if (const auto *OA = dyn_cast<OffloadAction>(CurDep)) {
+ OA->doOnEachDependence([&](Action *A, const ToolChain *TC, const char *) {
+ CurKind = A->getOffloadingDeviceKind();
+ CurTC = TC;
+ });
+ }
+ Triples += Action::GetOffloadKindName(CurKind);
+ Triples += '-';
+ Triples += CurTC->getTriple().normalize();
+ }
+ CmdArgs.push_back(TCArgs.MakeArgString(Triples));
+
+ // Get bundled file command.
+ CmdArgs.push_back(
+ TCArgs.MakeArgString(Twine("-outputs=") + Output.getFilename()));
+
+ // Get unbundled files command.
+ SmallString<128> UB;
+ UB += "-inputs=";
+ for (unsigned I = 0; I < Inputs.size(); ++I) {
+ if (I)
+ UB += ',';
+ UB += Inputs[I].getFilename();
+ }
+ CmdArgs.push_back(TCArgs.MakeArgString(UB));
+
+ // All the inputs are encoded as commands.
+ C.addCommand(llvm::make_unique<Command>(
+ JA, *this,
+ TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
+ CmdArgs, None));
+}
+
+void OffloadBundler::ConstructJobMultipleOutputs(
+ Compilation &C, const JobAction &JA, const InputInfoList &Outputs,
+ const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const {
+ // The version with multiple outputs is expected to refer to a unbundling job.
+ auto &UA = cast<OffloadUnbundlingJobAction>(JA);
+
+ // The unbundling command looks like this:
+ // clang-offload-bundler -type=bc
+ // -targets=host-triple,openmp-triple1,openmp-triple2
+ // -inputs=input_file
+ // -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2"
+ // -unbundle
+
+ ArgStringList CmdArgs;
+
+ assert(Inputs.size() == 1 && "Expecting to unbundle a single file!");
+ InputInfo Input = Inputs.front();
+
+ // Get the type.
+ CmdArgs.push_back(TCArgs.MakeArgString(
+ Twine("-type=") + types::getTypeTempSuffix(Input.getType())));
+
+ // Get the targets.
+ SmallString<128> Triples;
+ Triples += "-targets=";
+ auto DepInfo = UA.getDependentActionsInfo();
+ for (unsigned I = 0; I < DepInfo.size(); ++I) {
+ if (I)
+ Triples += ',';
+
+ auto &Dep = DepInfo[I];
+ Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind);
+ Triples += '-';
+ Triples += Dep.DependentToolChain->getTriple().normalize();
+ }
+
+ CmdArgs.push_back(TCArgs.MakeArgString(Triples));
+
+ // Get bundled file command.
+ CmdArgs.push_back(
+ TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename()));
+
+ // Get unbundled files command.
+ SmallString<128> UB;
+ UB += "-outputs=";
+ for (unsigned I = 0; I < Outputs.size(); ++I) {
+ if (I)
+ UB += ',';
+ UB += Outputs[I].getFilename();
+ }
+ CmdArgs.push_back(TCArgs.MakeArgString(UB));
+ CmdArgs.push_back("-unbundle");
+
+ // All the inputs are encoded as commands.
+ C.addCommand(llvm::make_unique<Command>(
+ JA, *this,
+ TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
+ CmdArgs, None));
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.h
new file mode 100644
index 0000000..d53c3b4
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.h
@@ -0,0 +1,149 @@
+//===--- Clang.h - Clang Tool and ToolChain Implementations ====-*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H
+
+#include "MSVC.h"
+#include "clang/Basic/DebugInfoOptions.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/Types.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+class ObjCRuntime;
+namespace driver {
+
+namespace tools {
+
+/// \brief Clang compiler tool.
+class LLVM_LIBRARY_VISIBILITY Clang : public Tool {
+public:
+ static const char *getBaseInputName(const llvm::opt::ArgList &Args,
+ const InputInfo &Input);
+ static const char *getBaseInputStem(const llvm::opt::ArgList &Args,
+ const InputInfoList &Inputs);
+ static const char *getDependencyFileName(const llvm::opt::ArgList &Args,
+ const InputInfoList &Inputs);
+
+private:
+ void AddPreprocessingOptions(Compilation &C, const JobAction &JA,
+ const Driver &D, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ const InputInfo &Output,
+ const InputInfoList &Inputs) const;
+
+ void AddAArch64TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddARMTargetArgs(const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ bool KernelOrKext) const;
+ void AddARM64TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddPPCTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddR600TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddSparcTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddSystemZTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddX86TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddHexagonTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddLanaiTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile };
+
+ ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args,
+ llvm::opt::ArgStringList &cmdArgs,
+ RewriteKind rewrite) const;
+
+ void AddClangCLArgs(const llvm::opt::ArgList &Args, types::ID InputType,
+ llvm::opt::ArgStringList &CmdArgs,
+ codegenoptions::DebugInfoKind *DebugInfoKind,
+ bool *EmitCodeView) const;
+
+ visualstudio::Compiler *getCLFallback() const;
+
+ mutable std::unique_ptr<visualstudio::Compiler> CLFallback;
+
+ mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr;
+ void DumpCompilationDatabase(Compilation &C, StringRef Filename,
+ StringRef Target,
+ const InputInfo &Output, const InputInfo &Input,
+ const llvm::opt::ArgList &Args) const;
+
+public:
+ Clang(const ToolChain &TC);
+ ~Clang() override;
+
+ bool hasGoodDiagnostics() const override { return true; }
+ bool hasIntegratedAssembler() const override { return true; }
+ bool hasIntegratedCPP() const override { return true; }
+ bool canEmitIR() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+/// \brief Clang integrated assembler tool.
+class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
+public:
+ ClangAs(const ToolChain &TC)
+ : Tool("clang::as", "clang integrated assembler", TC, RF_Full) {}
+ void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void AddX86TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ bool hasGoodDiagnostics() const override { return true; }
+ bool hasIntegratedAssembler() const override { return false; }
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+/// Offload bundler tool.
+class LLVM_LIBRARY_VISIBILITY OffloadBundler final : public Tool {
+public:
+ OffloadBundler(const ToolChain &TC)
+ : Tool("offload bundler", "clang-offload-bundler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+ void ConstructJobMultipleOutputs(Compilation &C, const JobAction &JA,
+ const InputInfoList &Outputs,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace tools
+
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.cpp
new file mode 100644
index 0000000..0f6c712
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.cpp
@@ -0,0 +1,145 @@
+//===--- CloudABI.cpp - CloudABI ToolChain Implementations ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloudABI.h"
+#include "InputInfo.h"
+#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const ToolChain &ToolChain = getToolChain();
+ const Driver &D = ToolChain.getDriver();
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ // CloudABI only supports static linkage.
+ CmdArgs.push_back("-Bstatic");
+ CmdArgs.push_back("--no-dynamic-linker");
+
+ // Provide PIE linker flags in case PIE is default for the architecture.
+ if (ToolChain.isPIEDefault()) {
+ CmdArgs.push_back("-pie");
+ CmdArgs.push_back("-zrelro");
+ }
+
+ CmdArgs.push_back("--eh-frame-hdr");
+ CmdArgs.push_back("--gc-sections");
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+ Args.AddAllArgs(CmdArgs,
+ {options::OPT_T_Group, options::OPT_e, options::OPT_s,
+ options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
+
+ if (D.isUsingLTO())
+ AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX())
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lcompiler_rt");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+// CloudABI - CloudABI tool chain which can call ld(1) directly.
+
+CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ SmallString<128> P(getDriver().Dir);
+ llvm::sys::path::append(P, "..", getTriple().str(), "lib");
+ getFilePaths().push_back(P.str());
+}
+
+std::string CloudABI::findLibCxxIncludePath() const {
+ SmallString<128> P(getDriver().Dir);
+ llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1");
+ return P.str();
+}
+
+void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ CmdArgs.push_back("-lunwind");
+}
+
+Tool *CloudABI::buildLinker() const {
+ return new tools::cloudabi::Linker(*this);
+}
+
+bool CloudABI::isPIEDefault() const {
+ // Only enable PIE on architectures that support PC-relative
+ // addressing. PC-relative addressing is required, as the process
+ // startup code must be able to relocate itself.
+ switch (getTriple().getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::x86_64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+SanitizerMask CloudABI::getSupportedSanitizers() const {
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::SafeStack;
+ return Res;
+}
+
+SanitizerMask CloudABI::getDefaultSanitizers() const {
+ return SanitizerKind::SafeStack;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.h
new file mode 100644
index 0000000..a284eb3
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CloudABI.h
@@ -0,0 +1,69 @@
+//===--- CloudABI.h - CloudABI ToolChain Implementations --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// cloudabi -- Directly call GNU Binutils linker
+namespace cloudabi {
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("cloudabi::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace cloudabi
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF {
+public:
+ CloudABI(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ bool HasNativeLLVMSupport() const override { return true; }
+
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
+
+ CXXStdlibType
+ GetCXXStdlibType(const llvm::opt::ArgList &Args) const override {
+ return ToolChain::CST_Libcxx;
+ }
+ std::string findLibCxxIncludePath() const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ bool isPIEDefault() const override;
+ SanitizerMask getSupportedSanitizers() const override;
+ SanitizerMask getDefaultSanitizers() const override;
+
+protected:
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp
new file mode 100644
index 0000000..00bd60b
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -0,0 +1,1025 @@
+//===--- CommonArgs.cpp - Args handling for multiple toolchains -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommonArgs.h"
+#include "InputInfo.h"
+#include "Hexagon.h"
+#include "Arch/AArch64.h"
+#include "Arch/ARM.h"
+#include "Arch/Mips.h"
+#include "Arch/PPC.h"
+#include "Arch/SystemZ.h"
+#include "Arch/X86.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/Version.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Action.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "clang/Driver/ToolChain.h"
+#include "clang/Driver/Util.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/YAMLParser.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+void tools::addPathIfExists(const Driver &D, const Twine &Path,
+ ToolChain::path_list &Paths) {
+ if (D.getVFS().exists(Path))
+ Paths.push_back(Path.str());
+}
+
+void tools::handleTargetFeaturesGroup(const ArgList &Args,
+ std::vector<StringRef> &Features,
+ OptSpecifier Group) {
+ for (const Arg *A : Args.filtered(Group)) {
+ StringRef Name = A->getOption().getName();
+ A->claim();
+
+ // Skip over "-m".
+ assert(Name.startswith("m") && "Invalid feature name.");
+ Name = Name.substr(1);
+
+ bool IsNegative = Name.startswith("no-");
+ if (IsNegative)
+ Name = Name.substr(3);
+ Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
+ }
+}
+
+void tools::addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs,
+ const char *ArgName, const char *EnvVar) {
+ const char *DirList = ::getenv(EnvVar);
+ bool CombinedArg = false;
+
+ if (!DirList)
+ return; // Nothing to do.
+
+ StringRef Name(ArgName);
+ if (Name.equals("-I") || Name.equals("-L"))
+ CombinedArg = true;
+
+ StringRef Dirs(DirList);
+ if (Dirs.empty()) // Empty string should not add '.'.
+ return;
+
+ StringRef::size_type Delim;
+ while ((Delim = Dirs.find(llvm::sys::EnvPathSeparator)) != StringRef::npos) {
+ if (Delim == 0) { // Leading colon.
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + "."));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ }
+ } else {
+ if (CombinedArg) {
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim)));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim)));
+ }
+ }
+ Dirs = Dirs.substr(Delim + 1);
+ }
+
+ if (Dirs.empty()) { // Trailing colon.
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + "."));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(".");
+ }
+ } else { // Add the last path.
+ if (CombinedArg) {
+ CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs));
+ } else {
+ CmdArgs.push_back(ArgName);
+ CmdArgs.push_back(Args.MakeArgString(Dirs));
+ }
+ }
+}
+
+void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs,
+ const ArgList &Args, ArgStringList &CmdArgs,
+ const JobAction &JA) {
+ const Driver &D = TC.getDriver();
+
+ // Add extra linker input arguments which are not treated as inputs
+ // (constructed via -Xarch_).
+ Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input);
+
+ for (const auto &II : Inputs) {
+ // If the current tool chain refers to an OpenMP offloading host, we should
+ // ignore inputs that refer to OpenMP offloading devices - they will be
+ // embedded according to a proper linker script.
+ if (auto *IA = II.getAction())
+ if (JA.isHostOffloading(Action::OFK_OpenMP) &&
+ IA->isDeviceOffloading(Action::OFK_OpenMP))
+ continue;
+
+ if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType()))
+ // Don't try to pass LLVM inputs unless we have native support.
+ D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString();
+
+ // Add filenames immediately.
+ if (II.isFilename()) {
+ CmdArgs.push_back(II.getFilename());
+ continue;
+ }
+
+ // Otherwise, this is a linker input argument.
+ const Arg &A = II.getInputArg();
+
+ // Handle reserved library options.
+ if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx))
+ TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+ else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext))
+ TC.AddCCKextLibArgs(Args, CmdArgs);
+ else if (A.getOption().matches(options::OPT_z)) {
+ // Pass -z prefix for gcc linker compatibility.
+ A.claim();
+ A.render(Args, CmdArgs);
+ } else {
+ A.renderAsInput(Args, CmdArgs);
+ }
+ }
+
+ // LIBRARY_PATH - included following the user specified library paths.
+ // and only supported on native toolchains.
+ if (!TC.isCrossCompiling()) {
+ addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
+ }
+}
+
+void tools::AddTargetFeature(const ArgList &Args,
+ std::vector<StringRef> &Features,
+ OptSpecifier OnOpt, OptSpecifier OffOpt,
+ StringRef FeatureName) {
+ if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) {
+ if (A->getOption().matches(OnOpt))
+ Features.push_back(Args.MakeArgString("+" + FeatureName));
+ else
+ Features.push_back(Args.MakeArgString("-" + FeatureName));
+ }
+}
+
+/// Get the (LLVM) name of the R600 gpu we are targeting.
+static std::string getR600TargetGPU(const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ const char *GPUName = A->getValue();
+ return llvm::StringSwitch<const char *>(GPUName)
+ .Cases("rv630", "rv635", "r600")
+ .Cases("rv610", "rv620", "rs780", "rs880")
+ .Case("rv740", "rv770")
+ .Case("palm", "cedar")
+ .Cases("sumo", "sumo2", "sumo")
+ .Case("hemlock", "cypress")
+ .Case("aruba", "cayman")
+ .Default(GPUName);
+ }
+ return "";
+}
+
+static std::string getNios2TargetCPU(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mcpu_EQ);
+ if (!A)
+ A = Args.getLastArg(options::OPT_march_EQ);
+
+ if (!A)
+ return "";
+
+ const char *name = A->getValue();
+ return llvm::StringSwitch<const char *>(name)
+ .Case("r1", "nios2r1")
+ .Case("r2", "nios2r2")
+ .Default(name);
+}
+
+static std::string getLanaiTargetCPU(const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ return A->getValue();
+ }
+ return "";
+}
+
+/// Get the (LLVM) name of the WebAssembly cpu we are targeting.
+static StringRef getWebAssemblyTargetCPU(const ArgList &Args) {
+ // If we have -mcpu=, use that.
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ StringRef CPU = A->getValue();
+
+#ifdef __wasm__
+ // Handle "native" by examining the host. "native" isn't meaningful when
+ // cross compiling, so only support this when the host is also WebAssembly.
+ if (CPU == "native")
+ return llvm::sys::getHostCPUName();
+#endif
+
+ return CPU;
+ }
+
+ return "generic";
+}
+
+std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T,
+ bool FromAs) {
+ Arg *A;
+
+ switch (T.getArch()) {
+ default:
+ return "";
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ return aarch64::getAArch64TargetCPU(Args, A);
+
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb: {
+ StringRef MArch, MCPU;
+ arm::getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs);
+ return arm::getARMTargetCPU(MCPU, MArch, T);
+ }
+
+ case llvm::Triple::avr:
+ if (const Arg *A = Args.getLastArg(options::OPT_mmcu_EQ))
+ return A->getValue();
+ return "";
+
+ case llvm::Triple::nios2: {
+ return getNios2TargetCPU(Args);
+ }
+
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
+ StringRef CPUName;
+ StringRef ABIName;
+ mips::getMipsCPUAndABI(Args, T, CPUName, ABIName);
+ return CPUName;
+ }
+
+ case llvm::Triple::nvptx:
+ case llvm::Triple::nvptx64:
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ return A->getValue();
+ return "";
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le: {
+ std::string TargetCPUName = ppc::getPPCTargetCPU(Args);
+ // LLVM may default to generating code for the native CPU,
+ // but, like gcc, we default to a more generic option for
+ // each architecture. (except on Darwin)
+ if (TargetCPUName.empty() && !T.isOSDarwin()) {
+ if (T.getArch() == llvm::Triple::ppc64)
+ TargetCPUName = "ppc64";
+ else if (T.getArch() == llvm::Triple::ppc64le)
+ TargetCPUName = "ppc64le";
+ else
+ TargetCPUName = "ppc";
+ }
+ return TargetCPUName;
+ }
+
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9:
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ return A->getValue();
+ return "";
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return x86::getX86TargetCPU(Args, T);
+
+ case llvm::Triple::hexagon:
+ return "hexagon" +
+ toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
+
+ case llvm::Triple::lanai:
+ return getLanaiTargetCPU(Args);
+
+ case llvm::Triple::systemz:
+ return systemz::getSystemZTargetCPU(Args);
+
+ case llvm::Triple::r600:
+ case llvm::Triple::amdgcn:
+ return getR600TargetGPU(Args);
+
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ return getWebAssemblyTargetCPU(Args);
+ }
+}
+
+unsigned tools::getLTOParallelism(const ArgList &Args, const Driver &D) {
+ unsigned Parallelism = 0;
+ Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ);
+ if (LtoJobsArg &&
+ StringRef(LtoJobsArg->getValue()).getAsInteger(10, Parallelism))
+ D.Diag(diag::err_drv_invalid_int_value) << LtoJobsArg->getAsString(Args)
+ << LtoJobsArg->getValue();
+ return Parallelism;
+}
+
+// CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by
+// default.
+bool tools::isUseSeparateSections(const llvm::Triple &Triple) {
+ return Triple.getOS() == llvm::Triple::CloudABI ||
+ Triple.getArch() == llvm::Triple::wasm32 ||
+ Triple.getArch() == llvm::Triple::wasm64;
+}
+
+void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
+ ArgStringList &CmdArgs, bool IsThinLTO,
+ const Driver &D) {
+ // Tell the linker to load the plugin. This has to come before AddLinkerInputs
+ // as gold requires -plugin to come before any -plugin-opt that -Wl might
+ // forward.
+ CmdArgs.push_back("-plugin");
+ std::string Plugin =
+ ToolChain.getDriver().Dir + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold.so";
+ CmdArgs.push_back(Args.MakeArgString(Plugin));
+
+ // Try to pass driver level flags relevant to LTO code generation down to
+ // the plugin.
+
+ // Handle flags for selecting CPU variants.
+ std::string CPU = getCPUName(Args, ToolChain.getTriple());
+ if (!CPU.empty())
+ CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU));
+
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ StringRef OOpt;
+ if (A->getOption().matches(options::OPT_O4) ||
+ A->getOption().matches(options::OPT_Ofast))
+ OOpt = "3";
+ else if (A->getOption().matches(options::OPT_O))
+ OOpt = A->getValue();
+ else if (A->getOption().matches(options::OPT_O0))
+ OOpt = "0";
+ if (!OOpt.empty())
+ CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt));
+ }
+
+ if (IsThinLTO)
+ CmdArgs.push_back("-plugin-opt=thinlto");
+
+ if (unsigned Parallelism = getLTOParallelism(Args, D))
+ CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") +
+ llvm::to_string(Parallelism)));
+
+ // If an explicit debugger tuning argument appeared, pass it along.
+ if (Arg *A = Args.getLastArg(options::OPT_gTune_Group,
+ options::OPT_ggdbN_Group)) {
+ if (A->getOption().matches(options::OPT_glldb))
+ CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb");
+ else if (A->getOption().matches(options::OPT_gsce))
+ CmdArgs.push_back("-plugin-opt=-debugger-tune=sce");
+ else
+ CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb");
+ }
+
+ bool UseSeparateSections =
+ isUseSeparateSections(ToolChain.getEffectiveTriple());
+
+ if (Args.hasFlag(options::OPT_ffunction_sections,
+ options::OPT_fno_function_sections, UseSeparateSections)) {
+ CmdArgs.push_back("-plugin-opt=-function-sections");
+ }
+
+ if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
+ UseSeparateSections)) {
+ CmdArgs.push_back("-plugin-opt=-data-sections");
+ }
+
+ if (Arg *A = getLastProfileSampleUseArg(Args)) {
+ StringRef FName = A->getValue();
+ if (!llvm::sys::fs::exists(FName))
+ D.Diag(diag::err_drv_no_such_file) << FName;
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName));
+ }
+}
+
+void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ std::string CandidateRPath = TC.getArchSpecificLibPath();
+ if (TC.getVFS().exists(CandidateRPath)) {
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str()));
+ }
+}
+
+bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
+ const ArgList &Args, bool IsOffloadingHost,
+ bool GompNeedsRT) {
+ if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
+ options::OPT_fno_openmp, false))
+ return false;
+
+ switch (TC.getDriver().getOpenMPRuntime(Args)) {
+ case Driver::OMPRT_OMP:
+ CmdArgs.push_back("-lomp");
+ break;
+ case Driver::OMPRT_GOMP:
+ CmdArgs.push_back("-lgomp");
+
+ if (GompNeedsRT)
+ CmdArgs.push_back("-lrt");
+ break;
+ case Driver::OMPRT_IOMP5:
+ CmdArgs.push_back("-liomp5");
+ break;
+ case Driver::OMPRT_Unknown:
+ // Already diagnosed.
+ return false;
+ }
+
+ if (IsOffloadingHost)
+ CmdArgs.push_back("-lomptarget");
+
+ addArchSpecificRPath(TC, Args, CmdArgs);
+
+ return true;
+}
+
+static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs, StringRef Sanitizer,
+ bool IsShared, bool IsWhole) {
+ // Wrap any static runtimes that must be forced into executable in
+ // whole-archive.
+ if (IsWhole) CmdArgs.push_back("-whole-archive");
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared));
+ if (IsWhole) CmdArgs.push_back("-no-whole-archive");
+
+ if (IsShared) {
+ addArchSpecificRPath(TC, Args, CmdArgs);
+ }
+}
+
+// Tries to use a file with the list of dynamic symbols that need to be exported
+// from the runtime library. Returns true if the file was found.
+static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs,
+ StringRef Sanitizer) {
+ SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer));
+ if (llvm::sys::fs::exists(SanRT + ".syms")) {
+ CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms"));
+ return true;
+ }
+ return false;
+}
+
+void tools::linkSanitizerRuntimeDeps(const ToolChain &TC,
+ ArgStringList &CmdArgs) {
+ // Force linking against the system libraries sanitizers depends on
+ // (see PR15823 why this is necessary).
+ CmdArgs.push_back("--no-as-needed");
+ // There's no libpthread or librt on RTEMS.
+ if (TC.getTriple().getOS() != llvm::Triple::RTEMS) {
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-lrt");
+ }
+ CmdArgs.push_back("-lm");
+ // There's no libdl on FreeBSD or RTEMS.
+ if (TC.getTriple().getOS() != llvm::Triple::FreeBSD &&
+ TC.getTriple().getOS() != llvm::Triple::NetBSD &&
+ TC.getTriple().getOS() != llvm::Triple::RTEMS)
+ CmdArgs.push_back("-ldl");
+}
+
+static void
+collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
+ SmallVectorImpl<StringRef> &SharedRuntimes,
+ SmallVectorImpl<StringRef> &StaticRuntimes,
+ SmallVectorImpl<StringRef> &NonWholeStaticRuntimes,
+ SmallVectorImpl<StringRef> &HelperStaticRuntimes,
+ SmallVectorImpl<StringRef> &RequiredSymbols) {
+ const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
+ // Collect shared runtimes.
+ if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) {
+ SharedRuntimes.push_back("asan");
+ }
+ // The stats_client library is also statically linked into DSOs.
+ if (SanArgs.needsStatsRt())
+ StaticRuntimes.push_back("stats_client");
+
+ // Collect static runtimes.
+ if (Args.hasArg(options::OPT_shared) || TC.getTriple().isAndroid()) {
+ // Don't link static runtimes into DSOs or if compiling for Android.
+ return;
+ }
+ if (SanArgs.needsAsanRt()) {
+ if (SanArgs.needsSharedAsanRt()) {
+ HelperStaticRuntimes.push_back("asan-preinit");
+ } else {
+ StaticRuntimes.push_back("asan");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("asan_cxx");
+ }
+ }
+ if (SanArgs.needsDfsanRt())
+ StaticRuntimes.push_back("dfsan");
+ if (SanArgs.needsLsanRt())
+ StaticRuntimes.push_back("lsan");
+ if (SanArgs.needsMsanRt()) {
+ StaticRuntimes.push_back("msan");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("msan_cxx");
+ }
+ if (SanArgs.needsTsanRt()) {
+ StaticRuntimes.push_back("tsan");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("tsan_cxx");
+ }
+ if (SanArgs.needsUbsanRt()) {
+ StaticRuntimes.push_back("ubsan_standalone");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("ubsan_standalone_cxx");
+ }
+ if (SanArgs.needsSafeStackRt()) {
+ NonWholeStaticRuntimes.push_back("safestack");
+ RequiredSymbols.push_back("__safestack_init");
+ }
+ if (SanArgs.needsCfiRt())
+ StaticRuntimes.push_back("cfi");
+ if (SanArgs.needsCfiDiagRt()) {
+ StaticRuntimes.push_back("cfi_diag");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("ubsan_standalone_cxx");
+ }
+ if (SanArgs.needsStatsRt()) {
+ NonWholeStaticRuntimes.push_back("stats");
+ RequiredSymbols.push_back("__sanitizer_stats_register");
+ }
+ if (SanArgs.needsEsanRt())
+ StaticRuntimes.push_back("esan");
+}
+
+static void addLibFuzzerRuntime(const ToolChain &TC,
+ const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ StringRef ParentDir = llvm::sys::path::parent_path(TC.getDriver().InstalledDir);
+ SmallString<128> P(ParentDir);
+ llvm::sys::path::append(P, "lib", "libLLVMFuzzer.a");
+ CmdArgs.push_back(Args.MakeArgString(P));
+ TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+}
+
+
+// Should be called before we add system libraries (C++ ABI, libstdc++/libc++,
+// C runtime, etc). Returns true if sanitizer system deps need to be linked in.
+bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes,
+ NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols;
+ collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
+ NonWholeStaticRuntimes, HelperStaticRuntimes,
+ RequiredSymbols);
+ // Inject libfuzzer dependencies.
+ if (TC.getSanitizerArgs().needsFuzzer()
+ && !Args.hasArg(options::OPT_shared)) {
+ addLibFuzzerRuntime(TC, Args, CmdArgs);
+ }
+
+ for (auto RT : SharedRuntimes)
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false);
+ for (auto RT : HelperStaticRuntimes)
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
+ bool AddExportDynamic = false;
+ for (auto RT : StaticRuntimes) {
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
+ AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
+ }
+ for (auto RT : NonWholeStaticRuntimes) {
+ addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false);
+ AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
+ }
+ for (auto S : RequiredSymbols) {
+ CmdArgs.push_back("-u");
+ CmdArgs.push_back(Args.MakeArgString(S));
+ }
+ // If there is a static runtime with no dynamic list, force all the symbols
+ // to be dynamic to be sure we export sanitizer interface functions.
+ if (AddExportDynamic)
+ CmdArgs.push_back("-export-dynamic");
+
+ const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
+ if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic)
+ CmdArgs.push_back("-export-dynamic-symbol=__cfi_check");
+
+ return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty();
+}
+
+bool tools::areOptimizationsEnabled(const ArgList &Args) {
+ // Find the last -O arg and see if it is non-zero.
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ return !A->getOption().matches(options::OPT_O0);
+ // Defaults to -O0.
+ return false;
+}
+
+const char *tools::SplitDebugName(const ArgList &Args, const InputInfo &Input) {
+ Arg *FinalOutput = Args.getLastArg(options::OPT_o);
+ if (FinalOutput && Args.hasArg(options::OPT_c)) {
+ SmallString<128> T(FinalOutput->getValue());
+ llvm::sys::path::replace_extension(T, "dwo");
+ return Args.MakeArgString(T);
+ } else {
+ // Use the compilation dir.
+ SmallString<128> T(
+ Args.getLastArgValue(options::OPT_fdebug_compilation_dir));
+ SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput()));
+ llvm::sys::path::replace_extension(F, "dwo");
+ T += F;
+ return Args.MakeArgString(F);
+ }
+}
+
+void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T,
+ const JobAction &JA, const ArgList &Args,
+ const InputInfo &Output, const char *OutFile) {
+ ArgStringList ExtractArgs;
+ ExtractArgs.push_back("--extract-dwo");
+
+ ArgStringList StripArgs;
+ StripArgs.push_back("--strip-dwo");
+
+ // Grabbing the output of the earlier compile step.
+ StripArgs.push_back(Output.getFilename());
+ ExtractArgs.push_back(Output.getFilename());
+ ExtractArgs.push_back(OutFile);
+
+ const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy"));
+ InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename());
+
+ // First extract the dwo sections.
+ C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs, II));
+
+ // Then remove them from the original .o file.
+ C.addCommand(llvm::make_unique<Command>(JA, T, Exec, StripArgs, II));
+}
+
+// Claim options we don't want to warn if they are unused. We do this for
+// options that build systems might add but are unused when assembling or only
+// running the preprocessor for example.
+void tools::claimNoWarnArgs(const ArgList &Args) {
+ // Don't warn about unused -f(no-)?lto. This can happen when we're
+ // preprocessing, precompiling or assembling.
+ Args.ClaimAllArgs(options::OPT_flto_EQ);
+ Args.ClaimAllArgs(options::OPT_flto);
+ Args.ClaimAllArgs(options::OPT_fno_lto);
+}
+
+Arg *tools::getLastProfileUseArg(const ArgList &Args) {
+ auto *ProfileUseArg = Args.getLastArg(
+ options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ,
+ options::OPT_fprofile_use, options::OPT_fprofile_use_EQ,
+ options::OPT_fno_profile_instr_use);
+
+ if (ProfileUseArg &&
+ ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use))
+ ProfileUseArg = nullptr;
+
+ return ProfileUseArg;
+}
+
+Arg *tools::getLastProfileSampleUseArg(const ArgList &Args) {
+ auto *ProfileSampleUseArg = Args.getLastArg(
+ options::OPT_fprofile_sample_use, options::OPT_fprofile_sample_use_EQ,
+ options::OPT_fauto_profile, options::OPT_fauto_profile_EQ,
+ options::OPT_fno_profile_sample_use, options::OPT_fno_auto_profile);
+
+ if (ProfileSampleUseArg &&
+ (ProfileSampleUseArg->getOption().matches(
+ options::OPT_fno_profile_sample_use) ||
+ ProfileSampleUseArg->getOption().matches(options::OPT_fno_auto_profile)))
+ return nullptr;
+
+ return Args.getLastArg(options::OPT_fprofile_sample_use_EQ,
+ options::OPT_fauto_profile_EQ);
+}
+
+/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then,
+/// smooshes them together with platform defaults, to decide whether
+/// this compile should be using PIC mode or not. Returns a tuple of
+/// (RelocationModel, PICLevel, IsPIE).
+std::tuple<llvm::Reloc::Model, unsigned, bool>
+tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
+ const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple();
+ const llvm::Triple &Triple = ToolChain.getTriple();
+
+ bool PIE = ToolChain.isPIEDefault();
+ bool PIC = PIE || ToolChain.isPICDefault();
+ // The Darwin/MachO default to use PIC does not apply when using -static.
+ if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static))
+ PIE = PIC = false;
+ bool IsPICLevelTwo = PIC;
+
+ bool KernelOrKext =
+ Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
+
+ // Android-specific defaults for PIC/PIE
+ if (Triple.isAndroid()) {
+ switch (Triple.getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ PIC = true; // "-fpic"
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ PIC = true; // "-fPIC"
+ IsPICLevelTwo = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // OpenBSD-specific defaults for PIE
+ if (Triple.getOS() == llvm::Triple::OpenBSD) {
+ switch (ToolChain.getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ IsPICLevelTwo = false; // "-fpie"
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9:
+ IsPICLevelTwo = true; // "-fPIE"
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // The last argument relating to either PIC or PIE wins, and no
+ // other argument is used. If the last argument is any flavor of the
+ // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE
+ // option implicitly enables PIC at the same level.
+ Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie);
+ if (Triple.isOSWindows() && LastPICArg &&
+ LastPICArg ==
+ Args.getLastArg(options::OPT_fPIC, options::OPT_fpic,
+ options::OPT_fPIE, options::OPT_fpie)) {
+ ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
+ << LastPICArg->getSpelling() << Triple.str();
+ if (Triple.getArch() == llvm::Triple::x86_64)
+ return std::make_tuple(llvm::Reloc::PIC_, 2U, false);
+ return std::make_tuple(llvm::Reloc::Static, 0U, false);
+ }
+
+ // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness
+ // is forced, then neither PIC nor PIE flags will have no effect.
+ if (!ToolChain.isPICDefaultForced()) {
+ if (LastPICArg) {
+ Option O = LastPICArg->getOption();
+ if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) ||
+ O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) {
+ PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie);
+ PIC =
+ PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic);
+ IsPICLevelTwo =
+ O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC);
+ } else {
+ PIE = PIC = false;
+ if (EffectiveTriple.isPS4CPU()) {
+ Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ);
+ StringRef Model = ModelArg ? ModelArg->getValue() : "";
+ if (Model != "kernel") {
+ PIC = true;
+ ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic)
+ << LastPICArg->getSpelling();
+ }
+ }
+ }
+ }
+ }
+
+ // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the
+ // PIC level would've been set to level 1, force it back to level 2 PIC
+ // instead.
+ if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU()))
+ IsPICLevelTwo |= ToolChain.isPICDefault();
+
+ // This kernel flags are a trump-card: they will disable PIC/PIE
+ // generation, independent of the argument order.
+ if (KernelOrKext &&
+ ((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) &&
+ !EffectiveTriple.isWatchOS()))
+ PIC = PIE = false;
+
+ if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) {
+ // This is a very special mode. It trumps the other modes, almost no one
+ // uses it, and it isn't even valid on any OS but Darwin.
+ if (!Triple.isOSDarwin())
+ ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << Triple.str();
+
+ // FIXME: Warn when this flag trumps some other PIC or PIE flag.
+
+ // Only a forced PIC mode can cause the actual compile to have PIC defines
+ // etc., no flags are sufficient. This behavior was selected to closely
+ // match that of llvm-gcc and Apple GCC before that.
+ PIC = ToolChain.isPICDefault() && ToolChain.isPICDefaultForced();
+
+ return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2U : 0U, false);
+ }
+
+ bool EmbeddedPISupported;
+ switch (Triple.getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ EmbeddedPISupported = true;
+ break;
+ default:
+ EmbeddedPISupported = false;
+ break;
+ }
+
+ bool ROPI = false, RWPI = false;
+ Arg* LastROPIArg = Args.getLastArg(options::OPT_fropi, options::OPT_fno_ropi);
+ if (LastROPIArg && LastROPIArg->getOption().matches(options::OPT_fropi)) {
+ if (!EmbeddedPISupported)
+ ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
+ << LastROPIArg->getSpelling() << Triple.str();
+ ROPI = true;
+ }
+ Arg *LastRWPIArg = Args.getLastArg(options::OPT_frwpi, options::OPT_fno_rwpi);
+ if (LastRWPIArg && LastRWPIArg->getOption().matches(options::OPT_frwpi)) {
+ if (!EmbeddedPISupported)
+ ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
+ << LastRWPIArg->getSpelling() << Triple.str();
+ RWPI = true;
+ }
+
+ // ROPI and RWPI are not comaptible with PIC or PIE.
+ if ((ROPI || RWPI) && (PIC || PIE))
+ ToolChain.getDriver().Diag(diag::err_drv_ropi_rwpi_incompatible_with_pic);
+
+ // When targettng MIPS64 with N64, the default is PIC, unless -mno-abicalls is
+ // used.
+ if ((Triple.getArch() == llvm::Triple::mips64 ||
+ Triple.getArch() == llvm::Triple::mips64el) &&
+ Args.hasArg(options::OPT_mno_abicalls))
+ return std::make_tuple(llvm::Reloc::Static, 0U, false);
+
+ if (PIC)
+ return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2U : 1U, PIE);
+
+ llvm::Reloc::Model RelocM = llvm::Reloc::Static;
+ if (ROPI && RWPI)
+ RelocM = llvm::Reloc::ROPI_RWPI;
+ else if (ROPI)
+ RelocM = llvm::Reloc::ROPI;
+ else if (RWPI)
+ RelocM = llvm::Reloc::RWPI;
+
+ return std::make_tuple(RelocM, 0U, false);
+}
+
+void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ llvm::Reloc::Model RelocationModel;
+ unsigned PICLevel;
+ bool IsPIE;
+ std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(ToolChain, Args);
+
+ if (RelocationModel != llvm::Reloc::Static)
+ CmdArgs.push_back("-KPIC");
+}
+
+/// \brief Determine whether Objective-C automated reference counting is
+/// enabled.
+bool tools::isObjCAutoRefCount(const ArgList &Args) {
+ return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false);
+}
+
+static void AddLibgcc(const llvm::Triple &Triple, const Driver &D,
+ ArgStringList &CmdArgs, const ArgList &Args) {
+ bool isAndroid = Triple.isAndroid();
+ bool isCygMing = Triple.isOSCygMing();
+ bool IsIAMCU = Triple.isOSIAMCU();
+ bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
+ Args.hasArg(options::OPT_static);
+ if (!D.CCCIsCXX())
+ CmdArgs.push_back("-lgcc");
+
+ if (StaticLibgcc || isAndroid) {
+ if (D.CCCIsCXX())
+ CmdArgs.push_back("-lgcc");
+ } else {
+ if (!D.CCCIsCXX() && !isCygMing)
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ if (!D.CCCIsCXX() && !isCygMing)
+ CmdArgs.push_back("--no-as-needed");
+ }
+
+ if (StaticLibgcc && !isAndroid && !IsIAMCU)
+ CmdArgs.push_back("-lgcc_eh");
+ else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX())
+ CmdArgs.push_back("-lgcc");
+
+ // According to Android ABI, we have to link with libdl if we are
+ // linking with non-static libgcc.
+ //
+ // NOTE: This fixes a link error on Android MIPS as well. The non-static
+ // libgcc for MIPS relies on _Unwind_Find_FDE and dl_iterate_phdr from libdl.
+ if (isAndroid && !StaticLibgcc)
+ CmdArgs.push_back("-ldl");
+}
+
+void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D,
+ ArgStringList &CmdArgs, const ArgList &Args) {
+ // Make use of compiler-rt if --rtlib option is used
+ ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args);
+
+ switch (RLT) {
+ case ToolChain::RLT_CompilerRT:
+ switch (TC.getTriple().getOS()) {
+ default:
+ llvm_unreachable("unsupported OS");
+ case llvm::Triple::Win32:
+ case llvm::Triple::Linux:
+ case llvm::Triple::Fuchsia:
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins"));
+ break;
+ }
+ break;
+ case ToolChain::RLT_Libgcc:
+ // Make sure libgcc is not used under MSVC environment by default
+ if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
+ // Issue error diagnostic if libgcc is explicitly specified
+ // through command line as --rtlib option argument.
+ if (Args.hasArg(options::OPT_rtlib_EQ)) {
+ TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform)
+ << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC";
+ }
+ } else
+ AddLibgcc(TC.getTriple(), D, CmdArgs, Args);
+ break;
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.h
new file mode 100644
index 0000000..fdeb666
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CommonArgs.h
@@ -0,0 +1,98 @@
+//===--- CommonArgs.h - Args handling for multiple toolchains ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
+
+#include "InputInfo.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+#include "llvm/Support/CodeGen.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+void addPathIfExists(const Driver &D, const Twine &Path,
+ ToolChain::path_list &Paths);
+
+void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, const JobAction &JA);
+
+void claimNoWarnArgs(const llvm::opt::ArgList &Args);
+
+bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs);
+
+void linkSanitizerRuntimeDeps(const ToolChain &TC,
+ llvm::opt::ArgStringList &CmdArgs);
+
+void AddRunTimeLibs(const ToolChain &TC, const Driver &D,
+ llvm::opt::ArgStringList &CmdArgs,
+ const llvm::opt::ArgList &Args);
+
+const char *SplitDebugName(const llvm::opt::ArgList &Args,
+ const InputInfo &Input);
+
+void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T,
+ const JobAction &JA, const llvm::opt::ArgList &Args,
+ const InputInfo &Output, const char *OutFile);
+
+void AddGoldPlugin(const ToolChain &ToolChain, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, bool IsThinLTO,
+ const Driver &D);
+
+std::tuple<llvm::Reloc::Model, unsigned, bool>
+ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args);
+
+void AddAssemblerKPIC(const ToolChain &ToolChain,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs);
+
+void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs);
+/// Returns true, if an OpenMP runtime has been added.
+bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
+ const llvm::opt::ArgList &Args,
+ bool IsOffloadingHost = false, bool GompNeedsRT = false);
+
+llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args);
+llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args);
+
+bool isObjCAutoRefCount(const llvm::opt::ArgList &Args);
+
+unsigned getLTOParallelism(const llvm::opt::ArgList &Args, const Driver &D);
+
+bool areOptimizationsEnabled(const llvm::opt::ArgList &Args);
+
+bool isUseSeparateSections(const llvm::Triple &Triple);
+
+void addDirectoryList(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, const char *ArgName,
+ const char *EnvVar);
+
+void AddTargetFeature(const llvm::opt::ArgList &Args,
+ std::vector<StringRef> &Features,
+ llvm::opt::OptSpecifier OnOpt,
+ llvm::opt::OptSpecifier OffOpt, StringRef FeatureName);
+
+std::string getCPUName(const llvm::opt::ArgList &Args, const llvm::Triple &T,
+ bool FromAs = false);
+
+void handleTargetFeaturesGroup(const llvm::opt::ArgList &Args,
+ std::vector<StringRef> &Features,
+ llvm::opt::OptSpecifier Group);
+
+} // end namespace tools
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Contiki.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Contiki.cpp
new file mode 100644
index 0000000..7f74bfc
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Contiki.cpp
@@ -0,0 +1,28 @@
+//===--- Contiki.cpp - Contiki ToolChain Implementations --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Contiki.h"
+#include "CommonArgs.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+Contiki::Contiki(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {}
+
+SanitizerMask Contiki::getSupportedSanitizers() const {
+ const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ if (IsX86)
+ Res |= SanitizerKind::SafeStack;
+ return Res;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Contiki.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Contiki.h
new file mode 100644
index 0000000..f6e1507
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Contiki.h
@@ -0,0 +1,38 @@
+//===--- Contiki.h - Contiki ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H
+
+#include "Gnu.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Contiki : public Generic_ELF {
+public:
+ Contiki(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ // No support for finding a C++ standard library yet.
+ std::string findLibCxxIncludePath() const override { return ""; }
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override {}
+
+ SanitizerMask getSupportedSanitizers() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.cpp
new file mode 100644
index 0000000..04b71c4
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.cpp
@@ -0,0 +1,315 @@
+//===--- CrossWindowsToolChain.cpp - Cross Windows Tool Chain -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CrossWindows.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+
+using llvm::opt::ArgList;
+
+void tools::CrossWindows::Assembler::ConstructJob(
+ Compilation &C, const JobAction &JA, const InputInfo &Output,
+ const InputInfoList &Inputs, const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ const auto &TC =
+ static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
+ ArgStringList CmdArgs;
+ const char *Exec;
+
+ switch (TC.getArch()) {
+ default:
+ llvm_unreachable("unsupported architecture");
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ break;
+ case llvm::Triple::x86:
+ CmdArgs.push_back("--32");
+ break;
+ case llvm::Triple::x86_64:
+ CmdArgs.push_back("--64");
+ break;
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &Input : Inputs)
+ CmdArgs.push_back(Input.getFilename());
+
+ const std::string Assembler = TC.GetProgramPath("as");
+ Exec = Args.MakeArgString(Assembler);
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void tools::CrossWindows::Linker::ConstructJob(
+ Compilation &C, const JobAction &JA, const InputInfo &Output,
+ const InputInfoList &Inputs, const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &TC =
+ static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
+ const llvm::Triple &T = TC.getTriple();
+ const Driver &D = TC.getDriver();
+ SmallString<128> EntryPoint;
+ ArgStringList CmdArgs;
+ const char *Exec;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_w);
+ // Other warning options are already handled somewhere else.
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back("-pie");
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("--strip-all");
+
+ CmdArgs.push_back("-m");
+ switch (TC.getArch()) {
+ default:
+ llvm_unreachable("unsupported architecture");
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // FIXME: this is incorrect for WinCE
+ CmdArgs.push_back("thumb2pe");
+ break;
+ case llvm::Triple::x86:
+ CmdArgs.push_back("i386pe");
+ EntryPoint.append("_");
+ break;
+ case llvm::Triple::x86_64:
+ CmdArgs.push_back("i386pep");
+ break;
+ }
+
+ if (Args.hasArg(options::OPT_shared)) {
+ switch (T.getArch()) {
+ default:
+ llvm_unreachable("unsupported architecture");
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ case llvm::Triple::x86_64:
+ EntryPoint.append("_DllMainCRTStartup");
+ break;
+ case llvm::Triple::x86:
+ EntryPoint.append("_DllMainCRTStartup@12");
+ break;
+ }
+
+ CmdArgs.push_back("-shared");
+ CmdArgs.push_back("-Bdynamic");
+
+ CmdArgs.push_back("--enable-auto-image-base");
+
+ CmdArgs.push_back("--entry");
+ CmdArgs.push_back(Args.MakeArgString(EntryPoint));
+ } else {
+ EntryPoint.append("mainCRTStartup");
+
+ CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
+ : "-Bdynamic");
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ CmdArgs.push_back("--entry");
+ CmdArgs.push_back(Args.MakeArgString(EntryPoint));
+ }
+
+ // FIXME: handle subsystem
+ }
+
+ // NOTE: deal with multiple definitions on Windows (e.g. COMDAT)
+ CmdArgs.push_back("--allow-multiple-definition");
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) {
+ SmallString<261> ImpLib(Output.getFilename());
+ llvm::sys::path::replace_extension(ImpLib, ".lib");
+
+ CmdArgs.push_back("--out-implib");
+ CmdArgs.push_back(Args.MakeArgString(ImpLib));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ TC.AddFilePathLibArgs(Args, CmdArgs);
+ AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
+
+ if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) &&
+ !Args.hasArg(options::OPT_static);
+ if (StaticCXX)
+ CmdArgs.push_back("-Bstatic");
+ TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (StaticCXX)
+ CmdArgs.push_back("-Bdynamic");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib)) {
+ if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+ // TODO handle /MT[d] /MD[d]
+ CmdArgs.push_back("-lmsvcrt");
+ AddRunTimeLibs(TC, D, CmdArgs, Args);
+ }
+ }
+
+ if (TC.getSanitizerArgs().needsAsanRt()) {
+ // TODO handle /MT[d] /MD[d]
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
+ } else {
+ for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
+ // Make sure the dynamic runtime thunk is not optimized out at link time
+ // to ensure proper SEH handling.
+ CmdArgs.push_back(Args.MakeArgString("--undefined"));
+ CmdArgs.push_back(Args.MakeArgString(TC.getArch() == llvm::Triple::x86
+ ? "___asan_seh_interceptor"
+ : "__asan_seh_interceptor"));
+ }
+ }
+
+ Exec = Args.MakeArgString(TC.GetLinkerPath());
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D,
+ const llvm::Triple &T,
+ const llvm::opt::ArgList &Args)
+ : Generic_GCC(D, T, Args) {
+ 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
+ // /usr/lib/gcc.
+ getFilePaths().push_back(SysRoot + "/usr/lib");
+ getFilePaths().push_back(SysRoot + "/usr/lib/gcc");
+ }
+}
+
+bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
+ // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does
+ // not know how to emit them.
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool CrossWindowsToolChain::isPICDefault() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool CrossWindowsToolChain::isPIEDefault() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool CrossWindowsToolChain::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+void CrossWindowsToolChain::
+AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ const std::string &SysRoot = D.SysRoot;
+
+ auto AddSystemAfterIncludes = [&]() {
+ for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after))
+ addSystemInclude(DriverArgs, CC1Args, P);
+ };
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc)) {
+ AddSystemAfterIncludes();
+ return;
+ }
+
+ addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> ResourceDir(D.ResourceDir);
+ llvm::sys::path::append(ResourceDir, "include");
+ addSystemInclude(DriverArgs, CC1Args, ResourceDir);
+ }
+ AddSystemAfterIncludes();
+ addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
+}
+
+void CrossWindowsToolChain::
+AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const llvm::Triple &Triple = getTriple();
+ const std::string &SysRoot = getDriver().SysRoot;
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++/v1");
+ break;
+
+ case ToolChain::CST_Libstdcxx:
+ addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++");
+ addSystemInclude(DriverArgs, CC1Args,
+ SysRoot + "/usr/include/c++/" + Triple.str());
+ addSystemInclude(DriverArgs, CC1Args,
+ SysRoot + "/usr/include/c++/backwards");
+ }
+}
+
+void CrossWindowsToolChain::
+AddCXXStdlibLibArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ CC1Args.push_back("-lc++");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ CC1Args.push_back("-lstdc++");
+ CC1Args.push_back("-lmingw32");
+ CC1Args.push_back("-lmingwex");
+ CC1Args.push_back("-lgcc");
+ CC1Args.push_back("-lmoldname");
+ CC1Args.push_back("-lmingw32");
+ break;
+ }
+}
+
+clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const {
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::Address;
+ return Res;
+}
+
+Tool *CrossWindowsToolChain::buildLinker() const {
+ return new tools::CrossWindows::Linker(*this);
+}
+
+Tool *CrossWindowsToolChain::buildAssembler() const {
+ return new tools::CrossWindows::Assembler(*this);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.h
new file mode 100644
index 0000000..2f66446
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/CrossWindows.h
@@ -0,0 +1,88 @@
+//===--- CrossWindows.h - CrossWindows ToolChain Implementation -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CROSSWINDOWS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CROSSWINDOWS_H
+
+#include "Cuda.h"
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+namespace CrossWindows {
+class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+public:
+ Assembler(const ToolChain &TC) : Tool("CrossWindows::Assembler", "as", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC)
+ : Tool("CrossWindows::Linker", "ld", TC, RF_Full) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace CrossWindows
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC {
+public:
+ CrossWindowsToolChain(const Driver &D, const llvm::Triple &T,
+ const llvm::opt::ArgList &Args);
+
+ bool IsIntegratedAssemblerDefault() const override { return true; }
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+
+ unsigned int GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
+ return 0;
+ }
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ SanitizerMask getSupportedSanitizers() const override;
+
+protected:
+ Tool *buildLinker() const override;
+ Tool *buildAssembler() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CROSSWINDOWS_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.cpp
new file mode 100644
index 0000000..935a5a3
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.cpp
@@ -0,0 +1,513 @@
+//===--- Cuda.cpp - Cuda Tool and ToolChain Implementations -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Cuda.h"
+#include "InputInfo.h"
+#include "clang/Basic/Cuda.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+#include <system_error>
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+// Parses the contents of version.txt in an CUDA installation. It should
+// contain one line of the from e.g. "CUDA Version 7.5.2".
+static CudaVersion ParseCudaVersionFile(llvm::StringRef V) {
+ if (!V.startswith("CUDA Version "))
+ return CudaVersion::UNKNOWN;
+ V = V.substr(strlen("CUDA Version "));
+ int Major = -1, Minor = -1;
+ auto First = V.split('.');
+ auto Second = First.second.split('.');
+ if (First.first.getAsInteger(10, Major) ||
+ Second.first.getAsInteger(10, Minor))
+ return CudaVersion::UNKNOWN;
+
+ if (Major == 7 && Minor == 0) {
+ // This doesn't appear to ever happen -- version.txt doesn't exist in the
+ // CUDA 7 installs I've seen. But no harm in checking.
+ return CudaVersion::CUDA_70;
+ }
+ if (Major == 7 && Minor == 5)
+ return CudaVersion::CUDA_75;
+ if (Major == 8 && Minor == 0)
+ return CudaVersion::CUDA_80;
+ return CudaVersion::UNKNOWN;
+}
+
+CudaInstallationDetector::CudaInstallationDetector(
+ const Driver &D, const llvm::Triple &HostTriple,
+ const llvm::opt::ArgList &Args)
+ : D(D) {
+ SmallVector<std::string, 4> CudaPathCandidates;
+
+ // In decreasing order so we prefer newer versions to older versions.
+ std::initializer_list<const char *> Versions = {"8.0", "7.5", "7.0"};
+
+ if (Args.hasArg(clang::driver::options::OPT_cuda_path_EQ)) {
+ CudaPathCandidates.push_back(
+ Args.getLastArgValue(clang::driver::options::OPT_cuda_path_EQ));
+ } else if (HostTriple.isOSWindows()) {
+ for (const char *Ver : Versions)
+ CudaPathCandidates.push_back(
+ D.SysRoot + "/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v" +
+ Ver);
+ } else {
+ CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda");
+ for (const char *Ver : Versions)
+ CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-" + Ver);
+ }
+
+ for (const auto &CudaPath : CudaPathCandidates) {
+ if (CudaPath.empty() || !D.getVFS().exists(CudaPath))
+ continue;
+
+ InstallPath = CudaPath;
+ BinPath = CudaPath + "/bin";
+ IncludePath = InstallPath + "/include";
+ LibDevicePath = InstallPath + "/nvvm/libdevice";
+
+ auto &FS = D.getVFS();
+ if (!(FS.exists(IncludePath) && FS.exists(BinPath) &&
+ FS.exists(LibDevicePath)))
+ continue;
+
+ // On Linux, we have both lib and lib64 directories, and we need to choose
+ // based on our triple. On MacOS, we have only a lib directory.
+ //
+ // It's sufficient for our purposes to be flexible: If both lib and lib64
+ // exist, we choose whichever one matches our triple. Otherwise, if only
+ // lib exists, we use it.
+ if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64"))
+ LibPath = InstallPath + "/lib64";
+ else if (FS.exists(InstallPath + "/lib"))
+ LibPath = InstallPath + "/lib";
+ else
+ continue;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
+ FS.getBufferForFile(InstallPath + "/version.txt");
+ if (!VersionFile) {
+ // CUDA 7.0 doesn't have a version.txt, so guess that's our version if
+ // version.txt isn't present.
+ Version = CudaVersion::CUDA_70;
+ } else {
+ Version = ParseCudaVersionFile((*VersionFile)->getBuffer());
+ }
+
+ std::error_code EC;
+ for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef FilePath = LI->path();
+ StringRef FileName = llvm::sys::path::filename(FilePath);
+ // Process all bitcode filenames that look like libdevice.compute_XX.YY.bc
+ const StringRef LibDeviceName = "libdevice.";
+ if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc")))
+ continue;
+ StringRef GpuArch = FileName.slice(
+ LibDeviceName.size(), FileName.find('.', LibDeviceName.size()));
+ LibDeviceMap[GpuArch] = FilePath.str();
+ // Insert map entries for specifc devices with this compute
+ // capability. NVCC's choice of the libdevice library version is
+ // rather peculiar and depends on the CUDA version.
+ if (GpuArch == "compute_20") {
+ LibDeviceMap["sm_20"] = FilePath;
+ LibDeviceMap["sm_21"] = FilePath;
+ LibDeviceMap["sm_32"] = FilePath;
+ } else if (GpuArch == "compute_30") {
+ LibDeviceMap["sm_30"] = FilePath;
+ if (Version < CudaVersion::CUDA_80) {
+ LibDeviceMap["sm_50"] = FilePath;
+ LibDeviceMap["sm_52"] = FilePath;
+ LibDeviceMap["sm_53"] = FilePath;
+ }
+ LibDeviceMap["sm_60"] = FilePath;
+ LibDeviceMap["sm_61"] = FilePath;
+ LibDeviceMap["sm_62"] = FilePath;
+ } else if (GpuArch == "compute_35") {
+ LibDeviceMap["sm_35"] = FilePath;
+ LibDeviceMap["sm_37"] = FilePath;
+ } else if (GpuArch == "compute_50") {
+ if (Version >= CudaVersion::CUDA_80) {
+ LibDeviceMap["sm_50"] = FilePath;
+ LibDeviceMap["sm_52"] = FilePath;
+ LibDeviceMap["sm_53"] = FilePath;
+ }
+ }
+ }
+
+ IsValid = true;
+ break;
+ }
+}
+
+void CudaInstallationDetector::AddCudaIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ // Add cuda_wrappers/* to our system include path. This lets us wrap
+ // standard library headers.
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ llvm::sys::path::append(P, "cuda_wrappers");
+ CC1Args.push_back("-internal-isystem");
+ CC1Args.push_back(DriverArgs.MakeArgString(P));
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nocudainc))
+ return;
+
+ if (!isValid()) {
+ D.Diag(diag::err_drv_no_cuda_installation);
+ return;
+ }
+
+ CC1Args.push_back("-internal-isystem");
+ CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath()));
+ CC1Args.push_back("-include");
+ CC1Args.push_back("__clang_cuda_runtime_wrapper.h");
+}
+
+void CudaInstallationDetector::CheckCudaVersionSupportsArch(
+ CudaArch Arch) const {
+ if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN ||
+ ArchsWithVersionTooLowErrors.count(Arch) > 0)
+ return;
+
+ auto RequiredVersion = MinVersionForCudaArch(Arch);
+ if (Version < RequiredVersion) {
+ ArchsWithVersionTooLowErrors.insert(Arch);
+ D.Diag(diag::err_drv_cuda_version_too_low)
+ << InstallPath << CudaArchToString(Arch) << CudaVersionToString(Version)
+ << CudaVersionToString(RequiredVersion);
+ }
+}
+
+void CudaInstallationDetector::print(raw_ostream &OS) const {
+ if (isValid())
+ OS << "Found CUDA installation: " << InstallPath << ", version "
+ << CudaVersionToString(Version) << "\n";
+}
+
+void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &TC =
+ static_cast<const toolchains::CudaToolChain &>(getToolChain());
+ assert(TC.getTriple().isNVPTX() && "Wrong platform");
+
+ // Obtain architecture from the action.
+ CudaArch gpu_arch = StringToCudaArch(JA.getOffloadingArch());
+ assert(gpu_arch != CudaArch::UNKNOWN &&
+ "Device action expected to have an architecture.");
+
+ // Check that our installation's ptxas supports gpu_arch.
+ if (!Args.hasArg(options::OPT_no_cuda_version_check)) {
+ TC.CudaInstallation.CheckCudaVersionSupportsArch(gpu_arch);
+ }
+
+ ArgStringList CmdArgs;
+ CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32");
+ if (Args.hasFlag(options::OPT_cuda_noopt_device_debug,
+ options::OPT_no_cuda_noopt_device_debug, false)) {
+ // ptxas does not accept -g option if optimization is enabled, so
+ // we ignore the compiler's -O* options if we want debug info.
+ CmdArgs.push_back("-g");
+ CmdArgs.push_back("--dont-merge-basicblocks");
+ CmdArgs.push_back("--return-at-end");
+ } else if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ // Map the -O we received to -O{0,1,2,3}.
+ //
+ // TODO: Perhaps we should map host -O2 to ptxas -O3. -O3 is ptxas's
+ // default, so it may correspond more closely to the spirit of clang -O2.
+
+ // -O3 seems like the least-bad option when -Osomething is specified to
+ // clang but it isn't handled below.
+ StringRef OOpt = "3";
+ if (A->getOption().matches(options::OPT_O4) ||
+ A->getOption().matches(options::OPT_Ofast))
+ OOpt = "3";
+ else if (A->getOption().matches(options::OPT_O0))
+ OOpt = "0";
+ else if (A->getOption().matches(options::OPT_O)) {
+ // -Os, -Oz, and -O(anything else) map to -O2, for lack of better options.
+ OOpt = llvm::StringSwitch<const char *>(A->getValue())
+ .Case("1", "1")
+ .Case("2", "2")
+ .Case("3", "3")
+ .Case("s", "2")
+ .Case("z", "2")
+ .Default("2");
+ }
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
+ } else {
+ // If no -O was passed, pass -O0 to ptxas -- no opt flag should correspond
+ // to no optimizations, but ptxas's default is -O3.
+ CmdArgs.push_back("-O0");
+ }
+
+ CmdArgs.push_back("--gpu-name");
+ CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch)));
+ CmdArgs.push_back("--output-file");
+ CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
+ for (const auto& II : Inputs)
+ CmdArgs.push_back(Args.MakeArgString(II.getFilename()));
+
+ for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
+ CmdArgs.push_back(Args.MakeArgString(A));
+
+ const char *Exec;
+ if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ))
+ Exec = A->getValue();
+ else
+ Exec = Args.MakeArgString(TC.GetProgramPath("ptxas"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+// All inputs to this linker must be from CudaDeviceActions, as we need to look
+// at the Inputs' Actions in order to figure out which GPU architecture they
+// correspond to.
+void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &TC =
+ static_cast<const toolchains::CudaToolChain &>(getToolChain());
+ assert(TC.getTriple().isNVPTX() && "Wrong platform");
+
+ ArgStringList CmdArgs;
+ CmdArgs.push_back("--cuda");
+ CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-64" : "-32");
+ CmdArgs.push_back(Args.MakeArgString("--create"));
+ CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
+
+ for (const auto& II : Inputs) {
+ auto *A = II.getAction();
+ assert(A->getInputs().size() == 1 &&
+ "Device offload action is expected to have a single input");
+ const char *gpu_arch_str = A->getOffloadingArch();
+ assert(gpu_arch_str &&
+ "Device action expected to have associated a GPU architecture!");
+ CudaArch gpu_arch = StringToCudaArch(gpu_arch_str);
+
+ // We need to pass an Arch of the form "sm_XX" for cubin files and
+ // "compute_XX" for ptx.
+ const char *Arch =
+ (II.getType() == types::TY_PP_Asm)
+ ? CudaVirtualArchToString(VirtualArchForCudaArch(gpu_arch))
+ : gpu_arch_str;
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") +
+ Arch + ",file=" + II.getFilename()));
+ }
+
+ for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary))
+ CmdArgs.push_back(Args.MakeArgString(A));
+
+ const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary,
+/// which isn't properly a linker but nonetheless performs the step of stitching
+/// together object files from the assembler into a single blob.
+
+CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ToolChain &HostTC, const ArgList &Args)
+ : ToolChain(D, Triple, Args), HostTC(HostTC),
+ CudaInstallation(D, HostTC.getTriple(), Args) {
+ if (CudaInstallation.isValid())
+ getProgramPaths().push_back(CudaInstallation.getBinPath());
+}
+
+void CudaToolChain::addClangTargetOptions(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadingKind) const {
+ HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
+
+ StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
+ assert(!GpuArch.empty() && "Must have an explicit GPU arch.");
+ assert((DeviceOffloadingKind == Action::OFK_OpenMP ||
+ DeviceOffloadingKind == Action::OFK_Cuda) &&
+ "Only OpenMP or CUDA offloading kinds are supported for NVIDIA GPUs.");
+
+ if (DeviceOffloadingKind == Action::OFK_Cuda) {
+ CC1Args.push_back("-fcuda-is-device");
+
+ if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero,
+ options::OPT_fno_cuda_flush_denormals_to_zero, false))
+ CC1Args.push_back("-fcuda-flush-denormals-to-zero");
+
+ if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
+ options::OPT_fno_cuda_approx_transcendentals, false))
+ CC1Args.push_back("-fcuda-approx-transcendentals");
+
+ if (DriverArgs.hasArg(options::OPT_nocudalib))
+ return;
+ }
+
+ std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch);
+
+ if (LibDeviceFile.empty()) {
+ getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch;
+ return;
+ }
+
+ CC1Args.push_back("-mlink-cuda-bitcode");
+ CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile));
+
+ // Libdevice in CUDA-7.0 requires PTX version that's more recent
+ // than LLVM defaults to. Use PTX4.2 which is the PTX version that
+ // came with CUDA-7.0.
+ CC1Args.push_back("-target-feature");
+ CC1Args.push_back("+ptx42");
+}
+
+void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ // Check our CUDA version if we're going to include the CUDA headers.
+ if (!DriverArgs.hasArg(options::OPT_nocudainc) &&
+ !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) {
+ StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
+ assert(!Arch.empty() && "Must have an explicit GPU arch.");
+ CudaInstallation.CheckCudaVersionSupportsArch(StringToCudaArch(Arch));
+ }
+ CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+}
+
+llvm::opt::DerivedArgList *
+CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
+ StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const {
+ DerivedArgList *DAL =
+ HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
+ if (!DAL)
+ DAL = new DerivedArgList(Args.getBaseArgs());
+
+ const OptTable &Opts = getDriver().getOpts();
+
+ // For OpenMP device offloading, append derived arguments. Make sure
+ // flags are not duplicated.
+ // TODO: Append the compute capability.
+ if (DeviceOffloadKind == Action::OFK_OpenMP) {
+ for (Arg *A : Args){
+ bool IsDuplicate = false;
+ for (Arg *DALArg : *DAL){
+ if (A == DALArg) {
+ IsDuplicate = true;
+ break;
+ }
+ }
+ if (!IsDuplicate)
+ DAL->append(A);
+ }
+ return DAL;
+ }
+
+ for (Arg *A : Args) {
+ if (A->getOption().matches(options::OPT_Xarch__)) {
+ // Skip this argument unless the architecture matches BoundArch
+ if (BoundArch.empty() || A->getValue(0) != BoundArch)
+ continue;
+
+ unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
+ unsigned Prev = Index;
+ std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index));
+
+ // If the argument parsing failed or more than one argument was
+ // consumed, the -Xarch_ argument's parameter tried to consume
+ // extra arguments. Emit an error and ignore.
+ //
+ // We also want to disallow any options which would alter the
+ // driver behavior; that isn't going to work in our model. We
+ // use isDriverOption() as an approximation, although things
+ // like -O4 are going to slip through.
+ if (!XarchArg || Index > Prev + 1) {
+ getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args)
+ << A->getAsString(Args);
+ continue;
+ } else if (XarchArg->getOption().hasFlag(options::DriverOption)) {
+ getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver)
+ << A->getAsString(Args);
+ continue;
+ }
+ XarchArg->setBaseArg(A);
+ A = XarchArg.release();
+ DAL->AddSynthesizedArg(A);
+ }
+ DAL->append(A);
+ }
+
+ if (!BoundArch.empty()) {
+ DAL->eraseArg(options::OPT_march_EQ);
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch);
+ }
+ return DAL;
+}
+
+Tool *CudaToolChain::buildAssembler() const {
+ return new tools::NVPTX::Assembler(*this);
+}
+
+Tool *CudaToolChain::buildLinker() const {
+ return new tools::NVPTX::Linker(*this);
+}
+
+void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
+ HostTC.addClangWarningOptions(CC1Args);
+}
+
+ToolChain::CXXStdlibType
+CudaToolChain::GetCXXStdlibType(const ArgList &Args) const {
+ return HostTC.GetCXXStdlibType(Args);
+}
+
+void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
+}
+
+void CudaToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
+ ArgStringList &CC1Args) const {
+ HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
+}
+
+void CudaToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
+ ArgStringList &CC1Args) const {
+ HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
+}
+
+SanitizerMask CudaToolChain::getSupportedSanitizers() const {
+ // The CudaToolChain only supports sanitizers in the sense that it allows
+ // sanitizer arguments on the command line if they are supported by the host
+ // toolchain. The CudaToolChain will actually ignore any command line
+ // arguments for any of these "supported" sanitizers. That means that no
+ // sanitization of device code is actually supported at this time.
+ //
+ // This behavior is necessary because the host and device toolchains
+ // invocations often share the command line, so the device toolchain must
+ // tolerate flags meant only for the host toolchain.
+ return HostTC.getSupportedSanitizers();
+}
+
+VersionTuple CudaToolChain::computeMSVCVersion(const Driver *D,
+ const ArgList &Args) const {
+ return HostTC.computeMSVCVersion(D, Args);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.h
new file mode 100644
index 0000000..e66fc23
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Cuda.h
@@ -0,0 +1,178 @@
+//===--- Cuda.h - Cuda ToolChain Implementations ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CUDA_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CUDA_H
+
+#include "clang/Basic/Cuda.h"
+#include "clang/Basic/VersionTuple.h"
+#include "clang/Driver/Action.h"
+#include "clang/Driver/Multilib.h"
+#include "clang/Driver/ToolChain.h"
+#include "clang/Driver/Tool.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/Compiler.h"
+#include <set>
+#include <vector>
+
+namespace clang {
+namespace driver {
+
+/// A class to find a viable CUDA installation
+class CudaInstallationDetector {
+private:
+ const Driver &D;
+ bool IsValid = false;
+ CudaVersion Version = CudaVersion::UNKNOWN;
+ std::string InstallPath;
+ std::string BinPath;
+ std::string LibPath;
+ std::string LibDevicePath;
+ std::string IncludePath;
+ llvm::StringMap<std::string> LibDeviceMap;
+
+ // CUDA architectures for which we have raised an error in
+ // CheckCudaVersionSupportsArch.
+ mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors;
+
+public:
+ CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple,
+ const llvm::opt::ArgList &Args);
+
+ void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+
+ /// \brief Emit an error if Version does not support the given Arch.
+ ///
+ /// If either Version or Arch is unknown, does not emit an error. Emits at
+ /// most one error per Arch.
+ void CheckCudaVersionSupportsArch(CudaArch Arch) const;
+
+ /// \brief Check whether we detected a valid Cuda install.
+ bool isValid() const { return IsValid; }
+ /// \brief Print information about the detected CUDA installation.
+ void print(raw_ostream &OS) const;
+
+ /// \brief Get the detected Cuda install's version.
+ CudaVersion version() const { return Version; }
+ /// \brief Get the detected Cuda installation path.
+ StringRef getInstallPath() const { return InstallPath; }
+ /// \brief Get the detected path to Cuda's bin directory.
+ StringRef getBinPath() const { return BinPath; }
+ /// \brief Get the detected Cuda Include path.
+ StringRef getIncludePath() const { return IncludePath; }
+ /// \brief Get the detected Cuda library path.
+ StringRef getLibPath() const { return LibPath; }
+ /// \brief Get the detected Cuda device library path.
+ StringRef getLibDevicePath() const { return LibDevicePath; }
+ /// \brief Get libdevice file for given architecture
+ std::string getLibDeviceFile(StringRef Gpu) const {
+ return LibDeviceMap.lookup(Gpu);
+ }
+};
+
+namespace tools {
+namespace NVPTX {
+
+// Run ptxas, the NVPTX assembler.
+class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+ public:
+ Assembler(const ToolChain &TC)
+ : Tool("NVPTX::Assembler", "ptxas", TC, RF_Full, llvm::sys::WEM_UTF8,
+ "--options-file") {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+// Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX
+// assembly into a single output file.
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+ public:
+ Linker(const ToolChain &TC)
+ : Tool("NVPTX::Linker", "fatbinary", TC, RF_Full, llvm::sys::WEM_UTF8,
+ "--options-file") {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+} // end namespace NVPTX
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain {
+public:
+ CudaToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ToolChain &HostTC, const llvm::opt::ArgList &Args);
+
+ virtual const llvm::Triple *getAuxTriple() const override {
+ return &HostTC.getTriple();
+ }
+
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
+ // Never try to use the integrated assembler with CUDA; always fork out to
+ // ptxas.
+ bool useIntegratedAs() const override { return false; }
+ bool isCrossCompiling() const override { return true; }
+ bool isPICDefault() const override { return false; }
+ bool isPIEDefault() const override { return false; }
+ bool isPICDefaultForced() const override { return false; }
+ bool SupportsProfiling() const override { return false; }
+ bool SupportsObjCGC() const override { return false; }
+
+ void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override;
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ SanitizerMask getSupportedSanitizers() const override;
+
+ VersionTuple
+ computeMSVCVersion(const Driver *D,
+ const llvm::opt::ArgList &Args) const override;
+
+ const ToolChain &HostTC;
+ CudaInstallationDetector CudaInstallation;
+
+protected:
+ Tool *buildAssembler() const override; // ptxas
+ Tool *buildLinker() const override; // fatbinary (ok, not really a linker)
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CUDA_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.cpp
new file mode 100644
index 0000000..32103a6
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -0,0 +1,2033 @@
+//===--- Darwin.cpp - Darwin Tool and ToolChain Implementations -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Darwin.h"
+#include "Arch/ARM.h"
+#include "CommonArgs.h"
+#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/TargetParser.h"
+#include <cstdlib> // ::getenv
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
+ // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for
+ // archs which Darwin doesn't use.
+
+ // The matching this routine does is fairly pointless, since it is neither the
+ // complete architecture list, nor a reasonable subset. The problem is that
+ // historically the driver driver accepts this and also ties its -march=
+ // handling to the architecture name, so we need to be careful before removing
+ // support for it.
+
+ // This code must be kept in sync with Clang's Darwin specific argument
+ // translation.
+
+ return llvm::StringSwitch<llvm::Triple::ArchType>(Str)
+ .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc)
+ .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc)
+ .Case("ppc64", llvm::Triple::ppc64)
+ .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86)
+ .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4",
+ llvm::Triple::x86)
+ .Cases("x86_64", "x86_64h", llvm::Triple::x86_64)
+ // This is derived from the driver driver.
+ .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
+ .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm)
+ .Cases("armv7s", "xscale", llvm::Triple::arm)
+ .Case("arm64", llvm::Triple::aarch64)
+ .Case("r600", llvm::Triple::r600)
+ .Case("amdgcn", llvm::Triple::amdgcn)
+ .Case("nvptx", llvm::Triple::nvptx)
+ .Case("nvptx64", llvm::Triple::nvptx64)
+ .Case("amdil", llvm::Triple::amdil)
+ .Case("spir", llvm::Triple::spir)
+ .Default(llvm::Triple::UnknownArch);
+}
+
+void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) {
+ const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str);
+ unsigned ArchKind = llvm::ARM::parseArch(Str);
+ T.setArch(Arch);
+
+ if (Str == "x86_64h")
+ T.setArchName(Str);
+ else if (ArchKind == llvm::ARM::AK_ARMV6M ||
+ ArchKind == llvm::ARM::AK_ARMV7M ||
+ ArchKind == llvm::ARM::AK_ARMV7EM) {
+ T.setOS(llvm::Triple::UnknownOS);
+ T.setObjectFormat(llvm::Triple::MachO);
+ }
+}
+
+void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ assert(Inputs.size() == 1 && "Unexpected number of inputs.");
+ const InputInfo &Input = Inputs[0];
+
+ // Determine the original source input.
+ const Action *SourceAction = &JA;
+ while (SourceAction->getKind() != Action::InputClass) {
+ assert(!SourceAction->getInputs().empty() && "unexpected root action!");
+ SourceAction = SourceAction->getInputs()[0];
+ }
+
+ // If -fno-integrated-as is used add -Q to the darwin assember driver to make
+ // sure it runs its system assembler not clang's integrated assembler.
+ // Applicable to darwin11+ and Xcode 4+. darwin<10 lacked integrated-as.
+ // FIXME: at run-time detect assembler capabilities or rely on version
+ // information forwarded by -target-assembler-version.
+ if (Args.hasArg(options::OPT_fno_integrated_as)) {
+ const llvm::Triple &T(getToolChain().getTriple());
+ if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7)))
+ CmdArgs.push_back("-Q");
+ }
+
+ // Forward -g, assuming we are dealing with an actual assembly file.
+ if (SourceAction->getType() == types::TY_Asm ||
+ SourceAction->getType() == types::TY_PP_Asm) {
+ if (Args.hasArg(options::OPT_gstabs))
+ CmdArgs.push_back("--gstabs");
+ else if (Args.hasArg(options::OPT_g_Group))
+ CmdArgs.push_back("-g");
+ }
+
+ // Derived from asm spec.
+ AddMachOArch(Args, CmdArgs);
+
+ // Use -force_cpusubtype_ALL on x86 by default.
+ if (getToolChain().getArch() == llvm::Triple::x86 ||
+ getToolChain().getArch() == llvm::Triple::x86_64 ||
+ Args.hasArg(options::OPT_force__cpusubtype__ALL))
+ CmdArgs.push_back("-force_cpusubtype_ALL");
+
+ if (getToolChain().getArch() != llvm::Triple::x86_64 &&
+ (((Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext)) &&
+ getMachOToolChain().isKernelStatic()) ||
+ Args.hasArg(options::OPT_static)))
+ CmdArgs.push_back("-static");
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ assert(Output.isFilename() && "Unexpected lipo output.");
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ assert(Input.isFilename() && "Invalid input.");
+ CmdArgs.push_back(Input.getFilename());
+
+ // asm_final spec is empty.
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void darwin::MachOTool::anchor() {}
+
+void darwin::MachOTool::AddMachOArch(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ StringRef ArchName = getMachOToolChain().getMachOArchName(Args);
+
+ // Derived from darwin_arch spec.
+ CmdArgs.push_back("-arch");
+ CmdArgs.push_back(Args.MakeArgString(ArchName));
+
+ // FIXME: Is this needed anymore?
+ if (ArchName == "arm")
+ CmdArgs.push_back("-force_cpusubtype_ALL");
+}
+
+bool darwin::Linker::NeedsTempPath(const InputInfoList &Inputs) const {
+ // We only need to generate a temp path for LTO if we aren't compiling object
+ // files. When compiling source files, we run 'dsymutil' after linking. We
+ // don't run 'dsymutil' when compiling object files.
+ for (const auto &Input : Inputs)
+ if (Input.getType() != types::TY_Object)
+ return true;
+
+ return false;
+}
+
+/// \brief Pass -no_deduplicate to ld64 under certain conditions:
+///
+/// - Either -O0 or -O1 is explicitly specified
+/// - No -O option is specified *and* this is a compile+link (implicit -O0)
+///
+/// Also do *not* add -no_deduplicate when no -O option is specified and this
+/// is just a link (we can't imply -O0)
+static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+ if (A->getOption().matches(options::OPT_O0))
+ return true;
+ if (A->getOption().matches(options::OPT_O))
+ return llvm::StringSwitch<bool>(A->getValue())
+ .Case("1", true)
+ .Default(false);
+ return false; // OPT_Ofast & OPT_O4
+ }
+
+ if (!IsLinkerOnlyAction) // Implicit -O0 for compile+linker only.
+ return true;
+ return false;
+}
+
+void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const InputInfoList &Inputs) const {
+ const Driver &D = getToolChain().getDriver();
+ const toolchains::MachO &MachOTC = getMachOToolChain();
+
+ unsigned Version[5] = {0, 0, 0, 0, 0};
+ if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
+ if (!Driver::GetReleaseVersion(A->getValue(), Version))
+ D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args);
+ }
+
+ // Newer linkers support -demangle. Pass it if supported and not disabled by
+ // the user.
+ if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+ CmdArgs.push_back("-demangle");
+
+ if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137)
+ CmdArgs.push_back("-export_dynamic");
+
+ // If we are using App Extension restrictions, pass a flag to the linker
+ // telling it that the compiled code has been audited.
+ if (Args.hasFlag(options::OPT_fapplication_extension,
+ options::OPT_fno_application_extension, false))
+ CmdArgs.push_back("-application_extension");
+
+ if (D.isUsingLTO()) {
+ // If we are using LTO, then automatically create a temporary file path for
+ // the linker to use, so that it's lifetime will extend past a possible
+ // dsymutil step.
+ if (Version[0] >= 116 && NeedsTempPath(Inputs)) {
+ const char *TmpPath = C.getArgs().MakeArgString(
+ D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object)));
+ C.addTempFile(TmpPath);
+ CmdArgs.push_back("-object_path_lto");
+ CmdArgs.push_back(TmpPath);
+ }
+ }
+
+ // Use -lto_library option to specify the libLTO.dylib path. Try to find
+ // it in clang installed libraries. ld64 will only look at this argument
+ // when it actually uses LTO, so libLTO.dylib only needs to exist at link
+ // time if ld64 decides that it needs to use LTO.
+ // Since this is passed unconditionally, ld64 will never look for libLTO.dylib
+ // next to it. That's ok since ld64 using a libLTO.dylib not matching the
+ // clang version won't work anyways.
+ if (Version[0] >= 133) {
+ // Search for libLTO in <InstalledDir>/../lib/libLTO.dylib
+ StringRef P = llvm::sys::path::parent_path(D.Dir);
+ SmallString<128> LibLTOPath(P);
+ llvm::sys::path::append(LibLTOPath, "lib");
+ llvm::sys::path::append(LibLTOPath, "libLTO.dylib");
+ CmdArgs.push_back("-lto_library");
+ CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath));
+ }
+
+ // ld64 version 262 and above run the deduplicate pass by default.
+ if (Version[0] >= 262 && shouldLinkerNotDedup(C.getJobs().empty(), Args))
+ CmdArgs.push_back("-no_deduplicate");
+
+ // Derived from the "link" spec.
+ Args.AddAllArgs(CmdArgs, options::OPT_static);
+ if (!Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-dynamic");
+ if (Args.hasArg(options::OPT_fgnu_runtime)) {
+ // FIXME: gcc replaces -lobjc in forward args with -lobjc-gnu
+ // here. How do we wish to handle such things?
+ }
+
+ if (!Args.hasArg(options::OPT_dynamiclib)) {
+ AddMachOArch(Args, CmdArgs);
+ // FIXME: Why do this only on this path?
+ Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL);
+
+ Args.AddLastArg(CmdArgs, options::OPT_bundle);
+ Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader);
+ Args.AddAllArgs(CmdArgs, options::OPT_client__name);
+
+ Arg *A;
+ if ((A = Args.getLastArg(options::OPT_compatibility__version)) ||
+ (A = Args.getLastArg(options::OPT_current__version)) ||
+ (A = Args.getLastArg(options::OPT_install__name)))
+ D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args)
+ << "-dynamiclib";
+
+ Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace);
+ Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs);
+ Args.AddLastArg(CmdArgs, options::OPT_private__bundle);
+ } else {
+ CmdArgs.push_back("-dylib");
+
+ Arg *A;
+ if ((A = Args.getLastArg(options::OPT_bundle)) ||
+ (A = Args.getLastArg(options::OPT_bundle__loader)) ||
+ (A = Args.getLastArg(options::OPT_client__name)) ||
+ (A = Args.getLastArg(options::OPT_force__flat__namespace)) ||
+ (A = Args.getLastArg(options::OPT_keep__private__externs)) ||
+ (A = Args.getLastArg(options::OPT_private__bundle)))
+ D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args)
+ << "-dynamiclib";
+
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version,
+ "-dylib_compatibility_version");
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version,
+ "-dylib_current_version");
+
+ AddMachOArch(Args, CmdArgs);
+
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name,
+ "-dylib_install_name");
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_all__load);
+ Args.AddAllArgs(CmdArgs, options::OPT_allowable__client);
+ Args.AddLastArg(CmdArgs, options::OPT_bind__at__load);
+ if (MachOTC.isTargetIOSBased())
+ Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal);
+ Args.AddLastArg(CmdArgs, options::OPT_dead__strip);
+ Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms);
+ Args.AddAllArgs(CmdArgs, options::OPT_dylib__file);
+ Args.AddLastArg(CmdArgs, options::OPT_dynamic);
+ Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list);
+ Args.AddLastArg(CmdArgs, options::OPT_flat__namespace);
+ Args.AddAllArgs(CmdArgs, options::OPT_force__load);
+ Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names);
+ Args.AddAllArgs(CmdArgs, options::OPT_image__base);
+ Args.AddAllArgs(CmdArgs, options::OPT_init);
+
+ // Add the deployment target.
+ MachOTC.addMinVersionArgs(Args, CmdArgs);
+
+ Args.AddLastArg(CmdArgs, options::OPT_nomultidefs);
+ Args.AddLastArg(CmdArgs, options::OPT_multi__module);
+ Args.AddLastArg(CmdArgs, options::OPT_single__module);
+ Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined);
+ Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused);
+
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fpie, options::OPT_fPIE,
+ options::OPT_fno_pie, options::OPT_fno_PIE)) {
+ if (A->getOption().matches(options::OPT_fpie) ||
+ A->getOption().matches(options::OPT_fPIE))
+ CmdArgs.push_back("-pie");
+ else
+ CmdArgs.push_back("-no_pie");
+ }
+
+ // for embed-bitcode, use -bitcode_bundle in linker command
+ if (C.getDriver().embedBitcodeEnabled()) {
+ // Check if the toolchain supports bitcode build flow.
+ if (MachOTC.SupportsEmbeddedBitcode()) {
+ CmdArgs.push_back("-bitcode_bundle");
+ if (C.getDriver().embedBitcodeMarkerOnly() && Version[0] >= 278) {
+ CmdArgs.push_back("-bitcode_process_mode");
+ CmdArgs.push_back("marker");
+ }
+ } else
+ D.Diag(diag::err_drv_bitcode_unsupported_on_toolchain);
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_prebind);
+ Args.AddLastArg(CmdArgs, options::OPT_noprebind);
+ Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding);
+ Args.AddLastArg(CmdArgs, options::OPT_prebind__all__twolevel__modules);
+ Args.AddLastArg(CmdArgs, options::OPT_read__only__relocs);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectcreate);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectorder);
+ Args.AddAllArgs(CmdArgs, options::OPT_seg1addr);
+ Args.AddAllArgs(CmdArgs, options::OPT_segprot);
+ Args.AddAllArgs(CmdArgs, options::OPT_segaddr);
+ Args.AddAllArgs(CmdArgs, options::OPT_segs__read__only__addr);
+ Args.AddAllArgs(CmdArgs, options::OPT_segs__read__write__addr);
+ Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table);
+ Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename);
+ Args.AddAllArgs(CmdArgs, options::OPT_sub__library);
+ Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella);
+
+ // Give --sysroot= preference, over the Apple specific behavior to also use
+ // --isysroot as the syslibroot.
+ StringRef sysroot = C.getSysRoot();
+ if (sysroot != "") {
+ CmdArgs.push_back("-syslibroot");
+ CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
+ } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ CmdArgs.push_back("-syslibroot");
+ CmdArgs.push_back(A->getValue());
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace);
+ Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints);
+ Args.AddAllArgs(CmdArgs, options::OPT_umbrella);
+ Args.AddAllArgs(CmdArgs, options::OPT_undefined);
+ Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list);
+ Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches);
+ Args.AddLastArg(CmdArgs, options::OPT_X_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_y);
+ Args.AddLastArg(CmdArgs, options::OPT_w);
+ Args.AddAllArgs(CmdArgs, options::OPT_pagezero__size);
+ Args.AddAllArgs(CmdArgs, options::OPT_segs__read__);
+ Args.AddLastArg(CmdArgs, options::OPT_seglinkedit);
+ Args.AddLastArg(CmdArgs, options::OPT_noseglinkedit);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectalign);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectobjectsymbols);
+ Args.AddAllArgs(CmdArgs, options::OPT_segcreate);
+ Args.AddLastArg(CmdArgs, options::OPT_whyload);
+ Args.AddLastArg(CmdArgs, options::OPT_whatsloaded);
+ Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name);
+ Args.AddLastArg(CmdArgs, options::OPT_dylinker);
+ Args.AddLastArg(CmdArgs, options::OPT_Mach);
+}
+
+/// \brief Determine whether we are linking the ObjC runtime.
+static bool isObjCRuntimeLinked(const ArgList &Args) {
+ if (isObjCAutoRefCount(Args)) {
+ Args.ClaimAllArgs(options::OPT_fobjc_link_runtime);
+ return true;
+ }
+ return Args.hasArg(options::OPT_fobjc_link_runtime);
+}
+
+void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ assert(Output.getType() == types::TY_Image && "Invalid linker output type.");
+
+ // If the number of arguments surpasses the system limits, we will encode the
+ // input files in a separate file, shortening the command line. To this end,
+ // build a list of input file names that can be passed via a file with the
+ // -filelist linker option.
+ llvm::opt::ArgStringList InputFileList;
+
+ // The logic here is derived from gcc's behavior; most of which
+ // comes from specs (starting with link_command). Consult gcc for
+ // more information.
+ ArgStringList CmdArgs;
+
+ /// Hack(tm) to ignore linking errors when we are doing ARC migration.
+ if (Args.hasArg(options::OPT_ccc_arcmt_check,
+ options::OPT_ccc_arcmt_migrate)) {
+ for (const auto &Arg : Args)
+ Arg->claim();
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("touch"));
+ CmdArgs.push_back(Output.getFilename());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, None));
+ return;
+ }
+
+ // I'm not sure why this particular decomposition exists in gcc, but
+ // we follow suite for ease of comparison.
+ AddLinkArgs(C, Args, CmdArgs, Inputs);
+
+ // For LTO, pass the name of the optimization record file.
+ if (Args.hasFlag(options::OPT_fsave_optimization_record,
+ options::OPT_fno_save_optimization_record, false)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-lto-pass-remarks-output");
+ CmdArgs.push_back("-mllvm");
+
+ SmallString<128> F;
+ F = Output.getFilename();
+ F += ".opt.yaml";
+ CmdArgs.push_back(Args.MakeArgString(F));
+
+ if (getLastProfileUseArg(Args)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-lto-pass-remarks-with-hotness");
+ }
+ }
+
+ // It seems that the 'e' option is completely ignored for dynamic executables
+ // (the default), and with static executables, the last one wins, as expected.
+ Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t,
+ options::OPT_Z_Flag, options::OPT_u_Group,
+ options::OPT_e, options::OPT_r});
+
+ // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading
+ // members of static archive libraries which implement Objective-C classes or
+ // categories.
+ if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX))
+ CmdArgs.push_back("-ObjC");
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
+ getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs);
+
+ // SafeStack requires its own runtime libraries
+ // These libraries should be linked first, to make sure the
+ // __safestack_init constructor executes before everything else
+ if (getToolChain().getSanitizerArgs().needsSafeStackRt()) {
+ getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs,
+ "libclang_rt.safestack_osx.a",
+ /*AlwaysLink=*/true);
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+ // Build the input file for -filelist (list of linker input files) in case we
+ // need it later
+ for (const auto &II : Inputs) {
+ if (!II.isFilename()) {
+ // This is a linker input argument.
+ // We cannot mix input arguments and file names in a -filelist input, thus
+ // we prematurely stop our list (remaining files shall be passed as
+ // arguments).
+ if (InputFileList.size() > 0)
+ break;
+
+ continue;
+ }
+
+ InputFileList.push_back(II.getFilename());
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
+ addOpenMPRuntime(CmdArgs, getToolChain(), Args);
+
+ if (isObjCRuntimeLinked(Args) &&
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ // We use arclite library for both ARC and subscripting support.
+ getMachOToolChain().AddLinkARCArgs(Args, CmdArgs);
+
+ CmdArgs.push_back("-framework");
+ CmdArgs.push_back("Foundation");
+ // Link libobj.
+ CmdArgs.push_back("-lobjc");
+ }
+
+ if (LinkingOutput) {
+ CmdArgs.push_back("-arch_multiple");
+ CmdArgs.push_back("-final_output");
+ CmdArgs.push_back(LinkingOutput);
+ }
+
+ if (Args.hasArg(options::OPT_fnested_functions))
+ CmdArgs.push_back("-allow_stack_execute");
+
+ getMachOToolChain().addProfileRTLibs(Args, CmdArgs);
+
+ if (unsigned Parallelism =
+ getLTOParallelism(Args, getToolChain().getDriver())) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-threads=") + llvm::to_string(Parallelism)));
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (getToolChain().getDriver().CCCIsCXX())
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+
+ // link_ssp spec is empty.
+
+ // Let the tool chain choose which runtime library to link.
+ getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs);
+
+ // No need to do anything for pthreads. Claim argument to avoid warning.
+ Args.ClaimAllArgs(options::OPT_pthread);
+ Args.ClaimAllArgs(options::OPT_pthreads);
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ // endfile_spec is empty.
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_F);
+
+ // -iframework should be forwarded as -F.
+ for (const Arg *A : Args.filtered(options::OPT_iframework))
+ CmdArgs.push_back(Args.MakeArgString(std::string("-F") + A->getValue()));
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (Arg *A = Args.getLastArg(options::OPT_fveclib)) {
+ if (A->getValue() == StringRef("Accelerate")) {
+ CmdArgs.push_back("-framework");
+ CmdArgs.push_back("Accelerate");
+ }
+ }
+ }
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ std::unique_ptr<Command> Cmd =
+ llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs);
+ Cmd->setInputFileList(std::move(InputFileList));
+ C.addCommand(std::move(Cmd));
+}
+
+void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ CmdArgs.push_back("-create");
+ assert(Output.isFilename() && "Unexpected lipo output.");
+
+ CmdArgs.push_back("-output");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs) {
+ assert(II.isFilename() && "Unexpected lipo input.");
+ CmdArgs.push_back(II.getFilename());
+ }
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
+ const InputInfo &Input = Inputs[0];
+ assert(Input.isFilename() && "Unexpected dsymutil input.");
+ CmdArgs.push_back(Input.getFilename());
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("dsymutil"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+ CmdArgs.push_back("--verify");
+ CmdArgs.push_back("--debug-info");
+ CmdArgs.push_back("--eh-frame");
+ CmdArgs.push_back("--quiet");
+
+ assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
+ const InputInfo &Input = Inputs[0];
+ assert(Input.isFilename() && "Unexpected verify input");
+
+ // Grabbing the output of the earlier dsymutil run.
+ CmdArgs.push_back(Input.getFilename());
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ // We expect 'as', 'ld', etc. to be adjacent to our install dir.
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+}
+
+/// Darwin - Darwin tool chain for i386 and x86_64.
+Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : MachO(D, Triple, Args), TargetInitialized(false),
+ CudaInstallation(D, Triple, Args) {}
+
+types::ID MachO::LookupTypeForExtension(StringRef Ext) const {
+ types::ID Ty = types::lookupTypeForExtension(Ext);
+
+ // Darwin always preprocesses assembly files (unless -x is used explicitly).
+ if (Ty == types::TY_PP_Asm)
+ return types::TY_Asm;
+
+ return Ty;
+}
+
+bool MachO::HasNativeLLVMSupport() const { return true; }
+
+ToolChain::CXXStdlibType Darwin::GetDefaultCXXStdlibType() const {
+ // Default to use libc++ on OS X 10.9+ and iOS 7+.
+ if ((isTargetMacOS() && !isMacosxVersionLT(10, 9)) ||
+ (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) ||
+ isTargetWatchOSBased())
+ return ToolChain::CST_Libcxx;
+
+ return ToolChain::CST_Libstdcxx;
+}
+
+/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
+ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const {
+ if (isTargetWatchOSBased())
+ return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion);
+ if (isTargetIOSBased())
+ return ObjCRuntime(ObjCRuntime::iOS, TargetVersion);
+ if (isNonFragile)
+ return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion);
+ return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion);
+}
+
+/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2.
+bool Darwin::hasBlocksRuntime() const {
+ if (isTargetWatchOSBased())
+ return true;
+ else if (isTargetIOSBased())
+ return !isIPhoneOSVersionLT(3, 2);
+ else {
+ assert(isTargetMacOS() && "unexpected darwin target");
+ return !isMacosxVersionLT(10, 6);
+ }
+}
+
+void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+}
+
+// This is just a MachO name translation routine and there's no
+// way to join this into ARMTargetParser without breaking all
+// other assumptions. Maybe MachO should consider standardising
+// their nomenclature.
+static const char *ArmMachOArchName(StringRef Arch) {
+ return llvm::StringSwitch<const char *>(Arch)
+ .Case("armv6k", "armv6")
+ .Case("armv6m", "armv6m")
+ .Case("armv5tej", "armv5")
+ .Case("xscale", "xscale")
+ .Case("armv4t", "armv4t")
+ .Case("armv7", "armv7")
+ .Cases("armv7a", "armv7-a", "armv7")
+ .Cases("armv7r", "armv7-r", "armv7")
+ .Cases("armv7em", "armv7e-m", "armv7em")
+ .Cases("armv7k", "armv7-k", "armv7k")
+ .Cases("armv7m", "armv7-m", "armv7m")
+ .Cases("armv7s", "armv7-s", "armv7s")
+ .Default(nullptr);
+}
+
+static const char *ArmMachOArchNameCPU(StringRef CPU) {
+ unsigned ArchKind = llvm::ARM::parseCPUArch(CPU);
+ if (ArchKind == llvm::ARM::AK_INVALID)
+ return nullptr;
+ StringRef Arch = llvm::ARM::getArchName(ArchKind);
+
+ // FIXME: Make sure this MachO triple mangling is really necessary.
+ // ARMv5* normalises to ARMv5.
+ if (Arch.startswith("armv5"))
+ Arch = Arch.substr(0, 5);
+ // ARMv6*, except ARMv6M, normalises to ARMv6.
+ else if (Arch.startswith("armv6") && !Arch.endswith("6m"))
+ Arch = Arch.substr(0, 5);
+ // ARMv7A normalises to ARMv7.
+ else if (Arch.endswith("v7a"))
+ Arch = Arch.substr(0, 5);
+ return Arch.data();
+}
+
+StringRef MachO::getMachOArchName(const ArgList &Args) const {
+ switch (getTriple().getArch()) {
+ default:
+ return getDefaultUniversalArchName();
+
+ case llvm::Triple::aarch64:
+ return "arm64";
+
+ case llvm::Triple::thumb:
+ case llvm::Triple::arm:
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ))
+ if (const char *Arch = ArmMachOArchName(A->getValue()))
+ return Arch;
+
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ if (const char *Arch = ArmMachOArchNameCPU(A->getValue()))
+ return Arch;
+
+ return "arm";
+ }
+}
+
+Darwin::~Darwin() {}
+
+MachO::~MachO() {}
+
+std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const {
+ llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
+
+ // If the target isn't initialized (e.g., an unknown Darwin platform, return
+ // the default triple).
+ if (!isTargetInitialized())
+ return Triple.getTriple();
+
+ SmallString<16> Str;
+ if (isTargetWatchOSBased())
+ Str += "watchos";
+ else if (isTargetTvOSBased())
+ Str += "tvos";
+ else if (isTargetIOSBased())
+ Str += "ios";
+ else
+ Str += "macosx";
+ Str += getTargetVersion().getAsString();
+ Triple.setOSName(Str);
+
+ return Triple.getTriple();
+}
+
+Tool *MachO::getTool(Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::LipoJobClass:
+ if (!Lipo)
+ Lipo.reset(new tools::darwin::Lipo(*this));
+ return Lipo.get();
+ case Action::DsymutilJobClass:
+ if (!Dsymutil)
+ Dsymutil.reset(new tools::darwin::Dsymutil(*this));
+ return Dsymutil.get();
+ case Action::VerifyDebugInfoJobClass:
+ if (!VerifyDebug)
+ VerifyDebug.reset(new tools::darwin::VerifyDebug(*this));
+ return VerifyDebug.get();
+ default:
+ return ToolChain::getTool(AC);
+ }
+}
+
+Tool *MachO::buildLinker() const { return new tools::darwin::Linker(*this); }
+
+Tool *MachO::buildAssembler() const {
+ return new tools::darwin::Assembler(*this);
+}
+
+DarwinClang::DarwinClang(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Darwin(D, Triple, Args) {}
+
+void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const {
+ // For modern targets, promote certain warnings to errors.
+ if (isTargetWatchOSBased() || getTriple().isArch64Bit()) {
+ // Always enable -Wdeprecated-objc-isa-usage and promote it
+ // to an error.
+ CC1Args.push_back("-Wdeprecated-objc-isa-usage");
+ CC1Args.push_back("-Werror=deprecated-objc-isa-usage");
+
+ // For iOS and watchOS, also error about implicit function declarations,
+ // as that can impact calling conventions.
+ if (!isTargetMacOS())
+ CC1Args.push_back("-Werror=implicit-function-declaration");
+ }
+}
+
+void DarwinClang::AddLinkARCArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Avoid linking compatibility stubs on i386 mac.
+ if (isTargetMacOS() && getArch() == llvm::Triple::x86)
+ return;
+
+ ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true);
+
+ if ((runtime.hasNativeARC() || !isObjCAutoRefCount(Args)) &&
+ runtime.hasSubscripting())
+ return;
+
+ CmdArgs.push_back("-force_load");
+ SmallString<128> P(getDriver().ClangExecutable);
+ llvm::sys::path::remove_filename(P); // 'clang'
+ llvm::sys::path::remove_filename(P); // 'bin'
+ llvm::sys::path::append(P, "lib", "arc", "libarclite_");
+ // Mash in the platform.
+ if (isTargetWatchOSSimulator())
+ P += "watchsimulator";
+ else if (isTargetWatchOS())
+ P += "watchos";
+ else if (isTargetTvOSSimulator())
+ P += "appletvsimulator";
+ else if (isTargetTvOS())
+ P += "appletvos";
+ else if (isTargetIOSSimulator())
+ P += "iphonesimulator";
+ else if (isTargetIPhoneOS())
+ P += "iphoneos";
+ else
+ P += "macosx";
+ P += ".a";
+
+ CmdArgs.push_back(Args.MakeArgString(P));
+}
+
+unsigned DarwinClang::GetDefaultDwarfVersion() const {
+ // Default to use DWARF 2 on OS X 10.10 / iOS 8 and lower.
+ if ((isTargetMacOS() && isMacosxVersionLT(10, 11)) ||
+ (isTargetIOSBased() && isIPhoneOSVersionLT(9)))
+ return 2;
+ return 4;
+}
+
+void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
+ StringRef DarwinLibName, bool AlwaysLink,
+ bool IsEmbedded, bool AddRPath) const {
+ SmallString<128> Dir(getDriver().ResourceDir);
+ llvm::sys::path::append(Dir, "lib", IsEmbedded ? "macho_embedded" : "darwin");
+
+ SmallString<128> P(Dir);
+ llvm::sys::path::append(P, DarwinLibName);
+
+ // For now, allow missing resource libraries to support developers who may
+ // not have compiler-rt checked out or integrated into their build (unless
+ // we explicitly force linking with this library).
+ if (AlwaysLink || getVFS().exists(P))
+ CmdArgs.push_back(Args.MakeArgString(P));
+
+ // Adding the rpaths might negatively interact when other rpaths are involved,
+ // so we should make sure we add the rpaths last, after all user-specified
+ // rpaths. This is currently true from this place, but we need to be
+ // careful if this function is ever called before user's rpaths are emitted.
+ if (AddRPath) {
+ assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library");
+
+ // Add @executable_path to rpath to support having the dylib copied with
+ // the executable.
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back("@executable_path");
+
+ // Add the path to the resource dir to rpath to support using the dylib
+ // from the default location without copying.
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back(Args.MakeArgString(Dir));
+ }
+}
+
+void MachO::AddFuzzerLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
+
+ // Go up one directory from Clang to find the libfuzzer archive file.
+ StringRef ParentDir = llvm::sys::path::parent_path(getDriver().InstalledDir);
+ SmallString<128> P(ParentDir);
+ llvm::sys::path::append(P, "lib", "libLLVMFuzzer.a");
+ CmdArgs.push_back(Args.MakeArgString(P));
+
+ // Libfuzzer is written in C++ and requires libcxx.
+ AddCXXStdlibLibArgs(Args, CmdArgs);
+}
+
+StringRef Darwin::getPlatformFamily() const {
+ switch (TargetPlatform) {
+ case DarwinPlatformKind::MacOS:
+ return "MacOSX";
+ case DarwinPlatformKind::IPhoneOS:
+ case DarwinPlatformKind::IPhoneOSSimulator:
+ return "iPhone";
+ case DarwinPlatformKind::TvOS:
+ case DarwinPlatformKind::TvOSSimulator:
+ return "AppleTV";
+ case DarwinPlatformKind::WatchOS:
+ case DarwinPlatformKind::WatchOSSimulator:
+ return "Watch";
+ }
+ llvm_unreachable("Unsupported platform");
+}
+
+StringRef Darwin::getSDKName(StringRef isysroot) {
+ // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk
+ llvm::sys::path::const_iterator SDKDir;
+ auto BeginSDK = llvm::sys::path::begin(isysroot);
+ auto EndSDK = llvm::sys::path::end(isysroot);
+ for (auto IT = BeginSDK; IT != EndSDK; ++IT) {
+ StringRef SDK = *IT;
+ if (SDK.endswith(".sdk"))
+ return SDK.slice(0, SDK.size() - 4);
+ }
+ return "";
+}
+
+StringRef Darwin::getOSLibraryNameSuffix() const {
+ switch(TargetPlatform) {
+ case DarwinPlatformKind::MacOS:
+ return "osx";
+ case DarwinPlatformKind::IPhoneOS:
+ return "ios";
+ case DarwinPlatformKind::IPhoneOSSimulator:
+ return "iossim";
+ case DarwinPlatformKind::TvOS:
+ return "tvos";
+ case DarwinPlatformKind::TvOSSimulator:
+ return "tvossim";
+ case DarwinPlatformKind::WatchOS:
+ return "watchos";
+ case DarwinPlatformKind::WatchOSSimulator:
+ return "watchossim";
+ }
+ llvm_unreachable("Unsupported platform");
+}
+
+void Darwin::addProfileRTLibs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ if (!needsProfileRT(Args)) return;
+
+ AddLinkRuntimeLib(Args, CmdArgs, (Twine("libclang_rt.profile_") +
+ getOSLibraryNameSuffix() + ".a").str(),
+ /*AlwaysLink*/ true);
+}
+
+void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs,
+ StringRef Sanitizer) const {
+ AddLinkRuntimeLib(
+ Args, CmdArgs,
+ (Twine("libclang_rt.") + Sanitizer + "_" +
+ getOSLibraryNameSuffix() + "_dynamic.dylib").str(),
+ /*AlwaysLink*/ true, /*IsEmbedded*/ false,
+ /*AddRPath*/ true);
+}
+
+ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType(
+ const ArgList &Args) const {
+ if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value != "compiler-rt")
+ getDriver().Diag(clang::diag::err_drv_unsupported_rtlib_for_platform)
+ << Value << "darwin";
+ }
+
+ return ToolChain::RLT_CompilerRT;
+}
+
+void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Call once to ensure diagnostic is printed if wrong value was specified
+ GetRuntimeLibType(Args);
+
+ // Darwin doesn't support real static executables, don't link any runtime
+ // libraries with -static.
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_fapple_kext) ||
+ Args.hasArg(options::OPT_mkernel))
+ return;
+
+ // Reject -static-libgcc for now, we can deal with this when and if someone
+ // cares. This is useful in situations where someone wants to statically link
+ // something like libstdc++, and needs its runtime support routines.
+ if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) {
+ getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args);
+ return;
+ }
+
+ const SanitizerArgs &Sanitize = getSanitizerArgs();
+ if (Sanitize.needsAsanRt())
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
+ if (Sanitize.needsLsanRt())
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan");
+ if (Sanitize.needsUbsanRt())
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan");
+ if (Sanitize.needsTsanRt())
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
+ if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib))
+ AddFuzzerLinkArgs(Args, CmdArgs);
+ if (Sanitize.needsStatsRt()) {
+ StringRef OS = isTargetMacOS() ? "osx" : "iossim";
+ AddLinkRuntimeLib(Args, CmdArgs,
+ (Twine("libclang_rt.stats_client_") + OS + ".a").str(),
+ /*AlwaysLink=*/true);
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "stats");
+ }
+ if (Sanitize.needsEsanRt())
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "esan");
+
+ // Otherwise link libSystem, then the dynamic runtime library, and finally any
+ // target specific static runtime library.
+ CmdArgs.push_back("-lSystem");
+
+ // Select the dynamic runtime library and the target specific static library.
+ if (isTargetWatchOSBased()) {
+ // We currently always need a static runtime library for watchOS.
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.watchos.a");
+ } else if (isTargetTvOSBased()) {
+ // We currently always need a static runtime library for tvOS.
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.tvos.a");
+ } else if (isTargetIOSBased()) {
+ // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1,
+ // it never went into the SDK.
+ // Linking against libgcc_s.1 isn't needed for iOS 5.0+
+ if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator() &&
+ getTriple().getArch() != llvm::Triple::aarch64)
+ CmdArgs.push_back("-lgcc_s.1");
+
+ // We currently always need a static runtime library for iOS.
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a");
+ } else {
+ assert(isTargetMacOS() && "unexpected non MacOS platform");
+ // The dynamic runtime library was merged with libSystem for 10.6 and
+ // beyond; only 10.4 and 10.5 need an additional runtime library.
+ if (isMacosxVersionLT(10, 5))
+ CmdArgs.push_back("-lgcc_s.10.4");
+ else if (isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-lgcc_s.10.5");
+
+ // Originally for OS X, we thought we would only need a static runtime
+ // library when targeting 10.4, to provide versions of the static functions
+ // which were omitted from 10.4.dylib. This led to the creation of the 10.4
+ // builtins library.
+ //
+ // Unfortunately, that turned out to not be true, because Darwin system
+ // headers can still use eprintf on i386, and it is not exported from
+ // libSystem. Therefore, we still must provide a runtime library just for
+ // the tiny tiny handful of projects that *might* use that symbol.
+ //
+ // Then over time, we figured out it was useful to add more things to the
+ // runtime so we created libclang_rt.osx.a to provide new functions when
+ // deploying to old OS builds, and for a long time we had both eprintf and
+ // osx builtin libraries. Which just seems excessive. So with PR 28855, we
+ // are removing the eprintf library and expecting eprintf to be provided by
+ // the OS X builtins library.
+ if (isMacosxVersionLT(10, 5))
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.10.4.a");
+ else
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.osx.a");
+ }
+}
+
+/// Returns the most appropriate macOS target version for the current process.
+///
+/// If the macOS SDK version is the same or earlier than the system version,
+/// then the SDK version is returned. Otherwise the system version is returned.
+static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) {
+ unsigned Major, Minor, Micro;
+ llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
+ if (!SystemTriple.isMacOSX())
+ return MacOSSDKVersion;
+ SystemTriple.getMacOSXVersion(Major, Minor, Micro);
+ VersionTuple SystemVersion(Major, Minor, Micro);
+ bool HadExtra;
+ if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro,
+ HadExtra))
+ return MacOSSDKVersion;
+ VersionTuple SDKVersion(Major, Minor, Micro);
+ if (SDKVersion > SystemVersion)
+ return SystemVersion.getAsString();
+ return MacOSSDKVersion;
+}
+
+void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
+ const OptTable &Opts = getDriver().getOpts();
+
+ // Support allowing the SDKROOT environment variable used by xcrun and other
+ // Xcode tools to define the default sysroot, by making it the default for
+ // isysroot.
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ // Warn if the path does not exist.
+ if (!getVFS().exists(A->getValue()))
+ getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue();
+ } else {
+ if (char *env = ::getenv("SDKROOT")) {
+ // We only use this value as the default if it is an absolute path,
+ // exists, and it is not the root path.
+ if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) &&
+ StringRef(env) != "/") {
+ Args.append(Args.MakeSeparateArg(
+ nullptr, Opts.getOption(options::OPT_isysroot), env));
+ }
+ }
+ }
+
+ Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
+ Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ,
+ options::OPT_mios_simulator_version_min_EQ);
+ Arg *TvOSVersion =
+ Args.getLastArg(options::OPT_mtvos_version_min_EQ,
+ options::OPT_mtvos_simulator_version_min_EQ);
+ Arg *WatchOSVersion =
+ Args.getLastArg(options::OPT_mwatchos_version_min_EQ,
+ options::OPT_mwatchos_simulator_version_min_EQ);
+
+ unsigned Major, Minor, Micro;
+ bool HadExtra;
+
+ // The iOS deployment target that is explicitly specified via a command line
+ // option or an environment variable.
+ std::string ExplicitIOSDeploymentTargetStr;
+
+ if (iOSVersion)
+ ExplicitIOSDeploymentTargetStr = iOSVersion->getAsString(Args);
+
+ // Add a macro to differentiate between m(iphone|tv|watch)os-version-min=X.Y and
+ // -m(iphone|tv|watch)simulator-version-min=X.Y.
+ if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ) ||
+ Args.hasArg(options::OPT_mtvos_simulator_version_min_EQ) ||
+ Args.hasArg(options::OPT_mwatchos_simulator_version_min_EQ))
+ Args.append(Args.MakeSeparateArg(nullptr, Opts.getOption(options::OPT_D),
+ " __APPLE_EMBEDDED_SIMULATOR__=1"));
+
+ if (OSXVersion && (iOSVersion || TvOSVersion || WatchOSVersion)) {
+ getDriver().Diag(diag::err_drv_argument_not_allowed_with)
+ << OSXVersion->getAsString(Args)
+ << (iOSVersion ? iOSVersion :
+ TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args);
+ iOSVersion = TvOSVersion = WatchOSVersion = nullptr;
+ } else if (iOSVersion && (TvOSVersion || WatchOSVersion)) {
+ getDriver().Diag(diag::err_drv_argument_not_allowed_with)
+ << iOSVersion->getAsString(Args)
+ << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args);
+ TvOSVersion = WatchOSVersion = nullptr;
+ } else if (TvOSVersion && WatchOSVersion) {
+ getDriver().Diag(diag::err_drv_argument_not_allowed_with)
+ << TvOSVersion->getAsString(Args)
+ << WatchOSVersion->getAsString(Args);
+ WatchOSVersion = nullptr;
+ } else if (!OSXVersion && !iOSVersion && !TvOSVersion && !WatchOSVersion) {
+ // If no deployment target was specified on the command line, check for
+ // environment defines.
+ std::string OSXTarget;
+ std::string iOSTarget;
+ std::string TvOSTarget;
+ std::string WatchOSTarget;
+
+ if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET"))
+ OSXTarget = env;
+ if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET"))
+ iOSTarget = env;
+ if (char *env = ::getenv("TVOS_DEPLOYMENT_TARGET"))
+ TvOSTarget = env;
+ if (char *env = ::getenv("WATCHOS_DEPLOYMENT_TARGET"))
+ WatchOSTarget = env;
+
+ if (!iOSTarget.empty())
+ ExplicitIOSDeploymentTargetStr =
+ std::string("IPHONEOS_DEPLOYMENT_TARGET=") + iOSTarget;
+
+ // If there is no command-line argument to specify the Target version and
+ // no environment variable defined, see if we can set the default based
+ // on -isysroot.
+ if (OSXTarget.empty() && iOSTarget.empty() && WatchOSTarget.empty() &&
+ TvOSTarget.empty() && Args.hasArg(options::OPT_isysroot)) {
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ StringRef isysroot = A->getValue();
+ StringRef SDK = getSDKName(isysroot);
+ if (SDK.size() > 0) {
+ // Slice the version number out.
+ // Version number is between the first and the last number.
+ size_t StartVer = SDK.find_first_of("0123456789");
+ size_t EndVer = SDK.find_last_of("0123456789");
+ if (StartVer != StringRef::npos && EndVer > StartVer) {
+ StringRef Version = SDK.slice(StartVer, EndVer + 1);
+ if (SDK.startswith("iPhoneOS") ||
+ SDK.startswith("iPhoneSimulator"))
+ iOSTarget = Version;
+ else if (SDK.startswith("MacOSX"))
+ OSXTarget = getSystemOrSDKMacOSVersion(Version);
+ else if (SDK.startswith("WatchOS") ||
+ SDK.startswith("WatchSimulator"))
+ WatchOSTarget = Version;
+ else if (SDK.startswith("AppleTVOS") ||
+ SDK.startswith("AppleTVSimulator"))
+ TvOSTarget = Version;
+ }
+ }
+ }
+ }
+
+ // If no OS targets have been specified, try to guess platform from -target
+ // or arch name and compute the version from the triple.
+ if (OSXTarget.empty() && iOSTarget.empty() && TvOSTarget.empty() &&
+ WatchOSTarget.empty()) {
+ llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS;
+
+ // Set the OSTy based on -target if -arch isn't present.
+ if (Args.hasArg(options::OPT_target) && !Args.hasArg(options::OPT_arch)) {
+ OSTy = getTriple().getOS();
+ } else {
+ StringRef MachOArchName = getMachOArchName(Args);
+ if (MachOArchName == "armv7" || MachOArchName == "armv7s" ||
+ MachOArchName == "arm64")
+ OSTy = llvm::Triple::IOS;
+ else if (MachOArchName == "armv7k")
+ OSTy = llvm::Triple::WatchOS;
+ else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
+ MachOArchName != "armv7em")
+ OSTy = llvm::Triple::MacOSX;
+ }
+
+
+ if (OSTy != llvm::Triple::UnknownOS) {
+ unsigned Major, Minor, Micro;
+ std::string *OSTarget;
+
+ switch (OSTy) {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ if (!getTriple().getMacOSXVersion(Major, Minor, Micro))
+ getDriver().Diag(diag::err_drv_invalid_darwin_version)
+ << getTriple().getOSName();
+ OSTarget = &OSXTarget;
+ break;
+ case llvm::Triple::IOS:
+ getTriple().getiOSVersion(Major, Minor, Micro);
+ OSTarget = &iOSTarget;
+ break;
+ case llvm::Triple::TvOS:
+ getTriple().getOSVersion(Major, Minor, Micro);
+ OSTarget = &TvOSTarget;
+ break;
+ case llvm::Triple::WatchOS:
+ getTriple().getWatchOSVersion(Major, Minor, Micro);
+ OSTarget = &WatchOSTarget;
+ break;
+ default:
+ llvm_unreachable("Unexpected OS type");
+ break;
+ }
+
+ llvm::raw_string_ostream(*OSTarget) << Major << '.' << Minor << '.'
+ << Micro;
+ }
+ }
+
+ // Do not allow conflicts with the watchOS target.
+ if (!WatchOSTarget.empty() && (!iOSTarget.empty() || !TvOSTarget.empty())) {
+ getDriver().Diag(diag::err_drv_conflicting_deployment_targets)
+ << "WATCHOS_DEPLOYMENT_TARGET"
+ << (!iOSTarget.empty() ? "IPHONEOS_DEPLOYMENT_TARGET" :
+ "TVOS_DEPLOYMENT_TARGET");
+ }
+
+ // Do not allow conflicts with the tvOS target.
+ if (!TvOSTarget.empty() && !iOSTarget.empty()) {
+ getDriver().Diag(diag::err_drv_conflicting_deployment_targets)
+ << "TVOS_DEPLOYMENT_TARGET"
+ << "IPHONEOS_DEPLOYMENT_TARGET";
+ }
+
+ // Allow conflicts among OSX and iOS for historical reasons, but choose the
+ // default platform.
+ if (!OSXTarget.empty() && (!iOSTarget.empty() ||
+ !WatchOSTarget.empty() ||
+ !TvOSTarget.empty())) {
+ if (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::thumb)
+ OSXTarget = "";
+ else
+ iOSTarget = WatchOSTarget = TvOSTarget = "";
+ }
+
+ if (!OSXTarget.empty()) {
+ const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
+ OSXVersion = Args.MakeJoinedArg(nullptr, O, OSXTarget);
+ Args.append(OSXVersion);
+ } else if (!iOSTarget.empty()) {
+ const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
+ iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget);
+ Args.append(iOSVersion);
+ } else if (!TvOSTarget.empty()) {
+ const Option O = Opts.getOption(options::OPT_mtvos_version_min_EQ);
+ TvOSVersion = Args.MakeJoinedArg(nullptr, O, TvOSTarget);
+ Args.append(TvOSVersion);
+ } else if (!WatchOSTarget.empty()) {
+ const Option O = Opts.getOption(options::OPT_mwatchos_version_min_EQ);
+ WatchOSVersion = Args.MakeJoinedArg(nullptr, O, WatchOSTarget);
+ Args.append(WatchOSVersion);
+ }
+ }
+
+ DarwinPlatformKind Platform;
+ if (OSXVersion)
+ Platform = MacOS;
+ else if (iOSVersion)
+ Platform = IPhoneOS;
+ else if (TvOSVersion)
+ Platform = TvOS;
+ else if (WatchOSVersion)
+ Platform = WatchOS;
+ else
+ llvm_unreachable("Unable to infer Darwin variant");
+
+ // Set the tool chain target information.
+ if (Platform == MacOS) {
+ assert((!iOSVersion && !TvOSVersion && !WatchOSVersion) &&
+ "Unknown target platform!");
+ if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro,
+ HadExtra) ||
+ HadExtra || Major != 10 || Minor >= 100 || Micro >= 100)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
+ << OSXVersion->getAsString(Args);
+ } else if (Platform == IPhoneOS) {
+ assert(iOSVersion && "Unknown target platform!");
+ if (!Driver::GetReleaseVersion(iOSVersion->getValue(), Major, Minor, Micro,
+ HadExtra) ||
+ HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
+ << iOSVersion->getAsString(Args);
+ // For 32-bit targets, the deployment target for iOS has to be earlier than
+ // iOS 11.
+ if (getTriple().isArch32Bit() && Major >= 11) {
+ // If the deployment target is explicitly specified, print a diagnostic.
+ if (!ExplicitIOSDeploymentTargetStr.empty()) {
+ getDriver().Diag(diag::warn_invalid_ios_deployment_target)
+ << ExplicitIOSDeploymentTargetStr;
+ // Otherwise, set it to 10.99.99.
+ } else {
+ Major = 10;
+ Minor = 99;
+ Micro = 99;
+ }
+ }
+ } else if (Platform == TvOS) {
+ if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor,
+ Micro, HadExtra) || HadExtra ||
+ Major >= 100 || Minor >= 100 || Micro >= 100)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
+ << TvOSVersion->getAsString(Args);
+ } else if (Platform == WatchOS) {
+ if (!Driver::GetReleaseVersion(WatchOSVersion->getValue(), Major, Minor,
+ Micro, HadExtra) || HadExtra ||
+ Major >= 10 || Minor >= 100 || Micro >= 100)
+ getDriver().Diag(diag::err_drv_invalid_version_number)
+ << WatchOSVersion->getAsString(Args);
+ } else
+ llvm_unreachable("unknown kind of Darwin platform");
+
+ // Recognize iOS targets with an x86 architecture as the iOS simulator.
+ if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 ||
+ getTriple().getArch() == llvm::Triple::x86_64))
+ Platform = IPhoneOSSimulator;
+ if (TvOSVersion && (getTriple().getArch() == llvm::Triple::x86 ||
+ getTriple().getArch() == llvm::Triple::x86_64))
+ Platform = TvOSSimulator;
+ if (WatchOSVersion && (getTriple().getArch() == llvm::Triple::x86 ||
+ getTriple().getArch() == llvm::Triple::x86_64))
+ Platform = WatchOSSimulator;
+
+ setTarget(Platform, Major, Minor, Micro);
+
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ StringRef SDK = getSDKName(A->getValue());
+ if (SDK.size() > 0) {
+ size_t StartVer = SDK.find_first_of("0123456789");
+ StringRef SDKName = SDK.slice(0, StartVer);
+ if (!SDKName.startswith(getPlatformFamily()))
+ getDriver().Diag(diag::warn_incompatible_sysroot)
+ << SDKName << getPlatformFamily();
+ }
+ }
+}
+
+void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CXXStdlibType Type = GetCXXStdlibType(Args);
+
+ switch (Type) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back("-lc++");
+ break;
+
+ case ToolChain::CST_Libstdcxx:
+ // Unfortunately, -lstdc++ doesn't always exist in the standard search path;
+ // it was previously found in the gcc lib dir. However, for all the Darwin
+ // platforms we care about it was -lstdc++.6, so we search for that
+ // explicitly if we can't see an obvious -lstdc++ candidate.
+
+ // Check in the sysroot first.
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ SmallString<128> P(A->getValue());
+ llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib");
+
+ if (!getVFS().exists(P)) {
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::append(P, "libstdc++.6.dylib");
+ if (getVFS().exists(P)) {
+ CmdArgs.push_back(Args.MakeArgString(P));
+ return;
+ }
+ }
+ }
+
+ // Otherwise, look in the root.
+ // FIXME: This should be removed someday when we don't have to care about
+ // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist.
+ if (!getVFS().exists("/usr/lib/libstdc++.dylib") &&
+ getVFS().exists("/usr/lib/libstdc++.6.dylib")) {
+ CmdArgs.push_back("/usr/lib/libstdc++.6.dylib");
+ return;
+ }
+
+ // Otherwise, let the linker search.
+ CmdArgs.push_back("-lstdc++");
+ break;
+ }
+}
+
+void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // For Darwin platforms, use the compiler-rt-based support library
+ // instead of the gcc-provided one (which is also incidentally
+ // only present in the gcc lib dir, which makes it hard to find).
+
+ SmallString<128> P(getDriver().ResourceDir);
+ llvm::sys::path::append(P, "lib", "darwin");
+
+ // Use the newer cc_kext for iOS ARM after 6.0.
+ if (isTargetWatchOS()) {
+ llvm::sys::path::append(P, "libclang_rt.cc_kext_watchos.a");
+ } else if (isTargetTvOS()) {
+ llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a");
+ } else if (isTargetIPhoneOS()) {
+ llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a");
+ } else {
+ llvm::sys::path::append(P, "libclang_rt.cc_kext.a");
+ }
+
+ // For now, allow missing resource libraries to support developers who may
+ // not have compiler-rt checked out or integrated into their build.
+ if (getVFS().exists(P))
+ CmdArgs.push_back(Args.MakeArgString(P));
+}
+
+DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args,
+ StringRef BoundArch,
+ Action::OffloadKind) const {
+ DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
+ const OptTable &Opts = getDriver().getOpts();
+
+ // FIXME: We really want to get out of the tool chain level argument
+ // translation business, as it makes the driver functionality much
+ // more opaque. For now, we follow gcc closely solely for the
+ // purpose of easily achieving feature parity & testability. Once we
+ // have something that works, we should reevaluate each translation
+ // and try to push it down into tool specific logic.
+
+ for (Arg *A : Args) {
+ if (A->getOption().matches(options::OPT_Xarch__)) {
+ // Skip this argument unless the architecture matches either the toolchain
+ // triple arch, or the arch being bound.
+ llvm::Triple::ArchType XarchArch =
+ tools::darwin::getArchTypeForMachOArchName(A->getValue(0));
+ if (!(XarchArch == getArch() ||
+ (!BoundArch.empty() &&
+ XarchArch ==
+ tools::darwin::getArchTypeForMachOArchName(BoundArch))))
+ continue;
+
+ Arg *OriginalArg = A;
+ unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
+ unsigned Prev = Index;
+ std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index));
+
+ // If the argument parsing failed or more than one argument was
+ // consumed, the -Xarch_ argument's parameter tried to consume
+ // extra arguments. Emit an error and ignore.
+ //
+ // We also want to disallow any options which would alter the
+ // driver behavior; that isn't going to work in our model. We
+ // use isDriverOption() as an approximation, although things
+ // like -O4 are going to slip through.
+ if (!XarchArg || Index > Prev + 1) {
+ getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args)
+ << A->getAsString(Args);
+ continue;
+ } else if (XarchArg->getOption().hasFlag(options::DriverOption)) {
+ getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver)
+ << A->getAsString(Args);
+ continue;
+ }
+
+ XarchArg->setBaseArg(A);
+
+ A = XarchArg.release();
+ DAL->AddSynthesizedArg(A);
+
+ // Linker input arguments require custom handling. The problem is that we
+ // have already constructed the phase actions, so we can not treat them as
+ // "input arguments".
+ if (A->getOption().hasFlag(options::LinkerInput)) {
+ // Convert the argument into individual Zlinker_input_args.
+ for (const char *Value : A->getValues()) {
+ DAL->AddSeparateArg(
+ OriginalArg, Opts.getOption(options::OPT_Zlinker_input), Value);
+ }
+ continue;
+ }
+ }
+
+ // Sob. These is strictly gcc compatible for the time being. Apple
+ // gcc translates options twice, which means that self-expanding
+ // options add duplicates.
+ switch ((options::ID)A->getOption().getID()) {
+ default:
+ DAL->append(A);
+ break;
+
+ case options::OPT_mkernel:
+ case options::OPT_fapple_kext:
+ DAL->append(A);
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_static));
+ break;
+
+ case options::OPT_dependency_file:
+ DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue());
+ break;
+
+ case options::OPT_gfull:
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag));
+ DAL->AddFlagArg(
+ A, Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols));
+ break;
+
+ case options::OPT_gused:
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag));
+ DAL->AddFlagArg(
+ A, Opts.getOption(options::OPT_feliminate_unused_debug_symbols));
+ break;
+
+ case options::OPT_shared:
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib));
+ break;
+
+ case options::OPT_fconstant_cfstrings:
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_mconstant_cfstrings));
+ break;
+
+ case options::OPT_fno_constant_cfstrings:
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_constant_cfstrings));
+ break;
+
+ case options::OPT_Wnonportable_cfstrings:
+ DAL->AddFlagArg(A,
+ Opts.getOption(options::OPT_mwarn_nonportable_cfstrings));
+ break;
+
+ case options::OPT_Wno_nonportable_cfstrings:
+ DAL->AddFlagArg(
+ A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings));
+ break;
+
+ case options::OPT_fpascal_strings:
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings));
+ break;
+
+ case options::OPT_fno_pascal_strings:
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings));
+ break;
+ }
+ }
+
+ if (getTriple().getArch() == llvm::Triple::x86 ||
+ getTriple().getArch() == llvm::Triple::x86_64)
+ if (!Args.hasArgNoClaim(options::OPT_mtune_EQ))
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ),
+ "core2");
+
+ // Add the arch options based on the particular spelling of -arch, to match
+ // how the driver driver works.
+ if (!BoundArch.empty()) {
+ StringRef Name = BoundArch;
+ const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ);
+ const Option MArch = Opts.getOption(clang::driver::options::OPT_march_EQ);
+
+ // This code must be kept in sync with LLVM's getArchTypeForDarwinArch,
+ // which defines the list of which architectures we accept.
+ if (Name == "ppc")
+ ;
+ else if (Name == "ppc601")
+ DAL->AddJoinedArg(nullptr, MCpu, "601");
+ else if (Name == "ppc603")
+ DAL->AddJoinedArg(nullptr, MCpu, "603");
+ else if (Name == "ppc604")
+ DAL->AddJoinedArg(nullptr, MCpu, "604");
+ else if (Name == "ppc604e")
+ DAL->AddJoinedArg(nullptr, MCpu, "604e");
+ else if (Name == "ppc750")
+ DAL->AddJoinedArg(nullptr, MCpu, "750");
+ else if (Name == "ppc7400")
+ DAL->AddJoinedArg(nullptr, MCpu, "7400");
+ else if (Name == "ppc7450")
+ DAL->AddJoinedArg(nullptr, MCpu, "7450");
+ else if (Name == "ppc970")
+ DAL->AddJoinedArg(nullptr, MCpu, "970");
+
+ else if (Name == "ppc64" || Name == "ppc64le")
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64));
+
+ else if (Name == "i386")
+ ;
+ else if (Name == "i486")
+ DAL->AddJoinedArg(nullptr, MArch, "i486");
+ else if (Name == "i586")
+ DAL->AddJoinedArg(nullptr, MArch, "i586");
+ else if (Name == "i686")
+ DAL->AddJoinedArg(nullptr, MArch, "i686");
+ else if (Name == "pentium")
+ DAL->AddJoinedArg(nullptr, MArch, "pentium");
+ else if (Name == "pentium2")
+ DAL->AddJoinedArg(nullptr, MArch, "pentium2");
+ else if (Name == "pentpro")
+ DAL->AddJoinedArg(nullptr, MArch, "pentiumpro");
+ else if (Name == "pentIIm3")
+ DAL->AddJoinedArg(nullptr, MArch, "pentium2");
+
+ else if (Name == "x86_64")
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64));
+ else if (Name == "x86_64h") {
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64));
+ DAL->AddJoinedArg(nullptr, MArch, "x86_64h");
+ }
+
+ else if (Name == "arm")
+ DAL->AddJoinedArg(nullptr, MArch, "armv4t");
+ else if (Name == "armv4t")
+ DAL->AddJoinedArg(nullptr, MArch, "armv4t");
+ else if (Name == "armv5")
+ DAL->AddJoinedArg(nullptr, MArch, "armv5tej");
+ else if (Name == "xscale")
+ DAL->AddJoinedArg(nullptr, MArch, "xscale");
+ else if (Name == "armv6")
+ DAL->AddJoinedArg(nullptr, MArch, "armv6k");
+ else if (Name == "armv6m")
+ DAL->AddJoinedArg(nullptr, MArch, "armv6m");
+ else if (Name == "armv7")
+ DAL->AddJoinedArg(nullptr, MArch, "armv7a");
+ else if (Name == "armv7em")
+ DAL->AddJoinedArg(nullptr, MArch, "armv7em");
+ else if (Name == "armv7k")
+ DAL->AddJoinedArg(nullptr, MArch, "armv7k");
+ else if (Name == "armv7m")
+ DAL->AddJoinedArg(nullptr, MArch, "armv7m");
+ else if (Name == "armv7s")
+ DAL->AddJoinedArg(nullptr, MArch, "armv7s");
+ }
+
+ return DAL;
+}
+
+void MachO::AddLinkRuntimeLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Embedded targets are simple at the moment, not supporting sanitizers and
+ // with different libraries for each member of the product { static, PIC } x
+ // { hard-float, soft-float }
+ llvm::SmallString<32> CompilerRT = StringRef("libclang_rt.");
+ CompilerRT +=
+ (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)
+ ? "hard"
+ : "soft";
+ CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a";
+
+ AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true);
+}
+
+bool Darwin::isAlignedAllocationUnavailable() const {
+ switch (TargetPlatform) {
+ case MacOS: // Earlier than 10.13.
+ return TargetVersion < VersionTuple(10U, 13U, 0U);
+ case IPhoneOS:
+ case IPhoneOSSimulator:
+ case TvOS:
+ case TvOSSimulator: // Earlier than 11.0.
+ return TargetVersion < VersionTuple(11U, 0U, 0U);
+ case WatchOS:
+ case WatchOSSimulator: // Earlier than 4.0.
+ return TargetVersion < VersionTuple(4U, 0U, 0U);
+ }
+ llvm_unreachable("Unsupported platform");
+}
+
+void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const {
+ if (isAlignedAllocationUnavailable())
+ CC1Args.push_back("-faligned-alloc-unavailable");
+}
+
+DerivedArgList *
+Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const {
+ // First get the generic Apple args, before moving onto Darwin-specific ones.
+ DerivedArgList *DAL =
+ MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
+ const OptTable &Opts = getDriver().getOpts();
+
+ // If no architecture is bound, none of the translations here are relevant.
+ if (BoundArch.empty())
+ return DAL;
+
+ // Add an explicit version min argument for the deployment target. We do this
+ // after argument translation because -Xarch_ arguments may add a version min
+ // argument.
+ AddDeploymentTarget(*DAL);
+
+ // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext.
+ // FIXME: It would be far better to avoid inserting those -static arguments,
+ // but we can't check the deployment target in the translation code until
+ // it is set here.
+ if (isTargetWatchOSBased() ||
+ (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) {
+ for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) {
+ Arg *A = *it;
+ ++it;
+ if (A->getOption().getID() != options::OPT_mkernel &&
+ A->getOption().getID() != options::OPT_fapple_kext)
+ continue;
+ assert(it != ie && "unexpected argument translation");
+ A = *it;
+ assert(A->getOption().getID() == options::OPT_static &&
+ "missing expected -static argument");
+ *it = nullptr;
+ ++it;
+ }
+ }
+
+ if (!Args.getLastArg(options::OPT_stdlib_EQ) &&
+ GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ),
+ "libc++");
+
+ // Validate the C++ standard library choice.
+ CXXStdlibType Type = GetCXXStdlibType(*DAL);
+ if (Type == ToolChain::CST_Libcxx) {
+ // Check whether the target provides libc++.
+ StringRef where;
+
+ // Complain about targeting iOS < 5.0 in any way.
+ if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0))
+ where = "iOS 5.0";
+
+ if (where != StringRef()) {
+ getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where;
+ }
+ }
+
+ auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch);
+ if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) {
+ if (Args.hasFlag(options::OPT_fomit_frame_pointer,
+ options::OPT_fno_omit_frame_pointer, false))
+ getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target)
+ << "-fomit-frame-pointer" << BoundArch;
+ }
+
+ return DAL;
+}
+
+bool MachO::IsUnwindTablesDefault(const ArgList &Args) const {
+ // Unwind tables are not emitted if -fno-exceptions is supplied (except when
+ // targeting x86_64).
+ return getArch() == llvm::Triple::x86_64 ||
+ (!UseSjLjExceptions(Args) &&
+ Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
+ true));
+}
+
+bool MachO::UseDwarfDebugFlags() const {
+ if (const char *S = ::getenv("RC_DEBUG_OPTIONS"))
+ return S[0] != '\0';
+ return false;
+}
+
+bool Darwin::UseSjLjExceptions(const ArgList &Args) const {
+ // Darwin uses SjLj exceptions on ARM.
+ if (getTriple().getArch() != llvm::Triple::arm &&
+ getTriple().getArch() != llvm::Triple::thumb)
+ return false;
+
+ // Only watchOS uses the new DWARF/Compact unwinding method.
+ llvm::Triple Triple(ComputeLLVMTriple(Args));
+ return !Triple.isWatchABI();
+}
+
+bool Darwin::SupportsEmbeddedBitcode() const {
+ assert(TargetInitialized && "Target not initialized!");
+ if (isTargetIPhoneOS() && isIPhoneOSVersionLT(6, 0))
+ return false;
+ return true;
+}
+
+bool MachO::isPICDefault() const { return true; }
+
+bool MachO::isPIEDefault() const { return false; }
+
+bool MachO::isPICDefaultForced() const {
+ return (getArch() == llvm::Triple::x86_64 ||
+ getArch() == llvm::Triple::aarch64);
+}
+
+bool MachO::SupportsProfiling() const {
+ // Profiling instrumentation is only supported on x86.
+ return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64;
+}
+
+void Darwin::addMinVersionArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ VersionTuple TargetVersion = getTargetVersion();
+
+ if (isTargetWatchOS())
+ CmdArgs.push_back("-watchos_version_min");
+ else if (isTargetWatchOSSimulator())
+ CmdArgs.push_back("-watchos_simulator_version_min");
+ else if (isTargetTvOS())
+ CmdArgs.push_back("-tvos_version_min");
+ else if (isTargetTvOSSimulator())
+ CmdArgs.push_back("-tvos_simulator_version_min");
+ else if (isTargetIOSSimulator())
+ CmdArgs.push_back("-ios_simulator_version_min");
+ else if (isTargetIOSBased())
+ CmdArgs.push_back("-iphoneos_version_min");
+ else {
+ assert(isTargetMacOS() && "unexpected target");
+ CmdArgs.push_back("-macosx_version_min");
+ }
+
+ CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
+}
+
+void Darwin::addStartObjectFileArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Derived from startfile spec.
+ if (Args.hasArg(options::OPT_dynamiclib)) {
+ // Derived from darwin_dylib1 spec.
+ if (isTargetWatchOSBased()) {
+ ; // watchOS does not need dylib1.o.
+ } else if (isTargetIOSSimulator()) {
+ ; // iOS simulator does not need dylib1.o.
+ } else if (isTargetIPhoneOS()) {
+ if (isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-ldylib1.o");
+ } else {
+ if (isMacosxVersionLT(10, 5))
+ CmdArgs.push_back("-ldylib1.o");
+ else if (isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-ldylib1.10.5.o");
+ }
+ } else {
+ if (Args.hasArg(options::OPT_bundle)) {
+ if (!Args.hasArg(options::OPT_static)) {
+ // Derived from darwin_bundle1 spec.
+ if (isTargetWatchOSBased()) {
+ ; // watchOS does not need bundle1.o.
+ } else if (isTargetIOSSimulator()) {
+ ; // iOS simulator does not need bundle1.o.
+ } else if (isTargetIPhoneOS()) {
+ if (isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-lbundle1.o");
+ } else {
+ if (isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-lbundle1.o");
+ }
+ }
+ } else {
+ if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) {
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_object) ||
+ Args.hasArg(options::OPT_preload)) {
+ CmdArgs.push_back("-lgcrt0.o");
+ } else {
+ CmdArgs.push_back("-lgcrt1.o");
+
+ // darwin_crt2 spec is empty.
+ }
+ // By default on OS X 10.8 and later, we don't link with a crt1.o
+ // file and the linker knows to use _main as the entry point. But,
+ // when compiling with -pg, we need to link with the gcrt1.o file,
+ // so pass the -no_new_main option to tell the linker to use the
+ // "start" symbol as the entry point.
+ if (isTargetMacOS() && !isMacosxVersionLT(10, 8))
+ CmdArgs.push_back("-no_new_main");
+ } else {
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_object) ||
+ Args.hasArg(options::OPT_preload)) {
+ CmdArgs.push_back("-lcrt0.o");
+ } else {
+ // Derived from darwin_crt1 spec.
+ if (isTargetWatchOSBased()) {
+ ; // watchOS does not need crt1.o.
+ } else if (isTargetIOSSimulator()) {
+ ; // iOS simulator does not need crt1.o.
+ } else if (isTargetIPhoneOS()) {
+ if (getArch() == llvm::Triple::aarch64)
+ ; // iOS does not need any crt1 files for arm64
+ else if (isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-lcrt1.o");
+ else if (isIPhoneOSVersionLT(6, 0))
+ CmdArgs.push_back("-lcrt1.3.1.o");
+ } else {
+ if (isMacosxVersionLT(10, 5))
+ CmdArgs.push_back("-lcrt1.o");
+ else if (isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-lcrt1.10.5.o");
+ else if (isMacosxVersionLT(10, 8))
+ CmdArgs.push_back("-lcrt1.10.6.o");
+
+ // darwin_crt2 spec is empty.
+ }
+ }
+ }
+ }
+ }
+
+ if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) &&
+ !isTargetWatchOS() &&
+ isMacosxVersionLT(10, 5)) {
+ const char *Str = Args.MakeArgString(GetFilePath("crt3.o"));
+ CmdArgs.push_back(Str);
+ }
+}
+
+bool Darwin::SupportsObjCGC() const { return isTargetMacOS(); }
+
+void Darwin::CheckObjCARC() const {
+ if (isTargetIOSBased() || isTargetWatchOSBased() ||
+ (isTargetMacOS() && !isMacosxVersionLT(10, 6)))
+ return;
+ getDriver().Diag(diag::err_arc_unsupported_on_toolchain);
+}
+
+SanitizerMask Darwin::getSupportedSanitizers() const {
+ const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::Leak;
+ Res |= SanitizerKind::Fuzzer;
+ if (isTargetMacOS()) {
+ if (!isMacosxVersionLT(10, 9))
+ Res |= SanitizerKind::Vptr;
+ Res |= SanitizerKind::SafeStack;
+ if (IsX86_64)
+ Res |= SanitizerKind::Thread;
+ } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) {
+ if (IsX86_64)
+ Res |= SanitizerKind::Thread;
+ }
+ return Res;
+}
+
+void Darwin::printVerboseInfo(raw_ostream &OS) const {
+ CudaInstallation.print(OS);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.h
new file mode 100644
index 0000000..77c569e
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Darwin.h
@@ -0,0 +1,499 @@
+//===--- Darwin.h - Darwin ToolChain Implementations ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H
+
+#include "Cuda.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+
+namespace toolchains {
+class MachO;
+} // end namespace toolchains
+
+namespace tools {
+
+namespace darwin {
+llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str);
+void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str);
+
+class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool {
+ virtual void anchor();
+
+protected:
+ void AddMachOArch(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ const toolchains::MachO &getMachOToolChain() const {
+ return reinterpret_cast<const toolchains::MachO &>(getToolChain());
+ }
+
+public:
+ MachOTool(
+ const char *Name, const char *ShortName, const ToolChain &TC,
+ ResponseFileSupport ResponseSupport = RF_None,
+ llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8,
+ const char *ResponseFlag = "@")
+ : Tool(Name, ShortName, TC, ResponseSupport, ResponseEncoding,
+ ResponseFlag) {}
+};
+
+class LLVM_LIBRARY_VISIBILITY Assembler : public MachOTool {
+public:
+ Assembler(const ToolChain &TC)
+ : MachOTool("darwin::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public MachOTool {
+ bool NeedsTempPath(const InputInfoList &Inputs) const;
+ void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ const InputInfoList &Inputs) const;
+
+public:
+ Linker(const ToolChain &TC)
+ : MachOTool("darwin::Linker", "linker", TC, RF_FileList,
+ llvm::sys::WEM_UTF8, "-filelist") {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool {
+public:
+ Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Dsymutil : public MachOTool {
+public:
+ Dsymutil(const ToolChain &TC)
+ : MachOTool("darwin::Dsymutil", "dsymutil", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isDsymutilJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY VerifyDebug : public MachOTool {
+public:
+ VerifyDebug(const ToolChain &TC)
+ : MachOTool("darwin::VerifyDebug", "dwarfdump", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace darwin
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY MachO : public ToolChain {
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+ Tool *getTool(Action::ActionClass AC) const override;
+
+private:
+ mutable std::unique_ptr<tools::darwin::Lipo> Lipo;
+ mutable std::unique_ptr<tools::darwin::Dsymutil> Dsymutil;
+ mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug;
+
+public:
+ MachO(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~MachO() override;
+
+ /// @name MachO specific toolchain API
+ /// {
+
+ /// Get the "MachO" arch name for a particular compiler invocation. For
+ /// example, Apple treats different ARM variations as distinct architectures.
+ StringRef getMachOArchName(const llvm::opt::ArgList &Args) const;
+
+ /// Add the linker arguments to link the ARC runtime library.
+ virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {}
+
+ /// Add the linker arguments to link the compiler runtime library.
+ virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ virtual void AddFuzzerLinkArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ }
+
+ virtual void addMinVersionArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {}
+
+ /// On some iOS platforms, kernel and kernel modules were built statically. Is
+ /// this such a target?
+ virtual bool isKernelStatic() const { return false; }
+
+ /// Is the target either iOS or an iOS simulator?
+ bool isTargetIOSBased() const { return false; }
+
+ void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ StringRef DarwinLibName, bool AlwaysLink = false,
+ bool IsEmbedded = false, bool AddRPath = false) const;
+
+ /// Add any profiling runtime libraries that are needed. This is essentially a
+ /// MachO specific version of addProfileRT in Tools.cpp.
+ void addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override {
+ // There aren't any profiling libs for embedded targets currently.
+ }
+
+ /// }
+ /// @name ToolChain Implementation
+ /// {
+
+ types::ID LookupTypeForExtension(StringRef Ext) const override;
+
+ bool HasNativeLLVMSupport() const override;
+
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
+ bool IsBlocksDefault() const override {
+ // Always allow blocks on Apple; users interested in versioning are
+ // expected to use /usr/include/Block.h.
+ return true;
+ }
+ bool IsIntegratedAssemblerDefault() const override {
+ // Default integrated assembler to on for Apple's MachO targets.
+ return true;
+ }
+
+ bool IsMathErrnoDefault() const override { return false; }
+
+ bool IsEncodeExtendedBlockSignatureDefault() const override { return true; }
+
+ bool IsObjCNonFragileABIDefault() const override {
+ // Non-fragile ABI is default for everything but i386.
+ return getTriple().getArch() != llvm::Triple::x86;
+ }
+
+ bool UseObjCMixedDispatch() const override { return true; }
+
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return ToolChain::RLT_CompilerRT;
+ }
+
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+
+ bool SupportsProfiling() const override;
+
+ bool SupportsObjCGC() const override { return false; }
+
+ bool UseDwarfDebugFlags() const override;
+
+ bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override {
+ return false;
+ }
+
+ /// }
+};
+
+/// Darwin - The base Darwin tool chain.
+class LLVM_LIBRARY_VISIBILITY Darwin : public MachO {
+public:
+ /// Whether the information on the target has been initialized.
+ //
+ // FIXME: This should be eliminated. What we want to do is make this part of
+ // the "default target for arguments" selection process, once we get out of
+ // the argument translation business.
+ mutable bool TargetInitialized;
+
+ enum DarwinPlatformKind {
+ MacOS,
+ IPhoneOS,
+ IPhoneOSSimulator,
+ TvOS,
+ TvOSSimulator,
+ WatchOS,
+ WatchOSSimulator
+ };
+
+ mutable DarwinPlatformKind TargetPlatform;
+
+ /// The OS version we are targeting.
+ mutable VersionTuple TargetVersion;
+
+ CudaInstallationDetector CudaInstallation;
+
+private:
+ void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const;
+
+public:
+ Darwin(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~Darwin() override;
+
+ std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
+ types::ID InputType) const override;
+
+ /// @name Apple Specific Toolchain Implementation
+ /// {
+
+ void addMinVersionArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ void addStartObjectFileArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ bool isKernelStatic() const override {
+ return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) &&
+ !isTargetWatchOS());
+ }
+
+ void addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+protected:
+ /// }
+ /// @name Darwin specific Toolchain functions
+ /// {
+
+ // FIXME: Eliminate these ...Target functions and derive separate tool chains
+ // for these targets and put version in constructor.
+ void setTarget(DarwinPlatformKind Platform, unsigned Major, unsigned Minor,
+ unsigned Micro) const {
+ // FIXME: For now, allow reinitialization as long as values don't
+ // change. This will go away when we move away from argument translation.
+ if (TargetInitialized && TargetPlatform == Platform &&
+ TargetVersion == VersionTuple(Major, Minor, Micro))
+ return;
+
+ assert(!TargetInitialized && "Target already initialized!");
+ TargetInitialized = true;
+ TargetPlatform = Platform;
+ TargetVersion = VersionTuple(Major, Minor, Micro);
+ }
+
+ bool isTargetIPhoneOS() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == IPhoneOS || TargetPlatform == TvOS;
+ }
+
+ bool isTargetIOSSimulator() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == IPhoneOSSimulator ||
+ TargetPlatform == TvOSSimulator;
+ }
+
+ bool isTargetIOSBased() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return isTargetIPhoneOS() || isTargetIOSSimulator();
+ }
+
+ bool isTargetTvOS() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == TvOS;
+ }
+
+ bool isTargetTvOSSimulator() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == TvOSSimulator;
+ }
+
+ bool isTargetTvOSBased() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == TvOS || TargetPlatform == TvOSSimulator;
+ }
+
+ bool isTargetWatchOS() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == WatchOS;
+ }
+
+ bool isTargetWatchOSSimulator() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == WatchOSSimulator;
+ }
+
+ bool isTargetWatchOSBased() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == WatchOS || TargetPlatform == WatchOSSimulator;
+ }
+
+ bool isTargetMacOS() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetPlatform == MacOS;
+ }
+
+ bool isTargetInitialized() const { return TargetInitialized; }
+
+ VersionTuple getTargetVersion() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return TargetVersion;
+ }
+
+ bool isIPhoneOSVersionLT(unsigned V0, unsigned V1 = 0,
+ unsigned V2 = 0) const {
+ assert(isTargetIOSBased() && "Unexpected call for non iOS target!");
+ return TargetVersion < VersionTuple(V0, V1, V2);
+ }
+
+ bool isMacosxVersionLT(unsigned V0, unsigned V1 = 0, unsigned V2 = 0) const {
+ assert(isTargetMacOS() && "Unexpected call for non OS X target!");
+ return TargetVersion < VersionTuple(V0, V1, V2);
+ }
+
+ /// Return true if c++17 aligned allocation/deallocation functions are not
+ /// implemented in the c++ standard library of the deployment target we are
+ /// targeting.
+ bool isAlignedAllocationUnavailable() const;
+
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
+ StringRef getPlatformFamily() const;
+ static StringRef getSDKName(StringRef isysroot);
+ StringRef getOSLibraryNameSuffix() const;
+
+public:
+ /// }
+ /// @name ToolChain Implementation
+ /// {
+
+ // Darwin tools support multiple architecture (e.g., i386 and x86_64) and
+ // most development is done against SDKs, so compiling for a different
+ // architecture should not get any special treatment.
+ bool isCrossCompiling() const override { return false; }
+
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
+ CXXStdlibType GetDefaultCXXStdlibType() const override;
+ ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override;
+ bool hasBlocksRuntime() const override;
+
+ void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ bool UseObjCMixedDispatch() const override {
+ // This is only used with the non-fragile ABI and non-legacy dispatch.
+
+ // Mixed dispatch is used everywhere except OS X before 10.6.
+ return !(isTargetMacOS() && isMacosxVersionLT(10, 6));
+ }
+
+ unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
+ // Stack protectors default to on for user code on 10.5,
+ // and for everything in 10.6 and beyond
+ if (isTargetIOSBased() || isTargetWatchOSBased())
+ return 1;
+ else if (isTargetMacOS() && !isMacosxVersionLT(10, 6))
+ return 1;
+ else if (isTargetMacOS() && !isMacosxVersionLT(10, 5) && !KernelOrKext)
+ return 1;
+
+ return 0;
+ }
+
+ bool SupportsObjCGC() const override;
+
+ void CheckObjCARC() const override;
+
+ bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override;
+
+ bool SupportsEmbeddedBitcode() const override;
+
+ SanitizerMask getSupportedSanitizers() const override;
+
+ void printVerboseInfo(raw_ostream &OS) const override;
+};
+
+/// DarwinClang - The Darwin toolchain used by Clang.
+class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
+public:
+ DarwinClang(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ /// @name Apple ToolChain Implementation
+ /// {
+
+ RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
+
+ void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ void AddCCKextLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override;
+
+ void AddLinkARCArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ unsigned GetDefaultDwarfVersion() const override;
+ // Until dtrace (via CTF) and LLDB can deal with distributed debug info,
+ // Darwin defaults to standalone/full debug info.
+ bool GetDefaultStandaloneDebug() const override { return true; }
+ llvm::DebuggerKind getDefaultDebuggerTuning() const override {
+ return llvm::DebuggerKind::LLDB;
+ }
+
+ /// }
+
+private:
+ void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ StringRef Sanitizer) const;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.cpp
new file mode 100644
index 0000000..bd2c7fc
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.cpp
@@ -0,0 +1,197 @@
+//===--- DragonFly.cpp - DragonFly ToolChain Implementations ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DragonFly.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+/// DragonFly Tools
+
+// For now, DragonFly Assemble does just about the same as for
+// FreeBSD, but this may change soon.
+void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ // When building 32-bit code on DragonFly/pc64, we have to explicitly
+ // instruct as in the base system to assemble 32-bit code.
+ if (getToolChain().getArch() == llvm::Triple::x86)
+ CmdArgs.push_back("--32");
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ CmdArgs.push_back("--eh-frame-hdr");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-Bshareable");
+ else {
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/usr/libexec/ld-elf.so.2");
+ }
+ CmdArgs.push_back("--hash-style=gnu");
+ CmdArgs.push_back("--enable-new-dtags");
+ }
+
+ // When building 32-bit code on DragonFly/pc64, we have to explicitly
+ // instruct ld in the base system to link 32-bit code.
+ if (getToolChain().getArch() == llvm::Triple::x86) {
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf_i386");
+ }
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("gcrt1.o")));
+ else {
+ if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("Scrt1.o")));
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
+ }
+ }
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ }
+
+ Args.AddAllArgs(CmdArgs,
+ {options::OPT_L, options::OPT_T_Group, options::OPT_e});
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ CmdArgs.push_back("-L/usr/lib/gcc50");
+
+ if (!Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-rpath");
+ CmdArgs.push_back("/usr/lib/gcc50");
+ }
+
+ if (D.CCCIsCXX()) {
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
+
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-lpthread");
+
+ if (!Args.hasArg(options::OPT_nolibc)) {
+ CmdArgs.push_back("-lc");
+ }
+
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_static_libgcc)) {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("-lgcc_eh");
+ } else {
+ if (Args.hasArg(options::OPT_shared_libgcc)) {
+ CmdArgs.push_back("-lgcc_pic");
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-lgcc");
+ } else {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_pic");
+ CmdArgs.push_back("--no-as-needed");
+ }
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
+ }
+
+ getToolChain().addProfileRTLibs(Args, CmdArgs);
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.
+
+DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+
+ // Path mangling to find libexec
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+
+ getFilePaths().push_back(getDriver().Dir + "/../lib");
+ getFilePaths().push_back("/usr/lib");
+ getFilePaths().push_back("/usr/lib/gcc50");
+}
+
+Tool *DragonFly::buildAssembler() const {
+ return new tools::dragonfly::Assembler(*this);
+}
+
+Tool *DragonFly::buildLinker() const {
+ return new tools::dragonfly::Linker(*this);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.h
new file mode 100644
index 0000000..9a06fbd
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/DragonFly.h
@@ -0,0 +1,68 @@
+//===--- DragonFly.h - DragonFly ToolChain Implementations ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DRAGONFLY_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DRAGONFLY_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+/// dragonfly -- Directly call GNU Binutils assembler and linker
+namespace dragonfly {
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
+public:
+ Assembler(const ToolChain &TC)
+ : GnuTool("dragonfly::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("dragonfly::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace dragonfly
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF {
+public:
+ DragonFly(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool IsMathErrnoDefault() const override { return false; }
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DRAGONFLY_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.cpp
new file mode 100644
index 0000000..c6626e9
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.cpp
@@ -0,0 +1,395 @@
+//===--- FreeBSD.cpp - FreeBSD ToolChain Implementations --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FreeBSD.h"
+#include "Arch/ARM.h"
+#include "Arch/Mips.h"
+#include "Arch/Sparc.h"
+#include "CommonArgs.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ // When building 32-bit code on FreeBSD/amd64, we have to explicitly
+ // instruct as in the base system to assemble 32-bit code.
+ switch (getToolChain().getArch()) {
+ default:
+ break;
+ case llvm::Triple::x86:
+ CmdArgs.push_back("--32");
+ break;
+ case llvm::Triple::ppc:
+ CmdArgs.push_back("-a32");
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
+ StringRef CPUName;
+ StringRef ABIName;
+ mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+
+ CmdArgs.push_back("-march");
+ CmdArgs.push_back(CPUName.data());
+
+ CmdArgs.push_back("-mabi");
+ CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());
+
+ if (getToolChain().getArch() == llvm::Triple::mips ||
+ getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else
+ CmdArgs.push_back("-EL");
+
+ if (Arg *A = Args.getLastArg(options::OPT_G)) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-G" + v));
+ A->claim();
+ }
+
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb: {
+ arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args);
+
+ if (ABI == arm::FloatABI::Hard)
+ CmdArgs.push_back("-mfpu=vfp");
+ else
+ CmdArgs.push_back("-mfpu=softvfp");
+
+ switch (getToolChain().getTriple().getEnvironment()) {
+ case llvm::Triple::GNUEABIHF:
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::EABI:
+ CmdArgs.push_back("-meabi=5");
+ break;
+
+ default:
+ CmdArgs.push_back("-matpcs");
+ }
+ break;
+ }
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9: {
+ std::string CPU = getCPUName(Args, getToolChain().getTriple());
+ CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const toolchains::FreeBSD &ToolChain =
+ static_cast<const toolchains::FreeBSD &>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+ const llvm::Triple::ArchType Arch = ToolChain.getArch();
+ const bool IsPIE =
+ !Args.hasArg(options::OPT_shared) &&
+ (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (IsPIE)
+ CmdArgs.push_back("-pie");
+
+ CmdArgs.push_back("--eh-frame-hdr");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-Bshareable");
+ } else {
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/libexec/ld-elf.so.1");
+ }
+ if (ToolChain.getTriple().getOSMajorVersion() >= 9) {
+ if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc ||
+ Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
+ CmdArgs.push_back("--hash-style=both");
+ }
+ }
+ CmdArgs.push_back("--enable-new-dtags");
+ }
+
+ // When building 32-bit code on FreeBSD/amd64, we have to explicitly
+ // instruct ld in the base system to link 32-bit code.
+ if (Arch == llvm::Triple::x86) {
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf_i386_fbsd");
+ }
+
+ if (Arch == llvm::Triple::ppc) {
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32ppc_fbsd");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_G)) {
+ if (ToolChain.getArch() == llvm::Triple::mips ||
+ ToolChain.getArch() == llvm::Triple::mipsel ||
+ ToolChain.getArch() == llvm::Triple::mips64 ||
+ ToolChain.getArch() == llvm::Triple::mips64el) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-G" + v));
+ A->claim();
+ }
+ }
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ const char *crt1 = nullptr;
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (Args.hasArg(options::OPT_pg))
+ crt1 = "gcrt1.o";
+ else if (IsPIE)
+ crt1 = "Scrt1.o";
+ else
+ crt1 = "crt1.o";
+ }
+ if (crt1)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+
+ const char *crtbegin = nullptr;
+ if (Args.hasArg(options::OPT_static))
+ crtbegin = "crtbeginT.o";
+ else if (Args.hasArg(options::OPT_shared) || IsPIE)
+ crtbegin = "crtbeginS.o";
+ else
+ crtbegin = "crtbegin.o";
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+ if (D.isUsingLTO())
+ AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
+
+ bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ addOpenMPRuntime(CmdArgs, ToolChain, Args);
+ if (D.CCCIsCXX()) {
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lm_p");
+ else
+ CmdArgs.push_back("-lm");
+ }
+ if (NeedsSanitizerDeps)
+ linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
+ // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
+ // the default system libraries. Just mimic this for now.
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lgcc_p");
+ else
+ CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-lgcc_eh");
+ } else if (Args.hasArg(options::OPT_pg)) {
+ CmdArgs.push_back("-lgcc_eh_p");
+ } else {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ }
+
+ if (Args.hasArg(options::OPT_pthread)) {
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lpthread_p");
+ else
+ CmdArgs.push_back("-lpthread");
+ }
+
+ if (Args.hasArg(options::OPT_pg)) {
+ if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-lc");
+ else
+ CmdArgs.push_back("-lc_p");
+ CmdArgs.push_back("-lgcc_p");
+ } else {
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lgcc");
+ }
+
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-lgcc_eh");
+ } else if (Args.hasArg(options::OPT_pg)) {
+ CmdArgs.push_back("-lgcc_eh_p");
+ } else {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (Args.hasArg(options::OPT_shared) || IsPIE)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
+ else
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+ }
+
+ ToolChain.addProfileRTLibs(Args, CmdArgs);
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.
+
+FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+
+ // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall
+ // back to '/usr/lib' if it doesn't exist.
+ if ((Triple.getArch() == llvm::Triple::x86 ||
+ Triple.getArch() == llvm::Triple::ppc) &&
+ D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o"))
+ getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32");
+ else
+ getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
+}
+
+ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const {
+ if (getTriple().getOSMajorVersion() >= 10)
+ return ToolChain::CST_Libcxx;
+ return ToolChain::CST_Libstdcxx;
+}
+
+void FreeBSD::addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/4.2", "", "",
+ "", "", DriverArgs, CC1Args);
+}
+
+void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CXXStdlibType Type = GetCXXStdlibType(Args);
+ bool Profiling = Args.hasArg(options::OPT_pg);
+
+ switch (Type) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
+ break;
+
+ case ToolChain::CST_Libstdcxx:
+ CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++");
+ break;
+ }
+}
+
+Tool *FreeBSD::buildAssembler() const {
+ return new tools::freebsd::Assembler(*this);
+}
+
+Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); }
+
+bool FreeBSD::UseSjLjExceptions(const ArgList &Args) const {
+ // FreeBSD uses SjLj exceptions on ARM oabi.
+ switch (getTriple().getEnvironment()) {
+ case llvm::Triple::GNUEABIHF:
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::EABI:
+ return false;
+
+ default:
+ return (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb);
+ }
+}
+
+bool FreeBSD::HasNativeLLVMSupport() const { return true; }
+
+bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
+
+SanitizerMask FreeBSD::getSupportedSanitizers() const {
+ const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
+ const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
+ const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 ||
+ getTriple().getArch() == llvm::Triple::mips64el;
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::Vptr;
+ if (IsX86_64 || IsMIPS64) {
+ Res |= SanitizerKind::Leak;
+ Res |= SanitizerKind::Thread;
+ }
+ if (IsX86 || IsX86_64) {
+ Res |= SanitizerKind::SafeStack;
+ }
+ return Res;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.h
new file mode 100644
index 0000000..25e9df7
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/FreeBSD.h
@@ -0,0 +1,86 @@
+//===--- FreeBSD.h - FreeBSD ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FREEBSD_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FREEBSD_H
+
+#include "Gnu.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// freebsd -- Directly call GNU Binutils assembler and linker
+namespace freebsd {
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
+public:
+ Assembler(const ToolChain &TC)
+ : GnuTool("freebsd::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("freebsd::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace freebsd
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF {
+public:
+ FreeBSD(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ bool HasNativeLLVMSupport() const override;
+
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
+
+ CXXStdlibType GetDefaultCXXStdlibType() const override;
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override;
+ bool isPIEDefault() const override;
+ SanitizerMask getSupportedSanitizers() const override;
+ unsigned GetDefaultDwarfVersion() const override { return 2; }
+ // Until dtrace (via CTF) and LLDB can deal with distributed debug info,
+ // FreeBSD defaults to standalone/full debug info.
+ bool GetDefaultStandaloneDebug() const override { return true; }
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FREEBSD_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.cpp
new file mode 100644
index 0000000..78053aa
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.cpp
@@ -0,0 +1,286 @@
+//===--- Fuchsia.cpp - Fuchsia ToolChain Implementations --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Fuchsia.h"
+#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const toolchains::Fuchsia &ToolChain =
+ static_cast<const toolchains::Fuchsia &>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ if (llvm::sys::path::stem(Exec).equals_lower("lld")) {
+ CmdArgs.push_back("-flavor");
+ CmdArgs.push_back("gnu");
+
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("rodynamic");
+ }
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r))
+ CmdArgs.push_back("-pie");
+
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("-s");
+
+ if (Args.hasArg(options::OPT_r))
+ CmdArgs.push_back("-r");
+ else
+ CmdArgs.push_back("--build-id");
+
+ if (!Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--eh-frame-hdr");
+
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-Bstatic");
+ else if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-shared");
+
+ if (!Args.hasArg(options::OPT_static)) {
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+
+ if (!Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back(Args.MakeArgString(D.DyldPrefix + "ld.so.1"));
+ }
+ }
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));
+ }
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_u);
+
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-Bdynamic");
+
+ if (D.CCCIsCXX()) {
+ bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
+ !Args.hasArg(options::OPT_static);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bstatic");
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bdynamic");
+ CmdArgs.push_back("-lm");
+ }
+
+ AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
+
+ if (Args.hasArg(options::OPT_pthread) ||
+ Args.hasArg(options::OPT_pthreads))
+ CmdArgs.push_back("-lpthread");
+
+ if (Args.hasArg(options::OPT_fsplit_stack))
+ CmdArgs.push_back("--wrap=pthread_create");
+
+ CmdArgs.push_back("-lc");
+ }
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.
+
+static std::string normalizeTriple(llvm::Triple Triple) {
+ SmallString<64> T;
+ T += Triple.getArchName();
+ T += "-";
+ T += Triple.getOSName();
+ return T.str();
+}
+
+static std::string getTargetDir(const Driver &D,
+ llvm::Triple Triple) {
+ SmallString<128> P(llvm::sys::path::parent_path(D.Dir));
+ llvm::sys::path::append(P, "lib", normalizeTriple(Triple));
+ return P.str();
+}
+
+Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != D.Dir)
+ getProgramPaths().push_back(D.Dir);
+
+ SmallString<128> P(getTargetDir(D, getTriple()));
+ llvm::sys::path::append(P, "lib");
+ getFilePaths().push_back(P.str());
+
+ if (!D.SysRoot.empty()) {
+ SmallString<128> P(D.SysRoot);
+ llvm::sys::path::append(P, "lib");
+ getFilePaths().push_back(P.str());
+ }
+}
+
+std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const {
+ llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
+ Triple.setTriple(normalizeTriple(Triple));
+ return Triple.getTriple();
+}
+
+Tool *Fuchsia::buildLinker() const {
+ return new tools::fuchsia::Linker(*this);
+}
+
+ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType(
+ const ArgList &Args) const {
+ if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value != "compiler-rt")
+ getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name)
+ << A->getAsString(Args);
+ }
+
+ return ToolChain::RLT_CompilerRT;
+}
+
+ToolChain::CXXStdlibType
+Fuchsia::GetCXXStdlibType(const ArgList &Args) const {
+ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value != "libc++")
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
+ }
+
+ return ToolChain::CST_Libcxx;
+}
+
+void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array, true))
+ CC1Args.push_back("-fuse-init-array");
+}
+
+void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Check for configure-time C include directories.
+ StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (CIncludeDirs != "") {
+ SmallVector<StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (StringRef dir : dirs) {
+ StringRef Prefix =
+ llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+ }
+ return;
+ }
+
+ if (!D.SysRoot.empty()) {
+ SmallString<128> P(D.SysRoot);
+ llvm::sys::path::append(P, "include");
+ addExternCSystemInclude(DriverArgs, CC1Args, P.str());
+ }
+}
+
+void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx: {
+ SmallString<128> P(getTargetDir(getDriver(), getTriple()));
+ llvm::sys::path::append(P, "include", "c++", "v1");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ break;
+ }
+
+ default:
+ llvm_unreachable("invalid stdlib name");
+ }
+}
+
+void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ CmdArgs.push_back("-lunwind");
+ break;
+
+ case ToolChain::CST_Libstdcxx:
+ llvm_unreachable("invalid stdlib name");
+ }
+}
+
+SanitizerMask Fuchsia::getSupportedSanitizers() const {
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::SafeStack;
+ return Res;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.h
new file mode 100644
index 0000000..a723a99
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Fuchsia.h
@@ -0,0 +1,92 @@
+//===--- Fuchsia.h - Fuchsia ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FUCHSIA_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FUCHSIA_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace fuchsia {
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("fuchsia::Linker", "ld.lld", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace fuchsia
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Fuchsia : public ToolChain {
+public:
+ Fuchsia(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool HasNativeLLVMSupport() const override { return true; }
+ bool IsIntegratedAssemblerDefault() const override { return true; }
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return ToolChain::RLT_CompilerRT;
+ }
+ CXXStdlibType GetDefaultCXXStdlibType() const override {
+ return ToolChain::CST_Libcxx;
+ }
+ bool isPICDefault() const override { return false; }
+ bool isPIEDefault() const override { return true; }
+ bool isPICDefaultForced() const override { return false; }
+ llvm::DebuggerKind getDefaultDebuggerTuning() const override {
+ return llvm::DebuggerKind::GDB;
+ }
+
+ std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
+ types::ID InputType) const override;
+
+ SanitizerMask getSupportedSanitizers() const override;
+
+ RuntimeLibType
+ GetRuntimeLibType(const llvm::opt::ArgList &Args) const override;
+ CXXStdlibType
+ GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void
+ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ const char *getDefaultLinker() const override {
+ return "lld";
+ }
+
+protected:
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FUCHSIA_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp
new file mode 100644
index 0000000..72a9f85
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -0,0 +1,2480 @@
+//===--- Gnu.cpp - Gnu Tool and ToolChain Implementations -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Gnu.h"
+#include "Linux.h"
+#include "Arch/ARM.h"
+#include "Arch/Mips.h"
+#include "Arch/Sparc.h"
+#include "Arch/SystemZ.h"
+#include "CommonArgs.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/Tool.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetParser.h"
+#include <system_error>
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+void tools::GnuTool::anchor() {}
+
+static bool forwardToGCC(const Option &O) {
+ // Don't forward inputs from the original command line. They are added from
+ // InputInfoList.
+ return O.getKind() != Option::InputClass &&
+ !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput);
+}
+
+void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ for (const auto &A : Args) {
+ if (forwardToGCC(A->getOption())) {
+ // It is unfortunate that we have to claim here, as this means
+ // we will basically never report anything interesting for
+ // platforms using a generic gcc, even if we are just using gcc
+ // to get to the assembler.
+ A->claim();
+
+ // Don't forward any -g arguments to assembly steps.
+ if (isa<AssembleJobAction>(JA) &&
+ A->getOption().matches(options::OPT_g_Group))
+ continue;
+
+ // Don't forward any -W arguments to assembly and link steps.
+ if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) &&
+ A->getOption().matches(options::OPT_W_Group))
+ continue;
+
+ A->render(Args, CmdArgs);
+ }
+ }
+
+ RenderExtraToolArgs(JA, CmdArgs);
+
+ // If using a driver driver, force the arch.
+ if (getToolChain().getTriple().isOSDarwin()) {
+ CmdArgs.push_back("-arch");
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().getDefaultUniversalArchName()));
+ }
+
+ // Try to force gcc to match the tool chain we want, if we recognize
+ // the arch.
+ //
+ // FIXME: The triple class should directly provide the information we want
+ // here.
+ switch (getToolChain().getArch()) {
+ default:
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::ppc:
+ CmdArgs.push_back("-m32");
+ break;
+ case llvm::Triple::x86_64:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ CmdArgs.push_back("-m64");
+ break;
+ case llvm::Triple::sparcel:
+ CmdArgs.push_back("-EL");
+ break;
+ }
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Unexpected output");
+ CmdArgs.push_back("-fsyntax-only");
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ // Only pass -x if gcc will understand it; otherwise hope gcc
+ // understands the suffix correctly. The main use case this would go
+ // wrong in is for linker inputs if they happened to have an odd
+ // suffix; really the only way to get this to happen is a command
+ // like '-x foobar a.c' which will treat a.c like a linker input.
+ //
+ // FIXME: For the linker case specifically, can we safely convert
+ // inputs into '-Wl,' options?
+ for (const auto &II : Inputs) {
+ // Don't try to pass LLVM or AST inputs to a generic gcc.
+ if (types::isLLVMIR(II.getType()))
+ D.Diag(clang::diag::err_drv_no_linker_llvm_support)
+ << getToolChain().getTripleString();
+ else if (II.getType() == types::TY_AST)
+ D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString();
+ else if (II.getType() == types::TY_ModuleFile)
+ D.Diag(diag::err_drv_no_module_support)
+ << getToolChain().getTripleString();
+
+ if (types::canTypeBeUserSpecified(II.getType())) {
+ CmdArgs.push_back("-x");
+ CmdArgs.push_back(types::getTypeName(II.getType()));
+ }
+
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else {
+ const Arg &A = II.getInputArg();
+
+ // Reverse translate some rewritten options.
+ if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) {
+ CmdArgs.push_back("-lstdc++");
+ continue;
+ }
+
+ // Don't render as input, we need gcc to do the translations.
+ A.render(Args, CmdArgs);
+ }
+ }
+
+ const std::string &customGCCName = D.getCCCGenericGCCName();
+ const char *GCCName;
+ if (!customGCCName.empty())
+ GCCName = customGCCName.c_str();
+ else if (D.CCCIsCXX()) {
+ GCCName = "g++";
+ } else
+ GCCName = "gcc";
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void tools::gcc::Preprocessor::RenderExtraToolArgs(
+ const JobAction &JA, ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-E");
+}
+
+void tools::gcc::Compiler::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getDriver();
+
+ switch (JA.getType()) {
+ // If -flto, etc. are present then make sure not to force assembly output.
+ case types::TY_LLVM_IR:
+ case types::TY_LTO_IR:
+ case types::TY_LLVM_BC:
+ case types::TY_LTO_BC:
+ CmdArgs.push_back("-c");
+ break;
+ // We assume we've got an "integrated" assembler in that gcc will produce an
+ // object file itself.
+ case types::TY_Object:
+ CmdArgs.push_back("-c");
+ break;
+ case types::TY_PP_Asm:
+ CmdArgs.push_back("-S");
+ break;
+ case types::TY_Nothing:
+ CmdArgs.push_back("-fsyntax-only");
+ break;
+ default:
+ D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType());
+ }
+}
+
+void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
+ // The types are (hopefully) good enough.
+}
+
+/// Add OpenMP linker script arguments at the end of the argument list so that
+/// the fat binary is built by embedding each of the device images into the
+/// host. The linker script also defines a few symbols required by the code
+/// generation so that the images can be easily retrieved at runtime by the
+/// offloading library. This should be used only in tool chains that support
+/// linker scripts.
+static void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args, ArgStringList &CmdArgs,
+ const JobAction &JA) {
+
+ // If this is not an OpenMP host toolchain, we don't need to do anything.
+ if (!JA.isHostOffloading(Action::OFK_OpenMP))
+ return;
+
+ // Create temporary linker script. Keep it if save-temps is enabled.
+ const char *LKS;
+ SmallString<256> Name = llvm::sys::path::filename(Output.getFilename());
+ if (C.getDriver().isSaveTempsEnabled()) {
+ llvm::sys::path::replace_extension(Name, "lk");
+ LKS = C.getArgs().MakeArgString(Name.c_str());
+ } else {
+ llvm::sys::path::replace_extension(Name, "");
+ Name = C.getDriver().GetTemporaryPath(Name, "lk");
+ LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str()));
+ }
+
+ // Add linker script option to the command.
+ CmdArgs.push_back("-T");
+ CmdArgs.push_back(LKS);
+
+ // Create a buffer to write the contents of the linker script.
+ std::string LksBuffer;
+ llvm::raw_string_ostream LksStream(LksBuffer);
+
+ // Get the OpenMP offload tool chains so that we can extract the triple
+ // associated with each device input.
+ auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>();
+ assert(OpenMPToolChains.first != OpenMPToolChains.second &&
+ "No OpenMP toolchains??");
+
+ // Track the input file name and device triple in order to build the script,
+ // inserting binaries in the designated sections.
+ SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo;
+
+ // Add commands to embed target binaries. We ensure that each section and
+ // image is 16-byte aligned. This is not mandatory, but increases the
+ // likelihood of data to be aligned with a cache block in several main host
+ // machines.
+ LksStream << "/*\n";
+ LksStream << " OpenMP Offload Linker Script\n";
+ LksStream << " *** Automatically generated by Clang ***\n";
+ LksStream << "*/\n";
+ LksStream << "TARGET(binary)\n";
+ auto DTC = OpenMPToolChains.first;
+ for (auto &II : Inputs) {
+ const Action *A = II.getAction();
+ // Is this a device linking action?
+ if (A && isa<LinkJobAction>(A) &&
+ A->isDeviceOffloading(Action::OFK_OpenMP)) {
+ assert(DTC != OpenMPToolChains.second &&
+ "More device inputs than device toolchains??");
+ InputBinaryInfo.push_back(std::make_pair(
+ DTC->second->getTriple().normalize(), II.getFilename()));
+ ++DTC;
+ LksStream << "INPUT(" << II.getFilename() << ")\n";
+ }
+ }
+
+ assert(DTC == OpenMPToolChains.second &&
+ "Less device inputs than device toolchains??");
+
+ LksStream << "SECTIONS\n";
+ LksStream << "{\n";
+
+ // Put each target binary into a separate section.
+ for (const auto &BI : InputBinaryInfo) {
+ LksStream << " .omp_offloading." << BI.first << " :\n";
+ LksStream << " ALIGN(0x10)\n";
+ LksStream << " {\n";
+ LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first
+ << " = .);\n";
+ LksStream << " " << BI.second << "\n";
+ LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first
+ << " = .);\n";
+ LksStream << " }\n";
+ }
+
+ // Add commands to define host entries begin and end. We use 1-byte subalign
+ // so that the linker does not add any padding and the elements in this
+ // section form an array.
+ LksStream << " .omp_offloading.entries :\n";
+ LksStream << " ALIGN(0x10)\n";
+ LksStream << " SUBALIGN(0x01)\n";
+ LksStream << " {\n";
+ LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n";
+ LksStream << " *(.omp_offloading.entries)\n";
+ LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n";
+ LksStream << " }\n";
+ LksStream << "}\n";
+ LksStream << "INSERT BEFORE .data\n";
+ LksStream.flush();
+
+ // Dump the contents of the linker script if the user requested that. We
+ // support this option to enable testing of behavior with -###.
+ if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script))
+ llvm::errs() << LksBuffer;
+
+ // If this is a dry run, do not create the linker script file.
+ if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
+ return;
+
+ // Open script file and write the contents.
+ std::error_code EC;
+ llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None);
+
+ if (EC) {
+ C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
+ return;
+ }
+
+ Lksf << LksBuffer;
+}
+
+static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (Args.hasFlag(options::OPT_fxray_instrument,
+ options::OPT_fnoxray_instrument, false)) {
+ CmdArgs.push_back("-whole-archive");
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false));
+ CmdArgs.push_back("-no-whole-archive");
+ return true;
+ }
+ return false;
+}
+
+static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ CmdArgs.push_back("--no-as-needed");
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-lrt");
+ CmdArgs.push_back("-lm");
+
+ if (TC.getTriple().getOS() != llvm::Triple::FreeBSD)
+ CmdArgs.push_back("-ldl");
+}
+
+static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
+ switch (T.getArch()) {
+ case llvm::Triple::x86:
+ if (T.isOSIAMCU())
+ return "elf_iamcu";
+ return "elf_i386";
+ case llvm::Triple::aarch64:
+ return "aarch64linux";
+ case llvm::Triple::aarch64_be:
+ return "aarch64_be_linux";
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ return "armelf_linux_eabi";
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ return "armelfb_linux_eabi";
+ case llvm::Triple::ppc:
+ return "elf32ppclinux";
+ case llvm::Triple::ppc64:
+ return "elf64ppc";
+ case llvm::Triple::ppc64le:
+ return "elf64lppc";
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ return "elf32_sparc";
+ case llvm::Triple::sparcv9:
+ return "elf64_sparc";
+ case llvm::Triple::mips:
+ return "elf32btsmip";
+ case llvm::Triple::mipsel:
+ return "elf32ltsmip";
+ case llvm::Triple::mips64:
+ if (tools::mips::hasMipsAbiArg(Args, "n32"))
+ return "elf32btsmipn32";
+ return "elf64btsmip";
+ case llvm::Triple::mips64el:
+ if (tools::mips::hasMipsAbiArg(Args, "n32"))
+ return "elf32ltsmipn32";
+ return "elf64ltsmip";
+ case llvm::Triple::systemz:
+ return "elf64_s390";
+ case llvm::Triple::x86_64:
+ if (T.getEnvironment() == llvm::Triple::GNUX32)
+ return "elf32_x86_64";
+ return "elf_x86_64";
+ default:
+ return nullptr;
+ }
+}
+
+void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const toolchains::Linux &ToolChain =
+ static_cast<const toolchains::Linux &>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+
+ const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
+
+ const llvm::Triple::ArchType Arch = ToolChain.getArch();
+ const bool isAndroid = ToolChain.getTriple().isAndroid();
+ const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU();
+ const bool IsPIE =
+ !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) &&
+ (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
+ const bool HasCRTBeginEndFiles =
+ ToolChain.getTriple().hasEnvironment() ||
+ (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies);
+
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ if (llvm::sys::path::stem(Exec) == "lld") {
+ CmdArgs.push_back("-flavor");
+ CmdArgs.push_back("old-gnu");
+ CmdArgs.push_back("-target");
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString()));
+ }
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (IsPIE)
+ CmdArgs.push_back("-pie");
+
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("-s");
+
+ if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb)
+ arm::appendEBLinkFlags(Args, CmdArgs, Triple);
+
+ // Most Android ARM64 targets should enable the linker fix for erratum
+ // 843419. Only non-Cortex-A53 devices are allowed to skip this flag.
+ if (Arch == llvm::Triple::aarch64 && isAndroid) {
+ std::string CPU = getCPUName(Args, Triple);
+ if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
+ CmdArgs.push_back("--fix-cortex-a53-843419");
+ }
+
+ for (const auto &Opt : ToolChain.ExtraOpts)
+ CmdArgs.push_back(Opt.c_str());
+
+ if (!Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("--eh-frame-hdr");
+ }
+
+ if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) {
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back(LDMOption);
+ } else {
+ D.Diag(diag::err_target_unknown_triple) << Triple.str();
+ return;
+ }
+
+ if (Args.hasArg(options::OPT_static)) {
+ if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb ||
+ Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb)
+ CmdArgs.push_back("-Bstatic");
+ else
+ CmdArgs.push_back("-static");
+ } else if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-shared");
+ }
+
+ if (!Args.hasArg(options::OPT_static)) {
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+
+ if (!Args.hasArg(options::OPT_shared)) {
+ const std::string Loader =
+ D.DyldPrefix + ToolChain.getDynamicLinker(Args);
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back(Args.MakeArgString(Loader));
+ }
+ }
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!isAndroid && !IsIAMCU) {
+ const char *crt1 = nullptr;
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (Args.hasArg(options::OPT_pg))
+ crt1 = "gcrt1.o";
+ else if (IsPIE)
+ crt1 = "Scrt1.o";
+ else
+ crt1 = "crt1.o";
+ }
+ if (crt1)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+ }
+
+ if (IsIAMCU)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
+ else {
+ const char *crtbegin;
+ if (Args.hasArg(options::OPT_static))
+ crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o";
+ else if (Args.hasArg(options::OPT_shared))
+ crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o";
+ else if (IsPIE)
+ crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o";
+ else
+ crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o";
+
+ if (HasCRTBeginEndFiles)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+ }
+
+ // Add crtfastmath.o if available and fast math is enabled.
+ ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_u);
+
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+ if (D.isUsingLTO())
+ AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
+
+ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+ CmdArgs.push_back("--no-demangle");
+
+ bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
+ bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+ // The profile runtime also needs access to system libraries.
+ getToolChain().addProfileRTLibs(Args, CmdArgs);
+
+ if (D.CCCIsCXX() &&
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
+ !Args.hasArg(options::OPT_static);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bstatic");
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bdynamic");
+ CmdArgs.push_back("-lm");
+ }
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+ if (!Args.hasArg(options::OPT_nostdlib)) {
+ if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--start-group");
+
+ if (NeedsSanitizerDeps)
+ linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
+
+ if (NeedsXRayDeps)
+ linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
+
+ bool WantPthread = Args.hasArg(options::OPT_pthread) ||
+ Args.hasArg(options::OPT_pthreads);
+
+ // FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
+ // require librt. Most modern Linux platforms do, but some may not.
+ if (addOpenMPRuntime(CmdArgs, ToolChain, Args,
+ JA.isHostOffloading(Action::OFK_OpenMP),
+ /* GompNeedsRT= */ true))
+ // OpenMP runtimes implies pthreads when using the GNU toolchain.
+ // FIXME: Does this really make sense for all GNU toolchains?
+ WantPthread = true;
+
+ AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
+
+ if (WantPthread && !isAndroid)
+ CmdArgs.push_back("-lpthread");
+
+ if (Args.hasArg(options::OPT_fsplit_stack))
+ CmdArgs.push_back("--wrap=pthread_create");
+
+ CmdArgs.push_back("-lc");
+
+ // Add IAMCU specific libs, if needed.
+ if (IsIAMCU)
+ CmdArgs.push_back("-lgloss");
+
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--end-group");
+ else
+ AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
+
+ // Add IAMCU specific libs (outside the group), if needed.
+ if (IsIAMCU) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lsoftfp");
+ CmdArgs.push_back("--no-as-needed");
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) {
+ const char *crtend;
+ if (Args.hasArg(options::OPT_shared))
+ crtend = isAndroid ? "crtend_so.o" : "crtendS.o";
+ else if (IsPIE)
+ crtend = isAndroid ? "crtend_android.o" : "crtendS.o";
+ else
+ crtend = isAndroid ? "crtend_android.o" : "crtend.o";
+
+ if (HasCRTBeginEndFiles)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
+ if (!isAndroid)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+ }
+ }
+
+ // Add OpenMP offloading linker script args if required.
+ AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA);
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void tools::gnutools::Assembler::ConstructJob(Compilation &C,
+ const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &D = getToolChain().getDriver();
+
+ claimNoWarnArgs(Args);
+
+ ArgStringList CmdArgs;
+
+ llvm::Reloc::Model RelocationModel;
+ unsigned PICLevel;
+ bool IsPIE;
+ std::tie(RelocationModel, PICLevel, IsPIE) =
+ ParsePICArgs(getToolChain(), Args);
+
+ if (const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ)) {
+ if (A->getOption().getID() == options::OPT_gz) {
+ CmdArgs.push_back("-compress-debug-sections");
+ } else {
+ StringRef Value = A->getValue();
+ if (Value == "none") {
+ CmdArgs.push_back("-compress-debug-sections=none");
+ } else if (Value == "zlib" || Value == "zlib-gnu") {
+ CmdArgs.push_back(
+ Args.MakeArgString("-compress-debug-sections=" + Twine(Value)));
+ } else {
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+ }
+ }
+
+ switch (getToolChain().getArch()) {
+ default:
+ break;
+ // Add --32/--64 to make sure we get the format we want.
+ // This is incomplete
+ case llvm::Triple::x86:
+ CmdArgs.push_back("--32");
+ break;
+ case llvm::Triple::x86_64:
+ if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32)
+ CmdArgs.push_back("--x32");
+ else
+ CmdArgs.push_back("--64");
+ break;
+ case llvm::Triple::ppc:
+ CmdArgs.push_back("-a32");
+ CmdArgs.push_back("-mppc");
+ CmdArgs.push_back("-many");
+ break;
+ case llvm::Triple::ppc64:
+ CmdArgs.push_back("-a64");
+ CmdArgs.push_back("-mppc64");
+ CmdArgs.push_back("-many");
+ break;
+ case llvm::Triple::ppc64le:
+ CmdArgs.push_back("-a64");
+ CmdArgs.push_back("-mppc64");
+ CmdArgs.push_back("-many");
+ CmdArgs.push_back("-mlittle-endian");
+ break;
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel: {
+ CmdArgs.push_back("-32");
+ std::string CPU = getCPUName(Args, getToolChain().getTriple());
+ CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+ case llvm::Triple::sparcv9: {
+ CmdArgs.push_back("-64");
+ std::string CPU = getCPUName(Args, getToolChain().getTriple());
+ CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb: {
+ const llvm::Triple &Triple2 = getToolChain().getTriple();
+ switch (Triple2.getSubArch()) {
+ case llvm::Triple::ARMSubArch_v7:
+ CmdArgs.push_back("-mfpu=neon");
+ break;
+ case llvm::Triple::ARMSubArch_v8:
+ CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8");
+ break;
+ default:
+ break;
+ }
+
+ switch (arm::getARMFloatABI(getToolChain(), Args)) {
+ case arm::FloatABI::Invalid: llvm_unreachable("must have an ABI!");
+ case arm::FloatABI::Soft:
+ CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=soft"));
+ break;
+ case arm::FloatABI::SoftFP:
+ CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=softfp"));
+ break;
+ case arm::FloatABI::Hard:
+ CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=hard"));
+ break;
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
+
+ // FIXME: remove krait check when GNU tools support krait cpu
+ // for now replace it with -mcpu=cortex-a15 to avoid a lower
+ // march from being picked in the absence of a cpu flag.
+ Arg *A;
+ if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) &&
+ StringRef(A->getValue()).equals_lower("krait"))
+ CmdArgs.push_back("-mcpu=cortex-a15");
+ else
+ Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
+ break;
+ }
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be: {
+ Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
+ break;
+ }
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
+ StringRef CPUName;
+ StringRef ABIName;
+ mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+ ABIName = mips::getGnuCompatibleMipsABIName(ABIName);
+
+ CmdArgs.push_back("-march");
+ CmdArgs.push_back(CPUName.data());
+
+ CmdArgs.push_back("-mabi");
+ CmdArgs.push_back(ABIName.data());
+
+ // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE,
+ // or -mshared (not implemented) is in effect.
+ if (RelocationModel == llvm::Reloc::Static)
+ CmdArgs.push_back("-mno-shared");
+
+ // LLVM doesn't support -mplt yet and acts as if it is always given.
+ // However, -mplt has no effect with the N64 ABI.
+ if (ABIName != "64" && !Args.hasArg(options::OPT_mno_abicalls))
+ CmdArgs.push_back("-call_nonpic");
+
+ if (getToolChain().getArch() == llvm::Triple::mips ||
+ getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else
+ CmdArgs.push_back("-EL");
+
+ if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
+ if (StringRef(A->getValue()) == "2008")
+ CmdArgs.push_back(Args.MakeArgString("-mnan=2008"));
+ }
+
+ // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default.
+ if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
+ options::OPT_mfp64)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ } else if (mips::shouldUseFPXX(
+ Args, getToolChain().getTriple(), CPUName, ABIName,
+ mips::getMipsFloatABI(getToolChain().getDriver(), Args)))
+ CmdArgs.push_back("-mfpxx");
+
+ // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of
+ // -mno-mips16 is actually -no-mips16.
+ if (Arg *A =
+ Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16)) {
+ if (A->getOption().matches(options::OPT_mips16)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ } else {
+ A->claim();
+ CmdArgs.push_back("-no-mips16");
+ }
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_mmicromips,
+ options::OPT_mno_micromips);
+ Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp);
+ Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2);
+
+ if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) {
+ // Do not use AddLastArg because not all versions of MIPS assembler
+ // support -mmsa / -mno-msa options.
+ if (A->getOption().matches(options::OPT_mmsa))
+ CmdArgs.push_back(Args.MakeArgString("-mmsa"));
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_mhard_float,
+ options::OPT_msoft_float);
+
+ Args.AddLastArg(CmdArgs, options::OPT_mdouble_float,
+ options::OPT_msingle_float);
+
+ Args.AddLastArg(CmdArgs, options::OPT_modd_spreg,
+ options::OPT_mno_odd_spreg);
+
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+ case llvm::Triple::systemz: {
+ // Always pass an -march option, since our default of z10 is later
+ // than the GNU assembler's default.
+ StringRef CPUName = systemz::getSystemZTargetCPU(Args);
+ CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
+ break;
+ }
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_I);
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+
+ // Handle the debug info splitting at object creation time if we're
+ // creating an object.
+ // TODO: Currently only works on linux with newer objcopy.
+ if (Args.hasArg(options::OPT_gsplit_dwarf) &&
+ getToolChain().getTriple().isOSLinux())
+ SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
+ SplitDebugName(Args, Inputs[0]));
+}
+
+namespace {
+// Filter to remove Multilibs that don't exist as a suffix to Path
+class FilterNonExistent {
+ StringRef Base, File;
+ vfs::FileSystem &VFS;
+
+public:
+ FilterNonExistent(StringRef Base, StringRef File, vfs::FileSystem &VFS)
+ : Base(Base), File(File), VFS(VFS) {}
+ bool operator()(const Multilib &M) {
+ return !VFS.exists(Base + M.gccSuffix() + File);
+ }
+};
+} // end anonymous namespace
+
+static bool isSoftFloatABI(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ);
+ if (!A)
+ return false;
+
+ return A->getOption().matches(options::OPT_msoft_float) ||
+ (A->getOption().matches(options::OPT_mfloat_abi_EQ) &&
+ 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)
+ Flags.push_back(std::string("+") + Flag);
+ else
+ Flags.push_back(std::string("-") + Flag);
+}
+
+static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb;
+}
+
+static bool isMips32(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel;
+}
+
+static bool isMips64(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el;
+}
+
+static bool isMipsEL(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el;
+}
+
+static bool isMips16(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16);
+ return A && A->getOption().matches(options::OPT_mips16);
+}
+
+static bool isMicroMips(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips);
+ return A && A->getOption().matches(options::OPT_mmicromips);
+}
+
+static Multilib makeMultilib(StringRef commonSuffix) {
+ return Multilib(commonSuffix, commonSuffix, commonSuffix);
+}
+
+static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
+ FilterNonExistent &NonExistent,
+ DetectedMultilibs &Result) {
+ // Check for Code Sourcery toolchain multilibs
+ MultilibSet CSMipsMultilibs;
+ {
+ auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16");
+
+ auto MArchMicroMips =
+ makeMultilib("/micromips").flag("+m32").flag("+mmicromips");
+
+ auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips");
+
+ auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
+
+ auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float");
+
+ auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
+
+ auto DefaultFloat =
+ makeMultilib("").flag("-msoft-float").flag("-mnan=2008");
+
+ auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
+
+ auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
+
+ // Note that this one's osSuffix is ""
+ auto MAbi64 = makeMultilib("")
+ .gccSuffix("/64")
+ .includeSuffix("/64")
+ .flag("+mabi=n64")
+ .flag("-mabi=n32")
+ .flag("-m32");
+
+ CSMipsMultilibs =
+ MultilibSet()
+ .Either(MArchMips16, MArchMicroMips, MArchDefault)
+ .Maybe(UCLibc)
+ .Either(SoftFloat, Nan2008, DefaultFloat)
+ .FilterOut("/micromips/nan2008")
+ .FilterOut("/mips16/nan2008")
+ .Either(BigEndian, LittleEndian)
+ .Maybe(MAbi64)
+ .FilterOut("/mips16.*/64")
+ .FilterOut("/micromips.*/64")
+ .FilterOut(NonExistent)
+ .setIncludeDirsCallback([](const Multilib &M) {
+ std::vector<std::string> Dirs({"/include"});
+ if (StringRef(M.includeSuffix()).startswith("/uclibc"))
+ Dirs.push_back(
+ "/../../../../mips-linux-gnu/libc/uclibc/usr/include");
+ else
+ Dirs.push_back("/../../../../mips-linux-gnu/libc/usr/include");
+ return Dirs;
+ });
+ }
+
+ MultilibSet DebianMipsMultilibs;
+ {
+ Multilib MAbiN32 =
+ Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32");
+
+ Multilib M64 = Multilib()
+ .gccSuffix("/64")
+ .includeSuffix("/64")
+ .flag("+m64")
+ .flag("-m32")
+ .flag("-mabi=n32");
+
+ Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32");
+
+ DebianMipsMultilibs =
+ MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent);
+ }
+
+ // Sort candidates. Toolchain that best meets the directories tree goes first.
+ // Then select the first toolchains matches command line flags.
+ MultilibSet *Candidates[] = {&CSMipsMultilibs, &DebianMipsMultilibs};
+ if (CSMipsMultilibs.size() < DebianMipsMultilibs.size())
+ std::iter_swap(Candidates, Candidates + 1);
+ for (const MultilibSet *Candidate : Candidates) {
+ if (Candidate->select(Flags, Result.SelectedMultilib)) {
+ if (Candidate == &DebianMipsMultilibs)
+ Result.BiarchSibling = Multilib();
+ Result.Multilibs = *Candidate;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool findMipsAndroidMultilibs(vfs::FileSystem &VFS, StringRef Path,
+ const Multilib::flags_list &Flags,
+ FilterNonExistent &NonExistent,
+ DetectedMultilibs &Result) {
+
+ MultilibSet AndroidMipsMultilibs =
+ MultilibSet()
+ .Maybe(Multilib("/mips-r2").flag("+march=mips32r2"))
+ .Maybe(Multilib("/mips-r6").flag("+march=mips32r6"))
+ .FilterOut(NonExistent);
+
+ MultilibSet AndroidMipselMultilibs =
+ MultilibSet()
+ .Either(Multilib().flag("+march=mips32"),
+ Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
+ Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
+ .FilterOut(NonExistent);
+
+ MultilibSet AndroidMips64elMultilibs =
+ MultilibSet()
+ .Either(
+ Multilib().flag("+march=mips64r6"),
+ Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"),
+ Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
+ Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
+ .FilterOut(NonExistent);
+
+ MultilibSet *MS = &AndroidMipsMultilibs;
+ if (VFS.exists(Path + "/mips-r6"))
+ MS = &AndroidMipselMultilibs;
+ else if (VFS.exists(Path + "/32"))
+ MS = &AndroidMips64elMultilibs;
+ if (MS->select(Flags, Result.SelectedMultilib)) {
+ Result.Multilibs = *MS;
+ return true;
+ }
+ return false;
+}
+
+static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags,
+ FilterNonExistent &NonExistent,
+ DetectedMultilibs &Result) {
+ // Musl toolchain multilibs
+ MultilibSet MuslMipsMultilibs;
+ {
+ auto MArchMipsR2 = makeMultilib("")
+ .osSuffix("/mips-r2-hard-musl")
+ .flag("+EB")
+ .flag("-EL")
+ .flag("+march=mips32r2");
+
+ auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl")
+ .flag("-EB")
+ .flag("+EL")
+ .flag("+march=mips32r2");
+
+ MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2);
+
+ // Specify the callback that computes the include directories.
+ MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) {
+ return std::vector<std::string>(
+ {"/../sysroot" + M.osSuffix() + "/usr/include"});
+ });
+ }
+ if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) {
+ Result.Multilibs = MuslMipsMultilibs;
+ return true;
+ }
+ return false;
+}
+
+static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
+ FilterNonExistent &NonExistent,
+ DetectedMultilibs &Result) {
+ // CodeScape MTI toolchain v1.2 and early.
+ MultilibSet MtiMipsMultilibsV1;
+ {
+ auto MArchMips32 = makeMultilib("/mips32")
+ .flag("+m32")
+ .flag("-m64")
+ .flag("-mmicromips")
+ .flag("+march=mips32");
+
+ auto MArchMicroMips = makeMultilib("/micromips")
+ .flag("+m32")
+ .flag("-m64")
+ .flag("+mmicromips");
+
+ auto MArchMips64r2 = makeMultilib("/mips64r2")
+ .flag("-m32")
+ .flag("+m64")
+ .flag("+march=mips64r2");
+
+ auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag(
+ "-march=mips64r2");
+
+ auto MArchDefault = makeMultilib("")
+ .flag("+m32")
+ .flag("-m64")
+ .flag("-mmicromips")
+ .flag("+march=mips32r2");
+
+ auto Mips16 = makeMultilib("/mips16").flag("+mips16");
+
+ auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
+
+ auto MAbi64 =
+ makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
+
+ auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
+
+ auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
+
+ auto SoftFloat = makeMultilib("/sof").flag("+msoft-float");
+
+ auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
+
+ MtiMipsMultilibsV1 =
+ MultilibSet()
+ .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64,
+ MArchDefault)
+ .Maybe(UCLibc)
+ .Maybe(Mips16)
+ .FilterOut("/mips64/mips16")
+ .FilterOut("/mips64r2/mips16")
+ .FilterOut("/micromips/mips16")
+ .Maybe(MAbi64)
+ .FilterOut("/micromips/64")
+ .FilterOut("/mips32/64")
+ .FilterOut("^/64")
+ .FilterOut("/mips16/64")
+ .Either(BigEndian, LittleEndian)
+ .Maybe(SoftFloat)
+ .Maybe(Nan2008)
+ .FilterOut(".*sof/nan2008")
+ .FilterOut(NonExistent)
+ .setIncludeDirsCallback([](const Multilib &M) {
+ std::vector<std::string> Dirs({"/include"});
+ if (StringRef(M.includeSuffix()).startswith("/uclibc"))
+ Dirs.push_back("/../../../../sysroot/uclibc/usr/include");
+ else
+ Dirs.push_back("/../../../../sysroot/usr/include");
+ return Dirs;
+ });
+ }
+
+ // CodeScape IMG toolchain starting from v1.3.
+ MultilibSet MtiMipsMultilibsV2;
+ {
+ auto BeHard = makeMultilib("/mips-r2-hard")
+ .flag("+EB")
+ .flag("-msoft-float")
+ .flag("-mnan=2008")
+ .flag("-muclibc");
+ auto BeSoft = makeMultilib("/mips-r2-soft")
+ .flag("+EB")
+ .flag("+msoft-float")
+ .flag("-mnan=2008");
+ auto ElHard = makeMultilib("/mipsel-r2-hard")
+ .flag("+EL")
+ .flag("-msoft-float")
+ .flag("-mnan=2008")
+ .flag("-muclibc");
+ auto ElSoft = makeMultilib("/mipsel-r2-soft")
+ .flag("+EL")
+ .flag("+msoft-float")
+ .flag("-mnan=2008")
+ .flag("-mmicromips");
+ auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008")
+ .flag("+EB")
+ .flag("-msoft-float")
+ .flag("+mnan=2008")
+ .flag("-muclibc");
+ auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008")
+ .flag("+EL")
+ .flag("-msoft-float")
+ .flag("+mnan=2008")
+ .flag("-muclibc")
+ .flag("-mmicromips");
+ auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc")
+ .flag("+EB")
+ .flag("-msoft-float")
+ .flag("+mnan=2008")
+ .flag("+muclibc");
+ auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc")
+ .flag("+EL")
+ .flag("-msoft-float")
+ .flag("+mnan=2008")
+ .flag("+muclibc");
+ auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc")
+ .flag("+EB")
+ .flag("-msoft-float")
+ .flag("-mnan=2008")
+ .flag("+muclibc");
+ auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc")
+ .flag("+EL")
+ .flag("-msoft-float")
+ .flag("-mnan=2008")
+ .flag("+muclibc");
+ auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008")
+ .flag("+EL")
+ .flag("-msoft-float")
+ .flag("+mnan=2008")
+ .flag("+mmicromips");
+ auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft")
+ .flag("+EL")
+ .flag("+msoft-float")
+ .flag("-mnan=2008")
+ .flag("+mmicromips");
+
+ auto O32 =
+ makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
+ auto N32 =
+ makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
+ auto N64 =
+ makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
+
+ MtiMipsMultilibsV2 =
+ MultilibSet()
+ .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan,
+ BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc,
+ ElHardUclibc, ElMicroHardNan, ElMicroSoft})
+ .Either(O32, N32, N64)
+ .FilterOut(NonExistent)
+ .setIncludeDirsCallback([](const Multilib &M) {
+ return std::vector<std::string>({"/../../../../sysroot" +
+ M.includeSuffix() +
+ "/../usr/include"});
+ })
+ .setFilePathsCallback([](const Multilib &M) {
+ return std::vector<std::string>(
+ {"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()});
+ });
+ }
+ for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) {
+ if (Candidate->select(Flags, Result.SelectedMultilib)) {
+ Result.Multilibs = *Candidate;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
+ FilterNonExistent &NonExistent,
+ DetectedMultilibs &Result) {
+ // CodeScape IMG toolchain v1.2 and early.
+ MultilibSet ImgMultilibsV1;
+ {
+ auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32");
+
+ auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
+
+ auto MAbi64 =
+ makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
+
+ ImgMultilibsV1 =
+ MultilibSet()
+ .Maybe(Mips64r6)
+ .Maybe(MAbi64)
+ .Maybe(LittleEndian)
+ .FilterOut(NonExistent)
+ .setIncludeDirsCallback([](const Multilib &M) {
+ return std::vector<std::string>(
+ {"/include", "/../../../../sysroot/usr/include"});
+ });
+ }
+
+ // CodeScape IMG toolchain starting from v1.3.
+ MultilibSet ImgMultilibsV2;
+ {
+ auto BeHard = makeMultilib("/mips-r6-hard")
+ .flag("+EB")
+ .flag("-msoft-float")
+ .flag("-mmicromips");
+ auto BeSoft = makeMultilib("/mips-r6-soft")
+ .flag("+EB")
+ .flag("+msoft-float")
+ .flag("-mmicromips");
+ auto ElHard = makeMultilib("/mipsel-r6-hard")
+ .flag("+EL")
+ .flag("-msoft-float")
+ .flag("-mmicromips");
+ auto ElSoft = makeMultilib("/mipsel-r6-soft")
+ .flag("+EL")
+ .flag("+msoft-float")
+ .flag("-mmicromips");
+ auto BeMicroHard = makeMultilib("/micromips-r6-hard")
+ .flag("+EB")
+ .flag("-msoft-float")
+ .flag("+mmicromips");
+ auto BeMicroSoft = makeMultilib("/micromips-r6-soft")
+ .flag("+EB")
+ .flag("+msoft-float")
+ .flag("+mmicromips");
+ auto ElMicroHard = makeMultilib("/micromipsel-r6-hard")
+ .flag("+EL")
+ .flag("-msoft-float")
+ .flag("+mmicromips");
+ auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft")
+ .flag("+EL")
+ .flag("+msoft-float")
+ .flag("+mmicromips");
+
+ auto O32 =
+ makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
+ auto N32 =
+ makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
+ auto N64 =
+ makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
+
+ ImgMultilibsV2 =
+ MultilibSet()
+ .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft,
+ ElMicroHard, ElMicroSoft})
+ .Either(O32, N32, N64)
+ .FilterOut(NonExistent)
+ .setIncludeDirsCallback([](const Multilib &M) {
+ return std::vector<std::string>({"/../../../../sysroot" +
+ M.includeSuffix() +
+ "/../usr/include"});
+ })
+ .setFilePathsCallback([](const Multilib &M) {
+ return std::vector<std::string>(
+ {"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()});
+ });
+ }
+ for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) {
+ if (Candidate->select(Flags, Result.SelectedMultilib)) {
+ Result.Multilibs = *Candidate;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool clang::driver::findMIPSMultilibs(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef Path, const ArgList &Args,
+ DetectedMultilibs &Result) {
+ FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
+
+ StringRef CPUName;
+ StringRef ABIName;
+ tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName);
+
+ llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
+
+ Multilib::flags_list Flags;
+ addMultilibFlag(isMips32(TargetArch), "m32", Flags);
+ addMultilibFlag(isMips64(TargetArch), "m64", Flags);
+ addMultilibFlag(isMips16(Args), "mips16", Flags);
+ addMultilibFlag(CPUName == "mips32", "march=mips32", Flags);
+ addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" ||
+ CPUName == "mips32r5" || CPUName == "p5600",
+ "march=mips32r2", Flags);
+ addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags);
+ addMultilibFlag(CPUName == "mips64", "march=mips64", Flags);
+ addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" ||
+ CPUName == "mips64r5" || CPUName == "octeon",
+ "march=mips64r2", Flags);
+ addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags);
+ addMultilibFlag(isMicroMips(Args), "mmicromips", Flags);
+ addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags);
+ addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008",
+ Flags);
+ addMultilibFlag(ABIName == "n32", "mabi=n32", Flags);
+ addMultilibFlag(ABIName == "n64", "mabi=n64", Flags);
+ addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags);
+ addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags);
+ addMultilibFlag(isMipsEL(TargetArch), "EL", Flags);
+ addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags);
+
+ if (TargetTriple.isAndroid())
+ return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent,
+ Result);
+
+ if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies &&
+ TargetTriple.getOS() == llvm::Triple::Linux &&
+ TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment)
+ return findMipsMuslMultilibs(Flags, NonExistent, Result);
+
+ if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies &&
+ TargetTriple.getOS() == llvm::Triple::Linux &&
+ TargetTriple.getEnvironment() == llvm::Triple::GNU)
+ return findMipsMtiMultilibs(Flags, NonExistent, Result);
+
+ if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies &&
+ TargetTriple.getOS() == llvm::Triple::Linux &&
+ TargetTriple.getEnvironment() == llvm::Triple::GNU)
+ return findMipsImgMultilibs(Flags, NonExistent, Result);
+
+ if (findMipsCsMultilibs(Flags, NonExistent, Result))
+ return true;
+
+ // Fallback to the regular toolchain-tree structure.
+ Multilib Default;
+ Result.Multilibs.push_back(Default);
+ Result.Multilibs.FilterOut(NonExistent);
+
+ if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) {
+ Result.BiarchSibling = Multilib();
+ return true;
+ }
+
+ return false;
+}
+
+static void findAndroidArmMultilibs(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef Path, const ArgList &Args,
+ DetectedMultilibs &Result) {
+ // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb.
+ FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
+ Multilib ArmV7Multilib = makeMultilib("/armv7-a")
+ .flag("+march=armv7-a")
+ .flag("-mthumb");
+ Multilib ThumbMultilib = makeMultilib("/thumb")
+ .flag("-march=armv7-a")
+ .flag("+mthumb");
+ Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb")
+ .flag("+march=armv7-a")
+ .flag("+mthumb");
+ Multilib DefaultMultilib = makeMultilib("")
+ .flag("-march=armv7-a")
+ .flag("-mthumb");
+ MultilibSet AndroidArmMultilibs =
+ MultilibSet()
+ .Either(ThumbMultilib, ArmV7Multilib,
+ ArmV7ThumbMultilib, DefaultMultilib)
+ .FilterOut(NonExistent);
+
+ Multilib::flags_list Flags;
+ llvm::StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ);
+ bool IsArmArch = TargetTriple.getArch() == llvm::Triple::arm;
+ bool IsThumbArch = TargetTriple.getArch() == llvm::Triple::thumb;
+ bool IsV7SubArch = TargetTriple.getSubArch() == llvm::Triple::ARMSubArch_v7;
+ bool IsThumbMode = IsThumbArch ||
+ Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, false) ||
+ (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::IK_THUMB);
+ bool IsArmV7Mode = (IsArmArch || IsThumbArch) &&
+ (llvm::ARM::parseArchVersion(Arch) == 7 ||
+ (IsArmArch && Arch == "" && IsV7SubArch));
+ addMultilibFlag(IsArmV7Mode, "march=armv7-a", Flags);
+ addMultilibFlag(IsThumbMode, "mthumb", Flags);
+
+ if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib))
+ Result.Multilibs = AndroidArmMultilibs;
+}
+
+static bool findBiarchMultilibs(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef Path, const ArgList &Args,
+ bool NeedsBiarchSuffix,
+ DetectedMultilibs &Result) {
+ // Some versions of SUSE and Fedora on ppc64 put 32-bit libs
+ // in what would normally be GCCInstallPath and put the 64-bit
+ // libs in a subdirectory named 64. The simple logic we follow is that
+ // *if* there is a subdirectory of the right name with crtbegin.o in it,
+ // we use that. If not, and if not a biarch triple alias, we look for
+ // crtbegin.o without the subdirectory.
+
+ Multilib Default;
+ Multilib Alt64 = Multilib()
+ .gccSuffix("/64")
+ .includeSuffix("/64")
+ .flag("-m32")
+ .flag("+m64")
+ .flag("-mx32");
+ Multilib Alt32 = Multilib()
+ .gccSuffix("/32")
+ .includeSuffix("/32")
+ .flag("+m32")
+ .flag("-m64")
+ .flag("-mx32");
+ Multilib Altx32 = Multilib()
+ .gccSuffix("/x32")
+ .includeSuffix("/x32")
+ .flag("-m32")
+ .flag("-m64")
+ .flag("+mx32");
+
+ // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a.
+ FilterNonExistent NonExistent(
+ Path, TargetTriple.isOSIAMCU() ? "/libgcc.a" : "/crtbegin.o", D.getVFS());
+
+ // Determine default multilib from: 32, 64, x32
+ // Also handle cases such as 64 on 32, 32 on 64, etc.
+ enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN;
+ const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32;
+ if (TargetTriple.isArch32Bit() && !NonExistent(Alt32))
+ Want = WANT64;
+ else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32))
+ Want = WANT64;
+ else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64))
+ Want = WANT32;
+ else {
+ if (TargetTriple.isArch32Bit())
+ Want = NeedsBiarchSuffix ? WANT64 : WANT32;
+ else if (IsX32)
+ Want = NeedsBiarchSuffix ? WANT64 : WANTX32;
+ else
+ Want = NeedsBiarchSuffix ? WANT32 : WANT64;
+ }
+
+ if (Want == WANT32)
+ Default.flag("+m32").flag("-m64").flag("-mx32");
+ else if (Want == WANT64)
+ Default.flag("-m32").flag("+m64").flag("-mx32");
+ else if (Want == WANTX32)
+ Default.flag("-m32").flag("-m64").flag("+mx32");
+ else
+ return false;
+
+ Result.Multilibs.push_back(Default);
+ Result.Multilibs.push_back(Alt64);
+ Result.Multilibs.push_back(Alt32);
+ Result.Multilibs.push_back(Altx32);
+
+ Result.Multilibs.FilterOut(NonExistent);
+
+ Multilib::flags_list Flags;
+ addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags);
+ addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags);
+ addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags);
+
+ if (!Result.Multilibs.select(Flags, Result.SelectedMultilib))
+ return false;
+
+ if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 ||
+ Result.SelectedMultilib == Altx32)
+ Result.BiarchSibling = Default;
+
+ return true;
+}
+
+/// Generic_GCC - A tool chain using the 'gcc' command to perform
+/// all subcommands; this relies on gcc translating the majority of
+/// command line options.
+
+/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering.
+bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,
+ int RHSPatch,
+ StringRef RHSPatchSuffix) const {
+ if (Major != RHSMajor)
+ return Major < RHSMajor;
+ if (Minor != RHSMinor)
+ return Minor < RHSMinor;
+ if (Patch != RHSPatch) {
+ // Note that versions without a specified patch sort higher than those with
+ // a patch.
+ if (RHSPatch == -1)
+ return true;
+ if (Patch == -1)
+ return false;
+
+ // Otherwise just sort on the patch itself.
+ return Patch < RHSPatch;
+ }
+ if (PatchSuffix != RHSPatchSuffix) {
+ // Sort empty suffixes higher.
+ if (RHSPatchSuffix.empty())
+ return true;
+ if (PatchSuffix.empty())
+ return false;
+
+ // Provide a lexicographic sort to make this a total ordering.
+ return PatchSuffix < RHSPatchSuffix;
+ }
+
+ // The versions are equal.
+ return false;
+}
+
+/// \brief Parse a GCCVersion object out of a string of text.
+///
+/// This is the primary means of forming GCCVersion objects.
+/*static*/
+Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) {
+ const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
+ std::pair<StringRef, StringRef> First = VersionText.split('.');
+ std::pair<StringRef, StringRef> Second = First.second.split('.');
+
+ GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
+ if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0)
+ return BadVersion;
+ GoodVersion.MajorStr = First.first.str();
+ if (First.second.empty())
+ return GoodVersion;
+ if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0)
+ return BadVersion;
+ GoodVersion.MinorStr = Second.first.str();
+
+ // First look for a number prefix and parse that if present. Otherwise just
+ // stash the entire patch string in the suffix, and leave the number
+ // unspecified. This covers versions strings such as:
+ // 5 (handled above)
+ // 4.4
+ // 4.4.0
+ // 4.4.x
+ // 4.4.2-rc4
+ // 4.4.x-patched
+ // And retains any patch number it finds.
+ StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
+ if (!PatchText.empty()) {
+ if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
+ // Try to parse the number and any suffix.
+ if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
+ GoodVersion.Patch < 0)
+ return BadVersion;
+ GoodVersion.PatchSuffix = PatchText.substr(EndNumber);
+ }
+ }
+
+ return GoodVersion;
+}
+
+static llvm::StringRef getGCCToolchainDir(const ArgList &Args) {
+ const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain);
+ if (A)
+ return A->getValue();
+ return GCC_INSTALL_PREFIX;
+}
+
+/// \brief Initialize a GCCInstallationDetector from the driver.
+///
+/// This performs all of the autodetection and sets up the various paths.
+/// Once constructed, a GCCInstallationDetector is essentially immutable.
+///
+/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and
+/// should instead pull the target out of the driver. This is currently
+/// necessary because the driver doesn't store the final version of the target
+/// triple.
+void Generic_GCC::GCCInstallationDetector::init(
+ const llvm::Triple &TargetTriple, const ArgList &Args,
+ ArrayRef<std::string> ExtraTripleAliases) {
+ llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit()
+ ? TargetTriple.get64BitArchVariant()
+ : TargetTriple.get32BitArchVariant();
+ // The library directories which may contain GCC installations.
+ SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs;
+ // The compatible GCC triples for this particular architecture.
+ SmallVector<StringRef, 16> CandidateTripleAliases;
+ SmallVector<StringRef, 16> CandidateBiarchTripleAliases;
+ CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs,
+ CandidateTripleAliases, CandidateBiarchLibDirs,
+ CandidateBiarchTripleAliases);
+
+ // Compute the set of prefixes for our search.
+ SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(),
+ D.PrefixDirs.end());
+
+ StringRef GCCToolchainDir = getGCCToolchainDir(Args);
+ if (GCCToolchainDir != "") {
+ if (GCCToolchainDir.back() == '/')
+ GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the /
+
+ Prefixes.push_back(GCCToolchainDir);
+ } else {
+ // If we have a SysRoot, try that first.
+ if (!D.SysRoot.empty()) {
+ Prefixes.push_back(D.SysRoot);
+ Prefixes.push_back(D.SysRoot + "/usr");
+ }
+
+ // Then look for gcc installed alongside clang.
+ Prefixes.push_back(D.InstalledDir + "/..");
+
+ // Then look for distribution supplied gcc installations.
+ if (D.SysRoot.empty()) {
+ // Look for RHEL devtoolsets.
+ Prefixes.push_back("/opt/rh/devtoolset-6/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-4/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-3/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-2/root/usr");
+ // And finally in /usr.
+ Prefixes.push_back("/usr");
+ }
+ }
+
+ // Try to respect gcc-config on Gentoo. However, do that only
+ // if --gcc-toolchain is not provided or equal to the Gentoo install
+ // in /usr. This avoids accidentally enforcing the system GCC version
+ // when using a custom toolchain.
+ if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") {
+ for (StringRef CandidateTriple : ExtraTripleAliases) {
+ if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple))
+ return;
+ }
+ for (StringRef CandidateTriple : CandidateTripleAliases) {
+ if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple))
+ return;
+ }
+ for (StringRef CandidateTriple : CandidateBiarchTripleAliases) {
+ if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true))
+ return;
+ }
+ }
+
+ // Loop over the various components which exist and select the best GCC
+ // installation available. GCC installs are ranked by version number.
+ Version = GCCVersion::Parse("0.0.0");
+ for (const std::string &Prefix : Prefixes) {
+ if (!D.getVFS().exists(Prefix))
+ continue;
+ for (StringRef Suffix : CandidateLibDirs) {
+ const std::string LibDir = Prefix + Suffix.str();
+ if (!D.getVFS().exists(LibDir))
+ continue;
+ for (StringRef Candidate : ExtraTripleAliases) // Try these first.
+ ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate);
+ for (StringRef Candidate : CandidateTripleAliases)
+ ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate);
+ }
+ for (StringRef Suffix : CandidateBiarchLibDirs) {
+ const std::string LibDir = Prefix + Suffix.str();
+ if (!D.getVFS().exists(LibDir))
+ continue;
+ for (StringRef Candidate : CandidateBiarchTripleAliases)
+ ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate,
+ /*NeedsBiarchSuffix=*/ true);
+ }
+ }
+}
+
+void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
+ for (const auto &InstallPath : CandidateGCCInstallPaths)
+ OS << "Found candidate GCC installation: " << InstallPath << "\n";
+
+ if (!GCCInstallPath.empty())
+ OS << "Selected GCC installation: " << GCCInstallPath << "\n";
+
+ for (const auto &Multilib : Multilibs)
+ OS << "Candidate multilib: " << Multilib << "\n";
+
+ if (Multilibs.size() != 0 || !SelectedMultilib.isDefault())
+ OS << "Selected multilib: " << SelectedMultilib << "\n";
+}
+
+bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
+ if (BiarchSibling.hasValue()) {
+ M = BiarchSibling.getValue();
+ return true;
+ }
+ return false;
+}
+
+/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
+ const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple,
+ SmallVectorImpl<StringRef> &LibDirs,
+ SmallVectorImpl<StringRef> &TripleAliases,
+ SmallVectorImpl<StringRef> &BiarchLibDirs,
+ SmallVectorImpl<StringRef> &BiarchTripleAliases) {
+ // Declare a bunch of static data sets that we'll select between below. These
+ // are specifically designed to always refer to string literals to avoid any
+ // lifetime or initialization issues.
+ static const char *const AArch64LibDirs[] = {"/lib64", "/lib"};
+ static const char *const AArch64Triples[] = {
+ "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android",
+ "aarch64-redhat-linux", "aarch64-suse-linux"};
+ static const char *const AArch64beLibDirs[] = {"/lib"};
+ static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu",
+ "aarch64_be-linux-gnu"};
+
+ static const char *const ARMLibDirs[] = {"/lib"};
+ static const char *const ARMTriples[] = {"arm-linux-gnueabi",
+ "arm-linux-androideabi"};
+ static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf",
+ "armv7hl-redhat-linux-gnueabi",
+ "armv6hl-suse-linux-gnueabi",
+ "armv7hl-suse-linux-gnueabi"};
+ static const char *const ARMebLibDirs[] = {"/lib"};
+ static const char *const ARMebTriples[] = {"armeb-linux-gnueabi",
+ "armeb-linux-androideabi"};
+ static const char *const ARMebHFTriples[] = {
+ "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"};
+
+ static const char *const X86_64LibDirs[] = {"/lib64", "/lib"};
+ static const char *const X86_64Triples[] = {
+ "x86_64-linux-gnu", "x86_64-unknown-linux-gnu",
+ "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E",
+ "x86_64-redhat-linux", "x86_64-suse-linux",
+ "x86_64-manbo-linux-gnu", "x86_64-linux-gnu",
+ "x86_64-slackware-linux", "x86_64-linux-android",
+ "x86_64-unknown-linux"};
+ static const char *const X32LibDirs[] = {"/libx32"};
+ static const char *const X86LibDirs[] = {"/lib32", "/lib"};
+ static const char *const X86Triples[] = {
+ "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu",
+ "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux",
+ "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux",
+ "i486-slackware-linux", "i686-montavista-linux", "i686-linux-android",
+ "i586-linux-gnu"};
+
+ static const char *const MIPSLibDirs[] = {"/lib"};
+ static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux",
+ "mips-mti-linux-gnu",
+ "mips-img-linux-gnu"};
+ static const char *const MIPSELLibDirs[] = {"/lib"};
+ static const char *const MIPSELTriples[] = {"mipsel-linux-gnu",
+ "mips-img-linux-gnu"};
+
+ static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"};
+ static const char *const MIPS64Triples[] = {
+ "mips64-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu",
+ "mips64-linux-gnuabi64"};
+ static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"};
+ static const char *const MIPS64ELTriples[] = {
+ "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu",
+ "mips64el-linux-gnuabi64"};
+
+ static const char *const MIPSELAndroidLibDirs[] = {"/lib", "/libr2",
+ "/libr6"};
+ static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"};
+ static const char *const MIPS64ELAndroidLibDirs[] = {"/lib64", "/lib",
+ "/libr2", "/libr6"};
+ static const char *const MIPS64ELAndroidTriples[] = {
+ "mips64el-linux-android"};
+
+ static const char *const PPCLibDirs[] = {"/lib32", "/lib"};
+ static const char *const PPCTriples[] = {
+ "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe",
+ "powerpc-suse-linux", "powerpc-montavista-linuxspe"};
+ static const char *const PPC64LibDirs[] = {"/lib64", "/lib"};
+ static const char *const PPC64Triples[] = {
+ "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu",
+ "powerpc64-suse-linux", "ppc64-redhat-linux"};
+ static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"};
+ static const char *const PPC64LETriples[] = {
+ "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu",
+ "powerpc64le-suse-linux", "ppc64le-redhat-linux"};
+
+ static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"};
+ static const char *const SPARCv8Triples[] = {"sparc-linux-gnu",
+ "sparcv8-linux-gnu"};
+ static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"};
+ static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu",
+ "sparcv9-linux-gnu"};
+
+ static const char *const SystemZLibDirs[] = {"/lib64", "/lib"};
+ static const char *const SystemZTriples[] = {
+ "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu",
+ "s390x-suse-linux", "s390x-redhat-linux"};
+
+ // Solaris.
+ static const char *const SolarisSPARCLibDirs[] = {"/gcc"};
+ static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11",
+ "i386-pc-solaris2.11"};
+
+ using std::begin;
+ using std::end;
+
+ if (TargetTriple.getOS() == llvm::Triple::Solaris) {
+ LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs));
+ TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples));
+ return;
+ }
+
+ switch (TargetTriple.getArch()) {
+ case llvm::Triple::aarch64:
+ LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
+ TripleAliases.append(begin(AArch64Triples), end(AArch64Triples));
+ BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
+ BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples));
+ break;
+ case llvm::Triple::aarch64_be:
+ LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs));
+ TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples));
+ BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs));
+ BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples));
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs));
+ if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
+ TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples));
+ } else {
+ TripleAliases.append(begin(ARMTriples), end(ARMTriples));
+ }
+ break;
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs));
+ if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
+ TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples));
+ } else {
+ TripleAliases.append(begin(ARMebTriples), end(ARMebTriples));
+ }
+ break;
+ case llvm::Triple::x86_64:
+ LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
+ TripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
+ // x32 is always available when x86_64 is available, so adding it as
+ // secondary arch with x86_64 triples
+ if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) {
+ BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs));
+ BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
+ } else {
+ BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs));
+ BiarchTripleAliases.append(begin(X86Triples), end(X86Triples));
+ }
+ break;
+ case llvm::Triple::x86:
+ LibDirs.append(begin(X86LibDirs), end(X86LibDirs));
+ // MCU toolchain is 32 bit only and its triple alias is TargetTriple
+ // itself, which will be appended below.
+ if (!TargetTriple.isOSIAMCU()) {
+ TripleAliases.append(begin(X86Triples), end(X86Triples));
+ BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
+ BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
+ }
+ break;
+ case llvm::Triple::mips:
+ LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs));
+ TripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
+ BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs));
+ BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples));
+ break;
+ case llvm::Triple::mipsel:
+ if (TargetTriple.isAndroid()) {
+ LibDirs.append(begin(MIPSELAndroidLibDirs), end(MIPSELAndroidLibDirs));
+ TripleAliases.append(begin(MIPSELAndroidTriples),
+ end(MIPSELAndroidTriples));
+ BiarchLibDirs.append(begin(MIPS64ELAndroidLibDirs),
+ end(MIPS64ELAndroidLibDirs));
+ BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples),
+ end(MIPS64ELAndroidTriples));
+
+ } else {
+ LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
+ TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples));
+ TripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
+ BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
+ BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples));
+ }
+ break;
+ case llvm::Triple::mips64:
+ LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs));
+ TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples));
+ BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs));
+ BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
+ break;
+ case llvm::Triple::mips64el:
+ if (TargetTriple.isAndroid()) {
+ LibDirs.append(begin(MIPS64ELAndroidLibDirs),
+ end(MIPS64ELAndroidLibDirs));
+ TripleAliases.append(begin(MIPS64ELAndroidTriples),
+ end(MIPS64ELAndroidTriples));
+ BiarchLibDirs.append(begin(MIPSELAndroidLibDirs),
+ end(MIPSELAndroidLibDirs));
+ BiarchTripleAliases.append(begin(MIPSELAndroidTriples),
+ end(MIPSELAndroidTriples));
+
+ } else {
+ LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
+ TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples));
+ BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
+ BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples));
+ BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
+ }
+ break;
+ case llvm::Triple::ppc:
+ LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs));
+ TripleAliases.append(begin(PPCTriples), end(PPCTriples));
+ BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs));
+ BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples));
+ break;
+ case llvm::Triple::ppc64:
+ LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs));
+ TripleAliases.append(begin(PPC64Triples), end(PPC64Triples));
+ BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs));
+ BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples));
+ break;
+ case llvm::Triple::ppc64le:
+ LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs));
+ TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples));
+ break;
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs));
+ TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples));
+ BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs));
+ BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples));
+ break;
+ case llvm::Triple::sparcv9:
+ LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs));
+ TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples));
+ BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs));
+ BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples));
+ break;
+ case llvm::Triple::systemz:
+ LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs));
+ TripleAliases.append(begin(SystemZTriples), end(SystemZTriples));
+ break;
+ default:
+ // By default, just rely on the standard lib directories and the original
+ // triple.
+ break;
+ }
+
+ // Always append the drivers target triple to the end, in case it doesn't
+ // match any of our aliases.
+ TripleAliases.push_back(TargetTriple.str());
+
+ // Also include the multiarch variant if it's different.
+ if (TargetTriple.str() != BiarchTriple.str())
+ BiarchTripleAliases.push_back(BiarchTriple.str());
+}
+
+void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris(
+ const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args,
+ const std::string &LibDir, StringRef CandidateTriple,
+ bool NeedsBiarchSuffix) {
+ // Solaris is a special case. The GCC installation is under
+ // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/, so we
+ // need to iterate twice.
+ std::error_code EC;
+ for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->getName());
+ GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
+
+ if (CandidateVersion.Major != -1) // Filter obviously bad entries.
+ if (!CandidateGCCInstallPaths.insert(LI->getName()).second)
+ continue; // Saw this path before; no need to look at it again.
+ if (CandidateVersion.isOlderThan(4, 1, 1))
+ continue;
+ if (CandidateVersion <= Version)
+ continue;
+
+ GCCInstallPath =
+ LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str();
+ if (!D.getVFS().exists(GCCInstallPath))
+ continue;
+
+ // If we make it here there has to be at least one GCC version, let's just
+ // use the latest one.
+ std::error_code EEC;
+ for (vfs::directory_iterator
+ LLI = D.getVFS().dir_begin(GCCInstallPath, EEC),
+ LLE;
+ !EEC && LLI != LLE; LLI = LLI.increment(EEC)) {
+
+ StringRef SubVersionText = llvm::sys::path::filename(LLI->getName());
+ GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText);
+
+ if (CandidateSubVersion > Version)
+ Version = CandidateSubVersion;
+ }
+
+ GCCTriple.setTriple(CandidateTriple);
+
+ GCCInstallPath += "/" + Version.Text;
+ GCCParentLibPath = GCCInstallPath + "/../../../../";
+
+ IsValid = true;
+ }
+}
+
+bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
+ const llvm::Triple &TargetTriple, const ArgList &Args,
+ StringRef Path, bool NeedsBiarchSuffix) {
+ llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
+ DetectedMultilibs Detected;
+
+ // Android standalone toolchain could have multilibs for ARM and Thumb.
+ // Debian mips multilibs behave more like the rest of the biarch ones,
+ // so handle them there
+ if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) {
+ // It should also work without multilibs in a simplified toolchain.
+ findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected);
+ } else if (tools::isMipsArch(TargetArch)) {
+ if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected))
+ return false;
+ } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args,
+ NeedsBiarchSuffix, Detected)) {
+ return false;
+ }
+
+ Multilibs = Detected.Multilibs;
+ SelectedMultilib = Detected.SelectedMultilib;
+ BiarchSibling = Detected.BiarchSibling;
+
+ return true;
+}
+
+void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
+ const llvm::Triple &TargetTriple, const ArgList &Args,
+ const std::string &LibDir, StringRef CandidateTriple,
+ bool NeedsBiarchSuffix) {
+ if (TargetTriple.getOS() == llvm::Triple::Solaris) {
+ scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple,
+ NeedsBiarchSuffix);
+ return;
+ }
+
+ llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
+ // Locations relative to the system lib directory where GCC's triple-specific
+ // directories might reside.
+ struct GCCLibSuffix {
+ // Path from system lib directory to GCC triple-specific directory.
+ std::string LibSuffix;
+ // Path from GCC triple-specific directory back to system lib directory.
+ // This is one '..' component per component in LibSuffix.
+ StringRef ReversePath;
+ // Whether this library suffix is relevant for the triple.
+ bool Active;
+ } Suffixes[] = {
+ // This is the normal place.
+ {"gcc/" + CandidateTriple.str(), "../..", true},
+
+ // Debian puts cross-compilers in gcc-cross.
+ {"gcc-cross/" + CandidateTriple.str(), "../..", true},
+
+ // The Freescale PPC SDK has the gcc libraries in
+ // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do
+ // this on Freescale triples, though, since some systems put a *lot* of
+ // files in that location, not just GCC installation data.
+ {CandidateTriple.str(), "..",
+ TargetTriple.getVendor() == llvm::Triple::Freescale},
+
+ // Natively multiarch systems sometimes put the GCC triple-specific
+ // directory within their multiarch lib directory, resulting in the
+ // triple appearing twice.
+ {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", true},
+
+ // Deal with cases (on Ubuntu) where the system architecture could be i386
+ // but the GCC target architecture could be (say) i686.
+ // FIXME: It may be worthwhile to generalize this and look for a second
+ // triple.
+ {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..",
+ TargetArch == llvm::Triple::x86}
+ };
+
+ for (auto &Suffix : Suffixes) {
+ if (!Suffix.Active)
+ continue;
+
+ StringRef LibSuffix = Suffix.LibSuffix;
+ std::error_code EC;
+ for (vfs::directory_iterator
+ LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC),
+ LE;
+ !EC && LI != LE; LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->getName());
+ GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
+ if (CandidateVersion.Major != -1) // Filter obviously bad entries.
+ if (!CandidateGCCInstallPaths.insert(LI->getName()).second)
+ continue; // Saw this path before; no need to look at it again.
+ if (CandidateVersion.isOlderThan(4, 1, 1))
+ continue;
+ if (CandidateVersion <= Version)
+ continue;
+
+ if (!ScanGCCForMultilibs(TargetTriple, Args, LI->getName(),
+ NeedsBiarchSuffix))
+ continue;
+
+ Version = CandidateVersion;
+ GCCTriple.setTriple(CandidateTriple);
+ // FIXME: We hack together the directory name here instead of
+ // using LI to ensure stable path separators across Windows and
+ // Linux.
+ GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str();
+ GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str();
+ IsValid = true;
+ }
+ }
+}
+
+bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
+ const llvm::Triple &TargetTriple, const ArgList &Args,
+ StringRef CandidateTriple, bool NeedsBiarchSuffix) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+ D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" +
+ CandidateTriple.str());
+ if (File) {
+ SmallVector<StringRef, 2> Lines;
+ File.get()->getBuffer().split(Lines, "\n");
+ for (StringRef Line : Lines) {
+ Line = Line.trim();
+ // CURRENT=triple-version
+ if (Line.consume_front("CURRENT=")) {
+ const std::pair<StringRef, StringRef> ActiveVersion =
+ Line.rsplit('-');
+ // Note: Strictly speaking, we should be reading
+ // /etc/env.d/gcc/${CURRENT} now. However, the file doesn't
+ // contain anything new or especially useful to us.
+ const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" +
+ ActiveVersion.first.str() + "/" +
+ ActiveVersion.second.str();
+ if (D.getVFS().exists(GentooPath + "/crtbegin.o")) {
+ if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath,
+ NeedsBiarchSuffix))
+ return false;
+
+ Version = GCCVersion::Parse(ActiveVersion.second);
+ GCCInstallPath = GentooPath;
+ GCCParentLibPath = GentooPath + "/../../..";
+ GCCTriple.setTriple(ActiveVersion.first);
+ IsValid = true;
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args), GCCInstallation(D),
+ CudaInstallation(D, Triple, Args) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+}
+
+Generic_GCC::~Generic_GCC() {}
+
+Tool *Generic_GCC::getTool(Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::PreprocessJobClass:
+ if (!Preprocess)
+ Preprocess.reset(new clang::driver::tools::gcc::Preprocessor(*this));
+ return Preprocess.get();
+ case Action::CompileJobClass:
+ if (!Compile)
+ Compile.reset(new tools::gcc::Compiler(*this));
+ return Compile.get();
+ default:
+ return ToolChain::getTool(AC);
+ }
+}
+
+Tool *Generic_GCC::buildAssembler() const {
+ return new tools::gnutools::Assembler(*this);
+}
+
+Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); }
+
+void Generic_GCC::printVerboseInfo(raw_ostream &OS) const {
+ // Print the information about how we detected the GCC installation.
+ GCCInstallation.print(OS);
+ CudaInstallation.print(OS);
+}
+
+bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool Generic_GCC::isPICDefault() const {
+ switch (getArch()) {
+ case llvm::Triple::x86_64:
+ return getTriple().isOSWindows();
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX();
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Generic_GCC::isPIEDefault() const { return false; }
+
+bool Generic_GCC::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows();
+}
+
+bool Generic_GCC::IsIntegratedAssemblerDefault() const {
+ switch (getTriple().getArch()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::avr:
+ case llvm::Triple::bpfel:
+ case llvm::Triple::bpfeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::systemz:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return true;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ // Enabled for Debian and Android mips64/mipsel, as they can precisely
+ // identify the ABI in use (Debian) or only use N64 for MIPS64 (Android).
+ // Other targets are unable to distinguish N32 from N64.
+ if (getTriple().getEnvironment() == llvm::Triple::GNUABI64 ||
+ getTriple().isAndroid())
+ return true;
+ return false;
+ default:
+ return false;
+ }
+}
+
+void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx: {
+ std::string Path = findLibCxxIncludePath();
+ if (!Path.empty())
+ addSystemInclude(DriverArgs, CC1Args, Path);
+ break;
+ }
+
+ case ToolChain::CST_Libstdcxx:
+ addLibStdCxxIncludePaths(DriverArgs, CC1Args);
+ break;
+ }
+}
+
+std::string Generic_GCC::findLibCxxIncludePath() const {
+ // FIXME: The Linux behavior would probaby be a better approach here.
+ return getDriver().SysRoot + "/usr/include/c++/v1";
+}
+
+void
+Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ // By default, we don't assume we know where libstdc++ might be installed.
+ // FIXME: If we have a valid GCCInstallation, use it.
+}
+
+/// \brief Helper to add the variant paths of a libstdc++ installation.
+bool Generic_GCC::addLibStdCXXIncludePaths(
+ Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple,
+ StringRef TargetMultiarchTriple, Twine IncludeSuffix,
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (!getVFS().exists(Base + Suffix))
+ return false;
+
+ addSystemInclude(DriverArgs, CC1Args, Base + Suffix);
+
+ // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If
+ // that path exists or we have neither a GCC nor target multiarch triple, use
+ // this vanilla search path.
+ if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) ||
+ getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) {
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + Suffix + "/" + GCCTriple + IncludeSuffix);
+ } else {
+ // Otherwise try to use multiarch naming schemes which have normalized the
+ // triples and put the triple before the suffix.
+ //
+ // GCC surprisingly uses *both* the GCC triple with a multilib suffix and
+ // the target triple, so we support that here.
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix);
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + "/" + TargetMultiarchTriple + Suffix);
+ }
+
+ addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward");
+ return true;
+}
+
+llvm::opt::DerivedArgList *
+Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef,
+ Action::OffloadKind DeviceOffloadKind) const {
+
+ // If this tool chain is used for an OpenMP offloading device we have to make
+ // sure we always generate a shared library regardless of the commands the
+ // user passed to the host. This is required because the runtime library
+ // is required to load the device image dynamically at run time.
+ if (DeviceOffloadKind == Action::OFK_OpenMP) {
+ DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
+ const OptTable &Opts = getDriver().getOpts();
+
+ // Request the shared library. Given that these options are decided
+ // implicitly, they do not refer to any base argument.
+ DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_shared));
+ DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_fPIC));
+
+ // Filter all the arguments we don't care passing to the offloading
+ // toolchain as they can mess up with the creation of a shared library.
+ for (auto *A : Args) {
+ switch ((options::ID)A->getOption().getID()) {
+ default:
+ DAL->append(A);
+ break;
+ case options::OPT_shared:
+ case options::OPT_dynamic:
+ case options::OPT_static:
+ case options::OPT_fPIC:
+ case options::OPT_fno_PIC:
+ case options::OPT_fpic:
+ case options::OPT_fno_pic:
+ case options::OPT_fPIE:
+ case options::OPT_fno_PIE:
+ case options::OPT_fpie:
+ case options::OPT_fno_pie:
+ break;
+ }
+ }
+ return DAL;
+ }
+ return nullptr;
+}
+
+void Generic_ELF::anchor() {}
+
+void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion();
+ bool UseInitArrayDefault =
+ getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::aarch64_be ||
+ (getTriple().getOS() == llvm::Triple::Linux &&
+ (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) ||
+ getTriple().getOS() == llvm::Triple::NaCl ||
+ (getTriple().getVendor() == llvm::Triple::MipsTechnologies &&
+ !getTriple().hasEnvironment()) ||
+ getTriple().getOS() == llvm::Triple::Solaris;
+
+ if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array, UseInitArrayDefault))
+ CC1Args.push_back("-fuse-init-array");
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.h
new file mode 100644
index 0000000..f29342b
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.h
@@ -0,0 +1,352 @@
+//===--- Gnu.h - Gnu Tool and ToolChain Implementations ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H
+
+#include "Cuda.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+#include <set>
+
+namespace clang {
+namespace driver {
+
+struct DetectedMultilibs {
+ /// The set of multilibs that the detected installation supports.
+ MultilibSet Multilibs;
+
+ /// The primary multilib appropriate for the given flags.
+ Multilib SelectedMultilib;
+
+ /// On Biarch systems, this corresponds to the default multilib when
+ /// targeting the non-default multilib. Otherwise, it is empty.
+ llvm::Optional<Multilib> BiarchSibling;
+};
+
+bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
+ StringRef Path, const llvm::opt::ArgList &Args,
+ DetectedMultilibs &Result);
+
+namespace tools {
+
+/// \brief Base class for all GNU tools that provide the same behavior when
+/// it comes to response files support
+class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool {
+ virtual void anchor();
+
+public:
+ GnuTool(const char *Name, const char *ShortName, const ToolChain &TC)
+ : Tool(Name, ShortName, TC, RF_Full, llvm::sys::WEM_CurrentCodePage) {}
+};
+
+/// Directly call GNU Binutils' assembler and linker.
+namespace gnutools {
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
+public:
+ Assembler(const ToolChain &TC) : GnuTool("GNU::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("GNU::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace gnutools
+
+/// gcc - Generic GCC tool implementations.
+namespace gcc {
+class LLVM_LIBRARY_VISIBILITY Common : public GnuTool {
+public:
+ Common(const char *Name, const char *ShortName, const ToolChain &TC)
+ : GnuTool(Name, ShortName, TC) {}
+
+ // A gcc tool has an "integrated" assembler that it will call to produce an
+ // object. Let it use that assembler so that we don't have to deal with
+ // assembly syntax incompatibilities.
+ bool hasIntegratedAssembler() const override { return true; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+
+ /// RenderExtraToolArgs - Render any arguments necessary to force
+ /// the particular tool mode.
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const = 0;
+};
+
+class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common {
+public:
+ Preprocessor(const ToolChain &TC)
+ : Common("gcc::Preprocessor", "gcc preprocessor", TC) {}
+
+ bool hasGoodDiagnostics() const override { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+
+ void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Compiler : public Common {
+public:
+ Compiler(const ToolChain &TC) : Common("gcc::Compiler", "gcc frontend", TC) {}
+
+ bool hasGoodDiagnostics() const override { return true; }
+ bool hasIntegratedCPP() const override { return true; }
+
+ void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Common {
+public:
+ Linker(const ToolChain &TC) : Common("gcc::Linker", "linker (via gcc)", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+};
+} // end namespace gcc
+} // end namespace tools
+
+namespace toolchains {
+
+/// Generic_GCC - A tool chain using the 'gcc' command to perform
+/// all subcommands; this relies on gcc translating the majority of
+/// command line options.
+class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain {
+public:
+ /// \brief Struct to store and manipulate GCC versions.
+ ///
+ /// We rely on assumptions about the form and structure of GCC version
+ /// numbers: they consist of at most three '.'-separated components, and each
+ /// component is a non-negative integer except for the last component. For
+ /// the last component we are very flexible in order to tolerate release
+ /// candidates or 'x' wildcards.
+ ///
+ /// Note that the ordering established among GCCVersions is based on the
+ /// preferred version string to use. For example we prefer versions without
+ /// a hard-coded patch number to those with a hard coded patch number.
+ ///
+ /// Currently this doesn't provide any logic for textual suffixes to patches
+ /// in the way that (for example) Debian's version format does. If that ever
+ /// becomes necessary, it can be added.
+ struct GCCVersion {
+ /// \brief The unparsed text of the version.
+ std::string Text;
+
+ /// \brief The parsed major, minor, and patch numbers.
+ int Major, Minor, Patch;
+
+ /// \brief The text of the parsed major, and major+minor versions.
+ std::string MajorStr, MinorStr;
+
+ /// \brief Any textual suffix on the patch number.
+ std::string PatchSuffix;
+
+ static GCCVersion Parse(StringRef VersionText);
+ bool isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch,
+ StringRef RHSPatchSuffix = StringRef()) const;
+ bool operator<(const GCCVersion &RHS) const {
+ return isOlderThan(RHS.Major, RHS.Minor, RHS.Patch, RHS.PatchSuffix);
+ }
+ bool operator>(const GCCVersion &RHS) const { return RHS < *this; }
+ bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); }
+ bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
+ };
+
+ /// \brief This is a class to find a viable GCC installation for Clang to
+ /// use.
+ ///
+ /// This class tries to find a GCC installation on the system, and report
+ /// information about it. It starts from the host information provided to the
+ /// Driver, and has logic for fuzzing that where appropriate.
+ class GCCInstallationDetector {
+ bool IsValid;
+ llvm::Triple GCCTriple;
+ const Driver &D;
+
+ // FIXME: These might be better as path objects.
+ std::string GCCInstallPath;
+ std::string GCCParentLibPath;
+
+ /// The primary multilib appropriate for the given flags.
+ Multilib SelectedMultilib;
+ /// On Biarch systems, this corresponds to the default multilib when
+ /// targeting the non-default multilib. Otherwise, it is empty.
+ llvm::Optional<Multilib> BiarchSibling;
+
+ GCCVersion Version;
+
+ // We retain the list of install paths that were considered and rejected in
+ // order to print out detailed information in verbose mode.
+ std::set<std::string> CandidateGCCInstallPaths;
+
+ /// The set of multilibs that the detected installation supports.
+ MultilibSet Multilibs;
+
+ public:
+ explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
+ void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args,
+ ArrayRef<std::string> ExtraTripleAliases = None);
+
+ /// \brief Check whether we detected a valid GCC install.
+ bool isValid() const { return IsValid; }
+
+ /// \brief Get the GCC triple for the detected install.
+ const llvm::Triple &getTriple() const { return GCCTriple; }
+
+ /// \brief Get the detected GCC installation path.
+ StringRef getInstallPath() const { return GCCInstallPath; }
+
+ /// \brief Get the detected GCC parent lib path.
+ StringRef getParentLibPath() const { return GCCParentLibPath; }
+
+ /// \brief Get the detected Multilib
+ const Multilib &getMultilib() const { return SelectedMultilib; }
+
+ /// \brief Get the whole MultilibSet
+ const MultilibSet &getMultilibs() const { return Multilibs; }
+
+ /// Get the biarch sibling multilib (if it exists).
+ /// \return true iff such a sibling exists
+ bool getBiarchSibling(Multilib &M) const;
+
+ /// \brief Get the detected GCC version string.
+ const GCCVersion &getVersion() const { return Version; }
+
+ /// \brief Print information about the detected GCC installation.
+ void print(raw_ostream &OS) const;
+
+ private:
+ static void
+ CollectLibDirsAndTriples(const llvm::Triple &TargetTriple,
+ const llvm::Triple &BiarchTriple,
+ SmallVectorImpl<StringRef> &LibDirs,
+ SmallVectorImpl<StringRef> &TripleAliases,
+ SmallVectorImpl<StringRef> &BiarchLibDirs,
+ SmallVectorImpl<StringRef> &BiarchTripleAliases);
+
+ bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple,
+ const llvm::opt::ArgList &Args,
+ StringRef Path,
+ bool NeedsBiarchSuffix = false);
+
+ void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch,
+ const llvm::opt::ArgList &Args,
+ const std::string &LibDir,
+ StringRef CandidateTriple,
+ bool NeedsBiarchSuffix = false);
+
+ void scanLibDirForGCCTripleSolaris(const llvm::Triple &TargetArch,
+ const llvm::opt::ArgList &Args,
+ const std::string &LibDir,
+ StringRef CandidateTriple,
+ bool NeedsBiarchSuffix = false);
+
+ bool ScanGentooGccConfig(const llvm::Triple &TargetTriple,
+ const llvm::opt::ArgList &Args,
+ StringRef CandidateTriple,
+ bool NeedsBiarchSuffix = false);
+ };
+
+protected:
+ GCCInstallationDetector GCCInstallation;
+ CudaInstallationDetector CudaInstallation;
+
+public:
+ Generic_GCC(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~Generic_GCC() override;
+
+ void printVerboseInfo(raw_ostream &OS) const override;
+
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+ bool IsIntegratedAssemblerDefault() const override;
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
+protected:
+ Tool *getTool(Action::ActionClass AC) const override;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+
+ /// \name ToolChain Implementation Helper Functions
+ /// @{
+
+ /// \brief Check whether the target triple's architecture is 64-bits.
+ bool isTarget64Bit() const { return getTriple().isArch64Bit(); }
+
+ /// \brief Check whether the target triple's architecture is 32-bits.
+ bool isTarget32Bit() const { return getTriple().isArch32Bit(); }
+
+ // FIXME: This should be final, but the Solaris tool chain does weird
+ // things we can't easily represent.
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ virtual std::string findLibCxxIncludePath() const;
+ virtual void
+ addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+
+ bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple,
+ StringRef GCCMultiarchTriple,
+ StringRef TargetMultiarchTriple,
+ Twine IncludeSuffix,
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+
+ /// @}
+
+private:
+ mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocess;
+ mutable std::unique_ptr<tools::gcc::Compiler> Compile;
+};
+
+class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
+ virtual void anchor();
+
+public:
+ Generic_ELF(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : Generic_GCC(D, Triple, Args) {}
+
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Haiku.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Haiku.cpp
new file mode 100644
index 0000000..284d269
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Haiku.cpp
@@ -0,0 +1,33 @@
+//===--- Haiku.cpp - Haiku ToolChain Implementations ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Haiku.h"
+#include "CommonArgs.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+/// Haiku - Haiku tool chain which can call as(1) and ld(1) directly.
+
+Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+
+}
+
+std::string Haiku::findLibCxxIncludePath() const {
+ return getDriver().SysRoot + "/system/develop/headers/c++/v1";
+}
+
+void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ addLibStdCXXIncludePaths(getDriver().SysRoot, "/system/develop/headers/c++",
+ getTriple().str(), "", "", "", DriverArgs, CC1Args);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Haiku.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Haiku.h
new file mode 100644
index 0000000..8b5b48e
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Haiku.h
@@ -0,0 +1,40 @@
+//===--- Haiku.h - Haiku ToolChain Implementations --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HAIKU_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HAIKU_H
+
+#include "Gnu.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF {
+public:
+ Haiku(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool isPIEDefault() const override {
+ return getTriple().getArch() == llvm::Triple::x86_64;
+ }
+
+ std::string findLibCxxIncludePath() const override;
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HAIKU_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.cpp
new file mode 100644
index 0000000..9bf1590
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -0,0 +1,492 @@
+//===--- Hexagon.cpp - Hexagon ToolChain Implementations --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Hexagon.h"
+#include "InputInfo.h"
+#include "CommonArgs.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+// Hexagon tools start.
+void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
+}
+
+void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+
+ auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
+ const Driver &D = HTC.getDriver();
+ ArgStringList CmdArgs;
+
+ std::string MArchString = "-march=hexagon";
+ CmdArgs.push_back(Args.MakeArgString(MArchString));
+
+ RenderExtraToolArgs(JA, CmdArgs);
+
+ std::string AsName = "hexagon-llvm-mc";
+ std::string MCpuString = "-mcpu=hexagon" +
+ toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
+ CmdArgs.push_back("-filetype=obj");
+ CmdArgs.push_back(Args.MakeArgString(MCpuString));
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Unexpected output");
+ CmdArgs.push_back("-fsyntax-only");
+ }
+
+ if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
+ std::string N = llvm::utostr(G.getValue());
+ CmdArgs.push_back(Args.MakeArgString(std::string("-gpsize=") + N));
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ // Only pass -x if gcc will understand it; otherwise hope gcc
+ // understands the suffix correctly. The main use case this would go
+ // wrong in is for linker inputs if they happened to have an odd
+ // suffix; really the only way to get this to happen is a command
+ // like '-x foobar a.c' which will treat a.c like a linker input.
+ //
+ // FIXME: For the linker case specifically, can we safely convert
+ // inputs into '-Wl,' options?
+ for (const auto &II : Inputs) {
+ // Don't try to pass LLVM or AST inputs to a generic gcc.
+ if (types::isLLVMIR(II.getType()))
+ D.Diag(clang::diag::err_drv_no_linker_llvm_support)
+ << HTC.getTripleString();
+ else if (II.getType() == types::TY_AST)
+ D.Diag(clang::diag::err_drv_no_ast_support)
+ << HTC.getTripleString();
+ else if (II.getType() == types::TY_ModuleFile)
+ D.Diag(diag::err_drv_no_module_support)
+ << HTC.getTripleString();
+
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ // Don't render as input, we need gcc to do the translations.
+ // FIXME: What is this?
+ II.getInputArg().render(Args, CmdArgs);
+ }
+
+ auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str()));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
+ ArgStringList &CmdArgs) const {
+}
+
+static void
+constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
+ const toolchains::HexagonToolChain &HTC,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const ArgList &Args, ArgStringList &CmdArgs,
+ const char *LinkingOutput) {
+
+ const Driver &D = HTC.getDriver();
+
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ bool IsStatic = Args.hasArg(options::OPT_static);
+ bool IsShared = Args.hasArg(options::OPT_shared);
+ bool IsPIE = Args.hasArg(options::OPT_pie);
+ bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
+ bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
+ bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
+ bool UseG0 = false;
+ bool UseShared = IsShared && !IsStatic;
+
+ //----------------------------------------------------------------------------
+ // Silence warnings for various options
+ //----------------------------------------------------------------------------
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_static_libgcc);
+
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("-s");
+
+ if (Args.hasArg(options::OPT_r))
+ CmdArgs.push_back("-r");
+
+ for (const auto &Opt : HTC.ExtraOpts)
+ CmdArgs.push_back(Opt.c_str());
+
+ CmdArgs.push_back("-march=hexagon");
+ std::string CpuVer =
+ toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
+ std::string MCpuString = "-mcpu=hexagon" + CpuVer;
+ CmdArgs.push_back(Args.MakeArgString(MCpuString));
+
+ if (IsShared) {
+ CmdArgs.push_back("-shared");
+ // The following should be the default, but doing as hexagon-gcc does.
+ CmdArgs.push_back("-call_shared");
+ }
+
+ if (IsStatic)
+ CmdArgs.push_back("-static");
+
+ if (IsPIE && !IsShared)
+ CmdArgs.push_back("-pie");
+
+ if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
+ std::string N = llvm::utostr(G.getValue());
+ CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N));
+ UseG0 = G.getValue() == 0;
+ }
+
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ //----------------------------------------------------------------------------
+ // moslib
+ //----------------------------------------------------------------------------
+ std::vector<std::string> OsLibs;
+ bool HasStandalone = false;
+
+ for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
+ A->claim();
+ OsLibs.emplace_back(A->getValue());
+ HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
+ }
+ if (OsLibs.empty()) {
+ OsLibs.push_back("standalone");
+ HasStandalone = true;
+ }
+
+ //----------------------------------------------------------------------------
+ // Start Files
+ //----------------------------------------------------------------------------
+ const std::string MCpuSuffix = "/" + CpuVer;
+ const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
+ const std::string RootDir =
+ HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
+ const std::string StartSubDir =
+ "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
+
+ auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
+ const char *Name) -> std::string {
+ std::string RelName = SubDir + Name;
+ std::string P = HTC.GetFilePath(RelName.c_str());
+ if (llvm::sys::fs::exists(P))
+ return P;
+ return RootDir + RelName;
+ };
+
+ if (IncStdLib && IncStartFiles) {
+ if (!IsShared) {
+ if (HasStandalone) {
+ std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
+ CmdArgs.push_back(Args.MakeArgString(Crt0SA));
+ }
+ std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
+ CmdArgs.push_back(Args.MakeArgString(Crt0));
+ }
+ std::string Init = UseShared
+ ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
+ : Find(RootDir, StartSubDir, "/init.o");
+ CmdArgs.push_back(Args.MakeArgString(Init));
+ }
+
+ //----------------------------------------------------------------------------
+ // Library Search Paths
+ //----------------------------------------------------------------------------
+ const ToolChain::path_list &LibPaths = HTC.getFilePaths();
+ for (const auto &LibPath : LibPaths)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
+
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ Args.AddAllArgs(CmdArgs,
+ {options::OPT_T_Group, options::OPT_e, options::OPT_s,
+ options::OPT_t, options::OPT_u_Group});
+
+ AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
+
+ //----------------------------------------------------------------------------
+ // Libraries
+ //----------------------------------------------------------------------------
+ if (IncStdLib && IncDefLibs) {
+ if (D.CCCIsCXX()) {
+ HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
+
+ CmdArgs.push_back("--start-group");
+
+ if (!IsShared) {
+ for (const std::string &Lib : OsLibs)
+ CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
+ CmdArgs.push_back("-lc");
+ }
+ CmdArgs.push_back("-lgcc");
+
+ CmdArgs.push_back("--end-group");
+ }
+
+ //----------------------------------------------------------------------------
+ // End files
+ //----------------------------------------------------------------------------
+ if (IncStdLib && IncStartFiles) {
+ std::string Fini = UseShared
+ ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
+ : Find(RootDir, StartSubDir, "/fini.o");
+ CmdArgs.push_back(Args.MakeArgString(Fini));
+ }
+}
+
+void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
+
+ ArgStringList CmdArgs;
+ constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
+ LinkingOutput);
+
+ std::string Linker = HTC.GetProgramPath("hexagon-link");
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
+ CmdArgs, Inputs));
+}
+// Hexagon tools end.
+
+/// Hexagon Toolchain
+
+std::string HexagonToolChain::getHexagonTargetDir(
+ const std::string &InstalledDir,
+ const SmallVectorImpl<std::string> &PrefixDirs) const {
+ std::string InstallRelDir;
+ const Driver &D = getDriver();
+
+ // Locate the rest of the toolchain ...
+ for (auto &I : PrefixDirs)
+ if (D.getVFS().exists(I))
+ return I;
+
+ if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
+ return InstallRelDir;
+
+ return InstalledDir;
+}
+
+Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
+ const ArgList &Args) {
+ StringRef Gn = "";
+ if (Arg *A = Args.getLastArg(options::OPT_G)) {
+ Gn = A->getValue();
+ } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
+ options::OPT_fPIC)) {
+ Gn = "0";
+ }
+
+ unsigned G;
+ if (!Gn.getAsInteger(10, G))
+ return G;
+
+ return None;
+}
+
+void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
+ ToolChain::path_list &LibPaths) const {
+ const Driver &D = getDriver();
+
+ //----------------------------------------------------------------------------
+ // -L Args
+ //----------------------------------------------------------------------------
+ for (Arg *A : Args.filtered(options::OPT_L))
+ for (const char *Value : A->getValues())
+ LibPaths.push_back(Value);
+
+ //----------------------------------------------------------------------------
+ // Other standard paths
+ //----------------------------------------------------------------------------
+ std::vector<std::string> RootDirs;
+ std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
+ std::back_inserter(RootDirs));
+
+ std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
+ D.PrefixDirs);
+ if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end())
+ RootDirs.push_back(TargetDir);
+
+ bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
+ // Assume G0 with -shared.
+ bool HasG0 = Args.hasArg(options::OPT_shared);
+ if (auto G = getSmallDataThreshold(Args))
+ HasG0 = G.getValue() == 0;
+
+ const std::string CpuVer = GetTargetCPUVersion(Args).str();
+ for (auto &Dir : RootDirs) {
+ std::string LibDir = Dir + "/hexagon/lib";
+ std::string LibDirCpu = LibDir + '/' + CpuVer;
+ if (HasG0) {
+ if (HasPIC)
+ LibPaths.push_back(LibDirCpu + "/G0/pic");
+ LibPaths.push_back(LibDirCpu + "/G0");
+ }
+ LibPaths.push_back(LibDirCpu);
+ LibPaths.push_back(LibDir);
+ }
+}
+
+HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : Linux(D, Triple, Args) {
+ const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
+ D.PrefixDirs);
+
+ // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
+ // program paths
+ const std::string BinDir(TargetDir + "/bin");
+ if (D.getVFS().exists(BinDir))
+ getProgramPaths().push_back(BinDir);
+
+ ToolChain::path_list &LibPaths = getFilePaths();
+
+ // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
+ // 'elf' OS type, so the Linux paths are not appropriate. When we actually
+ // support 'linux' we'll need to fix this up
+ LibPaths.clear();
+ getHexagonLibraryPaths(Args, LibPaths);
+}
+
+HexagonToolChain::~HexagonToolChain() {}
+
+Tool *HexagonToolChain::buildAssembler() const {
+ return new tools::hexagon::Assembler(*this);
+}
+
+Tool *HexagonToolChain::buildLinker() const {
+ return new tools::hexagon::Linker(*this);
+}
+
+unsigned HexagonToolChain::getOptimizationLevel(
+ const llvm::opt::ArgList &DriverArgs) const {
+ // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
+ Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
+ if (!A)
+ return 0;
+
+ if (A->getOption().matches(options::OPT_O0))
+ return 0;
+ if (A->getOption().matches(options::OPT_Ofast) ||
+ A->getOption().matches(options::OPT_O4))
+ return 3;
+ assert(A->getNumValues() != 0);
+ StringRef S(A->getValue());
+ if (S == "s" || S == "z" || S.empty())
+ return 2;
+ if (S == "g")
+ return 1;
+
+ unsigned OptLevel;
+ if (S.getAsInteger(10, OptLevel))
+ return 0;
+ return OptLevel;
+}
+
+void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ if (DriverArgs.hasArg(options::OPT_ffp_contract))
+ return;
+ unsigned OptLevel = getOptimizationLevel(DriverArgs);
+ if (OptLevel >= 3)
+ CC1Args.push_back("-ffp-contract=fast");
+}
+
+void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ const Driver &D = getDriver();
+ std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
+ D.PrefixDirs);
+ addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
+}
+
+
+void HexagonToolChain::addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
+ addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "",
+ DriverArgs, CC1Args);
+}
+
+ToolChain::CXXStdlibType
+HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
+ Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
+ if (!A)
+ return ToolChain::CST_Libstdcxx;
+
+ StringRef Value = A->getValue();
+ if (Value != "libstdc++")
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
+
+ return ToolChain::CST_Libstdcxx;
+}
+
+//
+// Returns the default CPU for Hexagon. This is the default compilation target
+// if no Hexagon processor is selected at the command-line.
+//
+const StringRef HexagonToolChain::GetDefaultCPU() {
+ return "hexagonv60";
+}
+
+const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
+ Arg *CpuArg = nullptr;
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
+ CpuArg = A;
+
+ StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
+ if (CPU.startswith("hexagon"))
+ return CPU.substr(sizeof("hexagon") - 1);
+ return CPU;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.h
new file mode 100644
index 0000000..7f9a6b2
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.h
@@ -0,0 +1,104 @@
+//===--- Hexagon.h - Hexagon ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HEXAGON_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HEXAGON_H
+
+#include "Linux.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace hexagon {
+// For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile
+// and Compile.
+// We simply use "clang -cc1" for those actions.
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
+public:
+ Assembler(const ToolChain &TC)
+ : GnuTool("hexagon::Assembler", "hexagon-as", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("hexagon::Linker", "hexagon-ld", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ virtual void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace hexagon.
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux {
+protected:
+ GCCVersion GCCLibAndIncVersion;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+
+ unsigned getOptimizationLevel(const llvm::opt::ArgList &DriverArgs) const;
+
+public:
+ HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~HexagonToolChain() override;
+
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+
+ StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; }
+ bool IsIntegratedAssemblerDefault() const override {
+ return true;
+ }
+
+ std::string getHexagonTargetDir(
+ const std::string &InstalledDir,
+ const SmallVectorImpl<std::string> &PrefixDirs) const;
+ void getHexagonLibraryPaths(const llvm::opt::ArgList &Args,
+ ToolChain::path_list &LibPaths) const;
+
+ static const StringRef GetDefaultCPU();
+ static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args);
+
+ static Optional<unsigned> getSmallDataThreshold(
+ const llvm::opt::ArgList &Args);
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HEXAGON_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Lanai.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Lanai.h
new file mode 100644
index 0000000..4ce658d
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Lanai.h
@@ -0,0 +1,39 @@
+//===--- Lanai.h - Lanai ToolChain Implementations --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LANAI_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LANAI_H
+
+#include "Gnu.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY LanaiToolChain : public Generic_ELF {
+public:
+ LanaiToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {}
+
+ // No support for finding a C++ standard library yet.
+ std::string findLibCxxIncludePath() const override { return ""; }
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override {}
+
+ bool IsIntegratedAssemblerDefault() const override { return true; }
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LANAI_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp
new file mode 100644
index 0000000..08a27fa
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.cpp
@@ -0,0 +1,860 @@
+//===--- Linux.h - Linux ToolChain Implementations --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Linux.h"
+#include "Arch/ARM.h"
+#include "Arch/Mips.h"
+#include "Arch/PPC.h"
+#include "CommonArgs.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Distro.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/Path.h"
+#include <system_error>
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+using tools::addPathIfExists;
+
+/// \brief Get our best guess at the multiarch triple for a target.
+///
+/// Debian-based systems are starting to use a multiarch setup where they use
+/// a target-triple directory in the library and header search paths.
+/// Unfortunately, this triple does not align with the vanilla target triple,
+/// so we provide a rough mapping here.
+static std::string getMultiarchTriple(const Driver &D,
+ const llvm::Triple &TargetTriple,
+ StringRef SysRoot) {
+ llvm::Triple::EnvironmentType TargetEnvironment =
+ TargetTriple.getEnvironment();
+
+ // For most architectures, just use whatever we have rather than trying to be
+ // clever.
+ switch (TargetTriple.getArch()) {
+ default:
+ break;
+
+ // We use the existence of '/lib/<triple>' as a directory to detect some
+ // common linux triples that don't quite match the Clang triple for both
+ // 32-bit and 64-bit targets. Multiarch fixes its install triples to these
+ // regardless of what the actual target triple is.
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ if (TargetEnvironment == llvm::Triple::GNUEABIHF) {
+ if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabihf"))
+ return "arm-linux-gnueabihf";
+ } else {
+ if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabi"))
+ return "arm-linux-gnueabi";
+ }
+ break;
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ if (TargetEnvironment == llvm::Triple::GNUEABIHF) {
+ if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabihf"))
+ return "armeb-linux-gnueabihf";
+ } else {
+ if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabi"))
+ return "armeb-linux-gnueabi";
+ }
+ break;
+ case llvm::Triple::x86:
+ if (D.getVFS().exists(SysRoot + "/lib/i386-linux-gnu"))
+ return "i386-linux-gnu";
+ break;
+ case llvm::Triple::x86_64:
+ // We don't want this for x32, otherwise it will match x86_64 libs
+ if (TargetEnvironment != llvm::Triple::GNUX32 &&
+ D.getVFS().exists(SysRoot + "/lib/x86_64-linux-gnu"))
+ return "x86_64-linux-gnu";
+ break;
+ case llvm::Triple::aarch64:
+ if (D.getVFS().exists(SysRoot + "/lib/aarch64-linux-gnu"))
+ return "aarch64-linux-gnu";
+ break;
+ case llvm::Triple::aarch64_be:
+ if (D.getVFS().exists(SysRoot + "/lib/aarch64_be-linux-gnu"))
+ return "aarch64_be-linux-gnu";
+ break;
+ case llvm::Triple::mips:
+ if (D.getVFS().exists(SysRoot + "/lib/mips-linux-gnu"))
+ return "mips-linux-gnu";
+ break;
+ case llvm::Triple::mipsel:
+ if (D.getVFS().exists(SysRoot + "/lib/mipsel-linux-gnu"))
+ return "mipsel-linux-gnu";
+ break;
+ case llvm::Triple::mips64:
+ if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu"))
+ return "mips64-linux-gnu";
+ if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnuabi64"))
+ return "mips64-linux-gnuabi64";
+ break;
+ case llvm::Triple::mips64el:
+ if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu"))
+ return "mips64el-linux-gnu";
+ if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnuabi64"))
+ return "mips64el-linux-gnuabi64";
+ break;
+ case llvm::Triple::ppc:
+ if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe"))
+ return "powerpc-linux-gnuspe";
+ if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnu"))
+ return "powerpc-linux-gnu";
+ break;
+ case llvm::Triple::ppc64:
+ if (D.getVFS().exists(SysRoot + "/lib/powerpc64-linux-gnu"))
+ return "powerpc64-linux-gnu";
+ break;
+ case llvm::Triple::ppc64le:
+ if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu"))
+ return "powerpc64le-linux-gnu";
+ break;
+ case llvm::Triple::sparc:
+ if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu"))
+ return "sparc-linux-gnu";
+ break;
+ case llvm::Triple::sparcv9:
+ if (D.getVFS().exists(SysRoot + "/lib/sparc64-linux-gnu"))
+ return "sparc64-linux-gnu";
+ break;
+ case llvm::Triple::systemz:
+ if (D.getVFS().exists(SysRoot + "/lib/s390x-linux-gnu"))
+ return "s390x-linux-gnu";
+ break;
+ }
+ return TargetTriple.str();
+}
+
+static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
+ if (tools::isMipsArch(Triple.getArch())) {
+ if (Triple.isAndroid()) {
+ StringRef CPUName;
+ StringRef ABIName;
+ tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
+ if (CPUName == "mips32r6")
+ return "libr6";
+ if (CPUName == "mips32r2")
+ return "libr2";
+ }
+ // lib32 directory has a special meaning on MIPS targets.
+ // It contains N32 ABI binaries. Use this folder if produce
+ // code for N32 ABI only.
+ if (tools::mips::hasMipsAbiArg(Args, "n32"))
+ return "lib32";
+ return Triple.isArch32Bit() ? "lib" : "lib64";
+ }
+
+ // It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and
+ // using that variant while targeting other architectures causes problems
+ // because the libraries are laid out in shared system roots that can't cope
+ // with a 'lib32' library search path being considered. So we only enable
+ // them when we know we may need it.
+ //
+ // FIXME: This is a bit of a hack. We should really unify this code for
+ // reasoning about oslibdir spellings with the lib dir spellings in the
+ // GCCInstallationDetector, but that is a more significant refactoring.
+ if (Triple.getArch() == llvm::Triple::x86 ||
+ Triple.getArch() == llvm::Triple::ppc)
+ return "lib32";
+
+ if (Triple.getArch() == llvm::Triple::x86_64 &&
+ Triple.getEnvironment() == llvm::Triple::GNUX32)
+ return "libx32";
+
+ return Triple.isArch32Bit() ? "lib" : "lib64";
+}
+
+static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
+ const Multilib &Multilib,
+ StringRef InstallPath,
+ ToolChain::path_list &Paths) {
+ if (const auto &PathsCallback = Multilibs.filePathsCallback())
+ for (const auto &Path : PathsCallback(Multilib))
+ addPathIfExists(D, InstallPath + Path, Paths);
+}
+
+Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ GCCInstallation.init(Triple, Args);
+ Multilibs = GCCInstallation.getMultilibs();
+ llvm::Triple::ArchType Arch = Triple.getArch();
+ std::string SysRoot = computeSysRoot();
+
+ // Cross-compiling binutils and GCC installations (vanilla and openSUSE at
+ // least) put various tools in a triple-prefixed directory off of the parent
+ // of the GCC installation. We use the GCC triple here to ensure that we end
+ // up with tools that support the same amount of cross compiling as the
+ // detected GCC installation. For example, if we find a GCC installation
+ // targeting x86_64, but it is a bi-arch GCC installation, it can also be
+ // used to target i386.
+ // FIXME: This seems unlikely to be Linux-specific.
+ ToolChain::path_list &PPaths = getProgramPaths();
+ PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
+ GCCInstallation.getTriple().str() + "/bin")
+ .str());
+
+ Distro Distro(D.getVFS());
+
+ if (Distro.IsOpenSUSE() || Distro.IsUbuntu()) {
+ ExtraOpts.push_back("-z");
+ ExtraOpts.push_back("relro");
+ }
+
+ if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
+ ExtraOpts.push_back("-X");
+
+ const bool IsAndroid = Triple.isAndroid();
+ const bool IsMips = tools::isMipsArch(Arch);
+ const bool IsHexagon = Arch == llvm::Triple::hexagon;
+
+ if (IsMips && !SysRoot.empty())
+ ExtraOpts.push_back("--sysroot=" + SysRoot);
+
+ // Do not use 'gnu' hash style for Mips targets because .gnu.hash
+ // and the MIPS ABI require .dynsym to be sorted in different ways.
+ // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS
+ // ABI requires a mapping between the GOT and the symbol table.
+ // Android loader does not support .gnu.hash.
+ // Hexagon linker/loader does not support .gnu.hash
+ if (!IsMips && !IsAndroid && !IsHexagon) {
+ if (Distro.IsRedhat() || Distro.IsOpenSUSE() ||
+ (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick))
+ ExtraOpts.push_back("--hash-style=gnu");
+
+ if (Distro.IsDebian() || Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid ||
+ Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic)
+ ExtraOpts.push_back("--hash-style=both");
+ }
+
+ if (Distro.IsRedhat() && Distro != Distro::RHEL5 && Distro != Distro::RHEL6)
+ ExtraOpts.push_back("--no-add-needed");
+
+#ifdef ENABLE_LINKER_BUILD_ID
+ ExtraOpts.push_back("--build-id");
+#endif
+
+ if (Distro.IsOpenSUSE())
+ ExtraOpts.push_back("--enable-new-dtags");
+
+ // The selection of paths to try here is designed to match the patterns which
+ // the GCC driver itself uses, as this is part of the GCC-compatible driver.
+ // This was determined by running GCC in a fake filesystem, creating all
+ // possible permutations of these directories, and seeing which ones it added
+ // to the link paths.
+ path_list &Paths = getFilePaths();
+
+ const std::string OSLibDir = getOSLibDir(Triple, Args);
+ const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot);
+
+ // Add the multilib suffixed paths where they are available.
+ if (GCCInstallation.isValid()) {
+ const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
+ const std::string &LibPath = GCCInstallation.getParentLibPath();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
+ const MultilibSet &Multilibs = GCCInstallation.getMultilibs();
+
+ // Add toolchain / multilib specific file paths.
+ addMultilibsFilePaths(D, Multilibs, Multilib,
+ GCCInstallation.getInstallPath(), Paths);
+
+ // Sourcery CodeBench MIPS toolchain holds some libraries under
+ // a biarch-like suffix of the GCC installation.
+ addPathIfExists(D, GCCInstallation.getInstallPath() + Multilib.gccSuffix(),
+ Paths);
+
+ // GCC cross compiling toolchains will install target libraries which ship
+ // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as
+ // any part of the GCC installation in
+ // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat
+ // debatable, but is the reality today. We need to search this tree even
+ // when we have a sysroot somewhere else. It is the responsibility of
+ // whomever is doing the cross build targeting a sysroot using a GCC
+ // installation that is *not* within the system root to ensure two things:
+ //
+ // 1) Any DSOs that are linked in from this tree or from the install path
+ // above must be present on the system root and found via an
+ // appropriate rpath.
+ // 2) There must not be libraries installed into
+ // <prefix>/<triple>/<libdir> unless they should be preferred over
+ // those within the system root.
+ //
+ // Note that this matches the GCC behavior. See the below comment for where
+ // Clang diverges from GCC's behavior.
+ addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" +
+ OSLibDir + Multilib.osSuffix(),
+ Paths);
+
+ // If the GCC installation we found is inside of the sysroot, we want to
+ // prefer libraries installed in the parent prefix of the GCC installation.
+ // It is important to *not* use these paths when the GCC installation is
+ // outside of the system root as that can pick up unintended libraries.
+ // This usually happens when there is an external cross compiler on the
+ // host system, and a more minimal sysroot available that is the target of
+ // the cross. Note that GCC does include some of these directories in some
+ // configurations but this seems somewhere between questionable and simply
+ // a bug.
+ if (StringRef(LibPath).startswith(SysRoot)) {
+ addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths);
+ addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths);
+ }
+ }
+
+ // Similar to the logic for GCC above, if we currently running Clang inside
+ // of the requested system root, add its parent library paths to
+ // those searched.
+ // FIXME: It's not clear whether we should use the driver's installed
+ // directory ('Dir' below) or the ResourceDir.
+ if (StringRef(D.Dir).startswith(SysRoot)) {
+ addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths);
+ addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths);
+ }
+
+ addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths);
+ addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths);
+ addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths);
+ addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths);
+
+ // Try walking via the GCC triple path in case of biarch or multiarch GCC
+ // installations with strange symlinks.
+ if (GCCInstallation.isValid()) {
+ addPathIfExists(D,
+ SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() +
+ "/../../" + OSLibDir,
+ Paths);
+
+ // Add the 'other' biarch variant path
+ Multilib BiarchSibling;
+ if (GCCInstallation.getBiarchSibling(BiarchSibling)) {
+ addPathIfExists(D, GCCInstallation.getInstallPath() +
+ BiarchSibling.gccSuffix(),
+ Paths);
+ }
+
+ // See comments above on the multilib variant for details of why this is
+ // included even from outside the sysroot.
+ const std::string &LibPath = GCCInstallation.getParentLibPath();
+ const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
+ addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" +
+ Multilib.osSuffix(),
+ Paths);
+
+ // See comments above on the multilib variant for details of why this is
+ // only included from within the sysroot.
+ if (StringRef(LibPath).startswith(SysRoot))
+ addPathIfExists(D, LibPath, Paths);
+ }
+
+ // Similar to the logic for GCC above, if we are currently running Clang
+ // inside of the requested system root, add its parent library path to those
+ // searched.
+ // FIXME: It's not clear whether we should use the driver's installed
+ // directory ('Dir' below) or the ResourceDir.
+ if (StringRef(D.Dir).startswith(SysRoot))
+ addPathIfExists(D, D.Dir + "/../lib", Paths);
+
+ addPathIfExists(D, SysRoot + "/lib", Paths);
+ addPathIfExists(D, SysRoot + "/usr/lib", Paths);
+}
+
+bool Linux::HasNativeLLVMSupport() const { return true; }
+
+Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); }
+
+Tool *Linux::buildAssembler() const {
+ return new tools::gnutools::Assembler(*this);
+}
+
+std::string Linux::computeSysRoot() const {
+ if (!getDriver().SysRoot.empty())
+ return getDriver().SysRoot;
+
+ if (!GCCInstallation.isValid() || !tools::isMipsArch(getTriple().getArch()))
+ return std::string();
+
+ // Standalone MIPS toolchains use different names for sysroot folder
+ // and put it into different places. Here we try to check some known
+ // variants.
+
+ const StringRef InstallDir = GCCInstallation.getInstallPath();
+ const StringRef TripleStr = GCCInstallation.getTriple().str();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
+
+ std::string Path =
+ (InstallDir + "/../../../../" + TripleStr + "/libc" + Multilib.osSuffix())
+ .str();
+
+ if (getVFS().exists(Path))
+ return Path;
+
+ Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str();
+
+ if (getVFS().exists(Path))
+ return Path;
+
+ return std::string();
+}
+
+std::string Linux::getDynamicLinker(const ArgList &Args) const {
+ const llvm::Triple::ArchType Arch = getArch();
+ const llvm::Triple &Triple = getTriple();
+
+ const Distro Distro(getDriver().getVFS());
+
+ if (Triple.isAndroid())
+ return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker";
+
+ if (Triple.isMusl()) {
+ std::string ArchName;
+ bool IsArm = false;
+
+ switch (Arch) {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ ArchName = "arm";
+ IsArm = true;
+ break;
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ ArchName = "armeb";
+ IsArm = true;
+ break;
+ default:
+ ArchName = Triple.getArchName().str();
+ }
+ if (IsArm &&
+ (Triple.getEnvironment() == llvm::Triple::MuslEABIHF ||
+ tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard))
+ ArchName += "hf";
+
+ return "/lib/ld-musl-" + ArchName + ".so.1";
+ }
+
+ std::string LibDir;
+ std::string Loader;
+
+ switch (Arch) {
+ default:
+ llvm_unreachable("unsupported architecture");
+
+ case llvm::Triple::aarch64:
+ LibDir = "lib";
+ Loader = "ld-linux-aarch64.so.1";
+ break;
+ case llvm::Triple::aarch64_be:
+ LibDir = "lib";
+ Loader = "ld-linux-aarch64_be.so.1";
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb: {
+ const bool HF =
+ Triple.getEnvironment() == llvm::Triple::GNUEABIHF ||
+ tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard;
+
+ LibDir = "lib";
+ Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3";
+ break;
+ }
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
+ bool LE = (Triple.getArch() == llvm::Triple::mipsel) ||
+ (Triple.getArch() == llvm::Triple::mips64el);
+ bool IsNaN2008 = tools::mips::isNaN2008(Args, Triple);
+
+ LibDir = "lib" + tools::mips::getMipsABILibSuffix(Args, Triple);
+
+ if (tools::mips::isUCLibc(Args))
+ Loader = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0";
+ else if (!Triple.hasEnvironment() &&
+ Triple.getVendor() == llvm::Triple::VendorType::MipsTechnologies)
+ Loader = LE ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1";
+ else
+ Loader = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1";
+
+ break;
+ }
+ case llvm::Triple::ppc:
+ LibDir = "lib";
+ Loader = "ld.so.1";
+ break;
+ case llvm::Triple::ppc64:
+ LibDir = "lib64";
+ Loader =
+ (tools::ppc::hasPPCAbiArg(Args, "elfv2")) ? "ld64.so.2" : "ld64.so.1";
+ break;
+ case llvm::Triple::ppc64le:
+ LibDir = "lib64";
+ Loader =
+ (tools::ppc::hasPPCAbiArg(Args, "elfv1")) ? "ld64.so.1" : "ld64.so.2";
+ break;
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ LibDir = "lib";
+ Loader = "ld-linux.so.2";
+ break;
+ case llvm::Triple::sparcv9:
+ LibDir = "lib64";
+ Loader = "ld-linux.so.2";
+ break;
+ case llvm::Triple::systemz:
+ LibDir = "lib";
+ Loader = "ld64.so.1";
+ break;
+ case llvm::Triple::x86:
+ LibDir = "lib";
+ Loader = "ld-linux.so.2";
+ break;
+ case llvm::Triple::x86_64: {
+ bool X32 = Triple.getEnvironment() == llvm::Triple::GNUX32;
+
+ LibDir = X32 ? "libx32" : "lib64";
+ Loader = X32 ? "ld-linux-x32.so.2" : "ld-linux-x86-64.so.2";
+ break;
+ }
+ }
+
+ if (Distro == Distro::Exherbo && (Triple.getVendor() == llvm::Triple::UnknownVendor ||
+ Triple.getVendor() == llvm::Triple::PC))
+ return "/usr/" + Triple.str() + "/lib/" + Loader;
+ return "/" + LibDir + "/" + Loader;
+}
+
+void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ std::string SysRoot = computeSysRoot();
+
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nostdlibinc))
+ addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Check for configure-time C include directories.
+ StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (CIncludeDirs != "") {
+ SmallVector<StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (StringRef dir : dirs) {
+ StringRef Prefix =
+ llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+ }
+ return;
+ }
+
+ // Lacking those, try to detect the correct set of system includes for the
+ // target triple.
+
+ // Add include directories specific to the selected multilib set and multilib.
+ if (GCCInstallation.isValid()) {
+ const auto &Callback = Multilibs.includeDirsCallback();
+ if (Callback) {
+ for (const auto &Path : Callback(GCCInstallation.getMultilib()))
+ addExternCSystemIncludeIfExists(
+ DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path);
+ }
+ }
+
+ // Implement generic Debian multiarch support.
+ const StringRef X86_64MultiarchIncludeDirs[] = {
+ "/usr/include/x86_64-linux-gnu",
+
+ // FIXME: These are older forms of multiarch. It's not clear that they're
+ // in use in any released version of Debian, so we should consider
+ // removing them.
+ "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64"};
+ const StringRef X86MultiarchIncludeDirs[] = {
+ "/usr/include/i386-linux-gnu",
+
+ // FIXME: These are older forms of multiarch. It's not clear that they're
+ // in use in any released version of Debian, so we should consider
+ // removing them.
+ "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu",
+ "/usr/include/i486-linux-gnu"};
+ const StringRef AArch64MultiarchIncludeDirs[] = {
+ "/usr/include/aarch64-linux-gnu"};
+ const StringRef ARMMultiarchIncludeDirs[] = {
+ "/usr/include/arm-linux-gnueabi"};
+ const StringRef ARMHFMultiarchIncludeDirs[] = {
+ "/usr/include/arm-linux-gnueabihf"};
+ const StringRef ARMEBMultiarchIncludeDirs[] = {
+ "/usr/include/armeb-linux-gnueabi"};
+ const StringRef ARMEBHFMultiarchIncludeDirs[] = {
+ "/usr/include/armeb-linux-gnueabihf"};
+ const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"};
+ const StringRef MIPSELMultiarchIncludeDirs[] = {
+ "/usr/include/mipsel-linux-gnu"};
+ const StringRef MIPS64MultiarchIncludeDirs[] = {
+ "/usr/include/mips64-linux-gnu", "/usr/include/mips64-linux-gnuabi64"};
+ const StringRef MIPS64ELMultiarchIncludeDirs[] = {
+ "/usr/include/mips64el-linux-gnu",
+ "/usr/include/mips64el-linux-gnuabi64"};
+ const StringRef PPCMultiarchIncludeDirs[] = {
+ "/usr/include/powerpc-linux-gnu"};
+ const StringRef PPC64MultiarchIncludeDirs[] = {
+ "/usr/include/powerpc64-linux-gnu"};
+ const StringRef PPC64LEMultiarchIncludeDirs[] = {
+ "/usr/include/powerpc64le-linux-gnu"};
+ const StringRef SparcMultiarchIncludeDirs[] = {
+ "/usr/include/sparc-linux-gnu"};
+ const StringRef Sparc64MultiarchIncludeDirs[] = {
+ "/usr/include/sparc64-linux-gnu"};
+ const StringRef SYSTEMZMultiarchIncludeDirs[] = {
+ "/usr/include/s390x-linux-gnu"};
+ ArrayRef<StringRef> MultiarchIncludeDirs;
+ switch (getTriple().getArch()) {
+ case llvm::Triple::x86_64:
+ MultiarchIncludeDirs = X86_64MultiarchIncludeDirs;
+ break;
+ case llvm::Triple::x86:
+ MultiarchIncludeDirs = X86MultiarchIncludeDirs;
+ break;
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ MultiarchIncludeDirs = AArch64MultiarchIncludeDirs;
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
+ MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs;
+ else
+ MultiarchIncludeDirs = ARMMultiarchIncludeDirs;
+ break;
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
+ MultiarchIncludeDirs = ARMEBHFMultiarchIncludeDirs;
+ else
+ MultiarchIncludeDirs = ARMEBMultiarchIncludeDirs;
+ break;
+ case llvm::Triple::mips:
+ MultiarchIncludeDirs = MIPSMultiarchIncludeDirs;
+ break;
+ case llvm::Triple::mipsel:
+ MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs;
+ break;
+ case llvm::Triple::mips64:
+ MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs;
+ break;
+ case llvm::Triple::mips64el:
+ MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs;
+ break;
+ case llvm::Triple::ppc:
+ MultiarchIncludeDirs = PPCMultiarchIncludeDirs;
+ break;
+ case llvm::Triple::ppc64:
+ MultiarchIncludeDirs = PPC64MultiarchIncludeDirs;
+ break;
+ case llvm::Triple::ppc64le:
+ MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs;
+ break;
+ case llvm::Triple::sparc:
+ MultiarchIncludeDirs = SparcMultiarchIncludeDirs;
+ break;
+ case llvm::Triple::sparcv9:
+ MultiarchIncludeDirs = Sparc64MultiarchIncludeDirs;
+ break;
+ case llvm::Triple::systemz:
+ MultiarchIncludeDirs = SYSTEMZMultiarchIncludeDirs;
+ break;
+ default:
+ break;
+ }
+ for (StringRef Dir : MultiarchIncludeDirs) {
+ if (D.getVFS().exists(SysRoot + Dir)) {
+ addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir);
+ break;
+ }
+ }
+
+ if (getTriple().getOS() == llvm::Triple::RTEMS)
+ return;
+
+ // Add an include of '/include' directly. This isn't provided by default by
+ // system GCCs, but is often used with cross-compiling GCCs, and harmless to
+ // add even when Clang is acting as-if it were a system compiler.
+ addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
+
+ addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
+}
+
+static std::string DetectLibcxxIncludePath(StringRef base) {
+ std::error_code EC;
+ int MaxVersion = 0;
+ std::string MaxVersionString = "";
+ for (llvm::sys::fs::directory_iterator LI(base, EC), LE; !EC && LI != LE;
+ LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
+ int Version;
+ if (VersionText[0] == 'v' &&
+ !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) {
+ if (Version > MaxVersion) {
+ MaxVersion = Version;
+ MaxVersionString = VersionText;
+ }
+ }
+ }
+ return MaxVersion ? (base + "/" + MaxVersionString).str() : "";
+}
+
+std::string Linux::findLibCxxIncludePath() const {
+ const std::string LibCXXIncludePathCandidates[] = {
+ DetectLibcxxIncludePath(getDriver().Dir + "/../include/c++"),
+ // If this is a development, non-installed, clang, libcxx will
+ // not be found at ../include/c++ but it likely to be found at
+ // one of the following two locations:
+ DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/local/include/c++"),
+ DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/include/c++") };
+ for (const auto &IncludePath : LibCXXIncludePathCandidates) {
+ if (IncludePath.empty() || !getVFS().exists(IncludePath))
+ continue;
+ // Use the first candidate that exists.
+ return IncludePath;
+ }
+ return "";
+}
+
+void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ // We need a detected GCC installation on Linux to provide libstdc++'s
+ // headers.
+ if (!GCCInstallation.isValid())
+ return;
+
+ // By default, look for the C++ headers in an include directory adjacent to
+ // the lib directory of the GCC installation. Note that this is expect to be
+ // equivalent to '/usr/include/c++/X.Y' in almost all cases.
+ StringRef LibDir = GCCInstallation.getParentLibPath();
+ StringRef InstallDir = GCCInstallation.getInstallPath();
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
+ const std::string GCCMultiarchTriple = getMultiarchTriple(
+ getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot);
+ const std::string TargetMultiarchTriple =
+ getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot);
+ const GCCVersion &Version = GCCInstallation.getVersion();
+
+ // The primary search for libstdc++ supports multiarch variants.
+ if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
+ "/c++/" + Version.Text, TripleStr,
+ GCCMultiarchTriple, TargetMultiarchTriple,
+ Multilib.includeSuffix(), DriverArgs, CC1Args))
+ return;
+
+ // Otherwise, fall back on a bunch of options which don't use multiarch
+ // layouts for simplicity.
+ const std::string LibStdCXXIncludePathCandidates[] = {
+ // Gentoo is weird and places its headers inside the GCC install,
+ // so if the first attempt to find the headers fails, try these patterns.
+ InstallDir.str() + "/include/g++-v" + Version.Text,
+ InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." +
+ Version.MinorStr,
+ InstallDir.str() + "/include/g++-v" + Version.MajorStr,
+ // Android standalone toolchain has C++ headers in yet another place.
+ LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
+ // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++,
+ // without a subdirectory corresponding to the gcc version.
+ LibDir.str() + "/../include/c++",
+ };
+
+ for (const auto &IncludePath : LibStdCXXIncludePathCandidates) {
+ if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr,
+ /*GCCMultiarchTriple*/ "",
+ /*TargetMultiarchTriple*/ "",
+ Multilib.includeSuffix(), DriverArgs, CC1Args))
+ break;
+ }
+}
+
+void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+}
+
+void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (GCCInstallation.isValid()) {
+ CC1Args.push_back("-isystem");
+ CC1Args.push_back(DriverArgs.MakeArgString(
+ GCCInstallation.getParentLibPath() + "/../" +
+ GCCInstallation.getTriple().str() + "/include"));
+ }
+}
+
+bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
+
+SanitizerMask Linux::getSupportedSanitizers() const {
+ const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
+ const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
+ const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 ||
+ getTriple().getArch() == llvm::Triple::mips64el;
+ const bool IsPowerPC64 = getTriple().getArch() == llvm::Triple::ppc64 ||
+ getTriple().getArch() == llvm::Triple::ppc64le;
+ const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::aarch64_be;
+ const bool IsArmArch = getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb ||
+ getTriple().getArch() == llvm::Triple::armeb ||
+ getTriple().getArch() == llvm::Triple::thumbeb;
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::Fuzzer;
+ Res |= SanitizerKind::KernelAddress;
+ Res |= SanitizerKind::Vptr;
+ Res |= SanitizerKind::SafeStack;
+ if (IsX86_64 || IsMIPS64 || IsAArch64)
+ Res |= SanitizerKind::DataFlow;
+ if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch)
+ Res |= SanitizerKind::Leak;
+ if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64)
+ Res |= SanitizerKind::Thread;
+ if (IsX86_64 || IsMIPS64 || IsPowerPC64 || IsAArch64)
+ Res |= SanitizerKind::Memory;
+ if (IsX86_64 || IsMIPS64)
+ Res |= SanitizerKind::Efficiency;
+ if (IsX86 || IsX86_64) {
+ Res |= SanitizerKind::Function;
+ }
+ return Res;
+}
+
+void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ if (!needsProfileRT(Args)) return;
+
+ // Add linker option -u__llvm_runtime_variable to cause runtime
+ // initialization module to be linked in.
+ if (!Args.hasArg(options::OPT_coverage))
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
+ ToolChain::addProfileRTLibs(Args, CmdArgs);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.h
new file mode 100644
index 0000000..9778c18
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Linux.h
@@ -0,0 +1,57 @@
+//===--- Linux.h - Linux ToolChain Implementations --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LINUX_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LINUX_H
+
+#include "Gnu.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {
+public:
+ Linux(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool HasNativeLLVMSupport() const override;
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ std::string findLibCxxIncludePath() const override;
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ bool isPIEDefault() const override;
+ SanitizerMask getSupportedSanitizers() const override;
+ void addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+ virtual std::string computeSysRoot() const;
+
+ virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const;
+
+ std::vector<std::string> ExtraOpts;
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LINUX_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.cpp
new file mode 100644
index 0000000..7978a694
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -0,0 +1,1463 @@
+//===--- ToolChains.cpp - ToolChain Implementations -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MSVC.h"
+#include "CommonArgs.h"
+#include "Darwin.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Version.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include <cstdio>
+
+// Include the necessary headers to interface with the Windows registry and
+// environment.
+#if defined(LLVM_ON_WIN32)
+#define USE_WIN32
+#endif
+
+#ifdef USE_WIN32
+ #define WIN32_LEAN_AND_MEAN
+ #define NOGDI
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+ #include <windows.h>
+#endif
+
+#ifdef _MSC_VER
+// Don't support SetupApi on MinGW.
+#define USE_MSVC_SETUP_API
+
+// Make sure this comes before MSVCSetupApi.h
+#include <comdef.h>
+
+#include "MSVCSetupApi.h"
+#include "llvm/Support/COM.h"
+_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration));
+_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2));
+_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper));
+_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances));
+_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance));
+_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2));
+#endif
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+// Defined below.
+// Forward declare this so there aren't too many things above the constructor.
+static bool getSystemRegistryString(const char *keyPath, const char *valueName,
+ std::string &value, std::string *phValue);
+
+// Check various environment variables to try and find a toolchain.
+static bool findVCToolChainViaEnvironment(std::string &Path,
+ MSVCToolChain::ToolsetLayout &VSLayout) {
+ // These variables are typically set by vcvarsall.bat
+ // when launching a developer command prompt.
+ if (llvm::Optional<std::string> VCToolsInstallDir =
+ llvm::sys::Process::GetEnv("VCToolsInstallDir")) {
+ // This is only set by newer Visual Studios, and it leads straight to
+ // the toolchain directory.
+ Path = std::move(*VCToolsInstallDir);
+ VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
+ return true;
+ }
+ if (llvm::Optional<std::string> VCInstallDir =
+ llvm::sys::Process::GetEnv("VCINSTALLDIR")) {
+ // If the previous variable isn't set but this one is, then we've found
+ // an older Visual Studio. This variable is set by newer Visual Studios too,
+ // so this check has to appear second.
+ // In older Visual Studios, the VC directory is the toolchain.
+ Path = std::move(*VCInstallDir);
+ VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
+ return true;
+ }
+
+ // We couldn't find any VC environment variables. Let's walk through PATH and
+ // see if it leads us to a VC toolchain bin directory. If it does, pick the
+ // first one that we find.
+ if (llvm::Optional<std::string> PathEnv =
+ llvm::sys::Process::GetEnv("PATH")) {
+ llvm::SmallVector<llvm::StringRef, 8> PathEntries;
+ llvm::StringRef(*PathEnv).split(PathEntries, llvm::sys::EnvPathSeparator);
+ for (llvm::StringRef PathEntry : PathEntries) {
+ if (PathEntry.empty())
+ continue;
+
+ llvm::SmallString<256> ExeTestPath;
+
+ // If cl.exe doesn't exist, then this definitely isn't a VC toolchain.
+ ExeTestPath = PathEntry;
+ llvm::sys::path::append(ExeTestPath, "cl.exe");
+ if (!llvm::sys::fs::exists(ExeTestPath))
+ continue;
+
+ // cl.exe existing isn't a conclusive test for a VC toolchain; clang also
+ // has a cl.exe. So let's check for link.exe too.
+ ExeTestPath = PathEntry;
+ llvm::sys::path::append(ExeTestPath, "link.exe");
+ if (!llvm::sys::fs::exists(ExeTestPath))
+ continue;
+
+ // whatever/VC/bin --> old toolchain, VC dir is toolchain dir.
+ llvm::StringRef TestPath = PathEntry;
+ bool IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin");
+ if (!IsBin) {
+ // Strip any architecture subdir like "amd64".
+ TestPath = llvm::sys::path::parent_path(TestPath);
+ IsBin = llvm::sys::path::filename(TestPath).equals_lower("bin");
+ }
+ if (IsBin) {
+ llvm::StringRef ParentPath = llvm::sys::path::parent_path(TestPath);
+ llvm::StringRef ParentFilename = llvm::sys::path::filename(ParentPath);
+ if (ParentFilename == "VC") {
+ Path = ParentPath;
+ VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
+ return true;
+ }
+ if (ParentFilename == "x86ret" || ParentFilename == "x86chk"
+ || ParentFilename == "amd64ret" || ParentFilename == "amd64chk") {
+ Path = ParentPath;
+ VSLayout = MSVCToolChain::ToolsetLayout::DevDivInternal;
+ return true;
+ }
+
+ } else {
+ // This could be a new (>=VS2017) toolchain. If it is, we should find
+ // path components with these prefixes when walking backwards through
+ // the path.
+ // Note: empty strings match anything.
+ llvm::StringRef ExpectedPrefixes[] = {"", "Host", "bin", "",
+ "MSVC", "Tools", "VC"};
+
+ auto It = llvm::sys::path::rbegin(PathEntry);
+ auto End = llvm::sys::path::rend(PathEntry);
+ for (llvm::StringRef Prefix : ExpectedPrefixes) {
+ if (It == End)
+ goto NotAToolChain;
+ if (!It->startswith(Prefix))
+ goto NotAToolChain;
+ ++It;
+ }
+
+ // We've found a new toolchain!
+ // Back up 3 times (/bin/Host/arch) to get the root path.
+ llvm::StringRef ToolChainPath(PathEntry);
+ for (int i = 0; i < 3; ++i)
+ ToolChainPath = llvm::sys::path::parent_path(ToolChainPath);
+
+ Path = ToolChainPath;
+ VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
+ return true;
+ }
+
+ NotAToolChain:
+ continue;
+ }
+ }
+ return false;
+}
+
+// Query the Setup Config server for installs, then pick the newest version
+// and find its default VC toolchain.
+// This is the preferred way to discover new Visual Studios, as they're no
+// longer listed in the registry.
+static bool findVCToolChainViaSetupConfig(std::string &Path,
+ MSVCToolChain::ToolsetLayout &VSLayout) {
+#if !defined(USE_MSVC_SETUP_API)
+ return false;
+#else
+ // FIXME: This really should be done once in the top-level program's main
+ // function, as it may have already been initialized with a different
+ // threading model otherwise.
+ llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded);
+ HRESULT HR;
+
+ // _com_ptr_t will throw a _com_error if a COM calls fail.
+ // The LLVM coding standards forbid exception handling, so we'll have to
+ // stop them from being thrown in the first place.
+ // The destructor will put the regular error handler back when we leave
+ // this scope.
+ struct SuppressCOMErrorsRAII {
+ static void __stdcall handler(HRESULT hr, IErrorInfo *perrinfo) {}
+
+ SuppressCOMErrorsRAII() { _set_com_error_handler(handler); }
+
+ ~SuppressCOMErrorsRAII() { _set_com_error_handler(_com_raise_error); }
+
+ } COMErrorSuppressor;
+
+ ISetupConfigurationPtr Query;
+ HR = Query.CreateInstance(__uuidof(SetupConfiguration));
+ if (FAILED(HR))
+ return false;
+
+ IEnumSetupInstancesPtr EnumInstances;
+ HR = ISetupConfiguration2Ptr(Query)->EnumAllInstances(&EnumInstances);
+ if (FAILED(HR))
+ return false;
+
+ ISetupInstancePtr Instance;
+ HR = EnumInstances->Next(1, &Instance, nullptr);
+ if (HR != S_OK)
+ return false;
+
+ ISetupInstancePtr NewestInstance;
+ Optional<uint64_t> NewestVersionNum;
+ do {
+ bstr_t VersionString;
+ uint64_t VersionNum;
+ HR = Instance->GetInstallationVersion(VersionString.GetAddress());
+ if (FAILED(HR))
+ continue;
+ HR = ISetupHelperPtr(Query)->ParseVersion(VersionString, &VersionNum);
+ if (FAILED(HR))
+ continue;
+ if (!NewestVersionNum || (VersionNum > NewestVersionNum)) {
+ NewestInstance = Instance;
+ NewestVersionNum = VersionNum;
+ }
+ } while ((HR = EnumInstances->Next(1, &Instance, nullptr)) == S_OK);
+
+ if (!NewestInstance)
+ return false;
+
+ bstr_t VCPathWide;
+ HR = NewestInstance->ResolvePath(L"VC", VCPathWide.GetAddress());
+ if (FAILED(HR))
+ return false;
+
+ std::string VCRootPath;
+ llvm::convertWideToUTF8(std::wstring(VCPathWide), VCRootPath);
+
+ llvm::SmallString<256> ToolsVersionFilePath(VCRootPath);
+ llvm::sys::path::append(ToolsVersionFilePath, "Auxiliary", "Build",
+ "Microsoft.VCToolsVersion.default.txt");
+
+ auto ToolsVersionFile = llvm::MemoryBuffer::getFile(ToolsVersionFilePath);
+ if (!ToolsVersionFile)
+ return false;
+
+ llvm::SmallString<256> ToolchainPath(VCRootPath);
+ llvm::sys::path::append(ToolchainPath, "Tools", "MSVC",
+ ToolsVersionFile->get()->getBuffer().rtrim());
+ if (!llvm::sys::fs::is_directory(ToolchainPath))
+ return false;
+
+ Path = ToolchainPath.str();
+ VSLayout = MSVCToolChain::ToolsetLayout::VS2017OrNewer;
+ return true;
+#endif
+}
+
+// Look in the registry for Visual Studio installs, and use that to get
+// a toolchain path. VS2017 and newer don't get added to the registry.
+// So if we find something here, we know that it's an older version.
+static bool findVCToolChainViaRegistry(std::string &Path,
+ MSVCToolChain::ToolsetLayout &VSLayout) {
+ std::string VSInstallPath;
+ if (getSystemRegistryString(R"(SOFTWARE\Microsoft\VisualStudio\$VERSION)",
+ "InstallDir", VSInstallPath, nullptr) ||
+ getSystemRegistryString(R"(SOFTWARE\Microsoft\VCExpress\$VERSION)",
+ "InstallDir", VSInstallPath, nullptr)) {
+ if (!VSInstallPath.empty()) {
+ llvm::SmallString<256> VCPath(llvm::StringRef(
+ VSInstallPath.c_str(), VSInstallPath.find(R"(\Common7\IDE)")));
+ llvm::sys::path::append(VCPath, "VC");
+
+ Path = VCPath.str();
+ VSLayout = MSVCToolChain::ToolsetLayout::OlderVS;
+ return true;
+ }
+ }
+ return false;
+}
+
+// Try to find Exe from a Visual Studio distribution. This first tries to find
+// an installed copy of Visual Studio and, failing that, looks in the PATH,
+// making sure that whatever executable that's found is not a same-named exe
+// from clang itself to prevent clang from falling back to itself.
+static std::string FindVisualStudioExecutable(const ToolChain &TC,
+ const char *Exe) {
+ const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
+ SmallString<128> FilePath(MSVC.getSubDirectoryPath(
+ toolchains::MSVCToolChain::SubDirectoryType::Bin));
+ llvm::sys::path::append(FilePath, Exe);
+ return llvm::sys::fs::can_execute(FilePath) ? FilePath.str() : Exe;
+}
+
+void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
+
+ assert((Output.isFilename() || Output.isNothing()) && "invalid output");
+ if (Output.isFilename())
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-out:") + Output.getFilename()));
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
+ !C.getDriver().IsCLMode())
+ CmdArgs.push_back("-defaultlib:libcmt");
+
+ if (!llvm::sys::Process::GetEnv("LIB")) {
+ // If the VC environment hasn't been configured (perhaps because the user
+ // did not run vcvarsall), try to build a consistent link environment. If
+ // the environment variable is set however, assume the user knows what
+ // they're doing.
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-libpath:") +
+ TC.getSubDirectoryPath(
+ toolchains::MSVCToolChain::SubDirectoryType::Lib)));
+
+ if (TC.useUniversalCRT()) {
+ std::string UniversalCRTLibPath;
+ if (TC.getUniversalCRTLibraryPath(UniversalCRTLibPath))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
+ }
+
+ std::string WindowsSdkLibPath;
+ if (TC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
+ }
+
+ if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
+ for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
+ CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
+
+ CmdArgs.push_back("-nologo");
+
+ if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7,
+ options::OPT__SLASH_Zd))
+ CmdArgs.push_back("-debug");
+
+ bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd,
+ options::OPT_shared);
+ if (DLL) {
+ CmdArgs.push_back(Args.MakeArgString("-dll"));
+
+ SmallString<128> ImplibName(Output.getFilename());
+ llvm::sys::path::replace_extension(ImplibName, "lib");
+ CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
+ }
+
+ if (TC.getSanitizerArgs().needsAsanRt()) {
+ CmdArgs.push_back(Args.MakeArgString("-debug"));
+ CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
+ if (TC.getSanitizerArgs().needsSharedAsanRt() ||
+ Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
+ for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
+ // Make sure the dynamic runtime thunk is not optimized out at link time
+ // to ensure proper SEH handling.
+ CmdArgs.push_back(Args.MakeArgString(
+ TC.getArch() == llvm::Triple::x86
+ ? "-include:___asan_seh_interceptor"
+ : "-include:__asan_seh_interceptor"));
+ // Make sure the linker consider all object files from the dynamic runtime
+ // thunk.
+ CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
+ TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
+ } else if (DLL) {
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
+ } else {
+ for (const auto &Lib : {"asan", "asan_cxx"}) {
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
+ // Make sure the linker consider all object files from the static lib.
+ // This is necessary because instrumented dlls need access to all the
+ // interface exported by the static lib in the main executable.
+ CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
+ TC.getCompilerRT(Args, Lib)));
+ }
+ }
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
+
+ if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
+ options::OPT_fno_openmp, false)) {
+ CmdArgs.push_back("-nodefaultlib:vcomp.lib");
+ CmdArgs.push_back("-nodefaultlib:vcompd.lib");
+ CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
+ TC.getDriver().Dir + "/../lib"));
+ switch (TC.getDriver().getOpenMPRuntime(Args)) {
+ case Driver::OMPRT_OMP:
+ CmdArgs.push_back("-defaultlib:libomp.lib");
+ break;
+ case Driver::OMPRT_IOMP5:
+ CmdArgs.push_back("-defaultlib:libiomp5md.lib");
+ break;
+ case Driver::OMPRT_GOMP:
+ break;
+ case Driver::OMPRT_Unknown:
+ // Already diagnosed.
+ break;
+ }
+ }
+
+ // Add compiler-rt lib in case if it was explicitly
+ // specified as an argument for --rtlib option.
+ if (!Args.hasArg(options::OPT_nostdlib)) {
+ AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);
+ }
+
+ // Add filenames, libraries, and other linker inputs.
+ for (const auto &Input : Inputs) {
+ if (Input.isFilename()) {
+ CmdArgs.push_back(Input.getFilename());
+ continue;
+ }
+
+ const Arg &A = Input.getInputArg();
+
+ // Render -l options differently for the MSVC linker.
+ if (A.getOption().matches(options::OPT_l)) {
+ StringRef Lib = A.getValue();
+ const char *LinkLibArg;
+ if (Lib.endswith(".lib"))
+ LinkLibArg = Args.MakeArgString(Lib);
+ else
+ LinkLibArg = Args.MakeArgString(Lib + ".lib");
+ CmdArgs.push_back(LinkLibArg);
+ continue;
+ }
+
+ // Otherwise, this is some other kind of linker input option like -Wl, -z,
+ // or -L. Render it, even if MSVC doesn't understand it.
+ A.renderAsInput(Args, CmdArgs);
+ }
+
+ TC.addProfileRTLibs(Args, CmdArgs);
+
+ std::vector<const char *> Environment;
+
+ // We need to special case some linker paths. In the case of lld, we need to
+ // translate 'lld' into 'lld-link', and in the case of the regular msvc
+ // linker, we need to use a special search algorithm.
+ llvm::SmallString<128> linkPath;
+ StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link");
+ if (Linker.equals_lower("lld"))
+ Linker = "lld-link";
+
+ if (Linker.equals_lower("link")) {
+ // If we're using the MSVC linker, it's not sufficient to just use link
+ // from the program PATH, because other environments like GnuWin32 install
+ // their own link.exe which may come first.
+ linkPath = FindVisualStudioExecutable(TC, "link.exe");
+
+#ifdef USE_WIN32
+ // When cross-compiling with VS2017 or newer, link.exe expects to have
+ // its containing bin directory at the top of PATH, followed by the
+ // native target bin directory.
+ // e.g. when compiling for x86 on an x64 host, PATH should start with:
+ // /bin/HostX64/x86;/bin/HostX64/x64
+ // This doesn't attempt to handle ToolsetLayout::DevDivInternal.
+ if (TC.getIsVS2017OrNewer() &&
+ llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
+ auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
+
+ auto EnvBlockWide =
+ std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(
+ GetEnvironmentStringsW(), FreeEnvironmentStringsW);
+ if (!EnvBlockWide)
+ goto SkipSettingEnvironment;
+
+ size_t EnvCount = 0;
+ size_t EnvBlockLen = 0;
+ while (EnvBlockWide[EnvBlockLen] != L'\0') {
+ ++EnvCount;
+ EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) +
+ 1 /*string null-terminator*/;
+ }
+ ++EnvBlockLen; // add the block null-terminator
+
+ std::string EnvBlock;
+ if (!llvm::convertUTF16ToUTF8String(
+ llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),
+ EnvBlockLen * sizeof(EnvBlockWide[0])),
+ EnvBlock))
+ goto SkipSettingEnvironment;
+
+ Environment.reserve(EnvCount);
+
+ // Now loop over each string in the block and copy them into the
+ // environment vector, adjusting the PATH variable as needed when we
+ // find it.
+ for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
+ llvm::StringRef EnvVar(Cursor);
+ if (EnvVar.startswith_lower("path=")) {
+ using SubDirectoryType = toolchains::MSVCToolChain::SubDirectoryType;
+ constexpr size_t PrefixLen = 5; // strlen("path=")
+ Environment.push_back(Args.MakeArgString(
+ EnvVar.substr(0, PrefixLen) +
+ TC.getSubDirectoryPath(SubDirectoryType::Bin) +
+ llvm::Twine(llvm::sys::EnvPathSeparator) +
+ TC.getSubDirectoryPath(SubDirectoryType::Bin, HostArch) +
+ (EnvVar.size() > PrefixLen
+ ? llvm::Twine(llvm::sys::EnvPathSeparator) +
+ EnvVar.substr(PrefixLen)
+ : "")));
+ } else {
+ Environment.push_back(Args.MakeArgString(EnvVar));
+ }
+ Cursor += EnvVar.size() + 1 /*null-terminator*/;
+ }
+ }
+ SkipSettingEnvironment:;
+#endif
+ } else {
+ linkPath = TC.GetProgramPath(Linker.str().c_str());
+ }
+
+ auto LinkCmd = llvm::make_unique<Command>(
+ JA, *this, Args.MakeArgString(linkPath), CmdArgs, Inputs);
+ if (!Environment.empty())
+ LinkCmd->setEnvironment(Environment);
+ C.addCommand(std::move(LinkCmd));
+}
+
+void visualstudio::Compiler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput));
+}
+
+std::unique_ptr<Command> visualstudio::Compiler::GetCommand(
+ Compilation &C, const JobAction &JA, const InputInfo &Output,
+ const InputInfoList &Inputs, const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+ CmdArgs.push_back("/nologo");
+ CmdArgs.push_back("/c"); // Compile only.
+ CmdArgs.push_back("/W0"); // No warnings.
+
+ // The goal is to be able to invoke this tool correctly based on
+ // any flag accepted by clang-cl.
+
+ // These are spelled the same way in clang and cl.exe,.
+ Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I});
+
+ // Optimization level.
+ if (Arg *A = Args.getLastArg(options::OPT_fbuiltin, options::OPT_fno_builtin))
+ CmdArgs.push_back(A->getOption().getID() == options::OPT_fbuiltin ? "/Oi"
+ : "/Oi-");
+ if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) {
+ if (A->getOption().getID() == options::OPT_O0) {
+ CmdArgs.push_back("/Od");
+ } else {
+ CmdArgs.push_back("/Og");
+
+ StringRef OptLevel = A->getValue();
+ if (OptLevel == "s" || OptLevel == "z")
+ CmdArgs.push_back("/Os");
+ else
+ CmdArgs.push_back("/Ot");
+
+ CmdArgs.push_back("/Ob2");
+ }
+ }
+ if (Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer,
+ options::OPT_fno_omit_frame_pointer))
+ CmdArgs.push_back(A->getOption().getID() == options::OPT_fomit_frame_pointer
+ ? "/Oy"
+ : "/Oy-");
+ if (!Args.hasArg(options::OPT_fwritable_strings))
+ CmdArgs.push_back("/GF");
+
+ // Flags for which clang-cl has an alias.
+ // FIXME: How can we ensure this stays in sync with relevant clang-cl options?
+
+ if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR,
+ /*default=*/false))
+ CmdArgs.push_back("/GR-");
+
+ if (Args.hasFlag(options::OPT__SLASH_GS_, options::OPT__SLASH_GS,
+ /*default=*/false))
+ CmdArgs.push_back("/GS-");
+
+ if (Arg *A = Args.getLastArg(options::OPT_ffunction_sections,
+ options::OPT_fno_function_sections))
+ CmdArgs.push_back(A->getOption().getID() == options::OPT_ffunction_sections
+ ? "/Gy"
+ : "/Gy-");
+ if (Arg *A = Args.getLastArg(options::OPT_fdata_sections,
+ options::OPT_fno_data_sections))
+ CmdArgs.push_back(
+ A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-");
+ if (Args.hasArg(options::OPT_fsyntax_only))
+ CmdArgs.push_back("/Zs");
+ if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only,
+ options::OPT__SLASH_Z7))
+ CmdArgs.push_back("/Z7");
+
+ std::vector<std::string> Includes =
+ Args.getAllArgValues(options::OPT_include);
+ for (const auto &Include : Includes)
+ CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Include));
+
+ // Flags that can simply be passed through.
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD);
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd);
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX);
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX_);
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH);
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_Zl);
+
+ // The order of these flags is relevant, so pick the last one.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd,
+ options::OPT__SLASH_MT, options::OPT__SLASH_MTd))
+ A->render(Args, CmdArgs);
+
+ // Use MSVC's default threadsafe statics behaviour unless there was a flag.
+ if (Arg *A = Args.getLastArg(options::OPT_fthreadsafe_statics,
+ options::OPT_fno_threadsafe_statics)) {
+ CmdArgs.push_back(A->getOption().getID() == options::OPT_fthreadsafe_statics
+ ? "/Zc:threadSafeInit"
+ : "/Zc:threadSafeInit-");
+ }
+
+ // Pass through all unknown arguments so that the fallback command can see
+ // them too.
+ Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN);
+
+ // Input filename.
+ assert(Inputs.size() == 1);
+ const InputInfo &II = Inputs[0];
+ assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX);
+ CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp");
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ II.getInputArg().renderAsInput(Args, CmdArgs);
+
+ // Output filename.
+ assert(Output.getType() == types::TY_Object);
+ const char *Fo =
+ Args.MakeArgString(std::string("/Fo") + Output.getFilename());
+ CmdArgs.push_back(Fo);
+
+ std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe");
+ return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ CmdArgs, Inputs);
+}
+
+MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+
+ // Check the environment first, since that's probably the user telling us
+ // what they want to use.
+ // Failing that, just try to find the newest Visual Studio version we can
+ // and use its default VC toolchain.
+ findVCToolChainViaEnvironment(VCToolChainPath, VSLayout) ||
+ findVCToolChainViaSetupConfig(VCToolChainPath, VSLayout) ||
+ findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
+}
+
+Tool *MSVCToolChain::buildLinker() const {
+ if (VCToolChainPath.empty())
+ getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
+ return new tools::visualstudio::Linker(*this);
+}
+
+Tool *MSVCToolChain::buildAssembler() const {
+ if (getTriple().isOSBinFormatMachO())
+ return new tools::darwin::Assembler(*this);
+ getDriver().Diag(clang::diag::err_no_external_assembler);
+ return nullptr;
+}
+
+bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
+ return true;
+}
+
+bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
+ // Emit unwind tables by default on Win64. All non-x86_32 Windows platforms
+ // such as ARM and PPC actually require unwind tables, but LLVM doesn't know
+ // how to generate them yet.
+
+ // Don't emit unwind tables by default for MachO targets.
+ if (getTriple().isOSBinFormatMachO())
+ return false;
+
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool MSVCToolChain::isPICDefault() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool MSVCToolChain::isPIEDefault() const {
+ return false;
+}
+
+bool MSVCToolChain::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+}
+
+void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
+ CudaInstallation.print(OS);
+}
+
+// Windows SDKs and VC Toolchains group their contents into subdirectories based
+// on the target architecture. This function converts an llvm::Triple::ArchType
+// to the corresponding subdirectory name.
+static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) {
+ using ArchType = llvm::Triple::ArchType;
+ switch (Arch) {
+ case ArchType::x86:
+ return "x86";
+ case ArchType::x86_64:
+ return "x64";
+ case ArchType::arm:
+ return "arm";
+ default:
+ return "";
+ }
+}
+
+// Similar to the above function, but for Visual Studios before VS2017.
+static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) {
+ using ArchType = llvm::Triple::ArchType;
+ switch (Arch) {
+ case ArchType::x86:
+ // x86 is default in legacy VC toolchains.
+ // e.g. x86 libs are directly in /lib as opposed to /lib/x86.
+ return "";
+ case ArchType::x86_64:
+ return "amd64";
+ case ArchType::arm:
+ return "arm";
+ default:
+ return "";
+ }
+}
+
+// Similar to the above function, but for DevDiv internal builds.
+static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) {
+ using ArchType = llvm::Triple::ArchType;
+ switch (Arch) {
+ case ArchType::x86:
+ return "i386";
+ case ArchType::x86_64:
+ return "amd64";
+ case ArchType::arm:
+ return "arm";
+ default:
+ return "";
+ }
+}
+
+// Get the path to a specific subdirectory in the current toolchain for
+// a given target architecture.
+// VS2017 changed the VC toolchain layout, so this should be used instead
+// of hardcoding paths.
+std::string
+MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
+ llvm::Triple::ArchType TargetArch) const {
+ const char *SubdirName;
+ const char *IncludeName;
+ switch (VSLayout) {
+ case ToolsetLayout::OlderVS:
+ SubdirName = llvmArchToLegacyVCArch(TargetArch);
+ IncludeName = "include";
+ break;
+ case ToolsetLayout::VS2017OrNewer:
+ SubdirName = llvmArchToWindowsSDKArch(TargetArch);
+ IncludeName = "include";
+ break;
+ case ToolsetLayout::DevDivInternal:
+ SubdirName = llvmArchToDevDivInternalArch(TargetArch);
+ IncludeName = "inc";
+ break;
+ }
+
+ llvm::SmallString<256> Path(VCToolChainPath);
+ switch (Type) {
+ case SubDirectoryType::Bin:
+ if (VSLayout == ToolsetLayout::VS2017OrNewer) {
+ const bool HostIsX64 =
+ llvm::Triple(llvm::sys::getProcessTriple()).isArch64Bit();
+ const char *const HostName = HostIsX64 ? "HostX64" : "HostX86";
+ llvm::sys::path::append(Path, "bin", HostName, SubdirName);
+ } else { // OlderVS or DevDivInternal
+ llvm::sys::path::append(Path, "bin", SubdirName);
+ }
+ break;
+ case SubDirectoryType::Include:
+ llvm::sys::path::append(Path, IncludeName);
+ break;
+ case SubDirectoryType::Lib:
+ llvm::sys::path::append(Path, "lib", SubdirName);
+ break;
+ }
+ return Path.str();
+}
+
+#ifdef USE_WIN32
+static bool readFullStringValue(HKEY hkey, const char *valueName,
+ std::string &value) {
+ std::wstring WideValueName;
+ if (!llvm::ConvertUTF8toWide(valueName, WideValueName))
+ return false;
+
+ DWORD result = 0;
+ DWORD valueSize = 0;
+ DWORD type = 0;
+ // First just query for the required size.
+ result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, &type, NULL,
+ &valueSize);
+ if (result != ERROR_SUCCESS || type != REG_SZ || !valueSize)
+ return false;
+ std::vector<BYTE> buffer(valueSize);
+ result = RegQueryValueExW(hkey, WideValueName.c_str(), NULL, NULL, &buffer[0],
+ &valueSize);
+ if (result == ERROR_SUCCESS) {
+ std::wstring WideValue(reinterpret_cast<const wchar_t *>(buffer.data()),
+ valueSize / sizeof(wchar_t));
+ if (valueSize && WideValue.back() == L'\0') {
+ WideValue.pop_back();
+ }
+ // The destination buffer must be empty as an invariant of the conversion
+ // function; but this function is sometimes called in a loop that passes in
+ // the same buffer, however. Simply clear it out so we can overwrite it.
+ value.clear();
+ return llvm::convertWideToUTF8(WideValue, value);
+ }
+ return false;
+}
+#endif
+
+/// \brief Read registry string.
+/// This also supports a means to look for high-versioned keys by use
+/// of a $VERSION placeholder in the key path.
+/// $VERSION in the key path is a placeholder for the version number,
+/// causing the highest value path to be searched for and used.
+/// I.e. "SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
+/// There can be additional characters in the component. Only the numeric
+/// characters are compared. This function only searches HKLM.
+static bool getSystemRegistryString(const char *keyPath, const char *valueName,
+ std::string &value, std::string *phValue) {
+#ifndef USE_WIN32
+ return false;
+#else
+ HKEY hRootKey = HKEY_LOCAL_MACHINE;
+ HKEY hKey = NULL;
+ long lResult;
+ bool returnValue = false;
+
+ const char *placeHolder = strstr(keyPath, "$VERSION");
+ std::string bestName;
+ // If we have a $VERSION placeholder, do the highest-version search.
+ if (placeHolder) {
+ const char *keyEnd = placeHolder - 1;
+ const char *nextKey = placeHolder;
+ // Find end of previous key.
+ while ((keyEnd > keyPath) && (*keyEnd != '\\'))
+ keyEnd--;
+ // Find end of key containing $VERSION.
+ while (*nextKey && (*nextKey != '\\'))
+ nextKey++;
+ size_t partialKeyLength = keyEnd - keyPath;
+ char partialKey[256];
+ if (partialKeyLength >= sizeof(partialKey))
+ partialKeyLength = sizeof(partialKey) - 1;
+ strncpy(partialKey, keyPath, partialKeyLength);
+ partialKey[partialKeyLength] = '\0';
+ HKEY hTopKey = NULL;
+ lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ | KEY_WOW64_32KEY,
+ &hTopKey);
+ if (lResult == ERROR_SUCCESS) {
+ char keyName[256];
+ double bestValue = 0.0;
+ DWORD index, size = sizeof(keyName) - 1;
+ for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, NULL,
+ NULL, NULL) == ERROR_SUCCESS;
+ index++) {
+ const char *sp = keyName;
+ while (*sp && !isDigit(*sp))
+ sp++;
+ if (!*sp)
+ continue;
+ const char *ep = sp + 1;
+ while (*ep && (isDigit(*ep) || (*ep == '.')))
+ ep++;
+ char numBuf[32];
+ strncpy(numBuf, sp, sizeof(numBuf) - 1);
+ numBuf[sizeof(numBuf) - 1] = '\0';
+ double dvalue = strtod(numBuf, NULL);
+ if (dvalue > bestValue) {
+ // Test that InstallDir is indeed there before keeping this index.
+ // Open the chosen key path remainder.
+ bestName = keyName;
+ // Append rest of key.
+ bestName.append(nextKey);
+ lResult = RegOpenKeyExA(hTopKey, bestName.c_str(), 0,
+ KEY_READ | KEY_WOW64_32KEY, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ if (readFullStringValue(hKey, valueName, value)) {
+ bestValue = dvalue;
+ if (phValue)
+ *phValue = bestName;
+ returnValue = true;
+ }
+ RegCloseKey(hKey);
+ }
+ }
+ size = sizeof(keyName) - 1;
+ }
+ RegCloseKey(hTopKey);
+ }
+ } else {
+ lResult =
+ RegOpenKeyExA(hRootKey, keyPath, 0, KEY_READ | KEY_WOW64_32KEY, &hKey);
+ if (lResult == ERROR_SUCCESS) {
+ if (readFullStringValue(hKey, valueName, value))
+ returnValue = true;
+ if (phValue)
+ phValue->clear();
+ RegCloseKey(hKey);
+ }
+ }
+ return returnValue;
+#endif // USE_WIN32
+}
+
+// Find the most recent version of Universal CRT or Windows 10 SDK.
+// vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
+// directory by name and uses the last one of the list.
+// So we compare entry names lexicographically to find the greatest one.
+static bool getWindows10SDKVersionFromPath(const std::string &SDKPath,
+ std::string &SDKVersion) {
+ SDKVersion.clear();
+
+ std::error_code EC;
+ llvm::SmallString<128> IncludePath(SDKPath);
+ llvm::sys::path::append(IncludePath, "Include");
+ for (llvm::sys::fs::directory_iterator DirIt(IncludePath, EC), DirEnd;
+ DirIt != DirEnd && !EC; DirIt.increment(EC)) {
+ if (!llvm::sys::fs::is_directory(DirIt->path()))
+ continue;
+ StringRef CandidateName = llvm::sys::path::filename(DirIt->path());
+ // If WDK is installed, there could be subfolders like "wdf" in the
+ // "Include" directory.
+ // Allow only directories which names start with "10.".
+ if (!CandidateName.startswith("10."))
+ continue;
+ if (CandidateName > SDKVersion)
+ SDKVersion = CandidateName;
+ }
+
+ return !SDKVersion.empty();
+}
+
+/// \brief Get Windows SDK installation directory.
+static bool getWindowsSDKDir(std::string &Path, int &Major,
+ std::string &WindowsSDKIncludeVersion,
+ std::string &WindowsSDKLibVersion) {
+ std::string RegistrySDKVersion;
+ // Try the Windows registry.
+ if (!getSystemRegistryString(
+ "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION",
+ "InstallationFolder", Path, &RegistrySDKVersion))
+ return false;
+ if (Path.empty() || RegistrySDKVersion.empty())
+ return false;
+
+ WindowsSDKIncludeVersion.clear();
+ WindowsSDKLibVersion.clear();
+ Major = 0;
+ std::sscanf(RegistrySDKVersion.c_str(), "v%d.", &Major);
+ if (Major <= 7)
+ return true;
+ if (Major == 8) {
+ // Windows SDK 8.x installs libraries in a folder whose names depend on the
+ // version of the OS you're targeting. By default choose the newest, which
+ // usually corresponds to the version of the OS you've installed the SDK on.
+ const char *Tests[] = {"winv6.3", "win8", "win7"};
+ for (const char *Test : Tests) {
+ llvm::SmallString<128> TestPath(Path);
+ llvm::sys::path::append(TestPath, "Lib", Test);
+ if (llvm::sys::fs::exists(TestPath.c_str())) {
+ WindowsSDKLibVersion = Test;
+ break;
+ }
+ }
+ return !WindowsSDKLibVersion.empty();
+ }
+ if (Major == 10) {
+ if (!getWindows10SDKVersionFromPath(Path, WindowsSDKIncludeVersion))
+ return false;
+ WindowsSDKLibVersion = WindowsSDKIncludeVersion;
+ return true;
+ }
+ // Unsupported SDK version
+ return false;
+}
+
+// Gets the library path required to link against the Windows SDK.
+bool MSVCToolChain::getWindowsSDKLibraryPath(std::string &path) const {
+ std::string sdkPath;
+ int sdkMajor = 0;
+ std::string windowsSDKIncludeVersion;
+ std::string windowsSDKLibVersion;
+
+ path.clear();
+ if (!getWindowsSDKDir(sdkPath, sdkMajor, windowsSDKIncludeVersion,
+ windowsSDKLibVersion))
+ return false;
+
+ llvm::SmallString<128> libPath(sdkPath);
+ llvm::sys::path::append(libPath, "Lib");
+ if (sdkMajor >= 8) {
+ llvm::sys::path::append(libPath, windowsSDKLibVersion, "um",
+ llvmArchToWindowsSDKArch(getArch()));
+ } else {
+ switch (getArch()) {
+ // In Windows SDK 7.x, x86 libraries are directly in the Lib folder.
+ case llvm::Triple::x86:
+ break;
+ case llvm::Triple::x86_64:
+ llvm::sys::path::append(libPath, "x64");
+ break;
+ case llvm::Triple::arm:
+ // It is not necessary to link against Windows SDK 7.x when targeting ARM.
+ return false;
+ default:
+ return false;
+ }
+ }
+
+ path = libPath.str();
+ return true;
+}
+
+// Check if the Include path of a specified version of Visual Studio contains
+// specific header files. If not, they are probably shipped with Universal CRT.
+bool MSVCToolChain::useUniversalCRT() const {
+ llvm::SmallString<128> TestPath(
+ getSubDirectoryPath(SubDirectoryType::Include));
+ llvm::sys::path::append(TestPath, "stdlib.h");
+ return !llvm::sys::fs::exists(TestPath);
+}
+
+static bool getUniversalCRTSdkDir(std::string &Path, std::string &UCRTVersion) {
+ // vcvarsqueryregistry.bat for Visual Studio 2015 queries the registry
+ // for the specific key "KitsRoot10". So do we.
+ if (!getSystemRegistryString(
+ "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10",
+ Path, nullptr))
+ return false;
+
+ return getWindows10SDKVersionFromPath(Path, UCRTVersion);
+}
+
+bool MSVCToolChain::getUniversalCRTLibraryPath(std::string &Path) const {
+ std::string UniversalCRTSdkPath;
+ std::string UCRTVersion;
+
+ Path.clear();
+ if (!getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion))
+ return false;
+
+ StringRef ArchName = llvmArchToWindowsSDKArch(getArch());
+ if (ArchName.empty())
+ return false;
+
+ llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
+ llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
+
+ Path = LibPath.str();
+ return true;
+}
+
+static VersionTuple getMSVCVersionFromTriple(const llvm::Triple &Triple) {
+ unsigned Major, Minor, Micro;
+ Triple.getEnvironmentVersion(Major, Minor, Micro);
+ if (Major || Minor || Micro)
+ return VersionTuple(Major, Minor, Micro);
+ return VersionTuple();
+}
+
+static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
+ VersionTuple Version;
+#ifdef USE_WIN32
+ SmallString<128> ClExe(BinDir);
+ llvm::sys::path::append(ClExe, "cl.exe");
+
+ std::wstring ClExeWide;
+ if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))
+ return Version;
+
+ const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
+ nullptr);
+ if (VersionSize == 0)
+ return Version;
+
+ SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);
+ if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,
+ VersionBlock.data()))
+ return Version;
+
+ VS_FIXEDFILEINFO *FileInfo = nullptr;
+ UINT FileInfoSize = 0;
+ if (!::VerQueryValueW(VersionBlock.data(), L"\\",
+ reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) ||
+ FileInfoSize < sizeof(*FileInfo))
+ return Version;
+
+ const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;
+ const unsigned Minor = (FileInfo->dwFileVersionMS ) & 0xFFFF;
+ const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;
+
+ Version = VersionTuple(Major, Minor, Micro);
+#endif
+ return Version;
+}
+
+void MSVCToolChain::AddSystemIncludeWithSubfolder(
+ const ArgList &DriverArgs, ArgStringList &CC1Args,
+ const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,
+ const Twine &subfolder3) const {
+ llvm::SmallString<128> path(folder);
+ llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3);
+ addSystemInclude(DriverArgs, CC1Args, path);
+}
+
+void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,
+ "include");
+ }
+
+ // Add %INCLUDE%-like directories from the -imsvc flag.
+ for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
+ addSystemInclude(DriverArgs, CC1Args, Path);
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
+ if (llvm::Optional<std::string> cl_include_dir =
+ llvm::sys::Process::GetEnv("INCLUDE")) {
+ SmallVector<StringRef, 8> Dirs;
+ StringRef(*cl_include_dir)
+ .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ for (StringRef Dir : Dirs)
+ addSystemInclude(DriverArgs, CC1Args, Dir);
+ if (!Dirs.empty())
+ return;
+ }
+
+ // When built with access to the proper Windows APIs, try to actually find
+ // the correct include paths first.
+ if (!VCToolChainPath.empty()) {
+ addSystemInclude(DriverArgs, CC1Args,
+ getSubDirectoryPath(SubDirectoryType::Include));
+
+ if (useUniversalCRT()) {
+ std::string UniversalCRTSdkPath;
+ std::string UCRTVersion;
+ if (getUniversalCRTSdkDir(UniversalCRTSdkPath, UCRTVersion)) {
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
+ "Include", UCRTVersion, "ucrt");
+ }
+ }
+
+ std::string WindowsSDKDir;
+ int major;
+ std::string windowsSDKIncludeVersion;
+ std::string windowsSDKLibVersion;
+ if (getWindowsSDKDir(WindowsSDKDir, major, windowsSDKIncludeVersion,
+ windowsSDKLibVersion)) {
+ if (major >= 8) {
+ // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
+ // Anyway, llvm::sys::path::append is able to manage it.
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
+ "include", windowsSDKIncludeVersion,
+ "shared");
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
+ "include", windowsSDKIncludeVersion,
+ "um");
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
+ "include", windowsSDKIncludeVersion,
+ "winrt");
+ } else {
+ AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
+ "include");
+ }
+ }
+
+ return;
+ }
+
+#if defined(LLVM_ON_WIN32)
+ // As a fallback, select default install paths.
+ // FIXME: Don't guess drives and paths like this on Windows.
+ const StringRef Paths[] = {
+ "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
+ "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
+ "C:/Program Files/Microsoft Visual Studio 8/VC/include",
+ "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
+ };
+ addSystemIncludes(DriverArgs, CC1Args, Paths);
+#endif
+}
+
+void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ // FIXME: There should probably be logic here to find libc++ on Windows.
+}
+
+VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
+ const ArgList &Args) const {
+ bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
+ VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
+ if (MSVT.empty())
+ MSVT = getMSVCVersionFromTriple(getTriple());
+ if (MSVT.empty() && IsWindowsMSVC)
+ MSVT = getMSVCVersionFromExe(getSubDirectoryPath(SubDirectoryType::Bin));
+ if (MSVT.empty() &&
+ Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
+ IsWindowsMSVC)) {
+ // -fms-compatibility-version=18.00 is default.
+ // FIXME: Consider bumping this to 19 (MSVC2015) soon.
+ MSVT = VersionTuple(18);
+ }
+ return MSVT;
+}
+
+std::string
+MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const {
+ // The MSVC version doesn't care about the architecture, even though it
+ // may look at the triple internally.
+ VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);
+ MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().getValueOr(0),
+ MSVT.getSubminor().getValueOr(0));
+
+ // For the rest of the triple, however, a computed architecture name may
+ // be needed.
+ llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));
+ if (Triple.getEnvironment() == llvm::Triple::MSVC) {
+ StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;
+ if (ObjFmt.empty())
+ Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());
+ else
+ Triple.setEnvironmentName(
+ (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str());
+ }
+ return Triple.getTriple();
+}
+
+SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::Address;
+ return Res;
+}
+
+static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
+ bool SupportsForcingFramePointer,
+ const char *ExpandChar, const OptTable &Opts) {
+ assert(A->getOption().matches(options::OPT__SLASH_O));
+
+ StringRef OptStr = A->getValue();
+ for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
+ const char &OptChar = *(OptStr.data() + I);
+ switch (OptChar) {
+ default:
+ break;
+ case '1':
+ case '2':
+ case 'x':
+ case 'd':
+ if (&OptChar == ExpandChar) {
+ if (OptChar == 'd') {
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
+ } else {
+ if (OptChar == '1') {
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
+ } else if (OptChar == '2' || OptChar == 'x') {
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
+ }
+ if (SupportsForcingFramePointer &&
+ !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))
+ DAL.AddFlagArg(A,
+ Opts.getOption(options::OPT_fomit_frame_pointer));
+ if (OptChar == '1' || OptChar == '2')
+ DAL.AddFlagArg(A,
+ Opts.getOption(options::OPT_ffunction_sections));
+ }
+ }
+ break;
+ case 'b':
+ if (I + 1 != E && isdigit(OptStr[I + 1])) {
+ switch (OptStr[I + 1]) {
+ case '0':
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
+ break;
+ case '1':
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
+ break;
+ case '2':
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));
+ break;
+ }
+ ++I;
+ }
+ break;
+ case 'g':
+ break;
+ case 'i':
+ if (I + 1 != E && OptStr[I + 1] == '-') {
+ ++I;
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
+ } else {
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
+ }
+ break;
+ case 's':
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
+ break;
+ case 't':
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
+ break;
+ case 'y': {
+ bool OmitFramePointer = true;
+ if (I + 1 != E && OptStr[I + 1] == '-') {
+ OmitFramePointer = false;
+ ++I;
+ }
+ if (SupportsForcingFramePointer) {
+ if (OmitFramePointer)
+ DAL.AddFlagArg(A,
+ Opts.getOption(options::OPT_fomit_frame_pointer));
+ else
+ DAL.AddFlagArg(
+ A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
+ } else {
+ // Don't warn about /Oy- in 64-bit builds (where
+ // SupportsForcingFramePointer is false). The flag having no effect
+ // there is a compiler-internal optimization, and people shouldn't have
+ // to special-case their build files for 64-bit clang-cl.
+ A->claim();
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
+ const OptTable &Opts) {
+ assert(A->getOption().matches(options::OPT_D));
+
+ StringRef Val = A->getValue();
+ size_t Hash = Val.find('#');
+ if (Hash == StringRef::npos || Hash > Val.find('=')) {
+ DAL.append(A);
+ return;
+ }
+
+ std::string NewVal = Val;
+ NewVal[Hash] = '=';
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
+}
+
+llvm::opt::DerivedArgList *
+MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
+ StringRef BoundArch, Action::OffloadKind) const {
+ DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
+ const OptTable &Opts = getDriver().getOpts();
+
+ // /Oy and /Oy- only has an effect under X86-32.
+ bool SupportsForcingFramePointer = getArch() == llvm::Triple::x86;
+
+ // The -O[12xd] flag actually expands to several flags. We must desugar the
+ // flags so that options embedded can be negated. For example, the '-O2' flag
+ // enables '-Oy'. Expanding '-O2' into its constituent flags allows us to
+ // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single
+ // aspect of '-O2'.
+ //
+ // Note that this expansion logic only applies to the *last* of '[12xd]'.
+
+ // First step is to search for the character we'd like to expand.
+ const char *ExpandChar = nullptr;
+ for (Arg *A : Args) {
+ if (!A->getOption().matches(options::OPT__SLASH_O))
+ continue;
+ StringRef OptStr = A->getValue();
+ for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
+ char OptChar = OptStr[I];
+ char PrevChar = I > 0 ? OptStr[I - 1] : '0';
+ if (PrevChar == 'b') {
+ // OptChar does not expand; it's an argument to the previous char.
+ continue;
+ }
+ if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')
+ ExpandChar = OptStr.data() + I;
+ }
+ }
+
+ for (Arg *A : Args) {
+ if (A->getOption().matches(options::OPT__SLASH_O)) {
+ // The -O flag actually takes an amalgam of other options. For example,
+ // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
+ TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
+ } else if (A->getOption().matches(options::OPT_D)) {
+ // Translate -Dfoo#bar into -Dfoo=bar.
+ TranslateDArg(A, *DAL, Opts);
+ } else {
+ DAL->append(A);
+ }
+ }
+
+ return DAL;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.h
new file mode 100644
index 0000000..854f88a
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVC.h
@@ -0,0 +1,146 @@
+//===--- MSVC.h - MSVC ToolChain Implementations ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H
+
+#include "Cuda.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// Visual studio tools.
+namespace visualstudio {
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC)
+ : Tool("visualstudio::Linker", "linker", TC, RF_Full,
+ llvm::sys::WEM_UTF16) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Compiler : public Tool {
+public:
+ Compiler(const ToolChain &TC)
+ : Tool("visualstudio::Compiler", "compiler", TC, RF_Full,
+ llvm::sys::WEM_UTF16) {}
+
+ bool hasIntegratedAssembler() const override { return true; }
+ bool hasIntegratedCPP() const override { return true; }
+ bool isLinkJob() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+
+ std::unique_ptr<Command> GetCommand(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const;
+};
+} // end namespace visualstudio
+
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain {
+public:
+ MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
+ bool IsIntegratedAssemblerDefault() const override;
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+
+ enum class SubDirectoryType {
+ Bin,
+ Include,
+ Lib,
+ };
+ std::string getSubDirectoryPath(SubDirectoryType Type,
+ llvm::Triple::ArchType TargetArch) const;
+
+ // Convenience overload.
+ // Uses the current target arch.
+ std::string getSubDirectoryPath(SubDirectoryType Type) const {
+ return getSubDirectoryPath(Type, getArch());
+ }
+
+ enum class ToolsetLayout {
+ OlderVS,
+ VS2017OrNewer,
+ DevDivInternal,
+ };
+ bool getIsVS2017OrNewer() const { return VSLayout == ToolsetLayout::VS2017OrNewer; }
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ bool getWindowsSDKLibraryPath(std::string &path) const;
+ /// \brief Check if Universal CRT should be used if available
+ bool getUniversalCRTLibraryPath(std::string &path) const;
+ bool useUniversalCRT() const;
+ VersionTuple
+ computeMSVCVersion(const Driver *D,
+ const llvm::opt::ArgList &Args) const override;
+
+ std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
+ types::ID InputType) const override;
+ SanitizerMask getSupportedSanitizers() const override;
+
+ void printVerboseInfo(raw_ostream &OS) const override;
+
+protected:
+ void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ const std::string &folder,
+ const Twine &subfolder1,
+ const Twine &subfolder2 = "",
+ const Twine &subfolder3 = "") const;
+
+ Tool *buildLinker() const override;
+ Tool *buildAssembler() const override;
+private:
+ std::string VCToolChainPath;
+ ToolsetLayout VSLayout = ToolsetLayout::OlderVS;
+ CudaInstallationDetector CudaInstallation;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVCSetupApi.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVCSetupApi.h
new file mode 100644
index 0000000..a890b85
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MSVCSetupApi.h
@@ -0,0 +1,514 @@
+// <copyright file="Program.cpp" company="Microsoft Corporation">
+// Copyright (C) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+// </copyright>
+// <license>
+// The MIT License (MIT)
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// 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.
+// </license>
+
+#pragma once
+
+// Constants
+//
+#ifndef E_NOTFOUND
+#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
+#endif
+
+#ifndef E_FILENOTFOUND
+#define E_FILENOTFOUND HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
+#endif
+
+// Enumerations
+//
+/// <summary>
+/// The state of an instance.
+/// </summary>
+enum InstanceState : unsigned {
+ /// <summary>
+ /// The instance state has not been determined.
+ /// </summary>
+ eNone = 0,
+
+ /// <summary>
+ /// The instance installation path exists.
+ /// </summary>
+ eLocal = 1,
+
+ /// <summary>
+ /// A product is registered to the instance.
+ /// </summary>
+ eRegistered = 2,
+
+ /// <summary>
+ /// No reboot is required for the instance.
+ /// </summary>
+ eNoRebootRequired = 4,
+
+ /// <summary>
+ /// The instance represents a complete install.
+ /// </summary>
+ eComplete = MAXUINT,
+};
+
+// Forward interface declarations
+//
+#ifndef __ISetupInstance_FWD_DEFINED__
+#define __ISetupInstance_FWD_DEFINED__
+typedef struct ISetupInstance ISetupInstance;
+#endif
+
+#ifndef __ISetupInstance2_FWD_DEFINED__
+#define __ISetupInstance2_FWD_DEFINED__
+typedef struct ISetupInstance2 ISetupInstance2;
+#endif
+
+#ifndef __IEnumSetupInstances_FWD_DEFINED__
+#define __IEnumSetupInstances_FWD_DEFINED__
+typedef struct IEnumSetupInstances IEnumSetupInstances;
+#endif
+
+#ifndef __ISetupConfiguration_FWD_DEFINED__
+#define __ISetupConfiguration_FWD_DEFINED__
+typedef struct ISetupConfiguration ISetupConfiguration;
+#endif
+
+#ifndef __ISetupConfiguration2_FWD_DEFINED__
+#define __ISetupConfiguration2_FWD_DEFINED__
+typedef struct ISetupConfiguration2 ISetupConfiguration2;
+#endif
+
+#ifndef __ISetupPackageReference_FWD_DEFINED__
+#define __ISetupPackageReference_FWD_DEFINED__
+typedef struct ISetupPackageReference ISetupPackageReference;
+#endif
+
+#ifndef __ISetupHelper_FWD_DEFINED__
+#define __ISetupHelper_FWD_DEFINED__
+typedef struct ISetupHelper ISetupHelper;
+#endif
+
+// Forward class declarations
+//
+#ifndef __SetupConfiguration_FWD_DEFINED__
+#define __SetupConfiguration_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class SetupConfiguration SetupConfiguration;
+#endif
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Interface definitions
+//
+EXTERN_C const IID IID_ISetupInstance;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Information about an instance of a product.
+/// </summary>
+struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E")
+ DECLSPEC_NOVTABLE ISetupInstance : public IUnknown {
+ /// <summary>
+ /// Gets the instance identifier (should match the name of the parent instance
+ /// directory).
+ /// </summary>
+ /// <param name="pbstrInstanceId">The instance identifier.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist.</returns>
+ STDMETHOD(GetInstanceId)(_Out_ BSTR *pbstrInstanceId) = 0;
+
+ /// <summary>
+ /// Gets the local date and time when the installation was originally
+ /// installed.
+ /// </summary>
+ /// <param name="pInstallDate">The local date and time when the installation
+ /// was originally installed.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
+ /// property is not defined.</returns>
+ STDMETHOD(GetInstallDate)(_Out_ LPFILETIME pInstallDate) = 0;
+
+ /// <summary>
+ /// Gets the unique name of the installation, often indicating the branch and
+ /// other information used for telemetry.
+ /// </summary>
+ /// <param name="pbstrInstallationName">The unique name of the installation,
+ /// often indicating the branch and other information used for
+ /// telemetry.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
+ /// property is not defined.</returns>
+ STDMETHOD(GetInstallationName)(_Out_ BSTR *pbstrInstallationName) = 0;
+
+ /// <summary>
+ /// Gets the path to the installation root of the product.
+ /// </summary>
+ /// <param name="pbstrInstallationPath">The path to the installation root of
+ /// the product.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
+ /// property is not defined.</returns>
+ STDMETHOD(GetInstallationPath)(_Out_ BSTR *pbstrInstallationPath) = 0;
+
+ /// <summary>
+ /// Gets the version of the product installed in this instance.
+ /// </summary>
+ /// <param name="pbstrInstallationVersion">The version of the product
+ /// installed in this instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
+ /// property is not defined.</returns>
+ STDMETHOD(GetInstallationVersion)(_Out_ BSTR *pbstrInstallationVersion) = 0;
+
+ /// <summary>
+ /// Gets the display name (title) of the product installed in this instance.
+ /// </summary>
+ /// <param name="lcid">The LCID for the display name.</param>
+ /// <param name="pbstrDisplayName">The display name (title) of the product
+ /// installed in this instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
+ /// property is not defined.</returns>
+ STDMETHOD(GetDisplayName)(_In_ LCID lcid, _Out_ BSTR *pbstrDisplayName) = 0;
+
+ /// <summary>
+ /// Gets the description of the product installed in this instance.
+ /// </summary>
+ /// <param name="lcid">The LCID for the description.</param>
+ /// <param name="pbstrDescription">The description of the product installed in
+ /// this instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
+ /// property is not defined.</returns>
+ STDMETHOD(GetDescription)(_In_ LCID lcid, _Out_ BSTR *pbstrDescription) = 0;
+
+ /// <summary>
+ /// Resolves the optional relative path to the root path of the instance.
+ /// </summary>
+ /// <param name="pwszRelativePath">A relative path within the instance to
+ /// resolve, or NULL to get the root path.</param>
+ /// <param name="pbstrAbsolutePath">The full path to the optional relative
+ /// path within the instance. If the relative path is NULL, the root path will
+ /// always terminate in a backslash.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
+ /// property is not defined.</returns>
+ STDMETHOD(ResolvePath)
+ (_In_opt_z_ LPCOLESTR pwszRelativePath, _Out_ BSTR *pbstrAbsolutePath) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupInstance2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Information about an instance of a product.
+/// </summary>
+struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C")
+ DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance {
+ /// <summary>
+ /// Gets the state of the instance.
+ /// </summary>
+ /// <param name="pState">The state of the instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist.</returns>
+ STDMETHOD(GetState)(_Out_ InstanceState *pState) = 0;
+
+ /// <summary>
+ /// Gets an array of package references registered to the instance.
+ /// </summary>
+ /// <param name="ppsaPackages">Pointer to an array of <see
+ /// cref="ISetupPackageReference"/>.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
+ /// packages property is not defined.</returns>
+ STDMETHOD(GetPackages)(_Out_ LPSAFEARRAY *ppsaPackages) = 0;
+
+ /// <summary>
+ /// Gets a pointer to the <see cref="ISetupPackageReference"/> that represents
+ /// the registered product.
+ /// </summary>
+ /// <param name="ppPackage">Pointer to an instance of <see
+ /// cref="ISetupPackageReference"/>. This may be NULL if <see
+ /// cref="GetState"/> does not return <see cref="eComplete"/>.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the
+ /// packages property is not defined.</returns>
+ STDMETHOD(GetProduct)
+ (_Outptr_result_maybenull_ ISetupPackageReference **ppPackage) = 0;
+
+ /// <summary>
+ /// Gets the relative path to the product application, if available.
+ /// </summary>
+ /// <param name="pbstrProductPath">The relative path to the product
+ /// application, if available.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_FILENOTFOUND if the instance state does not exist.</returns>
+ STDMETHOD(GetProductPath)
+ (_Outptr_result_maybenull_ BSTR *pbstrProductPath) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_IEnumSetupInstances;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// A enumerator of installed <see cref="ISetupInstance"/> objects.
+/// </summary>
+struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")
+ DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown {
+ /// <summary>
+ /// Retrieves the next set of product instances in the enumeration sequence.
+ /// </summary>
+ /// <param name="celt">The number of product instances to retrieve.</param>
+ /// <param name="rgelt">A pointer to an array of <see
+ /// cref="ISetupInstance"/>.</param>
+ /// <param name="pceltFetched">A pointer to the number of product instances
+ /// retrieved. If celt is 1 this parameter may be NULL.</param>
+ /// <returns>S_OK if the number of elements were fetched, S_FALSE if nothing
+ /// was fetched (at end of enumeration), E_INVALIDARG if celt is greater than
+ /// 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an <see
+ /// cref="ISetupInstance"/> could not be allocated.</returns>
+ STDMETHOD(Next)
+ (_In_ ULONG celt, _Out_writes_to_(celt, *pceltFetched) ISetupInstance **rgelt,
+ _Out_opt_ _Deref_out_range_(0, celt) ULONG *pceltFetched) = 0;
+
+ /// <summary>
+ /// Skips the next set of product instances in the enumeration sequence.
+ /// </summary>
+ /// <param name="celt">The number of product instances to skip.</param>
+ /// <returns>S_OK if the number of elements could be skipped; otherwise,
+ /// S_FALSE;</returns>
+ STDMETHOD(Skip)(_In_ ULONG celt) = 0;
+
+ /// <summary>
+ /// Resets the enumeration sequence to the beginning.
+ /// </summary>
+ /// <returns>Always returns S_OK;</returns>
+ STDMETHOD(Reset)(void) = 0;
+
+ /// <summary>
+ /// Creates a new enumeration object in the same state as the current
+ /// enumeration object: the new object points to the same place in the
+ /// enumeration sequence.
+ /// </summary>
+ /// <param name="ppenum">A pointer to a pointer to a new <see
+ /// cref="IEnumSetupInstances"/> interface. If the method fails, this
+ /// parameter is undefined.</param>
+ /// <returns>S_OK if a clone was returned; otherwise, E_OUTOFMEMORY.</returns>
+ STDMETHOD(Clone)(_Deref_out_opt_ IEnumSetupInstances **ppenum) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupConfiguration;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Gets information about product instances set up on the machine.
+/// </summary>
+struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B")
+ DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown {
+ /// <summary>
+ /// Enumerates all completed product instances installed.
+ /// </summary>
+ /// <param name="ppEnumInstances">An enumeration of completed, installed
+ /// product instances.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(EnumInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0;
+
+ /// <summary>
+ /// Gets the instance for the current process path.
+ /// </summary>
+ /// <param name="ppInstance">The instance for the current process
+ /// path.</param>
+ /// <returns>The instance for the current process path, or E_NOTFOUND if not
+ /// found.</returns>
+ STDMETHOD(GetInstanceForCurrentProcess)
+ (_Out_ ISetupInstance **ppInstance) = 0;
+
+ /// <summary>
+ /// Gets the instance for the given path.
+ /// </summary>
+ /// <param name="ppInstance">The instance for the given path.</param>
+ /// <returns>The instance for the given path, or E_NOTFOUND if not
+ /// found.</returns>
+ STDMETHOD(GetInstanceForPath)
+ (_In_z_ LPCWSTR wzPath, _Out_ ISetupInstance **ppInstance) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupConfiguration2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Gets information about product instances.
+/// </summary>
+struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")
+ DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration {
+ /// <summary>
+ /// Enumerates all product instances.
+ /// </summary>
+ /// <param name="ppEnumInstances">An enumeration of all product
+ /// instances.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(EnumAllInstances)(_Out_ IEnumSetupInstances **ppEnumInstances) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupPackageReference;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// A reference to a package.
+/// </summary>
+struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5")
+ DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown {
+ /// <summary>
+ /// Gets the general package identifier.
+ /// </summary>
+ /// <param name="pbstrId">The general package identifier.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetId)(_Out_ BSTR *pbstrId) = 0;
+
+ /// <summary>
+ /// Gets the version of the package.
+ /// </summary>
+ /// <param name="pbstrVersion">The version of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetVersion)(_Out_ BSTR *pbstrVersion) = 0;
+
+ /// <summary>
+ /// Gets the target process architecture of the package.
+ /// </summary>
+ /// <param name="pbstrChip">The target process architecture of the
+ /// package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetChip)(_Out_ BSTR *pbstrChip) = 0;
+
+ /// <summary>
+ /// Gets the language and optional region identifier.
+ /// </summary>
+ /// <param name="pbstrLanguage">The language and optional region
+ /// identifier.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetLanguage)(_Out_ BSTR *pbstrLanguage) = 0;
+
+ /// <summary>
+ /// Gets the build branch of the package.
+ /// </summary>
+ /// <param name="pbstrBranch">The build branch of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetBranch)(_Out_ BSTR *pbstrBranch) = 0;
+
+ /// <summary>
+ /// Gets the type of the package.
+ /// </summary>
+ /// <param name="pbstrType">The type of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetType)(_Out_ BSTR *pbstrType) = 0;
+
+ /// <summary>
+ /// Gets the unique identifier consisting of all defined tokens.
+ /// </summary>
+ /// <param name="pbstrUniqueId">The unique identifier consisting of all
+ /// defined tokens.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including
+ /// E_UNEXPECTED if no Id was defined (required).</returns>
+ STDMETHOD(GetUniqueId)(_Out_ BSTR *pbstrUniqueId) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupHelper;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Helper functions.
+/// </summary>
+/// <remarks>
+/// You can query for this interface from the <see cref="SetupConfiguration"/>
+/// class.
+/// </remarks>
+struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c")
+ DECLSPEC_NOVTABLE ISetupHelper : public IUnknown {
+ /// <summary>
+ /// Parses a dotted quad version string into a 64-bit unsigned integer.
+ /// </summary>
+ /// <param name="pwszVersion">The dotted quad version string to parse, e.g.
+ /// 1.2.3.4.</param>
+ /// <param name="pullVersion">A 64-bit unsigned integer representing the
+ /// version. You can compare this to other versions.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(ParseVersion)
+ (_In_ LPCOLESTR pwszVersion, _Out_ PULONGLONG pullVersion) = 0;
+
+ /// <summary>
+ /// Parses a dotted quad version string into a 64-bit unsigned integer.
+ /// </summary>
+ /// <param name="pwszVersionRange">The string containing 1 or 2 dotted quad
+ /// version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer.</param>
+ /// <param name="pullMinVersion">A 64-bit unsigned integer representing the
+ /// minimum version, which may be 0. You can compare this to other
+ /// versions.</param>
+ /// <param name="pullMaxVersion">A 64-bit unsigned integer representing the
+ /// maximum version, which may be MAXULONGLONG. You can compare this to other
+ /// versions.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(ParseVersionRange)
+ (_In_ LPCOLESTR pwszVersionRange, _Out_ PULONGLONG pullMinVersion,
+ _Out_ PULONGLONG pullMaxVersion) = 0;
+};
+#endif
+
+// Class declarations
+//
+EXTERN_C const CLSID CLSID_SetupConfiguration;
+
+#ifdef __cplusplus
+/// <summary>
+/// This class implements <see cref="ISetupConfiguration"/>, <see
+/// cref="ISetupConfiguration2"/>, and <see cref="ISetupHelper"/>.
+/// </summary>
+class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration;
+#endif
+
+// Function declarations
+//
+/// <summary>
+/// Gets an <see cref="ISetupConfiguration"/> that provides information about
+/// product instances installed on the machine.
+/// </summary>
+/// <param name="ppConfiguration">The <see cref="ISetupConfiguration"/> that
+/// provides information about product instances installed on the
+/// machine.</param>
+/// <param name="pReserved">Reserved for future use.</param>
+/// <returns>Standard HRESULT indicating success or failure.</returns>
+STDMETHODIMP GetSetupConfiguration(_Out_ ISetupConfiguration **ppConfiguration,
+ _Reserved_ LPVOID pReserved);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.cpp
new file mode 100644
index 0000000..632b76d
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -0,0 +1,473 @@
+//===--- MinGW.cpp - MinGWToolChain Implementation ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinGW.h"
+#include "InputInfo.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <system_error>
+
+using namespace clang::diag;
+using namespace clang::driver;
+using namespace clang;
+using namespace llvm::opt;
+
+/// MinGW Tools
+void tools::MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ if (getToolChain().getArch() == llvm::Triple::x86) {
+ CmdArgs.push_back("--32");
+ } else if (getToolChain().getArch() == llvm::Triple::x86_64) {
+ CmdArgs.push_back("--64");
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+
+ if (Args.hasArg(options::OPT_gsplit_dwarf))
+ SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
+ SplitDebugName(Args, Inputs[0]));
+}
+
+void tools::MinGW::Linker::AddLibGCC(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ if (Args.hasArg(options::OPT_mthreads))
+ CmdArgs.push_back("-lmingwthrd");
+ CmdArgs.push_back("-lmingw32");
+
+ // Make use of compiler-rt if --rtlib option is used
+ ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args);
+ if (RLT == ToolChain::RLT_Libgcc) {
+ bool Static = Args.hasArg(options::OPT_static_libgcc) ||
+ Args.hasArg(options::OPT_static);
+ bool Shared = Args.hasArg(options::OPT_shared);
+ bool CXX = getToolChain().getDriver().CCCIsCXX();
+
+ if (Static || (!CXX && !Shared)) {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("-lgcc_eh");
+ } else {
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("-lgcc");
+ }
+ } else {
+ AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args);
+ }
+
+ CmdArgs.push_back("-lmoldname");
+ CmdArgs.push_back("-lmingwex");
+ CmdArgs.push_back("-lmsvcrt");
+}
+
+void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const ToolChain &TC = getToolChain();
+ const Driver &D = TC.getDriver();
+ // const SanitizerArgs &Sanitize = TC.getSanitizerArgs();
+
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ StringRef LinkerName = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "ld");
+ if (LinkerName.equals_lower("lld")) {
+ CmdArgs.push_back("-flavor");
+ CmdArgs.push_back("gnu");
+ } else if (!LinkerName.equals_lower("ld")) {
+ D.Diag(diag::err_drv_unsupported_linker) << LinkerName;
+ }
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("-s");
+
+ CmdArgs.push_back("-m");
+ if (TC.getArch() == llvm::Triple::x86)
+ CmdArgs.push_back("i386pe");
+ if (TC.getArch() == llvm::Triple::x86_64)
+ CmdArgs.push_back("i386pep");
+ if (TC.getArch() == llvm::Triple::arm)
+ CmdArgs.push_back("thumb2pe");
+
+ if (Args.hasArg(options::OPT_mwindows)) {
+ CmdArgs.push_back("--subsystem");
+ CmdArgs.push_back("windows");
+ } else if (Args.hasArg(options::OPT_mconsole)) {
+ CmdArgs.push_back("--subsystem");
+ CmdArgs.push_back("console");
+ }
+
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-Bstatic");
+ else {
+ if (Args.hasArg(options::OPT_mdll))
+ CmdArgs.push_back("--dll");
+ else if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("--shared");
+ CmdArgs.push_back("-Bdynamic");
+ if (Args.hasArg(options::OPT_mdll) || Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-e");
+ if (TC.getArch() == llvm::Triple::x86)
+ CmdArgs.push_back("_DllMainCRTStartup@12");
+ else
+ CmdArgs.push_back("DllMainCRTStartup");
+ CmdArgs.push_back("--enable-auto-image-base");
+ }
+ }
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+ // FIXME: add -N, -n flags
+ Args.AddLastArg(CmdArgs, options::OPT_r);
+ Args.AddLastArg(CmdArgs, options::OPT_s);
+ Args.AddLastArg(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
+ Args.AddLastArg(CmdArgs, options::OPT_Z_Flag);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) {
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o")));
+ } else {
+ if (Args.hasArg(options::OPT_municode))
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2u.o")));
+ else
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2.o")));
+ }
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("gcrt2.o")));
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o")));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ TC.AddFilePathLibArgs(Args, CmdArgs);
+ AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
+
+ // TODO: Add ASan stuff here
+
+ // TODO: Add profile stuff here
+
+ if (D.CCCIsCXX() &&
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
+ !Args.hasArg(options::OPT_static);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bstatic");
+ TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bdynamic");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib)) {
+ if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--start-group");
+
+ if (Args.hasArg(options::OPT_fstack_protector) ||
+ Args.hasArg(options::OPT_fstack_protector_strong) ||
+ Args.hasArg(options::OPT_fstack_protector_all)) {
+ CmdArgs.push_back("-lssp_nonshared");
+ CmdArgs.push_back("-lssp");
+ }
+ if (Args.hasArg(options::OPT_fopenmp))
+ CmdArgs.push_back("-lgomp");
+
+ AddLibGCC(Args, CmdArgs);
+
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lgmon");
+
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-lpthread");
+
+ // add system libraries
+ if (Args.hasArg(options::OPT_mwindows)) {
+ CmdArgs.push_back("-lgdi32");
+ CmdArgs.push_back("-lcomdlg32");
+ }
+ CmdArgs.push_back("-ladvapi32");
+ CmdArgs.push_back("-lshell32");
+ CmdArgs.push_back("-luser32");
+ CmdArgs.push_back("-lkernel32");
+
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--end-group");
+ else if (!LinkerName.equals_lower("lld"))
+ AddLibGCC(Args, CmdArgs);
+ }
+
+ if (!Args.hasArg(options::OPT_nostartfiles)) {
+ // Add crtfastmath.o if available and fast math is enabled.
+ TC.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
+
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o")));
+ }
+ }
+ const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerName.data()));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
+static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
+ std::string &Ver) {
+ auto Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0");
+ std::error_code EC;
+ for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
+ LI = LI.increment(EC)) {
+ StringRef VersionText = llvm::sys::path::filename(LI->path());
+ auto CandidateVersion =
+ toolchains::Generic_GCC::GCCVersion::Parse(VersionText);
+ if (CandidateVersion.Major == -1)
+ continue;
+ if (CandidateVersion <= Version)
+ continue;
+ Ver = VersionText;
+ GccLibDir = LI->path();
+ }
+ return Ver.size();
+}
+
+void toolchains::MinGW::findGccLibDir() {
+ llvm::SmallVector<llvm::SmallString<32>, 2> Archs;
+ Archs.emplace_back(getTriple().getArchName());
+ Archs[0] += "-w64-mingw32";
+ Archs.emplace_back("mingw32");
+ Arch = Archs[0].str();
+ // lib: Arch Linux, Ubuntu, Windows
+ // lib64: openSUSE Linux
+ for (StringRef CandidateLib : {"lib", "lib64"}) {
+ for (StringRef CandidateArch : Archs) {
+ llvm::SmallString<1024> LibDir(Base);
+ llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch);
+ if (findGccVersion(LibDir, GccLibDir, Ver)) {
+ Arch = CandidateArch;
+ return;
+ }
+ }
+ }
+}
+
+llvm::ErrorOr<std::string> toolchains::MinGW::findGcc() {
+ llvm::SmallVector<llvm::SmallString<32>, 2> Gccs;
+ Gccs.emplace_back(getTriple().getArchName());
+ Gccs[0] += "-w64-mingw32-gcc";
+ Gccs.emplace_back("mingw32-gcc");
+ // Please do not add "gcc" here
+ for (StringRef CandidateGcc : Gccs)
+ if (llvm::ErrorOr<std::string> GPPName = llvm::sys::findProgramByName(CandidateGcc))
+ return GPPName;
+ return make_error_code(std::errc::no_such_file_or_directory);
+}
+
+toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+
+ if (getDriver().SysRoot.size())
+ Base = getDriver().SysRoot;
+ else if (llvm::ErrorOr<std::string> GPPName = findGcc())
+ Base = llvm::sys::path::parent_path(
+ llvm::sys::path::parent_path(GPPName.get()));
+ else
+ Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
+
+ Base += llvm::sys::path::get_separator();
+ findGccLibDir();
+ // GccLibDir must precede Base/lib so that the
+ // correct crtbegin.o ,cetend.o would be found.
+ getFilePaths().push_back(GccLibDir);
+ getFilePaths().push_back(
+ (Base + Arch + llvm::sys::path::get_separator() + "lib").str());
+ getFilePaths().push_back(Base + "lib");
+ // openSUSE
+ getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib");
+}
+
+bool toolchains::MinGW::IsIntegratedAssemblerDefault() const { return true; }
+
+Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::PreprocessJobClass:
+ if (!Preprocessor)
+ Preprocessor.reset(new tools::gcc::Preprocessor(*this));
+ return Preprocessor.get();
+ case Action::CompileJobClass:
+ if (!Compiler)
+ Compiler.reset(new tools::gcc::Compiler(*this));
+ return Compiler.get();
+ default:
+ return ToolChain::getTool(AC);
+ }
+}
+
+Tool *toolchains::MinGW::buildAssembler() const {
+ return new tools::MinGW::Assembler(*this);
+}
+
+Tool *toolchains::MinGW::buildLinker() const {
+ return new tools::MinGW::Linker(*this);
+}
+
+bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool toolchains::MinGW::isPICDefault() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool toolchains::MinGW::isPIEDefault() const { return false; }
+
+bool toolchains::MinGW::isPICDefaultForced() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+bool toolchains::MinGW::UseSEHExceptions() const {
+ return getArch() == llvm::Triple::x86_64;
+}
+
+void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
+}
+
+void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const {
+ CudaInstallation.print(OS);
+}
+
+// Include directories for various hosts:
+
+// Windows, mingw.org
+// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++
+// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32
+// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward
+// c:\mingw\include
+// c:\mingw\mingw32\include
+
+// Windows, mingw-w64 mingw-builds
+// c:\mingw32\i686-w64-mingw32\include
+// c:\mingw32\i686-w64-mingw32\include\c++
+// c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32
+// c:\mingw32\i686-w64-mingw32\include\c++\backward
+
+// Windows, mingw-w64 msys2
+// c:\msys64\mingw32\include
+// c:\msys64\mingw32\i686-w64-mingw32\include
+// c:\msys64\mingw32\include\c++\4.9.2
+// c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32
+// c:\msys64\mingw32\include\c++\4.9.2\backward
+
+// openSUSE
+// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++
+// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32
+// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward
+// /usr/x86_64-w64-mingw32/sys-root/mingw/include
+
+// Arch Linux
+// /usr/i686-w64-mingw32/include/c++/5.1.0
+// /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32
+// /usr/i686-w64-mingw32/include/c++/5.1.0/backward
+// /usr/i686-w64-mingw32/include
+
+// Ubuntu
+// /usr/include/c++/4.8
+// /usr/include/c++/4.8/x86_64-w64-mingw32
+// /usr/include/c++/4.8/backward
+// /usr/x86_64-w64-mingw32/include
+
+void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<1024> P(getDriver().ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) {
+ // openSUSE
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + Arch + "/sys-root/mingw/include");
+ }
+
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + Arch + llvm::sys::path::get_separator() + "include");
+ addSystemInclude(DriverArgs, CC1Args, Base + "include");
+}
+
+void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + "include" + llvm::sys::path::get_separator() +
+ "c++" + llvm::sys::path::get_separator() + "v1");
+ break;
+
+ case ToolChain::CST_Libstdcxx:
+ llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
+ CppIncludeBases.emplace_back(Base);
+ llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++");
+ CppIncludeBases.emplace_back(Base);
+ llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver);
+ CppIncludeBases.emplace_back(Base);
+ llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
+ CppIncludeBases.emplace_back(GccLibDir);
+ llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
+ for (auto &CppIncludeBase : CppIncludeBases) {
+ addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
+ CppIncludeBase += llvm::sys::path::get_separator();
+ addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch);
+ addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
+ }
+ break;
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.h
new file mode 100644
index 0000000..9b3d7c5
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MinGW.h
@@ -0,0 +1,103 @@
+//===--- MinGW.h - MinGW ToolChain Implementations --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINGW_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINGW_H
+
+#include "Cuda.h"
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// MinGW -- Directly call GNU Binutils assembler and linker
+namespace MinGW {
+class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+public:
+ Assembler(const ToolChain &TC) : Tool("MinGW::Assemble", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("MinGW::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+
+private:
+ void AddLibGCC(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+};
+} // end namespace MinGW
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain {
+public:
+ MinGW(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool IsIntegratedAssemblerDefault() const override;
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+ bool UseSEHExceptions() const;
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ void printVerboseInfo(raw_ostream &OS) const override;
+
+protected:
+ Tool *getTool(Action::ActionClass AC) const override;
+ Tool *buildLinker() const override;
+ Tool *buildAssembler() const override;
+
+private:
+ CudaInstallationDetector CudaInstallation;
+
+ std::string Base;
+ std::string GccLibDir;
+ std::string Ver;
+ std::string Arch;
+ mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor;
+ mutable std::unique_ptr<tools::gcc::Compiler> Compiler;
+ void findGccLibDir();
+ llvm::ErrorOr<std::string> findGcc();
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINGW_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.cpp
new file mode 100644
index 0000000..2e8939c
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.cpp
@@ -0,0 +1,109 @@
+//===--- Minix.cpp - Minix ToolChain Implementations ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Minix.h"
+#include "InputInfo.h"
+#include "CommonArgs.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang;
+using namespace llvm::opt;
+
+void tools::minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
+ }
+
+ Args.AddAllArgs(CmdArgs,
+ {options::OPT_L, options::OPT_T_Group, options::OPT_e});
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ getToolChain().addProfileRTLibs(Args, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX()) {
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lCompilerRT-Generic");
+ CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib");
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+ }
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// Minix - Minix tool chain which can call as(1) and ld(1) directly.
+
+toolchains::Minix::Minix(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ getFilePaths().push_back(getDriver().Dir + "/../lib");
+ getFilePaths().push_back("/usr/lib");
+}
+
+Tool *toolchains::Minix::buildAssembler() const {
+ return new tools::minix::Assembler(*this);
+}
+
+Tool *toolchains::Minix::buildLinker() const {
+ return new tools::minix::Linker(*this);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.h
new file mode 100644
index 0000000..6fd7185
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Minix.h
@@ -0,0 +1,66 @@
+//===--- Minix.h - Minix ToolChain Implementations --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+/// minix -- Directly call GNU Binutils assembler and linker
+namespace minix {
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
+public:
+ Assembler(const ToolChain &TC)
+ : GnuTool("minix::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("minix::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace minix
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF {
+public:
+ Minix(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MipsLinux.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MipsLinux.cpp
new file mode 100644
index 0000000..b394208
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MipsLinux.cpp
@@ -0,0 +1,128 @@
+//===--- Mips.cpp - Mips ToolChain Implementations --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsLinux.h"
+#include "Arch/Mips.h"
+#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+/// Mips Toolchain
+MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D,
+ const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Linux(D, Triple, Args) {
+ // Select the correct multilib according to the given arguments.
+ DetectedMultilibs Result;
+ findMIPSMultilibs(D, Triple, "", Args, Result);
+ Multilibs = Result.Multilibs;
+ SelectedMultilib = Result.SelectedMultilib;
+
+ // Find out the library suffix based on the ABI.
+ LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple);
+ getFilePaths().clear();
+ getFilePaths().push_back(computeSysRoot() + "/usr/lib" + LibSuffix);
+}
+
+void MipsLLVMToolChain::AddClangSystemIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
+ return;
+
+ const Driver &D = getDriver();
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ const auto &Callback = Multilibs.includeDirsCallback();
+ if (Callback) {
+ for (const auto &Path : Callback(SelectedMultilib))
+ addExternCSystemIncludeIfExists(DriverArgs, CC1Args,
+ D.getInstalledDir() + Path);
+ }
+}
+
+Tool *MipsLLVMToolChain::buildLinker() const {
+ return new tools::gnutools::Linker(*this);
+}
+
+std::string MipsLLVMToolChain::computeSysRoot() const {
+ if (!getDriver().SysRoot.empty())
+ return getDriver().SysRoot + SelectedMultilib.osSuffix();
+
+ const std::string InstalledDir(getDriver().getInstalledDir());
+ std::string SysRootPath =
+ InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix();
+ if (llvm::sys::fs::exists(SysRootPath))
+ return SysRootPath;
+
+ return std::string();
+}
+
+ToolChain::CXXStdlibType
+MipsLLVMToolChain::GetCXXStdlibType(const ArgList &Args) const {
+ Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
+ if (A) {
+ StringRef Value = A->getValue();
+ if (Value != "libc++")
+ getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
+ }
+
+ return ToolChain::CST_Libcxx;
+}
+
+std::string MipsLLVMToolChain::findLibCxxIncludePath() const {
+ if (const auto &Callback = Multilibs.includeDirsCallback()) {
+ for (std::string Path : Callback(SelectedMultilib)) {
+ Path = getDriver().getInstalledDir() + Path + "/c++/v1";
+ if (llvm::sys::fs::exists(Path)) {
+ return Path;
+ }
+ }
+ }
+ return "";
+}
+
+void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) &&
+ "Only -lc++ (aka libxx) is supported in this toolchain.");
+
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ CmdArgs.push_back("-lunwind");
+}
+
+std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args,
+ StringRef Component,
+ bool Shared) const {
+ SmallString<128> Path(getDriver().ResourceDir);
+ llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix,
+ getOS());
+ llvm::sys::path::append(Path, Twine("libclang_rt." + Component + "-" +
+ "mips" + (Shared ? ".so" : ".a")));
+ return Path.str();
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/MipsLinux.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MipsLinux.h
new file mode 100644
index 0000000..fa82efb
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/MipsLinux.h
@@ -0,0 +1,62 @@
+//===--- Mips.h - Mips ToolChain Implementations ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MIPS_LINUX_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MIPS_LINUX_H
+
+#include "Linux.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY MipsLLVMToolChain : public Linux {
+protected:
+ Tool *buildLinker() const override;
+
+public:
+ MipsLLVMToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+
+ std::string findLibCxxIncludePath() const override;
+
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
+ bool Shared = false) const override;
+
+ std::string computeSysRoot() const override;
+
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return GCCInstallation.isValid() ? RuntimeLibType::RLT_Libgcc
+ : RuntimeLibType::RLT_CompilerRT;
+ }
+
+ const char *getDefaultLinker() const override {
+ return "lld";
+ }
+
+private:
+ Multilib SelectedMultilib;
+ std::string LibSuffix;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MIPS_LINUX_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Myriad.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Myriad.cpp
new file mode 100644
index 0000000..6fdb5a2
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Myriad.cpp
@@ -0,0 +1,289 @@
+//===--- Myriad.cpp - Myriad ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Myriad.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+using tools::addPathIfExists;
+
+void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+ assert(Inputs.size() == 1);
+ const InputInfo &II = Inputs[0];
+ assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX ||
+ II.getType() == types::TY_PP_CXX);
+
+ if (JA.getKind() == Action::PreprocessJobClass) {
+ Args.ClaimAllArgs();
+ CmdArgs.push_back("-E");
+ } else {
+ assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm.
+ CmdArgs.push_back("-S");
+ CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified.
+ }
+ CmdArgs.push_back("-DMYRIAD2");
+
+ // Append all -I, -iquote, -isystem paths, defines/undefines, 'f'
+ // flags, 'g' flags, 'M' flags, optimize flags, warning options,
+ // mcpu flags, mllvm flags, and Xclang flags.
+ // These are spelled the same way in clang and moviCompile.
+ Args.AddAllArgsExcept(
+ CmdArgs,
+ {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ,
+ options::OPT_D, options::OPT_U, options::OPT_f_Group,
+ options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group,
+ options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ,
+ options::OPT_mllvm, options::OPT_Xclang},
+ {options::OPT_fno_split_dwarf_inlining});
+ Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present.
+
+ // If we're producing a dependency file, and assembly is the final action,
+ // then the name of the target in the dependency file should be the '.o'
+ // file, not the '.s' file produced by this step. For example, instead of
+ // /tmp/mumble.s: mumble.c .../someheader.h
+ // the filename on the lefthand side should be "mumble.o"
+ if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) &&
+ C.getActions().size() == 1 &&
+ C.getActions()[0]->getKind() == Action::AssembleJobClass) {
+ Arg *A = Args.getLastArg(options::OPT_o);
+ if (A) {
+ CmdArgs.push_back("-MT");
+ CmdArgs.push_back(Args.MakeArgString(A->getValue()));
+ }
+ }
+
+ CmdArgs.push_back(II.getFilename());
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ std::string Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("moviCompile"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ CmdArgs, Inputs));
+}
+
+void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ assert(Inputs.size() == 1);
+ const InputInfo &II = Inputs[0];
+ assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input.
+ assert(Output.getType() == types::TY_Object);
+
+ CmdArgs.push_back("-no6thSlotCompression");
+ const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ);
+ if (CPUArg)
+ CmdArgs.push_back(
+ Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue())));
+ CmdArgs.push_back("-noSPrefixing");
+ CmdArgs.push_back("-a"); // Mystery option.
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+ for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) {
+ A->claim();
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-i:") + A->getValue(0)));
+ }
+ CmdArgs.push_back("-elf"); // Output format.
+ CmdArgs.push_back(II.getFilename());
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-o:") + Output.getFilename()));
+
+ std::string Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("moviAsm"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ CmdArgs, Inputs));
+}
+
+void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const auto &TC =
+ static_cast<const toolchains::MyriadToolChain &>(getToolChain());
+ const llvm::Triple &T = TC.getTriple();
+ ArgStringList CmdArgs;
+ bool UseStartfiles =
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
+ bool UseDefaultLibs =
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs);
+ // Silence warning if the args contain both -nostdlib and -stdlib=.
+ Args.getLastArg(options::OPT_stdlib_EQ);
+
+ if (T.getArch() == llvm::Triple::sparc)
+ CmdArgs.push_back("-EB");
+ else // SHAVE assumes little-endian, and sparcel is expressly so.
+ CmdArgs.push_back("-EL");
+
+ // The remaining logic is mostly like gnutools::Linker::ConstructJob,
+ // but we never pass through a --sysroot option and various other bits.
+ // For example, there are no sanitizers (yet) nor gold linker.
+
+ // Eat some arguments that may be present but have no effect.
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ Args.ClaimAllArgs(options::OPT_w);
+ Args.ClaimAllArgs(options::OPT_static_libgcc);
+
+ if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option.
+ CmdArgs.push_back("-s");
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (UseStartfiles) {
+ // If you want startfiles, it means you want the builtin crti and crtbegin,
+ // but not crt0. Myriad link commands provide their own crt0.o as needed.
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o")));
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o")));
+ }
+
+ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_e, options::OPT_s, options::OPT_t,
+ options::OPT_Z_Flag, options::OPT_r});
+
+ TC.AddFilePathLibArgs(Args, CmdArgs);
+
+ bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs);
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ if (UseDefaultLibs) {
+ if (NeedsSanitizerDeps)
+ linkSanitizerRuntimeDeps(TC, CmdArgs);
+ if (C.getDriver().CCCIsCXX()) {
+ if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) {
+ CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
+ } else
+ CmdArgs.push_back("-lstdc++");
+ }
+ if (T.getOS() == llvm::Triple::RTEMS) {
+ CmdArgs.push_back("--start-group");
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lgcc"); // circularly dependent on rtems
+ // You must provide your own "-L" option to enable finding these.
+ CmdArgs.push_back("-lrtemscpu");
+ CmdArgs.push_back("-lrtemsbsp");
+ CmdArgs.push_back("--end-group");
+ } else {
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lgcc");
+ }
+ }
+ if (UseStartfiles) {
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o")));
+ }
+
+ std::string Exec =
+ Args.MakeArgString(TC.GetProgramPath("sparc-myriad-elf-ld"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ CmdArgs, Inputs));
+}
+
+MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use
+ // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple.
+ // This won't work to find gcc. Instead we give the installation detector an
+ // extra triple, which is preferable to further hacks of the logic that at
+ // present is based solely on getArch(). In particular, it would be wrong to
+ // choose the myriad installation when targeting a non-myriad sparc install.
+ switch (Triple.getArch()) {
+ default:
+ D.Diag(clang::diag::err_target_unsupported_arch)
+ << Triple.getArchName() << "myriad";
+ LLVM_FALLTHROUGH;
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::shave:
+ GCCInstallation.init(Triple, Args, {"sparc-myriad-elf"});
+ }
+
+ if (GCCInstallation.isValid()) {
+ // This directory contains crt{i,n,begin,end}.o as well as libgcc.
+ // These files are tied to a particular version of gcc.
+ SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath());
+ addPathIfExists(D, CompilerSupportDir, getFilePaths());
+ }
+ // libstd++ and libc++ must both be found in this one place.
+ addPathIfExists(D, D.Dir + "/../sparc-myriad-elf/lib", getFilePaths());
+}
+
+MyriadToolChain::~MyriadToolChain() {}
+
+void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
+ addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include");
+}
+
+std::string MyriadToolChain::findLibCxxIncludePath() const {
+ std::string Path(getDriver().getInstalledDir());
+ return Path + "/../include/c++/v1";
+}
+
+void MyriadToolChain::addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ StringRef LibDir = GCCInstallation.getParentLibPath();
+ const GCCVersion &Version = GCCInstallation.getVersion();
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
+ addLibStdCXXIncludePaths(
+ LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text,
+ "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args);
+}
+
+// MyriadToolChain handles several triples:
+// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf
+Tool *MyriadToolChain::SelectTool(const JobAction &JA) const {
+ // The inherited method works fine if not targeting the SHAVE.
+ if (!isShaveCompilation(getTriple()))
+ return ToolChain::SelectTool(JA);
+ switch (JA.getKind()) {
+ case Action::PreprocessJobClass:
+ case Action::CompileJobClass:
+ if (!Compiler)
+ Compiler.reset(new tools::SHAVE::Compiler(*this));
+ return Compiler.get();
+ case Action::AssembleJobClass:
+ if (!Assembler)
+ Assembler.reset(new tools::SHAVE::Assembler(*this));
+ return Assembler.get();
+ default:
+ return ToolChain::getTool(JA.getKind());
+ }
+}
+
+Tool *MyriadToolChain::buildLinker() const {
+ return new tools::Myriad::Linker(*this);
+}
+
+SanitizerMask MyriadToolChain::getSupportedSanitizers() const {
+ return SanitizerKind::Address;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Myriad.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Myriad.h
new file mode 100644
index 0000000..4c213c7
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Myriad.h
@@ -0,0 +1,102 @@
+//===--- Myriad.h - Myriad ToolChain Implementations ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// SHAVE tools -- Directly call moviCompile and moviAsm
+namespace SHAVE {
+class LLVM_LIBRARY_VISIBILITY Compiler : public Tool {
+public:
+ Compiler(const ToolChain &TC) : Tool("moviCompile", "movicompile", TC) {}
+
+ bool hasIntegratedCPP() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+public:
+ Assembler(const ToolChain &TC) : Tool("moviAsm", "moviAsm", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; } // not sure.
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace SHAVE
+
+/// The Myriad toolchain uses tools that are in two different namespaces.
+/// The Compiler and Assembler as defined above are in the SHAVE namespace,
+/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE,
+/// is in the Myriad namespace.
+namespace Myriad {
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("shave::Linker", "ld", TC) {}
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace Myriad
+} // end namespace tools
+
+namespace toolchains {
+
+/// MyriadToolChain - A tool chain using either clang or the external compiler
+/// installed by the Movidius SDK to perform all subcommands.
+class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_ELF {
+public:
+ MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~MyriadToolChain() override;
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ std::string findLibCxxIncludePath() const override;
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ Tool *SelectTool(const JobAction &JA) const override;
+ unsigned GetDefaultDwarfVersion() const override { return 2; }
+ SanitizerMask getSupportedSanitizers() const override;
+
+protected:
+ Tool *buildLinker() const override;
+ bool isShaveCompilation(const llvm::Triple &T) const {
+ return T.getArch() == llvm::Triple::shave;
+ }
+
+private:
+ mutable std::unique_ptr<Tool> Compiler;
+ mutable std::unique_ptr<Tool> Assembler;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.cpp
new file mode 100644
index 0000000..5eb5c74
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.cpp
@@ -0,0 +1,363 @@
+//===--- NaCl.cpp - Native Client ToolChain Implementations -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NaCl.h"
+#include "InputInfo.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+// NaCl ARM assembly (inline or standalone) can be written with a set of macros
+// for the various SFI requirements like register masking. The assembly tool
+// inserts the file containing the macros as an input into all the assembly
+// jobs.
+void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const toolchains::NaClToolChain &ToolChain =
+ static_cast<const toolchains::NaClToolChain &>(getToolChain());
+ InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(),
+ "nacl-arm-macros.s");
+ InputInfoList NewInputs;
+ NewInputs.push_back(NaClMacros);
+ NewInputs.append(Inputs.begin(), Inputs.end());
+ gnutools::Assembler::ConstructJob(C, JA, Output, NewInputs, Args,
+ LinkingOutput);
+}
+
+// This is quite similar to gnutools::Linker::ConstructJob with changes that
+// we use static by default, do not yet support sanitizers or LTO, and a few
+// others. Eventually we can support more of that and hopefully migrate back
+// to gnutools::Linker.
+void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+
+ const toolchains::NaClToolChain &ToolChain =
+ static_cast<const toolchains::NaClToolChain &>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+ const llvm::Triple::ArchType Arch = ToolChain.getArch();
+ const bool IsStatic =
+ !Args.hasArg(options::OPT_dynamic) && !Args.hasArg(options::OPT_shared);
+
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("-s");
+
+ // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag
+ // from there is --build-id, which we do want.
+ CmdArgs.push_back("--build-id");
+
+ if (!IsStatic)
+ CmdArgs.push_back("--eh-frame-hdr");
+
+ CmdArgs.push_back("-m");
+ if (Arch == llvm::Triple::x86)
+ CmdArgs.push_back("elf_i386_nacl");
+ else if (Arch == llvm::Triple::arm)
+ CmdArgs.push_back("armelf_nacl");
+ else if (Arch == llvm::Triple::x86_64)
+ CmdArgs.push_back("elf_x86_64_nacl");
+ else if (Arch == llvm::Triple::mipsel)
+ CmdArgs.push_back("mipselelf_nacl");
+ else
+ D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName()
+ << "Native Client";
+
+ if (IsStatic)
+ CmdArgs.push_back("-static");
+ else if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-shared");
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+
+ const char *crtbegin;
+ if (IsStatic)
+ crtbegin = "crtbeginT.o";
+ else if (Args.hasArg(options::OPT_shared))
+ crtbegin = "crtbeginS.o";
+ else
+ crtbegin = "crtbegin.o";
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_u);
+
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+ CmdArgs.push_back("--no-demangle");
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (D.CCCIsCXX() &&
+ !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ bool OnlyLibstdcxxStatic =
+ Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic;
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bstatic");
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (OnlyLibstdcxxStatic)
+ CmdArgs.push_back("-Bdynamic");
+ CmdArgs.push_back("-lm");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib)) {
+ if (!Args.hasArg(options::OPT_nodefaultlibs)) {
+ // Always use groups, since it has no effect on dynamic libraries.
+ CmdArgs.push_back("--start-group");
+ CmdArgs.push_back("-lc");
+ // NaCl's libc++ currently requires libpthread, so just always include it
+ // in the group for C++.
+ if (Args.hasArg(options::OPT_pthread) ||
+ Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) {
+ // Gold, used by Mips, handles nested groups differently than ld, and
+ // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a,
+ // which is not a desired behaviour here.
+ // See https://sourceware.org/ml/binutils/2015-03/msg00034.html
+ if (getToolChain().getArch() == llvm::Triple::mipsel)
+ CmdArgs.push_back("-lnacl");
+
+ CmdArgs.push_back("-lpthread");
+ }
+
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("--as-needed");
+ if (IsStatic)
+ CmdArgs.push_back("-lgcc_eh");
+ else
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+
+ // Mips needs to create and use pnacl_legacy library that contains
+ // definitions from bitcode/pnaclmm.c and definitions for
+ // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset().
+ if (getToolChain().getArch() == llvm::Triple::mipsel)
+ CmdArgs.push_back("-lpnacl_legacy");
+
+ CmdArgs.push_back("--end-group");
+ }
+
+ if (!Args.hasArg(options::OPT_nostartfiles)) {
+ const char *crtend;
+ if (Args.hasArg(options::OPT_shared))
+ crtend = "crtendS.o";
+ else
+ crtend = "crtend.o";
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+ }
+ }
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// NaCl Toolchain
+NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+
+ // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the
+ // default paths, and must instead only use the paths provided
+ // with this toolchain based on architecture.
+ path_list &file_paths = getFilePaths();
+ path_list &prog_paths = getProgramPaths();
+
+ file_paths.clear();
+ prog_paths.clear();
+
+ // Path for library files (libc.a, ...)
+ std::string FilePath(getDriver().Dir + "/../");
+
+ // Path for tools (clang, ld, etc..)
+ std::string ProgPath(getDriver().Dir + "/../");
+
+ // Path for toolchain libraries (libgcc.a, ...)
+ std::string ToolPath(getDriver().ResourceDir + "/lib/");
+
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86:
+ file_paths.push_back(FilePath + "x86_64-nacl/lib32");
+ file_paths.push_back(FilePath + "i686-nacl/usr/lib");
+ prog_paths.push_back(ProgPath + "x86_64-nacl/bin");
+ file_paths.push_back(ToolPath + "i686-nacl");
+ break;
+ case llvm::Triple::x86_64:
+ file_paths.push_back(FilePath + "x86_64-nacl/lib");
+ file_paths.push_back(FilePath + "x86_64-nacl/usr/lib");
+ prog_paths.push_back(ProgPath + "x86_64-nacl/bin");
+ file_paths.push_back(ToolPath + "x86_64-nacl");
+ break;
+ case llvm::Triple::arm:
+ file_paths.push_back(FilePath + "arm-nacl/lib");
+ file_paths.push_back(FilePath + "arm-nacl/usr/lib");
+ prog_paths.push_back(ProgPath + "arm-nacl/bin");
+ file_paths.push_back(ToolPath + "arm-nacl");
+ break;
+ case llvm::Triple::mipsel:
+ file_paths.push_back(FilePath + "mipsel-nacl/lib");
+ file_paths.push_back(FilePath + "mipsel-nacl/usr/lib");
+ prog_paths.push_back(ProgPath + "bin");
+ file_paths.push_back(ToolPath + "mipsel-nacl");
+ break;
+ default:
+ break;
+ }
+
+ NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s");
+}
+
+void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ SmallString<128> P(D.Dir + "/../");
+ switch (getTriple().getArch()) {
+ case llvm::Triple::x86:
+ // x86 is special because multilib style uses x86_64-nacl/include for libc
+ // headers but the SDK wants i686-nacl/usr/include. The other architectures
+ // have the same substring.
+ llvm::sys::path::append(P, "i686-nacl/usr/include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::append(P, "x86_64-nacl/include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ return;
+ case llvm::Triple::arm:
+ llvm::sys::path::append(P, "arm-nacl/usr/include");
+ break;
+ case llvm::Triple::x86_64:
+ llvm::sys::path::append(P, "x86_64-nacl/usr/include");
+ break;
+ case llvm::Triple::mipsel:
+ llvm::sys::path::append(P, "mipsel-nacl/usr/include");
+ break;
+ default:
+ return;
+ }
+
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::remove_filename(P);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+}
+
+void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Check for -stdlib= flags. We only support libc++ but this consumes the arg
+ // if the value is libc++, and emits an error for other values.
+ GetCXXStdlibType(Args);
+ CmdArgs.push_back("-lc++");
+}
+
+std::string NaClToolChain::findLibCxxIncludePath() const {
+ const Driver &D = getDriver();
+
+ SmallString<128> P(D.Dir + "/../");
+ switch (getTriple().getArch()) {
+ case llvm::Triple::arm:
+ llvm::sys::path::append(P, "arm-nacl/include/c++/v1");
+ return P.str();
+ case llvm::Triple::x86:
+ llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1");
+ return P.str();
+ case llvm::Triple::x86_64:
+ llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1");
+ return P.str();
+ case llvm::Triple::mipsel:
+ llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1");
+ return P.str();
+ default:
+ return "";
+ }
+}
+
+ToolChain::CXXStdlibType
+NaClToolChain::GetCXXStdlibType(const ArgList &Args) const {
+ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value == "libc++")
+ return ToolChain::CST_Libcxx;
+ getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
+ }
+
+ return ToolChain::CST_Libcxx;
+}
+
+std::string
+NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const {
+ llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType));
+ if (TheTriple.getArch() == llvm::Triple::arm &&
+ TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment)
+ TheTriple.setEnvironment(llvm::Triple::GNUEABIHF);
+ return TheTriple.getTriple();
+}
+
+Tool *NaClToolChain::buildLinker() const {
+ return new tools::nacltools::Linker(*this);
+}
+
+Tool *NaClToolChain::buildAssembler() const {
+ if (getTriple().getArch() == llvm::Triple::arm)
+ return new tools::nacltools::AssemblerARM(*this);
+ return new tools::gnutools::Assembler(*this);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.h
new file mode 100644
index 0000000..31af3a5
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NaCl.h
@@ -0,0 +1,87 @@
+//===--- NaCl.h - Native Client ToolChain Implementations -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NACL_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NACL_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace nacltools {
+class LLVM_LIBRARY_VISIBILITY AssemblerARM : public gnutools::Assembler {
+public:
+ AssemblerARM(const ToolChain &TC) : gnutools::Assembler(TC) {}
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("NaCl::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace nacltools
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY NaClToolChain : public Generic_ELF {
+public:
+ NaClToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ std::string findLibCxxIncludePath() const override;
+
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ bool IsIntegratedAssemblerDefault() const override {
+ return getTriple().getArch() == llvm::Triple::mipsel;
+ }
+
+ // Get the path to the file containing NaCl's ARM macros.
+ // It lives in NaClToolChain because the ARMAssembler tool needs a
+ // const char * that it can pass around,
+ const char *GetNaClArmMacrosPath() const { return NaClArmMacrosPath.c_str(); }
+
+ std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
+ types::ID InputType) const override;
+
+protected:
+ Tool *buildLinker() const override;
+ Tool *buildAssembler() const override;
+
+private:
+ std::string NaClArmMacrosPath;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NACL_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.cpp
new file mode 100644
index 0000000..a1a3108
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.cpp
@@ -0,0 +1,425 @@
+//===--- NetBSD.cpp - NetBSD ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NetBSD.h"
+#include "Arch/ARM.h"
+#include "Arch/Mips.h"
+#include "Arch/Sparc.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ // GNU as needs different flags for creating the correct output format
+ // on architectures with different ABIs or optional feature sets.
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::x86:
+ CmdArgs.push_back("--32");
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb: {
+ StringRef MArch, MCPU;
+ arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true);
+ std::string Arch =
+ arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple());
+ CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch));
+ break;
+ }
+
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
+ StringRef CPUName;
+ StringRef ABIName;
+ mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+
+ CmdArgs.push_back("-march");
+ CmdArgs.push_back(CPUName.data());
+
+ CmdArgs.push_back("-mabi");
+ CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());
+
+ if (getToolChain().getArch() == llvm::Triple::mips ||
+ getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else
+ CmdArgs.push_back("-EL");
+
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel: {
+ CmdArgs.push_back("-32");
+ std::string CPU = getCPUName(Args, getToolChain().getTriple());
+ CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+
+ case llvm::Triple::sparcv9: {
+ CmdArgs.push_back("-64");
+ std::string CPU = getCPUName(Args, getToolChain().getTriple());
+ CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as")));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ CmdArgs.push_back("--eh-frame-hdr");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-Bshareable");
+ } else {
+ Args.AddAllArgs(CmdArgs, options::OPT_pie);
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/libexec/ld.elf_so");
+ }
+ }
+
+ // Many NetBSD architectures support more than one ABI.
+ // Determine the correct emulation for ld.
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::x86:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf_i386");
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ CmdArgs.push_back("-m");
+ switch (getToolChain().getTriple().getEnvironment()) {
+ case llvm::Triple::EABI:
+ case llvm::Triple::GNUEABI:
+ CmdArgs.push_back("armelf_nbsd_eabi");
+ break;
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ CmdArgs.push_back("armelf_nbsd_eabihf");
+ break;
+ default:
+ CmdArgs.push_back("armelf_nbsd");
+ break;
+ }
+ break;
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ arm::appendEBLinkFlags(Args, CmdArgs, getToolChain().getEffectiveTriple());
+ CmdArgs.push_back("-m");
+ switch (getToolChain().getTriple().getEnvironment()) {
+ case llvm::Triple::EABI:
+ case llvm::Triple::GNUEABI:
+ CmdArgs.push_back("armelfb_nbsd_eabi");
+ break;
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ CmdArgs.push_back("armelfb_nbsd_eabihf");
+ break;
+ default:
+ CmdArgs.push_back("armelfb_nbsd");
+ break;
+ }
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ if (mips::hasMipsAbiArg(Args, "32")) {
+ CmdArgs.push_back("-m");
+ if (getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("elf32btsmip");
+ else
+ CmdArgs.push_back("elf32ltsmip");
+ } else if (mips::hasMipsAbiArg(Args, "64")) {
+ CmdArgs.push_back("-m");
+ if (getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("elf64btsmip");
+ else
+ CmdArgs.push_back("elf64ltsmip");
+ }
+ break;
+ case llvm::Triple::ppc:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32ppc_nbsd");
+ break;
+
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf64ppc");
+ break;
+
+ case llvm::Triple::sparc:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32_sparc");
+ break;
+
+ case llvm::Triple::sparcv9:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf64_sparc");
+ break;
+
+ default:
+ break;
+ }
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crt0.o")));
+ }
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) {
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
+ } else {
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ }
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+ bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ unsigned Major, Minor, Micro;
+ getToolChain().getTriple().getOSVersion(Major, Minor, Micro);
+ bool useLibgcc = true;
+ if (Major >= 7 || Major == 0) {
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ useLibgcc = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ addOpenMPRuntime(CmdArgs, getToolChain(), Args);
+ if (D.CCCIsCXX()) {
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
+ if (NeedsSanitizerDeps)
+ linkSanitizerRuntimeDeps(getToolChain(), CmdArgs);
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-lc");
+
+ if (useLibgcc) {
+ if (Args.hasArg(options::OPT_static)) {
+ // libgcc_eh depends on libc, so resolve as much as possible,
+ // pull in any new requirements from libc and then get the rest
+ // of libgcc.
+ CmdArgs.push_back("-lgcc_eh");
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lgcc");
+ } else {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ }
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
+ }
+
+ getToolChain().addProfileRTLibs(Args, CmdArgs);
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
+
+NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ if (getDriver().UseStdLib) {
+ // When targeting a 32-bit platform, try the special directory used on
+ // 64-bit hosts, and only fall back to the main library directory if that
+ // doesn't work.
+ // FIXME: It'd be nicer to test if this directory exists, but I'm not sure
+ // what all logic is needed to emulate the '=' prefix here.
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86:
+ getFilePaths().push_back("=/usr/lib/i386");
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::EABI:
+ case llvm::Triple::GNUEABI:
+ getFilePaths().push_back("=/usr/lib/eabi");
+ break;
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ getFilePaths().push_back("=/usr/lib/eabihf");
+ break;
+ default:
+ getFilePaths().push_back("=/usr/lib/oabi");
+ break;
+ }
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ if (tools::mips::hasMipsAbiArg(Args, "o32"))
+ getFilePaths().push_back("=/usr/lib/o32");
+ else if (tools::mips::hasMipsAbiArg(Args, "64"))
+ getFilePaths().push_back("=/usr/lib/64");
+ break;
+ case llvm::Triple::ppc:
+ getFilePaths().push_back("=/usr/lib/powerpc");
+ break;
+ case llvm::Triple::sparc:
+ getFilePaths().push_back("=/usr/lib/sparc");
+ break;
+ default:
+ break;
+ }
+
+ getFilePaths().push_back("=/usr/lib");
+ }
+}
+
+Tool *NetBSD::buildAssembler() const {
+ return new tools::netbsd::Assembler(*this);
+}
+
+Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); }
+
+ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const {
+ unsigned Major, Minor, Micro;
+ getTriple().getOSVersion(Major, Minor, Micro);
+ if (Major >= 7 || Major == 0) {
+ switch (getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return ToolChain::CST_Libcxx;
+ default:
+ break;
+ }
+ }
+ return ToolChain::CST_Libstdcxx;
+}
+
+std::string NetBSD::findLibCxxIncludePath() const {
+ return getDriver().SysRoot + "/usr/include/c++/";
+}
+
+void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "",
+ "", DriverArgs, CC1Args);
+}
+
+SanitizerMask NetBSD::getSupportedSanitizers() const {
+ const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ if (IsX86_64) {
+ Res |= SanitizerKind::Address;
+ }
+ return Res;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.h
new file mode 100644
index 0000000..5163ff7
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/NetBSD.h
@@ -0,0 +1,83 @@
+//===--- NetBSD.h - NetBSD ToolChain Implementations ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NETBSD_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NETBSD_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// netbsd -- Directly call GNU Binutils assembler and linker
+namespace netbsd {
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
+public:
+ Assembler(const ToolChain &TC)
+ : GnuTool("netbsd::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("netbsd::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace netbsd
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
+public:
+ NetBSD(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
+
+ CXXStdlibType GetDefaultCXXStdlibType() const override;
+
+ std::string findLibCxxIncludePath() const override;
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override {
+ return true;
+ }
+
+ SanitizerMask getSupportedSanitizers() const override;
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NETBSD_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp
new file mode 100644
index 0000000..1d54a1e
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.cpp
@@ -0,0 +1,236 @@
+//===--- OpenBSD.cpp - OpenBSD ToolChain Implementations --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OpenBSD.h"
+#include "Arch/Mips.h"
+#include "Arch/Sparc.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::x86:
+ // When building 32-bit code on OpenBSD/amd64, we have to explicitly
+ // instruct as in the base system to assemble 32-bit code.
+ CmdArgs.push_back("--32");
+ break;
+
+ case llvm::Triple::ppc:
+ CmdArgs.push_back("-mppc");
+ CmdArgs.push_back("-many");
+ break;
+
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel: {
+ CmdArgs.push_back("-32");
+ std::string CPU = getCPUName(Args, getToolChain().getTriple());
+ CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+
+ case llvm::Triple::sparcv9: {
+ CmdArgs.push_back("-64");
+ std::string CPU = getCPUName(Args, getToolChain().getTriple());
+ CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
+ StringRef CPUName;
+ StringRef ABIName;
+ mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+
+ CmdArgs.push_back("-mabi");
+ CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());
+
+ if (getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else
+ CmdArgs.push_back("-EL");
+
+ AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("-EB");
+ else if (getToolChain().getArch() == llvm::Triple::mips64el)
+ CmdArgs.push_back("-EL");
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
+ CmdArgs.push_back("-e");
+ CmdArgs.push_back("__start");
+ }
+
+ CmdArgs.push_back("--eh-frame-hdr");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ CmdArgs.push_back("-Bdynamic");
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-shared");
+ } else {
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/usr/libexec/ld.so");
+ }
+ }
+
+ if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back("-pie");
+ if (Args.hasArg(options::OPT_nopie))
+ CmdArgs.push_back("-nopie");
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("gcrt0.o")));
+ else if (Args.hasArg(options::OPT_static) &&
+ !Args.hasArg(options::OPT_nopie))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("rcrt0.o")));
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crt0.o")));
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ } else {
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
+ }
+ }
+
+ std::string Triple = getToolChain().getTripleString();
+ if (Triple.substr(0, 6) == "x86_64")
+ Triple.replace(0, 6, "amd64");
+ CmdArgs.push_back(
+ Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + "/4.2.1"));
+
+ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_e, options::OPT_s, options::OPT_t,
+ options::OPT_Z_Flag, options::OPT_r});
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX()) {
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lm_p");
+ else
+ CmdArgs.push_back("-lm");
+ }
+
+ // FIXME: For some reason GCC passes -lgcc before adding
+ // the default system libraries. Just mimic this for now.
+ CmdArgs.push_back("-lgcc");
+
+ if (Args.hasArg(options::OPT_pthread)) {
+ if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lpthread_p");
+ else
+ CmdArgs.push_back("-lpthread");
+ }
+
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lc_p");
+ else
+ CmdArgs.push_back("-lc");
+ }
+
+ CmdArgs.push_back("-lgcc");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+ else
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
+ }
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.
+
+OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ getFilePaths().push_back(getDriver().Dir + "/../lib");
+ getFilePaths().push_back("/usr/lib");
+}
+
+Tool *OpenBSD::buildAssembler() const {
+ return new tools::openbsd::Assembler(*this);
+}
+
+Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h
new file mode 100644
index 0000000..1cc0ca7
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/OpenBSD.h
@@ -0,0 +1,76 @@
+//===--- OpenBSD.h - OpenBSD ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OPENBSD_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OPENBSD_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// openbsd -- Directly call GNU Binutils assembler and linker
+namespace openbsd {
+class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
+public:
+ Assembler(const ToolChain &TC)
+ : GnuTool("openbsd::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ Linker(const ToolChain &TC) : GnuTool("openbsd::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace openbsd
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF {
+public:
+ OpenBSD(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
+ bool isPIEDefault() const override { return true; }
+
+ unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
+ return 2;
+ }
+ unsigned GetDefaultDwarfVersion() const override { return 2; }
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OPENBSD_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.cpp
new file mode 100644
index 0000000..c1b8c3d
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.cpp
@@ -0,0 +1,419 @@
+//===--- PS4CPU.cpp - PS4CPU ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PS4CPU.h"
+#include "FreeBSD.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <cstdlib> // ::getenv
+
+using namespace clang::driver;
+using namespace clang;
+using namespace llvm::opt;
+
+using clang::driver::tools::AddLinkerInputs;
+
+void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
+ false) ||
+ Args.hasFlag(options::OPT_fprofile_generate,
+ options::OPT_fno_profile_instr_generate, false) ||
+ Args.hasFlag(options::OPT_fprofile_generate_EQ,
+ options::OPT_fno_profile_instr_generate, false) ||
+ Args.hasFlag(options::OPT_fprofile_instr_generate,
+ options::OPT_fno_profile_instr_generate, false) ||
+ Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
+ options::OPT_fno_profile_instr_generate, false) ||
+ Args.hasArg(options::OPT_fcreate_profile) ||
+ Args.hasArg(options::OPT_coverage)))
+ CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a");
+}
+
+void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ assert(Inputs.size() == 1 && "Unexpected number of inputs.");
+ const InputInfo &Input = Inputs[0];
+ assert(Input.isFilename() && "Invalid input.");
+ CmdArgs.push_back(Input.getFilename());
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("orbis-as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) {
+ const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
+ if (SanArgs.needsUbsanRt()) {
+ CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak");
+ }
+ if (SanArgs.needsAsanRt()) {
+ CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak");
+ }
+}
+
+static void ConstructPS4LinkJob(const Tool &T, Compilation &C,
+ const JobAction &JA, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) {
+ const toolchains::FreeBSD &ToolChain =
+ static_cast<const toolchains::FreeBSD &>(T.getToolChain());
+ const Driver &D = ToolChain.getDriver();
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back("-pie");
+
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("--oformat=so");
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ AddPS4SanitizerArgs(ToolChain, CmdArgs);
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+ CmdArgs.push_back("--no-demangle");
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (Args.hasArg(options::OPT_pthread)) {
+ CmdArgs.push_back("-lpthread");
+ }
+
+ const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
+
+ C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
+}
+
+static void ConstructGoldLinkJob(const Tool &T, Compilation &C,
+ const JobAction &JA, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) {
+ const toolchains::FreeBSD &ToolChain =
+ static_cast<const toolchains::FreeBSD &>(T.getToolChain());
+ const Driver &D = ToolChain.getDriver();
+ ArgStringList CmdArgs;
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
+ if (!D.SysRoot.empty())
+ CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+ if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back("-pie");
+
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ } else {
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ CmdArgs.push_back("--eh-frame-hdr");
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-Bshareable");
+ } else {
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/libexec/ld-elf.so.1");
+ }
+ CmdArgs.push_back("--enable-new-dtags");
+ }
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ AddPS4SanitizerArgs(ToolChain, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ const char *crt1 = nullptr;
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (Args.hasArg(options::OPT_pg))
+ crt1 = "gcrt1.o";
+ else if (Args.hasArg(options::OPT_pie))
+ crt1 = "Scrt1.o";
+ else
+ crt1 = "crt1.o";
+ }
+ if (crt1)
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+
+ const char *crtbegin = nullptr;
+ if (Args.hasArg(options::OPT_static))
+ crtbegin = "crtbeginT.o";
+ else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ crtbegin = "crtbeginS.o";
+ else
+ crtbegin = "crtbegin.o";
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+ if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+ CmdArgs.push_back("--no-demangle");
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ // For PS4, we always want to pass libm, libstdc++ and libkernel
+ // libraries for both C and C++ compilations.
+ CmdArgs.push_back("-lkernel");
+ if (D.CCCIsCXX()) {
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lm_p");
+ else
+ CmdArgs.push_back("-lm");
+ }
+ // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
+ // the default system libraries. Just mimic this for now.
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lgcc_p");
+ else
+ CmdArgs.push_back("-lcompiler_rt");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-lstdc++");
+ } else if (Args.hasArg(options::OPT_pg)) {
+ CmdArgs.push_back("-lgcc_eh_p");
+ } else {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lstdc++");
+ CmdArgs.push_back("--no-as-needed");
+ }
+
+ if (Args.hasArg(options::OPT_pthread)) {
+ if (Args.hasArg(options::OPT_pg))
+ CmdArgs.push_back("-lpthread_p");
+ else
+ CmdArgs.push_back("-lpthread");
+ }
+
+ if (Args.hasArg(options::OPT_pg)) {
+ if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-lc");
+ else {
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("--start-group");
+ CmdArgs.push_back("-lc_p");
+ CmdArgs.push_back("-lpthread_p");
+ CmdArgs.push_back("--end-group");
+ } else {
+ CmdArgs.push_back("-lc_p");
+ }
+ }
+ CmdArgs.push_back("-lgcc_p");
+ } else {
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("--start-group");
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("--end-group");
+ } else {
+ CmdArgs.push_back("-lc");
+ }
+ CmdArgs.push_back("-lcompiler_rt");
+ }
+
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-lstdc++");
+ } else if (Args.hasArg(options::OPT_pg)) {
+ CmdArgs.push_back("-lgcc_eh_p");
+ } else {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lstdc++");
+ CmdArgs.push_back("--no-as-needed");
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
+ else
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+ }
+
+ const char *Exec =
+#ifdef LLVM_ON_WIN32
+ Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold"));
+#else
+ Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
+#endif
+
+ C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
+}
+
+void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ const toolchains::FreeBSD &ToolChain =
+ static_cast<const toolchains::FreeBSD &>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+ bool PS4Linker;
+ StringRef LinkerOptName;
+ if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
+ LinkerOptName = A->getValue();
+ if (LinkerOptName != "ps4" && LinkerOptName != "gold")
+ D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName;
+ }
+
+ if (LinkerOptName == "gold")
+ PS4Linker = false;
+ else if (LinkerOptName == "ps4")
+ PS4Linker = true;
+ else
+ PS4Linker = !Args.hasArg(options::OPT_shared);
+
+ if (PS4Linker)
+ ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput);
+ else
+ ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput);
+}
+
+toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ if (Args.hasArg(clang::driver::options::OPT_static))
+ D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static"
+ << "PS4";
+
+ // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR
+ // if it exists; otherwise use the driver's installation path, which
+ // should be <SDK_DIR>/host_tools/bin.
+
+ SmallString<512> PS4SDKDir;
+ if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) {
+ if (!llvm::sys::fs::exists(EnvValue))
+ getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue;
+ PS4SDKDir = EnvValue;
+ } else {
+ PS4SDKDir = getDriver().Dir;
+ llvm::sys::path::append(PS4SDKDir, "/../../");
+ }
+
+ // By default, the driver won't report a warning if it can't find
+ // PS4's include or lib directories. This behavior could be changed if
+ // -Weverything or -Winvalid-or-nonexistent-directory options are passed.
+ // If -isysroot was passed, use that as the SDK base path.
+ std::string PrefixDir;
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ PrefixDir = A->getValue();
+ if (!llvm::sys::fs::exists(PrefixDir))
+ getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir;
+ } else
+ PrefixDir = PS4SDKDir.str();
+
+ SmallString<512> PS4SDKIncludeDir(PrefixDir);
+ llvm::sys::path::append(PS4SDKIncludeDir, "target/include");
+ if (!Args.hasArg(options::OPT_nostdinc) &&
+ !Args.hasArg(options::OPT_nostdlibinc) &&
+ !Args.hasArg(options::OPT_isysroot) &&
+ !Args.hasArg(options::OPT__sysroot_EQ) &&
+ !llvm::sys::fs::exists(PS4SDKIncludeDir)) {
+ getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
+ << "PS4 system headers" << PS4SDKIncludeDir;
+ }
+
+ SmallString<512> PS4SDKLibDir(PS4SDKDir);
+ llvm::sys::path::append(PS4SDKLibDir, "target/lib");
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs) &&
+ !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) &&
+ !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) &&
+ !Args.hasArg(options::OPT_emit_ast) &&
+ !llvm::sys::fs::exists(PS4SDKLibDir)) {
+ getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
+ << "PS4 system libraries" << PS4SDKLibDir;
+ return;
+ }
+ getFilePaths().push_back(PS4SDKLibDir.str());
+}
+
+Tool *toolchains::PS4CPU::buildAssembler() const {
+ return new tools::PS4cpu::Assemble(*this);
+}
+
+Tool *toolchains::PS4CPU::buildLinker() const {
+ return new tools::PS4cpu::Link(*this);
+}
+
+bool toolchains::PS4CPU::isPICDefault() const { return true; }
+
+bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; }
+
+SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const {
+ SanitizerMask Res = ToolChain::getSupportedSanitizers();
+ Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::Vptr;
+ return Res;
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.h
new file mode 100644
index 0000000..e507edb
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/PS4CPU.h
@@ -0,0 +1,93 @@
+//===--- PS4CPU.h - PS4CPU ToolChain Implementations ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PS4CPU_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PS4CPU_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+namespace PS4cpu {
+
+void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs);
+
+class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+public:
+ Assemble(const ToolChain &TC)
+ : Tool("PS4cpu::Assemble", "assembler", TC, RF_Full) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+public:
+ Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC, RF_Full) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace PS4cpu
+} // namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF {
+public:
+ PS4CPU(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ // No support for finding a C++ standard library yet.
+ std::string findLibCxxIncludePath() const override { return ""; }
+ void addLibStdCxxIncludePaths(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override {}
+
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
+ bool HasNativeLLVMSupport() const override;
+ bool isPICDefault() const override;
+
+ unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
+ return 2; // SSPStrong
+ }
+
+ llvm::DebuggerKind getDefaultDebuggerTuning() const override {
+ return llvm::DebuggerKind::SCE;
+ }
+
+ SanitizerMask getSupportedSanitizers() const override;
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PS4CPU_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.cpp
new file mode 100644
index 0000000..de98d11
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.cpp
@@ -0,0 +1,193 @@
+//===--- Solaris.cpp - Solaris ToolChain Implementations --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Solaris.h"
+#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ // Demangle C++ names in errors
+ CmdArgs.push_back("-C");
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
+ CmdArgs.push_back("-e");
+ CmdArgs.push_back("_start");
+ }
+
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-Bstatic");
+ CmdArgs.push_back("-dn");
+ } else {
+ CmdArgs.push_back("-Bdynamic");
+ if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-shared");
+ } else {
+ CmdArgs.push_back("--dynamic-linker");
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("ld.so.1")));
+ }
+ }
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
+
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("values-Xa.o")));
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ }
+
+ getToolChain().AddFilePathLibArgs(Args, CmdArgs);
+
+ Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
+ options::OPT_e, options::OPT_r});
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (getToolChain().getDriver().CCCIsCXX())
+ getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("-lc");
+ if (!Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("-lm");
+ }
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ CmdArgs.push_back(
+ Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+ }
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
+
+ getToolChain().addProfileRTLibs(Args, CmdArgs);
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
+
+Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+
+ GCCInstallation.init(Triple, Args);
+
+ path_list &Paths = getFilePaths();
+ if (GCCInstallation.isValid())
+ addPathIfExists(D, GCCInstallation.getInstallPath(), Paths);
+
+ addPathIfExists(D, getDriver().getInstalledDir(), Paths);
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ addPathIfExists(D, getDriver().Dir, Paths);
+
+ addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib", Paths);
+
+ std::string LibPath = "/usr/lib/";
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::sparc:
+ break;
+ case llvm::Triple::x86_64:
+ LibPath += "amd64/";
+ break;
+ case llvm::Triple::sparcv9:
+ LibPath += "sparcv9/";
+ break;
+ default:
+ llvm_unreachable("Unsupported architecture");
+ }
+
+ addPathIfExists(D, getDriver().SysRoot + LibPath, Paths);
+}
+
+Tool *Solaris::buildAssembler() const {
+ return new tools::solaris::Assembler(*this);
+}
+
+Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); }
+
+void Solaris::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ // Include the support directory for things like xlocale and fudged system
+ // headers.
+ // FIXME: This is a weird mix of libc++ and libstdc++. We should also be
+ // checking the value of -stdlib= here and adding the includes for libc++
+ // rather than libstdc++ if it's requested.
+ addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/v1/support/solaris");
+
+ if (GCCInstallation.isValid()) {
+ GCCVersion Version = GCCInstallation.getVersion();
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/gcc/" +
+ Version.MajorStr + "." +
+ Version.MinorStr +
+ "/include/c++/" + Version.Text);
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/gcc/" + Version.MajorStr +
+ "." + Version.MinorStr + "/include/c++/" +
+ Version.Text + "/" +
+ GCCInstallation.getTriple().str());
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.h
new file mode 100644
index 0000000..787917a
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Solaris.h
@@ -0,0 +1,75 @@
+//===--- Solaris.h - Solaris ToolChain Implementations ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SOLARIS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SOLARIS_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+/// solaris -- Directly call Solaris assembler and linker
+namespace solaris {
+class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+public:
+ Assembler(const ToolChain &TC)
+ : Tool("solaris::Assembler", "assembler", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("solaris::Linker", "linker", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace solaris
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_ELF {
+public:
+ Solaris(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+ bool IsIntegratedAssemblerDefault() const override { return true; }
+
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ unsigned GetDefaultDwarfVersion() const override { return 2; }
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SOLARIS_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/TCE.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/TCE.cpp
new file mode 100644
index 0000000..ae8a1c8
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/TCE.cpp
@@ -0,0 +1,47 @@
+//===--- TCE.cpp - TCE ToolChain Implementations ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TCE.h"
+#include "CommonArgs.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
+/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
+/// Currently does not support anything else but compilation.
+
+TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ // Path mangling to find libexec
+ std::string Path(getDriver().Dir);
+
+ Path += "/../libexec";
+ getProgramPaths().push_back(Path);
+}
+
+TCEToolChain::~TCEToolChain() {}
+
+bool TCEToolChain::IsMathErrnoDefault() const { return true; }
+
+bool TCEToolChain::isPICDefault() const { return false; }
+
+bool TCEToolChain::isPIEDefault() const { return false; }
+
+bool TCEToolChain::isPICDefaultForced() const { return false; }
+
+TCELEToolChain::TCELEToolChain(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : TCEToolChain(D, Triple, Args) {
+}
+
+TCELEToolChain::~TCELEToolChain() {}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/TCE.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/TCE.h
new file mode 100644
index 0000000..4644f4e
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/TCE.h
@@ -0,0 +1,47 @@
+//===--- TCE.h - TCE Tool and ToolChain Implementations ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_TCE_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_TCE_H
+
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/ToolChain.h"
+#include <set>
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
+/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
+class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain {
+public:
+ TCEToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~TCEToolChain() override;
+
+ bool IsMathErrnoDefault() const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+};
+
+/// Toolchain for little endian TCE cores.
+class LLVM_LIBRARY_VISIBILITY TCELEToolChain : public TCEToolChain {
+public:
+ TCELEToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~TCELEToolChain() override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_TCE_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp
new file mode 100644
index 0000000..058bc42
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -0,0 +1,168 @@
+//===--- WebAssembly.cpp - WebAssembly ToolChain Implementation -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "WebAssembly.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+wasm::Linker::Linker(const ToolChain &TC)
+ : GnuTool("wasm::Linker", "lld", TC) {}
+
+bool wasm::Linker::isLinkJob() const {
+ return true;
+}
+
+bool wasm::Linker::hasIntegratedCPP() const {
+ return false;
+}
+
+void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+
+ const ToolChain &ToolChain = getToolChain();
+ const Driver &D = ToolChain.getDriver();
+ const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath());
+ ArgStringList CmdArgs;
+ CmdArgs.push_back("-flavor");
+ CmdArgs.push_back("wasm");
+
+ // Enable garbage collection of unused input sections by default, since code
+ // size is of particular importance. This is significantly facilitated by
+ // the enabling of -ffunction-sections and -fdata-sections in
+ // Clang::ConstructJob.
+ if (areOptimizationsEnabled(Args))
+ CmdArgs.push_back("--gc-sections");
+
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export-dynamic");
+ if (Args.hasArg(options::OPT_s))
+ CmdArgs.push_back("--strip-all");
+ if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-shared");
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-Bstatic");
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+ ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("rcrt1.o")));
+ else if (Args.hasArg(options::OPT_pie))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));
+ else
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+ }
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+ if (D.CCCIsCXX())
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+
+ if (Args.hasArg(options::OPT_pthread))
+ CmdArgs.push_back("-lpthread");
+
+ CmdArgs.push_back("-allow-undefined-file");
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("wasm.syms")));
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lcompiler_rt");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs));
+}
+
+WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+
+ assert(Triple.isArch32Bit() != Triple.isArch64Bit());
+
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+
+ getFilePaths().push_back(getDriver().SysRoot + "/lib");
+}
+
+bool WebAssembly::IsMathErrnoDefault() const { return false; }
+
+bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; }
+
+bool WebAssembly::UseObjCMixedDispatch() const { return true; }
+
+bool WebAssembly::isPICDefault() const { return false; }
+
+bool WebAssembly::isPIEDefault() const { return false; }
+
+bool WebAssembly::isPICDefaultForced() const { return false; }
+
+bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; }
+
+// TODO: Support Objective C stuff.
+bool WebAssembly::SupportsObjCGC() const { return false; }
+
+bool WebAssembly::hasBlocksRuntime() const { return false; }
+
+// TODO: Support profiling.
+bool WebAssembly::SupportsProfiling() const { return false; }
+
+bool WebAssembly::HasNativeLLVMSupport() const { return true; }
+
+void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array, true))
+ CC1Args.push_back("-fuse-init-array");
+}
+
+ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const {
+ return ToolChain::RLT_CompilerRT;
+}
+
+ToolChain::CXXStdlibType WebAssembly::GetCXXStdlibType(const ArgList &Args) const {
+ return ToolChain::CST_Libcxx;
+}
+
+void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (!DriverArgs.hasArg(options::OPT_nostdinc))
+ addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include");
+}
+
+void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (!DriverArgs.hasArg(options::OPT_nostdlibinc) &&
+ !DriverArgs.hasArg(options::OPT_nostdincxx))
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/include/c++/v1");
+}
+
+Tool *WebAssembly::buildLinker() const {
+ return new tools::wasm::Linker(*this);
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.h
new file mode 100644
index 0000000..2999db4
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.h
@@ -0,0 +1,78 @@
+//===--- WebAssembly.h - WebAssembly ToolChain Implementations --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_WEBASSEMBLY_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_WEBASSEMBLY_H
+
+#include "Gnu.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace wasm {
+
+class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+public:
+ explicit Linker(const ToolChain &TC);
+ bool isLinkJob() const override;
+ bool hasIntegratedCPP() const override;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+} // end namespace wasm
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain {
+public:
+ WebAssembly(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+private:
+ bool IsMathErrnoDefault() const override;
+ bool IsObjCNonFragileABIDefault() const override;
+ bool UseObjCMixedDispatch() const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+ bool IsIntegratedAssemblerDefault() const override;
+ bool hasBlocksRuntime() const override;
+ bool SupportsObjCGC() const override;
+ bool SupportsProfiling() const override;
+ bool HasNativeLLVMSupport() const override;
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ RuntimeLibType GetDefaultRuntimeLibType() const override;
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+ void AddClangSystemIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
+ const char *getDefaultLinker() const override {
+ return "lld";
+ }
+
+ Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_WEBASSEMBLY_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/XCore.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/XCore.cpp
new file mode 100644
index 0000000..43175ad
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/XCore.cpp
@@ -0,0 +1,150 @@
+//===--- XCore.cpp - XCore ToolChain Implementations ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "XCore.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Option/ArgList.h"
+#include <cstdlib> // ::getenv
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+/// XCore Tools
+// We pass assemble and link construction to the xcc tool.
+
+void tools::XCore::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ claimNoWarnArgs(Args);
+ ArgStringList CmdArgs;
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ CmdArgs.push_back("-c");
+
+ if (Args.hasArg(options::OPT_v))
+ CmdArgs.push_back("-v");
+
+ if (Arg *A = Args.getLastArg(options::OPT_g_Group))
+ if (!A->getOption().matches(options::OPT_g0))
+ CmdArgs.push_back("-g");
+
+ if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
+ false))
+ CmdArgs.push_back("-fverbose-asm");
+
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
+
+ for (const auto &II : Inputs)
+ CmdArgs.push_back(II.getFilename());
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ } else {
+ assert(Output.isNothing() && "Invalid output.");
+ }
+
+ if (Args.hasArg(options::OPT_v))
+ CmdArgs.push_back("-v");
+
+ // Pass -fexceptions through to the linker if it was present.
+ if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
+ false))
+ CmdArgs.push_back("-fexceptions");
+
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
+ C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+}
+
+/// XCore tool chain
+XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ // ProgramPaths are found via 'PATH' environment variable.
+}
+
+Tool *XCoreToolChain::buildAssembler() const {
+ return new tools::XCore::Assembler(*this);
+}
+
+Tool *XCoreToolChain::buildLinker() const {
+ return new tools::XCore::Linker(*this);
+}
+
+bool XCoreToolChain::isPICDefault() const { return false; }
+
+bool XCoreToolChain::isPIEDefault() const { return false; }
+
+bool XCoreToolChain::isPICDefaultForced() const { return false; }
+
+bool XCoreToolChain::SupportsProfiling() const { return false; }
+
+bool XCoreToolChain::hasBlocksRuntime() const { return false; }
+
+void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+ if (const char *cl_include_dir = getenv("XCC_C_INCLUDE_PATH")) {
+ SmallVector<StringRef, 4> Dirs;
+ const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
+ StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr));
+ ArrayRef<StringRef> DirVec(Dirs);
+ addSystemIncludes(DriverArgs, CC1Args, DirVec);
+ }
+}
+
+void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args,
+ Action::OffloadKind) const {
+ CC1Args.push_back("-nostdsysteminc");
+}
+
+void XCoreToolChain::AddClangCXXStdlibIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+ if (const char *cl_include_dir = getenv("XCC_CPLUS_INCLUDE_PATH")) {
+ SmallVector<StringRef, 4> Dirs;
+ const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
+ StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr));
+ ArrayRef<StringRef> DirVec(Dirs);
+ addSystemIncludes(DriverArgs, CC1Args, DirVec);
+ }
+}
+
+void XCoreToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // We don't output any lib args. This is handled by xcc.
+}
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/XCore.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/XCore.h
new file mode 100644
index 0000000..00c89bd
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/XCore.h
@@ -0,0 +1,83 @@
+//===--- XCore.h - XCore ToolChain Implementations --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_XCORE_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_XCORE_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+
+namespace XCore {
+// For XCore, we do not need to instantiate tools for PreProcess, PreCompile and
+// Compile.
+// We simply use "clang -cc1" for those actions.
+class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
+public:
+ Assembler(const ToolChain &TC) : Tool("XCore::Assembler", "XCore-as", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("XCore::Linker", "XCore-ld", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace XCore.
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY XCoreToolChain : public ToolChain {
+public:
+ XCoreToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+
+public:
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+ bool SupportsProfiling() const override;
+ bool hasBlocksRuntime() const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_XCORE_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp
deleted file mode 100644
index 3c3d453..0000000
--- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp
+++ /dev/null
@@ -1,12226 +0,0 @@
-//===--- Tools.cpp - Tools Implementations ----------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Tools.h"
-#include "InputInfo.h"
-#include "ToolChains.h"
-#include "clang/Basic/CharInfo.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/ObjCRuntime.h"
-#include "clang/Basic/Version.h"
-#include "clang/Config/config.h"
-#include "clang/Driver/Action.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Job.h"
-#include "clang/Driver/Options.h"
-#include "clang/Driver/SanitizerArgs.h"
-#include "clang/Driver/ToolChain.h"
-#include "clang/Driver/Util.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/ArgList.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/Compression.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/ScopedPrinter.h"
-#include "llvm/Support/TargetParser.h"
-#include "llvm/Support/YAMLParser.h"
-
-#ifdef LLVM_ON_UNIX
-#include <unistd.h> // For getuid().
-#endif
-
-using namespace clang::driver;
-using namespace clang::driver::tools;
-using namespace clang;
-using namespace llvm::opt;
-
-static void handleTargetFeaturesGroup(const ArgList &Args,
- std::vector<StringRef> &Features,
- OptSpecifier Group) {
- for (const Arg *A : Args.filtered(Group)) {
- StringRef Name = A->getOption().getName();
- A->claim();
-
- // Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
- Name = Name.substr(1);
-
- bool IsNegative = Name.startswith("no-");
- if (IsNegative)
- Name = Name.substr(3);
- Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
- }
-}
-
-static const char *getSparcAsmModeForCPU(StringRef Name,
- const llvm::Triple &Triple) {
- if (Triple.getArch() == llvm::Triple::sparcv9) {
- return llvm::StringSwitch<const char *>(Name)
- .Case("niagara", "-Av9b")
- .Case("niagara2", "-Av9b")
- .Case("niagara3", "-Av9d")
- .Case("niagara4", "-Av9d")
- .Default("-Av9");
- } else {
- return llvm::StringSwitch<const char *>(Name)
- .Case("v8", "-Av8")
- .Case("supersparc", "-Av8")
- .Case("sparclite", "-Asparclite")
- .Case("f934", "-Asparclite")
- .Case("hypersparc", "-Av8")
- .Case("sparclite86x", "-Asparclite")
- .Case("sparclet", "-Asparclet")
- .Case("tsc701", "-Asparclet")
- .Case("v9", "-Av8plus")
- .Case("ultrasparc", "-Av8plus")
- .Case("ultrasparc3", "-Av8plus")
- .Case("niagara", "-Av8plusb")
- .Case("niagara2", "-Av8plusb")
- .Case("niagara3", "-Av8plusd")
- .Case("niagara4", "-Av8plusd")
- .Case("leon2", "-Av8")
- .Case("at697e", "-Av8")
- .Case("at697f", "-Av8")
- .Case("leon3", "-Av8")
- .Case("ut699", "-Av8")
- .Case("gr712rc", "-Av8")
- .Case("leon4", "-Av8")
- .Case("gr740", "-Av8")
- .Default("-Av8");
- }
-}
-
-static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
- if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) {
- if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) &&
- !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) {
- D.Diag(diag::err_drv_argument_only_allowed_with)
- << A->getBaseArg().getAsString(Args)
- << (D.IsCLMode() ? "/E, /P or /EP" : "-E");
- }
- }
-}
-
-static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) {
- // In gcc, only ARM checks this, but it seems reasonable to check universally.
- if (Args.hasArg(options::OPT_static))
- if (const Arg *A =
- Args.getLastArg(options::OPT_dynamic, options::OPT_mdynamic_no_pic))
- D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args)
- << "-static";
-}
-
-// Add backslashes to escape spaces and other backslashes.
-// This is used for the space-separated argument list specified with
-// the -dwarf-debug-flags option.
-static void EscapeSpacesAndBackslashes(const char *Arg,
- SmallVectorImpl<char> &Res) {
- for (; *Arg; ++Arg) {
- switch (*Arg) {
- default:
- break;
- case ' ':
- case '\\':
- Res.push_back('\\');
- break;
- }
- Res.push_back(*Arg);
- }
-}
-
-// Quote target names for inclusion in GNU Make dependency files.
-// Only the characters '$', '#', ' ', '\t' are quoted.
-static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) {
- for (unsigned i = 0, e = Target.size(); i != e; ++i) {
- switch (Target[i]) {
- case ' ':
- case '\t':
- // Escape the preceding backslashes
- for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
- Res.push_back('\\');
-
- // Escape the space/tab
- Res.push_back('\\');
- break;
- case '$':
- Res.push_back('$');
- break;
- case '#':
- Res.push_back('\\');
- break;
- default:
- break;
- }
-
- Res.push_back(Target[i]);
- }
-}
-
-static void addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs,
- const char *ArgName, const char *EnvVar) {
- const char *DirList = ::getenv(EnvVar);
- bool CombinedArg = false;
-
- if (!DirList)
- return; // Nothing to do.
-
- StringRef Name(ArgName);
- if (Name.equals("-I") || Name.equals("-L"))
- CombinedArg = true;
-
- StringRef Dirs(DirList);
- if (Dirs.empty()) // Empty string should not add '.'.
- return;
-
- StringRef::size_type Delim;
- while ((Delim = Dirs.find(llvm::sys::EnvPathSeparator)) != StringRef::npos) {
- if (Delim == 0) { // Leading colon.
- if (CombinedArg) {
- CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + "."));
- } else {
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(".");
- }
- } else {
- if (CombinedArg) {
- CmdArgs.push_back(
- Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim)));
- } else {
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim)));
- }
- }
- Dirs = Dirs.substr(Delim + 1);
- }
-
- if (Dirs.empty()) { // Trailing colon.
- if (CombinedArg) {
- CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + "."));
- } else {
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(".");
- }
- } else { // Add the last path.
- if (CombinedArg) {
- CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs));
- } else {
- CmdArgs.push_back(ArgName);
- CmdArgs.push_back(Args.MakeArgString(Dirs));
- }
- }
-}
-
-static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs,
- const ArgList &Args, ArgStringList &CmdArgs,
- const JobAction &JA) {
- const Driver &D = TC.getDriver();
-
- // Add extra linker input arguments which are not treated as inputs
- // (constructed via -Xarch_).
- Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input);
-
- for (const auto &II : Inputs) {
- // If the current tool chain refers to an OpenMP offloading host, we should
- // ignore inputs that refer to OpenMP offloading devices - they will be
- // embedded according to a proper linker script.
- if (auto *IA = II.getAction())
- if (JA.isHostOffloading(Action::OFK_OpenMP) &&
- IA->isDeviceOffloading(Action::OFK_OpenMP))
- continue;
-
- if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType()))
- // Don't try to pass LLVM inputs unless we have native support.
- D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString();
-
- // Add filenames immediately.
- if (II.isFilename()) {
- CmdArgs.push_back(II.getFilename());
- continue;
- }
-
- // Otherwise, this is a linker input argument.
- const Arg &A = II.getInputArg();
-
- // Handle reserved library options.
- if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx))
- TC.AddCXXStdlibLibArgs(Args, CmdArgs);
- else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext))
- TC.AddCCKextLibArgs(Args, CmdArgs);
- else if (A.getOption().matches(options::OPT_z)) {
- // Pass -z prefix for gcc linker compatibility.
- A.claim();
- A.render(Args, CmdArgs);
- } else {
- A.renderAsInput(Args, CmdArgs);
- }
- }
-
- // LIBRARY_PATH - included following the user specified library paths.
- // and only supported on native toolchains.
- if (!TC.isCrossCompiling())
- addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
-}
-
-/// Add OpenMP linker script arguments at the end of the argument list so that
-/// the fat binary is built by embedding each of the device images into the
-/// host. The linker script also defines a few symbols required by the code
-/// generation so that the images can be easily retrieved at runtime by the
-/// offloading library. This should be used only in tool chains that support
-/// linker scripts.
-static void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args, ArgStringList &CmdArgs,
- const JobAction &JA) {
-
- // If this is not an OpenMP host toolchain, we don't need to do anything.
- if (!JA.isHostOffloading(Action::OFK_OpenMP))
- return;
-
- // Create temporary linker script. Keep it if save-temps is enabled.
- const char *LKS;
- SmallString<256> Name = llvm::sys::path::filename(Output.getFilename());
- if (C.getDriver().isSaveTempsEnabled()) {
- llvm::sys::path::replace_extension(Name, "lk");
- LKS = C.getArgs().MakeArgString(Name.c_str());
- } else {
- llvm::sys::path::replace_extension(Name, "");
- Name = C.getDriver().GetTemporaryPath(Name, "lk");
- LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str()));
- }
-
- // Add linker script option to the command.
- CmdArgs.push_back("-T");
- CmdArgs.push_back(LKS);
-
- // Create a buffer to write the contents of the linker script.
- std::string LksBuffer;
- llvm::raw_string_ostream LksStream(LksBuffer);
-
- // Get the OpenMP offload tool chains so that we can extract the triple
- // associated with each device input.
- auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>();
- assert(OpenMPToolChains.first != OpenMPToolChains.second &&
- "No OpenMP toolchains??");
-
- // Track the input file name and device triple in order to build the script,
- // inserting binaries in the designated sections.
- SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo;
-
- // Add commands to embed target binaries. We ensure that each section and
- // image is 16-byte aligned. This is not mandatory, but increases the
- // likelihood of data to be aligned with a cache block in several main host
- // machines.
- LksStream << "/*\n";
- LksStream << " OpenMP Offload Linker Script\n";
- LksStream << " *** Automatically generated by Clang ***\n";
- LksStream << "*/\n";
- LksStream << "TARGET(binary)\n";
- auto DTC = OpenMPToolChains.first;
- for (auto &II : Inputs) {
- const Action *A = II.getAction();
- // Is this a device linking action?
- if (A && isa<LinkJobAction>(A) &&
- A->isDeviceOffloading(Action::OFK_OpenMP)) {
- assert(DTC != OpenMPToolChains.second &&
- "More device inputs than device toolchains??");
- InputBinaryInfo.push_back(std::make_pair(
- DTC->second->getTriple().normalize(), II.getFilename()));
- ++DTC;
- LksStream << "INPUT(" << II.getFilename() << ")\n";
- }
- }
-
- assert(DTC == OpenMPToolChains.second &&
- "Less device inputs than device toolchains??");
-
- LksStream << "SECTIONS\n";
- LksStream << "{\n";
- LksStream << " .omp_offloading :\n";
- LksStream << " ALIGN(0x10)\n";
- LksStream << " {\n";
-
- for (auto &BI : InputBinaryInfo) {
- LksStream << " . = ALIGN(0x10);\n";
- LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first
- << " = .);\n";
- LksStream << " " << BI.second << "\n";
- LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first
- << " = .);\n";
- }
-
- LksStream << " }\n";
- // Add commands to define host entries begin and end. We use 1-byte subalign
- // so that the linker does not add any padding and the elements in this
- // section form an array.
- LksStream << " .omp_offloading.entries :\n";
- LksStream << " ALIGN(0x10)\n";
- LksStream << " SUBALIGN(0x01)\n";
- LksStream << " {\n";
- LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n";
- LksStream << " *(.omp_offloading.entries)\n";
- LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n";
- LksStream << " }\n";
- LksStream << "}\n";
- LksStream << "INSERT BEFORE .data\n";
- LksStream.flush();
-
- // Dump the contents of the linker script if the user requested that. We
- // support this option to enable testing of behavior with -###.
- if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script))
- llvm::errs() << LksBuffer;
-
- // If this is a dry run, do not create the linker script file.
- if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
- return;
-
- // Open script file and write the contents.
- std::error_code EC;
- llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None);
-
- if (EC) {
- C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
- return;
- }
-
- Lksf << LksBuffer;
-}
-
-/// \brief Determine whether Objective-C automated reference counting is
-/// enabled.
-static bool isObjCAutoRefCount(const ArgList &Args) {
- return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false);
-}
-
-/// \brief Determine whether we are linking the ObjC runtime.
-static bool isObjCRuntimeLinked(const ArgList &Args) {
- if (isObjCAutoRefCount(Args)) {
- Args.ClaimAllArgs(options::OPT_fobjc_link_runtime);
- return true;
- }
- return Args.hasArg(options::OPT_fobjc_link_runtime);
-}
-
-static bool forwardToGCC(const Option &O) {
- // Don't forward inputs from the original command line. They are added from
- // InputInfoList.
- return O.getKind() != Option::InputClass &&
- !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput);
-}
-
-/// Apply \a Work on the current tool chain \a RegularToolChain and any other
-/// offloading tool chain that is associated with the current action \a JA.
-static void
-forAllAssociatedToolChains(Compilation &C, const JobAction &JA,
- const ToolChain &RegularToolChain,
- llvm::function_ref<void(const ToolChain &)> Work) {
- // Apply Work on the current/regular tool chain.
- Work(RegularToolChain);
-
- // Apply Work on all the offloading tool chains associated with the current
- // action.
- if (JA.isHostOffloading(Action::OFK_Cuda))
- Work(*C.getSingleOffloadToolChain<Action::OFK_Cuda>());
- else if (JA.isDeviceOffloading(Action::OFK_Cuda))
- Work(*C.getSingleOffloadToolChain<Action::OFK_Host>());
-
- //
- // TODO: Add support for other offloading programming models here.
- //
-}
-
-void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
- const Driver &D, const ArgList &Args,
- ArgStringList &CmdArgs,
- const InputInfo &Output,
- const InputInfoList &Inputs) const {
- Arg *A;
- const bool IsIAMCU = getToolChain().getTriple().isOSIAMCU();
-
- CheckPreprocessingOptions(D, Args);
-
- Args.AddLastArg(CmdArgs, options::OPT_C);
- Args.AddLastArg(CmdArgs, options::OPT_CC);
-
- // Handle dependency file generation.
- if ((A = Args.getLastArg(options::OPT_M, options::OPT_MM)) ||
- (A = Args.getLastArg(options::OPT_MD)) ||
- (A = Args.getLastArg(options::OPT_MMD))) {
- // Determine the output location.
- const char *DepFile;
- if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
- DepFile = MF->getValue();
- C.addFailureResultFile(DepFile, &JA);
- } else if (Output.getType() == types::TY_Dependencies) {
- DepFile = Output.getFilename();
- } else if (A->getOption().matches(options::OPT_M) ||
- A->getOption().matches(options::OPT_MM)) {
- DepFile = "-";
- } else {
- DepFile = getDependencyFileName(Args, Inputs);
- C.addFailureResultFile(DepFile, &JA);
- }
- CmdArgs.push_back("-dependency-file");
- CmdArgs.push_back(DepFile);
-
- // Add a default target if one wasn't specified.
- if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) {
- const char *DepTarget;
-
- // If user provided -o, that is the dependency target, except
- // when we are only generating a dependency file.
- Arg *OutputOpt = Args.getLastArg(options::OPT_o);
- if (OutputOpt && Output.getType() != types::TY_Dependencies) {
- DepTarget = OutputOpt->getValue();
- } else {
- // Otherwise derive from the base input.
- //
- // FIXME: This should use the computed output file location.
- SmallString<128> P(Inputs[0].getBaseInput());
- llvm::sys::path::replace_extension(P, "o");
- DepTarget = Args.MakeArgString(llvm::sys::path::filename(P));
- }
-
- CmdArgs.push_back("-MT");
- SmallString<128> Quoted;
- QuoteTarget(DepTarget, Quoted);
- CmdArgs.push_back(Args.MakeArgString(Quoted));
- }
-
- if (A->getOption().matches(options::OPT_M) ||
- A->getOption().matches(options::OPT_MD))
- CmdArgs.push_back("-sys-header-deps");
- if ((isa<PrecompileJobAction>(JA) &&
- !Args.hasArg(options::OPT_fno_module_file_deps)) ||
- Args.hasArg(options::OPT_fmodule_file_deps))
- CmdArgs.push_back("-module-file-deps");
- }
-
- if (Args.hasArg(options::OPT_MG)) {
- if (!A || A->getOption().matches(options::OPT_MD) ||
- A->getOption().matches(options::OPT_MMD))
- D.Diag(diag::err_drv_mg_requires_m_or_mm);
- CmdArgs.push_back("-MG");
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_MP);
- Args.AddLastArg(CmdArgs, options::OPT_MV);
-
- // Convert all -MQ <target> args to -MT <quoted target>
- for (const Arg *A : Args.filtered(options::OPT_MT, options::OPT_MQ)) {
- A->claim();
-
- if (A->getOption().matches(options::OPT_MQ)) {
- CmdArgs.push_back("-MT");
- SmallString<128> Quoted;
- QuoteTarget(A->getValue(), Quoted);
- CmdArgs.push_back(Args.MakeArgString(Quoted));
-
- // -MT flag - no change
- } else {
- A->render(Args, CmdArgs);
- }
- }
-
- // Add offload include arguments specific for CUDA. This must happen before
- // we -I or -include anything else, because we must pick up the CUDA headers
- // from the particular CUDA installation, rather than from e.g.
- // /usr/local/include.
- if (JA.isOffloading(Action::OFK_Cuda))
- getToolChain().AddCudaIncludeArgs(Args, CmdArgs);
-
- // Add -i* options, and automatically translate to
- // -include-pch/-include-pth for transparent PCH support. It's
- // wonky, but we include looking for .gch so we can support seamless
- // replacement into a build system already set up to be generating
- // .gch files.
- int YcIndex = -1, YuIndex = -1;
- {
- int AI = -1;
- const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc);
- const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu);
- for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) {
- // Walk the whole i_Group and skip non "-include" flags so that the index
- // here matches the index in the next loop below.
- ++AI;
- if (!A->getOption().matches(options::OPT_include))
- continue;
- if (YcArg && strcmp(A->getValue(), YcArg->getValue()) == 0)
- YcIndex = AI;
- if (YuArg && strcmp(A->getValue(), YuArg->getValue()) == 0)
- YuIndex = AI;
- }
- }
- if (isa<PrecompileJobAction>(JA) && YcIndex != -1) {
- Driver::InputList Inputs;
- D.BuildInputs(getToolChain(), C.getArgs(), Inputs);
- assert(Inputs.size() == 1 && "Need one input when building pch");
- CmdArgs.push_back(Args.MakeArgString(Twine("-find-pch-source=") +
- Inputs[0].second->getValue()));
- }
-
- bool RenderedImplicitInclude = false;
- int AI = -1;
- for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) {
- ++AI;
-
- if (getToolChain().getDriver().IsCLMode() &&
- A->getOption().matches(options::OPT_include)) {
- // In clang-cl mode, /Ycfoo.h means that all code up to a foo.h
- // include is compiled into foo.h, and everything after goes into
- // the .obj file. /Yufoo.h means that all includes prior to and including
- // foo.h are completely skipped and replaced with a use of the pch file
- // for foo.h. (Each flag can have at most one value, multiple /Yc flags
- // just mean that the last one wins.) If /Yc and /Yu are both present
- // and refer to the same file, /Yc wins.
- // Note that OPT__SLASH_FI gets mapped to OPT_include.
- // FIXME: The code here assumes that /Yc and /Yu refer to the same file.
- // cl.exe seems to support both flags with different values, but that
- // seems strange (which flag does /Fp now refer to?), so don't implement
- // that until someone needs it.
- int PchIndex = YcIndex != -1 ? YcIndex : YuIndex;
- if (PchIndex != -1) {
- if (isa<PrecompileJobAction>(JA)) {
- // When building the pch, skip all includes after the pch.
- assert(YcIndex != -1 && PchIndex == YcIndex);
- if (AI >= YcIndex)
- continue;
- } else {
- // When using the pch, skip all includes prior to the pch.
- if (AI < PchIndex) {
- A->claim();
- continue;
- }
- if (AI == PchIndex) {
- A->claim();
- CmdArgs.push_back("-include-pch");
- CmdArgs.push_back(
- Args.MakeArgString(D.GetClPchPath(C, A->getValue())));
- continue;
- }
- }
- }
- } else if (A->getOption().matches(options::OPT_include)) {
- // Handling of gcc-style gch precompiled headers.
- bool IsFirstImplicitInclude = !RenderedImplicitInclude;
- RenderedImplicitInclude = true;
-
- // Use PCH if the user requested it.
- bool UsePCH = D.CCCUsePCH;
-
- bool FoundPTH = false;
- bool FoundPCH = false;
- SmallString<128> P(A->getValue());
- // We want the files to have a name like foo.h.pch. Add a dummy extension
- // so that replace_extension does the right thing.
- P += ".dummy";
- if (UsePCH) {
- llvm::sys::path::replace_extension(P, "pch");
- if (llvm::sys::fs::exists(P))
- FoundPCH = true;
- }
-
- if (!FoundPCH) {
- llvm::sys::path::replace_extension(P, "pth");
- if (llvm::sys::fs::exists(P))
- FoundPTH = true;
- }
-
- if (!FoundPCH && !FoundPTH) {
- llvm::sys::path::replace_extension(P, "gch");
- if (llvm::sys::fs::exists(P)) {
- FoundPCH = UsePCH;
- FoundPTH = !UsePCH;
- }
- }
-
- if (FoundPCH || FoundPTH) {
- if (IsFirstImplicitInclude) {
- A->claim();
- if (UsePCH)
- CmdArgs.push_back("-include-pch");
- else
- CmdArgs.push_back("-include-pth");
- CmdArgs.push_back(Args.MakeArgString(P));
- continue;
- } else {
- // Ignore the PCH if not first on command line and emit warning.
- D.Diag(diag::warn_drv_pch_not_first_include) << P
- << A->getAsString(Args);
- }
- }
- } else if (A->getOption().matches(options::OPT_isystem_after)) {
- // Handling of paths which must come late. These entries are handled by
- // the toolchain itself after the resource dir is inserted in the right
- // search order.
- // Do not claim the argument so that the use of the argument does not
- // silently go unnoticed on toolchains which do not honour the option.
- continue;
- }
-
- // Not translated, render as usual.
- A->claim();
- A->render(Args, CmdArgs);
- }
-
- Args.AddAllArgs(CmdArgs,
- {options::OPT_D, options::OPT_U, options::OPT_I_Group,
- options::OPT_F, options::OPT_index_header_map});
-
- // Add -Wp, and -Xpreprocessor if using the preprocessor.
-
- // FIXME: There is a very unfortunate problem here, some troubled
- // souls abuse -Wp, to pass preprocessor options in gcc syntax. To
- // really support that we would have to parse and then translate
- // those options. :(
- Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA,
- options::OPT_Xpreprocessor);
-
- // -I- is a deprecated GCC feature, reject it.
- if (Arg *A = Args.getLastArg(options::OPT_I_))
- D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args);
-
- // If we have a --sysroot, and don't have an explicit -isysroot flag, add an
- // -isysroot to the CC1 invocation.
- StringRef sysroot = C.getSysRoot();
- if (sysroot != "") {
- if (!Args.hasArg(options::OPT_isysroot)) {
- CmdArgs.push_back("-isysroot");
- CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
- }
- }
-
- // Parse additional include paths from environment variables.
- // FIXME: We should probably sink the logic for handling these from the
- // frontend into the driver. It will allow deleting 4 otherwise unused flags.
- // CPATH - included following the user specified includes (but prior to
- // builtin and standard includes).
- addDirectoryList(Args, CmdArgs, "-I", "CPATH");
- // C_INCLUDE_PATH - system includes enabled when compiling C.
- addDirectoryList(Args, CmdArgs, "-c-isystem", "C_INCLUDE_PATH");
- // CPLUS_INCLUDE_PATH - system includes enabled when compiling C++.
- addDirectoryList(Args, CmdArgs, "-cxx-isystem", "CPLUS_INCLUDE_PATH");
- // OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC.
- addDirectoryList(Args, CmdArgs, "-objc-isystem", "OBJC_INCLUDE_PATH");
- // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++.
- addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH");
-
- // While adding the include arguments, we also attempt to retrieve the
- // arguments of related offloading toolchains or arguments that are specific
- // of an offloading programming model.
-
- // Add C++ include arguments, if needed.
- if (types::isCXX(Inputs[0].getType()))
- forAllAssociatedToolChains(C, JA, getToolChain(),
- [&Args, &CmdArgs](const ToolChain &TC) {
- TC.AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
- });
-
- // Add system include arguments for all targets but IAMCU.
- if (!IsIAMCU)
- forAllAssociatedToolChains(C, JA, getToolChain(),
- [&Args, &CmdArgs](const ToolChain &TC) {
- TC.AddClangSystemIncludeArgs(Args, CmdArgs);
- });
- else {
- // For IAMCU add special include arguments.
- getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs);
- }
-}
-
-// FIXME: Move to target hook.
-static bool isSignedCharDefault(const llvm::Triple &Triple) {
- switch (Triple.getArch()) {
- default:
- return true;
-
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- if (Triple.isOSDarwin() || Triple.isOSWindows())
- return true;
- return false;
-
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- if (Triple.isOSDarwin())
- return true;
- return false;
-
- case llvm::Triple::hexagon:
- case llvm::Triple::ppc64le:
- case llvm::Triple::systemz:
- case llvm::Triple::xcore:
- return false;
- }
-}
-
-static bool isNoCommonDefault(const llvm::Triple &Triple) {
- switch (Triple.getArch()) {
- default:
- return false;
-
- case llvm::Triple::xcore:
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- return true;
- }
-}
-
-// ARM tools start.
-
-// Get SubArch (vN).
-static int getARMSubArchVersionNumber(const llvm::Triple &Triple) {
- llvm::StringRef Arch = Triple.getArchName();
- return llvm::ARM::parseArchVersion(Arch);
-}
-
-// True if M-profile.
-static bool isARMMProfile(const llvm::Triple &Triple) {
- llvm::StringRef Arch = Triple.getArchName();
- unsigned Profile = llvm::ARM::parseArchProfile(Arch);
- return Profile == llvm::ARM::PK_M;
-}
-
-// Get Arch/CPU from args.
-static void getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch,
- llvm::StringRef &CPU, bool FromAs = false) {
- if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- CPU = A->getValue();
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
- Arch = A->getValue();
- if (!FromAs)
- return;
-
- for (const Arg *A :
- Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
- StringRef Value = A->getValue();
- if (Value.startswith("-mcpu="))
- CPU = Value.substr(6);
- if (Value.startswith("-march="))
- Arch = Value.substr(7);
- }
-}
-
-// Handle -mhwdiv=.
-// FIXME: Use ARMTargetParser.
-static void getARMHWDivFeatures(const Driver &D, const Arg *A,
- const ArgList &Args, StringRef HWDiv,
- std::vector<StringRef> &Features) {
- unsigned HWDivID = llvm::ARM::parseHWDiv(HWDiv);
- if (!llvm::ARM::getHWDivFeatures(HWDivID, Features))
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
-}
-
-// Handle -mfpu=.
-static void getARMFPUFeatures(const Driver &D, const Arg *A,
- const ArgList &Args, StringRef FPU,
- std::vector<StringRef> &Features) {
- unsigned FPUID = llvm::ARM::parseFPU(FPU);
- if (!llvm::ARM::getFPUFeatures(FPUID, Features))
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
-}
-
-// Decode ARM features from string like +[no]featureA+[no]featureB+...
-static bool DecodeARMFeatures(const Driver &D, StringRef text,
- std::vector<StringRef> &Features) {
- SmallVector<StringRef, 8> Split;
- text.split(Split, StringRef("+"), -1, false);
-
- for (StringRef Feature : Split) {
- StringRef FeatureName = llvm::ARM::getArchExtFeature(Feature);
- if (!FeatureName.empty())
- Features.push_back(FeatureName);
- else
- return false;
- }
- return true;
-}
-
-// Check if -march is valid by checking if it can be canonicalised and parsed.
-// getARMArch is used here instead of just checking the -march value in order
-// to handle -march=native correctly.
-static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args,
- llvm::StringRef ArchName,
- std::vector<StringRef> &Features,
- const llvm::Triple &Triple) {
- std::pair<StringRef, StringRef> Split = ArchName.split("+");
-
- std::string MArch = arm::getARMArch(ArchName, Triple);
- if (llvm::ARM::parseArch(MArch) == llvm::ARM::AK_INVALID ||
- (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
-}
-
-// Check -mcpu=. Needs ArchName to handle -mcpu=generic.
-static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args,
- llvm::StringRef CPUName, llvm::StringRef ArchName,
- std::vector<StringRef> &Features,
- const llvm::Triple &Triple) {
- std::pair<StringRef, StringRef> Split = CPUName.split("+");
-
- std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
- if (arm::getLLVMArchSuffixForARM(CPU, ArchName, Triple).empty() ||
- (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
-}
-
-static bool useAAPCSForMachO(const llvm::Triple &T) {
- // The backend is hardwired to assume AAPCS for M-class processors, ensure
- // the frontend matches that.
- return T.getEnvironment() == llvm::Triple::EABI ||
- T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T);
-}
-
-// Select the float ABI as determined by -msoft-float, -mhard-float, and
-// -mfloat-abi=.
-arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) {
- const Driver &D = TC.getDriver();
- const llvm::Triple &Triple = TC.getEffectiveTriple();
- auto SubArch = getARMSubArchVersionNumber(Triple);
- arm::FloatABI ABI = FloatABI::Invalid;
- if (Arg *A =
- Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
- options::OPT_mfloat_abi_EQ)) {
- if (A->getOption().matches(options::OPT_msoft_float)) {
- ABI = FloatABI::Soft;
- } else if (A->getOption().matches(options::OPT_mhard_float)) {
- ABI = FloatABI::Hard;
- } else {
- ABI = llvm::StringSwitch<arm::FloatABI>(A->getValue())
- .Case("soft", FloatABI::Soft)
- .Case("softfp", FloatABI::SoftFP)
- .Case("hard", FloatABI::Hard)
- .Default(FloatABI::Invalid);
- if (ABI == FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
- D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
- ABI = FloatABI::Soft;
- }
- }
-
- // It is incorrect to select hard float ABI on MachO platforms if the ABI is
- // "apcs-gnu".
- if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(Triple) &&
- ABI == FloatABI::Hard) {
- D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args)
- << Triple.getArchName();
- }
- }
-
- // If unspecified, choose the default based on the platform.
- if (ABI == FloatABI::Invalid) {
- switch (Triple.getOS()) {
- case llvm::Triple::Darwin:
- case llvm::Triple::MacOSX:
- case llvm::Triple::IOS:
- case llvm::Triple::TvOS: {
- // Darwin defaults to "softfp" for v6 and v7.
- ABI = (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft;
- ABI = Triple.isWatchABI() ? FloatABI::Hard : ABI;
- break;
- }
- case llvm::Triple::WatchOS:
- ABI = FloatABI::Hard;
- break;
-
- // FIXME: this is invalid for WindowsCE
- case llvm::Triple::Win32:
- ABI = FloatABI::Hard;
- break;
-
- case llvm::Triple::FreeBSD:
- switch (Triple.getEnvironment()) {
- case llvm::Triple::GNUEABIHF:
- ABI = FloatABI::Hard;
- break;
- default:
- // FreeBSD defaults to soft float
- ABI = FloatABI::Soft;
- break;
- }
- break;
-
- default:
- switch (Triple.getEnvironment()) {
- case llvm::Triple::GNUEABIHF:
- case llvm::Triple::MuslEABIHF:
- case llvm::Triple::EABIHF:
- ABI = FloatABI::Hard;
- break;
- case llvm::Triple::GNUEABI:
- case llvm::Triple::MuslEABI:
- case llvm::Triple::EABI:
- // EABI is always AAPCS, and if it was not marked 'hard', it's softfp
- ABI = FloatABI::SoftFP;
- break;
- case llvm::Triple::Android:
- ABI = (SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft;
- break;
- default:
- // Assume "soft", but warn the user we are guessing.
- if (Triple.isOSBinFormatMachO() &&
- Triple.getSubArch() == llvm::Triple::ARMSubArch_v7em)
- ABI = FloatABI::Hard;
- else
- ABI = FloatABI::Soft;
-
- if (Triple.getOS() != llvm::Triple::UnknownOS ||
- !Triple.isOSBinFormatMachO())
- D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
- break;
- }
- }
- }
-
- assert(ABI != FloatABI::Invalid && "must select an ABI");
- return ABI;
-}
-
-static void getARMTargetFeatures(const ToolChain &TC,
- const llvm::Triple &Triple,
- const ArgList &Args,
- ArgStringList &CmdArgs,
- std::vector<StringRef> &Features,
- bool ForAS) {
- const Driver &D = TC.getDriver();
-
- bool KernelOrKext =
- Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
- arm::FloatABI ABI = arm::getARMFloatABI(TC, Args);
- const Arg *WaCPU = nullptr, *WaFPU = nullptr;
- const Arg *WaHDiv = nullptr, *WaArch = nullptr;
-
- if (!ForAS) {
- // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
- // yet (it uses the -mfloat-abi and -msoft-float options), and it is
- // stripped out by the ARM target. We should probably pass this a new
- // -target-option, which is handled by the -cc1/-cc1as invocation.
- //
- // FIXME2: For consistency, it would be ideal if we set up the target
- // machine state the same when using the frontend or the assembler. We don't
- // currently do that for the assembler, we pass the options directly to the
- // backend and never even instantiate the frontend TargetInfo. If we did,
- // and used its handleTargetFeatures hook, then we could ensure the
- // assembler and the frontend behave the same.
-
- // Use software floating point operations?
- if (ABI == arm::FloatABI::Soft)
- Features.push_back("+soft-float");
-
- // Use software floating point argument passing?
- if (ABI != arm::FloatABI::Hard)
- Features.push_back("+soft-float-abi");
- } else {
- // Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down
- // to the assembler correctly.
- for (const Arg *A :
- Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
- StringRef Value = A->getValue();
- if (Value.startswith("-mfpu=")) {
- WaFPU = A;
- } else if (Value.startswith("-mcpu=")) {
- WaCPU = A;
- } else if (Value.startswith("-mhwdiv=")) {
- WaHDiv = A;
- } else if (Value.startswith("-march=")) {
- WaArch = A;
- }
- }
- }
-
- // Check -march. ClangAs gives preference to -Wa,-march=.
- const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ);
- StringRef ArchName;
- if (WaArch) {
- if (ArchArg)
- D.Diag(clang::diag::warn_drv_unused_argument)
- << ArchArg->getAsString(Args);
- ArchName = StringRef(WaArch->getValue()).substr(7);
- checkARMArchName(D, WaArch, Args, ArchName, Features, Triple);
- // FIXME: Set Arch.
- D.Diag(clang::diag::warn_drv_unused_argument) << WaArch->getAsString(Args);
- } else if (ArchArg) {
- ArchName = ArchArg->getValue();
- checkARMArchName(D, ArchArg, Args, ArchName, Features, Triple);
- }
-
- // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=.
- const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ);
- StringRef CPUName;
- if (WaCPU) {
- if (CPUArg)
- D.Diag(clang::diag::warn_drv_unused_argument)
- << CPUArg->getAsString(Args);
- CPUName = StringRef(WaCPU->getValue()).substr(6);
- checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Features, Triple);
- } else if (CPUArg) {
- CPUName = CPUArg->getValue();
- checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Features, Triple);
- }
-
- // Add CPU features for generic CPUs
- if (CPUName == "native") {
- llvm::StringMap<bool> HostFeatures;
- if (llvm::sys::getHostCPUFeatures(HostFeatures))
- for (auto &F : HostFeatures)
- Features.push_back(
- Args.MakeArgString((F.second ? "+" : "-") + F.first()));
- }
-
- // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
- const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
- if (WaFPU) {
- if (FPUArg)
- D.Diag(clang::diag::warn_drv_unused_argument)
- << FPUArg->getAsString(Args);
- getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6),
- Features);
- } else if (FPUArg) {
- getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
- }
-
- // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=.
- const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ);
- if (WaHDiv) {
- if (HDivArg)
- D.Diag(clang::diag::warn_drv_unused_argument)
- << HDivArg->getAsString(Args);
- getARMHWDivFeatures(D, WaHDiv, Args,
- StringRef(WaHDiv->getValue()).substr(8), Features);
- } else if (HDivArg)
- getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features);
-
- // Setting -msoft-float effectively disables NEON because of the GCC
- // implementation, although the same isn't true of VFP or VFP3.
- if (ABI == arm::FloatABI::Soft) {
- Features.push_back("-neon");
- // Also need to explicitly disable features which imply NEON.
- Features.push_back("-crypto");
- }
-
- // En/disable crc code generation.
- if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
- if (A->getOption().matches(options::OPT_mcrc))
- Features.push_back("+crc");
- else
- Features.push_back("-crc");
- }
-
- // Look for the last occurrence of -mlong-calls or -mno-long-calls. If
- // neither options are specified, see if we are compiling for kernel/kext and
- // decide whether to pass "+long-calls" based on the OS and its version.
- if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
- options::OPT_mno_long_calls)) {
- if (A->getOption().matches(options::OPT_mlong_calls))
- Features.push_back("+long-calls");
- } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) &&
- !Triple.isWatchOS()) {
- Features.push_back("+long-calls");
- }
-
- // Generate execute-only output (no data access to code sections).
- // Supported only on ARMv6T2 and ARMv7 and above.
- // Cannot be combined with -mno-movt or -mlong-calls
- if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) {
- if (A->getOption().matches(options::OPT_mexecute_only)) {
- if (getARMSubArchVersionNumber(Triple) < 7 &&
- llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::AK_ARMV6T2)
- D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName();
- else if (Arg *B = Args.getLastArg(options::OPT_mno_movt))
- D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
- // Long calls create constant pool entries and have not yet been fixed up
- // to play nicely with execute-only. Hence, they cannot be used in
- // execute-only code for now
- else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) {
- if (B->getOption().matches(options::OPT_mlong_calls))
- D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
- }
-
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-execute-only");
- }
- }
-
- // Kernel code has more strict alignment requirements.
- if (KernelOrKext)
- Features.push_back("+strict-align");
- else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
- options::OPT_munaligned_access)) {
- if (A->getOption().matches(options::OPT_munaligned_access)) {
- // No v6M core supports unaligned memory access (v6M ARM ARM A3.2).
- if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
- D.Diag(diag::err_target_unsupported_unaligned) << "v6m";
- // v8M Baseline follows on from v6M, so doesn't support unaligned memory
- // access either.
- else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline)
- D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base";
- } else
- Features.push_back("+strict-align");
- } else {
- // Assume pre-ARMv6 doesn't support unaligned accesses.
- //
- // ARMv6 may or may not support unaligned accesses depending on the
- // SCTLR.U bit, which is architecture-specific. We assume ARMv6
- // Darwin and NetBSD targets support unaligned accesses, and others don't.
- //
- // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit
- // which raises an alignment fault on unaligned accesses. Linux
- // defaults this bit to 0 and handles it as a system-wide (not
- // per-process) setting. It is therefore safe to assume that ARMv7+
- // Linux targets support unaligned accesses. The same goes for NaCl.
- //
- // The above behavior is consistent with GCC.
- int VersionNum = getARMSubArchVersionNumber(Triple);
- if (Triple.isOSDarwin() || Triple.isOSNetBSD()) {
- if (VersionNum < 6 ||
- Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
- Features.push_back("+strict-align");
- } else if (Triple.isOSLinux() || Triple.isOSNaCl()) {
- if (VersionNum < 7)
- Features.push_back("+strict-align");
- } else
- Features.push_back("+strict-align");
- }
-
- // llvm does not support reserving registers in general. There is support
- // for reserving r9 on ARM though (defined as a platform-specific register
- // in ARM EABI).
- if (Args.hasArg(options::OPT_ffixed_r9))
- Features.push_back("+reserve-r9");
-
- // The kext linker doesn't know how to deal with movw/movt.
- if (KernelOrKext || Args.hasArg(options::OPT_mno_movt))
- Features.push_back("+no-movt");
-}
-
-void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
- ArgStringList &CmdArgs, bool KernelOrKext) const {
- // Select the ABI to use.
- // FIXME: Support -meabi.
- // FIXME: Parts of this are duplicated in the backend, unify this somehow.
- const char *ABIName = nullptr;
- if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
- ABIName = A->getValue();
- } else if (Triple.isOSBinFormatMachO()) {
- if (useAAPCSForMachO(Triple)) {
- ABIName = "aapcs";
- } else if (Triple.isWatchABI()) {
- ABIName = "aapcs16";
- } else {
- ABIName = "apcs-gnu";
- }
- } else if (Triple.isOSWindows()) {
- // FIXME: this is invalid for WindowsCE
- ABIName = "aapcs";
- } else {
- // Select the default based on the platform.
- switch (Triple.getEnvironment()) {
- case llvm::Triple::Android:
- case llvm::Triple::GNUEABI:
- case llvm::Triple::GNUEABIHF:
- case llvm::Triple::MuslEABI:
- case llvm::Triple::MuslEABIHF:
- ABIName = "aapcs-linux";
- break;
- case llvm::Triple::EABIHF:
- case llvm::Triple::EABI:
- ABIName = "aapcs";
- break;
- default:
- if (Triple.getOS() == llvm::Triple::NetBSD)
- ABIName = "apcs-gnu";
- else
- ABIName = "aapcs";
- break;
- }
- }
- CmdArgs.push_back("-target-abi");
- CmdArgs.push_back(ABIName);
-
- // Determine floating point ABI from the options & target defaults.
- arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args);
- if (ABI == arm::FloatABI::Soft) {
- // Floating point operations and argument passing are soft.
- // FIXME: This changes CPP defines, we need -target-soft-float.
- CmdArgs.push_back("-msoft-float");
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("soft");
- } else if (ABI == arm::FloatABI::SoftFP) {
- // Floating point operations are hard, but argument passing is soft.
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("soft");
- } else {
- // Floating point operations and argument passing are hard.
- assert(ABI == arm::FloatABI::Hard && "Invalid float abi!");
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("hard");
- }
-
- // Forward the -mglobal-merge option for explicit control over the pass.
- if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
- options::OPT_mno_global_merge)) {
- CmdArgs.push_back("-backend-option");
- if (A->getOption().matches(options::OPT_mno_global_merge))
- CmdArgs.push_back("-arm-global-merge=false");
- else
- CmdArgs.push_back("-arm-global-merge=true");
- }
-
- if (!Args.hasFlag(options::OPT_mimplicit_float,
- options::OPT_mno_implicit_float, true))
- CmdArgs.push_back("-no-implicit-float");
-}
-// ARM tools end.
-
-/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are
-/// targeting. Set \p A to the Arg corresponding to the -mcpu or -mtune
-/// arguments if they are provided, or to nullptr otherwise.
-static std::string getAArch64TargetCPU(const ArgList &Args, Arg *&A) {
- std::string CPU;
- // If we have -mtune or -mcpu, use that.
- if ((A = Args.getLastArg(options::OPT_mtune_EQ))) {
- CPU = StringRef(A->getValue()).lower();
- } else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) {
- StringRef Mcpu = A->getValue();
- CPU = Mcpu.split("+").first.lower();
- }
-
- // Handle CPU name is 'native'.
- if (CPU == "native")
- return llvm::sys::getHostCPUName();
- else if (CPU.size())
- return CPU;
-
- // Make sure we pick "cyclone" if -arch is used.
- // FIXME: Should this be picked by checking the target triple instead?
- if (Args.getLastArg(options::OPT_arch))
- return "cyclone";
-
- return "generic";
-}
-
-void Clang::AddAArch64TargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
-
- if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) ||
- Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_fapple_kext))
- CmdArgs.push_back("-disable-red-zone");
-
- if (!Args.hasFlag(options::OPT_mimplicit_float,
- options::OPT_mno_implicit_float, true))
- CmdArgs.push_back("-no-implicit-float");
-
- const char *ABIName = nullptr;
- if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
- ABIName = A->getValue();
- else if (Triple.isOSDarwin())
- ABIName = "darwinpcs";
- else
- ABIName = "aapcs";
-
- CmdArgs.push_back("-target-abi");
- CmdArgs.push_back(ABIName);
-
- if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769,
- options::OPT_mno_fix_cortex_a53_835769)) {
- CmdArgs.push_back("-backend-option");
- if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769))
- CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1");
- else
- CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0");
- } else if (Triple.isAndroid()) {
- // Enabled A53 errata (835769) workaround by default on android
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1");
- }
-
- // Forward the -mglobal-merge option for explicit control over the pass.
- if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
- options::OPT_mno_global_merge)) {
- CmdArgs.push_back("-backend-option");
- if (A->getOption().matches(options::OPT_mno_global_merge))
- CmdArgs.push_back("-aarch64-global-merge=false");
- else
- CmdArgs.push_back("-aarch64-global-merge=true");
- }
-}
-
-// Get CPU and ABI names. They are not independent
-// so we have to calculate them together.
-void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple,
- StringRef &CPUName, StringRef &ABIName) {
- const char *DefMips32CPU = "mips32r2";
- const char *DefMips64CPU = "mips64r2";
-
- // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the
- // default for mips64(el)?-img-linux-gnu.
- if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies &&
- Triple.getEnvironment() == llvm::Triple::GNU) {
- DefMips32CPU = "mips32r6";
- DefMips64CPU = "mips64r6";
- }
-
- // MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android).
- if (Triple.isAndroid()) {
- DefMips32CPU = "mips32";
- DefMips64CPU = "mips64r6";
- }
-
- // MIPS3 is the default for mips64*-unknown-openbsd.
- if (Triple.getOS() == llvm::Triple::OpenBSD)
- DefMips64CPU = "mips3";
-
- if (Arg *A = Args.getLastArg(options::OPT_march_EQ, options::OPT_mcpu_EQ))
- CPUName = A->getValue();
-
- if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
- ABIName = A->getValue();
- // Convert a GNU style Mips ABI name to the name
- // accepted by LLVM Mips backend.
- ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName)
- .Case("32", "o32")
- .Case("64", "n64")
- .Default(ABIName);
- }
-
- // Setup default CPU and ABI names.
- if (CPUName.empty() && ABIName.empty()) {
- switch (Triple.getArch()) {
- default:
- llvm_unreachable("Unexpected triple arch name");
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- CPUName = DefMips32CPU;
- break;
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- CPUName = DefMips64CPU;
- break;
- }
- }
-
- if (ABIName.empty() &&
- (Triple.getVendor() == llvm::Triple::MipsTechnologies ||
- Triple.getVendor() == llvm::Triple::ImaginationTechnologies)) {
- ABIName = llvm::StringSwitch<const char *>(CPUName)
- .Case("mips1", "o32")
- .Case("mips2", "o32")
- .Case("mips3", "n64")
- .Case("mips4", "n64")
- .Case("mips5", "n64")
- .Case("mips32", "o32")
- .Case("mips32r2", "o32")
- .Case("mips32r3", "o32")
- .Case("mips32r5", "o32")
- .Case("mips32r6", "o32")
- .Case("mips64", "n64")
- .Case("mips64r2", "n64")
- .Case("mips64r3", "n64")
- .Case("mips64r5", "n64")
- .Case("mips64r6", "n64")
- .Case("octeon", "n64")
- .Case("p5600", "o32")
- .Default("");
- }
-
- if (ABIName.empty()) {
- // Deduce ABI name from the target triple.
- if (Triple.getArch() == llvm::Triple::mips ||
- Triple.getArch() == llvm::Triple::mipsel)
- ABIName = "o32";
- else
- ABIName = "n64";
- }
-
- if (CPUName.empty()) {
- // Deduce CPU name from ABI name.
- CPUName = llvm::StringSwitch<const char *>(ABIName)
- .Case("o32", DefMips32CPU)
- .Cases("n32", "n64", DefMips64CPU)
- .Default("");
- }
-
- // FIXME: Warn on inconsistent use of -march and -mabi.
-}
-
-std::string mips::getMipsABILibSuffix(const ArgList &Args,
- const llvm::Triple &Triple) {
- StringRef CPUName, ABIName;
- tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
- return llvm::StringSwitch<std::string>(ABIName)
- .Case("o32", "")
- .Case("n32", "32")
- .Case("n64", "64");
-}
-
-// Convert ABI name to the GNU tools acceptable variant.
-static StringRef getGnuCompatibleMipsABIName(StringRef ABI) {
- return llvm::StringSwitch<llvm::StringRef>(ABI)
- .Case("o32", "32")
- .Case("n64", "64")
- .Default(ABI);
-}
-
-// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
-// and -mfloat-abi=.
-static mips::FloatABI getMipsFloatABI(const Driver &D, const ArgList &Args) {
- mips::FloatABI ABI = mips::FloatABI::Invalid;
- if (Arg *A =
- Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
- options::OPT_mfloat_abi_EQ)) {
- if (A->getOption().matches(options::OPT_msoft_float))
- ABI = mips::FloatABI::Soft;
- else if (A->getOption().matches(options::OPT_mhard_float))
- ABI = mips::FloatABI::Hard;
- else {
- ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue())
- .Case("soft", mips::FloatABI::Soft)
- .Case("hard", mips::FloatABI::Hard)
- .Default(mips::FloatABI::Invalid);
- if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
- D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
- ABI = mips::FloatABI::Hard;
- }
- }
- }
-
- // If unspecified, choose the default based on the platform.
- if (ABI == mips::FloatABI::Invalid) {
- // Assume "hard", because it's a default value used by gcc.
- // When we start to recognize specific target MIPS processors,
- // we will be able to select the default more correctly.
- ABI = mips::FloatABI::Hard;
- }
-
- assert(ABI != mips::FloatABI::Invalid && "must select an ABI");
- return ABI;
-}
-
-static void AddTargetFeature(const ArgList &Args,
- std::vector<StringRef> &Features,
- OptSpecifier OnOpt, OptSpecifier OffOpt,
- StringRef FeatureName) {
- if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) {
- if (A->getOption().matches(OnOpt))
- Features.push_back(Args.MakeArgString("+" + FeatureName));
- else
- Features.push_back(Args.MakeArgString("-" + FeatureName));
- }
-}
-
-static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args,
- std::vector<StringRef> &Features) {
- StringRef CPUName;
- StringRef ABIName;
- mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
- ABIName = getGnuCompatibleMipsABIName(ABIName);
-
- AddTargetFeature(Args, Features, options::OPT_mno_abicalls,
- options::OPT_mabicalls, "noabicalls");
-
- mips::FloatABI FloatABI = getMipsFloatABI(D, Args);
- if (FloatABI == mips::FloatABI::Soft) {
- // FIXME: Note, this is a hack. We need to pass the selected float
- // mode to the MipsTargetInfoBase to define appropriate macros there.
- // Now it is the only method.
- Features.push_back("+soft-float");
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
- StringRef Val = StringRef(A->getValue());
- if (Val == "2008") {
- if (mips::getSupportedNanEncoding(CPUName) & mips::Nan2008)
- Features.push_back("+nan2008");
- else {
- Features.push_back("-nan2008");
- D.Diag(diag::warn_target_unsupported_nan2008) << CPUName;
- }
- } else if (Val == "legacy") {
- if (mips::getSupportedNanEncoding(CPUName) & mips::NanLegacy)
- Features.push_back("-nan2008");
- else {
- Features.push_back("+nan2008");
- D.Diag(diag::warn_target_unsupported_nanlegacy) << CPUName;
- }
- } else
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
- }
-
- AddTargetFeature(Args, Features, options::OPT_msingle_float,
- options::OPT_mdouble_float, "single-float");
- AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16,
- "mips16");
- AddTargetFeature(Args, Features, options::OPT_mmicromips,
- options::OPT_mno_micromips, "micromips");
- AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp,
- "dsp");
- AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2,
- "dspr2");
- AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa,
- "msa");
-
- // Add the last -mfp32/-mfpxx/-mfp64, if none are given and the ABI is O32
- // pass -mfpxx, or if none are given and fp64a is default, pass fp64 and
- // nooddspreg.
- if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
- options::OPT_mfp64)) {
- if (A->getOption().matches(options::OPT_mfp32))
- Features.push_back(Args.MakeArgString("-fp64"));
- else if (A->getOption().matches(options::OPT_mfpxx)) {
- Features.push_back(Args.MakeArgString("+fpxx"));
- Features.push_back(Args.MakeArgString("+nooddspreg"));
- } else
- Features.push_back(Args.MakeArgString("+fp64"));
- } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) {
- Features.push_back(Args.MakeArgString("+fpxx"));
- Features.push_back(Args.MakeArgString("+nooddspreg"));
- } else if (mips::isFP64ADefault(Triple, CPUName)) {
- Features.push_back(Args.MakeArgString("+fp64"));
- Features.push_back(Args.MakeArgString("+nooddspreg"));
- }
-
- AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg,
- options::OPT_modd_spreg, "nooddspreg");
-}
-
-void Clang::AddMIPSTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- const Driver &D = getToolChain().getDriver();
- StringRef CPUName;
- StringRef ABIName;
- const llvm::Triple &Triple = getToolChain().getTriple();
- mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
-
- CmdArgs.push_back("-target-abi");
- CmdArgs.push_back(ABIName.data());
-
- mips::FloatABI ABI = getMipsFloatABI(D, Args);
- if (ABI == mips::FloatABI::Soft) {
- // Floating point operations and argument passing are soft.
- CmdArgs.push_back("-msoft-float");
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("soft");
- } else {
- // Floating point operations and argument passing are hard.
- assert(ABI == mips::FloatABI::Hard && "Invalid float abi!");
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("hard");
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
- if (A->getOption().matches(options::OPT_mxgot)) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-mxgot");
- }
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1,
- options::OPT_mno_ldc1_sdc1)) {
- if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-mno-ldc1-sdc1");
- }
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division,
- options::OPT_mno_check_zero_division)) {
- if (A->getOption().matches(options::OPT_mno_check_zero_division)) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-mno-check-zero-division");
- }
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_G)) {
- StringRef v = A->getValue();
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v));
- A->claim();
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_mcompact_branches_EQ)) {
- StringRef Val = StringRef(A->getValue());
- if (mips::hasCompactBranches(CPUName)) {
- if (Val == "never" || Val == "always" || Val == "optimal") {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val));
- } else
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
- } else
- D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName;
- }
-}
-
-/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting.
-static std::string getPPCTargetCPU(const ArgList &Args) {
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef CPUName = A->getValue();
-
- if (CPUName == "native") {
- std::string CPU = llvm::sys::getHostCPUName();
- if (!CPU.empty() && CPU != "generic")
- return CPU;
- else
- return "";
- }
-
- return llvm::StringSwitch<const char *>(CPUName)
- .Case("common", "generic")
- .Case("440", "440")
- .Case("440fp", "440")
- .Case("450", "450")
- .Case("601", "601")
- .Case("602", "602")
- .Case("603", "603")
- .Case("603e", "603e")
- .Case("603ev", "603ev")
- .Case("604", "604")
- .Case("604e", "604e")
- .Case("620", "620")
- .Case("630", "pwr3")
- .Case("G3", "g3")
- .Case("7400", "7400")
- .Case("G4", "g4")
- .Case("7450", "7450")
- .Case("G4+", "g4+")
- .Case("750", "750")
- .Case("970", "970")
- .Case("G5", "g5")
- .Case("a2", "a2")
- .Case("a2q", "a2q")
- .Case("e500mc", "e500mc")
- .Case("e5500", "e5500")
- .Case("power3", "pwr3")
- .Case("power4", "pwr4")
- .Case("power5", "pwr5")
- .Case("power5x", "pwr5x")
- .Case("power6", "pwr6")
- .Case("power6x", "pwr6x")
- .Case("power7", "pwr7")
- .Case("power8", "pwr8")
- .Case("power9", "pwr9")
- .Case("pwr3", "pwr3")
- .Case("pwr4", "pwr4")
- .Case("pwr5", "pwr5")
- .Case("pwr5x", "pwr5x")
- .Case("pwr6", "pwr6")
- .Case("pwr6x", "pwr6x")
- .Case("pwr7", "pwr7")
- .Case("pwr8", "pwr8")
- .Case("pwr9", "pwr9")
- .Case("powerpc", "ppc")
- .Case("powerpc64", "ppc64")
- .Case("powerpc64le", "ppc64le")
- .Default("");
- }
-
- return "";
-}
-
-static void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args,
- std::vector<StringRef> &Features) {
- handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group);
-
- ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args);
- if (FloatABI == ppc::FloatABI::Soft)
- Features.push_back("-hard-float");
-
- // Altivec is a bit weird, allow overriding of the Altivec feature here.
- AddTargetFeature(Args, Features, options::OPT_faltivec,
- options::OPT_fno_altivec, "altivec");
-}
-
-ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) {
- ppc::FloatABI ABI = ppc::FloatABI::Invalid;
- if (Arg *A =
- Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
- options::OPT_mfloat_abi_EQ)) {
- if (A->getOption().matches(options::OPT_msoft_float))
- ABI = ppc::FloatABI::Soft;
- else if (A->getOption().matches(options::OPT_mhard_float))
- ABI = ppc::FloatABI::Hard;
- else {
- ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue())
- .Case("soft", ppc::FloatABI::Soft)
- .Case("hard", ppc::FloatABI::Hard)
- .Default(ppc::FloatABI::Invalid);
- if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
- D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
- ABI = ppc::FloatABI::Hard;
- }
- }
- }
-
- // If unspecified, choose the default based on the platform.
- if (ABI == ppc::FloatABI::Invalid) {
- ABI = ppc::FloatABI::Hard;
- }
-
- return ABI;
-}
-
-void Clang::AddPPCTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Select the ABI to use.
- const char *ABIName = nullptr;
- if (getToolChain().getTriple().isOSLinux())
- switch (getToolChain().getArch()) {
- case llvm::Triple::ppc64: {
- // When targeting a processor that supports QPX, or if QPX is
- // specifically enabled, default to using the ABI that supports QPX (so
- // long as it is not specifically disabled).
- bool HasQPX = false;
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- HasQPX = A->getValue() == StringRef("a2q");
- HasQPX = Args.hasFlag(options::OPT_mqpx, options::OPT_mno_qpx, HasQPX);
- if (HasQPX) {
- ABIName = "elfv1-qpx";
- break;
- }
-
- ABIName = "elfv1";
- break;
- }
- case llvm::Triple::ppc64le:
- ABIName = "elfv2";
- break;
- default:
- break;
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
- // The ppc64 linux abis are all "altivec" abis by default. Accept and ignore
- // the option if given as we don't have backend support for any targets
- // that don't use the altivec abi.
- if (StringRef(A->getValue()) != "altivec")
- ABIName = A->getValue();
-
- ppc::FloatABI FloatABI =
- ppc::getPPCFloatABI(getToolChain().getDriver(), Args);
-
- if (FloatABI == ppc::FloatABI::Soft) {
- // Floating point operations and argument passing are soft.
- CmdArgs.push_back("-msoft-float");
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("soft");
- } else {
- // Floating point operations and argument passing are hard.
- assert(FloatABI == ppc::FloatABI::Hard && "Invalid float abi!");
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("hard");
- }
-
- if (ABIName) {
- CmdArgs.push_back("-target-abi");
- CmdArgs.push_back(ABIName);
- }
-}
-
-bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) {
- Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
- return A && (A->getValue() == StringRef(Value));
-}
-
-/// Get the (LLVM) name of the R600 gpu we are targeting.
-static std::string getR600TargetGPU(const ArgList &Args) {
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- const char *GPUName = A->getValue();
- return llvm::StringSwitch<const char *>(GPUName)
- .Cases("rv630", "rv635", "r600")
- .Cases("rv610", "rv620", "rs780", "rs880")
- .Case("rv740", "rv770")
- .Case("palm", "cedar")
- .Cases("sumo", "sumo2", "sumo")
- .Case("hemlock", "cypress")
- .Case("aruba", "cayman")
- .Default(GPUName);
- }
- return "";
-}
-
-static std::string getLanaiTargetCPU(const ArgList &Args) {
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- return A->getValue();
- }
- return "";
-}
-
-sparc::FloatABI sparc::getSparcFloatABI(const Driver &D,
- const ArgList &Args) {
- sparc::FloatABI ABI = sparc::FloatABI::Invalid;
- if (Arg *A =
- Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
- options::OPT_mfloat_abi_EQ)) {
- if (A->getOption().matches(options::OPT_msoft_float))
- ABI = sparc::FloatABI::Soft;
- else if (A->getOption().matches(options::OPT_mhard_float))
- ABI = sparc::FloatABI::Hard;
- else {
- ABI = llvm::StringSwitch<sparc::FloatABI>(A->getValue())
- .Case("soft", sparc::FloatABI::Soft)
- .Case("hard", sparc::FloatABI::Hard)
- .Default(sparc::FloatABI::Invalid);
- if (ABI == sparc::FloatABI::Invalid &&
- !StringRef(A->getValue()).empty()) {
- D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
- ABI = sparc::FloatABI::Hard;
- }
- }
- }
-
- // If unspecified, choose the default based on the platform.
- // Only the hard-float ABI on Sparc is standardized, and it is the
- // default. GCC also supports a nonstandard soft-float ABI mode, also
- // implemented in LLVM. However as this is not standard we set the default
- // to be hard-float.
- if (ABI == sparc::FloatABI::Invalid) {
- ABI = sparc::FloatABI::Hard;
- }
-
- return ABI;
-}
-
-static void getSparcTargetFeatures(const Driver &D, const ArgList &Args,
- std::vector<StringRef> &Features) {
- sparc::FloatABI FloatABI = sparc::getSparcFloatABI(D, Args);
- if (FloatABI == sparc::FloatABI::Soft)
- Features.push_back("+soft-float");
-}
-
-void Clang::AddSparcTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- sparc::FloatABI FloatABI =
- sparc::getSparcFloatABI(getToolChain().getDriver(), Args);
-
- if (FloatABI == sparc::FloatABI::Soft) {
- // Floating point operations and argument passing are soft.
- CmdArgs.push_back("-msoft-float");
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("soft");
- } else {
- // Floating point operations and argument passing are hard.
- assert(FloatABI == sparc::FloatABI::Hard && "Invalid float abi!");
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("hard");
- }
-}
-
-void Clang::AddSystemZTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- if (Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false))
- CmdArgs.push_back("-mbackchain");
-}
-
-static const char *getSystemZTargetCPU(const ArgList &Args) {
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
- return A->getValue();
- return "z10";
-}
-
-static void getSystemZTargetFeatures(const ArgList &Args,
- std::vector<StringRef> &Features) {
- // -m(no-)htm overrides use of the transactional-execution facility.
- if (Arg *A = Args.getLastArg(options::OPT_mhtm, options::OPT_mno_htm)) {
- if (A->getOption().matches(options::OPT_mhtm))
- Features.push_back("+transactional-execution");
- else
- Features.push_back("-transactional-execution");
- }
- // -m(no-)vx overrides use of the vector facility.
- if (Arg *A = Args.getLastArg(options::OPT_mvx, options::OPT_mno_vx)) {
- if (A->getOption().matches(options::OPT_mvx))
- Features.push_back("+vector");
- else
- Features.push_back("-vector");
- }
-}
-
-static const char *getX86TargetCPU(const ArgList &Args,
- const llvm::Triple &Triple) {
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- if (StringRef(A->getValue()) != "native") {
- if (Triple.isOSDarwin() && Triple.getArchName() == "x86_64h")
- return "core-avx2";
-
- return A->getValue();
- }
-
- // FIXME: Reject attempts to use -march=native unless the target matches
- // the host.
- //
- // FIXME: We should also incorporate the detected target features for use
- // with -native.
- std::string CPU = llvm::sys::getHostCPUName();
- if (!CPU.empty() && CPU != "generic")
- return Args.MakeArgString(CPU);
- }
-
- if (const Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
- // Mapping built by referring to X86TargetInfo::getDefaultFeatures().
- StringRef Arch = A->getValue();
- const char *CPU;
- if (Triple.getArch() == llvm::Triple::x86) {
- CPU = llvm::StringSwitch<const char *>(Arch)
- .Case("IA32", "i386")
- .Case("SSE", "pentium3")
- .Case("SSE2", "pentium4")
- .Case("AVX", "sandybridge")
- .Case("AVX2", "haswell")
- .Default(nullptr);
- } else {
- CPU = llvm::StringSwitch<const char *>(Arch)
- .Case("AVX", "sandybridge")
- .Case("AVX2", "haswell")
- .Default(nullptr);
- }
- if (CPU)
- return CPU;
- }
-
- // Select the default CPU if none was given (or detection failed).
-
- if (Triple.getArch() != llvm::Triple::x86_64 &&
- Triple.getArch() != llvm::Triple::x86)
- return nullptr; // This routine is only handling x86 targets.
-
- bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
-
- // FIXME: Need target hooks.
- if (Triple.isOSDarwin()) {
- if (Triple.getArchName() == "x86_64h")
- return "core-avx2";
- // macosx10.12 drops support for all pre-Penryn Macs.
- // Simulators can still run on 10.11 though, like Xcode.
- if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12))
- return "penryn";
- // The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah.
- return Is64Bit ? "core2" : "yonah";
- }
-
- // Set up default CPU name for PS4 compilers.
- if (Triple.isPS4CPU())
- return "btver2";
-
- // On Android use targets compatible with gcc
- if (Triple.isAndroid())
- return Is64Bit ? "x86-64" : "i686";
-
- // Everything else goes to x86-64 in 64-bit mode.
- if (Is64Bit)
- return "x86-64";
-
- switch (Triple.getOS()) {
- case llvm::Triple::FreeBSD:
- case llvm::Triple::NetBSD:
- case llvm::Triple::OpenBSD:
- return "i486";
- case llvm::Triple::Haiku:
- return "i586";
- case llvm::Triple::Bitrig:
- return "i686";
- default:
- // Fallback to p4.
- return "pentium4";
- }
-}
-
-/// Get the (LLVM) name of the WebAssembly cpu we are targeting.
-static StringRef getWebAssemblyTargetCPU(const ArgList &Args) {
- // If we have -mcpu=, use that.
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef CPU = A->getValue();
-
-#ifdef __wasm__
- // Handle "native" by examining the host. "native" isn't meaningful when
- // cross compiling, so only support this when the host is also WebAssembly.
- if (CPU == "native")
- return llvm::sys::getHostCPUName();
-#endif
-
- return CPU;
- }
-
- return "generic";
-}
-
-static std::string getCPUName(const ArgList &Args, const llvm::Triple &T,
- bool FromAs = false) {
- Arg *A;
-
- switch (T.getArch()) {
- default:
- return "";
-
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- return getAArch64TargetCPU(Args, A);
-
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb: {
- StringRef MArch, MCPU;
- getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs);
- return arm::getARMTargetCPU(MCPU, MArch, T);
- }
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el: {
- StringRef CPUName;
- StringRef ABIName;
- mips::getMipsCPUAndABI(Args, T, CPUName, ABIName);
- return CPUName;
- }
-
- case llvm::Triple::nvptx:
- case llvm::Triple::nvptx64:
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
- return A->getValue();
- return "";
-
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le: {
- std::string TargetCPUName = getPPCTargetCPU(Args);
- // LLVM may default to generating code for the native CPU,
- // but, like gcc, we default to a more generic option for
- // each architecture. (except on Darwin)
- if (TargetCPUName.empty() && !T.isOSDarwin()) {
- if (T.getArch() == llvm::Triple::ppc64)
- TargetCPUName = "ppc64";
- else if (T.getArch() == llvm::Triple::ppc64le)
- TargetCPUName = "ppc64le";
- else
- TargetCPUName = "ppc";
- }
- return TargetCPUName;
- }
-
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::sparcv9:
- if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- return A->getValue();
- return "";
-
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- return getX86TargetCPU(Args, T);
-
- case llvm::Triple::hexagon:
- return "hexagon" +
- toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
-
- case llvm::Triple::lanai:
- return getLanaiTargetCPU(Args);
-
- case llvm::Triple::systemz:
- return getSystemZTargetCPU(Args);
-
- case llvm::Triple::r600:
- case llvm::Triple::amdgcn:
- return getR600TargetGPU(Args);
-
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- return getWebAssemblyTargetCPU(Args);
- }
-}
-
-static unsigned getLTOParallelism(const ArgList &Args, const Driver &D) {
- unsigned Parallelism = 0;
- Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ);
- if (LtoJobsArg &&
- StringRef(LtoJobsArg->getValue()).getAsInteger(10, Parallelism))
- D.Diag(diag::err_drv_invalid_int_value) << LtoJobsArg->getAsString(Args)
- << LtoJobsArg->getValue();
- return Parallelism;
-}
-
-// CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by
-// default.
-static bool isUseSeparateSections(const llvm::Triple &Triple) {
- return Triple.getOS() == llvm::Triple::CloudABI ||
- Triple.getArch() == llvm::Triple::wasm32 ||
- Triple.getArch() == llvm::Triple::wasm64;
-}
-
-static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
- ArgStringList &CmdArgs, bool IsThinLTO,
- const Driver &D) {
- // Tell the linker to load the plugin. This has to come before AddLinkerInputs
- // as gold requires -plugin to come before any -plugin-opt that -Wl might
- // forward.
- CmdArgs.push_back("-plugin");
- std::string Plugin =
- ToolChain.getDriver().Dir + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold.so";
- CmdArgs.push_back(Args.MakeArgString(Plugin));
-
- // Try to pass driver level flags relevant to LTO code generation down to
- // the plugin.
-
- // Handle flags for selecting CPU variants.
- std::string CPU = getCPUName(Args, ToolChain.getTriple());
- if (!CPU.empty())
- CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU));
-
- if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- StringRef OOpt;
- if (A->getOption().matches(options::OPT_O4) ||
- A->getOption().matches(options::OPT_Ofast))
- OOpt = "3";
- else if (A->getOption().matches(options::OPT_O))
- OOpt = A->getValue();
- else if (A->getOption().matches(options::OPT_O0))
- OOpt = "0";
- if (!OOpt.empty())
- CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt));
- }
-
- if (IsThinLTO)
- CmdArgs.push_back("-plugin-opt=thinlto");
-
- if (unsigned Parallelism = getLTOParallelism(Args, D))
- CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") +
- llvm::to_string(Parallelism)));
-
- // If an explicit debugger tuning argument appeared, pass it along.
- if (Arg *A = Args.getLastArg(options::OPT_gTune_Group,
- options::OPT_ggdbN_Group)) {
- if (A->getOption().matches(options::OPT_glldb))
- CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb");
- else if (A->getOption().matches(options::OPT_gsce))
- CmdArgs.push_back("-plugin-opt=-debugger-tune=sce");
- else
- CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb");
- }
-
- bool UseSeparateSections =
- isUseSeparateSections(ToolChain.getEffectiveTriple());
-
- if (Args.hasFlag(options::OPT_ffunction_sections,
- options::OPT_fno_function_sections, UseSeparateSections)) {
- CmdArgs.push_back("-plugin-opt=-function-sections");
- }
-
- if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
- UseSeparateSections)) {
- CmdArgs.push_back("-plugin-opt=-data-sections");
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) {
- StringRef FName = A->getValue();
- if (!llvm::sys::fs::exists(FName))
- D.Diag(diag::err_drv_no_such_file) << FName;
- else
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName));
- }
-}
-
-/// This is a helper function for validating the optional refinement step
-/// parameter in reciprocal argument strings. Return false if there is an error
-/// parsing the refinement step. Otherwise, return true and set the Position
-/// of the refinement step in the input string.
-static bool getRefinementStep(StringRef In, const Driver &D,
- const Arg &A, size_t &Position) {
- const char RefinementStepToken = ':';
- Position = In.find(RefinementStepToken);
- if (Position != StringRef::npos) {
- StringRef Option = A.getOption().getName();
- StringRef RefStep = In.substr(Position + 1);
- // Allow exactly one numeric character for the additional refinement
- // step parameter. This is reasonable for all currently-supported
- // operations and architectures because we would expect that a larger value
- // of refinement steps would cause the estimate "optimization" to
- // under-perform the native operation. Also, if the estimate does not
- // converge quickly, it probably will not ever converge, so further
- // refinement steps will not produce a better answer.
- if (RefStep.size() != 1) {
- D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
- return false;
- }
- char RefStepChar = RefStep[0];
- if (RefStepChar < '0' || RefStepChar > '9') {
- D.Diag(diag::err_drv_invalid_value) << Option << RefStep;
- return false;
- }
- }
- return true;
-}
-
-/// The -mrecip flag requires processing of many optional parameters.
-static void ParseMRecip(const Driver &D, const ArgList &Args,
- ArgStringList &OutStrings) {
- StringRef DisabledPrefixIn = "!";
- StringRef DisabledPrefixOut = "!";
- StringRef EnabledPrefixOut = "";
- StringRef Out = "-mrecip=";
-
- Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ);
- if (!A)
- return;
-
- unsigned NumOptions = A->getNumValues();
- if (NumOptions == 0) {
- // No option is the same as "all".
- OutStrings.push_back(Args.MakeArgString(Out + "all"));
- return;
- }
-
- // Pass through "all", "none", or "default" with an optional refinement step.
- if (NumOptions == 1) {
- StringRef Val = A->getValue(0);
- size_t RefStepLoc;
- if (!getRefinementStep(Val, D, *A, RefStepLoc))
- return;
- StringRef ValBase = Val.slice(0, RefStepLoc);
- if (ValBase == "all" || ValBase == "none" || ValBase == "default") {
- OutStrings.push_back(Args.MakeArgString(Out + Val));
- return;
- }
- }
-
- // Each reciprocal type may be enabled or disabled individually.
- // Check each input value for validity, concatenate them all back together,
- // and pass through.
-
- llvm::StringMap<bool> OptionStrings;
- OptionStrings.insert(std::make_pair("divd", false));
- OptionStrings.insert(std::make_pair("divf", false));
- OptionStrings.insert(std::make_pair("vec-divd", false));
- OptionStrings.insert(std::make_pair("vec-divf", false));
- OptionStrings.insert(std::make_pair("sqrtd", false));
- OptionStrings.insert(std::make_pair("sqrtf", false));
- OptionStrings.insert(std::make_pair("vec-sqrtd", false));
- OptionStrings.insert(std::make_pair("vec-sqrtf", false));
-
- for (unsigned i = 0; i != NumOptions; ++i) {
- StringRef Val = A->getValue(i);
-
- bool IsDisabled = Val.startswith(DisabledPrefixIn);
- // Ignore the disablement token for string matching.
- if (IsDisabled)
- Val = Val.substr(1);
-
- size_t RefStep;
- if (!getRefinementStep(Val, D, *A, RefStep))
- return;
-
- StringRef ValBase = Val.slice(0, RefStep);
- llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase);
- if (OptionIter == OptionStrings.end()) {
- // Try again specifying float suffix.
- OptionIter = OptionStrings.find(ValBase.str() + 'f');
- if (OptionIter == OptionStrings.end()) {
- // The input name did not match any known option string.
- D.Diag(diag::err_drv_unknown_argument) << Val;
- return;
- }
- // The option was specified without a float or double suffix.
- // Make sure that the double entry was not already specified.
- // The float entry will be checked below.
- if (OptionStrings[ValBase.str() + 'd']) {
- D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
- return;
- }
- }
-
- if (OptionIter->second == true) {
- // Duplicate option specified.
- D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val;
- return;
- }
-
- // Mark the matched option as found. Do not allow duplicate specifiers.
- OptionIter->second = true;
-
- // If the precision was not specified, also mark the double entry as found.
- if (ValBase.back() != 'f' && ValBase.back() != 'd')
- OptionStrings[ValBase.str() + 'd'] = true;
-
- // Build the output string.
- StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;
- Out = Args.MakeArgString(Out + Prefix + Val);
- if (i != NumOptions - 1)
- Out = Args.MakeArgString(Out + ",");
- }
-
- OutStrings.push_back(Args.MakeArgString(Out));
-}
-
-static void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args,
- std::vector<StringRef> &Features) {
- // If -march=native, autodetect the feature list.
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- if (StringRef(A->getValue()) == "native") {
- llvm::StringMap<bool> HostFeatures;
- if (llvm::sys::getHostCPUFeatures(HostFeatures))
- for (auto &F : HostFeatures)
- Features.push_back(
- Args.MakeArgString((F.second ? "+" : "-") + F.first()));
- }
- }
-
- if (Triple.getArchName() == "x86_64h") {
- // x86_64h implies quite a few of the more modern subtarget features
- // for Haswell class CPUs, but not all of them. Opt-out of a few.
- Features.push_back("-rdrnd");
- Features.push_back("-aes");
- Features.push_back("-pclmul");
- Features.push_back("-rtm");
- Features.push_back("-hle");
- Features.push_back("-fsgsbase");
- }
-
- const llvm::Triple::ArchType ArchType = Triple.getArch();
- // Add features to be compatible with gcc for Android.
- if (Triple.isAndroid()) {
- if (ArchType == llvm::Triple::x86_64) {
- Features.push_back("+sse4.2");
- Features.push_back("+popcnt");
- } else
- Features.push_back("+ssse3");
- }
-
- // Set features according to the -arch flag on MSVC.
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
- StringRef Arch = A->getValue();
- bool ArchUsed = false;
- // First, look for flags that are shared in x86 and x86-64.
- if (ArchType == llvm::Triple::x86_64 || ArchType == llvm::Triple::x86) {
- if (Arch == "AVX" || Arch == "AVX2") {
- ArchUsed = true;
- Features.push_back(Args.MakeArgString("+" + Arch.lower()));
- }
- }
- // Then, look for x86-specific flags.
- if (ArchType == llvm::Triple::x86) {
- if (Arch == "IA32") {
- ArchUsed = true;
- } else if (Arch == "SSE" || Arch == "SSE2") {
- ArchUsed = true;
- Features.push_back(Args.MakeArgString("+" + Arch.lower()));
- }
- }
- if (!ArchUsed)
- D.Diag(clang::diag::warn_drv_unused_argument) << A->getAsString(Args);
- }
-
- // Now add any that the user explicitly requested on the command line,
- // which may override the defaults.
- handleTargetFeaturesGroup(Args, Features, options::OPT_m_x86_Features_Group);
-}
-
-void Clang::AddX86TargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) ||
- Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_fapple_kext))
- CmdArgs.push_back("-disable-red-zone");
-
- // Default to avoid implicit floating-point for kernel/kext code, but allow
- // that to be overridden with -mno-soft-float.
- bool NoImplicitFloat = (Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_fapple_kext));
- if (Arg *A = Args.getLastArg(
- options::OPT_msoft_float, options::OPT_mno_soft_float,
- options::OPT_mimplicit_float, options::OPT_mno_implicit_float)) {
- const Option &O = A->getOption();
- NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) ||
- O.matches(options::OPT_msoft_float));
- }
- if (NoImplicitFloat)
- CmdArgs.push_back("-no-implicit-float");
-
- if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
- StringRef Value = A->getValue();
- if (Value == "intel" || Value == "att") {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
- } else {
- getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
- }
- }
-
- // Set flags to support MCU ABI.
- if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) {
- CmdArgs.push_back("-mfloat-abi");
- CmdArgs.push_back("soft");
- CmdArgs.push_back("-mstack-alignment=4");
- }
-}
-
-void Clang::AddHexagonTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- CmdArgs.push_back("-mqdsp6-compat");
- CmdArgs.push_back("-Wreturn-type");
-
- if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
- std::string N = llvm::utostr(G.getValue());
- std::string Opt = std::string("-hexagon-small-data-threshold=") + N;
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString(Opt));
- }
-
- if (!Args.hasArg(options::OPT_fno_short_enums))
- CmdArgs.push_back("-fshort-enums");
- if (Args.getLastArg(options::OPT_mieee_rnd_near)) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-enable-hexagon-ieee-rnd-near");
- }
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-machine-sink-split=0");
-}
-
-void Clang::AddLanaiTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef CPUName = A->getValue();
-
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(CPUName));
- }
- if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
- StringRef Value = A->getValue();
- // Only support mregparm=4 to support old usage. Report error for all other
- // cases.
- int Mregparm;
- if (Value.getAsInteger(10, Mregparm)) {
- if (Mregparm != 4) {
- getToolChain().getDriver().Diag(
- diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
- }
- }
- }
-}
-
-void Clang::AddWebAssemblyTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Default to "hidden" visibility.
- if (!Args.hasArg(options::OPT_fvisibility_EQ,
- options::OPT_fvisibility_ms_compat)) {
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back("hidden");
- }
-}
-
-// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
-static bool DecodeAArch64Features(const Driver &D, StringRef text,
- std::vector<StringRef> &Features) {
- SmallVector<StringRef, 8> Split;
- text.split(Split, StringRef("+"), -1, false);
-
- for (StringRef Feature : Split) {
- StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
- if (!FeatureName.empty())
- Features.push_back(FeatureName);
- else if (Feature == "neon" || Feature == "noneon")
- D.Diag(diag::err_drv_no_neon_modifier);
- else
- return false;
- }
- return true;
-}
-
-// Check if the CPU name and feature modifiers in -mcpu are legal. If yes,
-// decode CPU and feature.
-static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
- std::vector<StringRef> &Features) {
- std::pair<StringRef, StringRef> Split = Mcpu.split("+");
- CPU = Split.first;
-
- if (CPU == "generic") {
- Features.push_back("+neon");
- } else {
- unsigned ArchKind = llvm::AArch64::parseCPUArch(CPU);
- if (!llvm::AArch64::getArchFeatures(ArchKind, Features))
- return false;
-
- unsigned Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind);
- if (!llvm::AArch64::getExtensionFeatures(Extension, Features))
- return false;
- }
-
- if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))
- return false;
-
- return true;
-}
-
-static bool
-getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
- const ArgList &Args,
- std::vector<StringRef> &Features) {
- std::string MarchLowerCase = March.lower();
- std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
-
- unsigned ArchKind = llvm::AArch64::parseArch(Split.first);
- if (ArchKind == static_cast<unsigned>(llvm::AArch64::ArchKind::AK_INVALID) ||
- !llvm::AArch64::getArchFeatures(ArchKind, Features) ||
- (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)))
- return false;
-
- return true;
-}
-
-static bool
-getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
- const ArgList &Args,
- std::vector<StringRef> &Features) {
- StringRef CPU;
- std::string McpuLowerCase = Mcpu.lower();
- if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features))
- return false;
-
- return true;
-}
-
-static bool
-getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
- const ArgList &Args,
- std::vector<StringRef> &Features) {
- std::string MtuneLowerCase = Mtune.lower();
- // Handle CPU name is 'native'.
- if (MtuneLowerCase == "native")
- MtuneLowerCase = llvm::sys::getHostCPUName();
- if (MtuneLowerCase == "cyclone") {
- Features.push_back("+zcm");
- Features.push_back("+zcz");
- }
- return true;
-}
-
-static bool
-getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
- const ArgList &Args,
- std::vector<StringRef> &Features) {
- StringRef CPU;
- std::vector<StringRef> DecodedFeature;
- std::string McpuLowerCase = Mcpu.lower();
- if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature))
- return false;
-
- return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
-}
-
-static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
- std::vector<StringRef> &Features) {
- Arg *A;
- bool success = true;
- // Enable NEON by default.
- Features.push_back("+neon");
- if ((A = Args.getLastArg(options::OPT_march_EQ)))
- success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features);
- else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
- success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
- else if (Args.hasArg(options::OPT_arch))
- success = getAArch64ArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args, A),
- Args, Features);
-
- if (success && (A = Args.getLastArg(options::OPT_mtune_EQ)))
- success =
- getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features);
- else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
- success =
- getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
- else if (success && Args.hasArg(options::OPT_arch))
- success = getAArch64MicroArchFeaturesFromMcpu(
- D, getAArch64TargetCPU(Args, A), Args, Features);
-
- if (!success)
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
-
- if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
- Features.push_back("-fp-armv8");
- Features.push_back("-crypto");
- Features.push_back("-neon");
- }
-
- // En/disable crc
- if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
- if (A->getOption().matches(options::OPT_mcrc))
- Features.push_back("+crc");
- else
- Features.push_back("-crc");
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
- options::OPT_munaligned_access))
- if (A->getOption().matches(options::OPT_mno_unaligned_access))
- Features.push_back("+strict-align");
-
- if (Args.hasArg(options::OPT_ffixed_x18))
- Features.push_back("+reserve-x18");
-}
-
-static void getHexagonTargetFeatures(const ArgList &Args,
- std::vector<StringRef> &Features) {
- handleTargetFeaturesGroup(Args, Features,
- options::OPT_m_hexagon_Features_Group);
-
- bool UseLongCalls = false;
- if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
- options::OPT_mno_long_calls)) {
- if (A->getOption().matches(options::OPT_mlong_calls))
- UseLongCalls = true;
- }
-
- Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls");
-}
-
-static void getWebAssemblyTargetFeatures(const ArgList &Args,
- std::vector<StringRef> &Features) {
- handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group);
-}
-
-static void getAMDGPUTargetFeatures(const Driver &D, const ArgList &Args,
- std::vector<StringRef> &Features) {
- if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) {
- StringRef value = dAbi->getValue();
- if (value == "1.0") {
- Features.push_back("+amdgpu-debugger-insert-nops");
- Features.push_back("+amdgpu-debugger-reserve-regs");
- Features.push_back("+amdgpu-debugger-emit-prologue");
- } else {
- D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args);
- }
- }
-
- handleTargetFeaturesGroup(
- Args, Features, options::OPT_m_amdgpu_Features_Group);
-}
-
-static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
- const ArgList &Args, ArgStringList &CmdArgs,
- bool ForAS) {
- const Driver &D = TC.getDriver();
- std::vector<StringRef> Features;
- switch (Triple.getArch()) {
- default:
- break;
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- getMIPSTargetFeatures(D, Triple, Args, Features);
- break;
-
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS);
- break;
-
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- getPPCTargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::systemz:
- getSystemZTargetFeatures(Args, Features);
- break;
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- getAArch64TargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- getX86TargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::hexagon:
- getHexagonTargetFeatures(Args, Features);
- break;
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- getWebAssemblyTargetFeatures(Args, Features);
- break;
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::sparcv9:
- getSparcTargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::r600:
- case llvm::Triple::amdgcn:
- getAMDGPUTargetFeatures(D, Args, Features);
- break;
- }
-
- // Find the last of each feature.
- llvm::StringMap<unsigned> LastOpt;
- for (unsigned I = 0, N = Features.size(); I < N; ++I) {
- StringRef Name = Features[I];
- assert(Name[0] == '-' || Name[0] == '+');
- LastOpt[Name.drop_front(1)] = I;
- }
-
- for (unsigned I = 0, N = Features.size(); I < N; ++I) {
- // If this feature was overridden, ignore it.
- StringRef Name = Features[I];
- llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1));
- assert(LastI != LastOpt.end());
- unsigned Last = LastI->second;
- if (Last != I)
- continue;
-
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back(Name.data());
- }
-}
-
-static bool
-shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
- const llvm::Triple &Triple) {
- // We use the zero-cost exception tables for Objective-C if the non-fragile
- // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and
- // later.
- if (runtime.isNonFragile())
- return true;
-
- if (!Triple.isMacOSX())
- return false;
-
- return (!Triple.isMacOSXVersionLT(10, 5) &&
- (Triple.getArch() == llvm::Triple::x86_64 ||
- Triple.getArch() == llvm::Triple::arm));
-}
-
-/// Adds exception related arguments to the driver command arguments. There's a
-/// master flag, -fexceptions and also language specific flags to enable/disable
-/// C++ and Objective-C exceptions. This makes it possible to for example
-/// disable C++ exceptions but enable Objective-C exceptions.
-static void addExceptionArgs(const ArgList &Args, types::ID InputType,
- const ToolChain &TC, bool KernelOrKext,
- const ObjCRuntime &objcRuntime,
- ArgStringList &CmdArgs) {
- const Driver &D = TC.getDriver();
- const llvm::Triple &Triple = TC.getTriple();
-
- if (KernelOrKext) {
- // -mkernel and -fapple-kext imply no exceptions, so claim exception related
- // arguments now to avoid warnings about unused arguments.
- Args.ClaimAllArgs(options::OPT_fexceptions);
- Args.ClaimAllArgs(options::OPT_fno_exceptions);
- Args.ClaimAllArgs(options::OPT_fobjc_exceptions);
- Args.ClaimAllArgs(options::OPT_fno_objc_exceptions);
- Args.ClaimAllArgs(options::OPT_fcxx_exceptions);
- Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions);
- return;
- }
-
- // See if the user explicitly enabled exceptions.
- bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
- false);
-
- // Obj-C exceptions are enabled by default, regardless of -fexceptions. This
- // is not necessarily sensible, but follows GCC.
- if (types::isObjC(InputType) &&
- Args.hasFlag(options::OPT_fobjc_exceptions,
- options::OPT_fno_objc_exceptions, true)) {
- CmdArgs.push_back("-fobjc-exceptions");
-
- EH |= shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple);
- }
-
- if (types::isCXX(InputType)) {
- // Disable C++ EH by default on XCore and PS4.
- bool CXXExceptionsEnabled =
- Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU();
- Arg *ExceptionArg = Args.getLastArg(
- options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions,
- options::OPT_fexceptions, options::OPT_fno_exceptions);
- if (ExceptionArg)
- CXXExceptionsEnabled =
- ExceptionArg->getOption().matches(options::OPT_fcxx_exceptions) ||
- ExceptionArg->getOption().matches(options::OPT_fexceptions);
-
- if (CXXExceptionsEnabled) {
- if (Triple.isPS4CPU()) {
- ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
- assert(ExceptionArg &&
- "On the PS4 exceptions should only be enabled if passing "
- "an argument");
- if (RTTIMode == ToolChain::RM_DisabledExplicitly) {
- const Arg *RTTIArg = TC.getRTTIArg();
- assert(RTTIArg && "RTTI disabled explicitly but no RTTIArg!");
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << RTTIArg->getAsString(Args) << ExceptionArg->getAsString(Args);
- } else if (RTTIMode == ToolChain::RM_EnabledImplicitly)
- D.Diag(diag::warn_drv_enabling_rtti_with_exceptions);
- } else
- assert(TC.getRTTIMode() != ToolChain::RM_DisabledImplicitly);
-
- CmdArgs.push_back("-fcxx-exceptions");
-
- EH = true;
- }
- }
-
- if (EH)
- CmdArgs.push_back("-fexceptions");
-}
-
-static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) {
- bool Default = true;
- if (TC.getTriple().isOSDarwin()) {
- // The native darwin assembler doesn't support the linker_option directives,
- // so we disable them if we think the .s file will be passed to it.
- Default = TC.useIntegratedAs();
- }
- return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink,
- Default);
-}
-
-static bool ShouldDisableDwarfDirectory(const ArgList &Args,
- const ToolChain &TC) {
- bool UseDwarfDirectory =
- Args.hasFlag(options::OPT_fdwarf_directory_asm,
- options::OPT_fno_dwarf_directory_asm, TC.useIntegratedAs());
- return !UseDwarfDirectory;
-}
-
-/// \brief Check whether the given input tree contains any compilation actions.
-static bool ContainsCompileAction(const Action *A) {
- if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A))
- return true;
-
- for (const auto &AI : A->inputs())
- if (ContainsCompileAction(AI))
- return true;
-
- return false;
-}
-
-/// \brief Check if -relax-all should be passed to the internal assembler.
-/// This is done by default when compiling non-assembler source with -O0.
-static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
- bool RelaxDefault = true;
-
- if (Arg *A = Args.getLastArg(options::OPT_O_Group))
- RelaxDefault = A->getOption().matches(options::OPT_O0);
-
- if (RelaxDefault) {
- RelaxDefault = false;
- for (const auto &Act : C.getActions()) {
- if (ContainsCompileAction(Act)) {
- RelaxDefault = true;
- break;
- }
- }
- }
-
- return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all,
- RelaxDefault);
-}
-
-// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases
-// to the corresponding DebugInfoKind.
-static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) {
- assert(A.getOption().matches(options::OPT_gN_Group) &&
- "Not a -g option that specifies a debug-info level");
- if (A.getOption().matches(options::OPT_g0) ||
- A.getOption().matches(options::OPT_ggdb0))
- return codegenoptions::NoDebugInfo;
- if (A.getOption().matches(options::OPT_gline_tables_only) ||
- A.getOption().matches(options::OPT_ggdb1))
- return codegenoptions::DebugLineTablesOnly;
- return codegenoptions::LimitedDebugInfo;
-}
-
-// Extract the integer N from a string spelled "-dwarf-N", returning 0
-// on mismatch. The StringRef input (rather than an Arg) allows
-// for use by the "-Xassembler" option parser.
-static unsigned DwarfVersionNum(StringRef ArgValue) {
- return llvm::StringSwitch<unsigned>(ArgValue)
- .Case("-gdwarf-2", 2)
- .Case("-gdwarf-3", 3)
- .Case("-gdwarf-4", 4)
- .Case("-gdwarf-5", 5)
- .Default(0);
-}
-
-static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
- codegenoptions::DebugInfoKind DebugInfoKind,
- unsigned DwarfVersion,
- llvm::DebuggerKind DebuggerTuning) {
- switch (DebugInfoKind) {
- case codegenoptions::DebugLineTablesOnly:
- CmdArgs.push_back("-debug-info-kind=line-tables-only");
- break;
- case codegenoptions::LimitedDebugInfo:
- CmdArgs.push_back("-debug-info-kind=limited");
- break;
- case codegenoptions::FullDebugInfo:
- CmdArgs.push_back("-debug-info-kind=standalone");
- break;
- default:
- break;
- }
- if (DwarfVersion > 0)
- CmdArgs.push_back(
- Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion)));
- switch (DebuggerTuning) {
- case llvm::DebuggerKind::GDB:
- CmdArgs.push_back("-debugger-tuning=gdb");
- break;
- case llvm::DebuggerKind::LLDB:
- CmdArgs.push_back("-debugger-tuning=lldb");
- break;
- case llvm::DebuggerKind::SCE:
- CmdArgs.push_back("-debugger-tuning=sce");
- break;
- default:
- break;
- }
-}
-
-static void CollectArgsForIntegratedAssembler(Compilation &C,
- const ArgList &Args,
- ArgStringList &CmdArgs,
- const Driver &D) {
- if (UseRelaxAll(C, Args))
- CmdArgs.push_back("-mrelax-all");
-
- // Only default to -mincremental-linker-compatible if we think we are
- // targeting the MSVC linker.
- bool DefaultIncrementalLinkerCompatible =
- C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
- if (Args.hasFlag(options::OPT_mincremental_linker_compatible,
- options::OPT_mno_incremental_linker_compatible,
- DefaultIncrementalLinkerCompatible))
- CmdArgs.push_back("-mincremental-linker-compatible");
-
- switch (C.getDefaultToolChain().getArch()) {
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- if (Arg *A = Args.getLastArg(options::OPT_mimplicit_it_EQ)) {
- StringRef Value = A->getValue();
- if (Value == "always" || Value == "never" || Value == "arm" ||
- Value == "thumb") {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString("-arm-implicit-it=" + Value));
- } else {
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
- }
- }
- break;
- default:
- break;
- }
-
- // When passing -I arguments to the assembler we sometimes need to
- // unconditionally take the next argument. For example, when parsing
- // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the
- // -Wa,-I arg and when parsing '-Wa,-I,foo' we need to accept the 'foo'
- // arg after parsing the '-I' arg.
- bool TakeNextArg = false;
-
- // When using an integrated assembler, translate -Wa, and -Xassembler
- // options.
- bool CompressDebugSections = false;
-
- bool UseRelaxRelocations = ENABLE_X86_RELAX_RELOCATIONS;
- const char *MipsTargetFeature = nullptr;
- for (const Arg *A :
- Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
- A->claim();
-
- for (StringRef Value : A->getValues()) {
- if (TakeNextArg) {
- CmdArgs.push_back(Value.data());
- TakeNextArg = false;
- continue;
- }
-
- if (C.getDefaultToolChain().getTriple().isOSBinFormatCOFF() &&
- Value == "-mbig-obj")
- continue; // LLVM handles bigobj automatically
-
- switch (C.getDefaultToolChain().getArch()) {
- default:
- break;
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- if (Value == "--trap") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+use-tcc-in-div");
- continue;
- }
- if (Value == "--break") {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-use-tcc-in-div");
- continue;
- }
- if (Value.startswith("-msoft-float")) {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("+soft-float");
- continue;
- }
- if (Value.startswith("-mhard-float")) {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back("-soft-float");
- continue;
- }
-
- MipsTargetFeature = llvm::StringSwitch<const char *>(Value)
- .Case("-mips1", "+mips1")
- .Case("-mips2", "+mips2")
- .Case("-mips3", "+mips3")
- .Case("-mips4", "+mips4")
- .Case("-mips5", "+mips5")
- .Case("-mips32", "+mips32")
- .Case("-mips32r2", "+mips32r2")
- .Case("-mips32r3", "+mips32r3")
- .Case("-mips32r5", "+mips32r5")
- .Case("-mips32r6", "+mips32r6")
- .Case("-mips64", "+mips64")
- .Case("-mips64r2", "+mips64r2")
- .Case("-mips64r3", "+mips64r3")
- .Case("-mips64r5", "+mips64r5")
- .Case("-mips64r6", "+mips64r6")
- .Default(nullptr);
- if (MipsTargetFeature)
- continue;
- }
-
- if (Value == "-force_cpusubtype_ALL") {
- // Do nothing, this is the default and we don't support anything else.
- } else if (Value == "-L") {
- CmdArgs.push_back("-msave-temp-labels");
- } else if (Value == "--fatal-warnings") {
- CmdArgs.push_back("-massembler-fatal-warnings");
- } else if (Value == "--noexecstack") {
- CmdArgs.push_back("-mnoexecstack");
- } else if (Value == "-compress-debug-sections" ||
- Value == "--compress-debug-sections") {
- CompressDebugSections = true;
- } else if (Value == "-nocompress-debug-sections" ||
- Value == "--nocompress-debug-sections") {
- CompressDebugSections = false;
- } else if (Value == "-mrelax-relocations=yes" ||
- Value == "--mrelax-relocations=yes") {
- UseRelaxRelocations = true;
- } else if (Value == "-mrelax-relocations=no" ||
- Value == "--mrelax-relocations=no") {
- UseRelaxRelocations = false;
- } else if (Value.startswith("-I")) {
- CmdArgs.push_back(Value.data());
- // We need to consume the next argument if the current arg is a plain
- // -I. The next arg will be the include directory.
- if (Value == "-I")
- TakeNextArg = true;
- } else if (Value.startswith("-gdwarf-")) {
- // "-gdwarf-N" options are not cc1as options.
- unsigned DwarfVersion = DwarfVersionNum(Value);
- if (DwarfVersion == 0) { // Send it onward, and let cc1as complain.
- CmdArgs.push_back(Value.data());
- } else {
- RenderDebugEnablingArgs(Args, CmdArgs,
- codegenoptions::LimitedDebugInfo,
- DwarfVersion, llvm::DebuggerKind::Default);
- }
- } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") ||
- Value.startswith("-mhwdiv") || Value.startswith("-march")) {
- // Do nothing, we'll validate it later.
- } else if (Value == "-defsym") {
- if (A->getNumValues() != 2) {
- D.Diag(diag::err_drv_defsym_invalid_format) << Value;
- break;
- }
- const char *S = A->getValue(1);
- auto Pair = StringRef(S).split('=');
- auto Sym = Pair.first;
- auto SVal = Pair.second;
-
- if (Sym.empty() || SVal.empty()) {
- D.Diag(diag::err_drv_defsym_invalid_format) << S;
- break;
- }
- int64_t IVal;
- if (SVal.getAsInteger(0, IVal)) {
- D.Diag(diag::err_drv_defsym_invalid_symval) << SVal;
- break;
- }
- CmdArgs.push_back(Value.data());
- TakeNextArg = true;
- } else {
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
- }
- }
- }
- if (CompressDebugSections) {
- if (llvm::zlib::isAvailable())
- CmdArgs.push_back("-compress-debug-sections");
- else
- D.Diag(diag::warn_debug_compression_unavailable);
- }
- if (UseRelaxRelocations)
- CmdArgs.push_back("--mrelax-relocations");
- if (MipsTargetFeature != nullptr) {
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back(MipsTargetFeature);
- }
-}
-
-// This adds the static libclang_rt.builtins-arch.a directly to the command line
-// FIXME: Make sure we can also emit shared objects if they're requested
-// and available, check for possible errors, etc.
-static void addClangRT(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins"));
-}
-
-static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
- const ArgList &Args) {
- if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
- options::OPT_fno_openmp, false))
- return;
-
- switch (TC.getDriver().getOpenMPRuntime(Args)) {
- case Driver::OMPRT_OMP:
- CmdArgs.push_back("-lomp");
- break;
- case Driver::OMPRT_GOMP:
- CmdArgs.push_back("-lgomp");
- break;
- case Driver::OMPRT_IOMP5:
- CmdArgs.push_back("-liomp5");
- break;
- case Driver::OMPRT_Unknown:
- // Already diagnosed.
- break;
- }
-}
-
-static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs, StringRef Sanitizer,
- bool IsShared, bool IsWhole) {
- // Wrap any static runtimes that must be forced into executable in
- // whole-archive.
- if (IsWhole) CmdArgs.push_back("-whole-archive");
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared));
- if (IsWhole) CmdArgs.push_back("-no-whole-archive");
-}
-
-// Tries to use a file with the list of dynamic symbols that need to be exported
-// from the runtime library. Returns true if the file was found.
-static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs,
- StringRef Sanitizer) {
- SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer));
- if (llvm::sys::fs::exists(SanRT + ".syms")) {
- CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms"));
- return true;
- }
- return false;
-}
-
-static void linkSanitizerRuntimeDeps(const ToolChain &TC,
- ArgStringList &CmdArgs) {
- // Force linking against the system libraries sanitizers depends on
- // (see PR15823 why this is necessary).
- CmdArgs.push_back("--no-as-needed");
- // There's no libpthread or librt on RTEMS.
- if (TC.getTriple().getOS() != llvm::Triple::RTEMS) {
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-lrt");
- }
- CmdArgs.push_back("-lm");
- // There's no libdl on FreeBSD or RTEMS.
- if (TC.getTriple().getOS() != llvm::Triple::FreeBSD &&
- TC.getTriple().getOS() != llvm::Triple::RTEMS)
- CmdArgs.push_back("-ldl");
-}
-
-static void
-collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
- SmallVectorImpl<StringRef> &SharedRuntimes,
- SmallVectorImpl<StringRef> &StaticRuntimes,
- SmallVectorImpl<StringRef> &NonWholeStaticRuntimes,
- SmallVectorImpl<StringRef> &HelperStaticRuntimes,
- SmallVectorImpl<StringRef> &RequiredSymbols) {
- const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
- // Collect shared runtimes.
- if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) {
- SharedRuntimes.push_back("asan");
- }
- // The stats_client library is also statically linked into DSOs.
- if (SanArgs.needsStatsRt())
- StaticRuntimes.push_back("stats_client");
-
- // Collect static runtimes.
- if (Args.hasArg(options::OPT_shared) || TC.getTriple().isAndroid()) {
- // Don't link static runtimes into DSOs or if compiling for Android.
- return;
- }
- if (SanArgs.needsAsanRt()) {
- if (SanArgs.needsSharedAsanRt()) {
- HelperStaticRuntimes.push_back("asan-preinit");
- } else {
- StaticRuntimes.push_back("asan");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("asan_cxx");
- }
- }
- if (SanArgs.needsDfsanRt())
- StaticRuntimes.push_back("dfsan");
- if (SanArgs.needsLsanRt())
- StaticRuntimes.push_back("lsan");
- if (SanArgs.needsMsanRt()) {
- StaticRuntimes.push_back("msan");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("msan_cxx");
- }
- if (SanArgs.needsTsanRt()) {
- StaticRuntimes.push_back("tsan");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("tsan_cxx");
- }
- if (SanArgs.needsUbsanRt()) {
- StaticRuntimes.push_back("ubsan_standalone");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("ubsan_standalone_cxx");
- }
- if (SanArgs.needsSafeStackRt())
- StaticRuntimes.push_back("safestack");
- if (SanArgs.needsCfiRt())
- StaticRuntimes.push_back("cfi");
- if (SanArgs.needsCfiDiagRt()) {
- StaticRuntimes.push_back("cfi_diag");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("ubsan_standalone_cxx");
- }
- if (SanArgs.needsStatsRt()) {
- NonWholeStaticRuntimes.push_back("stats");
- RequiredSymbols.push_back("__sanitizer_stats_register");
- }
- if (SanArgs.needsEsanRt())
- StaticRuntimes.push_back("esan");
-}
-
-// Should be called before we add system libraries (C++ ABI, libstdc++/libc++,
-// C runtime, etc). Returns true if sanitizer system deps need to be linked in.
-static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes,
- NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols;
- collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
- NonWholeStaticRuntimes, HelperStaticRuntimes,
- RequiredSymbols);
- for (auto RT : SharedRuntimes)
- addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false);
- for (auto RT : HelperStaticRuntimes)
- addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
- bool AddExportDynamic = false;
- for (auto RT : StaticRuntimes) {
- addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true);
- AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
- }
- for (auto RT : NonWholeStaticRuntimes) {
- addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false);
- AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT);
- }
- for (auto S : RequiredSymbols) {
- CmdArgs.push_back("-u");
- CmdArgs.push_back(Args.MakeArgString(S));
- }
- // If there is a static runtime with no dynamic list, force all the symbols
- // to be dynamic to be sure we export sanitizer interface functions.
- if (AddExportDynamic)
- CmdArgs.push_back("-export-dynamic");
-
- const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
- if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic)
- CmdArgs.push_back("-export-dynamic-symbol=__cfi_check");
-
- return !StaticRuntimes.empty();
-}
-
-static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (Args.hasFlag(options::OPT_fxray_instrument,
- options::OPT_fnoxray_instrument, false)) {
- CmdArgs.push_back("-whole-archive");
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false));
- CmdArgs.push_back("-no-whole-archive");
- return true;
- }
- return false;
-}
-
-static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- CmdArgs.push_back("--no-as-needed");
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-lrt");
- CmdArgs.push_back("-lm");
- CmdArgs.push_back("-latomic");
- if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
- CmdArgs.push_back("-lc++");
- else
- CmdArgs.push_back("-lstdc++");
- if (TC.getTriple().getOS() != llvm::Triple::FreeBSD)
- CmdArgs.push_back("-ldl");
-}
-
-static bool areOptimizationsEnabled(const ArgList &Args) {
- // Find the last -O arg and see if it is non-zero.
- if (Arg *A = Args.getLastArg(options::OPT_O_Group))
- return !A->getOption().matches(options::OPT_O0);
- // Defaults to -O0.
- return false;
-}
-
-static bool mustUseFramePointerForTarget(const llvm::Triple &Triple) {
- switch (Triple.getArch()){
- default:
- return false;
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- // ARM Darwin targets require a frame pointer to be always present to aid
- // offline debugging via backtraces.
- return Triple.isOSDarwin();
- }
-}
-
-static bool useFramePointerForTargetByDefault(const ArgList &Args,
- const llvm::Triple &Triple) {
- switch (Triple.getArch()) {
- case llvm::Triple::xcore:
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- // XCore never wants frame pointers, regardless of OS.
- // WebAssembly never wants frame pointers.
- return false;
- default:
- break;
- }
-
- if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI) {
- switch (Triple.getArch()) {
- // Don't use a frame pointer on linux if optimizing for certain targets.
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::systemz:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- return !areOptimizationsEnabled(Args);
- default:
- return true;
- }
- }
-
- if (Triple.isOSWindows()) {
- switch (Triple.getArch()) {
- case llvm::Triple::x86:
- return !areOptimizationsEnabled(Args);
- case llvm::Triple::x86_64:
- return Triple.isOSBinFormatMachO();
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- // Windows on ARM builds with FPO disabled to aid fast stack walking
- return true;
- default:
- // All other supported Windows ISAs use xdata unwind information, so frame
- // pointers are not generally useful.
- return false;
- }
- }
-
- return true;
-}
-
-static bool shouldUseFramePointer(const ArgList &Args,
- const llvm::Triple &Triple) {
- if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer,
- options::OPT_fomit_frame_pointer))
- return A->getOption().matches(options::OPT_fno_omit_frame_pointer) ||
- mustUseFramePointerForTarget(Triple);
-
- if (Args.hasArg(options::OPT_pg))
- return true;
-
- return useFramePointerForTargetByDefault(Args, Triple);
-}
-
-static bool shouldUseLeafFramePointer(const ArgList &Args,
- const llvm::Triple &Triple) {
- if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer,
- options::OPT_momit_leaf_frame_pointer))
- return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer) ||
- mustUseFramePointerForTarget(Triple);
-
- if (Args.hasArg(options::OPT_pg))
- return true;
-
- if (Triple.isPS4CPU())
- return false;
-
- return useFramePointerForTargetByDefault(Args, Triple);
-}
-
-/// Add a CC1 option to specify the debug compilation directory.
-static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) {
- SmallString<128> cwd;
- if (!llvm::sys::fs::current_path(cwd)) {
- CmdArgs.push_back("-fdebug-compilation-dir");
- CmdArgs.push_back(Args.MakeArgString(cwd));
- }
-}
-
-static const char *SplitDebugName(const ArgList &Args, const InputInfo &Input) {
- Arg *FinalOutput = Args.getLastArg(options::OPT_o);
- if (FinalOutput && Args.hasArg(options::OPT_c)) {
- SmallString<128> T(FinalOutput->getValue());
- llvm::sys::path::replace_extension(T, "dwo");
- return Args.MakeArgString(T);
- } else {
- // Use the compilation dir.
- SmallString<128> T(
- Args.getLastArgValue(options::OPT_fdebug_compilation_dir));
- SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput()));
- llvm::sys::path::replace_extension(F, "dwo");
- T += F;
- return Args.MakeArgString(F);
- }
-}
-
-static void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T,
- const JobAction &JA, const ArgList &Args,
- const InputInfo &Output, const char *OutFile) {
- ArgStringList ExtractArgs;
- ExtractArgs.push_back("--extract-dwo");
-
- ArgStringList StripArgs;
- StripArgs.push_back("--strip-dwo");
-
- // Grabbing the output of the earlier compile step.
- StripArgs.push_back(Output.getFilename());
- ExtractArgs.push_back(Output.getFilename());
- ExtractArgs.push_back(OutFile);
-
- const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy"));
- InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename());
-
- // First extract the dwo sections.
- C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs, II));
-
- // Then remove them from the original .o file.
- C.addCommand(llvm::make_unique<Command>(JA, T, Exec, StripArgs, II));
-}
-
-/// \brief Vectorize at all optimization levels greater than 1 except for -Oz.
-/// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled.
-static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) {
- if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- if (A->getOption().matches(options::OPT_O4) ||
- A->getOption().matches(options::OPT_Ofast))
- return true;
-
- if (A->getOption().matches(options::OPT_O0))
- return false;
-
- assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag");
-
- // Vectorize -Os.
- StringRef S(A->getValue());
- if (S == "s")
- return true;
-
- // Don't vectorize -Oz, unless it's the slp vectorizer.
- if (S == "z")
- return isSlpVec;
-
- unsigned OptLevel = 0;
- if (S.getAsInteger(10, OptLevel))
- return false;
-
- return OptLevel > 1;
- }
-
- return false;
-}
-
-/// Add -x lang to \p CmdArgs for \p Input.
-static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
- ArgStringList &CmdArgs) {
- // When using -verify-pch, we don't want to provide the type
- // 'precompiled-header' if it was inferred from the file extension
- if (Args.hasArg(options::OPT_verify_pch) && Input.getType() == types::TY_PCH)
- return;
-
- CmdArgs.push_back("-x");
- if (Args.hasArg(options::OPT_rewrite_objc))
- CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX));
- else
- CmdArgs.push_back(types::getTypeName(Input.getType()));
-}
-
-// Claim options we don't want to warn if they are unused. We do this for
-// options that build systems might add but are unused when assembling or only
-// running the preprocessor for example.
-static void claimNoWarnArgs(const ArgList &Args) {
- // Don't warn about unused -f(no-)?lto. This can happen when we're
- // preprocessing, precompiling or assembling.
- Args.ClaimAllArgs(options::OPT_flto_EQ);
- Args.ClaimAllArgs(options::OPT_flto);
- Args.ClaimAllArgs(options::OPT_fno_lto);
-}
-
-static void appendUserToPath(SmallVectorImpl<char> &Result) {
-#ifdef LLVM_ON_UNIX
- const char *Username = getenv("LOGNAME");
-#else
- const char *Username = getenv("USERNAME");
-#endif
- if (Username) {
- // Validate that LoginName can be used in a path, and get its length.
- size_t Len = 0;
- for (const char *P = Username; *P; ++P, ++Len) {
- if (!isAlphanumeric(*P) && *P != '_') {
- Username = nullptr;
- break;
- }
- }
-
- if (Username && Len > 0) {
- Result.append(Username, Username + Len);
- return;
- }
- }
-
-// Fallback to user id.
-#ifdef LLVM_ON_UNIX
- std::string UID = llvm::utostr(getuid());
-#else
- // FIXME: Windows seems to have an 'SID' that might work.
- std::string UID = "9999";
-#endif
- Result.append(UID.begin(), UID.end());
-}
-
-static Arg *getLastProfileUseArg(const ArgList &Args) {
- auto *ProfileUseArg = Args.getLastArg(
- options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ,
- options::OPT_fprofile_use, options::OPT_fprofile_use_EQ,
- options::OPT_fno_profile_instr_use);
-
- if (ProfileUseArg &&
- ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use))
- ProfileUseArg = nullptr;
-
- return ProfileUseArg;
-}
-
-static void addPGOAndCoverageFlags(Compilation &C, const Driver &D,
- const InputInfo &Output, const ArgList &Args,
- ArgStringList &CmdArgs) {
-
- auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate,
- options::OPT_fprofile_generate_EQ,
- options::OPT_fno_profile_generate);
- if (PGOGenerateArg &&
- PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate))
- PGOGenerateArg = nullptr;
-
- auto *ProfileGenerateArg = Args.getLastArg(
- options::OPT_fprofile_instr_generate,
- options::OPT_fprofile_instr_generate_EQ,
- options::OPT_fno_profile_instr_generate);
- if (ProfileGenerateArg &&
- ProfileGenerateArg->getOption().matches(
- options::OPT_fno_profile_instr_generate))
- ProfileGenerateArg = nullptr;
-
- if (PGOGenerateArg && ProfileGenerateArg)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << PGOGenerateArg->getSpelling() << ProfileGenerateArg->getSpelling();
-
- auto *ProfileUseArg = getLastProfileUseArg(Args);
-
- if (PGOGenerateArg && ProfileUseArg)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << ProfileUseArg->getSpelling() << PGOGenerateArg->getSpelling();
-
- if (ProfileGenerateArg && ProfileUseArg)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << ProfileGenerateArg->getSpelling() << ProfileUseArg->getSpelling();
-
- if (ProfileGenerateArg) {
- if (ProfileGenerateArg->getOption().matches(
- options::OPT_fprofile_instr_generate_EQ))
- CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instrument-path=") +
- ProfileGenerateArg->getValue()));
- // The default is to use Clang Instrumentation.
- CmdArgs.push_back("-fprofile-instrument=clang");
- }
-
- if (PGOGenerateArg) {
- CmdArgs.push_back("-fprofile-instrument=llvm");
- if (PGOGenerateArg->getOption().matches(
- options::OPT_fprofile_generate_EQ)) {
- SmallString<128> Path(PGOGenerateArg->getValue());
- llvm::sys::path::append(Path, "default_%m.profraw");
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-fprofile-instrument-path=") + Path));
- }
- }
-
- if (ProfileUseArg) {
- if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ))
- CmdArgs.push_back(Args.MakeArgString(
- Twine("-fprofile-instrument-use-path=") + ProfileUseArg->getValue()));
- else if ((ProfileUseArg->getOption().matches(
- options::OPT_fprofile_use_EQ) ||
- ProfileUseArg->getOption().matches(
- options::OPT_fprofile_instr_use))) {
- SmallString<128> Path(
- ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue());
- if (Path.empty() || llvm::sys::fs::is_directory(Path))
- llvm::sys::path::append(Path, "default.profdata");
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-fprofile-instrument-use-path=") + Path));
- }
- }
-
- if (Args.hasArg(options::OPT_ftest_coverage) ||
- Args.hasArg(options::OPT_coverage))
- CmdArgs.push_back("-femit-coverage-notes");
- if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
- false) ||
- Args.hasArg(options::OPT_coverage))
- CmdArgs.push_back("-femit-coverage-data");
-
- if (Args.hasFlag(options::OPT_fcoverage_mapping,
- options::OPT_fno_coverage_mapping, false) &&
- !ProfileGenerateArg)
- D.Diag(diag::err_drv_argument_only_allowed_with)
- << "-fcoverage-mapping"
- << "-fprofile-instr-generate";
-
- if (Args.hasFlag(options::OPT_fcoverage_mapping,
- options::OPT_fno_coverage_mapping, false))
- CmdArgs.push_back("-fcoverage-mapping");
-
- if (C.getArgs().hasArg(options::OPT_c) ||
- C.getArgs().hasArg(options::OPT_S)) {
- if (Output.isFilename()) {
- CmdArgs.push_back("-coverage-notes-file");
- SmallString<128> OutputFilename;
- if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
- OutputFilename = FinalOutput->getValue();
- else
- OutputFilename = llvm::sys::path::filename(Output.getBaseInput());
- SmallString<128> CoverageFilename = OutputFilename;
- if (llvm::sys::path::is_relative(CoverageFilename)) {
- SmallString<128> Pwd;
- if (!llvm::sys::fs::current_path(Pwd)) {
- llvm::sys::path::append(Pwd, CoverageFilename);
- CoverageFilename.swap(Pwd);
- }
- }
- llvm::sys::path::replace_extension(CoverageFilename, "gcno");
- CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
-
- // Leave -fprofile-dir= an unused argument unless .gcda emission is
- // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider
- // the flag used. There is no -fno-profile-dir, so the user has no
- // targeted way to suppress the warning.
- if (Args.hasArg(options::OPT_fprofile_arcs) ||
- Args.hasArg(options::OPT_coverage)) {
- CmdArgs.push_back("-coverage-data-file");
- if (Arg *FProfileDir = Args.getLastArg(options::OPT_fprofile_dir)) {
- CoverageFilename = FProfileDir->getValue();
- llvm::sys::path::append(CoverageFilename, OutputFilename);
- }
- llvm::sys::path::replace_extension(CoverageFilename, "gcda");
- CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
- }
- }
- }
-}
-
-static void addPS4ProfileRTArgs(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
- false) ||
- Args.hasFlag(options::OPT_fprofile_generate,
- options::OPT_fno_profile_instr_generate, false) ||
- Args.hasFlag(options::OPT_fprofile_generate_EQ,
- options::OPT_fno_profile_instr_generate, false) ||
- Args.hasFlag(options::OPT_fprofile_instr_generate,
- options::OPT_fno_profile_instr_generate, false) ||
- Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
- options::OPT_fno_profile_instr_generate, false) ||
- Args.hasArg(options::OPT_fcreate_profile) ||
- Args.hasArg(options::OPT_coverage)))
- CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a");
-}
-
-/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then,
-/// smooshes them together with platform defaults, to decide whether
-/// this compile should be using PIC mode or not. Returns a tuple of
-/// (RelocationModel, PICLevel, IsPIE).
-static std::tuple<llvm::Reloc::Model, unsigned, bool>
-ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) {
- const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple();
- const llvm::Triple &Triple = ToolChain.getTriple();
-
- bool PIE = ToolChain.isPIEDefault();
- bool PIC = PIE || ToolChain.isPICDefault();
- // The Darwin/MachO default to use PIC does not apply when using -static.
- if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static))
- PIE = PIC = false;
- bool IsPICLevelTwo = PIC;
-
- bool KernelOrKext =
- Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
-
- // Android-specific defaults for PIC/PIE
- if (Triple.isAndroid()) {
- switch (Triple.getArch()) {
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- case llvm::Triple::aarch64:
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- PIC = true; // "-fpic"
- break;
-
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- PIC = true; // "-fPIC"
- IsPICLevelTwo = true;
- break;
-
- default:
- break;
- }
- }
-
- // OpenBSD-specific defaults for PIE
- if (Triple.getOS() == llvm::Triple::OpenBSD) {
- switch (ToolChain.getArch()) {
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- case llvm::Triple::sparcel:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- IsPICLevelTwo = false; // "-fpie"
- break;
-
- case llvm::Triple::ppc:
- case llvm::Triple::sparc:
- case llvm::Triple::sparcv9:
- IsPICLevelTwo = true; // "-fPIE"
- break;
-
- default:
- break;
- }
- }
-
- // The last argument relating to either PIC or PIE wins, and no
- // other argument is used. If the last argument is any flavor of the
- // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE
- // option implicitly enables PIC at the same level.
- Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
- options::OPT_fpic, options::OPT_fno_pic,
- options::OPT_fPIE, options::OPT_fno_PIE,
- options::OPT_fpie, options::OPT_fno_pie);
- if (Triple.isOSWindows() && LastPICArg &&
- LastPICArg ==
- Args.getLastArg(options::OPT_fPIC, options::OPT_fpic,
- options::OPT_fPIE, options::OPT_fpie)) {
- ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
- << LastPICArg->getSpelling() << Triple.str();
- if (Triple.getArch() == llvm::Triple::x86_64)
- return std::make_tuple(llvm::Reloc::PIC_, 2U, false);
- return std::make_tuple(llvm::Reloc::Static, 0U, false);
- }
-
- // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness
- // is forced, then neither PIC nor PIE flags will have no effect.
- if (!ToolChain.isPICDefaultForced()) {
- if (LastPICArg) {
- Option O = LastPICArg->getOption();
- if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) ||
- O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) {
- PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie);
- PIC =
- PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic);
- IsPICLevelTwo =
- O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC);
- } else {
- PIE = PIC = false;
- if (EffectiveTriple.isPS4CPU()) {
- Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ);
- StringRef Model = ModelArg ? ModelArg->getValue() : "";
- if (Model != "kernel") {
- PIC = true;
- ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic)
- << LastPICArg->getSpelling();
- }
- }
- }
- }
- }
-
- // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the
- // PIC level would've been set to level 1, force it back to level 2 PIC
- // instead.
- if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU()))
- IsPICLevelTwo |= ToolChain.isPICDefault();
-
- // This kernel flags are a trump-card: they will disable PIC/PIE
- // generation, independent of the argument order.
- if (KernelOrKext &&
- ((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) &&
- !EffectiveTriple.isWatchOS()))
- PIC = PIE = false;
-
- if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) {
- // This is a very special mode. It trumps the other modes, almost no one
- // uses it, and it isn't even valid on any OS but Darwin.
- if (!Triple.isOSDarwin())
- ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
- << A->getSpelling() << Triple.str();
-
- // FIXME: Warn when this flag trumps some other PIC or PIE flag.
-
- // Only a forced PIC mode can cause the actual compile to have PIC defines
- // etc., no flags are sufficient. This behavior was selected to closely
- // match that of llvm-gcc and Apple GCC before that.
- PIC = ToolChain.isPICDefault() && ToolChain.isPICDefaultForced();
-
- return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2U : 0U, false);
- }
-
- bool EmbeddedPISupported;
- switch (Triple.getArch()) {
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- EmbeddedPISupported = true;
- break;
- default:
- EmbeddedPISupported = false;
- break;
- }
-
- bool ROPI = false, RWPI = false;
- Arg* LastROPIArg = Args.getLastArg(options::OPT_fropi, options::OPT_fno_ropi);
- if (LastROPIArg && LastROPIArg->getOption().matches(options::OPT_fropi)) {
- if (!EmbeddedPISupported)
- ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
- << LastROPIArg->getSpelling() << Triple.str();
- ROPI = true;
- }
- Arg *LastRWPIArg = Args.getLastArg(options::OPT_frwpi, options::OPT_fno_rwpi);
- if (LastRWPIArg && LastRWPIArg->getOption().matches(options::OPT_frwpi)) {
- if (!EmbeddedPISupported)
- ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
- << LastRWPIArg->getSpelling() << Triple.str();
- RWPI = true;
- }
-
- // ROPI and RWPI are not comaptible with PIC or PIE.
- if ((ROPI || RWPI) && (PIC || PIE))
- ToolChain.getDriver().Diag(diag::err_drv_ropi_rwpi_incompatible_with_pic);
-
- if (PIC)
- return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2U : 1U, PIE);
-
- llvm::Reloc::Model RelocM = llvm::Reloc::Static;
- if (ROPI && RWPI)
- RelocM = llvm::Reloc::ROPI_RWPI;
- else if (ROPI)
- RelocM = llvm::Reloc::ROPI;
- else if (RWPI)
- RelocM = llvm::Reloc::RWPI;
-
- return std::make_tuple(RelocM, 0U, false);
-}
-
-static const char *RelocationModelName(llvm::Reloc::Model Model) {
- switch (Model) {
- case llvm::Reloc::Static:
- return "static";
- case llvm::Reloc::PIC_:
- return "pic";
- case llvm::Reloc::DynamicNoPIC:
- return "dynamic-no-pic";
- case llvm::Reloc::ROPI:
- return "ropi";
- case llvm::Reloc::RWPI:
- return "rwpi";
- case llvm::Reloc::ROPI_RWPI:
- return "ropi-rwpi";
- }
- llvm_unreachable("Unknown Reloc::Model kind");
-}
-
-static void AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args,
- ArgStringList &CmdArgs) {
- llvm::Reloc::Model RelocationModel;
- unsigned PICLevel;
- bool IsPIE;
- std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(ToolChain, Args);
-
- if (RelocationModel != llvm::Reloc::Static)
- CmdArgs.push_back("-KPIC");
-}
-
-void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
- StringRef Target, const InputInfo &Output,
- const InputInfo &Input, const ArgList &Args) const {
- // If this is a dry run, do not create the compilation database file.
- if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
- return;
-
- using llvm::yaml::escape;
- const Driver &D = getToolChain().getDriver();
-
- if (!CompilationDatabase) {
- std::error_code EC;
- auto File = llvm::make_unique<llvm::raw_fd_ostream>(Filename, EC, llvm::sys::fs::F_Text);
- if (EC) {
- D.Diag(clang::diag::err_drv_compilationdatabase) << Filename
- << EC.message();
- return;
- }
- CompilationDatabase = std::move(File);
- }
- auto &CDB = *CompilationDatabase;
- SmallString<128> Buf;
- if (llvm::sys::fs::current_path(Buf))
- Buf = ".";
- CDB << "{ \"directory\": \"" << escape(Buf) << "\"";
- CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\"";
- CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\"";
- CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\"";
- Buf = "-x";
- Buf += types::getTypeName(Input.getType());
- CDB << ", \"" << escape(Buf) << "\"";
- if (!D.SysRoot.empty() && !Args.hasArg(options::OPT__sysroot_EQ)) {
- Buf = "--sysroot=";
- Buf += D.SysRoot;
- CDB << ", \"" << escape(Buf) << "\"";
- }
- CDB << ", \"" << escape(Input.getFilename()) << "\"";
- for (auto &A: Args) {
- auto &O = A->getOption();
- // Skip language selection, which is positional.
- if (O.getID() == options::OPT_x)
- continue;
- // Skip writing dependency output and the compilation database itself.
- if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group)
- continue;
- // Skip inputs.
- if (O.getKind() == Option::InputClass)
- continue;
- // All other arguments are quoted and appended.
- ArgStringList ASL;
- A->render(Args, ASL);
- for (auto &it: ASL)
- CDB << ", \"" << escape(it) << "\"";
- }
- Buf = "--target=";
- Buf += Target;
- CDB << ", \"" << escape(Buf) << "\"]},\n";
-}
-
-void Clang::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const ArgList &Args, const char *LinkingOutput) const {
- const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
- const std::string &TripleStr = Triple.getTriple();
-
- bool KernelOrKext =
- Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- // Check number of inputs for sanity. We need at least one input.
- assert(Inputs.size() >= 1 && "Must have at least one input.");
- const InputInfo &Input = Inputs[0];
- // CUDA compilation may have multiple inputs (source file + results of
- // device-side compilations). OpenMP device jobs also take the host IR as a
- // second input. All other jobs are expected to have exactly one
- // input.
- bool IsCuda = JA.isOffloading(Action::OFK_Cuda);
- bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
- assert((IsCuda || (IsOpenMPDevice && Inputs.size() == 2) ||
- Inputs.size() == 1) &&
- "Unable to handle multiple inputs.");
-
- bool IsWindowsGNU = getToolChain().getTriple().isWindowsGNUEnvironment();
- bool IsWindowsCygnus =
- getToolChain().getTriple().isWindowsCygwinEnvironment();
- bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment();
- bool IsPS4CPU = getToolChain().getTriple().isPS4CPU();
- bool IsIAMCU = getToolChain().getTriple().isOSIAMCU();
-
- // Adjust IsWindowsXYZ for CUDA compilations. Even when compiling in device
- // mode (i.e., getToolchain().getTriple() is NVPTX, not Windows), we need to
- // pass Windows-specific flags to cc1.
- if (IsCuda) {
- const llvm::Triple *AuxTriple = getToolChain().getAuxTriple();
- IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment();
- IsWindowsGNU |= AuxTriple && AuxTriple->isWindowsGNUEnvironment();
- IsWindowsCygnus |= AuxTriple && AuxTriple->isWindowsCygwinEnvironment();
- }
-
- // C++ is not supported for IAMCU.
- if (IsIAMCU && types::isCXX(Input.getType()))
- D.Diag(diag::err_drv_clang_unsupported) << "C++ for IAMCU";
-
- // Invoke ourselves in -cc1 mode.
- //
- // FIXME: Implement custom jobs for internal actions.
- CmdArgs.push_back("-cc1");
-
- // Add the "effective" target triple.
- CmdArgs.push_back("-triple");
- CmdArgs.push_back(Args.MakeArgString(TripleStr));
-
- if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) {
- DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args);
- Args.ClaimAllArgs(options::OPT_MJ);
- }
-
- if (IsCuda) {
- // We have to pass the triple of the host if compiling for a CUDA device and
- // vice-versa.
- std::string NormalizedTriple;
- if (JA.isDeviceOffloading(Action::OFK_Cuda))
- NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>()
- ->getTriple()
- .normalize();
- else
- NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Cuda>()
- ->getTriple()
- .normalize();
-
- CmdArgs.push_back("-aux-triple");
- CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
- }
-
- if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm ||
- Triple.getArch() == llvm::Triple::thumb)) {
- unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
- unsigned Version;
- Triple.getArchName().substr(Offset).getAsInteger(10, Version);
- if (Version < 7)
- D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName()
- << TripleStr;
- }
-
- // Push all default warning arguments that are specific to
- // the given target. These come before user provided warning options
- // are provided.
- getToolChain().addClangWarningOptions(CmdArgs);
-
- // Select the appropriate action.
- RewriteKind rewriteKind = RK_None;
-
- if (isa<AnalyzeJobAction>(JA)) {
- assert(JA.getType() == types::TY_Plist && "Invalid output type.");
- CmdArgs.push_back("-analyze");
- } else if (isa<MigrateJobAction>(JA)) {
- CmdArgs.push_back("-migrate");
- } else if (isa<PreprocessJobAction>(JA)) {
- if (Output.getType() == types::TY_Dependencies)
- CmdArgs.push_back("-Eonly");
- else {
- CmdArgs.push_back("-E");
- if (Args.hasArg(options::OPT_rewrite_objc) &&
- !Args.hasArg(options::OPT_g_Group))
- CmdArgs.push_back("-P");
- }
- } else if (isa<AssembleJobAction>(JA)) {
- CmdArgs.push_back("-emit-obj");
-
- CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D);
-
- // Also ignore explicit -force_cpusubtype_ALL option.
- (void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
- } else if (isa<PrecompileJobAction>(JA)) {
- // Use PCH if the user requested it.
- bool UsePCH = D.CCCUsePCH;
-
- if (JA.getType() == types::TY_Nothing)
- CmdArgs.push_back("-fsyntax-only");
- else if (JA.getType() == types::TY_ModuleFile)
- CmdArgs.push_back("-emit-module-interface");
- else if (UsePCH)
- CmdArgs.push_back("-emit-pch");
- else
- CmdArgs.push_back("-emit-pth");
- } else if (isa<VerifyPCHJobAction>(JA)) {
- CmdArgs.push_back("-verify-pch");
- } else {
- assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
- "Invalid action for clang tool.");
- if (JA.getType() == types::TY_Nothing) {
- CmdArgs.push_back("-fsyntax-only");
- } else if (JA.getType() == types::TY_LLVM_IR ||
- JA.getType() == types::TY_LTO_IR) {
- CmdArgs.push_back("-emit-llvm");
- } else if (JA.getType() == types::TY_LLVM_BC ||
- JA.getType() == types::TY_LTO_BC) {
- CmdArgs.push_back("-emit-llvm-bc");
- } else if (JA.getType() == types::TY_PP_Asm) {
- CmdArgs.push_back("-S");
- } else if (JA.getType() == types::TY_AST) {
- CmdArgs.push_back("-emit-pch");
- } else if (JA.getType() == types::TY_ModuleFile) {
- CmdArgs.push_back("-module-file-info");
- } else if (JA.getType() == types::TY_RewrittenObjC) {
- CmdArgs.push_back("-rewrite-objc");
- rewriteKind = RK_NonFragile;
- } else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
- CmdArgs.push_back("-rewrite-objc");
- rewriteKind = RK_Fragile;
- } else {
- assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
- }
-
- // Preserve use-list order by default when emitting bitcode, so that
- // loading the bitcode up in 'opt' or 'llc' and running passes gives the
- // same result as running passes here. For LTO, we don't need to preserve
- // the use-list order, since serialization to bitcode is part of the flow.
- if (JA.getType() == types::TY_LLVM_BC)
- CmdArgs.push_back("-emit-llvm-uselists");
-
- if (D.isUsingLTO())
- Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ);
- }
-
- if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) {
- if (!types::isLLVMIR(Input.getType()))
- D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args)
- << "-x ir";
- Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ);
- }
-
- // Embed-bitcode option.
- if (C.getDriver().embedBitcodeInObject() &&
- (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) {
- // Add flags implied by -fembed-bitcode.
- Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ);
- // Disable all llvm IR level optimizations.
- CmdArgs.push_back("-disable-llvm-passes");
- }
- if (C.getDriver().embedBitcodeMarkerOnly())
- CmdArgs.push_back("-fembed-bitcode=marker");
-
- // We normally speed up the clang process a bit by skipping destructors at
- // exit, but when we're generating diagnostics we can rely on some of the
- // cleanup.
- if (!C.isForDiagnostics())
- CmdArgs.push_back("-disable-free");
-
-// Disable the verification pass in -asserts builds.
-#ifdef NDEBUG
- CmdArgs.push_back("-disable-llvm-verifier");
- // Discard LLVM value names in -asserts builds.
- CmdArgs.push_back("-discard-value-names");
-#endif
-
- // Set the main file name, so that debug info works even with
- // -save-temps.
- CmdArgs.push_back("-main-file-name");
- CmdArgs.push_back(getBaseInputName(Args, Input));
-
- // Some flags which affect the language (via preprocessor
- // defines).
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("-static-define");
-
- if (isa<AnalyzeJobAction>(JA)) {
- // Enable region store model by default.
- CmdArgs.push_back("-analyzer-store=region");
-
- // Treat blocks as analysis entry points.
- CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks");
-
- CmdArgs.push_back("-analyzer-eagerly-assume");
-
- // Add default argument set.
- if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
- CmdArgs.push_back("-analyzer-checker=core");
- CmdArgs.push_back("-analyzer-checker=apiModeling");
-
- if (!IsWindowsMSVC) {
- CmdArgs.push_back("-analyzer-checker=unix");
- } else {
- // Enable "unix" checkers that also work on Windows.
- CmdArgs.push_back("-analyzer-checker=unix.API");
- CmdArgs.push_back("-analyzer-checker=unix.Malloc");
- CmdArgs.push_back("-analyzer-checker=unix.MallocSizeof");
- CmdArgs.push_back("-analyzer-checker=unix.MismatchedDeallocator");
- CmdArgs.push_back("-analyzer-checker=unix.cstring.BadSizeArg");
- CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg");
- }
-
- // Disable some unix checkers for PS4.
- if (IsPS4CPU) {
- CmdArgs.push_back("-analyzer-disable-checker=unix.API");
- CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork");
- }
-
- if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
- CmdArgs.push_back("-analyzer-checker=osx");
-
- CmdArgs.push_back("-analyzer-checker=deadcode");
-
- if (types::isCXX(Input.getType()))
- CmdArgs.push_back("-analyzer-checker=cplusplus");
-
- if (!IsPS4CPU) {
- CmdArgs.push_back(
- "-analyzer-checker=security.insecureAPI.UncheckedReturn");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp");
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork");
- }
-
- // Default nullability checks.
- CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull");
- CmdArgs.push_back(
- "-analyzer-checker=nullability.NullReturnedFromNonnull");
- }
-
- // Set the output format. The default is plist, for (lame) historical
- // reasons.
- CmdArgs.push_back("-analyzer-output");
- if (Arg *A = Args.getLastArg(options::OPT__analyzer_output))
- CmdArgs.push_back(A->getValue());
- else
- CmdArgs.push_back("plist");
-
- // Disable the presentation of standard compiler warnings when
- // using --analyze. We only want to show static analyzer diagnostics
- // or frontend errors.
- CmdArgs.push_back("-w");
-
- // Add -Xanalyzer arguments when running as analyzer.
- Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
- }
-
- CheckCodeGenerationOptions(D, Args);
-
- llvm::Reloc::Model RelocationModel;
- unsigned PICLevel;
- bool IsPIE;
- std::tie(RelocationModel, PICLevel, IsPIE) =
- ParsePICArgs(getToolChain(), Args);
-
- const char *RMName = RelocationModelName(RelocationModel);
-
- if ((RelocationModel == llvm::Reloc::ROPI ||
- RelocationModel == llvm::Reloc::ROPI_RWPI) &&
- types::isCXX(Input.getType()) &&
- !Args.hasArg(options::OPT_fallow_unsupported))
- D.Diag(diag::err_drv_ropi_incompatible_with_cxx);
-
- if (RMName) {
- CmdArgs.push_back("-mrelocation-model");
- CmdArgs.push_back(RMName);
- }
- if (PICLevel > 0) {
- CmdArgs.push_back("-pic-level");
- CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
- if (IsPIE)
- CmdArgs.push_back("-pic-is-pie");
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_meabi)) {
- CmdArgs.push_back("-meabi");
- CmdArgs.push_back(A->getValue());
- }
-
- CmdArgs.push_back("-mthread-model");
- if (Arg *A = Args.getLastArg(options::OPT_mthread_model))
- CmdArgs.push_back(A->getValue());
- else
- CmdArgs.push_back(Args.MakeArgString(getToolChain().getThreadModel()));
-
- Args.AddLastArg(CmdArgs, options::OPT_fveclib);
-
- if (!Args.hasFlag(options::OPT_fmerge_all_constants,
- options::OPT_fno_merge_all_constants))
- CmdArgs.push_back("-fno-merge-all-constants");
-
- // LLVM Code Generator Options.
-
- if (Args.hasArg(options::OPT_frewrite_map_file) ||
- Args.hasArg(options::OPT_frewrite_map_file_EQ)) {
- for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file,
- options::OPT_frewrite_map_file_EQ)) {
- StringRef Map = A->getValue();
- if (!llvm::sys::fs::exists(Map)) {
- D.Diag(diag::err_drv_no_such_file) << Map;
- } else {
- CmdArgs.push_back("-frewrite-map-file");
- CmdArgs.push_back(A->getValue());
- A->claim();
- }
- }
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) {
- StringRef v = A->getValue();
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString("-warn-stack-size=" + v));
- A->claim();
- }
-
- if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables,
- true))
- CmdArgs.push_back("-fno-jump-tables");
-
- if (!Args.hasFlag(options::OPT_fpreserve_as_comments,
- options::OPT_fno_preserve_as_comments, true))
- CmdArgs.push_back("-fno-preserve-as-comments");
-
- if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
- CmdArgs.push_back("-mregparm");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return,
- options::OPT_freg_struct_return)) {
- if (getToolChain().getArch() != llvm::Triple::x86) {
- D.Diag(diag::err_drv_unsupported_opt_for_target)
- << A->getSpelling() << getToolChain().getTriple().str();
- } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) {
- CmdArgs.push_back("-fpcc-struct-return");
- } else {
- assert(A->getOption().matches(options::OPT_freg_struct_return));
- CmdArgs.push_back("-freg-struct-return");
- }
- }
-
- if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
- CmdArgs.push_back("-fdefault-calling-conv=stdcall");
-
- if (shouldUseFramePointer(Args, getToolChain().getTriple()))
- CmdArgs.push_back("-mdisable-fp-elim");
- if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
- options::OPT_fno_zero_initialized_in_bss))
- CmdArgs.push_back("-mno-zero-initialized-in-bss");
-
- bool OFastEnabled = isOptimizationLevelFast(Args);
- // If -Ofast is the optimization level, then -fstrict-aliasing should be
- // enabled. This alias option is being used to simplify the hasFlag logic.
- OptSpecifier StrictAliasingAliasOption =
- OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing;
- // We turn strict aliasing off by default if we're in CL mode, since MSVC
- // doesn't do any TBAA.
- bool TBAAOnByDefault = !getToolChain().getDriver().IsCLMode();
- if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
- options::OPT_fno_strict_aliasing, TBAAOnByDefault))
- CmdArgs.push_back("-relaxed-aliasing");
- if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
- options::OPT_fno_struct_path_tbaa))
- CmdArgs.push_back("-no-struct-path-tbaa");
- if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
- false))
- CmdArgs.push_back("-fstrict-enums");
- if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
- true))
- CmdArgs.push_back("-fno-strict-return");
- if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
- options::OPT_fno_strict_vtable_pointers,
- false))
- CmdArgs.push_back("-fstrict-vtable-pointers");
- if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
- options::OPT_fno_optimize_sibling_calls))
- CmdArgs.push_back("-mdisable-tail-calls");
-
- // Handle segmented stacks.
- if (Args.hasArg(options::OPT_fsplit_stack))
- CmdArgs.push_back("-split-stacks");
-
- // If -Ofast is the optimization level, then -ffast-math should be enabled.
- // This alias option is being used to simplify the getLastArg logic.
- OptSpecifier FastMathAliasOption =
- OFastEnabled ? options::OPT_Ofast : options::OPT_ffast_math;
-
- // Handle various floating point optimization flags, mapping them to the
- // appropriate LLVM code generation flags. The pattern for all of these is to
- // default off the codegen optimizations, and if any flag enables them and no
- // flag disables them after the flag enabling them, enable the codegen
- // optimization. This is complicated by several "umbrella" flags.
- if (Arg *A = Args.getLastArg(
- options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math, options::OPT_ffinite_math_only,
- options::OPT_fno_finite_math_only, options::OPT_fhonor_infinities,
- options::OPT_fno_honor_infinities))
- if (A->getOption().getID() != options::OPT_fno_fast_math &&
- A->getOption().getID() != options::OPT_fno_finite_math_only &&
- A->getOption().getID() != options::OPT_fhonor_infinities)
- CmdArgs.push_back("-menable-no-infs");
- if (Arg *A = Args.getLastArg(
- options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math, options::OPT_ffinite_math_only,
- options::OPT_fno_finite_math_only, options::OPT_fhonor_nans,
- options::OPT_fno_honor_nans))
- if (A->getOption().getID() != options::OPT_fno_fast_math &&
- A->getOption().getID() != options::OPT_fno_finite_math_only &&
- A->getOption().getID() != options::OPT_fhonor_nans)
- CmdArgs.push_back("-menable-no-nans");
-
- // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes.
- bool MathErrno = getToolChain().IsMathErrnoDefault();
- if (Arg *A =
- Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math, options::OPT_fmath_errno,
- options::OPT_fno_math_errno)) {
- // Turning on -ffast_math (with either flag) removes the need for MathErrno.
- // However, turning *off* -ffast_math merely restores the toolchain default
- // (which may be false).
- if (A->getOption().getID() == options::OPT_fno_math_errno ||
- A->getOption().getID() == options::OPT_ffast_math ||
- A->getOption().getID() == options::OPT_Ofast)
- MathErrno = false;
- else if (A->getOption().getID() == options::OPT_fmath_errno)
- MathErrno = true;
- }
- if (MathErrno)
- CmdArgs.push_back("-fmath-errno");
-
- // There are several flags which require disabling very specific
- // optimizations. Any of these being disabled forces us to turn off the
- // entire set of LLVM optimizations, so collect them through all the flag
- // madness.
- bool AssociativeMath = false;
- if (Arg *A = Args.getLastArg(
- options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations,
- options::OPT_fno_unsafe_math_optimizations,
- options::OPT_fassociative_math, options::OPT_fno_associative_math))
- if (A->getOption().getID() != options::OPT_fno_fast_math &&
- A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
- A->getOption().getID() != options::OPT_fno_associative_math)
- AssociativeMath = true;
- bool ReciprocalMath = false;
- if (Arg *A = Args.getLastArg(
- options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations,
- options::OPT_fno_unsafe_math_optimizations,
- options::OPT_freciprocal_math, options::OPT_fno_reciprocal_math))
- if (A->getOption().getID() != options::OPT_fno_fast_math &&
- A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
- A->getOption().getID() != options::OPT_fno_reciprocal_math)
- ReciprocalMath = true;
- bool SignedZeros = true;
- if (Arg *A = Args.getLastArg(
- options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations,
- options::OPT_fno_unsafe_math_optimizations,
- options::OPT_fsigned_zeros, options::OPT_fno_signed_zeros))
- if (A->getOption().getID() != options::OPT_fno_fast_math &&
- A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
- A->getOption().getID() != options::OPT_fsigned_zeros)
- SignedZeros = false;
- bool TrappingMath = true;
- if (Arg *A = Args.getLastArg(
- options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations,
- options::OPT_fno_unsafe_math_optimizations,
- options::OPT_ftrapping_math, options::OPT_fno_trapping_math))
- if (A->getOption().getID() != options::OPT_fno_fast_math &&
- A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
- A->getOption().getID() != options::OPT_ftrapping_math)
- TrappingMath = false;
- if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
- !TrappingMath)
- CmdArgs.push_back("-menable-unsafe-fp-math");
-
- if (!SignedZeros)
- CmdArgs.push_back("-fno-signed-zeros");
-
- if (ReciprocalMath)
- CmdArgs.push_back("-freciprocal-math");
-
- if (!TrappingMath)
- CmdArgs.push_back("-fno-trapping-math");
-
-
- if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math,
- options::OPT_funsafe_math_optimizations,
- options::OPT_fno_unsafe_math_optimizations,
- options::OPT_fdenormal_fp_math_EQ))
- if (A->getOption().getID() != options::OPT_fno_fast_math &&
- A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations)
- Args.AddLastArg(CmdArgs, options::OPT_fdenormal_fp_math_EQ);
-
- // Validate and pass through -fp-contract option.
- if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math,
- options::OPT_ffp_contract)) {
- if (A->getOption().getID() == options::OPT_ffp_contract) {
- StringRef Val = A->getValue();
- if (Val == "fast" || Val == "on" || Val == "off") {
- CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + Val));
- } else {
- D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
- }
- } else if (A->getOption().matches(options::OPT_ffast_math) ||
- (OFastEnabled && A->getOption().matches(options::OPT_Ofast))) {
- // If fast-math is set then set the fp-contract mode to fast.
- CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast"));
- }
- }
-
- ParseMRecip(getToolChain().getDriver(), Args, CmdArgs);
-
- // We separately look for the '-ffast-math' and '-ffinite-math-only' flags,
- // and if we find them, tell the frontend to provide the appropriate
- // preprocessor macros. This is distinct from enabling any optimizations as
- // these options induce language changes which must survive serialization
- // and deserialization, etc.
- if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
- options::OPT_fno_fast_math))
- if (!A->getOption().matches(options::OPT_fno_fast_math))
- CmdArgs.push_back("-ffast-math");
- if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only,
- options::OPT_fno_fast_math))
- if (A->getOption().matches(options::OPT_ffinite_math_only))
- CmdArgs.push_back("-ffinite-math-only");
-
- // Decide whether to use verbose asm. Verbose assembly is the default on
- // toolchains which have the integrated assembler on by default.
- bool IsIntegratedAssemblerDefault =
- getToolChain().IsIntegratedAssemblerDefault();
- if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
- IsIntegratedAssemblerDefault) ||
- Args.hasArg(options::OPT_dA))
- CmdArgs.push_back("-masm-verbose");
-
- if (!Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as,
- IsIntegratedAssemblerDefault))
- CmdArgs.push_back("-no-integrated-as");
-
- if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
- CmdArgs.push_back("-mdebug-pass");
- CmdArgs.push_back("Structure");
- }
- if (Args.hasArg(options::OPT_fdebug_pass_arguments)) {
- CmdArgs.push_back("-mdebug-pass");
- CmdArgs.push_back("Arguments");
- }
-
- // Enable -mconstructor-aliases except on darwin, where we have to work around
- // a linker bug (see <rdar://problem/7651567>), and CUDA device code, where
- // aliases aren't supported.
- if (!getToolChain().getTriple().isOSDarwin() &&
- !getToolChain().getTriple().isNVPTX())
- CmdArgs.push_back("-mconstructor-aliases");
-
- // Darwin's kernel doesn't support guard variables; just die if we
- // try to use them.
- if (KernelOrKext && getToolChain().getTriple().isOSDarwin())
- CmdArgs.push_back("-fforbid-guard-variables");
-
- if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields,
- false)) {
- CmdArgs.push_back("-mms-bitfields");
- }
-
- if (Args.hasFlag(options::OPT_mpie_copy_relocations,
- options::OPT_mno_pie_copy_relocations,
- false)) {
- CmdArgs.push_back("-mpie-copy-relocations");
- }
-
- // This is a coarse approximation of what llvm-gcc actually does, both
- // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
- // complicated ways.
- bool AsynchronousUnwindTables =
- Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
- options::OPT_fno_asynchronous_unwind_tables,
- (getToolChain().IsUnwindTablesDefault() ||
- getToolChain().getSanitizerArgs().needsUnwindTables()) &&
- !KernelOrKext);
- if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
- AsynchronousUnwindTables))
- CmdArgs.push_back("-munwind-tables");
-
- getToolChain().addClangTargetOptions(Args, CmdArgs);
-
- if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
- CmdArgs.push_back("-mlimit-float-precision");
- CmdArgs.push_back(A->getValue());
- }
-
- // FIXME: Handle -mtune=.
- (void)Args.hasArg(options::OPT_mtune_EQ);
-
- if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
- CmdArgs.push_back("-mcode-model");
- CmdArgs.push_back(A->getValue());
- }
-
- // Add the target cpu
- std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false);
- if (!CPU.empty()) {
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(CPU));
- }
-
- if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) {
- CmdArgs.push_back("-mfpmath");
- CmdArgs.push_back(A->getValue());
- }
-
- // Add the target features
- getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, false);
-
- // Add target specific flags.
- switch (getToolChain().getArch()) {
- default:
- break;
-
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- // Use the effective triple, which takes into account the deployment target.
- AddARMTargetArgs(Triple, Args, CmdArgs, KernelOrKext);
- break;
-
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- AddAArch64TargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- AddMIPSTargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- AddPPCTargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::sparcv9:
- AddSparcTargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::systemz:
- AddSystemZTargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- AddX86TargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::lanai:
- AddLanaiTargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::hexagon:
- AddHexagonTargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- AddWebAssemblyTargetArgs(Args, CmdArgs);
- break;
- }
-
- // The 'g' groups options involve a somewhat intricate sequence of decisions
- // about what to pass from the driver to the frontend, but by the time they
- // reach cc1 they've been factored into three well-defined orthogonal choices:
- // * what level of debug info to generate
- // * what dwarf version to write
- // * what debugger tuning to use
- // This avoids having to monkey around further in cc1 other than to disable
- // codeview if not running in a Windows environment. Perhaps even that
- // decision should be made in the driver as well though.
- unsigned DwarfVersion = 0;
- llvm::DebuggerKind DebuggerTuning = getToolChain().getDefaultDebuggerTuning();
- // These two are potentially updated by AddClangCLArgs.
- codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
- bool EmitCodeView = false;
-
- // Add clang-cl arguments.
- types::ID InputType = Input.getType();
- if (getToolChain().getDriver().IsCLMode())
- AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView);
-
- // Pass the linker version in use.
- if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
- CmdArgs.push_back("-target-linker-version");
- CmdArgs.push_back(A->getValue());
- }
-
- if (!shouldUseLeafFramePointer(Args, getToolChain().getTriple()))
- CmdArgs.push_back("-momit-leaf-frame-pointer");
-
- // Explicitly error on some things we know we don't support and can't just
- // ignore.
- if (!Args.hasArg(options::OPT_fallow_unsupported)) {
- Arg *Unsupported;
- if (types::isCXX(InputType) && getToolChain().getTriple().isOSDarwin() &&
- getToolChain().getArch() == llvm::Triple::x86) {
- if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) ||
- (Unsupported = Args.getLastArg(options::OPT_mkernel)))
- D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386)
- << Unsupported->getOption().getName();
- }
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_v);
- Args.AddLastArg(CmdArgs, options::OPT_H);
- if (D.CCPrintHeaders && !D.CCGenDiagnostics) {
- CmdArgs.push_back("-header-include-file");
- CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename
- : "-");
- }
- Args.AddLastArg(CmdArgs, options::OPT_P);
- Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
-
- if (D.CCLogDiagnostics && !D.CCGenDiagnostics) {
- CmdArgs.push_back("-diagnostic-log-file");
- CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename
- : "-");
- }
-
- bool splitDwarfInlining =
- Args.hasFlag(options::OPT_fsplit_dwarf_inlining,
- options::OPT_fno_split_dwarf_inlining, true);
-
- Args.ClaimAllArgs(options::OPT_g_Group);
- Arg *SplitDwarfArg = Args.getLastArg(options::OPT_gsplit_dwarf);
- if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- // If the last option explicitly specified a debug-info level, use it.
- if (A->getOption().matches(options::OPT_gN_Group)) {
- DebugInfoKind = DebugLevelToInfoKind(*A);
- // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses.
- // But -gsplit-dwarf is not a g_group option, hence we have to check the
- // order explicitly. (If -gsplit-dwarf wins, we fix DebugInfoKind later.)
- // This gets a bit more complicated if you've disabled inline info in the
- // skeleton CUs (splitDwarfInlining) - then there's value in composing
- // split-dwarf and line-tables-only, so let those compose naturally in
- // that case.
- // And if you just turned off debug info, (-gsplit-dwarf -g0) - do that.
- if (SplitDwarfArg) {
- if (A->getIndex() > SplitDwarfArg->getIndex()) {
- if (DebugInfoKind == codegenoptions::NoDebugInfo ||
- (DebugInfoKind == codegenoptions::DebugLineTablesOnly &&
- splitDwarfInlining))
- SplitDwarfArg = nullptr;
- } else if (splitDwarfInlining)
- DebugInfoKind = codegenoptions::NoDebugInfo;
- }
- } else
- // For any other 'g' option, use Limited.
- DebugInfoKind = codegenoptions::LimitedDebugInfo;
- }
-
- // If a debugger tuning argument appeared, remember it.
- if (Arg *A = Args.getLastArg(options::OPT_gTune_Group,
- options::OPT_ggdbN_Group)) {
- if (A->getOption().matches(options::OPT_glldb))
- DebuggerTuning = llvm::DebuggerKind::LLDB;
- else if (A->getOption().matches(options::OPT_gsce))
- DebuggerTuning = llvm::DebuggerKind::SCE;
- else
- DebuggerTuning = llvm::DebuggerKind::GDB;
- }
-
- // If a -gdwarf argument appeared, remember it.
- if (Arg *A = Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3,
- options::OPT_gdwarf_4, options::OPT_gdwarf_5))
- DwarfVersion = DwarfVersionNum(A->getSpelling());
-
- // Forward -gcodeview. EmitCodeView might have been set by CL-compatibility
- // argument parsing.
- if (Args.hasArg(options::OPT_gcodeview) || EmitCodeView) {
- // DwarfVersion remains at 0 if no explicit choice was made.
- CmdArgs.push_back("-gcodeview");
- } else if (DwarfVersion == 0 &&
- DebugInfoKind != codegenoptions::NoDebugInfo) {
- DwarfVersion = getToolChain().GetDefaultDwarfVersion();
- }
-
- // We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now.
- Args.ClaimAllArgs(options::OPT_g_flags_Group);
-
- // Column info is included by default for everything except PS4 and CodeView.
- // Clang doesn't track end columns, just starting columns, which, in theory,
- // is fine for CodeView (and PDB). In practice, however, the Microsoft
- // debuggers don't handle missing end columns well, so it's better not to
- // include any column info.
- if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info,
- /*Default=*/ !IsPS4CPU && !(IsWindowsMSVC && EmitCodeView)))
- CmdArgs.push_back("-dwarf-column-info");
-
- // FIXME: Move backend command line options to the module.
- // If -gline-tables-only is the last option it wins.
- if (DebugInfoKind != codegenoptions::DebugLineTablesOnly &&
- Args.hasArg(options::OPT_gmodules)) {
- DebugInfoKind = codegenoptions::LimitedDebugInfo;
- CmdArgs.push_back("-dwarf-ext-refs");
- CmdArgs.push_back("-fmodule-format=obj");
- }
-
- // -gsplit-dwarf should turn on -g and enable the backend dwarf
- // splitting and extraction.
- // FIXME: Currently only works on Linux.
- if (getToolChain().getTriple().isOSLinux() && SplitDwarfArg) {
- if (!splitDwarfInlining)
- CmdArgs.push_back("-fno-split-dwarf-inlining");
- if (DebugInfoKind == codegenoptions::NoDebugInfo)
- DebugInfoKind = codegenoptions::LimitedDebugInfo;
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-split-dwarf=Enable");
- }
-
- // After we've dealt with all combinations of things that could
- // make DebugInfoKind be other than None or DebugLineTablesOnly,
- // figure out if we need to "upgrade" it to standalone debug info.
- // We parse these two '-f' options whether or not they will be used,
- // to claim them even if you wrote "-fstandalone-debug -gline-tables-only"
- bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug,
- options::OPT_fno_standalone_debug,
- getToolChain().GetDefaultStandaloneDebug());
- if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug)
- DebugInfoKind = codegenoptions::FullDebugInfo;
- RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
- DebuggerTuning);
-
- // -ggnu-pubnames turns on gnu style pubnames in the backend.
- if (Args.hasArg(options::OPT_ggnu_pubnames)) {
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-generate-gnu-dwarf-pub-sections");
- }
-
- // -gdwarf-aranges turns on the emission of the aranges section in the
- // backend.
- // Always enabled on the PS4.
- if (Args.hasArg(options::OPT_gdwarf_aranges) || IsPS4CPU) {
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-generate-arange-section");
- }
-
- if (Args.hasFlag(options::OPT_fdebug_types_section,
- options::OPT_fno_debug_types_section, false)) {
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-generate-type-units");
- }
-
- bool UseSeparateSections = isUseSeparateSections(Triple);
-
- if (Args.hasFlag(options::OPT_ffunction_sections,
- options::OPT_fno_function_sections, UseSeparateSections)) {
- CmdArgs.push_back("-ffunction-sections");
- }
-
- if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
- UseSeparateSections)) {
- CmdArgs.push_back("-fdata-sections");
- }
-
- if (!Args.hasFlag(options::OPT_funique_section_names,
- options::OPT_fno_unique_section_names, true))
- CmdArgs.push_back("-fno-unique-section-names");
-
- Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions);
-
- if (Args.hasFlag(options::OPT_fxray_instrument,
- options::OPT_fnoxray_instrument, false)) {
- const char *const XRayInstrumentOption = "-fxray-instrument";
- if (Triple.getOS() == llvm::Triple::Linux)
- switch (Triple.getArch()) {
- case llvm::Triple::x86_64:
- case llvm::Triple::arm:
- case llvm::Triple::aarch64:
- // Supported.
- break;
- default:
- D.Diag(diag::err_drv_clang_unsupported)
- << (std::string(XRayInstrumentOption) + " on " + Triple.str());
- }
- else
- D.Diag(diag::err_drv_clang_unsupported)
- << (std::string(XRayInstrumentOption) + " on non-Linux target OS");
- CmdArgs.push_back(XRayInstrumentOption);
- if (const Arg *A =
- Args.getLastArg(options::OPT_fxray_instruction_threshold_,
- options::OPT_fxray_instruction_threshold_EQ)) {
- CmdArgs.push_back("-fxray-instruction-threshold");
- CmdArgs.push_back(A->getValue());
- }
- }
-
- addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs);
-
- // Add runtime flag for PS4 when PGO or Coverage are enabled.
- if (getToolChain().getTriple().isPS4CPU())
- addPS4ProfileRTArgs(getToolChain(), Args, CmdArgs);
-
- // Pass options for controlling the default header search paths.
- if (Args.hasArg(options::OPT_nostdinc)) {
- CmdArgs.push_back("-nostdsysteminc");
- CmdArgs.push_back("-nobuiltininc");
- } else {
- if (Args.hasArg(options::OPT_nostdlibinc))
- CmdArgs.push_back("-nostdsysteminc");
- Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
- Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
- }
-
- // Pass the path to compiler resource files.
- CmdArgs.push_back("-resource-dir");
- CmdArgs.push_back(D.ResourceDir.c_str());
-
- Args.AddLastArg(CmdArgs, options::OPT_working_directory);
-
- bool ARCMTEnabled = false;
- if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) {
- if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check,
- options::OPT_ccc_arcmt_modify,
- options::OPT_ccc_arcmt_migrate)) {
- ARCMTEnabled = true;
- switch (A->getOption().getID()) {
- default:
- llvm_unreachable("missed a case");
- case options::OPT_ccc_arcmt_check:
- CmdArgs.push_back("-arcmt-check");
- break;
- case options::OPT_ccc_arcmt_modify:
- CmdArgs.push_back("-arcmt-modify");
- break;
- case options::OPT_ccc_arcmt_migrate:
- CmdArgs.push_back("-arcmt-migrate");
- CmdArgs.push_back("-mt-migrate-directory");
- CmdArgs.push_back(A->getValue());
-
- Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output);
- Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors);
- break;
- }
- }
- } else {
- Args.ClaimAllArgs(options::OPT_ccc_arcmt_check);
- Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify);
- Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate);
- }
-
- if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) {
- if (ARCMTEnabled) {
- D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args)
- << "-ccc-arcmt-migrate";
- }
- CmdArgs.push_back("-mt-migrate-directory");
- CmdArgs.push_back(A->getValue());
-
- if (!Args.hasArg(options::OPT_objcmt_migrate_literals,
- options::OPT_objcmt_migrate_subscripting,
- options::OPT_objcmt_migrate_property)) {
- // None specified, means enable them all.
- CmdArgs.push_back("-objcmt-migrate-literals");
- CmdArgs.push_back("-objcmt-migrate-subscripting");
- CmdArgs.push_back("-objcmt-migrate-property");
- } else {
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property);
- }
- } else {
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property_dot_syntax);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path);
- }
-
- // Add preprocessing options like -I, -D, etc. if we are using the
- // preprocessor.
- //
- // FIXME: Support -fpreprocessed
- if (types::getPreprocessedType(InputType) != types::TY_INVALID)
- AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs);
-
- // Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes
- // that "The compiler can only warn and ignore the option if not recognized".
- // When building with ccache, it will pass -D options to clang even on
- // preprocessed inputs and configure concludes that -fPIC is not supported.
- Args.ClaimAllArgs(options::OPT_D);
-
- // Manually translate -O4 to -O3; let clang reject others.
- if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- if (A->getOption().matches(options::OPT_O4)) {
- CmdArgs.push_back("-O3");
- D.Diag(diag::warn_O4_is_O3);
- } else {
- A->render(Args, CmdArgs);
- }
- }
-
- // Warn about ignored options to clang.
- for (const Arg *A :
- Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) {
- D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args);
- A->claim();
- }
-
- claimNoWarnArgs(Args);
-
- Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
-
- Args.AddAllArgs(CmdArgs, options::OPT_W_Group);
- if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
- CmdArgs.push_back("-pedantic");
- Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors);
- Args.AddLastArg(CmdArgs, options::OPT_w);
-
- // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi}
- // (-ansi is equivalent to -std=c89 or -std=c++98).
- //
- // If a std is supplied, only add -trigraphs if it follows the
- // option.
- bool ImplyVCPPCXXVer = false;
- if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
- if (Std->getOption().matches(options::OPT_ansi))
- if (types::isCXX(InputType))
- CmdArgs.push_back("-std=c++98");
- else
- CmdArgs.push_back("-std=c89");
- else
- Std->render(Args, CmdArgs);
-
- // If -f(no-)trigraphs appears after the language standard flag, honor it.
- if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi,
- options::OPT_ftrigraphs,
- options::OPT_fno_trigraphs))
- if (A != Std)
- A->render(Args, CmdArgs);
- } else {
- // Honor -std-default.
- //
- // FIXME: Clang doesn't correctly handle -std= when the input language
- // doesn't match. For the time being just ignore this for C++ inputs;
- // eventually we want to do all the standard defaulting here instead of
- // splitting it between the driver and clang -cc1.
- if (!types::isCXX(InputType))
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=",
- /*Joined=*/true);
- else if (IsWindowsMSVC)
- ImplyVCPPCXXVer = true;
-
- Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs,
- options::OPT_fno_trigraphs);
- }
-
- // GCC's behavior for -Wwrite-strings is a bit strange:
- // * In C, this "warning flag" changes the types of string literals from
- // 'char[N]' to 'const char[N]', and thus triggers an unrelated warning
- // for the discarded qualifier.
- // * In C++, this is just a normal warning flag.
- //
- // Implementing this warning correctly in C is hard, so we follow GCC's
- // behavior for now. FIXME: Directly diagnose uses of a string literal as
- // a non-const char* in C, rather than using this crude hack.
- if (!types::isCXX(InputType)) {
- // FIXME: This should behave just like a warning flag, and thus should also
- // respect -Weverything, -Wno-everything, -Werror=write-strings, and so on.
- Arg *WriteStrings =
- Args.getLastArg(options::OPT_Wwrite_strings,
- options::OPT_Wno_write_strings, options::OPT_w);
- if (WriteStrings &&
- WriteStrings->getOption().matches(options::OPT_Wwrite_strings))
- CmdArgs.push_back("-fconst-strings");
- }
-
- // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active
- // during C++ compilation, which it is by default. GCC keeps this define even
- // in the presence of '-w', match this behavior bug-for-bug.
- if (types::isCXX(InputType) &&
- Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated,
- true)) {
- CmdArgs.push_back("-fdeprecated-macro");
- }
-
- // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'.
- if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) {
- if (Asm->getOption().matches(options::OPT_fasm))
- CmdArgs.push_back("-fgnu-keywords");
- else
- CmdArgs.push_back("-fno-gnu-keywords");
- }
-
- if (ShouldDisableDwarfDirectory(Args, getToolChain()))
- CmdArgs.push_back("-fno-dwarf-directory-asm");
-
- if (ShouldDisableAutolink(Args, getToolChain()))
- CmdArgs.push_back("-fno-autolink");
-
- // Add in -fdebug-compilation-dir if necessary.
- addDebugCompDirArg(Args, CmdArgs);
-
- for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) {
- StringRef Map = A->getValue();
- if (Map.find('=') == StringRef::npos)
- D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map;
- else
- CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map));
- A->claim();
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
- options::OPT_ftemplate_depth_EQ)) {
- CmdArgs.push_back("-ftemplate-depth");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) {
- CmdArgs.push_back("-foperator-arrow-depth");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) {
- CmdArgs.push_back("-fconstexpr-depth");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) {
- CmdArgs.push_back("-fconstexpr-steps");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
- CmdArgs.push_back("-fbracket-depth");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
- options::OPT_Wlarge_by_value_copy_def)) {
- if (A->getNumValues()) {
- StringRef bytes = A->getValue();
- CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes));
- } else
- CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value
- }
-
- if (Args.hasArg(options::OPT_relocatable_pch))
- CmdArgs.push_back("-relocatable-pch");
-
- if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
- CmdArgs.push_back("-fconstant-string-class");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) {
- CmdArgs.push_back("-ftabstop");
- CmdArgs.push_back(A->getValue());
- }
-
- CmdArgs.push_back("-ferror-limit");
- if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
- CmdArgs.push_back(A->getValue());
- else
- CmdArgs.push_back("19");
-
- if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) {
- CmdArgs.push_back("-fmacro-backtrace-limit");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) {
- CmdArgs.push_back("-ftemplate-backtrace-limit");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) {
- CmdArgs.push_back("-fconstexpr-backtrace-limit");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) {
- CmdArgs.push_back("-fspell-checking-limit");
- CmdArgs.push_back(A->getValue());
- }
-
- // Pass -fmessage-length=.
- CmdArgs.push_back("-fmessage-length");
- if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
- CmdArgs.push_back(A->getValue());
- } else {
- // If -fmessage-length=N was not specified, determine whether this is a
- // terminal and, if so, implicitly define -fmessage-length appropriately.
- unsigned N = llvm::sys::Process::StandardErrColumns();
- CmdArgs.push_back(Args.MakeArgString(Twine(N)));
- }
-
- // -fvisibility= and -fvisibility-ms-compat are of a piece.
- if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
- options::OPT_fvisibility_ms_compat)) {
- if (A->getOption().matches(options::OPT_fvisibility_EQ)) {
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back(A->getValue());
- } else {
- assert(A->getOption().matches(options::OPT_fvisibility_ms_compat));
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back("hidden");
- CmdArgs.push_back("-ftype-visibility");
- CmdArgs.push_back("default");
- }
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden);
-
- Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
-
- // -fhosted is default.
- bool IsHosted = true;
- if (Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) ||
- KernelOrKext) {
- CmdArgs.push_back("-ffreestanding");
- IsHosted = false;
- }
-
- // Forward -f (flag) options which we can pass directly.
- Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
- Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
- Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
- // Emulated TLS is enabled by default on Android, and can be enabled manually
- // with -femulated-tls.
- bool EmulatedTLSDefault = Triple.isAndroid() || Triple.isWindowsCygwinEnvironment();
- if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls,
- EmulatedTLSDefault))
- CmdArgs.push_back("-femulated-tls");
- // AltiVec-like language extensions aren't relevant for assembling.
- if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) {
- Args.AddLastArg(CmdArgs, options::OPT_faltivec);
- Args.AddLastArg(CmdArgs, options::OPT_fzvector);
- }
- Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
- Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
-
- // Forward flags for OpenMP. We don't do this if the current action is an
- // device offloading action other than OpenMP.
- if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
- options::OPT_fno_openmp, false) &&
- (JA.isDeviceOffloading(Action::OFK_None) ||
- JA.isDeviceOffloading(Action::OFK_OpenMP))) {
- switch (getToolChain().getDriver().getOpenMPRuntime(Args)) {
- case Driver::OMPRT_OMP:
- case Driver::OMPRT_IOMP5:
- // Clang can generate useful OpenMP code for these two runtime libraries.
- CmdArgs.push_back("-fopenmp");
-
- // If no option regarding the use of TLS in OpenMP codegeneration is
- // given, decide a default based on the target. Otherwise rely on the
- // options and pass the right information to the frontend.
- if (!Args.hasFlag(options::OPT_fopenmp_use_tls,
- options::OPT_fnoopenmp_use_tls, /*Default=*/true))
- CmdArgs.push_back("-fnoopenmp-use-tls");
- Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
- break;
- default:
- // By default, if Clang doesn't know how to generate useful OpenMP code
- // for a specific runtime library, we just don't pass the '-fopenmp' flag
- // down to the actual compilation.
- // FIXME: It would be better to have a mode which *only* omits IR
- // generation based on the OpenMP support so that we get consistent
- // semantic analysis, etc.
- break;
- }
- }
-
- const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs();
- Sanitize.addArgs(getToolChain(), Args, CmdArgs, InputType);
-
- // Report an error for -faltivec on anything other than PowerPC.
- if (const Arg *A = Args.getLastArg(options::OPT_faltivec)) {
- const llvm::Triple::ArchType Arch = getToolChain().getArch();
- if (!(Arch == llvm::Triple::ppc || Arch == llvm::Triple::ppc64 ||
- Arch == llvm::Triple::ppc64le))
- D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args)
- << "ppc/ppc64/ppc64le";
- }
-
- // -fzvector is incompatible with -faltivec.
- if (Arg *A = Args.getLastArg(options::OPT_fzvector))
- if (Args.hasArg(options::OPT_faltivec))
- D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args)
- << "-faltivec";
-
- if (getToolChain().SupportsProfiling())
- Args.AddLastArg(CmdArgs, options::OPT_pg);
-
- // -flax-vector-conversions is default.
- if (!Args.hasFlag(options::OPT_flax_vector_conversions,
- options::OPT_fno_lax_vector_conversions))
- CmdArgs.push_back("-fno-lax-vector-conversions");
-
- if (Args.getLastArg(options::OPT_fapple_kext) ||
- (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType)))
- CmdArgs.push_back("-fapple-kext");
-
- Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
- Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
- Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
- Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
- Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
-
- if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
- CmdArgs.push_back("-ftrapv-handler");
- CmdArgs.push_back(A->getValue());
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);
-
- // -fno-strict-overflow implies -fwrapv if it isn't disabled, but
- // -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
- if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) {
- if (A->getOption().matches(options::OPT_fwrapv))
- CmdArgs.push_back("-fwrapv");
- } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
- options::OPT_fno_strict_overflow)) {
- if (A->getOption().matches(options::OPT_fno_strict_overflow))
- CmdArgs.push_back("-fwrapv");
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_freroll_loops,
- options::OPT_fno_reroll_loops))
- if (A->getOption().matches(options::OPT_freroll_loops))
- CmdArgs.push_back("-freroll-loops");
-
- Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
- Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
- options::OPT_fno_unroll_loops);
-
- Args.AddLastArg(CmdArgs, options::OPT_pthread);
-
- // -stack-protector=0 is default.
- unsigned StackProtectorLevel = 0;
- if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
- options::OPT_fstack_protector_all,
- options::OPT_fstack_protector_strong,
- options::OPT_fstack_protector)) {
- if (A->getOption().matches(options::OPT_fstack_protector)) {
- StackProtectorLevel = std::max<unsigned>(
- LangOptions::SSPOn,
- getToolChain().GetDefaultStackProtectorLevel(KernelOrKext));
- } else if (A->getOption().matches(options::OPT_fstack_protector_strong))
- StackProtectorLevel = LangOptions::SSPStrong;
- else if (A->getOption().matches(options::OPT_fstack_protector_all))
- StackProtectorLevel = LangOptions::SSPReq;
- } else {
- StackProtectorLevel =
- getToolChain().GetDefaultStackProtectorLevel(KernelOrKext);
- // Only use a default stack protector on Darwin in case -ffreestanding
- // is not specified.
- if (Triple.isOSDarwin() && !IsHosted)
- StackProtectorLevel = 0;
- }
- if (StackProtectorLevel) {
- CmdArgs.push_back("-stack-protector");
- CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel)));
- }
-
- // --param ssp-buffer-size=
- for (const Arg *A : Args.filtered(options::OPT__param)) {
- StringRef Str(A->getValue());
- if (Str.startswith("ssp-buffer-size=")) {
- if (StackProtectorLevel) {
- CmdArgs.push_back("-stack-protector-buffer-size");
- // FIXME: Verify the argument is a valid integer.
- CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16)));
- }
- A->claim();
- }
- }
-
- // Translate -mstackrealign
- if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
- false))
- CmdArgs.push_back(Args.MakeArgString("-mstackrealign"));
-
- if (Args.hasArg(options::OPT_mstack_alignment)) {
- StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
- CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
- }
-
- if (Args.hasArg(options::OPT_mstack_probe_size)) {
- StringRef Size = Args.getLastArgValue(options::OPT_mstack_probe_size);
-
- if (!Size.empty())
- CmdArgs.push_back(Args.MakeArgString("-mstack-probe-size=" + Size));
- else
- CmdArgs.push_back("-mstack-probe-size=0");
- }
-
- switch (getToolChain().getArch()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- CmdArgs.push_back("-fallow-half-arguments-and-returns");
- break;
-
- default:
- break;
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
- options::OPT_mno_restrict_it)) {
- if (A->getOption().matches(options::OPT_mrestrict_it)) {
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-restrict-it");
- } else {
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-no-restrict-it");
- }
- } else if (Triple.isOSWindows() &&
- (Triple.getArch() == llvm::Triple::arm ||
- Triple.getArch() == llvm::Triple::thumb)) {
- // Windows on ARM expects restricted IT blocks
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-restrict-it");
- }
-
- // Forward -cl options to -cc1
- if (Args.getLastArg(options::OPT_cl_opt_disable)) {
- CmdArgs.push_back("-cl-opt-disable");
- }
- if (Args.getLastArg(options::OPT_cl_strict_aliasing)) {
- CmdArgs.push_back("-cl-strict-aliasing");
- }
- if (Args.getLastArg(options::OPT_cl_single_precision_constant)) {
- CmdArgs.push_back("-cl-single-precision-constant");
- }
- if (Args.getLastArg(options::OPT_cl_finite_math_only)) {
- CmdArgs.push_back("-cl-finite-math-only");
- }
- if (Args.getLastArg(options::OPT_cl_kernel_arg_info)) {
- CmdArgs.push_back("-cl-kernel-arg-info");
- }
- if (Args.getLastArg(options::OPT_cl_unsafe_math_optimizations)) {
- CmdArgs.push_back("-cl-unsafe-math-optimizations");
- }
- if (Args.getLastArg(options::OPT_cl_fast_relaxed_math)) {
- CmdArgs.push_back("-cl-fast-relaxed-math");
- }
- if (Args.getLastArg(options::OPT_cl_mad_enable)) {
- CmdArgs.push_back("-cl-mad-enable");
- }
- if (Args.getLastArg(options::OPT_cl_no_signed_zeros)) {
- CmdArgs.push_back("-cl-no-signed-zeros");
- }
- if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) {
- std::string CLStdStr = "-cl-std=";
- CLStdStr += A->getValue();
- CmdArgs.push_back(Args.MakeArgString(CLStdStr));
- }
- if (Args.getLastArg(options::OPT_cl_denorms_are_zero)) {
- CmdArgs.push_back("-cl-denorms-are-zero");
- }
- if (Args.getLastArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt)) {
- CmdArgs.push_back("-cl-fp32-correctly-rounded-divide-sqrt");
- }
-
- // Forward -f options with positive and negative forms; we translate
- // these by hand.
- if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) {
- StringRef fname = A->getValue();
- if (!llvm::sys::fs::exists(fname))
- D.Diag(diag::err_drv_no_such_file) << fname;
- else
- A->render(Args, CmdArgs);
- }
-
- // -fbuiltin is default unless -mkernel is used.
- bool UseBuiltins =
- Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin,
- !Args.hasArg(options::OPT_mkernel));
- if (!UseBuiltins)
- CmdArgs.push_back("-fno-builtin");
-
- // -ffreestanding implies -fno-builtin.
- if (Args.hasArg(options::OPT_ffreestanding))
- UseBuiltins = false;
-
- // Process the -fno-builtin-* options.
- for (const auto &Arg : Args) {
- const Option &O = Arg->getOption();
- if (!O.matches(options::OPT_fno_builtin_))
- continue;
-
- Arg->claim();
- // If -fno-builtin is specified, then there's no need to pass the option to
- // the frontend.
- if (!UseBuiltins)
- continue;
-
- StringRef FuncName = Arg->getValue();
- CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName));
- }
-
- if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
- options::OPT_fno_assume_sane_operator_new))
- CmdArgs.push_back("-fno-assume-sane-operator-new");
-
- // -fblocks=0 is default.
- if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
- getToolChain().IsBlocksDefault()) ||
- (Args.hasArg(options::OPT_fgnu_runtime) &&
- Args.hasArg(options::OPT_fobjc_nonfragile_abi) &&
- !Args.hasArg(options::OPT_fno_blocks))) {
- CmdArgs.push_back("-fblocks");
-
- if (!Args.hasArg(options::OPT_fgnu_runtime) &&
- !getToolChain().hasBlocksRuntime())
- CmdArgs.push_back("-fblocks-runtime-optional");
- }
-
- if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts,
- false) &&
- types::isCXX(InputType)) {
- CmdArgs.push_back("-fcoroutines-ts");
- }
-
- // -fmodules enables the use of precompiled modules (off by default).
- // Users can pass -fno-cxx-modules to turn off modules support for
- // C++/Objective-C++ programs.
- bool HaveClangModules = false;
- if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
- bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
- options::OPT_fno_cxx_modules, true);
- if (AllowedInCXX || !types::isCXX(InputType)) {
- CmdArgs.push_back("-fmodules");
- HaveClangModules = true;
- }
- }
-
- bool HaveAnyModules = HaveClangModules;
- if (Args.hasArg(options::OPT_fmodules_ts)) {
- CmdArgs.push_back("-fmodules-ts");
- HaveAnyModules = true;
- }
-
- // -fmodule-maps enables implicit reading of module map files. By default,
- // this is enabled if we are using Clang's flavor of precompiled modules.
- if (Args.hasFlag(options::OPT_fimplicit_module_maps,
- options::OPT_fno_implicit_module_maps, HaveClangModules)) {
- CmdArgs.push_back("-fimplicit-module-maps");
- }
-
- // -fmodules-decluse checks that modules used are declared so (off by
- // default).
- if (Args.hasFlag(options::OPT_fmodules_decluse,
- options::OPT_fno_modules_decluse, false)) {
- CmdArgs.push_back("-fmodules-decluse");
- }
-
- // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that
- // all #included headers are part of modules.
- if (Args.hasFlag(options::OPT_fmodules_strict_decluse,
- options::OPT_fno_modules_strict_decluse, false)) {
- CmdArgs.push_back("-fmodules-strict-decluse");
- }
-
- // -fno-implicit-modules turns off implicitly compiling modules on demand.
- if (!Args.hasFlag(options::OPT_fimplicit_modules,
- options::OPT_fno_implicit_modules, HaveClangModules)) {
- if (HaveAnyModules)
- CmdArgs.push_back("-fno-implicit-modules");
- } else if (HaveAnyModules) {
- // -fmodule-cache-path specifies where our implicitly-built module files
- // should be written.
- SmallString<128> Path;
- if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path))
- Path = A->getValue();
- if (C.isForDiagnostics()) {
- // When generating crash reports, we want to emit the modules along with
- // the reproduction sources, so we ignore any provided module path.
- Path = Output.getFilename();
- llvm::sys::path::replace_extension(Path, ".cache");
- llvm::sys::path::append(Path, "modules");
- } else if (Path.empty()) {
- // No module path was provided: use the default.
- llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Path);
- llvm::sys::path::append(Path, "org.llvm.clang.");
- appendUserToPath(Path);
- llvm::sys::path::append(Path, "ModuleCache");
- }
- const char Arg[] = "-fmodules-cache-path=";
- Path.insert(Path.begin(), Arg, Arg + strlen(Arg));
- CmdArgs.push_back(Args.MakeArgString(Path));
- }
-
- if (HaveAnyModules) {
- // -fprebuilt-module-path specifies where to load the prebuilt module files.
- for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path))
- CmdArgs.push_back(Args.MakeArgString(
- std::string("-fprebuilt-module-path=") + A->getValue()));
- }
-
- // -fmodule-name specifies the module that is currently being built (or
- // used for header checking by -fmodule-maps).
- Args.AddLastArg(CmdArgs, options::OPT_fmodule_name_EQ);
-
- // -fmodule-map-file can be used to specify files containing module
- // definitions.
- Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file);
-
- // -fbuiltin-module-map can be used to load the clang
- // builtin headers modulemap file.
- if (Args.hasArg(options::OPT_fbuiltin_module_map)) {
- SmallString<128> BuiltinModuleMap(getToolChain().getDriver().ResourceDir);
- llvm::sys::path::append(BuiltinModuleMap, "include");
- llvm::sys::path::append(BuiltinModuleMap, "module.modulemap");
- if (llvm::sys::fs::exists(BuiltinModuleMap)) {
- CmdArgs.push_back(Args.MakeArgString("-fmodule-map-file=" +
- BuiltinModuleMap));
- }
- }
-
- // -fmodule-file can be used to specify files containing precompiled modules.
- if (HaveAnyModules)
- Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file);
- else
- Args.ClaimAllArgs(options::OPT_fmodule_file);
-
- // When building modules and generating crashdumps, we need to dump a module
- // dependency VFS alongside the output.
- if (HaveClangModules && C.isForDiagnostics()) {
- SmallString<128> VFSDir(Output.getFilename());
- llvm::sys::path::replace_extension(VFSDir, ".cache");
- // Add the cache directory as a temp so the crash diagnostics pick it up.
- C.addTempFile(Args.MakeArgString(VFSDir));
-
- llvm::sys::path::append(VFSDir, "vfs");
- CmdArgs.push_back("-module-dependency-dir");
- CmdArgs.push_back(Args.MakeArgString(VFSDir));
- }
-
- if (HaveClangModules)
- Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path);
-
- // Pass through all -fmodules-ignore-macro arguments.
- Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro);
- Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval);
- Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after);
-
- Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
-
- if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
- if (Args.hasArg(options::OPT_fbuild_session_timestamp))
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "-fbuild-session-timestamp";
-
- llvm::sys::fs::file_status Status;
- if (llvm::sys::fs::status(A->getValue(), Status))
- D.Diag(diag::err_drv_no_such_file) << A->getValue();
- CmdArgs.push_back(
- Args.MakeArgString("-fbuild-session-timestamp=" +
- Twine((uint64_t)Status.getLastModificationTime()
- .time_since_epoch()
- .count())));
- }
-
- if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) {
- if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
- options::OPT_fbuild_session_file))
- D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
-
- Args.AddLastArg(CmdArgs,
- options::OPT_fmodules_validate_once_per_build_session);
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers);
- Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation);
-
- // -faccess-control is default.
- if (Args.hasFlag(options::OPT_fno_access_control,
- options::OPT_faccess_control, false))
- CmdArgs.push_back("-fno-access-control");
-
- // -felide-constructors is the default.
- if (Args.hasFlag(options::OPT_fno_elide_constructors,
- options::OPT_felide_constructors, false))
- CmdArgs.push_back("-fno-elide-constructors");
-
- ToolChain::RTTIMode RTTIMode = getToolChain().getRTTIMode();
-
- if (KernelOrKext || (types::isCXX(InputType) &&
- (RTTIMode == ToolChain::RM_DisabledExplicitly ||
- RTTIMode == ToolChain::RM_DisabledImplicitly)))
- CmdArgs.push_back("-fno-rtti");
-
- // -fshort-enums=0 is default for all architectures except Hexagon.
- if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums,
- getToolChain().getArch() == llvm::Triple::hexagon))
- CmdArgs.push_back("-fshort-enums");
-
- // -fsigned-char is default.
- if (Arg *A = Args.getLastArg(
- options::OPT_fsigned_char, options::OPT_fno_signed_char,
- options::OPT_funsigned_char, options::OPT_fno_unsigned_char)) {
- if (A->getOption().matches(options::OPT_funsigned_char) ||
- A->getOption().matches(options::OPT_fno_signed_char)) {
- CmdArgs.push_back("-fno-signed-char");
- }
- } else if (!isSignedCharDefault(getToolChain().getTriple())) {
- CmdArgs.push_back("-fno-signed-char");
- }
-
- // -fuse-cxa-atexit is default.
- if (!Args.hasFlag(
- options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
- !IsWindowsCygnus && !IsWindowsGNU &&
- getToolChain().getTriple().getOS() != llvm::Triple::Solaris &&
- getToolChain().getArch() != llvm::Triple::hexagon &&
- getToolChain().getArch() != llvm::Triple::xcore &&
- ((getToolChain().getTriple().getVendor() !=
- llvm::Triple::MipsTechnologies) ||
- getToolChain().getTriple().hasEnvironment())) ||
- KernelOrKext)
- CmdArgs.push_back("-fno-use-cxa-atexit");
-
- // -fms-extensions=0 is default.
- if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
- IsWindowsMSVC))
- CmdArgs.push_back("-fms-extensions");
-
- // -fno-use-line-directives is default.
- if (Args.hasFlag(options::OPT_fuse_line_directives,
- options::OPT_fno_use_line_directives, false))
- CmdArgs.push_back("-fuse-line-directives");
-
- // -fms-compatibility=0 is default.
- if (Args.hasFlag(options::OPT_fms_compatibility,
- options::OPT_fno_ms_compatibility,
- (IsWindowsMSVC &&
- Args.hasFlag(options::OPT_fms_extensions,
- options::OPT_fno_ms_extensions, true))))
- CmdArgs.push_back("-fms-compatibility");
-
- VersionTuple MSVT =
- getToolChain().computeMSVCVersion(&getToolChain().getDriver(), Args);
- if (!MSVT.empty())
- CmdArgs.push_back(
- Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString()));
-
- bool IsMSVC2015Compatible = MSVT.getMajor() >= 19;
- if (ImplyVCPPCXXVer) {
- StringRef LanguageStandard;
- if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) {
- LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue())
- .Case("c++14", "-std=c++14")
- .Case("c++latest", "-std=c++1z")
- .Default("");
- if (LanguageStandard.empty())
- D.Diag(clang::diag::warn_drv_unused_argument)
- << StdArg->getAsString(Args);
- }
-
- if (LanguageStandard.empty()) {
- if (IsMSVC2015Compatible)
- LanguageStandard = "-std=c++14";
- else
- LanguageStandard = "-std=c++11";
- }
-
- CmdArgs.push_back(LanguageStandard.data());
- }
-
- // -fno-borland-extensions is default.
- if (Args.hasFlag(options::OPT_fborland_extensions,
- options::OPT_fno_borland_extensions, false))
- CmdArgs.push_back("-fborland-extensions");
-
- // -fno-declspec is default, except for PS4.
- if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec,
- getToolChain().getTriple().isPS4()))
- CmdArgs.push_back("-fdeclspec");
- else if (Args.hasArg(options::OPT_fno_declspec))
- CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec.
-
- // -fthreadsafe-static is default, except for MSVC compatibility versions less
- // than 19.
- if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
- options::OPT_fno_threadsafe_statics,
- !IsWindowsMSVC || IsMSVC2015Compatible))
- CmdArgs.push_back("-fno-threadsafe-statics");
-
- // -fno-delayed-template-parsing is default, except for Windows where MSVC STL
- // needs it.
- if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
- options::OPT_fno_delayed_template_parsing, IsWindowsMSVC))
- CmdArgs.push_back("-fdelayed-template-parsing");
-
- // -fgnu-keywords default varies depending on language; only pass if
- // specified.
- if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords,
- options::OPT_fno_gnu_keywords))
- A->render(Args, CmdArgs);
-
- if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline,
- false))
- CmdArgs.push_back("-fgnu89-inline");
-
- if (Args.hasArg(options::OPT_fno_inline))
- CmdArgs.push_back("-fno-inline");
-
- if (Arg* InlineArg = Args.getLastArg(options::OPT_finline_functions,
- options::OPT_finline_hint_functions,
- options::OPT_fno_inline_functions))
- InlineArg->render(Args, CmdArgs);
-
- Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager,
- options::OPT_fno_experimental_new_pass_manager);
-
- ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind);
-
- // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
- // legacy is the default. Except for deployment target of 10.5,
- // next runtime is always legacy dispatch and -fno-objc-legacy-dispatch
- // gets ignored silently.
- if (objcRuntime.isNonFragile()) {
- if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
- options::OPT_fno_objc_legacy_dispatch,
- objcRuntime.isLegacyDispatchDefaultForArch(
- getToolChain().getArch()))) {
- if (getToolChain().UseObjCMixedDispatch())
- CmdArgs.push_back("-fobjc-dispatch-method=mixed");
- else
- CmdArgs.push_back("-fobjc-dispatch-method=non-legacy");
- }
- }
-
- // When ObjectiveC legacy runtime is in effect on MacOSX,
- // turn on the option to do Array/Dictionary subscripting
- // by default.
- if (getToolChain().getArch() == llvm::Triple::x86 &&
- getToolChain().getTriple().isMacOSX() &&
- !getToolChain().getTriple().isMacOSXVersionLT(10, 7) &&
- objcRuntime.getKind() == ObjCRuntime::FragileMacOSX &&
- objcRuntime.isNeXTFamily())
- CmdArgs.push_back("-fobjc-subscripting-legacy-runtime");
-
- // -fencode-extended-block-signature=1 is default.
- if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) {
- CmdArgs.push_back("-fencode-extended-block-signature");
- }
-
- // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
- // NOTE: This logic is duplicated in ToolChains.cpp.
- bool ARC = isObjCAutoRefCount(Args);
- if (ARC) {
- getToolChain().CheckObjCARC();
-
- CmdArgs.push_back("-fobjc-arc");
-
- // FIXME: It seems like this entire block, and several around it should be
- // wrapped in isObjC, but for now we just use it here as this is where it
- // was being used previously.
- if (types::isCXX(InputType) && types::isObjC(InputType)) {
- if (getToolChain().GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
- CmdArgs.push_back("-fobjc-arc-cxxlib=libc++");
- else
- CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++");
- }
-
- // Allow the user to enable full exceptions code emission.
- // We define off for Objective-CC, on for Objective-C++.
- if (Args.hasFlag(options::OPT_fobjc_arc_exceptions,
- options::OPT_fno_objc_arc_exceptions,
- /*default*/ types::isCXX(InputType)))
- CmdArgs.push_back("-fobjc-arc-exceptions");
-
- }
-
- // -fobjc-infer-related-result-type is the default, except in the Objective-C
- // rewriter.
- if (rewriteKind != RK_None)
- CmdArgs.push_back("-fno-objc-infer-related-result-type");
-
- // Pass down -fobjc-weak or -fno-objc-weak if present.
- if (types::isObjC(InputType)) {
- auto WeakArg = Args.getLastArg(options::OPT_fobjc_weak,
- options::OPT_fno_objc_weak);
- if (!WeakArg) {
- // nothing to do
- } else if (!objcRuntime.allowsWeak()) {
- if (WeakArg->getOption().matches(options::OPT_fobjc_weak))
- D.Diag(diag::err_objc_weak_unsupported);
- } else {
- WeakArg->render(Args, CmdArgs);
- }
- }
-
- if (Args.hasFlag(options::OPT_fapplication_extension,
- options::OPT_fno_application_extension, false))
- CmdArgs.push_back("-fapplication-extension");
-
- // Handle GCC-style exception args.
- if (!C.getDriver().IsCLMode())
- addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, objcRuntime,
- CmdArgs);
-
- if (Args.hasArg(options::OPT_fsjlj_exceptions) ||
- getToolChain().UseSjLjExceptions(Args))
- CmdArgs.push_back("-fsjlj-exceptions");
-
- // C++ "sane" operator new.
- if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
- options::OPT_fno_assume_sane_operator_new))
- CmdArgs.push_back("-fno-assume-sane-operator-new");
-
- // -frelaxed-template-template-args is off by default, as it is a severe
- // breaking change until a corresponding change to template partial ordering
- // is provided.
- if (Args.hasFlag(options::OPT_frelaxed_template_template_args,
- options::OPT_fno_relaxed_template_template_args, false))
- CmdArgs.push_back("-frelaxed-template-template-args");
-
- // -fsized-deallocation is off by default, as it is an ABI-breaking change for
- // most platforms.
- if (Args.hasFlag(options::OPT_fsized_deallocation,
- options::OPT_fno_sized_deallocation, false))
- CmdArgs.push_back("-fsized-deallocation");
-
- // -faligned-allocation is on by default in C++17 onwards and otherwise off
- // by default.
- if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation,
- options::OPT_fno_aligned_allocation,
- options::OPT_faligned_new_EQ)) {
- if (A->getOption().matches(options::OPT_fno_aligned_allocation))
- CmdArgs.push_back("-fno-aligned-allocation");
- else
- CmdArgs.push_back("-faligned-allocation");
- }
-
- // The default new alignment can be specified using a dedicated option or via
- // a GCC-compatible option that also turns on aligned allocation.
- if (Arg *A = Args.getLastArg(options::OPT_fnew_alignment_EQ,
- options::OPT_faligned_new_EQ))
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-fnew-alignment=") + A->getValue()));
-
- // -fconstant-cfstrings is default, and may be subject to argument translation
- // on Darwin.
- if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
- options::OPT_fno_constant_cfstrings) ||
- !Args.hasFlag(options::OPT_mconstant_cfstrings,
- options::OPT_mno_constant_cfstrings))
- CmdArgs.push_back("-fno-constant-cfstrings");
-
- // -fshort-wchar default varies depending on platform; only
- // pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar,
- options::OPT_fno_short_wchar))
- A->render(Args, CmdArgs);
-
- // -fno-pascal-strings is default, only pass non-default.
- if (Args.hasFlag(options::OPT_fpascal_strings,
- options::OPT_fno_pascal_strings, false))
- CmdArgs.push_back("-fpascal-strings");
-
- // Honor -fpack-struct= and -fpack-struct, if given. Note that
- // -fno-pack-struct doesn't apply to -fpack-struct=.
- if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) {
- std::string PackStructStr = "-fpack-struct=";
- PackStructStr += A->getValue();
- CmdArgs.push_back(Args.MakeArgString(PackStructStr));
- } else if (Args.hasFlag(options::OPT_fpack_struct,
- options::OPT_fno_pack_struct, false)) {
- CmdArgs.push_back("-fpack-struct=1");
- }
-
- // Handle -fmax-type-align=N and -fno-type-align
- bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align);
- if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) {
- if (!SkipMaxTypeAlign) {
- std::string MaxTypeAlignStr = "-fmax-type-align=";
- MaxTypeAlignStr += A->getValue();
- CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
- }
- } else if (getToolChain().getTriple().isOSDarwin()) {
- if (!SkipMaxTypeAlign) {
- std::string MaxTypeAlignStr = "-fmax-type-align=16";
- CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
- }
- }
-
- // -fcommon is the default unless compiling kernel code or the target says so
- bool NoCommonDefault =
- KernelOrKext || isNoCommonDefault(getToolChain().getTriple());
- if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common,
- !NoCommonDefault))
- CmdArgs.push_back("-fno-common");
-
- // -fsigned-bitfields is default, and clang doesn't yet support
- // -funsigned-bitfields.
- if (!Args.hasFlag(options::OPT_fsigned_bitfields,
- options::OPT_funsigned_bitfields))
- D.Diag(diag::warn_drv_clang_unsupported)
- << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args);
-
- // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope.
- if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope))
- D.Diag(diag::err_drv_clang_unsupported)
- << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args);
-
- // -finput_charset=UTF-8 is default. Reject others
- if (Arg *inputCharset = Args.getLastArg(options::OPT_finput_charset_EQ)) {
- StringRef value = inputCharset->getValue();
- if (!value.equals_lower("utf-8"))
- D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args)
- << value;
- }
-
- // -fexec_charset=UTF-8 is default. Reject others
- if (Arg *execCharset = Args.getLastArg(options::OPT_fexec_charset_EQ)) {
- StringRef value = execCharset->getValue();
- if (!value.equals_lower("utf-8"))
- D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args)
- << value;
- }
-
- // -fcaret-diagnostics is default.
- if (!Args.hasFlag(options::OPT_fcaret_diagnostics,
- options::OPT_fno_caret_diagnostics, true))
- CmdArgs.push_back("-fno-caret-diagnostics");
-
- // -fdiagnostics-fixit-info is default, only pass non-default.
- if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info,
- options::OPT_fno_diagnostics_fixit_info))
- CmdArgs.push_back("-fno-diagnostics-fixit-info");
-
- // Enable -fdiagnostics-show-option by default.
- if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
- options::OPT_fno_diagnostics_show_option))
- CmdArgs.push_back("-fdiagnostics-show-option");
-
- if (const Arg *A =
- Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) {
- CmdArgs.push_back("-fdiagnostics-show-category");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness,
- options::OPT_fno_diagnostics_show_hotness, false))
- CmdArgs.push_back("-fdiagnostics-show-hotness");
-
- if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
- CmdArgs.push_back("-fdiagnostics-format");
- CmdArgs.push_back(A->getValue());
- }
-
- if (Arg *A = Args.getLastArg(
- options::OPT_fdiagnostics_show_note_include_stack,
- options::OPT_fno_diagnostics_show_note_include_stack)) {
- if (A->getOption().matches(
- options::OPT_fdiagnostics_show_note_include_stack))
- CmdArgs.push_back("-fdiagnostics-show-note-include-stack");
- else
- CmdArgs.push_back("-fno-diagnostics-show-note-include-stack");
- }
-
- // Color diagnostics are parsed by the driver directly from argv
- // and later re-parsed to construct this job; claim any possible
- // color diagnostic here to avoid warn_drv_unused_argument and
- // diagnose bad OPT_fdiagnostics_color_EQ values.
- for (Arg *A : Args) {
- const Option &O = A->getOption();
- if (!O.matches(options::OPT_fcolor_diagnostics) &&
- !O.matches(options::OPT_fdiagnostics_color) &&
- !O.matches(options::OPT_fno_color_diagnostics) &&
- !O.matches(options::OPT_fno_diagnostics_color) &&
- !O.matches(options::OPT_fdiagnostics_color_EQ))
- continue;
- if (O.matches(options::OPT_fdiagnostics_color_EQ)) {
- StringRef Value(A->getValue());
- if (Value != "always" && Value != "never" && Value != "auto")
- getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported)
- << ("-fdiagnostics-color=" + Value).str();
- }
- A->claim();
- }
- if (D.getDiags().getDiagnosticOptions().ShowColors)
- CmdArgs.push_back("-fcolor-diagnostics");
-
- if (Args.hasArg(options::OPT_fansi_escape_codes))
- CmdArgs.push_back("-fansi-escape-codes");
-
- if (!Args.hasFlag(options::OPT_fshow_source_location,
- options::OPT_fno_show_source_location))
- CmdArgs.push_back("-fno-show-source-location");
-
- if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths))
- CmdArgs.push_back("-fdiagnostics-absolute-paths");
-
- if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column,
- true))
- CmdArgs.push_back("-fno-show-column");
-
- if (!Args.hasFlag(options::OPT_fspell_checking,
- options::OPT_fno_spell_checking))
- CmdArgs.push_back("-fno-spell-checking");
-
- // -fno-asm-blocks is default.
- if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
- false))
- CmdArgs.push_back("-fasm-blocks");
-
- // -fgnu-inline-asm is default.
- if (!Args.hasFlag(options::OPT_fgnu_inline_asm,
- options::OPT_fno_gnu_inline_asm, true))
- CmdArgs.push_back("-fno-gnu-inline-asm");
-
- // Enable vectorization per default according to the optimization level
- // selected. For optimization levels that want vectorization we use the alias
- // option to simplify the hasFlag logic.
- bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false);
- OptSpecifier VectorizeAliasOption =
- EnableVec ? options::OPT_O_Group : options::OPT_fvectorize;
- if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption,
- options::OPT_fno_vectorize, EnableVec))
- CmdArgs.push_back("-vectorize-loops");
-
- // -fslp-vectorize is enabled based on the optimization level selected.
- bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true);
- OptSpecifier SLPVectAliasOption =
- EnableSLPVec ? options::OPT_O_Group : options::OPT_fslp_vectorize;
- if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption,
- options::OPT_fno_slp_vectorize, EnableSLPVec))
- CmdArgs.push_back("-vectorize-slp");
-
- // -fno-slp-vectorize-aggressive is default.
- if (Args.hasFlag(options::OPT_fslp_vectorize_aggressive,
- options::OPT_fno_slp_vectorize_aggressive, false))
- CmdArgs.push_back("-vectorize-slp-aggressive");
-
- if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ))
- A->render(Args, CmdArgs);
-
- if (Arg *A = Args.getLastArg(
- options::OPT_fsanitize_undefined_strip_path_components_EQ))
- A->render(Args, CmdArgs);
-
- // -fdollars-in-identifiers default varies depending on platform and
- // language; only pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers,
- options::OPT_fno_dollars_in_identifiers)) {
- if (A->getOption().matches(options::OPT_fdollars_in_identifiers))
- CmdArgs.push_back("-fdollars-in-identifiers");
- else
- CmdArgs.push_back("-fno-dollars-in-identifiers");
- }
-
- // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for
- // practical purposes.
- if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time,
- options::OPT_fno_unit_at_a_time)) {
- if (A->getOption().matches(options::OPT_fno_unit_at_a_time))
- D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
- }
-
- if (Args.hasFlag(options::OPT_fapple_pragma_pack,
- options::OPT_fno_apple_pragma_pack, false))
- CmdArgs.push_back("-fapple-pragma-pack");
-
- // le32-specific flags:
- // -fno-math-builtin: clang should not convert math builtins to intrinsics
- // by default.
- if (getToolChain().getArch() == llvm::Triple::le32) {
- CmdArgs.push_back("-fno-math-builtin");
- }
-
- if (Args.hasFlag(options::OPT_fsave_optimization_record,
- options::OPT_fno_save_optimization_record, false)) {
- CmdArgs.push_back("-opt-record-file");
-
- const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ);
- if (A) {
- CmdArgs.push_back(A->getValue());
- } else {
- SmallString<128> F;
- if (Output.isFilename() && (Args.hasArg(options::OPT_c) ||
- Args.hasArg(options::OPT_S))) {
- F = Output.getFilename();
- } else {
- // Use the input filename.
- F = llvm::sys::path::stem(Input.getBaseInput());
-
- // If we're compiling for an offload architecture (i.e. a CUDA device),
- // we need to make the file name for the device compilation different
- // from the host compilation.
- if (!JA.isDeviceOffloading(Action::OFK_None) &&
- !JA.isDeviceOffloading(Action::OFK_Host)) {
- llvm::sys::path::replace_extension(F, "");
- F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(),
- Triple.normalize());
- F += "-";
- F += JA.getOffloadingArch();
- }
- }
-
- llvm::sys::path::replace_extension(F, "opt.yaml");
- CmdArgs.push_back(Args.MakeArgString(F));
- }
- }
-
-// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM.
-//
-// FIXME: Now that PR4941 has been fixed this can be enabled.
-#if 0
- if (getToolChain().getTriple().isOSDarwin() &&
- (getToolChain().getArch() == llvm::Triple::arm ||
- getToolChain().getArch() == llvm::Triple::thumb)) {
- if (!Args.hasArg(options::OPT_fbuiltin_strcat))
- CmdArgs.push_back("-fno-builtin-strcat");
- if (!Args.hasArg(options::OPT_fbuiltin_strcpy))
- CmdArgs.push_back("-fno-builtin-strcpy");
- }
-#endif
-
- // Enable rewrite includes if the user's asked for it or if we're generating
- // diagnostics.
- // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be
- // nice to enable this when doing a crashdump for modules as well.
- if (Args.hasFlag(options::OPT_frewrite_includes,
- options::OPT_fno_rewrite_includes, false) ||
- (C.isForDiagnostics() && !HaveAnyModules))
- CmdArgs.push_back("-frewrite-includes");
-
- // Only allow -traditional or -traditional-cpp outside in preprocessing modes.
- if (Arg *A = Args.getLastArg(options::OPT_traditional,
- options::OPT_traditional_cpp)) {
- if (isa<PreprocessJobAction>(JA))
- CmdArgs.push_back("-traditional-cpp");
- else
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_dM);
- Args.AddLastArg(CmdArgs, options::OPT_dD);
-
- // Handle serialized diagnostics.
- if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
- CmdArgs.push_back("-serialize-diagnostic-file");
- CmdArgs.push_back(Args.MakeArgString(A->getValue()));
- }
-
- if (Args.hasArg(options::OPT_fretain_comments_from_system_headers))
- CmdArgs.push_back("-fretain-comments-from-system-headers");
-
- // Forward -fcomment-block-commands to -cc1.
- Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands);
- // Forward -fparse-all-comments to -cc1.
- Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments);
-
- // Turn -fplugin=name.so into -load name.so
- for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) {
- CmdArgs.push_back("-load");
- CmdArgs.push_back(A->getValue());
- A->claim();
- }
-
- // Setup statistics file output.
- if (const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ)) {
- StringRef SaveStats = A->getValue();
-
- SmallString<128> StatsFile;
- bool DoSaveStats = false;
- if (SaveStats == "obj") {
- if (Output.isFilename()) {
- StatsFile.assign(Output.getFilename());
- llvm::sys::path::remove_filename(StatsFile);
- }
- DoSaveStats = true;
- } else if (SaveStats == "cwd") {
- DoSaveStats = true;
- } else {
- D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats;
- }
-
- if (DoSaveStats) {
- StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput());
- llvm::sys::path::append(StatsFile, BaseName);
- llvm::sys::path::replace_extension(StatsFile, "stats");
- CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") +
- StatsFile));
- }
- }
-
- // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
- // parser.
- Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
- for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
- A->claim();
-
- // We translate this by hand to the -cc1 argument, since nightly test uses
- // it and developers have been trained to spell it with -mllvm. Both
- // spellings are now deprecated and should be removed.
- if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") {
- CmdArgs.push_back("-disable-llvm-optzns");
- } else {
- A->render(Args, CmdArgs);
- }
- }
-
- // With -save-temps, we want to save the unoptimized bitcode output from the
- // CompileJobAction, use -disable-llvm-passes to get pristine IR generated
- // by the frontend.
- // When -fembed-bitcode is enabled, optimized bitcode is emitted because it
- // has slightly different breakdown between stages.
- // FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of
- // pristine IR generated by the frontend. Ideally, a new compile action should
- // be added so both IR can be captured.
- if (C.getDriver().isSaveTempsEnabled() &&
- !C.getDriver().embedBitcodeInObject() && isa<CompileJobAction>(JA))
- CmdArgs.push_back("-disable-llvm-passes");
-
- if (Output.getType() == types::TY_Dependencies) {
- // Handled with other dependency code.
- } else if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- addDashXForInput(Args, Input, CmdArgs);
-
- if (Input.isFilename())
- CmdArgs.push_back(Input.getFilename());
- else
- Input.getInputArg().renderAsInput(Args, CmdArgs);
-
- Args.AddAllArgs(CmdArgs, options::OPT_undef);
-
- const char *Exec = getToolChain().getDriver().getClangProgramPath();
-
- // Optionally embed the -cc1 level arguments into the debug info, for build
- // analysis.
- if (getToolChain().UseDwarfDebugFlags()) {
- ArgStringList OriginalArgs;
- for (const auto &Arg : Args)
- Arg->render(Args, OriginalArgs);
-
- SmallString<256> Flags;
- Flags += Exec;
- for (const char *OriginalArg : OriginalArgs) {
- SmallString<128> EscapedArg;
- EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
- Flags += " ";
- Flags += EscapedArg;
- }
- CmdArgs.push_back("-dwarf-debug-flags");
- CmdArgs.push_back(Args.MakeArgString(Flags));
- }
-
- // Add the split debug info name to the command lines here so we
- // can propagate it to the backend.
- bool SplitDwarf = SplitDwarfArg && getToolChain().getTriple().isOSLinux() &&
- (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
- isa<BackendJobAction>(JA));
- const char *SplitDwarfOut;
- if (SplitDwarf) {
- CmdArgs.push_back("-split-dwarf-file");
- SplitDwarfOut = SplitDebugName(Args, Input);
- CmdArgs.push_back(SplitDwarfOut);
- }
-
- // Host-side cuda compilation receives device-side outputs as Inputs[1...].
- // Include them with -fcuda-include-gpubinary.
- if (IsCuda && Inputs.size() > 1)
- for (auto I = std::next(Inputs.begin()), E = Inputs.end(); I != E; ++I) {
- CmdArgs.push_back("-fcuda-include-gpubinary");
- CmdArgs.push_back(I->getFilename());
- }
-
- // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path
- // to specify the result of the compile phase on the host, so the meaningful
- // device declarations can be identified. Also, -fopenmp-is-device is passed
- // along to tell the frontend that it is generating code for a device, so that
- // only the relevant declarations are emitted.
- if (IsOpenMPDevice && Inputs.size() == 2) {
- CmdArgs.push_back("-fopenmp-is-device");
- CmdArgs.push_back("-fopenmp-host-ir-file-path");
- CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename()));
- }
-
- // For all the host OpenMP offloading compile jobs we need to pass the targets
- // information using -fopenmp-targets= option.
- if (isa<CompileJobAction>(JA) && JA.isHostOffloading(Action::OFK_OpenMP)) {
- SmallString<128> TargetInfo("-fopenmp-targets=");
-
- Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ);
- assert(Tgts && Tgts->getNumValues() &&
- "OpenMP offloading has to have targets specified.");
- for (unsigned i = 0; i < Tgts->getNumValues(); ++i) {
- if (i)
- TargetInfo += ',';
- // We need to get the string from the triple because it may be not exactly
- // the same as the one we get directly from the arguments.
- llvm::Triple T(Tgts->getValue(i));
- TargetInfo += T.getTriple();
- }
- CmdArgs.push_back(Args.MakeArgString(TargetInfo.str()));
- }
-
- bool WholeProgramVTables =
- Args.hasFlag(options::OPT_fwhole_program_vtables,
- options::OPT_fno_whole_program_vtables, false);
- if (WholeProgramVTables) {
- if (!D.isUsingLTO())
- D.Diag(diag::err_drv_argument_only_allowed_with)
- << "-fwhole-program-vtables"
- << "-flto";
- CmdArgs.push_back("-fwhole-program-vtables");
- }
-
- // Finally add the compile command to the compilation.
- if (Args.hasArg(options::OPT__SLASH_fallback) &&
- Output.getType() == types::TY_Object &&
- (InputType == types::TY_C || InputType == types::TY_CXX)) {
- auto CLCommand =
- getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput);
- C.addCommand(llvm::make_unique<FallbackCommand>(
- JA, *this, Exec, CmdArgs, Inputs, std::move(CLCommand)));
- } else if (Args.hasArg(options::OPT__SLASH_fallback) &&
- isa<PrecompileJobAction>(JA)) {
- // In /fallback builds, run the main compilation even if the pch generation
- // fails, so that the main compilation's fallback to cl.exe runs.
- C.addCommand(llvm::make_unique<ForceSuccessCommand>(JA, *this, Exec,
- CmdArgs, Inputs));
- } else {
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
- }
-
- // Handle the debug info splitting at object creation time if we're
- // creating an object.
- // TODO: Currently only works on linux with newer objcopy.
- if (SplitDwarf && Output.getType() == types::TY_Object)
- SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut);
-
- if (Arg *A = Args.getLastArg(options::OPT_pg))
- if (Args.hasArg(options::OPT_fomit_frame_pointer))
- D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer"
- << A->getAsString(Args);
-
- // Claim some arguments which clang supports automatically.
-
- // -fpch-preprocess is used with gcc to add a special marker in the output to
- // include the PCH file. Clang's PTH solution is completely transparent, so we
- // do not need to deal with it at all.
- Args.ClaimAllArgs(options::OPT_fpch_preprocess);
-
- // Claim some arguments which clang doesn't support, but we don't
- // care to warn the user about.
- Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group);
- Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);
-
- // Disable warnings for clang -E -emit-llvm foo.c
- Args.ClaimAllArgs(options::OPT_emit_llvm);
-}
-
-/// Add options related to the Objective-C runtime/ABI.
-///
-/// Returns true if the runtime is non-fragile.
-ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
- ArgStringList &cmdArgs,
- RewriteKind rewriteKind) const {
- // Look for the controlling runtime option.
- Arg *runtimeArg =
- args.getLastArg(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
- options::OPT_fobjc_runtime_EQ);
-
- // Just forward -fobjc-runtime= to the frontend. This supercedes
- // options about fragility.
- if (runtimeArg &&
- runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) {
- ObjCRuntime runtime;
- StringRef value = runtimeArg->getValue();
- if (runtime.tryParse(value)) {
- getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime)
- << value;
- }
-
- runtimeArg->render(args, cmdArgs);
- return runtime;
- }
-
- // Otherwise, we'll need the ABI "version". Version numbers are
- // slightly confusing for historical reasons:
- // 1 - Traditional "fragile" ABI
- // 2 - Non-fragile ABI, version 1
- // 3 - Non-fragile ABI, version 2
- unsigned objcABIVersion = 1;
- // If -fobjc-abi-version= is present, use that to set the version.
- if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
- StringRef value = abiArg->getValue();
- if (value == "1")
- objcABIVersion = 1;
- else if (value == "2")
- objcABIVersion = 2;
- else if (value == "3")
- objcABIVersion = 3;
- else
- getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) << value;
- } else {
- // Otherwise, determine if we are using the non-fragile ABI.
- bool nonFragileABIIsDefault =
- (rewriteKind == RK_NonFragile ||
- (rewriteKind == RK_None &&
- getToolChain().IsObjCNonFragileABIDefault()));
- if (args.hasFlag(options::OPT_fobjc_nonfragile_abi,
- options::OPT_fno_objc_nonfragile_abi,
- nonFragileABIIsDefault)) {
-// Determine the non-fragile ABI version to use.
-#ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO
- unsigned nonFragileABIVersion = 1;
-#else
- unsigned nonFragileABIVersion = 2;
-#endif
-
- if (Arg *abiArg =
- args.getLastArg(options::OPT_fobjc_nonfragile_abi_version_EQ)) {
- StringRef value = abiArg->getValue();
- if (value == "1")
- nonFragileABIVersion = 1;
- else if (value == "2")
- nonFragileABIVersion = 2;
- else
- getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported)
- << value;
- }
-
- objcABIVersion = 1 + nonFragileABIVersion;
- } else {
- objcABIVersion = 1;
- }
- }
-
- // We don't actually care about the ABI version other than whether
- // it's non-fragile.
- bool isNonFragile = objcABIVersion != 1;
-
- // If we have no runtime argument, ask the toolchain for its default runtime.
- // However, the rewriter only really supports the Mac runtime, so assume that.
- ObjCRuntime runtime;
- if (!runtimeArg) {
- switch (rewriteKind) {
- case RK_None:
- runtime = getToolChain().getDefaultObjCRuntime(isNonFragile);
- break;
- case RK_Fragile:
- runtime = ObjCRuntime(ObjCRuntime::FragileMacOSX, VersionTuple());
- break;
- case RK_NonFragile:
- runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple());
- break;
- }
-
- // -fnext-runtime
- } else if (runtimeArg->getOption().matches(options::OPT_fnext_runtime)) {
- // On Darwin, make this use the default behavior for the toolchain.
- if (getToolChain().getTriple().isOSDarwin()) {
- runtime = getToolChain().getDefaultObjCRuntime(isNonFragile);
-
- // Otherwise, build for a generic macosx port.
- } else {
- runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple());
- }
-
- // -fgnu-runtime
- } else {
- assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime));
- // Legacy behaviour is to target the gnustep runtime if we are in
- // non-fragile mode or the GCC runtime in fragile mode.
- if (isNonFragile)
- runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1, 6));
- else
- runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple());
- }
-
- cmdArgs.push_back(
- args.MakeArgString("-fobjc-runtime=" + runtime.getAsString()));
- return runtime;
-}
-
-static bool maybeConsumeDash(const std::string &EH, size_t &I) {
- bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-');
- I += HaveDash;
- return !HaveDash;
-}
-
-namespace {
-struct EHFlags {
- bool Synch = false;
- bool Asynch = false;
- bool NoUnwindC = false;
-};
-} // end anonymous namespace
-
-/// /EH controls whether to run destructor cleanups when exceptions are
-/// thrown. There are three modifiers:
-/// - s: Cleanup after "synchronous" exceptions, aka C++ exceptions.
-/// - a: Cleanup after "asynchronous" exceptions, aka structured exceptions.
-/// The 'a' modifier is unimplemented and fundamentally hard in LLVM IR.
-/// - c: Assume that extern "C" functions are implicitly nounwind.
-/// The default is /EHs-c-, meaning cleanups are disabled.
-static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
- EHFlags EH;
-
- std::vector<std::string> EHArgs =
- Args.getAllArgValues(options::OPT__SLASH_EH);
- for (auto EHVal : EHArgs) {
- for (size_t I = 0, E = EHVal.size(); I != E; ++I) {
- switch (EHVal[I]) {
- case 'a':
- EH.Asynch = maybeConsumeDash(EHVal, I);
- if (EH.Asynch)
- EH.Synch = false;
- continue;
- case 'c':
- EH.NoUnwindC = maybeConsumeDash(EHVal, I);
- continue;
- case 's':
- EH.Synch = maybeConsumeDash(EHVal, I);
- if (EH.Synch)
- EH.Asynch = false;
- continue;
- default:
- break;
- }
- D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal;
- break;
- }
- }
- // The /GX, /GX- flags are only processed if there are not /EH flags.
- // The default is that /GX is not specified.
- if (EHArgs.empty() &&
- Args.hasFlag(options::OPT__SLASH_GX, options::OPT__SLASH_GX_,
- /*default=*/false)) {
- EH.Synch = true;
- EH.NoUnwindC = true;
- }
-
- return EH;
-}
-
-void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
- ArgStringList &CmdArgs,
- codegenoptions::DebugInfoKind *DebugInfoKind,
- bool *EmitCodeView) const {
- unsigned RTOptionID = options::OPT__SLASH_MT;
-
- if (Args.hasArg(options::OPT__SLASH_LDd))
- // The /LDd option implies /MTd. The dependent lib part can be overridden,
- // but defining _DEBUG is sticky.
- RTOptionID = options::OPT__SLASH_MTd;
-
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group))
- RTOptionID = A->getOption().getID();
-
- StringRef FlagForCRT;
- switch (RTOptionID) {
- case options::OPT__SLASH_MD:
- if (Args.hasArg(options::OPT__SLASH_LDd))
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-D_DLL");
- FlagForCRT = "--dependent-lib=msvcrt";
- break;
- case options::OPT__SLASH_MDd:
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-D_DLL");
- FlagForCRT = "--dependent-lib=msvcrtd";
- break;
- case options::OPT__SLASH_MT:
- if (Args.hasArg(options::OPT__SLASH_LDd))
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-flto-visibility-public-std");
- FlagForCRT = "--dependent-lib=libcmt";
- break;
- case options::OPT__SLASH_MTd:
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-flto-visibility-public-std");
- FlagForCRT = "--dependent-lib=libcmtd";
- break;
- default:
- llvm_unreachable("Unexpected option ID.");
- }
-
- if (Args.hasArg(options::OPT__SLASH_Zl)) {
- CmdArgs.push_back("-D_VC_NODEFAULTLIB");
- } else {
- CmdArgs.push_back(FlagForCRT.data());
-
- // This provides POSIX compatibility (maps 'open' to '_open'), which most
- // users want. The /Za flag to cl.exe turns this off, but it's not
- // implemented in clang.
- CmdArgs.push_back("--dependent-lib=oldnames");
- }
-
- // Both /showIncludes and /E (and /EP) write to stdout. Allowing both
- // would produce interleaved output, so ignore /showIncludes in such cases.
- if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP))
- if (Arg *A = Args.getLastArg(options::OPT_show_includes))
- A->render(Args, CmdArgs);
-
- // This controls whether or not we emit RTTI data for polymorphic types.
- if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR,
- /*default=*/false))
- CmdArgs.push_back("-fno-rtti-data");
-
- // This controls whether or not we emit stack-protector instrumentation.
- // In MSVC, Buffer Security Check (/GS) is on by default.
- if (Args.hasFlag(options::OPT__SLASH_GS, options::OPT__SLASH_GS_,
- /*default=*/true)) {
- CmdArgs.push_back("-stack-protector");
- CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong)));
- }
-
- // Emit CodeView if -Z7, -Zd, or -gline-tables-only are present.
- if (Arg *DebugInfoArg =
- Args.getLastArg(options::OPT__SLASH_Z7, options::OPT__SLASH_Zd,
- options::OPT_gline_tables_only)) {
- *EmitCodeView = true;
- if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7))
- *DebugInfoKind = codegenoptions::LimitedDebugInfo;
- else
- *DebugInfoKind = codegenoptions::DebugLineTablesOnly;
- CmdArgs.push_back("-gcodeview");
- } else {
- *EmitCodeView = false;
- }
-
- const Driver &D = getToolChain().getDriver();
- EHFlags EH = parseClangCLEHFlags(D, Args);
- if (EH.Synch || EH.Asynch) {
- if (types::isCXX(InputType))
- CmdArgs.push_back("-fcxx-exceptions");
- CmdArgs.push_back("-fexceptions");
- }
- if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC)
- CmdArgs.push_back("-fexternc-nounwind");
-
- // /EP should expand to -E -P.
- if (Args.hasArg(options::OPT__SLASH_EP)) {
- CmdArgs.push_back("-E");
- CmdArgs.push_back("-P");
- }
-
- unsigned VolatileOptionID;
- if (getToolChain().getArch() == llvm::Triple::x86_64 ||
- getToolChain().getArch() == llvm::Triple::x86)
- VolatileOptionID = options::OPT__SLASH_volatile_ms;
- else
- VolatileOptionID = options::OPT__SLASH_volatile_iso;
-
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group))
- VolatileOptionID = A->getOption().getID();
-
- if (VolatileOptionID == options::OPT__SLASH_volatile_ms)
- CmdArgs.push_back("-fms-volatile");
-
- Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg);
- Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb);
- if (MostGeneralArg && BestCaseArg)
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << MostGeneralArg->getAsString(Args) << BestCaseArg->getAsString(Args);
-
- if (MostGeneralArg) {
- Arg *SingleArg = Args.getLastArg(options::OPT__SLASH_vms);
- Arg *MultipleArg = Args.getLastArg(options::OPT__SLASH_vmm);
- Arg *VirtualArg = Args.getLastArg(options::OPT__SLASH_vmv);
-
- Arg *FirstConflict = SingleArg ? SingleArg : MultipleArg;
- Arg *SecondConflict = VirtualArg ? VirtualArg : MultipleArg;
- if (FirstConflict && SecondConflict && FirstConflict != SecondConflict)
- D.Diag(clang::diag::err_drv_argument_not_allowed_with)
- << FirstConflict->getAsString(Args)
- << SecondConflict->getAsString(Args);
-
- if (SingleArg)
- CmdArgs.push_back("-fms-memptr-rep=single");
- else if (MultipleArg)
- CmdArgs.push_back("-fms-memptr-rep=multiple");
- else
- CmdArgs.push_back("-fms-memptr-rep=virtual");
- }
-
- if (Args.getLastArg(options::OPT__SLASH_Gd))
- CmdArgs.push_back("-fdefault-calling-conv=cdecl");
- else if (Args.getLastArg(options::OPT__SLASH_Gr))
- CmdArgs.push_back("-fdefault-calling-conv=fastcall");
- else if (Args.getLastArg(options::OPT__SLASH_Gz))
- CmdArgs.push_back("-fdefault-calling-conv=stdcall");
- else if (Args.getLastArg(options::OPT__SLASH_Gv))
- CmdArgs.push_back("-fdefault-calling-conv=vectorcall");
-
- if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ))
- A->render(Args, CmdArgs);
-
- if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) {
- CmdArgs.push_back("-fdiagnostics-format");
- if (Args.hasArg(options::OPT__SLASH_fallback))
- CmdArgs.push_back("msvc-fallback");
- else
- CmdArgs.push_back("msvc");
- }
-}
-
-visualstudio::Compiler *Clang::getCLFallback() const {
- if (!CLFallback)
- CLFallback.reset(new visualstudio::Compiler(getToolChain()));
- return CLFallback.get();
-}
-
-void ClangAs::AddMIPSTargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- StringRef CPUName;
- StringRef ABIName;
- const llvm::Triple &Triple = getToolChain().getTriple();
- mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
-
- CmdArgs.push_back("-target-abi");
- CmdArgs.push_back(ABIName.data());
-}
-
-void ClangAs::AddX86TargetArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
- StringRef Value = A->getValue();
- if (Value == "intel" || Value == "att") {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
- } else {
- getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
- }
- }
-}
-
-void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- assert(Inputs.size() == 1 && "Unexpected number of inputs.");
- const InputInfo &Input = Inputs[0];
-
- const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
- const std::string &TripleStr = Triple.getTriple();
-
- // Don't warn about "clang -w -c foo.s"
- Args.ClaimAllArgs(options::OPT_w);
- // and "clang -emit-llvm -c foo.s"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
-
- claimNoWarnArgs(Args);
-
- // Invoke ourselves in -cc1as mode.
- //
- // FIXME: Implement custom jobs for internal actions.
- CmdArgs.push_back("-cc1as");
-
- // Add the "effective" target triple.
- CmdArgs.push_back("-triple");
- CmdArgs.push_back(Args.MakeArgString(TripleStr));
-
- // Set the output mode, we currently only expect to be used as a real
- // assembler.
- CmdArgs.push_back("-filetype");
- CmdArgs.push_back("obj");
-
- // Set the main file name, so that debug info works even with
- // -save-temps or preprocessed assembly.
- CmdArgs.push_back("-main-file-name");
- CmdArgs.push_back(Clang::getBaseInputName(Args, Input));
-
- // Add the target cpu
- std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true);
- if (!CPU.empty()) {
- CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString(CPU));
- }
-
- // Add the target features
- getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, true);
-
- // Ignore explicit -force_cpusubtype_ALL option.
- (void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
-
- // Pass along any -I options so we get proper .include search paths.
- Args.AddAllArgs(CmdArgs, options::OPT_I_Group);
-
- // Determine the original source input.
- const Action *SourceAction = &JA;
- while (SourceAction->getKind() != Action::InputClass) {
- assert(!SourceAction->getInputs().empty() && "unexpected root action!");
- SourceAction = SourceAction->getInputs()[0];
- }
-
- // Forward -g and handle debug info related flags, assuming we are dealing
- // with an actual assembly file.
- bool WantDebug = false;
- unsigned DwarfVersion = 0;
- Args.ClaimAllArgs(options::OPT_g_Group);
- if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- WantDebug = !A->getOption().matches(options::OPT_g0) &&
- !A->getOption().matches(options::OPT_ggdb0);
- if (WantDebug)
- DwarfVersion = DwarfVersionNum(A->getSpelling());
- }
- if (DwarfVersion == 0)
- DwarfVersion = getToolChain().GetDefaultDwarfVersion();
-
- codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
-
- if (SourceAction->getType() == types::TY_Asm ||
- SourceAction->getType() == types::TY_PP_Asm) {
- // You might think that it would be ok to set DebugInfoKind outside of
- // the guard for source type, however there is a test which asserts
- // that some assembler invocation receives no -debug-info-kind,
- // and it's not clear whether that test is just overly restrictive.
- DebugInfoKind = (WantDebug ? codegenoptions::LimitedDebugInfo
- : codegenoptions::NoDebugInfo);
- // Add the -fdebug-compilation-dir flag if needed.
- addDebugCompDirArg(Args, CmdArgs);
-
- // Set the AT_producer to the clang version when using the integrated
- // assembler on assembly source files.
- CmdArgs.push_back("-dwarf-debug-producer");
- CmdArgs.push_back(Args.MakeArgString(getClangFullVersion()));
-
- // And pass along -I options
- Args.AddAllArgs(CmdArgs, options::OPT_I);
- }
- RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
- llvm::DebuggerKind::Default);
-
- // Handle -fPIC et al -- the relocation-model affects the assembler
- // for some targets.
- llvm::Reloc::Model RelocationModel;
- unsigned PICLevel;
- bool IsPIE;
- std::tie(RelocationModel, PICLevel, IsPIE) =
- ParsePICArgs(getToolChain(), Args);
-
- const char *RMName = RelocationModelName(RelocationModel);
- if (RMName) {
- CmdArgs.push_back("-mrelocation-model");
- CmdArgs.push_back(RMName);
- }
-
- // Optionally embed the -cc1as level arguments into the debug info, for build
- // analysis.
- if (getToolChain().UseDwarfDebugFlags()) {
- ArgStringList OriginalArgs;
- for (const auto &Arg : Args)
- Arg->render(Args, OriginalArgs);
-
- SmallString<256> Flags;
- const char *Exec = getToolChain().getDriver().getClangProgramPath();
- Flags += Exec;
- for (const char *OriginalArg : OriginalArgs) {
- SmallString<128> EscapedArg;
- EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
- Flags += " ";
- Flags += EscapedArg;
- }
- CmdArgs.push_back("-dwarf-debug-flags");
- CmdArgs.push_back(Args.MakeArgString(Flags));
- }
-
- // FIXME: Add -static support, once we have it.
-
- // Add target specific flags.
- switch (getToolChain().getArch()) {
- default:
- break;
-
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- AddMIPSTargetArgs(Args, CmdArgs);
- break;
-
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- AddX86TargetArgs(Args, CmdArgs);
- break;
- }
-
- // Consume all the warning flags. Usually this would be handled more
- // gracefully by -cc1 (warning about unknown warning flags, etc) but -cc1as
- // doesn't handle that so rather than warning about unused flags that are
- // actually used, we'll lie by omission instead.
- // FIXME: Stop lying and consume only the appropriate driver flags
- Args.ClaimAllArgs(options::OPT_W_Group);
-
- CollectArgsForIntegratedAssembler(C, Args, CmdArgs,
- getToolChain().getDriver());
-
- Args.AddAllArgs(CmdArgs, options::OPT_mllvm);
-
- assert(Output.isFilename() && "Unexpected lipo output.");
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- assert(Input.isFilename() && "Invalid input.");
- CmdArgs.push_back(Input.getFilename());
-
- const char *Exec = getToolChain().getDriver().getClangProgramPath();
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-
- // Handle the debug info splitting at object creation time if we're
- // creating an object.
- // TODO: Currently only works on linux with newer objcopy.
- if (Args.hasArg(options::OPT_gsplit_dwarf) &&
- getToolChain().getTriple().isOSLinux())
- SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
- SplitDebugName(Args, Input));
-}
-
-void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const {
- // The version with only one output is expected to refer to a bundling job.
- assert(isa<OffloadBundlingJobAction>(JA) && "Expecting bundling job!");
-
- // The bundling command looks like this:
- // clang-offload-bundler -type=bc
- // -targets=host-triple,openmp-triple1,openmp-triple2
- // -outputs=input_file
- // -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2"
-
- ArgStringList CmdArgs;
-
- // Get the type.
- CmdArgs.push_back(TCArgs.MakeArgString(
- Twine("-type=") + types::getTypeTempSuffix(Output.getType())));
-
- assert(JA.getInputs().size() == Inputs.size() &&
- "Not have inputs for all dependence actions??");
-
- // Get the targets.
- SmallString<128> Triples;
- Triples += "-targets=";
- for (unsigned I = 0; I < Inputs.size(); ++I) {
- if (I)
- Triples += ',';
-
- Action::OffloadKind CurKind = Action::OFK_Host;
- const ToolChain *CurTC = &getToolChain();
- const Action *CurDep = JA.getInputs()[I];
-
- if (const auto *OA = dyn_cast<OffloadAction>(CurDep)) {
- OA->doOnEachDependence([&](Action *A, const ToolChain *TC, const char *) {
- CurKind = A->getOffloadingDeviceKind();
- CurTC = TC;
- });
- }
- Triples += Action::GetOffloadKindName(CurKind);
- Triples += '-';
- Triples += CurTC->getTriple().normalize();
- }
- CmdArgs.push_back(TCArgs.MakeArgString(Triples));
-
- // Get bundled file command.
- CmdArgs.push_back(
- TCArgs.MakeArgString(Twine("-outputs=") + Output.getFilename()));
-
- // Get unbundled files command.
- SmallString<128> UB;
- UB += "-inputs=";
- for (unsigned I = 0; I < Inputs.size(); ++I) {
- if (I)
- UB += ',';
- UB += Inputs[I].getFilename();
- }
- CmdArgs.push_back(TCArgs.MakeArgString(UB));
-
- // All the inputs are encoded as commands.
- C.addCommand(llvm::make_unique<Command>(
- JA, *this,
- TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
- CmdArgs, None));
-}
-
-void OffloadBundler::ConstructJobMultipleOutputs(
- Compilation &C, const JobAction &JA, const InputInfoList &Outputs,
- const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const {
- // The version with multiple outputs is expected to refer to a unbundling job.
- auto &UA = cast<OffloadUnbundlingJobAction>(JA);
-
- // The unbundling command looks like this:
- // clang-offload-bundler -type=bc
- // -targets=host-triple,openmp-triple1,openmp-triple2
- // -inputs=input_file
- // -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2"
- // -unbundle
-
- ArgStringList CmdArgs;
-
- assert(Inputs.size() == 1 && "Expecting to unbundle a single file!");
- InputInfo Input = Inputs.front();
-
- // Get the type.
- CmdArgs.push_back(TCArgs.MakeArgString(
- Twine("-type=") + types::getTypeTempSuffix(Input.getType())));
-
- // Get the targets.
- SmallString<128> Triples;
- Triples += "-targets=";
- auto DepInfo = UA.getDependentActionsInfo();
- for (unsigned I = 0; I < DepInfo.size(); ++I) {
- if (I)
- Triples += ',';
-
- auto &Dep = DepInfo[I];
- Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind);
- Triples += '-';
- Triples += Dep.DependentToolChain->getTriple().normalize();
- }
-
- CmdArgs.push_back(TCArgs.MakeArgString(Triples));
-
- // Get bundled file command.
- CmdArgs.push_back(
- TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename()));
-
- // Get unbundled files command.
- SmallString<128> UB;
- UB += "-outputs=";
- for (unsigned I = 0; I < Outputs.size(); ++I) {
- if (I)
- UB += ',';
- UB += Outputs[I].getFilename();
- }
- CmdArgs.push_back(TCArgs.MakeArgString(UB));
- CmdArgs.push_back("-unbundle");
-
- // All the inputs are encoded as commands.
- C.addCommand(llvm::make_unique<Command>(
- JA, *this,
- TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
- CmdArgs, None));
-}
-
-void GnuTool::anchor() {}
-
-void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs, const ArgList &Args,
- const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- for (const auto &A : Args) {
- if (forwardToGCC(A->getOption())) {
- // It is unfortunate that we have to claim here, as this means
- // we will basically never report anything interesting for
- // platforms using a generic gcc, even if we are just using gcc
- // to get to the assembler.
- A->claim();
-
- // Don't forward any -g arguments to assembly steps.
- if (isa<AssembleJobAction>(JA) &&
- A->getOption().matches(options::OPT_g_Group))
- continue;
-
- // Don't forward any -W arguments to assembly and link steps.
- if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) &&
- A->getOption().matches(options::OPT_W_Group))
- continue;
-
- A->render(Args, CmdArgs);
- }
- }
-
- RenderExtraToolArgs(JA, CmdArgs);
-
- // If using a driver driver, force the arch.
- if (getToolChain().getTriple().isOSDarwin()) {
- CmdArgs.push_back("-arch");
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().getDefaultUniversalArchName()));
- }
-
- // Try to force gcc to match the tool chain we want, if we recognize
- // the arch.
- //
- // FIXME: The triple class should directly provide the information we want
- // here.
- switch (getToolChain().getArch()) {
- default:
- break;
- case llvm::Triple::x86:
- case llvm::Triple::ppc:
- CmdArgs.push_back("-m32");
- break;
- case llvm::Triple::x86_64:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- CmdArgs.push_back("-m64");
- break;
- case llvm::Triple::sparcel:
- CmdArgs.push_back("-EL");
- break;
- }
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Unexpected output");
- CmdArgs.push_back("-fsyntax-only");
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- // Only pass -x if gcc will understand it; otherwise hope gcc
- // understands the suffix correctly. The main use case this would go
- // wrong in is for linker inputs if they happened to have an odd
- // suffix; really the only way to get this to happen is a command
- // like '-x foobar a.c' which will treat a.c like a linker input.
- //
- // FIXME: For the linker case specifically, can we safely convert
- // inputs into '-Wl,' options?
- for (const auto &II : Inputs) {
- // Don't try to pass LLVM or AST inputs to a generic gcc.
- if (types::isLLVMIR(II.getType()))
- D.Diag(diag::err_drv_no_linker_llvm_support)
- << getToolChain().getTripleString();
- else if (II.getType() == types::TY_AST)
- D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString();
- else if (II.getType() == types::TY_ModuleFile)
- D.Diag(diag::err_drv_no_module_support)
- << getToolChain().getTripleString();
-
- if (types::canTypeBeUserSpecified(II.getType())) {
- CmdArgs.push_back("-x");
- CmdArgs.push_back(types::getTypeName(II.getType()));
- }
-
- if (II.isFilename())
- CmdArgs.push_back(II.getFilename());
- else {
- const Arg &A = II.getInputArg();
-
- // Reverse translate some rewritten options.
- if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) {
- CmdArgs.push_back("-lstdc++");
- continue;
- }
-
- // Don't render as input, we need gcc to do the translations.
- A.render(Args, CmdArgs);
- }
- }
-
- const std::string &customGCCName = D.getCCCGenericGCCName();
- const char *GCCName;
- if (!customGCCName.empty())
- GCCName = customGCCName.c_str();
- else if (D.CCCIsCXX()) {
- GCCName = "g++";
- } else
- GCCName = "gcc";
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void gcc::Preprocessor::RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const {
- CmdArgs.push_back("-E");
-}
-
-void gcc::Compiler::RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const {
- const Driver &D = getToolChain().getDriver();
-
- switch (JA.getType()) {
- // If -flto, etc. are present then make sure not to force assembly output.
- case types::TY_LLVM_IR:
- case types::TY_LTO_IR:
- case types::TY_LLVM_BC:
- case types::TY_LTO_BC:
- CmdArgs.push_back("-c");
- break;
- // We assume we've got an "integrated" assembler in that gcc will produce an
- // object file itself.
- case types::TY_Object:
- CmdArgs.push_back("-c");
- break;
- case types::TY_PP_Asm:
- CmdArgs.push_back("-S");
- break;
- case types::TY_Nothing:
- CmdArgs.push_back("-fsyntax-only");
- break;
- default:
- D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType());
- }
-}
-
-void gcc::Linker::RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const {
- // The types are (hopefully) good enough.
-}
-
-// Hexagon tools start.
-void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const {
-}
-
-void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
-
- auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
- const Driver &D = HTC.getDriver();
- ArgStringList CmdArgs;
-
- std::string MArchString = "-march=hexagon";
- CmdArgs.push_back(Args.MakeArgString(MArchString));
-
- RenderExtraToolArgs(JA, CmdArgs);
-
- std::string AsName = "hexagon-llvm-mc";
- std::string MCpuString = "-mcpu=hexagon" +
- toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
- CmdArgs.push_back("-filetype=obj");
- CmdArgs.push_back(Args.MakeArgString(MCpuString));
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Unexpected output");
- CmdArgs.push_back("-fsyntax-only");
- }
-
- if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
- std::string N = llvm::utostr(G.getValue());
- CmdArgs.push_back(Args.MakeArgString(std::string("-gpsize=") + N));
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- // Only pass -x if gcc will understand it; otherwise hope gcc
- // understands the suffix correctly. The main use case this would go
- // wrong in is for linker inputs if they happened to have an odd
- // suffix; really the only way to get this to happen is a command
- // like '-x foobar a.c' which will treat a.c like a linker input.
- //
- // FIXME: For the linker case specifically, can we safely convert
- // inputs into '-Wl,' options?
- for (const auto &II : Inputs) {
- // Don't try to pass LLVM or AST inputs to a generic gcc.
- if (types::isLLVMIR(II.getType()))
- D.Diag(clang::diag::err_drv_no_linker_llvm_support)
- << HTC.getTripleString();
- else if (II.getType() == types::TY_AST)
- D.Diag(clang::diag::err_drv_no_ast_support)
- << HTC.getTripleString();
- else if (II.getType() == types::TY_ModuleFile)
- D.Diag(diag::err_drv_no_module_support)
- << HTC.getTripleString();
-
- if (II.isFilename())
- CmdArgs.push_back(II.getFilename());
- else
- // Don't render as input, we need gcc to do the translations.
- // FIXME: What is this?
- II.getInputArg().render(Args, CmdArgs);
- }
-
- auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str()));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const {
-}
-
-static void
-constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
- const toolchains::HexagonToolChain &HTC,
- const InputInfo &Output, const InputInfoList &Inputs,
- const ArgList &Args, ArgStringList &CmdArgs,
- const char *LinkingOutput) {
-
- const Driver &D = HTC.getDriver();
-
- //----------------------------------------------------------------------------
- //
- //----------------------------------------------------------------------------
- bool IsStatic = Args.hasArg(options::OPT_static);
- bool IsShared = Args.hasArg(options::OPT_shared);
- bool IsPIE = Args.hasArg(options::OPT_pie);
- bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
- bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
- bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
- bool UseG0 = false;
- bool UseShared = IsShared && !IsStatic;
-
- //----------------------------------------------------------------------------
- // Silence warnings for various options
- //----------------------------------------------------------------------------
- Args.ClaimAllArgs(options::OPT_g_Group);
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_static_libgcc);
-
- //----------------------------------------------------------------------------
- //
- //----------------------------------------------------------------------------
- if (Args.hasArg(options::OPT_s))
- CmdArgs.push_back("-s");
-
- if (Args.hasArg(options::OPT_r))
- CmdArgs.push_back("-r");
-
- for (const auto &Opt : HTC.ExtraOpts)
- CmdArgs.push_back(Opt.c_str());
-
- CmdArgs.push_back("-march=hexagon");
- std::string CpuVer =
- toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
- std::string MCpuString = "-mcpu=hexagon" + CpuVer;
- CmdArgs.push_back(Args.MakeArgString(MCpuString));
-
- if (IsShared) {
- CmdArgs.push_back("-shared");
- // The following should be the default, but doing as hexagon-gcc does.
- CmdArgs.push_back("-call_shared");
- }
-
- if (IsStatic)
- CmdArgs.push_back("-static");
-
- if (IsPIE && !IsShared)
- CmdArgs.push_back("-pie");
-
- if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
- std::string N = llvm::utostr(G.getValue());
- CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N));
- UseG0 = G.getValue() == 0;
- }
-
- //----------------------------------------------------------------------------
- //
- //----------------------------------------------------------------------------
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- //----------------------------------------------------------------------------
- // moslib
- //----------------------------------------------------------------------------
- std::vector<std::string> OsLibs;
- bool HasStandalone = false;
-
- for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
- A->claim();
- OsLibs.emplace_back(A->getValue());
- HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
- }
- if (OsLibs.empty()) {
- OsLibs.push_back("standalone");
- HasStandalone = true;
- }
-
- //----------------------------------------------------------------------------
- // Start Files
- //----------------------------------------------------------------------------
- const std::string MCpuSuffix = "/" + CpuVer;
- const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
- const std::string RootDir =
- HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
- const std::string StartSubDir =
- "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
-
- auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
- const char *Name) -> std::string {
- std::string RelName = SubDir + Name;
- std::string P = HTC.GetFilePath(RelName.c_str());
- if (llvm::sys::fs::exists(P))
- return P;
- return RootDir + RelName;
- };
-
- if (IncStdLib && IncStartFiles) {
- if (!IsShared) {
- if (HasStandalone) {
- std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
- CmdArgs.push_back(Args.MakeArgString(Crt0SA));
- }
- std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
- CmdArgs.push_back(Args.MakeArgString(Crt0));
- }
- std::string Init = UseShared
- ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
- : Find(RootDir, StartSubDir, "/init.o");
- CmdArgs.push_back(Args.MakeArgString(Init));
- }
-
- //----------------------------------------------------------------------------
- // Library Search Paths
- //----------------------------------------------------------------------------
- const ToolChain::path_list &LibPaths = HTC.getFilePaths();
- for (const auto &LibPath : LibPaths)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
-
- //----------------------------------------------------------------------------
- //
- //----------------------------------------------------------------------------
- Args.AddAllArgs(CmdArgs,
- {options::OPT_T_Group, options::OPT_e, options::OPT_s,
- options::OPT_t, options::OPT_u_Group});
-
- AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
-
- //----------------------------------------------------------------------------
- // Libraries
- //----------------------------------------------------------------------------
- if (IncStdLib && IncDefLibs) {
- if (D.CCCIsCXX()) {
- HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-lm");
- }
-
- CmdArgs.push_back("--start-group");
-
- if (!IsShared) {
- for (const std::string &Lib : OsLibs)
- CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
- CmdArgs.push_back("-lc");
- }
- CmdArgs.push_back("-lgcc");
-
- CmdArgs.push_back("--end-group");
- }
-
- //----------------------------------------------------------------------------
- // End files
- //----------------------------------------------------------------------------
- if (IncStdLib && IncStartFiles) {
- std::string Fini = UseShared
- ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
- : Find(RootDir, StartSubDir, "/fini.o");
- CmdArgs.push_back(Args.MakeArgString(Fini));
- }
-}
-
-void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
-
- ArgStringList CmdArgs;
- constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
- LinkingOutput);
-
- std::string Linker = HTC.GetProgramPath("hexagon-link");
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
- CmdArgs, Inputs));
-}
-// Hexagon tools end.
-
-void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
-
- std::string Linker = getToolChain().GetProgramPath(getShortName());
- ArgStringList CmdArgs;
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
- CmdArgs.push_back("-shared");
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
- CmdArgs, Inputs));
-}
-// AMDGPU tools end.
-
-wasm::Linker::Linker(const ToolChain &TC)
- : GnuTool("wasm::Linker", "lld", TC) {}
-
-bool wasm::Linker::isLinkJob() const {
- return true;
-}
-
-bool wasm::Linker::hasIntegratedCPP() const {
- return false;
-}
-
-void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
-
- const ToolChain &ToolChain = getToolChain();
- const Driver &D = ToolChain.getDriver();
- const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath());
- ArgStringList CmdArgs;
- CmdArgs.push_back("-flavor");
- CmdArgs.push_back("ld");
-
- // Enable garbage collection of unused input sections by default, since code
- // size is of particular importance. This is significantly facilitated by
- // the enabling of -ffunction-sections and -fdata-sections in
- // Clang::ConstructJob.
- if (areOptimizationsEnabled(Args))
- CmdArgs.push_back("--gc-sections");
-
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- if (Args.hasArg(options::OPT_s))
- CmdArgs.push_back("--strip-all");
- if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-shared");
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("-Bstatic");
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- ToolChain.AddFilePathLibArgs(Args, CmdArgs);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("rcrt1.o")));
- else if (Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));
- else
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
-
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
- }
-
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX())
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
-
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
-
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lcompiler_rt");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- C.addCommand(llvm::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs));
-}
-
-const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) {
- std::string MArch;
- if (!Arch.empty())
- MArch = Arch;
- else
- MArch = Triple.getArchName();
- MArch = StringRef(MArch).split("+").first.lower();
-
- // Handle -march=native.
- if (MArch == "native") {
- std::string CPU = llvm::sys::getHostCPUName();
- if (CPU != "generic") {
- // Translate the native cpu into the architecture suffix for that CPU.
- StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch, Triple);
- // If there is no valid architecture suffix for this CPU we don't know how
- // to handle it, so return no architecture.
- if (Suffix.empty())
- MArch = "";
- else
- MArch = std::string("arm") + Suffix.str();
- }
- }
-
- return MArch;
-}
-
-/// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting.
-StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) {
- std::string MArch = getARMArch(Arch, Triple);
- // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch
- // here means an -march=native that we can't handle, so instead return no CPU.
- if (MArch.empty())
- return StringRef();
-
- // We need to return an empty string here on invalid MArch values as the
- // various places that call this function can't cope with a null result.
- return Triple.getARMCPUForArch(MArch);
-}
-
-/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
-std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch,
- const llvm::Triple &Triple) {
- // FIXME: Warn on inconsistent use of -mcpu and -march.
- // If we have -mcpu=, use that.
- if (!CPU.empty()) {
- std::string MCPU = StringRef(CPU).split("+").first.lower();
- // Handle -mcpu=native.
- if (MCPU == "native")
- return llvm::sys::getHostCPUName();
- else
- return MCPU;
- }
-
- return getARMCPUForMArch(Arch, Triple);
-}
-
-/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
-/// CPU (or Arch, if CPU is generic).
-// FIXME: This is redundant with -mcpu, why does LLVM use this.
-StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch,
- const llvm::Triple &Triple) {
- unsigned ArchKind;
- if (CPU == "generic") {
- std::string ARMArch = tools::arm::getARMArch(Arch, Triple);
- ArchKind = llvm::ARM::parseArch(ARMArch);
- if (ArchKind == llvm::ARM::AK_INVALID)
- // In case of generic Arch, i.e. "arm",
- // extract arch from default cpu of the Triple
- ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch));
- } else {
- // FIXME: horrible hack to get around the fact that Cortex-A7 is only an
- // armv7k triple if it's actually been specified via "-arch armv7k".
- ArchKind = (Arch == "armv7k" || Arch == "thumbv7k")
- ? (unsigned)llvm::ARM::AK_ARMV7K
- : llvm::ARM::parseCPUArch(CPU);
- }
- if (ArchKind == llvm::ARM::AK_INVALID)
- return "";
- return llvm::ARM::getSubArch(ArchKind);
-}
-
-void arm::appendEBLinkFlags(const ArgList &Args, ArgStringList &CmdArgs,
- const llvm::Triple &Triple) {
- if (Args.hasArg(options::OPT_r))
- return;
-
- // ARMv7 (and later) and ARMv6-M do not support BE-32, so instruct the linker
- // to generate BE-8 executables.
- if (getARMSubArchVersionNumber(Triple) >= 7 || isARMMProfile(Triple))
- CmdArgs.push_back("--be8");
-}
-
-mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) {
- // Strictly speaking, mips32r2 and mips64r2 are NanLegacy-only since Nan2008
- // was first introduced in Release 3. However, other compilers have
- // traditionally allowed it for Release 2 so we should do the same.
- return (NanEncoding)llvm::StringSwitch<int>(CPU)
- .Case("mips1", NanLegacy)
- .Case("mips2", NanLegacy)
- .Case("mips3", NanLegacy)
- .Case("mips4", NanLegacy)
- .Case("mips5", NanLegacy)
- .Case("mips32", NanLegacy)
- .Case("mips32r2", NanLegacy | Nan2008)
- .Case("mips32r3", NanLegacy | Nan2008)
- .Case("mips32r5", NanLegacy | Nan2008)
- .Case("mips32r6", Nan2008)
- .Case("mips64", NanLegacy)
- .Case("mips64r2", NanLegacy | Nan2008)
- .Case("mips64r3", NanLegacy | Nan2008)
- .Case("mips64r5", NanLegacy | Nan2008)
- .Case("mips64r6", Nan2008)
- .Default(NanLegacy);
-}
-
-bool mips::hasCompactBranches(StringRef &CPU) {
- // mips32r6 and mips64r6 have compact branches.
- return llvm::StringSwitch<bool>(CPU)
- .Case("mips32r6", true)
- .Case("mips64r6", true)
- .Default(false);
-}
-
-bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) {
- Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
- return A && (A->getValue() == StringRef(Value));
-}
-
-bool mips::isUCLibc(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_m_libc_Group);
- return A && A->getOption().matches(options::OPT_muclibc);
-}
-
-bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) {
- if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ))
- return llvm::StringSwitch<bool>(NaNArg->getValue())
- .Case("2008", true)
- .Case("legacy", false)
- .Default(false);
-
- // NaN2008 is the default for MIPS32r6/MIPS64r6.
- return llvm::StringSwitch<bool>(getCPUName(Args, Triple))
- .Cases("mips32r6", "mips64r6", true)
- .Default(false);
-
- return false;
-}
-
-bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) {
- if (!Triple.isAndroid())
- return false;
-
- // Android MIPS32R6 defaults to FP64A.
- return llvm::StringSwitch<bool>(CPUName)
- .Case("mips32r6", true)
- .Default(false);
-}
-
-bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
- StringRef ABIName, mips::FloatABI FloatABI) {
- if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies &&
- Triple.getVendor() != llvm::Triple::MipsTechnologies &&
- !Triple.isAndroid())
- return false;
-
- if (ABIName != "32")
- return false;
-
- // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is
- // present.
- if (FloatABI == mips::FloatABI::Soft)
- return false;
-
- return llvm::StringSwitch<bool>(CPUName)
- .Cases("mips2", "mips3", "mips4", "mips5", true)
- .Cases("mips32", "mips32r2", "mips32r3", "mips32r5", true)
- .Cases("mips64", "mips64r2", "mips64r3", "mips64r5", true)
- .Default(false);
-}
-
-bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple,
- StringRef CPUName, StringRef ABIName,
- mips::FloatABI FloatABI) {
- bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI);
-
- // FPXX shouldn't be used if -msingle-float is present.
- if (Arg *A = Args.getLastArg(options::OPT_msingle_float,
- options::OPT_mdouble_float))
- if (A->getOption().matches(options::OPT_msingle_float))
- UseFPXX = false;
-
- return UseFPXX;
-}
-
-llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
- // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for
- // archs which Darwin doesn't use.
-
- // The matching this routine does is fairly pointless, since it is neither the
- // complete architecture list, nor a reasonable subset. The problem is that
- // historically the driver driver accepts this and also ties its -march=
- // handling to the architecture name, so we need to be careful before removing
- // support for it.
-
- // This code must be kept in sync with Clang's Darwin specific argument
- // translation.
-
- return llvm::StringSwitch<llvm::Triple::ArchType>(Str)
- .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc)
- .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc)
- .Case("ppc64", llvm::Triple::ppc64)
- .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86)
- .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4",
- llvm::Triple::x86)
- .Cases("x86_64", "x86_64h", llvm::Triple::x86_64)
- // This is derived from the driver driver.
- .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
- .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm)
- .Cases("armv7s", "xscale", llvm::Triple::arm)
- .Case("arm64", llvm::Triple::aarch64)
- .Case("r600", llvm::Triple::r600)
- .Case("amdgcn", llvm::Triple::amdgcn)
- .Case("nvptx", llvm::Triple::nvptx)
- .Case("nvptx64", llvm::Triple::nvptx64)
- .Case("amdil", llvm::Triple::amdil)
- .Case("spir", llvm::Triple::spir)
- .Default(llvm::Triple::UnknownArch);
-}
-
-void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) {
- const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str);
- unsigned ArchKind = llvm::ARM::parseArch(Str);
- T.setArch(Arch);
-
- if (Str == "x86_64h")
- T.setArchName(Str);
- else if (ArchKind == llvm::ARM::AK_ARMV6M ||
- ArchKind == llvm::ARM::AK_ARMV7M ||
- ArchKind == llvm::ARM::AK_ARMV7EM) {
- T.setOS(llvm::Triple::UnknownOS);
- T.setObjectFormat(llvm::Triple::MachO);
- }
-}
-
-const char *Clang::getBaseInputName(const ArgList &Args,
- const InputInfo &Input) {
- return Args.MakeArgString(llvm::sys::path::filename(Input.getBaseInput()));
-}
-
-const char *Clang::getBaseInputStem(const ArgList &Args,
- const InputInfoList &Inputs) {
- const char *Str = getBaseInputName(Args, Inputs[0]);
-
- if (const char *End = strrchr(Str, '.'))
- return Args.MakeArgString(std::string(Str, End));
-
- return Str;
-}
-
-const char *Clang::getDependencyFileName(const ArgList &Args,
- const InputInfoList &Inputs) {
- // FIXME: Think about this more.
- std::string Res;
-
- if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
- std::string Str(OutputOpt->getValue());
- Res = Str.substr(0, Str.rfind('.'));
- } else {
- Res = getBaseInputStem(Args, Inputs);
- }
- return Args.MakeArgString(Res + ".d");
-}
-
-void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const ToolChain &ToolChain = getToolChain();
- const Driver &D = ToolChain.getDriver();
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- // CloudABI only supports static linkage.
- CmdArgs.push_back("-Bstatic");
- CmdArgs.push_back("--no-dynamic-linker");
-
- // Provide PIE linker flags in case PIE is default for the architecture.
- if (ToolChain.isPIEDefault()) {
- CmdArgs.push_back("-pie");
- CmdArgs.push_back("-zrelro");
- }
-
- CmdArgs.push_back("--eh-frame-hdr");
- CmdArgs.push_back("--gc-sections");
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- Args.AddAllArgs(CmdArgs,
- {options::OPT_T_Group, options::OPT_e, options::OPT_s,
- options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
-
- if (D.isUsingLTO())
- AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
-
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX())
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lcompiler_rt");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
-
- const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- assert(Inputs.size() == 1 && "Unexpected number of inputs.");
- const InputInfo &Input = Inputs[0];
-
- // Determine the original source input.
- const Action *SourceAction = &JA;
- while (SourceAction->getKind() != Action::InputClass) {
- assert(!SourceAction->getInputs().empty() && "unexpected root action!");
- SourceAction = SourceAction->getInputs()[0];
- }
-
- // If -fno-integrated-as is used add -Q to the darwin assember driver to make
- // sure it runs its system assembler not clang's integrated assembler.
- // Applicable to darwin11+ and Xcode 4+. darwin<10 lacked integrated-as.
- // FIXME: at run-time detect assembler capabilities or rely on version
- // information forwarded by -target-assembler-version.
- if (Args.hasArg(options::OPT_fno_integrated_as)) {
- const llvm::Triple &T(getToolChain().getTriple());
- if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7)))
- CmdArgs.push_back("-Q");
- }
-
- // Forward -g, assuming we are dealing with an actual assembly file.
- if (SourceAction->getType() == types::TY_Asm ||
- SourceAction->getType() == types::TY_PP_Asm) {
- if (Args.hasArg(options::OPT_gstabs))
- CmdArgs.push_back("--gstabs");
- else if (Args.hasArg(options::OPT_g_Group))
- CmdArgs.push_back("-g");
- }
-
- // Derived from asm spec.
- AddMachOArch(Args, CmdArgs);
-
- // Use -force_cpusubtype_ALL on x86 by default.
- if (getToolChain().getArch() == llvm::Triple::x86 ||
- getToolChain().getArch() == llvm::Triple::x86_64 ||
- Args.hasArg(options::OPT_force__cpusubtype__ALL))
- CmdArgs.push_back("-force_cpusubtype_ALL");
-
- if (getToolChain().getArch() != llvm::Triple::x86_64 &&
- (((Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_fapple_kext)) &&
- getMachOToolChain().isKernelStatic()) ||
- Args.hasArg(options::OPT_static)))
- CmdArgs.push_back("-static");
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- assert(Output.isFilename() && "Unexpected lipo output.");
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- assert(Input.isFilename() && "Invalid input.");
- CmdArgs.push_back(Input.getFilename());
-
- // asm_final spec is empty.
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void darwin::MachOTool::anchor() {}
-
-void darwin::MachOTool::AddMachOArch(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- StringRef ArchName = getMachOToolChain().getMachOArchName(Args);
-
- // Derived from darwin_arch spec.
- CmdArgs.push_back("-arch");
- CmdArgs.push_back(Args.MakeArgString(ArchName));
-
- // FIXME: Is this needed anymore?
- if (ArchName == "arm")
- CmdArgs.push_back("-force_cpusubtype_ALL");
-}
-
-bool darwin::Linker::NeedsTempPath(const InputInfoList &Inputs) const {
- // We only need to generate a temp path for LTO if we aren't compiling object
- // files. When compiling source files, we run 'dsymutil' after linking. We
- // don't run 'dsymutil' when compiling object files.
- for (const auto &Input : Inputs)
- if (Input.getType() != types::TY_Object)
- return true;
-
- return false;
-}
-
-/// \brief Pass -no_deduplicate to ld64 under certain conditions:
-///
-/// - Either -O0 or -O1 is explicitly specified
-/// - No -O option is specified *and* this is a compile+link (implicit -O0)
-///
-/// Also do *not* add -no_deduplicate when no -O option is specified and this
-/// is just a link (we can't imply -O0)
-static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) {
- if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- if (A->getOption().matches(options::OPT_O0))
- return true;
- if (A->getOption().matches(options::OPT_O))
- return llvm::StringSwitch<bool>(A->getValue())
- .Case("1", true)
- .Default(false);
- return false; // OPT_Ofast & OPT_O4
- }
-
- if (!IsLinkerOnlyAction) // Implicit -O0 for compile+linker only.
- return true;
- return false;
-}
-
-void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args,
- ArgStringList &CmdArgs,
- const InputInfoList &Inputs) const {
- const Driver &D = getToolChain().getDriver();
- const toolchains::MachO &MachOTC = getMachOToolChain();
-
- unsigned Version[5] = {0, 0, 0, 0, 0};
- if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
- if (!Driver::GetReleaseVersion(A->getValue(), Version))
- D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args);
- }
-
- // Newer linkers support -demangle. Pass it if supported and not disabled by
- // the user.
- if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
- CmdArgs.push_back("-demangle");
-
- if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137)
- CmdArgs.push_back("-export_dynamic");
-
- // If we are using App Extension restrictions, pass a flag to the linker
- // telling it that the compiled code has been audited.
- if (Args.hasFlag(options::OPT_fapplication_extension,
- options::OPT_fno_application_extension, false))
- CmdArgs.push_back("-application_extension");
-
- if (D.isUsingLTO()) {
- // If we are using LTO, then automatically create a temporary file path for
- // the linker to use, so that it's lifetime will extend past a possible
- // dsymutil step.
- if (Version[0] >= 116 && NeedsTempPath(Inputs)) {
- const char *TmpPath = C.getArgs().MakeArgString(
- D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object)));
- C.addTempFile(TmpPath);
- CmdArgs.push_back("-object_path_lto");
- CmdArgs.push_back(TmpPath);
- }
- }
-
- // Use -lto_library option to specify the libLTO.dylib path. Try to find
- // it in clang installed libraries. ld64 will only look at this argument
- // when it actually uses LTO, so libLTO.dylib only needs to exist at link
- // time if ld64 decides that it needs to use LTO.
- // Since this is passed unconditionally, ld64 will never look for libLTO.dylib
- // next to it. That's ok since ld64 using a libLTO.dylib not matching the
- // clang version won't work anyways.
- if (Version[0] >= 133) {
- // Search for libLTO in <InstalledDir>/../lib/libLTO.dylib
- StringRef P = llvm::sys::path::parent_path(D.Dir);
- SmallString<128> LibLTOPath(P);
- llvm::sys::path::append(LibLTOPath, "lib");
- llvm::sys::path::append(LibLTOPath, "libLTO.dylib");
- CmdArgs.push_back("-lto_library");
- CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath));
- }
-
- // ld64 version 262 and above run the deduplicate pass by default.
- if (Version[0] >= 262 && shouldLinkerNotDedup(C.getJobs().empty(), Args))
- CmdArgs.push_back("-no_deduplicate");
-
- // Derived from the "link" spec.
- Args.AddAllArgs(CmdArgs, options::OPT_static);
- if (!Args.hasArg(options::OPT_static))
- CmdArgs.push_back("-dynamic");
- if (Args.hasArg(options::OPT_fgnu_runtime)) {
- // FIXME: gcc replaces -lobjc in forward args with -lobjc-gnu
- // here. How do we wish to handle such things?
- }
-
- if (!Args.hasArg(options::OPT_dynamiclib)) {
- AddMachOArch(Args, CmdArgs);
- // FIXME: Why do this only on this path?
- Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL);
-
- Args.AddLastArg(CmdArgs, options::OPT_bundle);
- Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader);
- Args.AddAllArgs(CmdArgs, options::OPT_client__name);
-
- Arg *A;
- if ((A = Args.getLastArg(options::OPT_compatibility__version)) ||
- (A = Args.getLastArg(options::OPT_current__version)) ||
- (A = Args.getLastArg(options::OPT_install__name)))
- D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args)
- << "-dynamiclib";
-
- Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace);
- Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs);
- Args.AddLastArg(CmdArgs, options::OPT_private__bundle);
- } else {
- CmdArgs.push_back("-dylib");
-
- Arg *A;
- if ((A = Args.getLastArg(options::OPT_bundle)) ||
- (A = Args.getLastArg(options::OPT_bundle__loader)) ||
- (A = Args.getLastArg(options::OPT_client__name)) ||
- (A = Args.getLastArg(options::OPT_force__flat__namespace)) ||
- (A = Args.getLastArg(options::OPT_keep__private__externs)) ||
- (A = Args.getLastArg(options::OPT_private__bundle)))
- D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args)
- << "-dynamiclib";
-
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version,
- "-dylib_compatibility_version");
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version,
- "-dylib_current_version");
-
- AddMachOArch(Args, CmdArgs);
-
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name,
- "-dylib_install_name");
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_all__load);
- Args.AddAllArgs(CmdArgs, options::OPT_allowable__client);
- Args.AddLastArg(CmdArgs, options::OPT_bind__at__load);
- if (MachOTC.isTargetIOSBased())
- Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal);
- Args.AddLastArg(CmdArgs, options::OPT_dead__strip);
- Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms);
- Args.AddAllArgs(CmdArgs, options::OPT_dylib__file);
- Args.AddLastArg(CmdArgs, options::OPT_dynamic);
- Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list);
- Args.AddLastArg(CmdArgs, options::OPT_flat__namespace);
- Args.AddAllArgs(CmdArgs, options::OPT_force__load);
- Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names);
- Args.AddAllArgs(CmdArgs, options::OPT_image__base);
- Args.AddAllArgs(CmdArgs, options::OPT_init);
-
- // Add the deployment target.
- MachOTC.addMinVersionArgs(Args, CmdArgs);
-
- Args.AddLastArg(CmdArgs, options::OPT_nomultidefs);
- Args.AddLastArg(CmdArgs, options::OPT_multi__module);
- Args.AddLastArg(CmdArgs, options::OPT_single__module);
- Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined);
- Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused);
-
- if (const Arg *A =
- Args.getLastArg(options::OPT_fpie, options::OPT_fPIE,
- options::OPT_fno_pie, options::OPT_fno_PIE)) {
- if (A->getOption().matches(options::OPT_fpie) ||
- A->getOption().matches(options::OPT_fPIE))
- CmdArgs.push_back("-pie");
- else
- CmdArgs.push_back("-no_pie");
- }
-
- // for embed-bitcode, use -bitcode_bundle in linker command
- if (C.getDriver().embedBitcodeEnabled()) {
- // Check if the toolchain supports bitcode build flow.
- if (MachOTC.SupportsEmbeddedBitcode())
- CmdArgs.push_back("-bitcode_bundle");
- else
- D.Diag(diag::err_drv_bitcode_unsupported_on_toolchain);
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_prebind);
- Args.AddLastArg(CmdArgs, options::OPT_noprebind);
- Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding);
- Args.AddLastArg(CmdArgs, options::OPT_prebind__all__twolevel__modules);
- Args.AddLastArg(CmdArgs, options::OPT_read__only__relocs);
- Args.AddAllArgs(CmdArgs, options::OPT_sectcreate);
- Args.AddAllArgs(CmdArgs, options::OPT_sectorder);
- Args.AddAllArgs(CmdArgs, options::OPT_seg1addr);
- Args.AddAllArgs(CmdArgs, options::OPT_segprot);
- Args.AddAllArgs(CmdArgs, options::OPT_segaddr);
- Args.AddAllArgs(CmdArgs, options::OPT_segs__read__only__addr);
- Args.AddAllArgs(CmdArgs, options::OPT_segs__read__write__addr);
- Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table);
- Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename);
- Args.AddAllArgs(CmdArgs, options::OPT_sub__library);
- Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella);
-
- // Give --sysroot= preference, over the Apple specific behavior to also use
- // --isysroot as the syslibroot.
- StringRef sysroot = C.getSysRoot();
- if (sysroot != "") {
- CmdArgs.push_back("-syslibroot");
- CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
- } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- CmdArgs.push_back("-syslibroot");
- CmdArgs.push_back(A->getValue());
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace);
- Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints);
- Args.AddAllArgs(CmdArgs, options::OPT_umbrella);
- Args.AddAllArgs(CmdArgs, options::OPT_undefined);
- Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list);
- Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches);
- Args.AddLastArg(CmdArgs, options::OPT_X_Flag);
- Args.AddAllArgs(CmdArgs, options::OPT_y);
- Args.AddLastArg(CmdArgs, options::OPT_w);
- Args.AddAllArgs(CmdArgs, options::OPT_pagezero__size);
- Args.AddAllArgs(CmdArgs, options::OPT_segs__read__);
- Args.AddLastArg(CmdArgs, options::OPT_seglinkedit);
- Args.AddLastArg(CmdArgs, options::OPT_noseglinkedit);
- Args.AddAllArgs(CmdArgs, options::OPT_sectalign);
- Args.AddAllArgs(CmdArgs, options::OPT_sectobjectsymbols);
- Args.AddAllArgs(CmdArgs, options::OPT_segcreate);
- Args.AddLastArg(CmdArgs, options::OPT_whyload);
- Args.AddLastArg(CmdArgs, options::OPT_whatsloaded);
- Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name);
- Args.AddLastArg(CmdArgs, options::OPT_dylinker);
- Args.AddLastArg(CmdArgs, options::OPT_Mach);
-}
-
-void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- assert(Output.getType() == types::TY_Image && "Invalid linker output type.");
-
- // If the number of arguments surpasses the system limits, we will encode the
- // input files in a separate file, shortening the command line. To this end,
- // build a list of input file names that can be passed via a file with the
- // -filelist linker option.
- llvm::opt::ArgStringList InputFileList;
-
- // The logic here is derived from gcc's behavior; most of which
- // comes from specs (starting with link_command). Consult gcc for
- // more information.
- ArgStringList CmdArgs;
-
- /// Hack(tm) to ignore linking errors when we are doing ARC migration.
- if (Args.hasArg(options::OPT_ccc_arcmt_check,
- options::OPT_ccc_arcmt_migrate)) {
- for (const auto &Arg : Args)
- Arg->claim();
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("touch"));
- CmdArgs.push_back(Output.getFilename());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, None));
- return;
- }
-
- // I'm not sure why this particular decomposition exists in gcc, but
- // we follow suite for ease of comparison.
- AddLinkArgs(C, Args, CmdArgs, Inputs);
-
- // For LTO, pass the name of the optimization record file.
- if (Args.hasFlag(options::OPT_fsave_optimization_record,
- options::OPT_fno_save_optimization_record, false)) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-lto-pass-remarks-output");
- CmdArgs.push_back("-mllvm");
-
- SmallString<128> F;
- F = Output.getFilename();
- F += ".opt.yaml";
- CmdArgs.push_back(Args.MakeArgString(F));
-
- if (getLastProfileUseArg(Args)) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-lto-pass-remarks-with-hotness");
- }
- }
-
- // It seems that the 'e' option is completely ignored for dynamic executables
- // (the default), and with static executables, the last one wins, as expected.
- Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t,
- options::OPT_Z_Flag, options::OPT_u_Group,
- options::OPT_e, options::OPT_r});
-
- // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading
- // members of static archive libraries which implement Objective-C classes or
- // categories.
- if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX))
- CmdArgs.push_back("-ObjC");
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
- getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs);
-
- // SafeStack requires its own runtime libraries
- // These libraries should be linked first, to make sure the
- // __safestack_init constructor executes before everything else
- if (getToolChain().getSanitizerArgs().needsSafeStackRt()) {
- getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs,
- "libclang_rt.safestack_osx.a",
- /*AlwaysLink=*/true);
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
- // Build the input file for -filelist (list of linker input files) in case we
- // need it later
- for (const auto &II : Inputs) {
- if (!II.isFilename()) {
- // This is a linker input argument.
- // We cannot mix input arguments and file names in a -filelist input, thus
- // we prematurely stop our list (remaining files shall be passed as
- // arguments).
- if (InputFileList.size() > 0)
- break;
-
- continue;
- }
-
- InputFileList.push_back(II.getFilename());
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
- addOpenMPRuntime(CmdArgs, getToolChain(), Args);
-
- if (isObjCRuntimeLinked(Args) &&
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- // We use arclite library for both ARC and subscripting support.
- getMachOToolChain().AddLinkARCArgs(Args, CmdArgs);
-
- CmdArgs.push_back("-framework");
- CmdArgs.push_back("Foundation");
- // Link libobj.
- CmdArgs.push_back("-lobjc");
- }
-
- if (LinkingOutput) {
- CmdArgs.push_back("-arch_multiple");
- CmdArgs.push_back("-final_output");
- CmdArgs.push_back(LinkingOutput);
- }
-
- if (Args.hasArg(options::OPT_fnested_functions))
- CmdArgs.push_back("-allow_stack_execute");
-
- getMachOToolChain().addProfileRTLibs(Args, CmdArgs);
-
- if (unsigned Parallelism =
- getLTOParallelism(Args, getToolChain().getDriver())) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-threads=") + llvm::to_string(Parallelism)));
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (getToolChain().getDriver().CCCIsCXX())
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
-
- // link_ssp spec is empty.
-
- // Let the tool chain choose which runtime library to link.
- getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs);
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- // endfile_spec is empty.
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_F);
-
- // -iframework should be forwarded as -F.
- for (const Arg *A : Args.filtered(options::OPT_iframework))
- CmdArgs.push_back(Args.MakeArgString(std::string("-F") + A->getValue()));
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (Arg *A = Args.getLastArg(options::OPT_fveclib)) {
- if (A->getValue() == StringRef("Accelerate")) {
- CmdArgs.push_back("-framework");
- CmdArgs.push_back("Accelerate");
- }
- }
- }
-
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- std::unique_ptr<Command> Cmd =
- llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs);
- Cmd->setInputFileList(std::move(InputFileList));
- C.addCommand(std::move(Cmd));
-}
-
-void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- CmdArgs.push_back("-create");
- assert(Output.isFilename() && "Unexpected lipo output.");
-
- CmdArgs.push_back("-output");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs) {
- assert(II.isFilename() && "Unexpected lipo input.");
- CmdArgs.push_back(II.getFilename());
- }
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
- const InputInfo &Input = Inputs[0];
- assert(Input.isFilename() && "Unexpected dsymutil input.");
- CmdArgs.push_back(Input.getFilename());
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("dsymutil"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
- CmdArgs.push_back("--verify");
- CmdArgs.push_back("--debug-info");
- CmdArgs.push_back("--eh-frame");
- CmdArgs.push_back("--quiet");
-
- assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
- const InputInfo &Input = Inputs[0];
- assert(Input.isFilename() && "Unexpected verify input");
-
- // Grabbing the output of the earlier dsymutil run.
- CmdArgs.push_back(Input.getFilename());
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- // Demangle C++ names in errors
- CmdArgs.push_back("-C");
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
- CmdArgs.push_back("-e");
- CmdArgs.push_back("_start");
- }
-
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-Bstatic");
- CmdArgs.push_back("-dn");
- } else {
- CmdArgs.push_back("-Bdynamic");
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-shared");
- } else {
- CmdArgs.push_back("--dynamic-linker");
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("ld.so.1")));
- }
- }
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
-
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("values-Xa.o")));
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
- }
-
- getToolChain().AddFilePathLibArgs(Args, CmdArgs);
-
- Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
- options::OPT_e, options::OPT_r});
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (getToolChain().getDriver().CCCIsCXX())
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-lgcc_s");
- CmdArgs.push_back("-lc");
- if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-lgcc");
- CmdArgs.push_back("-lm");
- }
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
- }
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
-
- getToolChain().addProfileRTLibs(Args, CmdArgs);
-
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- switch (getToolChain().getArch()) {
- case llvm::Triple::x86:
- // When building 32-bit code on OpenBSD/amd64, we have to explicitly
- // instruct as in the base system to assemble 32-bit code.
- CmdArgs.push_back("--32");
- break;
-
- case llvm::Triple::ppc:
- CmdArgs.push_back("-mppc");
- CmdArgs.push_back("-many");
- break;
-
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel: {
- CmdArgs.push_back("-32");
- std::string CPU = getCPUName(Args, getToolChain().getTriple());
- CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
-
- case llvm::Triple::sparcv9: {
- CmdArgs.push_back("-64");
- std::string CPU = getCPUName(Args, getToolChain().getTriple());
- CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
-
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el: {
- StringRef CPUName;
- StringRef ABIName;
- mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
-
- CmdArgs.push_back("-mabi");
- CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
-
- if (getToolChain().getArch() == llvm::Triple::mips64)
- CmdArgs.push_back("-EB");
- else
- CmdArgs.push_back("-EL");
-
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
-
- default:
- break;
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- if (getToolChain().getArch() == llvm::Triple::mips64)
- CmdArgs.push_back("-EB");
- else if (getToolChain().getArch() == llvm::Triple::mips64el)
- CmdArgs.push_back("-EL");
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
- CmdArgs.push_back("-e");
- CmdArgs.push_back("__start");
- }
-
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-Bstatic");
- } else {
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- CmdArgs.push_back("--eh-frame-hdr");
- CmdArgs.push_back("-Bdynamic");
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-shared");
- } else {
- CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back("/usr/libexec/ld.so");
- }
- }
-
- if (Args.hasArg(options::OPT_nopie))
- CmdArgs.push_back("-nopie");
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("gcrt0.o")));
- else if (Args.hasArg(options::OPT_static) &&
- !Args.hasArg(options::OPT_nopie))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("rcrt0.o")));
- else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crt0.o")));
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
- } else {
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
- }
- }
-
- std::string Triple = getToolChain().getTripleString();
- if (Triple.substr(0, 6) == "x86_64")
- Triple.replace(0, 6, "amd64");
- CmdArgs.push_back(
- Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + "/4.2.1"));
-
- Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
- options::OPT_e, options::OPT_s, options::OPT_t,
- options::OPT_Z_Flag, options::OPT_r});
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX()) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lm_p");
- else
- CmdArgs.push_back("-lm");
- }
-
- // FIXME: For some reason GCC passes -lgcc before adding
- // the default system libraries. Just mimic this for now.
- CmdArgs.push_back("-lgcc");
-
- if (Args.hasArg(options::OPT_pthread)) {
- if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lpthread_p");
- else
- CmdArgs.push_back("-lpthread");
- }
-
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lc_p");
- else
- CmdArgs.push_back("-lc");
- }
-
- CmdArgs.push_back("-lgcc");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
- else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
- }
-
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void bitrig::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void bitrig::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) {
- CmdArgs.push_back("-e");
- CmdArgs.push_back("__start");
- }
-
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-Bstatic");
- } else {
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- CmdArgs.push_back("--eh-frame-hdr");
- CmdArgs.push_back("-Bdynamic");
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-shared");
- } else {
- CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back("/usr/libexec/ld.so");
- }
- }
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("gcrt0.o")));
- else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crt0.o")));
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
- } else {
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
- }
- }
-
- Args.AddAllArgs(CmdArgs,
- {options::OPT_L, options::OPT_T_Group, options::OPT_e});
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX()) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lm_p");
- else
- CmdArgs.push_back("-lm");
- }
-
- if (Args.hasArg(options::OPT_pthread)) {
- if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lpthread_p");
- else
- CmdArgs.push_back("-lpthread");
- }
-
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lc_p");
- else
- CmdArgs.push_back("-lc");
- }
-
- StringRef MyArch;
- switch (getToolChain().getArch()) {
- case llvm::Triple::arm:
- MyArch = "arm";
- break;
- case llvm::Triple::x86:
- MyArch = "i386";
- break;
- case llvm::Triple::x86_64:
- MyArch = "amd64";
- break;
- default:
- llvm_unreachable("Unsupported architecture");
- }
- CmdArgs.push_back(Args.MakeArgString("-lclang_rt." + MyArch));
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
- else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
- }
-
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- // When building 32-bit code on FreeBSD/amd64, we have to explicitly
- // instruct as in the base system to assemble 32-bit code.
- switch (getToolChain().getArch()) {
- default:
- break;
- case llvm::Triple::x86:
- CmdArgs.push_back("--32");
- break;
- case llvm::Triple::ppc:
- CmdArgs.push_back("-a32");
- break;
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el: {
- StringRef CPUName;
- StringRef ABIName;
- mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
-
- CmdArgs.push_back("-march");
- CmdArgs.push_back(CPUName.data());
-
- CmdArgs.push_back("-mabi");
- CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
-
- if (getToolChain().getArch() == llvm::Triple::mips ||
- getToolChain().getArch() == llvm::Triple::mips64)
- CmdArgs.push_back("-EB");
- else
- CmdArgs.push_back("-EL");
-
- if (Arg *A = Args.getLastArg(options::OPT_G)) {
- StringRef v = A->getValue();
- CmdArgs.push_back(Args.MakeArgString("-G" + v));
- A->claim();
- }
-
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb: {
- arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args);
-
- if (ABI == arm::FloatABI::Hard)
- CmdArgs.push_back("-mfpu=vfp");
- else
- CmdArgs.push_back("-mfpu=softvfp");
-
- switch (getToolChain().getTriple().getEnvironment()) {
- case llvm::Triple::GNUEABIHF:
- case llvm::Triple::GNUEABI:
- case llvm::Triple::EABI:
- CmdArgs.push_back("-meabi=5");
- break;
-
- default:
- CmdArgs.push_back("-matpcs");
- }
- break;
- }
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::sparcv9: {
- std::string CPU = getCPUName(Args, getToolChain().getTriple());
- CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const toolchains::FreeBSD &ToolChain =
- static_cast<const toolchains::FreeBSD &>(getToolChain());
- const Driver &D = ToolChain.getDriver();
- const llvm::Triple::ArchType Arch = ToolChain.getArch();
- const bool IsPIE =
- !Args.hasArg(options::OPT_shared) &&
- (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- if (IsPIE)
- CmdArgs.push_back("-pie");
-
- CmdArgs.push_back("--eh-frame-hdr");
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-Bstatic");
- } else {
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-Bshareable");
- } else {
- CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back("/libexec/ld-elf.so.1");
- }
- if (ToolChain.getTriple().getOSMajorVersion() >= 9) {
- if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc ||
- Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
- CmdArgs.push_back("--hash-style=both");
- }
- }
- CmdArgs.push_back("--enable-new-dtags");
- }
-
- // When building 32-bit code on FreeBSD/amd64, we have to explicitly
- // instruct ld in the base system to link 32-bit code.
- if (Arch == llvm::Triple::x86) {
- CmdArgs.push_back("-m");
- CmdArgs.push_back("elf_i386_fbsd");
- }
-
- if (Arch == llvm::Triple::ppc) {
- CmdArgs.push_back("-m");
- CmdArgs.push_back("elf32ppc_fbsd");
- }
-
- if (Arg *A = Args.getLastArg(options::OPT_G)) {
- if (ToolChain.getArch() == llvm::Triple::mips ||
- ToolChain.getArch() == llvm::Triple::mipsel ||
- ToolChain.getArch() == llvm::Triple::mips64 ||
- ToolChain.getArch() == llvm::Triple::mips64el) {
- StringRef v = A->getValue();
- CmdArgs.push_back(Args.MakeArgString("-G" + v));
- A->claim();
- }
- }
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- const char *crt1 = nullptr;
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
- crt1 = "gcrt1.o";
- else if (IsPIE)
- crt1 = "Scrt1.o";
- else
- crt1 = "crt1.o";
- }
- if (crt1)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
-
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
-
- const char *crtbegin = nullptr;
- if (Args.hasArg(options::OPT_static))
- crtbegin = "crtbeginT.o";
- else if (Args.hasArg(options::OPT_shared) || IsPIE)
- crtbegin = "crtbeginS.o";
- else
- crtbegin = "crtbegin.o";
-
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_e);
- Args.AddAllArgs(CmdArgs, options::OPT_s);
- Args.AddAllArgs(CmdArgs, options::OPT_t);
- Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
- Args.AddAllArgs(CmdArgs, options::OPT_r);
-
- if (D.isUsingLTO())
- AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
-
- bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- addOpenMPRuntime(CmdArgs, ToolChain, Args);
- if (D.CCCIsCXX()) {
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lm_p");
- else
- CmdArgs.push_back("-lm");
- }
- if (NeedsSanitizerDeps)
- linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
- // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
- // the default system libraries. Just mimic this for now.
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lgcc_p");
- else
- CmdArgs.push_back("-lgcc");
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-lgcc_eh");
- } else if (Args.hasArg(options::OPT_pg)) {
- CmdArgs.push_back("-lgcc_eh_p");
- } else {
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
- CmdArgs.push_back("--no-as-needed");
- }
-
- if (Args.hasArg(options::OPT_pthread)) {
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lpthread_p");
- else
- CmdArgs.push_back("-lpthread");
- }
-
- if (Args.hasArg(options::OPT_pg)) {
- if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-lc");
- else
- CmdArgs.push_back("-lc_p");
- CmdArgs.push_back("-lgcc_p");
- } else {
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lgcc");
- }
-
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-lgcc_eh");
- } else if (Args.hasArg(options::OPT_pg)) {
- CmdArgs.push_back("-lgcc_eh_p");
- } else {
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
- CmdArgs.push_back("--no-as-needed");
- }
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_shared) || IsPIE)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
- else
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
- }
-
- ToolChain.addProfileRTLibs(Args, CmdArgs);
-
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- // GNU as needs different flags for creating the correct output format
- // on architectures with different ABIs or optional feature sets.
- switch (getToolChain().getArch()) {
- case llvm::Triple::x86:
- CmdArgs.push_back("--32");
- break;
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb: {
- StringRef MArch, MCPU;
- getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true);
- std::string Arch =
- arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple());
- CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch));
- break;
- }
-
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el: {
- StringRef CPUName;
- StringRef ABIName;
- mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
-
- CmdArgs.push_back("-march");
- CmdArgs.push_back(CPUName.data());
-
- CmdArgs.push_back("-mabi");
- CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
-
- if (getToolChain().getArch() == llvm::Triple::mips ||
- getToolChain().getArch() == llvm::Triple::mips64)
- CmdArgs.push_back("-EB");
- else
- CmdArgs.push_back("-EL");
-
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
-
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel: {
- CmdArgs.push_back("-32");
- std::string CPU = getCPUName(Args, getToolChain().getTriple());
- CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
-
- case llvm::Triple::sparcv9: {
- CmdArgs.push_back("-64");
- std::string CPU = getCPUName(Args, getToolChain().getTriple());
- CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
-
- default:
- break;
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as")));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- CmdArgs.push_back("--eh-frame-hdr");
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-Bstatic");
- } else {
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-Bshareable");
- } else {
- Args.AddAllArgs(CmdArgs, options::OPT_pie);
- CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back("/libexec/ld.elf_so");
- }
- }
-
- // Many NetBSD architectures support more than one ABI.
- // Determine the correct emulation for ld.
- switch (getToolChain().getArch()) {
- case llvm::Triple::x86:
- CmdArgs.push_back("-m");
- CmdArgs.push_back("elf_i386");
- break;
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- CmdArgs.push_back("-m");
- switch (getToolChain().getTriple().getEnvironment()) {
- case llvm::Triple::EABI:
- case llvm::Triple::GNUEABI:
- CmdArgs.push_back("armelf_nbsd_eabi");
- break;
- case llvm::Triple::EABIHF:
- case llvm::Triple::GNUEABIHF:
- CmdArgs.push_back("armelf_nbsd_eabihf");
- break;
- default:
- CmdArgs.push_back("armelf_nbsd");
- break;
- }
- break;
- case llvm::Triple::armeb:
- case llvm::Triple::thumbeb:
- arm::appendEBLinkFlags(Args, CmdArgs, getToolChain().getEffectiveTriple());
- CmdArgs.push_back("-m");
- switch (getToolChain().getTriple().getEnvironment()) {
- case llvm::Triple::EABI:
- case llvm::Triple::GNUEABI:
- CmdArgs.push_back("armelfb_nbsd_eabi");
- break;
- case llvm::Triple::EABIHF:
- case llvm::Triple::GNUEABIHF:
- CmdArgs.push_back("armelfb_nbsd_eabihf");
- break;
- default:
- CmdArgs.push_back("armelfb_nbsd");
- break;
- }
- break;
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- if (mips::hasMipsAbiArg(Args, "32")) {
- CmdArgs.push_back("-m");
- if (getToolChain().getArch() == llvm::Triple::mips64)
- CmdArgs.push_back("elf32btsmip");
- else
- CmdArgs.push_back("elf32ltsmip");
- } else if (mips::hasMipsAbiArg(Args, "64")) {
- CmdArgs.push_back("-m");
- if (getToolChain().getArch() == llvm::Triple::mips64)
- CmdArgs.push_back("elf64btsmip");
- else
- CmdArgs.push_back("elf64ltsmip");
- }
- break;
- case llvm::Triple::ppc:
- CmdArgs.push_back("-m");
- CmdArgs.push_back("elf32ppc_nbsd");
- break;
-
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- CmdArgs.push_back("-m");
- CmdArgs.push_back("elf64ppc");
- break;
-
- case llvm::Triple::sparc:
- CmdArgs.push_back("-m");
- CmdArgs.push_back("elf32_sparc");
- break;
-
- case llvm::Triple::sparcv9:
- CmdArgs.push_back("-m");
- CmdArgs.push_back("elf64_sparc");
- break;
-
- default:
- break;
- }
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crt0.o")));
- }
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) {
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
- } else {
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
- }
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_e);
- Args.AddAllArgs(CmdArgs, options::OPT_s);
- Args.AddAllArgs(CmdArgs, options::OPT_t);
- Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
- Args.AddAllArgs(CmdArgs, options::OPT_r);
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- unsigned Major, Minor, Micro;
- getToolChain().getTriple().getOSVersion(Major, Minor, Micro);
- bool useLibgcc = true;
- if (Major >= 7 || Major == 0) {
- switch (getToolChain().getArch()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- case llvm::Triple::sparc:
- case llvm::Triple::sparcv9:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- useLibgcc = false;
- break;
- default:
- break;
- }
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- addOpenMPRuntime(CmdArgs, getToolChain(), Args);
- if (D.CCCIsCXX()) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-lm");
- }
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-lc");
-
- if (useLibgcc) {
- if (Args.hasArg(options::OPT_static)) {
- // libgcc_eh depends on libc, so resolve as much as possible,
- // pull in any new requirements from libc and then get the rest
- // of libgcc.
- CmdArgs.push_back("-lgcc_eh");
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lgcc");
- } else {
- CmdArgs.push_back("-lgcc");
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
- CmdArgs.push_back("--no-as-needed");
- }
- }
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
- else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
- }
-
- getToolChain().addProfileRTLibs(Args, CmdArgs);
-
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
-
- ArgStringList CmdArgs;
-
- llvm::Reloc::Model RelocationModel;
- unsigned PICLevel;
- bool IsPIE;
- std::tie(RelocationModel, PICLevel, IsPIE) =
- ParsePICArgs(getToolChain(), Args);
-
- switch (getToolChain().getArch()) {
- default:
- break;
- // Add --32/--64 to make sure we get the format we want.
- // This is incomplete
- case llvm::Triple::x86:
- CmdArgs.push_back("--32");
- break;
- case llvm::Triple::x86_64:
- if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32)
- CmdArgs.push_back("--x32");
- else
- CmdArgs.push_back("--64");
- break;
- case llvm::Triple::ppc:
- CmdArgs.push_back("-a32");
- CmdArgs.push_back("-mppc");
- CmdArgs.push_back("-many");
- break;
- case llvm::Triple::ppc64:
- CmdArgs.push_back("-a64");
- CmdArgs.push_back("-mppc64");
- CmdArgs.push_back("-many");
- break;
- case llvm::Triple::ppc64le:
- CmdArgs.push_back("-a64");
- CmdArgs.push_back("-mppc64");
- CmdArgs.push_back("-many");
- CmdArgs.push_back("-mlittle-endian");
- break;
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel: {
- CmdArgs.push_back("-32");
- std::string CPU = getCPUName(Args, getToolChain().getTriple());
- CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
- case llvm::Triple::sparcv9: {
- CmdArgs.push_back("-64");
- std::string CPU = getCPUName(Args, getToolChain().getTriple());
- CmdArgs.push_back(getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb: {
- const llvm::Triple &Triple2 = getToolChain().getTriple();
- switch (Triple2.getSubArch()) {
- case llvm::Triple::ARMSubArch_v7:
- CmdArgs.push_back("-mfpu=neon");
- break;
- case llvm::Triple::ARMSubArch_v8:
- CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8");
- break;
- default:
- break;
- }
-
- switch (arm::getARMFloatABI(getToolChain(), Args)) {
- case arm::FloatABI::Invalid: llvm_unreachable("must have an ABI!");
- case arm::FloatABI::Soft:
- CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=soft"));
- break;
- case arm::FloatABI::SoftFP:
- CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=softfp"));
- break;
- case arm::FloatABI::Hard:
- CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=hard"));
- break;
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
-
- // FIXME: remove krait check when GNU tools support krait cpu
- // for now replace it with -mcpu=cortex-a15 to avoid a lower
- // march from being picked in the absence of a cpu flag.
- Arg *A;
- if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) &&
- StringRef(A->getValue()).equals_lower("krait"))
- CmdArgs.push_back("-mcpu=cortex-a15");
- else
- Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
- Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
- break;
- }
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el: {
- StringRef CPUName;
- StringRef ABIName;
- mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
- ABIName = getGnuCompatibleMipsABIName(ABIName);
-
- CmdArgs.push_back("-march");
- CmdArgs.push_back(CPUName.data());
-
- CmdArgs.push_back("-mabi");
- CmdArgs.push_back(ABIName.data());
-
- // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE,
- // or -mshared (not implemented) is in effect.
- if (RelocationModel == llvm::Reloc::Static)
- CmdArgs.push_back("-mno-shared");
-
- // LLVM doesn't support -mplt yet and acts as if it is always given.
- // However, -mplt has no effect with the N64 ABI.
- CmdArgs.push_back(ABIName == "64" ? "-KPIC" : "-call_nonpic");
-
- if (getToolChain().getArch() == llvm::Triple::mips ||
- getToolChain().getArch() == llvm::Triple::mips64)
- CmdArgs.push_back("-EB");
- else
- CmdArgs.push_back("-EL");
-
- if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
- if (StringRef(A->getValue()) == "2008")
- CmdArgs.push_back(Args.MakeArgString("-mnan=2008"));
- }
-
- // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default.
- if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
- options::OPT_mfp64)) {
- A->claim();
- A->render(Args, CmdArgs);
- } else if (mips::shouldUseFPXX(
- Args, getToolChain().getTriple(), CPUName, ABIName,
- getMipsFloatABI(getToolChain().getDriver(), Args)))
- CmdArgs.push_back("-mfpxx");
-
- // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of
- // -mno-mips16 is actually -no-mips16.
- if (Arg *A =
- Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16)) {
- if (A->getOption().matches(options::OPT_mips16)) {
- A->claim();
- A->render(Args, CmdArgs);
- } else {
- A->claim();
- CmdArgs.push_back("-no-mips16");
- }
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_mmicromips,
- options::OPT_mno_micromips);
- Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp);
- Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2);
-
- if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) {
- // Do not use AddLastArg because not all versions of MIPS assembler
- // support -mmsa / -mno-msa options.
- if (A->getOption().matches(options::OPT_mmsa))
- CmdArgs.push_back(Args.MakeArgString("-mmsa"));
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_mhard_float,
- options::OPT_msoft_float);
-
- Args.AddLastArg(CmdArgs, options::OPT_mdouble_float,
- options::OPT_msingle_float);
-
- Args.AddLastArg(CmdArgs, options::OPT_modd_spreg,
- options::OPT_mno_odd_spreg);
-
- AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
- break;
- }
- case llvm::Triple::systemz: {
- // Always pass an -march option, since our default of z10 is later
- // than the GNU assembler's default.
- StringRef CPUName = getSystemZTargetCPU(Args);
- CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
- break;
- }
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_I);
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-
- // Handle the debug info splitting at object creation time if we're
- // creating an object.
- // TODO: Currently only works on linux with newer objcopy.
- if (Args.hasArg(options::OPT_gsplit_dwarf) &&
- getToolChain().getTriple().isOSLinux())
- SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
- SplitDebugName(Args, Inputs[0]));
-}
-
-static void AddLibgcc(const llvm::Triple &Triple, const Driver &D,
- ArgStringList &CmdArgs, const ArgList &Args) {
- bool isAndroid = Triple.isAndroid();
- bool isCygMing = Triple.isOSCygMing();
- bool IsIAMCU = Triple.isOSIAMCU();
- bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
- Args.hasArg(options::OPT_static);
- if (!D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
-
- if (StaticLibgcc || isAndroid) {
- if (D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
- } else {
- if (!D.CCCIsCXX() && !isCygMing)
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
- if (!D.CCCIsCXX() && !isCygMing)
- CmdArgs.push_back("--no-as-needed");
- }
-
- if (StaticLibgcc && !isAndroid && !IsIAMCU)
- CmdArgs.push_back("-lgcc_eh");
- else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
-
- // According to Android ABI, we have to link with libdl if we are
- // linking with non-static libgcc.
- //
- // NOTE: This fixes a link error on Android MIPS as well. The non-static
- // libgcc for MIPS relies on _Unwind_Find_FDE and dl_iterate_phdr from libdl.
- if (isAndroid && !StaticLibgcc)
- CmdArgs.push_back("-ldl");
-}
-
-static void AddRunTimeLibs(const ToolChain &TC, const Driver &D,
- ArgStringList &CmdArgs, const ArgList &Args) {
- // Make use of compiler-rt if --rtlib option is used
- ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args);
-
- switch (RLT) {
- case ToolChain::RLT_CompilerRT:
- switch (TC.getTriple().getOS()) {
- default:
- llvm_unreachable("unsupported OS");
- case llvm::Triple::Win32:
- case llvm::Triple::Linux:
- case llvm::Triple::Fuchsia:
- addClangRT(TC, Args, CmdArgs);
- break;
- }
- break;
- case ToolChain::RLT_Libgcc:
- // Make sure libgcc is not used under MSVC environment by default
- if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
- // Issue error diagnostic if libgcc is explicitly specified
- // through command line as --rtlib option argument.
- if (Args.hasArg(options::OPT_rtlib_EQ)) {
- TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform)
- << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC";
- }
- } else
- AddLibgcc(TC.getTriple(), D, CmdArgs, Args);
- break;
- }
-}
-
-static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
- switch (T.getArch()) {
- case llvm::Triple::x86:
- if (T.isOSIAMCU())
- return "elf_iamcu";
- return "elf_i386";
- case llvm::Triple::aarch64:
- return "aarch64linux";
- case llvm::Triple::aarch64_be:
- return "aarch64_be_linux";
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- return "armelf_linux_eabi";
- case llvm::Triple::armeb:
- case llvm::Triple::thumbeb:
- return "armelfb_linux_eabi";
- case llvm::Triple::ppc:
- return "elf32ppclinux";
- case llvm::Triple::ppc64:
- return "elf64ppc";
- case llvm::Triple::ppc64le:
- return "elf64lppc";
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- return "elf32_sparc";
- case llvm::Triple::sparcv9:
- return "elf64_sparc";
- case llvm::Triple::mips:
- return "elf32btsmip";
- case llvm::Triple::mipsel:
- return "elf32ltsmip";
- case llvm::Triple::mips64:
- if (mips::hasMipsAbiArg(Args, "n32"))
- return "elf32btsmipn32";
- return "elf64btsmip";
- case llvm::Triple::mips64el:
- if (mips::hasMipsAbiArg(Args, "n32"))
- return "elf32ltsmipn32";
- return "elf64ltsmip";
- case llvm::Triple::systemz:
- return "elf64_s390";
- case llvm::Triple::x86_64:
- if (T.getEnvironment() == llvm::Triple::GNUX32)
- return "elf32_x86_64";
- return "elf_x86_64";
- default:
- return nullptr;
- }
-}
-
-void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const toolchains::Linux &ToolChain =
- static_cast<const toolchains::Linux &>(getToolChain());
- const Driver &D = ToolChain.getDriver();
-
- const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
-
- const llvm::Triple::ArchType Arch = ToolChain.getArch();
- const bool isAndroid = ToolChain.getTriple().isAndroid();
- const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU();
- const bool IsPIE =
- !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) &&
- (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
- const bool HasCRTBeginEndFiles =
- ToolChain.getTriple().hasEnvironment() ||
- (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies);
-
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- if (llvm::sys::path::filename(Exec) == "lld") {
- CmdArgs.push_back("-flavor");
- CmdArgs.push_back("old-gnu");
- CmdArgs.push_back("-target");
- CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString()));
- }
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- if (IsPIE)
- CmdArgs.push_back("-pie");
-
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
-
- if (Args.hasArg(options::OPT_s))
- CmdArgs.push_back("-s");
-
- if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb)
- arm::appendEBLinkFlags(Args, CmdArgs, Triple);
-
- // Most Android ARM64 targets should enable the linker fix for erratum
- // 843419. Only non-Cortex-A53 devices are allowed to skip this flag.
- if (Arch == llvm::Triple::aarch64 && isAndroid) {
- std::string CPU = getCPUName(Args, Triple);
- if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
- CmdArgs.push_back("--fix-cortex-a53-843419");
- }
-
- for (const auto &Opt : ToolChain.ExtraOpts)
- CmdArgs.push_back(Opt.c_str());
-
- if (!Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("--eh-frame-hdr");
- }
-
- if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) {
- CmdArgs.push_back("-m");
- CmdArgs.push_back(LDMOption);
- } else {
- D.Diag(diag::err_target_unknown_triple) << Triple.str();
- return;
- }
-
- if (Args.hasArg(options::OPT_static)) {
- if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb ||
- Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb)
- CmdArgs.push_back("-Bstatic");
- else
- CmdArgs.push_back("-static");
- } else if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-shared");
- }
-
- if (!Args.hasArg(options::OPT_static)) {
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
-
- if (!Args.hasArg(options::OPT_shared)) {
- const std::string Loader =
- D.DyldPrefix + ToolChain.getDynamicLinker(Args);
- CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back(Args.MakeArgString(Loader));
- }
- }
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!isAndroid && !IsIAMCU) {
- const char *crt1 = nullptr;
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
- crt1 = "gcrt1.o";
- else if (IsPIE)
- crt1 = "Scrt1.o";
- else
- crt1 = "crt1.o";
- }
- if (crt1)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
-
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
- }
-
- if (IsIAMCU)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
- else {
- const char *crtbegin;
- if (Args.hasArg(options::OPT_static))
- crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o";
- else if (Args.hasArg(options::OPT_shared))
- crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o";
- else if (IsPIE)
- crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o";
- else
- crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o";
-
- if (HasCRTBeginEndFiles)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
- }
-
- // Add crtfastmath.o if available and fast math is enabled.
- ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_u);
-
- ToolChain.AddFilePathLibArgs(Args, CmdArgs);
-
- if (D.isUsingLTO())
- AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
-
- if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
- CmdArgs.push_back("--no-demangle");
-
- bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
- bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
- // The profile runtime also needs access to system libraries.
- getToolChain().addProfileRTLibs(Args, CmdArgs);
-
- if (D.CCCIsCXX() &&
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
- !Args.hasArg(options::OPT_static);
- if (OnlyLibstdcxxStatic)
- CmdArgs.push_back("-Bstatic");
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (OnlyLibstdcxxStatic)
- CmdArgs.push_back("-Bdynamic");
- CmdArgs.push_back("-lm");
- }
- // Silence warnings when linking C code with a C++ '-stdlib' argument.
- Args.ClaimAllArgs(options::OPT_stdlib_EQ);
-
- if (!Args.hasArg(options::OPT_nostdlib)) {
- if (!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("--start-group");
-
- if (NeedsSanitizerDeps)
- linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
-
- if (NeedsXRayDeps)
- linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
-
- bool WantPthread = Args.hasArg(options::OPT_pthread) ||
- Args.hasArg(options::OPT_pthreads);
-
- if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
- options::OPT_fno_openmp, false)) {
- // OpenMP runtimes implies pthreads when using the GNU toolchain.
- // FIXME: Does this really make sense for all GNU toolchains?
- WantPthread = true;
-
- // Also link the particular OpenMP runtimes.
- switch (ToolChain.getDriver().getOpenMPRuntime(Args)) {
- case Driver::OMPRT_OMP:
- CmdArgs.push_back("-lomp");
- break;
- case Driver::OMPRT_GOMP:
- CmdArgs.push_back("-lgomp");
-
- // FIXME: Exclude this for platforms with libgomp that don't require
- // librt. Most modern Linux platforms require it, but some may not.
- CmdArgs.push_back("-lrt");
- break;
- case Driver::OMPRT_IOMP5:
- CmdArgs.push_back("-liomp5");
- break;
- case Driver::OMPRT_Unknown:
- // Already diagnosed.
- break;
- }
- if (JA.isHostOffloading(Action::OFK_OpenMP))
- CmdArgs.push_back("-lomptarget");
- }
-
- AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
-
- if (WantPthread && !isAndroid)
- CmdArgs.push_back("-lpthread");
-
- if (Args.hasArg(options::OPT_fsplit_stack))
- CmdArgs.push_back("--wrap=pthread_create");
-
- CmdArgs.push_back("-lc");
-
- // Add IAMCU specific libs, if needed.
- if (IsIAMCU)
- CmdArgs.push_back("-lgloss");
-
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("--end-group");
- else
- AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
-
- // Add IAMCU specific libs (outside the group), if needed.
- if (IsIAMCU) {
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lsoftfp");
- CmdArgs.push_back("--no-as-needed");
- }
- }
-
- if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) {
- const char *crtend;
- if (Args.hasArg(options::OPT_shared))
- crtend = isAndroid ? "crtend_so.o" : "crtendS.o";
- else if (IsPIE)
- crtend = isAndroid ? "crtend_android.o" : "crtendS.o";
- else
- crtend = isAndroid ? "crtend_android.o" : "crtend.o";
-
- if (HasCRTBeginEndFiles)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
- if (!isAndroid)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
- }
- }
-
- // Add OpenMP offloading linker script args if required.
- AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA);
-
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-// NaCl ARM assembly (inline or standalone) can be written with a set of macros
-// for the various SFI requirements like register masking. The assembly tool
-// inserts the file containing the macros as an input into all the assembly
-// jobs.
-void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const toolchains::NaClToolChain &ToolChain =
- static_cast<const toolchains::NaClToolChain &>(getToolChain());
- InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(),
- "nacl-arm-macros.s");
- InputInfoList NewInputs;
- NewInputs.push_back(NaClMacros);
- NewInputs.append(Inputs.begin(), Inputs.end());
- gnutools::Assembler::ConstructJob(C, JA, Output, NewInputs, Args,
- LinkingOutput);
-}
-
-// This is quite similar to gnutools::Linker::ConstructJob with changes that
-// we use static by default, do not yet support sanitizers or LTO, and a few
-// others. Eventually we can support more of that and hopefully migrate back
-// to gnutools::Linker.
-void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
-
- const toolchains::NaClToolChain &ToolChain =
- static_cast<const toolchains::NaClToolChain &>(getToolChain());
- const Driver &D = ToolChain.getDriver();
- const llvm::Triple::ArchType Arch = ToolChain.getArch();
- const bool IsStatic =
- !Args.hasArg(options::OPT_dynamic) && !Args.hasArg(options::OPT_shared);
-
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
-
- if (Args.hasArg(options::OPT_s))
- CmdArgs.push_back("-s");
-
- // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag
- // from there is --build-id, which we do want.
- CmdArgs.push_back("--build-id");
-
- if (!IsStatic)
- CmdArgs.push_back("--eh-frame-hdr");
-
- CmdArgs.push_back("-m");
- if (Arch == llvm::Triple::x86)
- CmdArgs.push_back("elf_i386_nacl");
- else if (Arch == llvm::Triple::arm)
- CmdArgs.push_back("armelf_nacl");
- else if (Arch == llvm::Triple::x86_64)
- CmdArgs.push_back("elf_x86_64_nacl");
- else if (Arch == llvm::Triple::mipsel)
- CmdArgs.push_back("mipselelf_nacl");
- else
- D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName()
- << "Native Client";
-
- if (IsStatic)
- CmdArgs.push_back("-static");
- else if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-shared");
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
-
- const char *crtbegin;
- if (IsStatic)
- crtbegin = "crtbeginT.o";
- else if (Args.hasArg(options::OPT_shared))
- crtbegin = "crtbeginS.o";
- else
- crtbegin = "crtbegin.o";
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_u);
-
- ToolChain.AddFilePathLibArgs(Args, CmdArgs);
-
- if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
- CmdArgs.push_back("--no-demangle");
-
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
-
- if (D.CCCIsCXX() &&
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- bool OnlyLibstdcxxStatic =
- Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic;
- if (OnlyLibstdcxxStatic)
- CmdArgs.push_back("-Bstatic");
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (OnlyLibstdcxxStatic)
- CmdArgs.push_back("-Bdynamic");
- CmdArgs.push_back("-lm");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib)) {
- if (!Args.hasArg(options::OPT_nodefaultlibs)) {
- // Always use groups, since it has no effect on dynamic libraries.
- CmdArgs.push_back("--start-group");
- CmdArgs.push_back("-lc");
- // NaCl's libc++ currently requires libpthread, so just always include it
- // in the group for C++.
- if (Args.hasArg(options::OPT_pthread) ||
- Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) {
- // Gold, used by Mips, handles nested groups differently than ld, and
- // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a,
- // which is not a desired behaviour here.
- // See https://sourceware.org/ml/binutils/2015-03/msg00034.html
- if (getToolChain().getArch() == llvm::Triple::mipsel)
- CmdArgs.push_back("-lnacl");
-
- CmdArgs.push_back("-lpthread");
- }
-
- CmdArgs.push_back("-lgcc");
- CmdArgs.push_back("--as-needed");
- if (IsStatic)
- CmdArgs.push_back("-lgcc_eh");
- else
- CmdArgs.push_back("-lgcc_s");
- CmdArgs.push_back("--no-as-needed");
-
- // Mips needs to create and use pnacl_legacy library that contains
- // definitions from bitcode/pnaclmm.c and definitions for
- // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset().
- if (getToolChain().getArch() == llvm::Triple::mipsel)
- CmdArgs.push_back("-lpnacl_legacy");
-
- CmdArgs.push_back("--end-group");
- }
-
- if (!Args.hasArg(options::OPT_nostartfiles)) {
- const char *crtend;
- if (Args.hasArg(options::OPT_shared))
- crtend = "crtendS.o";
- else
- crtend = "crtend.o";
-
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
- }
- }
-
- const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const toolchains::Fuchsia &ToolChain =
- static_cast<const toolchains::Fuchsia &>(getToolChain());
- const Driver &D = ToolChain.getDriver();
-
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- if (llvm::sys::path::stem(Exec).equals_lower("lld")) {
- CmdArgs.push_back("-flavor");
- CmdArgs.push_back("gnu");
- }
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r))
- CmdArgs.push_back("-pie");
-
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
-
- if (Args.hasArg(options::OPT_s))
- CmdArgs.push_back("-s");
-
- if (Args.hasArg(options::OPT_r))
- CmdArgs.push_back("-r");
- else
- CmdArgs.push_back("--build-id");
-
- if (!Args.hasArg(options::OPT_static))
- CmdArgs.push_back("--eh-frame-hdr");
-
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("-Bstatic");
- else if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-shared");
-
- if (!Args.hasArg(options::OPT_static)) {
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
-
- if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back(Args.MakeArgString(D.DyldPrefix + "ld.so.1"));
- }
- }
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o")));
- }
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_u);
-
- ToolChain.AddFilePathLibArgs(Args, CmdArgs);
-
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("-Bdynamic");
-
- if (D.CCCIsCXX()) {
- bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
- !Args.hasArg(options::OPT_static);
- if (OnlyLibstdcxxStatic)
- CmdArgs.push_back("-Bstatic");
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (OnlyLibstdcxxStatic)
- CmdArgs.push_back("-Bdynamic");
- CmdArgs.push_back("-lm");
- }
-
- AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
-
- if (Args.hasArg(options::OPT_pthread) ||
- Args.hasArg(options::OPT_pthreads))
- CmdArgs.push_back("-lpthread");
-
- if (Args.hasArg(options::OPT_fsplit_stack))
- CmdArgs.push_back("--wrap=pthread_create");
-
- CmdArgs.push_back("-lc");
- }
-
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void minix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
- }
-
- Args.AddAllArgs(CmdArgs,
- {options::OPT_L, options::OPT_T_Group, options::OPT_e});
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- getToolChain().addProfileRTLibs(Args, CmdArgs);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- if (D.CCCIsCXX()) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-lm");
- }
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lCompilerRT-Generic");
- CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib");
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
- }
-
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-/// DragonFly Tools
-
-// For now, DragonFly Assemble does just about the same as for
-// FreeBSD, but this may change soon.
-void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- // When building 32-bit code on DragonFly/pc64, we have to explicitly
- // instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArch() == llvm::Triple::x86)
- CmdArgs.push_back("--32");
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- CmdArgs.push_back("--eh-frame-hdr");
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-Bstatic");
- } else {
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-Bshareable");
- else {
- CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back("/usr/libexec/ld-elf.so.2");
- }
- CmdArgs.push_back("--hash-style=gnu");
- CmdArgs.push_back("--enable-new-dtags");
- }
-
- // When building 32-bit code on DragonFly/pc64, we have to explicitly
- // instruct ld in the base system to link 32-bit code.
- if (getToolChain().getArch() == llvm::Triple::x86) {
- CmdArgs.push_back("-m");
- CmdArgs.push_back("elf_i386");
- }
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("gcrt1.o")));
- else {
- if (Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("Scrt1.o")));
- else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
- }
- }
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
- else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
- }
-
- Args.AddAllArgs(CmdArgs,
- {options::OPT_L, options::OPT_T_Group, options::OPT_e});
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- CmdArgs.push_back("-L/usr/lib/gcc50");
-
- if (!Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-rpath");
- CmdArgs.push_back("/usr/lib/gcc50");
- }
-
- if (D.CCCIsCXX()) {
- getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-lm");
- }
-
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
-
- if (!Args.hasArg(options::OPT_nolibc)) {
- CmdArgs.push_back("-lc");
- }
-
- if (Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_static_libgcc)) {
- CmdArgs.push_back("-lgcc");
- CmdArgs.push_back("-lgcc_eh");
- } else {
- if (Args.hasArg(options::OPT_shared_libgcc)) {
- CmdArgs.push_back("-lgcc_pic");
- if (!Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-lgcc");
- } else {
- CmdArgs.push_back("-lgcc");
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_pic");
- CmdArgs.push_back("--no-as-needed");
- }
- }
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtendS.o")));
- else
- CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
- CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o")));
- }
-
- getToolChain().addProfileRTLibs(Args, CmdArgs);
-
- const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-// Try to find Exe from a Visual Studio distribution. This first tries to find
-// an installed copy of Visual Studio and, failing that, looks in the PATH,
-// making sure that whatever executable that's found is not a same-named exe
-// from clang itself to prevent clang from falling back to itself.
-static std::string FindVisualStudioExecutable(const ToolChain &TC,
- const char *Exe,
- const char *ClangProgramPath) {
- const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
- std::string visualStudioBinDir;
- if (MSVC.getVisualStudioBinariesFolder(ClangProgramPath,
- visualStudioBinDir)) {
- SmallString<128> FilePath(visualStudioBinDir);
- llvm::sys::path::append(FilePath, Exe);
- if (llvm::sys::fs::can_execute(FilePath.c_str()))
- return FilePath.str();
- }
-
- return Exe;
-}
-
-void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
- const ToolChain &TC = getToolChain();
-
- assert((Output.isFilename() || Output.isNothing()) && "invalid output");
- if (Output.isFilename())
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-out:") + Output.getFilename()));
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
- !C.getDriver().IsCLMode())
- CmdArgs.push_back("-defaultlib:libcmt");
-
- if (!llvm::sys::Process::GetEnv("LIB")) {
- // If the VC environment hasn't been configured (perhaps because the user
- // did not run vcvarsall), try to build a consistent link environment. If
- // the environment variable is set however, assume the user knows what
- // they're doing.
- std::string VisualStudioDir;
- const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
- if (MSVC.getVisualStudioInstallDir(VisualStudioDir)) {
- SmallString<128> LibDir(VisualStudioDir);
- llvm::sys::path::append(LibDir, "VC", "lib");
- switch (MSVC.getArch()) {
- case llvm::Triple::x86:
- // x86 just puts the libraries directly in lib
- break;
- case llvm::Triple::x86_64:
- llvm::sys::path::append(LibDir, "amd64");
- break;
- case llvm::Triple::arm:
- llvm::sys::path::append(LibDir, "arm");
- break;
- default:
- break;
- }
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-libpath:") + LibDir.c_str()));
-
- if (MSVC.useUniversalCRT(VisualStudioDir)) {
- std::string UniversalCRTLibPath;
- if (MSVC.getUniversalCRTLibraryPath(UniversalCRTLibPath))
- CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
- UniversalCRTLibPath));
- }
- }
-
- std::string WindowsSdkLibPath;
- if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
- }
-
- if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
- for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
- CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
-
- CmdArgs.push_back("-nologo");
-
- if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7,
- options::OPT__SLASH_Zd))
- CmdArgs.push_back("-debug");
-
- bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd,
- options::OPT_shared);
- if (DLL) {
- CmdArgs.push_back(Args.MakeArgString("-dll"));
-
- SmallString<128> ImplibName(Output.getFilename());
- llvm::sys::path::replace_extension(ImplibName, "lib");
- CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
- }
-
- if (TC.getSanitizerArgs().needsAsanRt()) {
- CmdArgs.push_back(Args.MakeArgString("-debug"));
- CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
- if (TC.getSanitizerArgs().needsSharedAsanRt() ||
- Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
- for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
- // Make sure the dynamic runtime thunk is not optimized out at link time
- // to ensure proper SEH handling.
- CmdArgs.push_back(Args.MakeArgString(
- TC.getArch() == llvm::Triple::x86
- ? "-include:___asan_seh_interceptor"
- : "-include:__asan_seh_interceptor"));
- } else if (DLL) {
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
- } else {
- for (const auto &Lib : {"asan", "asan_cxx"})
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
- }
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
-
- if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
- options::OPT_fno_openmp, false)) {
- CmdArgs.push_back("-nodefaultlib:vcomp.lib");
- CmdArgs.push_back("-nodefaultlib:vcompd.lib");
- CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
- TC.getDriver().Dir + "/../lib"));
- switch (TC.getDriver().getOpenMPRuntime(Args)) {
- case Driver::OMPRT_OMP:
- CmdArgs.push_back("-defaultlib:libomp.lib");
- break;
- case Driver::OMPRT_IOMP5:
- CmdArgs.push_back("-defaultlib:libiomp5md.lib");
- break;
- case Driver::OMPRT_GOMP:
- break;
- case Driver::OMPRT_Unknown:
- // Already diagnosed.
- break;
- }
- }
-
- // Add compiler-rt lib in case if it was explicitly
- // specified as an argument for --rtlib option.
- if (!Args.hasArg(options::OPT_nostdlib)) {
- AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);
- }
-
- // Add filenames, libraries, and other linker inputs.
- for (const auto &Input : Inputs) {
- if (Input.isFilename()) {
- CmdArgs.push_back(Input.getFilename());
- continue;
- }
-
- const Arg &A = Input.getInputArg();
-
- // Render -l options differently for the MSVC linker.
- if (A.getOption().matches(options::OPT_l)) {
- StringRef Lib = A.getValue();
- const char *LinkLibArg;
- if (Lib.endswith(".lib"))
- LinkLibArg = Args.MakeArgString(Lib);
- else
- LinkLibArg = Args.MakeArgString(Lib + ".lib");
- CmdArgs.push_back(LinkLibArg);
- continue;
- }
-
- // Otherwise, this is some other kind of linker input option like -Wl, -z,
- // or -L. Render it, even if MSVC doesn't understand it.
- A.renderAsInput(Args, CmdArgs);
- }
-
- TC.addProfileRTLibs(Args, CmdArgs);
-
- // We need to special case some linker paths. In the case of lld, we need to
- // translate 'lld' into 'lld-link', and in the case of the regular msvc
- // linker, we need to use a special search algorithm.
- llvm::SmallString<128> linkPath;
- StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link");
- if (Linker.equals_lower("lld"))
- Linker = "lld-link";
-
- if (Linker.equals_lower("link")) {
- // If we're using the MSVC linker, it's not sufficient to just use link
- // from the program PATH, because other environments like GnuWin32 install
- // their own link.exe which may come first.
- linkPath = FindVisualStudioExecutable(TC, "link.exe",
- C.getDriver().getClangProgramPath());
- } else {
- linkPath = Linker;
- llvm::sys::path::replace_extension(linkPath, "exe");
- linkPath = TC.GetProgramPath(linkPath.c_str());
- }
-
- const char *Exec = Args.MakeArgString(linkPath);
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void visualstudio::Compiler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput));
-}
-
-std::unique_ptr<Command> visualstudio::Compiler::GetCommand(
- Compilation &C, const JobAction &JA, const InputInfo &Output,
- const InputInfoList &Inputs, const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
- CmdArgs.push_back("/nologo");
- CmdArgs.push_back("/c"); // Compile only.
- CmdArgs.push_back("/W0"); // No warnings.
-
- // The goal is to be able to invoke this tool correctly based on
- // any flag accepted by clang-cl.
-
- // These are spelled the same way in clang and cl.exe,.
- Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I});
-
- // Optimization level.
- if (Arg *A = Args.getLastArg(options::OPT_fbuiltin, options::OPT_fno_builtin))
- CmdArgs.push_back(A->getOption().getID() == options::OPT_fbuiltin ? "/Oi"
- : "/Oi-");
- if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) {
- if (A->getOption().getID() == options::OPT_O0) {
- CmdArgs.push_back("/Od");
- } else {
- CmdArgs.push_back("/Og");
-
- StringRef OptLevel = A->getValue();
- if (OptLevel == "s" || OptLevel == "z")
- CmdArgs.push_back("/Os");
- else
- CmdArgs.push_back("/Ot");
-
- CmdArgs.push_back("/Ob2");
- }
- }
- if (Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer,
- options::OPT_fno_omit_frame_pointer))
- CmdArgs.push_back(A->getOption().getID() == options::OPT_fomit_frame_pointer
- ? "/Oy"
- : "/Oy-");
- if (!Args.hasArg(options::OPT_fwritable_strings))
- CmdArgs.push_back("/GF");
-
- // Flags for which clang-cl has an alias.
- // FIXME: How can we ensure this stays in sync with relevant clang-cl options?
-
- if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR,
- /*default=*/false))
- CmdArgs.push_back("/GR-");
-
- if (Args.hasFlag(options::OPT__SLASH_GS_, options::OPT__SLASH_GS,
- /*default=*/false))
- CmdArgs.push_back("/GS-");
-
- if (Arg *A = Args.getLastArg(options::OPT_ffunction_sections,
- options::OPT_fno_function_sections))
- CmdArgs.push_back(A->getOption().getID() == options::OPT_ffunction_sections
- ? "/Gy"
- : "/Gy-");
- if (Arg *A = Args.getLastArg(options::OPT_fdata_sections,
- options::OPT_fno_data_sections))
- CmdArgs.push_back(
- A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-");
- if (Args.hasArg(options::OPT_fsyntax_only))
- CmdArgs.push_back("/Zs");
- if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only,
- options::OPT__SLASH_Z7))
- CmdArgs.push_back("/Z7");
-
- std::vector<std::string> Includes =
- Args.getAllArgValues(options::OPT_include);
- for (const auto &Include : Includes)
- CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Include));
-
- // Flags that can simply be passed through.
- Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD);
- Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd);
- Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX);
- Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX_);
- Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH);
- Args.AddAllArgs(CmdArgs, options::OPT__SLASH_Zl);
-
- // The order of these flags is relevant, so pick the last one.
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd,
- options::OPT__SLASH_MT, options::OPT__SLASH_MTd))
- A->render(Args, CmdArgs);
-
- // Use MSVC's default threadsafe statics behaviour unless there was a flag.
- if (Arg *A = Args.getLastArg(options::OPT_fthreadsafe_statics,
- options::OPT_fno_threadsafe_statics)) {
- CmdArgs.push_back(A->getOption().getID() == options::OPT_fthreadsafe_statics
- ? "/Zc:threadSafeInit"
- : "/Zc:threadSafeInit-");
- }
-
- // Pass through all unknown arguments so that the fallback command can see
- // them too.
- Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN);
-
- // Input filename.
- assert(Inputs.size() == 1);
- const InputInfo &II = Inputs[0];
- assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX);
- CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp");
- if (II.isFilename())
- CmdArgs.push_back(II.getFilename());
- else
- II.getInputArg().renderAsInput(Args, CmdArgs);
-
- // Output filename.
- assert(Output.getType() == types::TY_Object);
- const char *Fo =
- Args.MakeArgString(std::string("/Fo") + Output.getFilename());
- CmdArgs.push_back(Fo);
-
- const Driver &D = getToolChain().getDriver();
- std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe",
- D.getClangProgramPath());
- return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
- CmdArgs, Inputs);
-}
-
-/// MinGW Tools
-void MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- if (getToolChain().getArch() == llvm::Triple::x86) {
- CmdArgs.push_back("--32");
- } else if (getToolChain().getArch() == llvm::Triple::x86_64) {
- CmdArgs.push_back("--64");
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-
- if (Args.hasArg(options::OPT_gsplit_dwarf))
- SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
- SplitDebugName(Args, Inputs[0]));
-}
-
-void MinGW::Linker::AddLibGCC(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- if (Args.hasArg(options::OPT_mthreads))
- CmdArgs.push_back("-lmingwthrd");
- CmdArgs.push_back("-lmingw32");
-
- // Make use of compiler-rt if --rtlib option is used
- ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args);
- if (RLT == ToolChain::RLT_Libgcc) {
- bool Static = Args.hasArg(options::OPT_static_libgcc) ||
- Args.hasArg(options::OPT_static);
- bool Shared = Args.hasArg(options::OPT_shared);
- bool CXX = getToolChain().getDriver().CCCIsCXX();
-
- if (Static || (!CXX && !Shared)) {
- CmdArgs.push_back("-lgcc");
- CmdArgs.push_back("-lgcc_eh");
- } else {
- CmdArgs.push_back("-lgcc_s");
- CmdArgs.push_back("-lgcc");
- }
- } else {
- AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args);
- }
-
- CmdArgs.push_back("-lmoldname");
- CmdArgs.push_back("-lmingwex");
- CmdArgs.push_back("-lmsvcrt");
-}
-
-void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const ToolChain &TC = getToolChain();
- const Driver &D = TC.getDriver();
- // const SanitizerArgs &Sanitize = TC.getSanitizerArgs();
-
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- StringRef LinkerName = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "ld");
- if (LinkerName.equals_lower("lld")) {
- CmdArgs.push_back("-flavor");
- CmdArgs.push_back("gnu");
- } else if (!LinkerName.equals_lower("ld")) {
- D.Diag(diag::err_drv_unsupported_linker) << LinkerName;
- }
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- if (Args.hasArg(options::OPT_s))
- CmdArgs.push_back("-s");
-
- CmdArgs.push_back("-m");
- if (TC.getArch() == llvm::Triple::x86)
- CmdArgs.push_back("i386pe");
- if (TC.getArch() == llvm::Triple::x86_64)
- CmdArgs.push_back("i386pep");
- if (TC.getArch() == llvm::Triple::arm)
- CmdArgs.push_back("thumb2pe");
-
- if (Args.hasArg(options::OPT_mwindows)) {
- CmdArgs.push_back("--subsystem");
- CmdArgs.push_back("windows");
- } else if (Args.hasArg(options::OPT_mconsole)) {
- CmdArgs.push_back("--subsystem");
- CmdArgs.push_back("console");
- }
-
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("-Bstatic");
- else {
- if (Args.hasArg(options::OPT_mdll))
- CmdArgs.push_back("--dll");
- else if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("--shared");
- CmdArgs.push_back("-Bdynamic");
- if (Args.hasArg(options::OPT_mdll) || Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-e");
- if (TC.getArch() == llvm::Triple::x86)
- CmdArgs.push_back("_DllMainCRTStartup@12");
- else
- CmdArgs.push_back("DllMainCRTStartup");
- CmdArgs.push_back("--enable-auto-image-base");
- }
- }
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- Args.AddAllArgs(CmdArgs, options::OPT_e);
- // FIXME: add -N, -n flags
- Args.AddLastArg(CmdArgs, options::OPT_r);
- Args.AddLastArg(CmdArgs, options::OPT_s);
- Args.AddLastArg(CmdArgs, options::OPT_t);
- Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
- Args.AddLastArg(CmdArgs, options::OPT_Z_Flag);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) {
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o")));
- } else {
- if (Args.hasArg(options::OPT_municode))
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2u.o")));
- else
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2.o")));
- }
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("gcrt2.o")));
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o")));
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- TC.AddFilePathLibArgs(Args, CmdArgs);
- AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
-
- // TODO: Add ASan stuff here
-
- // TODO: Add profile stuff here
-
- if (D.CCCIsCXX() &&
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
- !Args.hasArg(options::OPT_static);
- if (OnlyLibstdcxxStatic)
- CmdArgs.push_back("-Bstatic");
- TC.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (OnlyLibstdcxxStatic)
- CmdArgs.push_back("-Bdynamic");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib)) {
- if (!Args.hasArg(options::OPT_nodefaultlibs)) {
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("--start-group");
-
- if (Args.hasArg(options::OPT_fstack_protector) ||
- Args.hasArg(options::OPT_fstack_protector_strong) ||
- Args.hasArg(options::OPT_fstack_protector_all)) {
- CmdArgs.push_back("-lssp_nonshared");
- CmdArgs.push_back("-lssp");
- }
- if (Args.hasArg(options::OPT_fopenmp))
- CmdArgs.push_back("-lgomp");
-
- AddLibGCC(Args, CmdArgs);
-
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lgmon");
-
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-lpthread");
-
- // add system libraries
- if (Args.hasArg(options::OPT_mwindows)) {
- CmdArgs.push_back("-lgdi32");
- CmdArgs.push_back("-lcomdlg32");
- }
- CmdArgs.push_back("-ladvapi32");
- CmdArgs.push_back("-lshell32");
- CmdArgs.push_back("-luser32");
- CmdArgs.push_back("-lkernel32");
-
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("--end-group");
- else if (!LinkerName.equals_lower("lld"))
- AddLibGCC(Args, CmdArgs);
- }
-
- if (!Args.hasArg(options::OPT_nostartfiles)) {
- // Add crtfastmath.o if available and fast math is enabled.
- TC.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
-
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o")));
- }
- }
- const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerName.data()));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-/// XCore Tools
-// We pass assemble and link construction to the xcc tool.
-
-void XCore::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- CmdArgs.push_back("-c");
-
- if (Args.hasArg(options::OPT_v))
- CmdArgs.push_back("-v");
-
- if (Arg *A = Args.getLastArg(options::OPT_g_Group))
- if (!A->getOption().matches(options::OPT_g0))
- CmdArgs.push_back("-g");
-
- if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
- false))
- CmdArgs.push_back("-fverbose-asm");
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- for (const auto &II : Inputs)
- CmdArgs.push_back(II.getFilename());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- if (Args.hasArg(options::OPT_v))
- CmdArgs.push_back("-v");
-
- // Pass -fexceptions through to the linker if it was present.
- if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
- false))
- CmdArgs.push_back("-fexceptions");
-
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void CrossWindows::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- const auto &TC =
- static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
- ArgStringList CmdArgs;
- const char *Exec;
-
- switch (TC.getArch()) {
- default:
- llvm_unreachable("unsupported architecture");
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- break;
- case llvm::Triple::x86:
- CmdArgs.push_back("--32");
- break;
- case llvm::Triple::x86_64:
- CmdArgs.push_back("--64");
- break;
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- for (const auto &Input : Inputs)
- CmdArgs.push_back(Input.getFilename());
-
- const std::string Assembler = TC.GetProgramPath("as");
- Exec = Args.MakeArgString(Assembler);
-
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void CrossWindows::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const auto &TC =
- static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain());
- const llvm::Triple &T = TC.getTriple();
- const Driver &D = TC.getDriver();
- SmallString<128> EntryPoint;
- ArgStringList CmdArgs;
- const char *Exec;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_w);
- // Other warning options are already handled somewhere else.
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- if (Args.hasArg(options::OPT_pie))
- CmdArgs.push_back("-pie");
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- if (Args.hasArg(options::OPT_s))
- CmdArgs.push_back("--strip-all");
-
- CmdArgs.push_back("-m");
- switch (TC.getArch()) {
- default:
- llvm_unreachable("unsupported architecture");
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- // FIXME: this is incorrect for WinCE
- CmdArgs.push_back("thumb2pe");
- break;
- case llvm::Triple::x86:
- CmdArgs.push_back("i386pe");
- EntryPoint.append("_");
- break;
- case llvm::Triple::x86_64:
- CmdArgs.push_back("i386pep");
- break;
- }
-
- if (Args.hasArg(options::OPT_shared)) {
- switch (T.getArch()) {
- default:
- llvm_unreachable("unsupported architecture");
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- case llvm::Triple::x86_64:
- EntryPoint.append("_DllMainCRTStartup");
- break;
- case llvm::Triple::x86:
- EntryPoint.append("_DllMainCRTStartup@12");
- break;
- }
-
- CmdArgs.push_back("-shared");
- CmdArgs.push_back("-Bdynamic");
-
- CmdArgs.push_back("--enable-auto-image-base");
-
- CmdArgs.push_back("--entry");
- CmdArgs.push_back(Args.MakeArgString(EntryPoint));
- } else {
- EntryPoint.append("mainCRTStartup");
-
- CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic"
- : "-Bdynamic");
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- CmdArgs.push_back("--entry");
- CmdArgs.push_back(Args.MakeArgString(EntryPoint));
- }
-
- // FIXME: handle subsystem
- }
-
- // NOTE: deal with multiple definitions on Windows (e.g. COMDAT)
- CmdArgs.push_back("--allow-multiple-definition");
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) {
- SmallString<261> ImpLib(Output.getFilename());
- llvm::sys::path::replace_extension(ImpLib, ".lib");
-
- CmdArgs.push_back("--out-implib");
- CmdArgs.push_back(Args.MakeArgString(ImpLib));
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- const std::string CRTPath(D.SysRoot + "/usr/lib/");
- const char *CRTBegin;
-
- CRTBegin =
- Args.hasArg(options::OPT_shared) ? "crtbeginS.obj" : "crtbegin.obj";
- CmdArgs.push_back(Args.MakeArgString(CRTPath + CRTBegin));
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- TC.AddFilePathLibArgs(Args, CmdArgs);
- AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
-
- if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nodefaultlibs)) {
- bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) &&
- !Args.hasArg(options::OPT_static);
- if (StaticCXX)
- CmdArgs.push_back("-Bstatic");
- TC.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (StaticCXX)
- CmdArgs.push_back("-Bdynamic");
- }
-
- if (!Args.hasArg(options::OPT_nostdlib)) {
- if (!Args.hasArg(options::OPT_nodefaultlibs)) {
- // TODO handle /MT[d] /MD[d]
- CmdArgs.push_back("-lmsvcrt");
- AddRunTimeLibs(TC, D, CmdArgs, Args);
- }
- }
-
- if (TC.getSanitizerArgs().needsAsanRt()) {
- // TODO handle /MT[d] /MD[d]
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
- } else {
- for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
- // Make sure the dynamic runtime thunk is not optimized out at link time
- // to ensure proper SEH handling.
- CmdArgs.push_back(Args.MakeArgString("--undefined"));
- CmdArgs.push_back(Args.MakeArgString(TC.getArch() == llvm::Triple::x86
- ? "___asan_seh_interceptor"
- : "__asan_seh_interceptor"));
- }
- }
-
- Exec = Args.MakeArgString(TC.GetLinkerPath());
-
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
- assert(Inputs.size() == 1);
- const InputInfo &II = Inputs[0];
- assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX ||
- II.getType() == types::TY_PP_CXX);
-
- if (JA.getKind() == Action::PreprocessJobClass) {
- Args.ClaimAllArgs();
- CmdArgs.push_back("-E");
- } else {
- assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm.
- CmdArgs.push_back("-S");
- CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified.
- }
- CmdArgs.push_back("-DMYRIAD2");
-
- // Append all -I, -iquote, -isystem paths, defines/undefines,
- // 'f' flags, optimize flags, and warning options.
- // These are spelled the same way in clang and moviCompile.
- Args.AddAllArgsExcept(
- CmdArgs,
- {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ,
- options::OPT_D, options::OPT_U, options::OPT_f_Group,
- options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group,
- options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ},
- {options::OPT_fno_split_dwarf_inlining});
- Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present.
-
- // If we're producing a dependency file, and assembly is the final action,
- // then the name of the target in the dependency file should be the '.o'
- // file, not the '.s' file produced by this step. For example, instead of
- // /tmp/mumble.s: mumble.c .../someheader.h
- // the filename on the lefthand side should be "mumble.o"
- if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) &&
- C.getActions().size() == 1 &&
- C.getActions()[0]->getKind() == Action::AssembleJobClass) {
- Arg *A = Args.getLastArg(options::OPT_o);
- if (A) {
- CmdArgs.push_back("-MT");
- CmdArgs.push_back(Args.MakeArgString(A->getValue()));
- }
- }
-
- CmdArgs.push_back(II.getFilename());
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- std::string Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("moviCompile"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
- CmdArgs, Inputs));
-}
-
-void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- assert(Inputs.size() == 1);
- const InputInfo &II = Inputs[0];
- assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input.
- assert(Output.getType() == types::TY_Object);
-
- CmdArgs.push_back("-no6thSlotCompression");
- const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ);
- if (CPUArg)
- CmdArgs.push_back(
- Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue())));
- CmdArgs.push_back("-noSPrefixing");
- CmdArgs.push_back("-a"); // Mystery option.
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
- for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) {
- A->claim();
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-i:") + A->getValue(0)));
- }
- CmdArgs.push_back("-elf"); // Output format.
- CmdArgs.push_back(II.getFilename());
- CmdArgs.push_back(
- Args.MakeArgString(std::string("-o:") + Output.getFilename()));
-
- std::string Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("moviAsm"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
- CmdArgs, Inputs));
-}
-
-void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const auto &TC =
- static_cast<const toolchains::MyriadToolChain &>(getToolChain());
- const llvm::Triple &T = TC.getTriple();
- ArgStringList CmdArgs;
- bool UseStartfiles =
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
- bool UseDefaultLibs =
- !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs);
- // Silence warning if the args contain both -nostdlib and -stdlib=.
- Args.getLastArg(options::OPT_stdlib_EQ);
-
- if (T.getArch() == llvm::Triple::sparc)
- CmdArgs.push_back("-EB");
- else // SHAVE assumes little-endian, and sparcel is expressly so.
- CmdArgs.push_back("-EL");
-
- // The remaining logic is mostly like gnutools::Linker::ConstructJob,
- // but we never pass through a --sysroot option and various other bits.
- // For example, there are no sanitizers (yet) nor gold linker.
-
- // Eat some arguments that may be present but have no effect.
- Args.ClaimAllArgs(options::OPT_g_Group);
- Args.ClaimAllArgs(options::OPT_w);
- Args.ClaimAllArgs(options::OPT_static_libgcc);
-
- if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option.
- CmdArgs.push_back("-s");
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- if (UseStartfiles) {
- // If you want startfiles, it means you want the builtin crti and crtbegin,
- // but not crt0. Myriad link commands provide their own crt0.o as needed.
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o")));
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o")));
- }
-
- Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
- options::OPT_e, options::OPT_s, options::OPT_t,
- options::OPT_Z_Flag, options::OPT_r});
-
- TC.AddFilePathLibArgs(Args, CmdArgs);
-
- bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs);
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
-
- if (UseDefaultLibs) {
- if (NeedsSanitizerDeps)
- linkSanitizerRuntimeDeps(TC, CmdArgs);
- if (C.getDriver().CCCIsCXX()) {
- if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) {
- CmdArgs.push_back("-lc++");
- CmdArgs.push_back("-lc++abi");
- } else
- CmdArgs.push_back("-lstdc++");
- }
- if (T.getOS() == llvm::Triple::RTEMS) {
- CmdArgs.push_back("--start-group");
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lgcc"); // circularly dependent on rtems
- // You must provide your own "-L" option to enable finding these.
- CmdArgs.push_back("-lrtemscpu");
- CmdArgs.push_back("-lrtemsbsp");
- CmdArgs.push_back("--end-group");
- } else {
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lgcc");
- }
- }
- if (UseStartfiles) {
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o")));
- CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o")));
- }
-
- std::string Exec =
- Args.MakeArgString(TC.GetProgramPath("sparc-myriad-elf-ld"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
- CmdArgs, Inputs));
-}
-
-void PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- claimNoWarnArgs(Args);
- ArgStringList CmdArgs;
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
-
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
- assert(Inputs.size() == 1 && "Unexpected number of inputs.");
- const InputInfo &Input = Inputs[0];
- assert(Input.isFilename() && "Invalid input.");
- CmdArgs.push_back(Input.getFilename());
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("orbis-as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) {
- const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
- if (SanArgs.needsUbsanRt()) {
- CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak");
- }
- if (SanArgs.needsAsanRt()) {
- CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak");
- }
-}
-
-static void ConstructPS4LinkJob(const Tool &T, Compilation &C,
- const JobAction &JA, const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) {
- const toolchains::FreeBSD &ToolChain =
- static_cast<const toolchains::FreeBSD &>(T.getToolChain());
- const Driver &D = ToolChain.getDriver();
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- if (Args.hasArg(options::OPT_pie))
- CmdArgs.push_back("-pie");
-
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("--oformat=so");
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- AddPS4SanitizerArgs(ToolChain, CmdArgs);
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_e);
- Args.AddAllArgs(CmdArgs, options::OPT_s);
- Args.AddAllArgs(CmdArgs, options::OPT_t);
- Args.AddAllArgs(CmdArgs, options::OPT_r);
-
- if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
- CmdArgs.push_back("--no-demangle");
-
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
-
- if (Args.hasArg(options::OPT_pthread)) {
- CmdArgs.push_back("-lpthread");
- }
-
- const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
-
- C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
-}
-
-static void ConstructGoldLinkJob(const Tool &T, Compilation &C,
- const JobAction &JA, const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) {
- const toolchains::FreeBSD &ToolChain =
- static_cast<const toolchains::FreeBSD &>(T.getToolChain());
- const Driver &D = ToolChain.getDriver();
- ArgStringList CmdArgs;
-
- // Silence warning for "clang -g foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_g_Group);
- // and "clang -emit-llvm foo.o -o foo"
- Args.ClaimAllArgs(options::OPT_emit_llvm);
- // and for "clang -w foo.o -o foo". Other warning options are already
- // handled somewhere else.
- Args.ClaimAllArgs(options::OPT_w);
-
- if (!D.SysRoot.empty())
- CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
-
- if (Args.hasArg(options::OPT_pie))
- CmdArgs.push_back("-pie");
-
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-Bstatic");
- } else {
- if (Args.hasArg(options::OPT_rdynamic))
- CmdArgs.push_back("-export-dynamic");
- CmdArgs.push_back("--eh-frame-hdr");
- if (Args.hasArg(options::OPT_shared)) {
- CmdArgs.push_back("-Bshareable");
- } else {
- CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back("/libexec/ld-elf.so.1");
- }
- CmdArgs.push_back("--enable-new-dtags");
- }
-
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- } else {
- assert(Output.isNothing() && "Invalid output.");
- }
-
- AddPS4SanitizerArgs(ToolChain, CmdArgs);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- const char *crt1 = nullptr;
- if (!Args.hasArg(options::OPT_shared)) {
- if (Args.hasArg(options::OPT_pg))
- crt1 = "gcrt1.o";
- else if (Args.hasArg(options::OPT_pie))
- crt1 = "Scrt1.o";
- else
- crt1 = "crt1.o";
- }
- if (crt1)
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
-
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
-
- const char *crtbegin = nullptr;
- if (Args.hasArg(options::OPT_static))
- crtbegin = "crtbeginT.o";
- else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
- crtbegin = "crtbeginS.o";
- else
- crtbegin = "crtbegin.o";
-
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_L);
- ToolChain.AddFilePathLibArgs(Args, CmdArgs);
- Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_e);
- Args.AddAllArgs(CmdArgs, options::OPT_s);
- Args.AddAllArgs(CmdArgs, options::OPT_t);
- Args.AddAllArgs(CmdArgs, options::OPT_r);
-
- if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
- CmdArgs.push_back("--no-demangle");
-
- AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- // For PS4, we always want to pass libm, libstdc++ and libkernel
- // libraries for both C and C++ compilations.
- CmdArgs.push_back("-lkernel");
- if (D.CCCIsCXX()) {
- ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lm_p");
- else
- CmdArgs.push_back("-lm");
- }
- // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
- // the default system libraries. Just mimic this for now.
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lgcc_p");
- else
- CmdArgs.push_back("-lcompiler_rt");
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-lstdc++");
- } else if (Args.hasArg(options::OPT_pg)) {
- CmdArgs.push_back("-lgcc_eh_p");
- } else {
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lstdc++");
- CmdArgs.push_back("--no-as-needed");
- }
-
- if (Args.hasArg(options::OPT_pthread)) {
- if (Args.hasArg(options::OPT_pg))
- CmdArgs.push_back("-lpthread_p");
- else
- CmdArgs.push_back("-lpthread");
- }
-
- if (Args.hasArg(options::OPT_pg)) {
- if (Args.hasArg(options::OPT_shared))
- CmdArgs.push_back("-lc");
- else {
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("--start-group");
- CmdArgs.push_back("-lc_p");
- CmdArgs.push_back("-lpthread_p");
- CmdArgs.push_back("--end-group");
- } else {
- CmdArgs.push_back("-lc_p");
- }
- }
- CmdArgs.push_back("-lgcc_p");
- } else {
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("--start-group");
- CmdArgs.push_back("-lc");
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("--end-group");
- } else {
- CmdArgs.push_back("-lc");
- }
- CmdArgs.push_back("-lcompiler_rt");
- }
-
- if (Args.hasArg(options::OPT_static)) {
- CmdArgs.push_back("-lstdc++");
- } else if (Args.hasArg(options::OPT_pg)) {
- CmdArgs.push_back("-lgcc_eh_p");
- } else {
- CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lstdc++");
- CmdArgs.push_back("--no-as-needed");
- }
- }
-
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
- else
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
- CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
- }
-
- const char *Exec =
-#ifdef LLVM_ON_WIN32
- Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold"));
-#else
- Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
-#endif
-
- C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
-}
-
-void PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const toolchains::FreeBSD &ToolChain =
- static_cast<const toolchains::FreeBSD &>(getToolChain());
- const Driver &D = ToolChain.getDriver();
- bool PS4Linker;
- StringRef LinkerOptName;
- if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
- LinkerOptName = A->getValue();
- if (LinkerOptName != "ps4" && LinkerOptName != "gold")
- D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName;
- }
-
- if (LinkerOptName == "gold")
- PS4Linker = false;
- else if (LinkerOptName == "ps4")
- PS4Linker = true;
- else
- PS4Linker = !Args.hasArg(options::OPT_shared);
-
- if (PS4Linker)
- ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput);
- else
- ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput);
-}
-
-void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const auto &TC =
- static_cast<const toolchains::CudaToolChain &>(getToolChain());
- assert(TC.getTriple().isNVPTX() && "Wrong platform");
-
- // Obtain architecture from the action.
- CudaArch gpu_arch = StringToCudaArch(JA.getOffloadingArch());
- assert(gpu_arch != CudaArch::UNKNOWN &&
- "Device action expected to have an architecture.");
-
- // Check that our installation's ptxas supports gpu_arch.
- if (!Args.hasArg(options::OPT_no_cuda_version_check)) {
- TC.CudaInstallation.CheckCudaVersionSupportsArch(gpu_arch);
- }
-
- ArgStringList CmdArgs;
- CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32");
- if (Args.hasFlag(options::OPT_cuda_noopt_device_debug,
- options::OPT_no_cuda_noopt_device_debug, false)) {
- // ptxas does not accept -g option if optimization is enabled, so
- // we ignore the compiler's -O* options if we want debug info.
- CmdArgs.push_back("-g");
- CmdArgs.push_back("--dont-merge-basicblocks");
- CmdArgs.push_back("--return-at-end");
- } else if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- // Map the -O we received to -O{0,1,2,3}.
- //
- // TODO: Perhaps we should map host -O2 to ptxas -O3. -O3 is ptxas's
- // default, so it may correspond more closely to the spirit of clang -O2.
-
- // -O3 seems like the least-bad option when -Osomething is specified to
- // clang but it isn't handled below.
- StringRef OOpt = "3";
- if (A->getOption().matches(options::OPT_O4) ||
- A->getOption().matches(options::OPT_Ofast))
- OOpt = "3";
- else if (A->getOption().matches(options::OPT_O0))
- OOpt = "0";
- else if (A->getOption().matches(options::OPT_O)) {
- // -Os, -Oz, and -O(anything else) map to -O2, for lack of better options.
- OOpt = llvm::StringSwitch<const char *>(A->getValue())
- .Case("1", "1")
- .Case("2", "2")
- .Case("3", "3")
- .Case("s", "2")
- .Case("z", "2")
- .Default("2");
- }
- CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
- } else {
- // If no -O was passed, pass -O0 to ptxas -- no opt flag should correspond
- // to no optimizations, but ptxas's default is -O3.
- CmdArgs.push_back("-O0");
- }
-
- CmdArgs.push_back("--gpu-name");
- CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch)));
- CmdArgs.push_back("--output-file");
- CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
- for (const auto& II : Inputs)
- CmdArgs.push_back(Args.MakeArgString(II.getFilename()));
-
- for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
- CmdArgs.push_back(Args.MakeArgString(A));
-
- const char *Exec;
- if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ))
- Exec = A->getValue();
- else
- Exec = Args.MakeArgString(TC.GetProgramPath("ptxas"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-// All inputs to this linker must be from CudaDeviceActions, as we need to look
-// at the Inputs' Actions in order to figure out which GPU architecture they
-// correspond to.
-void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const auto &TC =
- static_cast<const toolchains::CudaToolChain &>(getToolChain());
- assert(TC.getTriple().isNVPTX() && "Wrong platform");
-
- ArgStringList CmdArgs;
- CmdArgs.push_back("--cuda");
- CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-64" : "-32");
- CmdArgs.push_back(Args.MakeArgString("--create"));
- CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
-
- for (const auto& II : Inputs) {
- auto *A = II.getAction();
- assert(A->getInputs().size() == 1 &&
- "Device offload action is expected to have a single input");
- const char *gpu_arch_str = A->getOffloadingArch();
- assert(gpu_arch_str &&
- "Device action expected to have associated a GPU architecture!");
- CudaArch gpu_arch = StringToCudaArch(gpu_arch_str);
-
- // We need to pass an Arch of the form "sm_XX" for cubin files and
- // "compute_XX" for ptx.
- const char *Arch =
- (II.getType() == types::TY_PP_Asm)
- ? CudaVirtualArchToString(VirtualArchForCudaArch(gpu_arch))
- : gpu_arch_str;
- CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") +
- Arch + ",file=" + II.getFilename()));
- }
-
- for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary))
- CmdArgs.push_back(Args.MakeArgString(A));
-
- const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
-}
-
-void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
-
- std::string Linker = getToolChain().GetProgramPath(getShortName());
- ArgStringList CmdArgs;
- AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
- CmdArgs, Inputs));
-}
-// AVR tools end.
diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.h b/contrib/llvm/tools/clang/lib/Driver/Tools.h
deleted file mode 100644
index 9d5b892..0000000
--- a/contrib/llvm/tools/clang/lib/Driver/Tools.h
+++ /dev/null
@@ -1,1010 +0,0 @@
-//===--- Tools.h - Tool Implementations -------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_DRIVER_TOOLS_H
-#define LLVM_CLANG_LIB_DRIVER_TOOLS_H
-
-#include "clang/Basic/DebugInfoOptions.h"
-#include "clang/Basic/VersionTuple.h"
-#include "clang/Driver/Tool.h"
-#include "clang/Driver/Types.h"
-#include "clang/Driver/Util.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Compiler.h"
-
-namespace clang {
-class ObjCRuntime;
-
-namespace driver {
-class Command;
-class Driver;
-
-namespace toolchains {
-class MachO;
-}
-
-namespace tools {
-
-namespace visualstudio {
-class Compiler;
-}
-
-using llvm::opt::ArgStringList;
-
-SmallString<128> getCompilerRT(const ToolChain &TC,
- const llvm::opt::ArgList &Args,
- StringRef Component, bool Shared = false);
-
-/// \brief Clang compiler tool.
-class LLVM_LIBRARY_VISIBILITY Clang : public Tool {
-public:
- static const char *getBaseInputName(const llvm::opt::ArgList &Args,
- const InputInfo &Input);
- static const char *getBaseInputStem(const llvm::opt::ArgList &Args,
- const InputInfoList &Inputs);
- static const char *getDependencyFileName(const llvm::opt::ArgList &Args,
- const InputInfoList &Inputs);
-
-private:
- void AddPreprocessingOptions(Compilation &C, const JobAction &JA,
- const Driver &D, const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
- const InputInfo &Output,
- const InputInfoList &Inputs) const;
-
- void AddAArch64TargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddARMTargetArgs(const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
- bool KernelOrKext) const;
- void AddARM64TargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddPPCTargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddR600TargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddSparcTargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddSystemZTargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddX86TargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddHexagonTargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddLanaiTargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
-
- enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile };
-
- ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args,
- llvm::opt::ArgStringList &cmdArgs,
- RewriteKind rewrite) const;
-
- void AddClangCLArgs(const llvm::opt::ArgList &Args, types::ID InputType,
- llvm::opt::ArgStringList &CmdArgs,
- codegenoptions::DebugInfoKind *DebugInfoKind,
- bool *EmitCodeView) const;
-
- visualstudio::Compiler *getCLFallback() const;
-
- mutable std::unique_ptr<visualstudio::Compiler> CLFallback;
-
- mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr;
- void DumpCompilationDatabase(Compilation &C, StringRef Filename,
- StringRef Target,
- const InputInfo &Output, const InputInfo &Input,
- const llvm::opt::ArgList &Args) const;
-
-public:
- // CAUTION! The first constructor argument ("clang") is not arbitrary,
- // as it is for other tools. Some operations on a Tool actually test
- // whether that tool is Clang based on the Tool's Name as a string.
- Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC, RF_Full) {}
-
- bool hasGoodDiagnostics() const override { return true; }
- bool hasIntegratedAssembler() const override { return true; }
- bool hasIntegratedCPP() const override { return true; }
- bool canEmitIR() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-/// \brief Clang integrated assembler tool.
-class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
-public:
- ClangAs(const ToolChain &TC)
- : Tool("clang::as", "clang integrated assembler", TC, RF_Full) {}
- void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddX86TargetArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- bool hasGoodDiagnostics() const override { return true; }
- bool hasIntegratedAssembler() const override { return false; }
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-/// Offload bundler tool.
-class LLVM_LIBRARY_VISIBILITY OffloadBundler final : public Tool {
-public:
- OffloadBundler(const ToolChain &TC)
- : Tool("offload bundler", "clang-offload-bundler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
- void ConstructJobMultipleOutputs(Compilation &C, const JobAction &JA,
- const InputInfoList &Outputs,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-/// \brief Base class for all GNU tools that provide the same behavior when
-/// it comes to response files support
-class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool {
- virtual void anchor();
-
-public:
- GnuTool(const char *Name, const char *ShortName, const ToolChain &TC)
- : Tool(Name, ShortName, TC, RF_Full, llvm::sys::WEM_CurrentCodePage) {}
-};
-
-/// gcc - Generic GCC tool implementations.
-namespace gcc {
-class LLVM_LIBRARY_VISIBILITY Common : public GnuTool {
-public:
- Common(const char *Name, const char *ShortName, const ToolChain &TC)
- : GnuTool(Name, ShortName, TC) {}
-
- // A gcc tool has an "integrated" assembler that it will call to produce an
- // object. Let it use that assembler so that we don't have to deal with
- // assembly syntax incompatibilities.
- bool hasIntegratedAssembler() const override { return true; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-
- /// RenderExtraToolArgs - Render any arguments necessary to force
- /// the particular tool mode.
- virtual void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const = 0;
-};
-
-class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common {
-public:
- Preprocessor(const ToolChain &TC)
- : Common("gcc::Preprocessor", "gcc preprocessor", TC) {}
-
- bool hasGoodDiagnostics() const override { return true; }
- bool hasIntegratedCPP() const override { return false; }
-
- void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Compiler : public Common {
-public:
- Compiler(const ToolChain &TC) : Common("gcc::Compiler", "gcc frontend", TC) {}
-
- bool hasGoodDiagnostics() const override { return true; }
- bool hasIntegratedCPP() const override { return true; }
-
- void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public Common {
-public:
- Linker(const ToolChain &TC) : Common("gcc::Linker", "linker (via gcc)", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const override;
-};
-} // end namespace gcc
-
-namespace hexagon {
-// For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile
-// and Compile.
-// We simply use "clang -cc1" for those actions.
-class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
-public:
- Assembler(const ToolChain &TC)
- : GnuTool("hexagon::Assembler", "hexagon-as", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const;
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("hexagon::Linker", "hexagon-ld", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- virtual void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const;
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace hexagon.
-
-namespace amdgpu {
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "ld.lld", TC) {}
- bool isLinkJob() const override { return true; }
- bool hasIntegratedCPP() const override { return false; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-} // end namespace amdgpu
-
-namespace wasm {
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- explicit Linker(const ToolChain &TC);
- bool isLinkJob() const override;
- bool hasIntegratedCPP() const override;
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-} // end namespace wasm
-
-namespace arm {
-std::string getARMTargetCPU(StringRef CPU, StringRef Arch,
- const llvm::Triple &Triple);
-const std::string getARMArch(StringRef Arch,
- const llvm::Triple &Triple);
-StringRef getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple);
-StringRef getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch,
- const llvm::Triple &Triple);
-
-void appendEBLinkFlags(const llvm::opt::ArgList &Args, ArgStringList &CmdArgs,
- const llvm::Triple &Triple);
-} // end namespace arm
-
-namespace mips {
-typedef enum { NanLegacy = 1, Nan2008 = 2 } NanEncoding;
-
-enum class FloatABI {
- Invalid,
- Soft,
- Hard,
-};
-
-NanEncoding getSupportedNanEncoding(StringRef &CPU);
-bool hasCompactBranches(StringRef &CPU);
-void getMipsCPUAndABI(const llvm::opt::ArgList &Args,
- const llvm::Triple &Triple, StringRef &CPUName,
- StringRef &ABIName);
-std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args,
- const llvm::Triple &Triple);
-bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value);
-bool isUCLibc(const llvm::opt::ArgList &Args);
-bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple);
-bool isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName);
-bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
- StringRef ABIName, mips::FloatABI FloatABI);
-bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple,
- StringRef CPUName, StringRef ABIName,
- mips::FloatABI FloatABI);
-} // end namespace mips
-
-namespace ppc {
-bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value);
-} // end namespace ppc
-
-/// cloudabi -- Directly call GNU Binutils linker
-namespace cloudabi {
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("cloudabi::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace cloudabi
-
-namespace darwin {
-llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str);
-void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str);
-
-class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool {
- virtual void anchor();
-
-protected:
- void AddMachOArch(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
-
- const toolchains::MachO &getMachOToolChain() const {
- return reinterpret_cast<const toolchains::MachO &>(getToolChain());
- }
-
-public:
- MachOTool(
- const char *Name, const char *ShortName, const ToolChain &TC,
- ResponseFileSupport ResponseSupport = RF_None,
- llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8,
- const char *ResponseFlag = "@")
- : Tool(Name, ShortName, TC, ResponseSupport, ResponseEncoding,
- ResponseFlag) {}
-};
-
-class LLVM_LIBRARY_VISIBILITY Assembler : public MachOTool {
-public:
- Assembler(const ToolChain &TC)
- : MachOTool("darwin::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public MachOTool {
- bool NeedsTempPath(const InputInfoList &Inputs) const;
- void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
- const InputInfoList &Inputs) const;
-
-public:
- Linker(const ToolChain &TC)
- : MachOTool("darwin::Linker", "linker", TC, RF_FileList,
- llvm::sys::WEM_UTF8, "-filelist") {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool {
-public:
- Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Dsymutil : public MachOTool {
-public:
- Dsymutil(const ToolChain &TC)
- : MachOTool("darwin::Dsymutil", "dsymutil", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isDsymutilJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY VerifyDebug : public MachOTool {
-public:
- VerifyDebug(const ToolChain &TC)
- : MachOTool("darwin::VerifyDebug", "dwarfdump", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace darwin
-
-/// openbsd -- Directly call GNU Binutils assembler and linker
-namespace openbsd {
-class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
-public:
- Assembler(const ToolChain &TC)
- : GnuTool("openbsd::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("openbsd::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace openbsd
-
-/// bitrig -- Directly call GNU Binutils assembler and linker
-namespace bitrig {
-class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
-public:
- Assembler(const ToolChain &TC)
- : GnuTool("bitrig::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("bitrig::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace bitrig
-
-/// freebsd -- Directly call GNU Binutils assembler and linker
-namespace freebsd {
-class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
-public:
- Assembler(const ToolChain &TC)
- : GnuTool("freebsd::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("freebsd::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace freebsd
-
-/// netbsd -- Directly call GNU Binutils assembler and linker
-namespace netbsd {
-class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
-public:
- Assembler(const ToolChain &TC)
- : GnuTool("netbsd::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("netbsd::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace netbsd
-
-/// Directly call GNU Binutils' assembler and linker.
-namespace gnutools {
-class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
-public:
- Assembler(const ToolChain &TC) : GnuTool("GNU::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("GNU::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace gnutools
-
-namespace nacltools {
-class LLVM_LIBRARY_VISIBILITY AssemblerARM : public gnutools::Assembler {
-public:
- AssemblerARM(const ToolChain &TC) : gnutools::Assembler(TC) {}
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("NaCl::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace nacltools
-
-namespace fuchsia {
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("fuchsia::Linker", "ld.lld", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace fuchsia
-
-/// minix -- Directly call GNU Binutils assembler and linker
-namespace minix {
-class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
-public:
- Assembler(const ToolChain &TC)
- : GnuTool("minix::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("minix::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace minix
-
-/// solaris -- Directly call Solaris assembler and linker
-namespace solaris {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
-public:
- Assembler(const ToolChain &TC)
- : Tool("solaris::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
-public:
- Linker(const ToolChain &TC) : Tool("solaris::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace solaris
-
-/// dragonfly -- Directly call GNU Binutils assembler and linker
-namespace dragonfly {
-class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
-public:
- Assembler(const ToolChain &TC)
- : GnuTool("dragonfly::Assembler", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("dragonfly::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace dragonfly
-
-/// Visual studio tools.
-namespace visualstudio {
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
-public:
- Linker(const ToolChain &TC)
- : Tool("visualstudio::Linker", "linker", TC, RF_Full,
- llvm::sys::WEM_UTF16) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Compiler : public Tool {
-public:
- Compiler(const ToolChain &TC)
- : Tool("visualstudio::Compiler", "compiler", TC, RF_Full,
- llvm::sys::WEM_UTF16) {}
-
- bool hasIntegratedAssembler() const override { return true; }
- bool hasIntegratedCPP() const override { return true; }
- bool isLinkJob() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-
- std::unique_ptr<Command> GetCommand(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
-};
-} // end namespace visualstudio
-
-/// MinGW -- Directly call GNU Binutils assembler and linker
-namespace MinGW {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
-public:
- Assembler(const ToolChain &TC) : Tool("MinGW::Assemble", "assembler", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
-public:
- Linker(const ToolChain &TC) : Tool("MinGW::Linker", "linker", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-
-private:
- void AddLibGCC(const llvm::opt::ArgList &Args, ArgStringList &CmdArgs) const;
-};
-} // end namespace MinGW
-
-namespace arm {
-enum class FloatABI {
- Invalid,
- Soft,
- SoftFP,
- Hard,
-};
-
-FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args);
-} // end namespace arm
-
-namespace ppc {
-enum class FloatABI {
- Invalid,
- Soft,
- Hard,
-};
-
-FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
-} // end namespace ppc
-
-namespace sparc {
-enum class FloatABI {
- Invalid,
- Soft,
- Hard,
-};
-
-FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
-} // end namespace sparc
-
-namespace XCore {
-// For XCore, we do not need to instantiate tools for PreProcess, PreCompile and
-// Compile.
-// We simply use "clang -cc1" for those actions.
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
-public:
- Assembler(const ToolChain &TC) : Tool("XCore::Assembler", "XCore-as", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
-public:
- Linker(const ToolChain &TC) : Tool("XCore::Linker", "XCore-ld", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace XCore.
-
-namespace CrossWindows {
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
-public:
- Assembler(const ToolChain &TC) : Tool("CrossWindows::Assembler", "as", TC) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
-public:
- Linker(const ToolChain &TC)
- : Tool("CrossWindows::Linker", "ld", TC, RF_Full) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace CrossWindows
-
-/// SHAVE tools -- Directly call moviCompile and moviAsm
-namespace SHAVE {
-class LLVM_LIBRARY_VISIBILITY Compiler : public Tool {
-public:
- Compiler(const ToolChain &TC) : Tool("moviCompile", "movicompile", TC) {}
-
- bool hasIntegratedCPP() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
-public:
- Assembler(const ToolChain &TC) : Tool("moviAsm", "moviAsm", TC) {}
-
- bool hasIntegratedCPP() const override { return false; } // not sure.
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace SHAVE
-
-/// The Myriad toolchain uses tools that are in two different namespaces.
-/// The Compiler and Assembler as defined above are in the SHAVE namespace,
-/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE,
-/// is in the Myriad namespace.
-namespace Myriad {
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("shave::Linker", "ld", TC) {}
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace Myriad
-
-namespace PS4cpu {
-class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
-public:
- Assemble(const ToolChain &TC)
- : Tool("PS4cpu::Assemble", "assembler", TC, RF_Full) {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-class LLVM_LIBRARY_VISIBILITY Link : public Tool {
-public:
- Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC, RF_Full) {}
-
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace PS4cpu
-
-namespace NVPTX {
-
-// Run ptxas, the NVPTX assembler.
-class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
- public:
- Assembler(const ToolChain &TC)
- : Tool("NVPTX::Assembler", "ptxas", TC, RF_Full, llvm::sys::WEM_UTF8,
- "--options-file") {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-// Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX
-// assembly into a single output file.
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
- public:
- Linker(const ToolChain &TC)
- : Tool("NVPTX::Linker", "fatbinary", TC, RF_Full, llvm::sys::WEM_UTF8,
- "--options-file") {}
-
- bool hasIntegratedCPP() const override { return false; }
-
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-
-} // end namespace NVPTX
-
-namespace AVR {
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
-public:
- Linker(const ToolChain &TC) : GnuTool("AVR::Linker", "avr-ld", TC) {}
- bool hasIntegratedCPP() const override { return false; }
- bool isLinkJob() const override { return true; }
- void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output, const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const override;
-};
-} // end namespace AVR
-
-} // end namespace tools
-} // end namespace driver
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIB_DRIVER_TOOLS_H
diff --git a/contrib/llvm/tools/clang/lib/Driver/XRayArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/XRayArgs.cpp
new file mode 100644
index 0000000..8d68a84
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Driver/XRayArgs.cpp
@@ -0,0 +1,114 @@
+//===--- XRayArgs.cpp - Arguments for XRay --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Driver/XRayArgs.h"
+#include "ToolChains/CommonArgs.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/SpecialCaseList.h"
+
+using namespace clang;
+using namespace clang::driver;
+using namespace llvm::opt;
+
+namespace {
+constexpr char XRayInstrumentOption[] = "-fxray-instrument";
+constexpr char XRayInstructionThresholdOption[] =
+ "-fxray-instruction-threshold=";
+constexpr char XRayAlwaysInstrumentOption[] = "-fxray-always-instrument=";
+constexpr char XRayNeverInstrumentOption[] = "-fxray-never-instrument=";
+} // namespace
+
+XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
+ const Driver &D = TC.getDriver();
+ const llvm::Triple &Triple = TC.getTriple();
+ if (Args.hasFlag(options::OPT_fxray_instrument,
+ options::OPT_fnoxray_instrument, false)) {
+ if (Triple.getOS() == llvm::Triple::Linux)
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86_64:
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::ppc64le:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ break;
+ default:
+ D.Diag(diag::err_drv_clang_unsupported)
+ << (std::string(XRayInstrumentOption) + " on " + Triple.str());
+ }
+ else
+ D.Diag(diag::err_drv_clang_unsupported)
+ << (std::string(XRayInstrumentOption) + " on non-Linux target OS");
+ XRayInstrument = true;
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fxray_instruction_threshold_,
+ options::OPT_fxray_instruction_threshold_EQ)) {
+ StringRef S = A->getValue();
+ if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0)
+ D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
+
+ // Validate the always/never attribute files. We also make sure that they
+ // are treated as actual dependencies.
+ for (const auto &Filename :
+ Args.getAllArgValues(options::OPT_fxray_always_instrument)) {
+ if (llvm::sys::fs::exists(Filename)) {
+ AlwaysInstrumentFiles.push_back(Filename);
+ ExtraDeps.push_back(Filename);
+ } else
+ D.Diag(clang::diag::err_drv_no_such_file) << Filename;
+ }
+
+ for (const auto &Filename :
+ Args.getAllArgValues(options::OPT_fxray_never_instrument)) {
+ if (llvm::sys::fs::exists(Filename)) {
+ NeverInstrumentFiles.push_back(Filename);
+ ExtraDeps.push_back(Filename);
+ } else
+ D.Diag(clang::diag::err_drv_no_such_file) << Filename;
+ }
+ }
+}
+
+void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs, types::ID InputType) const {
+ if (!XRayInstrument)
+ return;
+
+ CmdArgs.push_back(XRayInstrumentOption);
+ CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) +
+ Twine(InstructionThreshold)));
+
+ for (const auto &Always : AlwaysInstrumentFiles) {
+ SmallString<64> AlwaysInstrumentOpt(XRayAlwaysInstrumentOption);
+ AlwaysInstrumentOpt += Always;
+ CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt));
+ }
+
+ for (const auto &Never : NeverInstrumentFiles) {
+ SmallString<64> NeverInstrumentOpt(XRayNeverInstrumentOption);
+ NeverInstrumentOpt += Never;
+ CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt));
+ }
+
+ for (const auto &Dep : ExtraDeps) {
+ SmallString<64> ExtraDepOpt("-fdepfile-entry=");
+ ExtraDepOpt += Dep;
+ CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
+ }
+}
diff --git a/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp b/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp
index 5292a58..444d039 100644
--- a/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp
+++ b/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp
@@ -25,17 +25,21 @@ void EditsReceiver::remove(CharSourceRange range) {
void EditedSource::deconstructMacroArgLoc(SourceLocation Loc,
SourceLocation &ExpansionLoc,
- IdentifierInfo *&II) {
+ MacroArgUse &ArgUse) {
assert(SourceMgr.isMacroArgExpansion(Loc));
SourceLocation DefArgLoc = SourceMgr.getImmediateExpansionRange(Loc).first;
- ExpansionLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
+ SourceLocation ImmediateExpansionLoc =
+ SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
+ ExpansionLoc = ImmediateExpansionLoc;
+ while (SourceMgr.isMacroBodyExpansion(ExpansionLoc))
+ ExpansionLoc = SourceMgr.getImmediateExpansionRange(ExpansionLoc).first;
SmallString<20> Buf;
StringRef ArgName = Lexer::getSpelling(SourceMgr.getSpellingLoc(DefArgLoc),
Buf, SourceMgr, LangOpts);
- II = nullptr;
- if (!ArgName.empty()) {
- II = &IdentTable.get(ArgName);
- }
+ ArgUse = MacroArgUse{nullptr, SourceLocation(), SourceLocation()};
+ if (!ArgName.empty())
+ ArgUse = {&IdentTable.get(ArgName), ImmediateExpansionLoc,
+ SourceMgr.getSpellingLoc(DefArgLoc)};
}
void EditedSource::startingCommit() {}
@@ -43,12 +47,11 @@ void EditedSource::startingCommit() {}
void EditedSource::finishedCommit() {
for (auto &ExpArg : CurrCommitMacroArgExps) {
SourceLocation ExpLoc;
- IdentifierInfo *II;
- std::tie(ExpLoc, II) = ExpArg;
- auto &ArgNames = ExpansionToArgMap[ExpLoc.getRawEncoding()];
- if (std::find(ArgNames.begin(), ArgNames.end(), II) == ArgNames.end()) {
- ArgNames.push_back(II);
- }
+ MacroArgUse ArgUse;
+ std::tie(ExpLoc, ArgUse) = ExpArg;
+ auto &ArgUses = ExpansionToArgMap[ExpLoc.getRawEncoding()];
+ if (std::find(ArgUses.begin(), ArgUses.end(), ArgUse) == ArgUses.end())
+ ArgUses.push_back(ArgUse);
}
CurrCommitMacroArgExps.clear();
}
@@ -66,12 +69,16 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
}
if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
- IdentifierInfo *II;
SourceLocation ExpLoc;
- deconstructMacroArgLoc(OrigLoc, ExpLoc, II);
+ MacroArgUse ArgUse;
+ deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
auto I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
if (I != ExpansionToArgMap.end() &&
- std::find(I->second.begin(), I->second.end(), II) != I->second.end()) {
+ find_if(I->second, [&](const MacroArgUse &U) {
+ return ArgUse.Identifier == U.Identifier &&
+ std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
+ std::tie(U.ImmediateExpansionLoc, U.UseLoc);
+ }) != I->second.end()) {
// Trying to write in a macro argument input that has already been
// written by a previous commit for another expansion of the same macro
// argument name. For example:
@@ -88,7 +95,6 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
return false;
}
}
-
return true;
}
@@ -101,13 +107,13 @@ bool EditedSource::commitInsert(SourceLocation OrigLoc,
return true;
if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
- IdentifierInfo *II;
+ MacroArgUse ArgUse;
SourceLocation ExpLoc;
- deconstructMacroArgLoc(OrigLoc, ExpLoc, II);
- if (II)
- CurrCommitMacroArgExps.emplace_back(ExpLoc, II);
+ deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
+ if (ArgUse.Identifier)
+ CurrCommitMacroArgExps.emplace_back(ExpLoc, ArgUse);
}
-
+
FileEdit &FA = FileEdits[Offs];
if (FA.Text.empty()) {
FA.Text = copyString(text);
@@ -363,13 +369,14 @@ static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts,
static void applyRewrite(EditsReceiver &receiver,
StringRef text, FileOffset offs, unsigned len,
- const SourceManager &SM, const LangOptions &LangOpts) {
+ const SourceManager &SM, const LangOptions &LangOpts,
+ bool shouldAdjustRemovals) {
assert(offs.getFID().isValid());
SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
Loc = Loc.getLocWithOffset(offs.getOffset());
assert(Loc.isFileID());
- if (text.empty())
+ if (text.empty() && shouldAdjustRemovals)
adjustRemoval(SM, LangOpts, Loc, offs, len, text);
CharSourceRange range = CharSourceRange::getCharRange(Loc,
@@ -387,7 +394,8 @@ static void applyRewrite(EditsReceiver &receiver,
receiver.insert(Loc, text);
}
-void EditedSource::applyRewrites(EditsReceiver &receiver) {
+void EditedSource::applyRewrites(EditsReceiver &receiver,
+ bool shouldAdjustRemovals) {
SmallString<128> StrVec;
FileOffset CurOffs, CurEnd;
unsigned CurLen;
@@ -414,14 +422,16 @@ void EditedSource::applyRewrites(EditsReceiver &receiver) {
continue;
}
- applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts);
+ applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
+ shouldAdjustRemovals);
CurOffs = offs;
StrVec = act.Text;
CurLen = act.RemoveLen;
CurEnd = CurOffs.getWithOffset(CurLen);
}
- applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts);
+ applyRewrite(receiver, StrVec, CurOffs, CurLen, SourceMgr, LangOpts,
+ shouldAdjustRemovals);
}
void EditedSource::clearRewrites() {
diff --git a/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 2148316..dc501b5 100644
--- a/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -798,24 +798,28 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
case NSAPI::NSNumberWithUnsignedInt:
case NSAPI::NSNumberWithUnsignedInteger:
CallIsUnsigned = true;
+ LLVM_FALLTHROUGH;
case NSAPI::NSNumberWithInt:
case NSAPI::NSNumberWithInteger:
break;
case NSAPI::NSNumberWithUnsignedLong:
CallIsUnsigned = true;
+ LLVM_FALLTHROUGH;
case NSAPI::NSNumberWithLong:
CallIsLong = true;
break;
case NSAPI::NSNumberWithUnsignedLongLong:
CallIsUnsigned = true;
+ LLVM_FALLTHROUGH;
case NSAPI::NSNumberWithLongLong:
CallIsLongLong = true;
break;
case NSAPI::NSNumberWithDouble:
CallIsDouble = true;
+ LLVM_FALLTHROUGH;
case NSAPI::NSNumberWithFloat:
CallIsFloating = true;
break;
diff --git a/contrib/llvm/tools/clang/lib/Format/BreakableToken.cpp b/contrib/llvm/tools/clang/lib/Format/BreakableToken.cpp
index 6363f89..3c9df62 100644
--- a/contrib/llvm/tools/clang/lib/Format/BreakableToken.cpp
+++ b/contrib/llvm/tools/clang/lib/Format/BreakableToken.cpp
@@ -14,7 +14,7 @@
//===----------------------------------------------------------------------===//
#include "BreakableToken.h"
-#include "Comments.h"
+#include "ContinuationIndenter.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Format/Format.h"
#include "llvm/ADT/STLExtras.h"
@@ -40,6 +40,22 @@ static bool IsBlank(char C) {
}
}
+static StringRef getLineCommentIndentPrefix(StringRef Comment) {
+ static const char *const KnownPrefixes[] = {
+ "///<", "//!<", "///", "//", "//!"};
+ StringRef LongestPrefix;
+ for (StringRef KnownPrefix : KnownPrefixes) {
+ if (Comment.startswith(KnownPrefix)) {
+ size_t PrefixLength = KnownPrefix.size();
+ while (PrefixLength < Comment.size() && Comment[PrefixLength] == ' ')
+ ++PrefixLength;
+ if (PrefixLength > LongestPrefix.size())
+ LongestPrefix = Comment.substr(0, PrefixLength);
+ }
+ }
+ return LongestPrefix;
+}
+
static BreakableToken::Split getCommentSplit(StringRef Text,
unsigned ContentStartColumn,
unsigned ColumnLimit,
@@ -62,6 +78,14 @@ static BreakableToken::Split getCommentSplit(StringRef Text,
}
StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes);
+
+ // Do not split before a number followed by a dot: this would be interpreted
+ // as a numbered list, which would prevent re-flowing in subsequent passes.
+ static llvm::Regex kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\.");
+ if (SpaceOffset != StringRef::npos &&
+ kNumberedListRegexp.match(Text.substr(SpaceOffset).ltrim(Blanks)))
+ SpaceOffset = Text.find_last_of(Blanks, SpaceOffset);
+
if (SpaceOffset == StringRef::npos ||
// Don't break at leading whitespace.
Text.find_last_not_of(Blanks, SpaceOffset) == StringRef::npos) {
@@ -132,37 +156,61 @@ getStringSplit(StringRef Text, unsigned UsedColumns, unsigned ColumnLimit,
return BreakableToken::Split(StringRef::npos, 0);
}
+bool switchesFormatting(const FormatToken &Token) {
+ assert((Token.is(TT_BlockComment) || Token.is(TT_LineComment)) &&
+ "formatting regions are switched by comment tokens");
+ StringRef Content = Token.TokenText.substr(2).ltrim();
+ return Content.startswith("clang-format on") ||
+ Content.startswith("clang-format off");
+}
+
+unsigned
+BreakableToken::getLineLengthAfterCompression(unsigned RemainingTokenColumns,
+ Split Split) const {
+ // Example: consider the content
+ // lala lala
+ // - RemainingTokenColumns is the original number of columns, 10;
+ // - Split is (4, 2), denoting the two spaces between the two words;
+ //
+ // We compute the number of columns when the split is compressed into a single
+ // space, like:
+ // lala lala
+ return RemainingTokenColumns + 1 - Split.second;
+}
+
unsigned BreakableSingleLineToken::getLineCount() const { return 1; }
unsigned BreakableSingleLineToken::getLineLengthAfterSplit(
- unsigned LineIndex, unsigned Offset, StringRef::size_type Length) const {
+ unsigned LineIndex, unsigned TailOffset,
+ StringRef::size_type Length) const {
return StartColumn + Prefix.size() + Postfix.size() +
- encoding::columnWidthWithTabs(Line.substr(Offset, Length),
+ encoding::columnWidthWithTabs(Line.substr(TailOffset, Length),
StartColumn + Prefix.size(),
Style.TabWidth, Encoding);
}
BreakableSingleLineToken::BreakableSingleLineToken(
- const FormatToken &Tok, unsigned IndentLevel, unsigned StartColumn,
- StringRef Prefix, StringRef Postfix, bool InPPDirective,
- encoding::Encoding Encoding, const FormatStyle &Style)
- : BreakableToken(Tok, IndentLevel, InPPDirective, Encoding, Style),
+ const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
+ StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding,
+ const FormatStyle &Style)
+ : BreakableToken(Tok, InPPDirective, Encoding, Style),
StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix) {
- assert(Tok.TokenText.endswith(Postfix));
+ assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix));
Line = Tok.TokenText.substr(
Prefix.size(), Tok.TokenText.size() - Prefix.size() - Postfix.size());
}
BreakableStringLiteral::BreakableStringLiteral(
- const FormatToken &Tok, unsigned IndentLevel, unsigned StartColumn,
- StringRef Prefix, StringRef Postfix, bool InPPDirective,
- encoding::Encoding Encoding, const FormatStyle &Style)
- : BreakableSingleLineToken(Tok, IndentLevel, StartColumn, Prefix, Postfix,
- InPPDirective, Encoding, Style) {}
+ const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
+ StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding,
+ const FormatStyle &Style)
+ : BreakableSingleLineToken(Tok, StartColumn, Prefix, Postfix, InPPDirective,
+ Encoding, Style) {}
BreakableToken::Split
BreakableStringLiteral::getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const {
+ unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const {
return getStringSplit(Line.substr(TailOffset),
StartColumn + Prefix.size() + Postfix.size(),
ColumnLimit, Style.TabWidth, Encoding);
@@ -171,86 +219,158 @@ BreakableStringLiteral::getSplit(unsigned LineIndex, unsigned TailOffset,
void BreakableStringLiteral::insertBreak(unsigned LineIndex,
unsigned TailOffset, Split Split,
WhitespaceManager &Whitespaces) {
- unsigned LeadingSpaces = StartColumn;
- // The '@' of an ObjC string literal (@"Test") does not become part of the
- // string token.
- // FIXME: It might be a cleaner solution to merge the tokens as a
- // precomputation step.
- if (Prefix.startswith("@"))
- --LeadingSpaces;
Whitespaces.replaceWhitespaceInToken(
Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
- Prefix, InPPDirective, 1, IndentLevel, LeadingSpaces);
-}
-
-BreakableLineComment::BreakableLineComment(
- const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn,
- bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
- : BreakableSingleLineToken(Token, IndentLevel, StartColumn,
- getLineCommentIndentPrefix(Token.TokenText), "",
- InPPDirective, Encoding, Style) {
- OriginalPrefix = Prefix;
- if (Token.TokenText.size() > Prefix.size() &&
- isAlphanumeric(Token.TokenText[Prefix.size()])) {
- if (Prefix == "//")
- Prefix = "// ";
- else if (Prefix == "///")
- Prefix = "/// ";
- else if (Prefix == "//!")
- Prefix = "//! ";
- }
+ Prefix, InPPDirective, 1, StartColumn);
}
+BreakableComment::BreakableComment(const FormatToken &Token,
+ unsigned StartColumn,
+ bool InPPDirective,
+ encoding::Encoding Encoding,
+ const FormatStyle &Style)
+ : BreakableToken(Token, InPPDirective, Encoding, Style),
+ StartColumn(StartColumn) {}
+
+unsigned BreakableComment::getLineCount() const { return Lines.size(); }
+
BreakableToken::Split
-BreakableLineComment::getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const {
- return getCommentSplit(Line.substr(TailOffset), StartColumn + Prefix.size(),
+BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const {
+ // Don't break lines matching the comment pragmas regex.
+ if (CommentPragmasRegex.match(Content[LineIndex]))
+ return Split(StringRef::npos, 0);
+ return getCommentSplit(Content[LineIndex].substr(TailOffset),
+ getContentStartColumn(LineIndex, TailOffset),
ColumnLimit, Style.TabWidth, Encoding);
}
-void BreakableLineComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
- Split Split,
- WhitespaceManager &Whitespaces) {
+void BreakableComment::compressWhitespace(unsigned LineIndex,
+ unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) {
+ StringRef Text = Content[LineIndex].substr(TailOffset);
+ // Text is relative to the content line, but Whitespaces operates relative to
+ // the start of the corresponding token, so compute the start of the Split
+ // that needs to be compressed into a single space relative to the start of
+ // its token.
+ unsigned BreakOffsetInToken =
+ Text.data() - tokenAt(LineIndex).TokenText.data() + Split.first;
+ unsigned CharsToRemove = Split.second;
Whitespaces.replaceWhitespaceInToken(
- Tok, OriginalPrefix.size() + TailOffset + Split.first, Split.second,
- Postfix, Prefix, InPPDirective, /*Newlines=*/1, IndentLevel, StartColumn);
+ tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", "",
+ /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1);
}
-void BreakableLineComment::replaceWhitespace(unsigned LineIndex,
- unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces) {
- Whitespaces.replaceWhitespaceInToken(
- Tok, OriginalPrefix.size() + TailOffset + Split.first, Split.second, "",
- "", /*InPPDirective=*/false, /*Newlines=*/0, /*IndentLevel=*/0,
- /*Spaces=*/1);
-}
-
-void BreakableLineComment::replaceWhitespaceBefore(
- unsigned LineIndex, WhitespaceManager &Whitespaces) {
- if (OriginalPrefix != Prefix) {
- Whitespaces.replaceWhitespaceInToken(Tok, OriginalPrefix.size(), 0, "", "",
- /*InPPDirective=*/false,
- /*Newlines=*/0, /*IndentLevel=*/0,
- /*Spaces=*/1);
+BreakableToken::Split
+BreakableComment::getReflowSplit(StringRef Text, StringRef ReflowPrefix,
+ unsigned PreviousEndColumn,
+ unsigned ColumnLimit) const {
+ unsigned ReflowStartColumn = PreviousEndColumn + ReflowPrefix.size();
+ StringRef TrimmedText = Text.rtrim(Blanks);
+ // This is the width of the resulting line in case the full line of Text gets
+ // reflown up starting at ReflowStartColumn.
+ unsigned FullWidth = ReflowStartColumn + encoding::columnWidthWithTabs(
+ TrimmedText, ReflowStartColumn,
+ Style.TabWidth, Encoding);
+ // If the full line fits up, we return a reflow split after it,
+ // otherwise we compute the largest piece of text that fits after
+ // ReflowStartColumn.
+ Split ReflowSplit =
+ FullWidth <= ColumnLimit
+ ? Split(TrimmedText.size(), Text.size() - TrimmedText.size())
+ : getCommentSplit(Text, ReflowStartColumn, ColumnLimit,
+ Style.TabWidth, Encoding);
+
+ // We need to be extra careful here, because while it's OK to keep a long line
+ // if it can't be broken into smaller pieces (like when the first word of a
+ // long line is longer than the column limit), it's not OK to reflow that long
+ // word up. So we recompute the size of the previous line after reflowing and
+ // only return the reflow split if that's under the line limit.
+ if (ReflowSplit.first != StringRef::npos &&
+ // Check if the width of the newly reflown line is under the limit.
+ PreviousEndColumn + ReflowPrefix.size() +
+ encoding::columnWidthWithTabs(Text.substr(0, ReflowSplit.first),
+ PreviousEndColumn +
+ ReflowPrefix.size(),
+ Style.TabWidth, Encoding) <=
+ ColumnLimit) {
+ return ReflowSplit;
}
+ return Split(StringRef::npos, 0);
+}
+
+const FormatToken &BreakableComment::tokenAt(unsigned LineIndex) const {
+ return Tokens[LineIndex] ? *Tokens[LineIndex] : Tok;
+}
+
+static bool mayReflowContent(StringRef Content) {
+ Content = Content.trim(Blanks);
+ // Lines starting with '@' commonly have special meaning.
+ // Lines starting with '-', '-#', '+' or '*' are bulleted/numbered lists.
+ static const SmallVector<StringRef, 8> kSpecialMeaningPrefixes = {
+ "@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* " };
+ bool hasSpecialMeaningPrefix = false;
+ for (StringRef Prefix : kSpecialMeaningPrefixes) {
+ if (Content.startswith(Prefix)) {
+ hasSpecialMeaningPrefix = true;
+ break;
+ }
+ }
+
+ // Numbered lists may also start with a number followed by '.'
+ // To avoid issues if a line starts with a number which is actually the end
+ // of a previous line, we only consider numbers with up to 2 digits.
+ static llvm::Regex kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\. ");
+ hasSpecialMeaningPrefix = hasSpecialMeaningPrefix ||
+ kNumberedListRegexp.match(Content);
+
+ // Simple heuristic for what to reflow: content should contain at least two
+ // characters and either the first or second character must be
+ // non-punctuation.
+ return Content.size() >= 2 && !hasSpecialMeaningPrefix &&
+ !Content.endswith("\\") &&
+ // Note that this is UTF-8 safe, since if isPunctuation(Content[0]) is
+ // true, then the first code point must be 1 byte long.
+ (!isPunctuation(Content[0]) || !isPunctuation(Content[1]));
}
BreakableBlockComment::BreakableBlockComment(
- const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn,
+ const FormatToken &Token, unsigned StartColumn,
unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style)
- : BreakableToken(Token, IndentLevel, InPPDirective, Encoding, Style) {
- StringRef TokenText(Token.TokenText);
+ : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style) {
+ assert(Tok.is(TT_BlockComment) &&
+ "block comment section must start with a block comment");
+
+ StringRef TokenText(Tok.TokenText);
assert(TokenText.startswith("/*") && TokenText.endswith("*/"));
TokenText.substr(2, TokenText.size() - 4).split(Lines, "\n");
int IndentDelta = StartColumn - OriginalStartColumn;
- LeadingWhitespace.resize(Lines.size());
- StartOfLineColumn.resize(Lines.size());
- StartOfLineColumn[0] = StartColumn + 2;
+ Content.resize(Lines.size());
+ Content[0] = Lines[0];
+ ContentColumn.resize(Lines.size());
+ // Account for the initial '/*'.
+ ContentColumn[0] = StartColumn + 2;
+ Tokens.resize(Lines.size());
for (size_t i = 1; i < Lines.size(); ++i)
adjustWhitespace(i, IndentDelta);
+ // Align decorations with the column of the star on the first line,
+ // that is one column after the start "/*".
+ DecorationColumn = StartColumn + 1;
+
+ // Account for comment decoration patterns like this:
+ //
+ // /*
+ // ** blah blah blah
+ // */
+ if (Lines.size() >= 2 && Content[1].startswith("**") &&
+ static_cast<unsigned>(ContentColumn[1]) == StartColumn) {
+ DecorationColumn = StartColumn;
+ }
+
Decoration = "* ";
if (Lines.size() == 1 && !FirstInLine) {
// Comments for which FirstInLine is false can start on arbitrary column,
@@ -262,49 +382,60 @@ BreakableBlockComment::BreakableBlockComment(
}
for (size_t i = 1, e = Lines.size(); i < e && !Decoration.empty(); ++i) {
// If the last line is empty, the closing "*/" will have a star.
- if (i + 1 == e && Lines[i].empty())
+ if (i + 1 == e && Content[i].empty())
break;
- if (!Lines[i].empty() && i + 1 != e && Decoration.startswith(Lines[i]))
+ if (!Content[i].empty() && i + 1 != e &&
+ Decoration.startswith(Content[i]))
continue;
- while (!Lines[i].startswith(Decoration))
+ while (!Content[i].startswith(Decoration))
Decoration = Decoration.substr(0, Decoration.size() - 1);
}
LastLineNeedsDecoration = true;
- IndentAtLineBreak = StartOfLineColumn[0] + 1;
- for (size_t i = 1; i < Lines.size(); ++i) {
- if (Lines[i].empty()) {
- if (i + 1 == Lines.size()) {
+ IndentAtLineBreak = ContentColumn[0] + 1;
+ for (size_t i = 1, e = Lines.size(); i < e; ++i) {
+ if (Content[i].empty()) {
+ if (i + 1 == e) {
// Empty last line means that we already have a star as a part of the
// trailing */. We also need to preserve whitespace, so that */ is
// correctly indented.
LastLineNeedsDecoration = false;
+ // Align the star in the last '*/' with the stars on the previous lines.
+ if (e >= 2 && !Decoration.empty()) {
+ ContentColumn[i] = DecorationColumn;
+ }
} else if (Decoration.empty()) {
// For all other lines, set the start column to 0 if they're empty, so
// we do not insert trailing whitespace anywhere.
- StartOfLineColumn[i] = 0;
+ ContentColumn[i] = 0;
}
continue;
}
// The first line already excludes the star.
+ // The last line excludes the star if LastLineNeedsDecoration is false.
// For all other lines, adjust the line to exclude the star and
// (optionally) the first whitespace.
- unsigned DecorationSize =
- Decoration.startswith(Lines[i]) ? Lines[i].size() : Decoration.size();
- StartOfLineColumn[i] += DecorationSize;
- Lines[i] = Lines[i].substr(DecorationSize);
- LeadingWhitespace[i] += DecorationSize;
- if (!Decoration.startswith(Lines[i]))
+ unsigned DecorationSize = Decoration.startswith(Content[i])
+ ? Content[i].size()
+ : Decoration.size();
+ if (DecorationSize) {
+ ContentColumn[i] = DecorationColumn + DecorationSize;
+ }
+ Content[i] = Content[i].substr(DecorationSize);
+ if (!Decoration.startswith(Content[i]))
IndentAtLineBreak =
- std::min<int>(IndentAtLineBreak, std::max(0, StartOfLineColumn[i]));
+ std::min<int>(IndentAtLineBreak, std::max(0, ContentColumn[i]));
}
- IndentAtLineBreak = std::max<unsigned>(IndentAtLineBreak, Decoration.size());
+ IndentAtLineBreak =
+ std::max<unsigned>(IndentAtLineBreak, Decoration.size());
+
DEBUG({
llvm::dbgs() << "IndentAtLineBreak " << IndentAtLineBreak << "\n";
for (size_t i = 0; i < Lines.size(); ++i) {
- llvm::dbgs() << i << " |" << Lines[i] << "| " << LeadingWhitespace[i]
- << "\n";
+ llvm::dbgs() << i << " |" << Content[i] << "| "
+ << "CC=" << ContentColumn[i] << "| "
+ << "IN=" << (Content[i].data() - Lines[i].data()) << "\n";
}
});
}
@@ -334,78 +465,162 @@ void BreakableBlockComment::adjustWhitespace(unsigned LineIndex,
StringRef Whitespace = Lines[LineIndex].substr(0, StartOfLine);
// Adjust Lines to only contain relevant text.
- Lines[LineIndex - 1] = Lines[LineIndex - 1].substr(0, EndOfPreviousLine);
- Lines[LineIndex] = Lines[LineIndex].substr(StartOfLine);
- // Adjust LeadingWhitespace to account all whitespace between the lines
- // to the current line.
- LeadingWhitespace[LineIndex] =
- Lines[LineIndex].begin() - Lines[LineIndex - 1].end();
+ size_t PreviousContentOffset =
+ Content[LineIndex - 1].data() - Lines[LineIndex - 1].data();
+ Content[LineIndex - 1] = Lines[LineIndex - 1].substr(
+ PreviousContentOffset, EndOfPreviousLine - PreviousContentOffset);
+ Content[LineIndex] = Lines[LineIndex].substr(StartOfLine);
// Adjust the start column uniformly across all lines.
- StartOfLineColumn[LineIndex] =
+ ContentColumn[LineIndex] =
encoding::columnWidthWithTabs(Whitespace, 0, Style.TabWidth, Encoding) +
IndentDelta;
}
-unsigned BreakableBlockComment::getLineCount() const { return Lines.size(); }
-
unsigned BreakableBlockComment::getLineLengthAfterSplit(
- unsigned LineIndex, unsigned Offset, StringRef::size_type Length) const {
- unsigned ContentStartColumn = getContentStartColumn(LineIndex, Offset);
- return ContentStartColumn +
- encoding::columnWidthWithTabs(Lines[LineIndex].substr(Offset, Length),
- ContentStartColumn, Style.TabWidth,
- Encoding) +
- // The last line gets a "*/" postfix.
- (LineIndex + 1 == Lines.size() ? 2 : 0);
-}
-
-BreakableToken::Split
-BreakableBlockComment::getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const {
- return getCommentSplit(Lines[LineIndex].substr(TailOffset),
- getContentStartColumn(LineIndex, TailOffset),
- ColumnLimit, Style.TabWidth, Encoding);
+ unsigned LineIndex, unsigned TailOffset,
+ StringRef::size_type Length) const {
+ unsigned ContentStartColumn = getContentStartColumn(LineIndex, TailOffset);
+ unsigned LineLength =
+ ContentStartColumn + encoding::columnWidthWithTabs(
+ Content[LineIndex].substr(TailOffset, Length),
+ ContentStartColumn, Style.TabWidth, Encoding);
+ // The last line gets a "*/" postfix.
+ if (LineIndex + 1 == Lines.size()) {
+ LineLength += 2;
+ // We never need a decoration when breaking just the trailing "*/" postfix.
+ // Note that checking that Length == 0 is not enough, since Length could
+ // also be StringRef::npos.
+ if (Content[LineIndex].substr(TailOffset, Length).empty()) {
+ LineLength -= Decoration.size();
+ }
+ }
+ return LineLength;
}
void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
Split Split,
WhitespaceManager &Whitespaces) {
- StringRef Text = Lines[LineIndex].substr(TailOffset);
+ StringRef Text = Content[LineIndex].substr(TailOffset);
StringRef Prefix = Decoration;
+ // We need this to account for the case when we have a decoration "* " for all
+ // the lines except for the last one, where the star in "*/" acts as a
+ // decoration.
+ unsigned LocalIndentAtLineBreak = IndentAtLineBreak;
if (LineIndex + 1 == Lines.size() &&
Text.size() == Split.first + Split.second) {
// For the last line we need to break before "*/", but not to add "* ".
Prefix = "";
+ if (LocalIndentAtLineBreak >= 2)
+ LocalIndentAtLineBreak -= 2;
}
-
+ // The split offset is from the beginning of the line. Convert it to an offset
+ // from the beginning of the token text.
unsigned BreakOffsetInToken =
- Text.data() - Tok.TokenText.data() + Split.first;
+ Text.data() - tokenAt(LineIndex).TokenText.data() + Split.first;
unsigned CharsToRemove = Split.second;
- assert(IndentAtLineBreak >= Decoration.size());
+ assert(LocalIndentAtLineBreak >= Prefix.size());
Whitespaces.replaceWhitespaceInToken(
- Tok, BreakOffsetInToken, CharsToRemove, "", Prefix, InPPDirective, 1,
- IndentLevel, IndentAtLineBreak - Decoration.size());
+ tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", Prefix,
+ InPPDirective, /*Newlines=*/1,
+ /*Spaces=*/LocalIndentAtLineBreak - Prefix.size());
}
-void BreakableBlockComment::replaceWhitespace(unsigned LineIndex,
- unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces) {
- StringRef Text = Lines[LineIndex].substr(TailOffset);
- unsigned BreakOffsetInToken =
- Text.data() - Tok.TokenText.data() + Split.first;
- unsigned CharsToRemove = Split.second;
- Whitespaces.replaceWhitespaceInToken(
- Tok, BreakOffsetInToken, CharsToRemove, "", "", /*InPPDirective=*/false,
- /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1);
+BreakableToken::Split BreakableBlockComment::getSplitBefore(
+ unsigned LineIndex,
+ unsigned PreviousEndColumn,
+ unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const {
+ if (!mayReflow(LineIndex, CommentPragmasRegex))
+ return Split(StringRef::npos, 0);
+ StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks);
+ return getReflowSplit(TrimmedContent, ReflowPrefix, PreviousEndColumn,
+ ColumnLimit);
}
+unsigned BreakableBlockComment::getReflownColumn(
+ StringRef Content,
+ unsigned LineIndex,
+ unsigned PreviousEndColumn) const {
+ unsigned StartColumn = PreviousEndColumn + ReflowPrefix.size();
+ // If this is the last line, it will carry around its '*/' postfix.
+ unsigned PostfixLength = (LineIndex + 1 == Lines.size() ? 2 : 0);
+ // The line is composed of previous text, reflow prefix, reflown text and
+ // postfix.
+ unsigned ReflownColumn =
+ StartColumn + encoding::columnWidthWithTabs(Content, StartColumn,
+ Style.TabWidth, Encoding) +
+ PostfixLength;
+ return ReflownColumn;
+}
+
+unsigned BreakableBlockComment::getLineLengthAfterSplitBefore(
+ unsigned LineIndex, unsigned TailOffset,
+ unsigned PreviousEndColumn,
+ unsigned ColumnLimit,
+ Split SplitBefore) const {
+ if (SplitBefore.first == StringRef::npos ||
+ // Block comment line contents contain the trailing whitespace after the
+ // decoration, so the need of left trim. Note that this behavior is
+ // consistent with the breaking of block comments where the indentation of
+ // a broken line is uniform across all the lines of the block comment.
+ SplitBefore.first + SplitBefore.second <
+ Content[LineIndex].ltrim().size()) {
+ // A piece of line, not the whole, gets reflown.
+ return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
+ } else {
+ // The whole line gets reflown, need to check if we need to insert a break
+ // for the postfix or not.
+ StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks);
+ unsigned ReflownColumn =
+ getReflownColumn(TrimmedContent, LineIndex, PreviousEndColumn);
+ if (ReflownColumn <= ColumnLimit) {
+ return ReflownColumn;
+ }
+ return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
+ }
+}
void BreakableBlockComment::replaceWhitespaceBefore(
- unsigned LineIndex, WhitespaceManager &Whitespaces) {
- if (LineIndex == 0)
+ unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit,
+ Split SplitBefore, WhitespaceManager &Whitespaces) {
+ if (LineIndex == 0) return;
+ StringRef TrimmedContent = Content[LineIndex].ltrim(Blanks);
+ if (SplitBefore.first != StringRef::npos) {
+ // Here we need to reflow.
+ assert(Tokens[LineIndex - 1] == Tokens[LineIndex] &&
+ "Reflowing whitespace within a token");
+ // This is the offset of the end of the last line relative to the start of
+ // the token text in the token.
+ unsigned WhitespaceOffsetInToken = Content[LineIndex - 1].data() +
+ Content[LineIndex - 1].size() -
+ tokenAt(LineIndex).TokenText.data();
+ unsigned WhitespaceLength = TrimmedContent.data() -
+ tokenAt(LineIndex).TokenText.data() -
+ WhitespaceOffsetInToken;
+ Whitespaces.replaceWhitespaceInToken(
+ tokenAt(LineIndex), WhitespaceOffsetInToken,
+ /*ReplaceChars=*/WhitespaceLength, /*PreviousPostfix=*/"",
+ /*CurrentPrefix=*/ReflowPrefix, InPPDirective, /*Newlines=*/0,
+ /*Spaces=*/0);
+ // Check if we need to also insert a break at the whitespace range.
+ // For this we first adapt the reflow split relative to the beginning of the
+ // content.
+ // Note that we don't need a penalty for this break, since it doesn't change
+ // the total number of lines.
+ Split BreakSplit = SplitBefore;
+ BreakSplit.first += TrimmedContent.data() - Content[LineIndex].data();
+ unsigned ReflownColumn =
+ getReflownColumn(TrimmedContent, LineIndex, PreviousEndColumn);
+ if (ReflownColumn > ColumnLimit) {
+ insertBreak(LineIndex, 0, BreakSplit, Whitespaces);
+ }
return;
+ }
+
+ // Here no reflow with the previous line will happen.
+ // Fix the decoration of the line at LineIndex.
StringRef Prefix = Decoration;
- if (Lines[LineIndex].empty()) {
+ if (Content[LineIndex].empty()) {
if (LineIndex + 1 == Lines.size()) {
if (!LastLineNeedsDecoration) {
// If the last line was empty, we don't need a prefix, as the */ will
@@ -418,19 +633,35 @@ void BreakableBlockComment::replaceWhitespaceBefore(
Prefix = Prefix.substr(0, 1);
}
} else {
- if (StartOfLineColumn[LineIndex] == 1) {
+ if (ContentColumn[LineIndex] == 1) {
// This line starts immediately after the decorating *.
Prefix = Prefix.substr(0, 1);
}
}
-
- unsigned WhitespaceOffsetInToken = Lines[LineIndex].data() -
- Tok.TokenText.data() -
- LeadingWhitespace[LineIndex];
+ // This is the offset of the end of the last line relative to the start of the
+ // token text in the token.
+ unsigned WhitespaceOffsetInToken = Content[LineIndex - 1].data() +
+ Content[LineIndex - 1].size() -
+ tokenAt(LineIndex).TokenText.data();
+ unsigned WhitespaceLength = Content[LineIndex].data() -
+ tokenAt(LineIndex).TokenText.data() -
+ WhitespaceOffsetInToken;
Whitespaces.replaceWhitespaceInToken(
- Tok, WhitespaceOffsetInToken, LeadingWhitespace[LineIndex], "", Prefix,
- InPPDirective, 1, IndentLevel,
- StartOfLineColumn[LineIndex] - Prefix.size());
+ tokenAt(LineIndex), WhitespaceOffsetInToken, WhitespaceLength, "", Prefix,
+ InPPDirective, /*Newlines=*/1, ContentColumn[LineIndex] - Prefix.size());
+}
+
+bool BreakableBlockComment::mayReflow(unsigned LineIndex,
+ llvm::Regex &CommentPragmasRegex) const {
+ // Content[LineIndex] may exclude the indent after the '*' decoration. In that
+ // case, we compute the start of the comment pragma manually.
+ StringRef IndentContent = Content[LineIndex];
+ if (Lines[LineIndex].ltrim(Blanks).startswith("*")) {
+ IndentContent = Lines[LineIndex].ltrim(Blanks).substr(1);
+ }
+ return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
+ mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
+ !switchesFormatting(tokenAt(LineIndex));
}
unsigned
@@ -439,7 +670,252 @@ BreakableBlockComment::getContentStartColumn(unsigned LineIndex,
// If we break, we always break at the predefined indent.
if (TailOffset != 0)
return IndentAtLineBreak;
- return std::max(0, StartOfLineColumn[LineIndex]);
+ return std::max(0, ContentColumn[LineIndex]);
+}
+
+BreakableLineCommentSection::BreakableLineCommentSection(
+ const FormatToken &Token, unsigned StartColumn,
+ unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
+ encoding::Encoding Encoding, const FormatStyle &Style)
+ : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style) {
+ assert(Tok.is(TT_LineComment) &&
+ "line comment section must start with a line comment");
+ FormatToken *LineTok = nullptr;
+ for (const FormatToken *CurrentTok = &Tok;
+ CurrentTok && CurrentTok->is(TT_LineComment);
+ CurrentTok = CurrentTok->Next) {
+ LastLineTok = LineTok;
+ StringRef TokenText(CurrentTok->TokenText);
+ assert(TokenText.startswith("//"));
+ size_t FirstLineIndex = Lines.size();
+ TokenText.split(Lines, "\n");
+ Content.resize(Lines.size());
+ ContentColumn.resize(Lines.size());
+ OriginalContentColumn.resize(Lines.size());
+ Tokens.resize(Lines.size());
+ Prefix.resize(Lines.size());
+ OriginalPrefix.resize(Lines.size());
+ for (size_t i = FirstLineIndex, e = Lines.size(); i < e; ++i) {
+ // We need to trim the blanks in case this is not the first line in a
+ // multiline comment. Then the indent is included in Lines[i].
+ StringRef IndentPrefix =
+ getLineCommentIndentPrefix(Lines[i].ltrim(Blanks));
+ assert(IndentPrefix.startswith("//"));
+ OriginalPrefix[i] = Prefix[i] = IndentPrefix;
+ if (Lines[i].size() > Prefix[i].size() &&
+ isAlphanumeric(Lines[i][Prefix[i].size()])) {
+ if (Prefix[i] == "//")
+ Prefix[i] = "// ";
+ else if (Prefix[i] == "///")
+ Prefix[i] = "/// ";
+ else if (Prefix[i] == "//!")
+ Prefix[i] = "//! ";
+ else if (Prefix[i] == "///<")
+ Prefix[i] = "///< ";
+ else if (Prefix[i] == "//!<")
+ Prefix[i] = "//!< ";
+ }
+
+ Tokens[i] = LineTok;
+ Content[i] = Lines[i].substr(IndentPrefix.size());
+ OriginalContentColumn[i] =
+ StartColumn +
+ encoding::columnWidthWithTabs(OriginalPrefix[i],
+ StartColumn,
+ Style.TabWidth,
+ Encoding);
+ ContentColumn[i] =
+ StartColumn +
+ encoding::columnWidthWithTabs(Prefix[i],
+ StartColumn,
+ Style.TabWidth,
+ Encoding);
+
+ // Calculate the end of the non-whitespace text in this line.
+ size_t EndOfLine = Content[i].find_last_not_of(Blanks);
+ if (EndOfLine == StringRef::npos)
+ EndOfLine = Content[i].size();
+ else
+ ++EndOfLine;
+ Content[i] = Content[i].substr(0, EndOfLine);
+ }
+ LineTok = CurrentTok->Next;
+ if (CurrentTok->Next && !CurrentTok->Next->ContinuesLineCommentSection) {
+ // A line comment section needs to broken by a line comment that is
+ // preceded by at least two newlines. Note that we put this break here
+ // instead of breaking at a previous stage during parsing, since that
+ // would split the contents of the enum into two unwrapped lines in this
+ // example, which is undesirable:
+ // enum A {
+ // a, // comment about a
+ //
+ // // comment about b
+ // b
+ // };
+ //
+ // FIXME: Consider putting separate line comment sections as children to
+ // the unwrapped line instead.
+ break;
+ }
+ }
+}
+
+unsigned BreakableLineCommentSection::getLineLengthAfterSplit(
+ unsigned LineIndex, unsigned TailOffset,
+ StringRef::size_type Length) const {
+ unsigned ContentStartColumn =
+ (TailOffset == 0 ? ContentColumn[LineIndex]
+ : OriginalContentColumn[LineIndex]);
+ return ContentStartColumn + encoding::columnWidthWithTabs(
+ Content[LineIndex].substr(TailOffset, Length),
+ ContentStartColumn, Style.TabWidth, Encoding);
+}
+
+void BreakableLineCommentSection::insertBreak(unsigned LineIndex,
+ unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) {
+ StringRef Text = Content[LineIndex].substr(TailOffset);
+ // Compute the offset of the split relative to the beginning of the token
+ // text.
+ unsigned BreakOffsetInToken =
+ Text.data() - tokenAt(LineIndex).TokenText.data() + Split.first;
+ unsigned CharsToRemove = Split.second;
+ // Compute the size of the new indent, including the size of the new prefix of
+ // the newly broken line.
+ unsigned IndentAtLineBreak = OriginalContentColumn[LineIndex] +
+ Prefix[LineIndex].size() -
+ OriginalPrefix[LineIndex].size();
+ assert(IndentAtLineBreak >= Prefix[LineIndex].size());
+ Whitespaces.replaceWhitespaceInToken(
+ tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "",
+ Prefix[LineIndex], InPPDirective, /*Newlines=*/1,
+ /*Spaces=*/IndentAtLineBreak - Prefix[LineIndex].size());
+}
+
+BreakableComment::Split BreakableLineCommentSection::getSplitBefore(
+ unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const {
+ if (!mayReflow(LineIndex, CommentPragmasRegex))
+ return Split(StringRef::npos, 0);
+ return getReflowSplit(Content[LineIndex], ReflowPrefix, PreviousEndColumn,
+ ColumnLimit);
+}
+
+unsigned BreakableLineCommentSection::getLineLengthAfterSplitBefore(
+ unsigned LineIndex, unsigned TailOffset,
+ unsigned PreviousEndColumn,
+ unsigned ColumnLimit,
+ Split SplitBefore) const {
+ if (SplitBefore.first == StringRef::npos ||
+ SplitBefore.first + SplitBefore.second < Content[LineIndex].size()) {
+ // A piece of line, not the whole line, gets reflown.
+ return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
+ } else {
+ // The whole line gets reflown.
+ unsigned StartColumn = PreviousEndColumn + ReflowPrefix.size();
+ return StartColumn + encoding::columnWidthWithTabs(Content[LineIndex],
+ StartColumn,
+ Style.TabWidth,
+ Encoding);
+ }
+}
+
+void BreakableLineCommentSection::replaceWhitespaceBefore(
+ unsigned LineIndex, unsigned PreviousEndColumn, unsigned ColumnLimit,
+ Split SplitBefore, WhitespaceManager &Whitespaces) {
+ // If this is the first line of a token, we need to inform Whitespace Manager
+ // about it: either adapt the whitespace range preceding it, or mark it as an
+ // untouchable token.
+ // This happens for instance here:
+ // // line 1 \
+ // // line 2
+ if (LineIndex > 0 && Tokens[LineIndex] != Tokens[LineIndex - 1]) {
+ if (SplitBefore.first != StringRef::npos) {
+ // Reflow happens between tokens. Replace the whitespace between the
+ // tokens by the empty string.
+ Whitespaces.replaceWhitespace(
+ *Tokens[LineIndex], /*Newlines=*/0, /*Spaces=*/0,
+ /*StartOfTokenColumn=*/StartColumn, /*InPPDirective=*/false);
+ // Replace the indent and prefix of the token with the reflow prefix.
+ unsigned WhitespaceLength =
+ Content[LineIndex].data() - tokenAt(LineIndex).TokenText.data();
+ Whitespaces.replaceWhitespaceInToken(*Tokens[LineIndex],
+ /*Offset=*/0,
+ /*ReplaceChars=*/WhitespaceLength,
+ /*PreviousPostfix=*/"",
+ /*CurrentPrefix=*/ReflowPrefix,
+ /*InPPDirective=*/false,
+ /*Newlines=*/0,
+ /*Spaces=*/0);
+ } else {
+ // This is the first line for the current token, but no reflow with the
+ // previous token is necessary. However, we still may need to adjust the
+ // start column. Note that ContentColumn[LineIndex] is the expected
+ // content column after a possible update to the prefix, hence the prefix
+ // length change is included.
+ unsigned LineColumn =
+ ContentColumn[LineIndex] -
+ (Content[LineIndex].data() - Lines[LineIndex].data()) +
+ (OriginalPrefix[LineIndex].size() - Prefix[LineIndex].size());
+
+ // We always want to create a replacement instead of adding an untouchable
+ // token, even if LineColumn is the same as the original column of the
+ // token. This is because WhitespaceManager doesn't align trailing
+ // comments if they are untouchable.
+ Whitespaces.replaceWhitespace(*Tokens[LineIndex],
+ /*Newlines=*/1,
+ /*Spaces=*/LineColumn,
+ /*StartOfTokenColumn=*/LineColumn,
+ /*InPPDirective=*/false);
+ }
+ }
+ if (OriginalPrefix[LineIndex] != Prefix[LineIndex]) {
+ // Adjust the prefix if necessary.
+
+ // Take care of the space possibly introduced after a decoration.
+ assert(Prefix[LineIndex] == (OriginalPrefix[LineIndex] + " ").str() &&
+ "Expecting a line comment prefix to differ from original by at most "
+ "a space");
+ Whitespaces.replaceWhitespaceInToken(
+ tokenAt(LineIndex), OriginalPrefix[LineIndex].size(), 0, "", "",
+ /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1);
+ }
+ // Add a break after a reflow split has been introduced, if necessary.
+ // Note that this break doesn't need to be penalized, since it doesn't change
+ // the number of lines.
+ if (SplitBefore.first != StringRef::npos &&
+ SplitBefore.first + SplitBefore.second < Content[LineIndex].size()) {
+ insertBreak(LineIndex, 0, SplitBefore, Whitespaces);
+ }
+}
+
+void BreakableLineCommentSection::updateNextToken(LineState& State) const {
+ if (LastLineTok) {
+ State.NextToken = LastLineTok->Next;
+ }
+}
+
+bool BreakableLineCommentSection::mayReflow(
+ unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const {
+ // Line comments have the indent as part of the prefix, so we need to
+ // recompute the start of the line.
+ StringRef IndentContent = Content[LineIndex];
+ if (Lines[LineIndex].startswith("//")) {
+ IndentContent = Lines[LineIndex].substr(2);
+ }
+ return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
+ mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
+ !switchesFormatting(tokenAt(LineIndex)) &&
+ OriginalPrefix[LineIndex] == OriginalPrefix[LineIndex - 1];
+}
+
+unsigned
+BreakableLineCommentSection::getContentStartColumn(unsigned LineIndex,
+ unsigned TailOffset) const {
+ if (TailOffset != 0) {
+ return OriginalContentColumn[LineIndex];
+ }
+ return ContentColumn[LineIndex];
}
} // namespace format
diff --git a/contrib/llvm/tools/clang/lib/Format/BreakableToken.h b/contrib/llvm/tools/clang/lib/Format/BreakableToken.h
index eb1f9fd..e642a53 100644
--- a/contrib/llvm/tools/clang/lib/Format/BreakableToken.h
+++ b/contrib/llvm/tools/clang/lib/Format/BreakableToken.h
@@ -8,9 +8,10 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Declares BreakableToken, BreakableStringLiteral, and
-/// BreakableBlockComment classes, that contain token type-specific logic to
-/// break long lines in tokens.
+/// \brief Declares BreakableToken, BreakableStringLiteral, BreakableComment,
+/// BreakableBlockComment and BreakableLineCommentSection classes, that contain
+/// token type-specific logic to break long lines in tokens and reflow content
+/// between tokens.
///
//===----------------------------------------------------------------------===//
@@ -20,15 +21,49 @@
#include "Encoding.h"
#include "TokenAnnotator.h"
#include "WhitespaceManager.h"
+#include "llvm/Support/Regex.h"
#include <utility>
namespace clang {
namespace format {
+/// \brief Checks if \p Token switches formatting, like /* clang-format off */.
+/// \p Token must be a comment.
+bool switchesFormatting(const FormatToken &Token);
+
struct FormatStyle;
/// \brief Base class for strategies on how to break tokens.
///
+/// This is organised around the concept of a \c Split, which is a whitespace
+/// range that signifies a position of the content of a token where a
+/// reformatting might be done. Operating with splits is divided into 3
+/// operations:
+/// - getSplit, for finding a split starting at a position,
+/// - getLineLengthAfterSplit, for calculating the size in columns of the rest
+/// of the content after a split has been used for breaking, and
+/// - insertBreak, for executing the split using a whitespace manager.
+///
+/// There is a pair of operations that are used to compress a long whitespace
+/// range with a single space if that will bring the line lenght under the
+/// column limit:
+/// - getLineLengthAfterCompression, for calculating the size in columns of the
+/// line after a whitespace range has been compressed, and
+/// - compressWhitespace, for executing the whitespace compression using a
+/// whitespace manager; note that the compressed whitespace may be in the
+/// middle of the original line and of the reformatted line.
+///
+/// For tokens where the whitespace before each line needs to be also
+/// reformatted, for example for tokens supporting reflow, there are analogous
+/// operations that might be executed before the main line breaking occurs:
+/// - getSplitBefore, for finding a split such that the content preceding it
+/// needs to be specially reflown,
+/// - getLineLengthAfterSplitBefore, for calculating the line length in columns
+/// of the remainder of the content after the beginning of the content has
+/// been reformatted, and
+/// - replaceWhitespaceBefore, for executing the reflow using a whitespace
+/// manager.
+///
/// FIXME: The interface seems set in stone, so we might want to just pull the
/// strategy into the class, instead of controlling it from the outside.
class BreakableToken {
@@ -42,44 +77,85 @@ public:
virtual unsigned getLineCount() const = 0;
/// \brief Returns the number of columns required to format the piece of line
- /// at \p LineIndex, from byte offset \p Offset with length \p Length.
+ /// at \p LineIndex, from byte offset \p TailOffset with length \p Length.
///
- /// Note that previous breaks are not taken into account. \p Offset is always
- /// specified from the start of the (original) line.
+ /// Note that previous breaks are not taken into account. \p TailOffset is
+ /// always specified from the start of the (original) line.
/// \p Length can be set to StringRef::npos, which means "to the end of line".
virtual unsigned
- getLineLengthAfterSplit(unsigned LineIndex, unsigned Offset,
+ getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
StringRef::size_type Length) const = 0;
/// \brief Returns a range (offset, length) at which to break the line at
/// \p LineIndex, if previously broken at \p TailOffset. If possible, do not
/// violate \p ColumnLimit.
virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const = 0;
+ unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const = 0;
/// \brief Emits the previously retrieved \p Split via \p Whitespaces.
virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
WhitespaceManager &Whitespaces) = 0;
+ /// \brief Returns the number of columns required to format the piece of line
+ /// at \p LineIndex, from byte offset \p TailOffset after the whitespace range
+ /// \p Split has been compressed into a single space.
+ unsigned getLineLengthAfterCompression(unsigned RemainingTokenColumns,
+ Split Split) const;
+
/// \brief Replaces the whitespace range described by \p Split with a single
/// space.
- virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
- Split Split,
- WhitespaceManager &Whitespaces) = 0;
+ virtual void compressWhitespace(unsigned LineIndex, unsigned TailOffset,
+ Split Split,
+ WhitespaceManager &Whitespaces) = 0;
+
+ /// \brief Returns a whitespace range (offset, length) of the content at
+ /// \p LineIndex such that the content preceding this range needs to be
+ /// reformatted before any breaks are made to this line.
+ ///
+ /// \p PreviousEndColumn is the end column of the previous line after
+ /// formatting.
+ ///
+ /// A result having offset == StringRef::npos means that no piece of the line
+ /// needs to be reformatted before any breaks are made.
+ virtual Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn,
+ unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const {
+ return Split(StringRef::npos, 0);
+ }
+
+ /// \brief Returns the number of columns required to format the piece of line
+ /// at \p LineIndex after the content preceding the whitespace range specified
+ /// \p SplitBefore has been reformatted, but before any breaks are made to
+ /// this line.
+ virtual unsigned getLineLengthAfterSplitBefore(unsigned LineIndex,
+ unsigned TailOffset,
+ unsigned PreviousEndColumn,
+ unsigned ColumnLimit,
+ Split SplitBefore) const {
+ return getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
+ }
/// \brief Replaces the whitespace between \p LineIndex-1 and \p LineIndex.
+ /// Performs a reformatting of the content at \p LineIndex preceding the
+ /// whitespace range \p SplitBefore.
virtual void replaceWhitespaceBefore(unsigned LineIndex,
+ unsigned PreviousEndColumn,
+ unsigned ColumnLimit, Split SplitBefore,
WhitespaceManager &Whitespaces) {}
+ /// \brief Updates the next token of \p State to the next token after this
+ /// one. This can be used when this token manages a set of underlying tokens
+ /// as a unit and is responsible for the formatting of the them.
+ virtual void updateNextToken(LineState &State) const {}
+
protected:
- BreakableToken(const FormatToken &Tok, unsigned IndentLevel,
- bool InPPDirective, encoding::Encoding Encoding,
- const FormatStyle &Style)
- : Tok(Tok), IndentLevel(IndentLevel), InPPDirective(InPPDirective),
- Encoding(Encoding), Style(Style) {}
+ BreakableToken(const FormatToken &Tok, bool InPPDirective,
+ encoding::Encoding Encoding, const FormatStyle &Style)
+ : Tok(Tok), InPPDirective(InPPDirective), Encoding(Encoding),
+ Style(Style) {}
const FormatToken &Tok;
- const unsigned IndentLevel;
const bool InPPDirective;
const encoding::Encoding Encoding;
const FormatStyle &Style;
@@ -95,10 +171,9 @@ public:
StringRef::size_type Length) const override;
protected:
- BreakableSingleLineToken(const FormatToken &Tok, unsigned IndentLevel,
- unsigned StartColumn, StringRef Prefix,
- StringRef Postfix, bool InPPDirective,
- encoding::Encoding Encoding,
+ BreakableSingleLineToken(const FormatToken &Tok, unsigned StartColumn,
+ StringRef Prefix, StringRef Postfix,
+ bool InPPDirective, encoding::Encoding Encoding,
const FormatStyle &Style);
// The column in which the token starts.
@@ -117,107 +192,139 @@ public:
///
/// \p StartColumn specifies the column in which the token will start
/// after formatting.
- BreakableStringLiteral(const FormatToken &Tok, unsigned IndentLevel,
- unsigned StartColumn, StringRef Prefix,
- StringRef Postfix, bool InPPDirective,
- encoding::Encoding Encoding, const FormatStyle &Style);
+ BreakableStringLiteral(const FormatToken &Tok, unsigned StartColumn,
+ StringRef Prefix, StringRef Postfix,
+ bool InPPDirective, encoding::Encoding Encoding,
+ const FormatStyle &Style);
- Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const override;
+ Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const override;
void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
WhitespaceManager &Whitespaces) override;
- void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces) override {}
+ void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override {}
};
-class BreakableLineComment : public BreakableSingleLineToken {
-public:
- /// \brief Creates a breakable token for a line comment.
+class BreakableComment : public BreakableToken {
+protected:
+ /// \brief Creates a breakable token for a comment.
///
- /// \p StartColumn specifies the column in which the comment will start
- /// after formatting.
- BreakableLineComment(const FormatToken &Token, unsigned IndentLevel,
- unsigned StartColumn, bool InPPDirective,
- encoding::Encoding Encoding, const FormatStyle &Style);
+ /// \p StartColumn specifies the column in which the comment will start after
+ /// formatting.
+ BreakableComment(const FormatToken &Token, unsigned StartColumn,
+ bool InPPDirective, encoding::Encoding Encoding,
+ const FormatStyle &Style);
- Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const override;
- void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces) override;
- void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces) override;
- void replaceWhitespaceBefore(unsigned LineIndex,
- WhitespaceManager &Whitespaces) override;
+public:
+ unsigned getLineCount() const override;
+ Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const override;
+ void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
-private:
- // The prefix without an additional space if one was added.
- StringRef OriginalPrefix;
+protected:
+ virtual unsigned getContentStartColumn(unsigned LineIndex,
+ unsigned TailOffset) const = 0;
+
+ // Returns a split that divides Text into a left and right parts, such that
+ // the left part is suitable for reflowing after PreviousEndColumn.
+ Split getReflowSplit(StringRef Text, StringRef ReflowPrefix,
+ unsigned PreviousEndColumn, unsigned ColumnLimit) const;
+
+ // Returns the token containing the line at LineIndex.
+ const FormatToken &tokenAt(unsigned LineIndex) const;
+
+ // Checks if the content of line LineIndex may be reflown with the previous
+ // line.
+ virtual bool mayReflow(unsigned LineIndex,
+ llvm::Regex &CommentPragmasRegex) const = 0;
+
+ // Contains the original text of the lines of the block comment.
+ //
+ // In case of a block comments, excludes the leading /* in the first line and
+ // trailing */ in the last line. In case of line comments, excludes the
+ // leading // and spaces.
+ SmallVector<StringRef, 16> Lines;
+
+ // Contains the text of the lines excluding all leading and trailing
+ // whitespace between the lines. Note that the decoration (if present) is also
+ // not considered part of the text.
+ SmallVector<StringRef, 16> Content;
+
+ // Tokens[i] contains a reference to the token containing Lines[i] if the
+ // whitespace range before that token is managed by this block.
+ // Otherwise, Tokens[i] is a null pointer.
+ SmallVector<FormatToken *, 16> Tokens;
+
+ // ContentColumn[i] is the target column at which Content[i] should be.
+ // Note that this excludes a leading "* " or "*" in case of block comments
+ // where all lines have a "*" prefix, or the leading "// " or "//" in case of
+ // line comments.
+ //
+ // In block comments, the first line's target column is always positive. The
+ // remaining lines' target columns are relative to the first line to allow
+ // correct indentation of comments in \c WhitespaceManager. Thus they can be
+ // negative as well (in case the first line needs to be unindented more than
+ // there's actual whitespace in another line).
+ SmallVector<int, 16> ContentColumn;
+
+ // The intended start column of the first line of text from this section.
+ unsigned StartColumn;
+
+ // The prefix to use in front a line that has been reflown up.
+ // For example, when reflowing the second line after the first here:
+ // // comment 1
+ // // comment 2
+ // we expect:
+ // // comment 1 comment 2
+ // and not:
+ // // comment 1comment 2
+ StringRef ReflowPrefix = " ";
};
-class BreakableBlockComment : public BreakableToken {
+class BreakableBlockComment : public BreakableComment {
public:
- /// \brief Creates a breakable token for a block comment.
- ///
- /// \p StartColumn specifies the column in which the comment will start
- /// after formatting, while \p OriginalStartColumn specifies in which
- /// column the comment started before formatting.
- /// If the comment starts a line after formatting, set \p FirstInLine to true.
- BreakableBlockComment(const FormatToken &Token, unsigned IndentLevel,
- unsigned StartColumn, unsigned OriginaStartColumn,
- bool FirstInLine, bool InPPDirective,
- encoding::Encoding Encoding, const FormatStyle &Style);
+ BreakableBlockComment(const FormatToken &Token, unsigned StartColumn,
+ unsigned OriginalStartColumn, bool FirstInLine,
+ bool InPPDirective, encoding::Encoding Encoding,
+ const FormatStyle &Style);
- unsigned getLineCount() const override;
unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
StringRef::size_type Length) const override;
- Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const override;
void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
WhitespaceManager &Whitespaces) override;
- void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces) override;
- void replaceWhitespaceBefore(unsigned LineIndex,
+ Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn,
+ unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const override;
+ unsigned getLineLengthAfterSplitBefore(unsigned LineIndex,
+ unsigned TailOffset,
+ unsigned PreviousEndColumn,
+ unsigned ColumnLimit,
+ Split SplitBefore) const override;
+ void replaceWhitespaceBefore(unsigned LineIndex, unsigned PreviousEndColumn,
+ unsigned ColumnLimit, Split SplitBefore,
WhitespaceManager &Whitespaces) override;
+ bool mayReflow(unsigned LineIndex,
+ llvm::Regex &CommentPragmasRegex) const override;
private:
- // Rearranges the whitespace between Lines[LineIndex-1] and Lines[LineIndex],
- // so that all whitespace between the lines is accounted to Lines[LineIndex]
- // as leading whitespace:
- // - Lines[LineIndex] points to the text after that whitespace
- // - Lines[LineIndex-1] shrinks by its trailing whitespace
- // - LeadingWhitespace[LineIndex] is updated with the complete whitespace
- // between the end of the text of Lines[LineIndex-1] and Lines[LineIndex]
+ // Rearranges the whitespace between Lines[LineIndex-1] and Lines[LineIndex].
//
- // Sets StartOfLineColumn to the intended column in which the text at
+ // Updates Content[LineIndex-1] and Content[LineIndex] by stripping off
+ // leading and trailing whitespace.
+ //
+ // Sets ContentColumn to the intended column in which the text at
// Lines[LineIndex] starts (note that the decoration, if present, is not
// considered part of the text).
void adjustWhitespace(unsigned LineIndex, int IndentDelta);
- // Returns the column at which the text in line LineIndex starts, when broken
- // at TailOffset. Note that the decoration (if present) is not considered part
- // of the text.
- unsigned getContentStartColumn(unsigned LineIndex, unsigned TailOffset) const;
-
- // Contains the text of the lines of the block comment, excluding the leading
- // /* in the first line and trailing */ in the last line, and excluding all
- // trailing whitespace between the lines. Note that the decoration (if
- // present) is also not considered part of the text.
- SmallVector<StringRef, 16> Lines;
+ // Computes the end column if the full Content from LineIndex gets reflown
+ // after PreviousEndColumn.
+ unsigned getReflownColumn(StringRef Content, unsigned LineIndex,
+ unsigned PreviousEndColumn) const;
- // LeadingWhitespace[i] is the number of characters regarded as whitespace in
- // front of Lines[i]. Note that this can include "* " sequences, which we
- // regard as whitespace when all lines have a "*" prefix.
- SmallVector<unsigned, 16> LeadingWhitespace;
-
- // StartOfLineColumn[i] is the target column at which Line[i] should be.
- // Note that this excludes a leading "* " or "*" in case all lines have
- // a "*" prefix.
- // The first line's target column is always positive. The remaining lines'
- // target columns are relative to the first line to allow correct indentation
- // of comments in \c WhitespaceManager. Thus they can be negative as well (in
- // case the first line needs to be unindented more than there's actual
- // whitespace in another line).
- SmallVector<int, 16> StartOfLineColumn;
+ unsigned getContentStartColumn(unsigned LineIndex,
+ unsigned TailOffset) const override;
// The column at which the text of a broken line should start.
// Note that an optional decoration would go before that column.
@@ -237,8 +344,69 @@ private:
// Either "* " if all lines begin with a "*", or empty.
StringRef Decoration;
+
+ // If this block comment has decorations, this is the column of the start of
+ // the decorations.
+ unsigned DecorationColumn;
};
+class BreakableLineCommentSection : public BreakableComment {
+public:
+ BreakableLineCommentSection(const FormatToken &Token, unsigned StartColumn,
+ unsigned OriginalStartColumn, bool FirstInLine,
+ bool InPPDirective, encoding::Encoding Encoding,
+ const FormatStyle &Style);
+
+ unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
+ StringRef::size_type Length) const override;
+ void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ Split getSplitBefore(unsigned LineIndex, unsigned PreviousEndColumn,
+ unsigned ColumnLimit,
+ llvm::Regex &CommentPragmasRegex) const override;
+ unsigned getLineLengthAfterSplitBefore(unsigned LineIndex,
+ unsigned TailOffset,
+ unsigned PreviousEndColumn,
+ unsigned ColumnLimit,
+ Split SplitBefore) const override;
+ void replaceWhitespaceBefore(unsigned LineIndex, unsigned PreviousEndColumn,
+ unsigned ColumnLimit, Split SplitBefore,
+ WhitespaceManager &Whitespaces) override;
+ void updateNextToken(LineState &State) const override;
+ bool mayReflow(unsigned LineIndex,
+ llvm::Regex &CommentPragmasRegex) const override;
+
+private:
+ unsigned getContentStartColumn(unsigned LineIndex,
+ unsigned TailOffset) const override;
+
+ // OriginalPrefix[i] contains the original prefix of line i, including
+ // trailing whitespace before the start of the content. The indentation
+ // preceding the prefix is not included.
+ // For example, if the line is:
+ // // content
+ // then the original prefix is "// ".
+ SmallVector<StringRef, 16> OriginalPrefix;
+
+ // Prefix[i] contains the intended leading "//" with trailing spaces to
+ // account for the indentation of content within the comment at line i after
+ // formatting. It can be different than the original prefix when the original
+ // line starts like this:
+ // //content
+ // Then the original prefix is "//", but the prefix is "// ".
+ SmallVector<StringRef, 16> Prefix;
+
+ SmallVector<unsigned, 16> OriginalContentColumn;
+
+ /// \brief The token to which the last line of this breakable token belongs
+ /// to; nullptr if that token is the initial token.
+ ///
+ /// The distinction is because if the token of the last line of this breakable
+ /// token is distinct from the initial token, this breakable token owns the
+ /// whitespace before the token of the last line, and the whitespace manager
+ /// must be able to modify it.
+ FormatToken *LastLineTok = nullptr;
+};
} // namespace format
} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Format/Comments.cpp b/contrib/llvm/tools/clang/lib/Format/Comments.cpp
deleted file mode 100644
index 1b27f5b..0000000
--- a/contrib/llvm/tools/clang/lib/Format/Comments.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-//===--- Comments.cpp - Comment Manipulation -------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Implements comment manipulation.
-///
-//===----------------------------------------------------------------------===//
-
-#include "Comments.h"
-
-namespace clang {
-namespace format {
-
-StringRef getLineCommentIndentPrefix(StringRef Comment) {
- static const char *const KnownPrefixes[] = {"///", "//", "//!"};
- StringRef LongestPrefix;
- for (StringRef KnownPrefix : KnownPrefixes) {
- if (Comment.startswith(KnownPrefix)) {
- size_t PrefixLength = KnownPrefix.size();
- while (PrefixLength < Comment.size() && Comment[PrefixLength] == ' ')
- ++PrefixLength;
- if (PrefixLength > LongestPrefix.size())
- LongestPrefix = Comment.substr(0, PrefixLength);
- }
- }
- return LongestPrefix;
-}
-
-} // namespace format
-} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Format/Comments.h b/contrib/llvm/tools/clang/lib/Format/Comments.h
deleted file mode 100644
index 59f0596..0000000
--- a/contrib/llvm/tools/clang/lib/Format/Comments.h
+++ /dev/null
@@ -1,33 +0,0 @@
-//===--- Comments.cpp - Comment manipulation -----------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Declares comment manipulation functionality.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_LIB_FORMAT_COMMENTS_H
-#define LLVM_CLANG_LIB_FORMAT_COMMENTS_H
-
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/StringRef.h"
-
-namespace clang {
-namespace format {
-
-/// \brief Returns the comment prefix of the line comment \p Comment.
-///
-/// The comment prefix consists of a leading known prefix, like "//" or "///",
-/// together with the following whitespace.
-StringRef getLineCommentIndentPrefix(StringRef Comment);
-
-} // namespace format
-} // namespace clang
-
-#endif
diff --git a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp
index 6bb6fb3..3bf1cd8 100644
--- a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp
+++ b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp
@@ -20,7 +20,7 @@
#include "clang/Format/Format.h"
#include "llvm/Support/Debug.h"
-#define DEBUG_TYPE "format-formatter"
+#define DEBUG_TYPE "format-indenter"
namespace clang {
namespace format {
@@ -54,11 +54,26 @@ static bool startsNextParameter(const FormatToken &Current,
const FormatStyle &Style) {
const FormatToken &Previous = *Current.Previous;
if (Current.is(TT_CtorInitializerComma) &&
- Style.BreakConstructorInitializersBeforeComma)
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
+ return true;
+ if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName))
return true;
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
- (Previous.isNot(TT_CtorInitializerComma) ||
- !Style.BreakConstructorInitializersBeforeComma);
+ ((Previous.isNot(TT_CtorInitializerComma) ||
+ Style.BreakConstructorInitializers !=
+ FormatStyle::BCIS_BeforeComma) &&
+ (Previous.isNot(TT_InheritanceComma) ||
+ !Style.BreakBeforeInheritanceComma));
+}
+
+static bool opensProtoMessageField(const FormatToken &LessTok,
+ const FormatStyle &Style) {
+ if (LessTok.isNot(tok::less))
+ return false;
+ return Style.Language == FormatStyle::LK_TextProto ||
+ (Style.Language == FormatStyle::LK_Proto &&
+ (LessTok.NestingLevel > 0 ||
+ (LessTok.Previous && LessTok.Previous->is(tok::equal))));
}
ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
@@ -80,7 +95,7 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
State.Column = FirstIndent;
State.Line = Line;
State.NextToken = Line->First;
- State.Stack.push_back(ParenState(FirstIndent, Line->Level, FirstIndent,
+ State.Stack.push_back(ParenState(FirstIndent, FirstIndent,
/*AvoidBinPacking=*/false,
/*NoLineBreak=*/false));
State.LineContainsContinuedForLoopSection = false;
@@ -89,6 +104,13 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
State.LowestLevelOnLine = 0;
State.IgnoreStackForComparison = false;
+ if (Style.Language == FormatStyle::LK_TextProto) {
+ // We need this in order to deal with the bin packing of text fields at
+ // global scope.
+ State.Stack.back().AvoidBinPacking = true;
+ State.Stack.back().BreakBeforeParameter = true;
+ }
+
// The first token has already been indented and thus consumed.
moveStateToNextToken(State, DryRun, /*Newline=*/false);
return State;
@@ -135,6 +157,12 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
return false;
}
+ // If binary operators are moved to the next line (including commas for some
+ // styles of constructor initializers), that's always ok.
+ if (!Current.isOneOf(TT_BinaryOperator, tok::comma) &&
+ State.Stack.back().NoLineBreakInOperand)
+ return false;
+
return !State.Stack.back().NoLineBreak;
}
@@ -150,7 +178,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
(Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName) &&
- Style.Language == FormatStyle::LK_Cpp &&
+ Style.isCpp() &&
// FIXME: This is a temporary workaround for the case where clang-format
// sets BreakBeforeParameter to avoid bin packing and this creates a
// completely unnecessary line break after a template type that isn't
@@ -165,18 +193,26 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) ||
(Previous.is(TT_ArrayInitializerLSquare) &&
- Previous.ParameterCount > 1)) &&
+ Previous.ParameterCount > 1) ||
+ opensProtoMessageField(Previous, Style)) &&
Style.ColumnLimit > 0 &&
getLengthToMatchingParen(Previous) + State.Column - 1 >
getColumnLimit(State))
return true;
- if (Current.is(TT_CtorInitializerColon) &&
- (State.Column + State.Line->Last->TotalLength - Current.TotalLength + 2 >
+
+ const FormatToken &BreakConstructorInitializersToken =
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon
+ ? Previous
+ : Current;
+ if (BreakConstructorInitializersToken.is(TT_CtorInitializerColon) &&
+ (State.Column + State.Line->Last->TotalLength - Previous.TotalLength >
getColumnLimit(State) ||
State.Stack.back().BreakBeforeParameter) &&
- ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) ||
- Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))
+ (Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All ||
+ Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeColon ||
+ Style.ColumnLimit != 0))
return true;
+
if (Current.is(TT_ObjCMethodExpr) && !Previous.is(TT_SelectorName) &&
State.Line->startsWith(TT_ObjCMethodSpecifier))
return true;
@@ -191,6 +227,18 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
Current.NestingLevel < State.StartOfLineLevel))
return true;
+ if (startsSegmentOfBuilderTypeCall(Current) &&
+ (State.Stack.back().CallContinuation != 0 ||
+ State.Stack.back().BreakBeforeParameter) &&
+ // JavaScript is treated different here as there is a frequent pattern:
+ // SomeFunction(function() {
+ // ...
+ // }.bind(...));
+ // FIXME: We should find a more generic solution to this problem.
+ !(State.Column <= NewLineColumn &&
+ Style.Language == FormatStyle::LK_JavaScript))
+ return true;
+
if (State.Column <= NewLineColumn)
return false;
@@ -255,11 +303,6 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
!Previous.is(tok::kw_template) && State.Stack.back().BreakBeforeParameter)
return true;
- if (startsSegmentOfBuilderTypeCall(Current) &&
- (State.Stack.back().CallContinuation != 0 ||
- State.Stack.back().BreakBeforeParameter))
- return true;
-
// The following could be precomputed as they do not depend on the state.
// However, as they should take effect only if the UnwrappedLine does not fit
// into the ColumnLimit, they are checked here in the ContinuationIndenter.
@@ -334,8 +377,13 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
unsigned Spaces = Current.SpacesRequiredBefore + ExtraSpaces;
if (!DryRun)
- Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0,
- Spaces, State.Column + Spaces);
+ Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, Spaces,
+ State.Column + Spaces);
+
+ // If "BreakBeforeInheritanceComma" mode, don't break within the inheritance
+ // declaration unless there is multiple inheritance.
+ if (Style.BreakBeforeInheritanceComma && Current.is(TT_InheritanceColon))
+ State.Stack.back().NoLineBreak = true;
if (Current.is(TT_SelectorName) &&
!State.Stack.back().ObjCSelectorNameFound) {
@@ -370,6 +418,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
Current.FakeLParens.size() > 0 &&
Current.FakeLParens.back() > prec::Unknown)
State.Stack.back().NoLineBreak = true;
+ if (Previous.is(TT_TemplateString) && Previous.opensScope())
+ State.Stack.back().NoLineBreak = true;
if (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign &&
Previous.opensScope() && Previous.isNot(TT_ObjCMethodExpr) &&
@@ -385,7 +435,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
State.Stack.back().NoLineBreak = true;
if (Current.isMemberAccess() && Previous.is(tok::r_paren) &&
(Previous.MatchingParen &&
- (Previous.TotalLength - Previous.MatchingParen->TotalLength > 10))) {
+ (Previous.TotalLength - Previous.MatchingParen->TotalLength > 10)))
// If there is a function call with long parameters, break before trailing
// calls. This prevents things like:
// EXPECT_CALL(SomeLongParameter).Times(
@@ -393,12 +443,38 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
// We don't want to do this for short parameters as they can just be
// indexes.
State.Stack.back().NoLineBreak = true;
+
+ // Don't allow the RHS of an operator to be split over multiple lines unless
+ // there is a line-break right after the operator.
+ // Exclude relational operators, as there, it is always more desirable to
+ // have the LHS 'left' of the RHS.
+ const FormatToken *P = Current.getPreviousNonComment();
+ if (!Current.is(tok::comment) && P &&
+ (P->isOneOf(TT_BinaryOperator, tok::comma) ||
+ (P->is(TT_ConditionalExpr) && P->is(tok::colon))) &&
+ !P->isOneOf(TT_OverloadedOperator, TT_CtorInitializerComma) &&
+ P->getPrecedence() != prec::Assignment &&
+ P->getPrecedence() != prec::Relational) {
+ bool BreakBeforeOperator =
+ P->MustBreakBefore || P->is(tok::lessless) ||
+ (P->is(TT_BinaryOperator) &&
+ Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None) ||
+ (P->is(TT_ConditionalExpr) && Style.BreakBeforeTernaryOperators);
+ // Don't do this if there are only two operands. In these cases, there is
+ // always a nice vertical separation between them and the extra line break
+ // does not help.
+ bool HasTwoOperands =
+ P->OperatorIndex == 0 && !P->NextOperator && !P->is(TT_ConditionalExpr);
+ if ((!BreakBeforeOperator && !(HasTwoOperands && Style.AlignOperands)) ||
+ (!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator))
+ State.Stack.back().NoLineBreakInOperand = true;
}
State.Column += Spaces;
if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) &&
Previous.Previous &&
- Previous.Previous->isOneOf(tok::kw_if, tok::kw_for)) {
+ (Previous.Previous->isOneOf(tok::kw_if, tok::kw_for) ||
+ Previous.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) {
// Treat the condition inside an if as if it was a second function
// parameter, i.e. let nested calls have a continuation indent.
State.Stack.back().LastSpace = State.Column;
@@ -408,6 +484,11 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
!Previous.is(TT_OverloadedOperator)) ||
(Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) {
State.Stack.back().LastSpace = State.Column;
+ } else if (Previous.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers ==
+ FormatStyle::BCIS_AfterColon) {
+ State.Stack.back().Indent = State.Column;
+ State.Stack.back().LastSpace = State.Column;
} else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
TT_CtorInitializerColon)) &&
((Previous.getPrecedence() != prec::Assignment &&
@@ -540,9 +621,10 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
if (!DryRun) {
unsigned Newlines = std::max(
1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1));
- Whitespaces.replaceWhitespace(Current, Newlines,
- State.Stack.back().IndentLevel, State.Column,
- State.Column, State.Line->InPPDirective);
+ bool ContinuePPDirective =
+ State.Line->InPPDirective && State.Line->Type != LT_ImportStatement;
+ Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column,
+ ContinuePPDirective);
}
if (!Current.isTrailingComment())
@@ -559,16 +641,14 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
// Any break on this level means that the parent level has been broken
// and we need to avoid bin packing there.
bool NestedBlockSpecialCase =
- Style.Language != FormatStyle::LK_Cpp &&
- Style.Language != FormatStyle::LK_ObjC &&
- Current.is(tok::r_brace) && State.Stack.size() > 1 &&
+ !Style.isCpp() && Current.is(tok::r_brace) && State.Stack.size() > 1 &&
State.Stack[State.Stack.size() - 2].NestedBlockInlined;
if (!NestedBlockSpecialCase)
for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i)
State.Stack[i].BreakBeforeParameter = true;
if (PreviousNonComment &&
- !PreviousNonComment->isOneOf(tok::comma, tok::semi) &&
+ !PreviousNonComment->isOneOf(tok::comma, tok::colon, tok::semi) &&
(PreviousNonComment->isNot(TT_TemplateCloser) ||
Current.NestingLevel != 0) &&
!PreviousNonComment->isOneOf(
@@ -580,7 +660,10 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
// If we break after { or the [ of an array initializer, we should also break
// before the corresponding } or ].
if (PreviousNonComment &&
- (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)))
+ (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
+ opensProtoMessageField(*PreviousNonComment, Style) ||
+ (PreviousNonComment->is(TT_TemplateString) &&
+ PreviousNonComment->opensScope())))
State.Stack.back().BreakBeforeClosingBrace = true;
if (State.Stack.back().AvoidBinPacking) {
@@ -620,7 +703,11 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)
return Current.NestingLevel == 0 ? State.FirstIndent
: State.Stack.back().Indent;
- if (Current.isOneOf(tok::r_brace, tok::r_square) && State.Stack.size() > 1) {
+ if ((Current.isOneOf(tok::r_brace, tok::r_square) ||
+ (Current.is(tok::greater) &&
+ (Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto))) &&
+ State.Stack.size() > 1) {
if (Current.closesBlockOrBlockTypeList(Style))
return State.Stack[State.Stack.size() - 2].NestedBlockIndent;
if (Current.MatchingParen &&
@@ -628,14 +715,29 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
return State.Stack[State.Stack.size() - 2].LastSpace;
return State.FirstIndent;
}
+ // Indent a closing parenthesis at the previous level if followed by a semi or
+ // opening brace. This allows indentations such as:
+ // foo(
+ // a,
+ // );
+ // function foo(
+ // a,
+ // ) {
+ // code(); //
+ // }
+ if (Current.is(tok::r_paren) && State.Stack.size() > 1 &&
+ (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace)))
+ return State.Stack[State.Stack.size() - 2].LastSpace;
+ if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
+ return State.Stack[State.Stack.size() - 2].LastSpace;
if (Current.is(tok::identifier) && Current.Next &&
Current.Next->is(TT_DictLiteral))
return State.Stack.back().Indent;
- if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0)
- return State.StartOfStringLiteral;
if (NextNonComment->is(TT_ObjCStringLiteral) &&
State.StartOfStringLiteral != 0)
return State.StartOfStringLiteral - 1;
+ if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0)
+ return State.StartOfStringLiteral;
if (NextNonComment->is(tok::lessless) &&
State.Stack.back().FirstLessLess != 0)
return State.Stack.back().FirstLessLess;
@@ -696,10 +798,14 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&
PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral))
return ContinuationIndent;
- if (NextNonComment->is(TT_CtorInitializerColon))
- return State.FirstIndent + Style.ConstructorInitializerIndentWidth;
if (NextNonComment->is(TT_CtorInitializerComma))
return State.Stack.back().Indent;
+ if (PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon)
+ return State.Stack.back().Indent;
+ if (NextNonComment->isOneOf(TT_CtorInitializerColon, TT_InheritanceColon,
+ TT_InheritanceComma))
+ return State.FirstIndent + Style.ConstructorInitializerIndentWidth;
if (Previous.is(tok::r_paren) && !Current.isBinaryOperator() &&
!Current.isOneOf(tok::colon, tok::comment))
return ContinuationIndent;
@@ -716,6 +822,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
assert(State.Stack.size());
const FormatToken &Current = *State.NextToken;
+ if (Current.isOneOf(tok::comma, TT_BinaryOperator))
+ State.Stack.back().NoLineBreakInOperand = false;
if (Current.is(TT_InheritanceColon))
State.Stack.back().AvoidBinPacking = true;
if (Current.is(tok::lessless) && Current.isNot(TT_OverloadedOperator)) {
@@ -724,8 +832,10 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
else
State.Stack.back().LastOperatorWrapped = Newline;
}
- if ((Current.is(TT_BinaryOperator) && Current.isNot(tok::lessless)) ||
- Current.is(TT_ConditionalExpr))
+ if (Current.is(TT_BinaryOperator) && Current.isNot(tok::lessless))
+ State.Stack.back().LastOperatorWrapped = Newline;
+ if (Current.is(TT_ConditionalExpr) && Current.Previous &&
+ !Current.Previous->is(TT_ConditionalExpr))
State.Stack.back().LastOperatorWrapped = Newline;
if (Current.is(TT_ArraySubscriptLSquare) &&
State.Stack.back().StartOfArraySubscripts == 0)
@@ -739,7 +849,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
if (Previous && Previous->is(tok::question))
State.Stack.back().QuestionColumn = State.Column;
}
- if (!Current.opensScope() && !Current.closesScope())
+ if (!Current.opensScope() && !Current.closesScope() &&
+ !Current.is(TT_PointerOrReference))
State.LowestLevelOnLine =
std::min(State.LowestLevelOnLine, Current.NestingLevel);
if (Current.isMemberAccess())
@@ -752,22 +863,37 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
State.FirstIndent + Style.ContinuationIndentWidth;
}
}
- if (Current.is(TT_CtorInitializerColon)) {
+ if (Current.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon) {
// Indent 2 from the column, so:
// SomeClass::SomeClass()
// : First(...), ...
// Next(...)
// ^ line up here.
State.Stack.back().Indent =
- State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2);
+ State.Column + (Style.BreakConstructorInitializers ==
+ FormatStyle::BCIS_BeforeComma ? 0 : 2);
State.Stack.back().NestedBlockIndent = State.Stack.back().Indent;
if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
State.Stack.back().AvoidBinPacking = true;
State.Stack.back().BreakBeforeParameter = false;
}
+ if (Current.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon) {
+ State.Stack.back().Indent =
+ State.FirstIndent + Style.ConstructorInitializerIndentWidth;
+ State.Stack.back().NestedBlockIndent = State.Stack.back().Indent;
+ if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
+ State.Stack.back().AvoidBinPacking = true;
+ }
+ if (Current.is(TT_InheritanceColon))
+ State.Stack.back().Indent =
+ State.FirstIndent + Style.ContinuationIndentWidth;
if (Current.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && Newline)
State.Stack.back().NestedBlockIndent =
State.Column + Current.ColumnWidth + 1;
+ if (Current.isOneOf(TT_LambdaLSquare, TT_LambdaArrow))
+ State.Stack.back().LastSpace = State.Column;
// Insert scopes created by fake parenthesis.
const FormatToken *Previous = Current.getPreviousNonComment();
@@ -795,21 +921,30 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
}
moveStatePastFakeLParens(State, Newline);
- moveStatePastScopeOpener(State, Newline);
moveStatePastScopeCloser(State);
+ if (Current.is(TT_TemplateString) && Current.opensScope())
+ State.Stack.back().LastSpace =
+ (Current.IsMultiline ? Current.LastLineColumnWidth
+ : State.Column + Current.ColumnWidth) -
+ strlen("${");
+ bool CanBreakProtrudingToken = !State.Stack.back().NoLineBreak &&
+ !State.Stack.back().NoLineBreakInOperand;
+ moveStatePastScopeOpener(State, Newline);
moveStatePastFakeRParens(State);
- if (Current.isStringLiteral() && State.StartOfStringLiteral == 0)
- State.StartOfStringLiteral = State.Column;
if (Current.is(TT_ObjCStringLiteral) && State.StartOfStringLiteral == 0)
State.StartOfStringLiteral = State.Column + 1;
+ else if (Current.isStringLiteral() && State.StartOfStringLiteral == 0)
+ State.StartOfStringLiteral = State.Column;
else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) &&
!Current.isStringLiteral())
State.StartOfStringLiteral = 0;
State.Column += Current.ColumnWidth;
State.NextToken = State.NextToken->Next;
- unsigned Penalty = breakProtrudingToken(Current, State, DryRun);
+ unsigned Penalty = 0;
+ if (CanBreakProtrudingToken)
+ Penalty = breakProtrudingToken(Current, State, DryRun);
if (State.Column > getColumnLimit(State)) {
unsigned ExcessCharacters = State.Column - getColumnLimit(State);
Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
@@ -848,6 +983,13 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
I != E; ++I) {
ParenState NewParenState = State.Stack.back();
NewParenState.ContainsLineBreak = false;
+ NewParenState.LastOperatorWrapped = true;
+ NewParenState.NoLineBreak =
+ NewParenState.NoLineBreak || State.Stack.back().NoLineBreakInOperand;
+
+ // Don't propagate AvoidBinPacking into subexpressions of arg/param lists.
+ if (*I > prec::Comma)
+ NewParenState.AvoidBinPacking = false;
// Indent from 'LastSpace' unless these are fake parentheses encapsulating
// a builder type call after 'return' or, if the alignment after opening
@@ -862,24 +1004,6 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
std::max(std::max(State.Column, NewParenState.Indent),
State.Stack.back().LastSpace);
- // Don't allow the RHS of an operator to be split over multiple lines unless
- // there is a line-break right after the operator.
- // Exclude relational operators, as there, it is always more desirable to
- // have the LHS 'left' of the RHS.
- if (Previous && Previous->getPrecedence() != prec::Assignment &&
- Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr, tok::comma) &&
- Previous->getPrecedence() != prec::Relational) {
- bool BreakBeforeOperator =
- Previous->is(tok::lessless) ||
- (Previous->is(TT_BinaryOperator) &&
- Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None) ||
- (Previous->is(TT_ConditionalExpr) &&
- Style.BreakBeforeTernaryOperators);
- if ((!Newline && !BreakBeforeOperator) ||
- (!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator))
- NewParenState.NoLineBreak = true;
- }
-
// Do not indent relative to the fake parentheses inserted for "." or "->".
// This is a special case to make the following to statements consistent:
// OuterFunction(InnerFunctionCall( // break
@@ -931,17 +1055,16 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
}
unsigned NewIndent;
- unsigned NewIndentLevel = State.Stack.back().IndentLevel;
unsigned LastSpace = State.Stack.back().LastSpace;
bool AvoidBinPacking;
bool BreakBeforeParameter = false;
unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall,
State.Stack.back().NestedBlockIndent);
- if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) {
+ if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
+ opensProtoMessageField(Current, Style)) {
if (Current.opensBlockOrBlockTypeList(Style)) {
- NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth;
- NewIndent = std::min(State.Column + 2, NewIndent);
- ++NewIndentLevel;
+ NewIndent = Style.IndentWidth +
+ std::min(State.Column, State.Stack.back().NestedBlockIndent);
} else {
NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
}
@@ -950,10 +1073,14 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
Current.MatchingParen->Previous &&
Current.MatchingParen->Previous->is(tok::comma);
AvoidBinPacking =
- (Current.is(TT_ArrayInitializerLSquare) && EndsInComma) ||
- Current.is(TT_DictLiteral) ||
- Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments ||
- (NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod));
+ EndsInComma || Current.is(TT_DictLiteral) ||
+ Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto ||
+ !Style.BinPackArguments ||
+ (NextNoComment &&
+ NextNoComment->isOneOf(TT_DesignatedInitializerPeriod,
+ TT_DesignatedInitializerLSquare));
+ BreakBeforeParameter = EndsInComma;
if (Current.ParameterCount > 1)
NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1);
} else {
@@ -966,19 +1093,37 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
// int> v);
// FIXME: We likely want to do this for more combinations of brackets.
// Verify that it is wanted for ObjC, too.
- if (Current.Tok.getKind() == tok::less &&
- Current.ParentBracket == tok::l_paren) {
+ if (Current.is(tok::less) && Current.ParentBracket == tok::l_paren) {
NewIndent = std::max(NewIndent, State.Stack.back().Indent);
LastSpace = std::max(LastSpace, State.Stack.back().Indent);
}
+ // JavaScript template strings are special as we always want to indent
+ // nested expressions relative to the ${}. Otherwise, this can create quite
+ // a mess.
+ if (Current.is(TT_TemplateString)) {
+ unsigned Column = Current.IsMultiline
+ ? Current.LastLineColumnWidth
+ : State.Column + Current.ColumnWidth;
+ NewIndent = Column;
+ LastSpace = Column;
+ NestedBlockIndent = Column;
+ }
+
+ bool EndsInComma =
+ Current.MatchingParen &&
+ Current.MatchingParen->getPreviousNonComment() &&
+ Current.MatchingParen->getPreviousNonComment()->is(tok::comma);
+
AvoidBinPacking =
+ (Style.Language == FormatStyle::LK_JavaScript && EndsInComma) ||
(State.Line->MustBeDeclaration && !Style.BinPackParameters) ||
(!State.Line->MustBeDeclaration && !Style.BinPackArguments) ||
(Style.ExperimentalAutoDetectBinPacking &&
(Current.PackingKind == PPK_OnePerLine ||
(!BinPackInconclusiveFunctions &&
Current.PackingKind == PPK_Inconclusive)));
+
if (Current.is(TT_ObjCMethodExpr) && Current.MatchingParen) {
if (Style.ColumnLimit) {
// If this '[' opens an ObjC call, determine whether all parameters fit
@@ -999,21 +1144,22 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
}
}
}
+
+ if (Style.Language == FormatStyle::LK_JavaScript && EndsInComma)
+ BreakBeforeParameter = true;
}
// Generally inherit NoLineBreak from the current scope to nested scope.
// However, don't do this for non-empty nested blocks, dict literals and
// array literals as these follow different indentation rules.
- const FormatToken *Previous = Current.getPreviousNonComment();
bool NoLineBreak =
Current.Children.empty() &&
!Current.isOneOf(TT_DictLiteral, TT_ArrayInitializerLSquare) &&
(State.Stack.back().NoLineBreak ||
+ State.Stack.back().NoLineBreakInOperand ||
(Current.is(TT_TemplateOpener) &&
- State.Stack.back().ContainsUnwrappedBuilder) ||
- (Current.is(tok::l_brace) && !Newline && Previous &&
- Previous->is(tok::comma)));
- State.Stack.push_back(ParenState(NewIndent, NewIndentLevel, LastSpace,
- AvoidBinPacking, NoLineBreak));
+ State.Stack.back().ContainsUnwrappedBuilder));
+ State.Stack.push_back(
+ ParenState(NewIndent, LastSpace, AvoidBinPacking, NoLineBreak));
State.Stack.back().NestedBlockIndent = NestedBlockIndent;
State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1;
@@ -1027,7 +1173,7 @@ void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) {
// If we encounter a closing ), ], } or >, we can remove a level from our
// stacks.
if (State.Stack.size() > 1 &&
- (Current.isOneOf(tok::r_paren, tok::r_square) ||
+ (Current.isOneOf(tok::r_paren, tok::r_square, TT_TemplateString) ||
(Current.is(tok::r_brace) && State.NextToken != State.Line->First) ||
State.NextToken->is(TT_TemplateCloser)))
State.Stack.pop_back();
@@ -1047,10 +1193,9 @@ void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
NestedBlockIndent + (State.NextToken->is(TT_ObjCBlockLBrace)
? Style.ObjCBlockIndentWidth
: Style.IndentWidth);
- State.Stack.push_back(ParenState(
- NewIndent, /*NewIndentLevel=*/State.Stack.back().IndentLevel + 1,
- State.Stack.back().LastSpace, /*AvoidBinPacking=*/true,
- /*NoLineBreak=*/false));
+ State.Stack.push_back(ParenState(NewIndent, State.Stack.back().LastSpace,
+ /*AvoidBinPacking=*/true,
+ /*NoLineBreak=*/false));
State.Stack.back().NestedBlockIndent = NestedBlockIndent;
State.Stack.back().BreakBeforeParameter = true;
}
@@ -1117,44 +1262,42 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
StringRef Text = Current.TokenText;
StringRef Prefix;
StringRef Postfix;
- bool IsNSStringLiteral = false;
// FIXME: Handle whitespace between '_T', '(', '"..."', and ')'.
// FIXME: Store Prefix and Suffix (or PrefixLength and SuffixLength to
// reduce the overhead) for each FormatToken, which is a string, so that we
// don't run multiple checks here on the hot path.
- if (Text.startswith("\"") && Current.Previous &&
- Current.Previous->is(tok::at)) {
- IsNSStringLiteral = true;
- Prefix = "@\"";
- }
if ((Text.endswith(Postfix = "\"") &&
- (IsNSStringLiteral || Text.startswith(Prefix = "\"") ||
+ (Text.startswith(Prefix = "@\"") || Text.startswith(Prefix = "\"") ||
Text.startswith(Prefix = "u\"") || Text.startswith(Prefix = "U\"") ||
Text.startswith(Prefix = "u8\"") ||
Text.startswith(Prefix = "L\""))) ||
(Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) {
- Token.reset(new BreakableStringLiteral(
- Current, State.Line->Level, StartColumn, Prefix, Postfix,
- State.Line->InPPDirective, Encoding, Style));
+ Token.reset(new BreakableStringLiteral(Current, StartColumn, Prefix,
+ Postfix, State.Line->InPPDirective,
+ Encoding, Style));
} else {
return 0;
}
} else if (Current.is(TT_BlockComment)) {
if (!Current.isTrailingComment() || !Style.ReflowComments ||
- CommentPragmasRegex.match(Current.TokenText.substr(2)))
+ // If a comment token switches formatting, like
+ // /* clang-format on */, we don't want to break it further,
+ // but we may still want to adjust its indentation.
+ switchesFormatting(Current))
return addMultilineToken(Current, State);
Token.reset(new BreakableBlockComment(
- Current, State.Line->Level, StartColumn, Current.OriginalColumn,
- !Current.Previous, State.Line->InPPDirective, Encoding, Style));
+ Current, StartColumn, Current.OriginalColumn, !Current.Previous,
+ State.Line->InPPDirective, Encoding, Style));
} else if (Current.is(TT_LineComment) &&
(Current.Previous == nullptr ||
Current.Previous->isNot(TT_ImplicitStringLiteral))) {
if (!Style.ReflowComments ||
- CommentPragmasRegex.match(Current.TokenText.substr(2)))
+ CommentPragmasRegex.match(Current.TokenText.substr(2)) ||
+ switchesFormatting(Current))
return 0;
- Token.reset(new BreakableLineComment(Current, State.Line->Level,
- StartColumn, /*InPPDirective=*/false,
- Encoding, Style));
+ Token.reset(new BreakableLineCommentSection(
+ Current, StartColumn, Current.OriginalColumn, !Current.Previous,
+ /*InPPDirective=*/false, Encoding, Style));
// We don't insert backslashes when breaking line comments.
ColumnLimit = Style.ColumnLimit;
} else {
@@ -1165,18 +1308,30 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
unsigned RemainingSpace = ColumnLimit - Current.UnbreakableTailLength;
bool BreakInserted = false;
+ // We use a conservative reflowing strategy. Reflow starts after a line is
+ // broken or the corresponding whitespace compressed. Reflow ends as soon as a
+ // line that doesn't get reflown with the previous line is reached.
+ bool ReflowInProgress = false;
unsigned Penalty = 0;
unsigned RemainingTokenColumns = 0;
for (unsigned LineIndex = 0, EndIndex = Token->getLineCount();
LineIndex != EndIndex; ++LineIndex) {
+ BreakableToken::Split SplitBefore(StringRef::npos, 0);
+ if (ReflowInProgress) {
+ SplitBefore = Token->getSplitBefore(LineIndex, RemainingTokenColumns,
+ RemainingSpace, CommentPragmasRegex);
+ }
+ ReflowInProgress = SplitBefore.first != StringRef::npos;
+ unsigned TailOffset =
+ ReflowInProgress ? (SplitBefore.first + SplitBefore.second) : 0;
if (!DryRun)
- Token->replaceWhitespaceBefore(LineIndex, Whitespaces);
- unsigned TailOffset = 0;
- RemainingTokenColumns =
- Token->getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
+ Token->replaceWhitespaceBefore(LineIndex, RemainingTokenColumns,
+ RemainingSpace, SplitBefore, Whitespaces);
+ RemainingTokenColumns = Token->getLineLengthAfterSplitBefore(
+ LineIndex, TailOffset, RemainingTokenColumns, ColumnLimit, SplitBefore);
while (RemainingTokenColumns > RemainingSpace) {
- BreakableToken::Split Split =
- Token->getSplit(LineIndex, TailOffset, ColumnLimit);
+ BreakableToken::Split Split = Token->getSplit(
+ LineIndex, TailOffset, ColumnLimit, CommentPragmasRegex);
if (Split.first == StringRef::npos) {
// The last line's penalty is handled in addNextStateToQueue().
if (LineIndex < EndIndex - 1)
@@ -1185,17 +1340,23 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
break;
}
assert(Split.first != 0);
- unsigned NewRemainingTokenColumns = Token->getLineLengthAfterSplit(
- LineIndex, TailOffset + Split.first + Split.second, StringRef::npos);
- // We can remove extra whitespace instead of breaking the line.
- if (RemainingTokenColumns + 1 - Split.second <= RemainingSpace) {
- RemainingTokenColumns = 0;
+ // Check if compressing the whitespace range will bring the line length
+ // under the limit. If that is the case, we perform whitespace compression
+ // instead of inserting a line break.
+ unsigned RemainingTokenColumnsAfterCompression =
+ Token->getLineLengthAfterCompression(RemainingTokenColumns, Split);
+ if (RemainingTokenColumnsAfterCompression <= RemainingSpace) {
+ RemainingTokenColumns = RemainingTokenColumnsAfterCompression;
+ ReflowInProgress = true;
if (!DryRun)
- Token->replaceWhitespace(LineIndex, TailOffset, Split, Whitespaces);
+ Token->compressWhitespace(LineIndex, TailOffset, Split, Whitespaces);
break;
}
+ unsigned NewRemainingTokenColumns = Token->getLineLengthAfterSplit(
+ LineIndex, TailOffset + Split.first + Split.second, StringRef::npos);
+
// When breaking before a tab character, it may be moved by a few columns,
// but will still be expanded to the next tab stop, so we don't save any
// columns.
@@ -1213,6 +1374,7 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
}
TailOffset += Split.first + Split.second;
RemainingTokenColumns = NewRemainingTokenColumns;
+ ReflowInProgress = true;
BreakInserted = true;
}
}
@@ -1233,6 +1395,9 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
State.Stack.back().LastSpace = StartColumn;
}
+
+ Token->updateNextToken(State);
+
return Penalty;
}
diff --git a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.h b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.h
index 21ad653..9a06aa6 100644
--- a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.h
+++ b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.h
@@ -146,12 +146,12 @@ private:
};
struct ParenState {
- ParenState(unsigned Indent, unsigned IndentLevel, unsigned LastSpace,
- bool AvoidBinPacking, bool NoLineBreak)
- : Indent(Indent), IndentLevel(IndentLevel), LastSpace(LastSpace),
- NestedBlockIndent(Indent), BreakBeforeClosingBrace(false),
- AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
- NoLineBreak(NoLineBreak), LastOperatorWrapped(true),
+ ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking,
+ bool NoLineBreak)
+ : Indent(Indent), LastSpace(LastSpace), NestedBlockIndent(Indent),
+ BreakBeforeClosingBrace(false), AvoidBinPacking(AvoidBinPacking),
+ BreakBeforeParameter(false), NoLineBreak(NoLineBreak),
+ NoLineBreakInOperand(false), LastOperatorWrapped(true),
ContainsLineBreak(false), ContainsUnwrappedBuilder(false),
AlignColons(true), ObjCSelectorNameFound(false),
HasMultipleNestedBlocks(false), NestedBlockInlined(false) {}
@@ -160,9 +160,6 @@ struct ParenState {
/// indented.
unsigned Indent;
- /// \brief The number of indentation levels of the block.
- unsigned IndentLevel;
-
/// \brief The position of the last space on each level.
///
/// Used e.g. to break like:
@@ -224,6 +221,10 @@ struct ParenState {
/// \brief Line breaking in this context would break a formatting rule.
bool NoLineBreak : 1;
+ /// \brief Same as \c NoLineBreak, but is restricted until the end of the
+ /// operand (including the next ",").
+ bool NoLineBreakInOperand : 1;
+
/// \brief True if the last binary operator on this level was wrapped to the
/// next line.
bool LastOperatorWrapped : 1;
diff --git a/contrib/llvm/tools/clang/lib/Format/Format.cpp b/contrib/llvm/tools/clang/lib/Format/Format.cpp
index 389761d..aa4ed8c 100644
--- a/contrib/llvm/tools/clang/lib/Format/Format.cpp
+++ b/contrib/llvm/tools/clang/lib/Format/Format.cpp
@@ -17,11 +17,13 @@
#include "AffectedRangeManager.h"
#include "ContinuationIndenter.h"
#include "FormatTokenLexer.h"
+#include "NamespaceEndCommentsFixer.h"
#include "SortJavaScriptImports.h"
#include "TokenAnalyzer.h"
#include "TokenAnnotator.h"
#include "UnwrappedLineFormatter.h"
#include "UnwrappedLineParser.h"
+#include "UsingDeclarationsSorter.h"
#include "WhitespaceManager.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
@@ -42,7 +44,6 @@
using clang::format::FormatStyle;
-LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)
namespace llvm {
@@ -55,6 +56,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC);
IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
+ IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto);
}
};
@@ -95,6 +97,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
IO.enumCase(Value, "All", FormatStyle::SFS_All);
IO.enumCase(Value, "true", FormatStyle::SFS_All);
IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
+ IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
}
};
@@ -122,6 +125,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
}
};
+template <> struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
+ static void enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
+ IO.enumCase(Value, "BeforeColon", FormatStyle::BCIS_BeforeColon);
+ IO.enumCase(Value, "BeforeComma", FormatStyle::BCIS_BeforeComma);
+ IO.enumCase(Value, "AfterColon", FormatStyle::BCIS_AfterColon);
+ }
+};
+
template <>
struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
@@ -170,6 +181,18 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
}
};
+template <> struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
+ static void enumeration(IO &IO, FormatStyle::EscapedNewlineAlignmentStyle &Value) {
+ IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign);
+ IO.enumCase(Value, "Left", FormatStyle::ENAS_Left);
+ IO.enumCase(Value, "Right", FormatStyle::ENAS_Right);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "true", FormatStyle::ENAS_Left);
+ IO.enumCase(Value, "false", FormatStyle::ENAS_Right);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
@@ -232,6 +255,7 @@ template <> struct MappingTraits<FormatStyle> {
// For backward compatibility.
if (!IO.outputting()) {
+ IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines);
IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
IO.mapOptional("IndentFunctionDeclarationAfterType",
Style.IndentWrappedFunctionNames);
@@ -246,7 +270,7 @@ template <> struct MappingTraits<FormatStyle> {
Style.AlignConsecutiveAssignments);
IO.mapOptional("AlignConsecutiveDeclarations",
Style.AlignConsecutiveDeclarations);
- IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlinesLeft);
+ IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
IO.mapOptional("AlignOperands", Style.AlignOperands);
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
@@ -288,15 +312,29 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("BreakBeforeBinaryOperators",
Style.BreakBeforeBinaryOperators);
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
+ IO.mapOptional("BreakBeforeInheritanceComma",
+ Style.BreakBeforeInheritanceComma);
IO.mapOptional("BreakBeforeTernaryOperators",
Style.BreakBeforeTernaryOperators);
+
+ bool BreakConstructorInitializersBeforeComma = false;
IO.mapOptional("BreakConstructorInitializersBeforeComma",
- Style.BreakConstructorInitializersBeforeComma);
+ BreakConstructorInitializersBeforeComma);
+ IO.mapOptional("BreakConstructorInitializers",
+ Style.BreakConstructorInitializers);
+ // If BreakConstructorInitializersBeforeComma was specified but
+ // BreakConstructorInitializers was not, initialize the latter from the
+ // former for backwards compatibility.
+ if (BreakConstructorInitializersBeforeComma &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon)
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
+
IO.mapOptional("BreakAfterJavaFieldAnnotations",
Style.BreakAfterJavaFieldAnnotations);
IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
IO.mapOptional("ColumnLimit", Style.ColumnLimit);
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
+ IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
IO.mapOptional("ConstructorInitializerIndentWidth",
@@ -307,6 +345,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("DisableFormat", Style.DisableFormat);
IO.mapOptional("ExperimentalAutoDetectBinPacking",
Style.ExperimentalAutoDetectBinPacking);
+ IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
IO.mapOptional("ForEachMacros", Style.ForEachMacros);
IO.mapOptional("IncludeCategories", Style.IncludeCategories);
IO.mapOptional("IncludeIsMainRegex", Style.IncludeIsMainRegex);
@@ -326,6 +365,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
IO.mapOptional("ObjCSpaceBeforeProtocolList",
Style.ObjCSpaceBeforeProtocolList);
+ IO.mapOptional("PenaltyBreakAssignment",
+ Style.PenaltyBreakAssignment);
IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
Style.PenaltyBreakBeforeFirstCallParameter);
IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment);
@@ -338,6 +379,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("PointerAlignment", Style.PointerAlignment);
IO.mapOptional("ReflowComments", Style.ReflowComments);
IO.mapOptional("SortIncludes", Style.SortIncludes);
+ IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
IO.mapOptional("SpaceAfterTemplateKeyword", Style.SpaceAfterTemplateKeyword);
IO.mapOptional("SpaceBeforeAssignmentOperators",
@@ -372,6 +414,9 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
+ IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
+ IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
+ IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
}
};
@@ -421,6 +466,11 @@ std::error_code make_error_code(ParseError e) {
return std::error_code(static_cast<int>(e), getParseCategory());
}
+inline llvm::Error make_string_error(const llvm::Twine &Message) {
+ return llvm::make_error<llvm::StringError>(Message,
+ llvm::inconvertibleErrorCode());
+}
+
const char *ParseErrorCategory::name() const noexcept {
return "clang-format.parse_error";
}
@@ -442,7 +492,8 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
return Style;
FormatStyle Expanded = Style;
Expanded.BraceWrapping = {false, false, false, false, false, false,
- false, false, false, false, false};
+ false, false, false, false, false, true,
+ true, true};
switch (Style.BreakBeforeBraces) {
case FormatStyle::BS_Linux:
Expanded.BraceWrapping.AfterClass = true;
@@ -455,6 +506,8 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
Expanded.BraceWrapping.AfterFunction = true;
Expanded.BraceWrapping.AfterStruct = true;
Expanded.BraceWrapping.AfterUnion = true;
+ Expanded.BraceWrapping.SplitEmptyFunction = false;
+ Expanded.BraceWrapping.SplitEmptyRecord = false;
break;
case FormatStyle::BS_Stroustrup:
Expanded.BraceWrapping.AfterFunction = true;
@@ -474,7 +527,8 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
break;
case FormatStyle::BS_GNU:
Expanded.BraceWrapping = {true, true, true, true, true, true,
- true, true, true, true, true};
+ true, true, true, true, true, true,
+ true, true};
break;
case FormatStyle::BS_WebKit:
Expanded.BraceWrapping.AfterFunction = true;
@@ -489,7 +543,7 @@ FormatStyle getLLVMStyle() {
FormatStyle LLVMStyle;
LLVMStyle.Language = FormatStyle::LK_Cpp;
LLVMStyle.AccessModifierOffset = -2;
- LLVMStyle.AlignEscapedNewlinesLeft = false;
+ LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
LLVMStyle.AlignOperands = true;
LLVMStyle.AlignTrailingComments = true;
@@ -505,31 +559,35 @@ FormatStyle getLLVMStyle() {
LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AlwaysBreakTemplateDeclarations = false;
- LLVMStyle.BinPackParameters = true;
LLVMStyle.BinPackArguments = true;
+ LLVMStyle.BinPackParameters = true;
LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
LLVMStyle.BreakBeforeTernaryOperators = true;
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
LLVMStyle.BraceWrapping = {false, false, false, false, false, false,
- false, false, false, false, false};
+ false, false, false, false, false, true,
+ true, true};
LLVMStyle.BreakAfterJavaFieldAnnotations = false;
- LLVMStyle.BreakConstructorInitializersBeforeComma = false;
+ LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
+ LLVMStyle.BreakBeforeInheritanceComma = false;
LLVMStyle.BreakStringLiterals = true;
LLVMStyle.ColumnLimit = 80;
LLVMStyle.CommentPragmas = "^ IWYU pragma:";
+ LLVMStyle.CompactNamespaces = false;
LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
LLVMStyle.ConstructorInitializerIndentWidth = 4;
LLVMStyle.ContinuationIndentWidth = 4;
LLVMStyle.Cpp11BracedListStyle = true;
LLVMStyle.DerivePointerAlignment = false;
LLVMStyle.ExperimentalAutoDetectBinPacking = false;
+ LLVMStyle.FixNamespaceComments = true;
LLVMStyle.ForEachMacros.push_back("foreach");
LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
LLVMStyle.IncludeCategories = {{"^\"(llvm|llvm-c|clang|clang-c)/", 2},
- {"^(<|\"(gtest|isl|json)/)", 3},
+ {"^(<|\"(gtest|gmock|isl|json)/)", 3},
{".*", 1}};
- LLVMStyle.IncludeIsMainRegex = "$";
+ LLVMStyle.IncludeIsMainRegex = "(Test)?$";
LLVMStyle.IndentCaseLabels = false;
LLVMStyle.IndentWrappedFunctionNames = false;
LLVMStyle.IndentWidth = 2;
@@ -546,7 +604,6 @@ FormatStyle getLLVMStyle() {
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.Standard = FormatStyle::LS_Cpp11;
LLVMStyle.UseTab = FormatStyle::UT_Never;
- LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
LLVMStyle.ReflowComments = true;
LLVMStyle.SpacesInParentheses = false;
LLVMStyle.SpacesInSquareBrackets = false;
@@ -559,6 +616,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.SpaceBeforeAssignmentOperators = true;
LLVMStyle.SpacesInAngles = false;
+ LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
LLVMStyle.PenaltyBreakComment = 300;
LLVMStyle.PenaltyBreakFirstLessLess = 120;
LLVMStyle.PenaltyBreakString = 1000;
@@ -568,16 +626,23 @@ FormatStyle getLLVMStyle() {
LLVMStyle.DisableFormat = false;
LLVMStyle.SortIncludes = true;
+ LLVMStyle.SortUsingDeclarations = true;
return LLVMStyle;
}
FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
+ if (Language == FormatStyle::LK_TextProto) {
+ FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto);
+ GoogleStyle.Language = FormatStyle::LK_TextProto;
+ return GoogleStyle;
+ }
+
FormatStyle GoogleStyle = getLLVMStyle();
GoogleStyle.Language = Language;
GoogleStyle.AccessModifierOffset = -1;
- GoogleStyle.AlignEscapedNewlinesLeft = true;
+ GoogleStyle.AlignEscapedNewlines = FormatStyle::ENAS_Left;
GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
GoogleStyle.AllowShortLoopsOnASingleLine = true;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
@@ -614,8 +679,10 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
GoogleStyle.BreakBeforeTernaryOperators = false;
+ // taze:, triple slash directives (`/// <...`), @tag followed by { for a lot
+ // of JSDoc tags, and @see, which is commonly followed by overlong URLs.
GoogleStyle.CommentPragmas =
- "(taze:|@(export|requirecss|return|returns|see|visibility)) ";
+ "(taze:|^/[ \t]*<|(@[A-Za-z_0-9-]+[ \\t]*{)|@see)";
GoogleStyle.MaxEmptyLinesToKeep = 3;
GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
GoogleStyle.SpacesInContainerLiterals = false;
@@ -648,8 +715,9 @@ FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
ChromiumStyle.AllowShortLoopsOnASingleLine = false;
ChromiumStyle.BinPackParameters = false;
ChromiumStyle.DerivePointerAlignment = false;
+ if (Language == FormatStyle::LK_ObjC)
+ ChromiumStyle.ColumnLimit = 80;
}
- ChromiumStyle.SortIncludes = false;
return ChromiumStyle;
}
@@ -665,10 +733,12 @@ FormatStyle getMozillaStyle() {
MozillaStyle.BinPackParameters = false;
MozillaStyle.BinPackArguments = false;
MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla;
- MozillaStyle.BreakConstructorInitializersBeforeComma = true;
+ MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
+ MozillaStyle.BreakBeforeInheritanceComma = true;
MozillaStyle.ConstructorInitializerIndentWidth = 2;
MozillaStyle.ContinuationIndentWidth = 2;
MozillaStyle.Cpp11BracedListStyle = false;
+ MozillaStyle.FixNamespaceComments = false;
MozillaStyle.IndentCaseLabels = true;
MozillaStyle.ObjCSpaceAfterProperty = true;
MozillaStyle.ObjCSpaceBeforeProtocolList = false;
@@ -686,9 +756,10 @@ FormatStyle getWebKitStyle() {
Style.AlignTrailingComments = false;
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
- Style.BreakConstructorInitializersBeforeComma = true;
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
Style.Cpp11BracedListStyle = false;
Style.ColumnLimit = 0;
+ Style.FixNamespaceComments = false;
Style.IndentWidth = 4;
Style.NamespaceIndentation = FormatStyle::NI_Inner;
Style.ObjCBlockIndentWidth = 4;
@@ -706,6 +777,7 @@ FormatStyle getGNUStyle() {
Style.BreakBeforeTernaryOperators = true;
Style.Cpp11BracedListStyle = false;
Style.ColumnLimit = 79;
+ Style.FixNamespaceComments = false;
Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
Style.Standard = FormatStyle::LS_Cpp03;
return Style;
@@ -715,6 +787,7 @@ FormatStyle getNoStyle() {
FormatStyle NoStyle = getLLVMStyle();
NoStyle.DisableFormat = true;
NoStyle.SortIncludes = false;
+ NoStyle.SortUsingDeclarations = false;
return NoStyle;
}
@@ -892,8 +965,8 @@ private:
class Formatter : public TokenAnalyzer {
public:
Formatter(const Environment &Env, const FormatStyle &Style,
- bool *IncompleteFormat)
- : TokenAnalyzer(Env, Style), IncompleteFormat(IncompleteFormat) {}
+ FormattingAttemptStatus *Status)
+ : TokenAnalyzer(Env, Style), Status(Status) {}
tooling::Replacements
analyze(TokenAnnotator &Annotator,
@@ -915,7 +988,7 @@ public:
Env.getSourceManager(), Whitespaces, Encoding,
BinPackInconclusiveFunctions);
UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(),
- IncompleteFormat)
+ Env.getSourceManager(), Status)
.format(AnnotatedLines);
for (const auto &R : Whitespaces.generateReplacements())
if (Result.add(R))
@@ -997,7 +1070,7 @@ private:
}
bool BinPackInconclusiveFunctions;
- bool *IncompleteFormat;
+ FormattingAttemptStatus *Status;
};
// This class clean up the erroneous/redundant code around the given ranges in
@@ -1348,7 +1421,7 @@ public:
: Style(Style), FileName(FileName) {
FileStem = llvm::sys::path::stem(FileName);
for (const auto &Category : Style.IncludeCategories)
- CategoryRegexs.emplace_back(Category.Regex);
+ CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
FileName.endswith(".cpp") || FileName.endswith(".c++") ||
FileName.endswith(".cxx") || FileName.endswith(".m") ||
@@ -1376,9 +1449,11 @@ private:
return false;
StringRef HeaderStem =
llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
- if (FileStem.startswith(HeaderStem)) {
+ if (FileStem.startswith(HeaderStem) ||
+ FileStem.startswith_lower(HeaderStem)) {
llvm::Regex MainIncludeRegex(
- (HeaderStem + Style.IncludeIsMainRegex).str());
+ (HeaderStem + Style.IncludeIsMainRegex).str(),
+ llvm::Regex::IgnoreCase);
if (MainIncludeRegex.match(FileStem))
return true;
}
@@ -1457,12 +1532,22 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
return Replaces;
}
+bool isMpegTS(StringRef Code) {
+ // MPEG transport streams use the ".ts" file extension. clang-format should
+ // not attempt to format those. MPEG TS' frame format starts with 0x47 every
+ // 189 bytes - detect that and return.
+ return Code.size() > 188 && Code[0] == 0x47 && Code[188] == 0x47;
+}
+
tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
StringRef FileName, unsigned *Cursor) {
tooling::Replacements Replaces;
if (!Style.SortIncludes)
return Replaces;
+ if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript &&
+ isMpegTS(Code))
+ return Replaces;
if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript)
return sortJavaScriptImports(Style, Code, Ranges, FileName);
sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor);
@@ -1531,8 +1616,8 @@ inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
// tokens and returns an offset after the sequence.
unsigned getOffsetAfterTokenSequence(
StringRef FileName, StringRef Code, const FormatStyle &Style,
- std::function<unsigned(const SourceManager &, Lexer &, Token &)>
- GetOffsetAfterSequense) {
+ llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
+ GetOffsetAfterSequence) {
std::unique_ptr<Environment> Env =
Environment::CreateVirtualEnvironment(Code, FileName, /*Ranges=*/{});
const SourceManager &SourceMgr = Env->getSourceManager();
@@ -1541,7 +1626,7 @@ unsigned getOffsetAfterTokenSequence(
Token Tok;
// Get the first token.
Lex.LexFromRawLexer(Tok);
- return GetOffsetAfterSequense(SourceMgr, Lex, Tok);
+ return GetOffsetAfterSequence(SourceMgr, Lex, Tok);
}
// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
@@ -1645,7 +1730,7 @@ bool isDeletedHeader(llvm::StringRef HeaderName,
tooling::Replacements
fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
const FormatStyle &Style) {
- if (Style.Language != FormatStyle::LanguageKind::LK_Cpp)
+ if (!Style.isCpp())
return Replaces;
tooling::Replacements HeaderInsertions;
@@ -1804,49 +1889,112 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
- StringRef FileName, bool *IncompleteFormat) {
+ StringRef FileName,
+ FormattingAttemptStatus *Status) {
FormatStyle Expanded = expandPresets(Style);
if (Expanded.DisableFormat)
return tooling::Replacements();
+ if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
+ return tooling::Replacements();
+
+ typedef std::function<tooling::Replacements(const Environment &)>
+ AnalyzerPass;
+ SmallVector<AnalyzerPass, 4> Passes;
- auto Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
+ if (Style.Language == FormatStyle::LK_Cpp) {
+ if (Style.FixNamespaceComments)
+ Passes.emplace_back([&](const Environment &Env) {
+ return NamespaceEndCommentsFixer(Env, Expanded).process();
+ });
+
+ if (Style.SortUsingDeclarations)
+ Passes.emplace_back([&](const Environment &Env) {
+ return UsingDeclarationsSorter(Env, Expanded).process();
+ });
+ }
if (Style.Language == FormatStyle::LK_JavaScript &&
- Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) {
- JavaScriptRequoter Requoter(*Env, Expanded);
- tooling::Replacements Requotes = Requoter.process();
- if (!Requotes.empty()) {
- auto NewCode = applyAllReplacements(Code, Requotes);
- if (NewCode) {
- auto NewEnv = Environment::CreateVirtualEnvironment(
- *NewCode, FileName,
- tooling::calculateRangesAfterReplacements(Requotes, Ranges));
- Formatter Format(*NewEnv, Expanded, IncompleteFormat);
- return Requotes.merge(Format.process());
+ Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
+ Passes.emplace_back([&](const Environment &Env) {
+ return JavaScriptRequoter(Env, Expanded).process();
+ });
+
+ Passes.emplace_back([&](const Environment &Env) {
+ return Formatter(Env, Expanded, Status).process();
+ });
+
+ std::unique_ptr<Environment> Env =
+ Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
+ llvm::Optional<std::string> CurrentCode = None;
+ tooling::Replacements Fixes;
+ for (size_t I = 0, E = Passes.size(); I < E; ++I) {
+ tooling::Replacements PassFixes = Passes[I](*Env);
+ auto NewCode = applyAllReplacements(
+ CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes);
+ if (NewCode) {
+ Fixes = Fixes.merge(PassFixes);
+ if (I + 1 < E) {
+ CurrentCode = std::move(*NewCode);
+ Env = Environment::CreateVirtualEnvironment(
+ *CurrentCode, FileName,
+ tooling::calculateRangesAfterReplacements(Fixes, Ranges));
}
}
}
- Formatter Format(*Env, Expanded, IncompleteFormat);
- return Format.process();
+ return Fixes;
}
tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
StringRef FileName) {
+ // cleanups only apply to C++ (they mostly concern ctor commas etc.)
+ if (Style.Language != FormatStyle::LK_Cpp)
+ return tooling::Replacements();
std::unique_ptr<Environment> Env =
Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
Cleaner Clean(*Env, Style);
return Clean.process();
}
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName, bool *IncompleteFormat) {
+ FormattingAttemptStatus Status;
+ auto Result = reformat(Style, Code, Ranges, FileName, &Status);
+ if (!Status.FormatComplete)
+ *IncompleteFormat = true;
+ return Result;
+}
+
+tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
+ StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName) {
+ std::unique_ptr<Environment> Env =
+ Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
+ NamespaceEndCommentsFixer Fix(*Env, Style);
+ return Fix.process();
+}
+
+tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
+ StringRef Code,
+ ArrayRef<tooling::Range> Ranges,
+ StringRef FileName) {
+ std::unique_ptr<Environment> Env =
+ Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
+ UsingDeclarationsSorter Sorter(*Env, Style);
+ return Sorter.process();
+}
+
LangOptions getFormattingLangOpts(const FormatStyle &Style) {
LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
+ LangOpts.CPlusPlus1z = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.LineComment = 1;
- bool AlternativeOperators = Style.Language == FormatStyle::LK_Cpp;
+ bool AlternativeOperators = Style.isCpp();
LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
LangOpts.Bool = 1;
LangOpts.ObjC1 = 1;
@@ -1882,9 +2030,9 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
return FormatStyle::LK_Cpp;
}
-FormatStyle getStyle(StringRef StyleName, StringRef FileName,
- StringRef FallbackStyle, StringRef Code,
- vfs::FileSystem *FS) {
+llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
+ StringRef FallbackStyleName,
+ StringRef Code, vfs::FileSystem *FS) {
if (!FS) {
FS = vfs::getRealFileSystem().get();
}
@@ -1898,35 +2046,28 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName,
(Code.contains("\n- (") || Code.contains("\n+ (")))
Style.Language = FormatStyle::LK_ObjC;
- if (!getPredefinedStyle(FallbackStyle, Style.Language, &Style)) {
- llvm::errs() << "Invalid fallback style \"" << FallbackStyle
- << "\" using LLVM style\n";
- return Style;
- }
+ FormatStyle FallbackStyle = getNoStyle();
+ if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
+ return make_string_error("Invalid fallback style \"" + FallbackStyleName);
if (StyleName.startswith("{")) {
// Parse YAML/JSON style from the command line.
- if (std::error_code ec = parseConfiguration(StyleName, &Style)) {
- llvm::errs() << "Error parsing -style: " << ec.message() << ", using "
- << FallbackStyle << " style\n";
- }
+ if (std::error_code ec = parseConfiguration(StyleName, &Style))
+ return make_string_error("Error parsing -style: " + ec.message());
return Style;
}
if (!StyleName.equals_lower("file")) {
if (!getPredefinedStyle(StyleName, Style.Language, &Style))
- llvm::errs() << "Invalid value for -style, using " << FallbackStyle
- << " style\n";
+ return make_string_error("Invalid value for -style");
return Style;
}
// Look for .clang-format/_clang-format file in the file's parent directories.
SmallString<128> UnsuitableConfigFiles;
SmallString<128> Path(FileName);
- if (std::error_code EC = FS->makeAbsolute(Path)) {
- llvm::errs() << EC.message() << "\n";
- return Style;
- }
+ if (std::error_code EC = FS->makeAbsolute(Path))
+ return make_string_error(EC.message());
for (StringRef Directory = Path; !Directory.empty();
Directory = llvm::sys::path::parent_path(Directory)) {
@@ -1943,25 +2084,23 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName,
DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Status = FS->status(ConfigFile.str());
- bool IsFile =
+ bool FoundConfigFile =
Status && (Status->getType() == llvm::sys::fs::file_type::regular_file);
- if (!IsFile) {
+ if (!FoundConfigFile) {
// Try _clang-format too, since dotfiles are not commonly used on Windows.
ConfigFile = Directory;
llvm::sys::path::append(ConfigFile, "_clang-format");
DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
Status = FS->status(ConfigFile.str());
- IsFile = Status &&
- (Status->getType() == llvm::sys::fs::file_type::regular_file);
+ FoundConfigFile = Status && (Status->getType() ==
+ llvm::sys::fs::file_type::regular_file);
}
- if (IsFile) {
+ if (FoundConfigFile) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
FS->getBufferForFile(ConfigFile.str());
- if (std::error_code EC = Text.getError()) {
- llvm::errs() << EC.message() << "\n";
- break;
- }
+ if (std::error_code EC = Text.getError())
+ return make_string_error(EC.message());
if (std::error_code ec =
parseConfiguration(Text.get()->getBuffer(), &Style)) {
if (ec == ParseError::Unsuitable) {
@@ -1970,20 +2109,18 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName,
UnsuitableConfigFiles.append(ConfigFile);
continue;
}
- llvm::errs() << "Error reading " << ConfigFile << ": " << ec.message()
- << "\n";
- break;
+ return make_string_error("Error reading " + ConfigFile + ": " +
+ ec.message());
}
DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
return Style;
}
}
- if (!UnsuitableConfigFiles.empty()) {
- llvm::errs() << "Configuration file(s) do(es) not support "
- << getLanguageName(Style.Language) << ": "
- << UnsuitableConfigFiles << "\n";
- }
- return Style;
+ if (!UnsuitableConfigFiles.empty())
+ return make_string_error("Configuration file(s) do(es) not support " +
+ getLanguageName(Style.Language) + ": " +
+ UnsuitableConfigFiles);
+ return FallbackStyle;
}
} // namespace format
diff --git a/contrib/llvm/tools/clang/lib/Format/FormatToken.h b/contrib/llvm/tools/clang/lib/Format/FormatToken.h
index ea3bbe3..a60361a 100644
--- a/contrib/llvm/tools/clang/lib/Format/FormatToken.h
+++ b/contrib/llvm/tools/clang/lib/Format/FormatToken.h
@@ -21,6 +21,7 @@
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
#include <memory>
+#include <unordered_set>
namespace clang {
namespace format {
@@ -39,6 +40,7 @@ namespace format {
TYPE(ConflictStart) \
TYPE(CtorInitializerColon) \
TYPE(CtorInitializerComma) \
+ TYPE(DesignatedInitializerLSquare) \
TYPE(DesignatedInitializerPeriod) \
TYPE(DictLiteral) \
TYPE(ForEachMacro) \
@@ -48,11 +50,15 @@ namespace format {
TYPE(FunctionTypeLParen) \
TYPE(ImplicitStringLiteral) \
TYPE(InheritanceColon) \
+ TYPE(InheritanceComma) \
TYPE(InlineASMBrace) \
TYPE(InlineASMColon) \
TYPE(JavaAnnotation) \
TYPE(JsComputedPropertyName) \
+ TYPE(JsExponentiation) \
+ TYPE(JsExponentiationEqual) \
TYPE(JsFatArrow) \
+ TYPE(JsNonNullAssertion) \
TYPE(JsTypeColon) \
TYPE(JsTypeOperator) \
TYPE(JsTypeOptionalQuestion) \
@@ -220,6 +226,9 @@ struct FormatToken {
/// [], {} or <>.
unsigned NestingLevel = 0;
+ /// \brief The indent level of this token. Copied from the surrounding line.
+ unsigned IndentLevel = 0;
+
/// \brief Penalty for inserting a line break before this token.
unsigned SplitPenalty = 0;
@@ -258,6 +267,11 @@ struct FormatToken {
/// Only set if \c Type == \c TT_StartOfName.
bool PartOfMultiVariableDeclStmt = false;
+ /// \brief Does this line comment continue a line comment section?
+ ///
+ /// Only set to true if \c Type == \c TT_LineComment.
+ bool ContinuesLineCommentSection = false;
+
/// \brief If this is a bracket, this points to the matching one.
FormatToken *MatchingParen = nullptr;
@@ -334,11 +348,15 @@ struct FormatToken {
/// \brief Returns whether \p Tok is ([{ or a template opening <.
bool opensScope() const {
+ if (is(TT_TemplateString) && TokenText.endswith("${"))
+ return true;
return isOneOf(tok::l_paren, tok::l_brace, tok::l_square,
TT_TemplateOpener);
}
/// \brief Returns whether \p Tok is )]} or a template closing >.
bool closesScope() const {
+ if (is(TT_TemplateString) && TokenText.startswith("}"))
+ return true;
return isOneOf(tok::r_paren, tok::r_brace, tok::r_square,
TT_TemplateCloser);
}
@@ -443,17 +461,36 @@ struct FormatToken {
/// \brief Returns \c true if this tokens starts a block-type list, i.e. a
/// list that should be indented with a block indent.
bool opensBlockOrBlockTypeList(const FormatStyle &Style) const {
+ if (is(TT_TemplateString) && opensScope())
+ return true;
return is(TT_ArrayInitializerLSquare) ||
(is(tok::l_brace) &&
(BlockKind == BK_Block || is(TT_DictLiteral) ||
- (!Style.Cpp11BracedListStyle && NestingLevel == 0)));
+ (!Style.Cpp11BracedListStyle && NestingLevel == 0))) ||
+ (is(tok::less) && (Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto));
}
/// \brief Same as opensBlockOrBlockTypeList, but for the closing token.
bool closesBlockOrBlockTypeList(const FormatStyle &Style) const {
+ if (is(TT_TemplateString) && closesScope())
+ return true;
return MatchingParen && MatchingParen->opensBlockOrBlockTypeList(Style);
}
+ /// \brief Return the actual namespace token, if this token starts a namespace
+ /// block.
+ const FormatToken *getNamespaceToken() const {
+ const FormatToken *NamespaceTok = this;
+ if (is(tok::comment))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ // Detect "(inline)? namespace" in the beginning of a line.
+ if (NamespaceTok && NamespaceTok->is(tok::kw_inline))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ return NamespaceTok && NamespaceTok->is(tok::kw_namespace) ? NamespaceTok
+ : nullptr;
+ }
+
private:
// Disallow copying.
FormatToken(const FormatToken &) = delete;
@@ -599,10 +636,13 @@ struct AdditionalKeywords {
kw_finally = &IdentTable.get("finally");
kw_from = &IdentTable.get("from");
kw_function = &IdentTable.get("function");
+ kw_get = &IdentTable.get("get");
kw_import = &IdentTable.get("import");
kw_is = &IdentTable.get("is");
kw_let = &IdentTable.get("let");
kw_module = &IdentTable.get("module");
+ kw_readonly = &IdentTable.get("readonly");
+ kw_set = &IdentTable.get("set");
kw_type = &IdentTable.get("type");
kw_var = &IdentTable.get("var");
kw_yield = &IdentTable.get("yield");
@@ -618,6 +658,8 @@ struct AdditionalKeywords {
kw_synchronized = &IdentTable.get("synchronized");
kw_throws = &IdentTable.get("throws");
kw___except = &IdentTable.get("__except");
+ kw___has_include = &IdentTable.get("__has_include");
+ kw___has_include_next = &IdentTable.get("__has_include_next");
kw_mark = &IdentTable.get("mark");
@@ -632,6 +674,15 @@ struct AdditionalKeywords {
kw_qsignals = &IdentTable.get("Q_SIGNALS");
kw_slots = &IdentTable.get("slots");
kw_qslots = &IdentTable.get("Q_SLOTS");
+
+ // Keep this at the end of the constructor to make sure everything here is
+ // already initialized.
+ JsExtraKeywords = std::unordered_set<IdentifierInfo *>(
+ {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from,
+ kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly,
+ kw_set, kw_type, kw_var, kw_yield,
+ // Keywords from the Java section.
+ kw_abstract, kw_extends, kw_implements, kw_instanceof, kw_interface});
}
// Context sensitive keywords.
@@ -644,6 +695,8 @@ struct AdditionalKeywords {
IdentifierInfo *kw_NS_ENUM;
IdentifierInfo *kw_NS_OPTIONS;
IdentifierInfo *kw___except;
+ IdentifierInfo *kw___has_include;
+ IdentifierInfo *kw___has_include_next;
// JavaScript keywords.
IdentifierInfo *kw_as;
@@ -653,10 +706,13 @@ struct AdditionalKeywords {
IdentifierInfo *kw_finally;
IdentifierInfo *kw_from;
IdentifierInfo *kw_function;
+ IdentifierInfo *kw_get;
IdentifierInfo *kw_import;
IdentifierInfo *kw_is;
IdentifierInfo *kw_let;
IdentifierInfo *kw_module;
+ IdentifierInfo *kw_readonly;
+ IdentifierInfo *kw_set;
IdentifierInfo *kw_type;
IdentifierInfo *kw_var;
IdentifierInfo *kw_yield;
@@ -689,6 +745,18 @@ struct AdditionalKeywords {
IdentifierInfo *kw_qsignals;
IdentifierInfo *kw_slots;
IdentifierInfo *kw_qslots;
+
+ /// \brief Returns \c true if \p Tok is a true JavaScript identifier, returns
+ /// \c false if it is a keyword or a pseudo keyword.
+ bool IsJavaScriptIdentifier(const FormatToken &Tok) const {
+ return Tok.is(tok::identifier) &&
+ JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) ==
+ JsExtraKeywords.end();
+ }
+
+private:
+ /// \brief The JavaScript keywords beyond the C++ keyword set.
+ std::unordered_set<IdentifierInfo *> JsExtraKeywords;
};
} // namespace format
diff --git a/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.cpp b/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.cpp
index 46a32a9..45c3ae1 100644
--- a/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.cpp
+++ b/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.cpp
@@ -64,6 +64,8 @@ void FormatTokenLexer::tryMergePreviousTokens() {
return;
if (tryMergeLessLess())
return;
+ if (tryMergeNSStringLiteral())
+ return;
if (Style.Language == FormatStyle::LK_JavaScript) {
static const tok::TokenKind JSIdentity[] = {tok::equalequal, tok::equal};
@@ -72,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;
@@ -81,9 +87,44 @@ 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) {
+ static const tok::TokenKind JavaRightLogicalShift[] = {tok::greater,
+ tok::greater,
+ tok::greater};
+ static const tok::TokenKind JavaRightLogicalShiftAssign[] = {tok::greater,
+ tok::greater,
+ tok::greaterequal};
+ if (tryMergeTokens(JavaRightLogicalShift, TT_BinaryOperator))
+ return;
+ if (tryMergeTokens(JavaRightLogicalShiftAssign, TT_BinaryOperator))
+ return;
}
}
+bool FormatTokenLexer::tryMergeNSStringLiteral() {
+ if (Tokens.size() < 2)
+ return false;
+ auto &At = *(Tokens.end() - 2);
+ auto &String = *(Tokens.end() - 1);
+ if (!At->is(tok::at) || !String->is(tok::string_literal))
+ return false;
+ At->Tok.setKind(tok::string_literal);
+ At->TokenText = StringRef(At->TokenText.begin(),
+ String->TokenText.end() - At->TokenText.begin());
+ At->ColumnWidth += String->ColumnWidth;
+ At->Type = TT_ObjCStringLiteral;
+ Tokens.erase(Tokens.end() - 1);
+ return true;
+}
+
bool FormatTokenLexer::tryMergeLessLess() {
// Merge X,less,less,Y into X,lessless,Y unless X or Y is less.
if (Tokens.size() < 3)
@@ -157,7 +198,9 @@ bool FormatTokenLexer::canPrecedeRegexLiteral(FormatToken *Prev) {
// postfix unary operators. If the '++' is followed by a non-operand
// introducing token, the slash here is the operand and not the start of a
// regex.
- if (Prev->isOneOf(tok::plusplus, tok::minusminus))
+ // `!` is an unary prefix operator, but also a post-fix operator that casts
+ // away nullability, so the same check applies.
+ if (Prev->isOneOf(tok::plusplus, tok::minusminus, tok::exclaim))
return (Tokens.size() < 3 || precedesOperand(Tokens[Tokens.size() - 3]));
// The previous token must introduce an operand location where regex
@@ -434,6 +477,9 @@ FormatToken *FormatTokenLexer::getNextToken() {
if (pos >= 0 && Text[pos] == '\r')
--pos;
// See whether there is an odd number of '\' before this.
+ // FIXME: This is wrong. A '\' followed by a newline is always removed,
+ // regardless of whether there is another '\' before it.
+ // FIXME: Newlines can also be escaped by a '?' '?' '/' trigraph.
unsigned count = 0;
for (; pos >= 0; --pos, ++count)
if (Text[pos] != '\\')
@@ -558,8 +604,7 @@ FormatToken *FormatTokenLexer::getNextToken() {
Column = FormatTok->LastLineColumnWidth;
}
- if (Style.Language == FormatStyle::LK_Cpp ||
- Style.Language == FormatStyle::LK_ObjC) {
+ if (Style.isCpp()) {
if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() &&
Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_define) &&
diff --git a/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.h b/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.h
index c47b0e7..bf10f09 100644
--- a/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.h
+++ b/contrib/llvm/tools/clang/lib/Format/FormatTokenLexer.h
@@ -47,6 +47,7 @@ private:
void tryMergePreviousTokens();
bool tryMergeLessLess();
+ bool tryMergeNSStringLiteral();
bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, TokenType NewType);
diff --git a/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.cpp
new file mode 100644
index 0000000..85b70b8
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -0,0 +1,207 @@
+//===--- NamespaceEndCommentsFixer.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements NamespaceEndCommentsFixer, a TokenAnalyzer that
+/// fixes namespace end comments.
+///
+//===----------------------------------------------------------------------===//
+
+#include "NamespaceEndCommentsFixer.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Regex.h"
+
+#define DEBUG_TYPE "namespace-end-comments-fixer"
+
+namespace clang {
+namespace format {
+
+namespace {
+// The maximal number of unwrapped lines that a short namespace spans.
+// Short namespaces don't need an end comment.
+static const int kShortNamespaceMaxLines = 1;
+
+// Matches a valid namespace end comment.
+// Valid namespace end comments don't need to be edited.
+static llvm::Regex kNamespaceCommentPattern =
+ llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *"
+ "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$",
+ llvm::Regex::IgnoreCase);
+
+// Computes the name of a namespace given the namespace token.
+// Returns "" for anonymous namespace.
+std::string computeName(const FormatToken *NamespaceTok) {
+ assert(NamespaceTok && NamespaceTok->is(tok::kw_namespace) &&
+ "expecting a namespace token");
+ std::string name = "";
+ // Collects all the non-comment tokens between 'namespace' and '{'.
+ const FormatToken *Tok = NamespaceTok->getNextNonComment();
+ while (Tok && !Tok->is(tok::l_brace)) {
+ name += Tok->TokenText;
+ Tok = Tok->getNextNonComment();
+ }
+ return name;
+}
+
+std::string computeEndCommentText(StringRef NamespaceName, bool AddNewline) {
+ std::string text = "// namespace";
+ if (!NamespaceName.empty()) {
+ text += ' ';
+ text += NamespaceName;
+ }
+ if (AddNewline)
+ text += '\n';
+ return text;
+}
+
+bool hasEndComment(const FormatToken *RBraceTok) {
+ return RBraceTok->Next && RBraceTok->Next->is(tok::comment);
+}
+
+bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName) {
+ assert(hasEndComment(RBraceTok));
+ const FormatToken *Comment = RBraceTok->Next;
+ SmallVector<StringRef, 7> Groups;
+ if (kNamespaceCommentPattern.match(Comment->TokenText, &Groups)) {
+ StringRef NamespaceNameInComment = Groups.size() > 5 ? Groups[5] : "";
+ // Anonymous namespace comments must not mention a namespace name.
+ if (NamespaceName.empty() && !NamespaceNameInComment.empty())
+ return false;
+ StringRef AnonymousInComment = Groups.size() > 3 ? Groups[3] : "";
+ // Named namespace comments must not mention anonymous namespace.
+ if (!NamespaceName.empty() && !AnonymousInComment.empty())
+ return false;
+ return NamespaceNameInComment == NamespaceName;
+ }
+ return false;
+}
+
+void addEndComment(const FormatToken *RBraceTok, StringRef EndCommentText,
+ const SourceManager &SourceMgr,
+ tooling::Replacements *Fixes) {
+ auto EndLoc = RBraceTok->Tok.getEndLoc();
+ auto Range = CharSourceRange::getCharRange(EndLoc, EndLoc);
+ auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, EndCommentText));
+ if (Err) {
+ llvm::errs() << "Error while adding namespace end comment: "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+}
+
+void updateEndComment(const FormatToken *RBraceTok, StringRef EndCommentText,
+ const SourceManager &SourceMgr,
+ tooling::Replacements *Fixes) {
+ assert(hasEndComment(RBraceTok));
+ const FormatToken *Comment = RBraceTok->Next;
+ auto Range = CharSourceRange::getCharRange(Comment->getStartOfNonWhitespace(),
+ Comment->Tok.getEndLoc());
+ auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, EndCommentText));
+ if (Err) {
+ llvm::errs() << "Error while updating namespace end comment: "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+}
+
+const FormatToken *
+getNamespaceToken(const AnnotatedLine *line,
+ const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+ if (!line->Affected || line->InPPDirective || !line->startsWith(tok::r_brace))
+ return nullptr;
+ size_t StartLineIndex = line->MatchingOpeningBlockLineIndex;
+ if (StartLineIndex == UnwrappedLine::kInvalidIndex)
+ return nullptr;
+ assert(StartLineIndex < AnnotatedLines.size());
+ const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First;
+ // Detect "(inline)? namespace" in the beginning of a line.
+ if (NamespaceTok->is(tok::kw_inline))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace))
+ return nullptr;
+ return NamespaceTok;
+}
+} // namespace
+
+NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env,
+ const FormatStyle &Style)
+ : TokenAnalyzer(Env, Style) {}
+
+tooling::Replacements NamespaceEndCommentsFixer::analyze(
+ TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) {
+ const SourceManager &SourceMgr = Env.getSourceManager();
+ AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
+ AnnotatedLines.end());
+ tooling::Replacements Fixes;
+ std::string AllNamespaceNames = "";
+ size_t StartLineIndex = SIZE_MAX;
+ unsigned int CompactedNamespacesCount = 0;
+ for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
+ const AnnotatedLine *EndLine = AnnotatedLines[I];
+ const FormatToken *NamespaceTok =
+ getNamespaceToken(EndLine, AnnotatedLines);
+ if (!NamespaceTok)
+ continue;
+ FormatToken *RBraceTok = EndLine->First;
+ if (RBraceTok->Finalized)
+ continue;
+ RBraceTok->Finalized = true;
+ const FormatToken *EndCommentPrevTok = RBraceTok;
+ // Namespaces often end with '};'. In that case, attach namespace end
+ // comments to the semicolon tokens.
+ if (RBraceTok->Next && RBraceTok->Next->is(tok::semi)) {
+ EndCommentPrevTok = RBraceTok->Next;
+ }
+ if (StartLineIndex == SIZE_MAX)
+ StartLineIndex = EndLine->MatchingOpeningBlockLineIndex;
+ std::string NamespaceName = computeName(NamespaceTok);
+ if (Style.CompactNamespaces) {
+ if ((I + 1 < E) &&
+ getNamespaceToken(AnnotatedLines[I + 1], AnnotatedLines) &&
+ StartLineIndex - CompactedNamespacesCount - 1 ==
+ AnnotatedLines[I + 1]->MatchingOpeningBlockLineIndex &&
+ !AnnotatedLines[I + 1]->First->Finalized) {
+ if (hasEndComment(EndCommentPrevTok)) {
+ // remove end comment, it will be merged in next one
+ updateEndComment(EndCommentPrevTok, std::string(), SourceMgr, &Fixes);
+ }
+ CompactedNamespacesCount++;
+ AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames;
+ continue;
+ }
+ NamespaceName += AllNamespaceNames;
+ CompactedNamespacesCount = 0;
+ AllNamespaceNames = std::string();
+ }
+ // The next token in the token stream after the place where the end comment
+ // token must be. This is either the next token on the current line or the
+ // first token on the next line.
+ const FormatToken *EndCommentNextTok = EndCommentPrevTok->Next;
+ if (EndCommentNextTok && EndCommentNextTok->is(tok::comment))
+ EndCommentNextTok = EndCommentNextTok->Next;
+ if (!EndCommentNextTok && I + 1 < E)
+ EndCommentNextTok = AnnotatedLines[I + 1]->First;
+ bool AddNewline = EndCommentNextTok &&
+ EndCommentNextTok->NewlinesBefore == 0 &&
+ EndCommentNextTok->isNot(tok::eof);
+ const std::string EndCommentText =
+ computeEndCommentText(NamespaceName, AddNewline);
+ if (!hasEndComment(EndCommentPrevTok)) {
+ bool isShort = I - StartLineIndex <= kShortNamespaceMaxLines + 1;
+ if (!isShort)
+ addEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
+ } else if (!validEndComment(EndCommentPrevTok, NamespaceName)) {
+ updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
+ }
+ StartLineIndex = SIZE_MAX;
+ }
+ return Fixes;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.h b/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.h
new file mode 100644
index 0000000..7790668
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Format/NamespaceEndCommentsFixer.h
@@ -0,0 +1,37 @@
+//===--- NamespaceEndCommentsFixer.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file declares NamespaceEndCommentsFixer, a TokenAnalyzer that
+/// fixes namespace end comments.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_NAMESPACEENDCOMMENTSFIXER_H
+#define LLVM_CLANG_LIB_FORMAT_NAMESPACEENDCOMMENTSFIXER_H
+
+#include "TokenAnalyzer.h"
+
+namespace clang {
+namespace format {
+
+class NamespaceEndCommentsFixer : public TokenAnalyzer {
+public:
+ NamespaceEndCommentsFixer(const Environment &Env, const FormatStyle &Style);
+
+ tooling::Replacements
+ analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) override;
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif
diff --git a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp
index b5f7de2..46ea06b 100644
--- a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp
+++ b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp
@@ -89,7 +89,9 @@ private:
continue;
}
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
- (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext))
+ (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
+ Style.Language != FormatStyle::LK_Proto &&
+ Style.Language != FormatStyle::LK_TextProto))
return false;
// If a && or || is found and interpreted as a binary operator, this set
// of angles is likely part of something like "a < b && c > d". If the
@@ -103,6 +105,14 @@ private:
!Line.startsWith(tok::kw_template))
return false;
updateParameterCount(Left, CurrentToken);
+ if (Style.Language == FormatStyle::LK_Proto) {
+ if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) {
+ if (CurrentToken->is(tok::colon) ||
+ (CurrentToken->isOneOf(tok::l_brace, tok::less) &&
+ Previous->isNot(tok::colon)))
+ Previous->Type = TT_SelectorName;
+ }
+ }
if (!consumeToken())
return false;
}
@@ -135,13 +145,17 @@ private:
if (Left->is(TT_OverloadedOperatorLParen)) {
Contexts.back().IsExpression = false;
} else if (Style.Language == FormatStyle::LK_JavaScript &&
- Line.startsWith(Keywords.kw_type, tok::identifier)) {
+ (Line.startsWith(Keywords.kw_type, tok::identifier) ||
+ Line.startsWith(tok::kw_export, Keywords.kw_type,
+ tok::identifier))) {
// type X = (...);
+ // export type X = (...);
Contexts.back().IsExpression = false;
} else if (Left->Previous &&
(Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype,
tok::kw_if, tok::kw_while, tok::l_paren,
tok::comma) ||
+ Left->Previous->endsSequence(tok::kw_constexpr, tok::kw_if) ||
Left->Previous->is(TT_BinaryOperator))) {
// static_assert, if and while usually contain expressions.
Contexts.back().IsExpression = true;
@@ -311,14 +325,13 @@ private:
// In C++, this can happen either in array of templates (foo<int>[10])
// or when array is a nested template type (unique_ptr<type1<type2>[]>).
bool CppArrayTemplates =
- Style.Language == FormatStyle::LK_Cpp && Parent &&
+ Style.isCpp() && Parent &&
Parent->is(TT_TemplateCloser) &&
(Contexts.back().CanBeExpression || Contexts.back().IsExpression ||
Contexts.back().InTemplateArgument);
bool StartsObjCMethodExpr =
- !CppArrayTemplates && (Style.Language == FormatStyle::LK_Cpp ||
- Style.Language == FormatStyle::LK_ObjC) &&
+ !CppArrayTemplates && Style.isCpp() &&
Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
CurrentToken->isNot(tok::l_brace) &&
(!Parent ||
@@ -337,6 +350,12 @@ private:
Contexts.back().ContextKind == tok::l_brace &&
Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->Type = TT_JsComputedPropertyName;
+ } else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
+ Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
+ Left->Type = TT_DesignatedInitializerLSquare;
+ } else if (CurrentToken->is(tok::r_square) && Parent &&
+ Parent->is(TT_TemplateCloser)) {
+ Left->Type = TT_ArraySubscriptLSquare;
} else if (Style.Language == FormatStyle::LK_Proto ||
(!CppArrayTemplates && Parent &&
Parent->isOneOf(TT_BinaryOperator, TT_TemplateCloser, tok::at,
@@ -386,7 +405,8 @@ private:
if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
return false;
if (CurrentToken->is(tok::colon)) {
- if (Left->is(TT_ArraySubscriptLSquare)) {
+ if (Left->isOneOf(TT_ArraySubscriptLSquare,
+ TT_DesignatedInitializerLSquare)) {
Left->Type = TT_ObjCMethodExpr;
StartsObjCMethodExpr = true;
Contexts.back().ColonIsObjCMethodExpr = true;
@@ -430,13 +450,12 @@ private:
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
return false;
updateParameterCount(Left, CurrentToken);
- if (CurrentToken->isOneOf(tok::colon, tok::l_brace)) {
+ if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
FormatToken *Previous = CurrentToken->getPreviousNonComment();
if (((CurrentToken->is(tok::colon) &&
- (!Contexts.back().ColonIsDictLiteral ||
- (Style.Language != FormatStyle::LK_Cpp &&
- Style.Language != FormatStyle::LK_ObjC))) ||
- Style.Language == FormatStyle::LK_Proto) &&
+ (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
+ Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) &&
(Previous->Tok.getIdentifierInfo() ||
Previous->is(tok::string_literal)))
Previous->Type = TT_SelectorName;
@@ -519,8 +538,13 @@ private:
}
}
if (Contexts.back().ColonIsDictLiteral ||
- Style.Language == FormatStyle::LK_Proto) {
+ Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) {
Tok->Type = TT_DictLiteral;
+ if (Style.Language == FormatStyle::LK_TextProto) {
+ if (FormatToken *Previous = Tok->getPreviousNonComment())
+ Previous->Type = TT_SelectorName;
+ }
} else if (Contexts.back().ColonIsObjCMethodExpr ||
Line.startsWith(TT_ObjCMethodSpecifier)) {
Tok->Type = TT_ObjCMethodExpr;
@@ -569,6 +593,8 @@ private:
break;
case tok::kw_if:
case tok::kw_while:
+ if (Tok->is(tok::kw_if) && CurrentToken && CurrentToken->is(tok::kw_constexpr))
+ next();
if (CurrentToken && CurrentToken->is(tok::l_paren)) {
next();
if (!parseParens(/*LookForDecls=*/true))
@@ -576,9 +602,13 @@ private:
}
break;
case tok::kw_for:
- if (Style.Language == FormatStyle::LK_JavaScript && Tok->Previous &&
- Tok->Previous->is(tok::period))
- break;
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Tok->Previous && Tok->Previous->is(tok::period))
+ break;
+ // JS' for await ( ...
+ if (CurrentToken && CurrentToken->is(Keywords.kw_await))
+ next();
+ }
Contexts.back().ColonIsForRangeExpr = true;
next();
if (!parseParens())
@@ -612,12 +642,22 @@ private:
return false;
break;
case tok::l_brace:
+ if (Style.Language == FormatStyle::LK_TextProto) {
+ FormatToken *Previous =Tok->getPreviousNonComment();
+ if (Previous && Previous->Type != TT_DictLiteral)
+ Previous->Type = TT_SelectorName;
+ }
if (!parseBrace())
return false;
break;
case tok::less:
if (parseAngle()) {
Tok->Type = TT_TemplateOpener;
+ if (Style.Language == FormatStyle::LK_TextProto) {
+ FormatToken *Previous = Tok->getPreviousNonComment();
+ if (Previous && Previous->Type != TT_DictLiteral)
+ Previous->Type = TT_SelectorName;
+ }
} else {
Tok->Type = TT_BinaryOperator;
NonTemplateLess.insert(Tok);
@@ -676,6 +716,8 @@ private:
case tok::comma:
if (Contexts.back().InCtorInitializer)
Tok->Type = TT_CtorInitializerComma;
+ else if (Contexts.back().InInheritanceList)
+ Tok->Type = TT_InheritanceComma;
else if (Contexts.back().FirstStartOfName &&
(Contexts.size() == 1 || Line.startsWith(tok::kw_for))) {
Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
@@ -684,6 +726,12 @@ private:
if (Contexts.back().IsForEachMacro)
Contexts.back().IsExpression = true;
break;
+ case tok::identifier:
+ if (Tok->isOneOf(Keywords.kw___has_include,
+ Keywords.kw___has_include_next)) {
+ parseHasInclude();
+ }
+ break;
default:
break;
}
@@ -692,9 +740,12 @@ private:
void parseIncludeDirective() {
if (CurrentToken && CurrentToken->is(tok::less)) {
- next();
- while (CurrentToken) {
- if (CurrentToken->isNot(tok::comment) || CurrentToken->Next)
+ next();
+ while (CurrentToken) {
+ // Mark tokens up to the trailing line comments as implicit string
+ // literals.
+ if (CurrentToken->isNot(tok::comment) &&
+ !CurrentToken->TokenText.startswith("//"))
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
@@ -727,6 +778,14 @@ private:
}
}
+ void parseHasInclude() {
+ if (!CurrentToken || !CurrentToken->is(tok::l_paren))
+ return;
+ next(); // '('
+ parseIncludeDirective();
+ next(); // ')'
+ }
+
LineType parsePreprocessorDirective() {
bool IsFirstToken = CurrentToken->IsFirst;
LineType Type = LT_PreprocessorDirective;
@@ -777,8 +836,15 @@ private:
default:
break;
}
- while (CurrentToken)
+ while (CurrentToken) {
+ FormatToken *Tok = CurrentToken;
next();
+ if (Tok->is(tok::l_paren))
+ parseParens();
+ else if (Tok->isOneOf(Keywords.kw___has_include,
+ Keywords.kw___has_include_next))
+ parseHasInclude();
+ }
return Type;
}
@@ -885,7 +951,7 @@ private:
TT_FunctionLBrace, TT_ImplicitStringLiteral,
TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow,
TT_OverloadedOperator, TT_RegexLiteral,
- TT_TemplateString))
+ TT_TemplateString, TT_ObjCStringLiteral))
CurrentToken->Type = TT_Unknown;
CurrentToken->Role.reset();
CurrentToken->MatchingParen = nullptr;
@@ -925,6 +991,7 @@ private:
bool CanBeExpression = true;
bool InTemplateArgument = false;
bool InCtorInitializer = false;
+ bool InInheritanceList = false;
bool CaretFound = false;
bool IsForEachMacro = false;
};
@@ -948,9 +1015,12 @@ private:
void modifyContext(const FormatToken &Current) {
if (Current.getPrecedence() == prec::Assignment &&
!Line.First->isOneOf(tok::kw_template, tok::kw_using, tok::kw_return) &&
- // Type aliases use `type X = ...;` in TypeScript.
+ // Type aliases use `type X = ...;` in TypeScript and can be exported
+ // using `export type ...`.
!(Style.Language == FormatStyle::LK_JavaScript &&
- Line.startsWith(Keywords.kw_type, tok::identifier)) &&
+ (Line.startsWith(Keywords.kw_type, tok::identifier) ||
+ Line.startsWith(tok::kw_export, Keywords.kw_type,
+ tok::identifier))) &&
(!Current.Previous || Current.Previous->isNot(tok::kw_operator))) {
Contexts.back().IsExpression = true;
if (!Line.startsWith(TT_UnaryOperator)) {
@@ -984,6 +1054,9 @@ private:
Current.Previous->is(TT_CtorInitializerColon)) {
Contexts.back().IsExpression = true;
Contexts.back().InCtorInitializer = true;
+ } else if (Current.Previous &&
+ Current.Previous->is(TT_InheritanceColon)) {
+ Contexts.back().InInheritanceList = true;
} else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
for (FormatToken *Previous = Current.Previous;
Previous && Previous->isOneOf(tok::star, tok::amp);
@@ -1004,6 +1077,24 @@ private:
// The token type is already known.
return;
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Current.is(tok::exclaim)) {
+ if (Current.Previous &&
+ (Current.Previous->isOneOf(tok::identifier, tok::kw_namespace,
+ tok::r_paren, tok::r_square,
+ tok::r_brace) ||
+ Current.Previous->Tok.isLiteral())) {
+ Current.Type = TT_JsNonNullAssertion;
+ return;
+ }
+ if (Current.Next &&
+ Current.Next->isOneOf(TT_BinaryOperator, Keywords.kw_as)) {
+ Current.Type = TT_JsNonNullAssertion;
+ return;
+ }
+ }
+ }
+
// Line.MightBeFunctionDecl can only be true after the parentheses of a
// function declaration have been found. In this case, 'Current' is a
// trailing token of this declaration and thus cannot be a name.
@@ -1063,7 +1154,8 @@ private:
if (Current.MatchingParen && Current.Next &&
!Current.Next->isBinaryOperator() &&
!Current.Next->isOneOf(tok::semi, tok::colon, tok::l_brace,
- tok::period, tok::arrow, tok::coloncolon))
+ tok::comma, tok::period, tok::arrow,
+ tok::coloncolon))
if (FormatToken *AfterParen = Current.MatchingParen->Next) {
// Make sure this isn't the return type of an Obj-C block declaration
if (AfterParen->Tok.isNot(tok::caret)) {
@@ -1075,22 +1167,22 @@ private:
Current.Type = TT_FunctionAnnotationRParen;
}
}
- } else if (Current.is(tok::at) && Current.Next) {
- if (Current.Next->isStringLiteral()) {
- Current.Type = TT_ObjCStringLiteral;
- } else {
- switch (Current.Next->Tok.getObjCKeywordID()) {
- case tok::objc_interface:
- case tok::objc_implementation:
- case tok::objc_protocol:
- Current.Type = TT_ObjCDecl;
- break;
- case tok::objc_property:
- Current.Type = TT_ObjCProperty;
- break;
- default:
- break;
- }
+ } else if (Current.is(tok::at) && Current.Next &&
+ Style.Language != FormatStyle::LK_JavaScript &&
+ Style.Language != FormatStyle::LK_Java) {
+ // In Java & JavaScript, "@..." is a decorator or annotation. In ObjC, it
+ // marks declarations and properties that need special formatting.
+ switch (Current.Next->Tok.getObjCKeywordID()) {
+ case tok::objc_interface:
+ case tok::objc_implementation:
+ case tok::objc_protocol:
+ Current.Type = TT_ObjCDecl;
+ break;
+ case tok::objc_property:
+ Current.Type = TT_ObjCProperty;
+ break;
+ default:
+ break;
}
} else if (Current.is(tok::period)) {
FormatToken *PreviousNoComment = Current.getPreviousNonComment();
@@ -1137,16 +1229,17 @@ private:
if (Tok.isNot(tok::identifier) || !Tok.Previous)
return false;
- if (Tok.Previous->isOneOf(TT_LeadingJavaAnnotation, Keywords.kw_instanceof))
+ if (Tok.Previous->isOneOf(TT_LeadingJavaAnnotation, Keywords.kw_instanceof,
+ Keywords.kw_as))
return false;
if (Style.Language == FormatStyle::LK_JavaScript &&
Tok.Previous->is(Keywords.kw_in))
return false;
// Skip "const" as it does not have an influence on whether this is a name.
- FormatToken *PreviousNotConst = Tok.Previous;
+ FormatToken *PreviousNotConst = Tok.getPreviousNonComment();
while (PreviousNotConst && PreviousNotConst->is(tok::kw_const))
- PreviousNotConst = PreviousNotConst->Previous;
+ PreviousNotConst = PreviousNotConst->getPreviousNonComment();
if (!PreviousNotConst)
return false;
@@ -1175,9 +1268,7 @@ private:
/// \brief Determine whether ')' is ending a cast.
bool rParenEndsCast(const FormatToken &Tok) {
// C-style casts are only used in C++ and Java.
- if (Style.Language != FormatStyle::LK_Cpp &&
- Style.Language != FormatStyle::LK_ObjC &&
- Style.Language != FormatStyle::LK_Java)
+ if (!Style.isCpp() && Style.Language != FormatStyle::LK_Java)
return false;
// Empty parens aren't casts and there are no casts at the end of the line.
@@ -1282,7 +1373,8 @@ private:
return TT_UnaryOperator;
const FormatToken *NextToken = Tok.getNextNonComment();
- if (!NextToken || NextToken->isOneOf(tok::arrow, tok::equal) ||
+ if (!NextToken ||
+ NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_const) ||
(NextToken->is(tok::l_brace) && !NextToken->getNextNonComment()))
return TT_PointerOrReference;
@@ -1291,7 +1383,8 @@ private:
if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace,
tok::comma, tok::semi, tok::kw_return, tok::colon,
- tok::equal, tok::kw_delete, tok::kw_sizeof) ||
+ tok::equal, tok::kw_delete, tok::kw_sizeof,
+ tok::kw_throw) ||
PrevToken->isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
TT_UnaryOperator, TT_CastRParen))
return TT_UnaryOperator;
@@ -1445,7 +1538,9 @@ public:
// At the end of the line or when an operator with higher precedence is
// found, insert fake parenthesis and return.
- if (!Current || (Current->closesScope() && Current->MatchingParen) ||
+ if (!Current ||
+ (Current->closesScope() &&
+ (Current->MatchingParen || Current->is(TT_TemplateString))) ||
(CurrentPrecedence != -1 && CurrentPrecedence < Precedence) ||
(CurrentPrecedence == prec::Conditional &&
Precedence == prec::Assignment && Current->is(tok::colon))) {
@@ -1454,7 +1549,9 @@ public:
// Consume scopes: (), [], <> and {}
if (Current->opensScope()) {
- while (Current && !Current->closesScope()) {
+ // In fragment of a JavaScript template string can look like '}..${' and
+ // thus close a scope and open a new one at the same time.
+ while (Current && (!Current->closesScope() || Current->opensScope())) {
next();
parse();
}
@@ -1491,15 +1588,19 @@ private:
const FormatToken *NextNonComment = Current->getNextNonComment();
if (Current->is(TT_ConditionalExpr))
return prec::Conditional;
- if (NextNonComment && NextNonComment->is(tok::colon) &&
- NextNonComment->is(TT_DictLiteral))
- return prec::Comma;
+ if (NextNonComment && Current->is(TT_SelectorName) &&
+ (NextNonComment->is(TT_DictLiteral) ||
+ ((Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) &&
+ NextNonComment->is(tok::less))))
+ return prec::Assignment;
+ if (Current->is(TT_JsComputedPropertyName))
+ return prec::Assignment;
if (Current->is(TT_LambdaArrow))
return prec::Comma;
if (Current->is(TT_JsFatArrow))
return prec::Assignment;
- if (Current->isOneOf(tok::semi, TT_InlineASMColon, TT_SelectorName,
- TT_JsComputedPropertyName) ||
+ if (Current->isOneOf(tok::semi, TT_InlineASMColon, TT_SelectorName) ||
(Current->is(tok::comment) && NextNonComment &&
NextNonComment->is(TT_SelectorName)))
return 0;
@@ -1510,7 +1611,7 @@ private:
Current->is(Keywords.kw_instanceof))
return prec::Relational;
if (Style.Language == FormatStyle::LK_JavaScript &&
- Current->is(Keywords.kw_in))
+ Current->isOneOf(Keywords.kw_in, Keywords.kw_as))
return prec::Relational;
if (Current->is(TT_BinaryOperator) || Current->is(tok::comma))
return Current->getPrecedence();
@@ -1594,11 +1695,26 @@ void TokenAnnotator::setCommentLineLevels(
for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(),
E = Lines.rend();
I != E; ++I) {
- if (NextNonCommentLine && (*I)->First->is(tok::comment) &&
- (*I)->First->Next == nullptr)
- (*I)->Level = NextNonCommentLine->Level;
- else
+ bool CommentLine = true;
+ for (const FormatToken *Tok = (*I)->First; Tok; Tok = Tok->Next) {
+ if (!Tok->is(tok::comment)) {
+ CommentLine = false;
+ break;
+ }
+ }
+
+ if (NextNonCommentLine && CommentLine) {
+ // If the comment is currently aligned with the line immediately following
+ // it, that's probably intentional and we should keep it.
+ bool AlignedWithNextLine =
+ NextNonCommentLine->First->NewlinesBefore <= 1 &&
+ NextNonCommentLine->First->OriginalColumn ==
+ (*I)->First->OriginalColumn;
+ if (AlignedWithNextLine)
+ (*I)->Level = NextNonCommentLine->Level;
+ } else {
NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr;
+ }
setCommentLineLevels((*I)->Children);
}
@@ -1697,7 +1813,7 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
}
}
- // Check whether parameter list can be long to a function declaration.
+ // Check whether parameter list can belong to a function declaration.
if (!Next || !Next->is(tok::l_paren) || !Next->MatchingParen)
return false;
// If the lines ends with "{", this is likely an function definition.
@@ -1711,6 +1827,10 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
return true;
for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen;
Tok = Tok->Next) {
+ if (Tok->is(tok::l_paren) && Tok->MatchingParen) {
+ Tok = Tok->MatchingParen;
+ continue;
+ }
if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() ||
Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis))
return true;
@@ -1753,8 +1873,6 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
Line.First->TotalLength =
Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth;
- if (!Line.First->Next)
- return;
FormatToken *Current = Line.First->Next;
bool InFunctionDecl = Line.MightBeFunctionDecl;
while (Current) {
@@ -1830,9 +1948,18 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
}
calculateUnbreakableTailLengths(Line);
+ unsigned IndentLevel = Line.Level;
for (Current = Line.First; Current != nullptr; Current = Current->Next) {
if (Current->Role)
Current->Role->precomputeFormattingInfos(Current);
+ if (Current->MatchingParen &&
+ Current->MatchingParen->opensBlockOrBlockTypeList(Style)) {
+ assert(IndentLevel > 0);
+ --IndentLevel;
+ }
+ Current->IndentLevel = IndentLevel;
+ if (Current->opensBlockOrBlockTypeList(Style))
+ ++IndentLevel;
}
DEBUG({ printDebugInfo(Line); });
@@ -1891,7 +2018,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Right.is(TT_LambdaLSquare) && Left.is(tok::equal))
return 35;
if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
- TT_ArrayInitializerLSquare))
+ TT_ArrayInitializerLSquare,
+ TT_DesignatedInitializerLSquare))
return 500;
}
@@ -1910,7 +2038,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Right.is(TT_LambdaArrow))
return 110;
if (Left.is(tok::equal) && Right.is(tok::l_brace))
- return 150;
+ return 160;
if (Left.is(TT_CastRParen))
return 100;
if (Left.is(tok::coloncolon) ||
@@ -1921,7 +2049,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.is(tok::comment))
return 1000;
- if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon))
+ if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon, TT_CtorInitializerColon))
return 2;
if (Right.isMemberAccess()) {
@@ -1979,7 +2107,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign)
return 100;
if (Left.is(tok::l_paren) && Left.Previous &&
- Left.Previous->isOneOf(tok::kw_if, tok::kw_for))
+ (Left.Previous->isOneOf(tok::kw_if, tok::kw_for)
+ || Left.Previous->endsSequence(tok::kw_constexpr, tok::kw_if)))
return 1000;
if (Left.is(tok::equal) && InFunctionDecl)
return 110;
@@ -2018,9 +2147,10 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.is(TT_ConditionalExpr))
return prec::Conditional;
prec::Level Level = Left.getPrecedence();
- if (Level != prec::Unknown)
- return Level;
- Level = Right.getPrecedence();
+ if (Level == prec::Unknown)
+ Level = Right.getPrecedence();
+ if (Level == prec::Assignment)
+ return Style.PenaltyBreakAssignment;
if (Level != prec::Unknown)
return Level;
@@ -2110,7 +2240,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
(Style.SpacesInSquareBrackets &&
Right.MatchingParen->is(TT_ArraySubscriptLSquare)));
if (Right.is(tok::l_square) &&
- !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare) &&
+ !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
+ TT_DesignatedInitializerLSquare) &&
!Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
return false;
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
@@ -2129,6 +2260,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
(Left.isOneOf(tok::kw_if, tok::pp_elif, tok::kw_for, tok::kw_while,
tok::kw_switch, tok::kw_case, TT_ForEachMacro,
TT_ObjCForIn) ||
+ Left.endsSequence(tok::kw_constexpr, tok::kw_if) ||
(Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
tok::kw_new, tok::kw_delete) &&
(!Left.Previous || Left.Previous->isNot(tok::period))))) ||
@@ -2167,10 +2299,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
const FormatToken &Left = *Right.Previous;
if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo())
return true; // Never ever merge two identifiers.
- if (Style.Language == FormatStyle::LK_Cpp) {
+ if (Style.isCpp()) {
if (Left.is(tok::kw_operator))
return Right.is(tok::coloncolon);
- } else if (Style.Language == FormatStyle::LK_Proto) {
+ } else if (Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TextProto) {
if (Right.is(tok::period) &&
Left.isOneOf(Keywords.kw_optional, Keywords.kw_required,
Keywords.kw_repeated, Keywords.kw_extend))
@@ -2178,13 +2311,31 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Right.is(tok::l_paren) &&
Left.isOneOf(Keywords.kw_returns, Keywords.kw_option))
return true;
+ if (Right.isOneOf(tok::l_brace, tok::less) && Left.is(TT_SelectorName))
+ return true;
} else if (Style.Language == FormatStyle::LK_JavaScript) {
if (Left.is(TT_JsFatArrow))
return true;
+ // for await ( ...
+ if (Right.is(tok::l_paren) && Left.is(Keywords.kw_await) &&
+ Left.Previous && Left.Previous->is(tok::kw_for))
+ return true;
+ if (Left.is(Keywords.kw_async) && Right.is(tok::l_paren) &&
+ Right.MatchingParen) {
+ const FormatToken *Next = Right.MatchingParen->getNextNonComment();
+ // An async arrow function, for example: `x = async () => foo();`,
+ // as opposed to calling a function called async: `x = async();`
+ if (Next && Next->is(TT_JsFatArrow))
+ return true;
+ }
if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
(Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
return false;
- if (Left.is(tok::identifier) && Right.is(TT_TemplateString))
+ // In tagged template literals ("html`bar baz`"), there is no space between
+ // the tag identifier and the template string. getIdentifierInfo makes sure
+ // that the identifier is not a pseudo keyword like `yield`, either.
+ if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) &&
+ Right.is(TT_TemplateString))
return false;
if (Right.is(tok::star) &&
Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
@@ -2196,8 +2347,12 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Right.is(tok::l_paren) && Line.MustBeDeclaration &&
Left.Tok.getIdentifierInfo())
return false;
- if (Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
- Keywords.kw_of, tok::kw_const) &&
+ if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
+ tok::kw_const) ||
+ // "of" is only a keyword if it appears after another identifier
+ // (e.g. as "const x of y" in a for loop).
+ (Left.is(Keywords.kw_of) && Left.Previous &&
+ Left.Previous->Tok.getIdentifierInfo())) &&
(!Left.Previous || !Left.Previous->is(tok::period)))
return true;
if (Left.isOneOf(tok::kw_for, Keywords.kw_as) && Left.Previous &&
@@ -2227,12 +2382,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// locations that should have whitespace following are identified by the
// above set of follower tokens.
return false;
- // Postfix non-null assertion operator, as in `foo!.bar()`.
- if (Right.is(tok::exclaim) && (Left.isOneOf(tok::identifier, tok::r_paren,
- tok::r_square, tok::r_brace) ||
- Left.Tok.isLiteral()))
+ if (Right.is(TT_JsNonNullAssertion))
return false;
- if (Left.is(tok::exclaim) && Right.is(Keywords.kw_as))
+ if (Left.is(TT_JsNonNullAssertion) && Right.is(Keywords.kw_as))
return true; // "x! as string"
} else if (Style.Language == FormatStyle::LK_Java) {
if (Left.is(tok::r_square) && Right.is(tok::l_brace))
@@ -2296,18 +2448,23 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Left.is(tok::greater) && Right.is(tok::greater))
return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
(Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
- if (Right.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
- Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar))
+ if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) ||
+ Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
+ (Right.is(tok::period) && Right.isNot(TT_DesignatedInitializerPeriod)))
return false;
if (!Style.SpaceBeforeAssignmentOperators &&
Right.getPrecedence() == prec::Assignment)
return false;
+ if (Right.is(tok::coloncolon) && Left.is(tok::identifier))
+ // Generally don't remove existing spaces between an identifier and "::".
+ // The identifier might actually be a macro name such as ALWAYS_INLINE. If
+ // this turns out to be too lenient, add analysis of the identifier itself.
+ return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment))
return (Left.is(TT_TemplateOpener) &&
Style.Standard == FormatStyle::LS_Cpp03) ||
- !(Left.isOneOf(tok::identifier, tok::l_paren, tok::r_paren,
- tok::l_square) ||
- Left.isOneOf(TT_TemplateCloser, TT_TemplateOpener));
+ !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
+ tok::kw___super, TT_TemplateCloser, TT_TemplateOpener));
if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser)))
return Style.SpacesInAngles;
if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
@@ -2369,28 +2526,40 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None ||
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty ||
(Left.NestingLevel == 0 && Line.Level == 0 &&
- Style.AllowShortFunctionsOnASingleLine ==
- FormatStyle::SFS_Inline);
+ Style.AllowShortFunctionsOnASingleLine &
+ FormatStyle::SFS_InlineOnly);
} else if (Style.Language == FormatStyle::LK_Java) {
if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next &&
Right.Next->is(tok::string_literal))
return true;
+ } else if (Style.Language == FormatStyle::LK_Cpp ||
+ Style.Language == FormatStyle::LK_ObjC ||
+ Style.Language == FormatStyle::LK_Proto) {
+ if (Left.isStringLiteral() && Right.isStringLiteral())
+ return true;
}
- // If the last token before a '}' is a comma or a trailing comment, the
- // intention is to insert a line break after it in order to make shuffling
- // around entries easier.
- const FormatToken *BeforeClosingBrace = nullptr;
- if (Left.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) &&
- Left.BlockKind != BK_Block && Left.MatchingParen)
- BeforeClosingBrace = Left.MatchingParen->Previous;
- else if (Right.MatchingParen &&
- Right.MatchingParen->isOneOf(tok::l_brace,
- TT_ArrayInitializerLSquare))
- BeforeClosingBrace = &Left;
- if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) ||
- BeforeClosingBrace->isTrailingComment()))
- return true;
+ // If the last token before a '}', ']', or ')' is a comma or a trailing
+ // comment, the intention is to insert a line break after it in order to make
+ // shuffling around entries easier. Import statements, especially in
+ // JavaScript, can be an exception to this rule.
+ if (Style.JavaScriptWrapImports || Line.Type != LT_ImportStatement) {
+ const FormatToken *BeforeClosingBrace = nullptr;
+ if ((Left.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
+ (Style.Language == FormatStyle::LK_JavaScript &&
+ Left.is(tok::l_paren))) &&
+ Left.BlockKind != BK_Block && Left.MatchingParen)
+ BeforeClosingBrace = Left.MatchingParen->Previous;
+ else if (Right.MatchingParen &&
+ (Right.MatchingParen->isOneOf(tok::l_brace,
+ TT_ArrayInitializerLSquare) ||
+ (Style.Language == FormatStyle::LK_JavaScript &&
+ Right.MatchingParen->is(tok::l_paren))))
+ BeforeClosingBrace = &Left;
+ if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) ||
+ BeforeClosingBrace->isTrailingComment()))
+ return true;
+ }
if (Right.is(tok::comment))
return Left.BlockKind != BK_BracedInit &&
@@ -2398,9 +2567,6 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
(Right.NewlinesBefore > 0 && Right.HasUnescapedNewline);
if (Left.isTrailingComment())
return true;
- if (Left.isStringLiteral() &&
- (Right.isStringLiteral() || Right.is(TT_ObjCStringLiteral)))
- return true;
if (Right.Previous->IsUnterminatedLiteral)
return true;
if (Right.is(tok::lessless) && Right.Next &&
@@ -2412,19 +2578,33 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
Right.Previous->MatchingParen->NestingLevel == 0 &&
Style.AlwaysBreakTemplateDeclarations)
return true;
- if ((Right.isOneOf(TT_CtorInitializerComma, TT_CtorInitializerColon)) &&
- Style.BreakConstructorInitializersBeforeComma &&
+ if (Right.is(TT_CtorInitializerComma) &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma &&
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
return true;
+ if (Right.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma &&
+ !Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
+ return true;
+ // Break only if we have multiple inheritance.
+ if (Style.BreakBeforeInheritanceComma &&
+ Right.is(TT_InheritanceComma))
+ return true;
if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\""))
// Raw string literals are special wrt. line breaks. The author has made a
// deliberate choice and might have aligned the contents of the string
// literal accordingly. Thus, we try keep existing line breaks.
return Right.NewlinesBefore > 0;
- if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
- Style.Language == FormatStyle::LK_Proto)
- // Don't put enums onto single lines in protocol buffers.
+ if ((Right.Previous->is(tok::l_brace) ||
+ (Right.Previous->is(tok::less) &&
+ Right.Previous->Previous &&
+ Right.Previous->Previous->is(tok::equal))
+ ) &&
+ Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) {
+ // Don't put enums or option definitions onto single lines in protocol
+ // buffers.
return true;
+ }
if (Right.is(TT_InlineASMBrace))
return Right.HasUnescapedNewline;
if (isAllmanBrace(Left) || isAllmanBrace(Right))
@@ -2458,12 +2638,14 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return true;
} else if (Style.Language == FormatStyle::LK_JavaScript) {
const FormatToken *NonComment = Right.getPreviousNonComment();
- if (Left.isOneOf(tok::kw_return, tok::kw_continue, tok::kw_break,
- tok::kw_throw) ||
- (NonComment &&
- NonComment->isOneOf(tok::kw_return, tok::kw_continue, tok::kw_break,
- tok::kw_throw)))
- return false; // Otherwise a semicolon is inserted.
+ if (NonComment &&
+ NonComment->isOneOf(tok::kw_return, tok::kw_continue, tok::kw_break,
+ tok::kw_throw, Keywords.kw_interface,
+ Keywords.kw_type, tok::kw_static, tok::kw_public,
+ tok::kw_private, tok::kw_protected,
+ Keywords.kw_readonly, Keywords.kw_abstract,
+ Keywords.kw_get, Keywords.kw_set))
+ return false; // Otherwise automatic semicolon insertion would trigger.
if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace))
return false;
if (Left.is(TT_JsTypeColon))
@@ -2476,6 +2658,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None;
if (Right.is(Keywords.kw_as))
return false; // must not break before as in 'x as type' casts
+ if (Left.is(Keywords.kw_as))
+ return true;
+ if (Left.is(TT_JsNonNullAssertion))
+ return true;
if (Left.is(Keywords.kw_declare) &&
Right.isOneOf(Keywords.kw_module, tok::kw_namespace,
Keywords.kw_function, tok::kw_class, tok::kw_enum,
@@ -2485,9 +2671,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
// https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#A.10
return false;
if (Left.isOneOf(Keywords.kw_module, tok::kw_namespace) &&
- Right.isOneOf(tok::identifier, tok::string_literal)) {
+ Right.isOneOf(tok::identifier, tok::string_literal))
return false; // must not break in "module foo { ...}"
- }
+ if (Right.is(TT_TemplateString) && Right.closesScope())
+ return false;
+ if (Left.is(TT_TemplateString) && Left.opensScope())
+ return true;
}
if (Left.is(tok::at))
@@ -2511,7 +2700,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
// The first comment in a braced lists is always interpreted as belonging to
// the first list element. Otherwise, it should be placed outside of the
// list.
- return Left.BlockKind == BK_BracedInit;
+ return Left.BlockKind == BK_BracedInit ||
+ (Left.is(TT_CtorInitializerColon) &&
+ Style.BreakConstructorInitializers ==
+ FormatStyle::BCIS_AfterColon);
if (Left.is(tok::question) && Right.is(tok::colon))
return false;
if (Right.is(TT_ConditionalExpr) || Right.is(tok::question))
@@ -2584,11 +2776,19 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
return true;
+ if (Left.is(TT_CtorInitializerColon))
+ return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon;
+ if (Right.is(TT_CtorInitializerColon))
+ return Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon;
if (Left.is(TT_CtorInitializerComma) &&
- Style.BreakConstructorInitializersBeforeComma)
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
return false;
if (Right.is(TT_CtorInitializerComma) &&
- Style.BreakConstructorInitializersBeforeComma)
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
+ return true;
+ if (Left.is(TT_InheritanceComma) && Style.BreakBeforeInheritanceComma)
+ return false;
+ if (Right.is(TT_InheritanceComma) && Style.BreakBeforeInheritanceComma)
return true;
if ((Left.is(tok::greater) && Right.is(tok::greater)) ||
(Left.is(tok::less) && Right.is(tok::less)))
@@ -2615,7 +2815,8 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
tok::colon, tok::l_square, tok::at) ||
(Left.is(tok::r_paren) &&
Right.isOneOf(tok::identifier, tok::kw_const)) ||
- (Left.is(tok::l_paren) && !Right.is(tok::r_paren));
+ (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
+ (Left.is(TT_TemplateOpener) && !Right.is(TT_TemplateCloser));
}
void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
@@ -2627,6 +2828,7 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
<< " T=" << getTokenTypeName(Tok->Type)
<< " S=" << Tok->SpacesRequiredBefore
<< " B=" << Tok->BlockParameterCount
+ << " BK=" << Tok->BlockKind
<< " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName()
<< " L=" << Tok->TotalLength << " PPK=" << Tok->PackingKind
<< " FakeLParens=";
diff --git a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.h b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.h
index 97daaf4..8055095 100644
--- a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.h
+++ b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.h
@@ -39,6 +39,7 @@ class AnnotatedLine {
public:
AnnotatedLine(const UnwrappedLine &Line)
: First(Line.Tokens.front().Tok), Level(Line.Level),
+ MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex),
InPPDirective(Line.InPPDirective),
MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
IsMultiVariableDeclStmt(false), Affected(false),
@@ -109,6 +110,7 @@ public:
LineType Type;
unsigned Level;
+ size_t MatchingOpeningBlockLineIndex;
bool InPPDirective;
bool MustBeDeclaration;
bool MightBeFunctionDecl;
@@ -122,7 +124,7 @@ public:
/// input ranges.
bool LeadingEmptyLinesAffected;
- /// \c True if a one of this line's children intersects with an input range.
+ /// \c True if one of this line's children intersects with an input range.
bool ChildrenAffected;
private:
diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp
index d7f1c42..2005a28 100644
--- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -66,6 +66,13 @@ public:
Indent += Offset;
}
+ /// \brief Update the indent state given that \p Line indent should be
+ /// skipped.
+ void skipLine(const AnnotatedLine &Line) {
+ while (IndentForLevel.size() <= Line.Level)
+ IndentForLevel.push_back(Indent);
+ }
+
/// \brief Update the level indent to adapt to the given \p Line.
///
/// When a line is not formatted, we move the subsequent lines on the same
@@ -127,12 +134,28 @@ private:
unsigned Indent = 0;
};
+bool isNamespaceDeclaration(const AnnotatedLine *Line) {
+ const FormatToken *NamespaceTok = Line->First;
+ return NamespaceTok && NamespaceTok->getNamespaceToken();
+}
+
+bool isEndOfNamespace(const AnnotatedLine *Line,
+ const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+ if (!Line->startsWith(tok::r_brace))
+ return false;
+ size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex;
+ if (StartLineIndex == UnwrappedLine::kInvalidIndex)
+ return false;
+ assert(StartLineIndex < AnnotatedLines.size());
+ return isNamespaceDeclaration(AnnotatedLines[StartLineIndex]);
+}
+
class LineJoiner {
public:
LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords,
const SmallVectorImpl<AnnotatedLine *> &Lines)
- : Style(Style), Keywords(Keywords), End(Lines.end()),
- Next(Lines.begin()) {}
+ : Style(Style), Keywords(Keywords), End(Lines.end()), Next(Lines.begin()),
+ AnnotatedLines(Lines) {}
/// \brief Returns the next line, merging multiple lines into one if possible.
const AnnotatedLine *getNextMergedLine(bool DryRun,
@@ -142,7 +165,7 @@ public:
const AnnotatedLine *Current = *Next;
IndentTracker.nextLine(*Current);
unsigned MergedLines =
- tryFitMultipleLinesInOne(IndentTracker.getIndent(), Next, End);
+ tryFitMultipleLinesInOne(IndentTracker, Next, End);
if (MergedLines > 0 && Style.ColumnLimit == 0)
// Disallow line merging if there is a break at the start of one of the
// input lines.
@@ -159,9 +182,11 @@ public:
private:
/// \brief Calculates how many lines can be merged into 1 starting at \p I.
unsigned
- tryFitMultipleLinesInOne(unsigned Indent,
+ tryFitMultipleLinesInOne(LevelIndentTracker &IndentTracker,
SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
+ const unsigned Indent = IndentTracker.getIndent();
+
// Can't join the last line with anything.
if (I + 1 == E)
return 0;
@@ -186,15 +211,74 @@ private:
? 0
: Limit - TheLine->Last->TotalLength;
+ if (TheLine->Last->is(TT_FunctionLBrace) &&
+ TheLine->First == TheLine->Last &&
+ !Style.BraceWrapping.SplitEmptyFunction &&
+ I[1]->First->is(tok::r_brace))
+ return tryMergeSimpleBlock(I, E, Limit);
+
+ // Handle empty record blocks where the brace has already been wrapped
+ if (TheLine->Last->is(tok::l_brace) && TheLine->First == TheLine->Last &&
+ I != AnnotatedLines.begin()) {
+ bool EmptyBlock = I[1]->First->is(tok::r_brace);
+
+ const FormatToken *Tok = I[-1]->First;
+ if (Tok && Tok->is(tok::comment))
+ Tok = Tok->getNextNonComment();
+
+ if (Tok && Tok->getNamespaceToken())
+ return !Style.BraceWrapping.SplitEmptyNamespace && EmptyBlock
+ ? tryMergeSimpleBlock(I, E, Limit) : 0;
+
+ if (Tok && Tok->is(tok::kw_typedef))
+ Tok = Tok->getNextNonComment();
+ if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
+ Keywords.kw_interface))
+ return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock
+ ? tryMergeSimpleBlock(I, E, Limit) : 0;
+ }
+
// FIXME: TheLine->Level != 0 might or might not be the right check to do.
// If necessary, change to something smarter.
bool MergeShortFunctions =
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
(Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
I[1]->First->is(tok::r_brace)) ||
- (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
+ (Style.AllowShortFunctionsOnASingleLine & FormatStyle::SFS_InlineOnly &&
TheLine->Level != 0);
+ if (Style.CompactNamespaces) {
+ if (isNamespaceDeclaration(TheLine)) {
+ int i = 0;
+ unsigned closingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
+ for (; I + 1 + i != E && isNamespaceDeclaration(I[i + 1]) &&
+ closingLine == I[i + 1]->MatchingOpeningBlockLineIndex &&
+ I[i + 1]->Last->TotalLength < Limit;
+ i++, closingLine--) {
+ // No extra indent for compacted namespaces
+ IndentTracker.skipLine(*I[i + 1]);
+
+ Limit -= I[i + 1]->Last->TotalLength;
+ }
+ return i;
+ }
+
+ if (isEndOfNamespace(TheLine, AnnotatedLines)) {
+ int i = 0;
+ unsigned openingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
+ for (; I + 1 + i != E && isEndOfNamespace(I[i + 1], AnnotatedLines) &&
+ openingLine == I[i + 1]->MatchingOpeningBlockLineIndex;
+ i++, openingLine--) {
+ // No space between consecutive braces
+ I[i + 1]->First->SpacesRequiredBefore = !I[i]->Last->is(tok::r_brace);
+
+ // Indent like the outer-most namespace
+ IndentTracker.nextLine(*I[i + 1]);
+ }
+ return i;
+ }
+ }
+
if (TheLine->Last->is(TT_FunctionLBrace) &&
TheLine->First != TheLine->Last) {
return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
@@ -215,7 +299,10 @@ private:
Limit -= 2;
unsigned MergedLines = 0;
- if (MergeShortFunctions) {
+ if (MergeShortFunctions ||
+ (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
+ I[1]->First == I[1]->Last && I + 2 != E &&
+ I[2]->First->is(tok::r_brace))) {
MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
// If we managed to merge the block, count the function header, which is
// on a separate line.
@@ -365,8 +452,11 @@ private:
} else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
!startsExternCBlock(Line)) {
// We don't merge short records.
- if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
- Keywords.kw_interface))
+ FormatToken *RecordTok =
+ Line.First->is(tok::kw_typedef) ? Line.First->Next : Line.First;
+ if (RecordTok &&
+ RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
+ Keywords.kw_interface))
return 0;
// Check that we still have three lines and they fit into the limit.
@@ -449,6 +539,7 @@ private:
const SmallVectorImpl<AnnotatedLine *>::const_iterator End;
SmallVectorImpl<AnnotatedLine *>::const_iterator Next;
+ const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines;
};
static void markFinalized(FormatToken *Tok) {
@@ -530,34 +621,33 @@ protected:
if (Previous.Children[0]->First->MustBreakBefore)
return false;
- // Cannot merge multiple statements into a single line.
- if (Previous.Children.size() > 1)
- return false;
-
// Cannot merge into one line if this line ends on a comment.
if (Previous.is(tok::comment))
return false;
+ // Cannot merge multiple statements into a single line.
+ if (Previous.Children.size() > 1)
+ return false;
+
+ const AnnotatedLine *Child = Previous.Children[0];
// We can't put the closing "}" on a line with a trailing comment.
- if (Previous.Children[0]->Last->isTrailingComment())
+ if (Child->Last->isTrailingComment())
return false;
// If the child line exceeds the column limit, we wouldn't want to merge it.
// We add +2 for the trailing " }".
if (Style.ColumnLimit > 0 &&
- Previous.Children[0]->Last->TotalLength + State.Column + 2 >
- Style.ColumnLimit)
+ Child->Last->TotalLength + State.Column + 2 > Style.ColumnLimit)
return false;
if (!DryRun) {
Whitespaces->replaceWhitespace(
- *Previous.Children[0]->First,
- /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,
+ *Child->First, /*Newlines=*/0, /*Spaces=*/1,
/*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
}
- Penalty += formatLine(*Previous.Children[0], State.Column + 1, DryRun);
+ Penalty += formatLine(*Child, State.Column + 1, DryRun);
- State.Column += 1 + Previous.Children[0]->Last->TotalLength;
+ State.Column += 1 + Child->Last->TotalLength;
return true;
}
@@ -612,7 +702,8 @@ public:
LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
while (State.NextToken) {
formatChildren(State, /*Newline=*/false, DryRun, Penalty);
- Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
+ Indenter->addTokenToState(
+ State, /*Newline=*/State.NextToken->MustBreakBefore, DryRun);
}
return Penalty;
}
@@ -836,13 +927,15 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
bool ShouldFormat = TheLine.Affected || FixIndentation;
// We cannot format this line; if the reason is that the line had a
// parsing error, remember that.
- if (ShouldFormat && TheLine.Type == LT_Invalid && IncompleteFormat)
- *IncompleteFormat = true;
+ if (ShouldFormat && TheLine.Type == LT_Invalid && Status) {
+ Status->FormatComplete = false;
+ Status->Line =
+ SourceMgr.getSpellingLineNumber(TheLine.First->Tok.getLocation());
+ }
if (ShouldFormat && TheLine.Type != LT_Invalid) {
if (!DryRun)
- formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level, Indent,
- TheLine.InPPDirective);
+ formatFirstToken(TheLine, PreviousLine, Indent);
NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine);
@@ -882,9 +975,8 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
TheLine.LeadingEmptyLinesAffected);
// Format the first token.
if (ReformatLeadingWhitespace)
- formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,
- TheLine.First->OriginalColumn,
- TheLine.InPPDirective);
+ formatFirstToken(TheLine, PreviousLine,
+ TheLine.First->OriginalColumn);
else
Whitespaces->addUntouchableToken(*TheLine.First,
TheLine.InPPDirective);
@@ -904,15 +996,14 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
return Penalty;
}
-void UnwrappedLineFormatter::formatFirstToken(FormatToken &RootToken,
+void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
const AnnotatedLine *PreviousLine,
- unsigned IndentLevel,
- unsigned Indent,
- bool InPPDirective) {
+ unsigned Indent) {
+ FormatToken& RootToken = *Line.First;
if (RootToken.is(tok::eof)) {
unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u);
- Whitespaces->replaceWhitespace(RootToken, Newlines, /*IndentLevel=*/0,
- /*Spaces=*/0, /*TargetColumn=*/0);
+ Whitespaces->replaceWhitespace(RootToken, Newlines, /*Spaces=*/0,
+ /*StartOfTokenColumn=*/0);
return;
}
unsigned Newlines =
@@ -944,9 +1035,9 @@ void UnwrappedLineFormatter::formatFirstToken(FormatToken &RootToken,
(!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline))
Newlines = std::min(1u, Newlines);
- Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
- Indent, InPPDirective &&
- !RootToken.HasUnescapedNewline);
+ Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
+ Line.InPPDirective &&
+ !RootToken.HasUnescapedNewline);
}
unsigned
diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.h b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.h
index 7bcead9..55f0d1c 100644
--- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.h
+++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.h
@@ -32,9 +32,11 @@ public:
WhitespaceManager *Whitespaces,
const FormatStyle &Style,
const AdditionalKeywords &Keywords,
- bool *IncompleteFormat)
+ const SourceManager &SourceMgr,
+ FormattingAttemptStatus *Status)
: Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
- Keywords(Keywords), IncompleteFormat(IncompleteFormat) {}
+ Keywords(Keywords), SourceMgr(SourceMgr),
+ Status(Status) {}
/// \brief Format the current block and return the penalty.
unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines,
@@ -44,9 +46,8 @@ public:
private:
/// \brief Add a new line and the required indent before the first Token
/// of the \c UnwrappedLine if there was no structural parsing error.
- void formatFirstToken(FormatToken &RootToken,
- const AnnotatedLine *PreviousLine, unsigned IndentLevel,
- unsigned Indent, bool InPPDirective);
+ void formatFirstToken(const AnnotatedLine &Line,
+ const AnnotatedLine *PreviousLine, unsigned Indent);
/// \brief Returns the column limit for a line, taking into account whether we
/// need an escaped newline due to a continued preprocessor directive.
@@ -57,13 +58,15 @@ private:
// starting from a specific additional offset. Improves performance if there
// are many nested blocks.
std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
- unsigned> PenaltyCache;
+ unsigned>
+ PenaltyCache;
ContinuationIndenter *Indenter;
WhitespaceManager *Whitespaces;
const FormatStyle &Style;
const AdditionalKeywords &Keywords;
- bool *IncompleteFormat;
+ const SourceManager &SourceMgr;
+ FormattingAttemptStatus *Status;
};
} // end namespace format
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp
index 8fc3b78..faac5a3 100644
--- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp
@@ -55,13 +55,33 @@ private:
std::vector<bool> &Stack;
};
+static bool isLineComment(const FormatToken &FormatTok) {
+ return FormatTok.is(tok::comment) &&
+ FormatTok.TokenText.startswith("//");
+}
+
+// Checks if \p FormatTok is a line comment that continues the line comment
+// \p Previous. The original column of \p MinColumnToken is used to determine
+// whether \p FormatTok is indented enough to the right to continue \p Previous.
+static bool continuesLineComment(const FormatToken &FormatTok,
+ const FormatToken *Previous,
+ const FormatToken *MinColumnToken) {
+ if (!Previous || !MinColumnToken)
+ return false;
+ unsigned MinContinueColumn =
+ MinColumnToken->OriginalColumn + (isLineComment(*MinColumnToken) ? 0 : 1);
+ return isLineComment(FormatTok) && FormatTok.NewlinesBefore == 1 &&
+ isLineComment(*Previous) &&
+ FormatTok.OriginalColumn >= MinContinueColumn;
+}
+
class ScopedMacroState : public FormatTokenSource {
public:
ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,
FormatToken *&ResetToken)
: Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource),
- Token(nullptr) {
+ Token(nullptr), PreviousToken(nullptr) {
TokenSource = this;
Line.Level = 0;
Line.InPPDirective = true;
@@ -78,6 +98,7 @@ public:
// The \c UnwrappedLineParser guards against this by never calling
// \c getNextToken() after it has encountered the first eof token.
assert(!eof());
+ PreviousToken = Token;
Token = PreviousTokenSource->getNextToken();
if (eof())
return getFakeEOF();
@@ -87,12 +108,17 @@ public:
unsigned getPosition() override { return PreviousTokenSource->getPosition(); }
FormatToken *setPosition(unsigned Position) override {
+ PreviousToken = nullptr;
Token = PreviousTokenSource->setPosition(Position);
return Token;
}
private:
- bool eof() { return Token && Token->HasUnescapedNewline; }
+ bool eof() {
+ return Token && Token->HasUnescapedNewline &&
+ !continuesLineComment(*Token, PreviousToken,
+ /*MinColumnToken=*/PreviousToken);
+ }
FormatToken *getFakeEOF() {
static bool EOFInitialized = false;
@@ -112,6 +138,7 @@ private:
FormatTokenSource *PreviousTokenSource;
FormatToken *Token;
+ FormatToken *PreviousToken;
};
} // end anonymous namespace
@@ -202,7 +229,8 @@ UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
- CurrentLines(&Lines), Style(Style), Keywords(Keywords), Tokens(nullptr),
+ CurrentLines(&Lines), Style(Style), Keywords(Keywords),
+ CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {}
void UnwrappedLineParser::reset() {
@@ -258,7 +286,10 @@ void UnwrappedLineParser::parseFile() {
!Line->InPPDirective && Style.Language != FormatStyle::LK_JavaScript;
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
MustBeDeclaration);
- parseLevel(/*HasOpeningBrace=*/false);
+ if (Style.Language == FormatStyle::LK_TextProto)
+ parseBracedList();
+ else
+ parseLevel(/*HasOpeningBrace=*/false);
// Make sure to format the remaining tokens.
flushComments(true);
addUnwrappedLine();
@@ -332,13 +363,21 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
switch (Tok->Tok.getKind()) {
case tok::l_brace:
- if (Style.Language == FormatStyle::LK_JavaScript && PrevTok &&
- PrevTok->is(tok::colon))
- // In TypeScript's TypeMemberLists, there can be semicolons between the
- // individual members.
- Tok->BlockKind = BK_BracedInit;
- else
+ if (Style.Language == FormatStyle::LK_JavaScript && PrevTok) {
+ if (PrevTok->is(tok::colon))
+ // A colon indicates this code is in a type, or a braced list
+ // following a label in an object literal ({a: {b: 1}}). The code
+ // below could be confused by semicolons between the individual
+ // members in a type member list, which would normally trigger
+ // BK_Block. In both cases, this must be parsed as an inline braced
+ // init.
+ Tok->BlockKind = BK_BracedInit;
+ else if (PrevTok->is(tok::r_paren))
+ // `) { }` can only occur in function or method declarations in JS.
+ Tok->BlockKind = BK_Block;
+ } else {
Tok->BlockKind = BK_Unknown;
+ }
LBraceStack.push_back(Tok);
break;
case tok::r_brace:
@@ -360,13 +399,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
// BlockKind later if we parse a braced list (where all blocks
// inside are by default braced lists), or when we explicitly detect
// blocks (for example while parsing lambdas).
+ // FIXME: Some of these do not apply to JS, e.g. "} {" can never be a
+ // braced list in JS.
ProbablyBracedList =
(Style.Language == FormatStyle::LK_JavaScript &&
NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in,
Keywords.kw_as)) ||
+ (Style.isCpp() && NextTok->is(tok::l_paren)) ||
NextTok->isOneOf(tok::comma, tok::period, tok::colon,
tok::r_paren, tok::r_square, tok::l_brace,
- tok::l_square, tok::l_paren, tok::ellipsis) ||
+ tok::l_square, tok::ellipsis) ||
(NextTok->is(tok::identifier) &&
!PrevTok->isOneOf(tok::semi, tok::r_brace, tok::l_brace)) ||
(NextTok->is(tok::semi) &&
@@ -424,6 +466,9 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
parseParens();
addUnwrappedLine();
+ size_t OpeningLineIndex = CurrentLines->empty()
+ ? (UnwrappedLine::kInvalidIndex)
+ : (CurrentLines->size() - 1);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
MustBeDeclaration);
@@ -449,6 +494,12 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
if (MunchSemi && FormatTok->Tok.is(tok::semi))
nextToken();
Line->Level = InitialLevel;
+ Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
+ if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) {
+ // Update the opening line to add the forward reference as well
+ (*CurrentLines)[OpeningLineIndex].MatchingOpeningBlockLineIndex =
+ CurrentLines->size() - 1;
+ }
}
static bool isGoogScope(const UnwrappedLine &Line) {
@@ -469,6 +520,24 @@ static bool isGoogScope(const UnwrappedLine &Line) {
return I->Tok->is(tok::l_paren);
}
+static bool isIIFE(const UnwrappedLine &Line,
+ const AdditionalKeywords &Keywords) {
+ // Look for the start of an immediately invoked anonymous function.
+ // https://en.wikipedia.org/wiki/Immediately-invoked_function_expression
+ // This is commonly done in JavaScript to create a new, anonymous scope.
+ // Example: (function() { ... })()
+ if (Line.Tokens.size() < 3)
+ return false;
+ auto I = Line.Tokens.begin();
+ if (I->Tok->isNot(tok::l_paren))
+ return false;
+ ++I;
+ if (I->Tok->isNot(Keywords.kw_function))
+ return false;
+ ++I;
+ return I->Tok->is(tok::l_paren);
+}
+
static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
const FormatToken &InitialToken) {
if (InitialToken.is(tok::kw_namespace))
@@ -486,15 +555,16 @@ void UnwrappedLineParser::parseChildBlock() {
FormatTok->BlockKind = BK_Block;
nextToken();
{
- bool GoogScope =
- Style.Language == FormatStyle::LK_JavaScript && isGoogScope(*Line);
+ bool SkipIndent =
+ (Style.Language == FormatStyle::LK_JavaScript &&
+ (isGoogScope(*Line) || isIIFE(*Line, Keywords)));
ScopedLineState LineState(*this);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
/*MustBeDeclaration=*/false);
- Line->Level += GoogScope ? 0 : 1;
+ Line->Level += SkipIndent ? 0 : 1;
parseLevel(/*HasOpeningBrace=*/true);
flushComments(isOnNewLine(*FormatTok));
- Line->Level -= GoogScope ? 0 : 1;
+ Line->Level -= SkipIndent ? 0 : 1;
}
nextToken();
}
@@ -582,13 +652,14 @@ void UnwrappedLineParser::conditionalCompilationEnd() {
}
void UnwrappedLineParser::parsePPIf(bool IfDef) {
+ bool IfNDef = FormatTok->is(tok::pp_ifndef);
nextToken();
- bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
- FormatTok->Tok.getLiteralData() != nullptr &&
- StringRef(FormatTok->Tok.getLiteralData(),
- FormatTok->Tok.getLength()) == "0") ||
- FormatTok->Tok.is(tok::kw_false);
- conditionalCompilationStart(!IfDef && IsLiteralFalse);
+ bool Unreachable = false;
+ if (!IfDef && (FormatTok->is(tok::kw_false) || FormatTok->TokenText == "0"))
+ Unreachable = true;
+ if (IfDef && !IfNDef && FormatTok->TokenText == "SWIG")
+ Unreachable = true;
+ conditionalCompilationStart(Unreachable);
parsePPUnknown();
}
@@ -676,7 +747,7 @@ static bool mustBeJSIdent(const AdditionalKeywords &Keywords,
Keywords.kw_let, Keywords.kw_var, tok::kw_const,
Keywords.kw_abstract, Keywords.kw_extends, Keywords.kw_implements,
Keywords.kw_instanceof, Keywords.kw_interface,
- Keywords.kw_throws));
+ Keywords.kw_throws, Keywords.kw_from));
}
static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords,
@@ -746,8 +817,7 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
Previous->isOneOf(tok::r_square, tok::r_paren, tok::plusplus,
tok::minusminus)))
return addUnwrappedLine();
- if ((PreviousMustBeValue || Previous->is(tok::r_brace)) &&
- isJSDeclOrStmt(Keywords, Next))
+ if (PreviousMustBeValue && isJSDeclOrStmt(Keywords, Next))
return addUnwrappedLine();
}
@@ -765,6 +835,7 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::at:
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
break;
}
@@ -909,7 +980,8 @@ void UnwrappedLineParser::parseStructuralElement() {
return;
}
}
- if (FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
+ if (Style.isCpp() &&
+ FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
Keywords.kw_slots, Keywords.kw_qslots)) {
nextToken();
if (FormatTok->is(tok::colon)) {
@@ -928,8 +1000,10 @@ void UnwrappedLineParser::parseStructuralElement() {
switch (FormatTok->Tok.getKind()) {
case tok::at:
nextToken();
- if (FormatTok->Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
+ }
break;
case tok::kw_enum:
// Ignore if this is part of "template <enum ...".
@@ -943,7 +1017,7 @@ void UnwrappedLineParser::parseStructuralElement() {
if (!parseEnum())
break;
// This only applies for C++.
- if (Style.Language != FormatStyle::LK_Cpp) {
+ if (!Style.isCpp()) {
addUnwrappedLine();
return;
}
@@ -1032,13 +1106,15 @@ void UnwrappedLineParser::parseStructuralElement() {
return;
}
- // Parse function literal unless 'function' is the first token in a line
- // in which case this should be treated as a free-standing function.
+ // Function declarations (as opposed to function expressions) are parsed
+ // on their own unwrapped line by continuing this loop. Function
+ // expressions (functions that are not on their own line) must not create
+ // a new unwrapped line, so they are special cased below.
+ size_t TokenCount = Line->Tokens.size();
if (Style.Language == FormatStyle::LK_JavaScript &&
- (FormatTok->is(Keywords.kw_function) ||
- FormatTok->startsSequence(Keywords.kw_async,
- Keywords.kw_function)) &&
- Line->Tokens.size() > 0) {
+ FormatTok->is(Keywords.kw_function) &&
+ (TokenCount > 1 || (TokenCount == 1 && !Line->Tokens.front().Tok->is(
+ Keywords.kw_async)))) {
tryToParseJSFunction();
break;
}
@@ -1107,7 +1183,13 @@ void UnwrappedLineParser::parseStructuralElement() {
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
+ } else if (Style.Language == FormatStyle::LK_Proto &&
+ FormatTok->Tok.is(tok::less)) {
+ nextToken();
+ parseBracedList(/*ContinueOnSemicolons=*/false,
+ /*ClosingBraceKind=*/tok::greater);
}
break;
case tok::l_square:
@@ -1124,7 +1206,7 @@ void UnwrappedLineParser::parseStructuralElement() {
}
bool UnwrappedLineParser::tryToParseLambda() {
- if (Style.Language != FormatStyle::LK_Cpp) {
+ if (!Style.isCpp()) {
nextToken();
return false;
}
@@ -1272,13 +1354,14 @@ bool UnwrappedLineParser::tryToParseBracedList() {
assert(FormatTok->BlockKind != BK_Unknown);
if (FormatTok->BlockKind == BK_Block)
return false;
+ nextToken();
parseBracedList();
return true;
}
-bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
+bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
+ tok::TokenKind ClosingBraceKind) {
bool HasError = false;
- nextToken();
// FIXME: Once we have an expression parser in the UnwrappedLineParser,
// replace this by using parseAssigmentExpression() inside.
@@ -1298,6 +1381,16 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
continue;
}
}
+ if (FormatTok->is(tok::l_brace)) {
+ // Could be a method inside of a braced list `{a() { return 1; }}`.
+ if (tryToParseBracedList())
+ continue;
+ parseChildBlock();
+ }
+ }
+ if (FormatTok->Tok.getKind() == ClosingBraceKind) {
+ nextToken();
+ return !HasError;
}
switch (FormatTok->Tok.getKind()) {
case tok::caret:
@@ -1309,12 +1402,6 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
case tok::l_square:
tryToParseLambda();
break;
- case tok::l_brace:
- // Assume there are no blocks inside a braced init list apart
- // from the ones we explicitly parse out (like lambdas).
- FormatTok->BlockKind = BK_BracedInit;
- parseBracedList();
- break;
case tok::l_paren:
parseParens();
// JavaScript can just have free standing methods and getters/setters in
@@ -1325,9 +1412,13 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
break;
}
break;
- case tok::r_brace:
+ case tok::l_brace:
+ // Assume there are no blocks inside a braced init list apart
+ // from the ones we explicitly parse out (like lambdas).
+ FormatTok->BlockKind = BK_BracedInit;
nextToken();
- return !HasError;
+ parseBracedList();
+ break;
case tok::semi:
// JavaScript (or more precisely TypeScript) can have semicolons in braced
// lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
@@ -1378,8 +1469,16 @@ void UnwrappedLineParser::parseParens() {
break;
case tok::at:
nextToken();
- if (FormatTok->Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
+ }
+ break;
+ case tok::kw_class:
+ if (Style.Language == FormatStyle::LK_JavaScript)
+ parseRecord(/*ParseAsExpr=*/true);
+ else
+ nextToken();
break;
case tok::identifier:
if (Style.Language == FormatStyle::LK_JavaScript &&
@@ -1421,8 +1520,10 @@ void UnwrappedLineParser::parseSquare() {
}
case tok::at:
nextToken();
- if (FormatTok->Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ nextToken();
parseBracedList();
+ }
break;
default:
nextToken();
@@ -1434,6 +1535,8 @@ void UnwrappedLineParser::parseSquare() {
void UnwrappedLineParser::parseIfThenElse() {
assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected");
nextToken();
+ if (FormatTok->Tok.is(tok::kw_constexpr))
+ nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
bool NeedsUnwrappedLine = false;
@@ -1593,6 +1696,10 @@ void UnwrappedLineParser::parseForOrWhileLoop() {
assert(FormatTok->isOneOf(tok::kw_for, tok::kw_while, TT_ForEachMacro) &&
"'for', 'while' or foreach macro expected");
nextToken();
+ // JS' for await ( ...
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->is(Keywords.kw_await))
+ nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
if (FormatTok->Tok.is(tok::l_brace)) {
@@ -1722,8 +1829,7 @@ bool UnwrappedLineParser::parseEnum() {
nextToken();
// If there are two identifiers in a row, this is likely an elaborate
// return type. In Java, this can be "implements", etc.
- if (Style.Language == FormatStyle::LK_Cpp &&
- FormatTok->is(tok::identifier))
+ if (Style.isCpp() && FormatTok->is(tok::identifier))
return false;
}
}
@@ -1744,6 +1850,7 @@ bool UnwrappedLineParser::parseEnum() {
}
// Parse enum body.
+ nextToken();
bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true);
if (HasError) {
if (FormatTok->is(tok::semi))
@@ -1778,6 +1885,7 @@ void UnwrappedLineParser::parseJavaEnumBody() {
FormatTok = Tokens->setPosition(StoredPosition);
if (IsSimple) {
+ nextToken();
parseBracedList();
addUnwrappedLine();
return;
@@ -1819,7 +1927,7 @@ void UnwrappedLineParser::parseJavaEnumBody() {
addUnwrappedLine();
}
-void UnwrappedLineParser::parseRecord() {
+void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
const FormatToken &InitialToken = *FormatTok;
nextToken();
@@ -1863,11 +1971,15 @@ void UnwrappedLineParser::parseRecord() {
}
}
if (FormatTok->Tok.is(tok::l_brace)) {
- if (ShouldBreakBeforeBrace(Style, InitialToken))
- addUnwrappedLine();
+ if (ParseAsExpr) {
+ parseChildBlock();
+ } else {
+ if (ShouldBreakBeforeBrace(Style, InitialToken))
+ addUnwrappedLine();
- parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
- /*MunchSemi=*/false);
+ parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
+ /*MunchSemi=*/false);
+ }
}
// There is no addUnwrappedLine() here so that we fall through to parsing a
// structural element afterwards. Thus, in "class A {} n, m;",
@@ -1985,6 +2097,7 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
}
if (FormatTok->is(tok::l_brace)) {
FormatTok->BlockKind = BK_Block;
+ nextToken();
parseBracedList();
} else {
nextToken();
@@ -1999,7 +2112,9 @@ LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
E = Line.Tokens.end();
I != E; ++I) {
- llvm::dbgs() << I->Tok->Tok.getName() << "[" << I->Tok->Type << "] ";
+ llvm::dbgs() << I->Tok->Tok.getName() << "["
+ << "T=" << I->Tok->Type
+ << ", OC=" << I->Tok->OriginalColumn << "] ";
}
for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
E = Line.Tokens.end();
@@ -2024,6 +2139,7 @@ void UnwrappedLineParser::addUnwrappedLine() {
});
CurrentLines->push_back(std::move(*Line));
Line->Tokens.clear();
+ Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex;
if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
CurrentLines->append(
std::make_move_iterator(PreprocessorDirectives.begin()),
@@ -2039,13 +2155,130 @@ bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) {
FormatTok.NewlinesBefore > 0;
}
+// Checks if \p FormatTok is a line comment that continues the line comment
+// section on \p Line.
+static bool continuesLineCommentSection(const FormatToken &FormatTok,
+ const UnwrappedLine &Line,
+ llvm::Regex &CommentPragmasRegex) {
+ if (Line.Tokens.empty())
+ return false;
+
+ StringRef IndentContent = FormatTok.TokenText;
+ if (FormatTok.TokenText.startswith("//") ||
+ FormatTok.TokenText.startswith("/*"))
+ IndentContent = FormatTok.TokenText.substr(2);
+ if (CommentPragmasRegex.match(IndentContent))
+ return false;
+
+ // If Line starts with a line comment, then FormatTok continues the comment
+ // section if its original column is greater or equal to the original start
+ // column of the line.
+ //
+ // Define the min column token of a line as follows: if a line ends in '{' or
+ // contains a '{' followed by a line comment, then the min column token is
+ // that '{'. Otherwise, the min column token of the line is the first token of
+ // the line.
+ //
+ // If Line starts with a token other than a line comment, then FormatTok
+ // continues the comment section if its original column is greater than the
+ // original start column of the min column token of the line.
+ //
+ // For example, the second line comment continues the first in these cases:
+ //
+ // // first line
+ // // second line
+ //
+ // and:
+ //
+ // // first line
+ // // second line
+ //
+ // and:
+ //
+ // int i; // first line
+ // // second line
+ //
+ // and:
+ //
+ // do { // first line
+ // // second line
+ // int i;
+ // } while (true);
+ //
+ // and:
+ //
+ // enum {
+ // a, // first line
+ // // second line
+ // b
+ // };
+ //
+ // The second line comment doesn't continue the first in these cases:
+ //
+ // // first line
+ // // second line
+ //
+ // and:
+ //
+ // int i; // first line
+ // // second line
+ //
+ // and:
+ //
+ // do { // first line
+ // // second line
+ // int i;
+ // } while (true);
+ //
+ // and:
+ //
+ // enum {
+ // a, // first line
+ // // second line
+ // };
+ const FormatToken *MinColumnToken = Line.Tokens.front().Tok;
+
+ // Scan for '{//'. If found, use the column of '{' as a min column for line
+ // comment section continuation.
+ const FormatToken *PreviousToken = nullptr;
+ for (const UnwrappedLineNode &Node : Line.Tokens) {
+ if (PreviousToken && PreviousToken->is(tok::l_brace) &&
+ isLineComment(*Node.Tok)) {
+ MinColumnToken = PreviousToken;
+ break;
+ }
+ PreviousToken = Node.Tok;
+
+ // Grab the last newline preceding a token in this unwrapped line.
+ if (Node.Tok->NewlinesBefore > 0) {
+ MinColumnToken = Node.Tok;
+ }
+ }
+ if (PreviousToken && PreviousToken->is(tok::l_brace)) {
+ MinColumnToken = PreviousToken;
+ }
+
+ return continuesLineComment(FormatTok, /*Previous=*/Line.Tokens.back().Tok,
+ MinColumnToken);
+}
+
void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
bool JustComments = Line->Tokens.empty();
for (SmallVectorImpl<FormatToken *>::const_iterator
I = CommentsBeforeNextToken.begin(),
E = CommentsBeforeNextToken.end();
I != E; ++I) {
- if (isOnNewLine(**I) && JustComments)
+ // Line comments that belong to the same line comment section are put on the
+ // same line since later we might want to reflow content between them.
+ // Additional fine-grained breaking of line comment sections is controlled
+ // by the class BreakableLineCommentSection in case it is desirable to keep
+ // several line comment sections in the same unwrapped line.
+ //
+ // FIXME: Consider putting separate line comment sections as children to the
+ // unwrapped line instead.
+ (*I)->ContinuesLineCommentSection =
+ continuesLineCommentSection(**I, *Line, CommentPragmasRegex);
+ if (isOnNewLine(**I) && JustComments && !(*I)->ContinuesLineCommentSection)
addUnwrappedLine();
pushToken(*I);
}
@@ -2073,13 +2306,71 @@ const FormatToken *UnwrappedLineParser::getPreviousToken() {
return Line->Tokens.back().Tok;
}
+void UnwrappedLineParser::distributeComments(
+ const SmallVectorImpl<FormatToken *> &Comments,
+ const FormatToken *NextTok) {
+ // Whether or not a line comment token continues a line is controlled by
+ // the method continuesLineCommentSection, with the following caveat:
+ //
+ // Define a trail of Comments to be a nonempty proper postfix of Comments such
+ // that each comment line from the trail is aligned with the next token, if
+ // the next token exists. If a trail exists, the beginning of the maximal
+ // trail is marked as a start of a new comment section.
+ //
+ // For example in this code:
+ //
+ // int a; // line about a
+ // // line 1 about b
+ // // line 2 about b
+ // int b;
+ //
+ // the two lines about b form a maximal trail, so there are two sections, the
+ // first one consisting of the single comment "// line about a" and the
+ // second one consisting of the next two comments.
+ if (Comments.empty())
+ return;
+ bool ShouldPushCommentsInCurrentLine = true;
+ bool HasTrailAlignedWithNextToken = false;
+ unsigned StartOfTrailAlignedWithNextToken = 0;
+ if (NextTok) {
+ // We are skipping the first element intentionally.
+ for (unsigned i = Comments.size() - 1; i > 0; --i) {
+ if (Comments[i]->OriginalColumn == NextTok->OriginalColumn) {
+ HasTrailAlignedWithNextToken = true;
+ StartOfTrailAlignedWithNextToken = i;
+ }
+ }
+ }
+ for (unsigned i = 0, e = Comments.size(); i < e; ++i) {
+ FormatToken *FormatTok = Comments[i];
+ if (HasTrailAlignedWithNextToken &&
+ i == StartOfTrailAlignedWithNextToken) {
+ FormatTok->ContinuesLineCommentSection = false;
+ } else {
+ FormatTok->ContinuesLineCommentSection =
+ continuesLineCommentSection(*FormatTok, *Line, CommentPragmasRegex);
+ }
+ if (!FormatTok->ContinuesLineCommentSection &&
+ (isOnNewLine(*FormatTok) || FormatTok->IsFirst)) {
+ ShouldPushCommentsInCurrentLine = false;
+ }
+ if (ShouldPushCommentsInCurrentLine) {
+ pushToken(FormatTok);
+ } else {
+ CommentsBeforeNextToken.push_back(FormatTok);
+ }
+ }
+}
+
void UnwrappedLineParser::readToken() {
- bool CommentsInCurrentLine = true;
+ SmallVector<FormatToken *, 1> Comments;
do {
FormatTok = Tokens->getNextToken();
assert(FormatTok);
while (!Line->InPPDirective && FormatTok->Tok.is(tok::hash) &&
(FormatTok->HasUnescapedNewline || FormatTok->IsFirst)) {
+ distributeComments(Comments, FormatTok);
+ Comments.clear();
// If there is an unfinished unwrapped line, we flush the preprocessor
// directives only after that unwrapped line was finished later.
bool SwitchToPreprocessorLines = !Line->Tokens.empty();
@@ -2109,17 +2400,17 @@ void UnwrappedLineParser::readToken() {
continue;
}
- if (!FormatTok->Tok.is(tok::comment))
+ if (!FormatTok->Tok.is(tok::comment)) {
+ distributeComments(Comments, FormatTok);
+ Comments.clear();
return;
- if (isOnNewLine(*FormatTok) || FormatTok->IsFirst) {
- CommentsInCurrentLine = false;
- }
- if (CommentsInCurrentLine) {
- pushToken(FormatTok);
- } else {
- CommentsBeforeNextToken.push_back(FormatTok);
}
+
+ Comments.push_back(FormatTok);
} while (!eof());
+
+ distributeComments(Comments, nullptr);
+ Comments.clear();
}
void UnwrappedLineParser::pushToken(FormatToken *Tok) {
diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.h b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.h
index 9c78d33..a2aa2f0 100644
--- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.h
+++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.h
@@ -19,6 +19,7 @@
#include "FormatToken.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Format/Format.h"
+#include "llvm/Support/Regex.h"
#include <list>
#include <stack>
@@ -47,6 +48,14 @@ struct UnwrappedLine {
bool InPPDirective;
bool MustBeDeclaration;
+
+ /// \brief If this \c UnwrappedLine closes a block in a sequence of lines,
+ /// \c MatchingOpeningBlockLineIndex stores the index of the corresponding
+ /// opening line. Otherwise, \c MatchingOpeningBlockLineIndex must be
+ /// \c kInvalidIndex.
+ size_t MatchingOpeningBlockLineIndex;
+
+ static const size_t kInvalidIndex = -1;
};
class UnwrappedLineConsumer {
@@ -84,7 +93,8 @@ private:
void readTokenWithJavaScriptASI();
void parseStructuralElement();
bool tryToParseBracedList();
- bool parseBracedList(bool ContinueOnSemicolons = false);
+ bool parseBracedList(bool ContinueOnSemicolons = false,
+ tok::TokenKind ClosingBraceKind = tok::r_brace);
void parseParens();
void parseSquare();
void parseIfThenElse();
@@ -99,7 +109,10 @@ private:
void parseAccessSpecifier();
bool parseEnum();
void parseJavaEnumBody();
- void parseRecord();
+ // Parses a record (aka class) as a top level element. If ParseAsExpr is true,
+ // parses the record as a child block, i.e. if the class declaration is an
+ // expression.
+ void parseRecord(bool ParseAsExpr = false);
void parseObjCProtocolList();
void parseObjCUntilAtEnd();
void parseObjCInterfaceOrImplementation();
@@ -113,6 +126,21 @@ private:
void nextToken();
const FormatToken *getPreviousToken();
void readToken();
+
+ // Decides which comment tokens should be added to the current line and which
+ // should be added as comments before the next token.
+ //
+ // Comments specifies the sequence of comment tokens to analyze. They get
+ // either pushed to the current line or added to the comments before the next
+ // token.
+ //
+ // NextTok specifies the next token. A null pointer NextTok is supported, and
+ // signifies either the absense of a next token, or that the next token
+ // shouldn't be taken into accunt for the analysis.
+ void distributeComments(const SmallVectorImpl<FormatToken *> &Comments,
+ const FormatToken *NextTok);
+
+ // Adds the comment preceding the next token to unwrapped lines.
void flushComments(bool NewlineBeforeNext);
void pushToken(FormatToken *Tok);
void calculateBraceTypes(bool ExpectClassBody = false);
@@ -162,6 +190,8 @@ private:
const FormatStyle &Style;
const AdditionalKeywords &Keywords;
+ llvm::Regex CommentPragmasRegex;
+
FormatTokenSource *Tokens;
UnwrappedLineConsumer &Callback;
@@ -213,8 +243,8 @@ struct UnwrappedLineNode {
SmallVector<UnwrappedLine, 0> Children;
};
-inline UnwrappedLine::UnwrappedLine()
- : Level(0), InPPDirective(false), MustBeDeclaration(false) {}
+inline UnwrappedLine::UnwrappedLine() : Level(0), InPPDirective(false),
+ MustBeDeclaration(false), MatchingOpeningBlockLineIndex(kInvalidIndex) {}
} // end namespace format
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp
new file mode 100644
index 0000000..fb4f59f
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp
@@ -0,0 +1,144 @@
+//===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements UsingDeclarationsSorter, a TokenAnalyzer that
+/// sorts consecutive using declarations.
+///
+//===----------------------------------------------------------------------===//
+
+#include "UsingDeclarationsSorter.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Regex.h"
+
+#include <algorithm>
+
+#define DEBUG_TYPE "using-declarations-sorter"
+
+namespace clang {
+namespace format {
+
+namespace {
+
+struct UsingDeclaration {
+ const AnnotatedLine *Line;
+ std::string Label;
+
+ UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
+ : Line(Line), Label(Label) {}
+
+ bool operator<(const UsingDeclaration &Other) const {
+ return Label < Other.Label;
+ }
+};
+
+/// Computes the label of a using declaration starting at tthe using token
+/// \p UsingTok.
+/// If \p UsingTok doesn't begin a using declaration, returns the empty string.
+/// Note that this detects specifically using declarations, as in:
+/// using A::B::C;
+/// and not type aliases, as in:
+/// using A = B::C;
+/// Type aliases are in general not safe to permute.
+std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
+ assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
+ std::string Label;
+ const FormatToken *Tok = UsingTok->Next;
+ if (Tok && Tok->is(tok::kw_typename)) {
+ Label.append("typename ");
+ Tok = Tok->Next;
+ }
+ if (Tok && Tok->is(tok::coloncolon)) {
+ Label.append("::");
+ Tok = Tok->Next;
+ }
+ bool HasIdentifier = false;
+ while (Tok && Tok->is(tok::identifier)) {
+ HasIdentifier = true;
+ Label.append(Tok->TokenText.str());
+ Tok = Tok->Next;
+ if (!Tok || Tok->isNot(tok::coloncolon))
+ break;
+ Label.append("::");
+ Tok = Tok->Next;
+ }
+ if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
+ return Label;
+ return "";
+}
+
+void endUsingDeclarationBlock(
+ SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
+ const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
+ SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
+ UsingDeclarations->begin(), UsingDeclarations->end());
+ std::sort(SortedUsingDeclarations.begin(), SortedUsingDeclarations.end());
+ for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
+ if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
+ continue;
+ auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
+ auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
+ auto SortedBegin =
+ SortedUsingDeclarations[I].Line->First->Tok.getLocation();
+ auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
+ StringRef Text(SourceMgr.getCharacterData(SortedBegin),
+ SourceMgr.getCharacterData(SortedEnd) -
+ SourceMgr.getCharacterData(SortedBegin));
+ DEBUG({
+ StringRef OldText(SourceMgr.getCharacterData(Begin),
+ SourceMgr.getCharacterData(End) -
+ SourceMgr.getCharacterData(Begin));
+ llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
+ });
+ auto Range = CharSourceRange::getCharRange(Begin, End);
+ auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
+ if (Err) {
+ llvm::errs() << "Error while sorting using declarations: "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+ }
+ UsingDeclarations->clear();
+}
+
+} // namespace
+
+UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
+ const FormatStyle &Style)
+ : TokenAnalyzer(Env, Style) {}
+
+tooling::Replacements UsingDeclarationsSorter::analyze(
+ TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) {
+ const SourceManager &SourceMgr = Env.getSourceManager();
+ AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
+ AnnotatedLines.end());
+ tooling::Replacements Fixes;
+ SmallVector<UsingDeclaration, 4> UsingDeclarations;
+ for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
+ if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective ||
+ !AnnotatedLines[I]->startsWith(tok::kw_using) ||
+ AnnotatedLines[I]->First->Finalized) {
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ continue;
+ }
+ if (AnnotatedLines[I]->First->NewlinesBefore > 1)
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First);
+ if (Label.empty()) {
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ continue;
+ }
+ UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
+ }
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ return Fixes;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h
new file mode 100644
index 0000000..f7d5f97
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h
@@ -0,0 +1,37 @@
+//===--- UsingDeclarationsSorter.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file declares UsingDeclarationsSorter, a TokenAnalyzer that
+/// sorts consecutive using declarations.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_USINGDECLARATIONSSORTER_H
+#define LLVM_CLANG_LIB_FORMAT_USINGDECLARATIONSSORTER_H
+
+#include "TokenAnalyzer.h"
+
+namespace clang {
+namespace format {
+
+class UsingDeclarationsSorter : public TokenAnalyzer {
+public:
+ UsingDeclarationsSorter(const Environment &Env, const FormatStyle &Style);
+
+ tooling::Replacements
+ analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) override;
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif
diff --git a/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp b/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp
index b64506f..377ec3a 100644
--- a/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp
+++ b/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp
@@ -25,64 +25,60 @@ operator()(const Change &C1, const Change &C2) const {
C2.OriginalWhitespaceRange.getBegin());
}
-WhitespaceManager::Change::Change(
- bool CreateReplacement, SourceRange OriginalWhitespaceRange,
- unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
- unsigned NewlinesBefore, StringRef PreviousLinePostfix,
- StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective,
- bool IsStartOfDeclName, bool IsInsideToken)
- : CreateReplacement(CreateReplacement),
+WhitespaceManager::Change::Change(const FormatToken &Tok,
+ bool CreateReplacement,
+ SourceRange OriginalWhitespaceRange,
+ int Spaces, unsigned StartOfTokenColumn,
+ unsigned NewlinesBefore,
+ StringRef PreviousLinePostfix,
+ StringRef CurrentLinePrefix,
+ bool ContinuesPPDirective, bool IsInsideToken)
+ : Tok(&Tok), CreateReplacement(CreateReplacement),
OriginalWhitespaceRange(OriginalWhitespaceRange),
StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
PreviousLinePostfix(PreviousLinePostfix),
- CurrentLinePrefix(CurrentLinePrefix), Kind(Kind),
- ContinuesPPDirective(ContinuesPPDirective),
- IsStartOfDeclName(IsStartOfDeclName), IndentLevel(IndentLevel),
- Spaces(Spaces), IsInsideToken(IsInsideToken), IsTrailingComment(false),
- TokenLength(0), PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
+ CurrentLinePrefix(CurrentLinePrefix),
+ ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
+ IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0),
+ PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
StartOfBlockComment(nullptr), IndentationOffset(0) {}
void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
- unsigned IndentLevel, unsigned Spaces,
+ unsigned Spaces,
unsigned StartOfTokenColumn,
bool InPPDirective) {
if (Tok.Finalized)
return;
Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
- Changes.push_back(
- Change(/*CreateReplacement=*/true, Tok.WhitespaceRange, IndentLevel,
- Spaces, StartOfTokenColumn, Newlines, "", "", Tok.Tok.getKind(),
- InPPDirective && !Tok.IsFirst,
- Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
- /*IsInsideToken=*/false));
+ Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange,
+ Spaces, StartOfTokenColumn, Newlines, "", "",
+ InPPDirective && !Tok.IsFirst,
+ /*IsInsideToken=*/false));
}
void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
bool InPPDirective) {
if (Tok.Finalized)
return;
- Changes.push_back(Change(
- /*CreateReplacement=*/false, Tok.WhitespaceRange, /*IndentLevel=*/0,
- /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
- Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst,
- Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
- /*IsInsideToken=*/false));
+ Changes.push_back(Change(Tok, /*CreateReplacement=*/false,
+ Tok.WhitespaceRange, /*Spaces=*/0,
+ Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
+ InPPDirective && !Tok.IsFirst,
+ /*IsInsideToken=*/false));
}
void WhitespaceManager::replaceWhitespaceInToken(
const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
- unsigned Newlines, unsigned IndentLevel, int Spaces) {
+ unsigned Newlines, int Spaces) {
if (Tok.Finalized)
return;
SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
- Changes.push_back(Change(
- true, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)),
- IndentLevel, Spaces, std::max(0, Spaces), Newlines, PreviousPostfix,
- CurrentPrefix, Tok.is(TT_LineComment) ? tok::comment : tok::unknown,
- InPPDirective && !Tok.IsFirst,
- Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
- /*IsInsideToken=*/Newlines == 0));
+ Changes.push_back(
+ Change(Tok, /*CreateReplacement=*/true,
+ SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces,
+ std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
+ InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/true));
}
const tooling::Replacements &WhitespaceManager::generateReplacements() {
@@ -104,18 +100,56 @@ void WhitespaceManager::calculateLineBreakInformation() {
Changes[0].PreviousEndOfTokenColumn = 0;
Change *LastOutsideTokenChange = &Changes[0];
for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
- unsigned OriginalWhitespaceStart =
- SourceMgr.getFileOffset(Changes[i].OriginalWhitespaceRange.getBegin());
- unsigned PreviousOriginalWhitespaceEnd = SourceMgr.getFileOffset(
- Changes[i - 1].OriginalWhitespaceRange.getEnd());
- Changes[i - 1].TokenLength = OriginalWhitespaceStart -
- PreviousOriginalWhitespaceEnd +
- Changes[i].PreviousLinePostfix.size() +
- Changes[i - 1].CurrentLinePrefix.size();
+ SourceLocation OriginalWhitespaceStart =
+ Changes[i].OriginalWhitespaceRange.getBegin();
+ SourceLocation PreviousOriginalWhitespaceEnd =
+ Changes[i - 1].OriginalWhitespaceRange.getEnd();
+ unsigned OriginalWhitespaceStartOffset =
+ SourceMgr.getFileOffset(OriginalWhitespaceStart);
+ unsigned PreviousOriginalWhitespaceEndOffset =
+ SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);
+ assert(PreviousOriginalWhitespaceEndOffset <=
+ OriginalWhitespaceStartOffset);
+ const char *const PreviousOriginalWhitespaceEndData =
+ SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd);
+ StringRef Text(PreviousOriginalWhitespaceEndData,
+ SourceMgr.getCharacterData(OriginalWhitespaceStart) -
+ PreviousOriginalWhitespaceEndData);
+ // Usually consecutive changes would occur in consecutive tokens. This is
+ // not the case however when analyzing some preprocessor runs of the
+ // annotated lines. For example, in this code:
+ //
+ // #if A // line 1
+ // int i = 1;
+ // #else B // line 2
+ // int i = 2;
+ // #endif // line 3
+ //
+ // one of the runs will produce the sequence of lines marked with line 1, 2
+ // and 3. So the two consecutive whitespace changes just before '// line 2'
+ // and before '#endif // line 3' span multiple lines and tokens:
+ //
+ // #else B{change X}[// line 2
+ // int i = 2;
+ // ]{change Y}#endif // line 3
+ //
+ // For this reason, if the text between consecutive changes spans multiple
+ // newlines, the token length must be adjusted to the end of the original
+ // line of the token.
+ auto NewlinePos = Text.find_first_of('\n');
+ if (NewlinePos == StringRef::npos) {
+ Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset -
+ PreviousOriginalWhitespaceEndOffset +
+ Changes[i].PreviousLinePostfix.size() +
+ Changes[i - 1].CurrentLinePrefix.size();
+ } else {
+ Changes[i - 1].TokenLength =
+ NewlinePos + Changes[i - 1].CurrentLinePrefix.size();
+ }
// If there are multiple changes in this token, sum up all the changes until
// the end of the line.
- if (Changes[i - 1].IsInsideToken)
+ if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0)
LastOutsideTokenChange->TokenLength +=
Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
else
@@ -125,30 +159,64 @@ void WhitespaceManager::calculateLineBreakInformation() {
Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
Changes[i - 1].IsTrailingComment =
- (Changes[i].NewlinesBefore > 0 || Changes[i].Kind == tok::eof ||
- (Changes[i].IsInsideToken && Changes[i].Kind == tok::comment)) &&
- Changes[i - 1].Kind == tok::comment;
+ (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) ||
+ (Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) &&
+ Changes[i - 1].Tok->is(tok::comment) &&
+ // FIXME: This is a dirty hack. The problem is that
+ // BreakableLineCommentSection does comment reflow changes and here is
+ // the aligning of trailing comments. Consider the case where we reflow
+ // the second line up in this example:
+ //
+ // // line 1
+ // // line 2
+ //
+ // That amounts to 2 changes by BreakableLineCommentSection:
+ // - the first, delimited by (), for the whitespace between the tokens,
+ // - and second, delimited by [], for the whitespace at the beginning
+ // of the second token:
+ //
+ // // line 1(
+ // )[// ]line 2
+ //
+ // So in the end we have two changes like this:
+ //
+ // // line1()[ ]line 2
+ //
+ // Note that the OriginalWhitespaceStart of the second change is the
+ // same as the PreviousOriginalWhitespaceEnd of the first change.
+ // In this case, the below check ensures that the second change doesn't
+ // get treated as a trailing comment change here, since this might
+ // trigger additional whitespace to be wrongly inserted before "line 2"
+ // by the comment aligner here.
+ //
+ // For a proper solution we need a mechanism to say to WhitespaceManager
+ // that a particular change breaks the current sequence of trailing
+ // comments.
+ OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd;
}
// FIXME: The last token is currently not always an eof token; in those
// cases, setting TokenLength of the last token to 0 is wrong.
Changes.back().TokenLength = 0;
- Changes.back().IsTrailingComment = Changes.back().Kind == tok::comment;
+ Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
const WhitespaceManager::Change *LastBlockComment = nullptr;
for (auto &Change : Changes) {
// Reset the IsTrailingComment flag for changes inside of trailing comments
- // so they don't get realigned later.
- if (Change.IsInsideToken)
+ // so they don't get realigned later. Comment line breaks however still need
+ // to be aligned.
+ if (Change.IsInsideToken && Change.NewlinesBefore == 0)
Change.IsTrailingComment = false;
Change.StartOfBlockComment = nullptr;
Change.IndentationOffset = 0;
- if (Change.Kind == tok::comment) {
- LastBlockComment = &Change;
- } else if (Change.Kind == tok::unknown) {
- if ((Change.StartOfBlockComment = LastBlockComment))
- Change.IndentationOffset =
- Change.StartOfTokenColumn -
- Change.StartOfBlockComment->StartOfTokenColumn;
+ if (Change.Tok->is(tok::comment)) {
+ if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken)
+ LastBlockComment = &Change;
+ else {
+ if ((Change.StartOfBlockComment = LastBlockComment))
+ Change.IndentationOffset =
+ Change.StartOfTokenColumn -
+ Change.StartOfBlockComment->StartOfTokenColumn;
+ }
} else {
LastBlockComment = nullptr;
}
@@ -162,21 +230,56 @@ AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
SmallVector<WhitespaceManager::Change, 16> &Changes) {
bool FoundMatchOnLine = false;
int Shift = 0;
+
+ // ScopeStack keeps track of the current scope depth. It contains indices of
+ // the first token on each scope.
+ // We only run the "Matches" function on tokens from the outer-most scope.
+ // However, we do need to pay special attention to one class of tokens
+ // that are not in the outer-most scope, and that is function parameters
+ // which are split across multiple lines, as illustrated by this example:
+ // double a(int x);
+ // int b(int y,
+ // double z);
+ // In the above example, we need to take special care to ensure that
+ // 'double z' is indented along with it's owning function 'b'.
+ SmallVector<unsigned, 16> ScopeStack;
+
for (unsigned i = Start; i != End; ++i) {
- if (Changes[i].NewlinesBefore > 0) {
- FoundMatchOnLine = false;
+ if (ScopeStack.size() != 0 &&
+ Changes[i].indentAndNestingLevel() <
+ Changes[ScopeStack.back()].indentAndNestingLevel())
+ ScopeStack.pop_back();
+
+ if (i != Start && Changes[i].indentAndNestingLevel() >
+ Changes[i - 1].indentAndNestingLevel())
+ ScopeStack.push_back(i);
+
+ bool InsideNestedScope = ScopeStack.size() != 0;
+
+ if (Changes[i].NewlinesBefore > 0 && !InsideNestedScope) {
Shift = 0;
+ FoundMatchOnLine = false;
}
// If this is the first matching token to be aligned, remember by how many
// spaces it has to be shifted, so the rest of the changes on the line are
// shifted by the same amount
- if (!FoundMatchOnLine && Matches(Changes[i])) {
+ if (!FoundMatchOnLine && !InsideNestedScope && Matches(Changes[i])) {
FoundMatchOnLine = true;
Shift = Column - Changes[i].StartOfTokenColumn;
Changes[i].Spaces += Shift;
}
+ // This is for function parameters that are split across multiple lines,
+ // as mentioned in the ScopeStack comment.
+ if (InsideNestedScope && Changes[i].NewlinesBefore > 0) {
+ unsigned ScopeStart = ScopeStack.back();
+ if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
+ (ScopeStart > Start + 1 &&
+ Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)))
+ Changes[i].Spaces += Shift;
+ }
+
assert(Shift >= 0);
Changes[i].StartOfTokenColumn += Shift;
if (i + 1 != Changes.size())
@@ -184,15 +287,37 @@ AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
}
}
-// Walk through all of the changes and find sequences of matching tokens to
-// align. To do so, keep track of the lines and whether or not a matching token
-// was found on a line. If a matching token is found, extend the current
-// sequence. If the current line cannot be part of a sequence, e.g. because
-// there is an empty line before it or it contains only non-matching tokens,
-// finalize the previous sequence.
+// Walk through a subset of the changes, starting at StartAt, and find
+// sequences of matching tokens to align. To do so, keep track of the lines and
+// whether or not a matching token was found on a line. If a matching token is
+// found, extend the current sequence. If the current line cannot be part of a
+// sequence, e.g. because there is an empty line before it or it contains only
+// non-matching tokens, finalize the previous sequence.
+// The value returned is the token on which we stopped, either because we
+// exhausted all items inside Changes, or because we hit a scope level higher
+// than our initial scope.
+// This function is recursive. Each invocation processes only the scope level
+// equal to the initial level, which is the level of Changes[StartAt].
+// If we encounter a scope level greater than the initial level, then we call
+// ourselves recursively, thereby avoiding the pollution of the current state
+// with the alignment requirements of the nested sub-level. This recursive
+// behavior is necessary for aligning function prototypes that have one or more
+// arguments.
+// If this function encounters a scope level less than the initial level,
+// it returns the current position.
+// There is a non-obvious subtlety in the recursive behavior: Even though we
+// defer processing of nested levels to recursive invocations of this
+// function, when it comes time to align a sequence of tokens, we run the
+// alignment on the entire sequence, including the nested levels.
+// When doing so, most of the nested tokens are skipped, because their
+// alignment was already handled by the recursive invocations of this function.
+// However, the special exception is that we do NOT skip function parameters
+// that are split across multiple lines. See the test case in FormatTest.cpp
+// that mentions "split function parameter alignment" for an example of this.
template <typename F>
-static void AlignTokens(const FormatStyle &Style, F &&Matches,
- SmallVector<WhitespaceManager::Change, 16> &Changes) {
+static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
+ SmallVector<WhitespaceManager::Change, 16> &Changes,
+ unsigned StartAt) {
unsigned MinColumn = 0;
unsigned MaxColumn = UINT_MAX;
@@ -200,14 +325,11 @@ static void AlignTokens(const FormatStyle &Style, F &&Matches,
unsigned StartOfSequence = 0;
unsigned EndOfSequence = 0;
- // Keep track of the nesting level of matching tokens, i.e. the number of
- // surrounding (), [], or {}. We will only align a sequence of matching
- // token that share the same scope depth.
- //
- // FIXME: This could use FormatToken::NestingLevel information, but there is
- // an outstanding issue wrt the brace scopes.
- unsigned NestingLevelOfLastMatch = 0;
- unsigned NestingLevel = 0;
+ // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
+ // abort when we hit any token in a higher scope than the starting one.
+ auto IndentAndNestingLevel = StartAt < Changes.size()
+ ? Changes[StartAt].indentAndNestingLevel()
+ : std::pair<unsigned, unsigned>(0, 0);
// Keep track of the number of commas before the matching tokens, we will only
// align a sequence of matching tokens if they are preceded by the same number
@@ -235,7 +357,11 @@ static void AlignTokens(const FormatStyle &Style, F &&Matches,
EndOfSequence = 0;
};
- for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
+ unsigned i = StartAt;
+ for (unsigned e = Changes.size(); i != e; ++i) {
+ if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
+ break;
+
if (Changes[i].NewlinesBefore != 0) {
CommasBeforeMatch = 0;
EndOfSequence = i;
@@ -247,33 +373,24 @@ static void AlignTokens(const FormatStyle &Style, F &&Matches,
FoundMatchOnLine = false;
}
- if (Changes[i].Kind == tok::comma) {
+ if (Changes[i].Tok->is(tok::comma)) {
++CommasBeforeMatch;
- } else if (Changes[i].Kind == tok::r_brace ||
- Changes[i].Kind == tok::r_paren ||
- Changes[i].Kind == tok::r_square) {
- --NestingLevel;
- } else if (Changes[i].Kind == tok::l_brace ||
- Changes[i].Kind == tok::l_paren ||
- Changes[i].Kind == tok::l_square) {
- // We want sequences to skip over child scopes if possible, but not the
- // other way around.
- NestingLevelOfLastMatch = std::min(NestingLevelOfLastMatch, NestingLevel);
- ++NestingLevel;
+ } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
+ // Call AlignTokens recursively, skipping over this scope block.
+ unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
+ i = StoppedAt - 1;
+ continue;
}
if (!Matches(Changes[i]))
continue;
// If there is more than one matching token per line, or if the number of
- // preceding commas, or the scope depth, do not match anymore, end the
- // sequence.
- if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch ||
- NestingLevel != NestingLevelOfLastMatch)
+ // preceding commas, do not match anymore, end the sequence.
+ if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
AlignCurrentSequence();
CommasBeforeLastMatch = CommasBeforeMatch;
- NestingLevelOfLastMatch = NestingLevel;
FoundMatchOnLine = true;
if (StartOfSequence == 0)
@@ -296,8 +413,9 @@ static void AlignTokens(const FormatStyle &Style, F &&Matches,
MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
}
- EndOfSequence = Changes.size();
+ EndOfSequence = i;
AlignCurrentSequence();
+ return i;
}
void WhitespaceManager::alignConsecutiveAssignments() {
@@ -314,9 +432,9 @@ void WhitespaceManager::alignConsecutiveAssignments() {
if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
return false;
- return C.Kind == tok::equal;
+ return C.Tok->is(tok::equal);
},
- Changes);
+ Changes, /*StartAt=*/0);
}
void WhitespaceManager::alignConsecutiveDeclarations() {
@@ -329,9 +447,15 @@ void WhitespaceManager::alignConsecutiveDeclarations() {
// const char* const* v1;
// float const* v2;
// SomeVeryLongType const& v3;
-
- AlignTokens(Style, [](Change const &C) { return C.IsStartOfDeclName; },
- Changes);
+ AlignTokens(Style,
+ [](Change const &C) {
+ // tok::kw_operator is necessary for aligning operator overload
+ // definitions.
+ return C.Tok->is(TT_StartOfName) ||
+ C.Tok->is(TT_FunctionDeclarationName) ||
+ C.Tok->is(tok::kw_operator);
+ },
+ Changes, /*StartAt=*/0);
}
void WhitespaceManager::alignTrailingComments() {
@@ -348,7 +472,14 @@ void WhitespaceManager::alignTrailingComments() {
continue;
unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
- unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
+ unsigned ChangeMaxColumn;
+
+ if (Style.ColumnLimit == 0)
+ ChangeMaxColumn = UINT_MAX;
+ else if (Style.ColumnLimit >= Changes[i].TokenLength)
+ ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
+ else
+ ChangeMaxColumn = ChangeMinColumn;
// If we don't create a replacement for this change, we have to consider
// it to be immovable.
@@ -360,17 +491,14 @@ void WhitespaceManager::alignTrailingComments() {
// If this comment follows an } in column 0, it probably documents the
// closing of a namespace and we don't want to align it.
bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
- Changes[i - 1].Kind == tok::r_brace &&
+ Changes[i - 1].Tok->is(tok::r_brace) &&
Changes[i - 1].StartOfTokenColumn == 0;
bool WasAlignedWithStartOfNextLine = false;
if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
Changes[i].OriginalWhitespaceRange.getEnd());
for (unsigned j = i + 1; j != e; ++j) {
- if (Changes[j].Kind == tok::comment ||
- Changes[j].Kind == tok::unknown)
- // Skip over comments and unknown tokens. "unknown tokens are used for
- // the continuation of multiline comments.
+ if (Changes[j].Tok->is(tok::comment))
continue;
unsigned NextColumn = SourceMgr.getSpellingColumnNumber(
@@ -434,8 +562,11 @@ void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
}
void WhitespaceManager::alignEscapedNewlines() {
- unsigned MaxEndOfLine =
- Style.AlignEscapedNewlinesLeft ? 0 : Style.ColumnLimit;
+ if (Style.AlignEscapedNewlines == FormatStyle::ENAS_DontAlign)
+ return;
+
+ bool AlignLeft = Style.AlignEscapedNewlines == FormatStyle::ENAS_Left;
+ unsigned MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
unsigned StartOfMacro = 0;
for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
Change &C = Changes[i];
@@ -444,7 +575,7 @@ void WhitespaceManager::alignEscapedNewlines() {
MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
} else {
alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
- MaxEndOfLine = Style.AlignEscapedNewlinesLeft ? 0 : Style.ColumnLimit;
+ MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
StartOfMacro = i;
}
}
@@ -481,7 +612,8 @@ void WhitespaceManager::generateChanges() {
C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
else
appendNewlineText(ReplacementText, C.NewlinesBefore);
- appendIndentText(ReplacementText, C.IndentLevel, std::max(0, C.Spaces),
+ appendIndentText(ReplacementText, C.Tok->IndentLevel,
+ std::max(0, C.Spaces),
C.StartOfTokenColumn - std::max(0, C.Spaces));
ReplacementText.append(C.CurrentLinePrefix);
storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
@@ -518,7 +650,7 @@ void WhitespaceManager::appendNewlineText(std::string &Text, unsigned Newlines,
unsigned EscapedNewlineColumn) {
if (Newlines > 0) {
unsigned Offset =
- std::min<int>(EscapedNewlineColumn - 1, PreviousEndOfTokenColumn);
+ std::min<int>(EscapedNewlineColumn - 2, PreviousEndOfTokenColumn);
for (unsigned i = 0; i < Newlines; ++i) {
Text.append(EscapedNewlineColumn - Offset - 1, ' ');
Text.append(UseCRLF ? "\\\r\n" : "\\\n");
diff --git a/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.h b/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.h
index f42e371..4e78ab4 100644
--- a/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.h
+++ b/contrib/llvm/tools/clang/lib/Format/WhitespaceManager.h
@@ -43,8 +43,11 @@ public:
/// \brief Replaces the whitespace in front of \p Tok. Only call once for
/// each \c AnnotatedToken.
- void replaceWhitespace(FormatToken &Tok, unsigned Newlines,
- unsigned IndentLevel, unsigned Spaces,
+ ///
+ /// \p StartOfTokenColumn is the column at which the token will start after
+ /// this replacement. It is needed for determining how \p Spaces is turned
+ /// into tabs and spaces for some format styles.
+ void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces,
unsigned StartOfTokenColumn,
bool InPPDirective = false);
@@ -72,8 +75,7 @@ public:
unsigned ReplaceChars,
StringRef PreviousPostfix,
StringRef CurrentPrefix, bool InPPDirective,
- unsigned Newlines, unsigned IndentLevel,
- int Spaces);
+ unsigned Newlines, int Spaces);
/// \brief Returns all the \c Replacements created during formatting.
const tooling::Replacements &generateReplacements();
@@ -91,8 +93,6 @@ public:
const SourceManager &SourceMgr;
};
- Change() {}
-
/// \brief Creates a \c Change.
///
/// The generated \c Change will replace the characters at
@@ -102,12 +102,17 @@ public:
///
/// \p StartOfTokenColumn and \p InPPDirective will be used to lay out
/// trailing comments and escaped newlines.
- Change(bool CreateReplacement, SourceRange OriginalWhitespaceRange,
- unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
- unsigned NewlinesBefore, StringRef PreviousLinePostfix,
- StringRef CurrentLinePrefix, tok::TokenKind Kind,
- bool ContinuesPPDirective, bool IsStartOfDeclName,
- bool IsInsideToken);
+ Change(const FormatToken &Tok, bool CreateReplacement,
+ SourceRange OriginalWhitespaceRange, int Spaces,
+ unsigned StartOfTokenColumn, unsigned NewlinesBefore,
+ StringRef PreviousLinePostfix, StringRef CurrentLinePrefix,
+ bool ContinuesPPDirective, bool IsInsideToken);
+
+ // The kind of the token whose whitespace this change replaces, or in which
+ // this change inserts whitespace.
+ // FIXME: Currently this is not set correctly for breaks inside comments, as
+ // the \c BreakableToken is still doing its own alignment.
+ const FormatToken *Tok;
bool CreateReplacement;
// Changes might be in the middle of a token, so we cannot just keep the
@@ -117,18 +122,7 @@ public:
unsigned NewlinesBefore;
std::string PreviousLinePostfix;
std::string CurrentLinePrefix;
- // The kind of the token whose whitespace this change replaces, or in which
- // this change inserts whitespace.
- // FIXME: Currently this is not set correctly for breaks inside comments, as
- // the \c BreakableToken is still doing its own alignment.
- tok::TokenKind Kind;
bool ContinuesPPDirective;
- bool IsStartOfDeclName;
-
- // The number of nested blocks the token is in. This is used to add tabs
- // only for the indentation, and not for alignment, when
- // UseTab = US_ForIndentation.
- unsigned IndentLevel;
// The number of spaces in front of the token or broken part of the token.
// This will be adapted when aligning tokens.
@@ -159,6 +153,13 @@ public:
// the alignment process.
const Change *StartOfBlockComment;
int IndentationOffset;
+
+ // A combination of indent level and nesting level, which are used in
+ // tandem to compute lexical scope, for the purposes of deciding
+ // when to stop consecutive alignment runs.
+ std::pair<unsigned, unsigned> indentAndNestingLevel() const {
+ return std::make_pair(Tok->IndentLevel, Tok->NestingLevel);
+ }
};
private:
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
index d8118cb..7dc475e 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
@@ -34,10 +34,11 @@ namespace {
typedef RecursiveASTVisitor<ASTPrinter> base;
public:
- ASTPrinter(std::unique_ptr<raw_ostream> Out = nullptr, bool Dump = false,
- StringRef FilterString = "", bool DumpLookups = false)
- : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)), Dump(Dump),
- FilterString(FilterString), DumpLookups(DumpLookups) {}
+ enum Kind { DumpFull, Dump, Print, None };
+ ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K, StringRef FilterString,
+ bool DumpLookups = false)
+ : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)),
+ OutputKind(K), FilterString(FilterString), DumpLookups(DumpLookups) {}
void HandleTranslationUnit(ASTContext &Context) override {
TranslationUnitDecl *D = Context.getTranslationUnitDecl();
@@ -55,7 +56,7 @@ namespace {
bool ShowColors = Out.has_colors();
if (ShowColors)
Out.changeColor(raw_ostream::BLUE);
- Out << ((Dump || DumpLookups) ? "Dumping " : "Printing ") << getName(D)
+ Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D)
<< ":\n";
if (ShowColors)
Out.resetColor();
@@ -80,22 +81,30 @@ namespace {
if (DumpLookups) {
if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
if (DC == DC->getPrimaryContext())
- DC->dumpLookups(Out, Dump);
+ DC->dumpLookups(Out, OutputKind != None, OutputKind == DumpFull);
else
Out << "Lookup map is in primary DeclContext "
<< DC->getPrimaryContext() << "\n";
} else
Out << "Not a DeclContext\n";
- } else if (Dump)
- D->dump(Out);
- else
+ } else if (OutputKind == Print)
D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true);
+ else if (OutputKind != None)
+ D->dump(Out, OutputKind == DumpFull);
}
raw_ostream &Out;
std::unique_ptr<raw_ostream> OwnedOut;
- bool Dump;
+
+ /// How to output individual declarations.
+ Kind OutputKind;
+
+ /// Which declarations or DeclContexts to display.
std::string FilterString;
+
+ /// Whether the primary output is lookup results or declarations. Individual
+ /// results will be output with a format determined by OutputKind. This is
+ /// incompatible with OutputKind == Print.
bool DumpLookups;
};
@@ -125,16 +134,20 @@ namespace {
std::unique_ptr<ASTConsumer>
clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
StringRef FilterString) {
- return llvm::make_unique<ASTPrinter>(std::move(Out), /*Dump=*/false,
+ return llvm::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
FilterString);
}
std::unique_ptr<ASTConsumer> clang::CreateASTDumper(StringRef FilterString,
bool DumpDecls,
+ bool Deserialize,
bool DumpLookups) {
- assert((DumpDecls || DumpLookups) && "nothing to dump");
- return llvm::make_unique<ASTPrinter>(nullptr, DumpDecls, FilterString,
- DumpLookups);
+ assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
+ return llvm::make_unique<ASTPrinter>(nullptr,
+ Deserialize ? ASTPrinter::DumpFull :
+ DumpDecls ? ASTPrinter::Dump :
+ ASTPrinter::None,
+ FilterString, DumpLookups);
}
std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
index 51064da..354527d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
@@ -21,14 +21,13 @@ ASTMergeAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return AdaptedAction->CreateASTConsumer(CI, InFile);
}
-bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI) {
// FIXME: This is a hack. We need a better way to communicate the
// AST file, compiler instance, and file name than member variables
// of FrontendAction.
AdaptedAction->setCurrentInput(getCurrentInput(), takeCurrentASTUnit());
AdaptedAction->setCompilerInstance(&CI);
- return AdaptedAction->BeginSourceFileAction(CI, Filename);
+ return AdaptedAction->BeginSourceFileAction(CI);
}
void ASTMergeAction::ExecuteAction() {
@@ -45,9 +44,9 @@ void ASTMergeAction::ExecuteAction() {
new ForwardingDiagnosticConsumer(
*CI.getDiagnostics().getClient()),
/*ShouldOwnClient=*/true));
- std::unique_ptr<ASTUnit> Unit =
- ASTUnit::LoadFromASTFile(ASTFiles[I], CI.getPCHContainerReader(),
- Diags, CI.getFileSystemOpts(), false);
+ std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
+ ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
+ CI.getFileSystemOpts(), false);
if (!Unit)
continue;
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
index d892996..1094e6d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/VirtualFileSystem.h"
@@ -78,106 +79,83 @@ namespace {
}
}
};
-
- struct OnDiskData {
- /// \brief The file in which the precompiled preamble is stored.
- std::string PreambleFile;
-
- /// \brief Temporary files that should be removed when the ASTUnit is
- /// destroyed.
- SmallVector<std::string, 4> TemporaryFiles;
-
- /// \brief Erase temporary files.
- void CleanTemporaryFiles();
-
- /// \brief Erase the preamble file.
- void CleanPreambleFile();
-
- /// \brief Erase temporary files and the preamble file.
- void Cleanup();
- };
-}
-
-static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
- static llvm::sys::SmartMutex<false> M(/* recursive = */ true);
- return M;
-}
-
-static void cleanupOnDiskMapAtExit();
-typedef llvm::DenseMap<const ASTUnit *,
- std::unique_ptr<OnDiskData>> OnDiskDataMap;
-static OnDiskDataMap &getOnDiskDataMap() {
- static OnDiskDataMap M;
- static bool hasRegisteredAtExit = false;
- if (!hasRegisteredAtExit) {
- hasRegisteredAtExit = true;
- atexit(cleanupOnDiskMapAtExit);
+ template <class T>
+ std::unique_ptr<T> valueOrNull(llvm::ErrorOr<std::unique_ptr<T>> Val) {
+ if (!Val)
+ return nullptr;
+ return std::move(*Val);
}
- return M;
-}
-static void cleanupOnDiskMapAtExit() {
- // Use the mutex because there can be an alive thread destroying an ASTUnit.
- llvm::MutexGuard Guard(getOnDiskMutex());
- for (const auto &I : getOnDiskDataMap()) {
- // We don't worry about freeing the memory associated with OnDiskDataMap.
- // All we care about is erasing stale files.
- I.second->Cleanup();
+ template <class T>
+ bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
+ if (!Val)
+ return false;
+ Output = std::move(*Val);
+ return true;
}
-}
-static OnDiskData &getOnDiskData(const ASTUnit *AU) {
- // We require the mutex since we are modifying the structure of the
- // DenseMap.
- llvm::MutexGuard Guard(getOnDiskMutex());
- OnDiskDataMap &M = getOnDiskDataMap();
- auto &D = M[AU];
- if (!D)
- D = llvm::make_unique<OnDiskData>();
- return *D;
-}
-
-static void erasePreambleFile(const ASTUnit *AU) {
- getOnDiskData(AU).CleanPreambleFile();
-}
+/// \brief Get a source buffer for \p MainFilePath, handling all file-to-file
+/// and file-to-buffer remappings inside \p Invocation.
+static std::unique_ptr<llvm::MemoryBuffer>
+getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation,
+ vfs::FileSystem *VFS,
+ StringRef FilePath) {
+ const auto &PreprocessorOpts = Invocation.getPreprocessorOpts();
-static void removeOnDiskEntry(const ASTUnit *AU) {
- // We require the mutex since we are modifying the structure of the
- // DenseMap.
- llvm::MutexGuard Guard(getOnDiskMutex());
- OnDiskDataMap &M = getOnDiskDataMap();
- OnDiskDataMap::iterator I = M.find(AU);
- if (I != M.end()) {
- I->second->Cleanup();
- M.erase(I);
- }
-}
-
-static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) {
- getOnDiskData(AU).PreambleFile = preambleFile;
-}
+ // Try to determine if the main file has been remapped, either from the
+ // command line (to another file) or directly through the compiler
+ // invocation (to a memory buffer).
+ llvm::MemoryBuffer *Buffer = nullptr;
+ std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
+ auto FileStatus = VFS->status(FilePath);
+ if (FileStatus) {
+ llvm::sys::fs::UniqueID MainFileID = FileStatus->getUniqueID();
-static const std::string &getPreambleFile(const ASTUnit *AU) {
- return getOnDiskData(AU).PreambleFile;
-}
+ // Check whether there is a file-file remapping of the main file
+ for (const auto &RF : PreprocessorOpts.RemappedFiles) {
+ std::string MPath(RF.first);
+ auto MPathStatus = VFS->status(MPath);
+ if (MPathStatus) {
+ llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
+ if (MainFileID == MID) {
+ // We found a remapping. Try to load the resulting, remapped source.
+ BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second));
+ if (!BufferOwner)
+ return nullptr;
+ }
+ }
+ }
-void OnDiskData::CleanTemporaryFiles() {
- for (StringRef File : TemporaryFiles)
- llvm::sys::fs::remove(File);
- TemporaryFiles.clear();
-}
+ // Check whether there is a file-buffer remapping. It supercedes the
+ // file-file remapping.
+ for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+ std::string MPath(RB.first);
+ auto MPathStatus = VFS->status(MPath);
+ if (MPathStatus) {
+ llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
+ if (MainFileID == MID) {
+ // We found a remapping.
+ BufferOwner.reset();
+ Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
+ }
+ }
+ }
+ }
-void OnDiskData::CleanPreambleFile() {
- if (!PreambleFile.empty()) {
- llvm::sys::fs::remove(PreambleFile);
- PreambleFile.clear();
+ // If the main source file was not remapped, load it now.
+ if (!Buffer && !BufferOwner) {
+ BufferOwner = valueOrNull(VFS->getBufferForFile(FilePath));
+ if (!BufferOwner)
+ return nullptr;
}
-}
-void OnDiskData::Cleanup() {
- CleanTemporaryFiles();
- CleanPreambleFile();
+ if (BufferOwner)
+ return BufferOwner;
+ if (!Buffer)
+ return nullptr;
+ return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath);
+}
}
struct ASTUnit::ASTWriterData {
@@ -185,21 +163,14 @@ struct ASTUnit::ASTWriterData {
llvm::BitstreamWriter Stream;
ASTWriter Writer;
- ASTWriterData() : Stream(Buffer), Writer(Stream, { }) { }
+ ASTWriterData(MemoryBufferCache &PCMCache)
+ : Stream(Buffer), Writer(Stream, Buffer, PCMCache, {}) {}
};
void ASTUnit::clearFileLevelDecls() {
llvm::DeleteContainerSeconds(FileDecls);
}
-void ASTUnit::CleanTemporaryFiles() {
- getOnDiskData(this).CleanTemporaryFiles();
-}
-
-void ASTUnit::addTemporaryFile(StringRef TempFile) {
- getOnDiskData(this).TemporaryFiles.push_back(TempFile);
-}
-
/// \brief After failing to build a precompiled preamble (due to
/// errors in the source that occurs in the preamble), the number of
/// reparses during which we'll skip even trying to precompile the
@@ -238,9 +209,6 @@ ASTUnit::~ASTUnit() {
clearFileLevelDecls();
- // Clean up the temporary files and the preamble file.
- removeOnDiskEntry(this);
-
// Free the buffers associated with remapped files. We are required to
// perform this operation here because we explicitly request that the
// compiler instance *not* free these buffers for each invocation of the
@@ -490,7 +458,9 @@ namespace {
/// a Preprocessor.
class ASTInfoCollector : public ASTReaderListener {
Preprocessor &PP;
- ASTContext &Context;
+ ASTContext *Context;
+ HeaderSearchOptions &HSOpts;
+ PreprocessorOptions &PPOpts;
LangOptions &LangOpt;
std::shared_ptr<TargetOptions> &TargetOpts;
IntrusiveRefCntPtr<TargetInfo> &Target;
@@ -498,11 +468,14 @@ class ASTInfoCollector : public ASTReaderListener {
bool InitializedLanguage;
public:
- ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
+ ASTInfoCollector(Preprocessor &PP, ASTContext *Context,
+ HeaderSearchOptions &HSOpts, PreprocessorOptions &PPOpts,
+ LangOptions &LangOpt,
std::shared_ptr<TargetOptions> &TargetOpts,
IntrusiveRefCntPtr<TargetInfo> &Target, unsigned &Counter)
- : PP(PP), Context(Context), LangOpt(LangOpt), TargetOpts(TargetOpts),
- Target(Target), Counter(Counter), InitializedLanguage(false) {}
+ : PP(PP), Context(Context), HSOpts(HSOpts), PPOpts(PPOpts),
+ LangOpt(LangOpt), TargetOpts(TargetOpts), Target(Target),
+ Counter(Counter), InitializedLanguage(false) {}
bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
bool AllowCompatibleDifferences) override {
@@ -516,6 +489,20 @@ public:
return false;
}
+ virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ StringRef SpecificModuleCachePath,
+ bool Complain) override {
+ this->HSOpts = HSOpts;
+ return false;
+ }
+
+ virtual bool
+ ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain,
+ std::string &SuggestedPredefines) override {
+ this->PPOpts = PPOpts;
+ return false;
+ }
+
bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
bool AllowCompatibleDifferences) override {
// If we've already initialized the target, don't do it again.
@@ -549,28 +536,39 @@ private:
// Initialize the preprocessor.
PP.Initialize(*Target);
+ if (!Context)
+ return;
+
// Initialize the ASTContext
- Context.InitBuiltinTypes(*Target);
+ Context->InitBuiltinTypes(*Target);
// We didn't have access to the comment options when the ASTContext was
// constructed, so register them now.
- Context.getCommentCommandTraits().registerCommentOptions(
+ Context->getCommentCommandTraits().registerCommentOptions(
LangOpt.CommentOpts);
}
};
/// \brief Diagnostic consumer that saves each diagnostic it is given.
class StoredDiagnosticConsumer : public DiagnosticConsumer {
- SmallVectorImpl<StoredDiagnostic> &StoredDiags;
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags;
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags;
+ const LangOptions *LangOpts;
SourceManager *SourceMgr;
public:
- explicit StoredDiagnosticConsumer(
- SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : StoredDiags(StoredDiags), SourceMgr(nullptr) {}
+ StoredDiagnosticConsumer(
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
+ : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags),
+ LangOpts(nullptr), SourceMgr(nullptr) {
+ assert((StoredDiags || StandaloneDiags) &&
+ "No output collections were passed to StoredDiagnosticConsumer.");
+ }
void BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP = nullptr) override {
+ this->LangOpts = &LangOpts;
if (PP)
SourceMgr = &PP->getSourceManager();
}
@@ -589,8 +587,9 @@ class CaptureDroppedDiagnostics {
public:
CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags,
- SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : Diags(Diags), Client(StoredDiags), PreviousClient(nullptr)
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
+ : Diags(Diags), Client(StoredDiags, StandaloneDiags), PreviousClient(nullptr)
{
if (RequestCapture || Diags.getClient() == nullptr) {
OwningPreviousClient = Diags.takeClient();
@@ -607,16 +606,39 @@ public:
} // anonymous namespace
+static ASTUnit::StandaloneDiagnostic
+makeStandaloneDiagnostic(const LangOptions &LangOpts,
+ const StoredDiagnostic &InDiag);
+
void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
- const Diagnostic &Info) {
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
DiagnosticConsumer::HandleDiagnostic(Level, Info);
// Only record the diagnostic if it's part of the source manager we know
// about. This effectively drops diagnostics from modules we're building.
// FIXME: In the long run, ee don't want to drop source managers from modules.
- if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr)
- StoredDiags.emplace_back(Level, Info);
+ if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) {
+ StoredDiagnostic *ResultDiag = nullptr;
+ if (StoredDiags) {
+ StoredDiags->emplace_back(Level, Info);
+ ResultDiag = &StoredDiags->back();
+ }
+
+ if (StandaloneDiags) {
+ llvm::Optional<StoredDiagnostic> StoredDiag = llvm::None;
+ if (!ResultDiag) {
+ StoredDiag.emplace(Level, Info);
+ ResultDiag = StoredDiag.getPointer();
+ }
+ StandaloneDiags->push_back(
+ makeStandaloneDiagnostic(*LangOpts, *ResultDiag));
+ }
+ }
+}
+
+IntrusiveRefCntPtr<ASTReader> ASTUnit::getASTReader() const {
+ return Reader;
}
ASTMutationListener *ASTUnit::getASTMutationListener() {
@@ -647,12 +669,12 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTUnit &AST, bool CaptureDiagnostics) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
if (CaptureDiagnostics)
- Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics));
+ Diags->setClient(new StoredDiagnosticConsumer(&AST.StoredDiagnostics, nullptr));
}
std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
const std::string &Filename, const PCHContainerReader &PCHContainerRdr,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts, bool UseDebugInfo,
bool OnlyLocalDecls, ArrayRef<RemappedFile> RemappedFiles,
bool CaptureDiagnostics, bool AllowPCHWithCompilerErrors,
@@ -668,6 +690,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
+ AST->LangOpts = std::make_shared<LangOptions>();
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->Diagnostics = Diags;
@@ -677,18 +700,18 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
AST->getFileManager(),
UserFilesAreVolatile);
+ AST->PCMCache = new MemoryBufferCache;
AST->HSOpts = std::make_shared<HeaderSearchOptions>();
AST->HSOpts->ModuleFormat = PCHContainerRdr.getFormat();
AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts,
AST->getSourceManager(),
AST->getDiagnostics(),
- AST->ASTFileLangOpts,
+ AST->getLangOpts(),
/*Target=*/nullptr));
-
- auto PPOpts = std::make_shared<PreprocessorOptions>();
+ AST->PPOpts = std::make_shared<PreprocessorOptions>();
for (const auto &RemappedFile : RemappedFiles)
- PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second);
+ AST->PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second);
// Gather Info for preprocessor construction later on.
@@ -696,35 +719,36 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
unsigned Counter;
AST->PP = std::make_shared<Preprocessor>(
- std::move(PPOpts), AST->getDiagnostics(), AST->ASTFileLangOpts,
- AST->getSourceManager(), HeaderInfo, *AST,
+ AST->PPOpts, AST->getDiagnostics(), *AST->LangOpts,
+ AST->getSourceManager(), *AST->PCMCache, HeaderInfo, AST->ModuleLoader,
/*IILookup=*/nullptr,
/*OwnsHeaderSearch=*/false);
Preprocessor &PP = *AST->PP;
- AST->Ctx = new ASTContext(AST->ASTFileLangOpts, AST->getSourceManager(),
- PP.getIdentifierTable(), PP.getSelectorTable(),
- PP.getBuiltinInfo());
- ASTContext &Context = *AST->Ctx;
+ if (ToLoad >= LoadASTOnly)
+ AST->Ctx = new ASTContext(*AST->LangOpts, AST->getSourceManager(),
+ PP.getIdentifierTable(), PP.getSelectorTable(),
+ PP.getBuiltinInfo());
bool disableValid = false;
if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION"))
disableValid = true;
- AST->Reader = new ASTReader(PP, Context, PCHContainerRdr, { },
+ AST->Reader = new ASTReader(PP, AST->Ctx.get(), PCHContainerRdr, { },
/*isysroot=*/"",
/*DisableValidation=*/disableValid,
AllowPCHWithCompilerErrors);
AST->Reader->setListener(llvm::make_unique<ASTInfoCollector>(
- *AST->PP, Context, AST->ASTFileLangOpts, AST->TargetOpts, AST->Target,
- Counter));
+ *AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts,
+ AST->TargetOpts, AST->Target, Counter));
// Attach the AST reader to the AST context as an external AST
// source, so that declarations will be deserialized from the
// AST file as needed.
// We need the external source to be set up before we read the AST, because
// eagerly-deserialized declarations may use it.
- Context.setExternalSource(AST->Reader);
+ if (AST->Ctx)
+ AST->Ctx->setExternalSource(AST->Reader);
switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile,
SourceLocation(), ASTReader::ARR_None)) {
@@ -746,21 +770,29 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
PP.setCounterValue(Counter);
// Create an AST consumer, even though it isn't used.
- AST->Consumer.reset(new ASTConsumer);
-
+ if (ToLoad >= LoadASTOnly)
+ AST->Consumer.reset(new ASTConsumer);
+
// Create a semantic analysis object and tell the AST reader about it.
- AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer));
- AST->TheSema->Initialize();
- AST->Reader->InitializeSema(*AST->TheSema);
+ if (ToLoad >= LoadEverything) {
+ AST->TheSema.reset(new Sema(PP, *AST->Ctx, *AST->Consumer));
+ AST->TheSema->Initialize();
+ AST->Reader->InitializeSema(*AST->TheSema);
+ }
// Tell the diagnostic client that we have started a source file.
- AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP);
+ AST->getDiagnostics().getClient()->BeginSourceFile(PP.getLangOpts(), &PP);
return AST;
}
namespace {
+/// \brief Add the given macro to the hash of all top-level entities.
+void AddDefinedMacroToHash(const Token &MacroNameTok, unsigned &Hash) {
+ Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+}
+
/// \brief Preprocessor callback class that updates a hash value with the names
/// of all macros that have been defined by the translation unit.
class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
@@ -771,7 +803,7 @@ public:
void MacroDefined(const Token &MacroNameTok,
const MacroDirective *MD) override {
- Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+ AddDefinedMacroToHash(MacroNameTok, Hash);
}
};
@@ -897,45 +929,27 @@ public:
}
};
-class PrecompilePreambleAction : public ASTFrontendAction {
- ASTUnit &Unit;
- bool HasEmittedPreamblePCH;
-
+class ASTUnitPreambleCallbacks : public PreambleCallbacks {
public:
- explicit PrecompilePreambleAction(ASTUnit &Unit)
- : Unit(Unit), HasEmittedPreamblePCH(false) {}
+ unsigned getHash() const { return Hash; }
- std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
- bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
- void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; }
- bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
-
- bool hasCodeCompletionSupport() const override { return false; }
- bool hasASTFileSupport() const override { return false; }
- TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
-};
+ std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); }
-class PrecompilePreambleConsumer : public PCHGenerator {
- ASTUnit &Unit;
- unsigned &Hash;
- std::vector<Decl *> TopLevelDecls;
- PrecompilePreambleAction *Action;
- std::unique_ptr<raw_ostream> Out;
+ std::vector<serialization::DeclID> takeTopLevelDeclIDs() {
+ return std::move(TopLevelDeclIDs);
+ }
-public:
- PrecompilePreambleConsumer(ASTUnit &Unit, PrecompilePreambleAction *Action,
- const Preprocessor &PP, StringRef isysroot,
- std::unique_ptr<raw_ostream> Out)
- : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
- ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
- /*AllowASTWithErrors=*/true),
- Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()), Action(Action),
- Out(std::move(Out)) {
- Hash = 0;
+ void AfterPCHEmitted(ASTWriter &Writer) override {
+ TopLevelDeclIDs.reserve(TopLevelDecls.size());
+ for (Decl *D : TopLevelDecls) {
+ // Invalid top-level decls may not have been serialized.
+ if (D->isInvalidDecl())
+ continue;
+ TopLevelDeclIDs.push_back(Writer.getDeclID(D));
+ }
}
- bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ void HandleTopLevelDecl(DeclGroupRef DG) override {
for (Decl *D : DG) {
// FIXME: Currently ObjC method declarations are incorrectly being
// reported as top-level declarations, even though their DeclContext
@@ -946,59 +960,22 @@ public:
AddTopLevelDeclarationToHash(D, Hash);
TopLevelDecls.push_back(D);
}
- return true;
}
- void HandleTranslationUnit(ASTContext &Ctx) override {
- PCHGenerator::HandleTranslationUnit(Ctx);
- if (hasEmittedPCH()) {
- // Write the generated bitstream to "Out".
- *Out << getPCH();
- // Make sure it hits disk now.
- Out->flush();
- // Free the buffer.
- llvm::SmallVector<char, 0> Empty;
- getPCH() = std::move(Empty);
-
- // Translate the top-level declarations we captured during
- // parsing into declaration IDs in the precompiled
- // preamble. This will allow us to deserialize those top-level
- // declarations when requested.
- for (Decl *D : TopLevelDecls) {
- // Invalid top-level decls may not have been serialized.
- if (D->isInvalidDecl())
- continue;
- Unit.addTopLevelDeclFromPreamble(getWriter().getDeclID(D));
- }
-
- Action->setHasEmittedPreamblePCH();
- }
+ void HandleMacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ AddDefinedMacroToHash(MacroNameTok, Hash);
}
+
+private:
+ unsigned Hash = 0;
+ std::vector<Decl *> TopLevelDecls;
+ std::vector<serialization::DeclID> TopLevelDeclIDs;
+ llvm::SmallVector<ASTUnit::StandaloneDiagnostic, 4> PreambleDiags;
};
} // anonymous namespace
-std::unique_ptr<ASTConsumer>
-PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- std::string Sysroot;
- std::string OutputFile;
- std::unique_ptr<raw_ostream> OS =
- GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
- OutputFile);
- if (!OS)
- return nullptr;
-
- if (!CI.getFrontendOpts().RelocatablePCH)
- Sysroot.clear();
-
- CI.getPreprocessor().addPPCallbacks(
- llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
- Unit.getCurrentTopLevelHashValue()));
- return llvm::make_unique<PrecompilePreambleConsumer>(
- Unit, this, CI.getPreprocessor(), Sysroot, std::move(OS));
-}
-
static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) {
return StoredDiag.getLocation().isValid();
}
@@ -1034,15 +1011,20 @@ static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> &
/// \returns True if a failure occurred that causes the ASTUnit not to
/// contain any translation-unit information, false otherwise.
bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer) {
- SavedMainFileBuffer.reset();
-
+ std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Invocation)
return true;
// Create the compiler instance to use for building the AST.
std::unique_ptr<CompilerInstance> Clang(
new CompilerInstance(std::move(PCHContainerOps)));
+ if (FileMgr && VFS) {
+ assert(VFS == FileMgr->getVirtualFileSystem() &&
+ "VFS passed to Parse and VFS in FileMgr are different");
+ } else if (VFS) {
+ Clang->setVirtualFileSystem(VFS);
+ }
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
@@ -1069,9 +1051,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
"IR inputs not support here!");
// Configure the various subsystems.
@@ -1081,18 +1065,11 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
Clang->createFileManager();
FileMgr = &Clang->getFileManager();
}
- SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
- UserFilesAreVolatile);
- TheSema.reset();
- Ctx = nullptr;
- PP = nullptr;
- Reader = nullptr;
- // Clear out old caches and data.
- TopLevelDecls.clear();
- clearFileLevelDecls();
- CleanTemporaryFiles();
+ ResetForParse();
+ SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
+ UserFilesAreVolatile);
if (!OverrideMainBuffer) {
checkAndRemoveNonDriverDiags(StoredDiagnostics);
TopLevelDeclsInPreamble.clear();
@@ -1106,15 +1083,9 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
- PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile,
- OverrideMainBuffer.get());
- PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
- PreprocessorOpts.PrecompiledPreambleBytes.second
- = PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
- PreprocessorOpts.DisablePCHValidation = true;
+ assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null");
+ Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get());
// The stored diagnostic has the old source manager in it; update
// the locations to refer into the new source manager. Since we've
@@ -1140,6 +1111,8 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
if (SavedMainFileBuffer)
TranslateStoredDiagnostics(getFileManager(), getSourceManager(),
PreambleDiagnostics, StoredDiagnostics);
+ else
+ PreambleSrcLocCache.clear();
if (!Act->Execute())
goto error;
@@ -1165,111 +1138,6 @@ error:
return true;
}
-/// \brief Simple function to retrieve a path for a preamble precompiled header.
-static std::string GetPreamblePCHPath() {
- // FIXME: This is a hack so that we can override the preamble file during
- // crash-recovery testing, which is the only case where the preamble files
- // are not necessarily cleaned up.
- const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
- if (TmpFile)
- return TmpFile;
-
- SmallString<128> Path;
- llvm::sys::fs::createTemporaryFile("preamble", "pch", Path);
-
- return Path.str();
-}
-
-/// \brief Compute the preamble for the main file, providing the source buffer
-/// that corresponds to the main file along with a pair (bytes, start-of-line)
-/// that describes the preamble.
-ASTUnit::ComputedPreamble
-ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines) {
- FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts();
-
- // Try to determine if the main file has been remapped, either from the
- // command line (to another file) or directly through the compiler invocation
- // (to a memory buffer).
- llvm::MemoryBuffer *Buffer = nullptr;
- std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
- std::string MainFilePath(FrontendOpts.Inputs[0].getFile());
- llvm::sys::fs::UniqueID MainFileID;
- if (!llvm::sys::fs::getUniqueID(MainFilePath, MainFileID)) {
- // Check whether there is a file-file remapping of the main file
- for (const auto &RF : PreprocessorOpts.RemappedFiles) {
- std::string MPath(RF.first);
- llvm::sys::fs::UniqueID MID;
- if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
- if (MainFileID == MID) {
- // We found a remapping. Try to load the resulting, remapped source.
- BufferOwner = getBufferForFile(RF.second);
- if (!BufferOwner)
- return ComputedPreamble(nullptr, nullptr, 0, true);
- }
- }
- }
-
- // Check whether there is a file-buffer remapping. It supercedes the
- // file-file remapping.
- for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
- std::string MPath(RB.first);
- llvm::sys::fs::UniqueID MID;
- if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
- if (MainFileID == MID) {
- // We found a remapping.
- BufferOwner.reset();
- Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
- }
- }
- }
- }
-
- // If the main source file was not remapped, load it now.
- if (!Buffer && !BufferOwner) {
- BufferOwner = getBufferForFile(FrontendOpts.Inputs[0].getFile());
- if (!BufferOwner)
- return ComputedPreamble(nullptr, nullptr, 0, true);
- }
-
- if (!Buffer)
- Buffer = BufferOwner.get();
- auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(),
- *Invocation.getLangOpts(), MaxLines);
- return ComputedPreamble(Buffer, std::move(BufferOwner), Pre.first,
- Pre.second);
-}
-
-ASTUnit::PreambleFileHash
-ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) {
- PreambleFileHash Result;
- Result.Size = Size;
- Result.ModTime = ModTime;
- memset(Result.MD5, 0, sizeof(Result.MD5));
- return Result;
-}
-
-ASTUnit::PreambleFileHash ASTUnit::PreambleFileHash::createForMemoryBuffer(
- const llvm::MemoryBuffer *Buffer) {
- PreambleFileHash Result;
- Result.Size = Buffer->getBufferSize();
- Result.ModTime = 0;
-
- llvm::MD5 MD5Ctx;
- MD5Ctx.update(Buffer->getBuffer().data());
- MD5Ctx.final(Result.MD5);
-
- return Result;
-}
-
-namespace clang {
-bool operator==(const ASTUnit::PreambleFileHash &LHS,
- const ASTUnit::PreambleFileHash &RHS) {
- return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
- memcmp(LHS.MD5, RHS.MD5, sizeof(LHS.MD5)) == 0;
-}
-} // namespace clang
-
static std::pair<unsigned, unsigned>
makeStandaloneRange(CharSourceRange Range, const SourceManager &SM,
const LangOptions &LangOpts) {
@@ -1338,135 +1206,44 @@ makeStandaloneDiagnostic(const LangOptions &LangOpts,
std::unique_ptr<llvm::MemoryBuffer>
ASTUnit::getMainBufferWithPrecompiledPreamble(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- const CompilerInvocation &PreambleInvocationIn, bool AllowRebuild,
+ const CompilerInvocation &PreambleInvocationIn,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild,
unsigned MaxLines) {
- auto PreambleInvocation =
- std::make_shared<CompilerInvocation>(PreambleInvocationIn);
- FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts
- = PreambleInvocation->getPreprocessorOpts();
-
- ComputedPreamble NewPreamble = ComputePreamble(*PreambleInvocation, MaxLines);
-
- if (!NewPreamble.Size) {
- // We couldn't find a preamble in the main source. Clear out the current
- // preamble, if we have one. It's obviously no good any more.
- Preamble.clear();
- erasePreambleFile(this);
-
- // The next time we actually see a preamble, precompile it.
- PreambleRebuildCounter = 1;
+ auto MainFilePath =
+ PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile();
+ std::unique_ptr<llvm::MemoryBuffer> MainFileBuffer =
+ getBufferForFileHandlingRemapping(PreambleInvocationIn, VFS.get(),
+ MainFilePath);
+ if (!MainFileBuffer)
return nullptr;
- }
-
- if (!Preamble.empty()) {
- // We've previously computed a preamble. Check whether we have the same
- // preamble now that we did before, and that there's enough space in
- // the main-file buffer within the precompiled preamble to fit the
- // new main file.
- if (Preamble.size() == NewPreamble.Size &&
- PreambleEndsAtStartOfLine == NewPreamble.PreambleEndsAtStartOfLine &&
- memcmp(Preamble.getBufferStart(), NewPreamble.Buffer->getBufferStart(),
- NewPreamble.Size) == 0) {
- // The preamble has not changed. We may be able to re-use the precompiled
- // preamble.
-
- // Check that none of the files used by the preamble have changed.
- bool AnyFileChanged = false;
-
- // First, make a record of those files that have been overridden via
- // remapping or unsaved_files.
- std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
- for (const auto &R : PreprocessorOpts.RemappedFiles) {
- if (AnyFileChanged)
- break;
-
- vfs::Status Status;
- if (FileMgr->getNoncachedStatValue(R.second, Status)) {
- // If we can't stat the file we're remapping to, assume that something
- // horrible happened.
- AnyFileChanged = true;
- break;
- }
- OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
- Status.getSize(),
- llvm::sys::toTimeT(Status.getLastModificationTime()));
- }
+ PreambleBounds Bounds =
+ ComputePreambleBounds(*PreambleInvocationIn.getLangOpts(),
+ MainFileBuffer.get(), MaxLines);
+ if (!Bounds.Size)
+ return nullptr;
- for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
- if (AnyFileChanged)
- break;
+ if (Preamble) {
+ if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds,
+ VFS.get())) {
+ // Okay! We can re-use the precompiled preamble.
- vfs::Status Status;
- if (FileMgr->getNoncachedStatValue(RB.first, Status)) {
- AnyFileChanged = true;
- break;
- }
+ // Set the state of the diagnostic object to mimic its state
+ // after parsing the preamble.
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(),
+ PreambleInvocationIn.getDiagnosticOpts());
+ getDiagnostics().setNumWarnings(NumWarningsInPreamble);
- OverriddenFiles[Status.getUniqueID()] =
- PreambleFileHash::createForMemoryBuffer(RB.second);
- }
-
- // Check whether anything has changed.
- for (llvm::StringMap<PreambleFileHash>::iterator
- F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
- !AnyFileChanged && F != FEnd;
- ++F) {
- vfs::Status Status;
- if (FileMgr->getNoncachedStatValue(F->first(), Status)) {
- // If we can't stat the file, assume that something horrible happened.
- AnyFileChanged = true;
- break;
- }
-
- std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden
- = OverriddenFiles.find(Status.getUniqueID());
- if (Overridden != OverriddenFiles.end()) {
- // This file was remapped; check whether the newly-mapped file
- // matches up with the previous mapping.
- if (Overridden->second != F->second)
- AnyFileChanged = true;
- continue;
- }
-
- // The file was not remapped; check whether it has changed on disk.
- if (Status.getSize() != uint64_t(F->second.Size) ||
- llvm::sys::toTimeT(Status.getLastModificationTime()) !=
- F->second.ModTime)
- AnyFileChanged = true;
- }
-
- if (!AnyFileChanged) {
- // Okay! We can re-use the precompiled preamble.
-
- // Set the state of the diagnostic object to mimic its state
- // after parsing the preamble.
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(),
- PreambleInvocation->getDiagnosticOpts());
- getDiagnostics().setNumWarnings(NumWarningsInPreamble);
-
- return llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.Buffer->getBuffer(), FrontendOpts.Inputs[0].getFile());
- }
+ PreambleRebuildCounter = 1;
+ return MainFileBuffer;
+ } else {
+ Preamble.reset();
+ PreambleDiagnostics.clear();
+ TopLevelDeclsInPreamble.clear();
+ PreambleRebuildCounter = 1;
}
-
- // If we aren't allowed to rebuild the precompiled preamble, just
- // return now.
- if (!AllowRebuild)
- return nullptr;
-
- // We can't reuse the previously-computed preamble. Build a new one.
- Preamble.clear();
- PreambleDiagnostics.clear();
- erasePreambleFile(this);
- PreambleRebuildCounter = 1;
- } else if (!AllowRebuild) {
- // We aren't allowed to rebuild the precompiled preamble; just
- // return now.
- return nullptr;
}
// If the preamble rebuild counter > 1, it's because we previously
@@ -1477,162 +1254,61 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
return nullptr;
}
- // Create a temporary file for the precompiled preamble. In rare
- // circumstances, this can fail.
- std::string PreamblePCHPath = GetPreamblePCHPath();
- if (PreamblePCHPath.empty()) {
- // Try again next time.
- PreambleRebuildCounter = 1;
- return nullptr;
- }
-
- // We did not previously compute a preamble, or it can't be reused anyway.
- SimpleTimer PreambleTimer(WantTiming);
- PreambleTimer.setOutput("Precompiling preamble");
-
- // Save the preamble text for later; we'll need to compare against it for
- // subsequent reparses.
- StringRef MainFilename = FrontendOpts.Inputs[0].getFile();
- Preamble.assign(FileMgr->getFile(MainFilename),
- NewPreamble.Buffer->getBufferStart(),
- NewPreamble.Buffer->getBufferStart() + NewPreamble.Size);
- PreambleEndsAtStartOfLine = NewPreamble.PreambleEndsAtStartOfLine;
-
- PreambleBuffer = llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.Buffer->getBuffer().slice(0, Preamble.size()), MainFilename);
-
- // Remap the main source file to the preamble buffer.
- StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
- PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer.get());
-
- // Tell the compiler invocation to generate a temporary precompiled header.
- FrontendOpts.ProgramAction = frontend::GeneratePCH;
- // FIXME: Generate the precompiled header into memory?
- FrontendOpts.OutputFile = PreamblePCHPath;
- PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
- PreprocessorOpts.PrecompiledPreambleBytes.second = false;
-
- // Create the compiler instance to use for building the precompiled preamble.
- std::unique_ptr<CompilerInstance> Clang(
- new CompilerInstance(std::move(PCHContainerOps)));
-
- // Recover resources if we crash before exiting this method.
- llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
- CICleanup(Clang.get());
-
- Clang->setInvocation(std::move(PreambleInvocation));
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
-
- // Set up diagnostics, capturing all of the diagnostics produced.
- Clang->setDiagnostics(&getDiagnostics());
-
- // Create the target instance.
- Clang->setTarget(TargetInfo::CreateTargetInfo(
- Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
- if (!Clang->hasTarget()) {
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
- }
-
- // Inform the target of the language options.
- //
- // FIXME: We shouldn't need to do this, the target should be immutable once
- // created. This complexity should be lifted elsewhere.
- Clang->getTarget().adjust(Clang->getLangOpts());
-
- assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
- "Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
- "FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
- "IR inputs not support here!");
-
- // Clear out old caches and data.
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts());
- checkAndRemoveNonDriverDiags(StoredDiagnostics);
- TopLevelDecls.clear();
- TopLevelDeclsInPreamble.clear();
- PreambleDiagnostics.clear();
-
- IntrusiveRefCntPtr<vfs::FileSystem> VFS =
- createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics());
- if (!VFS)
+ assert(!Preamble && "No Preamble should be stored at that point");
+ // If we aren't allowed to rebuild the precompiled preamble, just
+ // return now.
+ if (!AllowRebuild)
return nullptr;
- // Create a file manager object to provide access to and cache the filesystem.
- Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
-
- // Create the source manager.
- Clang->setSourceManager(new SourceManager(getDiagnostics(),
- Clang->getFileManager()));
-
- auto PreambleDepCollector = std::make_shared<DependencyCollector>();
- Clang->addDependencyCollector(PreambleDepCollector);
-
- std::unique_ptr<PrecompilePreambleAction> Act;
- Act.reset(new PrecompilePreambleAction(*this));
- if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
+ SmallVector<StandaloneDiagnostic, 4> NewPreambleDiagsStandalone;
+ SmallVector<StoredDiagnostic, 4> NewPreambleDiags;
+ ASTUnitPreambleCallbacks Callbacks;
+ {
+ llvm::Optional<CaptureDroppedDiagnostics> Capture;
+ if (CaptureDiagnostics)
+ Capture.emplace(/*RequestCapture=*/true, *Diagnostics, &NewPreambleDiags,
+ &NewPreambleDiagsStandalone);
+
+ // We did not previously compute a preamble, or it can't be reused anyway.
+ SimpleTimer PreambleTimer(WantTiming);
+ PreambleTimer.setOutput("Precompiling preamble");
+
+ llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build(
+ PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS,
+ PCHContainerOps, Callbacks);
+ if (NewPreamble) {
+ Preamble = std::move(*NewPreamble);
+ PreambleRebuildCounter = 1;
+ } else {
+ switch (static_cast<BuildPreambleError>(NewPreamble.getError().value())) {
+ case BuildPreambleError::CouldntCreateTempFile:
+ case BuildPreambleError::PreambleIsEmpty:
+ // Try again next time.
+ PreambleRebuildCounter = 1;
+ return nullptr;
+ case BuildPreambleError::CouldntCreateTargetInfo:
+ case BuildPreambleError::BeginSourceFileFailed:
+ case BuildPreambleError::CouldntEmitPCH:
+ case BuildPreambleError::CouldntCreateVFSOverlay:
+ // These erros are more likely to repeat, retry after some period.
+ PreambleRebuildCounter = DefaultPreambleRebuildInterval;
+ return nullptr;
+ }
+ llvm_unreachable("unexpected BuildPreambleError");
+ }
}
-
- Act->Execute();
-
- // Transfer any diagnostics generated when parsing the preamble into the set
- // of preamble diagnostics.
- for (stored_diag_iterator I = stored_diag_afterDriver_begin(),
- E = stored_diag_end();
- I != E; ++I)
- PreambleDiagnostics.push_back(
- makeStandaloneDiagnostic(Clang->getLangOpts(), *I));
- Act->EndSourceFile();
+ assert(Preamble && "Preamble wasn't built");
- checkAndRemoveNonDriverDiags(StoredDiagnostics);
+ TopLevelDecls.clear();
+ TopLevelDeclsInPreamble = Callbacks.takeTopLevelDeclIDs();
+ PreambleTopLevelHashValue = Callbacks.getHash();
- if (!Act->hasEmittedPreamblePCH()) {
- // The preamble PCH failed (e.g. there was a module loading fatal error),
- // so no precompiled header was generated. Forget that we even tried.
- // FIXME: Should we leave a note for ourselves to try again?
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- TopLevelDeclsInPreamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
- }
-
- // Keep track of the preamble we precompiled.
- setPreambleFile(this, FrontendOpts.OutputFile);
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
-
- // Keep track of all of the files that the source manager knows about,
- // so we can verify whether they have changed or not.
- FilesInPreamble.clear();
- SourceManager &SourceMgr = Clang->getSourceManager();
- for (auto &Filename : PreambleDepCollector->getDependencies()) {
- const FileEntry *File = Clang->getFileManager().getFile(Filename);
- if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
- continue;
- if (time_t ModTime = File->getModificationTime()) {
- FilesInPreamble[File->getName()] = PreambleFileHash::createForFile(
- File->getSize(), ModTime);
- } else {
- llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
- FilesInPreamble[File->getName()] =
- PreambleFileHash::createForMemoryBuffer(Buffer);
- }
- }
- PreambleRebuildCounter = 1;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
+ checkAndRemoveNonDriverDiags(NewPreambleDiags);
+ StoredDiagnostics = std::move(NewPreambleDiags);
+ PreambleDiagnostics = std::move(NewPreambleDiagsStandalone);
// If the hash of top-level entities differs from the hash of the top-level
// entities the last time we rebuilt the preamble, clear out the completion
@@ -1642,11 +1318,12 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
PreambleTopLevelHashValue = CurrentTopLevelHashValue;
}
- return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.Buffer->getBuffer(),
- MainFilename);
+ return MainFileBuffer;
}
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
+ assert(Preamble && "Should only be called when preamble was built");
+
std::vector<Decl *> Resolved;
Resolved.reserve(TopLevelDeclsInPreamble.size());
ExternalASTSource &Source = *getASTContext().getExternalSource();
@@ -1723,6 +1400,7 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
AST->UserFilesAreVolatile = UserFilesAreVolatile;
AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
UserFilesAreVolatile);
+ AST->PCMCache = new MemoryBufferCache;
return AST;
}
@@ -1802,10 +1480,12 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
- "IR inputs not supported here!");
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
+ "IR inputs not support here!");
// Configure the various subsystems.
AST->TheSema.reset();
@@ -1872,30 +1552,36 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
bool ASTUnit::LoadFromCompilerInvocation(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- unsigned PrecompilePreambleAfterNParses) {
+ unsigned PrecompilePreambleAfterNParses,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Invocation)
return true;
-
+
+ assert(VFS && "VFS is null");
+
// We'll manage file buffers ourselves.
Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
Invocation->getFrontendOpts().DisableFree = false;
+ getDiagnostics().Reset();
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
if (PrecompilePreambleAfterNParses > 0) {
PreambleRebuildCounter = PrecompilePreambleAfterNParses;
OverrideMainBuffer =
- getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
+ getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
}
-
+
SimpleTimer ParsingTimer(WantTiming);
ParsingTimer.setOutput("Parsing " + getMainFileName());
-
+
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer>
MemBufferCleanup(OverrideMainBuffer.get());
- return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
+ return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
}
std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
@@ -1929,7 +1615,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
DiagCleanup(Diags.get());
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
- PrecompilePreambleAfterNParses))
+ PrecompilePreambleAfterNParses,
+ AST->FileMgr->getVirtualFileSystem()))
return nullptr;
return AST;
}
@@ -1943,8 +1630,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies,
- bool UserFilesAreVolatile, bool ForSerialization,
- llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST) {
+ bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization,
+ llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
@@ -1953,11 +1641,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
{
- CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
- StoredDiagnostics);
+ CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
+ &StoredDiagnostics, nullptr);
CI = clang::createInvocationFromCommandLine(
- llvm::makeArrayRef(ArgBegin, ArgEnd), Diags);
+ llvm::makeArrayRef(ArgBegin, ArgEnd), Diags, VFS);
if (!CI)
return nullptr;
}
@@ -1970,6 +1658,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
+ PPOpts.GeneratePreamble = PrecompilePreambleAfterNParses != 0;
+ PPOpts.SingleFileParseMode = SingleFileParse;
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
@@ -1985,11 +1675,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
AST->FileSystemOpts = CI->getFileSystemOpts();
- IntrusiveRefCntPtr<vfs::FileSystem> VFS =
- createVFSFromCompilerInvocation(*CI, *Diags);
+ if (!VFS)
+ VFS = vfs::getRealFileSystem();
+ VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
if (!VFS)
return nullptr;
AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
+ AST->PCMCache = new MemoryBufferCache;
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->TUKind = TUKind;
@@ -2001,7 +1693,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
AST->StoredDiagnostics.swap(StoredDiagnostics);
AST->Invocation = CI;
if (ForSerialization)
- AST->WriterData.reset(new ASTWriterData());
+ AST->WriterData.reset(new ASTWriterData(*AST->PCMCache));
// Zero out now to ease cleanup during crash recovery.
CI = nullptr;
Diags = nullptr;
@@ -2011,7 +1703,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
ASTUnitCleanup(AST.get());
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
- PrecompilePreambleAfterNParses)) {
+ PrecompilePreambleAfterNParses,
+ VFS)) {
// Some error occurred, if caller wants to examine diagnostics, pass it the
// ASTUnit.
if (ErrAST) {
@@ -2025,10 +1718,16 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
}
bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- ArrayRef<RemappedFile> RemappedFiles) {
+ ArrayRef<RemappedFile> RemappedFiles,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Invocation)
return true;
+ if (!VFS) {
+ assert(FileMgr && "FileMgr is null on Reparse call");
+ VFS = FileMgr->getVirtualFileSystem();
+ }
+
clearFileLevelDecls();
SimpleTimer ParsingTimer(WantTiming);
@@ -2048,9 +1747,10 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// If we have a preamble file lying around, or if we might try to
// build a precompiled preamble, do so now.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0)
+ if (Preamble || PreambleRebuildCounter > 0)
OverrideMainBuffer =
- getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
+ getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+
// Clear out the diagnostics state.
FileMgr.reset();
@@ -2061,7 +1761,7 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// Parse the sources
bool Result =
- Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer));
+ Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
// If we're caching global code-completion results, and the top-level
// declarations have changed, clear out the code-completion cache.
@@ -2076,6 +1776,19 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
return Result;
}
+void ASTUnit::ResetForParse() {
+ SavedMainFileBuffer.reset();
+
+ SourceMgr.reset();
+ TheSema.reset();
+ Ctx.reset();
+ PP.reset();
+ Reader.reset();
+
+ TopLevelDecls.clear();
+ clearFileLevelDecls();
+}
+
//----------------------------------------------------------------------------//
// Code completion
//----------------------------------------------------------------------------//
@@ -2368,7 +2081,7 @@ void ASTUnit::CodeComplete(
Clang->setDiagnostics(&Diag);
CaptureDroppedDiagnostics Capture(true,
Clang->getDiagnostics(),
- StoredDiagnostics);
+ &StoredDiagnostics, nullptr);
ProcessWarningOptions(Diag, Inv.getDiagnosticOpts());
// Create the target instance.
@@ -2387,11 +2100,12 @@ void ASTUnit::CodeComplete(
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
- assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR &&
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
"IR inputs not support here!");
-
// Use the source and file managers that we were given.
Clang->setFileManager(&FileMgr);
@@ -2416,17 +2130,21 @@ void ASTUnit::CodeComplete(
// point is within the main file, after the end of the precompiled
// preamble.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (!getPreambleFile(this).empty()) {
+ if (Preamble) {
std::string CompleteFilePath(File);
- llvm::sys::fs::UniqueID CompleteFileID;
- if (!llvm::sys::fs::getUniqueID(CompleteFilePath, CompleteFileID)) {
+ auto VFS = FileMgr.getVirtualFileSystem();
+ auto CompleteFileStatus = VFS->status(CompleteFilePath);
+ if (CompleteFileStatus) {
+ llvm::sys::fs::UniqueID CompleteFileID = CompleteFileStatus->getUniqueID();
+
std::string MainPath(OriginalSourceFile);
- llvm::sys::fs::UniqueID MainID;
- if (!llvm::sys::fs::getUniqueID(MainPath, MainID)) {
+ auto MainStatus = VFS->status(MainPath);
+ if (MainStatus) {
+ llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID();
if (CompleteFileID == MainID && Line > 1)
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
- PCHContainerOps, Inv, false, Line - 1);
+ PCHContainerOps, Inv, VFS, false, Line - 1);
}
}
}
@@ -2434,14 +2152,8 @@ void ASTUnit::CodeComplete(
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile,
- OverrideMainBuffer.get());
- PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
- PreprocessorOpts.PrecompiledPreambleBytes.second
- = PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
- PreprocessorOpts.DisablePCHValidation = true;
-
+ assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null");
+ Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get());
OwnedBuffers.push_back(OverrideMainBuffer.release());
} else {
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
@@ -2516,7 +2228,8 @@ bool ASTUnit::serialize(raw_ostream &OS) {
SmallString<128> Buffer;
llvm::BitstreamWriter Stream(Buffer);
- ASTWriter Writer(Stream, { });
+ MemoryBufferCache PCMCache;
+ ASTWriter Writer(Stream, Buffer, PCMCache, {});
return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS);
}
@@ -2531,9 +2244,9 @@ void ASTUnit::TranslateStoredDiagnostics(
// remap all the locations to the new view. This includes the diag location,
// any associated source ranges, and the source ranges of associated fix-its.
// FIXME: There should be a cleaner way to do this.
-
SmallVector<StoredDiagnostic, 4> Result;
Result.reserve(Diags.size());
+
for (const StandaloneDiagnostic &SD : Diags) {
// Rebuild the StoredDiagnostic.
if (SD.Filename.empty())
@@ -2541,8 +2254,16 @@ void ASTUnit::TranslateStoredDiagnostics(
const FileEntry *FE = FileMgr.getFile(SD.Filename);
if (!FE)
continue;
- FileID FID = SrcMgr.translateFile(FE);
- SourceLocation FileLoc = SrcMgr.getLocForStartOfFile(FID);
+ SourceLocation FileLoc;
+ auto ItFileID = PreambleSrcLocCache.find(SD.Filename);
+ if (ItFileID == PreambleSrcLocCache.end()) {
+ FileID FID = SrcMgr.translateFile(FE);
+ FileLoc = SrcMgr.getLocForStartOfFile(FID);
+ PreambleSrcLocCache[SD.Filename] = FileLoc;
+ } else {
+ FileLoc = ItFileID->getValue();
+ }
+
if (FileLoc.isInvalid())
continue;
SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset);
@@ -2679,11 +2400,11 @@ SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) {
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
- if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
unsigned Offs;
- if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) {
+ if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble->getBounds().Size) {
SourceLocation FileLoc
= SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID());
return FileLoc.getLocWithOffset(Offs);
@@ -2700,12 +2421,12 @@ SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) {
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
- if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
unsigned Offs;
if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) &&
- Offs < Preamble.size()) {
+ Offs < Preamble->getBounds().Size) {
SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID);
return FileLoc.getLocWithOffset(Offs);
}
@@ -2823,18 +2544,32 @@ const FileEntry *ASTUnit::getPCHFile() {
}
bool ASTUnit::isModuleFile() {
- return isMainFileAST() && ASTFileLangOpts.isCompilingModule();
+ return isMainFileAST() && getLangOpts().isCompilingModule();
}
-void ASTUnit::PreambleData::countLines() const {
- NumLines = 0;
- if (empty())
- return;
+InputKind ASTUnit::getInputKind() const {
+ auto &LangOpts = getLangOpts();
+
+ InputKind::Language Lang;
+ if (LangOpts.OpenCL)
+ Lang = InputKind::OpenCL;
+ else if (LangOpts.CUDA)
+ Lang = InputKind::CUDA;
+ else if (LangOpts.RenderScript)
+ Lang = InputKind::RenderScript;
+ else if (LangOpts.CPlusPlus)
+ Lang = LangOpts.ObjC1 ? InputKind::ObjCXX : InputKind::CXX;
+ else
+ Lang = LangOpts.ObjC1 ? InputKind::ObjC : InputKind::C;
+
+ InputKind::Format Fmt = InputKind::Source;
+ if (LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap)
+ Fmt = InputKind::ModuleMap;
- NumLines = std::count(Buffer.begin(), Buffer.end(), '\n');
+ // We don't know if input was preprocessed. Assume not.
+ bool PP = false;
- if (Buffer.back() != '\n')
- ++NumLines;
+ return InputKind(Lang, Fmt, PP);
}
#ifndef NDEBUG
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp b/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp
index b984c2e..534c758 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp
@@ -83,7 +83,7 @@ createASTReader(CompilerInstance &CI, StringRef pchFile,
ASTDeserializationListener *deserialListener = nullptr) {
Preprocessor &PP = CI.getPreprocessor();
std::unique_ptr<ASTReader> Reader;
- Reader.reset(new ASTReader(PP, CI.getASTContext(),
+ Reader.reset(new ASTReader(PP, &CI.getASTContext(),
CI.getPCHContainerReader(),
/*Extensions=*/{ },
/*isysroot=*/"", /*DisableValidation=*/true));
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
index afcaa6e..bb6a665 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
@@ -11,8 +11,10 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
@@ -55,12 +57,15 @@ using namespace clang;
CompilerInstance::CompilerInstance(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- bool BuildingModule)
- : ModuleLoader(BuildingModule), Invocation(new CompilerInvocation()),
- ModuleManager(nullptr),
- ThePCHContainerOperations(std::move(PCHContainerOps)),
- BuildGlobalModuleIndex(false), HaveFullGlobalModuleIndex(false),
- ModuleBuildFailed(false) {}
+ MemoryBufferCache *SharedPCMCache)
+ : ModuleLoader(/* BuildingModule = */ SharedPCMCache),
+ Invocation(new CompilerInvocation()),
+ PCMCache(SharedPCMCache ? SharedPCMCache : new MemoryBufferCache),
+ ThePCHContainerOperations(std::move(PCHContainerOps)) {
+ // Don't allow this to invalidate buffers in use by others.
+ if (SharedPCMCache)
+ getPCMCache().finalizeCurrentBuffers();
+}
CompilerInstance::~CompilerInstance() {
assert(OutputFiles.empty() && "Still output files in flight?");
@@ -131,6 +136,8 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::getModuleManager() const {
return ModuleManager;
}
void CompilerInstance::setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader) {
+ assert(PCMCache.get() == &Reader->getModuleManager().getPCMCache() &&
+ "Expected ASTReader to use the same PCM cache");
ModuleManager = std::move(Reader);
}
@@ -373,7 +380,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
getDiagnostics(), getLangOpts(), &getTarget());
PP = std::make_shared<Preprocessor>(
Invocation->getPreprocessorOptsPtr(), getDiagnostics(), getLangOpts(),
- getSourceManager(), *HeaderInfo, *this, PTHMgr,
+ getSourceManager(), getPCMCache(), *HeaderInfo, *this, PTHMgr,
/*OwnsHeaderSearch=*/true, TUKind);
PP->Initialize(getTarget(), getAuxTarget());
@@ -491,6 +498,8 @@ void CompilerInstance::createPCHExternalASTSource(
AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(),
getPCHContainerReader(),
getFrontendOpts().ModuleFileExtensions,
+ TheDependencyFileGenerator.get(),
+ DependencyCollectors,
DeserializationListener,
OwnDeserializationListener, Preamble,
getFrontendOpts().UseGlobalModuleIndex);
@@ -501,12 +510,14 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
+ DependencyFileGenerator *DependencyFile,
+ ArrayRef<std::shared_ptr<DependencyCollector>> DependencyCollectors,
void *DeserializationListener, bool OwnDeserializationListener,
bool Preamble, bool UseGlobalModuleIndex) {
HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts();
IntrusiveRefCntPtr<ASTReader> Reader(new ASTReader(
- PP, Context, PCHContainerRdr, Extensions,
+ PP, &Context, PCHContainerRdr, Extensions,
Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation,
AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false,
HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex));
@@ -518,6 +529,12 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
Reader->setDeserializationListener(
static_cast<ASTDeserializationListener *>(DeserializationListener),
/*TakeOwnership=*/OwnDeserializationListener);
+
+ if (DependencyFile)
+ DependencyFile->AttachToASTReader(*Reader);
+ for (auto &Listener : DependencyCollectors)
+ Listener->attachToASTReader(*Reader);
+
switch (Reader->ReadAST(Path,
Preamble ? serialization::MK_Preamble
: serialization::MK_PCH,
@@ -651,6 +668,11 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
llvm::sys::fs::remove(OF.Filename);
}
OutputFiles.clear();
+ if (DeleteBuiltModules) {
+ for (auto &Module : BuiltModules)
+ llvm::sys::fs::remove(Module.second);
+ BuiltModules.clear();
+ }
NonSeekStream.reset();
}
@@ -803,8 +825,11 @@ bool CompilerInstance::InitializeSourceManager(
const FrontendInputFile &Input, DiagnosticsEngine &Diags,
FileManager &FileMgr, SourceManager &SourceMgr, HeaderSearch *HS,
DependencyOutputOptions &DepOpts, const FrontendOptions &Opts) {
- SrcMgr::CharacteristicKind
- Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
+ SrcMgr::CharacteristicKind Kind =
+ Input.getKind().getFormat() == InputKind::ModuleMap
+ ? Input.isSystem() ? SrcMgr::C_System_ModuleMap
+ : SrcMgr::C_User_ModuleMap
+ : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
if (Input.isBuffer()) {
SourceMgr.setMainFileID(SourceMgr.createFileID(
@@ -842,7 +867,8 @@ bool CompilerInstance::InitializeSourceManager(
/*SearchPath=*/nullptr,
/*RelativePath=*/nullptr,
/*RequestingModule=*/nullptr,
- /*SuggestedModule=*/nullptr, /*SkipCache=*/true);
+ /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr,
+ /*SkipCache=*/true);
// Also add the header to /showIncludes output.
if (File)
DepOpts.ShowIncludesPretendHeader = File->getName();
@@ -910,8 +936,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
if (!hasTarget())
return false;
- // Create TargetInfo for the other side of CUDA compilation.
- if (getLangOpts().CUDA && !getFrontendOpts().AuxTriple.empty()) {
+ // Create TargetInfo for the other side of CUDA and OpenMP compilation.
+ if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) &&
+ !getFrontendOpts().AuxTriple.empty()) {
auto TO = std::make_shared<TargetOptions>();
TO->Triple = getFrontendOpts().AuxTriple;
TO->HostTriple = getTarget().getTriple().str();
@@ -999,26 +1026,27 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
/// \brief Determine the appropriate source input kind based on language
/// options.
-static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) {
+static InputKind::Language getLanguageFromOptions(const LangOptions &LangOpts) {
if (LangOpts.OpenCL)
- return IK_OpenCL;
+ return InputKind::OpenCL;
if (LangOpts.CUDA)
- return IK_CUDA;
+ return InputKind::CUDA;
if (LangOpts.ObjC1)
- return LangOpts.CPlusPlus? IK_ObjCXX : IK_ObjC;
- return LangOpts.CPlusPlus? IK_CXX : IK_C;
+ return LangOpts.CPlusPlus ? InputKind::ObjCXX : InputKind::ObjC;
+ return LangOpts.CPlusPlus ? InputKind::CXX : InputKind::C;
}
/// \brief Compile a module file for the given module, using the options
/// provided by the importing compiler instance. Returns true if the module
/// was built without errors.
-static bool compileModuleImpl(CompilerInstance &ImportingInstance,
- SourceLocation ImportLoc,
- Module *Module,
- StringRef ModuleFileName) {
- ModuleMap &ModMap
- = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
-
+static bool
+compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
+ StringRef ModuleName, FrontendInputFile Input,
+ StringRef OriginalModuleMapFile, StringRef ModuleFileName,
+ llvm::function_ref<void(CompilerInstance &)> PreBuildStep =
+ [](CompilerInstance &) {},
+ llvm::function_ref<void(CompilerInstance &)> PostBuildStep =
+ [](CompilerInstance &) {}) {
// Construct a compiler invocation for creating this module.
auto Invocation =
std::make_shared<CompilerInvocation>(ImportingInstance.getInvocation());
@@ -1032,7 +1060,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
// Remove any macro definitions that are explicitly ignored by the module.
// They aren't supposed to affect how the module is built anyway.
- const HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts();
+ HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts();
PPOpts.Macros.erase(
std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(),
[&HSOpts](const std::pair<std::string, bool> &def) {
@@ -1043,7 +1071,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
PPOpts.Macros.end());
// Note the name of the module we're building.
- Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName();
+ Invocation->getLangOpts()->CurrentModule = ModuleName;
// Make sure that the failed-module structure has been allocated in
// the importing instance, and propagate the pointer to the newly-created
@@ -1063,8 +1091,10 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
FrontendOpts.DisableFree = false;
FrontendOpts.GenerateGlobalModuleIndex = false;
FrontendOpts.BuildingImplicitModule = true;
- FrontendOpts.Inputs.clear();
- InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());
+ FrontendOpts.OriginalModuleMap = OriginalModuleMapFile;
+ // Force implicitly-built modules to hash the content of the module file.
+ HSOpts.ModulesHashContent = true;
+ FrontendOpts.Inputs = {Input};
// Don't free the remapped file buffers; they are owned by our caller.
PPOpts.RetainRemappedFileBuffers = true;
@@ -1074,9 +1104,11 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
Invocation->getModuleHash() && "Module hash mismatch!");
// Construct a compiler instance that will be used to actually create the
- // module.
+ // module. Since we're sharing a PCMCache,
+ // CompilerInstance::CompilerInstance is responsible for finalizing the
+ // buffers to prevent use-after-frees.
CompilerInstance Instance(ImportingInstance.getPCHContainerOperations(),
- /*BuildingModule=*/true);
+ &ImportingInstance.getPreprocessor().getPCMCache());
auto &Inv = *Invocation;
Instance.setInvocation(std::move(Invocation));
@@ -1093,7 +1125,7 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
SourceManager &SourceMgr = Instance.getSourceManager();
SourceMgr.setModuleBuildStack(
ImportingInstance.getSourceManager().getModuleBuildStack());
- SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
+ SourceMgr.pushModuleBuildStack(ModuleName,
FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
// If we're collecting module dependencies, we need to share a collector
@@ -1102,47 +1134,28 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector());
Inv.getDependencyOutputOpts() = DependencyOutputOptions();
- // Get or create the module map that we'll use to build this module.
- std::string InferredModuleMapContent;
- if (const FileEntry *ModuleMapFile =
- ModMap.getContainingModuleMapFile(Module)) {
- // Use the module map where this module resides.
- FrontendOpts.Inputs.emplace_back(ModuleMapFile->getName(), IK);
- } else {
- SmallString<128> FakeModuleMapFile(Module->Directory->getName());
- llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
- FrontendOpts.Inputs.emplace_back(FakeModuleMapFile, IK);
-
- llvm::raw_string_ostream OS(InferredModuleMapContent);
- Module->print(OS);
- OS.flush();
-
- std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
- llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
- ModuleMapFile = Instance.getFileManager().getVirtualFile(
- FakeModuleMapFile, InferredModuleMapContent.size(), 0);
- SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer));
- }
-
- // Construct a module-generating action. Passing through the module map is
- // safe because the FileManager is shared between the compiler instances.
- GenerateModuleFromModuleMapAction CreateModuleAction(
- ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem);
-
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build)
- << Module->Name << ModuleFileName;
+ << ModuleName << ModuleFileName;
+
+ PreBuildStep(Instance);
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
const unsigned ThreadStackSize = 8 << 20;
llvm::CrashRecoveryContext CRC;
- CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); },
- ThreadStackSize);
+ CRC.RunSafelyOnThread(
+ [&]() {
+ GenerateModuleFromModuleMapAction Action;
+ Instance.ExecuteAction(Action);
+ },
+ ThreadStackSize);
+
+ PostBuildStep(Instance);
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build_done)
- << Module->Name;
+ << ModuleName;
// Delete the temporary module map file.
// FIXME: Even though we're executing under crash protection, it would still
@@ -1150,13 +1163,66 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance,
// doesn't make sense for all clients, so clean this up manually.
Instance.clearOutputFiles(/*EraseFiles=*/true);
+ return !Instance.getDiagnostics().hasErrorOccurred();
+}
+
+/// \brief Compile a module file for the given module, using the options
+/// provided by the importing compiler instance. Returns true if the module
+/// was built without errors.
+static bool compileModuleImpl(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc,
+ Module *Module,
+ StringRef ModuleFileName) {
+ InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()),
+ InputKind::ModuleMap);
+
+ // Get or create the module map that we'll use to build this module.
+ ModuleMap &ModMap
+ = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ bool Result;
+ if (const FileEntry *ModuleMapFile =
+ ModMap.getContainingModuleMapFile(Module)) {
+ // Use the module map where this module resides.
+ Result = compileModuleImpl(
+ ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
+ FrontendInputFile(ModuleMapFile->getName(), IK, +Module->IsSystem),
+ ModMap.getModuleMapFileForUniquing(Module)->getName(),
+ ModuleFileName);
+ } else {
+ // FIXME: We only need to fake up an input file here as a way of
+ // transporting the module's directory to the module map parser. We should
+ // be able to do that more directly, and parse from a memory buffer without
+ // inventing this file.
+ SmallString<128> FakeModuleMapFile(Module->Directory->getName());
+ llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map");
+
+ std::string InferredModuleMapContent;
+ llvm::raw_string_ostream OS(InferredModuleMapContent);
+ Module->print(OS);
+ OS.flush();
+
+ Result = compileModuleImpl(
+ ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
+ FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem),
+ ModMap.getModuleMapFileForUniquing(Module)->getName(),
+ ModuleFileName,
+ [&](CompilerInstance &Instance) {
+ std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
+ llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
+ ModuleMapFile = Instance.getFileManager().getVirtualFile(
+ FakeModuleMapFile, InferredModuleMapContent.size(), 0);
+ Instance.getSourceManager().overrideFileContents(
+ ModuleMapFile, std::move(ModuleMapBuffer));
+ });
+ }
+
// We've rebuilt a module. If we're allowed to generate or update the global
// module index, record that fact in the importing compiler instance.
if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) {
ImportingInstance.setBuildGlobalModuleIndex(true);
}
- return !Instance.getDiagnostics().hasErrorOccurred();
+ return Result;
}
static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
@@ -1180,10 +1246,14 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
llvm::LockFileManager Locked(ModuleFileName);
switch (Locked) {
case llvm::LockFileManager::LFS_Error:
- Diags.Report(ModuleNameLoc, diag::err_module_lock_failure)
+ // PCMCache takes care of correctness and locks are only necessary for
+ // performance. Fallback to building the module in case of any lock
+ // related errors.
+ Diags.Report(ModuleNameLoc, diag::remark_module_lock_failure)
<< Module->Name << Locked.getErrorMessage();
- return false;
-
+ // Clear out any potential leftover.
+ Locked.unsafeRemoveLockFile();
+ // FALLTHROUGH
case llvm::LockFileManager::LFS_Owned:
// We're responsible for building the module ourselves.
if (!compileModuleImpl(ImportingInstance, ModuleNameLoc, Module,
@@ -1203,11 +1273,14 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
case llvm::LockFileManager::Res_OwnerDied:
continue; // try again to get the lock.
case llvm::LockFileManager::Res_Timeout:
- Diags.Report(ModuleNameLoc, diag::err_module_lock_timeout)
+ // Since PCMCache takes care of correctness, we try waiting for another
+ // process to complete the build so clang does not do it done twice. If
+ // case of timeout, build it ourselves.
+ Diags.Report(ModuleNameLoc, diag::remark_module_lock_timeout)
<< Module->Name;
// Clear the lock file so that future invokations can make progress.
Locked.unsafeRemoveLockFile();
- return false;
+ continue;
}
break;
}
@@ -1400,7 +1473,7 @@ void CompilerInstance::createModuleManager() {
"Reading modules",
*FrontendTimerGroup);
ModuleManager = new ASTReader(
- getPreprocessor(), getASTContext(), getPCHContainerReader(),
+ getPreprocessor(), &getASTContext(), getPCHContainerReader(),
getFrontendOpts().ModuleFileExtensions,
Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation,
/*AllowASTWithCompilerErrors=*/false,
@@ -1555,24 +1628,36 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
PP->getHeaderSearchInfo().getHeaderSearchOpts();
std::string ModuleFileName;
- bool LoadFromPrebuiltModulePath = false;
- // We try to load the module from the prebuilt module paths. If not
- // successful, we then try to find it in the module cache.
- if (!HSOpts.PrebuiltModulePaths.empty()) {
- // Load the module from the prebuilt module path.
+ enum ModuleSource {
+ ModuleNotFound, ModuleCache, PrebuiltModulePath, ModuleBuildPragma
+ } Source = ModuleNotFound;
+
+ // Check to see if the module has been built as part of this compilation
+ // via a module build pragma.
+ auto BuiltModuleIt = BuiltModules.find(ModuleName);
+ if (BuiltModuleIt != BuiltModules.end()) {
+ ModuleFileName = BuiltModuleIt->second;
+ Source = ModuleBuildPragma;
+ }
+
+ // Try to load the module from the prebuilt module path.
+ if (Source == ModuleNotFound && !HSOpts.PrebuiltModulePaths.empty()) {
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(
ModuleName, "", /*UsePrebuiltPath*/ true);
if (!ModuleFileName.empty())
- LoadFromPrebuiltModulePath = true;
+ Source = PrebuiltModulePath;
}
- if (!LoadFromPrebuiltModulePath && Module) {
- // Load the module from the module cache.
+
+ // Try to load the module from the module cache.
+ if (Source == ModuleNotFound && Module) {
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
- } else if (!LoadFromPrebuiltModulePath) {
+ Source = ModuleCache;
+ }
+
+ if (Source == ModuleNotFound) {
// We can't find a module, error out here.
getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
+ << ModuleName << SourceRange(ImportLoc, ModuleNameLoc);
ModuleBuildFailed = true;
return ModuleLoadResult();
}
@@ -1600,20 +1685,20 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
*FrontendTimerGroup);
llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr);
- // Try to load the module file. If we are trying to load from the prebuilt
- // module path, we don't have the module map files and don't know how to
- // rebuild modules.
- unsigned ARRFlags = LoadFromPrebuiltModulePath ?
- ASTReader::ARR_ConfigurationMismatch :
- ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+ // Try to load the module file. If we are not trying to load from the
+ // module cache, we don't know how to rebuild modules.
+ unsigned ARRFlags = Source == ModuleCache ?
+ ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing :
+ ASTReader::ARR_ConfigurationMismatch;
switch (ModuleManager->ReadAST(ModuleFileName,
- LoadFromPrebuiltModulePath ?
- serialization::MK_PrebuiltModule :
- serialization::MK_ImplicitModule,
- ImportLoc,
- ARRFlags)) {
+ Source == PrebuiltModulePath
+ ? serialization::MK_PrebuiltModule
+ : Source == ModuleBuildPragma
+ ? serialization::MK_ExplicitModule
+ : serialization::MK_ImplicitModule,
+ ImportLoc, ARRFlags)) {
case ASTReader::Success: {
- if (LoadFromPrebuiltModulePath && !Module) {
+ if (Source != ModuleCache && !Module) {
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
if (!Module || !Module->getASTFile() ||
FileMgr->getFile(ModuleFileName) != Module->getASTFile()) {
@@ -1631,10 +1716,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
case ASTReader::OutOfDate:
case ASTReader::Missing: {
- if (LoadFromPrebuiltModulePath) {
- // We can't rebuild the module without a module map. Since ReadAST
- // already produces diagnostics for these two cases, we simply
- // error out here.
+ if (Source != ModuleCache) {
+ // We don't know the desired configuration for this module and don't
+ // necessarily even have a module map. Since ReadAST already produces
+ // diagnostics for these two cases, we simply error out here.
ModuleBuildFailed = true;
KnownModules[Path[0].first] = nullptr;
return ModuleLoadResult();
@@ -1691,11 +1776,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
}
case ASTReader::ConfigurationMismatch:
- if (LoadFromPrebuiltModulePath)
+ if (Source == PrebuiltModulePath)
+ // FIXME: We shouldn't be setting HadFatalFailure below if we only
+ // produce a warning here!
getDiagnostics().Report(SourceLocation(),
diag::warn_module_config_mismatch)
<< ModuleFileName;
// Fall through to error out.
+ LLVM_FALLTHROUGH;
case ASTReader::VersionMismatch:
case ASTReader::HadErrors:
ModuleLoader::HadFatalFailure = true;
@@ -1719,7 +1807,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// If we never found the module, fail.
if (!Module)
return ModuleLoadResult();
-
+
// Verify that the rest of the module path actually corresponds to
// a submodule.
if (Path.size() > 1) {
@@ -1792,20 +1880,10 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
}
// Check whether this module is available.
- clang::Module::Requirement Requirement;
- clang::Module::UnresolvedHeaderDirective MissingHeader;
- if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement,
- MissingHeader)) {
- if (MissingHeader.FileNameLoc.isValid()) {
- getDiagnostics().Report(MissingHeader.FileNameLoc,
- diag::err_module_header_missing)
- << MissingHeader.IsUmbrella << MissingHeader.FileName;
- } else {
- getDiagnostics().Report(ImportLoc, diag::err_module_unavailable)
- << Module->getFullModuleName()
- << Requirement.second << Requirement.first
- << SourceRange(Path.front().second, Path.back().second);
- }
+ if (Preprocessor::checkModuleIsAvailable(getLangOpts(), getTarget(),
+ getDiagnostics(), Module)) {
+ getDiagnostics().Report(ImportLoc, diag::note_module_import_here)
+ << SourceRange(Path.front().second, Path.back().second);
LastModuleImportLoc = ImportLoc;
LastModuleImportResult = ModuleLoadResult();
return ModuleLoadResult();
@@ -1826,6 +1904,59 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return LastModuleImportResult;
}
+void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc,
+ StringRef ModuleName,
+ StringRef Source) {
+ // Avoid creating filenames with special characters.
+ SmallString<128> CleanModuleName(ModuleName);
+ for (auto &C : CleanModuleName)
+ if (!isAlphanumeric(C))
+ C = '_';
+
+ // FIXME: Using a randomized filename here means that our intermediate .pcm
+ // output is nondeterministic (as .pcm files refer to each other by name).
+ // Can this affect the output in any way?
+ SmallString<128> ModuleFileName;
+ if (std::error_code EC = llvm::sys::fs::createTemporaryFile(
+ CleanModuleName, "pcm", ModuleFileName)) {
+ getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output)
+ << ModuleFileName << EC.message();
+ return;
+ }
+ std::string ModuleMapFileName = (CleanModuleName + ".map").str();
+
+ FrontendInputFile Input(
+ ModuleMapFileName,
+ InputKind(getLanguageFromOptions(*Invocation->getLangOpts()),
+ InputKind::ModuleMap, /*Preprocessed*/true));
+
+ std::string NullTerminatedSource(Source.str());
+
+ auto PreBuildStep = [&](CompilerInstance &Other) {
+ // Create a virtual file containing our desired source.
+ // FIXME: We shouldn't need to do this.
+ const FileEntry *ModuleMapFile = Other.getFileManager().getVirtualFile(
+ ModuleMapFileName, NullTerminatedSource.size(), 0);
+ Other.getSourceManager().overrideFileContents(
+ ModuleMapFile,
+ llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource.c_str()));
+
+ Other.BuiltModules = std::move(BuiltModules);
+ Other.DeleteBuiltModules = false;
+ };
+
+ auto PostBuildStep = [this](CompilerInstance &Other) {
+ BuiltModules = std::move(Other.BuiltModules);
+ };
+
+ // Build the module, inheriting any modules that we've built locally.
+ if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(),
+ ModuleFileName, PreBuildStep, PostBuildStep)) {
+ BuiltModules[ModuleName] = ModuleFileName.str();
+ llvm::sys::RemoveFileOnSignal(ModuleFileName);
+ }
+}
+
void CompilerInstance::makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
index 36f6b0a..0d0869c 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
@@ -81,7 +81,7 @@ using namespace llvm::opt;
static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
unsigned DefaultOpt = 0;
- if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable))
+ if (IK.getLanguage() == InputKind::OpenCL && !Args.hasArg(OPT_cl_opt_disable))
DefaultOpt = 2;
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
@@ -330,6 +330,17 @@ static StringRef getCodeModel(ArgList &Args, DiagnosticsEngine &Diags) {
return "default";
}
+static StringRef getRelocModel(ArgList &Args, DiagnosticsEngine &Diags) {
+ if (Arg *A = Args.getLastArg(OPT_mrelocation_model)) {
+ StringRef Value = A->getValue();
+ if (Value == "static" || Value == "pic" || Value == "ropi" ||
+ Value == "rwpi" || Value == "ropi-rwpi" || Value == "dynamic-no-pic")
+ return Value;
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Value;
+ }
+ return "pic";
+}
+
/// \brief Create a new Regex instance out of the string value in \p RpassArg.
/// It returns a pointer to the newly generated Regex instance.
static std::shared_ptr<llvm::Regex>
@@ -465,6 +476,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
OPT_fexperimental_new_pass_manager, OPT_fno_experimental_new_pass_manager,
/* Default */ false);
+ Opts.DebugPassManager =
+ Args.hasFlag(OPT_fdebug_pass_manager, OPT_fno_debug_pass_manager,
+ /* Default */ false);
+
if (Arg *A = Args.getLastArg(OPT_fveclib)) {
StringRef Name = A->getValue();
if (Name == "Accelerate")
@@ -505,8 +520,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 0, Diags);
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.EmitCodeView = Args.hasArg(OPT_gcodeview);
+ Opts.MacroDebugInfo = Args.hasArg(OPT_debug_info_macro);
Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables);
Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std);
+ Opts.EnableSplitDwarf = Args.hasArg(OPT_enable_split_dwarf);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
Opts.SplitDwarfInlining = !Args.hasArg(OPT_fno_split_dwarf_inlining);
Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs);
@@ -521,6 +538,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DisableLLVMPasses = Args.hasArg(OPT_disable_llvm_passes);
Opts.DisableLifetimeMarkers = Args.hasArg(OPT_disable_lifetimemarkers);
+ Opts.DisableO0ImplyOptNone = Args.hasArg(OPT_disable_O0_optnone);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
@@ -544,6 +562,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DisableIntegratedAS = Args.hasArg(OPT_fno_integrated_as);
Opts.Autolink = !Args.hasArg(OPT_fno_autolink);
Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ);
+ Opts.DebugInfoForProfiling = Args.hasFlag(
+ OPT_fdebug_info_for_profiling, OPT_fno_debug_info_for_profiling, false);
setPGOInstrumentor(Opts, Args, Diags);
Opts.InstrProfileOutput =
@@ -553,6 +573,33 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
if (!Opts.ProfileInstrumentUsePath.empty())
setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath);
+ if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) {
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest);
+
+ StringRef Ver = A->getValue();
+ std::pair<StringRef, StringRef> VerParts = Ver.split('.');
+ unsigned Major, Minor = 0;
+
+ // Check the version number is valid: either 3.x (0 <= x <= 9) or
+ // y or y.0 (4 <= y <= current version).
+ if (!VerParts.first.startswith("0") &&
+ !VerParts.first.getAsInteger(10, Major) &&
+ 3 <= Major && Major <= CLANG_VERSION_MAJOR &&
+ (Major == 3 ? VerParts.second.size() == 1 &&
+ !VerParts.second.getAsInteger(10, Minor)
+ : VerParts.first.size() == Ver.size() ||
+ VerParts.second == "0")) {
+ // Got a valid version number.
+ if (Major == 3 && Minor <= 8)
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver3_8);
+ else if (Major <= 4)
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4);
+ } else if (Ver != "latest") {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ }
+
Opts.CoverageMapping =
Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false);
Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping);
@@ -570,7 +617,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names);
Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);
Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
- Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable);
+ Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable) ||
+ Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
+ Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision);
Opts.NoInfsFPMath = (Args.hasArg(OPT_menable_no_infinities) ||
Args.hasArg(OPT_cl_finite_math_only) ||
@@ -580,7 +629,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_cl_finite_math_only) ||
Args.hasArg(OPT_cl_fast_relaxed_math));
Opts.NoSignedZeros = (Args.hasArg(OPT_fno_signed_zeros) ||
- Args.hasArg(OPT_cl_no_signed_zeros));
+ Args.hasArg(OPT_cl_no_signed_zeros) ||
+ Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
+ Args.hasArg(OPT_cl_fast_relaxed_math));
Opts.FlushDenorm = Args.hasArg(OPT_cl_denorms_are_zero);
Opts.CorrectlyRoundedDivSqrt =
Args.hasArg(OPT_cl_fp32_correctly_rounded_divide_sqrt);
@@ -608,7 +659,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Args.hasArg(OPT_cl_fast_relaxed_math);
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
- Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
+ Opts.RelocationModel = getRelocModel(Args, Diags);
Opts.ThreadModel = Args.getLastArgValue(OPT_mthread_model, "posix");
if (Opts.ThreadModel != "posix" && Opts.ThreadModel != "single")
Diags.Report(diag::err_drv_invalid_value)
@@ -629,18 +680,25 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables);
Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ);
- const Arg *A = Args.getLastArg(OPT_flto, OPT_flto_EQ);
- Opts.EmitSummaryIndex = A && A->containsValue("thin");
+ Opts.EmitSummaryIndex = false;
+ if (Arg *A = Args.getLastArg(OPT_flto_EQ)) {
+ StringRef S = A->getValue();
+ if (S == "thin")
+ Opts.EmitSummaryIndex = true;
+ else if (S != "full")
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
+ Opts.LTOUnit = Args.hasFlag(OPT_flto_unit, OPT_fno_lto_unit, false);
if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) {
- if (IK != IK_LLVM_IR)
+ if (IK.getLanguage() != InputKind::LLVM_IR)
Diags.Report(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-x ir";
Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ);
}
+ Opts.ThinLinkBitcodeFile = Args.getLastArgValue(OPT_fthin_link_bitcode_EQ);
Opts.MSVolatile = Args.hasArg(OPT_fms_volatile);
- Opts.VectorizeBB = Args.hasArg(OPT_vectorize_slp_aggressive);
Opts.VectorizeLoop = Args.hasArg(OPT_vectorize_loops);
Opts.VectorizeSLP = Args.hasArg(OPT_vectorize_slp);
@@ -709,21 +767,43 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
}
+ Opts.PreserveVec3Type = Args.hasArg(OPT_fpreserve_vec3_type);
Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
Opts.XRayInstrumentFunctions = Args.hasArg(OPT_fxray_instrument);
Opts.XRayInstructionThreshold =
- getLastArgIntValue(Args, OPT_fxray_instruction_threshold_, 200, Diags);
+ getLastArgIntValue(Args, OPT_fxray_instruction_threshold_EQ, 200, Diags);
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
+ Opts.CallFEntry = Args.hasArg(OPT_mfentry);
Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
- Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections);
+
+ if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
+ OPT_compress_debug_sections_EQ)) {
+ if (A->getOption().getID() == OPT_compress_debug_sections) {
+ // TODO: be more clever about the compression type auto-detection
+ Opts.setCompressDebugSections(llvm::DebugCompressionType::GNU);
+ } else {
+ auto DCT = llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
+ .Case("none", llvm::DebugCompressionType::None)
+ .Case("zlib", llvm::DebugCompressionType::Z)
+ .Case("zlib-gnu", llvm::DebugCompressionType::GNU)
+ .Default(llvm::DebugCompressionType::None);
+ Opts.setCompressDebugSections(DCT);
+ }
+ }
+
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
for (auto A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) {
- unsigned LinkFlags = llvm::Linker::Flags::None;
- if (A->getOption().matches(OPT_mlink_cuda_bitcode))
- LinkFlags = llvm::Linker::Flags::LinkOnlyNeeded |
- llvm::Linker::Flags::InternalizeLinkedSymbols;
- Opts.LinkBitcodeFiles.push_back(std::make_pair(LinkFlags, A->getValue()));
+ CodeGenOptions::BitcodeFileToLink F;
+ F.Filename = A->getValue();
+ if (A->getOption().matches(OPT_mlink_cuda_bitcode)) {
+ F.LinkFlags = llvm::Linker::Flags::LinkOnlyNeeded;
+ // When linking CUDA bitcode, propagate function attributes so that
+ // e.g. libdevice gets fast-math attrs if we're building with fast-math.
+ F.PropagateAttrs = true;
+ F.Internalize = true;
+ }
+ Opts.LinkBitcodeFiles.push_back(F);
}
Opts.SanitizeCoverageType =
getLastArgIntValue(Args, OPT_fsanitize_coverage_type, 0, Diags);
@@ -738,6 +818,9 @@ 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.SanitizeCoverageInline8bitCounters =
+ Args.hasArg(OPT_fsanitize_coverage_inline_8bit_counters);
Opts.SanitizeMemoryTrackOrigins =
getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags);
Opts.SanitizeMemoryUseAfterDtor =
@@ -749,6 +832,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeAddressUseAfterScope =
A->getOption().getID() == OPT_fsanitize_address_use_after_scope;
}
+ Opts.SanitizeAddressGlobalsDeadStripping =
+ Args.hasArg(OPT_fsanitize_address_globals_dead_stripping);
Opts.SSPBufferSize =
getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
@@ -801,18 +886,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
}
- if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
- StringRef Val = A->getValue();
- if (Val == "fast")
- Opts.setFPContractMode(CodeGenOptions::FPC_Fast);
- else if (Val == "on")
- Opts.setFPContractMode(CodeGenOptions::FPC_On);
- else if (Val == "off")
- Opts.setFPContractMode(CodeGenOptions::FPC_Off);
- else
- Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
- }
-
if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_EQ)) {
StringRef Val = A->getValue();
if (Val == "ieee")
@@ -862,14 +935,24 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DiagnosticsWithHotness =
Args.hasArg(options::OPT_fdiagnostics_show_hotness);
- if (Opts.DiagnosticsWithHotness &&
- Opts.getProfileUse() == CodeGenOptions::ProfileNone)
- Diags.Report(diag::warn_drv_fdiagnostics_show_hotness_requires_pgo);
+ bool UsingSampleProfile = !Opts.SampleProfileFile.empty();
+ bool UsingProfile = UsingSampleProfile ||
+ (Opts.getProfileUse() != CodeGenOptions::ProfileNone);
+
+ if (Opts.DiagnosticsWithHotness && !UsingProfile)
+ Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
+ << "-fdiagnostics-show-hotness";
+
+ Opts.DiagnosticsHotnessThreshold = getLastArgUInt64Value(
+ Args, options::OPT_fdiagnostics_hotness_threshold_EQ, 0);
+ if (Opts.DiagnosticsHotnessThreshold > 0 && !UsingProfile)
+ Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
+ << "-fdiagnostics-hotness-threshold=";
// If the user requested to use a sample profile for PGO, then the
// backend will need to track source location information so the profile
// can be incorporated into the IR.
- if (!Opts.SampleProfileFile.empty())
+ if (UsingSampleProfile)
NeedLocTracking = true;
// If the user requested a flag that requires source locations available in
@@ -1068,6 +1151,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.SpellCheckingLimit = getLastArgIntValue(
Args, OPT_fspell_checking_limit,
DiagnosticOptions::DefaultSpellCheckingLimit, Diags);
+ Opts.SnippetLineLimit = getLastArgIntValue(
+ Args, OPT_fcaret_diagnostics_max_lines,
+ DiagnosticOptions::DefaultSnippetLineLimit, Diags);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
@@ -1123,6 +1209,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
case OPT_ast_list:
Opts.ProgramAction = frontend::ASTDeclList; break;
case OPT_ast_dump:
+ case OPT_ast_dump_all:
case OPT_ast_dump_lookups:
Opts.ProgramAction = frontend::ASTDump; break;
case OPT_ast_print:
@@ -1241,6 +1328,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump);
+ Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all);
Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter);
Opts.ASTDumpLookups = Args.hasArg(OPT_ast_dump_lookups);
Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index);
@@ -1329,44 +1417,54 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
<< "ARC migration" << "ObjC migration";
}
- InputKind DashX = IK_None;
+ InputKind DashX(InputKind::Unknown);
if (const Arg *A = Args.getLastArg(OPT_x)) {
- DashX = llvm::StringSwitch<InputKind>(A->getValue())
- .Case("c", IK_C)
- .Case("cl", IK_OpenCL)
- .Case("cuda", IK_CUDA)
- .Case("c++", IK_CXX)
- .Case("c++-module", IK_CXX)
- .Case("objective-c", IK_ObjC)
- .Case("objective-c++", IK_ObjCXX)
- .Case("cpp-output", IK_PreprocessedC)
- .Case("assembler-with-cpp", IK_Asm)
- .Case("c++-cpp-output", IK_PreprocessedCXX)
- .Case("c++-module-cpp-output", IK_PreprocessedCXX)
- .Case("cuda-cpp-output", IK_PreprocessedCuda)
- .Case("objective-c-cpp-output", IK_PreprocessedObjC)
- .Case("objc-cpp-output", IK_PreprocessedObjC)
- .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX)
- .Case("objc++-cpp-output", IK_PreprocessedObjCXX)
- .Case("c-header", IK_C)
- .Case("cl-header", IK_OpenCL)
- .Case("objective-c-header", IK_ObjC)
- .Case("c++-header", IK_CXX)
- .Case("objective-c++-header", IK_ObjCXX)
- .Cases("ast", "pcm", IK_AST)
- .Case("ir", IK_LLVM_IR)
- .Case("renderscript", IK_RenderScript)
- .Default(IK_None);
- if (DashX == IK_None)
+ StringRef XValue = A->getValue();
+
+ // Parse suffixes: '<lang>(-header|[-module-map][-cpp-output])'.
+ // FIXME: Supporting '<lang>-header-cpp-output' would be useful.
+ bool Preprocessed = XValue.consume_back("-cpp-output");
+ bool ModuleMap = XValue.consume_back("-module-map");
+ IsHeaderFile =
+ !Preprocessed && !ModuleMap && XValue.consume_back("-header");
+
+ // Principal languages.
+ DashX = llvm::StringSwitch<InputKind>(XValue)
+ .Case("c", InputKind::C)
+ .Case("cl", InputKind::OpenCL)
+ .Case("cuda", InputKind::CUDA)
+ .Case("c++", InputKind::CXX)
+ .Case("objective-c", InputKind::ObjC)
+ .Case("objective-c++", InputKind::ObjCXX)
+ .Case("renderscript", InputKind::RenderScript)
+ .Default(InputKind::Unknown);
+
+ // "objc[++]-cpp-output" is an acceptable synonym for
+ // "objective-c[++]-cpp-output".
+ if (DashX.isUnknown() && Preprocessed && !IsHeaderFile && !ModuleMap)
+ DashX = llvm::StringSwitch<InputKind>(XValue)
+ .Case("objc", InputKind::ObjC)
+ .Case("objc++", InputKind::ObjCXX)
+ .Default(InputKind::Unknown);
+
+ // Some special cases cannot be combined with suffixes.
+ if (DashX.isUnknown() && !Preprocessed && !ModuleMap && !IsHeaderFile)
+ DashX = llvm::StringSwitch<InputKind>(XValue)
+ .Case("cpp-output", InputKind(InputKind::C).getPreprocessed())
+ .Case("assembler-with-cpp", InputKind::Asm)
+ .Cases("ast", "pcm",
+ InputKind(InputKind::Unknown, InputKind::Precompiled))
+ .Case("ir", InputKind::LLVM_IR)
+ .Default(InputKind::Unknown);
+
+ if (DashX.isUnknown())
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
- IsHeaderFile = llvm::StringSwitch<bool>(A->getValue())
- .Case("c-header", true)
- .Case("cl-header", true)
- .Case("objective-c-header", true)
- .Case("c++-header", true)
- .Case("objective-c++-header", true)
- .Default(false);
+
+ if (Preprocessed)
+ DashX = DashX.getPreprocessed();
+ if (ModuleMap)
+ DashX = DashX.withFormat(InputKind::ModuleMap);
}
// '-' is the default input if none is given.
@@ -1376,13 +1474,22 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Inputs.push_back("-");
for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
InputKind IK = DashX;
- if (IK == IK_None) {
+ if (IK.isUnknown()) {
IK = FrontendOptions::getInputKindForExtension(
StringRef(Inputs[i]).rsplit('.').second);
+ // FIXME: Warn on this?
+ if (IK.isUnknown())
+ IK = InputKind::C;
// FIXME: Remove this hack.
if (i == 0)
DashX = IK;
}
+
+ // The -emit-module action implicitly takes a module map.
+ if (Opts.ProgramAction == frontend::GenerateModule &&
+ IK.getFormat() == InputKind::Source)
+ IK = IK.withFormat(InputKind::ModuleMap);
+
Opts.Inputs.emplace_back(std::move(Inputs[i]), IK);
}
@@ -1407,7 +1514,8 @@ std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
return P.str();
}
-static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
+static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
+ const std::string &WorkingDir) {
using namespace options;
Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/");
Opts.Verbose = Args.hasArg(OPT_v);
@@ -1417,11 +1525,23 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ))
Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
- Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodules_cache_path);
+
+ // Canonicalize -fmodules-cache-path before storing it.
+ SmallString<128> P(Args.getLastArgValue(OPT_fmodules_cache_path));
+ if (!(P.empty() || llvm::sys::path::is_absolute(P))) {
+ if (WorkingDir.empty())
+ llvm::sys::fs::make_absolute(P);
+ else
+ llvm::sys::fs::make_absolute(WorkingDir, P);
+ }
+ llvm::sys::path::remove_dots(P);
+ Opts.ModuleCachePath = P.str();
+
Opts.ModuleUserBuildPath = Args.getLastArgValue(OPT_fmodules_user_build_path);
for (const Arg *A : Args.filtered(OPT_fprebuilt_module_path))
Opts.AddPrebuiltModulePath(A->getValue());
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
+ Opts.ModulesHashContent = Args.hasArg(OPT_fmodules_hash_content);
Opts.ModulesValidateDiagnosticOptions =
!Args.hasArg(OPT_fmodules_disable_diagnostic_validation);
Opts.ImplicitModuleMaps = Args.hasArg(OPT_fimplicit_module_maps);
@@ -1495,6 +1615,9 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
!A->getOption().matches(OPT_iwithsysroot));
for (const Arg *A : Args.filtered(OPT_iframework))
Opts.AddPath(A->getValue(), frontend::System, true, true);
+ for (const Arg *A : Args.filtered(OPT_iframeworkwithsysroot))
+ Opts.AddPath(A->getValue(), frontend::System, /*IsFramework=*/true,
+ /*IgnoreSysRoot=*/false);
// Add the paths for the various language specific isystem flags.
for (const Arg *A : Args.filtered(OPT_c_isystem))
@@ -1525,13 +1648,6 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.AddVFSOverlayFile(A->getValue());
}
-static bool isOpenCL(LangStandard::Kind LangStd) {
- return LangStd == LangStandard::lang_opencl ||
- LangStd == LangStandard::lang_opencl11 ||
- LangStd == LangStandard::lang_opencl12 ||
- LangStd == LangStandard::lang_opencl20;
-}
-
void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
const llvm::Triple &T,
PreprocessorOptions &PPOpts,
@@ -1539,49 +1655,48 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
// Set some properties which depend solely on the input kind; it would be nice
// to move these to the language standard, and have the driver resolve the
// input kind + language standard.
- if (IK == IK_Asm) {
+ //
+ // FIXME: Perhaps a better model would be for a single source file to have
+ // multiple language standards (C / C++ std, ObjC std, OpenCL std, OpenMP std)
+ // simultaneously active?
+ if (IK.getLanguage() == InputKind::Asm) {
Opts.AsmPreprocessor = 1;
- } else if (IK == IK_ObjC ||
- IK == IK_ObjCXX ||
- IK == IK_PreprocessedObjC ||
- IK == IK_PreprocessedObjCXX) {
+ } else if (IK.isObjectiveC()) {
Opts.ObjC1 = Opts.ObjC2 = 1;
}
if (LangStd == LangStandard::lang_unspecified) {
// Based on the base language, pick one.
- switch (IK) {
- case IK_None:
- case IK_AST:
- case IK_LLVM_IR:
+ switch (IK.getLanguage()) {
+ case InputKind::Unknown:
+ case InputKind::LLVM_IR:
llvm_unreachable("Invalid input kind!");
- case IK_OpenCL:
- LangStd = LangStandard::lang_opencl;
+ case InputKind::OpenCL:
+ LangStd = LangStandard::lang_opencl10;
break;
- case IK_CUDA:
- case IK_PreprocessedCuda:
+ case InputKind::CUDA:
LangStd = LangStandard::lang_cuda;
break;
- case IK_Asm:
- case IK_C:
- case IK_PreprocessedC:
+ case InputKind::Asm:
+ case InputKind::C:
// The PS4 uses C99 as the default C standard.
if (T.isPS4())
LangStd = LangStandard::lang_gnu99;
else
LangStd = LangStandard::lang_gnu11;
break;
- case IK_ObjC:
- case IK_PreprocessedObjC:
+ case InputKind::ObjC:
LangStd = LangStandard::lang_gnu11;
break;
- case IK_CXX:
- case IK_PreprocessedCXX:
- case IK_ObjCXX:
- case IK_PreprocessedObjCXX:
- LangStd = LangStandard::lang_gnucxx98;
+ case InputKind::CXX:
+ case InputKind::ObjCXX:
+ // The PS4 uses C++11 as the default C++ standard.
+ if (T.isPS4())
+ LangStd = LangStandard::lang_gnucxx11;
+ else
+ LangStd = LangStandard::lang_gnucxx98;
break;
- case IK_RenderScript:
+ case InputKind::RenderScript:
LangStd = LangStandard::lang_c99;
break;
}
@@ -1595,15 +1710,16 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.CPlusPlus11 = Std.isCPlusPlus11();
Opts.CPlusPlus14 = Std.isCPlusPlus14();
Opts.CPlusPlus1z = Std.isCPlusPlus1z();
+ Opts.CPlusPlus2a = Std.isCPlusPlus2a();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
- Opts.GNUInline = Std.isC89();
+ Opts.GNUInline = !Opts.C99 && !Opts.CPlusPlus;
Opts.HexFloats = Std.hasHexFloats();
Opts.ImplicitInt = Std.hasImplicitInt();
// Set OpenCL Version.
- Opts.OpenCL = isOpenCL(LangStd) || IK == IK_OpenCL;
- if (LangStd == LangStandard::lang_opencl)
+ Opts.OpenCL = Std.isOpenCL();
+ if (LangStd == LangStandard::lang_opencl10)
Opts.OpenCLVersion = 100;
else if (LangStd == LangStandard::lang_opencl11)
Opts.OpenCLVersion = 110;
@@ -1616,9 +1732,8 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
if (Opts.OpenCL) {
Opts.AltiVec = 0;
Opts.ZVector = 0;
- Opts.CXXOperatorNames = 1;
Opts.LaxVectorConversions = 0;
- Opts.DefaultFPContract = 1;
+ Opts.setDefaultFPContractMode(LangOptions::FPC_On);
Opts.NativeHalfType = 1;
Opts.NativeHalfArgsAndReturns = 1;
// Include default header file for OpenCL.
@@ -1627,10 +1742,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
}
}
- Opts.CUDA = IK == IK_CUDA || IK == IK_PreprocessedCuda ||
- LangStd == LangStandard::lang_cuda;
+ Opts.CUDA = IK.getLanguage() == InputKind::CUDA;
+ if (Opts.CUDA)
+ // Set default FP_CONTRACT to FAST.
+ Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
- Opts.RenderScript = IK == IK_RenderScript;
+ Opts.RenderScript = IK.getLanguage() == InputKind::RenderScript;
if (Opts.RenderScript) {
Opts.NativeHalfType = 1;
Opts.NativeHalfArgsAndReturns = 1;
@@ -1671,6 +1788,70 @@ static Visibility parseVisibility(Arg *arg, ArgList &args,
return DefaultVisibility;
}
+/// Check if input file kind and language standard are compatible.
+static bool IsInputCompatibleWithStandard(InputKind IK,
+ const LangStandard &S) {
+ switch (IK.getLanguage()) {
+ case InputKind::Unknown:
+ case InputKind::LLVM_IR:
+ llvm_unreachable("should not parse language flags for this input");
+
+ case InputKind::C:
+ case InputKind::ObjC:
+ case InputKind::RenderScript:
+ return S.getLanguage() == InputKind::C;
+
+ case InputKind::OpenCL:
+ return S.getLanguage() == InputKind::OpenCL;
+
+ case InputKind::CXX:
+ case InputKind::ObjCXX:
+ return S.getLanguage() == InputKind::CXX;
+
+ case InputKind::CUDA:
+ // FIXME: What -std= values should be permitted for CUDA compilations?
+ return S.getLanguage() == InputKind::CUDA ||
+ S.getLanguage() == InputKind::CXX;
+
+ case InputKind::Asm:
+ // Accept (and ignore) all -std= values.
+ // FIXME: The -std= value is not ignored; it affects the tokenization
+ // and preprocessing rules if we're preprocessing this asm input.
+ return true;
+ }
+
+ llvm_unreachable("unexpected input language");
+}
+
+/// Get language name for given input kind.
+static const StringRef GetInputKindName(InputKind IK) {
+ switch (IK.getLanguage()) {
+ case InputKind::C:
+ return "C";
+ case InputKind::ObjC:
+ return "Objective-C";
+ case InputKind::CXX:
+ return "C++";
+ case InputKind::ObjCXX:
+ return "Objective-C++";
+ case InputKind::OpenCL:
+ return "OpenCL";
+ case InputKind::CUDA:
+ return "CUDA";
+ case InputKind::RenderScript:
+ return "RenderScript";
+
+ case InputKind::Asm:
+ return "Asm";
+ case InputKind::LLVM_IR:
+ return "LLVM IR";
+
+ case InputKind::Unknown:
+ break;
+ }
+ llvm_unreachable("unknown input language");
+}
+
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
const TargetOptions &TargetOpts,
PreprocessorOptions &PPOpts,
@@ -1679,49 +1860,45 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
.Case(name, LangStandard::lang_##id)
#define LANGSTANDARD_ALIAS(id, alias) \
.Case(alias, LangStandard::lang_##id)
#include "clang/Frontend/LangStandards.def"
.Default(LangStandard::lang_unspecified);
- if (LangStd == LangStandard::lang_unspecified)
+ if (LangStd == LangStandard::lang_unspecified) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
- else {
+ // Report supported standards with short description.
+ for (unsigned KindValue = 0;
+ KindValue != LangStandard::lang_unspecified;
+ ++KindValue) {
+ const LangStandard &Std = LangStandard::getLangStandardForKind(
+ static_cast<LangStandard::Kind>(KindValue));
+ if (IsInputCompatibleWithStandard(IK, Std)) {
+ auto Diag = Diags.Report(diag::note_drv_use_standard);
+ Diag << Std.getName() << Std.getDescription();
+ unsigned NumAliases = 0;
+#define LANGSTANDARD(id, name, lang, desc, features)
+#define LANGSTANDARD_ALIAS(id, alias) \
+ if (KindValue == LangStandard::lang_##id) ++NumAliases;
+#define LANGSTANDARD_ALIAS_DEPR(id, alias)
+#include "clang/Frontend/LangStandards.def"
+ Diag << NumAliases;
+#define LANGSTANDARD(id, name, lang, desc, features)
+#define LANGSTANDARD_ALIAS(id, alias) \
+ if (KindValue == LangStandard::lang_##id) Diag << alias;
+#define LANGSTANDARD_ALIAS_DEPR(id, alias)
+#include "clang/Frontend/LangStandards.def"
+ }
+ }
+ } else {
// Valid standard, check to make sure language and standard are
// compatible.
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
- switch (IK) {
- case IK_C:
- case IK_ObjC:
- case IK_PreprocessedC:
- case IK_PreprocessedObjC:
- if (!(Std.isC89() || Std.isC99()))
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "C/ObjC";
- break;
- case IK_CXX:
- case IK_ObjCXX:
- case IK_PreprocessedCXX:
- case IK_PreprocessedObjCXX:
- if (!Std.isCPlusPlus())
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "C++/ObjC++";
- break;
- case IK_OpenCL:
- if (!isOpenCL(LangStd))
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "OpenCL";
- break;
- case IK_CUDA:
- case IK_PreprocessedCuda:
- if (!Std.isCPlusPlus())
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "CUDA";
- break;
- default:
- break;
+ if (!IsInputCompatibleWithStandard(IK, Std)) {
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << GetInputKindName(IK);
}
}
}
@@ -1730,16 +1907,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// Override the -std option in this case.
if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
LangStandard::Kind OpenCLLangStd
- = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
- .Cases("cl", "CL", LangStandard::lang_opencl)
- .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11)
- .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12)
- .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20)
- .Default(LangStandard::lang_unspecified);
+ = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
+ .Cases("cl", "CL", LangStandard::lang_opencl10)
+ .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11)
+ .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12)
+ .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20)
+ .Default(LangStandard::lang_unspecified);
if (OpenCLLangStd == LangStandard::lang_unspecified) {
Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << A->getValue();
+ << A->getAsString(Args) << A->getValue();
}
else
LangStd = OpenCLLangStd;
@@ -1840,8 +2017,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fgnu89_inline)) {
if (Opts.CPlusPlus)
- Diags.Report(diag::err_drv_argument_not_allowed_with) << "-fgnu89-inline"
- << "C++/ObjC++";
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << "-fgnu89-inline" << GetInputKindName(IK);
else
Opts.GNUInline = 1;
}
@@ -1858,9 +2035,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_constant_cfstrings))
Opts.NoConstantCFStrings = 1;
- if (Args.hasArg(OPT_faltivec))
- Opts.AltiVec = 1;
-
if (Args.hasArg(OPT_fzvector))
Opts.ZVector = 1;
@@ -1947,6 +2121,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse;
Opts.ModulesLocalVisibility =
Args.hasArg(OPT_fmodules_local_submodule_visibility) || Opts.ModulesTS;
+ Opts.ModulesCodegen = Args.hasArg(OPT_fmodules_codegen);
+ Opts.ModulesDebugInfo = Args.hasArg(OPT_fmodules_debuginfo);
Opts.ModulesSearchAll = Opts.Modules &&
!Args.hasArg(OPT_fno_modules_search_all) &&
Args.hasArg(OPT_fmodules_search_all);
@@ -1967,6 +2143,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.AlignedAllocation =
Args.hasFlag(OPT_faligned_allocation, OPT_fno_aligned_allocation,
Opts.AlignedAllocation);
+ Opts.AlignedAllocationUnavailable =
+ Opts.AlignedAllocation && Args.hasArg(OPT_aligned_alloc_unavailable);
Opts.NewAlignOverride =
getLastArgIntValue(Args, OPT_fnew_alignment_EQ, 0, Diags);
if (Opts.NewAlignOverride && !llvm::isPowerOf2_32(Opts.NewAlignOverride)) {
@@ -2045,12 +2223,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.hasFlag(OPT_fdeclspec, OPT_fno_declspec,
(Opts.MicrosoftExt || Opts.Borland || Opts.CUDA));
- // For now, we only support local submodule visibility in C++ (because we
- // heavily depend on the ODR for merging redefinitions).
- if (Opts.ModulesLocalVisibility && !Opts.CPlusPlus)
- Diags.Report(diag::err_drv_argument_not_allowed_with)
- << "-fmodules-local-submodule-visibility" << "C";
-
if (Arg *A = Args.getLastArg(OPT_faddress_space_map_mangling_EQ)) {
switch (llvm::StringSwitch<unsigned>(A->getValue())
.Case("target", LangOptions::ASMM_Target)
@@ -2108,8 +2280,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
llvm::Triple T(TargetOpts.Triple);
llvm::Triple::ArchType Arch = T.getArch();
bool emitError = (DefaultCC == LangOptions::DCC_FastCall ||
- DefaultCC == LangOptions::DCC_StdCall) &&
- Arch != llvm::Triple::x86;
+ DefaultCC == LangOptions::DCC_StdCall) &&
+ Arch != llvm::Triple::x86;
emitError |= DefaultCC == LangOptions::DCC_VectorCall &&
!(Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64);
if (emitError)
@@ -2214,6 +2386,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_cl_unsafe_math_optimizations) ||
Args.hasArg(OPT_cl_fast_relaxed_math);
+ if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
+ StringRef Val = A->getValue();
+ if (Val == "fast")
+ Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
+ else if (Val == "on")
+ Opts.setDefaultFPContractMode(LangOptions::FPC_On);
+ else if (Val == "off")
+ Opts.setDefaultFPContractMode(LangOptions::FPC_Off);
+ else
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+ }
+
Opts.RetainCommentsFromSystemHeaders =
Args.hasArg(OPT_fretain_comments_from_system_headers);
@@ -2236,11 +2420,66 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeAddressFieldPadding =
getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags);
Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist);
+
+ // -fxray-instrument
+ Opts.XRayInstrument =
+ Args.hasFlag(OPT_fxray_instrument, OPT_fnoxray_instrument, false);
+
+ // -fxray-{always,never}-instrument= filenames.
+ Opts.XRayAlwaysInstrumentFiles =
+ Args.getAllArgValues(OPT_fxray_always_instrument);
+ Opts.XRayNeverInstrumentFiles =
+ Args.getAllArgValues(OPT_fxray_never_instrument);
+
+ // -fallow-editor-placeholders
+ Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders);
+}
+
+static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
+ switch (Action) {
+ case frontend::ASTDeclList:
+ case frontend::ASTDump:
+ case frontend::ASTPrint:
+ case frontend::ASTView:
+ case frontend::EmitAssembly:
+ case frontend::EmitBC:
+ case frontend::EmitHTML:
+ case frontend::EmitLLVM:
+ case frontend::EmitLLVMOnly:
+ case frontend::EmitCodeGenOnly:
+ case frontend::EmitObj:
+ case frontend::FixIt:
+ case frontend::GenerateModule:
+ case frontend::GenerateModuleInterface:
+ case frontend::GeneratePCH:
+ case frontend::GeneratePTH:
+ case frontend::ParseSyntaxOnly:
+ case frontend::ModuleFileInfo:
+ case frontend::VerifyPCH:
+ case frontend::PluginAction:
+ case frontend::PrintDeclContext:
+ case frontend::RewriteObjC:
+ case frontend::RewriteTest:
+ case frontend::RunAnalysis:
+ case frontend::MigrateSource:
+ return false;
+
+ case frontend::DumpRawTokens:
+ case frontend::DumpTokens:
+ case frontend::InitOnly:
+ case frontend::PrintPreamble:
+ case frontend::PrintPreprocessedInput:
+ case frontend::RewriteMacros:
+ case frontend::RunPreprocessorOnly:
+ return true;
+ }
+ llvm_unreachable("invalid frontend action");
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
FileManager &FileMgr,
- DiagnosticsEngine &Diags) {
+ DiagnosticsEngine &Diags,
+ frontend::ActionKind Action) {
using namespace options;
Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
@@ -2251,6 +2490,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.UsePredefines = !Args.hasArg(OPT_undef);
Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch);
+ Opts.AllowPCHWithCompilerErrors = Args.hasArg(OPT_fallow_pch_with_errors);
Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls);
for (const Arg *A : Args.filtered(OPT_error_on_deserialized_pch_decl))
@@ -2312,6 +2552,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
else
Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library;
}
+
+ // Always avoid lexing editor placeholders when we're just running the
+ // preprocessor as we never want to emit the
+ // "editor placeholder in source file" error in PP only mode.
+ if (isStrictlyPreprocessorAction(Action))
+ Opts.LexEditorPlaceholders = false;
}
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
@@ -2319,45 +2565,10 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
frontend::ActionKind Action) {
using namespace options;
- switch (Action) {
- case frontend::ASTDeclList:
- case frontend::ASTDump:
- case frontend::ASTPrint:
- case frontend::ASTView:
- case frontend::EmitAssembly:
- case frontend::EmitBC:
- case frontend::EmitHTML:
- case frontend::EmitLLVM:
- case frontend::EmitLLVMOnly:
- case frontend::EmitCodeGenOnly:
- case frontend::EmitObj:
- case frontend::FixIt:
- case frontend::GenerateModule:
- case frontend::GenerateModuleInterface:
- case frontend::GeneratePCH:
- case frontend::GeneratePTH:
- case frontend::ParseSyntaxOnly:
- case frontend::ModuleFileInfo:
- case frontend::VerifyPCH:
- case frontend::PluginAction:
- case frontend::PrintDeclContext:
- case frontend::RewriteObjC:
- case frontend::RewriteTest:
- case frontend::RunAnalysis:
- case frontend::MigrateSource:
- Opts.ShowCPP = 0;
- break;
-
- case frontend::DumpRawTokens:
- case frontend::DumpTokens:
- case frontend::InitOnly:
- case frontend::PrintPreamble:
- case frontend::PrintPreprocessedInput:
- case frontend::RewriteMacros:
- case frontend::RunPreprocessorOnly:
+ if (isStrictlyPreprocessorAction(Action))
Opts.ShowCPP = !Args.hasArg(OPT_dM);
- break;
- }
+ else
+ Opts.ShowCPP = 0;
Opts.ShowComments = Args.hasArg(OPT_C);
Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
@@ -2365,6 +2576,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
Opts.ShowIncludeDirectives = Args.hasArg(OPT_dI);
Opts.RewriteIncludes = Args.hasArg(OPT_frewrite_includes);
+ Opts.RewriteImports = Args.hasArg(OPT_frewrite_imports);
Opts.UseLineDirectives = Args.hasArg(OPT_fuse_line_directives);
}
@@ -2384,7 +2596,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args,
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
<< Value;
else
- Opts.EABIVersion = Value;
+ Opts.EABIVersion = EABIVersion;
}
Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
Opts.FPMath = Args.getLastArgValue(OPT_mfpmath);
@@ -2405,7 +2617,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
bool Success = true;
// Parse the arguments.
- std::unique_ptr<OptTable> Opts(createDriverOptTable());
+ std::unique_ptr<OptTable> Opts = createDriverOptTable();
const unsigned IncludedFlagsBitmask = options::CC1Option;
unsigned MissingArgIndex, MissingArgCount;
InputArgList Args =
@@ -2440,8 +2652,10 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParseTargetArgs(Res.getTargetOpts(), Args, Diags);
Success &= ParseCodeGenArgs(Res.getCodeGenOpts(), Args, DashX, Diags,
Res.getTargetOpts());
- ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args);
- if (DashX == IK_AST || DashX == IK_LLVM_IR) {
+ ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args,
+ Res.getFileSystemOpts().WorkingDir);
+ if (DashX.getFormat() == InputKind::Precompiled ||
+ DashX.getLanguage() == InputKind::LLVM_IR) {
// ObjCAAutoRefCount and Sanitize LangOpts are used to setup the
// PassManager in BackendUtil.cpp. They need to be initializd no matter
// what the input type is.
@@ -2455,8 +2669,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Diags, LangOpts.Sanitize);
} else {
// Other LangOpts are only initialzed when the input is not AST or LLVM IR.
+ // FIXME: Should we really be calling this for an InputKind::Asm input?
ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
- Res.getPreprocessorOpts(), Diags);
+ Res.getPreprocessorOpts(), Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
LangOpts.ObjCExceptions = 1;
}
@@ -2466,12 +2681,12 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// triple used for host compilation.
if (LangOpts.CUDAIsDevice)
Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
-
- // Set default FP_CONTRACT to FAST.
- if (!Args.hasArg(OPT_ffp_contract))
- Res.getCodeGenOpts().setFPContractMode(CodeGenOptions::FPC_Fast);
}
+ // Set the triple of the host for OpenMP device compile.
+ if (LangOpts.OpenMPIsDevice)
+ Res.getTargetOpts().HostTriple = Res.getFrontendOpts().AuxTriple;
+
// FIXME: Override value name discarding when asan or msan is used because the
// backend passes depend on the name of the alloca in order to print out
// names.
@@ -2484,7 +2699,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// ParsePreprocessorArgs and remove the FileManager
// parameters from the function and the "FileManager.h" #include.
FileManager FileMgr(Res.getFileSystemOpts());
- ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags);
+ ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags,
+ Res.getFrontendOpts().ProgramAction);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args,
Res.getFrontendOpts().ProgramAction);
@@ -2569,28 +2785,12 @@ std::string CompilerInvocation::getModuleHash() const {
code = ext->hashExtension(code);
}
- // Darwin-specific hack: if we have a sysroot, use the contents and
- // modification time of
- // $sysroot/System/Library/CoreServices/SystemVersion.plist
- // as part of the module hash.
- if (!hsOpts.Sysroot.empty()) {
- SmallString<128> systemVersionFile;
- systemVersionFile += hsOpts.Sysroot;
- llvm::sys::path::append(systemVersionFile, "System");
- llvm::sys::path::append(systemVersionFile, "Library");
- llvm::sys::path::append(systemVersionFile, "CoreServices");
- llvm::sys::path::append(systemVersionFile, "SystemVersion.plist");
-
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
- llvm::MemoryBuffer::getFile(systemVersionFile);
- if (buffer) {
- code = hash_combine(code, buffer.get()->getBuffer());
-
- struct stat statBuf;
- if (stat(systemVersionFile.c_str(), &statBuf) == 0)
- code = hash_combine(code, statBuf.st_mtime);
- }
- }
+ // Extend the signature with the enabled sanitizers, if at least one is
+ // enabled. Sanitizers which cannot affect AST generation aren't hashed.
+ SanitizerSet SanHash = LangOpts->Sanitize;
+ SanHash.clear(getPPTransparentSanitizers());
+ if (!SanHash.empty())
+ code = hash_combine(code, SanHash.Mask);
return llvm::APInt(64, code).toString(36, /*Signed=*/false);
}
@@ -2643,15 +2843,22 @@ void BuryPointer(const void *Ptr) {
IntrusiveRefCntPtr<vfs::FileSystem>
createVFSFromCompilerInvocation(const CompilerInvocation &CI,
DiagnosticsEngine &Diags) {
+ return createVFSFromCompilerInvocation(CI, Diags, vfs::getRealFileSystem());
+}
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+ DiagnosticsEngine &Diags,
+ IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
- return vfs::getRealFileSystem();
+ return BaseFS;
- IntrusiveRefCntPtr<vfs::OverlayFileSystem>
- Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> Overlay(
+ new vfs::OverlayFileSystem(BaseFS));
// earlier vfs files are on the bottom
for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
- llvm::MemoryBuffer::getFile(File);
+ BaseFS->getBufferForFile(File);
if (!Buffer) {
Diags.Report(diag::err_missing_vfs_overlay_file) << File;
return IntrusiveRefCntPtr<vfs::FileSystem>();
diff --git a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 1626906..c3ce7ce 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -31,8 +31,8 @@ using namespace llvm::opt;
/// \return A CompilerInvocation, or 0 if none was built for the given
/// argument vector.
std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
- ArrayRef<const char *> ArgList,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
+ ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
if (!Diags.get()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -46,12 +46,14 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(),
- *Diags);
+ *Diags, VFS);
// Don't check that inputs exist, they may have been remapped.
TheDriver.setCheckInputsExist(false);
std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
+ if (!C)
+ return nullptr;
// Just print the cc1 options if -### was present.
if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
index bd14c53..561eb9c 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
@@ -55,8 +55,8 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
llvm::sys::path::remove_leading_dotslash(FE->getName());
DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
- FileType != SrcMgr::C_User,
- /*IsModuleFile*/false, /*IsMissing*/false);
+ isSystem(FileType),
+ /*IsModuleFile*/false, /*IsMissing*/false);
}
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
@@ -265,7 +265,7 @@ bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
if (IncludeSystemHeaders)
return true;
- return FileType == SrcMgr::C_User;
+ return !isSystem(FileType);
}
void DFGImpl::FileChanged(SourceLocation Loc,
diff --git a/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp b/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
index 177feac..e326384 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
@@ -76,20 +76,19 @@ static void mergeFixits(ArrayRef<FixItHint> FixItHints,
}
}
-void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
+void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
StringRef Message,
ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> FixItHints,
- const SourceManager *SM,
DiagOrStoredDiag D) {
- assert(SM || Loc.isInvalid());
+ assert(Loc.hasManager() || Loc.isInvalid());
beginDiagnostic(D, Level);
if (!Loc.isValid())
// If we have no source location, just emit the diagnostic message.
- emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D);
+ emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, D);
else {
// Get the ranges into a local array we can hack on.
SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
@@ -97,7 +96,7 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
SmallVector<FixItHint, 8> MergedFixits;
if (!FixItHints.empty()) {
- mergeFixits(FixItHints, *SM, LangOpts, MergedFixits);
+ mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits);
FixItHints = MergedFixits;
}
@@ -107,25 +106,25 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
if (I->RemoveRange.isValid())
MutableRanges.push_back(I->RemoveRange);
- SourceLocation UnexpandedLoc = Loc;
+ FullSourceLoc UnexpandedLoc = Loc;
// Find the ultimate expansion location for the diagnostic.
- Loc = SM->getFileLoc(Loc);
+ Loc = Loc.getFileLoc();
- PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+ PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
// First, if this diagnostic is not in the main file, print out the
// "included from" lines.
- emitIncludeStack(Loc, PLoc, Level, *SM);
+ emitIncludeStack(Loc, PLoc, Level);
// Next, emit the actual diagnostic message and caret.
- emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D);
- emitCaret(Loc, Level, MutableRanges, FixItHints, *SM);
+ emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D);
+ emitCaret(Loc, Level, MutableRanges, FixItHints);
// If this location is within a macro, walk from UnexpandedLoc up to Loc
// and produce a macro backtrace.
if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
- emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM);
+ emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
}
}
@@ -139,15 +138,12 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
Diag.getRanges(), Diag.getFixIts(),
- Diag.getLocation().isValid() ? &Diag.getLocation().getManager()
- : nullptr,
&Diag);
}
void DiagnosticRenderer::emitBasicNote(StringRef Message) {
- emitDiagnosticMessage(
- SourceLocation(), PresumedLoc(), DiagnosticsEngine::Note, Message,
- None, nullptr, DiagOrStoredDiag());
+ emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note,
+ Message, None, DiagOrStoredDiag());
}
/// \brief Prints an include stack when appropriate for a particular
@@ -161,12 +157,11 @@ void DiagnosticRenderer::emitBasicNote(StringRef Message) {
/// \param Loc The diagnostic location.
/// \param PLoc The presumed location of the diagnostic location.
/// \param Level The diagnostic level of the message this stack pertains to.
-void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- const SourceManager &SM) {
- SourceLocation IncludeLoc =
- PLoc.isInvalid() ? SourceLocation() : PLoc.getIncludeLoc();
+void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level) {
+ FullSourceLoc IncludeLoc =
+ PLoc.isInvalid() ? FullSourceLoc()
+ : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager());
// Skip redundant include stacks altogether.
if (LastIncludeLoc == IncludeLoc)
@@ -178,74 +173,70 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
return;
if (IncludeLoc.isValid())
- emitIncludeStackRecursively(IncludeLoc, SM);
+ emitIncludeStackRecursively(IncludeLoc);
else {
- emitModuleBuildStack(SM);
- emitImportStack(Loc, SM);
+ emitModuleBuildStack(Loc.getManager());
+ emitImportStack(Loc);
}
}
/// \brief Helper to recursivly walk up the include stack and print each layer
/// on the way back down.
-void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
- const SourceManager &SM) {
+void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {
if (Loc.isInvalid()) {
- emitModuleBuildStack(SM);
+ emitModuleBuildStack(Loc.getManager());
return;
}
-
- PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+
+ PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
if (PLoc.isInvalid())
return;
// If this source location was imported from a module, print the module
// import stack rather than the
// FIXME: We want submodule granularity here.
- std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc);
+ std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc();
if (!Imported.second.empty()) {
// This location was imported by a module. Emit the module import stack.
- emitImportStackRecursively(Imported.first, Imported.second, SM);
+ emitImportStackRecursively(Imported.first, Imported.second);
return;
}
// Emit the other include frames first.
- emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM);
-
+ emitIncludeStackRecursively(
+ FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()));
+
// Emit the inclusion text/note.
- emitIncludeLocation(Loc, PLoc, SM);
+ emitIncludeLocation(Loc, PLoc);
}
/// \brief Emit the module import stack associated with the current location.
-void DiagnosticRenderer::emitImportStack(SourceLocation Loc,
- const SourceManager &SM) {
+void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) {
if (Loc.isInvalid()) {
- emitModuleBuildStack(SM);
+ emitModuleBuildStack(Loc.getManager());
return;
}
- std::pair<SourceLocation, StringRef> NextImportLoc
- = SM.getModuleImportLoc(Loc);
- emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+ std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
}
/// \brief Helper to recursivly walk up the import stack and print each layer
/// on the way back down.
-void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
- StringRef ModuleName,
- const SourceManager &SM) {
+void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
+ StringRef ModuleName) {
if (ModuleName.empty()) {
return;
}
- PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+ PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
// Emit the other import frames first.
- std::pair<SourceLocation, StringRef> NextImportLoc
- = SM.getModuleImportLoc(Loc);
- emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+ std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
// Emit the inclusion text/note.
- emitImportLocation(Loc, PLoc, ModuleName, SM);
+ emitImportLocation(Loc, PLoc, ModuleName);
}
/// \brief Emit the module build stack, for cases where a module is (re-)built
@@ -253,13 +244,9 @@ void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
ModuleBuildStack Stack = SM.getModuleBuildStack();
for (unsigned I = 0, N = Stack.size(); I != N; ++I) {
- const SourceManager &CurSM = Stack[I].second.getManager();
- SourceLocation CurLoc = Stack[I].second;
- emitBuildingModuleLocation(CurLoc,
- CurSM.getPresumedLoc(CurLoc,
+ emitBuildingModuleLocation(Stack[I].second, Stack[I].second.getPresumedLoc(
DiagOpts->ShowPresumedLoc),
- Stack[I].first,
- CurSM);
+ Stack[I].first);
}
}
@@ -348,12 +335,12 @@ static void computeCommonMacroArgExpansionFileIDs(
// in the same expansion as the caret; otherwise, we crawl to the top of
// each chain. Two locations are part of the same macro expansion
// iff the FileID is the same.
-static void mapDiagnosticRanges(
- SourceLocation CaretLoc,
- ArrayRef<CharSourceRange> Ranges,
- SmallVectorImpl<CharSourceRange> &SpellingRanges,
- const SourceManager *SM) {
- FileID CaretLocFileID = SM->getFileID(CaretLoc);
+static void
+mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef<CharSourceRange> Ranges,
+ SmallVectorImpl<CharSourceRange> &SpellingRanges) {
+ FileID CaretLocFileID = CaretLoc.getFileID();
+
+ const SourceManager *SM = &CaretLoc.getManager();
for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
if (I->isInvalid()) continue;
@@ -404,42 +391,39 @@ static void mapDiagnosticRanges(
}
}
-void DiagnosticRenderer::emitCaret(SourceLocation Loc,
+void DiagnosticRenderer::emitCaret(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+ ArrayRef<FixItHint> Hints) {
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
- emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
+ emitCodeContext(Loc, Level, SpellingRanges, Hints);
}
/// \brief A helper function for emitMacroExpansion to print the
/// macro expansion message
void DiagnosticRenderer::emitSingleMacroExpansion(
- SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {
+ FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) {
// Find the spelling location for the macro definition. We must use the
// spelling location here to avoid emitting a macro backtrace for the note.
- SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
+ FullSourceLoc SpellingLoc = Loc.getSpellingLoc();
// Map the ranges into the FileID of the diagnostic location.
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
SmallString<100> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
- StringRef MacroName =
- Lexer::getImmediateMacroNameForDiagnostics(Loc, SM, LangOpts);
+ StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
+ Loc, Loc.getManager(), LangOpts);
if (MacroName.empty())
Message << "expanded from here";
else
Message << "expanded from macro '" << MacroName << "'";
emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(),
- SpellingRanges, None, &SM);
+ SpellingRanges, None);
}
/// Check that the macro argument location of Loc starts with ArgumentLoc.
@@ -473,13 +457,12 @@ static bool checkRangeForMacroArgExpansion(CharSourceRange Range,
/// A helper function to check if the current ranges are all inside the same
/// macro argument expansion as Loc.
-static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {
+static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc,
+ ArrayRef<CharSourceRange> Ranges) {
assert(Loc.isMacroID() && "Must be a macro expansion!");
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges);
/// Count all valid ranges.
unsigned ValidCount = 0;
@@ -490,15 +473,15 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
return false;
/// To store the source location of the argument location.
- SourceLocation ArgumentLoc;
+ FullSourceLoc ArgumentLoc;
/// Set the ArgumentLoc to the beginning location of the expansion of Loc
/// so to check if the ranges expands to the same beginning location.
- if (!SM.isMacroArgExpansion(Loc,&ArgumentLoc))
+ if (!Loc.isMacroArgExpansion(&ArgumentLoc))
return false;
for (auto I = SpellingRanges.begin(), E = SpellingRanges.end(); I != E; ++I) {
- if (!checkRangeForMacroArgExpansion(*I, SM, ArgumentLoc))
+ if (!checkRangeForMacroArgExpansion(*I, Loc.getManager(), ArgumentLoc))
return false;
}
@@ -516,34 +499,33 @@ static bool checkRangesForMacroArgExpansion(SourceLocation Loc,
/// \param Level The diagnostic level currently being emitted.
/// \param Ranges The underlined ranges for this code snippet.
/// \param Hints The FixIt hints active for this diagnostic.
-void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
+void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+ ArrayRef<FixItHint> Hints) {
assert(Loc.isValid() && "must have a valid source location here");
// Produce a stack of macro backtraces.
- SmallVector<SourceLocation, 8> LocationStack;
+ SmallVector<FullSourceLoc, 8> LocationStack;
unsigned IgnoredEnd = 0;
while (Loc.isMacroID()) {
// If this is the expansion of a macro argument, point the caret at the
// use of the argument in the definition of the macro, not the expansion.
- if (SM.isMacroArgExpansion(Loc))
- LocationStack.push_back(SM.getImmediateExpansionRange(Loc).first);
+ if (Loc.isMacroArgExpansion())
+ LocationStack.push_back(Loc.getImmediateExpansionRange().first);
else
LocationStack.push_back(Loc);
- if (checkRangesForMacroArgExpansion(Loc, Ranges, SM))
+ if (checkRangesForMacroArgExpansion(Loc, Ranges))
IgnoredEnd = LocationStack.size();
- Loc = SM.getImmediateMacroCallerLoc(Loc);
+ Loc = Loc.getImmediateMacroCallerLoc();
// Once the location no longer points into a macro, try stepping through
// the last found location. This sometimes produces additional useful
// backtraces.
if (Loc.isFileID())
- Loc = SM.getImmediateMacroCallerLoc(LocationStack.back());
+ Loc = LocationStack.back().getImmediateMacroCallerLoc();
assert(Loc.isValid() && "must have a valid source location here");
}
@@ -555,7 +537,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
if (MacroDepth <= MacroLimit || MacroLimit == 0) {
for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
I != E; ++I)
- emitSingleMacroExpansion(*I, Level, Ranges, SM);
+ emitSingleMacroExpansion(*I, Level, Ranges);
return;
}
@@ -565,7 +547,7 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
for (auto I = LocationStack.rbegin(),
E = LocationStack.rbegin() + MacroStartMessages;
I != E; ++I)
- emitSingleMacroExpansion(*I, Level, Ranges, SM);
+ emitSingleMacroExpansion(*I, Level, Ranges);
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
@@ -577,26 +559,24 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
for (auto I = LocationStack.rend() - MacroEndMessages,
E = LocationStack.rend();
I != E; ++I)
- emitSingleMacroExpansion(*I, Level, Ranges, SM);
+ emitSingleMacroExpansion(*I, Level, Ranges);
}
DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {}
-void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc,
- PresumedLoc PLoc,
- const SourceManager &SM) {
+void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc,
+ PresumedLoc PLoc) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
Message << "in file included from " << PLoc.getFilename() << ':'
<< PLoc.getLine() << ":";
- emitNote(Loc, Message.str(), &SM);
+ emitNote(Loc, Message.str());
}
-void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
+void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc,
PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+ StringRef ModuleName) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
@@ -605,14 +585,12 @@ void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
Message << "' imported from " << PLoc.getFilename() << ':'
<< PLoc.getLine();
Message << ":";
- emitNote(Loc, Message.str(), &SM);
+ emitNote(Loc, Message.str());
}
-void
-DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
- PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName) {
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
@@ -621,5 +599,5 @@ DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":";
else
Message << "while building module '" << ModuleName << "':";
- emitNote(Loc, Message.str(), &SM);
+ emitNote(Loc, Message.str());
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
index 39fc137..704d5150 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
@@ -19,6 +19,7 @@
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/ParseAST.h"
@@ -135,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) {
@@ -187,8 +194,324 @@ 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.
+/// 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 IsModuleMap If \c true, add a line note corresponding to this line
+/// directive. (We need to do this because the directive will not be
+/// visited by the preprocessor.)
+static SourceLocation ReadOriginalFileName(CompilerInstance &CI,
+ std::string &InputFile,
+ bool IsModuleMap = false) {
+ auto &SourceMgr = CI.getSourceManager();
+ auto MainFileID = SourceMgr.getMainFileID();
+
+ bool Invalid = false;
+ const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
+ std::unique_ptr<Lexer> RawLexer(
+ new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts()));
+
+ // If the first line has the syntax of
+ //
+ // # NUM "FILENAME"
+ //
+ // we use FILENAME as the input file name.
+ Token T;
+ if (RawLexer->LexFromRawLexer(T) || T.getKind() != tok::hash)
+ return SourceLocation();
+ if (RawLexer->LexFromRawLexer(T) || T.isAtStartOfLine() ||
+ T.getKind() != tok::numeric_constant)
+ return SourceLocation();
+
+ unsigned LineNo;
+ SourceLocation LineNoLoc = T.getLocation();
+ if (IsModuleMap) {
+ 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 SourceLocation();
+
+ StringLiteralParser Literal(T, CI.getPreprocessor());
+ if (Literal.hadError)
+ return SourceLocation();
+ RawLexer->LexFromRawLexer(T);
+ if (T.isNot(tok::eof) && !T.isAtStartOfLine())
+ return SourceLocation();
+ InputFile = Literal.GetString().str();
+
+ if (IsModuleMap)
+ CI.getSourceManager().AddLineNote(
+ LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false,
+ false, SrcMgr::C_User_ModuleMap);
+
+ return T.getLocation();
+}
+
+static SmallVectorImpl<char> &
+operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
+ Includes.append(RHS.begin(), RHS.end());
+ return Includes;
+}
+
+static void addHeaderInclude(StringRef HeaderName,
+ SmallVectorImpl<char> &Includes,
+ const LangOptions &LangOpts,
+ bool IsExternC) {
+ if (IsExternC && LangOpts.CPlusPlus)
+ Includes += "extern \"C\" {\n";
+ if (LangOpts.ObjC1)
+ Includes += "#import \"";
+ else
+ Includes += "#include \"";
+
+ Includes += HeaderName;
+
+ Includes += "\"\n";
+ if (IsExternC && LangOpts.CPlusPlus)
+ Includes += "}\n";
+}
+
+/// \brief Collect the set of header includes needed to construct the given
+/// module and update the TopHeaders file set of the module.
+///
+/// \param Module The module we're collecting includes from.
+///
+/// \param Includes Will be augmented with the set of \#includes or \#imports
+/// needed to load all of the named headers.
+static std::error_code collectModuleHeaderIncludes(
+ const LangOptions &LangOpts, FileManager &FileMgr, DiagnosticsEngine &Diag,
+ ModuleMap &ModMap, clang::Module *Module, SmallVectorImpl<char> &Includes) {
+ // Don't collect any headers for unavailable modules.
+ if (!Module->isAvailable())
+ return std::error_code();
+
+ // Resolve all lazy header directives to header files.
+ ModMap.resolveHeaderDirectives(Module);
+
+ // If any headers are missing, we can't build this module. In most cases,
+ // diagnostics for this should have already been produced; we only get here
+ // if explicit stat information was provided.
+ // FIXME: If the name resolves to a file with different stat information,
+ // produce a better diagnostic.
+ if (!Module->MissingHeaders.empty()) {
+ auto &MissingHeader = Module->MissingHeaders.front();
+ Diag.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing)
+ << MissingHeader.IsUmbrella << MissingHeader.FileName;
+ return std::error_code();
+ }
+
+ // Add includes for each of these headers.
+ for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
+ for (Module::Header &H : Module->Headers[HK]) {
+ Module->addTopHeader(H.Entry);
+ // Use the path as specified in the module map file. We'll look for this
+ // file relative to the module build directory (the directory containing
+ // the module map file) so this will find the same file that we found
+ // while parsing the module map.
+ addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC);
+ }
+ }
+ // Note that Module->PrivateHeaders will not be a TopHeader.
+
+ if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) {
+ Module->addTopHeader(UmbrellaHeader.Entry);
+ if (Module->Parent)
+ // Include the umbrella header for submodules.
+ addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts,
+ Module->IsExternC);
+ } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) {
+ // Add all of the headers we find in this subdirectory.
+ std::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative);
+
+ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+ for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
+ Dir != End && !EC; Dir.increment(EC)) {
+ // Check whether this entry has an extension typically associated with
+ // headers.
+ if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName()))
+ .Cases(".h", ".H", ".hh", ".hpp", true)
+ .Default(false))
+ continue;
+
+ const FileEntry *Header = FileMgr.getFile(Dir->getName());
+ // FIXME: This shouldn't happen unless there is a file system race. Is
+ // that worth diagnosing?
+ if (!Header)
+ continue;
+
+ // If this header is marked 'unavailable' in this module, don't include
+ // it.
+ if (ModMap.isHeaderUnavailableInModule(Header, Module))
+ continue;
+
+ // Compute the relative path from the directory to this file.
+ SmallVector<StringRef, 16> Components;
+ auto PathIt = llvm::sys::path::rbegin(Dir->getName());
+ for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt)
+ Components.push_back(*PathIt);
+ SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten);
+ for (auto It = Components.rbegin(), End = Components.rend(); It != End;
+ ++It)
+ llvm::sys::path::append(RelativeHeader, *It);
+
+ // Include this header as part of the umbrella directory.
+ Module->addTopHeader(Header);
+ addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC);
+ }
+
+ if (EC)
+ return EC;
+ }
+
+ // Recurse into submodules.
+ for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
+ SubEnd = Module->submodule_end();
+ Sub != SubEnd; ++Sub)
+ if (std::error_code Err = collectModuleHeaderIncludes(
+ LangOpts, FileMgr, Diag, ModMap, *Sub, Includes))
+ return Err;
+
+ return std::error_code();
+}
+
+static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem,
+ bool IsPreprocessed,
+ std::string &PresumedModuleMapFile,
+ unsigned &Offset) {
+ auto &SrcMgr = CI.getSourceManager();
+ HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+
+ // 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) {
+ SourceLocation EndOfLineMarker =
+ ReadOriginalFileName(CI, PresumedModuleMapFile, /*IsModuleMap*/ true);
+ if (EndOfLineMarker.isValid())
+ Offset = CI.getSourceManager().getDecomposedLoc(EndOfLineMarker).second;
+ }
+
+ // Load the module map file.
+ if (HS.loadModuleMapFile(ModuleMap, IsSystem, ModuleMapID, &Offset,
+ PresumedModuleMapFile))
+ 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
+ // map with a single module (the common case).
+ return nullptr;
+ }
+
+ // 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 << ModuleMapFilename;
+
+ return nullptr;
+ }
+
+ // Check whether we can build this module at all.
+ if (Preprocessor::checkModuleIsAvailable(CI.getLangOpts(), CI.getTarget(),
+ CI.getDiagnostics(), M))
+ 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);
+
+ // 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.
+ SmallString<256> HeaderContents;
+ std::error_code Err = std::error_code();
+ if (Module::Header UmbrellaHeader = M->getUmbrellaHeader())
+ addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents,
+ CI.getLangOpts(), M->IsExternC);
+ Err = collectModuleHeaderIncludes(
+ CI.getLangOpts(), FileMgr, CI.getDiagnostics(),
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), M,
+ HeaderContents);
+
+ if (Err) {
+ CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
+ << M->getFullModuleName() << Err.message();
+ return nullptr;
+ }
+
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ HeaderContents, Module::getModuleInputBufferName());
+}
+
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
- const FrontendInputFile &Input) {
+ const FrontendInputFile &RealInput) {
+ FrontendInputFile Input(RealInput);
assert(!Instance && "Already processing a source file!");
assert(!Input.isEmpty() && "Unexpected empty filename!");
setCurrentInput(Input);
@@ -196,22 +519,88 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
StringRef InputFile = Input.getFile();
bool HasBegunSourceFile = false;
+ bool ReplayASTFile = Input.getKind().getFormat() == InputKind::Precompiled &&
+ usesPreprocessorOnly();
if (!BeginInvocation(CI))
goto failure;
+ // If we're replaying the build of an AST file, import it and set up
+ // the initial state from its build.
+ if (ReplayASTFile) {
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
+
+ // The AST unit populates its own diagnostics engine rather than ours.
+ IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(
+ new DiagnosticsEngine(Diags->getDiagnosticIDs(),
+ &Diags->getDiagnosticOptions()));
+ ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
+
+ std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
+ InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly,
+ ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
+ if (!AST)
+ goto failure;
+
+ // Options relating to how we treat the input (but not what we do with it)
+ // are inherited from the AST unit.
+ CI.getHeaderSearchOpts() = AST->getHeaderSearchOpts();
+ CI.getPreprocessorOpts() = AST->getPreprocessorOpts();
+ CI.getLangOpts() = AST->getLangOpts();
+
+ // Set the shared objects, these are reset when we finish processing the
+ // file, otherwise the CompilerInstance will happily destroy them.
+ CI.setFileManager(&AST->getFileManager());
+ CI.createSourceManager(CI.getFileManager());
+ CI.getSourceManager().initializeForReplay(AST->getSourceManager());
+
+ // Preload all the module files loaded transitively by the AST unit. Also
+ // load all module map files that were parsed as part of building the AST
+ // unit.
+ if (auto ASTReader = AST->getASTReader()) {
+ auto &MM = ASTReader->getModuleManager();
+ auto &PrimaryModule = MM.getPrimaryModule();
+
+ for (ModuleFile &MF : MM)
+ if (&MF != &PrimaryModule)
+ CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName);
+
+ ASTReader->visitTopLevelModuleMaps(PrimaryModule,
+ [&](const FileEntry *FE) {
+ CI.getFrontendOpts().ModuleMapFiles.push_back(FE->getName());
+ });
+ }
+
+ // Set up the input file for replay purposes.
+ auto Kind = AST->getInputKind();
+ if (Kind.getFormat() == InputKind::ModuleMap) {
+ Module *ASTModule =
+ AST->getPreprocessor().getHeaderSearchInfo().lookupModule(
+ AST->getLangOpts().CurrentModule, /*AllowSearch*/ false);
+ assert(ASTModule && "module file does not define its own module");
+ Input = FrontendInputFile(ASTModule->PresumedModuleMapFile, Kind);
+ } else {
+ auto &SM = CI.getSourceManager();
+ FileID ID = SM.getMainFileID();
+ if (auto *File = SM.getFileEntryForID(ID))
+ Input = FrontendInputFile(File->getName(), Kind);
+ else
+ Input = FrontendInputFile(SM.getBuffer(ID), Kind);
+ }
+ setCurrentInput(Input, std::move(AST));
+ }
+
// AST files follow a very different path, since they share objects via the
// AST unit.
- if (Input.getKind() == IK_AST) {
- assert(!usesPreprocessorOnly() &&
- "Attempt to pass AST file to preprocessor only action!");
+ if (Input.getKind().getFormat() == InputKind::Precompiled) {
+ assert(!usesPreprocessorOnly() && "this case was handled above");
assert(hasASTFileSupport() &&
"This action does not have AST file support!");
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
- InputFile, CI.getPCHContainerReader(), Diags, CI.getFileSystemOpts(),
- CI.getCodeGenOpts().DebugTypeExtRefs);
+ InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
+ CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs);
if (!AST)
goto failure;
@@ -225,12 +614,15 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.setFileManager(&AST->getFileManager());
CI.setSourceManager(&AST->getSourceManager());
CI.setPreprocessor(AST->getPreprocessorPtr());
+ Preprocessor &PP = CI.getPreprocessor();
+ PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
+ PP.getLangOpts());
CI.setASTContext(&AST->getASTContext());
setCurrentInput(Input, std::move(AST));
// Initialize the action.
- if (!BeginSourceFileAction(CI, InputFile))
+ if (!BeginSourceFileAction(CI))
goto failure;
// Create the AST consumer.
@@ -256,8 +648,19 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!CI.hasSourceManager())
CI.createSourceManager(CI.getFileManager());
+ // Set up embedding for any specified files. Do this before we load any
+ // source files, including the primary module map for the compilation.
+ for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
+ if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
+ CI.getSourceManager().setFileIsTransient(FE);
+ else
+ CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
+ }
+ if (CI.getFrontendOpts().ModulesEmbedAllFiles)
+ CI.getSourceManager().setAllFilesAreTransient(true);
+
// IR files bypass the rest of initialization.
- if (Input.getKind() == IK_LLVM_IR) {
+ if (Input.getKind().getLanguage() == InputKind::LLVM_IR) {
assert(hasIRSupport() &&
"This action does not have IR file support!");
@@ -266,7 +669,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
HasBegunSourceFile = true;
// Initialize the action.
- if (!BeginSourceFileAction(CI, InputFile))
+ if (!BeginSourceFileAction(CI))
goto failure;
// Initialize the main file entry.
@@ -319,13 +722,47 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
&CI.getPreprocessor());
HasBegunSourceFile = true;
- // Initialize the action.
- if (!BeginSourceFileAction(CI, InputFile))
+ // Initialize the main file entry.
+ if (!CI.InitializeSourceManager(Input))
goto failure;
- // Initialize the main file entry. It is important that this occurs after
- // BeginSourceFileAction, which may change CurrentInput during module builds.
- if (!CI.InitializeSourceManager(CurrentInput))
+ // 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);
+
+ std::string PresumedModuleMapFile;
+ unsigned OffsetToContents;
+ if (loadModuleMapForModuleBuild(CI, Input.isSystem(),
+ Input.isPreprocessed(),
+ PresumedModuleMapFile, OffsetToContents))
+ goto failure;
+
+ auto *CurrentModule = prepareToBuildModule(CI, Input.getFile());
+ if (!CurrentModule)
+ goto failure;
+
+ CurrentModule->PresumedModuleMapFile = PresumedModuleMapFile;
+
+ 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;
+
+ // 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))
goto failure;
// Create the AST context and consumer unless this is a preprocessor only
@@ -335,8 +772,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!isModelParsingAction())
CI.createASTContext();
+ // For preprocessed files, check if the first line specifies the original
+ // source file name with a linemarker.
+ std::string PresumedInputFile = InputFile;
+ if (Input.isPreprocessed())
+ ReadOriginalFileName(CI, PresumedInputFile);
+
std::unique_ptr<ASTConsumer> Consumer =
- CreateWrappedASTConsumer(CI, InputFile);
+ CreateWrappedASTConsumer(CI, PresumedInputFile);
if (!Consumer)
goto failure;
@@ -352,8 +795,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
goto failure;
CI.setModuleManager(static_cast<ASTReader *>(FinalReader.get()));
CI.getASTContext().setExternalSource(source);
- } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
- // Use PCH.
+ } else if (CI.getLangOpts().Modules ||
+ !CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ // Use PCM or PCH.
assert(hasPCHSupport() && "This action does not have PCH support!");
ASTDeserializationListener *DeserialListener =
Consumer->GetASTDeserializationListener();
@@ -370,13 +814,24 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
DeserialListener, DeleteDeserialListener);
DeleteDeserialListener = true;
}
- CI.createPCHExternalASTSource(
- CI.getPreprocessorOpts().ImplicitPCHInclude,
- CI.getPreprocessorOpts().DisablePCHValidation,
+ if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ CI.createPCHExternalASTSource(
+ CI.getPreprocessorOpts().ImplicitPCHInclude,
+ CI.getPreprocessorOpts().DisablePCHValidation,
CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener,
- DeleteDeserialListener);
- if (!CI.getASTContext().getExternalSource())
- goto failure;
+ DeleteDeserialListener);
+ if (!CI.getASTContext().getExternalSource())
+ goto failure;
+ }
+ // If modules are enabled, create the module manager before creating
+ // any builtins, so that all declarations know that they might be
+ // extended by an external source.
+ if (CI.getLangOpts().Modules || !CI.hasASTContext() ||
+ !CI.getASTContext().getExternalSource()) {
+ CI.createModuleManager();
+ CI.getModuleManager()->setDeserializationListener(DeserialListener,
+ DeleteDeserialListener);
+ }
}
CI.setASTConsumer(std::move(Consumer));
@@ -386,15 +841,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// Initialize built-in info as long as we aren't using an external AST
// source.
- if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
+ if (CI.getLangOpts().Modules || !CI.hasASTContext() ||
+ !CI.getASTContext().getExternalSource()) {
Preprocessor &PP = CI.getPreprocessor();
-
- // If modules are enabled, create the module manager before creating
- // any builtins, so that all declarations know that they might be
- // extended by an external source.
- if (CI.getLangOpts().Modules)
- CI.createModuleManager();
-
PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
PP.getLangOpts());
} else {
@@ -421,9 +870,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// If there is a layout overrides file, attach an external AST source that
// provides the layouts from that file.
- if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
+ if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
- IntrusiveRefCntPtr<ExternalASTSource>
+ IntrusiveRefCntPtr<ExternalASTSource>
Override(new LayoutOverrideSource(
CI.getFrontendOpts().OverrideRecordLayoutsFile));
CI.getASTContext().setExternalSource(Override);
@@ -433,17 +882,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// If we failed, reset state since the client will not end up calling the
// matching EndSourceFile().
- failure:
- if (isCurrentFileAST()) {
- CI.setASTContext(nullptr);
- CI.setPreprocessor(nullptr);
- CI.setSourceManager(nullptr);
- CI.setFileManager(nullptr);
- }
-
+failure:
if (HasBegunSourceFile)
CI.getDiagnosticClient().EndSourceFile();
CI.clearOutputFiles(/*EraseFiles=*/true);
+ CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
setCurrentInput(FrontendInputFile());
setCompilerInstance(nullptr);
return false;
@@ -517,6 +960,7 @@ void FrontendAction::EndSourceFile() {
CI.resetAndLeakPreprocessor();
CI.resetAndLeakSourceManager();
CI.resetAndLeakFileManager();
+ BuryPointer(CurrentASTUnit.release());
} else {
CI.setPreprocessor(nullptr);
CI.setSourceManager(nullptr);
@@ -526,6 +970,7 @@ void FrontendAction::EndSourceFile() {
setCompilerInstance(nullptr);
setCurrentInput(FrontendInputFile());
+ CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
}
bool FrontendAction::shouldEraseOutputFiles() {
@@ -575,11 +1020,10 @@ WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
return WrappedAction->BeginInvocation(CI);
}
-bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI) {
WrappedAction->setCurrentInput(getCurrentInput());
WrappedAction->setCompilerInstance(&CI);
- auto Ret = WrappedAction->BeginSourceFileAction(CI, Filename);
+ auto Ret = WrappedAction->BeginSourceFileAction(CI);
// BeginSourceFileAction may change CurrentInput, e.g. during module builds.
setCurrentInput(WrappedAction->getCurrentInput());
return Ret;
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
index f795a1d..d424001 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
@@ -57,6 +57,7 @@ std::unique_ptr<ASTConsumer>
ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter,
CI.getFrontendOpts().ASTDumpDecls,
+ CI.getFrontendOpts().ASTDumpAll,
CI.getFrontendOpts().ASTDumpLookups);
}
@@ -93,7 +94,7 @@ GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Consumers.push_back(llvm::make_unique<PCHGenerator>(
CI.getPreprocessor(), OutputFile, Sysroot,
Buffer, CI.getFrontendOpts().ModuleFileExtensions,
- /*AllowASTWithErrors*/false,
+ /*AllowASTWithErrors*/CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
/*IncludeTimestamps*/
+CI.getFrontendOpts().IncludeTimestamps));
Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
@@ -127,8 +128,13 @@ GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
return OS;
}
-bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool GeneratePCHAction::shouldEraseOutputFiles() {
+ if (getCompilerInstance().getPreprocessorOpts().AllowPCHWithCompilerErrors)
+ return false;
+ return ASTFrontendAction::shouldEraseOutputFiles();
+}
+
+bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) {
CI.getLangOpts().CompilingPCH = true;
return true;
}
@@ -157,242 +163,14 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
}
-bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
- // Set up embedding for any specified files. Do this before we load any
- // source files, including the primary module map for the compilation.
- for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
- if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
- CI.getSourceManager().setFileIsTransient(FE);
- else
- CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
- }
- if (CI.getFrontendOpts().ModulesEmbedAllFiles)
- CI.getSourceManager().setAllFilesAreTransient(true);
-
- return true;
-}
-
-
-static SmallVectorImpl<char> &
-operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
- Includes.append(RHS.begin(), RHS.end());
- return Includes;
-}
-
-static void addHeaderInclude(StringRef HeaderName,
- SmallVectorImpl<char> &Includes,
- const LangOptions &LangOpts,
- bool IsExternC) {
- if (IsExternC && LangOpts.CPlusPlus)
- Includes += "extern \"C\" {\n";
- if (LangOpts.ObjC1)
- Includes += "#import \"";
- else
- Includes += "#include \"";
-
- Includes += HeaderName;
-
- Includes += "\"\n";
- if (IsExternC && LangOpts.CPlusPlus)
- Includes += "}\n";
-}
-
-/// \brief Collect the set of header includes needed to construct the given
-/// module and update the TopHeaders file set of the module.
-///
-/// \param Module The module we're collecting includes from.
-///
-/// \param Includes Will be augmented with the set of \#includes or \#imports
-/// needed to load all of the named headers.
-static std::error_code
-collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
- ModuleMap &ModMap, clang::Module *Module,
- SmallVectorImpl<char> &Includes) {
- // Don't collect any headers for unavailable modules.
- if (!Module->isAvailable())
- return std::error_code();
-
- // Add includes for each of these headers.
- for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
- for (Module::Header &H : Module->Headers[HK]) {
- Module->addTopHeader(H.Entry);
- // Use the path as specified in the module map file. We'll look for this
- // file relative to the module build directory (the directory containing
- // the module map file) so this will find the same file that we found
- // while parsing the module map.
- addHeaderInclude(H.NameAsWritten, Includes, LangOpts, Module->IsExternC);
- }
- }
- // Note that Module->PrivateHeaders will not be a TopHeader.
-
- if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader()) {
- Module->addTopHeader(UmbrellaHeader.Entry);
- if (Module->Parent)
- // Include the umbrella header for submodules.
- addHeaderInclude(UmbrellaHeader.NameAsWritten, Includes, LangOpts,
- Module->IsExternC);
- } else if (Module::DirectoryName UmbrellaDir = Module->getUmbrellaDir()) {
- // Add all of the headers we find in this subdirectory.
- std::error_code EC;
- SmallString<128> DirNative;
- llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative);
-
- vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
- for (vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
- Dir != End && !EC; Dir.increment(EC)) {
- // Check whether this entry has an extension typically associated with
- // headers.
- if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->getName()))
- .Cases(".h", ".H", ".hh", ".hpp", true)
- .Default(false))
- continue;
-
- const FileEntry *Header = FileMgr.getFile(Dir->getName());
- // FIXME: This shouldn't happen unless there is a file system race. Is
- // that worth diagnosing?
- if (!Header)
- continue;
-
- // If this header is marked 'unavailable' in this module, don't include
- // it.
- if (ModMap.isHeaderUnavailableInModule(Header, Module))
- continue;
-
- // Compute the relative path from the directory to this file.
- SmallVector<StringRef, 16> Components;
- auto PathIt = llvm::sys::path::rbegin(Dir->getName());
- for (int I = 0; I != Dir.level() + 1; ++I, ++PathIt)
- Components.push_back(*PathIt);
- SmallString<128> RelativeHeader(UmbrellaDir.NameAsWritten);
- for (auto It = Components.rbegin(), End = Components.rend(); It != End;
- ++It)
- llvm::sys::path::append(RelativeHeader, *It);
-
- // Include this header as part of the umbrella directory.
- Module->addTopHeader(Header);
- addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC);
- }
-
- if (EC)
- return EC;
- }
-
- // Recurse into submodules.
- for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
- SubEnd = Module->submodule_end();
- Sub != SubEnd; ++Sub)
- if (std::error_code Err = collectModuleHeaderIncludes(
- LangOpts, FileMgr, ModMap, *Sub, Includes))
- return Err;
-
- return std::error_code();
-}
-
bool GenerateModuleFromModuleMapAction::BeginSourceFileAction(
- CompilerInstance &CI, StringRef Filename) {
- CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap);
-
- if (!GenerateModuleAction::BeginSourceFileAction(CI, Filename))
- return false;
-
- // 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;
+ CompilerInstance &CI) {
+ if (!CI.getLangOpts().Modules) {
+ CI.getDiagnostics().Report(diag::err_module_build_requires_fmodules);
return false;
}
-
- // Parse the module map file.
- HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
- if (HS.loadModuleMapFile(ModuleMap, IsSystem))
- return false;
-
- 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
- // map with a single module (the common case).
- return false;
- }
-
- // 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.
- Module = HS.lookupModule(CI.getLangOpts().CurrentModule,
- /*AllowSearch=*/false);
- if (!Module) {
- CI.getDiagnostics().Report(diag::err_missing_module)
- << CI.getLangOpts().CurrentModule << Filename;
-
- return false;
- }
-
- // Check whether we can build this module at all.
- clang::Module::Requirement Requirement;
- clang::Module::UnresolvedHeaderDirective MissingHeader;
- if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
- MissingHeader)) {
- if (MissingHeader.FileNameLoc.isValid()) {
- CI.getDiagnostics().Report(MissingHeader.FileNameLoc,
- diag::err_module_header_missing)
- << MissingHeader.IsUmbrella << MissingHeader.FileName;
- } else {
- CI.getDiagnostics().Report(diag::err_module_unavailable)
- << Module->getFullModuleName()
- << Requirement.second << Requirement.first;
- }
-
- return false;
- }
-
- if (ModuleMapForUniquing && ModuleMapForUniquing != ModuleMap) {
- Module->IsInferred = true;
- HS.getModuleMap().setInferredModuleAllowedBy(Module, ModuleMapForUniquing);
- } else {
- ModuleMapForUniquing = ModuleMap;
- }
- FileManager &FileMgr = CI.getFileManager();
-
- // Collect the set of #includes we need to build the module.
- SmallString<256> HeaderContents;
- std::error_code Err = std::error_code();
- if (Module::Header UmbrellaHeader = Module->getUmbrellaHeader())
- addHeaderInclude(UmbrellaHeader.NameAsWritten, HeaderContents,
- CI.getLangOpts(), Module->IsExternC);
- Err = collectModuleHeaderIncludes(
- CI.getLangOpts(), FileMgr,
- CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module,
- HeaderContents);
-
- if (Err) {
- CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
- << Module->getFullModuleName() << Err.message();
- return false;
- }
-
- // 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(Module->Directory);
-
- std::unique_ptr<llvm::MemoryBuffer> InputBuffer =
- llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
- Module::getModuleInputBufferName());
- // Ownership of InputBuffer will be transferred to the SourceManager.
- setCurrentInput(FrontendInputFile(InputBuffer.release(), getCurrentFileKind(),
- Module->IsSystem));
- return true;
+ return GenerateModuleAction::BeginSourceFileAction(CI);
}
std::unique_ptr<raw_pwrite_stream>
@@ -401,10 +179,13 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
// If no output file was provided, figure out where this module would go
// in the module cache.
if (CI.getFrontendOpts().OutputFile.empty()) {
+ StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap;
+ if (ModuleMapFile.empty())
+ ModuleMapFile = InFile;
+
HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
CI.getFrontendOpts().OutputFile =
- HS.getModuleFileName(CI.getLangOpts().CurrentModule,
- ModuleMapForUniquing->getName(),
+ HS.getModuleFileName(CI.getLangOpts().CurrentModule, ModuleMapFile,
/*UsePrebuiltPath=*/false);
}
@@ -417,8 +198,8 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
/*CreateMissingDirectories=*/true);
}
-bool GenerateModuleInterfaceAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool GenerateModuleInterfaceAction::BeginSourceFileAction(
+ CompilerInstance &CI) {
if (!CI.getLangOpts().ModulesTS) {
CI.getDiagnostics().Report(diag::err_module_interface_requires_modules_ts);
return false;
@@ -426,7 +207,7 @@ bool GenerateModuleInterfaceAction::BeginSourceFileAction(CompilerInstance &CI,
CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
- return GenerateModuleAction::BeginSourceFileAction(CI, Filename);
+ return GenerateModuleAction::BeginSourceFileAction(CI);
}
std::unique_ptr<raw_pwrite_stream>
@@ -459,7 +240,7 @@ void VerifyPCHAction::ExecuteAction() {
bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
std::unique_ptr<ASTReader> Reader(new ASTReader(
- CI.getPreprocessor(), CI.getASTContext(), CI.getPCHContainerReader(),
+ CI.getPreprocessor(), &CI.getASTContext(), CI.getPCHContainerReader(),
CI.getFrontendOpts().ModuleFileExtensions,
Sysroot.empty() ? "" : Sysroot.c_str(),
/*DisableValidation*/ false,
@@ -567,6 +348,7 @@ namespace {
bool Complain) override {
Out.indent(2) << "Header search options:\n";
Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n";
+ Out.indent(4) << "Resource dir [ -resource-dir=]: '" << HSOpts.ResourceDir << "'\n";
Out.indent(4) << "Module Cache: '" << SpecificModuleCachePath << "'\n";
DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes,
"Use builtin include directories [-nobuiltininc]");
@@ -745,7 +527,7 @@ void PrintPreprocessedAction::ExecuteAction() {
// file. This is mostly a sanity check in case the file has no
// newlines whatsoever.
if (end - cur > 256) end = cur + 256;
-
+
while (next < end) {
if (*cur == 0x0D) { // CR
if (*next == 0x0A) // CRLF
@@ -764,34 +546,47 @@ 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 \"";
+ OS->write_escaped(Input.getFile());
+ (*OS) << "\"\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());
}
void PrintPreambleAction::ExecuteAction() {
- switch (getCurrentFileKind()) {
- case IK_C:
- case IK_CXX:
- case IK_ObjC:
- case IK_ObjCXX:
- case IK_OpenCL:
- case IK_CUDA:
+ switch (getCurrentFileKind().getLanguage()) {
+ case InputKind::C:
+ case InputKind::CXX:
+ case InputKind::ObjC:
+ case InputKind::ObjCXX:
+ case InputKind::OpenCL:
+ case InputKind::CUDA:
break;
- case IK_None:
- case IK_Asm:
- case IK_PreprocessedC:
- case IK_PreprocessedCuda:
- case IK_PreprocessedCXX:
- case IK_PreprocessedObjC:
- case IK_PreprocessedObjCXX:
- case IK_AST:
- case IK_LLVM_IR:
- case IK_RenderScript:
+ case InputKind::Unknown:
+ case InputKind::Asm:
+ case InputKind::LLVM_IR:
+ case InputKind::RenderScript:
// We can't do anything with these.
return;
}
+ // We don't expect to find any #include directives in a preprocessed input.
+ if (getCurrentFileKind().isPreprocessed())
+ return;
+
CompilerInstance &CI = getCompilerInstance();
auto Buffer = CI.getFileManager().getBufferForFile(getCurrentFile());
if (Buffer) {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp
index 6a82084..dca4345 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp
@@ -13,22 +13,22 @@ using namespace clang;
InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) {
return llvm::StringSwitch<InputKind>(Extension)
- .Cases("ast", "pcm", IK_AST)
- .Case("c", IK_C)
- .Cases("S", "s", IK_Asm)
- .Case("i", IK_PreprocessedC)
- .Case("ii", IK_PreprocessedCXX)
- .Case("cui", IK_PreprocessedCuda)
- .Case("m", IK_ObjC)
- .Case("mi", IK_PreprocessedObjC)
- .Cases("mm", "M", IK_ObjCXX)
- .Case("mii", IK_PreprocessedObjCXX)
- .Cases("C", "cc", "cp", IK_CXX)
- .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX)
- .Case("cppm", IK_CXX)
- .Case("iim", IK_PreprocessedCXX)
- .Case("cl", IK_OpenCL)
- .Case("cu", IK_CUDA)
- .Cases("ll", "bc", IK_LLVM_IR)
- .Default(IK_C);
+ .Cases("ast", "pcm", InputKind(InputKind::Unknown, InputKind::Precompiled))
+ .Case("c", InputKind::C)
+ .Cases("S", "s", InputKind::Asm)
+ .Case("i", InputKind(InputKind::C).getPreprocessed())
+ .Case("ii", InputKind(InputKind::CXX).getPreprocessed())
+ .Case("cui", InputKind(InputKind::CUDA).getPreprocessed())
+ .Case("m", InputKind::ObjC)
+ .Case("mi", InputKind(InputKind::ObjC).getPreprocessed())
+ .Cases("mm", "M", InputKind::ObjCXX)
+ .Case("mii", InputKind(InputKind::ObjCXX).getPreprocessed())
+ .Cases("C", "cc", "cp", InputKind::CXX)
+ .Cases("cpp", "CPP", "c++", "cxx", "hpp", InputKind::CXX)
+ .Case("cppm", InputKind::CXX)
+ .Case("iim", InputKind(InputKind::CXX).getPreprocessed())
+ .Case("cl", InputKind::OpenCL)
+ .Case("cu", InputKind::CUDA)
+ .Cases("ll", "bc", InputKind::LLVM_IR)
+ .Default(InputKind::Unknown);
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
index d50fb6d..1d7c8a0 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
@@ -221,6 +221,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
case llvm::Triple::Win32:
if (triple.getEnvironment() != llvm::Triple::Cygnus)
break;
+ LLVM_FALLTHROUGH;
default:
// FIXME: temporary hack: hard-coded paths.
AddPath("/usr/local/include", System, false);
@@ -343,6 +344,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath(BaseSDKPath + "/target/include", System, false);
if (triple.isPS4CPU())
AddPath(BaseSDKPath + "/target/include_common", System, false);
+ LLVM_FALLTHROUGH;
}
default:
AddPath("/usr/include", ExternCSystem, false);
diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
index 17603ad..92d6136 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
@@ -374,9 +374,14 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
Builder.defineMacro("__STDC_VERSION__", "199409L");
} else {
- // FIXME: Use correct value for C++17.
- if (LangOpts.CPlusPlus1z)
- Builder.defineMacro("__cplusplus", "201406L");
+ // FIXME: Use correct value for C++20.
+ if (LangOpts.CPlusPlus2a)
+ Builder.defineMacro("__cplusplus", "201707L");
+ // C++17 [cpp.predefined]p1:
+ // The name __cplusplus is defined to the value 201703L when compiling a
+ // C++ translation unit.
+ else if (LangOpts.CPlusPlus1z)
+ Builder.defineMacro("__cplusplus", "201703L");
// C++1y [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201402L when compiling a
// C++ translation unit.
@@ -475,6 +480,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_user_defined_literals", "200809");
Builder.defineMacro("__cpp_lambdas", "200907");
Builder.defineMacro("__cpp_constexpr",
+ LangOpts.CPlusPlus1z ? "201603" :
LangOpts.CPlusPlus14 ? "201304" : "200704");
Builder.defineMacro("__cpp_range_based_for",
LangOpts.CPlusPlus1z ? "201603" : "200907");
@@ -491,6 +497,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_ref_qualifiers", "200710");
Builder.defineMacro("__cpp_alias_templates", "200704");
}
+ if (LangOpts.ThreadsafeStatics)
+ Builder.defineMacro("__cpp_threadsafe_static_init", "200806");
// C++14 features.
if (LangOpts.CPlusPlus14) {
@@ -513,6 +521,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_noexcept_function_type", "201510");
Builder.defineMacro("__cpp_capture_star_this", "201603");
Builder.defineMacro("__cpp_if_constexpr", "201606");
+ Builder.defineMacro("__cpp_deduction_guides", "201611");
Builder.defineMacro("__cpp_template_auto", "201606");
Builder.defineMacro("__cpp_namespace_attributes", "201411");
Builder.defineMacro("__cpp_enumerator_attributes", "201411");
@@ -530,7 +539,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
if (LangOpts.ConceptsTS)
Builder.defineMacro("__cpp_experimental_concepts", "1");
if (LangOpts.CoroutinesTS)
- Builder.defineMacro("__cpp_coroutines", "1");
+ Builder.defineMacro("__cpp_coroutines", "201703L");
}
static void InitializePredefinedMacros(const TargetInfo &TI,
@@ -593,9 +602,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
}
- Builder.defineMacro("__OBJC_BOOL_IS_BOOL",
- Twine(TI.useSignedCharForObjCBool() ? "0" : "1"));
-
if (LangOpts.getGC() != LangOptions::NonGC)
Builder.defineMacro("__OBJC_GC__");
@@ -626,6 +632,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("IB_DESIGNABLE", "");
}
+ // Define a macro that describes the Objective-C boolean type even for C
+ // and C++ since BOOL can be used from non Objective-C code.
+ Builder.defineMacro("__OBJC_BOOL_IS_BOOL",
+ Twine(TI.useSignedCharForObjCBool() ? "0" : "1"));
+
if (LangOpts.CPlusPlus)
InitializeCPlusPlusFeatureTestMacros(LangOpts, Builder);
@@ -875,14 +886,16 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// The value written by __atomic_test_and_set.
// FIXME: This is target-dependent.
Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
+ }
+ auto addLockFreeMacros = [&](const llvm::Twine &Prefix) {
// Used by libc++ and libstdc++ to implement ATOMIC_<foo>_LOCK_FREE.
unsigned InlineWidthBits = TI.getMaxAtomicInlineWidth();
-#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
- Builder.defineMacro("__GCC_ATOMIC_" #TYPE "_LOCK_FREE", \
- getLockFreeValue(TI.get##Type##Width(), \
- TI.get##Type##Align(), \
- InlineWidthBits));
+#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
+ Builder.defineMacro(Prefix + #TYPE "_LOCK_FREE", \
+ getLockFreeValue(TI.get##Type##Width(), \
+ TI.get##Type##Align(), \
+ InlineWidthBits));
DEFINE_LOCK_FREE_MACRO(BOOL, Bool);
DEFINE_LOCK_FREE_MACRO(CHAR, Char);
DEFINE_LOCK_FREE_MACRO(CHAR16_T, Char16);
@@ -892,12 +905,15 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DEFINE_LOCK_FREE_MACRO(INT, Int);
DEFINE_LOCK_FREE_MACRO(LONG, Long);
DEFINE_LOCK_FREE_MACRO(LLONG, LongLong);
- Builder.defineMacro("__GCC_ATOMIC_POINTER_LOCK_FREE",
+ Builder.defineMacro(Prefix + "POINTER_LOCK_FREE",
getLockFreeValue(TI.getPointerWidth(0),
TI.getPointerAlign(0),
InlineWidthBits));
#undef DEFINE_LOCK_FREE_MACRO
- }
+ };
+ addLockFreeMacros("__CLANG_ATOMIC_");
+ if (!LangOpts.MSVCCompat)
+ addLockFreeMacros("__GCC_ATOMIC_");
if (LangOpts.NoInlineDefine)
Builder.defineMacro("__NO_INLINE__");
@@ -1029,7 +1045,9 @@ void clang::InitializePreprocessor(
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
if (InitOpts.UsePredefines) {
- if (LangOpts.CUDA && PP.getAuxTargetInfo())
+ // FIXME: This will create multiple definitions for most of the predefined
+ // macros. This is not the right way to handle this.
+ if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice) && PP.getAuxTargetInfo())
InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts,
Builder);
diff --git a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
index f133327..47023e5 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
@@ -13,15 +13,15 @@
using namespace clang;
using namespace clang::frontend;
-#define LANGSTANDARD(id, name, desc, features) \
- static const LangStandard Lang_##id = { name, desc, features };
+#define LANGSTANDARD(id, name, lang, desc, features) \
+static const LangStandard Lang_##id = { name, desc, features, InputKind::lang };
#include "clang/Frontend/LangStandards.def"
const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
switch (K) {
case lang_unspecified:
llvm::report_fatal_error("getLangStandardForKind() on unspecified kind");
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
case lang_##id: return Lang_##id;
#include "clang/Frontend/LangStandards.def"
}
@@ -30,7 +30,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
const LangStandard *LangStandard::getLangStandardForName(StringRef Name) {
Kind K = llvm::StringSwitch<Kind>(Name)
-#define LANGSTANDARD(id, name, desc, features) \
+#define LANGSTANDARD(id, name, lang, desc, features) \
.Case(name, lang_##id)
#include "clang/Frontend/LangStandards.def"
.Default(lang_unspecified);
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp b/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp
index 9b34d42..ede12aa 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/ModuleDependencyCollector.cpp
@@ -248,7 +248,7 @@ std::error_code ModuleDependencyCollector::copyToRoot(StringRef Src,
// Always map a canonical src path to its real path into the YAML, by doing
// this we map different virtual src paths to the same entry in the VFS
// overlay, which is a way to emulate symlink inside the VFS; this is also
- // needed for correctness, not doing that can lead to module redifinition
+ // needed for correctness, not doing that can lead to module redefinition
// errors.
addFileMapping(VirtualPath, CacheDst);
return std::error_code();
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp
new file mode 100644
index 0000000..15b24cb
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp
@@ -0,0 +1,563 @@
+//===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper class to build precompiled preamble.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PrecompiledPreamble.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Serialization/ASTWriter.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
+
+using namespace clang;
+
+namespace {
+
+/// Keeps a track of files to be deleted in destructor.
+class TemporaryFiles {
+public:
+ // A static instance to be used by all clients.
+ static TemporaryFiles &getInstance();
+
+private:
+ // Disallow constructing the class directly.
+ TemporaryFiles() = default;
+ // Disallow copy.
+ TemporaryFiles(const TemporaryFiles &) = delete;
+
+public:
+ ~TemporaryFiles();
+
+ /// Adds \p File to a set of tracked files.
+ void addFile(StringRef File);
+
+ /// Remove \p File from disk and from the set of tracked files.
+ void removeFile(StringRef File);
+
+private:
+ llvm::sys::SmartMutex<false> Mutex;
+ llvm::StringSet<> Files;
+};
+
+TemporaryFiles &TemporaryFiles::getInstance() {
+ static TemporaryFiles Instance;
+ return Instance;
+}
+
+TemporaryFiles::~TemporaryFiles() {
+ llvm::MutexGuard Guard(Mutex);
+ for (const auto &File : Files)
+ llvm::sys::fs::remove(File.getKey());
+}
+
+void TemporaryFiles::addFile(StringRef File) {
+ llvm::MutexGuard Guard(Mutex);
+ auto IsInserted = Files.insert(File).second;
+ (void)IsInserted;
+ assert(IsInserted && "File has already been added");
+}
+
+void TemporaryFiles::removeFile(StringRef File) {
+ llvm::MutexGuard Guard(Mutex);
+ auto WasPresent = Files.erase(File);
+ (void)WasPresent;
+ assert(WasPresent && "File was not tracked");
+ llvm::sys::fs::remove(File);
+}
+
+class PreambleMacroCallbacks : public PPCallbacks {
+public:
+ PreambleMacroCallbacks(PreambleCallbacks &Callbacks) : Callbacks(Callbacks) {}
+
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ Callbacks.HandleMacroDefined(MacroNameTok, MD);
+ }
+
+private:
+ PreambleCallbacks &Callbacks;
+};
+
+class PrecompilePreambleAction : public ASTFrontendAction {
+public:
+ PrecompilePreambleAction(PreambleCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
+
+ bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
+
+ void setEmittedPreamblePCH(ASTWriter &Writer) {
+ this->HasEmittedPreamblePCH = true;
+ Callbacks.AfterPCHEmitted(Writer);
+ }
+
+ bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
+ bool hasCodeCompletionSupport() const override { return false; }
+ bool hasASTFileSupport() const override { return false; }
+ TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
+
+private:
+ friend class PrecompilePreambleConsumer;
+
+ bool HasEmittedPreamblePCH = false;
+ PreambleCallbacks &Callbacks;
+};
+
+class PrecompilePreambleConsumer : public PCHGenerator {
+public:
+ PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
+ const Preprocessor &PP, StringRef isysroot,
+ std::unique_ptr<raw_ostream> Out)
+ : PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
+ ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
+ /*AllowASTWithErrors=*/true),
+ Action(Action), Out(std::move(Out)) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ Action.Callbacks.HandleTopLevelDecl(DG);
+ return true;
+ }
+
+ void HandleTranslationUnit(ASTContext &Ctx) override {
+ PCHGenerator::HandleTranslationUnit(Ctx);
+ if (!hasEmittedPCH())
+ return;
+
+ // Write the generated bitstream to "Out".
+ *Out << getPCH();
+ // Make sure it hits disk now.
+ Out->flush();
+ // Free the buffer.
+ llvm::SmallVector<char, 0> Empty;
+ getPCH() = std::move(Empty);
+
+ Action.setEmittedPreamblePCH(getWriter());
+ }
+
+private:
+ PrecompilePreambleAction &Action;
+ std::unique_ptr<raw_ostream> Out;
+};
+
+std::unique_ptr<ASTConsumer>
+PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
+
+ StringRef InFile) {
+ std::string Sysroot;
+ std::string OutputFile;
+ std::unique_ptr<raw_ostream> OS =
+ GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
+ OutputFile);
+ if (!OS)
+ return nullptr;
+
+ if (!CI.getFrontendOpts().RelocatablePCH)
+ Sysroot.clear();
+
+ CI.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<PreambleMacroCallbacks>(Callbacks));
+ return llvm::make_unique<PrecompilePreambleConsumer>(
+ *this, CI.getPreprocessor(), Sysroot, std::move(OS));
+}
+
+template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
+ if (!Val)
+ return false;
+ Output = std::move(*Val);
+ return true;
+}
+
+} // namespace
+
+PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts,
+ llvm::MemoryBuffer *Buffer,
+ unsigned MaxLines) {
+ auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines);
+ return PreambleBounds(Pre.first, Pre.second);
+}
+
+llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
+ const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
+ DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ PreambleCallbacks &Callbacks) {
+ assert(VFS && "VFS is null");
+
+ if (!Bounds.Size)
+ return BuildPreambleError::PreambleIsEmpty;
+
+ auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
+ FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
+ PreprocessorOptions &PreprocessorOpts =
+ PreambleInvocation->getPreprocessorOpts();
+
+ // Create a temporary file for the precompiled preamble. In rare
+ // circumstances, this can fail.
+ llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
+ PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
+ if (!PreamblePCHFile)
+ return BuildPreambleError::CouldntCreateTempFile;
+
+ // Save the preamble text for later; we'll need to compare against it for
+ // subsequent reparses.
+ std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
+ MainFileBuffer->getBufferStart() +
+ Bounds.Size);
+ bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
+
+ // Tell the compiler invocation to generate a temporary precompiled header.
+ FrontendOpts.ProgramAction = frontend::GeneratePCH;
+ // FIXME: Generate the precompiled header into memory?
+ FrontendOpts.OutputFile = PreamblePCHFile->getFilePath();
+ PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
+ PreprocessorOpts.PrecompiledPreambleBytes.second = false;
+
+ // Create the compiler instance to use for building the precompiled preamble.
+ std::unique_ptr<CompilerInstance> Clang(
+ new CompilerInstance(std::move(PCHContainerOps)));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
+ Clang.get());
+
+ Clang->setInvocation(std::move(PreambleInvocation));
+ Clang->setDiagnostics(&Diagnostics);
+
+ // Create the target instance.
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
+ if (!Clang->hasTarget())
+ return BuildPreambleError::CouldntCreateTargetInfo;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Clang->getTarget().adjust(Clang->getLangOpts());
+
+ assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
+ "Invocation must have exactly one source file!");
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
+ InputKind::Source &&
+ "FIXME: AST inputs not yet supported here!");
+ assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
+ InputKind::LLVM_IR &&
+ "IR inputs not support here!");
+
+ // Clear out old caches and data.
+ Diagnostics.Reset();
+ ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
+
+ VFS =
+ createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
+ if (!VFS)
+ return BuildPreambleError::CouldntCreateVFSOverlay;
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
+
+ // Create the source manager.
+ Clang->setSourceManager(
+ new SourceManager(Diagnostics, Clang->getFileManager()));
+
+ auto PreambleDepCollector = std::make_shared<DependencyCollector>();
+ Clang->addDependencyCollector(PreambleDepCollector);
+
+ // Remap the main source file to the preamble buffer.
+ StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
+ auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
+ MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
+ if (PreprocessorOpts.RetainRemappedFileBuffers) {
+ // MainFileBuffer will be deleted by unique_ptr after leaving the method.
+ PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
+ } else {
+ // In that case, remapped buffer will be deleted by CompilerInstance on
+ // BeginSourceFile, so we call release() to avoid double deletion.
+ PreprocessorOpts.addRemappedFile(MainFilePath,
+ PreambleInputBuffer.release());
+ }
+
+ std::unique_ptr<PrecompilePreambleAction> Act;
+ Act.reset(new PrecompilePreambleAction(Callbacks));
+ if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
+ return BuildPreambleError::BeginSourceFileFailed;
+
+ Act->Execute();
+
+ // Run the callbacks.
+ Callbacks.AfterExecute(*Clang);
+
+ Act->EndSourceFile();
+
+ if (!Act->hasEmittedPreamblePCH())
+ return BuildPreambleError::CouldntEmitPCH;
+
+ // Keep track of all of the files that the source manager knows about,
+ // so we can verify whether they have changed or not.
+ llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
+
+ SourceManager &SourceMgr = Clang->getSourceManager();
+ for (auto &Filename : PreambleDepCollector->getDependencies()) {
+ const FileEntry *File = Clang->getFileManager().getFile(Filename);
+ if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
+ continue;
+ if (time_t ModTime = File->getModificationTime()) {
+ FilesInPreamble[File->getName()] =
+ PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
+ ModTime);
+ } else {
+ llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
+ FilesInPreamble[File->getName()] =
+ PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
+ }
+ }
+
+ return PrecompiledPreamble(
+ std::move(*PreamblePCHFile), std::move(PreambleBytes),
+ PreambleEndsAtStartOfLine, std::move(FilesInPreamble));
+}
+
+PreambleBounds PrecompiledPreamble::getBounds() const {
+ return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
+}
+
+bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation,
+ const llvm::MemoryBuffer *MainFileBuffer,
+ PreambleBounds Bounds,
+ vfs::FileSystem *VFS) const {
+
+ assert(
+ Bounds.Size <= MainFileBuffer->getBufferSize() &&
+ "Buffer is too large. Bounds were calculated from a different buffer?");
+
+ auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
+ PreprocessorOptions &PreprocessorOpts =
+ PreambleInvocation->getPreprocessorOpts();
+
+ if (!Bounds.Size)
+ return false;
+
+ // We've previously computed a preamble. Check whether we have the same
+ // preamble now that we did before, and that there's enough space in
+ // the main-file buffer within the precompiled preamble to fit the
+ // new main file.
+ if (PreambleBytes.size() != Bounds.Size ||
+ PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
+ memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
+ Bounds.Size) != 0)
+ return false;
+ // The preamble has not changed. We may be able to re-use the precompiled
+ // preamble.
+
+ // Check that none of the files used by the preamble have changed.
+ // First, make a record of those files that have been overridden via
+ // remapping or unsaved_files.
+ std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
+ for (const auto &R : PreprocessorOpts.RemappedFiles) {
+ vfs::Status Status;
+ if (!moveOnNoError(VFS->status(R.second), Status)) {
+ // If we can't stat the file we're remapping to, assume that something
+ // horrible happened.
+ return false;
+ }
+
+ OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
+ Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
+ }
+
+ for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+ vfs::Status Status;
+ if (!moveOnNoError(VFS->status(RB.first), Status))
+ return false;
+
+ OverriddenFiles[Status.getUniqueID()] =
+ PreambleFileHash::createForMemoryBuffer(RB.second);
+ }
+
+ // Check whether anything has changed.
+ for (const auto &F : FilesInPreamble) {
+ vfs::Status Status;
+ if (!moveOnNoError(VFS->status(F.first()), Status)) {
+ // If we can't stat the file, assume that something horrible happened.
+ return false;
+ }
+
+ std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
+ OverriddenFiles.find(Status.getUniqueID());
+ if (Overridden != OverriddenFiles.end()) {
+ // This file was remapped; check whether the newly-mapped file
+ // matches up with the previous mapping.
+ if (Overridden->second != F.second)
+ return false;
+ continue;
+ }
+
+ // The file was not remapped; check whether it has changed on disk.
+ if (Status.getSize() != uint64_t(F.second.Size) ||
+ llvm::sys::toTimeT(Status.getLastModificationTime()) !=
+ F.second.ModTime)
+ return false;
+ }
+ return true;
+}
+
+void PrecompiledPreamble::AddImplicitPreamble(
+ CompilerInvocation &CI, llvm::MemoryBuffer *MainFileBuffer) const {
+ auto &PreprocessorOpts = CI.getPreprocessorOpts();
+
+ // Configure ImpicitPCHInclude.
+ PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size();
+ PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine;
+ PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
+ PreprocessorOpts.DisablePCHValidation = true;
+
+ // Remap main file to point to MainFileBuffer.
+ auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
+ PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
+}
+
+PrecompiledPreamble::PrecompiledPreamble(
+ TempPCHFile PCHFile, std::vector<char> PreambleBytes,
+ bool PreambleEndsAtStartOfLine,
+ llvm::StringMap<PreambleFileHash> FilesInPreamble)
+ : PCHFile(std::move(PCHFile)), FilesInPreamble(FilesInPreamble),
+ PreambleBytes(std::move(PreambleBytes)),
+ PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
+
+llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
+PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
+ // FIXME: This is a hack so that we can override the preamble file during
+ // crash-recovery testing, which is the only case where the preamble files
+ // are not necessarily cleaned up.
+ const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
+ if (TmpFile)
+ return TempPCHFile::createFromCustomPath(TmpFile);
+ return TempPCHFile::createInSystemTempDir("preamble", "pch");
+}
+
+llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
+PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
+ StringRef Suffix) {
+ llvm::SmallString<64> File;
+ auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, /*ref*/ File);
+ if (EC)
+ return EC;
+ return TempPCHFile(std::move(File).str());
+}
+
+llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
+PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
+ return TempPCHFile(Path.str());
+}
+
+PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
+ : FilePath(std::move(FilePath)) {
+ TemporaryFiles::getInstance().addFile(*this->FilePath);
+}
+
+PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
+ FilePath = std::move(Other.FilePath);
+ Other.FilePath = None;
+}
+
+PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
+operator=(TempPCHFile &&Other) {
+ RemoveFileIfPresent();
+
+ FilePath = std::move(Other.FilePath);
+ Other.FilePath = None;
+ return *this;
+}
+
+PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
+
+void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
+ if (FilePath) {
+ TemporaryFiles::getInstance().removeFile(*FilePath);
+ FilePath = None;
+ }
+}
+
+llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
+ assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
+ return *FilePath;
+}
+
+PrecompiledPreamble::PreambleFileHash
+PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
+ time_t ModTime) {
+ PreambleFileHash Result;
+ Result.Size = Size;
+ Result.ModTime = ModTime;
+ Result.MD5 = {};
+ return Result;
+}
+
+PrecompiledPreamble::PreambleFileHash
+PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
+ const llvm::MemoryBuffer *Buffer) {
+ PreambleFileHash Result;
+ Result.Size = Buffer->getBufferSize();
+ Result.ModTime = 0;
+
+ llvm::MD5 MD5Ctx;
+ MD5Ctx.update(Buffer->getBuffer().data());
+ MD5Ctx.final(Result.MD5);
+
+ return Result;
+}
+
+void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {}
+void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {}
+void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {}
+void PreambleCallbacks::HandleMacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {}
+
+std::error_code clang::make_error_code(BuildPreambleError Error) {
+ return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
+}
+
+const char *BuildPreambleErrorCategory::name() const noexcept {
+ return "build-preamble.error";
+}
+
+std::string BuildPreambleErrorCategory::message(int condition) const {
+ switch (static_cast<BuildPreambleError>(condition)) {
+ case BuildPreambleError::PreambleIsEmpty:
+ return "Preamble is empty";
+ case BuildPreambleError::CouldntCreateTempFile:
+ return "Could not create temporary file for PCH";
+ case BuildPreambleError::CouldntCreateTargetInfo:
+ return "CreateTargetInfo() return null";
+ case BuildPreambleError::CouldntCreateVFSOverlay:
+ return "Could not create VFS Overlay";
+ case BuildPreambleError::BeginSourceFileFailed:
+ return "BeginSourceFile() return an error";
+ case BuildPreambleError::CouldntEmitPCH:
+ return "Could not emit PCH";
+ }
+ llvm_unreachable("unexpected BuildPreambleError");
+}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index d48b952..914039a 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -38,8 +38,8 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
if (MI.isFunctionLike()) {
OS << '(';
- if (!MI.arg_empty()) {
- MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+ if (!MI.param_empty()) {
+ MacroInfo::param_iterator AI = MI.param_begin(), E = MI.param_end();
for (; AI+1 != E; ++AI) {
OS << (*AI)->getName();
OS << ',';
@@ -172,7 +172,11 @@ public:
/// MacroUndefined - This hook is called whenever a macro #undef is seen.
void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) override;
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) override;
+
+ void BeginModule(const Module *M);
+ void EndModule(const Module *M);
};
} // end anonymous namespace
@@ -323,47 +327,68 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc,
StringRef SearchPath,
StringRef RelativePath,
const Module *Imported) {
- if (Imported) {
- // When preprocessing, turn implicit imports into @imports.
- // FIXME: This is a stop-gap until a more comprehensive "preprocessing with
- // modules" solution is introduced.
+ // In -dI mode, dump #include directives prior to dumping their content or
+ // interpretation.
+ if (DumpIncludeDirectives) {
startNewLineIfNeeded();
MoveToLine(HashLoc);
- if (PP.getLangOpts().ObjC2) {
- OS << "@import " << Imported->getFullModuleName() << ";"
- << " /* clang -E: implicit import for \"" << File->getName()
- << "\" */";
- } else {
- const std::string TokenText = PP.getSpelling(IncludeTok);
- assert(!TokenText.empty());
- OS << "#" << TokenText << " "
- << (IsAngled ? '<' : '"')
- << FileName
- << (IsAngled ? '>' : '"')
- << " /* clang -E: implicit import for module "
- << Imported->getFullModuleName() << " */";
- }
- // Since we want a newline after the @import, but not a #<line>, start a new
- // line immediately.
- EmittedTokensOnThisLine = true;
+ const std::string TokenText = PP.getSpelling(IncludeTok);
+ assert(!TokenText.empty());
+ OS << "#" << TokenText << " "
+ << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
+ << " /* clang -E -dI */";
+ setEmittedDirectiveOnThisLine();
startNewLineIfNeeded();
- } else {
- // Not a module import; it's a more vanilla inclusion of some file using one
- // of: #include, #import, #include_next, #include_macros.
- if (DumpIncludeDirectives) {
+ }
+
+ // When preprocessing, turn implicit imports into module import pragmas.
+ if (Imported) {
+ switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
+ case tok::pp_include:
+ case tok::pp_import:
+ case tok::pp_include_next:
startNewLineIfNeeded();
MoveToLine(HashLoc);
- const std::string TokenText = PP.getSpelling(IncludeTok);
- assert(!TokenText.empty());
- OS << "#" << TokenText << " "
+ OS << "#pragma clang module import " << Imported->getFullModuleName(true)
+ << " /* clang -E: implicit import for "
+ << "#" << PP.getSpelling(IncludeTok) << " "
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
- << " /* clang -E -dI */";
- setEmittedDirectiveOnThisLine();
+ << " */";
+ // Since we want a newline after the pragma, but not a #<line>, start a
+ // new line immediately.
+ EmittedTokensOnThisLine = true;
startNewLineIfNeeded();
+ break;
+
+ case tok::pp___include_macros:
+ // #__include_macros has no effect on a user of a preprocessed source
+ // file; the only effect is on preprocessing.
+ //
+ // FIXME: That's not *quite* true: it causes the module in question to
+ // be loaded, which can affect downstream diagnostics.
+ break;
+
+ default:
+ llvm_unreachable("unknown include directive kind");
+ break;
}
}
}
+/// 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(true);
+ 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(true) << "*/";
+ setEmittedDirectiveOnThisLine();
+}
+
/// Ident - Handle #ident directives when read by the preprocessor.
///
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) {
@@ -389,7 +414,8 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
}
void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD) {
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) {
// Only print out macro definitions in -dD mode.
if (!DumpDefines) return;
@@ -676,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() &&
@@ -773,26 +813,33 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
// Expand macros in pragmas with -fms-extensions. The assumption is that
// the majority of pragmas in such a file will be Microsoft pragmas.
- PP.AddPragmaHandler(new UnknownPragmaHandler(
- "#pragma", Callbacks,
+ // Remember the handlers we will add so that we can remove them later.
+ std::unique_ptr<UnknownPragmaHandler> MicrosoftExtHandler(
+ new UnknownPragmaHandler(
+ "#pragma", Callbacks,
+ /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
+
+ std::unique_ptr<UnknownPragmaHandler> GCCHandler(new UnknownPragmaHandler(
+ "#pragma GCC", Callbacks,
/*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
- PP.AddPragmaHandler(
- "GCC", new UnknownPragmaHandler(
- "#pragma GCC", Callbacks,
- /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
- PP.AddPragmaHandler(
- "clang", new UnknownPragmaHandler(
- "#pragma clang", Callbacks,
- /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
+
+ std::unique_ptr<UnknownPragmaHandler> ClangHandler(new UnknownPragmaHandler(
+ "#pragma clang", Callbacks,
+ /*RequireTokenExpansion=*/PP.getLangOpts().MicrosoftExt));
+
+ PP.AddPragmaHandler(MicrosoftExtHandler.get());
+ PP.AddPragmaHandler("GCC", GCCHandler.get());
+ PP.AddPragmaHandler("clang", ClangHandler.get());
// The tokens after pragma omp need to be expanded.
//
// OpenMP [2.1, Directive format]
// Preprocessing tokens following the #pragma omp are subject to macro
// replacement.
- PP.AddPragmaHandler("omp",
- new UnknownPragmaHandler("#pragma omp", Callbacks,
- /*RequireTokenExpansion=*/true));
+ std::unique_ptr<UnknownPragmaHandler> OpenMPHandler(
+ new UnknownPragmaHandler("#pragma omp", Callbacks,
+ /*RequireTokenExpansion=*/true));
+ PP.AddPragmaHandler("omp", OpenMPHandler.get());
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
@@ -820,4 +867,11 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
// Read all the preprocessed tokens, printing them out to the stream.
PrintPreprocessedTokens(PP, Tok, Callbacks, *OS);
*OS << '\n';
+
+ // Remove the handlers we just added to leave the preprocessor in a sane state
+ // so that it can be reused (for example by a clang::Parser instance).
+ PP.RemovePragmaHandler(MicrosoftExtHandler.get());
+ PP.RemovePragmaHandler("GCC", GCCHandler.get());
+ PP.RemovePragmaHandler("clang", ClangHandler.get());
+ PP.RemovePragmaHandler("omp", OpenMPHandler.get());
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp
index 2e76e2e..5efa6ae 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -9,6 +9,8 @@
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Config/config.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -18,6 +20,11 @@
#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleManager.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -86,8 +93,7 @@ public:
};
} // end anonymous namespace
-bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
- StringRef Filename) {
+bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
if (!FEOpts.FixItSuffix.empty()) {
FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
@@ -190,12 +196,123 @@ void RewriteTestAction::ExecuteAction() {
DoRewriteTest(CI.getPreprocessor(), OS.get());
}
+class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
+ CompilerInstance &CI;
+ std::weak_ptr<raw_ostream> Out;
+
+ llvm::DenseSet<const FileEntry*> Rewritten;
+
+public:
+ RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
+ : CI(CI), Out(Out) {}
+
+ void visitModuleFile(StringRef Filename,
+ serialization::ModuleKind Kind) override {
+ auto *File = CI.getFileManager().getFile(Filename);
+ assert(File && "missing file for loaded module?");
+
+ // Only rewrite each module file once.
+ if (!Rewritten.insert(File).second)
+ return;
+
+ serialization::ModuleFile *MF =
+ CI.getModuleManager()->getModuleManager().lookup(File);
+ assert(File && "missing module file for loaded module?");
+
+ // Not interested in PCH / preambles.
+ if (!MF->isModule())
+ return;
+
+ auto OS = Out.lock();
+ assert(OS && "loaded module file after finishing rewrite action?");
+
+ (*OS) << "#pragma clang module build ";
+ if (isValidIdentifier(MF->ModuleName))
+ (*OS) << MF->ModuleName;
+ else {
+ (*OS) << '"';
+ OS->write_escaped(MF->ModuleName);
+ (*OS) << '"';
+ }
+ (*OS) << '\n';
+
+ // Rewrite the contents of the module in a separate compiler instance.
+ CompilerInstance Instance(CI.getPCHContainerOperations(),
+ &CI.getPreprocessor().getPCMCache());
+ Instance.setInvocation(
+ std::make_shared<CompilerInvocation>(CI.getInvocation()));
+ Instance.createDiagnostics(
+ new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
+ /*ShouldOwnClient=*/true);
+ Instance.getFrontendOpts().DisableFree = false;
+ Instance.getFrontendOpts().Inputs.clear();
+ Instance.getFrontendOpts().Inputs.emplace_back(
+ Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
+ Instance.getFrontendOpts().ModuleFiles.clear();
+ Instance.getFrontendOpts().ModuleMapFiles.clear();
+ // Don't recursively rewrite imports. We handle them all at the top level.
+ Instance.getPreprocessorOutputOpts().RewriteImports = false;
+
+ llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
+ RewriteIncludesAction Action;
+ Action.OutputStream = OS;
+ Instance.ExecuteAction(Action);
+ });
+
+ (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
+ }
+};
+
+bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
+ if (!OutputStream) {
+ OutputStream = CI.createDefaultOutputFile(true, getCurrentFile());
+ if (!OutputStream)
+ return false;
+ }
+
+ auto &OS = *OutputStream;
+
+ // 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 \"";
+ OS.write_escaped(Input.getFile());
+ OS << "\"\n";
+ }
+ getCurrentModule()->print(OS);
+ OS << "#pragma clang module contents\n";
+ }
+
+ // If we're rewriting imports, set up a listener to track when we import
+ // module files.
+ if (CI.getPreprocessorOutputOpts().RewriteImports) {
+ CI.createModuleManager();
+ CI.getModuleManager()->addListener(
+ llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
+ }
+
+ return true;
+}
+
void RewriteIncludesAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
- std::unique_ptr<raw_ostream> OS =
- CI.createDefaultOutputFile(true, getCurrentFile());
- if (!OS) return;
- RewriteIncludesInInput(CI.getPreprocessor(), OS.get(),
- CI.getPreprocessorOutputOpts());
+ // If we're rewriting imports, emit the module build output first rather
+ // than switching back and forth (potentially in the middle of a line).
+ if (CI.getPreprocessorOutputOpts().RewriteImports) {
+ std::string Buffer;
+ llvm::raw_string_ostream OS(Buffer);
+
+ RewriteIncludesInInput(CI.getPreprocessor(), &OS,
+ CI.getPreprocessorOutputOpts());
+
+ (*OutputStream) << OS.str();
+ } else {
+ RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
+ CI.getPreprocessorOutputOpts());
+ }
+
+ OutputStream.reset();
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
index d953da2..e047706 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -46,17 +46,24 @@ 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;
public:
InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers,
bool UseLineDirectives);
- bool Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
+ void Process(FileID FileId, SrcMgr::CharacteristicKind FileType);
void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) {
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);
};
@@ -132,7 +140,7 @@ void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line,
}
void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) {
- OS << "@import " << Mod->getFullModuleName() << ";"
+ OS << "#pragma clang module import " << Mod->getFullModuleName(true)
<< " /* clang -frewrite-includes: implicit import */" << MainEOL;
}
@@ -169,7 +177,9 @@ void InclusionRewriter::FileSkipped(const FileEntry &/*SkippedFile*/,
/// directives. It does not say whether the file has been included, but it
/// provides more information about the directive (hash location instead
/// of location inside the included file). It is assumed that the matching
-/// FileChanged() or FileSkipped() is called after this.
+/// FileChanged() or FileSkipped() is called after this (or neither is
+/// called if this #include results in an error or does not textually include
+/// anything).
void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
const Token &/*IncludeTok*/,
StringRef /*FileName*/,
@@ -179,9 +189,6 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
StringRef /*SearchPath*/,
StringRef /*RelativePath*/,
const Module *Imported) {
- assert(LastInclusionLocation.isInvalid() &&
- "Another inclusion directive was found before the previous one "
- "was processed");
if (Imported) {
auto P = ModuleIncludes.insert(
std::make_pair(HashLoc.getRawEncoding(), Imported));
@@ -211,6 +218,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) {
@@ -392,7 +409,7 @@ bool InclusionRewriter::HandleHasInclude(
// FIXME: Why don't we call PP.LookupFile here?
const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr,
- nullptr, nullptr, nullptr, false);
+ nullptr, nullptr, nullptr, nullptr);
FileExists = File != nullptr;
return true;
@@ -400,9 +417,8 @@ bool InclusionRewriter::HandleHasInclude(
/// Use a raw lexer to analyze \p FileId, incrementally copying parts of it
/// and including content of included files recursively.
-bool InclusionRewriter::Process(FileID FileId,
- SrcMgr::CharacteristicKind FileType)
-{
+void InclusionRewriter::Process(FileID FileId,
+ SrcMgr::CharacteristicKind FileType) {
bool Invalid;
const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid);
assert(!Invalid && "Attempting to process invalid inclusion");
@@ -419,7 +435,7 @@ bool InclusionRewriter::Process(FileID FileId,
WriteLineInfo(FileName, 1, FileType, " 1");
if (SM.getFileIDSize(FileId) == 0)
- return false;
+ return;
// The next byte to be copied from the source file, which may be non-zero if
// the lexer handled a BOM.
@@ -450,19 +466,24 @@ bool InclusionRewriter::Process(FileID FileId,
WriteLineInfo(FileName, Line - 1, FileType, "");
StringRef LineInfoExtra;
SourceLocation Loc = HashToken.getLocation();
- if (const Module *Mod = PP.getLangOpts().ObjC2
- ? FindModuleAtLocation(Loc)
- : nullptr)
+ if (const Module *Mod = FindModuleAtLocation(Loc))
WriteImplicitModuleImport(Mod);
else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
- // include and recursively process the file
- if (Process(Inc->Id, Inc->FileType)) {
- // and set lineinfo back to this file, if the nested one was
- // actually included
- // `2' indicates returning to a file (after having included
- // another file.
- LineInfoExtra = " 2";
- }
+ const Module *Mod = FindEnteredModule(Loc);
+ if (Mod)
+ OS << "#pragma clang module begin "
+ << Mod->getFullModuleName(true) << "\n";
+
+ // Include and recursively process the file.
+ Process(Inc->Id, Inc->FileType);
+
+ if (Mod)
+ OS << "#pragma clang module end /*"
+ << Mod->getFullModuleName(true) << "*/\n";
+
+ // Add line marker to indicate we're returning from an included
+ // file.
+ LineInfoExtra = " 2";
}
// fix up lineinfo (since commented out directive changed line
// numbers) for inclusions that were skipped due to header guards
@@ -571,7 +592,6 @@ bool InclusionRewriter::Process(FileID FileId,
OutputContentUpTo(FromFile, NextToWrite,
SM.getFileOffset(SM.getLocForEndOfFile(FileId)), LocalEOL,
Line, /*EnsureNewline=*/true);
- return true;
}
/// InclusionRewriterInInput - Implement -frewrite-includes mode.
@@ -597,6 +617,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/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp
index 0d0a991..ae6b51b 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteMacros.cpp
@@ -76,7 +76,7 @@ static void LexRawTokensFromMainFile(Preprocessor &PP,
RawLex.LexFromRawLexer(RawTok);
// If we have an identifier with no identifier info for our raw token, look
- // up the indentifier info. This is important for equality comparison of
+ // up the identifier info. This is important for equality comparison of
// identifier tokens.
if (RawTok.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(RawTok);
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index e7bfced..21686b8 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -21,6 +21,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Config/config.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/DenseSet.h"
@@ -146,7 +147,7 @@ namespace {
llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
llvm::DenseMap<ObjCInterfaceDecl *,
- llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars;
+ llvm::SmallSetVector<ObjCIvarDecl *, 8> > ReferencedIvars;
// ivar bitfield grouping containers
llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups;
@@ -1013,7 +1014,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
Setr = "\nextern \"C\" __declspec(dllimport) "
"void objc_setProperty (id, SEL, long, id, bool, bool);\n";
}
-
+
RewriteObjCMethodDecl(OID->getContainingInterface(),
PD->getSetterMethodDecl(), Setr);
Setr += "{ ";
@@ -3965,10 +3966,11 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
std::string &Result) {
// write out ivar offset symbols which have been referenced in an ivar
// access expression.
- llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
+ llvm::SmallSetVector<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
+
if (Ivars.empty())
return;
-
+
llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput;
for (ObjCIvarDecl *IvarDecl : Ivars) {
const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface();
@@ -4454,7 +4456,7 @@ static void BuildUniqueMethodName(std::string &Name,
Name += "__" + MD->getSelector().getAsString();
// Convert colons to underscores.
std::string::size_type loc = 0;
- while ((loc = Name.find(":", loc)) != std::string::npos)
+ while ((loc = Name.find(':', loc)) != std::string::npos)
Name.replace(loc, 1, "_");
}
@@ -5141,7 +5143,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl,
if (!hasInit) {
ByrefType += "};\n";
unsigned nameSize = Name.size();
- // for block or function pointer declaration. Name is aleady
+ // for block or function pointer declaration. Name is already
// part of the declaration.
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
nameSize = 1;
@@ -6068,7 +6070,7 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
}
-/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
+/// RewriteIvarOffsetComputation - This routine synthesizes computation of
/// ivar offset.
void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
std::string &Result) {
@@ -7500,7 +7502,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
BinaryOperator *addExpr =
new (Context) BinaryOperator(castExpr, DRE, BO_Add,
Context->getPointerType(Context->CharTy),
- VK_RValue, OK_Ordinary, SourceLocation(), false);
+ VK_RValue, OK_Ordinary, SourceLocation(), FPOptions());
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(),
SourceLocation(),
diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
index e842e59..e0d813d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Config/config.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/DenseSet.h"
@@ -2992,7 +2993,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
BinaryOperator *lessThanExpr =
new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
VK_RValue, OK_Ordinary, SourceLocation(),
- false);
+ FPOptions());
// (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
ConditionalOperator *CondExpr =
new (Context) ConditionalOperator(lessThanExpr,
@@ -3629,7 +3630,7 @@ static void BuildUniqueMethodName(std::string &Name,
Name += "__" + MD->getSelector().getAsString();
// Convert colons to underscores.
std::string::size_type loc = 0;
- while ((loc = Name.find(":", loc)) != std::string::npos)
+ while ((loc = Name.find(':', loc)) != std::string::npos)
Name.replace(loc, 1, "_");
}
@@ -4261,7 +4262,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
}
ByrefType += "};\n";
unsigned nameSize = Name.size();
- // for block or function pointer declaration. Name is aleady
+ // for block or function pointer declaration. Name is already
// part of the declaration.
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType())
nameSize = 1;
@@ -5052,7 +5053,7 @@ void RewriteObjCFragileABI::Initialize(ASTContext &context) {
Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n";
}
-/// RewriteIvarOffsetComputation - This rutine synthesizes computation of
+/// RewriteIvarOffsetComputation - This routine synthesizes computation of
/// ivar offset.
void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
std::string &Result) {
diff --git a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 7f88c91..7666fe1 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -63,27 +63,20 @@ public:
~SDiagsRenderer() override {}
protected:
- void emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
+ void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
ArrayRef<CharSourceRange> Ranges,
- const SourceManager *SM,
DiagOrStoredDiag D) override;
- void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) override {}
+ ArrayRef<CharSourceRange> Ranges) override {}
- void emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM) override;
+ void emitNote(FullSourceLoc Loc, StringRef Message) override;
- void emitCodeContext(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) override;
+ void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) override;
void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) override;
@@ -193,11 +186,8 @@ private:
void ExitDiagBlock();
/// \brief Emit a DIAG record.
- void EmitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- const SourceManager *SM,
+ void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
DiagOrStoredDiag D);
/// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic.
@@ -220,16 +210,14 @@ private:
/// \brief Emit (lazily) the file string and retrieved the file identifier.
unsigned getEmitFile(const char *Filename);
- /// \brief Add SourceLocation information the specified record.
- void AddLocToRecord(SourceLocation Loc, const SourceManager *SM,
- PresumedLoc PLoc, RecordDataImpl &Record,
- unsigned TokSize = 0);
+ /// \brief Add SourceLocation information the specified record.
+ void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
+ RecordDataImpl &Record, unsigned TokSize = 0);
/// \brief Add SourceLocation information the specified record.
- void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
- const SourceManager *SM,
+ void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &Record,
unsigned TokSize = 0) {
- AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(),
+ AddLocToRecord(Loc, Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(),
Record, TokSize);
}
@@ -350,11 +338,8 @@ static void EmitRecordID(unsigned ID, const char *Name,
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
}
-void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
- const SourceManager *SM,
- PresumedLoc PLoc,
- RecordDataImpl &Record,
- unsigned TokSize) {
+void SDiagsWriter::AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
+ RecordDataImpl &Record, unsigned TokSize) {
if (PLoc.isInvalid()) {
// Emit a "sentinel" location.
Record.push_back((unsigned)0); // File.
@@ -367,19 +352,19 @@ void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
Record.push_back(getEmitFile(PLoc.getFilename()));
Record.push_back(PLoc.getLine());
Record.push_back(PLoc.getColumn()+TokSize);
- Record.push_back(SM->getFileOffset(Loc));
+ Record.push_back(Loc.getFileOffset());
}
void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
RecordDataImpl &Record,
const SourceManager &SM) {
- AddLocToRecord(Range.getBegin(), Record, &SM);
+ AddLocToRecord(FullSourceLoc(Range.getBegin(), SM), Record);
unsigned TokSize = 0;
if (Range.isTokenRange())
TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
SM, *LangOpts);
-
- AddLocToRecord(Range.getEnd(), Record, &SM, TokSize);
+
+ AddLocToRecord(FullSourceLoc(Range.getEnd(), SM), Record, TokSize);
}
unsigned SDiagsWriter::getEmitFile(const char *FileName){
@@ -506,7 +491,7 @@ void SDiagsWriter::EmitBlockInfoBlock() {
Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modification time.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
@@ -606,8 +591,8 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
if (DiagLevel == DiagnosticsEngine::Note)
EnterDiagBlock();
- EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
- State->diagBuf, nullptr, &Info);
+ EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel,
+ State->diagBuf, &Info);
if (DiagLevel == DiagnosticsEngine::Note)
ExitDiagBlock();
@@ -618,12 +603,9 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
assert(Info.hasSourceManager() && LangOpts &&
"Unexpected diagnostic with valid location outside of a source file");
SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
- Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
- State->diagBuf,
- Info.getRanges(),
- Info.getFixItHints(),
- &Info.getSourceManager(),
- &Info);
+ Renderer.emitDiagnostic(
+ FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel,
+ State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info);
}
static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) {
@@ -641,11 +623,9 @@ static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) {
llvm_unreachable("invalid diagnostic level");
}
-void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
+void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
StringRef Message,
- const SourceManager *SM,
DiagOrStoredDiag D) {
llvm::BitstreamWriter &Stream = State->Stream;
RecordData &Record = State->Record;
@@ -655,7 +635,7 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
Record.clear();
Record.push_back(RECORD_DIAG);
Record.push_back(getStableLevel(Level));
- AddLocToRecord(Loc, SM, PLoc, Record);
+ AddLocToRecord(Loc, PLoc, Record);
if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
// Emit the category string lazily and get the category ID.
@@ -672,15 +652,11 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message);
}
-void
-SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- ArrayRef<clang::CharSourceRange> Ranges,
- const SourceManager *SM,
- DiagOrStoredDiag D) {
- Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
+void SDiagsRenderer::emitDiagnosticMessage(
+ FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
+ StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
+ Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D);
}
void SDiagsWriter::EnterDiagBlock() {
@@ -733,20 +709,18 @@ void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
}
}
-void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
+void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc,
DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange> &Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
- Writer.EmitCodeContext(Ranges, Hints, SM);
+ ArrayRef<FixItHint> Hints) {
+ Writer.EmitCodeContext(Ranges, Hints, Loc.getManager());
}
-void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM) {
+void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) {
Writer.EnterDiagBlock();
- PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc();
- Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note,
- Message, SM, DiagOrStoredDiag());
+ PresumedLoc PLoc = Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc();
+ Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, Message,
+ DiagOrStoredDiag());
Writer.ExitDiagBlock();
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp
index c4461d4..08b7087 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticReader.cpp
@@ -27,6 +27,9 @@ std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
llvm::BitstreamCursor Stream(**Buffer);
Optional<llvm::BitstreamBlockInfo> BlockInfo;
+ if (Stream.AtEndOfStream())
+ return SDError::InvalidSignature;
+
// Sniff for the signature.
if (Stream.Read(8) != 'D' ||
Stream.Read(8) != 'I' ||
@@ -125,6 +128,7 @@ SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
case Cursor::BlockBegin:
if (Stream.SkipBlock())
return SDError::MalformedMetadataBlock;
+ LLVM_FALLTHROUGH;
case Cursor::BlockEnd:
if (!VersionChecked)
return SDError::MissingVersion;
diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp
index a493738..6a72b00 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp
@@ -672,20 +672,16 @@ TextDiagnostic::TextDiagnostic(raw_ostream &OS,
TextDiagnostic::~TextDiagnostic() {}
-void
-TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- ArrayRef<clang::CharSourceRange> Ranges,
- const SourceManager *SM,
- DiagOrStoredDiag D) {
+void TextDiagnostic::emitDiagnosticMessage(
+ FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
+ StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
uint64_t StartOfLocationInfo = OS.tell();
// Emit the location of this particular diagnostic.
if (Loc.isValid())
- emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM);
-
+ emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
+
if (DiagOpts->ShowColors)
OS.resetColor();
@@ -787,17 +783,16 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
/// This includes extracting as much location information as is present for
/// the diagnostic and printing it, as well as any include stack or source
/// ranges necessary.
-void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {
+ ArrayRef<CharSourceRange> Ranges) {
if (PLoc.isInvalid()) {
// At least print the file name if available:
- FileID FID = SM.getFileID(Loc);
+ FileID FID = Loc.getFileID();
if (FID.isValid()) {
- const FileEntry* FE = SM.getFileEntryForID(FID);
+ const FileEntry *FE = Loc.getFileEntry();
if (FE && FE->isValid()) {
- emitFilename(FE->getName(), SM);
+ emitFilename(FE->getName(), Loc.getManager());
if (FE->isInPCH())
OS << " (in PCH)";
OS << ": ";
@@ -813,7 +808,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
- emitFilename(PLoc.getFilename(), SM);
+ emitFilename(PLoc.getFilename(), Loc.getManager());
switch (DiagOpts->getFormat()) {
case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
case DiagnosticOptions::MSVC: OS << '(' << LineNo; break;
@@ -848,8 +843,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
}
if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
- FileID CaretFileID =
- SM.getFileID(SM.getExpansionLoc(Loc));
+ FileID CaretFileID = Loc.getExpansionLoc().getFileID();
bool PrintedRange = false;
for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(),
@@ -858,8 +852,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
// Ignore invalid ranges.
if (!RI->isValid()) continue;
- SourceLocation B = SM.getExpansionLoc(RI->getBegin());
- SourceLocation E = SM.getExpansionLoc(RI->getEnd());
+ FullSourceLoc B =
+ FullSourceLoc(RI->getBegin(), Loc.getManager()).getExpansionLoc();
+ FullSourceLoc E =
+ FullSourceLoc(RI->getEnd(), Loc.getManager()).getExpansionLoc();
// If the End location and the start location are the same and are a
// macro location, then the range was something that came from a
@@ -867,10 +863,12 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
// best we can do is to highlight the range. If this is a
// function-like macro, we'd also like to highlight the arguments.
if (B == E && RI->getEnd().isMacroID())
- E = SM.getExpansionRange(RI->getEnd()).second;
+ E = FullSourceLoc(RI->getEnd(), Loc.getManager())
+ .getExpansionRange()
+ .second;
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+ std::pair<FileID, unsigned> BInfo = B.getDecomposedLoc();
+ std::pair<FileID, unsigned> EInfo = E.getDecomposedLoc();
// If the start or end of the range is in another file, just discard
// it.
@@ -881,13 +879,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
// tokens.
unsigned TokSize = 0;
if (RI->isTokenRange())
- TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
+ TokSize = Lexer::MeasureTokenLength(E, E.getManager(), LangOpts);
- OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
- << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
- << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
- << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize)
- << '}';
+ OS << '{' << B.getLineNumber() << ':' << B.getColumnNumber() << '-'
+ << E.getLineNumber() << ':' << (E.getColumnNumber() + TokSize) << '}';
PrintedRange = true;
}
@@ -897,9 +892,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
OS << ' ';
}
-void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
- PresumedLoc PLoc,
- const SourceManager &SM) {
+void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "In file included from " << PLoc.getFilename() << ':'
<< PLoc.getLine() << ":\n";
@@ -907,9 +900,8 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
OS << "In included file:\n";
}
-void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "In module '" << ModuleName << "' imported from "
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
@@ -917,10 +909,9 @@ void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
OS << "In module '" << ModuleName << "':\n";
}
-void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
+void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
PresumedLoc PLoc,
- StringRef ModuleName,
- const SourceManager &SM) {
+ StringRef ModuleName) {
if (DiagOpts->ShowLocation && PLoc.isValid())
OS << "While building module '" << ModuleName << "' imported from "
<< PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
@@ -928,6 +919,56 @@ void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
OS << "While building module '" << ModuleName << "':\n";
}
+/// \brief Find the suitable set of lines to show to include a set of ranges.
+static llvm::Optional<std::pair<unsigned, unsigned>>
+findLinesForRange(const CharSourceRange &R, FileID FID,
+ const SourceManager &SM) {
+ if (!R.isValid()) return None;
+
+ SourceLocation Begin = R.getBegin();
+ SourceLocation End = R.getEnd();
+ if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
+ return None;
+
+ return std::make_pair(SM.getExpansionLineNumber(Begin),
+ SM.getExpansionLineNumber(End));
+}
+
+/// Add as much of range B into range A as possible without exceeding a maximum
+/// size of MaxRange. Ranges are inclusive.
+static std::pair<unsigned, unsigned>
+maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
+ unsigned MaxRange) {
+ // If A is already the maximum size, we're done.
+ unsigned Slack = MaxRange - (A.second - A.first + 1);
+ if (Slack == 0)
+ return A;
+
+ // Easy case: merge succeeds within MaxRange.
+ unsigned Min = std::min(A.first, B.first);
+ unsigned Max = std::max(A.second, B.second);
+ if (Max - Min + 1 <= MaxRange)
+ return {Min, Max};
+
+ // If we can't reach B from A within MaxRange, there's nothing to do.
+ // Don't add lines to the range that contain nothing interesting.
+ if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
+ (B.second < A.second && A.second - B.second + 1 > MaxRange))
+ return A;
+
+ // Otherwise, expand A towards B to produce a range of size MaxRange. We
+ // attempt to expand by the same amount in both directions if B strictly
+ // contains A.
+
+ // Expand downwards by up to half the available amount, then upwards as
+ // much as possible, then downwards as much as possible.
+ A.second = std::min(A.second + (Slack + 1) / 2, Max);
+ Slack = MaxRange - (A.second - A.first + 1);
+ A.first = std::max(Min + Slack, A.first) - Slack;
+ A.second = std::min(A.first + MaxRange - 1, Max);
+ return A;
+}
+
/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
static void highlightRange(const CharSourceRange &R,
unsigned LineNo, FileID FID,
@@ -990,9 +1031,12 @@ static void highlightRange(const CharSourceRange &R,
EndColNo = map.startOfPreviousColumn(EndColNo);
// If the start/end passed each other, then we are trying to highlight a
- // range that just exists in whitespace, which must be some sort of other
- // bug.
- assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
+ // range that just exists in whitespace. That most likely means we have
+ // a multi-line highlighting range that covers a blank line.
+ if (StartColNo > EndColNo) {
+ assert(StartLineNo != EndLineNo && "trying to highlight whitespace");
+ StartColNo = EndColNo;
+ }
}
assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
@@ -1008,7 +1052,8 @@ static void highlightRange(const CharSourceRange &R,
std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
}
-static std::string buildFixItInsertionLine(unsigned LineNo,
+static std::string buildFixItInsertionLine(FileID FID,
+ unsigned LineNo,
const SourceColumnMap &map,
ArrayRef<FixItHint> Hints,
const SourceManager &SM,
@@ -1025,7 +1070,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
// code contains no newlines and is on the same line as the caret.
std::pair<FileID, unsigned> HintLocInfo
= SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
- if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
+ if (FID == HintLocInfo.first &&
+ LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
// Insert the new code into the line just below the code
// that the user wrote.
@@ -1061,9 +1107,6 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
PrevHintEndCol =
HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert);
- } else {
- FixItInsertionLine.clear();
- break;
}
}
}
@@ -1081,10 +1124,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo,
/// \param Ranges The underlined ranges for this code snippet.
/// \param Hints The FixIt hints active for this diagnostic.
void TextDiagnostic::emitSnippetAndCaret(
- SourceLocation Loc, DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
+ FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges, ArrayRef<FixItHint> Hints) {
assert(Loc.isValid() && "must have a valid source location here");
assert(Loc.isFileID() && "must have a file location here");
@@ -1101,111 +1142,128 @@ void TextDiagnostic::emitSnippetAndCaret(
return;
// Decompose the location into a FID/Offset pair.
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc();
FileID FID = LocInfo.first;
- unsigned FileOffset = LocInfo.second;
+ const SourceManager &SM = Loc.getManager();
// Get information about the buffer it points into.
bool Invalid = false;
- StringRef BufData = SM.getBufferData(FID, &Invalid);
+ StringRef BufData = Loc.getBufferData(&Invalid);
if (Invalid)
return;
- const char *BufStart = BufData.data();
- const char *BufEnd = BufStart + BufData.size();
+ unsigned CaretLineNo = Loc.getLineNumber();
+ unsigned CaretColNo = Loc.getColumnNumber();
- unsigned LineNo = SM.getLineNumber(FID, FileOffset);
- unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
-
// Arbitrarily stop showing snippets when the line is too long.
static const size_t MaxLineLengthToPrint = 4096;
- if (ColNo > MaxLineLengthToPrint)
+ if (CaretColNo > MaxLineLengthToPrint)
return;
- // Rewind from the current position to the start of the line.
- const char *TokPtr = BufStart+FileOffset;
- const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
-
- // Compute the line end. Scan forward from the error position to the end of
- // the line.
- const char *LineEnd = TokPtr;
- while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
- ++LineEnd;
-
- // Arbitrarily stop showing snippets when the line is too long.
- if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
- return;
-
- // Trim trailing null-bytes.
- StringRef Line(LineStart, LineEnd - LineStart);
- while (Line.size() > ColNo && Line.back() == '\0')
- Line = Line.drop_back();
+ // Find the set of lines to include.
+ const unsigned MaxLines = DiagOpts->SnippetLineLimit;
+ std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ if (auto OptionalRange = findLinesForRange(*I, FID, SM))
+ Lines = maybeAddRange(Lines, *OptionalRange, MaxLines);
+
+ for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) {
+ const char *BufStart = BufData.data();
+ const char *BufEnd = BufStart + BufData.size();
+
+ // Rewind from the current position to the start of the line.
+ const char *LineStart =
+ BufStart +
+ SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second;
+ if (LineStart == BufEnd)
+ break;
- // Copy the line of code into an std::string for ease of manipulation.
- std::string SourceLine(Line.begin(), Line.end());
+ // Compute the line end.
+ const char *LineEnd = LineStart;
+ while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
+ ++LineEnd;
- // Build the byte to column map.
- const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
+ // Arbitrarily stop showing snippets when the line is too long.
+ // FIXME: Don't print any lines in this case.
+ if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
+ return;
- // Create a line for the caret that is filled with spaces that is the same
- // number of columns as the line of source code.
- std::string CaretLine(sourceColMap.columns(), ' ');
+ // Trim trailing null-bytes.
+ StringRef Line(LineStart, LineEnd - LineStart);
+ while (!Line.empty() && Line.back() == '\0' &&
+ (LineNo != CaretLineNo || Line.size() > CaretColNo))
+ Line = Line.drop_back();
+
+ // Copy the line of code into an std::string for ease of manipulation.
+ std::string SourceLine(Line.begin(), Line.end());
+
+ // Build the byte to column map.
+ const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
+
+ // Create a line for the caret that is filled with spaces that is the same
+ // number of columns as the line of source code.
+ std::string CaretLine(sourceColMap.columns(), ' ');
+
+ // Highlight all of the characters covered by Ranges with ~ characters.
+ for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I)
+ highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
+
+ // Next, insert the caret itself.
+ if (CaretLineNo == LineNo) {
+ CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1);
+ if (CaretLine.size() < CaretColNo + 1)
+ CaretLine.resize(CaretColNo + 1, ' ');
+ CaretLine[CaretColNo] = '^';
+ }
- // Highlight all of the characters covered by Ranges with ~ characters.
- for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I)
- highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
-
- // Next, insert the caret itself.
- ColNo = sourceColMap.byteToContainingColumn(ColNo-1);
- if (CaretLine.size()<ColNo+1)
- CaretLine.resize(ColNo+1, ' ');
- CaretLine[ColNo] = '^';
-
- std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
- sourceColMap,
- Hints, SM,
- DiagOpts.get());
-
- // If the source line is too long for our terminal, select only the
- // "interesting" source region within that line.
- unsigned Columns = DiagOpts->MessageLength;
- if (Columns)
- selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
- Columns, sourceColMap);
-
- // If we are in -fdiagnostics-print-source-range-info mode, we are trying
- // to produce easily machine parsable output. Add a space before the
- // source line and the caret to make it trivial to tell the main diagnostic
- // line from what the user is intended to see.
- if (DiagOpts->ShowSourceRanges) {
- SourceLine = ' ' + SourceLine;
- CaretLine = ' ' + CaretLine;
- }
+ std::string FixItInsertionLine = buildFixItInsertionLine(
+ FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get());
+
+ // If the source line is too long for our terminal, select only the
+ // "interesting" source region within that line.
+ unsigned Columns = DiagOpts->MessageLength;
+ if (Columns)
+ selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
+ Columns, sourceColMap);
+
+ // If we are in -fdiagnostics-print-source-range-info mode, we are trying
+ // to produce easily machine parsable output. Add a space before the
+ // source line and the caret to make it trivial to tell the main diagnostic
+ // line from what the user is intended to see.
+ if (DiagOpts->ShowSourceRanges) {
+ SourceLine = ' ' + SourceLine;
+ CaretLine = ' ' + CaretLine;
+ }
- // Finally, remove any blank spaces from the end of CaretLine.
- while (CaretLine[CaretLine.size()-1] == ' ')
- CaretLine.erase(CaretLine.end()-1);
+ // Finally, remove any blank spaces from the end of CaretLine.
+ while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] == ' ')
+ CaretLine.erase(CaretLine.end() - 1);
- // Emit what we have computed.
- emitSnippet(SourceLine);
+ // Emit what we have computed.
+ emitSnippet(SourceLine);
- if (DiagOpts->ShowColors)
- OS.changeColor(caretColor, true);
- OS << CaretLine << '\n';
- if (DiagOpts->ShowColors)
- OS.resetColor();
+ if (!CaretLine.empty()) {
+ if (DiagOpts->ShowColors)
+ OS.changeColor(caretColor, true);
+ OS << CaretLine << '\n';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+ }
- if (!FixItInsertionLine.empty()) {
- if (DiagOpts->ShowColors)
- // Print fixit line in color
- OS.changeColor(fixitColor, false);
- if (DiagOpts->ShowSourceRanges)
- OS << ' ';
- OS << FixItInsertionLine << '\n';
- if (DiagOpts->ShowColors)
- OS.resetColor();
+ if (!FixItInsertionLine.empty()) {
+ if (DiagOpts->ShowColors)
+ // Print fixit line in color
+ OS.changeColor(fixitColor, false);
+ if (DiagOpts->ShowSourceRanges)
+ OS << ' ';
+ OS << FixItInsertionLine << '\n';
+ if (DiagOpts->ShowColors)
+ OS.resetColor();
+ }
}
// Print out any parseable fixit information requested by the options.
diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index 17646b4..5dd3252 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -150,10 +150,9 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
"Unexpected diagnostic with no source manager");
assert(TextDiag && "Unexpected diagnostic outside source file processing");
- TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(),
- Info.getRanges(),
- Info.getFixItHints(),
- &Info.getSourceManager());
+ TextDiag->emitDiagnostic(
+ FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level,
+ DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints());
OS.flush();
}
diff --git a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index ae16ea1..427d15e 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -400,7 +400,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
const DirectoryLookup *CurDir;
const FileEntry *FE =
PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
- nullptr, nullptr, nullptr);
+ nullptr, nullptr, nullptr, nullptr);
if (!FE) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_file) << Filename << KindStr;
diff --git a/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 187a6e7..1666315 100644
--- a/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -15,6 +15,7 @@
#include "clang/FrontendTool/Utils.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -85,7 +86,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
case PrintDeclContext: return llvm::make_unique<DeclContextPrintAction>();
case PrintPreamble: return llvm::make_unique<PrintPreambleAction>();
case PrintPreprocessedInput: {
- if (CI.getPreprocessorOutputOpts().RewriteIncludes)
+ if (CI.getPreprocessorOutputOpts().RewriteIncludes ||
+ CI.getPreprocessorOutputOpts().RewriteImports)
return llvm::make_unique<RewriteIncludesAction>();
return llvm::make_unique<PrintPreprocessedAction>();
}
@@ -174,7 +176,7 @@ CreateFrontendAction(CompilerInstance &CI) {
bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Honor -help.
if (Clang->getFrontendOpts().ShowHelp) {
- std::unique_ptr<OptTable> Opts(driver::createDriverOptTable());
+ std::unique_ptr<OptTable> Opts = driver::createDriverOptTable();
Opts->PrintHelp(llvm::outs(), "clang -cc1",
"LLVM 'Clang' Compiler: http://clang.llvm.org",
/*Include=*/ driver::options::CC1Option, /*Exclude=*/ 0);
diff --git a/contrib/llvm/tools/clang/lib/Headers/altivec.h b/contrib/llvm/tools/clang/lib/Headers/altivec.h
index a01d9d8..90fd477 100644
--- a/contrib/llvm/tools/clang/lib/Headers/altivec.h
+++ b/contrib/llvm/tools/clang/lib/Headers/altivec.h
@@ -2887,87 +2887,79 @@ static __inline__ vector double __ATTRS_o_ai vec_cpsgn(vector double __a,
/* vec_ctf */
-static __inline__ vector float __ATTRS_o_ai vec_ctf(vector int __a, int __b) {
- return __builtin_altivec_vcfsx(__a, __b);
-}
-
-static __inline__ vector float __ATTRS_o_ai vec_ctf(vector unsigned int __a,
- int __b) {
- return __builtin_altivec_vcfux((vector int)__a, __b);
-}
-
#ifdef __VSX__
-static __inline__ vector double __ATTRS_o_ai
-vec_ctf(vector unsigned long long __a, int __b) {
- vector double __ret = __builtin_convertvector(__a, vector double);
- __ret *= (vector double)(vector unsigned long long)((0x3ffULL - __b) << 52);
- return __ret;
-}
-
-static __inline__ vector double __ATTRS_o_ai
-vec_ctf(vector signed long long __a, int __b) {
- vector double __ret = __builtin_convertvector(__a, vector double);
- __ret *= (vector double)(vector unsigned long long)((0x3ffULL - __b) << 52);
- return __ret;
-}
+#define vec_ctf(__a, __b) \
+ _Generic((__a), vector int \
+ : (vector float)__builtin_altivec_vcfsx((__a), (__b)), \
+ vector unsigned int \
+ : (vector float)__builtin_altivec_vcfux((vector int)(__a), (__b)), \
+ vector unsigned long long \
+ : (__builtin_convertvector((vector unsigned long long)(__a), \
+ vector double) * \
+ (vector double)(vector unsigned long long)((0x3ffULL - (__b)) \
+ << 52)), \
+ vector signed long long \
+ : (__builtin_convertvector((vector signed long long)(__a), \
+ vector double) * \
+ (vector double)(vector unsigned long long)((0x3ffULL - (__b)) \
+ << 52)))
+#else
+#define vec_ctf(__a, __b) \
+ _Generic((__a), vector int \
+ : (vector float)__builtin_altivec_vcfsx((__a), (__b)), \
+ vector unsigned int \
+ : (vector float)__builtin_altivec_vcfux((vector int)(__a), (__b)))
#endif
/* vec_vcfsx */
-static __inline__ vector float __attribute__((__always_inline__))
-vec_vcfsx(vector int __a, int __b) {
- return __builtin_altivec_vcfsx(__a, __b);
-}
+#define vec_vcfux __builtin_altivec_vcfux
/* vec_vcfux */
-static __inline__ vector float __attribute__((__always_inline__))
-vec_vcfux(vector unsigned int __a, int __b) {
- return __builtin_altivec_vcfux((vector int)__a, __b);
-}
+#define vec_vcfsx(__a, __b) __builtin_altivec_vcfsx((vector int)(__a), (__b))
/* vec_cts */
-static __inline__ vector int __ATTRS_o_ai vec_cts(vector float __a, int __b) {
- return __builtin_altivec_vctsxs(__a, __b);
-}
-
#ifdef __VSX__
-static __inline__ vector signed long long __ATTRS_o_ai
-vec_cts(vector double __a, int __b) {
- __a *= (vector double)(vector unsigned long long)((0x3ffULL + __b) << 52);
- return __builtin_convertvector(__a, vector signed long long);
-}
+#define vec_cts(__a, __b) \
+ _Generic((__a), vector float \
+ : __builtin_altivec_vctsxs((__a), (__b)), vector double \
+ : __extension__({ \
+ vector double __ret = \
+ (__a) * \
+ (vector double)(vector unsigned long long)((0x3ffULL + (__b)) \
+ << 52); \
+ __builtin_convertvector(__ret, vector signed long long); \
+ }))
+#else
+#define vec_cts __builtin_altivec_vctsxs
#endif
/* vec_vctsxs */
-static __inline__ vector int __attribute__((__always_inline__))
-vec_vctsxs(vector float __a, int __b) {
- return __builtin_altivec_vctsxs(__a, __b);
-}
+#define vec_vctsxs __builtin_altivec_vctsxs
/* vec_ctu */
-static __inline__ vector unsigned int __ATTRS_o_ai vec_ctu(vector float __a,
- int __b) {
- return __builtin_altivec_vctuxs(__a, __b);
-}
-
#ifdef __VSX__
-static __inline__ vector unsigned long long __ATTRS_o_ai
-vec_ctu(vector double __a, int __b) {
- __a *= (vector double)(vector unsigned long long)((0x3ffULL + __b) << 52);
- return __builtin_convertvector(__a, vector unsigned long long);
-}
+#define vec_ctu(__a, __b) \
+ _Generic((__a), vector float \
+ : __builtin_altivec_vctuxs((__a), (__b)), vector double \
+ : __extension__({ \
+ vector double __ret = \
+ (__a) * \
+ (vector double)(vector unsigned long long)((0x3ffULL + __b) \
+ << 52); \
+ __builtin_convertvector(__ret, vector unsigned long long); \
+ }))
+#else
+#define vec_ctu __builtin_altivec_vctuxs
#endif
/* vec_vctuxs */
-static __inline__ vector unsigned int __attribute__((__always_inline__))
-vec_vctuxs(vector float __a, int __b) {
- return __builtin_altivec_vctuxs(__a, __b);
-}
+#define vec_vctuxs __builtin_altivec_vctuxs
/* vec_signed */
@@ -8045,45 +8037,51 @@ static __inline__ vector float __ATTRS_o_ai vec_vsel(vector float __a,
/* vec_sl */
-static __inline__ vector signed char __ATTRS_o_ai
-vec_sl(vector signed char __a, vector unsigned char __b) {
- return __a << (vector signed char)__b;
-}
-
+// vec_sl does modulo arithmetic on __b first, so __b is allowed to be more
+// than the length of __a.
static __inline__ vector unsigned char __ATTRS_o_ai
vec_sl(vector unsigned char __a, vector unsigned char __b) {
- return __a << __b;
+ return __a << (__b %
+ (vector unsigned char)(sizeof(unsigned char) * __CHAR_BIT__));
}
-static __inline__ vector short __ATTRS_o_ai vec_sl(vector short __a,
- vector unsigned short __b) {
- return __a << (vector short)__b;
+static __inline__ vector signed char __ATTRS_o_ai
+vec_sl(vector signed char __a, vector unsigned char __b) {
+ return (vector signed char)vec_sl((vector unsigned char)__a, __b);
}
static __inline__ vector unsigned short __ATTRS_o_ai
vec_sl(vector unsigned short __a, vector unsigned short __b) {
- return __a << __b;
+ return __a << (__b % (vector unsigned short)(sizeof(unsigned short) *
+ __CHAR_BIT__));
}
-static __inline__ vector int __ATTRS_o_ai vec_sl(vector int __a,
- vector unsigned int __b) {
- return __a << (vector int)__b;
+static __inline__ vector short __ATTRS_o_ai vec_sl(vector short __a,
+ vector unsigned short __b) {
+ return (vector short)vec_sl((vector unsigned short)__a, __b);
}
static __inline__ vector unsigned int __ATTRS_o_ai
vec_sl(vector unsigned int __a, vector unsigned int __b) {
- return __a << __b;
+ return __a << (__b %
+ (vector unsigned int)(sizeof(unsigned int) * __CHAR_BIT__));
}
-#ifdef __POWER8_VECTOR__
-static __inline__ vector signed long long __ATTRS_o_ai
-vec_sl(vector signed long long __a, vector unsigned long long __b) {
- return __a << (vector long long)__b;
+static __inline__ vector int __ATTRS_o_ai vec_sl(vector int __a,
+ vector unsigned int __b) {
+ return (vector int)vec_sl((vector unsigned int)__a, __b);
}
+#ifdef __POWER8_VECTOR__
static __inline__ vector unsigned long long __ATTRS_o_ai
vec_sl(vector unsigned long long __a, vector unsigned long long __b) {
- return __a << __b;
+ return __a << (__b % (vector unsigned long long)(sizeof(unsigned long long) *
+ __CHAR_BIT__));
+}
+
+static __inline__ vector long long __ATTRS_o_ai
+vec_sl(vector long long __a, vector unsigned long long __b) {
+ return (vector long long)vec_sl((vector unsigned long long)__a, __b);
}
#endif
@@ -12150,6 +12148,11 @@ static __inline__ void __ATTRS_o_ai vec_vsx_st(vector unsigned char __a,
#endif
+#ifdef __VSX__
+#define vec_xxpermdi __builtin_vsx_xxpermdi
+#define vec_xxsldwi __builtin_vsx_xxsldwi
+#endif
+
/* vec_xor */
#define __builtin_altivec_vxor vec_xor
diff --git a/contrib/llvm/tools/clang/lib/Headers/arm_acle.h b/contrib/llvm/tools/clang/lib/Headers/arm_acle.h
index 8423e62..ab25897 100644
--- a/contrib/llvm/tools/clang/lib/Headers/arm_acle.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h b/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h
index 13bcbef..576f761 100644
--- a/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h
@@ -832,7 +832,8 @@ _mm256_xor_si256(__m256i __a, __m256i __b)
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_stream_load_si256(__m256i const *__V)
{
- return (__m256i)__builtin_ia32_movntdqa256((const __v4di *)__V);
+ typedef __v4di __v4di_aligned __attribute__((aligned(32)));
+ return (__m256i)__builtin_nontemporal_load((const __v4di_aligned *)__V);
}
static __inline__ __m128 __DEFAULT_FN_ATTRS
diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512bwintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512bwintrin.h
index 629dc86..41958b7 100644
--- a/contrib/llvm/tools/clang/lib/Headers/avx512bwintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/avx512bwintrin.h
@@ -504,115 +504,91 @@ _mm512_maskz_abs_epi16 (__mmask32 __U, __m512i __A)
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_packs_epi32 (__m512i __A, __m512i __B)
+_mm512_packs_epi32(__m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packssdw512_mask ((__v16si) __A,
- (__v16si) __B,
- (__v32hi) _mm512_setzero_hi(),
- (__mmask32) -1);
+ return (__m512i)__builtin_ia32_packssdw512((__v16si)__A, (__v16si)__B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_packs_epi32 (__mmask32 __M, __m512i __A, __m512i __B)
+_mm512_maskz_packs_epi32(__mmask32 __M, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packssdw512_mask ((__v16si) __A,
- (__v16si) __B,
- (__v32hi) _mm512_setzero_hi(),
- __M);
+ return (__m512i)__builtin_ia32_selectw_512((__mmask32)__M,
+ (__v32hi)_mm512_packs_epi32(__A, __B),
+ (__v32hi)_mm512_setzero_hi());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_mask_packs_epi32 (__m512i __W, __mmask32 __M, __m512i __A,
- __m512i __B)
+_mm512_mask_packs_epi32(__m512i __W, __mmask32 __M, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packssdw512_mask ((__v16si) __A,
- (__v16si) __B,
- (__v32hi) __W,
- __M);
+ return (__m512i)__builtin_ia32_selectw_512((__mmask32)__M,
+ (__v32hi)_mm512_packs_epi32(__A, __B),
+ (__v32hi)__W);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_packs_epi16 (__m512i __A, __m512i __B)
+_mm512_packs_epi16(__m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packsswb512_mask ((__v32hi) __A,
- (__v32hi) __B,
- (__v64qi) _mm512_setzero_qi(),
- (__mmask64) -1);
+ return (__m512i)__builtin_ia32_packsswb512((__v32hi)__A, (__v32hi) __B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_mask_packs_epi16 (__m512i __W, __mmask64 __M, __m512i __A,
- __m512i __B)
+_mm512_mask_packs_epi16(__m512i __W, __mmask64 __M, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packsswb512_mask ((__v32hi) __A,
- (__v32hi) __B,
- (__v64qi) __W,
- (__mmask64) __M);
+ return (__m512i)__builtin_ia32_selectb_512((__mmask64)__M,
+ (__v64qi)_mm512_packs_epi16(__A, __B),
+ (__v64qi)__W);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_packs_epi16 (__mmask64 __M, __m512i __A, __m512i __B)
+_mm512_maskz_packs_epi16(__mmask64 __M, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packsswb512_mask ((__v32hi) __A,
- (__v32hi) __B,
- (__v64qi) _mm512_setzero_qi(),
- __M);
+ return (__m512i)__builtin_ia32_selectb_512((__mmask64)__M,
+ (__v64qi)_mm512_packs_epi16(__A, __B),
+ (__v64qi)_mm512_setzero_qi());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_packus_epi32 (__m512i __A, __m512i __B)
+_mm512_packus_epi32(__m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packusdw512_mask ((__v16si) __A,
- (__v16si) __B,
- (__v32hi) _mm512_setzero_hi(),
- (__mmask32) -1);
+ return (__m512i)__builtin_ia32_packusdw512((__v16si) __A, (__v16si) __B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_packus_epi32 (__mmask32 __M, __m512i __A, __m512i __B)
+_mm512_maskz_packus_epi32(__mmask32 __M, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packusdw512_mask ((__v16si) __A,
- (__v16si) __B,
- (__v32hi) _mm512_setzero_hi(),
- __M);
+ return (__m512i)__builtin_ia32_selectw_512((__mmask32)__M,
+ (__v32hi)_mm512_packus_epi32(__A, __B),
+ (__v32hi)_mm512_setzero_hi());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_mask_packus_epi32 (__m512i __W, __mmask32 __M, __m512i __A,
- __m512i __B)
+_mm512_mask_packus_epi32(__m512i __W, __mmask32 __M, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packusdw512_mask ((__v16si) __A,
- (__v16si) __B,
- (__v32hi) __W,
- __M);
+ return (__m512i)__builtin_ia32_selectw_512((__mmask32)__M,
+ (__v32hi)_mm512_packus_epi32(__A, __B),
+ (__v32hi)__W);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_packus_epi16 (__m512i __A, __m512i __B)
+_mm512_packus_epi16(__m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packuswb512_mask ((__v32hi) __A,
- (__v32hi) __B,
- (__v64qi) _mm512_setzero_qi(),
- (__mmask64) -1);
+ return (__m512i)__builtin_ia32_packuswb512((__v32hi) __A, (__v32hi) __B);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_mask_packus_epi16 (__m512i __W, __mmask64 __M, __m512i __A,
- __m512i __B)
+_mm512_mask_packus_epi16(__m512i __W, __mmask64 __M, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packuswb512_mask ((__v32hi) __A,
- (__v32hi) __B,
- (__v64qi) __W,
- (__mmask64) __M);
+ return (__m512i)__builtin_ia32_selectb_512((__mmask64)__M,
+ (__v64qi)_mm512_packus_epi16(__A, __B),
+ (__v64qi)__W);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_packus_epi16 (__mmask64 __M, __m512i __A, __m512i __B)
+_mm512_maskz_packus_epi16(__mmask64 __M, __m512i __A, __m512i __B)
{
- return (__m512i) __builtin_ia32_packuswb512_mask ((__v32hi) __A,
- (__v32hi) __B,
- (__v64qi) _mm512_setzero_qi(),
- (__mmask64) __M);
+ return (__m512i)__builtin_ia32_selectb_512((__mmask64)__M,
+ (__v64qi)_mm512_packus_epi16(__A, __B),
+ (__v64qi)_mm512_setzero_qi());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512dqintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512dqintrin.h
index ae44b98..4fd1add 100644
--- a/contrib/llvm/tools/clang/lib/Headers/avx512dqintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/avx512dqintrin.h
@@ -995,51 +995,50 @@ _mm512_maskz_broadcast_f32x2 (__mmask16 __M, __m128 __A)
}
static __inline__ __m512 __DEFAULT_FN_ATTRS
-_mm512_broadcast_f32x8 (__m256 __A)
+_mm512_broadcast_f32x8(__m256 __A)
{
- return (__m512) __builtin_ia32_broadcastf32x8_512_mask ((__v8sf) __A,
- _mm512_undefined_ps(),
- (__mmask16) -1);
+ return (__m512)__builtin_shufflevector((__v8sf)__A, (__v8sf)__A,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7);
}
static __inline__ __m512 __DEFAULT_FN_ATTRS
-_mm512_mask_broadcast_f32x8 (__m512 __O, __mmask16 __M, __m256 __A)
+_mm512_mask_broadcast_f32x8(__m512 __O, __mmask16 __M, __m256 __A)
{
- return (__m512) __builtin_ia32_broadcastf32x8_512_mask ((__v8sf) __A,
- (__v16sf)__O,
- __M);
+ return (__m512)__builtin_ia32_selectps_512((__mmask8)__M,
+ (__v16sf)_mm512_broadcast_f32x8(__A),
+ (__v16sf)__O);
}
static __inline__ __m512 __DEFAULT_FN_ATTRS
-_mm512_maskz_broadcast_f32x8 (__mmask16 __M, __m256 __A)
+_mm512_maskz_broadcast_f32x8(__mmask16 __M, __m256 __A)
{
- return (__m512) __builtin_ia32_broadcastf32x8_512_mask ((__v8sf) __A,
- (__v16sf)_mm512_setzero_ps (),
- __M);
+ return (__m512)__builtin_ia32_selectps_512((__mmask8)__M,
+ (__v16sf)_mm512_broadcast_f32x8(__A),
+ (__v16sf)_mm512_setzero_ps());
}
static __inline__ __m512d __DEFAULT_FN_ATTRS
-_mm512_broadcast_f64x2 (__m128d __A)
+_mm512_broadcast_f64x2(__m128d __A)
{
- return (__m512d) __builtin_ia32_broadcastf64x2_512_mask ((__v2df) __A,
- (__v8df)_mm512_undefined_pd(),
- (__mmask8) -1);
+ return (__m512d)__builtin_shufflevector((__v2df)__A, (__v2df)__A,
+ 0, 1, 0, 1, 0, 1, 0, 1);
}
static __inline__ __m512d __DEFAULT_FN_ATTRS
-_mm512_mask_broadcast_f64x2 (__m512d __O, __mmask8 __M, __m128d __A)
+_mm512_mask_broadcast_f64x2(__m512d __O, __mmask8 __M, __m128d __A)
{
- return (__m512d) __builtin_ia32_broadcastf64x2_512_mask ((__v2df) __A,
- (__v8df)
- __O, __M);
+ return (__m512d)__builtin_ia32_selectpd_512((__mmask8)__M,
+ (__v8df)_mm512_broadcast_f64x2(__A),
+ (__v8df)__O);
}
static __inline__ __m512d __DEFAULT_FN_ATTRS
-_mm512_maskz_broadcast_f64x2 (__mmask8 __M, __m128d __A)
+_mm512_maskz_broadcast_f64x2(__mmask8 __M, __m128d __A)
{
- return (__m512d) __builtin_ia32_broadcastf64x2_512_mask ((__v2df) __A,
- (__v8df)_mm512_setzero_ps (),
- __M);
+ return (__m512d)__builtin_ia32_selectpd_512((__mmask8)__M,
+ (__v8df)_mm512_broadcast_f64x2(__A),
+ (__v8df)_mm512_setzero_pd());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
@@ -1067,52 +1066,50 @@ _mm512_maskz_broadcast_i32x2 (__mmask16 __M, __m128i __A)
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_broadcast_i32x8 (__m256i __A)
+_mm512_broadcast_i32x8(__m256i __A)
{
- return (__m512i) __builtin_ia32_broadcasti32x8_512_mask ((__v8si) __A,
- (__v16si)_mm512_setzero_si512(),
- (__mmask16) -1);
+ return (__m512i)__builtin_shufflevector((__v8si)__A, (__v8si)__A,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_mask_broadcast_i32x8 (__m512i __O, __mmask16 __M, __m256i __A)
+_mm512_mask_broadcast_i32x8(__m512i __O, __mmask16 __M, __m256i __A)
{
- return (__m512i) __builtin_ia32_broadcasti32x8_512_mask ((__v8si) __A,
- (__v16si)__O,
- __M);
+ return (__m512i)__builtin_ia32_selectd_512((__mmask8)__M,
+ (__v16si)_mm512_broadcast_i32x8(__A),
+ (__v16si)__O);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_broadcast_i32x8 (__mmask16 __M, __m256i __A)
+_mm512_maskz_broadcast_i32x8(__mmask16 __M, __m256i __A)
{
- return (__m512i) __builtin_ia32_broadcasti32x8_512_mask ((__v8si) __A,
- (__v16si)
- _mm512_setzero_si512 (),
- __M);
+ return (__m512i)__builtin_ia32_selectd_512((__mmask8)__M,
+ (__v16si)_mm512_broadcast_i32x8(__A),
+ (__v16si)_mm512_setzero_si512());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_broadcast_i64x2 (__m128i __A)
+_mm512_broadcast_i64x2(__m128i __A)
{
- return (__m512i) __builtin_ia32_broadcasti64x2_512_mask ((__v2di) __A,
- (__v8di)_mm512_setzero_si512(),
- (__mmask8) -1);
+ return (__m512i)__builtin_shufflevector((__v2di)__A, (__v2di)__A,
+ 0, 1, 0, 1, 0, 1, 0, 1);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_mask_broadcast_i64x2 (__m512i __O, __mmask8 __M, __m128i __A)
+_mm512_mask_broadcast_i64x2(__m512i __O, __mmask8 __M, __m128i __A)
{
- return (__m512i) __builtin_ia32_broadcasti64x2_512_mask ((__v2di) __A,
- (__v8di)
- __O, __M);
+ return (__m512i)__builtin_ia32_selectq_512((__mmask8)__M,
+ (__v8di)_mm512_broadcast_i64x2(__A),
+ (__v8di)__O);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_broadcast_i64x2 (__mmask8 __M, __m128i __A)
+_mm512_maskz_broadcast_i64x2(__mmask8 __M, __m128i __A)
{
- return (__m512i) __builtin_ia32_broadcasti64x2_512_mask ((__v2di) __A,
- (__v8di)_mm512_setzero_si512 (),
- __M);
+ return (__m512i)__builtin_ia32_selectq_512((__mmask8)__M,
+ (__v8di)_mm512_broadcast_i64x2(__A),
+ (__v8di)_mm512_setzero_si512());
}
#define _mm512_extractf32x8_ps(A, imm) __extension__ ({ \
diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h
index e6a7217..4ce6945 100644
--- a/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/avx512fintrin.h
@@ -528,6 +528,116 @@ _mm512_mask2int(__mmask16 __a)
return (int)__a;
}
+/// \brief Constructs a 512-bit floating-point vector of [8 x double] from a
+/// 128-bit floating-point vector of [2 x double]. The lower 128 bits
+/// contain the value of the source vector. The upper 384 bits are set
+/// to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit vector of [2 x double].
+/// \returns A 512-bit floating-point vector of [8 x double]. The lower 128 bits
+/// contain the value of the parameter. The upper 384 bits are set to zero.
+static __inline __m512d __DEFAULT_FN_ATTRS
+_mm512_zextpd128_pd512(__m128d __a)
+{
+ return __builtin_shufflevector((__v2df)__a, (__v2df)_mm_setzero_pd(), 0, 1, 2, 3, 2, 3, 2, 3);
+}
+
+/// \brief Constructs a 512-bit floating-point vector of [8 x double] from a
+/// 256-bit floating-point vector of [4 x double]. The lower 256 bits
+/// contain the value of the source vector. The upper 256 bits are set
+/// to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 256-bit vector of [4 x double].
+/// \returns A 512-bit floating-point vector of [8 x double]. The lower 256 bits
+/// contain the value of the parameter. The upper 256 bits are set to zero.
+static __inline __m512d __DEFAULT_FN_ATTRS
+_mm512_zextpd256_pd512(__m256d __a)
+{
+ return __builtin_shufflevector((__v4df)__a, (__v4df)_mm256_setzero_pd(), 0, 1, 2, 3, 4, 5, 6, 7);
+}
+
+/// \brief Constructs a 512-bit floating-point vector of [16 x float] from a
+/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain
+/// the value of the source vector. The upper 384 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit vector of [4 x float].
+/// \returns A 512-bit floating-point vector of [16 x float]. The lower 128 bits
+/// contain the value of the parameter. The upper 384 bits are set to zero.
+static __inline __m512 __DEFAULT_FN_ATTRS
+_mm512_zextps128_ps512(__m128 __a)
+{
+ return __builtin_shufflevector((__v4sf)__a, (__v4sf)_mm_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7);
+}
+
+/// \brief Constructs a 512-bit floating-point vector of [16 x float] from a
+/// 256-bit floating-point vector of [8 x float]. The lower 256 bits contain
+/// the value of the source vector. The upper 256 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 256-bit vector of [8 x float].
+/// \returns A 512-bit floating-point vector of [16 x float]. The lower 256 bits
+/// contain the value of the parameter. The upper 256 bits are set to zero.
+static __inline __m512 __DEFAULT_FN_ATTRS
+_mm512_zextps256_ps512(__m256 __a)
+{
+ return __builtin_shufflevector((__v8sf)__a, (__v8sf)_mm256_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+}
+
+/// \brief Constructs a 512-bit integer vector from a 128-bit integer vector.
+/// The lower 128 bits contain the value of the source vector. The upper
+/// 384 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit integer vector.
+/// \returns A 512-bit integer vector. The lower 128 bits contain the value of
+/// the parameter. The upper 384 bits are set to zero.
+static __inline __m512i __DEFAULT_FN_ATTRS
+_mm512_zextsi128_si512(__m128i __a)
+{
+ return __builtin_shufflevector((__v2di)__a, (__v2di)_mm_setzero_si128(), 0, 1, 2, 3, 2, 3, 2, 3);
+}
+
+/// \brief Constructs a 512-bit integer vector from a 256-bit integer vector.
+/// The lower 256 bits contain the value of the source vector. The upper
+/// 256 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 256-bit integer vector.
+/// \returns A 512-bit integer vector. The lower 256 bits contain the value of
+/// the parameter. The upper 256 bits are set to zero.
+static __inline __m512i __DEFAULT_FN_ATTRS
+_mm512_zextsi256_si512(__m256i __a)
+{
+ return __builtin_shufflevector((__v4di)__a, (__v4di)_mm256_setzero_si256(), 0, 1, 2, 3, 4, 5, 6, 7);
+}
+
/* Bitwise operators */
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_and_epi32(__m512i __a, __m512i __b)
@@ -4179,7 +4289,7 @@ static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_maskz_cvtps_epu32 ( __mmask16 __U, __m512 __A)
{
return (__m512i) __builtin_ia32_cvtps2udq512_mask ((__v16sf) __A,
- (__v16si)
+ (__v16si)
_mm512_setzero_si512 (),
(__mmask16) __U ,
_MM_FROUND_CUR_DIRECTION);
@@ -4229,6 +4339,18 @@ _mm512_maskz_cvtpd_epu32 (__mmask8 __U, __m512d __A)
_MM_FROUND_CUR_DIRECTION);
}
+static __inline__ double __DEFAULT_FN_ATTRS
+_mm512_cvtsd_f64(__m512d __a)
+{
+ return __a[0];
+}
+
+static __inline__ float __DEFAULT_FN_ATTRS
+_mm512_cvtss_f32(__m512 __a)
+{
+ return __a[0];
+}
+
/* Unpack and Interleave */
static __inline __m512d __DEFAULT_FN_ATTRS
@@ -4540,7 +4662,7 @@ _mm512_maskz_loadu_pd(__mmask8 __U, void const *__P)
}
static __inline __m512d __DEFAULT_FN_ATTRS
-_mm512_loadu_pd(double const *__p)
+_mm512_loadu_pd(void const *__p)
{
struct __loadu_pd {
__m512d __v;
@@ -4549,7 +4671,7 @@ _mm512_loadu_pd(double const *__p)
}
static __inline __m512 __DEFAULT_FN_ATTRS
-_mm512_loadu_ps(float const *__p)
+_mm512_loadu_ps(void const *__p)
{
struct __loadu_ps {
__m512 __v;
@@ -4558,7 +4680,7 @@ _mm512_loadu_ps(float const *__p)
}
static __inline __m512 __DEFAULT_FN_ATTRS
-_mm512_load_ps(float const *__p)
+_mm512_load_ps(void const *__p)
{
return (__m512) __builtin_ia32_loadaps512_mask ((const __v16sf *)__p,
(__v16sf)
@@ -4584,7 +4706,7 @@ _mm512_maskz_load_ps(__mmask16 __U, void const *__P)
}
static __inline __m512d __DEFAULT_FN_ATTRS
-_mm512_load_pd(double const *__p)
+_mm512_load_pd(void const *__p)
{
return (__m512d) __builtin_ia32_loadapd512_mask ((const __v8df *)__p,
(__v8df)
@@ -7278,107 +7400,97 @@ _mm_maskz_sqrt_ss (__mmask8 __U, __m128 __A, __m128 __B)
(__mmask8)(U), (int)(R)); })
static __inline__ __m512 __DEFAULT_FN_ATTRS
-_mm512_broadcast_f32x4 (__m128 __A)
+_mm512_broadcast_f32x4(__m128 __A)
{
- return (__m512) __builtin_ia32_broadcastf32x4_512 ((__v4sf) __A,
- (__v16sf)
- _mm512_undefined_ps (),
- (__mmask16) -1);
+ return (__m512)__builtin_shufflevector((__v4sf)__A, (__v4sf)__A,
+ 0, 1, 2, 3, 0, 1, 2, 3,
+ 0, 1, 2, 3, 0, 1, 2, 3);
}
static __inline__ __m512 __DEFAULT_FN_ATTRS
-_mm512_mask_broadcast_f32x4 (__m512 __O, __mmask16 __M, __m128 __A)
+_mm512_mask_broadcast_f32x4(__m512 __O, __mmask16 __M, __m128 __A)
{
- return (__m512) __builtin_ia32_broadcastf32x4_512 ((__v4sf) __A,
- (__v16sf) __O,
- __M);
+ return (__m512)__builtin_ia32_selectps_512((__mmask16)__M,
+ (__v16sf)_mm512_broadcast_f32x4(__A),
+ (__v16sf)__O);
}
static __inline__ __m512 __DEFAULT_FN_ATTRS
-_mm512_maskz_broadcast_f32x4 (__mmask16 __M, __m128 __A)
+_mm512_maskz_broadcast_f32x4(__mmask16 __M, __m128 __A)
{
- return (__m512) __builtin_ia32_broadcastf32x4_512 ((__v4sf) __A,
- (__v16sf)
- _mm512_setzero_ps (),
- __M);
+ return (__m512)__builtin_ia32_selectps_512((__mmask16)__M,
+ (__v16sf)_mm512_broadcast_f32x4(__A),
+ (__v16sf)_mm512_setzero_ps());
}
static __inline__ __m512d __DEFAULT_FN_ATTRS
-_mm512_broadcast_f64x4 (__m256d __A)
+_mm512_broadcast_f64x4(__m256d __A)
{
- return (__m512d) __builtin_ia32_broadcastf64x4_512 ((__v4df) __A,
- (__v8df)
- _mm512_undefined_pd (),
- (__mmask8) -1);
+ return (__m512d)__builtin_shufflevector((__v4df)__A, (__v4df)__A,
+ 0, 1, 2, 3, 0, 1, 2, 3);
}
static __inline__ __m512d __DEFAULT_FN_ATTRS
-_mm512_mask_broadcast_f64x4 (__m512d __O, __mmask8 __M, __m256d __A)
+_mm512_mask_broadcast_f64x4(__m512d __O, __mmask8 __M, __m256d __A)
{
- return (__m512d) __builtin_ia32_broadcastf64x4_512 ((__v4df) __A,
- (__v8df) __O,
- __M);
+ return (__m512d)__builtin_ia32_selectpd_512((__mmask8)__M,
+ (__v8df)_mm512_broadcast_f64x4(__A),
+ (__v8df)__O);
}
static __inline__ __m512d __DEFAULT_FN_ATTRS
-_mm512_maskz_broadcast_f64x4 (__mmask8 __M, __m256d __A)
+_mm512_maskz_broadcast_f64x4(__mmask8 __M, __m256d __A)
{
- return (__m512d) __builtin_ia32_broadcastf64x4_512 ((__v4df) __A,
- (__v8df)
- _mm512_setzero_pd (),
- __M);
+ return (__m512d)__builtin_ia32_selectpd_512((__mmask8)__M,
+ (__v8df)_mm512_broadcast_f64x4(__A),
+ (__v8df)_mm512_setzero_pd());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_broadcast_i32x4 (__m128i __A)
+_mm512_broadcast_i32x4(__m128i __A)
{
- return (__m512i) __builtin_ia32_broadcasti32x4_512 ((__v4si) __A,
- (__v16si)
- _mm512_undefined_epi32 (),
- (__mmask16) -1);
+ return (__m512i)__builtin_shufflevector((__v4si)__A, (__v4si)__A,
+ 0, 1, 2, 3, 0, 1, 2, 3,
+ 0, 1, 2, 3, 0, 1, 2, 3);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_mask_broadcast_i32x4 (__m512i __O, __mmask16 __M, __m128i __A)
+_mm512_mask_broadcast_i32x4(__m512i __O, __mmask16 __M, __m128i __A)
{
- return (__m512i) __builtin_ia32_broadcasti32x4_512 ((__v4si) __A,
- (__v16si) __O,
- __M);
+ return (__m512i)__builtin_ia32_selectd_512((__mmask16)__M,
+ (__v16si)_mm512_broadcast_i32x4(__A),
+ (__v16si)__O);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_broadcast_i32x4 (__mmask16 __M, __m128i __A)
+_mm512_maskz_broadcast_i32x4(__mmask16 __M, __m128i __A)
{
- return (__m512i) __builtin_ia32_broadcasti32x4_512 ((__v4si) __A,
- (__v16si)
- _mm512_setzero_si512 (),
- __M);
+ return (__m512i)__builtin_ia32_selectd_512((__mmask16)__M,
+ (__v16si)_mm512_broadcast_i32x4(__A),
+ (__v16si)_mm512_setzero_si512());
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_broadcast_i64x4 (__m256i __A)
+_mm512_broadcast_i64x4(__m256i __A)
{
- return (__m512i) __builtin_ia32_broadcasti64x4_512 ((__v4di) __A,
- (__v8di)
- _mm512_undefined_epi32 (),
- (__mmask8) -1);
+ return (__m512i)__builtin_shufflevector((__v4di)__A, (__v4di)__A,
+ 0, 1, 2, 3, 0, 1, 2, 3);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_mask_broadcast_i64x4 (__m512i __O, __mmask8 __M, __m256i __A)
+_mm512_mask_broadcast_i64x4(__m512i __O, __mmask8 __M, __m256i __A)
{
- return (__m512i) __builtin_ia32_broadcasti64x4_512 ((__v4di) __A,
- (__v8di) __O,
- __M);
+ return (__m512i)__builtin_ia32_selectq_512((__mmask8)__M,
+ (__v8di)_mm512_broadcast_i64x4(__A),
+ (__v8di)__O);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
-_mm512_maskz_broadcast_i64x4 (__mmask8 __M, __m256i __A)
+_mm512_maskz_broadcast_i64x4(__mmask8 __M, __m256i __A)
{
- return (__m512i) __builtin_ia32_broadcasti64x4_512 ((__v4di) __A,
- (__v8di)
- _mm512_setzero_si512 (),
- __M);
+ return (__m512i)__builtin_ia32_selectq_512((__mmask8)__M,
+ (__v8di)_mm512_broadcast_i64x4(__A),
+ (__v8di)_mm512_setzero_si512());
}
static __inline__ __m512d __DEFAULT_FN_ATTRS
@@ -7860,12 +7972,12 @@ _mm512_mask_cvtepi64_storeu_epi16 (void *__P, __mmask8 __M, __m512i __A)
3 + ((imm) & 0x3) * 4); })
#define _mm512_mask_extracti32x4_epi32(W, U, A, imm) __extension__ ({ \
- (__m128i)__builtin_ia32_selectd_128((__mmask8)__U, \
+ (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \
(__v4si)_mm512_extracti32x4_epi32((A), (imm)), \
- (__v4si)__W); })
+ (__v4si)(W)); })
#define _mm512_maskz_extracti32x4_epi32(U, A, imm) __extension__ ({ \
- (__m128i)__builtin_ia32_selectd_128((__mmask8)__U, \
+ (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \
(__v4si)_mm512_extracti32x4_epi32((A), (imm)), \
(__v4si)_mm_setzero_si128()); })
@@ -7878,12 +7990,12 @@ _mm512_mask_cvtepi64_storeu_epi16 (void *__P, __mmask8 __M, __m512i __A)
((imm) & 1) ? 7 : 3); })
#define _mm512_mask_extracti64x4_epi64(W, U, A, imm) __extension__ ({ \
- (__m256i)__builtin_ia32_selectq_256((__mmask8)__U, \
+ (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \
(__v4di)_mm512_extracti64x4_epi64((A), (imm)), \
- (__v4di)__W); })
+ (__v4di)(W)); })
#define _mm512_maskz_extracti64x4_epi64(U, A, imm) __extension__ ({ \
- (__m256i)__builtin_ia32_selectq_256((__mmask8)__U, \
+ (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \
(__v4di)_mm512_extracti64x4_epi64((A), (imm)), \
(__v4di)_mm256_setzero_si256()); })
@@ -8159,11 +8271,11 @@ _mm512_maskz_getexp_ps (__mmask16 __U, __m512 __A)
(__v8di)(__m512i)(index), (__mmask8)-1, \
(int)(scale)); })
-#define _mm512_mask_i64gather_ps( __v1_old, __mask, __index,\
- __addr, __scale) __extension__({\
-__builtin_ia32_gatherdiv16sf ((__v8sf) __v1_old,\
- __addr,(__v8di) __index, __mask, __scale);\
-})
+#define _mm512_mask_i64gather_ps(v1_old, mask, index, addr, scale) __extension__({\
+ (__m256)__builtin_ia32_gatherdiv16sf((__v8sf)(__m256)(v1_old),\
+ (float const *)(addr), \
+ (__v8di)(__m512i)(index), \
+ (__mmask8)(mask), (int)(scale)); })
#define _mm512_i64gather_epi32(index, addr, scale) __extension__ ({\
(__m256i)__builtin_ia32_gatherdiv16si((__v8si)_mm256_undefined_ps(), \
@@ -8858,6 +8970,8 @@ _mm512_permutexvar_epi32 (__m512i __X, __m512i __Y)
(__mmask16) -1);
}
+#define _mm512_permutevar_epi32 _mm512_permutexvar_epi32
+
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_mask_permutexvar_epi32 (__m512i __W, __mmask16 __M, __m512i __X,
__m512i __Y)
@@ -8868,6 +8982,8 @@ _mm512_mask_permutexvar_epi32 (__m512i __W, __mmask16 __M, __m512i __X,
__M);
}
+#define _mm512_mask_permutevar_epi32 _mm512_mask_permutexvar_epi32
+
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_kand (__mmask16 __A, __mmask16 __B)
{
@@ -8919,25 +9035,29 @@ _mm512_kxor (__mmask16 __A, __mmask16 __B)
static __inline__ void __DEFAULT_FN_ATTRS
_mm512_stream_si512 (__m512i * __P, __m512i __A)
{
- __builtin_nontemporal_store((__v8di)__A, (__v8di*)__P);
+ typedef __v8di __v8di_aligned __attribute__((aligned(64)));
+ __builtin_nontemporal_store((__v8di_aligned)__A, (__v8di_aligned*)__P);
}
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_stream_load_si512 (void *__P)
{
- return __builtin_ia32_movntdqa512 ((__v8di *)__P);
+ typedef __v8di __v8di_aligned __attribute__((aligned(64)));
+ return (__m512i) __builtin_nontemporal_load((const __v8di_aligned *)__P);
}
static __inline__ void __DEFAULT_FN_ATTRS
_mm512_stream_pd (double *__P, __m512d __A)
{
- __builtin_nontemporal_store((__v8df)__A, (__v8df*)__P);
+ typedef __v8df __v8df_aligned __attribute__((aligned(64)));
+ __builtin_nontemporal_store((__v8df_aligned)__A, (__v8df_aligned*)__P);
}
static __inline__ void __DEFAULT_FN_ATTRS
_mm512_stream_ps (float *__P, __m512 __A)
{
- __builtin_nontemporal_store((__v16sf)__A, (__v16sf*)__P);
+ typedef __v16sf __v16sf_aligned __attribute__((aligned(64)));
+ __builtin_nontemporal_store((__v16sf_aligned)__A, (__v16sf_aligned*)__P);
}
static __inline__ __m512d __DEFAULT_FN_ATTRS
@@ -9101,39 +9221,39 @@ _mm512_maskz_moveldup_ps (__mmask16 __U, __m512 __A)
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_mask_move_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B)
{
- __m128 res = __A;
+ __m128 res = __A;
res[0] = (__U & 1) ? __B[0] : __W[0];
- return res;
+ return res;
}
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_maskz_move_ss (__mmask8 __U, __m128 __A, __m128 __B)
{
- __m128 res = __A;
- res[0] = (__U & 1) ? __B[0] : 0;
- return res;
+ __m128 res = __A;
+ res[0] = (__U & 1) ? __B[0] : 0;
+ return res;
}
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_mask_move_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B)
{
- __m128d res = __A;
+ __m128d res = __A;
res[0] = (__U & 1) ? __B[0] : __W[0];
- return res;
+ return res;
}
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_maskz_move_sd (__mmask8 __U, __m128d __A, __m128d __B)
{
- __m128d res = __A;
- res[0] = (__U & 1) ? __B[0] : 0;
- return res;
+ __m128d res = __A;
+ res[0] = (__U & 1) ? __B[0] : 0;
+ return res;
}
static __inline__ void __DEFAULT_FN_ATTRS
_mm_mask_store_ss (float * __W, __mmask8 __U, __m128 __A)
{
- __builtin_ia32_storess128_mask ((__v16sf *)__W,
+ __builtin_ia32_storess128_mask ((__v16sf *)__W,
(__v16sf) _mm512_castps128_ps512(__A),
(__mmask16) __U & (__mmask16)1);
}
@@ -9141,7 +9261,7 @@ _mm_mask_store_ss (float * __W, __mmask8 __U, __m128 __A)
static __inline__ void __DEFAULT_FN_ATTRS
_mm_mask_store_sd (double * __W, __mmask8 __U, __m128d __A)
{
- __builtin_ia32_storesd128_mask ((__v8df *)__W,
+ __builtin_ia32_storesd128_mask ((__v8df *)__W,
(__v8df) _mm512_castpd128_pd512(__A),
(__mmask8) __U & 1);
}
@@ -9490,7 +9610,7 @@ _mm_mask_cvtsd_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128d __B)
{
return __builtin_ia32_cvtsd2ss_round_mask ((__v4sf)(__A),
(__v2df)(__B),
- (__v4sf)(__W),
+ (__v4sf)(__W),
(__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
}
@@ -9499,7 +9619,7 @@ _mm_maskz_cvtsd_ss (__mmask8 __U, __m128 __A, __m128d __B)
{
return __builtin_ia32_cvtsd2ss_round_mask ((__v4sf)(__A),
(__v2df)(__B),
- (__v4sf)_mm_setzero_ps(),
+ (__v4sf)_mm_setzero_ps(),
(__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
}
@@ -9564,7 +9684,7 @@ _mm_mask_cvtss_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128 __B)
return __builtin_ia32_cvtss2sd_round_mask((__v2df)(__A),
(__v4sf)(__B),
(__v2df)(__W),
- (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
+ (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
}
static __inline__ __m128d __DEFAULT_FN_ATTRS
@@ -9572,8 +9692,8 @@ _mm_maskz_cvtss_sd (__mmask8 __U, __m128d __A, __m128 __B)
{
return __builtin_ia32_cvtss2sd_round_mask((__v2df)(__A),
(__v4sf)(__B),
- (__v2df)_mm_setzero_pd(),
- (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
+ (__v2df)_mm_setzero_pd(),
+ (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION);
}
static __inline__ __m128d __DEFAULT_FN_ATTRS
@@ -9635,6 +9755,45 @@ _mm512_mask_set1_epi64 (__m512i __O, __mmask8 __M, long long __A)
}
#endif
+static __inline __m512i __DEFAULT_FN_ATTRS
+_mm512_set_epi8 (char __e63, char __e62, char __e61, char __e60, char __e59,
+ char __e58, char __e57, char __e56, char __e55, char __e54, char __e53,
+ char __e52, char __e51, char __e50, char __e49, char __e48, char __e47,
+ char __e46, char __e45, char __e44, char __e43, char __e42, char __e41,
+ char __e40, char __e39, char __e38, char __e37, char __e36, char __e35,
+ char __e34, char __e33, char __e32, char __e31, char __e30, char __e29,
+ char __e28, char __e27, char __e26, char __e25, char __e24, char __e23,
+ char __e22, char __e21, char __e20, char __e19, char __e18, char __e17,
+ char __e16, char __e15, char __e14, char __e13, char __e12, char __e11,
+ char __e10, char __e9, char __e8, char __e7, char __e6, char __e5,
+ char __e4, char __e3, char __e2, char __e1, char __e0) {
+
+ return __extension__ (__m512i)(__v64qi)
+ {__e0, __e1, __e2, __e3, __e4, __e5, __e6, __e7,
+ __e8, __e9, __e10, __e11, __e12, __e13, __e14, __e15,
+ __e16, __e17, __e18, __e19, __e20, __e21, __e22, __e23,
+ __e24, __e25, __e26, __e27, __e28, __e29, __e30, __e31,
+ __e32, __e33, __e34, __e35, __e36, __e37, __e38, __e39,
+ __e40, __e41, __e42, __e43, __e44, __e45, __e46, __e47,
+ __e48, __e49, __e50, __e51, __e52, __e53, __e54, __e55,
+ __e56, __e57, __e58, __e59, __e60, __e61, __e62, __e63};
+}
+
+static __inline __m512i __DEFAULT_FN_ATTRS
+_mm512_set_epi16(short __e31, short __e30, short __e29, short __e28,
+ short __e27, short __e26, short __e25, short __e24, short __e23,
+ short __e22, short __e21, short __e20, short __e19, short __e18,
+ short __e17, short __e16, short __e15, short __e14, short __e13,
+ short __e12, short __e11, short __e10, short __e9, short __e8,
+ short __e7, short __e6, short __e5, short __e4, short __e3,
+ short __e2, short __e1, short __e0) {
+ return __extension__ (__m512i)(__v32hi)
+ {__e0, __e1, __e2, __e3, __e4, __e5, __e6, __e7,
+ __e8, __e9, __e10, __e11, __e12, __e13, __e14, __e15,
+ __e16, __e17, __e18, __e19, __e20, __e21, __e22, __e23,
+ __e24, __e25, __e26, __e27, __e28, __e29, __e30, __e31 };
+}
+
static __inline __m512i __DEFAULT_FN_ATTRS
_mm512_set_epi32 (int __A, int __B, int __C, int __D,
int __E, int __F, int __G, int __H,
@@ -9780,7 +9939,7 @@ static __inline__ double __DEFAULT_FN_ATTRS _mm512_reduce_mul_pd(__m512d __W) {
}
// Vec512 - Vector with size 512.
-// Vec512Neutral - All vector elements set to the identity element.
+// Vec512Neutral - All vector elements set to the identity element.
// Identity element: {+,0},{*,1},{&,0xFFFFFFFFFFFFFFFF},{|,0}
// Operator - Can be one of following: +,*,&,|
// Mask - Intrinsic Mask
@@ -9810,19 +9969,19 @@ _mm512_mask_reduce_mul_epi64(__mmask8 __M, __m512i __W) {
static __inline__ long long __DEFAULT_FN_ATTRS
_mm512_mask_reduce_and_epi64(__mmask8 __M, __m512i __W) {
- _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_epi64(0xFFFFFFFFFFFFFFFF),
+ _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_epi64(0xFFFFFFFFFFFFFFFF),
&, __M, i, i, q);
}
static __inline__ long long __DEFAULT_FN_ATTRS
_mm512_mask_reduce_or_epi64(__mmask8 __M, __m512i __W) {
- _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_epi64(0), |, __M,
+ _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_epi64(0), |, __M,
i, i, q);
}
static __inline__ double __DEFAULT_FN_ATTRS
_mm512_mask_reduce_add_pd(__mmask8 __M, __m512d __W) {
- _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_pd(0), +, __M,
+ _mm512_mask_reduce_operator_64bit(__W, _mm512_set1_pd(0), +, __M,
f, d, pd);
}
@@ -9884,17 +10043,17 @@ _mm512_reduce_add_epi32(__m512i __W) {
_mm512_reduce_operator_32bit(__W, +, i, i);
}
-static __inline__ int __DEFAULT_FN_ATTRS
+static __inline__ int __DEFAULT_FN_ATTRS
_mm512_reduce_mul_epi32(__m512i __W) {
_mm512_reduce_operator_32bit(__W, *, i, i);
}
-static __inline__ int __DEFAULT_FN_ATTRS
+static __inline__ int __DEFAULT_FN_ATTRS
_mm512_reduce_and_epi32(__m512i __W) {
_mm512_reduce_operator_32bit(__W, &, i, i);
}
-static __inline__ int __DEFAULT_FN_ATTRS
+static __inline__ int __DEFAULT_FN_ATTRS
_mm512_reduce_or_epi32(__m512i __W) {
_mm512_reduce_operator_32bit(__W, |, i, i);
}
@@ -9910,7 +10069,7 @@ _mm512_reduce_mul_ps(__m512 __W) {
}
// Vec512 - Vector with size 512.
-// Vec512Neutral - All vector elements set to the identity element.
+// Vec512Neutral - All vector elements set to the identity element.
// Identity element: {+,0},{*,1},{&,0xFFFFFFFF},{|,0}
// Operator - Can be one of following: +,*,&,|
// Mask - Intrinsic Mask
@@ -9940,7 +10099,7 @@ _mm512_mask_reduce_mul_epi32( __mmask16 __M, __m512i __W) {
static __inline__ int __DEFAULT_FN_ATTRS
_mm512_mask_reduce_and_epi32( __mmask16 __M, __m512i __W) {
- _mm512_mask_reduce_operator_32bit(__W, _mm512_set1_epi32(0xFFFFFFFF), &, __M,
+ _mm512_mask_reduce_operator_32bit(__W, _mm512_set1_epi32(0xFFFFFFFF), &, __M,
i, i, d);
}
@@ -10003,7 +10162,7 @@ _mm512_mask_reduce_mul_ps(__mmask16 __M, __m512 __W) {
return Vec512[0]; \
})
-static __inline__ long long __DEFAULT_FN_ATTRS
+static __inline__ long long __DEFAULT_FN_ATTRS
_mm512_reduce_max_epi64(__m512i __V) {
_mm512_reduce_maxMin_64bit(__V, max_epi64, i, i);
}
@@ -10013,7 +10172,7 @@ _mm512_reduce_max_epu64(__m512i __V) {
_mm512_reduce_maxMin_64bit(__V, max_epu64, i, i);
}
-static __inline__ double __DEFAULT_FN_ATTRS
+static __inline__ double __DEFAULT_FN_ATTRS
_mm512_reduce_max_pd(__m512d __V) {
_mm512_reduce_maxMin_64bit(__V, max_pd, d, f);
}
@@ -10028,7 +10187,7 @@ _mm512_reduce_min_epu64(__m512i __V) {
_mm512_reduce_maxMin_64bit(__V, min_epu64, i, i);
}
-static __inline__ double __DEFAULT_FN_ATTRS
+static __inline__ double __DEFAULT_FN_ATTRS
_mm512_reduce_min_pd(__m512d __V) {
_mm512_reduce_maxMin_64bit(__V, min_pd, d, f);
}
diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512vldqintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512vldqintrin.h
index cd9da43..aecd7df 100644
--- a/contrib/llvm/tools/clang/lib/Headers/avx512vldqintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/avx512vldqintrin.h
@@ -1000,27 +1000,26 @@ _mm256_maskz_broadcast_f32x2 (__mmask8 __M, __m128 __A)
}
static __inline__ __m256d __DEFAULT_FN_ATTRS
-_mm256_broadcast_f64x2 (__m128d __A)
+_mm256_broadcast_f64x2(__m128d __A)
{
- return (__m256d) __builtin_ia32_broadcastf64x2_256_mask ((__v2df) __A,
- (__v4df)_mm256_undefined_pd(),
- (__mmask8) -1);
+ return (__m256d)__builtin_shufflevector((__v2df)__A, (__v2df)__A,
+ 0, 1, 0, 1);
}
static __inline__ __m256d __DEFAULT_FN_ATTRS
-_mm256_mask_broadcast_f64x2 (__m256d __O, __mmask8 __M, __m128d __A)
+_mm256_mask_broadcast_f64x2(__m256d __O, __mmask8 __M, __m128d __A)
{
- return (__m256d) __builtin_ia32_broadcastf64x2_256_mask ((__v2df) __A,
- (__v4df) __O,
- __M);
+ return (__m256d)__builtin_ia32_selectpd_256((__mmask8)__M,
+ (__v4df)_mm256_broadcast_f64x2(__A),
+ (__v4df)__O);
}
static __inline__ __m256d __DEFAULT_FN_ATTRS
_mm256_maskz_broadcast_f64x2 (__mmask8 __M, __m128d __A)
{
- return (__m256d) __builtin_ia32_broadcastf64x2_256_mask ((__v2df) __A,
- (__v4df) _mm256_setzero_ps (),
- __M);
+ return (__m256d)__builtin_ia32_selectpd_256((__mmask8)__M,
+ (__v4df)_mm256_broadcast_f64x2(__A),
+ (__v4df)_mm256_setzero_pd());
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
@@ -1072,27 +1071,26 @@ _mm256_maskz_broadcast_i32x2 (__mmask8 __M, __m128i __A)
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
-_mm256_broadcast_i64x2 (__m128i __A)
+_mm256_broadcast_i64x2(__m128i __A)
{
- return (__m256i) __builtin_ia32_broadcasti64x2_256_mask ((__v2di) __A,
- (__v4di)_mm256_undefined_si256(),
- (__mmask8) -1);
+ return (__m256i)__builtin_shufflevector((__v2di)__A, (__v2di)__A,
+ 0, 1, 0, 1);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
-_mm256_mask_broadcast_i64x2 (__m256i __O, __mmask8 __M, __m128i __A)
+_mm256_mask_broadcast_i64x2(__m256i __O, __mmask8 __M, __m128i __A)
{
- return (__m256i) __builtin_ia32_broadcasti64x2_256_mask ((__v2di) __A,
- (__v4di) __O,
- __M);
+ return (__m256i)__builtin_ia32_selectq_256((__mmask8)__M,
+ (__v4di)_mm256_broadcast_i64x2(__A),
+ (__v4di)__O);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_maskz_broadcast_i64x2 (__mmask8 __M, __m128i __A)
{
- return (__m256i) __builtin_ia32_broadcasti64x2_256_mask ((__v2di) __A,
- (__v4di) _mm256_setzero_si256 (),
- __M);
+ return (__m256i)__builtin_ia32_selectq_256((__mmask8)__M,
+ (__v4di)_mm256_broadcast_i64x2(__A),
+ (__v4di)_mm256_setzero_si256());
}
#define _mm256_extractf64x2_pd(A, imm) __extension__ ({ \
diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512vlintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512vlintrin.h
index f3744da..99bb050 100644
--- a/contrib/llvm/tools/clang/lib/Headers/avx512vlintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/avx512vlintrin.h
@@ -7189,52 +7189,49 @@ _mm256_maskz_rsqrt14_ps (__mmask8 __U, __m256 __A)
}
static __inline__ __m256 __DEFAULT_FN_ATTRS
-_mm256_broadcast_f32x4 (__m128 __A)
+_mm256_broadcast_f32x4(__m128 __A)
{
- return (__m256) __builtin_ia32_broadcastf32x4_256_mask ((__v4sf) __A,
- (__v8sf)_mm256_undefined_pd (),
- (__mmask8) -1);
+ return (__m256)__builtin_shufflevector((__v4sf)__A, (__v4sf)__A,
+ 0, 1, 2, 3, 0, 1, 2, 3);
}
static __inline__ __m256 __DEFAULT_FN_ATTRS
-_mm256_mask_broadcast_f32x4 (__m256 __O, __mmask8 __M, __m128 __A)
+_mm256_mask_broadcast_f32x4(__m256 __O, __mmask8 __M, __m128 __A)
{
- return (__m256) __builtin_ia32_broadcastf32x4_256_mask ((__v4sf) __A,
- (__v8sf) __O,
- __M);
+ return (__m256)__builtin_ia32_selectps_256((__mmask8)__M,
+ (__v8sf)_mm256_broadcast_f32x4(__A),
+ (__v8sf)__O);
}
static __inline__ __m256 __DEFAULT_FN_ATTRS
_mm256_maskz_broadcast_f32x4 (__mmask8 __M, __m128 __A)
{
- return (__m256) __builtin_ia32_broadcastf32x4_256_mask ((__v4sf) __A,
- (__v8sf) _mm256_setzero_ps (),
- __M);
+ return (__m256)__builtin_ia32_selectps_256((__mmask8)__M,
+ (__v8sf)_mm256_broadcast_f32x4(__A),
+ (__v8sf)_mm256_setzero_ps());
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
-_mm256_broadcast_i32x4 (__m128i __A)
+_mm256_broadcast_i32x4(__m128i __A)
{
- return (__m256i) __builtin_ia32_broadcasti32x4_256_mask ((__v4si) __A,
- (__v8si)_mm256_undefined_si256 (),
- (__mmask8) -1);
+ return (__m256i)__builtin_shufflevector((__v4si)__A, (__v4si)__A,
+ 0, 1, 2, 3, 0, 1, 2, 3);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
-_mm256_mask_broadcast_i32x4 (__m256i __O, __mmask8 __M, __m128i __A)
+_mm256_mask_broadcast_i32x4(__m256i __O, __mmask8 __M, __m128i __A)
{
- return (__m256i) __builtin_ia32_broadcasti32x4_256_mask ((__v4si) __A,
- (__v8si)
- __O, __M);
+ return (__m256i)__builtin_ia32_selectd_256((__mmask8)__M,
+ (__v8si)_mm256_broadcast_i32x4(__A),
+ (__v8si)__O);
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
-_mm256_maskz_broadcast_i32x4 (__mmask8 __M, __m128i __A)
+_mm256_maskz_broadcast_i32x4(__mmask8 __M, __m128i __A)
{
- return (__m256i) __builtin_ia32_broadcasti32x4_256_mask ((__v4si)
- __A,
- (__v8si) _mm256_setzero_si256 (),
- __M);
+ return (__m256i)__builtin_ia32_selectd_256((__mmask8)__M,
+ (__v8si)_mm256_broadcast_i32x4(__A),
+ (__v8si)_mm256_setzero_si256());
}
static __inline__ __m256d __DEFAULT_FN_ATTRS
diff --git a/contrib/llvm/tools/clang/lib/Headers/avx512vpopcntdqintrin.h b/contrib/llvm/tools/clang/lib/Headers/avx512vpopcntdqintrin.h
new file mode 100644
index 0000000..34ab849
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Headers/avx512vpopcntdqintrin.h
@@ -0,0 +1,70 @@
+/*===------------- avx512vpopcntdqintrin.h - AVX512VPOPCNTDQ intrinsics
+ *------------------===
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+#ifndef __IMMINTRIN_H
+#error \
+ "Never use <avx512vpopcntdqintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __AVX512VPOPCNTDQINTRIN_H
+#define __AVX512VPOPCNTDQINTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS \
+ __attribute__((__always_inline__, __nodebug__, __target__("avx512vpopcntd" \
+ "q")))
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_popcnt_epi64(__m512i __A) {
+ return (__m512i)__builtin_ia32_vpopcntq_512((__v8di)__A);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS
+_mm512_mask_popcnt_epi64(__m512i __W, __mmask8 __U, __m512i __A) {
+ return (__m512i)__builtin_ia32_selectq_512(
+ (__mmask8)__U, (__v8di)_mm512_popcnt_epi64(__A), (__v8di)__W);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS
+_mm512_maskz_popcnt_epi64(__mmask8 __U, __m512i __A) {
+ return _mm512_mask_popcnt_epi64((__m512i)_mm512_setzero_si512(), __U, __A);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_popcnt_epi32(__m512i __A) {
+ return (__m512i)__builtin_ia32_vpopcntd_512((__v16si)__A);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS
+_mm512_mask_popcnt_epi32(__m512i __W, __mmask16 __U, __m512i __A) {
+ return (__m512i)__builtin_ia32_selectd_512(
+ (__mmask16)__U, (__v16si)_mm512_popcnt_epi32(__A), (__v16si)__W);
+}
+
+static __inline__ __m512i __DEFAULT_FN_ATTRS
+_mm512_maskz_popcnt_epi32(__mmask16 __U, __m512i __A) {
+ return _mm512_mask_popcnt_epi32((__m512i)_mm512_setzero_si512(), __U, __A);
+}
+
+#undef __DEFAULT_FN_ATTRS
+
+#endif
diff --git a/contrib/llvm/tools/clang/lib/Headers/avxintrin.h b/contrib/llvm/tools/clang/lib/Headers/avxintrin.h
index be03ba3..dff5897 100644
--- a/contrib/llvm/tools/clang/lib/Headers/avxintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/avxintrin.h
@@ -1458,12 +1458,13 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Computes two dot products in parallel, using the lower and upper
/// halves of two [8 x float] vectors as input to the two computations, and
/// returning the two dot products in the lower and upper halves of the
-/// [8 x float] result. The immediate integer operand controls which input
-/// elements will contribute to the dot product, and where the final results
-/// are returned. In general, for each dot product, the four corresponding
-/// elements of the input vectors are multiplied; the first two and second
-/// two products are summed, then the two sums are added to form the final
-/// result.
+/// [8 x float] result.
+///
+/// The immediate integer operand controls which input elements will
+/// contribute to the dot product, and where the final results are returned.
+/// In general, for each dot product, the four corresponding elements of the
+/// input vectors are multiplied; the first two and second two products are
+/// summed, then the two sums are added to form the final result.
///
/// \headerfile <x86intrin.h>
///
@@ -1497,15 +1498,16 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/* Vector shuffle */
/// \brief Selects 8 float values from the 256-bit operands of [8 x float], as
-/// specified by the immediate value operand. The four selected elements in
-/// each operand are copied to the destination according to the bits
-/// specified in the immediate operand. The selected elements from the first
-/// 256-bit operand are copied to bits [63:0] and bits [191:128] of the
-/// destination, and the selected elements from the second 256-bit operand
-/// are copied to bits [127:64] and bits [255:192] of the destination. For
-/// example, if bits [7:0] of the immediate operand contain a value of 0xFF,
-/// the 256-bit destination vector would contain the following values: b[7],
-/// b[7], a[7], a[7], b[3], b[3], a[3], a[3].
+/// specified by the immediate value operand.
+///
+/// The four selected elements in each operand are copied to the destination
+/// according to the bits specified in the immediate operand. The selected
+/// elements from the first 256-bit operand are copied to bits [63:0] and
+/// bits [191:128] of the destination, and the selected elements from the
+/// second 256-bit operand are copied to bits [127:64] and bits [255:192] of
+/// the destination. For example, if bits [7:0] of the immediate operand
+/// contain a value of 0xFF, the 256-bit destination vector would contain the
+/// following values: b[7], b[7], a[7], a[7], b[3], b[3], a[3], a[3].
///
/// \headerfile <x86intrin.h>
///
@@ -1557,13 +1559,14 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
12 + (((mask) >> 6) & 0x3)); })
/// \brief Selects four double-precision values from the 256-bit operands of
-/// [4 x double], as specified by the immediate value operand. The selected
-/// elements from the first 256-bit operand are copied to bits [63:0] and
-/// bits [191:128] in the destination, and the selected elements from the
-/// second 256-bit operand are copied to bits [127:64] and bits [255:192] in
-/// the destination. For example, if bits [3:0] of the immediate operand
-/// contain a value of 0xF, the 256-bit destination vector would contain the
-/// following values: b[3], a[3], b[1], a[1].
+/// [4 x double], as specified by the immediate value operand.
+///
+/// The selected elements from the first 256-bit operand are copied to bits
+/// [63:0] and bits [191:128] in the destination, and the selected elements
+/// from the second 256-bit operand are copied to bits [127:64] and bits
+/// [255:192] in the destination. For example, if bits [3:0] of the immediate
+/// operand contain a value of 0xF, the 256-bit destination vector would
+/// contain the following values: b[3], a[3], b[1], a[1].
///
/// \headerfile <x86intrin.h>
///
@@ -1613,9 +1616,9 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
#define _CMP_NEQ_UQ 0x04 /* Not-equal (unordered, non-signaling) */
#define _CMP_NLT_US 0x05 /* Not-less-than (unordered, signaling) */
#define _CMP_NLE_US 0x06 /* Not-less-than-or-equal (unordered, signaling) */
-#define _CMP_ORD_Q 0x07 /* Ordered (nonsignaling) */
+#define _CMP_ORD_Q 0x07 /* Ordered (non-signaling) */
#define _CMP_EQ_UQ 0x08 /* Equal (unordered, non-signaling) */
-#define _CMP_NGE_US 0x09 /* Not-greater-than-or-equal (unord, signaling) */
+#define _CMP_NGE_US 0x09 /* Not-greater-than-or-equal (unordered, signaling) */
#define _CMP_NGT_US 0x0a /* Not-greater-than (unordered, signaling) */
#define _CMP_FALSE_OQ 0x0b /* False (ordered, non-signaling) */
#define _CMP_NEQ_OQ 0x0c /* Not-equal (ordered, non-signaling) */
@@ -1628,10 +1631,10 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
#define _CMP_UNORD_S 0x13 /* Unordered (signaling) */
#define _CMP_NEQ_US 0x14 /* Not-equal (unordered, signaling) */
#define _CMP_NLT_UQ 0x15 /* Not-less-than (unordered, non-signaling) */
-#define _CMP_NLE_UQ 0x16 /* Not-less-than-or-equal (unord, non-signaling) */
+#define _CMP_NLE_UQ 0x16 /* Not-less-than-or-equal (unordered, non-signaling) */
#define _CMP_ORD_S 0x17 /* Ordered (signaling) */
#define _CMP_EQ_US 0x18 /* Equal (unordered, signaling) */
-#define _CMP_NGE_UQ 0x19 /* Not-greater-than-or-equal (unord, non-sign) */
+#define _CMP_NGE_UQ 0x19 /* Not-greater-than-or-equal (unordered, non-signaling) */
#define _CMP_NGT_UQ 0x1a /* Not-greater-than (unordered, non-signaling) */
#define _CMP_FALSE_OS 0x1b /* False (ordered, signaling) */
#define _CMP_NEQ_OS 0x1c /* Not-equal (ordered, signaling) */
@@ -1641,9 +1644,11 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding double-precision values of two
/// 128-bit vectors of [2 x double], using the operation specified by the
-/// immediate integer operand. Returns a [2 x double] vector consisting of
-/// two doubles corresponding to the two comparison results: zero if the
-/// comparison is false, and all 1's if the comparison is true.
+/// immediate integer operand.
+///
+/// Returns a [2 x double] vector consisting of two doubles corresponding to
+/// the two comparison results: zero if the comparison is false, and all 1's
+/// if the comparison is true.
///
/// \headerfile <x86intrin.h>
///
@@ -1660,17 +1665,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 128-bit vector of [2 x double] containing the comparison results.
#define _mm_cmp_pd(a, b, c) __extension__ ({ \
(__m128d)__builtin_ia32_cmppd((__v2df)(__m128d)(a), \
@@ -1678,9 +1704,11 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding values of two 128-bit vectors of
/// [4 x float], using the operation specified by the immediate integer
-/// operand. Returns a [4 x float] vector consisting of four floats
-/// corresponding to the four comparison results: zero if the comparison is
-/// false, and all 1's if the comparison is true.
+/// operand.
+///
+/// Returns a [4 x float] vector consisting of four floats corresponding to
+/// the four comparison results: zero if the comparison is false, and all 1's
+/// if the comparison is true.
///
/// \headerfile <x86intrin.h>
///
@@ -1697,17 +1725,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 128-bit vector of [4 x float] containing the comparison results.
#define _mm_cmp_ps(a, b, c) __extension__ ({ \
(__m128)__builtin_ia32_cmpps((__v4sf)(__m128)(a), \
@@ -1715,9 +1764,11 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding double-precision values of two
/// 256-bit vectors of [4 x double], using the operation specified by the
-/// immediate integer operand. Returns a [4 x double] vector consisting of
-/// four doubles corresponding to the four comparison results: zero if the
-/// comparison is false, and all 1's if the comparison is true.
+/// immediate integer operand.
+///
+/// Returns a [4 x double] vector consisting of four doubles corresponding to
+/// the four comparison results: zero if the comparison is false, and all 1's
+/// if the comparison is true.
///
/// \headerfile <x86intrin.h>
///
@@ -1734,17 +1785,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 256-bit vector of [4 x double] containing the comparison results.
#define _mm256_cmp_pd(a, b, c) __extension__ ({ \
(__m256d)__builtin_ia32_cmppd256((__v4df)(__m256d)(a), \
@@ -1752,9 +1824,11 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding values of two 256-bit vectors of
/// [8 x float], using the operation specified by the immediate integer
-/// operand. Returns a [8 x float] vector consisting of eight floats
-/// corresponding to the eight comparison results: zero if the comparison is
-/// false, and all 1's if the comparison is true.
+/// operand.
+///
+/// Returns a [8 x float] vector consisting of eight floats corresponding to
+/// the eight comparison results: zero if the comparison is false, and all
+/// 1's if the comparison is true.
///
/// \headerfile <x86intrin.h>
///
@@ -1771,17 +1845,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 256-bit vector of [8 x float] containing the comparison results.
#define _mm256_cmp_ps(a, b, c) __extension__ ({ \
(__m256)__builtin_ia32_cmpps256((__v8sf)(__m256)(a), \
@@ -1789,8 +1884,10 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding scalar double-precision values of
/// two 128-bit vectors of [2 x double], using the operation specified by the
-/// immediate integer operand. If the result is true, all 64 bits of the
-/// destination vector are set; otherwise they are cleared.
+/// immediate integer operand.
+///
+/// If the result is true, all 64 bits of the destination vector are set;
+/// otherwise they are cleared.
///
/// \headerfile <x86intrin.h>
///
@@ -1807,17 +1904,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 128-bit vector of [2 x double] containing the comparison results.
#define _mm_cmp_sd(a, b, c) __extension__ ({ \
(__m128d)__builtin_ia32_cmpsd((__v2df)(__m128d)(a), \
@@ -1825,8 +1943,10 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \brief Compares each of the corresponding scalar values of two 128-bit
/// vectors of [4 x float], using the operation specified by the immediate
-/// integer operand. If the result is true, all 32 bits of the destination
-/// vector are set; otherwise they are cleared.
+/// integer operand.
+///
+/// If the result is true, all 32 bits of the destination vector are set;
+/// otherwise they are cleared.
///
/// \headerfile <x86intrin.h>
///
@@ -1843,17 +1963,38 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
/// \param c
/// An immediate integer operand, with bits [4:0] specifying which comparison
/// operation to use: \n
-/// 00h, 08h, 10h, 18h: Equal \n
-/// 01h, 09h, 11h, 19h: Less than \n
-/// 02h, 0Ah, 12h, 1Ah: Less than or equal / Greater than or equal
-/// (swapped operands) \n
-/// 03h, 0Bh, 13h, 1Bh: Unordered \n
-/// 04h, 0Ch, 14h, 1Ch: Not equal \n
-/// 05h, 0Dh, 15h, 1Dh: Not less than / Not greater than
-/// (swapped operands) \n
-/// 06h, 0Eh, 16h, 1Eh: Not less than or equal / Not greater than or equal
-/// (swapped operands) \n
-/// 07h, 0Fh, 17h, 1Fh: Ordered
+/// 0x00 : Equal (ordered, non-signaling)
+/// 0x01 : Less-than (ordered, signaling)
+/// 0x02 : Less-than-or-equal (ordered, signaling)
+/// 0x03 : Unordered (non-signaling)
+/// 0x04 : Not-equal (unordered, non-signaling)
+/// 0x05 : Not-less-than (unordered, signaling)
+/// 0x06 : Not-less-than-or-equal (unordered, signaling)
+/// 0x07 : Ordered (non-signaling)
+/// 0x08 : Equal (unordered, non-signaling)
+/// 0x09 : Not-greater-than-or-equal (unordered, signaling)
+/// 0x0a : Not-greater-than (unordered, signaling)
+/// 0x0b : False (ordered, non-signaling)
+/// 0x0c : Not-equal (ordered, non-signaling)
+/// 0x0d : Greater-than-or-equal (ordered, signaling)
+/// 0x0e : Greater-than (ordered, signaling)
+/// 0x0f : True (unordered, non-signaling)
+/// 0x10 : Equal (ordered, signaling)
+/// 0x11 : Less-than (ordered, non-signaling)
+/// 0x12 : Less-than-or-equal (ordered, non-signaling)
+/// 0x13 : Unordered (signaling)
+/// 0x14 : Not-equal (unordered, signaling)
+/// 0x15 : Not-less-than (unordered, non-signaling)
+/// 0x16 : Not-less-than-or-equal (unordered, non-signaling)
+/// 0x17 : Ordered (signaling)
+/// 0x18 : Equal (unordered, signaling)
+/// 0x19 : Not-greater-than-or-equal (unordered, non-signaling)
+/// 0x1a : Not-greater-than (unordered, non-signaling)
+/// 0x1b : False (ordered, signaling)
+/// 0x1c : Not-equal (ordered, signaling)
+/// 0x1d : Greater-than-or-equal (ordered, non-signaling)
+/// 0x1e : Greater-than (ordered, non-signaling)
+/// 0x1f : True (unordered, signaling)
/// \returns A 128-bit vector of [4 x float] containing the comparison results.
#define _mm_cmp_ss(a, b, c) __extension__ ({ \
(__m128)__builtin_ia32_cmpss((__v4sf)(__m128)(a), \
@@ -2184,12 +2325,32 @@ _mm256_cvttps_epi32(__m256 __a)
return (__m256i)__builtin_ia32_cvttps2dq256((__v8sf) __a);
}
+/// \brief Returns the first element of the input vector of [4 x double].
+///
+/// \headerfile <avxintrin.h>
+///
+/// This intrinsic is a utility function and does not correspond to a specific
+/// instruction.
+///
+/// \param __a
+/// A 256-bit vector of [4 x double].
+/// \returns A 64 bit double containing the first element of the input vector.
static __inline double __DEFAULT_FN_ATTRS
_mm256_cvtsd_f64(__m256d __a)
{
return __a[0];
}
+/// \brief Returns the first element of the input vector of [8 x i32].
+///
+/// \headerfile <avxintrin.h>
+///
+/// This intrinsic is a utility function and does not correspond to a specific
+/// instruction.
+///
+/// \param __a
+/// A 256-bit vector of [8 x i32].
+/// \returns A 32 bit integer containing the first element of the input vector.
static __inline int __DEFAULT_FN_ATTRS
_mm256_cvtsi256_si32(__m256i __a)
{
@@ -2197,6 +2358,16 @@ _mm256_cvtsi256_si32(__m256i __a)
return __b[0];
}
+/// \brief Returns the first element of the input vector of [8 x float].
+///
+/// \headerfile <avxintrin.h>
+///
+/// This intrinsic is a utility function and does not correspond to a specific
+/// instruction.
+///
+/// \param __a
+/// A 256-bit vector of [8 x float].
+/// \returns A 32 bit float containing the first element of the input vector.
static __inline float __DEFAULT_FN_ATTRS
_mm256_cvtss_f32(__m256 __a)
{
@@ -2380,7 +2551,9 @@ _mm256_unpacklo_ps(__m256 __a, __m256 __b)
/// \brief Given two 128-bit floating-point vectors of [2 x double], perform an
/// element-by-element comparison of the double-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2407,7 +2580,9 @@ _mm_testz_pd(__m128d __a, __m128d __b)
/// \brief Given two 128-bit floating-point vectors of [2 x double], perform an
/// element-by-element comparison of the double-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2434,7 +2609,9 @@ _mm_testc_pd(__m128d __a, __m128d __b)
/// \brief Given two 128-bit floating-point vectors of [2 x double], perform an
/// element-by-element comparison of the double-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2462,7 +2639,9 @@ _mm_testnzc_pd(__m128d __a, __m128d __b)
/// \brief Given two 128-bit floating-point vectors of [4 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2489,7 +2668,9 @@ _mm_testz_ps(__m128 __a, __m128 __b)
/// \brief Given two 128-bit floating-point vectors of [4 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2516,7 +2697,9 @@ _mm_testc_ps(__m128 __a, __m128 __b)
/// \brief Given two 128-bit floating-point vectors of [4 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2544,7 +2727,9 @@ _mm_testnzc_ps(__m128 __a, __m128 __b)
/// \brief Given two 256-bit floating-point vectors of [4 x double], perform an
/// element-by-element comparison of the double-precision elements in the
/// first source vector and the corresponding elements in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2571,7 +2756,9 @@ _mm256_testz_pd(__m256d __a, __m256d __b)
/// \brief Given two 256-bit floating-point vectors of [4 x double], perform an
/// element-by-element comparison of the double-precision elements in the
/// first source vector and the corresponding elements in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2598,7 +2785,9 @@ _mm256_testc_pd(__m256d __a, __m256d __b)
/// \brief Given two 256-bit floating-point vectors of [4 x double], perform an
/// element-by-element comparison of the double-precision elements in the
/// first source vector and the corresponding elements in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of double-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2626,7 +2815,9 @@ _mm256_testnzc_pd(__m256d __a, __m256d __b)
/// \brief Given two 256-bit floating-point vectors of [8 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2653,7 +2844,9 @@ _mm256_testz_ps(__m256 __a, __m256 __b)
/// \brief Given two 256-bit floating-point vectors of [8 x float], perform an
/// element-by-element comparison of the single-precision element in the
/// first source vector and the corresponding element in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2680,7 +2873,9 @@ _mm256_testc_ps(__m256 __a, __m256 __b)
/// \brief Given two 256-bit floating-point vectors of [8 x float], perform an
/// element-by-element comparison of the single-precision elements in the
/// first source vector and the corresponding elements in the second source
-/// vector. The EFLAGS register is updated as follows: \n
+/// vector.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of single-precision elements where the
/// sign-bits of both elements are 1, the ZF flag is set to 0. Otherwise the
/// ZF flag is set to 1. \n
@@ -2706,7 +2901,9 @@ _mm256_testnzc_ps(__m256 __a, __m256 __b)
}
/// \brief Given two 256-bit integer vectors, perform a bit-by-bit comparison
-/// of the two source vectors and update the EFLAGS register as follows: \n
+/// of the two source vectors.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of bits where both bits are 1, the ZF flag
/// is set to 0. Otherwise the ZF flag is set to 1. \n
/// If there is at least one pair of bits where the bit from the first source
@@ -2730,7 +2927,9 @@ _mm256_testz_si256(__m256i __a, __m256i __b)
}
/// \brief Given two 256-bit integer vectors, perform a bit-by-bit comparison
-/// of the two source vectors and update the EFLAGS register as follows: \n
+/// of the two source vectors.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of bits where both bits are 1, the ZF flag
/// is set to 0. Otherwise the ZF flag is set to 1. \n
/// If there is at least one pair of bits where the bit from the first source
@@ -2754,7 +2953,9 @@ _mm256_testc_si256(__m256i __a, __m256i __b)
}
/// \brief Given two 256-bit integer vectors, perform a bit-by-bit comparison
-/// of the two source vectors and update the EFLAGS register as follows: \n
+/// of the two source vectors.
+///
+/// The EFLAGS register is updated as follows: \n
/// If there is at least one pair of bits where both bits are 1, the ZF flag
/// is set to 0. Otherwise the ZF flag is set to 1. \n
/// If there is at least one pair of bits where the bit from the first source
@@ -3389,7 +3590,8 @@ _mm_maskstore_ps(float *__p, __m128i __m, __m128 __a)
static __inline void __DEFAULT_FN_ATTRS
_mm256_stream_si256(__m256i *__a, __m256i __b)
{
- __builtin_nontemporal_store((__v4di)__b, (__v4di*)__a);
+ typedef __v4di __v4di_aligned __attribute__((aligned(32)));
+ __builtin_nontemporal_store((__v4di_aligned)__b, (__v4di_aligned*)__a);
}
/// \brief Moves double-precision values from a 256-bit vector of [4 x double]
@@ -3402,13 +3604,14 @@ _mm256_stream_si256(__m256i *__a, __m256i __b)
///
/// \param __a
/// A pointer to a 32-byte aligned memory location that will receive the
-/// integer values.
+/// double-precision floating-point values.
/// \param __b
/// A 256-bit vector of [4 x double] containing the values to be moved.
static __inline void __DEFAULT_FN_ATTRS
_mm256_stream_pd(double *__a, __m256d __b)
{
- __builtin_nontemporal_store((__v4df)__b, (__v4df*)__a);
+ typedef __v4df __v4df_aligned __attribute__((aligned(32)));
+ __builtin_nontemporal_store((__v4df_aligned)__b, (__v4df_aligned*)__a);
}
/// \brief Moves single-precision floating point values from a 256-bit vector
@@ -3428,7 +3631,8 @@ _mm256_stream_pd(double *__a, __m256d __b)
static __inline void __DEFAULT_FN_ATTRS
_mm256_stream_ps(float *__p, __m256 __a)
{
- __builtin_nontemporal_store((__v8sf)__a, (__v8sf*)__p);
+ typedef __v8sf __v8sf_aligned __attribute__((aligned(32)));
+ __builtin_nontemporal_store((__v8sf_aligned)__a, (__v8sf_aligned*)__p);
}
/* Create vectors */
@@ -4310,9 +4514,10 @@ _mm256_castsi256_si128(__m256i __a)
}
/// \brief Constructs a 256-bit floating-point vector of [4 x double] from a
-/// 128-bit floating-point vector of [2 x double]. The lower 128 bits
-/// contain the value of the source vector. The contents of the upper 128
-/// bits are undefined.
+/// 128-bit floating-point vector of [2 x double].
+///
+/// The lower 128 bits contain the value of the source vector. The contents
+/// of the upper 128 bits are undefined.
///
/// \headerfile <x86intrin.h>
///
@@ -4330,9 +4535,10 @@ _mm256_castpd128_pd256(__m128d __a)
}
/// \brief Constructs a 256-bit floating-point vector of [8 x float] from a
-/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain
-/// the value of the source vector. The contents of the upper 128 bits are
-/// undefined.
+/// 128-bit floating-point vector of [4 x float].
+///
+/// The lower 128 bits contain the value of the source vector. The contents
+/// of the upper 128 bits are undefined.
///
/// \headerfile <x86intrin.h>
///
@@ -4350,6 +4556,7 @@ _mm256_castps128_ps256(__m128 __a)
}
/// \brief Constructs a 256-bit integer vector from a 128-bit integer vector.
+///
/// The lower 128 bits contain the value of the source vector. The contents
/// of the upper 128 bits are undefined.
///
@@ -4367,6 +4574,61 @@ _mm256_castsi128_si256(__m128i __a)
return __builtin_shufflevector((__v2di)__a, (__v2di)__a, 0, 1, -1, -1);
}
+/// \brief Constructs a 256-bit floating-point vector of [4 x double] from a
+/// 128-bit floating-point vector of [2 x double]. The lower 128 bits
+/// contain the value of the source vector. The upper 128 bits are set
+/// to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit vector of [2 x double].
+/// \returns A 256-bit floating-point vector of [4 x double]. The lower 128 bits
+/// contain the value of the parameter. The upper 128 bits are set to zero.
+static __inline __m256d __DEFAULT_FN_ATTRS
+_mm256_zextpd128_pd256(__m128d __a)
+{
+ return __builtin_shufflevector((__v2df)__a, (__v2df)_mm_setzero_pd(), 0, 1, 2, 3);
+}
+
+/// \brief Constructs a 256-bit floating-point vector of [8 x float] from a
+/// 128-bit floating-point vector of [4 x float]. The lower 128 bits contain
+/// the value of the source vector. The upper 128 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit vector of [4 x float].
+/// \returns A 256-bit floating-point vector of [8 x float]. The lower 128 bits
+/// contain the value of the parameter. The upper 128 bits are set to zero.
+static __inline __m256 __DEFAULT_FN_ATTRS
+_mm256_zextps128_ps256(__m128 __a)
+{
+ return __builtin_shufflevector((__v4sf)__a, (__v4sf)_mm_setzero_ps(), 0, 1, 2, 3, 4, 5, 6, 7);
+}
+
+/// \brief Constructs a 256-bit integer vector from a 128-bit integer vector.
+/// The lower 128 bits contain the value of the source vector. The upper
+/// 128 bits are set to zero.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic has no corresponding instruction.
+///
+/// \param __a
+/// A 128-bit integer vector.
+/// \returns A 256-bit integer vector. The lower 128 bits contain the value of
+/// the parameter. The upper 128 bits are set to zero.
+static __inline __m256i __DEFAULT_FN_ATTRS
+_mm256_zextsi128_si256(__m128i __a)
+{
+ return __builtin_shufflevector((__v2di)__a, (__v2di)_mm_setzero_si128(), 0, 1, 2, 3);
+}
+
/*
Vector insert.
We use macros rather than inlines because we only want to accept
@@ -4375,8 +4637,10 @@ _mm256_castsi128_si256(__m128i __a)
/// \brief Constructs a new 256-bit vector of [8 x float] by first duplicating
/// a 256-bit vector of [8 x float] given in the first parameter, and then
/// replacing either the upper or the lower 128 bits with the contents of a
-/// 128-bit vector of [4 x float] in the second parameter. The immediate
-/// integer parameter determines between the upper or the lower 128 bits.
+/// 128-bit vector of [4 x float] in the second parameter.
+///
+/// The immediate integer parameter determines between the upper or the lower
+/// 128 bits.
///
/// \headerfile <x86intrin.h>
///
@@ -4420,8 +4684,10 @@ _mm256_castsi128_si256(__m128i __a)
/// \brief Constructs a new 256-bit vector of [4 x double] by first duplicating
/// a 256-bit vector of [4 x double] given in the first parameter, and then
/// replacing either the upper or the lower 128 bits with the contents of a
-/// 128-bit vector of [2 x double] in the second parameter. The immediate
-/// integer parameter determines between the upper or the lower 128 bits.
+/// 128-bit vector of [2 x double] in the second parameter.
+///
+/// The immediate integer parameter determines between the upper or the lower
+/// 128 bits.
///
/// \headerfile <x86intrin.h>
///
@@ -4461,8 +4727,10 @@ _mm256_castsi128_si256(__m128i __a)
/// \brief Constructs a new 256-bit integer vector by first duplicating a
/// 256-bit integer vector given in the first parameter, and then replacing
/// either the upper or the lower 128 bits with the contents of a 128-bit
-/// integer vector in the second parameter. The immediate integer parameter
-/// determines between the upper or the lower 128 bits.
+/// integer vector in the second parameter.
+///
+/// The immediate integer parameter determines between the upper or the lower
+/// 128 bits.
///
/// \headerfile <x86intrin.h>
///
diff --git a/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h b/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h
index 488eb2d..e812a16 100644
--- a/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h
@@ -28,107 +28,17 @@
#ifndef __BMIINTRIN_H
#define __BMIINTRIN_H
-/// \brief Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned short _tzcnt_u16(unsigned short a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param a
-/// An unsigned 16-bit integer whose trailing zeros are to be counted.
-/// \returns An unsigned 16-bit integer containing the number of trailing zero
-/// bits in the operand.
#define _tzcnt_u16(a) (__tzcnt_u16((a)))
-/// \brief Performs a bitwise AND of the second operand with the one's
-/// complement of the first operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _andn_u32(unsigned int a, unsigned int b);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> ANDN </c> instruction.
-///
-/// \param a
-/// An unsigned integer containing one of the operands.
-/// \param b
-/// An unsigned integer containing one of the operands.
-/// \returns An unsigned integer containing the bitwise AND of the second
-/// operand with the one's complement of the first operand.
#define _andn_u32(a, b) (__andn_u32((a), (b)))
/* _bextr_u32 != __bextr_u32 */
-/// \brief Clears all bits in the source except for the least significant bit
-/// containing a value of 1 and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _blsi_u32(unsigned int a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSI </c> instruction.
-///
-/// \param a
-/// An unsigned integer whose bits are to be cleared.
-/// \returns An unsigned integer containing the result of clearing the bits from
-/// the source operand.
#define _blsi_u32(a) (__blsi_u32((a)))
-/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and
-/// including the least siginificant bit that is set to 1 in the source
-/// operand and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _blsmsk_u32(unsigned int a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSMSK </c> instruction.
-///
-/// \param a
-/// An unsigned integer used to create the mask.
-/// \returns An unsigned integer containing the newly created mask.
#define _blsmsk_u32(a) (__blsmsk_u32((a)))
-/// \brief Clears the least siginificant bit that is set to 1 in the source
-/// operand and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _blsr_u32(unsigned int a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSR </c> instruction.
-///
-/// \param a
-/// An unsigned integer containing the operand to be cleared.
-/// \returns An unsigned integer containing the result of clearing the source
-/// operand.
#define _blsr_u32(a) (__blsr_u32((a)))
-/// \brief Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned int _tzcnt_u32(unsigned int a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param a
-/// An unsigned 32-bit integer whose trailing zeros are to be counted.
-/// \returns An unsigned 32-bit integer containing the number of trailing zero
-/// bits in the operand.
#define _tzcnt_u32(a) (__tzcnt_u32((a)))
/* Define the default attributes for the functions in this file. */
@@ -238,7 +148,7 @@ __blsi_u32(unsigned int __X)
}
/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and
-/// including the least siginificant bit that is set to 1 in the source
+/// including the least significant bit that is set to 1 in the source
/// operand and returns the result.
///
/// \headerfile <x86intrin.h>
@@ -254,7 +164,7 @@ __blsmsk_u32(unsigned int __X)
return __X ^ (__X - 1);
}
-/// \brief Clears the least siginificant bit that is set to 1 in the source
+/// \brief Clears the least significant bit that is set to 1 in the source
/// operand and returns the result.
///
/// \headerfile <x86intrin.h>
@@ -305,91 +215,15 @@ _mm_tzcnt_32(unsigned int __X)
#ifdef __x86_64__
-/// \brief Performs a bitwise AND of the second operand with the one's
-/// complement of the first operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _andn_u64 (unsigned long long a, unsigned long long b);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> ANDN </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer containing one of the operands.
-/// \param b
-/// An unsigned 64-bit integer containing one of the operands.
-/// \returns An unsigned 64-bit integer containing the bitwise AND of the second
-/// operand with the one's complement of the first operand.
#define _andn_u64(a, b) (__andn_u64((a), (b)))
/* _bextr_u64 != __bextr_u64 */
-/// \brief Clears all bits in the source except for the least significant bit
-/// containing a value of 1 and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _blsi_u64(unsigned long long a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSI </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer whose bits are to be cleared.
-/// \returns An unsigned 64-bit integer containing the result of clearing the
-/// bits from the source operand.
#define _blsi_u64(a) (__blsi_u64((a)))
-/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and
-/// including the least siginificant bit that is set to 1 in the source
-/// operand and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _blsmsk_u64(unsigned long long a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSMSK </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer used to create the mask.
-/// \returns A unsigned 64-bit integer containing the newly created mask.
#define _blsmsk_u64(a) (__blsmsk_u64((a)))
-/// \brief Clears the least siginificant bit that is set to 1 in the source
-/// operand and returns the result.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _blsr_u64(unsigned long long a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> BLSR </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer containing the operand to be cleared.
-/// \returns An unsigned 64-bit integer containing the result of clearing the
-/// source operand.
#define _blsr_u64(a) (__blsr_u64((a)))
-/// \brief Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// \code
-/// unsigned long long _tzcnt_u64(unsigned long long a);
-/// \endcode
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param a
-/// An unsigned 64-bit integer whose trailing zeros are to be counted.
-/// \returns An unsigned 64-bit integer containing the number of trailing zero
-/// bits in the operand.
#define _tzcnt_u64(a) (__tzcnt_u64((a)))
/// \brief Performs a bitwise AND of the second operand with the one's
@@ -475,7 +309,7 @@ __blsi_u64(unsigned long long __X)
}
/// \brief Creates a mask whose bits are set to 1, using bit 0 up to and
-/// including the least siginificant bit that is set to 1 in the source
+/// including the least significant bit that is set to 1 in the source
/// operand and returns the result.
///
/// \headerfile <x86intrin.h>
@@ -484,14 +318,14 @@ __blsi_u64(unsigned long long __X)
///
/// \param __X
/// An unsigned 64-bit integer used to create the mask.
-/// \returns A unsigned 64-bit integer containing the newly created mask.
+/// \returns An unsigned 64-bit integer containing the newly created mask.
static __inline__ unsigned long long __DEFAULT_FN_ATTRS
__blsmsk_u64(unsigned long long __X)
{
return __X ^ (__X - 1);
}
-/// \brief Clears the least siginificant bit that is set to 1 in the source
+/// \brief Clears the least significant bit that is set to 1 in the source
/// operand and returns the result.
///
/// \headerfile <x86intrin.h>
diff --git a/contrib/llvm/tools/clang/lib/Headers/clzerointrin.h b/contrib/llvm/tools/clang/lib/Headers/clzerointrin.h
new file mode 100644
index 0000000..ed7478f
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Headers/clzerointrin.h
@@ -0,0 +1,50 @@
+/*===----------------------- clzerointrin.h - CLZERO ----------------------===
+ *
+ * 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 <clzerointrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef _CLZEROINTRIN_H
+#define _CLZEROINTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS \
+ __attribute__((__always_inline__, __nodebug__, __target__("clzero")))
+
+/// \brief Loads the cache line address and zero's out the cacheline
+///
+/// \headerfile <clzerointrin.h>
+///
+/// This intrinsic corresponds to the <c> CLZERO </c> instruction.
+///
+/// \param __line
+/// A pointer to a cacheline which needs to be zeroed out.
+static __inline__ void __DEFAULT_FN_ATTRS
+_mm_clzero (void * __line)
+{
+ __builtin_ia32_clzero ((void *)__line);
+}
+
+#undef __DEFAULT_FN_ATTRS
+
+#endif /* _CLZEROINTRIN_H */
diff --git a/contrib/llvm/tools/clang/lib/Headers/cpuid.h b/contrib/llvm/tools/clang/lib/Headers/cpuid.h
index 400dcfa..2dd0add 100644
--- a/contrib/llvm/tools/clang/lib/Headers/cpuid.h
+++ b/contrib/llvm/tools/clang/lib/Headers/cpuid.h
@@ -79,7 +79,7 @@
#define signature_VORTEX_edx 0x36387865
#define signature_VORTEX_ecx 0x436f5320
-/* Features in %ecx for level 1 */
+/* Features in %ecx for leaf 1 */
#define bit_SSE3 0x00000001
#define bit_PCLMULQDQ 0x00000002
#define bit_PCLMUL bit_PCLMULQDQ /* for gcc compat */
@@ -114,7 +114,7 @@
#define bit_F16C 0x20000000
#define bit_RDRND 0x40000000
-/* Features in %edx for level 1 */
+/* Features in %edx for leaf 1 */
#define bit_FPU 0x00000001
#define bit_VME 0x00000002
#define bit_DE 0x00000004
@@ -147,44 +147,95 @@
#define bit_TM 0x20000000
#define bit_PBE 0x80000000
-/* Features in %ebx for level 7 sub-leaf 0 */
+/* Features in %ebx for leaf 7 sub-leaf 0 */
#define bit_FSGSBASE 0x00000001
+#define bit_SGX 0x00000004
+#define bit_BMI 0x00000008
+#define bit_HLE 0x00000010
+#define bit_AVX2 0x00000020
#define bit_SMEP 0x00000080
+#define bit_BMI2 0x00000100
#define bit_ENH_MOVSB 0x00000200
+#define bit_RTM 0x00000800
+#define bit_MPX 0x00004000
+#define bit_AVX512F 0x00010000
+#define bit_AVX512DQ 0x00020000
+#define bit_RDSEED 0x00040000
+#define bit_ADX 0x00080000
+#define bit_AVX512IFMA 0x00200000
+#define bit_CLFLUSHOPT 0x00800000
+#define bit_CLWB 0x01000000
+#define bit_AVX512PF 0x04000000
+#define bit_AVX51SER 0x08000000
+#define bit_AVX512CD 0x10000000
+#define bit_SHA 0x20000000
+#define bit_AVX512BW 0x40000000
+#define bit_AVX512VL 0x80000000
+
+/* Features in %ecx for leaf 7 sub-leaf 0 */
+#define bit_PREFTCHWT1 0x00000001
+#define bit_AVX512VBMI 0x00000002
+#define bit_PKU 0x00000004
+#define bit_OSPKE 0x00000010
+#define bit_AVX512VPOPCNTDQ 0x00004000
+#define bit_RDPID 0x00400000
+
+/* Features in %edx for leaf 7 sub-leaf 0 */
+#define bit_AVX5124VNNIW 0x00000004
+#define bit_AVX5124FMAPS 0x00000008
+
+/* Features in %eax for leaf 13 sub-leaf 1 */
+#define bit_XSAVEOPT 0x00000001
+#define bit_XSAVEC 0x00000002
+#define bit_XSAVES 0x00000008
+
+/* Features in %ecx for leaf 0x80000001 */
+#define bit_LAHF_LM 0x00000001
+#define bit_ABM 0x00000020
+#define bit_SSE4a 0x00000040
+#define bit_PRFCHW 0x00000100
+#define bit_XOP 0x00000800
+#define bit_LWP 0x00008000
+#define bit_FMA4 0x00010000
+#define bit_TBM 0x00200000
+#define bit_MWAITX 0x20000000
+
+/* Features in %edx for leaf 0x80000001 */
+#define bit_MMXEXT 0x00400000
+#define bit_LM 0x20000000
+#define bit_3DNOWP 0x40000000
+#define bit_3DNOW 0x80000000
+
+/* Features in %ebx for leaf 0x80000001 */
+#define bit_CLZERO 0x00000001
+
#if __i386__
-#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
+#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \
__asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level))
+ : "0"(__leaf))
-#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
+#define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \
__asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level), "2"(__count))
+ : "0"(__leaf), "2"(__count))
#else
/* x86-64 uses %rbx as the base register, so preserve it. */
-#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \
+#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \
__asm(" xchgq %%rbx,%q1\n" \
" cpuid\n" \
" xchgq %%rbx,%q1" \
: "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level))
+ : "0"(__leaf))
-#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \
+#define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \
__asm(" xchgq %%rbx,%q1\n" \
" cpuid\n" \
" xchgq %%rbx,%q1" \
: "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \
- : "0"(__level), "2"(__count))
+ : "0"(__leaf), "2"(__count))
#endif
-static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax,
- unsigned int *__ebx, unsigned int *__ecx,
- unsigned int *__edx) {
- __cpuid(__level, *__eax, *__ebx, *__ecx, *__edx);
- return 1;
-}
-
-static __inline int __get_cpuid_max (unsigned int __level, unsigned int *__sig)
+static __inline int __get_cpuid_max (unsigned int __leaf, unsigned int *__sig)
{
unsigned int __eax, __ebx, __ecx, __edx;
#if __i386__
@@ -208,8 +259,35 @@ static __inline int __get_cpuid_max (unsigned int __level, unsigned int *__sig)
return 0;
#endif
- __cpuid(__level, __eax, __ebx, __ecx, __edx);
+ __cpuid(__leaf, __eax, __ebx, __ecx, __edx);
if (__sig)
*__sig = __ebx;
return __eax;
}
+
+static __inline int __get_cpuid (unsigned int __leaf, unsigned int *__eax,
+ unsigned int *__ebx, unsigned int *__ecx,
+ unsigned int *__edx)
+{
+ unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0);
+
+ if (__max_leaf == 0 || __max_leaf < __leaf)
+ return 0;
+
+ __cpuid(__leaf, *__eax, *__ebx, *__ecx, *__edx);
+ return 1;
+}
+
+static __inline int __get_cpuid_count (unsigned int __leaf,
+ unsigned int __subleaf,
+ unsigned int *__eax, unsigned int *__ebx,
+ unsigned int *__ecx, unsigned int *__edx)
+{
+ unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0);
+
+ if (__max_leaf == 0 || __max_leaf < __leaf)
+ return 0;
+
+ __cpuid_count(__leaf, __subleaf, *__eax, *__ebx, *__ecx, *__edx);
+ return 1;
+}
diff --git a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h
index 1512f9f..709815c 100644
--- a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h
@@ -302,7 +302,7 @@ _mm_min_pd(__m128d __a, __m128d __b)
return __builtin_ia32_minpd((__v2df)__a, (__v2df)__b);
}
-/// \brief Compares lower 64-bits double-precision values of both operands, and
+/// \brief Compares lower 64-bit double-precision values of both operands, and
/// returns the greater of the pair of values in the lower 64-bits of the
/// result. The upper 64 bits of the result are copied from the upper double-
/// precision value of the first operand.
@@ -462,8 +462,9 @@ _mm_cmplt_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are less than or equal to those in the second operand. Each
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are less than or equal to those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -482,8 +483,9 @@ _mm_cmple_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are greater than those in the second operand. Each comparison
-/// yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are greater than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -502,8 +504,9 @@ _mm_cmpgt_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are greater than or equal to those in the second operand. Each
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are greater than or equal to those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -522,9 +525,10 @@ _mm_cmpge_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are ordered with respect to those in the second operand. A pair
-/// of double-precision values are "ordered" with respect to each other if
-/// neither value is a NaN. Each comparison yields 0h for false,
+/// operand are ordered with respect to those in the second operand.
+///
+/// A pair of double-precision values are "ordered" with respect to each
+/// other if neither value is a NaN. Each comparison yields 0h for false,
/// FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
@@ -544,9 +548,10 @@ _mm_cmpord_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are unordered with respect to those in the second operand. A pair
-/// of double-precision values are "unordered" with respect to each other if
-/// one or both values are NaN. Each comparison yields 0h for false,
+/// operand are unordered with respect to those in the second operand.
+///
+/// A pair of double-precision values are "unordered" with respect to each
+/// other if one or both values are NaN. Each comparison yields 0h for false,
/// FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
@@ -567,8 +572,9 @@ _mm_cmpunord_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are unequal to those in the second operand. Each comparison
-/// yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are unequal to those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -587,8 +593,9 @@ _mm_cmpneq_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are not less than those in the second operand. Each comparison
-/// yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are not less than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -607,8 +614,9 @@ _mm_cmpnlt_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are not less than or equal to those in the second operand. Each
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are not less than or equal to those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -627,8 +635,9 @@ _mm_cmpnle_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
-/// operand are not greater than those in the second operand. Each
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// operand are not greater than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -648,6 +657,7 @@ _mm_cmpngt_pd(__m128d __a, __m128d __b)
/// \brief Compares each of the corresponding double-precision values of the
/// 128-bit vectors of [2 x double] to determine if the values in the first
/// operand are not greater than or equal to those in the second operand.
+///
/// Each comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
@@ -666,8 +676,9 @@ _mm_cmpnge_pd(__m128d __a, __m128d __b)
}
/// \brief Compares the lower double-precision floating-point values in each of
-/// the two 128-bit floating-point vectors of [2 x double] for equality. The
-/// comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
+/// the two 128-bit floating-point vectors of [2 x double] for equality.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -690,8 +701,9 @@ _mm_cmpeq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than the corresponding value in
-/// the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -714,8 +726,9 @@ _mm_cmplt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0h for
-/// false, FFFFFFFFFFFFFFFFh for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -738,8 +751,9 @@ _mm_cmple_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than the corresponding value
-/// in the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -763,8 +777,9 @@ _mm_cmpgt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0h for
-/// false, FFFFFFFFFFFFFFFFh for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -788,9 +803,11 @@ _mm_cmpge_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is "ordered" with respect to the
-/// corresponding value in the second parameter. The comparison yields 0h for
-/// false, FFFFFFFFFFFFFFFFh for true. A pair of double-precision values are
-/// "ordered" with respect to each other if neither value is a NaN.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true. A pair of
+/// double-precision values are "ordered" with respect to each other if
+/// neither value is a NaN.
///
/// \headerfile <x86intrin.h>
///
@@ -813,9 +830,11 @@ _mm_cmpord_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is "unordered" with respect to the
-/// corresponding value in the second parameter. The comparison yields 0h
-/// for false, FFFFFFFFFFFFFFFFh for true. A pair of double-precision values
-/// are "unordered" with respect to each other if one or both values are NaN.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true. A pair of
+/// double-precision values are "unordered" with respect to each other if one
+/// or both values are NaN.
///
/// \headerfile <x86intrin.h>
///
@@ -839,8 +858,9 @@ _mm_cmpunord_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is unequal to the corresponding value in
-/// the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -863,8 +883,9 @@ _mm_cmpneq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is not less than the corresponding
-/// value in the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -887,8 +908,9 @@ _mm_cmpnlt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is not less than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0h
-/// for false, FFFFFFFFFFFFFFFFh for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -911,8 +933,9 @@ _mm_cmpnle_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is not greater than the corresponding
-/// value in the second parameter. The comparison yields 0h for false,
-/// FFFFFFFFFFFFFFFFh for true.
+/// value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -936,8 +959,9 @@ _mm_cmpngt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is not greater than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0h
-/// for false, FFFFFFFFFFFFFFFFh for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0h for false, FFFFFFFFFFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -982,7 +1006,9 @@ _mm_comieq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than the corresponding value in
-/// the second parameter. The comparison yields 0 for false, 1 for true.
+/// the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1004,8 +1030,9 @@ _mm_comilt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0 for
-/// false, 1 for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1027,7 +1054,9 @@ _mm_comile_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than the corresponding value
-/// in the second parameter. The comparison yields 0 for false, 1 for true.
+/// in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1049,8 +1078,9 @@ _mm_comigt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0 for
-/// false, 1 for true.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1072,7 +1102,9 @@ _mm_comige_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is unequal to the corresponding value in
-/// the second parameter. The comparison yields 0 for false, 1 for true.
+/// the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1093,8 +1125,9 @@ _mm_comineq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] for equality. The
-/// comparison yields 0 for false, 1 for true. If either of the two lower
-/// double-precision values is NaN, 1 is returned.
+/// comparison yields 0 for false, 1 for true.
+///
+/// If either of the two lower double-precision values is NaN, 1 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1117,8 +1150,10 @@ _mm_ucomieq_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than the corresponding value in
-/// the second parameter. The comparison yields 0 for false, 1 for true. If
-/// either of the two lower double-precision values is NaN, 1 is returned.
+/// the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two lower
+/// double-precision values is NaN, 1 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1141,9 +1176,10 @@ _mm_ucomilt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is less than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0 for
-/// false, 1 for true. If either of the two lower double-precision values is
-/// NaN, 1 is returned.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two lower
+/// double-precision values is NaN, 1 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1166,8 +1202,10 @@ _mm_ucomile_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than the corresponding value
-/// in the second parameter. The comparison yields 0 for false, 1 for true.
-/// If either of the two lower double-precision values is NaN, 0 is returned.
+/// in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two lower
+/// double-precision values is NaN, 0 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1190,9 +1228,10 @@ _mm_ucomigt_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is greater than or equal to the
-/// corresponding value in the second parameter. The comparison yields 0 for
-/// false, 1 for true. If either of the two lower double-precision values
-/// is NaN, 0 is returned.
+/// corresponding value in the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two
+/// lower double-precision values is NaN, 0 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1215,8 +1254,10 @@ _mm_ucomige_sd(__m128d __a, __m128d __b)
/// \brief Compares the lower double-precision floating-point values in each of
/// the two 128-bit floating-point vectors of [2 x double] to determine if
/// the value in the first parameter is unequal to the corresponding value in
-/// the second parameter. The comparison yields 0 for false, 1 for true. If
-/// either of the two lower double-precision values is NaN, 0 is returned.
+/// the second parameter.
+///
+/// The comparison yields 0 for false, 1 for true. If either of the two lower
+/// double-precision values is NaN, 0 is returned.
///
/// \headerfile <x86intrin.h>
///
@@ -1278,8 +1319,9 @@ _mm_cvtps_pd(__m128 __a)
/// \brief Converts the lower two integer elements of a 128-bit vector of
/// [4 x i32] into two double-precision floating-point values, returned in a
-/// 128-bit vector of [2 x double]. The upper two elements of the input
-/// vector are unused.
+/// 128-bit vector of [2 x double].
+///
+/// The upper two elements of the input vector are unused.
///
/// \headerfile <x86intrin.h>
///
@@ -1287,7 +1329,9 @@ _mm_cvtps_pd(__m128 __a)
///
/// \param __a
/// A 128-bit integer vector of [4 x i32]. The lower two integer elements are
-/// converted to double-precision values. The upper two elements are unused.
+/// converted to double-precision values.
+///
+/// The upper two elements are unused.
/// \returns A 128-bit vector of [2 x double] containing the converted values.
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_cvtepi32_pd(__m128i __a)
@@ -1409,10 +1453,11 @@ _mm_cvtss_sd(__m128d __a, __m128 __b)
/// \brief Converts the two double-precision floating-point elements of a
/// 128-bit vector of [2 x double] into two signed 32-bit integer values,
-/// returned in the lower 64 bits of a 128-bit vector of [4 x i32]. If the
-/// result of either conversion is inexact, the result is truncated (rounded
-/// towards zero) regardless of the current MXCSR setting. The upper 64 bits
-/// of the result vector are set to zero.
+/// returned in the lower 64 bits of a 128-bit vector of [4 x i32].
+///
+/// If the result of either conversion is inexact, the result is truncated
+/// (rounded towards zero) regardless of the current MXCSR setting. The upper
+/// 64 bits of the result vector are set to zero.
///
/// \headerfile <x86intrin.h>
///
@@ -1466,9 +1511,10 @@ _mm_cvtpd_pi32(__m128d __a)
/// \brief Converts the two double-precision floating-point elements of a
/// 128-bit vector of [2 x double] into two signed 32-bit integer values,
-/// returned in a 64-bit vector of [2 x i32]. If the result of either
-/// conversion is inexact, the result is truncated (rounded towards zero)
-/// regardless of the current MXCSR setting.
+/// returned in a 64-bit vector of [2 x i32].
+///
+/// If the result of either conversion is inexact, the result is truncated
+/// (rounded towards zero) regardless of the current MXCSR setting.
///
/// \headerfile <x86intrin.h>
///
@@ -1599,6 +1645,17 @@ _mm_loadu_pd(double const *__dp)
return ((struct __loadu_pd*)__dp)->__v;
}
+/// \brief Loads a 64-bit integer value to the low element of a 128-bit integer
+/// vector and clears the upper element.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VMOVQ / MOVQ </c> instruction.
+///
+/// \param __a
+/// A pointer to a 64-bit memory location. The address of the memory
+/// location does not have to be aligned.
+/// \returns A 128-bit vector of [2 x i64] containing the loaded value.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_loadu_si64(void const *__a)
{
@@ -1609,6 +1666,17 @@ _mm_loadu_si64(void const *__a)
return (__m128i){__u, 0L};
}
+/// \brief Loads a 64-bit double-precision value to the low element of a
+/// 128-bit integer vector and clears the upper element.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VMOVSD / MOVSD </c> instruction.
+///
+/// \param __dp
+/// A pointer to a memory location containing a double-precision value.
+/// The address of the memory location does not have to be aligned.
+/// \returns A 128-bit vector of [2 x double] containing the loaded value.
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_load_sd(double const *__dp)
{
@@ -1728,6 +1796,24 @@ _mm_set1_pd(double __w)
return (__m128d){ __w, __w };
}
+/// \brief Constructs a 128-bit floating-point vector of [2 x double], with each
+/// of the two double-precision floating-point vector elements set to the
+/// specified double-precision floating-point value.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VMOVDDUP / MOVLHPS </c> instruction.
+///
+/// \param __w
+/// A double-precision floating-point value used to initialize each vector
+/// element of the result.
+/// \returns An initialized 128-bit floating-point vector of [2 x double].
+static __inline__ __m128d __DEFAULT_FN_ATTRS
+_mm_set_pd1(double __w)
+{
+ return _mm_set1_pd(__w);
+}
+
/// \brief Constructs a 128-bit floating-point vector of [2 x double]
/// initialized with the specified double-precision floating-point values.
///
@@ -1787,7 +1873,7 @@ _mm_setzero_pd(void)
/// \brief Constructs a 128-bit floating-point vector of [2 x double]. The lower
/// 64 bits are set to the lower 64 bits of the second parameter. The upper
/// 64 bits are set to the upper 64 bits of the first parameter.
-//
+///
/// \headerfile <x86intrin.h>
///
/// This intrinsic corresponds to the <c> VBLENDPD / BLENDPD </c> instruction.
@@ -1825,12 +1911,38 @@ _mm_store_sd(double *__dp, __m128d __a)
((struct __mm_store_sd_struct*)__dp)->__u = __a[0];
}
+/// \brief Moves packed double-precision values from a 128-bit vector of
+/// [2 x double] to a memory location.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c>VMOVAPD / MOVAPS</c> instruction.
+///
+/// \param __dp
+/// A pointer to an aligned memory location that can store two
+/// double-precision values.
+/// \param __a
+/// A packed 128-bit vector of [2 x double] containing the values to be
+/// moved.
static __inline__ void __DEFAULT_FN_ATTRS
_mm_store_pd(double *__dp, __m128d __a)
{
*(__m128d*)__dp = __a;
}
+/// \brief Moves the lower 64 bits of a 128-bit vector of [2 x double] twice to
+/// the upper and lower 64 bits of a memory location.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c>VMOVDDUP + VMOVAPD / MOVLHPS + MOVAPS </c> instruction.
+///
+/// \param __dp
+/// A pointer to a memory location that can store two double-precision
+/// values.
+/// \param __a
+/// A 128-bit vector of [2 x double] whose lower 64 bits are copied to each
+/// of the values in \a dp.
static __inline__ void __DEFAULT_FN_ATTRS
_mm_store1_pd(double *__dp, __m128d __a)
{
@@ -1940,8 +2052,9 @@ _mm_storel_pd(double *__dp, __m128d __a)
/// \brief Adds the corresponding elements of two 128-bit vectors of [16 x i8],
/// saving the lower 8 bits of each sum in the corresponding element of a
-/// 128-bit result vector of [16 x i8]. The integer elements of both
-/// parameters can be either signed or unsigned.
+/// 128-bit result vector of [16 x i8].
+///
+/// The integer elements of both parameters can be either signed or unsigned.
///
/// \headerfile <x86intrin.h>
///
@@ -1961,8 +2074,9 @@ _mm_add_epi8(__m128i __a, __m128i __b)
/// \brief Adds the corresponding elements of two 128-bit vectors of [8 x i16],
/// saving the lower 16 bits of each sum in the corresponding element of a
-/// 128-bit result vector of [8 x i16]. The integer elements of both
-/// parameters can be either signed or unsigned.
+/// 128-bit result vector of [8 x i16].
+///
+/// The integer elements of both parameters can be either signed or unsigned.
///
/// \headerfile <x86intrin.h>
///
@@ -1982,8 +2096,9 @@ _mm_add_epi16(__m128i __a, __m128i __b)
/// \brief Adds the corresponding elements of two 128-bit vectors of [4 x i32],
/// saving the lower 32 bits of each sum in the corresponding element of a
-/// 128-bit result vector of [4 x i32]. The integer elements of both
-/// parameters can be either signed or unsigned.
+/// 128-bit result vector of [4 x i32].
+///
+/// The integer elements of both parameters can be either signed or unsigned.
///
/// \headerfile <x86intrin.h>
///
@@ -2021,8 +2136,9 @@ _mm_add_si64(__m64 __a, __m64 __b)
/// \brief Adds the corresponding elements of two 128-bit vectors of [2 x i64],
/// saving the lower 64 bits of each sum in the corresponding element of a
-/// 128-bit result vector of [2 x i64]. The integer elements of both
-/// parameters can be either signed or unsigned.
+/// 128-bit result vector of [2 x i64].
+///
+/// The integer elements of both parameters can be either signed or unsigned.
///
/// \headerfile <x86intrin.h>
///
@@ -2168,10 +2284,12 @@ _mm_avg_epu16(__m128i __a, __m128i __b)
/// \brief Multiplies the corresponding elements of two 128-bit signed [8 x i16]
/// vectors, producing eight intermediate 32-bit signed integer products, and
/// adds the consecutive pairs of 32-bit products to form a 128-bit signed
-/// [4 x i32] vector. For example, bits [15:0] of both parameters are
-/// multiplied producing a 32-bit product, bits [31:16] of both parameters
-/// are multiplied producing a 32-bit product, and the sum of those two
-/// products becomes bits [31:0] of the result.
+/// [4 x i32] vector.
+///
+/// For example, bits [15:0] of both parameters are multiplied producing a
+/// 32-bit product, bits [31:16] of both parameters are multiplied producing
+/// a 32-bit product, and the sum of those two products becomes bits [31:0]
+/// of the result.
///
/// \headerfile <x86intrin.h>
///
@@ -2369,7 +2487,7 @@ _mm_mul_epu32(__m128i __a, __m128i __b)
/// \brief Computes the absolute differences of corresponding 8-bit integer
/// values in two 128-bit vectors. Sums the first 8 absolute differences, and
-/// separately sums the second 8 absolute differences. Packss these two
+/// separately sums the second 8 absolute differences. Packs these two
/// unsigned 16-bit integer sums into the upper and lower elements of a
/// [2 x i64] vector.
///
@@ -3106,8 +3224,9 @@ _mm_cmpgt_epi8(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 16-bit values of the
/// 128-bit integer vectors to determine if the values in the first operand
-/// are greater than those in the second operand. Each comparison yields 0h
-/// for false, FFFFh for true.
+/// are greater than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3126,8 +3245,9 @@ _mm_cmpgt_epi16(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 32-bit values of the
/// 128-bit integer vectors to determine if the values in the first operand
-/// are greater than those in the second operand. Each comparison yields 0h
-/// for false, FFFFFFFFh for true.
+/// are greater than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3146,8 +3266,9 @@ _mm_cmpgt_epi32(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 8-bit values of the 128-bit
/// integer vectors to determine if the values in the first operand are less
-/// than those in the second operand. Each comparison yields 0h for false,
-/// FFh for true.
+/// than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3166,8 +3287,9 @@ _mm_cmplt_epi8(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 16-bit values of the
/// 128-bit integer vectors to determine if the values in the first operand
-/// are less than those in the second operand. Each comparison yields 0h for
-/// false, FFFFh for true.
+/// are less than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3186,8 +3308,9 @@ _mm_cmplt_epi16(__m128i __a, __m128i __b)
/// \brief Compares each of the corresponding signed 32-bit values of the
/// 128-bit integer vectors to determine if the values in the first operand
-/// are less than those in the second operand. Each comparison yields 0h for
-/// false, FFFFFFFFh for true.
+/// are less than those in the second operand.
+///
+/// Each comparison yields 0h for false, FFFFFFFFh for true.
///
/// \headerfile <x86intrin.h>
///
@@ -3885,10 +4008,11 @@ _mm_storeu_si128(__m128i *__p, __m128i __b)
/// \brief Moves bytes selected by the mask from the first operand to the
/// specified unaligned memory location. When a mask bit is 1, the
-/// corresponding byte is written, otherwise it is not written. To minimize
-/// caching, the date is flagged as non-temporal (unlikely to be used again
-/// soon). Exception and trap behavior for elements not selected for storage
-/// to memory are implementation dependent.
+/// corresponding byte is written, otherwise it is not written.
+///
+/// To minimize caching, the date is flagged as non-temporal (unlikely to be
+/// used again soon). Exception and trap behavior for elements not selected
+/// for storage to memory are implementation dependent.
///
/// \headerfile <x86intrin.h>
///
@@ -3932,8 +4056,10 @@ _mm_storel_epi64(__m128i *__p, __m128i __a)
}
/// \brief Stores a 128-bit floating point vector of [2 x double] to a 128-bit
-/// aligned memory location. To minimize caching, the data is flagged as
-/// non-temporal (unlikely to be used again soon).
+/// aligned memory location.
+///
+/// To minimize caching, the data is flagged as non-temporal (unlikely to be
+/// used again soon).
///
/// \headerfile <x86intrin.h>
///
@@ -3950,6 +4076,7 @@ _mm_stream_pd(double *__p, __m128d __a)
}
/// \brief Stores a 128-bit integer vector to a 128-bit aligned memory location.
+///
/// To minimize caching, the data is flagged as non-temporal (unlikely to be
/// used again soon).
///
@@ -3967,8 +4094,9 @@ _mm_stream_si128(__m128i *__p, __m128i __a)
__builtin_nontemporal_store((__v2di)__a, (__v2di*)__p);
}
-/// \brief Stores a 32-bit integer value in the specified memory location. To
-/// minimize caching, the data is flagged as non-temporal (unlikely to be
+/// \brief Stores a 32-bit integer value in the specified memory location.
+///
+/// To minimize caching, the data is flagged as non-temporal (unlikely to be
/// used again soon).
///
/// \headerfile <x86intrin.h>
@@ -3986,8 +4114,9 @@ _mm_stream_si32(int *__p, int __a)
}
#ifdef __x86_64__
-/// \brief Stores a 64-bit integer value in the specified memory location. To
-/// minimize caching, the data is flagged as non-temporal (unlikely to be
+/// \brief Stores a 64-bit integer value in the specified memory location.
+///
+/// To minimize caching, the data is flagged as non-temporal (unlikely to be
/// used again soon).
///
/// \headerfile <x86intrin.h>
@@ -4019,7 +4148,7 @@ extern "C" {
/// \param __p
/// A pointer to the memory location used to identify the cache line to be
/// flushed.
-void _mm_clflush(void const *);
+void _mm_clflush(void const * __p);
/// \brief Forces strong memory ordering (serialization) between load
/// instructions preceding this instruction and load instructions following
@@ -4141,7 +4270,7 @@ _mm_packus_epi16(__m128i __a, __m128i __b)
/// \param __a
/// A 128-bit integer vector.
/// \param __imm
-/// An immediate value. Bits [3:0] selects values from \a __a to be assigned
+/// An immediate value. Bits [2:0] selects values from \a __a to be assigned
/// to bits[15:0] of the result. \n
/// 000: assign values from bits [15:0] of \a __a. \n
/// 001: assign values from bits [31:16] of \a __a. \n
@@ -4788,4 +4917,12 @@ void _mm_pause(void);
#define _MM_SHUFFLE2(x, y) (((x) << 1) | (y))
+#define _MM_DENORMALS_ZERO_ON (0x0040)
+#define _MM_DENORMALS_ZERO_OFF (0x0000)
+
+#define _MM_DENORMALS_ZERO_MASK (0x0040)
+
+#define _MM_GET_DENORMALS_ZERO_MODE() (_mm_getcsr() & _MM_DENORMALS_ZERO_MASK)
+#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x)))
+
#endif /* __EMMINTRIN_H */
diff --git a/contrib/llvm/tools/clang/lib/Headers/f16cintrin.h b/contrib/llvm/tools/clang/lib/Headers/f16cintrin.h
index 180712f..b796cc8 100644
--- a/contrib/llvm/tools/clang/lib/Headers/f16cintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/f16cintrin.h
@@ -72,9 +72,9 @@ _cvtsh_ss(unsigned short __a)
/// 011: Truncate \n
/// 1XX: Use MXCSR.RC for rounding
/// \returns The converted 16-bit half-precision float value.
-#define _cvtss_sh(a, imm) \
- ((unsigned short)(((__v8hi)__builtin_ia32_vcvtps2ph((__v4sf){a, 0, 0, 0}, \
- (imm)))[0]))
+#define _cvtss_sh(a, imm) __extension__ ({ \
+ (unsigned short)(((__v8hi)__builtin_ia32_vcvtps2ph((__v4sf){a, 0, 0, 0}, \
+ (imm)))[0]); })
/// \brief Converts a 128-bit vector containing 32-bit float values into a
/// 128-bit vector containing 16-bit half-precision float values.
@@ -99,8 +99,8 @@ _cvtsh_ss(unsigned short __a)
/// \returns A 128-bit vector containing converted 16-bit half-precision float
/// values. The lower 64 bits are used to store the converted 16-bit
/// half-precision floating-point values.
-#define _mm_cvtps_ph(a, imm) \
- ((__m128i)__builtin_ia32_vcvtps2ph((__v4sf)(__m128)(a), (imm)))
+#define _mm_cvtps_ph(a, imm) __extension__ ({ \
+ (__m128i)__builtin_ia32_vcvtps2ph((__v4sf)(__m128)(a), (imm)); })
/// \brief Converts a 128-bit vector containing 16-bit half-precision float
/// values into a 128-bit vector containing 32-bit float values.
diff --git a/contrib/llvm/tools/clang/lib/Headers/float.h b/contrib/llvm/tools/clang/lib/Headers/float.h
index 0f453d8..502143d 100644
--- a/contrib/llvm/tools/clang/lib/Headers/float.h
+++ b/contrib/llvm/tools/clang/lib/Headers/float.h
@@ -33,6 +33,15 @@
*/
#if (defined(__APPLE__) || (defined(__MINGW32__) || defined(_MSC_VER))) && \
__STDC_HOSTED__ && __has_include_next(<float.h>)
+
+/* Prior to Apple's 10.7 SDK, float.h SDK header used to apply an extra level
+ * of #include_next<float.h> to keep Metrowerks compilers happy. Avoid this
+ * extra indirection.
+ */
+#ifdef __APPLE__
+#define _FLOAT_H_
+#endif
+
# include_next <float.h>
/* Undefine anything that we'll be redefining below. */
diff --git a/contrib/llvm/tools/clang/lib/Headers/htmxlintrin.h b/contrib/llvm/tools/clang/lib/Headers/htmxlintrin.h
index 16dc705..28f7d02 100644
--- a/contrib/llvm/tools/clang/lib/Headers/htmxlintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/htmxlintrin.h
@@ -35,14 +35,10 @@
extern "C" {
#endif
-#define _TEXASR_PTR(TM_BUF) \
- ((texasr_t *)((TM_BUF)+0))
-#define _TEXASRU_PTR(TM_BUF) \
- ((texasru_t *)((TM_BUF)+0))
-#define _TEXASRL_PTR(TM_BUF) \
- ((texasrl_t *)((TM_BUF)+4))
-#define _TFIAR_PTR(TM_BUF) \
- ((tfiar_t *)((TM_BUF)+8))
+#define _TEXASR_PTR(TM_BUF) ((texasr_t *)((char *)(TM_BUF) + 0))
+#define _TEXASRU_PTR(TM_BUF) ((texasru_t *)((char *)(TM_BUF) + 0))
+#define _TEXASRL_PTR(TM_BUF) ((texasrl_t *)((char *)(TM_BUF) + 4))
+#define _TFIAR_PTR(TM_BUF) ((tfiar_t *)((char *)(TM_BUF) + 8))
typedef char TM_buff_type[16];
@@ -178,7 +174,7 @@ extern __inline long
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
__TM_is_conflict(void* const __TM_buff)
{
- texasru_t texasru = *_TEXASRU_PTR (TM_buff);
+ texasru_t texasru = *_TEXASRU_PTR (__TM_buff);
/* Return TEXASR bits 11 (Self-Induced Conflict) through
14 (Translation Invalidation Conflict). */
return (_TEXASRU_EXTRACT_BITS (texasru, 14, 4)) ? 1 : 0;
diff --git a/contrib/llvm/tools/clang/lib/Headers/immintrin.h b/contrib/llvm/tools/clang/lib/Headers/immintrin.h
index 7f91d49..c5f25bf 100644
--- a/contrib/llvm/tools/clang/lib/Headers/immintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/immintrin.h
@@ -146,6 +146,10 @@ _mm256_cvtph_ps(__m128i __a)
#include <avx512cdintrin.h>
#endif
+#if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX512VPOPCNTDQ__)
+#include <avx512vpopcntdqintrin.h>
+#endif
+
#if !defined(_MSC_VER) || __has_feature(modules) || defined(__AVX512DQ__)
#include <avx512dqintrin.h>
#endif
@@ -208,6 +212,15 @@ _rdrand32_step(unsigned int *__p)
return __builtin_ia32_rdrand32_step(__p);
}
+#ifdef __x86_64__
+static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd")))
+_rdrand64_step(unsigned long long *__p)
+{
+ return __builtin_ia32_rdrand64_step(__p);
+}
+#endif
+#endif /* __RDRND__ */
+
/* __bit_scan_forward */
static __inline__ int __attribute__((__always_inline__, __nodebug__))
_bit_scan_forward(int __A) {
@@ -220,15 +233,6 @@ _bit_scan_reverse(int __A) {
return 31 - __builtin_clz(__A);
}
-#ifdef __x86_64__
-static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd")))
-_rdrand64_step(unsigned long long *__p)
-{
- return __builtin_ia32_rdrand64_step(__p);
-}
-#endif
-#endif /* __RDRND__ */
-
#if !defined(_MSC_VER) || __has_feature(modules) || defined(__FSGSBASE__)
#ifdef __x86_64__
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__, __target__("fsgsbase")))
diff --git a/contrib/llvm/tools/clang/lib/Headers/intrin.h b/contrib/llvm/tools/clang/lib/Headers/intrin.h
index a35262a..881d05c 100644
--- a/contrib/llvm/tools/clang/lib/Headers/intrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/intrin.h
@@ -69,7 +69,6 @@ static __inline__
__int64 __emul(int, int);
static __inline__
unsigned __int64 __emulu(unsigned int, unsigned int);
-void __cdecl __fastfail(unsigned int);
unsigned int __getcallerseflags(void);
static __inline__
void __halt(void);
@@ -80,16 +79,12 @@ void __incfsdword(unsigned long);
void __incfsword(unsigned long);
unsigned long __indword(unsigned short);
void __indwordstring(unsigned short, unsigned long *, unsigned long);
-void __int2c(void);
void __invlpg(void *);
unsigned short __inword(unsigned short);
void __inwordstring(unsigned short, unsigned short *, unsigned long);
void __lidt(void *);
unsigned __int64 __ll_lshift(unsigned __int64, int);
__int64 __ll_rshift(__int64, int);
-void __llwpcb(void *);
-unsigned char __lwpins32(unsigned int, unsigned int, unsigned int);
-void __lwpval32(unsigned int, unsigned int, unsigned int);
unsigned int __lzcnt(unsigned int);
unsigned short __lzcnt16(unsigned short);
static __inline__
@@ -128,7 +123,6 @@ unsigned __int64 __readmsr(unsigned long);
unsigned __int64 __readpmc(unsigned long);
unsigned long __segmentlimit(unsigned long);
void __sidt(void *);
-void *__slwpcb(void);
static __inline__
void __stosb(unsigned char *, unsigned char, size_t);
static __inline__
@@ -142,7 +136,6 @@ void __svm_stgi(void);
void __svm_vmload(size_t);
void __svm_vmrun(size_t);
void __svm_vmsave(size_t);
-void __ud2(void);
unsigned __int64 __ull_rshift(unsigned __int64, int);
void __vmx_off(void);
void __vmx_vmptrst(unsigned __int64 *);
@@ -176,7 +169,6 @@ void __cdecl _disable(void);
void __cdecl _enable(void);
long _InterlockedAddLargeStatistic(__int64 volatile *_Addend, long _Value);
unsigned char _interlockedbittestandreset(long volatile *, long);
-static __inline__
unsigned char _interlockedbittestandset(long volatile *, long);
long _InterlockedCompareExchange_HLEAcquire(long volatile *, long, long);
long _InterlockedCompareExchange_HLERelease(long volatile *, long, long);
@@ -231,8 +223,6 @@ void __incgsbyte(unsigned long);
void __incgsdword(unsigned long);
void __incgsqword(unsigned long);
void __incgsword(unsigned long);
-unsigned char __lwpins64(unsigned __int64, unsigned int, unsigned int);
-void __lwpval64(unsigned __int64, unsigned int, unsigned int);
unsigned __int64 __lzcnt64(unsigned __int64);
static __inline__
void __movsq(unsigned long long *, unsigned long long const *, size_t);
@@ -372,11 +362,6 @@ _bittestandset(long *_BitBase, long _BitPos) {
*_BitBase = *_BitBase | (1 << _BitPos);
return _Res;
}
-static __inline__ unsigned char __DEFAULT_FN_ATTRS
-_interlockedbittestandset(long volatile *_BitBase, long _BitPos) {
- long _PrevVal = __atomic_fetch_or(_BitBase, 1l << _BitPos, __ATOMIC_SEQ_CST);
- return (_PrevVal >> _BitPos) & 1;
-}
#if defined(__arm__) || defined(__aarch64__)
static __inline__ unsigned char __DEFAULT_FN_ATTRS
_interlockedbittestandset_acq(long volatile *_BitBase, long _BitPos) {
@@ -872,48 +857,7 @@ _InterlockedCompareExchange64_rel(__int64 volatile *_Destination,
return _Comparand;
}
#endif
-/*----------------------------------------------------------------------------*\
-|* readfs, readgs
-|* (Pointers in address space #256 and #257 are relative to the GS and FS
-|* segment registers, respectively.)
-\*----------------------------------------------------------------------------*/
-#define __ptr_to_addr_space(__addr_space_nbr, __type, __offset) \
- ((volatile __type __attribute__((__address_space__(__addr_space_nbr)))*) \
- (__offset))
-#ifdef __i386__
-static __inline__ unsigned char __DEFAULT_FN_ATTRS
-__readfsbyte(unsigned long __offset) {
- return *__ptr_to_addr_space(257, unsigned char, __offset);
-}
-static __inline__ unsigned short __DEFAULT_FN_ATTRS
-__readfsword(unsigned long __offset) {
- return *__ptr_to_addr_space(257, unsigned short, __offset);
-}
-static __inline__ unsigned __int64 __DEFAULT_FN_ATTRS
-__readfsqword(unsigned long __offset) {
- return *__ptr_to_addr_space(257, unsigned __int64, __offset);
-}
-#endif
-#ifdef __x86_64__
-static __inline__ unsigned char __DEFAULT_FN_ATTRS
-__readgsbyte(unsigned long __offset) {
- return *__ptr_to_addr_space(256, unsigned char, __offset);
-}
-static __inline__ unsigned short __DEFAULT_FN_ATTRS
-__readgsword(unsigned long __offset) {
- return *__ptr_to_addr_space(256, unsigned short, __offset);
-}
-static __inline__ unsigned long __DEFAULT_FN_ATTRS
-__readgsdword(unsigned long __offset) {
- return *__ptr_to_addr_space(256, unsigned long, __offset);
-}
-static __inline__ unsigned __int64 __DEFAULT_FN_ATTRS
-__readgsqword(unsigned long __offset) {
- return *__ptr_to_addr_space(256, unsigned __int64, __offset);
-}
-#endif
-#undef __ptr_to_addr_space
/*----------------------------------------------------------------------------*\
|* movs, stos
\*----------------------------------------------------------------------------*/
diff --git a/contrib/llvm/tools/clang/lib/Headers/lwpintrin.h b/contrib/llvm/tools/clang/lib/Headers/lwpintrin.h
new file mode 100644
index 0000000..c95fdd9
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/mmintrin.h b/contrib/llvm/tools/clang/lib/Headers/mmintrin.h
index e0c277a..4b38d51 100644
--- a/contrib/llvm/tools/clang/lib/Headers/mmintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/mmintrin.h
@@ -211,7 +211,7 @@ _mm_packs_pu16(__m64 __m1, __m64 __m2)
/// This intrinsic corresponds to the <c> PUNPCKHBW </c> instruction.
///
/// \param __m1
-/// A 64-bit integer vector of [8 x i8]. \n
+/// A 64-bit integer vector of [8 x i8]. \n
/// Bits [39:32] are written to bits [7:0] of the result. \n
/// Bits [47:40] are written to bits [23:16] of the result. \n
/// Bits [55:48] are written to bits [39:32] of the result. \n
@@ -608,10 +608,11 @@ _mm_subs_pi16(__m64 __m1, __m64 __m2)
/// \brief Subtracts each 8-bit unsigned integer element of the second 64-bit
/// integer vector of [8 x i8] from the corresponding 8-bit unsigned integer
-/// element of the first 64-bit integer vector of [8 x i8]. If an element of
-/// the first vector is less than the corresponding element of the second
-/// vector, the result is saturated to 0. The results are packed into a
-/// 64-bit integer vector of [8 x i8].
+/// element of the first 64-bit integer vector of [8 x i8].
+///
+/// If an element of the first vector is less than the corresponding element
+/// of the second vector, the result is saturated to 0. The results are
+/// packed into a 64-bit integer vector of [8 x i8].
///
/// \headerfile <x86intrin.h>
///
@@ -631,10 +632,11 @@ _mm_subs_pu8(__m64 __m1, __m64 __m2)
/// \brief Subtracts each 16-bit unsigned integer element of the second 64-bit
/// integer vector of [4 x i16] from the corresponding 16-bit unsigned
-/// integer element of the first 64-bit integer vector of [4 x i16]. If an
-/// element of the first vector is less than the corresponding element of the
-/// second vector, the result is saturated to 0. The results are packed into
-/// a 64-bit integer vector of [4 x i16].
+/// integer element of the first 64-bit integer vector of [4 x i16].
+///
+/// If an element of the first vector is less than the corresponding element
+/// of the second vector, the result is saturated to 0. The results are
+/// packed into a 64-bit integer vector of [4 x i16].
///
/// \headerfile <x86intrin.h>
///
@@ -657,9 +659,11 @@ _mm_subs_pu16(__m64 __m1, __m64 __m2)
/// element of the second 64-bit integer vector of [4 x i16] and get four
/// 32-bit products. Adds adjacent pairs of products to get two 32-bit sums.
/// The lower 32 bits of these two sums are packed into a 64-bit integer
-/// vector of [2 x i32]. For example, bits [15:0] of both parameters are
-/// multiplied, bits [31:16] of both parameters are multiplied, and the sum
-/// of both results is written to bits [31:0] of the result.
+/// vector of [2 x i32].
+///
+/// For example, bits [15:0] of both parameters are multiplied, bits [31:16]
+/// of both parameters are multiplied, and the sum of both results is written
+/// to bits [31:0] of the result.
///
/// \headerfile <x86intrin.h>
///
@@ -851,10 +855,11 @@ _mm_slli_si64(__m64 __m, int __count)
/// \brief Right-shifts each 16-bit integer element of the first parameter,
/// which is a 64-bit integer vector of [4 x i16], by the number of bits
-/// specified by the second parameter, which is a 64-bit integer. High-order
-/// bits are filled with the sign bit of the initial value of each 16-bit
-/// element. The 16-bit results are packed into a 64-bit integer vector of
-/// [4 x i16].
+/// specified by the second parameter, which is a 64-bit integer.
+///
+/// High-order bits are filled with the sign bit of the initial value of each
+/// 16-bit element. The 16-bit results are packed into a 64-bit integer
+/// vector of [4 x i16].
///
/// \headerfile <x86intrin.h>
///
@@ -874,6 +879,7 @@ _mm_sra_pi16(__m64 __m, __m64 __count)
/// \brief Right-shifts each 16-bit integer element of a 64-bit integer vector
/// of [4 x i16] by the number of bits specified by a 32-bit integer.
+///
/// High-order bits are filled with the sign bit of the initial value of each
/// 16-bit element. The 16-bit results are packed into a 64-bit integer
/// vector of [4 x i16].
@@ -896,10 +902,11 @@ _mm_srai_pi16(__m64 __m, int __count)
/// \brief Right-shifts each 32-bit integer element of the first parameter,
/// which is a 64-bit integer vector of [2 x i32], by the number of bits
-/// specified by the second parameter, which is a 64-bit integer. High-order
-/// bits are filled with the sign bit of the initial value of each 32-bit
-/// element. The 32-bit results are packed into a 64-bit integer vector of
-/// [2 x i32].
+/// specified by the second parameter, which is a 64-bit integer.
+///
+/// High-order bits are filled with the sign bit of the initial value of each
+/// 32-bit element. The 32-bit results are packed into a 64-bit integer
+/// vector of [2 x i32].
///
/// \headerfile <x86intrin.h>
///
@@ -919,6 +926,7 @@ _mm_sra_pi32(__m64 __m, __m64 __count)
/// \brief Right-shifts each 32-bit integer element of a 64-bit integer vector
/// of [2 x i32] by the number of bits specified by a 32-bit integer.
+///
/// High-order bits are filled with the sign bit of the initial value of each
/// 32-bit element. The 32-bit results are packed into a 64-bit integer
/// vector of [2 x i32].
@@ -941,9 +949,10 @@ _mm_srai_pi32(__m64 __m, int __count)
/// \brief Right-shifts each 16-bit integer element of the first parameter,
/// which is a 64-bit integer vector of [4 x i16], by the number of bits
-/// specified by the second parameter, which is a 64-bit integer. High-order
-/// bits are cleared. The 16-bit results are packed into a 64-bit integer
-/// vector of [4 x i16].
+/// specified by the second parameter, which is a 64-bit integer.
+///
+/// High-order bits are cleared. The 16-bit results are packed into a 64-bit
+/// integer vector of [4 x i16].
///
/// \headerfile <x86intrin.h>
///
@@ -963,6 +972,7 @@ _mm_srl_pi16(__m64 __m, __m64 __count)
/// \brief Right-shifts each 16-bit integer element of a 64-bit integer vector
/// of [4 x i16] by the number of bits specified by a 32-bit integer.
+///
/// High-order bits are cleared. The 16-bit results are packed into a 64-bit
/// integer vector of [4 x i16].
///
@@ -984,9 +994,10 @@ _mm_srli_pi16(__m64 __m, int __count)
/// \brief Right-shifts each 32-bit integer element of the first parameter,
/// which is a 64-bit integer vector of [2 x i32], by the number of bits
-/// specified by the second parameter, which is a 64-bit integer. High-order
-/// bits are cleared. The 32-bit results are packed into a 64-bit integer
-/// vector of [2 x i32].
+/// specified by the second parameter, which is a 64-bit integer.
+///
+/// High-order bits are cleared. The 32-bit results are packed into a 64-bit
+/// integer vector of [2 x i32].
///
/// \headerfile <x86intrin.h>
///
@@ -1006,6 +1017,7 @@ _mm_srl_pi32(__m64 __m, __m64 __count)
/// \brief Right-shifts each 32-bit integer element of a 64-bit integer vector
/// of [2 x i32] by the number of bits specified by a 32-bit integer.
+///
/// High-order bits are cleared. The 32-bit results are packed into a 64-bit
/// integer vector of [2 x i32].
///
@@ -1026,8 +1038,9 @@ _mm_srli_pi32(__m64 __m, int __count)
}
/// \brief Right-shifts the first 64-bit integer parameter by the number of bits
-/// specified by the second 64-bit integer parameter. High-order bits are
-/// cleared.
+/// specified by the second 64-bit integer parameter.
+///
+/// High-order bits are cleared.
///
/// \headerfile <x86intrin.h>
///
@@ -1046,7 +1059,9 @@ _mm_srl_si64(__m64 __m, __m64 __count)
/// \brief Right-shifts the first parameter, which is a 64-bit integer, by the
/// number of bits specified by the second parameter, which is a 32-bit
-/// integer. High-order bits are cleared.
+/// integer.
+///
+/// High-order bits are cleared.
///
/// \headerfile <x86intrin.h>
///
@@ -1140,8 +1155,9 @@ _mm_xor_si64(__m64 __m1, __m64 __m2)
/// \brief Compares the 8-bit integer elements of two 64-bit integer vectors of
/// [8 x i8] to determine if the element of the first vector is equal to the
-/// corresponding element of the second vector. The comparison yields 0 for
-/// false, 0xFF for true.
+/// corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1161,8 +1177,9 @@ _mm_cmpeq_pi8(__m64 __m1, __m64 __m2)
/// \brief Compares the 16-bit integer elements of two 64-bit integer vectors of
/// [4 x i16] to determine if the element of the first vector is equal to the
-/// corresponding element of the second vector. The comparison yields 0 for
-/// false, 0xFFFF for true.
+/// corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFFFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1182,8 +1199,9 @@ _mm_cmpeq_pi16(__m64 __m1, __m64 __m2)
/// \brief Compares the 32-bit integer elements of two 64-bit integer vectors of
/// [2 x i32] to determine if the element of the first vector is equal to the
-/// corresponding element of the second vector. The comparison yields 0 for
-/// false, 0xFFFFFFFF for true.
+/// corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFFFFFFFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1203,8 +1221,9 @@ _mm_cmpeq_pi32(__m64 __m1, __m64 __m2)
/// \brief Compares the 8-bit integer elements of two 64-bit integer vectors of
/// [8 x i8] to determine if the element of the first vector is greater than
-/// the corresponding element of the second vector. The comparison yields 0
-/// for false, 0xFF for true.
+/// the corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1224,8 +1243,9 @@ _mm_cmpgt_pi8(__m64 __m1, __m64 __m2)
/// \brief Compares the 16-bit integer elements of two 64-bit integer vectors of
/// [4 x i16] to determine if the element of the first vector is greater than
-/// the corresponding element of the second vector. The comparison yields 0
-/// for false, 0xFFFF for true.
+/// the corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFFFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1245,8 +1265,9 @@ _mm_cmpgt_pi16(__m64 __m1, __m64 __m2)
/// \brief Compares the 32-bit integer elements of two 64-bit integer vectors of
/// [2 x i32] to determine if the element of the first vector is greater than
-/// the corresponding element of the second vector. The comparison yields 0
-/// for false, 0xFFFFFFFF for true.
+/// the corresponding element of the second vector.
+///
+/// The comparison yields 0 for false, 0xFFFFFFFF for true.
///
/// \headerfile <x86intrin.h>
///
@@ -1268,7 +1289,7 @@ _mm_cmpgt_pi32(__m64 __m1, __m64 __m2)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the the <c> VXORPS / XORPS </c> instruction.
+/// This intrinsic corresponds to the <c> VXORPS / XORPS </c> instruction.
///
/// \returns An initialized 64-bit integer vector with all elements set to zero.
static __inline__ __m64 __DEFAULT_FN_ATTRS
diff --git a/contrib/llvm/tools/clang/lib/Headers/module.modulemap b/contrib/llvm/tools/clang/lib/Headers/module.modulemap
index 11ef2f9..95d26ce 100644
--- a/contrib/llvm/tools/clang/lib/Headers/module.modulemap
+++ b/contrib/llvm/tools/clang/lib/Headers/module.modulemap
@@ -61,6 +61,7 @@ module _Builtin_intrinsics [system] [extern_c] {
textual header "xopintrin.h"
textual header "fma4intrin.h"
textual header "mwaitxintrin.h"
+ textual header "clzerointrin.h"
explicit module mm_malloc {
requires !freestanding
diff --git a/contrib/llvm/tools/clang/lib/Headers/opencl-c.h b/contrib/llvm/tools/clang/lib/Headers/opencl-c.h
index 0c25d312..58c8daf 100644
--- a/contrib/llvm/tools/clang/lib/Headers/opencl-c.h
+++ b/contrib/llvm/tools/clang/lib/Headers/opencl-c.h
@@ -16,6 +16,12 @@
#endif //cl_khr_depth_images
#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if __OPENCL_C_VERSION__ < CL_VERSION_2_0
+#ifdef cl_khr_3d_image_writes
+#pragma OPENCL EXTENSION cl_khr_3d_image_writes : enable
+#endif //cl_khr_3d_image_writes
+#endif //__OPENCL_C_VERSION__ < CL_VERSION_2_0
+
#define __ovld __attribute__((overloadable))
#define __conv __attribute__((convergent))
@@ -6578,777 +6584,85 @@ half16 __ovld __cnfn convert_half16_rtz(double16);
* OpenCL v1.1/1.2/2.0 s6.2.4.2 - as_type operators
* Reinterprets a data type as another data type of the same size
*/
-char __ovld __cnfn as_char(char);
-char __ovld __cnfn as_char(uchar);
-
-char2 __ovld __cnfn as_char2(char2);
-char2 __ovld __cnfn as_char2(uchar2);
-char2 __ovld __cnfn as_char2(short);
-char2 __ovld __cnfn as_char2(ushort);
-
-char3 __ovld __cnfn as_char3(char3);
-char3 __ovld __cnfn as_char3(char4);
-char3 __ovld __cnfn as_char3(uchar3);
-char3 __ovld __cnfn as_char3(uchar4);
-char3 __ovld __cnfn as_char3(short2);
-char3 __ovld __cnfn as_char3(ushort2);
-char3 __ovld __cnfn as_char3(int);
-char3 __ovld __cnfn as_char3(uint);
-char3 __ovld __cnfn as_char3(float);
-
-char4 __ovld __cnfn as_char4(char3);
-char4 __ovld __cnfn as_char4(char4);
-char4 __ovld __cnfn as_char4(uchar3);
-char4 __ovld __cnfn as_char4(uchar4);
-char4 __ovld __cnfn as_char4(short2);
-char4 __ovld __cnfn as_char4(ushort2);
-char4 __ovld __cnfn as_char4(int);
-char4 __ovld __cnfn as_char4(uint);
-char4 __ovld __cnfn as_char4(float);
-
-char8 __ovld __cnfn as_char8(char8);
-char8 __ovld __cnfn as_char8(uchar8);
-char8 __ovld __cnfn as_char8(short3);
-char8 __ovld __cnfn as_char8(short4);
-char8 __ovld __cnfn as_char8(ushort3);
-char8 __ovld __cnfn as_char8(ushort4);
-char8 __ovld __cnfn as_char8(int2);
-char8 __ovld __cnfn as_char8(uint2);
-char8 __ovld __cnfn as_char8(long);
-char8 __ovld __cnfn as_char8(ulong);
-char8 __ovld __cnfn as_char8(float2);
-
-char16 __ovld __cnfn as_char16(char16);
-char16 __ovld __cnfn as_char16(uchar16);
-char16 __ovld __cnfn as_char16(short8);
-char16 __ovld __cnfn as_char16(ushort8);
-char16 __ovld __cnfn as_char16(int3);
-char16 __ovld __cnfn as_char16(int4);
-char16 __ovld __cnfn as_char16(uint3);
-char16 __ovld __cnfn as_char16(uint4);
-char16 __ovld __cnfn as_char16(long2);
-char16 __ovld __cnfn as_char16(ulong2);
-char16 __ovld __cnfn as_char16(float3);
-char16 __ovld __cnfn as_char16(float4);
-
-uchar __ovld __cnfn as_uchar(char);
-uchar __ovld __cnfn as_uchar(uchar);
-
-uchar2 __ovld __cnfn as_uchar2(char2);
-uchar2 __ovld __cnfn as_uchar2(uchar2);
-uchar2 __ovld __cnfn as_uchar2(short);
-uchar2 __ovld __cnfn as_uchar2(ushort);
-
-uchar3 __ovld __cnfn as_uchar3(char3);
-uchar3 __ovld __cnfn as_uchar3(char4);
-uchar3 __ovld __cnfn as_uchar3(uchar3);
-uchar3 __ovld __cnfn as_uchar3(uchar4);
-uchar3 __ovld __cnfn as_uchar3(short2);
-uchar3 __ovld __cnfn as_uchar3(ushort2);
-uchar3 __ovld __cnfn as_uchar3(int);
-uchar3 __ovld __cnfn as_uchar3(uint);
-uchar3 __ovld __cnfn as_uchar3(float);
-
-uchar4 __ovld __cnfn as_uchar4(char3);
-uchar4 __ovld __cnfn as_uchar4(char4);
-uchar4 __ovld __cnfn as_uchar4(uchar3);
-uchar4 __ovld __cnfn as_uchar4(uchar4);
-uchar4 __ovld __cnfn as_uchar4(short2);
-uchar4 __ovld __cnfn as_uchar4(ushort2);
-uchar4 __ovld __cnfn as_uchar4(int);
-uchar4 __ovld __cnfn as_uchar4(uint);
-uchar4 __ovld __cnfn as_uchar4(float);
-
-uchar8 __ovld __cnfn as_uchar8(char8);
-uchar8 __ovld __cnfn as_uchar8(uchar8);
-uchar8 __ovld __cnfn as_uchar8(short3);
-uchar8 __ovld __cnfn as_uchar8(short4);
-uchar8 __ovld __cnfn as_uchar8(ushort3);
-uchar8 __ovld __cnfn as_uchar8(ushort4);
-uchar8 __ovld __cnfn as_uchar8(int2);
-uchar8 __ovld __cnfn as_uchar8(uint2);
-uchar8 __ovld __cnfn as_uchar8(long);
-uchar8 __ovld __cnfn as_uchar8(ulong);
-uchar8 __ovld __cnfn as_uchar8(float2);
-
-uchar16 __ovld __cnfn as_uchar16(char16);
-uchar16 __ovld __cnfn as_uchar16(uchar16);
-uchar16 __ovld __cnfn as_uchar16(short8);
-uchar16 __ovld __cnfn as_uchar16(ushort8);
-uchar16 __ovld __cnfn as_uchar16(int3);
-uchar16 __ovld __cnfn as_uchar16(int4);
-uchar16 __ovld __cnfn as_uchar16(uint3);
-uchar16 __ovld __cnfn as_uchar16(uint4);
-uchar16 __ovld __cnfn as_uchar16(long2);
-uchar16 __ovld __cnfn as_uchar16(ulong2);
-uchar16 __ovld __cnfn as_uchar16(float3);
-uchar16 __ovld __cnfn as_uchar16(float4);
-
-short __ovld __cnfn as_short(char2);
-short __ovld __cnfn as_short(uchar2);
-short __ovld __cnfn as_short(short);
-short __ovld __cnfn as_short(ushort);
-
-short2 __ovld __cnfn as_short2(char3);
-short2 __ovld __cnfn as_short2(char4);
-short2 __ovld __cnfn as_short2(uchar3);
-short2 __ovld __cnfn as_short2(uchar4);
-short2 __ovld __cnfn as_short2(short2);
-short2 __ovld __cnfn as_short2(ushort2);
-short2 __ovld __cnfn as_short2(int);
-short2 __ovld __cnfn as_short2(uint);
-short2 __ovld __cnfn as_short2(float);
-
-short3 __ovld __cnfn as_short3(char8);
-short3 __ovld __cnfn as_short3(uchar8);
-short3 __ovld __cnfn as_short3(short3);
-short3 __ovld __cnfn as_short3(short4);
-short3 __ovld __cnfn as_short3(ushort3);
-short3 __ovld __cnfn as_short3(ushort4);
-short3 __ovld __cnfn as_short3(int2);
-short3 __ovld __cnfn as_short3(uint2);
-short3 __ovld __cnfn as_short3(long);
-short3 __ovld __cnfn as_short3(ulong);
-short3 __ovld __cnfn as_short3(float2);
-
-short4 __ovld __cnfn as_short4(char8);
-short4 __ovld __cnfn as_short4(uchar8);
-short4 __ovld __cnfn as_short4(short3);
-short4 __ovld __cnfn as_short4(short4);
-short4 __ovld __cnfn as_short4(ushort3);
-short4 __ovld __cnfn as_short4(ushort4);
-short4 __ovld __cnfn as_short4(int2);
-short4 __ovld __cnfn as_short4(uint2);
-short4 __ovld __cnfn as_short4(long);
-short4 __ovld __cnfn as_short4(ulong);
-short4 __ovld __cnfn as_short4(float2);
-
-short8 __ovld __cnfn as_short8(char16);
-short8 __ovld __cnfn as_short8(uchar16);
-short8 __ovld __cnfn as_short8(short8);
-short8 __ovld __cnfn as_short8(ushort8);
-short8 __ovld __cnfn as_short8(int3);
-short8 __ovld __cnfn as_short8(int4);
-short8 __ovld __cnfn as_short8(uint3);
-short8 __ovld __cnfn as_short8(uint4);
-short8 __ovld __cnfn as_short8(long2);
-short8 __ovld __cnfn as_short8(ulong2);
-short8 __ovld __cnfn as_short8(float3);
-short8 __ovld __cnfn as_short8(float4);
-
-short16 __ovld __cnfn as_short16(short16);
-short16 __ovld __cnfn as_short16(ushort16);
-short16 __ovld __cnfn as_short16(int8);
-short16 __ovld __cnfn as_short16(uint8);
-short16 __ovld __cnfn as_short16(long3);
-short16 __ovld __cnfn as_short16(long4);
-short16 __ovld __cnfn as_short16(ulong3);
-short16 __ovld __cnfn as_short16(ulong4);
-short16 __ovld __cnfn as_short16(float8);
-
-ushort __ovld __cnfn as_ushort(char2);
-ushort __ovld __cnfn as_ushort(uchar2);
-ushort __ovld __cnfn as_ushort(short);
-ushort __ovld __cnfn as_ushort(ushort);
-
-ushort2 __ovld __cnfn as_ushort2(char3);
-ushort2 __ovld __cnfn as_ushort2(char4);
-ushort2 __ovld __cnfn as_ushort2(uchar3);
-ushort2 __ovld __cnfn as_ushort2(uchar4);
-ushort2 __ovld __cnfn as_ushort2(short2);
-ushort2 __ovld __cnfn as_ushort2(ushort2);
-ushort2 __ovld __cnfn as_ushort2(int);
-ushort2 __ovld __cnfn as_ushort2(uint);
-ushort2 __ovld __cnfn as_ushort2(float);
-
-ushort3 __ovld __cnfn as_ushort3(char8);
-ushort3 __ovld __cnfn as_ushort3(uchar8);
-ushort3 __ovld __cnfn as_ushort3(short3);
-ushort3 __ovld __cnfn as_ushort3(short4);
-ushort3 __ovld __cnfn as_ushort3(ushort3);
-ushort3 __ovld __cnfn as_ushort3(ushort4);
-ushort3 __ovld __cnfn as_ushort3(int2);
-ushort3 __ovld __cnfn as_ushort3(uint2);
-ushort3 __ovld __cnfn as_ushort3(long);
-ushort3 __ovld __cnfn as_ushort3(ulong);
-ushort3 __ovld __cnfn as_ushort3(float2);
-
-ushort4 __ovld __cnfn as_ushort4(char8);
-ushort4 __ovld __cnfn as_ushort4(uchar8);
-ushort4 __ovld __cnfn as_ushort4(short3);
-ushort4 __ovld __cnfn as_ushort4(short4);
-ushort4 __ovld __cnfn as_ushort4(ushort3);
-ushort4 __ovld __cnfn as_ushort4(ushort4);
-ushort4 __ovld __cnfn as_ushort4(int2);
-ushort4 __ovld __cnfn as_ushort4(uint2);
-ushort4 __ovld __cnfn as_ushort4(long);
-ushort4 __ovld __cnfn as_ushort4(ulong);
-ushort4 __ovld __cnfn as_ushort4(float2);
-
-ushort8 __ovld __cnfn as_ushort8(char16);
-ushort8 __ovld __cnfn as_ushort8(uchar16);
-ushort8 __ovld __cnfn as_ushort8(short8);
-ushort8 __ovld __cnfn as_ushort8(ushort8);
-ushort8 __ovld __cnfn as_ushort8(int3);
-ushort8 __ovld __cnfn as_ushort8(int4);
-ushort8 __ovld __cnfn as_ushort8(uint3);
-ushort8 __ovld __cnfn as_ushort8(uint4);
-ushort8 __ovld __cnfn as_ushort8(long2);
-ushort8 __ovld __cnfn as_ushort8(ulong2);
-ushort8 __ovld __cnfn as_ushort8(float3);
-ushort8 __ovld __cnfn as_ushort8(float4);
-
-ushort16 __ovld __cnfn as_ushort16(short16);
-ushort16 __ovld __cnfn as_ushort16(ushort16);
-ushort16 __ovld __cnfn as_ushort16(int8);
-ushort16 __ovld __cnfn as_ushort16(uint8);
-ushort16 __ovld __cnfn as_ushort16(long3);
-ushort16 __ovld __cnfn as_ushort16(long4);
-ushort16 __ovld __cnfn as_ushort16(ulong3);
-ushort16 __ovld __cnfn as_ushort16(ulong4);
-ushort16 __ovld __cnfn as_ushort16(float8);
-
-int __ovld __cnfn as_int(char3);
-int __ovld __cnfn as_int(char4);
-int __ovld __cnfn as_int(uchar3);
-int __ovld __cnfn as_int(uchar4);
-int __ovld __cnfn as_int(short2);
-int __ovld __cnfn as_int(ushort2);
-int __ovld __cnfn as_int(int);
-int __ovld __cnfn as_int(uint);
-int __ovld __cnfn as_int(float);
-
-int2 __ovld __cnfn as_int2(char8);
-int2 __ovld __cnfn as_int2(uchar8);
-int2 __ovld __cnfn as_int2(short3);
-int2 __ovld __cnfn as_int2(short4);
-int2 __ovld __cnfn as_int2(ushort3);
-int2 __ovld __cnfn as_int2(ushort4);
-int2 __ovld __cnfn as_int2(int2);
-int2 __ovld __cnfn as_int2(uint2);
-int2 __ovld __cnfn as_int2(long);
-int2 __ovld __cnfn as_int2(ulong);
-int2 __ovld __cnfn as_int2(float2);
-
-int3 __ovld __cnfn as_int3(char16);
-int3 __ovld __cnfn as_int3(uchar16);
-int3 __ovld __cnfn as_int3(short8);
-int3 __ovld __cnfn as_int3(ushort8);
-int3 __ovld __cnfn as_int3(int3);
-int3 __ovld __cnfn as_int3(int4);
-int3 __ovld __cnfn as_int3(uint3);
-int3 __ovld __cnfn as_int3(uint4);
-int3 __ovld __cnfn as_int3(long2);
-int3 __ovld __cnfn as_int3(ulong2);
-int3 __ovld __cnfn as_int3(float3);
-int3 __ovld __cnfn as_int3(float4);
-
-int4 __ovld __cnfn as_int4(char16);
-int4 __ovld __cnfn as_int4(uchar16);
-int4 __ovld __cnfn as_int4(short8);
-int4 __ovld __cnfn as_int4(ushort8);
-int4 __ovld __cnfn as_int4(int3);
-int4 __ovld __cnfn as_int4(int4);
-int4 __ovld __cnfn as_int4(uint3);
-int4 __ovld __cnfn as_int4(uint4);
-int4 __ovld __cnfn as_int4(long2);
-int4 __ovld __cnfn as_int4(ulong2);
-int4 __ovld __cnfn as_int4(float3);
-int4 __ovld __cnfn as_int4(float4);
-
-int8 __ovld __cnfn as_int8(short16);
-int8 __ovld __cnfn as_int8(ushort16);
-int8 __ovld __cnfn as_int8(int8);
-int8 __ovld __cnfn as_int8(uint8);
-int8 __ovld __cnfn as_int8(long3);
-int8 __ovld __cnfn as_int8(long4);
-int8 __ovld __cnfn as_int8(ulong3);
-int8 __ovld __cnfn as_int8(ulong4);
-int8 __ovld __cnfn as_int8(float8);
-
-int16 __ovld __cnfn as_int16(int16);
-int16 __ovld __cnfn as_int16(uint16);
-int16 __ovld __cnfn as_int16(long8);
-int16 __ovld __cnfn as_int16(ulong8);
-int16 __ovld __cnfn as_int16(float16);
-
-uint __ovld __cnfn as_uint(char3);
-uint __ovld __cnfn as_uint(char4);
-uint __ovld __cnfn as_uint(uchar3);
-uint __ovld __cnfn as_uint(uchar4);
-uint __ovld __cnfn as_uint(short2);
-uint __ovld __cnfn as_uint(ushort2);
-uint __ovld __cnfn as_uint(int);
-uint __ovld __cnfn as_uint(uint);
-uint __ovld __cnfn as_uint(float);
-
-uint2 __ovld __cnfn as_uint2(char8);
-uint2 __ovld __cnfn as_uint2(uchar8);
-uint2 __ovld __cnfn as_uint2(short3);
-uint2 __ovld __cnfn as_uint2(short4);
-uint2 __ovld __cnfn as_uint2(ushort3);
-uint2 __ovld __cnfn as_uint2(ushort4);
-uint2 __ovld __cnfn as_uint2(int2);
-uint2 __ovld __cnfn as_uint2(uint2);
-uint2 __ovld __cnfn as_uint2(long);
-uint2 __ovld __cnfn as_uint2(ulong);
-uint2 __ovld __cnfn as_uint2(float2);
-
-uint3 __ovld __cnfn as_uint3(char16);
-uint3 __ovld __cnfn as_uint3(uchar16);
-uint3 __ovld __cnfn as_uint3(short8);
-uint3 __ovld __cnfn as_uint3(ushort8);
-uint3 __ovld __cnfn as_uint3(int3);
-uint3 __ovld __cnfn as_uint3(int4);
-uint3 __ovld __cnfn as_uint3(uint3);
-uint3 __ovld __cnfn as_uint3(uint4);
-uint3 __ovld __cnfn as_uint3(long2);
-uint3 __ovld __cnfn as_uint3(ulong2);
-uint3 __ovld __cnfn as_uint3(float3);
-uint3 __ovld __cnfn as_uint3(float4);
-
-uint4 __ovld __cnfn as_uint4(char16);
-uint4 __ovld __cnfn as_uint4(uchar16);
-uint4 __ovld __cnfn as_uint4(short8);
-uint4 __ovld __cnfn as_uint4(ushort8);
-uint4 __ovld __cnfn as_uint4(int3);
-uint4 __ovld __cnfn as_uint4(int4);
-uint4 __ovld __cnfn as_uint4(uint3);
-uint4 __ovld __cnfn as_uint4(uint4);
-uint4 __ovld __cnfn as_uint4(long2);
-uint4 __ovld __cnfn as_uint4(ulong2);
-uint4 __ovld __cnfn as_uint4(float3);
-uint4 __ovld __cnfn as_uint4(float4);
-
-uint8 __ovld __cnfn as_uint8(short16);
-uint8 __ovld __cnfn as_uint8(ushort16);
-uint8 __ovld __cnfn as_uint8(int8);
-uint8 __ovld __cnfn as_uint8(uint8);
-uint8 __ovld __cnfn as_uint8(long3);
-uint8 __ovld __cnfn as_uint8(long4);
-uint8 __ovld __cnfn as_uint8(ulong3);
-uint8 __ovld __cnfn as_uint8(ulong4);
-uint8 __ovld __cnfn as_uint8(float8);
-
-uint16 __ovld __cnfn as_uint16(int16);
-uint16 __ovld __cnfn as_uint16(uint16);
-uint16 __ovld __cnfn as_uint16(long8);
-uint16 __ovld __cnfn as_uint16(ulong8);
-uint16 __ovld __cnfn as_uint16(float16);
-
-long __ovld __cnfn as_long(char8);
-long __ovld __cnfn as_long(uchar8);
-long __ovld __cnfn as_long(short3);
-long __ovld __cnfn as_long(short4);
-long __ovld __cnfn as_long(ushort3);
-long __ovld __cnfn as_long(ushort4);
-long __ovld __cnfn as_long(int2);
-long __ovld __cnfn as_long(uint2);
-long __ovld __cnfn as_long(long);
-long __ovld __cnfn as_long(ulong);
-long __ovld __cnfn as_long(float2);
-
-long2 __ovld __cnfn as_long2(char16);
-long2 __ovld __cnfn as_long2(uchar16);
-long2 __ovld __cnfn as_long2(short8);
-long2 __ovld __cnfn as_long2(ushort8);
-long2 __ovld __cnfn as_long2(int3);
-long2 __ovld __cnfn as_long2(int4);
-long2 __ovld __cnfn as_long2(uint3);
-long2 __ovld __cnfn as_long2(uint4);
-long2 __ovld __cnfn as_long2(long2);
-long2 __ovld __cnfn as_long2(ulong2);
-long2 __ovld __cnfn as_long2(float3);
-long2 __ovld __cnfn as_long2(float4);
-
-long3 __ovld __cnfn as_long3(short16);
-long3 __ovld __cnfn as_long3(ushort16);
-long3 __ovld __cnfn as_long3(int8);
-long3 __ovld __cnfn as_long3(uint8);
-long3 __ovld __cnfn as_long3(long3);
-long3 __ovld __cnfn as_long3(long4);
-long3 __ovld __cnfn as_long3(ulong3);
-long3 __ovld __cnfn as_long3(ulong4);
-long3 __ovld __cnfn as_long3(float8);
-
-long4 __ovld __cnfn as_long4(short16);
-long4 __ovld __cnfn as_long4(ushort16);
-long4 __ovld __cnfn as_long4(int8);
-long4 __ovld __cnfn as_long4(uint8);
-long4 __ovld __cnfn as_long4(long3);
-long4 __ovld __cnfn as_long4(long4);
-long4 __ovld __cnfn as_long4(ulong3);
-long4 __ovld __cnfn as_long4(ulong4);
-long4 __ovld __cnfn as_long4(float8);
-
-long8 __ovld __cnfn as_long8(int16);
-long8 __ovld __cnfn as_long8(uint16);
-long8 __ovld __cnfn as_long8(long8);
-long8 __ovld __cnfn as_long8(ulong8);
-long8 __ovld __cnfn as_long8(float16);
-
-long16 __ovld __cnfn as_long16(long16);
-long16 __ovld __cnfn as_long16(ulong16);
-
-ulong __ovld __cnfn as_ulong(char8);
-ulong __ovld __cnfn as_ulong(uchar8);
-ulong __ovld __cnfn as_ulong(short3);
-ulong __ovld __cnfn as_ulong(short4);
-ulong __ovld __cnfn as_ulong(ushort3);
-ulong __ovld __cnfn as_ulong(ushort4);
-ulong __ovld __cnfn as_ulong(int2);
-ulong __ovld __cnfn as_ulong(uint2);
-ulong __ovld __cnfn as_ulong(long);
-ulong __ovld __cnfn as_ulong(ulong);
-ulong __ovld __cnfn as_ulong(float2);
-
-ulong2 __ovld __cnfn as_ulong2(char16);
-ulong2 __ovld __cnfn as_ulong2(uchar16);
-ulong2 __ovld __cnfn as_ulong2(short8);
-ulong2 __ovld __cnfn as_ulong2(ushort8);
-ulong2 __ovld __cnfn as_ulong2(int3);
-ulong2 __ovld __cnfn as_ulong2(int4);
-ulong2 __ovld __cnfn as_ulong2(uint3);
-ulong2 __ovld __cnfn as_ulong2(uint4);
-ulong2 __ovld __cnfn as_ulong2(long2);
-ulong2 __ovld __cnfn as_ulong2(ulong2);
-ulong2 __ovld __cnfn as_ulong2(float3);
-ulong2 __ovld __cnfn as_ulong2(float4);
-
-ulong3 __ovld __cnfn as_ulong3(short16);
-ulong3 __ovld __cnfn as_ulong3(ushort16);
-ulong3 __ovld __cnfn as_ulong3(int8);
-ulong3 __ovld __cnfn as_ulong3(uint8);
-ulong3 __ovld __cnfn as_ulong3(long3);
-ulong3 __ovld __cnfn as_ulong3(long4);
-ulong3 __ovld __cnfn as_ulong3(ulong3);
-ulong3 __ovld __cnfn as_ulong3(ulong4);
-ulong3 __ovld __cnfn as_ulong3(float8);
-
-ulong4 __ovld __cnfn as_ulong4(short16);
-ulong4 __ovld __cnfn as_ulong4(ushort16);
-ulong4 __ovld __cnfn as_ulong4(int8);
-ulong4 __ovld __cnfn as_ulong4(uint8);
-ulong4 __ovld __cnfn as_ulong4(long3);
-ulong4 __ovld __cnfn as_ulong4(long4);
-ulong4 __ovld __cnfn as_ulong4(ulong3);
-ulong4 __ovld __cnfn as_ulong4(ulong4);
-ulong4 __ovld __cnfn as_ulong4(float8);
-
-ulong8 __ovld __cnfn as_ulong8(int16);
-ulong8 __ovld __cnfn as_ulong8(uint16);
-ulong8 __ovld __cnfn as_ulong8(long8);
-ulong8 __ovld __cnfn as_ulong8(ulong8);
-ulong8 __ovld __cnfn as_ulong8(float16);
-
-ulong16 __ovld __cnfn as_ulong16(long16);
-ulong16 __ovld __cnfn as_ulong16(ulong16);
-
-float __ovld __cnfn as_float(char3);
-float __ovld __cnfn as_float(char4);
-float __ovld __cnfn as_float(uchar3);
-float __ovld __cnfn as_float(uchar4);
-float __ovld __cnfn as_float(short2);
-float __ovld __cnfn as_float(ushort2);
-float __ovld __cnfn as_float(int);
-float __ovld __cnfn as_float(uint);
-float __ovld __cnfn as_float(float);
-
-float2 __ovld __cnfn as_float2(char8);
-float2 __ovld __cnfn as_float2(uchar8);
-float2 __ovld __cnfn as_float2(short3);
-float2 __ovld __cnfn as_float2(short4);
-float2 __ovld __cnfn as_float2(ushort3);
-float2 __ovld __cnfn as_float2(ushort4);
-float2 __ovld __cnfn as_float2(int2);
-float2 __ovld __cnfn as_float2(uint2);
-float2 __ovld __cnfn as_float2(long);
-float2 __ovld __cnfn as_float2(ulong);
-float2 __ovld __cnfn as_float2(float2);
-
-float3 __ovld __cnfn as_float3(char16);
-float3 __ovld __cnfn as_float3(uchar16);
-float3 __ovld __cnfn as_float3(short8);
-float3 __ovld __cnfn as_float3(ushort8);
-float3 __ovld __cnfn as_float3(int3);
-float3 __ovld __cnfn as_float3(int4);
-float3 __ovld __cnfn as_float3(uint3);
-float3 __ovld __cnfn as_float3(uint4);
-float3 __ovld __cnfn as_float3(long2);
-float3 __ovld __cnfn as_float3(ulong2);
-float3 __ovld __cnfn as_float3(float3);
-float3 __ovld __cnfn as_float3(float4);
-
-float4 __ovld __cnfn as_float4(char16);
-float4 __ovld __cnfn as_float4(uchar16);
-float4 __ovld __cnfn as_float4(short8);
-float4 __ovld __cnfn as_float4(ushort8);
-float4 __ovld __cnfn as_float4(int3);
-float4 __ovld __cnfn as_float4(int4);
-float4 __ovld __cnfn as_float4(uint3);
-float4 __ovld __cnfn as_float4(uint4);
-float4 __ovld __cnfn as_float4(long2);
-float4 __ovld __cnfn as_float4(ulong2);
-float4 __ovld __cnfn as_float4(float3);
-float4 __ovld __cnfn as_float4(float4);
-
-float8 __ovld __cnfn as_float8(short16);
-float8 __ovld __cnfn as_float8(ushort16);
-float8 __ovld __cnfn as_float8(int8);
-float8 __ovld __cnfn as_float8(uint8);
-float8 __ovld __cnfn as_float8(long3);
-float8 __ovld __cnfn as_float8(long4);
-float8 __ovld __cnfn as_float8(ulong3);
-float8 __ovld __cnfn as_float8(ulong4);
-float8 __ovld __cnfn as_float8(float8);
-
-float16 __ovld __cnfn as_float16(int16);
-float16 __ovld __cnfn as_float16(uint16);
-float16 __ovld __cnfn as_float16(long8);
-float16 __ovld __cnfn as_float16(ulong8);
-float16 __ovld __cnfn as_float16(float16);
+#define as_char(x) __builtin_astype((x), char)
+#define as_char2(x) __builtin_astype((x), char2)
+#define as_char3(x) __builtin_astype((x), char3)
+#define as_char4(x) __builtin_astype((x), char4)
+#define as_char8(x) __builtin_astype((x), char8)
+#define as_char16(x) __builtin_astype((x), char16)
+
+#define as_uchar(x) __builtin_astype((x), uchar)
+#define as_uchar2(x) __builtin_astype((x), uchar2)
+#define as_uchar3(x) __builtin_astype((x), uchar3)
+#define as_uchar4(x) __builtin_astype((x), uchar4)
+#define as_uchar8(x) __builtin_astype((x), uchar8)
+#define as_uchar16(x) __builtin_astype((x), uchar16)
+
+#define as_short(x) __builtin_astype((x), short)
+#define as_short2(x) __builtin_astype((x), short2)
+#define as_short3(x) __builtin_astype((x), short3)
+#define as_short4(x) __builtin_astype((x), short4)
+#define as_short8(x) __builtin_astype((x), short8)
+#define as_short16(x) __builtin_astype((x), short16)
+
+#define as_ushort(x) __builtin_astype((x), ushort)
+#define as_ushort2(x) __builtin_astype((x), ushort2)
+#define as_ushort3(x) __builtin_astype((x), ushort3)
+#define as_ushort4(x) __builtin_astype((x), ushort4)
+#define as_ushort8(x) __builtin_astype((x), ushort8)
+#define as_ushort16(x) __builtin_astype((x), ushort16)
+
+#define as_int(x) __builtin_astype((x), int)
+#define as_int2(x) __builtin_astype((x), int2)
+#define as_int3(x) __builtin_astype((x), int3)
+#define as_int4(x) __builtin_astype((x), int4)
+#define as_int8(x) __builtin_astype((x), int8)
+#define as_int16(x) __builtin_astype((x), int16)
+
+#define as_uint(x) __builtin_astype((x), uint)
+#define as_uint2(x) __builtin_astype((x), uint2)
+#define as_uint3(x) __builtin_astype((x), uint3)
+#define as_uint4(x) __builtin_astype((x), uint4)
+#define as_uint8(x) __builtin_astype((x), uint8)
+#define as_uint16(x) __builtin_astype((x), uint16)
+
+#define as_long(x) __builtin_astype((x), long)
+#define as_long2(x) __builtin_astype((x), long2)
+#define as_long3(x) __builtin_astype((x), long3)
+#define as_long4(x) __builtin_astype((x), long4)
+#define as_long8(x) __builtin_astype((x), long8)
+#define as_long16(x) __builtin_astype((x), long16)
+
+#define as_ulong(x) __builtin_astype((x), ulong)
+#define as_ulong2(x) __builtin_astype((x), ulong2)
+#define as_ulong3(x) __builtin_astype((x), ulong3)
+#define as_ulong4(x) __builtin_astype((x), ulong4)
+#define as_ulong8(x) __builtin_astype((x), ulong8)
+#define as_ulong16(x) __builtin_astype((x), ulong16)
+
+#define as_float(x) __builtin_astype((x), float)
+#define as_float2(x) __builtin_astype((x), float2)
+#define as_float3(x) __builtin_astype((x), float3)
+#define as_float4(x) __builtin_astype((x), float4)
+#define as_float8(x) __builtin_astype((x), float8)
+#define as_float16(x) __builtin_astype((x), float16)
#ifdef cl_khr_fp64
-char8 __ovld __cnfn as_char8(double);
-char16 __ovld __cnfn as_char16(double2);
-uchar8 __ovld __cnfn as_uchar8(double);
-uchar16 __ovld __cnfn as_uchar16(double2);
-short3 __ovld __cnfn as_short3(double);
-short4 __ovld __cnfn as_short4(double);
-short8 __ovld __cnfn as_short8(double2);
-short16 __ovld __cnfn as_short16(double3);
-short16 __ovld __cnfn as_short16(double4);
-ushort3 __ovld __cnfn as_ushort3(double);
-ushort4 __ovld __cnfn as_ushort4(double);
-ushort8 __ovld __cnfn as_ushort8(double2);
-ushort16 __ovld __cnfn as_ushort16(double3);
-ushort16 __ovld __cnfn as_ushort16(double4);
-int2 __ovld __cnfn as_int2(double);
-int3 __ovld __cnfn as_int3(double2);
-int4 __ovld __cnfn as_int4(double2);
-int8 __ovld __cnfn as_int8(double3);
-int8 __ovld __cnfn as_int8(double4);
-int16 __ovld __cnfn as_int16(double8);
-uint2 __ovld __cnfn as_uint2(double);
-uint3 __ovld __cnfn as_uint3(double2);
-uint4 __ovld __cnfn as_uint4(double2);
-uint8 __ovld __cnfn as_uint8(double3);
-uint8 __ovld __cnfn as_uint8(double4);
-uint16 __ovld __cnfn as_uint16(double8);
-long __ovld __cnfn as_long(double);
-long2 __ovld __cnfn as_long2(double2);
-long3 __ovld __cnfn as_long3(double3);
-long3 __ovld __cnfn as_long3(double4);
-long4 __ovld __cnfn as_long4(double3);
-long4 __ovld __cnfn as_long4(double4);
-long8 __ovld __cnfn as_long8(double8);
-long16 __ovld __cnfn as_long16(double16);
-ulong __ovld __cnfn as_ulong(double);
-ulong2 __ovld __cnfn as_ulong2(double2);
-ulong3 __ovld __cnfn as_ulong3(double3);
-ulong3 __ovld __cnfn as_ulong3(double4);
-ulong4 __ovld __cnfn as_ulong4(double3);
-ulong4 __ovld __cnfn as_ulong4(double4);
-ulong8 __ovld __cnfn as_ulong8(double8);
-ulong16 __ovld __cnfn as_ulong16(double16);
-float2 __ovld __cnfn as_float2(double);
-float3 __ovld __cnfn as_float3(double2);
-float4 __ovld __cnfn as_float4(double2);
-float8 __ovld __cnfn as_float8(double3);
-float8 __ovld __cnfn as_float8(double4);
-float16 __ovld __cnfn as_float16(double8);
-double __ovld __cnfn as_double(char8);
-double __ovld __cnfn as_double(uchar8);
-double __ovld __cnfn as_double(short3);
-double __ovld __cnfn as_double(short4);
-double __ovld __cnfn as_double(ushort3);
-double __ovld __cnfn as_double(ushort4);
-double __ovld __cnfn as_double(int2);
-double __ovld __cnfn as_double(uint2);
-double __ovld __cnfn as_double(long);
-double __ovld __cnfn as_double(ulong);
-double __ovld __cnfn as_double(float2);
-double __ovld __cnfn as_double(double);
-double2 __ovld __cnfn as_double2(char16);
-double2 __ovld __cnfn as_double2(uchar16);
-double2 __ovld __cnfn as_double2(short8);
-double2 __ovld __cnfn as_double2(ushort8);
-double2 __ovld __cnfn as_double2(int3);
-double2 __ovld __cnfn as_double2(int4);
-double2 __ovld __cnfn as_double2(uint3);
-double2 __ovld __cnfn as_double2(uint4);
-double2 __ovld __cnfn as_double2(long2);
-double2 __ovld __cnfn as_double2(ulong2);
-double2 __ovld __cnfn as_double2(float3);
-double2 __ovld __cnfn as_double2(float4);
-double2 __ovld __cnfn as_double2(double2);
-double3 __ovld __cnfn as_double3(short16);
-double3 __ovld __cnfn as_double3(ushort16);
-double3 __ovld __cnfn as_double3(int8);
-double3 __ovld __cnfn as_double3(uint8);
-double3 __ovld __cnfn as_double3(long3);
-double3 __ovld __cnfn as_double3(long4);
-double3 __ovld __cnfn as_double3(ulong3);
-double3 __ovld __cnfn as_double3(ulong4);
-double3 __ovld __cnfn as_double3(float8);
-double3 __ovld __cnfn as_double3(double3);
-double3 __ovld __cnfn as_double3(double4);
-double4 __ovld __cnfn as_double4(short16);
-double4 __ovld __cnfn as_double4(ushort16);
-double4 __ovld __cnfn as_double4(int8);
-double4 __ovld __cnfn as_double4(uint8);
-double4 __ovld __cnfn as_double4(long3);
-double4 __ovld __cnfn as_double4(long4);
-double4 __ovld __cnfn as_double4(ulong3);
-double4 __ovld __cnfn as_double4(ulong4);
-double4 __ovld __cnfn as_double4(float8);
-double4 __ovld __cnfn as_double4(double3);
-double4 __ovld __cnfn as_double4(double4);
-double8 __ovld __cnfn as_double8(int16);
-double8 __ovld __cnfn as_double8(uint16);
-double8 __ovld __cnfn as_double8(long8);
-double8 __ovld __cnfn as_double8(ulong8);
-double8 __ovld __cnfn as_double8(float16);
-double8 __ovld __cnfn as_double8(double8);
-double16 __ovld __cnfn as_double16(long16);
-double16 __ovld __cnfn as_double16(ulong16);
-double16 __ovld __cnfn as_double16(double16);
+#define as_double(x) __builtin_astype((x), double)
+#define as_double2(x) __builtin_astype((x), double2)
+#define as_double3(x) __builtin_astype((x), double3)
+#define as_double4(x) __builtin_astype((x), double4)
+#define as_double8(x) __builtin_astype((x), double8)
+#define as_double16(x) __builtin_astype((x), double16)
#endif //cl_khr_fp64
#ifdef cl_khr_fp16
-char2 __ovld __cnfn as_char2(half);
-char3 __ovld __cnfn as_char3(half2);
-char4 __ovld __cnfn as_char4(half2);
-char8 __ovld __cnfn as_char8(half3);
-char8 __ovld __cnfn as_char8(half4);
-char16 __ovld __cnfn as_char16(half8);
-uchar2 __ovld __cnfn as_uchar2(half);
-uchar3 __ovld __cnfn as_uchar3(half2);
-uchar4 __ovld __cnfn as_uchar4(half2);
-uchar8 __ovld __cnfn as_uchar8(half3);
-uchar8 __ovld __cnfn as_uchar8(half4);
-uchar16 __ovld __cnfn as_uchar16(half8);
-short __ovld __cnfn as_short(half);
-short2 __ovld __cnfn as_short2(half2);
-short3 __ovld __cnfn as_short3(half3);
-short3 __ovld __cnfn as_short3(half4);
-short4 __ovld __cnfn as_short4(half3);
-short4 __ovld __cnfn as_short4(half4);
-short8 __ovld __cnfn as_short8(half8);
-short16 __ovld __cnfn as_short16(half16);
-ushort __ovld __cnfn as_ushort(half);
-ushort2 __ovld __cnfn as_ushort2(half2);
-ushort3 __ovld __cnfn as_ushort3(half3);
-ushort3 __ovld __cnfn as_ushort3(half4);
-ushort4 __ovld __cnfn as_ushort4(half3);
-ushort4 __ovld __cnfn as_ushort4(half4);
-ushort8 __ovld __cnfn as_ushort8(half8);
-ushort16 __ovld __cnfn as_ushort16(half16);
-int __ovld __cnfn as_int(half2);
-int2 __ovld __cnfn as_int2(half3);
-int2 __ovld __cnfn as_int2(half4);
-int3 __ovld __cnfn as_int3(half8);
-int4 __ovld __cnfn as_int4(half8);
-int8 __ovld __cnfn as_int8(half16);
-uint __ovld __cnfn as_uint(half2);
-uint2 __ovld __cnfn as_uint2(half3);
-uint2 __ovld __cnfn as_uint2(half4);
-uint3 __ovld __cnfn as_uint3(half8);
-uint4 __ovld __cnfn as_uint4(half8);
-uint8 __ovld __cnfn as_uint8(half16);
-long __ovld __cnfn as_long(half3);
-long __ovld __cnfn as_long(half4);
-long2 __ovld __cnfn as_long2(half8);
-long3 __ovld __cnfn as_long3(half16);
-long4 __ovld __cnfn as_long4(half16);
-ulong __ovld __cnfn as_ulong(half3);
-ulong __ovld __cnfn as_ulong(half4);
-ulong2 __ovld __cnfn as_ulong2(half8);
-ulong3 __ovld __cnfn as_ulong3(half16);
-ulong4 __ovld __cnfn as_ulong4(half16);
-half __ovld __cnfn as_half(char2);
-half __ovld __cnfn as_half(uchar2);
-half __ovld __cnfn as_half(short);
-half __ovld __cnfn as_half(ushort);
-half __ovld __cnfn as_half(half);
-half2 __ovld __cnfn as_half2(char3);
-half2 __ovld __cnfn as_half2(char4);
-half2 __ovld __cnfn as_half2(uchar3);
-half2 __ovld __cnfn as_half2(uchar4);
-half2 __ovld __cnfn as_half2(short2);
-half2 __ovld __cnfn as_half2(ushort2);
-half2 __ovld __cnfn as_half2(int);
-half2 __ovld __cnfn as_half2(uint);
-half2 __ovld __cnfn as_half2(half2);
-half2 __ovld __cnfn as_half2(float);
-half3 __ovld __cnfn as_half3(char8);
-half3 __ovld __cnfn as_half3(uchar8);
-half3 __ovld __cnfn as_half3(short3);
-half3 __ovld __cnfn as_half3(short4);
-half3 __ovld __cnfn as_half3(ushort3);
-half3 __ovld __cnfn as_half3(ushort4);
-half3 __ovld __cnfn as_half3(int2);
-half3 __ovld __cnfn as_half3(uint2);
-half3 __ovld __cnfn as_half3(long);
-half3 __ovld __cnfn as_half3(ulong);
-half3 __ovld __cnfn as_half3(half3);
-half3 __ovld __cnfn as_half3(half4);
-half3 __ovld __cnfn as_half3(float2);
-half4 __ovld __cnfn as_half4(char8);
-half4 __ovld __cnfn as_half4(uchar8);
-half4 __ovld __cnfn as_half4(short3);
-half4 __ovld __cnfn as_half4(short4);
-half4 __ovld __cnfn as_half4(ushort3);
-half4 __ovld __cnfn as_half4(ushort4);
-half4 __ovld __cnfn as_half4(int2);
-half4 __ovld __cnfn as_half4(uint2);
-half4 __ovld __cnfn as_half4(long);
-half4 __ovld __cnfn as_half4(ulong);
-half4 __ovld __cnfn as_half4(half3);
-half4 __ovld __cnfn as_half4(half4);
-half4 __ovld __cnfn as_half4(float2);
-half8 __ovld __cnfn as_half8(char16);
-half8 __ovld __cnfn as_half8(uchar16);
-half8 __ovld __cnfn as_half8(short8);
-half8 __ovld __cnfn as_half8(ushort8);
-half8 __ovld __cnfn as_half8(int3);
-half8 __ovld __cnfn as_half8(int4);
-half8 __ovld __cnfn as_half8(uint3);
-half8 __ovld __cnfn as_half8(uint4);
-half8 __ovld __cnfn as_half8(long2);
-half8 __ovld __cnfn as_half8(ulong2);
-half8 __ovld __cnfn as_half8(half8);
-half8 __ovld __cnfn as_half8(float3);
-half8 __ovld __cnfn as_half8(float4);
-half16 __ovld __cnfn as_half16(short16);
-half16 __ovld __cnfn as_half16(ushort16);
-half16 __ovld __cnfn as_half16(int8);
-half16 __ovld __cnfn as_half16(uint8);
-half16 __ovld __cnfn as_half16(long3);
-half16 __ovld __cnfn as_half16(long4);
-half16 __ovld __cnfn as_half16(ulong3);
-half16 __ovld __cnfn as_half16(ulong4);
-half16 __ovld __cnfn as_half16(half16);
-half16 __ovld __cnfn as_half16(float8);
-float __ovld __cnfn as_float(half2);
-float2 __ovld __cnfn as_float2(half3);
-float2 __ovld __cnfn as_float2(half4);
-float3 __ovld __cnfn as_float3(half8);
-float4 __ovld __cnfn as_float4(half8);
-float8 __ovld __cnfn as_float8(half16);
-
-#ifdef cl_khr_fp64
-half3 __ovld __cnfn as_half3(double);
-half4 __ovld __cnfn as_half4(double);
-half8 __ovld __cnfn as_half8(double2);
-half16 __ovld __cnfn as_half16(double3);
-half16 __ovld __cnfn as_half16(double4);
-double __ovld __cnfn as_double(half3);
-double __ovld __cnfn as_double(half4);
-double2 __ovld __cnfn as_double2(half8);
-double3 __ovld __cnfn as_double3(half16);
-double4 __ovld __cnfn as_double4(half16);
-#endif //cl_khr_fp64
+#define as_half(x) __builtin_astype((x), half)
+#define as_half2(x) __builtin_astype((x), half2)
+#define as_half3(x) __builtin_astype((x), half3)
+#define as_half4(x) __builtin_astype((x), half4)
+#define as_half8(x) __builtin_astype((x), half8)
+#define as_half16(x) __builtin_astype((x), half16)
#endif //cl_khr_fp16
// OpenCL v1.1 s6.9, v1.2/2.0 s6.10 - Function qualifiers
@@ -14389,10 +13703,10 @@ float __ovld atomic_xchg(volatile __local float *p, float val);
#if defined(cl_khr_global_int32_base_atomics)
int __ovld atom_xchg(volatile __global int *p, int val);
-int __ovld atom_xchg(volatile __local int *p, int val);
+unsigned int __ovld atom_xchg(volatile __global unsigned int *p, unsigned int val);
#endif
#if defined(cl_khr_local_int32_base_atomics)
-unsigned int __ovld atom_xchg(volatile __global unsigned int *p, unsigned int val);
+int __ovld atom_xchg(volatile __local int *p, int val);
unsigned int __ovld atom_xchg(volatile __local unsigned int *p, unsigned int val);
#endif
@@ -14509,8 +13823,6 @@ unsigned int __ovld atom_min(volatile __local unsigned int *p, unsigned int val)
#if defined(cl_khr_int64_extended_atomics)
long __ovld atom_min(volatile __global long *p, long val);
unsigned long __ovld atom_min(volatile __global unsigned long *p, unsigned long val);
-#endif
-#if defined(cl_khr_local_int32_extended_atomics)
long __ovld atom_min(volatile __local long *p, long val);
unsigned long __ovld atom_min(volatile __local unsigned long *p, unsigned long val);
#endif
@@ -15650,6 +14962,7 @@ float __purefn __ovld read_imagef(read_only image2d_array_msaa_depth_t image, in
#endif //cl_khr_gl_msaa_sharing
// OpenCL Extension v2.0 s9.18 - Mipmaps
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
float4 __purefn __ovld read_imagef(read_only image1d_t image, sampler_t sampler, float coord, float lod);
@@ -15725,6 +15038,7 @@ int4 __purefn __ovld read_imagei(read_only image3d_t image, sampler_t sampler, f
uint4 __purefn __ovld read_imageui(read_only image3d_t image, sampler_t sampler, float4 coord, float lod);
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
/**
* Sampler-less Image Access
@@ -15823,6 +15137,7 @@ float __purefn __ovld read_imagef(read_write image2d_msaa_depth_t image, int2 co
float __purefn __ovld read_imagef(read_write image2d_array_msaa_depth_t image, int4 coord, int sample);
#endif //cl_khr_gl_msaa_sharing
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
float4 __purefn __ovld read_imagef(read_write image1d_t image, sampler_t sampler, float coord, float lod);
int4 __purefn __ovld read_imagei(read_write image1d_t image, sampler_t sampler, float coord, float lod);
@@ -15896,6 +15211,7 @@ float4 __purefn __ovld read_imagef(read_write image3d_t image, sampler_t sampler
int4 __purefn __ovld read_imagei(read_write image3d_t image, sampler_t sampler, float4 coord, float lod);
uint4 __purefn __ovld read_imageui(read_write image3d_t image, sampler_t sampler, float4 coord, float lod);
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
// Image read functions returning half4 type
#ifdef cl_khr_fp16
@@ -15995,9 +15311,11 @@ void __ovld write_imagef(write_only image1d_array_t image_array, int2 coord, flo
void __ovld write_imagei(write_only image1d_array_t image_array, int2 coord, int4 color);
void __ovld write_imageui(write_only image1d_array_t image_array, int2 coord, uint4 color);
+#ifdef cl_khr_3d_image_writes
void __ovld write_imagef(write_only image3d_t image, int4 coord, float4 color);
void __ovld write_imagei(write_only image3d_t image, int4 coord, int4 color);
void __ovld write_imageui(write_only image3d_t image, int4 coord, uint4 color);
+#endif
#ifdef cl_khr_depth_images
void __ovld write_imagef(write_only image2d_depth_t image, int2 coord, float color);
@@ -16005,6 +15323,7 @@ void __ovld write_imagef(write_only image2d_array_depth_t image, int4 coord, flo
#endif //cl_khr_depth_images
// OpenCL Extension v2.0 s9.18 - Mipmaps
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
void __ovld write_imagef(write_only image1d_t image, int coord, int lod, float4 color);
void __ovld write_imagei(write_only image1d_t image, int coord, int lod, int4 color);
@@ -16025,16 +15344,21 @@ void __ovld write_imageui(write_only image2d_array_t image_array, int4 coord, in
void __ovld write_imagef(write_only image2d_depth_t image, int2 coord, int lod, float color);
void __ovld write_imagef(write_only image2d_array_depth_t image, int4 coord, int lod, float color);
+#ifdef cl_khr_3d_image_writes
void __ovld write_imagef(write_only image3d_t image, int4 coord, int lod, float4 color);
void __ovld write_imagei(write_only image3d_t image, int4 coord, int lod, int4 color);
void __ovld write_imageui(write_only image3d_t image, int4 coord, int lod, uint4 color);
+#endif
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
// Image write functions for half4 type
#ifdef cl_khr_fp16
void __ovld write_imageh(write_only image1d_t image, int coord, half4 color);
void __ovld write_imageh(write_only image2d_t image, int2 coord, half4 color);
+#ifdef cl_khr_3d_image_writes
void __ovld write_imageh(write_only image3d_t image, int4 coord, half4 color);
+#endif
void __ovld write_imageh(write_only image1d_array_t image, int2 coord, half4 color);
void __ovld write_imageh(write_only image2d_array_t image, int4 coord, half4 color);
void __ovld write_imageh(write_only image1d_buffer_t image, int coord, half4 color);
@@ -16062,15 +15386,18 @@ void __ovld write_imagef(read_write image1d_array_t image_array, int2 coord, flo
void __ovld write_imagei(read_write image1d_array_t image_array, int2 coord, int4 color);
void __ovld write_imageui(read_write image1d_array_t image_array, int2 coord, uint4 color);
+#ifdef cl_khr_3d_image_writes
void __ovld write_imagef(read_write image3d_t image, int4 coord, float4 color);
void __ovld write_imagei(read_write image3d_t image, int4 coord, int4 color);
void __ovld write_imageui(read_write image3d_t image, int4 coord, uint4 color);
+#endif
#ifdef cl_khr_depth_images
void __ovld write_imagef(read_write image2d_depth_t image, int2 coord, float color);
void __ovld write_imagef(read_write image2d_array_depth_t image, int4 coord, float color);
#endif //cl_khr_depth_images
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
void __ovld write_imagef(read_write image1d_t image, int coord, int lod, float4 color);
void __ovld write_imagei(read_write image1d_t image, int coord, int lod, int4 color);
@@ -16091,16 +15418,21 @@ void __ovld write_imageui(read_write image2d_array_t image_array, int4 coord, in
void __ovld write_imagef(read_write image2d_depth_t image, int2 coord, int lod, float color);
void __ovld write_imagef(read_write image2d_array_depth_t image, int4 coord, int lod, float color);
+#ifdef cl_khr_3d_image_writes
void __ovld write_imagef(read_write image3d_t image, int4 coord, int lod, float4 color);
void __ovld write_imagei(read_write image3d_t image, int4 coord, int lod, int4 color);
void __ovld write_imageui(read_write image3d_t image, int4 coord, int lod, uint4 color);
+#endif
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
// Image write functions for half4 type
#ifdef cl_khr_fp16
void __ovld write_imageh(read_write image1d_t image, int coord, half4 color);
void __ovld write_imageh(read_write image2d_t image, int2 coord, half4 color);
+#ifdef cl_khr_3d_image_writes
void __ovld write_imageh(read_write image3d_t image, int4 coord, half4 color);
+#endif
void __ovld write_imageh(read_write image1d_array_t image, int2 coord, half4 color);
void __ovld write_imageh(read_write image2d_array_t image, int4 coord, half4 color);
void __ovld write_imageh(read_write image1d_buffer_t image, int coord, half4 color);
@@ -16118,7 +15450,9 @@ void __ovld write_imageh(read_write image1d_buffer_t image, int coord, half4 col
int __ovld __cnfn get_image_width(read_only image1d_t image);
int __ovld __cnfn get_image_width(read_only image1d_buffer_t image);
int __ovld __cnfn get_image_width(read_only image2d_t image);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_width(read_only image3d_t image);
+#endif
int __ovld __cnfn get_image_width(read_only image1d_array_t image);
int __ovld __cnfn get_image_width(read_only image2d_array_t image);
#ifdef cl_khr_depth_images
@@ -16135,7 +15469,9 @@ int __ovld __cnfn get_image_width(read_only image2d_array_msaa_depth_t image);
int __ovld __cnfn get_image_width(write_only image1d_t image);
int __ovld __cnfn get_image_width(write_only image1d_buffer_t image);
int __ovld __cnfn get_image_width(write_only image2d_t image);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_width(write_only image3d_t image);
+#endif
int __ovld __cnfn get_image_width(write_only image1d_array_t image);
int __ovld __cnfn get_image_width(write_only image2d_array_t image);
#ifdef cl_khr_depth_images
@@ -16186,7 +15522,9 @@ int __ovld __cnfn get_image_height(read_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
int __ovld __cnfn get_image_height(write_only image2d_t image);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_height(write_only image3d_t image);
+#endif
int __ovld __cnfn get_image_height(write_only image2d_array_t image);
#ifdef cl_khr_depth_images
int __ovld __cnfn get_image_height(write_only image2d_depth_t image);
@@ -16220,13 +15558,16 @@ int __ovld __cnfn get_image_height(read_write image2d_array_msaa_depth_t image);
*/
int __ovld __cnfn get_image_depth(read_only image3d_t image);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_depth(write_only image3d_t image);
+#endif
#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
int __ovld __cnfn get_image_depth(read_write image3d_t image);
#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
// OpenCL Extension v2.0 s9.18 - Mipmaps
+#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
#ifdef cl_khr_mipmap_image
/**
* Return the image miplevels.
@@ -16238,13 +15579,13 @@ int __ovld get_image_num_mip_levels(read_only image3d_t image);
int __ovld get_image_num_mip_levels(write_only image1d_t image);
int __ovld get_image_num_mip_levels(write_only image2d_t image);
+#ifdef cl_khr_3d_image_writes
int __ovld get_image_num_mip_levels(write_only image3d_t image);
+#endif
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
int __ovld get_image_num_mip_levels(read_write image1d_t image);
int __ovld get_image_num_mip_levels(read_write image2d_t image);
int __ovld get_image_num_mip_levels(read_write image3d_t image);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
int __ovld get_image_num_mip_levels(read_only image1d_array_t image);
int __ovld get_image_num_mip_levels(read_only image2d_array_t image);
@@ -16256,14 +15597,13 @@ int __ovld get_image_num_mip_levels(write_only image2d_array_t image);
int __ovld get_image_num_mip_levels(write_only image2d_array_depth_t image);
int __ovld get_image_num_mip_levels(write_only image2d_depth_t image);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
int __ovld get_image_num_mip_levels(read_write image1d_array_t image);
int __ovld get_image_num_mip_levels(read_write image2d_array_t image);
int __ovld get_image_num_mip_levels(read_write image2d_array_depth_t image);
int __ovld get_image_num_mip_levels(read_write image2d_depth_t image);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
#endif //cl_khr_mipmap_image
+#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
/**
* Return the channel data type. Valid values are:
@@ -16324,7 +15664,9 @@ int __ovld __cnfn get_image_channel_data_type(read_only image2d_array_msaa_depth
int __ovld __cnfn get_image_channel_data_type(write_only image1d_t image);
int __ovld __cnfn get_image_channel_data_type(write_only image1d_buffer_t image);
int __ovld __cnfn get_image_channel_data_type(write_only image2d_t image);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_channel_data_type(write_only image3d_t image);
+#endif
int __ovld __cnfn get_image_channel_data_type(write_only image1d_array_t image);
int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_t image);
#ifdef cl_khr_depth_images
@@ -16418,7 +15760,9 @@ int __ovld __cnfn get_image_channel_order(read_only image2d_array_msaa_depth_t i
int __ovld __cnfn get_image_channel_order(write_only image1d_t image);
int __ovld __cnfn get_image_channel_order(write_only image1d_buffer_t image);
int __ovld __cnfn get_image_channel_order(write_only image2d_t image);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_channel_order(write_only image3d_t image);
+#endif
int __ovld __cnfn get_image_channel_order(write_only image1d_array_t image);
int __ovld __cnfn get_image_channel_order(write_only image2d_array_t image);
#ifdef cl_khr_depth_images
@@ -16504,7 +15848,9 @@ int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_depth_t image);
* component and the w component is 0.
*/
int4 __ovld __cnfn get_image_dim(read_only image3d_t image);
+#ifdef cl_khr_3d_image_writes
int4 __ovld __cnfn get_image_dim(write_only image3d_t image);
+#endif
#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
int4 __ovld __cnfn get_image_dim(read_write image3d_t image);
#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
@@ -16714,16 +16060,12 @@ typedef int clk_profiling_info;
#define MAX_WORK_DIM 3
-// ToDo: Remove definition of ndrange_t in Clang as an opaque type and add back
-// the following ndrange_t definition.
-#if 0
typedef struct {
unsigned int workDimension;
size_t globalWorkOffset[MAX_WORK_DIM];
size_t globalWorkSize[MAX_WORK_DIM];
size_t localWorkSize[MAX_WORK_DIM];
} ndrange_t;
-#endif
ndrange_t __ovld ndrange_1D(size_t);
ndrange_t __ovld ndrange_1D(size_t, size_t);
diff --git a/contrib/llvm/tools/clang/lib/Headers/pmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/pmmintrin.h
index d4f6487..559ece2 100644
--- a/contrib/llvm/tools/clang/lib/Headers/pmmintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/pmmintrin.h
@@ -31,9 +31,11 @@
__attribute__((__always_inline__, __nodebug__, __target__("sse3")))
/// \brief Loads data from an unaligned memory location to elements in a 128-bit
-/// vector. If the address of the data is not 16-byte aligned, the
-/// instruction may read two adjacent aligned blocks of memory to retrieve
-/// the requested data.
+/// vector.
+///
+/// If the address of the data is not 16-byte aligned, the instruction may
+/// read two adjacent aligned blocks of memory to retrieve the requested
+/// data.
///
/// \headerfile <x86intrin.h>
///
@@ -115,7 +117,7 @@ _mm_hsub_ps(__m128 __a, __m128 __b)
/// \brief Moves and duplicates high-order (odd-indexed) values from a 128-bit
/// vector of [4 x float] to float values stored in a 128-bit vector of
-/// [4 x float].
+/// [4 x float].
///
/// \headerfile <x86intrin.h>
///
@@ -136,7 +138,7 @@ _mm_movehdup_ps(__m128 __a)
}
/// \brief Duplicates low-order (even-indexed) values from a 128-bit vector of
-/// [4 x float] to float values stored in a 128-bit vector of [4 x float].
+/// [4 x float] to float values stored in a 128-bit vector of [4 x float].
///
/// \headerfile <x86intrin.h>
///
@@ -257,14 +259,6 @@ _mm_movedup_pd(__m128d __a)
return __builtin_shufflevector((__v2df)__a, (__v2df)__a, 0, 0);
}
-#define _MM_DENORMALS_ZERO_ON (0x0040)
-#define _MM_DENORMALS_ZERO_OFF (0x0000)
-
-#define _MM_DENORMALS_ZERO_MASK (0x0040)
-
-#define _MM_GET_DENORMALS_ZERO_MODE() (_mm_getcsr() & _MM_DENORMALS_ZERO_MASK)
-#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x)))
-
/// \brief Establishes a linear address memory range to be monitored and puts
/// the processor in the monitor event pending state. Data stored in the
/// monitored address range causes the processor to exit the pending state.
diff --git a/contrib/llvm/tools/clang/lib/Headers/prfchwintrin.h b/contrib/llvm/tools/clang/lib/Headers/prfchwintrin.h
index ba02857..b52f31d 100644
--- a/contrib/llvm/tools/clang/lib/Headers/prfchwintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/prfchwintrin.h
@@ -29,12 +29,38 @@
#define __PRFCHWINTRIN_H
#if defined(__PRFCHW__) || defined(__3dNOW__)
+/// \brief Loads a memory sequence containing the specified memory address into
+/// all data cache levels. The cache-coherency state is set to exclusive.
+/// Data can be read from and written to the cache line without additional
+/// delay.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c PREFETCHT0 instruction.
+///
+/// \param __P
+/// A pointer specifying the memory address to be prefetched.
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_m_prefetch(void *__P)
{
__builtin_prefetch (__P, 0, 3 /* _MM_HINT_T0 */);
}
+/// \brief Loads a memory sequence containing the specified memory address into
+/// the L1 data cache and sets the cache-coherency to modified. This
+/// provides a hint to the processor that the cache line will be modified.
+/// It is intended for use when the cache line will be written to shortly
+/// after the prefetch is performed.
+///
+/// Note that the effect of this intrinsic is dependent on the processor
+/// implementation.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c PREFETCHW instruction.
+///
+/// \param __P
+/// A pointer specifying the memory address to be prefetched.
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_m_prefetchw(void *__P)
{
diff --git a/contrib/llvm/tools/clang/lib/Headers/smmintrin.h b/contrib/llvm/tools/clang/lib/Headers/smmintrin.h
index e48ab03..c2fa5a4 100644
--- a/contrib/llvm/tools/clang/lib/Headers/smmintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/smmintrin.h
@@ -46,37 +46,379 @@
#define _MM_FROUND_RINT (_MM_FROUND_RAISE_EXC | _MM_FROUND_CUR_DIRECTION)
#define _MM_FROUND_NEARBYINT (_MM_FROUND_NO_EXC | _MM_FROUND_CUR_DIRECTION)
+/// \brief Rounds up each element of the 128-bit vector of [4 x float] to an
+/// integer and returns the rounded values in a 128-bit vector of
+/// [4 x float].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128 _mm_ceil_ps(__m128 X);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [4 x float] values to be rounded up.
+/// \returns A 128-bit vector of [4 x float] containing the rounded values.
#define _mm_ceil_ps(X) _mm_round_ps((X), _MM_FROUND_CEIL)
+
+/// \brief Rounds up each element of the 128-bit vector of [2 x double] to an
+/// integer and returns the rounded values in a 128-bit vector of
+/// [2 x double].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128d _mm_ceil_pd(__m128d X);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [2 x double] values to be rounded up.
+/// \returns A 128-bit vector of [2 x double] containing the rounded values.
#define _mm_ceil_pd(X) _mm_round_pd((X), _MM_FROUND_CEIL)
+
+/// \brief Copies three upper elements of the first 128-bit vector operand to
+/// the corresponding three upper elements of the 128-bit result vector of
+/// [4 x float]. Rounds up the lowest element of the second 128-bit vector
+/// operand to an integer and copies it to the lowest element of the 128-bit
+/// result vector of [4 x float].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128 _mm_ceil_ss(__m128 X, __m128 Y);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are
+/// copied to the corresponding bits of the result.
+/// \param Y
+/// A 128-bit vector of [4 x float]. The value stored in bits [31:0] is
+/// rounded up to the nearest integer and copied to the corresponding bits
+/// of the result.
+/// \returns A 128-bit vector of [4 x float] containing the copied and rounded
+/// values.
#define _mm_ceil_ss(X, Y) _mm_round_ss((X), (Y), _MM_FROUND_CEIL)
+
+/// \brief Copies the upper element of the first 128-bit vector operand to the
+/// corresponding upper element of the 128-bit result vector of [2 x double].
+/// Rounds up the lower element of the second 128-bit vector operand to an
+/// integer and copies it to the lower element of the 128-bit result vector
+/// of [2 x double].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128d _mm_ceil_sd(__m128d X, __m128d Y);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is
+/// copied to the corresponding bits of the result.
+/// \param Y
+/// A 128-bit vector of [2 x double]. The value stored in bits [63:0] is
+/// rounded up to the nearest integer and copied to the corresponding bits
+/// of the result.
+/// \returns A 128-bit vector of [2 x double] containing the copied and rounded
+/// values.
#define _mm_ceil_sd(X, Y) _mm_round_sd((X), (Y), _MM_FROUND_CEIL)
+/// \brief Rounds down each element of the 128-bit vector of [4 x float] to an
+/// an integer and returns the rounded values in a 128-bit vector of
+/// [4 x float].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128 _mm_floor_ps(__m128 X);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [4 x float] values to be rounded down.
+/// \returns A 128-bit vector of [4 x float] containing the rounded values.
#define _mm_floor_ps(X) _mm_round_ps((X), _MM_FROUND_FLOOR)
+
+/// \brief Rounds down each element of the 128-bit vector of [2 x double] to an
+/// integer and returns the rounded values in a 128-bit vector of
+/// [2 x double].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128d _mm_floor_pd(__m128d X);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [2 x double].
+/// \returns A 128-bit vector of [2 x double] containing the rounded values.
#define _mm_floor_pd(X) _mm_round_pd((X), _MM_FROUND_FLOOR)
+
+/// \brief Copies three upper elements of the first 128-bit vector operand to
+/// the corresponding three upper elements of the 128-bit result vector of
+/// [4 x float]. Rounds down the lowest element of the second 128-bit vector
+/// operand to an integer and copies it to the lowest element of the 128-bit
+/// result vector of [4 x float].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128 _mm_floor_ss(__m128 X, __m128 Y);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are
+/// copied to the corresponding bits of the result.
+/// \param Y
+/// A 128-bit vector of [4 x float]. The value stored in bits [31:0] is
+/// rounded down to the nearest integer and copied to the corresponding bits
+/// of the result.
+/// \returns A 128-bit vector of [4 x float] containing the copied and rounded
+/// values.
#define _mm_floor_ss(X, Y) _mm_round_ss((X), (Y), _MM_FROUND_FLOOR)
+
+/// \brief Copies the upper element of the first 128-bit vector operand to the
+/// corresponding upper element of the 128-bit result vector of [2 x double].
+/// Rounds down the lower element of the second 128-bit vector operand to an
+/// integer and copies it to the lower element of the 128-bit result vector
+/// of [2 x double].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128d _mm_floor_sd(__m128d X, __m128d Y);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is
+/// copied to the corresponding bits of the result.
+/// \param Y
+/// A 128-bit vector of [2 x double]. The value stored in bits [63:0] is
+/// rounded down to the nearest integer and copied to the corresponding bits
+/// of the result.
+/// \returns A 128-bit vector of [2 x double] containing the copied and rounded
+/// values.
#define _mm_floor_sd(X, Y) _mm_round_sd((X), (Y), _MM_FROUND_FLOOR)
+/// \brief Rounds each element of the 128-bit vector of [4 x float] to an
+/// integer value according to the rounding control specified by the second
+/// argument and returns the rounded values in a 128-bit vector of
+/// [4 x float].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128 _mm_round_ps(__m128 X, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDPS / ROUNDPS </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [4 x float].
+/// \param M
+/// An integer value that specifies the rounding operation. \n
+/// Bits [7:4] are reserved. \n
+/// Bit [3] is a precision exception value: \n
+/// 0: A normal PE exception is used \n
+/// 1: The PE field is not updated \n
+/// Bit [2] is the rounding control source: \n
+/// 0: Use bits [1:0] of \a M \n
+/// 1: Use the current MXCSR setting \n
+/// Bits [1:0] contain the rounding control definition: \n
+/// 00: Nearest \n
+/// 01: Downward (toward negative infinity) \n
+/// 10: Upward (toward positive infinity) \n
+/// 11: Truncated
+/// \returns A 128-bit vector of [4 x float] containing the rounded values.
#define _mm_round_ps(X, M) __extension__ ({ \
(__m128)__builtin_ia32_roundps((__v4sf)(__m128)(X), (M)); })
+/// \brief Copies three upper elements of the first 128-bit vector operand to
+/// the corresponding three upper elements of the 128-bit result vector of
+/// [4 x float]. Rounds the lowest element of the second 128-bit vector
+/// operand to an integer value according to the rounding control specified
+/// by the third argument and copies it to the lowest element of the 128-bit
+/// result vector of [4 x float].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128 _mm_round_ss(__m128 X, __m128 Y, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDSS / ROUNDSS </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [4 x float]. The values stored in bits [127:32] are
+/// copied to the corresponding bits of the result.
+/// \param Y
+/// A 128-bit vector of [4 x float]. The value stored in bits [31:0] is
+/// rounded to the nearest integer using the specified rounding control and
+/// copied to the corresponding bits of the result.
+/// \param M
+/// An integer value that specifies the rounding operation. \n
+/// Bits [7:4] are reserved. \n
+/// Bit [3] is a precision exception value: \n
+/// 0: A normal PE exception is used \n
+/// 1: The PE field is not updated \n
+/// Bit [2] is the rounding control source: \n
+/// 0: Use bits [1:0] of \a M \n
+/// 1: Use the current MXCSR setting \n
+/// Bits [1:0] contain the rounding control definition: \n
+/// 00: Nearest \n
+/// 01: Downward (toward negative infinity) \n
+/// 10: Upward (toward positive infinity) \n
+/// 11: Truncated
+/// \returns A 128-bit vector of [4 x float] containing the copied and rounded
+/// values.
#define _mm_round_ss(X, Y, M) __extension__ ({ \
(__m128)__builtin_ia32_roundss((__v4sf)(__m128)(X), \
(__v4sf)(__m128)(Y), (M)); })
+/// \brief Rounds each element of the 128-bit vector of [2 x double] to an
+/// integer value according to the rounding control specified by the second
+/// argument and returns the rounded values in a 128-bit vector of
+/// [2 x double].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128d _mm_round_pd(__m128d X, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDPD / ROUNDPD </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [2 x double].
+/// \param M
+/// An integer value that specifies the rounding operation. \n
+/// Bits [7:4] are reserved. \n
+/// Bit [3] is a precision exception value: \n
+/// 0: A normal PE exception is used \n
+/// 1: The PE field is not updated \n
+/// Bit [2] is the rounding control source: \n
+/// 0: Use bits [1:0] of \a M \n
+/// 1: Use the current MXCSR setting \n
+/// Bits [1:0] contain the rounding control definition: \n
+/// 00: Nearest \n
+/// 01: Downward (toward negative infinity) \n
+/// 10: Upward (toward positive infinity) \n
+/// 11: Truncated
+/// \returns A 128-bit vector of [2 x double] containing the rounded values.
#define _mm_round_pd(X, M) __extension__ ({ \
(__m128d)__builtin_ia32_roundpd((__v2df)(__m128d)(X), (M)); })
+/// \brief Copies the upper element of the first 128-bit vector operand to the
+/// corresponding upper element of the 128-bit result vector of [2 x double].
+/// Rounds the lower element of the second 128-bit vector operand to an
+/// integer value according to the rounding control specified by the third
+/// argument and copies it to the lower element of the 128-bit result vector
+/// of [2 x double].
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128d _mm_round_sd(__m128d X, __m128d Y, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VROUNDSD / ROUNDSD </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [2 x double]. The value stored in bits [127:64] is
+/// copied to the corresponding bits of the result.
+/// \param Y
+/// A 128-bit vector of [2 x double]. The value stored in bits [63:0] is
+/// rounded to the nearest integer using the specified rounding control and
+/// copied to the corresponding bits of the result.
+/// \param M
+/// An integer value that specifies the rounding operation. \n
+/// Bits [7:4] are reserved. \n
+/// Bit [3] is a precision exception value: \n
+/// 0: A normal PE exception is used \n
+/// 1: The PE field is not updated \n
+/// Bit [2] is the rounding control source: \n
+/// 0: Use bits [1:0] of \a M \n
+/// 1: Use the current MXCSR setting \n
+/// Bits [1:0] contain the rounding control definition: \n
+/// 00: Nearest \n
+/// 01: Downward (toward negative infinity) \n
+/// 10: Upward (toward positive infinity) \n
+/// 11: Truncated
+/// \returns A 128-bit vector of [2 x double] containing the copied and rounded
+/// values.
#define _mm_round_sd(X, Y, M) __extension__ ({ \
(__m128d)__builtin_ia32_roundsd((__v2df)(__m128d)(X), \
(__v2df)(__m128d)(Y), (M)); })
/* SSE4 Packed Blending Intrinsics. */
+/// \brief Returns a 128-bit vector of [2 x double] where the values are
+/// selected from either the first or second operand as specified by the
+/// third operand, the control mask.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128d _mm_blend_pd(__m128d V1, __m128d V2, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VBLENDPD / BLENDPD </c> instruction.
+///
+/// \param V1
+/// A 128-bit vector of [2 x double].
+/// \param V2
+/// A 128-bit vector of [2 x double].
+/// \param M
+/// An immediate integer operand, with mask bits [1:0] specifying how the
+/// values are to be copied. The position of the mask bit corresponds to the
+/// index of a copied value. When a mask bit is 0, the corresponding 64-bit
+/// element in operand \a V1 is copied to the same position in the result.
+/// When a mask bit is 1, the corresponding 64-bit element in operand \a V2
+/// is copied to the same position in the result.
+/// \returns A 128-bit vector of [2 x double] containing the copied values.
#define _mm_blend_pd(V1, V2, M) __extension__ ({ \
(__m128d)__builtin_shufflevector((__v2df)(__m128d)(V1), \
(__v2df)(__m128d)(V2), \
(((M) & 0x01) ? 2 : 0), \
(((M) & 0x02) ? 3 : 1)); })
+/// \brief Returns a 128-bit vector of [4 x float] where the values are selected
+/// from either the first or second operand as specified by the third
+/// operand, the control mask.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128 _mm_blend_ps(__m128 V1, __m128 V2, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VBLENDPS / BLENDPS </c> instruction.
+///
+/// \param V1
+/// A 128-bit vector of [4 x float].
+/// \param V2
+/// A 128-bit vector of [4 x float].
+/// \param M
+/// An immediate integer operand, with mask bits [3:0] specifying how the
+/// values are to be copied. The position of the mask bit corresponds to the
+/// index of a copied value. When a mask bit is 0, the corresponding 32-bit
+/// element in operand \a V1 is copied to the same position in the result.
+/// When a mask bit is 1, the corresponding 32-bit element in operand \a V2
+/// is copied to the same position in the result.
+/// \returns A 128-bit vector of [4 x float] containing the copied values.
#define _mm_blend_ps(V1, V2, M) __extension__ ({ \
(__m128)__builtin_shufflevector((__v4sf)(__m128)(V1), (__v4sf)(__m128)(V2), \
(((M) & 0x01) ? 4 : 0), \
@@ -84,6 +426,26 @@
(((M) & 0x04) ? 6 : 2), \
(((M) & 0x08) ? 7 : 3)); })
+/// \brief Returns a 128-bit vector of [2 x double] where the values are
+/// selected from either the first or second operand as specified by the
+/// third operand, the control mask.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VBLENDVPD / BLENDVPD </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [2 x double].
+/// \param __V2
+/// A 128-bit vector of [2 x double].
+/// \param __M
+/// A 128-bit vector operand, with mask bits 127 and 63 specifying how the
+/// values are to be copied. The position of the mask bit corresponds to the
+/// most significant bit of a copied value. When a mask bit is 0, the
+/// corresponding 64-bit element in operand \a __V1 is copied to the same
+/// position in the result. When a mask bit is 1, the corresponding 64-bit
+/// element in operand \a __V2 is copied to the same position in the result.
+/// \returns A 128-bit vector of [2 x double] containing the copied values.
static __inline__ __m128d __DEFAULT_FN_ATTRS
_mm_blendv_pd (__m128d __V1, __m128d __V2, __m128d __M)
{
@@ -91,6 +453,26 @@ _mm_blendv_pd (__m128d __V1, __m128d __V2, __m128d __M)
(__v2df)__M);
}
+/// \brief Returns a 128-bit vector of [4 x float] where the values are
+/// selected from either the first or second operand as specified by the
+/// third operand, the control mask.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VBLENDVPS / BLENDVPS </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [4 x float].
+/// \param __V2
+/// A 128-bit vector of [4 x float].
+/// \param __M
+/// A 128-bit vector operand, with mask bits 127, 95, 63, and 31 specifying
+/// how the values are to be copied. The position of the mask bit corresponds
+/// to the most significant bit of a copied value. When a mask bit is 0, the
+/// corresponding 32-bit element in operand \a __V1 is copied to the same
+/// position in the result. When a mask bit is 1, the corresponding 32-bit
+/// element in operand \a __V2 is copied to the same position in the result.
+/// \returns A 128-bit vector of [4 x float] containing the copied values.
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_blendv_ps (__m128 __V1, __m128 __V2, __m128 __M)
{
@@ -98,6 +480,26 @@ _mm_blendv_ps (__m128 __V1, __m128 __V2, __m128 __M)
(__v4sf)__M);
}
+/// \brief Returns a 128-bit vector of [16 x i8] where the values are selected
+/// from either of the first or second operand as specified by the third
+/// operand, the control mask.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPBLENDVB / PBLENDVB </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [16 x i8].
+/// \param __V2
+/// A 128-bit vector of [16 x i8].
+/// \param __M
+/// A 128-bit vector operand, with mask bits 127, 119, 111 ... 7 specifying
+/// how the values are to be copied. The position of the mask bit corresponds
+/// to the most significant bit of a copied value. When a mask bit is 0, the
+/// corresponding 8-bit element in operand \a __V1 is copied to the same
+/// position in the result. When a mask bit is 1, the corresponding 8-bit
+/// element in operand \a __V2 is copied to the same position in the result.
+/// \returns A 128-bit vector of [16 x i8] containing the copied values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
{
@@ -105,6 +507,30 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
(__v16qi)__M);
}
+/// \brief Returns a 128-bit vector of [8 x i16] where the values are selected
+/// from either of the first or second operand as specified by the third
+/// operand, the control mask.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128i _mm_blend_epi16(__m128i V1, __m128i V2, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPBLENDW / PBLENDW </c> instruction.
+///
+/// \param V1
+/// A 128-bit vector of [8 x i16].
+/// \param V2
+/// A 128-bit vector of [8 x i16].
+/// \param M
+/// An immediate integer operand, with mask bits [7:0] specifying how the
+/// values are to be copied. The position of the mask bit corresponds to the
+/// index of a copied value. When a mask bit is 0, the corresponding 16-bit
+/// element in operand \a V1 is copied to the same position in the result.
+/// When a mask bit is 1, the corresponding 16-bit element in operand \a V2
+/// is copied to the same position in the result.
+/// \returns A 128-bit vector of [8 x i16] containing the copied values.
#define _mm_blend_epi16(V1, V2, M) __extension__ ({ \
(__m128i)__builtin_shufflevector((__v8hi)(__m128i)(V1), \
(__v8hi)(__m128i)(V2), \
@@ -118,12 +544,39 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
(((M) & 0x80) ? 15 : 7)); })
/* SSE4 Dword Multiply Instructions. */
+/// \brief Multiples corresponding elements of two 128-bit vectors of [4 x i32]
+/// and returns the lower 32 bits of the each product in a 128-bit vector of
+/// [4 x i32].
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMULLD / PMULLD </c> instruction.
+///
+/// \param __V1
+/// A 128-bit integer vector.
+/// \param __V2
+/// A 128-bit integer vector.
+/// \returns A 128-bit integer vector containing the products of both operands.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_mullo_epi32 (__m128i __V1, __m128i __V2)
{
return (__m128i) ((__v4su)__V1 * (__v4su)__V2);
}
+/// \brief Multiplies corresponding even-indexed elements of two 128-bit
+/// vectors of [4 x i32] and returns a 128-bit vector of [2 x i64]
+/// containing the products.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMULDQ / PMULDQ </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [4 x i32].
+/// \param __V2
+/// A 128-bit vector of [4 x i32].
+/// \returns A 128-bit vector of [2 x i64] containing the products of both
+/// operands.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_mul_epi32 (__m128i __V1, __m128i __V2)
{
@@ -131,64 +584,243 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
}
/* SSE4 Floating Point Dot Product Instructions. */
+/// \brief Computes the dot product of the two 128-bit vectors of [4 x float]
+/// and returns it in the elements of the 128-bit result vector of
+/// [4 x float].
+///
+/// The immediate integer operand controls which input elements
+/// will contribute to the dot product, and where the final results are
+/// returned.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128 _mm_dp_ps(__m128 X, __m128 Y, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VDPPS / DPPS </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [4 x float].
+/// \param Y
+/// A 128-bit vector of [4 x float].
+/// \param M
+/// An immediate integer operand. Mask bits [7:4] determine which elements
+/// of the input vectors are used, with bit [4] corresponding to the lowest
+/// element and bit [7] corresponding to the highest element of each [4 x
+/// float] vector. If a bit is set, the corresponding elements from the two
+/// input vectors are used as an input for dot product; otherwise that input
+/// is treated as zero. Bits [3:0] determine which elements of the result
+/// will receive a copy of the final dot product, with bit [0] corresponding
+/// to the lowest element and bit [3] corresponding to the highest element of
+/// each [4 x float] subvector. If a bit is set, the dot product is returned
+/// in the corresponding element; otherwise that element is set to zero.
+/// \returns A 128-bit vector of [4 x float] containing the dot product.
#define _mm_dp_ps(X, Y, M) __extension__ ({ \
(__m128) __builtin_ia32_dpps((__v4sf)(__m128)(X), \
(__v4sf)(__m128)(Y), (M)); })
+/// \brief Computes the dot product of the two 128-bit vectors of [2 x double]
+/// and returns it in the elements of the 128-bit result vector of
+/// [2 x double].
+///
+/// The immediate integer operand controls which input
+/// elements will contribute to the dot product, and where the final results
+/// are returned.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128d _mm_dp_pd(__m128d X, __m128d Y, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VDPPD / DPPD </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [2 x double].
+/// \param Y
+/// A 128-bit vector of [2 x double].
+/// \param M
+/// An immediate integer operand. Mask bits [5:4] determine which elements
+/// of the input vectors are used, with bit [4] corresponding to the lowest
+/// element and bit [5] corresponding to the highest element of each of [2 x
+/// double] vector. If a bit is set, the corresponding elements from the two
+/// input vectors are used as an input for dot product; otherwise that input
+/// is treated as zero. Bits [1:0] determine which elements of the result
+/// will receive a copy of the final dot product, with bit [0] corresponding
+/// to the lowest element and bit [3] corresponding to the highest element of
+/// each [2 x double] vector. If a bit is set, the dot product is returned in
+/// the corresponding element; otherwise that element is set to zero.
#define _mm_dp_pd(X, Y, M) __extension__ ({\
(__m128d) __builtin_ia32_dppd((__v2df)(__m128d)(X), \
(__v2df)(__m128d)(Y), (M)); })
/* SSE4 Streaming Load Hint Instruction. */
+/// \brief Loads integer values from a 128-bit aligned memory location to a
+/// 128-bit integer vector.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VMOVNTDQA / MOVNTDQA </c> instruction.
+///
+/// \param __V
+/// A pointer to a 128-bit aligned memory location that contains the integer
+/// values.
+/// \returns A 128-bit integer vector containing the data stored at the
+/// specified memory location.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_stream_load_si128 (__m128i const *__V)
{
- return (__m128i) __builtin_ia32_movntdqa ((const __v2di *) __V);
+ return (__m128i) __builtin_nontemporal_load ((const __v2di *) __V);
}
/* SSE4 Packed Integer Min/Max Instructions. */
+/// \brief Compares the corresponding elements of two 128-bit vectors of
+/// [16 x i8] and returns a 128-bit vector of [16 x i8] containing the lesser
+/// of the two values.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMINSB / PMINSB </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [16 x i8].
+/// \param __V2
+/// A 128-bit vector of [16 x i8]
+/// \returns A 128-bit vector of [16 x i8] containing the lesser values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epi8 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pminsb128 ((__v16qi) __V1, (__v16qi) __V2);
}
+/// \brief Compares the corresponding elements of two 128-bit vectors of
+/// [16 x i8] and returns a 128-bit vector of [16 x i8] containing the
+/// greater value of the two.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMAXSB / PMAXSB </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [16 x i8].
+/// \param __V2
+/// A 128-bit vector of [16 x i8].
+/// \returns A 128-bit vector of [16 x i8] containing the greater values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epi8 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pmaxsb128 ((__v16qi) __V1, (__v16qi) __V2);
}
+/// \brief Compares the corresponding elements of two 128-bit vectors of
+/// [8 x u16] and returns a 128-bit vector of [8 x u16] containing the lesser
+/// value of the two.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMINUW / PMINUW </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [8 x u16].
+/// \param __V2
+/// A 128-bit vector of [8 x u16].
+/// \returns A 128-bit vector of [8 x u16] containing the lesser values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epu16 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pminuw128 ((__v8hi) __V1, (__v8hi) __V2);
}
+/// \brief Compares the corresponding elements of two 128-bit vectors of
+/// [8 x u16] and returns a 128-bit vector of [8 x u16] containing the
+/// greater value of the two.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMAXUW / PMAXUW </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [8 x u16].
+/// \param __V2
+/// A 128-bit vector of [8 x u16].
+/// \returns A 128-bit vector of [8 x u16] containing the greater values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epu16 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pmaxuw128 ((__v8hi) __V1, (__v8hi) __V2);
}
+/// \brief Compares the corresponding elements of two 128-bit vectors of
+/// [4 x i32] and returns a 128-bit vector of [4 x i32] containing the lesser
+/// value of the two.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMINSD / PMINSD </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [4 x i32].
+/// \param __V2
+/// A 128-bit vector of [4 x i32].
+/// \returns A 128-bit vector of [4 x i32] containing the lesser values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epi32 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pminsd128 ((__v4si) __V1, (__v4si) __V2);
}
+/// \brief Compares the corresponding elements of two 128-bit vectors of
+/// [4 x i32] and returns a 128-bit vector of [4 x i32] containing the
+/// greater value of the two.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMAXSD / PMAXSD </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [4 x i32].
+/// \param __V2
+/// A 128-bit vector of [4 x i32].
+/// \returns A 128-bit vector of [4 x i32] containing the greater values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epi32 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pmaxsd128 ((__v4si) __V1, (__v4si) __V2);
}
+/// \brief Compares the corresponding elements of two 128-bit vectors of
+/// [4 x u32] and returns a 128-bit vector of [4 x u32] containing the lesser
+/// value of the two.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMINUD / PMINUD </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [4 x u32].
+/// \param __V2
+/// A 128-bit vector of [4 x u32].
+/// \returns A 128-bit vector of [4 x u32] containing the lesser values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_min_epu32 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pminud128((__v4si) __V1, (__v4si) __V2);
}
+/// \brief Compares the corresponding elements of two 128-bit vectors of
+/// [4 x u32] and returns a 128-bit vector of [4 x u32] containing the
+/// greater value of the two.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMAXUD / PMAXUD </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [4 x u32].
+/// \param __V2
+/// A 128-bit vector of [4 x u32].
+/// \returns A 128-bit vector of [4 x u32] containing the greater values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_max_epu32 (__m128i __V1, __m128i __V2)
{
@@ -196,7 +828,70 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
}
/* SSE4 Insertion and Extraction from XMM Register Instructions. */
+/// \brief Takes the first argument \a X and inserts an element from the second
+/// argument \a Y as selected by the third argument \a N. That result then
+/// has elements zeroed out also as selected by the third argument \a N. The
+/// resulting 128-bit vector of [4 x float] is then returned.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128 _mm_insert_ps(__m128 X, __m128 Y, const int N);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VINSERTPS </c> instruction.
+///
+/// \param X
+/// A 128-bit vector source operand of [4 x float]. With the exception of
+/// those bits in the result copied from parameter \a Y and zeroed by bits
+/// [3:0] of \a N, all bits from this parameter are copied to the result.
+/// \param Y
+/// A 128-bit vector source operand of [4 x float]. One single-precision
+/// floating-point element from this source, as determined by the immediate
+/// parameter, is copied to the result.
+/// \param N
+/// Specifies which bits from operand \a Y will be copied, which bits in the
+/// result they will be be copied to, and which bits in the result will be
+/// cleared. The following assignments are made: \n
+/// Bits [7:6] specify the bits to copy from operand \a Y: \n
+/// 00: Selects bits [31:0] from operand \a Y. \n
+/// 01: Selects bits [63:32] from operand \a Y. \n
+/// 10: Selects bits [95:64] from operand \a Y. \n
+/// 11: Selects bits [127:96] from operand \a Y. \n
+/// Bits [5:4] specify the bits in the result to which the selected bits
+/// from operand \a Y are copied: \n
+/// 00: Copies the selected bits from \a Y to result bits [31:0]. \n
+/// 01: Copies the selected bits from \a Y to result bits [63:32]. \n
+/// 10: Copies the selected bits from \a Y to result bits [95:64]. \n
+/// 11: Copies the selected bits from \a Y to result bits [127:96]. \n
+/// Bits[3:0]: If any of these bits are set, the corresponding result
+/// element is cleared.
+/// \returns A 128-bit vector of [4 x float] containing the copied single-
+/// precision floating point elements from the operands.
#define _mm_insert_ps(X, Y, N) __builtin_ia32_insertps128((X), (Y), (N))
+
+/// \brief Extracts a 32-bit integer from a 128-bit vector of [4 x float] and
+/// returns it, using the immediate value parameter \a N as a selector.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_extract_ps(__m128 X, const int N);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VEXTRACTPS / EXTRACTPS </c>
+/// instruction.
+///
+/// \param X
+/// A 128-bit vector of [4 x float].
+/// \param N
+/// An immediate value. Bits [1:0] determines which bits from the argument
+/// \a X are extracted and returned: \n
+/// 00: Bits [31:0] of parameter \a X are returned. \n
+/// 01: Bits [63:32] of parameter \a X are returned. \n
+/// 10: Bits [95:64] of parameter \a X are returned. \n
+/// 11: Bits [127:96] of parameter \a X are returned.
+/// \returns A 32-bit integer containing the extracted 32 bits of float data.
#define _mm_extract_ps(X, N) (__extension__ \
({ union { int __i; float __f; } __t; \
__v4sf __a = (__v4sf)(__m128)(X); \
@@ -217,15 +912,111 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
_MM_MK_INSERTPS_NDX((N), 0, 0x0e))
/* Insert int into packed integer array at index. */
+/// \brief Constructs a 128-bit vector of [16 x i8] by first making a copy of
+/// the 128-bit integer vector parameter, and then inserting the lower 8 bits
+/// of an integer parameter \a I into an offset specified by the immediate
+/// value parameter \a N.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128i _mm_insert_epi8(__m128i X, int I, const int N);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPINSRB / PINSRB </c> instruction.
+///
+/// \param X
+/// A 128-bit integer vector of [16 x i8]. This vector is copied to the
+/// result and then one of the sixteen elements in the result vector is
+/// replaced by the lower 8 bits of \a I.
+/// \param I
+/// An integer. The lower 8 bits of this operand are written to the result
+/// beginning at the offset specified by \a N.
+/// \param N
+/// An immediate value. Bits [3:0] specify the bit offset in the result at
+/// which the lower 8 bits of \a I are written. \n
+/// 0000: Bits [7:0] of the result are used for insertion. \n
+/// 0001: Bits [15:8] of the result are used for insertion. \n
+/// 0010: Bits [23:16] of the result are used for insertion. \n
+/// 0011: Bits [31:24] of the result are used for insertion. \n
+/// 0100: Bits [39:32] of the result are used for insertion. \n
+/// 0101: Bits [47:40] of the result are used for insertion. \n
+/// 0110: Bits [55:48] of the result are used for insertion. \n
+/// 0111: Bits [63:56] of the result are used for insertion. \n
+/// 1000: Bits [71:64] of the result are used for insertion. \n
+/// 1001: Bits [79:72] of the result are used for insertion. \n
+/// 1010: Bits [87:80] of the result are used for insertion. \n
+/// 1011: Bits [95:88] of the result are used for insertion. \n
+/// 1100: Bits [103:96] of the result are used for insertion. \n
+/// 1101: Bits [111:104] of the result are used for insertion. \n
+/// 1110: Bits [119:112] of the result are used for insertion. \n
+/// 1111: Bits [127:120] of the result are used for insertion.
+/// \returns A 128-bit integer vector containing the constructed values.
#define _mm_insert_epi8(X, I, N) (__extension__ \
({ __v16qi __a = (__v16qi)(__m128i)(X); \
__a[(N) & 15] = (I); \
(__m128i)__a;}))
+
+/// \brief Constructs a 128-bit vector of [4 x i32] by first making a copy of
+/// the 128-bit integer vector parameter, and then inserting the 32-bit
+/// integer parameter \a I at the offset specified by the immediate value
+/// parameter \a N.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128i _mm_insert_epi32(__m128i X, int I, const int N);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPINSRD / PINSRD </c> instruction.
+///
+/// \param X
+/// A 128-bit integer vector of [4 x i32]. This vector is copied to the
+/// result and then one of the four elements in the result vector is
+/// replaced by \a I.
+/// \param I
+/// A 32-bit integer that is written to the result beginning at the offset
+/// specified by \a N.
+/// \param N
+/// An immediate value. Bits [1:0] specify the bit offset in the result at
+/// which the integer \a I is written. \n
+/// 00: Bits [31:0] of the result are used for insertion. \n
+/// 01: Bits [63:32] of the result are used for insertion. \n
+/// 10: Bits [95:64] of the result are used for insertion. \n
+/// 11: Bits [127:96] of the result are used for insertion.
+/// \returns A 128-bit integer vector containing the constructed values.
#define _mm_insert_epi32(X, I, N) (__extension__ \
({ __v4si __a = (__v4si)(__m128i)(X); \
__a[(N) & 3] = (I); \
(__m128i)__a;}))
+
#ifdef __x86_64__
+/// \brief Constructs a 128-bit vector of [2 x i64] by first making a copy of
+/// the 128-bit integer vector parameter, and then inserting the 64-bit
+/// integer parameter \a I, using the immediate value parameter \a N as an
+/// insertion location selector.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128i _mm_insert_epi64(__m128i X, long long I, const int N);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPINSRQ / PINSRQ </c> instruction.
+///
+/// \param X
+/// A 128-bit integer vector of [2 x i64]. This vector is copied to the
+/// result and then one of the two elements in the result vector is replaced
+/// by \a I.
+/// \param I
+/// A 64-bit integer that is written to the result beginning at the offset
+/// specified by \a N.
+/// \param N
+/// An immediate value. Bit [0] specifies the bit offset in the result at
+/// which the integer \a I is written. \n
+/// 0: Bits [63:0] of the result are used for insertion. \n
+/// 1: Bits [127:64] of the result are used for insertion. \n
+/// \returns A 128-bit integer vector containing the constructed values.
#define _mm_insert_epi64(X, I, N) (__extension__ \
({ __v2di __a = (__v2di)(__m128i)(X); \
__a[(N) & 1] = (I); \
@@ -235,42 +1026,219 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/* Extract int from packed integer array at index. This returns the element
* as a zero extended value, so it is unsigned.
*/
+/// \brief Extracts an 8-bit element from the 128-bit integer vector of
+/// [16 x i8], using the immediate value parameter \a N as a selector.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_extract_epi8(__m128i X, const int N);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPEXTRB / PEXTRB </c> instruction.
+///
+/// \param X
+/// A 128-bit integer vector.
+/// \param N
+/// An immediate value. Bits [3:0] specify which 8-bit vector element from
+/// the argument \a X to extract and copy to the result. \n
+/// 0000: Bits [7:0] of parameter \a X are extracted. \n
+/// 0001: Bits [15:8] of the parameter \a X are extracted. \n
+/// 0010: Bits [23:16] of the parameter \a X are extracted. \n
+/// 0011: Bits [31:24] of the parameter \a X are extracted. \n
+/// 0100: Bits [39:32] of the parameter \a X are extracted. \n
+/// 0101: Bits [47:40] of the parameter \a X are extracted. \n
+/// 0110: Bits [55:48] of the parameter \a X are extracted. \n
+/// 0111: Bits [63:56] of the parameter \a X are extracted. \n
+/// 1000: Bits [71:64] of the parameter \a X are extracted. \n
+/// 1001: Bits [79:72] of the parameter \a X are extracted. \n
+/// 1010: Bits [87:80] of the parameter \a X are extracted. \n
+/// 1011: Bits [95:88] of the parameter \a X are extracted. \n
+/// 1100: Bits [103:96] of the parameter \a X are extracted. \n
+/// 1101: Bits [111:104] of the parameter \a X are extracted. \n
+/// 1110: Bits [119:112] of the parameter \a X are extracted. \n
+/// 1111: Bits [127:120] of the parameter \a X are extracted.
+/// \returns An unsigned integer, whose lower 8 bits are selected from the
+/// 128-bit integer vector parameter and the remaining bits are assigned
+/// zeros.
#define _mm_extract_epi8(X, N) (__extension__ \
({ __v16qi __a = (__v16qi)(__m128i)(X); \
(int)(unsigned char) __a[(N) & 15];}))
+
+/// \brief Extracts a 32-bit element from the 128-bit integer vector of
+/// [4 x i32], using the immediate value parameter \a N as a selector.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_extract_epi32(__m128i X, const int N);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPEXTRD / PEXTRD </c> instruction.
+///
+/// \param X
+/// A 128-bit integer vector.
+/// \param N
+/// An immediate value. Bits [1:0] specify which 32-bit vector element from
+/// the argument \a X to extract and copy to the result. \n
+/// 00: Bits [31:0] of the parameter \a X are extracted. \n
+/// 01: Bits [63:32] of the parameter \a X are extracted. \n
+/// 10: Bits [95:64] of the parameter \a X are extracted. \n
+/// 11: Bits [127:96] of the parameter \a X are exracted.
+/// \returns An integer, whose lower 32 bits are selected from the 128-bit
+/// integer vector parameter and the remaining bits are assigned zeros.
#define _mm_extract_epi32(X, N) (__extension__ \
({ __v4si __a = (__v4si)(__m128i)(X); \
(int)__a[(N) & 3];}))
+
#ifdef __x86_64__
+/// \brief Extracts a 64-bit element from the 128-bit integer vector of
+/// [2 x i64], using the immediate value parameter \a N as a selector.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// long long _mm_extract_epi64(__m128i X, const int N);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPEXTRQ / PEXTRQ </c> instruction.
+///
+/// \param X
+/// A 128-bit integer vector.
+/// \param N
+/// An immediate value. Bit [0] specifies which 64-bit vector element from
+/// the argument \a X to return. \n
+/// 0: Bits [63:0] are returned. \n
+/// 1: Bits [127:64] are returned. \n
+/// \returns A 64-bit integer.
#define _mm_extract_epi64(X, N) (__extension__ \
({ __v2di __a = (__v2di)(__m128i)(X); \
(long long)__a[(N) & 1];}))
#endif /* __x86_64 */
/* SSE4 128-bit Packed Integer Comparisons. */
+/// \brief Tests whether the specified bits in a 128-bit integer vector are all
+/// zeros.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
+///
+/// \param __M
+/// A 128-bit integer vector containing the bits to be tested.
+/// \param __V
+/// A 128-bit integer vector selecting which bits to test in operand \a __M.
+/// \returns TRUE if the specified bits are all zeros; FALSE otherwise.
static __inline__ int __DEFAULT_FN_ATTRS
_mm_testz_si128(__m128i __M, __m128i __V)
{
return __builtin_ia32_ptestz128((__v2di)__M, (__v2di)__V);
}
+/// \brief Tests whether the specified bits in a 128-bit integer vector are all
+/// ones.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
+///
+/// \param __M
+/// A 128-bit integer vector containing the bits to be tested.
+/// \param __V
+/// A 128-bit integer vector selecting which bits to test in operand \a __M.
+/// \returns TRUE if the specified bits are all ones; FALSE otherwise.
static __inline__ int __DEFAULT_FN_ATTRS
_mm_testc_si128(__m128i __M, __m128i __V)
{
return __builtin_ia32_ptestc128((__v2di)__M, (__v2di)__V);
}
+/// \brief Tests whether the specified bits in a 128-bit integer vector are
+/// neither all zeros nor all ones.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
+///
+/// \param __M
+/// A 128-bit integer vector containing the bits to be tested.
+/// \param __V
+/// A 128-bit integer vector selecting which bits to test in operand \a __M.
+/// \returns TRUE if the specified bits are neither all zeros nor all ones;
+/// FALSE otherwise.
static __inline__ int __DEFAULT_FN_ATTRS
_mm_testnzc_si128(__m128i __M, __m128i __V)
{
return __builtin_ia32_ptestnzc128((__v2di)__M, (__v2di)__V);
}
+/// \brief Tests whether the specified bits in a 128-bit integer vector are all
+/// ones.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_test_all_ones(__m128i V);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
+///
+/// \param V
+/// A 128-bit integer vector containing the bits to be tested.
+/// \returns TRUE if the bits specified in the operand are all set to 1; FALSE
+/// otherwise.
#define _mm_test_all_ones(V) _mm_testc_si128((V), _mm_cmpeq_epi32((V), (V)))
+
+/// \brief Tests whether the specified bits in a 128-bit integer vector are
+/// neither all zeros nor all ones.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_test_mix_ones_zeros(__m128i M, __m128i V);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
+///
+/// \param M
+/// A 128-bit integer vector containing the bits to be tested.
+/// \param V
+/// A 128-bit integer vector selecting which bits to test in operand \a M.
+/// \returns TRUE if the specified bits are neither all zeros nor all ones;
+/// FALSE otherwise.
#define _mm_test_mix_ones_zeros(M, V) _mm_testnzc_si128((M), (V))
+
+/// \brief Tests whether the specified bits in a 128-bit integer vector are all
+/// zeros.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_test_all_zeros(__m128i M, __m128i V);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPTEST / PTEST </c> instruction.
+///
+/// \param M
+/// A 128-bit integer vector containing the bits to be tested.
+/// \param V
+/// A 128-bit integer vector selecting which bits to test in operand \a M.
+/// \returns TRUE if the specified bits are all zeros; FALSE otherwise.
#define _mm_test_all_zeros(M, V) _mm_testz_si128 ((M), (V))
/* SSE4 64-bit Packed Integer Comparisons. */
+/// \brief Compares each of the corresponding 64-bit values of the 128-bit
+/// integer vectors for equality.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPCMPEQQ / PCMPEQQ </c> instruction.
+///
+/// \param __V1
+/// A 128-bit integer vector.
+/// \param __V2
+/// A 128-bit integer vector.
+/// \returns A 128-bit integer vector containing the comparison results.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cmpeq_epi64(__m128i __V1, __m128i __V2)
{
@@ -278,6 +1246,19 @@ _mm_cmpeq_epi64(__m128i __V1, __m128i __V2)
}
/* SSE4 Packed Integer Sign-Extension. */
+/// \brief Sign-extends each of the lower eight 8-bit integer elements of a
+/// 128-bit vector of [16 x i8] to 16-bit values and returns them in a
+/// 128-bit vector of [8 x i16]. The upper eight elements of the input vector
+/// are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVSXBW / PMOVSXBW </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [16 x i8]. The lower eight 8-bit elements are sign-
+/// extended to 16-bit values.
+/// \returns A 128-bit vector of [8 x i16] containing the sign-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepi8_epi16(__m128i __V)
{
@@ -286,6 +1267,19 @@ _mm_cvtepi8_epi16(__m128i __V)
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v16qs)__V, (__v16qs)__V, 0, 1, 2, 3, 4, 5, 6, 7), __v8hi);
}
+/// \brief Sign-extends each of the lower four 8-bit integer elements of a
+/// 128-bit vector of [16 x i8] to 32-bit values and returns them in a
+/// 128-bit vector of [4 x i32]. The upper twelve elements of the input
+/// vector are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVSXBD / PMOVSXBD </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [16 x i8]. The lower four 8-bit elements are sign-
+/// extended to 32-bit values.
+/// \returns A 128-bit vector of [4 x i32] containing the sign-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepi8_epi32(__m128i __V)
{
@@ -294,6 +1288,19 @@ _mm_cvtepi8_epi32(__m128i __V)
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v16qs)__V, (__v16qs)__V, 0, 1, 2, 3), __v4si);
}
+/// \brief Sign-extends each of the lower two 8-bit integer elements of a
+/// 128-bit integer vector of [16 x i8] to 64-bit values and returns them in
+/// a 128-bit vector of [2 x i64]. The upper fourteen elements of the input
+/// vector are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVSXBQ / PMOVSXBQ </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [16 x i8]. The lower two 8-bit elements are sign-
+/// extended to 64-bit values.
+/// \returns A 128-bit vector of [2 x i64] containing the sign-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepi8_epi64(__m128i __V)
{
@@ -302,18 +1309,57 @@ _mm_cvtepi8_epi64(__m128i __V)
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v16qs)__V, (__v16qs)__V, 0, 1), __v2di);
}
+/// \brief Sign-extends each of the lower four 16-bit integer elements of a
+/// 128-bit integer vector of [8 x i16] to 32-bit values and returns them in
+/// a 128-bit vector of [4 x i32]. The upper four elements of the input
+/// vector are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVSXWD / PMOVSXWD </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [8 x i16]. The lower four 16-bit elements are sign-
+/// extended to 32-bit values.
+/// \returns A 128-bit vector of [4 x i32] containing the sign-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepi16_epi32(__m128i __V)
{
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v8hi)__V, (__v8hi)__V, 0, 1, 2, 3), __v4si);
}
+/// \brief Sign-extends each of the lower two 16-bit integer elements of a
+/// 128-bit integer vector of [8 x i16] to 64-bit values and returns them in
+/// a 128-bit vector of [2 x i64]. The upper six elements of the input
+/// vector are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVSXWQ / PMOVSXWQ </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [8 x i16]. The lower two 16-bit elements are sign-
+/// extended to 64-bit values.
+/// \returns A 128-bit vector of [2 x i64] containing the sign-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepi16_epi64(__m128i __V)
{
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v8hi)__V, (__v8hi)__V, 0, 1), __v2di);
}
+/// \brief Sign-extends each of the lower two 32-bit integer elements of a
+/// 128-bit integer vector of [4 x i32] to 64-bit values and returns them in
+/// a 128-bit vector of [2 x i64]. The upper two elements of the input vector
+/// are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVSXDQ / PMOVSXDQ </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [4 x i32]. The lower two 32-bit elements are sign-
+/// extended to 64-bit values.
+/// \returns A 128-bit vector of [2 x i64] containing the sign-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepi32_epi64(__m128i __V)
{
@@ -321,36 +1367,114 @@ _mm_cvtepi32_epi64(__m128i __V)
}
/* SSE4 Packed Integer Zero-Extension. */
+/// \brief Zero-extends each of the lower eight 8-bit integer elements of a
+/// 128-bit vector of [16 x i8] to 16-bit values and returns them in a
+/// 128-bit vector of [8 x i16]. The upper eight elements of the input vector
+/// are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVZXBW / PMOVZXBW </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [16 x i8]. The lower eight 8-bit elements are zero-
+/// extended to 16-bit values.
+/// \returns A 128-bit vector of [8 x i16] containing the zero-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepu8_epi16(__m128i __V)
{
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v16qu)__V, (__v16qu)__V, 0, 1, 2, 3, 4, 5, 6, 7), __v8hi);
}
+/// \brief Zero-extends each of the lower four 8-bit integer elements of a
+/// 128-bit vector of [16 x i8] to 32-bit values and returns them in a
+/// 128-bit vector of [4 x i32]. The upper twelve elements of the input
+/// vector are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVZXBD / PMOVZXBD </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [16 x i8]. The lower four 8-bit elements are zero-
+/// extended to 32-bit values.
+/// \returns A 128-bit vector of [4 x i32] containing the zero-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepu8_epi32(__m128i __V)
{
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v16qu)__V, (__v16qu)__V, 0, 1, 2, 3), __v4si);
}
+/// \brief Zero-extends each of the lower two 8-bit integer elements of a
+/// 128-bit integer vector of [16 x i8] to 64-bit values and returns them in
+/// a 128-bit vector of [2 x i64]. The upper fourteen elements of the input
+/// vector are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVZXBQ / PMOVZXBQ </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [16 x i8]. The lower two 8-bit elements are zero-
+/// extended to 64-bit values.
+/// \returns A 128-bit vector of [2 x i64] containing the zero-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepu8_epi64(__m128i __V)
{
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v16qu)__V, (__v16qu)__V, 0, 1), __v2di);
}
+/// \brief Zero-extends each of the lower four 16-bit integer elements of a
+/// 128-bit integer vector of [8 x i16] to 32-bit values and returns them in
+/// a 128-bit vector of [4 x i32]. The upper four elements of the input
+/// vector are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVZXWD / PMOVZXWD </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [8 x i16]. The lower four 16-bit elements are zero-
+/// extended to 32-bit values.
+/// \returns A 128-bit vector of [4 x i32] containing the zero-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepu16_epi32(__m128i __V)
{
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v8hu)__V, (__v8hu)__V, 0, 1, 2, 3), __v4si);
}
+/// \brief Zero-extends each of the lower two 16-bit integer elements of a
+/// 128-bit integer vector of [8 x i16] to 64-bit values and returns them in
+/// a 128-bit vector of [2 x i64]. The upper six elements of the input vector
+/// are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVZXWQ / PMOVZXWQ </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [8 x i16]. The lower two 16-bit elements are zero-
+/// extended to 64-bit values.
+/// \returns A 128-bit vector of [2 x i64] containing the zero-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepu16_epi64(__m128i __V)
{
return (__m128i)__builtin_convertvector(__builtin_shufflevector((__v8hu)__V, (__v8hu)__V, 0, 1), __v2di);
}
+/// \brief Zero-extends each of the lower two 32-bit integer elements of a
+/// 128-bit integer vector of [4 x i32] to 64-bit values and returns them in
+/// a 128-bit vector of [2 x i64]. The upper two elements of the input vector
+/// are unused.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPMOVZXDQ / PMOVZXDQ </c> instruction.
+///
+/// \param __V
+/// A 128-bit vector of [4 x i32]. The lower two 32-bit elements are zero-
+/// extended to 64-bit values.
+/// \returns A 128-bit vector of [2 x i64] containing the zero-extended values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtepu32_epi64(__m128i __V)
{
@@ -358,6 +1482,28 @@ _mm_cvtepu32_epi64(__m128i __V)
}
/* SSE4 Pack with Unsigned Saturation. */
+/// \brief Converts 32-bit signed integers from both 128-bit integer vector
+/// operands into 16-bit unsigned integers, and returns the packed result.
+/// Values greater than 0xFFFF are saturated to 0xFFFF. Values less than
+/// 0x0000 are saturated to 0x0000.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPACKUSDW / PACKUSDW </c> instruction.
+///
+/// \param __V1
+/// A 128-bit vector of [4 x i32]. Each 32-bit element is treated as a
+/// signed integer and is converted to a 16-bit unsigned integer with
+/// saturation. Values greater than 0xFFFF are saturated to 0xFFFF. Values
+/// less than 0x0000 are saturated to 0x0000. The converted [4 x i16] values
+/// are written to the lower 64 bits of the result.
+/// \param __V2
+/// A 128-bit vector of [4 x i32]. Each 32-bit element is treated as a
+/// signed integer and is converted to a 16-bit unsigned integer with
+/// saturation. Values greater than 0xFFFF are saturated to 0xFFFF. Values
+/// less than 0x0000 are saturated to 0x0000. The converted [4 x i16] values
+/// are written to the higher 64 bits of the result.
+/// \returns A 128-bit vector of [8 x i16] containing the converted values.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_packus_epi32(__m128i __V1, __m128i __V2)
{
@@ -365,10 +1511,58 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
}
/* SSE4 Multiple Packed Sums of Absolute Difference. */
+/// \brief Subtracts 8-bit unsigned integer values and computes the absolute
+/// values of the differences to the corresponding bits in the destination.
+/// Then sums of the absolute differences are returned according to the bit
+/// fields in the immediate operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128i _mm_mpsadbw_epu8(__m128i X, __m128i Y, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VMPSADBW / MPSADBW </c> instruction.
+///
+/// \param X
+/// A 128-bit vector of [16 x i8].
+/// \param Y
+/// A 128-bit vector of [16 x i8].
+/// \param M
+/// An 8-bit immediate operand specifying how the absolute differences are to
+/// be calculated, according to the following algorithm:
+/// \code
+/// // M2 represents bit 2 of the immediate operand
+/// // M10 represents bits [1:0] of the immediate operand
+/// i = M2 * 4
+/// j = M10 * 4
+/// for (k = 0; k < 8; k = k + 1) {
+/// d0 = abs(X[i + k + 0] - Y[j + 0])
+/// d1 = abs(X[i + k + 1] - Y[j + 1])
+/// d2 = abs(X[i + k + 2] - Y[j + 2])
+/// d3 = abs(X[i + k + 3] - Y[j + 3])
+/// r[k] = d0 + d1 + d2 + d3
+/// }
+/// \endcode
+/// \returns A 128-bit integer vector containing the sums of the sets of
+/// absolute differences between both operands.
#define _mm_mpsadbw_epu8(X, Y, M) __extension__ ({ \
(__m128i) __builtin_ia32_mpsadbw128((__v16qi)(__m128i)(X), \
(__v16qi)(__m128i)(Y), (M)); })
+/// \brief Finds the minimum unsigned 16-bit element in the input 128-bit
+/// vector of [8 x u16] and returns it and along with its index.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPHMINPOSUW / PHMINPOSUW </c>
+/// instruction.
+///
+/// \param __V
+/// A 128-bit vector of [8 x u16].
+/// \returns A 128-bit value where bits [15:0] contain the minimum value found
+/// in parameter \a __V, bits [18:16] contain the index of the minimum value
+/// and the remaining bits are set to 0.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_minpos_epu16(__m128i __V)
{
@@ -410,61 +1604,769 @@ _mm_minpos_epu16(__m128i __V)
#define _SIDD_UNIT_MASK 0x40
/* SSE4.2 Packed Comparison Intrinsics. */
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with implicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns a 128-bit integer vector representing the result
+/// mask of the comparison.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128i _mm_cmpistrm(__m128i A, __m128i B, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPISTRM / PCMPISTRM </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words, the type of comparison to perform, and the format of the return
+/// value. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B. \n
+/// Bit [6]: Determines whether the result is zero-extended or expanded to 16
+/// bytes. \n
+/// 0: The result is zero-extended to 16 bytes. \n
+/// 1: The result is expanded to 16 bytes (this expansion is performed by
+/// repeating each bit 8 or 16 times).
+/// \returns Returns a 128-bit integer vector representing the result mask of
+/// the comparison.
#define _mm_cmpistrm(A, B, M) \
(__m128i)__builtin_ia32_pcmpistrm128((__v16qi)(__m128i)(A), \
(__v16qi)(__m128i)(B), (int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with implicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns an integer representing the result index of the
+/// comparison.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpistri(__m128i A, __m128i B, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words, the type of comparison to perform, and the format of the return
+/// value. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B. \n
+/// Bit [6]: Determines whether the index of the lowest set bit or the
+/// highest set bit is returned. \n
+/// 0: The index of the least significant set bit. \n
+/// 1: The index of the most significant set bit. \n
+/// \returns Returns an integer representing the result index of the comparison.
#define _mm_cmpistri(A, B, M) \
(int)__builtin_ia32_pcmpistri128((__v16qi)(__m128i)(A), \
(__v16qi)(__m128i)(B), (int)(M))
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with explicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns a 128-bit integer vector representing the result
+/// mask of the comparison.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// __m128i _mm_cmpestrm(__m128i A, int LA, __m128i B, int LB, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPESTRM / PCMPESTRM </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LA
+/// An integer that specifies the length of the string in \a A.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LB
+/// An integer that specifies the length of the string in \a B.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words, the type of comparison to perform, and the format of the return
+/// value. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B. \n
+/// Bit [6]: Determines whether the result is zero-extended or expanded to 16
+/// bytes. \n
+/// 0: The result is zero-extended to 16 bytes. \n
+/// 1: The result is expanded to 16 bytes (this expansion is performed by
+/// repeating each bit 8 or 16 times). \n
+/// \returns Returns a 128-bit integer vector representing the result mask of
+/// the comparison.
#define _mm_cmpestrm(A, LA, B, LB, M) \
(__m128i)__builtin_ia32_pcmpestrm128((__v16qi)(__m128i)(A), (int)(LA), \
(__v16qi)(__m128i)(B), (int)(LB), \
(int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with explicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns an integer representing the result index of the
+/// comparison.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpestri(__m128i A, int LA, __m128i B, int LB, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LA
+/// An integer that specifies the length of the string in \a A.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LB
+/// An integer that specifies the length of the string in \a B.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words, the type of comparison to perform, and the format of the return
+/// value. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B. \n
+/// Bit [6]: Determines whether the index of the lowest set bit or the
+/// highest set bit is returned. \n
+/// 0: The index of the least significant set bit. \n
+/// 1: The index of the most significant set bit. \n
+/// \returns Returns an integer representing the result index of the comparison.
#define _mm_cmpestri(A, LA, B, LB, M) \
(int)__builtin_ia32_pcmpestri128((__v16qi)(__m128i)(A), (int)(LA), \
(__v16qi)(__m128i)(B), (int)(LB), \
(int)(M))
/* SSE4.2 Packed Comparison Intrinsics and EFlag Reading. */
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with implicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns 1 if the bit mask is zero and the length of the
+/// string in \a B is the maximum, otherwise, returns 0.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpistra(__m128i A, __m128i B, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B. \n
+/// \returns Returns 1 if the bit mask is zero and the length of the string in
+/// \a B is the maximum; otherwise, returns 0.
#define _mm_cmpistra(A, B, M) \
(int)__builtin_ia32_pcmpistria128((__v16qi)(__m128i)(A), \
(__v16qi)(__m128i)(B), (int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with implicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns 1 if the bit mask is non-zero, otherwise, returns
+/// 0.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpistrc(__m128i A, __m128i B, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B.
+/// \returns Returns 1 if the bit mask is non-zero, otherwise, returns 0.
#define _mm_cmpistrc(A, B, M) \
(int)__builtin_ia32_pcmpistric128((__v16qi)(__m128i)(A), \
(__v16qi)(__m128i)(B), (int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with implicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns bit 0 of the resulting bit mask.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpistro(__m128i A, __m128i B, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B. \n
+/// \returns Returns bit 0 of the resulting bit mask.
#define _mm_cmpistro(A, B, M) \
(int)__builtin_ia32_pcmpistrio128((__v16qi)(__m128i)(A), \
(__v16qi)(__m128i)(B), (int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with implicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns 1 if the length of the string in \a A is less than
+/// the maximum, otherwise, returns 0.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpistrs(__m128i A, __m128i B, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B. \n
+/// \returns Returns 1 if the length of the string in \a A is less than the
+/// maximum, otherwise, returns 0.
#define _mm_cmpistrs(A, B, M) \
(int)__builtin_ia32_pcmpistris128((__v16qi)(__m128i)(A), \
(__v16qi)(__m128i)(B), (int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with implicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns 1 if the length of the string in \a B is less than
+/// the maximum, otherwise, returns 0.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpistrz(__m128i A, __m128i B, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPISTRI / PCMPISTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B.
+/// \returns Returns 1 if the length of the string in \a B is less than the
+/// maximum, otherwise, returns 0.
#define _mm_cmpistrz(A, B, M) \
(int)__builtin_ia32_pcmpistriz128((__v16qi)(__m128i)(A), \
(__v16qi)(__m128i)(B), (int)(M))
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with explicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns 1 if the bit mask is zero and the length of the
+/// string in \a B is the maximum, otherwise, returns 0.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpestra(__m128i A, int LA, __m128i B, int LB, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LA
+/// An integer that specifies the length of the string in \a A.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LB
+/// An integer that specifies the length of the string in \a B.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B.
+/// \returns Returns 1 if the bit mask is zero and the length of the string in
+/// \a B is the maximum, otherwise, returns 0.
#define _mm_cmpestra(A, LA, B, LB, M) \
(int)__builtin_ia32_pcmpestria128((__v16qi)(__m128i)(A), (int)(LA), \
(__v16qi)(__m128i)(B), (int)(LB), \
(int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with explicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns 1 if the resulting mask is non-zero, otherwise,
+/// returns 0.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpestrc(__m128i A, int LA, __m128i B, int LB, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LA
+/// An integer that specifies the length of the string in \a A.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LB
+/// An integer that specifies the length of the string in \a B.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B. \n
+/// \returns Returns 1 if the resulting mask is non-zero, otherwise, returns 0.
#define _mm_cmpestrc(A, LA, B, LB, M) \
(int)__builtin_ia32_pcmpestric128((__v16qi)(__m128i)(A), (int)(LA), \
(__v16qi)(__m128i)(B), (int)(LB), \
(int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with explicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns bit 0 of the resulting bit mask.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpestro(__m128i A, int LA, __m128i B, int LB, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LA
+/// An integer that specifies the length of the string in \a A.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LB
+/// An integer that specifies the length of the string in \a B.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B.
+/// \returns Returns bit 0 of the resulting bit mask.
#define _mm_cmpestro(A, LA, B, LB, M) \
(int)__builtin_ia32_pcmpestrio128((__v16qi)(__m128i)(A), (int)(LA), \
(__v16qi)(__m128i)(B), (int)(LB), \
(int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with explicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns 1 if the length of the string in \a A is less than
+/// the maximum, otherwise, returns 0.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpestrs(__m128i A, int LA, __m128i B, int LB, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPESTRI / PCMPESTRI </c>
+/// instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LA
+/// An integer that specifies the length of the string in \a A.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LB
+/// An integer that specifies the length of the string in \a B.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement in the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B. \n
+/// \returns Returns 1 if the length of the string in \a A is less than the
+/// maximum, otherwise, returns 0.
#define _mm_cmpestrs(A, LA, B, LB, M) \
(int)__builtin_ia32_pcmpestris128((__v16qi)(__m128i)(A), (int)(LA), \
(__v16qi)(__m128i)(B), (int)(LB), \
(int)(M))
+
+/// \brief Uses the immediate operand \a M to perform a comparison of string
+/// data with explicitly defined lengths that is contained in source operands
+/// \a A and \a B. Returns 1 if the length of the string in \a B is less than
+/// the maximum, otherwise, returns 0.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// int _mm_cmpestrz(__m128i A, int LA, __m128i B, int LB, const int M);
+/// \endcode
+///
+/// This intrinsic corresponds to the <c> VPCMPESTRI </c> instruction.
+///
+/// \param A
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LA
+/// An integer that specifies the length of the string in \a A.
+/// \param B
+/// A 128-bit integer vector containing one of the source operands to be
+/// compared.
+/// \param LB
+/// An integer that specifies the length of the string in \a B.
+/// \param M
+/// An 8-bit immediate operand specifying whether the characters are bytes or
+/// words and the type of comparison to perform. \n
+/// Bits [1:0]: Determine source data format. \n
+/// 00: 16 unsigned bytes \n
+/// 01: 8 unsigned words \n
+/// 10: 16 signed bytes \n
+/// 11: 8 signed words \n
+/// Bits [3:2]: Determine comparison type and aggregation method. \n
+/// 00: Subset: Each character in \a B is compared for equality with all
+/// the characters in \a A. \n
+/// 01: Ranges: Each character in \a B is compared to \a A. The comparison
+/// basis is greater than or equal for even-indexed elements in \a A,
+/// and less than or equal for odd-indexed elements in \a A. \n
+/// 10: Match: Compare each pair of corresponding characters in \a A and
+/// \a B for equality. \n
+/// 11: Substring: Search \a B for substring matches of \a A. \n
+/// Bits [5:4]: Determine whether to perform a one's complement on the bit
+/// mask of the comparison results. \n
+/// 00: No effect. \n
+/// 01: Negate the bit mask. \n
+/// 10: No effect. \n
+/// 11: Negate the bit mask only for bits with an index less than or equal
+/// to the size of \a A or \a B.
+/// \returns Returns 1 if the length of the string in \a B is less than the
+/// maximum, otherwise, returns 0.
#define _mm_cmpestrz(A, LA, B, LB, M) \
(int)__builtin_ia32_pcmpestriz128((__v16qi)(__m128i)(A), (int)(LA), \
(__v16qi)(__m128i)(B), (int)(LB), \
(int)(M))
/* SSE4.2 Compare Packed Data -- Greater Than. */
+/// \brief Compares each of the corresponding 64-bit values of the 128-bit
+/// integer vectors to determine if the values in the first operand are
+/// greater than those in the second operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VPCMPGTQ / PCMPGTQ </c> instruction.
+///
+/// \param __V1
+/// A 128-bit integer vector.
+/// \param __V2
+/// A 128-bit integer vector.
+/// \returns A 128-bit integer vector containing the comparison results.
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cmpgt_epi64(__m128i __V1, __m128i __V2)
{
@@ -472,18 +2374,60 @@ _mm_cmpgt_epi64(__m128i __V1, __m128i __V2)
}
/* SSE4.2 Accumulate CRC32. */
+/// \brief Adds the unsigned integer operand to the CRC-32C checksum of the
+/// unsigned char operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> CRC32B </c> instruction.
+///
+/// \param __C
+/// An unsigned integer operand to add to the CRC-32C checksum of operand
+/// \a __D.
+/// \param __D
+/// An unsigned 8-bit integer operand used to compute the CRC-32C checksum.
+/// \returns The result of adding operand \a __C to the CRC-32C checksum of
+/// operand \a __D.
static __inline__ unsigned int __DEFAULT_FN_ATTRS
_mm_crc32_u8(unsigned int __C, unsigned char __D)
{
return __builtin_ia32_crc32qi(__C, __D);
}
+/// \brief Adds the unsigned integer operand to the CRC-32C checksum of the
+/// unsigned short operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> CRC32W </c> instruction.
+///
+/// \param __C
+/// An unsigned integer operand to add to the CRC-32C checksum of operand
+/// \a __D.
+/// \param __D
+/// An unsigned 16-bit integer operand used to compute the CRC-32C checksum.
+/// \returns The result of adding operand \a __C to the CRC-32C checksum of
+/// operand \a __D.
static __inline__ unsigned int __DEFAULT_FN_ATTRS
_mm_crc32_u16(unsigned int __C, unsigned short __D)
{
return __builtin_ia32_crc32hi(__C, __D);
}
+/// \brief Adds the first unsigned integer operand to the CRC-32C checksum of
+/// the second unsigned integer operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> CRC32L </c> instruction.
+///
+/// \param __C
+/// An unsigned integer operand to add to the CRC-32C checksum of operand
+/// \a __D.
+/// \param __D
+/// An unsigned 32-bit integer operand used to compute the CRC-32C checksum.
+/// \returns The result of adding operand \a __C to the CRC-32C checksum of
+/// operand \a __D.
static __inline__ unsigned int __DEFAULT_FN_ATTRS
_mm_crc32_u32(unsigned int __C, unsigned int __D)
{
@@ -491,6 +2435,20 @@ _mm_crc32_u32(unsigned int __C, unsigned int __D)
}
#ifdef __x86_64__
+/// \brief Adds the unsigned integer operand to the CRC-32C checksum of the
+/// unsigned 64-bit integer operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> CRC32Q </c> instruction.
+///
+/// \param __C
+/// An unsigned integer operand to add to the CRC-32C checksum of operand
+/// \a __D.
+/// \param __D
+/// An unsigned 64-bit integer operand used to compute the CRC-32C checksum.
+/// \returns The result of adding operand \a __C to the CRC-32C checksum of
+/// operand \a __D.
static __inline__ unsigned long long __DEFAULT_FN_ATTRS
_mm_crc32_u64(unsigned long long __C, unsigned long long __D)
{
diff --git a/contrib/llvm/tools/clang/lib/Headers/stdarg.h b/contrib/llvm/tools/clang/lib/Headers/stdarg.h
index a57e183..101426f 100644
--- a/contrib/llvm/tools/clang/lib/Headers/stdarg.h
+++ b/contrib/llvm/tools/clang/lib/Headers/stdarg.h
@@ -43,10 +43,9 @@ typedef __builtin_va_list va_list;
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#endif
-/* Hack required to make standard headers work, at least on Ubuntu */
#ifndef __GNUC_VA_LIST
#define __GNUC_VA_LIST 1
-#endif
typedef __builtin_va_list __gnuc_va_list;
+#endif
#endif /* __STDARG_H */
diff --git a/contrib/llvm/tools/clang/lib/Headers/stdatomic.h b/contrib/llvm/tools/clang/lib/Headers/stdatomic.h
index 23bb3a3..b4845a7 100644
--- a/contrib/llvm/tools/clang/lib/Headers/stdatomic.h
+++ b/contrib/llvm/tools/clang/lib/Headers/stdatomic.h
@@ -40,16 +40,16 @@ extern "C" {
/* 7.17.1 Introduction */
-#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
-#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
-#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
-#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
-#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
-#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
-#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
-#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
-#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
-#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
+#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE
+#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE
+#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE
+#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE
+#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE
+#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE
+#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE
+#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE
+#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE
+#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE
/* 7.17.2 Initialization */
diff --git a/contrib/llvm/tools/clang/lib/Headers/stdint.h b/contrib/llvm/tools/clang/lib/Headers/stdint.h
index 3f2fcbc..c488153 100644
--- a/contrib/llvm/tools/clang/lib/Headers/stdint.h
+++ b/contrib/llvm/tools/clang/lib/Headers/stdint.h
@@ -255,19 +255,16 @@ typedef __uint_least8_t uint_fast8_t;
*/
#define __stdint_join3(a,b,c) a ## b ## c
-#define __intn_t(n) __stdint_join3( int, n, _t)
-#define __uintn_t(n) __stdint_join3(uint, n, _t)
-
#ifndef _INTPTR_T
#ifndef __intptr_t_defined
-typedef __intn_t(__INTPTR_WIDTH__) intptr_t;
+typedef __INTPTR_TYPE__ intptr_t;
#define __intptr_t_defined
#define _INTPTR_T
#endif
#endif
#ifndef _UINTPTR_T
-typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
#define _UINTPTR_T
#endif
@@ -659,12 +656,12 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */
/* C99 7.18.3 Limits of other integer types. */
-#define INTPTR_MIN __INTN_MIN(__INTPTR_WIDTH__)
-#define INTPTR_MAX __INTN_MAX(__INTPTR_WIDTH__)
-#define UINTPTR_MAX __UINTN_MAX(__INTPTR_WIDTH__)
-#define PTRDIFF_MIN __INTN_MIN(__PTRDIFF_WIDTH__)
-#define PTRDIFF_MAX __INTN_MAX(__PTRDIFF_WIDTH__)
-#define SIZE_MAX __UINTN_MAX(__SIZE_WIDTH__)
+#define INTPTR_MIN (-__INTPTR_MAX__-1)
+#define INTPTR_MAX __INTPTR_MAX__
+#define UINTPTR_MAX __UINTPTR_MAX__
+#define PTRDIFF_MIN (-__PTRDIFF_MAX__-1)
+#define PTRDIFF_MAX __PTRDIFF_MAX__
+#define SIZE_MAX __SIZE_MAX__
/* ISO9899:2011 7.20 (C11 Annex K): Define RSIZE_MAX if __STDC_WANT_LIB_EXT1__
* is enabled. */
@@ -673,9 +670,9 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#endif
/* C99 7.18.2.5 Limits of greatest-width integer types. */
-#define INTMAX_MIN __INTN_MIN(__INTMAX_WIDTH__)
-#define INTMAX_MAX __INTN_MAX(__INTMAX_WIDTH__)
-#define UINTMAX_MAX __UINTN_MAX(__INTMAX_WIDTH__)
+#define INTMAX_MIN (-__INTMAX_MAX__-1)
+#define INTMAX_MAX __INTMAX_MAX__
+#define UINTMAX_MAX __UINTMAX_MAX__
/* C99 7.18.3 Limits of other integer types. */
#define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__)
@@ -700,8 +697,8 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#endif
/* 7.18.4.2 Macros for greatest-width integer constants. */
-#define INTMAX_C(v) __INTN_C(__INTMAX_WIDTH__, v)
-#define UINTMAX_C(v) __UINTN_C(__INTMAX_WIDTH__, v)
+#define INTMAX_C(v) __int_c(v, __INTMAX_C_SUFFIX__)
+#define UINTMAX_C(v) __int_c(v, __UINTMAX_C_SUFFIX__)
#endif /* __STDC_HOSTED__ */
#endif /* __CLANG_STDINT_H */
diff --git a/contrib/llvm/tools/clang/lib/Headers/tgmath.h b/contrib/llvm/tools/clang/lib/Headers/tgmath.h
index 318e118..34e26dc 100644
--- a/contrib/llvm/tools/clang/lib/Headers/tgmath.h
+++ b/contrib/llvm/tools/clang/lib/Headers/tgmath.h
@@ -22,12 +22,21 @@
*
\*===----------------------------------------------------------------------===*/
-#ifndef __TGMATH_H
-#define __TGMATH_H
+#ifndef __CLANG_TGMATH_H
+#define __CLANG_TGMATH_H
/* C99 7.22 Type-generic math <tgmath.h>. */
#include <math.h>
+/*
+ * Allow additional definitions and implementation-defined values on Apple
+ * platforms. This is done after #include <math.h> to avoid depcycle conflicts
+ * between libcxx and darwin in C++ modules builds.
+ */
+#if defined(__APPLE__) && __STDC_HOSTED__ && __has_include_next(<tgmath.h>)
+# include_next <tgmath.h>
+#else
+
/* C++ handles type genericity with overloading in math.h. */
#ifndef __cplusplus
#include <complex.h>
@@ -1371,4 +1380,5 @@ static long double
#undef _TG_ATTRS
#endif /* __cplusplus */
-#endif /* __TGMATH_H */
+#endif /* __has_include_next */
+#endif /* __CLANG_TGMATH_H */
diff --git a/contrib/llvm/tools/clang/lib/Headers/tmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/tmmintrin.h
index 8066404..042bfc7 100644
--- a/contrib/llvm/tools/clang/lib/Headers/tmmintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/tmmintrin.h
@@ -469,10 +469,11 @@ _mm_hsubs_pi16(__m64 __a, __m64 __b)
/// values contained in the first source operand and packed 8-bit signed
/// integer values contained in the second source operand, adds pairs of
/// contiguous products with signed saturation, and writes the 16-bit sums to
-/// the corresponding bits in the destination. For example, bits [7:0] of
-/// both operands are multiplied, bits [15:8] of both operands are
-/// multiplied, and the sum of both results is written to bits [15:0] of the
-/// destination.
+/// the corresponding bits in the destination.
+///
+/// For example, bits [7:0] of both operands are multiplied, bits [15:8] of
+/// both operands are multiplied, and the sum of both results is written to
+/// bits [15:0] of the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -502,10 +503,11 @@ _mm_maddubs_epi16(__m128i __a, __m128i __b)
/// values contained in the first source operand and packed 8-bit signed
/// integer values contained in the second source operand, adds pairs of
/// contiguous products with signed saturation, and writes the 16-bit sums to
-/// the corresponding bits in the destination. For example, bits [7:0] of
-/// both operands are multiplied, bits [15:8] of both operands are
-/// multiplied, and the sum of both results is written to bits [15:0] of the
-/// destination.
+/// the corresponding bits in the destination.
+///
+/// For example, bits [7:0] of both operands are multiplied, bits [15:8] of
+/// both operands are multiplied, and the sum of both results is written to
+/// bits [15:0] of the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -619,13 +621,14 @@ _mm_shuffle_pi8(__m64 __a, __m64 __b)
}
/// \brief For each 8-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// byte in the second source is negative, calculate the two's complement of
-/// the corresponding byte in the first source, and write that value to the
-/// destination. If the byte in the second source is positive, copy the
-/// corresponding byte from the first source to the destination. If the byte
-/// in the second source is zero, clear the corresponding byte in the
-/// destination.
+/// the following actions as specified by the second source operand.
+///
+/// If the byte in the second source is negative, calculate the two's
+/// complement of the corresponding byte in the first source, and write that
+/// value to the destination. If the byte in the second source is positive,
+/// copy the corresponding byte from the first source to the destination. If
+/// the byte in the second source is zero, clear the corresponding byte in
+/// the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -644,13 +647,14 @@ _mm_sign_epi8(__m128i __a, __m128i __b)
}
/// \brief For each 16-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// word in the second source is negative, calculate the two's complement of
-/// the corresponding word in the first source, and write that value to the
-/// destination. If the word in the second source is positive, copy the
-/// corresponding word from the first source to the destination. If the word
-/// in the second source is zero, clear the corresponding word in the
-/// destination.
+/// the following actions as specified by the second source operand.
+///
+/// If the word in the second source is negative, calculate the two's
+/// complement of the corresponding word in the first source, and write that
+/// value to the destination. If the word in the second source is positive,
+/// copy the corresponding word from the first source to the destination. If
+/// the word in the second source is zero, clear the corresponding word in
+/// the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -669,8 +673,9 @@ _mm_sign_epi16(__m128i __a, __m128i __b)
}
/// \brief For each 32-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// doubleword in the second source is negative, calculate the two's
+/// the following actions as specified by the second source operand.
+///
+/// If the doubleword in the second source is negative, calculate the two's
/// complement of the corresponding word in the first source, and write that
/// value to the destination. If the doubleword in the second source is
/// positive, copy the corresponding word from the first source to the
@@ -694,13 +699,14 @@ _mm_sign_epi32(__m128i __a, __m128i __b)
}
/// \brief For each 8-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// byte in the second source is negative, calculate the two's complement of
-/// the corresponding byte in the first source, and write that value to the
-/// destination. If the byte in the second source is positive, copy the
-/// corresponding byte from the first source to the destination. If the byte
-/// in the second source is zero, clear the corresponding byte in the
-/// destination.
+/// the following actions as specified by the second source operand.
+///
+/// If the byte in the second source is negative, calculate the two's
+/// complement of the corresponding byte in the first source, and write that
+/// value to the destination. If the byte in the second source is positive,
+/// copy the corresponding byte from the first source to the destination. If
+/// the byte in the second source is zero, clear the corresponding byte in
+/// the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -719,13 +725,14 @@ _mm_sign_pi8(__m64 __a, __m64 __b)
}
/// \brief For each 16-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// word in the second source is negative, calculate the two's complement of
-/// the corresponding word in the first source, and write that value to the
-/// destination. If the word in the second source is positive, copy the
-/// corresponding word from the first source to the destination. If the word
-/// in the second source is zero, clear the corresponding word in the
-/// destination.
+/// the following actions as specified by the second source operand.
+///
+/// If the word in the second source is negative, calculate the two's
+/// complement of the corresponding word in the first source, and write that
+/// value to the destination. If the word in the second source is positive,
+/// copy the corresponding word from the first source to the destination. If
+/// the word in the second source is zero, clear the corresponding word in
+/// the destination.
///
/// \headerfile <x86intrin.h>
///
@@ -744,8 +751,9 @@ _mm_sign_pi16(__m64 __a, __m64 __b)
}
/// \brief For each 32-bit integer in the first source operand, perform one of
-/// the following actions as specified by the second source operand: If the
-/// doubleword in the second source is negative, calculate the two's
+/// the following actions as specified by the second source operand.
+///
+/// If the doubleword in the second source is negative, calculate the two's
/// complement of the corresponding doubleword in the first source, and
/// write that value to the destination. If the doubleword in the second
/// source is positive, copy the corresponding doubleword from the first
diff --git a/contrib/llvm/tools/clang/lib/Headers/vecintrin.h b/contrib/llvm/tools/clang/lib/Headers/vecintrin.h
index ca7acb4..f7061e8 100644
--- a/contrib/llvm/tools/clang/lib/Headers/vecintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/vecintrin.h
@@ -116,6 +116,13 @@ vec_extract(vector unsigned long long __vec, int __index) {
return __vec[__index & 1];
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai float
+vec_extract(vector float __vec, int __index) {
+ return __vec[__index & 3];
+}
+#endif
+
static inline __ATTRS_o_ai double
vec_extract(vector double __vec, int __index) {
return __vec[__index & 1];
@@ -129,6 +136,7 @@ vec_insert(signed char __scalar, vector signed char __vec, int __index) {
return __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_insert(unsigned char __scalar, vector bool char __vec, int __index) {
vector unsigned char __newvec = (vector unsigned char)__vec;
@@ -148,6 +156,7 @@ vec_insert(signed short __scalar, vector signed short __vec, int __index) {
return __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_insert(unsigned short __scalar, vector bool short __vec, int __index) {
vector unsigned short __newvec = (vector unsigned short)__vec;
@@ -167,6 +176,7 @@ vec_insert(signed int __scalar, vector signed int __vec, int __index) {
return __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_insert(unsigned int __scalar, vector bool int __vec, int __index) {
vector unsigned int __newvec = (vector unsigned int)__vec;
@@ -187,6 +197,7 @@ vec_insert(signed long long __scalar, vector signed long long __vec,
return __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_insert(unsigned long long __scalar, vector bool long long __vec,
int __index) {
@@ -202,6 +213,14 @@ vec_insert(unsigned long long __scalar, vector unsigned long long __vec,
return __vec;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_insert(float __scalar, vector float __vec, int __index) {
+ __vec[__index & 1] = __scalar;
+ return __vec;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_insert(double __scalar, vector double __vec, int __index) {
__vec[__index & 1] = __scalar;
@@ -282,6 +301,16 @@ vec_promote(unsigned long long __scalar, int __index) {
return __vec;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_promote(float __scalar, int __index) {
+ const vector float __zero = (vector float)0;
+ vector float __vec = __builtin_shufflevector(__zero, __zero, -1, -1, -1, -1);
+ __vec[__index & 3] = __scalar;
+ return __vec;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_promote(double __scalar, int __index) {
const vector double __zero = (vector double)0;
@@ -348,6 +377,15 @@ vec_insert_and_zero(const unsigned long long *__ptr) {
return __vec;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_insert_and_zero(const float *__ptr) {
+ vector float __vec = (vector float)0;
+ __vec[0] = *__ptr;
+ return __vec;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_insert_and_zero(const double *__ptr) {
vector double __vec = (vector double)0;
@@ -441,6 +479,15 @@ vec_perm(vector bool long long __a, vector bool long long __b,
(vector unsigned char)__a, (vector unsigned char)__b, __c);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_perm(vector float __a, vector float __b,
+ vector unsigned char __c) {
+ return (vector float)__builtin_s390_vperm(
+ (vector unsigned char)__a, (vector unsigned char)__b, __c);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_perm(vector double __a, vector double __b,
vector unsigned char __c) {
@@ -450,18 +497,22 @@ vec_perm(vector double __a, vector double __b,
/*-- vec_permi --------------------------------------------------------------*/
+// This prototype is deprecated.
extern __ATTRS_o vector signed long long
vec_permi(vector signed long long __a, vector signed long long __b, int __c)
__constant_range(__c, 0, 3);
+// This prototype is deprecated.
extern __ATTRS_o vector unsigned long long
vec_permi(vector unsigned long long __a, vector unsigned long long __b, int __c)
__constant_range(__c, 0, 3);
+// This prototype is deprecated.
extern __ATTRS_o vector bool long long
vec_permi(vector bool long long __a, vector bool long long __b, int __c)
__constant_range(__c, 0, 3);
+// This prototype is deprecated.
extern __ATTRS_o vector double
vec_permi(vector double __a, vector double __b, int __c)
__constant_range(__c, 0, 3);
@@ -471,6 +522,15 @@ vec_permi(vector double __a, vector double __b, int __c)
(vector unsigned long long)(Y), \
(((Z) & 2) << 1) | ((Z) & 1)))
+/*-- vec_bperm_u128 ---------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_ai vector unsigned long long
+vec_bperm_u128(vector unsigned char __a, vector unsigned char __b) {
+ return __builtin_s390_vbperm(__a, __b);
+}
+#endif
+
/*-- vec_sel ----------------------------------------------------------------*/
static inline __ATTRS_o_ai vector signed char
@@ -614,6 +674,22 @@ vec_sel(vector unsigned long long __a, vector unsigned long long __b,
(~(vector unsigned long long)__c & __a));
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_sel(vector float __a, vector float __b, vector unsigned int __c) {
+ return (vector float)((__c & (vector unsigned int)__b) |
+ (~__c & (vector unsigned int)__a));
+}
+
+static inline __ATTRS_o_ai vector float
+vec_sel(vector float __a, vector float __b, vector bool int __c) {
+ vector unsigned int __ac = (vector unsigned int)__a;
+ vector unsigned int __bc = (vector unsigned int)__b;
+ vector unsigned int __cc = (vector unsigned int)__c;
+ return (vector float)((__cc & __bc) | (~__cc & __ac));
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_sel(vector double __a, vector double __b, vector unsigned long long __c) {
return (vector double)((__c & (vector unsigned long long)__b) |
@@ -687,6 +763,17 @@ vec_gather_element(vector unsigned long long __vec,
return __vec;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_gather_element(vector float __vec, vector unsigned int __offset,
+ const float *__ptr, int __index)
+ __constant_range(__index, 0, 3) {
+ __vec[__index] = *(const float *)(
+ (__INTPTR_TYPE__)__ptr + (__INTPTR_TYPE__)__offset[__index]);
+ return __vec;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_gather_element(vector double __vec, vector unsigned long long __offset,
const double *__ptr, int __index)
@@ -749,6 +836,16 @@ vec_scatter_element(vector unsigned long long __vec,
__vec[__index];
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai void
+vec_scatter_element(vector float __vec, vector unsigned int __offset,
+ float *__ptr, int __index)
+ __constant_range(__index, 0, 3) {
+ *(float *)((__INTPTR_TYPE__)__ptr + __offset[__index]) =
+ __vec[__index];
+}
+#endif
+
static inline __ATTRS_o_ai void
vec_scatter_element(vector double __vec, vector unsigned long long __offset,
double *__ptr, int __index)
@@ -757,48 +854,111 @@ vec_scatter_element(vector double __vec, vector unsigned long long __offset,
__vec[__index];
}
+/*-- vec_xl -----------------------------------------------------------------*/
+
+static inline __ATTRS_o_ai vector signed char
+vec_xl(long __offset, const signed char *__ptr) {
+ return *(const vector signed char *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector unsigned char
+vec_xl(long __offset, const unsigned char *__ptr) {
+ return *(const vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector signed short
+vec_xl(long __offset, const signed short *__ptr) {
+ return *(const vector signed short *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector unsigned short
+vec_xl(long __offset, const unsigned short *__ptr) {
+ return *(const vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector signed int
+vec_xl(long __offset, const signed int *__ptr) {
+ return *(const vector signed int *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector unsigned int
+vec_xl(long __offset, const unsigned int *__ptr) {
+ return *(const vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector signed long long
+vec_xl(long __offset, const signed long long *__ptr) {
+ return *(const vector signed long long *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_xl(long __offset, const unsigned long long *__ptr) {
+ return *(const vector unsigned long long *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_xl(long __offset, const float *__ptr) {
+ return *(const vector float *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
+vec_xl(long __offset, const double *__ptr) {
+ return *(const vector double *)((__INTPTR_TYPE__)__ptr + __offset);
+}
+
/*-- vec_xld2 ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_xld2(long __offset, const signed char *__ptr) {
return *(const vector signed char *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_xld2(long __offset, const unsigned char *__ptr) {
return *(const vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_xld2(long __offset, const signed short *__ptr) {
return *(const vector signed short *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_xld2(long __offset, const unsigned short *__ptr) {
return *(const vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_xld2(long __offset, const signed int *__ptr) {
return *(const vector signed int *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_xld2(long __offset, const unsigned int *__ptr) {
return *(const vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_xld2(long __offset, const signed long long *__ptr) {
return *(const vector signed long long *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_xld2(long __offset, const unsigned long long *__ptr) {
return *(const vector unsigned long long *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_xld2(long __offset, const double *__ptr) {
return *(const vector double *)((__INTPTR_TYPE__)__ptr + __offset);
@@ -806,74 +966,145 @@ vec_xld2(long __offset, const double *__ptr) {
/*-- vec_xlw4 ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_xlw4(long __offset, const signed char *__ptr) {
return *(const vector signed char *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_xlw4(long __offset, const unsigned char *__ptr) {
return *(const vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_xlw4(long __offset, const signed short *__ptr) {
return *(const vector signed short *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_xlw4(long __offset, const unsigned short *__ptr) {
return *(const vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_xlw4(long __offset, const signed int *__ptr) {
return *(const vector signed int *)((__INTPTR_TYPE__)__ptr + __offset);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_xlw4(long __offset, const unsigned int *__ptr) {
return *(const vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset);
}
+/*-- vec_xst ----------------------------------------------------------------*/
+
+static inline __ATTRS_o_ai void
+vec_xst(vector signed char __vec, long __offset, signed char *__ptr) {
+ *(vector signed char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector unsigned char __vec, long __offset, unsigned char *__ptr) {
+ *(vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector signed short __vec, long __offset, signed short *__ptr) {
+ *(vector signed short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector unsigned short __vec, long __offset, unsigned short *__ptr) {
+ *(vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector signed int __vec, long __offset, signed int *__ptr) {
+ *(vector signed int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector unsigned int __vec, long __offset, unsigned int *__ptr) {
+ *(vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector signed long long __vec, long __offset,
+ signed long long *__ptr) {
+ *(vector signed long long *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
+static inline __ATTRS_o_ai void
+vec_xst(vector unsigned long long __vec, long __offset,
+ unsigned long long *__ptr) {
+ *(vector unsigned long long *)((__INTPTR_TYPE__)__ptr + __offset) =
+ __vec;
+}
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai void
+vec_xst(vector float __vec, long __offset, float *__ptr) {
+ *(vector float *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+#endif
+
+static inline __ATTRS_o_ai void
+vec_xst(vector double __vec, long __offset, double *__ptr) {
+ *(vector double *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
+}
+
/*-- vec_xstd2 --------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector signed char __vec, long __offset, signed char *__ptr) {
*(vector signed char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector unsigned char __vec, long __offset, unsigned char *__ptr) {
*(vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector signed short __vec, long __offset, signed short *__ptr) {
*(vector signed short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector unsigned short __vec, long __offset, unsigned short *__ptr) {
*(vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector signed int __vec, long __offset, signed int *__ptr) {
*(vector signed int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector unsigned int __vec, long __offset, unsigned int *__ptr) {
*(vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector signed long long __vec, long __offset,
signed long long *__ptr) {
*(vector signed long long *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector unsigned long long __vec, long __offset,
unsigned long long *__ptr) {
@@ -881,6 +1112,7 @@ vec_xstd2(vector unsigned long long __vec, long __offset,
__vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstd2(vector double __vec, long __offset, double *__ptr) {
*(vector double *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
@@ -888,31 +1120,37 @@ vec_xstd2(vector double __vec, long __offset, double *__ptr) {
/*-- vec_xstw4 --------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector signed char __vec, long __offset, signed char *__ptr) {
*(vector signed char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector unsigned char __vec, long __offset, unsigned char *__ptr) {
*(vector unsigned char *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector signed short __vec, long __offset, signed short *__ptr) {
*(vector signed short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector unsigned short __vec, long __offset, unsigned short *__ptr) {
*(vector unsigned short *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector signed int __vec, long __offset, signed int *__ptr) {
*(vector signed int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai void
vec_xstw4(vector unsigned int __vec, long __offset, unsigned int *__ptr) {
*(vector unsigned int *)((__INTPTR_TYPE__)__ptr + __offset) = __vec;
@@ -952,6 +1190,12 @@ extern __ATTRS_o vector unsigned long long
vec_load_bndry(const unsigned long long *__ptr, unsigned short __len)
__constant_pow2_range(__len, 64, 4096);
+#if __ARCH__ >= 12
+extern __ATTRS_o vector float
+vec_load_bndry(const float *__ptr, unsigned short __len)
+ __constant_pow2_range(__len, 64, 4096);
+#endif
+
extern __ATTRS_o vector double
vec_load_bndry(const double *__ptr, unsigned short __len)
__constant_pow2_range(__len, 64, 4096);
@@ -1007,11 +1251,27 @@ vec_load_len(const unsigned long long *__ptr, unsigned int __len) {
return (vector unsigned long long)__builtin_s390_vll(__len, __ptr);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_load_len(const float *__ptr, unsigned int __len) {
+ return (vector float)__builtin_s390_vll(__len, __ptr);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_load_len(const double *__ptr, unsigned int __len) {
return (vector double)__builtin_s390_vll(__len, __ptr);
}
+/*-- vec_load_len_r ---------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_ai vector unsigned char
+vec_load_len_r(const unsigned char *__ptr, unsigned int __len) {
+ return (vector unsigned char)__builtin_s390_vlrl(__len, __ptr);
+}
+#endif
+
/*-- vec_store_len ----------------------------------------------------------*/
static inline __ATTRS_o_ai void
@@ -1062,12 +1322,30 @@ vec_store_len(vector unsigned long long __vec, unsigned long long *__ptr,
__builtin_s390_vstl((vector signed char)__vec, __len, __ptr);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai void
+vec_store_len(vector float __vec, float *__ptr,
+ unsigned int __len) {
+ __builtin_s390_vstl((vector signed char)__vec, __len, __ptr);
+}
+#endif
+
static inline __ATTRS_o_ai void
vec_store_len(vector double __vec, double *__ptr,
unsigned int __len) {
__builtin_s390_vstl((vector signed char)__vec, __len, __ptr);
}
+/*-- vec_store_len_r --------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_ai void
+vec_store_len_r(vector unsigned char __vec, unsigned char *__ptr,
+ unsigned int __len) {
+ __builtin_s390_vstrl((vector signed char)__vec, __len, __ptr);
+}
+#endif
+
/*-- vec_load_pair ----------------------------------------------------------*/
static inline __ATTRS_o_ai vector signed long long
@@ -1232,6 +1510,14 @@ vec_splat(vector unsigned long long __vec, int __index)
return (vector unsigned long long)__vec[__index];
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_splat(vector float __vec, int __index)
+ __constant_range(__index, 0, 3) {
+ return (vector float)__vec[__index];
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_splat(vector double __vec, int __index)
__constant_range(__index, 0, 1) {
@@ -1332,6 +1618,13 @@ vec_splats(unsigned long long __scalar) {
return (vector unsigned long long)__scalar;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_splats(float __scalar) {
+ return (vector float)__scalar;
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_splats(double __scalar) {
return (vector double)__scalar;
@@ -1425,6 +1718,13 @@ vec_mergeh(vector unsigned long long __a, vector unsigned long long __b) {
return (vector unsigned long long)(__a[0], __b[0]);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_mergeh(vector float __a, vector float __b) {
+ return (vector float)(__a[0], __b[0], __a[1], __b[1]);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_mergeh(vector double __a, vector double __b) {
return (vector double)(__a[0], __b[0]);
@@ -1501,6 +1801,13 @@ vec_mergel(vector unsigned long long __a, vector unsigned long long __b) {
return (vector unsigned long long)(__a[1], __b[1]);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_mergel(vector float __a, vector float __b) {
+ return (vector float)(__a[2], __b[2], __a[3], __b[3]);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_mergel(vector double __a, vector double __b) {
return (vector double)(__a[1], __b[1]);
@@ -1866,6 +2173,13 @@ vec_cmpeq(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a == __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmpeq(vector float __a, vector float __b) {
+ return (vector bool int)(__a == __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmpeq(vector double __a, vector double __b) {
return (vector bool long long)(__a == __b);
@@ -1913,6 +2227,13 @@ vec_cmpge(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a >= __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmpge(vector float __a, vector float __b) {
+ return (vector bool int)(__a >= __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmpge(vector double __a, vector double __b) {
return (vector bool long long)(__a >= __b);
@@ -1960,6 +2281,13 @@ vec_cmpgt(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a > __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmpgt(vector float __a, vector float __b) {
+ return (vector bool int)(__a > __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmpgt(vector double __a, vector double __b) {
return (vector bool long long)(__a > __b);
@@ -2007,6 +2335,13 @@ vec_cmple(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a <= __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmple(vector float __a, vector float __b) {
+ return (vector bool int)(__a <= __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmple(vector double __a, vector double __b) {
return (vector bool long long)(__a <= __b);
@@ -2054,6 +2389,13 @@ vec_cmplt(vector unsigned long long __a, vector unsigned long long __b) {
return (vector bool long long)(__a < __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool int
+vec_cmplt(vector float __a, vector float __b) {
+ return (vector bool int)(__a < __b);
+}
+#endif
+
static inline __ATTRS_o_ai vector bool long long
vec_cmplt(vector double __a, vector double __b) {
return (vector bool long long)(__a < __b);
@@ -2068,6 +2410,7 @@ vec_all_eq(vector signed char __a, vector signed char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2075,6 +2418,7 @@ vec_all_eq(vector signed char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2090,6 +2434,7 @@ vec_all_eq(vector unsigned char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2098,6 +2443,7 @@ vec_all_eq(vector unsigned char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2121,6 +2467,7 @@ vec_all_eq(vector signed short __a, vector signed short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2128,6 +2475,7 @@ vec_all_eq(vector signed short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2143,6 +2491,7 @@ vec_all_eq(vector unsigned short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -2151,6 +2500,7 @@ vec_all_eq(vector unsigned short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -2174,6 +2524,7 @@ vec_all_eq(vector signed int __a, vector signed int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector signed int __a, vector bool int __b) {
int __cc;
@@ -2181,6 +2532,7 @@ vec_all_eq(vector signed int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool int __a, vector signed int __b) {
int __cc;
@@ -2196,6 +2548,7 @@ vec_all_eq(vector unsigned int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -2204,6 +2557,7 @@ vec_all_eq(vector unsigned int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -2227,6 +2581,7 @@ vec_all_eq(vector signed long long __a, vector signed long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -2234,6 +2589,7 @@ vec_all_eq(vector signed long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -2249,6 +2605,7 @@ vec_all_eq(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -2257,6 +2614,7 @@ vec_all_eq(vector unsigned long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_eq(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -2273,6 +2631,15 @@ vec_all_eq(vector bool long long __a, vector bool long long __b) {
return __cc == 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_eq(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfcesbs(__a, __b, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_eq(vector double __a, vector double __b) {
int __cc;
@@ -2289,6 +2656,7 @@ vec_all_ne(vector signed char __a, vector signed char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2296,6 +2664,7 @@ vec_all_ne(vector signed char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2311,6 +2680,7 @@ vec_all_ne(vector unsigned char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2319,6 +2689,7 @@ vec_all_ne(vector unsigned char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2342,6 +2713,7 @@ vec_all_ne(vector signed short __a, vector signed short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2349,6 +2721,7 @@ vec_all_ne(vector signed short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2364,6 +2737,7 @@ vec_all_ne(vector unsigned short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -2372,6 +2746,7 @@ vec_all_ne(vector unsigned short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -2395,6 +2770,7 @@ vec_all_ne(vector signed int __a, vector signed int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector signed int __a, vector bool int __b) {
int __cc;
@@ -2402,6 +2778,7 @@ vec_all_ne(vector signed int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool int __a, vector signed int __b) {
int __cc;
@@ -2417,6 +2794,7 @@ vec_all_ne(vector unsigned int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -2425,6 +2803,7 @@ vec_all_ne(vector unsigned int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -2448,6 +2827,7 @@ vec_all_ne(vector signed long long __a, vector signed long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -2455,6 +2835,7 @@ vec_all_ne(vector signed long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -2470,6 +2851,7 @@ vec_all_ne(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -2478,6 +2860,7 @@ vec_all_ne(vector unsigned long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ne(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -2494,6 +2877,15 @@ vec_all_ne(vector bool long long __a, vector bool long long __b) {
return __cc == 3;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_ne(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfcesbs(__a, __b, &__cc);
+ return __cc == 3;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_ne(vector double __a, vector double __b) {
int __cc;
@@ -2510,6 +2902,7 @@ vec_all_ge(vector signed char __a, vector signed char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2517,6 +2910,7 @@ vec_all_ge(vector signed char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2531,6 +2925,7 @@ vec_all_ge(vector unsigned char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2538,6 +2933,7 @@ vec_all_ge(vector unsigned char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2545,6 +2941,7 @@ vec_all_ge(vector bool char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool char __a, vector bool char __b) {
int __cc;
@@ -2560,6 +2957,7 @@ vec_all_ge(vector signed short __a, vector signed short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2567,6 +2965,7 @@ vec_all_ge(vector signed short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2581,6 +2980,7 @@ vec_all_ge(vector unsigned short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -2588,6 +2988,7 @@ vec_all_ge(vector unsigned short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -2595,6 +2996,7 @@ vec_all_ge(vector bool short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool short __a, vector bool short __b) {
int __cc;
@@ -2610,6 +3012,7 @@ vec_all_ge(vector signed int __a, vector signed int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector signed int __a, vector bool int __b) {
int __cc;
@@ -2617,6 +3020,7 @@ vec_all_ge(vector signed int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool int __a, vector signed int __b) {
int __cc;
@@ -2631,6 +3035,7 @@ vec_all_ge(vector unsigned int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -2638,6 +3043,7 @@ vec_all_ge(vector unsigned int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -2645,6 +3051,7 @@ vec_all_ge(vector bool int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool int __a, vector bool int __b) {
int __cc;
@@ -2660,6 +3067,7 @@ vec_all_ge(vector signed long long __a, vector signed long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -2667,6 +3075,7 @@ vec_all_ge(vector signed long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -2681,6 +3090,7 @@ vec_all_ge(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -2688,6 +3098,7 @@ vec_all_ge(vector unsigned long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -2695,6 +3106,7 @@ vec_all_ge(vector bool long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_ge(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -2703,6 +3115,15 @@ vec_all_ge(vector bool long long __a, vector bool long long __b) {
return __cc == 3;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_ge(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__a, __b, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_ge(vector double __a, vector double __b) {
int __cc;
@@ -2719,6 +3140,7 @@ vec_all_gt(vector signed char __a, vector signed char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2726,6 +3148,7 @@ vec_all_gt(vector signed char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2740,6 +3163,7 @@ vec_all_gt(vector unsigned char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2747,6 +3171,7 @@ vec_all_gt(vector unsigned char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2754,6 +3179,7 @@ vec_all_gt(vector bool char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool char __a, vector bool char __b) {
int __cc;
@@ -2769,6 +3195,7 @@ vec_all_gt(vector signed short __a, vector signed short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2776,6 +3203,7 @@ vec_all_gt(vector signed short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2790,6 +3218,7 @@ vec_all_gt(vector unsigned short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -2797,6 +3226,7 @@ vec_all_gt(vector unsigned short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -2804,6 +3234,7 @@ vec_all_gt(vector bool short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool short __a, vector bool short __b) {
int __cc;
@@ -2819,6 +3250,7 @@ vec_all_gt(vector signed int __a, vector signed int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector signed int __a, vector bool int __b) {
int __cc;
@@ -2826,6 +3258,7 @@ vec_all_gt(vector signed int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool int __a, vector signed int __b) {
int __cc;
@@ -2840,6 +3273,7 @@ vec_all_gt(vector unsigned int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -2847,6 +3281,7 @@ vec_all_gt(vector unsigned int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -2854,6 +3289,7 @@ vec_all_gt(vector bool int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool int __a, vector bool int __b) {
int __cc;
@@ -2869,6 +3305,7 @@ vec_all_gt(vector signed long long __a, vector signed long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -2876,6 +3313,7 @@ vec_all_gt(vector signed long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -2890,6 +3328,7 @@ vec_all_gt(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -2897,6 +3336,7 @@ vec_all_gt(vector unsigned long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -2904,6 +3344,7 @@ vec_all_gt(vector bool long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_gt(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -2912,6 +3353,15 @@ vec_all_gt(vector bool long long __a, vector bool long long __b) {
return __cc == 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_gt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__a, __b, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_gt(vector double __a, vector double __b) {
int __cc;
@@ -2928,6 +3378,7 @@ vec_all_le(vector signed char __a, vector signed char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector signed char __a, vector bool char __b) {
int __cc;
@@ -2935,6 +3386,7 @@ vec_all_le(vector signed char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool char __a, vector signed char __b) {
int __cc;
@@ -2949,6 +3401,7 @@ vec_all_le(vector unsigned char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -2956,6 +3409,7 @@ vec_all_le(vector unsigned char __a, vector bool char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -2963,6 +3417,7 @@ vec_all_le(vector bool char __a, vector unsigned char __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool char __a, vector bool char __b) {
int __cc;
@@ -2978,6 +3433,7 @@ vec_all_le(vector signed short __a, vector signed short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector signed short __a, vector bool short __b) {
int __cc;
@@ -2985,6 +3441,7 @@ vec_all_le(vector signed short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool short __a, vector signed short __b) {
int __cc;
@@ -2999,6 +3456,7 @@ vec_all_le(vector unsigned short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3006,6 +3464,7 @@ vec_all_le(vector unsigned short __a, vector bool short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3013,6 +3472,7 @@ vec_all_le(vector bool short __a, vector unsigned short __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool short __a, vector bool short __b) {
int __cc;
@@ -3028,6 +3488,7 @@ vec_all_le(vector signed int __a, vector signed int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3035,6 +3496,7 @@ vec_all_le(vector signed int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3049,6 +3511,7 @@ vec_all_le(vector unsigned int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3056,6 +3519,7 @@ vec_all_le(vector unsigned int __a, vector bool int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3063,6 +3527,7 @@ vec_all_le(vector bool int __a, vector unsigned int __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool int __a, vector bool int __b) {
int __cc;
@@ -3078,6 +3543,7 @@ vec_all_le(vector signed long long __a, vector signed long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3085,6 +3551,7 @@ vec_all_le(vector signed long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -3099,6 +3566,7 @@ vec_all_le(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -3106,6 +3574,7 @@ vec_all_le(vector unsigned long long __a, vector bool long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -3113,6 +3582,7 @@ vec_all_le(vector bool long long __a, vector unsigned long long __b) {
return __cc == 3;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_le(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -3121,6 +3591,15 @@ vec_all_le(vector bool long long __a, vector bool long long __b) {
return __cc == 3;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_le(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__b, __a, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_le(vector double __a, vector double __b) {
int __cc;
@@ -3137,6 +3616,7 @@ vec_all_lt(vector signed char __a, vector signed char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector signed char __a, vector bool char __b) {
int __cc;
@@ -3144,6 +3624,7 @@ vec_all_lt(vector signed char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool char __a, vector signed char __b) {
int __cc;
@@ -3158,6 +3639,7 @@ vec_all_lt(vector unsigned char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -3165,6 +3647,7 @@ vec_all_lt(vector unsigned char __a, vector bool char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -3172,6 +3655,7 @@ vec_all_lt(vector bool char __a, vector unsigned char __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool char __a, vector bool char __b) {
int __cc;
@@ -3187,6 +3671,7 @@ vec_all_lt(vector signed short __a, vector signed short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector signed short __a, vector bool short __b) {
int __cc;
@@ -3194,6 +3679,7 @@ vec_all_lt(vector signed short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool short __a, vector signed short __b) {
int __cc;
@@ -3208,6 +3694,7 @@ vec_all_lt(vector unsigned short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3215,6 +3702,7 @@ vec_all_lt(vector unsigned short __a, vector bool short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3222,6 +3710,7 @@ vec_all_lt(vector bool short __a, vector unsigned short __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool short __a, vector bool short __b) {
int __cc;
@@ -3237,6 +3726,7 @@ vec_all_lt(vector signed int __a, vector signed int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3244,6 +3734,7 @@ vec_all_lt(vector signed int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3258,6 +3749,7 @@ vec_all_lt(vector unsigned int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3265,6 +3757,7 @@ vec_all_lt(vector unsigned int __a, vector bool int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3272,6 +3765,7 @@ vec_all_lt(vector bool int __a, vector unsigned int __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool int __a, vector bool int __b) {
int __cc;
@@ -3287,6 +3781,7 @@ vec_all_lt(vector signed long long __a, vector signed long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3294,6 +3789,7 @@ vec_all_lt(vector signed long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -3308,6 +3804,7 @@ vec_all_lt(vector unsigned long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -3315,6 +3812,7 @@ vec_all_lt(vector unsigned long long __a, vector bool long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -3322,6 +3820,7 @@ vec_all_lt(vector bool long long __a, vector unsigned long long __b) {
return __cc == 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_all_lt(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -3330,6 +3829,15 @@ vec_all_lt(vector bool long long __a, vector bool long long __b) {
return __cc == 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_lt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__b, __a, &__cc);
+ return __cc == 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_all_lt(vector double __a, vector double __b) {
int __cc;
@@ -3339,7 +3847,16 @@ vec_all_lt(vector double __a, vector double __b) {
/*-- vec_all_nge ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_nge(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__a, __b, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_nge(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchedbs(__a, __b, &__cc);
@@ -3348,7 +3865,16 @@ vec_all_nge(vector double __a, vector double __b) {
/*-- vec_all_ngt ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_ngt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__a, __b, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_ngt(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchdbs(__a, __b, &__cc);
@@ -3357,7 +3883,16 @@ vec_all_ngt(vector double __a, vector double __b) {
/*-- vec_all_nle ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_nle(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__b, __a, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_nle(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchedbs(__b, __a, &__cc);
@@ -3366,7 +3901,16 @@ vec_all_nle(vector double __a, vector double __b) {
/*-- vec_all_nlt ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_nlt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__b, __a, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_nlt(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchdbs(__b, __a, &__cc);
@@ -3375,7 +3919,16 @@ vec_all_nlt(vector double __a, vector double __b) {
/*-- vec_all_nan ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_nan(vector float __a) {
+ int __cc;
+ __builtin_s390_vftcisb(__a, 15, &__cc);
+ return __cc == 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_nan(vector double __a) {
int __cc;
__builtin_s390_vftcidb(__a, 15, &__cc);
@@ -3384,7 +3937,16 @@ vec_all_nan(vector double __a) {
/*-- vec_all_numeric --------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_all_numeric(vector float __a) {
+ int __cc;
+ __builtin_s390_vftcisb(__a, 15, &__cc);
+ return __cc == 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_all_numeric(vector double __a) {
int __cc;
__builtin_s390_vftcidb(__a, 15, &__cc);
@@ -3400,6 +3962,7 @@ vec_any_eq(vector signed char __a, vector signed char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector signed char __a, vector bool char __b) {
int __cc;
@@ -3407,6 +3970,7 @@ vec_any_eq(vector signed char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool char __a, vector signed char __b) {
int __cc;
@@ -3422,6 +3986,7 @@ vec_any_eq(vector unsigned char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -3430,6 +3995,7 @@ vec_any_eq(vector unsigned char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -3453,6 +4019,7 @@ vec_any_eq(vector signed short __a, vector signed short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector signed short __a, vector bool short __b) {
int __cc;
@@ -3460,6 +4027,7 @@ vec_any_eq(vector signed short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool short __a, vector signed short __b) {
int __cc;
@@ -3475,6 +4043,7 @@ vec_any_eq(vector unsigned short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3483,6 +4052,7 @@ vec_any_eq(vector unsigned short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3506,6 +4076,7 @@ vec_any_eq(vector signed int __a, vector signed int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3513,6 +4084,7 @@ vec_any_eq(vector signed int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3528,6 +4100,7 @@ vec_any_eq(vector unsigned int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3536,6 +4109,7 @@ vec_any_eq(vector unsigned int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3559,6 +4133,7 @@ vec_any_eq(vector signed long long __a, vector signed long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3566,6 +4141,7 @@ vec_any_eq(vector signed long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -3581,6 +4157,7 @@ vec_any_eq(vector unsigned long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -3589,6 +4166,7 @@ vec_any_eq(vector unsigned long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_eq(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -3605,6 +4183,15 @@ vec_any_eq(vector bool long long __a, vector bool long long __b) {
return __cc <= 1;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_eq(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfcesbs(__a, __b, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_eq(vector double __a, vector double __b) {
int __cc;
@@ -3621,6 +4208,7 @@ vec_any_ne(vector signed char __a, vector signed char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector signed char __a, vector bool char __b) {
int __cc;
@@ -3628,6 +4216,7 @@ vec_any_ne(vector signed char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool char __a, vector signed char __b) {
int __cc;
@@ -3643,6 +4232,7 @@ vec_any_ne(vector unsigned char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -3651,6 +4241,7 @@ vec_any_ne(vector unsigned char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -3674,6 +4265,7 @@ vec_any_ne(vector signed short __a, vector signed short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector signed short __a, vector bool short __b) {
int __cc;
@@ -3681,6 +4273,7 @@ vec_any_ne(vector signed short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool short __a, vector signed short __b) {
int __cc;
@@ -3696,6 +4289,7 @@ vec_any_ne(vector unsigned short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3704,6 +4298,7 @@ vec_any_ne(vector unsigned short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3727,6 +4322,7 @@ vec_any_ne(vector signed int __a, vector signed int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3734,6 +4330,7 @@ vec_any_ne(vector signed int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3749,6 +4346,7 @@ vec_any_ne(vector unsigned int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3757,6 +4355,7 @@ vec_any_ne(vector unsigned int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3780,6 +4379,7 @@ vec_any_ne(vector signed long long __a, vector signed long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3787,6 +4387,7 @@ vec_any_ne(vector signed long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -3802,6 +4403,7 @@ vec_any_ne(vector unsigned long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -3810,6 +4412,7 @@ vec_any_ne(vector unsigned long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ne(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -3826,6 +4429,15 @@ vec_any_ne(vector bool long long __a, vector bool long long __b) {
return __cc != 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_ne(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfcesbs(__a, __b, &__cc);
+ return __cc != 0;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_ne(vector double __a, vector double __b) {
int __cc;
@@ -3842,6 +4454,7 @@ vec_any_ge(vector signed char __a, vector signed char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector signed char __a, vector bool char __b) {
int __cc;
@@ -3849,6 +4462,7 @@ vec_any_ge(vector signed char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool char __a, vector signed char __b) {
int __cc;
@@ -3863,6 +4477,7 @@ vec_any_ge(vector unsigned char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -3870,6 +4485,7 @@ vec_any_ge(vector unsigned char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -3877,6 +4493,7 @@ vec_any_ge(vector bool char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool char __a, vector bool char __b) {
int __cc;
@@ -3892,6 +4509,7 @@ vec_any_ge(vector signed short __a, vector signed short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector signed short __a, vector bool short __b) {
int __cc;
@@ -3899,6 +4517,7 @@ vec_any_ge(vector signed short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool short __a, vector signed short __b) {
int __cc;
@@ -3913,6 +4532,7 @@ vec_any_ge(vector unsigned short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -3920,6 +4540,7 @@ vec_any_ge(vector unsigned short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -3927,6 +4548,7 @@ vec_any_ge(vector bool short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool short __a, vector bool short __b) {
int __cc;
@@ -3942,6 +4564,7 @@ vec_any_ge(vector signed int __a, vector signed int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector signed int __a, vector bool int __b) {
int __cc;
@@ -3949,6 +4572,7 @@ vec_any_ge(vector signed int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool int __a, vector signed int __b) {
int __cc;
@@ -3963,6 +4587,7 @@ vec_any_ge(vector unsigned int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -3970,6 +4595,7 @@ vec_any_ge(vector unsigned int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -3977,6 +4603,7 @@ vec_any_ge(vector bool int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool int __a, vector bool int __b) {
int __cc;
@@ -3992,6 +4619,7 @@ vec_any_ge(vector signed long long __a, vector signed long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -3999,6 +4627,7 @@ vec_any_ge(vector signed long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -4013,6 +4642,7 @@ vec_any_ge(vector unsigned long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -4020,6 +4650,7 @@ vec_any_ge(vector unsigned long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -4027,6 +4658,7 @@ vec_any_ge(vector bool long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_ge(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -4035,6 +4667,15 @@ vec_any_ge(vector bool long long __a, vector bool long long __b) {
return __cc != 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_ge(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__a, __b, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_ge(vector double __a, vector double __b) {
int __cc;
@@ -4051,6 +4692,7 @@ vec_any_gt(vector signed char __a, vector signed char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector signed char __a, vector bool char __b) {
int __cc;
@@ -4058,6 +4700,7 @@ vec_any_gt(vector signed char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool char __a, vector signed char __b) {
int __cc;
@@ -4072,6 +4715,7 @@ vec_any_gt(vector unsigned char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -4079,6 +4723,7 @@ vec_any_gt(vector unsigned char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -4086,6 +4731,7 @@ vec_any_gt(vector bool char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool char __a, vector bool char __b) {
int __cc;
@@ -4101,6 +4747,7 @@ vec_any_gt(vector signed short __a, vector signed short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector signed short __a, vector bool short __b) {
int __cc;
@@ -4108,6 +4755,7 @@ vec_any_gt(vector signed short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool short __a, vector signed short __b) {
int __cc;
@@ -4122,6 +4770,7 @@ vec_any_gt(vector unsigned short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -4129,6 +4778,7 @@ vec_any_gt(vector unsigned short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -4136,6 +4786,7 @@ vec_any_gt(vector bool short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool short __a, vector bool short __b) {
int __cc;
@@ -4151,6 +4802,7 @@ vec_any_gt(vector signed int __a, vector signed int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector signed int __a, vector bool int __b) {
int __cc;
@@ -4158,6 +4810,7 @@ vec_any_gt(vector signed int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool int __a, vector signed int __b) {
int __cc;
@@ -4172,6 +4825,7 @@ vec_any_gt(vector unsigned int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -4179,6 +4833,7 @@ vec_any_gt(vector unsigned int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -4186,6 +4841,7 @@ vec_any_gt(vector bool int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool int __a, vector bool int __b) {
int __cc;
@@ -4201,6 +4857,7 @@ vec_any_gt(vector signed long long __a, vector signed long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -4208,6 +4865,7 @@ vec_any_gt(vector signed long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -4222,6 +4880,7 @@ vec_any_gt(vector unsigned long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -4229,6 +4888,7 @@ vec_any_gt(vector unsigned long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -4236,6 +4896,7 @@ vec_any_gt(vector bool long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_gt(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -4244,6 +4905,15 @@ vec_any_gt(vector bool long long __a, vector bool long long __b) {
return __cc <= 1;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_gt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__a, __b, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_gt(vector double __a, vector double __b) {
int __cc;
@@ -4260,6 +4930,7 @@ vec_any_le(vector signed char __a, vector signed char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector signed char __a, vector bool char __b) {
int __cc;
@@ -4267,6 +4938,7 @@ vec_any_le(vector signed char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool char __a, vector signed char __b) {
int __cc;
@@ -4281,6 +4953,7 @@ vec_any_le(vector unsigned char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -4288,6 +4961,7 @@ vec_any_le(vector unsigned char __a, vector bool char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -4295,6 +4969,7 @@ vec_any_le(vector bool char __a, vector unsigned char __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool char __a, vector bool char __b) {
int __cc;
@@ -4310,6 +4985,7 @@ vec_any_le(vector signed short __a, vector signed short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector signed short __a, vector bool short __b) {
int __cc;
@@ -4317,6 +4993,7 @@ vec_any_le(vector signed short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool short __a, vector signed short __b) {
int __cc;
@@ -4331,6 +5008,7 @@ vec_any_le(vector unsigned short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -4338,6 +5016,7 @@ vec_any_le(vector unsigned short __a, vector bool short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -4345,6 +5024,7 @@ vec_any_le(vector bool short __a, vector unsigned short __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool short __a, vector bool short __b) {
int __cc;
@@ -4360,6 +5040,7 @@ vec_any_le(vector signed int __a, vector signed int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector signed int __a, vector bool int __b) {
int __cc;
@@ -4367,6 +5048,7 @@ vec_any_le(vector signed int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool int __a, vector signed int __b) {
int __cc;
@@ -4381,6 +5063,7 @@ vec_any_le(vector unsigned int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -4388,6 +5071,7 @@ vec_any_le(vector unsigned int __a, vector bool int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -4395,6 +5079,7 @@ vec_any_le(vector bool int __a, vector unsigned int __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool int __a, vector bool int __b) {
int __cc;
@@ -4410,6 +5095,7 @@ vec_any_le(vector signed long long __a, vector signed long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -4417,6 +5103,7 @@ vec_any_le(vector signed long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -4431,6 +5118,7 @@ vec_any_le(vector unsigned long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -4438,6 +5126,7 @@ vec_any_le(vector unsigned long long __a, vector bool long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -4445,6 +5134,7 @@ vec_any_le(vector bool long long __a, vector unsigned long long __b) {
return __cc != 0;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_le(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -4453,6 +5143,15 @@ vec_any_le(vector bool long long __a, vector bool long long __b) {
return __cc != 0;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_le(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__b, __a, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_le(vector double __a, vector double __b) {
int __cc;
@@ -4469,6 +5168,7 @@ vec_any_lt(vector signed char __a, vector signed char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector signed char __a, vector bool char __b) {
int __cc;
@@ -4476,6 +5176,7 @@ vec_any_lt(vector signed char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool char __a, vector signed char __b) {
int __cc;
@@ -4490,6 +5191,7 @@ vec_any_lt(vector unsigned char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector unsigned char __a, vector bool char __b) {
int __cc;
@@ -4497,6 +5199,7 @@ vec_any_lt(vector unsigned char __a, vector bool char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool char __a, vector unsigned char __b) {
int __cc;
@@ -4504,6 +5207,7 @@ vec_any_lt(vector bool char __a, vector unsigned char __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool char __a, vector bool char __b) {
int __cc;
@@ -4519,6 +5223,7 @@ vec_any_lt(vector signed short __a, vector signed short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector signed short __a, vector bool short __b) {
int __cc;
@@ -4526,6 +5231,7 @@ vec_any_lt(vector signed short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool short __a, vector signed short __b) {
int __cc;
@@ -4540,6 +5246,7 @@ vec_any_lt(vector unsigned short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector unsigned short __a, vector bool short __b) {
int __cc;
@@ -4547,6 +5254,7 @@ vec_any_lt(vector unsigned short __a, vector bool short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool short __a, vector unsigned short __b) {
int __cc;
@@ -4554,6 +5262,7 @@ vec_any_lt(vector bool short __a, vector unsigned short __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool short __a, vector bool short __b) {
int __cc;
@@ -4569,6 +5278,7 @@ vec_any_lt(vector signed int __a, vector signed int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector signed int __a, vector bool int __b) {
int __cc;
@@ -4576,6 +5286,7 @@ vec_any_lt(vector signed int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool int __a, vector signed int __b) {
int __cc;
@@ -4590,6 +5301,7 @@ vec_any_lt(vector unsigned int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector unsigned int __a, vector bool int __b) {
int __cc;
@@ -4597,6 +5309,7 @@ vec_any_lt(vector unsigned int __a, vector bool int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool int __a, vector unsigned int __b) {
int __cc;
@@ -4604,6 +5317,7 @@ vec_any_lt(vector bool int __a, vector unsigned int __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool int __a, vector bool int __b) {
int __cc;
@@ -4619,6 +5333,7 @@ vec_any_lt(vector signed long long __a, vector signed long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector signed long long __a, vector bool long long __b) {
int __cc;
@@ -4626,6 +5341,7 @@ vec_any_lt(vector signed long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool long long __a, vector signed long long __b) {
int __cc;
@@ -4640,6 +5356,7 @@ vec_any_lt(vector unsigned long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector unsigned long long __a, vector bool long long __b) {
int __cc;
@@ -4647,6 +5364,7 @@ vec_any_lt(vector unsigned long long __a, vector bool long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool long long __a, vector unsigned long long __b) {
int __cc;
@@ -4654,6 +5372,7 @@ vec_any_lt(vector bool long long __a, vector unsigned long long __b) {
return __cc <= 1;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai int
vec_any_lt(vector bool long long __a, vector bool long long __b) {
int __cc;
@@ -4662,6 +5381,15 @@ vec_any_lt(vector bool long long __a, vector bool long long __b) {
return __cc <= 1;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_lt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__b, __a, &__cc);
+ return __cc <= 1;
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_any_lt(vector double __a, vector double __b) {
int __cc;
@@ -4671,7 +5399,16 @@ vec_any_lt(vector double __a, vector double __b) {
/*-- vec_any_nge ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_nge(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__a, __b, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_nge(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchedbs(__a, __b, &__cc);
@@ -4680,7 +5417,16 @@ vec_any_nge(vector double __a, vector double __b) {
/*-- vec_any_ngt ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_ngt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__a, __b, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_ngt(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchdbs(__a, __b, &__cc);
@@ -4689,7 +5435,16 @@ vec_any_ngt(vector double __a, vector double __b) {
/*-- vec_any_nle ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_nle(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchesbs(__b, __a, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_nle(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchedbs(__b, __a, &__cc);
@@ -4698,7 +5453,16 @@ vec_any_nle(vector double __a, vector double __b) {
/*-- vec_any_nlt ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_nlt(vector float __a, vector float __b) {
+ int __cc;
+ __builtin_s390_vfchsbs(__b, __a, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_nlt(vector double __a, vector double __b) {
int __cc;
__builtin_s390_vfchdbs(__b, __a, &__cc);
@@ -4707,7 +5471,16 @@ vec_any_nlt(vector double __a, vector double __b) {
/*-- vec_any_nan ------------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_nan(vector float __a) {
+ int __cc;
+ __builtin_s390_vftcisb(__a, 15, &__cc);
+ return __cc != 3;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_nan(vector double __a) {
int __cc;
__builtin_s390_vftcidb(__a, 15, &__cc);
@@ -4716,7 +5489,16 @@ vec_any_nan(vector double __a) {
/*-- vec_any_numeric --------------------------------------------------------*/
-static inline __ATTRS_ai int
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_any_numeric(vector float __a) {
+ int __cc;
+ __builtin_s390_vftcisb(__a, 15, &__cc);
+ return __cc != 0;
+}
+#endif
+
+static inline __ATTRS_o_ai int
vec_any_numeric(vector double __a) {
int __cc;
__builtin_s390_vftcidb(__a, 15, &__cc);
@@ -4735,11 +5517,13 @@ vec_andc(vector signed char __a, vector signed char __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_andc(vector bool char __a, vector signed char __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_andc(vector signed char __a, vector bool char __b) {
return __a & ~__b;
@@ -4750,11 +5534,13 @@ vec_andc(vector unsigned char __a, vector unsigned char __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_andc(vector bool char __a, vector unsigned char __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_andc(vector unsigned char __a, vector bool char __b) {
return __a & ~__b;
@@ -4770,11 +5556,13 @@ vec_andc(vector signed short __a, vector signed short __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_andc(vector bool short __a, vector signed short __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_andc(vector signed short __a, vector bool short __b) {
return __a & ~__b;
@@ -4785,11 +5573,13 @@ vec_andc(vector unsigned short __a, vector unsigned short __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_andc(vector bool short __a, vector unsigned short __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_andc(vector unsigned short __a, vector bool short __b) {
return __a & ~__b;
@@ -4805,11 +5595,13 @@ vec_andc(vector signed int __a, vector signed int __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_andc(vector bool int __a, vector signed int __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_andc(vector signed int __a, vector bool int __b) {
return __a & ~__b;
@@ -4820,11 +5612,13 @@ vec_andc(vector unsigned int __a, vector unsigned int __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_andc(vector bool int __a, vector unsigned int __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_andc(vector unsigned int __a, vector bool int __b) {
return __a & ~__b;
@@ -4840,11 +5634,13 @@ vec_andc(vector signed long long __a, vector signed long long __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_andc(vector bool long long __a, vector signed long long __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_andc(vector signed long long __a, vector bool long long __b) {
return __a & ~__b;
@@ -4855,28 +5651,40 @@ vec_andc(vector unsigned long long __a, vector unsigned long long __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_andc(vector bool long long __a, vector unsigned long long __b) {
return __a & ~__b;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_andc(vector unsigned long long __a, vector bool long long __b) {
return __a & ~__b;
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_andc(vector float __a, vector float __b) {
+ return (vector float)((vector unsigned int)__a &
+ ~(vector unsigned int)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_andc(vector double __a, vector double __b) {
return (vector double)((vector unsigned long long)__a &
~(vector unsigned long long)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_andc(vector bool long long __a, vector double __b) {
return (vector double)((vector unsigned long long)__a &
~(vector unsigned long long)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_andc(vector double __a, vector bool long long __b) {
return (vector double)((vector unsigned long long)__a &
@@ -4895,11 +5703,13 @@ vec_nor(vector signed char __a, vector signed char __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_nor(vector bool char __a, vector signed char __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_nor(vector signed char __a, vector bool char __b) {
return ~(__a | __b);
@@ -4910,11 +5720,13 @@ vec_nor(vector unsigned char __a, vector unsigned char __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_nor(vector bool char __a, vector unsigned char __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_nor(vector unsigned char __a, vector bool char __b) {
return ~(__a | __b);
@@ -4930,11 +5742,13 @@ vec_nor(vector signed short __a, vector signed short __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_nor(vector bool short __a, vector signed short __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_nor(vector signed short __a, vector bool short __b) {
return ~(__a | __b);
@@ -4945,11 +5759,13 @@ vec_nor(vector unsigned short __a, vector unsigned short __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_nor(vector bool short __a, vector unsigned short __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_nor(vector unsigned short __a, vector bool short __b) {
return ~(__a | __b);
@@ -4965,11 +5781,13 @@ vec_nor(vector signed int __a, vector signed int __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_nor(vector bool int __a, vector signed int __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_nor(vector signed int __a, vector bool int __b) {
return ~(__a | __b);
@@ -4980,11 +5798,13 @@ vec_nor(vector unsigned int __a, vector unsigned int __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_nor(vector bool int __a, vector unsigned int __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_nor(vector unsigned int __a, vector bool int __b) {
return ~(__a | __b);
@@ -5000,11 +5820,13 @@ vec_nor(vector signed long long __a, vector signed long long __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_nor(vector bool long long __a, vector signed long long __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_nor(vector signed long long __a, vector bool long long __b) {
return ~(__a | __b);
@@ -5015,34 +5837,274 @@ vec_nor(vector unsigned long long __a, vector unsigned long long __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_nor(vector bool long long __a, vector unsigned long long __b) {
return ~(__a | __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_nor(vector unsigned long long __a, vector bool long long __b) {
return ~(__a | __b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_nor(vector float __a, vector float __b) {
+ return (vector float)~((vector unsigned int)__a |
+ (vector unsigned int)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_nor(vector double __a, vector double __b) {
return (vector double)~((vector unsigned long long)__a |
(vector unsigned long long)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_nor(vector bool long long __a, vector double __b) {
return (vector double)~((vector unsigned long long)__a |
(vector unsigned long long)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_nor(vector double __a, vector bool long long __b) {
return (vector double)~((vector unsigned long long)__a |
(vector unsigned long long)__b);
}
+/*-- vec_orc ----------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool char
+vec_orc(vector bool char __a, vector bool char __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector signed char
+vec_orc(vector signed char __a, vector signed char __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector unsigned char
+vec_orc(vector unsigned char __a, vector unsigned char __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector bool short
+vec_orc(vector bool short __a, vector bool short __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector signed short
+vec_orc(vector signed short __a, vector signed short __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector unsigned short
+vec_orc(vector unsigned short __a, vector unsigned short __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector bool int
+vec_orc(vector bool int __a, vector bool int __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector signed int
+vec_orc(vector signed int __a, vector signed int __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector unsigned int
+vec_orc(vector unsigned int __a, vector unsigned int __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector bool long long
+vec_orc(vector bool long long __a, vector bool long long __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector signed long long
+vec_orc(vector signed long long __a, vector signed long long __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_orc(vector unsigned long long __a, vector unsigned long long __b) {
+ return __a | ~__b;
+}
+
+static inline __ATTRS_o_ai vector float
+vec_orc(vector float __a, vector float __b) {
+ return (vector float)((vector unsigned int)__a &
+ ~(vector unsigned int)__b);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_orc(vector double __a, vector double __b) {
+ return (vector double)((vector unsigned long long)__a &
+ ~(vector unsigned long long)__b);
+}
+#endif
+
+/*-- vec_nand ---------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool char
+vec_nand(vector bool char __a, vector bool char __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector signed char
+vec_nand(vector signed char __a, vector signed char __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned char
+vec_nand(vector unsigned char __a, vector unsigned char __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector bool short
+vec_nand(vector bool short __a, vector bool short __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector signed short
+vec_nand(vector signed short __a, vector signed short __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned short
+vec_nand(vector unsigned short __a, vector unsigned short __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector bool int
+vec_nand(vector bool int __a, vector bool int __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector signed int
+vec_nand(vector signed int __a, vector signed int __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned int
+vec_nand(vector unsigned int __a, vector unsigned int __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector bool long long
+vec_nand(vector bool long long __a, vector bool long long __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector signed long long
+vec_nand(vector signed long long __a, vector signed long long __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_nand(vector unsigned long long __a, vector unsigned long long __b) {
+ return ~(__a & __b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_nand(vector float __a, vector float __b) {
+ return (vector float)~((vector unsigned int)__a &
+ (vector unsigned int)__b);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_nand(vector double __a, vector double __b) {
+ return (vector double)~((vector unsigned long long)__a &
+ (vector unsigned long long)__b);
+}
+#endif
+
+/*-- vec_eqv ----------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector bool char
+vec_eqv(vector bool char __a, vector bool char __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector signed char
+vec_eqv(vector signed char __a, vector signed char __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned char
+vec_eqv(vector unsigned char __a, vector unsigned char __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector bool short
+vec_eqv(vector bool short __a, vector bool short __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector signed short
+vec_eqv(vector signed short __a, vector signed short __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned short
+vec_eqv(vector unsigned short __a, vector unsigned short __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector bool int
+vec_eqv(vector bool int __a, vector bool int __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector signed int
+vec_eqv(vector signed int __a, vector signed int __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned int
+vec_eqv(vector unsigned int __a, vector unsigned int __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector bool long long
+vec_eqv(vector bool long long __a, vector bool long long __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector signed long long
+vec_eqv(vector signed long long __a, vector signed long long __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_eqv(vector unsigned long long __a, vector unsigned long long __b) {
+ return ~(__a ^ __b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_eqv(vector float __a, vector float __b) {
+ return (vector float)~((vector unsigned int)__a ^
+ (vector unsigned int)__b);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_eqv(vector double __a, vector double __b) {
+ return (vector double)~((vector unsigned long long)__a ^
+ (vector unsigned long long)__b);
+}
+#endif
+
/*-- vec_cntlz --------------------------------------------------------------*/
static inline __ATTRS_o_ai vector unsigned char
@@ -5323,30 +6385,35 @@ vec_sll(vector signed char __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_sll(vector signed char __a, vector unsigned short __b) {
return (vector signed char)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_sll(vector signed char __a, vector unsigned int __b) {
return (vector signed char)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sll(vector bool char __a, vector unsigned char __b) {
return (vector bool char)__builtin_s390_vsl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sll(vector bool char __a, vector unsigned short __b) {
return (vector bool char)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sll(vector bool char __a, vector unsigned int __b) {
return (vector bool char)__builtin_s390_vsl(
@@ -5358,11 +6425,13 @@ vec_sll(vector unsigned char __a, vector unsigned char __b) {
return __builtin_s390_vsl(__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_sll(vector unsigned char __a, vector unsigned short __b) {
return __builtin_s390_vsl(__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_sll(vector unsigned char __a, vector unsigned int __b) {
return __builtin_s390_vsl(__a, (vector unsigned char)__b);
@@ -5374,30 +6443,35 @@ vec_sll(vector signed short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_sll(vector signed short __a, vector unsigned short __b) {
return (vector signed short)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_sll(vector signed short __a, vector unsigned int __b) {
return (vector signed short)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sll(vector bool short __a, vector unsigned char __b) {
return (vector bool short)__builtin_s390_vsl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sll(vector bool short __a, vector unsigned short __b) {
return (vector bool short)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sll(vector bool short __a, vector unsigned int __b) {
return (vector bool short)__builtin_s390_vsl(
@@ -5410,12 +6484,14 @@ vec_sll(vector unsigned short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_sll(vector unsigned short __a, vector unsigned short __b) {
return (vector unsigned short)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_sll(vector unsigned short __a, vector unsigned int __b) {
return (vector unsigned short)__builtin_s390_vsl(
@@ -5428,30 +6504,35 @@ vec_sll(vector signed int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_sll(vector signed int __a, vector unsigned short __b) {
return (vector signed int)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_sll(vector signed int __a, vector unsigned int __b) {
return (vector signed int)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sll(vector bool int __a, vector unsigned char __b) {
return (vector bool int)__builtin_s390_vsl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sll(vector bool int __a, vector unsigned short __b) {
return (vector bool int)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sll(vector bool int __a, vector unsigned int __b) {
return (vector bool int)__builtin_s390_vsl(
@@ -5464,12 +6545,14 @@ vec_sll(vector unsigned int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_sll(vector unsigned int __a, vector unsigned short __b) {
return (vector unsigned int)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_sll(vector unsigned int __a, vector unsigned int __b) {
return (vector unsigned int)__builtin_s390_vsl(
@@ -5482,30 +6565,35 @@ vec_sll(vector signed long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_sll(vector signed long long __a, vector unsigned short __b) {
return (vector signed long long)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_sll(vector signed long long __a, vector unsigned int __b) {
return (vector signed long long)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sll(vector bool long long __a, vector unsigned char __b) {
return (vector bool long long)__builtin_s390_vsl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sll(vector bool long long __a, vector unsigned short __b) {
return (vector bool long long)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sll(vector bool long long __a, vector unsigned int __b) {
return (vector bool long long)__builtin_s390_vsl(
@@ -5518,12 +6606,14 @@ vec_sll(vector unsigned long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_sll(vector unsigned long long __a, vector unsigned short __b) {
return (vector unsigned long long)__builtin_s390_vsl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_sll(vector unsigned long long __a, vector unsigned int __b) {
return (vector unsigned long long)__builtin_s390_vsl(
@@ -5626,6 +6716,20 @@ vec_slb(vector unsigned long long __a, vector unsigned long long __b) {
(vector unsigned char)__a, (vector unsigned char)__b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_slb(vector float __a, vector signed int __b) {
+ return (vector float)__builtin_s390_vslb(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_slb(vector float __a, vector unsigned int __b) {
+ return (vector float)__builtin_s390_vslb(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_slb(vector double __a, vector signed long long __b) {
return (vector double)__builtin_s390_vslb(
@@ -5644,6 +6748,10 @@ extern __ATTRS_o vector signed char
vec_sld(vector signed char __a, vector signed char __b, int __c)
__constant_range(__c, 0, 15);
+extern __ATTRS_o vector bool char
+vec_sld(vector bool char __a, vector bool char __b, int __c)
+ __constant_range(__c, 0, 15);
+
extern __ATTRS_o vector unsigned char
vec_sld(vector unsigned char __a, vector unsigned char __b, int __c)
__constant_range(__c, 0, 15);
@@ -5652,6 +6760,10 @@ extern __ATTRS_o vector signed short
vec_sld(vector signed short __a, vector signed short __b, int __c)
__constant_range(__c, 0, 15);
+extern __ATTRS_o vector bool short
+vec_sld(vector bool short __a, vector bool short __b, int __c)
+ __constant_range(__c, 0, 15);
+
extern __ATTRS_o vector unsigned short
vec_sld(vector unsigned short __a, vector unsigned short __b, int __c)
__constant_range(__c, 0, 15);
@@ -5660,6 +6772,10 @@ extern __ATTRS_o vector signed int
vec_sld(vector signed int __a, vector signed int __b, int __c)
__constant_range(__c, 0, 15);
+extern __ATTRS_o vector bool int
+vec_sld(vector bool int __a, vector bool int __b, int __c)
+ __constant_range(__c, 0, 15);
+
extern __ATTRS_o vector unsigned int
vec_sld(vector unsigned int __a, vector unsigned int __b, int __c)
__constant_range(__c, 0, 15);
@@ -5668,10 +6784,20 @@ extern __ATTRS_o vector signed long long
vec_sld(vector signed long long __a, vector signed long long __b, int __c)
__constant_range(__c, 0, 15);
+extern __ATTRS_o vector bool long long
+vec_sld(vector bool long long __a, vector bool long long __b, int __c)
+ __constant_range(__c, 0, 15);
+
extern __ATTRS_o vector unsigned long long
vec_sld(vector unsigned long long __a, vector unsigned long long __b, int __c)
__constant_range(__c, 0, 15);
+#if __ARCH__ >= 12
+extern __ATTRS_o vector float
+vec_sld(vector float __a, vector float __b, int __c)
+ __constant_range(__c, 0, 15);
+#endif
+
extern __ATTRS_o vector double
vec_sld(vector double __a, vector double __b, int __c)
__constant_range(__c, 0, 15);
@@ -5714,6 +6840,7 @@ extern __ATTRS_o vector unsigned long long
vec_sldw(vector unsigned long long __a, vector unsigned long long __b, int __c)
__constant_range(__c, 0, 3);
+// This prototype is deprecated.
extern __ATTRS_o vector double
vec_sldw(vector double __a, vector double __b, int __c)
__constant_range(__c, 0, 3);
@@ -5730,30 +6857,35 @@ vec_sral(vector signed char __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_sral(vector signed char __a, vector unsigned short __b) {
return (vector signed char)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_sral(vector signed char __a, vector unsigned int __b) {
return (vector signed char)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sral(vector bool char __a, vector unsigned char __b) {
return (vector bool char)__builtin_s390_vsra(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sral(vector bool char __a, vector unsigned short __b) {
return (vector bool char)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_sral(vector bool char __a, vector unsigned int __b) {
return (vector bool char)__builtin_s390_vsra(
@@ -5765,11 +6897,13 @@ vec_sral(vector unsigned char __a, vector unsigned char __b) {
return __builtin_s390_vsra(__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_sral(vector unsigned char __a, vector unsigned short __b) {
return __builtin_s390_vsra(__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_sral(vector unsigned char __a, vector unsigned int __b) {
return __builtin_s390_vsra(__a, (vector unsigned char)__b);
@@ -5781,30 +6915,35 @@ vec_sral(vector signed short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_sral(vector signed short __a, vector unsigned short __b) {
return (vector signed short)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_sral(vector signed short __a, vector unsigned int __b) {
return (vector signed short)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sral(vector bool short __a, vector unsigned char __b) {
return (vector bool short)__builtin_s390_vsra(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sral(vector bool short __a, vector unsigned short __b) {
return (vector bool short)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_sral(vector bool short __a, vector unsigned int __b) {
return (vector bool short)__builtin_s390_vsra(
@@ -5817,12 +6956,14 @@ vec_sral(vector unsigned short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_sral(vector unsigned short __a, vector unsigned short __b) {
return (vector unsigned short)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_sral(vector unsigned short __a, vector unsigned int __b) {
return (vector unsigned short)__builtin_s390_vsra(
@@ -5835,30 +6976,35 @@ vec_sral(vector signed int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_sral(vector signed int __a, vector unsigned short __b) {
return (vector signed int)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_sral(vector signed int __a, vector unsigned int __b) {
return (vector signed int)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sral(vector bool int __a, vector unsigned char __b) {
return (vector bool int)__builtin_s390_vsra(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sral(vector bool int __a, vector unsigned short __b) {
return (vector bool int)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_sral(vector bool int __a, vector unsigned int __b) {
return (vector bool int)__builtin_s390_vsra(
@@ -5871,12 +7017,14 @@ vec_sral(vector unsigned int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_sral(vector unsigned int __a, vector unsigned short __b) {
return (vector unsigned int)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_sral(vector unsigned int __a, vector unsigned int __b) {
return (vector unsigned int)__builtin_s390_vsra(
@@ -5889,30 +7037,35 @@ vec_sral(vector signed long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_sral(vector signed long long __a, vector unsigned short __b) {
return (vector signed long long)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_sral(vector signed long long __a, vector unsigned int __b) {
return (vector signed long long)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sral(vector bool long long __a, vector unsigned char __b) {
return (vector bool long long)__builtin_s390_vsra(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sral(vector bool long long __a, vector unsigned short __b) {
return (vector bool long long)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_sral(vector bool long long __a, vector unsigned int __b) {
return (vector bool long long)__builtin_s390_vsra(
@@ -5925,12 +7078,14 @@ vec_sral(vector unsigned long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_sral(vector unsigned long long __a, vector unsigned short __b) {
return (vector unsigned long long)__builtin_s390_vsra(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_sral(vector unsigned long long __a, vector unsigned int __b) {
return (vector unsigned long long)__builtin_s390_vsra(
@@ -6033,6 +7188,20 @@ vec_srab(vector unsigned long long __a, vector unsigned long long __b) {
(vector unsigned char)__a, (vector unsigned char)__b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_srab(vector float __a, vector signed int __b) {
+ return (vector float)__builtin_s390_vsrab(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_srab(vector float __a, vector unsigned int __b) {
+ return (vector float)__builtin_s390_vsrab(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_srab(vector double __a, vector signed long long __b) {
return (vector double)__builtin_s390_vsrab(
@@ -6053,30 +7222,35 @@ vec_srl(vector signed char __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_srl(vector signed char __a, vector unsigned short __b) {
return (vector signed char)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_srl(vector signed char __a, vector unsigned int __b) {
return (vector signed char)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_srl(vector bool char __a, vector unsigned char __b) {
return (vector bool char)__builtin_s390_vsrl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_srl(vector bool char __a, vector unsigned short __b) {
return (vector bool char)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool char
vec_srl(vector bool char __a, vector unsigned int __b) {
return (vector bool char)__builtin_s390_vsrl(
@@ -6088,11 +7262,13 @@ vec_srl(vector unsigned char __a, vector unsigned char __b) {
return __builtin_s390_vsrl(__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_srl(vector unsigned char __a, vector unsigned short __b) {
return __builtin_s390_vsrl(__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_srl(vector unsigned char __a, vector unsigned int __b) {
return __builtin_s390_vsrl(__a, (vector unsigned char)__b);
@@ -6104,30 +7280,35 @@ vec_srl(vector signed short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_srl(vector signed short __a, vector unsigned short __b) {
return (vector signed short)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_srl(vector signed short __a, vector unsigned int __b) {
return (vector signed short)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_srl(vector bool short __a, vector unsigned char __b) {
return (vector bool short)__builtin_s390_vsrl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_srl(vector bool short __a, vector unsigned short __b) {
return (vector bool short)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool short
vec_srl(vector bool short __a, vector unsigned int __b) {
return (vector bool short)__builtin_s390_vsrl(
@@ -6140,12 +7321,14 @@ vec_srl(vector unsigned short __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_srl(vector unsigned short __a, vector unsigned short __b) {
return (vector unsigned short)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_srl(vector unsigned short __a, vector unsigned int __b) {
return (vector unsigned short)__builtin_s390_vsrl(
@@ -6158,30 +7341,35 @@ vec_srl(vector signed int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_srl(vector signed int __a, vector unsigned short __b) {
return (vector signed int)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_srl(vector signed int __a, vector unsigned int __b) {
return (vector signed int)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_srl(vector bool int __a, vector unsigned char __b) {
return (vector bool int)__builtin_s390_vsrl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_srl(vector bool int __a, vector unsigned short __b) {
return (vector bool int)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool int
vec_srl(vector bool int __a, vector unsigned int __b) {
return (vector bool int)__builtin_s390_vsrl(
@@ -6194,12 +7382,14 @@ vec_srl(vector unsigned int __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_srl(vector unsigned int __a, vector unsigned short __b) {
return (vector unsigned int)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_srl(vector unsigned int __a, vector unsigned int __b) {
return (vector unsigned int)__builtin_s390_vsrl(
@@ -6212,30 +7402,35 @@ vec_srl(vector signed long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_srl(vector signed long long __a, vector unsigned short __b) {
return (vector signed long long)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_srl(vector signed long long __a, vector unsigned int __b) {
return (vector signed long long)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_srl(vector bool long long __a, vector unsigned char __b) {
return (vector bool long long)__builtin_s390_vsrl(
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_srl(vector bool long long __a, vector unsigned short __b) {
return (vector bool long long)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector bool long long
vec_srl(vector bool long long __a, vector unsigned int __b) {
return (vector bool long long)__builtin_s390_vsrl(
@@ -6248,12 +7443,14 @@ vec_srl(vector unsigned long long __a, vector unsigned char __b) {
(vector unsigned char)__a, __b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_srl(vector unsigned long long __a, vector unsigned short __b) {
return (vector unsigned long long)__builtin_s390_vsrl(
(vector unsigned char)__a, (vector unsigned char)__b);
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_srl(vector unsigned long long __a, vector unsigned int __b) {
return (vector unsigned long long)__builtin_s390_vsrl(
@@ -6356,6 +7553,20 @@ vec_srb(vector unsigned long long __a, vector unsigned long long __b) {
(vector unsigned char)__a, (vector unsigned char)__b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_srb(vector float __a, vector signed int __b) {
+ return (vector float)__builtin_s390_vsrlb(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+
+static inline __ATTRS_o_ai vector float
+vec_srb(vector float __a, vector unsigned int __b) {
+ return (vector float)__builtin_s390_vsrlb(
+ (vector unsigned char)__a, (vector unsigned char)__b);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_srb(vector double __a, vector signed long long __b) {
return (vector double)__builtin_s390_vsrlb(
@@ -6390,6 +7601,13 @@ vec_abs(vector signed long long __a) {
return vec_sel(__a, -__a, vec_cmplt(__a, (vector signed long long)0));
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_abs(vector float __a) {
+ return __builtin_s390_vflpsb(__a);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_abs(vector double __a) {
return __builtin_s390_vflpdb(__a);
@@ -6397,7 +7615,14 @@ vec_abs(vector double __a) {
/*-- vec_nabs ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_nabs(vector float __a) {
+ return __builtin_s390_vflnsb(__a);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_nabs(vector double __a) {
return __builtin_s390_vflndb(__a);
}
@@ -6409,12 +7634,14 @@ vec_max(vector signed char __a, vector signed char __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_max(vector signed char __a, vector bool char __b) {
vector signed char __bc = (vector signed char)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_max(vector bool char __a, vector signed char __b) {
vector signed char __ac = (vector signed char)__a;
@@ -6426,12 +7653,14 @@ vec_max(vector unsigned char __a, vector unsigned char __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_max(vector unsigned char __a, vector bool char __b) {
vector unsigned char __bc = (vector unsigned char)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_max(vector bool char __a, vector unsigned char __b) {
vector unsigned char __ac = (vector unsigned char)__a;
@@ -6443,12 +7672,14 @@ vec_max(vector signed short __a, vector signed short __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_max(vector signed short __a, vector bool short __b) {
vector signed short __bc = (vector signed short)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_max(vector bool short __a, vector signed short __b) {
vector signed short __ac = (vector signed short)__a;
@@ -6460,12 +7691,14 @@ vec_max(vector unsigned short __a, vector unsigned short __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_max(vector unsigned short __a, vector bool short __b) {
vector unsigned short __bc = (vector unsigned short)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_max(vector bool short __a, vector unsigned short __b) {
vector unsigned short __ac = (vector unsigned short)__a;
@@ -6477,12 +7710,14 @@ vec_max(vector signed int __a, vector signed int __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_max(vector signed int __a, vector bool int __b) {
vector signed int __bc = (vector signed int)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_max(vector bool int __a, vector signed int __b) {
vector signed int __ac = (vector signed int)__a;
@@ -6494,12 +7729,14 @@ vec_max(vector unsigned int __a, vector unsigned int __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_max(vector unsigned int __a, vector bool int __b) {
vector unsigned int __bc = (vector unsigned int)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_max(vector bool int __a, vector unsigned int __b) {
vector unsigned int __ac = (vector unsigned int)__a;
@@ -6511,12 +7748,14 @@ vec_max(vector signed long long __a, vector signed long long __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_max(vector signed long long __a, vector bool long long __b) {
vector signed long long __bc = (vector signed long long)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_max(vector bool long long __a, vector signed long long __b) {
vector signed long long __ac = (vector signed long long)__a;
@@ -6528,21 +7767,34 @@ vec_max(vector unsigned long long __a, vector unsigned long long __b) {
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_max(vector unsigned long long __a, vector bool long long __b) {
vector unsigned long long __bc = (vector unsigned long long)__b;
return vec_sel(__bc, __a, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_max(vector bool long long __a, vector unsigned long long __b) {
vector unsigned long long __ac = (vector unsigned long long)__a;
return vec_sel(__b, __ac, vec_cmpgt(__ac, __b));
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_max(vector float __a, vector float __b) {
+ return __builtin_s390_vfmaxsb(__a, __b, 0);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_max(vector double __a, vector double __b) {
+#if __ARCH__ >= 12
+ return __builtin_s390_vfmaxdb(__a, __b, 0);
+#else
return vec_sel(__b, __a, vec_cmpgt(__a, __b));
+#endif
}
/*-- vec_min ----------------------------------------------------------------*/
@@ -6552,12 +7804,14 @@ vec_min(vector signed char __a, vector signed char __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_min(vector signed char __a, vector bool char __b) {
vector signed char __bc = (vector signed char)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed char
vec_min(vector bool char __a, vector signed char __b) {
vector signed char __ac = (vector signed char)__a;
@@ -6569,12 +7823,14 @@ vec_min(vector unsigned char __a, vector unsigned char __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_min(vector unsigned char __a, vector bool char __b) {
vector unsigned char __bc = (vector unsigned char)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned char
vec_min(vector bool char __a, vector unsigned char __b) {
vector unsigned char __ac = (vector unsigned char)__a;
@@ -6586,12 +7842,14 @@ vec_min(vector signed short __a, vector signed short __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_min(vector signed short __a, vector bool short __b) {
vector signed short __bc = (vector signed short)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed short
vec_min(vector bool short __a, vector signed short __b) {
vector signed short __ac = (vector signed short)__a;
@@ -6603,12 +7861,14 @@ vec_min(vector unsigned short __a, vector unsigned short __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_min(vector unsigned short __a, vector bool short __b) {
vector unsigned short __bc = (vector unsigned short)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned short
vec_min(vector bool short __a, vector unsigned short __b) {
vector unsigned short __ac = (vector unsigned short)__a;
@@ -6620,12 +7880,14 @@ vec_min(vector signed int __a, vector signed int __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_min(vector signed int __a, vector bool int __b) {
vector signed int __bc = (vector signed int)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed int
vec_min(vector bool int __a, vector signed int __b) {
vector signed int __ac = (vector signed int)__a;
@@ -6637,12 +7899,14 @@ vec_min(vector unsigned int __a, vector unsigned int __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_min(vector unsigned int __a, vector bool int __b) {
vector unsigned int __bc = (vector unsigned int)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned int
vec_min(vector bool int __a, vector unsigned int __b) {
vector unsigned int __ac = (vector unsigned int)__a;
@@ -6654,12 +7918,14 @@ vec_min(vector signed long long __a, vector signed long long __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_min(vector signed long long __a, vector bool long long __b) {
vector signed long long __bc = (vector signed long long)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_min(vector bool long long __a, vector signed long long __b) {
vector signed long long __ac = (vector signed long long)__a;
@@ -6671,21 +7937,34 @@ vec_min(vector unsigned long long __a, vector unsigned long long __b) {
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_min(vector unsigned long long __a, vector bool long long __b) {
vector unsigned long long __bc = (vector unsigned long long)__b;
return vec_sel(__a, __bc, vec_cmpgt(__a, __bc));
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_min(vector bool long long __a, vector unsigned long long __b) {
vector unsigned long long __ac = (vector unsigned long long)__a;
return vec_sel(__ac, __b, vec_cmpgt(__ac, __b));
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_min(vector float __a, vector float __b) {
+ return __builtin_s390_vfminsb(__a, __b, 0);
+}
+#endif
+
static inline __ATTRS_o_ai vector double
vec_min(vector double __a, vector double __b) {
+#if __ARCH__ >= 12
+ return __builtin_s390_vfmindb(__a, __b, 0);
+#else
return vec_sel(__a, __b, vec_cmpgt(__a, __b));
+#endif
}
/*-- vec_add_u128 -----------------------------------------------------------*/
@@ -7126,6 +8405,13 @@ vec_mulo(vector unsigned int __a, vector unsigned int __b) {
return __builtin_s390_vmlof(__a, __b);
}
+/*-- vec_msum_u128 ----------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+#define vec_msum_u128(X, Y, Z, W) \
+ ((vector unsigned char)__builtin_s390_vmslg((X), (Y), (Z), (W)));
+#endif
+
/*-- vec_sub_u128 -----------------------------------------------------------*/
static inline __ATTRS_ai vector unsigned char
@@ -7263,6 +8549,14 @@ vec_test_mask(vector unsigned long long __a, vector unsigned long long __b) {
(vector unsigned char)__b);
}
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai int
+vec_test_mask(vector float __a, vector unsigned int __b) {
+ return __builtin_s390_vtm((vector unsigned char)__a,
+ (vector unsigned char)__b);
+}
+#endif
+
static inline __ATTRS_o_ai int
vec_test_mask(vector double __a, vector unsigned long long __b) {
return __builtin_s390_vtm((vector unsigned char)__a,
@@ -7271,27 +8565,77 @@ vec_test_mask(vector double __a, vector unsigned long long __b) {
/*-- vec_madd ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_madd(vector float __a, vector float __b, vector float __c) {
+ return __builtin_s390_vfmasb(__a, __b, __c);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_madd(vector double __a, vector double __b, vector double __c) {
return __builtin_s390_vfmadb(__a, __b, __c);
}
/*-- vec_msub ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_msub(vector float __a, vector float __b, vector float __c) {
+ return __builtin_s390_vfmssb(__a, __b, __c);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_msub(vector double __a, vector double __b, vector double __c) {
return __builtin_s390_vfmsdb(__a, __b, __c);
}
+/*-- vec_nmadd ---------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_nmadd(vector float __a, vector float __b, vector float __c) {
+ return __builtin_s390_vfnmasb(__a, __b, __c);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_nmadd(vector double __a, vector double __b, vector double __c) {
+ return __builtin_s390_vfnmadb(__a, __b, __c);
+}
+#endif
+
+/*-- vec_nmsub ---------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_nmsub(vector float __a, vector float __b, vector float __c) {
+ return __builtin_s390_vfnmssb(__a, __b, __c);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_nmsub(vector double __a, vector double __b, vector double __c) {
+ return __builtin_s390_vfnmsdb(__a, __b, __c);
+}
+#endif
+
/*-- vec_sqrt ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_sqrt(vector float __a) {
+ return __builtin_s390_vfsqsb(__a);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_sqrt(vector double __a) {
return __builtin_s390_vfsqdb(__a);
}
/*-- vec_ld2f ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_ai vector double
vec_ld2f(const float *__ptr) {
typedef float __v2f32 __attribute__((__vector_size__(8)));
@@ -7300,6 +8644,7 @@ vec_ld2f(const float *__ptr) {
/*-- vec_st2f ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_ai void
vec_st2f(vector double __a, float *__ptr) {
typedef float __v2f32 __attribute__((__vector_size__(8)));
@@ -7308,6 +8653,7 @@ vec_st2f(vector double __a, float *__ptr) {
/*-- vec_ctd ----------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_ctd(vector signed long long __a, int __b)
__constant_range(__b, 0, 31) {
@@ -7316,6 +8662,7 @@ vec_ctd(vector signed long long __a, int __b)
return __conv;
}
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector double
vec_ctd(vector unsigned long long __a, int __b)
__constant_range(__b, 0, 31) {
@@ -7326,6 +8673,7 @@ vec_ctd(vector unsigned long long __a, int __b)
/*-- vec_ctsl ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector signed long long
vec_ctsl(vector double __a, int __b)
__constant_range(__b, 0, 31) {
@@ -7335,6 +8683,7 @@ vec_ctsl(vector double __a, int __b)
/*-- vec_ctul ---------------------------------------------------------------*/
+// This prototype is deprecated.
static inline __ATTRS_o_ai vector unsigned long long
vec_ctul(vector double __a, int __b)
__constant_range(__b, 0, 31) {
@@ -7342,16 +8691,79 @@ vec_ctul(vector double __a, int __b)
return __builtin_convertvector(__a, vector unsigned long long);
}
-/*-- vec_roundp -------------------------------------------------------------*/
+/*-- vec_doublee ------------------------------------------------------------*/
+#if __ARCH__ >= 12
static inline __ATTRS_ai vector double
+vec_doublee(vector float __a) {
+ typedef float __v2f32 __attribute__((__vector_size__(8)));
+ __v2f32 __pack = __builtin_shufflevector(__a, __a, 0, 2);
+ return __builtin_convertvector(__pack, vector double);
+}
+#endif
+
+/*-- vec_floate -------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_ai vector float
+vec_floate(vector double __a) {
+ typedef float __v2f32 __attribute__((__vector_size__(8)));
+ __v2f32 __pack = __builtin_convertvector(__a, __v2f32);
+ return __builtin_shufflevector(__pack, __pack, 0, -1, 1, -1);
+}
+#endif
+
+/*-- vec_double -------------------------------------------------------------*/
+
+static inline __ATTRS_o_ai vector double
+vec_double(vector signed long long __a) {
+ return __builtin_convertvector(__a, vector double);
+}
+
+static inline __ATTRS_o_ai vector double
+vec_double(vector unsigned long long __a) {
+ return __builtin_convertvector(__a, vector double);
+}
+
+/*-- vec_signed -------------------------------------------------------------*/
+
+static inline __ATTRS_o_ai vector signed long long
+vec_signed(vector double __a) {
+ return __builtin_convertvector(__a, vector signed long long);
+}
+
+/*-- vec_unsigned -----------------------------------------------------------*/
+
+static inline __ATTRS_o_ai vector unsigned long long
+vec_unsigned(vector double __a) {
+ return __builtin_convertvector(__a, vector unsigned long long);
+}
+
+/*-- vec_roundp -------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_roundp(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 6);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_roundp(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 6);
}
/*-- vec_ceil ---------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_ceil(vector float __a) {
+ // On this platform, vec_ceil never triggers the IEEE-inexact exception.
+ return __builtin_s390_vfisb(__a, 4, 6);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_ceil(vector double __a) {
// On this platform, vec_ceil never triggers the IEEE-inexact exception.
return __builtin_s390_vfidb(__a, 4, 6);
@@ -7359,14 +8771,29 @@ vec_ceil(vector double __a) {
/*-- vec_roundm -------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_roundm(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 7);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_roundm(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 7);
}
/*-- vec_floor --------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_floor(vector float __a) {
+ // On this platform, vec_floor never triggers the IEEE-inexact exception.
+ return __builtin_s390_vfisb(__a, 4, 7);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_floor(vector double __a) {
// On this platform, vec_floor never triggers the IEEE-inexact exception.
return __builtin_s390_vfidb(__a, 4, 7);
@@ -7374,14 +8801,29 @@ vec_floor(vector double __a) {
/*-- vec_roundz -------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_roundz(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 5);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_roundz(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 5);
}
/*-- vec_trunc --------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_trunc(vector float __a) {
+ // On this platform, vec_trunc never triggers the IEEE-inexact exception.
+ return __builtin_s390_vfisb(__a, 4, 5);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_trunc(vector double __a) {
// On this platform, vec_trunc never triggers the IEEE-inexact exception.
return __builtin_s390_vfidb(__a, 4, 5);
@@ -7389,22 +8831,104 @@ vec_trunc(vector double __a) {
/*-- vec_roundc -------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_roundc(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 0);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_roundc(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 0);
}
+/*-- vec_rint ---------------------------------------------------------------*/
+
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_rint(vector float __a) {
+ // vec_rint may trigger the IEEE-inexact exception.
+ return __builtin_s390_vfisb(__a, 0, 0);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
+vec_rint(vector double __a) {
+ // vec_rint may trigger the IEEE-inexact exception.
+ return __builtin_s390_vfidb(__a, 0, 0);
+}
+
/*-- vec_round --------------------------------------------------------------*/
-static inline __ATTRS_ai vector double
+#if __ARCH__ >= 12
+static inline __ATTRS_o_ai vector float
+vec_round(vector float __a) {
+ return __builtin_s390_vfisb(__a, 4, 4);
+}
+#endif
+
+static inline __ATTRS_o_ai vector double
vec_round(vector double __a) {
return __builtin_s390_vfidb(__a, 4, 4);
}
/*-- vec_fp_test_data_class -------------------------------------------------*/
+#if __ARCH__ >= 12
+extern __ATTRS_o vector bool int
+vec_fp_test_data_class(vector float __a, int __b, int *__c)
+ __constant_range(__b, 0, 4095);
+
+extern __ATTRS_o vector bool long long
+vec_fp_test_data_class(vector double __a, int __b, int *__c)
+ __constant_range(__b, 0, 4095);
+
+#define vec_fp_test_data_class(X, Y, Z) \
+ ((__typeof__((vec_fp_test_data_class)((X), (Y), (Z)))) \
+ __extension__ ({ \
+ vector unsigned char __res; \
+ vector unsigned char __x = (vector unsigned char)(X); \
+ int *__z = (Z); \
+ switch (sizeof ((X)[0])) { \
+ case 4: __res = (vector unsigned char) \
+ __builtin_s390_vftcisb((vector float)__x, (Y), __z); \
+ break; \
+ default: __res = (vector unsigned char) \
+ __builtin_s390_vftcidb((vector double)__x, (Y), __z); \
+ break; \
+ } __res; }))
+#else
#define vec_fp_test_data_class(X, Y, Z) \
((vector bool long long)__builtin_s390_vftcidb((X), (Y), (Z)))
+#endif
+
+#define __VEC_CLASS_FP_ZERO_P (1 << 11)
+#define __VEC_CLASS_FP_ZERO_N (1 << 10)
+#define __VEC_CLASS_FP_ZERO (__VEC_CLASS_FP_ZERO_P | __VEC_CLASS_FP_ZERO_N)
+#define __VEC_CLASS_FP_NORMAL_P (1 << 9)
+#define __VEC_CLASS_FP_NORMAL_N (1 << 8)
+#define __VEC_CLASS_FP_NORMAL (__VEC_CLASS_FP_NORMAL_P | \
+ __VEC_CLASS_FP_NORMAL_N)
+#define __VEC_CLASS_FP_SUBNORMAL_P (1 << 7)
+#define __VEC_CLASS_FP_SUBNORMAL_N (1 << 6)
+#define __VEC_CLASS_FP_SUBNORMAL (__VEC_CLASS_FP_SUBNORMAL_P | \
+ __VEC_CLASS_FP_SUBNORMAL_N)
+#define __VEC_CLASS_FP_INFINITY_P (1 << 5)
+#define __VEC_CLASS_FP_INFINITY_N (1 << 4)
+#define __VEC_CLASS_FP_INFINITY (__VEC_CLASS_FP_INFINITY_P | \
+ __VEC_CLASS_FP_INFINITY_N)
+#define __VEC_CLASS_FP_QNAN_P (1 << 3)
+#define __VEC_CLASS_FP_QNAN_N (1 << 2)
+#define __VEC_CLASS_FP_QNAN (__VEC_CLASS_FP_QNAN_P | __VEC_CLASS_FP_QNAN_N)
+#define __VEC_CLASS_FP_SNAN_P (1 << 1)
+#define __VEC_CLASS_FP_SNAN_N (1 << 0)
+#define __VEC_CLASS_FP_SNAN (__VEC_CLASS_FP_SNAN_P | __VEC_CLASS_FP_SNAN_N)
+#define __VEC_CLASS_FP_NAN (__VEC_CLASS_FP_QNAN | __VEC_CLASS_FP_SNAN)
+#define __VEC_CLASS_FP_NOT_NORMAL (__VEC_CLASS_FP_NAN | \
+ __VEC_CLASS_FP_SUBNORMAL | \
+ __VEC_CLASS_FP_ZERO | \
+ __VEC_CLASS_FP_INFINITY)
/*-- vec_cp_until_zero ------------------------------------------------------*/
diff --git a/contrib/llvm/tools/clang/lib/Headers/x86intrin.h b/contrib/llvm/tools/clang/lib/Headers/x86intrin.h
index 81a404f..31ee7b8 100644
--- a/contrib/llvm/tools/clang/lib/Headers/x86intrin.h
+++ b/contrib/llvm/tools/clang/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
@@ -80,6 +84,8 @@
#include <mwaitxintrin.h>
#endif
-/* FIXME: LWP */
+#if !defined(_MSC_VER) || __has_feature(modules) || defined(__CLZERO__)
+#include <clzerointrin.h>
+#endif
#endif /* __X86INTRIN_H */
diff --git a/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h
index dc31b85..bbc2117 100644
--- a/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h
@@ -2067,7 +2067,7 @@ _mm_storer_ps(float *__p, __m128 __a)
/// _MM_HINT_T1: Move data using the T1 hint. The PREFETCHT1 instruction will
/// be generated. \n
/// _MM_HINT_T2: Move data using the T2 hint. The PREFETCHT2 instruction will
-/// be generated.
+/// be generated.
#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), 0, (sel)))
#endif
@@ -2099,7 +2099,7 @@ _mm_stream_pi(__m64 *__p, __m64 __a)
///
/// \param __p
/// A pointer to a 128-bit aligned memory location that will receive the
-/// integer values.
+/// single-precision floating-point values.
/// \param __a
/// A 128-bit vector of [4 x float] containing the values to be moved.
static __inline__ void __DEFAULT_FN_ATTRS
@@ -2133,7 +2133,7 @@ void _mm_sfence(void);
/// \headerfile <x86intrin.h>
///
/// \code
-/// void _mm_extract_pi(__m64 a, int n);
+/// int _mm_extract_pi16(__m64 a, int n);
/// \endcode
///
/// This intrinsic corresponds to the <c> VPEXTRW / PEXTRW </c> instruction.
@@ -2157,7 +2157,7 @@ void _mm_sfence(void);
/// \headerfile <x86intrin.h>
///
/// \code
-/// void _mm_insert_pi(__m64 a, int d, int n);
+/// __m64 _mm_insert_pi16(__m64 a, int d, int n);
/// \endcode
///
/// This intrinsic corresponds to the <c> VPINSRW / PINSRW </c> instruction.
@@ -2331,8 +2331,10 @@ _mm_mulhi_pu16(__m64 __a, __m64 __b)
/// \brief Conditionally copies the values from each 8-bit element in the first
/// 64-bit integer vector operand to the specified memory location, as
/// specified by the most significant bit in the corresponding element in the
-/// second 64-bit integer vector operand. To minimize caching, the data is
-/// flagged as non-temporal (unlikely to be used again soon).
+/// second 64-bit integer vector operand.
+///
+/// To minimize caching, the data is flagged as non-temporal
+/// (unlikely to be used again soon).
///
/// \headerfile <x86intrin.h>
///
@@ -2435,17 +2437,17 @@ extern "C" {
/// For checking exception masks: _MM_MASK_UNDERFLOW, _MM_MASK_OVERFLOW,
/// _MM_MASK_INVALID, _MM_MASK_DENORM, _MM_MASK_DIV_ZERO, _MM_MASK_INEXACT.
/// There is a convenience wrapper _MM_GET_EXCEPTION_MASK().
-/// </li>
+/// </li>
/// <li>
/// For checking rounding modes: _MM_ROUND_NEAREST, _MM_ROUND_DOWN,
/// _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO. There is a convenience wrapper
/// _MM_GET_ROUNDING_MODE(x) where x is one of these macros.
/// </li>
-/// <li>
+/// <li>
/// For checking flush-to-zero mode: _MM_FLUSH_ZERO_ON, _MM_FLUSH_ZERO_OFF.
/// There is a convenience wrapper _MM_GET_FLUSH_ZERO_MODE().
/// </li>
-/// <li>
+/// <li>
/// For checking denormals-are-zero mode: _MM_DENORMALS_ZERO_ON,
/// _MM_DENORMALS_ZERO_OFF. There is a convenience wrapper
/// _MM_GET_DENORMALS_ZERO_MODE().
@@ -2468,11 +2470,11 @@ extern "C" {
unsigned int _mm_getcsr(void);
/// \brief Sets the MXCSR register with the 32-bit unsigned integer value.
-///
+///
/// There are several groups of macros associated with this intrinsic,
/// including:
/// <ul>
-/// <li>
+/// <li>
/// For setting exception states: _MM_EXCEPT_INVALID, _MM_EXCEPT_DIV_ZERO,
/// _MM_EXCEPT_DENORM, _MM_EXCEPT_OVERFLOW, _MM_EXCEPT_UNDERFLOW,
/// _MM_EXCEPT_INEXACT. There is a convenience wrapper
@@ -2517,7 +2519,7 @@ unsigned int _mm_getcsr(void);
///
/// \param __i
/// A 32-bit unsigned integer value to be written to the MXCSR register.
-void _mm_setcsr(unsigned int);
+void _mm_setcsr(unsigned int __i);
#if defined(__cplusplus)
} // extern "C"
@@ -2540,7 +2542,7 @@ void _mm_setcsr(unsigned int);
/// A 128-bit vector of [4 x float].
/// \param mask
/// An immediate value containing an 8-bit value specifying which elements to
-/// copy from \ a and \a b. \n
+/// copy from \a a and \a b. \n
/// Bits [3:0] specify the values copied from operand \a a. \n
/// Bits [7:4] specify the values copied from operand \a b. \n
/// The destinations within the 128-bit destination are assigned values as
@@ -2678,8 +2680,7 @@ _mm_movelh_ps(__m128 __a, __m128 __b)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of [4 x i16]. The elements of the destination are copied
@@ -2709,8 +2710,7 @@ _mm_cvtpi16_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of 16-bit unsigned integer values. The elements of the
@@ -2739,8 +2739,7 @@ _mm_cvtpu16_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of [8 x i8]. The elements of the destination are copied
@@ -2764,8 +2763,7 @@ _mm_cvtpi8_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of unsigned 8-bit integer values. The elements of the
@@ -2789,8 +2787,7 @@ _mm_cvtpu8_ps(__m64 __a)
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPI2PS + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPI2PS + COMPOSITE </c> instruction.
///
/// \param __a
/// A 64-bit vector of [2 x i32]. The lower elements of the destination are
@@ -2815,16 +2812,16 @@ _mm_cvtpi32x2_ps(__m64 __a, __m64 __b)
/// \brief Converts each single-precision floating-point element of a 128-bit
/// floating-point vector of [4 x float] into a 16-bit signed integer, and
-/// packs the results into a 64-bit integer vector of [4 x i16]. If the
-/// floating-point element is NaN or infinity, or if the floating-point
-/// element is greater than 0x7FFFFFFF or less than -0x8000, it is converted
-/// to 0x8000. Otherwise if the floating-point element is greater than
-/// 0x7FFF, it is converted to 0x7FFF.
+/// packs the results into a 64-bit integer vector of [4 x i16].
+///
+/// If the floating-point element is NaN or infinity, or if the
+/// floating-point element is greater than 0x7FFFFFFF or less than -0x8000,
+/// it is converted to 0x8000. Otherwise if the floating-point element is
+/// greater than 0x7FFF, it is converted to 0x7FFF.
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPS2PI + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPS2PI + COMPOSITE </c> instruction.
///
/// \param __a
/// A 128-bit floating-point vector of [4 x float].
@@ -2845,16 +2842,16 @@ _mm_cvtps_pi16(__m128 __a)
/// \brief Converts each single-precision floating-point element of a 128-bit
/// floating-point vector of [4 x float] into an 8-bit signed integer, and
/// packs the results into the lower 32 bits of a 64-bit integer vector of
-/// [8 x i8]. The upper 32 bits of the vector are set to 0. If the
-/// floating-point element is NaN or infinity, or if the floating-point
-/// element is greater than 0x7FFFFFFF or less than -0x80, it is converted
-/// to 0x80. Otherwise if the floating-point element is greater than 0x7F,
-/// it is converted to 0x7F.
+/// [8 x i8]. The upper 32 bits of the vector are set to 0.
+///
+/// If the floating-point element is NaN or infinity, or if the
+/// floating-point element is greater than 0x7FFFFFFF or less than -0x80, it
+/// is converted to 0x80. Otherwise if the floating-point element is greater
+/// than 0x7F, it is converted to 0x7F.
///
/// \headerfile <x86intrin.h>
///
-/// This intrinsic corresponds to the <c> CVTPS2PI + \c COMPOSITE </c>
-/// instruction.
+/// This intrinsic corresponds to the <c> CVTPS2PI + COMPOSITE </c> instruction.
///
/// \param __a
/// 128-bit floating-point vector of [4 x float].
diff --git a/contrib/llvm/tools/clang/lib/Headers/xopintrin.h b/contrib/llvm/tools/clang/lib/Headers/xopintrin.h
index bdf0cec..4a34f77 100644
--- a/contrib/llvm/tools/clang/lib/Headers/xopintrin.h
+++ b/contrib/llvm/tools/clang/lib/Headers/xopintrin.h
@@ -198,13 +198,13 @@ _mm_hsubq_epi32(__m128i __A)
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cmov_si128(__m128i __A, __m128i __B, __m128i __C)
{
- return (__m128i)__builtin_ia32_vpcmov((__v2di)__A, (__v2di)__B, (__v2di)__C);
+ return (__m128i)(((__v2du)__A & (__v2du)__C) | ((__v2du)__B & ~(__v2du)__C));
}
static __inline__ __m256i __DEFAULT_FN_ATTRS
_mm256_cmov_si256(__m256i __A, __m256i __B, __m256i __C)
{
- return (__m256i)__builtin_ia32_vpcmov_256((__v4di)__A, (__v4di)__B, (__v4di)__C);
+ return (__m256i)(((__v4du)__A & (__v4du)__C) | ((__v4du)__B & ~(__v4du)__C));
}
static __inline__ __m128i __DEFAULT_FN_ATTRS
diff --git a/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp b/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp
index ee066cc..e568c83 100644
--- a/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp
+++ b/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp
@@ -592,10 +592,10 @@ void CommentASTToXMLConverter::formatTextOfDeclaration(
unsigned Offset = 0;
unsigned Length = Declaration.size();
- bool IncompleteFormat = false;
+ format::FormatStyle Style = format::getLLVMStyle();
+ Style.FixNamespaceComments = false;
tooling::Replacements Replaces =
- reformat(format::getLLVMStyle(), StringDecl,
- tooling::Range(Offset, Length), "xmldecl.xd", &IncompleteFormat);
+ reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd");
auto FormattedStringDecl = applyAllReplacements(StringDecl, Replaces);
if (static_cast<bool>(FormattedStringDecl)) {
Declaration = *FormattedStringDecl;
diff --git a/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp b/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp
index 3aa0152..6bbd381 100644
--- a/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp
+++ b/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp
@@ -22,6 +22,10 @@ class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {
SmallVector<Stmt*, 16> StmtStack;
typedef RecursiveASTVisitor<BodyIndexer> base;
+
+ Stmt *getParentStmt() const {
+ return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2];
+ }
public:
BodyIndexer(IndexingContext &indexCtx,
const NamedDecl *Parent, const DeclContext *DC)
@@ -146,6 +150,53 @@ public:
Parent, ParentDC, Roles, Relations, E);
}
+ bool indexDependentReference(
+ const Expr *E, const Type *T, const DeclarationNameInfo &NameInfo,
+ llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
+ if (!T)
+ return true;
+ const TemplateSpecializationType *TST =
+ T->getAs<TemplateSpecializationType>();
+ if (!TST)
+ return true;
+ TemplateName TN = TST->getTemplateName();
+ const ClassTemplateDecl *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ return true;
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ if (!RD->hasDefinition())
+ return true;
+ RD = RD->getDefinition();
+ std::vector<const NamedDecl *> Symbols =
+ RD->lookupDependentName(NameInfo.getName(), Filter);
+ // FIXME: Improve overload handling.
+ if (Symbols.size() != 1)
+ return true;
+ SourceLocation Loc = NameInfo.getLoc();
+ if (Loc.isInvalid())
+ Loc = E->getLocStart();
+ SmallVector<SymbolRelation, 4> Relations;
+ SymbolRoleSet Roles = getRolesForRef(E, Relations);
+ return IndexCtx.handleReference(Symbols[0], Loc, Parent, ParentDC, Roles,
+ Relations, E);
+ }
+
+ bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
+ const DeclarationNameInfo &Info = E->getMemberNameInfo();
+ return indexDependentReference(
+ E, E->getBaseType().getTypePtrOrNull(), Info,
+ [](const NamedDecl *D) { return D->isCXXInstanceMember(); });
+ }
+
+ bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+ const DeclarationNameInfo &Info = E->getNameInfo();
+ const NestedNameSpecifier *NNS = E->getQualifier();
+ return indexDependentReference(
+ E, NNS->getAsType(), Info,
+ [](const NamedDecl *D) { return !D->isCXXInstanceMember(); });
+ }
+
bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {
for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {
if (D.isFieldDesignator() && D.getField())
@@ -178,7 +229,32 @@ public:
SymbolRoleSet Roles{};
SmallVector<SymbolRelation, 2> Relations;
addCallRole(Roles, Relations);
- if (E->isImplicit())
+ Stmt *Containing = getParentStmt();
+
+ auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool {
+ const auto *E = POE->getSyntacticForm();
+ if (const auto *BinOp = dyn_cast<BinaryOperator>(E))
+ E = BinOp->getLHS();
+ const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E);
+ if (!PRE)
+ return false;
+ if (PRE->isExplicitProperty())
+ return false;
+ if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) {
+ // Class properties that are explicitly defined using @property
+ // declarations are represented implicitly as there is no ivar for
+ // class properties.
+ if (Getter->isClassMethod() &&
+ Getter->getCanonicalDecl()->findPropertyDecl())
+ return false;
+ }
+ return true;
+ };
+ bool IsPropCall = Containing && isa<PseudoObjectExpr>(Containing);
+ // Implicit property message sends are not 'implicit'.
+ if ((E->isImplicit() || IsPropCall) &&
+ !(IsPropCall &&
+ IsImplicitProperty(cast<PseudoObjectExpr>(Containing))))
Roles |= (unsigned)SymbolRole::Implicit;
if (isDynamic(E)) {
@@ -194,9 +270,27 @@ public:
}
bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- if (E->isExplicitProperty())
+ if (E->isClassReceiver())
+ IndexCtx.handleReference(E->getClassReceiver(), E->getReceiverLocation(),
+ Parent, ParentDC);
+ if (E->isExplicitProperty()) {
+ SmallVector<SymbolRelation, 2> Relations;
+ SymbolRoleSet Roles = getRolesForRef(E, Relations);
return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),
- Parent, ParentDC, SymbolRoleSet(), {}, E);
+ Parent, ParentDC, Roles, Relations, E);
+ } else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) {
+ // Class properties that are explicitly defined using @property
+ // declarations are represented implicitly as there is no ivar for class
+ // properties.
+ if (Getter->isClassMethod()) {
+ if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) {
+ SmallVector<SymbolRelation, 2> Relations;
+ SymbolRoleSet Roles = getRolesForRef(E, Relations);
+ return IndexCtx.handleReference(PD, E->getLocation(), Parent,
+ ParentDC, Roles, Relations, E);
+ }
+ }
+ }
// No need to do a handleReference for the objc method, because there will
// be a message expr as part of PseudoObjectExpr.
@@ -269,7 +363,7 @@ public:
const Decl *D = *I;
if (!D)
continue;
- if (!IndexCtx.isFunctionLocalDecl(D))
+ if (!isFunctionLocalSymbol(D))
IndexCtx.indexTopLevelDecl(D);
}
diff --git a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp
index 3b4f3f8..c5230c0 100644
--- a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp
+++ b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp
@@ -14,6 +14,13 @@
using namespace clang;
using namespace index;
+#define TRY_DECL(D,CALL_EXPR) \
+ do { \
+ if (!IndexCtx.shouldIndex(D)) return true; \
+ if (!CALL_EXPR) \
+ return false; \
+ } while (0)
+
#define TRY_TO(CALL_EXPR) \
do { \
if (!CALL_EXPR) \
@@ -45,6 +52,33 @@ public:
return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition();
}
+ void handleTemplateArgumentLoc(const TemplateArgumentLoc &TALoc,
+ const NamedDecl *Parent,
+ const DeclContext *DC) {
+ const TemplateArgumentLocInfo &LocInfo = TALoc.getLocInfo();
+ switch (TALoc.getArgument().getKind()) {
+ case TemplateArgument::Expression:
+ IndexCtx.indexBody(LocInfo.getAsExpr(), Parent, DC);
+ break;
+ case TemplateArgument::Type:
+ IndexCtx.indexTypeSourceInfo(LocInfo.getAsTypeSourceInfo(), Parent, DC);
+ break;
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ IndexCtx.indexNestedNameSpecifierLoc(TALoc.getTemplateQualifierLoc(),
+ Parent, DC);
+ if (const TemplateDecl *TD = TALoc.getArgument()
+ .getAsTemplateOrTemplatePattern()
+ .getAsTemplateDecl()) {
+ if (const NamedDecl *TTD = TD->getTemplatedDecl())
+ IndexCtx.handleReference(TTD, TALoc.getTemplateNameLoc(), Parent, DC);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
void handleDeclarator(const DeclaratorDecl *D,
const NamedDecl *Parent = nullptr,
bool isIBType = false) {
@@ -75,6 +109,17 @@ public:
}
}
}
+ } else {
+ // Index the default parameter value for function definitions.
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isThisDeclarationADefinition()) {
+ for (const auto *PV : FD->parameters()) {
+ if (PV->hasDefaultArg() && !PV->hasUninstantiatedDefaultArg() &&
+ !PV->hasUnparsedDefaultArg())
+ IndexCtx.indexBody(PV->getDefaultArg(), D);
+ }
+ }
+ }
}
}
@@ -98,8 +143,29 @@ public:
if (MethodLoc.isInvalid())
MethodLoc = D->getLocation();
- if (!IndexCtx.handleDecl(D, MethodLoc, (unsigned)SymbolRole::Dynamic, Relations))
- return false;
+ SourceLocation AttrLoc;
+
+ // check for (getter=/setter=)
+ if (AssociatedProp) {
+ bool isGetter = !D->param_size();
+ AttrLoc = isGetter ?
+ AssociatedProp->getGetterNameLoc():
+ AssociatedProp->getSetterNameLoc();
+ }
+
+ SymbolRoleSet Roles = (SymbolRoleSet)SymbolRole::Dynamic;
+ if (D->isImplicit()) {
+ if (AttrLoc.isValid()) {
+ MethodLoc = AttrLoc;
+ } else {
+ Roles |= (SymbolRoleSet)SymbolRole::Implicit;
+ }
+ } else if (AttrLoc.isValid()) {
+ IndexCtx.handleReference(D, AttrLoc, cast<NamedDecl>(D->getDeclContext()),
+ D->getDeclContext(), 0);
+ }
+
+ TRY_DECL(D, IndexCtx.handleDecl(D, MethodLoc, Roles, Relations));
IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D);
bool hasIBActionAndFirst = D->hasAttr<IBActionAttr>();
for (const auto *I : D->parameters()) {
@@ -116,10 +182,52 @@ public:
return true;
}
- bool VisitFunctionDecl(const FunctionDecl *D) {
- if (D->isDeleted())
- return true;
+ /// Gather the declarations which the given declaration \D overrides in a
+ /// pseudo-override manner.
+ ///
+ /// Pseudo-overrides occur when a class template specialization declares
+ /// a declaration that has the same name as a similar declaration in the
+ /// non-specialized template.
+ void
+ gatherTemplatePseudoOverrides(const NamedDecl *D,
+ SmallVectorImpl<SymbolRelation> &Relations) {
+ if (!IndexCtx.getLangOpts().CPlusPlus)
+ return;
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(D->getLexicalDeclContext());
+ if (!CTSD)
+ return;
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ Template = CTSD->getSpecializedTemplateOrPartial();
+ if (const auto *CTD = Template.dyn_cast<ClassTemplateDecl *>()) {
+ const CXXRecordDecl *Pattern = CTD->getTemplatedDecl();
+ bool TypeOverride = isa<TypeDecl>(D);
+ for (const NamedDecl *ND : Pattern->lookup(D->getDeclName())) {
+ if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND))
+ ND = CTD->getTemplatedDecl();
+ if (ND->isImplicit())
+ continue;
+ // Types can override other types.
+ if (!TypeOverride) {
+ if (ND->getKind() != D->getKind())
+ continue;
+ } else if (!isa<TypeDecl>(ND))
+ continue;
+ if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
+ const auto *DFD = cast<FunctionDecl>(D);
+ // Function overrides are approximated using the number of parameters.
+ if (FD->getStorageClass() != DFD->getStorageClass() ||
+ FD->getNumParams() != DFD->getNumParams())
+ continue;
+ }
+ Relations.emplace_back(
+ SymbolRoleSet(SymbolRole::RelationSpecializationOf), ND);
+ }
+ }
+ }
+ bool VisitFunctionDecl(const FunctionDecl *D) {
SymbolRoleSet Roles{};
SmallVector<SymbolRelation, 4> Relations;
if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) {
@@ -130,12 +238,19 @@ public:
Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
}
}
+ gatherTemplatePseudoOverrides(D, Relations);
+ if (const auto *Base = D->getPrimaryTemplate())
+ Relations.push_back(
+ SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
+ Base->getTemplatedDecl()));
- if (!IndexCtx.handleDecl(D, Roles, Relations))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations));
handleDeclarator(D);
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
+ IndexCtx.handleReference(Ctor->getParent(), Ctor->getLocation(),
+ Ctor->getParent(), Ctor->getDeclContext());
+
// Constructor initializers.
for (const auto *Init : Ctor->inits()) {
if (Init->isWritten()) {
@@ -146,6 +261,18 @@ public:
IndexCtx.indexBody(Init->getInit(), D, D);
}
}
+ } else if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(D)) {
+ if (auto TypeNameInfo = Dtor->getNameInfo().getNamedTypeInfo()) {
+ IndexCtx.handleReference(Dtor->getParent(),
+ TypeNameInfo->getTypeLoc().getLocStart(),
+ Dtor->getParent(), Dtor->getDeclContext());
+ }
+ }
+ // Template specialization arguments.
+ if (const ASTTemplateArgumentListInfo *TemplateArgInfo =
+ D->getTemplateSpecializationArgsAsWritten()) {
+ for (const auto &Arg : TemplateArgInfo->arguments())
+ handleTemplateArgumentLoc(Arg, D, D->getLexicalDeclContext());
}
if (D->isThisDeclarationADefinition()) {
@@ -158,16 +285,24 @@ public:
}
bool VisitVarDecl(const VarDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
handleDeclarator(D);
IndexCtx.indexBody(D->getInit(), D);
return true;
}
+ bool VisitDecompositionDecl(const DecompositionDecl *D) {
+ for (const auto *Binding : D->bindings())
+ TRY_DECL(Binding, IndexCtx.handleDecl(Binding));
+ return Base::VisitDecompositionDecl(D);
+ }
+
bool VisitFieldDecl(const FieldDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
handleDeclarator(D);
if (D->isBitField())
IndexCtx.indexBody(D->getBitWidth(), D);
@@ -178,17 +313,10 @@ public:
bool VisitObjCIvarDecl(const ObjCIvarDecl *D) {
if (D->getSynthesize()) {
- // For synthesized ivars, use the location of the ObjC implementation,
- // not the location of the property.
- // Otherwise the header file containing the @interface will have different
- // indexing contents based on whether the @implementation was present or
- // not in the translation unit.
- return IndexCtx.handleDecl(D,
- cast<Decl>(D->getDeclContext())->getLocation(),
- (unsigned)SymbolRole::Implicit);
+ // handled in VisitObjCPropertyImplDecl
+ return true;
}
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
handleDeclarator(D);
return true;
}
@@ -199,16 +327,18 @@ public:
}
bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
IndexCtx.indexBody(D->getInitExpr(), D);
return true;
}
bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
- IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+ if (!D->isTransparentTag()) {
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
+ IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+ }
return true;
}
@@ -216,26 +346,33 @@ public:
// Non-free standing tags are handled in indexTypeSourceInfo.
if (D->isFreeStanding()) {
if (D->isThisDeclarationADefinition()) {
- IndexCtx.indexTagDecl(D);
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ IndexCtx.indexTagDecl(D, Relations);
} else {
auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
+ SmallVector<SymbolRelation, 1> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
return IndexCtx.handleReference(D, D->getLocation(), Parent,
D->getLexicalDeclContext(),
- SymbolRoleSet());
+ SymbolRoleSet(), Relations);
}
}
return true;
}
bool handleReferencedProtocols(const ObjCProtocolList &ProtList,
- const ObjCContainerDecl *ContD) {
+ const ObjCContainerDecl *ContD,
+ SourceLocation SuperLoc) {
ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin();
for (ObjCInterfaceDecl::protocol_iterator
I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) {
SourceLocation Loc = *LI;
ObjCProtocolDecl *PD = *I;
- TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD,
- SymbolRoleSet(),
+ SymbolRoleSet roles{};
+ if (Loc == SuperLoc)
+ roles |= (SymbolRoleSet)SymbolRole::Implicit;
+ TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, roles,
SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD}));
}
return true;
@@ -243,13 +380,27 @@ public:
bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
if (D->isThisDeclarationADefinition()) {
- TRY_TO(IndexCtx.handleDecl(D));
+ TRY_DECL(D, IndexCtx.handleDecl(D));
+ SourceLocation SuperLoc = D->getSuperClassLoc();
if (auto *SuperD = D->getSuperClass()) {
- TRY_TO(IndexCtx.handleReference(SuperD, D->getSuperClassLoc(), D, D,
- SymbolRoleSet(),
+ bool hasSuperTypedef = false;
+ if (auto *TInfo = D->getSuperClassTInfo()) {
+ if (auto *TT = TInfo->getType()->getAs<TypedefType>()) {
+ if (auto *TD = TT->getDecl()) {
+ hasSuperTypedef = true;
+ TRY_TO(IndexCtx.handleReference(TD, SuperLoc, D, D,
+ SymbolRoleSet()));
+ }
+ }
+ }
+ SymbolRoleSet superRoles{};
+ if (hasSuperTypedef)
+ superRoles |= (SymbolRoleSet)SymbolRole::Implicit;
+ TRY_TO(IndexCtx.handleReference(SuperD, SuperLoc, D, D, superRoles,
SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D}));
}
- TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D));
+ TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
+ SuperLoc));
TRY_TO(IndexCtx.indexDeclContext(D));
} else {
return IndexCtx.handleReference(D, D->getLocation(), nullptr,
@@ -260,8 +411,9 @@ public:
bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
if (D->isThisDeclarationADefinition()) {
- TRY_TO(IndexCtx.handleDecl(D));
- TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D));
+ TRY_DECL(D, IndexCtx.handleDecl(D));
+ TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
+ /*superLoc=*/SourceLocation()));
TRY_TO(IndexCtx.indexDeclContext(D));
} else {
return IndexCtx.handleReference(D, D->getLocation(), nullptr,
@@ -278,15 +430,18 @@ public:
if (Class->isImplicitInterfaceDecl())
IndexCtx.handleDecl(Class);
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
- // Index the ivars first to make sure the synthesized ivars are indexed
- // before indexing the methods that can reference them.
- for (const auto *IvarI : D->ivars())
- IndexCtx.indexDecl(IvarI);
+ // Visit implicit @synthesize property implementations first as their
+ // location is reported at the name of the @implementation block. This
+ // serves no purpose other than to simplify the FileCheck-based tests.
+ for (const auto *I : D->property_impls()) {
+ if (I->getLocation().isInvalid())
+ IndexCtx.indexDecl(I);
+ }
for (const auto *I : D->decls()) {
- if (!isa<ObjCIvarDecl>(I))
+ if (!isa<ObjCPropertyImplDecl>(I) ||
+ cast<ObjCPropertyImplDecl>(I)->getLocation().isValid())
IndexCtx.indexDecl(I);
}
@@ -294,6 +449,8 @@ public:
}
bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
+ if (!IndexCtx.shouldIndex(D))
+ return true;
const ObjCInterfaceDecl *C = D->getClassInterface();
if (!C)
return true;
@@ -305,7 +462,8 @@ public:
if (!CategoryLoc.isValid())
CategoryLoc = D->getLocation();
TRY_TO(IndexCtx.handleDecl(D, CategoryLoc));
- TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D));
+ TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D,
+ /*superLoc=*/SourceLocation()));
TRY_TO(IndexCtx.indexDeclContext(D));
return true;
}
@@ -321,8 +479,7 @@ public:
SourceLocation CategoryLoc = D->getCategoryNameLoc();
if (!CategoryLoc.isValid())
CategoryLoc = D->getLocation();
- if (!IndexCtx.handleDecl(D, CategoryLoc))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D, CategoryLoc));
IndexCtx.indexDeclContext(D);
return true;
}
@@ -344,8 +501,7 @@ public:
if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
handleObjCMethod(MD, D);
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
if (IBOutletCollectionAttr *attr = D->getAttr<IBOutletCollectionAttr>())
IndexCtx.indexTypeSourceInfo(attr->getInterfaceLoc(), D,
D->getLexicalDeclContext(), false, true);
@@ -355,43 +511,74 @@ public:
bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
ObjCPropertyDecl *PD = D->getPropertyDecl();
- if (!IndexCtx.handleReference(PD, D->getLocation(),
- /*Parent=*/cast<NamedDecl>(D->getDeclContext()),
- D->getDeclContext(), SymbolRoleSet(), {},
- /*RefE=*/nullptr, D))
- return false;
+ auto *Container = cast<ObjCImplDecl>(D->getDeclContext());
+ SourceLocation Loc = D->getLocation();
+ SymbolRoleSet Roles = 0;
+ SmallVector<SymbolRelation, 1> Relations;
+
+ if (ObjCIvarDecl *ID = D->getPropertyIvarDecl())
+ Relations.push_back({(SymbolRoleSet)SymbolRole::RelationAccessorOf, ID});
+ if (Loc.isInvalid()) {
+ Loc = Container->getLocation();
+ Roles |= (SymbolRoleSet)SymbolRole::Implicit;
+ }
+ TRY_DECL(D, IndexCtx.handleDecl(D, Loc, Roles, Relations));
if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
return true;
- assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
-
- if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
- if (!IvarD->getSynthesize())
- IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
- D->getDeclContext(), SymbolRoleSet());
- }
- auto *ImplD = cast<ObjCImplDecl>(D->getDeclContext());
+ assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
+ SymbolRoleSet AccessorMethodRoles =
+ SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit);
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
if (MD->isPropertyAccessor() &&
- !hasUserDefined(MD, ImplD))
- IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD);
+ !hasUserDefined(MD, Container))
+ IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
}
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
if (MD->isPropertyAccessor() &&
- !hasUserDefined(MD, ImplD))
- IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD);
+ !hasUserDefined(MD, Container))
+ IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container);
+ }
+ if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
+ if (IvarD->getSynthesize()) {
+ // For synthesized ivars, use the location of its name in the
+ // corresponding @synthesize. If there isn't one, use the containing
+ // @implementation's location, rather than the property's location,
+ // otherwise the header file containing the @interface will have different
+ // indexing contents based on whether the @implementation was present or
+ // not in the translation unit.
+ SymbolRoleSet IvarRoles = 0;
+ SourceLocation IvarLoc = D->getPropertyIvarDeclLoc();
+ if (D->getLocation().isInvalid()) {
+ IvarLoc = Container->getLocation();
+ IvarRoles = (SymbolRoleSet)SymbolRole::Implicit;
+ } else if (D->getLocation() == IvarLoc) {
+ IvarRoles = (SymbolRoleSet)SymbolRole::Implicit;
+ }
+ TRY_DECL(IvarD, IndexCtx.handleDecl(IvarD, IvarLoc, IvarRoles));
+ } else {
+ IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr,
+ D->getDeclContext(), SymbolRoleSet());
+ }
}
return true;
}
bool VisitNamespaceDecl(const NamespaceDecl *D) {
- if (!IndexCtx.handleDecl(D))
- return false;
+ TRY_DECL(D, IndexCtx.handleDecl(D));
IndexCtx.indexDeclContext(D);
return true;
}
+ bool VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
+ TRY_DECL(D, IndexCtx.handleDecl(D));
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
+ IndexCtx.handleReference(D->getAliasedNamespace(), D->getTargetNameLoc(), D,
+ D->getLexicalDeclContext());
+ return true;
+ }
+
bool VisitUsingDecl(const UsingDecl *D) {
const DeclContext *DC = D->getDeclContext()->getRedeclContext();
const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
@@ -408,8 +595,12 @@ public:
const DeclContext *DC = D->getDeclContext()->getRedeclContext();
const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
- IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
- D->getLexicalDeclContext());
+ // NNS for the local 'using namespace' directives is visited by the body
+ // visitor.
+ if (!D->getParentFunctionOrMethod())
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
+ D->getLexicalDeclContext());
+
return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
D->getLocation(), Parent,
D->getLexicalDeclContext(),
@@ -420,13 +611,61 @@ public:
ClassTemplateSpecializationDecl *D) {
// FIXME: Notify subsequent callbacks if info comes from implicit
// instantiation.
- if (D->isThisDeclarationADefinition())
- IndexCtx.indexTagDecl(D);
+ llvm::PointerUnion<ClassTemplateDecl *,
+ ClassTemplatePartialSpecializationDecl *>
+ Template = D->getSpecializedTemplateOrPartial();
+ const Decl *SpecializationOf =
+ Template.is<ClassTemplateDecl *>()
+ ? (Decl *)Template.get<ClassTemplateDecl *>()
+ : Template.get<ClassTemplatePartialSpecializationDecl *>();
+ if (!D->isThisDeclarationADefinition())
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
+ IndexCtx.indexTagDecl(
+ D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
+ SpecializationOf));
+ if (TypeSourceInfo *TSI = D->getTypeAsWritten())
+ IndexCtx.indexTypeSourceInfo(TSI, /*Parent=*/nullptr,
+ D->getLexicalDeclContext());
+ return true;
+ }
+
+ static bool shouldIndexTemplateParameterDefaultValue(const NamedDecl *D) {
+ if (!D)
+ return false;
+ // We want to index the template parameters only once when indexing the
+ // canonical declaration.
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getCanonicalDecl() == FD;
+ else if (const auto *TD = dyn_cast<TagDecl>(D))
+ return TD->getCanonicalDecl() == TD;
+ else if (const auto *VD = dyn_cast<VarDecl>(D))
+ return VD->getCanonicalDecl() == VD;
return true;
}
bool VisitTemplateDecl(const TemplateDecl *D) {
// FIXME: Template parameters.
+
+ // Index the default values for the template parameters.
+ const NamedDecl *Parent = D->getTemplatedDecl();
+ if (D->getTemplateParameters() &&
+ shouldIndexTemplateParameterDefaultValue(Parent)) {
+ const TemplateParameterList *Params = D->getTemplateParameters();
+ for (const NamedDecl *TP : *Params) {
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(TP)) {
+ if (TTP->hasDefaultArgument())
+ IndexCtx.indexTypeSourceInfo(TTP->getDefaultArgumentInfo(), Parent);
+ } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TP)) {
+ if (NTTP->hasDefaultArgument())
+ IndexCtx.indexBody(NTTP->getDefaultArgument(), Parent);
+ } else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(TP)) {
+ if (TTPD->hasDefaultArgument())
+ handleTemplateArgumentLoc(TTPD->getDefaultArgument(), Parent,
+ /*DC=*/nullptr);
+ }
+ }
+ }
+
return Visit(D->getTemplatedDecl());
}
@@ -451,6 +690,13 @@ public:
bool VisitImportDecl(const ImportDecl *D) {
return IndexCtx.importedModule(D);
}
+
+ bool VisitStaticAssertDecl(const StaticAssertDecl *D) {
+ IndexCtx.indexBody(D->getAssertExpr(),
+ dyn_cast<NamedDecl>(D->getDeclContext()),
+ D->getLexicalDeclContext());
+ return true;
+ }
};
} // anonymous namespace
diff --git a/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp b/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp
index 84984fc..0dc3720 100644
--- a/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp
+++ b/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp
@@ -49,6 +49,41 @@ static void checkForIBOutlets(const Decl *D, SymbolPropertySet &PropSet) {
}
}
+bool index::isFunctionLocalSymbol(const Decl *D) {
+ assert(D);
+
+ if (isa<ParmVarDecl>(D))
+ return true;
+
+ if (isa<TemplateTemplateParmDecl>(D))
+ return true;
+
+ if (isa<ObjCTypeParamDecl>(D))
+ return true;
+
+ if (isa<UsingDirectiveDecl>(D))
+ return false;
+ if (!D->getParentFunctionOrMethod())
+ return false;
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ switch (ND->getFormalLinkage()) {
+ case NoLinkage:
+ case InternalLinkage:
+ return true;
+ case VisibleNoLinkage:
+ case UniqueExternalLinkage:
+ case ModuleInternalLinkage:
+ llvm_unreachable("Not a sema linkage");
+ case ModuleLinkage:
+ case ExternalLinkage:
+ return false;
+ }
+ }
+
+ return true;
+}
+
SymbolInfo index::getSymbolInfo(const Decl *D) {
assert(D);
SymbolInfo Info;
@@ -57,6 +92,10 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
Info.Properties = SymbolPropertySet();
Info.Lang = SymbolLanguage::C;
+ if (isFunctionLocalSymbol(D)) {
+ Info.Properties |= (unsigned)SymbolProperty::Local;
+ }
+
if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
case TTK_Struct:
@@ -94,10 +133,13 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
Info.Kind = SymbolKind::Variable;
- if (isa<CXXRecordDecl>(D->getDeclContext())) {
+ if (isa<ParmVarDecl>(D)) {
+ Info.Kind = SymbolKind::Parameter;
+ } else if (isa<CXXRecordDecl>(D->getDeclContext())) {
Info.Kind = SymbolKind::StaticProperty;
Info.Lang = SymbolLanguage::CXX;
}
+
if (isa<VarTemplatePartialSpecializationDecl>(D)) {
Info.Lang = SymbolLanguage::CXX;
Info.Properties |= (unsigned)SymbolProperty::Generic;
@@ -147,10 +189,18 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
Info.Lang = SymbolLanguage::ObjC;
break;
case Decl::ObjCCategory:
- case Decl::ObjCCategoryImpl:
+ case Decl::ObjCCategoryImpl: {
Info.Kind = SymbolKind::Extension;
Info.Lang = SymbolLanguage::ObjC;
+ const ObjCInterfaceDecl *ClsD = nullptr;
+ if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D))
+ ClsD = CatD->getClassInterface();
+ else
+ ClsD = cast<ObjCCategoryImplDecl>(D)->getClassInterface();
+ if (isUnitTestCase(ClsD))
+ Info.Properties |= (unsigned)SymbolProperty::UnitTest;
break;
+ }
case Decl::ObjCMethod:
if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) {
const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);
@@ -253,6 +303,10 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
Info.Kind = SymbolKind::TypeAlias;
Info.Lang = SymbolLanguage::CXX;
break;
+ case Decl::Binding:
+ Info.Kind = SymbolKind::Variable;
+ Info.Lang = SymbolLanguage::CXX;
+ break;
default:
break;
}
@@ -272,14 +326,20 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
if (Info.Properties & (unsigned)SymbolProperty::Generic)
Info.Lang = SymbolLanguage::CXX;
+ if (auto *attr = D->getExternalSourceSymbolAttr()) {
+ if (attr->getLanguage() == "Swift")
+ Info.Lang = SymbolLanguage::Swift;
+ }
+
return Info;
}
-void index::applyForEachSymbolRole(SymbolRoleSet Roles,
- llvm::function_ref<void(SymbolRole)> Fn) {
+bool index::applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles,
+ llvm::function_ref<bool(SymbolRole)> Fn) {
#define APPLY_FOR_ROLE(Role) \
if (Roles & (unsigned)SymbolRole::Role) \
- Fn(SymbolRole::Role)
+ if (!Fn(SymbolRole::Role)) \
+ return false;
APPLY_FOR_ROLE(Declaration);
APPLY_FOR_ROLE(Definition);
@@ -299,8 +359,19 @@ void index::applyForEachSymbolRole(SymbolRoleSet Roles,
APPLY_FOR_ROLE(RelationAccessorOf);
APPLY_FOR_ROLE(RelationContainedBy);
APPLY_FOR_ROLE(RelationIBTypeOf);
+ APPLY_FOR_ROLE(RelationSpecializationOf);
#undef APPLY_FOR_ROLE
+
+ return true;
+}
+
+void index::applyForEachSymbolRole(SymbolRoleSet Roles,
+ llvm::function_ref<void(SymbolRole)> Fn) {
+ applyForEachSymbolRoleInterruptible(Roles, [&](SymbolRole r) -> bool {
+ Fn(r);
+ return true;
+ });
}
void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {
@@ -329,6 +400,7 @@ void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {
case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break;
case SymbolRole::RelationContainedBy: OS << "RelCont"; break;
case SymbolRole::RelationIBTypeOf: OS << "RelIBType"; break;
+ case SymbolRole::RelationSpecializationOf: OS << "RelSpecialization"; break;
}
});
}
@@ -378,6 +450,7 @@ StringRef index::getSymbolKindString(SymbolKind K) {
case SymbolKind::Constructor: return "constructor";
case SymbolKind::Destructor: return "destructor";
case SymbolKind::ConversionFunction: return "coversion-func";
+ case SymbolKind::Parameter: return "param";
}
llvm_unreachable("invalid symbol kind");
}
@@ -398,6 +471,7 @@ StringRef index::getSymbolLanguageString(SymbolLanguage K) {
case SymbolLanguage::C: return "C";
case SymbolLanguage::ObjC: return "ObjC";
case SymbolLanguage::CXX: return "C++";
+ case SymbolLanguage::Swift: return "Swift";
}
llvm_unreachable("invalid symbol language kind");
}
@@ -415,6 +489,7 @@ void index::applyForEachSymbolProperty(SymbolPropertySet Props,
APPLY_FOR_PROPERTY(IBAnnotated);
APPLY_FOR_PROPERTY(IBOutletCollection);
APPLY_FOR_PROPERTY(GKInspectable);
+ APPLY_FOR_PROPERTY(Local);
#undef APPLY_FOR_PROPERTY
}
@@ -434,6 +509,7 @@ void index::printSymbolProperties(SymbolPropertySet Props, raw_ostream &OS) {
case SymbolProperty::IBAnnotated: OS << "IB"; break;
case SymbolProperty::IBOutletCollection: OS << "IBColl"; break;
case SymbolProperty::GKInspectable: OS << "GKI"; break;
+ case SymbolProperty::Local: OS << "local"; break;
}
});
}
diff --git a/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp b/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp
index 38bbb30..ae27ebe 100644
--- a/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp
+++ b/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp
@@ -40,18 +40,36 @@ public:
bool shouldWalkTypesOfTypeLocs() const { return false; }
- bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
- return IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(),
- Parent, ParentDC, SymbolRoleSet(),
- Relations);
- }
-
#define TRY_TO(CALL_EXPR) \
do { \
if (!CALL_EXPR) \
return false; \
} while (0)
+ bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ SourceLocation Loc = TL.getNameLoc();
+ TypedefNameDecl *ND = TL.getTypedefNameDecl();
+ if (ND->isTransparentTag()) {
+ TagDecl *Underlying = ND->getUnderlyingType()->getAsTagDecl();
+ return IndexCtx.handleReference(Underlying, Loc, Parent,
+ ParentDC, SymbolRoleSet(), Relations);
+ }
+ if (IsBase) {
+ TRY_TO(IndexCtx.handleReference(ND, Loc,
+ Parent, ParentDC, SymbolRoleSet()));
+ if (auto *CD = TL.getType()->getAsCXXRecordDecl()) {
+ TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC,
+ (unsigned)SymbolRole::Implicit,
+ Relations));
+ }
+ } else {
+ TRY_TO(IndexCtx.handleReference(ND, Loc,
+ Parent, ParentDC, SymbolRoleSet(),
+ Relations));
+ }
+ return true;
+ }
+
bool traverseParamVarHelper(ParmVarDecl *D) {
TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc()));
if (D->getTypeSourceInfo())
@@ -123,6 +141,34 @@ public:
return true;
}
+ bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ const DependentNameType *DNT = TL.getTypePtr();
+ const NestedNameSpecifier *NNS = DNT->getQualifier();
+ const Type *T = NNS->getAsType();
+ if (!T)
+ return true;
+ const TemplateSpecializationType *TST =
+ T->getAs<TemplateSpecializationType>();
+ if (!TST)
+ return true;
+ TemplateName TN = TST->getTemplateName();
+ const ClassTemplateDecl *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ return true;
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ if (!RD->hasDefinition())
+ return true;
+ RD = RD->getDefinition();
+ DeclarationName Name(DNT->getIdentifier());
+ std::vector<const NamedDecl *> Symbols = RD->lookupDependentName(
+ Name, [](const NamedDecl *ND) { return isa<TypeDecl>(ND); });
+ if (Symbols.size() != 1)
+ return true;
+ return IndexCtx.handleReference(Symbols[0], TL.getNameLoc(), Parent,
+ ParentDC, SymbolRoleSet(), Relations);
+ }
+
bool TraverseStmt(Stmt *S) {
IndexCtx.indexBody(S, Parent, ParentDC);
return true;
@@ -166,7 +212,7 @@ void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
if (!DC)
DC = Parent->getLexicalDeclContext();
- SourceLocation Loc = NNS.getSourceRange().getBegin();
+ SourceLocation Loc = NNS.getLocalBeginLoc();
switch (NNS.getNestedNameSpecifier()->getKind()) {
case NestedNameSpecifier::Identifier:
@@ -190,11 +236,14 @@ void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
}
}
-void IndexingContext::indexTagDecl(const TagDecl *D) {
- if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
+void IndexingContext::indexTagDecl(const TagDecl *D,
+ ArrayRef<SymbolRelation> Relations) {
+ if (!shouldIndex(D))
+ return;
+ if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
return;
- if (handleDecl(D)) {
+ if (handleDecl(D, /*Roles=*/SymbolRoleSet(), Relations)) {
if (D->isThisDeclarationADefinition()) {
indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) {
diff --git a/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp b/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp
index d744293..84d3120 100644
--- a/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp
+++ b/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp
@@ -13,6 +13,7 @@
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Serialization/ASTReader.h"
using namespace clang;
using namespace clang::index;
@@ -173,4 +174,32 @@ void index::indexASTUnit(ASTUnit &Unit,
IndexCtx.setASTContext(Unit.getASTContext());
DataConsumer->initialize(Unit.getASTContext());
indexTranslationUnit(Unit, IndexCtx);
+ DataConsumer->finish();
+}
+
+void index::indexTopLevelDecls(ASTContext &Ctx, ArrayRef<const Decl *> Decls,
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ IndexingOptions Opts) {
+ IndexingContext IndexCtx(Opts, *DataConsumer);
+ IndexCtx.setASTContext(Ctx);
+
+ DataConsumer->initialize(Ctx);
+ for (const Decl *D : Decls)
+ IndexCtx.indexTopLevelDecl(D);
+ DataConsumer->finish();
+}
+
+void index::indexModuleFile(serialization::ModuleFile &Mod,
+ ASTReader &Reader,
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ IndexingOptions Opts) {
+ ASTContext &Ctx = Reader.getContext();
+ IndexingContext IndexCtx(Opts, *DataConsumer);
+ IndexCtx.setASTContext(Ctx);
+ DataConsumer->initialize(Ctx);
+
+ for (const Decl *D :Reader.getModuleFileLevelDecls(Mod)) {
+ IndexCtx.indexTopLevelDecl(D);
+ }
+ DataConsumer->finish();
}
diff --git a/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp b/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp
index 6dd6c0c..addee69 100644
--- a/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp
+++ b/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp
@@ -17,6 +17,21 @@
using namespace clang;
using namespace index;
+static bool isGeneratedDecl(const Decl *D) {
+ if (auto *attr = D->getAttr<ExternalSourceSymbolAttr>()) {
+ return attr->getGeneratedDeclaration();
+ }
+ return false;
+}
+
+bool IndexingContext::shouldIndex(const Decl *D) {
+ return !isGeneratedDecl(D);
+}
+
+const LangOptions &IndexingContext::getLangOpts() const {
+ return Ctx->getLangOpts();
+}
+
bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
return IndexOpts.IndexFunctionLocals;
}
@@ -24,9 +39,7 @@ bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
bool IndexingContext::handleDecl(const Decl *D,
SymbolRoleSet Roles,
ArrayRef<SymbolRelation> Relations) {
- return handleDeclOccurrence(D, D->getLocation(), /*IsRef=*/false,
- cast<Decl>(D->getDeclContext()), Roles, Relations,
- nullptr, nullptr, D->getDeclContext());
+ return handleDecl(D, D->getLocation(), Roles, Relations);
}
bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
@@ -35,9 +48,14 @@ bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc,
const DeclContext *DC) {
if (!DC)
DC = D->getDeclContext();
+
+ const Decl *OrigD = D;
+ if (isa<ObjCPropertyImplDecl>(D)) {
+ D = cast<ObjCPropertyImplDecl>(D)->getPropertyDecl();
+ }
return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC),
Roles, Relations,
- nullptr, nullptr, DC);
+ nullptr, OrigD, DC);
}
bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
@@ -47,7 +65,7 @@ bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
ArrayRef<SymbolRelation> Relations,
const Expr *RefE,
const Decl *RefD) {
- if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
+ if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalSymbol(D))
return true;
if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D))
@@ -97,34 +115,6 @@ bool IndexingContext::importedModule(const ImportDecl *ImportD) {
return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset);
}
-bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
- assert(D);
-
- if (isa<TemplateTemplateParmDecl>(D))
- return true;
-
- if (isa<ObjCTypeParamDecl>(D))
- return true;
-
- if (!D->getParentFunctionOrMethod())
- return false;
-
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
- switch (ND->getFormalLinkage()) {
- case NoLinkage:
- case VisibleNoLinkage:
- case InternalLinkage:
- return true;
- case UniqueExternalLinkage:
- llvm_unreachable("Not a sema linkage");
- case ExternalLinkage:
- return false;
- }
- }
-
- return true;
-}
-
bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
TemplateSpecializationKind TKind = TSK_Undeclared;
if (const ClassTemplateSpecializationDecl *
@@ -134,6 +124,16 @@ bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
TKind = FD->getTemplateSpecializationKind();
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
TKind = VD->getTemplateSpecializationKind();
+ } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (RD->getInstantiatedFromMemberClass())
+ TKind = RD->getTemplateSpecializationKind();
+ } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
+ if (ED->getInstantiatedFromMemberEnum())
+ TKind = ED->getTemplateSpecializationKind();
+ } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D) ||
+ isa<EnumConstantDecl>(D)) {
+ if (const auto *Parent = dyn_cast<Decl>(D->getDeclContext()))
+ return isTemplateImplicitInstantiation(Parent);
}
switch (TKind) {
case TSK_Undeclared:
@@ -161,6 +161,16 @@ bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
return true;
}
+static const CXXRecordDecl *
+getDeclContextForTemplateInstationPattern(const Decl *D) {
+ if (const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(D->getDeclContext()))
+ return CTSD->getTemplateInstantiationPattern();
+ else if (const auto *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()))
+ return RD->getInstantiatedFromMemberClass();
+ return nullptr;
+}
+
static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
if (const ClassTemplateSpecializationDecl *
SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
@@ -169,6 +179,28 @@ static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
return FD->getTemplateInstantiationPattern();
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
return VD->getTemplateInstantiationPattern();
+ } else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
+ return RD->getInstantiatedFromMemberClass();
+ } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
+ return ED->getInstantiatedFromMemberEnum();
+ } else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
+ const auto *ND = cast<NamedDecl>(D);
+ if (const CXXRecordDecl *Pattern =
+ getDeclContextForTemplateInstationPattern(ND)) {
+ for (const NamedDecl *BaseND : Pattern->lookup(ND->getDeclName())) {
+ if (BaseND->isImplicit())
+ continue;
+ if (BaseND->getKind() == ND->getKind())
+ return BaseND;
+ }
+ }
+ } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
+ if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
+ if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
+ for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
+ return BaseECD;
+ }
+ }
}
return nullptr;
}
@@ -197,6 +229,12 @@ static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, AST
return false;
}
+/// Whether the given NamedDecl should be skipped because it has no name.
+static bool shouldSkipNamelessDecl(const NamedDecl *ND) {
+ return ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) &&
+ !isa<ObjCCategoryDecl>(ND);
+}
+
static const Decl *adjustParent(const Decl *Parent) {
if (!Parent)
return nullptr;
@@ -211,8 +249,8 @@ static const Decl *adjustParent(const Decl *Parent) {
} else if (auto RD = dyn_cast<RecordDecl>(Parent)) {
if (RD->isAnonymousStructOrUnion())
continue;
- } else if (auto FD = dyn_cast<FieldDecl>(Parent)) {
- if (FD->getDeclName().isEmpty())
+ } else if (auto ND = dyn_cast<NamedDecl>(Parent)) {
+ if (shouldSkipNamelessDecl(ND))
continue;
}
return Parent;
@@ -222,13 +260,60 @@ static const Decl *adjustParent(const Decl *Parent) {
static const Decl *getCanonicalDecl(const Decl *D) {
D = D->getCanonicalDecl();
if (auto TD = dyn_cast<TemplateDecl>(D)) {
- D = TD->getTemplatedDecl();
- assert(D->isCanonicalDecl());
+ if (auto TTD = TD->getTemplatedDecl()) {
+ D = TTD;
+ assert(D->isCanonicalDecl());
+ }
}
return D;
}
+static bool shouldReportOccurrenceForSystemDeclOnlyMode(
+ bool IsRef, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations) {
+ if (!IsRef)
+ return true;
+
+ auto acceptForRelation = [](SymbolRoleSet roles) -> bool {
+ bool accept = false;
+ applyForEachSymbolRoleInterruptible(roles, [&accept](SymbolRole r) -> bool {
+ switch (r) {
+ case SymbolRole::RelationChildOf:
+ case SymbolRole::RelationBaseOf:
+ case SymbolRole::RelationOverrideOf:
+ case SymbolRole::RelationExtendedBy:
+ case SymbolRole::RelationAccessorOf:
+ case SymbolRole::RelationIBTypeOf:
+ accept = true;
+ return false;
+ case SymbolRole::Declaration:
+ case SymbolRole::Definition:
+ case SymbolRole::Reference:
+ case SymbolRole::Read:
+ case SymbolRole::Write:
+ case SymbolRole::Call:
+ case SymbolRole::Dynamic:
+ case SymbolRole::AddressOf:
+ case SymbolRole::Implicit:
+ case SymbolRole::RelationReceivedBy:
+ case SymbolRole::RelationCalledBy:
+ case SymbolRole::RelationContainedBy:
+ case SymbolRole::RelationSpecializationOf:
+ return true;
+ }
+ llvm_unreachable("Unsupported SymbolRole value!");
+ });
+ return accept;
+ };
+
+ for (auto &Rel : Relations) {
+ if (acceptForRelation(Rel.Roles))
+ return true;
+ }
+
+ return false;
+}
+
bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
bool IsRef, const Decl *Parent,
SymbolRoleSet Roles,
@@ -238,9 +323,7 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
const DeclContext *ContainerDC) {
if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
return true;
- if (!isa<NamedDecl>(D) ||
- (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
- !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D)))
+ if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D)))
return true;
SourceManager &SM = Ctx->getSourceManager();
@@ -264,7 +347,7 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
case IndexingOptions::SystemSymbolFilterKind::None:
return true;
case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly:
- if (IsRef)
+ if (!shouldReportOccurrenceForSystemDeclOnlyMode(IsRef, Roles, Relations))
return true;
break;
case IndexingOptions::SystemSymbolFilterKind::All:
@@ -286,7 +369,7 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
if (IsRef)
Roles |= (unsigned)SymbolRole::Reference;
- else if (isDeclADefinition(D, ContainerDC, *Ctx))
+ else if (isDeclADefinition(OrigD, ContainerDC, *Ctx))
Roles |= (unsigned)SymbolRole::Definition;
else
Roles |= (unsigned)SymbolRole::Declaration;
@@ -313,12 +396,12 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc,
};
if (Parent) {
- if (IsRef) {
+ if (IsRef || (!isa<ParmVarDecl>(D) && isFunctionLocalSymbol(D))) {
addRelation(SymbolRelation{
(unsigned)SymbolRole::RelationContainedBy,
Parent
});
- } else if (!cast<DeclContext>(Parent)->isFunctionOrMethod()) {
+ } else {
addRelation(SymbolRelation{
(unsigned)SymbolRole::RelationChildOf,
Parent
diff --git a/contrib/llvm/tools/clang/lib/Index/IndexingContext.h b/contrib/llvm/tools/clang/lib/Index/IndexingContext.h
index dd1dd32..566651c 100644
--- a/contrib/llvm/tools/clang/lib/Index/IndexingContext.h
+++ b/contrib/llvm/tools/clang/lib/Index/IndexingContext.h
@@ -48,6 +48,10 @@ public:
void setASTContext(ASTContext &ctx) { Ctx = &ctx; }
+ bool shouldIndex(const Decl *D);
+
+ const LangOptions &getLangOpts() const;
+
bool shouldSuppressRefs() const {
return false;
}
@@ -58,7 +62,6 @@ public:
return false;
}
- static bool isFunctionLocalDecl(const Decl *D);
static bool isTemplateImplicitInstantiation(const Decl *D);
bool handleDecl(const Decl *D, SymbolRoleSet Roles = SymbolRoleSet(),
@@ -72,7 +75,7 @@ public:
bool handleReference(const NamedDecl *D, SourceLocation Loc,
const NamedDecl *Parent,
const DeclContext *DC,
- SymbolRoleSet Roles,
+ SymbolRoleSet Roles = SymbolRoleSet(),
ArrayRef<SymbolRelation> Relations = None,
const Expr *RefE = nullptr,
const Decl *RefD = nullptr);
@@ -81,7 +84,8 @@ public:
bool indexDecl(const Decl *D);
- void indexTagDecl(const TagDecl *D);
+ void indexTagDecl(const TagDecl *D,
+ ArrayRef<SymbolRelation> Relations = None);
void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent,
const DeclContext *DC = nullptr,
diff --git a/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp b/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp
index 58f61c3..21054b0 100644
--- a/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp
+++ b/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp
@@ -46,6 +46,15 @@ static bool printLoc(llvm::raw_ostream &OS, SourceLocation Loc,
return false;
}
+static StringRef GetExternalSourceContainer(const NamedDecl *D) {
+ if (!D)
+ return StringRef();
+ if (auto *attr = D->getExternalSourceSymbolAttr()) {
+ return attr->getDefinedIn();
+ }
+ return StringRef();
+}
+
namespace {
class USRGenerator : public ConstDeclVisitor<USRGenerator> {
SmallVectorImpl<char> &Buf;
@@ -79,7 +88,8 @@ public:
void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
void VisitClassTemplateDecl(const ClassTemplateDecl *D);
- void VisitObjCContainerDecl(const ObjCContainerDecl *CD);
+ void VisitObjCContainerDecl(const ObjCContainerDecl *CD,
+ const ObjCCategoryDecl *CatD = nullptr);
void VisitObjCMethodDecl(const ObjCMethodDecl *MD);
void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
@@ -116,6 +126,8 @@ public:
return D->getParentFunctionOrMethod() != nullptr;
}
+ void GenExtSymbolContainer(const NamedDecl *D);
+
/// Generate the string component containing the location of the
/// declaration.
bool GenLoc(const Decl *D, bool IncludeOffset);
@@ -127,13 +139,16 @@ public:
/// itself.
/// Generate a USR for an Objective-C class.
- void GenObjCClass(StringRef cls) {
- generateUSRForObjCClass(cls, Out);
+ void GenObjCClass(StringRef cls, StringRef ExtSymDefinedIn,
+ StringRef CategoryContextExtSymbolDefinedIn) {
+ generateUSRForObjCClass(cls, Out, ExtSymDefinedIn,
+ CategoryContextExtSymbolDefinedIn);
}
/// Generate a USR for an Objective-C class category.
- void GenObjCCategory(StringRef cls, StringRef cat) {
- generateUSRForObjCCategory(cls, cat, Out);
+ void GenObjCCategory(StringRef cls, StringRef cat,
+ StringRef clsExt, StringRef catExt) {
+ generateUSRForObjCCategory(cls, cat, Out, clsExt, catExt);
}
/// Generate a USR fragment for an Objective-C property.
@@ -142,8 +157,8 @@ public:
}
/// Generate a USR for an Objective-C protocol.
- void GenObjCProtocol(StringRef prot) {
- generateUSRForObjCProtocol(prot, Out);
+ void GenObjCProtocol(StringRef prot, StringRef ext) {
+ generateUSRForObjCProtocol(prot, Out, ext);
}
void VisitType(QualType T);
@@ -204,7 +219,11 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
+ const unsigned StartSize = Buf.size();
VisitDeclContext(D->getDeclContext());
+ if (Buf.size() == StartSize)
+ GenExtSymbolContainer(D);
+
bool IsTemplate = false;
if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) {
IsTemplate = true;
@@ -310,7 +329,7 @@ void USRGenerator::VisitVarDecl(const VarDecl *D) {
// For a template specialization, mangle the template arguments.
if (const VarTemplateSpecializationDecl *Spec
= dyn_cast<VarTemplateSpecializationDecl>(D)) {
- const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs();
+ const TemplateArgumentList &Args = Spec->getTemplateArgs();
Out << '>';
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
Out << '#';
@@ -367,7 +386,16 @@ void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
IgnoreResults = true;
return;
}
- Visit(ID);
+ auto getCategoryContext = [](const ObjCMethodDecl *D) ->
+ const ObjCCategoryDecl * {
+ if (auto *CD = dyn_cast<ObjCCategoryDecl>(D->getDeclContext()))
+ return CD;
+ if (auto *ICD = dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
+ return ICD->getCategoryDecl();
+ return nullptr;
+ };
+ auto *CD = getCategoryContext(D);
+ VisitObjCContainerDecl(ID, CD);
}
// Ideally we would use 'GenObjCMethod', but this is such a hot path
// for Objective-C code that we don't want to use
@@ -376,13 +404,15 @@ void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
<< DeclarationName(D->getSelector());
}
-void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
+void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D,
+ const ObjCCategoryDecl *CatD) {
switch (D->getKind()) {
default:
llvm_unreachable("Invalid ObjC container.");
case Decl::ObjCInterface:
case Decl::ObjCImplementation:
- GenObjCClass(D->getName());
+ GenObjCClass(D->getName(), GetExternalSourceContainer(D),
+ GetExternalSourceContainer(CatD));
break;
case Decl::ObjCCategory: {
const ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
@@ -402,7 +432,9 @@ void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
GenLoc(CD, /*IncludeOffset=*/true);
}
else
- GenObjCCategory(ID->getName(), CD->getName());
+ GenObjCCategory(ID->getName(), CD->getName(),
+ GetExternalSourceContainer(ID),
+ GetExternalSourceContainer(CD));
break;
}
@@ -417,12 +449,16 @@ void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
IgnoreResults = true;
return;
}
- GenObjCCategory(ID->getName(), CD->getName());
+ GenObjCCategory(ID->getName(), CD->getName(),
+ GetExternalSourceContainer(ID),
+ GetExternalSourceContainer(CD));
break;
}
- case Decl::ObjCProtocol:
- GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName());
+ case Decl::ObjCProtocol: {
+ const ObjCProtocolDecl *PD = cast<ObjCProtocolDecl>(D);
+ GenObjCProtocol(PD->getName(), GetExternalSourceContainer(PD));
break;
+ }
}
}
@@ -452,6 +488,8 @@ void USRGenerator::VisitTagDecl(const TagDecl *D) {
ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
+ GenExtSymbolContainer(D);
+
D = D->getCanonicalDecl();
VisitDeclContext(D->getDeclContext());
@@ -521,7 +559,7 @@ void USRGenerator::VisitTagDecl(const TagDecl *D) {
// For a class template specialization, mangle the template arguments.
if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(D)) {
- const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs();
+ const TemplateArgumentList &Args = Spec->getTemplateArgs();
Out << '>';
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
Out << '#';
@@ -544,6 +582,12 @@ void USRGenerator::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
GenLoc(D, /*IncludeOffset=*/true);
}
+void USRGenerator::GenExtSymbolContainer(const NamedDecl *D) {
+ StringRef Container = GetExternalSourceContainer(D);
+ if (!Container.empty())
+ Out << "@M@" << Container;
+}
+
bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) {
if (generatedLoc)
return IgnoreResults;
@@ -654,7 +698,6 @@ void USRGenerator::VisitType(QualType T) {
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
- case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
case BuiltinType::OCLSampler:
IgnoreResults = true;
@@ -768,7 +811,13 @@ void USRGenerator::VisitType(QualType T) {
T = InjT->getInjectedSpecializationType();
continue;
}
-
+ if (const auto *VT = T->getAs<VectorType>()) {
+ Out << (T->isExtVectorType() ? ']' : '[');
+ Out << VT->getNumElements();
+ T = VT->getElementType();
+ continue;
+ }
+
// Unhandled type.
Out << ' ';
break;
@@ -867,12 +916,34 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
// USR generation functions.
//===----------------------------------------------------------------------===//
-void clang::index::generateUSRForObjCClass(StringRef Cls, raw_ostream &OS) {
+static void combineClassAndCategoryExtContainers(StringRef ClsSymDefinedIn,
+ StringRef CatSymDefinedIn,
+ raw_ostream &OS) {
+ if (ClsSymDefinedIn.empty() && CatSymDefinedIn.empty())
+ return;
+ if (CatSymDefinedIn.empty()) {
+ OS << "@M@" << ClsSymDefinedIn << '@';
+ return;
+ }
+ OS << "@CM@" << CatSymDefinedIn << '@';
+ if (ClsSymDefinedIn != CatSymDefinedIn) {
+ OS << ClsSymDefinedIn << '@';
+ }
+}
+
+void clang::index::generateUSRForObjCClass(StringRef Cls, raw_ostream &OS,
+ StringRef ExtSymDefinedIn,
+ StringRef CategoryContextExtSymbolDefinedIn) {
+ combineClassAndCategoryExtContainers(ExtSymDefinedIn,
+ CategoryContextExtSymbolDefinedIn, OS);
OS << "objc(cs)" << Cls;
}
void clang::index::generateUSRForObjCCategory(StringRef Cls, StringRef Cat,
- raw_ostream &OS) {
+ raw_ostream &OS,
+ StringRef ClsSymDefinedIn,
+ StringRef CatSymDefinedIn) {
+ combineClassAndCategoryExtContainers(ClsSymDefinedIn, CatSymDefinedIn, OS);
OS << "objc(cy)" << Cls << '@' << Cat;
}
@@ -891,10 +962,25 @@ void clang::index::generateUSRForObjCProperty(StringRef Prop, bool isClassProp,
OS << (isClassProp ? "(cpy)" : "(py)") << Prop;
}
-void clang::index::generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS) {
+void clang::index::generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS,
+ StringRef ExtSymDefinedIn) {
+ if (!ExtSymDefinedIn.empty())
+ OS << "@M@" << ExtSymDefinedIn << '@';
OS << "objc(pl)" << Prot;
}
+void clang::index::generateUSRForGlobalEnum(StringRef EnumName, raw_ostream &OS,
+ StringRef ExtSymDefinedIn) {
+ if (!ExtSymDefinedIn.empty())
+ OS << "@M@" << ExtSymDefinedIn;
+ OS << "@E@" << EnumName;
+}
+
+void clang::index::generateUSRForEnumConstant(StringRef EnumConstantName,
+ raw_ostream &OS) {
+ OS << '@' << EnumConstantName;
+}
+
bool clang::index::generateUSRForDecl(const Decl *D,
SmallVectorImpl<char> &Buf) {
if (!D)
@@ -911,21 +997,30 @@ bool clang::index::generateUSRForDecl(const Decl *D,
bool clang::index::generateUSRForMacro(const MacroDefinitionRecord *MD,
const SourceManager &SM,
SmallVectorImpl<char> &Buf) {
+ if (!MD)
+ return true;
+ return generateUSRForMacro(MD->getName()->getName(), MD->getLocation(),
+ SM, Buf);
+
+}
+
+bool clang::index::generateUSRForMacro(StringRef MacroName, SourceLocation Loc,
+ const SourceManager &SM,
+ SmallVectorImpl<char> &Buf) {
// Don't generate USRs for things with invalid locations.
- if (!MD || MD->getLocation().isInvalid())
+ if (MacroName.empty() || Loc.isInvalid())
return true;
llvm::raw_svector_ostream Out(Buf);
// Assume that system headers are sane. Don't put source location
// information into the USR if the macro comes from a system header.
- SourceLocation Loc = MD->getLocation();
bool ShouldGenerateLocation = !SM.isInSystemHeader(Loc);
Out << getUSRSpacePrefix();
if (ShouldGenerateLocation)
printLoc(Out, Loc, SM, /*IncludeOffset=*/true);
Out << "@macro@";
- Out << MD->getName()->getName();
+ Out << MacroName;
return false;
}
diff --git a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp
index c667f4b..1ebcc0a 100644
--- a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp
@@ -172,8 +172,10 @@ std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
//
// To avoid false-negatives, we form as canonical a path as we can, and map
// to lower-case in case we're on a case-insensitive file system.
- auto *Dir =
- FileMgr.getDirectory(llvm::sys::path::parent_path(ModuleMapPath));
+ std::string Parent = llvm::sys::path::parent_path(ModuleMapPath);
+ if (Parent.empty())
+ Parent = ".";
+ auto *Dir = FileMgr.getDirectory(Parent);
if (!Dir)
return std::string();
auto DirName = FileMgr.getCanonicalName(Dir);
@@ -622,7 +624,10 @@ const FileEntry *HeaderSearch::LookupFile(
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache, bool BuildSystemModule) {
+ bool *IsMapped, bool SkipCache, bool BuildSystemModule) {
+ if (IsMapped)
+ *IsMapped = false;
+
if (SuggestedModule)
*SuggestedModule = ModuleMap::KnownHeader();
@@ -752,8 +757,11 @@ const FileEntry *HeaderSearch::LookupFile(
if (!SkipCache && CacheLookup.StartIdx == i+1) {
// Skip querying potentially lots of directories for this lookup.
i = CacheLookup.HitIdx;
- if (CacheLookup.MappedName)
+ if (CacheLookup.MappedName) {
Filename = CacheLookup.MappedName;
+ if (IsMapped)
+ *IsMapped = true;
+ }
} else {
// Otherwise, this is the first query, or the previous query didn't match
// our search start. We will fill in our found location below, so prime the
@@ -774,6 +782,8 @@ const FileEntry *HeaderSearch::LookupFile(
if (HasBeenMapped) {
CacheLookup.MappedName =
copyString(Filename, LookupFileCache.getAllocator());
+ if (IsMapped)
+ *IsMapped = true;
}
if (!FE) continue;
@@ -837,7 +847,7 @@ const FileEntry *HeaderSearch::LookupFile(
const FileEntry *FE =
LookupFile(ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir,
CurDir, Includers.front(), SearchPath, RelativePath,
- RequestingModule, SuggestedModule);
+ RequestingModule, SuggestedModule, IsMapped);
if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
if (SuggestedModule)
@@ -1104,6 +1114,8 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
auto TryEnterImported = [&](void) -> bool {
if (!ModulesEnabled)
return false;
+ // Ensure FileInfo bits are up to date.
+ ModMap.resolveHeaderDirectives(File);
// Modules with builtins are special; multiple modules use builtins as
// modular headers, example:
//
@@ -1315,14 +1327,28 @@ 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,
+ StringRef OriginalModuleMapFile) {
// Find the directory for the module. For frameworks, that may require going
// up from the 'Modules' directory.
const DirectoryEntry *Dir = nullptr;
if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd)
Dir = FileMgr.getDirectory(".");
else {
- Dir = File->getDir();
+ if (!OriginalModuleMapFile.empty()) {
+ // We're building a preprocessed module map. Find or invent the directory
+ // that it originally occupied.
+ Dir = FileMgr.getDirectory(
+ llvm::sys::path::parent_path(OriginalModuleMapFile));
+ if (!Dir) {
+ auto *FakeFile = FileMgr.getVirtualFile(OriginalModuleMapFile, 0, 0);
+ Dir = FakeFile->getDir();
+ }
+ } else {
+ Dir = File->getDir();
+ }
+
StringRef DirName(Dir->getName());
if (llvm::sys::path::filename(DirName) == "Modules") {
DirName = llvm::sys::path::parent_path(DirName);
@@ -1334,7 +1360,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;
@@ -1347,7 +1373,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
@@ -1356,7 +1383,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/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp
index 6025a66..61bcef8 100644
--- a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp
@@ -19,6 +19,7 @@
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Compiler.h"
@@ -43,6 +44,8 @@ using namespace clang;
/// isObjCAtKeyword - Return true if we have an ObjC keyword identifier.
bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
+ if (isAnnotation())
+ return false;
if (IdentifierInfo *II = getIdentifierInfo())
return II->getObjCKeywordID() == objcKey;
return false;
@@ -50,6 +53,8 @@ bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
/// getObjCKeywordID - Return the ObjC keyword kind.
tok::ObjCKeywordKind Token::getObjCKeywordID() const {
+ if (isAnnotation())
+ return tok::objc_not_keyword;
IdentifierInfo *specId = getIdentifierInfo();
return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword;
}
@@ -452,6 +457,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 +495,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.
@@ -535,8 +551,6 @@ namespace {
enum PreambleDirectiveKind {
PDK_Skipped,
- PDK_StartIf,
- PDK_EndIf,
PDK_Unknown
};
@@ -559,8 +573,6 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer,
bool InPreprocessorDirective = false;
Token TheTok;
- Token IfStartTok;
- unsigned IfCount = 0;
SourceLocation ActiveCommentLoc;
unsigned MaxLineOffset = 0;
@@ -643,33 +655,18 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer,
.Case("sccs", PDK_Skipped)
.Case("assert", PDK_Skipped)
.Case("unassert", PDK_Skipped)
- .Case("if", PDK_StartIf)
- .Case("ifdef", PDK_StartIf)
- .Case("ifndef", PDK_StartIf)
+ .Case("if", PDK_Skipped)
+ .Case("ifdef", PDK_Skipped)
+ .Case("ifndef", PDK_Skipped)
.Case("elif", PDK_Skipped)
.Case("else", PDK_Skipped)
- .Case("endif", PDK_EndIf)
+ .Case("endif", PDK_Skipped)
.Default(PDK_Unknown);
switch (PDK) {
case PDK_Skipped:
continue;
- case PDK_StartIf:
- if (IfCount == 0)
- IfStartTok = HashTok;
-
- ++IfCount;
- continue;
-
- case PDK_EndIf:
- // Mismatched #endif. The preamble ends here.
- if (IfCount == 0)
- break;
-
- --IfCount;
- continue;
-
case PDK_Unknown:
// We don't know what this directive is; stop at the '#'.
break;
@@ -690,16 +687,13 @@ std::pair<unsigned, bool> Lexer::ComputePreamble(StringRef Buffer,
} while (true);
SourceLocation End;
- if (IfCount)
- End = IfStartTok.getLocation();
- else if (ActiveCommentLoc.isValid())
+ if (ActiveCommentLoc.isValid())
End = ActiveCommentLoc; // don't truncate a decl comment.
else
End = TheTok.getLocation();
return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(),
- IfCount? IfStartTok.isAtStartOfLine()
- : TheTok.isAtStartOfLine());
+ TheTok.isAtStartOfLine());
}
/// AdvanceToTokenCharacter - Given a location that specifies the start of a
@@ -1038,6 +1032,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.
//===----------------------------------------------------------------------===//
@@ -1171,6 +1186,8 @@ const char *Lexer::SkipEscapedNewLines(const char *P) {
// If not a trigraph for escape, bail out.
if (P[1] != '?' || P[2] != '/')
return P;
+ // FIXME: Take LangOpts into account; the language might not
+ // support trigraphs.
AfterEscape = P+3;
} else {
return P;
@@ -1282,12 +1299,6 @@ Slash:
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
- // If the char that we finally got was a \n, then we must have had
- // something like \<newline><newline>. We don't want to consume the
- // second newline.
- if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
- return ' ';
-
// Use slow version to accumulate a correct size field.
return getCharAndSizeSlow(Ptr, Size, Tok);
}
@@ -1338,12 +1349,6 @@ Slash:
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
- // If the char that we finally got was a \n, then we must have had
- // something like \<newline><newline>. We don't want to consume the
- // second newline.
- if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
- return ' ';
-
// Use slow version to accumulate a correct size field.
return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
}
@@ -2070,8 +2075,11 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
// Scan over the body of the comment. The common case, when scanning, is that
// the comment contains normal ascii characters with nothing interesting in
// them. As such, optimize for this case with the inner loop.
+ //
+ // This loop terminates with CurPtr pointing at the newline (or end of buffer)
+ // character that ends the line comment.
char C;
- do {
+ while (true) {
C = *CurPtr;
// Skip over characters in the fast loop.
while (C != 0 && // Potentially EOF.
@@ -2088,10 +2096,12 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
HasSpace = true;
}
- if (*EscapePtr == '\\') // Escaped newline.
+ if (*EscapePtr == '\\')
+ // Escaped newline.
CurPtr = EscapePtr;
else if (EscapePtr[0] == '/' && EscapePtr[-1] == '?' &&
- EscapePtr[-2] == '?') // Trigraph-escaped newline.
+ EscapePtr[-2] == '?' && LangOpts.Trigraphs)
+ // Trigraph-escaped newline.
CurPtr = EscapePtr-2;
else
break; // This is a newline, we're done.
@@ -2140,9 +2150,9 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
}
}
- if (CurPtr == BufferEnd+1) {
- --CurPtr;
- break;
+ if (C == '\r' || C == '\n' || CurPtr == BufferEnd + 1) {
+ --CurPtr;
+ break;
}
if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) {
@@ -2150,8 +2160,7 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
cutOffLexing();
return false;
}
-
- } while (C != '\n' && C != '\r');
+ }
// Found but did not consume the newline. Notify comment handlers about the
// comment unless we're in a #if 0 block.
@@ -2490,6 +2499,7 @@ void Lexer::ReadToEndOfLine(SmallVectorImpl<char> *Result) {
break;
}
// FALL THROUGH.
+ LLVM_FALLTHROUGH;
case '\r':
case '\n':
// Okay, we found the end of the line. First, back up past the \0, \r, \n.
@@ -2540,6 +2550,11 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
return true;
}
+ if (PP->isRecordingPreamble() && PP->isInPrimaryFile()) {
+ PP->setRecordedPreambleConditionalStack(ConditionalStack);
+ ConditionalStack.clear();
+ }
+
// Issue diagnostics for unterminated #if and missing newline.
// If we are in a #if directive, emit an error.
@@ -2722,6 +2737,37 @@ bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) {
return false;
}
+static const char *findPlaceholderEnd(const char *CurPtr,
+ const char *BufferEnd) {
+ if (CurPtr == BufferEnd)
+ return nullptr;
+ BufferEnd -= 1; // Scan until the second last character.
+ for (; CurPtr != BufferEnd; ++CurPtr) {
+ if (CurPtr[0] == '#' && CurPtr[1] == '>')
+ return CurPtr + 2;
+ }
+ return nullptr;
+}
+
+bool Lexer::lexEditorPlaceholder(Token &Result, const char *CurPtr) {
+ assert(CurPtr[-1] == '<' && CurPtr[0] == '#' && "Not a placeholder!");
+ if (!PP || !PP->getPreprocessorOpts().LexEditorPlaceholders || LexingRawMode)
+ return false;
+ const char *End = findPlaceholderEnd(CurPtr + 1, BufferEnd);
+ if (!End)
+ return false;
+ const char *Start = CurPtr - 1;
+ if (!LangOpts.AllowEditorPlaceholders)
+ Diag(Start, diag::err_placeholder_in_source);
+ Result.startToken();
+ FormTokenWithChars(Result, End, tok::raw_identifier);
+ Result.setRawIdentifierData(Start);
+ PP->LookUpIdentifierInfo(Result);
+ Result.setFlag(Token::IsEditorPlaceholder);
+ BufferPtr = End;
+ return true;
+}
+
bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
if (PP && PP->isCodeCompletionEnabled()) {
SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart);
@@ -3203,6 +3249,7 @@ LexNextToken:
return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::wide_char_constant);
// FALL THROUGH, treating L like the start of an identifier.
+ LLVM_FALLTHROUGH;
// C99 6.4.2: Identifiers.
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
@@ -3479,6 +3526,8 @@ LexNextToken:
} else if (LangOpts.Digraphs && Char == '%') { // '<%' -> '{'
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_brace;
+ } else if (Char == '#' && lexEditorPlaceholder(Result, CurPtr)) {
+ return true;
} else {
Kind = tok::less;
}
@@ -3603,17 +3652,19 @@ LexNextToken:
// UCNs (C99 6.4.3, C++11 [lex.charset]p2)
case '\\':
- if (uint32_t CodePoint = tryReadUCN(CurPtr, BufferPtr, &Result)) {
- if (CheckUnicodeWhitespace(Result, CodePoint, CurPtr)) {
- if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine))
- return true; // KeepWhitespaceMode
+ if (!LangOpts.AsmPreprocessor) {
+ if (uint32_t CodePoint = tryReadUCN(CurPtr, BufferPtr, &Result)) {
+ if (CheckUnicodeWhitespace(Result, CodePoint, CurPtr)) {
+ if (SkipWhitespace(Result, CurPtr, TokAtPhysicalStartOfLine))
+ return true; // KeepWhitespaceMode
+
+ // We only saw whitespace, so just try again with this lexer.
+ // (We manually eliminate the tail call to avoid recursion.)
+ goto LexNextToken;
+ }
- // We only saw whitespace, so just try again with this lexer.
- // (We manually eliminate the tail call to avoid recursion.)
- goto LexNextToken;
+ return LexUnicode(Result, CodePoint, CurPtr);
}
-
- return LexUnicode(Result, CodePoint, CurPtr);
}
Kind = tok::unknown;
diff --git a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp
index fbfd3fe..a598a46 100644
--- a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp
@@ -456,10 +456,17 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
// Finally, we write the bytes into ResultBuf.
ResultBuf += bytesToWrite;
switch (bytesToWrite) { // note: everything falls through.
- case 4: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 3: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 2: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- case 1: *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
+ case 4:
+ *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ LLVM_FALLTHROUGH;
+ case 3:
+ *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ LLVM_FALLTHROUGH;
+ case 2:
+ *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
+ LLVM_FALLTHROUGH;
+ case 1:
+ *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
}
// Update the buffer.
ResultBuf += bytesToWrite;
@@ -563,7 +570,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// Parse the suffix. At this point we can classify whether we have an FP or
// integer constant.
bool isFPConstant = isFloatingLiteral();
- const char *ImaginarySuffixLoc = nullptr;
// Loop over all of the characters of the suffix. If we see something bad,
// we break out of the loop.
@@ -660,7 +666,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
case 'J':
if (isImaginary) break; // Cannot be repeated.
isImaginary = true;
- ImaginarySuffixLoc = s;
continue; // Success.
}
// If we reached here, there was an error or a ud-suffix.
@@ -694,8 +699,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
}
if (isImaginary) {
- PP.Diag(PP.AdvanceToTokenCharacter(TokLoc,
- ImaginarySuffixLoc - ThisTokBegin),
+ PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin),
diag::ext_imaginary_constant);
}
}
diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp
index 1c1979d..f791d8d 100644
--- a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp
@@ -44,20 +44,22 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
// Otherwise, use the best fit.
ClosestMatch = (*Entry)->NumUnexpArgTokens;
}
-
+
MacroArgs *Result;
if (!ResultEnt) {
// Allocate memory for a MacroArgs object with the lexer tokens at the end.
- Result = (MacroArgs*)malloc(sizeof(MacroArgs) +
- UnexpArgTokens.size() * sizeof(Token));
+ Result = (MacroArgs *)malloc(sizeof(MacroArgs) +
+ UnexpArgTokens.size() * sizeof(Token));
// Construct the MacroArgs object.
- new (Result) MacroArgs(UnexpArgTokens.size(), VarargsElided);
+ new (Result)
+ MacroArgs(UnexpArgTokens.size(), VarargsElided, MI->getNumParams());
} else {
Result = *ResultEnt;
// Unlink this node from the preprocessors singly linked list.
*ResultEnt = Result->ArgCache;
Result->NumUnexpArgTokens = UnexpArgTokens.size();
Result->VarargsElided = VarargsElided;
+ Result->NumMacroArgs = MI->getNumParams();
}
// Copy the actual unexpanded tokens to immediately after the result ptr.
@@ -146,11 +148,11 @@ bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok,
const std::vector<Token> &
MacroArgs::getPreExpArgument(unsigned Arg, const MacroInfo *MI,
Preprocessor &PP) {
- assert(Arg < MI->getNumArgs() && "Invalid argument number!");
+ assert(Arg < MI->getNumParams() && "Invalid argument number!");
// If we have already computed this, return it.
- if (PreExpArgTokens.size() < MI->getNumArgs())
- PreExpArgTokens.resize(MI->getNumArgs());
+ if (PreExpArgTokens.size() < MI->getNumParams())
+ PreExpArgTokens.resize(MI->getNumParams());
std::vector<Token> &Result = PreExpArgTokens[Arg];
if (!Result.empty()) return Result;
@@ -298,12 +300,10 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
Preprocessor &PP,
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd) {
- assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!");
- if (StringifiedArgs.empty()) {
- StringifiedArgs.resize(getNumArguments());
- memset((void*)&StringifiedArgs[0], 0,
- sizeof(StringifiedArgs[0])*getNumArguments());
- }
+ assert(ArgNo < getNumMacroArguments() && "Invalid argument number!");
+ if (StringifiedArgs.empty())
+ StringifiedArgs.resize(getNumMacroArguments(), {});
+
if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP,
/*Charify=*/false,
diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp
index 924613d..6dc7841 100644
--- a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp
@@ -17,8 +17,8 @@ using namespace clang;
MacroInfo::MacroInfo(SourceLocation DefLoc)
: Location(DefLoc),
- ArgumentList(nullptr),
- NumArguments(0),
+ ParameterList(nullptr),
+ NumParameters(0),
IsDefinitionLengthCached(false),
IsFunctionLike(false),
IsC99Varargs(false),
@@ -29,11 +29,10 @@ MacroInfo::MacroInfo(SourceLocation DefLoc)
IsUsed(false),
IsAllowRedefinitionsWithoutWarning(false),
IsWarnIfUnused(false),
- FromASTFile(false),
UsedForHeaderGuard(false) {
}
-unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
+unsigned MacroInfo::getDefinitionLengthSlow(const SourceManager &SM) const {
assert(!IsDefinitionLengthCached);
IsDefinitionLengthCached = true;
@@ -75,7 +74,7 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
// Check # tokens in replacement, number of args, and various flags all match.
if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
- getNumArgs() != Other.getNumArgs() ||
+ getNumParams() != Other.getNumParams() ||
isFunctionLike() != Other.isFunctionLike() ||
isC99Varargs() != Other.isC99Varargs() ||
isGNUVarargs() != Other.isGNUVarargs())
@@ -83,7 +82,8 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
if (Lexically) {
// Check arguments.
- for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
+ for (param_iterator I = param_begin(), OI = Other.param_begin(),
+ E = param_end();
I != E; ++I, ++OI)
if (*I != *OI) return false;
}
@@ -110,10 +110,10 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
return false;
// With syntactic equivalence the parameter names can be different as long
// as they are used in the same place.
- int AArgNum = getArgumentNum(A.getIdentifierInfo());
+ int AArgNum = getParameterNum(A.getIdentifierInfo());
if (AArgNum == -1)
return false;
- if (AArgNum != Other.getArgumentNum(B.getIdentifierInfo()))
+ if (AArgNum != Other.getParameterNum(B.getIdentifierInfo()))
return false;
continue;
}
@@ -137,18 +137,17 @@ LLVM_DUMP_METHOD void MacroInfo::dump() const {
if (IsAllowRedefinitionsWithoutWarning)
Out << " allow_redefinitions_without_warning";
if (IsWarnIfUnused) Out << " warn_if_unused";
- if (FromASTFile) Out << " imported";
if (UsedForHeaderGuard) Out << " header_guard";
Out << "\n #define <macro>";
if (IsFunctionLike) {
Out << "(";
- for (unsigned I = 0; I != NumArguments; ++I) {
+ for (unsigned I = 0; I != NumParameters; ++I) {
if (I) Out << ", ";
- Out << ArgumentList[I]->getName();
+ Out << ParameterList[I]->getName();
}
if (IsC99Varargs || IsGNUVarargs) {
- if (NumArguments && IsC99Varargs) Out << ", ";
+ if (NumParameters && IsC99Varargs) Out << ", ";
Out << "...";
}
Out << ")";
diff --git a/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp b/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp
index 1488f62..40f78ce 100644
--- a/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp
@@ -36,6 +36,37 @@
#endif
using namespace clang;
+Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) {
+ switch ((int)Role) {
+ default: llvm_unreachable("unknown header role");
+ case NormalHeader:
+ return Module::HK_Normal;
+ case PrivateHeader:
+ return Module::HK_Private;
+ case TextualHeader:
+ return Module::HK_Textual;
+ case PrivateHeader | TextualHeader:
+ return Module::HK_PrivateTextual;
+ }
+}
+
+ModuleMap::ModuleHeaderRole
+ModuleMap::headerKindToRole(Module::HeaderKind Kind) {
+ switch ((int)Kind) {
+ case Module::HK_Normal:
+ return NormalHeader;
+ case Module::HK_Private:
+ return PrivateHeader;
+ case Module::HK_Textual:
+ return TextualHeader;
+ case Module::HK_PrivateTextual:
+ return ModuleHeaderRole(PrivateHeader | TextualHeader);
+ case Module::HK_Excluded:
+ llvm_unreachable("unexpected header kind");
+ }
+ llvm_unreachable("unknown header kind");
+}
+
Module::ExportDecl
ModuleMap::resolveExport(Module *Mod,
const Module::UnresolvedExportDecl &Unresolved,
@@ -84,6 +115,143 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
return Context;
}
+/// \brief Append to \p Paths the set of paths needed to get to the
+/// subframework in which the given module lives.
+static void appendSubframeworkPaths(Module *Mod,
+ SmallVectorImpl<char> &Path) {
+ // Collect the framework names from the given module to the top-level module.
+ SmallVector<StringRef, 2> Paths;
+ for (; Mod; Mod = Mod->Parent) {
+ if (Mod->IsFramework)
+ Paths.push_back(Mod->Name);
+ }
+
+ if (Paths.empty())
+ return;
+
+ // Add Frameworks/Name.framework for each subframework.
+ for (unsigned I = Paths.size() - 1; I != 0; --I)
+ llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
+}
+
+const FileEntry *
+ModuleMap::findHeader(Module *M,
+ const Module::UnresolvedHeaderDirective &Header,
+ SmallVectorImpl<char> &RelativePathName) {
+ auto GetFile = [&](StringRef Filename) -> const FileEntry * {
+ auto *File = SourceMgr.getFileManager().getFile(Filename);
+ if (!File ||
+ (Header.Size && File->getSize() != *Header.Size) ||
+ (Header.ModTime && File->getModificationTime() != *Header.ModTime))
+ return nullptr;
+ return File;
+ };
+
+ if (llvm::sys::path::is_absolute(Header.FileName)) {
+ RelativePathName.clear();
+ RelativePathName.append(Header.FileName.begin(), Header.FileName.end());
+ return GetFile(Header.FileName);
+ }
+
+ // Search for the header file within the module's home directory.
+ auto *Directory = M->Directory;
+ SmallString<128> FullPathName(Directory->getName());
+ unsigned FullPathLength = FullPathName.size();
+
+ if (M->isPartOfFramework()) {
+ appendSubframeworkPaths(M, RelativePathName);
+ unsigned RelativePathLength = RelativePathName.size();
+
+ // Check whether this file is in the public headers.
+ llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
+ llvm::sys::path::append(FullPathName, RelativePathName);
+ if (auto *File = GetFile(FullPathName))
+ return File;
+
+ // Check whether this file is in the private headers.
+ // Ideally, private modules in the form 'FrameworkName.Private' should
+ // be defined as 'module FrameworkName.Private', and not as
+ // 'framework module FrameworkName.Private', since a 'Private.Framework'
+ // does not usually exist. However, since both are currently widely used
+ // for private modules, make sure we find the right path in both cases.
+ if (M->IsFramework && M->Name == "Private")
+ RelativePathName.clear();
+ else
+ RelativePathName.resize(RelativePathLength);
+ FullPathName.resize(FullPathLength);
+ llvm::sys::path::append(RelativePathName, "PrivateHeaders",
+ Header.FileName);
+ llvm::sys::path::append(FullPathName, RelativePathName);
+ return GetFile(FullPathName);
+ }
+
+ // Lookup for normal headers.
+ llvm::sys::path::append(RelativePathName, Header.FileName);
+ llvm::sys::path::append(FullPathName, RelativePathName);
+ return GetFile(FullPathName);
+}
+
+void ModuleMap::resolveHeader(Module *Mod,
+ const Module::UnresolvedHeaderDirective &Header) {
+ SmallString<128> RelativePathName;
+ if (const FileEntry *File = findHeader(Mod, Header, RelativePathName)) {
+ if (Header.IsUmbrella) {
+ const DirectoryEntry *UmbrellaDir = File->getDir();
+ if (Module *UmbrellaMod = UmbrellaDirs[UmbrellaDir])
+ Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
+ << UmbrellaMod->getFullModuleName();
+ else
+ // Record this umbrella header.
+ setUmbrellaHeader(Mod, File, RelativePathName.str());
+ } else {
+ Module::Header H = {RelativePathName.str(), File};
+ if (Header.Kind == Module::HK_Excluded)
+ excludeHeader(Mod, H);
+ else
+ addHeader(Mod, H, headerKindToRole(Header.Kind));
+ }
+ } else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime) {
+ // There's a builtin header but no corresponding on-disk header. Assume
+ // this was supposed to modularize the builtin header alone.
+ } else if (Header.Kind == Module::HK_Excluded) {
+ // Ignore missing excluded header files. They're optional anyway.
+ } else {
+ // If we find a module that has a missing header, we mark this module as
+ // unavailable and store the header directive for displaying diagnostics.
+ Mod->MissingHeaders.push_back(Header);
+ // A missing header with stat information doesn't make the module
+ // unavailable; this keeps our behavior consistent as headers are lazily
+ // resolved. (Such a module still can't be built though, except from
+ // preprocessed source.)
+ if (!Header.Size && !Header.ModTime)
+ Mod->markUnavailable();
+ }
+}
+
+bool ModuleMap::resolveAsBuiltinHeader(
+ Module *Mod, const Module::UnresolvedHeaderDirective &Header) {
+ if (Header.Kind == Module::HK_Excluded ||
+ llvm::sys::path::is_absolute(Header.FileName) ||
+ Mod->isPartOfFramework() || !Mod->IsSystem || Header.IsUmbrella ||
+ !BuiltinIncludeDir || BuiltinIncludeDir == Mod->Directory ||
+ !isBuiltinHeader(Header.FileName))
+ return false;
+
+ // This is a system module with a top-level header. This header
+ // may have a counterpart (or replacement) in the set of headers
+ // supplied by Clang. Find that builtin header.
+ SmallString<128> Path;
+ llvm::sys::path::append(Path, BuiltinIncludeDir->getName(), Header.FileName);
+ auto *File = SourceMgr.getFileManager().getFile(Path);
+ if (!File)
+ return false;
+
+ auto Role = headerKindToRole(Header.Kind);
+ Module::Header H = {Path.str(), File};
+ addHeader(Mod, H, Role);
+ return true;
+}
+
ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags,
const LangOptions &LangOpts, const TargetInfo *Target,
HeaderSearch &HeaderInfo)
@@ -162,6 +330,7 @@ bool ModuleMap::isBuiltinHeader(StringRef FileName) {
ModuleMap::HeadersMap::iterator
ModuleMap::findKnownHeader(const FileEntry *File) {
+ resolveHeaderDirectives(File);
HeadersMap::iterator Known = Headers.find(File);
if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
@@ -244,8 +413,10 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
if (getTopLevelOrNull(RequestingModule) != getTopLevelOrNull(SourceModule))
return;
- if (RequestingModule)
+ if (RequestingModule) {
resolveUses(RequestingModule, /*Complain=*/false);
+ resolveHeaderDirectives(RequestingModule);
+ }
bool Excluded = false;
Module *Private = nullptr;
@@ -427,6 +598,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
ArrayRef<ModuleMap::KnownHeader>
ModuleMap::findAllModulesForHeader(const FileEntry *File) const {
+ resolveHeaderDirectives(File);
auto It = Headers.find(File);
if (It == Headers.end())
return None;
@@ -440,6 +612,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
bool
ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
const Module *RequestingModule) const {
+ resolveHeaderDirectives(Header);
HeadersMap::const_iterator Known = Headers.find(Header);
if (Known != Headers.end()) {
for (SmallVectorImpl<KnownHeader>::const_iterator
@@ -554,16 +727,17 @@ Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
return Context->findSubmodule(Name);
}
-std::pair<Module *, bool>
-ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
- bool IsExplicit) {
+std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
+ Module *Parent,
+ bool IsFramework,
+ bool IsExplicit) {
// Try to find an existing module with this name.
if (Module *Sub = lookupModuleQualified(Name, Parent))
return std::make_pair(Sub, false);
// Create a new module with this name.
- Module *Result = new Module(Name, SourceLocation(), Parent,
- IsFramework, IsExplicit, NumCreatedModules++);
+ Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
+ IsExplicit, NumCreatedModules++);
if (!Parent) {
if (LangOpts.CurrentModule == Name)
SourceModule = Result;
@@ -580,6 +754,7 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
auto *Result =
new Module(Name, Loc, nullptr, /*IsFramework*/ false,
/*IsExplicit*/ false, NumCreatedModules++);
+ Result->Kind = Module::ModuleInterfaceUnit;
Modules[Name] = SourceModule = Result;
// Mark the main source file as being within the newly-created module so that
@@ -810,18 +985,63 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir,
UmbrellaDirs[UmbrellaDir] = Mod;
}
-static Module::HeaderKind headerRoleToKind(ModuleMap::ModuleHeaderRole Role) {
- switch ((int)Role) {
- default: llvm_unreachable("unknown header role");
- case ModuleMap::NormalHeader:
- return Module::HK_Normal;
- case ModuleMap::PrivateHeader:
- return Module::HK_Private;
- case ModuleMap::TextualHeader:
- return Module::HK_Textual;
- case ModuleMap::PrivateHeader | ModuleMap::TextualHeader:
- return Module::HK_PrivateTextual;
+void ModuleMap::addUnresolvedHeader(Module *Mod,
+ Module::UnresolvedHeaderDirective Header) {
+ // If there is a builtin counterpart to this file, add it now so it can
+ // wrap the system header.
+ if (resolveAsBuiltinHeader(Mod, Header)) {
+ // If we have both a builtin and system version of the file, the
+ // builtin version may want to inject macros into the system header, so
+ // force the system header to be treated as a textual header in this
+ // case.
+ Header.Kind = headerRoleToKind(ModuleMap::ModuleHeaderRole(
+ headerKindToRole(Header.Kind) | ModuleMap::TextualHeader));
+ Header.HasBuiltinHeader = true;
+ }
+
+ // If possible, don't stat the header until we need to. This requires the
+ // user to have provided us with some stat information about the file.
+ // FIXME: Add support for lazily stat'ing umbrella headers and excluded
+ // headers.
+ if ((Header.Size || Header.ModTime) && !Header.IsUmbrella &&
+ Header.Kind != Module::HK_Excluded) {
+ // We expect more variation in mtime than size, so if we're given both,
+ // use the mtime as the key.
+ if (Header.ModTime)
+ LazyHeadersByModTime[*Header.ModTime].push_back(Mod);
+ else
+ LazyHeadersBySize[*Header.Size].push_back(Mod);
+ Mod->UnresolvedHeaders.push_back(Header);
+ return;
}
+
+ // We don't have stat information or can't defer looking this file up.
+ // Perform the lookup now.
+ resolveHeader(Mod, Header);
+}
+
+void ModuleMap::resolveHeaderDirectives(const FileEntry *File) const {
+ auto BySize = LazyHeadersBySize.find(File->getSize());
+ if (BySize != LazyHeadersBySize.end()) {
+ for (auto *M : BySize->second)
+ resolveHeaderDirectives(M);
+ LazyHeadersBySize.erase(BySize);
+ }
+
+ auto ByModTime = LazyHeadersByModTime.find(File->getModificationTime());
+ if (ByModTime != LazyHeadersByModTime.end()) {
+ for (auto *M : ByModTime->second)
+ resolveHeaderDirectives(M);
+ LazyHeadersByModTime.erase(ByModTime);
+ }
+}
+
+void ModuleMap::resolveHeaderDirectives(Module *Mod) const {
+ for (auto &Header : Mod->UnresolvedHeaders)
+ // This operation is logically const; we're just changing how we represent
+ // the header information for this file.
+ const_cast<ModuleMap*>(this)->resolveHeader(Mod, Header);
+ Mod->UnresolvedHeaders.clear();
}
void ModuleMap::addHeader(Module *Mod, Module::Header Header,
@@ -948,39 +1168,6 @@ bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
return !Mod->UnresolvedConflicts.empty();
}
-Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
- if (Loc.isInvalid())
- return nullptr;
-
- if (UmbrellaDirs.empty() && Headers.empty())
- return nullptr;
-
- // Use the expansion location to determine which module we're in.
- FullSourceLoc ExpansionLoc = Loc.getExpansionLoc();
- if (!ExpansionLoc.isFileID())
- return nullptr;
-
- const SourceManager &SrcMgr = Loc.getManager();
- FileID ExpansionFileID = ExpansionLoc.getFileID();
-
- while (const FileEntry *ExpansionFile
- = SrcMgr.getFileEntryForID(ExpansionFileID)) {
- // Find the module that owns this header (if any).
- if (Module *Mod = findModuleForHeader(ExpansionFile).getModule())
- return Mod;
-
- // No module owns this header, so look up the inclusion chain to see if
- // any included header has an associated module.
- SourceLocation IncludeLoc = SrcMgr.getIncludeLoc(ExpansionFileID);
- if (IncludeLoc.isInvalid())
- return nullptr;
-
- ExpansionFileID = SrcMgr.getFileID(IncludeLoc);
- }
-
- return nullptr;
-}
-
//----------------------------------------------------------------------------//
// Module map file parser
//----------------------------------------------------------------------------//
@@ -1010,6 +1197,7 @@ namespace clang {
RequiresKeyword,
Star,
StringLiteral,
+ IntegerLiteral,
TextualKeyword,
LBrace,
RBrace,
@@ -1019,7 +1207,12 @@ namespace clang {
unsigned Location;
unsigned StringLength;
- const char *StringData;
+ union {
+ // If Kind != IntegerLiteral.
+ const char *StringData;
+ // If Kind == IntegerLiteral.
+ uint64_t IntegerValue;
+ };
void clear() {
Kind = EndOfFile;
@@ -1033,9 +1226,14 @@ namespace clang {
SourceLocation getLocation() const {
return SourceLocation::getFromRawEncoding(Location);
}
+
+ uint64_t getInteger() const {
+ return Kind == IntegerLiteral ? IntegerValue : 0;
+ }
StringRef getString() const {
- return StringRef(StringData, StringLength);
+ return Kind == IntegerLiteral ? StringRef()
+ : StringRef(StringData, StringLength);
}
};
@@ -1057,9 +1255,6 @@ namespace clang {
/// be resolved relative to.
const DirectoryEntry *Directory;
- /// \brief The directory containing Clang-supplied headers.
- const DirectoryEntry *BuiltinIncludeDir;
-
/// \brief Whether this module map is in a system header directory.
bool IsSystem;
@@ -1118,26 +1313,27 @@ namespace clang {
ModuleMap &Map,
const FileEntry *ModuleMapFile,
const DirectoryEntry *Directory,
- const DirectoryEntry *BuiltinIncludeDir,
bool IsSystem)
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
ModuleMapFile(ModuleMapFile), Directory(Directory),
- BuiltinIncludeDir(BuiltinIncludeDir), IsSystem(IsSystem),
- HadError(false), ActiveModule(nullptr)
+ IsSystem(IsSystem), HadError(false), ActiveModule(nullptr)
{
Tok.clear();
consumeToken();
}
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();
@@ -1227,12 +1423,50 @@ retry:
Tok.StringLength = Length;
break;
}
+
+ case tok::numeric_constant: {
+ // We don't support any suffixes or other complications.
+ SmallString<32> SpellingBuffer;
+ SpellingBuffer.resize(LToken.getLength() + 1);
+ const char *Start = SpellingBuffer.data();
+ unsigned Length =
+ Lexer::getSpelling(LToken, Start, SourceMgr, L.getLangOpts());
+ uint64_t Value;
+ if (StringRef(Start, Length).getAsInteger(0, Value)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
+ HadError = true;
+ goto retry;
+ }
+
+ Tok.Kind = MMToken::IntegerLiteral;
+ Tok.IntegerValue = Value;
+ break;
+ }
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;
}
@@ -1461,7 +1695,19 @@ void ModuleMapParser::parseModuleDecl() {
// Determine whether this (sub)module has already been defined.
if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {
- if (Existing->DefinitionLoc.isInvalid() && !ActiveModule) {
+ // We might see a (re)definition of a module that we already have a
+ // definition for in two cases:
+ // - If we loaded one definition from an AST file and we've just found a
+ // corresponding definition in a module map file, or
+ bool LoadedFromASTFile = Existing->DefinitionLoc.isInvalid();
+ // - If we're building a (preprocessed) module and we've just loaded the
+ // module map file from which it was created.
+ bool ParsedAsMainInput =
+ Map.LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap &&
+ Map.LangOpts.CurrentModule == ModuleName &&
+ SourceMgr.getDecomposedLoc(ModuleNameLoc).first !=
+ SourceMgr.getDecomposedLoc(Existing->DefinitionLoc).first;
+ if (!ActiveModule && (LoadedFromASTFile || ParsedAsMainInput)) {
// Skip the module definition.
skipUntil(MMToken::RBrace);
if (Tok.is(MMToken::RBrace))
@@ -1680,7 +1926,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.
@@ -1768,25 +2015,6 @@ void ModuleMapParser::parseRequiresDecl() {
} while (true);
}
-/// \brief Append to \p Paths the set of paths needed to get to the
-/// subframework in which the given module lives.
-static void appendSubframeworkPaths(Module *Mod,
- SmallVectorImpl<char> &Path) {
- // Collect the framework names from the given module to the top-level module.
- SmallVector<StringRef, 2> Paths;
- for (; Mod; Mod = Mod->Parent) {
- if (Mod->IsFramework)
- Paths.push_back(Mod->Name);
- }
-
- if (Paths.empty())
- return;
-
- // Add Frameworks/Name.framework for each subframework.
- for (unsigned I = Paths.size() - 1; I != 0; --I)
- llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
-}
-
/// \brief Parse a header declaration.
///
/// header-declaration:
@@ -1839,119 +2067,75 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
Module::UnresolvedHeaderDirective Header;
Header.FileName = Tok.getString();
Header.FileNameLoc = consumeToken();
-
+ Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
+ Header.Kind =
+ (LeadingToken == MMToken::ExcludeKeyword ? Module::HK_Excluded
+ : Map.headerRoleToKind(Role));
+
// Check whether we already have an umbrella.
- if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) {
+ if (Header.IsUmbrella && ActiveModule->Umbrella) {
Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
<< ActiveModule->getFullModuleName();
HadError = true;
return;
}
- // Look for this file.
- const FileEntry *File = nullptr;
- const FileEntry *BuiltinFile = nullptr;
- SmallString<128> RelativePathName;
- if (llvm::sys::path::is_absolute(Header.FileName)) {
- RelativePathName = Header.FileName;
- File = SourceMgr.getFileManager().getFile(RelativePathName);
- } else {
- // Search for the header file within the search directory.
- SmallString<128> FullPathName(Directory->getName());
- unsigned FullPathLength = FullPathName.size();
-
- if (ActiveModule->isPartOfFramework()) {
- appendSubframeworkPaths(ActiveModule, RelativePathName);
-
- // Check whether this file is in the public headers.
- llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
- llvm::sys::path::append(FullPathName, RelativePathName);
- File = SourceMgr.getFileManager().getFile(FullPathName);
-
- if (!File) {
- // Check whether this file is in the private headers.
- // FIXME: Should we retain the subframework paths here?
- RelativePathName.clear();
- FullPathName.resize(FullPathLength);
- llvm::sys::path::append(RelativePathName, "PrivateHeaders",
- Header.FileName);
- llvm::sys::path::append(FullPathName, RelativePathName);
- File = SourceMgr.getFileManager().getFile(FullPathName);
- }
- } else {
- // Lookup for normal headers.
- llvm::sys::path::append(RelativePathName, Header.FileName);
- llvm::sys::path::append(FullPathName, RelativePathName);
- File = SourceMgr.getFileManager().getFile(FullPathName);
-
- // If this is a system module with a top-level header, this header
- // may have a counterpart (or replacement) in the set of headers
- // supplied by Clang. Find that builtin header.
- if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword &&
- BuiltinIncludeDir && BuiltinIncludeDir != Directory &&
- ModuleMap::isBuiltinHeader(Header.FileName)) {
- SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
- llvm::sys::path::append(BuiltinPathName, Header.FileName);
- BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
-
- // If Clang supplies this header but the underlying system does not,
- // just silently swap in our builtin version. Otherwise, we'll end
- // up adding both (later).
- if (BuiltinFile && !File) {
- File = BuiltinFile;
- RelativePathName = BuiltinPathName;
- BuiltinFile = nullptr;
+ // If we were given stat information, parse it so we can skip looking for
+ // the file.
+ if (Tok.is(MMToken::LBrace)) {
+ SourceLocation LBraceLoc = consumeToken();
+
+ while (!Tok.is(MMToken::RBrace) && !Tok.is(MMToken::EndOfFile)) {
+ enum Attribute { Size, ModTime, Unknown };
+ StringRef Str = Tok.getString();
+ SourceLocation Loc = consumeToken();
+ switch (llvm::StringSwitch<Attribute>(Str)
+ .Case("size", Size)
+ .Case("mtime", ModTime)
+ .Default(Unknown)) {
+ case Size:
+ if (Header.Size)
+ Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
+ if (!Tok.is(MMToken::IntegerLiteral)) {
+ Diags.Report(Tok.getLocation(),
+ diag::err_mmap_invalid_header_attribute_value) << Str;
+ skipUntil(MMToken::RBrace);
+ break;
}
- }
- }
- }
+ Header.Size = Tok.getInteger();
+ consumeToken();
+ break;
- // FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
- // Come up with a lazy way to do this.
- if (File) {
- if (LeadingToken == MMToken::UmbrellaKeyword) {
- const DirectoryEntry *UmbrellaDir = File->getDir();
- if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
- Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash)
- << UmbrellaModule->getFullModuleName();
- HadError = true;
- } else {
- // Record this umbrella header.
- Map.setUmbrellaHeader(ActiveModule, File, RelativePathName.str());
- }
- } else if (LeadingToken == MMToken::ExcludeKeyword) {
- Module::Header H = {RelativePathName.str(), File};
- Map.excludeHeader(ActiveModule, H);
- } else {
- // If there is a builtin counterpart to this file, add it now so it can
- // wrap the system header.
- if (BuiltinFile) {
- // FIXME: Taking the name from the FileEntry is unstable and can give
- // different results depending on how we've previously named that file
- // in this build.
- Module::Header H = { BuiltinFile->getName(), BuiltinFile };
- Map.addHeader(ActiveModule, H, Role);
-
- // If we have both a builtin and system version of the file, the
- // builtin version may want to inject macros into the system header, so
- // force the system header to be treated as a textual header in this
- // case.
- Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);
- }
+ case ModTime:
+ if (Header.ModTime)
+ Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
+ if (!Tok.is(MMToken::IntegerLiteral)) {
+ Diags.Report(Tok.getLocation(),
+ diag::err_mmap_invalid_header_attribute_value) << Str;
+ skipUntil(MMToken::RBrace);
+ break;
+ }
+ Header.ModTime = Tok.getInteger();
+ consumeToken();
+ break;
- // Record this header.
- Module::Header H = { RelativePathName.str(), File };
- Map.addHeader(ActiveModule, H, Role);
+ case Unknown:
+ Diags.Report(Loc, diag::err_mmap_expected_header_attribute);
+ skipUntil(MMToken::RBrace);
+ break;
+ }
}
- } else if (LeadingToken != MMToken::ExcludeKeyword) {
- // Ignore excluded header files. They're optional anyway.
- // If we find a module that has a missing header, we mark this module as
- // unavailable and store the header directive for displaying diagnostics.
- Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
- ActiveModule->markUnavailable();
- ActiveModule->MissingHeaders.push_back(Header);
+ if (Tok.is(MMToken::RBrace))
+ consumeToken();
+ else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
+ Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
+ HadError = true;
+ }
}
+
+ Map.addUnresolvedHeader(ActiveModule, std::move(Header));
}
static int compareModuleHeaders(const Module::Header *A,
@@ -1995,9 +2179,8 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
}
if (!Dir) {
- Diags.Report(DirNameLoc, diag::err_mmap_umbrella_dir_not_found)
+ Diags.Report(DirNameLoc, diag::warn_mmap_umbrella_dir_not_found)
<< DirName;
- HadError = true;
return;
}
@@ -2503,6 +2686,7 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::RequiresKeyword:
case MMToken::Star:
case MMToken::StringLiteral:
+ case MMToken::IntegerLiteral:
case MMToken::TextualKeyword:
case MMToken::UmbrellaKeyword:
case MMToken::UseKeyword:
@@ -2515,28 +2699,46 @@ 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_ModuleMap : SrcMgr::C_User_ModuleMap;
+ 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);
+ 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/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp b/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp
index 45bdce3..f5e8cdc 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp
@@ -35,6 +35,29 @@ void Preprocessor::CommitBacktrackedTokens() {
BacktrackPositions.pop_back();
}
+Preprocessor::CachedTokensRange Preprocessor::LastCachedTokenRange() {
+ assert(isBacktrackEnabled());
+ auto PrevCachedLexPos = BacktrackPositions.back();
+ return CachedTokensRange{PrevCachedLexPos, CachedLexPos};
+}
+
+void Preprocessor::EraseCachedTokens(CachedTokensRange TokenRange) {
+ assert(TokenRange.Begin <= TokenRange.End);
+ if (CachedLexPos == TokenRange.Begin && TokenRange.Begin != TokenRange.End) {
+ // We have backtracked to the start of the token range as we want to consume
+ // them again. Erase the tokens only after consuming then.
+ assert(!CachedTokenRangeToErase);
+ CachedTokenRangeToErase = TokenRange;
+ return;
+ }
+ // The cached tokens were committed, so they should be erased now.
+ assert(TokenRange.End == CachedLexPos);
+ CachedTokens.erase(CachedTokens.begin() + TokenRange.Begin,
+ CachedTokens.begin() + TokenRange.End);
+ CachedLexPos = TokenRange.Begin;
+ ExitCachingLexMode();
+}
+
// Make Preprocessor re-lex the tokens that were lexed since
// EnableBacktrackAtThisPos() was previously called.
void Preprocessor::Backtrack() {
@@ -51,6 +74,13 @@ void Preprocessor::CachingLex(Token &Result) {
if (CachedLexPos < CachedTokens.size()) {
Result = CachedTokens[CachedLexPos++];
+ // Erase the some of the cached tokens after they are consumed when
+ // asked to do so.
+ if (CachedTokenRangeToErase &&
+ CachedTokenRangeToErase->End == CachedLexPos) {
+ EraseCachedTokens(*CachedTokenRangeToErase);
+ CachedTokenRangeToErase = None;
+ }
return;
}
diff --git a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp
index 322c580..b2450f5 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp
@@ -30,6 +30,7 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/PTHLexer.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/ArrayRef.h"
@@ -54,35 +55,12 @@ using namespace clang;
// Utility Methods for Preprocessor Directive Handling.
//===----------------------------------------------------------------------===//
-MacroInfo *Preprocessor::AllocateMacroInfo() {
- MacroInfoChain *MIChain = BP.Allocate<MacroInfoChain>();
- MIChain->Next = MIChainHead;
+MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
+ auto *MIChain = new (BP) MacroInfoChain{L, MIChainHead};
MIChainHead = MIChain;
return &MIChain->MI;
}
-MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
- MacroInfo *MI = AllocateMacroInfo();
- new (MI) MacroInfo(L);
- return MI;
-}
-
-MacroInfo *Preprocessor::AllocateDeserializedMacroInfo(SourceLocation L,
- unsigned SubModuleID) {
- static_assert(alignof(MacroInfo) >= sizeof(SubModuleID),
- "alignment for MacroInfo is less than the ID");
- DeserializedMacroInfoChain *MIChain =
- BP.Allocate<DeserializedMacroInfoChain>();
- MIChain->Next = DeserialMIChainHead;
- DeserialMIChainHead = MIChain;
-
- MacroInfo *MI = &MIChain->MI;
- new (MI) MacroInfo(L);
- MI->FromASTFile = true;
- MI->setOwningModuleID(SubModuleID);
- return MI;
-}
-
DefMacroDirective *Preprocessor::AllocateDefMacroDirective(MacroInfo *MI,
SourceLocation Loc) {
return new (BP) DefMacroDirective(MI, Loc);
@@ -242,26 +220,18 @@ bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
return Diag(MacroNameTok, diag::err_pp_missing_macro_name);
IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
- if (!II) {
- bool Invalid = false;
- std::string Spelling = getSpelling(MacroNameTok, &Invalid);
- if (Invalid)
- return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
- II = getIdentifierInfo(Spelling);
-
- if (!II->isCPlusPlusOperatorKeyword())
- return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+ if (!II)
+ return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+ if (II->isCPlusPlusOperatorKeyword()) {
// C++ 2.5p2: Alternative tokens behave the same as its primary token
// except for their spellings.
Diag(MacroNameTok, getLangOpts().MicrosoftExt
? diag::ext_pp_operator_used_as_macro_name
: diag::err_pp_operator_used_as_macro_name)
<< II << MacroNameTok.getKind();
-
// Allow #defining |and| and friends for Microsoft compatibility or
// recovery when legacy C headers are included in C++.
- MacroNameTok.setIdentifierInfo(II);
}
if ((isDefineUndef != MU_Other) && II->getPPKeywordID() == tok::pp_defined) {
@@ -560,7 +530,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
assert(CurPPLexer->LexingRawMode && "We have to be skipping here!");
CurPPLexer->LexingRawMode = false;
IdentifierInfo *IfNDefMacro = nullptr;
- const bool CondValue = EvaluateDirectiveExpression(IfNDefMacro);
+ const bool CondValue = EvaluateDirectiveExpression(IfNDefMacro).Conditional;
CurPPLexer->LexingRawMode = true;
if (Callbacks) {
const SourceLocation CondEnd = CurPPLexer->getSourceLocation();
@@ -657,7 +627,7 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
// Evaluate the condition of the #elif.
IdentifierInfo *IfNDefMacro = nullptr;
CurPTHLexer->ParsingPreprocessorDirective = true;
- bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro);
+ bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro).Conditional;
CurPTHLexer->ParsingPreprocessorDirective = false;
// If this condition is true, enter it!
@@ -690,24 +660,17 @@ Module *Preprocessor::getModuleForLocation(SourceLocation Loc) {
: HeaderInfo.lookupModule(getLangOpts().CurrentModule);
}
-Module *Preprocessor::getModuleContainingLocation(SourceLocation Loc) {
- return HeaderInfo.getModuleMap().inferModuleFromLocation(
- FullSourceLoc(Loc, SourceMgr));
-}
-
const FileEntry *
Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
+ Module *M,
SourceLocation Loc) {
+ assert(M && "no module to include");
+
// If we have a module import syntax, we shouldn't include a header to
// make a particular module visible.
if (getLangOpts().ObjC2)
return nullptr;
- // Figure out which module we'd want to import.
- Module *M = getModuleContainingLocation(Loc);
- if (!M)
- return nullptr;
-
Module *TopM = M->getTopLevelModule();
Module *IncM = getModuleForLocation(IncLoc);
@@ -719,6 +682,8 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
while (!Loc.isInvalid() && !SM.isInMainFile(Loc)) {
auto ID = SM.getFileID(SM.getExpansionLoc(Loc));
auto *FE = SM.getFileEntryForID(ID);
+ if (!FE)
+ break;
bool InTextualHeader = false;
for (auto Header : HeaderInfo.getModuleMap().findAllModulesForHeader(FE)) {
@@ -752,16 +717,11 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
}
const FileEntry *Preprocessor::LookupFile(
- SourceLocation FilenameLoc,
- StringRef Filename,
- bool isAngled,
- const DirectoryLookup *FromDir,
- const FileEntry *FromFile,
- const DirectoryLookup *&CurDir,
- SmallVectorImpl<char> *SearchPath,
+ SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
+ const DirectoryLookup *FromDir, const FileEntry *FromFile,
+ const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache) {
+ ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool SkipCache) {
Module *RequestingModule = getModuleForLocation(FilenameLoc);
bool RequestingModuleIsModuleInterface = !SourceMgr.isInMainFile(FilenameLoc);
@@ -819,7 +779,7 @@ const FileEntry *Preprocessor::LookupFile(
while (const FileEntry *FE = HeaderInfo.LookupFile(
Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir,
Includers, SearchPath, RelativePath, RequestingModule,
- SuggestedModule, SkipCache)) {
+ SuggestedModule, /*IsMapped=*/nullptr, SkipCache)) {
// Keep looking as if this file did a #include_next.
TmpFromDir = TmpCurDir;
++TmpFromDir;
@@ -835,7 +795,7 @@ const FileEntry *Preprocessor::LookupFile(
// Do a standard file entry lookup.
const FileEntry *FE = HeaderInfo.LookupFile(
Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
- RelativePath, RequestingModule, SuggestedModule, SkipCache,
+ RelativePath, RequestingModule, SuggestedModule, IsMapped, SkipCache,
BuildSystemModule);
if (FE) {
if (SuggestedModule && !LangOpts.AsmPreprocessor)
@@ -1206,18 +1166,26 @@ void Preprocessor::HandleLineDirective() {
CheckEndOfDirective("line", true);
}
- SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID);
+ // Take the file kind of the file containing the #line directive. #line
+ // directives are often used for generated sources from the same codebase, so
+ // the new file should generally be classified the same way as the current
+ // file. This is visible in GCC's pre-processed output, which rewrites #line
+ // to GNU line markers.
+ SrcMgr::CharacteristicKind FileKind =
+ SourceMgr.getFileCharacteristic(DigitTok.getLocation());
+
+ SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, false,
+ false, FileKind);
if (Callbacks)
Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
- PPCallbacks::RenameFile,
- SrcMgr::C_User);
+ PPCallbacks::RenameFile, FileKind);
}
/// ReadLineMarkerFlags - Parse and validate any flags at the end of a GNU line
/// marker directive.
static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
- bool &IsSystemHeader, bool &IsExternCHeader,
+ SrcMgr::CharacteristicKind &FileKind,
Preprocessor &PP) {
unsigned FlagVal;
Token FlagTok;
@@ -1268,7 +1236,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
return true;
}
- IsSystemHeader = true;
+ FileKind = SrcMgr::C_System;
PP.Lex(FlagTok);
if (FlagTok.is(tok::eod)) return false;
@@ -1282,7 +1250,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
return true;
}
- IsExternCHeader = true;
+ FileKind = SrcMgr::C_ExternCSystem;
PP.Lex(FlagTok);
if (FlagTok.is(tok::eod)) return false;
@@ -1312,14 +1280,15 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
Lex(StrTok);
bool IsFileEntry = false, IsFileExit = false;
- bool IsSystemHeader = false, IsExternCHeader = false;
int FilenameID = -1;
+ SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User;
// If the StrTok is "eod", then it wasn't present. Otherwise, it must be a
// string followed by eod.
- if (StrTok.is(tok::eod))
- ; // ok
- else if (StrTok.isNot(tok::string_literal)) {
+ if (StrTok.is(tok::eod)) {
+ // Treat this like "#line NN", which doesn't change file characteristics.
+ FileKind = SourceMgr.getFileCharacteristic(DigitTok.getLocation());
+ } else if (StrTok.isNot(tok::string_literal)) {
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
return DiscardUntilEndOfDirective();
} else if (StrTok.hasUDSuffix()) {
@@ -1338,15 +1307,13 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
// If a filename was present, read any flags that are present.
- if (ReadLineMarkerFlags(IsFileEntry, IsFileExit,
- IsSystemHeader, IsExternCHeader, *this))
+ if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, FileKind, *this))
return;
}
// Create a line note with this information.
- SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID,
- IsFileEntry, IsFileExit,
- IsSystemHeader, IsExternCHeader);
+ SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, IsFileEntry,
+ IsFileExit, FileKind);
// If the preprocessor has callbacks installed, notify them of the #line
// change. This is used so that the line marker comes out in -E mode for
@@ -1357,11 +1324,6 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
Reason = PPCallbacks::EnterFile;
else if (IsFileExit)
Reason = PPCallbacks::ExitFile;
- SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User;
- if (IsExternCHeader)
- FileKind = SrcMgr::C_ExternCSystem;
- else if (IsSystemHeader)
- FileKind = SrcMgr::C_System;
Callbacks->FileChanged(CurPPLexer->getSourceLocation(), Reason, FileKind);
}
@@ -1593,18 +1555,18 @@ bool Preprocessor::ConcatenateIncludeName(SmallString<128> &FilenameBuffer,
}
/// \brief Push a token onto the token stream containing an annotation.
-static void EnterAnnotationToken(Preprocessor &PP,
- SourceLocation Begin, SourceLocation End,
- tok::TokenKind Kind, void *AnnotationVal) {
+void Preprocessor::EnterAnnotationToken(SourceRange Range,
+ tok::TokenKind Kind,
+ void *AnnotationVal) {
// FIXME: Produce this as the current token directly, rather than
// allocating a new token for it.
auto Tok = llvm::make_unique<Token[]>(1);
Tok[0].startToken();
Tok[0].setKind(Kind);
- Tok[0].setLocation(Begin);
- Tok[0].setAnnotationEndLoc(End);
+ Tok[0].setLocation(Range.getBegin());
+ Tok[0].setAnnotationEndLoc(Range.getEnd());
Tok[0].setAnnotationValue(AnnotationVal);
- PP.EnterTokenStream(std::move(Tok), 1, true);
+ EnterTokenStream(std::move(Tok), 1, true);
}
/// \brief Produce a diagnostic informing the user that a #include or similar
@@ -1685,6 +1647,26 @@ static bool trySimplifyPath(SmallVectorImpl<StringRef> &Components,
return SuggestReplacement;
}
+bool Preprocessor::checkModuleIsAvailable(const LangOptions &LangOpts,
+ const TargetInfo &TargetInfo,
+ DiagnosticsEngine &Diags, Module *M) {
+ Module::Requirement Requirement;
+ Module::UnresolvedHeaderDirective MissingHeader;
+ if (M->isAvailable(LangOpts, TargetInfo, Requirement, MissingHeader))
+ return false;
+
+ if (MissingHeader.FileNameLoc.isValid()) {
+ Diags.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing)
+ << MissingHeader.IsUmbrella << MissingHeader.FileName;
+ } else {
+ // FIXME: Track the location at which the requirement was specified, and
+ // use it here.
+ Diags.Report(M->DefinitionLoc, diag::err_module_unavailable)
+ << M->getFullModuleName() << Requirement.second << Requirement.first;
+ }
+ return true;
+}
+
/// HandleIncludeDirective - The "\#include" tokens have just been read, read
/// the file to be included from the lexer, then include it! This is a common
/// routine with functionality shared between \#include, \#include_next and
@@ -1783,6 +1765,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
// Search include directories.
+ bool IsMapped = false;
const DirectoryLookup *CurDir;
SmallString<1024> SearchPath;
SmallString<1024> RelativePath;
@@ -1801,7 +1784,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
isAngled, LookupFrom, LookupFromFile, CurDir,
Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
- &SuggestedModule);
+ &SuggestedModule, &IsMapped);
if (!File) {
if (Callbacks) {
@@ -1818,7 +1801,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
FilenameLoc,
LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
LookupFrom, LookupFromFile, CurDir, nullptr, nullptr,
- &SuggestedModule, /*SkipCache*/ true);
+ &SuggestedModule, &IsMapped, /*SkipCache*/ true);
}
}
}
@@ -1833,8 +1816,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, false,
LookupFrom, LookupFromFile, CurDir,
Callbacks ? &SearchPath : nullptr,
- Callbacks ? &RelativePath : nullptr,
- &SuggestedModule);
+ Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped);
if (File) {
SourceRange Range(FilenameTok.getLocation(), CharEnd);
Diag(FilenameTok, diag::err_pp_file_not_found_not_fatal) <<
@@ -1856,33 +1838,24 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// we've imported or already built.
bool ShouldEnter = true;
+ if (PPOpts->SingleFileParseMode)
+ ShouldEnter = false;
+
// Determine whether we should try to import the module for this #include, if
// there is one. Don't do so if precompiled module support is disabled or we
// are processing this module textually (because we're building the module).
- if (File && SuggestedModule && getLangOpts().Modules &&
+ if (ShouldEnter && File && SuggestedModule && getLangOpts().Modules &&
SuggestedModule.getModule()->getTopLevelModuleName() !=
getLangOpts().CurrentModule) {
// If this include corresponds to a module but that module is
// unavailable, diagnose the situation and bail out.
// FIXME: Remove this; loadModule does the same check (but produces
// slightly worse diagnostics).
- if (!SuggestedModule.getModule()->isAvailable()) {
- Module::Requirement Requirement;
- Module::UnresolvedHeaderDirective MissingHeader;
- Module *M = SuggestedModule.getModule();
- // Identify the cause.
- (void)M->isAvailable(getLangOpts(), getTargetInfo(), Requirement,
- MissingHeader);
- if (MissingHeader.FileNameLoc.isValid()) {
- Diag(MissingHeader.FileNameLoc, diag::err_module_header_missing)
- << MissingHeader.IsUmbrella << MissingHeader.FileName;
- } else {
- Diag(M->DefinitionLoc, diag::err_module_unavailable)
- << M->getFullModuleName() << Requirement.second << Requirement.first;
- }
+ if (checkModuleIsAvailable(getLangOpts(), getTargetInfo(), getDiagnostics(),
+ SuggestedModule.getModule())) {
Diag(FilenameTok.getLocation(),
diag::note_implicit_top_level_module_import_here)
- << M->getTopLevelModuleName();
+ << SuggestedModule.getModule()->getTopLevelModuleName();
return;
}
@@ -1939,6 +1912,25 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
}
+ // The #included file will be considered to be a system header if either it is
+ // in a system include directory, or if the #includer is a system include
+ // header.
+ SrcMgr::CharacteristicKind FileCharacter =
+ SourceMgr.getFileCharacteristic(FilenameTok.getLocation());
+ if (File)
+ FileCharacter = std::max(HeaderInfo.getFileDirFlavor(File), FileCharacter);
+
+ // Ask HeaderInfo if we should enter this #include file. If not, #including
+ // this file will have no effect.
+ bool SkipHeader = false;
+ if (ShouldEnter && File &&
+ !HeaderInfo.ShouldEnterIncludeFile(*this, File, isImport,
+ getLangOpts().Modules,
+ SuggestedModule.getModule())) {
+ ShouldEnter = false;
+ SkipHeader = true;
+ }
+
if (Callbacks) {
// Notify the callback object that we've seen an inclusion directive.
Callbacks->InclusionDirective(
@@ -1946,25 +1938,20 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
FilenameRange, File, SearchPath, RelativePath,
ShouldEnter ? nullptr : SuggestedModule.getModule());
+ if (SkipHeader && !SuggestedModule.getModule())
+ Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
}
if (!File)
return;
- // The #included file will be considered to be a system header if either it is
- // in a system include directory, or if the #includer is a system include
- // header.
- SrcMgr::CharacteristicKind FileCharacter =
- std::max(HeaderInfo.getFileDirFlavor(File),
- SourceMgr.getFileCharacteristic(FilenameTok.getLocation()));
-
// FIXME: If we have a suggested module, and we've already visited this file,
// don't bother entering it again. We know it has no further effect.
// Issue a diagnostic if the name of the file on disk has a different case
// than the one we're about to open.
const bool CheckIncludePathPortability =
- File && !File->tryGetRealPathName().empty();
+ !IsMapped && File && !File->tryGetRealPathName().empty();
if (CheckIncludePathPortability) {
StringRef Name = LangOpts.MSVCCompat ? NormalizedPath.str() : Filename;
@@ -1976,37 +1963,27 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
SmallString<128> Path;
Path.reserve(Name.size()+2);
Path.push_back(isAngled ? '<' : '"');
+ bool isLeadingSeparator = llvm::sys::path::is_absolute(Name);
for (auto Component : Components) {
- Path.append(Component);
+ if (isLeadingSeparator)
+ isLeadingSeparator = false;
+ else
+ Path.append(Component);
// Append the separator the user used, or the close quote
Path.push_back(
Path.size() <= Filename.size() ? Filename[Path.size()-1] :
(isAngled ? '>' : '"'));
}
- auto Replacement = Path.str().str();
// For user files and known standard headers, by default we issue a diagnostic.
// For other system headers, we don't. They can be controlled separately.
auto DiagId = (FileCharacter == SrcMgr::C_User || warnByDefaultOnWrongCase(Name)) ?
diag::pp_nonportable_path : diag::pp_nonportable_system_path;
SourceRange Range(FilenameTok.getLocation(), CharEnd);
- Diag(FilenameTok, DiagId) << Replacement <<
- FixItHint::CreateReplacement(Range, Replacement);
+ Diag(FilenameTok, DiagId) << Path <<
+ FixItHint::CreateReplacement(Range, Path);
}
}
- // Ask HeaderInfo if we should enter this #include file. If not, #including
- // this file will have no effect.
- bool SkipHeader = false;
- if (ShouldEnter &&
- !HeaderInfo.ShouldEnterIncludeFile(*this, File, isImport,
- getLangOpts().Modules,
- SuggestedModule.getModule())) {
- ShouldEnter = false;
- SkipHeader = true;
- if (Callbacks)
- Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
- }
-
// If we don't need to enter the file, stop now.
if (!ShouldEnter) {
// If this is a module import, make it visible if needed.
@@ -2023,7 +2000,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (IncludeTok.getIdentifierInfo()->getPPKeywordID() !=
tok::pp___include_macros)
- EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_include, M);
+ EnterAnnotationToken(SourceRange(HashLoc, End),
+ tok::annot_module_include, M);
}
return;
}
@@ -2050,18 +2028,18 @@ 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.
// FIXME: There's no point doing this if we're handling a #__include_macros
// directive.
- EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_begin, M);
+ EnterAnnotationToken(SourceRange(HashLoc, End), tok::annot_module_begin, M);
}
}
@@ -2083,7 +2061,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?");
@@ -2157,11 +2135,11 @@ void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc,
// Preprocessor Macro Directive Handling.
//===----------------------------------------------------------------------===//
-/// ReadMacroDefinitionArgList - The ( starting an argument list of a macro
+/// ReadMacroParameterList - The ( starting an argument list of a macro
/// definition has just been read. Lex the rest of the arguments and the
/// closing ), updating MI with what we learn. Return true if an error occurs
/// parsing the arg list.
-bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
+bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) {
SmallVector<IdentifierInfo*, 32> Arguments;
while (true) {
@@ -2195,7 +2173,7 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
// Add the __VA_ARGS__ identifier as an argument.
Arguments.push_back(Ident__VA_ARGS__);
MI->setIsC99Varargs();
- MI->setArgumentList(Arguments, BP);
+ MI->setParameterList(Arguments, BP);
return false;
case tok::eod: // #define X(
Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
@@ -2229,7 +2207,7 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
Diag(Tok, diag::err_pp_expected_comma_in_arg_list);
return true;
case tok::r_paren: // #define X(A)
- MI->setArgumentList(Arguments, BP);
+ MI->setParameterList(Arguments, BP);
return false;
case tok::comma: // #define X(A,
break;
@@ -2245,7 +2223,7 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
}
MI->setIsGNUVarargs();
- MI->setArgumentList(Arguments, BP);
+ MI->setParameterList(Arguments, BP);
return false;
}
}
@@ -2294,28 +2272,20 @@ static bool isConfigurationPattern(Token &MacroName, MacroInfo *MI,
MI->getNumTokens() == 0;
}
-/// HandleDefineDirective - Implements \#define. This consumes the entire macro
-/// line then lets the caller lex the next real token.
-void Preprocessor::HandleDefineDirective(Token &DefineTok,
- bool ImmediatelyAfterHeaderGuard) {
- ++NumDefined;
-
- Token MacroNameTok;
- bool MacroShadowsKeyword;
- ReadMacroName(MacroNameTok, MU_Define, &MacroShadowsKeyword);
+// ReadOptionalMacroParameterListAndBody - This consumes all (i.e. the
+// entire line) of the macro's tokens and adds them to MacroInfo, and while
+// doing so performs certain validity checks including (but not limited to):
+// - # (stringization) is followed by a macro parameter
+//
+// Returns a nullptr if an invalid sequence of tokens is encountered or returns
+// a pointer to a MacroInfo object.
- // Error reading macro name? If so, diagnostic already issued.
- if (MacroNameTok.is(tok::eod))
- return;
+MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
+ const Token &MacroNameTok, const bool ImmediatelyAfterHeaderGuard) {
Token LastTok = MacroNameTok;
-
- // If we are supposed to keep comments in #defines, reenable comment saving
- // mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepMacroComments);
-
// Create the new macro.
- MacroInfo *MI = AllocateMacroInfo(MacroNameTok.getLocation());
+ MacroInfo *const MI = AllocateMacroInfo(MacroNameTok.getLocation());
Token Tok;
LexUnexpandedToken(Tok);
@@ -2337,11 +2307,11 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
} else if (Tok.is(tok::l_paren)) {
// This is a function-like macro definition. Read the argument list.
MI->setIsFunctionLike();
- if (ReadMacroDefinitionArgList(MI, LastTok)) {
+ if (ReadMacroParameterList(MI, LastTok)) {
// Throw away the rest of the line.
if (CurPPLexer->ParsingPreprocessorDirective)
DiscardUntilEndOfDirective();
- return;
+ return nullptr;
}
// If this is a definition of a variadic C99 function-like macro, not using
@@ -2448,7 +2418,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
// Check for a valid macro arg identifier.
if (Tok.getIdentifierInfo() == nullptr ||
- MI->getArgumentNum(Tok.getIdentifierInfo()) == -1) {
+ MI->getParameterNum(Tok.getIdentifierInfo()) == -1) {
// If this is assembler-with-cpp mode, we accept random gibberish after
// the '#' because '#' is often a comment character. However, change
@@ -2464,7 +2434,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
// Disable __VA_ARGS__ again.
Ident__VA_ARGS__->setIsPoisoned(true);
- return;
+ return nullptr;
}
}
@@ -2477,15 +2447,39 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
LexUnexpandedToken(Tok);
}
}
+ MI->setDefinitionEndLoc(LastTok.getLocation());
+ // Disable __VA_ARGS__ again.
+ Ident__VA_ARGS__->setIsPoisoned(true);
+
+ return MI;
+}
+/// HandleDefineDirective - Implements \#define. This consumes the entire macro
+/// line then lets the caller lex the next real token.
+void Preprocessor::HandleDefineDirective(
+ Token &DefineTok, const bool ImmediatelyAfterHeaderGuard) {
+ ++NumDefined;
+
+ Token MacroNameTok;
+ bool MacroShadowsKeyword;
+ ReadMacroName(MacroNameTok, MU_Define, &MacroShadowsKeyword);
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.is(tok::eod))
+ return;
+
+ // If we are supposed to keep comments in #defines, reenable comment saving
+ // mode.
+ if (CurLexer) CurLexer->SetCommentRetentionState(KeepMacroComments);
+
+ MacroInfo *const MI = ReadOptionalMacroParameterListAndBody(
+ MacroNameTok, ImmediatelyAfterHeaderGuard);
+
+ if (!MI) return;
if (MacroShadowsKeyword &&
!isConfigurationPattern(MacroNameTok, MI, getLangOpts())) {
Diag(MacroNameTok, diag::warn_pp_macro_hides_keyword);
- }
-
- // Disable __VA_ARGS__ again.
- Ident__VA_ARGS__->setIsPoisoned(true);
-
+ }
// Check that there is no paste (##) operator at the beginning or end of the
// replacement list.
unsigned NumTokens = MI->getNumTokens();
@@ -2500,7 +2494,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
}
}
- MI->setDefinitionEndLoc(LastTok.getLocation());
+
// Finally, if this identifier already had a macro defined for it, verify that
// the macro bodies are identical, and issue diagnostics if they are not.
@@ -2589,25 +2583,26 @@ void Preprocessor::HandleUndefDirective() {
// Okay, we have a valid identifier to undef.
auto *II = MacroNameTok.getIdentifierInfo();
auto MD = getMacroDefinition(II);
+ UndefMacroDirective *Undef = nullptr;
+
+ // If the macro is not defined, this is a noop undef.
+ if (const MacroInfo *MI = MD.getMacroInfo()) {
+ if (!MI->isUsed() && MI->isWarnIfUnused())
+ Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
+
+ if (MI->isWarnIfUnused())
+ WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
+
+ Undef = AllocateUndefMacroDirective(MacroNameTok.getLocation());
+ }
// If the callbacks want to know, tell them about the macro #undef.
// Note: no matter if the macro was defined or not.
if (Callbacks)
- Callbacks->MacroUndefined(MacroNameTok, MD);
-
- // If the macro is not defined, this is a noop undef, just return.
- const MacroInfo *MI = MD.getMacroInfo();
- if (!MI)
- return;
+ Callbacks->MacroUndefined(MacroNameTok, MD, Undef);
- if (!MI->isUsed() && MI->isWarnIfUnused())
- Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
-
- if (MI->isWarnIfUnused())
- WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
-
- appendMacroDirective(MacroNameTok.getIdentifierInfo(),
- AllocateUndefMacroDirective(MacroNameTok.getLocation()));
+ if (Undef)
+ appendMacroDirective(II, Undef);
}
//===----------------------------------------------------------------------===//
@@ -2667,7 +2662,13 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
}
// Should we include the stuff contained by this directive?
- if (!MI == isIfndef) {
+ if (PPOpts->SingleFileParseMode && !MI) {
+ // In 'single-file-parse mode' undefined identifiers trigger parsing of all
+ // the directive blocks.
+ CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(),
+ /*wasskip*/false, /*foundnonskip*/false,
+ /*foundelse*/false);
+ } else if (!MI == isIfndef) {
// Yes, remember that we are inside a conditional, then lex the next token.
CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(),
/*wasskip*/false, /*foundnonskip*/true,
@@ -2689,7 +2690,8 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
// Parse and evaluate the conditional expression.
IdentifierInfo *IfNDefMacro = nullptr;
const SourceLocation ConditionalBegin = CurPPLexer->getSourceLocation();
- const bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro);
+ const DirectiveEvalResult DER = EvaluateDirectiveExpression(IfNDefMacro);
+ const bool ConditionalTrue = DER.Conditional;
const SourceLocation ConditionalEnd = CurPPLexer->getSourceLocation();
// If this condition is equivalent to #ifndef X, and if this is the first
@@ -2708,7 +2710,12 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
(ConditionalTrue ? PPCallbacks::CVK_True : PPCallbacks::CVK_False));
// Should we include the stuff contained by this directive?
- if (ConditionalTrue) {
+ if (PPOpts->SingleFileParseMode && DER.IncludedUndefinedIds) {
+ // In 'single-file-parse mode' undefined identifiers trigger parsing of all
+ // the directive blocks.
+ CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
+ /*foundnonskip*/false, /*foundelse*/false);
+ } else if (ConditionalTrue) {
// Yes, remember that we are inside a conditional, then lex the next token.
CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
/*foundnonskip*/true, /*foundelse*/false);
@@ -2769,6 +2776,14 @@ void Preprocessor::HandleElseDirective(Token &Result) {
if (Callbacks)
Callbacks->Else(Result.getLocation(), CI.IfLoc);
+ if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) {
+ // In 'single-file-parse mode' undefined identifiers trigger parsing of all
+ // the directive blocks.
+ CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/false,
+ /*foundnonskip*/false, /*foundelse*/true);
+ return;
+ }
+
// Finally, skip the rest of the contents of this block.
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
/*FoundElse*/true, Result.getLocation());
@@ -2804,6 +2819,14 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
SourceRange(ConditionalBegin, ConditionalEnd),
PPCallbacks::CVK_NotEvaluated, CI.IfLoc);
+ if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) {
+ // In 'single-file-parse mode' undefined identifiers trigger parsing of all
+ // the directive blocks.
+ CurPPLexer->pushConditionalLevel(ElifToken.getLocation(), /*wasskip*/false,
+ /*foundnonskip*/false, /*foundelse*/false);
+ return;
+ }
+
// Finally, skip the rest of the contents of this block.
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
/*FoundElse*/CI.FoundElse,
diff --git a/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp b/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp
index 862a471..d843182 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp
@@ -73,6 +73,7 @@ public:
static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
Token &PeekTok, bool ValueLive,
+ bool &IncludedUndefinedIds,
Preprocessor &PP);
/// DefinedTracker - This struct is used while parsing expressions to keep track
@@ -93,6 +94,7 @@ struct DefinedTracker {
/// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
/// indicates the macro that was checked.
IdentifierInfo *TheMacro;
+ bool IncludedUndefinedIds = false;
};
/// EvaluateDefined - Process a 'defined(sym)' expression.
@@ -128,6 +130,7 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
MacroDefinition Macro = PP.getMacroDefinition(II);
Result.Val = !!Macro;
Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+ DT.IncludedUndefinedIds = !Macro;
// If there is a macro, mark it used.
if (Result.Val != 0 && ValueLive)
@@ -234,33 +237,32 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.setCodeCompletionReached();
PP.LexNonComment(PeekTok);
}
-
- // If this token's spelling is a pp-identifier, check to see if it is
- // 'defined' or if it is a macro. Note that we check here because many
- // keywords are pp-identifiers, so we can't check the kind.
- if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
- // Handle "defined X" and "defined(X)".
- if (II->isStr("defined"))
- return EvaluateDefined(Result, PeekTok, DT, ValueLive, PP);
-
- // If this identifier isn't 'defined' or one of the special
- // preprocessor keywords and it wasn't macro expanded, it turns
- // into a simple 0, unless it is the C++ keyword "true", in which case it
- // turns into "1".
- if (ValueLive &&
- II->getTokenID() != tok::kw_true &&
- II->getTokenID() != tok::kw_false)
- PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
- Result.Val = II->getTokenID() == tok::kw_true;
- Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
- Result.setIdentifier(II);
- Result.setRange(PeekTok.getLocation());
- PP.LexNonComment(PeekTok);
- return false;
- }
switch (PeekTok.getKind()) {
- default: // Non-value token.
+ default:
+ // If this token's spelling is a pp-identifier, check to see if it is
+ // 'defined' or if it is a macro. Note that we check here because many
+ // keywords are pp-identifiers, so we can't check the kind.
+ if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
+ // Handle "defined X" and "defined(X)".
+ if (II->isStr("defined"))
+ return EvaluateDefined(Result, PeekTok, DT, ValueLive, PP);
+
+ if (!II->isCPlusPlusOperatorKeyword()) {
+ // If this identifier isn't 'defined' or one of the special
+ // preprocessor keywords and it wasn't macro expanded, it turns
+ // into a simple 0
+ if (ValueLive)
+ PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
+ Result.Val = 0;
+ Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
+ Result.setIdentifier(II);
+ Result.setRange(PeekTok.getLocation());
+ DT.IncludedUndefinedIds = true;
+ PP.LexNonComment(PeekTok);
+ return false;
+ }
+ }
PP.Diag(PeekTok, diag::err_pp_expr_bad_token_start_expr);
return true;
case tok::eod:
@@ -400,7 +402,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// Just use DT unmodified as our result.
} else {
// Otherwise, we have something like (x+y), and we consumed '(x'.
- if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
+ if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive,
+ DT.IncludedUndefinedIds, PP))
return true;
if (PeekTok.isNot(tok::r_paren)) {
@@ -475,6 +478,14 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
DT.State = DefinedTracker::DefinedMacro;
return false;
}
+ case tok::kw_true:
+ case tok::kw_false:
+ Result.Val = PeekTok.getKind() == tok::kw_true;
+ Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
+ Result.setIdentifier(PeekTok.getIdentifierInfo());
+ Result.setRange(PeekTok.getLocation());
+ PP.LexNonComment(PeekTok);
+ return false;
// FIXME: Handle #assert
}
@@ -532,6 +543,7 @@ static void diagnoseUnexpectedOperator(Preprocessor &PP, PPValue &LHS,
/// evaluation, such as division by zero warnings.
static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
Token &PeekTok, bool ValueLive,
+ bool &IncludedUndefinedIds,
Preprocessor &PP) {
unsigned PeekPrec = getPrecedence(PeekTok.getKind());
// If this token isn't valid, report the error.
@@ -571,6 +583,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
// Parse the RHS of the operator.
DefinedTracker DT;
if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true;
+ IncludedUndefinedIds = DT.IncludedUndefinedIds;
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
@@ -601,7 +614,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
RHSPrec = ThisPrec+1;
if (PeekPrec >= RHSPrec) {
- if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive, PP))
+ if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive,
+ IncludedUndefinedIds, PP))
return true;
PeekPrec = getPrecedence(PeekTok.getKind());
}
@@ -769,7 +783,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
// Parse anything after the : with the same precedence as ?. We allow
// things of equal precedence because ?: is right associative.
if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec,
- PeekTok, AfterColonLive, PP))
+ PeekTok, AfterColonLive,
+ IncludedUndefinedIds, PP))
return true;
// Now that we have the condition, the LHS and the RHS of the :, evaluate.
@@ -806,7 +821,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
/// may occur after a #if or #elif directive. If the expression is equivalent
/// to "!defined(X)" return X in IfNDefMacro.
-bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
+Preprocessor::DirectiveEvalResult
+Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true);
// Save the current state of 'DisableMacroExpansion' and reset it to false. If
// 'DisableMacroExpansion' is true, then we must be in a macro argument list
@@ -833,7 +849,7 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// Restore 'DisableMacroExpansion'.
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
- return false;
+ return {false, DT.IncludedUndefinedIds};
}
// If we are at the end of the expression after just parsing a value, there
@@ -847,20 +863,20 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// Restore 'DisableMacroExpansion'.
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
- return ResVal.Val != 0;
+ return {ResVal.Val != 0, DT.IncludedUndefinedIds};
}
// Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the
// operator and the stuff after it.
if (EvaluateDirectiveSubExpr(ResVal, getPrecedence(tok::question),
- Tok, true, *this)) {
+ Tok, true, DT.IncludedUndefinedIds, *this)) {
// Parse error, skip the rest of the macro line.
if (Tok.isNot(tok::eod))
DiscardUntilEndOfDirective();
// Restore 'DisableMacroExpansion'.
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
- return false;
+ return {false, DT.IncludedUndefinedIds};
}
// If we aren't at the tok::eod token, something bad happened, like an extra
@@ -872,5 +888,5 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
// Restore 'DisableMacroExpansion'.
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
- return ResVal.Val != 0;
+ return {ResVal.Val != 0, DT.IncludedUndefinedIds};
}
diff --git a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp
index 4db17c3..36d7028 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp
+++ b/contrib/llvm/tools/clang/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;
@@ -287,6 +287,48 @@ const char *Preprocessor::getCurLexerEndPos() {
return EndPos;
}
+static void collectAllSubModulesWithUmbrellaHeader(
+ const Module &Mod, SmallVectorImpl<const Module *> &SubMods) {
+ if (Mod.getUmbrellaHeader())
+ SubMods.push_back(&Mod);
+ for (auto *M : Mod.submodules())
+ collectAllSubModulesWithUmbrellaHeader(*M, SubMods);
+}
+
+void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) {
+ assert(Mod.getUmbrellaHeader() && "Module must use umbrella header");
+ SourceLocation StartLoc =
+ SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+ if (getDiagnostics().isIgnored(diag::warn_uncovered_module_header, StartLoc))
+ return;
+
+ ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
+ const DirectoryEntry *Dir = Mod.getUmbrellaDir().Entry;
+ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+ std::error_code EC;
+ for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End;
+ Entry != End && !EC; Entry.increment(EC)) {
+ using llvm::StringSwitch;
+
+ // Check whether this entry has an extension typically associated with
+ // headers.
+ if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName()))
+ .Cases(".h", ".H", ".hh", ".hpp", true)
+ .Default(false))
+ continue;
+
+ if (const FileEntry *Header = getFileManager().getFile(Entry->getName()))
+ if (!getSourceManager().hasFileInfo(Header)) {
+ if (!ModMap.isHeaderInUnavailableModule(Header)) {
+ // Find the relative path that would access this header.
+ SmallString<128> RelativePath;
+ computeRelativePath(FileMgr, Dir, Header, RelativePath);
+ Diag(StartLoc, diag::warn_uncovered_module_header)
+ << Mod.getFullModuleName() << RelativePath;
+ }
+ }
+ }
+}
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
/// the current file. This either returns the EOF token or pops a level off
@@ -295,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 =
@@ -303,9 +365,8 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
if (const FileEntry *FE = CurPPLexer->getFileEntry()) {
HeaderInfo.SetFileControllingMacro(FE, ControllingMacro);
if (MacroInfo *MI =
- getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro))) {
- MI->UsedForHeaderGuard = true;
- }
+ getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro)))
+ MI->setUsedForHeaderGuard(true);
if (const IdentifierInfo *DefinedMacro =
CurPPLexer->MIOpt.GetDefinedMacro()) {
if (!isMacroDefined(ControllingMacro) &&
@@ -397,22 +458,27 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs);
}
+ bool ExitedFromPredefinesFile = false;
FileID ExitedFID;
- if (Callbacks && !isEndOfMacro && CurPPLexer)
+ if (!isEndOfMacro && CurPPLexer) {
ExitedFID = CurPPLexer->getFileID();
- bool LeavingSubmodule = CurSubmodule && CurLexer;
+ assert(PredefinesFileID.isValid() &&
+ "HandleEndOfFile is called before PredefinesFileId is set");
+ ExitedFromPredefinesFile = (PredefinesFileID == ExitedFID);
+ }
+
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.
@@ -429,6 +495,11 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
PPCallbacks::ExitFile, FileType, ExitedFID);
}
+ // Restore conditional stack from the preamble right after exiting from the
+ // predefines file.
+ if (ExitedFromPredefinesFile)
+ replayPreambleConditionalStack();
+
// Client should lex another token unless we generated an EOM.
return LeavingSubmodule;
}
@@ -474,44 +545,14 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
}
// If we are building a module that has an umbrella header, make sure that
- // each of the headers within the directory covered by the umbrella header
- // was actually included by the umbrella header.
+ // each of the headers within the directory, including all submodules, is
+ // covered by the umbrella header was actually included by the umbrella
+ // header.
if (Module *Mod = getCurrentModule()) {
- if (Mod->getUmbrellaHeader()) {
- SourceLocation StartLoc
- = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
-
- if (!getDiagnostics().isIgnored(diag::warn_uncovered_module_header,
- StartLoc)) {
- ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
- const DirectoryEntry *Dir = Mod->getUmbrellaDir().Entry;
- vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
- std::error_code EC;
- for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End;
- Entry != End && !EC; Entry.increment(EC)) {
- using llvm::StringSwitch;
-
- // Check whether this entry has an extension typically associated with
- // headers.
- if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName()))
- .Cases(".h", ".H", ".hh", ".hpp", true)
- .Default(false))
- continue;
-
- if (const FileEntry *Header =
- getFileManager().getFile(Entry->getName()))
- if (!getSourceManager().hasFileInfo(Header)) {
- if (!ModMap.isHeaderInUnavailableModule(Header)) {
- // Find the relative path that would access this header.
- SmallString<128> RelativePath;
- computeRelativePath(FileMgr, Dir, Header, RelativePath);
- Diag(StartLoc, diag::warn_uncovered_module_header)
- << Mod->getFullModuleName() << RelativePath;
- }
- }
- }
- }
- }
+ llvm::SmallVector<const Module *, 4> AllMods;
+ collectAllSubModulesWithUmbrellaHeader(*Mod, AllMods);
+ for (auto *M : AllMods)
+ diagnoseMissingHeaderInUmbrellaDir(*M);
}
return true;
@@ -617,11 +658,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;
}
@@ -662,8 +705,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;
@@ -686,13 +730,19 @@ 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;
SourceLocation ImportLoc = Info.ImportLoc;
- if (!needModuleMacros() ||
+ if (!needModuleMacros() ||
(!getLangOpts().ModulesLocalVisibility &&
LeavingMod->getTopLevelModuleName() != getLangOpts().CurrentModule)) {
// If we don't need module macros, or this is not a module for which we
@@ -700,7 +750,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.
@@ -738,17 +788,6 @@ void Preprocessor::LeaveSubmodule() {
for (auto *MD = Macro.getLatest(); MD != OldMD; MD = MD->getPrevious()) {
assert(MD && "broken macro directive chain");
- // Stop on macros defined in other submodules of this module that we
- // #included along the way. There's no point doing this if we're
- // tracking local submodule visibility, since there can be no such
- // directives in our list.
- if (!getLangOpts().ModulesLocalVisibility) {
- Module *Mod = getModuleContainingLocation(MD->getLocation());
- if (Mod != LeavingMod &&
- Mod->getTopLevelModule() == LeavingMod->getTopLevelModule())
- break;
- }
-
if (auto *VisMD = dyn_cast<VisibilityMacroDirective>(MD)) {
// The latest visibility directive for a name in a submodule affects
// all the directives that come before it.
@@ -770,6 +809,13 @@ void Preprocessor::LeaveSubmodule() {
if (Def || !Macro.getOverriddenMacros().empty())
addModuleMacro(LeavingMod, II, Def,
Macro.getOverriddenMacros(), IsNew);
+
+ if (!getLangOpts().ModulesLocalVisibility) {
+ // This macro is exposed to the rest of this compilation as a
+ // ModuleMacro; we don't need to track its MacroDirective any more.
+ Macro.setLatest(nullptr);
+ Macro.setOverriddenMacros(*this, {});
+ }
break;
}
}
@@ -789,4 +835,5 @@ void Preprocessor::LeaveSubmodule() {
// A nested #include makes the included submodule visible.
makeModuleVisible(LeavingMod, ImportLoc);
+ return LeavingMod;
}
diff --git a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp
index de166c7..3f8ede2 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp
@@ -412,7 +412,7 @@ static bool isTrivialSingleTokenExpansion(const MacroInfo *MI,
// If this is a function-like macro invocation, it's safe to trivially expand
// as long as the identifier is not a macro argument.
- return std::find(MI->arg_begin(), MI->arg_end(), II) == MI->arg_end();
+ return std::find(MI->param_begin(), MI->param_end(), II) == MI->param_end();
}
/// isNextPPTokenLParen - Determine whether the next preprocessor token to be
@@ -492,7 +492,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// Preprocessor directives used inside macro arguments are not portable, and
// this enables the warning.
InMacroArgs = true;
- Args = ReadFunctionLikeMacroArgs(Identifier, MI, ExpansionEnd);
+ Args = ReadMacroCallArgumentList(Identifier, MI, ExpansionEnd);
// Finished parsing args.
InMacroArgs = false;
@@ -745,11 +745,11 @@ static bool GenerateNewArgTokens(Preprocessor &PP,
/// token is the '(' of the macro, this method is invoked to read all of the
/// actual arguments specified for the macro invocation. This returns null on
/// error.
-MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
+MacroArgs *Preprocessor::ReadMacroCallArgumentList(Token &MacroName,
MacroInfo *MI,
SourceLocation &MacroEnd) {
// The number of fixed arguments to parse.
- unsigned NumFixedArgsLeft = MI->getNumArgs();
+ unsigned NumFixedArgsLeft = MI->getNumParams();
bool isVariadic = MI->isVariadic();
// Outer loop, while there are more arguments, keep reading them.
@@ -889,7 +889,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// Okay, we either found the r_paren. Check to see if we parsed too few
// arguments.
- unsigned MinArgsExpected = MI->getNumArgs();
+ unsigned MinArgsExpected = MI->getNumParams();
// If this is not a variadic macro, and too many args were specified, emit
// an error.
@@ -1125,6 +1125,7 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) {
.Case("attribute_overloadable", true)
.Case("attribute_unavailable_with_message", true)
.Case("attribute_unused_on_fields", true)
+ .Case("attribute_diagnose_if_objc", true)
.Case("blocks", LangOpts.Blocks)
.Case("c_thread_safety_attributes", true)
.Case("cxx_exceptions", LangOpts.CXXExceptions)
@@ -1314,6 +1315,8 @@ static bool HasExtension(const Preprocessor &PP, StringRef Extension) {
.Case("cxx_binary_literals", true)
.Case("cxx_init_captures", LangOpts.CPlusPlus11)
.Case("cxx_variable_templates", LangOpts.CPlusPlus)
+ // Miscellaneous language extensions
+ .Case("overloadable_unmarked", true)
.Default(false);
}
@@ -1422,7 +1425,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
const DirectoryLookup *CurDir;
const FileEntry *File =
PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile,
- CurDir, nullptr, nullptr, nullptr);
+ CurDir, nullptr, nullptr, nullptr, nullptr);
// Get the result value. A result of true means the file exists.
return File != nullptr;
@@ -1453,7 +1456,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?");
@@ -1746,6 +1749,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
return llvm::StringSwitch<bool>(II->getName())
.Case("__make_integer_seq", LangOpts.CPlusPlus)
.Case("__type_pack_element", LangOpts.CPlusPlus)
+ .Case("__builtin_available", true)
.Default(false);
}
});
diff --git a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp
index 100da51..bf2363a 100644
--- a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
@@ -160,12 +161,23 @@ public:
~LexingFor_PragmaRAII() {
if (InMacroArgPreExpansion) {
+ // When committing/backtracking the cached pragma tokens in a macro
+ // argument pre-expansion we want to ensure that either the tokens which
+ // have been committed will be removed from the cache or that the tokens
+ // over which we just backtracked won't remain in the cache after they're
+ // consumed and that the caching will stop after consuming them.
+ // Otherwise the caching will interfere with the way macro expansion
+ // works, because we will continue to cache tokens after consuming the
+ // backtracked tokens, which shouldn't happen when we're dealing with
+ // macro argument pre-expansion.
+ auto CachedTokenRange = PP.LastCachedTokenRange();
if (Failed) {
PP.CommitBacktrackedTokens();
} else {
PP.Backtrack();
OutTok = PragmaTok;
}
+ PP.EraseCachedTokens(CachedTokenRange);
}
}
@@ -464,9 +476,9 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
// Emit a line marker. This will change any source locations from this point
// forward to realize they are in a system header.
// Create a line note with this information.
- SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine()+1,
+ SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine() + 1,
FilenameID, /*IsEntry=*/false, /*IsExit=*/false,
- /*IsSystem=*/true, /*IsExternC=*/false);
+ SrcMgr::C_System);
}
/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
@@ -497,7 +509,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
const DirectoryLookup *CurDir;
const FileEntry *File =
LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
- nullptr, CurDir, nullptr, nullptr, nullptr);
+ nullptr, CurDir, nullptr, nullptr, nullptr, nullptr);
if (!File) {
if (!SuppressIncludeNotFoundError)
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
@@ -743,6 +755,125 @@ void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) {
getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName);
}
+// Lex a component of a module name: either an identifier or a string literal;
+// for components that can be expressed both ways, the two forms are equivalent.
+static bool LexModuleNameComponent(
+ Preprocessor &PP, Token &Tok,
+ std::pair<IdentifierInfo *, SourceLocation> &ModuleNameComponent,
+ bool First) {
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) {
+ StringLiteralParser Literal(Tok, PP);
+ if (Literal.hadError)
+ return true;
+ ModuleNameComponent = std::make_pair(
+ PP.getIdentifierInfo(Literal.GetString()), Tok.getLocation());
+ } else if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) {
+ ModuleNameComponent =
+ std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation());
+ } else {
+ PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << First;
+ return true;
+ }
+ return false;
+}
+
+static bool LexModuleName(
+ Preprocessor &PP, Token &Tok,
+ llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
+ &ModuleName) {
+ while (true) {
+ std::pair<IdentifierInfo*, SourceLocation> NameComponent;
+ if (LexModuleNameComponent(PP, Tok, NameComponent, ModuleName.empty()))
+ return true;
+ ModuleName.push_back(NameComponent);
+
+ PP.LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::period))
+ return false;
+ }
+}
+
+void Preprocessor::HandlePragmaModuleBuild(Token &Tok) {
+ SourceLocation Loc = Tok.getLocation();
+
+ std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
+ if (LexModuleNameComponent(*this, Tok, ModuleNameLoc, true))
+ return;
+ IdentifierInfo *ModuleName = ModuleNameLoc.first;
+
+ LexUnexpandedToken(Tok);
+ if (Tok.isNot(tok::eod)) {
+ Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
+ DiscardUntilEndOfDirective();
+ }
+
+ if (CurPTHLexer) {
+ // FIXME: Support this somehow?
+ Diag(Loc, diag::err_pp_module_build_pth);
+ return;
+ }
+
+ CurLexer->LexingRawMode = true;
+
+ auto TryConsumeIdentifier = [&](StringRef Ident) -> bool {
+ if (Tok.getKind() != tok::raw_identifier ||
+ Tok.getRawIdentifier() != Ident)
+ return false;
+ CurLexer->Lex(Tok);
+ return true;
+ };
+
+ // Scan forward looking for the end of the module.
+ const char *Start = CurLexer->getBufferLocation();
+ const char *End = nullptr;
+ unsigned NestingLevel = 1;
+ while (true) {
+ End = CurLexer->getBufferLocation();
+ CurLexer->Lex(Tok);
+
+ if (Tok.is(tok::eof)) {
+ Diag(Loc, diag::err_pp_module_build_missing_end);
+ break;
+ }
+
+ if (Tok.isNot(tok::hash) || !Tok.isAtStartOfLine()) {
+ // Token was part of module; keep going.
+ continue;
+ }
+
+ // We hit something directive-shaped; check to see if this is the end
+ // of the module build.
+ CurLexer->ParsingPreprocessorDirective = true;
+ CurLexer->Lex(Tok);
+ if (TryConsumeIdentifier("pragma") && TryConsumeIdentifier("clang") &&
+ TryConsumeIdentifier("module")) {
+ if (TryConsumeIdentifier("build"))
+ // #pragma clang module build -> entering a nested module build.
+ ++NestingLevel;
+ else if (TryConsumeIdentifier("endbuild")) {
+ // #pragma clang module endbuild -> leaving a module build.
+ if (--NestingLevel == 0)
+ break;
+ }
+ // We should either be looking at the EOD or more of the current directive
+ // preceding the EOD. Either way we can ignore this token and keep going.
+ assert(Tok.getKind() != tok::eof && "missing EOD before EOF");
+ }
+ }
+
+ CurLexer->LexingRawMode = false;
+
+ // Load the extracted text as a preprocessed module.
+ assert(CurLexer->getBuffer().begin() <= Start &&
+ Start <= CurLexer->getBuffer().end() &&
+ CurLexer->getBuffer().begin() <= End &&
+ End <= CurLexer->getBuffer().end() &&
+ "module source range not contained within same file buffer");
+ TheModuleLoader.loadModuleFromSource(Loc, ModuleName->getName(),
+ StringRef(Start, End - Start));
+}
+
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
/// If 'Namespace' is non-null, then it is a token required to exist on the
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
@@ -978,9 +1109,9 @@ struct PragmaDebugHandler : public PragmaHandler {
#ifdef _MSC_VER
#pragma warning(disable : 4717)
#endif
- static void DebugOverflowStack() {
- void (*volatile Self)() = DebugOverflowStack;
- Self();
+ static void DebugOverflowStack(void (*P)() = nullptr) {
+ void (*volatile Self)(void(*P)()) = DebugOverflowStack;
+ Self(reinterpret_cast<void(*)()>(Self));
}
#ifdef _MSC_VER
#pragma warning(default : 4717)
@@ -1290,6 +1421,160 @@ public:
}
};
+/// Handle the clang \#pragma module import extension. The syntax is:
+/// \code
+/// #pragma clang module import some.module.name
+/// \endcode
+struct PragmaModuleImportHandler : public PragmaHandler {
+ PragmaModuleImportHandler() : PragmaHandler("import") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ 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().lookupModule(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;
+ }
+
+ // If the module isn't available, it doesn't make sense to enter it.
+ if (Preprocessor::checkModuleIsAvailable(
+ PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics(), M)) {
+ PP.Diag(BeginLoc, diag::note_pp_module_begin_here)
+ << M->getTopLevelModuleName();
+ return;
+ }
+
+ // 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);
+ }
+};
+
+/// Handle the clang \#pragma module build extension.
+struct PragmaModuleBuildHandler : public PragmaHandler {
+ PragmaModuleBuildHandler() : PragmaHandler("build") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ PP.HandlePragmaModuleBuild(Tok);
+ }
+};
+
+/// Handle the clang \#pragma module load extension.
+struct PragmaModuleLoadHandler : public PragmaHandler {
+ PragmaModuleLoadHandler() : PragmaHandler("load") {}
+
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
+ SourceLocation Loc = 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";
+
+ // Load the module, don't make it visible.
+ PP.getModuleLoader().loadModule(Loc, ModuleName, Module::Hidden,
+ /*IsIncludeDirective=*/false);
+ }
+};
+
/// PragmaPushMacroHandler - "\#pragma push_macro" saves the value of the
/// macro on the top of the stack.
struct PragmaPushMacroHandler : public PragmaHandler {
@@ -1513,6 +1798,15 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler());
AddPragmaHandler("clang", new PragmaAssumeNonNullHandler());
+ // #pragma clang module ...
+ auto *ModuleHandler = new PragmaNamespace("module");
+ AddPragmaHandler("clang", ModuleHandler);
+ ModuleHandler->AddPragma(new PragmaModuleImportHandler());
+ ModuleHandler->AddPragma(new PragmaModuleBeginHandler());
+ ModuleHandler->AddPragma(new PragmaModuleEndHandler());
+ ModuleHandler->AddPragma(new PragmaModuleBuildHandler());
+ ModuleHandler->AddPragma(new PragmaModuleLoadHandler());
+
AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
AddPragmaHandler("STDC", new PragmaSTDC_UnknownHandler());
diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp
index 13e15f3..03c4cbe 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp
@@ -422,7 +422,8 @@ void PreprocessingRecord::MacroDefined(const Token &Id,
}
void PreprocessingRecord::MacroUndefined(const Token &Id,
- const MacroDefinition &MD) {
+ const MacroDefinition &MD,
+ const MacroDirective *Undef) {
MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); });
}
diff --git a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp
index 91319be..7979be7 100644
--- a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp
@@ -70,25 +70,25 @@ ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts,
- SourceManager &SM, HeaderSearch &Headers,
- ModuleLoader &TheModuleLoader,
+ SourceManager &SM, MemoryBufferCache &PCMCache,
+ HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup, bool OwnsHeaders,
TranslationUnitKind TUKind)
: PPOpts(std::move(PPOpts)), Diags(&diags), LangOpts(opts), Target(nullptr),
AuxTarget(nullptr), FileMgr(Headers.getFileMgr()), SourceMgr(SM),
- ScratchBuf(new ScratchBuffer(SourceMgr)), HeaderInfo(Headers),
- TheModuleLoader(TheModuleLoader), ExternalSource(nullptr),
- Identifiers(opts, IILookup),
+ PCMCache(PCMCache), ScratchBuf(new ScratchBuffer(SourceMgr)),
+ HeaderInfo(Headers), TheModuleLoader(TheModuleLoader),
+ ExternalSource(nullptr), Identifiers(opts, IILookup),
PragmaHandlers(new PragmaNamespace(StringRef())),
IncrementalProcessing(false), TUKind(TUKind), CodeComplete(nullptr),
CodeCompletionFile(nullptr), CodeCompletionOffset(0),
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) {
OwnsHeaderSearch = OwnsHeaders;
CounterValue = 0; // __COUNTER__ starts at 0.
@@ -150,6 +150,9 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
Ident_GetExceptionInfo = Ident_GetExceptionCode = nullptr;
Ident_AbnormalTermination = nullptr;
}
+
+ if (this->PPOpts->GeneratePreamble)
+ PreambleConditionalStack.startRecording();
}
Preprocessor::~Preprocessor() {
@@ -169,11 +172,6 @@ Preprocessor::~Preprocessor() {
std::fill(TokenLexerCache, TokenLexerCache + NumCachedTokenLexers, nullptr);
CurTokenLexer.reset();
- while (DeserializedMacroInfoChain *I = DeserialMIChainHead) {
- DeserialMIChainHead = I->Next;
- I->~DeserializedMacroInfoChain();
- }
-
// Free any cached MacroArgs.
for (MacroArgs *ArgList = MacroArgCache; ArgList;)
ArgList = ArgList->deallocate();
@@ -539,6 +537,16 @@ void Preprocessor::EnterMainSourceFile() {
EnterSourceFile(FID, nullptr, SourceLocation());
}
+void Preprocessor::replayPreambleConditionalStack() {
+ // Restore the conditional stack from the preamble, if there is one.
+ if (PreambleConditionalStack.isReplaying()) {
+ assert(CurPPLexer &&
+ "CurPPLexer is null when calling replayPreambleConditionalStack.");
+ CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack());
+ PreambleConditionalStack.doneReplaying();
+ }
+}
+
void Preprocessor::EndSourceFile() {
// Notify the client that we reached the end of the source file.
if (Callbacks)
@@ -576,7 +584,11 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
// Update the token info (identifier info and appropriate token kind).
Identifier.setIdentifierInfo(II);
- Identifier.setKind(II->getTokenID());
+ if (getLangOpts().MSVCCompat && II->isCPlusPlusOperatorKeyword() &&
+ getSourceManager().isInSystemHeader(Identifier.getLocation()))
+ Identifier.setKind(clang::tok::identifier);
+ else
+ Identifier.setKind(II->getTokenID());
return II;
}
@@ -702,12 +714,6 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
II.setIsFutureCompatKeyword(false);
}
- // C++ 2.11p2: If this is an alternative representation of a C++ operator,
- // then we act as if it is the actual operator and not the textual
- // representation of it.
- if (II.isCPlusPlusOperatorKeyword())
- Identifier.setIdentifierInfo(nullptr);
-
// If this is an extension token, diagnose its use.
// We avoid diagnosing tokens that originate from macro definitions.
// FIXME: This warning is disabled in cases where it shouldn't be,
diff --git a/contrib/llvm/tools/clang/lib/Lex/ScratchBuffer.cpp b/contrib/llvm/tools/clang/lib/Lex/ScratchBuffer.cpp
index cd8a27e..e0f3966 100644
--- a/contrib/llvm/tools/clang/lib/Lex/ScratchBuffer.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/ScratchBuffer.cpp
@@ -35,6 +35,14 @@ SourceLocation ScratchBuffer::getToken(const char *Buf, unsigned Len,
const char *&DestPtr) {
if (BytesUsed+Len+2 > ScratchBufSize)
AllocScratchBuffer(Len+2);
+ else {
+ // Clear out the source line cache if it's already been computed.
+ // FIXME: Allow this to be incrementally extended.
+ auto *ContentCache = const_cast<SrcMgr::ContentCache *>(
+ SourceMgr.getSLocEntry(SourceMgr.getFileID(BufferStartLoc))
+ .getFile().getContentCache());
+ ContentCache->SourceLineCache = nullptr;
+ }
// Prefix the token with a \n, so that it looks like it is the first thing on
// its own virtual line in caret diagnostics.
diff --git a/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp
index a53c801..c2e49ba 100644
--- a/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp
+++ b/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp
@@ -67,7 +67,7 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI,
// If this is a function-like macro, expand the arguments and change
// Tokens to point to the expanded tokens.
- if (Macro->isFunctionLike() && Macro->getNumArgs())
+ if (Macro->isFunctionLike() && Macro->getNumParams())
ExpandFunctionArguments();
// Mark the macro as currently disabled, so that it is not recursively
@@ -122,7 +122,7 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
SmallVectorImpl<Token> &ResultToks, bool HasPasteOperator, MacroInfo *Macro,
unsigned MacroArgNo, Preprocessor &PP) {
// Is the macro argument __VA_ARGS__?
- if (!Macro->isVariadic() || MacroArgNo != Macro->getNumArgs()-1)
+ if (!Macro->isVariadic() || MacroArgNo != Macro->getNumParams()-1)
return false;
// In Microsoft-compatibility mode, a comma is removed in the expansion
@@ -137,7 +137,7 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
// with GNU extensions, it is removed regardless of named arguments.
// Microsoft also appears to support this extension, unofficially.
if (PP.getLangOpts().C99 && !PP.getLangOpts().GNUMode
- && Macro->getNumArgs() < 2)
+ && Macro->getNumParams() < 2)
return false;
// Is a comma available to be removed?
@@ -183,11 +183,17 @@ 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;
if (CurTok.isOneOf(tok::hash, tok::hashat)) {
- int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo());
+ int ArgNo = Macro->getParameterNum(Tokens[i+1].getIdentifierInfo());
assert(ArgNo != -1 && "Token following # is not an argument?");
SourceLocation ExpansionLocStart =
@@ -231,7 +237,7 @@ void TokenLexer::ExpandFunctionArguments() {
// Otherwise, if this is not an argument token, just add the token to the
// output buffer.
IdentifierInfo *II = CurTok.getIdentifierInfo();
- int ArgNo = II ? Macro->getArgumentNum(II) : -1;
+ int ArgNo = II ? Macro->getParameterNum(II) : -1;
if (ArgNo == -1) {
// This isn't an argument, just add it.
ResultToks.push_back(CurTok);
@@ -317,14 +323,16 @@ 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__
// expansion.
if (NonEmptyPasteBefore && ResultToks.size() >= 2 &&
ResultToks[ResultToks.size()-2].is(tok::comma) &&
- (unsigned)ArgNo == Macro->getNumArgs()-1 &&
+ (unsigned)ArgNo == Macro->getNumParams()-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/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp
index c52b61e..27651c9 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "RAIIObjectsForParser.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
using namespace clang;
@@ -166,20 +166,11 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
}
if (FnD) {
- // If this is a friend function, mark that it's late-parsed so that
- // it's still known to be a definition even before we attach the
- // parsed body. Sema needs to treat friend function definitions
- // differently during template instantiation, and it's possible for
- // the containing class to be instantiated before all its member
- // function definitions are parsed.
- //
- // If you remove this, you can remove the code that clears the flag
- // after parsing the member.
- if (D.getDeclSpec().isFriendSpecified()) {
- FunctionDecl *FD = FnD->getAsFunction();
- Actions.CheckForFunctionRedefinition(FD);
- FD->setLateTemplateParsed(true);
- }
+ FunctionDecl *FD = FnD->getAsFunction();
+ // Track that this function will eventually have a body; Sema needs
+ // to know this.
+ Actions.CheckForFunctionRedefinition(FD);
+ FD->setWillHaveBody(true);
} else {
// If semantic analysis could not build a function declaration,
// just throw away the late-parsed declaration.
@@ -344,9 +335,9 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// The argument isn't actually potentially evaluated unless it is
// used.
- EnterExpressionEvaluationContext Eval(Actions,
- Sema::PotentiallyEvaluatedIfUsed,
- Param);
+ EnterExpressionEvaluationContext Eval(
+ Actions,
+ Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, Param);
ExprResult DefArgResult;
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
@@ -558,10 +549,6 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
ParseFunctionStatementBody(LM.D, FnScope);
- // Clear the late-template-parsed bit if we set it before.
- if (LM.D)
- LM.D->getAsFunction()->setLateTemplateParsed(false);
-
while (Tok.isNot(tok::eof))
ConsumeAnyToken();
@@ -731,19 +718,6 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
ConsumeBrace();
break;
- case tok::code_completion:
- Toks.push_back(Tok);
- ConsumeCodeCompletionToken();
- break;
-
- case tok::string_literal:
- case tok::wide_string_literal:
- case tok::utf8_string_literal:
- case tok::utf16_string_literal:
- case tok::utf32_string_literal:
- Toks.push_back(Tok);
- ConsumeStringToken();
- break;
case tok::semi:
if (StopAtSemi)
return false;
@@ -751,7 +725,7 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
default:
// consume this token.
Toks.push_back(Tok);
- ConsumeToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok*/true);
break;
}
isFirstTokenConsumed = false;
@@ -902,7 +876,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
// If the opening brace is not preceded by one of these tokens, we are
// missing the mem-initializer-id. In order to recover better, we need
// to use heuristics to determine if this '{' is most likely the
- // begining of a brace-init-list or the function body.
+ // beginning of a brace-init-list or the function body.
// Check the token after the corresponding '}'.
TentativeParsingAction PA(*this);
if (SkipUntil(tok::r_brace) &&
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp
index 2d32087..a461069 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "RAIIObjectsForParser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/AddressSpaces.h"
@@ -71,11 +71,18 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
}
+/// \brief Normalizes an attribute name by dropping prefixed and suffixed __.
+static StringRef normalizeAttrName(StringRef Name) {
+ if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
+ return Name.drop_front(2).drop_back(2);
+ return Name;
+}
+
/// isAttributeLateParsed - Return true if the attribute has arguments that
/// require late parsing.
static bool isAttributeLateParsed(const IdentifierInfo &II) {
#define CLANG_ATTR_LATE_PARSED_LIST
- return llvm::StringSwitch<bool>(II.getName())
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
#undef CLANG_ATTR_LATE_PARSED_LIST
@@ -200,13 +207,6 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
}
}
-/// \brief Normalizes an attribute name by dropping prefixed and suffixed __.
-static StringRef normalizeAttrName(StringRef Name) {
- if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
- Name = Name.drop_front(2).drop_back(2);
- return Name;
-}
-
/// \brief Determine whether the given attribute has an identifier argument.
static bool attributeHasIdentifierArg(const IdentifierInfo &II) {
#define CLANG_ATTR_IDENTIFIER_ARG_LIST
@@ -308,7 +308,9 @@ unsigned Parser::ParseAttributeArgsCommon(
do {
bool Uneval = attributeParsedArgsUnevaluated(*AttrName);
EnterExpressionEvaluationContext Unevaluated(
- Actions, Uneval ? Sema::Unevaluated : Sema::ConstantEvaluated,
+ Actions,
+ Uneval ? Sema::ExpressionEvaluationContext::Unevaluated
+ : Sema::ExpressionEvaluationContext::ConstantEvaluated,
/*LambdaContextDecl=*/nullptr,
/*IsDecltype=*/false);
@@ -356,6 +358,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
ScopeLoc, Syntax);
return;
+ } else if (AttrKind == AttributeList::AT_ExternalSourceSymbol) {
+ ParseExternalSourceSymbolAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, Syntax);
+ return;
} else if (AttrKind == AttributeList::AT_ObjCBridgeRelated) {
ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, Syntax);
@@ -389,6 +395,25 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
ScopeLoc, Syntax);
}
+unsigned Parser::ParseClangAttributeArgs(
+ IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc, AttributeList::Syntax Syntax) {
+ assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
+
+ AttributeList::Kind AttrKind =
+ AttributeList::getKind(AttrName, ScopeName, Syntax);
+
+ if (AttrKind == AttributeList::AT_ExternalSourceSymbol) {
+ ParseExternalSourceSymbolAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, Syntax);
+ return Attrs.getList() ? Attrs.getList()->getNumArgs() : 0;
+ }
+
+ return ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, Syntax);
+}
+
bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs) {
@@ -1064,6 +1089,119 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
Syntax, StrictLoc, ReplacementExpr.get());
}
+/// \brief Parse the contents of the "external_source_symbol" attribute.
+///
+/// external-source-symbol-attribute:
+/// 'external_source_symbol' '(' keyword-arg-list ')'
+///
+/// keyword-arg-list:
+/// keyword-arg
+/// keyword-arg ',' keyword-arg-list
+///
+/// keyword-arg:
+/// 'language' '=' <string>
+/// 'defined_in' '=' <string>
+/// 'generated_declaration'
+void Parser::ParseExternalSourceSymbolAttribute(
+ IdentifierInfo &ExternalSourceSymbol, SourceLocation Loc,
+ ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc, AttributeList::Syntax Syntax) {
+ // Opening '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume())
+ return;
+
+ // Initialize the pointers for the keyword identifiers when required.
+ if (!Ident_language) {
+ Ident_language = PP.getIdentifierInfo("language");
+ Ident_defined_in = PP.getIdentifierInfo("defined_in");
+ Ident_generated_declaration = PP.getIdentifierInfo("generated_declaration");
+ }
+
+ ExprResult Language;
+ bool HasLanguage = false;
+ ExprResult DefinedInExpr;
+ bool HasDefinedIn = false;
+ IdentifierLoc *GeneratedDeclaration = nullptr;
+
+ // Parse the language/defined_in/generated_declaration keywords
+ do {
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_external_source_symbol_expected_keyword);
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+
+ SourceLocation KeywordLoc = Tok.getLocation();
+ IdentifierInfo *Keyword = Tok.getIdentifierInfo();
+ if (Keyword == Ident_generated_declaration) {
+ if (GeneratedDeclaration) {
+ Diag(Tok, diag::err_external_source_symbol_duplicate_clause) << Keyword;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ GeneratedDeclaration = ParseIdentifierLoc();
+ continue;
+ }
+
+ if (Keyword != Ident_language && Keyword != Ident_defined_in) {
+ Diag(Tok, diag::err_external_source_symbol_expected_keyword);
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+
+ ConsumeToken();
+ if (ExpectAndConsume(tok::equal, diag::err_expected_after,
+ Keyword->getName())) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+
+ bool HadLanguage = HasLanguage, HadDefinedIn = HasDefinedIn;
+ if (Keyword == Ident_language)
+ HasLanguage = true;
+ else
+ HasDefinedIn = true;
+
+ if (Tok.isNot(tok::string_literal)) {
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='external_source_symbol attribute'*/ 3
+ << /*language | source container*/ (Keyword != Ident_language);
+ SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
+ continue;
+ }
+ if (Keyword == Ident_language) {
+ if (HadLanguage) {
+ Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause)
+ << Keyword;
+ ParseStringLiteralExpression();
+ continue;
+ }
+ Language = ParseStringLiteralExpression();
+ } else {
+ assert(Keyword == Ident_defined_in && "Invalid clause keyword!");
+ if (HadDefinedIn) {
+ Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause)
+ << Keyword;
+ ParseStringLiteralExpression();
+ continue;
+ }
+ DefinedInExpr = ParseStringLiteralExpression();
+ }
+ } while (TryConsumeToken(tok::comma));
+
+ // Closing ')'.
+ if (T.consumeClose())
+ return;
+ if (EndLoc)
+ *EndLoc = T.getCloseLocation();
+
+ ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(),
+ GeneratedDeclaration};
+ Attrs.addNew(&ExternalSourceSymbol, SourceRange(Loc, T.getCloseLocation()),
+ ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax);
+}
+
/// \brief Parse the contents of the "objc_bridge_related" attribute.
/// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')'
/// related_class:
@@ -2414,6 +2552,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
}
}
// Fall through.
+ LLVM_FALLTHROUGH;
}
case tok::comma:
case tok::equal:
@@ -2439,9 +2578,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// and attempt to recover.
ParsedType T;
IdentifierInfo *II = Tok.getIdentifierInfo();
+ bool IsTemplateName = getLangOpts().CPlusPlus && NextToken().is(tok::less);
Actions.DiagnoseUnknownTypeName(II, Loc, getCurScope(), SS, T,
- getLangOpts().CPlusPlus &&
- NextToken().is(tok::less));
+ IsTemplateName);
if (T) {
// The action has suggested that the type T could be used. Set that as
// the type in the declaration specifiers, consume the would-be type
@@ -2466,6 +2605,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken();
+ // Eat any following template arguments.
+ if (IsTemplateName) {
+ SourceLocation LAngle, RAngle;
+ TemplateArgList Args;
+ ParseTemplateIdAfterTemplateName(true, LAngle, Args, RAngle);
+ }
+
// TODO: Could inject an invalid typedef decl in an enclosing scope to
// avoid rippling error messages on subsequent uses of the same type,
// could be useful if #include was forgotten.
@@ -2483,6 +2629,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
return DSC_class;
if (Context == Declarator::FileContext)
return DSC_top_level;
+ if (Context == Declarator::TemplateParamContext)
+ return DSC_template_param;
if (Context == Declarator::TemplateTypeArgContext)
return DSC_template_type_arg;
if (Context == Declarator::TrailingReturnContext)
@@ -2824,48 +2972,27 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
->Kind == TNK_Type_template) {
// We have a qualified template-id, e.g., N::A<int>
- // C++ [class.qual]p2:
- // In a lookup in which the constructor is an acceptable lookup
- // result and the nested-name-specifier nominates a class C:
- //
- // - if the name specified after the
- // nested-name-specifier, when looked up in C, is the
- // injected-class-name of C (Clause 9), or
- //
- // - if the name specified after the nested-name-specifier
- // is the same as the identifier or the
- // simple-template-id's template-name in the last
- // component of the nested-name-specifier,
+ // If this would be a valid constructor declaration with template
+ // arguments, we will reject the attempt to form an invalid type-id
+ // referring to the injected-class-name when we annotate the token,
+ // per C++ [class.qual]p2.
//
- // the name is instead considered to name the constructor of
- // class C.
- //
- // Thus, if the template-name is actually the constructor
- // name, then the code is ill-formed; this interpretation is
- // reinforced by the NAD status of core issue 635.
+ // To improve diagnostics for this case, parse the declaration as a
+ // constructor (and reject the extra template arguments later).
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
TemplateId->Name &&
- Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
- if (isConstructorDeclarator(/*Unqualified*/false)) {
- // The user meant this to be an out-of-line constructor
- // definition, but template arguments are not allowed
- // there. Just allow this as a constructor; we'll
- // complain about it later.
- goto DoneWithDeclSpec;
- }
-
- // The user meant this to name a type, but it actually names
- // a constructor with some extraneous template
- // arguments. Complain, then parse it as a type as the user
- // intended.
- Diag(TemplateId->TemplateNameLoc,
- diag::err_out_of_line_template_id_type_names_constructor)
- << TemplateId->Name << 0 /* template name */;
+ Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) &&
+ isConstructorDeclarator(/*Unqualified*/false)) {
+ // The user meant this to be an out-of-line constructor
+ // definition, but template arguments are not allowed
+ // there. Just allow this as a constructor; we'll
+ // complain about it later.
+ goto DoneWithDeclSpec;
}
DS.getTypeSpecScope() = SS;
- ConsumeToken(); // The C++ scope.
+ ConsumeAnnotationToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
AnnotateTemplateIdTokenAsType();
@@ -2874,7 +3001,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (Next.is(tok::annot_typename)) {
DS.getTypeSpecScope() = SS;
- ConsumeToken(); // The C++ scope.
+ ConsumeAnnotationToken(); // The C++ scope.
if (Tok.getAnnotationValue()) {
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
@@ -2886,43 +3013,35 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
else
DS.SetTypeSpecError();
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
- ConsumeToken(); // The typename
+ ConsumeAnnotationToken(); // The typename
}
if (Next.isNot(tok::identifier))
goto DoneWithDeclSpec;
- // If we're in a context where the identifier could be a class name,
- // check whether this is a constructor declaration.
+ // Check whether this is a constructor declaration. If we're in a
+ // context where the identifier could be a class name, and it has the
+ // shape of a constructor declaration, process it as one.
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
- &SS)) {
- if (isConstructorDeclarator(/*Unqualified*/false))
- goto DoneWithDeclSpec;
-
- // As noted in C++ [class.qual]p2 (cited above), when the name
- // of the class is qualified in a context where it could name
- // a constructor, its a constructor name. However, we've
- // looked at the declarator, and the user probably meant this
- // to be a type. Complain that it isn't supposed to be treated
- // as a type, then proceed to parse it as a type.
- Diag(Next.getLocation(),
- diag::err_out_of_line_template_id_type_names_constructor)
- << Next.getIdentifierInfo() << 1 /* type */;
- }
+ &SS) &&
+ isConstructorDeclarator(/*Unqualified*/ false))
+ goto DoneWithDeclSpec;
ParsedType TypeRep =
Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(),
getCurScope(), &SS, false, false, nullptr,
/*IsCtorOrDtorName=*/false,
- /*NonTrivialSourceInfo=*/true);
+ /*WantNonTrivialSourceInfo=*/true,
+ isClassTemplateDeductionContext(DSContext));
// If the referenced identifier is not a type, then this declspec is
// erroneous: We already checked about that it has no type specifier, and
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
// typename.
if (!TypeRep) {
- ConsumeToken(); // Eat the scope spec so the identifier is current.
+ // Eat the scope spec so the identifier is current.
+ ConsumeAnnotationToken();
ParsedAttributesWithRange Attrs(AttrFactory);
if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
@@ -2935,7 +3054,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
DS.getTypeSpecScope() = SS;
- ConsumeToken(); // The C++ scope.
+ ConsumeAnnotationToken(); // The C++ scope.
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, TypeRep, Policy);
@@ -2965,7 +3084,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
- ConsumeToken(); // The typename
+ ConsumeAnnotationToken(); // The typename
continue;
}
@@ -2996,6 +3115,31 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DS.hasTypeSpecifier())
goto DoneWithDeclSpec;
+ // If the token is an identifier named "__declspec" and Microsoft
+ // extensions are not enabled, it is likely that there will be cascading
+ // parse errors if this really is a __declspec attribute. Attempt to
+ // recognize that scenario and recover gracefully.
+ if (!getLangOpts().DeclSpecKeyword && Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo()->getName().equals("__declspec")) {
+ Diag(Loc, diag::err_ms_attributes_not_enabled);
+
+ // The next token should be an open paren. If it is, eat the entire
+ // attribute declaration and continue.
+ if (NextToken().is(tok::l_paren)) {
+ // Consume the __declspec identifier.
+ ConsumeToken();
+
+ // Eat the parens and everything between them.
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
+ assert(false && "Not a left paren?");
+ return;
+ }
+ T.skipToEnd();
+ continue;
+ }
+ }
+
// In C++, check to see if this is a scope specifier like foo::bar::, if
// so handle it as such. This is important for ctor parsing.
if (getLangOpts().CPlusPlus) {
@@ -3029,9 +3173,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
}
- ParsedType TypeRep =
- Actions.getTypeName(*Tok.getIdentifierInfo(),
- Tok.getLocation(), getCurScope());
+ ParsedType TypeRep = Actions.getTypeName(
+ *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr,
+ false, false, nullptr, false, false,
+ isClassTemplateDeductionContext(DSContext));
// If this is not a typedef name, don't parse it as part of the declspec,
// it must be an implicit int or an error.
@@ -3054,6 +3199,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isConstructorDeclarator(/*Unqualified*/true))
goto DoneWithDeclSpec;
+ // Likewise, if this is a context where the identifier could be a template
+ // name, check whether this is a deduction guide declaration.
+ if (getLangOpts().CPlusPlus1z &&
+ (DSContext == DSC_class || DSContext == DSC_top_level) &&
+ Actions.isDeductionGuideName(getCurScope(), *Tok.getIdentifierInfo(),
+ Tok.getLocation()) &&
+ isConstructorDeclarator(/*Unqualified*/ true,
+ /*DeductionGuide*/ true))
+ goto DoneWithDeclSpec;
+
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
DiagID, TypeRep, Policy);
if (isInvalid)
@@ -3526,6 +3681,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = true;
break;
};
+ LLVM_FALLTHROUGH;
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -3951,8 +4107,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// anything that's a simple-type-specifier followed by '(' as an
// expression. This suffices because function types are not valid
// underlying types anyway.
- EnterExpressionEvaluationContext Unevaluated(Actions,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind());
// If the next token starts an expression, we know we're parsing a
// bit-field. This is the common case.
@@ -4107,7 +4263,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
AS, DS.getModulePrivateSpecLoc(), TParams,
Owned, IsDependent, ScopedEnumKWLoc,
IsScopedUsingClassTag, BaseType,
- DSC == DSC_type_specifier, &SkipBody);
+ DSC == DSC_type_specifier,
+ DSC == DSC_template_param ||
+ DSC == DSC_template_type_arg, &SkipBody);
if (SkipBody.ShouldSkip) {
assert(TUK == Sema::TUK_Definition && "can only skip a definition");
@@ -4161,8 +4319,15 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
}
- if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference)
- ParseEnumBody(StartLoc, TagDecl);
+ if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
+ Decl *D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagDecl;
+ ParseEnumBody(StartLoc, D);
+ if (SkipBody.CheckSameAsPrevious &&
+ !Actions.ActOnDuplicateDefinition(DS, TagDecl, SkipBody)) {
+ DS.SetTypeSpecError();
+ return;
+ }
+ }
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
@@ -4234,11 +4399,9 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
}
// Install the enumerator constant into EnumDecl.
- Decl *EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl,
- LastEnumConstDecl,
- IdentLoc, Ident,
- attrs.getList(), EqualLoc,
- AssignedVal.get());
+ Decl *EnumConstDecl = Actions.ActOnEnumConstant(
+ getCurScope(), EnumDecl, LastEnumConstDecl, IdentLoc, Ident,
+ attrs.getList(), EqualLoc, AssignedVal.get());
EnumAvailabilityDiags.back().done();
EnumConstantDecls.push_back(EnumConstDecl);
@@ -4673,7 +4836,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
}
}
-bool Parser::isConstructorDeclarator(bool IsUnqualified) {
+bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
TentativeParsingAction TPA(*this);
// Parse the C++ scope specifier.
@@ -4685,15 +4848,21 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) {
}
// Parse the constructor name.
- if (Tok.isOneOf(tok::identifier, tok::annot_template_id)) {
+ if (Tok.is(tok::identifier)) {
// We already know that we have a constructor name; just consume
// the token.
ConsumeToken();
+ } else if (Tok.is(tok::annot_template_id)) {
+ ConsumeAnnotationToken();
} else {
TPA.Revert();
return false;
}
+ // There may be attributes here, appertaining to the constructor name or type
+ // we just stepped past.
+ SkipCXX11Attributes();
+
// Current class name must be followed by a left parenthesis.
if (Tok.isNot(tok::l_paren)) {
TPA.Revert();
@@ -4740,7 +4909,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) {
// be a constructor declaration with an invalid argument type. Keep
// looking.
if (Tok.is(tok::annot_cxxscope))
- ConsumeToken();
+ ConsumeAnnotationToken();
ConsumeToken();
// If this is not a constructor, we must be parsing a declarator,
@@ -4761,13 +4930,24 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) {
case tok::r_paren:
// C(X )
- if (NextToken().is(tok::colon) || NextToken().is(tok::kw_try)) {
+
+ // Skip past the right-paren and any following attributes to get to
+ // the function body or trailing-return-type.
+ ConsumeParen();
+ SkipCXX11Attributes();
+
+ if (DeductionGuide) {
+ // C(X) -> ... is a deduction guide.
+ IsConstructor = Tok.is(tok::arrow);
+ break;
+ }
+ if (Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
// Assume these were meant to be constructors:
// C(X) : (the name of a bit-field cannot be parenthesized).
// C(X) try (this is otherwise ill-formed).
IsConstructor = true;
}
- if (NextToken().is(tok::semi) || NextToken().is(tok::l_brace)) {
+ if (Tok.is(tok::semi) || Tok.is(tok::l_brace)) {
// If we have a constructor name within the class definition,
// assume these were meant to be constructors:
// C(X) {
@@ -4778,7 +4958,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) {
//
// FIXME: We can actually do this whether or not the name is qualified,
// because if it is qualified in this context it must be being used as
- // a constructor name. However, we do not implement that rule correctly
+ // a constructor name.
// currently, so we're somewhat conservative here.
IsConstructor = IsUnqualified;
}
@@ -4806,9 +4986,10 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) {
/// [ only if AttReqs & AR_CXX11AttributesParsed ]
/// Note: vendor can be GNU, MS, etc and can be explicitly controlled via
/// AttrRequirements bitmask values.
-void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs,
- bool AtomicAllowed,
- bool IdentifierRequired) {
+void Parser::ParseTypeQualifierListOpt(
+ DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed,
+ bool IdentifierRequired,
+ Optional<llvm::function_ref<void()>> CodeCompletionHandler) {
if (getLangOpts().CPlusPlus11 && (AttrReqs & AR_CXX11AttributesParsed) &&
isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
@@ -4826,7 +5007,10 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs,
switch (Tok.getKind()) {
case tok::code_completion:
- Actions.CodeCompleteTypeQualifiers(DS);
+ if (CodeCompletionHandler)
+ (*CodeCompletionHandler)();
+ else
+ Actions.CodeCompleteTypeQualifiers(DS);
return cutOffParsing();
case tok::kw_const:
@@ -4872,6 +5056,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs,
if (TryKeywordIdentFallback(false))
continue;
}
+ LLVM_FALLTHROUGH;
case tok::kw___sptr:
case tok::kw___w64:
case tok::kw___ptr64:
@@ -4921,6 +5106,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs,
continue; // do *not* consume the next token!
}
// otherwise, FALL THROUGH!
+ LLVM_FALLTHROUGH;
default:
DoneWithTypeQuals:
// If this is not a type-qualifier token, we're done reading type
@@ -5309,21 +5495,29 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// We found something that indicates the start of an unqualified-id.
// Parse that unqualified-id.
bool AllowConstructorName;
- if (D.getDeclSpec().hasTypeSpecifier())
+ bool AllowDeductionGuide;
+ if (D.getDeclSpec().hasTypeSpecifier()) {
AllowConstructorName = false;
- else if (D.getCXXScopeSpec().isSet())
+ AllowDeductionGuide = false;
+ } else if (D.getCXXScopeSpec().isSet()) {
AllowConstructorName =
(D.getContext() == Declarator::FileContext ||
D.getContext() == Declarator::MemberContext);
- else
+ AllowDeductionGuide = false;
+ } else {
AllowConstructorName = (D.getContext() == Declarator::MemberContext);
+ AllowDeductionGuide =
+ (D.getContext() == Declarator::FileContext ||
+ D.getContext() == Declarator::MemberContext);
+ }
SourceLocation TemplateKWLoc;
bool HadScope = D.getCXXScopeSpec().isValid();
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
/*EnteringContext=*/true,
/*AllowDestructorName=*/true, AllowConstructorName,
- nullptr, TemplateKWLoc, D.getName()) ||
+ AllowDeductionGuide, nullptr, TemplateKWLoc,
+ D.getName()) ||
// Once we're past the identifier, if the scope was bad, mark the
// whole declarator bad.
D.getCXXScopeSpec().isInvalid()) {
@@ -5361,11 +5555,28 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
D.SetRangeEnd(Tok.getLocation());
ConsumeToken();
goto PastIdentifier;
- } else if (Tok.is(tok::identifier) && D.diagnoseIdentifier()) {
- // A virt-specifier isn't treated as an identifier if it appears after a
- // trailing-return-type.
- if (D.getContext() != Declarator::TrailingReturnContext ||
- !isCXX11VirtSpecifier(Tok)) {
+ } else if (Tok.is(tok::identifier) && !D.mayHaveIdentifier()) {
+ // We're not allowed an identifier here, but we got one. Try to figure out
+ // if the user was trying to attach a name to the type, or whether the name
+ // is some unrelated trailing syntax.
+ bool DiagnoseIdentifier = false;
+ if (D.hasGroupingParens())
+ // An identifier within parens is unlikely to be intended to be anything
+ // other than a name being "declared".
+ DiagnoseIdentifier = true;
+ else if (D.getContext() == Declarator::TemplateTypeArgContext)
+ // T<int N> is an accidental identifier; T<int N indicates a missing '>'.
+ DiagnoseIdentifier =
+ NextToken().isOneOf(tok::comma, tok::greater, tok::greatergreater);
+ else if (D.getContext() == Declarator::AliasDeclContext ||
+ D.getContext() == Declarator::AliasTemplateContext)
+ // The most likely error is that the ';' was forgotten.
+ DiagnoseIdentifier = NextToken().isOneOf(tok::comma, tok::semi);
+ else if (D.getContext() == Declarator::TrailingReturnContext &&
+ !isCXX11VirtSpecifier(Tok))
+ DiagnoseIdentifier = NextToken().isOneOf(
+ tok::comma, tok::semi, tok::equal, tok::l_brace, tok::kw_try);
+ if (DiagnoseIdentifier) {
Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id)
<< FixItHint::CreateRemoval(Tok.getLocation());
D.SetIdentifier(nullptr, Tok.getLocation());
@@ -5409,6 +5620,21 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (Tok.is(tok::l_square))
return ParseMisplacedBracketDeclarator(D);
if (D.getContext() == Declarator::MemberContext) {
+ // Objective-C++: Detect C++ keywords and try to prevent further errors by
+ // treating these keyword as valid member names.
+ if (getLangOpts().ObjC1 && getLangOpts().CPlusPlus &&
+ Tok.getIdentifierInfo() &&
+ Tok.getIdentifierInfo()->isCPlusPlusKeyword(getLangOpts())) {
+ Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
+ diag::err_expected_member_name_or_semi_objcxx_keyword)
+ << Tok.getIdentifierInfo()
+ << (D.getDeclSpec().isEmpty() ? SourceRange()
+ : D.getDeclSpec().getSourceRange());
+ D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+ D.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+ goto PastIdentifier;
+ }
Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
diag::err_expected_member_name_or_semi)
<< (D.getDeclSpec().isEmpty() ? SourceRange()
@@ -5744,7 +5970,11 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// Parse cv-qualifier-seq[opt].
ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed,
- /*AtomicAllowed*/ false);
+ /*AtomicAllowed*/ false,
+ /*IdentifierRequired=*/false,
+ llvm::function_ref<void()>([&]() {
+ Actions.CodeCompleteFunctionQualifiers(DS, D);
+ }));
if (!DS.getSourceRange().getEnd().isInvalid()) {
EndLoc = DS.getSourceRange().getEnd();
ConstQualifierLoc = DS.getConstSpecLoc();
@@ -6097,9 +6327,10 @@ void Parser::ParseParameterDeclarationClause(
// The argument isn't actually potentially evaluated unless it is
// used.
- EnterExpressionEvaluationContext Eval(Actions,
- Sema::PotentiallyEvaluatedIfUsed,
- Param);
+ EnterExpressionEvaluationContext Eval(
+ Actions,
+ Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed,
+ Param);
ExprResult DefArgResult;
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
@@ -6249,8 +6480,8 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
if (getLangOpts().CPlusPlus) {
NumElements = ParseConstantExpression();
} else {
- EnterExpressionEvaluationContext Unevaluated(Actions,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
NumElements =
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
}
@@ -6385,8 +6616,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const bool hasParens = Tok.is(tok::l_paren);
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
- Sema::ReuseLambdaContextDecl);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
bool isCastExpr;
ParsedType CastTy;
@@ -6418,7 +6650,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
return;
}
- // If we get here, the operand to the typeof was an expresion.
+ // If we get here, the operand to the typeof was an expression.
if (Operand.isInvalid()) {
DS.SetTypeSpecError();
return;
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp
index 3f1fe7e..2301284 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/Attributes.h"
@@ -20,6 +19,7 @@
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
@@ -266,15 +266,26 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false,
+ /*MayBePseudoDestructor=*/nullptr,
+ /*IsTypename=*/false,
+ /*LastII=*/nullptr,
+ /*OnlyNamespace=*/true);
- if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
+ if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_namespace_name);
// Skip to end of the definition and eat the ';'.
SkipUntil(tok::semi);
return nullptr;
}
+ if (SS.isInvalid()) {
+ // Diagnostics have been emitted in ParseOptionalCXXScopeSpecifier.
+ // Skip to end of the definition and eat the ';'.
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
+
// Parse identifier.
IdentifierInfo *Ident = Tok.getIdentifierInfo();
SourceLocation IdentLoc = ConsumeToken();
@@ -487,13 +498,17 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
+ ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false,
+ /*MayBePseudoDestructor=*/nullptr,
+ /*IsTypename=*/false,
+ /*LastII=*/nullptr,
+ /*OnlyNamespace=*/true);
IdentifierInfo *NamespcName = nullptr;
SourceLocation IdentLoc = SourceLocation();
// Parse namespace-name.
- if (SS.isInvalid() || Tok.isNot(tok::identifier)) {
+ if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_namespace_name);
// If there was invalid namespace name, skip to end of decl, and eat ';'.
SkipUntil(tok::semi);
@@ -501,6 +516,13 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
return nullptr;
}
+ if (SS.isInvalid()) {
+ // Diagnostics have been emitted in ParseOptionalCXXScopeSpecifier.
+ // Skip to end of the definition and eat the ';'.
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
+
// Parse identifier.
NamespcName = Tok.getIdentifierInfo();
IdentLoc = ConsumeToken();
@@ -576,6 +598,7 @@ bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) {
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
NextToken().is(tok::equal)),
+ /*AllowDeductionGuide=*/false,
nullptr, D.TemplateKWLoc, D.Name))
return true;
}
@@ -817,7 +840,9 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
return nullptr;
}
- ExprResult AssertExpr(ParseConstantExpression());
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ ExprResult AssertExpr(ParseConstantExpressionInExprEvalContext());
if (AssertExpr.isInvalid()) {
SkipMalformedDecl();
return nullptr;
@@ -878,7 +903,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
if (Tok.is(tok::annot_decltype)) {
Result = getExprAnnotation(Tok);
EndLoc = Tok.getAnnotationEndLoc();
- ConsumeToken();
+ ConsumeAnnotationToken();
if (Result.isInvalid()) {
DS.SetTypeSpecError();
return EndLoc;
@@ -912,8 +937,9 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
// C++11 [dcl.type.simple]p4:
// The operand of the decltype specifier is an unevaluated operand.
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
- nullptr,/*IsDecltype=*/true);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated, nullptr,
+ /*IsDecltype=*/true);
Result =
Actions.CorrectDelayedTyposInExpr(ParseExpression(), [](Expr *E) {
return E->hasPlaceholderType() ? ExprError() : E;
@@ -1076,12 +1102,12 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
- AnnotateTemplateIdTokenAsType();
+ AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
ParsedType Type = getTypeAnnotation(Tok);
EndLocation = Tok.getAnnotationEndLoc();
- ConsumeToken();
+ ConsumeAnnotationToken();
if (Type)
return Type;
@@ -1113,8 +1139,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
if (!Template) {
TemplateArgList TemplateArgs;
SourceLocation LAngleLoc, RAngleLoc;
- ParseTemplateIdAfterTemplateName(nullptr, IdLoc, SS, true, LAngleLoc,
- TemplateArgs, RAngleLoc);
+ ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs,
+ RAngleLoc);
return true;
}
@@ -1124,10 +1150,10 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// Parse the full template-id, then turn it into a type.
if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
- TemplateName, true))
+ TemplateName))
return true;
- if (TNK == TNK_Dependent_template_name)
- AnnotateTemplateIdTokenAsType();
+ if (TNK == TNK_Type_template || TNK == TNK_Dependent_template_name)
+ AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
// If we didn't end up with a typename token, there's nothing more we
// can do.
@@ -1138,16 +1164,17 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// return.
EndLocation = Tok.getAnnotationEndLoc();
ParsedType Type = getTypeAnnotation(Tok);
- ConsumeToken();
+ ConsumeAnnotationToken();
return Type;
}
// We have an identifier; check whether it is actually a type.
IdentifierInfo *CorrectedII = nullptr;
- ParsedType Type =
- Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, false, nullptr,
- /*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo=*/true, &CorrectedII);
+ ParsedType Type = Actions.getTypeName(
+ *Id, IdLoc, getCurScope(), &SS, /*IsClassName=*/true, false, nullptr,
+ /*IsCtorOrDtorName=*/false,
+ /*NonTrivialTypeSourceInfo=*/true,
+ /*IsClassTemplateDeductionContext*/ false, &CorrectedII);
if (!Type) {
Diag(IdLoc, diag::err_expected_class_name);
return true;
@@ -1381,6 +1408,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
!Tok.isAnnotation() &&
Tok.getIdentifierInfo() &&
Tok.isOneOf(tok::kw___is_abstract,
+ tok::kw___is_aggregate,
tok::kw___is_arithmetic,
tok::kw___is_array,
tok::kw___is_assignable,
@@ -1504,8 +1532,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// a class (or template thereof).
TemplateArgList TemplateArgs;
SourceLocation LAngleLoc, RAngleLoc;
- if (ParseTemplateIdAfterTemplateName(
- nullptr, NameLoc, SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) {
+ if (ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs,
+ RAngleLoc)) {
// We couldn't parse the template argument list at all, so don't
// try to give any location information for the list.
LAngleLoc = RAngleLoc = SourceLocation();
@@ -1539,7 +1567,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
} else if (Tok.is(tok::annot_template_id)) {
TemplateId = takeTemplateIdAnnotation(Tok);
- NameLoc = ConsumeToken();
+ NameLoc = ConsumeAnnotationToken();
if (TemplateId->Kind != TNK_Type_template &&
TemplateId->Kind != TNK_Dependent_template_name) {
@@ -1859,7 +1887,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation(), false,
clang::TypeResult(),
DSC == DSC_type_specifier,
- &SkipBody);
+ DSC == DSC_template_param ||
+ DSC == DSC_template_type_arg, &SkipBody);
// If ActOnTag said the type was dependent, try again with the
// less common call.
@@ -1881,10 +1910,24 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
else if (getLangOpts().CPlusPlus)
ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,
TagOrTempResult.get());
- else
- ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
+ else {
+ Decl *D =
+ SkipBody.CheckSameAsPrevious ? SkipBody.New : TagOrTempResult.get();
+ // Parse the definition body.
+ ParseStructUnionBody(StartLoc, TagType, D);
+ if (SkipBody.CheckSameAsPrevious &&
+ !Actions.ActOnDuplicateDefinition(DS, TagOrTempResult.get(),
+ SkipBody)) {
+ DS.SetTypeSpecError();
+ return;
+ }
+ }
}
+ if (!TagOrTempResult.isInvalid())
+ // Delayed processing of attributes.
+ Actions.ProcessDeclAttributeDelayed(TagOrTempResult.get(), attrs.getList());
+
const char *PrevSpec = nullptr;
unsigned DiagID;
bool Result;
@@ -2283,7 +2326,11 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
// GNU-style and C++11 attributes are not allowed here, but they will be
// handled by the caller. Diagnose everything else.
- ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, false);
+ ParseTypeQualifierListOpt(
+ DS, AR_NoAttributesParsed, false,
+ /*IdentifierRequired=*/false, llvm::function_ref<void()>([&]() {
+ Actions.CodeCompleteFunctionQualifiers(DS, D, &VS);
+ }));
D.ExtendWithDeclSpec(DS);
if (D.isFunctionDeclarator()) {
@@ -2425,8 +2472,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Try to parse an unqualified-id.
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
- if (ParseUnqualifiedId(SS, false, true, true, nullptr, TemplateKWLoc,
- Name)) {
+ if (ParseUnqualifiedId(SS, false, true, true, false, nullptr,
+ TemplateKWLoc, Name)) {
SkipUntil(tok::semi);
return nullptr;
}
@@ -2457,9 +2504,10 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::kw_template)) {
assert(!TemplateInfo.TemplateParams &&
"Nested template improperly parsed?");
+ ObjCDeclContextSwitch ObjCDC(*this);
SourceLocation DeclEnd;
return DeclGroupPtrTy::make(
- DeclGroupRef(ParseDeclarationStartingWithTemplate(
+ DeclGroupRef(ParseTemplateDeclarationOrSpecialization(
Declarator::MemberContext, DeclEnd, AS, AccessAttrs)));
}
@@ -2864,9 +2912,8 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
assert(Tok.isOneOf(tok::equal, tok::l_brace)
&& "Data member initializer not starting with '=' or '{'");
- EnterExpressionEvaluationContext Context(Actions,
- Sema::PotentiallyEvaluated,
- D);
+ EnterExpressionEvaluationContext Context(
+ Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, D);
if (TryConsumeToken(tok::equal, EqualLoc)) {
if (Tok.is(tok::kw_delete)) {
// In principle, an initializer of '= delete p;' is legal, but it will
@@ -2957,56 +3004,50 @@ void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc,
Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs,
DeclSpec::TST TagType, Decl *TagDecl) {
- if (getLangOpts().MicrosoftExt &&
- Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
+ switch (Tok.getKind()) {
+ case tok::kw___if_exists:
+ case tok::kw___if_not_exists:
ParseMicrosoftIfExistsClassDeclaration(TagType, AS);
return nullptr;
- }
- // Check for extraneous top-level semicolon.
- if (Tok.is(tok::semi)) {
+ case tok::semi:
+ // Check for extraneous top-level semicolon.
ConsumeExtraSemi(InsideStruct, TagType);
return nullptr;
- }
- if (Tok.is(tok::annot_pragma_vis)) {
+ // Handle pragmas that can appear as member declarations.
+ case tok::annot_pragma_vis:
HandlePragmaVisibility();
return nullptr;
- }
-
- if (Tok.is(tok::annot_pragma_pack)) {
+ case tok::annot_pragma_pack:
HandlePragmaPack();
return nullptr;
- }
-
- if (Tok.is(tok::annot_pragma_align)) {
+ case tok::annot_pragma_align:
HandlePragmaAlign();
return nullptr;
- }
-
- if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) {
+ case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return nullptr;
- }
-
- if (Tok.is(tok::annot_pragma_ms_pragma)) {
+ case tok::annot_pragma_ms_pragma:
HandlePragmaMSPragma();
return nullptr;
- }
-
- if (Tok.is(tok::annot_pragma_ms_vtordisp)) {
+ case tok::annot_pragma_ms_vtordisp:
HandlePragmaMSVtorDisp();
return nullptr;
- }
+ case tok::annot_pragma_dump:
+ HandlePragmaDump();
+ return nullptr;
- // If we see a namespace here, a close brace was missing somewhere.
- if (Tok.is(tok::kw_namespace)) {
+ case tok::kw_namespace:
+ // If we see a namespace here, a close brace was missing somewhere.
DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
return nullptr;
- }
- AccessSpecifier NewAS = getAccessSpecifierIfPresent();
- if (NewAS != AS_none) {
+ case tok::kw_public:
+ case tok::kw_protected:
+ case tok::kw_private: {
+ AccessSpecifier NewAS = getAccessSpecifierIfPresent();
+ assert(NewAS != AS_none);
// Current token is a C++ access specifier.
AS = NewAS;
SourceLocation ASLoc = Tok.getLocation();
@@ -3041,12 +3082,13 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
return nullptr;
}
- if (Tok.is(tok::annot_pragma_openmp))
+ case tok::annot_pragma_openmp:
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType,
TagDecl);
- // Parse all the comma separated declarators.
- return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList());
+ default:
+ return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList());
+ }
}
/// ParseCXXMemberSpecification - Parse the class definition.
@@ -3376,39 +3418,42 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
- ParsedType TemplateTypeTy;
- if (Tok.is(tok::annot_template_id)) {
- TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
- if (TemplateId->Kind == TNK_Type_template ||
- TemplateId->Kind == TNK_Dependent_template_name) {
- AnnotateTemplateIdTokenAsType();
- assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
- TemplateTypeTy = getTypeAnnotation(Tok);
- }
- }
- // Uses of decltype will already have been converted to annot_decltype by
- // ParseOptionalCXXScopeSpecifier at this point.
- if (!TemplateTypeTy && Tok.isNot(tok::identifier)
- && Tok.isNot(tok::annot_decltype)) {
- Diag(Tok, diag::err_expected_member_or_base_name);
- return true;
- }
+ // : identifier
IdentifierInfo *II = nullptr;
- DeclSpec DS(AttrFactory);
SourceLocation IdLoc = Tok.getLocation();
- if (Tok.is(tok::annot_decltype)) {
+ // : declype(...)
+ DeclSpec DS(AttrFactory);
+ // : template_name<...>
+ ParsedType TemplateTypeTy;
+
+ if (Tok.is(tok::identifier)) {
+ // Get the identifier. This may be a member name or a class name,
+ // but we'll let the semantic analysis determine which it is.
+ II = Tok.getIdentifierInfo();
+ ConsumeToken();
+ } else if (Tok.is(tok::annot_decltype)) {
// Get the decltype expression, if there is one.
+ // Uses of decltype will already have been converted to annot_decltype by
+ // ParseOptionalCXXScopeSpecifier at this point.
+ // FIXME: Can we get here with a scope specifier?
ParseDecltypeSpecifier(DS);
} else {
- if (Tok.is(tok::identifier))
- // Get the identifier. This may be a member name or a class name,
- // but we'll let the semantic analysis determine which it is.
- II = Tok.getIdentifierInfo();
- ConsumeToken();
+ TemplateIdAnnotation *TemplateId = Tok.is(tok::annot_template_id)
+ ? takeTemplateIdAnnotation(Tok)
+ : nullptr;
+ if (TemplateId && (TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name)) {
+ AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
+ assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
+ TemplateTypeTy = getTypeAnnotation(Tok);
+ ConsumeAnnotationToken();
+ } else {
+ Diag(Tok, diag::err_expected_member_or_base_name);
+ return true;
+ }
}
-
// Parse the '('.
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
@@ -3817,36 +3862,44 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
return false;
}
- if (ScopeName && ScopeName->getName() == "gnu")
+ if (ScopeName && ScopeName->getName() == "gnu") {
// GNU-scoped attributes have some special cases to handle GNU-specific
// behaviors.
ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
ScopeLoc, AttributeList::AS_CXX11, nullptr);
- else {
- unsigned NumArgs =
+ return true;
+ }
+
+ unsigned NumArgs;
+ // Some Clang-scoped attributes have some special parsing behavior.
+ if (ScopeName && ScopeName->getName() == "clang")
+ NumArgs =
+ ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+ ScopeLoc, AttributeList::AS_CXX11);
+ else
+ NumArgs =
ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, AttributeList::AS_CXX11);
-
- const AttributeList *Attr = Attrs.getList();
- if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) {
- // If the attribute is a standard or built-in attribute and we are
- // parsing an argument list, we need to determine whether this attribute
- // was allowed to have an argument list (such as [[deprecated]]), and how
- // many arguments were parsed (so we can diagnose on [[deprecated()]]).
- if (Attr->getMaxArgs() && !NumArgs) {
- // The attribute was allowed to have arguments, but none were provided
- // even though the attribute parsed successfully. This is an error.
- Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName;
- Attr->setInvalid(true);
- } else if (!Attr->getMaxArgs()) {
- // The attribute parsed successfully, but was not allowed to have any
- // arguments. It doesn't matter whether any were provided -- the
- // presence of the argument list (even if empty) is diagnosed.
- Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments)
- << AttrName
- << FixItHint::CreateRemoval(SourceRange(LParenLoc, *EndLoc));
- Attr->setInvalid(true);
- }
+
+ const AttributeList *Attr = Attrs.getList();
+ if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) {
+ // If the attribute is a standard or built-in attribute and we are
+ // parsing an argument list, we need to determine whether this attribute
+ // was allowed to have an argument list (such as [[deprecated]]), and how
+ // many arguments were parsed (so we can diagnose on [[deprecated()]]).
+ if (Attr->getMaxArgs() && !NumArgs) {
+ // The attribute was allowed to have arguments, but none were provided
+ // even though the attribute parsed successfully. This is an error.
+ Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName;
+ Attr->setInvalid(true);
+ } else if (!Attr->getMaxArgs()) {
+ // The attribute parsed successfully, but was not allowed to have any
+ // arguments. It doesn't matter whether any were provided -- the
+ // presence of the argument list (even if empty) is diagnosed.
+ Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments)
+ << AttrName
+ << FixItHint::CreateRemoval(SourceRange(LParenLoc, *EndLoc));
+ Attr->setInvalid(true);
}
}
return true;
@@ -4114,8 +4167,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);
@@ -4177,6 +4228,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
<< Result.IsIfExists;
// Fall through to skip.
+ LLVM_FALLTHROUGH;
case IEB_Skip:
Braces.skipToEnd();
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp
index 852e226..44b87af 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp
@@ -21,10 +21,10 @@
///
//===----------------------------------------------------------------------===//
-#include "RAIIObjectsForParser.h"
+#include "clang/Parse/Parser.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/PrettyStackTrace.h"
-#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
@@ -192,18 +192,25 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
return ParseRHSOfBinaryExpression(R, prec::Assignment);
}
+ExprResult
+Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) {
+ assert(Actions.ExprEvalContexts.back().Context ==
+ Sema::ExpressionEvaluationContext::ConstantEvaluated &&
+ "Call this function only if your ExpressionEvaluationContext is "
+ "already ConstantEvaluated");
+ ExprResult LHS(ParseCastExpression(false, false, isTypeCast));
+ ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
+ return Actions.ActOnConstantExpression(Res);
+}
ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
// C++03 [basic.def.odr]p2:
// An expression is potentially evaluated unless it appears where an
// integral constant expression is required (see 5.19) [...].
// C++98 and C++11 have no such rule, but this is only a defect in C++98.
- EnterExpressionEvaluationContext ConstantEvaluated(Actions,
- Sema::ConstantEvaluated);
-
- ExprResult LHS(ParseCastExpression(false, false, isTypeCast));
- ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
- return Actions.ActOnConstantExpression(Res);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ return ParseConstantExpressionInExprEvalContext(isTypeCast);
}
/// \brief Parse a constraint-expression.
@@ -235,6 +242,30 @@ bool Parser::isNotExpressionStart() {
return isKnownToBeDeclarationSpecifier();
}
+/// We've parsed something that could plausibly be intended to be a template
+/// name (\p LHS) followed by a '<' token, and the following code can't possibly
+/// be an expression. Determine if this is likely to be a template-id and if so,
+/// diagnose it.
+bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) {
+ TentativeParsingAction TPA(*this);
+ // FIXME: We could look at the token sequence in a lot more detail here.
+ if (SkipUntil(tok::greater, tok::greatergreater, tok::greatergreatergreater,
+ StopAtSemi | StopBeforeMatch)) {
+ TPA.Commit();
+
+ SourceLocation Greater;
+ ParseGreaterThanInTemplateList(Greater, true, false);
+ Actions.diagnoseExprIntendedAsTemplateName(getCurScope(), LHS,
+ Less, Greater);
+ return true;
+ }
+
+ // There's no matching '>' token, this probably isn't supposed to be
+ // interpreted as a template-id. Parse it as an (ill-formed) comparison.
+ TPA.Revert();
+ return false;
+}
+
static bool isFoldOperator(prec::Level Level) {
return Level > prec::Unknown && Level != prec::Conditional;
}
@@ -276,6 +307,16 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
return LHS;
}
+ // If a '<' token is followed by a type that can be a template argument and
+ // cannot be an expression, then this is ill-formed, but might be intended
+ // to be a template-id.
+ if (OpToken.is(tok::less) && Actions.mightBeIntendedToBeTemplateName(LHS) &&
+ (isKnownToBeDeclarationSpecifier() ||
+ Tok.isOneOf(tok::greater, tok::greatergreater,
+ tok::greatergreatergreater)) &&
+ diagnoseUnknownTemplateId(LHS, OpToken.getLocation()))
+ return ExprError();
+
// If the next token is an ellipsis, then this is a fold-expression. Leave
// it alone so we can handle it in the paren expression.
if (isFoldOperator(NextTokPrec) && Tok.is(tok::ellipsis)) {
@@ -339,7 +380,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
ColonLoc = Tok.getLocation();
}
}
-
+
// Code completion for the right-hand side of an assignment expression
// goes through a special hook that takes the left-hand side into account.
if (Tok.is(tok::code_completion) && NextTokPrec == prec::Assignment) {
@@ -347,7 +388,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
cutOffParsing();
return ExprError();
}
-
+
// Parse another leaf here for the RHS of the operator.
// ParseCastExpression works here because all RHS expressions in C have it
// as a prefix, at least. However, in C++, an assignment-expression could
@@ -456,6 +497,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
if (!getLangOpts().CPlusPlus)
continue;
}
+
// Ensure potential typos aren't left undiagnosed.
if (LHS.isInvalid()) {
Actions.CorrectDelayedTyposInExpr(OrigLHS);
@@ -473,12 +515,14 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
///
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
- TypeCastState isTypeCast) {
+ TypeCastState isTypeCast,
+ bool isVectorLiteral) {
bool NotCastExpr;
ExprResult Res = ParseCastExpression(isUnaryExpression,
isAddressOfOperand,
NotCastExpr,
- isTypeCast);
+ isTypeCast,
+ isVectorLiteral);
if (NotCastExpr)
Diag(Tok, diag::err_expected_expression);
return Res;
@@ -674,6 +718,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
/// '__is_union'
///
/// [Clang] unary-type-trait:
+/// '__is_aggregate'
/// '__trivially_copyable'
///
/// binary-type-trait:
@@ -694,7 +739,8 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
- TypeCastState isTypeCast) {
+ TypeCastState isTypeCast,
+ bool isVectorLiteral) {
ExprResult Res;
tok::TokenKind SavedKind = Tok.getKind();
NotCastExpr = false;
@@ -722,6 +768,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
isTypeCast == IsTypeCast, CastTy, RParenLoc);
+ if (isVectorLiteral)
+ return Res;
+
switch (ParenExprType) {
case SimpleExpr: break; // Nothing else to do.
case CompoundStmt: break; // Nothing else to do.
@@ -762,7 +811,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::annot_primary_expr:
assert(Res.get() == nullptr && "Stray primary-expression annotation?");
Res = getExprAnnotation(Tok);
- ConsumeToken();
+ ConsumeAnnotationToken();
break;
case tok::kw___super:
@@ -798,6 +847,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
= RTT_JOIN(tok::kw_,Name)
REVERTIBLE_TYPE_TRAIT(__is_abstract);
+ REVERTIBLE_TYPE_TRAIT(__is_aggregate);
REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
REVERTIBLE_TYPE_TRAIT(__is_array);
REVERTIBLE_TYPE_TRAIT(__is_assignable);
@@ -1156,7 +1206,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (Ty.isInvalid())
break;
- ConsumeToken();
+ ConsumeAnnotationToken();
Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
Ty.get(), nullptr);
break;
@@ -1264,6 +1314,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
// Fall through to treat the template-id as an id-expression.
+ LLVM_FALLTHROUGH;
}
case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
@@ -1307,7 +1358,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// C++11 [expr.unary.noexcept]p1:
// The noexcept operator determines whether the evaluation of its operand,
// which is an unevaluated operand, can throw an exception.
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult Result = ParseExpression();
T.consumeClose();
@@ -1433,9 +1485,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
nullptr, LHS.get());
break;
}
-
// Fall through; this isn't a message send.
-
+ LLVM_FALLTHROUGH;
+
default: // Not a postfix-expression suffix.
return LHS;
case tok::l_square: { // postfix-expression: p-e '[' expression ']'
@@ -1693,6 +1745,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/
getLangOpts().MicrosoftExt,
+ /*AllowDeductionGuide=*/false,
ObjectType, TemplateKWLoc, Name)) {
(void)Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
@@ -1813,7 +1866,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
}
}
- // If we get here, the operand to the typeof/sizeof/alignof was an expresion.
+ // If we get here, the operand to the typeof/sizeof/alignof was an expression.
isCastExpr = false;
return Operand;
}
@@ -1875,9 +1928,10 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
if (!Name)
return ExprError();
-
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
- Sema::ReuseLambdaContextDecl);
+
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
return Actions.ActOnSizeofParameterPackExpr(getCurScope(),
OpTok.getLocation(),
@@ -1888,8 +1942,9 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
Diag(OpTok, diag::warn_cxx98_compat_alignof);
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
- Sema::ReuseLambdaContextDecl);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
bool isCastExpr;
ParsedType CastTy;
@@ -1917,7 +1972,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo();
- // If we get here, the operand to the sizeof/alignof was an expresion.
+ // If we get here, the operand to the sizeof/alignof was an expression.
if (!Operand.isInvalid())
Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
ExprKind,
@@ -2349,6 +2404,48 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc);
}
+ if (Tok.is(tok::l_paren)) {
+ // This could be OpenCL vector Literals
+ if (getLangOpts().OpenCL)
+ {
+ TypeResult Ty;
+ {
+ InMessageExpressionRAIIObject InMessage(*this, false);
+ Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+ }
+ if(Ty.isInvalid())
+ {
+ return ExprError();
+ }
+ QualType QT = Ty.get().get().getCanonicalType();
+ if (QT->isVectorType())
+ {
+ // We parsed '(' vector-type-name ')' followed by '('
+
+ // Parse the cast-expression that follows it next.
+ // isVectorLiteral = true will make sure we don't parse any
+ // Postfix expression yet
+ Result = ParseCastExpression(/*isUnaryExpression=*/false,
+ /*isAddressOfOperand=*/false,
+ /*isTypeCast=*/IsTypeCast,
+ /*isVectorLiteral=*/true);
+
+ if (!Result.isInvalid()) {
+ Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc,
+ DeclaratorInfo, CastTy,
+ RParenLoc, Result.get());
+ }
+
+ // After we performed the cast we can check for postfix-expr pieces.
+ if (!Result.isInvalid()) {
+ Result = ParsePostfixExpressionSuffix(Result);
+ }
+
+ return Result;
+ }
+ }
+ }
+
if (ExprType == CastExpr) {
// We parsed '(' type-name ')' and the thing after it wasn't a '{'.
@@ -2520,7 +2617,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
{
// C11 6.5.1.1p3 "The controlling expression of a generic selection is
// not evaluated."
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
ControllingExpr =
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (ControllingExpr.isInvalid()) {
@@ -2933,6 +3031,11 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
return AvailabilitySpec(ConsumeToken());
} else {
// Parse the platform name.
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteAvailabilityPlatformName();
+ cutOffParsing();
+ return None;
+ }
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_avail_query_expected_platform_name);
return None;
@@ -2945,12 +3048,14 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
if (Version.empty())
return None;
- StringRef Platform = PlatformIdentifier->Ident->getName();
+ StringRef GivenPlatform = PlatformIdentifier->Ident->getName();
+ StringRef Platform =
+ AvailabilityAttr::canonicalizePlatformName(GivenPlatform);
if (AvailabilityAttr::getPrettyPlatformName(Platform).empty()) {
Diag(PlatformIdentifier->Loc,
diag::err_avail_query_unrecognized_platform_name)
- << Platform;
+ << GivenPlatform;
return None;
}
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp
index 124266a..dcafbad 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp
@@ -10,13 +10,13 @@
// This file implements the Expression parsing implementation for C++.
//
//===----------------------------------------------------------------------===//
+#include "clang/Parse/Parser.h"
#include "clang/AST/ASTContext.h"
-#include "RAIIObjectsForParser.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Parse/ParseDiagnostic.h"
-#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
@@ -141,13 +141,16 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
/// filled in with the leading identifier in the last component of the
/// nested-name-specifier, if any.
///
+/// \param OnlyNamespace If true, only considers namespaces in lookup.
+///
/// \returns true if there was an error parsing a scope specifier
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ParsedType ObjectType,
bool EnteringContext,
bool *MayBePseudoDestructor,
bool IsTypename,
- IdentifierInfo **LastII) {
+ IdentifierInfo **LastII,
+ bool OnlyNamespace) {
assert(getLangOpts().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
@@ -157,7 +160,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
Tok.getAnnotationRange(),
SS);
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
}
@@ -216,7 +219,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
SourceLocation CCLoc;
- if (!TryConsumeToken(tok::coloncolon, CCLoc)) {
+ // Work around a standard defect: 'decltype(auto)::' is not a
+ // nested-name-specifier.
+ if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto ||
+ !TryConsumeToken(tok::coloncolon, CCLoc)) {
AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc);
return false;
}
@@ -310,11 +316,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// Commit to parsing the template-id.
TPA.Commit();
TemplateTy Template;
- if (TemplateNameKind TNK
- = Actions.ActOnDependentTemplateName(getCurScope(),
- SS, TemplateKWLoc, TemplateName,
- ObjectType, EnteringContext,
- Template)) {
+ if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(
+ getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
+ EnteringContext, Template, /*AllowInjectedClassName*/ true)) {
if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc,
TemplateName, false))
return true;
@@ -342,7 +346,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
*LastII = TemplateId->Name;
// Consume the template-id token.
- ConsumeToken();
+ ConsumeAnnotationToken();
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
@@ -449,9 +453,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
bool IsCorrectedToColon = false;
bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr;
- if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), IdInfo,
- EnteringContext, SS,
- false, CorrectionFlagPtr)) {
+ if (Actions.ActOnCXXNestedNameSpecifier(
+ getCurScope(), IdInfo, EnteringContext, SS, false,
+ CorrectionFlagPtr, OnlyNamespace)) {
// Identifier is not recognized as a nested name, but we can have
// mistyped '::' instead of ':'.
if (CorrectionFlagPtr && IsCorrectedToColon) {
@@ -509,12 +513,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
Diag(Tok.getLocation(), DiagID)
<< II.getName()
<< FixItHint::CreateInsertion(Tok.getLocation(), "template ");
-
- if (TemplateNameKind TNK
- = Actions.ActOnDependentTemplateName(getCurScope(),
- SS, SourceLocation(),
- TemplateName, ObjectType,
- EnteringContext, Template)) {
+
+ if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(
+ getCurScope(), SS, SourceLocation(), TemplateName, ObjectType,
+ EnteringContext, Template, /*AllowInjectedClassName*/ true)) {
// Consume the identifier.
ConsumeToken();
if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),
@@ -550,6 +552,7 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOpe
/*EnteringContext=*/false,
/*AllowDestructorName=*/false,
/*AllowConstructorName=*/false,
+ /*AllowDeductionGuide=*/false,
/*ObjectType=*/nullptr, TemplateKWLoc, Name))
return ExprError();
@@ -863,8 +866,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// Each lambda init-capture forms its own full expression, which clears
// Actions.MaybeODRUseExprs. So create an expression evaluation context
// to save the necessary state, and restore it later.
- EnterExpressionEvaluationContext EC(Actions,
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EC(
+ Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
if (TryConsumeToken(tok::equal))
InitKind = LambdaCaptureInitKind::CopyInit;
@@ -917,7 +920,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
PP.AnnotateCachedTokens(Tok);
// Consume the annotated initializer.
- ConsumeToken();
+ ConsumeAnnotationToken();
}
}
} else
@@ -1402,8 +1405,9 @@ ExprResult Parser::ParseCXXTypeid() {
// We enter the unevaluated context before trying to determine whether we
// have a type-id, because the tentative parse logic will try to resolve
// names, and must treat them as unevaluated.
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
- Sema::ReuseLambdaContextDecl);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
if (isTypeIdInParens()) {
TypeResult Ty = ParseTypeName();
@@ -1466,7 +1470,8 @@ ExprResult Parser::ParseCXXUuidof() {
Ty.get().getAsOpaquePtr(),
T.getCloseLocation());
} else {
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ Actions, Sema::ExpressionEvaluationContext::Unevaluated);
Result = ParseExpression();
// Match the ')'.
@@ -1523,7 +1528,7 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
// store it in the pseudo-dtor node (to be used when instantiating it).
FirstTypeName.setTemplateId(
(TemplateIdAnnotation *)Tok.getAnnotationValue());
- ConsumeToken();
+ ConsumeAnnotationToken();
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
CCLoc = ConsumeToken();
} else {
@@ -1643,9 +1648,10 @@ ExprResult Parser::ParseCXXThis() {
/// typename-specifier '(' expression-list[opt] ')'
/// [C++0x] typename-specifier braced-init-list
///
+/// In C++1z onwards, the type specifier can also be a template-name.
ExprResult
Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
- Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ Declarator DeclaratorInfo(DS, Declarator::FunctionalCastContext);
ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
assert((Tok.is(tok::l_paren) ||
@@ -1876,7 +1882,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetTypeSpecError();
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
- ConsumeToken();
+ ConsumeAnnotationToken();
DS.Finish(Actions, Policy);
return;
@@ -1945,11 +1951,8 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.Finish(Actions, Policy);
return;
}
- if (Tok.is(tok::annot_typename))
- DS.SetRangeEnd(Tok.getAnnotationEndLoc());
- else
- DS.SetRangeEnd(Tok.getLocation());
- ConsumeToken();
+ ConsumeAnyToken();
+ DS.SetRangeEnd(PrevTokLocation);
DS.Finish(Actions, Policy);
}
@@ -2020,9 +2023,11 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId:
if (AssumeTemplateId) {
- TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc,
- Id, ObjectType, EnteringContext,
- Template);
+ // We defer the injected-class-name checks until we've found whether
+ // this template-id is used to form a nested-name-specifier or not.
+ TNK = Actions.ActOnDependentTemplateName(
+ getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext,
+ Template, /*AllowInjectedClassName*/ true);
if (TNK == TNK_Non_template)
return true;
} else {
@@ -2051,10 +2056,9 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
<< Name
<< FixItHint::CreateInsertion(Id.StartLocation, "template ");
- TNK = Actions.ActOnDependentTemplateName(getCurScope(),
- SS, TemplateKWLoc, Id,
- ObjectType, EnteringContext,
- Template);
+ TNK = Actions.ActOnDependentTemplateName(
+ getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext,
+ Template, /*AllowInjectedClassName*/ true);
if (TNK == TNK_Non_template)
return true;
}
@@ -2077,10 +2081,9 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
bool MemberOfUnknownSpecialization;
TemplateName.setIdentifier(Name, NameLoc);
if (ObjectType) {
- TNK = Actions.ActOnDependentTemplateName(getCurScope(),
- SS, TemplateKWLoc, TemplateName,
- ObjectType, EnteringContext,
- Template);
+ TNK = Actions.ActOnDependentTemplateName(
+ getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType,
+ EnteringContext, Template, /*AllowInjectedClassName*/ true);
if (TNK == TNK_Non_template)
return true;
} else {
@@ -2108,11 +2111,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
- if (Tok.is(tok::less) &&
- ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
- SS, true, LAngleLoc,
- TemplateArgs,
- RAngleLoc))
+ if (Tok.is(tok::less) && ParseTemplateIdAfterTemplateName(
+ true, LAngleLoc, TemplateArgs, RAngleLoc))
return true;
if (Id.getKind() == UnqualifiedId::IK_Identifier ||
@@ -2120,31 +2120,18 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) {
// Form a parsed representation of the template-id to be stored in the
// UnqualifiedId.
- TemplateIdAnnotation *TemplateId
- = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
// FIXME: Store name for literal operator too.
- if (Id.getKind() == UnqualifiedId::IK_Identifier) {
- TemplateId->Name = Id.Identifier;
- TemplateId->Operator = OO_None;
- TemplateId->TemplateNameLoc = Id.StartLocation;
- } else {
- TemplateId->Name = nullptr;
- TemplateId->Operator = Id.OperatorFunctionId.Operator;
- TemplateId->TemplateNameLoc = Id.StartLocation;
- }
+ IdentifierInfo *TemplateII =
+ Id.getKind() == UnqualifiedId::IK_Identifier ? Id.Identifier : nullptr;
+ OverloadedOperatorKind OpKind = Id.getKind() == UnqualifiedId::IK_Identifier
+ ? OO_None
+ : Id.OperatorFunctionId.Operator;
+
+ TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
+ SS, TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK,
+ LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
- TemplateId->SS = SS;
- TemplateId->TemplateKWLoc = TemplateKWLoc;
- TemplateId->Template = Template;
- TemplateId->Kind = TNK;
- TemplateId->LAngleLoc = LAngleLoc;
- TemplateId->RAngleLoc = RAngleLoc;
- ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
- for (unsigned Arg = 0, ArgEnd = TemplateArgs.size();
- Arg != ArgEnd; ++Arg)
- Args[Arg] = TemplateArgs[Arg];
-
Id.setTemplateId(TemplateId);
return false;
}
@@ -2155,7 +2142,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Constructor and destructor names.
TypeResult Type
= Actions.ActOnTemplateIdType(SS, TemplateKWLoc,
- Template, NameLoc,
+ Template, Name, NameLoc,
LAngleLoc, TemplateArgsPtr, RAngleLoc,
/*IsCtorOrDtorName=*/true);
if (Type.isInvalid())
@@ -2432,6 +2419,8 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
///
/// \param AllowConstructorName whether we allow parsing a constructor name.
///
+/// \param AllowDeductionGuide whether we allow parsing a deduction guide name.
+///
/// \param ObjectType if this unqualified-id occurs within a member access
/// expression, the type of the base object whose member is being accessed.
///
@@ -2441,6 +2430,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
+ bool AllowDeductionGuide,
ParsedType ObjectType,
SourceLocation& TemplateKWLoc,
UnqualifiedId &Result) {
@@ -2469,6 +2459,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
return false;
}
+ ParsedTemplateTy TemplateName;
if (AllowConstructorName &&
Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
// We have parsed a constructor name.
@@ -2477,6 +2468,12 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
/*IsCtorOrDtorName=*/true,
/*NonTrivialTypeSourceInfo=*/true);
Result.setConstructorName(Ty, IdLoc, IdLoc);
+ } else if (getLangOpts().CPlusPlus1z &&
+ AllowDeductionGuide && SS.isEmpty() &&
+ Actions.isDeductionGuideName(getCurScope(), *Id, IdLoc,
+ &TemplateName)) {
+ // We have parsed a template-name naming a deduction guide.
+ Result.setDeductionGuideName(TemplateName, IdLoc);
} else {
// We have parsed an identifier.
Result.setIdentifier(Id, IdLoc);
@@ -2516,12 +2513,12 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
/*NontrivialTypeSourceInfo=*/true);
Result.setConstructorName(Ty, TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc);
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
}
Result.setConstructorTemplateId(TemplateId);
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
}
@@ -2529,7 +2526,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// our unqualified-id.
Result.setTemplateId(TemplateId);
TemplateKWLoc = TemplateId->TemplateKWLoc;
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
}
@@ -2569,7 +2566,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
if (SS.isEmpty() && Tok.is(tok::kw_decltype)) {
DeclSpec DS(AttrFactory);
SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
- if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) {
+ if (ParsedType Type =
+ Actions.getDestructorTypeForDecltype(DS, ObjectType)) {
Result.setDestructorName(TildeLoc, Type, EndLoc);
return false;
}
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp
index fa6b75d..90f3561 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "RAIIObjectsForParser.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallString.h"
@@ -501,7 +501,8 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
<< Result.IsIfExists;
// Fall through to skip.
-
+ LLVM_FALLTHROUGH;
+
case IEB_Skip:
Braces.skipToEnd();
return false;
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp
index 81761bf..01b1bf4 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
@@ -137,8 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
while (1) {
MaybeSkipAttributes(tok::objc_class);
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+ if (expectIdentifier()) {
SkipUntil(tok::semi);
return Actions.ConvertDeclToDeclGroup(nullptr);
}
@@ -229,11 +228,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
MaybeSkipAttributes(tok::objc_interface);
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing class or category name.
- return nullptr;
- }
+ if (expectIdentifier())
+ return nullptr; // missing class or category name.
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
@@ -278,11 +274,6 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
T.consumeClose();
if (T.getCloseLocation().isInvalid())
return nullptr;
-
- if (!attrs.empty()) { // categories don't support attributes.
- Diag(nameLoc, diag::err_objc_no_attributes_on_category);
- attrs.clear();
- }
// Next, we need to check for any protocol references.
assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
@@ -294,16 +285,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
/*consumeLastToken=*/true))
return nullptr;
- Decl *CategoryType =
- Actions.ActOnStartCategoryInterface(AtLoc,
- nameId, nameLoc,
- typeParameterList,
- categoryId, categoryLoc,
- ProtocolRefs.data(),
- ProtocolRefs.size(),
- ProtocolLocs.data(),
- EndProtoLoc);
-
+ Decl *CategoryType = Actions.ActOnStartCategoryInterface(
+ AtLoc, nameId, nameLoc, typeParameterList, categoryId, categoryLoc,
+ ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(),
+ EndProtoLoc, attrs.getList());
+
if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
@@ -329,11 +315,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
return nullptr;
}
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing super class name.
- return nullptr;
- }
+ if (expectIdentifier())
+ return nullptr; // missing super class name.
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken();
@@ -929,7 +912,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
if (IsSetter) {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
- DS.setSetterName(SelIdent);
+ DS.setSetterName(SelIdent, SelLoc);
if (ExpectAndConsume(tok::colon,
diag::err_expected_colon_after_setter_name)) {
@@ -938,7 +921,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
}
} else {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
- DS.setGetterName(SelIdent);
+ DS.setGetterName(SelIdent, SelLoc);
}
} else if (II->isStr("nonnull")) {
if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
@@ -1024,6 +1007,10 @@ IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
switch (Tok.getKind()) {
default:
return nullptr;
+ case tok::colon:
+ // Empty selector piece uses the location of the ':'.
+ SelectorLoc = Tok.getLocation();
+ return nullptr;
case tok::ampamp:
case tok::ampequal:
case tok::amp:
@@ -1448,12 +1435,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
cutOffParsing();
return nullptr;
}
-
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing argument name.
- break;
- }
+
+ if (expectIdentifier())
+ break; // missing argument name.
ArgInfo.Name = Tok.getIdentifierInfo();
ArgInfo.NameLoc = Tok.getLocation();
@@ -1562,8 +1546,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
return true;
}
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+ if (expectIdentifier()) {
SkipUntil(tok::greater, StopAtSemi);
return true;
}
@@ -2045,10 +2028,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
MaybeSkipAttributes(tok::objc_protocol);
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier; // missing protocol name.
- return nullptr;
- }
+ if (expectIdentifier())
+ return nullptr; // missing protocol name.
// Save the protocol name, then consume it.
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
@@ -2068,8 +2049,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
// Parse the list of forward declarations.
while (1) {
ConsumeToken(); // the ','
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+ if (expectIdentifier()) {
SkipUntil(tok::semi);
return nullptr;
}
@@ -2136,11 +2116,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
MaybeSkipAttributes(tok::objc_implementation);
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing class or category name.
- return nullptr;
- }
+ if (expectIdentifier())
+ return nullptr; // missing class or category name.
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
@@ -2210,11 +2187,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
IdentifierInfo *superClassId = nullptr;
if (TryConsumeToken(tok::colon)) {
// We have a super class
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected)
- << tok::identifier; // missing super class name.
- return nullptr;
- }
+ if (expectIdentifier())
+ return nullptr; // missing super class name.
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken(); // Consume super class name
}
@@ -2285,7 +2259,7 @@ Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
assert(!Finished);
- P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl);
+ P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl, AtEnd.getBegin());
for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
true/*Methods*/);
@@ -2314,16 +2288,12 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
"ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
ConsumeToken(); // consume compatibility_alias
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+ if (expectIdentifier())
return nullptr;
- }
IdentifierInfo *aliasId = Tok.getIdentifierInfo();
SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+ if (expectIdentifier())
return nullptr;
- }
IdentifierInfo *classId = Tok.getIdentifierInfo();
SourceLocation classLoc = ConsumeToken(); // consume class-name;
ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");
@@ -2371,11 +2341,9 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
cutOffParsing();
return nullptr;
}
-
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+
+ if (expectIdentifier())
break;
- }
propertyIvar = Tok.getIdentifierInfo();
propertyIvarLoc = ConsumeToken(); // consume ivar-name
}
@@ -2433,9 +2401,8 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
cutOffParsing();
return nullptr;
}
-
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
+
+ if (expectIdentifier()) {
SkipUntil(tok::semi);
return nullptr;
}
@@ -3571,8 +3538,8 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
- if (Tok.isNot(tok::identifier))
- return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
+ if (expectIdentifier())
+ return ExprError();
IdentifierInfo *protocolId = Tok.getIdentifierInfo();
SourceLocation ProtoIdLoc = ConsumeToken();
@@ -3664,6 +3631,14 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
SourceLocation OrigLoc = Tok.getLocation();
assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
+ // Store an artificial EOF token to ensure that we don't run off the end of
+ // the method's body when we come to parse it.
+ Token Eof;
+ Eof.startToken();
+ Eof.setKind(tok::eof);
+ Eof.setEofData(MCDecl);
+ Eof.setLocation(OrigLoc);
+ LM.Toks.push_back(Eof);
// Append the current token at the end of the new token stream so that it
// doesn't get lost.
LM.Toks.push_back(Tok);
@@ -3695,7 +3670,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
Actions.ActOnDefaultCtorInitializers(MCDecl);
ParseFunctionStatementBody(MCDecl, BodyScope);
}
-
+
if (Tok.getLocation() != OrigLoc) {
// Due to parsing error, we either went over the cached tokens or
// there are still cached tokens left. If it's the latter case skip the
@@ -3707,4 +3682,6 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
ConsumeAnyToken();
}
+ // Clean up the remaining EOF token.
+ ConsumeAnyToken();
}
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp
index cab7d34..d9a0885 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseOpenMP.cpp
@@ -11,11 +11,11 @@
///
//===----------------------------------------------------------------------===//
-#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -192,6 +192,7 @@ static DeclarationName parseOpenMPReductionId(Parser &P) {
case tok::identifier: // identifier
if (!WithOperator)
break;
+ LLVM_FALLTHROUGH;
default:
P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier);
P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
@@ -532,7 +533,7 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
ConsumeAnyToken();
}
// Skip the last annot_pragma_openmp_end.
- SourceLocation EndLoc = ConsumeToken();
+ SourceLocation EndLoc = ConsumeAnnotationToken();
if (!IsError) {
return Actions.ActOnOpenMPDeclareSimdDirective(
Ptr, BS, Simdlen.get(), Uniforms, Aligneds, Alignments, Linears,
@@ -562,7 +563,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
- SourceLocation Loc = ConsumeToken();
+ SourceLocation Loc = ConsumeAnnotationToken();
auto DKind = ParseOpenMPDirectiveKind(*this);
switch (DKind) {
@@ -578,7 +579,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
// Skip the last annot_pragma_openmp_end.
- ConsumeToken();
+ ConsumeAnnotationToken();
return Actions.ActOnOpenMPThreadprivateDirective(Loc,
Helper.getIdentifiers());
}
@@ -596,7 +597,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ConsumeAnyToken();
}
// Skip the last annot_pragma_openmp_end.
- ConsumeToken();
+ ConsumeAnnotationToken();
return Res;
}
break;
@@ -686,7 +687,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ParseExternalDeclaration(attrs);
if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) {
TentativeParsingAction TPA(*this);
- ConsumeToken();
+ ConsumeAnnotationToken();
DKind = ParseOpenMPDirectiveKind(*this);
if (DKind != OMPD_end_declare_target)
TPA.Revert();
@@ -806,7 +807,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
/// annot_pragma_openmp_end
///
StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
- AllowedContsructsKind Allowed) {
+ AllowedConstructsKind Allowed) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<OMPClause *, 5> Clauses;
@@ -814,7 +815,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
FirstClauses(OMPC_unknown + 1);
unsigned ScopeFlags =
Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
- SourceLocation Loc = ConsumeToken(), EndLoc;
+ SourceLocation Loc = ConsumeAnnotationToken(), EndLoc;
auto DKind = ParseOpenMPDirectiveKind(*this);
OpenMPDirectiveKind CancelRegion = OMPD_unknown;
// Name of critical directive.
@@ -869,6 +870,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
// pseudo-clause OMPFlushClause.
PP.EnterToken(Tok);
}
+ LLVM_FALLTHROUGH;
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
@@ -883,6 +885,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
}
HasAssociatedStatement = false;
// Fall through for further analysis.
+ LLVM_FALLTHROUGH;
case OMPD_parallel:
case OMPD_simd:
case OMPD_for:
@@ -973,7 +976,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
// End location of the directive.
EndLoc = Tok.getLocation();
// Consume final annot_pragma_openmp_end.
- ConsumeToken();
+ ConsumeAnnotationToken();
// OpenMP [2.13.8, ordered Construct, Syntax]
// If the depend clause is specified, the ordered construct is a stand-alone
@@ -1053,7 +1056,7 @@ bool Parser::ParseOpenMPSimpleVarList(
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
- } else if (ParseUnqualifiedId(SS, false, false, false, nullptr,
+ } else if (ParseUnqualifiedId(SS, false, false, false, false, nullptr,
TemplateKWLoc, Name)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
@@ -1099,7 +1102,7 @@ bool Parser::ParseOpenMPSimpleVarList(
/// simdlen-clause | threads-clause | simd-clause | num_teams-clause |
/// thread_limit-clause | priority-clause | grainsize-clause |
/// nogroup-clause | num_tasks-clause | hint-clause | to-clause |
-/// from-clause | is_device_ptr-clause
+/// from-clause | is_device_ptr-clause | task_reduction-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -1184,6 +1187,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
ErrorFound = true;
}
+ LLVM_FALLTHROUGH;
case OMPC_if:
Clause = ParseOpenMPSingleExprWithArgClause(CKind);
@@ -1216,6 +1220,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -1557,8 +1562,9 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
}
return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
/*AllowDestructorName*/ false,
- /*AllowConstructorName*/ false, nullptr,
- TemplateKWLoc, ReductionId);
+ /*AllowConstructorName*/ false,
+ /*AllowDeductionGuide*/ false,
+ nullptr, TemplateKWLoc, ReductionId);
}
/// Parses clauses with list.
@@ -1580,7 +1586,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
BalancedDelimiterTracker LinearT(*this, tok::l_paren,
tok::annot_pragma_openmp_end);
// Handle reduction-identifier for reduction clause.
- if (Kind == OMPC_reduction) {
+ if (Kind == OMPC_reduction || Kind == OMPC_task_reduction) {
ColonProtectionRAIIObject ColonRAII(*this);
if (getLangOpts().CPlusPlus)
ParseOptionalCXXScopeSpecifier(Data.ReductionIdScopeSpec,
@@ -1689,6 +1695,30 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Data.MapType = OMPC_MAP_tofrom;
Data.IsMapTypeImplicit = true;
}
+ } else if (IsMapClauseModifierToken(PP.LookAhead(0))) {
+ if (PP.LookAhead(1).is(tok::colon)) {
+ Data.MapTypeModifier = Data.MapType;
+ if (Data.MapTypeModifier != OMPC_MAP_always) {
+ Diag(Tok, diag::err_omp_unknown_map_type_modifier);
+ Data.MapTypeModifier = OMPC_MAP_unknown;
+ } else
+ MapTypeModifierSpecified = true;
+
+ ConsumeToken();
+
+ Data.MapType =
+ IsMapClauseModifierToken(Tok)
+ ? static_cast<OpenMPMapClauseKind>(
+ getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)))
+ : OMPC_MAP_unknown;
+ if (Data.MapType == OMPC_MAP_unknown ||
+ Data.MapType == OMPC_MAP_always)
+ Diag(Tok, diag::err_omp_unknown_map_type);
+ ConsumeToken();
+ } else {
+ Data.MapType = OMPC_MAP_tofrom;
+ Data.IsMapTypeImplicit = true;
+ }
} else {
Data.MapType = OMPC_MAP_tofrom;
Data.IsMapTypeImplicit = true;
@@ -1704,13 +1734,13 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Diag(Tok, diag::warn_pragma_expected_colon) << "map type";
}
- bool IsComma =
- (Kind != OMPC_reduction && Kind != OMPC_depend && Kind != OMPC_map) ||
- (Kind == OMPC_reduction && !InvalidReductionId) ||
- (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown &&
- (!MapTypeModifierSpecified ||
- Data.MapTypeModifier == OMPC_MAP_always)) ||
- (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown);
+ bool IsComma = (Kind != OMPC_reduction && Kind != OMPC_task_reduction &&
+ Kind != OMPC_depend && Kind != OMPC_map) ||
+ (Kind == OMPC_reduction && !InvalidReductionId) ||
+ (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown &&
+ (!MapTypeModifierSpecified ||
+ Data.MapTypeModifier == OMPC_MAP_always)) ||
+ (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown);
const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
Tok.isNot(tok::annot_pragma_openmp_end))) {
@@ -1766,7 +1796,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
}
/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
-/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'.
+/// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction' or 'task_reduction'.
///
/// private-clause:
/// 'private' '(' list ')'
@@ -1782,6 +1812,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
/// 'aligned' '(' list [ ':' alignment ] ')'
/// reduction-clause:
/// 'reduction' '(' reduction-identifier ':' list ')'
+/// task_reduction-clause:
+/// 'task_reduction' '(' reduction-identifier ':' list ')'
/// copyprivate-clause:
/// 'copyprivate' '(' list ')'
/// flush-clause:
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp
index 8973323..2627437 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/PragmaKinds.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/LoopHint.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/StringSwitch.h"
@@ -49,6 +49,15 @@ struct PragmaPackHandler : public PragmaHandler {
Token &FirstToken) override;
};
+struct PragmaClangSectionHandler : public PragmaHandler {
+ explicit PragmaClangSectionHandler(Sema &S)
+ : PragmaHandler("section"), Actions(S) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+private:
+ Sema &Actions;
+};
+
struct PragmaMSStructHandler : public PragmaHandler {
explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
@@ -86,6 +95,12 @@ struct PragmaFPContractHandler : public PragmaHandler {
Token &FirstToken) override;
};
+struct PragmaFPHandler : public PragmaHandler {
+ PragmaFPHandler() : PragmaHandler("fp") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
struct PragmaNoOpenMPHandler : public PragmaHandler {
PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
@@ -177,6 +192,17 @@ private:
Sema &Actions;
};
+/// PragmaAttributeHandler - "\#pragma clang attribute ...".
+struct PragmaAttributeHandler : public PragmaHandler {
+ PragmaAttributeHandler(AttributeFactory &AttrFactory)
+ : PragmaHandler("attribute"), AttributesForPragmaAttribute(AttrFactory) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+
+ /// A pool of attributes that were parsed in \#pragma clang attribute.
+ ParsedAttributes AttributesForPragmaAttribute;
+};
+
} // end namespace
void Parser::initializePragmaHandlers() {
@@ -207,6 +233,9 @@ void Parser::initializePragmaHandlers() {
FPContractHandler.reset(new PragmaFPContractHandler());
PP.AddPragmaHandler("STDC", FPContractHandler.get());
+ PCSectionHandler.reset(new PragmaClangSectionHandler(Actions));
+ PP.AddPragmaHandler("clang", PCSectionHandler.get());
+
if (getLangOpts().OpenCL) {
OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler());
PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get());
@@ -266,6 +295,12 @@ void Parser::initializePragmaHandlers() {
NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
PP.AddPragmaHandler(NoUnrollHintHandler.get());
+
+ FPHandler.reset(new PragmaFPHandler());
+ PP.AddPragmaHandler("clang", FPHandler.get());
+
+ AttributePragmaHandler.reset(new PragmaAttributeHandler(AttrFactory));
+ PP.AddPragmaHandler("clang", AttributePragmaHandler.get());
}
void Parser::resetPragmaHandlers() {
@@ -300,6 +335,9 @@ void Parser::resetPragmaHandlers() {
MSCommentHandler.reset();
}
+ PP.RemovePragmaHandler("clang", PCSectionHandler.get());
+ PCSectionHandler.reset();
+
if (getLangOpts().MicrosoftExt) {
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
MSDetectMismatchHandler.reset();
@@ -344,6 +382,12 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler(NoUnrollHintHandler.get());
NoUnrollHintHandler.reset();
+
+ PP.RemovePragmaHandler("clang", FPHandler.get());
+ FPHandler.reset();
+
+ PP.RemovePragmaHandler("clang", AttributePragmaHandler.get());
+ AttributePragmaHandler.reset();
}
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -353,7 +397,7 @@ void Parser::resetPragmaHandlers() {
/// annot_pragma_unused 'x' annot_pragma_unused 'y'
void Parser::HandlePragmaUnused() {
assert(Tok.is(tok::annot_pragma_unused));
- SourceLocation UnusedLoc = ConsumeToken();
+ SourceLocation UnusedLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaUnused(Tok, getCurScope(), UnusedLoc);
ConsumeToken(); // The argument token.
}
@@ -362,7 +406,7 @@ void Parser::HandlePragmaVisibility() {
assert(Tok.is(tok::annot_pragma_vis));
const IdentifierInfo *VisType =
static_cast<IdentifierInfo *>(Tok.getAnnotationValue());
- SourceLocation VisLoc = ConsumeToken();
+ SourceLocation VisLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaVisibility(VisType, VisLoc);
}
@@ -378,7 +422,7 @@ void Parser::HandlePragmaPack() {
assert(Tok.is(tok::annot_pragma_pack));
PragmaPackInfo *Info =
static_cast<PragmaPackInfo *>(Tok.getAnnotationValue());
- SourceLocation PragmaLoc = ConsumeToken();
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
ExprResult Alignment;
if (Info->Alignment.is(tok::numeric_constant)) {
Alignment = Actions.ActOnNumericConstant(Info->Alignment);
@@ -394,7 +438,7 @@ void Parser::HandlePragmaMSStruct() {
PragmaMSStructKind Kind = static_cast<PragmaMSStructKind>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
Actions.ActOnPragmaMSStruct(Kind);
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
}
void Parser::HandlePragmaAlign() {
@@ -402,7 +446,7 @@ void Parser::HandlePragmaAlign() {
Sema::PragmaOptionsAlignKind Kind =
static_cast<Sema::PragmaOptionsAlignKind>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
- SourceLocation PragmaLoc = ConsumeToken();
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc);
}
@@ -411,12 +455,12 @@ void Parser::HandlePragmaDump() {
IdentifierInfo *II =
reinterpret_cast<IdentifierInfo *>(Tok.getAnnotationValue());
Actions.ActOnPragmaDump(getCurScope(), Tok.getLocation(), II);
- ConsumeToken();
+ ConsumeAnnotationToken();
}
void Parser::HandlePragmaWeak() {
assert(Tok.is(tok::annot_pragma_weak));
- SourceLocation PragmaLoc = ConsumeToken();
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaWeakID(Tok.getIdentifierInfo(), PragmaLoc,
Tok.getLocation());
ConsumeToken(); // The weak name.
@@ -424,7 +468,7 @@ void Parser::HandlePragmaWeak() {
void Parser::HandlePragmaWeakAlias() {
assert(Tok.is(tok::annot_pragma_weakalias));
- SourceLocation PragmaLoc = ConsumeToken();
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
IdentifierInfo *WeakName = Tok.getIdentifierInfo();
SourceLocation WeakNameLoc = Tok.getLocation();
ConsumeToken();
@@ -438,7 +482,7 @@ void Parser::HandlePragmaWeakAlias() {
void Parser::HandlePragmaRedefineExtname() {
assert(Tok.is(tok::annot_pragma_redefine_extname));
- SourceLocation RedefLoc = ConsumeToken();
+ SourceLocation RedefLoc = ConsumeAnnotationToken();
IdentifierInfo *RedefName = Tok.getIdentifierInfo();
SourceLocation RedefNameLoc = Tok.getLocation();
ConsumeToken();
@@ -454,14 +498,28 @@ void Parser::HandlePragmaFPContract() {
tok::OnOffSwitch OOS =
static_cast<tok::OnOffSwitch>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
- Actions.ActOnPragmaFPContract(OOS);
- ConsumeToken(); // The annotation token.
+
+ LangOptions::FPContractModeKind FPC;
+ switch (OOS) {
+ case tok::OOS_ON:
+ FPC = LangOptions::FPC_On;
+ break;
+ case tok::OOS_OFF:
+ FPC = LangOptions::FPC_Off;
+ break;
+ case tok::OOS_DEFAULT:
+ FPC = getLangOpts().getDefaultFPContractMode();
+ break;
+ }
+
+ Actions.ActOnPragmaFPContract(FPC);
+ ConsumeAnnotationToken();
}
StmtResult Parser::HandlePragmaCaptured()
{
assert(Tok.is(tok::annot_pragma_captured));
- ConsumeToken();
+ ConsumeAnnotationToken();
if (Tok.isNot(tok::l_brace)) {
PP.Diag(Tok, diag::err_expected) << tok::l_brace;
@@ -498,7 +556,7 @@ void Parser::HandlePragmaOpenCLExtension() {
auto State = Data->second;
auto Ident = Data->first;
SourceLocation NameLoc = Tok.getLocation();
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
auto &Opt = Actions.getOpenCLOptions();
auto Name = Ident->getName();
@@ -537,7 +595,7 @@ void Parser::HandlePragmaMSPointersToMembers() {
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod =
static_cast<LangOptions::PragmaMSPointersToMembersKind>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
- SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaMSPointersToMembers(RepresentationMethod, PragmaLoc);
}
@@ -547,7 +605,7 @@ void Parser::HandlePragmaMSVtorDisp() {
Sema::PragmaMsStackAction Action =
static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF);
- SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
+ SourceLocation PragmaLoc = ConsumeAnnotationToken();
Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Mode);
}
@@ -557,7 +615,7 @@ void Parser::HandlePragmaMSPragma() {
auto TheTokens =
(std::pair<std::unique_ptr<Token[]>, size_t> *)Tok.getAnnotationValue();
PP.EnterTokenStream(std::move(TheTokens->first), TheTokens->second, true);
- SourceLocation PragmaLocation = ConsumeToken(); // The annotation token.
+ SourceLocation PragmaLocation = ConsumeAnnotationToken();
assert(Tok.isAnyIdentifier());
StringRef PragmaName = Tok.getIdentifierInfo()->getName();
PP.Lex(Tok); // pragma kind
@@ -853,7 +911,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
if (Toks.empty() && (PragmaUnroll || PragmaNoUnroll)) {
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
Hint.Range = Info->PragmaName.getLocation();
return true;
}
@@ -880,7 +938,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
bool AssumeSafetyArg = !OptionUnroll && !OptionDistribute;
// Verify loop hint has an argument.
if (Toks[0].is(tok::eof)) {
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument)
<< /*StateArgument=*/StateOption << /*FullKeyword=*/OptionUnroll
<< /*AssumeSafetyKeyword=*/AssumeSafetyArg;
@@ -889,7 +947,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
// Validate the argument.
if (StateOption) {
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
SourceLocation StateLoc = Toks[0].getLocation();
IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
@@ -912,7 +970,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
} else {
// Enter constant expression including eof terminator into token stream.
PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false);
- ConsumeToken(); // The annotation token.
+ ConsumeAnnotationToken();
ExprResult R = ParseConstantExpression();
@@ -940,6 +998,422 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
return true;
}
+namespace {
+struct PragmaAttributeInfo {
+ enum ActionType { Push, Pop };
+ ParsedAttributes &Attributes;
+ ActionType Action;
+ ArrayRef<Token> Tokens;
+
+ PragmaAttributeInfo(ParsedAttributes &Attributes) : Attributes(Attributes) {}
+};
+
+#include "clang/Parse/AttrSubMatchRulesParserStringSwitches.inc"
+
+} // end anonymous namespace
+
+static StringRef getIdentifier(const Token &Tok) {
+ if (Tok.is(tok::identifier))
+ return Tok.getIdentifierInfo()->getName();
+ const char *S = tok::getKeywordSpelling(Tok.getKind());
+ if (!S)
+ return "";
+ return S;
+}
+
+static bool isAbstractAttrMatcherRule(attr::SubjectMatchRule Rule) {
+ using namespace attr;
+ switch (Rule) {
+#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract) \
+ case Value: \
+ return IsAbstract;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+ llvm_unreachable("Invalid attribute subject match rule");
+ return false;
+}
+
+static void diagnoseExpectedAttributeSubjectSubRule(
+ Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
+ SourceLocation SubRuleLoc) {
+ auto Diagnostic =
+ PRef.Diag(SubRuleLoc,
+ diag::err_pragma_attribute_expected_subject_sub_identifier)
+ << PrimaryRuleName;
+ if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule))
+ Diagnostic << /*SubRulesSupported=*/1 << SubRules;
+ else
+ Diagnostic << /*SubRulesSupported=*/0;
+}
+
+static void diagnoseUnknownAttributeSubjectSubRule(
+ Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
+ StringRef SubRuleName, SourceLocation SubRuleLoc) {
+
+ auto Diagnostic =
+ PRef.Diag(SubRuleLoc, diag::err_pragma_attribute_unknown_subject_sub_rule)
+ << SubRuleName << PrimaryRuleName;
+ if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule))
+ Diagnostic << /*SubRulesSupported=*/1 << SubRules;
+ else
+ Diagnostic << /*SubRulesSupported=*/0;
+}
+
+bool Parser::ParsePragmaAttributeSubjectMatchRuleSet(
+ attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, SourceLocation &AnyLoc,
+ SourceLocation &LastMatchRuleEndLoc) {
+ bool IsAny = false;
+ BalancedDelimiterTracker AnyParens(*this, tok::l_paren);
+ if (getIdentifier(Tok) == "any") {
+ AnyLoc = ConsumeToken();
+ IsAny = true;
+ if (AnyParens.expectAndConsume())
+ return true;
+ }
+
+ do {
+ // Parse the subject matcher rule.
+ StringRef Name = getIdentifier(Tok);
+ if (Name.empty()) {
+ Diag(Tok, diag::err_pragma_attribute_expected_subject_identifier);
+ return true;
+ }
+ std::pair<Optional<attr::SubjectMatchRule>,
+ Optional<attr::SubjectMatchRule> (*)(StringRef, bool)>
+ Rule = isAttributeSubjectMatchRule(Name);
+ if (!Rule.first) {
+ Diag(Tok, diag::err_pragma_attribute_unknown_subject_rule) << Name;
+ return true;
+ }
+ attr::SubjectMatchRule PrimaryRule = *Rule.first;
+ SourceLocation RuleLoc = ConsumeToken();
+
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ if (isAbstractAttrMatcherRule(PrimaryRule)) {
+ if (Parens.expectAndConsume())
+ return true;
+ } else if (Parens.consumeOpen()) {
+ if (!SubjectMatchRules
+ .insert(
+ std::make_pair(PrimaryRule, SourceRange(RuleLoc, RuleLoc)))
+ .second)
+ Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject)
+ << Name
+ << FixItHint::CreateRemoval(SourceRange(
+ RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleLoc));
+ LastMatchRuleEndLoc = RuleLoc;
+ continue;
+ }
+
+ // Parse the sub-rules.
+ StringRef SubRuleName = getIdentifier(Tok);
+ if (SubRuleName.empty()) {
+ diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ Tok.getLocation());
+ return true;
+ }
+ attr::SubjectMatchRule SubRule;
+ if (SubRuleName == "unless") {
+ SourceLocation SubRuleLoc = ConsumeToken();
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ if (Parens.expectAndConsume())
+ return true;
+ SubRuleName = getIdentifier(Tok);
+ if (SubRuleName.empty()) {
+ diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ SubRuleLoc);
+ return true;
+ }
+ auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/true);
+ if (!SubRuleOrNone) {
+ std::string SubRuleUnlessName = "unless(" + SubRuleName.str() + ")";
+ diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ SubRuleUnlessName, SubRuleLoc);
+ return true;
+ }
+ SubRule = *SubRuleOrNone;
+ ConsumeToken();
+ if (Parens.consumeClose())
+ return true;
+ } else {
+ auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/false);
+ if (!SubRuleOrNone) {
+ diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name,
+ SubRuleName, Tok.getLocation());
+ return true;
+ }
+ SubRule = *SubRuleOrNone;
+ ConsumeToken();
+ }
+ SourceLocation RuleEndLoc = Tok.getLocation();
+ LastMatchRuleEndLoc = RuleEndLoc;
+ if (Parens.consumeClose())
+ return true;
+ if (!SubjectMatchRules
+ .insert(std::make_pair(SubRule, SourceRange(RuleLoc, RuleEndLoc)))
+ .second) {
+ Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject)
+ << attr::getSubjectMatchRuleSpelling(SubRule)
+ << FixItHint::CreateRemoval(SourceRange(
+ RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleEndLoc));
+ continue;
+ }
+ } while (IsAny && TryConsumeToken(tok::comma));
+
+ if (IsAny)
+ if (AnyParens.consumeClose())
+ return true;
+
+ return false;
+}
+
+namespace {
+
+/// Describes the stage at which attribute subject rule parsing was interruped.
+enum class MissingAttributeSubjectRulesRecoveryPoint {
+ Comma,
+ ApplyTo,
+ Equals,
+ Any,
+ None,
+};
+
+MissingAttributeSubjectRulesRecoveryPoint
+getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) {
+ if (const auto *II = Tok.getIdentifierInfo()) {
+ if (II->isStr("apply_to"))
+ return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo;
+ if (II->isStr("any"))
+ return MissingAttributeSubjectRulesRecoveryPoint::Any;
+ }
+ if (Tok.is(tok::equal))
+ return MissingAttributeSubjectRulesRecoveryPoint::Equals;
+ return MissingAttributeSubjectRulesRecoveryPoint::None;
+}
+
+/// Creates a diagnostic for the attribute subject rule parsing diagnostic that
+/// suggests the possible attribute subject rules in a fix-it together with
+/// any other missing tokens.
+DiagnosticBuilder createExpectedAttributeSubjectRulesTokenDiagnostic(
+ unsigned DiagID, AttributeList &Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint Point, Parser &PRef) {
+ SourceLocation Loc = PRef.getEndOfPreviousToken();
+ if (Loc.isInvalid())
+ Loc = PRef.getCurToken().getLocation();
+ auto Diagnostic = PRef.Diag(Loc, DiagID);
+ std::string FixIt;
+ MissingAttributeSubjectRulesRecoveryPoint EndPoint =
+ getAttributeSubjectRulesRecoveryPointForToken(PRef.getCurToken());
+ if (Point == MissingAttributeSubjectRulesRecoveryPoint::Comma)
+ FixIt = ", ";
+ if (Point <= MissingAttributeSubjectRulesRecoveryPoint::ApplyTo &&
+ EndPoint > MissingAttributeSubjectRulesRecoveryPoint::ApplyTo)
+ FixIt += "apply_to";
+ if (Point <= MissingAttributeSubjectRulesRecoveryPoint::Equals &&
+ EndPoint > MissingAttributeSubjectRulesRecoveryPoint::Equals)
+ FixIt += " = ";
+ SourceRange FixItRange(Loc);
+ if (EndPoint == MissingAttributeSubjectRulesRecoveryPoint::None) {
+ // Gather the subject match rules that are supported by the attribute.
+ SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> SubjectMatchRuleSet;
+ Attribute.getMatchRules(PRef.getLangOpts(), SubjectMatchRuleSet);
+ if (SubjectMatchRuleSet.empty()) {
+ // FIXME: We can emit a "fix-it" with a subject list placeholder when
+ // placeholders will be supported by the fix-its.
+ return Diagnostic;
+ }
+ FixIt += "any(";
+ bool NeedsComma = false;
+ for (const auto &I : SubjectMatchRuleSet) {
+ // Ensure that the missing rule is reported in the fix-it only when it's
+ // supported in the current language mode.
+ if (!I.second)
+ continue;
+ if (NeedsComma)
+ FixIt += ", ";
+ else
+ NeedsComma = true;
+ FixIt += attr::getSubjectMatchRuleSpelling(I.first);
+ }
+ FixIt += ")";
+ // Check if we need to remove the range
+ PRef.SkipUntil(tok::eof, Parser::StopBeforeMatch);
+ FixItRange.setEnd(PRef.getCurToken().getLocation());
+ }
+ if (FixItRange.getBegin() == FixItRange.getEnd())
+ Diagnostic << FixItHint::CreateInsertion(FixItRange.getBegin(), FixIt);
+ else
+ Diagnostic << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(FixItRange), FixIt);
+ return Diagnostic;
+}
+
+} // end anonymous namespace
+
+void Parser::HandlePragmaAttribute() {
+ assert(Tok.is(tok::annot_pragma_attribute) &&
+ "Expected #pragma attribute annotation token");
+ SourceLocation PragmaLoc = Tok.getLocation();
+ auto *Info = static_cast<PragmaAttributeInfo *>(Tok.getAnnotationValue());
+ if (Info->Action == PragmaAttributeInfo::Pop) {
+ ConsumeAnnotationToken();
+ Actions.ActOnPragmaAttributePop(PragmaLoc);
+ return;
+ }
+ // Parse the actual attribute with its arguments.
+ assert(Info->Action == PragmaAttributeInfo::Push &&
+ "Unexpected #pragma attribute command");
+ PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false);
+ ConsumeAnnotationToken();
+
+ ParsedAttributes &Attrs = Info->Attributes;
+ Attrs.clearListOnly();
+
+ auto SkipToEnd = [this]() {
+ SkipUntil(tok::eof, StopBeforeMatch);
+ ConsumeToken();
+ };
+
+ if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
+ // Parse the CXX11 style attribute.
+ ParseCXX11AttributeSpecifier(Attrs);
+ } else if (Tok.is(tok::kw___attribute)) {
+ ConsumeToken();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "attribute"))
+ return SkipToEnd();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "("))
+ return SkipToEnd();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_pragma_attribute_expected_attribute_name);
+ SkipToEnd();
+ return;
+ }
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+
+ if (Tok.isNot(tok::l_paren))
+ Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ AttributeList::AS_GNU);
+ else
+ ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr,
+ /*ScopeName=*/nullptr,
+ /*ScopeLoc=*/SourceLocation(),
+ AttributeList::AS_GNU,
+ /*Declarator=*/nullptr);
+
+ if (ExpectAndConsume(tok::r_paren))
+ return SkipToEnd();
+ if (ExpectAndConsume(tok::r_paren))
+ return SkipToEnd();
+ } else if (Tok.is(tok::kw___declspec)) {
+ ParseMicrosoftDeclSpecs(Attrs);
+ } else {
+ Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax);
+ if (Tok.getIdentifierInfo()) {
+ // If we suspect that this is an attribute suggest the use of
+ // '__attribute__'.
+ if (AttributeList::getKind(Tok.getIdentifierInfo(), /*ScopeName=*/nullptr,
+ AttributeList::AS_GNU) !=
+ AttributeList::UnknownAttribute) {
+ SourceLocation InsertStartLoc = Tok.getLocation();
+ ConsumeToken();
+ if (Tok.is(tok::l_paren)) {
+ ConsumeAnyToken();
+ SkipUntil(tok::r_paren, StopBeforeMatch);
+ if (Tok.isNot(tok::r_paren))
+ return SkipToEnd();
+ }
+ Diag(Tok, diag::note_pragma_attribute_use_attribute_kw)
+ << FixItHint::CreateInsertion(InsertStartLoc, "__attribute__((")
+ << FixItHint::CreateInsertion(Tok.getEndLoc(), "))");
+ }
+ }
+ SkipToEnd();
+ return;
+ }
+
+ if (!Attrs.getList() || Attrs.getList()->isInvalid()) {
+ SkipToEnd();
+ return;
+ }
+
+ // Ensure that we don't have more than one attribute.
+ if (Attrs.getList()->getNext()) {
+ SourceLocation Loc = Attrs.getList()->getNext()->getLoc();
+ Diag(Loc, diag::err_pragma_attribute_multiple_attributes);
+ SkipToEnd();
+ return;
+ }
+
+ if (!Attrs.getList()->isSupportedByPragmaAttribute()) {
+ Diag(PragmaLoc, diag::err_pragma_attribute_unsupported_attribute)
+ << Attrs.getList()->getName();
+ SkipToEnd();
+ return;
+ }
+ AttributeList &Attribute = *Attrs.getList();
+
+ // Parse the subject-list.
+ if (!TryConsumeToken(tok::comma)) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_expected, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::Comma, *this)
+ << tok::comma;
+ SkipToEnd();
+ return;
+ }
+
+ if (Tok.isNot(tok::identifier)) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this);
+ SkipToEnd();
+ return;
+ }
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (!II->isStr("apply_to")) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this);
+ SkipToEnd();
+ return;
+ }
+ ConsumeToken();
+
+ if (!TryConsumeToken(tok::equal)) {
+ createExpectedAttributeSubjectRulesTokenDiagnostic(
+ diag::err_expected, Attribute,
+ MissingAttributeSubjectRulesRecoveryPoint::Equals, *this)
+ << tok::equal;
+ SkipToEnd();
+ return;
+ }
+
+ attr::ParsedSubjectMatchRuleSet SubjectMatchRules;
+ SourceLocation AnyLoc, LastMatchRuleEndLoc;
+ if (ParsePragmaAttributeSubjectMatchRuleSet(SubjectMatchRules, AnyLoc,
+ LastMatchRuleEndLoc)) {
+ SkipToEnd();
+ return;
+ }
+
+ // Tokens following an ill-formed attribute will remain in the token stream
+ // and must be removed.
+ if (Tok.isNot(tok::eof)) {
+ Diag(Tok, diag::err_pragma_attribute_extra_tokens_after_attribute);
+ SkipToEnd();
+ return;
+ }
+
+ // Consume the eof terminator token.
+ ConsumeToken();
+
+ Actions.ActOnPragmaAttributePush(Attribute, PragmaLoc,
+ std::move(SubjectMatchRules));
+}
+
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
@@ -1155,6 +1629,51 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true);
}
+// #pragma clang section bss="abc" data="" rodata="def" text=""
+void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer, Token &FirstToken) {
+
+ Token Tok;
+ auto SecKind = Sema::PragmaClangSectionKind::PCSK_Invalid;
+
+ PP.Lex(Tok); // eat 'section'
+ while (Tok.isNot(tok::eod)) {
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section";
+ return;
+ }
+
+ const IdentifierInfo *SecType = Tok.getIdentifierInfo();
+ if (SecType->isStr("bss"))
+ SecKind = Sema::PragmaClangSectionKind::PCSK_BSS;
+ else if (SecType->isStr("data"))
+ SecKind = Sema::PragmaClangSectionKind::PCSK_Data;
+ else if (SecType->isStr("rodata"))
+ SecKind = Sema::PragmaClangSectionKind::PCSK_Rodata;
+ else if (SecType->isStr("text"))
+ SecKind = Sema::PragmaClangSectionKind::PCSK_Text;
+ else {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section";
+ return;
+ }
+
+ PP.Lex(Tok); // eat ['bss'|'data'|'rodata'|'text']
+ if (Tok.isNot(tok::equal)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal) << SecKind;
+ return;
+ }
+
+ std::string SecName;
+ if (!PP.LexStringLiteral(Tok, SecName, "pragma clang section", false))
+ return;
+
+ Actions.ActOnPragmaClangSection(Tok.getLocation(),
+ (SecName.size()? Sema::PragmaClangSectionAction::PCSA_Set :
+ Sema::PragmaClangSectionAction::PCSA_Clear),
+ SecKind, SecName);
+ }
+}
+
// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok,
@@ -1947,6 +2466,129 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
}
+namespace {
+/// Used as the annotation value for tok::annot_pragma_fp.
+struct TokFPAnnotValue {
+ enum FlagKinds { Contract };
+ enum FlagValues { On, Off, Fast };
+
+ FlagKinds FlagKind;
+ FlagValues FlagValue;
+};
+} // end anonymous namespace
+
+void PragmaFPHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ // fp
+ Token PragmaName = Tok;
+ SmallVector<Token, 1> TokenList;
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+ << /*MissingOption=*/true << "";
+ return;
+ }
+
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
+
+ auto FlagKind =
+ llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagKinds>>(
+ OptionInfo->getName())
+ .Case("contract", TokFPAnnotValue::Contract)
+ .Default(None);
+ if (!FlagKind) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
+ << /*MissingOption=*/false << OptionInfo;
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Read '('
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+ return;
+ }
+ PP.Lex(Tok);
+
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+ << PP.getSpelling(Tok) << OptionInfo->getName();
+ return;
+ }
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+
+ auto FlagValue =
+ llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagValues>>(
+ II->getName())
+ .Case("on", TokFPAnnotValue::On)
+ .Case("off", TokFPAnnotValue::Off)
+ .Case("fast", TokFPAnnotValue::Fast)
+ .Default(llvm::None);
+
+ if (!FlagValue) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
+ << PP.getSpelling(Tok) << OptionInfo->getName();
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Read ')'
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+ return;
+ }
+ PP.Lex(Tok);
+
+ auto *AnnotValue = new (PP.getPreprocessorAllocator())
+ TokFPAnnotValue{*FlagKind, *FlagValue};
+ // Generate the loop hint token.
+ Token FPTok;
+ FPTok.startToken();
+ FPTok.setKind(tok::annot_pragma_fp);
+ FPTok.setLocation(PragmaName.getLocation());
+ FPTok.setAnnotationEndLoc(PragmaName.getLocation());
+ FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
+ TokenList.push_back(FPTok);
+ }
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "clang fp";
+ return;
+ }
+
+ auto TokenArray = llvm::make_unique<Token[]>(TokenList.size());
+ std::copy(TokenList.begin(), TokenList.end(), TokenArray.get());
+
+ PP.EnterTokenStream(std::move(TokenArray), TokenList.size(),
+ /*DisableMacroExpansion=*/false);
+}
+
+void Parser::HandlePragmaFP() {
+ assert(Tok.is(tok::annot_pragma_fp));
+ auto *AnnotValue =
+ reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
+
+ LangOptions::FPContractModeKind FPC;
+ switch (AnnotValue->FlagValue) {
+ case TokFPAnnotValue::On:
+ FPC = LangOptions::FPC_On;
+ break;
+ case TokFPAnnotValue::Fast:
+ FPC = LangOptions::FPC_Fast;
+ break;
+ case TokFPAnnotValue::Off:
+ FPC = LangOptions::FPC_Off;
+ break;
+ }
+
+ Actions.ActOnPragmaFPContract(FPC);
+ ConsumeAnnotationToken();
+}
+
/// \brief Parses loop or unroll pragma hint value and fills in Info.
static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
Token Option, bool ValueInParens,
@@ -2246,3 +2888,104 @@ void PragmaForceCUDAHostDeviceHandler::HandlePragma(
PP.Diag(FirstTok.getLocation(),
diag::warn_pragma_force_cuda_host_device_bad_arg);
}
+
+/// \brief Handle the #pragma clang attribute directive.
+///
+/// The syntax is:
+/// \code
+/// #pragma clang attribute push(attribute, subject-set)
+/// #pragma clang attribute pop
+/// \endcode
+///
+/// The subject-set clause defines the set of declarations which receive the
+/// attribute. Its exact syntax is described in the LanguageExtensions document
+/// in Clang's documentation.
+///
+/// This directive instructs the compiler to begin/finish applying the specified
+/// attribute to the set of attribute-specific declarations in the active range
+/// of the pragma.
+void PragmaAttributeHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &FirstToken) {
+ Token Tok;
+ PP.Lex(Tok);
+ auto *Info = new (PP.getPreprocessorAllocator())
+ PragmaAttributeInfo(AttributesForPragmaAttribute);
+
+ // Parse the 'push' or 'pop'.
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_push_pop);
+ return;
+ }
+ const auto *II = Tok.getIdentifierInfo();
+ if (II->isStr("push"))
+ Info->Action = PragmaAttributeInfo::Push;
+ else if (II->isStr("pop"))
+ Info->Action = PragmaAttributeInfo::Pop;
+ else {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_invalid_argument)
+ << PP.getSpelling(Tok);
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Parse the actual attribute.
+ if (Info->Action == PragmaAttributeInfo::Push) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+ return;
+ }
+ PP.Lex(Tok);
+
+ // Lex the attribute tokens.
+ SmallVector<Token, 16> AttributeTokens;
+ int OpenParens = 1;
+ while (Tok.isNot(tok::eod)) {
+ if (Tok.is(tok::l_paren))
+ OpenParens++;
+ else if (Tok.is(tok::r_paren)) {
+ OpenParens--;
+ if (OpenParens == 0)
+ break;
+ }
+
+ AttributeTokens.push_back(Tok);
+ PP.Lex(Tok);
+ }
+
+ if (AttributeTokens.empty()) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_attribute);
+ return;
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+ return;
+ }
+ SourceLocation EndLoc = Tok.getLocation();
+ PP.Lex(Tok);
+
+ // Terminate the attribute for parsing.
+ Token EOFTok;
+ EOFTok.startToken();
+ EOFTok.setKind(tok::eof);
+ EOFTok.setLocation(EndLoc);
+ AttributeTokens.push_back(EOFTok);
+
+ Info->Tokens =
+ llvm::makeArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator());
+ }
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "clang attribute";
+
+ // Generate the annotated pragma token.
+ auto TokenArray = llvm::make_unique<Token[]>(1);
+ TokenArray[0].startToken();
+ TokenArray[0].setKind(tok::annot_pragma_attribute);
+ TokenArray[0].setLocation(FirstToken.getLocation());
+ TokenArray[0].setAnnotationEndLoc(FirstToken.getLocation());
+ TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
+ PP.EnterTokenStream(std::move(TokenArray), 1,
+ /*DisableMacroExpansion=*/false);
+}
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp
index 30e392f..b1fbb20 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp
@@ -12,10 +12,10 @@
//
//===----------------------------------------------------------------------===//
-#include "RAIIObjectsForParser.h"
#include "clang/Basic/Attributes.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/LoopHint.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
@@ -97,7 +97,7 @@ StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc,
///
StmtResult
Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
- AllowedContsructsKind Allowed,
+ AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -150,7 +150,7 @@ private:
StmtResult
Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts,
- AllowedContsructsKind Allowed, SourceLocation *TrailingElseLoc,
+ AllowedConstructsKind Allowed, SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs) {
const char *SemiError = nullptr;
StmtResult Res;
@@ -203,6 +203,7 @@ Retry:
}
// Fall through
+ LLVM_FALLTHROUGH;
}
default: {
@@ -338,7 +339,13 @@ Retry:
case tok::annot_pragma_fp_contract:
ProhibitAttributes(Attrs);
Diag(Tok, diag::err_pragma_fp_contract_scope);
- ConsumeToken();
+ ConsumeAnnotationToken();
+ return StmtError();
+
+ case tok::annot_pragma_fp:
+ ProhibitAttributes(Attrs);
+ Diag(Tok, diag::err_pragma_fp_scope);
+ ConsumeAnnotationToken();
return StmtError();
case tok::annot_pragma_opencl_extension:
@@ -376,6 +383,10 @@ Retry:
case tok::annot_pragma_dump:
HandlePragmaDump();
return StmtEmpty();
+
+ case tok::annot_pragma_attribute:
+ HandlePragmaAttribute();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
@@ -900,6 +911,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
case tok::annot_pragma_fp_contract:
HandlePragmaFPContract();
break;
+ case tok::annot_pragma_fp:
+ HandlePragmaFP();
+ break;
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
break;
@@ -1179,7 +1193,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
StmtResult ThenStmt;
{
EnterExpressionEvaluationContext PotentiallyDiscarded(
- Actions, Sema::DiscardedStatement, nullptr, false,
+ Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr,
+ false,
/*ShouldEnter=*/ConstexprCondition && !*ConstexprCondition);
ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc);
}
@@ -1212,7 +1227,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
Tok.is(tok::l_brace));
EnterExpressionEvaluationContext PotentiallyDiscarded(
- Actions, Sema::DiscardedStatement, nullptr, false,
+ Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr,
+ false,
/*ShouldEnter=*/ConstexprCondition && *ConstexprCondition);
ElseStmt = ParseStatement();
@@ -1898,12 +1914,12 @@ StmtResult Parser::ParseReturnStatement() {
}
}
if (IsCoreturn)
- return Actions.ActOnCoreturnStmt(ReturnLoc, R.get());
+ return Actions.ActOnCoreturnStmt(getCurScope(), ReturnLoc, R.get());
return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope());
}
StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts,
- AllowedContsructsKind Allowed,
+ AllowedConstructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs) {
// Create temporary attribute list.
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp
index 293de78..d6f16bb 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -224,6 +224,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
/*EnteringContext=*/false,
/*AllowDestructorName=*/false,
/*AllowConstructorName=*/false,
+ /*AllowDeductionGuide=*/false,
/*ObjectType=*/nullptr, TemplateKWLoc, Id);
// Perform the lookup.
Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
@@ -451,12 +452,17 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
// We're no longer in a comment.
InAsmComment = false;
if (isAsm) {
- // If this is a new __asm {} block we want to process it seperately
+ // If this is a new __asm {} block we want to process it separately
// from the single-line __asm statements
if (PP.LookAhead(0).is(tok::l_brace))
break;
LineNo = SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second);
SkippedStartOfLine = Tok.isAtStartOfLine();
+ } else if (Tok.is(tok::semi)) {
+ // A multi-line asm-statement, where next line is a comment
+ InAsmComment = true;
+ FID = ExpLoc.first;
+ LineNo = SrcMgr.getLineNumber(FID, ExpLoc.second);
}
} else if (!InAsmComment && Tok.is(tok::r_brace)) {
// In MSVC mode, braces only participate in brace matching and
@@ -615,10 +621,11 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
MII.get(), IP.get(), Callback))
return StmtError();
- // Filter out "fpsw". Clang doesn't accept it, and it always lists flags and
- // fpsr as clobbers.
- auto End = std::remove(Clobbers.begin(), Clobbers.end(), "fpsw");
- Clobbers.erase(End, Clobbers.end());
+ // Filter out "fpsw" and "mxcsr". They aren't valid GCC asm clobber
+ // constraints. Clang always adds fpsr to the clobber list anyway.
+ llvm::erase_if(Clobbers, [](const std::string &C) {
+ return C == "fpsw" || C == "mxcsr";
+ });
// Build the vector of clobber StringRefs.
ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end());
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp
index 6a09ea7..944cd77 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
@@ -674,7 +674,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// FIXME: The type should probably be restricted in some way... Not all
// declarators (parts of declarators?) are accepted for parameters.
DeclSpec DS(AttrFactory);
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
+ DSC_template_param);
// Parse this as a typename.
Declarator ParamDecl(DS, Declarator::TemplateParamContext);
@@ -701,8 +702,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// end of the template-parameter-list rather than a greater-than
// operator.
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
- EnterExpressionEvaluationContext ConstantEvaluated(Actions,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
if (DefaultArg.isInvalid())
@@ -886,22 +887,12 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
/// list ('<' template-parameter-list [opt] '>') and placing the
/// results into a form that can be transferred to semantic analysis.
///
-/// \param Template the template declaration produced by isTemplateName
-///
-/// \param TemplateNameLoc the source location of the template name
-///
-/// \param SS if non-NULL, the nested-name-specifier preceding the
-/// template name.
-///
/// \param ConsumeLastToken if true, then we will consume the last
/// token that forms the template-id. Otherwise, we will leave the
/// last token in the stream (e.g., so that it can be replaced with an
/// annotation token).
bool
-Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
- SourceLocation TemplateNameLoc,
- const CXXScopeSpec &SS,
- bool ConsumeLastToken,
+Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken,
SourceLocation &LAngleLoc,
TemplateArgList &TemplateArgs,
SourceLocation &RAngleLoc) {
@@ -983,9 +974,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Parse the enclosed template argument list.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
- bool Invalid = ParseTemplateIdAfterTemplateName(Template,
- TemplateNameLoc,
- SS, false, LAngleLoc,
+ bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc,
TemplateArgs,
RAngleLoc);
@@ -1000,13 +989,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Build the annotation token.
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
- TypeResult Type
- = Actions.ActOnTemplateIdType(SS, TemplateKWLoc,
- Template, TemplateNameLoc,
- LAngleLoc, TemplateArgsPtr, RAngleLoc);
+ TypeResult Type = Actions.ActOnTemplateIdType(
+ SS, TemplateKWLoc, Template, TemplateName.Identifier,
+ TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc);
if (Type.isInvalid()) {
- // If we failed to parse the template ID but skipped ahead to a >, we're not
- // going to be able to form a token annotation. Eat the '>' if present.
+ // If we failed to parse the template ID but skipped ahead to a >, we're
+ // not going to be able to form a token annotation. Eat the '>' if
+ // present.
TryConsumeToken(tok::greater);
return true;
}
@@ -1023,25 +1012,21 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Build a template-id annotation token that can be processed
// later.
Tok.setKind(tok::annot_template_id);
- TemplateIdAnnotation *TemplateId
- = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
- TemplateId->TemplateNameLoc = TemplateNameLoc;
- if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) {
- TemplateId->Name = TemplateName.Identifier;
- TemplateId->Operator = OO_None;
- } else {
- TemplateId->Name = nullptr;
- TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
- }
- TemplateId->SS = SS;
- TemplateId->TemplateKWLoc = TemplateKWLoc;
- TemplateId->Template = Template;
- TemplateId->Kind = TNK;
- TemplateId->LAngleLoc = LAngleLoc;
- TemplateId->RAngleLoc = RAngleLoc;
- ParsedTemplateArgument *Args = TemplateId->getTemplateArgs();
- for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
- Args[Arg] = ParsedTemplateArgument(TemplateArgs[Arg]);
+
+ IdentifierInfo *TemplateII =
+ TemplateName.getKind() == UnqualifiedId::IK_Identifier
+ ? TemplateName.Identifier
+ : nullptr;
+
+ OverloadedOperatorKind OpKind =
+ TemplateName.getKind() == UnqualifiedId::IK_Identifier
+ ? OO_None
+ : TemplateName.OperatorFunctionId.Operator;
+
+ TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
+ SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
+ LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
+
Tok.setAnnotationValue(TemplateId);
if (TemplateKWLoc.isValid())
Tok.setLocation(TemplateKWLoc);
@@ -1064,7 +1049,12 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
/// If there was a failure when forming the type from the template-id,
/// a type annotation token will still be created, but will have a
/// NULL type pointer to signify an error.
-void Parser::AnnotateTemplateIdTokenAsType() {
+///
+/// \param IsClassName Is this template-id appearing in a context where we
+/// know it names a class, such as in an elaborated-type-specifier or
+/// base-specifier? ('typename' and 'template' are unneeded and disallowed
+/// in those contexts.)
+void Parser::AnnotateTemplateIdTokenAsType(bool IsClassName) {
assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
@@ -1079,10 +1069,13 @@ void Parser::AnnotateTemplateIdTokenAsType() {
= Actions.ActOnTemplateIdType(TemplateId->SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
+ TemplateId->Name,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
- TemplateId->RAngleLoc);
+ TemplateId->RAngleLoc,
+ /*IsCtorOrDtorName*/false,
+ IsClassName);
// Create the new "type" annotation token.
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get());
@@ -1190,7 +1183,13 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
// expression is resolved to a type-id, regardless of the form of
// the corresponding template-parameter.
//
- // Therefore, we initially try to parse a type-id.
+ // Therefore, we initially try to parse a type-id - and isCXXTypeId might look
+ // up and annotate an identifier as an id-expression during disambiguation,
+ // so enter the appropriate context for a constant expression template
+ // argument before trying to disambiguate.
+
+ EnterExpressionEvaluationContext EnterConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
if (isCXXTypeId(TypeIdAsTemplateArgument)) {
SourceLocation Loc = Tok.getLocation();
TypeResult TypeArg = ParseTypeName(/*Range=*/nullptr,
@@ -1220,7 +1219,7 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
// Parse a non-type template argument.
SourceLocation Loc = Tok.getLocation();
- ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast);
+ ExprResult ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast);
if (ExprArg.isInvalid() || !ExprArg.get())
return ParsedTemplateArgument();
@@ -1238,7 +1237,7 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
} Tentative(*this);
while (Skip) {
- ConsumeToken();
+ ConsumeAnyToken();
--Skip;
}
@@ -1252,7 +1251,7 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
// See whether we have declaration specifiers, which indicate a type.
while (isCXXDeclarationSpecifier() == TPResult::True)
- ConsumeToken();
+ ConsumeAnyToken();
// If we have a '>' or a ',' then this is a template argument list.
return Tok.isOneOf(tok::greater, tok::comma);
@@ -1266,8 +1265,7 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
/// template-argument-list ',' template-argument
bool
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
- // Template argument lists are constant-evaluation contexts.
- EnterExpressionEvaluationContext EvalContext(Actions,Sema::ConstantEvaluated);
+
ColonProtectionRAIIObject ColonProtection(*this, false);
do {
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp
index 0ea3f8d..d6684c3 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp
@@ -208,17 +208,20 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
TryAnnotateCXXScopeToken())
return TPResult::Error;
if (Tok.is(tok::annot_cxxscope))
+ ConsumeAnnotationToken();
+ if (Tok.is(tok::identifier))
ConsumeToken();
- if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
+ else if (Tok.is(tok::annot_template_id))
+ ConsumeAnnotationToken();
+ else
return TPResult::Error;
- ConsumeToken();
break;
case tok::annot_cxxscope:
- ConsumeToken();
+ ConsumeAnnotationToken();
// Fall through.
default:
- ConsumeToken();
+ ConsumeAnyToken();
if (getLangOpts().ObjC1 && Tok.is(tok::less))
return TryParseProtocolQualifiers();
@@ -478,10 +481,10 @@ Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement) {
/// the corresponding ')'. If the context is
/// TypeIdAsTemplateArgument, we've already parsed the '<' or ','
/// before this template argument, and will cease lookahead when we
- /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id
- /// and false for an expression. If during the disambiguation
- /// process a parsing error is encountered, the function returns
- /// true to let the declaration parsing code handle it.
+ /// hit a '>', '>>' (in C++0x), or ','; or, in C++0x, an ellipsis immediately
+ /// preceding such. Returns true for a type-id and false for an expression.
+ /// If during the disambiguation process a parsing error is encountered,
+ /// the function returns true to let the declaration parsing code handle it.
///
/// type-id:
/// type-specifier-seq abstract-declarator[opt]
@@ -530,10 +533,15 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
// We are supposed to be inside a template argument, so if after
// the abstract declarator we encounter a '>', '>>' (in C++0x), or
- // ',', this is a type-id. Otherwise, it's an expression.
+ // ','; or, in C++0x, an ellipsis immediately preceding such, this
+ // is a type-id. Otherwise, it's an expression.
} else if (Context == TypeIdAsTemplateArgument &&
(Tok.isOneOf(tok::greater, tok::comma) ||
- (getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater)))) {
+ (getLangOpts().CPlusPlus11 &&
+ (Tok.is(tok::greatergreater) ||
+ (Tok.is(tok::ellipsis) &&
+ NextToken().isOneOf(tok::greater, tok::greatergreater,
+ tok::comma)))))) {
TPR = TPResult::True;
isAmbiguous = true;
@@ -706,7 +714,7 @@ Parser::TPResult Parser::TryParsePtrOperatorSeq() {
if (Tok.isOneOf(tok::star, tok::amp, tok::caret, tok::ampamp) ||
(Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
// ptr-operator
- ConsumeToken();
+ ConsumeAnyToken();
while (Tok.isOneOf(tok::kw_const, tok::kw_volatile, tok::kw_restrict,
tok::kw__Nonnull, tok::kw__Nullable,
tok::kw__Null_unspecified))
@@ -826,14 +834,14 @@ Parser::TPResult Parser::TryParseOperatorId() {
/// abstract-declarator:
/// ptr-operator abstract-declarator[opt]
/// direct-abstract-declarator
-/// ...
///
/// direct-abstract-declarator:
/// direct-abstract-declarator[opt]
-/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
+/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
/// exception-specification[opt]
/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
/// '(' abstract-declarator ')'
+/// [C++0x] ...
///
/// ptr-operator:
/// '*' cv-qualifier-seq[opt]
@@ -883,7 +891,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
mayHaveIdentifier) {
// declarator-id
if (Tok.is(tok::annot_cxxscope))
- ConsumeToken();
+ ConsumeAnnotationToken();
else if (Tok.is(tok::identifier))
TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo());
if (Tok.is(tok::kw_operator)) {
@@ -925,10 +933,6 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
while (1) {
TPResult TPR(TPResult::Ambiguous);
- // abstract-declarator: ...
- if (Tok.is(tok::ellipsis))
- ConsumeToken();
-
if (Tok.is(tok::l_paren)) {
// Check whether we have a function declarator or a possible ctor-style
// initializer that follows the declarator. Note that ctor-style
@@ -1399,7 +1403,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
SS);
if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) {
RevertingTentativeParsingAction PA(*this);
- ConsumeToken();
+ ConsumeAnnotationToken();
ConsumeToken();
bool isIdentifier = Tok.is(tok::identifier);
TPResult TPR = TPResult::False;
@@ -1446,6 +1450,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
return TPResult::False;
}
// If that succeeded, fallthrough into the generic simple-type-id case.
+ LLVM_FALLTHROUGH;
// The ambiguity resides in a simple-type-specifier/typename-specifier
// followed by a '('. The '(' could either be the start of:
@@ -1471,7 +1476,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
if (getLangOpts().ObjC1 && NextToken().is(tok::less)) {
// Tentatively parse the protocol qualifiers.
RevertingTentativeParsingAction PA(*this);
- ConsumeToken(); // The type token
+ ConsumeAnyToken(); // The type token
TPResult TPR = TryParseProtocolQualifiers();
bool isFollowedByParen = Tok.is(tok::l_paren);
@@ -1488,6 +1493,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
return TPResult::True;
}
+ LLVM_FALLTHROUGH;
case tok::kw_char:
case tok::kw_wchar_t:
diff --git a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp
index 52e5194..1ed7ef9 100644
--- a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp
+++ b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
@@ -37,26 +37,6 @@ public:
return false;
}
};
-
-/// \brief RAIIObject to destroy the contents of a SmallVector of
-/// TemplateIdAnnotation pointers and clear the vector.
-class DestroyTemplateIdAnnotationsRAIIObj {
- SmallVectorImpl<TemplateIdAnnotation *> &Container;
-
-public:
- DestroyTemplateIdAnnotationsRAIIObj(
- SmallVectorImpl<TemplateIdAnnotation *> &Container)
- : Container(Container) {}
-
- ~DestroyTemplateIdAnnotationsRAIIObj() {
- for (SmallVectorImpl<TemplateIdAnnotation *>::iterator I =
- Container.begin(),
- E = Container.end();
- I != E; ++I)
- (*I)->Destroy();
- Container.clear();
- }
-};
} // end anonymous namespace
IdentifierInfo *Parser::getSEHExceptKeyword() {
@@ -231,6 +211,21 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
<< FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
}
+bool Parser::expectIdentifier() {
+ if (Tok.is(tok::identifier))
+ return false;
+ if (const auto *II = Tok.getIdentifierInfo()) {
+ if (II->isCPlusPlusKeyword(getLangOpts())) {
+ Diag(Tok, diag::err_expected_token_instead_of_objcxx_keyword)
+ << tok::identifier << Tok.getIdentifierInfo();
+ // Objective-C++: Recover by treating this keyword as a valid identifier.
+ return false;
+ }
+ }
+ Diag(Tok, diag::err_expected) << tok::identifier;
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Error recovery.
//===----------------------------------------------------------------------===//
@@ -342,21 +337,13 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
ConsumeBrace();
break;
- case tok::string_literal:
- case tok::wide_string_literal:
- case tok::utf8_string_literal:
- case tok::utf16_string_literal:
- case tok::utf32_string_literal:
- ConsumeStringToken();
- break;
-
case tok::semi:
if (HasFlagsSet(Flags, StopAtSemi))
return false;
// FALL THROUGH.
default:
// Skip this token.
- ConsumeToken();
+ ConsumeAnyToken();
break;
}
isFirstTokenSkipped = false;
@@ -493,6 +480,8 @@ void Parser::Initialize() {
Ident_strict = nullptr;
Ident_replacement = nullptr;
+ Ident_language = Ident_defined_in = Ident_generated_declaration = nullptr;
+
Ident__except = nullptr;
Ident__exception_code = Ident__exception_info = nullptr;
@@ -537,22 +526,7 @@ void Parser::LateTemplateParserCleanupCallback(void *P) {
}
bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) {
- // C++ Modules TS: module-declaration must be the first declaration in the
- // file. (There can be no preceding preprocessor directives, but we expect
- // the lexer to check that.)
- if (Tok.is(tok::kw_module)) {
- Result = ParseModuleDecl();
- return false;
- } else if (getLangOpts().getCompilingModule() ==
- LangOptions::CMK_ModuleInterface) {
- // FIXME: We avoid providing this diagnostic when generating an object file
- // from an existing PCM file. This is not a good way to detect this
- // condition; we should provide a mechanism to indicate whether we've
- // already parsed a declaration in this translation unit and avoid calling
- // ParseFirstTopLevelDecl in that case.
- if (Actions.TUKind == TU_Module)
- Diag(Tok, diag::err_expected_module_interface_decl);
- }
+ Actions.ActOnStartOfTranslationUnit();
// C11 6.9p1 says translation units must have at least one top-level
// declaration. C++ doesn't have this restriction. We also don't want to
@@ -586,23 +560,35 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
Result = ParseModuleImport(SourceLocation());
return false;
+ case tok::kw_export:
+ if (NextToken().isNot(tok::kw_module))
+ break;
+ LLVM_FALLTHROUGH;
+ case tok::kw_module:
+ Result = ParseModuleDecl();
+ return false;
+
case tok::annot_module_include:
Actions.ActOnModuleInclude(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
case tok::annot_module_begin:
Actions.ActOnModuleBegin(Tok.getLocation(), reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
return false;
case tok::annot_module_end:
Actions.ActOnModuleEnd(Tok.getLocation(), reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
+ return false;
+
+ case tok::annot_pragma_attribute:
+ HandlePragmaAttribute();
return false;
case tok::eof:
@@ -688,6 +674,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_fp_contract:
HandlePragmaFPContract();
return nullptr;
+ case tok::annot_pragma_fp:
+ HandlePragmaFP();
+ break;
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
return nullptr;
@@ -776,6 +765,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
}
// This must be 'export template'. Parse it so we can diagnose our lack
// of support.
+ LLVM_FALLTHROUGH;
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
@@ -847,6 +837,10 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
default:
dont_know:
+ if (Tok.isEditorPlaceholder()) {
+ ConsumeToken();
+ return nullptr;
+ }
// We can't tell whether this is a function-definition or declaration yet.
return ParseDeclarationOrFunctionDefinition(attrs, DS);
}
@@ -1675,6 +1669,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
return false;
}
}
+ if (Tok.isEditorPlaceholder())
+ return true;
Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
return true;
@@ -1701,6 +1697,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
+ TemplateId->Name,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
@@ -1742,7 +1739,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS,
false, NextToken().is(tok::period), nullptr,
/*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo*/ true)) {
+ /*NonTrivialTypeSourceInfo*/ true,
+ /*IsClassTemplateDeductionContext*/GreaterThanIsOperator)) {
SourceLocation BeginLoc = Tok.getLocation();
if (SS.isNotEmpty()) // it was a C++ qualified type name.
BeginLoc = SS.getBeginLoc();
@@ -1880,6 +1878,7 @@ bool Parser::isTokenEqualOrEqualTypo() {
Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal)
<< Kind
<< FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "=");
+ LLVM_FALLTHROUGH;
case tok::equal:
return true;
}
@@ -1964,8 +1963,10 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
// Parse the unqualified-id.
SourceLocation TemplateKWLoc; // FIXME: parsed, but unused.
- if (ParseUnqualifiedId(Result.SS, false, true, true, nullptr, TemplateKWLoc,
- Result.Name)) {
+ if (ParseUnqualifiedId(
+ Result.SS, /*EnteringContext*/false, /*AllowDestructorName*/true,
+ /*AllowConstructorName*/true, /*AllowDeductionGuide*/false, nullptr,
+ TemplateKWLoc, Result.Name)) {
T.skipToEnd();
return true;
}
@@ -2035,30 +2036,28 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
/// Parse a C++ Modules TS module declaration, which appears at the beginning
/// of a module interface, module partition, or module implementation file.
///
-/// module-declaration: [Modules TS + P0273R0]
-/// 'module' module-kind[opt] module-name attribute-specifier-seq[opt] ';'
-/// module-kind:
-/// 'implementation'
-/// 'partition'
+/// module-declaration: [Modules TS + P0273R0 + P0629R0]
+/// 'export'[opt] 'module' 'partition'[opt]
+/// module-name attribute-specifier-seq[opt] ';'
///
-/// Note that the module-kind values are context-sensitive keywords.
+/// Note that 'partition' is a context-sensitive keyword.
Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
- assert(Tok.is(tok::kw_module) && getLangOpts().ModulesTS &&
- "should not be parsing a module declaration");
+ SourceLocation StartLoc = Tok.getLocation();
+
+ Sema::ModuleDeclKind MDK = TryConsumeToken(tok::kw_export)
+ ? Sema::ModuleDeclKind::Module
+ : Sema::ModuleDeclKind::Implementation;
+
+ assert(Tok.is(tok::kw_module) && "not a module declaration");
SourceLocation ModuleLoc = ConsumeToken();
- // Check for a module-kind.
- Sema::ModuleDeclKind MDK = Sema::ModuleDeclKind::Module;
- if (Tok.is(tok::identifier) && NextToken().is(tok::identifier)) {
- if (Tok.getIdentifierInfo()->isStr("implementation"))
- MDK = Sema::ModuleDeclKind::Implementation;
- else if (Tok.getIdentifierInfo()->isStr("partition"))
- MDK = Sema::ModuleDeclKind::Partition;
- else {
- Diag(Tok, diag::err_unexpected_module_kind) << Tok.getIdentifierInfo();
- SkipUntil(tok::semi);
- return nullptr;
- }
+ if (Tok.is(tok::identifier) && NextToken().is(tok::identifier) &&
+ Tok.getIdentifierInfo()->isStr("partition")) {
+ // If 'partition' is present, this must be a module interface unit.
+ if (MDK != Sema::ModuleDeclKind::Module)
+ Diag(Tok.getLocation(), diag::err_module_implementation_partition)
+ << FixItHint::CreateInsertion(ModuleLoc, "export ");
+ MDK = Sema::ModuleDeclKind::Partition;
ConsumeToken();
}
@@ -2066,14 +2065,14 @@ Parser::DeclGroupPtrTy Parser::ParseModuleDecl() {
if (ParseModuleName(ModuleLoc, Path, /*IsImport*/false))
return nullptr;
+ // We don't support any module attributes yet; just parse them and diagnose.
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
- // We don't support any module attributes yet.
ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr);
ExpectAndConsumeSemi(diag::err_module_expected_semi);
- return Actions.ActOnModuleDecl(ModuleLoc, MDK, Path);
+ return Actions.ActOnModuleDecl(StartLoc, ModuleLoc, MDK, Path);
}
/// Parse a module import declaration. This is essentially the same for
@@ -2166,7 +2165,7 @@ bool Parser::parseMisplacedModuleImport() {
Actions.ActOnModuleEnd(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
continue;
}
// Inform caller that recovery failed, the error must be handled at upper
@@ -2178,7 +2177,7 @@ bool Parser::parseMisplacedModuleImport() {
Actions.ActOnModuleBegin(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
++MisplacedModuleBeginCount;
continue;
case tok::annot_module_include:
@@ -2187,7 +2186,7 @@ bool Parser::parseMisplacedModuleImport() {
Actions.ActOnModuleInclude(Tok.getLocation(),
reinterpret_cast<Module *>(
Tok.getAnnotationValue()));
- ConsumeToken();
+ ConsumeAnnotationToken();
// If there is another module import, process it.
continue;
default:
diff --git a/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp b/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp
index 27bb976..9e307f3 100644
--- a/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -409,6 +409,7 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
++TokOffs;
--TokLen;
// FALL THROUGH to chop the 8
+ LLVM_FALLTHROUGH;
case tok::wide_string_literal:
case tok::utf16_string_literal:
case tok::utf32_string_literal:
diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
index a987a8c..f83baa7 100644
--- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -279,6 +279,159 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
}
//===----------------------------------------------------------------------===//
+// Check for throw in a non-throwing function.
+//===----------------------------------------------------------------------===//
+enum ThrowState {
+ FoundNoPathForThrow,
+ FoundPathForThrow,
+ FoundPathWithNoThrowOutFunction,
+};
+
+static bool isThrowCaught(const CXXThrowExpr *Throw,
+ const CXXCatchStmt *Catch) {
+ const Type *ThrowType = nullptr;
+ if (Throw->getSubExpr())
+ ThrowType = Throw->getSubExpr()->getType().getTypePtrOrNull();
+ if (!ThrowType)
+ return false;
+ const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull();
+ if (!CaughtType)
+ return true;
+ if (ThrowType->isReferenceType())
+ ThrowType = ThrowType->castAs<ReferenceType>()
+ ->getPointeeType()
+ ->getUnqualifiedDesugaredType();
+ if (CaughtType->isReferenceType())
+ CaughtType = CaughtType->castAs<ReferenceType>()
+ ->getPointeeType()
+ ->getUnqualifiedDesugaredType();
+ if (ThrowType->isPointerType() && CaughtType->isPointerType()) {
+ ThrowType = ThrowType->getPointeeType()->getUnqualifiedDesugaredType();
+ CaughtType = CaughtType->getPointeeType()->getUnqualifiedDesugaredType();
+ }
+ if (CaughtType == ThrowType)
+ return true;
+ const CXXRecordDecl *CaughtAsRecordType =
+ CaughtType->getAsCXXRecordDecl();
+ const CXXRecordDecl *ThrowTypeAsRecordType = ThrowType->getAsCXXRecordDecl();
+ if (CaughtAsRecordType && ThrowTypeAsRecordType)
+ return ThrowTypeAsRecordType->isDerivedFrom(CaughtAsRecordType);
+ return false;
+}
+
+static bool isThrowCaughtByHandlers(const CXXThrowExpr *CE,
+ const CXXTryStmt *TryStmt) {
+ for (unsigned H = 0, E = TryStmt->getNumHandlers(); H < E; ++H) {
+ if (isThrowCaught(CE, TryStmt->getHandler(H)))
+ return true;
+ }
+ return false;
+}
+
+static bool doesThrowEscapePath(CFGBlock Block, SourceLocation &OpLoc) {
+ for (const auto &B : Block) {
+ if (B.getKind() != CFGElement::Statement)
+ continue;
+ const auto *CE = dyn_cast<CXXThrowExpr>(B.getAs<CFGStmt>()->getStmt());
+ if (!CE)
+ continue;
+
+ OpLoc = CE->getThrowLoc();
+ for (const auto &I : Block.succs()) {
+ if (!I.isReachable())
+ continue;
+ if (const auto *Terminator =
+ dyn_cast_or_null<CXXTryStmt>(I->getTerminator()))
+ if (isThrowCaughtByHandlers(CE, Terminator))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) {
+
+ unsigned ExitID = BodyCFG->getExit().getBlockID();
+
+ SmallVector<ThrowState, 16> States(BodyCFG->getNumBlockIDs(),
+ FoundNoPathForThrow);
+ States[BodyCFG->getEntry().getBlockID()] = FoundPathWithNoThrowOutFunction;
+
+ SmallVector<CFGBlock *, 16> Stack;
+ Stack.push_back(&BodyCFG->getEntry());
+ while (!Stack.empty()) {
+ CFGBlock *CurBlock = Stack.back();
+ Stack.pop_back();
+
+ unsigned ID = CurBlock->getBlockID();
+ ThrowState CurState = States[ID];
+ if (CurState == FoundPathWithNoThrowOutFunction) {
+ if (ExitID == ID)
+ continue;
+
+ if (doesThrowEscapePath(*CurBlock, OpLoc))
+ CurState = FoundPathForThrow;
+ }
+
+ // Loop over successor blocks and add them to the Stack if their state
+ // changes.
+ for (const auto &I : CurBlock->succs())
+ if (I.isReachable()) {
+ unsigned NextID = I->getBlockID();
+ if (NextID == ExitID && CurState == FoundPathForThrow) {
+ States[NextID] = CurState;
+ } else if (States[NextID] < CurState) {
+ States[NextID] = CurState;
+ Stack.push_back(I);
+ }
+ }
+ }
+ // Return true if the exit node is reachable, and only reachable through
+ // a throw expression.
+ return States[ExitID] == FoundPathForThrow;
+}
+
+static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc,
+ const FunctionDecl *FD) {
+ if (!S.getSourceManager().isInSystemHeader(OpLoc) &&
+ FD->getTypeSourceInfo()) {
+ S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
+ if (S.getLangOpts().CPlusPlus11 &&
+ (isa<CXXDestructorDecl>(FD) ||
+ FD->getDeclName().getCXXOverloadedOperator() == OO_Delete ||
+ FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) {
+ if (const auto *Ty = FD->getTypeSourceInfo()->getType()->
+ getAs<FunctionProtoType>())
+ S.Diag(FD->getLocation(), diag::note_throw_in_dtor)
+ << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec()
+ << FD->getExceptionSpecSourceRange();
+ } else
+ S.Diag(FD->getLocation(), diag::note_throw_in_function)
+ << FD->getExceptionSpecSourceRange();
+ }
+}
+
+static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD,
+ AnalysisDeclContext &AC) {
+ CFG *BodyCFG = AC.getCFG();
+ if (!BodyCFG)
+ return;
+ if (BodyCFG->getExit().pred_empty())
+ return;
+ SourceLocation OpLoc;
+ if (hasThrowOutNonThrowingFunc(OpLoc, BodyCFG))
+ EmitDiagForCXXThrowInNonThrowingFunc(S, OpLoc, FD);
+}
+
+static bool isNoexcept(const FunctionDecl *FD) {
+ const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+ if (FPT->isNothrow(FD->getASTContext()))
+ return true;
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
// Check for missing return value.
//===----------------------------------------------------------------------===//
@@ -542,6 +695,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
bool ReturnsVoid = false;
bool HasNoReturn = false;
+ bool IsCoroutine = S.getCurFunction() && S.getCurFunction()->isCoroutine();
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body))
@@ -570,8 +724,13 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// Short circuit for compilation speed.
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
return;
-
SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd();
+ auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) {
+ if (IsCoroutine)
+ S.Diag(Loc, DiagID) << S.getCurFunction()->CoroutinePromise->getType();
+ else
+ S.Diag(Loc, DiagID);
+ };
// Either in a function body compound statement, or a function-try-block.
switch (CheckFallThrough(AC)) {
case UnknownFallThrough:
@@ -579,15 +738,15 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
case MaybeFallThrough:
if (HasNoReturn)
- S.Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
+ EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn);
else if (!ReturnsVoid)
- S.Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
+ EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid);
break;
case AlwaysFallThrough:
if (HasNoReturn)
- S.Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
+ EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn);
else if (!ReturnsVoid)
- S.Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
+ EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
break;
case NeverFallThroughOrReturn:
if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
@@ -972,7 +1131,8 @@ namespace {
}
}
- bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt) {
+ bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt,
+ bool IsTemplateInstantiation) {
assert(!ReachableBlocks.empty() && "ReachableBlocks empty");
int UnannotatedCnt = 0;
@@ -1002,8 +1162,12 @@ namespace {
ElemIt != ElemEnd; ++ElemIt) {
if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) {
if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
- S.Diag(AS->getLocStart(),
- diag::warn_fallthrough_attr_unreachable);
+ // Don't issue a warning for an unreachable fallthrough
+ // attribute in template instantiations as it may not be
+ // unreachable in all instantiations of the template.
+ if (!IsTemplateInstantiation)
+ S.Diag(AS->getLocStart(),
+ diag::warn_fallthrough_attr_unreachable);
markFallthroughVisited(AS);
++AnnotatedCnt;
break;
@@ -1164,7 +1328,11 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
int AnnotatedCnt;
- if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt))
+ bool IsTemplateInstantiation = false;
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(AC.getDecl()))
+ IsTemplateInstantiation = Function->isTemplateInstantiation();
+ if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt,
+ IsTemplateInstantiation))
continue;
S.Diag(Label->getLocStart(),
@@ -2018,12 +2186,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// Warning: check missing 'return'
if (P.enableCheckFallThrough) {
- auto IsCoro = [&]() {
- if (auto *FD = dyn_cast<FunctionDecl>(D))
- if (FD->getBody() && isa<CoroutineBodyStmt>(FD->getBody()))
- return true;
- return false;
- };
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D)
? CheckFallThroughDiagnostics::MakeForBlock()
@@ -2031,7 +2193,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call &&
cast<CXXMethodDecl>(D)->getParent()->isLambda())
? CheckFallThroughDiagnostics::MakeForLambda()
- : (IsCoro()
+ : (fscope->isCoroutine()
? CheckFallThroughDiagnostics::MakeForCoroutine(D)
: CheckFallThroughDiagnostics::MakeForFunction(D)));
CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC);
@@ -2118,6 +2280,12 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
}
}
+ // Check for throw out of non-throwing function.
+ if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getLocStart()))
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (S.getLangOpts().CPlusPlus && isNoexcept(FD))
+ checkThrowInNonThrowingFunc(S, FD, AC);
+
// If none of the previous checks caused a CFG build, trigger one here
// for -Wtautological-overlap-compare
if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison,
diff --git a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp
index 55e9601..724db45 100644
--- a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaInternal.h"
@@ -160,12 +161,16 @@ struct ParsedAttrInfo {
unsigned IsType : 1;
unsigned IsStmt : 1;
unsigned IsKnownToGCC : 1;
+ unsigned IsSupportedByPragmaAttribute : 1;
bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
const Decl *);
bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr);
bool (*ExistsInTarget)(const TargetInfo &Target);
unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr);
+ void (*GetPragmaAttributeMatchRules)(
+ llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
+ const LangOptions &LangOpts);
};
namespace {
@@ -192,6 +197,18 @@ bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
}
+bool AttributeList::appliesToDecl(const Decl *D,
+ attr::SubjectMatchRule MatchRule) const {
+ return checkAttributeMatchRuleAppliesTo(D, MatchRule);
+}
+
+void AttributeList::getMatchRules(
+ const LangOptions &LangOpts,
+ SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
+ const {
+ return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts);
+}
+
bool AttributeList::diagnoseLangOpts(Sema &S) const {
return getInfo(*this).DiagLangOpts(S, *this);
}
@@ -216,6 +233,10 @@ bool AttributeList::isKnownToGCC() const {
return getInfo(*this).IsKnownToGCC;
}
+bool AttributeList::isSupportedByPragmaAttribute() const {
+ return getInfo(*this).IsSupportedByPragmaAttribute;
+}
+
unsigned AttributeList::getSemanticSpelling() const {
return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/CoroutineStmtBuilder.h b/contrib/llvm/tools/clang/lib/Sema/CoroutineStmtBuilder.h
new file mode 100644
index 0000000..33a368d
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Sema/CoroutineStmtBuilder.h
@@ -0,0 +1,73 @@
+//===- CoroutineStmtBuilder.h - Implicit coroutine stmt builder -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===//
+//
+// This file defines CoroutineStmtBuilder, a class for building the implicit
+// statements required for building a coroutine body.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_SEMA_COROUTINESTMTBUILDER_H
+#define LLVM_CLANG_LIB_SEMA_COROUTINESTMTBUILDER_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaInternal.h"
+
+namespace clang {
+
+class CoroutineStmtBuilder : public CoroutineBodyStmt::CtorArgs {
+ Sema &S;
+ FunctionDecl &FD;
+ sema::FunctionScopeInfo &Fn;
+ bool IsValid = true;
+ SourceLocation Loc;
+ SmallVector<Stmt *, 4> ParamMovesVector;
+ const bool IsPromiseDependentType;
+ CXXRecordDecl *PromiseRecordDecl = nullptr;
+
+public:
+ /// \brief Construct a CoroutineStmtBuilder and initialize the promise
+ /// statement and initial/final suspends from the FunctionScopeInfo.
+ CoroutineStmtBuilder(Sema &S, FunctionDecl &FD, sema::FunctionScopeInfo &Fn,
+ Stmt *Body);
+
+ /// \brief Build the coroutine body statements, including the
+ /// "promise dependent" statements when the promise type is not dependent.
+ bool buildStatements();
+
+ /// \brief Build the coroutine body statements that require a non-dependent
+ /// promise type in order to construct.
+ ///
+ /// For example different new/delete overloads are selected depending on
+ /// if the promise type provides `unhandled_exception()`, and therefore they
+ /// cannot be built until the promise type is complete so that we can perform
+ /// name lookup.
+ bool buildDependentStatements();
+
+ /// \brief Build just parameter moves. To use for rebuilding in TreeTransform.
+ bool buildParameterMoves();
+
+ bool isInvalid() const { return !this->IsValid; }
+
+private:
+ bool makePromiseStmt();
+ bool makeInitialAndFinalSuspend();
+ bool makeNewAndDeleteExpr();
+ bool makeOnFallthrough();
+ bool makeOnException();
+ bool makeReturnObject();
+ bool makeGroDeclAndReturnStmt();
+ bool makeReturnOnAllocFailure();
+ bool makeParamMoves();
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_SEMA_COROUTINESTMTBUILDER_H
diff --git a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp
index a55cdcc..e4e84fc 100644
--- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp
@@ -1082,8 +1082,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
!S.getLangOpts().ZVector)
S.Diag(TSTLoc, diag::err_invalid_vector_double_decl_spec);
} else if (TypeSpecType == TST_float) {
- // vector float is unsupported for ZVector.
- if (S.getLangOpts().ZVector)
+ // vector float is unsupported for ZVector unless we have the
+ // vector-enhancements facility 1 (ISA revision 12).
+ if (S.getLangOpts().ZVector &&
+ !S.Context.getTargetInfo().hasFeature("arch12"))
S.Diag(TSTLoc, diag::err_invalid_vector_float_decl_spec);
} else if (TypeSpecWidth == TSW_long) {
// vector long is unsupported for ZVector and deprecated for AltiVec.
diff --git a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp
index 2fa5718..3d321d5 100644
--- a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp
@@ -22,7 +22,8 @@ using namespace sema;
DelayedDiagnostic
DelayedDiagnostic::makeAvailability(AvailabilityResult AR,
SourceLocation Loc,
- const NamedDecl *D,
+ const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
StringRef Msg,
@@ -31,7 +32,8 @@ DelayedDiagnostic::makeAvailability(AvailabilityResult AR,
DD.Kind = Availability;
DD.Triggered = false;
DD.Loc = Loc;
- DD.AvailabilityData.Decl = D;
+ DD.AvailabilityData.ReferringDecl = ReferringDecl;
+ DD.AvailabilityData.OffendingDecl = OffendingDecl;
DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass;
DD.AvailabilityData.ObjCProperty = ObjCProperty;
char *MessageData = nullptr;
diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
index 899d3fa..865aea9 100644
--- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
@@ -287,6 +287,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
IndirectJumpTargets.push_back(cast<AddrLabelExpr>(S)->getLabel());
break;
+ case Stmt::ObjCForCollectionStmtClass: {
+ auto *CS = cast<ObjCForCollectionStmt>(S);
+ unsigned Diag = diag::note_protected_by_objc_fast_enumeration;
+ unsigned NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope, Diag, 0, S->getLocStart()));
+ BuildScopeInformation(CS->getBody(), NewParentScope);
+ return;
+ }
+
case Stmt::IndirectGotoStmtClass:
// "goto *&&lbl;" is a special case which we treat as equivalent
// to a normal goto. In addition, we don't calculate scope in the
diff --git a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index 077a56f..b7e343c 100644
--- a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -94,6 +94,15 @@ MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
return nullptr;
}
+ExternalASTSource::ExtKind
+MultiplexExternalSemaSource::hasExternalDefinitions(const Decl *D) {
+ for (const auto &S : Sources)
+ if (auto EK = S->hasExternalDefinitions(D))
+ if (EK != EK_ReplyHazy)
+ return EK;
+ return EK_ReplyHazy;
+}
+
bool MultiplexExternalSemaSource::
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
bool AnyDeclsFound = false;
diff --git a/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp b/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp
index 3970b41..b309a36 100644
--- a/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp
@@ -40,10 +40,15 @@ void FunctionScopeInfo::Clear() {
FirstCXXTryLoc = SourceLocation();
FirstSEHTryLoc = SourceLocation();
+ // Coroutine state
+ FirstCoroutineStmtLoc = SourceLocation();
+ CoroutinePromise = nullptr;
+ NeedsCoroutineSuspends = true;
+ CoroutineSuspends.first = nullptr;
+ CoroutineSuspends.second = nullptr;
+
SwitchStack.clear();
Returns.clear();
- CoroutinePromise = nullptr;
- CoroutineStmts.clear();
ErrorTrap.reset();
PossiblyUnreachableDiags.clear();
WeakObjectUses.clear();
@@ -184,7 +189,7 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
}
// Has this weak object been seen before?
- FunctionScopeInfo::WeakObjectUseMap::iterator Uses;
+ FunctionScopeInfo::WeakObjectUseMap::iterator Uses = WeakObjectUses.end();
if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E)) {
if (!RefExpr->isObjectReceiver())
return;
@@ -197,10 +202,10 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
}
else if (const ObjCIvarRefExpr *IvarE = dyn_cast<ObjCIvarRefExpr>(E))
Uses = WeakObjectUses.find(WeakObjectProfileTy(IvarE));
- else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- Uses = WeakObjectUses.find(WeakObjectProfileTy(DRE));
- else if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E)) {
- Uses = WeakObjectUses.end();
+ else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (isa<VarDecl>(DRE->getDecl()))
+ Uses = WeakObjectUses.find(WeakObjectProfileTy(DRE));
+ } else if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E)) {
if (const ObjCMethodDecl *MD = MsgE->getMethodDecl()) {
if (const ObjCPropertyDecl *Prop = MD->findPropertyDecl()) {
Uses =
diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp
index 412f944..a18f714 100644
--- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp
@@ -71,42 +71,34 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
}
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
- TranslationUnitKind TUKind,
- CodeCompleteConsumer *CodeCompleter)
- : ExternalSource(nullptr),
- isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
- LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
- Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
- CollectStats(false), CodeCompleter(CodeCompleter),
- CurContext(nullptr), OriginalLexicalContext(nullptr),
- MSStructPragmaOn(false),
- MSPointerToMemberRepresentationMethod(
- LangOpts.getMSPointerToMemberRepresentationMethod()),
- VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
- PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr),
- ConstSegStack(nullptr), CodeSegStack(nullptr), CurInitSeg(nullptr),
- VisContext(nullptr),
- IsBuildingRecoveryCallExpr(false),
- Cleanup{}, LateTemplateParser(nullptr),
- LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
- StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
- CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
- NSNumberDecl(nullptr), NSValueDecl(nullptr),
- NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
- ValueWithBytesObjCTypeMethod(nullptr),
- NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr),
- NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr),
- GlobalNewDeleteDeclared(false),
- TUKind(TUKind),
- NumSFINAEErrors(0),
- CachedFakeTopLevelModule(nullptr),
- AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
- NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
- TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),
- VarDataSharingAttributesStack(nullptr), CurScope(nullptr),
- Ident_super(nullptr), Ident___float128(nullptr)
-{
+ TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
+ : ExternalSource(nullptr), isMultiplexExternalSource(false),
+ FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
+ Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
+ SourceMgr(PP.getSourceManager()), CollectStats(false),
+ CodeCompleter(CodeCompleter), CurContext(nullptr),
+ OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
+ MSPointerToMemberRepresentationMethod(
+ LangOpts.getMSPointerToMemberRepresentationMethod()),
+ VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), PackStack(0),
+ DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
+ CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
+ PragmaAttributeCurrentTargetDecl(nullptr),
+ IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
+ LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
+ StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
+ CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr),
+ NSValueDecl(nullptr), NSStringDecl(nullptr),
+ StringWithUTF8StringMethod(nullptr),
+ ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr),
+ ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr),
+ DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false),
+ TUKind(TUKind), NumSFINAEErrors(0), AccessCheckingSFINAE(false),
+ InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
+ ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr),
+ DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),
+ ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
+ CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
TUScope = nullptr;
LoadedExternalKnownNamespaces = false;
@@ -122,8 +114,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
// Tell diagnostics how to render things from the AST library.
Diags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &Context);
- ExprEvalContexts.emplace_back(PotentiallyEvaluated, 0, CleanupInfo{}, nullptr,
- false);
+ ExprEvalContexts.emplace_back(
+ ExpressionEvaluationContext::PotentiallyEvaluated, 0, CleanupInfo{},
+ nullptr, false);
FunctionScopes.push_back(new FunctionScopeInfo(Diags));
@@ -217,7 +210,6 @@ void Sema::Initialize() {
if (getLangOpts().OpenCLVersion >= 200) {
addImplicitTypedef("clk_event_t", Context.OCLClkEventTy);
addImplicitTypedef("queue_t", Context.OCLQueueTy);
- addImplicitTypedef("ndrange_t", Context.OCLNDRangeTy);
addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy);
addImplicitTypedef("atomic_int", Context.getAtomicType(Context.IntTy));
addImplicitTypedef("atomic_uint",
@@ -328,7 +320,7 @@ bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
if (!fn) return false;
// If we're in template instantiation, it's an error.
- if (!ActiveTemplateInstantiations.empty())
+ if (inTemplateInstantiation())
return false;
// If that function's not in a system header, it's an error.
@@ -390,6 +382,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.
@@ -414,6 +419,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);
@@ -470,6 +476,13 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
return true;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // If this is a function template and none of its specializations is used,
+ // we should warn.
+ if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate())
+ for (const auto *Spec : Template->specializations())
+ if (ShouldRemoveFromUnused(SemaRef, Spec))
+ return true;
+
// UnusedFileScopedDecls stores the first declaration.
// The declaration may have become definition so check again.
const FunctionDecl *DeclToCheck;
@@ -493,6 +506,13 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
VD->isUsableInConstantExpressions(SemaRef->Context))
return true;
+ if (VarTemplateDecl *Template = VD->getDescribedVarTemplate())
+ // If this is a variable template and none of its specializations is used,
+ // we should warn.
+ for (const auto *Spec : Template->specializations())
+ if (ShouldRemoveFromUnused(SemaRef, Spec))
+ return true;
+
// UnusedFileScopedDecls stores the first declaration.
// The declaration may have become definition so check again.
const VarDecl *DeclToCheck = VD->getDefinition();
@@ -522,6 +542,9 @@ void Sema::getUndefinedButUsed(
// __attribute__((weakref)) is basically a definition.
if (ND->hasAttr<WeakRefAttr>()) continue;
+ if (isa<CXXDeductionGuideDecl>(ND))
+ continue;
+
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (FD->isDefined())
continue;
@@ -685,6 +708,18 @@ void Sema::emitAndClearUnusedLocalTypedefWarnings() {
UnusedLocalTypedefNameCandidates.clear();
}
+/// This is called before the very first declaration in the translation unit
+/// is parsed. Note that the ASTContext may have already injected some
+/// declarations.
+void Sema::ActOnStartOfTranslationUnit() {
+ if (getLangOpts().ModulesTS) {
+ // We start in the global module; all those declarations are implicitly
+ // module-private (though they do not have module linkage).
+ Context.getTranslationUnitDecl()->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::ModulePrivate);
+ }
+}
+
/// ActOnEndOfTranslationUnit - This is called at the very end of the
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
@@ -720,6 +755,9 @@ void Sema::ActOnEndOfTranslationUnit() {
// Load pending instantiations from the external source.
SmallVector<PendingImplicitInstantiation, 4> Pending;
ExternalSource->ReadPendingInstantiations(Pending);
+ for (auto PII : Pending)
+ if (auto Func = dyn_cast<FunctionDecl>(PII.first))
+ Func->setInstantiationIsPending(true);
PendingInstantiations.insert(PendingInstantiations.begin(),
Pending.begin(), Pending.end());
}
@@ -731,6 +769,8 @@ void Sema::ActOnEndOfTranslationUnit() {
CheckDelayedMemberExceptionSpecs();
}
+ DiagnoseUnterminatedPragmaAttribute();
+
// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
// FIXME: This is wrong for TUKind == TU_Prefix. In that case, we need to
@@ -745,7 +785,9 @@ void Sema::ActOnEndOfTranslationUnit() {
UnusedFileScopedDecls.erase(
std::remove_if(UnusedFileScopedDecls.begin(nullptr, true),
UnusedFileScopedDecls.end(),
- std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), this)),
+ [this](const DeclaratorDecl *DD) {
+ return ShouldRemoveFromUnused(this, DD);
+ }),
UnusedFileScopedDecls.end());
if (TUKind == TU_Prefix) {
@@ -811,7 +853,8 @@ void Sema::ActOnEndOfTranslationUnit() {
emitAndClearUnusedLocalTypedefWarnings();
// Modules don't need any of the checking below.
- TUScope = nullptr;
+ if (!PP.isIncrementalProcessingEnabled())
+ TUScope = nullptr;
return;
}
@@ -894,10 +937,14 @@ void Sema::ActOnEndOfTranslationUnit() {
<< /*function*/0 << DiagD->getDeclName();
}
} else {
- Diag(DiagD->getLocation(),
- isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
- : diag::warn_unused_function)
- << DiagD->getDeclName();
+ if (FD->getDescribedFunctionTemplate())
+ Diag(DiagD->getLocation(), diag::warn_unused_template)
+ << /*function*/0 << DiagD->getDeclName();
+ else
+ Diag(DiagD->getLocation(),
+ isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
+ : diag::warn_unused_function)
+ << DiagD->getDeclName();
}
} else {
const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition();
@@ -913,7 +960,11 @@ void Sema::ActOnEndOfTranslationUnit() {
Diag(DiagD->getLocation(), diag::warn_unused_const_variable)
<< DiagD->getDeclName();
} else {
- Diag(DiagD->getLocation(), diag::warn_unused_variable)
+ if (DiagD->getDescribedVarTemplate())
+ Diag(DiagD->getLocation(), diag::warn_unused_template)
+ << /*variable*/1 << DiagD->getDeclName();
+ else
+ Diag(DiagD->getLocation(), diag::warn_unused_variable)
<< DiagD->getDeclName();
}
}
@@ -1007,7 +1058,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// and yet we also use the current diag ID on the DiagnosticsEngine. This has
// been made more painfully obvious by the refactor that introduced this
// function, but it is possible that the incoming argument can be
- // eliminnated. If it truly cannot be (for example, there is some reentrancy
+ // eliminated. If it truly cannot be (for example, there is some reentrancy
// issue I am not seeing yet), then there should at least be a clarifying
// comment somewhere.
if (Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) {
@@ -1095,13 +1146,8 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// that is different from the last template instantiation where
// we emitted an error, print a template instantiation
// backtrace.
- if (!DiagnosticIDs::isBuiltinNote(DiagID) &&
- !ActiveTemplateInstantiations.empty() &&
- ActiveTemplateInstantiations.back()
- != LastTemplateInstantiationErrorContext) {
- PrintInstantiationStack();
- LastTemplateInstantiationErrorContext = ActiveTemplateInstantiations.back();
- }
+ if (!DiagnosticIDs::isBuiltinNote(DiagID))
+ PrintContextStack();
}
Sema::SemaDiagnosticBuilder
@@ -1169,10 +1215,14 @@ void Sema::PushFunctionScope() {
// memory for a new scope.
FunctionScopes.back()->Clear();
FunctionScopes.push_back(FunctionScopes.back());
+ if (LangOpts.OpenMP)
+ pushOpenMPFunctionRegion();
return;
}
FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics()));
+ if (LangOpts.OpenMP)
+ pushOpenMPFunctionRegion();
}
void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
@@ -1200,6 +1250,9 @@ void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
assert(!FunctionScopes.empty() && "mismatched push/pop!");
+ if (LangOpts.OpenMP)
+ popOpenMPFunctionRegion(Scope);
+
// Issue any analysis-based warnings.
if (WP && D)
AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr);
@@ -1236,21 +1289,21 @@ BlockScopeInfo *Sema::getCurBlock() {
if (CurBSI && CurBSI->TheDecl &&
!CurBSI->TheDecl->Encloses(CurContext)) {
// We have switched contexts due to template instantiation.
- assert(!ActiveTemplateInstantiations.empty());
+ assert(!CodeSynthesisContexts.empty());
return nullptr;
}
return CurBSI;
}
-LambdaScopeInfo *Sema::getCurLambda(bool IgnoreCapturedRegions) {
+LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
if (FunctionScopes.empty())
return nullptr;
auto I = FunctionScopes.rbegin();
- if (IgnoreCapturedRegions) {
+ if (IgnoreNonLambdaCapturingScope) {
auto E = FunctionScopes.rend();
- while (I != E && isa<CapturedRegionScopeInfo>(*I))
+ while (I != E && isa<CapturingScopeInfo>(*I) && !isa<LambdaScopeInfo>(*I))
++I;
if (I == E)
return nullptr;
@@ -1259,7 +1312,7 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreCapturedRegions) {
if (CurLSI && CurLSI->Lambda &&
!CurLSI->Lambda->Encloses(CurContext)) {
// We have switched contexts due to template instantiation.
- assert(!ActiveTemplateInstantiations.empty());
+ assert(!CodeSynthesisContexts.empty());
return nullptr;
}
@@ -1651,7 +1704,8 @@ bool Sema::checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType QT) {
QT, OpenCLTypeExtMap);
}
-bool Sema::checkOpenCLDisabledDecl(const Decl &D, const Expr &E) {
- return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), "",
+bool Sema::checkOpenCLDisabledDecl(const NamedDecl &D, const Expr &E) {
+ IdentifierInfo *FnName = D.getIdentifier();
+ return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), FnName,
OpenCLDeclExtMap, 1, D.getSourceRange());
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp
index bad9e70..8c13ead 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp
@@ -126,6 +126,36 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
PackStack.Act(PragmaLoc, Action, StringRef(), Alignment);
}
+void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action,
+ PragmaClangSectionKind SecKind, StringRef SecName) {
+ PragmaClangSection *CSec;
+ switch (SecKind) {
+ case PragmaClangSectionKind::PCSK_BSS:
+ CSec = &PragmaClangBSSSection;
+ break;
+ case PragmaClangSectionKind::PCSK_Data:
+ CSec = &PragmaClangDataSection;
+ break;
+ case PragmaClangSectionKind::PCSK_Rodata:
+ CSec = &PragmaClangRodataSection;
+ break;
+ case PragmaClangSectionKind::PCSK_Text:
+ CSec = &PragmaClangTextSection;
+ break;
+ default:
+ llvm_unreachable("invalid clang section kind");
+ }
+
+ if (Action == PragmaClangSectionAction::PCSA_Clear) {
+ CSec->Valid = false;
+ return;
+ }
+
+ CSec->Valid = true;
+ CSec->SectionName = SecName;
+ CSec->PragmaLocation = PragmaLoc;
+}
+
void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
StringRef SlotLabel, Expr *alignment) {
Expr *Alignment = static_cast<Expr *>(alignment);
@@ -215,6 +245,7 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
ValueType Value) {
if (Action == PSK_Reset) {
CurrentValue = DefaultValue;
+ CurrentPragmaLocation = PragmaLocation;
return;
}
if (Action & PSK_Push)
@@ -367,6 +398,219 @@ void Sema::AddCFAuditedAttribute(Decl *D) {
D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc));
}
+namespace {
+
+Optional<attr::SubjectMatchRule>
+getParentAttrMatcherRule(attr::SubjectMatchRule Rule) {
+ using namespace attr;
+ switch (Rule) {
+ default:
+ return None;
+#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
+#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
+ case Value: \
+ return Parent;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+}
+
+bool isNegatedAttrMatcherSubRule(attr::SubjectMatchRule Rule) {
+ using namespace attr;
+ switch (Rule) {
+ default:
+ return false;
+#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
+#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
+ case Value: \
+ return IsNegated;
+#include "clang/Basic/AttrSubMatchRulesList.inc"
+ }
+}
+
+CharSourceRange replacementRangeForListElement(const Sema &S,
+ SourceRange Range) {
+ // Make sure that the ',' is removed as well.
+ SourceLocation AfterCommaLoc = Lexer::findLocationAfterToken(
+ Range.getEnd(), tok::comma, S.getSourceManager(), S.getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/false);
+ if (AfterCommaLoc.isValid())
+ return CharSourceRange::getCharRange(Range.getBegin(), AfterCommaLoc);
+ else
+ return CharSourceRange::getTokenRange(Range);
+}
+
+std::string
+attrMatcherRuleListToString(ArrayRef<attr::SubjectMatchRule> Rules) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ for (const auto &I : llvm::enumerate(Rules)) {
+ if (I.index())
+ OS << (I.index() == Rules.size() - 1 ? ", and " : ", ");
+ OS << "'" << attr::getSubjectMatchRuleSpelling(I.value()) << "'";
+ }
+ return OS.str();
+}
+
+} // end anonymous namespace
+
+void Sema::ActOnPragmaAttributePush(AttributeList &Attribute,
+ SourceLocation PragmaLoc,
+ attr::ParsedSubjectMatchRuleSet Rules) {
+ SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules;
+ // Gather the subject match rules that are supported by the attribute.
+ SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4>
+ StrictSubjectMatchRuleSet;
+ Attribute.getMatchRules(LangOpts, StrictSubjectMatchRuleSet);
+
+ // Figure out which subject matching rules are valid.
+ if (StrictSubjectMatchRuleSet.empty()) {
+ // Check for contradicting match rules. Contradicting match rules are
+ // either:
+ // - a top-level rule and one of its sub-rules. E.g. variable and
+ // variable(is_parameter).
+ // - a sub-rule and a sibling that's negated. E.g.
+ // variable(is_thread_local) and variable(unless(is_parameter))
+ llvm::SmallDenseMap<int, std::pair<int, SourceRange>, 2>
+ RulesToFirstSpecifiedNegatedSubRule;
+ for (const auto &Rule : Rules) {
+ attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
+ Optional<attr::SubjectMatchRule> ParentRule =
+ getParentAttrMatcherRule(MatchRule);
+ if (!ParentRule)
+ continue;
+ auto It = Rules.find(*ParentRule);
+ if (It != Rules.end()) {
+ // A sub-rule contradicts a parent rule.
+ Diag(Rule.second.getBegin(),
+ diag::err_pragma_attribute_matcher_subrule_contradicts_rule)
+ << attr::getSubjectMatchRuleSpelling(MatchRule)
+ << attr::getSubjectMatchRuleSpelling(*ParentRule) << It->second
+ << FixItHint::CreateRemoval(
+ replacementRangeForListElement(*this, Rule.second));
+ // Keep going without removing this rule as it won't change the set of
+ // declarations that receive the attribute.
+ continue;
+ }
+ if (isNegatedAttrMatcherSubRule(MatchRule))
+ RulesToFirstSpecifiedNegatedSubRule.insert(
+ std::make_pair(*ParentRule, Rule));
+ }
+ bool IgnoreNegatedSubRules = false;
+ for (const auto &Rule : Rules) {
+ attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
+ Optional<attr::SubjectMatchRule> ParentRule =
+ getParentAttrMatcherRule(MatchRule);
+ if (!ParentRule)
+ continue;
+ auto It = RulesToFirstSpecifiedNegatedSubRule.find(*ParentRule);
+ if (It != RulesToFirstSpecifiedNegatedSubRule.end() &&
+ It->second != Rule) {
+ // Negated sub-rule contradicts another sub-rule.
+ Diag(
+ It->second.second.getBegin(),
+ diag::
+ err_pragma_attribute_matcher_negated_subrule_contradicts_subrule)
+ << attr::getSubjectMatchRuleSpelling(
+ attr::SubjectMatchRule(It->second.first))
+ << attr::getSubjectMatchRuleSpelling(MatchRule) << Rule.second
+ << FixItHint::CreateRemoval(
+ replacementRangeForListElement(*this, It->second.second));
+ // Keep going but ignore all of the negated sub-rules.
+ IgnoreNegatedSubRules = true;
+ RulesToFirstSpecifiedNegatedSubRule.erase(It);
+ }
+ }
+
+ if (!IgnoreNegatedSubRules) {
+ for (const auto &Rule : Rules)
+ SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first));
+ } else {
+ for (const auto &Rule : Rules) {
+ if (!isNegatedAttrMatcherSubRule(attr::SubjectMatchRule(Rule.first)))
+ SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first));
+ }
+ }
+ Rules.clear();
+ } else {
+ for (const auto &Rule : StrictSubjectMatchRuleSet) {
+ if (Rules.erase(Rule.first)) {
+ // Add the rule to the set of attribute receivers only if it's supported
+ // in the current language mode.
+ if (Rule.second)
+ SubjectMatchRules.push_back(Rule.first);
+ }
+ }
+ }
+
+ if (!Rules.empty()) {
+ auto Diagnostic =
+ Diag(PragmaLoc, diag::err_pragma_attribute_invalid_matchers)
+ << Attribute.getName();
+ SmallVector<attr::SubjectMatchRule, 2> ExtraRules;
+ for (const auto &Rule : Rules) {
+ ExtraRules.push_back(attr::SubjectMatchRule(Rule.first));
+ Diagnostic << FixItHint::CreateRemoval(
+ replacementRangeForListElement(*this, Rule.second));
+ }
+ Diagnostic << attrMatcherRuleListToString(ExtraRules);
+ }
+
+ PragmaAttributeStack.push_back(
+ {PragmaLoc, &Attribute, std::move(SubjectMatchRules), /*IsUsed=*/false});
+}
+
+void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc) {
+ if (PragmaAttributeStack.empty()) {
+ Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch);
+ return;
+ }
+ const PragmaAttributeEntry &Entry = PragmaAttributeStack.back();
+ if (!Entry.IsUsed) {
+ assert(Entry.Attribute && "Expected an attribute");
+ Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused)
+ << Entry.Attribute->getName();
+ Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here);
+ }
+ PragmaAttributeStack.pop_back();
+}
+
+void Sema::AddPragmaAttributes(Scope *S, Decl *D) {
+ if (PragmaAttributeStack.empty())
+ return;
+ for (auto &Entry : PragmaAttributeStack) {
+ const AttributeList *Attribute = Entry.Attribute;
+ assert(Attribute && "Expected an attribute");
+
+ // Ensure that the attribute can be applied to the given declaration.
+ bool Applies = false;
+ for (const auto &Rule : Entry.MatchRules) {
+ if (Attribute->appliesToDecl(D, Rule)) {
+ Applies = true;
+ break;
+ }
+ }
+ if (!Applies)
+ continue;
+ Entry.IsUsed = true;
+ assert(!Attribute->getNext() && "Expected just one attribute");
+ PragmaAttributeCurrentTargetDecl = D;
+ ProcessDeclAttributeList(S, D, Attribute);
+ PragmaAttributeCurrentTargetDecl = nullptr;
+ }
+}
+
+void Sema::PrintPragmaAttributeInstantiationPoint() {
+ assert(PragmaAttributeCurrentTargetDecl && "Expected an active declaration");
+ Diags.Report(PragmaAttributeCurrentTargetDecl->getLocStart(),
+ diag::note_pragma_attribute_applied_decl_here);
+}
+
+void Sema::DiagnoseUnterminatedPragmaAttribute() {
+ if (PragmaAttributeStack.empty())
+ return;
+ Diag(PragmaAttributeStack.back().Loc, diag::err_pragma_attribute_no_pop_eof);
+}
+
void Sema::ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc) {
if(On)
OptimizeOffPragmaLocation = SourceLocation();
@@ -447,16 +691,16 @@ void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType,
}
}
-void Sema::ActOnPragmaFPContract(tok::OnOffSwitch OOS) {
- switch (OOS) {
- case tok::OOS_ON:
- FPFeatures.fp_contract = 1;
+void Sema::ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC) {
+ switch (FPC) {
+ case LangOptions::FPC_On:
+ FPFeatures.setAllowFPContractWithinStatement();
break;
- case tok::OOS_OFF:
- FPFeatures.fp_contract = 0;
+ case LangOptions::FPC_Fast:
+ FPFeatures.setAllowFPContractAcrossStatement();
break;
- case tok::OOS_DEFAULT:
- FPFeatures.fp_contract = getLangOpts().DefaultFPContract;
+ case LangOptions::FPC_Off:
+ FPFeatures.setDisallowFPContract();
break;
}
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp
index 282633b..cac5f68 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp
@@ -295,7 +295,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
}
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
LookupSpecialMember(BaseClassDecl, CSM,
/* ConstArg */ ConstRHS,
/* VolatileArg */ false,
@@ -303,11 +303,10 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
/* ConstThis */ false,
/* VolatileThis */ false);
- if (!SMOR || !SMOR->getMethod()) {
+ if (!SMOR.getMethod())
continue;
- }
- CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR->getMethod());
+ CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR.getMethod());
if (!InferredTarget.hasValue()) {
InferredTarget = BaseMethodTarget;
} else {
@@ -339,7 +338,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
}
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl());
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
LookupSpecialMember(FieldRecDecl, CSM,
/* ConstArg */ ConstRHS && !F->isMutable(),
/* VolatileArg */ false,
@@ -347,12 +346,11 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
/* ConstThis */ false,
/* VolatileThis */ false);
- if (!SMOR || !SMOR->getMethod()) {
+ if (!SMOR.getMethod())
continue;
- }
CUDAFunctionTarget FieldMethodTarget =
- IdentifyCUDATarget(SMOR->getMethod());
+ IdentifyCUDATarget(SMOR.getMethod());
if (!InferredTarget.hasValue()) {
InferredTarget = FieldMethodTarget;
} else {
@@ -631,12 +629,6 @@ static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) {
// emitted, because (say) the definition could include "inline".
FunctionDecl *Def = FD->getDefinition();
- // We may currently be parsing the body of FD, in which case
- // FD->getDefinition() will be null, but we still want to treat FD as though
- // it's a definition.
- if (!Def && FD->willHaveBody())
- Def = FD;
-
if (Def &&
!isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def)))
return true;
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp
index d8971c0..6da4d2a 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -461,6 +461,7 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
/// are allowed. The bool value pointed by this parameter is set to
/// 'true' if the identifier is treated as if it was followed by ':',
/// not '::'.
+/// \param OnlyNamespace If true, only considers namespaces in lookup.
///
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
@@ -473,15 +474,17 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
/// scope if it *knows* that the result is correct. It should not return in a
/// dependent context, for example. Nor will it extend \p SS with the scope
/// specifier.
-bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
- NestedNameSpecInfo &IdInfo,
- bool EnteringContext,
- CXXScopeSpec &SS,
+bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
+ bool EnteringContext, CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
- bool *IsCorrectedToColon) {
+ bool *IsCorrectedToColon,
+ bool OnlyNamespace) {
+ if (IdInfo.Identifier->isEditorPlaceholder())
+ return true;
LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
- LookupNestedNameSpecifierName);
+ OnlyNamespace ? LookupNamespaceName
+ : LookupNestedNameSpecifierName);
QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType);
// Determine where to perform name lookup
@@ -594,7 +597,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
return true;
}
// Replacement '::' -> ':' is not allowed, just issue respective error.
- Diag(R.getNameLoc(), diag::err_expected_class_or_namespace)
+ Diag(R.getNameLoc(), OnlyNamespace
+ ? unsigned(diag::err_expected_namespace_name)
+ : unsigned(diag::err_expected_class_or_namespace))
<< IdInfo.Identifier << getLangOpts().CPlusPlus;
if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
Diag(ND->getLocation(), diag::note_entity_declared_at)
@@ -819,19 +824,17 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
return true;
}
-bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
- NestedNameSpecInfo &IdInfo,
- bool EnteringContext,
- CXXScopeSpec &SS,
+bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
+ bool EnteringContext, CXXScopeSpec &SS,
bool ErrorRecoveryLookup,
- bool *IsCorrectedToColon) {
+ bool *IsCorrectedToColon,
+ bool OnlyNamespace) {
if (SS.isInvalid())
return true;
- return BuildCXXNestedNameSpecifier(S, IdInfo,
- EnteringContext, SS,
+ return BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
/*ScopeLookupResult=*/nullptr, false,
- IsCorrectedToColon);
+ IsCorrectedToColon, OnlyNamespace);
}
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
@@ -933,8 +936,8 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
// We were able to resolve the template name to an actual template.
// Build an appropriate nested-name-specifier.
- QualType T = CheckTemplateIdType(Template.get(), TemplateNameLoc,
- TemplateArgs);
+ QualType T =
+ CheckTemplateIdType(Template.get(), TemplateNameLoc, TemplateArgs);
if (T.isNull())
return true;
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp
index 6222e4c..d603101 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp
@@ -120,12 +120,12 @@ namespace {
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
}
- void checkObjCARCConversion(Sema::CheckedConversionKind CCK) {
- assert(Self.getLangOpts().ObjCAutoRefCount);
+ void checkObjCConversion(Sema::CheckedConversionKind CCK) {
+ assert(Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers());
Expr *src = SrcExpr.get();
- if (Self.CheckObjCARCConversion(OpRange, DestType, src, CCK) ==
- Sema::ACR_unbridged)
+ if (Self.CheckObjCConversion(OpRange, DestType, src, CCK) ==
+ Sema::ACR_unbridged)
IsARCUnbridgedCast = true;
SrcExpr = src;
}
@@ -143,6 +143,9 @@ namespace {
};
}
+static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
+ QualType DestType);
+
// The Try functions attempt a specific way of casting. If they succeed, they
// return TC_Success. If their way of casting is not appropriate for the given
// arguments, they return TC_NotApplicable and *may* set diag to a diagnostic
@@ -427,6 +430,10 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
/// the same kind of pointer (plain or to-member). Unlike the Sema function,
/// this one doesn't care if the two pointers-to-member don't point into the
/// same class. This is because CastsAwayConstness doesn't care.
+/// And additionally, it handles C++ references. If both the types are
+/// references, then their pointee types are returned,
+/// else if only one of them is reference, it's pointee type is returned,
+/// and the other type is returned as-is.
static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
const PointerType *T1PtrType = T1->getAs<PointerType>(),
*T2PtrType = T2->getAs<PointerType>();
@@ -475,6 +482,26 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
return true;
}
+ const LValueReferenceType *T1RefType = T1->getAs<LValueReferenceType>(),
+ *T2RefType = T2->getAs<LValueReferenceType>();
+ if (T1RefType && T2RefType) {
+ T1 = T1RefType->getPointeeType();
+ T2 = T2RefType->getPointeeType();
+ return true;
+ }
+
+ if (T1RefType) {
+ T1 = T1RefType->getPointeeType();
+ // T2 = T2;
+ return true;
+ }
+
+ if (T2RefType) {
+ // T1 = T1;
+ T2 = T2RefType->getPointeeType();
+ return true;
+ }
+
return false;
}
@@ -503,11 +530,13 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
// the rules are non-trivial. So first we construct Tcv *...cv* as described
// in C++ 5.2.11p8.
assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() ||
- SrcType->isBlockPointerType()) &&
+ SrcType->isBlockPointerType() ||
+ DestType->isLValueReferenceType()) &&
"Source type is not pointer or pointer to member.");
assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() ||
- DestType->isBlockPointerType()) &&
- "Destination type is not pointer or pointer to member.");
+ DestType->isBlockPointerType() ||
+ DestType->isLValueReferenceType()) &&
+ "Destination type is not pointer or pointer to member, or reference.");
QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType),
UnwrappedDestType = Self.Context.getCanonicalType(DestType);
@@ -523,7 +552,14 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
Qualifiers SrcQuals, DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals);
-
+
+ // We do not meaningfully track object const-ness of Objective-C object
+ // types. Remove const from the source type if either the source or
+ // the destination is an Objective-C object type.
+ if (UnwrappedSrcType->isObjCObjectType() ||
+ UnwrappedDestType->isObjCObjectType())
+ SrcQuals.removeConst();
+
Qualifiers RetainedSrcQuals, RetainedDestQuals;
if (CheckCVR) {
RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers());
@@ -871,8 +907,8 @@ void CastOperation::CheckReinterpretCast() {
}
SrcExpr = ExprError();
} else if (tcr == TC_Success) {
- if (Self.getLangOpts().ObjCAutoRefCount)
- checkObjCARCConversion(Sema::CCK_OtherCast);
+ if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
+ checkObjCConversion(Sema::CCK_OtherCast);
DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
}
}
@@ -935,8 +971,8 @@ void CastOperation::CheckStaticCast() {
} else if (tcr == TC_Success) {
if (Kind == CK_BitCast)
checkCastAlign();
- if (Self.getLangOpts().ObjCAutoRefCount)
- checkObjCARCConversion(Sema::CCK_OtherCast);
+ if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
+ checkObjCConversion(Sema::CCK_OtherCast);
} else if (Kind == CK_BitCast) {
checkCastAlign();
}
@@ -1763,13 +1799,12 @@ static void DiagnoseCallingConvCast(Sema &Self, const ExprResult &SrcExpr,
if (!DRE)
return;
auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl());
- const FunctionDecl *Definition;
- if (!FD || !FD->hasBody(Definition))
+ if (!FD)
return;
// Only warn if we are casting from the default convention to a non-default
// convention. This can happen when the programmer forgot to apply the calling
- // convention to the function definition and then inserted this cast to
+ // convention to the function declaration and then inserted this cast to
// satisfy the type system.
CallingConv DefaultCC = Self.getASTContext().getDefaultCallingConvention(
FD->isVariadic(), FD->isCXXInstanceMember());
@@ -1792,7 +1827,7 @@ static void DiagnoseCallingConvCast(Sema &Self, const ExprResult &SrcExpr,
// whose address was taken. Try to use the latest macro for the convention.
// For example, users probably want to write "WINAPI" instead of "__stdcall"
// to match the Windows header declarations.
- SourceLocation NameLoc = Definition->getNameInfo().getLoc();
+ SourceLocation NameLoc = FD->getFirstDecl()->getNameInfo().getLoc();
Preprocessor &PP = Self.getPreprocessor();
SmallVector<TokenValue, 6> AttrTokens;
SmallString<64> CCAttrText;
@@ -1872,7 +1907,8 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType,
// No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
// preserves Result.
Result = E;
- if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
+ if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(
+ Result, /*DoFunctionPointerConversion=*/true))
return false;
return Result.isUsable();
}
@@ -2177,6 +2213,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
bool ListInitialization) {
+ assert(Self.getLangOpts().CPlusPlus);
+
// Handle placeholders.
if (isPlaceholder()) {
// C-style casts can resolve __unknown_any types.
@@ -2273,8 +2311,9 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
}
}
- if (Self.getLangOpts().ObjCAutoRefCount && tcr == TC_Success)
- checkObjCARCConversion(CCK);
+ if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
+ tcr == TC_Success)
+ checkObjCConversion(CCK);
if (tcr != TC_Success && msg != 0) {
if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
@@ -2540,12 +2579,13 @@ void CastOperation::CheckCStyleCast() {
}
// ARC imposes extra restrictions on casts.
- if (Self.getLangOpts().ObjCAutoRefCount) {
- checkObjCARCConversion(Sema::CCK_CStyleCast);
+ if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) {
+ checkObjCConversion(Sema::CCK_CStyleCast);
if (SrcExpr.isInvalid())
return;
-
- if (const PointerType *CastPtr = DestType->getAs<PointerType>()) {
+
+ const PointerType *CastPtr = DestType->getAs<PointerType>();
+ if (Self.getLangOpts().ObjCAutoRefCount && CastPtr) {
if (const PointerType *ExprPtr = SrcType->getAs<PointerType>()) {
Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers();
Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers();
@@ -2578,30 +2618,42 @@ void CastOperation::CheckCStyleCast() {
if (Kind == CK_BitCast)
checkCastAlign();
+}
+
+/// DiagnoseCastQual - Warn whenever casts discards a qualifiers, be it either
+/// const, volatile or both.
+static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
+ QualType DestType) {
+ if (SrcExpr.isInvalid())
+ return;
+
+ QualType SrcType = SrcExpr.get()->getType();
+ if (!((SrcType->isAnyPointerType() && DestType->isAnyPointerType()) ||
+ DestType->isLValueReferenceType()))
+ return;
- // -Wcast-qual
QualType TheOffendingSrcType, TheOffendingDestType;
Qualifiers CastAwayQualifiers;
- if (SrcType->isAnyPointerType() && DestType->isAnyPointerType() &&
- CastsAwayConstness(Self, SrcType, DestType, true, false,
- &TheOffendingSrcType, &TheOffendingDestType,
- &CastAwayQualifiers)) {
- int qualifiers = -1;
- if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) {
- qualifiers = 0;
- } else if (CastAwayQualifiers.hasConst()) {
- qualifiers = 1;
- } else if (CastAwayQualifiers.hasVolatile()) {
- qualifiers = 2;
- }
- // This is a variant of int **x; const int **y = (const int **)x;
- if (qualifiers == -1)
- Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) <<
- SrcType << DestType;
- else
- Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) <<
- TheOffendingSrcType << TheOffendingDestType << qualifiers;
- }
+ if (!CastsAwayConstness(Self, SrcType, DestType, true, false,
+ &TheOffendingSrcType, &TheOffendingDestType,
+ &CastAwayQualifiers))
+ return;
+
+ int qualifiers = -1;
+ if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) {
+ qualifiers = 0;
+ } else if (CastAwayQualifiers.hasConst()) {
+ qualifiers = 1;
+ } else if (CastAwayQualifiers.hasVolatile()) {
+ qualifiers = 2;
+ }
+ // This is a variant of int **x; const int **y = (const int **)x;
+ if (qualifiers == -1)
+ Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2)
+ << SrcType << DestType;
+ else
+ Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual)
+ << TheOffendingSrcType << TheOffendingDestType << qualifiers;
}
ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
@@ -2622,17 +2674,21 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
if (Op.SrcExpr.isInvalid())
return ExprError();
+ // -Wcast-qual
+ DiagnoseCastQual(Op.Self, Op.SrcExpr, Op.DestType);
+
return Op.complete(CStyleCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
&Op.BasePath, CastTypeInfo, LPLoc, RPLoc));
}
ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
+ QualType Type,
SourceLocation LPLoc,
Expr *CastExpr,
SourceLocation RPLoc) {
assert(LPLoc.isValid() && "List-initialization shouldn't get here.");
- CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
+ CastOperation Op(*this, Type, CastExpr);
Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
index 3aedb2a..b2223b7 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
@@ -244,7 +244,7 @@ static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall,
// Scopes aren't available during instantiation. Fortunately, builtin
// functions cannot be template args so they cannot be formed through template
// instantiation. Therefore checking once during the parse is sufficient.
- if (!SemaRef.ActiveTemplateInstantiations.empty())
+ if (SemaRef.inTemplateInstantiation())
return false;
Scope *S = SemaRef.getCurScope();
@@ -309,13 +309,14 @@ static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) {
Expr *BlockArg = TheCall->getArg(0);
if (!isBlockPointer(BlockArg)) {
S.Diag(BlockArg->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type) << "block";
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "block";
return true;
}
return checkOpenCLBlockArgs(S, BlockArg);
}
-/// Diagnose integer type and any valid implicit convertion to it.
+/// Diagnose integer type and any valid implicit conversion to it.
static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E,
const QualType &IntType);
@@ -394,24 +395,24 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
// First argument always needs to be a queue_t type.
if (!Arg0->getType()->isQueueT()) {
S.Diag(TheCall->getArg(0)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
- << S.Context.OCLQueueTy;
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << S.Context.OCLQueueTy;
return true;
}
// Second argument always needs to be a kernel_enqueue_flags_t enum value.
if (!Arg1->getType()->isIntegerType()) {
S.Diag(TheCall->getArg(1)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
- << "'kernel_enqueue_flags_t' (i.e. uint)";
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "'kernel_enqueue_flags_t' (i.e. uint)";
return true;
}
// Third argument is always an ndrange_t type.
- if (!Arg2->getType()->isNDRangeT()) {
+ if (Arg2->getType().getUnqualifiedType().getAsString() != "ndrange_t") {
S.Diag(TheCall->getArg(2)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
- << S.Context.OCLNDRangeTy;
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "'ndrange_t'";
return true;
}
@@ -420,8 +421,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
if (NumArgs == 4) {
// check that the last argument is the right block type.
if (!isBlockPointer(Arg3)) {
- S.Diag(Arg3->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type)
- << "block";
+ S.Diag(Arg3->getLocStart(), diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "block";
return true;
}
// we have a block type, check the prototype
@@ -443,8 +444,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
// check common block argument.
Expr *Arg6 = TheCall->getArg(6);
if (!isBlockPointer(Arg6)) {
- S.Diag(Arg6->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type)
- << "block";
+ S.Diag(Arg6->getLocStart(), diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "block";
return true;
}
if (checkOpenCLBlockArgs(S, Arg6))
@@ -453,8 +454,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
// Forth argument has to be any integer type.
if (!Arg3->getType()->isIntegerType()) {
S.Diag(TheCall->getArg(3)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
- << "integer";
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee() << "integer";
return true;
}
// check remaining common arguments.
@@ -466,7 +467,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
Expr::NPC_ValueDependentIsNotNull) &&
!Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) {
S.Diag(TheCall->getArg(4)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee()
<< S.Context.getPointerType(S.Context.OCLClkEventTy);
return true;
}
@@ -477,7 +479,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
!(Arg5->getType()->isPointerType() &&
Arg5->getType()->getPointeeType()->isClkEventT())) {
S.Diag(TheCall->getArg(5)->getLocStart(),
- diag::err_opencl_enqueue_kernel_expected_type)
+ diag::err_opencl_builtin_expected_type)
+ << TheCall->getDirectCallee()
<< S.Context.getPointerType(S.Context.OCLClkEventTy);
return true;
}
@@ -757,9 +760,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (CheckObjCString(TheCall->getArg(0)))
return ExprError();
break;
+ case Builtin::BI__builtin_ms_va_start:
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
- if (SemaBuiltinVAStart(TheCall))
+ if (SemaBuiltinVAStart(BuiltinID, TheCall))
return ExprError();
break;
case Builtin::BI__va_start: {
@@ -770,7 +774,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
default:
- if (SemaBuiltinVAStart(TheCall))
+ if (SemaBuiltinVAStart(BuiltinID, TheCall))
return ExprError();
break;
}
@@ -1391,8 +1395,6 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
}
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
- llvm::APSInt Result;
-
if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
BuiltinID == ARM::BI__builtin_arm_ldaex ||
BuiltinID == ARM::BI__builtin_arm_strex ||
@@ -1439,8 +1441,6 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
- llvm::APSInt Result;
-
if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
BuiltinID == AArch64::BI__builtin_arm_ldaex ||
BuiltinID == AArch64::BI__builtin_arm_strex ||
@@ -1619,32 +1619,28 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Mips::BI__builtin_msa_copy_u_b:
case Mips::BI__builtin_msa_insve_b:
case Mips::BI__builtin_msa_splati_b: i = 1; l = 0; u = 15; break;
- case Mips::BI__builtin_msa_sld_b:
case Mips::BI__builtin_msa_sldi_b: i = 2; l = 0; u = 15; break;
// These intrinsics take an unsigned 3 bit immediate.
case Mips::BI__builtin_msa_copy_s_h:
case Mips::BI__builtin_msa_copy_u_h:
case Mips::BI__builtin_msa_insve_h:
case Mips::BI__builtin_msa_splati_h: i = 1; l = 0; u = 7; break;
- case Mips::BI__builtin_msa_sld_h:
case Mips::BI__builtin_msa_sldi_h: i = 2; l = 0; u = 7; break;
// These intrinsics take an unsigned 2 bit immediate.
case Mips::BI__builtin_msa_copy_s_w:
case Mips::BI__builtin_msa_copy_u_w:
case Mips::BI__builtin_msa_insve_w:
case Mips::BI__builtin_msa_splati_w: i = 1; l = 0; u = 3; break;
- case Mips::BI__builtin_msa_sld_w:
case Mips::BI__builtin_msa_sldi_w: i = 2; l = 0; u = 3; break;
// These intrinsics take an unsigned 1 bit immediate.
case Mips::BI__builtin_msa_copy_s_d:
case Mips::BI__builtin_msa_copy_u_d:
case Mips::BI__builtin_msa_insve_d:
case Mips::BI__builtin_msa_splati_d: i = 1; l = 0; u = 1; break;
- case Mips::BI__builtin_msa_sld_d:
case Mips::BI__builtin_msa_sldi_d: i = 2; l = 0; u = 1; break;
// Memory offsets and immediate loads.
// These intrinsics take a signed 10 bit immediate.
- case Mips::BI__builtin_msa_ldi_b: i = 0; l = -128; u = 127; break;
+ case Mips::BI__builtin_msa_ldi_b: i = 0; l = -128; u = 255; break;
case Mips::BI__builtin_msa_ldi_h:
case Mips::BI__builtin_msa_ldi_w:
case Mips::BI__builtin_msa_ldi_d: i = 0; l = -512; u = 511; break;
@@ -1704,6 +1700,9 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case PPC::BI__builtin_tabortdci:
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) ||
SemaBuiltinConstantArgRange(TheCall, 2, 0, 31);
+ case PPC::BI__builtin_vsx_xxpermdi:
+ case PPC::BI__builtin_vsx_xxsldwi:
+ return SemaBuiltinVSX(TheCall);
}
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
@@ -1741,9 +1740,11 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
case SystemZ::BI__builtin_s390_vfaezbs:
case SystemZ::BI__builtin_s390_vfaezhs:
case SystemZ::BI__builtin_s390_vfaezfs: i = 2; l = 0; u = 15; break;
+ case SystemZ::BI__builtin_s390_vfisb:
case SystemZ::BI__builtin_s390_vfidb:
return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15) ||
SemaBuiltinConstantArgRange(TheCall, 2, 0, 15);
+ case SystemZ::BI__builtin_s390_vftcisb:
case SystemZ::BI__builtin_s390_vftcidb: i = 1; l = 0; u = 4095; break;
case SystemZ::BI__builtin_s390_vlbb: i = 1; l = 0; u = 15; break;
case SystemZ::BI__builtin_s390_vpdi: i = 2; l = 0; u = 15; break;
@@ -1760,6 +1761,11 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
case SystemZ::BI__builtin_s390_vstrczbs:
case SystemZ::BI__builtin_s390_vstrczhs:
case SystemZ::BI__builtin_s390_vstrczfs: i = 3; l = 0; u = 15; break;
+ case SystemZ::BI__builtin_s390_vmslg: i = 3; l = 0; u = 15; break;
+ case SystemZ::BI__builtin_s390_vfminsb:
+ case SystemZ::BI__builtin_s390_vfmaxsb:
+ case SystemZ::BI__builtin_s390_vfmindb:
+ case SystemZ::BI__builtin_s390_vfmaxdb: i = 2; l = 0; u = 15; break;
}
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
@@ -1990,17 +1996,121 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
<< Arg->getSourceRange();
}
+// Check if the gather/scatter scale is legal.
+bool Sema::CheckX86BuiltinGatherScatterScale(unsigned BuiltinID,
+ CallExpr *TheCall) {
+ unsigned ArgNum = 0;
+ switch (BuiltinID) {
+ default:
+ return false;
+ case X86::BI__builtin_ia32_gatherpfdpd:
+ case X86::BI__builtin_ia32_gatherpfdps:
+ case X86::BI__builtin_ia32_gatherpfqpd:
+ case X86::BI__builtin_ia32_gatherpfqps:
+ case X86::BI__builtin_ia32_scatterpfdpd:
+ case X86::BI__builtin_ia32_scatterpfdps:
+ case X86::BI__builtin_ia32_scatterpfqpd:
+ case X86::BI__builtin_ia32_scatterpfqps:
+ ArgNum = 3;
+ break;
+ case X86::BI__builtin_ia32_gatherd_pd:
+ case X86::BI__builtin_ia32_gatherd_pd256:
+ case X86::BI__builtin_ia32_gatherq_pd:
+ case X86::BI__builtin_ia32_gatherq_pd256:
+ case X86::BI__builtin_ia32_gatherd_ps:
+ case X86::BI__builtin_ia32_gatherd_ps256:
+ case X86::BI__builtin_ia32_gatherq_ps:
+ case X86::BI__builtin_ia32_gatherq_ps256:
+ case X86::BI__builtin_ia32_gatherd_q:
+ case X86::BI__builtin_ia32_gatherd_q256:
+ case X86::BI__builtin_ia32_gatherq_q:
+ case X86::BI__builtin_ia32_gatherq_q256:
+ case X86::BI__builtin_ia32_gatherd_d:
+ case X86::BI__builtin_ia32_gatherd_d256:
+ case X86::BI__builtin_ia32_gatherq_d:
+ case X86::BI__builtin_ia32_gatherq_d256:
+ case X86::BI__builtin_ia32_gather3div2df:
+ case X86::BI__builtin_ia32_gather3div2di:
+ case X86::BI__builtin_ia32_gather3div4df:
+ case X86::BI__builtin_ia32_gather3div4di:
+ case X86::BI__builtin_ia32_gather3div4sf:
+ case X86::BI__builtin_ia32_gather3div4si:
+ case X86::BI__builtin_ia32_gather3div8sf:
+ case X86::BI__builtin_ia32_gather3div8si:
+ case X86::BI__builtin_ia32_gather3siv2df:
+ case X86::BI__builtin_ia32_gather3siv2di:
+ case X86::BI__builtin_ia32_gather3siv4df:
+ case X86::BI__builtin_ia32_gather3siv4di:
+ case X86::BI__builtin_ia32_gather3siv4sf:
+ case X86::BI__builtin_ia32_gather3siv4si:
+ case X86::BI__builtin_ia32_gather3siv8sf:
+ case X86::BI__builtin_ia32_gather3siv8si:
+ case X86::BI__builtin_ia32_gathersiv8df:
+ case X86::BI__builtin_ia32_gathersiv16sf:
+ case X86::BI__builtin_ia32_gatherdiv8df:
+ case X86::BI__builtin_ia32_gatherdiv16sf:
+ case X86::BI__builtin_ia32_gathersiv8di:
+ case X86::BI__builtin_ia32_gathersiv16si:
+ case X86::BI__builtin_ia32_gatherdiv8di:
+ case X86::BI__builtin_ia32_gatherdiv16si:
+ case X86::BI__builtin_ia32_scatterdiv2df:
+ case X86::BI__builtin_ia32_scatterdiv2di:
+ case X86::BI__builtin_ia32_scatterdiv4df:
+ case X86::BI__builtin_ia32_scatterdiv4di:
+ case X86::BI__builtin_ia32_scatterdiv4sf:
+ case X86::BI__builtin_ia32_scatterdiv4si:
+ case X86::BI__builtin_ia32_scatterdiv8sf:
+ case X86::BI__builtin_ia32_scatterdiv8si:
+ case X86::BI__builtin_ia32_scattersiv2df:
+ case X86::BI__builtin_ia32_scattersiv2di:
+ case X86::BI__builtin_ia32_scattersiv4df:
+ case X86::BI__builtin_ia32_scattersiv4di:
+ case X86::BI__builtin_ia32_scattersiv4sf:
+ case X86::BI__builtin_ia32_scattersiv4si:
+ case X86::BI__builtin_ia32_scattersiv8sf:
+ case X86::BI__builtin_ia32_scattersiv8si:
+ case X86::BI__builtin_ia32_scattersiv8df:
+ case X86::BI__builtin_ia32_scattersiv16sf:
+ case X86::BI__builtin_ia32_scatterdiv8df:
+ case X86::BI__builtin_ia32_scatterdiv16sf:
+ case X86::BI__builtin_ia32_scattersiv8di:
+ case X86::BI__builtin_ia32_scattersiv16si:
+ case X86::BI__builtin_ia32_scatterdiv8di:
+ case X86::BI__builtin_ia32_scatterdiv16si:
+ ArgNum = 4;
+ break;
+ }
+
+ llvm::APSInt Result;
+
+ // We can't check the value of a dependent argument.
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ return false;
+
+ // Check constant-ness first.
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
+ return true;
+
+ if (Result == 1 || Result == 2 || Result == 4 || Result == 8)
+ return false;
+
+ return Diag(TheCall->getLocStart(), diag::err_x86_builtin_invalid_scale)
+ << Arg->getSourceRange();
+}
+
bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (BuiltinID == X86::BI__builtin_cpu_supports)
return SemaBuiltinCpuSupports(*this, TheCall);
- if (BuiltinID == X86::BI__builtin_ms_va_start)
- return SemaBuiltinMSVAStart(TheCall);
-
// If the intrinsic has rounding or SAE make sure its valid.
if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall))
return true;
+ // If the intrinsic has a gather/scatter scale immediate make sure its valid.
+ if (CheckX86BuiltinGatherScatterScale(BuiltinID, TheCall))
+ return true;
+
// For intrinsics which take an immediate value as part of the instruction,
// range check them here.
int i = 0, l = 0, u = 0;
@@ -2197,6 +2307,16 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_pternlogq256_maskz:
i = 3; l = 0; u = 255;
break;
+ case X86::BI__builtin_ia32_gatherpfdpd:
+ case X86::BI__builtin_ia32_gatherpfdps:
+ case X86::BI__builtin_ia32_gatherpfqpd:
+ case X86::BI__builtin_ia32_gatherpfqps:
+ case X86::BI__builtin_ia32_scatterpfdpd:
+ case X86::BI__builtin_ia32_scatterpfdps:
+ case X86::BI__builtin_ia32_scatterpfqpd:
+ case X86::BI__builtin_ia32_scatterpfqps:
+ i = 4; l = 2; u = 3;
+ break;
case X86::BI__builtin_ia32_pcmpestrm128:
case X86::BI__builtin_ia32_pcmpestri128:
case X86::BI__builtin_ia32_pcmpestria128:
@@ -3502,11 +3622,89 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) {
return Result;
}
+/// Check that the user is calling the appropriate va_start builtin for the
+/// target and calling convention.
+static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
+ const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
+ bool IsX64 = TT.getArch() == llvm::Triple::x86_64;
+ bool IsAArch64 = TT.getArch() == llvm::Triple::aarch64;
+ bool IsWindows = TT.isOSWindows();
+ bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start;
+ if (IsX64 || IsAArch64) {
+ clang::CallingConv CC = CC_C;
+ if (const FunctionDecl *FD = S.getCurFunctionDecl())
+ CC = FD->getType()->getAs<FunctionType>()->getCallConv();
+ if (IsMSVAStart) {
+ // Don't allow this in System V ABI functions.
+ if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_Win64))
+ return S.Diag(Fn->getLocStart(),
+ diag::err_ms_va_start_used_in_sysv_function);
+ } else {
+ // On x86-64/AArch64 Unix, don't allow this in Win64 ABI functions.
+ // On x64 Windows, don't allow this in System V ABI functions.
+ // (Yes, that means there's no corresponding way to support variadic
+ // System V ABI functions on Windows.)
+ if ((IsWindows && CC == CC_X86_64SysV) ||
+ (!IsWindows && CC == CC_Win64))
+ return S.Diag(Fn->getLocStart(),
+ diag::err_va_start_used_in_wrong_abi_function)
+ << !IsWindows;
+ }
+ return false;
+ }
+
+ if (IsMSVAStart)
+ return S.Diag(Fn->getLocStart(), diag::err_builtin_x64_aarch64_only);
+ return false;
+}
+
+static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn,
+ ParmVarDecl **LastParam = nullptr) {
+ // Determine whether the current function, block, or obj-c method is variadic
+ // and get its parameter list.
+ bool IsVariadic = false;
+ ArrayRef<ParmVarDecl *> Params;
+ 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 (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 {
+ // 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_fixed_function);
+ return true;
+ }
+
+ if (LastParam)
+ *LastParam = Params.empty() ? nullptr : Params.back();
+
+ return false;
+}
+
/// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start'
/// for validity. Emit an error and return true on failure; return false
/// on success.
-bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
+bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
Expr *Fn = TheCall->getCallee();
+
+ if (checkVAStartABI(*this, BuiltinID, Fn))
+ return true;
+
if (TheCall->getNumArgs() > 2) {
Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
@@ -3527,20 +3725,10 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
if (checkBuiltinArgument(*this, TheCall, 0))
return true;
- // Determine whether the current function is variadic or not.
- BlockScopeInfo *CurBlock = getCurBlock();
- bool isVariadic;
- if (CurBlock)
- isVariadic = CurBlock->TheDecl->isVariadic();
- else if (FunctionDecl *FD = getCurFunctionDecl())
- isVariadic = FD->isVariadic();
- else
- isVariadic = getCurMethodDecl()->isVariadic();
-
- if (!isVariadic) {
- Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
+ // Check that the current function is variadic, and get its last parameter.
+ ParmVarDecl *LastParam;
+ if (checkVAStartIsInVariadicFunction(*this, Fn, &LastParam))
return true;
- }
// Verify that the second argument to the builtin is the last argument of the
// current function or method.
@@ -3555,16 +3743,7 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
- // FIXME: This isn't correct for methods (results in bogus warning).
- // Get the last formal in the current function.
- const ParmVarDecl *LastArg;
- if (CurBlock)
- LastArg = CurBlock->TheDecl->parameters().back();
- else if (FunctionDecl *FD = getCurFunctionDecl())
- LastArg = FD->parameters().back();
- else
- LastArg = getCurMethodDecl()->parameters().back();
- SecondArgIsLastNamedArgument = PV == LastArg;
+ SecondArgIsLastNamedArgument = PV == LastParam;
Type = PV->getType();
ParamLoc = PV->getLocation();
@@ -3599,48 +3778,6 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
return false;
}
-/// Check the arguments to '__builtin_va_start' for validity, and that
-/// it was called from a function of the native ABI.
-/// Emit an error and return true on failure; return false on success.
-bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
- // On x86-64 Unix, don't allow this in Win64 ABI functions.
- // On x64 Windows, don't allow this in System V ABI functions.
- // (Yes, that means there's no corresponding way to support variadic
- // System V ABI functions on Windows.)
- if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64) {
- unsigned OS = Context.getTargetInfo().getTriple().getOS();
- clang::CallingConv CC = CC_C;
- if (const FunctionDecl *FD = getCurFunctionDecl())
- CC = FD->getType()->getAs<FunctionType>()->getCallConv();
- if ((OS == llvm::Triple::Win32 && CC == CC_X86_64SysV) ||
- (OS != llvm::Triple::Win32 && CC == CC_X86_64Win64))
- return Diag(TheCall->getCallee()->getLocStart(),
- diag::err_va_start_used_in_wrong_abi_function)
- << (OS != llvm::Triple::Win32);
- }
- return SemaBuiltinVAStartImpl(TheCall);
-}
-
-/// Check the arguments to '__builtin_ms_va_start' for validity, and that
-/// it was called from a Win64 ABI function.
-/// Emit an error and return true on failure; return false on success.
-bool Sema::SemaBuiltinMSVAStart(CallExpr *TheCall) {
- // This only makes sense for x86-64.
- const llvm::Triple &TT = Context.getTargetInfo().getTriple();
- Expr *Callee = TheCall->getCallee();
- if (TT.getArch() != llvm::Triple::x86_64)
- return Diag(Callee->getLocStart(), diag::err_x86_builtin_32_bit_tgt);
- // Don't allow this in System V ABI functions.
- clang::CallingConv CC = CC_C;
- if (const FunctionDecl *FD = getCurFunctionDecl())
- CC = FD->getType()->getAs<FunctionType>()->getCallConv();
- if (CC == CC_X86_64SysV ||
- (TT.getOS() != llvm::Triple::Win32 && CC != CC_X86_64Win64))
- return Diag(Callee->getLocStart(),
- diag::err_ms_va_start_used_in_sysv_function);
- return SemaBuiltinVAStartImpl(TheCall);
-}
-
bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
// void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
// const char *named_addr);
@@ -3652,26 +3789,14 @@ bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
diag::err_typecheck_call_too_few_args_at_least)
<< 0 /*function call*/ << 3 << Call->getNumArgs();
- // Determine whether the current function is variadic or not.
- bool IsVariadic;
- if (BlockScopeInfo *CurBlock = getCurBlock())
- IsVariadic = CurBlock->TheDecl->isVariadic();
- else if (FunctionDecl *FD = getCurFunctionDecl())
- IsVariadic = FD->isVariadic();
- else if (ObjCMethodDecl *MD = getCurMethodDecl())
- IsVariadic = MD->isVariadic();
- else
- llvm_unreachable("unexpected statement type");
-
- if (!IsVariadic) {
- Diag(Func->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
- return true;
- }
-
// Type-check the first argument normally.
if (checkBuiltinArgument(*this, Call, 0))
return true;
+ // Check that the current function is variadic.
+ if (checkVAStartIsInVariadicFunction(*this, Func))
+ return true;
+
const struct {
unsigned ArgNo;
QualType Type;
@@ -3779,6 +3904,65 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
return false;
}
+// Customized Sema Checking for VSX builtins that have the following signature:
+// vector [...] builtinName(vector [...], vector [...], const int);
+// Which takes the same type of vectors (any legal vector type) for the first
+// two arguments and takes compile time constant for the third argument.
+// Example builtins are :
+// vector double vec_xxpermdi(vector double, vector double, int);
+// vector short vec_xxsldwi(vector short, vector short, int);
+bool Sema::SemaBuiltinVSX(CallExpr *TheCall) {
+ unsigned ExpectedNumArgs = 3;
+ if (TheCall->getNumArgs() < ExpectedNumArgs)
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs()
+ << TheCall->getSourceRange();
+
+ if (TheCall->getNumArgs() > ExpectedNumArgs)
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_many_args_at_most)
+ << 0 /*function call*/ << ExpectedNumArgs << TheCall->getNumArgs()
+ << TheCall->getSourceRange();
+
+ // Check the third argument is a compile time constant
+ llvm::APSInt Value;
+ if(!TheCall->getArg(2)->isIntegerConstantExpr(Value, Context))
+ return Diag(TheCall->getLocStart(),
+ diag::err_vsx_builtin_nonconstant_argument)
+ << 3 /* argument index */ << TheCall->getDirectCallee()
+ << SourceRange(TheCall->getArg(2)->getLocStart(),
+ TheCall->getArg(2)->getLocEnd());
+
+ QualType Arg1Ty = TheCall->getArg(0)->getType();
+ QualType Arg2Ty = TheCall->getArg(1)->getType();
+
+ // Check the type of argument 1 and argument 2 are vectors.
+ SourceLocation BuiltinLoc = TheCall->getLocStart();
+ if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) ||
+ (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) {
+ return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
+ << TheCall->getDirectCallee()
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
+ TheCall->getArg(1)->getLocEnd());
+ }
+
+ // Check the first two arguments are the same type.
+ if (!Context.hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) {
+ return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
+ << TheCall->getDirectCallee()
+ << SourceRange(TheCall->getArg(0)->getLocStart(),
+ TheCall->getArg(1)->getLocEnd());
+ }
+
+ // When default clang type checking is turned off and the customized type
+ // checking is used, the returning type of the function must be explicitly
+ // set. Otherwise it is _Bool by default.
+ TheCall->setType(Arg1Ty);
+
+ return false;
+}
+
/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector.
// This is declared to take (...), so we have to check everything.
ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
@@ -3801,7 +3985,8 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (!LHSType->isVectorType() || !RHSType->isVectorType())
return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_non_vector)
+ diag::err_vec_builtin_non_vector)
+ << TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd()));
@@ -3815,12 +4000,14 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (!RHSType->hasIntegerRepresentation() ||
RHSType->getAs<VectorType>()->getNumElements() != numElements)
return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_incompatible_vector)
+ diag::err_vec_builtin_incompatible_vector)
+ << TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(1)->getLocStart(),
TheCall->getArg(1)->getLocEnd()));
} else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_incompatible_vector)
+ diag::err_vec_builtin_incompatible_vector)
+ << TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(0)->getLocStart(),
TheCall->getArg(1)->getLocEnd()));
} else if (numElements != numResElements) {
@@ -5822,6 +6009,7 @@ shouldNotPrintDirectly(const ASTContext &Context,
while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
StringRef Name = UserTy->getDecl()->getName();
QualType CastTy = llvm::StringSwitch<QualType>(Name)
+ .Case("CFIndex", Context.LongTy)
.Case("NSInteger", Context.LongTy)
.Case("NSUInteger", Context.UnsignedLongTy)
.Case("SInt32", Context.IntTy)
@@ -6782,7 +6970,7 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
if (!Call || !FDecl) return;
// Ignore template specializations and macros.
- if (!ActiveTemplateInstantiations.empty()) return;
+ if (inTemplateInstantiation()) return;
if (Call->getExprLoc().isMacroID()) return;
// Only care about the one template argument, two function parameter std::max
@@ -7340,7 +7528,7 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
if (!stackE)
return; // Nothing suspicious was found.
- // Parameters are initalized in the calling scope, so taking the address
+ // Parameters are initialized in the calling scope, so taking the address
// of a parameter reference doesn't need a warning.
for (auto *DRE : refVars)
if (isa<ParmVarDecl>(DRE->getDecl()))
@@ -8235,7 +8423,7 @@ bool HasEnumType(Expr *E) {
void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
// Disable warning in template instantiations.
- if (!S.ActiveTemplateInstantiations.empty())
+ if (S.inTemplateInstantiation())
return;
BinaryOperatorKind op = E->getOpcode();
@@ -8265,7 +8453,7 @@ void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
Expr *Other, const llvm::APSInt &Value,
bool RhsConstant) {
// Disable warning in template instantiations.
- if (!S.ActiveTemplateInstantiations.empty())
+ if (S.inTemplateInstantiation())
return;
// TODO: Investigate using GetExprRange() to get tighter bounds
@@ -8616,13 +8804,66 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
return false;
Expr *OriginalInit = Init->IgnoreParenImpCasts();
+ unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context);
llvm::APSInt Value;
- if (!OriginalInit->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects))
+ if (!OriginalInit->EvaluateAsInt(Value, S.Context,
+ Expr::SE_AllowSideEffects)) {
+ // The RHS is not constant. If the RHS has an enum type, make sure the
+ // bitfield is wide enough to hold all the values of the enum without
+ // truncation.
+ if (const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>()) {
+ EnumDecl *ED = EnumTy->getDecl();
+ bool SignedBitfield = BitfieldType->isSignedIntegerType();
+
+ // Enum types are implicitly signed on Windows, so check if there are any
+ // negative enumerators to see if the enum was intended to be signed or
+ // not.
+ bool SignedEnum = ED->getNumNegativeBits() > 0;
+
+ // Check for surprising sign changes when assigning enum values to a
+ // bitfield of different signedness. If the bitfield is signed and we
+ // have exactly the right number of bits to store this unsigned enum,
+ // suggest changing the enum to an unsigned type. This typically happens
+ // on Windows where unfixed enums always use an underlying type of 'int'.
+ unsigned DiagID = 0;
+ if (SignedEnum && !SignedBitfield) {
+ DiagID = diag::warn_unsigned_bitfield_assigned_signed_enum;
+ } else if (SignedBitfield && !SignedEnum &&
+ ED->getNumPositiveBits() == FieldWidth) {
+ DiagID = diag::warn_signed_bitfield_enum_conversion;
+ }
+
+ if (DiagID) {
+ S.Diag(InitLoc, DiagID) << Bitfield << ED;
+ TypeSourceInfo *TSI = Bitfield->getTypeSourceInfo();
+ SourceRange TypeRange =
+ TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange();
+ S.Diag(Bitfield->getTypeSpecStartLoc(), diag::note_change_bitfield_sign)
+ << SignedEnum << TypeRange;
+ }
+
+ // Compute the required bitwidth. If the enum has negative values, we need
+ // one more bit than the normal number of positive bits to represent the
+ // sign bit.
+ unsigned BitsNeeded = SignedEnum ? std::max(ED->getNumPositiveBits() + 1,
+ ED->getNumNegativeBits())
+ : ED->getNumPositiveBits();
+
+ // Check the bitwidth.
+ if (BitsNeeded > FieldWidth) {
+ Expr *WidthExpr = Bitfield->getBitWidth();
+ S.Diag(InitLoc, diag::warn_bitfield_too_small_for_enum)
+ << Bitfield << ED;
+ S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield)
+ << BitsNeeded << ED << WidthExpr->getSourceRange();
+ }
+ }
+
return false;
+ }
unsigned OriginalWidth = Value.getBitWidth();
- unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context);
if (!Value.isSigned() || Value.isNegative())
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit))
@@ -8703,7 +8944,7 @@ void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
SourceLocation CContext) {
const bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool);
- const bool PruneWarnings = !S.ActiveTemplateInstantiations.empty();
+ const bool PruneWarnings = S.inTemplateInstantiation();
Expr *InnerE = E->IgnoreParenImpCasts();
// We also want to warn on, e.g., "int i = -1.234"
@@ -9720,6 +9961,9 @@ void Sema::CheckForIntOverflow (Expr *E) {
if (auto InitList = dyn_cast<InitListExpr>(E))
Exprs.append(InitList->inits().begin(), InitList->inits().end());
+
+ if (isa<ObjCBoxedExpr>(E))
+ E->IgnoreParenCasts()->EvaluateForOverflow(Context);
} while (!Exprs.empty());
}
@@ -10609,6 +10853,12 @@ void Sema::CheckArrayAccess(const Expr *expr) {
CheckArrayAccess(rhs);
return;
}
+ case Stmt::CXXOperatorCallExprClass: {
+ const auto *OCE = cast<CXXOperatorCallExpr>(expr);
+ for (const auto *Arg : OCE->arguments())
+ CheckArrayAccess(Arg);
+ return;
+ }
default:
return;
}
@@ -11314,7 +11564,7 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc))
return;
- if (!ActiveTemplateInstantiations.empty())
+ if (inTemplateInstantiation())
return;
// Strip parens and casts away.
@@ -11839,6 +12089,10 @@ void Sema::RefersToMemberWithReducedAlignment(
if (!ME)
return;
+ // No need to check expressions with an __unaligned-qualified type.
+ if (E->getType().getQualifiers().hasUnaligned())
+ return;
+
// For a chain of MemberExpr like "a.b.c.d" this list
// will keep FieldDecl's like [d, c, b].
SmallVector<FieldDecl *, 4> ReverseMemberChain;
@@ -11849,6 +12103,8 @@ void Sema::RefersToMemberWithReducedAlignment(
if (ME->isArrow())
BaseType = BaseType->getPointeeType();
RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl();
+ if (RD->isInvalidDecl())
+ return;
ValueDecl *MD = ME->getMemberDecl();
auto *FD = dyn_cast<FieldDecl>(MD);
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp
index 94cfc4b..4de7d42 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1334,8 +1334,9 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
Builder.AddChunk(CodeCompletionString::CK_RightParen);
Results.AddResult(Result(Builder.TakeString()));
}
- }
-
+ } else
+ Results.AddResult(Result("__auto_type", CCP_Type));
+
// GNU extensions
if (LangOpts.GNUMode) {
// FIXME: Enable when we actually support decimal floating point.
@@ -1370,6 +1371,21 @@ static void AddStorageSpecifiers(Sema::ParserCompletionContext CCC,
// in C++0x as a type specifier.
Results.AddResult(Result("extern"));
Results.AddResult(Result("static"));
+
+ if (LangOpts.CPlusPlus11) {
+ CodeCompletionAllocator &Allocator = Results.getAllocator();
+ CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());
+
+ // alignas
+ Builder.AddTypedTextChunk("alignas");
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("expression");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Builder.TakeString()));
+
+ Results.AddResult(Result("constexpr"));
+ Results.AddResult(Result("thread_local"));
+ }
}
static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC,
@@ -1527,6 +1543,21 @@ static void addThisCompletion(Sema &S, ResultBuilder &Results) {
Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
+static void AddStaticAssertResult(CodeCompletionBuilder &Builder,
+ ResultBuilder &Results,
+ const LangOptions &LangOpts) {
+ if (!LangOpts.CPlusPlus11)
+ return;
+
+ Builder.AddTypedTextChunk("static_assert");
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("expression");
+ Builder.AddChunk(CodeCompletionString::CK_Comma);
+ Builder.AddPlaceholderChunk("message");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(CodeCompletionResult(Builder.TakeString()));
+}
+
/// \brief Add language constructs that show up for "ordinary" names.
static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Scope *S,
@@ -1611,6 +1642,8 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Results.AddResult(Result(Builder.TakeString()));
}
+ AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
+
if (CCC == Sema::PCC_Class) {
AddTypedefResult(Results);
@@ -1824,13 +1857,17 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("identifier");
Results.AddResult(Result(Builder.TakeString()));
+
+ AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
}
+ LLVM_FALLTHROUGH;
// Fall through (for statement expressions).
case Sema::PCC_ForInit:
case Sema::PCC_Condition:
AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
// Fall through: conditions and statements can have expressions.
+ LLVM_FALLTHROUGH;
case Sema::PCC_ParenthesizedExpression:
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
@@ -1860,6 +1897,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
Results.AddResult(Result(Builder.TakeString()));
}
// Fall through
+ LLVM_FALLTHROUGH;
case Sema::PCC_Expression: {
if (SemaRef.getLangOpts().CPlusPlus) {
@@ -2253,6 +2291,15 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy,
FunctionProtoTypeLoc BlockProto;
findTypeLocationForBlockDecl(Param->getTypeSourceInfo(), Block, BlockProto,
SuppressBlock);
+ // Try to retrieve the block type information from the property if this is a
+ // parameter in a setter.
+ if (!Block && ObjCMethodParam &&
+ cast<ObjCMethodDecl>(Param->getDeclContext())->isPropertyAccessor()) {
+ if (const auto *PD = cast<ObjCMethodDecl>(Param->getDeclContext())
+ ->findPropertyDecl(/*CheckOverrides=*/false))
+ findTypeLocationForBlockDecl(PD->getTypeSourceInfo(), Block, BlockProto,
+ SuppressBlock);
+ }
if (!Block) {
// We were unable to find a FunctionProtoTypeLoc with parameter names
@@ -2351,6 +2398,34 @@ formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
return Result;
}
+static std::string GetDefaultValueString(const ParmVarDecl *Param,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ const SourceRange SrcRange = Param->getDefaultArgRange();
+ CharSourceRange CharSrcRange = CharSourceRange::getTokenRange(SrcRange);
+ bool Invalid = CharSrcRange.isInvalid();
+ if (Invalid)
+ return "";
+ StringRef srcText = Lexer::getSourceText(CharSrcRange, SM, LangOpts, &Invalid);
+ if (Invalid)
+ return "";
+
+ if (srcText.empty() || srcText == "=") {
+ // Lexer can't determine the value.
+ // This happens if the code is incorrect (for example class is forward declared).
+ return "";
+ }
+ std::string DefValue(srcText.str());
+ // FIXME: remove this check if the Lexer::getSourceText value is fixed and
+ // this value always has (or always does not have) '=' in front of it
+ if (DefValue.at(0) != '=') {
+ // If we don't have '=' in front of value.
+ // Lexer returns built-in types values without '=' and user-defined types values with it.
+ return " = " + DefValue;
+ }
+ return " " + DefValue;
+}
+
/// \brief Add function parameter chunks to the given code completion string.
static void AddFunctionParameterChunks(Preprocessor &PP,
const PrintingPolicy &Policy,
@@ -2384,6 +2459,8 @@ static void AddFunctionParameterChunks(Preprocessor &PP,
// Format the placeholder string.
std::string PlaceholderStr = FormatFunctionParameter(Policy, Param);
+ if (Param->hasDefaultArg())
+ PlaceholderStr += GetDefaultValueString(Param, PP.getSourceManager(), PP.getLangOpts());
if (Function->isVariadic() && P == N - 1)
PlaceholderStr += ", ...";
@@ -2585,6 +2662,7 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
Result.getAllocator().CopyString(ND->getNameAsString()));
break;
+ case DeclarationName::CXXDeductionGuideName:
case DeclarationName::CXXUsingDirective:
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
@@ -2690,7 +2768,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
// Format a function-like macro with placeholders for the arguments.
Result.AddChunk(CodeCompletionString::CK_LeftParen);
- MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end();
+ MacroInfo::param_iterator A = MI->param_begin(), AEnd = MI->param_end();
// C99 variadic macros add __VA_ARGS__ at the end. Skip it.
if (MI->isC99Varargs()) {
@@ -2701,8 +2779,8 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
}
}
- for (MacroInfo::arg_iterator A = MI->arg_begin(); A != AEnd; ++A) {
- if (A != MI->arg_begin())
+ for (MacroInfo::param_iterator A = MI->param_begin(); A != AEnd; ++A) {
+ if (A != MI->param_begin())
Result.AddChunk(CodeCompletionString::CK_Comma);
if (MI->isVariadic() && (A+1) == AEnd) {
@@ -2964,10 +3042,14 @@ static void AddOverloadParameterChunks(ASTContext &Context,
// Format the placeholder string.
std::string Placeholder;
- if (Function)
- Placeholder = FormatFunctionParameter(Policy, Function->getParamDecl(P));
- else
+ if (Function) {
+ const ParmVarDecl *Param = Function->getParamDecl(P);
+ Placeholder = FormatFunctionParameter(Policy, Param);
+ if (Param->hasDefaultArg())
+ Placeholder += GetDefaultValueString(Param, Context.getSourceManager(), Context.getLangOpts());
+ } else {
Placeholder = Prototype->getParamType(P).getAsString(Policy);
+ }
if (P == CurrentArg)
Result.AddCurrentParameterChunk(
@@ -3482,6 +3564,11 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
Results.AddResult(Result("restrict"));
if (getLangOpts().CPlusPlus) {
+ if (getLangOpts().CPlusPlus11 &&
+ (DS.getTypeSpecType() == DeclSpec::TST_class ||
+ DS.getTypeSpecType() == DeclSpec::TST_struct))
+ Results.AddResult("final");
+
if (AllowNonIdentifiers) {
Results.AddResult(Result("operator"));
}
@@ -3819,6 +3906,41 @@ static void AddObjCProperties(
}
}
+static void AddRecordMembersCompletionResults(Sema &SemaRef,
+ ResultBuilder &Results, Scope *S,
+ QualType BaseType,
+ RecordDecl *RD) {
+ // Indicate that we are performing a member access, and the cv-qualifiers
+ // for the base object type.
+ Results.setObjectTypeQualifiers(BaseType.getQualifiers());
+
+ // Access to a C/C++ class, struct, or union.
+ Results.allowNestedNameSpecifiers();
+ CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);
+ SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer,
+ SemaRef.CodeCompleter->includeGlobals(),
+ /*IncludeDependentBases=*/true);
+
+ if (SemaRef.getLangOpts().CPlusPlus) {
+ if (!Results.empty()) {
+ // The "template" keyword can follow "->" or "." in the grammar.
+ // However, we only want to suggest the template keyword if something
+ // is dependent.
+ bool IsDependent = BaseType->isDependentType();
+ if (!IsDependent) {
+ for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent())
+ if (DeclContext *Ctx = DepScope->getEntity()) {
+ IsDependent = Ctx->isDependentContext();
+ break;
+ }
+ }
+
+ if (IsDependent)
+ Results.AddResult(CodeCompletionResult("template"));
+ }
+ }
+}
+
void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
SourceLocation OpLoc, bool IsArrow,
bool IsBaseExprStatement) {
@@ -3829,8 +3951,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
if (ConvertedBase.isInvalid())
return;
Base = ConvertedBase.get();
-
- typedef CodeCompletionResult Result;
QualType BaseType = Base->getType();
@@ -3865,34 +3985,18 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
&ResultBuilder::IsMember);
Results.EnterNewScope();
if (const RecordType *Record = BaseType->getAs<RecordType>()) {
- // Indicate that we are performing a member access, and the cv-qualifiers
- // for the base object type.
- Results.setObjectTypeQualifiers(BaseType.getQualifiers());
-
- // Access to a C/C++ class, struct, or union.
- Results.allowNestedNameSpecifiers();
- CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer,
- CodeCompleter->includeGlobals());
-
- if (getLangOpts().CPlusPlus) {
- if (!Results.empty()) {
- // The "template" keyword can follow "->" or "." in the grammar.
- // However, we only want to suggest the template keyword if something
- // is dependent.
- bool IsDependent = BaseType->isDependentType();
- if (!IsDependent) {
- for (Scope *DepScope = S; DepScope; DepScope = DepScope->getParent())
- if (DeclContext *Ctx = DepScope->getEntity()) {
- IsDependent = Ctx->isDependentContext();
- break;
- }
- }
-
- if (IsDependent)
- Results.AddResult(Result("template"));
- }
- }
+ AddRecordMembersCompletionResults(*this, Results, S, BaseType,
+ Record->getDecl());
+ } else if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) {
+ TemplateName TN = TST->getTemplateName();
+ if (const auto *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) {
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD);
+ }
+ } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) {
+ if (auto *RD = ICNT->getDecl())
+ AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD);
} else if (!IsArrow && BaseType->isObjCObjectPointerType()) {
// Objective-C property reference.
AddedPropertiesSet AddedProperties;
@@ -4012,30 +4116,54 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
Results.data(),Results.size());
}
-void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) {
- ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompleter->getCodeCompletionTUInfo(),
- CodeCompletionContext::CCC_TypeQualifiers);
- Results.EnterNewScope();
+static void AddTypeQualifierResults(DeclSpec &DS, ResultBuilder &Results,
+ const LangOptions &LangOpts) {
if (!(DS.getTypeQualifiers() & DeclSpec::TQ_const))
Results.AddResult("const");
if (!(DS.getTypeQualifiers() & DeclSpec::TQ_volatile))
Results.AddResult("volatile");
- if (getLangOpts().C99 &&
- !(DS.getTypeQualifiers() & DeclSpec::TQ_restrict))
+ if (LangOpts.C99 && !(DS.getTypeQualifiers() & DeclSpec::TQ_restrict))
Results.AddResult("restrict");
- if (getLangOpts().C11 &&
- !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic))
+ if (LangOpts.C11 && !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic))
Results.AddResult("_Atomic");
- if (getLangOpts().MSVCCompat &&
- !(DS.getTypeQualifiers() & DeclSpec::TQ_unaligned))
+ if (LangOpts.MSVCCompat && !(DS.getTypeQualifiers() & DeclSpec::TQ_unaligned))
Results.AddResult("__unaligned");
+}
+
+void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) {
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext::CCC_TypeQualifiers);
+ Results.EnterNewScope();
+ AddTypeQualifierResults(DS, Results, LangOpts);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
Results.getCompletionContext(),
Results.data(), Results.size());
}
+void Sema::CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D,
+ const VirtSpecifiers *VS) {
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext::CCC_TypeQualifiers);
+ Results.EnterNewScope();
+ AddTypeQualifierResults(DS, Results, LangOpts);
+ if (LangOpts.CPlusPlus11) {
+ Results.AddResult("noexcept");
+ if (D.getContext() == Declarator::MemberContext && !D.isCtorOrDtor() &&
+ !D.isStaticMember()) {
+ if (!VS || !VS->isFinalSpecified())
+ Results.AddResult("final");
+ if (!VS || !VS->isOverrideSpecified())
+ Results.AddResult("override");
+ }
+ }
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+ Results.data(), Results.size());
+}
+
void Sema::CodeCompleteBracketDeclarator(Scope *S) {
CodeCompleteExpression(S, QualType(getASTContext().getSizeType()));
}
@@ -4244,7 +4372,10 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args) {
UME->copyTemplateArgumentsInto(TemplateArgsBuffer);
TemplateArgs = &TemplateArgsBuffer;
}
- SmallVector<Expr *, 12> ArgExprs(1, UME->getBase());
+
+ // Add the base as first argument (use a nullptr if the base is implicit).
+ SmallVector<Expr *, 12> ArgExprs(
+ 1, UME->isImplicitAccess() ? nullptr : UME->getBase());
ArgExprs.append(Args.begin(), Args.end());
UnresolvedSet<8> Decls;
Decls.append(UME->decls_begin(), UME->decls_end());
@@ -4445,8 +4576,10 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext) {
if (!SS.getScopeRep() || !CodeCompleter)
return;
-
- DeclContext *Ctx = computeDeclContext(SS, EnteringContext);
+
+ // Always pretend to enter a context to ensure that a dependent type
+ // resolves to a dependent record.
+ DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true);
if (!Ctx)
return;
@@ -4476,7 +4609,9 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
Results.ExitScope();
CodeCompletionDeclConsumer Consumer(Results, CurContext);
- LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer);
+ LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer,
+ /*IncludeGlobalScope=*/true,
+ /*IncludeDependentBases=*/true);
HandleCodeCompleteResults(this, CodeCompleter,
Results.getCompletionContext(),
@@ -5230,24 +5365,22 @@ namespace {
/// when it has the same number of parameters as we have selector identifiers.
///
/// \param Results the structure into which we'll add results.
-static void AddObjCMethods(ObjCContainerDecl *Container,
- bool WantInstanceMethods,
- ObjCMethodKind WantKind,
+static void AddObjCMethods(ObjCContainerDecl *Container,
+ bool WantInstanceMethods, ObjCMethodKind WantKind,
ArrayRef<IdentifierInfo *> SelIdents,
DeclContext *CurContext,
- VisitedSelectorSet &Selectors,
- bool AllowSameLength,
- ResultBuilder &Results,
- bool InOriginalClass = true) {
+ VisitedSelectorSet &Selectors, bool AllowSameLength,
+ ResultBuilder &Results, bool InOriginalClass = true,
+ bool IsRootClass = false) {
typedef CodeCompletionResult Result;
Container = getContainerDef(Container);
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
- bool isRootClass = IFace && !IFace->getSuperClass();
+ IsRootClass = IsRootClass || (IFace && !IFace->getSuperClass());
for (auto *M : Container->methods()) {
// The instance methods on the root class can be messaged via the
// metaclass.
if (M->isInstanceMethod() == WantInstanceMethods ||
- (isRootClass && !WantInstanceMethods)) {
+ (IsRootClass && !WantInstanceMethods)) {
// Check whether the selector identifiers we've been given are a
// subset of the identifiers for this particular method.
if (!isAcceptableObjCMethod(M, WantKind, SelIdents, AllowSameLength))
@@ -5273,8 +5406,8 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end();
I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength, Results, false);
+ AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, false, IsRootClass);
}
}
@@ -5283,43 +5416,43 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
// Add methods in protocols.
for (auto *I : IFace->protocols())
- AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength, Results, false);
-
+ AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, false, IsRootClass);
+
// Add methods in categories.
for (auto *CatDecl : IFace->known_categories()) {
AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength,
- Results, InOriginalClass);
-
+ CurContext, Selectors, AllowSameLength, Results,
+ InOriginalClass, IsRootClass);
+
// Add a categories protocol methods.
const ObjCList<ObjCProtocolDecl> &Protocols
= CatDecl->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end();
I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength,
- Results, false);
-
+ AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, false, IsRootClass);
+
// Add methods in category implementations.
if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation())
- AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength,
- Results, InOriginalClass);
+ AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, InOriginalClass,
+ IsRootClass);
}
// Add methods in superclass.
+ // Avoid passing in IsRootClass since root classes won't have super classes.
if (IFace->getSuperClass())
- AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind,
- SelIdents, CurContext, Selectors,
- AllowSameLength, Results, false);
+ AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind,
+ SelIdents, CurContext, Selectors, AllowSameLength, Results,
+ /*IsRootClass=*/false);
// Add methods in our implementation, if any.
if (ObjCImplementationDecl *Impl = IFace->getImplementation())
- AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents,
- CurContext, Selectors, AllowSameLength,
- Results, InOriginalClass);
+ AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, CurContext,
+ Selectors, AllowSameLength, Results, InOriginalClass,
+ IsRootClass);
}
@@ -7736,6 +7869,23 @@ void Sema::CodeCompleteNaturalLanguage() {
nullptr, 0);
}
+void Sema::CodeCompleteAvailabilityPlatformName() {
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext::CCC_Other);
+ Results.EnterNewScope();
+ static const char *Platforms[] = {"macOS", "iOS", "watchOS", "tvOS"};
+ for (const char *Platform : llvm::makeArrayRef(Platforms)) {
+ Results.AddResult(CodeCompletionResult(Platform));
+ Results.AddResult(CodeCompletionResult(Results.getAllocator().CopyString(
+ Twine(Platform) + "ApplicationExtension")));
+ }
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter,
+ CodeCompletionContext::CCC_Other, Results.data(),
+ Results.size());
+}
+
void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
SmallVectorImpl<CodeCompletionResult> &Results) {
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp
index 9814b4a..dc7d8e4 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp
@@ -11,31 +11,55 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
+#include "CoroutineStmtBuilder.h"
#include "clang/AST/Decl.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Overload.h"
+#include "clang/Sema/SemaInternal.h"
+
using namespace clang;
using namespace sema;
+static LookupResult lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
+ SourceLocation Loc, bool &Res) {
+ DeclarationName DN = S.PP.getIdentifierInfo(Name);
+ LookupResult LR(S, DN, Loc, Sema::LookupMemberName);
+ // Suppress diagnostics when a private member is selected. The same warnings
+ // will be produced again when building the call.
+ LR.suppressDiagnostics();
+ Res = S.LookupQualifiedName(LR, RD);
+ return LR;
+}
+
+static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD,
+ SourceLocation Loc) {
+ bool Res;
+ lookupMember(S, Name, RD, Loc, Res);
+ return Res;
+}
+
/// Look up the std::coroutine_traits<...>::promise_type for the given
/// function type.
-static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
- SourceLocation Loc) {
+static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
+ SourceLocation KwLoc) {
+ const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>();
+ const SourceLocation FuncLoc = FD->getLocation();
// FIXME: Cache std::coroutine_traits once we've found it.
NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace();
if (!StdExp) {
- S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
+ S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found)
+ << "std::experimental::coroutine_traits";
return QualType();
}
LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"),
- Loc, Sema::LookupOrdinaryName);
+ FuncLoc, Sema::LookupOrdinaryName);
if (!S.LookupQualifiedName(Result, StdExp)) {
- S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found);
+ S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found)
+ << "std::experimental::coroutine_traits";
return QualType();
}
@@ -48,57 +72,126 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType,
return QualType();
}
- // Form template argument list for coroutine_traits<R, P1, P2, ...>.
- TemplateArgumentListInfo Args(Loc, Loc);
- Args.addArgument(TemplateArgumentLoc(
- TemplateArgument(FnType->getReturnType()),
- S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), Loc)));
- // FIXME: If the function is a non-static member function, add the type
+ // Form template argument list for coroutine_traits<R, P1, P2, ...> according
+ // to [dcl.fct.def.coroutine]3
+ TemplateArgumentListInfo Args(KwLoc, KwLoc);
+ auto AddArg = [&](QualType T) {
+ Args.addArgument(TemplateArgumentLoc(
+ TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc)));
+ };
+ AddArg(FnType->getReturnType());
+ // If the function is a non-static member function, add the type
// of the implicit object parameter before the formal parameters.
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (MD->isInstance()) {
+ // [over.match.funcs]4
+ // For non-static member functions, the type of the implicit object
+ // parameter is
+ // -- "lvalue reference to cv X" for functions declared without a
+ // ref-qualifier or with the & ref-qualifier
+ // -- "rvalue reference to cv X" for functions declared with the &&
+ // ref-qualifier
+ QualType T =
+ MD->getThisType(S.Context)->getAs<PointerType>()->getPointeeType();
+ T = FnType->getRefQualifier() == RQ_RValue
+ ? S.Context.getRValueReferenceType(T)
+ : S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true);
+ AddArg(T);
+ }
+ }
for (QualType T : FnType->getParamTypes())
- Args.addArgument(TemplateArgumentLoc(
- TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, Loc)));
+ AddArg(T);
// Build the template-id.
QualType CoroTrait =
- S.CheckTemplateIdType(TemplateName(CoroTraits), Loc, Args);
+ S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args);
if (CoroTrait.isNull())
return QualType();
- if (S.RequireCompleteType(Loc, CoroTrait,
- diag::err_coroutine_traits_missing_specialization))
+ if (S.RequireCompleteType(KwLoc, CoroTrait,
+ diag::err_coroutine_type_missing_specialization))
return QualType();
- CXXRecordDecl *RD = CoroTrait->getAsCXXRecordDecl();
+ auto *RD = CoroTrait->getAsCXXRecordDecl();
assert(RD && "specialization of class template is not a class?");
// Look up the ::promise_type member.
- LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), Loc,
+ LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), KwLoc,
Sema::LookupOrdinaryName);
S.LookupQualifiedName(R, RD);
auto *Promise = R.getAsSingle<TypeDecl>();
if (!Promise) {
- S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_found)
+ S.Diag(FuncLoc,
+ diag::err_implied_std_coroutine_traits_promise_type_not_found)
<< RD;
return QualType();
}
-
// The promise type is required to be a class type.
QualType PromiseType = S.Context.getTypeDeclType(Promise);
- if (!PromiseType->getAsCXXRecordDecl()) {
- // Use the fully-qualified name of the type.
+
+ auto buildElaboratedType = [&]() {
auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, StdExp);
NNS = NestedNameSpecifier::Create(S.Context, NNS, false,
CoroTrait.getTypePtr());
- PromiseType = S.Context.getElaboratedType(ETK_None, NNS, PromiseType);
+ return S.Context.getElaboratedType(ETK_None, NNS, PromiseType);
+ };
- S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_class)
- << PromiseType;
+ if (!PromiseType->getAsCXXRecordDecl()) {
+ S.Diag(FuncLoc,
+ diag::err_implied_std_coroutine_traits_promise_type_not_class)
+ << buildElaboratedType();
return QualType();
}
+ if (S.RequireCompleteType(FuncLoc, buildElaboratedType(),
+ diag::err_coroutine_promise_type_incomplete))
+ return QualType();
return PromiseType;
}
+/// Look up the std::experimental::coroutine_handle<PromiseType>.
+static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
+ SourceLocation Loc) {
+ if (PromiseType.isNull())
+ return QualType();
+
+ NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace();
+ assert(StdExp && "Should already be diagnosed");
+
+ LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_handle"),
+ Loc, Sema::LookupOrdinaryName);
+ if (!S.LookupQualifiedName(Result, StdExp)) {
+ S.Diag(Loc, diag::err_implied_coroutine_type_not_found)
+ << "std::experimental::coroutine_handle";
+ return QualType();
+ }
+
+ ClassTemplateDecl *CoroHandle = Result.getAsSingle<ClassTemplateDecl>();
+ if (!CoroHandle) {
+ Result.suppressDiagnostics();
+ // We found something weird. Complain about the first thing we found.
+ NamedDecl *Found = *Result.begin();
+ S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_handle);
+ return QualType();
+ }
+
+ // Form template argument list for coroutine_handle<Promise>.
+ TemplateArgumentListInfo Args(Loc, Loc);
+ Args.addArgument(TemplateArgumentLoc(
+ TemplateArgument(PromiseType),
+ S.Context.getTrivialTypeSourceInfo(PromiseType, Loc)));
+
+ // Build the template-id.
+ QualType CoroHandleType =
+ S.CheckTemplateIdType(TemplateName(CoroHandle), Loc, Args);
+ if (CoroHandleType.isNull())
+ return QualType();
+ if (S.RequireCompleteType(Loc, CoroHandleType,
+ diag::err_coroutine_type_missing_specialization))
+ return QualType();
+
+ return CoroHandleType;
+}
+
static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
StringRef Keyword) {
// 'co_await' and 'co_yield' are not permitted in unevaluated operands.
@@ -160,41 +253,48 @@ static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
return !Diagnosed;
}
-/// Check that this is a context in which a coroutine suspension can appear.
-static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc,
- StringRef Keyword) {
- if (!isValidCoroutineContext(S, Loc, Keyword))
- return nullptr;
-
- assert(isa<FunctionDecl>(S.CurContext) && "not in a function scope");
- auto *FD = cast<FunctionDecl>(S.CurContext);
- auto *ScopeInfo = S.getCurFunction();
- assert(ScopeInfo && "missing function scope for function");
+static ExprResult buildOperatorCoawaitLookupExpr(Sema &SemaRef, Scope *S,
+ SourceLocation Loc) {
+ DeclarationName OpName =
+ SemaRef.Context.DeclarationNames.getCXXOperatorName(OO_Coawait);
+ LookupResult Operators(SemaRef, OpName, SourceLocation(),
+ Sema::LookupOperatorName);
+ SemaRef.LookupName(Operators, S);
+
+ assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
+ const auto &Functions = Operators.asUnresolvedSet();
+ bool IsOverloaded =
+ Functions.size() > 1 ||
+ (Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
+ Expr *CoawaitOp = UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass*/ nullptr, NestedNameSpecifierLoc(),
+ DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, IsOverloaded,
+ Functions.begin(), Functions.end());
+ assert(CoawaitOp);
+ return CoawaitOp;
+}
- // If we don't have a promise variable, build one now.
- if (!ScopeInfo->CoroutinePromise) {
- QualType T = FD->getType()->isDependentType()
- ? S.Context.DependentTy
- : lookupPromiseType(
- S, FD->getType()->castAs<FunctionProtoType>(), Loc);
- if (T.isNull())
- return nullptr;
-
- // Create and default-initialize the promise.
- ScopeInfo->CoroutinePromise =
- VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(),
- &S.PP.getIdentifierTable().get("__promise"), T,
- S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None);
- S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise);
- if (!ScopeInfo->CoroutinePromise->isInvalidDecl())
- S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise);
- }
+/// Build a call to 'operator co_await' if there is a suitable operator for
+/// the given expression.
+static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, SourceLocation Loc,
+ Expr *E,
+ UnresolvedLookupExpr *Lookup) {
+ UnresolvedSet<16> Functions;
+ Functions.append(Lookup->decls_begin(), Lookup->decls_end());
+ return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
+}
- return ScopeInfo;
+static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
+ SourceLocation Loc, Expr *E) {
+ ExprResult R = buildOperatorCoawaitLookupExpr(SemaRef, S, Loc);
+ if (R.isInvalid())
+ return ExprError();
+ return buildOperatorCoawaitCall(SemaRef, Loc, E,
+ cast<UnresolvedLookupExpr>(R.get()));
}
static Expr *buildBuiltinCall(Sema &S, SourceLocation Loc, Builtin::ID Id,
- MutableArrayRef<Expr *> CallArgs) {
+ MultiExprArg CallArgs) {
StringRef Name = S.Context.BuiltinInfo.getName(Id);
LookupResult R(S, &S.Context.Idents.get(Name), Loc, Sema::LookupOrdinaryName);
S.LookupName(R, S.TUScope, /*AllowBuiltinCreation=*/true);
@@ -213,24 +313,42 @@ static Expr *buildBuiltinCall(Sema &S, SourceLocation Loc, Builtin::ID Id,
return Call.get();
}
-/// Build a call to 'operator co_await' if there is a suitable operator for
-/// the given expression.
-static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
- SourceLocation Loc, Expr *E) {
- UnresolvedSet<16> Functions;
- SemaRef.LookupOverloadedOperatorName(OO_Coawait, S, E->getType(), QualType(),
- Functions);
- return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
+static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
+ SourceLocation Loc) {
+ QualType CoroHandleType = lookupCoroutineHandleType(S, PromiseType, Loc);
+ if (CoroHandleType.isNull())
+ return ExprError();
+
+ DeclContext *LookupCtx = S.computeDeclContext(CoroHandleType);
+ LookupResult Found(S, &S.PP.getIdentifierTable().get("from_address"), Loc,
+ Sema::LookupOrdinaryName);
+ if (!S.LookupQualifiedName(Found, LookupCtx)) {
+ S.Diag(Loc, diag::err_coroutine_handle_missing_member)
+ << "from_address";
+ return ExprError();
+ }
+
+ Expr *FramePtr =
+ buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_frame, {});
+
+ CXXScopeSpec SS;
+ ExprResult FromAddr =
+ S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false);
+ if (FromAddr.isInvalid())
+ return ExprError();
+
+ return S.ActOnCallExpr(nullptr, FromAddr.get(), Loc, FramePtr, Loc);
}
struct ReadySuspendResumeResult {
- bool IsInvalid;
+ enum AwaitCallType { ACT_Ready, ACT_Suspend, ACT_Resume };
Expr *Results[3];
+ OpaqueValueExpr *OpaqueValue;
+ bool IsInvalid;
};
static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
- StringRef Name,
- MutableArrayRef<Expr *> Args) {
+ StringRef Name, MultiExprArg Args) {
DeclarationNameInfo NameInfo(&S.PP.getIdentifierTable().get(Name), Loc);
// FIXME: Fix BuildMemberReferenceExpr to take a const CXXScopeSpec&.
@@ -247,47 +365,244 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc,
/// Build calls to await_ready, await_suspend, and await_resume for a co_await
/// expression.
-static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc,
- Expr *E) {
+static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
+ SourceLocation Loc, Expr *E) {
+ OpaqueValueExpr *Operand = new (S.Context)
+ OpaqueValueExpr(Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
+
// Assume invalid until we see otherwise.
- ReadySuspendResumeResult Calls = {true, {}};
+ ReadySuspendResumeResult Calls = {{}, Operand, /*IsInvalid=*/true};
+
+ ExprResult CoroHandleRes = buildCoroutineHandle(S, CoroPromise->getType(), Loc);
+ if (CoroHandleRes.isInvalid())
+ return Calls;
+ Expr *CoroHandle = CoroHandleRes.get();
const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"};
+ MultiExprArg Args[] = {None, CoroHandle, None};
for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) {
- Expr *Operand = new (S.Context) OpaqueValueExpr(
- Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
-
- // FIXME: Pass coroutine handle to await_suspend.
- ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], None);
+ ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], Args[I]);
if (Result.isInvalid())
return Calls;
Calls.Results[I] = Result.get();
}
+ // Assume the calls are valid; all further checking should make them invalid.
Calls.IsInvalid = false;
+
+ using ACT = ReadySuspendResumeResult::AwaitCallType;
+ CallExpr *AwaitReady = cast<CallExpr>(Calls.Results[ACT::ACT_Ready]);
+ if (!AwaitReady->getType()->isDependentType()) {
+ // [expr.await]p3 [...]
+ // — await-ready is the expression e.await_ready(), contextually converted
+ // to bool.
+ ExprResult Conv = S.PerformContextuallyConvertToBool(AwaitReady);
+ if (Conv.isInvalid()) {
+ S.Diag(AwaitReady->getDirectCallee()->getLocStart(),
+ diag::note_await_ready_no_bool_conversion);
+ S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
+ << AwaitReady->getDirectCallee() << E->getSourceRange();
+ Calls.IsInvalid = true;
+ }
+ Calls.Results[ACT::ACT_Ready] = Conv.get();
+ }
+ CallExpr *AwaitSuspend = cast<CallExpr>(Calls.Results[ACT::ACT_Suspend]);
+ if (!AwaitSuspend->getType()->isDependentType()) {
+ // [expr.await]p3 [...]
+ // - await-suspend is the expression e.await_suspend(h), which shall be
+ // a prvalue of type void or bool.
+ QualType RetType = AwaitSuspend->getCallReturnType(S.Context);
+ // non-class prvalues always have cv-unqualified types
+ QualType AdjRetType = RetType.getUnqualifiedType();
+ if (RetType->isReferenceType() ||
+ (AdjRetType != S.Context.BoolTy && AdjRetType != S.Context.VoidTy)) {
+ S.Diag(AwaitSuspend->getCalleeDecl()->getLocation(),
+ diag::err_await_suspend_invalid_return_type)
+ << RetType;
+ S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
+ << AwaitSuspend->getDirectCallee();
+ Calls.IsInvalid = true;
+ }
+ }
+
return Calls;
}
+static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise,
+ SourceLocation Loc, StringRef Name,
+ MultiExprArg Args) {
+
+ // Form a reference to the promise.
+ ExprResult PromiseRef = S.BuildDeclRefExpr(
+ Promise, Promise->getType().getNonReferenceType(), VK_LValue, Loc);
+ if (PromiseRef.isInvalid())
+ return ExprError();
+
+ return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
+}
+
+VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
+ assert(isa<FunctionDecl>(CurContext) && "not in a function scope");
+ auto *FD = cast<FunctionDecl>(CurContext);
+ bool IsThisDependentType = [&] {
+ if (auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD))
+ return MD->isInstance() && MD->getThisType(Context)->isDependentType();
+ else
+ return false;
+ }();
+
+ QualType T = FD->getType()->isDependentType() || IsThisDependentType
+ ? Context.DependentTy
+ : lookupPromiseType(*this, FD, Loc);
+ if (T.isNull())
+ return nullptr;
+
+ auto *VD = VarDecl::Create(Context, FD, FD->getLocation(), FD->getLocation(),
+ &PP.getIdentifierTable().get("__promise"), T,
+ Context.getTrivialTypeSourceInfo(T, Loc), SC_None);
+ CheckVariableDeclarationType(VD);
+ if (VD->isInvalidDecl())
+ return nullptr;
+ ActOnUninitializedDecl(VD);
+ FD->addDecl(VD);
+ assert(!VD->isInvalidDecl());
+ return VD;
+}
+
+/// Check that this is a context in which a coroutine suspension can appear.
+static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc,
+ StringRef Keyword,
+ bool IsImplicit = false) {
+ if (!isValidCoroutineContext(S, Loc, Keyword))
+ return nullptr;
+
+ assert(isa<FunctionDecl>(S.CurContext) && "not in a function scope");
+
+ auto *ScopeInfo = S.getCurFunction();
+ assert(ScopeInfo && "missing function scope for function");
+
+ if (ScopeInfo->FirstCoroutineStmtLoc.isInvalid() && !IsImplicit)
+ ScopeInfo->setFirstCoroutineStmt(Loc, Keyword);
+
+ if (ScopeInfo->CoroutinePromise)
+ return ScopeInfo;
+
+ ScopeInfo->CoroutinePromise = S.buildCoroutinePromise(Loc);
+ if (!ScopeInfo->CoroutinePromise)
+ return nullptr;
+
+ return ScopeInfo;
+}
+
+bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
+ StringRef Keyword) {
+ if (!checkCoroutineContext(*this, KWLoc, Keyword))
+ return false;
+ auto *ScopeInfo = getCurFunction();
+ assert(ScopeInfo->CoroutinePromise);
+
+ // If we have existing coroutine statements then we have already built
+ // the initial and final suspend points.
+ if (!ScopeInfo->NeedsCoroutineSuspends)
+ return true;
+
+ ScopeInfo->setNeedsCoroutineSuspends(false);
+
+ auto *Fn = cast<FunctionDecl>(CurContext);
+ SourceLocation Loc = Fn->getLocation();
+ // Build the initial suspend point
+ auto buildSuspends = [&](StringRef Name) mutable -> StmtResult {
+ ExprResult Suspend =
+ buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, None);
+ if (Suspend.isInvalid())
+ return StmtError();
+ Suspend = buildOperatorCoawaitCall(*this, SC, Loc, Suspend.get());
+ if (Suspend.isInvalid())
+ return StmtError();
+ Suspend = BuildResolvedCoawaitExpr(Loc, Suspend.get(),
+ /*IsImplicit*/ true);
+ Suspend = ActOnFinishFullExpr(Suspend.get());
+ if (Suspend.isInvalid()) {
+ Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required)
+ << ((Name == "initial_suspend") ? 0 : 1);
+ Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
+ return StmtError();
+ }
+ return cast<Stmt>(Suspend.get());
+ };
+
+ StmtResult InitSuspend = buildSuspends("initial_suspend");
+ if (InitSuspend.isInvalid())
+ return true;
+
+ StmtResult FinalSuspend = buildSuspends("final_suspend");
+ if (FinalSuspend.isInvalid())
+ return true;
+
+ ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
+
+ return true;
+}
+
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
- auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await");
- if (!Coroutine) {
+ if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
+
if (E->getType()->isPlaceholderType()) {
ExprResult R = CheckPlaceholderExpr(E);
if (R.isInvalid()) return ExprError();
E = R.get();
}
+ ExprResult Lookup = buildOperatorCoawaitLookupExpr(*this, S, Loc);
+ if (Lookup.isInvalid())
+ return ExprError();
+ return BuildUnresolvedCoawaitExpr(Loc, E,
+ cast<UnresolvedLookupExpr>(Lookup.get()));
+}
+
+ExprResult Sema::BuildUnresolvedCoawaitExpr(SourceLocation Loc, Expr *E,
+ UnresolvedLookupExpr *Lookup) {
+ auto *FSI = checkCoroutineContext(*this, Loc, "co_await");
+ if (!FSI)
+ return ExprError();
+
+ if (E->getType()->isPlaceholderType()) {
+ ExprResult R = CheckPlaceholderExpr(E);
+ if (R.isInvalid())
+ return ExprError();
+ E = R.get();
+ }
+
+ auto *Promise = FSI->CoroutinePromise;
+ if (Promise->getType()->isDependentType()) {
+ Expr *Res =
+ new (Context) DependentCoawaitExpr(Loc, Context.DependentTy, E, Lookup);
+ return Res;
+ }
- ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E);
+ auto *RD = Promise->getType()->getAsCXXRecordDecl();
+ if (lookupMember(*this, "await_transform", RD, Loc)) {
+ ExprResult R = buildPromiseCall(*this, Promise, Loc, "await_transform", E);
+ if (R.isInvalid()) {
+ Diag(Loc,
+ diag::note_coroutine_promise_implicit_await_transform_required_here)
+ << E->getSourceRange();
+ return ExprError();
+ }
+ E = R.get();
+ }
+ ExprResult Awaitable = buildOperatorCoawaitCall(*this, Loc, E, Lookup);
if (Awaitable.isInvalid())
return ExprError();
- return BuildCoawaitExpr(Loc, Awaitable.get());
+ return BuildResolvedCoawaitExpr(Loc, Awaitable.get());
}
-ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
- auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await");
+
+ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *E,
+ bool IsImplicit) {
+ auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await", IsImplicit);
if (!Coroutine)
return ExprError();
@@ -298,8 +613,8 @@ ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
}
if (E->getType()->isDependentType()) {
- Expr *Res = new (Context) CoawaitExpr(Loc, Context.DependentTy, E);
- Coroutine->CoroutineStmts.push_back(Res);
+ Expr *Res = new (Context)
+ CoawaitExpr(Loc, Context.DependentTy, E, IsImplicit);
return Res;
}
@@ -309,42 +624,27 @@ ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
// Build the await_ready, await_suspend, await_resume calls.
- ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
+ ReadySuspendResumeResult RSS =
+ buildCoawaitCalls(*this, Coroutine->CoroutinePromise, Loc, E);
if (RSS.IsInvalid)
return ExprError();
- Expr *Res = new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1],
- RSS.Results[2]);
- Coroutine->CoroutineStmts.push_back(Res);
- return Res;
-}
-
-static ExprResult buildPromiseCall(Sema &S, FunctionScopeInfo *Coroutine,
- SourceLocation Loc, StringRef Name,
- MutableArrayRef<Expr *> Args) {
- assert(Coroutine->CoroutinePromise && "no promise for coroutine");
-
- // Form a reference to the promise.
- auto *Promise = Coroutine->CoroutinePromise;
- ExprResult PromiseRef = S.BuildDeclRefExpr(
- Promise, Promise->getType().getNonReferenceType(), VK_LValue, Loc);
- if (PromiseRef.isInvalid())
- return ExprError();
+ Expr *Res =
+ new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1],
+ RSS.Results[2], RSS.OpaqueValue, IsImplicit);
- // Call 'yield_value', passing in E.
- return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
+ return Res;
}
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
- auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield");
- if (!Coroutine) {
+ if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
// Build yield_value call.
- ExprResult Awaitable =
- buildPromiseCall(*this, Coroutine, Loc, "yield_value", E);
+ ExprResult Awaitable = buildPromiseCall(
+ *this, getCurFunction()->CoroutinePromise, Loc, "yield_value", E);
if (Awaitable.isInvalid())
return ExprError();
@@ -368,7 +668,6 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
if (E->getType()->isDependentType()) {
Expr *Res = new (Context) CoyieldExpr(Loc, Context.DependentTy, E);
- Coroutine->CoroutineStmts.push_back(Res);
return Res;
}
@@ -378,28 +677,30 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
// Build the await_ready, await_suspend, await_resume calls.
- ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
+ ReadySuspendResumeResult RSS =
+ buildCoawaitCalls(*this, Coroutine->CoroutinePromise, Loc, E);
if (RSS.IsInvalid)
return ExprError();
- Expr *Res = new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
- RSS.Results[2]);
- Coroutine->CoroutineStmts.push_back(Res);
+ Expr *Res =
+ new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
+ RSS.Results[2], RSS.OpaqueValue);
+
return Res;
}
-StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) {
- auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return");
- if (!Coroutine) {
+StmtResult Sema::ActOnCoreturnStmt(Scope *S, SourceLocation Loc, Expr *E) {
+ if (!ActOnCoroutineBodyStart(S, Loc, "co_return")) {
CorrectDelayedTyposInExpr(E);
return StmtError();
}
return BuildCoreturnStmt(Loc, E);
}
-StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) {
- auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return");
- if (!Coroutine)
+StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E,
+ bool IsImplicit) {
+ auto *FSI = checkCoroutineContext(*this, Loc, "co_return", IsImplicit);
+ if (!FSI)
return StmtError();
if (E && E->getType()->isPlaceholderType() &&
@@ -412,49 +713,52 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) {
// FIXME: If the operand is a reference to a variable that's about to go out
// of scope, we should treat the operand as an xvalue for this overload
// resolution.
+ VarDecl *Promise = FSI->CoroutinePromise;
ExprResult PC;
if (E && (isa<InitListExpr>(E) || !E->getType()->isVoidType())) {
- PC = buildPromiseCall(*this, Coroutine, Loc, "return_value", E);
+ PC = buildPromiseCall(*this, Promise, Loc, "return_value", E);
} else {
E = MakeFullDiscardedValueExpr(E).get();
- PC = buildPromiseCall(*this, Coroutine, Loc, "return_void", None);
+ PC = buildPromiseCall(*this, Promise, Loc, "return_void", None);
}
if (PC.isInvalid())
return StmtError();
Expr *PCE = ActOnFinishFullExpr(PC.get()).get();
- Stmt *Res = new (Context) CoreturnStmt(Loc, E, PCE);
- Coroutine->CoroutineStmts.push_back(Res);
+ Stmt *Res = new (Context) CoreturnStmt(Loc, E, PCE, IsImplicit);
return Res;
}
-static ExprResult buildStdCurrentExceptionCall(Sema &S, SourceLocation Loc) {
+/// Look up the std::nothrow object.
+static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) {
NamespaceDecl *Std = S.getStdNamespace();
- if (!Std) {
- S.Diag(Loc, diag::err_implied_std_current_exception_not_found);
- return ExprError();
- }
- LookupResult Result(S, &S.PP.getIdentifierTable().get("current_exception"),
- Loc, Sema::LookupOrdinaryName);
+ assert(Std && "Should already be diagnosed");
+
+ LookupResult Result(S, &S.PP.getIdentifierTable().get("nothrow"), Loc,
+ Sema::LookupOrdinaryName);
if (!S.LookupQualifiedName(Result, Std)) {
- S.Diag(Loc, diag::err_implied_std_current_exception_not_found);
- return ExprError();
+ // FIXME: <experimental/coroutine> should have been included already.
+ // If we require it to include <new> then this diagnostic is no longer
+ // needed.
+ S.Diag(Loc, diag::err_implicit_coroutine_std_nothrow_type_not_found);
+ return nullptr;
}
- // FIXME The STL is free to provide more than one overload.
- FunctionDecl *FD = Result.getAsSingle<FunctionDecl>();
- if (!FD) {
- S.Diag(Loc, diag::err_malformed_std_current_exception);
- return ExprError();
- }
- ExprResult Res = S.BuildDeclRefExpr(FD, FD->getType(), VK_LValue, Loc);
- Res = S.ActOnCallExpr(/*Scope*/ nullptr, Res.get(), Loc, None, Loc);
- if (Res.isInvalid()) {
- S.Diag(Loc, diag::err_malformed_std_current_exception);
- return ExprError();
+ auto *VD = Result.getAsSingle<VarDecl>();
+ if (!VD) {
+ Result.suppressDiagnostics();
+ // We found something weird. Complain about the first thing we found.
+ NamedDecl *Found = *Result.begin();
+ S.Diag(Found->getLocation(), diag::err_malformed_std_nothrow);
+ return nullptr;
}
- return Res;
+
+ ExprResult DR = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, Loc);
+ if (DR.isInvalid())
+ return nullptr;
+
+ return DR.get();
}
// Find an appropriate delete for the promise.
@@ -482,36 +786,224 @@ static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc,
return OperatorDelete;
}
-// Builds allocation and deallocation for the coroutine. Returns false on
-// failure.
-static bool buildAllocationAndDeallocation(Sema &S, SourceLocation Loc,
- FunctionScopeInfo *Fn,
- Expr *&Allocation,
- Stmt *&Deallocation) {
- TypeSourceInfo *TInfo = Fn->CoroutinePromise->getTypeSourceInfo();
- QualType PromiseType = TInfo->getType();
- if (PromiseType->isDependentType())
+
+void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
+ FunctionScopeInfo *Fn = getCurFunction();
+ assert(Fn && Fn->isCoroutine() && "not a coroutine");
+ if (!Body) {
+ assert(FD->isInvalidDecl() &&
+ "a null body is only allowed for invalid declarations");
+ return;
+ }
+ // We have a function that uses coroutine keywords, but we failed to build
+ // the promise type.
+ if (!Fn->CoroutinePromise)
+ return FD->setInvalidDecl();
+
+ if (isa<CoroutineBodyStmt>(Body)) {
+ // Nothing todo. the body is already a transformed coroutine body statement.
+ return;
+ }
+
+ // Coroutines [stmt.return]p1:
+ // A return statement shall not appear in a coroutine.
+ if (Fn->FirstReturnLoc.isValid()) {
+ assert(Fn->FirstCoroutineStmtLoc.isValid() &&
+ "first coroutine location not set");
+ Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine);
+ Diag(Fn->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn->getFirstCoroutineStmtKeyword();
+ }
+ CoroutineStmtBuilder Builder(*this, *FD, *Fn, Body);
+ if (Builder.isInvalid() || !Builder.buildStatements())
+ return FD->setInvalidDecl();
+
+ // Build body for the coroutine wrapper statement.
+ Body = CoroutineBodyStmt::Create(Context, Builder);
+}
+
+CoroutineStmtBuilder::CoroutineStmtBuilder(Sema &S, FunctionDecl &FD,
+ sema::FunctionScopeInfo &Fn,
+ Stmt *Body)
+ : S(S), FD(FD), Fn(Fn), Loc(FD.getLocation()),
+ IsPromiseDependentType(
+ !Fn.CoroutinePromise ||
+ Fn.CoroutinePromise->getType()->isDependentType()) {
+ this->Body = Body;
+ if (!IsPromiseDependentType) {
+ PromiseRecordDecl = Fn.CoroutinePromise->getType()->getAsCXXRecordDecl();
+ assert(PromiseRecordDecl && "Type should have already been checked");
+ }
+ this->IsValid = makePromiseStmt() && makeInitialAndFinalSuspend();
+}
+
+bool CoroutineStmtBuilder::buildStatements() {
+ assert(this->IsValid && "coroutine already invalid");
+ this->IsValid = makeReturnObject() && makeParamMoves();
+ if (this->IsValid && !IsPromiseDependentType)
+ buildDependentStatements();
+ return this->IsValid;
+}
+
+bool CoroutineStmtBuilder::buildDependentStatements() {
+ assert(this->IsValid && "coroutine already invalid");
+ assert(!this->IsPromiseDependentType &&
+ "coroutine cannot have a dependent promise type");
+ this->IsValid = makeOnException() && makeOnFallthrough() &&
+ makeGroDeclAndReturnStmt() && makeReturnOnAllocFailure() &&
+ makeNewAndDeleteExpr();
+ return this->IsValid;
+}
+
+bool CoroutineStmtBuilder::buildParameterMoves() {
+ assert(this->IsValid && "coroutine already invalid");
+ assert(this->ParamMoves.empty() && "param moves already built");
+ return this->IsValid = makeParamMoves();
+}
+
+bool CoroutineStmtBuilder::makePromiseStmt() {
+ // Form a declaration statement for the promise declaration, so that AST
+ // visitors can more easily find it.
+ StmtResult PromiseStmt =
+ S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(Fn.CoroutinePromise), Loc, Loc);
+ if (PromiseStmt.isInvalid())
+ return false;
+
+ this->Promise = PromiseStmt.get();
+ return true;
+}
+
+bool CoroutineStmtBuilder::makeInitialAndFinalSuspend() {
+ if (Fn.hasInvalidCoroutineSuspends())
+ return false;
+ this->InitialSuspend = cast<Expr>(Fn.CoroutineSuspends.first);
+ this->FinalSuspend = cast<Expr>(Fn.CoroutineSuspends.second);
+ return true;
+}
+
+static bool diagReturnOnAllocFailure(Sema &S, Expr *E,
+ CXXRecordDecl *PromiseRecordDecl,
+ FunctionScopeInfo &Fn) {
+ auto Loc = E->getExprLoc();
+ if (auto *DeclRef = dyn_cast_or_null<DeclRefExpr>(E)) {
+ auto *Decl = DeclRef->getDecl();
+ if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(Decl)) {
+ if (Method->isStatic())
+ return true;
+ else
+ Loc = Decl->getLocation();
+ }
+ }
+
+ S.Diag(
+ Loc,
+ diag::err_coroutine_promise_get_return_object_on_allocation_failure)
+ << PromiseRecordDecl;
+ S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
+ return false;
+}
+
+bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
+
+ // [dcl.fct.def.coroutine]/8
+ // The unqualified-id get_return_object_on_allocation_failure is looked up in
+ // the scope of class P by class member access lookup (3.4.5). ...
+ // If an allocation function returns nullptr, ... the coroutine return value
+ // is obtained by a call to ... get_return_object_on_allocation_failure().
+
+ DeclarationName DN =
+ S.PP.getIdentifierInfo("get_return_object_on_allocation_failure");
+ LookupResult Found(S, DN, Loc, Sema::LookupMemberName);
+ if (!S.LookupQualifiedName(Found, PromiseRecordDecl))
return true;
+ CXXScopeSpec SS;
+ ExprResult DeclNameExpr =
+ S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false);
+ if (DeclNameExpr.isInvalid())
+ return false;
+
+ if (!diagReturnOnAllocFailure(S, DeclNameExpr.get(), PromiseRecordDecl, Fn))
+ return false;
+
+ ExprResult ReturnObjectOnAllocationFailure =
+ S.ActOnCallExpr(nullptr, DeclNameExpr.get(), Loc, {}, Loc);
+ if (ReturnObjectOnAllocationFailure.isInvalid())
+ return false;
+
+ StmtResult ReturnStmt =
+ S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get());
+ if (ReturnStmt.isInvalid()) {
+ S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here)
+ << DN;
+ S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
+ return false;
+ }
+
+ this->ReturnStmtOnAllocFailure = ReturnStmt.get();
+ return true;
+}
+
+bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
+ // Form and check allocation and deallocation calls.
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
+ QualType PromiseType = Fn.CoroutinePromise->getType();
+
if (S.RequireCompleteType(Loc, PromiseType, diag::err_incomplete_type))
return false;
- // FIXME: Add support for get_return_object_on_allocation failure.
+ const bool RequiresNoThrowAlloc = ReturnStmtOnAllocFailure != nullptr;
+
// FIXME: Add support for stateful allocators.
FunctionDecl *OperatorNew = nullptr;
FunctionDecl *OperatorDelete = nullptr;
FunctionDecl *UnusedResult = nullptr;
bool PassAlignment = false;
+ SmallVector<Expr *, 1> PlacementArgs;
S.FindAllocationFunctions(Loc, SourceRange(),
/*UseGlobal*/ false, PromiseType,
- /*isArray*/ false, PassAlignment,
- /*PlacementArgs*/ None, OperatorNew, UnusedResult);
+ /*isArray*/ false, PassAlignment, PlacementArgs,
+ OperatorNew, UnusedResult);
+
+ bool IsGlobalOverload =
+ OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext());
+ // If we didn't find a class-local new declaration and non-throwing new
+ // was is required then we need to lookup the non-throwing global operator
+ // instead.
+ if (RequiresNoThrowAlloc && (!OperatorNew || IsGlobalOverload)) {
+ auto *StdNoThrow = buildStdNoThrowDeclRef(S, Loc);
+ if (!StdNoThrow)
+ return false;
+ PlacementArgs = {StdNoThrow};
+ OperatorNew = nullptr;
+ S.FindAllocationFunctions(Loc, SourceRange(),
+ /*UseGlobal*/ true, PromiseType,
+ /*isArray*/ false, PassAlignment, PlacementArgs,
+ OperatorNew, UnusedResult);
+ }
- OperatorDelete = findDeleteForPromise(S, Loc, PromiseType);
+ assert(OperatorNew && "expected definition of operator new to be found");
+
+ if (RequiresNoThrowAlloc) {
+ const auto *FT = OperatorNew->getType()->getAs<FunctionProtoType>();
+ if (!FT->isNothrow(S.Context, /*ResultIfDependent*/ false)) {
+ S.Diag(OperatorNew->getLocation(),
+ diag::err_coroutine_promise_new_requires_nothrow)
+ << OperatorNew;
+ S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required)
+ << OperatorNew;
+ return false;
+ }
+ }
- if (!OperatorDelete || !OperatorNew)
+ if ((OperatorDelete = findDeleteForPromise(S, Loc, PromiseType)) == nullptr)
return false;
Expr *FramePtr =
@@ -527,13 +1019,16 @@ static bool buildAllocationAndDeallocation(Sema &S, SourceLocation Loc,
if (NewRef.isInvalid())
return false;
+ SmallVector<Expr *, 2> NewArgs(1, FrameSize);
+ for (auto Arg : PlacementArgs)
+ NewArgs.push_back(Arg);
+
ExprResult NewExpr =
- S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, FrameSize, Loc);
+ S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
+ NewExpr = S.ActOnFinishFullExpr(NewExpr.get());
if (NewExpr.isInvalid())
return false;
- Allocation = NewExpr.get();
-
// Make delete call.
QualType OpDeleteQualType = OperatorDelete->getType();
@@ -556,141 +1051,275 @@ static bool buildAllocationAndDeallocation(Sema &S, SourceLocation Loc,
ExprResult DeleteExpr =
S.ActOnCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc);
+ DeleteExpr = S.ActOnFinishFullExpr(DeleteExpr.get());
if (DeleteExpr.isInvalid())
return false;
- Deallocation = DeleteExpr.get();
+ this->Allocate = NewExpr.get();
+ this->Deallocate = DeleteExpr.get();
return true;
}
-void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
- FunctionScopeInfo *Fn = getCurFunction();
- assert(Fn && !Fn->CoroutineStmts.empty() && "not a coroutine");
+bool CoroutineStmtBuilder::makeOnFallthrough() {
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
- // Coroutines [stmt.return]p1:
- // A return statement shall not appear in a coroutine.
- if (Fn->FirstReturnLoc.isValid()) {
- Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine);
- auto *First = Fn->CoroutineStmts[0];
- Diag(First->getLocStart(), diag::note_declared_coroutine_here)
- << (isa<CoawaitExpr>(First) ? 0 :
- isa<CoyieldExpr>(First) ? 1 : 2);
- }
-
- SourceLocation Loc = FD->getLocation();
+ // [dcl.fct.def.coroutine]/4
+ // The unqualified-ids 'return_void' and 'return_value' are looked up in
+ // the scope of class P. If both are found, the program is ill-formed.
+ bool HasRVoid, HasRValue;
+ LookupResult LRVoid =
+ lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid);
+ LookupResult LRValue =
+ lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue);
- // Form a declaration statement for the promise declaration, so that AST
- // visitors can more easily find it.
- StmtResult PromiseStmt =
- ActOnDeclStmt(ConvertDeclToDeclGroup(Fn->CoroutinePromise), Loc, Loc);
- if (PromiseStmt.isInvalid())
- return FD->setInvalidDecl();
+ StmtResult Fallthrough;
+ if (HasRVoid && HasRValue) {
+ // FIXME Improve this diagnostic
+ S.Diag(FD.getLocation(),
+ diag::err_coroutine_promise_incompatible_return_functions)
+ << PromiseRecordDecl;
+ S.Diag(LRVoid.getRepresentativeDecl()->getLocation(),
+ diag::note_member_first_declared_here)
+ << LRVoid.getLookupName();
+ S.Diag(LRValue.getRepresentativeDecl()->getLocation(),
+ diag::note_member_first_declared_here)
+ << LRValue.getLookupName();
+ return false;
+ } else if (!HasRVoid && !HasRValue) {
+ // FIXME: The PDTS currently specifies this case as UB, not ill-formed.
+ // However we still diagnose this as an error since until the PDTS is fixed.
+ S.Diag(FD.getLocation(),
+ diag::err_coroutine_promise_requires_return_function)
+ << PromiseRecordDecl;
+ S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here)
+ << PromiseRecordDecl;
+ return false;
+ } else if (HasRVoid) {
+ // If the unqualified-id return_void is found, flowing off the end of a
+ // coroutine is equivalent to a co_return with no operand. Otherwise,
+ // flowing off the end of a coroutine results in undefined behavior.
+ Fallthrough = S.BuildCoreturnStmt(FD.getLocation(), nullptr,
+ /*IsImplicit*/false);
+ Fallthrough = S.ActOnFinishFullStmt(Fallthrough.get());
+ if (Fallthrough.isInvalid())
+ return false;
+ }
- // Form and check implicit 'co_await p.initial_suspend();' statement.
- ExprResult InitialSuspend =
- buildPromiseCall(*this, Fn, Loc, "initial_suspend", None);
- // FIXME: Support operator co_await here.
- if (!InitialSuspend.isInvalid())
- InitialSuspend = BuildCoawaitExpr(Loc, InitialSuspend.get());
- InitialSuspend = ActOnFinishFullExpr(InitialSuspend.get());
- if (InitialSuspend.isInvalid())
- return FD->setInvalidDecl();
+ this->OnFallthrough = Fallthrough.get();
+ return true;
+}
- // Form and check implicit 'co_await p.final_suspend();' statement.
- ExprResult FinalSuspend =
- buildPromiseCall(*this, Fn, Loc, "final_suspend", None);
- // FIXME: Support operator co_await here.
- if (!FinalSuspend.isInvalid())
- FinalSuspend = BuildCoawaitExpr(Loc, FinalSuspend.get());
- FinalSuspend = ActOnFinishFullExpr(FinalSuspend.get());
- if (FinalSuspend.isInvalid())
- return FD->setInvalidDecl();
+bool CoroutineStmtBuilder::makeOnException() {
+ // Try to form 'p.unhandled_exception();'
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
+
+ const bool RequireUnhandledException = S.getLangOpts().CXXExceptions;
+
+ if (!lookupMember(S, "unhandled_exception", PromiseRecordDecl, Loc)) {
+ auto DiagID =
+ RequireUnhandledException
+ ? diag::err_coroutine_promise_unhandled_exception_required
+ : diag::
+ warn_coroutine_promise_unhandled_exception_required_with_exceptions;
+ S.Diag(Loc, DiagID) << PromiseRecordDecl;
+ S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here)
+ << PromiseRecordDecl;
+ return !RequireUnhandledException;
+ }
- // Form and check allocation and deallocation calls.
- Expr *Allocation = nullptr;
- Stmt *Deallocation = nullptr;
- if (!buildAllocationAndDeallocation(*this, Loc, Fn, Allocation, Deallocation))
- return FD->setInvalidDecl();
+ // If exceptions are disabled, don't try to build OnException.
+ if (!S.getLangOpts().CXXExceptions)
+ return true;
- // control flowing off the end of the coroutine.
- // Also try to form 'p.set_exception(std::current_exception());' to handle
- // uncaught exceptions.
- ExprResult SetException;
- StmtResult Fallthrough;
- if (Fn->CoroutinePromise &&
- !Fn->CoroutinePromise->getType()->isDependentType()) {
- CXXRecordDecl *RD = Fn->CoroutinePromise->getType()->getAsCXXRecordDecl();
- assert(RD && "Type should have already been checked");
- // [dcl.fct.def.coroutine]/4
- // The unqualified-ids 'return_void' and 'return_value' are looked up in
- // the scope of class P. If both are found, the program is ill-formed.
- DeclarationName RVoidDN = PP.getIdentifierInfo("return_void");
- LookupResult RVoidResult(*this, RVoidDN, Loc, Sema::LookupMemberName);
- const bool HasRVoid = LookupQualifiedName(RVoidResult, RD);
-
- DeclarationName RValueDN = PP.getIdentifierInfo("return_value");
- LookupResult RValueResult(*this, RValueDN, Loc, Sema::LookupMemberName);
- const bool HasRValue = LookupQualifiedName(RValueResult, RD);
-
- if (HasRVoid && HasRValue) {
- // FIXME Improve this diagnostic
- Diag(FD->getLocation(), diag::err_coroutine_promise_return_ill_formed)
- << RD;
- return FD->setInvalidDecl();
- } else if (HasRVoid) {
- // If the unqualified-id return_void is found, flowing off the end of a
- // coroutine is equivalent to a co_return with no operand. Otherwise,
- // flowing off the end of a coroutine results in undefined behavior.
- Fallthrough = BuildCoreturnStmt(FD->getLocation(), nullptr);
- Fallthrough = ActOnFinishFullStmt(Fallthrough.get());
- if (Fallthrough.isInvalid())
- return FD->setInvalidDecl();
- }
+ ExprResult UnhandledException = buildPromiseCall(S, Fn.CoroutinePromise, Loc,
+ "unhandled_exception", None);
+ UnhandledException = S.ActOnFinishFullExpr(UnhandledException.get(), Loc);
+ if (UnhandledException.isInvalid())
+ return false;
- // [dcl.fct.def.coroutine]/3
- // The unqualified-id set_exception is found in the scope of P by class
- // member access lookup (3.4.5).
- DeclarationName SetExDN = PP.getIdentifierInfo("set_exception");
- LookupResult SetExResult(*this, SetExDN, Loc, Sema::LookupMemberName);
- if (LookupQualifiedName(SetExResult, RD)) {
- // Form the call 'p.set_exception(std::current_exception())'
- SetException = buildStdCurrentExceptionCall(*this, Loc);
- if (SetException.isInvalid())
- return FD->setInvalidDecl();
- Expr *E = SetException.get();
- SetException = buildPromiseCall(*this, Fn, Loc, "set_exception", E);
- SetException = ActOnFinishFullExpr(SetException.get(), Loc);
- if (SetException.isInvalid())
- return FD->setInvalidDecl();
- }
+ // Since the body of the coroutine will be wrapped in try-catch, it will
+ // be incompatible with SEH __try if present in a function.
+ if (!S.getLangOpts().Borland && Fn.FirstSEHTryLoc.isValid()) {
+ S.Diag(Fn.FirstSEHTryLoc, diag::err_seh_in_a_coroutine_with_cxx_exceptions);
+ S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
+ return false;
}
+ this->OnException = UnhandledException.get();
+ return true;
+}
+
+bool CoroutineStmtBuilder::makeReturnObject() {
// Build implicit 'p.get_return_object()' expression and form initialization
// of return type from it.
ExprResult ReturnObject =
- buildPromiseCall(*this, Fn, Loc, "get_return_object", None);
+ buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None);
if (ReturnObject.isInvalid())
- return FD->setInvalidDecl();
- QualType RetType = FD->getReturnType();
- if (!RetType->isDependentType()) {
+ return false;
+
+ this->ReturnValue = ReturnObject.get();
+ return true;
+}
+
+static void noteMemberDeclaredHere(Sema &S, Expr *E, FunctionScopeInfo &Fn) {
+ if (auto *MbrRef = dyn_cast<CXXMemberCallExpr>(E)) {
+ auto *MethodDecl = MbrRef->getMethodDecl();
+ S.Diag(MethodDecl->getLocation(), diag::note_member_declared_here)
+ << MethodDecl;
+ }
+ S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
+ << Fn.getFirstCoroutineStmtKeyword();
+}
+
+bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() {
+ assert(!IsPromiseDependentType &&
+ "cannot make statement while the promise type is dependent");
+ assert(this->ReturnValue && "ReturnValue must be already formed");
+
+ QualType const GroType = this->ReturnValue->getType();
+ assert(!GroType->isDependentType() &&
+ "get_return_object type must no longer be dependent");
+
+ QualType const FnRetType = FD.getReturnType();
+ assert(!FnRetType->isDependentType() &&
+ "get_return_object type must no longer be dependent");
+
+ if (FnRetType->isVoidType()) {
+ ExprResult Res = S.ActOnFinishFullExpr(this->ReturnValue, Loc);
+ if (Res.isInvalid())
+ return false;
+
+ this->ResultDecl = Res.get();
+ return true;
+ }
+
+ if (GroType->isVoidType()) {
+ // Trigger a nice error message.
InitializedEntity Entity =
- InitializedEntity::InitializeResult(Loc, RetType, false);
- ReturnObject = PerformMoveOrCopyInitialization(Entity, nullptr, RetType,
- ReturnObject.get());
- if (ReturnObject.isInvalid())
- return FD->setInvalidDecl();
+ InitializedEntity::InitializeResult(Loc, FnRetType, false);
+ S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue);
+ noteMemberDeclaredHere(S, ReturnValue, Fn);
+ return false;
}
- ReturnObject = ActOnFinishFullExpr(ReturnObject.get(), Loc);
- if (ReturnObject.isInvalid())
- return FD->setInvalidDecl();
- // FIXME: Perform move-initialization of parameters into frame-local copies.
- SmallVector<Expr*, 16> ParamMoves;
+ auto *GroDecl = VarDecl::Create(
+ S.Context, &FD, FD.getLocation(), FD.getLocation(),
+ &S.PP.getIdentifierTable().get("__coro_gro"), GroType,
+ S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None);
- // Build body for the coroutine wrapper statement.
- Body = new (Context) CoroutineBodyStmt(
- Body, PromiseStmt.get(), InitialSuspend.get(), FinalSuspend.get(),
- SetException.get(), Fallthrough.get(), Allocation, Deallocation,
- ReturnObject.get(), ParamMoves);
+ S.CheckVariableDeclarationType(GroDecl);
+ if (GroDecl->isInvalidDecl())
+ return false;
+
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl);
+ ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType,
+ this->ReturnValue);
+ if (Res.isInvalid())
+ return false;
+
+ Res = S.ActOnFinishFullExpr(Res.get());
+ if (Res.isInvalid())
+ return false;
+
+ if (GroType == FnRetType) {
+ GroDecl->setNRVOVariable(true);
+ }
+
+ S.AddInitializerToDecl(GroDecl, Res.get(),
+ /*DirectInit=*/false);
+
+ S.FinalizeDeclaration(GroDecl);
+
+ // Form a declaration statement for the return declaration, so that AST
+ // visitors can more easily find it.
+ StmtResult GroDeclStmt =
+ S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc);
+ if (GroDeclStmt.isInvalid())
+ return false;
+
+ this->ResultDecl = GroDeclStmt.get();
+
+ ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc);
+ if (declRef.isInvalid())
+ return false;
+
+ StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get());
+ if (ReturnStmt.isInvalid()) {
+ noteMemberDeclaredHere(S, ReturnValue, Fn);
+ return false;
+ }
+
+ this->ReturnStmt = ReturnStmt.get();
+ return true;
+}
+
+// Create a static_cast\<T&&>(expr).
+static Expr *castForMoving(Sema &S, Expr *E, QualType T = QualType()) {
+ if (T.isNull())
+ T = E->getType();
+ QualType TargetType = S.BuildReferenceType(
+ T, /*SpelledAsLValue*/ false, SourceLocation(), DeclarationName());
+ SourceLocation ExprLoc = E->getLocStart();
+ TypeSourceInfo *TargetLoc =
+ S.Context.getTrivialTypeSourceInfo(TargetType, ExprLoc);
+
+ return S
+ .BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E,
+ SourceRange(ExprLoc, ExprLoc), E->getSourceRange())
+ .get();
+}
+
+
+/// \brief Build a variable declaration for move parameter.
+static VarDecl *buildVarDecl(Sema &S, SourceLocation Loc, QualType Type,
+ IdentifierInfo *II) {
+ TypeSourceInfo *TInfo = S.Context.getTrivialTypeSourceInfo(Type, Loc);
+ VarDecl *Decl =
+ VarDecl::Create(S.Context, S.CurContext, Loc, Loc, II, Type, TInfo, SC_None);
+ Decl->setImplicit();
+ return Decl;
+}
+
+bool CoroutineStmtBuilder::makeParamMoves() {
+ for (auto *paramDecl : FD.parameters()) {
+ auto Ty = paramDecl->getType();
+ if (Ty->isDependentType())
+ continue;
+
+ // No need to copy scalars, llvm will take care of them.
+ if (Ty->getAsCXXRecordDecl()) {
+ ExprResult ParamRef =
+ S.BuildDeclRefExpr(paramDecl, paramDecl->getType(),
+ ExprValueKind::VK_LValue, Loc); // FIXME: scope?
+ if (ParamRef.isInvalid())
+ return false;
+
+ Expr *RCast = castForMoving(S, ParamRef.get());
+
+ auto D = buildVarDecl(S, Loc, Ty, paramDecl->getIdentifier());
+ S.AddInitializerToDecl(D, RCast, /*DirectInit=*/true);
+
+ // Convert decl to a statement.
+ StmtResult Stmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(D), Loc, Loc);
+ if (Stmt.isInvalid())
+ return false;
+
+ ParamMovesVector.push_back(Stmt.get());
+ }
+ }
+
+ // Convert to ArrayRef in CtorArgs structure that builder inherits from.
+ ParamMoves = ParamMovesVector;
+ return true;
+}
+
+StmtResult Sema::BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) {
+ CoroutineBodyStmt *Res = CoroutineBodyStmt::Create(Context, Args);
+ if (!Res)
+ return StmtError();
+ return Res;
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp
index adcf2ee..692a77e 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp
@@ -64,29 +64,53 @@ namespace {
class TypeNameValidatorCCC : public CorrectionCandidateCallback {
public:
- TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false,
- bool AllowTemplates=false)
- : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass),
- AllowClassTemplates(AllowTemplates) {
- WantExpressionKeywords = false;
- WantCXXNamedCasts = false;
- WantRemainingKeywords = false;
+ TypeNameValidatorCCC(bool AllowInvalid, bool WantClass = false,
+ bool AllowTemplates = false,
+ bool AllowNonTemplates = true)
+ : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass),
+ AllowTemplates(AllowTemplates), AllowNonTemplates(AllowNonTemplates) {
+ WantExpressionKeywords = false;
+ WantCXXNamedCasts = false;
+ WantRemainingKeywords = false;
}
bool ValidateCandidate(const TypoCorrection &candidate) override {
if (NamedDecl *ND = candidate.getCorrectionDecl()) {
+ if (!AllowInvalidDecl && ND->isInvalidDecl())
+ return false;
+
+ if (getAsTypeTemplateDecl(ND))
+ return AllowTemplates;
+
bool IsType = isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
- bool AllowedTemplate = AllowClassTemplates && isa<ClassTemplateDecl>(ND);
- return (IsType || AllowedTemplate) &&
- (AllowInvalidDecl || !ND->isInvalidDecl());
+ if (!IsType)
+ return false;
+
+ if (AllowNonTemplates)
+ return true;
+
+ // An injected-class-name of a class template (specialization) is valid
+ // as a template or as a non-template.
+ if (AllowTemplates) {
+ auto *RD = dyn_cast<CXXRecordDecl>(ND);
+ if (!RD || !RD->isInjectedClassName())
+ return false;
+ RD = cast<CXXRecordDecl>(RD->getDeclContext());
+ return RD->getDescribedClassTemplate() ||
+ isa<ClassTemplateSpecializationDecl>(RD);
+ }
+
+ return false;
}
+
return !WantClassName && candidate.isKeyword();
}
private:
bool AllowInvalidDecl;
bool WantClassName;
- bool AllowClassTemplates;
+ bool AllowTemplates;
+ bool AllowNonTemplates;
};
} // end anonymous namespace
@@ -252,7 +276,13 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
ParsedType ObjectTypePtr,
bool IsCtorOrDtorName,
bool WantNontrivialTypeSourceInfo,
+ bool IsClassTemplateDeductionContext,
IdentifierInfo **CorrectedII) {
+ // FIXME: Consider allowing this outside C++1z mode as an extension.
+ bool AllowDeducedTemplate = IsClassTemplateDeductionContext &&
+ getLangOpts().CPlusPlus1z && !IsCtorOrDtorName &&
+ !isClassName && !HasTrailingDot;
+
// Determine where we will perform name lookup.
DeclContext *LookupCtx = nullptr;
if (ObjectTypePtr) {
@@ -334,10 +364,11 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (CorrectedII) {
- TypoCorrection Correction = CorrectTypo(
- Result.getLookupNameInfo(), Kind, S, SS,
- llvm::make_unique<TypeNameValidatorCCC>(true, isClassName),
- CTK_ErrorRecovery);
+ TypoCorrection Correction =
+ CorrectTypo(Result.getLookupNameInfo(), Kind, S, SS,
+ llvm::make_unique<TypeNameValidatorCCC>(
+ true, isClassName, AllowDeducedTemplate),
+ CTK_ErrorRecovery);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
TemplateTy Template;
bool MemberOfUnknownSpecialization;
@@ -359,7 +390,8 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr,
isClassName, HasTrailingDot, ObjectTypePtr,
IsCtorOrDtorName,
- WantNontrivialTypeSourceInfo);
+ WantNontrivialTypeSourceInfo,
+ IsClassTemplateDeductionContext);
if (Ty) {
diagnoseTypo(Correction,
PDiag(diag::err_unknown_type_or_class_name_suggest)
@@ -372,6 +404,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
}
}
// If typo correction failed or was not performed, fall through
+ LLVM_FALLTHROUGH;
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
Result.suppressDiagnostics();
@@ -391,7 +424,8 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
// Look to see if we have a type anywhere in the list of results.
for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end();
Res != ResEnd; ++Res) {
- if (isa<TypeDecl>(*Res) || isa<ObjCInterfaceDecl>(*Res)) {
+ if (isa<TypeDecl>(*Res) || isa<ObjCInterfaceDecl>(*Res) ||
+ (AllowDeducedTemplate && getAsTypeTemplateDecl(*Res))) {
if (!IIDecl ||
(*Res)->getLocation().getRawEncoding() <
IIDecl->getLocation().getRawEncoding())
@@ -425,33 +459,29 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
QualType T;
if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
+ // C++ [class.qual]p2: A lookup that would find the injected-class-name
+ // instead names the constructors of the class, except when naming a class.
+ // This is ill-formed when we're not actually forming a ctor or dtor name.
+ auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
+ auto *FoundRD = dyn_cast<CXXRecordDecl>(TD);
+ if (!isClassName && !IsCtorOrDtorName && LookupRD && FoundRD &&
+ FoundRD->isInjectedClassName() &&
+ declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent())))
+ Diag(NameLoc, diag::err_out_of_line_qualified_id_type_names_constructor)
+ << &II << /*Type*/1;
+
DiagnoseUseOfDecl(IIDecl, NameLoc);
T = Context.getTypeDeclType(TD);
MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
-
- // NOTE: avoid constructing an ElaboratedType(Loc) if this is a
- // constructor or destructor name (in such a case, the scope specifier
- // will be attached to the enclosing Expr or Decl node).
- if (SS && SS->isNotEmpty() && !IsCtorOrDtorName) {
- if (WantNontrivialTypeSourceInfo) {
- // Construct a type with type-source information.
- TypeLocBuilder Builder;
- Builder.pushTypeSpec(T).setNameLoc(NameLoc);
-
- T = getElaboratedType(ETK_None, *SS, T);
- ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
- ElabTL.setElaboratedKeywordLoc(SourceLocation());
- ElabTL.setQualifierLoc(SS->getWithLocInContext(Context));
- return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
- } else {
- T = getElaboratedType(ETK_None, *SS, T);
- }
- }
} else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
(void)DiagnoseUseOfDecl(IDecl, NameLoc);
if (!HasTrailingDot)
T = Context.getObjCInterfaceType(IDecl);
+ } else if (AllowDeducedTemplate) {
+ if (auto *TD = getAsTypeTemplateDecl(IIDecl))
+ T = Context.getDeducedTemplateSpecializationType(TemplateName(TD),
+ QualType(), false);
}
if (T.isNull()) {
@@ -459,6 +489,27 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
Result.suppressDiagnostics();
return nullptr;
}
+
+ // NOTE: avoid constructing an ElaboratedType(Loc) if this is a
+ // constructor or destructor name (in such a case, the scope specifier
+ // will be attached to the enclosing Expr or Decl node).
+ if (SS && SS->isNotEmpty() && !IsCtorOrDtorName &&
+ !isa<ObjCInterfaceDecl>(IIDecl)) {
+ if (WantNontrivialTypeSourceInfo) {
+ // Construct a type with type-source information.
+ TypeLocBuilder Builder;
+ Builder.pushTypeSpec(T).setNameLoc(NameLoc);
+
+ T = getElaboratedType(ETK_None, *SS, T);
+ ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ ElabTL.setQualifierLoc(SS->getWithLocInContext(Context));
+ return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+ } else {
+ T = getElaboratedType(ETK_None, *SS, T);
+ }
+ }
+
return ParsedType::make(T);
}
@@ -589,7 +640,7 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(CurContext);
for (const auto &Base : RD->bases())
- if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType()))
+ if (Ty && Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType()))
return true;
return S->isFunctionPrototypeScope();
}
@@ -601,7 +652,10 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
Scope *S,
CXXScopeSpec *SS,
ParsedType &SuggestedType,
- bool AllowClassTemplates) {
+ bool IsTemplateName) {
+ // Don't report typename errors for editor placeholders.
+ if (II->isEditorPlaceholder())
+ return;
// We don't have anything to suggest (yet).
SuggestedType = nullptr;
@@ -610,32 +664,46 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
if (TypoCorrection Corrected =
CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS,
llvm::make_unique<TypeNameValidatorCCC>(
- false, false, AllowClassTemplates),
+ false, false, IsTemplateName, !IsTemplateName),
CTK_ErrorRecovery)) {
+ // FIXME: Support error recovery for the template-name case.
+ bool CanRecover = !IsTemplateName;
if (Corrected.isKeyword()) {
// We corrected to a keyword.
- diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II);
+ diagnoseTypo(Corrected,
+ PDiag(IsTemplateName ? diag::err_no_template_suggest
+ : diag::err_unknown_typename_suggest)
+ << II);
II = Corrected.getCorrectionAsIdentifierInfo();
} else {
// We found a similarly-named type or interface; suggest that.
if (!SS || !SS->isSet()) {
diagnoseTypo(Corrected,
- PDiag(diag::err_unknown_typename_suggest) << II);
+ PDiag(IsTemplateName ? diag::err_no_template_suggest
+ : diag::err_unknown_typename_suggest)
+ << II, CanRecover);
} else if (DeclContext *DC = computeDeclContext(*SS, false)) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
II->getName().equals(CorrectedStr);
diagnoseTypo(Corrected,
- PDiag(diag::err_unknown_nested_typename_suggest)
- << II << DC << DroppedSpecifier << SS->getRange());
+ PDiag(IsTemplateName
+ ? diag::err_no_member_template_suggest
+ : diag::err_unknown_nested_typename_suggest)
+ << II << DC << DroppedSpecifier << SS->getRange(),
+ CanRecover);
} else {
llvm_unreachable("could not have corrected a typo here");
}
+ if (!CanRecover)
+ return;
+
CXXScopeSpec tmpSS;
if (Corrected.getCorrectionSpecifier())
tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(),
SourceRange(IILoc));
+ // FIXME: Support class template argument deduction here.
SuggestedType =
getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S,
tmpSS.isSet() ? &tmpSS : SS, false, false, nullptr,
@@ -645,7 +713,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
return;
}
- if (getLangOpts().CPlusPlus) {
+ if (getLangOpts().CPlusPlus && !IsTemplateName) {
// See if II is a class template that the user forgot to pass arguments to.
UnqualifiedId Name;
Name.setIdentifier(II, IILoc);
@@ -656,7 +724,8 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
Name, nullptr, true, TemplateResult,
MemberOfUnknownSpecialization) == TNK_Type_template) {
TemplateName TplName = TemplateResult.get();
- Diag(IILoc, diag::err_template_missing_args) << TplName;
+ Diag(IILoc, diag::err_template_missing_args)
+ << (int)getTemplateNameKindForDiagnostics(TplName) << TplName;
if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) {
Diag(TplDecl->getLocation(), diag::note_template_decl_here)
<< TplDecl->getTemplateParameters()->getSourceRange();
@@ -669,10 +738,13 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
// (struct, union, enum) from Parser::ParseImplicitInt here, instead?
if (!SS || (!SS->isSet() && !SS->isInvalid()))
- Diag(IILoc, diag::err_unknown_typename) << II;
+ Diag(IILoc, IsTemplateName ? diag::err_no_template
+ : diag::err_unknown_typename)
+ << II;
else if (DeclContext *DC = computeDeclContext(*SS, false))
- Diag(IILoc, diag::err_typename_nested_not_found)
- << II << DC << SS->getRange();
+ Diag(IILoc, IsTemplateName ? diag::err_no_member_template
+ : diag::err_typename_nested_not_found)
+ << II << DC << SS->getRange();
else if (isDependentScopeSpecifier(*SS)) {
unsigned DiagID = diag::err_typename_missing;
if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S))
@@ -782,6 +854,13 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
if (NextToken.is(tok::coloncolon)) {
NestedNameSpecInfo IdInfo(Name, NameLoc, NextToken.getLocation());
BuildCXXNestedNameSpecifier(S, IdInfo, false, SS, nullptr, false);
+ } else if (getLangOpts().CPlusPlus && SS.isSet() &&
+ isCurrentClassName(*Name, S, &SS)) {
+ // Per [class.qual]p2, this names the constructors of SS, not the
+ // injected-class-name. We don't have a classification for that.
+ // There's not much point caching this result, since the parser
+ // will reject it later.
+ return NameClassification::Unknown();
}
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
@@ -1072,6 +1151,24 @@ Corrected:
return BuildDeclarationNameExpr(SS, Result, ADL);
}
+Sema::TemplateNameKindForDiagnostics
+Sema::getTemplateNameKindForDiagnostics(TemplateName Name) {
+ auto *TD = Name.getAsTemplateDecl();
+ if (!TD)
+ return TemplateNameKindForDiagnostics::DependentTemplate;
+ if (isa<ClassTemplateDecl>(TD))
+ return TemplateNameKindForDiagnostics::ClassTemplate;
+ if (isa<FunctionTemplateDecl>(TD))
+ return TemplateNameKindForDiagnostics::FunctionTemplate;
+ if (isa<VarTemplateDecl>(TD))
+ return TemplateNameKindForDiagnostics::VarTemplate;
+ if (isa<TypeAliasTemplateDecl>(TD))
+ return TemplateNameKindForDiagnostics::AliasTemplate;
+ if (isa<TemplateTemplateParmDecl>(TD))
+ return TemplateNameKindForDiagnostics::TemplateTemplateParam;
+ return TemplateNameKindForDiagnostics::DependentTemplate;
+}
+
// Determines the context to return to after temporarily entering a
// context. This depends in an unnecessarily complicated way on the
// exact ordering of callbacks from the parser.
@@ -1230,15 +1327,17 @@ void Sema::ActOnExitFunctionContext() {
/// overloaded function declaration or has the "overloadable"
/// attribute.
static bool AllowOverloadingOfFunction(LookupResult &Previous,
- ASTContext &Context) {
+ ASTContext &Context,
+ const FunctionDecl *New) {
if (Context.getLangOpts().CPlusPlus)
return true;
if (Previous.getResultKind() == LookupResult::FoundOverloaded)
return true;
- return (Previous.getResultKind() == LookupResult::Found
- && Previous.getFoundDecl()->hasAttr<OverloadableAttr>());
+ return Previous.getResultKind() == LookupResult::Found &&
+ (Previous.getFoundDecl()->hasAttr<OverloadableAttr>() ||
+ New->hasAttr<OverloadableAttr>());
}
/// Add this decl to the scope shadowed decl chains.
@@ -1432,6 +1531,11 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return false;
+ // A non-out-of-line declaration of a member specialization was implicitly
+ // instantiated; it's the out-of-line declaration that we're interested in.
+ if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
+ FD->getMemberSpecializationInfo() && !FD->isOutOfLine())
+ return false;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD))
@@ -1458,6 +1562,10 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
if (VD->isStaticDataMember() &&
VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return false;
+ if (VD->isStaticDataMember() &&
+ VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
+ VD->getMemberSpecializationInfo() && !VD->isOutOfLine())
+ return false;
if (VD->isInline() && !isMainFileLoc(*this, VD->getLocation()))
return false;
@@ -1890,8 +1998,7 @@ static void filterNonConflictingPreviousTypedefDecls(Sema &S,
// If both declarations give a tag declaration a typedef name for linkage
// purposes, then they declare the same entity.
- if (S.getLangOpts().CPlusPlus &&
- OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) &&
+ if (OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) &&
Decl->getAnonDeclWithTypedefName())
continue;
}
@@ -1916,7 +2023,7 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
Diag(New->getLocation(), diag::err_redefinition_variably_modified_typedef)
<< Kind << NewType;
if (Old->getLocation().isValid())
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->setInvalidDecl();
return true;
}
@@ -1929,7 +2036,7 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
Diag(New->getLocation(), diag::err_redefinition_different_typedef)
<< Kind << NewType << OldType;
if (Old->getLocation().isValid())
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->setInvalidDecl();
return true;
}
@@ -1996,7 +2103,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
NamedDecl *OldD = OldDecls.getRepresentativeDecl();
if (OldD->getLocation().isValid())
- Diag(OldD->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(OldD, New->getLocation());
return New->setInvalidDecl();
}
@@ -2009,7 +2116,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
auto *OldTag = OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true);
auto *NewTag = New->getAnonDeclWithTypedefName();
NamedDecl *Hidden = nullptr;
- if (getLangOpts().CPlusPlus && OldTag && NewTag &&
+ if (OldTag && NewTag &&
OldTag->getCanonicalDecl() != NewTag->getCanonicalDecl() &&
!hasVisibleDefinition(OldTag, &Hidden)) {
// There is a definition of this tag, but it is not visible. Use it
@@ -2022,7 +2129,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
New->setTypeSourceInfo(OldTD->getTypeSourceInfo());
// Make the old tag definition visible.
- makeMergedDefinitionVisible(Hidden, NewTag->getLocation());
+ makeMergedDefinitionVisible(Hidden);
// If this was an unscoped enumeration, yank all of its enumerators
// out of the scope.
@@ -2088,7 +2195,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
Diag(New->getLocation(), diag::err_redefinition)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
return New->setInvalidDecl();
}
@@ -2101,13 +2208,15 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
// -Wtypedef-redefinition. If either the original or the redefinition is
// in a system header, don't emit this for compatibility with GCC.
if (getDiagnostics().getSuppressSystemWarnings() &&
- (Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
+ // Some standard types are defined implicitly in Clang (e.g. OpenCL).
+ (Old->isImplicit() ||
+ Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
Context.getSourceManager().isInSystemHeader(New->getLocation())))
return;
Diag(New->getLocation(), diag::ext_redefinition_of_typedef)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
}
/// DeclhasAttr - returns true if decl Declaration already has the target
@@ -2341,7 +2450,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
return false;
}
-static const Decl *getDefinition(const Decl *D) {
+static const NamedDecl *getDefinition(const Decl *D) {
if (const TagDecl *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
@@ -2368,7 +2477,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
if (!New->hasAttrs())
return;
- const Decl *Def = getDefinition(Old);
+ const NamedDecl *Def = getDefinition(Old);
if (!Def || Def == New)
return;
@@ -2394,7 +2503,10 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
? diag::err_alias_after_tentative
: diag::err_redefinition;
S.Diag(VD->getLocation(), Diag) << VD->getDeclName();
- S.Diag(Def->getLocation(), diag::note_previous_definition);
+ if (Diag == diag::err_redefinition)
+ S.notePreviousDefinition(Def, VD->getLocation());
+ else
+ S.Diag(Def->getLocation(), diag::note_previous_definition);
VD->setInvalidDecl();
}
++I;
@@ -2781,7 +2893,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
} else {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
<< New->getDeclName();
- Diag(OldD->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(OldD, New->getLocation());
return true;
}
}
@@ -2818,10 +2930,45 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
!Old->hasAttr<InternalLinkageAttr>()) {
Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->dropAttr<InternalLinkageAttr>();
}
+ if (!getLangOpts().CPlusPlus) {
+ bool OldOvl = Old->hasAttr<OverloadableAttr>();
+ if (OldOvl != New->hasAttr<OverloadableAttr>() && !Old->isImplicit()) {
+ Diag(New->getLocation(), diag::err_attribute_overloadable_mismatch)
+ << New << OldOvl;
+
+ // Try our best to find a decl that actually has the overloadable
+ // attribute for the note. In most cases (e.g. programs with only one
+ // broken declaration/definition), this won't matter.
+ //
+ // FIXME: We could do this if we juggled some extra state in
+ // OverloadableAttr, rather than just removing it.
+ const Decl *DiagOld = Old;
+ if (OldOvl) {
+ auto OldIter = llvm::find_if(Old->redecls(), [](const Decl *D) {
+ const auto *A = D->getAttr<OverloadableAttr>();
+ return A && !A->isImplicit();
+ });
+ // If we've implicitly added *all* of the overloadable attrs to this
+ // chain, emitting a "previous redecl" note is pointless.
+ DiagOld = OldIter == Old->redecls_end() ? nullptr : *OldIter;
+ }
+
+ if (DiagOld)
+ Diag(DiagOld->getLocation(),
+ diag::note_attribute_overloadable_prev_overload)
+ << OldOvl;
+
+ if (OldOvl)
+ New->addAttr(OverloadableAttr::CreateImplicit(Context));
+ else
+ New->dropAttr<OverloadableAttr>();
+ }
+ }
+
// If a function is first declared with a calling convention, but is later
// declared or defined without one, all following decls assume the calling
// convention of the first.
@@ -2893,7 +3040,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
// Merge ns_returns_retained attribute.
if (OldTypeInfo.getProducesResult() != NewTypeInfo.getProducesResult()) {
if (NewTypeInfo.getProducesResult()) {
- Diag(New->getLocation(), diag::err_returns_retained_mismatch);
+ Diag(New->getLocation(), diag::err_function_attribute_mismatch)
+ << "'ns_returns_retained'";
Diag(OldLocation, diag::note_previous_declaration);
return true;
}
@@ -2902,6 +3050,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
RequiresAdjustment = true;
}
+ if (OldTypeInfo.getNoCallerSavedRegs() !=
+ NewTypeInfo.getNoCallerSavedRegs()) {
+ if (NewTypeInfo.getNoCallerSavedRegs()) {
+ AnyX86NoCallerSavedRegistersAttr *Attr =
+ New->getAttr<AnyX86NoCallerSavedRegistersAttr>();
+ Diag(New->getLocation(), diag::err_function_attribute_mismatch) << Attr;
+ Diag(OldLocation, diag::note_previous_declaration);
+ return true;
+ }
+
+ NewTypeInfo = NewTypeInfo.withNoCallerSavedRegs(true);
+ RequiresAdjustment = true;
+ }
+
if (RequiresAdjustment) {
const FunctionType *AdjustedType = New->getType()->getAs<FunctionType>();
AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo);
@@ -3035,7 +3197,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
// [...] A member shall not be declared twice in the
// member-specification, except that a nested class or member
// class template can be declared and then later defined.
- if (ActiveTemplateInstantiations.empty()) {
+ if (!inTemplateInstantiation()) {
unsigned NewDiag;
if (isa<CXXConstructorDecl>(OldMethod))
NewDiag = diag::err_constructor_redeclared;
@@ -3531,9 +3693,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
- << New->getDeclName();
- Diag(Previous.getRepresentativeDecl()->getLocation(),
- diag::note_previous_definition);
+ << New->getDeclName();
+ notePreviousDefinition(Previous.getRepresentativeDecl(),
+ New->getLocation());
return New->setInvalidDecl();
}
@@ -3562,7 +3724,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
Old->getStorageClass() == SC_None &&
!Old->hasAttr<WeakImportAttr>()) {
Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
// Remove weak_import attribute on new declaration.
New->dropAttr<WeakImportAttr>();
}
@@ -3571,7 +3733,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
!Old->hasAttr<InternalLinkageAttr>()) {
Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->dropAttr<InternalLinkageAttr>();
}
@@ -3728,6 +3890,60 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->setImplicitlyInline();
}
+void Sema::notePreviousDefinition(const NamedDecl *Old, SourceLocation New) {
+ SourceManager &SrcMgr = getSourceManager();
+ auto FNewDecLoc = SrcMgr.getDecomposedLoc(New);
+ auto FOldDecLoc = SrcMgr.getDecomposedLoc(Old->getLocation());
+ auto *FNew = SrcMgr.getFileEntryForID(FNewDecLoc.first);
+ auto *FOld = SrcMgr.getFileEntryForID(FOldDecLoc.first);
+ auto &HSI = PP.getHeaderSearchInfo();
+ StringRef HdrFilename =
+ SrcMgr.getFilename(SrcMgr.getSpellingLoc(Old->getLocation()));
+
+ auto noteFromModuleOrInclude = [&](Module *Mod,
+ SourceLocation IncLoc) -> bool {
+ // Redefinition errors with modules are common with non modular mapped
+ // headers, example: a non-modular header H in module A that also gets
+ // included directly in a TU. Pointing twice to the same header/definition
+ // is confusing, try to get better diagnostics when modules is on.
+ if (IncLoc.isValid()) {
+ if (Mod) {
+ Diag(IncLoc, diag::note_redefinition_modules_same_file)
+ << HdrFilename.str() << Mod->getFullModuleName();
+ if (!Mod->DefinitionLoc.isInvalid())
+ Diag(Mod->DefinitionLoc, diag::note_defined_here)
+ << Mod->getFullModuleName();
+ } else {
+ Diag(IncLoc, diag::note_redefinition_include_same_file)
+ << HdrFilename.str();
+ }
+ return true;
+ }
+
+ return false;
+ };
+
+ // Is it the same file and same offset? Provide more information on why
+ // this leads to a redefinition error.
+ bool EmittedDiag = false;
+ if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) {
+ SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(FOldDecLoc.first);
+ SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(FNewDecLoc.first);
+ EmittedDiag = noteFromModuleOrInclude(Old->getOwningModule(), OldIncLoc);
+ EmittedDiag |= noteFromModuleOrInclude(getCurrentModule(), NewIncLoc);
+
+ // If the header has no guards, emit a note suggesting one.
+ if (FOld && !HSI.isFileMultipleIncludeGuarded(FOld))
+ Diag(Old->getLocation(), diag::note_use_ifdef_guards);
+
+ if (EmittedDiag)
+ return;
+ }
+
+ // Redefinition coming from different files or couldn't do better above.
+ Diag(Old->getLocation(), diag::note_previous_definition);
+}
+
/// We've just determined that \p Old and \p New both appear to be definitions
/// of the same variable. Either diagnose or fix the problem.
bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) {
@@ -3743,12 +3959,12 @@ bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) {
// Make the canonical definition visible.
if (auto *OldTD = Old->getDescribedVarTemplate())
- makeMergedDefinitionVisible(OldTD, New->getLocation());
- makeMergedDefinitionVisible(Old, New->getLocation());
+ makeMergedDefinitionVisible(OldTD);
+ makeMergedDefinitionVisible(Old);
return false;
} else {
Diag(New->getLocation(), diag::err_redefinition) << New;
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old, New->getLocation());
New->setInvalidDecl();
return true;
}
@@ -4622,6 +4838,34 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
NameInfo.setLoc(Name.StartLocation);
return NameInfo;
+ case UnqualifiedId::IK_DeductionGuideName: {
+ // C++ [temp.deduct.guide]p3:
+ // The simple-template-id shall name a class template specialization.
+ // The template-name shall be the same identifier as the template-name
+ // of the simple-template-id.
+ // These together intend to imply that the template-name shall name a
+ // class template.
+ // FIXME: template<typename T> struct X {};
+ // template<typename T> using Y = X<T>;
+ // Y(int) -> Y<int>;
+ // satisfies these rules but does not name a class template.
+ TemplateName TN = Name.TemplateName.get().get();
+ auto *Template = TN.getAsTemplateDecl();
+ if (!Template || !isa<ClassTemplateDecl>(Template)) {
+ Diag(Name.StartLocation,
+ diag::err_deduction_guide_name_not_class_template)
+ << (int)getTemplateNameKindForDiagnostics(TN) << TN;
+ if (Template)
+ Diag(Template->getLocation(), diag::note_template_decl_here);
+ return DeclarationNameInfo();
+ }
+
+ NameInfo.setName(
+ Context.DeclarationNames.getCXXDeductionGuideName(Template));
+ NameInfo.setLoc(Name.StartLocation);
+ return NameInfo;
+ }
+
case UnqualifiedId::IK_OperatorFunctionId:
NameInfo.setName(Context.DeclarationNames.getCXXOperatorName(
Name.OperatorFunctionId.Operator));
@@ -5382,8 +5626,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
diag::err_concept_wrong_decl_kind);
if (D.getName().Kind != UnqualifiedId::IK_Identifier) {
- Diag(D.getName().StartLocation, diag::err_typedef_not_identifier)
- << D.getName().getSourceRange();
+ if (D.getName().Kind == UnqualifiedId::IK_DeductionGuideName)
+ Diag(D.getName().StartLocation,
+ diag::err_deduction_guide_invalid_specifier)
+ << "typedef";
+ else
+ Diag(D.getName().StartLocation, diag::err_typedef_not_identifier)
+ << D.getName().getSourceRange();
return nullptr;
}
@@ -5444,6 +5693,10 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
NamedDecl*
Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
LookupResult &Previous, bool &Redeclaration) {
+
+ // Find the shadowed declaration before filtering for scope.
+ NamedDecl *ShadowedDecl = getShadowedDeclaration(NewTD, Previous);
+
// Merge the decl with the existing one if appropriate. If the decl is
// in an outer scope, it isn't the same thing.
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/false,
@@ -5454,6 +5707,9 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
MergeTypedefNameDecl(S, NewTD, Previous);
}
+ if (ShadowedDecl && !Redeclaration)
+ CheckShadow(NewTD, ShadowedDecl, Previous);
+
// If this is the C FILE type, notify the AST context.
if (IdentifierInfo *II = NewTD->getIdentifier())
if (!NewTD->isInvalidDecl() &&
@@ -5649,13 +5905,17 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
if (OldDecl->isInvalidDecl())
return;
+ bool IsTemplate = false;
if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl)) {
OldDecl = OldTD->getTemplatedDecl();
+ IsTemplate = true;
if (!IsSpecialization)
IsDefinition = false;
}
- if (TemplateDecl *NewTD = dyn_cast<TemplateDecl>(NewDecl))
+ if (TemplateDecl *NewTD = dyn_cast<TemplateDecl>(NewDecl)) {
NewDecl = NewTD->getTemplatedDecl();
+ IsTemplate = true;
+ }
if (!OldDecl || !NewDecl)
return;
@@ -5708,9 +5968,10 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
}
// A redeclaration is not allowed to drop a dllimport attribute, the only
- // exceptions being inline function definitions, local extern declarations,
- // qualified friend declarations or special MSVC extension: in the last case,
- // the declaration is treated as if it were marked dllexport.
+ // exceptions being inline function definitions (except for function
+ // templates), local extern declarations, qualified friend declarations or
+ // special MSVC extension: in the last case, the declaration is treated as if
+ // it were marked dllexport.
bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false;
bool IsMicrosoft = S.Context.getTargetInfo().getCXXABI().isMicrosoft();
if (const auto *VD = dyn_cast<VarDecl>(NewDecl)) {
@@ -5725,7 +5986,8 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
FD->getFriendObjectKind() == Decl::FOK_Declared;
}
- if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember &&
+ if (OldImportAttr && !HasNewAttr &&
+ (!IsInline || (IsMicrosoft && IsTemplate)) && !IsStaticDataMember &&
!NewDecl->isLocalExternDecl() && !IsQualifiedFriend) {
if (IsMicrosoft && IsDefinition) {
S.Diag(NewDecl->getLocation(),
@@ -5902,8 +6164,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
Name = II;
}
} else if (!II) {
- Diag(D.getIdentifierLoc(), diag::err_bad_variable_name)
- << Name;
+ Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) << Name;
return nullptr;
}
@@ -5936,7 +6197,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
QualType NR = R;
while (NR->isPointerType()) {
if (NR->isFunctionPointerType()) {
- Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer_variable);
+ Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
D.setInvalidType();
break;
}
@@ -5952,12 +6213,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:
@@ -6017,7 +6290,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
- bool IsExplicitSpecialization = false;
+ bool IsMemberSpecialization = false;
bool IsVariableTemplateSpecialization = false;
bool IsPartialSpecialization = false;
bool IsVariableTemplate = false;
@@ -6029,7 +6302,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
D.getIdentifierLoc(), II,
R, TInfo, SC);
- if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType())
+ if (R->getContainedDeducedType())
ParsingInitForAutoVars.insert(NewVD);
if (D.isInvalidType())
@@ -6095,7 +6368,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
? D.getName().TemplateId
: nullptr,
TemplateParamLists,
- /*never a friend*/ false, IsExplicitSpecialization, Invalid);
+ /*never a friend*/ false, IsMemberSpecialization, Invalid);
if (TemplateParams) {
if (!TemplateParams->size() &&
@@ -6165,7 +6438,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// If this decl has an auto type in need of deduction, make a note of the
// Decl so we can diagnose uses of it in its own initializer.
- if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType())
+ if (R->getContainedDeducedType())
ParsingInitForAutoVars.insert(NewVD);
if (D.isInvalidType() || Invalid) {
@@ -6280,7 +6553,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
diag::err_thread_non_global)
<< DeclSpec::getSpecifierName(TSCS);
else if (!Context.getTargetInfo().isTLSSupported()) {
- if (getLangOpts().CUDA) {
+ if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) {
// Postpone error emission until we've collected attributes required to
// figure out whether it's a host or device variable and whether the
// error should be ignored.
@@ -6321,7 +6594,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
<< (IsPartialSpecialization ? 1 : 0)
<< FixItHint::CreateRemoval(
D.getDeclSpec().getModulePrivateSpecLoc());
- else if (IsExplicitSpecialization)
+ else if (IsMemberSpecialization)
Diag(NewVD->getLocation(), diag::err_module_private_specialization)
<< 2
<< FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
@@ -6342,8 +6615,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
- if (getLangOpts().CUDA) {
- if (EmitTLSUnsupportedError && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD))
+ if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) {
+ if (EmitTLSUnsupportedError &&
+ ((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) ||
+ (getLangOpts().OpenMPIsDevice &&
+ NewVD->hasAttr<OMPDeclareTargetDeclAttr>())))
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_thread_unsupported);
// CUDA B.2.5: "__shared__ and __constant__ variables have implied static
@@ -6436,7 +6712,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// declaration has linkage).
FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewVD),
D.getCXXScopeSpec().isNotEmpty() ||
- IsExplicitSpecialization ||
+ IsMemberSpecialization ||
IsVariableTemplateSpecialization);
// Check whether the previous declaration is in the same block scope. This
@@ -6451,7 +6727,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
} else {
// If this is an explicit specialization of a static data member, check it.
- if (IsExplicitSpecialization && !NewVD->isInvalidDecl() &&
+ if (IsMemberSpecialization && !NewVD->isInvalidDecl() &&
CheckMemberSpecialization(NewVD, Previous))
NewVD->setInvalidDecl();
@@ -6566,7 +6842,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (D.isRedeclaration() && !Previous.empty()) {
checkDLLAttributeRedeclaration(
*this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewVD,
- IsExplicitSpecialization, D.isFunctionDefinition());
+ IsMemberSpecialization, D.isFunctionDefinition());
}
if (NewTemplate) {
@@ -6576,17 +6852,32 @@ NamedDecl *Sema::ActOnVariableDeclarator(
return NewTemplate;
}
+ if (IsMemberSpecialization && !NewVD->isInvalidDecl())
+ CompleteMemberSpecialization(NewVD, Previous);
+
return NewVD;
}
/// Enum describing the %select options in diag::warn_decl_shadow.
-enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field };
+enum ShadowedDeclKind {
+ SDK_Local,
+ SDK_Global,
+ SDK_StaticMember,
+ SDK_Field,
+ SDK_Typedef,
+ SDK_Using
+};
/// Determine what kind of declaration we're shadowing.
static ShadowedDeclKind computeShadowedDeclKind(const NamedDecl *ShadowedDecl,
const DeclContext *OldDC) {
- if (isa<RecordDecl>(OldDC))
+ if (isa<TypeAliasDecl>(ShadowedDecl))
+ return SDK_Using;
+ else if (isa<TypedefDecl>(ShadowedDecl))
+ return SDK_Typedef;
+ else if (isa<RecordDecl>(OldDC))
return isa<FieldDecl>(ShadowedDecl) ? SDK_Field : SDK_StaticMember;
+
return OldDC->isFileContext() ? SDK_Global : SDK_Local;
}
@@ -6601,28 +6892,48 @@ static SourceLocation getCaptureLocation(const LambdaScopeInfo *LSI,
return SourceLocation();
}
+static bool shouldWarnIfShadowedDecl(const DiagnosticsEngine &Diags,
+ const LookupResult &R) {
+ // Only diagnose if we're shadowing an unambiguous field or variable.
+ if (R.getResultKind() != LookupResult::Found)
+ return false;
+
+ // Return false if warning is ignored.
+ return !Diags.isIgnored(diag::warn_decl_shadow, R.getNameLoc());
+}
+
/// \brief Return the declaration shadowed by the given variable \p D, or null
/// if it doesn't shadow any declaration or shadowing warnings are disabled.
NamedDecl *Sema::getShadowedDeclaration(const VarDecl *D,
const LookupResult &R) {
- // Return if warning is ignored.
- if (Diags.isIgnored(diag::warn_decl_shadow, R.getNameLoc()))
+ if (!shouldWarnIfShadowedDecl(Diags, R))
return nullptr;
// Don't diagnose declarations at file scope.
if (D->hasGlobalStorage())
return nullptr;
- // Only diagnose if we're shadowing an unambiguous field or variable.
- if (R.getResultKind() != LookupResult::Found)
- return nullptr;
-
NamedDecl *ShadowedDecl = R.getFoundDecl();
return isa<VarDecl>(ShadowedDecl) || isa<FieldDecl>(ShadowedDecl)
? ShadowedDecl
: nullptr;
}
+/// \brief Return the declaration shadowed by the given typedef \p D, or null
+/// if it doesn't shadow any declaration or shadowing warnings are disabled.
+NamedDecl *Sema::getShadowedDeclaration(const TypedefNameDecl *D,
+ const LookupResult &R) {
+ // Don't warn if typedef declaration is part of a class
+ if (D->getDeclContext()->isRecord())
+ return nullptr;
+
+ if (!shouldWarnIfShadowedDecl(Diags, R))
+ return nullptr;
+
+ NamedDecl *ShadowedDecl = R.getFoundDecl();
+ return isa<TypedefNameDecl>(ShadowedDecl) ? ShadowedDecl : nullptr;
+}
+
/// \brief Diagnose variable or built-in function shadowing. Implements
/// -Wshadow.
///
@@ -6632,7 +6943,7 @@ NamedDecl *Sema::getShadowedDeclaration(const VarDecl *D,
/// \param ShadowedDecl the declaration that is shadowed by the given variable
/// \param R the lookup of the name
///
-void Sema::CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl,
+void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
const LookupResult &R) {
DeclContext *NewDC = D->getDeclContext();
@@ -6644,13 +6955,13 @@ void Sema::CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl,
// Fields shadowed by constructor parameters are a special case. Usually
// the constructor initializes the field with the parameter.
- if (isa<CXXConstructorDecl>(NewDC) && isa<ParmVarDecl>(D)) {
- // Remember that this was shadowed so we can either warn about its
- // modification or its existence depending on warning settings.
- D = D->getCanonicalDecl();
- ShadowingDecls.insert({D, FD});
- return;
- }
+ if (isa<CXXConstructorDecl>(NewDC))
+ if (const auto PVD = dyn_cast<ParmVarDecl>(D)) {
+ // Remember that this was shadowed so we can either warn about its
+ // modification or its existence depending on warning settings.
+ ShadowingDecls.insert({PVD->getCanonicalDecl(), FD});
+ return;
+ }
}
if (VarDecl *shadowedVar = dyn_cast<VarDecl>(ShadowedDecl))
@@ -6664,11 +6975,12 @@ void Sema::CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl,
}
}
- DeclContext *OldDC = ShadowedDecl->getDeclContext();
+ DeclContext *OldDC = ShadowedDecl->getDeclContext()->getRedeclContext();
unsigned WarningDiag = diag::warn_decl_shadow;
SourceLocation CaptureLoc;
- if (isa<VarDecl>(ShadowedDecl) && NewDC && isa<CXXMethodDecl>(NewDC)) {
+ if (isa<VarDecl>(D) && isa<VarDecl>(ShadowedDecl) && NewDC &&
+ isa<CXXMethodDecl>(NewDC)) {
if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) {
if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) {
if (RD->getLambdaCaptureDefault() == LCD_None) {
@@ -6682,10 +6994,26 @@ void Sema::CheckShadow(VarDecl *D, NamedDecl *ShadowedDecl,
// Remember that this was shadowed so we can avoid the warning if the
// shadowed decl isn't captured and the warning settings allow it.
cast<LambdaScopeInfo>(getCurFunction())
- ->ShadowingDecls.push_back({D, cast<VarDecl>(ShadowedDecl)});
+ ->ShadowingDecls.push_back(
+ {cast<VarDecl>(D), cast<VarDecl>(ShadowedDecl)});
return;
}
}
+
+ if (cast<VarDecl>(ShadowedDecl)->hasLocalStorage()) {
+ // A variable can't shadow a local variable in an enclosing scope, if
+ // they are separated by a non-capturing declaration context.
+ for (DeclContext *ParentDC = NewDC;
+ ParentDC && !ParentDC->Equals(OldDC);
+ ParentDC = getLambdaAwareParentOfDeclContext(ParentDC)) {
+ // Only block literals, captured statements, and lambda expressions
+ // can capture; other scopes don't.
+ if (!isa<BlockDecl>(ParentDC) && !isa<CapturedDecl>(ParentDC) &&
+ !isLambdaCallOperator(ParentDC)) {
+ return;
+ }
+ }
+ }
}
}
@@ -6918,7 +7246,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
// ISO/IEC TR 18037 S5.1.2
if (!getLangOpts().OpenCL
&& NewVD->hasLocalStorage() && T.getAddressSpace() != 0) {
- Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl);
+ Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 0;
NewVD->setInvalidDecl();
return;
}
@@ -6983,11 +7311,11 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setInvalidDecl();
return;
}
- // OpenCL v1.1 s6.5.2 and s6.5.3 no local or constant variables
- // in functions.
if (T.getAddressSpace() == LangAS::opencl_constant ||
T.getAddressSpace() == LangAS::opencl_local) {
FunctionDecl *FD = getCurFunctionDecl();
+ // OpenCL v1.1 s6.5.2 and s6.5.3: no local or constant variables
+ // in functions.
if (FD && !FD->hasAttr<OpenCLKernelAttr>()) {
if (T.getAddressSpace() == LangAS::opencl_constant)
Diag(NewVD->getLocation(), diag::err_opencl_function_variable)
@@ -6998,6 +7326,25 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setInvalidDecl();
return;
}
+ // OpenCL v2.0 s6.5.2 and s6.5.3: local and constant variables must be
+ // in the outermost scope of a kernel function.
+ if (FD && FD->hasAttr<OpenCLKernelAttr>()) {
+ if (!getCurScope()->isFunctionScope()) {
+ if (T.getAddressSpace() == LangAS::opencl_constant)
+ Diag(NewVD->getLocation(), diag::err_opencl_addrspace_scope)
+ << "constant";
+ else
+ Diag(NewVD->getLocation(), diag::err_opencl_addrspace_scope)
+ << "local";
+ NewVD->setInvalidDecl();
+ return;
+ }
+ }
+ } else if (T.getAddressSpace() != LangAS::Default) {
+ // Do not allow other address spaces on automatic variable.
+ Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 1;
+ NewVD->setInvalidDecl();
+ return;
}
}
}
@@ -7273,6 +7620,10 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
} // end anonymous namespace
+void Sema::MarkTypoCorrectedFunctionDefinition(const NamedDecl *F) {
+ TypoCorrectedFunctionDefinitions.insert(F);
+}
+
/// \brief Generate diagnostics for an invalid function redeclaration.
///
/// This routine handles generating the diagnostic messages for an invalid
@@ -7370,6 +7721,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
if ((*I)->getCanonicalDecl() == Canonical)
Correction.setCorrectionDecl(*I);
+ // Let Sema know about the correction.
+ SemaRef.MarkTypoCorrectedFunctionDefinition(Result);
SemaRef.diagnoseTypo(
Correction,
SemaRef.PDiag(IsLocalFriend
@@ -7430,6 +7783,7 @@ static StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) {
case DeclSpec::SCS_mutable:
SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_typecheck_sclass_func);
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
D.setInvalidType();
break;
case DeclSpec::SCS_unspecified: break;
@@ -7472,11 +7826,12 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// Determine whether the function was written with a
// prototype. This true when:
// - there is a prototype in the declarator, or
- // - the type R of the function is some kind of typedef or other reference
- // to a type name (which eventually refers to a function type).
+ // - the type R of the function is some kind of typedef or other non-
+ // attributed reference to a type name (which eventually refers to a
+ // function type).
bool HasPrototype =
(D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) ||
- (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType());
+ (!R->getAsAdjusted<FunctionType>() && R->isFunctionProtoType());
NewFD = FunctionDecl::Create(SemaRef.Context, DC,
D.getLocStart(), NameInfo, R,
@@ -7562,6 +7917,12 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
R, TInfo, isInline, isExplicit,
isConstexpr, SourceLocation());
+ } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
+ SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
+
+ return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getLocStart(),
+ isExplicit, NameInfo, R, TInfo,
+ D.getLocEnd());
} else if (DC->isRecord()) {
// If the name of the function is the same as the name of the record,
// then this must be an invalid constructor that has a return type.
@@ -7625,10 +7986,7 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
if (PT->isImageType())
return PtrKernelParam;
- if (PT->isBooleanType())
- return InvalidKernelParam;
-
- if (PT->isEventT())
+ if (PT->isBooleanType() || PT->isEventT() || PT->isReserveIDT())
return InvalidKernelParam;
// OpenCL extension spec v1.2 s9.5:
@@ -7835,7 +8193,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isFriend = false;
FunctionTemplateDecl *FunctionTemplate = nullptr;
- bool isExplicitSpecialization = false;
+ bool isMemberSpecialization = false;
bool isFunctionTemplateSpecialization = false;
bool isDependentClassScopeExplicitSpecialization = false;
@@ -7891,7 +8249,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
SetNestedNameSpecifier(NewFD, D);
- isExplicitSpecialization = false;
+ isMemberSpecialization = false;
isFunctionTemplateSpecialization = false;
if (D.isInvalidType())
NewFD->setInvalidDecl();
@@ -7906,7 +8264,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getName().getKind() == UnqualifiedId::IK_TemplateId
? D.getName().TemplateId
: nullptr,
- TemplateParamLists, isFriend, isExplicitSpecialization,
+ TemplateParamLists, isFriend, isMemberSpecialization,
Invalid)) {
if (TemplateParams->size() > 0) {
// This is a function template
@@ -8050,7 +8408,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// The explicit specifier shall be used only in the declaration of a
// constructor or conversion function within its class definition;
// see 12.3.1 and 12.3.2.
- if (isExplicit && !NewFD->isInvalidDecl()) {
+ if (isExplicit && !NewFD->isInvalidDecl() &&
+ !isa<CXXDeductionGuideDecl>(NewFD)) {
if (!CurContext->isRecord()) {
// 'explicit' was specified outside of the class.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
@@ -8239,7 +8598,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Filter out previous declarations that don't match the scope.
FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD),
D.getCXXScopeSpec().isNotEmpty() ||
- isExplicitSpecialization ||
+ isMemberSpecialization ||
isFunctionTemplateSpecialization);
// Handle GNU asm-label extension (encoded as an attribute).
@@ -8357,6 +8716,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setInvalidDecl();
}
+ // Apply an implicit SectionAttr if '#pragma clang section text' is active
+ if (PragmaClangTextSection.Valid && D.isFunctionDefinition() &&
+ !NewFD->hasAttr<SectionAttr>()) {
+ NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit(Context,
+ PragmaClangTextSection.SectionName,
+ PragmaClangTextSection.PragmaLocation));
+ }
+
// Apply an implicit SectionAttr if #pragma code_seg is active.
if (CodeSegStack.CurrentValue && D.isFunctionDefinition() &&
!NewFD->hasAttr<SectionAttr>()) {
@@ -8389,7 +8756,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!getLangOpts().CPlusPlus) {
// Perform semantic checking on the function declaration.
- bool isExplicitSpecialization=false;
if (!NewFD->isInvalidDecl() && NewFD->isMain())
CheckMain(NewFD, D.getDeclSpec());
@@ -8398,7 +8764,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!NewFD->isInvalidDecl())
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
- isExplicitSpecialization));
+ isMemberSpecialization));
else if (!Previous.empty())
// Recover gracefully from an invalid redeclaration.
D.setRedeclaration(true);
@@ -8533,7 +8899,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< FixItHint::CreateRemoval(
D.getDeclSpec().getStorageClassSpecLoc());
}
- } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
+ } else if (isMemberSpecialization && isa<CXXMethodDecl>(NewFD)) {
if (CheckMemberSpecialization(NewFD, Previous))
NewFD->setInvalidDecl();
}
@@ -8548,7 +8914,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!NewFD->isInvalidDecl())
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
- isExplicitSpecialization));
+ isMemberSpecialization));
else if (!Previous.empty())
// Recover gracefully from an invalid redeclaration.
D.setRedeclaration(true);
@@ -8654,7 +9020,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
} else if (!D.isFunctionDefinition() &&
isa<CXXMethodDecl>(NewFD) && NewFD->isOutOfLine() &&
!isFriend && !isFunctionTemplateSpecialization &&
- !isExplicitSpecialization) {
+ !isMemberSpecialization) {
// An out-of-line member function declaration must also be a
// definition (C++ [class.mfct]p2).
// Note that this is not the case for explicit specializations of
@@ -8715,7 +9081,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (D.isRedeclaration() && !Previous.empty()) {
checkDLLAttributeRedeclaration(
*this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewFD,
- isExplicitSpecialization || isFunctionTemplateSpecialization,
+ isMemberSpecialization || isFunctionTemplateSpecialization,
D.isFunctionDefinition());
}
@@ -8741,12 +9107,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ MarkUnusedFileScopedDecl(NewFD);
+
if (getLangOpts().CPlusPlus) {
if (FunctionTemplate) {
if (NewFD->isInvalidDecl())
FunctionTemplate->setInvalidDecl();
return FunctionTemplate;
}
+
+ if (isMemberSpecialization && !NewFD->isInvalidDecl())
+ CompleteMemberSpecialization(NewFD, Previous);
}
if (NewFD->hasAttr<OpenCLKernelAttr>()) {
@@ -8786,8 +9157,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- MarkUnusedFileScopedDecl(NewFD);
-
// Here we have an function template explicit specialization at class scope.
// The actually specialization will be postponed to template instatiation
// time via the ClassScopeFunctionSpecializationDecl node.
@@ -8840,15 +9209,16 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
/// that have been instantiated via C++ template instantiation (called
/// via InstantiateDecl).
///
-/// \param IsExplicitSpecialization whether this new function declaration is
-/// an explicit specialization of the previous declaration.
+/// \param IsMemberSpecialization whether this new function declaration is
+/// a member specialization (that replaces any definition provided by the
+/// previous declaration).
///
/// This sets NewFD->isInvalidDecl() to true if there was an error.
///
/// \returns true if the function declaration is a redeclaration.
bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
LookupResult &Previous,
- bool IsExplicitSpecialization) {
+ bool IsMemberSpecialization) {
assert(!NewFD->getReturnType()->isVariablyModifiedType() &&
"Variably modified return types are not handled here");
@@ -8860,6 +9230,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
bool Redeclaration = false;
NamedDecl *OldDecl = nullptr;
+ bool MayNeedOverloadableChecks = false;
// Merge or overload the declaration with an existing declaration of
// the same name, if appropriate.
@@ -8868,13 +9239,14 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// a declaration that requires merging. If it's an overload,
// there's no more work to do here; we'll just add the new
// function to the scope.
- if (!AllowOverloadingOfFunction(Previous, Context)) {
+ if (!AllowOverloadingOfFunction(Previous, Context, NewFD)) {
NamedDecl *Candidate = Previous.getRepresentativeDecl();
if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) {
Redeclaration = true;
OldDecl = Candidate;
}
} else {
+ MayNeedOverloadableChecks = true;
switch (CheckOverload(S, NewFD, Previous, OldDecl,
/*NewIsUsingDecl*/ false)) {
case Ovl_Match:
@@ -8889,22 +9261,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
Redeclaration = false;
break;
}
-
- if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
- // If a function name is overloadable in C, then every function
- // with that name must be marked "overloadable".
- Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
- << Redeclaration << NewFD;
- NamedDecl *OverloadedDecl = nullptr;
- if (Redeclaration)
- OverloadedDecl = OldDecl;
- else if (!Previous.empty())
- OverloadedDecl = Previous.getRepresentativeDecl();
- if (OverloadedDecl)
- Diag(OverloadedDecl->getLocation(),
- diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
- }
}
}
@@ -8919,15 +9275,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
MergeTypeWithPrevious = false;
// ... except in the presence of __attribute__((overloadable)).
- if (OldDecl->hasAttr<OverloadableAttr>()) {
- if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
- Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
- << Redeclaration << NewFD;
- Diag(Previous.getFoundDecl()->getLocation(),
- diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
- }
+ if (OldDecl->hasAttr<OverloadableAttr>() ||
+ NewFD->hasAttr<OverloadableAttr>()) {
if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
+ MayNeedOverloadableChecks = true;
Redeclaration = false;
OldDecl = nullptr;
}
@@ -8961,7 +9312,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Warn that we did this, if we're not performing template instantiation.
// In that case, we'll have warned already when the template was defined.
- if (ActiveTemplateInstantiations.empty()) {
+ if (!inTemplateInstantiation()) {
SourceLocation AddConstLoc;
if (FunctionTypeLoc FTL = MD->getTypeSourceInfo()->getTypeLoc()
.IgnoreParens().getAs<FunctionTypeLoc>())
@@ -8998,7 +9349,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// If this is an explicit specialization of a member that is a function
// template, mark it as a member specialization.
- if (IsExplicitSpecialization &&
+ if (IsMemberSpecialization &&
NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
NewTemplateDecl->setMemberSpecialization();
assert(OldTemplateDecl->isMemberSpecialization());
@@ -9007,7 +9358,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (OldTemplateDecl->getTemplatedDecl()->isDeleted()) {
FunctionDecl *const OldTemplatedDecl =
OldTemplateDecl->getTemplatedDecl();
+ // FIXME: This assert will not hold in the presence of modules.
assert(OldTemplatedDecl->getCanonicalDecl() == OldTemplatedDecl);
+ // FIXME: We need an update record for this AST mutation.
OldTemplatedDecl->setDeletedAsWritten(false);
}
}
@@ -9020,6 +9373,29 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
NewFD->setAccess(OldDecl->getAccess());
}
}
+ } else if (!getLangOpts().CPlusPlus && MayNeedOverloadableChecks &&
+ !NewFD->getAttr<OverloadableAttr>()) {
+ assert((Previous.empty() ||
+ llvm::any_of(Previous,
+ [](const NamedDecl *ND) {
+ return ND->hasAttr<OverloadableAttr>();
+ })) &&
+ "Non-redecls shouldn't happen without overloadable present");
+
+ auto OtherUnmarkedIter = llvm::find_if(Previous, [](const NamedDecl *ND) {
+ const auto *FD = dyn_cast<FunctionDecl>(ND);
+ return FD && !FD->hasAttr<OverloadableAttr>();
+ });
+
+ if (OtherUnmarkedIter != Previous.end()) {
+ Diag(NewFD->getLocation(),
+ diag::err_attribute_overloadable_multiple_unmarked_overloads);
+ Diag((*OtherUnmarkedIter)->getLocation(),
+ diag::note_attribute_overloadable_prev_overload)
+ << false;
+
+ NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
+ }
}
// Semantic checking for this function declaration (in isolation).
@@ -9048,6 +9424,15 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(NewFD)) {
ActOnConversionDeclarator(Conversion);
+ } else if (auto *Guide = dyn_cast<CXXDeductionGuideDecl>(NewFD)) {
+ if (auto *TD = Guide->getDescribedFunctionTemplate())
+ CheckDeductionGuideTemplate(TD);
+
+ // A deduction guide is not on the list of entities that can be
+ // explicitly specialized.
+ if (Guide->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ Diag(Guide->getLocStart(), diag::err_deduction_guide_specialized)
+ << /*explicit specialization*/ 1;
}
// Find any virtual functions that this function overrides.
@@ -9395,7 +9780,7 @@ namespace {
InitFieldIndex.pop_back();
}
- // Returns true if MemberExpr is checked and no futher checking is needed.
+ // Returns true if MemberExpr is checked and no further checking is needed.
// Returns false if additional checking is required.
bool CheckInitListMemberExpr(MemberExpr *E, bool CheckReference) {
llvm::SmallVector<FieldDecl*, 4> Fields;
@@ -9703,11 +10088,36 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
VarDeclOrName VN{VDecl, Name};
- ArrayRef<Expr *> DeduceInits = Init;
+ DeducedType *Deduced = Type->getContainedDeducedType();
+ assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type");
+
+ // C++11 [dcl.spec.auto]p3
+ if (!Init) {
+ assert(VDecl && "no init for init capture deduction?");
+ Diag(VDecl->getLocation(), diag::err_auto_var_requires_init)
+ << VDecl->getDeclName() << Type;
+ return QualType();
+ }
+
+ ArrayRef<Expr*> DeduceInits = Init;
if (DirectInit) {
- if (auto *PL = dyn_cast<ParenListExpr>(Init))
+ if (auto *PL = dyn_cast_or_null<ParenListExpr>(Init))
DeduceInits = PL->exprs();
- else if (auto *IL = dyn_cast<InitListExpr>(Init))
+ }
+
+ if (isa<DeducedTemplateSpecializationType>(Deduced)) {
+ assert(VDecl && "non-auto type for init capture deduction?");
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
+ InitializationKind Kind = InitializationKind::CreateForInit(
+ VDecl->getLocation(), DirectInit, Init);
+ // FIXME: Initialization should not be taking a mutable list of inits.
+ SmallVector<Expr*, 8> InitsCopy(DeduceInits.begin(), DeduceInits.end());
+ return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind,
+ InitsCopy);
+ }
+
+ if (DirectInit) {
+ if (auto *IL = dyn_cast<InitListExpr>(Init))
DeduceInits = IL->inits();
}
@@ -9784,8 +10194,8 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
// checks.
// We only want to warn outside of template instantiations, though:
// inside a template, the 'id' could have come from a parameter.
- if (ActiveTemplateInstantiations.empty() && !DefaultedAnyToId &&
- !IsInitCapture && !DeducedType.isNull() && DeducedType->isObjCIdType()) {
+ if (!inTemplateInstantiation() && !DefaultedAnyToId && !IsInitCapture &&
+ !DeducedType.isNull() && DeducedType->isObjCIdType()) {
SourceLocation Loc = TSI->getTypeLoc().getBeginLoc();
Diag(Loc, diag::warn_auto_var_is_id) << VN << Range;
}
@@ -9793,6 +10203,36 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
return DeducedType;
}
+bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
+ Expr *Init) {
+ QualType DeducedType = deduceVarTypeFromInitializer(
+ VDecl, VDecl->getDeclName(), VDecl->getType(), VDecl->getTypeSourceInfo(),
+ VDecl->getSourceRange(), DirectInit, Init);
+ if (DeducedType.isNull()) {
+ VDecl->setInvalidDecl();
+ return true;
+ }
+
+ VDecl->setType(DeducedType);
+ assert(VDecl->isLinkageValid());
+
+ // In ARC, infer lifetime.
+ if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
+ VDecl->setInvalidDecl();
+
+ // If this is a redeclaration, check that the type we just deduced matches
+ // the previously declared type.
+ if (VarDecl *Old = VDecl->getPreviousDecl()) {
+ // We never need to merge the type, because we cannot form an incomplete
+ // array of auto, nor deduce such a type.
+ MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/ false);
+ }
+
+ // Check the deduced type is valid for a variable declaration.
+ CheckVariableDeclarationType(VDecl);
+ return VDecl->isInvalidDecl();
+}
+
/// AddInitializerToDecl - Adds the initializer Init to the
/// declaration dcl. If DirectInit is true, this is C++ direct
/// initialization rather than copy initialization.
@@ -9832,32 +10272,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
}
Init = Res.get();
- QualType DeducedType = deduceVarTypeFromInitializer(
- VDecl, VDecl->getDeclName(), VDecl->getType(),
- VDecl->getTypeSourceInfo(), VDecl->getSourceRange(), DirectInit, Init);
- if (DeducedType.isNull()) {
- RealDecl->setInvalidDecl();
- return;
- }
-
- VDecl->setType(DeducedType);
- assert(VDecl->isLinkageValid());
-
- // In ARC, infer lifetime.
- if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
- VDecl->setInvalidDecl();
-
- // If this is a redeclaration, check that the type we just deduced matches
- // the previously declared type.
- if (VarDecl *Old = VDecl->getPreviousDecl()) {
- // We never need to merge the type, because we cannot form an incomplete
- // array of auto, nor deduce such a type.
- MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/ false);
- }
-
- // Check the deduced type is valid for a variable declaration.
- CheckVariableDeclarationType(VDecl);
- if (VDecl->isInvalidDecl())
+ if (DeduceVariableDeclarationType(VDecl, DirectInit, Init))
return;
}
@@ -9963,28 +10378,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// Perform the initialization.
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
if (!VDecl->isInvalidDecl()) {
- // Handle errors like: int a({0})
- if (CXXDirectInit && CXXDirectInit->getNumExprs() == 1 &&
- !canInitializeWithParenthesizedList(VDecl->getType()))
- if (auto IList = dyn_cast<InitListExpr>(CXXDirectInit->getExpr(0))) {
- Diag(VDecl->getLocation(), diag::err_list_init_in_parens)
- << VDecl->getType() << CXXDirectInit->getSourceRange()
- << FixItHint::CreateRemoval(CXXDirectInit->getLocStart())
- << FixItHint::CreateRemoval(CXXDirectInit->getLocEnd());
- Init = IList;
- CXXDirectInit = nullptr;
- }
-
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
- InitializationKind Kind =
- DirectInit
- ? CXXDirectInit
- ? InitializationKind::CreateDirect(VDecl->getLocation(),
- Init->getLocStart(),
- Init->getLocEnd())
- : InitializationKind::CreateDirectList(VDecl->getLocation())
- : InitializationKind::CreateCopy(VDecl->getLocation(),
- Init->getLocStart());
+ InitializationKind Kind = InitializationKind::CreateForInit(
+ VDecl->getLocation(), DirectInit, Init);
MultiExprArg Args = Init;
if (CXXDirectInit)
@@ -10047,7 +10443,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// we do not warn to warn spuriously when 'x' and 'y' are on separate
// paths through the function. This should be revisited if
// -Wrepeated-use-of-weak is made flow-sensitive.
- if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong &&
+ if ((VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong ||
+ VDecl->getType().isNonWeakInMRRWithObjCWeak(Context)) &&
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak,
Init->getLocStart()))
getCurFunction()->markSafeWeakUse(Init);
@@ -10077,23 +10474,36 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
VDecl->setInit(Init);
if (VDecl->isLocalVarDecl()) {
+ // Don't check the initializer if the declaration is malformed.
+ if (VDecl->isInvalidDecl()) {
+ // do nothing
+
+ // OpenCL v1.2 s6.5.3: __constant locals must be constant-initialized.
+ // This is true even in OpenCL C++.
+ } else if (VDecl->getType().getAddressSpace() == LangAS::opencl_constant) {
+ CheckForConstantInitializer(Init, DclT);
+
+ // Otherwise, C++ does not restrict the initializer.
+ } else if (getLangOpts().CPlusPlus) {
+ // do nothing
+
// C99 6.7.8p4: All the expressions in an initializer for an object that has
// static storage duration shall be constant expressions or string literals.
- // C++ does not have this restriction.
- if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) {
+ } else if (VDecl->getStorageClass() == SC_Static) {
+ CheckForConstantInitializer(Init, DclT);
+
+ // C89 is stricter than C99 for aggregate initializers.
+ // C89 6.5.7p3: All the expressions [...] in an initializer list
+ // for an object that has aggregate or union type shall be
+ // constant expressions.
+ } else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() &&
+ isa<InitListExpr>(Init)) {
const Expr *Culprit;
- if (VDecl->getStorageClass() == SC_Static)
- CheckForConstantInitializer(Init, DclT);
- // C89 is stricter than C99 for non-static aggregate types.
- // C89 6.5.7p3: All the expressions [...] in an initializer list
- // for an object that has aggregate or union type shall be
- // constant expressions.
- else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() &&
- isa<InitListExpr>(Init) &&
- !Init->isConstantInitializer(Context, false, &Culprit))
+ if (!Init->isConstantInitializer(Context, false, &Culprit)) {
Diag(Culprit->getExprLoc(),
diag::ext_aggregate_init_not_constant)
<< Culprit->getSourceRange();
+ }
}
} else if (VDecl->isStaticDataMember() && !VDecl->isInline() &&
VDecl->getLexicalDeclContext()->isRecord()) {
@@ -10111,7 +10521,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// C++11 [class.static.data]p3:
// If a non-volatile non-inline const static data member is of integral
// or enumeration type, its declaration in the class definition can
- // specify a brace-or-equal-initializer in which every initalizer-clause
+ // specify a brace-or-equal-initializer in which every initializer-clause
// that is an assignment-expression is a constant expression. A static
// data member of literal type can be declared in the class definition
// with the constexpr specifier; if so, its declaration shall specify a
@@ -10281,18 +10691,6 @@ void Sema::ActOnInitializerError(Decl *D) {
// though.
}
-/// Checks if an object of the given type can be initialized with parenthesized
-/// init-list.
-///
-/// \param TargetType Type of object being initialized.
-///
-/// The function is used to detect wrong initializations, such as 'int({0})'.
-///
-bool Sema::canInitializeWithParenthesizedList(QualType TargetType) {
- return TargetType->isDependentType() || TargetType->isRecordType() ||
- TargetType->getContainedAutoType();
-}
-
void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
// If there is no declaration, there was an error parsing it. Just ignore it.
if (!RealDecl)
@@ -10308,13 +10706,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
return;
}
- // C++11 [dcl.spec.auto]p3
- if (Type->isUndeducedType()) {
- Diag(Var->getLocation(), diag::err_auto_var_requires_init)
- << Var->getDeclName() << Type;
- Var->setInvalidDecl();
+ if (Type->isUndeducedType() &&
+ DeduceVariableDeclarationType(Var, false, nullptr))
return;
- }
// C++11 [class.static.data]p3: A static data member can be declared with
// the constexpr specifier; if so, its declaration shall specify
@@ -10693,7 +11087,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Apply section attributes and pragmas to global variables.
bool GlobalStorage = var->hasGlobalStorage();
if (GlobalStorage && var->isThisDeclarationADefinition() &&
- ActiveTemplateInstantiations.empty()) {
+ !inTemplateInstantiation()) {
PragmaStack<StringLiteral *> *Stack = nullptr;
int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read;
if (var->getType().isConstQualified())
@@ -10745,7 +11139,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Regardless, we don't want to ignore array nesting when
// constructing this copy.
if (type->isStructureOrClassType()) {
- EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
+ EnterExpressionEvaluationContext scope(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated);
SourceLocation poi = var->getLocation();
Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi);
ExprResult result
@@ -10764,9 +11159,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
bool IsGlobal = GlobalStorage && !var->isStaticLocal();
QualType baseType = Context.getBaseElementType(type);
- if (!var->getDeclContext()->isDependentContext() &&
- Init && !Init->isValueDependent()) {
-
+ if (Init && !Init->isValueDependent()) {
if (var->isConstexpr()) {
SmallVector<PartialDiagnosticAt, 8> Notes;
if (!var->evaluateValue(Notes) || !var->isInitICE()) {
@@ -10803,6 +11196,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
<< Init->getSourceRange();
Diag(attr->getLocation(), diag::note_declared_required_constant_init_here)
<< attr->getRange();
+ if (getLangOpts().CPlusPlus11) {
+ APValue Value;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
+ Init->EvaluateAsInitializer(Value, getASTContext(), var, Notes);
+ for (auto &it : Notes)
+ Diag(it.first, it.second);
+ } else {
+ Diag(CacheCulprit->getExprLoc(),
+ diag::note_invalid_subexpr_in_const_expr)
+ << CacheCulprit->getSourceRange();
+ }
}
}
else if (!var->isConstexpr() && IsGlobal &&
@@ -10842,8 +11246,7 @@ static bool hasDependentAlignment(VarDecl *VD) {
/// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform
/// any semantic actions necessary after any initializer has been attached.
-void
-Sema::FinalizeDeclaration(Decl *ThisDecl) {
+void Sema::FinalizeDeclaration(Decl *ThisDecl) {
// Note that we are no longer parsing the initializer for this declaration.
ParsingInitForAutoVars.erase(ThisDecl);
@@ -10851,6 +11254,23 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (!VD)
return;
+ // Apply an implicit SectionAttr if '#pragma clang section bss|data|rodata' is active
+ if (VD->hasGlobalStorage() && VD->isThisDeclarationADefinition() &&
+ !inTemplateInstantiation() && !VD->hasAttr<SectionAttr>()) {
+ if (PragmaClangBSSSection.Valid)
+ VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit(Context,
+ PragmaClangBSSSection.SectionName,
+ PragmaClangBSSSection.PragmaLocation));
+ if (PragmaClangDataSection.Valid)
+ VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit(Context,
+ PragmaClangDataSection.SectionName,
+ PragmaClangDataSection.PragmaLocation));
+ if (PragmaClangRodataSection.Valid)
+ VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit(Context,
+ PragmaClangRodataSection.SectionName,
+ PragmaClangRodataSection.PragmaLocation));
+ }
+
if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) {
for (auto *BD : DD->bindings()) {
FinalizeDeclaration(BD);
@@ -10865,7 +11285,8 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
// Protect the check so that it's not performed on dependent types and
// dependent alignments (we can't determine the alignment in that case).
- if (VD->getTLSKind() && !hasDependentAlignment(VD)) {
+ if (VD->getTLSKind() && !hasDependentAlignment(VD) &&
+ !VD->isInvalidDecl()) {
CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign);
if (Context.getDeclAlign(VD) > MaxAlignChars) {
Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
@@ -11007,9 +11428,8 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (DC->getRedeclContext()->isFileContext() && VD->isExternallyVisible())
AddPushedVisibilityAttribute(VD);
- // FIXME: Warn on unused templates.
- if (VD->isFileVarDecl() && !VD->getDescribedVarTemplate() &&
- !isa<VarTemplatePartialSpecializationDecl>(VD))
+ // FIXME: Warn on unused var template partial specializations.
+ if (VD->isFileVarDecl() && !isa<VarTemplatePartialSpecializationDecl>(VD))
MarkUnusedFileScopedDecl(VD);
// Now we have parsed the initializer and can update the table of magic
@@ -11045,6 +11465,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
}
}
+static bool hasDeducedAuto(DeclaratorDecl *DD) {
+ auto *VD = dyn_cast<VarDecl>(DD);
+ return VD && !VD->getType()->hasAutoForTrailingReturnType();
+}
+
Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
ArrayRef<Decl *> Group) {
SmallVector<Decl*, 8> Decls;
@@ -11055,29 +11480,46 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
DeclaratorDecl *FirstDeclaratorInGroup = nullptr;
DecompositionDecl *FirstDecompDeclaratorInGroup = nullptr;
bool DiagnosedMultipleDecomps = false;
+ DeclaratorDecl *FirstNonDeducedAutoInGroup = nullptr;
+ bool DiagnosedNonDeducedAuto = false;
for (unsigned i = 0, e = Group.size(); i != e; ++i) {
if (Decl *D = Group[i]) {
- auto *DD = dyn_cast<DeclaratorDecl>(D);
- if (DD && !FirstDeclaratorInGroup)
- FirstDeclaratorInGroup = DD;
-
- auto *Decomp = dyn_cast<DecompositionDecl>(D);
- if (Decomp && !FirstDecompDeclaratorInGroup)
- FirstDecompDeclaratorInGroup = Decomp;
-
- // A decomposition declaration cannot be combined with any other
- // declaration in the same group.
- auto *OtherDD = FirstDeclaratorInGroup;
- if (OtherDD == FirstDecompDeclaratorInGroup)
- OtherDD = DD;
- if (OtherDD && FirstDecompDeclaratorInGroup &&
- OtherDD != FirstDecompDeclaratorInGroup &&
- !DiagnosedMultipleDecomps) {
- Diag(FirstDecompDeclaratorInGroup->getLocation(),
- diag::err_decomp_decl_not_alone)
- << OtherDD->getSourceRange();
- DiagnosedMultipleDecomps = true;
+ // For declarators, there are some additional syntactic-ish checks we need
+ // to perform.
+ if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (!FirstDeclaratorInGroup)
+ FirstDeclaratorInGroup = DD;
+ if (!FirstDecompDeclaratorInGroup)
+ FirstDecompDeclaratorInGroup = dyn_cast<DecompositionDecl>(D);
+ if (!FirstNonDeducedAutoInGroup && DS.hasAutoTypeSpec() &&
+ !hasDeducedAuto(DD))
+ FirstNonDeducedAutoInGroup = DD;
+
+ if (FirstDeclaratorInGroup != DD) {
+ // A decomposition declaration cannot be combined with any other
+ // declaration in the same group.
+ if (FirstDecompDeclaratorInGroup && !DiagnosedMultipleDecomps) {
+ Diag(FirstDecompDeclaratorInGroup->getLocation(),
+ diag::err_decomp_decl_not_alone)
+ << FirstDeclaratorInGroup->getSourceRange()
+ << DD->getSourceRange();
+ DiagnosedMultipleDecomps = true;
+ }
+
+ // A declarator that uses 'auto' in any way other than to declare a
+ // variable with a deduced type cannot be combined with any other
+ // declarator in the same group.
+ if (FirstNonDeducedAutoInGroup && !DiagnosedNonDeducedAuto) {
+ Diag(FirstNonDeducedAutoInGroup->getLocation(),
+ diag::err_auto_non_deduced_not_alone)
+ << FirstNonDeducedAutoInGroup->getType()
+ ->hasAutoForTrailingReturnType()
+ << FirstDeclaratorInGroup->getSourceRange()
+ << DD->getSourceRange();
+ DiagnosedNonDeducedAuto = true;
+ }
+ }
}
Decls.push_back(D);
@@ -11105,38 +11547,28 @@ Sema::BuildDeclaratorGroup(MutableArrayRef<Decl *> Group) {
// deduction, the program is ill-formed.
if (Group.size() > 1) {
QualType Deduced;
- CanQualType DeducedCanon;
VarDecl *DeducedDecl = nullptr;
for (unsigned i = 0, e = Group.size(); i != e; ++i) {
- if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) {
- AutoType *AT = D->getType()->getContainedAutoType();
- // FIXME: DR1265: if we have a function pointer declaration, we can have
- // an 'auto' from a trailing return type. In that case, the return type
- // must match the various other uses of 'auto'.
- if (!AT)
- continue;
- // Don't reissue diagnostics when instantiating a template.
- if (D->isInvalidDecl())
- break;
- QualType U = AT->getDeducedType();
- if (!U.isNull()) {
- CanQualType UCanon = Context.getCanonicalType(U);
- if (Deduced.isNull()) {
- Deduced = U;
- DeducedCanon = UCanon;
- DeducedDecl = D;
- } else if (DeducedCanon != UCanon) {
- Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
- diag::err_auto_different_deductions)
- << (unsigned)AT->getKeyword()
- << Deduced << DeducedDecl->getDeclName()
- << U << D->getDeclName()
- << DeducedDecl->getInit()->getSourceRange()
- << D->getInit()->getSourceRange();
- D->setInvalidDecl();
- break;
- }
- }
+ VarDecl *D = dyn_cast<VarDecl>(Group[i]);
+ if (!D || D->isInvalidDecl())
+ break;
+ DeducedType *DT = D->getType()->getContainedDeducedType();
+ if (!DT || DT->getDeducedType().isNull())
+ continue;
+ if (Deduced.isNull()) {
+ Deduced = DT->getDeducedType();
+ DeducedDecl = D;
+ } else if (!Context.hasSameType(DT->getDeducedType(), Deduced)) {
+ auto *AT = dyn_cast<AutoType>(DT);
+ Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+ diag::err_auto_different_deductions)
+ << (AT ? (unsigned)AT->getKeyword() : 3)
+ << Deduced << DeducedDecl->getDeclName()
+ << DT->getDeducedType() << D->getDeclName()
+ << DeducedDecl->getInit()->getSourceRange()
+ << D->getInit()->getSourceRange();
+ D->setInvalidDecl();
+ break;
}
}
}
@@ -11331,7 +11763,7 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC,
void Sema::DiagnoseUnusedParameters(ArrayRef<ParmVarDecl *> Parameters) {
// Don't diagnose unused-parameter errors in template instantiations; we
// will already have done so in the template itself.
- if (!ActiveTemplateInstantiations.empty())
+ if (inTemplateInstantiation())
return;
for (const ParmVarDecl *Parameter : Parameters) {
@@ -11549,8 +11981,6 @@ void
Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
const FunctionDecl *EffectiveDefinition,
SkipBodyInfo *SkipBody) {
- // Don't complain if we're in GNU89 mode and the previous definition
- // was an extern inline function.
const FunctionDecl *Definition = EffectiveDefinition;
if (!Definition)
if (!FD->isDefined(Definition))
@@ -11559,6 +11989,11 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
if (canRedefineFunction(Definition, getLangOpts()))
return;
+ // Don't emit an error when this is redefinition of a typo-corrected
+ // definition.
+ if (TypoCorrectedFunctionDefinitions.count(Definition))
+ return;
+
// If we don't have a visible definition of the function, and it's inline or
// a template, skip the new definition.
if (SkipBody && !hasVisibleDefinition(Definition) &&
@@ -11568,9 +12003,8 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
Definition->getNumTemplateParameterLists())) {
SkipBody->ShouldSkip = true;
if (auto *TD = Definition->getDescribedFunctionTemplate())
- makeMergedDefinitionVisible(TD, FD->getLocation());
- makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition),
- FD->getLocation());
+ makeMergedDefinitionVisible(TD);
+ makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition));
return;
}
@@ -11635,9 +12069,6 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
SkipBodyInfo *SkipBody) {
- // Clear the last template instantiation error context.
- LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation();
-
if (!D)
return D;
FunctionDecl *FD = nullptr;
@@ -11647,8 +12078,21 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
else
FD = cast<FunctionDecl>(D);
- // See if this is a redefinition.
- if (!FD->isLateTemplateParsed()) {
+ // Check for defining attributes before the check for redefinition.
+ if (const auto *Attr = FD->getAttr<AliasAttr>()) {
+ Diag(Attr->getLocation(), diag::err_alias_is_definition) << FD << 0;
+ FD->dropAttr<AliasAttr>();
+ FD->setInvalidDecl();
+ }
+ if (const auto *Attr = FD->getAttr<IFuncAttr>()) {
+ Diag(Attr->getLocation(), diag::err_alias_is_definition) << FD << 1;
+ FD->dropAttr<IFuncAttr>();
+ FD->setInvalidDecl();
+ }
+
+ // See if this is a redefinition. If 'will have body' is already set, then
+ // these checks were already performed when it was set.
+ if (!FD->willHaveBody() && !FD->isLateTemplateParsed()) {
CheckForFunctionRedefinition(FD, nullptr, SkipBody);
// If we're skipping the body, we're done. Don't enter the scope.
@@ -11671,14 +12115,14 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
// captures during transformation of nested lambdas, it is necessary to
// have the LSI properly restored.
if (isGenericLambdaCallOperatorSpecialization(FD)) {
- assert(ActiveTemplateInstantiations.size() &&
- "There should be an active template instantiation on the stack "
- "when instantiating a generic lambda!");
+ assert(inTemplateInstantiation() &&
+ "There should be an active template instantiation on the stack "
+ "when instantiating a generic lambda!");
RebuildLambdaScopeInfo(cast<CXXMethodDecl>(D), *this);
- }
- else
+ } else {
// Enter a new function scope
PushFunctionScope();
+ }
// Builtin functions cannot be defined.
if (unsigned BuiltinID = FD->getBuiltinID()) {
@@ -11793,7 +12237,7 @@ bool Sema::canDelayFunctionBody(const Declarator &D) {
// We can't delay parsing the body of a function template with a deduced
// return type (yet).
- if (D.getDeclSpec().containsPlaceholderType()) {
+ if (D.getDeclSpec().hasAutoTypeSpec()) {
// If the placeholder introduces a non-deduced trailing return type,
// we can still delay parsing it.
if (D.getNumTypeObjects()) {
@@ -11841,11 +12285,12 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
- if (getLangOpts().CoroutinesTS && !getCurFunction()->CoroutineStmts.empty())
+ if (getLangOpts().CoroutinesTS && getCurFunction()->isCoroutine())
CheckCompletedCoroutineBody(FD, Body);
if (FD) {
FD->setBody(Body);
+ FD->setWillHaveBody(false);
if (getLangOpts().CPlusPlus14) {
if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&
@@ -11962,8 +12407,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
!LangOpts.CPlusPlus) {
TypeSourceInfo *TI = FD->getTypeSourceInfo();
TypeLoc TL = TI->getTypeLoc();
- FunctionTypeLoc FTL = TL.castAs<FunctionTypeLoc>();
- Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 1;
+ FunctionTypeLoc FTL = TL.getAsAdjusted<FunctionTypeLoc>();
+ Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 2;
}
}
@@ -12174,6 +12619,9 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
unsigned diag_id;
if (II.getName().startswith("__builtin_"))
diag_id = diag::warn_builtin_unknown;
+ // OpenCL v2.0 s6.9.u - Implicit function declaration is not supported.
+ else if (getLangOpts().OpenCL)
+ diag_id = diag::err_opencl_implicit_function_decl;
else if (getLangOpts().C99)
diag_id = diag::ext_implicit_function_decl;
else
@@ -12555,7 +13003,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
isTemplate = Record->getDescribedClassTemplate();
- if (!ActiveTemplateInstantiations.empty()) {
+ if (inTemplateInstantiation()) {
// In a template instantiation, do not offer fix-its for tag mismatches
// since they usually mess up the template instead of fixing the problem.
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
@@ -12700,7 +13148,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag,
TypeResult UnderlyingType,
- bool IsTypeSpecifier, SkipBodyInfo *SkipBody) {
+ bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+ SkipBodyInfo *SkipBody) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -12711,8 +13160,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
bool ScopedEnum = ScopedEnumKWLoc.isValid();
- // FIXME: Check explicit specializations more carefully.
- bool isExplicitSpecialization = false;
+ // FIXME: Check member specializations more carefully.
+ bool isMemberSpecialization = false;
bool Invalid = false;
// We only need to do this matching if we have template parameters
@@ -12723,7 +13172,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
KWLoc, NameLoc, SS, nullptr, TemplateParameterLists,
- TUK == TUK_Friend, isExplicitSpecialization, Invalid)) {
+ TUK == TUK_Friend, isMemberSpecialization, Invalid)) {
if (Kind == TTK_Enum) {
Diag(KWLoc, diag::err_enum_template);
return nullptr;
@@ -12750,7 +13199,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
<< TypeWithKeyword::getTagTypeKindName(Kind) << Name;
- isExplicitSpecialization = true;
+ isMemberSpecialization = true;
}
}
}
@@ -12799,6 +13248,56 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (TUK == TUK_Friend || TUK == TUK_Reference)
Redecl = NotForRedeclaration;
+ /// Create a new tag decl in C/ObjC. Since the ODR-like semantics for ObjC/C
+ /// implemented asks for structural equivalence checking, the returned decl
+ /// here is passed back to the parser, allowing the tag body to be parsed.
+ auto createTagFromNewDecl = [&]() -> TagDecl * {
+ assert(!getLangOpts().CPlusPlus && "not meant for C++ usage");
+ // If there is an identifier, use the location of the identifier as the
+ // location of the decl, otherwise use the location of the struct/union
+ // keyword.
+ SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc;
+ TagDecl *New = nullptr;
+
+ if (Kind == TTK_Enum) {
+ New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, nullptr,
+ ScopedEnum, ScopedEnumUsesClassTag,
+ !EnumUnderlying.isNull());
+ // If this is an undefined enum, bail.
+ if (TUK != TUK_Definition && !Invalid)
+ return nullptr;
+ if (EnumUnderlying) {
+ EnumDecl *ED = cast<EnumDecl>(New);
+ if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo *>())
+ ED->setIntegerTypeSourceInfo(TI);
+ else
+ ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0));
+ ED->setPromotionType(ED->getIntegerType());
+ }
+ } else { // struct/union
+ New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name,
+ nullptr);
+ }
+
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(New)) {
+ // Add alignment attributes if necessary; these attributes are checked
+ // when the ASTContext lays out the structure.
+ //
+ // It is important for implementing the correct semantics that this
+ // happen here (in ActOnTag). The #pragma pack stack is
+ // maintained as a result of parser callbacks which can occur at
+ // many points during the parsing of a struct declaration (because
+ // the #pragma tokens are effectively skipped over during the
+ // parsing of the struct).
+ if (TUK == TUK_Definition) {
+ AddAlignmentAttributesForRecord(RD);
+ AddMsStructLayoutForRecord(RD);
+ }
+ }
+ New->setLexicalDeclContext(CurContext);
+ return New;
+ };
+
LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl);
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
@@ -12970,11 +13469,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// also need to do a redeclaration lookup there, just in case
// there's a shadow friend decl.
if (Name && Previous.empty() &&
- (TUK == TUK_Reference || TUK == TUK_Friend)) {
+ (TUK == TUK_Reference || TUK == TUK_Friend || IsTemplateParamOrArg)) {
if (Invalid) goto CreateNewDecl;
assert(SS.isEmpty());
- if (TUK == TUK_Reference) {
+ if (TUK == TUK_Reference || IsTemplateParamOrArg) {
// C++ [basic.scope.pdecl]p5:
// -- for an elaborated-type-specifier of the form
//
@@ -13070,7 +13569,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (auto *Shadow = dyn_cast<UsingShadowDecl>(DirectPrevDecl)) {
auto *OldTag = dyn_cast<TagDecl>(PrevDecl);
if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend &&
- isDeclInScope(Shadow, SearchDC, S, isExplicitSpecialization) &&
+ isDeclInScope(Shadow, SearchDC, S, isMemberSpecialization) &&
!(OldTag && isAcceptableTagRedeclContext(
*this, OldTag->getDeclContext(), SearchDC))) {
Diag(KWLoc, diag::err_using_decl_conflict_reverse);
@@ -13090,7 +13589,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// rementions the tag), reuse the decl.
if (TUK == TUK_Reference || TUK == TUK_Friend ||
isDeclInScope(DirectPrevDecl, SearchDC, S,
- SS.isNotEmpty() || isExplicitSpecialization)) {
+ SS.isNotEmpty() || isMemberSpecialization)) {
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind,
@@ -13166,9 +13665,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
} else if (TUK == TUK_Reference &&
(PrevTagDecl->getFriendObjectKind() ==
Decl::FOK_Undeclared ||
- PP.getModuleContainingLocation(
- PrevDecl->getLocation()) !=
- PP.getModuleContainingLocation(KWLoc)) &&
+ PrevDecl->getOwningModule() != getCurrentModule()) &&
SS.isEmpty()) {
// This declaration is a reference to an existing entity, but
// has different visibility from that entity: it either makes
@@ -13195,7 +13692,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// is from an implicit instantiation, don't emit an error
// here; we'll catch this in the general case below.
bool IsExplicitSpecializationAfterInstantiation = false;
- if (isExplicitSpecialization) {
+ if (isMemberSpecialization) {
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Def))
IsExplicitSpecializationAfterInstantiation =
RD->getTemplateSpecializationKind() !=
@@ -13206,16 +13703,28 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
TSK_ExplicitSpecialization;
}
+ // Note that clang allows ODR-like semantics for ObjC/C, i.e., do
+ // not keep more that one definition around (merge them). However,
+ // ensure the decl passes the structural compatibility check in
+ // C11 6.2.7/1 (or 6.1.2.6/1 in C89).
NamedDecl *Hidden = nullptr;
- if (SkipBody && getLangOpts().CPlusPlus &&
- !hasVisibleDefinition(Def, &Hidden)) {
+ if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
// There is a definition of this tag, but it is not visible. We
// explicitly make use of C++'s one definition rule here, and
// assume that this definition is identical to the hidden one
// we already have. Make the existing definition visible and
// use it in place of this one.
- SkipBody->ShouldSkip = true;
- makeMergedDefinitionVisible(Hidden, KWLoc);
+ if (!getLangOpts().CPlusPlus) {
+ // Postpone making the old definition visible until after we
+ // complete parsing the new one and do the structural
+ // comparison.
+ SkipBody->CheckSameAsPrevious = true;
+ SkipBody->New = createTagFromNewDecl();
+ SkipBody->Previous = Hidden;
+ } else {
+ SkipBody->ShouldSkip = true;
+ makeMergedDefinitionVisible(Hidden);
+ }
return Def;
} else if (!IsExplicitSpecializationAfterInstantiation) {
// A redeclaration in function prototype scope in C isn't
@@ -13224,7 +13733,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Diag(NameLoc, diag::warn_redefinition_in_param_list) << Name;
else
Diag(NameLoc, diag::err_redefinition) << Name;
- Diag(Def->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Def,
+ NameLoc.isValid() ? NameLoc : KWLoc);
// If this is a redefinition, recover by making this
// struct be anonymous, which will make any later
// references get the previous definition.
@@ -13289,7 +13799,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Otherwise, only diagnose if the declaration is in scope.
} else if (!isDeclInScope(DirectPrevDecl, SearchDC, S,
- SS.isNotEmpty() || isExplicitSpecialization)) {
+ SS.isNotEmpty() || isMemberSpecialization)) {
// do nothing
// Diagnose implicit declarations introduced by elaborated types.
@@ -13314,7 +13824,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// The tag name clashes with something else in the target scope,
// issue an error and recover by making this tag be anonymous.
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(PrevDecl, NameLoc);
Name = nullptr;
Invalid = true;
}
@@ -13355,7 +13865,8 @@ CreateNewDecl:
// If this is an undefined enum, warn.
if (TUK != TUK_Definition && !Invalid) {
TagDecl *Def;
- if ((getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) &&
+ if (!EnumUnderlyingIsImplicit &&
+ (getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) &&
cast<EnumDecl>(New)->isFixed()) {
// C++0x: 7.2p2: opaque-enum-declaration.
// Conflicts are diagnosed above. Do nothing.
@@ -13407,7 +13918,8 @@ CreateNewDecl:
// C++11 [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration [...].
- if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) {
+ if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) &&
+ TUK == TUK_Definition) {
Diag(New->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTagDeclType(New);
Invalid = true;
@@ -13421,7 +13933,7 @@ CreateNewDecl:
// for explicit specializations, because they have similar checking
// (with more specific diagnostics) in the call to
// CheckMemberSpecialization, below.
- if (!isExplicitSpecialization &&
+ if (!isMemberSpecialization &&
(TUK == TUK_Definition || TUK == TUK_Declaration) &&
diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc))
Invalid = true;
@@ -13440,7 +13952,7 @@ CreateNewDecl:
// the ASTContext lays out the structure.
//
// It is important for implementing the correct semantics that this
- // happen here (in act on tag decl). The #pragma pack stack is
+ // happen here (in ActOnTag). The #pragma pack stack is
// maintained as a result of parser callbacks which can occur at
// many points during the parsing of a struct declaration (because
// the #pragma tokens are effectively skipped over during the
@@ -13452,7 +13964,7 @@ CreateNewDecl:
}
if (ModulePrivateLoc.isValid()) {
- if (isExplicitSpecialization)
+ if (isMemberSpecialization)
Diag(New->getLocation(), diag::err_module_private_specialization)
<< 2
<< FixItHint::CreateRemoval(ModulePrivateLoc);
@@ -13465,7 +13977,7 @@ CreateNewDecl:
// If this is a specialization of a member class (of a class template),
// check the specialization.
- if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
+ if (isMemberSpecialization && CheckMemberSpecialization(New, Previous))
Invalid = true;
// If we're declaring or defining a tag in function prototype scope in C,
@@ -13489,9 +14001,6 @@ CreateNewDecl:
if (Invalid)
New->setInvalidDecl();
- if (Attr)
- ProcessDeclAttributeList(S, New, Attr);
-
// Set the lexical context. If the tag has a C++ scope specifier, the
// lexical context will be different from the semantic context.
New->setLexicalDeclContext(CurContext);
@@ -13510,6 +14019,10 @@ CreateNewDecl:
if (TUK == TUK_Definition)
New->startDefinition();
+ if (Attr)
+ ProcessDeclAttributeList(S, New, Attr);
+ AddPragmaAttributes(S, New);
+
// If this has an identifier, add it to the scope stack.
if (TUK == TUK_Friend) {
// We might be replacing an existing declaration in the lookup tables;
@@ -13545,6 +14058,9 @@ CreateNewDecl:
// record.
AddPushedVisibilityAttribute(New);
+ if (isMemberSpecialization && !New->isInvalidDecl())
+ CompleteMemberSpecialization(New, Previous);
+
OwnedDecl = true;
// In C++, don't return an invalid declaration. We can't recover well from
// the cases where we make the type anonymous.
@@ -13572,6 +14088,16 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
AddPushedVisibilityAttribute(Tag);
}
+bool Sema::ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev,
+ SkipBodyInfo &SkipBody) {
+ if (!hasStructuralCompatLayout(Prev, SkipBody.New))
+ return false;
+
+ // Make the previous decl visible.
+ makeMergedDefinitionVisible(SkipBody.Previous);
+ return true;
+}
+
Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
assert(isa<ObjCContainerDecl>(IDecl) &&
"ActOnObjCContainerStartDefinition - Not ObjCContainerDecl");
@@ -13632,8 +14158,9 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
RD->completeDefinition();
}
- if (isa<CXXRecordDecl>(Tag))
+ if (isa<CXXRecordDecl>(Tag)) {
FieldCollector->FinishClass();
+ }
// Exit this scope of this tag's definition.
PopDeclContext();
@@ -14340,7 +14867,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// Verify that all the fields are okay.
SmallVector<FieldDecl*, 32> RecFields;
- bool ARCErrReported = false;
+ bool ObjCFieldLifetimeErrReported = false;
for (ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end();
i != end; ++i) {
FieldDecl *FD = cast<FieldDecl>(*i);
@@ -14475,16 +15002,16 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
<< FixItHint::CreateInsertion(FD->getLocation(), "*");
QualType T = Context.getObjCObjectPointerType(FD->getType());
FD->setType(T);
- } else if (getLangOpts().ObjCAutoRefCount && Record && !ARCErrReported &&
+ } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
+ Record && !ObjCFieldLifetimeErrReported &&
(!getLangOpts().CPlusPlus || Record->isUnion())) {
- // It's an error in ARC if a field has lifetime.
+ // It's an error in ARC or Weak if a field has lifetime.
// We don't want to report this in a system header, though,
// so we just make the field unavailable.
// FIXME: that's really not sufficient; we need to make the type
// itself invalid to, say, initialize or copy.
QualType T = FD->getType();
- Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime();
- if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) {
+ if (T.hasNonTrivialObjCLifetime()) {
SourceLocation loc = FD->getLocation();
if (getSourceManager().isInSystemHeader(loc)) {
if (!FD->hasAttr<UnavailableAttr>()) {
@@ -14495,7 +15022,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag)
<< T->isBlockPointerType() << Record->getTagKind();
}
- ARCErrReported = true;
+ ObjCFieldLifetimeErrReported = true;
}
} else if (getLangOpts().ObjC1 &&
getLangOpts().getGC() != LangOptions::NonGC &&
@@ -14992,7 +15519,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// different from T:
// - every enumerator of every member of class T that is an unscoped
// enumerated type
- if (!TheEnumDecl->isScoped())
+ if (getLangOpts().CPlusPlus && !TheEnumDecl->isScoped())
DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(),
DeclarationNameInfo(Id, IdLoc));
@@ -15012,13 +15539,14 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id;
else
Diag(IdLoc, diag::err_redefinition) << Id;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(PrevDecl, IdLoc);
return nullptr;
}
}
// Process attributes.
if (Attr) ProcessDeclAttributeList(S, New, Attr);
+ AddPragmaAttributes(S, New);
// Register this decl in the current scope stack.
New->setAccess(TheEnumDecl->getAccess());
@@ -15207,7 +15735,7 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements,
bool Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
bool AllowMask) const {
- assert(ED->hasAttr<FlagEnumAttr>() && "looking for value in non-flag enum");
+ assert(ED->isClosedFlag() && "looking for value in non-flag or open enum");
assert(ED->isCompleteDefinition() && "expected enum definition");
auto R = FlagBitsCache.insert(std::make_pair(ED, llvm::APInt()));
@@ -15452,7 +15980,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
CheckForDuplicateEnumValues(*this, Elements, Enum, EnumType);
- if (Enum->hasAttr<FlagEnumAttr>()) {
+ if (Enum->isClosedFlag()) {
for (Decl *D : Elements) {
EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(D);
if (!ECD) continue; // Already issued a diagnostic.
@@ -15516,30 +16044,39 @@ static void checkModuleImportContext(Sema &S, Module *M,
}
}
-Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
+Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc,
+ SourceLocation ModuleLoc,
ModuleDeclKind MDK,
ModuleIdPath Path) {
- // 'module implementation' requires that we are not compiling a module of any
- // kind. 'module' and 'module partition' require that we are compiling a
- // module inteface (not a module map).
- auto CMK = getLangOpts().getCompilingModule();
- if (MDK == ModuleDeclKind::Implementation
- ? CMK != LangOptions::CMK_None
- : CMK != LangOptions::CMK_ModuleInterface) {
+ // A module implementation unit requires that we are not compiling a module
+ // of any kind. A module interface unit requires that we are not compiling a
+ // module map.
+ switch (getLangOpts().getCompilingModule()) {
+ case LangOptions::CMK_None:
+ // It's OK to compile a module interface as a normal translation unit.
+ break;
+
+ case LangOptions::CMK_ModuleInterface:
+ if (MDK != ModuleDeclKind::Implementation)
+ break;
+
+ // We were asked to compile a module interface unit but this is a module
+ // implementation unit. That indicates the 'export' is missing.
Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch)
- << (unsigned)MDK;
+ << FixItHint::CreateInsertion(ModuleLoc, "export ");
+ break;
+
+ case LangOptions::CMK_ModuleMap:
+ Diag(ModuleLoc, diag::err_module_decl_in_module_map_module);
return nullptr;
}
- // FIXME: Create a ModuleDecl and return it.
-
// FIXME: Most of this work should be done by the preprocessor rather than
- // here, in case we look ahead across something where the current
- // module matters (eg a #include).
+ // here, in order to support macro import.
- // The dots in a module name in the Modules TS are a lie. Unlike Clang's
- // hierarchical module map modules, the dots here are just another character
- // that can appear in a module name. Flatten down to the actual module name.
+ // Flatten the dots in a module name. Unlike Clang's hierarchical module map
+ // modules, the dots here are just another character that can appear in a
+ // module name.
std::string ModuleName;
for (auto &Piece : Path) {
if (!ModuleName.empty())
@@ -15547,6 +16084,8 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
ModuleName += Piece.first->getName();
}
+ // FIXME: If we've already seen a module-declaration, report an error.
+
// If a module name was explicitly specified on the command line, it must be
// correct.
if (!getLangOpts().CurrentModule.empty() &&
@@ -15559,13 +16098,14 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName;
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ Module *Mod;
switch (MDK) {
case ModuleDeclKind::Module: {
// FIXME: Check we're not in a submodule.
- // We can't have imported a definition of this module or parsed a module
- // map defining it already.
+ // We can't have parsed or imported a definition of this module or parsed a
+ // module map defining it already.
if (auto *M = Map.findModule(ModuleName)) {
Diag(Path[0].second, diag::err_module_redefinition) << ModuleName;
if (M->DefinitionLoc.isValid())
@@ -15577,12 +16117,9 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
}
// Create a Module for the module that we're defining.
- Module *Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
assert(Mod && "module creation should not fail");
-
- // Enter the semantic scope of the module.
- ActOnModuleBegin(ModuleLoc, Mod);
- return nullptr;
+ break;
}
case ModuleDeclKind::Partition:
@@ -15592,14 +16129,26 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc,
case ModuleDeclKind::Implementation:
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
PP.getIdentifierInfo(ModuleName), Path[0].second);
-
- DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, ModuleNameLoc);
- if (Import.isInvalid())
+ Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible,
+ /*IsIncludeDirective=*/false);
+ if (!Mod)
return nullptr;
- return ConvertDeclToDeclGroup(Import.get());
+ break;
}
- llvm_unreachable("unexpected module decl kind");
+ // Enter the semantic scope of the module.
+ ModuleScopes.push_back({});
+ ModuleScopes.back().Module = Mod;
+ ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
+ VisibleModules.setVisible(Mod, ModuleLoc);
+
+ // From now on, we have an owning module for all declarations we see.
+ // However, those declarations are module-private unless explicitly
+ // exported.
+ Context.getTranslationUnitDecl()->setLocalOwningModule(Mod);
+
+ // FIXME: Create a ModuleDecl.
+ return nullptr;
}
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
@@ -15691,9 +16240,22 @@ void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
VisibleModules.setVisible(Mod, DirectiveLoc);
+
+ // The enclosing context is now part of this module.
+ // FIXME: Consider creating a child DeclContext to hold the entities
+ // lexically within the module.
+ if (getLangOpts().trackLocalOwningModule()) {
+ for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
+ cast<Decl>(DC)->setModuleOwnershipKind(
+ getLangOpts().ModulesLocalVisibility
+ ? Decl::ModuleOwnershipKind::VisibleWhenImported
+ : Decl::ModuleOwnershipKind::Visible);
+ cast<Decl>(DC)->setLocalOwningModule(Mod);
+ }
+ }
}
-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
@@ -15705,19 +16267,39 @@ 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);
+
+ // Any further declarations are in whatever module we returned to.
+ if (getLangOpts().trackLocalOwningModule()) {
+ // The parser guarantees that this is the same context that we entered
+ // the module within.
+ for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
+ cast<Decl>(DC)->setLocalOwningModule(getCurrentModule());
+ if (!getCurrentModule())
+ cast<Decl>(DC)->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::Unowned);
+ }
+ }
}
void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
Module *Mod) {
// Bail if we're not allowed to implicitly import a module here.
- if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery)
+ if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery ||
+ VisibleModules.isVisible(Mod))
return;
// Create the implicit import declaration.
@@ -15739,6 +16321,12 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc);
// C++ Modules TS draft:
+ // An export-declaration shall appear in the purview of a module other than
+ // the global module.
+ if (ModuleScopes.empty() || !ModuleScopes.back().Module ||
+ ModuleScopes.back().Module->Kind != Module::ModuleInterfaceUnit)
+ Diag(ExportLoc, diag::err_export_not_in_module_interface);
+
// An export-declaration [...] shall not contain more than one
// export keyword.
//
@@ -15749,6 +16337,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
CurContext->addDecl(D);
PushDeclContext(S, D);
+ D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported);
return D;
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
index c6a5bc7..2a310bf 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
@@ -218,21 +218,45 @@ static bool checkAttributeAtMostNumArgs(Sema &S, const AttributeList &Attr,
std::greater<unsigned>());
}
+/// \brief A helper function to provide Attribute Location for the Attr types
+/// AND the AttributeList.
+template <typename AttrInfo>
+static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value,
+ SourceLocation>::type
+getAttrLoc(const AttrInfo &Attr) {
+ return Attr.getLocation();
+}
+static SourceLocation getAttrLoc(const clang::AttributeList &Attr) {
+ return Attr.getLoc();
+}
+
+/// \brief A helper function to provide Attribute Name for the Attr types
+/// AND the AttributeList.
+template <typename AttrInfo>
+static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value,
+ const AttrInfo *>::type
+getAttrName(const AttrInfo &Attr) {
+ return &Attr;
+}
+static const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) {
+ return Attr.getName();
+}
+
/// \brief If Expr is a valid integer constant, get the value of the integer
/// expression and return success or failure. May output an error.
-static bool checkUInt32Argument(Sema &S, const AttributeList &Attr,
- const Expr *Expr, uint32_t &Val,
- unsigned Idx = UINT_MAX) {
+template<typename AttrInfo>
+static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr,
+ uint32_t &Val, unsigned Idx = UINT_MAX) {
llvm::APSInt I(32);
if (Expr->isTypeDependent() || Expr->isValueDependent() ||
!Expr->isIntegerConstantExpr(I, S.Context)) {
if (Idx != UINT_MAX)
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << Idx << AANT_ArgumentIntegerConstant
+ S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type)
+ << getAttrName(Attr) << Idx << AANT_ArgumentIntegerConstant
<< Expr->getSourceRange();
else
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
+ S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_type)
+ << getAttrName(Attr) << AANT_ArgumentIntegerConstant
<< Expr->getSourceRange();
return false;
}
@@ -250,9 +274,9 @@ static bool checkUInt32Argument(Sema &S, const AttributeList &Attr,
/// \brief Wrapper around checkUInt32Argument, with an extra check to be sure
/// that the result will fit into a regular (signed) int. All args have the same
/// purpose as they do in checkUInt32Argument.
-static bool checkPositiveIntArgument(Sema &S, const AttributeList &Attr,
- const Expr *Expr, int &Val,
- unsigned Idx = UINT_MAX) {
+template<typename AttrInfo>
+static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr *Expr,
+ int &Val, unsigned Idx = UINT_MAX) {
uint32_t UVal;
if (!checkUInt32Argument(S, Attr, Expr, UVal, Idx))
return false;
@@ -287,11 +311,10 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range,
/// instance method D. May output an error.
///
/// \returns true if IdxExpr is a valid index.
-static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D,
- const AttributeList &Attr,
- unsigned AttrArgNum,
- const Expr *IdxExpr,
- uint64_t &Idx) {
+template <typename AttrInfo>
+static bool checkFunctionOrMethodParameterIndex(
+ Sema &S, const Decl *D, const AttrInfo &Attr, unsigned AttrArgNum,
+ const Expr *IdxExpr, uint64_t &Idx, bool AllowImplicitThis = false) {
assert(isFunctionOrMethodOrBlock(D));
// In C++ the implicit 'this' function parameter also counts.
@@ -305,24 +328,24 @@ static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D,
llvm::APSInt IdxInt;
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
!IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << AttrArgNum << AANT_ArgumentIntegerConstant
+ S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type)
+ << getAttrName(Attr) << AttrArgNum << AANT_ArgumentIntegerConstant
<< IdxExpr->getSourceRange();
return false;
}
Idx = IdxInt.getLimitedValue();
if (Idx < 1 || (!IV && Idx > NumParams)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << Attr.getName() << AttrArgNum << IdxExpr->getSourceRange();
+ S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_out_of_bounds)
+ << getAttrName(Attr) << AttrArgNum << IdxExpr->getSourceRange();
return false;
}
Idx--; // Convert to zero-based.
- if (HasImplicitThisParam) {
+ if (HasImplicitThisParam && !AllowImplicitThis) {
if (Idx == 0) {
- S.Diag(Attr.getLoc(),
+ S.Diag(getAttrLoc(Attr),
diag::err_attribute_invalid_implicit_this_argument)
- << Attr.getName() << IdxExpr->getSourceRange();
+ << getAttrName(Attr) << IdxExpr->getSourceRange();
return false;
}
--Idx;
@@ -753,31 +776,48 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-/// \brief Checks to be sure that the given parameter number is inbounds, and is
-/// an some integral type. Will emit appropriate diagnostics if this returns
+/// \brief Checks to be sure that the given parameter number is in bounds, and is
+/// an integral type. Will emit appropriate diagnostics if this returns
/// false.
///
/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used
/// to actually retrieve the argument, so it's base-0.
+template <typename AttrInfo>
static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD,
- const AttributeList &Attr,
- unsigned FuncParamNo, unsigned AttrArgNo) {
- assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument");
+ const AttrInfo &Attr, Expr *AttrArg,
+ unsigned FuncParamNo, unsigned AttrArgNo,
+ bool AllowDependentType = false) {
uint64_t Idx;
- if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo,
- Attr.getArgAsExpr(AttrArgNo), Idx))
+ if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo, AttrArg,
+ Idx))
return false;
const ParmVarDecl *Param = FD->getParamDecl(Idx);
+ if (AllowDependentType && Param->getType()->isDependentType())
+ return true;
if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) {
- SourceLocation SrcLoc = Attr.getArgAsExpr(AttrArgNo)->getLocStart();
+ SourceLocation SrcLoc = AttrArg->getLocStart();
S.Diag(SrcLoc, diag::err_attribute_integers_only)
- << Attr.getName() << Param->getSourceRange();
+ << getAttrName(Attr) << Param->getSourceRange();
return false;
}
return true;
}
+/// \brief Checks to be sure that the given parameter number is in bounds, and is
+/// an integral type. Will emit appropriate diagnostics if this returns false.
+///
+/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used
+/// to actually retrieve the argument, so it's base-0.
+static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD,
+ const AttributeList &Attr,
+ unsigned FuncParamNo, unsigned AttrArgNo,
+ bool AllowDependentType = false) {
+ assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument");
+ return checkParamIsIntegerType(S, FD, Attr, Attr.getArgAsExpr(AttrArgNo),
+ FuncParamNo, AttrArgNo, AllowDependentType);
+}
+
static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeAtLeastNumArgs(S, Attr, 1) ||
!checkAttributeAtMostNumArgs(S, Attr, 2))
@@ -792,7 +832,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
const Expr *SizeExpr = Attr.getArgAsExpr(0);
int SizeArgNo;
- // Paramater indices are 1-indexed, hence Index=1
+ // Parameter indices are 1-indexed, hence Index=1
if (!checkPositiveIntArgument(S, Attr, SizeExpr, SizeArgNo, /*Index=*/1))
return;
@@ -803,7 +843,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
int NumberArgNo = 0;
if (Attr.getNumArgs() == 2) {
const Expr *NumberExpr = Attr.getArgAsExpr(1);
- // Paramater indices are 1-based, hence Index=2
+ // Parameter indices are 1-based, hence Index=2
if (!checkPositiveIntArgument(S, Attr, NumberExpr, NumberArgNo,
/*Index=*/2))
return;
@@ -909,7 +949,7 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D,
Msg = "<no message provided>";
SmallVector<PartialDiagnosticAt, 8> Diags;
- if (!Cond->isValueDependent() &&
+ if (isa<FunctionDecl>(D) && !Cond->isValueDependent() &&
!Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D),
Diags)) {
S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr)
@@ -997,10 +1037,11 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- auto *FD = cast<FunctionDecl>(D);
- bool ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
+ bool ArgDependent = false;
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
D->addAttr(::new (S.Context) DiagnoseIfAttr(
- Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, FD,
+ Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D),
Attr.getAttributeSpellingListIndex()));
}
@@ -1420,7 +1461,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check if the attribute came from a macro expansion or a template
// instantiation.
if (NonNullArgs.empty() && Attr.getLoc().isFileID() &&
- S.ActiveTemplateInstantiations.empty()) {
+ !S.inTemplateInstantiation()) {
bool AnyPointers = isFunctionOrMethodVariadic(D);
for (unsigned I = 0, E = getFunctionOrMethodNumParams(D);
I != E && !AnyPointers; ++I) {
@@ -1484,6 +1525,12 @@ static void handleAssumeAlignedAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex());
}
+static void handleAllocAlignAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ S.AddAllocAlignAttr(Attr.getRange(), D, Attr.getArgAsExpr(0),
+ Attr.getAttributeSpellingListIndex());
+}
+
void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
Expr *OE, unsigned SpellingListIndex) {
QualType ResultType = getFunctionOrMethodResultType(D);
@@ -1535,6 +1582,44 @@ void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
AssumeAlignedAttr(AttrRange, Context, E, OE, SpellingListIndex));
}
+void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
+ unsigned SpellingListIndex) {
+ QualType ResultType = getFunctionOrMethodResultType(D);
+
+ AllocAlignAttr TmpAttr(AttrRange, Context, 0, SpellingListIndex);
+ SourceLocation AttrLoc = AttrRange.getBegin();
+
+ if (!ResultType->isDependentType() &&
+ !isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
+ Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
+ << &TmpAttr << AttrRange << getFunctionOrMethodResultSourceRange(D);
+ return;
+ }
+
+ uint64_t IndexVal;
+ const auto *FuncDecl = cast<FunctionDecl>(D);
+ if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr,
+ /*AttrArgNo=*/1, ParamExpr,
+ IndexVal))
+ return;
+
+ QualType Ty = getFunctionOrMethodParamType(D, IndexVal);
+ if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) {
+ Diag(ParamExpr->getLocStart(), diag::err_attribute_integers_only)
+ << &TmpAttr << FuncDecl->getParamDecl(IndexVal)->getSourceRange();
+ return;
+ }
+
+ // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex
+ // because that has corrected for the implicit this parameter, and is zero-
+ // based. The attribute expects what the user wrote explicitly.
+ llvm::APSInt Val;
+ ParamExpr->EvaluateAsInt(Val, Context);
+
+ D->addAttr(::new (Context) AllocAlignAttr(
+ AttrRange, Context, Val.getZExtValue(), SpellingListIndex));
+}
+
/// Normalize the attribute, __foo__ becomes foo.
/// Returns true if normalization was applied.
static bool normalizeName(StringRef &AttrName) {
@@ -1839,6 +1924,17 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getName()))
return;
+ if (Attr.isDeclspecAttribute()) {
+ const auto &Triple = S.getASTContext().getTargetInfo().getTriple();
+ const auto &Arch = Triple.getArch();
+ if (Arch != llvm::Triple::x86 &&
+ (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_on_arch)
+ << Attr.getName() << Triple.getArchName();
+ return;
+ }
+ }
+
D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
}
@@ -1846,17 +1942,26 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
if (hasDeclarator(D)) return;
- if (S.CheckNoReturnAttr(attr)) return;
+ if (S.CheckNoReturnAttr(attr))
+ return;
if (!isa<ObjCMethodDecl>(D)) {
S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << attr.getName() << ExpectedFunctionOrMethod;
+ << attr.getName() << ExpectedFunctionOrMethod;
return;
}
- D->addAttr(::new (S.Context)
- NoReturnAttr(attr.getRange(), S.Context,
- attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoReturnAttr(
+ attr.getRange(), S.Context, attr.getAttributeSpellingListIndex()));
+}
+
+static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (S.CheckNoCallerSavedRegsAttr(Attr))
+ return;
+
+ D->addAttr(::new (S.Context) AnyX86NoCallerSavedRegistersAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
}
bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
@@ -1868,6 +1973,22 @@ bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
return false;
}
+bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &Attr) {
+ // Check whether the attribute is valid on the current target.
+ if (!Attr.existsInTarget(Context.getTargetInfo())) {
+ Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) << Attr.getName();
+ Attr.setInvalid();
+ return true;
+ }
+
+ if (!checkAttributeNumArgs(*this, Attr, 0)) {
+ Attr.setInvalid();
+ return true;
+ }
+
+ return false;
+}
+
static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
@@ -2303,10 +2424,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
<< Platform->Ident;
NamedDecl *ND = dyn_cast<NamedDecl>(D);
- if (!ND) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ if (!ND) // We warned about this already, so just return.
return;
- }
AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
@@ -2409,6 +2528,26 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
}
}
+static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+ assert(checkAttributeAtMostNumArgs(S, Attr, 3) &&
+ "Invalid number of arguments in an external_source_symbol attribute");
+
+ StringRef Language;
+ if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(0)))
+ Language = SE->getString();
+ StringRef DefinedIn;
+ if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(1)))
+ DefinedIn = SE->getString();
+ bool IsGeneratedDeclaration = Attr.getArgAsIdent(2) != nullptr;
+
+ D->addAttr(::new (S.Context) ExternalSourceSymbolAttr(
+ Attr.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration,
+ Attr.getAttributeSpellingListIndex()));
+}
+
template <class T>
static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range,
typename T::VisibilityType value,
@@ -2753,6 +2892,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)
@@ -2917,6 +3078,28 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
+static void handleEnumExtensibilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!Attr.isArgIdent(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << 0 << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ EnumExtensibilityAttr::Kind ExtensibilityKind;
+ IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident;
+ if (!EnumExtensibilityAttr::ConvertStrToKind(II->getName(),
+ ExtensibilityKind)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << Attr.getName() << II;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) EnumExtensibilityAttr(
+ Attr.getRange(), S.Context, ExtensibilityKind,
+ Attr.getAttributeSpellingListIndex()));
+}
+
/// Handle __attribute__((format_arg((idx)))) attribute based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3193,8 +3376,9 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D,
}
if (!RD->isCompleteDefinition()) {
- S.Diag(Attr.getLoc(),
- diag::warn_transparent_union_attribute_not_definition);
+ if (!RD->isBeingDefined())
+ S.Diag(Attr.getLoc(),
+ diag::warn_transparent_union_attribute_not_definition);
return;
}
@@ -4048,6 +4232,26 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
}
+static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ std::vector<StringRef> DiagnosticIdentifiers;
+ for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) {
+ StringRef RuleName;
+
+ if (!S.checkStringLiteralArgumentAttr(Attr, I, RuleName, nullptr))
+ return;
+
+ // FIXME: Warn if the rule name is unknown. This is tricky because only
+ // clang-tidy knows about available rules.
+ DiagnosticIdentifiers.push_back(RuleName);
+ }
+ D->addAttr(::new (S.Context) SuppressAttr(
+ Attr.getRange(), S.Context, DiagnosticIdentifiers.data(),
+ DiagnosticIdentifiers.size(), Attr.getAttributeSpellingListIndex()));
+}
+
bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
const FunctionDecl *FD) {
if (attr.isInvalid())
@@ -4076,7 +4280,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
case AttributeList::AT_RegCall: CC = CC_X86RegCall; break;
case AttributeList::AT_MSABI:
CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C :
- CC_X86_64Win64;
+ CC_Win64;
break;
case AttributeList::AT_SysVABI:
CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV :
@@ -4397,6 +4601,21 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleXRayLogArgsAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ uint64_t ArgCount;
+
+ if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, Attr.getArgAsExpr(0),
+ ArgCount,
+ true /* AllowImplicitThis*/))
+ return;
+
+ // ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1.
+ D->addAttr(::new (S.Context)
+ XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount,
+ Attr.getAttributeSpellingListIndex()));
+}
+
//===----------------------------------------------------------------------===//
// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -4460,6 +4679,16 @@ void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D,
CFConsumedAttr(attrRange, Context, spellingIndex));
}
+bool Sema::checkNSReturnsRetainedReturnType(SourceLocation loc,
+ QualType type) {
+ if (isValidSubjectOfNSReturnsRetainedAttribute(type))
+ return false;
+
+ Diag(loc, diag::warn_ns_attribute_wrong_return_type)
+ << "'ns_returns_retained'" << 0 << 0;
+ return true;
+}
+
static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
QualType returnType;
@@ -4481,6 +4710,8 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
<< Attr.getRange();
return;
}
+ } else if (Attr.isUsedAsTypeAttr()) {
+ return;
} else {
AttributeDeclKind ExpectedDeclKind;
switch (Attr.getKind()) {
@@ -4524,6 +4755,9 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
}
if (!typeOK) {
+ if (Attr.isUsedAsTypeAttr())
+ return;
+
if (isa<ParmVarDecl>(D)) {
S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
<< Attr.getName() << /*pointer-to-CF*/2
@@ -4863,6 +5097,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)
@@ -5126,6 +5369,32 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D,
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
+static void handleAVRInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << "'interrupt'" << ExpectedFunction;
+ return;
+ }
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ handleSimpleAttribute<AVRInterruptAttr>(S, D, Attr);
+}
+
+static void handleAVRSignalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << "'signal'" << ExpectedFunction;
+ return;
+ }
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ handleSimpleAttribute<AVRSignalAttr>(S, D, Attr);
+}
+
static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Dispatch the interrupt attribute based on the current target.
switch (S.Context.getTargetInfo().getTriple().getArch()) {
@@ -5140,6 +5409,9 @@ static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
case llvm::Triple::x86_64:
handleAnyX86InterruptAttr(S, D, Attr);
break;
+ case llvm::Triple::avr:
+ handleAVRInterruptAttr(S, D, Attr);
+ break;
default:
handleARMInterruptAttr(S, D, Attr);
break;
@@ -5559,18 +5831,21 @@ static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
// Several attributes carry different semantics than the parsing requires, so
- // those are opted out of the common handling.
+ // those are opted out of the common argument checks.
//
// We also bail on unknown and ignored attributes because those are handled
// as part of the target-specific handling logic.
- if (Attr.hasCustomParsing() ||
- Attr.getKind() == AttributeList::UnknownAttribute)
+ if (Attr.getKind() == AttributeList::UnknownAttribute)
return false;
-
// Check whether the attribute requires specific language extensions to be
// enabled.
if (!Attr.diagnoseLangOpts(S))
return true;
+ // Check whether the attribute appertains to the given subject.
+ if (!Attr.diagnoseAppertainsTo(S, D))
+ return true;
+ if (Attr.hasCustomParsing())
+ return false;
if (Attr.getMinArgs() == Attr.getMaxArgs()) {
// If there are no optional arguments, then checking for the argument count
@@ -5587,10 +5862,6 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
return true;
}
- // Check whether the attribute appertains to the given subject.
- if (!Attr.diagnoseAppertainsTo(S, D))
- return true;
-
return false;
}
@@ -5682,12 +5953,18 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleDLLAttr(S, D, Attr);
break;
case AttributeList::AT_Mips16:
- handleSimpleAttributeWithExclusions<Mips16Attr, MipsInterruptAttr>(S, D,
- Attr);
+ handleSimpleAttributeWithExclusions<Mips16Attr, MicroMipsAttr,
+ MipsInterruptAttr>(S, D, Attr);
break;
case AttributeList::AT_NoMips16:
handleSimpleAttribute<NoMips16Attr>(S, D, Attr);
break;
+ case AttributeList::AT_MicroMips:
+ handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, Attr);
+ break;
+ case AttributeList::AT_NoMicroMips:
+ handleSimpleAttribute<NoMicroMipsAttr>(S, D, Attr);
+ break;
case AttributeList::AT_AMDGPUFlatWorkGroupSize:
handleAMDGPUFlatWorkGroupSizeAttr(S, D, Attr);
break;
@@ -5700,6 +5977,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_AMDGPUNumVGPR:
handleAMDGPUNumVGPRAttr(S, D, Attr);
break;
+ case AttributeList::AT_AVRSignal:
+ handleAVRSignalAttr(S, D, Attr);
+ break;
case AttributeList::AT_IBAction:
handleSimpleAttribute<IBActionAttr>(S, D, Attr);
break;
@@ -5772,6 +6052,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ExtVectorType:
handleExtVectorTypeAttr(S, scope, D, Attr);
break;
+ case AttributeList::AT_ExternalSourceSymbol:
+ handleExternalSourceSymbolAttr(S, D, Attr);
+ break;
case AttributeList::AT_MinSize:
handleMinSizeAttr(S, D, Attr);
break;
@@ -5781,6 +6064,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_FlagEnum:
handleSimpleAttribute<FlagEnumAttr>(S, D, Attr);
break;
+ case AttributeList::AT_EnumExtensibility:
+ handleEnumExtensibilityAttr(S, D, Attr);
+ break;
case AttributeList::AT_Flatten:
handleSimpleAttribute<FlattenAttr>(S, D, Attr);
break;
@@ -5837,6 +6123,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_AssumeAligned:
handleAssumeAlignedAttr(S, D, Attr);
break;
+ case AttributeList::AT_AllocAlign:
+ handleAllocAlignAttr(S, D, Attr);
+ break;
case AttributeList::AT_Overloadable:
handleSimpleAttribute<OverloadableAttr>(S, D, Attr);
break;
@@ -5923,6 +6212,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;
@@ -6056,6 +6348,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_PreserveAll:
handleCallConvAttr(S, D, Attr);
break;
+ case AttributeList::AT_Suppress:
+ handleSuppressAttr(S, D, Attr);
+ break;
case AttributeList::AT_OpenCLKernel:
handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr);
break;
@@ -6216,6 +6511,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_TypeTagForDatatype:
handleTypeTagForDatatypeAttr(S, D, Attr);
break;
+ case AttributeList::AT_AnyX86NoCallerSavedRegisters:
+ handleNoCallerSavedRegsAttr(S, D, Attr);
+ break;
case AttributeList::AT_RenderScriptKernel:
handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr);
break;
@@ -6223,6 +6521,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_XRayInstrument:
handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr);
break;
+ case AttributeList::AT_XRayLogArgs:
+ handleXRayLogArgsAttr(S, D, Attr);
+ break;
}
}
@@ -6278,10 +6579,22 @@ 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();
}
}
}
+// Helper for delayed processing TransparentUnion attribute.
+void Sema::ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList) {
+ for (const AttributeList *Attr = AttrList; Attr; Attr = Attr->getNext())
+ if (Attr->getKind() == AttributeList::AT_TransparentUnion) {
+ handleTransparentUnionAttr(*this, D, *Attr);
+ break;
+ }
+}
+
// Annotation attributes are the only attributes allowed after an access
// specifier.
bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
@@ -6443,6 +6756,9 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
ProcessDeclAttributeList(S, D, Attrs);
+
+ // Apply additional attributes specified by '#pragma clang attribute'.
+ AddPragmaAttributes(S, D);
}
/// Is the given declaration allowed to use a forbidden type?
@@ -6537,6 +6853,50 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
return nullptr;
}
+/// The diagnostic we should emit for \c D, and the declaration that
+/// originated it, or \c AR_Available.
+///
+/// \param D The declaration to check.
+/// \param Message If non-null, this will be populated with the message from
+/// the availability attribute that is selected.
+static std::pair<AvailabilityResult, const NamedDecl *>
+ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) {
+ AvailabilityResult Result = D->getAvailability(Message);
+
+ // For typedefs, if the typedef declaration appears available look
+ // to the underlying type to see if it is more restrictive.
+ while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
+ if (Result == AR_Available) {
+ if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
+ D = TT->getDecl();
+ Result = D->getAvailability(Message);
+ continue;
+ }
+ }
+ break;
+ }
+
+ // Forward class declarations get their attributes from their definition.
+ if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
+ if (IDecl->getDefinition()) {
+ D = IDecl->getDefinition();
+ Result = D->getAvailability(Message);
+ }
+ }
+
+ if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
+ if (Result == AR_Available) {
+ const DeclContext *DC = ECD->getDeclContext();
+ if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
+ Result = TheEnumDecl->getAvailability(Message);
+ D = TheEnumDecl;
+ }
+ }
+
+ return {Result, D};
+}
+
+
/// \brief whether we should emit a diagnostic for \c K and \c DeclVersion in
/// the context of \c Ctx. For example, we should emit an unavailable diagnostic
/// in a deprecated context, but not the other way around.
@@ -6602,8 +6962,60 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
return true;
}
+static bool
+shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
+ const VersionTuple &DeploymentVersion,
+ const VersionTuple &DeclVersion) {
+ const auto &Triple = Context.getTargetInfo().getTriple();
+ VersionTuple ForceAvailabilityFromVersion;
+ switch (Triple.getOS()) {
+ case llvm::Triple::IOS:
+ case llvm::Triple::TvOS:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
+ break;
+ case llvm::Triple::WatchOS:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
+ break;
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
+ break;
+ default:
+ // New targets should always warn about availability.
+ return Triple.getVendor() == llvm::Triple::Apple;
+ }
+ return DeploymentVersion >= ForceAvailabilityFromVersion ||
+ DeclVersion >= ForceAvailabilityFromVersion;
+}
+
+static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
+ for (Decl *Ctx = OrigCtx; Ctx;
+ Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
+ if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
+ return cast<NamedDecl>(Ctx);
+ if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
+ if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
+ return Imp->getClassInterface();
+ return CD;
+ }
+ }
+
+ return dyn_cast<NamedDecl>(OrigCtx);
+}
+
+/// Actually emit an availability diagnostic for a reference to an unavailable
+/// decl.
+///
+/// \param Ctx The context that the reference occurred in
+/// \param ReferringDecl The exact declaration that was referenced.
+/// \param OffendingDecl A related decl to \c ReferringDecl that has an
+/// availability attribute corrisponding to \c K attached to it. Note that this
+/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
+/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
+/// and OffendingDecl is the EnumDecl.
static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
- Decl *Ctx, const NamedDecl *D,
+ Decl *Ctx, const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
StringRef Message, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
@@ -6611,6 +7023,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
// Diagnostics for deprecated or unavailable.
unsigned diag, diag_message, diag_fwdclass_message;
unsigned diag_available_here = diag::note_availability_specified_here;
+ SourceLocation NoteLocation = OffendingDecl->getLocation();
// Matches 'diag::note_property_attribute' options.
unsigned property_note_select;
@@ -6619,7 +7032,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
unsigned available_here_select_kind;
VersionTuple DeclVersion;
- if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D))
+ if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
DeclVersion = AA->getIntroduced();
if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx))
@@ -6633,6 +7046,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
property_note_select = /* deprecated */ 0;
available_here_select_kind = /* deprecated */ 2;
+ if (const auto *attr = OffendingDecl->getAttr<DeprecatedAttr>())
+ NoteLocation = attr->getLocation();
break;
case AR_Unavailable:
@@ -6643,13 +7058,14 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
property_note_select = /* unavailable */ 1;
available_here_select_kind = /* unavailable */ 0;
- if (auto attr = D->getAttr<UnavailableAttr>()) {
+ if (auto attr = OffendingDecl->getAttr<UnavailableAttr>()) {
if (attr->isImplicit() && attr->getImplicitReason()) {
// Most of these failures are due to extra restrictions in ARC;
// reflect that in the primary diagnostic when applicable.
auto flagARCError = [&] {
if (S.getLangOpts().ObjCAutoRefCount &&
- S.getSourceManager().isInSystemHeader(D->getLocation()))
+ S.getSourceManager().isInSystemHeader(
+ OffendingDecl->getLocation()))
diag = diag::err_unavailable_in_arc;
};
@@ -6687,13 +7103,27 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
}
break;
- case AR_NotYetIntroduced:
- diag = diag::warn_partial_availability;
- diag_message = diag::warn_partial_message;
- diag_fwdclass_message = diag::warn_partial_fwdclass_message;
+ case AR_NotYetIntroduced: {
+ // We would like to emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
+ const AvailabilityAttr *AA =
+ getAttrForPlatform(S.getASTContext(), OffendingDecl);
+ VersionTuple Introduced = AA->getIntroduced();
+ bool NewWarning = shouldDiagnoseAvailabilityByDefault(
+ S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
+ Introduced);
+ diag = NewWarning ? diag::warn_partial_availability_new
+ : diag::warn_partial_availability;
+ diag_message = NewWarning ? diag::warn_partial_message_new
+ : diag::warn_partial_message;
+ diag_fwdclass_message = NewWarning ? diag::warn_partial_fwdclass_message_new
+ : diag::warn_partial_fwdclass_message;
property_note_select = /* partial */ 2;
available_here_select_kind = /* partial */ 3;
break;
+ }
case AR_Available:
llvm_unreachable("Warning for availability of available declaration?");
@@ -6702,9 +7132,9 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
CharSourceRange UseRange;
StringRef Replacement;
if (K == AR_Deprecated) {
- if (auto attr = D->getAttr<DeprecatedAttr>())
+ if (auto attr = OffendingDecl->getAttr<DeprecatedAttr>())
Replacement = attr->getReplacement();
- if (auto attr = getAttrForPlatform(S.Context, D))
+ if (auto attr = getAttrForPlatform(S.Context, OffendingDecl))
Replacement = attr->getReplacement();
if (!Replacement.empty())
@@ -6713,21 +7143,21 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
}
if (!Message.empty()) {
- S.Diag(Loc, diag_message) << D << Message
+ S.Diag(Loc, diag_message) << ReferringDecl << Message
<< (UseRange.isValid() ?
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
<< ObjCProperty->getDeclName() << property_note_select;
} else if (!UnknownObjCClass) {
- S.Diag(Loc, diag) << D
+ S.Diag(Loc, diag) << ReferringDecl
<< (UseRange.isValid() ?
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
<< ObjCProperty->getDeclName() << property_note_select;
} else {
- S.Diag(Loc, diag_fwdclass_message) << D
+ S.Diag(Loc, diag_fwdclass_message) << ReferringDecl
<< (UseRange.isValid() ?
FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
@@ -6735,27 +7165,36 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
// The declaration can have multiple availability attributes, we are looking
// at one of them.
- const AvailabilityAttr *A = getAttrForPlatform(S.Context, D);
+ const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
if (A && A->isInherited()) {
- for (const Decl *Redecl = D->getMostRecentDecl(); Redecl;
+ for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
Redecl = Redecl->getPreviousDecl()) {
const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context,
Redecl);
if (AForRedecl && !AForRedecl->isInherited()) {
// If D is a declaration with inherited attributes, the note should
// point to the declaration with actual attributes.
- S.Diag(Redecl->getLocation(), diag_available_here) << D
+ S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl
<< available_here_select_kind;
break;
}
}
}
else
- S.Diag(D->getLocation(), diag_available_here)
- << D << available_here_select_kind;
+ S.Diag(NoteLocation, diag_available_here)
+ << OffendingDecl << available_here_select_kind;
if (K == AR_NotYetIntroduced)
- S.Diag(Loc, diag::note_partial_availability_silence) << D;
+ if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
+ if (auto *TD = dyn_cast<TagDecl>(Enclosing))
+ if (TD->getDeclName().isEmpty()) {
+ S.Diag(TD->getLocation(), diag::note_partial_availability_silence)
+ << /*Anonymous*/1 << TD->getKindName();
+ return;
+ }
+ S.Diag(Enclosing->getLocation(), diag::note_partial_availability_silence)
+ << /*Named*/0 << Enclosing;
+ }
}
static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
@@ -6765,9 +7204,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
DD.Triggered = true;
DoEmitAvailabilityWarning(
- S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityDecl(),
- DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(),
- DD.getObjCProperty(), false);
+ S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
+ DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc,
+ DD.getUnknownObjCClass(), DD.getObjCProperty(), false);
}
void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
@@ -6825,27 +7264,93 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
curPool->steal(pool);
}
-void Sema::EmitAvailabilityWarning(AvailabilityResult AR,
- NamedDecl *D, StringRef Message,
- SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty,
- bool ObjCPropertyAccess) {
+static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR,
+ const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
+ StringRef Message, SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
+ bool ObjCPropertyAccess) {
// Delay if we're currently parsing a declaration.
- if (DelayedDiagnostics.shouldDelayDiagnostics()) {
- DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(
- AR, Loc, D, UnknownObjCClass, ObjCProperty, Message,
- ObjCPropertyAccess));
+ if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+ S.DelayedDiagnostics.add(
+ DelayedDiagnostic::makeAvailability(
+ AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass,
+ ObjCProperty, Message, ObjCPropertyAccess));
return;
}
- Decl *Ctx = cast<Decl>(getCurLexicalContext());
- DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass,
- ObjCProperty, ObjCPropertyAccess);
+ Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
+ DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
+ Message, Loc, UnknownObjCClass, ObjCProperty,
+ ObjCPropertyAccess);
}
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
@@ -6861,6 +7366,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);
@@ -6871,10 +7377,34 @@ public:
SemaRef.Context.getTargetInfo().getPlatformMinVersion());
}
+ bool TraverseDecl(Decl *D) {
+ // Avoid visiting nested functions to prevent duplicate warnings.
+ if (!D || isa<FunctionDecl>(D))
+ return true;
+ return Base::TraverseDecl(D);
+ }
+
+ 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);
+ bool TraverseLambdaExpr(LambdaExpr *E) { return true; }
+
+ bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) {
+ if (PRE->isClassReceiver())
+ DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation());
+ return true;
+ }
+
bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
if (ObjCMethodDecl *D = Msg->getMethodDecl())
DiagnoseDeclAvailability(
@@ -6894,24 +7424,32 @@ public:
return true;
}
+ bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
+ SemaRef.Diag(E->getLocStart(), diag::warn_at_available_unchecked_use)
+ << (!SemaRef.getLangOpts().ObjC1);
+ return true;
+ }
+
bool VisitTypeLoc(TypeLoc Ty);
};
void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
NamedDecl *D, SourceRange Range) {
-
- VersionTuple ContextVersion = AvailabilityStack.back();
- if (AvailabilityResult Result =
- SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) {
+ AvailabilityResult Result;
+ const NamedDecl *OffendingDecl;
+ std::tie(Result, OffendingDecl) =
+ ShouldDiagnoseAvailabilityOfDecl(D, nullptr);
+ if (Result != AR_Available) {
// All other diagnostic kinds have already been handled in
// DiagnoseAvailabilityOfDecl.
if (Result != AR_NotYetIntroduced)
return;
- const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D);
+ const AvailabilityAttr *AA =
+ getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
VersionTuple Introduced = AA->getIntroduced();
- if (ContextVersion >= Introduced)
+ if (AvailabilityStack.back() >= Introduced)
return;
// If the context of this function is less available than D, we should not
@@ -6919,18 +7457,96 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx))
return;
- SemaRef.Diag(Range.getBegin(), diag::warn_unguarded_availability)
+ // We would like to emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
+ unsigned DiagKind =
+ shouldDiagnoseAvailabilityByDefault(
+ SemaRef.Context,
+ SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
+ ? diag::warn_unguarded_availability_new
+ : diag::warn_unguarded_availability;
+
+ SemaRef.Diag(Range.getBegin(), DiagKind)
<< Range << D
<< AvailabilityAttr::getPrettyPlatformName(
SemaRef.getASTContext().getTargetInfo().getPlatformName())
<< Introduced.getAsString();
- SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here)
- << D << /* partial */ 3;
+ SemaRef.Diag(OffendingDecl->getLocation(),
+ diag::note_availability_specified_here)
+ << OffendingDecl << /* partial */ 3;
+
+ 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;
- // FIXME: Replace this with a fixit diagnostic.
- SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
- << Range << D;
+ 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")
+ << "("
+ << AvailabilityAttr::getPlatformNameSourceSpelling(
+ 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());
}
}
@@ -6938,6 +7554,9 @@ bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
const Type *TyPtr = Ty.getTypePtr();
SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()};
+ if (Range.isInvalid())
+ return true;
+
if (const TagType *TT = dyn_cast<TagType>(TyPtr)) {
TagDecl *TD = TT->getDecl();
DiagnoseDeclAvailability(TD, Range);
@@ -6990,8 +7609,51 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
Body = FD->getBody();
} else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
Body = MD->getBody();
+ else if (auto *BD = dyn_cast<BlockDecl>(D))
+ Body = BD->getBody();
assert(Body && "Need a body here!");
DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
}
+
+void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ bool ObjCPropertyAccess,
+ bool AvoidPartialAvailabilityChecks) {
+ std::string Message;
+ AvailabilityResult Result;
+ const NamedDecl* OffendingDecl;
+ // See if this declaration is unavailable, deprecated, or partial.
+ std::tie(Result, OffendingDecl) = ShouldDiagnoseAvailabilityOfDecl(D, &Message);
+ if (Result == AR_Available)
+ return;
+
+ if (Result == AR_NotYetIntroduced) {
+ if (AvoidPartialAvailabilityChecks)
+ return;
+
+ // We need to know the @available context in the current function to
+ // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
+ // when we're done parsing the current function.
+ if (getCurFunctionOrMethodDecl()) {
+ getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
+ return;
+ } else if (getCurBlock() || getCurLambda()) {
+ getCurFunction()->HasPotentialAvailabilityViolations = true;
+ return;
+ }
+ }
+
+ const ObjCPropertyDecl *ObjCPDecl = nullptr;
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
+ AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
+ if (PDeclResult == Result)
+ ObjCPDecl = PD;
+ }
+ }
+
+ EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Loc,
+ UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
+}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
index f265f4c..c05e5f0 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
@@ -467,7 +467,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// If only one of these is a local function declaration, then they are
// declared in different scopes, even though isDeclInScope may think
// they're in the same scope. (If both are local, the scope check is
- // sufficent, and if neither is local, then they are in the same scope.)
+ // sufficient, and if neither is local, then they are in the same scope.)
continue;
}
@@ -547,17 +547,23 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Diag(OldParam->getLocation(), diag::note_previous_definition)
<< OldParam->getDefaultArgRange();
} else if (OldParamHasDfl) {
- // Merge the old default argument into the new parameter.
- // It's important to use getInit() here; getDefaultArg()
- // strips off any top-level ExprWithCleanups.
- NewParam->setHasInheritedDefaultArg();
- if (OldParam->hasUnparsedDefaultArg())
- NewParam->setUnparsedDefaultArg();
- else if (OldParam->hasUninstantiatedDefaultArg())
- NewParam->setUninstantiatedDefaultArg(
- OldParam->getUninstantiatedDefaultArg());
- else
- NewParam->setDefaultArg(OldParam->getInit());
+ // Merge the old default argument into the new parameter unless the new
+ // function is a friend declaration in a template class. In the latter
+ // case the default arguments will be inherited when the friend
+ // declaration will be instantiated.
+ if (New->getFriendObjectKind() == Decl::FOK_None ||
+ !New->getLexicalDeclContext()->isDependentContext()) {
+ // It's important to use getInit() here; getDefaultArg()
+ // strips off any top-level ExprWithCleanups.
+ NewParam->setHasInheritedDefaultArg();
+ if (OldParam->hasUnparsedDefaultArg())
+ NewParam->setUnparsedDefaultArg();
+ else if (OldParam->hasUninstantiatedDefaultArg())
+ NewParam->setUninstantiatedDefaultArg(
+ OldParam->getUninstantiatedDefaultArg());
+ else
+ NewParam->setDefaultArg(OldParam->getInit());
+ }
} else if (NewParamHasDfl) {
if (New->getDescribedFunctionTemplate()) {
// Paragraph 4, quoted above, only applies to non-template functions.
@@ -638,7 +644,12 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Diag(Old->getLocation(), diag::note_previous_declaration);
Invalid = true;
} else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
- Old->isDefined(Def)) {
+ Old->isDefined(Def) &&
+ // If a friend function is inlined but does not have 'inline'
+ // specifier, it is a definition. Do not report attribute conflict
+ // in this case, redefinition will be diagnosed later.
+ (New->isInlineSpecified() ||
+ New->getFriendObjectKind() == Decl::FOK_None)) {
// C++11 [dcl.fcn.spec]p4:
// If the definition of a function appears in a translation unit before its
// first declaration as inline, the program is ill-formed.
@@ -647,6 +658,17 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Invalid = true;
}
+ // FIXME: It's not clear what should happen if multiple declarations of a
+ // deduction guide have different explicitness. For now at least we simply
+ // reject any case where the explicitness changes.
+ auto *NewGuide = dyn_cast<CXXDeductionGuideDecl>(New);
+ if (NewGuide && NewGuide->isExplicitSpecified() !=
+ cast<CXXDeductionGuideDecl>(Old)->isExplicitSpecified()) {
+ Diag(New->getLocation(), diag::err_deduction_guide_explicit_mismatch)
+ << NewGuide->isExplicitSpecified();
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
+
// C++11 [dcl.fct.default]p4: If a friend declaration specifies a default
// argument expression, that declaration shall be a definition and shall be
// the only declaration of the function or function template in the
@@ -970,7 +992,8 @@ namespace { enum class IsTupleLike { TupleLike, NotTupleLike, Error }; }
static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,
llvm::APSInt &Size) {
- EnterExpressionEvaluationContext ContextRAII(S, Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext ContextRAII(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
DeclarationName Value = S.PP.getIdentifierInfo("value");
LookupResult R(S, Value, Loc, Sema::LookupOrdinaryName);
@@ -2705,8 +2728,7 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) {
if (D->isInvalidDecl() || D->hasAttr<OverrideAttr>())
return;
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
- if (!MD || MD->isImplicit() || MD->hasAttr<FinalAttr>() ||
- isa<CXXDestructorDecl>(MD))
+ if (!MD || MD->isImplicit() || MD->hasAttr<FinalAttr>())
return;
SourceLocation Loc = MD->getLocation();
@@ -2716,10 +2738,12 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) {
SpellingLoc = getSourceManager().getSpellingLoc(SpellingLoc);
if (SpellingLoc.isValid() && getSourceManager().isInSystemHeader(SpellingLoc))
return;
-
+
if (MD->size_overridden_methods() > 0) {
- Diag(MD->getLocation(), diag::warn_function_marked_not_override_overriding)
- << MD->getDeclName();
+ unsigned DiagID = isa<CXXDestructorDecl>(MD)
+ ? diag::warn_destructor_marked_not_override_overriding
+ : diag::warn_function_marked_not_override_overriding;
+ Diag(MD->getLocation(), DiagID) << MD->getDeclName();
const CXXMethodDecl *OMD = *MD->begin_overridden_methods();
Diag(OMD->getLocation(), diag::note_overridden_virtual_function);
}
@@ -2758,6 +2782,56 @@ static AttributeList *getMSPropertyAttr(AttributeList *list) {
return nullptr;
}
+// Check if there is a field shadowing.
+void Sema::CheckShadowInheritedFields(const SourceLocation &Loc,
+ DeclarationName FieldName,
+ const CXXRecordDecl *RD) {
+ if (Diags.isIgnored(diag::warn_shadow_field, Loc))
+ return;
+
+ // To record a shadowed field in a base
+ std::map<CXXRecordDecl*, NamedDecl*> Bases;
+ auto FieldShadowed = [&](const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path) {
+ const auto Base = Specifier->getType()->getAsCXXRecordDecl();
+ // Record an ambiguous path directly
+ if (Bases.find(Base) != Bases.end())
+ return true;
+ for (const auto Field : Base->lookup(FieldName)) {
+ if ((isa<FieldDecl>(Field) || isa<IndirectFieldDecl>(Field)) &&
+ Field->getAccess() != AS_private) {
+ assert(Field->getAccess() != AS_none);
+ assert(Bases.find(Base) == Bases.end());
+ Bases[Base] = Field;
+ return true;
+ }
+ }
+ return false;
+ };
+
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/true);
+ if (!RD->lookupInBases(FieldShadowed, Paths))
+ return;
+
+ for (const auto &P : Paths) {
+ auto Base = P.back().Base->getType()->getAsCXXRecordDecl();
+ auto It = Bases.find(Base);
+ // Skip duplicated bases
+ if (It == Bases.end())
+ continue;
+ auto BaseField = It->second;
+ assert(BaseField->getAccess() != AS_private);
+ if (AS_none !=
+ CXXRecordDecl::MergeAccess(P.Access, BaseField->getAccess())) {
+ Diag(Loc, diag::warn_shadow_field)
+ << FieldName.getAsString() << RD->getName() << Base->getName();
+ Diag(BaseField->getLocation(), diag::note_shadow_field);
+ Bases.erase(It);
+ }
+ }
+}
+
/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
/// bitfield width if there is one, 'InitExpr' specifies the initializer if
@@ -2957,6 +3031,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (!Member)
return nullptr;
}
+
+ CheckShadowInheritedFields(Loc, Name, cast<CXXRecordDecl>(CurContext));
} else {
Member = HandleDeclarator(S, D, TemplateParameterLists);
if (!Member)
@@ -3673,6 +3749,9 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo);
} else if (DS.getTypeSpecType() == TST_decltype) {
BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+ } else if (DS.getTypeSpecType() == TST_decltype_auto) {
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid);
+ return true;
} else {
LookupResult R(*this, MemberOrBase, IdLoc, LookupOrdinaryName);
LookupParsedName(R, S, &SS);
@@ -3699,6 +3778,15 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (BaseType.isNull())
return true;
+ TInfo = Context.CreateTypeSourceInfo(BaseType);
+ DependentNameTypeLoc TL =
+ TInfo->getTypeLoc().castAs<DependentNameTypeLoc>();
+ if (!TL.isNull()) {
+ TL.setNameLoc(IdLoc);
+ TL.setElaboratedKeywordLoc(SourceLocation());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+ }
+
R.clear();
R.setLookupName(MemberOrBase);
}
@@ -4332,11 +4420,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
}
}
- if (SemaRef.getLangOpts().ObjCAutoRefCount &&
- FieldBaseElementType->isObjCRetainableType() &&
- FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
- FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
- // ARC:
+ if (FieldBaseElementType.hasNonTrivialObjCLifetime()) {
+ // ARC and Weak:
// Default-initialize Objective-C pointers to NULL.
CXXMemberInit
= new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
@@ -5015,6 +5100,10 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
DiagnoseUseOfDecl(Dtor, Location);
}
+ // We only potentially invoke the destructors of potentially constructed
+ // subobjects.
+ bool VisitVirtualBases = !ClassDecl->isAbstract();
+
llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
// Bases.
@@ -5023,8 +5112,11 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
const RecordType *RT = Base.getType()->getAs<RecordType>();
// Remember direct virtual bases.
- if (Base.isVirtual())
+ if (Base.isVirtual()) {
+ if (!VisitVirtualBases)
+ continue;
DirectVirtualBases.insert(RT);
+ }
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
// If our base class is invalid, we probably can't get its dtor anyway.
@@ -5046,6 +5138,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
MarkFunctionReferenced(Location, Dtor);
DiagnoseUseOfDecl(Dtor, Location);
}
+
+ if (!VisitVirtualBases)
+ return;
// Virtual bases.
for (const auto &VBase : ClassDecl->vbases()) {
@@ -5378,7 +5473,7 @@ static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) {
// Synthesize and instantiate non-trivial implicit methods, explicitly
// defaulted methods, and the copy and move assignment operators. The
// latter are exported even if they are trivial, because the address of
- // an operator can be taken and should compare equal accross libraries.
+ // an operator can be taken and should compare equal across libraries.
DiagnosticErrorTrap Trap(S.Diags);
S.MarkFunctionReferenced(Class->getLocation(), MD);
if (Trap.hasErrorOccurred()) {
@@ -5631,6 +5726,53 @@ static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
}
}
+/// Determine whether a type is permitted to be passed or returned in
+/// registers, per C++ [class.temporary]p3.
+static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) {
+ if (D->isDependentType() || D->isInvalidDecl())
+ return false;
+
+ // Per C++ [class.temporary]p3, the relevant condition is:
+ // each copy constructor, move constructor, and destructor of X is
+ // either trivial or deleted, and X has at least one non-deleted copy
+ // or move constructor
+ bool HasNonDeletedCopyOrMove = false;
+
+ if (D->needsImplicitCopyConstructor() &&
+ !D->defaultedCopyConstructorIsDeleted()) {
+ if (!D->hasTrivialCopyConstructor())
+ return false;
+ HasNonDeletedCopyOrMove = true;
+ }
+
+ if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor() &&
+ !D->defaultedMoveConstructorIsDeleted()) {
+ if (!D->hasTrivialMoveConstructor())
+ return false;
+ HasNonDeletedCopyOrMove = true;
+ }
+
+ if (D->needsImplicitDestructor() && !D->defaultedDestructorIsDeleted() &&
+ !D->hasTrivialDestructor())
+ return false;
+
+ for (const CXXMethodDecl *MD : D->methods()) {
+ if (MD->isDeleted())
+ continue;
+
+ auto *CD = dyn_cast<CXXConstructorDecl>(MD);
+ if (CD && CD->isCopyOrMoveConstructor())
+ HasNonDeletedCopyOrMove = true;
+ else if (!isa<CXXDestructorDecl>(MD))
+ continue;
+
+ if (!MD->isTrivial())
+ return false;
+ }
+
+ return HasNonDeletedCopyOrMove;
+}
+
/// \brief Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
@@ -5775,6 +5917,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
checkClassLevelDLLAttribute(Record);
+
+ Record->setCanPassInRegisters(computeCanPassInRegisters(*this, Record));
}
/// Look up the special member function that would be called by a special
@@ -5786,7 +5930,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
/// \param ConstRHS True if this is a copy operation with a const object
/// on its RHS, that is, if the argument to the outer special member
/// function is 'const' and this is not a field marked 'mutable'.
-static Sema::SpecialMemberOverloadResult *lookupCallFromSpecialMember(
+static Sema::SpecialMemberOverloadResult lookupCallFromSpecialMember(
Sema &S, CXXRecordDecl *Class, Sema::CXXSpecialMember CSM,
unsigned FieldQuals, bool ConstRHS) {
unsigned LHSQuals = 0;
@@ -5909,13 +6053,13 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
if (CSM == Sema::CXXDefaultConstructor)
return ClassDecl->hasConstexprDefaultConstructor();
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS);
- if (!SMOR || !SMOR->getMethod())
+ if (!SMOR.getMethod())
// A constructor we wouldn't select can't be "involved in initializing"
// anything.
return true;
- return SMOR->getMethod()->isConstexpr();
+ return SMOR.getMethod()->isConstexpr();
}
/// Determine whether the specified special member function would be constexpr
@@ -6025,27 +6169,23 @@ static bool defaultedSpecialMemberIsConstexpr(
}
static Sema::ImplicitExceptionSpecification
+ComputeDefaultedSpecialMemberExceptionSpec(
+ Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI);
+
+static Sema::ImplicitExceptionSpecification
computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
- switch (S.getSpecialMember(MD)) {
- case Sema::CXXDefaultConstructor:
- return S.ComputeDefaultedDefaultCtorExceptionSpec(Loc, MD);
- case Sema::CXXCopyConstructor:
- return S.ComputeDefaultedCopyCtorExceptionSpec(MD);
- case Sema::CXXCopyAssignment:
- return S.ComputeDefaultedCopyAssignmentExceptionSpec(MD);
- case Sema::CXXMoveConstructor:
- return S.ComputeDefaultedMoveCtorExceptionSpec(MD);
- case Sema::CXXMoveAssignment:
- return S.ComputeDefaultedMoveAssignmentExceptionSpec(MD);
- case Sema::CXXDestructor:
- return S.ComputeDefaultedDtorExceptionSpec(MD);
- case Sema::CXXInvalid:
- break;
- }
- assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
+ auto CSM = S.getSpecialMember(MD);
+ if (CSM != Sema::CXXInvalid)
+ return ComputeDefaultedSpecialMemberExceptionSpec(S, Loc, MD, CSM, nullptr);
+
+ auto *CD = cast<CXXConstructorDecl>(MD);
+ assert(CD->getInheritedConstructor() &&
"only special members have implicit exception specs");
- return S.ComputeInheritingCtorExceptionSpec(Loc,
- cast<CXXConstructorDecl>(MD));
+ Sema::InheritedConstructorInfo ICI(
+ S, Loc, CD->getInheritedConstructor().getShadowDecl());
+ return ComputeDefaultedSpecialMemberExceptionSpec(
+ S, Loc, CD, Sema::CXXDefaultConstructor, &ICI);
}
static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
@@ -6300,45 +6440,35 @@ void Sema::CheckDelayedMemberExceptionSpecs() {
}
namespace {
-struct SpecialMemberDeletionInfo {
+/// CRTP base class for visiting operations performed by a special member
+/// function (or inherited constructor).
+template<typename Derived>
+struct SpecialMemberVisitor {
Sema &S;
CXXMethodDecl *MD;
Sema::CXXSpecialMember CSM;
Sema::InheritedConstructorInfo *ICI;
- bool Diagnose;
// Properties of the special member, computed for convenience.
- bool IsConstructor, IsAssignment, IsMove, ConstArg;
- SourceLocation Loc;
-
- bool AllFieldsAreConst;
+ bool IsConstructor = false, IsAssignment = false, ConstArg = false;
- SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD,
- Sema::CXXSpecialMember CSM,
- Sema::InheritedConstructorInfo *ICI, bool Diagnose)
- : S(S), MD(MD), CSM(CSM), ICI(ICI), Diagnose(Diagnose),
- IsConstructor(false), IsAssignment(false), IsMove(false),
- ConstArg(false), Loc(MD->getLocation()), AllFieldsAreConst(true) {
+ SpecialMemberVisitor(Sema &S, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI)
+ : S(S), MD(MD), CSM(CSM), ICI(ICI) {
switch (CSM) {
- case Sema::CXXDefaultConstructor:
- case Sema::CXXCopyConstructor:
- IsConstructor = true;
- break;
- case Sema::CXXMoveConstructor:
- IsConstructor = true;
- IsMove = true;
- break;
- case Sema::CXXCopyAssignment:
- IsAssignment = true;
- break;
- case Sema::CXXMoveAssignment:
- IsAssignment = true;
- IsMove = true;
- break;
- case Sema::CXXDestructor:
- break;
- case Sema::CXXInvalid:
- llvm_unreachable("invalid special member kind");
+ case Sema::CXXDefaultConstructor:
+ case Sema::CXXCopyConstructor:
+ case Sema::CXXMoveConstructor:
+ IsConstructor = true;
+ break;
+ case Sema::CXXCopyAssignment:
+ case Sema::CXXMoveAssignment:
+ IsAssignment = true;
+ break;
+ case Sema::CXXDestructor:
+ break;
+ case Sema::CXXInvalid:
+ llvm_unreachable("invalid special member kind");
}
if (MD->getNumParams()) {
@@ -6348,21 +6478,109 @@ struct SpecialMemberDeletionInfo {
}
}
- bool inUnion() const { return MD->getParent()->isUnion(); }
+ Derived &getDerived() { return static_cast<Derived&>(*this); }
- Sema::CXXSpecialMember getEffectiveCSM() {
- return ICI ? Sema::CXXInvalid : CSM;
+ /// Is this a "move" special member?
+ bool isMove() const {
+ return CSM == Sema::CXXMoveConstructor || CSM == Sema::CXXMoveAssignment;
}
/// Look up the corresponding special member in the given class.
- Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class,
- unsigned Quals, bool IsMutable) {
+ Sema::SpecialMemberOverloadResult lookupIn(CXXRecordDecl *Class,
+ unsigned Quals, bool IsMutable) {
return lookupCallFromSpecialMember(S, Class, CSM, Quals,
ConstArg && !IsMutable);
}
+ /// Look up the constructor for the specified base class to see if it's
+ /// overridden due to this being an inherited constructor.
+ Sema::SpecialMemberOverloadResult lookupInheritedCtor(CXXRecordDecl *Class) {
+ if (!ICI)
+ return {};
+ assert(CSM == Sema::CXXDefaultConstructor);
+ auto *BaseCtor =
+ cast<CXXConstructorDecl>(MD)->getInheritedConstructor().getConstructor();
+ if (auto *MD = ICI->findConstructorForBase(Class, BaseCtor).first)
+ return MD;
+ return {};
+ }
+
+ /// A base or member subobject.
typedef llvm::PointerUnion<CXXBaseSpecifier*, FieldDecl*> Subobject;
+ /// Get the location to use for a subobject in diagnostics.
+ static SourceLocation getSubobjectLoc(Subobject Subobj) {
+ // FIXME: For an indirect virtual base, the direct base leading to
+ // the indirect virtual base would be a more useful choice.
+ if (auto *B = Subobj.dyn_cast<CXXBaseSpecifier*>())
+ return B->getBaseTypeLoc();
+ else
+ return Subobj.get<FieldDecl*>()->getLocation();
+ }
+
+ enum BasesToVisit {
+ /// Visit all non-virtual (direct) bases.
+ VisitNonVirtualBases,
+ /// Visit all direct bases, virtual or not.
+ VisitDirectBases,
+ /// Visit all non-virtual bases, and all virtual bases if the class
+ /// is not abstract.
+ VisitPotentiallyConstructedBases,
+ /// Visit all direct or virtual bases.
+ VisitAllBases
+ };
+
+ // Visit the bases and members of the class.
+ bool visit(BasesToVisit Bases) {
+ CXXRecordDecl *RD = MD->getParent();
+
+ if (Bases == VisitPotentiallyConstructedBases)
+ Bases = RD->isAbstract() ? VisitNonVirtualBases : VisitAllBases;
+
+ for (auto &B : RD->bases())
+ if ((Bases == VisitDirectBases || !B.isVirtual()) &&
+ getDerived().visitBase(&B))
+ return true;
+
+ if (Bases == VisitAllBases)
+ for (auto &B : RD->vbases())
+ if (getDerived().visitBase(&B))
+ return true;
+
+ for (auto *F : RD->fields())
+ if (!F->isInvalidDecl() && !F->isUnnamedBitfield() &&
+ getDerived().visitField(F))
+ return true;
+
+ return false;
+ }
+};
+}
+
+namespace {
+struct SpecialMemberDeletionInfo
+ : SpecialMemberVisitor<SpecialMemberDeletionInfo> {
+ bool Diagnose;
+
+ SourceLocation Loc;
+
+ bool AllFieldsAreConst;
+
+ SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD,
+ Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI, bool Diagnose)
+ : SpecialMemberVisitor(S, MD, CSM, ICI), Diagnose(Diagnose),
+ Loc(MD->getLocation()), AllFieldsAreConst(true) {}
+
+ bool inUnion() const { return MD->getParent()->isUnion(); }
+
+ Sema::CXXSpecialMember getEffectiveCSM() {
+ return ICI ? Sema::CXXInvalid : CSM;
+ }
+
+ bool visitBase(CXXBaseSpecifier *Base) { return shouldDeleteForBase(Base); }
+ bool visitField(FieldDecl *Field) { return shouldDeleteForField(Field); }
+
bool shouldDeleteForBase(CXXBaseSpecifier *Base);
bool shouldDeleteForField(FieldDecl *FD);
bool shouldDeleteForAllConstMembers();
@@ -6370,7 +6588,7 @@ struct SpecialMemberDeletionInfo {
bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj,
unsigned Quals);
bool shouldDeleteForSubobjectCall(Subobject Subobj,
- Sema::SpecialMemberOverloadResult *SMOR,
+ Sema::SpecialMemberOverloadResult SMOR,
bool IsDtorCallInCtor);
bool isAccessible(Subobject Subobj, CXXMethodDecl *D);
@@ -6400,16 +6618,16 @@ bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj,
/// Check whether we should delete a special member due to the implicit
/// definition containing a call to a special member of a subobject.
bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
- Subobject Subobj, Sema::SpecialMemberOverloadResult *SMOR,
+ Subobject Subobj, Sema::SpecialMemberOverloadResult SMOR,
bool IsDtorCallInCtor) {
- CXXMethodDecl *Decl = SMOR->getMethod();
+ CXXMethodDecl *Decl = SMOR.getMethod();
FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
int DiagKind = -1;
- if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
+ if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted)
DiagKind = !Decl ? 0 : 1;
- else if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+ else if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
DiagKind = 2;
else if (!isAccessible(Subobj, Decl))
DiagKind = 3;
@@ -6479,7 +6697,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
// -- any direct or virtual base class or non-static data member has a
// type with a destructor that is deleted or inaccessible
if (IsConstructor) {
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
S.LookupSpecialMember(Class, Sema::CXXDestructor,
false, false, false, false, false);
if (shouldDeleteForSubobjectCall(Subobj, SMOR, true))
@@ -6499,23 +6717,20 @@ bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
return false;
// If we have an inheriting constructor, check whether we're calling an
// inherited constructor instead of a default constructor.
- if (ICI) {
- assert(CSM == Sema::CXXDefaultConstructor);
- auto *BaseCtor =
- ICI->findConstructorForBase(BaseClass, cast<CXXConstructorDecl>(MD)
- ->getInheritedConstructor()
- .getConstructor())
- .first;
- if (BaseCtor) {
- if (BaseCtor->isDeleted() && Diagnose) {
- S.Diag(Base->getLocStart(),
- diag::note_deleted_special_member_class_subobject)
- << getEffectiveCSM() << MD->getParent() << /*IsField*/false
- << Base->getType() << /*Deleted*/1 << /*IsDtorCallInCtor*/false;
- S.NoteDeletedFunction(BaseCtor);
- }
- return BaseCtor->isDeleted();
+ Sema::SpecialMemberOverloadResult SMOR = lookupInheritedCtor(BaseClass);
+ if (auto *BaseCtor = SMOR.getMethod()) {
+ // Note that we do not check access along this path; other than that,
+ // this is the same as shouldDeleteForSubobjectCall(Base, BaseCtor, false);
+ // FIXME: Check that the base has a usable destructor! Sink this into
+ // shouldDeleteForClassSubobject.
+ if (BaseCtor->isDeleted() && Diagnose) {
+ S.Diag(Base->getLocStart(),
+ diag::note_deleted_special_member_class_subobject)
+ << getEffectiveCSM() << MD->getParent() << /*IsField*/false
+ << Base->getType() << /*Deleted*/1 << /*IsDtorCallInCtor*/false;
+ S.NoteDeletedFunction(BaseCtor);
}
+ return BaseCtor->isDeleted();
}
return shouldDeleteForClassSubobject(BaseClass, Base, 0);
}
@@ -6564,7 +6779,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
if (FieldType->isReferenceType()) {
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_assign_field)
- << IsMove << MD->getParent() << FD << FieldType << /*Reference*/0;
+ << isMove() << MD->getParent() << FD << FieldType << /*Reference*/0;
return true;
}
if (!FieldRecord && FieldType.isConstQualified()) {
@@ -6572,7 +6787,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
// -- a non-static data member of const non-class type (or array thereof)
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_assign_field)
- << IsMove << MD->getParent() << FD << FD->getType() << /*Const*/1;
+ << isMove() << MD->getParent() << FD << FD->getType() << /*Const*/1;
return true;
}
}
@@ -6743,24 +6958,15 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
SpecialMemberDeletionInfo SMI(*this, MD, CSM, ICI, Diagnose);
- for (auto &BI : RD->bases())
- if ((SMI.IsAssignment || !BI.isVirtual()) &&
- SMI.shouldDeleteForBase(&BI))
- return true;
-
// Per DR1611, do not consider virtual bases of constructors of abstract
- // classes, since we are not going to construct them. For assignment
- // operators, we only assign (and thus only consider) direct bases.
- if ((!RD->isAbstract() || !SMI.IsConstructor) && !SMI.IsAssignment) {
- for (auto &BI : RD->vbases())
- if (SMI.shouldDeleteForBase(&BI))
- return true;
- }
-
- for (auto *FI : RD->fields())
- if (!FI->isInvalidDecl() && !FI->isUnnamedBitfield() &&
- SMI.shouldDeleteForField(FI))
- return true;
+ // classes, since we are not going to construct them.
+ // Per DR1658, do not consider virtual bases of destructors of abstract
+ // classes either.
+ // Per DR2180, for assignment operators we only assign (and thus only
+ // consider) direct bases.
+ if (SMI.visit(SMI.IsAssignment ? SMI.VisitDirectBases
+ : SMI.VisitPotentiallyConstructedBases))
+ return true;
if (SMI.shouldDeleteForAllConstMembers())
return true;
@@ -6874,18 +7080,18 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
case Sema::CXXMoveConstructor:
case Sema::CXXMoveAssignment:
NeedOverloadResolution:
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
lookupCallFromSpecialMember(S, RD, CSM, Quals, ConstRHS);
// The standard doesn't describe how to behave if the lookup is ambiguous.
// We treat it as not making the member non-trivial, just like the standard
// mandates for the default constructor. This should rarely matter, because
// the member will also be deleted.
- if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+ if (SMOR.getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
return true;
- if (!SMOR->getMethod()) {
- assert(SMOR->getKind() ==
+ if (!SMOR.getMethod()) {
+ assert(SMOR.getKind() ==
Sema::SpecialMemberOverloadResult::NoMemberOrDeleted);
return false;
}
@@ -6893,8 +7099,8 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
// We deliberately don't check if we found a deleted special member. We're
// not supposed to!
if (Selected)
- *Selected = SMOR->getMethod();
- return SMOR->getMethod()->isTrivial();
+ *Selected = SMOR.getMethod();
+ return SMOR.getMethod()->isTrivial();
}
llvm_unreachable("unknown special method kind");
@@ -7009,8 +7215,7 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
// [...] nontrivally ownership-qualified types are [...] not trivially
// default constructible, copy constructible, move constructible, copy
// assignable, move assignable, or destructible [...]
- if (S.getLangOpts().ObjCAutoRefCount &&
- FieldType.hasNonTrivialObjCLifetime()) {
+ if (FieldType.hasNonTrivialObjCLifetime()) {
if (Diagnose)
S.Diag(FI->getLocation(), diag::note_nontrivial_objc_ownership)
<< RD << FieldType.getObjCLifetime();
@@ -7340,8 +7545,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList);
- CheckCompletedCXXClass(
- dyn_cast_or_null<CXXRecordDecl>(TagDecl));
+ CheckCompletedCXXClass(dyn_cast_or_null<CXXRecordDecl>(TagDecl));
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -8033,6 +8237,154 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
return Conversion;
}
+namespace {
+/// Utility class to accumulate and print a diagnostic listing the invalid
+/// specifier(s) on a declaration.
+struct BadSpecifierDiagnoser {
+ BadSpecifierDiagnoser(Sema &S, SourceLocation Loc, unsigned DiagID)
+ : S(S), Diagnostic(S.Diag(Loc, DiagID)) {}
+ ~BadSpecifierDiagnoser() {
+ Diagnostic << Specifiers;
+ }
+
+ template<typename T> void check(SourceLocation SpecLoc, T Spec) {
+ return check(SpecLoc, DeclSpec::getSpecifierName(Spec));
+ }
+ void check(SourceLocation SpecLoc, DeclSpec::TST Spec) {
+ return check(SpecLoc,
+ DeclSpec::getSpecifierName(Spec, S.getPrintingPolicy()));
+ }
+ void check(SourceLocation SpecLoc, const char *Spec) {
+ if (SpecLoc.isInvalid()) return;
+ Diagnostic << SourceRange(SpecLoc, SpecLoc);
+ if (!Specifiers.empty()) Specifiers += " ";
+ Specifiers += Spec;
+ }
+
+ Sema &S;
+ Sema::SemaDiagnosticBuilder Diagnostic;
+ std::string Specifiers;
+};
+}
+
+/// Check the validity of a declarator that we parsed for a deduction-guide.
+/// These aren't actually declarators in the grammar, so we need to check that
+/// the user didn't specify any pieces that are not part of the deduction-guide
+/// grammar.
+void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
+ StorageClass &SC) {
+ TemplateName GuidedTemplate = D.getName().TemplateName.get().get();
+ TemplateDecl *GuidedTemplateDecl = GuidedTemplate.getAsTemplateDecl();
+ assert(GuidedTemplateDecl && "missing template decl for deduction guide");
+
+ // C++ [temp.deduct.guide]p3:
+ // A deduction-gide shall be declared in the same scope as the
+ // corresponding class template.
+ if (!CurContext->getRedeclContext()->Equals(
+ GuidedTemplateDecl->getDeclContext()->getRedeclContext())) {
+ Diag(D.getIdentifierLoc(), diag::err_deduction_guide_wrong_scope)
+ << GuidedTemplateDecl;
+ Diag(GuidedTemplateDecl->getLocation(), diag::note_template_decl_here);
+ }
+
+ auto &DS = D.getMutableDeclSpec();
+ // We leave 'friend' and 'virtual' to be rejected in the normal way.
+ if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() ||
+ DS.getStorageClassSpecLoc().isValid() || DS.isInlineSpecified() ||
+ DS.isNoreturnSpecified() || DS.isConstexprSpecified() ||
+ DS.isConceptSpecified()) {
+ BadSpecifierDiagnoser Diagnoser(
+ *this, D.getIdentifierLoc(),
+ diag::err_deduction_guide_invalid_specifier);
+
+ Diagnoser.check(DS.getStorageClassSpecLoc(), DS.getStorageClassSpec());
+ DS.ClearStorageClassSpecs();
+ SC = SC_None;
+
+ // 'explicit' is permitted.
+ Diagnoser.check(DS.getInlineSpecLoc(), "inline");
+ Diagnoser.check(DS.getNoreturnSpecLoc(), "_Noreturn");
+ Diagnoser.check(DS.getConstexprSpecLoc(), "constexpr");
+ Diagnoser.check(DS.getConceptSpecLoc(), "concept");
+ DS.ClearConstexprSpec();
+ DS.ClearConceptSpec();
+
+ Diagnoser.check(DS.getConstSpecLoc(), "const");
+ Diagnoser.check(DS.getRestrictSpecLoc(), "__restrict");
+ Diagnoser.check(DS.getVolatileSpecLoc(), "volatile");
+ Diagnoser.check(DS.getAtomicSpecLoc(), "_Atomic");
+ Diagnoser.check(DS.getUnalignedSpecLoc(), "__unaligned");
+ DS.ClearTypeQualifiers();
+
+ Diagnoser.check(DS.getTypeSpecComplexLoc(), DS.getTypeSpecComplex());
+ Diagnoser.check(DS.getTypeSpecSignLoc(), DS.getTypeSpecSign());
+ Diagnoser.check(DS.getTypeSpecWidthLoc(), DS.getTypeSpecWidth());
+ Diagnoser.check(DS.getTypeSpecTypeLoc(), DS.getTypeSpecType());
+ DS.ClearTypeSpecType();
+ }
+
+ if (D.isInvalidType())
+ return;
+
+ // Check the declarator is simple enough.
+ bool FoundFunction = false;
+ for (const DeclaratorChunk &Chunk : llvm::reverse(D.type_objects())) {
+ if (Chunk.Kind == DeclaratorChunk::Paren)
+ continue;
+ if (Chunk.Kind != DeclaratorChunk::Function || FoundFunction) {
+ Diag(D.getDeclSpec().getLocStart(),
+ diag::err_deduction_guide_with_complex_decl)
+ << D.getSourceRange();
+ break;
+ }
+ if (!Chunk.Fun.hasTrailingReturnType()) {
+ Diag(D.getName().getLocStart(),
+ diag::err_deduction_guide_no_trailing_return_type);
+ break;
+ }
+
+ // Check that the return type is written as a specialization of
+ // the template specified as the deduction-guide's name.
+ ParsedType TrailingReturnType = Chunk.Fun.getTrailingReturnType();
+ TypeSourceInfo *TSI = nullptr;
+ QualType RetTy = GetTypeFromParser(TrailingReturnType, &TSI);
+ assert(TSI && "deduction guide has valid type but invalid return type?");
+ bool AcceptableReturnType = false;
+ bool MightInstantiateToSpecialization = false;
+ if (auto RetTST =
+ TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) {
+ TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
+ bool TemplateMatches =
+ Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
+ if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches)
+ AcceptableReturnType = true;
+ else {
+ // This could still instantiate to the right type, unless we know it
+ // names the wrong class template.
+ auto *TD = SpecifiedName.getAsTemplateDecl();
+ MightInstantiateToSpecialization = !(TD && isa<ClassTemplateDecl>(TD) &&
+ !TemplateMatches);
+ }
+ } else if (!RetTy.hasQualifiers() && RetTy->isDependentType()) {
+ MightInstantiateToSpecialization = true;
+ }
+
+ if (!AcceptableReturnType) {
+ Diag(TSI->getTypeLoc().getLocStart(),
+ diag::err_deduction_guide_bad_trailing_return_type)
+ << GuidedTemplate << TSI->getType() << MightInstantiateToSpecialization
+ << TSI->getTypeLoc().getSourceRange();
+ }
+
+ // Keep going to check that we don't have any inner declarator pieces (we
+ // could still have a function returning a pointer to a function).
+ FoundFunction = true;
+ }
+
+ if (D.isFunctionDefinition())
+ Diag(D.getIdentifierLoc(), diag::err_deduction_guide_defines_function);
+}
+
//===----------------------------------------------------------------------===//
// Namespace Handling
//===----------------------------------------------------------------------===//
@@ -8161,6 +8513,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
Namespc->setInvalidDecl();
ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
+ AddPragmaAttributes(DeclRegionScope, Namespc);
// FIXME: Should we be merging attributes?
if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
@@ -8397,7 +8750,7 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
}
-bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) {
+bool Sema::isInitListConstructor(const FunctionDecl *Ctor) {
// C++ [dcl.init.list]p2:
// A constructor is an initializer-list constructor if its first parameter
// is of type std::initializer_list<E> or reference to possibly cv-qualified
@@ -8613,6 +8966,9 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
Diag(Name.getLocStart(), diag::err_using_decl_template_id)
<< SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc);
return nullptr;
+
+ case UnqualifiedId::IK_DeductionGuideName:
+ llvm_unreachable("cannot parse qualified deduction guide name");
}
DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
@@ -9169,15 +9525,18 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
HasTypenameKeyword, IsInstantiation, SS.getScopeRep(),
dyn_cast<CXXRecordDecl>(CurContext)),
CTK_ErrorRecovery)) {
- // We reject any correction for which ND would be NULL.
- NamedDecl *ND = Corrected.getCorrectionDecl();
-
// We reject candidates where DroppedSpecifier == true, hence the
// literal '0' below.
diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest)
<< NameInfo.getName() << LookupContext << 0
<< SS.getRange());
+ // If we picked a correction with no attached Decl we can't do anything
+ // useful with it, bail out.
+ NamedDecl *ND = Corrected.getCorrectionDecl();
+ if (!ND)
+ return BuildInvalid();
+
// If we corrected to an inheriting constructor, handle it as one.
auto *RD = dyn_cast<CXXRecordDecl>(ND);
if (RD && RD->isInjectedClassName()) {
@@ -9641,6 +10000,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
NewTD->setInvalidDecl();
ProcessDeclAttributeList(S, NewTD, AttrList);
+ AddPragmaAttributes(S, NewTD);
CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
@@ -9816,123 +10176,113 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc,
return AliasDecl;
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
- CXXMethodDecl *MD) {
- CXXRecordDecl *ClassDecl = MD->getParent();
+namespace {
+struct SpecialMemberExceptionSpecInfo
+ : SpecialMemberVisitor<SpecialMemberExceptionSpecInfo> {
+ SourceLocation Loc;
+ Sema::ImplicitExceptionSpecification ExceptSpec;
- // C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
- // exception-specification. [...]
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
+ SpecialMemberExceptionSpecInfo(Sema &S, CXXMethodDecl *MD,
+ Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI,
+ SourceLocation Loc)
+ : SpecialMemberVisitor(S, MD, CSM, ICI), Loc(Loc), ExceptSpec(S) {}
- // Direct base-class constructors.
- for (const auto &B : ClassDecl->bases()) {
- if (B.isVirtual()) // Handled below.
- continue;
-
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
- // If this is a deleted function, add it anyway. This might be conformant
- // with the standard. This might not. I'm not sure. It might not matter.
- if (Constructor)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
+ bool visitBase(CXXBaseSpecifier *Base);
+ bool visitField(FieldDecl *FD);
- // Virtual base-class constructors.
- for (const auto &B : ClassDecl->vbases()) {
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
- // If this is a deleted function, add it anyway. This might be conformant
- // with the standard. This might not. I'm not sure. It might not matter.
- if (Constructor)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
-
- // Field constructors.
- for (auto *F : ClassDecl->fields()) {
- if (F->hasInClassInitializer()) {
- Expr *E = F->getInClassInitializer();
- if (!E)
- // FIXME: It's a little wasteful to build and throw away a
- // CXXDefaultInitExpr here.
- E = BuildCXXDefaultInitExpr(Loc, F).get();
- if (E)
- ExceptSpec.CalledExpr(E);
- } else if (const RecordType *RecordTy
- = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
- CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
- // If this is a deleted function, add it anyway. This might be conformant
- // with the standard. This might not. I'm not sure. It might not matter.
- // In particular, the problem is that this function never gets called. It
- // might just be ill-formed because this function attempts to refer to
- // a deleted function here.
- if (Constructor)
- ExceptSpec.CalledDecl(F->getLocation(), Constructor);
- }
- }
+ void visitClassSubobject(CXXRecordDecl *Class, Subobject Subobj,
+ unsigned Quals);
- return ExceptSpec;
+ void visitSubobjectCall(Subobject Subobj,
+ Sema::SpecialMemberOverloadResult SMOR);
+};
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeInheritingCtorExceptionSpec(SourceLocation Loc,
- CXXConstructorDecl *CD) {
- CXXRecordDecl *ClassDecl = CD->getParent();
+bool SpecialMemberExceptionSpecInfo::visitBase(CXXBaseSpecifier *Base) {
+ auto *RT = Base->getType()->getAs<RecordType>();
+ if (!RT)
+ return false;
- // C++ [except.spec]p14:
- // An inheriting constructor [...] shall have an exception-specification. [...]
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
+ auto *BaseClass = cast<CXXRecordDecl>(RT->getDecl());
+ Sema::SpecialMemberOverloadResult SMOR = lookupInheritedCtor(BaseClass);
+ if (auto *BaseCtor = SMOR.getMethod()) {
+ visitSubobjectCall(Base, BaseCtor);
+ return false;
+ }
- auto Inherited = CD->getInheritedConstructor();
- InheritedConstructorInfo ICI(*this, Loc, Inherited.getShadowDecl());
+ visitClassSubobject(BaseClass, Base, 0);
+ return false;
+}
- // Direct and virtual base-class constructors.
- for (bool VBase : {false, true}) {
- for (CXXBaseSpecifier &B :
- VBase ? ClassDecl->vbases() : ClassDecl->bases()) {
- // Don't visit direct vbases twice.
- if (B.isVirtual() != VBase)
- continue;
+bool SpecialMemberExceptionSpecInfo::visitField(FieldDecl *FD) {
+ if (CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer()) {
+ Expr *E = FD->getInClassInitializer();
+ if (!E)
+ // FIXME: It's a little wasteful to build and throw away a
+ // CXXDefaultInitExpr here.
+ // FIXME: We should have a single context note pointing at Loc, and
+ // this location should be MD->getLocation() instead, since that's
+ // the location where we actually use the default init expression.
+ E = S.BuildCXXDefaultInitExpr(Loc, FD).get();
+ if (E)
+ ExceptSpec.CalledExpr(E);
+ } else if (auto *RT = S.Context.getBaseElementType(FD->getType())
+ ->getAs<RecordType>()) {
+ visitClassSubobject(cast<CXXRecordDecl>(RT->getDecl()), FD,
+ FD->getType().getCVRQualifiers());
+ }
+ return false;
+}
- CXXRecordDecl *BaseClass = B.getType()->getAsCXXRecordDecl();
- if (!BaseClass)
- continue;
+void SpecialMemberExceptionSpecInfo::visitClassSubobject(CXXRecordDecl *Class,
+ Subobject Subobj,
+ unsigned Quals) {
+ FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
+ bool IsMutable = Field && Field->isMutable();
+ visitSubobjectCall(Subobj, lookupIn(Class, Quals, IsMutable));
+}
- CXXConstructorDecl *Constructor =
- ICI.findConstructorForBase(BaseClass, Inherited.getConstructor())
- .first;
- if (!Constructor)
- Constructor = LookupDefaultConstructor(BaseClass);
- if (Constructor)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
+void SpecialMemberExceptionSpecInfo::visitSubobjectCall(
+ Subobject Subobj, Sema::SpecialMemberOverloadResult SMOR) {
+ // Note, if lookup fails, it doesn't matter what exception specification we
+ // choose because the special member will be deleted.
+ if (CXXMethodDecl *MD = SMOR.getMethod())
+ ExceptSpec.CalledDecl(getSubobjectLoc(Subobj), MD);
+}
- // Field constructors.
- for (const auto *F : ClassDecl->fields()) {
- if (F->hasInClassInitializer()) {
- if (Expr *E = F->getInClassInitializer())
- ExceptSpec.CalledExpr(E);
- } else if (const RecordType *RecordTy
- = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
- CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
- if (Constructor)
- ExceptSpec.CalledDecl(F->getLocation(), Constructor);
- }
- }
+static Sema::ImplicitExceptionSpecification
+ComputeDefaultedSpecialMemberExceptionSpec(
+ Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI) {
+ CXXRecordDecl *ClassDecl = MD->getParent();
- return ExceptSpec;
+ // C++ [except.spec]p14:
+ // An implicitly declared special member function (Clause 12) shall have an
+ // exception-specification. [...]
+ SpecialMemberExceptionSpecInfo Info(S, MD, CSM, ICI, Loc);
+ if (ClassDecl->isInvalidDecl())
+ return Info.ExceptSpec;
+
+ // C++1z [except.spec]p7:
+ // [Look for exceptions thrown by] a constructor selected [...] to
+ // initialize a potentially constructed subobject,
+ // C++1z [except.spec]p8:
+ // The exception specification for an implicitly-declared destructor, or a
+ // destructor without a noexcept-specifier, is potentially-throwing if and
+ // only if any of the destructors for any of its potentially constructed
+ // subojects is potentially throwing.
+ // FIXME: We respect the first rule but ignore the "potentially constructed"
+ // in the second rule to resolve a core issue (no number yet) that would have
+ // us reject:
+ // struct A { virtual void f() = 0; virtual ~A() noexcept(false) = 0; };
+ // struct B : A {};
+ // struct C : B { void f(); };
+ // ... due to giving B::~B() a non-throwing exception specification.
+ Info.visit(Info.IsConstructor ? Info.VisitPotentiallyConstructedBases
+ : Info.VisitAllBases);
+
+ return Info.ExceptSpec;
}
namespace {
@@ -9944,19 +10294,34 @@ struct DeclaringSpecialMember {
bool WasAlreadyBeingDeclared;
DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM)
- : S(S), D(RD, CSM), SavedContext(S, RD) {
+ : S(S), D(RD, CSM), SavedContext(S, RD) {
WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second;
if (WasAlreadyBeingDeclared)
// This almost never happens, but if it does, ensure that our cache
// doesn't contain a stale result.
S.SpecialMemberCache.clear();
-
- // FIXME: Register a note to be produced if we encounter an error while
- // declaring the special member.
+ else {
+ // Register a note to be produced if we encounter an error while
+ // declaring the special member.
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::DeclaringSpecialMember;
+ // FIXME: We don't have a location to use here. Using the class's
+ // location maintains the fiction that we declare all special members
+ // with the class, but (1) it's not clear that lying about that helps our
+ // users understand what's going on, and (2) there may be outer contexts
+ // on the stack (some of which are relevant) and printing them exposes
+ // our lies.
+ Ctx.PointOfInstantiation = RD->getLocation();
+ Ctx.Entity = RD;
+ Ctx.SpecialMember = CSM;
+ S.pushCodeSynthesisContext(Ctx);
+ }
}
~DeclaringSpecialMember() {
- if (!WasAlreadyBeingDeclared)
+ if (!WasAlreadyBeingDeclared) {
S.SpecialMembersBeingDeclared.erase(D);
+ S.popCodeSynthesisContext();
+ }
}
/// \brief Are we already trying to declare this special member?
@@ -9978,7 +10343,7 @@ void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) {
R.resolveKind();
R.suppressDiagnostics();
- CheckFunctionDeclaration(S, FD, R, /*IsExplicitSpecialization*/false);
+ CheckFunctionDeclaration(S, FD, R, /*IsMemberSpecialization*/false);
}
CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
@@ -10051,32 +10416,33 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
!Constructor->doesThisDeclarationHaveABody() &&
!Constructor->isDeleted()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
+ if (Constructor->willHaveBody() || Constructor->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = Constructor->getParent();
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
SynthesizedFunctionScope Scope(*this, Constructor);
- DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
- Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
- Constructor->setInvalidDecl();
- return;
- }
// The exception specification is needed because we are defining the
// function.
ResolveExceptionSpec(CurrentLocation,
Constructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
+ if (SetCtorInitializers(Constructor, /*AnyErrors=*/false)) {
+ Constructor->setInvalidDecl();
+ return;
+ }
SourceLocation Loc = Constructor->getLocEnd().isValid()
? Constructor->getLocEnd()
: Constructor->getLocation();
Constructor->setBody(new (Context) CompoundStmt(Loc));
-
Constructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
@@ -10186,9 +10552,22 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
assert(Constructor->getInheritedConstructor() &&
!Constructor->doesThisDeclarationHaveABody() &&
!Constructor->isDeleted());
- if (Constructor->isInvalidDecl())
+ if (Constructor->willHaveBody() || Constructor->isInvalidDecl())
return;
+ // Initializations are performed "as if by a defaulted default constructor",
+ // so enter the appropriate scope.
+ SynthesizedFunctionScope Scope(*this, Constructor);
+
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ Constructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
ConstructorUsingShadowDecl *Shadow =
Constructor->getInheritedConstructor().getShadowDecl();
CXXConstructorDecl *InheritedCtor =
@@ -10203,11 +10582,6 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *RD = Shadow->getParent();
SourceLocation InitLoc = Shadow->getLocation();
- // Initializations are performed "as if by a defaulted default constructor",
- // so enter the appropriate scope.
- SynthesizedFunctionScope Scope(*this, Constructor);
- DiagnosticErrorTrap Trap(Diags);
-
// Build explicit initializers for all base classes from which the
// constructor was inherited.
SmallVector<CXXCtorInitializer*, 8> Inits;
@@ -10238,22 +10612,13 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
// We now proceed as if for a defaulted default constructor, with the relevant
// initializers replaced.
- bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits);
- if (HadError || Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD;
+ if (SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits)) {
Constructor->setInvalidDecl();
return;
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- Constructor->getType()->castAs<FunctionProtoType>());
-
Constructor->setBody(new (Context) CompoundStmt(InitLoc));
-
Constructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
@@ -10262,45 +10627,6 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
DiagnoseUninitializedFields(*this, Constructor);
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
- CXXRecordDecl *ClassDecl = MD->getParent();
-
- // C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have
- // an exception-specification.
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
-
- // Direct base-class destructors.
- for (const auto &B : ClassDecl->bases()) {
- if (B.isVirtual()) // Handled below.
- continue;
-
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>())
- ExceptSpec.CalledDecl(B.getLocStart(),
- LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
- }
-
- // Virtual base-class destructors.
- for (const auto &B : ClassDecl->vbases()) {
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>())
- ExceptSpec.CalledDecl(B.getLocStart(),
- LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
- }
-
- // Field destructors.
- for (const auto *F : ClassDecl->fields()) {
- if (const RecordType *RecordTy
- = Context.getBaseElementType(F->getType())->getAs<RecordType>())
- ExceptSpec.CalledDecl(F->getLocation(),
- LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
- }
-
- return ExceptSpec;
-}
-
CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
// C++ [class.dtor]p2:
// If a class has no user-declared destructor, a destructor is
@@ -10368,37 +10694,36 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
!Destructor->doesThisDeclarationHaveABody() &&
!Destructor->isDeleted()) &&
"DefineImplicitDestructor - call it for implicit default dtor");
+ if (Destructor->willHaveBody() || Destructor->isInvalidDecl())
+ return;
+
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
- if (Destructor->isInvalidDecl())
- return;
-
SynthesizedFunctionScope Scope(*this, Destructor);
- DiagnosticErrorTrap Trap(Diags);
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ Destructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
Destructor->getParent());
- if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXDestructor << Context.getTagDeclType(ClassDecl);
-
+ if (CheckDestructor(Destructor)) {
Destructor->setInvalidDecl();
return;
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- Destructor->getType()->castAs<FunctionProtoType>());
-
SourceLocation Loc = Destructor->getLocEnd().isValid()
? Destructor->getLocEnd()
: Destructor->getLocation();
Destructor->setBody(new (Context) CompoundStmt(Loc));
Destructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Destructor);
@@ -10852,7 +11177,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
= new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc),
IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
BO_NE, S.Context.BoolTy,
- VK_RValue, OK_Ordinary, Loc, false);
+ VK_RValue, OK_Ordinary, Loc, FPOptions());
// Create the pre-increment of the iteration variable.
Expr *Increment
@@ -10887,62 +11212,6 @@ buildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
return Result;
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD) {
- CXXRecordDecl *ClassDecl = MD->getParent();
-
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
-
- const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();
- assert(T->getNumParams() == 1 && "not a copy assignment op");
- unsigned ArgQuals =
- T->getParamType(0).getNonReferenceType().getCVRQualifiers();
-
- // C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
- // exception-specification. [...]
-
- // It is unspecified whether or not an implicit copy assignment operator
- // attempts to deduplicate calls to assignment operators of virtual bases are
- // made. As such, this exception specification is effectively unspecified.
- // Based on a similar decision made for constness in C++0x, we're erring on
- // the side of assuming such calls to be made regardless of whether they
- // actually happen.
- for (const auto &Base : ClassDecl->bases()) {
- if (Base.isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
- ArgQuals, false, 0))
- ExceptSpec.CalledDecl(Base.getLocStart(), CopyAssign);
- }
-
- for (const auto &Base : ClassDecl->vbases()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
- ArgQuals, false, 0))
- ExceptSpec.CalledDecl(Base.getLocStart(), CopyAssign);
- }
-
- for (const auto *Field : ClassDecl->fields()) {
- QualType FieldType = Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (CXXMethodDecl *CopyAssign =
- LookupCopyingAssignment(FieldClassDecl,
- ArgQuals | FieldType.getCVRQualifiers(),
- false, 0))
- ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign);
- }
- }
-
- return ExceptSpec;
-}
-
CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// Note: The following rules are largely analoguous to the copy
// constructor rules. Note that virtual bases are not taken into account
@@ -11022,8 +11291,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
/// Diagnose an implicit copy operation for a class which is odr-used, but
/// which is deprecated because the class has a user-declared copy constructor,
/// copy assignment operator, or destructor.
-static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp,
- SourceLocation UseLoc) {
+static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
assert(CopyOp->isImplicit());
CXXRecordDecl *RD = CopyOp->getParent();
@@ -11062,10 +11330,6 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp,
diag::warn_deprecated_copy_operation)
<< RD << /*copy assignment*/!isa<CXXConstructorDecl>(CopyOp)
<< /*destructor*/isa<CXXDestructorDecl>(UserDeclaredOperation);
- S.Diag(UseLoc, diag::note_member_synthesized_at)
- << (isa<CXXConstructorDecl>(CopyOp) ? Sema::CXXCopyConstructor
- : Sema::CXXCopyAssignment)
- << RD;
}
}
@@ -11077,25 +11341,31 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
!CopyAssignOperator->doesThisDeclarationHaveABody() &&
!CopyAssignOperator->isDeleted()) &&
"DefineImplicitCopyAssignment called for wrong function");
+ if (CopyAssignOperator->willHaveBody() || CopyAssignOperator->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
-
- if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) {
+ if (ClassDecl->isInvalidDecl()) {
CopyAssignOperator->setInvalidDecl();
return;
}
+ SynthesizedFunctionScope Scope(*this, CopyAssignOperator);
+
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ CopyAssignOperator->getType()->castAs<FunctionProtoType>());
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
// C++11 [class.copy]p18:
// The [definition of an implicitly declared copy assignment operator] is
// deprecated if the class has a user-declared copy constructor or a
// user-declared destructor.
if (getLangOpts().CPlusPlus11 && CopyAssignOperator->isImplicit())
- diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator, CurrentLocation);
-
- CopyAssignOperator->markUsed(Context);
-
- SynthesizedFunctionScope Scope(*this, CopyAssignOperator);
- DiagnosticErrorTrap Trap(Diags);
+ diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator);
// C++0x [class.copy]p30:
// The implicitly-defined or explicitly-defaulted copy assignment operator
@@ -11161,8 +11431,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
/*CopyingBaseSubobject=*/true,
/*Copying=*/true);
if (Copy.isInvalid()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
CopyAssignOperator->setInvalidDecl();
return;
}
@@ -11188,8 +11456,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
@@ -11200,8 +11466,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
@@ -11234,8 +11498,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
/*CopyingBaseSubobject=*/false,
/*Copying=*/true);
if (Copy.isInvalid()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
CopyAssignOperator->setInvalidDecl();
return;
}
@@ -11251,22 +11513,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
if (Return.isInvalid())
Invalid = true;
- else {
+ else
Statements.push_back(Return.getAs<Stmt>());
-
- if (Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyAssignment << Context.getTagDeclType(ClassDecl);
- Invalid = true;
- }
- }
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- CopyAssignOperator->getType()->castAs<FunctionProtoType>());
-
if (Invalid) {
CopyAssignOperator->setInvalidDecl();
return;
@@ -11280,65 +11530,13 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
CopyAssignOperator->setBody(Body.getAs<Stmt>());
+ CopyAssignOperator->markUsed(Context);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyAssignOperator);
}
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) {
- CXXRecordDecl *ClassDecl = MD->getParent();
-
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
-
- // C++0x [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
- // exception-specification. [...]
-
- // It is unspecified whether or not an implicit move assignment operator
- // attempts to deduplicate calls to assignment operators of virtual bases are
- // made. As such, this exception specification is effectively unspecified.
- // Based on a similar decision made for constness in C++0x, we're erring on
- // the side of assuming such calls to be made regardless of whether they
- // actually happen.
- // Note that a move constructor is not implicitly declared when there are
- // virtual bases, but it can still be user-declared and explicitly defaulted.
- for (const auto &Base : ClassDecl->bases()) {
- if (Base.isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
- 0, false, 0))
- ExceptSpec.CalledDecl(Base.getLocStart(), MoveAssign);
- }
-
- for (const auto &Base : ClassDecl->vbases()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
- 0, false, 0))
- ExceptSpec.CalledDecl(Base.getLocStart(), MoveAssign);
- }
-
- for (const auto *Field : ClassDecl->fields()) {
- QualType FieldType = Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (CXXMethodDecl *MoveAssign =
- LookupMovingAssignment(FieldClassDecl,
- FieldType.getCVRQualifiers(),
- false, 0))
- ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign);
- }
- }
-
- return ExceptSpec;
-}
-
CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
assert(ClassDecl->needsImplicitMoveAssignment());
@@ -11449,13 +11647,13 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
// If we're not actually going to call a move assignment for this base,
// or the selected move assignment is trivial, skip it.
- Sema::SpecialMemberOverloadResult *SMOR =
+ Sema::SpecialMemberOverloadResult SMOR =
S.LookupSpecialMember(Base, Sema::CXXMoveAssignment,
/*ConstArg*/false, /*VolatileArg*/false,
/*RValueThis*/true, /*ConstThis*/false,
/*VolatileThis*/false);
- if (!SMOR->getMethod() || SMOR->getMethod()->isTrivial() ||
- !SMOR->getMethod()->isMoveAssignmentOperator())
+ if (!SMOR.getMethod() || SMOR.getMethod()->isTrivial() ||
+ !SMOR.getMethod()->isMoveAssignmentOperator())
continue;
if (BaseSpec->isVirtual()) {
@@ -11486,7 +11684,7 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
// Only walk over bases that have defaulted move assignment operators.
// We assume that any user-provided move assignment operator handles
// the multiple-moves-of-vbase case itself somehow.
- if (!SMOR->getMethod()->isDefaulted())
+ if (!SMOR.getMethod()->isDefaulted())
continue;
// We're going to move the base classes of Base. Add them to the list.
@@ -11505,19 +11703,15 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
!MoveAssignOperator->doesThisDeclarationHaveABody() &&
!MoveAssignOperator->isDeleted()) &&
"DefineImplicitMoveAssignment called for wrong function");
+ if (MoveAssignOperator->willHaveBody() || MoveAssignOperator->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent();
-
- if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) {
+ if (ClassDecl->isInvalidDecl()) {
MoveAssignOperator->setInvalidDecl();
return;
}
- MoveAssignOperator->markUsed(Context);
-
- SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
- DiagnosticErrorTrap Trap(Diags);
-
// C++0x [class.copy]p28:
// The implicitly-defined or move assignment operator for a non-union class
// X performs memberwise move assignment of its subobjects. The direct base
@@ -11530,6 +11724,16 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// from a virtual base more than once.
checkMoveAssignmentForRepeatedMove(*this, ClassDecl, CurrentLocation);
+ SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
+
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ MoveAssignOperator->getType()->castAs<FunctionProtoType>());
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
// The statements that form the synthesized function body.
SmallVector<Stmt*, 8> Statements;
@@ -11594,8 +11798,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
/*CopyingBaseSubobject=*/true,
/*Copying=*/false);
if (Move.isInvalid()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
MoveAssignOperator->setInvalidDecl();
return;
}
@@ -11621,8 +11823,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
@@ -11633,8 +11833,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
Invalid = true;
continue;
}
@@ -11670,8 +11868,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
/*CopyingBaseSubobject=*/false,
/*Copying=*/false);
if (Move.isInvalid()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
MoveAssignOperator->setInvalidDecl();
return;
}
@@ -11688,22 +11884,10 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
if (Return.isInvalid())
Invalid = true;
- else {
+ else
Statements.push_back(Return.getAs<Stmt>());
-
- if (Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveAssignment << Context.getTagDeclType(ClassDecl);
- Invalid = true;
- }
- }
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- MoveAssignOperator->getType()->castAs<FunctionProtoType>());
-
if (Invalid) {
MoveAssignOperator->setInvalidDecl();
return;
@@ -11717,58 +11901,13 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
MoveAssignOperator->setBody(Body.getAs<Stmt>());
+ MoveAssignOperator->markUsed(Context);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(MoveAssignOperator);
}
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) {
- CXXRecordDecl *ClassDecl = MD->getParent();
-
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
-
- const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();
- assert(T->getNumParams() >= 1 && "not a copy ctor");
- unsigned Quals = T->getParamType(0).getNonReferenceType().getCVRQualifiers();
-
- // C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
- // exception-specification. [...]
- for (const auto &Base : ClassDecl->bases()) {
- // Virtual bases are handled below.
- if (Base.isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXConstructorDecl *CopyConstructor =
- LookupCopyingConstructor(BaseClassDecl, Quals))
- ExceptSpec.CalledDecl(Base.getLocStart(), CopyConstructor);
- }
- for (const auto &Base : ClassDecl->vbases()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- if (CXXConstructorDecl *CopyConstructor =
- LookupCopyingConstructor(BaseClassDecl, Quals))
- ExceptSpec.CalledDecl(Base.getLocStart(), CopyConstructor);
- }
- for (const auto *Field : ClassDecl->fields()) {
- QualType FieldType = Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (CXXConstructorDecl *CopyConstructor =
- LookupCopyingConstructor(FieldClassDecl,
- Quals | FieldType.getCVRQualifiers()))
- ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor);
- }
- }
-
- return ExceptSpec;
-}
-
CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CXXRecordDecl *ClassDecl) {
// C++ [class.copy]p4:
@@ -11838,8 +11977,10 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, CopyConstructor);
- if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
+ if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) {
+ ClassDecl->setImplicitCopyConstructorIsDeleted();
SetDeclDeleted(CopyConstructor, ClassLoc);
+ }
if (S)
PushOnScopeChains(CopyConstructor, S, false);
@@ -11849,30 +11990,37 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *CopyConstructor) {
+ CXXConstructorDecl *CopyConstructor) {
assert((CopyConstructor->isDefaulted() &&
CopyConstructor->isCopyConstructor() &&
!CopyConstructor->doesThisDeclarationHaveABody() &&
!CopyConstructor->isDeleted()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
+ if (CopyConstructor->willHaveBody() || CopyConstructor->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
+ SynthesizedFunctionScope Scope(*this, CopyConstructor);
+
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ CopyConstructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
// C++11 [class.copy]p7:
// The [definition of an implicitly declared copy constructor] is
// deprecated if the class has a user-declared copy assignment operator
// or a user-declared destructor.
if (getLangOpts().CPlusPlus11 && CopyConstructor->isImplicit())
- diagnoseDeprecatedCopyOperation(*this, CopyConstructor, CurrentLocation);
+ diagnoseDeprecatedCopyOperation(*this, CopyConstructor);
- SynthesizedFunctionScope Scope(*this, CopyConstructor);
- DiagnosticErrorTrap Trap(Diags);
-
- if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false) ||
- Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
+ if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false)) {
CopyConstructor->setInvalidDecl();
} else {
SourceLocation Loc = CopyConstructor->getLocEnd().isValid()
@@ -11881,80 +12029,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
Sema::CompoundScopeRAII CompoundScope(*this);
CopyConstructor->setBody(
ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>());
+ CopyConstructor->markUsed(Context);
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- CopyConstructor->getType()->castAs<FunctionProtoType>());
-
- CopyConstructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
-
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyConstructor);
}
}
-Sema::ImplicitExceptionSpecification
-Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD) {
- CXXRecordDecl *ClassDecl = MD->getParent();
-
- // C++ [except.spec]p14:
- // An implicitly declared special member function (Clause 12) shall have an
- // exception-specification. [...]
- ImplicitExceptionSpecification ExceptSpec(*this);
- if (ClassDecl->isInvalidDecl())
- return ExceptSpec;
-
- // Direct base-class constructors.
- for (const auto &B : ClassDecl->bases()) {
- if (B.isVirtual()) // Handled below.
- continue;
-
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor =
- LookupMovingConstructor(BaseClassDecl, 0);
- // If this is a deleted function, add it anyway. This might be conformant
- // with the standard. This might not. I'm not sure. It might not matter.
- if (Constructor)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
-
- // Virtual base-class constructors.
- for (const auto &B : ClassDecl->vbases()) {
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- CXXConstructorDecl *Constructor =
- LookupMovingConstructor(BaseClassDecl, 0);
- // If this is a deleted function, add it anyway. This might be conformant
- // with the standard. This might not. I'm not sure. It might not matter.
- if (Constructor)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
-
- // Field constructors.
- for (const auto *F : ClassDecl->fields()) {
- QualType FieldType = Context.getBaseElementType(F->getType());
- if (CXXRecordDecl *FieldRecDecl = FieldType->getAsCXXRecordDecl()) {
- CXXConstructorDecl *Constructor =
- LookupMovingConstructor(FieldRecDecl, FieldType.getCVRQualifiers());
- // If this is a deleted function, add it anyway. This might be conformant
- // with the standard. This might not. I'm not sure. It might not matter.
- // In particular, the problem is that this function never gets called. It
- // might just be ill-formed because this function attempts to refer to
- // a deleted function here.
- if (Constructor)
- ExceptSpec.CalledDecl(F->getLocation(), Constructor);
- }
- }
-
- return ExceptSpec;
-}
-
CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
CXXRecordDecl *ClassDecl) {
assert(ClassDecl->needsImplicitMoveConstructor());
@@ -12031,41 +12113,41 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
}
void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *MoveConstructor) {
+ CXXConstructorDecl *MoveConstructor) {
assert((MoveConstructor->isDefaulted() &&
MoveConstructor->isMoveConstructor() &&
!MoveConstructor->doesThisDeclarationHaveABody() &&
!MoveConstructor->isDeleted()) &&
"DefineImplicitMoveConstructor - call it for implicit move ctor");
+ if (MoveConstructor->willHaveBody() || MoveConstructor->isInvalidDecl())
+ return;
CXXRecordDecl *ClassDecl = MoveConstructor->getParent();
assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor");
SynthesizedFunctionScope Scope(*this, MoveConstructor);
- DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false) ||
- Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXMoveConstructor << Context.getTagDeclType(ClassDecl);
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ MoveConstructor->getType()->castAs<FunctionProtoType>());
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
+ if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false)) {
MoveConstructor->setInvalidDecl();
- } else {
+ } else {
SourceLocation Loc = MoveConstructor->getLocEnd().isValid()
? MoveConstructor->getLocEnd()
: MoveConstructor->getLocation();
Sema::CompoundScopeRAII CompoundScope(*this);
MoveConstructor->setBody(ActOnCompoundStmt(
Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>());
+ MoveConstructor->markUsed(Context);
}
- // The exception specification is needed because we are defining the
- // function.
- ResolveExceptionSpec(CurrentLocation,
- MoveConstructor->getType()->castAs<FunctionProtoType>());
-
- MoveConstructor->markUsed(Context);
- MarkVTableUsed(CurrentLocation, ClassDecl);
-
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(MoveConstructor);
}
@@ -12078,6 +12160,8 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
void Sema::DefineImplicitLambdaToFunctionPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv) {
+ SynthesizedFunctionScope Scope(*this, Conv);
+
CXXRecordDecl *Lambda = Conv->getParent();
CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
// If we are defining a specialization of a conversion to function-ptr
@@ -12100,6 +12184,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
"Conversion operator must have a corresponding call operator");
CallOp = cast<CXXMethodDecl>(CallOpSpec);
}
+
// Mark the call operator referenced (and add to pending instantiations
// if necessary).
// For both the conversion and static-invoker template specializations
@@ -12107,9 +12192,6 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// to the PendingInstantiations.
MarkFunctionReferenced(CurrentLocation, CallOp);
- SynthesizedFunctionScope Scope(*this, Conv);
- DiagnosticErrorTrap Trap(Diags);
-
// Retrieve the static invoker...
CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();
// ... and get the corresponding specialization for a generic lambda.
@@ -12147,7 +12229,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
L->CompletedImplicitDefinition(Invoker);
- }
+ }
}
@@ -12158,10 +12240,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
{
assert(!Conv->getParent()->isGenericLambda());
- Conv->markUsed(Context);
-
SynthesizedFunctionScope Scope(*this, Conv);
- DiagnosticErrorTrap Trap(Diags);
// Copy-initialize the lambda object as needed to capture it.
Expr *This = ActOnCXXThis(CurrentLocation).get();
@@ -12198,8 +12277,9 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
// Set the body of the conversion function.
Stmt *ReturnS = Return.get();
Conv->setBody(new (Context) CompoundStmt(Context, ReturnS,
- Conv->getLocation(),
+ Conv->getLocation(),
Conv->getLocation()));
+ Conv->markUsed(Context);
// We're done; notify the mutation listener, if any.
if (ASTMutationListener *L = getASTMutationListener()) {
@@ -12750,7 +12830,7 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef,
PmArgs->getType()->getAs<TemplateTypeParmType>();
if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
TArgs->getIndex() == PmType->getIndex()) {
- if (SemaRef.ActiveTemplateInstantiations.empty())
+ if (!SemaRef.inTemplateInstantiation())
SemaRef.Diag(TpDecl->getLocation(),
diag::ext_string_literal_operator_template);
return false;
@@ -13076,7 +13156,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
if (!Invalid && !ExDeclType->isDependentType()) {
if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
// Insulate this from anything else we might currently be parsing.
- EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
+ EnterExpressionEvaluationContext scope(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated);
// C++ [except.handle]p16:
// The object declared in an exception-declaration or, if the
@@ -13221,6 +13302,14 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
}
}
+ ExprResult FullAssertExpr = ActOnFinishFullExpr(AssertExpr, StaticAssertLoc,
+ /*DiscardedValue*/false,
+ /*IsConstexpr*/true);
+ if (FullAssertExpr.isInvalid())
+ Failed = true;
+ else
+ AssertExpr = FullAssertExpr.get();
+
Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc,
AssertExpr, AssertMessage, RParenLoc,
Failed);
@@ -13245,10 +13334,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
// for a class.*
//
// * The class-key of the elaborated-type-specifier is required.
- if (!ActiveTemplateInstantiations.empty()) {
- // Do not complain about the form of friend template types during
- // template instantiation; we will already have complained when the
- // template was declared.
+ if (!CodeSynthesisContexts.empty()) {
+ // Do not complain about the form of friend template types during any kind
+ // of code synthesis. For template instantiation, we will have complained
+ // when the template was defined.
} else {
if (!T->isElaboratedTypeSpecifier()) {
// If we evaluated the type to a record type, suggest putting
@@ -13313,13 +13402,13 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
MultiTemplateParamsArg TempParamLists) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
- bool isExplicitSpecialization = false;
+ bool IsMemberSpecialization = false;
bool Invalid = false;
if (TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
TagLoc, NameLoc, SS, nullptr, TempParamLists, /*friend*/ true,
- isExplicitSpecialization, Invalid)) {
+ IsMemberSpecialization, Invalid)) {
if (TemplateParams->size() > 0) {
// This is a declaration of a class template.
if (Invalid)
@@ -13334,7 +13423,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
<< TypeWithKeyword::getTagTypeKindName(Kind) << Name;
- isExplicitSpecialization = true;
+ IsMemberSpecialization = true;
}
}
@@ -13364,7 +13453,8 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
/*ScopedEnumKWLoc=*/SourceLocation(),
/*ScopedEnumUsesClassTag=*/false,
/*UnderlyingType=*/TypeResult(),
- /*IsTypeSpecifier=*/false);
+ /*IsTypeSpecifier=*/false,
+ /*IsTemplateParamOrArg=*/false);
}
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
@@ -13744,6 +13834,9 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
case UnqualifiedId::IK_ConversionFunctionId:
DiagArg = 2;
break;
+ case UnqualifiedId::IK_DeductionGuideName:
+ DiagArg = 3;
+ break;
case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_ImplicitSelfParam:
case UnqualifiedId::IK_LiteralOperatorId:
@@ -13845,6 +13938,9 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
return;
}
+ // Deleted function does not have a body.
+ Fn->setWillHaveBody(false);
+
if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
// Don't consider the implicit declaration we generate for explicit
// specializations. FIXME: Do not generate these implicit declarations.
@@ -13923,6 +14019,11 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
MD->setDefaulted();
MD->setExplicitlyDefaulted();
+ // Unset that we will have a body for this function. We might not,
+ // if it turns out to be trivial, and we don't need this marking now
+ // that we've marked it as defaulted.
+ MD->setWillHaveBody(false);
+
// If this definition appears within the record, do the checking when
// the record is complete.
const FunctionDecl *Primary = MD;
@@ -14157,7 +14258,8 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// new expression evaluation context that is associated with this static
// data member.
if (isStaticDataMember(D))
- PushExpressionEvaluationContext(PotentiallyEvaluated, D);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated, D);
}
/// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an
@@ -14619,6 +14721,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
case EST_ComputedNoexcept:
if (!Finder.TraverseStmt(Proto->getNoexceptExpr()))
return true;
+ LLVM_FALLTHROUGH;
case EST_Dynamic:
for (const auto &E : Proto->exceptions()) {
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
index b43e5b9..9675730 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
@@ -248,18 +248,41 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
return false;
}
-static void DiagnoseObjCImplementedDeprecations(Sema &S,
- NamedDecl *ND,
- SourceLocation ImplLoc,
- int select) {
- if (ND && ND->isDeprecated()) {
- S.Diag(ImplLoc, diag::warn_deprecated_def) << select;
- if (select == 0)
+static void DiagnoseObjCImplementedDeprecations(Sema &S, const NamedDecl *ND,
+ SourceLocation ImplLoc) {
+ if (!ND)
+ return;
+ bool IsCategory = false;
+ AvailabilityResult Availability = ND->getAvailability();
+ if (Availability != AR_Deprecated) {
+ if (isa<ObjCMethodDecl>(ND)) {
+ if (Availability != AR_Unavailable)
+ return;
+ // Warn about implementing unavailable methods.
+ S.Diag(ImplLoc, diag::warn_unavailable_def);
S.Diag(ND->getLocation(), diag::note_method_declared_at)
- << ND->getDeclName();
- else
- S.Diag(ND->getLocation(), diag::note_previous_decl) << "class";
+ << ND->getDeclName();
+ return;
+ }
+ if (const auto *CD = dyn_cast<ObjCCategoryDecl>(ND)) {
+ if (!CD->getClassInterface()->isDeprecated())
+ return;
+ ND = CD->getClassInterface();
+ IsCategory = true;
+ } else
+ return;
}
+ S.Diag(ImplLoc, diag::warn_deprecated_def)
+ << (isa<ObjCMethodDecl>(ND)
+ ? /*Method*/ 0
+ : isa<ObjCCategoryDecl>(ND) || IsCategory ? /*Category*/ 2
+ : /*Class*/ 1);
+ if (isa<ObjCMethodDecl>(ND))
+ S.Diag(ND->getLocation(), diag::note_method_declared_at)
+ << ND->getDeclName();
+ else
+ S.Diag(ND->getLocation(), diag::note_previous_decl)
+ << (isa<ObjCCategoryDecl>(ND) ? "category" : "class");
}
/// AddAnyMethodToGlobalPool - Add any method, instance or factory to global
@@ -384,9 +407,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// No need to issue deprecated warning if deprecated mehod in class/category
// is being implemented in its own implementation (no overriding is involved).
if (!ImplDeclOfMethodDecl || ImplDeclOfMethodDecl != ImplDeclOfMethodDef)
- DiagnoseObjCImplementedDeprecations(*this,
- dyn_cast<NamedDecl>(IMD),
- MDecl->getLocation(), 0);
+ DiagnoseObjCImplementedDeprecations(*this, IMD, MDecl->getLocation());
}
if (MDecl->getMethodFamily() == OMF_init) {
@@ -457,7 +478,10 @@ static void diagnoseUseOfProtocols(Sema &TheSema,
// Diagnose availability in the context of the ObjC container.
Sema::ContextRAII SavedContext(TheSema, CD);
for (unsigned i = 0; i < NumProtoRefs; ++i) {
- (void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i]);
+ (void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i],
+ /*UnknownObjCClass=*/nullptr,
+ /*ObjCPropertyAccess=*/false,
+ /*AvoidPartialAvailabilityChecks=*/true);
}
}
@@ -992,6 +1016,7 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc,
if (AttrList)
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
+ AddPragmaAttributes(TUScope, IDecl);
PushOnScopeChains(IDecl, TUScope);
// Start the definition of this class. If we're in a redefinition case, there
@@ -1175,7 +1200,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
-
+ AddPragmaAttributes(TUScope, PDecl);
+
// Merge attributes from previous declarations.
if (PrevDecl)
mergeDeclAttributes(PDecl, PrevDecl);
@@ -1705,7 +1731,8 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
if (attrList)
ProcessDeclAttributeList(TUScope, PDecl, attrList);
-
+ AddPragmaAttributes(TUScope, PDecl);
+
if (PrevDecl)
mergeDeclAttributes(PDecl, PrevDecl);
@@ -1724,7 +1751,8 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
Decl * const *ProtoRefs,
unsigned NumProtoRefs,
const SourceLocation *ProtoLocs,
- SourceLocation EndProtoLoc) {
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
ObjCCategoryDecl *CDecl;
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
@@ -1801,6 +1829,10 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
NumProtoRefs, Context);
}
+ if (AttrList)
+ ProcessDeclAttributeList(TUScope, CDecl, AttrList);
+ AddPragmaAttributes(TUScope, CDecl);
+
CheckObjCDeclScope(CDecl);
return ActOnObjCContainerStartDefinition(CDecl);
}
@@ -1842,10 +1874,6 @@ Decl *Sema::ActOnStartCategoryImplementation(
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
- // If the interface is deprecated/unavailable, warn/error about it.
- if (IDecl)
- DiagnoseUseOfDecl(IDecl, ClassLoc);
-
// If the interface has the objc_runtime_visible attribute, we
// cannot implement a category for it.
if (IDecl && IDecl->hasAttr<ObjCRuntimeVisibleAttr>()) {
@@ -1865,9 +1893,8 @@ Decl *Sema::ActOnStartCategoryImplementation(
CatIDecl->setImplementation(CDecl);
// Warn on implementating category of deprecated class under
// -Wdeprecated-implementations flag.
- DiagnoseObjCImplementedDeprecations(*this,
- dyn_cast<NamedDecl>(IDecl),
- CDecl->getLocation(), 2);
+ DiagnoseObjCImplementedDeprecations(*this, CatIDecl,
+ CDecl->getLocation());
}
}
@@ -1948,6 +1975,7 @@ Decl *Sema::ActOnStartClassImplementation(
ClassName, /*typeParamList=*/nullptr,
/*PrevDecl=*/nullptr, ClassLoc,
true);
+ AddPragmaAttributes(TUScope, IDecl);
IDecl->startDefinition();
if (SDecl) {
IDecl->setSuperClass(Context.getTrivialTypeSourceInfo(
@@ -1986,9 +2014,7 @@ Decl *Sema::ActOnStartClassImplementation(
PushOnScopeChains(IMPDecl, TUScope);
// Warn on implementating deprecated class under
// -Wdeprecated-implementations flag.
- DiagnoseObjCImplementedDeprecations(*this,
- dyn_cast<NamedDecl>(IDecl),
- IMPDecl->getLocation(), 1);
+ DiagnoseObjCImplementedDeprecations(*this, IDecl, IMPDecl->getLocation());
}
// If the superclass has the objc_runtime_visible attribute, we
@@ -3037,7 +3063,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
ClassName, TypeParams, PrevIDecl,
IdentLocs[i]);
IDecl->setAtEndRange(IdentLocs[i]);
-
+
PushOnScopeChains(IDecl, TUScope);
CheckObjCDeclScope(IDecl);
DeclsInGroup.push_back(IDecl);
@@ -4302,6 +4328,49 @@ static void mergeInterfaceMethodToImpl(Sema &S,
}
}
+/// Verify that the method parameters/return value have types that are supported
+/// by the x86 target.
+static void checkObjCMethodX86VectorTypes(Sema &SemaRef,
+ const ObjCMethodDecl *Method) {
+ assert(SemaRef.getASTContext().getTargetInfo().getTriple().getArch() ==
+ llvm::Triple::x86 &&
+ "x86-specific check invoked for a different target");
+ SourceLocation Loc;
+ QualType T;
+ for (const ParmVarDecl *P : Method->parameters()) {
+ if (P->getType()->isVectorType()) {
+ Loc = P->getLocStart();
+ T = P->getType();
+ break;
+ }
+ }
+ if (Loc.isInvalid()) {
+ if (Method->getReturnType()->isVectorType()) {
+ Loc = Method->getReturnTypeSourceRange().getBegin();
+ T = Method->getReturnType();
+ } else
+ return;
+ }
+
+ // Vector parameters/return values are not supported by objc_msgSend on x86 in
+ // iOS < 9 and macOS < 10.11.
+ const auto &Triple = SemaRef.getASTContext().getTargetInfo().getTriple();
+ VersionTuple AcceptedInVersion;
+ if (Triple.getOS() == llvm::Triple::IOS)
+ AcceptedInVersion = VersionTuple(/*Major=*/9);
+ else if (Triple.isMacOSX())
+ AcceptedInVersion = VersionTuple(/*Major=*/10, /*Minor=*/11);
+ else
+ return;
+ if (SemaRef.getASTContext().getTargetInfo().getPlatformMinVersion() >=
+ AcceptedInVersion)
+ return;
+ SemaRef.Diag(Loc, diag::err_objc_method_unsupported_param_ret_type)
+ << T << (Method->getReturnType()->isVectorType() ? /*return value*/ 1
+ : /*parameter*/ 0)
+ << (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9");
+}
+
Decl *Sema::ActOnMethodDeclaration(
Scope *S,
SourceLocation MethodLoc, SourceLocation EndLoc,
@@ -4393,6 +4462,7 @@ Decl *Sema::ActOnMethodDeclaration(
// Apply the attributes to the parameter.
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
+ AddPragmaAttributes(TUScope, Param);
if (Param->hasAttr<BlocksAttr>()) {
Diag(Param->getLocation(), diag::err_block_on_nonlocal);
@@ -4423,6 +4493,7 @@ Decl *Sema::ActOnMethodDeclaration(
if (AttrList)
ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
+ AddPragmaAttributes(TUScope, ObjCMethod);
// Add the method now.
const ObjCMethodDecl *PrevMethod = nullptr;
@@ -4521,6 +4592,10 @@ Decl *Sema::ActOnMethodDeclaration(
ObjCMethod->SetRelatedResultType();
}
+ if (MethodDefinition &&
+ Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
+ checkObjCMethodX86VectorTypes(*this, ObjCMethod);
+
ActOnDocumentableDecl(ObjCMethod);
return ObjCMethod;
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp
index 2ac2aca..deb6cbb 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1182,6 +1182,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ArraySubscriptExprClass:
case Expr::OMPArraySectionExprClass:
case Expr::BinaryOperatorClass:
+ case Expr::DependentCoawaitExprClass:
case Expr::CompoundAssignOperatorClass:
case Expr::CStyleCastExprClass:
case Expr::CXXStaticCastExprClass:
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp
index 0077d6c..d3d7d8b 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp
@@ -87,109 +87,6 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
}
}
-static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) {
- const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
- if (!OMD)
- return false;
- const ObjCInterfaceDecl *OID = OMD->getClassInterface();
- if (!OID)
- return false;
-
- for (const ObjCCategoryDecl *Cat : OID->visible_categories())
- if (ObjCMethodDecl *CatMeth =
- Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod()))
- if (!CatMeth->hasAttr<AvailabilityAttr>())
- return true;
- return false;
-}
-
-AvailabilityResult
-Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) {
- AvailabilityResult Result = D->getAvailability(Message);
-
- // For typedefs, if the typedef declaration appears available look
- // to the underlying type to see if it is more restrictive.
- while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
- if (Result == AR_Available) {
- if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
- D = TT->getDecl();
- Result = D->getAvailability(Message);
- continue;
- }
- }
- break;
- }
-
- // Forward class declarations get their attributes from their definition.
- if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
- if (IDecl->getDefinition()) {
- D = IDecl->getDefinition();
- Result = D->getAvailability(Message);
- }
- }
-
- if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
- if (Result == AR_Available) {
- const DeclContext *DC = ECD->getDeclContext();
- if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC))
- Result = TheEnumDecl->getAvailability(Message);
- }
-
- if (Result == AR_NotYetIntroduced) {
- // Don't do this for enums, they can't be redeclared.
- if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D))
- return AR_Available;
-
- bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited();
- // Objective-C method declarations in categories are not modelled as
- // redeclarations, so manually look for a redeclaration in a category
- // if necessary.
- if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D))
- Warn = false;
- // In general, D will point to the most recent redeclaration. However,
- // for `@class A;` decls, this isn't true -- manually go through the
- // redecl chain in that case.
- if (Warn && isa<ObjCInterfaceDecl>(D))
- for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn;
- Redecl = Redecl->getPreviousDecl())
- if (!Redecl->hasAttr<AvailabilityAttr>() ||
- Redecl->getAttr<AvailabilityAttr>()->isInherited())
- Warn = false;
-
- return Warn ? AR_NotYetIntroduced : AR_Available;
- }
-
- return Result;
-}
-
-static void
-DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- bool ObjCPropertyAccess) {
- std::string Message;
- // See if this declaration is unavailable, deprecated, or partial.
- if (AvailabilityResult Result =
- S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) {
-
- if (Result == AR_NotYetIntroduced && S.getCurFunctionOrMethodDecl()) {
- S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
- return;
- }
-
- const ObjCPropertyDecl *ObjCPDecl = nullptr;
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
- AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
- if (PDeclResult == Result)
- ObjCPDecl = PD;
- }
- }
-
- S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass,
- ObjCPDecl, ObjCPropertyAccess);
- }
-}
-
/// \brief Emit a note explaining that this function is deleted.
void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
assert(Decl->isDeleted());
@@ -305,7 +202,8 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
///
bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
const ObjCInterfaceDecl *UnknownObjCClass,
- bool ObjCPropertyAccess) {
+ bool ObjCPropertyAccess,
+ bool AvoidPartialAvailabilityChecks) {
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
// emit them now.
@@ -333,10 +231,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
Diag(Loc, diag::err_binding_cannot_appear_in_own_initializer)
<< D->getDeclName();
} else {
- const AutoType *AT = cast<VarDecl>(D)->getType()->getContainedAutoType();
-
Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer)
- << D->getDeclName() << (unsigned)AT->getKeyword();
+ << D->getDeclName() << cast<VarDecl>(D)->getType();
}
return true;
}
@@ -363,8 +259,18 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
return true;
+ }
- if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc))
+ auto getReferencedObjCProp = [](const NamedDecl *D) ->
+ const ObjCPropertyDecl * {
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
+ return MD->findPropertyDecl();
+ return nullptr;
+ };
+ if (const ObjCPropertyDecl *ObjCPDecl = getReferencedObjCProp(D)) {
+ if (diagnoseArgIndependentDiagnoseIfAttrs(ObjCPDecl, Loc))
+ return true;
+ } else if (diagnoseArgIndependentDiagnoseIfAttrs(D, Loc)) {
return true;
}
@@ -381,8 +287,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
return true;
}
- DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
- ObjCPropertyAccess);
+ DiagnoseAvailabilityOfDecl(D, Loc, UnknownObjCClass, ObjCPropertyAccess,
+ AvoidPartialAvailabilityChecks);
DiagnoseUnusedOfDecl(*this, D, Loc);
@@ -706,8 +612,7 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// Loading a __weak object implicitly retains the value, so we need a cleanup to
// balance that.
- if (getLangOpts().ObjCAutoRefCount &&
- E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
+ if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
Cleanup.setExprNeedsCleanups(true);
ExprResult Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E,
@@ -1434,7 +1339,8 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
// Decay and strip qualifiers for the controlling expression type, and handle
// placeholder type replacement. See committee discussion from WG14 DR423.
{
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult R = DefaultFunctionArrayLvalueConversion(ControllingExpr);
if (R.isInvalid())
return ExprError();
@@ -1443,7 +1349,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
// The controlling expression is an unevaluated operand, so side effects are
// likely unintended.
- if (ActiveTemplateInstantiations.empty() &&
+ if (!inTemplateInstantiation() &&
ControllingExpr->HasSideEffects(Context, false))
Diag(ControllingExpr->getExprLoc(),
diag::warn_side_effects_unevaluated_context);
@@ -1774,7 +1680,10 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getLocStart()))
recordUseOfEvaluatedWeak(E);
- if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ FieldDecl *FD = dyn_cast<FieldDecl>(D);
+ if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D))
+ FD = IFD->getAnonField();
+ if (FD) {
UnusedPrivateFields.remove(FD);
// Just in case we're building an illegal pointer-to-member.
if (FD->isBitField())
@@ -1890,9 +1799,10 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// During a default argument instantiation the CurContext points
// to a CXXMethodDecl; but we can't apply a this-> fixit inside a
// function parameter list, hence add an explicit check.
- bool isDefaultArgument = !ActiveTemplateInstantiations.empty() &&
- ActiveTemplateInstantiations.back().Kind ==
- ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
+ bool isDefaultArgument =
+ !CodeSynthesisContexts.empty() &&
+ CodeSynthesisContexts.back().Kind ==
+ CodeSynthesisContext::DefaultFunctionArgumentInstantiation;
CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext);
bool isInstance = CurMethod &&
CurMethod->isInstance() &&
@@ -2127,6 +2037,12 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
IdentifierInfo *II = Name.getAsIdentifierInfo();
SourceLocation NameLoc = NameInfo.getLoc();
+ if (II && II->isEditorPlaceholder()) {
+ // FIXME: When typed placeholders are supported we can create a typed
+ // placeholder expression node.
+ return ExprError();
+ }
+
// C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
// -- an identifier that was declared with a dependent type,
@@ -2510,11 +2426,11 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
IV->getLocation(), SelfExpr.get(), true, true);
+ if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
+ recordUseOfEvaluatedWeak(Result);
+ }
if (getLangOpts().ObjCAutoRefCount) {
- if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
- recordUseOfEvaluatedWeak(Result);
- }
if (CurContext->isClosure())
Diag(Loc, diag::warn_implicitly_retains_self)
<< FixItHint::CreateInsertion(Loc, "self->");
@@ -3038,6 +2954,9 @@ ExprResult Sema::BuildDeclarationNameExpr(
break;
}
+ case Decl::CXXDeductionGuide:
+ llvm_unreachable("building reference to deduction guide");
+
case Decl::MSProperty:
valueKind = VK_LValue;
break;
@@ -3694,7 +3613,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
// The operand for sizeof and alignof is in an unevaluated expression context,
// so side effects could result in unintended consequences.
if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf) &&
- ActiveTemplateInstantiations.empty() && E->HasSideEffects(Context, false))
+ !inTemplateInstantiation() && E->HasSideEffects(Context, false))
Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(),
@@ -3969,7 +3888,8 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
T = cast<DecltypeType>(Ty)->desugar();
break;
case Type::Auto:
- T = cast<AutoType>(Ty)->getDeducedType();
+ case Type::DeducedTemplateSpecialization:
+ T = cast<DeducedType>(Ty)->getDeducedType();
break;
case Type::TypeOfExpr:
T = cast<TypeOfExprType>(Ty)->getUnderlyingExpr()->getType();
@@ -4553,8 +4473,8 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
if (Param->hasUninstantiatedDefaultArg()) {
Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
- EnterExpressionEvaluationContext EvalContext(*this, PotentiallyEvaluated,
- Param);
+ EnterExpressionEvaluationContext EvalContext(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
// Instantiate the expression.
MultiLevelTemplateArgumentList MutiLevelArgList
@@ -5258,9 +5178,11 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
if (Fn->getType() == Context.OverloadTy) {
OverloadExpr::FindResult find = OverloadExpr::find(Fn);
- // We aren't supposed to apply this logic for if there'Scope an '&'
- // involved.
+ // We aren't supposed to apply this logic if there's an '&' involved.
if (!find.HasFormOfMemberPointer) {
+ if (Expr::hasAnyTypeDependentArguments(ArgExprs))
+ return new (Context) CallExpr(
+ Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc);
OverloadExpr *ovl = find.Expression;
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl))
return BuildOverloadedCallExpr(
@@ -5378,6 +5300,17 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
return ExprError();
}
+ // Interrupt handlers don't save off the VFP regs automatically on ARM,
+ // so there's some risk when calling out to non-interrupt handler functions
+ // 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>()) {
+ 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
// builtin functions to function pointers in the callee of a call.
@@ -6323,92 +6256,97 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
Qualifiers lhQual = lhptee.getQualifiers();
Qualifiers rhQual = rhptee.getQualifiers();
+ unsigned ResultAddrSpace = 0;
+ unsigned LAddrSpace = lhQual.getAddressSpace();
+ unsigned RAddrSpace = rhQual.getAddressSpace();
+ if (S.getLangOpts().OpenCL) {
+ // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address
+ // spaces is disallowed.
+ if (lhQual.isAddressSpaceSupersetOf(rhQual))
+ ResultAddrSpace = LAddrSpace;
+ else if (rhQual.isAddressSpaceSupersetOf(lhQual))
+ ResultAddrSpace = RAddrSpace;
+ else {
+ S.Diag(Loc,
+ diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
+ << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+ }
+
unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers();
+ auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast;
lhQual.removeCVRQualifiers();
rhQual.removeCVRQualifiers();
+ // OpenCL v2.0 specification doesn't extend compatibility of type qualifiers
+ // (C99 6.7.3) for address spaces. We assume that the check should behave in
+ // the same manner as it's defined for CVR qualifiers, so for OpenCL two
+ // qual types are compatible iff
+ // * corresponded types are compatible
+ // * CVR qualifiers are equal
+ // * address spaces are equal
+ // Thus for conditional operator we merge CVR and address space unqualified
+ // pointees and if there is a composite type we return a pointer to it with
+ // merged qualifiers.
+ if (S.getLangOpts().OpenCL) {
+ LHSCastKind = LAddrSpace == ResultAddrSpace
+ ? CK_BitCast
+ : CK_AddressSpaceConversion;
+ RHSCastKind = RAddrSpace == ResultAddrSpace
+ ? CK_BitCast
+ : CK_AddressSpaceConversion;
+ lhQual.removeAddressSpace();
+ rhQual.removeAddressSpace();
+ }
+
lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual);
rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual);
- // For OpenCL:
- // 1. If LHS and RHS types match exactly and:
- // (a) AS match => use standard C rules, no bitcast or addrspacecast
- // (b) AS overlap => generate addrspacecast
- // (c) AS don't overlap => give an error
- // 2. if LHS and RHS types don't match:
- // (a) AS match => use standard C rules, generate bitcast
- // (b) AS overlap => generate addrspacecast instead of bitcast
- // (c) AS don't overlap => give an error
-
- // For OpenCL, non-null composite type is returned only for cases 1a and 1b.
QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee);
- // OpenCL cases 1c, 2a, 2b, and 2c.
if (CompositeTy.isNull()) {
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
QualType incompatTy;
- if (S.getLangOpts().OpenCL) {
- // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address
- // spaces is disallowed.
- unsigned ResultAddrSpace;
- if (lhQual.isAddressSpaceSupersetOf(rhQual)) {
- // Cases 2a and 2b.
- ResultAddrSpace = lhQual.getAddressSpace();
- } else if (rhQual.isAddressSpaceSupersetOf(lhQual)) {
- // Cases 2a and 2b.
- ResultAddrSpace = rhQual.getAddressSpace();
- } else {
- // Cases 1c and 2c.
- S.Diag(Loc,
- diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
- << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange()
- << RHS.get()->getSourceRange();
- return QualType();
- }
-
- // Continue handling cases 2a and 2b.
- incompatTy = S.Context.getPointerType(
- S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace));
- LHS = S.ImpCastExprToType(LHS.get(), incompatTy,
- (lhQual.getAddressSpace() != ResultAddrSpace)
- ? CK_AddressSpaceConversion /* 2b */
- : CK_BitCast /* 2a */);
- RHS = S.ImpCastExprToType(RHS.get(), incompatTy,
- (rhQual.getAddressSpace() != ResultAddrSpace)
- ? CK_AddressSpaceConversion /* 2b */
- : CK_BitCast /* 2a */);
- } else {
- S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS.get()->getSourceRange()
- << RHS.get()->getSourceRange();
- incompatTy = S.Context.getPointerType(S.Context.VoidTy);
- LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast);
- }
+ incompatTy = S.Context.getPointerType(
+ S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace));
+ LHS = S.ImpCastExprToType(LHS.get(), incompatTy, LHSCastKind);
+ RHS = S.ImpCastExprToType(RHS.get(), incompatTy, RHSCastKind);
+ // FIXME: For OpenCL the warning emission and cast to void* leaves a room
+ // for casts between types with incompatible address space qualifiers.
+ // For the following code the compiler produces casts between global and
+ // local address spaces of the corresponded innermost pointees:
+ // local int *global *a;
+ // global int *global *b;
+ // a = (0 ? a : b); // see C99 6.5.16.1.p1.
+ S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
+ << LHSTy << RHSTy << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
return incompatTy;
}
// The pointer types are compatible.
- QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual);
- auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast;
+ // In case of OpenCL ResultTy should have the address space qualifier
+ // which is a superset of address spaces of both the 2nd and the 3rd
+ // operands of the conditional operator.
+ QualType ResultTy = [&, ResultAddrSpace]() {
+ if (S.getLangOpts().OpenCL) {
+ Qualifiers CompositeQuals = CompositeTy.getQualifiers();
+ CompositeQuals.setAddressSpace(ResultAddrSpace);
+ return S.Context
+ .getQualifiedType(CompositeTy.getUnqualifiedType(), CompositeQuals)
+ .withCVRQualifiers(MergedCVRQual);
+ }
+ return CompositeTy.withCVRQualifiers(MergedCVRQual);
+ }();
if (IsBlockPointer)
ResultTy = S.Context.getBlockPointerType(ResultTy);
- else {
- // Cases 1a and 1b for OpenCL.
- auto ResultAddrSpace = ResultTy.getQualifiers().getAddressSpace();
- LHSCastKind = lhQual.getAddressSpace() == ResultAddrSpace
- ? CK_BitCast /* 1a */
- : CK_AddressSpaceConversion /* 1b */;
- RHSCastKind = rhQual.getAddressSpace() == ResultAddrSpace
- ? CK_BitCast /* 1a */
- : CK_AddressSpaceConversion /* 1b */;
+ else
ResultTy = S.Context.getPointerType(ResultTy);
- }
- // For case 1a of OpenCL, S.ImpCastExprToType will not insert bitcast
- // if the target type does not change.
LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind);
RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind);
return ResultTy;
@@ -7378,10 +7316,31 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType,
Sema::AssignConvertType ConvTy = Sema::Compatible;
// For blocks we enforce that qualifiers are identical.
- if (lhptee.getLocalQualifiers() != rhptee.getLocalQualifiers())
+ Qualifiers LQuals = lhptee.getLocalQualifiers();
+ Qualifiers RQuals = rhptee.getLocalQualifiers();
+ if (S.getLangOpts().OpenCL) {
+ LQuals.removeAddressSpace();
+ RQuals.removeAddressSpace();
+ }
+ if (LQuals != RQuals)
ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
- if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType))
+ // FIXME: OpenCL doesn't define the exact compile time semantics for a block
+ // assignment.
+ // The current behavior is similar to C++ lambdas. A block might be
+ // assigned to a variable iff its return type and parameters are compatible
+ // (C99 6.2.7) with the corresponding return type and parameters of the LHS of
+ // an assignment. Presumably it should behave in way that a function pointer
+ // assignment does in C, so for each parameter and return type:
+ // * CVR and address space of LHS should be a superset of CVR and address
+ // space of RHS.
+ // * unqualified types should be compatible.
+ if (S.getLangOpts().OpenCL) {
+ if (!S.Context.typesAreBlockPointerCompatible(
+ S.Context.getQualifiedType(LHSType.getUnqualifiedType(), LQuals),
+ S.Context.getQualifiedType(RHSType.getUnqualifiedType(), RQuals)))
+ return Sema::IncompatibleBlockPointer;
+ } else if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType))
return Sema::IncompatibleBlockPointer;
return ConvTy;
@@ -7603,7 +7562,12 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// U^ -> void*
if (RHSType->getAs<BlockPointerType>()) {
if (LHSPointer->getPointeeType()->isVoidType()) {
- Kind = CK_BitCast;
+ unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace();
+ unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>()
+ ->getPointeeType()
+ .getAddressSpace();
+ Kind =
+ AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
return Compatible;
}
}
@@ -7615,7 +7579,13 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (isa<BlockPointerType>(LHSType)) {
// U^ -> T^
if (RHSType->isBlockPointerType()) {
- Kind = CK_BitCast;
+ unsigned AddrSpaceL = LHSType->getAs<BlockPointerType>()
+ ->getPointeeType()
+ .getAddressSpace();
+ unsigned AddrSpaceR = RHSType->getAs<BlockPointerType>()
+ ->getPointeeType()
+ .getAddressSpace();
+ Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType);
}
@@ -7648,7 +7618,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
Kind = CK_BitCast;
Sema::AssignConvertType result =
checkObjCPointerTypesForAssignment(*this, LHSType, RHSType);
- if (getLangOpts().ObjCAutoRefCount &&
+ if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
result == Compatible &&
!CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType))
result = IncompatibleObjCWeakRef;
@@ -7855,7 +7825,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
if (RHS.isInvalid())
return Incompatible;
Sema::AssignConvertType result = Compatible;
- if (getLangOpts().ObjCAutoRefCount &&
+ if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
!CheckObjCARCUnavailableWeakConversion(LHSType, RHSType))
result = IncompatibleObjCWeakRef;
return result;
@@ -7932,9 +7902,9 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
// Check for various Objective-C errors. If we are not reporting
// diagnostics and just checking for errors, e.g., during overload
// resolution, return Incompatible to indicate the failure.
- if (getLangOpts().ObjCAutoRefCount &&
- CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion,
- Diagnose, DiagnoseCFAudited) != ACR_okay) {
+ if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
+ CheckObjCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion,
+ Diagnose, DiagnoseCFAudited) != ACR_okay) {
if (!Diagnose)
return Incompatible;
}
@@ -7964,34 +7934,71 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS,
return QualType();
}
+// Diagnose cases where a scalar was implicitly converted to a vector and
+// diagnose the underlying types. Otherwise, diagnose the error
+// as invalid vector logical operands for non-C++ cases.
+QualType Sema::InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS,
+ ExprResult &RHS) {
+ QualType LHSType = LHS.get()->IgnoreImpCasts()->getType();
+ QualType RHSType = RHS.get()->IgnoreImpCasts()->getType();
+
+ bool LHSNatVec = LHSType->isVectorType();
+ bool RHSNatVec = RHSType->isVectorType();
+
+ if (!(LHSNatVec && RHSNatVec)) {
+ Expr *Vector = LHSNatVec ? LHS.get() : RHS.get();
+ Expr *NonVector = !LHSNatVec ? LHS.get() : RHS.get();
+ Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict)
+ << 0 << Vector->getType() << NonVector->IgnoreImpCasts()->getType()
+ << Vector->getSourceRange();
+ return QualType();
+ }
+
+ Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict)
+ << 1 << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+
+ return QualType();
+}
+
/// Try to convert a value of non-vector type to a vector type by converting
/// the type to the element type of the vector and then performing a splat.
/// If the language is OpenCL, we only use conversions that promote scalar
/// rank; for C, Obj-C, and C++ we allow any real scalar conversion except
/// for float->int.
///
+/// OpenCL V2.0 6.2.6.p2:
+/// An error shall occur if any scalar operand type has greater rank
+/// than the type of the vector element.
+///
/// \param scalar - if non-null, actually perform the conversions
/// \return true if the operation fails (but without diagnosing the failure)
static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
QualType scalarTy,
QualType vectorEltTy,
- QualType vectorTy) {
+ QualType vectorTy,
+ unsigned &DiagID) {
// The conversion to apply to the scalar before splatting it,
// if necessary.
CastKind scalarCast = CK_Invalid;
if (vectorEltTy->isIntegralType(S.Context)) {
- if (!scalarTy->isIntegralType(S.Context))
+ if (S.getLangOpts().OpenCL && (scalarTy->isRealFloatingType() ||
+ (scalarTy->isIntegerType() &&
+ S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy) < 0))) {
+ DiagID = diag::err_opencl_scalar_type_rank_greater_than_vector_type;
return true;
- if (S.getLangOpts().OpenCL &&
- S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy) < 0)
+ }
+ if (!scalarTy->isIntegralType(S.Context))
return true;
scalarCast = CK_IntegralCast;
} else if (vectorEltTy->isRealFloatingType()) {
if (scalarTy->isRealFloatingType()) {
if (S.getLangOpts().OpenCL &&
- S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) < 0)
+ S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) < 0) {
+ DiagID = diag::err_opencl_scalar_type_rank_greater_than_vector_type;
return true;
+ }
scalarCast = CK_FloatingCast;
}
else if (scalarTy->isIntegralType(S.Context))
@@ -8011,6 +8018,162 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
return false;
}
+/// Test if a (constant) integer Int can be casted to another integer type
+/// IntTy without losing precision.
+static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int,
+ QualType OtherIntTy) {
+ QualType IntTy = Int->get()->getType().getUnqualifiedType();
+
+ // Reject cases where the value of the Int is unknown as that would
+ // possibly cause truncation, but accept cases where the scalar can be
+ // demoted without loss of precision.
+ llvm::APSInt Result;
+ bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context);
+ int Order = S.Context.getIntegerTypeOrder(OtherIntTy, IntTy);
+ bool IntSigned = IntTy->hasSignedIntegerRepresentation();
+ bool OtherIntSigned = OtherIntTy->hasSignedIntegerRepresentation();
+
+ if (CstInt) {
+ // If the scalar is constant and is of a higher order and has more active
+ // bits that the vector element type, reject it.
+ unsigned NumBits = IntSigned
+ ? (Result.isNegative() ? Result.getMinSignedBits()
+ : Result.getActiveBits())
+ : Result.getActiveBits();
+ if (Order < 0 && S.Context.getIntWidth(OtherIntTy) < NumBits)
+ return true;
+
+ // If the signedness of the scalar type and the vector element type
+ // differs and the number of bits is greater than that of the vector
+ // element reject it.
+ return (IntSigned != OtherIntSigned &&
+ NumBits > S.Context.getIntWidth(OtherIntTy));
+ }
+
+ // Reject cases where the value of the scalar is not constant and it's
+ // order is greater than that of the vector element type.
+ return (Order < 0);
+}
+
+/// Test if a (constant) integer Int can be casted to floating point type
+/// FloatTy without losing precision.
+static bool canConvertIntTyToFloatTy(Sema &S, ExprResult *Int,
+ QualType FloatTy) {
+ QualType IntTy = Int->get()->getType().getUnqualifiedType();
+
+ // Determine if the integer constant can be expressed as a floating point
+ // number of the appropiate type.
+ llvm::APSInt Result;
+ bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context);
+ uint64_t Bits = 0;
+ if (CstInt) {
+ // Reject constants that would be truncated if they were converted to
+ // the floating point type. Test by simple to/from conversion.
+ // FIXME: Ideally the conversion to an APFloat and from an APFloat
+ // could be avoided if there was a convertFromAPInt method
+ // which could signal back if implicit truncation occurred.
+ llvm::APFloat Float(S.Context.getFloatTypeSemantics(FloatTy));
+ Float.convertFromAPInt(Result, IntTy->hasSignedIntegerRepresentation(),
+ llvm::APFloat::rmTowardZero);
+ llvm::APSInt ConvertBack(S.Context.getIntWidth(IntTy),
+ !IntTy->hasSignedIntegerRepresentation());
+ bool Ignored = false;
+ Float.convertToInteger(ConvertBack, llvm::APFloat::rmNearestTiesToEven,
+ &Ignored);
+ if (Result != ConvertBack)
+ return true;
+ } else {
+ // Reject types that cannot be fully encoded into the mantissa of
+ // the float.
+ Bits = S.Context.getTypeSize(IntTy);
+ unsigned FloatPrec = llvm::APFloat::semanticsPrecision(
+ S.Context.getFloatTypeSemantics(FloatTy));
+ if (Bits > FloatPrec)
+ return true;
+ }
+
+ return false;
+}
+
+/// Attempt to convert and splat Scalar into a vector whose types matches
+/// Vector following GCC conversion rules. The rule is that implicit
+/// conversion can occur when Scalar can be casted to match Vector's element
+/// type without causing truncation of Scalar.
+static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
+ ExprResult *Vector) {
+ QualType ScalarTy = Scalar->get()->getType().getUnqualifiedType();
+ QualType VectorTy = Vector->get()->getType().getUnqualifiedType();
+ const VectorType *VT = VectorTy->getAs<VectorType>();
+
+ assert(!isa<ExtVectorType>(VT) &&
+ "ExtVectorTypes should not be handled here!");
+
+ QualType VectorEltTy = VT->getElementType();
+
+ // Reject cases where the vector element type or the scalar element type are
+ // not integral or floating point types.
+ if (!VectorEltTy->isArithmeticType() || !ScalarTy->isArithmeticType())
+ return true;
+
+ // The conversion to apply to the scalar before splatting it,
+ // if necessary.
+ CastKind ScalarCast = CK_NoOp;
+
+ // Accept cases where the vector elements are integers and the scalar is
+ // an integer.
+ // FIXME: Notionally if the scalar was a floating point value with a precise
+ // integral representation, we could cast it to an appropriate integer
+ // type and then perform the rest of the checks here. GCC will perform
+ // this conversion in some cases as determined by the input language.
+ // We should accept it on a language independent basis.
+ if (VectorEltTy->isIntegralType(S.Context) &&
+ ScalarTy->isIntegralType(S.Context) &&
+ S.Context.getIntegerTypeOrder(VectorEltTy, ScalarTy)) {
+
+ if (canConvertIntToOtherIntTy(S, Scalar, VectorEltTy))
+ return true;
+
+ ScalarCast = CK_IntegralCast;
+ } else if (VectorEltTy->isRealFloatingType()) {
+ if (ScalarTy->isRealFloatingType()) {
+
+ // Reject cases where the scalar type is not a constant and has a higher
+ // Order than the vector element type.
+ llvm::APFloat Result(0.0);
+ bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context);
+ int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy);
+ if (!CstScalar && Order < 0)
+ return true;
+
+ // If the scalar cannot be safely casted to the vector element type,
+ // reject it.
+ if (CstScalar) {
+ bool Truncated = false;
+ Result.convert(S.Context.getFloatTypeSemantics(VectorEltTy),
+ llvm::APFloat::rmNearestTiesToEven, &Truncated);
+ if (Truncated)
+ return true;
+ }
+
+ ScalarCast = CK_FloatingCast;
+ } else if (ScalarTy->isIntegralType(S.Context)) {
+ if (canConvertIntTyToFloatTy(S, Scalar, VectorEltTy))
+ return true;
+
+ ScalarCast = CK_IntegralToFloating;
+ } else
+ return true;
+ }
+
+ // Adjust scalar if desired.
+ if (Scalar) {
+ if (ScalarCast != CK_NoOp)
+ *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast);
+ *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat);
+ }
+ return false;
+}
+
QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompAssign,
bool AllowBothBool,
@@ -8079,22 +8242,34 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
}
}
- // If there's an ext-vector type and a scalar, try to convert the scalar to
+ // If there's a vector type and a scalar, try to convert the scalar to
// the vector element type and splat.
- // FIXME: this should also work for regular vector types as supported in GCC.
- if (!RHSVecType && isa<ExtVectorType>(LHSVecType)) {
- if (!tryVectorConvertAndSplat(*this, &RHS, RHSType,
- LHSVecType->getElementType(), LHSType))
- return LHSType;
+ unsigned DiagID = diag::err_typecheck_vector_not_convertable;
+ if (!RHSVecType) {
+ if (isa<ExtVectorType>(LHSVecType)) {
+ if (!tryVectorConvertAndSplat(*this, &RHS, RHSType,
+ LHSVecType->getElementType(), LHSType,
+ DiagID))
+ return LHSType;
+ } else {
+ if (!tryGCCVectorConvertAndSplat(*this, &RHS, &LHS))
+ return LHSType;
+ }
}
- if (!LHSVecType && isa<ExtVectorType>(RHSVecType)) {
- if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS),
- LHSType, RHSVecType->getElementType(),
- RHSType))
- return RHSType;
+ if (!LHSVecType) {
+ if (isa<ExtVectorType>(RHSVecType)) {
+ if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS),
+ LHSType, RHSVecType->getElementType(),
+ RHSType, DiagID))
+ return RHSType;
+ } else {
+ if (LHS.get()->getValueKind() == VK_LValue ||
+ !tryGCCVectorConvertAndSplat(*this, &LHS, &RHS))
+ return RHSType;
+ }
}
- // FIXME: The code below also handles convertion between vectors and
+ // FIXME: The code below also handles conversion between vectors and
// non-scalars, we should break this down into fine grained specific checks
// and emit proper diagnostics.
QualType VecType = LHSVecType ? LHSType : RHSType;
@@ -8113,7 +8288,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
// type. Note that this is already done by non-compound assignments in
// CheckAssignmentConstraints. If it's a scalar type, only bitcast for
// <1 x T> -> T. The result is also a vector type.
- } else if (OtherType->isExtVectorType() ||
+ } else if (OtherType->isExtVectorType() || OtherType->isVectorType() ||
(OtherType->isScalarType() && VT->getNumElements() == 1)) {
ExprResult *RHSExpr = &RHS;
*RHSExpr = ImpCastExprToType(RHSExpr->get(), LHSType, CK_BitCast);
@@ -8144,8 +8319,24 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
return QualType();
}
+
+ // If there is a vector type that is not a ExtVector and a scalar, we reach
+ // this point if scalar could not be converted to the vector's element type
+ // without truncation.
+ if ((RHSVecType && !isa<ExtVectorType>(RHSVecType)) ||
+ (LHSVecType && !isa<ExtVectorType>(LHSVecType))) {
+ QualType Scalar = LHSVecType ? RHSType : LHSType;
+ QualType Vector = LHSVecType ? LHSType : RHSType;
+ unsigned ScalarOrVector = LHSVecType && RHSVecType ? 1 : 0;
+ Diag(Loc,
+ diag::err_typecheck_vector_not_convertable_implict_truncation)
+ << ScalarOrVector << Scalar << Vector;
+
+ return QualType();
+ }
+
// Otherwise, use the generic diagnostic.
- Diag(Loc, diag::err_typecheck_vector_not_convertable)
+ Diag(Loc, DiagID)
<< LHSType << RHSType
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
@@ -9231,7 +9422,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
!(LHSType->isBlockPointerType() && IsRelational) &&
!LHS.get()->getLocStart().isMacroID() &&
!RHS.get()->getLocStart().isMacroID() &&
- ActiveTemplateInstantiations.empty()) {
+ !inTemplateInstantiation()) {
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
@@ -9374,7 +9565,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// If both operands are pointers, [...] bring them to their composite
// pointer type.
if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >=
- (IsRelational ? 2 : 1)) {
+ (IsRelational ? 2 : 1) &&
+ (!LangOpts.ObjCAutoRefCount ||
+ !(LHSType->isObjCObjectPointerType() ||
+ RHSType->isObjCObjectPointerType()))) {
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
else
@@ -9560,16 +9754,17 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (LHSIsNull && !RHSIsNull) {
Expr *E = LHS.get();
if (getLangOpts().ObjCAutoRefCount)
- CheckObjCARCConversion(SourceRange(), RHSType, E, CCK_ImplicitConversion);
+ CheckObjCConversion(SourceRange(), RHSType, E,
+ CCK_ImplicitConversion);
LHS = ImpCastExprToType(E, RHSType,
RPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
}
else {
Expr *E = RHS.get();
if (getLangOpts().ObjCAutoRefCount)
- CheckObjCARCConversion(SourceRange(), LHSType, E,
- CCK_ImplicitConversion, /*Diagnose=*/true,
- /*DiagnoseCFAudited=*/false, Opc);
+ CheckObjCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion,
+ /*Diagnose=*/true,
+ /*DiagnoseCFAudited=*/false, Opc);
RHS = ImpCastExprToType(E, LHSType,
LPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
}
@@ -9657,24 +9852,45 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return InvalidOperands(Loc, LHS, RHS);
}
-
-// Return a signed type that is of identical size and number of elements.
-// For floating point vectors, return an integer type of identical size
-// and number of elements.
+// Return a signed ext_vector_type that is of identical size and number of
+// elements. For floating point vectors, return an integer type of identical
+// size and number of elements. In the non ext_vector_type case, search from
+// the largest type to the smallest type to avoid cases where long long == long,
+// where long gets picked over long long.
QualType Sema::GetSignedVectorType(QualType V) {
const VectorType *VTy = V->getAs<VectorType>();
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
- if (TypeSize == Context.getTypeSize(Context.CharTy))
- return Context.getExtVectorType(Context.CharTy, VTy->getNumElements());
- else if (TypeSize == Context.getTypeSize(Context.ShortTy))
- return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements());
- else if (TypeSize == Context.getTypeSize(Context.IntTy))
- return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
+
+ if (isa<ExtVectorType>(VTy)) {
+ if (TypeSize == Context.getTypeSize(Context.CharTy))
+ return Context.getExtVectorType(Context.CharTy, VTy->getNumElements());
+ else if (TypeSize == Context.getTypeSize(Context.ShortTy))
+ return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements());
+ else if (TypeSize == Context.getTypeSize(Context.IntTy))
+ return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
+ else if (TypeSize == Context.getTypeSize(Context.LongTy))
+ return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
+ assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
+ "Unhandled vector element size in vector compare");
+ return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
+ }
+
+ if (TypeSize == Context.getTypeSize(Context.LongLongTy))
+ return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(),
+ VectorType::GenericVector);
else if (TypeSize == Context.getTypeSize(Context.LongTy))
- return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
- assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
+ return Context.getVectorType(Context.LongTy, VTy->getNumElements(),
+ VectorType::GenericVector);
+ else if (TypeSize == Context.getTypeSize(Context.IntTy))
+ return Context.getVectorType(Context.IntTy, VTy->getNumElements(),
+ VectorType::GenericVector);
+ else if (TypeSize == Context.getTypeSize(Context.ShortTy))
+ return Context.getVectorType(Context.ShortTy, VTy->getNumElements(),
+ VectorType::GenericVector);
+ assert(TypeSize == Context.getTypeSize(Context.CharTy) &&
"Unhandled vector element size in vector compare");
- return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
+ return Context.getVectorType(Context.CharTy, VTy->getNumElements(),
+ VectorType::GenericVector);
}
/// CheckVectorCompareOperands - vector comparisons are a clang extension that
@@ -9703,8 +9919,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
- if (!LHSType->hasFloatingRepresentation() &&
- ActiveTemplateInstantiations.empty()) {
+ if (!LHSType->hasFloatingRepresentation() && !inTemplateInstantiation()) {
if (DeclRefExpr* DRL
= dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParenImpCasts()))
if (DeclRefExpr* DRR
@@ -9722,7 +9937,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
assert (RHS.get()->getType()->hasFloatingRepresentation());
CheckFloatComparison(Loc, LHS.get(), RHS.get());
}
-
+
// Return a signed type for the vector.
return GetSignedVectorType(vType);
}
@@ -9739,7 +9954,13 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 &&
vType->hasFloatingRepresentation())
return InvalidOperands(Loc, LHS, RHS);
-
+ // FIXME: The check for C++ here is for GCC compatibility. GCC rejects the
+ // usage of the logical operators && and || with vectors in C. This
+ // check could be notionally dropped.
+ if (!getLangOpts().CPlusPlus &&
+ !(isa<ExtVectorType>(vType->getAs<VectorType>())))
+ return InvalidLogicalVectorOperands(Loc, LHS, RHS);
+
return GetSignedVectorType(LHS.get()->getType());
}
@@ -9792,7 +10013,7 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
!LHS.get()->getType()->isBooleanType() &&
RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() &&
// Don't warn in macros or template instantiations.
- !Loc.isMacroID() && ActiveTemplateInstantiations.empty()) {
+ !Loc.isMacroID() && !inTemplateInstantiation()) {
// If the RHS can be constant folded, and if it constant folds to something
// that isn't 0 or 1 (which indicate a potential logical operation that
// happened to fold to true/false) then warn.
@@ -10268,7 +10489,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InnerLHS);
if (!DRE || DRE->getDecl()->hasAttr<BlocksAttr>())
checkRetainCycles(LHSExpr, RHS.get());
+ }
+ if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong ||
+ LHSType.isNonWeakInMRRWithObjCWeak(Context)) {
// It is safe to assign a weak reference into a strong variable.
// Although this code can still have problems:
// id x = self.weakProp;
@@ -10276,11 +10500,13 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// we do not warn to warn spuriously when 'x' and 'y' are on separate
// paths through the function. This should be revisited if
// -Wrepeated-use-of-weak is made flow-sensitive.
+ // For ObjCWeak only, we do not warn if the assign is to a non-weak
+ // variable, which will be valid for the current autorelease scope.
if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak,
RHS.get()->getLocStart()))
getCurFunction()->markSafeWeakUse(RHS.get());
- } else if (getLangOpts().ObjCAutoRefCount) {
+ } else if (getLangOpts().ObjCAutoRefCount || getLangOpts().ObjCWeak) {
checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get());
}
}
@@ -10328,7 +10554,7 @@ void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) {
return;
// Don't warn in template instantiations.
- if (!ActiveTemplateInstantiations.empty())
+ if (inTemplateInstantiation())
return;
// Scope isn't fine-grained enough to whitelist the specific cases, so
@@ -10923,7 +11149,7 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode(
/// suppressed in the event of macro expansions.
static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
SourceLocation OpLoc) {
- if (!S.ActiveTemplateInstantiations.empty())
+ if (S.inTemplateInstantiation())
return;
if (OpLoc.isInvalid() || OpLoc.isMacroID())
return;
@@ -11063,7 +11289,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (LHSTy->isAtomicType() || RHSTy->isAtomicType()) {
SourceRange SR(LHSExpr->getLocStart(), RHSExpr->getLocEnd());
if (BO_Assign == Opc)
- Diag(OpLoc, diag::err_atomic_init_constant) << SR;
+ Diag(OpLoc, diag::err_opencl_atomic_init) << 0 << SR;
else
ResultTy = InvalidOperands(OpLoc, LHS, RHS);
return ExprError();
@@ -11129,6 +11355,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_And:
checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc);
+ LLVM_FALLTHROUGH;
case BO_Xor:
case BO_Or:
ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
@@ -11171,6 +11398,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
case BO_AndAssign:
case BO_OrAssign: // fallthrough
DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
+ LLVM_FALLTHROUGH;
case BO_XorAssign:
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
CompLHSTy = CompResultTy;
@@ -11212,7 +11440,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (CompResultTy.isNull())
return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK,
- OK, OpLoc, FPFeatures.fp_contract);
+ OK, OpLoc, FPFeatures);
if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() !=
OK_ObjCProperty) {
VK = VK_LValue;
@@ -11220,7 +11448,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
}
return new (Context) CompoundAssignOperator(
LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy,
- OpLoc, FPFeatures.fp_contract);
+ OpLoc, FPFeatures);
}
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -11493,6 +11721,28 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
RHSExpr->getType()->isOverloadableType())
return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
}
+
+ // If we're instantiating "a.x < b" or "A::x < b" and 'x' names a function
+ // template, diagnose the missing 'template' keyword instead of diagnosing
+ // an invalid use of a bound member function.
+ //
+ // Note that "A::x < b" might be valid if 'b' has an overloadable type due
+ // to C++1z [over.over]/1.4, but we already checked for that case above.
+ if (Opc == BO_LT && inTemplateInstantiation() &&
+ (pty->getKind() == BuiltinType::BoundMember ||
+ pty->getKind() == BuiltinType::Overload)) {
+ auto *OE = dyn_cast<OverloadExpr>(LHSExpr);
+ if (OE && !OE->hasTemplateKeyword() && !OE->hasExplicitTemplateArgs() &&
+ std::any_of(OE->decls_begin(), OE->decls_end(), [](NamedDecl *ND) {
+ return isa<FunctionTemplateDecl>(ND);
+ })) {
+ Diag(OE->getQualifier() ? OE->getQualifierLoc().getBeginLoc()
+ : OE->getNameLoc(),
+ diag::err_template_kw_missing)
+ << OE->getName().getAsString() << "";
+ return ExprError();
+ }
+ }
ExprResult LHS = CheckPlaceholderExpr(LHSExpr);
if (LHS.isInvalid()) return ExprError();
@@ -11618,16 +11868,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< resultType << Input.get()->getSourceRange();
else if (resultType->hasIntegerRepresentation())
break;
- else if (resultType->isExtVectorType()) {
- if (Context.getLangOpts().OpenCL) {
- // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
- // on vector float types.
- QualType T = resultType->getAs<ExtVectorType>()->getElementType();
- if (!T->isIntegerType())
- return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
- << resultType << Input.get()->getSourceRange());
- }
- break;
+ else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
+ // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+ // on vector float types.
+ QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ if (!T->isIntegerType())
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input.get()->getSourceRange());
} else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -11659,7 +11906,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Context.getLangOpts().OpenCLVersion < 120) {
// OpenCL v1.1 6.3.h: The logical operator not (!) does not
// operate on scalar float types.
- if (!resultType->isIntegerType())
+ if (!resultType->isIntegerType() && !resultType->isPointerType())
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
}
@@ -11677,6 +11924,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType = GetSignedVectorType(resultType);
break;
} else {
+ // FIXME: GCC's vector extension permits the usage of '!' with a vector
+ // type in C++. We should allow that here too.
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
}
@@ -11701,11 +11950,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
}
break;
case UO_Extension:
- case UO_Coawait:
resultType = Input.get()->getType();
VK = Input.get()->getValueKind();
OK = Input.get()->getObjectKind();
break;
+ case UO_Coawait:
+ // It's unnessesary to represent the pass-through operator co_await in the
+ // AST; just return the input expression instead.
+ assert(!Input.get()->getType()->isDependentType() &&
+ "the co_await expression must be non-dependant before "
+ "building operator co_await");
+ return Input;
}
if (resultType.isNull() || Input.isInvalid())
return ExprError();
@@ -12193,7 +12448,8 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
// Enter a new evaluation context to insulate the block from any
// cleanups from the enclosing full-expression.
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
@@ -12409,6 +12665,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BSI->TheDecl->setBody(cast<CompoundStmt>(Body));
+ if (Body && getCurFunction()->HasPotentialAvailabilityViolations)
+ DiagnoseUnguardedAvailabilityViolations(BSI->TheDecl);
+
// Try to apply the named return value optimization. We have to check again
// if we can do this, though, because blocks keep return statements around
// to deduce an implicit return type.
@@ -13086,7 +13345,7 @@ void Sema::PopExpressionEvaluationContext() {
unsigned NumTypos = Rec.NumTypos;
if (!Rec.Lambdas.empty()) {
- if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) {
+ if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) {
unsigned D;
if (Rec.isUnevaluated()) {
// C++11 [expr.prim.lambda]p2:
@@ -13107,7 +13366,7 @@ void Sema::PopExpressionEvaluationContext() {
// are part of function-signatures. Be mindful that P0315 (Lambdas in
// unevaluated contexts) might lift some of these restrictions in a
// future version.
- if (Rec.Context != ConstantEvaluated || !getLangOpts().CPlusPlus1z)
+ if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus1z)
for (const auto *L : Rec.Lambdas)
Diag(L->getLocStart(), D);
} else {
@@ -13124,7 +13383,7 @@ void Sema::PopExpressionEvaluationContext() {
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
// will never be constructed.
- if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) {
+ if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) {
ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects,
ExprCleanupObjects.end());
Cleanup = Rec.ParentCleanup;
@@ -13166,19 +13425,19 @@ ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) {
/// captured by C++'s idea of an "unevaluated context".
static bool isEvaluatableContext(Sema &SemaRef) {
switch (SemaRef.ExprEvalContexts.back().Context) {
- case Sema::Unevaluated:
- case Sema::UnevaluatedAbstract:
- case Sema::DiscardedStatement:
+ case Sema::ExpressionEvaluationContext::Unevaluated:
+ case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
+ case Sema::ExpressionEvaluationContext::DiscardedStatement:
// Expressions in this context are never evaluated.
return false;
- case Sema::UnevaluatedList:
- case Sema::ConstantEvaluated:
- case Sema::PotentiallyEvaluated:
+ case Sema::ExpressionEvaluationContext::UnevaluatedList:
+ case Sema::ExpressionEvaluationContext::ConstantEvaluated:
+ case Sema::ExpressionEvaluationContext::PotentiallyEvaluated:
// Expressions in this context could be evaluated.
return true;
- case Sema::PotentiallyEvaluatedIfUsed:
+ case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
// Referenced declarations will only be used if the construct in the
// containing expression is used, at which point we'll be given another
// turn to mark them.
@@ -13196,17 +13455,17 @@ static bool isOdrUseContext(Sema &SemaRef, bool SkipDependentUses = true) {
return false;
switch (SemaRef.ExprEvalContexts.back().Context) {
- case Sema::Unevaluated:
- case Sema::UnevaluatedList:
- case Sema::UnevaluatedAbstract:
- case Sema::DiscardedStatement:
+ case Sema::ExpressionEvaluationContext::Unevaluated:
+ case Sema::ExpressionEvaluationContext::UnevaluatedList:
+ case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
+ case Sema::ExpressionEvaluationContext::DiscardedStatement:
return false;
- case Sema::ConstantEvaluated:
- case Sema::PotentiallyEvaluated:
+ case Sema::ExpressionEvaluationContext::ConstantEvaluated:
+ case Sema::ExpressionEvaluationContext::PotentiallyEvaluated:
return true;
- case Sema::PotentiallyEvaluatedIfUsed:
+ case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
return false;
}
llvm_unreachable("Invalid context");
@@ -13357,7 +13616,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (!AlreadyInstantiated || Func->isConstexpr()) {
if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
- ActiveTemplateInstantiations.size())
+ CodeSynthesisContexts.size())
PendingLocalImplicitInstantiations.push_back(
std::make_pair(Func, PointOfInstantiation));
else if (Func->isConstexpr())
@@ -13366,6 +13625,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// call to such a function.
InstantiateFunctionDefinition(PointOfInstantiation, Func);
else {
+ Func->setInstantiationIsPending(true);
PendingInstantiations.push_back(std::make_pair(Func,
PointOfInstantiation));
// Notify the consumer that a function was implicitly instantiated.
@@ -13540,6 +13800,13 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
}
return false;
}
+ // OpenCL v2.0 s6.12.5: Blocks cannot reference/capture other blocks
+ if (S.getLangOpts().OpenCL && IsBlock &&
+ Var->getType()->isBlockPointerType()) {
+ if (Diagnose)
+ S.Diag(Loc, diag::err_opencl_block_ref_block);
+ return false;
+ }
return true;
}
@@ -13577,16 +13844,55 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
}
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
- if (auto *PT = dyn_cast<PointerType>(CaptureType)) {
+ if (const auto *PT = CaptureType->getAs<PointerType>()) {
+ // This function finds out whether there is an AttributedType of kind
+ // attr_objc_ownership in Ty. The existence of AttributedType of kind
+ // attr_objc_ownership implies __autoreleasing was explicitly specified
+ // rather than being added implicitly by the compiler.
+ auto IsObjCOwnershipAttributedType = [](QualType Ty) {
+ while (const auto *AttrTy = Ty->getAs<AttributedType>()) {
+ if (AttrTy->getAttrKind() == AttributedType::attr_objc_ownership)
+ return true;
+
+ // Peel off AttributedTypes that are not of kind objc_ownership.
+ Ty = AttrTy->getModifiedType();
+ }
+
+ return false;
+ };
+
QualType PointeeTy = PT->getPointeeType();
- if (isa<ObjCObjectPointerType>(PointeeTy.getCanonicalType()) &&
+
+ if (PointeeTy->getAs<ObjCObjectPointerType>() &&
PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing &&
- !isa<AttributedType>(PointeeTy)) {
+ !IsObjCOwnershipAttributedType(PointeeTy)) {
if (BuildAndDiagnose) {
SourceLocation VarLoc = Var->getLocation();
S.Diag(Loc, diag::warn_block_capture_autoreleasing);
- S.Diag(VarLoc, diag::note_declare_parameter_autoreleasing) <<
- FixItHint::CreateInsertion(VarLoc, "__autoreleasing");
+ {
+ auto AddAutoreleaseNote =
+ S.Diag(VarLoc, diag::note_declare_parameter_autoreleasing);
+ // Provide a fix-it for the '__autoreleasing' keyword at the
+ // appropriate location in the variable's type.
+ if (const auto *TSI = Var->getTypeSourceInfo()) {
+ PointerTypeLoc PTL =
+ TSI->getTypeLoc().getAsAdjusted<PointerTypeLoc>();
+ if (PTL) {
+ SourceLocation Loc = PTL.getPointeeLoc().getEndLoc();
+ Loc = Lexer::getLocForEndOfToken(Loc, 0, S.getSourceManager(),
+ S.getLangOpts());
+ if (Loc.isValid()) {
+ StringRef CharAtLoc = Lexer::getSourceText(
+ CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(1)),
+ S.getSourceManager(), S.getLangOpts());
+ AddAutoreleaseNote << FixItHint::CreateInsertion(
+ Loc, CharAtLoc.empty() || !isWhitespace(CharAtLoc[0])
+ ? " __autoreleasing "
+ : " __autoreleasing");
+ }
+ }
+ }
+ }
S.Diag(VarLoc, diag::note_declare_parameter_strong);
}
}
@@ -13615,7 +13921,8 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Enter a new evaluation context to insulate the copy
// full-expression.
- EnterExpressionEvaluationContext scope(S, S.PotentiallyEvaluated);
+ EnterExpressionEvaluationContext scope(
+ S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
// According to the blocks spec, the capture of a variable from
// the stack requires a const copy constructor. This is not true
@@ -13898,8 +14205,10 @@ bool Sema::tryCaptureVariable(
// Check whether we've already captured it.
if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
- DeclRefType))
+ DeclRefType)) {
+ CSI->getCapture(Var).markUsed(BuildAndDiagnose);
break;
+ }
// If we are instantiating a generic lambda call operator body,
// we do not want to capture new variables. What was captured
// during either a lambdas transformation or initial parsing
@@ -14227,8 +14536,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
(SemaRef.CurContext != Var->getDeclContext() &&
Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
if (RefersToEnclosingScope) {
- if (LambdaScopeInfo *const LSI =
- SemaRef.getCurLambda(/*IgnoreCapturedRegions=*/true)) {
+ LambdaScopeInfo *const LSI =
+ SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true);
+ if (LSI && !LSI->CallOperator->Encloses(Var->getDeclContext())) {
// If a variable could potentially be odr-used, defer marking it so
// until we finish analyzing the full expression for any
// lvalue-to-rvalue
@@ -14278,24 +14588,24 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
ME->performsVirtualDispatch(SemaRef.getLangOpts());
if (!IsVirtualCall)
return;
- const Expr *Base = ME->getBase();
- const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType();
- if (!MostDerivedClassDecl)
- return;
- CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl);
- if (!DM || DM->isPure())
- return;
- SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse);
+
+ // If it's possible to devirtualize the call, mark the called function
+ // referenced.
+ CXXMethodDecl *DM = MD->getDevirtualizedMethod(
+ ME->getBase(), SemaRef.getLangOpts().AppleKext);
+ if (DM)
+ SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse);
}
/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
-void Sema::MarkDeclRefReferenced(DeclRefExpr *E) {
+void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
// TODO: update this with DR# once a defect report is filed.
// C++11 defect. The address of a pure member should not be an ODR use, even
// if it's a qualified reference.
bool OdrUse = true;
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl()))
- if (Method->isVirtual())
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl()))
+ if (Method->isVirtual() &&
+ !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext))
OdrUse = false;
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
}
@@ -14363,7 +14673,8 @@ bool MarkReferencedDecls::TraverseTemplateArgument(
const TemplateArgument &Arg) {
{
// A non-type template argument is a constant-evaluated context.
- EnterExpressionEvaluationContext Evaluated(S, Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Evaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
if (Arg.getKind() == TemplateArgument::Declaration) {
if (Decl *D = Arg.getAsDecl())
S.MarkAnyDeclReferenced(Loc, D, true);
@@ -14483,19 +14794,19 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
const PartialDiagnostic &PD) {
switch (ExprEvalContexts.back().Context) {
- case Unevaluated:
- case UnevaluatedList:
- case UnevaluatedAbstract:
- case DiscardedStatement:
+ case ExpressionEvaluationContext::Unevaluated:
+ case ExpressionEvaluationContext::UnevaluatedList:
+ case ExpressionEvaluationContext::UnevaluatedAbstract:
+ case ExpressionEvaluationContext::DiscardedStatement:
// The argument will never be evaluated, so don't complain.
break;
- case ConstantEvaluated:
+ case ExpressionEvaluationContext::ConstantEvaluated:
// Relevant diagnostics should be produced by constant evaluation.
break;
- case PotentiallyEvaluated:
- case PotentiallyEvaluatedIfUsed:
+ case ExpressionEvaluationContext::PotentiallyEvaluated:
+ case ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
if (Statement && getCurFunctionOrMethodDecl()) {
FunctionScopes.back()->PossiblyUnreachableDiags.
push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement));
@@ -15226,7 +15537,7 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
}
/// Check for operands with placeholder types and complain if found.
-/// Returns true if there was an error and no recovery was possible.
+/// Returns ExprError() if there was an error and no recovery was possible.
ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
if (!getLangOpts().CPlusPlus) {
// C cannot handle TypoExpr nodes on either side of a binop because it
@@ -15374,6 +15685,13 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
if (Spec != AvailSpecs.end())
Version = Spec->getVersion();
+ // The use of `@available` in the enclosing function should be analyzed to
+ // warn when it's used inappropriately (i.e. not if(@available)).
+ if (getCurFunctionOrMethodDecl())
+ getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
+ else if (getCurBlock() || getCurLambda())
+ getCurFunction()->HasPotentialAvailabilityViolations = true;
+
return new (Context)
ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp
index 3afa95f..a9cf3ec 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp
@@ -189,12 +189,15 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
// have one) and, if that fails to find a match, in the scope (if
// we're allowed to look there).
Found.clear();
- if (Step == 0 && LookupCtx)
+ if (Step == 0 && LookupCtx) {
+ if (RequireCompleteDeclContext(SS, LookupCtx))
+ return nullptr;
LookupQualifiedName(Found, LookupCtx);
- else if (Step == 1 && LookInScope && S)
+ } else if (Step == 1 && LookInScope && S) {
LookupName(Found, S);
- else
+ } else {
continue;
+ }
// FIXME: Should we be suppressing ambiguities here?
if (Found.isAmbiguous())
@@ -323,20 +326,31 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
return nullptr;
}
-ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) {
- if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType)
- return nullptr;
- assert(DS.getTypeSpecType() == DeclSpec::TST_decltype
- && "only get destructor types from declspecs");
- QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
- QualType SearchType = GetTypeFromParser(ObjectType);
- if (SearchType->isDependentType() || Context.hasSameUnqualifiedType(SearchType, T)) {
- return ParsedType::make(T);
- }
+ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS,
+ ParsedType ObjectType) {
+ if (DS.getTypeSpecType() == DeclSpec::TST_error)
+ return nullptr;
+ if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto) {
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid);
+ return nullptr;
+ }
+
+ assert(DS.getTypeSpecType() == DeclSpec::TST_decltype &&
+ "unexpected type in getDestructorType");
+ QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+
+ // If we know the type of the object, check that the correct destructor
+ // type was named now; we can give better diagnostics this way.
+ QualType SearchType = GetTypeFromParser(ObjectType);
+ if (!SearchType.isNull() && !SearchType->isDependentType() &&
+ !Context.hasSameUnqualifiedType(T, SearchType)) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch)
<< T << SearchType;
return nullptr;
+ }
+
+ return ParsedType::make(T);
}
bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
@@ -448,7 +462,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
if (E->getType()->isVariablyModifiedType())
return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid)
<< E->getType());
- else if (ActiveTemplateInstantiations.empty() &&
+ else if (!inTemplateInstantiation() &&
E->HasSideEffects(Context, WasEvaluated)) {
// The expression operand for typeid is in an unevaluated expression
// context, so side effects could result in unintended consequences.
@@ -890,17 +904,36 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda(
// capturing lamdbda's call operator.
//
- // The issue is that we cannot rely entirely on the FunctionScopeInfo stack
- // since ScopeInfos are pushed on during parsing and treetransforming. But
- // since a generic lambda's call operator can be instantiated anywhere (even
- // end of the TU) we need to be able to examine its enclosing lambdas and so
- // we use the DeclContext to get a hold of the closure-class and query it for
- // capture information. The reason we don't just resort to always using the
- // DeclContext chain is that it is only mature for lambda expressions
- // enclosing generic lambda's call operators that are being instantiated.
-
+ // Since the FunctionScopeInfo stack is representative of the lexical
+ // nesting of the lambda expressions during initial parsing (and is the best
+ // place for querying information about captures about lambdas that are
+ // partially processed) and perhaps during instantiation of function templates
+ // that contain lambda expressions that need to be transformed BUT not
+ // necessarily during instantiation of a nested generic lambda's function call
+ // operator (which might even be instantiated at the end of the TU) - at which
+ // time the DeclContext tree is mature enough to query capture information
+ // reliably - we use a two pronged approach to walk through all the lexically
+ // enclosing lambda expressions:
+ //
+ // 1) Climb down the FunctionScopeInfo stack as long as each item represents
+ // a Lambda (i.e. LambdaScopeInfo) AND each LSI's 'closure-type' is lexically
+ // enclosed by the call-operator of the LSI below it on the stack (while
+ // tracking the enclosing DC for step 2 if needed). Note the topmost LSI on
+ // the stack represents the innermost lambda.
+ //
+ // 2) If we run out of enclosing LSI's, check if the enclosing DeclContext
+ // represents a lambda's call operator. If it does, we must be instantiating
+ // a generic lambda's call operator (represented by the Current LSI, and
+ // should be the only scenario where an inconsistency between the LSI and the
+ // DeclContext should occur), so climb out the DeclContexts if they
+ // represent lambdas, while querying the corresponding closure types
+ // regarding capture information.
+
+ // 1) Climb down the function scope info stack.
for (int I = FunctionScopes.size();
- I-- && isa<LambdaScopeInfo>(FunctionScopes[I]);
+ I-- && isa<LambdaScopeInfo>(FunctionScopes[I]) &&
+ (!CurLSI || !CurLSI->Lambda || CurLSI->Lambda->getDeclContext() ==
+ cast<LambdaScopeInfo>(FunctionScopes[I])->CallOperator);
CurDC = getLambdaAwareParentOfDeclContext(CurDC)) {
CurLSI = cast<LambdaScopeInfo>(FunctionScopes[I]);
@@ -916,11 +949,17 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda(
return ASTCtx.getPointerType(ClassType);
}
}
- // We've run out of ScopeInfos but check if CurDC is a lambda (which can
- // happen during instantiation of generic lambdas)
+
+ // 2) We've run out of ScopeInfos but check if CurDC is a lambda (which can
+ // happen during instantiation of its nested generic lambda call operator)
if (isLambdaCallOperator(CurDC)) {
- assert(CurLSI);
- assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator));
+ assert(CurLSI && "While computing 'this' capture-type for a generic "
+ "lambda, we must have a corresponding LambdaScopeInfo");
+ assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator) &&
+ "While computing 'this' capture-type for a generic lambda, when we "
+ "run out of enclosing LSI's, yet the enclosing DC is a "
+ "lambda-call-operator we must be (i.e. Current LSI) in a generic "
+ "lambda call oeprator");
assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator));
auto IsThisCaptured =
@@ -968,7 +1007,7 @@ QualType Sema::getCurrentThisType() {
}
if (ThisTy.isNull() && isLambdaCallOperator(CurContext) &&
- !ActiveTemplateInstantiations.empty()) {
+ inTemplateInstantiation()) {
assert(isa<CXXRecordDecl>(DC) &&
"Trying to get 'this' type from static method?");
@@ -1106,6 +1145,7 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {
if (CSI->CXXThisCaptureIndex != 0) {
// 'this' is already being captured; there isn't anything more to do.
+ CSI->Captures[CSI->CXXThisCaptureIndex - 1].markUsed(BuildAndDiagnose);
break;
}
LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI);
@@ -1216,17 +1256,6 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep,
if (!TInfo)
TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation());
- // Handle errors like: int({0})
- if (exprs.size() == 1 && !canInitializeWithParenthesizedList(Ty) &&
- LParenLoc.isValid() && RParenLoc.isValid())
- if (auto IList = dyn_cast<InitListExpr>(exprs[0])) {
- Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens)
- << Ty << IList->getSourceRange()
- << FixItHint::CreateRemoval(LParenLoc)
- << FixItHint::CreateRemoval(RParenLoc);
- LParenLoc = RParenLoc = SourceLocation();
- }
-
auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc);
// Avoid creating a non-type-dependent expression that contains typos.
// Non-type-dependent expressions are liable to be discarded without
@@ -1255,58 +1284,79 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
}
bool ListInitialization = LParenLoc.isInvalid();
- assert((!ListInitialization || (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0])))
- && "List initialization must have initializer list as expression.");
+ assert((!ListInitialization ||
+ (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) &&
+ "List initialization must have initializer list as expression.");
SourceRange FullRange = SourceRange(TyBeginLoc,
ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc);
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
+ InitializationKind Kind =
+ Exprs.size()
+ ? ListInitialization
+ ? InitializationKind::CreateDirectList(TyBeginLoc)
+ : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc,
+ RParenLoc)
+ : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc);
+
+ // C++1z [expr.type.conv]p1:
+ // If the type is a placeholder for a deduced class type, [...perform class
+ // template argument deduction...]
+ DeducedType *Deduced = Ty->getContainedDeducedType();
+ if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
+ Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity,
+ Kind, Exprs);
+ if (Ty.isNull())
+ return ExprError();
+ Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
+ }
+
// C++ [expr.type.conv]p1:
- // If the expression list is a single expression, the type conversion
- // expression is equivalent (in definedness, and if defined in meaning) to the
- // corresponding cast expression.
- if (Exprs.size() == 1 && !ListInitialization) {
+ // If the expression list is a parenthesized single expression, the type
+ // conversion expression is equivalent (in definedness, and if defined in
+ // meaning) to the corresponding cast expression.
+ if (Exprs.size() == 1 && !ListInitialization &&
+ !isa<InitListExpr>(Exprs[0])) {
Expr *Arg = Exprs[0];
- return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc);
+ return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenLoc, Arg, RParenLoc);
}
- // C++14 [expr.type.conv]p2: The expression T(), where T is a
- // simple-type-specifier or typename-specifier for a non-array complete
- // object type or the (possibly cv-qualified) void type, creates a prvalue
- // of the specified type, whose value is that produced by value-initializing
- // an object of type T.
+ // For an expression of the form T(), T shall not be an array type.
QualType ElemTy = Ty;
if (Ty->isArrayType()) {
if (!ListInitialization)
- return ExprError(Diag(TyBeginLoc,
- diag::err_value_init_for_array_type) << FullRange);
+ return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_array_type)
+ << FullRange);
ElemTy = Context.getBaseElementType(Ty);
}
- if (!ListInitialization && Ty->isFunctionType())
- return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_function_type)
- << FullRange);
+ // There doesn't seem to be an explicit rule against this but sanity demands
+ // we only construct objects with object types.
+ if (Ty->isFunctionType())
+ return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type)
+ << Ty << FullRange);
+ // C++17 [expr.type.conv]p2:
+ // If the type is cv void and the initializer is (), the expression is a
+ // prvalue of the specified type that performs no initialization.
if (!Ty->isVoidType() &&
RequireCompleteType(TyBeginLoc, ElemTy,
diag::err_invalid_incomplete_type_use, FullRange))
return ExprError();
- InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
- InitializationKind Kind =
- Exprs.size() ? ListInitialization
- ? InitializationKind::CreateDirectList(TyBeginLoc)
- : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, RParenLoc)
- : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc);
+ // Otherwise, the expression is a prvalue of the specified type whose
+ // result object is direct-initialized (11.6) with the initializer.
InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs);
- if (Result.isInvalid() || !ListInitialization)
+ if (Result.isInvalid())
return Result;
Expr *Inner = Result.get();
if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null<CXXBindTemporaryExpr>(Inner))
Inner = BTE->getSubExpr();
- if (!isa<CXXTemporaryObjectExpr>(Inner)) {
+ if (!isa<CXXTemporaryObjectExpr>(Inner) &&
+ !isa<CXXScalarValueInitExpr>(Inner)) {
// If we created a CXXTemporaryObjectExpr, that node also represents the
// functional cast. Otherwise, create an explicit cast to represent
// the syntactic form of a functional-style cast that was used here.
@@ -1317,7 +1367,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
// is sometimes handled by initialization and sometimes not.
QualType ResultType = Result.get()->getType();
Result = CXXFunctionalCastExpr::Create(
- Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo,
+ Context, ResultType, Expr::getValueKindForType(Ty), TInfo,
CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc);
}
@@ -1509,7 +1559,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (D.getNumTypeObjects() > 0 &&
D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
DeclaratorChunk &Chunk = D.getTypeObject(0);
- if (D.getDeclSpec().containsPlaceholderType())
+ if (D.getDeclSpec().hasAutoTypeSpec())
return ExprError(Diag(Chunk.Loc, diag::err_new_array_of_auto)
<< D.getSourceRange());
if (Chunk.Arr.hasStatic)
@@ -1562,20 +1612,8 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
return ExprError();
SourceRange DirectInitRange;
- if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
+ if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer))
DirectInitRange = List->getSourceRange();
- // Handle errors like: new int a({0})
- if (List->getNumExprs() == 1 &&
- !canInitializeWithParenthesizedList(AllocType))
- if (auto IList = dyn_cast<InitListExpr>(List->getExpr(0))) {
- Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens)
- << AllocType << List->getSourceRange()
- << FixItHint::CreateRemoval(List->getLocStart())
- << FixItHint::CreateRemoval(List->getLocEnd());
- DirectInitRange = SourceRange();
- Initializer = IList;
- }
- }
return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal,
PlacementLParen,
@@ -1608,6 +1646,27 @@ static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style,
return false;
}
+// Emit a diagnostic if an aligned allocation/deallocation function that is not
+// implemented in the standard library is selected.
+static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
+ SourceLocation Loc, bool IsDelete,
+ Sema &S) {
+ if (!S.getLangOpts().AlignedAllocationUnavailable)
+ return;
+
+ // Return if there is a definition.
+ if (FD.isDefined())
+ return;
+
+ bool IsAligned = false;
+ if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) {
+ S.Diag(Loc, diag::warn_aligned_allocation_unavailable)
+ << IsDelete << FD.getType().getAsString()
+ << S.getASTContext().getTargetInfo().getTriple().str();
+ S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable);
+ }
+}
+
ExprResult
Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SourceLocation PlacementLParen,
@@ -1643,8 +1702,38 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
NumInits = List->getNumExprs();
}
+ // C++11 [expr.new]p15:
+ // A new-expression that creates an object of type T initializes that
+ // object as follows:
+ InitializationKind Kind
+ // - If the new-initializer is omitted, the object is default-
+ // initialized (8.5); if no initialization is performed,
+ // the object has indeterminate value
+ = initStyle == CXXNewExpr::NoInit
+ ? InitializationKind::CreateDefault(TypeRange.getBegin())
+ // - Otherwise, the new-initializer is interpreted according to the
+ // initialization rules of 8.5 for direct-initialization.
+ : initStyle == CXXNewExpr::ListInit
+ ? InitializationKind::CreateDirectList(TypeRange.getBegin())
+ : InitializationKind::CreateDirect(TypeRange.getBegin(),
+ DirectInitRange.getBegin(),
+ DirectInitRange.getEnd());
+
// C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for.
- if (AllocType->isUndeducedType()) {
+ auto *Deduced = AllocType->getContainedDeducedType();
+ if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
+ if (ArraySize)
+ return ExprError(Diag(ArraySize->getExprLoc(),
+ diag::err_deduced_class_template_compound_type)
+ << /*array*/ 2 << ArraySize->getSourceRange());
+
+ InitializedEntity Entity
+ = InitializedEntity::InitializeNew(StartLoc, AllocType);
+ AllocType = DeduceTemplateSpecializationFromInitializer(
+ AllocTypeInfo, Entity, Kind, MultiExprArg(Inits, NumInits));
+ if (AllocType.isNull())
+ return ExprError();
+ } else if (Deduced) {
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange);
@@ -1931,23 +2020,6 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
else
InitType = AllocType;
- // C++11 [expr.new]p15:
- // A new-expression that creates an object of type T initializes that
- // object as follows:
- InitializationKind Kind
- // - If the new-initializer is omitted, the object is default-
- // initialized (8.5); if no initialization is performed,
- // the object has indeterminate value
- = initStyle == CXXNewExpr::NoInit
- ? InitializationKind::CreateDefault(TypeRange.getBegin())
- // - Otherwise, the new-initializer is interpreted according to the
- // initialization rules of 8.5 for direct-initialization.
- : initStyle == CXXNewExpr::ListInit
- ? InitializationKind::CreateDirectList(TypeRange.getBegin())
- : InitializationKind::CreateDirect(TypeRange.getBegin(),
- DirectInitRange.getBegin(),
- DirectInitRange.getEnd());
-
InitializedEntity Entity
= InitializedEntity::InitializeNew(StartLoc, InitType);
InitializationSequence InitSeq(*this, Entity, Kind,
@@ -1972,11 +2044,13 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (DiagnoseUseOfDecl(OperatorNew, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorNew);
+ diagnoseUnavailableAlignedAllocation(*OperatorNew, StartLoc, false, *this);
}
if (OperatorDelete) {
if (DiagnoseUseOfDecl(OperatorDelete, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorDelete);
+ diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, *this);
}
// C++0x [expr.new]p17:
@@ -2025,9 +2099,10 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
else if (AllocType->isVariablyModifiedType())
return Diag(Loc, diag::err_variably_modified_new_type)
<< AllocType;
- else if (unsigned AddressSpace = AllocType.getAddressSpace())
+ else if (AllocType.getAddressSpace())
return Diag(Loc, diag::err_address_space_qualified_new)
- << AllocType.getUnqualifiedType() << AddressSpace;
+ << AllocType.getUnqualifiedType()
+ << AllocType.getQualifiers().getAddressSpaceAttributePrintValue();
else if (getLangOpts().ObjCAutoRefCount) {
if (const ArrayType *AT = Context.getAsArrayType(AllocType)) {
QualType BaseAllocType = Context.getBaseElementType(AT);
@@ -2578,7 +2653,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
// Make the function visible to name lookup, even if we found it in
// an unimported module. It either is an implicitly-declared global
// allocation function, or is suppressing that function.
- Func->setHidden(false);
+ Func->setVisibleDespiteOwningModule();
return;
}
}
@@ -2609,6 +2684,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
Context, GlobalCtx, SourceLocation(), SourceLocation(), Name,
FnType, /*TInfo=*/nullptr, SC_None, false, true);
Alloc->setImplicit();
+ // Global allocation functions should always be visible.
+ Alloc->setVisibleDespiteOwningModule();
// Implicit sized deallocation functions always have default visibility.
Alloc->addAttr(
@@ -3094,10 +3171,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
QualType PointeeElem = Context.getBaseElementType(Pointee);
- if (unsigned AddressSpace = Pointee.getAddressSpace())
+ if (Pointee.getAddressSpace())
return Diag(Ex.get()->getLocStart(),
diag::err_address_space_qualified_delete)
- << Pointee.getUnqualifiedType() << AddressSpace;
+ << Pointee.getUnqualifiedType()
+ << Pointee.getQualifiers().getAddressSpaceAttributePrintValue();
CXXRecordDecl *PointeeRD = nullptr;
if (Pointee->isVoidType() && !isSFINAEContext()) {
@@ -3188,6 +3266,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
PDiag(diag::err_access_dtor) << PointeeElem);
}
}
+
+ diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true,
+ *this);
}
CXXDeleteExpr *Result = new (Context) CXXDeleteExpr(
@@ -3703,10 +3784,9 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (From->getType()->isObjCObjectPointerType() &&
ToType->isObjCObjectPointerType())
EmitRelatedResultTypeNote(From);
- }
- else if (getLangOpts().ObjCAutoRefCount &&
- !CheckObjCARCUnavailableWeakConversion(ToType,
- From->getType())) {
+ } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
+ !CheckObjCARCUnavailableWeakConversion(ToType,
+ From->getType())) {
if (Action == AA_Initializing)
Diag(From->getLocStart(),
diag::err_arc_weak_unavailable_assign);
@@ -3729,8 +3809,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
(void) PrepareCastToObjCObjectPointer(E);
From = E.get();
}
- if (getLangOpts().ObjCAutoRefCount)
- CheckObjCARCConversion(SourceRange(), ToType, From, CCK);
+ if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
+ CheckObjCConversion(SourceRange(), ToType, From, CCK);
From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
.get();
break;
@@ -4031,23 +4111,17 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
return true;
- // C++0x [meta.unary.prop] Table 49 requires the following traits to be
- // applied to a complete type.
+ // C++1z [meta.unary.prop]:
+ // remove_all_extents_t<T> shall be a complete type or cv void.
+ case UTT_IsAggregate:
case UTT_IsTrivial:
case UTT_IsTriviallyCopyable:
case UTT_IsStandardLayout:
case UTT_IsPOD:
case UTT_IsLiteral:
-
- case UTT_IsDestructible:
- case UTT_IsNothrowDestructible:
- // Fall-through
-
- // These trait expressions are designed to help implement predicates in
- // [meta.unary.prop] despite not being named the same. They are specified
- // by both GCC and the Embarcadero C++ compiler, and require the complete
- // type due to the overarching C++0x type predicates being implemented
- // requiring the complete type.
+ // Per the GCC type traits documentation, T shall be a complete type, cv void,
+ // or an array of unknown bound. But GCC actually imposes the same constraints
+ // as above.
case UTT_HasNothrowAssign:
case UTT_HasNothrowMoveAssign:
case UTT_HasNothrowConstructor:
@@ -4059,17 +4133,19 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_HasTrivialCopy:
case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor:
- // Arrays of unknown bound are expressly allowed.
- QualType ElTy = ArgTy;
- if (ArgTy->isIncompleteArrayType())
- ElTy = S.Context.getAsArrayType(ArgTy)->getElementType();
+ ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
+ LLVM_FALLTHROUGH;
- // The void type is expressly allowed.
- if (ElTy->isVoidType())
+ // C++1z [meta.unary.prop]:
+ // T shall be a complete type, cv void, or an array of unknown bound.
+ case UTT_IsDestructible:
+ case UTT_IsNothrowDestructible:
+ case UTT_IsTriviallyDestructible:
+ if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
return true;
return !S.RequireCompleteType(
- Loc, ElTy, diag::err_incomplete_type_used_in_type_trait_expr);
+ Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
}
}
@@ -4207,6 +4283,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return !RD->isUnion() && RD->isAbstract();
return false;
+ case UTT_IsAggregate:
+ // Report vector extensions and complex types as aggregates because they
+ // support aggregate initialization. GCC mirrors this behavior for vectors
+ // but not _Complex.
+ return T->isAggregateType() || T->isVectorType() || T->isExtVectorType() ||
+ T->isAnyComplexType();
// __is_interface_class only returns true when CL is invoked in /CLR mode and
// even then only when it is used with the 'interface struct ...' syntax
// Clang doesn't support /CLR which makes this type trait moot.
@@ -4300,6 +4382,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
!RD->hasNonTrivialCopyAssignment();
return false;
case UTT_IsDestructible:
+ case UTT_IsTriviallyDestructible:
case UTT_IsNothrowDestructible:
// C++14 [meta.unary.prop]:
// For reference types, is_destructible<T>::value is true.
@@ -4317,6 +4400,11 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (T->isIncompleteType() || T->isFunctionType())
return false;
+ // A type that requires destruction (via a non-trivial destructor or ARC
+ // lifetime semantics) is not trivially-destructible.
+ if (UTT == UTT_IsTriviallyDestructible && T.isDestructedType())
+ return false;
+
// C++14 [meta.unary.prop]:
// For object types and given U equal to remove_all_extents_t<T>, if the
// expression std::declval<U&>().~U() is well-formed when treated as an
@@ -4495,25 +4583,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
}
}
-/// \brief Determine whether T has a non-trivial Objective-C lifetime in
-/// ARC mode.
-static bool hasNontrivialObjCLifetime(QualType T) {
- switch (T.getObjCLifetime()) {
- case Qualifiers::OCL_ExplicitNone:
- return false;
-
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Autoreleasing:
- return true;
-
- case Qualifiers::OCL_None:
- return T->isObjCLifetimeType();
- }
-
- llvm_unreachable("Unknown ObjC lifetime qualifier");
-}
-
static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
QualType RhsT, SourceLocation KeyLoc);
@@ -4586,7 +4655,8 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
// Perform the initialization in an unevaluated context within a SFINAE
// trap at translation unit scope.
- EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0]));
@@ -4607,10 +4677,9 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
return S.canThrow(Result.get()) == CT_Cannot;
if (Kind == clang::TT_IsTriviallyConstructible) {
- // Under Objective-C ARC, if the destination has non-trivial Objective-C
- // lifetime, this is a non-trivial construction.
- if (S.getLangOpts().ObjCAutoRefCount &&
- hasNontrivialObjCLifetime(T.getNonReferenceType()))
+ // Under Objective-C ARC and Weak, if the destination has non-trivial
+ // Objective-C lifetime, this is a non-trivial construction.
+ if (T.getNonReferenceType().hasNonTrivialObjCLifetime())
return false;
// The initialization succeeded; now make sure there are no non-trivial
@@ -4683,10 +4752,24 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
// regard to cv-qualifiers.
const RecordType *lhsRecord = LhsT->getAs<RecordType>();
- if (!lhsRecord) return false;
-
const RecordType *rhsRecord = RhsT->getAs<RecordType>();
- if (!rhsRecord) return false;
+ if (!rhsRecord || !lhsRecord) {
+ const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>();
+ const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>();
+ if (!LHSObjTy || !RHSObjTy)
+ return false;
+
+ ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface();
+ ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface();
+ if (!BaseInterface || !DerivedInterface)
+ return false;
+
+ if (Self.RequireCompleteType(
+ KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr))
+ return false;
+
+ return BaseInterface->isSuperClassOf(DerivedInterface);
+ }
assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT)
== (lhsRecord == rhsRecord));
@@ -4763,7 +4846,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
// Perform the initialization in an unevaluated context within a SFINAE
// trap at translation unit scope.
- EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ Self, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true);
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
InitializationSequence Init(Self, To, Kind, FromPtr);
@@ -4814,7 +4898,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
// Attempt the assignment in an unevaluated context within a SFINAE
// trap at translation unit scope.
- EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ Self, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true);
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs,
@@ -4829,10 +4914,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
return Self.canThrow(Result.get()) == CT_Cannot;
if (BTT == BTT_IsTriviallyAssignable) {
- // Under Objective-C ARC, if the destination has non-trivial Objective-C
- // lifetime, this is a non-trivial assignment.
- if (Self.getLangOpts().ObjCAutoRefCount &&
- hasNontrivialObjCLifetime(LhsT.getNonReferenceType()))
+ // Under Objective-C ARC and Weak, if the destination has non-trivial
+ // Objective-C lifetime, this is a non-trivial assignment.
+ if (LhsT.getNonReferenceType().hasNonTrivialObjCLifetime())
return false;
return !Result.get()->hasNonTrivialCall(Self.Context);
@@ -5053,7 +5137,9 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
return QualType();
// Cast LHS to type of use.
- QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
+ QualType UseType = Context.getQualifiedType(Class, LHSType.getQualifiers());
+ if (isIndirect)
+ UseType = Context.getPointerType(UseType);
ExprValueKind VK = isIndirect ? VK_RValue : LHS.get()->getValueKind();
LHS = ImpCastExprToType(LHS.get(), UseType, CK_DerivedToBase, VK,
&BasePath);
@@ -5230,16 +5316,16 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS
switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) {
case OR_Success: {
// We found a match. Perform the conversions on the arguments and move on.
- ExprResult LHSRes =
- Self.PerformImplicitConversion(LHS.get(), Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], Sema::AA_Converting);
+ ExprResult LHSRes = Self.PerformImplicitConversion(
+ LHS.get(), Best->BuiltinParamTypes[0], Best->Conversions[0],
+ Sema::AA_Converting);
if (LHSRes.isInvalid())
break;
LHS = LHSRes;
- ExprResult RHSRes =
- Self.PerformImplicitConversion(RHS.get(), Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], Sema::AA_Converting);
+ ExprResult RHSRes = Self.PerformImplicitConversion(
+ RHS.get(), Best->BuiltinParamTypes[1], Best->Conversions[1],
+ Sema::AA_Converting);
if (RHSRes.isInvalid())
break;
RHS = RHSRes;
@@ -5304,6 +5390,15 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
+ //
+ // FIXME; GCC's vector extension permits the use of a?b:c where the type of
+ // a is that of a integer vector with the same number of elements and
+ // size as the vectors of b and c. If one of either b or c is a scalar
+ // it is implicitly converted to match the type of the vector.
+ // Otherwise the expression is ill-formed. If both b and c are scalars,
+ // then b and c are checked and converted to the type of a if possible.
+ // Unlike the OpenCL ?: operator, the expression is evaluated as
+ // (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
if (!Cond.get()->isTypeDependent()) {
ExprResult CondRes = CheckCXXBooleanCondition(Cond.get());
if (CondRes.isInvalid())
@@ -5967,9 +6062,21 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
} else if (ObjCBoxedExpr *BoxedExpr = dyn_cast<ObjCBoxedExpr>(E)) {
D = BoxedExpr->getBoxingMethod();
} else if (ObjCArrayLiteral *ArrayLit = dyn_cast<ObjCArrayLiteral>(E)) {
+ // Don't do reclaims if we're using the zero-element array
+ // constant.
+ if (ArrayLit->getNumElements() == 0 &&
+ Context.getLangOpts().ObjCRuntime.hasEmptyCollections())
+ return E;
+
D = ArrayLit->getArrayWithObjectsMethod();
} else if (ObjCDictionaryLiteral *DictLit
= dyn_cast<ObjCDictionaryLiteral>(E)) {
+ // Don't do reclaims if we're using the zero-element dictionary
+ // constant.
+ if (DictLit->getNumElements() == 0 &&
+ Context.getLangOpts().ObjCRuntime.hasEmptyCollections())
+ return E;
+
D = DictLit->getDictWithObjectsMethod();
}
@@ -6136,7 +6243,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
return E;
return new (Context) BinaryOperator(
BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(),
- BO->getObjectKind(), BO->getOperatorLoc(), BO->isFPContractable());
+ BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures());
}
}
@@ -6402,6 +6509,23 @@ static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base,
return false;
}
+/// \brief Check if it's ok to try and recover dot pseudo destructor calls on
+/// pointer objects.
+static bool
+canRecoverDotPseudoDestructorCallsOnPointerObjects(Sema &SemaRef,
+ QualType DestructedType) {
+ // If this is a record type, check if its destructor is callable.
+ if (auto *RD = DestructedType->getAsCXXRecordDecl()) {
+ if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD))
+ return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false);
+ return false;
+ }
+
+ // Otherwise, check if it's a type for which it's valid to use a pseudo-dtor.
+ return DestructedType->isDependentType() || DestructedType->isScalarType() ||
+ DestructedType->isVectorType();
+}
+
ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
@@ -6436,15 +6560,36 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
= DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) {
if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
- Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
- << ObjectType << DestructedType << Base->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
-
- // Recover by setting the destructed type to the object type.
- DestructedType = ObjectType;
- DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
- DestructedTypeStart);
- Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ // Detect dot pseudo destructor calls on pointer objects, e.g.:
+ // Foo *foo;
+ // foo.~Foo();
+ if (OpKind == tok::period && ObjectType->isPointerType() &&
+ Context.hasSameUnqualifiedType(DestructedType,
+ ObjectType->getPointeeType())) {
+ auto Diagnostic =
+ Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << ObjectType << /*IsArrow=*/0 << Base->getSourceRange();
+
+ // Issue a fixit only when the destructor is valid.
+ if (canRecoverDotPseudoDestructorCallsOnPointerObjects(
+ *this, DestructedType))
+ Diagnostic << FixItHint::CreateReplacement(OpLoc, "->");
+
+ // Recover by setting the object type to the destructed type and the
+ // operator to '->'.
+ ObjectType = DestructedType;
+ OpKind = tok::arrow;
+ } else {
+ Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo =
+ Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ }
} else if (DestructedType.getObjCLifetime() !=
ObjectType.getObjCLifetime()) {
@@ -6537,7 +6682,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
ParsedType T = getTypeName(*SecondTypeName.Identifier,
SecondTypeName.StartLocation,
- S, &SS, true, false, ObjectTypePtrForLookup);
+ S, &SS, true, false, ObjectTypePtrForLookup,
+ /*IsCtorOrDtorName*/true);
if (!T &&
((SS.isSet() && !computeDeclContext(SS, false)) ||
(!SS.isSet() && ObjectType->isDependentType()))) {
@@ -6566,10 +6712,12 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
TypeResult T = ActOnTemplateIdType(TemplateId->SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
+ TemplateId->Name,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
- TemplateId->RAngleLoc);
+ TemplateId->RAngleLoc,
+ /*IsCtorOrDtorName*/true);
if (T.isInvalid() || !T.get()) {
// Recover by assuming we had the right type all along.
DestructedType = ObjectType;
@@ -6594,7 +6742,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
ParsedType T = getTypeName(*FirstTypeName.Identifier,
FirstTypeName.StartLocation,
- S, &SS, true, false, ObjectTypePtrForLookup);
+ S, &SS, true, false, ObjectTypePtrForLookup,
+ /*IsCtorOrDtorName*/true);
if (!T) {
Diag(FirstTypeName.StartLocation,
diag::err_pseudo_dtor_destructor_non_type)
@@ -6615,10 +6764,12 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
TypeResult T = ActOnTemplateIdType(TemplateId->SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
+ TemplateId->Name,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
- TemplateId->RAngleLoc);
+ TemplateId->RAngleLoc,
+ /*IsCtorOrDtorName*/true);
if (T.isInvalid() || !T.get()) {
// Recover by dropping this type.
ScopeType = QualType();
@@ -6681,7 +6832,8 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
// follows the normal lifetime rules for block literals instead of being
// autoreleased.
DiagnosticErrorTrap Trap(Diags);
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
ExprResult Exp = BuildBlockForLambdaConversion(E->getExprLoc(),
E->getExprLoc(),
Method, E);
@@ -6732,8 +6884,7 @@ ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand,
// The operand may have been modified when checking the placeholder type.
Operand = R.get();
- if (ActiveTemplateInstantiations.empty() &&
- Operand->HasSideEffects(Context, false)) {
+ if (!inTemplateInstantiation() && Operand->HasSideEffects(Context, false)) {
// The expression operand for noexcept is in an unevaluated expression
// context, so side effects could result in unintended consequences.
Diag(Operand->getExprLoc(), diag::warn_side_effects_unevaluated_context);
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp
index c9aa99e..c3d0e2d 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp
@@ -133,20 +133,20 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
IMAKind AbstractInstanceResult = IMA_Static; // happens to be 'false'
assert(!AbstractInstanceResult);
switch (SemaRef.ExprEvalContexts.back().Context) {
- case Sema::Unevaluated:
- case Sema::UnevaluatedList:
+ case Sema::ExpressionEvaluationContext::Unevaluated:
+ case Sema::ExpressionEvaluationContext::UnevaluatedList:
if (isField && SemaRef.getLangOpts().CPlusPlus11)
AbstractInstanceResult = IMA_Field_Uneval_Context;
break;
- case Sema::UnevaluatedAbstract:
+ case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
AbstractInstanceResult = IMA_Abstract;
break;
- case Sema::DiscardedStatement:
- case Sema::ConstantEvaluated:
- case Sema::PotentiallyEvaluated:
- case Sema::PotentiallyEvaluatedIfUsed:
+ case Sema::ExpressionEvaluationContext::DiscardedStatement:
+ case Sema::ExpressionEvaluationContext::ConstantEvaluated:
+ case Sema::ExpressionEvaluationContext::PotentiallyEvaluated:
+ case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
break;
}
@@ -284,6 +284,14 @@ IsRGBA(char c) {
}
}
+// OpenCL v1.1, s6.1.7
+// The component swizzle length must be in accordance with the acceptable
+// vector sizes.
+static bool IsValidOpenCLComponentSwizzleLength(unsigned len)
+{
+ return (len >= 1 && len <= 4) || len == 8 || len == 16;
+}
+
/// Check an ext-vector component access expression.
///
/// VK should be set in advance to the value kind of the base
@@ -376,6 +384,19 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
}
}
+ if (!HalvingSwizzle) {
+ unsigned SwizzleLength = CompName->getLength();
+
+ if (HexSwizzle)
+ SwizzleLength--;
+
+ if (IsValidOpenCLComponentSwizzleLength(SwizzleLength) == false) {
+ S.Diag(OpLoc, diag::err_opencl_ext_vector_component_invalid_length)
+ << SwizzleLength << SourceRange(CompLoc);
+ return QualType();
+ }
+ }
+
// The component accessor looks fine - now we need to compute the actual type.
// The vector type is implied by the component accessor. For example,
// vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc.
@@ -973,7 +994,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// C++1z [expr.ref]p2:
// For the first option (dot) the first expression shall be a glvalue [...]
- if (!IsArrow && BaseExpr->isRValue()) {
+ if (!IsArrow && BaseExpr && BaseExpr->isRValue()) {
ExprResult Converted = TemporaryMaterializationConversion(BaseExpr);
if (Converted.isInvalid())
return ExprError();
@@ -1475,7 +1496,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
}
}
bool warn = true;
- if (S.getLangOpts().ObjCAutoRefCount) {
+ if (S.getLangOpts().ObjCWeak) {
Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts();
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp))
if (UO->getOpcode() == UO_Deref)
@@ -1502,11 +1523,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
IV, IV->getUsageType(BaseType), MemberLoc, OpLoc, BaseExpr.get(),
IsArrow);
- if (S.getLangOpts().ObjCAutoRefCount) {
- if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- if (!S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, MemberLoc))
- S.recordUseOfEvaluatedWeak(Result);
- }
+ if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ if (!S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, MemberLoc))
+ S.recordUseOfEvaluatedWeak(Result);
}
return Result;
@@ -1823,10 +1842,6 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
FoundDecl, Field);
if (Base.isInvalid())
return ExprError();
- MemberExpr *ME =
- BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS,
- /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
- MemberNameInfo, MemberType, VK, OK);
// Build a reference to a private copy for non-static data members in
// non-static member functions, privatized by OpenMP constructs.
@@ -1836,7 +1851,10 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field))
return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc);
}
- return ME;
+
+ return BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS,
+ /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
+ MemberNameInfo, MemberType, VK, OK);
}
/// Builds an implicit member access expression. The current context
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp
index 7dbd660..28581ba 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp
@@ -595,7 +595,6 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
break;
}
}
- CheckForIntOverflow(ValueExpr);
// FIXME: Do I need to do anything special with BoolTy expressions?
// Look for the appropriate method within NSNumber.
@@ -1984,13 +1983,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
}
}
+ Selector GetterSel;
+ Selector SetterSel;
+ if (auto PD = IFace->FindPropertyDeclaration(
+ &propertyName, ObjCPropertyQueryKind::OBJC_PR_query_class)) {
+ GetterSel = PD->getGetterName();
+ SetterSel = PD->getSetterName();
+ } else {
+ GetterSel = PP.getSelectorTable().getNullarySelector(&propertyName);
+ SetterSel = SelectorTable::constructSetterSelector(
+ PP.getIdentifierTable(), PP.getSelectorTable(), &propertyName);
+ }
+
// Search for a declared property first.
- Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
- ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel);
+ ObjCMethodDecl *Getter = IFace->lookupClassMethod(GetterSel);
// If this reference is in an @implementation, check for 'private' methods.
if (!Getter)
- Getter = IFace->lookupPrivateClassMethod(Sel);
+ Getter = IFace->lookupPrivateClassMethod(GetterSel);
if (Getter) {
// FIXME: refactor/share with ActOnMemberReference().
@@ -2000,11 +2010,6 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
}
// Look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
- PP.getSelectorTable(),
- &propertyName);
-
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
if (!Setter) {
// If this reference is in an @implementation, also check for 'private'
@@ -2260,6 +2265,53 @@ static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) {
edit::rewriteObjCRedundantCallWithLiteral);
}
+static void checkFoundationAPI(Sema &S, SourceLocation Loc,
+ const ObjCMethodDecl *Method,
+ ArrayRef<Expr *> Args, QualType ReceiverType,
+ bool IsClassObjectCall) {
+ // Check if this is a performSelector method that uses a selector that returns
+ // a record or a vector type.
+ if (Method->getSelector().getMethodFamily() != OMF_performSelector ||
+ Args.empty())
+ return;
+ const auto *SE = dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens());
+ if (!SE)
+ return;
+ ObjCMethodDecl *ImpliedMethod;
+ if (!IsClassObjectCall) {
+ const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>();
+ if (!OPT || !OPT->getInterfaceDecl())
+ return;
+ ImpliedMethod =
+ OPT->getInterfaceDecl()->lookupInstanceMethod(SE->getSelector());
+ if (!ImpliedMethod)
+ ImpliedMethod =
+ OPT->getInterfaceDecl()->lookupPrivateMethod(SE->getSelector());
+ } else {
+ const auto *IT = ReceiverType->getAs<ObjCInterfaceType>();
+ if (!IT)
+ return;
+ ImpliedMethod = IT->getDecl()->lookupClassMethod(SE->getSelector());
+ if (!ImpliedMethod)
+ ImpliedMethod =
+ IT->getDecl()->lookupPrivateClassMethod(SE->getSelector());
+ }
+ if (!ImpliedMethod)
+ return;
+ QualType Ret = ImpliedMethod->getReturnType();
+ if (Ret->isRecordType() || Ret->isVectorType() || Ret->isExtVectorType()) {
+ QualType Ret = ImpliedMethod->getReturnType();
+ S.Diag(Loc, diag::warn_objc_unsafe_perform_selector)
+ << Method->getSelector()
+ << (!Ret->isRecordType()
+ ? /*Vector*/ 2
+ : Ret->isUnionType() ? /*Union*/ 1 : /*Struct*/ 0);
+ S.Diag(ImpliedMethod->getLocStart(),
+ diag::note_objc_unsafe_perform_selector_method_declared_here)
+ << ImpliedMethod->getSelector() << Ret;
+ }
+}
+
/// \brief Diagnose use of %s directive in an NSString which is being passed
/// as formatting string to formatting method.
static void
@@ -2462,6 +2514,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
if (!isImplicit)
checkCocoaAPI(*this, Result);
}
+ if (Method)
+ checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs),
+ ReceiverType, /*IsClassObjectCall=*/true);
return MaybeBindToTemporary(Result);
}
@@ -2501,6 +2556,24 @@ ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
/*isImplicit=*/true);
}
+static bool isMethodDeclaredInRootProtocol(Sema &S, const ObjCMethodDecl *M) {
+ if (!S.NSAPIObj)
+ return false;
+ const auto *Protocol = dyn_cast<ObjCProtocolDecl>(M->getDeclContext());
+ if (!Protocol)
+ return false;
+ const IdentifierInfo *II = S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject);
+ if (const auto *RootClass = dyn_cast_or_null<ObjCInterfaceDecl>(
+ S.LookupSingleName(S.TUScope, II, Protocol->getLocStart(),
+ Sema::LookupOrdinaryName))) {
+ for (const ObjCProtocolDecl *P : RootClass->all_referenced_protocols()) {
+ if (P->getCanonicalDecl() == Protocol->getCanonicalDecl())
+ return true;
+ }
+ }
+ return false;
+}
+
/// \brief Build an Objective-C instance message expression.
///
/// This routine takes care of both normal instance messages and
@@ -2676,7 +2749,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (!Method) {
Method = LookupMethodInQualifiedType(Sel, QClassTy, true);
// warn if instance method found for a Class message.
- if (Method) {
+ if (Method && !isMethodDeclaredInRootProtocol(*this, Method)) {
Diag(SelLoc, diag::warn_instance_method_on_class_found)
<< Method->getSelector() << Sel;
Diag(Method->getLocation(), diag::note_method_declared_at)
@@ -2920,7 +2993,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
case OMF_performSelector:
if (Method && NumArgs >= 1) {
- if (ObjCSelectorExpr *SelExp = dyn_cast<ObjCSelectorExpr>(Args[0])) {
+ if (const auto *SelExp =
+ dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens())) {
Selector ArgSel = SelExp->getSelector();
ObjCMethodDecl *SelMethod =
LookupInstanceMethodInGlobalPool(ArgSel,
@@ -2936,7 +3010,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
case OMF_copy:
case OMF_mutableCopy:
case OMF_new:
- case OMF_self:
case OMF_init:
// Issue error, unless ns_returns_not_retained.
if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) {
@@ -2987,6 +3060,26 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (!isImplicit)
checkCocoaAPI(*this, Result);
}
+ if (Method) {
+ bool IsClassObjectCall = ClassMessage;
+ // 'self' message receivers in class methods should be treated as message
+ // sends to the class object in order for the semantic checks to be
+ // performed correctly. Messages to 'super' already count as class messages,
+ // so they don't need to be handled here.
+ if (Receiver && isSelfExpr(Receiver)) {
+ if (const auto *OPT = ReceiverType->getAs<ObjCObjectPointerType>()) {
+ if (OPT->getObjectType()->isObjCClass()) {
+ if (const auto *CurMeth = getCurMethodDecl()) {
+ IsClassObjectCall = true;
+ ReceiverType =
+ Context.getObjCInterfaceType(CurMeth->getClassInterface());
+ }
+ }
+ }
+ }
+ checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs),
+ ReceiverType, IsClassObjectCall);
+ }
if (getLangOpts().ObjCAutoRefCount) {
// In ARC, annotate delegate init calls.
@@ -3006,7 +3099,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// In ARC, check for message sends which are likely to introduce
// retain cycles.
checkRetainCycles(Result);
+ }
+ if (getLangOpts().ObjCWeak) {
if (!isImplicit && Method) {
if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) {
bool IsWeak =
@@ -3259,7 +3354,7 @@ namespace {
if (isAnyRetainable(TargetClass) &&
isAnyRetainable(SourceClass) &&
var &&
- var->getStorageClass() == SC_Extern &&
+ !var->hasDefinition(Context) &&
var->getType().isConstQualified()) {
// In system headers, they can also be assumed to be immune to retains.
@@ -4012,11 +4107,10 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
}
Sema::ARCConversionResult
-Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
- Expr *&castExpr, CheckedConversionKind CCK,
- bool Diagnose,
- bool DiagnoseCFAudited,
- BinaryOperatorKind Opc) {
+Sema::CheckObjCConversion(SourceRange castRange, QualType castType,
+ Expr *&castExpr, CheckedConversionKind CCK,
+ bool Diagnose, bool DiagnoseCFAudited,
+ BinaryOperatorKind Opc) {
QualType castExprType = castExpr->getType();
// For the purposes of the classification, we assume reference types
@@ -4056,7 +4150,12 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
}
return ACR_okay;
}
-
+
+ // The life-time qualifier cast check above is all we need for ObjCWeak.
+ // ObjCAutoRefCount has more restrictions on what is legal.
+ if (!getLangOpts().ObjCAutoRefCount)
+ return ACR_okay;
+
if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return ACR_okay;
// Allow all of these types to be cast to integer types (but not
@@ -4142,8 +4241,7 @@ void Sema::diagnoseARCUnbridgedCast(Expr *e) {
castType = cast->getTypeAsWritten();
CCK = CCK_OtherCast;
} else {
- castType = cast->getType();
- CCK = CCK_ImplicitConversion;
+ llvm_unreachable("Unexpected ImplicitCastExpr");
}
ARCConversionTypeClass castACTC =
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp
index b053c83..32024cb 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp
@@ -623,6 +623,11 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
+ // A transparent ILE is not performing aggregate initialization and should
+ // not be filled in.
+ if (ILE->isTransparent())
+ return;
+
if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
const RecordDecl *RDecl = RType->getDecl();
if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
@@ -902,7 +907,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
// Don't warn during template instantiation. If the initialization was
// non-dependent, we warned during the initial parse; otherwise, the
// type might not be scalar in some uses of the template.
- if (!S.ActiveTemplateInstantiations.empty())
+ if (S.inTemplateInstantiation())
return;
unsigned DiagID = 0;
@@ -945,6 +950,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_Binding:
llvm_unreachable("unexpected braced scalar init");
}
@@ -1203,7 +1209,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
} else {
assert((ElemType->isRecordType() || ElemType->isVectorType() ||
- ElemType->isClkEventT()) && "Unexpected type");
+ ElemType->isOpenCLSpecificType()) && "Unexpected type");
// C99 6.7.8p13:
//
@@ -2237,6 +2243,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
}
unsigned FieldIndex = 0;
+
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ FieldIndex = CXXRD->getNumBases();
+
for (auto *FI : RT->getDecl()->fields()) {
if (FI->isUnnamedBitfield())
continue;
@@ -2260,15 +2270,17 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
assert(StructuredList->getNumInits() == 1
&& "A union should never have more than one initializer!");
- // We're about to throw away an initializer, emit warning.
- SemaRef.Diag(D->getFieldLoc(),
- diag::warn_initializer_overrides)
- << D->getSourceRange();
Expr *ExistingInit = StructuredList->getInit(0);
- SemaRef.Diag(ExistingInit->getLocStart(),
- diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0
- << ExistingInit->getSourceRange();
+ if (ExistingInit) {
+ // We're about to throw away an initializer, emit warning.
+ SemaRef.Diag(D->getFieldLoc(),
+ diag::warn_initializer_overrides)
+ << D->getSourceRange();
+ SemaRef.Diag(ExistingInit->getLocStart(),
+ diag::note_previous_initializer)
+ << /*FIXME:has side effects=*/0
+ << ExistingInit->getSourceRange();
+ }
// remove existing initializer
StructuredList->resizeInits(SemaRef.Context, 0);
@@ -2925,6 +2937,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_VectorElement:
case EK_ComplexElement:
case EK_BlockElement:
+ case EK_LambdaToBlockConversionBlockElement:
case EK_CompoundLiteralInit:
case EK_RelatedResult:
return DeclarationName();
@@ -2954,6 +2967,7 @@ ValueDecl *InitializedEntity::getDecl() const {
case EK_VectorElement:
case EK_ComplexElement:
case EK_BlockElement:
+ case EK_LambdaToBlockConversionBlockElement:
case EK_LambdaCapture:
case EK_CompoundLiteralInit:
case EK_RelatedResult:
@@ -2983,6 +2997,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_VectorElement:
case EK_ComplexElement:
case EK_BlockElement:
+ case EK_LambdaToBlockConversionBlockElement:
case EK_LambdaCapture:
case EK_RelatedResult:
break;
@@ -3016,6 +3031,9 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
case EK_VectorElement: OS << "VectorElement " << Index; break;
case EK_ComplexElement: OS << "ComplexElement " << Index; break;
case EK_BlockElement: OS << "Block"; break;
+ case EK_LambdaToBlockConversionBlockElement:
+ OS << "Block (lambda)";
+ break;
case EK_LambdaCapture:
OS << "LambdaCapture ";
OS << DeclarationName(Capture.VarID);
@@ -3103,6 +3121,7 @@ bool InitializationSequence::isAmbiguous() const {
switch (getFailureKind()) {
case FK_TooManyInitsForReference:
+ case FK_ParenthesizedListInitForReference:
case FK_ArrayNeedsInitList:
case FK_ArrayNeedsInitListOrStringLiteral:
case FK_ArrayNeedsInitListOrWideStringLiteral:
@@ -3120,6 +3139,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_ConversionFailed:
case FK_ConversionFromPropertyFailed:
case FK_TooManyInitsForScalar:
+ case FK_ParenthesizedListInitForScalar:
case FK_ReferenceBindingToInitList:
case FK_InitListBadDestinationType:
case FK_DefaultInitOfConst:
@@ -3611,9 +3631,13 @@ static void TryConstructorInitialization(Sema &S,
// destination object.
// Per DR (no number yet), this does not apply when initializing a base
// class or delegating to another constructor from a mem-initializer.
+ // ObjC++: Lambda captured by the block in the lambda to block conversion
+ // should avoid copy elision.
if (S.getLangOpts().CPlusPlus1z &&
Entity.getKind() != InitializedEntity::EK_Base &&
Entity.getKind() != InitializedEntity::EK_Delegating &&
+ Entity.getKind() !=
+ InitializedEntity::EK_LambdaToBlockConversionBlockElement &&
UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isRValue() &&
S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(), DestType)) {
// Convert qualifications if necessary.
@@ -3977,6 +4001,8 @@ static void TryListInitialization(Sema &S,
ImplicitConversionSequence ICS;
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
+ if (!E->isRValue())
+ ICS.Standard.First = ICK_Lvalue_To_Rvalue;
// If E is of a floating-point type, then the conversion is ill-formed
// due to narrowing, but go through the motions in order to produce the
// right diagnostic.
@@ -4675,15 +4701,7 @@ static void TryUserDefinedConversion(Sema &S,
// Try to complete the type we're converting to.
if (S.isCompleteType(Kind.getLocation(), DestType)) {
- DeclContext::lookup_result R = S.LookupConstructors(DestRecordDecl);
- // The container holding the constructors can under certain conditions
- // be changed while iterating. To be safe we copy the lookup results
- // to a new container.
- SmallVector<NamedDecl*, 8> CopyOfCon(R.begin(), R.end());
- for (SmallVectorImpl<NamedDecl *>::iterator
- Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end();
- Con != ConEnd; ++Con) {
- NamedDecl *D = *Con;
+ for (NamedDecl *D : S.LookupConstructors(DestRecordDecl)) {
auto Info = getConstructorInfo(D);
if (!Info.Constructor)
continue;
@@ -5176,6 +5194,12 @@ void InitializationSequence::InitializeFrom(Sema &S,
// (Therefore, multiple arguments are not permitted.)
if (Args.size() != 1)
SetFailed(FK_TooManyInitsForReference);
+ // C++17 [dcl.init.ref]p5:
+ // A reference [...] is initialized by an expression [...] as follows:
+ // If the initializer is not an expression, presumably we should reject,
+ // but the standard fails to actually say so.
+ else if (isa<InitListExpr>(Args[0]))
+ SetFailed(FK_ParenthesizedListInitForReference);
else
TryReferenceInitialization(S, Entity, Kind, Args[0], *this);
return;
@@ -5341,11 +5365,16 @@ void InitializationSequence::InitializeFrom(Sema &S,
return;
}
+ assert(Args.size() >= 1 && "Zero-argument case handled above");
+
+ // The remaining cases all need a source type.
if (Args.size() > 1) {
SetFailed(FK_TooManyInitsForScalar);
return;
+ } else if (isa<InitListExpr>(Args[0])) {
+ SetFailed(FK_ParenthesizedListInitForScalar);
+ return;
}
- assert(Args.size() == 1 && "Zero-argument case handled above");
// - Otherwise, if the source type is a (possibly cv-qualified) class
// type, conversion functions are considered.
@@ -5472,6 +5501,7 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) {
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
case InitializedEntity::EK_CompoundLiteralInit:
return Sema::AA_Initializing;
@@ -5495,6 +5525,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
case InitializedEntity::EK_CompoundLiteralInit:
return false;
@@ -5521,6 +5552,7 @@ static bool shouldDestroyEntity(const InitializedEntity &Entity) {
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
return false;
@@ -5568,6 +5600,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_CompoundLiteralInit:
case InitializedEntity::EK_RelatedResult:
return Initializer->getLocStart();
@@ -5918,7 +5951,8 @@ PerformConstructorInitialization(Sema &S,
S.MarkFunctionReferenced(Loc, Constructor);
CurInit = new (S.Context) CXXTemporaryObjectExpr(
- S.Context, Constructor, TSInfo,
+ S.Context, Constructor,
+ Entity.getType().getNonLValueExprType(S.Context), TSInfo,
ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
IsListInitialization, IsStdInitListInitialization,
ConstructorInitRequiresZeroInit);
@@ -6004,6 +6038,7 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_ComplexElement:
// Could not determine what the full initialization is. Assume it might not
// outlive the full-expression.
@@ -6092,6 +6127,7 @@ static const InitializedEntity *getEntityForTemporaryLifetimeExtension(
return FallbackDecl;
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_VectorElement:
@@ -6250,7 +6286,7 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
if (!InitExpr)
return;
- if (!S.ActiveTemplateInstantiations.empty())
+ if (S.inTemplateInstantiation())
return;
QualType DestType = InitExpr->getType();
@@ -6485,6 +6521,20 @@ InitializationSequence::Perform(Sema &S,
<< Init->getSourceRange();
}
+ // OpenCL v2.0 s6.13.11.1. atomic variables can be initialized in global scope
+ QualType ETy = Entity.getType();
+ Qualifiers TyQualifiers = ETy.getQualifiers();
+ bool HasGlobalAS = TyQualifiers.hasAddressSpace() &&
+ TyQualifiers.getAddressSpace() == LangAS::opencl_global;
+
+ if (S.getLangOpts().OpenCLVersion >= 200 &&
+ ETy->isAtomicType() && !HasGlobalAS &&
+ Entity.getKind() == InitializedEntity::EK_Variable && Args.size() > 0) {
+ S.Diag(Args[0]->getLocStart(), diag::err_opencl_atomic_init) << 1 <<
+ SourceRange(Entity.getDecl()->getLocStart(), Args[0]->getLocEnd());
+ return ExprError();
+ }
+
// Diagnose cases where we initialize a pointer to an array temporary, and the
// pointer obviously outlives the temporary.
if (Args.size() == 1 && Args[0]->getType()->isArrayType() &&
@@ -6636,6 +6686,19 @@ InitializationSequence::Perform(Sema &S,
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
+ // We don't check for e.g. function pointers here, since address
+ // availability checks should only occur when the function first decays
+ // into a pointer or reference.
+ if (CurInit.get()->getType()->isFunctionProtoType()) {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(CurInit.get()->IgnoreParens())) {
+ if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
+ if (!S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
+ DRE->getLocStart()))
+ return ExprError();
+ }
+ }
+ }
+
// Even though we didn't materialize a temporary, the binding may still
// extend the lifetime of a temporary. This happens if we bind a reference
// to the result of a cast to reference type.
@@ -6670,14 +6733,10 @@ InitializationSequence::Perform(Sema &S,
/*IsInitializerList=*/false,
ExtendingEntity->getDecl());
- // If we're binding to an Objective-C object that has lifetime, we
- // need cleanups. Likewise if we're extending this temporary to automatic
- // storage duration -- we need to register its cleanup during the
- // full-expression's cleanups.
- if ((S.getLangOpts().ObjCAutoRefCount &&
- MTE->getType()->isObjCLifetimeType()) ||
- (MTE->getStorageDuration() == SD_Automatic &&
- MTE->getType().isDestructedType()))
+ // If we're extending this temporary to automatic storage duration -- we
+ // need to register its cleanup during the full-expression's cleanups.
+ if (MTE->getStorageDuration() == SD_Automatic &&
+ MTE->getType().isDestructedType())
S.Cleanup.setExprNeedsCleanups(true);
CurInit = MTE;
@@ -6986,7 +7045,7 @@ InitializationSequence::Perform(Sema &S,
Kind.getRange().getBegin());
CurInit = new (S.Context) CXXScalarValueInitExpr(
- TSInfo->getType().getNonLValueExprType(S.Context), TSInfo,
+ Entity.getType().getNonLValueExprType(S.Context), TSInfo,
Kind.getRange().getEnd());
} else {
CurInit = new (S.Context) ImplicitValueInitExpr(Step->Type);
@@ -7161,7 +7220,7 @@ InitializationSequence::Perform(Sema &S,
QualType SourceType = Init->getType();
// Case 1
if (Entity.isParameterKind()) {
- if (!SourceType->isSamplerT()) {
+ if (!SourceType->isSamplerT() && !SourceType->isIntegerType()) {
S.Diag(Kind.getLocation(), diag::err_sampler_argument_required)
<< SourceType;
break;
@@ -7385,6 +7444,10 @@ bool InitializationSequence::Diagnose(Sema &S,
S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
<< SourceRange(Args.front()->getLocStart(), Args.back()->getLocEnd());
break;
+ case FK_ParenthesizedListInitForReference:
+ S.Diag(Kind.getLocation(), diag::err_list_init_in_parens)
+ << 1 << Entity.getType() << Args[0]->getSourceRange();
+ break;
case FK_ArrayNeedsInitList:
S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 0;
@@ -7596,6 +7659,11 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}
+ case FK_ParenthesizedListInitForScalar:
+ S.Diag(Kind.getLocation(), diag::err_list_init_in_parens)
+ << 0 << Entity.getType() << Args[0]->getSourceRange();
+ break;
+
case FK_ReferenceBindingToInitList:
S.Diag(Kind.getLocation(), diag::err_reference_bind_init_list)
<< DestType.getNonReferenceType() << Args[0]->getSourceRange();
@@ -7759,7 +7827,8 @@ bool InitializationSequence::Diagnose(Sema &S,
(void)Ovl;
assert(Ovl == OR_Success && "Inconsistent overload resolution");
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
- S.Diag(CtorDecl->getLocation(), diag::note_constructor_declared_here);
+ S.Diag(CtorDecl->getLocation(),
+ diag::note_explicit_ctor_deduction_guide_here) << false;
break;
}
}
@@ -7777,6 +7846,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "too many initializers for reference";
break;
+ case FK_ParenthesizedListInitForReference:
+ OS << "parenthesized list init for reference";
+ break;
+
case FK_ArrayNeedsInitList:
OS << "array requires initializer list";
break;
@@ -7861,6 +7934,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "too many initializers for scalar";
break;
+ case FK_ParenthesizedListInitForScalar:
+ OS << "parenthesized list init for reference";
+ break;
+
case FK_ReferenceBindingToInitList:
OS << "referencing binding to initializer list";
break;
@@ -8219,7 +8296,261 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
AllowExplicit);
InitializationSequence Seq(*this, Entity, Kind, InitE, TopLevelOfInitList);
+ // Prevent infinite recursion when performing parameter copy-initialization.
+ const bool ShouldTrackCopy =
+ Entity.isParameterKind() && Seq.isConstructorInitialization();
+ if (ShouldTrackCopy) {
+ if (llvm::find(CurrentParameterCopyTypes, Entity.getType()) !=
+ CurrentParameterCopyTypes.end()) {
+ Seq.SetOverloadFailure(
+ InitializationSequence::FK_ConstructorOverloadFailed,
+ OR_No_Viable_Function);
+
+ // Try to give a meaningful diagnostic note for the problematic
+ // constructor.
+ const auto LastStep = Seq.step_end() - 1;
+ assert(LastStep->Kind ==
+ InitializationSequence::SK_ConstructorInitialization);
+ const FunctionDecl *Function = LastStep->Function.Function;
+ auto Candidate =
+ llvm::find_if(Seq.getFailedCandidateSet(),
+ [Function](const OverloadCandidate &Candidate) -> bool {
+ return Candidate.Viable &&
+ Candidate.Function == Function &&
+ Candidate.Conversions.size() > 0;
+ });
+ if (Candidate != Seq.getFailedCandidateSet().end() &&
+ Function->getNumParams() > 0) {
+ Candidate->Viable = false;
+ Candidate->FailureKind = ovl_fail_bad_conversion;
+ Candidate->Conversions[0].setBad(BadConversionSequence::no_conversion,
+ InitE,
+ Function->getParamDecl(0)->getType());
+ }
+ }
+ CurrentParameterCopyTypes.push_back(Entity.getType());
+ }
+
ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE);
+ if (ShouldTrackCopy)
+ CurrentParameterCopyTypes.pop_back();
+
return Result;
}
+
+QualType Sema::DeduceTemplateSpecializationFromInitializer(
+ TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
+ const InitializationKind &Kind, MultiExprArg Inits) {
+ auto *DeducedTST = dyn_cast<DeducedTemplateSpecializationType>(
+ TSInfo->getType()->getContainedDeducedType());
+ assert(DeducedTST && "not a deduced template specialization type");
+
+ // We can only perform deduction for class templates.
+ auto TemplateName = DeducedTST->getTemplateName();
+ auto *Template =
+ dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
+ if (!Template) {
+ Diag(Kind.getLocation(),
+ diag::err_deduced_non_class_template_specialization_type)
+ << (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName;
+ if (auto *TD = TemplateName.getAsTemplateDecl())
+ Diag(TD->getLocation(), diag::note_template_decl_here);
+ return QualType();
+ }
+
+ // Can't deduce from dependent arguments.
+ if (Expr::hasAnyTypeDependentArguments(Inits))
+ return Context.DependentTy;
+
+ // FIXME: Perform "exact type" matching first, per CWG discussion?
+ // Or implement this via an implied 'T(T) -> T' deduction guide?
+
+ // FIXME: Do we need/want a std::initializer_list<T> special case?
+
+ // Look up deduction guides, including those synthesized from constructors.
+ //
+ // C++1z [over.match.class.deduct]p1:
+ // A set of functions and function templates is formed comprising:
+ // - For each constructor of the class template designated by the
+ // template-name, a function template [...]
+ // - For each deduction-guide, a function or function template [...]
+ DeclarationNameInfo NameInfo(
+ Context.DeclarationNames.getCXXDeductionGuideName(Template),
+ TSInfo->getTypeLoc().getEndLoc());
+ LookupResult Guides(*this, NameInfo, LookupOrdinaryName);
+ LookupQualifiedName(Guides, Template->getDeclContext());
+
+ // FIXME: Do not diagnose inaccessible deduction guides. The standard isn't
+ // clear on this, but they're not found by name so access does not apply.
+ Guides.suppressDiagnostics();
+
+ // Figure out if this is list-initialization.
+ InitListExpr *ListInit =
+ (Inits.size() == 1 && Kind.getKind() != InitializationKind::IK_Direct)
+ ? dyn_cast<InitListExpr>(Inits[0])
+ : nullptr;
+
+ // C++1z [over.match.class.deduct]p1:
+ // Initialization and overload resolution are performed as described in
+ // [dcl.init] and [over.match.ctor], [over.match.copy], or [over.match.list]
+ // (as appropriate for the type of initialization performed) for an object
+ // of a hypothetical class type, where the selected functions and function
+ // templates are considered to be the constructors of that class type
+ //
+ // Since we know we're initializing a class type of a type unrelated to that
+ // of the initializer, this reduces to something fairly reasonable.
+ OverloadCandidateSet Candidates(Kind.getLocation(),
+ OverloadCandidateSet::CSK_Normal);
+ OverloadCandidateSet::iterator Best;
+ auto tryToResolveOverload =
+ [&](bool OnlyListConstructors) -> OverloadingResult {
+ Candidates.clear();
+ for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
+ NamedDecl *D = (*I)->getUnderlyingDecl();
+ if (D->isInvalidDecl())
+ continue;
+
+ auto *TD = dyn_cast<FunctionTemplateDecl>(D);
+ auto *GD = dyn_cast_or_null<CXXDeductionGuideDecl>(
+ TD ? TD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D));
+ if (!GD)
+ continue;
+
+ // C++ [over.match.ctor]p1: (non-list copy-initialization from non-class)
+ // For copy-initialization, the candidate functions are all the
+ // converting constructors (12.3.1) of that class.
+ // C++ [over.match.copy]p1: (non-list copy-initialization from class)
+ // The converting constructors of T are candidate functions.
+ if (Kind.isCopyInit() && !ListInit) {
+ // Only consider converting constructors.
+ if (GD->isExplicit())
+ continue;
+
+ // When looking for a converting constructor, deduction guides that
+ // could never be called with one argument are not interesting to
+ // check or note.
+ if (GD->getMinRequiredArguments() > 1 ||
+ (GD->getNumParams() == 0 && !GD->isVariadic()))
+ continue;
+ }
+
+ // C++ [over.match.list]p1.1: (first phase list initialization)
+ // Initially, the candidate functions are the initializer-list
+ // constructors of the class T
+ if (OnlyListConstructors && !isInitListConstructor(GD))
+ continue;
+
+ // C++ [over.match.list]p1.2: (second phase list initialization)
+ // the candidate functions are all the constructors of the class T
+ // C++ [over.match.ctor]p1: (all other cases)
+ // the candidate functions are all the constructors of the class of
+ // the object being initialized
+
+ // C++ [over.best.ics]p4:
+ // When [...] the constructor [...] is a candidate by
+ // - [over.match.copy] (in all cases)
+ // FIXME: The "second phase of [over.match.list] case can also
+ // theoretically happen here, but it's not clear whether we can
+ // ever have a parameter of the right type.
+ bool SuppressUserConversions = Kind.isCopyInit();
+
+ if (TD)
+ AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
+ Inits, Candidates,
+ SuppressUserConversions);
+ else
+ AddOverloadCandidate(GD, I.getPair(), Inits, Candidates,
+ SuppressUserConversions);
+ }
+ return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
+ };
+
+ OverloadingResult Result = OR_No_Viable_Function;
+
+ // C++11 [over.match.list]p1, per DR1467: for list-initialization, first
+ // try initializer-list constructors.
+ if (ListInit) {
+ bool TryListConstructors = true;
+
+ // Try list constructors unless the list is empty and the class has one or
+ // more default constructors, in which case those constructors win.
+ if (!ListInit->getNumInits()) {
+ for (NamedDecl *D : Guides) {
+ auto *FD = dyn_cast<FunctionDecl>(D->getUnderlyingDecl());
+ if (FD && FD->getMinRequiredArguments() == 0) {
+ TryListConstructors = false;
+ break;
+ }
+ }
+ }
+
+ if (TryListConstructors)
+ Result = tryToResolveOverload(/*OnlyListConstructor*/true);
+ // Then unwrap the initializer list and try again considering all
+ // constructors.
+ Inits = MultiExprArg(ListInit->getInits(), ListInit->getNumInits());
+ }
+
+ // If list-initialization fails, or if we're doing any other kind of
+ // initialization, we (eventually) consider constructors.
+ if (Result == OR_No_Viable_Function)
+ Result = tryToResolveOverload(/*OnlyListConstructor*/false);
+
+ switch (Result) {
+ case OR_Ambiguous:
+ Diag(Kind.getLocation(), diag::err_deduced_class_template_ctor_ambiguous)
+ << TemplateName;
+ // FIXME: For list-initialization candidates, it'd usually be better to
+ // list why they were not viable when given the initializer list itself as
+ // an argument.
+ Candidates.NoteCandidates(*this, OCD_ViableCandidates, Inits);
+ return QualType();
+
+ case OR_No_Viable_Function: {
+ CXXRecordDecl *Primary =
+ cast<ClassTemplateDecl>(Template)->getTemplatedDecl();
+ bool Complete =
+ isCompleteType(Kind.getLocation(), Context.getTypeDeclType(Primary));
+ Diag(Kind.getLocation(),
+ Complete ? diag::err_deduced_class_template_ctor_no_viable
+ : diag::err_deduced_class_template_incomplete)
+ << TemplateName << !Guides.empty();
+ Candidates.NoteCandidates(*this, OCD_AllCandidates, Inits);
+ return QualType();
+ }
+
+ case OR_Deleted: {
+ Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted)
+ << TemplateName;
+ NoteDeletedFunction(Best->Function);
+ return QualType();
+ }
+
+ case OR_Success:
+ // C++ [over.match.list]p1:
+ // In copy-list-initialization, if an explicit constructor is chosen, the
+ // initialization is ill-formed.
+ if (Kind.isCopyInit() && ListInit &&
+ cast<CXXDeductionGuideDecl>(Best->Function)->isExplicit()) {
+ bool IsDeductionGuide = !Best->Function->isImplicit();
+ Diag(Kind.getLocation(), diag::err_deduced_class_template_explicit)
+ << TemplateName << IsDeductionGuide;
+ Diag(Best->Function->getLocation(),
+ diag::note_explicit_ctor_deduction_guide_here)
+ << IsDeductionGuide;
+ return QualType();
+ }
+
+ // Make sure we didn't select an unusable deduction guide, and mark it
+ // as referenced.
+ DiagnoseUseOfDecl(Best->Function, Kind.getLocation());
+ MarkFunctionReferenced(Kind.getLocation(), Best->Function);
+ break;
+ }
+
+ // C++ [dcl.type.class.deduct]p1:
+ // The placeholder is replaced by the return type of the function selected
+ // by overload resolution for class template deduction.
+ return SubstAutoType(TSInfo->getType(), Best->Function->getReturnType());
+}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp
index a0d5749..46f2ba3 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp
@@ -312,7 +312,7 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
// In the following contexts [...] the one-definition rule requires closure
// types in different translation units to "correspond":
bool IsInNonspecializedTemplate =
- !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext();
+ inTemplateInstantiation() || CurContext->isDependentContext();
switch (Kind) {
case Normal: {
// -- the bodies of non-exported nonspecialized template functions
@@ -337,6 +337,7 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
return nullptr;
}
// Fall through to get the current context.
+ LLVM_FALLTHROUGH;
case DataMember:
// -- the in-class initializers of class members
@@ -763,7 +764,7 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc,
// call-operator.
Result = ActOnFinishFullExpr(Init, Loc, /*DiscardedValue*/ false,
/*IsConstexpr*/ false,
- /*IsLambdaInitCaptureInitalizer*/ true);
+ /*IsLambdaInitCaptureInitializer*/ true);
if (Result.isInvalid())
return QualType();
@@ -1127,7 +1128,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Enter a new evaluation context to insulate the lambda from any
// cleanups from the enclosing full-expression.
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
@@ -1384,7 +1386,7 @@ static void addBlockPointerConversion(Sema &S,
}
static ExprResult performLambdaVarCaptureInitialization(
- Sema &S, LambdaScopeInfo::Capture &Capture, FieldDecl *Field) {
+ Sema &S, const LambdaScopeInfo::Capture &Capture, FieldDecl *Field) {
assert(Capture.isVariableCapture() && "not a variable capture");
auto *Var = Capture.getVariable();
@@ -1438,6 +1440,43 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) {
llvm_unreachable("Unknown implicit capture style");
}
+bool Sema::CaptureHasSideEffects(const LambdaScopeInfo::Capture &From) {
+ if (!From.isVLATypeCapture()) {
+ Expr *Init = From.getInitExpr();
+ if (Init && Init->HasSideEffects(Context))
+ return true;
+ }
+
+ if (!From.isCopyCapture())
+ return false;
+
+ const QualType T = From.isThisCapture()
+ ? getCurrentThisType()->getPointeeType()
+ : From.getCaptureType();
+
+ if (T.isVolatileQualified())
+ return true;
+
+ const Type *BaseT = T->getBaseElementTypeUnsafe();
+ if (const CXXRecordDecl *RD = BaseT->getAsCXXRecordDecl())
+ return !RD->isCompleteDefinition() || !RD->hasTrivialCopyConstructor() ||
+ !RD->hasTrivialDestructor();
+
+ return false;
+}
+
+void Sema::DiagnoseUnusedLambdaCapture(const LambdaScopeInfo::Capture &From) {
+ if (CaptureHasSideEffects(From))
+ return;
+
+ auto diag = Diag(From.getLocation(), diag::warn_unused_lambda_capture);
+ if (From.isThisCapture())
+ diag << "'this'";
+ else
+ diag << From.getVariable();
+ diag << From.isNonODRUsed();
+}
+
ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
LambdaScopeInfo *LSI) {
// Collect information from the lambda scope.
@@ -1453,6 +1492,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
bool ExplicitResultType;
CleanupInfo LambdaCleanup;
bool ContainsUnexpandedParameterPack;
+ bool IsGenericLambda;
{
CallOperator = LSI->CallOperator;
Class = LSI->Lambda;
@@ -1461,7 +1501,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
ExplicitResultType = !LSI->HasImplicitReturnType;
LambdaCleanup = LSI->Cleanup;
ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
-
+ IsGenericLambda = Class->isGenericLambda();
+
CallOperator->setLexicalDeclContext(Class);
Decl *TemplateOrNonTemplateCallOperatorDecl =
CallOperator->getDescribedFunctionTemplate()
@@ -1476,10 +1517,19 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// Translate captures.
auto CurField = Class->field_begin();
for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I, ++CurField) {
- LambdaScopeInfo::Capture From = LSI->Captures[I];
+ const LambdaScopeInfo::Capture &From = LSI->Captures[I];
assert(!From.isBlockCapture() && "Cannot capture __block variables");
bool IsImplicit = I >= LSI->NumExplicitCaptures;
+ // Warn about unused explicit captures.
+ if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
+ // Initialized captures that are non-ODR used may not be eliminated.
+ bool NonODRUsedInitCapture =
+ IsGenericLambda && From.isNonODRUsed() && From.getInitExpr();
+ if (!NonODRUsedInitCapture)
+ DiagnoseUnusedLambdaCapture(From);
+ }
+
// Handle 'this' capture.
if (From.isThisCapture()) {
Captures.push_back(
@@ -1525,8 +1575,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// same parameter and return types as the closure type's function call
// operator.
// FIXME: Fix generic lambda to block conversions.
- if (getLangOpts().Blocks && getLangOpts().ObjC1 &&
- !Class->isGenericLambda())
+ if (getLangOpts().Blocks && getLangOpts().ObjC1 && !IsGenericLambda)
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
@@ -1546,9 +1595,10 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
ContainsUnexpandedParameterPack);
// If the lambda expression's call operator is not explicitly marked constexpr
// and we are not in a dependent context, analyze the call operator to infer
- // its constexpr-ness, supressing diagnostics while doing so.
+ // its constexpr-ness, suppressing diagnostics while doing so.
if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() &&
!CallOperator->isConstexpr() &&
+ !isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
!Class->getDeclContext()->isDependentContext()) {
TentativeAnalysisScope DiagnosticScopeGuard(*this);
CallOperator->setConstexpr(
@@ -1564,9 +1614,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand
// (Clause 5).
- case Unevaluated:
- case UnevaluatedList:
- case UnevaluatedAbstract:
+ case ExpressionEvaluationContext::Unevaluated:
+ case ExpressionEvaluationContext::UnevaluatedList:
+ case ExpressionEvaluationContext::UnevaluatedAbstract:
// C++1y [expr.const]p2:
// A conditional-expression e is a core constant expression unless the
// evaluation of e, following the rules of the abstract machine, would
@@ -1576,16 +1626,16 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// where this should be allowed. We should probably fix this when DR1607 is
// ratified, it lays out the exact set of conditions where we shouldn't
// allow a lambda-expression.
- case ConstantEvaluated:
+ case ExpressionEvaluationContext::ConstantEvaluated:
// We don't actually diagnose this case immediately, because we
// could be within a context where we might find out later that
// the expression is potentially evaluated (e.g., for typeid).
ExprEvalContexts.back().Lambdas.push_back(Lambda);
break;
- case DiscardedStatement:
- case PotentiallyEvaluated:
- case PotentiallyEvaluatedIfUsed:
+ case ExpressionEvaluationContext::DiscardedStatement:
+ case ExpressionEvaluationContext::PotentiallyEvaluated:
+ case ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
break;
}
}
@@ -1607,10 +1657,9 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
CallOperator->markUsed(Context);
ExprResult Init = PerformCopyInitialization(
- InitializedEntity::InitializeBlock(ConvLocation,
- Src->getType(),
- /*NRVO=*/false),
- CurrentLocation, Src);
+ InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType(),
+ /*NRVO=*/false),
+ CurrentLocation, Src);
if (!Init.isInvalid())
Init = ActOnFinishFullExpr(Init.get());
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp
index e2cb2c8..85596ed 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp
@@ -774,6 +774,7 @@ static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) {
/// that need to be declared in the given declaration context, do so.
static void DeclareImplicitMemberFunctionsWithName(Sema &S,
DeclarationName Name,
+ SourceLocation Loc,
const DeclContext *DC) {
if (!DC)
return;
@@ -816,6 +817,10 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
}
break;
+ case DeclarationName::CXXDeductionGuideName:
+ S.DeclareImplicitDeductionGuides(Name.getCXXDeductionGuideTemplate(), Loc);
+ break;
+
default:
break;
}
@@ -828,13 +833,12 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// Lazily declare C++ special member functions.
if (S.getLangOpts().CPlusPlus)
- DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC);
+ DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), R.getNameLoc(),
+ DC);
// Perform lookup into this declaration context.
DeclContext::lookup_result DR = DC->lookup(R.getLookupName());
- for (DeclContext::lookup_iterator I = DR.begin(), E = DR.end(); I != E;
- ++I) {
- NamedDecl *D = *I;
+ for (NamedDecl *D : DR) {
if ((D = R.getAcceptableDecl(D))) {
R.addDecl(D);
Found = true;
@@ -858,6 +862,16 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
if (!Record->isCompleteDefinition())
return Found;
+ // For conversion operators, 'operator auto' should only match
+ // 'operator auto'. Since 'auto' is not a type, it shouldn't be considered
+ // as a candidate for template substitution.
+ auto *ContainedDeducedType =
+ R.getLookupName().getCXXNameType()->getContainedDeducedType();
+ if (R.getLookupName().getNameKind() ==
+ DeclarationName::CXXConversionFunctionName &&
+ ContainedDeducedType && ContainedDeducedType->isUndeducedType())
+ return Found;
+
for (CXXRecordDecl::conversion_iterator U = Record->conversion_begin(),
UEnd = Record->conversion_end(); U != UEnd; ++U) {
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
@@ -1041,7 +1055,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (isImplicitlyDeclaredMemberFunctionName(Name)) {
for (Scope *PreS = S; PreS; PreS = PreS->getParent())
if (DeclContext *DC = PreS->getEntity())
- DeclareImplicitMemberFunctionsWithName(*this, Name, DC);
+ DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
}
// Implicitly declare member functions with the name we're looking for, if in
@@ -1322,80 +1336,18 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return !R.empty();
}
-/// \brief Find the declaration that a class temploid member specialization was
-/// instantiated from, or the member itself if it is an explicit specialization.
-static Decl *getInstantiatedFrom(Decl *D, MemberSpecializationInfo *MSInfo) {
- return MSInfo->isExplicitSpecialization() ? D : MSInfo->getInstantiatedFrom();
-}
-
-Module *Sema::getOwningModule(Decl *Entity) {
- // If it's imported, grab its owning module.
- Module *M = Entity->getImportedOwningModule();
- if (M || !isa<NamedDecl>(Entity) || !cast<NamedDecl>(Entity)->isHidden())
- return M;
- assert(!Entity->isFromASTFile() &&
- "hidden entity from AST file has no owning module");
-
- if (!getLangOpts().ModulesLocalVisibility) {
- // If we're not tracking visibility locally, the only way a declaration
- // can be hidden and local is if it's hidden because it's parent is (for
- // instance, maybe this is a lazily-declared special member of an imported
- // class).
- auto *Parent = cast<NamedDecl>(Entity->getDeclContext());
- assert(Parent->isHidden() && "unexpectedly hidden decl");
- return getOwningModule(Parent);
- }
-
- // It's local and hidden; grab or compute its owning module.
- M = Entity->getLocalOwningModule();
- if (M)
- return M;
-
- if (auto *Containing =
- PP.getModuleContainingLocation(Entity->getLocation())) {
- M = Containing;
- } else if (Entity->isInvalidDecl() || Entity->getLocation().isInvalid()) {
- // Don't bother tracking visibility for invalid declarations with broken
- // locations.
- cast<NamedDecl>(Entity)->setHidden(false);
- } else {
- // We need to assign a module to an entity that exists outside of any
- // module, so that we can hide it from modules that we textually enter.
- // Invent a fake module for all such entities.
- if (!CachedFakeTopLevelModule) {
- CachedFakeTopLevelModule =
- PP.getHeaderSearchInfo().getModuleMap().findOrCreateModule(
- "<top-level>", nullptr, false, false).first;
-
- auto &SrcMgr = PP.getSourceManager();
- SourceLocation StartLoc =
- SrcMgr.getLocForStartOfFile(SrcMgr.getMainFileID());
- auto &TopLevel = ModuleScopes.empty()
- ? VisibleModules
- : ModuleScopes[0].OuterVisibleModules;
- TopLevel.setVisible(CachedFakeTopLevelModule, StartLoc);
- }
-
- M = CachedFakeTopLevelModule;
- }
-
- if (M)
- Entity->setLocalOwningModule(M);
- return M;
-}
-
-void Sema::makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc) {
- if (auto *M = PP.getModuleContainingLocation(Loc))
+void Sema::makeMergedDefinitionVisible(NamedDecl *ND) {
+ if (auto *M = getCurrentModule())
Context.mergeDefinitionIntoModule(ND, M);
else
// We're not building a module; just make the definition visible.
- ND->setHidden(false);
+ ND->setVisibleDespiteOwningModule();
// If ND is a template declaration, make the template parameters
// visible too. They're not (necessarily) within a mergeable DeclContext.
if (auto *TD = dyn_cast<TemplateDecl>(ND))
for (auto *Param : *TD->getTemplateParameters())
- makeMergedDefinitionVisible(Param, Loc);
+ makeMergedDefinitionVisible(Param);
}
/// \brief Find the module in which the given declaration was defined.
@@ -1409,12 +1361,11 @@ static Module *getDefiningModule(Sema &S, Decl *Entity) {
if (CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern())
Entity = Pattern;
} else if (EnumDecl *ED = dyn_cast<EnumDecl>(Entity)) {
- if (MemberSpecializationInfo *MSInfo = ED->getMemberSpecializationInfo())
- Entity = getInstantiatedFrom(ED, MSInfo);
+ if (auto *Pattern = ED->getTemplateInstantiationPattern())
+ Entity = Pattern;
} else if (VarDecl *VD = dyn_cast<VarDecl>(Entity)) {
- // FIXME: Map from variable template specializations back to the template.
- if (MemberSpecializationInfo *MSInfo = VD->getMemberSpecializationInfo())
- Entity = getInstantiatedFrom(VD, MSInfo);
+ if (VarDecl *Pattern = VD->getTemplateInstantiationPattern())
+ Entity = Pattern;
}
// Walk up to the containing context. That might also have been instantiated
@@ -1426,14 +1377,13 @@ static Module *getDefiningModule(Sema &S, Decl *Entity) {
}
llvm::DenseSet<Module*> &Sema::getLookupModules() {
- unsigned N = ActiveTemplateInstantiations.size();
- for (unsigned I = ActiveTemplateInstantiationLookupModules.size();
+ unsigned N = CodeSynthesisContexts.size();
+ for (unsigned I = CodeSynthesisContextLookupModules.size();
I != N; ++I) {
- Module *M =
- getDefiningModule(*this, ActiveTemplateInstantiations[I].Entity);
+ Module *M = getDefiningModule(*this, CodeSynthesisContexts[I].Entity);
if (M && !LookupModulesCache.insert(M).second)
M = nullptr;
- ActiveTemplateInstantiationLookupModules.push_back(M);
+ CodeSynthesisContextLookupModules.push_back(M);
}
return LookupModulesCache;
}
@@ -1445,6 +1395,20 @@ bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) {
return false;
}
+bool Sema::hasMergedDefinitionInCurrentModule(NamedDecl *Def) {
+ // FIXME: When not in local visibility mode, we can't tell the difference
+ // between a declaration being visible because we merged a local copy of
+ // the same declaration into it, and it being visible because its owning
+ // module is visible.
+ if (Def->getModuleOwnershipKind() == Decl::ModuleOwnershipKind::Visible &&
+ getLangOpts().ModulesLocalVisibility)
+ return true;
+ for (Module *Merged : Context.getModulesWithMergedDefinition(Def))
+ if (Merged->getTopLevelModuleName() == getLangOpts().CurrentModule)
+ return true;
+ return false;
+}
+
template<typename ParmDecl>
static bool
hasVisibleDefaultArgument(Sema &S, const ParmDecl *D,
@@ -1480,11 +1444,46 @@ bool Sema::hasVisibleDefaultArgument(const NamedDecl *D,
Modules);
}
+template<typename Filter>
+static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D,
+ llvm::SmallVectorImpl<Module *> *Modules,
+ Filter F) {
+ for (auto *Redecl : D->redecls()) {
+ auto *R = cast<NamedDecl>(Redecl);
+ if (!F(R))
+ continue;
+
+ if (S.isVisible(R))
+ return true;
+
+ if (Modules) {
+ Modules->push_back(R->getOwningModule());
+ const auto &Merged = S.Context.getModulesWithMergedDefinition(R);
+ Modules->insert(Modules->end(), Merged.begin(), Merged.end());
+ }
+ }
+
+ return false;
+}
+
+bool Sema::hasVisibleExplicitSpecialization(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+ return hasVisibleDeclarationImpl(*this, D, Modules, [](const NamedDecl *D) {
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ return RD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ return VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+ llvm_unreachable("unknown explicit specialization kind");
+ });
+}
+
bool Sema::hasVisibleMemberSpecialization(
const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
assert(isa<CXXRecordDecl>(D->getDeclContext()) &&
"not a member specialization");
- for (auto *Redecl : D->redecls()) {
+ return hasVisibleDeclarationImpl(*this, D, Modules, [](const NamedDecl *D) {
// If the specialization is declared at namespace scope, then it's a member
// specialization declaration. If it's lexically inside the class
// definition then it was instantiated.
@@ -1492,19 +1491,8 @@ bool Sema::hasVisibleMemberSpecialization(
// FIXME: This is a hack. There should be a better way to determine this.
// FIXME: What about MS-style explicit specializations declared within a
// class definition?
- if (Redecl->getLexicalDeclContext()->isFileContext()) {
- auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl));
-
- if (isVisible(NonConstR))
- return true;
-
- if (Modules) {
- Modules->push_back(getOwningModule(NonConstR));
- const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR);
- Modules->insert(Modules->end(), Merged.begin(), Merged.end());
- }
- }
- }
+ return D->getLexicalDeclContext()->isFileContext();
+ });
return false;
}
@@ -1519,30 +1507,42 @@ bool Sema::hasVisibleMemberSpecialization(
/// your module can see, including those later on in your module).
bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
assert(D->isHidden() && "should not call this: not in slow case");
- Module *DeclModule = nullptr;
-
- if (SemaRef.getLangOpts().ModulesLocalVisibility) {
- DeclModule = SemaRef.getOwningModule(D);
- if (!DeclModule) {
- // getOwningModule() may have decided the declaration should not be hidden.
- assert(!D->isHidden() && "hidden decl not from a module");
- return true;
- }
+ Module *DeclModule = SemaRef.getOwningModule(D);
+ if (!DeclModule) {
+ // A module-private declaration with no owning module means this is in the
+ // global module in the C++ Modules TS. This is visible within the same
+ // translation unit only.
+ // FIXME: Don't assume that "same translation unit" means the same thing
+ // as "not from an AST file".
+ assert(D->isModulePrivate() && "hidden decl has no module");
+ if (!D->isFromASTFile() || SemaRef.hasMergedDefinitionInCurrentModule(D))
+ return true;
+ } else {
// If the owning module is visible, and the decl is not module private,
// then the decl is visible too. (Module private is ignored within the same
// top-level module.)
- if ((!D->isFromASTFile() || !D->isModulePrivate()) &&
- (SemaRef.isModuleVisible(DeclModule) ||
- SemaRef.hasVisibleMergedDefinition(D)))
+ if (D->isModulePrivate()
+ ? DeclModule->getTopLevelModuleName() ==
+ SemaRef.getLangOpts().CurrentModule ||
+ SemaRef.hasMergedDefinitionInCurrentModule(D)
+ : SemaRef.isModuleVisible(DeclModule) ||
+ SemaRef.hasVisibleMergedDefinition(D))
return true;
}
- // If this declaration is not at namespace scope nor module-private,
+ // Determine whether a decl context is a file context for the purpose of
+ // visibility. This looks through some (export and linkage spec) transparent
+ // contexts, but not others (enums).
+ auto IsEffectivelyFileContext = [](const DeclContext *DC) {
+ return DC->isFileContext() || isa<LinkageSpecDecl>(DC) ||
+ isa<ExportDecl>(DC);
+ };
+
+ // If this declaration is not at namespace scope
// then it is visible if its lexical parent has a visible definition.
DeclContext *DC = D->getLexicalDeclContext();
- if (!D->isModulePrivate() && DC && !DC->isFileContext() &&
- !isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC)) {
+ if (DC && !IsEffectivelyFileContext(DC)) {
// For a parameter, check whether our current template declaration's
// lexical context is visible, not whether there's some other visible
// definition of it, because parameters aren't "within" the definition.
@@ -1550,32 +1550,45 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
// In C++ we need to check for a visible definition due to ODR merging,
// and in C we must not because each declaration of a function gets its own
// set of declarations for tags in prototype scope.
- if ((D->isTemplateParameter() || isa<ParmVarDecl>(D)
- || (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus))
- ? isVisible(SemaRef, cast<NamedDecl>(DC))
- : SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC))) {
- if (SemaRef.ActiveTemplateInstantiations.empty() &&
- // FIXME: Do something better in this case.
- !SemaRef.getLangOpts().ModulesLocalVisibility) {
- // Cache the fact that this declaration is implicitly visible because
- // its parent has a visible definition.
- D->setHidden(false);
- }
- return true;
+ bool VisibleWithinParent;
+ if (D->isTemplateParameter() || isa<ParmVarDecl>(D) ||
+ (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus))
+ VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC));
+ else if (D->isModulePrivate()) {
+ // A module-private declaration is only visible if an enclosing lexical
+ // parent was merged with another definition in the current module.
+ VisibleWithinParent = false;
+ do {
+ if (SemaRef.hasMergedDefinitionInCurrentModule(cast<NamedDecl>(DC))) {
+ VisibleWithinParent = true;
+ break;
+ }
+ DC = DC->getLexicalParent();
+ } while (!IsEffectivelyFileContext(DC));
+ } else {
+ VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC));
}
- return false;
+
+ if (VisibleWithinParent && SemaRef.CodeSynthesisContexts.empty() &&
+ // FIXME: Do something better in this case.
+ !SemaRef.getLangOpts().ModulesLocalVisibility) {
+ // Cache the fact that this declaration is implicitly visible because
+ // its parent has a visible definition.
+ D->setVisibleDespiteOwningModule();
+ }
+ return VisibleWithinParent;
}
+ // FIXME: All uses of DeclModule below this point should also check merged
+ // modules.
+ if (!DeclModule)
+ return false;
+
// Find the extra places where we need to look.
llvm::DenseSet<Module*> &LookupModules = SemaRef.getLookupModules();
if (LookupModules.empty())
return false;
- if (!DeclModule) {
- DeclModule = SemaRef.getOwningModule(D);
- assert(DeclModule && "hidden decl not from a module");
- }
-
// If our lookup set contains the decl's module, it's visible.
if (LookupModules.count(DeclModule))
return true;
@@ -1632,20 +1645,8 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
bool Sema::hasVisibleDeclarationSlow(const NamedDecl *D,
llvm::SmallVectorImpl<Module *> *Modules) {
assert(!isVisible(D) && "not in slow case");
-
- for (auto *Redecl : D->redecls()) {
- auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl));
- if (isVisible(NonConstR))
- return true;
-
- if (Modules) {
- Modules->push_back(getOwningModule(NonConstR));
- const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR);
- Modules->insert(Modules->end(), Merged.begin(), Merged.end());
- }
- }
-
- return false;
+ return hasVisibleDeclarationImpl(*this, D, Modules,
+ [](const NamedDecl *) { return true; });
}
NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
@@ -2647,6 +2648,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
for (const auto &Arg : Proto->param_types())
Queue.push_back(Arg.getTypePtr());
// fallthrough
+ LLVM_FALLTHROUGH;
}
case Type::FunctionNoProto: {
const FunctionType *FnType = cast<FunctionType>(T);
@@ -2694,6 +2696,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// Non-deduced auto types only get here for error cases.
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
break;
// If T is an Objective-C object or interface type, or a pointer to an
@@ -2814,13 +2817,13 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
Functions.append(Operators.begin(), Operators.end());
}
-Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
- CXXSpecialMember SM,
- bool ConstArg,
- bool VolatileArg,
- bool RValueThis,
- bool ConstThis,
- bool VolatileThis) {
+Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
+ CXXSpecialMember SM,
+ bool ConstArg,
+ bool VolatileArg,
+ bool RValueThis,
+ bool ConstThis,
+ bool VolatileThis) {
assert(CanDeclareSpecialMemberFunction(RD) &&
"doing special member lookup into record that isn't fully complete");
RD = RD->getDefinition();
@@ -2844,15 +2847,15 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
ID.AddInteger(VolatileThis);
void *InsertPoint;
- SpecialMemberOverloadResult *Result =
+ SpecialMemberOverloadResultEntry *Result =
SpecialMemberCache.FindNodeOrInsertPos(ID, InsertPoint);
// This was already cached
if (Result)
- return Result;
+ return *Result;
- Result = BumpAlloc.Allocate<SpecialMemberOverloadResult>();
- Result = new (Result) SpecialMemberOverloadResult(ID);
+ Result = BumpAlloc.Allocate<SpecialMemberOverloadResultEntry>();
+ Result = new (Result) SpecialMemberOverloadResultEntry(ID);
SpecialMemberCache.InsertNode(Result, InsertPoint);
if (SM == CXXDestructor) {
@@ -2864,7 +2867,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
Result->setKind(DD->isDeleted() ?
SpecialMemberOverloadResult::NoMemberOrDeleted :
SpecialMemberOverloadResult::Success);
- return Result;
+ return *Result;
}
// Prepare for overload resolution. Here we construct a synthetic argument
@@ -2947,7 +2950,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
"lookup for a constructor or assignment operator was empty");
Result->setMethod(nullptr);
Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted);
- return Result;
+ return *Result;
}
// Copy the candidates as our processing of them may load new declarations
@@ -3012,16 +3015,16 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
break;
}
- return Result;
+ return *Result;
}
/// \brief Look up the default constructor for the given class.
CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) {
- SpecialMemberOverloadResult *Result =
+ SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false,
false, false);
- return cast_or_null<CXXConstructorDecl>(Result->getMethod());
+ return cast_or_null<CXXConstructorDecl>(Result.getMethod());
}
/// \brief Look up the copying constructor for the given class.
@@ -3029,21 +3032,21 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class,
unsigned Quals) {
assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
"non-const, non-volatile qualifiers for copy ctor arg");
- SpecialMemberOverloadResult *Result =
+ SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, false, false, false);
- return cast_or_null<CXXConstructorDecl>(Result->getMethod());
+ return cast_or_null<CXXConstructorDecl>(Result.getMethod());
}
/// \brief Look up the moving constructor for the given class.
CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class,
unsigned Quals) {
- SpecialMemberOverloadResult *Result =
+ SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXMoveConstructor, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, false, false, false);
- return cast_or_null<CXXConstructorDecl>(Result->getMethod());
+ return cast_or_null<CXXConstructorDecl>(Result.getMethod());
}
/// \brief Look up the constructors for the given class.
@@ -3071,13 +3074,13 @@ CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class,
"non-const, non-volatile qualifiers for copy assignment arg");
assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
"non-const, non-volatile qualifiers for copy assignment this");
- SpecialMemberOverloadResult *Result =
+ SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXCopyAssignment, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, RValueThis,
ThisQuals & Qualifiers::Const,
ThisQuals & Qualifiers::Volatile);
- return Result->getMethod();
+ return Result.getMethod();
}
/// \brief Look up the moving assignment operator for the given class.
@@ -3087,13 +3090,13 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class,
unsigned ThisQuals) {
assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
"non-const, non-volatile qualifiers for copy assignment this");
- SpecialMemberOverloadResult *Result =
+ SpecialMemberOverloadResult Result =
LookupSpecialMember(Class, CXXMoveAssignment, Quals & Qualifiers::Const,
Quals & Qualifiers::Volatile, RValueThis,
ThisQuals & Qualifiers::Const,
ThisQuals & Qualifiers::Volatile);
- return Result->getMethod();
+ return Result.getMethod();
}
/// \brief Look for the destructor of the given class.
@@ -3105,7 +3108,7 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class,
CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
return cast<CXXDestructorDecl>(LookupSpecialMember(Class, CXXDestructor,
false, false, false,
- false, false)->getMethod());
+ false, false).getMethod());
}
/// LookupLiteralOperator - Determine which literal operator should be used for
@@ -3430,6 +3433,12 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
SM == ShadowMaps.rbegin())
continue;
+ // A shadow declaration that's created by a resolved using declaration
+ // is not hidden by the same using declaration.
+ if (isa<UsingShadowDecl>(ND) && isa<UsingDecl>(D) &&
+ cast<UsingShadowDecl>(ND)->getUsingDecl() == D)
+ continue;
+
// We've found a declaration that hides this one.
return D;
}
@@ -3442,7 +3451,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
bool QualifiedNameLookup,
bool InBaseClass,
VisibleDeclConsumer &Consumer,
- VisibleDeclsRecord &Visited) {
+ VisibleDeclsRecord &Visited,
+ bool IncludeDependentBases = false) {
if (!Ctx)
return;
@@ -3498,7 +3508,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
ShadowContextRAII Shadow(Visited);
for (auto I : Ctx->using_directives()) {
LookupVisibleDecls(I->getNominatedNamespace(), Result,
- QualifiedNameLookup, InBaseClass, Consumer, Visited);
+ QualifiedNameLookup, InBaseClass, Consumer, Visited,
+ IncludeDependentBases);
}
}
@@ -3510,14 +3521,28 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
for (const auto &B : Record->bases()) {
QualType BaseType = B.getType();
- // Don't look into dependent bases, because name lookup can't look
- // there anyway.
- if (BaseType->isDependentType())
- continue;
-
- const RecordType *Record = BaseType->getAs<RecordType>();
- if (!Record)
- continue;
+ RecordDecl *RD;
+ if (BaseType->isDependentType()) {
+ if (!IncludeDependentBases) {
+ // Don't look into dependent bases, because name lookup can't look
+ // there anyway.
+ continue;
+ }
+ const auto *TST = BaseType->getAs<TemplateSpecializationType>();
+ if (!TST)
+ continue;
+ TemplateName TN = TST->getTemplateName();
+ const auto *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ continue;
+ RD = TD->getTemplatedDecl();
+ } else {
+ const auto *Record = BaseType->getAs<RecordType>();
+ if (!Record)
+ continue;
+ RD = Record->getDecl();
+ }
// FIXME: It would be nice to be able to determine whether referencing
// a particular member would be ambiguous. For example, given
@@ -3540,8 +3565,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Find results in this base class (and its bases).
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup,
- true, Consumer, Visited);
+ LookupVisibleDecls(RD, Result, QualifiedNameLookup, true, Consumer,
+ Visited, IncludeDependentBases);
}
}
@@ -3710,7 +3735,8 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
- bool IncludeGlobalScope) {
+ bool IncludeGlobalScope,
+ bool IncludeDependentBases) {
LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
Result.setAllowHidden(Consumer.includeHiddenDecls());
VisibleDeclsRecord Visited;
@@ -3718,7 +3744,8 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
Visited.visitedContext(Context.getTranslationUnitDecl());
ShadowContextRAII Shadow(Visited);
::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
- /*InBaseClass=*/false, Consumer, Visited);
+ /*InBaseClass=*/false, Consumer, Visited,
+ IncludeDependentBases);
}
/// LookupOrCreateLabel - Do a name lookup of a label with the specified name.
@@ -3774,20 +3801,19 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
bool FindHidden);
/// \brief Check whether the declarations found for a typo correction are
-/// visible, and if none of them are, convert the correction to an 'import
-/// a module' correction.
+/// visible. Set the correction's RequiresImport flag to true if none of the
+/// declarations are visible, false otherwise.
static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) {
- if (TC.begin() == TC.end())
- return;
-
TypoCorrection::decl_iterator DI = TC.begin(), DE = TC.end();
for (/**/; DI != DE; ++DI)
if (!LookupResult::isVisible(SemaRef, *DI))
break;
- // Nothing to do if all decls are visible.
- if (DI == DE)
+ // No filtering needed if all decls are visible.
+ if (DI == DE) {
+ TC.setRequiresImport(false);
return;
+ }
llvm::SmallVector<NamedDecl*, 4> NewDecls(TC.begin(), DI);
bool AnyVisibleDecls = !NewDecls.empty();
@@ -4498,9 +4524,8 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer(
if (SS && SS->isInvalid())
return nullptr;
- // Never try to correct typos during template deduction or
- // instantiation.
- if (!ActiveTemplateInstantiations.empty())
+ // Never try to correct typos during any kind of code synthesis.
+ if (!CodeSynthesisContexts.empty())
return nullptr;
// Don't try to correct 'super'.
@@ -4958,8 +4983,6 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) {
void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
MissingImportKind MIK, bool Recover) {
- assert(!isVisible(Decl) && "missing import for non-hidden decl?");
-
// Suggest importing a module providing the definition of this entity, if
// possible.
NamedDecl *Def = getDefinitionToImport(Decl);
@@ -4994,6 +5017,14 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
MissingImportKind MIK, bool Recover) {
assert(!Modules.empty());
+ // Weed out duplicates from module list.
+ llvm::SmallVector<Module*, 8> UniqueModules;
+ llvm::SmallDenseSet<Module*, 8> UniqueModuleSet;
+ for (auto *M : Modules)
+ if (UniqueModuleSet.insert(M).second)
+ UniqueModules.push_back(M);
+ Modules = UniqueModules;
+
if (Modules.size() > 1) {
std::string ModuleList;
unsigned N = 0;
@@ -5008,8 +5039,8 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
Diag(UseLoc, diag::err_module_unimported_use_multiple)
<< (int)MIK << Decl << ModuleList;
- } else if (const FileEntry *E =
- PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, DeclLoc)) {
+ } else if (const FileEntry *E = PP.getModuleHeaderToIncludeForDiagnostics(
+ UseLoc, Modules[0], DeclLoc)) {
// The right way to make the declaration visible is to include a header;
// suggest doing so.
//
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp
index 3481b82..bfb0071 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp
@@ -200,9 +200,10 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
if (CDecl->IsClassExtension()) {
Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
- FD, GetterSel, SetterSel,
- isReadWrite,
- Attributes,
+ FD,
+ GetterSel, ODS.getGetterNameLoc(),
+ SetterSel, ODS.getSetterNameLoc(),
+ isReadWrite, Attributes,
ODS.getPropertyAttributes(),
T, TSI, MethodImplKind);
if (!Res)
@@ -212,9 +213,10 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
if (!Res) {
Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
- GetterSel, SetterSel, isReadWrite,
- Attributes, ODS.getPropertyAttributes(),
- T, TSI, MethodImplKind);
+ GetterSel, ODS.getGetterNameLoc(), SetterSel,
+ ODS.getSetterNameLoc(), isReadWrite, Attributes,
+ ODS.getPropertyAttributes(), T, TSI,
+ MethodImplKind);
if (lexicalDC)
Res->setLexicalDeclContext(lexicalDC);
}
@@ -412,7 +414,10 @@ Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
SourceLocation LParenLoc,
FieldDeclarator &FD,
- Selector GetterSel, Selector SetterSel,
+ Selector GetterSel,
+ SourceLocation GetterNameLoc,
+ Selector SetterSel,
+ SourceLocation SetterNameLoc,
const bool isReadWrite,
unsigned &Attributes,
const unsigned AttributesAsWritten,
@@ -512,7 +517,8 @@ Sema::HandlePropertyInClassExtension(Scope *S,
// Create a new ObjCPropertyDecl with the DeclContext being
// the class extension.
ObjCPropertyDecl *PDecl = CreatePropertyDecl(S, CDecl, AtLoc, LParenLoc,
- FD, GetterSel, SetterSel,
+ FD, GetterSel, GetterNameLoc,
+ SetterSel, SetterNameLoc,
isReadWrite,
Attributes, AttributesAsWritten,
T, TSI, MethodImplKind, DC);
@@ -562,7 +568,9 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
SourceLocation LParenLoc,
FieldDeclarator &FD,
Selector GetterSel,
+ SourceLocation GetterNameLoc,
Selector SetterSel,
+ SourceLocation SetterNameLoc,
const bool isReadWrite,
const unsigned Attributes,
const unsigned AttributesAsWritten,
@@ -640,8 +648,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
// Regardless of setter/getter attribute, we save the default getter/setter
// selector names in anticipation of declaration of setter/getter methods.
- PDecl->setGetterName(GetterSel);
- PDecl->setSetterName(SetterSel);
+ PDecl->setGetterName(GetterSel, GetterNameLoc);
+ PDecl->setSetterName(SetterSel, SetterNameLoc);
PDecl->setPropertyAttributesAsWritten(
makePropertyAttributesAsWritten(AttributesAsWritten));
@@ -806,53 +814,185 @@ static void setImpliedPropertyAttributeForReadOnlyProperty(
property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
}
-/// DiagnosePropertyMismatchDeclInProtocols - diagnose properties declared
-/// in inherited protocols with mismatched types. Since any of them can
-/// be candidate for synthesis.
-static void
-DiagnosePropertyMismatchDeclInProtocols(Sema &S, SourceLocation AtLoc,
+static bool
+isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2,
+ ObjCPropertyDecl::PropertyAttributeKind Kind) {
+ return (Attr1 & Kind) != (Attr2 & Kind);
+}
+
+static bool areIncompatiblePropertyAttributes(unsigned Attr1, unsigned Attr2,
+ unsigned Kinds) {
+ return ((Attr1 & Kinds) != 0) != ((Attr2 & Kinds) != 0);
+}
+
+/// SelectPropertyForSynthesisFromProtocols - Finds the most appropriate
+/// property declaration that should be synthesised in all of the inherited
+/// protocols. It also diagnoses properties declared in inherited protocols with
+/// mismatched types or attributes, since any of them can be candidate for
+/// synthesis.
+static ObjCPropertyDecl *
+SelectPropertyForSynthesisFromProtocols(Sema &S, SourceLocation AtLoc,
ObjCInterfaceDecl *ClassDecl,
ObjCPropertyDecl *Property) {
- ObjCInterfaceDecl::ProtocolPropertyMap PropMap;
+ assert(isa<ObjCProtocolDecl>(Property->getDeclContext()) &&
+ "Expected a property from a protocol");
+ ObjCInterfaceDecl::ProtocolPropertySet ProtocolSet;
+ ObjCInterfaceDecl::PropertyDeclOrder Properties;
for (const auto *PI : ClassDecl->all_referenced_protocols()) {
if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
- PDecl->collectInheritedProtocolProperties(Property, PropMap);
+ PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
+ Properties);
}
- if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass())
+ if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass()) {
while (SDecl) {
for (const auto *PI : SDecl->all_referenced_protocols()) {
if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
- PDecl->collectInheritedProtocolProperties(Property, PropMap);
+ PDecl->collectInheritedProtocolProperties(Property, ProtocolSet,
+ Properties);
}
SDecl = SDecl->getSuperClass();
}
-
- if (PropMap.empty())
- return;
-
+ }
+
+ if (Properties.empty())
+ return Property;
+
+ ObjCPropertyDecl *OriginalProperty = Property;
+ size_t SelectedIndex = 0;
+ for (const auto &Prop : llvm::enumerate(Properties)) {
+ // Select the 'readwrite' property if such property exists.
+ if (Property->isReadOnly() && !Prop.value()->isReadOnly()) {
+ Property = Prop.value();
+ SelectedIndex = Prop.index();
+ }
+ }
+ if (Property != OriginalProperty) {
+ // Check that the old property is compatible with the new one.
+ Properties[SelectedIndex] = OriginalProperty;
+ }
+
QualType RHSType = S.Context.getCanonicalType(Property->getType());
- bool FirsTime = true;
- for (ObjCInterfaceDecl::ProtocolPropertyMap::iterator
- I = PropMap.begin(), E = PropMap.end(); I != E; I++) {
- ObjCPropertyDecl *Prop = I->second;
+ unsigned OriginalAttributes = Property->getPropertyAttributesAsWritten();
+ enum MismatchKind {
+ IncompatibleType = 0,
+ HasNoExpectedAttribute,
+ HasUnexpectedAttribute,
+ DifferentGetter,
+ DifferentSetter
+ };
+ // Represents a property from another protocol that conflicts with the
+ // selected declaration.
+ struct MismatchingProperty {
+ const ObjCPropertyDecl *Prop;
+ MismatchKind Kind;
+ StringRef AttributeName;
+ };
+ SmallVector<MismatchingProperty, 4> Mismatches;
+ for (ObjCPropertyDecl *Prop : Properties) {
+ // Verify the property attributes.
+ unsigned Attr = Prop->getPropertyAttributesAsWritten();
+ if (Attr != OriginalAttributes) {
+ auto Diag = [&](bool OriginalHasAttribute, StringRef AttributeName) {
+ MismatchKind Kind = OriginalHasAttribute ? HasNoExpectedAttribute
+ : HasUnexpectedAttribute;
+ Mismatches.push_back({Prop, Kind, AttributeName});
+ };
+ if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
+ ObjCPropertyDecl::OBJC_PR_copy)) {
+ Diag(OriginalAttributes & ObjCPropertyDecl::OBJC_PR_copy, "copy");
+ continue;
+ }
+ if (areIncompatiblePropertyAttributes(
+ OriginalAttributes, Attr, ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong)) {
+ Diag(OriginalAttributes & (ObjCPropertyDecl::OBJC_PR_retain |
+ ObjCPropertyDecl::OBJC_PR_strong),
+ "retain (or strong)");
+ continue;
+ }
+ if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
+ ObjCPropertyDecl::OBJC_PR_atomic)) {
+ Diag(OriginalAttributes & ObjCPropertyDecl::OBJC_PR_atomic, "atomic");
+ continue;
+ }
+ }
+ if (Property->getGetterName() != Prop->getGetterName()) {
+ Mismatches.push_back({Prop, DifferentGetter, ""});
+ continue;
+ }
+ if (!Property->isReadOnly() && !Prop->isReadOnly() &&
+ Property->getSetterName() != Prop->getSetterName()) {
+ Mismatches.push_back({Prop, DifferentSetter, ""});
+ continue;
+ }
QualType LHSType = S.Context.getCanonicalType(Prop->getType());
if (!S.Context.propertyTypesAreCompatible(LHSType, RHSType)) {
bool IncompatibleObjC = false;
QualType ConvertedType;
if (!S.isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC)
|| IncompatibleObjC) {
- if (FirsTime) {
- S.Diag(Property->getLocation(), diag::warn_protocol_property_mismatch)
- << Property->getType();
- FirsTime = false;
- }
- S.Diag(Prop->getLocation(), diag::note_protocol_property_declare)
- << Prop->getType();
+ Mismatches.push_back({Prop, IncompatibleType, ""});
+ continue;
}
}
}
- if (!FirsTime && AtLoc.isValid())
+
+ if (Mismatches.empty())
+ return Property;
+
+ // Diagnose incompability.
+ {
+ bool HasIncompatibleAttributes = false;
+ for (const auto &Note : Mismatches)
+ HasIncompatibleAttributes =
+ Note.Kind != IncompatibleType ? true : HasIncompatibleAttributes;
+ // Promote the warning to an error if there are incompatible attributes or
+ // incompatible types together with readwrite/readonly incompatibility.
+ auto Diag = S.Diag(Property->getLocation(),
+ Property != OriginalProperty || HasIncompatibleAttributes
+ ? diag::err_protocol_property_mismatch
+ : diag::warn_protocol_property_mismatch);
+ Diag << Mismatches[0].Kind;
+ switch (Mismatches[0].Kind) {
+ case IncompatibleType:
+ Diag << Property->getType();
+ break;
+ case HasNoExpectedAttribute:
+ case HasUnexpectedAttribute:
+ Diag << Mismatches[0].AttributeName;
+ break;
+ case DifferentGetter:
+ Diag << Property->getGetterName();
+ break;
+ case DifferentSetter:
+ Diag << Property->getSetterName();
+ break;
+ }
+ }
+ for (const auto &Note : Mismatches) {
+ auto Diag =
+ S.Diag(Note.Prop->getLocation(), diag::note_protocol_property_declare)
+ << Note.Kind;
+ switch (Note.Kind) {
+ case IncompatibleType:
+ Diag << Note.Prop->getType();
+ break;
+ case HasNoExpectedAttribute:
+ case HasUnexpectedAttribute:
+ Diag << Note.AttributeName;
+ break;
+ case DifferentGetter:
+ Diag << Note.Prop->getGetterName();
+ break;
+ case DifferentSetter:
+ Diag << Note.Prop->getSetterName();
+ break;
+ }
+ }
+ if (AtLoc.isValid())
S.Diag(AtLoc, diag::note_property_synthesize);
+
+ return Property;
}
/// Determine whether any storage attributes were written on the property.
@@ -988,8 +1128,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
}
if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))
- DiagnosePropertyMismatchDeclInProtocols(*this, AtLoc, IDecl, property);
-
+ property = SelectPropertyForSynthesisFromProtocols(*this, AtLoc, IDecl,
+ property);
+
} else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
if (Synthesize) {
Diag(AtLoc, diag::err_synthesize_category_decl);
@@ -1668,8 +1809,9 @@ static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,
/// \brief Default synthesizes all properties which must be synthesized
/// in class's \@implementation.
-void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
- ObjCInterfaceDecl *IDecl) {
+void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
+ ObjCInterfaceDecl *IDecl,
+ SourceLocation AtEnd) {
ObjCInterfaceDecl::PropertyMap PropMap;
ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder;
IDecl->collectPropertiesToImplement(PropMap, PropertyOrder);
@@ -1717,6 +1859,10 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
diag::warn_auto_synthesizing_protocol_property)
<< Prop << Proto;
Diag(Prop->getLocation(), diag::note_property_declare);
+ std::string FixIt =
+ (Twine("@synthesize ") + Prop->getName() + ";\n\n").str();
+ Diag(AtEnd, diag::note_add_synthesize_directive)
+ << FixItHint::CreateInsertion(AtEnd, FixIt);
}
continue;
}
@@ -1756,7 +1902,8 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
}
}
-void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
+void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D,
+ SourceLocation AtEnd) {
if (!LangOpts.ObjCDefaultSynthProperties || LangOpts.ObjCRuntime.isFragile())
return;
ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D);
@@ -1764,7 +1911,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
return;
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface())
if (!IDecl->isObjCRequiresPropertyDefs())
- DefaultSynthesizeProperties(S, IC, IDecl);
+ DefaultSynthesizeProperties(S, IC, IDecl, AtEnd);
}
static void DiagnoseUnimplementedAccessor(
@@ -2177,12 +2324,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
DiagnosePropertyAccessorMismatch(property, GetterMethod,
property->getLocation());
- if (SetterMethod) {
- ObjCPropertyDecl::PropertyAttributeKind CAttr =
- property->getPropertyAttributes();
- if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) &&
- Context.getCanonicalType(SetterMethod->getReturnType()) !=
- Context.VoidTy)
+ if (!property->isReadOnly() && SetterMethod) {
+ if (Context.getCanonicalType(SetterMethod->getReturnType()) !=
+ Context.VoidTy)
Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
if (SetterMethod->param_size() != 1 ||
!Context.hasSameUnqualifiedType(
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp
index dcd19c8..01f574b 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp
@@ -118,7 +118,9 @@ private:
typedef SmallVector<SharingMapTy, 4> StackTy;
/// \brief Stack of used declaration and their data-sharing attributes.
- StackTy Stack;
+ DeclSAMapTy Threadprivates;
+ const FunctionScopeInfo *CurrentNonCapturingFunctionScope = nullptr;
+ SmallVector<std::pair<StackTy, const FunctionScopeInfo *>, 4> Stack;
/// \brief true, if check for DSA must be from parent directive, false, if
/// from current directive.
OpenMPClauseKind ClauseKindMode = OMPC_unknown;
@@ -133,8 +135,14 @@ private:
/// \brief Checks if the variable is a local for OpenMP region.
bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter);
+ bool isStackEmpty() const {
+ return Stack.empty() ||
+ Stack.back().second != CurrentNonCapturingFunctionScope ||
+ Stack.back().first.empty();
+ }
+
public:
- explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {}
+ explicit DSAStackTy(Sema &S) : SemaRef(S) {}
bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; }
@@ -144,13 +152,38 @@ public:
void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
- Stack.push_back(SharingMapTy(DKind, DirName, CurScope, Loc));
- Stack.back().DefaultAttrLoc = Loc;
+ if (Stack.empty() ||
+ Stack.back().second != CurrentNonCapturingFunctionScope)
+ Stack.emplace_back(StackTy(), CurrentNonCapturingFunctionScope);
+ Stack.back().first.emplace_back(DKind, DirName, CurScope, Loc);
+ Stack.back().first.back().DefaultAttrLoc = Loc;
}
void pop() {
- assert(Stack.size() > 1 && "Data-sharing attributes stack is empty!");
- Stack.pop_back();
+ assert(!Stack.back().first.empty() &&
+ "Data-sharing attributes stack is empty!");
+ Stack.back().first.pop_back();
+ }
+
+ /// Start new OpenMP region stack in new non-capturing function.
+ void pushFunction() {
+ const FunctionScopeInfo *CurFnScope = SemaRef.getCurFunction();
+ assert(!isa<CapturingScopeInfo>(CurFnScope));
+ CurrentNonCapturingFunctionScope = CurFnScope;
+ }
+ /// Pop region stack for non-capturing function.
+ void popFunction(const FunctionScopeInfo *OldFSI) {
+ if (!Stack.empty() && Stack.back().second == OldFSI) {
+ assert(Stack.back().first.empty());
+ Stack.pop_back();
+ }
+ CurrentNonCapturingFunctionScope = nullptr;
+ for (const FunctionScopeInfo *FSI : llvm::reverse(SemaRef.FunctionScopes)) {
+ if (!isa<CapturingScopeInfo>(FSI)) {
+ CurrentNonCapturingFunctionScope = FSI;
+ break;
+ }
+ }
}
void addCriticalWithHint(OMPCriticalDirective *D, llvm::APSInt Hint) {
@@ -229,31 +262,35 @@ public:
/// \brief Returns currently analyzed directive.
OpenMPDirectiveKind getCurrentDirective() const {
- return Stack.back().Directive;
+ return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive;
}
/// \brief Returns parent directive.
OpenMPDirectiveKind getParentDirective() const {
- if (Stack.size() > 2)
- return Stack[Stack.size() - 2].Directive;
- return OMPD_unknown;
+ if (isStackEmpty() || Stack.back().first.size() == 1)
+ return OMPD_unknown;
+ return std::next(Stack.back().first.rbegin())->Directive;
}
/// \brief Set default data sharing attribute to none.
void setDefaultDSANone(SourceLocation Loc) {
- Stack.back().DefaultAttr = DSA_none;
- Stack.back().DefaultAttrLoc = Loc;
+ assert(!isStackEmpty());
+ Stack.back().first.back().DefaultAttr = DSA_none;
+ Stack.back().first.back().DefaultAttrLoc = Loc;
}
/// \brief Set default data sharing attribute to shared.
void setDefaultDSAShared(SourceLocation Loc) {
- Stack.back().DefaultAttr = DSA_shared;
- Stack.back().DefaultAttrLoc = Loc;
+ assert(!isStackEmpty());
+ Stack.back().first.back().DefaultAttr = DSA_shared;
+ Stack.back().first.back().DefaultAttrLoc = Loc;
}
DefaultDataSharingAttributes getDefaultDSA() const {
- return Stack.back().DefaultAttr;
+ return isStackEmpty() ? DSA_unspecified
+ : Stack.back().first.back().DefaultAttr;
}
SourceLocation getDefaultDSALocation() const {
- return Stack.back().DefaultAttrLoc;
+ return isStackEmpty() ? SourceLocation()
+ : Stack.back().first.back().DefaultAttrLoc;
}
/// \brief Checks if the specified variable is a threadprivate.
@@ -264,52 +301,64 @@ public:
/// \brief Marks current region as ordered (it has an 'ordered' clause).
void setOrderedRegion(bool IsOrdered, Expr *Param) {
- Stack.back().OrderedRegion.setInt(IsOrdered);
- Stack.back().OrderedRegion.setPointer(Param);
+ assert(!isStackEmpty());
+ Stack.back().first.back().OrderedRegion.setInt(IsOrdered);
+ Stack.back().first.back().OrderedRegion.setPointer(Param);
}
/// \brief Returns true, if parent region is ordered (has associated
/// 'ordered' clause), false - otherwise.
bool isParentOrderedRegion() const {
- if (Stack.size() > 2)
- return Stack[Stack.size() - 2].OrderedRegion.getInt();
- return false;
+ if (isStackEmpty() || Stack.back().first.size() == 1)
+ return false;
+ return std::next(Stack.back().first.rbegin())->OrderedRegion.getInt();
}
/// \brief Returns optional parameter for the ordered region.
Expr *getParentOrderedRegionParam() const {
- if (Stack.size() > 2)
- return Stack[Stack.size() - 2].OrderedRegion.getPointer();
- return nullptr;
+ if (isStackEmpty() || Stack.back().first.size() == 1)
+ return nullptr;
+ return std::next(Stack.back().first.rbegin())->OrderedRegion.getPointer();
}
/// \brief Marks current region as nowait (it has a 'nowait' clause).
void setNowaitRegion(bool IsNowait = true) {
- Stack.back().NowaitRegion = IsNowait;
+ assert(!isStackEmpty());
+ Stack.back().first.back().NowaitRegion = IsNowait;
}
/// \brief Returns true, if parent region is nowait (has associated
/// 'nowait' clause), false - otherwise.
bool isParentNowaitRegion() const {
- if (Stack.size() > 2)
- return Stack[Stack.size() - 2].NowaitRegion;
- return false;
+ if (isStackEmpty() || Stack.back().first.size() == 1)
+ return false;
+ return std::next(Stack.back().first.rbegin())->NowaitRegion;
}
/// \brief Marks parent region as cancel region.
void setParentCancelRegion(bool Cancel = true) {
- if (Stack.size() > 2)
- Stack[Stack.size() - 2].CancelRegion =
- Stack[Stack.size() - 2].CancelRegion || Cancel;
+ if (!isStackEmpty() && Stack.back().first.size() > 1) {
+ auto &StackElemRef = *std::next(Stack.back().first.rbegin());
+ StackElemRef.CancelRegion |= StackElemRef.CancelRegion || Cancel;
+ }
}
/// \brief Return true if current region has inner cancel construct.
- bool isCancelRegion() const { return Stack.back().CancelRegion; }
+ bool isCancelRegion() const {
+ return isStackEmpty() ? false : Stack.back().first.back().CancelRegion;
+ }
/// \brief Set collapse value for the region.
- void setAssociatedLoops(unsigned Val) { Stack.back().AssociatedLoops = Val; }
+ void setAssociatedLoops(unsigned Val) {
+ assert(!isStackEmpty());
+ Stack.back().first.back().AssociatedLoops = Val;
+ }
/// \brief Return collapse value for region.
- unsigned getAssociatedLoops() const { return Stack.back().AssociatedLoops; }
+ unsigned getAssociatedLoops() const {
+ return isStackEmpty() ? 0 : Stack.back().first.back().AssociatedLoops;
+ }
/// \brief Marks current target region as one with closely nested teams
/// region.
void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) {
- if (Stack.size() > 2)
- Stack[Stack.size() - 2].InnerTeamsRegionLoc = TeamsRegionLoc;
+ if (!isStackEmpty() && Stack.back().first.size() > 1) {
+ std::next(Stack.back().first.rbegin())->InnerTeamsRegionLoc =
+ TeamsRegionLoc;
+ }
}
/// \brief Returns true, if current region has closely nested teams region.
bool hasInnerTeamsRegion() const {
@@ -317,14 +366,20 @@ public:
}
/// \brief Returns location of the nested teams region (if any).
SourceLocation getInnerTeamsRegionLoc() const {
- if (Stack.size() > 1)
- return Stack.back().InnerTeamsRegionLoc;
- return SourceLocation();
+ return isStackEmpty() ? SourceLocation()
+ : Stack.back().first.back().InnerTeamsRegionLoc;
}
- Scope *getCurScope() const { return Stack.back().CurScope; }
- Scope *getCurScope() { return Stack.back().CurScope; }
- SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; }
+ Scope *getCurScope() const {
+ return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope;
+ }
+ Scope *getCurScope() {
+ return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope;
+ }
+ SourceLocation getConstructLoc() {
+ return isStackEmpty() ? SourceLocation()
+ : Stack.back().first.back().ConstructLoc;
+ }
/// Do the check specified in \a Check to all component lists and return true
/// if any issue is found.
@@ -333,8 +388,10 @@ public:
const llvm::function_ref<
bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind)> &Check) {
- auto SI = Stack.rbegin();
- auto SE = Stack.rend();
+ if (isStackEmpty())
+ return false;
+ auto SI = Stack.back().first.rbegin();
+ auto SE = Stack.back().first.rend();
if (SI == SE)
return false;
@@ -355,15 +412,39 @@ public:
return false;
}
+ /// Do the check specified in \a Check to all component lists at a given level
+ /// and return true if any issue is found.
+ bool checkMappableExprComponentListsForDeclAtLevel(
+ ValueDecl *VD, unsigned Level,
+ const llvm::function_ref<
+ bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
+ OpenMPClauseKind)> &Check) {
+ if (isStackEmpty())
+ return false;
+
+ auto StartI = Stack.back().first.begin();
+ auto EndI = Stack.back().first.end();
+ if (std::distance(StartI, EndI) <= (int)Level)
+ return false;
+ std::advance(StartI, Level);
+
+ auto MI = StartI->MappedExprComponents.find(VD);
+ if (MI != StartI->MappedExprComponents.end())
+ for (auto &L : MI->second.Components)
+ if (Check(L, MI->second.Kind))
+ return true;
+ return false;
+ }
+
/// Create a new mappable expression component list associated with a given
/// declaration and initialize it with the provided list of components.
void addMappableExpressionComponents(
ValueDecl *VD,
OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
OpenMPClauseKind WhereFoundClauseKind) {
- assert(Stack.size() > 1 &&
+ assert(!isStackEmpty() &&
"Not expecting to retrieve components from a empty stack!");
- auto &MEC = Stack.back().MappedExprComponents[VD];
+ auto &MEC = Stack.back().first.back().MappedExprComponents[VD];
// Create new entry and append the new components there.
MEC.Components.resize(MEC.Components.size() + 1);
MEC.Components.back().append(Components.begin(), Components.end());
@@ -371,23 +452,25 @@ public:
}
unsigned getNestingLevel() const {
- assert(Stack.size() > 1);
- return Stack.size() - 2;
+ assert(!isStackEmpty());
+ return Stack.back().first.size() - 1;
}
void addDoacrossDependClause(OMPDependClause *C, OperatorOffsetTy &OpsOffs) {
- assert(Stack.size() > 2);
- assert(isOpenMPWorksharingDirective(Stack[Stack.size() - 2].Directive));
- Stack[Stack.size() - 2].DoacrossDepends.insert({C, OpsOffs});
+ assert(!isStackEmpty() && Stack.back().first.size() > 1);
+ auto &StackElem = *std::next(Stack.back().first.rbegin());
+ assert(isOpenMPWorksharingDirective(StackElem.Directive));
+ StackElem.DoacrossDepends.insert({C, OpsOffs});
}
llvm::iterator_range<DoacrossDependMapTy::const_iterator>
getDoacrossDependClauses() const {
- assert(Stack.size() > 1);
- if (isOpenMPWorksharingDirective(Stack[Stack.size() - 1].Directive)) {
- auto &Ref = Stack[Stack.size() - 1].DoacrossDepends;
+ assert(!isStackEmpty());
+ auto &StackElem = Stack.back().first.back();
+ if (isOpenMPWorksharingDirective(StackElem.Directive)) {
+ auto &Ref = StackElem.DoacrossDepends;
return llvm::make_range(Ref.begin(), Ref.end());
}
- return llvm::make_range(Stack[0].DoacrossDepends.end(),
- Stack[0].DoacrossDepends.end());
+ return llvm::make_range(StackElem.DoacrossDepends.end(),
+ StackElem.DoacrossDepends.end());
}
};
bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
@@ -416,7 +499,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
auto *VD = dyn_cast<VarDecl>(D);
auto *FD = dyn_cast<FieldDecl>(D);
DSAVarData DVar;
- if (Iter == std::prev(Stack.rend())) {
+ if (isStackEmpty() || Iter == Stack.back().first.rend()) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a region but not in construct]
// File-scope or namespace-scope variables referenced in called routines
@@ -490,8 +573,9 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
// bound to the current team is shared.
if (isOpenMPTaskingDirective(DVar.DKind)) {
DSAVarData DVarTemp;
- for (StackTy::reverse_iterator I = std::next(Iter), EE = Stack.rend();
- I != EE; ++I) {
+ auto I = Iter, E = Stack.back().first.rend();
+ do {
+ ++I;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
// Referenced in a Construct, implicitly determined, p.6]
// In a task construct, if no default clause is present, a variable
@@ -503,9 +587,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
DVar.CKind = OMPC_firstprivate;
return DVar;
}
- if (isParallelOrTaskRegion(I->Directive))
- break;
- }
+ } while (I != E && !isParallelOrTaskRegion(I->Directive));
DVar.CKind =
(DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
return DVar;
@@ -520,12 +602,13 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter,
}
Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) {
- assert(Stack.size() > 1 && "Data sharing attributes stack is empty");
+ assert(!isStackEmpty() && "Data sharing attributes stack is empty");
D = getCanonicalDecl(D);
- auto It = Stack.back().AlignedMap.find(D);
- if (It == Stack.back().AlignedMap.end()) {
+ auto &StackElem = Stack.back().first.back();
+ auto It = StackElem.AlignedMap.find(D);
+ if (It == StackElem.AlignedMap.end()) {
assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
- Stack.back().AlignedMap[D] = NewDE;
+ StackElem.AlignedMap[D] = NewDE;
return nullptr;
} else {
assert(It->second && "Unexpected nullptr expr in the aligned map");
@@ -535,35 +618,43 @@ Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) {
}
void DSAStackTy::addLoopControlVariable(ValueDecl *D, VarDecl *Capture) {
- assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- Stack.back().LCVMap.insert(
- std::make_pair(D, LCDeclInfo(Stack.back().LCVMap.size() + 1, Capture)));
+ auto &StackElem = Stack.back().first.back();
+ StackElem.LCVMap.insert(
+ {D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture)});
}
DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(ValueDecl *D) {
- assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D]
- : LCDeclInfo(0, nullptr);
+ auto &StackElem = Stack.back().first.back();
+ auto It = StackElem.LCVMap.find(D);
+ if (It != StackElem.LCVMap.end())
+ return It->second;
+ return {0, nullptr};
}
DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(ValueDecl *D) {
- assert(Stack.size() > 2 && "Data-sharing attributes stack is empty");
+ assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
+ "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- return Stack[Stack.size() - 2].LCVMap.count(D) > 0
- ? Stack[Stack.size() - 2].LCVMap[D]
- : LCDeclInfo(0, nullptr);
+ auto &StackElem = *std::next(Stack.back().first.rbegin());
+ auto It = StackElem.LCVMap.find(D);
+ if (It != StackElem.LCVMap.end())
+ return It->second;
+ return {0, nullptr};
}
ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) {
- assert(Stack.size() > 2 && "Data-sharing attributes stack is empty");
- if (Stack[Stack.size() - 2].LCVMap.size() < I)
+ assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
+ "Data-sharing attributes stack is empty");
+ auto &StackElem = *std::next(Stack.back().first.rbegin());
+ if (StackElem.LCVMap.size() < I)
return nullptr;
- for (auto &Pair : Stack[Stack.size() - 2].LCVMap) {
+ for (auto &Pair : StackElem.LCVMap)
if (Pair.second.first == I)
return Pair.first;
- }
return nullptr;
}
@@ -571,13 +662,13 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
DeclRefExpr *PrivateCopy) {
D = getCanonicalDecl(D);
if (A == OMPC_threadprivate) {
- auto &Data = Stack[0].SharingMap[D];
+ auto &Data = Threadprivates[D];
Data.Attributes = A;
Data.RefExpr.setPointer(E);
Data.PrivateCopy = nullptr;
} else {
- assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
- auto &Data = Stack.back().SharingMap[D];
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
+ auto &Data = Stack.back().first.back().SharingMap[D];
assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
(A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
(A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
@@ -592,7 +683,7 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
Data.RefExpr.setPointerAndInt(E, IsLastprivate);
Data.PrivateCopy = PrivateCopy;
if (PrivateCopy) {
- auto &Data = Stack.back().SharingMap[PrivateCopy->getDecl()];
+ auto &Data = Stack.back().first.back().SharingMap[PrivateCopy->getDecl()];
Data.Attributes = A;
Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
Data.PrivateCopy = nullptr;
@@ -602,19 +693,17 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) {
D = D->getCanonicalDecl();
- if (Stack.size() > 2) {
- reverse_iterator I = Iter, E = std::prev(Stack.rend());
+ if (!isStackEmpty() && Stack.back().first.size() > 1) {
+ reverse_iterator I = Iter, E = Stack.back().first.rend();
Scope *TopScope = nullptr;
- while (I != E && !isParallelOrTaskRegion(I->Directive)) {
+ while (I != E && !isParallelOrTaskRegion(I->Directive))
++I;
- }
if (I == E)
return false;
TopScope = I->CurScope ? I->CurScope->getParent() : nullptr;
Scope *CurScope = getCurScope();
- while (CurScope != TopScope && !CurScope->isDeclScope(D)) {
+ while (CurScope != TopScope && !CurScope->isDeclScope(D))
CurScope = CurScope->getParent();
- }
return CurScope != TopScope;
}
return false;
@@ -665,16 +754,16 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
D->getLocation()),
OMPC_threadprivate);
}
- if (Stack[0].SharingMap.count(D)) {
- DVar.RefExpr = Stack[0].SharingMap[D].RefExpr.getPointer();
+ auto TI = Threadprivates.find(D);
+ if (TI != Threadprivates.end()) {
+ DVar.RefExpr = TI->getSecond().RefExpr.getPointer();
DVar.CKind = OMPC_threadprivate;
return DVar;
}
- if (Stack.size() == 1) {
+ if (isStackEmpty())
// Not in OpenMP execution region and top scope was already checked.
return DVar;
- }
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.4]
@@ -722,11 +811,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
// Explicitly specified attributes and local variables with predetermined
// attributes.
- auto StartI = std::next(Stack.rbegin());
- auto EndI = std::prev(Stack.rend());
- if (FromParent && StartI != EndI) {
+ auto StartI = std::next(Stack.back().first.rbegin());
+ auto EndI = Stack.back().first.rend();
+ if (FromParent && StartI != EndI)
StartI = std::next(StartI);
- }
auto I = std::prev(StartI);
if (I->SharingMap.count(D)) {
DVar.RefExpr = I->SharingMap[D].RefExpr.getPointer();
@@ -740,12 +828,15 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
bool FromParent) {
+ if (isStackEmpty()) {
+ StackTy::reverse_iterator I;
+ return getDSA(I, D);
+ }
D = getCanonicalDecl(D);
- auto StartI = Stack.rbegin();
- auto EndI = std::prev(Stack.rend());
- if (FromParent && StartI != EndI) {
+ auto StartI = Stack.back().first.rbegin();
+ auto EndI = Stack.back().first.rend();
+ if (FromParent && StartI != EndI)
StartI = std::next(StartI);
- }
return getDSA(StartI, D);
}
@@ -754,33 +845,37 @@ DSAStackTy::hasDSA(ValueDecl *D,
const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
bool FromParent) {
+ if (isStackEmpty())
+ return {};
D = getCanonicalDecl(D);
- auto StartI = std::next(Stack.rbegin());
- auto EndI = Stack.rend();
- if (FromParent && StartI != EndI) {
- StartI = std::next(StartI);
- }
- for (auto I = StartI, EE = EndI; I != EE; ++I) {
+ auto I = (FromParent && Stack.back().first.size() > 1)
+ ? std::next(Stack.back().first.rbegin())
+ : Stack.back().first.rbegin();
+ auto EndI = Stack.back().first.rend();
+ while (std::distance(I, EndI) > 1) {
+ std::advance(I, 1);
if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive))
continue;
DSAVarData DVar = getDSA(I, D);
if (CPred(DVar.CKind))
return DVar;
}
- return DSAVarData();
+ return {};
}
DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
bool FromParent) {
+ if (isStackEmpty())
+ return {};
D = getCanonicalDecl(D);
- auto StartI = std::next(Stack.rbegin());
- auto EndI = Stack.rend();
+ auto StartI = std::next(Stack.back().first.rbegin());
+ auto EndI = Stack.back().first.rend();
if (FromParent && StartI != EndI)
StartI = std::next(StartI);
if (StartI == EndI || !DPred(StartI->Directive))
- return DSAVarData();
+ return {};
DSAVarData DVar = getDSA(StartI, D);
return CPred(DVar.CKind) ? DVar : DSAVarData();
}
@@ -790,9 +885,11 @@ bool DSAStackTy::hasExplicitDSA(
unsigned Level, bool NotLastprivate) {
if (CPred(ClauseKindMode))
return true;
+ if (isStackEmpty())
+ return false;
D = getCanonicalDecl(D);
- auto StartI = std::next(Stack.begin());
- auto EndI = Stack.end();
+ auto StartI = Stack.back().first.begin();
+ auto EndI = Stack.back().first.end();
if (std::distance(StartI, EndI) <= (int)Level)
return false;
std::advance(StartI, Level);
@@ -805,8 +902,10 @@ bool DSAStackTy::hasExplicitDSA(
bool DSAStackTy::hasExplicitDirective(
const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
unsigned Level) {
- auto StartI = std::next(Stack.begin());
- auto EndI = Stack.end();
+ if (isStackEmpty())
+ return false;
+ auto StartI = Stack.back().first.begin();
+ auto EndI = Stack.back().first.end();
if (std::distance(StartI, EndI) <= (int)Level)
return false;
std::advance(StartI, Level);
@@ -819,13 +918,12 @@ bool DSAStackTy::hasDirective(
&DPred,
bool FromParent) {
// We look only in the enclosing region.
- if (Stack.size() < 2)
+ if (isStackEmpty())
return false;
- auto StartI = std::next(Stack.rbegin());
- auto EndI = std::prev(Stack.rend());
- if (FromParent && StartI != EndI) {
+ auto StartI = std::next(Stack.back().first.rbegin());
+ auto EndI = Stack.back().first.rend();
+ if (FromParent && StartI != EndI)
StartI = std::next(StartI);
- }
for (auto I = StartI, EE = EndI; I != EE; ++I) {
if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc))
return true;
@@ -839,6 +937,14 @@ void Sema::InitDataSharingAttributesStack() {
#define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
+void Sema::pushOpenMPFunctionRegion() {
+ DSAStack->pushFunction();
+}
+
+void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
+ DSAStack->popFunction(OldFSI);
+}
+
bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
@@ -912,9 +1018,8 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
bool IsVariableUsedInMapClause = false;
bool IsVariableAssociatedWithSection = false;
- DSAStack->checkMappableExprComponentListsForDecl(
- D, /*CurrentRegionOnly=*/true,
- [&](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ DSAStack->checkMappableExprComponentListsForDeclAtLevel(
+ D, Level, [&](OMPClauseMappableExprCommon::MappableExprComponentListRef
MapExprComponents,
OpenMPClauseKind WhereFoundClauseKind) {
// Only the map clause information influences how a variable is
@@ -1050,7 +1155,8 @@ void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
DSAStack->push(DKind, DirName, CurScope, Loc);
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::StartOpenMPClause(OpenMPClauseKind K) {
@@ -1594,8 +1700,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
- case OMPD_teams:
- case OMPD_target_teams: {
+ case OMPD_teams: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
@@ -1608,6 +1713,28 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
+ case OMPD_target_teams:
+ case OMPD_target_parallel: {
+ Sema::CapturedParamNameType ParamsTarget[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ // Start a captured region for 'target' with no implicit parameters.
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ ParamsTarget);
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
+ QualType KmpInt32PtrTy =
+ Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
+ Sema::CapturedParamNameType ParamsTeamsOrParallel[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ // Start a captured region for 'teams' or 'parallel'. Both regions have
+ // the same implicit parameters.
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ ParamsTeamsOrParallel);
+ break;
+ }
case OMPD_simd:
case OMPD_for:
case OMPD_for_simd:
@@ -1622,7 +1749,6 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_atomic:
case OMPD_target_data:
case OMPD_target:
- case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
case OMPD_target_simd: {
@@ -1681,6 +1807,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(".lb.", KmpUInt64Ty),
std::make_pair(".ub.", KmpUInt64Ty), std::make_pair(".st.", KmpInt64Ty),
std::make_pair(".liter.", KmpInt32Ty),
+ std::make_pair(".reductions.",
+ Context.VoidPtrTy.withConst().withRestrict()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
@@ -1737,6 +1865,12 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
}
}
+int Sema::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) {
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, DKind);
+ return CaptureRegions.size();
+}
+
static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
Expr *CaptureExpr, bool WithInit,
bool AsExpression) {
@@ -1796,16 +1930,49 @@ static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref) {
return CaptureExpr->isGLValue() ? Res : S.DefaultLvalueConversion(Res.get());
}
+namespace {
+// OpenMP directives parsed in this section are represented as a
+// CapturedStatement with an associated statement. If a syntax error
+// is detected during the parsing of the associated statement, the
+// compiler must abort processing and close the CapturedStatement.
+//
+// Combined directives such as 'target parallel' have more than one
+// nested CapturedStatements. This RAII ensures that we unwind out
+// of all the nested CapturedStatements when an error is found.
+class CaptureRegionUnwinderRAII {
+private:
+ Sema &S;
+ bool &ErrorFound;
+ OpenMPDirectiveKind DKind;
+
+public:
+ CaptureRegionUnwinderRAII(Sema &S, bool &ErrorFound,
+ OpenMPDirectiveKind DKind)
+ : S(S), ErrorFound(ErrorFound), DKind(DKind) {}
+ ~CaptureRegionUnwinderRAII() {
+ if (ErrorFound) {
+ int ThisCaptureLevel = S.getOpenMPCaptureLevels(DKind);
+ while (--ThisCaptureLevel >= 0)
+ S.ActOnCapturedRegionError();
+ }
+ }
+};
+} // namespace
+
StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
ArrayRef<OMPClause *> Clauses) {
+ bool ErrorFound = false;
+ CaptureRegionUnwinderRAII CaptureRegionUnwinder(
+ *this, ErrorFound, DSAStack->getCurrentDirective());
if (!S.isUsable()) {
- ActOnCapturedRegionError();
+ ErrorFound = true;
return StmtError();
}
OMPOrderedClause *OC = nullptr;
OMPScheduleClause *SC = nullptr;
SmallVector<OMPLinearClause *, 4> LCs;
+ SmallVector<OMPClauseWithPreInit *, 8> PICs;
// This is required for proper codegen.
for (auto *Clause : Clauses) {
if (isOpenMPPrivate(Clause->getClauseKind()) ||
@@ -1822,15 +1989,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
}
DSAStack->setForceVarCapturing(/*V=*/false);
} else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) {
- // Mark all variables in private list clauses as used in inner region.
- // Required for proper codegen of combined directives.
- // TODO: add processing for other clauses.
- if (auto *C = OMPClauseWithPreInit::get(Clause)) {
- if (auto *DS = cast_or_null<DeclStmt>(C->getPreInitStmt())) {
- for (auto *D : DS->decls())
- MarkVariableReferenced(D->getLocation(), cast<VarDecl>(D));
- }
- }
+ if (auto *C = OMPClauseWithPreInit::get(Clause))
+ PICs.push_back(C);
if (auto *C = OMPClauseWithPostUpdate::get(Clause)) {
if (auto *E = C->getPostUpdateExpr())
MarkDeclarationsReferencedInExpr(E);
@@ -1843,7 +2003,6 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
else if (Clause->getClauseKind() == OMPC_linear)
LCs.push_back(cast<OMPLinearClause>(Clause));
}
- bool ErrorFound = false;
// OpenMP, 2.7.1 Loop Construct, Restrictions
// The nonmonotonic modifier cannot be specified if an ordered clause is
// specified.
@@ -1874,13 +2033,54 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
ErrorFound = true;
}
if (ErrorFound) {
- ActOnCapturedRegionError();
return StmtError();
}
- return ActOnCapturedRegionEnd(S.get());
+ StmtResult SR = S;
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective());
+ for (auto ThisCaptureRegion : llvm::reverse(CaptureRegions)) {
+ // Mark all variables in private list clauses as used in inner region.
+ // Required for proper codegen of combined directives.
+ // TODO: add processing for other clauses.
+ if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) {
+ for (auto *C : PICs) {
+ OpenMPDirectiveKind CaptureRegion = C->getCaptureRegion();
+ // Find the particular capture region for the clause if the
+ // directive is a combined one with multiple capture regions.
+ // If the directive is not a combined one, the capture region
+ // associated with the clause is OMPD_unknown and is generated
+ // only once.
+ if (CaptureRegion == ThisCaptureRegion ||
+ CaptureRegion == OMPD_unknown) {
+ if (auto *DS = cast_or_null<DeclStmt>(C->getPreInitStmt())) {
+ for (auto *D : DS->decls())
+ MarkVariableReferenced(D->getLocation(), cast<VarDecl>(D));
+ }
+ }
+ }
+ }
+ SR = ActOnCapturedRegionEnd(SR.get());
+ }
+ return SR;
+}
+
+static bool checkCancelRegion(Sema &SemaRef, OpenMPDirectiveKind CurrentRegion,
+ OpenMPDirectiveKind CancelRegion,
+ SourceLocation StartLoc) {
+ // CancelRegion is only needed for cancel and cancellation_point.
+ if (CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_cancellation_point)
+ return false;
+
+ if (CancelRegion == OMPD_parallel || CancelRegion == OMPD_for ||
+ CancelRegion == OMPD_sections || CancelRegion == OMPD_taskgroup)
+ return false;
+
+ SemaRef.Diag(StartLoc, diag::err_omp_wrong_cancel_region)
+ << getOpenMPDirectiveName(CancelRegion);
+ return true;
}
-static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
+static bool checkNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
OpenMPDirectiveKind CurrentRegion,
const DeclarationNameInfo &CurrentName,
OpenMPDirectiveKind CancelRegion,
@@ -2180,7 +2380,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
StmtResult Res = StmtError();
- if (CheckNestingOfRegions(*this, DSAStack, Kind, DirName, CancelRegion,
+ // First check CancelRegion which is then used in checkNestingOfRegions.
+ if (checkCancelRegion(*this, Kind, CancelRegion, StartLoc) ||
+ checkNestingOfRegions(*this, DSAStack, Kind, DirName, CancelRegion,
StartLoc))
return StmtError();
@@ -2193,7 +2395,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
// Check default data sharing attributes for referenced variables.
DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt));
- DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt());
+ int ThisCaptureLevel = getOpenMPCaptureLevels(Kind);
+ Stmt *S = AStmt;
+ while (--ThisCaptureLevel >= 0)
+ S = cast<CapturedStmt>(S)->getCapturedStmt();
+ DSAChecker.Visit(S);
if (DSAChecker.isErrorFound())
return StmtError();
// Generate list of implicitly defined firstprivate variables.
@@ -2294,9 +2500,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc);
break;
case OMPD_taskgroup:
- assert(ClausesWithImplicit.empty() &&
- "No clauses are allowed for 'omp taskgroup' directive");
- Res = ActOnOpenMPTaskgroupDirective(AStmt, StartLoc, EndLoc);
+ Res = ActOnOpenMPTaskgroupDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc);
break;
case OMPD_flush:
assert(AStmt == nullptr &&
@@ -3969,7 +4174,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin();
// Build variables passed into runtime, necessary for worksharing directives.
- ExprResult LB, UB, IL, ST, EUB, PrevLB, PrevUB;
+ ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB;
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
isOpenMPDistributeDirective(DKind)) {
// Lower bound variable, initialized with zero.
@@ -4017,8 +4222,32 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// enclosing region. E.g. in 'distribute parallel for' the bounds obtained
// by scheduling 'distribute' have to be passed to the schedule of 'for'.
if (isOpenMPLoopBoundSharingDirective(DKind)) {
- auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl();
+ // Lower bound variable, initialized with zero.
+ VarDecl *CombLBDecl =
+ buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.lb");
+ CombLB = buildDeclRefExpr(SemaRef, CombLBDecl, VType, InitLoc);
+ SemaRef.AddInitializerToDecl(
+ CombLBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(),
+ /*DirectInit*/ false);
+
+ // Upper bound variable, initialized with last iteration number.
+ VarDecl *CombUBDecl =
+ buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.ub");
+ CombUB = buildDeclRefExpr(SemaRef, CombUBDecl, VType, InitLoc);
+ SemaRef.AddInitializerToDecl(CombUBDecl, LastIteration.get(),
+ /*DirectInit*/ false);
+
+ ExprResult CombIsUBGreater = SemaRef.BuildBinOp(
+ CurScope, InitLoc, BO_GT, CombUB.get(), LastIteration.get());
+ ExprResult CombCondOp =
+ SemaRef.ActOnConditionalOp(InitLoc, InitLoc, CombIsUBGreater.get(),
+ LastIteration.get(), CombUB.get());
+ CombEUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, CombUB.get(),
+ CombCondOp.get());
+ CombEUB = SemaRef.ActOnFinishFullExpr(CombEUB.get());
+
+ auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl();
// We expect to have at least 2 more parameters than the 'parallel'
// directive does - the lower and upper bounds of the previous schedule.
assert(CD->getNumParams() >= 4 &&
@@ -4040,7 +4269,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// Build the iteration variable and its initialization before loop.
ExprResult IV;
- ExprResult Init;
+ ExprResult Init, CombInit;
{
VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv");
IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc);
@@ -4051,6 +4280,18 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
: SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS);
Init = SemaRef.ActOnFinishFullExpr(Init.get());
+
+ if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ Expr *CombRHS =
+ (isOpenMPWorksharingDirective(DKind) ||
+ isOpenMPTaskLoopDirective(DKind) ||
+ isOpenMPDistributeDirective(DKind))
+ ? CombLB.get()
+ : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get();
+ CombInit =
+ SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), CombRHS);
+ CombInit = SemaRef.ActOnFinishFullExpr(CombInit.get());
+ }
}
// Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops.
@@ -4061,7 +4302,11 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get())
: SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
NumIterations.get());
-
+ ExprResult CombCond;
+ if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ CombCond =
+ SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get());
+ }
// Loop increment (IV = IV + 1)
SourceLocation IncLoc;
ExprResult Inc =
@@ -4076,7 +4321,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// Increments for worksharing loops (LB = LB + ST; UB = UB + ST).
// Used for directives with static scheduling.
- ExprResult NextLB, NextUB;
+ // In combined construct, add combined version that use CombLB and CombUB
+ // base variables for the update
+ ExprResult NextLB, NextUB, CombNextLB, CombNextUB;
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
isOpenMPDistributeDirective(DKind)) {
// LB + ST
@@ -4099,6 +4346,59 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
NextUB = SemaRef.ActOnFinishFullExpr(NextUB.get());
if (!NextUB.isUsable())
return 0;
+ if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ CombNextLB =
+ SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombLB.get(), ST.get());
+ if (!NextLB.isUsable())
+ return 0;
+ // LB = LB + ST
+ CombNextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombLB.get(),
+ CombNextLB.get());
+ CombNextLB = SemaRef.ActOnFinishFullExpr(CombNextLB.get());
+ if (!CombNextLB.isUsable())
+ return 0;
+ // UB + ST
+ CombNextUB =
+ SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, CombUB.get(), ST.get());
+ if (!CombNextUB.isUsable())
+ return 0;
+ // UB = UB + ST
+ CombNextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, CombUB.get(),
+ CombNextUB.get());
+ CombNextUB = SemaRef.ActOnFinishFullExpr(CombNextUB.get());
+ if (!CombNextUB.isUsable())
+ return 0;
+ }
+ }
+
+ // Create increment expression for distribute loop when combined in a same
+ // directive with for as IV = IV + ST; ensure upper bound expression based
+ // on PrevUB instead of NumIterations - used to implement 'for' when found
+ // in combination with 'distribute', like in 'distribute parallel for'
+ SourceLocation DistIncLoc;
+ ExprResult DistCond, DistInc, PrevEUB;
+ if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ DistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get());
+ assert(DistCond.isUsable() && "distribute cond expr was not built");
+
+ DistInc =
+ SemaRef.BuildBinOp(CurScope, DistIncLoc, BO_Add, IV.get(), ST.get());
+ assert(DistInc.isUsable() && "distribute inc expr was not built");
+ DistInc = SemaRef.BuildBinOp(CurScope, DistIncLoc, BO_Assign, IV.get(),
+ DistInc.get());
+ DistInc = SemaRef.ActOnFinishFullExpr(DistInc.get());
+ assert(DistInc.isUsable() && "distribute inc expr was not built");
+
+ // Build expression: UB = min(UB, prevUB) for #for in composite or combined
+ // construct
+ SourceLocation DistEUBLoc;
+ ExprResult IsUBGreater =
+ SemaRef.BuildBinOp(CurScope, DistEUBLoc, BO_GT, UB.get(), PrevUB.get());
+ ExprResult CondOp = SemaRef.ActOnConditionalOp(
+ DistEUBLoc, DistEUBLoc, IsUBGreater.get(), PrevUB.get(), UB.get());
+ PrevEUB = SemaRef.BuildBinOp(CurScope, DistIncLoc, BO_Assign, UB.get(),
+ CondOp.get());
+ PrevEUB = SemaRef.ActOnFinishFullExpr(PrevEUB.get());
}
// Build updates and final values of the loop counters.
@@ -4215,6 +4515,15 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.NUB = NextUB.get();
Built.PrevLB = PrevLB.get();
Built.PrevUB = PrevUB.get();
+ Built.DistInc = DistInc.get();
+ Built.PrevEUB = PrevEUB.get();
+ Built.DistCombinedFields.LB = CombLB.get();
+ Built.DistCombinedFields.UB = CombUB.get();
+ Built.DistCombinedFields.EUB = CombEUB.get();
+ Built.DistCombinedFields.Init = CombInit.get();
+ Built.DistCombinedFields.Cond = CombCond.get();
+ Built.DistCombinedFields.NLB = CombNextLB.get();
+ Built.DistCombinedFields.NUB = CombNextUB.get();
Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get();
// Fill data for doacross depend clauses.
@@ -4759,7 +5068,8 @@ StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc,
return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc);
}
-StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt,
+StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
@@ -4769,7 +5079,8 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(Stmt *AStmt,
getCurFunction()->setHasBranchProtectedScope();
- return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, AStmt);
+ return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
}
StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
@@ -5644,16 +5955,17 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective(
B, DSAStack->isCancelRegion());
}
-/// \brief Check for existence of a map clause in the list of clauses.
-static bool HasMapClause(ArrayRef<OMPClause *> Clauses) {
- for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
- I != E; ++I) {
- if (*I != nullptr && (*I)->getClauseKind() == OMPC_map) {
- return true;
- }
- }
+/// Check for existence of a map clause in the list of clauses.
+static bool hasClauses(ArrayRef<OMPClause *> Clauses,
+ const OpenMPClauseKind K) {
+ return llvm::any_of(
+ Clauses, [K](const OMPClause *C) { return C->getClauseKind() == K; });
+}
- return false;
+template <typename... Params>
+static bool hasClauses(ArrayRef<OMPClause *> Clauses, const OpenMPClauseKind K,
+ const Params... ClauseTypes) {
+ return hasClauses(Clauses, K) || hasClauses(Clauses, ClauseTypes...);
}
StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
@@ -5667,8 +5979,9 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
// OpenMP [2.10.1, Restrictions, p. 97]
// At least one map clause must appear on the directive.
- if (!HasMapClause(Clauses)) {
- Diag(StartLoc, diag::err_omp_no_map_for_directive)
+ if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr)) {
+ Diag(StartLoc, diag::err_omp_no_clause_for_directive)
+ << "'map' or 'use_device_ptr'"
<< getOpenMPDirectiveName(OMPD_target_data);
return StmtError();
}
@@ -5685,9 +5998,9 @@ Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation EndLoc) {
// OpenMP [2.10.2, Restrictions, p. 99]
// At least one map clause must appear on the directive.
- if (!HasMapClause(Clauses)) {
- Diag(StartLoc, diag::err_omp_no_map_for_directive)
- << getOpenMPDirectiveName(OMPD_target_enter_data);
+ if (!hasClauses(Clauses, OMPC_map)) {
+ Diag(StartLoc, diag::err_omp_no_clause_for_directive)
+ << "'map'" << getOpenMPDirectiveName(OMPD_target_enter_data);
return StmtError();
}
@@ -5701,9 +6014,9 @@ Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation EndLoc) {
// OpenMP [2.10.3, Restrictions, p. 102]
// At least one map clause must appear on the directive.
- if (!HasMapClause(Clauses)) {
- Diag(StartLoc, diag::err_omp_no_map_for_directive)
- << getOpenMPDirectiveName(OMPD_target_exit_data);
+ if (!hasClauses(Clauses, OMPC_map)) {
+ Diag(StartLoc, diag::err_omp_no_clause_for_directive)
+ << "'map'" << getOpenMPDirectiveName(OMPD_target_exit_data);
return StmtError();
}
@@ -5713,12 +6026,7 @@ Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses,
StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc) {
- bool seenMotionClause = false;
- for (auto *C : Clauses) {
- if (C->getClauseKind() == OMPC_to || C->getClauseKind() == OMPC_from)
- seenMotionClause = true;
- }
- if (!seenMotionClause) {
+ if (!hasClauses(Clauses, OMPC_to, OMPC_from)) {
Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required);
return StmtError();
}
@@ -5748,12 +6056,6 @@ StmtResult
Sema::ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc,
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion) {
- if (CancelRegion != OMPD_parallel && CancelRegion != OMPD_for &&
- CancelRegion != OMPD_sections && CancelRegion != OMPD_taskgroup) {
- Diag(StartLoc, diag::err_omp_wrong_cancel_region)
- << getOpenMPDirectiveName(CancelRegion);
- return StmtError();
- }
if (DSAStack->isParentNowaitRegion()) {
Diag(StartLoc, diag::err_omp_parent_cancel_region_nowait) << 0;
return StmtError();
@@ -5770,12 +6072,6 @@ StmtResult Sema::ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion) {
- if (CancelRegion != OMPD_parallel && CancelRegion != OMPD_for &&
- CancelRegion != OMPD_sections && CancelRegion != OMPD_taskgroup) {
- Diag(StartLoc, diag::err_omp_wrong_cancel_region)
- << getOpenMPDirectiveName(CancelRegion);
- return StmtError();
- }
if (DSAStack->isParentNowaitRegion()) {
Diag(StartLoc, diag::err_omp_parent_cancel_region_nowait) << 1;
return StmtError();
@@ -5813,6 +6109,33 @@ static bool checkGrainsizeNumTasksClauses(Sema &S,
return ErrorFound;
}
+static bool checkReductionClauseWithNogroup(Sema &S,
+ ArrayRef<OMPClause *> Clauses) {
+ OMPClause *ReductionClause = nullptr;
+ OMPClause *NogroupClause = nullptr;
+ for (auto *C : Clauses) {
+ if (C->getClauseKind() == OMPC_reduction) {
+ ReductionClause = C;
+ if (NogroupClause)
+ break;
+ continue;
+ }
+ if (C->getClauseKind() == OMPC_nogroup) {
+ NogroupClause = C;
+ if (ReductionClause)
+ break;
+ continue;
+ }
+ }
+ if (ReductionClause && NogroupClause) {
+ S.Diag(ReductionClause->getLocStart(), diag::err_omp_reduction_with_nogroup)
+ << SourceRange(NogroupClause->getLocStart(),
+ NogroupClause->getLocEnd());
+ return true;
+ }
+ return false;
+}
+
StmtResult Sema::ActOnOpenMPTaskLoopDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
@@ -5839,6 +6162,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective(
// not appear on the same taskloop directive.
if (checkGrainsizeNumTasksClauses(*this, Clauses))
return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
getCurFunction()->setHasBranchProtectedScope();
return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc,
@@ -5882,6 +6210,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
// not appear on the same taskloop directive.
if (checkGrainsizeNumTasksClauses(*this, Clauses))
return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
getCurFunction()->setHasBranchProtectedScope();
return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc,
@@ -6519,6 +6852,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -6551,6 +6885,323 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
return Res;
}
+// An OpenMP directive such as 'target parallel' has two captured regions:
+// for the 'target' and 'parallel' respectively. This function returns
+// the region in which to capture expressions associated with a clause.
+// A return value of OMPD_unknown signifies that the expression should not
+// be captured.
+static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
+ OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
+ OpenMPDirectiveKind NameModifier = OMPD_unknown) {
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
+
+ switch (CKind) {
+ case OMPC_if:
+ switch (DKind) {
+ case OMPD_target_parallel:
+ // If this clause applies to the nested 'parallel' region, capture within
+ // the 'target' region, otherwise do not capture.
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
+ CaptureRegion = OMPD_target;
+ break;
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_target_data:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target_update:
+ // Do not capture if-clause expressions.
+ break;
+ case OMPD_threadprivate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_teams:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_distribute_simd:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ llvm_unreachable("Unexpected OpenMP directive with if-clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
+ case OMPC_num_threads:
+ switch (DKind) {
+ case OMPD_target_parallel:
+ CaptureRegion = OMPD_target;
+ break;
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_target_data:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target_update:
+ // Do not capture num_threads-clause expressions.
+ break;
+ case OMPD_threadprivate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_teams:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_distribute_simd:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ llvm_unreachable("Unexpected OpenMP directive with num_threads-clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
+ case OMPC_num_teams:
+ switch (DKind) {
+ case OMPD_target_teams:
+ CaptureRegion = OMPD_target;
+ break;
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_parallel:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_target_data:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target_update:
+ case OMPD_teams:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ // Do not capture num_teams-clause expressions.
+ break;
+ case OMPD_threadprivate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_distribute_simd:
+ llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
+ case OMPC_thread_limit:
+ switch (DKind) {
+ case OMPD_target_teams:
+ CaptureRegion = OMPD_target;
+ break;
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_parallel:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_target_data:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target_update:
+ case OMPD_teams:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ // Do not capture thread_limit-clause expressions.
+ break;
+ case OMPD_threadprivate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_distribute_simd:
+ llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
+ case OMPC_schedule:
+ case OMPC_dist_schedule:
+ case OMPC_firstprivate:
+ case OMPC_lastprivate:
+ case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_linear:
+ case OMPC_default:
+ case OMPC_proc_bind:
+ case OMPC_final:
+ case OMPC_safelen:
+ case OMPC_simdlen:
+ case OMPC_collapse:
+ case OMPC_private:
+ case OMPC_shared:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_ordered:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
+ case OMPC_threadprivate:
+ case OMPC_flush:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
+ case OMPC_depend:
+ case OMPC_device:
+ case OMPC_threads:
+ case OMPC_simd:
+ case OMPC_map:
+ case OMPC_priority:
+ case OMPC_grainsize:
+ case OMPC_nogroup:
+ case OMPC_num_tasks:
+ case OMPC_hint:
+ case OMPC_defaultmap:
+ case OMPC_unknown:
+ case OMPC_uniform:
+ case OMPC_to:
+ case OMPC_from:
+ case OMPC_use_device_ptr:
+ case OMPC_is_device_ptr:
+ llvm_unreachable("Unexpected OpenMP clause.");
+ }
+ return CaptureRegion;
+}
+
OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier,
Expr *Condition, SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -6558,6 +7209,8 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier,
SourceLocation ColonLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Condition;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
!Condition->isInstantiationDependent() &&
!Condition->containsUnexpandedParameterPack()) {
@@ -6566,10 +7219,20 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier,
return nullptr;
ValExpr = MakeFullExpr(Val.get()).get();
+
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ CaptureRegion =
+ getOpenMPCaptureRegionForClause(DKind, OMPC_if, NameModifier);
+ if (CaptureRegion != OMPD_unknown) {
+ llvm::MapVector<Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
+ }
}
- return new (Context) OMPIfClause(NameModifier, ValExpr, StartLoc, LParenLoc,
- NameModifierLoc, ColonLoc, EndLoc);
+ return new (Context)
+ OMPIfClause(NameModifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc,
+ LParenLoc, NameModifierLoc, ColonLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
@@ -6665,6 +7328,8 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = NumThreads;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.5, Restrictions]
// The num_threads expression must evaluate to a positive integer value.
@@ -6672,8 +7337,16 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
/*StrictlyPositive=*/true))
return nullptr;
- return new (Context)
- OMPNumThreadsClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads);
+ if (CaptureRegion != OMPD_unknown) {
+ llvm::MapVector<Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
+ }
+
+ return new (Context) OMPNumThreadsClause(
+ ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
}
ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E,
@@ -6799,6 +7472,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -6956,6 +7630,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -7153,6 +7828,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_lastprivate:
case OMPC_shared:
case OMPC_reduction:
+ case OMPC_task_reduction:
case OMPC_linear:
case OMPC_aligned:
case OMPC_copyin:
@@ -7265,6 +7941,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
EndLoc, ReductionIdScopeSpec, ReductionId);
break;
+ case OMPC_task_reduction:
+ Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, ReductionIdScopeSpec,
+ ReductionId);
+ break;
case OMPC_linear:
Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
LinKind, DepLinMapLoc, ColonLoc, EndLoc);
@@ -8233,15 +8914,66 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
return ExprEmpty();
}
-OMPClause *Sema::ActOnOpenMPReductionClause(
+namespace {
+/// Data for the reduction-based clauses.
+struct ReductionData {
+ /// List of original reduction items.
+ SmallVector<Expr *, 8> Vars;
+ /// List of private copies of the reduction items.
+ SmallVector<Expr *, 8> Privates;
+ /// LHS expressions for the reduction_op expressions.
+ SmallVector<Expr *, 8> LHSs;
+ /// RHS expressions for the reduction_op expressions.
+ SmallVector<Expr *, 8> RHSs;
+ /// Reduction operation expression.
+ SmallVector<Expr *, 8> ReductionOps;
+ /// List of captures for clause.
+ SmallVector<Decl *, 4> ExprCaptures;
+ /// List of postupdate expressions.
+ SmallVector<Expr *, 4> ExprPostUpdates;
+ ReductionData() = delete;
+ /// Reserves required memory for the reduction data.
+ ReductionData(unsigned Size) {
+ Vars.reserve(Size);
+ Privates.reserve(Size);
+ LHSs.reserve(Size);
+ RHSs.reserve(Size);
+ ReductionOps.reserve(Size);
+ ExprCaptures.reserve(Size);
+ ExprPostUpdates.reserve(Size);
+ }
+ /// Stores reduction item and reduction operation only (required for dependent
+ /// reduction item).
+ void push(Expr *Item, Expr *ReductionOp) {
+ Vars.emplace_back(Item);
+ Privates.emplace_back(nullptr);
+ LHSs.emplace_back(nullptr);
+ RHSs.emplace_back(nullptr);
+ ReductionOps.emplace_back(ReductionOp);
+ }
+ /// Stores reduction data.
+ void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS,
+ Expr *ReductionOp) {
+ Vars.emplace_back(Item);
+ Privates.emplace_back(Private);
+ LHSs.emplace_back(LHS);
+ RHSs.emplace_back(RHS);
+ ReductionOps.emplace_back(ReductionOp);
+ }
+};
+} // namespace
+
+static bool ActOnOMPReductionKindClause(
+ Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind,
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
- ArrayRef<Expr *> UnresolvedReductions) {
+ ArrayRef<Expr *> UnresolvedReductions, ReductionData &RD) {
auto DN = ReductionId.getName();
auto OOK = DN.getCXXOverloadedOperator();
BinaryOperatorKind BOK = BO_Comma;
+ ASTContext &Context = S.Context;
// OpenMP [2.14.3.6, reduction clause]
// C
// reduction-identifier is either an identifier or one of the following
@@ -8325,13 +9057,6 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
ReductionIdRange.setEnd(ReductionId.getEndLoc());
- SmallVector<Expr *, 8> Vars;
- SmallVector<Expr *, 8> Privates;
- SmallVector<Expr *, 8> LHSs;
- SmallVector<Expr *, 8> RHSs;
- SmallVector<Expr *, 8> ReductionOps;
- SmallVector<Decl *, 4> ExprCaptures;
- SmallVector<Expr *, 4> ExprPostUpdates;
auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end();
bool FirstIter = true;
for (auto RefExpr : VarList) {
@@ -8349,27 +9074,23 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
- auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange,
/*AllowArraySection=*/true);
if (Res.second) {
- // It will be analyzed later.
- Vars.push_back(RefExpr);
- Privates.push_back(nullptr);
- LHSs.push_back(nullptr);
- RHSs.push_back(nullptr);
// Try to find 'declare reduction' corresponding construct before using
// builtin/overloaded operators.
QualType Type = Context.DependentTy;
CXXCastPath BasePath;
ExprResult DeclareReductionRef = buildDeclareReductionRef(
- *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec,
+ S, ELoc, ERange, Stack->getCurScope(), ReductionIdScopeSpec,
ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
- if (CurContext->isDependentContext() &&
+ Expr *ReductionOp = nullptr;
+ if (S.CurContext->isDependentContext() &&
(DeclareReductionRef.isUnset() ||
isa<UnresolvedLookupExpr>(DeclareReductionRef.get())))
- ReductionOps.push_back(DeclareReductionRef.get());
- else
- ReductionOps.push_back(nullptr);
+ ReductionOp = DeclareReductionRef.get();
+ // It will be analyzed later.
+ RD.push(RefExpr, ReductionOp);
}
ValueDecl *D = Res.first;
if (!D)
@@ -8394,21 +9115,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
// type or a reference type.
- if (RequireCompleteType(ELoc, Type,
- diag::err_omp_reduction_incomplete_type))
+ if (S.RequireCompleteType(ELoc, Type,
+ diag::err_omp_reduction_incomplete_type))
continue;
// OpenMP [2.14.3.6, reduction clause, Restrictions]
// A list item that appears in a reduction clause must not be
// const-qualified.
if (Type.getNonReferenceType().isConstant(Context)) {
- Diag(ELoc, diag::err_omp_const_reduction_list_item)
- << getOpenMPClauseName(OMPC_reduction) << Type << ERange;
+ S.Diag(ELoc, diag::err_omp_const_reduction_list_item) << ERange;
if (!ASE && !OASE) {
- bool IsDecl = !VD ||
- VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ S.Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
continue;
@@ -8419,10 +9138,11 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
if (!ASE && !OASE && VD) {
VarDecl *VDDef = VD->getDefinition();
if (VD->getType()->isReferenceType() && VDDef && VDDef->hasInit()) {
- DSARefChecker Check(DSAStack);
+ DSARefChecker Check(Stack);
if (Check.Visit(VDDef->getInit())) {
- Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange;
- Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef;
+ S.Diag(ELoc, diag::err_omp_reduction_ref_type_arg)
+ << getOpenMPClauseName(ClauseKind) << ERange;
+ S.Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef;
continue;
}
}
@@ -8440,17 +9160,17 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// but a list item can appear only once in the reduction clauses for that
// directive.
DSAStackTy::DSAVarData DVar;
- DVar = DSAStack->getTopDSA(D, false);
+ DVar = Stack->getTopDSA(D, false);
if (DVar.CKind == OMPC_reduction) {
- Diag(ELoc, diag::err_omp_once_referenced)
- << getOpenMPClauseName(OMPC_reduction);
+ S.Diag(ELoc, diag::err_omp_once_referenced)
+ << getOpenMPClauseName(ClauseKind);
if (DVar.RefExpr)
- Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
+ S.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
} else if (DVar.CKind != OMPC_unknown) {
- Diag(ELoc, diag::err_omp_wrong_dsa)
+ S.Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_reduction);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
+ ReportOriginalDSA(S, Stack, D, DVar);
continue;
}
@@ -8458,16 +9178,16 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// A list item that appears in a reduction clause of a worksharing
// construct must be shared in the parallel regions to which any of the
// worksharing regions arising from the worksharing construct bind.
- OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
+ OpenMPDirectiveKind CurrDir = Stack->getCurrentDirective();
if (isOpenMPWorksharingDirective(CurrDir) &&
!isOpenMPParallelDirective(CurrDir) &&
!isOpenMPTeamsDirective(CurrDir)) {
- DVar = DSAStack->getImplicitDSA(D, true);
+ DVar = Stack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared) {
- Diag(ELoc, diag::err_omp_required_access)
+ S.Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_reduction)
<< getOpenMPClauseName(OMPC_shared);
- ReportOriginalDSA(*this, DSAStack, D, DVar);
+ ReportOriginalDSA(S, Stack, D, DVar);
continue;
}
}
@@ -8476,24 +9196,20 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// builtin/overloaded operators.
CXXCastPath BasePath;
ExprResult DeclareReductionRef = buildDeclareReductionRef(
- *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec,
+ S, ELoc, ERange, Stack->getCurScope(), ReductionIdScopeSpec,
ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
if (DeclareReductionRef.isInvalid())
continue;
- if (CurContext->isDependentContext() &&
+ if (S.CurContext->isDependentContext() &&
(DeclareReductionRef.isUnset() ||
isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) {
- Vars.push_back(RefExpr);
- Privates.push_back(nullptr);
- LHSs.push_back(nullptr);
- RHSs.push_back(nullptr);
- ReductionOps.push_back(DeclareReductionRef.get());
+ RD.push(RefExpr, DeclareReductionRef.get());
continue;
}
if (BOK == BO_Comma && DeclareReductionRef.isUnset()) {
// Not allowed reduction identifier is found.
- Diag(ReductionId.getLocStart(),
- diag::err_omp_unknown_reduction_identifier)
+ S.Diag(ReductionId.getLocStart(),
+ diag::err_omp_unknown_reduction_identifier)
<< Type << ReductionIdRange;
continue;
}
@@ -8509,28 +9225,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
if (DeclareReductionRef.isUnset()) {
if ((BOK == BO_GT || BOK == BO_LT) &&
!(Type->isScalarType() ||
- (getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
- Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
- << getLangOpts().CPlusPlus;
+ (S.getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
+ S.Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
+ << getOpenMPClauseName(ClauseKind) << S.getLangOpts().CPlusPlus;
if (!ASE && !OASE) {
- bool IsDecl = !VD ||
- VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ S.Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
continue;
}
if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
- !getLangOpts().CPlusPlus && Type->isFloatingType()) {
- Diag(ELoc, diag::err_omp_clause_floating_type_arg);
+ !S.getLangOpts().CPlusPlus && Type->isFloatingType()) {
+ S.Diag(ELoc, diag::err_omp_clause_floating_type_arg)
+ << getOpenMPClauseName(ClauseKind);
if (!ASE && !OASE) {
- bool IsDecl = !VD ||
- VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ S.Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
}
continue;
@@ -8538,9 +9253,9 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
}
Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
- auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs",
+ auto *LHSVD = buildVarDecl(S, ELoc, Type, ".reduction.lhs",
D->hasAttrs() ? &D->getAttrs() : nullptr);
- auto *RHSVD = buildVarDecl(*this, ELoc, Type, D->getName(),
+ auto *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr);
auto PrivateTy = Type;
if (OASE ||
@@ -8552,19 +9267,20 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// For array subscripts or single variables Private Ty is the same as Type
// (type of the variable or single array element).
PrivateTy = Context.getVariableArrayType(
- Type, new (Context) OpaqueValueExpr(SourceLocation(),
- Context.getSizeType(), VK_RValue),
+ Type,
+ new (Context) OpaqueValueExpr(SourceLocation(), Context.getSizeType(),
+ VK_RValue),
ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange());
} else if (!ASE && !OASE &&
Context.getAsArrayType(D->getType().getNonReferenceType()))
PrivateTy = D->getType().getNonReferenceType();
// Private copy.
- auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, D->getName(),
+ auto *PrivateVD = buildVarDecl(S, ELoc, PrivateTy, D->getName(),
D->hasAttrs() ? &D->getAttrs() : nullptr);
// Add initializer for private variable.
Expr *Init = nullptr;
- auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc);
- auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc);
+ auto *LHSDRE = buildDeclRefExpr(S, LHSVD, Type, ELoc);
+ auto *RHSDRE = buildDeclRefExpr(S, RHSVD, Type, ELoc);
if (DeclareReductionRef.isUsable()) {
auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>();
auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl());
@@ -8581,13 +9297,13 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
case BO_LOr:
// '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
if (Type->isScalarType() || Type->isAnyComplexType())
- Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get();
+ Init = S.ActOnIntegerConstant(ELoc, /*Val=*/0).get();
break;
case BO_Mul:
case BO_LAnd:
if (Type->isScalarType() || Type->isAnyComplexType()) {
// '*' and '&&' reduction ops - initializer is '1'.
- Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get();
+ Init = S.ActOnIntegerConstant(ELoc, /*Val=*/1).get();
}
break;
case BO_And: {
@@ -8610,7 +9326,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
if (Init && OrigType->isAnyComplexType()) {
// Init = 0xFFFF + 0xFFFFi;
auto *Im = new (Context) ImaginaryLiteral(Init, OrigType);
- Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
+ Init = S.CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
}
Type = OrigType;
break;
@@ -8627,15 +9343,14 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
QualType IntTy =
Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned);
llvm::APInt InitValue =
- (BOK != BO_LT)
- ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
- : llvm::APInt::getMinValue(Size)
- : IsSigned ? llvm::APInt::getSignedMaxValue(Size)
- : llvm::APInt::getMaxValue(Size);
+ (BOK != BO_LT) ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
+ : llvm::APInt::getMinValue(Size)
+ : IsSigned ? llvm::APInt::getSignedMaxValue(Size)
+ : llvm::APInt::getMaxValue(Size);
Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
if (Type->isPointerType()) {
// Cast to pointer type.
- auto CastExpr = BuildCStyleCastExpr(
+ auto CastExpr = S.BuildCStyleCastExpr(
SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc),
SourceLocation(), Init);
if (CastExpr.isInvalid())
@@ -8676,20 +9391,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
llvm_unreachable("Unexpected reduction operation");
}
}
- if (Init && DeclareReductionRef.isUnset()) {
- AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false);
- } else if (!Init)
- ActOnUninitializedDecl(RHSVD);
+ if (Init && DeclareReductionRef.isUnset())
+ S.AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false);
+ else if (!Init)
+ S.ActOnUninitializedDecl(RHSVD);
if (RHSVD->isInvalidDecl())
continue;
if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) {
- Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
- << ReductionIdRange;
- bool IsDecl =
- !VD ||
- VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ S.Diag(ELoc, diag::err_omp_reduction_id_not_compatible)
+ << Type << ReductionIdRange;
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ S.Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
<< D;
continue;
}
@@ -8697,16 +9411,16 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// codegen.
PrivateVD->setInit(RHSVD->getInit());
PrivateVD->setInitStyle(RHSVD->getInitStyle());
- auto *PrivateDRE = buildDeclRefExpr(*this, PrivateVD, PrivateTy, ELoc);
+ auto *PrivateDRE = buildDeclRefExpr(S, PrivateVD, PrivateTy, ELoc);
ExprResult ReductionOp;
if (DeclareReductionRef.isUsable()) {
QualType RedTy = DeclareReductionRef.get()->getType();
QualType PtrRedTy = Context.getPointerType(RedTy);
- ExprResult LHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE);
- ExprResult RHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE);
+ ExprResult LHS = S.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE);
+ ExprResult RHS = S.CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE);
if (!BasePath.empty()) {
- LHS = DefaultLvalueConversion(LHS.get());
- RHS = DefaultLvalueConversion(RHS.get());
+ LHS = S.DefaultLvalueConversion(LHS.get());
+ RHS = S.DefaultLvalueConversion(RHS.get());
LHS = ImplicitCastExpr::Create(Context, PtrRedTy,
CK_UncheckedDerivedToBase, LHS.get(),
&BasePath, LHS.get()->getValueKind());
@@ -8719,27 +9433,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
QualType FnTy = Context.getFunctionType(Context.VoidTy, Params, EPI);
auto *OVE = new (Context) OpaqueValueExpr(
ELoc, Context.getPointerType(FnTy), VK_RValue, OK_Ordinary,
- DefaultLvalueConversion(DeclareReductionRef.get()).get());
+ S.DefaultLvalueConversion(DeclareReductionRef.get()).get());
Expr *Args[] = {LHS.get(), RHS.get()};
ReductionOp = new (Context)
CallExpr(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc);
} else {
- ReductionOp = BuildBinOp(DSAStack->getCurScope(),
- ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE);
+ ReductionOp = S.BuildBinOp(
+ Stack->getCurScope(), ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE);
if (ReductionOp.isUsable()) {
if (BOK != BO_LT && BOK != BO_GT) {
ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
- BO_Assign, LHSDRE, ReductionOp.get());
+ S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ReductionOp.get());
} else {
auto *ConditionalOp = new (Context) ConditionalOperator(
ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(),
RHSDRE, Type, VK_LValue, OK_Ordinary);
ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
- BO_Assign, LHSDRE, ConditionalOp);
+ S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ConditionalOp);
}
- ReductionOp = ActOnFinishFullExpr(ReductionOp.get());
+ ReductionOp = S.ActOnFinishFullExpr(ReductionOp.get());
}
if (ReductionOp.isInvalid())
continue;
@@ -8747,48 +9461,86 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
DeclRefExpr *Ref = nullptr;
Expr *VarsExpr = RefExpr->IgnoreParens();
- if (!VD && !CurContext->isDependentContext()) {
+ if (!VD && !S.CurContext->isDependentContext()) {
if (ASE || OASE) {
- TransformExprToCaptures RebuildToCapture(*this, D);
+ TransformExprToCaptures RebuildToCapture(S, D);
VarsExpr =
RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get();
Ref = RebuildToCapture.getCapturedExpr();
} else {
- VarsExpr = Ref =
- buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
+ VarsExpr = Ref = buildCapture(S, D, SimpleRefExpr, /*WithInit=*/false);
}
- if (!IsOpenMPCapturedDecl(D)) {
- ExprCaptures.push_back(Ref->getDecl());
+ if (!S.IsOpenMPCapturedDecl(D)) {
+ RD.ExprCaptures.emplace_back(Ref->getDecl());
if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) {
- ExprResult RefRes = DefaultLvalueConversion(Ref);
+ ExprResult RefRes = S.DefaultLvalueConversion(Ref);
if (!RefRes.isUsable())
continue;
ExprResult PostUpdateRes =
- BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign,
- SimpleRefExpr, RefRes.get());
+ S.BuildBinOp(Stack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr,
+ RefRes.get());
if (!PostUpdateRes.isUsable())
continue;
- ExprPostUpdates.push_back(
- IgnoredValueConversions(PostUpdateRes.get()).get());
+ if (isOpenMPTaskingDirective(Stack->getCurrentDirective()) ||
+ Stack->getCurrentDirective() == OMPD_taskgroup) {
+ S.Diag(RefExpr->getExprLoc(),
+ diag::err_omp_reduction_non_addressable_expression)
+ << RefExpr->getSourceRange();
+ continue;
+ }
+ RD.ExprPostUpdates.emplace_back(
+ S.IgnoredValueConversions(PostUpdateRes.get()).get());
}
}
}
- DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
- Vars.push_back(VarsExpr);
- Privates.push_back(PrivateDRE);
- LHSs.push_back(LHSDRE);
- RHSs.push_back(RHSDRE);
- ReductionOps.push_back(ReductionOp.get());
+ // All reduction items are still marked as reduction (to do not increase
+ // code base size).
+ Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
+ RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get());
}
+ return RD.Vars.empty();
+}
- if (Vars.empty())
+OMPClause *Sema::ActOnOpenMPReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ ReductionData RD(VarList.size());
+
+ if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList,
+ StartLoc, LParenLoc, ColonLoc, EndLoc,
+ ReductionIdScopeSpec, ReductionId,
+ UnresolvedReductions, RD))
return nullptr;
return OMPReductionClause::Create(
- Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
- ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates,
- LHSs, RHSs, ReductionOps, buildPreInits(Context, ExprCaptures),
- buildPostUpdate(*this, ExprPostUpdates));
+ Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
+ ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
+ RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps,
+ buildPreInits(Context, RD.ExprCaptures),
+ buildPostUpdate(*this, RD.ExprPostUpdates));
+}
+
+OMPClause *Sema::ActOnOpenMPTaskReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ ReductionData RD(VarList.size());
+
+ if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_task_reduction,
+ VarList, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, ReductionIdScopeSpec, ReductionId,
+ UnresolvedReductions, RD))
+ return nullptr;
+
+ return OMPTaskReductionClause::Create(
+ Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
+ ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
+ RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps,
+ buildPreInits(Context, RD.ExprCaptures),
+ buildPostUpdate(*this, RD.ExprPostUpdates));
}
bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
@@ -10451,7 +11203,8 @@ void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) {
else
CurContext = DRD;
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
QualType ReductionType = DRD->getType();
// Create 'T* omp_parm;T omp_in;'. All references to 'omp_in' will
@@ -10505,7 +11258,8 @@ void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
else
CurContext = DRD;
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
QualType ReductionType = DRD->getType();
// Create 'T* omp_parm;T omp_priv;'. All references to 'omp_priv' will
@@ -10566,6 +11320,8 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = NumTeams;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [teams Constrcut, Restrictions]
// The num_teams expression must evaluate to a positive integer value.
@@ -10573,7 +11329,16 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
/*StrictlyPositive=*/true))
return nullptr;
- return new (Context) OMPNumTeamsClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams);
+ if (CaptureRegion != OMPD_unknown) {
+ llvm::MapVector<Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
+ }
+
+ return new (Context) OMPNumTeamsClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
@@ -10581,6 +11346,8 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = ThreadLimit;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [teams Constrcut, Restrictions]
// The thread_limit expression must evaluate to a positive integer value.
@@ -10588,8 +11355,16 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
/*StrictlyPositive=*/true))
return nullptr;
- return new (Context)
- OMPThreadLimitClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit);
+ if (CaptureRegion != OMPD_unknown) {
+ llvm::MapVector<Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
+ }
+
+ return new (Context) OMPThreadLimitClause(
+ ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority,
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp
index f976b76..36f24fd 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp
@@ -48,13 +48,13 @@ static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) {
/// A convenience routine for creating a decayed reference to a function.
static ExprResult
CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
- bool HadMultipleCandidates,
- SourceLocation Loc = SourceLocation(),
+ const Expr *Base, bool HadMultipleCandidates,
+ SourceLocation Loc = SourceLocation(),
const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
if (S.DiagnoseUseOfDecl(FoundDecl, Loc))
- return ExprError();
+ return ExprError();
// If FoundDecl is different from Fn (such as if one is a template
- // and the other a specialization), make sure DiagnoseUseOfDecl is
+ // and the other a specialization), make sure DiagnoseUseOfDecl is
// called on both.
// FIXME: This would be more comprehensively addressed by modifying
// DiagnoseUseOfDecl to accept both the FoundDecl and the decl
@@ -68,7 +68,7 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
- S.MarkDeclRefReferenced(DRE);
+ S.MarkDeclRefReferenced(DRE, Base);
return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
CK_FunctionToPointerDecay);
}
@@ -79,7 +79,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
bool CStyle,
bool AllowObjCWritebackConversion);
-static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From,
+static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From,
QualType &ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
@@ -131,7 +131,7 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) {
ICR_Conversion,
ICR_Conversion,
ICR_Conversion,
- ICR_Conversion,
+ ICR_OCL_Scalar_Widening,
ICR_Complex_Real_Conversion,
ICR_Conversion,
ICR_Conversion,
@@ -330,13 +330,13 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
} else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) {
llvm::APSInt IntConstantValue;
const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ assert(Initializer && "Unknown conversion expression");
// If it's value-dependent, we can't tell whether it's narrowing.
if (Initializer->isValueDependent())
return NK_Dependent_Narrowing;
- if (Initializer &&
- Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) {
+ if (Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) {
// Convert the integer to the floating type.
llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(),
@@ -852,7 +852,7 @@ namespace {
Expr *Saved;
};
SmallVector<Entry, 2> Entries;
-
+
public:
void save(Sema &S, Expr *&E) {
assert(E->hasPlaceholderType(BuiltinType::ARCUnbridgedCast));
@@ -863,7 +863,7 @@ namespace {
void restore() {
for (SmallVectorImpl<Entry>::iterator
- i = Entries.begin(), e = Entries.end(); i != e; ++i)
+ i = Entries.begin(), e = Entries.end(); i != e; ++i)
*i->Addr = i->Saved;
}
};
@@ -917,40 +917,39 @@ static bool checkArgPlaceholdersForOverload(Sema &S,
return false;
}
-// IsOverload - Determine whether the given New declaration is an
-// overload of the declarations in Old. This routine returns false if
-// New and Old cannot be overloaded, e.g., if New has the same
-// signature as some function in Old (C++ 1.3.10) or if the Old
-// declarations aren't functions (or function templates) at all. When
-// it does return false, MatchedDecl will point to the decl that New
-// cannot be overloaded with. This decl may be a UsingShadowDecl on
-// top of the underlying declaration.
-//
-// Example: Given the following input:
-//
-// void f(int, float); // #1
-// void f(int, int); // #2
-// int f(int, int); // #3
-//
-// When we process #1, there is no previous declaration of "f",
-// so IsOverload will not be used.
-//
-// When we process #2, Old contains only the FunctionDecl for #1. By
-// comparing the parameter types, we see that #1 and #2 are overloaded
-// (since they have different signatures), so this routine returns
-// false; MatchedDecl is unchanged.
-//
-// When we process #3, Old is an overload set containing #1 and #2. We
-// compare the signatures of #3 to #1 (they're overloaded, so we do
-// nothing) and then #3 to #2. Since the signatures of #3 and #2 are
-// identical (return types of functions are not part of the
-// signature), IsOverload returns false and MatchedDecl will be set to
-// point to the FunctionDecl for #2.
-//
-// 'NewIsUsingShadowDecl' indicates that 'New' is being introduced
-// into a class by a using declaration. The rules for whether to hide
-// shadow declarations ignore some properties which otherwise figure
-// into a function template's signature.
+/// Determine whether the given New declaration is an overload of the
+/// declarations in Old. This routine returns Ovl_Match or Ovl_NonFunction if
+/// New and Old cannot be overloaded, e.g., if New has the same signature as
+/// some function in Old (C++ 1.3.10) or if the Old declarations aren't
+/// functions (or function templates) at all. When it does return Ovl_Match or
+/// Ovl_NonFunction, MatchedDecl will point to the decl that New cannot be
+/// overloaded with. This decl may be a UsingShadowDecl on top of the underlying
+/// declaration.
+///
+/// Example: Given the following input:
+///
+/// void f(int, float); // #1
+/// void f(int, int); // #2
+/// int f(int, int); // #3
+///
+/// When we process #1, there is no previous declaration of "f", so IsOverload
+/// will not be used.
+///
+/// When we process #2, Old contains only the FunctionDecl for #1. By comparing
+/// the parameter types, we see that #1 and #2 are overloaded (since they have
+/// different signatures), so this routine returns Ovl_Overload; MatchedDecl is
+/// unchanged.
+///
+/// When we process #3, Old is an overload set containing #1 and #2. We compare
+/// the signatures of #3 to #1 (they're overloaded, so we do nothing) and then
+/// #3 to #2. Since the signatures of #3 and #2 are identical (return types of
+/// functions are not part of the signature), IsOverload returns Ovl_Match and
+/// MatchedDecl will be set to point to the FunctionDecl for #2.
+///
+/// 'NewIsUsingShadowDecl' indicates that 'New' is being introduced into a class
+/// by a using declaration. The rules for whether to hide shadow declarations
+/// ignore some properties which otherwise figure into a function template's
+/// signature.
Sema::OverloadKind
Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
NamedDecl *&Match, bool NewIsUsingDecl) {
@@ -1369,9 +1368,9 @@ Sema::TryImplicitConversion(Expr *From, QualType ToType,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion) {
- return ::TryImplicitConversion(*this, From, ToType,
+ return ::TryImplicitConversion(*this, From, ToType,
SuppressUserConversions, AllowExplicit,
- InOverloadResolution, CStyle,
+ InOverloadResolution, CStyle,
AllowObjCWritebackConversion,
/*AllowObjCConversionOnExplicit=*/false);
}
@@ -1397,7 +1396,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// Objective-C ARC: Determine whether we will allow the writeback conversion.
bool AllowObjCWritebackConversion
- = getLangOpts().ObjCAutoRefCount &&
+ = getLangOpts().ObjCAutoRefCount &&
(Action == AA_Passing || Action == AA_Sending);
if (getLangOpts().ObjC1)
CheckObjCBridgeRelatedConversions(From->getLocStart(),
@@ -1593,15 +1592,15 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// if the function type matches except for [[noreturn]], it's ok
if (!S.IsFunctionConversion(FromType,
S.ExtractUnqualifiedFunctionType(ToType), resultTy))
- // otherwise, only a boolean conversion is standard
- if (!ToType->isBooleanType())
- return false;
+ // otherwise, only a boolean conversion is standard
+ if (!ToType->isBooleanType())
+ return false;
}
// Check if the "from" expression is taking the address of an overloaded
// function and recompute the FromType accordingly. Take advantage of the
// fact that non-static member functions *must* have such an address-of
- // expression.
+ // expression.
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn);
if (Method && !Method->isStatic()) {
assert(isa<UnaryOperator>(From->IgnoreParens()) &&
@@ -1639,7 +1638,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
SCS.First = ICK_Lvalue_To_Rvalue;
// C11 6.3.2.1p2:
- // ... if the lvalue has atomic type, the value has the non-atomic version
+ // ... if the lvalue has atomic type, the value has the non-atomic version
// of the type of the lvalue ...
if (const AtomicType *Atomic = FromType->getAs<AtomicType>())
FromType = Atomic->getValueType();
@@ -1891,12 +1890,12 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
}
static bool
-IsTransparentUnionStandardConversion(Sema &S, Expr* From,
+IsTransparentUnionStandardConversion(Sema &S, Expr* From,
QualType &ToType,
bool InOverloadResolution,
StandardConversionSequence &SCS,
bool CStyle) {
-
+
const RecordType *UT = ToType->getAsUnionType();
if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
return false;
@@ -2130,7 +2129,7 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
"Invalid similarly-qualified pointer type");
/// Conversions to 'id' subsume cv-qualifier conversions.
- if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
+ if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
return ToType.getUnqualifiedType();
QualType CanonFromPointee
@@ -2140,7 +2139,7 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
if (StripObjCLifetime)
Quals.removeObjCLifetime();
-
+
// Exact qualifier match -> return the pointer type we're converting to.
if (CanonToPointee.getLocalQualifiers() == Quals) {
// ToType is exactly what we need. Return it.
@@ -2324,21 +2323,21 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
ToType, Context);
return true;
}
-
+
return false;
}
-
+
/// \brief Adopt the given qualifiers for the given type.
static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){
Qualifiers TQs = T.getQualifiers();
-
+
// Check whether qualifiers already match.
if (TQs == Qs)
return T;
-
+
if (Qs.compatiblyIncludes(TQs))
return Context.getQualifiedType(T, Qs);
-
+
return Context.getQualifiedType(T.getUnqualifiedType(), Qs);
}
@@ -2353,7 +2352,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// The set of qualifiers on the type we're converting from.
Qualifiers FromQualifiers = FromType.getQualifiers();
-
+
// First, we handle all conversions on ObjC object pointer types.
const ObjCObjectPointerType* ToObjCPtr =
ToType->getAs<ObjCObjectPointerType>();
@@ -2444,7 +2443,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ToPointeeType->getAs<ObjCObjectPointerType>() &&
isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
IncompatibleObjC)) {
-
+
ConvertedType = Context.getPointerType(ConvertedType);
ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
return true;
@@ -2527,46 +2526,46 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
/// this conversion.
bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
QualType &ConvertedType) {
- if (!getLangOpts().ObjCAutoRefCount ||
+ if (!getLangOpts().ObjCAutoRefCount ||
Context.hasSameUnqualifiedType(FromType, ToType))
return false;
-
+
// Parameter must be a pointer to __autoreleasing (with no other qualifiers).
QualType ToPointee;
if (const PointerType *ToPointer = ToType->getAs<PointerType>())
ToPointee = ToPointer->getPointeeType();
else
return false;
-
+
Qualifiers ToQuals = ToPointee.getQualifiers();
- if (!ToPointee->isObjCLifetimeType() ||
+ if (!ToPointee->isObjCLifetimeType() ||
ToQuals.getObjCLifetime() != Qualifiers::OCL_Autoreleasing ||
!ToQuals.withoutObjCLifetime().empty())
return false;
-
+
// Argument must be a pointer to __strong to __weak.
QualType FromPointee;
if (const PointerType *FromPointer = FromType->getAs<PointerType>())
FromPointee = FromPointer->getPointeeType();
else
return false;
-
+
Qualifiers FromQuals = FromPointee.getQualifiers();
if (!FromPointee->isObjCLifetimeType() ||
(FromQuals.getObjCLifetime() != Qualifiers::OCL_Strong &&
FromQuals.getObjCLifetime() != Qualifiers::OCL_Weak))
return false;
-
+
// Make sure that we have compatible qualifiers.
FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing);
if (!ToQuals.compatiblyIncludes(FromQuals))
return false;
-
+
// Remove qualifiers from the pointee type we're converting from; they
// aren't used in the compatibility check belong, and we'll be adding back
// qualifiers (with __autoreleasing) if the compatibility check succeeds.
FromPointee = FromPointee.getUnqualifiedType();
-
+
// The unqualified form of the pointee types must be compatible.
ToPointee = ToPointee.getUnqualifiedType();
bool IncompatibleObjC;
@@ -2575,7 +2574,7 @@ bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
else if (!isObjCPointerConversion(FromPointee, ToPointee, FromPointee,
IncompatibleObjC))
return false;
-
+
/// \brief Construct the type we're converting to, which is a pointer to
/// __autoreleasing pointee.
FromPointee = Context.getQualifiedType(FromPointee, FromQuals);
@@ -2591,7 +2590,7 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
ToPointeeType = ToBlockPtr->getPointeeType();
else
return false;
-
+
QualType FromPointeeType;
if (const BlockPointerType *FromBlockPtr =
FromType->getAs<BlockPointerType>())
@@ -2601,24 +2600,24 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
// We have pointer to blocks, check whether the only
// differences in the argument and result types are in Objective-C
// pointer conversions. If so, we permit the conversion.
-
+
const FunctionProtoType *FromFunctionType
= FromPointeeType->getAs<FunctionProtoType>();
const FunctionProtoType *ToFunctionType
= ToPointeeType->getAs<FunctionProtoType>();
-
+
if (!FromFunctionType || !ToFunctionType)
return false;
if (Context.hasSameType(FromPointeeType, ToPointeeType))
return true;
-
+
// Perform the quick checks that will tell us whether these
// function types are obviously different.
if (FromFunctionType->getNumParams() != ToFunctionType->getNumParams() ||
FromFunctionType->isVariadic() != ToFunctionType->isVariadic())
return false;
-
+
FunctionType::ExtInfo FromEInfo = FromFunctionType->getExtInfo();
FunctionType::ExtInfo ToEInfo = ToFunctionType->getExtInfo();
if (FromEInfo != ToEInfo)
@@ -2646,7 +2645,7 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
else
return false;
}
-
+
// Check argument types.
for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumParams();
ArgIdx != NumArgs; ++ArgIdx) {
@@ -2667,7 +2666,7 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
if (!Context.doFunctionTypesMatchOnExtParameterInfos(FromFunctionType,
ToFunctionType))
return false;
-
+
ConvertedType = ToType;
return true;
}
@@ -3013,7 +3012,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
Qualifiers ToQuals) {
// Converting anything to const __unsafe_unretained is trivial.
- if (ToQuals.hasConst() &&
+ if (ToQuals.hasConst() &&
ToQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone)
return false;
@@ -3033,7 +3032,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
FromType = Context.getCanonicalType(FromType);
ToType = Context.getCanonicalType(ToType);
ObjCLifetimeConversion = false;
-
+
// If FromType and ToType are the same type, this is not a
// qualification conversion.
if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType())
@@ -3059,7 +3058,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
// Ignore __unaligned qualifier if this type is void.
if (ToType.getUnqualifiedType()->isVoidType())
FromQuals.removeUnaligned();
-
+
// Objective-C ARC:
// Check Objective-C lifetime conversions.
if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
@@ -3075,14 +3074,14 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
return false;
}
}
-
+
// Allow addition/removal of GC attributes but not changing GC attributes.
if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
(!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
FromQuals.removeObjCGCAttr();
ToQuals.removeObjCGCAttr();
}
-
+
// -- for every j > 0, if const is in cv 1,j then const is in cv
// 2,j, and similarly for volatile.
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
@@ -3120,13 +3119,13 @@ static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType,
const AtomicType *ToAtomic = ToType->getAs<AtomicType>();
if (!ToAtomic)
return false;
-
+
StandardConversionSequence InnerSCS;
- if (!IsStandardConversion(S, From, ToAtomic->getValueType(),
+ if (!IsStandardConversion(S, From, ToAtomic->getValueType(),
InOverloadResolution, InnerSCS,
CStyle, /*AllowObjCWritebackConversion=*/false))
return false;
-
+
SCS.Second = InnerSCS.Second;
SCS.setToType(1, InnerSCS.getToType(1));
SCS.Third = InnerSCS.Third;
@@ -3181,8 +3180,8 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
bool HadMultipleCandidates = (CandidateSet.size() > 1);
OverloadCandidateSet::iterator Best;
- switch (auto Result =
- CandidateSet.BestViableFunction(S, From->getLocStart(),
+ switch (auto Result =
+ CandidateSet.BestViableFunction(S, From->getLocStart(),
Best, true)) {
case OR_Deleted:
case OR_Success: {
@@ -3553,7 +3552,7 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc,
// Two implicit conversion sequences of the same form are
// indistinguishable conversion sequences unless one of the
// following rules apply: (C++ 13.3.3.2p3):
-
+
// List-initialization sequence L1 is a better conversion sequence than
// list-initialization sequence L2 if:
// - L1 converts to std::initializer_list<X> for some X and L2 does not, or,
@@ -3588,7 +3587,7 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc,
ICS1.UserDefined.After,
ICS2.UserDefined.After);
else
- Result = compareConversionFunctions(S,
+ Result = compareConversionFunctions(S,
ICS1.UserDefined.ConversionFunction,
ICS2.UserDefined.ConversionFunction);
}
@@ -3770,9 +3769,9 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
const ObjCObjectPointerType* FromObjCPtr2
= FromType2->getAs<ObjCObjectPointerType>();
if (FromObjCPtr1 && FromObjCPtr2) {
- bool AssignLeft = S.Context.canAssignObjCInterfaces(FromObjCPtr1,
+ bool AssignLeft = S.Context.canAssignObjCInterfaces(FromObjCPtr1,
FromObjCPtr2);
- bool AssignRight = S.Context.canAssignObjCInterfaces(FromObjCPtr2,
+ bool AssignRight = S.Context.canAssignObjCInterfaces(FromObjCPtr2,
FromObjCPtr1);
if (AssignLeft != AssignRight) {
return AssignLeft? ImplicitConversionSequence::Better
@@ -3810,13 +3809,13 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
if (UnqualT1 == UnqualT2) {
// Objective-C++ ARC: If the references refer to objects with different
// lifetimes, prefer bindings that don't change lifetime.
- if (SCS1.ObjCLifetimeConversionBinding !=
+ if (SCS1.ObjCLifetimeConversionBinding !=
SCS2.ObjCLifetimeConversionBinding) {
return SCS1.ObjCLifetimeConversionBinding
? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
}
-
+
// If the type is an array type, promote the element qualifiers to the
// type for comparison.
if (isa<ArrayType>(T1) && T1Quals)
@@ -3826,7 +3825,7 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
else if (T1.isMoreQualifiedThan(T2))
- return ImplicitConversionSequence::Worse;
+ return ImplicitConversionSequence::Worse;
}
}
@@ -3892,17 +3891,17 @@ CompareQualificationConversions(Sema &S,
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
-
+
// Objective-C++ ARC:
// Prefer qualification conversions not involving a change in lifetime
// to qualification conversions that do not change lifetime.
- if (SCS1.QualificationIncludesObjCLifetime !=
+ if (SCS1.QualificationIncludesObjCLifetime !=
SCS2.QualificationIncludesObjCLifetime) {
Result = SCS1.QualificationIncludesObjCLifetime
? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
}
-
+
while (S.Context.UnwrapSimilarPointerTypes(T1, T2)) {
// Within each iteration of the loop, we check the qualifiers to
// determine if this still looks like a qualification
@@ -4034,7 +4033,7 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
= ToType1->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType *ToPtr2
= ToType2->getAs<ObjCObjectPointerType>();
-
+
if (FromPtr1 && FromPtr2 && ToPtr1 && ToPtr2) {
// Apply the same conversion ranking rules for Objective-C pointer types
// that we do for C++ pointers to class types. However, we employ the
@@ -4048,8 +4047,8 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
= S.Context.canAssignObjCInterfaces(ToPtr1, ToPtr2);
bool ToAssignRight
= S.Context.canAssignObjCInterfaces(ToPtr2, ToPtr1);
-
- // A conversion to an a non-id object pointer type or qualified 'id'
+
+ // A conversion to an a non-id object pointer type or qualified 'id'
// type is better than a conversion to 'id'.
if (ToPtr1->isObjCIdType() &&
(ToPtr2->isObjCQualifiedIdType() || ToPtr2->getInterfaceDecl()))
@@ -4057,15 +4056,15 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
if (ToPtr2->isObjCIdType() &&
(ToPtr1->isObjCQualifiedIdType() || ToPtr1->getInterfaceDecl()))
return ImplicitConversionSequence::Better;
-
- // A conversion to a non-id object pointer type is better than a
- // conversion to a qualified 'id' type
+
+ // A conversion to a non-id object pointer type is better than a
+ // conversion to a qualified 'id' type
if (ToPtr1->isObjCQualifiedIdType() && ToPtr2->getInterfaceDecl())
return ImplicitConversionSequence::Worse;
if (ToPtr2->isObjCQualifiedIdType() && ToPtr1->getInterfaceDecl())
return ImplicitConversionSequence::Better;
-
- // A conversion to an a non-Class object pointer type or qualified 'Class'
+
+ // A conversion to an a non-Class object pointer type or qualified 'Class'
// type is better than a conversion to 'Class'.
if (ToPtr1->isObjCClassType() &&
(ToPtr2->isObjCQualifiedClassType() || ToPtr2->getInterfaceDecl()))
@@ -4073,8 +4072,8 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
if (ToPtr2->isObjCClassType() &&
(ToPtr1->isObjCQualifiedClassType() || ToPtr1->getInterfaceDecl()))
return ImplicitConversionSequence::Better;
-
- // A conversion to a non-Class object pointer type is better than a
+
+ // A conversion to a non-Class object pointer type is better than a
// conversion to a qualified 'Class' type.
if (ToPtr1->isObjCQualifiedClassType() && ToPtr2->getInterfaceDecl())
return ImplicitConversionSequence::Worse;
@@ -4082,11 +4081,25 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
return ImplicitConversionSequence::Better;
// -- "conversion of C* to B* is better than conversion of C* to A*,"
- if (S.Context.hasSameType(FromType1, FromType2) &&
+ if (S.Context.hasSameType(FromType1, FromType2) &&
!FromPtr1->isObjCIdType() && !FromPtr1->isObjCClassType() &&
- (ToAssignLeft != ToAssignRight))
+ (ToAssignLeft != ToAssignRight)) {
+ if (FromPtr1->isSpecialized()) {
+ // "conversion of B<A> * to B * is better than conversion of B * to
+ // C *.
+ bool IsFirstSame =
+ FromPtr1->getInterfaceDecl() == ToPtr1->getInterfaceDecl();
+ bool IsSecondSame =
+ FromPtr1->getInterfaceDecl() == ToPtr2->getInterfaceDecl();
+ if (IsFirstSame) {
+ if (!IsSecondSame)
+ return ImplicitConversionSequence::Better;
+ } else if (IsSecondSame)
+ return ImplicitConversionSequence::Worse;
+ }
return ToAssignLeft? ImplicitConversionSequence::Worse
: ImplicitConversionSequence::Better;
+ }
// -- "conversion of B* to A* is better than conversion of C* to A*,"
if (S.Context.hasSameUnqualifiedType(ToType1, ToType2) &&
@@ -4095,7 +4108,7 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
: ImplicitConversionSequence::Worse;
}
}
-
+
// Ranking of member-pointer types.
if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member &&
FromType1->isMemberPointerType() && FromType2->isMemberPointerType() &&
@@ -4251,9 +4264,9 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
ObjCLifetimeConversion = true;
T1Quals.removeObjCLifetime();
- T2Quals.removeObjCLifetime();
+ T2Quals.removeObjCLifetime();
}
-
+
// MS compiler ignores __unaligned qualifier for references; do the same.
T1Quals.removeUnaligned();
T2Quals.removeUnaligned();
@@ -4264,7 +4277,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
return Ref_Related;
}
-/// \brief Look for a user-defined conversion to an value reference-compatible
+/// \brief Look for a user-defined conversion to a value reference-compatible
/// with DeclType. Return true if something definite is found.
static bool
FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
@@ -4300,7 +4313,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
-
+
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
if (!ConvTemplate && DeclType->isRValueReferenceType()) {
@@ -4309,7 +4322,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (RefType && !RefType->getPointeeType()->isFunctionType())
continue;
}
-
+
if (!ConvTemplate &&
S.CompareReferenceRelationship(
DeclLoc,
@@ -5888,7 +5901,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
return;
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
// Add this candidate
OverloadCandidate &Candidate =
@@ -6037,24 +6051,24 @@ Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance,
NumNamedArgs = Method->param_size();
if (Args.size() < NumNamedArgs)
continue;
-
+
for (unsigned i = 0; i < NumNamedArgs; i++) {
// We can't do any type-checking on a type-dependent argument.
if (Args[i]->isTypeDependent()) {
Match = false;
break;
}
-
+
ParmVarDecl *param = Method->parameters()[i];
Expr *argExpr = Args[i];
assert(argExpr && "SelectBestMethod(): missing expression");
-
+
// Strip the unbridged-cast placeholder expression off unless it's
// a consumed argument.
if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) &&
!param->hasAttr<CFConsumedAttr>())
argExpr = stripARCUnbridgedCast(argExpr);
-
+
// If the parameter is __unknown_anytype, move on to the next method.
if (param->getType() == Context.UnknownAnyTy) {
Match = false;
@@ -6228,11 +6242,11 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
}
template <typename CheckFn>
-static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const FunctionDecl *FD,
+static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const NamedDecl *ND,
bool ArgDependent, SourceLocation Loc,
CheckFn &&IsSuccessful) {
SmallVector<const DiagnoseIfAttr *, 8> Attrs;
- for (const auto *DIA : FD->specific_attrs<DiagnoseIfAttr>()) {
+ for (const auto *DIA : ND->specific_attrs<DiagnoseIfAttr>()) {
if (ArgDependent == DIA->getArgDependent())
Attrs.push_back(DIA);
}
@@ -6279,16 +6293,16 @@ bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
// EvaluateWithSubstitution only cares about the position of each
// argument in the arg list, not the ParmVarDecl* it maps to.
if (!DIA->getCond()->EvaluateWithSubstitution(
- Result, Context, DIA->getParent(), Args, ThisArg))
+ Result, Context, cast<FunctionDecl>(DIA->getParent()), Args, ThisArg))
return false;
return Result.isInt() && Result.getInt().getBoolValue();
});
}
-bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
+bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND,
SourceLocation Loc) {
return diagnoseDiagnoseIfAttrsWith(
- *this, Function, /*ArgDependent=*/false, Loc,
+ *this, ND, /*ArgDependent=*/false, Loc,
[&](const DiagnoseIfAttr *DIA) {
bool Result;
return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) &&
@@ -6307,30 +6321,45 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
NamedDecl *D = F.getDecl()->getUnderlyingDecl();
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
+ if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) {
+ QualType ObjectType;
+ Expr::Classification ObjectClassification;
+ if (Expr *E = Args[0]) {
+ // Use the explit base to restrict the lookup:
+ ObjectType = E->getType();
+ ObjectClassification = E->Classify(Context);
+ } // .. else there is an implit base.
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
- cast<CXXMethodDecl>(FD)->getParent(),
- Args[0]->getType(), Args[0]->Classify(Context),
- Args.slice(1), CandidateSet, SuppressUserConversions,
- PartialOverloading);
- else
+ cast<CXXMethodDecl>(FD)->getParent(), ObjectType,
+ ObjectClassification, Args.slice(1), CandidateSet,
+ SuppressUserConversions, PartialOverloading);
+ } else {
AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
SuppressUserConversions, PartialOverloading);
+ }
} else {
FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(D);
if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
- !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic())
+ !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic()) {
+ QualType ObjectType;
+ Expr::Classification ObjectClassification;
+ if (Expr *E = Args[0]) {
+ // Use the explit base to restrict the lookup:
+ ObjectType = E->getType();
+ ObjectClassification = E->Classify(Context);
+ } // .. else there is an implit base.
AddMethodTemplateCandidate(
FunTmpl, F.getPair(),
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
- ExplicitTemplateArgs, Args[0]->getType(),
- Args[0]->Classify(Context), Args.slice(1), CandidateSet,
- SuppressUserConversions, PartialOverloading);
- else
+ ExplicitTemplateArgs, ObjectType, ObjectClassification,
+ Args.slice(1), CandidateSet, SuppressUserConversions,
+ PartialOverloading);
+ } else {
AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
ExplicitTemplateArgs, Args,
CandidateSet, SuppressUserConversions,
PartialOverloading);
+ }
}
}
}
@@ -6396,7 +6425,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
return;
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
// Add this candidate
OverloadCandidate &Candidate =
@@ -6652,7 +6682,8 @@ bool Sema::CheckNonDependentConversions(
CandidateSet.allocateConversionSequences(ThisConversions + Args.size());
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
// For a method call, check the 'this' conversion here too. DR1391 doesn't
// require that, but this check should never result in a hard error, and
@@ -6723,7 +6754,7 @@ static bool isAllowableExplicitConversion(Sema &S,
return S.isObjCPointerConversion(ConvType, ToNonRefType, ConvertedType,
IncompatibleObjC);
}
-
+
/// AddConversionCandidate - Add a C++ conversion function as a
/// candidate in the candidate set (C++ [over.match.conv],
/// C++ [over.match.copy]). From is the expression we're converting from,
@@ -6754,13 +6785,14 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
// operator is only a candidate if its return type is the target type or
// can be converted to the target type with a qualification conversion.
- if (Conversion->isExplicit() &&
- !isAllowableExplicitConversion(*this, ConvType, ToType,
+ if (Conversion->isExplicit() &&
+ !isAllowableExplicitConversion(*this, ConvType, ToType,
AllowObjCConversionOnExplicit))
return;
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
// Add this candidate
OverloadCandidate &Candidate = CandidateSet.addCandidate(1);
@@ -6951,7 +6983,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
return;
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size() + 1);
Candidate.FoundDecl = FoundDecl;
@@ -7103,13 +7136,13 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
/// operator. NumContextualBoolArguments is the number of arguments
/// (at the beginning of the argument list) that will be contextually
/// converted to bool.
-void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
- ArrayRef<Expr *> Args,
+void Sema::AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator,
unsigned NumContextualBoolArguments) {
// Overload resolution is always an unevaluated context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
// Add this candidate
OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
@@ -7117,9 +7150,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Candidate.Function = nullptr;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
- Candidate.BuiltinTypes.ResultTy = ResultTy;
- for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx)
- Candidate.BuiltinTypes.ParamTypes[ArgIdx] = ParamTys[ArgIdx];
+ std::copy(ParamTys, ParamTys + Args.size(), Candidate.BuiltinParamTypes);
// Determine the implicit conversion sequences for each of the
// arguments.
@@ -7196,7 +7227,7 @@ class BuiltinCandidateTypeSet {
/// \brief A flag indicating whether the nullptr type was present in the
/// candidate set.
bool HasNullPtrType;
-
+
/// Sema - The semantic analysis instance where we are building the
/// candidate type set.
Sema &SemaRef;
@@ -7280,14 +7311,14 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
} else {
PointeeTy = PointerTy->getPointeeType();
}
-
+
// Don't add qualified variants of arrays. For one, they're not allowed
// (the qualifier would sink to the element type), and for another, the
// only overload situation where it matters is subscript or pointer +- int,
// and those shouldn't have qualifier variants anyway.
if (PointeeTy->isArrayType())
return true;
-
+
unsigned BaseCVR = PointeeTy.getCVRQualifiers();
bool hasVolatile = VisibleQuals.hasVolatile();
bool hasRestrict = VisibleQuals.hasRestrict();
@@ -7297,24 +7328,24 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
if ((CVR | BaseCVR) != CVR) continue;
// Skip over volatile if no volatile found anywhere in the types.
if ((CVR & Qualifiers::Volatile) && !hasVolatile) continue;
-
+
// Skip over restrict if no restrict found anywhere in the types, or if
// the type cannot be restrict-qualified.
if ((CVR & Qualifiers::Restrict) &&
(!hasRestrict ||
(!(PointeeTy->isAnyPointerType() || PointeeTy->isReferenceType()))))
continue;
-
+
// Build qualified pointee type.
QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR);
-
+
// Build qualified pointer type.
QualType QPointerTy;
if (!buildObjCPtr)
QPointerTy = Context.getPointerType(QPointeeTy);
else
QPointerTy = Context.getObjCObjectPointerType(QPointeeTy);
-
+
// Insert qualified pointer type.
PointerTypes.insert(QPointerTy);
}
@@ -7458,7 +7489,7 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S,
// T& operator=(T&, T)
ParamTypes[0] = S.Context.getLValueReferenceType(T);
ParamTypes[1] = T;
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/true);
if (!S.Context.getCanonicalType(T).isVolatileQualified()) {
@@ -7466,7 +7497,7 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S,
ParamTypes[0]
= S.Context.getLValueReferenceType(S.Context.getVolatileType(T));
ParamTypes[1] = T;
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/true);
}
}
@@ -7586,64 +7617,6 @@ class BuiltinOperatorOverloadBuilder {
return S.Context.*ArithmeticTypes[index];
}
- /// \brief Gets the canonical type resulting from the usual arithemetic
- /// converions for the given arithmetic types.
- CanQualType getUsualArithmeticConversions(unsigned L, unsigned R) {
- // Accelerator table for performing the usual arithmetic conversions.
- // The rules are basically:
- // - if either is floating-point, use the wider floating-point
- // - if same signedness, use the higher rank
- // - if same size, use unsigned of the higher rank
- // - use the larger type
- // These rules, together with the axiom that higher ranks are
- // never smaller, are sufficient to precompute all of these results
- // *except* when dealing with signed types of higher rank.
- // (we could precompute SLL x UI for all known platforms, but it's
- // better not to make any assumptions).
- // We assume that int128 has a higher rank than long long on all platforms.
- enum PromotedType : int8_t {
- Dep=-1,
- Flt, Dbl, LDbl, SI, SL, SLL, S128, UI, UL, ULL, U128
- };
- static const PromotedType ConversionsTable[LastPromotedArithmeticType]
- [LastPromotedArithmeticType] = {
-/* Flt*/ { Flt, Dbl, LDbl, Flt, Flt, Flt, Flt, Flt, Flt, Flt, Flt },
-/* Dbl*/ { Dbl, Dbl, LDbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl },
-/*LDbl*/ { LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl },
-/* SI*/ { Flt, Dbl, LDbl, SI, SL, SLL, S128, UI, UL, ULL, U128 },
-/* SL*/ { Flt, Dbl, LDbl, SL, SL, SLL, S128, Dep, UL, ULL, U128 },
-/* SLL*/ { Flt, Dbl, LDbl, SLL, SLL, SLL, S128, Dep, Dep, ULL, U128 },
-/*S128*/ { Flt, Dbl, LDbl, S128, S128, S128, S128, S128, S128, S128, U128 },
-/* UI*/ { Flt, Dbl, LDbl, UI, Dep, Dep, S128, UI, UL, ULL, U128 },
-/* UL*/ { Flt, Dbl, LDbl, UL, UL, Dep, S128, UL, UL, ULL, U128 },
-/* ULL*/ { Flt, Dbl, LDbl, ULL, ULL, ULL, S128, ULL, ULL, ULL, U128 },
-/*U128*/ { Flt, Dbl, LDbl, U128, U128, U128, U128, U128, U128, U128, U128 },
- };
-
- assert(L < LastPromotedArithmeticType);
- assert(R < LastPromotedArithmeticType);
- int Idx = ConversionsTable[L][R];
-
- // Fast path: the table gives us a concrete answer.
- if (Idx != Dep) return getArithmeticType(Idx);
-
- // Slow path: we need to compare widths.
- // An invariant is that the signed type has higher rank.
- CanQualType LT = getArithmeticType(L),
- RT = getArithmeticType(R);
- unsigned LW = S.Context.getIntWidth(LT),
- RW = S.Context.getIntWidth(RT);
-
- // If they're different widths, use the signed type.
- if (LW > RW) return LT;
- else if (LW < RW) return RT;
-
- // Otherwise, use the unsigned type of the signed type's rank.
- if (L == SL || R == SL) return S.Context.UnsignedLongTy;
- assert(L == SLL || R == SLL);
- return S.Context.UnsignedLongLongTy;
- }
-
/// \brief Helper method to factor out the common pattern of adding overloads
/// for '++' and '--' builtin operators.
void addPlusPlusMinusMinusStyleOverloads(QualType CandidateTy,
@@ -7655,10 +7628,7 @@ class BuiltinOperatorOverloadBuilder {
};
// Non-volatile version.
- if (Args.size() == 1)
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
- else
- S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
// Use a heuristic to reduce number of builtin candidates in the set:
// add volatile version only if there are conversions to a volatile type.
@@ -7666,12 +7636,9 @@ class BuiltinOperatorOverloadBuilder {
ParamTypes[0] =
S.Context.getLValueReferenceType(
S.Context.getVolatileType(CandidateTy));
- if (Args.size() == 1)
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
- else
- S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
-
+
// Add restrict version only if there are conversions to a restrict type
// and our candidate type is a non-restrict-qualified pointer.
if (HasRestrict && CandidateTy->isAnyPointerType() &&
@@ -7679,21 +7646,15 @@ class BuiltinOperatorOverloadBuilder {
ParamTypes[0]
= S.Context.getLValueReferenceType(
S.Context.getCVRQualifiedType(CandidateTy, Qualifiers::Restrict));
- if (Args.size() == 1)
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
- else
- S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet);
-
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
+
if (HasVolatile) {
ParamTypes[0]
= S.Context.getLValueReferenceType(
S.Context.getCVRQualifiedType(CandidateTy,
(Qualifiers::Volatile |
Qualifiers::Restrict)));
- if (Args.size() == 1)
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
- else
- S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
@@ -7807,8 +7768,7 @@ public:
if (Proto->getTypeQuals() || Proto->getRefQualifier())
continue;
- S.AddBuiltinCandidate(S.Context.getLValueReferenceType(PointeeTy),
- &ParamTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet);
}
}
@@ -7825,7 +7785,7 @@ public:
for (unsigned Arith = FirstPromotedArithmeticType;
Arith < LastPromotedArithmeticType; ++Arith) {
QualType ArithTy = getArithmeticType(Arith);
- S.AddBuiltinCandidate(ArithTy, &ArithTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&ArithTy, Args, CandidateSet);
}
// Extension: We also add these operators for vector types.
@@ -7834,7 +7794,7 @@ public:
VecEnd = CandidateTypes[0].vector_end();
Vec != VecEnd; ++Vec) {
QualType VecTy = *Vec;
- S.AddBuiltinCandidate(VecTy, &VecTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&VecTy, Args, CandidateSet);
}
}
@@ -7849,7 +7809,7 @@ public:
PtrEnd = CandidateTypes[0].pointer_end();
Ptr != PtrEnd; ++Ptr) {
QualType ParamTy = *Ptr;
- S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet);
}
}
@@ -7865,7 +7825,7 @@ public:
for (unsigned Int = FirstPromotedIntegralType;
Int < LastPromotedIntegralType; ++Int) {
QualType IntTy = getArithmeticType(Int);
- S.AddBuiltinCandidate(IntTy, &IntTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&IntTy, Args, CandidateSet);
}
// Extension: We also add this operator for vector types.
@@ -7874,7 +7834,7 @@ public:
VecEnd = CandidateTypes[0].vector_end();
Vec != VecEnd; ++Vec) {
QualType VecTy = *Vec;
- S.AddBuiltinCandidate(VecTy, &VecTy, Args, CandidateSet);
+ S.AddBuiltinCandidate(&VecTy, Args, CandidateSet);
}
}
@@ -7899,15 +7859,14 @@ public:
continue;
QualType ParamTypes[2] = { *MemPtr, *MemPtr };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
if (CandidateTypes[ArgIdx].hasNullPtrType()) {
CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy);
if (AddedTypes.insert(NullPtrTy).second) {
QualType ParamTypes[2] = { NullPtrTy, NullPtrTy };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args,
- CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -7983,7 +7942,7 @@ public:
continue;
QualType ParamTypes[2] = { *Ptr, *Ptr };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
for (BuiltinCandidateTypeSet::iterator
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
@@ -7999,7 +7958,7 @@ public:
continue;
QualType ParamTypes[2] = { *Enum, *Enum };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8042,7 +8001,7 @@ public:
if (Arg == 0 || Op == OO_Plus) {
// operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t)
// T* operator+(ptrdiff_t, T*);
- S.AddBuiltinCandidate(*Ptr, AsymmetricParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(AsymmetricParamTypes, Args, CandidateSet);
}
if (Op == OO_Minus) {
// ptrdiff_t operator-(T, T);
@@ -8050,8 +8009,7 @@ public:
continue;
QualType ParamTypes[2] = { *Ptr, *Ptr };
- S.AddBuiltinCandidate(S.Context.getPointerDiffType(), ParamTypes,
- Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8086,7 +8044,7 @@ public:
// where LR is the result of the usual arithmetic conversions
// between types L and R.
// Our candidates ignore the first parameter.
- void addGenericBinaryArithmeticOverloads(bool isComparison) {
+ void addGenericBinaryArithmeticOverloads() {
if (!HasArithmeticOrEnumeralCandidateType)
return;
@@ -8096,10 +8054,7 @@ public:
Right < LastPromotedArithmeticType; ++Right) {
QualType LandR[2] = { getArithmeticType(Left),
getArithmeticType(Right) };
- QualType Result =
- isComparison ? S.Context.BoolTy
- : getUsualArithmeticConversions(Left, Right);
- S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet);
+ S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
@@ -8114,15 +8069,7 @@ public:
Vec2End = CandidateTypes[1].vector_end();
Vec2 != Vec2End; ++Vec2) {
QualType LandR[2] = { *Vec1, *Vec2 };
- QualType Result = S.Context.BoolTy;
- if (!isComparison) {
- if ((*Vec1)->isExtVectorType() || !(*Vec2)->isExtVectorType())
- Result = *Vec1;
- else
- Result = *Vec2;
- }
-
- S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet);
+ S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
}
@@ -8151,10 +8098,7 @@ public:
Right < LastPromotedIntegralType; ++Right) {
QualType LandR[2] = { getArithmeticType(Left),
getArithmeticType(Right) };
- QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater)
- ? LandR[0]
- : getUsualArithmeticConversions(Left, Right);
- S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet);
+ S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
}
}
@@ -8228,7 +8172,7 @@ public:
S.Context.getLValueReferenceType(*Ptr),
isEqualOp ? *Ptr : S.Context.getPointerDiffType(),
};
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/ isEqualOp);
bool NeedVolatile = !(*Ptr).isVolatileQualified() &&
@@ -8237,18 +8181,18 @@ public:
// volatile version
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
}
-
+
if (!(*Ptr).isRestrictQualified() &&
VisibleTypeConversionsQuals.hasRestrict()) {
// restrict version
ParamTypes[0]
= S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
-
+
if (NeedVolatile) {
// volatile restrict version
ParamTypes[0]
@@ -8256,7 +8200,7 @@ public:
S.Context.getCVRQualifiedType(*Ptr,
(Qualifiers::Volatile |
Qualifiers::Restrict)));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
}
}
@@ -8277,7 +8221,7 @@ public:
};
// non-volatile version
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/true);
bool NeedVolatile = !(*Ptr).isVolatileQualified() &&
@@ -8286,18 +8230,18 @@ public:
// volatile version
ParamTypes[0] =
S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/true);
}
-
+
if (!(*Ptr).isRestrictQualified() &&
VisibleTypeConversionsQuals.hasRestrict()) {
// restrict version
ParamTypes[0]
= S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/true);
-
+
if (NeedVolatile) {
// volatile restrict version
ParamTypes[0]
@@ -8305,7 +8249,7 @@ public:
S.Context.getCVRQualifiedType(*Ptr,
(Qualifiers::Volatile |
Qualifiers::Restrict)));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/true);
}
}
@@ -8338,7 +8282,7 @@ public:
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] =
S.Context.getLValueReferenceType(getArithmeticType(Left));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
// Add this built-in operator as a candidate (VQ is 'volatile').
@@ -8346,7 +8290,7 @@ public:
ParamTypes[0] =
S.Context.getVolatileType(getArithmeticType(Left));
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
}
}
@@ -8365,14 +8309,14 @@ public:
ParamTypes[1] = *Vec2;
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] = S.Context.getLValueReferenceType(*Vec1);
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
// Add this built-in operator as a candidate (VQ is 'volatile').
if (VisibleTypeConversionsQuals.hasVolatile()) {
ParamTypes[0] = S.Context.getVolatileType(*Vec1);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssigmentOperator=*/isEqualOp);
}
}
@@ -8404,13 +8348,13 @@ public:
// Add this built-in operator as a candidate (VQ is empty).
ParamTypes[0] =
S.Context.getLValueReferenceType(getArithmeticType(Left));
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
if (VisibleTypeConversionsQuals.hasVolatile()) {
// Add this built-in operator as a candidate (VQ is 'volatile').
ParamTypes[0] = getArithmeticType(Left);
ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
- S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8425,13 +8369,13 @@ public:
// bool operator||(bool, bool);
void addExclaimOverload() {
QualType ParamTy = S.Context.BoolTy;
- S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, CandidateSet,
+ S.AddBuiltinCandidate(&ParamTy, Args, CandidateSet,
/*IsAssignmentOperator=*/false,
/*NumContextualBoolArguments=*/1);
}
void addAmpAmpOrPipePipeOverload() {
QualType ParamTypes[2] = { S.Context.BoolTy, S.Context.BoolTy };
- S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet,
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/false,
/*NumContextualBoolArguments=*/2);
}
@@ -8456,10 +8400,8 @@ public:
if (!PointeeType->isObjectType())
continue;
- QualType ResultTy = S.Context.getLValueReferenceType(PointeeType);
-
// T& operator[](T*, ptrdiff_t)
- S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
for (BuiltinCandidateTypeSet::iterator
@@ -8471,10 +8413,8 @@ public:
if (!PointeeType->isObjectType())
continue;
- QualType ResultTy = S.Context.getLValueReferenceType(PointeeType);
-
// T& operator[](ptrdiff_t, T*)
- S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
@@ -8524,8 +8464,7 @@ public:
T.isRestrictQualified())
continue;
T = Q1.apply(S.Context, T);
- QualType ResultTy = S.Context.getLValueReferenceType(T);
- S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8553,7 +8492,7 @@ public:
continue;
QualType ParamTypes[2] = { *Ptr, *Ptr };
- S.AddBuiltinCandidate(*Ptr, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
for (BuiltinCandidateTypeSet::iterator
@@ -8564,7 +8503,7 @@ public:
continue;
QualType ParamTypes[2] = { *MemPtr, *MemPtr };
- S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
if (S.getLangOpts().CPlusPlus11) {
@@ -8579,7 +8518,7 @@ public:
continue;
QualType ParamTypes[2] = { *Enum, *Enum };
- S.AddBuiltinCandidate(*Enum, ParamTypes, Args, CandidateSet);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
}
}
}
@@ -8673,7 +8612,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
OpBuilder.addUnaryPlusOrMinusArithmeticOverloads();
} else {
OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op);
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
}
break;
@@ -8681,11 +8620,11 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
if (Args.size() == 1)
OpBuilder.addUnaryStarPointerOverloads();
else
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
break;
case OO_Slash:
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
break;
case OO_PlusPlus:
@@ -8704,7 +8643,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
case OO_LessEqual:
case OO_GreaterEqual:
OpBuilder.addRelationalPointerOrEnumeralOverloads();
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/true);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
break;
case OO_Percent:
@@ -8771,7 +8710,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
case OO_Conditional:
OpBuilder.addConditionalOperatorOverloads();
- OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false);
+ OpBuilder.addGenericBinaryArithmeticOverloads();
break;
}
}
@@ -8991,6 +8930,12 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
// C++14 [over.match.best]p1 section 2 bullet 3.
}
+ // -- F1 is generated from a deduction-guide and F2 is not
+ auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
+ auto *Guide2 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand2.Function);
+ if (Guide1 && Guide2 && Guide1->isImplicit() != Guide2->isImplicit())
+ return Guide2->isImplicit();
+
// -- F1 is a non-template function and F2 is a function template
// specialization, or, if not that,
bool Cand1IsSpecialization = Cand1.Function &&
@@ -9384,13 +9329,13 @@ void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType,
OverloadExpr *OvlExpr = Ovl.Expression;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
- IEnd = OvlExpr->decls_end();
+ IEnd = OvlExpr->decls_end();
I != IEnd; ++I) {
- if (FunctionTemplateDecl *FunTmpl =
+ if (FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {
NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), DestType,
TakingAddress);
- } else if (FunctionDecl *Fun
+ } else if (FunctionDecl *Fun
= dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {
NoteOverloadCandidate(*I, Fun, DestType, TakingAddress);
}
@@ -9488,7 +9433,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy
- << FromQs.getAddressSpace() << ToQs.getAddressSpace()
+ << FromQs.getAddressSpaceAttributePrintValue()
+ << ToQs.getAddressSpaceAttributePrintValue()
<< (unsigned) isObjectArgument << I+1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
@@ -9567,7 +9513,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << ToTy << (unsigned) isObjectArgument << I+1
<< (unsigned) (Cand->Fix.Kind);
-
+
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9670,7 +9616,7 @@ static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
// right number of arguments, because only overloaded operators have
// the weird behavior of overloading member and non-member functions.
// Just don't report anything.
- if (Fn->isInvalidDecl() &&
+ if (Fn->isInvalidDecl() &&
Fn->getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
return true;
@@ -9694,9 +9640,9 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
"The templated declaration should at least be a function"
" when diagnosing bad template argument deduction due to too many"
" or too few arguments");
-
+
FunctionDecl *Fn = cast<FunctionDecl>(D);
-
+
// TODO: treat calls to a missing default constructor as a special case
const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>();
unsigned MinParams = Fn->getMinRequiredArguments();
@@ -9884,6 +9830,15 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
return;
}
+ // We found a specific requirement that disabled the enable_if.
+ if (PDiag && PDiag->second.getDiagID() ==
+ diag::err_typename_nested_not_found_requirement) {
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_disabled_by_requirement)
+ << PDiag->second.getStringArg(0) << TemplateArgString;
+ return;
+ }
+
// Format the SFINAE diagnostic into the argument string.
// FIXME: Add a general mechanism to include a PartialDiagnostic *'s
// formatted message in another diagnostic.
@@ -9952,8 +9907,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
return;
// FIXME: For generic lambda parameters, check if the function is a lambda
- // call operator, and if so, emit a prettier and more informative
- // diagnostic that mentions 'auto' and lambda in addition to
+ // call operator, and if so, emit a prettier and more informative
+ // diagnostic that mentions 'auto' and lambda in addition to
// (or instead of?) the canonical template type parameters.
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_non_deduced_mismatch)
@@ -10196,13 +10151,13 @@ static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
std::string TypeStr("operator");
TypeStr += Opc;
TypeStr += "(";
- TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
+ TypeStr += Cand->BuiltinParamTypes[0].getAsString();
if (Cand->Conversions.size() == 1) {
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
} else {
TypeStr += ", ";
- TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString();
+ TypeStr += Cand->BuiltinParamTypes[1].getAsString();
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_binary_candidate) << TypeStr;
}
@@ -10439,7 +10394,7 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
} else {
// Builtin operator.
assert(ConvCount <= 3);
- ParamTypes = Cand->BuiltinTypes.ParamTypes;
+ ParamTypes = Cand->BuiltinParamTypes;
}
// Fill in the rest of the conversions.
@@ -10651,16 +10606,16 @@ void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) {
// R (S::*)(A) --> R (A)
QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) {
QualType Ret = PossiblyAFunctionType;
- if (const PointerType *ToTypePtr =
+ if (const PointerType *ToTypePtr =
PossiblyAFunctionType->getAs<PointerType>())
Ret = ToTypePtr->getPointeeType();
- else if (const ReferenceType *ToTypeRef =
+ else if (const ReferenceType *ToTypeRef =
PossiblyAFunctionType->getAs<ReferenceType>())
Ret = ToTypeRef->getPointeeType();
else if (const MemberPointerType *MemTypePtr =
- PossiblyAFunctionType->getAs<MemberPointerType>())
- Ret = MemTypePtr->getPointeeType();
- Ret =
+ PossiblyAFunctionType->getAs<MemberPointerType>())
+ Ret = MemTypePtr->getPointeeType();
+ Ret =
Context.getCanonicalType(Ret).getUnqualifiedType();
return Ret;
}
@@ -10686,9 +10641,9 @@ namespace {
class AddressOfFunctionResolver {
Sema& S;
Expr* SourceExpr;
- const QualType& TargetType;
- QualType TargetFunctionType; // Extracted function type from target type
-
+ const QualType& TargetType;
+ QualType TargetFunctionType; // Extracted function type from target type
+
bool Complain;
//DeclAccessPair& ResultFunctionAccessPair;
ASTContext& Context;
@@ -10698,7 +10653,7 @@ class AddressOfFunctionResolver {
bool StaticMemberFunctionFromBoundPointer;
bool HasComplained;
- OverloadExpr::FindResult OvlExprInfo;
+ OverloadExpr::FindResult OvlExprInfo;
OverloadExpr *OvlExpr;
TemplateArgumentListInfo OvlExplicitTemplateArgs;
SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
@@ -10745,7 +10700,7 @@ public:
}
return;
}
-
+
if (OvlExpr->hasExplicitTemplateArgs())
OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs);
@@ -10823,7 +10778,7 @@ private:
}
// return true if any matching specializations were found
- bool AddMatchingTemplateFunction(FunctionTemplateDecl* FunctionTemplate,
+ bool AddMatchingTemplateFunction(FunctionTemplateDecl* FunctionTemplate,
const DeclAccessPair& CurAccessFunPair) {
if (CXXMethodDecl *Method
= dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl())) {
@@ -10831,7 +10786,7 @@ private:
// static when converting to member pointer.
if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction)
return false;
- }
+ }
else if (TargetTypeIsNonStaticMemberFunction)
return false;
@@ -10844,17 +10799,17 @@ private:
FunctionDecl *Specialization = nullptr;
TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (Sema::TemplateDeductionResult Result
- = S.DeduceTemplateArguments(FunctionTemplate,
+ = S.DeduceTemplateArguments(FunctionTemplate,
&OvlExplicitTemplateArgs,
- TargetFunctionType, Specialization,
+ TargetFunctionType, Specialization,
Info, /*IsAddressOfFunction*/true)) {
// Make a note of the failed deduction for diagnostics.
FailedCandidates.addCandidate()
.set(CurAccessFunPair, FunctionTemplate->getTemplatedDecl(),
MakeDeductionFailureInfo(Context, Result, Info));
return false;
- }
-
+ }
+
// Template argument deduction ensures that we have an exact match or
// compatible pointer-to-function arguments that would be adjusted by ICS.
// This function template specicalization works.
@@ -10868,15 +10823,15 @@ private:
Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
return true;
}
-
- bool AddMatchingNonTemplateFunction(NamedDecl* Fn,
+
+ bool AddMatchingNonTemplateFunction(NamedDecl* Fn,
const DeclAccessPair& CurAccessFunPair) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
// Skip non-static functions when converting to pointer, and static
// when converting to member pointer.
if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction)
return false;
- }
+ }
else if (TargetTypeIsNonStaticMemberFunction)
return false;
@@ -10906,20 +10861,20 @@ private:
return true;
}
}
-
+
return false;
}
-
+
bool FindAllFunctionsThatMatchTargetTypeExactly() {
bool Ret = false;
-
+
// If the overload expression doesn't have the form of a pointer to
// member, don't try to convert it to a pointer-to-member type.
if (IsInvalidFormOfPointerToMemberFunction())
return false;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
- E = OvlExpr->decls_end();
+ E = OvlExpr->decls_end();
I != E; ++I) {
// Look through any using declarations to find the underlying function.
NamedDecl *Fn = (*I)->getUnderlyingDecl();
@@ -11062,12 +11017,12 @@ public:
bool hadMultipleCandidates() const { return (OvlExpr->getNumDecls() > 1); }
int getNumMatches() const { return Matches.size(); }
-
+
FunctionDecl* getMatchingFunctionDecl() const {
if (Matches.size() != 1) return nullptr;
return Matches[0].second;
}
-
+
const DeclAccessPair* getMatchingFunctionAccessPair() const {
if (Matches.size() != 1) return nullptr;
return &Matches[0].first;
@@ -11169,12 +11124,12 @@ Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
/// \brief Given an overloaded function, tries to turn it into a non-overloaded
/// function reference using resolveAddressOfOnlyViableOverloadCandidate. This
/// will perform access checks, diagnose the use of the resultant decl, and, if
-/// necessary, perform a function-to-pointer decay.
+/// requested, potentially perform a function-to-pointer decay.
///
/// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails.
/// Otherwise, returns true. This may emit diagnostics and return true.
bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
- ExprResult &SrcExpr) {
+ ExprResult &SrcExpr, bool DoFunctionPointerConverion) {
Expr *E = SrcExpr.get();
assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
@@ -11189,7 +11144,7 @@ bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
DiagnoseUseOfDecl(Found, E->getExprLoc());
CheckAddressOfMemberAccess(E, DAP);
Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found);
- if (Fixed->getType()->isFunctionType())
+ if (DoFunctionPointerConverion && Fixed->getType()->isFunctionType())
SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false);
else
SrcExpr = Fixed;
@@ -11207,7 +11162,7 @@ bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
/// If no template-ids are found, no diagnostics are emitted and NULL is
/// returned.
FunctionDecl *
-Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
+Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
bool Complain,
DeclAccessPair *FoundResult) {
// C++ [over.over]p1:
@@ -11270,9 +11225,9 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
}
return nullptr;
}
-
+
Matched = Specialization;
- if (FoundResult) *FoundResult = I.getPair();
+ if (FoundResult) *FoundResult = I.getPair();
}
if (Matched &&
@@ -11295,8 +11250,8 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// returns true if 'complain' is set.
bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
ExprResult &SrcExpr, bool doFunctionPointerConverion,
- bool complain, SourceRange OpRangeForComplaining,
- QualType DestTypeForComplaining,
+ bool complain, SourceRange OpRangeForComplaining,
+ QualType DestTypeForComplaining,
unsigned DiagIDForComplaining) {
assert(SrcExpr.get()->getType() == Context.OverloadTy);
@@ -11353,7 +11308,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining)
<< ovl.Expression->getName()
<< DestTypeForComplaining
- << OpRangeForComplaining
+ << OpRangeForComplaining
<< ovl.Expression->getQualifierLoc().getSourceRange();
NoteAllOverloadCandidates(SrcExpr.get());
@@ -11385,6 +11340,10 @@ static void AddOverloadedCallCandidate(Sema &S,
assert(!KnownValid && "Explicit template arguments?");
return;
}
+ // Prevent ill-formed function decls to be added as overload candidates.
+ if (!dyn_cast<FunctionProtoType>(Func->getType()->getAs<FunctionType>()))
+ return;
+
S.AddOverloadCandidate(Func, FoundDecl, Args, CandidateSet,
/*SuppressUsedConversions=*/false,
PartialOverloading);
@@ -11485,7 +11444,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
TemplateArgumentListInfo *ExplicitTemplateArgs,
ArrayRef<Expr *> Args,
bool *DoDiagnoseEmptyLookup = nullptr) {
- if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty())
+ if (!SemaRef.inTemplateInstantiation() || !SS.isEmpty())
return false;
for (DeclContext *DC = SemaRef.CurContext; DC; DC = DC->getParent()) {
@@ -11957,7 +11916,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
Fns.begin(), Fns.end());
return new (Context)
CXXOperatorCallExpr(Context, Op, Fn, ArgsArray, Context.DependentTy,
- VK_RValue, OpLoc, false);
+ VK_RValue, OpLoc, FPOptions());
}
// Build an empty overload set.
@@ -11987,6 +11946,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
FunctionDecl *FnDecl = Best->Function;
if (FnDecl) {
+ Expr *Base = nullptr;
// We matched an overloaded operator. Build a call to that
// operator.
@@ -11999,7 +11959,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
Best->FoundDecl, Method);
if (InputRes.isInvalid())
return ExprError();
- Input = InputRes.get();
+ Base = Input = InputRes.get();
} else {
// Convert the arguments.
ExprResult InputInit
@@ -12015,7 +11975,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
// Build the actual expression node.
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl,
- HadMultipleCandidates, OpLoc);
+ Base, HadMultipleCandidates,
+ OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -12027,7 +11988,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
Args[0] = Input;
CallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(), ArgsArray,
- ResultTy, VK, OpLoc, false);
+ ResultTy, VK, OpLoc, FPOptions());
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
return ExprError();
@@ -12041,9 +12002,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
// operator node.
- ExprResult InputRes =
- PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], AA_Passing);
+ ExprResult InputRes = PerformImplicitConversion(
+ Input, Best->BuiltinParamTypes[0], Best->Conversions[0], AA_Passing);
if (InputRes.isInvalid())
return ExprError();
Input = InputRes.get();
@@ -12125,12 +12085,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Opc <= BO_Assign || Opc > BO_OrAssign)
return new (Context) BinaryOperator(
Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary,
- OpLoc, FPFeatures.fp_contract);
+ OpLoc, FPFeatures);
return new (Context) CompoundAssignOperator(
Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, OK_Ordinary,
Context.DependentTy, Context.DependentTy, OpLoc,
- FPFeatures.fp_contract);
+ FPFeatures);
}
// FIXME: save results of ADL from here?
@@ -12138,13 +12098,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// TODO: provide better source location info in DNLoc component.
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
UnresolvedLookupExpr *Fn
- = UnresolvedLookupExpr::Create(Context, NamingClass,
- NestedNameSpecifierLoc(), OpNameInfo,
+ = UnresolvedLookupExpr::Create(Context, NamingClass,
+ NestedNameSpecifierLoc(), OpNameInfo,
/*ADL*/ true, IsOverloaded(Fns),
Fns.begin(), Fns.end());
return new (Context)
CXXOperatorCallExpr(Context, Op, Fn, Args, Context.DependentTy,
- VK_RValue, OpLoc, FPFeatures.fp_contract);
+ VK_RValue, OpLoc, FPFeatures);
}
// Always do placeholder-like conversions on the RHS.
@@ -12201,6 +12161,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
FunctionDecl *FnDecl = Best->Function;
if (FnDecl) {
+ Expr *Base = nullptr;
// We matched an overloaded operator. Build a call to that
// operator.
@@ -12222,7 +12183,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Best->FoundDecl, Method);
if (Arg0.isInvalid())
return ExprError();
- Args[0] = Arg0.getAs<Expr>();
+ Base = Args[0] = Arg0.getAs<Expr>();
Args[1] = RHS = Arg1.getAs<Expr>();
} else {
// Convert the arguments.
@@ -12246,7 +12207,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Build the actual expression node.
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
- Best->FoundDecl,
+ Best->FoundDecl, Base,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -12259,7 +12220,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(),
Args, ResultTy, VK, OpLoc,
- FPFeatures.fp_contract);
+ FPFeatures);
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,
FnDecl))
@@ -12287,15 +12248,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// break out so that we will build the appropriate built-in
// operator node.
ExprResult ArgsRes0 =
- PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], AA_Passing);
+ PerformImplicitConversion(Args[0], Best->BuiltinParamTypes[0],
+ Best->Conversions[0], AA_Passing);
if (ArgsRes0.isInvalid())
return ExprError();
Args[0] = ArgsRes0.get();
ExprResult ArgsRes1 =
- PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], AA_Passing);
+ PerformImplicitConversion(Args[1], Best->BuiltinParamTypes[1],
+ Best->Conversions[1], AA_Passing);
if (ArgsRes1.isInvalid())
return ExprError();
Args[1] = ArgsRes1.get();
@@ -12407,7 +12368,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
return new (Context)
CXXOperatorCallExpr(Context, OO_Subscript, Fn, Args,
- Context.DependentTy, VK_RValue, RLoc, false);
+ Context.DependentTy, VK_RValue, RLoc, FPOptions());
}
// Handle placeholders on both operands.
@@ -12468,6 +12429,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
Best->FoundDecl,
+ Base,
HadMultipleCandidates,
OpLocInfo.getLoc(),
OpLocInfo.getInfo());
@@ -12483,7 +12445,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
FnExpr.get(), Args,
ResultTy, VK, RLoc,
- false);
+ FPOptions());
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
return ExprError();
@@ -12498,15 +12460,15 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// break out so that we will build the appropriate built-in
// operator node.
ExprResult ArgsRes0 =
- PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0],
- Best->Conversions[0], AA_Passing);
+ PerformImplicitConversion(Args[0], Best->BuiltinParamTypes[0],
+ Best->Conversions[0], AA_Passing);
if (ArgsRes0.isInvalid())
return ExprError();
Args[0] = ArgsRes0.get();
ExprResult ArgsRes1 =
- PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
- Best->Conversions[1], AA_Passing);
+ PerformImplicitConversion(Args[1], Best->BuiltinParamTypes[1],
+ Best->Conversions[1], AA_Passing);
if (ArgsRes1.isInvalid())
return ExprError();
Args[1] = ArgsRes1.get();
@@ -12702,12 +12664,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
return ExprError();
// If FoundDecl is different from Method (such as if one is a template
- // and the other a specialization), make sure DiagnoseUseOfDecl is
+ // and the other a specialization), make sure DiagnoseUseOfDecl is
// called on both.
// FIXME: This would be more comprehensively addressed by modifying
// DiagnoseUseOfDecl to accept both the FoundDecl and the decl
// being used.
- if (Method != FoundDecl.getDecl() &&
+ if (Method != FoundDecl.getDecl() &&
DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc()))
return ExprError();
break;
@@ -12730,7 +12692,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
case OR_Deleted:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
<< Best->Function->isDeleted()
- << DeclName
+ << DeclName
<< getDeletedOrUnavailableSuffix(Best->Function)
<< MemExprE->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
@@ -12803,8 +12765,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
}
}
- if ((isa<CXXConstructorDecl>(CurContext) ||
- isa<CXXDestructorDecl>(CurContext)) &&
+ if ((isa<CXXConstructorDecl>(CurContext) ||
+ isa<CXXDestructorDecl>(CurContext)) &&
TheCall->getMethodDecl()->isPure()) {
const CXXMethodDecl *MD = TheCall->getMethodDecl();
@@ -12884,7 +12846,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
}
// C++ [over.call.object]p2:
- // In addition, for each (non-explicit in C++0x) conversion function
+ // In addition, for each (non-explicit in C++0x) conversion function
// declared in T of the form
//
// operator conversion-type-id () cv-qualifier;
@@ -12963,7 +12925,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Diag(Object.get()->getLocStart(),
diag::err_ovl_deleted_object_call)
<< Best->Function->isDeleted()
- << Object.get()->getType()
+ << Object.get()->getType()
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Object.get()->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args);
@@ -12986,7 +12948,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Best->FoundDecl);
if (DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc))
return ExprError();
- assert(Conv == Best->FoundDecl.getDecl() &&
+ assert(Conv == Best->FoundDecl.getDecl() &&
"Found Decl & conversion-to-functionptr should be same, right?!");
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
@@ -13026,7 +12988,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LParenLoc, RParenLoc));
ExprResult NewFn = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
- HadMultipleCandidates,
+ Obj, HadMultipleCandidates,
OpLocInfo.getLoc(),
OpLocInfo.getInfo());
if (NewFn.isInvalid())
@@ -13046,7 +13008,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
CXXOperatorCallExpr *TheCall = new (Context)
CXXOperatorCallExpr(Context, OO_Call, NewFn.get(), MethodArgs, ResultTy,
- VK, RParenLoc, false);
+ VK, RParenLoc, FPOptions());
if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
return true;
@@ -13197,7 +13159,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
- << "->"
+ << "->"
<< getDeletedOrUnavailableSuffix(Best->Function)
<< Base->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Base);
@@ -13217,7 +13179,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
// Build the operator call.
ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
- HadMultipleCandidates, OpLoc);
+ Base, HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -13226,7 +13188,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr.get(),
- Base, ResultTy, VK, OpLoc, false);
+ Base, ResultTy, VK, OpLoc, FPOptions());
if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
return ExprError();
@@ -13276,7 +13238,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
FunctionDecl *FD = Best->Function;
ExprResult Fn = CreateFunctionRefExpr(*this, FD, Best->FoundDecl,
- HadMultipleCandidates,
+ nullptr, HadMultipleCandidates,
SuffixInfo.getLoc(),
SuffixInfo.getInfo());
if (Fn.isInvalid())
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp
index 8e53fda..d159172 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp
@@ -447,7 +447,8 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS,
opcode, capturedRHS->getType(),
capturedRHS->getValueKind(),
- OK_Ordinary, opcLoc, false);
+ OK_Ordinary, opcLoc,
+ FPOptions());
} else {
ExprResult opLHS = buildGet();
if (opLHS.isInvalid()) return ExprError();
@@ -465,7 +466,7 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
OK_Ordinary,
opLHS.get()->getType(),
result.get()->getType(),
- opcLoc, false);
+ opcLoc, FPOptions());
}
// The result of the assignment, if not void, is the value set into
@@ -841,12 +842,10 @@ ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) {
result = S.ImpCastExprToType(result.get(), propType, CK_BitCast);
}
}
- if (S.getLangOpts().ObjCAutoRefCount) {
- Qualifiers::ObjCLifetime LT = propType.getObjCLifetime();
- if (LT == Qualifiers::OCL_Weak)
- if (!S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, RefExpr->getLocation()))
- S.getCurFunction()->markSafeWeakUse(RefExpr);
- }
+ if (propType.getObjCLifetime() == Qualifiers::OCL_Weak &&
+ !S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak,
+ RefExpr->getLocation()))
+ S.getCurFunction()->markSafeWeakUse(RefExpr);
}
return result;
@@ -962,11 +961,11 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
}
ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) {
- if (S.getLangOpts().ObjCAutoRefCount && isWeakProperty() &&
+ if (isWeakProperty() &&
!S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak,
SyntacticForm->getLocStart()))
- S.recordUseOfEvaluatedWeak(SyntacticRefExpr,
- SyntacticRefExpr->isMessagingGetter());
+ S.recordUseOfEvaluatedWeak(SyntacticRefExpr,
+ SyntacticRefExpr->isMessagingGetter());
return PseudoOpBuilder::complete(SyntacticForm);
}
@@ -1127,8 +1126,8 @@ static void CheckKeyForObjCARCConversion(Sema &S, QualType ContainerT,
if (!Getter)
return;
QualType T = Getter->parameters()[0]->getType();
- S.CheckObjCARCConversion(Key->getSourceRange(),
- T, Key, Sema::CCK_ImplicitConversion);
+ S.CheckObjCConversion(Key->getSourceRange(), T, Key,
+ Sema::CCK_ImplicitConversion);
}
bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
@@ -1177,8 +1176,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
AtIndexGetter = S.LookupMethodInObjectType(AtIndexGetterSelector, ResultType,
true /*instance*/);
- bool receiverIdType = (BaseT->isObjCIdType() ||
- BaseT->isObjCQualifiedIdType());
if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) {
AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(),
@@ -1204,7 +1201,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
}
if (!AtIndexGetter) {
- if (!receiverIdType) {
+ if (!BaseT->isObjCIdType()) {
S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found)
<< BaseExpr->getType() << 0 << arrayRef;
return false;
@@ -1285,9 +1282,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
}
AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType,
true /*instance*/);
-
- bool receiverIdType = (BaseT->isObjCIdType() ||
- BaseT->isObjCQualifiedIdType());
if (!AtIndexSetter && S.getLangOpts().DebuggerObjCLiteral) {
TypeSourceInfo *ReturnTInfo = nullptr;
@@ -1322,7 +1316,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
}
if (!AtIndexSetter) {
- if (!receiverIdType) {
+ if (!BaseT->isObjCIdType()) {
S.Diag(BaseExpr->getExprLoc(),
diag::err_objc_subscript_method_not_found)
<< BaseExpr->getType() << 1 << arrayRef;
@@ -1587,7 +1581,8 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
// Do nothing if either argument is dependent.
if (LHS->isTypeDependent() || RHS->isTypeDependent())
return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,
- VK_RValue, OK_Ordinary, opcLoc, false);
+ VK_RValue, OK_Ordinary, opcLoc,
+ FPOptions());
// Filter out non-overload placeholder types in the RHS.
if (RHS->getType()->isNonOverloadPlaceholderType()) {
@@ -1652,14 +1647,15 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
cop->getObjectKind(),
cop->getComputationLHSType(),
cop->getComputationResultType(),
- cop->getOperatorLoc(), false);
+ cop->getOperatorLoc(),
+ FPOptions());
} else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
bop->getType(), bop->getValueKind(),
bop->getObjectKind(),
- bop->getOperatorLoc(), false);
+ bop->getOperatorLoc(), FPOptions());
} else {
assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp
index 390e1b5..2a38a1f 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp
@@ -290,9 +290,15 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
DiagID = diag::warn_unused_property_expr;
} else if (const CXXFunctionalCastExpr *FC
= dyn_cast<CXXFunctionalCastExpr>(E)) {
- if (isa<CXXConstructExpr>(FC->getSubExpr()) ||
- isa<CXXTemporaryObjectExpr>(FC->getSubExpr()))
+ const Expr *E = FC->getSubExpr();
+ if (const CXXBindTemporaryExpr *TE = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = TE->getSubExpr();
+ if (isa<CXXTemporaryObjectExpr>(E))
return;
+ if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E))
+ if (const CXXRecordDecl *RD = CE->getType()->getAsCXXRecordDecl())
+ if (!RD->getAttr<WarnUnusedAttr>())
+ return;
}
// Diagnose "(void*) blah" as a typo for "(void) blah".
else if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) {
@@ -711,6 +717,9 @@ static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S,
EnumValsTy::iterator &EI,
EnumValsTy::iterator &EIEnd,
const llvm::APSInt &Val) {
+ if (!ED->isClosed())
+ return false;
+
if (const DeclRefExpr *DRE =
dyn_cast<DeclRefExpr>(CaseExpr->IgnoreParenImpCasts())) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
@@ -722,15 +731,14 @@ static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S,
}
}
- if (ED->hasAttr<FlagEnumAttr>()) {
+ if (ED->hasAttr<FlagEnumAttr>())
return !S.IsValueInFlagEnum(ED, Val, false);
- } else {
- while (EI != EIEnd && EI->first < Val)
- EI++;
- if (EI != EIEnd && EI->first == Val)
- return false;
- }
+ while (EI != EIEnd && EI->first < Val)
+ EI++;
+
+ if (EI != EIEnd && EI->first == Val)
+ return false;
return true;
}
@@ -1147,7 +1155,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
}
}
- if (TheDefaultStmt && UnhandledNames.empty())
+ if (TheDefaultStmt && UnhandledNames.empty() && ED->isClosedNonFlag())
Diag(TheDefaultStmt->getDefaultLoc(), diag::warn_unreachable_default);
// Produce a nice diagnostic if multiple values aren't handled.
@@ -1198,6 +1206,9 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
AdjustAPSInt(RhsVal, DstWidth, DstIsSigned);
const EnumDecl *ED = ET->getDecl();
+ if (!ED->isClosed())
+ return;
+
if (ED->hasAttr<FlagEnumAttr>()) {
if (!IsValueInFlagEnum(ED, RhsVal, true))
Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
@@ -1277,17 +1288,22 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
}
namespace {
+ // Use SetVector since the diagnostic cares about the ordering of the Decl's.
+ using DeclSetVector =
+ llvm::SetVector<VarDecl *, llvm::SmallVector<VarDecl *, 8>,
+ llvm::SmallPtrSet<VarDecl *, 8>>;
+
// This visitor will traverse a conditional statement and store all
// the evaluated decls into a vector. Simple is set to true if none
// of the excluded constructs are used.
class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> {
- llvm::SmallPtrSetImpl<VarDecl*> &Decls;
+ DeclSetVector &Decls;
SmallVectorImpl<SourceRange> &Ranges;
bool Simple;
public:
typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
- DeclExtractor(Sema &S, llvm::SmallPtrSetImpl<VarDecl*> &Decls,
+ DeclExtractor(Sema &S, DeclSetVector &Decls,
SmallVectorImpl<SourceRange> &Ranges) :
Inherited(S.Context),
Decls(Decls),
@@ -1359,14 +1375,13 @@ namespace {
// DeclMatcher checks to see if the decls are used in a non-evaluated
// context.
class DeclMatcher : public EvaluatedExprVisitor<DeclMatcher> {
- llvm::SmallPtrSetImpl<VarDecl*> &Decls;
+ DeclSetVector &Decls;
bool FoundDecl;
public:
typedef EvaluatedExprVisitor<DeclMatcher> Inherited;
- DeclMatcher(Sema &S, llvm::SmallPtrSetImpl<VarDecl*> &Decls,
- Stmt *Statement) :
+ DeclMatcher(Sema &S, DeclSetVector &Decls, Stmt *Statement) :
Inherited(S.Context), Decls(Decls), FoundDecl(false) {
if (!Statement) return;
@@ -1448,7 +1463,7 @@ namespace {
return;
PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body);
- llvm::SmallPtrSet<VarDecl*, 8> Decls;
+ DeclSetVector Decls;
SmallVector<SourceRange, 10> Ranges;
DeclExtractor DE(S, Decls, Ranges);
DE.Visit(Second);
@@ -1460,11 +1475,9 @@ namespace {
if (Decls.size() == 0) return;
// Don't warn on volatile, static, or global variables.
- for (llvm::SmallPtrSetImpl<VarDecl*>::iterator I = Decls.begin(),
- E = Decls.end();
- I != E; ++I)
- if ((*I)->getType().isVolatileQualified() ||
- (*I)->hasGlobalStorage()) return;
+ for (auto *VD : Decls)
+ if (VD->getType().isVolatileQualified() || VD->hasGlobalStorage())
+ return;
if (DeclMatcher(S, Decls, Second).FoundDeclInUse() ||
DeclMatcher(S, Decls, Third).FoundDeclInUse() ||
@@ -1472,25 +1485,16 @@ namespace {
return;
// Load decl names into diagnostic.
- if (Decls.size() > 4)
+ if (Decls.size() > 4) {
PDiag << 0;
- else {
- PDiag << Decls.size();
- for (llvm::SmallPtrSetImpl<VarDecl*>::iterator I = Decls.begin(),
- E = Decls.end();
- I != E; ++I)
- PDiag << (*I)->getDeclName();
- }
-
- // Load SourceRanges into diagnostic if there is room.
- // Otherwise, load the SourceRange of the conditional expression.
- if (Ranges.size() <= PartialDiagnostic::MaxArguments)
- for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I)
- PDiag << *I;
- else
- PDiag << Second->getSourceRange();
+ } else {
+ PDiag << (unsigned)Decls.size();
+ for (auto *VD : Decls)
+ PDiag << VD->getDeclName();
+ }
+
+ for (auto Range : Ranges)
+ PDiag << Range;
S.Diag(Ranges.begin()->getBegin(), PDiag);
}
@@ -1540,23 +1544,78 @@ namespace {
// A visitor to determine if a continue or break statement is a
// subexpression.
- class BreakContinueFinder : public EvaluatedExprVisitor<BreakContinueFinder> {
+ class BreakContinueFinder : public ConstEvaluatedExprVisitor<BreakContinueFinder> {
SourceLocation BreakLoc;
SourceLocation ContinueLoc;
+ bool InSwitch = false;
+
public:
- BreakContinueFinder(Sema &S, Stmt* Body) :
+ BreakContinueFinder(Sema &S, const Stmt* Body) :
Inherited(S.Context) {
Visit(Body);
}
- typedef EvaluatedExprVisitor<BreakContinueFinder> Inherited;
+ typedef ConstEvaluatedExprVisitor<BreakContinueFinder> Inherited;
- void VisitContinueStmt(ContinueStmt* E) {
+ void VisitContinueStmt(const ContinueStmt* E) {
ContinueLoc = E->getContinueLoc();
}
- void VisitBreakStmt(BreakStmt* E) {
- BreakLoc = E->getBreakLoc();
+ void VisitBreakStmt(const BreakStmt* E) {
+ if (!InSwitch)
+ BreakLoc = E->getBreakLoc();
+ }
+
+ void VisitSwitchStmt(const SwitchStmt* S) {
+ if (const Stmt *Init = S->getInit())
+ Visit(Init);
+ if (const Stmt *CondVar = S->getConditionVariableDeclStmt())
+ Visit(CondVar);
+ if (const Stmt *Cond = S->getCond())
+ Visit(Cond);
+
+ // Don't return break statements from the body of a switch.
+ InSwitch = true;
+ if (const Stmt *Body = S->getBody())
+ Visit(Body);
+ InSwitch = false;
+ }
+
+ void VisitForStmt(const ForStmt *S) {
+ // Only visit the init statement of a for loop; the body
+ // has a different break/continue scope.
+ if (const Stmt *Init = S->getInit())
+ Visit(Init);
+ }
+
+ void VisitWhileStmt(const WhileStmt *) {
+ // Do nothing; the children of a while loop have a different
+ // break/continue scope.
+ }
+
+ void VisitDoStmt(const DoStmt *) {
+ // Do nothing; the children of a while loop have a different
+ // break/continue scope.
+ }
+
+ void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
+ // Only visit the initialization of a for loop; the body
+ // has a different break/continue scope.
+ if (const Stmt *Range = S->getRangeStmt())
+ Visit(Range);
+ if (const Stmt *Begin = S->getBeginStmt())
+ Visit(Begin);
+ if (const Stmt *End = S->getEndStmt())
+ Visit(End);
+ }
+
+ void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
+ // Only visit the initialization of a for loop; the body
+ // has a different break/continue scope.
+ if (const Stmt *Element = S->getElement())
+ Visit(Element);
+ if (const Stmt *Collection = S->getCollection())
+ Visit(Collection);
}
bool ContinueFound() { return ContinueLoc.isValid(); }
@@ -1772,6 +1831,7 @@ StmtResult
Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
Stmt *First, Expr *collection,
SourceLocation RParenLoc) {
+ getCurFunction()->setHasBranchProtectedScope();
ExprResult CollectionExprResult =
CheckObjCForCollectionOperand(ForLoc, collection);
@@ -1810,7 +1870,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
D->setType(FirstType);
- if (ActiveTemplateInstantiations.empty()) {
+ if (!inTemplateInstantiation()) {
SourceLocation Loc =
D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
Diag(Loc, diag::warn_auto_var_is_id)
@@ -1984,11 +2044,11 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
return StmtError();
}
- // Coroutines: 'for co_await' implicitly co_awaits its range.
- if (CoawaitLoc.isValid()) {
- ExprResult Coawait = ActOnCoawaitExpr(S, CoawaitLoc, Range);
- if (Coawait.isInvalid()) return StmtError();
- Range = Coawait.get();
+ // Build the coroutine state immediately and not later during template
+ // instantiation
+ if (!CoawaitLoc.isInvalid()) {
+ if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await"))
+ return StmtError();
}
// Build auto && __range = range-init
@@ -2026,16 +2086,12 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
/// BeginExpr and EndExpr are set and FRS_Success is returned on success;
/// CandidateSet and BEF are set and some non-success value is returned on
/// failure.
-static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef,
- Expr *BeginRange, Expr *EndRange,
- QualType RangeType,
- VarDecl *BeginVar,
- VarDecl *EndVar,
- SourceLocation ColonLoc,
- OverloadCandidateSet *CandidateSet,
- ExprResult *BeginExpr,
- ExprResult *EndExpr,
- BeginEndFunction *BEF) {
+static Sema::ForRangeStatus
+BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange,
+ QualType RangeType, VarDecl *BeginVar, VarDecl *EndVar,
+ SourceLocation ColonLoc, SourceLocation CoawaitLoc,
+ OverloadCandidateSet *CandidateSet, ExprResult *BeginExpr,
+ ExprResult *EndExpr, BeginEndFunction *BEF) {
DeclarationNameInfo BeginNameInfo(
&SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc);
DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"),
@@ -2082,6 +2138,15 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef,
<< ColonLoc << BEF_begin << BeginRange->getType();
return RangeStatus;
}
+ if (!CoawaitLoc.isInvalid()) {
+ // FIXME: getCurScope() should not be used during template instantiation.
+ // We should pick up the set of unqualified lookup results for operator
+ // co_await during the initial parse.
+ *BeginExpr = SemaRef.ActOnCoawaitExpr(SemaRef.getCurScope(), ColonLoc,
+ BeginExpr->get());
+ if (BeginExpr->isInvalid())
+ return Sema::FRS_DiagnosticIssued;
+ }
if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF);
@@ -2201,8 +2266,12 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
// Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
// them in properly when we instantiate the loop.
- if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check)
+ if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
+ if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
+ for (auto *Binding : DD->bindings())
+ Binding->setType(Context.DependentTy);
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
+ }
} else if (!BeginDeclStmt.get()) {
SourceLocation RangeLoc = RangeVar->getLocation();
@@ -2244,6 +2313,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
// begin-expr is __range.
BeginExpr = BeginRangeRef;
+ if (!CoawaitLoc.isInvalid()) {
+ BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get());
+ if (BeginExpr.isInvalid())
+ return StmtError();
+ }
if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
diag::err_for_range_iter_deduction_failure)) {
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
@@ -2256,9 +2330,57 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
BoundExpr = IntegerLiteral::Create(
Context, CAT->getSize(), Context.getPointerDiffType(), RangeLoc);
else if (const VariableArrayType *VAT =
- dyn_cast<VariableArrayType>(UnqAT))
- BoundExpr = VAT->getSizeExpr();
- else {
+ dyn_cast<VariableArrayType>(UnqAT)) {
+ // For a variably modified type we can't just use the expression within
+ // the array bounds, since we don't want that to be re-evaluated here.
+ // Rather, we need to determine what it was when the array was first
+ // created - so we resort to using sizeof(vla)/sizeof(element).
+ // For e.g.
+ // void f(int b) {
+ // int vla[b];
+ // b = -1; <-- This should not affect the num of iterations below
+ // for (int &c : vla) { .. }
+ // }
+
+ // FIXME: This results in codegen generating IR that recalculates the
+ // run-time number of elements (as opposed to just using the IR Value
+ // that corresponds to the run-time value of each bound that was
+ // generated when the array was created.) If this proves too embarassing
+ // even for unoptimized IR, consider passing a magic-value/cookie to
+ // codegen that then knows to simply use that initial llvm::Value (that
+ // corresponds to the bound at time of array creation) within
+ // getelementptr. But be prepared to pay the price of increasing a
+ // customized form of coupling between the two components - which could
+ // be hard to maintain as the codebase evolves.
+
+ ExprResult SizeOfVLAExprR = ActOnUnaryExprOrTypeTraitExpr(
+ EndVar->getLocation(), UETT_SizeOf,
+ /*isType=*/true,
+ CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
+ VAT->desugar(), RangeLoc))
+ .getAsOpaquePtr(),
+ EndVar->getSourceRange());
+ if (SizeOfVLAExprR.isInvalid())
+ return StmtError();
+
+ ExprResult SizeOfEachElementExprR = ActOnUnaryExprOrTypeTraitExpr(
+ EndVar->getLocation(), UETT_SizeOf,
+ /*isType=*/true,
+ CreateParsedType(VAT->desugar(),
+ Context.getTrivialTypeSourceInfo(
+ VAT->getElementType(), RangeLoc))
+ .getAsOpaquePtr(),
+ EndVar->getSourceRange());
+ if (SizeOfEachElementExprR.isInvalid())
+ return StmtError();
+
+ BoundExpr =
+ ActOnBinOp(S, EndVar->getLocation(), tok::slash,
+ SizeOfVLAExprR.get(), SizeOfEachElementExprR.get());
+ if (BoundExpr.isInvalid())
+ return StmtError();
+
+ } else {
// Can't be a DependentSizedArrayType or an IncompleteArrayType since
// UnqAT is not incomplete and Range is not type-dependent.
llvm_unreachable("Unexpected array type in for-range");
@@ -2278,11 +2400,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
OverloadCandidateSet CandidateSet(RangeLoc,
OverloadCandidateSet::CSK_Normal);
BeginEndFunction BEFFailure;
- ForRangeStatus RangeStatus =
- BuildNonArrayForRange(*this, BeginRangeRef.get(),
- EndRangeRef.get(), RangeType,
- BeginVar, EndVar, ColonLoc, &CandidateSet,
- &BeginExpr, &EndExpr, &BEFFailure);
+ ForRangeStatus RangeStatus = BuildNonArrayForRange(
+ *this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar,
+ EndVar, ColonLoc, CoawaitLoc, &CandidateSet, &BeginExpr, &EndExpr,
+ &BEFFailure);
if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
BEFFailure == BEF_begin) {
@@ -2379,6 +2500,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get());
if (!IncrExpr.isInvalid() && CoawaitLoc.isValid())
+ // FIXME: getCurScope() should not be used during template instantiation.
+ // We should pick up the set of unqualified lookup results for operator
+ // co_await during the initial parse.
IncrExpr = ActOnCoawaitExpr(S, CoawaitLoc, IncrExpr.get());
if (!IncrExpr.isInvalid())
IncrExpr = ActOnFinishFullExpr(IncrExpr.get());
@@ -2816,7 +2940,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 ||
@@ -2866,7 +2990,8 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
bool HasDeducedReturnType =
CurLambda && hasDeducedReturnType(CurLambda->CallOperator);
- if (ExprEvalContexts.back().Context == DiscardedStatement &&
+ if (ExprEvalContexts.back().Context ==
+ ExpressionEvaluationContext::DiscardedStatement &&
(HasDeducedReturnType || CurCap->HasImplicitReturnType)) {
if (RetValExp) {
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
@@ -3158,7 +3283,8 @@ StmtResult
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
Scope *CurScope) {
StmtResult R = BuildReturnStmt(ReturnLoc, RetValExp);
- if (R.isInvalid() || ExprEvalContexts.back().Context == DiscardedStatement)
+ if (R.isInvalid() || ExprEvalContexts.back().Context ==
+ ExpressionEvaluationContext::DiscardedStatement)
return R;
if (VarDecl *VD =
@@ -3214,7 +3340,8 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// C++1z: discarded return statements are not considered when deducing a
// return type.
- if (ExprEvalContexts.back().Context == DiscardedStatement &&
+ if (ExprEvalContexts.back().Context ==
+ ExpressionEvaluationContext::DiscardedStatement &&
FnRetType->getContainedAutoType()) {
if (RetValExp) {
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
@@ -3900,8 +4027,9 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
DeclContext *DC = CapturedDecl::castToDeclContext(CD);
IdentifierInfo *ParamName = &Context.Idents.get("__context");
QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
- ImplicitParamDecl *Param
- = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType);
+ auto *Param =
+ ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType,
+ ImplicitParamDecl::CapturedContext);
DC->addDecl(Param);
CD->setContextParam(0, Param);
@@ -3914,7 +4042,8 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
else
CurContext = CD;
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
@@ -3935,15 +4064,17 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
"null type has been found already for '__context' parameter");
IdentifierInfo *ParamName = &Context.Idents.get("__context");
QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
- ImplicitParamDecl *Param
- = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType);
+ auto *Param =
+ ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType,
+ ImplicitParamDecl::CapturedContext);
DC->addDecl(Param);
CD->setContextParam(ParamNum, Param);
ContextIsFound = true;
} else {
IdentifierInfo *ParamName = &Context.Idents.get(I->first);
- ImplicitParamDecl *Param
- = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, I->second);
+ auto *Param =
+ ImplicitParamDecl::Create(Context, DC, Loc, ParamName, I->second,
+ ImplicitParamDecl::CapturedContext);
DC->addDecl(Param);
CD->setParam(ParamNum, Param);
}
@@ -3953,8 +4084,9 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
// Add __context implicitly if it is not specified.
IdentifierInfo *ParamName = &Context.Idents.get("__context");
QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
- ImplicitParamDecl *Param =
- ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType);
+ auto *Param =
+ ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType,
+ ImplicitParamDecl::CapturedContext);
DC->addDecl(Param);
CD->setContextParam(ParamNum, Param);
}
@@ -3966,7 +4098,8 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
else
CurContext = CD;
- PushExpressionEvaluationContext(PotentiallyEvaluated);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::ActOnCapturedRegionError() {
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp
index 76de9e2..c182b35 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp
@@ -277,6 +277,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(),
diag::err_dereference_incomplete_type))
return StmtError();
+ LLVM_FALLTHROUGH;
default:
return StmtError(Diag(OutputExpr->getLocStart(),
diag::err_asm_invalid_lvalue_in_output)
@@ -623,8 +624,9 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
Info.clear();
if (IsUnevaluatedContext)
- PushExpressionEvaluationContext(UnevaluatedAbstract,
- ReuseLambdaContextDecl);
+ PushExpressionEvaluationContext(
+ ExpressionEvaluationContext::UnevaluatedAbstract,
+ ReuseLambdaContextDecl);
ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id,
/*trailing lparen*/ false,
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp
index 01fa856..4ee3412 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp
@@ -53,6 +53,31 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
return ::new (S.Context) auto(Attr);
}
+static Attr *handleSuppressAttr(Sema &S, Stmt *St, const AttributeList &A,
+ SourceRange Range) {
+ if (A.getNumArgs() < 1) {
+ S.Diag(A.getLoc(), diag::err_attribute_too_few_arguments)
+ << A.getName() << 1;
+ return nullptr;
+ }
+
+ std::vector<StringRef> DiagnosticIdentifiers;
+ for (unsigned I = 0, E = A.getNumArgs(); I != E; ++I) {
+ StringRef RuleName;
+
+ if (!S.checkStringLiteralArgumentAttr(A, I, RuleName, nullptr))
+ return nullptr;
+
+ // FIXME: Warn if the rule name is unknown. This is tricky because only
+ // clang-tidy knows about available rules.
+ DiagnosticIdentifiers.push_back(RuleName);
+ }
+
+ return ::new (S.Context) SuppressAttr(
+ A.getRange(), S.Context, DiagnosticIdentifiers.data(),
+ DiagnosticIdentifiers.size(), A.getAttributeSpellingListIndex());
+}
+
static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
SourceRange) {
IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
@@ -279,6 +304,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
return handleLoopHintAttr(S, St, A, Range);
case AttributeList::AT_OpenCLUnrollHint:
return handleOpenCLUnrollHint(S, St, A, Range);
+ case AttributeList::AT_Suppress:
+ return handleSuppressAttr(S, St, A, Range);
default:
// if we're here, then we parsed a known attribute, but didn't recognize
// it as a statement attribute => it is declaration attribute
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp
index ad1e89a..e9b3855 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp
@@ -45,6 +45,26 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc());
}
+namespace clang {
+/// \brief [temp.constr.decl]p2: A template's associated constraints are
+/// defined as a single constraint-expression derived from the introduced
+/// constraint-expressions [ ... ].
+///
+/// \param Params The template parameter list and optional requires-clause.
+///
+/// \param FD The underlying templated function declaration for a function
+/// template.
+static Expr *formAssociatedConstraints(TemplateParameterList *Params,
+ FunctionDecl *FD);
+}
+
+static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params,
+ FunctionDecl *FD) {
+ // FIXME: Concepts: collect additional introduced constraint-expressions
+ assert(!FD && "Cannot collect constraints from function declaration yet.");
+ return Params->getRequiresClause();
+}
+
/// \brief Determine whether the declaration found is acceptable as the name
/// of a template and, if so, return that template declaration. Otherwise,
/// returns NULL.
@@ -222,6 +242,37 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
return TemplateKind;
}
+bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
+ SourceLocation NameLoc,
+ ParsedTemplateTy *Template) {
+ CXXScopeSpec SS;
+ bool MemberOfUnknownSpecialization = false;
+
+ // We could use redeclaration lookup here, but we don't need to: the
+ // syntactic form of a deduction guide is enough to identify it even
+ // if we can't look up the template name at all.
+ LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName);
+ LookupTemplateName(R, S, SS, /*ObjectType*/QualType(),
+ /*EnteringContext*/false, MemberOfUnknownSpecialization);
+
+ if (R.empty()) return false;
+ if (R.isAmbiguous()) {
+ // FIXME: Diagnose an ambiguity if we find at least one template.
+ R.suppressDiagnostics();
+ return false;
+ }
+
+ // We only treat template-names that name type templates as valid deduction
+ // guide names.
+ TemplateDecl *TD = R.getAsSingle<TemplateDecl>();
+ if (!TD || !getAsTypeTemplateDecl(TD))
+ return false;
+
+ if (Template)
+ *Template = TemplateTy::make(TemplateName(TD));
+ return true;
+}
+
bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
@@ -404,6 +455,85 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
}
+void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
+ SourceLocation Less,
+ SourceLocation Greater) {
+ if (TemplateName.isInvalid())
+ return;
+
+ DeclarationNameInfo NameInfo;
+ CXXScopeSpec SS;
+ LookupNameKind LookupKind;
+
+ DeclContext *LookupCtx = nullptr;
+ NamedDecl *Found = nullptr;
+
+ // Figure out what name we looked up.
+ if (auto *ME = dyn_cast<MemberExpr>(TemplateName.get())) {
+ NameInfo = ME->getMemberNameInfo();
+ SS.Adopt(ME->getQualifierLoc());
+ LookupKind = LookupMemberName;
+ LookupCtx = ME->getBase()->getType()->getAsCXXRecordDecl();
+ Found = ME->getMemberDecl();
+ } else {
+ auto *DRE = cast<DeclRefExpr>(TemplateName.get());
+ NameInfo = DRE->getNameInfo();
+ SS.Adopt(DRE->getQualifierLoc());
+ LookupKind = LookupOrdinaryName;
+ Found = DRE->getFoundDecl();
+ }
+
+ // Try to correct the name by looking for templates and C++ named casts.
+ struct TemplateCandidateFilter : CorrectionCandidateCallback {
+ TemplateCandidateFilter() {
+ WantTypeSpecifiers = false;
+ WantExpressionKeywords = false;
+ WantRemainingKeywords = false;
+ WantCXXNamedCasts = true;
+ };
+ bool ValidateCandidate(const TypoCorrection &Candidate) override {
+ if (auto *ND = Candidate.getCorrectionDecl())
+ return isAcceptableTemplateName(ND->getASTContext(), ND, true);
+ return Candidate.isKeyword();
+ }
+ };
+
+ DeclarationName Name = NameInfo.getName();
+ if (TypoCorrection Corrected =
+ CorrectTypo(NameInfo, LookupKind, S, &SS,
+ llvm::make_unique<TemplateCandidateFilter>(),
+ CTK_ErrorRecovery, LookupCtx)) {
+ auto *ND = Corrected.getFoundDecl();
+ if (ND)
+ ND = isAcceptableTemplateName(Context, ND,
+ /*AllowFunctionTemplates*/ true);
+ if (ND || Corrected.isKeyword()) {
+ if (LookupCtx) {
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
+ Name.getAsString() == CorrectedStr;
+ diagnoseTypo(Corrected,
+ PDiag(diag::err_non_template_in_member_template_id_suggest)
+ << Name << LookupCtx << DroppedSpecifier
+ << SS.getRange(), false);
+ } else {
+ diagnoseTypo(Corrected,
+ PDiag(diag::err_non_template_in_template_id_suggest)
+ << Name, false);
+ }
+ if (Found)
+ Diag(Found->getLocation(),
+ diag::note_non_template_in_template_id_found);
+ return;
+ }
+ }
+
+ Diag(NameInfo.getLoc(), diag::err_non_template_in_template_id)
+ << Name << SourceRange(Less, Greater);
+ if (Found)
+ Diag(Found->getLocation(), diag::note_non_template_in_template_id_found);
+}
+
/// ActOnDependentIdExpression - Handle a dependent id-expression that
/// was just parsed. This is only possible with an explicit scope
/// specifier naming a dependent type.
@@ -1137,6 +1267,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
}
+ // TODO Memory management; associated constraints are not always stored.
+ Expr *const CurAC = formAssociatedConstraints(TemplateParams, nullptr);
+
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible. Skip this check
// for a friend in a dependent context: the template parameter list itself
@@ -1148,6 +1281,29 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
TPL_TemplateMatch))
return true;
+ // Check for matching associated constraints on redeclarations.
+ const Expr *const PrevAC = PrevClassTemplate->getAssociatedConstraints();
+ const bool RedeclACMismatch = [&] {
+ if (!(CurAC || PrevAC))
+ return false; // Nothing to check; no mismatch.
+ if (CurAC && PrevAC) {
+ llvm::FoldingSetNodeID CurACInfo, PrevACInfo;
+ CurAC->Profile(CurACInfo, Context, /*Canonical=*/true);
+ PrevAC->Profile(PrevACInfo, Context, /*Canonical=*/true);
+ if (CurACInfo == PrevACInfo)
+ return false; // All good; no mismatch.
+ }
+ return true;
+ }();
+
+ if (RedeclACMismatch) {
+ Diag(CurAC ? CurAC->getLocStart() : NameLoc,
+ diag::err_template_different_associated_constraints);
+ Diag(PrevAC ? PrevAC->getLocStart() : PrevClassTemplate->getLocation(),
+ diag::note_template_prev_declaration) << /*declaration*/0;
+ return true;
+ }
+
// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
// specialization or explicit instantiation of a class template,
@@ -1174,8 +1330,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
assert(Tmpl && "original definition of a class template is not a "
"class template?");
- makeMergedDefinitionVisible(Hidden, KWLoc);
- makeMergedDefinitionVisible(Tmpl, KWLoc);
+ makeMergedDefinitionVisible(Hidden);
+ makeMergedDefinitionVisible(Tmpl);
return Def;
}
@@ -1250,10 +1406,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
AddMsStructLayoutForRecord(NewClass);
}
+ // Attach the associated constraints when the declaration will not be part of
+ // a decl chain.
+ Expr *const ACtoAttach =
+ PrevClassTemplate && ShouldAddRedecl ? nullptr : CurAC;
+
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
- NewClass);
+ NewClass, ACtoAttach);
if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate);
@@ -1333,6 +1494,379 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
return NewTemplate;
}
+namespace {
+/// Transform to convert portions of a constructor declaration into the
+/// corresponding deduction guide, per C++1z [over.match.class.deduct]p1.
+struct ConvertConstructorToDeductionGuideTransform {
+ ConvertConstructorToDeductionGuideTransform(Sema &S,
+ ClassTemplateDecl *Template)
+ : SemaRef(S), Template(Template) {}
+
+ Sema &SemaRef;
+ ClassTemplateDecl *Template;
+
+ DeclContext *DC = Template->getDeclContext();
+ CXXRecordDecl *Primary = Template->getTemplatedDecl();
+ DeclarationName DeductionGuideName =
+ SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(Template);
+
+ QualType DeducedType = SemaRef.Context.getTypeDeclType(Primary);
+
+ // Index adjustment to apply to convert depth-1 template parameters into
+ // depth-0 template parameters.
+ unsigned Depth1IndexAdjustment = Template->getTemplateParameters()->size();
+
+ /// Transform a constructor declaration into a deduction guide.
+ NamedDecl *transformConstructor(FunctionTemplateDecl *FTD,
+ CXXConstructorDecl *CD) {
+ SmallVector<TemplateArgument, 16> SubstArgs;
+
+ LocalInstantiationScope Scope(SemaRef);
+
+ // C++ [over.match.class.deduct]p1:
+ // -- For each constructor of the class template designated by the
+ // template-name, a function template with the following properties:
+
+ // -- The template parameters are the template parameters of the class
+ // template followed by the template parameters (including default
+ // template arguments) of the constructor, if any.
+ TemplateParameterList *TemplateParams = Template->getTemplateParameters();
+ if (FTD) {
+ TemplateParameterList *InnerParams = FTD->getTemplateParameters();
+ SmallVector<NamedDecl *, 16> AllParams;
+ AllParams.reserve(TemplateParams->size() + InnerParams->size());
+ AllParams.insert(AllParams.begin(),
+ TemplateParams->begin(), TemplateParams->end());
+ SubstArgs.reserve(InnerParams->size());
+
+ // Later template parameters could refer to earlier ones, so build up
+ // a list of substituted template arguments as we go.
+ for (NamedDecl *Param : *InnerParams) {
+ MultiLevelTemplateArgumentList Args;
+ Args.addOuterTemplateArguments(SubstArgs);
+ Args.addOuterRetainedLevel();
+ NamedDecl *NewParam = transformTemplateParameter(Param, Args);
+ if (!NewParam)
+ return nullptr;
+ AllParams.push_back(NewParam);
+ SubstArgs.push_back(SemaRef.Context.getCanonicalTemplateArgument(
+ SemaRef.Context.getInjectedTemplateArg(NewParam)));
+ }
+ TemplateParams = TemplateParameterList::Create(
+ SemaRef.Context, InnerParams->getTemplateLoc(),
+ InnerParams->getLAngleLoc(), AllParams, InnerParams->getRAngleLoc(),
+ /*FIXME: RequiresClause*/ nullptr);
+ }
+
+ // If we built a new template-parameter-list, track that we need to
+ // substitute references to the old parameters into references to the
+ // new ones.
+ MultiLevelTemplateArgumentList Args;
+ if (FTD) {
+ Args.addOuterTemplateArguments(SubstArgs);
+ Args.addOuterRetainedLevel();
+ }
+
+ FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc()
+ .getAsAdjusted<FunctionProtoTypeLoc>();
+ assert(FPTL && "no prototype for constructor declaration");
+
+ // Transform the type of the function, adjusting the return type and
+ // replacing references to the old parameters with references to the
+ // new ones.
+ TypeLocBuilder TLB;
+ SmallVector<ParmVarDecl*, 8> Params;
+ QualType NewType = transformFunctionProtoType(TLB, FPTL, Params, Args);
+ if (NewType.isNull())
+ return nullptr;
+ TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
+
+ return buildDeductionGuide(TemplateParams, CD->isExplicit(), NewTInfo,
+ CD->getLocStart(), CD->getLocation(),
+ CD->getLocEnd());
+ }
+
+ /// Build a deduction guide with the specified parameter types.
+ NamedDecl *buildSimpleDeductionGuide(MutableArrayRef<QualType> ParamTypes) {
+ SourceLocation Loc = Template->getLocation();
+
+ // Build the requested type.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.HasTrailingReturn = true;
+ QualType Result = SemaRef.BuildFunctionType(DeducedType, ParamTypes, Loc,
+ DeductionGuideName, EPI);
+ TypeSourceInfo *TSI = SemaRef.Context.getTrivialTypeSourceInfo(Result, Loc);
+
+ FunctionProtoTypeLoc FPTL =
+ TSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
+
+ // Build the parameters, needed during deduction / substitution.
+ SmallVector<ParmVarDecl*, 4> Params;
+ for (auto T : ParamTypes) {
+ ParmVarDecl *NewParam = ParmVarDecl::Create(
+ SemaRef.Context, DC, Loc, Loc, nullptr, T,
+ SemaRef.Context.getTrivialTypeSourceInfo(T, Loc), SC_None, nullptr);
+ NewParam->setScopeInfo(0, Params.size());
+ FPTL.setParam(Params.size(), NewParam);
+ Params.push_back(NewParam);
+ }
+
+ return buildDeductionGuide(Template->getTemplateParameters(), false, TSI,
+ Loc, Loc, Loc);
+ }
+
+private:
+ /// Transform a constructor template parameter into a deduction guide template
+ /// parameter, rebuilding any internal references to earlier parameters and
+ /// renumbering as we go.
+ NamedDecl *transformTemplateParameter(NamedDecl *TemplateParam,
+ MultiLevelTemplateArgumentList &Args) {
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam)) {
+ // TemplateTypeParmDecl's index cannot be changed after creation, so
+ // substitute it directly.
+ auto *NewTTP = TemplateTypeParmDecl::Create(
+ SemaRef.Context, DC, TTP->getLocStart(), TTP->getLocation(),
+ /*Depth*/0, Depth1IndexAdjustment + TTP->getIndex(),
+ TTP->getIdentifier(), TTP->wasDeclaredWithTypename(),
+ TTP->isParameterPack());
+ if (TTP->hasDefaultArgument()) {
+ TypeSourceInfo *InstantiatedDefaultArg =
+ SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
+ TTP->getDefaultArgumentLoc(), TTP->getDeclName());
+ if (InstantiatedDefaultArg)
+ NewTTP->setDefaultArgument(InstantiatedDefaultArg);
+ }
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(TemplateParam,
+ NewTTP);
+ return NewTTP;
+ }
+
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
+ return transformTemplateParameterImpl(TTP, Args);
+
+ return transformTemplateParameterImpl(
+ cast<NonTypeTemplateParmDecl>(TemplateParam), Args);
+ }
+ template<typename TemplateParmDecl>
+ TemplateParmDecl *
+ transformTemplateParameterImpl(TemplateParmDecl *OldParam,
+ MultiLevelTemplateArgumentList &Args) {
+ // Ask the template instantiator to do the heavy lifting for us, then adjust
+ // the index of the parameter once it's done.
+ auto *NewParam =
+ cast_or_null<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args));
+ assert(NewParam->getDepth() == 0 && "unexpected template param depth");
+ NewParam->setPosition(NewParam->getPosition() + Depth1IndexAdjustment);
+ return NewParam;
+ }
+
+ QualType transformFunctionProtoType(TypeLocBuilder &TLB,
+ FunctionProtoTypeLoc TL,
+ SmallVectorImpl<ParmVarDecl*> &Params,
+ MultiLevelTemplateArgumentList &Args) {
+ SmallVector<QualType, 4> ParamTypes;
+ const FunctionProtoType *T = TL.getTypePtr();
+
+ // -- The types of the function parameters are those of the constructor.
+ for (auto *OldParam : TL.getParams()) {
+ ParmVarDecl *NewParam = transformFunctionTypeParam(OldParam, Args);
+ if (!NewParam)
+ return QualType();
+ ParamTypes.push_back(NewParam->getType());
+ Params.push_back(NewParam);
+ }
+
+ // -- The return type is the class template specialization designated by
+ // the template-name and template arguments corresponding to the
+ // template parameters obtained from the class template.
+ //
+ // We use the injected-class-name type of the primary template instead.
+ // This has the convenient property that it is different from any type that
+ // the user can write in a deduction-guide (because they cannot enter the
+ // context of the template), so implicit deduction guides can never collide
+ // with explicit ones.
+ QualType ReturnType = DeducedType;
+ TLB.pushTypeSpec(ReturnType).setNameLoc(Primary->getLocation());
+
+ // Resolving a wording defect, we also inherit the variadicness of the
+ // constructor.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.Variadic = T->isVariadic();
+ EPI.HasTrailingReturn = true;
+
+ QualType Result = SemaRef.BuildFunctionType(
+ ReturnType, ParamTypes, TL.getLocStart(), DeductionGuideName, EPI);
+ if (Result.isNull())
+ return QualType();
+
+ FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result);
+ NewTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
+ NewTL.setExceptionSpecRange(SourceRange());
+ NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
+ for (unsigned I = 0, E = NewTL.getNumParams(); I != E; ++I)
+ NewTL.setParam(I, Params[I]);
+
+ return Result;
+ }
+
+ ParmVarDecl *
+ transformFunctionTypeParam(ParmVarDecl *OldParam,
+ MultiLevelTemplateArgumentList &Args) {
+ TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();
+ TypeSourceInfo *NewDI;
+ if (!Args.getNumLevels())
+ NewDI = OldDI;
+ else if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) {
+ // Expand out the one and only element in each inner pack.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0);
+ NewDI =
+ SemaRef.SubstType(PackTL.getPatternLoc(), Args,
+ OldParam->getLocation(), OldParam->getDeclName());
+ if (!NewDI) return nullptr;
+ NewDI =
+ SemaRef.CheckPackExpansion(NewDI, PackTL.getEllipsisLoc(),
+ PackTL.getTypePtr()->getNumExpansions());
+ } else
+ NewDI = SemaRef.SubstType(OldDI, Args, OldParam->getLocation(),
+ OldParam->getDeclName());
+ if (!NewDI)
+ return nullptr;
+
+ // Canonicalize the type. This (for instance) replaces references to
+ // typedef members of the current instantiations with the definitions of
+ // those typedefs, avoiding triggering instantiation of the deduced type
+ // during deduction.
+ // FIXME: It would be preferable to retain type sugar and source
+ // information here (and handle this in substitution instead).
+ NewDI = SemaRef.Context.getTrivialTypeSourceInfo(
+ SemaRef.Context.getCanonicalType(NewDI->getType()),
+ OldParam->getLocation());
+
+ // Resolving a wording defect, we also inherit default arguments from the
+ // constructor.
+ ExprResult NewDefArg;
+ if (OldParam->hasDefaultArg()) {
+ NewDefArg = Args.getNumLevels()
+ ? SemaRef.SubstExpr(OldParam->getDefaultArg(), Args)
+ : OldParam->getDefaultArg();
+ if (NewDefArg.isInvalid())
+ return nullptr;
+ }
+
+ ParmVarDecl *NewParam = ParmVarDecl::Create(SemaRef.Context, DC,
+ OldParam->getInnerLocStart(),
+ OldParam->getLocation(),
+ OldParam->getIdentifier(),
+ NewDI->getType(),
+ NewDI,
+ OldParam->getStorageClass(),
+ NewDefArg.get());
+ NewParam->setScopeInfo(OldParam->getFunctionScopeDepth(),
+ OldParam->getFunctionScopeIndex());
+ return NewParam;
+ }
+
+ NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams,
+ bool Explicit, TypeSourceInfo *TInfo,
+ SourceLocation LocStart, SourceLocation Loc,
+ SourceLocation LocEnd) {
+ DeclarationNameInfo Name(DeductionGuideName, Loc);
+ ArrayRef<ParmVarDecl *> Params =
+ TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams();
+
+ // Build the implicit deduction guide template.
+ auto *Guide =
+ CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, Explicit,
+ Name, TInfo->getType(), TInfo, LocEnd);
+ Guide->setImplicit();
+ Guide->setParams(Params);
+
+ for (auto *Param : Params)
+ Param->setDeclContext(Guide);
+
+ auto *GuideTemplate = FunctionTemplateDecl::Create(
+ SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide);
+ GuideTemplate->setImplicit();
+ Guide->setDescribedFunctionTemplate(GuideTemplate);
+
+ if (isa<CXXRecordDecl>(DC)) {
+ Guide->setAccess(AS_public);
+ GuideTemplate->setAccess(AS_public);
+ }
+
+ DC->addDecl(GuideTemplate);
+ return GuideTemplate;
+ }
+};
+}
+
+void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
+ SourceLocation Loc) {
+ DeclContext *DC = Template->getDeclContext();
+ if (DC->isDependentContext())
+ return;
+
+ ConvertConstructorToDeductionGuideTransform Transform(
+ *this, cast<ClassTemplateDecl>(Template));
+ if (!isCompleteType(Loc, Transform.DeducedType))
+ return;
+
+ // Check whether we've already declared deduction guides for this template.
+ // FIXME: Consider storing a flag on the template to indicate this.
+ auto Existing = DC->lookup(Transform.DeductionGuideName);
+ for (auto *D : Existing)
+ if (D->isImplicit())
+ return;
+
+ // In case we were expanding a pack when we attempted to declare deduction
+ // guides, turn off pack expansion for everything we're about to do.
+ ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1);
+ // Create a template instantiation record to track the "instantiation" of
+ // constructors into deduction guides.
+ // FIXME: Add a kind for this to give more meaningful diagnostics. But can
+ // this substitution process actually fail?
+ InstantiatingTemplate BuildingDeductionGuides(*this, Loc, Template);
+
+ // Convert declared constructors into deduction guide templates.
+ // FIXME: Skip constructors for which deduction must necessarily fail (those
+ // for which some class template parameter without a default argument never
+ // appears in a deduced context).
+ bool AddedAny = false;
+ bool AddedCopyOrMove = false;
+ for (NamedDecl *D : LookupConstructors(Transform.Primary)) {
+ D = D->getUnderlyingDecl();
+ if (D->isInvalidDecl() || D->isImplicit())
+ continue;
+ D = cast<NamedDecl>(D->getCanonicalDecl());
+
+ auto *FTD = dyn_cast<FunctionTemplateDecl>(D);
+ auto *CD =
+ dyn_cast_or_null<CXXConstructorDecl>(FTD ? FTD->getTemplatedDecl() : D);
+ // Class-scope explicit specializations (MS extension) do not result in
+ // deduction guides.
+ if (!CD || (!FTD && CD->isFunctionTemplateSpecialization()))
+ continue;
+
+ Transform.transformConstructor(FTD, CD);
+ AddedAny = true;
+
+ AddedCopyOrMove |= CD->isCopyOrMoveConstructor();
+ }
+
+ // Synthesize an X() -> X<...> guide if there were no declared constructors.
+ // FIXME: The standard doesn't say (how) to do this.
+ if (!AddedAny)
+ Transform.buildSimpleDeductionGuide(None);
+
+ // Synthesize an X(X<...>) -> X<...> guide if there was no declared constructor
+ // resembling a copy or move constructor.
+ // FIXME: The standard doesn't say (how) to do this.
+ if (!AddedCopyOrMove)
+ Transform.buildSimpleDeductionGuide(Transform.DeducedType);
+}
+
/// \brief Diagnose the presence of a default template argument on a
/// template parameter, which is ill-formed in certain contexts.
///
@@ -1665,7 +2199,6 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
typedef RecursiveASTVisitor<DependencyChecker> super;
unsigned Depth;
- bool FindLessThanDepth;
// Whether we're looking for a use of a template parameter that makes the
// overall construct type-dependent / a dependent type. This is strictly
@@ -1676,16 +2209,25 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
bool Match;
SourceLocation MatchLoc;
- DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent,
- bool FindLessThanDepth = false)
- : Depth(Depth), FindLessThanDepth(FindLessThanDepth),
- IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) {}
+ DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent)
+ : Depth(Depth), IgnoreNonTypeDependent(IgnoreNonTypeDependent),
+ Match(false) {}
DependencyChecker(TemplateParameterList *Params, bool IgnoreNonTypeDependent)
- : DependencyChecker(Params->getDepth(), IgnoreNonTypeDependent) {}
+ : IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) {
+ NamedDecl *ND = Params->getParam(0);
+ if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) {
+ Depth = PD->getDepth();
+ } else if (NonTypeTemplateParmDecl *PD =
+ dyn_cast<NonTypeTemplateParmDecl>(ND)) {
+ Depth = PD->getDepth();
+ } else {
+ Depth = cast<TemplateTemplateParmDecl>(ND)->getDepth();
+ }
+ }
bool Matches(unsigned ParmDepth, SourceLocation Loc = SourceLocation()) {
- if (FindLessThanDepth ^ (ParmDepth >= Depth)) {
+ if (ParmDepth >= Depth) {
Match = true;
MatchLoc = Loc;
return true;
@@ -1802,8 +2344,9 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
/// matching template parameters to scope specifiers in friend
/// declarations.
///
-/// \param IsExplicitSpecialization will be set true if the entity being
-/// declared is an explicit specialization, false otherwise.
+/// \param IsMemberSpecialization will be set true if the scope specifier
+/// denotes a fully-specialized type, and therefore this is a declaration of
+/// a member specialization.
///
/// \returns the template parameter list, if any, that corresponds to the
/// name that is preceded by the scope specifier @p SS. This template
@@ -1815,8 +2358,8 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
- bool &IsExplicitSpecialization, bool &Invalid) {
- IsExplicitSpecialization = false;
+ bool &IsMemberSpecialization, bool &Invalid) {
+ IsMemberSpecialization = false;
Invalid = false;
// The sequence of nested types to which we will match up the template
@@ -1926,7 +2469,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
Diag(DeclLoc, diag::err_specialize_member_of_template)
<< !Recovery << Range;
Invalid = true;
- IsExplicitSpecialization = false;
+ IsMemberSpecialization = false;
return true;
}
@@ -1996,7 +2539,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (Record->getTemplateSpecializationKind()
!= TSK_ExplicitSpecialization &&
TypeIdx == NumTypes - 1)
- IsExplicitSpecialization = true;
+ IsMemberSpecialization = true;
continue;
}
@@ -2030,9 +2573,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (NeedEmptyTemplateHeader) {
// If we're on the last of the types, and we need a 'template<>' header
- // here, then it's an explicit specialization.
+ // here, then it's a member specialization.
if (TypeIdx == NumTypes - 1)
- IsExplicitSpecialization = true;
+ IsMemberSpecialization = true;
if (ParamIdx < ParamLists.size()) {
if (ParamLists[ParamIdx]->size() > 0) {
@@ -2105,7 +2648,6 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (TemplateId && !IsFriend) {
// We don't have a template header for the declaration itself, but we
// should.
- IsExplicitSpecialization = true;
DiagnoseMissingExplicitSpecialization(SourceRange(TemplateId->LAngleLoc,
TemplateId->RAngleLoc));
@@ -2264,6 +2806,101 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
llvm_unreachable("unexpected BuiltinTemplateDecl!");
}
+/// Determine whether this alias template is "enable_if_t".
+static bool isEnableIfAliasTemplate(TypeAliasTemplateDecl *AliasTemplate) {
+ return AliasTemplate->getName().equals("enable_if_t");
+}
+
+/// Collect all of the separable terms in the given condition, which
+/// might be a conjunction.
+///
+/// FIXME: The right answer is to convert the logical expression into
+/// disjunctive normal form, so we can find the first failed term
+/// within each possible clause.
+static void collectConjunctionTerms(Expr *Clause,
+ SmallVectorImpl<Expr *> &Terms) {
+ if (auto BinOp = dyn_cast<BinaryOperator>(Clause->IgnoreParenImpCasts())) {
+ if (BinOp->getOpcode() == BO_LAnd) {
+ collectConjunctionTerms(BinOp->getLHS(), Terms);
+ collectConjunctionTerms(BinOp->getRHS(), Terms);
+ }
+
+ return;
+ }
+
+ Terms.push_back(Clause);
+}
+
+// The ranges-v3 library uses an odd pattern of a top-level "||" with
+// a left-hand side that is value-dependent but never true. Identify
+// the idiom and ignore that term.
+static Expr *lookThroughRangesV3Condition(Preprocessor &PP, Expr *Cond) {
+ // Top-level '||'.
+ auto *BinOp = dyn_cast<BinaryOperator>(Cond->IgnoreParenImpCasts());
+ if (!BinOp) return Cond;
+
+ if (BinOp->getOpcode() != BO_LOr) return Cond;
+
+ // With an inner '==' that has a literal on the right-hand side.
+ Expr *LHS = BinOp->getLHS();
+ auto *InnerBinOp = dyn_cast<BinaryOperator>(LHS->IgnoreParenImpCasts());
+ if (!InnerBinOp) return Cond;
+
+ if (InnerBinOp->getOpcode() != BO_EQ ||
+ !isa<IntegerLiteral>(InnerBinOp->getRHS()))
+ return Cond;
+
+ // If the inner binary operation came from a macro expansion named
+ // CONCEPT_REQUIRES or CONCEPT_REQUIRES_, return the right-hand side
+ // of the '||', which is the real, user-provided condition.
+ SourceLocation Loc = InnerBinOp->getExprLoc();
+ if (!Loc.isMacroID()) return Cond;
+
+ StringRef MacroName = PP.getImmediateMacroName(Loc);
+ if (MacroName == "CONCEPT_REQUIRES" || MacroName == "CONCEPT_REQUIRES_")
+ return BinOp->getRHS();
+
+ return Cond;
+}
+
+/// Find the failed subexpression within enable_if, and describe it
+/// with a string.
+static std::pair<Expr *, std::string>
+findFailedEnableIfCondition(Sema &S, Expr *Cond) {
+ Cond = lookThroughRangesV3Condition(S.PP, Cond);
+
+ // Separate out all of the terms in a conjunction.
+ SmallVector<Expr *, 4> Terms;
+ collectConjunctionTerms(Cond, Terms);
+
+ // Determine which term failed.
+ Expr *FailedCond = nullptr;
+ for (Expr *Term : Terms) {
+ // The initialization of the parameter from the argument is
+ // a constant-evaluated context.
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ bool Succeeded;
+ if (Term->EvaluateAsBooleanCondition(Succeeded, S.Context) &&
+ !Succeeded) {
+ FailedCond = Term->IgnoreParenImpCasts();
+ break;
+ }
+ }
+
+ if (!FailedCond)
+ FailedCond = Cond->IgnoreParenImpCasts();
+
+ std::string Description;
+ {
+ llvm::raw_string_ostream Out(Description);
+ FailedCond->printPretty(Out, nullptr,
+ PrintingPolicy(S.Context.getLangOpts()));
+ }
+ return { FailedCond, Description };
+}
+
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
@@ -2310,12 +2947,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
if (Pattern->isInvalidDecl())
return QualType();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted);
+ TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
+ Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs);
unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth();
for (unsigned I = 0; I < Depth; ++I)
TemplateArgLists.addOuterTemplateArguments(None);
@@ -2328,8 +2965,42 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
CanonType = SubstType(Pattern->getUnderlyingType(),
TemplateArgLists, AliasTemplate->getLocation(),
AliasTemplate->getDeclName());
- if (CanonType.isNull())
+ if (CanonType.isNull()) {
+ // If this was enable_if and we failed to find the nested type
+ // within enable_if in a SFINAE context, dig out the specific
+ // enable_if condition that failed and present that instead.
+ if (isEnableIfAliasTemplate(AliasTemplate)) {
+ if (auto DeductionInfo = isSFINAEContext()) {
+ if (*DeductionInfo &&
+ (*DeductionInfo)->hasSFINAEDiagnostic() &&
+ (*DeductionInfo)->peekSFINAEDiagnostic().second.getDiagID() ==
+ diag::err_typename_nested_not_found_enable_if &&
+ TemplateArgs[0].getArgument().getKind()
+ == TemplateArgument::Expression) {
+ Expr *FailedCond;
+ std::string FailedDescription;
+ std::tie(FailedCond, FailedDescription) =
+ findFailedEnableIfCondition(
+ *this, TemplateArgs[0].getSourceExpression());
+
+ // Remove the old SFINAE diagnostic.
+ PartialDiagnosticAt OldDiag =
+ {SourceLocation(), PartialDiagnostic::NullDiagnostic()};
+ (*DeductionInfo)->takeSFINAEDiagnostic(OldDiag);
+
+ // Add a new SFINAE diagnostic specifying which condition
+ // failed.
+ (*DeductionInfo)->addSFINAEDiagnostic(
+ OldDiag.first,
+ PDiag(diag::err_typename_nested_not_found_requirement)
+ << FailedDescription
+ << FailedCond->getSourceRange());
+ }
+ }
+ }
+
return QualType();
+ }
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs, InstantiationDependent)) {
@@ -2402,6 +3073,13 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
}
+ if (Decl->getSpecializationKind() == TSK_Undeclared) {
+ MultiLevelTemplateArgumentList TemplateArgLists;
+ TemplateArgLists.addOuterTemplateArguments(Converted);
+ InstantiateAttrsForDecl(TemplateArgLists, ClassTemplate->getTemplatedDecl(),
+ Decl);
+ }
+
// Diagnose uses of this specialization.
(void)DiagnoseUseOfDecl(Decl, TemplateLoc);
@@ -2421,14 +3099,51 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
TypeResult
Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- TemplateTy TemplateD, SourceLocation TemplateLoc,
+ TemplateTy TemplateD, IdentifierInfo *TemplateII,
+ SourceLocation TemplateIILoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc,
- bool IsCtorOrDtorName) {
+ bool IsCtorOrDtorName, bool IsClassName) {
if (SS.isInvalid())
return true;
+ if (!IsCtorOrDtorName && !IsClassName && SS.isSet()) {
+ DeclContext *LookupCtx = computeDeclContext(SS, /*EnteringContext*/false);
+
+ // C++ [temp.res]p3:
+ // A qualified-id that refers to a type and in which the
+ // nested-name-specifier depends on a template-parameter (14.6.2)
+ // shall be prefixed by the keyword typename to indicate that the
+ // qualified-id denotes a type, forming an
+ // elaborated-type-specifier (7.1.5.3).
+ if (!LookupCtx && isDependentScopeSpecifier(SS)) {
+ Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
+ << SS.getScopeRep() << TemplateII->getName();
+ // Recover as if 'typename' were specified.
+ // FIXME: This is not quite correct recovery as we don't transform SS
+ // into the corresponding dependent form (and we don't diagnose missing
+ // 'template' keywords within SS as a result).
+ return ActOnTypenameType(nullptr, SourceLocation(), SS, TemplateKWLoc,
+ TemplateD, TemplateII, TemplateIILoc, LAngleLoc,
+ TemplateArgsIn, RAngleLoc);
+ }
+
+ // Per C++ [class.qual]p2, if the template-id was an injected-class-name,
+ // it's not actually allowed to be used as a type in most cases. Because
+ // we annotate it before we know whether it's valid, we have to check for
+ // this case here.
+ auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
+ if (LookupRD && LookupRD->getIdentifier() == TemplateII) {
+ Diag(TemplateIILoc,
+ TemplateKWLoc.isInvalid()
+ ? diag::err_out_of_line_qualified_id_type_names_constructor
+ : diag::ext_out_of_line_qualified_id_type_names_constructor)
+ << TemplateII << 0 /*injected-class-name used as template name*/
+ << 1 /*if any keyword was present, it was 'template'*/;
+ }
+ }
+
TemplateName Template = TemplateD.get();
// Translate the parser's template argument list in our AST format.
@@ -2448,7 +3163,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
SpecTL.setElaboratedKeywordLoc(SourceLocation());
SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
- SpecTL.setTemplateNameLoc(TemplateLoc);
+ SpecTL.setTemplateNameLoc(TemplateIILoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
for (unsigned I = 0, N = SpecTL.getNumArgs(); I != N; ++I)
@@ -2456,8 +3171,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
}
- QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
-
+ QualType Result = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
if (Result.isNull())
return true;
@@ -2466,7 +3180,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
TemplateSpecializationTypeLoc SpecTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
- SpecTL.setTemplateNameLoc(TemplateLoc);
+ SpecTL.setTemplateNameLoc(TemplateIILoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i)
@@ -2690,6 +3404,23 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) {
S.Diag(Template->getLocation(), diag::note_template_decl_here);
}
+static void
+noteNonDeducibleParameters(Sema &S, TemplateParameterList *TemplateParams,
+ const llvm::SmallBitVector &DeducibleParams) {
+ for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
+ if (!DeducibleParams[I]) {
+ NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
+ if (Param->getDeclName())
+ S.Diag(Param->getLocation(), diag::note_non_deducible_parameter)
+ << Param->getDeclName();
+ else
+ S.Diag(Param->getLocation(), diag::note_non_deducible_parameter)
+ << "(anonymous)";
+ }
+ }
+}
+
+
template<typename PartialSpecDecl>
static void checkTemplatePartialSpecialization(Sema &S,
PartialSpecDecl *Partial) {
@@ -2717,19 +3448,7 @@ static void checkTemplatePartialSpecialization(Sema &S,
<< (NumNonDeducible > 1)
<< SourceRange(Partial->getLocation(),
Partial->getTemplateArgsAsWritten()->RAngleLoc);
- for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
- if (!DeducibleParams[I]) {
- NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
- if (Param->getDeclName())
- S.Diag(Param->getLocation(),
- diag::note_partial_spec_unused_parameter)
- << Param->getDeclName();
- else
- S.Diag(Param->getLocation(),
- diag::note_partial_spec_unused_parameter)
- << "(anonymous)";
- }
- }
+ noteNonDeducibleParameters(S, TemplateParams, DeducibleParams);
}
}
@@ -2743,6 +3462,29 @@ void Sema::CheckTemplatePartialSpecialization(
checkTemplatePartialSpecialization(*this, Partial);
}
+void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) {
+ // C++1z [temp.param]p11:
+ // A template parameter of a deduction guide template that does not have a
+ // default-argument shall be deducible from the parameter-type-list of the
+ // deduction guide template.
+ auto *TemplateParams = TD->getTemplateParameters();
+ llvm::SmallBitVector DeducibleParams(TemplateParams->size());
+ MarkDeducedTemplateParameters(TD, DeducibleParams);
+ for (unsigned I = 0; I != TemplateParams->size(); ++I) {
+ // A parameter pack is deducible (to an empty pack).
+ auto *Param = TemplateParams->getParam(I);
+ if (Param->isParameterPack() || hasVisibleDefaultArgument(Param))
+ DeducibleParams[I] = true;
+ }
+
+ if (!DeducibleParams.all()) {
+ unsigned NumNonDeducible = DeducibleParams.size() - DeducibleParams.count();
+ Diag(TD->getLocation(), diag::err_deduction_guide_template_not_deducible)
+ << (NumNonDeducible > 1);
+ noteNonDeducibleParameters(*this, TemplateParams, DeducibleParams);
+ }
+}
+
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,
TemplateParameterList *TemplateParams, StorageClass SC,
@@ -3224,7 +3966,8 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
UnqualifiedId &Name,
ParsedType ObjectType,
bool EnteringContext,
- TemplateTy &Result) {
+ TemplateTy &Result,
+ bool AllowInjectedClassName) {
if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent())
Diag(TemplateKWLoc,
getLangOpts().CPlusPlus11 ?
@@ -3272,6 +4015,24 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
return TNK_Non_template;
} else {
// We found something; return it.
+ auto *LookupRD = dyn_cast<CXXRecordDecl>(LookupCtx);
+ if (!AllowInjectedClassName && SS.isSet() && LookupRD &&
+ Name.getKind() == UnqualifiedId::IK_Identifier && Name.Identifier &&
+ LookupRD->getIdentifier() == Name.Identifier) {
+ // C++14 [class.qual]p2:
+ // In a lookup in which function names are not ignored and the
+ // nested-name-specifier nominates a class C, if the name specified
+ // [...] is the injected-class-name of C, [...] the name is instead
+ // considered to name the constructor
+ //
+ // We don't get here if naming the constructor would be valid, so we
+ // just reject immediately and recover by treating the
+ // injected-class-name as naming the template.
+ Diag(Name.getLocStart(),
+ diag::ext_out_of_line_qualified_id_type_names_constructor)
+ << Name.Identifier << 0 /*injected-class-name used as template name*/
+ << 1 /*'template' keyword was used*/;
+ }
return TNK;
}
}
@@ -3326,7 +4087,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
SourceRange SR = AL.getSourceRange();
TemplateName Name = Arg.getAsTemplate();
Diag(SR.getBegin(), diag::err_template_missing_args)
- << Name << SR;
+ << (int)getTemplateNameKindForDiagnostics(Name) << Name << SR;
if (TemplateDecl *Decl = Name.getAsTemplateDecl())
Diag(Decl->getLocation(), diag::note_template_decl_here);
@@ -3388,6 +4149,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
}
}
// fallthrough
+ LLVM_FALLTHROUGH;
}
default: {
// We have a template type parameter but the template argument
@@ -3520,8 +4282,8 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);
- EnterExpressionEvaluationContext ConstantEvaluated(SemaRef,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists);
}
@@ -3657,6 +4419,39 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
TempTempParm->getDefaultArgument().getTemplateNameLoc());
}
+/// Convert a template-argument that we parsed as a type into a template, if
+/// possible. C++ permits injected-class-names to perform dual service as
+/// template template arguments and as template type arguments.
+static TemplateArgumentLoc convertTypeTemplateArgumentToTemplate(TypeLoc TLoc) {
+ // Extract and step over any surrounding nested-name-specifier.
+ NestedNameSpecifierLoc QualLoc;
+ if (auto ETLoc = TLoc.getAs<ElaboratedTypeLoc>()) {
+ if (ETLoc.getTypePtr()->getKeyword() != ETK_None)
+ return TemplateArgumentLoc();
+
+ QualLoc = ETLoc.getQualifierLoc();
+ TLoc = ETLoc.getNamedTypeLoc();
+ }
+
+ // If this type was written as an injected-class-name, it can be used as a
+ // template template argument.
+ if (auto InjLoc = TLoc.getAs<InjectedClassNameTypeLoc>())
+ return TemplateArgumentLoc(InjLoc.getTypePtr()->getTemplateName(),
+ QualLoc, InjLoc.getNameLoc());
+
+ // If this type was written as an injected-class-name, it may have been
+ // converted to a RecordType during instantiation. If the RecordType is
+ // *not* wrapped in a TemplateSpecializationType and denotes a class
+ // template specialization, it must have come from an injected-class-name.
+ if (auto RecLoc = TLoc.getAs<RecordTypeLoc>())
+ if (auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RecLoc.getDecl()))
+ return TemplateArgumentLoc(TemplateName(CTSD->getSpecializedTemplate()),
+ QualLoc, RecLoc.getNameLoc());
+
+ return TemplateArgumentLoc();
+}
+
/// \brief Check that the given template argument corresponds to the given
/// template parameter.
///
@@ -3863,6 +4658,17 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
return true;
}
+ // C++1z [temp.local]p1: (DR1004)
+ // When [the injected-class-name] is used [...] as a template-argument for
+ // a template template-parameter [...] it refers to the class template
+ // itself.
+ if (Arg.getArgument().getKind() == TemplateArgument::Type) {
+ TemplateArgumentLoc ConvertedArg = convertTypeTemplateArgumentToTemplate(
+ Arg.getTypeSourceInfo()->getTypeLoc());
+ if (!ConvertedArg.getArgument().isNull())
+ Arg = ConvertedArg;
+ }
+
switch (Arg.getArgument().getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Should never see a NULL template argument here");
@@ -3911,9 +4717,7 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
TemplateArgs.getRAngleLoc());
S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
<< (NumArgs > NumParams)
- << (isa<ClassTemplateDecl>(Template)? 0 :
- isa<FunctionTemplateDecl>(Template)? 1 :
- isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+ << (int)S.getTemplateNameKindForDiagnostics(TemplateName(Template))
<< Template << Range;
S.Diag(Template->getLocation(), diag::note_template_decl_here)
<< Params->getSourceRange();
@@ -3978,11 +4782,11 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
-bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
- SourceLocation TemplateLoc,
- TemplateArgumentListInfo &TemplateArgs,
- bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted) {
+bool Sema::CheckTemplateArgumentList(
+ TemplateDecl *Template, SourceLocation TemplateLoc,
+ TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
+ SmallVectorImpl<TemplateArgument> &Converted,
+ bool UpdateArgsWithConversions) {
// Make a copy of the template arguments for processing. Only make the
// changes at the end when successful in matching the arguments to the
// template.
@@ -4021,9 +4825,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// Not enough arguments for this parameter pack.
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
<< false
- << (isa<ClassTemplateDecl>(Template)? 0 :
- isa<FunctionTemplateDecl>(Template)? 1 :
- isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+ << (int)getTemplateNameKindForDiagnostics(TemplateName(Template))
<< Template;
Diag(Template->getLocation(), diag::note_template_decl_here)
<< Params->getSourceRange();
@@ -4222,7 +5024,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// No problems found with the new argument list, propagate changes back
// to caller.
- TemplateArgs = std::move(NewArgs);
+ if (UpdateArgsWithConversions)
+ TemplateArgs = std::move(NewArgs);
return false;
}
@@ -4362,6 +5165,11 @@ bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) {
return Visit(T->getDeducedType());
}
+bool UnnamedLocalNoLinkageFinder::VisitDeducedTemplateSpecializationType(
+ const DeducedTemplateSpecializationType *T) {
+ return Visit(T->getDeducedType());
+}
+
bool UnnamedLocalNoLinkageFinder::VisitRecordType(const RecordType* T) {
return VisitTagDecl(T->getDecl());
}
@@ -4511,10 +5319,16 @@ enum NullPointerValueKind {
/// value of the appropriate type.
static NullPointerValueKind
isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
- QualType ParamType, Expr *Arg) {
+ QualType ParamType, Expr *Arg,
+ Decl *Entity = nullptr) {
if (Arg->isValueDependent() || Arg->isTypeDependent())
return NPV_NotNullPointer;
+ // dllimport'd entities aren't constant but are available inside of template
+ // arguments.
+ if (Entity && Entity->hasAttr<DLLImportAttr>())
+ return NPV_NotNullPointer;
+
if (!S.isCompleteType(Arg->getExprLoc(), ParamType))
llvm_unreachable(
"Incomplete parameter type in isNullPointerValueTemplateArgument!");
@@ -4758,14 +5572,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// If our parameter has pointer type, check for a null template value.
if (ParamType->isPointerType() || ParamType->isNullPtrType()) {
- NullPointerValueKind NPV;
- // dllimport'd entities aren't constant but are available inside of template
- // arguments.
- if (Entity && Entity->hasAttr<DLLImportAttr>())
- NPV = NPV_NotNullPointer;
- else
- NPV = isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn);
- switch (NPV) {
+ switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn,
+ Entity)) {
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
@@ -4957,39 +5765,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
TemplateArgument &Converted) {
bool Invalid = false;
- // Check for a null pointer value.
Expr *Arg = ResultArg;
- switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) {
- case NPV_Error:
- return true;
- case NPV_NullPointer:
- S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
- /*isNullPtr*/true);
- return false;
- case NPV_NotNullPointer:
- break;
- }
-
bool ObjCLifetimeConversion;
- if (S.IsQualificationConversion(Arg->getType(),
- ParamType.getNonReferenceType(),
- false, ObjCLifetimeConversion)) {
- Arg = S.ImpCastExprToType(Arg, ParamType, CK_NoOp,
- Arg->getValueKind()).get();
- ResultArg = Arg;
- } else if (!S.Context.hasSameUnqualifiedType(Arg->getType(),
- ParamType.getNonReferenceType())) {
- // We can't perform this conversion.
- S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
- << Arg->getType() << ParamType << Arg->getSourceRange();
- S.Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
-
- // See through any implicit casts we added to fix the type.
- while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
- Arg = Cast->getSubExpr();
// C++ [temp.arg.nontype]p1:
//
@@ -5046,6 +5823,37 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
DRE = nullptr;
}
+ ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr;
+
+ // Check for a null pointer value.
+ switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ResultArg,
+ Entity)) {
+ case NPV_Error:
+ return true;
+ case NPV_NullPointer:
+ S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
+ Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr*/true);
+ return false;
+ case NPV_NotNullPointer:
+ break;
+ }
+
+ if (S.IsQualificationConversion(ResultArg->getType(),
+ ParamType.getNonReferenceType(), false,
+ ObjCLifetimeConversion)) {
+ ResultArg = S.ImpCastExprToType(ResultArg, ParamType, CK_NoOp,
+ ResultArg->getValueKind())
+ .get();
+ } else if (!S.Context.hasSameUnqualifiedType(
+ ResultArg->getType(), ParamType.getNonReferenceType())) {
+ // We can't perform this conversion.
+ S.Diag(ResultArg->getLocStart(), diag::err_template_arg_not_convertible)
+ << ResultArg->getType() << ParamType << ResultArg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
if (!DRE)
return S.Diag(Arg->getLocStart(),
diag::err_template_arg_not_pointer_to_member_form)
@@ -5093,6 +5901,19 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// If the parameter type somehow involves auto, deduce the type now.
if (getLangOpts().CPlusPlus1z && ParamType->isUndeducedType()) {
+ // During template argument deduction, we allow 'decltype(auto)' to
+ // match an arbitrary dependent argument.
+ // FIXME: The language rules don't say what happens in this case.
+ // FIXME: We get an opaque dependent type out of decltype(auto) if the
+ // expression is merely instantiation-dependent; is this enough?
+ if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) {
+ auto *AT = dyn_cast<AutoType>(ParamType);
+ if (AT && AT->isDecltypeAuto()) {
+ Converted = TemplateArgument(Arg);
+ return Arg;
+ }
+ }
+
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.
@@ -5160,8 +5981,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// The initialization of the parameter from the argument is
// a constant-evaluated context.
- EnterExpressionEvaluationContext ConstantEvaluated(*this,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
if (getLangOpts().CPlusPlus1z) {
// C++1z [temp.arg.nontype]p1:
@@ -5217,7 +6038,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- a temporary object
// -- a string literal
// -- the result of a typeid expression, or
- // -- a predefind __func__ variable
+ // -- a predefined __func__ variable
if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) {
if (isa<CXXUuidofExpr>(E)) {
Converted = TemplateArgument(const_cast<Expr*>(E));
@@ -5748,8 +6569,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
if (RefExpr.isInvalid())
return ExprError();
- if (T->isFunctionType() || T->isArrayType()) {
- // Decay functions and arrays.
+ if (!Context.hasSameUnqualifiedType(ParamType->getPointeeType(), T) &&
+ (T->isFunctionType() || T->isArrayType())) {
+ // Decay functions and arrays unless we're forming a pointer to array.
RefExpr = DefaultFunctionArrayConversion(RefExpr.get());
if (RefExpr.isInvalid())
return ExprError();
@@ -5838,15 +6660,6 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
return E;
}
-static bool isDependentOnOuter(NonTypeTemplateParmDecl *NTTP) {
- if (NTTP->getDepth() == 0 || !NTTP->getType()->isDependentType())
- return false;
- DependencyChecker Checker(NTTP->getDepth(), /*IgnoreNonTypeDependent*/ false,
- /*FindLessThanDepth*/ true);
- Checker.TraverseType(NTTP->getType());
- return Checker.Match;
-}
-
/// \brief Match two template parameters within template parameter lists.
static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
bool Complain,
@@ -5903,10 +6716,11 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
// If we are matching a template template argument to a template
// template parameter and one of the non-type template parameter types
- // is dependent on an outer template's parameter, then we must wait until
- // template instantiation time to actually compare the arguments.
+ // is dependent, then we must wait until template instantiation time
+ // to actually compare the arguments.
if (Kind == Sema::TPL_TemplateTemplateArgumentMatch &&
- (isDependentOnOuter(OldNTTP) || isDependentOnOuter(NewNTTP)))
+ (OldNTTP->getType()->isDependentType() ||
+ NewNTTP->getType()->isDependentType()))
return true;
if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {
@@ -6205,7 +7019,7 @@ static bool CheckTemplateSpecializationScope(Sema &S,
// Do not warn for class scope explicit specialization during
// instantiation, warning was already emitted during pattern
// semantic analysis.
- if (!S.ActiveTemplateInstantiations.size())
+ if (!S.inTemplateInstantiation())
S.Diag(Loc, diag::ext_function_specialization_in_class)
<< Specialized;
} else {
@@ -6479,7 +7293,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
return true;
}
- bool isExplicitSpecialization = false;
+ bool isMemberSpecialization = false;
bool isPartialSpecialization = false;
// Check the validity of the template headers that introduce this
@@ -6490,7 +7304,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
KWLoc, TemplateNameLoc, SS, &TemplateId,
- TemplateParameterLists, TUK == TUK_Friend, isExplicitSpecialization,
+ TemplateParameterLists, TUK == TUK_Friend, isMemberSpecialization,
Invalid);
if (Invalid)
return true;
@@ -6540,8 +7354,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc()))
<< SourceRange(LAngleLoc, RAngleLoc);
- else
- isExplicitSpecialization = true;
} else {
assert(TUK == TUK_Friend && "should have a 'template<>' for this decl");
}
@@ -6749,7 +7561,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
NamedDecl *Hidden = nullptr;
if (Def && SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
SkipBody->ShouldSkip = true;
- makeMergedDefinitionVisible(Hidden, KWLoc);
+ makeMergedDefinitionVisible(Hidden);
// From here on out, treat this as just a redeclaration.
TUK = TUK_Declaration;
} else if (Def) {
@@ -6912,6 +7724,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
return false;
}
// Fall through
+ LLVM_FALLTHROUGH;
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
@@ -6938,6 +7751,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
return true;
}
+ llvm_unreachable("The switch over PrevTSK must be exhaustive.");
case TSK_ExplicitInstantiationDeclaration:
switch (PrevTSK) {
@@ -7219,9 +8033,13 @@ bool Sema::CheckFunctionTemplateSpecialization(
TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind();
if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation) {
Specialization->setLocation(FD->getLocation());
+ Specialization->setLexicalDeclContext(FD->getLexicalDeclContext());
// C++11 [dcl.constexpr]p1: An explicit specialization of a constexpr
// function can differ from the template declaration with respect to
// the constexpr specifier.
+ // FIXME: We need an update record for this AST mutation.
+ // FIXME: What if there are multiple such prior declarations (for instance,
+ // from different modules)?
Specialization->setConstexpr(FD->isConstexpr());
}
@@ -7269,11 +8087,14 @@ bool Sema::CheckFunctionTemplateSpecialization(
// flag to not-deleted, so that we can inherit that information from 'FD'.
if (Specialization->isDeleted() && !SpecInfo->isExplicitSpecialization() &&
!Specialization->getCanonicalDecl()->isReferenced()) {
+ // FIXME: This assert will not hold in the presence of modules.
assert(
Specialization->getCanonicalDecl() == Specialization &&
"This must be the only existing declaration of this specialization");
+ // FIXME: We need an update record for this AST mutation.
Specialization->setDeletedAsWritten(false);
}
+ // FIXME: We need an update record for this AST mutation.
SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
MarkUnusedFileScopedDecl(Specialization);
}
@@ -7384,8 +8205,11 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
return false;
}
- // If this is a friend, just bail out here before we start turning
- // things into explicit specializations.
+ // A member specialization in a friend declaration isn't really declaring
+ // an explicit specialization, just identifying a specific (possibly implicit)
+ // specialization. Don't change the template specialization kind.
+ //
+ // FIXME: Is this really valid? Other compilers reject.
if (Member->getFriendObjectKind() != Decl::FOK_None) {
// Preserve instantiation information.
if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) {
@@ -7435,66 +8259,36 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
false))
return true;
- // Note that this is an explicit instantiation of a member.
- // the original declaration to note that it is an explicit specialization
- // (if it was previously an implicit instantiation). This latter step
- // makes bookkeeping easier.
- if (isa<FunctionDecl>(Member)) {
+ // Note that this member specialization is an "instantiation of" the
+ // corresponding member of the original template.
+ if (auto *MemberFunction = dyn_cast<FunctionDecl>(Member)) {
FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation);
if (InstantiationFunction->getTemplateSpecializationKind() ==
TSK_ImplicitInstantiation) {
- InstantiationFunction->setTemplateSpecializationKind(
- TSK_ExplicitSpecialization);
- InstantiationFunction->setLocation(Member->getLocation());
// Explicit specializations of member functions of class templates do not
// inherit '=delete' from the member function they are specializing.
if (InstantiationFunction->isDeleted()) {
+ // FIXME: This assert will not hold in the presence of modules.
assert(InstantiationFunction->getCanonicalDecl() ==
InstantiationFunction);
+ // FIXME: We need an update record for this AST mutation.
InstantiationFunction->setDeletedAsWritten(false);
}
}
- cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
- cast<CXXMethodDecl>(InstantiatedFrom),
- TSK_ExplicitSpecialization);
- MarkUnusedFileScopedDecl(InstantiationFunction);
- } else if (isa<VarDecl>(Member)) {
- VarDecl *InstantiationVar = cast<VarDecl>(Instantiation);
- if (InstantiationVar->getTemplateSpecializationKind() ==
- TSK_ImplicitInstantiation) {
- InstantiationVar->setTemplateSpecializationKind(
- TSK_ExplicitSpecialization);
- InstantiationVar->setLocation(Member->getLocation());
- }
-
- cast<VarDecl>(Member)->setInstantiationOfStaticDataMember(
+ MemberFunction->setInstantiationOfMemberFunction(
+ cast<CXXMethodDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
+ } else if (auto *MemberVar = dyn_cast<VarDecl>(Member)) {
+ MemberVar->setInstantiationOfStaticDataMember(
cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
- MarkUnusedFileScopedDecl(InstantiationVar);
- } else if (isa<CXXRecordDecl>(Member)) {
- CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
- if (InstantiationClass->getTemplateSpecializationKind() ==
- TSK_ImplicitInstantiation) {
- InstantiationClass->setTemplateSpecializationKind(
- TSK_ExplicitSpecialization);
- InstantiationClass->setLocation(Member->getLocation());
- }
-
- cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
- cast<CXXRecordDecl>(InstantiatedFrom),
- TSK_ExplicitSpecialization);
- } else {
- assert(isa<EnumDecl>(Member) && "Only member enums remain");
- EnumDecl *InstantiationEnum = cast<EnumDecl>(Instantiation);
- if (InstantiationEnum->getTemplateSpecializationKind() ==
- TSK_ImplicitInstantiation) {
- InstantiationEnum->setTemplateSpecializationKind(
- TSK_ExplicitSpecialization);
- InstantiationEnum->setLocation(Member->getLocation());
- }
-
- cast<EnumDecl>(Member)->setInstantiationOfMemberEnum(
+ } else if (auto *MemberClass = dyn_cast<CXXRecordDecl>(Member)) {
+ MemberClass->setInstantiationOfMemberClass(
+ cast<CXXRecordDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
+ } else if (auto *MemberEnum = dyn_cast<EnumDecl>(Member)) {
+ MemberEnum->setInstantiationOfMemberEnum(
cast<EnumDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
+ } else {
+ llvm_unreachable("unknown member specialization kind");
}
// Save the caller the trouble of having to figure out which declaration
@@ -7504,6 +8298,43 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
return false;
}
+/// Complete the explicit specialization of a member of a class template by
+/// updating the instantiated member to be marked as an explicit specialization.
+///
+/// \param OrigD The member declaration instantiated from the template.
+/// \param Loc The location of the explicit specialization of the member.
+template<typename DeclT>
+static void completeMemberSpecializationImpl(Sema &S, DeclT *OrigD,
+ SourceLocation Loc) {
+ if (OrigD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
+ return;
+
+ // FIXME: Inform AST mutation listeners of this AST mutation.
+ // FIXME: If there are multiple in-class declarations of the member (from
+ // multiple modules, or a declaration and later definition of a member type),
+ // should we update all of them?
+ OrigD->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
+ OrigD->setLocation(Loc);
+}
+
+void Sema::CompleteMemberSpecialization(NamedDecl *Member,
+ LookupResult &Previous) {
+ NamedDecl *Instantiation = cast<NamedDecl>(Member->getCanonicalDecl());
+ if (Instantiation == Member)
+ return;
+
+ if (auto *Function = dyn_cast<CXXMethodDecl>(Instantiation))
+ completeMemberSpecializationImpl(*this, Function, Member->getLocation());
+ else if (auto *Var = dyn_cast<VarDecl>(Instantiation))
+ completeMemberSpecializationImpl(*this, Var, Member->getLocation());
+ else if (auto *Record = dyn_cast<CXXRecordDecl>(Instantiation))
+ completeMemberSpecializationImpl(*this, Record, Member->getLocation());
+ else if (auto *Enum = dyn_cast<EnumDecl>(Instantiation))
+ completeMemberSpecializationImpl(*this, Enum, Member->getLocation());
+ else
+ llvm_unreachable("unknown member specialization kind");
+}
+
/// \brief Check the scope of an explicit instantiation.
///
/// \returns true if a serious error occurs, false otherwise.
@@ -7910,7 +8741,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(), Owned, IsDependent,
SourceLocation(), false, TypeResult(),
- /*IsTypeSpecifier*/false);
+ /*IsTypeSpecifier*/false,
+ /*IsTemplateParamOrArg*/false);
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
@@ -8087,6 +8919,14 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
+ // A deduction guide is not on the list of entities that can be explicitly
+ // instantiated.
+ if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
+ Diag(D.getDeclSpec().getLocStart(), diag::err_deduction_guide_specialized)
+ << /*explicit instantiation*/ 0;
+ return true;
+ }
+
// C++0x [temp.explicit]p2:
// There are two forms of explicit instantiation: an explicit instantiation
// definition and an explicit instantiation declaration. An explicit
@@ -8248,7 +9088,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// A member function [...] of a class template can be explicitly
// instantiated from the member definition associated with its class
// template.
- UnresolvedSet<8> Matches;
+ UnresolvedSet<8> TemplateMatches;
+ FunctionDecl *NonTemplateMatch = nullptr;
AttributeList *Attr = D.getDeclSpec().getAttributes().getList();
TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc());
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
@@ -8259,11 +9100,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
QualType Adjusted = adjustCCAndNoReturn(R, Method->getType(),
/*AdjustExceptionSpec*/true);
if (Context.hasSameUnqualifiedType(Method->getType(), Adjusted)) {
- Matches.clear();
-
- Matches.addDecl(Method, P.getAccess());
- if (Method->getTemplateSpecializationKind() == TSK_Undeclared)
- break;
+ if (Method->getPrimaryTemplate()) {
+ TemplateMatches.addDecl(Method, P.getAccess());
+ } else {
+ // FIXME: Can this assert ever happen? Needs a test.
+ assert(!NonTemplateMatch && "Multiple NonTemplateMatches");
+ NonTemplateMatch = Method;
+ }
}
}
}
@@ -8302,22 +9145,25 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
continue;
}
- Matches.addDecl(Specialization, P.getAccess());
+ TemplateMatches.addDecl(Specialization, P.getAccess());
}
- // Find the most specialized function template specialization.
- UnresolvedSetIterator Result = getMostSpecialized(
- Matches.begin(), Matches.end(), FailedCandidates,
- D.getIdentifierLoc(),
- PDiag(diag::err_explicit_instantiation_not_known) << Name,
- PDiag(diag::err_explicit_instantiation_ambiguous) << Name,
- PDiag(diag::note_explicit_instantiation_candidate));
-
- if (Result == Matches.end())
- return true;
+ FunctionDecl *Specialization = NonTemplateMatch;
+ if (!Specialization) {
+ // Find the most specialized function template specialization.
+ UnresolvedSetIterator Result = getMostSpecialized(
+ TemplateMatches.begin(), TemplateMatches.end(), FailedCandidates,
+ D.getIdentifierLoc(),
+ PDiag(diag::err_explicit_instantiation_not_known) << Name,
+ PDiag(diag::err_explicit_instantiation_ambiguous) << Name,
+ PDiag(diag::note_explicit_instantiation_candidate));
+
+ if (Result == TemplateMatches.end())
+ return true;
- // Ignore access control bits, we don't need them for redeclaration checking.
- FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
+ // Ignore access control bits, we don't need them for redeclaration checking.
+ Specialization = cast<FunctionDecl>(*Result);
+ }
// C++11 [except.spec]p4
// In an explicit instantiation an exception-specification may be specified,
@@ -8491,7 +9337,8 @@ Sema::ActOnTypenameType(Scope *S,
const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
TemplateTy TemplateIn,
- SourceLocation TemplateNameLoc,
+ IdentifierInfo *TemplateII,
+ SourceLocation TemplateIILoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc) {
@@ -8502,6 +9349,19 @@ Sema::ActOnTypenameType(Scope *S,
diag::ext_typename_outside_of_template)
<< FixItHint::CreateRemoval(TypenameLoc);
+ // Strangely, non-type results are not ignored by this lookup, so the
+ // program is ill-formed if it finds an injected-class-name.
+ if (TypenameLoc.isValid()) {
+ auto *LookupRD =
+ dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, false));
+ if (LookupRD && LookupRD->getIdentifier() == TemplateII) {
+ Diag(TemplateIILoc,
+ diag::ext_out_of_line_qualified_id_type_names_constructor)
+ << TemplateII << 0 /*injected-class-name used as template name*/
+ << (TemplateKWLoc.isValid() ? 1 : 0 /*'template'/'typename' keyword*/);
+ }
+ }
+
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
@@ -8523,7 +9383,7 @@ Sema::ActOnTypenameType(Scope *S,
SpecTL.setElaboratedKeywordLoc(TypenameLoc);
SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
- SpecTL.setTemplateNameLoc(TemplateNameLoc);
+ SpecTL.setTemplateNameLoc(TemplateIILoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
@@ -8531,7 +9391,7 @@ Sema::ActOnTypenameType(Scope *S,
return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
}
- QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
+ QualType T = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
if (T.isNull())
return true;
@@ -8540,7 +9400,7 @@ Sema::ActOnTypenameType(Scope *S,
TemplateSpecializationTypeLoc SpecTL
= Builder.push<TemplateSpecializationTypeLoc>(T);
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
- SpecTL.setTemplateNameLoc(TemplateNameLoc);
+ SpecTL.setTemplateNameLoc(TemplateIILoc);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
@@ -8559,7 +9419,7 @@ Sema::ActOnTypenameType(Scope *S,
/// Determine whether this failed name lookup should be treated as being
/// disabled by a usage of std::enable_if.
static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
- SourceRange &CondRange) {
+ SourceRange &CondRange, Expr *&Cond) {
// We must be looking for a ::type...
if (!II.isStr("type"))
return false;
@@ -8589,6 +9449,19 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
// Assume the first template argument is the condition.
CondRange = EnableIfTSTLoc.getArgLoc(0).getSourceRange();
+
+ // Dig out the condition.
+ Cond = nullptr;
+ if (EnableIfTSTLoc.getArgLoc(0).getArgument().getKind()
+ != TemplateArgument::Expression)
+ return true;
+
+ Cond = EnableIfTSTLoc.getArgLoc(0).getSourceExpression();
+
+ // Ignore Boolean literals; they add no value.
+ if (isa<CXXBoolLiteralExpr>(Cond->IgnoreParenCasts()))
+ Cond = nullptr;
+
return true;
}
@@ -8632,9 +9505,25 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// If we're looking up 'type' within a template named 'enable_if', produce
// a more specific diagnostic.
SourceRange CondRange;
- if (isEnableIf(QualifierLoc, II, CondRange)) {
+ Expr *Cond = nullptr;
+ if (isEnableIf(QualifierLoc, II, CondRange, Cond)) {
+ // If we have a condition, narrow it down to the specific failed
+ // condition.
+ if (Cond) {
+ Expr *FailedCond;
+ std::string FailedDescription;
+ std::tie(FailedCond, FailedDescription) =
+ findFailedEnableIfCondition(*this, Cond);
+
+ Diag(FailedCond->getExprLoc(),
+ diag::err_typename_nested_not_found_requirement)
+ << FailedDescription
+ << FailedCond->getSourceRange();
+ return QualType();
+ }
+
Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if)
- << Ctx << CondRange;
+ << Ctx << CondRange;
return QualType();
}
@@ -8658,6 +9547,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
}
// Fall through to create a dependent typename type, from which we can recover
// better.
+ LLVM_FALLTHROUGH;
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
@@ -8667,14 +9557,49 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
+ // C++ [class.qual]p2:
+ // In a lookup in which function names are not ignored and the
+ // nested-name-specifier nominates a class C, if the name specified
+ // after the nested-name-specifier, when looked up in C, is the
+ // injected-class-name of C [...] then the name is instead considered
+ // to name the constructor of class C.
+ //
+ // Unlike in an elaborated-type-specifier, function names are not ignored
+ // in typename-specifier lookup. However, they are ignored in all the
+ // contexts where we form a typename type with no keyword (that is, in
+ // mem-initializer-ids, base-specifiers, and elaborated-type-specifiers).
+ //
+ // FIXME: That's not strictly true: mem-initializer-id lookup does not
+ // ignore functions, but that appears to be an oversight.
+ auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(Ctx);
+ auto *FoundRD = dyn_cast<CXXRecordDecl>(Type);
+ if (Keyword == ETK_Typename && LookupRD && FoundRD &&
+ FoundRD->isInjectedClassName() &&
+ declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent())))
+ Diag(IILoc, diag::ext_out_of_line_qualified_id_type_names_constructor)
+ << &II << 1 << 0 /*'typename' keyword used*/;
+
// We found a type. Build an ElaboratedType, since the
// typename-specifier was just sugar.
MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
- return Context.getElaboratedType(ETK_Typename,
+ return Context.getElaboratedType(Keyword,
QualifierLoc.getNestedNameSpecifier(),
Context.getTypeDeclType(Type));
}
+ // C++ [dcl.type.simple]p2:
+ // A type-specifier of the form
+ // typename[opt] nested-name-specifier[opt] template-name
+ // is a placeholder for a deduced class type [...].
+ if (getLangOpts().CPlusPlus1z) {
+ if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) {
+ return Context.getElaboratedType(
+ Keyword, QualifierLoc.getNestedNameSpecifier(),
+ Context.getDeducedTemplateSpecializationType(TemplateName(TD),
+ QualType(), false));
+ }
+ }
+
DiagID = diag::err_typename_nested_not_type;
Referenced = Result.getFoundDecl();
break;
@@ -8991,7 +9916,7 @@ private:
IsHiddenExplicitSpecialization =
Spec->getMemberSpecializationInfo()
? !S.hasVisibleMemberSpecialization(Spec, &Modules)
- : !S.hasVisibleDeclaration(Spec);
+ : !S.hasVisibleExplicitSpecialization(Spec, &Modules);
} else {
checkInstantiated(Spec);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp
index 93e796e..983b1ea 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -56,8 +56,12 @@ namespace clang {
TDF_TopLevelParameterTypeList = 0x10,
/// \brief Within template argument deduction from overload resolution per
/// C++ [over.over] allow matching function types that are compatible in
- /// terms of noreturn and default calling convention adjustments.
- TDF_InOverloadResolution = 0x20
+ /// terms of noreturn and default calling convention adjustments, or
+ /// similarly matching a declared template specialization against a
+ /// possible template, per C++ [temp.deduct.decl]. In either case, permit
+ /// deduction where the parameter is a function type that can be converted
+ /// to the argument type.
+ TDF_AllowCompatibleFunctionType = 0x20,
};
}
@@ -112,6 +116,15 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch);
+static void MarkUsedTemplateParameters(ASTContext &Ctx,
+ const TemplateArgument &TemplateArg,
+ bool OnlyDeduced, unsigned Depth,
+ llvm::SmallBitVector &Used);
+
+static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
+ bool OnlyDeduced, unsigned Level,
+ llvm::SmallBitVector &Deduced);
+
/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
/// non-type template parameter.
@@ -334,12 +347,24 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
if (!S.getLangOpts().CPlusPlus1z)
return Sema::TDK_Success;
+ if (NTTP->isExpandedParameterPack())
+ // FIXME: We may still need to deduce parts of the type here! But we
+ // don't have any way to find which slice of the type to use, and the
+ // type stored on the NTTP itself is nonsense. Perhaps the type of an
+ // expanded NTTP should be a pack expansion type?
+ return Sema::TDK_Success;
+
+ // Get the type of the parameter for deduction.
+ QualType ParamType = NTTP->getType();
+ if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType))
+ ParamType = Expansion->getPattern();
+
// FIXME: It's not clear how deduction of a parameter of reference
// type from an argument (of non-reference type) should be performed.
// For now, we just remove reference types from both sides and let
// the final check for matching types sort out the mess.
return DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, NTTP->getType().getNonReferenceType(),
+ S, TemplateParams, ParamType.getNonReferenceType(),
ValueType.getNonReferenceType(), Info, Deduced, TDF_SkipNonDependent,
/*PartialOrdering=*/false,
/*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound());
@@ -617,29 +642,68 @@ public:
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info, TemplateArgument Pattern)
: S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) {
+ // Dig out the partially-substituted pack, if there is one.
+ const TemplateArgument *PartialPackArgs = nullptr;
+ unsigned NumPartialPackArgs = 0;
+ std::pair<unsigned, unsigned> PartialPackDepthIndex(-1u, -1u);
+ if (auto *Scope = S.CurrentInstantiationScope)
+ if (auto *Partial = Scope->getPartiallySubstitutedPack(
+ &PartialPackArgs, &NumPartialPackArgs))
+ PartialPackDepthIndex = getDepthAndIndex(Partial);
+
// Compute the set of template parameter indices that correspond to
// parameter packs expanded by the pack expansion.
{
llvm::SmallBitVector SawIndices(TemplateParams->size());
+
+ auto AddPack = [&](unsigned Index) {
+ if (SawIndices[Index])
+ return;
+ SawIndices[Index] = true;
+
+ // Save the deduced template argument for the parameter pack expanded
+ // by this pack expansion, then clear out the deduction.
+ DeducedPack Pack(Index);
+ Pack.Saved = Deduced[Index];
+ Deduced[Index] = TemplateArgument();
+
+ Packs.push_back(Pack);
+ };
+
+ // First look for unexpanded packs in the pattern.
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
unsigned Depth, Index;
std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
- if (Depth == Info.getDeducedDepth() && !SawIndices[Index]) {
- SawIndices[Index] = true;
-
- // Save the deduced template argument for the parameter pack expanded
- // by this pack expansion, then clear out the deduction.
- DeducedPack Pack(Index);
- Pack.Saved = Deduced[Index];
- Deduced[Index] = TemplateArgument();
-
- Packs.push_back(Pack);
- }
+ if (Depth == Info.getDeducedDepth())
+ AddPack(Index);
}
+ assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
+
+ // This pack expansion will have been partially expanded iff the only
+ // unexpanded parameter pack within it is the partially-substituted pack.
+ IsPartiallyExpanded =
+ Packs.size() == 1 &&
+ PartialPackDepthIndex ==
+ std::make_pair(Info.getDeducedDepth(), Packs.front().Index);
+
+ // Skip over the pack elements that were expanded into separate arguments.
+ if (IsPartiallyExpanded)
+ PackElements += NumPartialPackArgs;
+
+ // We can also have deduced template parameters that do not actually
+ // appear in the pattern, but can be deduced by it (the type of a non-type
+ // template parameter pack, in particular). These won't have prevented us
+ // from partially expanding the pack.
+ llvm::SmallBitVector Used(TemplateParams->size());
+ MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true,
+ Info.getDeducedDepth(), Used);
+ for (int Index = Used.find_first(); Index != -1;
+ Index = Used.find_next(Index))
+ if (TemplateParams->getParam(Index)->isParameterPack())
+ AddPack(Index);
}
- assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
for (auto &Pack : Packs) {
if (Info.PendingDeducedPacks.size() > Pack.Index)
@@ -648,18 +712,19 @@ public:
Info.PendingDeducedPacks.resize(Pack.Index + 1);
Info.PendingDeducedPacks[Pack.Index] = &Pack;
- if (S.CurrentInstantiationScope) {
- // If the template argument pack was explicitly specified, add that to
- // the set of deduced arguments.
- const TemplateArgument *ExplicitArgs;
- unsigned NumExplicitArgs;
- NamedDecl *PartiallySubstitutedPack =
- S.CurrentInstantiationScope->getPartiallySubstitutedPack(
- &ExplicitArgs, &NumExplicitArgs);
- if (PartiallySubstitutedPack &&
- getDepthAndIndex(PartiallySubstitutedPack) ==
- std::make_pair(Info.getDeducedDepth(), Pack.Index))
- Pack.New.append(ExplicitArgs, ExplicitArgs + NumExplicitArgs);
+ if (PartialPackDepthIndex ==
+ std::make_pair(Info.getDeducedDepth(), Pack.Index)) {
+ Pack.New.append(PartialPackArgs, PartialPackArgs + NumPartialPackArgs);
+ // We pre-populate the deduced value of the partially-substituted
+ // pack with the specified value. This is not entirely correct: the
+ // value is supposed to have been substituted, not deduced, but the
+ // cases where this is observable require an exact type match anyway.
+ //
+ // FIXME: If we could represent a "depth i, index j, pack elem k"
+ // parameter, we could substitute the partially-substituted pack
+ // everywhere and avoid this.
+ if (Pack.New.size() > PackElements)
+ Deduced[Pack.Index] = Pack.New[PackElements];
}
}
}
@@ -671,16 +736,7 @@ public:
/// Determine whether this pack has already been partially expanded into a
/// sequence of (prior) function parameters / template arguments.
- bool isPartiallyExpanded() {
- if (Packs.size() != 1 || !S.CurrentInstantiationScope)
- return false;
-
- auto *PartiallySubstitutedPack =
- S.CurrentInstantiationScope->getPartiallySubstitutedPack();
- return PartiallySubstitutedPack &&
- getDepthAndIndex(PartiallySubstitutedPack) ==
- std::make_pair(Info.getDeducedDepth(), Packs.front().Index);
- }
+ bool isPartiallyExpanded() { return IsPartiallyExpanded; }
/// Move to deducing the next element in each pack that is being deduced.
void nextPackElement() {
@@ -692,8 +748,13 @@ public:
if (!Pack.New.empty() || !DeducedArg.isNull()) {
while (Pack.New.size() < PackElements)
Pack.New.push_back(DeducedTemplateArgument());
- Pack.New.push_back(DeducedArg);
- DeducedArg = DeducedTemplateArgument();
+ if (Pack.New.size() == PackElements)
+ Pack.New.push_back(DeducedArg);
+ else
+ Pack.New[PackElements] = DeducedArg;
+ DeducedArg = Pack.New.size() > PackElements + 1
+ ? Pack.New[PackElements + 1]
+ : DeducedTemplateArgument();
}
}
++PackElements;
@@ -730,6 +791,11 @@ public:
std::copy(Pack.New.begin(), Pack.New.end(), ArgumentPack);
NewPack = DeducedTemplateArgument(
TemplateArgument(llvm::makeArrayRef(ArgumentPack, Pack.New.size())),
+ // FIXME: This is wrong, it's possible that some pack elements are
+ // deduced from an array bound and others are not:
+ // template<typename ...T, T ...V> void g(const T (&...p)[V]);
+ // g({1, 2, 3}, {{}, {}});
+ // ... should deduce T = {int, size_t (from array bound)}.
Pack.New[0].wasDeducedFromArrayBound());
}
@@ -779,6 +845,7 @@ private:
SmallVectorImpl<DeducedTemplateArgument> &Deduced;
TemplateDeductionInfo &Info;
unsigned PackElements = 0;
+ bool IsPartiallyExpanded = false;
SmallVector<DeducedPack, 2> Packs;
};
@@ -963,6 +1030,32 @@ bool Sema::isSameOrCompatibleFunctionType(CanQualType Param,
return Param == Arg;
}
+/// Get the index of the first template parameter that was originally from the
+/// innermost template-parameter-list. This is 0 except when we concatenate
+/// the template parameter lists of a class template and a constructor template
+/// when forming an implicit deduction guide.
+static unsigned getFirstInnerIndex(FunctionTemplateDecl *FTD) {
+ auto *Guide = dyn_cast<CXXDeductionGuideDecl>(FTD->getTemplatedDecl());
+ if (!Guide || !Guide->isImplicit())
+ return 0;
+ return Guide->getDeducedTemplate()->getTemplateParameters()->size();
+}
+
+/// Determine whether a type denotes a forwarding reference.
+static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
+ // C++1z [temp.deduct.call]p3:
+ // A forwarding reference is an rvalue reference to a cv-unqualified
+ // template parameter that does not represent a template parameter of a
+ // class template.
+ if (auto *ParamRef = Param->getAs<RValueReferenceType>()) {
+ if (ParamRef->getPointeeType().getQualifiers())
+ return false;
+ auto *TypeParm = ParamRef->getPointeeType()->getAs<TemplateTypeParmType>();
+ return TypeParm && TypeParm->getIndex() >= FirstInnerIndex;
+ }
+ return false;
+}
+
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
@@ -1083,21 +1176,15 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// taking the address of a function template (14.8.2.2) or when deducing
// template arguments from a function declaration (14.8.2.6) and Pi and
// Ai are parameters of the top-level parameter-type-list of P and A,
- // respectively, Pi is adjusted if it is an rvalue reference to a
- // cv-unqualified template parameter and Ai is an lvalue reference, in
+ // respectively, Pi is adjusted if it is a forwarding reference and Ai
+ // is an lvalue reference, in
// which case the type of Pi is changed to be the template parameter
// type (i.e., T&& is changed to simply T). [ Note: As a result, when
// Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be
// deduced as X&. - end note ]
TDF &= ~TDF_TopLevelParameterTypeList;
-
- if (const RValueReferenceType *ParamRef
- = Param->getAs<RValueReferenceType>()) {
- if (isa<TemplateTypeParmType>(ParamRef->getPointeeType()) &&
- !ParamRef->getPointeeType().getQualifiers())
- if (Arg->isLValueReferenceType())
- Param = ParamRef->getPointeeType();
- }
+ if (isForwardingReference(Param, 0) && Arg->isLValueReferenceType())
+ Param = Param->getPointeeType();
}
}
@@ -1223,9 +1310,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// If the parameter type is not dependent, there is nothing to deduce.
if (!Param->isDependentType()) {
if (!(TDF & TDF_SkipNonDependent)) {
- bool NonDeduced = (TDF & TDF_InOverloadResolution)?
- !S.isSameOrCompatibleFunctionType(CanParam, CanArg) :
- Param != Arg;
+ bool NonDeduced =
+ (TDF & TDF_AllowCompatibleFunctionType)
+ ? !S.isSameOrCompatibleFunctionType(CanParam, CanArg)
+ : Param != Arg;
if (NonDeduced) {
return Sema::TDK_NonDeducedMismatch;
}
@@ -1235,10 +1323,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
} else if (!Param->isDependentType()) {
CanQualType ParamUnqualType = CanParam.getUnqualifiedType(),
ArgUnqualType = CanArg.getUnqualifiedType();
- bool Success = (TDF & TDF_InOverloadResolution)?
- S.isSameOrCompatibleFunctionType(ParamUnqualType,
- ArgUnqualType) :
- ParamUnqualType == ArgUnqualType;
+ bool Success =
+ (TDF & TDF_AllowCompatibleFunctionType)
+ ? S.isSameOrCompatibleFunctionType(ParamUnqualType, ArgUnqualType)
+ : ParamUnqualType == ArgUnqualType;
if (Success)
return Sema::TDK_Success;
}
@@ -1441,17 +1529,56 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
return Sema::TDK_NonDeducedMismatch;
// Check return types.
- if (Sema::TemplateDeductionResult Result =
- DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, FunctionProtoParam->getReturnType(),
- FunctionProtoArg->getReturnType(), Info, Deduced, 0))
+ if (auto Result = DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, FunctionProtoParam->getReturnType(),
+ FunctionProtoArg->getReturnType(), Info, Deduced, 0))
+ return Result;
+
+ // Check parameter types.
+ if (auto Result = DeduceTemplateArguments(
+ S, TemplateParams, FunctionProtoParam->param_type_begin(),
+ FunctionProtoParam->getNumParams(),
+ FunctionProtoArg->param_type_begin(),
+ FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF))
return Result;
- return DeduceTemplateArguments(
- S, TemplateParams, FunctionProtoParam->param_type_begin(),
- FunctionProtoParam->getNumParams(),
- FunctionProtoArg->param_type_begin(),
- FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF);
+ if (TDF & TDF_AllowCompatibleFunctionType)
+ return Sema::TDK_Success;
+
+ // FIXME: Per core-2016/10/1019 (no corresponding core issue yet), permit
+ // deducing through the noexcept-specifier if it's part of the canonical
+ // type. libstdc++ relies on this.
+ Expr *NoexceptExpr = FunctionProtoParam->getNoexceptExpr();
+ if (NonTypeTemplateParmDecl *NTTP =
+ NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
+ : nullptr) {
+ assert(NTTP->getDepth() == Info.getDeducedDepth() &&
+ "saw non-type template parameter with wrong depth");
+
+ llvm::APSInt Noexcept(1);
+ switch (FunctionProtoArg->canThrow(S.Context)) {
+ case CT_Cannot:
+ Noexcept = 1;
+ LLVM_FALLTHROUGH;
+
+ case CT_Can:
+ // We give E in noexcept(E) the "deduced from array bound" treatment.
+ // FIXME: Should we?
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy,
+ /*ArrayBound*/true, Info, Deduced);
+
+ case CT_Dependent:
+ if (Expr *ArgNoexceptExpr = FunctionProtoArg->getNoexceptExpr())
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced);
+ // Can't deduce anything from throw(T...).
+ break;
+ }
+ }
+ // FIXME: Detect non-deduced exception specification mismatches?
+
+ return Sema::TDK_Success;
}
case Type::InjectedClassName: {
@@ -1461,7 +1588,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
->getInjectedSpecializationType();
assert(isa<TemplateSpecializationType>(Param) &&
"injected class name is not a template specialization type");
- // fall through
+ LLVM_FALLTHROUGH;
}
// template-name<T> (where template-name refers to a class template)
@@ -1723,6 +1850,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
case Type::Decltype:
case Type::UnaryTransform:
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
case Type::DependentTemplateSpecialization:
case Type::PackExpansion:
case Type::Pipe:
@@ -2299,7 +2427,8 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
bool HasDefaultArg = false;
TemplateDecl *TD = dyn_cast<TemplateDecl>(Template);
if (!TD) {
- assert(isa<ClassTemplatePartialSpecializationDecl>(Template));
+ assert(isa<ClassTemplatePartialSpecializationDecl>(Template) ||
+ isa<VarTemplatePartialSpecializationDecl>(Template));
return Sema::TDK_Incomplete;
}
@@ -2335,7 +2464,7 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
return Sema::TDK_Success;
}
-DeclContext *getAsDeclContextOrEnclosing(Decl *D) {
+static DeclContext *getAsDeclContextOrEnclosing(Decl *D) {
if (auto *DC = dyn_cast<DeclContext>(D))
return DC;
return D->getDeclContext();
@@ -2363,7 +2492,8 @@ FinishTemplateArgumentDeduction(
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info) {
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap Trap(S);
Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Partial));
@@ -2435,13 +2565,14 @@ FinishTemplateArgumentDeduction(
/// Complete template argument deduction for a class or variable template,
/// when partial ordering against a partial specialization.
// FIXME: Factor out duplication with partial specialization version above.
-Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
+static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
Sema &S, TemplateDecl *Template, bool PartialOrdering,
const TemplateArgumentList &TemplateArgs,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info) {
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap Trap(S);
Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Template));
@@ -2491,7 +2622,8 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// list (14.8.2).
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
SmallVector<DeducedTemplateArgument, 4> Deduced;
@@ -2533,7 +2665,8 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
// list (14.8.2).
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
SmallVector<DeducedTemplateArgument, 4> Deduced;
@@ -2565,12 +2698,6 @@ static bool isSimpleTemplateIdType(QualType T) {
return false;
}
-static void
-MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
- bool OnlyDeduced,
- unsigned Level,
- llvm::SmallBitVector &Deduced);
-
/// \brief Substitute the explicitly-provided template arguments into the
/// given function template according to C++ [temp.arg.explicit].
///
@@ -2619,7 +2746,8 @@ Sema::SubstituteExplicitTemplateArguments(
}
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
// C++ [temp.arg.explicit]p3:
@@ -2633,18 +2761,15 @@ Sema::SubstituteExplicitTemplateArguments(
// explicitly-specified template arguments against this function template,
// and then substitute them into the function parameter types.
SmallVector<TemplateArgument, 4> DeducedArgs;
- InstantiatingTemplate Inst(*this, Info.getLocation(), FunctionTemplate,
- DeducedArgs,
- ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution,
- Info);
+ InstantiatingTemplate Inst(
+ *this, Info.getLocation(), FunctionTemplate, DeducedArgs,
+ CodeSynthesisContext::ExplicitTemplateArgumentSubstitution, Info);
if (Inst.isInvalid())
return TDK_InstantiationDepth;
- if (CheckTemplateArgumentList(FunctionTemplate,
- SourceLocation(),
- ExplicitTemplateArgs,
- true,
- Builder) || Trap.hasErrorOccurred()) {
+ if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(),
+ ExplicitTemplateArgs, true, Builder, false) ||
+ Trap.hasErrorOccurred()) {
unsigned Index = Builder.size();
if (Index >= TemplateParams->size())
Index = TemplateParams->size() - 1;
@@ -2739,6 +2864,17 @@ Sema::SubstituteExplicitTemplateArguments(
if (FunctionType) {
auto EPI = Proto->getExtProtoInfo();
EPI.ExtParameterInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size());
+
+ // In C++1z onwards, exception specifications are part of the function type,
+ // so substitution into the type must also substitute into the exception
+ // specification.
+ SmallVector<QualType, 4> ExceptionStorage;
+ if (getLangOpts().CPlusPlus1z &&
+ SubstExceptionSpec(
+ Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
+ MultiLevelTemplateArgumentList(*ExplicitArgumentList)))
+ return TDK_SubstitutionFailure;
+
*FunctionType = BuildFunctionType(ResultType, ParamTypes,
Function->getLocation(),
Function->getDeclName(),
@@ -2920,16 +3056,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
bool PartialOverloading, llvm::function_ref<bool()> CheckNonDependent) {
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
// Enter a new template instantiation context while we instantiate the
// actual function declaration.
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
- InstantiatingTemplate Inst(*this, Info.getLocation(), FunctionTemplate,
- DeducedArgs,
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
- Info);
+ InstantiatingTemplate Inst(
+ *this, Info.getLocation(), FunctionTemplate, DeducedArgs,
+ CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
if (Inst.isInvalid())
return TDK_InstantiationDepth;
@@ -3186,12 +3322,9 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
/// \returns true if the caller should not attempt to perform any template
/// argument deduction based on this P/A pair because the argument is an
/// overloaded function set that could not be resolved.
-static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
- TemplateParameterList *TemplateParams,
- QualType &ParamType,
- QualType &ArgType,
- Expr *Arg,
- unsigned &TDF) {
+static bool AdjustFunctionParmAndArgTypesForDeduction(
+ Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex,
+ QualType &ParamType, QualType &ArgType, Expr *Arg, unsigned &TDF) {
// C++0x [temp.deduct.call]p3:
// If P is a cv-qualified type, the top level cv-qualifiers of P's type
// are ignored for type deduction.
@@ -3222,13 +3355,10 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
ArgType = Arg->getType();
}
- // C++0x [temp.deduct.call]p3:
- // If P is an rvalue reference to a cv-unqualified template
- // parameter and the argument is an lvalue, the type "lvalue
- // reference to A" is used in place of A for type deduction.
- if (ParamRefType->isRValueReferenceType() &&
- !ParamType.getQualifiers() &&
- isa<TemplateTypeParmType>(ParamType) &&
+ // C++1z [temp.deduct.call]p3:
+ // If P is a forwarding reference and the argument is an lvalue, the type
+ // "lvalue reference to A" is used in place of A for type deduction.
+ if (isForwardingReference(QualType(ParamRefType, 0), FirstInnerIndex) &&
Arg->isLValue())
ArgType = S.Context.getLValueReferenceType(ArgType);
} else {
@@ -3287,8 +3417,8 @@ hasDeducibleTemplateParameters(Sema &S, FunctionTemplateDecl *FunctionTemplate,
QualType T);
static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
- Sema &S, TemplateParameterList *TemplateParams, QualType ParamType,
- Expr *Arg, TemplateDeductionInfo &Info,
+ Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex,
+ QualType ParamType, Expr *Arg, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
bool DecomposedParam, unsigned ArgIdx, unsigned TDF);
@@ -3326,7 +3456,7 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
if (ElTy->isDependentType()) {
for (Expr *E : ILE->inits()) {
if (auto Result = DeduceTemplateArgumentsFromCallArgument(
- S, TemplateParams, ElTy, E, Info, Deduced, OriginalCallArgs, true,
+ S, TemplateParams, 0, ElTy, E, Info, Deduced, OriginalCallArgs, true,
ArgIdx, TDF))
return Result;
}
@@ -3340,10 +3470,12 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
getDeducedParameterFromExpr(Info, DependentArrTy->getSizeExpr())) {
// We can perform template argument deduction for the given non-type
// template parameter.
- llvm::APInt Size(S.Context.getIntWidth(NTTP->getType()),
- ILE->getNumInits());
+ // C++ [temp.deduct.type]p13:
+ // The type of N in the type T[N] is std::size_t.
+ QualType T = S.Context.getSizeType();
+ llvm::APInt Size(S.Context.getIntWidth(T), ILE->getNumInits());
if (auto Result = DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, llvm::APSInt(Size), NTTP->getType(),
+ S, TemplateParams, NTTP, llvm::APSInt(Size), T,
/*ArrayBound=*/true, Info, Deduced))
return Result;
}
@@ -3355,8 +3487,8 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
/// \brief Perform template argument deduction per [temp.deduct.call] for a
/// single parameter / argument pair.
static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
- Sema &S, TemplateParameterList *TemplateParams, QualType ParamType,
- Expr *Arg, TemplateDeductionInfo &Info,
+ Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex,
+ QualType ParamType, Expr *Arg, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
bool DecomposedParam, unsigned ArgIdx, unsigned TDF) {
@@ -3365,8 +3497,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
// If P is a reference type [...]
// If P is a cv-qualified type [...]
- if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType,
- ArgType, Arg, TDF))
+ if (AdjustFunctionParmAndArgTypesForDeduction(
+ S, TemplateParams, FirstInnerIndex, ParamType, ArgType, Arg, TDF))
return Sema::TDK_Success;
// If [...] the argument is a non-empty initializer list [...]
@@ -3422,6 +3554,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
unsigned NumParams = Function->getNumParams();
+ unsigned FirstInnerIndex = getFirstInnerIndex(FunctionTemplate);
+
// C++ [temp.deduct.call]p1:
// Template argument deduction is done by comparing each function template
// parameter type (call it P) with the type of the corresponding argument
@@ -3476,7 +3610,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// ... with the type of the corresponding argument
return DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParams, ParamType, Args[ArgIdx], Info, Deduced,
+ *this, TemplateParams, FirstInnerIndex, ParamType, Args[ArgIdx], Info, Deduced,
OriginalCallArgs, /*Decomposed*/false, ArgIdx, /*TDF*/ 0);
};
@@ -3635,13 +3769,6 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
= FunctionTemplate->getTemplateParameters();
QualType FunctionType = Function->getType();
- // When taking the address of a function, we require convertibility of
- // the resulting function type. Otherwise, we allow arbitrary mismatches
- // of calling convention, noreturn, and noexcept.
- if (!IsAddressOfFunction)
- ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType,
- /*AdjustExceptionSpec*/true);
-
// Substitute any explicit template arguments.
LocalInstantiationScope InstScope(*this);
SmallVector<DeducedTemplateArgument, 4> Deduced;
@@ -3658,8 +3785,16 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
NumExplicitlySpecified = Deduced.size();
}
+ // When taking the address of a function, we require convertibility of
+ // the resulting function type. Otherwise, we allow arbitrary mismatches
+ // of calling convention and noreturn.
+ if (!IsAddressOfFunction)
+ ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType,
+ /*AdjustExceptionSpec*/false);
+
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
Deduced.resize(TemplateParams->size());
@@ -3676,9 +3811,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
}
if (!ArgFunctionType.isNull()) {
- unsigned TDF = TDF_TopLevelParameterTypeList;
- if (IsAddressOfFunction)
- TDF |= TDF_InOverloadResolution;
+ unsigned TDF =
+ TDF_TopLevelParameterTypeList | TDF_AllowCompatibleFunctionType;
// Deduce template arguments from the function type.
if (TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
@@ -3709,7 +3843,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
return TDK_MiscellaneousDeductionFailure;
- // Adjust the exception specification of the argument again to match the
+ // Adjust the exception specification of the argument to match the
// substituted and resolved type we just formed. (Calling convention and
// noreturn can't be dependent, so we don't actually need this for them
// right now.)
@@ -3907,7 +4041,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
}
// Unevaluated SFINAE context.
- EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
// C++ [temp.deduct.conv]p1:
@@ -4020,17 +4155,26 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
}
namespace {
- /// Substitute the 'auto' type specifier within a type for a given replacement
- /// type.
- class SubstituteAutoTransform :
- public TreeTransform<SubstituteAutoTransform> {
+ /// Substitute the 'auto' specifier or deduced template specialization type
+ /// specifier within a type for a given replacement type.
+ class SubstituteDeducedTypeTransform :
+ public TreeTransform<SubstituteDeducedTypeTransform> {
QualType Replacement;
- bool UseAutoSugar;
+ bool UseTypeSugar;
public:
- SubstituteAutoTransform(Sema &SemaRef, QualType Replacement,
- bool UseAutoSugar = true)
- : TreeTransform<SubstituteAutoTransform>(SemaRef),
- Replacement(Replacement), UseAutoSugar(UseAutoSugar) {}
+ SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement,
+ bool UseTypeSugar = true)
+ : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
+ Replacement(Replacement), UseTypeSugar(UseTypeSugar) {}
+
+ QualType TransformDesugared(TypeLocBuilder &TLB, DeducedTypeLoc TL) {
+ assert(isa<TemplateTypeParmType>(Replacement) &&
+ "unexpected unsugared replacement kind");
+ QualType Result = Replacement;
+ TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ return Result;
+ }
QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) {
// If we're building the type pattern to deduce against, don't wrap the
@@ -4040,21 +4184,29 @@ namespace {
// auto &&lref = lvalue;
// must transform into "rvalue reference to T" not "rvalue reference to
// auto type deduced as T" in order for [temp.deduct.call]p3 to apply.
- if (!UseAutoSugar) {
- assert(isa<TemplateTypeParmType>(Replacement) &&
- "unexpected unsugared replacement kind");
- QualType Result = Replacement;
- TemplateTypeParmTypeLoc NewTL =
- TLB.push<TemplateTypeParmTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
- return Result;
- } else {
- QualType Result = SemaRef.Context.getAutoType(
- Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
- AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
- return Result;
- }
+ //
+ // FIXME: Is this still necessary?
+ if (!UseTypeSugar)
+ return TransformDesugared(TLB, TL);
+
+ QualType Result = SemaRef.Context.getAutoType(
+ Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
+ auto NewTL = TLB.push<AutoTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ return Result;
+ }
+
+ QualType TransformDeducedTemplateSpecializationType(
+ TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {
+ if (!UseTypeSugar)
+ return TransformDesugared(TLB, TL);
+
+ QualType Result = SemaRef.Context.getDeducedTemplateSpecializationType(
+ TL.getTypePtr()->getTemplateName(),
+ Replacement, Replacement.isNull());
+ auto NewTL = TLB.push<DeducedTemplateSpecializationTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ return Result;
}
ExprResult TransformLambdaExpr(LambdaExpr *E) {
@@ -4105,7 +4257,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (!DependentDeductionDepth &&
(Type.getType()->isDependentType() || Init->isTypeDependent())) {
- Result = SubstituteAutoTransform(*this, QualType()).Apply(Type);
+ Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
@@ -4128,7 +4280,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
// FIXME: Support a non-canonical deduced type for 'auto'.
Deduced = Context.getCanonicalType(Deduced);
- Result = SubstituteAutoTransform(*this, Deduced).Apply(Type);
+ Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
return DAR_Succeeded;
@@ -4153,7 +4305,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
Loc, Loc, TemplParamPtr, Loc, nullptr);
QualType FuncParam =
- SubstituteAutoTransform(*this, TemplArg, /*UseAutoSugar*/false)
+ SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
.Apply(Type);
assert(!FuncParam.isNull() &&
"substituting template parameter for 'auto' failed");
@@ -4168,7 +4320,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// might acquire a matching type in the instantiation.
auto DeductionFailed = [&]() -> DeduceAutoResult {
if (Init->isTypeDependent()) {
- Result = SubstituteAutoTransform(*this, QualType()).Apply(Type);
+ Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
@@ -4187,7 +4339,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
if (DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), TemplArg, InitList->getInit(i),
+ *this, TemplateParamsSt.get(), 0, TemplArg, InitList->getInit(i),
Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
/*ArgIdx*/ 0, /*TDF*/ 0))
return DeductionFailed();
@@ -4199,7 +4351,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
}
if (DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), FuncParam, Init, Info, Deduced,
+ *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
return DeductionFailed();
}
@@ -4216,7 +4368,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
- Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type);
+ Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
@@ -4239,15 +4391,22 @@ QualType Sema::SubstAutoType(QualType TypeWithAuto,
QualType TypeToReplaceAuto) {
if (TypeToReplaceAuto->isDependentType())
TypeToReplaceAuto = QualType();
- return SubstituteAutoTransform(*this, TypeToReplaceAuto)
+ return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
.TransformType(TypeWithAuto);
}
-TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
- QualType TypeToReplaceAuto) {
+TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
+ QualType TypeToReplaceAuto) {
if (TypeToReplaceAuto->isDependentType())
TypeToReplaceAuto = QualType();
- return SubstituteAutoTransform(*this, TypeToReplaceAuto)
+ return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
+ .TransformType(TypeWithAuto);
+}
+
+QualType Sema::ReplaceAutoType(QualType TypeWithAuto,
+ QualType TypeToReplaceAuto) {
+ return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto,
+ /*UseTypeSugar*/ false)
.TransformType(TypeWithAuto);
}
@@ -4848,13 +5007,6 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info);
}
-static void
-MarkUsedTemplateParameters(ASTContext &Ctx,
- const TemplateArgument &TemplateArg,
- bool OnlyDeduced,
- unsigned Depth,
- llvm::SmallBitVector &Used);
-
/// \brief Mark the template parameters that are used by the given
/// expression.
static void
@@ -4996,6 +5148,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
cast<DependentSizedArrayType>(T)->getSizeExpr(),
OnlyDeduced, Depth, Used);
// Fall through to check the element type
+ LLVM_FALLTHROUGH;
case Type::ConstantArray:
case Type::IncompleteArray:
@@ -5028,6 +5181,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
for (unsigned I = 0, N = Proto->getNumParams(); I != N; ++I)
MarkUsedTemplateParameters(Ctx, Proto->getParamType(I), OnlyDeduced,
Depth, Used);
+ if (auto *E = Proto->getNoexceptExpr())
+ MarkUsedTemplateParameters(Ctx, E, OnlyDeduced, Depth, Used);
break;
}
@@ -5154,8 +5309,9 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
break;
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
MarkUsedTemplateParameters(Ctx,
- cast<AutoType>(T)->getDeducedType(),
+ cast<DeducedType>(T)->getDeducedType(),
OnlyDeduced, Depth, Used);
// None of these types have any template parameters in them.
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 9f744a1..f4f0c80 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -184,7 +184,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
return Result;
}
-bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
+bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
switch (Kind) {
case TemplateInstantiation:
case ExceptionSpecInstantiation:
@@ -196,19 +196,20 @@ bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
return true;
case DefaultTemplateArgumentChecking:
+ case DeclaringSpecialMember:
+ case DefiningSynthesizedFunction:
return false;
}
- llvm_unreachable("Invalid InstantiationKind!");
+ llvm_unreachable("Invalid SynthesisKind!");
}
Sema::InstantiatingTemplate::InstantiatingTemplate(
- Sema &SemaRef, ActiveTemplateInstantiation::InstantiationKind Kind,
+ Sema &SemaRef, CodeSynthesisContext::SynthesisKind Kind,
SourceLocation PointOfInstantiation, SourceRange InstantiationRange,
Decl *Entity, NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
sema::TemplateDeductionInfo *DeductionInfo)
- : SemaRef(SemaRef), SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext) {
+ : SemaRef(SemaRef) {
// Don't allow further instantiation if a fatal error and an uncompilable
// error have occurred. Any diagnostics we might have raised will not be
// visible, and we do not need to construct a correct AST.
@@ -219,7 +220,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
}
Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
if (!Invalid) {
- ActiveTemplateInstantiation Inst;
+ CodeSynthesisContext Inst;
Inst.Kind = Kind;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = Entity;
@@ -228,14 +229,12 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.DeductionInfo = DeductionInfo;
Inst.InstantiationRange = InstantiationRange;
+ SemaRef.pushCodeSynthesisContext(Inst);
+
AlreadyInstantiating =
!SemaRef.InstantiatingSpecializations
.insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind))
.second;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- if (!Inst.isInstantiationRecord())
- ++SemaRef.NonInstantiationEntries;
}
}
@@ -243,14 +242,14 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity,
SourceRange InstantiationRange)
: InstantiatingTemplate(SemaRef,
- ActiveTemplateInstantiation::TemplateInstantiation,
+ CodeSynthesisContext::TemplateInstantiation,
PointOfInstantiation, InstantiationRange, Entity) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity,
ExceptionSpecification, SourceRange InstantiationRange)
: InstantiatingTemplate(
- SemaRef, ActiveTemplateInstantiation::ExceptionSpecInstantiation,
+ SemaRef, CodeSynthesisContext::ExceptionSpecInstantiation,
PointOfInstantiation, InstantiationRange, Entity) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
@@ -259,7 +258,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation,
+ CodeSynthesisContext::DefaultTemplateArgumentInstantiation,
PointOfInstantiation, InstantiationRange, getAsNamedDecl(Param),
Template, TemplateArgs) {}
@@ -267,14 +266,14 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
FunctionTemplateDecl *FunctionTemplate,
ArrayRef<TemplateArgument> TemplateArgs,
- ActiveTemplateInstantiation::InstantiationKind Kind,
+ CodeSynthesisContext::SynthesisKind Kind,
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(SemaRef, Kind, PointOfInstantiation,
InstantiationRange, FunctionTemplate, nullptr,
TemplateArgs, &DeductionInfo) {
assert(
- Kind == ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution ||
- Kind == ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
+ Kind == CodeSynthesisContext::ExplicitTemplateArgumentSubstitution ||
+ Kind == CodeSynthesisContext::DeducedTemplateArgumentSubstitution);
}
Sema::InstantiatingTemplate::InstantiatingTemplate(
@@ -284,7 +283,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ CodeSynthesisContext::DeducedTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, Template, nullptr,
TemplateArgs, &DeductionInfo) {}
@@ -295,7 +294,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ CodeSynthesisContext::DeducedTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, PartialSpec, nullptr,
TemplateArgs, &DeductionInfo) {}
@@ -306,7 +305,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ CodeSynthesisContext::DeducedTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, PartialSpec, nullptr,
TemplateArgs, &DeductionInfo) {}
@@ -315,7 +314,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation,
+ CodeSynthesisContext::DefaultFunctionArgumentInstantiation,
PointOfInstantiation, InstantiationRange, Param, nullptr,
TemplateArgs) {}
@@ -325,7 +324,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
+ CodeSynthesisContext::PriorTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
@@ -335,7 +334,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
- ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
+ CodeSynthesisContext::PriorTemplateArgumentSubstitution,
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
@@ -344,36 +343,59 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
NamedDecl *Param, ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
: InstantiatingTemplate(
- SemaRef, ActiveTemplateInstantiation::DefaultTemplateArgumentChecking,
+ SemaRef, CodeSynthesisContext::DefaultTemplateArgumentChecking,
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
+void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
+ Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
+ InNonInstantiationSFINAEContext = false;
+
+ CodeSynthesisContexts.push_back(Ctx);
+
+ if (!Ctx.isInstantiationRecord())
+ ++NonInstantiationEntries;
+}
+
+void Sema::popCodeSynthesisContext() {
+ auto &Active = CodeSynthesisContexts.back();
+ if (!Active.isInstantiationRecord()) {
+ assert(NonInstantiationEntries > 0);
+ --NonInstantiationEntries;
+ }
+
+ InNonInstantiationSFINAEContext = Active.SavedInNonInstantiationSFINAEContext;
+
+ // Name lookup no longer looks in this template's defining module.
+ assert(CodeSynthesisContexts.size() >=
+ CodeSynthesisContextLookupModules.size() &&
+ "forgot to remove a lookup module for a template instantiation");
+ if (CodeSynthesisContexts.size() ==
+ CodeSynthesisContextLookupModules.size()) {
+ if (Module *M = CodeSynthesisContextLookupModules.back())
+ LookupModulesCache.erase(M);
+ CodeSynthesisContextLookupModules.pop_back();
+ }
+
+ // If we've left the code synthesis context for the current context stack,
+ // stop remembering that we've emitted that stack.
+ if (CodeSynthesisContexts.size() ==
+ LastEmittedCodeSynthesisContextDepth)
+ LastEmittedCodeSynthesisContextDepth = 0;
+
+ CodeSynthesisContexts.pop_back();
+}
+
void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
- auto &Active = SemaRef.ActiveTemplateInstantiations.back();
- if (!Active.isInstantiationRecord()) {
- assert(SemaRef.NonInstantiationEntries > 0);
- --SemaRef.NonInstantiationEntries;
- }
- SemaRef.InNonInstantiationSFINAEContext
- = SavedInNonInstantiationSFINAEContext;
-
- // Name lookup no longer looks in this template's defining module.
- assert(SemaRef.ActiveTemplateInstantiations.size() >=
- SemaRef.ActiveTemplateInstantiationLookupModules.size() &&
- "forgot to remove a lookup module for a template instantiation");
- if (SemaRef.ActiveTemplateInstantiations.size() ==
- SemaRef.ActiveTemplateInstantiationLookupModules.size()) {
- if (Module *M = SemaRef.ActiveTemplateInstantiationLookupModules.back())
- SemaRef.LookupModulesCache.erase(M);
- SemaRef.ActiveTemplateInstantiationLookupModules.pop_back();
- }
-
- if (!AlreadyInstantiating)
+ if (!AlreadyInstantiating) {
+ auto &Active = SemaRef.CodeSynthesisContexts.back();
SemaRef.InstantiatingSpecializations.erase(
std::make_pair(Active.Entity, Active.Kind));
+ }
+
+ SemaRef.popCodeSynthesisContext();
- SemaRef.ActiveTemplateInstantiations.pop_back();
Invalid = true;
}
}
@@ -382,8 +404,8 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
SourceLocation PointOfInstantiation,
SourceRange InstantiationRange) {
assert(SemaRef.NonInstantiationEntries <=
- SemaRef.ActiveTemplateInstantiations.size());
- if ((SemaRef.ActiveTemplateInstantiations.size() -
+ SemaRef.CodeSynthesisContexts.size());
+ if ((SemaRef.CodeSynthesisContexts.size() -
SemaRef.NonInstantiationEntries)
<= SemaRef.getLangOpts().InstantiationDepth)
return false;
@@ -401,18 +423,18 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
/// notes.
void Sema::PrintInstantiationStack() {
// Determine which template instantiations to skip, if any.
- unsigned SkipStart = ActiveTemplateInstantiations.size(), SkipEnd = SkipStart;
+ unsigned SkipStart = CodeSynthesisContexts.size(), SkipEnd = SkipStart;
unsigned Limit = Diags.getTemplateBacktraceLimit();
- if (Limit && Limit < ActiveTemplateInstantiations.size()) {
+ if (Limit && Limit < CodeSynthesisContexts.size()) {
SkipStart = Limit / 2 + Limit % 2;
- SkipEnd = ActiveTemplateInstantiations.size() - Limit / 2;
+ SkipEnd = CodeSynthesisContexts.size() - Limit / 2;
}
// FIXME: In all of these cases, we need to show the template arguments
unsigned InstantiationIdx = 0;
- for (SmallVectorImpl<ActiveTemplateInstantiation>::reverse_iterator
- Active = ActiveTemplateInstantiations.rbegin(),
- ActiveEnd = ActiveTemplateInstantiations.rend();
+ for (SmallVectorImpl<CodeSynthesisContext>::reverse_iterator
+ Active = CodeSynthesisContexts.rbegin(),
+ ActiveEnd = CodeSynthesisContexts.rend();
Active != ActiveEnd;
++Active, ++InstantiationIdx) {
// Skip this instantiation?
@@ -421,13 +443,13 @@ void Sema::PrintInstantiationStack() {
// Note that we're skipping instantiations.
Diags.Report(Active->PointOfInstantiation,
diag::note_instantiation_contexts_suppressed)
- << unsigned(ActiveTemplateInstantiations.size() - Limit);
+ << unsigned(CodeSynthesisContexts.size() - Limit);
}
continue;
}
switch (Active->Kind) {
- case ActiveTemplateInstantiation::TemplateInstantiation: {
+ case CodeSynthesisContext::TemplateInstantiation: {
Decl *D = Active->Entity;
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
unsigned DiagID = diag::note_template_member_class_here;
@@ -469,7 +491,7 @@ void Sema::PrintInstantiationStack() {
break;
}
- case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: {
+ case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: {
TemplateDecl *Template = cast<TemplateDecl>(Active->Template);
SmallVector<char, 128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
@@ -483,7 +505,7 @@ void Sema::PrintInstantiationStack() {
break;
}
- case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: {
+ case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: {
FunctionTemplateDecl *FnTmpl = cast<FunctionTemplateDecl>(Active->Entity);
Diags.Report(Active->PointOfInstantiation,
diag::note_explicit_template_arg_substitution_here)
@@ -495,7 +517,7 @@ void Sema::PrintInstantiationStack() {
break;
}
- case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: {
+ case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: {
if (FunctionTemplateDecl *FnTmpl =
dyn_cast<FunctionTemplateDecl>(Active->Entity)) {
Diags.Report(Active->PointOfInstantiation,
@@ -533,7 +555,7 @@ void Sema::PrintInstantiationStack() {
break;
}
- case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: {
+ case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: {
ParmVarDecl *Param = cast<ParmVarDecl>(Active->Entity);
FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext());
@@ -549,7 +571,7 @@ void Sema::PrintInstantiationStack() {
break;
}
- case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: {
+ case CodeSynthesisContext::PriorTemplateArgumentSubstitution: {
NamedDecl *Parm = cast<NamedDecl>(Active->Entity);
std::string Name;
if (!Parm->getName().empty())
@@ -573,7 +595,7 @@ void Sema::PrintInstantiationStack() {
break;
}
- case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: {
+ case CodeSynthesisContext::DefaultTemplateArgumentChecking: {
TemplateParameterList *TemplateParams = nullptr;
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(Active->Template))
TemplateParams = Template->getTemplateParameters();
@@ -591,12 +613,29 @@ void Sema::PrintInstantiationStack() {
break;
}
- case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
+ case CodeSynthesisContext::ExceptionSpecInstantiation:
Diags.Report(Active->PointOfInstantiation,
diag::note_template_exception_spec_instantiation_here)
<< cast<FunctionDecl>(Active->Entity)
<< Active->InstantiationRange;
break;
+
+ case CodeSynthesisContext::DeclaringSpecialMember:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_in_declaration_of_implicit_special_member)
+ << cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember;
+ break;
+
+ case CodeSynthesisContext::DefiningSynthesizedFunction:
+ // FIXME: For synthesized members other than special members, produce a note.
+ auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity);
+ auto CSM = MD ? getSpecialMember(MD) : CXXInvalid;
+ if (CSM != CXXInvalid) {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_member_synthesized_at)
+ << CSM << Context.getTagDeclType(MD->getParent());
+ }
+ break;
}
}
}
@@ -605,39 +644,50 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
if (InNonInstantiationSFINAEContext)
return Optional<TemplateDeductionInfo *>(nullptr);
- for (SmallVectorImpl<ActiveTemplateInstantiation>::const_reverse_iterator
- Active = ActiveTemplateInstantiations.rbegin(),
- ActiveEnd = ActiveTemplateInstantiations.rend();
+ for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator
+ Active = CodeSynthesisContexts.rbegin(),
+ ActiveEnd = CodeSynthesisContexts.rend();
Active != ActiveEnd;
++Active)
{
- switch(Active->Kind) {
- case ActiveTemplateInstantiation::TemplateInstantiation:
+ switch (Active->Kind) {
+ case CodeSynthesisContext::TemplateInstantiation:
// An instantiation of an alias template may or may not be a SFINAE
// context, depending on what else is on the stack.
if (isa<TypeAliasTemplateDecl>(Active->Entity))
break;
// Fall through.
- case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
- case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
+ case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
+ case CodeSynthesisContext::ExceptionSpecInstantiation:
// This is a template instantiation, so there is no SFINAE.
return None;
- case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
- case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution:
- case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking:
+ case CodeSynthesisContext::DefaultTemplateArgumentInstantiation:
+ case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
+ case CodeSynthesisContext::DefaultTemplateArgumentChecking:
// A default template argument instantiation and substitution into
// template parameters with arguments for prior parameters may or may
// not be a SFINAE context; look further up the stack.
break;
- case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution:
- case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
+ case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
+ case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
// We're either substitution explicitly-specified template arguments
// or deduced template arguments, so SFINAE applies.
assert(Active->DeductionInfo && "Missing deduction info pointer");
return Active->DeductionInfo;
+
+ case CodeSynthesisContext::DeclaringSpecialMember:
+ case CodeSynthesisContext::DefiningSynthesizedFunction:
+ // This happens in a context unrelated to template instantiation, so
+ // there is no SFINAE.
+ return None;
}
+
+ // The inner context was transparent for SFINAE. If it occurred within a
+ // non-instantiation SFINAE context, then SFINAE applies.
+ if (Active->SavedInNonInstantiationSFINAEContext)
+ return Optional<TemplateDeductionInfo *>(nullptr);
}
return None;
@@ -806,7 +856,8 @@ namespace {
TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
SourceLocation NameLoc,
QualType ObjectType = QualType(),
- NamedDecl *FirstQualifierInScope = nullptr);
+ NamedDecl *FirstQualifierInScope = nullptr,
+ bool AllowInjectedClassName = false);
const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
@@ -1040,11 +1091,10 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
T);
}
-TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
- TemplateName Name,
- SourceLocation NameLoc,
- QualType ObjectType,
- NamedDecl *FirstQualifierInScope) {
+TemplateName TemplateInstantiator::TransformTemplateName(
+ CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc,
+ QualType ObjectType, NamedDecl *FirstQualifierInScope,
+ bool AllowInjectedClassName) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) {
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
@@ -1095,9 +1145,10 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
return Arg.getAsTemplate();
}
-
- return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
- FirstQualifierInScope);
+
+ return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
+ FirstQualifierInScope,
+ AllowInjectedClassName);
}
ExprResult
@@ -1120,6 +1171,23 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
return E;
TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
+
+ if (TemplateArgs.getNumLevels() != TemplateArgs.getNumSubstitutedLevels()) {
+ // We're performing a partial substitution, so the substituted argument
+ // could be dependent. As a result we can't create a SubstNonType*Expr
+ // node now, since that represents a fully-substituted argument.
+ // FIXME: We should have some AST representation for this.
+ if (Arg.getKind() == TemplateArgument::Pack) {
+ // FIXME: This won't work for alias templates.
+ assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() &&
+ "unexpected pack arguments in partial substitution");
+ Arg = Arg.pack_begin()->getPackExpansionPattern();
+ }
+ assert(Arg.getKind() == TemplateArgument::Expression &&
+ "unexpected nontype template argument kind in partial substitution");
+ return Arg.getAsExpr();
+ }
+
if (NTTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1428,12 +1496,9 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
TransformDecl(TL.getNameLoc(), OldTTPDecl));
- QualType Result
- = getSema().Context.getTemplateTypeParmType(T->getDepth()
- - TemplateArgs.getNumLevels(),
- T->getIndex(),
- T->isParameterPack(),
- NewTTPDecl);
+ QualType Result = getSema().Context.getTemplateTypeParmType(
+ T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(),
+ T->isParameterPack(), NewTTPDecl);
TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
@@ -1489,13 +1554,17 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
/// a cast expression) or that the entity has no name (e.g., an
/// unnamed function parameter).
///
+/// \param AllowDeducedTST Whether a DeducedTemplateSpecializationType is
+/// acceptable as the top level type of the result.
+///
/// \returns If the instantiation succeeds, the instantiated
/// type. Otherwise, produces diagnostics and returns a NULL type.
TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &Args,
SourceLocation Loc,
- DeclarationName Entity) {
- assert(!ActiveTemplateInstantiations.empty() &&
+ DeclarationName Entity,
+ bool AllowDeducedTST) {
+ assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -1504,14 +1573,15 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
return T;
TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
- return Instantiator.TransformType(T);
+ return AllowDeducedTST ? Instantiator.TransformTypeWithDeducedTST(T)
+ : Instantiator.TransformType(T);
}
TypeSourceInfo *Sema::SubstType(TypeLoc TL,
const MultiLevelTemplateArgumentList &Args,
SourceLocation Loc,
DeclarationName Entity) {
- assert(!ActiveTemplateInstantiations.empty() &&
+ assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -1541,7 +1611,7 @@ TypeSourceInfo *Sema::SubstType(TypeLoc TL,
QualType Sema::SubstType(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity) {
- assert(!ActiveTemplateInstantiations.empty() &&
+ assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -1586,7 +1656,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
DeclarationName Entity,
CXXRecordDecl *ThisContext,
unsigned ThisTypeQuals) {
- assert(!ActiveTemplateInstantiations.empty() &&
+ assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -1622,20 +1692,26 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
return TLB.getTypeSourceInfo(Context, Result);
}
+bool Sema::SubstExceptionSpec(SourceLocation Loc,
+ FunctionProtoType::ExceptionSpecInfo &ESI,
+ SmallVectorImpl<QualType> &ExceptionStorage,
+ const MultiLevelTemplateArgumentList &Args) {
+ assert(ESI.Type != EST_Uninstantiated);
+
+ bool Changed = false;
+ TemplateInstantiator Instantiator(*this, Args, Loc, DeclarationName());
+ return Instantiator.TransformExceptionSpec(Loc, ESI, ExceptionStorage,
+ Changed);
+}
+
void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
const MultiLevelTemplateArgumentList &Args) {
FunctionProtoType::ExceptionSpecInfo ESI =
Proto->getExtProtoInfo().ExceptionSpec;
- assert(ESI.Type != EST_Uninstantiated);
-
- TemplateInstantiator Instantiator(*this, Args, New->getLocation(),
- New->getDeclName());
SmallVector<QualType, 4> ExceptionStorage;
- bool Changed = false;
- if (Instantiator.TransformExceptionSpec(
- New->getTypeSourceInfo()->getTypeLoc().getLocEnd(), ESI,
- ExceptionStorage, Changed))
+ if (SubstExceptionSpec(New->getTypeSourceInfo()->getTypeLoc().getLocEnd(),
+ ESI, ExceptionStorage, Args))
// On error, recover by dropping the exception specification.
ESI.Type = EST_None;
@@ -1758,7 +1834,7 @@ bool Sema::SubstParmTypes(
SmallVectorImpl<QualType> &ParamTypes,
SmallVectorImpl<ParmVarDecl *> *OutParams,
ExtParameterInfoBuilder &ParamInfos) {
- assert(!ActiveTemplateInstantiations.empty() &&
+ assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -1882,6 +1958,9 @@ namespace clang {
namespace sema {
Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, Sema &S,
const MultiLevelTemplateArgumentList &TemplateArgs);
+ Attr *instantiateTemplateAttributeForDecl(
+ const Attr *At, ASTContext &C, Sema &S,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
}
}
@@ -1942,8 +2021,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII SavedContext(*this, Instantiation);
- EnterExpressionEvaluationContext EvalContext(*this,
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EvalContext(
+ *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
// If this is an instantiation of a local class, merge this local
// instantiation scope with the enclosing scope. Otherwise, every
@@ -1966,7 +2045,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Instantiation->setHidden(false);
+ Instantiation->setVisibleDespiteOwningModule();
// FIXME: This loses the as-written tag kind for an explicit instantiation.
Instantiation->setTagKind(Pattern->getTagKind());
@@ -2168,13 +2247,13 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Instantiation->setHidden(false);
+ Instantiation->setVisibleDespiteOwningModule();
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII SavedContext(*this, Instantiation);
- EnterExpressionEvaluationContext EvalContext(*this,
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EvalContext(
+ *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
LocalInstantiationScope Scope(*this, /*MergeWithParentScope*/true);
@@ -2245,8 +2324,8 @@ bool Sema::InstantiateInClassInitializer(
// Enter the scope of this instantiation. We don't use PushDeclContext because
// we don't have a scope.
ContextRAII SavedContext(*this, Instantiation->getParent());
- EnterExpressionEvaluationContext EvalContext(*this,
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EvalContext(
+ *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
LocalInstantiationScope Scope(*this, true);
@@ -2277,6 +2356,25 @@ namespace {
};
}
+bool Sema::usesPartialOrExplicitSpecialization(
+ SourceLocation Loc, ClassTemplateSpecializationDecl *ClassTemplateSpec) {
+ if (ClassTemplateSpec->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization)
+ return true;
+
+ SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ ClassTemplateSpec->getSpecializedTemplate()
+ ->getPartialSpecializations(PartialSpecs);
+ for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
+ TemplateDeductionInfo Info(Loc);
+ if (!DeduceTemplateArguments(PartialSpecs[I],
+ ClassTemplateSpec->getTemplateArgs(), Info))
+ return true;
+ }
+
+ return false;
+}
+
/// Get the instantiation pattern to use to instantiate the definition of a
/// given ClassTemplateSpecializationDecl (either the pattern of the primary
/// template or of a partial specialization).
@@ -2545,10 +2643,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
== TSK_ExplicitSpecialization)
continue;
- if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ if ((Context.getTargetInfo().getCXXABI().isMicrosoft() ||
+ Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) &&
TSK == TSK_ExplicitInstantiationDeclaration) {
- // In MSVC mode, explicit instantiation decl of the outer class doesn't
- // affect the inner class.
+ // In MSVC and Windows Itanium mode, explicit instantiation decl of the
+ // outer class doesn't affect the inner class.
continue;
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 2007757..6fee23a 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -81,7 +81,8 @@ static void instantiateDependentAlignedAttr(
const AlignedAttr *Aligned, Decl *New, bool IsPackExpansion) {
if (Aligned->isAlignmentExpr()) {
// The alignment expression is a constant expression.
- EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs);
if (!Result.isInvalid())
S.AddAlignedAttr(Aligned->getLocation(), New, Result.getAs<Expr>(),
@@ -138,7 +139,8 @@ static void instantiateDependentAssumeAlignedAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AssumeAlignedAttr *Aligned, Decl *New) {
// The alignment expression is a constant expression.
- EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
Expr *E, *OE = nullptr;
ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs);
@@ -161,20 +163,32 @@ static void instantiateDependentAlignValueAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AlignValueAttr *Aligned, Decl *New) {
// The alignment expression is a constant expression.
- EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs);
if (!Result.isInvalid())
S.AddAlignValueAttr(Aligned->getLocation(), New, Result.getAs<Expr>(),
Aligned->getSpellingListIndex());
}
+static void instantiateDependentAllocAlignAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const AllocAlignAttr *Align, Decl *New) {
+ Expr *Param = IntegerLiteral::Create(
+ S.getASTContext(), llvm::APInt(64, Align->getParamIndex()),
+ S.getASTContext().UnsignedLongLongTy, Align->getLocation());
+ S.AddAllocAlignAttr(Align->getLocation(), New, Param,
+ Align->getSpellingListIndex());
+}
+
static Expr *instantiateDependentFunctionAttrCondition(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) {
Expr *Cond = nullptr;
{
Sema::ContextRAII SwitchContext(S, New);
- EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(OldCond, TemplateArgs);
if (Result.isInvalid())
return nullptr;
@@ -229,7 +243,8 @@ static void instantiateDependentCUDALaunchBoundsAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const CUDALaunchBoundsAttr &Attr, Decl *New) {
// The alignment expression is a constant expression.
- EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Attr.getMaxThreads(), TemplateArgs);
if (Result.isInvalid())
@@ -328,6 +343,34 @@ static void instantiateOMPDeclareSimdDeclAttr(
Attr.getRange());
}
+static bool DeclContainsAttr(const Decl *D, const Attr *NewAttr) {
+ if (!D->hasAttrs() || NewAttr->duplicatesAllowed())
+ return false;
+ return llvm::find_if(D->getAttrs(), [NewAttr](const Attr *Attr) {
+ return Attr->getKind() == NewAttr->getKind();
+ }) != D->getAttrs().end();
+}
+
+void Sema::InstantiateAttrsForDecl(
+ const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
+ Decl *New, LateInstantiatedAttrVec *LateAttrs,
+ LocalInstantiationScope *OuterMostScope) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(New)) {
+ for (const auto *TmplAttr : Tmpl->attrs()) {
+ // FIXME: If any of the special case versions from InstantiateAttrs become
+ // applicable to template declaration, we'll need to add them here.
+ CXXThisScopeRAII ThisScope(
+ *this, dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext()),
+ /*TypeQuals*/ 0, ND->isCXXInstanceMember());
+
+ Attr *NewAttr = sema::instantiateTemplateAttributeForDecl(
+ TmplAttr, Context, *this, TemplateArgs);
+ if (NewAttr && !DeclContainsAttr(New, NewAttr))
+ New->addAttr(NewAttr);
+ }
+ }
+}
+
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
@@ -352,6 +395,12 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
+ if (const auto *AllocAlign = dyn_cast<AllocAlignAttr>(TmplAttr)) {
+ instantiateDependentAllocAlignAttr(*this, TemplateArgs, AllocAlign, New);
+ continue;
+ }
+
+
if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) {
instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
cast<FunctionDecl>(New));
@@ -421,7 +470,8 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
*this, TemplateArgs);
- if (NewAttr)
+
+ if (NewAttr && !DeclContainsAttr(New, NewAttr))
New->addAttr(NewAttr);
}
}
@@ -657,10 +707,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
ArrayRef<BindingDecl*> *Bindings) {
// Do substitution on the type of the declaration
- TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
- TemplateArgs,
- D->getTypeSpecStartLoc(),
- D->getDeclName());
+ TypeSourceInfo *DI = SemaRef.SubstType(
+ D->getTypeSourceInfo(), TemplateArgs, D->getTypeSpecStartLoc(),
+ D->getDeclName(), /*AllowDeducedTST*/true);
if (!DI)
return nullptr;
@@ -746,8 +795,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
BitWidth = nullptr;
else if (BitWidth) {
// The bit-width expression is a constant expression.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult InstantiatedBitWidth
= SemaRef.SubstExpr(BitWidth, TemplateArgs);
@@ -923,8 +972,8 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Expr *AssertExpr = D->getAssertExpr();
// The expression in a static assertion is a constant expression.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult InstantiatedAssertExpr
= SemaRef.SubstExpr(AssertExpr, TemplateArgs);
@@ -1034,8 +1083,8 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition(
ExprResult Value((Expr *)nullptr);
if (Expr *UninstValue = EC->getInitExpr()) {
// The enumerator's value expression is a constant expression.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
Value = SemaRef.SubstExpr(UninstValue, TemplateArgs);
}
@@ -1491,8 +1540,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
// DR1484 clarifies that the members of a local class are instantiated as part
// of the instantiation of their enclosing entity.
if (D->isCompleteDefinition() && D->isLocalClass()) {
- Sema::SavePendingLocalImplicitInstantiationsRAII
- SavedPendingLocalImplicitInstantiations(SemaRef);
+ Sema::LocalEagerInstantiationScope LocalInstantiations(SemaRef);
SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
TSK_ImplicitInstantiation,
@@ -1506,7 +1554,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
// This class may have local implicit instantiations that need to be
// performed within this scope.
- SemaRef.PerformPendingInstantiations(/*LocalOnly=*/true);
+ LocalInstantiations.perform();
}
SemaRef.DiagnoseUnusedNestedTypedefs(Record);
@@ -1600,13 +1648,18 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TemplateArgs);
}
- FunctionDecl *Function =
- FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
- D->getNameInfo(), T, TInfo,
- D->getCanonicalDecl()->getStorageClass(),
- D->isInlineSpecified(), D->hasWrittenPrototype(),
- D->isConstexpr());
- Function->setRangeEnd(D->getSourceRange().getEnd());
+ FunctionDecl *Function;
+ if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D))
+ Function = CXXDeductionGuideDecl::Create(
+ SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(),
+ D->getNameInfo(), T, TInfo, D->getSourceRange().getEnd());
+ else {
+ Function = FunctionDecl::Create(
+ SemaRef.Context, DC, D->getInnerLocStart(), D->getNameInfo(), T, TInfo,
+ D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(),
+ D->hasWrittenPrototype(), D->isConstexpr());
+ Function->setRangeEnd(D->getSourceRange().getEnd());
+ }
if (D->isInlined())
Function->setImplicitlyInline();
@@ -1656,8 +1709,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionTemplate->setLexicalDeclContext(LexicalDC);
if (isFriend && D->isThisDeclarationADefinition()) {
- // TODO: should we remember this connection regardless of whether
- // the friend declaration provided a body?
FunctionTemplate->setInstantiatedFromMemberTemplate(
D->getDescribedFunctionTemplate());
}
@@ -1668,13 +1719,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost),
/*InsertPos=*/nullptr);
- } else if (isFriend) {
- // Note, we need this connection even if the friend doesn't have a body.
- // Its body may exist but not have been attached yet due to deferred
- // parsing.
- // FIXME: It might be cleaner to set this when attaching the body to the
- // friend function declaration, however that would require finding all the
- // instantiations and modifying them.
+ } else if (isFriend && D->isThisDeclarationADefinition()) {
+ // Do not connect the friend to the template unless it's actually a
+ // definition. We don't want non-template functions to be marked as being
+ // template instantiations.
Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
@@ -1734,6 +1782,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Previous.clear();
}
+ if (isFriend)
+ Function->setObjectOfFriendDecl();
+
SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
isExplicitSpecialization);
@@ -1800,6 +1851,19 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
}
}
+
+ // Check the template parameter list against the previous declaration. The
+ // goal here is to pick up default arguments added since the friend was
+ // declared; we know the template parameter lists match, since otherwise
+ // we would not have picked this template as the previous declaration.
+ if (TemplateParams && FunctionTemplate->getPreviousDecl()) {
+ SemaRef.CheckTemplateParameterList(
+ TemplateParams,
+ FunctionTemplate->getPreviousDecl()->getTemplateParameters(),
+ Function->isThisDeclarationADefinition()
+ ? Sema::TPC_FriendFunctionTemplateDefinition
+ : Sema::TPC_FriendFunctionTemplate);
+ }
}
if (Function->isLocalExternDecl() && !Function->getPreviousDecl())
@@ -2075,13 +2139,10 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
// TODO: don't always clone when decls are refcounted.
assert(D->getTypeForDecl()->isTemplateTypeParmType());
- TemplateTypeParmDecl *Inst =
- TemplateTypeParmDecl::Create(SemaRef.Context, Owner,
- D->getLocStart(), D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getIndex(), D->getIdentifier(),
- D->wasDeclaredWithTypename(),
- D->isParameterPack());
+ TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(
+ SemaRef.Context, Owner, D->getLocStart(), D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
+ D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack());
Inst->setAccess(AS_public);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
@@ -2219,25 +2280,22 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
if (IsExpandedParameterPack)
Param = NonTypeTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(), D->getPosition(),
- D->getIdentifier(), T, DI, ExpandedParameterPackTypes,
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->getIdentifier(), T, DI, ExpandedParameterPackTypes,
ExpandedParameterPackTypesAsWritten);
else
- Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getInnerLocStart(),
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->getIdentifier(), T,
- D->isParameterPack(), DI);
+ Param = NonTypeTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
Param->setAccess(AS_public);
if (Invalid)
Param->setInvalidDecl();
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
- EnterExpressionEvaluationContext ConstantEvaluated(SemaRef,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs);
if (!Value.isInvalid())
Param->setDefaultArgument(Value.get());
@@ -2350,19 +2408,15 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
// Build the template template parameter.
TemplateTemplateParmDecl *Param;
if (IsExpandedParameterPack)
- Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->getIdentifier(), InstParams,
- ExpandedParams);
+ Param = TemplateTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->getIdentifier(), InstParams, ExpandedParams);
else
- Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->isParameterPack(),
- D->getIdentifier(), InstParams);
+ Param = TemplateTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
NestedNameSpecifierLoc QualifierLoc =
D->getDefaultArgument().getTemplateQualifierLoc();
@@ -2783,6 +2837,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
return VisitFunctionDecl(D, nullptr);
}
+Decl *
+TemplateDeclInstantiator::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+ return VisitFunctionDecl(D, nullptr);
+}
+
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
return VisitCXXMethodDecl(D, nullptr);
}
@@ -3555,6 +3614,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
if (Tmpl->isDeleted())
New->setDeletedAsWritten();
+ New->setImplicit(Tmpl->isImplicit());
+
// Forward the mangling number from the template to the instantiated decl.
SemaRef.Context.setManglingNumber(New,
SemaRef.Context.getManglingNumber(Tmpl));
@@ -3567,8 +3628,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
// into a template instantiation for this specific function template
// specialization, which is not a SFINAE context, so that we diagnose any
// further errors in the declaration itself.
- typedef Sema::ActiveTemplateInstantiation ActiveInstType;
- ActiveInstType &ActiveInst = SemaRef.ActiveTemplateInstantiations.back();
+ typedef Sema::CodeSynthesisContext ActiveInstType;
+ ActiveInstType &ActiveInst = SemaRef.CodeSynthesisContexts.back();
if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution ||
ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) {
if (FunctionTemplateDecl *FunTmpl
@@ -3614,6 +3675,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
New->setType(SemaRef.Context.getFunctionType(
NewProto->getReturnType(), NewProto->getParamTypes(), EPI));
} else {
+ Sema::ContextRAII SwitchContext(SemaRef, New);
SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs);
}
}
@@ -3709,6 +3771,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (PatternDef) {
Pattern = PatternDef->getBody(PatternDef);
PatternDecl = PatternDef;
+ if (PatternDef->willHaveBody())
+ PatternDef = nullptr;
}
// FIXME: We need to track the instantiation stack in order to know which
@@ -3723,6 +3787,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Try again at the end of the translation unit (at which point a
// definition will be required).
assert(!Recursive);
+ Function->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
} else if (TSK == TSK_ImplicitInstantiation) {
@@ -3742,6 +3807,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Postpone late parsed template instantiations.
if (PatternDecl->isLateTemplateParsed() &&
!LateTemplateParser) {
+ Function->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
return;
@@ -3752,10 +3818,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// while we're still within our own instantiation context.
// This has to happen before LateTemplateParser below is called, so that
// it marks vtables used in late parsed templates as used.
- SavePendingLocalImplicitInstantiationsRAII
- SavedPendingLocalImplicitInstantiations(*this);
- SavePendingInstantiationsAndVTableUsesRAII
- SavePendingInstantiationsAndVTableUses(*this, /*Enabled=*/Recursive);
+ GlobalEagerInstantiationScope GlobalInstantiations(*this,
+ /*Enabled=*/Recursive);
+ LocalEagerInstantiationScope LocalInstantiations(*this);
// Call the LateTemplateParser callback if there is a need to late parse
// a templated function definition.
@@ -3805,13 +3870,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Function->setHidden(false);
+ Function->setVisibleDespiteOwningModule();
// Copy the inner loc start from the pattern.
Function->setInnerLocStart(PatternDecl->getInnerLocStart());
- EnterExpressionEvaluationContext EvalContext(*this,
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EvalContext(
+ *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
// Introduce a new scope where local variable instantiations will be
// recorded, unless we're actually a member function within a local
@@ -3864,6 +3929,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (Body.isInvalid())
Function->setInvalidDecl();
+ // FIXME: finishing the function body while in an expression evaluation
+ // context seems wrong. Investigate more.
ActOnFinishFunctionBody(Function, Body.get(),
/*IsInstantiation=*/true);
@@ -3880,20 +3947,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// This class may have local implicit instantiations that need to be
// instantiation within this scope.
- PerformPendingInstantiations(/*LocalOnly=*/true);
+ LocalInstantiations.perform();
Scope.Exit();
-
- if (Recursive) {
- // Define any pending vtables.
- DefineUsedVTables();
-
- // Instantiate any pending implicit instantiations found during the
- // instantiation of this template.
- PerformPendingInstantiations();
-
- // PendingInstantiations and VTableUses are restored through
- // SavePendingInstantiationsAndVTableUses's destructor.
- }
+ GlobalInstantiations.perform();
}
VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
@@ -4073,9 +4129,11 @@ void Sema::InstantiateVariableInitializer(
if (OldVar->getInit()) {
if (Var->isStaticDataMember() && !OldVar->isOutOfLine())
- PushExpressionEvaluationContext(Sema::ConstantEvaluated, OldVar);
+ PushExpressionEvaluationContext(
+ Sema::ExpressionEvaluationContext::ConstantEvaluated, OldVar);
else
- PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar);
+ PushExpressionEvaluationContext(
+ Sema::ExpressionEvaluationContext::PotentiallyEvaluated, OldVar);
// Instantiate the initializer.
ExprResult Init;
@@ -4218,15 +4276,15 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Var->setHidden(false);
+ Var->setVisibleDespiteOwningModule();
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate
// later, while we're still within our own instantiation context.
- SavePendingInstantiationsAndVTableUsesRAII
- SavePendingInstantiationsAndVTableUses(*this, /*Enabled=*/Recursive);
-
+ GlobalEagerInstantiationScope GlobalInstantiations(*this,
+ /*Enabled=*/Recursive);
LocalInstantiationScope Local(*this);
+ LocalEagerInstantiationScope LocalInstantiations(*this);
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
@@ -4234,26 +4292,11 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
InstantiateVariableInitializer(Var, PatternDecl, TemplateArgs);
PreviousContext.pop();
- // FIXME: Need to inform the ASTConsumer that we instantiated the
- // initializer?
-
// This variable may have local implicit instantiations that need to be
// instantiated within this scope.
- PerformPendingInstantiations(/*LocalOnly=*/true);
-
+ LocalInstantiations.perform();
Local.Exit();
-
- if (Recursive) {
- // Define any newly required vtables.
- DefineUsedVTables();
-
- // Instantiate any pending implicit instantiations found during the
- // instantiation of this template.
- PerformPendingInstantiations();
-
- // PendingInstantiations and VTableUses are restored through
- // SavePendingInstantiationsAndVTableUses's destructor.
- }
+ GlobalInstantiations.perform();
}
// Find actual definition
@@ -4344,21 +4387,20 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
- SavePendingLocalImplicitInstantiationsRAII
- SavedPendingLocalImplicitInstantiations(*this);
- SavePendingInstantiationsAndVTableUsesRAII
- SavePendingInstantiationsAndVTableUses(*this, /*Enabled=*/Recursive);
+ GlobalEagerInstantiationScope GlobalInstantiations(*this,
+ /*Enabled=*/Recursive);
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII PreviousContext(*this, Var->getDeclContext());
LocalInstantiationScope Local(*this);
+ LocalEagerInstantiationScope LocalInstantiations(*this);
+
VarDecl *OldVar = Var;
if (Def->isStaticDataMember() && !Def->isOutOfLine()) {
// We're instantiating an inline static data member whose definition was
// provided inside the class.
- // FIXME: Update record?
InstantiateVariableInitializer(Var, Def, TemplateArgs);
} else if (!VarSpec) {
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
@@ -4406,21 +4448,9 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// This variable may have local implicit instantiations that need to be
// instantiated within this scope.
- PerformPendingInstantiations(/*LocalOnly=*/true);
-
+ LocalInstantiations.perform();
Local.Exit();
-
- if (Recursive) {
- // Define any newly required vtables.
- DefineUsedVTables();
-
- // Instantiate any pending implicit instantiations found during the
- // instantiation of this template.
- PerformPendingInstantiations();
-
- // PendingInstantiations and VTableUses are restored through
- // SavePendingInstantiationsAndVTableUses's destructor.
- }
+ GlobalInstantiations.perform();
}
void
@@ -4780,7 +4810,7 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
const MultiLevelTemplateArgumentList &TemplateArgs) {
if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
- Decl* ID = FindInstantiatedDecl(Loc, D, TemplateArgs);
+ Decl* ID = FindInstantiatedDecl(Loc, D, TemplateArgs, true);
return cast_or_null<DeclContext>(ID);
} else return DC;
}
@@ -4812,7 +4842,8 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
/// (<tt>X<int>::<Kind>::KnownValue</tt>). \p FindInstantiatedDecl performs
/// this mapping from within the instantiation of <tt>X<int></tt>.
NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool FindingInstantiatedContext) {
DeclContext *ParentDC = D->getDeclContext();
// FIXME: Parmeters of pointer to functions (y below) that are themselves
// parameters (p below) can have their ParentDC set to the translation-unit
@@ -4954,6 +4985,43 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
DC = FD->getLexicalDeclContext();
continue;
}
+ // An implicit deduction guide acts as if it's within the class template
+ // specialization described by its name and first N template params.
+ auto *Guide = dyn_cast<CXXDeductionGuideDecl>(FD);
+ if (Guide && Guide->isImplicit()) {
+ TemplateDecl *TD = Guide->getDeducedTemplate();
+ // Convert the arguments to an "as-written" list.
+ TemplateArgumentListInfo Args(Loc, Loc);
+ for (TemplateArgument Arg : TemplateArgs.getInnermost().take_front(
+ TD->getTemplateParameters()->size())) {
+ ArrayRef<TemplateArgument> Unpacked(Arg);
+ if (Arg.getKind() == TemplateArgument::Pack)
+ Unpacked = Arg.pack_elements();
+ for (TemplateArgument UnpackedArg : Unpacked)
+ Args.addArgument(
+ getTrivialTemplateArgumentLoc(UnpackedArg, QualType(), Loc));
+ }
+ QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args);
+ if (T.isNull())
+ return nullptr;
+ auto *SubstRecord = T->getAsCXXRecordDecl();
+ assert(SubstRecord && "class template id not a class type?");
+ // Check that this template-id names the primary template and not a
+ // partial or explicit specialization. (In the latter cases, it's
+ // meaningless to attempt to find an instantiation of D within the
+ // specialization.)
+ // FIXME: The standard doesn't say what should happen here.
+ if (FindingInstantiatedContext &&
+ usesPartialOrExplicitSpecialization(
+ Loc, cast<ClassTemplateSpecializationDecl>(SubstRecord))) {
+ Diag(Loc, diag::err_specialization_not_primary_template)
+ << T << (SubstRecord->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization);
+ return nullptr;
+ }
+ DC = SubstRecord;
+ continue;
+ }
}
DC = DC->getParent();
@@ -5081,6 +5149,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
TSK_ExplicitInstantiationDefinition;
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
DefinitionRequired, true);
+ if (Function->isDefined())
+ Function->setInstantiationIsPending(false);
continue;
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp
index 725a3e4..9f57200 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -321,6 +321,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
return false;
case DeclarationName::CXXConstructorName:
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
index 2cdf76c..598a113 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -119,8 +120,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
// Function type attributes.
#define FUNCTION_TYPE_ATTRS_CASELIST \
- case AttributeList::AT_NoReturn: \
- case AttributeList::AT_Regparm: \
+ case AttributeList::AT_NSReturnsRetained: \
+ case AttributeList::AT_NoReturn: \
+ case AttributeList::AT_Regparm: \
+ case AttributeList::AT_AnyX86NoCallerSavedRegisters: \
CALLING_CONV_ATTRS_CASELIST
// Microsoft-specific type qualifiers.
@@ -638,11 +641,6 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
- case AttributeList::AT_NSReturnsRetained:
- if (!state.getSema().getLangOpts().ObjCAutoRefCount)
- break;
- // fallthrough
-
FUNCTION_TYPE_ATTRS_CASELIST:
distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType);
break;
@@ -742,7 +740,7 @@ static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS,
if (!(RemoveTQs & Qual.first))
continue;
- if (S.ActiveTemplateInstantiations.empty()) {
+ if (!S.inTemplateInstantiation()) {
if (TypeQuals & Qual.first)
S.Diag(Qual.second, DiagID)
<< DeclSpec::getSpecifierName(Qual.first) << TypeSoFar
@@ -1502,40 +1500,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_auto:
- // TypeQuals handled by caller.
- // If auto is mentioned in a lambda parameter context, convert it to a
- // template parameter type immediately, with the appropriate depth and
- // index, and update sema's state (LambdaScopeInfo) for the current lambda
- // being analyzed (which tracks the invented type template parameter).
- if (declarator.getContext() == Declarator::LambdaExprParameterContext) {
- sema::LambdaScopeInfo *LSI = S.getCurLambda();
- assert(LSI && "No LambdaScopeInfo on the stack!");
- const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
- const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
- const bool IsParameterPack = declarator.hasEllipsis();
-
- // Turns out we must create the TemplateTypeParmDecl here to
- // retrieve the corresponding template parameter type.
- TemplateTypeParmDecl *CorrespondingTemplateParam =
- TemplateTypeParmDecl::Create(Context,
- // Temporarily add to the TranslationUnit DeclContext. When the
- // associated TemplateParameterList is attached to a template
- // declaration (such as FunctionTemplateDecl), the DeclContext
- // for each template parameter gets updated appropriately via
- // a call to AdoptTemplateParameterList.
- Context.getTranslationUnitDecl(),
- /*KeyLoc*/ SourceLocation(),
- /*NameLoc*/ declarator.getLocStart(),
- TemplateParameterDepth,
- AutoParameterPosition, // our template param index
- /* Identifier*/ nullptr, false, IsParameterPack);
- LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
- // Replace the 'auto' in the function parameter with this invented
- // template type parameter.
- Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
- } else {
- Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
- }
+ Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
break;
case DeclSpec::TST_auto_type:
@@ -1913,6 +1878,11 @@ QualType Sema::BuildPointerType(QualType T,
return QualType();
}
+ if (T->isFunctionType() && getLangOpts().OpenCL) {
+ Diag(Loc, diag::err_opencl_function_pointer);
+ return QualType();
+ }
+
if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer))
return QualType();
@@ -2317,8 +2287,9 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
// Methods cannot return interface types. All ObjC objects are
// passed by reference.
if (T->isObjCObjectType()) {
- Diag(Loc, diag::err_object_cannot_be_passed_returned_by_value) << 0 << T;
- return 0;
+ Diag(Loc, diag::err_object_cannot_be_passed_returned_by_value)
+ << 0 << T << FixItHint::CreateInsertion(Loc, "*");
+ return true;
}
return false;
@@ -2409,6 +2380,11 @@ QualType Sema::BuildFunctionType(QualType T,
[=](unsigned i) { return Loc; });
}
+ if (EPI.ExtInfo.getProducesResult()) {
+ // This is just a warning, so we can't fail to build if we see it.
+ checkNSReturnsRetainedReturnType(Loc, T);
+ }
+
if (Invalid)
return QualType();
@@ -2766,6 +2742,12 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
D.getDeclSpec().getAttributes().getList());
break;
+ case UnqualifiedId::IK_DeductionGuideName:
+ // Deduction guides have a trailing return type and no type in their
+ // decl-specifier sequence. Use a placeholder return type for now.
+ T = SemaRef.Context.DependentTy;
+ break;
+
case UnqualifiedId::IK_ConversionFunctionId:
// The result type of a conversion function is the type that it
// converts to.
@@ -2778,12 +2760,20 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
distributeTypeAttrsFromDeclarator(state, T);
// C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
- if (D.getDeclSpec().containsPlaceholderType()) {
+ if (DeducedType *Deduced = T->getContainedDeducedType()) {
+ AutoType *Auto = dyn_cast<AutoType>(Deduced);
int Error = -1;
+ // Is this a 'auto' or 'decltype(auto)' type (as opposed to __auto_type or
+ // class template argument deduction)?
+ bool IsCXXAutoType =
+ (Auto && Auto->getKeyword() != AutoTypeKeyword::GNUAutoType);
+
switch (D.getContext()) {
case Declarator::LambdaExprContext:
- llvm_unreachable("Can't specify a type specifier in lambda grammar");
+ // Declared return type of a lambda-declarator is implicit and is always
+ // 'auto'.
+ break;
case Declarator::ObjCParameterContext:
case Declarator::ObjCResultContext:
case Declarator::PrototypeContext:
@@ -2791,9 +2781,35 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
break;
case Declarator::LambdaExprParameterContext:
// In C++14, generic lambdas allow 'auto' in their parameters.
- if (!(SemaRef.getLangOpts().CPlusPlus14
- && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto))
+ if (!SemaRef.getLangOpts().CPlusPlus14 ||
+ !Auto || Auto->getKeyword() != AutoTypeKeyword::Auto)
Error = 16;
+ else {
+ // If auto is mentioned in a lambda parameter context, convert it to a
+ // template parameter type.
+ sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
+ assert(LSI && "No LambdaScopeInfo on the stack!");
+ const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
+ const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
+ const bool IsParameterPack = D.hasEllipsis();
+
+ // Create the TemplateTypeParmDecl here to retrieve the corresponding
+ // template parameter type. Template parameters are temporarily added
+ // to the TU until the associated TemplateDecl is created.
+ TemplateTypeParmDecl *CorrespondingTemplateParam =
+ TemplateTypeParmDecl::Create(
+ SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(),
+ /*KeyLoc*/SourceLocation(), /*NameLoc*/D.getLocStart(),
+ TemplateParameterDepth, AutoParameterPosition,
+ /*Identifier*/nullptr, false, IsParameterPack);
+ LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+ // Replace the 'auto' in the function parameter with this invented
+ // template type parameter.
+ // FIXME: Retain some type sugar to indicate that this was written
+ // as 'auto'.
+ T = SemaRef.ReplaceAutoType(
+ T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0));
+ }
break;
case Declarator::MemberContext: {
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
@@ -2807,6 +2823,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case TTK_Class: Error = 5; /* Class member */ break;
case TTK_Interface: Error = 6; /* Interface member */ break;
}
+ if (D.getDeclSpec().isFriendSpecified())
+ Error = 20; // Friend type
break;
}
case Declarator::CXXCatchContext:
@@ -2814,8 +2832,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
Error = 7; // Exception declaration
break;
case Declarator::TemplateParamContext:
- if (!SemaRef.getLangOpts().CPlusPlus1z)
- Error = 8; // Template parameter
+ if (isa<DeducedTemplateSpecializationType>(Deduced))
+ Error = 19; // Template parameter
+ else if (!SemaRef.getLangOpts().CPlusPlus1z)
+ Error = 8; // Template parameter (until C++1z)
break;
case Declarator::BlockLiteralContext:
Error = 9; // Block literal
@@ -2828,15 +2848,17 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
Error = 12; // Type alias
break;
case Declarator::TrailingReturnContext:
- if (!SemaRef.getLangOpts().CPlusPlus14 ||
- D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type)
+ if (!SemaRef.getLangOpts().CPlusPlus14 || !IsCXXAutoType)
Error = 13; // Function return type
break;
case Declarator::ConversionIdContext:
- if (!SemaRef.getLangOpts().CPlusPlus14 ||
- D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type)
+ if (!SemaRef.getLangOpts().CPlusPlus14 || !IsCXXAutoType)
Error = 14; // conversion-type-id
break;
+ case Declarator::FunctionalCastContext:
+ if (isa<DeducedTemplateSpecializationType>(Deduced))
+ break;
+ LLVM_FALLTHROUGH;
case Declarator::TypeNameContext:
Error = 15; // Generic
break;
@@ -2845,9 +2867,14 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case Declarator::ForContext:
case Declarator::InitStmtContext:
case Declarator::ConditionContext:
+ // FIXME: P0091R3 (erroneously) does not permit class template argument
+ // deduction in conditions, for-init-statements, and other declarations
+ // that are not simple-declarations.
break;
case Declarator::CXXNewContext:
- if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type)
+ // FIXME: P0091R3 does not permit class template argument deduction here,
+ // but we follow GCC and allow it anyway.
+ if (!IsCXXAutoType && !isa<DeducedTemplateSpecializationType>(Deduced))
Error = 17; // 'new' type
break;
case Declarator::KNRTypeListContext:
@@ -2861,8 +2888,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// In Objective-C it is an error to use 'auto' on a function declarator
// (and everywhere for '__auto_type').
if (D.isFunctionDeclarator() &&
- (!SemaRef.getLangOpts().CPlusPlus11 ||
- D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type))
+ (!SemaRef.getLangOpts().CPlusPlus11 || !IsCXXAutoType))
Error = 13;
bool HaveTrailing = false;
@@ -2872,21 +2898,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// level. Check all declarator chunks (outermost first) anyway, to give
// better diagnostics.
// We don't support '__auto_type' with trailing return types.
- if (SemaRef.getLangOpts().CPlusPlus11 &&
- D.getDeclSpec().getTypeSpecType() != DeclSpec::TST_auto_type) {
- for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
- unsigned chunkIndex = e - i - 1;
- state.setCurrentChunkIndex(chunkIndex);
- DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
- if (DeclType.Kind == DeclaratorChunk::Function) {
- const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
- if (FTI.hasTrailingReturnType()) {
- HaveTrailing = true;
- Error = -1;
- break;
- }
- }
- }
+ // FIXME: Should we only do this for 'auto' and not 'decltype(auto)'?
+ if (SemaRef.getLangOpts().CPlusPlus11 && IsCXXAutoType &&
+ D.hasTrailingReturnType()) {
+ HaveTrailing = true;
+ Error = -1;
}
SourceRange AutoRange = D.getDeclSpec().getTypeSpecTypeLoc();
@@ -2894,15 +2910,28 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
AutoRange = D.getName().getSourceRange();
if (Error != -1) {
- unsigned Keyword;
- switch (D.getDeclSpec().getTypeSpecType()) {
- case DeclSpec::TST_auto: Keyword = 0; break;
- case DeclSpec::TST_decltype_auto: Keyword = 1; break;
- case DeclSpec::TST_auto_type: Keyword = 2; break;
- default: llvm_unreachable("unknown auto TypeSpecType");
+ unsigned Kind;
+ if (Auto) {
+ switch (Auto->getKeyword()) {
+ case AutoTypeKeyword::Auto: Kind = 0; break;
+ case AutoTypeKeyword::DecltypeAuto: Kind = 1; break;
+ case AutoTypeKeyword::GNUAutoType: Kind = 2; break;
+ }
+ } else {
+ assert(isa<DeducedTemplateSpecializationType>(Deduced) &&
+ "unknown auto type");
+ Kind = 3;
}
+
+ auto *DTST = dyn_cast<DeducedTemplateSpecializationType>(Deduced);
+ TemplateName TN = DTST ? DTST->getTemplateName() : TemplateName();
+
SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed)
- << Keyword << Error << AutoRange;
+ << Kind << Error << (int)SemaRef.getTemplateNameKindForDiagnostics(TN)
+ << QualType(Deduced, 0) << AutoRange;
+ if (auto *TD = TN.getAsTemplateDecl())
+ SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here);
+
T = SemaRef.Context.IntTy;
D.setInvalidType(true);
} else if (!HaveTrailing) {
@@ -2942,6 +2971,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
DiagID = diag::err_type_defined_in_alias_template;
break;
case Declarator::TypeNameContext:
+ case Declarator::FunctionalCastContext:
case Declarator::ConversionIdContext:
case Declarator::TemplateParamContext:
case Declarator::CXXNewContext:
@@ -3152,11 +3182,7 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D,
for (const AttributeList *Attr = D.getDeclSpec().getAttributes().getList();
Attr; Attr = Attr->getNext()) {
if (Attr->getKind() == AttributeList::AT_OpenCLKernel) {
- llvm::Triple::ArchType arch = S.Context.getTargetInfo().getTriple().getArch();
- if (arch == llvm::Triple::spir || arch == llvm::Triple::spir64 ||
- arch == llvm::Triple::amdgcn || arch == llvm::Triple::r600) {
- CC = CC_OpenCLKernel;
- }
+ CC = CC_OpenCLKernel;
break;
}
}
@@ -3342,7 +3368,7 @@ classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator,
if (auto objcClass = type->getAs<ObjCInterfaceType>()) {
if (objcClass->getInterface()->getIdentifier() == S.getNSErrorIdent()) {
if (numNormalPointers == 2 && numTypeSpecifierPointers < 2)
- return PointerDeclaratorKind::NSErrorPointerPointer;;
+ return PointerDeclaratorKind::NSErrorPointerPointer;
}
break;
@@ -3623,17 +3649,32 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If T is 'decltype(auto)', the only declarators we can have are parens
// and at most one function declarator if this is a function declaration.
- if (const AutoType *AT = T->getAs<AutoType>()) {
- if (AT->isDecltypeAuto()) {
+ // If T is a deduced class template specialization type, we can have no
+ // declarator chunks at all.
+ if (auto *DT = T->getAs<DeducedType>()) {
+ const AutoType *AT = T->getAs<AutoType>();
+ bool IsClassTemplateDeduction = isa<DeducedTemplateSpecializationType>(DT);
+ if ((AT && AT->isDecltypeAuto()) || IsClassTemplateDeduction) {
for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
unsigned Index = E - I - 1;
DeclaratorChunk &DeclChunk = D.getTypeObject(Index);
- unsigned DiagId = diag::err_decltype_auto_compound_type;
+ unsigned DiagId = IsClassTemplateDeduction
+ ? diag::err_deduced_class_template_compound_type
+ : diag::err_decltype_auto_compound_type;
unsigned DiagKind = 0;
switch (DeclChunk.Kind) {
case DeclaratorChunk::Paren:
+ // FIXME: Rejecting this is a little silly.
+ if (IsClassTemplateDeduction) {
+ DiagKind = 4;
+ break;
+ }
continue;
case DeclaratorChunk::Function: {
+ if (IsClassTemplateDeduction) {
+ DiagKind = 3;
+ break;
+ }
unsigned FnIndex;
if (D.isFunctionDeclarationContext() &&
D.isFunctionDeclarator(FnIndex) && FnIndex == Index)
@@ -3697,16 +3738,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// inner pointers.
complainAboutMissingNullability = CAMN_InnerPointers;
- auto isDependentNonPointerType = [](QualType T) -> bool {
- // Note: This is intended to be the same check as Type::canHaveNullability
- // except with all of the ambiguous cases being treated as 'false' rather
- // than 'true'.
- return T->isDependentType() && !T->isAnyPointerType() &&
- !T->isBlockPointerType() && !T->isMemberPointerType();
- };
-
- if (T->canHaveNullability() && !T->getNullability(S.Context) &&
- !isDependentNonPointerType(T)) {
+ if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
+ !T->getNullability(S.Context)) {
// Note that we allow but don't require nullability on dependent types.
++NumPointersRemaining;
}
@@ -3834,6 +3867,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case Declarator::TemplateParamContext:
case Declarator::TemplateTypeArgContext:
case Declarator::TypeNameContext:
+ case Declarator::FunctionalCastContext:
// Don't infer in these contexts.
break;
}
@@ -3922,8 +3956,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If the type itself could have nullability but does not, infer pointer
// nullability and perform consistency checking.
- if (S.ActiveTemplateInstantiations.empty()) {
- if (T->canHaveNullability() && !T->getNullability(S.Context)) {
+ if (S.CodeSynthesisContexts.empty()) {
+ if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
+ !T->getNullability(S.Context)) {
if (isVaList(T)) {
// Record that we've seen a pointer, but do nothing else.
if (NumPointersRemaining > 0)
@@ -4123,7 +4158,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (!D.isInvalidType()) {
// trailing-return-type is only required if we're declaring a function,
// and not, for instance, a pointer to a function.
- if (D.getDeclSpec().containsPlaceholderType() &&
+ if (D.getDeclSpec().hasAutoTypeSpec() &&
!FTI.hasTrailingReturnType() && chunkIndex == 0 &&
!S.getLangOpts().CPlusPlus14) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
@@ -4135,16 +4170,25 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} else if (FTI.hasTrailingReturnType()) {
// T must be exactly 'auto' at this point. See CWG issue 681.
if (isa<ParenType>(T)) {
- S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
+ S.Diag(D.getLocStart(),
diag::err_trailing_return_in_parens)
- << T << D.getDeclSpec().getSourceRange();
+ << T << D.getSourceRange();
D.setInvalidType(true);
+ } else if (D.getName().getKind() ==
+ UnqualifiedId::IK_DeductionGuideName) {
+ if (T != Context.DependentTy) {
+ S.Diag(D.getDeclSpec().getLocStart(),
+ diag::err_deduction_guide_with_complex_decl)
+ << D.getSourceRange();
+ D.setInvalidType(true);
+ }
} else if (D.getContext() != Declarator::LambdaExprContext &&
(T.hasQualifiers() || !isa<AutoType>(T) ||
- cast<AutoType>(T)->getKeyword() != AutoTypeKeyword::Auto)) {
+ cast<AutoType>(T)->getKeyword() !=
+ AutoTypeKeyword::Auto)) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
- diag::err_trailing_return_without_auto)
- << T << D.getDeclSpec().getSourceRange();
+ diag::err_trailing_return_without_auto)
+ << T << D.getDeclSpec().getSourceRange();
D.setInvalidType(true);
}
T = S.GetTypeFromParser(FTI.getTrailingReturnType(), &TInfo);
@@ -4158,7 +4202,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C99 6.7.5.3p1: The return type may not be a function or array type.
// For conversion functions, we'll diagnose this particular error later.
- if ((T->isArrayType() || T->isFunctionType()) &&
+ if (!D.isInvalidType() && (T->isArrayType() || T->isFunctionType()) &&
(D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) {
unsigned diagID = diag::err_func_returning_array_function;
// Last processing chunk in block context means this function chunk
@@ -4310,19 +4354,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (FTI.isAmbiguous)
warnAboutAmbiguousFunction(S, D, DeclType, T);
- // GNU warning -Wstrict-prototypes
- // Warn if a function declaration is without a prototype.
- // This warning is issued for all kinds of unprototyped function
- // declarations (i.e. function type typedef, function pointer etc.)
- // C99 6.7.5.3p14:
- // The empty list in a function declarator that is not part of a
- // definition of that function specifies that no information
- // about the number or types of the parameters is supplied.
- if (D.getFunctionDefinitionKind() == FDK_Declaration &&
- FTI.NumParams == 0 && !LangOpts.CPlusPlus)
- S.Diag(DeclType.Loc, diag::warn_strict_prototypes)
- << 0 << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void");
-
FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));
if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus) {
@@ -4442,6 +4473,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
HasAnyInterestingExtParameterInfos = true;
}
+ if (Param->hasAttr<PassObjectSizeAttr>()) {
+ ExtParameterInfos[i] = ExtParameterInfos[i].withHasPassObjectSize();
+ HasAnyInterestingExtParameterInfos = true;
+ }
+
ParamTys.push_back(ParamTy);
}
@@ -4560,6 +4596,36 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
const_cast<AttributeList *>(DeclType.getAttrs()));
}
+ // GNU warning -Wstrict-prototypes
+ // Warn if a function declaration is without a prototype.
+ // This warning is issued for all kinds of unprototyped function
+ // declarations (i.e. function type typedef, function pointer etc.)
+ // C99 6.7.5.3p14:
+ // The empty list in a function declarator that is not part of a definition
+ // of that function specifies that no information about the number or types
+ // of the parameters is supplied.
+ if (!LangOpts.CPlusPlus && D.getFunctionDefinitionKind() == FDK_Declaration) {
+ bool IsBlock = false;
+ for (const DeclaratorChunk &DeclType : D.type_objects()) {
+ switch (DeclType.Kind) {
+ case DeclaratorChunk::BlockPointer:
+ IsBlock = true;
+ break;
+ case DeclaratorChunk::Function: {
+ const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+ if (FTI.NumParams == 0)
+ S.Diag(DeclType.Loc, diag::warn_strict_prototypes)
+ << IsBlock
+ << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void");
+ IsBlock = false;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
assert(!T.isNull() && "T must not be null after this point");
if (LangOpts.CPlusPlus && T->isFunctionType()) {
@@ -4574,14 +4640,18 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
//
// Core issue 547 also allows cv-qualifiers on function types that are
// top-level template type arguments.
- bool FreeFunction;
- if (!D.getCXXScopeSpec().isSet()) {
- FreeFunction = ((D.getContext() != Declarator::MemberContext &&
- D.getContext() != Declarator::LambdaExprContext) ||
- D.getDeclSpec().isFriendSpecified());
+ enum { NonMember, Member, DeductionGuide } Kind = NonMember;
+ if (D.getName().getKind() == UnqualifiedId::IK_DeductionGuideName)
+ Kind = DeductionGuide;
+ else if (!D.getCXXScopeSpec().isSet()) {
+ if ((D.getContext() == Declarator::MemberContext ||
+ D.getContext() == Declarator::LambdaExprContext) &&
+ !D.getDeclSpec().isFriendSpecified())
+ Kind = Member;
} else {
DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec());
- FreeFunction = (DC && !DC->isRecord());
+ if (!DC || DC->isRecord())
+ Kind = Member;
}
// C++11 [dcl.fct]p6 (w/DR1417):
@@ -4601,7 +4671,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
//
// ... for instance.
if (IsQualifiedFunction &&
- !(!FreeFunction &&
+ !(Kind == Member &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) &&
!IsTypedefName &&
D.getContext() != Declarator::TemplateTypeArgContext) {
@@ -4629,7 +4699,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
S.Diag(Loc, diag::err_invalid_qualified_function_type)
- << FreeFunction << D.isFunctionDeclarator() << T
+ << Kind << D.isFunctionDeclarator() << T
<< getFunctionQualifiersAsString(FnTy)
<< FixItHint::CreateRemoval(RemovalRange);
@@ -4713,6 +4783,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case Declarator::ObjCParameterContext: // FIXME: special diagnostic here?
case Declarator::ObjCResultContext: // FIXME: special diagnostic here?
case Declarator::TypeNameContext:
+ case Declarator::FunctionalCastContext:
case Declarator::CXXNewContext:
case Declarator::AliasDeclContext:
case Declarator::AliasTemplateContext:
@@ -4946,6 +5017,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_TypeNullUnspecified;
case AttributedType::attr_objc_kindof:
return AttributeList::AT_ObjCKindOf;
+ case AttributedType::attr_ns_returns_retained:
+ return AttributeList::AT_NSReturnsRetained;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -5473,14 +5546,15 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
addrSpace.setIsSigned(false);
}
llvm::APSInt max(addrSpace.getBitWidth());
- max = Qualifiers::MaxAddressSpace;
+ max = Qualifiers::MaxAddressSpace - LangAS::FirstTargetAddressSpace;
if (addrSpace > max) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
- << int(Qualifiers::MaxAddressSpace) << ASArgExpr->getSourceRange();
+ << (unsigned)max.getZExtValue() << ASArgExpr->getSourceRange();
Attr.setInvalid();
return;
}
- ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
+ ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()) +
+ LangAS::FirstTargetAddressSpace;
} else {
// The keyword-based type attributes imply which address space to use.
switch (Attr.getKind()) {
@@ -6301,16 +6375,39 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
// ns_returns_retained is not always a type attribute, but if we got
// here, we're treating it as one right now.
if (attr.getKind() == AttributeList::AT_NSReturnsRetained) {
- assert(S.getLangOpts().ObjCAutoRefCount &&
- "ns_returns_retained treated as type attribute in non-ARC");
if (attr.getNumArgs()) return true;
// Delay if this is not a function type.
if (!unwrapped.isFunctionType())
return false;
- FunctionType::ExtInfo EI
- = unwrapped.get()->getExtInfo().withProducesResult(true);
+ // Check whether the return type is reasonable.
+ if (S.checkNSReturnsRetainedReturnType(attr.getLoc(),
+ unwrapped.get()->getReturnType()))
+ return true;
+
+ // Only actually change the underlying type in ARC builds.
+ QualType origType = type;
+ if (state.getSema().getLangOpts().ObjCAutoRefCount) {
+ FunctionType::ExtInfo EI
+ = unwrapped.get()->getExtInfo().withProducesResult(true);
+ type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ }
+ type = S.Context.getAttributedType(AttributedType::attr_ns_returns_retained,
+ origType, type);
+ return true;
+ }
+
+ if (attr.getKind() == AttributeList::AT_AnyX86NoCallerSavedRegisters) {
+ if (S.CheckNoCallerSavedRegsAttr(attr))
+ return true;
+
+ // Delay if this is not a function type.
+ if (!unwrapped.isFunctionType())
+ return false;
+
+ FunctionType::ExtInfo EI =
+ unwrapped.get()->getExtInfo().withNoCallerSavedRegs(true);
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
return true;
}
@@ -6859,11 +6956,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_NSReturnsRetained:
- if (!state.getSema().getLangOpts().ObjCAutoRefCount)
- break;
- // fallthrough into the function attrs
-
FUNCTION_TYPE_ATTRS_CASELIST:
attr.setUsedAsTypeAttr();
@@ -6893,8 +6985,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
(TAL == TAL_DeclSpec || TAL == TAL_DeclChunk)) {
Declarator &D = state.getDeclarator();
if (state.getCurrentChunkIndex() > 0 &&
- D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind ==
- DeclaratorChunk::Pointer) {
+ (D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind ==
+ DeclaratorChunk::Pointer ||
+ D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind ==
+ DeclaratorChunk::BlockPointer)) {
type = state.getSema().Context.getAddrSpaceQualType(
type, LangAS::opencl_generic);
} else if (state.getCurrentChunkIndex() == 0 &&
@@ -7023,6 +7117,20 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return false;
}
+bool Sema::hasStructuralCompatLayout(Decl *D, Decl *Suggested) {
+ llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
+ if (!Suggested)
+ return false;
+
+ // FIXME: Add a specific mode for C11 6.2.7/1 in StructuralEquivalenceContext
+ // and isolate from other C++ specific checks.
+ StructuralEquivalenceContext Ctx(
+ D->getASTContext(), Suggested->getASTContext(), NonEquivalentDecls,
+ false /*StrictTypeSpelling*/, true /*Complain*/,
+ true /*ErrorOnTagTypeMismatch*/);
+ return Ctx.IsStructurallyEquivalent(D, Suggested);
+}
+
/// \brief Determine whether there is any declaration of \p D that was ever a
/// definition (perhaps before module merging) and is currently visible.
/// \param D The definition of the entity.
@@ -7510,7 +7618,7 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc,
if (ER.isInvalid()) return QualType();
E = ER.get();
- if (AsUnevaluated && ActiveTemplateInstantiations.empty() &&
+ if (AsUnevaluated && CodeSynthesisContexts.empty() &&
E->HasSideEffects(Context, false)) {
// The expression operand for decltype is in an unevaluated expression
// context, so side effects could result in unintended consequences.
diff --git a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h
index f8e65a1..91da9f8 100644
--- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h
+++ b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H
#define LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H
+#include "CoroutineStmtBuilder.h"
#include "TypeLocBuilder.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -307,6 +308,17 @@ public:
///
QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL);
+ /// \brief Transform a type that is permitted to produce a
+ /// DeducedTemplateSpecializationType.
+ ///
+ /// This is used in the (relatively rare) contexts where it is acceptable
+ /// for transformation to produce a class template type with deduced
+ /// template arguments.
+ /// @{
+ QualType TransformTypeWithDeducedTST(QualType T);
+ TypeSourceInfo *TransformTypeWithDeducedTST(TypeSourceInfo *DI);
+ /// @}
+
/// \brief Transform the given statement.
///
/// By default, this routine transforms a statement by delegating to the
@@ -505,7 +517,8 @@ public:
TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
SourceLocation NameLoc,
QualType ObjectType = QualType(),
- NamedDecl *FirstQualifierInScope = nullptr);
+ NamedDecl *FirstQualifierInScope = nullptr,
+ bool AllowInjectedClassName = false);
/// \brief Transform the given template argument.
///
@@ -671,6 +684,16 @@ public:
OMPClause *Transform ## Class(Class *S);
#include "clang/Basic/OpenMPKinds.def"
+ /// \brief Build a new qualified type given its unqualified type and type
+ /// qualifiers.
+ ///
+ /// By default, this routine adds type qualifiers only to types that can
+ /// have qualifiers, and silently suppresses those qualifiers that are not
+ /// permitted. Subclasses may override this routine to provide different
+ /// behavior.
+ QualType RebuildQualifiedType(QualType T, SourceLocation Loc,
+ Qualifiers Quals);
+
/// \brief Build a new pointer type given its pointee type.
///
/// By default, performs semantic analysis when building the pointer type.
@@ -875,6 +898,14 @@ public:
/*IsDependent*/ false);
}
+ /// By default, builds a new DeducedTemplateSpecializationType with the given
+ /// deduced type.
+ QualType RebuildDeducedTemplateSpecializationType(TemplateName Template,
+ QualType Deduced) {
+ return SemaRef.Context.getDeducedTemplateSpecializationType(
+ Template, Deduced, /*IsDependent*/ false);
+ }
+
/// \brief Build a new template specialization type.
///
/// By default, performs semantic analysis when building the template
@@ -889,7 +920,7 @@ public:
/// By default, builds a new ParenType type from the inner type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildParenType(QualType InnerType) {
- return SemaRef.Context.getParenType(InnerType);
+ return SemaRef.BuildParenType(InnerType);
}
/// \brief Build a new qualified name type.
@@ -916,14 +947,15 @@ public:
NestedNameSpecifierLoc QualifierLoc,
const IdentifierInfo *Name,
SourceLocation NameLoc,
- TemplateArgumentListInfo &Args) {
+ TemplateArgumentListInfo &Args,
+ bool AllowInjectedClassName) {
// Rebuild the template name.
// TODO: avoid TemplateName abstraction
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
TemplateName InstName
= getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(),
- nullptr);
+ nullptr, AllowInjectedClassName);
if (InstName.isNull())
return QualType();
@@ -958,7 +990,8 @@ public:
SourceLocation KeywordLoc,
NestedNameSpecifierLoc QualifierLoc,
const IdentifierInfo *Id,
- SourceLocation IdLoc) {
+ SourceLocation IdLoc,
+ bool DeducedTSTContext) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
@@ -970,9 +1003,25 @@ public:
Id);
}
- if (Keyword == ETK_None || Keyword == ETK_Typename)
- return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc,
- *Id, IdLoc);
+ if (Keyword == ETK_None || Keyword == ETK_Typename) {
+ QualType T = SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc,
+ *Id, IdLoc);
+ // If a dependent name resolves to a deduced template specialization type,
+ // check that we're in one of the syntactic contexts permitting it.
+ if (!DeducedTSTContext) {
+ if (auto *Deduced = dyn_cast_or_null<DeducedTemplateSpecializationType>(
+ T.isNull() ? nullptr : T->getContainedDeducedType())) {
+ SemaRef.Diag(IdLoc, diag::err_dependent_deduced_tst)
+ << (int)SemaRef.getTemplateNameKindForDiagnostics(
+ Deduced->getTemplateName())
+ << QualType(QualifierLoc.getNestedNameSpecifier()->getAsType(), 0);
+ if (auto *TD = Deduced->getTemplateName().getAsTemplateDecl())
+ SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here);
+ return QualType();
+ }
+ }
+ return T;
+ }
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
@@ -1088,7 +1137,8 @@ public:
const IdentifierInfo &Name,
SourceLocation NameLoc,
QualType ObjectType,
- NamedDecl *FirstQualifierInScope);
+ NamedDecl *FirstQualifierInScope,
+ bool AllowInjectedClassName);
/// \brief Build a new template name given a nested name specifier and the
/// overloaded operator name that is referred to as a template.
@@ -1100,7 +1150,8 @@ public:
TemplateName RebuildTemplateName(CXXScopeSpec &SS,
OverloadedOperatorKind Operator,
SourceLocation NameLoc,
- QualType ObjectType);
+ QualType ObjectType,
+ bool AllowInjectedClassName);
/// \brief Build a new template name given a template template parameter pack
/// and the
@@ -1312,16 +1363,28 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildCoreturnStmt(SourceLocation CoreturnLoc, Expr *Result) {
- return getSema().BuildCoreturnStmt(CoreturnLoc, Result);
+ StmtResult RebuildCoreturnStmt(SourceLocation CoreturnLoc, Expr *Result,
+ bool IsImplicit) {
+ return getSema().BuildCoreturnStmt(CoreturnLoc, Result, IsImplicit);
+ }
+
+ /// \brief Build a new co_await expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildCoawaitExpr(SourceLocation CoawaitLoc, Expr *Result,
+ bool IsImplicit) {
+ return getSema().BuildResolvedCoawaitExpr(CoawaitLoc, Result, IsImplicit);
}
/// \brief Build a new co_await expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCoawaitExpr(SourceLocation CoawaitLoc, Expr *Result) {
- return getSema().BuildCoawaitExpr(CoawaitLoc, Result);
+ ExprResult RebuildDependentCoawaitExpr(SourceLocation CoawaitLoc,
+ Expr *Result,
+ UnresolvedLookupExpr *Lookup) {
+ return getSema().BuildUnresolvedCoawaitExpr(CoawaitLoc, Result, Lookup);
}
/// \brief Build a new co_yield expression.
@@ -1332,6 +1395,10 @@ public:
return getSema().BuildCoyieldExpr(CoyieldLoc, Result);
}
+ StmtResult RebuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) {
+ return getSema().BuildCoroutineBodyStmt(Args);
+ }
+
/// \brief Build a new Objective-C \@try statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -1584,6 +1651,21 @@ public:
ReductionId, UnresolvedReductions);
}
+ /// Build a new OpenMP 'task_reduction' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPTaskReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
+ return getSema().ActOnOpenMPTaskReductionClause(
+ VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
+ ReductionId, UnresolvedReductions);
+ }
+
/// \brief Build a new OpenMP 'linear' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -2153,6 +2235,9 @@ public:
Base = BaseResult.get();
QualType BaseType = Base->getType();
+ if (isArrow && !BaseType->isPointerType())
+ return ExprError();
+
// FIXME: this involves duplicating earlier analysis in a lot of
// cases; we should avoid this when possible.
LookupResult R(getSema(), MemberNameInfo, Sema::LookupMemberName);
@@ -3146,6 +3231,10 @@ private:
TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType ObjectType,
NamedDecl *FirstQualifierInScope,
CXXScopeSpec &SS);
+
+ QualType TransformDependentNameType(TypeLocBuilder &TLB,
+ DependentNameTypeLoc TL,
+ bool DeducibleTSTContext);
};
template<typename Derived>
@@ -3563,6 +3652,19 @@ TreeTransform<Derived>
case DeclarationName::CXXUsingDirective:
return NameInfo;
+ case DeclarationName::CXXDeductionGuideName: {
+ TemplateDecl *OldTemplate = Name.getCXXDeductionGuideTemplate();
+ TemplateDecl *NewTemplate = cast_or_null<TemplateDecl>(
+ getDerived().TransformDecl(NameInfo.getLoc(), OldTemplate));
+ if (!NewTemplate)
+ return DeclarationNameInfo();
+
+ DeclarationNameInfo NewNameInfo(NameInfo);
+ NewNameInfo.setName(
+ SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(NewTemplate));
+ return NewNameInfo;
+ }
+
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName: {
@@ -3602,7 +3704,8 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
TemplateName Name,
SourceLocation NameLoc,
QualType ObjectType,
- NamedDecl *FirstQualifierInScope) {
+ NamedDecl *FirstQualifierInScope,
+ bool AllowInjectedClassName) {
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
TemplateDecl *Template = QTN->getTemplateDecl();
assert(Template && "qualified template name must refer to a template");
@@ -3639,11 +3742,12 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
*DTN->getIdentifier(),
NameLoc,
ObjectType,
- FirstQualifierInScope);
+ FirstQualifierInScope,
+ AllowInjectedClassName);
}
return getDerived().RebuildTemplateName(SS, DTN->getOperator(), NameLoc,
- ObjectType);
+ ObjectType, AllowInjectedClassName);
}
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
@@ -3782,7 +3886,9 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
case TemplateArgument::Expression: {
// Template argument expressions are constant expressions.
EnterExpressionEvaluationContext Unevaluated(
- getSema(), Uneval ? Sema::Unevaluated : Sema::ConstantEvaluated);
+ getSema(), Uneval
+ ? Sema::ExpressionEvaluationContext::Unevaluated
+ : Sema::ExpressionEvaluationContext::ConstantEvaluated);
Expr *InputExpr = Input.getSourceExpression();
if (!InputExpr) InputExpr = Input.getArgument().getAsExpr();
@@ -4035,11 +4141,57 @@ TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) {
llvm_unreachable("unhandled type loc!");
}
-/// FIXME: By default, this routine adds type qualifiers only to types
-/// that can have qualifiers, and silently suppresses those qualifiers
-/// that are not permitted (e.g., qualifiers on reference or function
-/// types). This is the right thing for template instantiation, but
-/// probably not for other clients.
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformTypeWithDeducedTST(QualType T) {
+ if (!isa<DependentNameType>(T))
+ return TransformType(T);
+
+ if (getDerived().AlreadyTransformed(T))
+ return T;
+ TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo(T,
+ getDerived().getBaseLocation());
+ TypeSourceInfo *NewDI = getDerived().TransformTypeWithDeducedTST(DI);
+ return NewDI ? NewDI->getType() : QualType();
+}
+
+template<typename Derived>
+TypeSourceInfo *
+TreeTransform<Derived>::TransformTypeWithDeducedTST(TypeSourceInfo *DI) {
+ if (!isa<DependentNameType>(DI->getType()))
+ return TransformType(DI);
+
+ // Refine the base location to the type's location.
+ TemporaryBase Rebase(*this, DI->getTypeLoc().getBeginLoc(),
+ getDerived().getBaseEntity());
+ if (getDerived().AlreadyTransformed(DI->getType()))
+ return DI;
+
+ TypeLocBuilder TLB;
+
+ TypeLoc TL = DI->getTypeLoc();
+ TLB.reserve(TL.getFullDataSize());
+
+ Qualifiers Quals;
+ auto QTL = TL.getAs<QualifiedTypeLoc>();
+ if (QTL)
+ TL = QTL.getUnqualifiedLoc();
+
+ auto DNTL = TL.castAs<DependentNameTypeLoc>();
+
+ QualType Result = getDerived().TransformDependentNameType(
+ TLB, DNTL, /*DeducedTSTContext*/true);
+ if (Result.isNull())
+ return nullptr;
+
+ if (QTL) {
+ Result = getDerived().RebuildQualifiedType(
+ Result, QTL.getBeginLoc(), QTL.getType().getLocalQualifiers());
+ TLB.TypeWasModifiedSafely(Result);
+ }
+
+ return TLB.getTypeSourceInfo(SemaRef.Context, Result);
+}
+
template<typename Derived>
QualType
TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
@@ -4050,64 +4202,71 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
- // Silently suppress qualifiers if the result type can't be qualified.
- // FIXME: this is the right thing for template instantiation, but
- // probably not for other clients.
- if (Result->isFunctionType() || Result->isReferenceType())
- return Result;
+ Result = getDerived().RebuildQualifiedType(Result, T.getBeginLoc(), Quals);
+
+ // RebuildQualifiedType might have updated the type, but not in a way
+ // that invalidates the TypeLoc. (There's no location information for
+ // qualifiers.)
+ TLB.TypeWasModifiedSafely(Result);
+
+ return Result;
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
+ SourceLocation Loc,
+ Qualifiers Quals) {
+ // C++ [dcl.fct]p7:
+ // [When] adding cv-qualifications on top of the function type [...] the
+ // cv-qualifiers are ignored.
+ // C++ [dcl.ref]p1:
+ // when the cv-qualifiers are introduced through the use of a typedef-name
+ // or decltype-specifier [...] the cv-qualifiers are ignored.
+ // Note that [dcl.ref]p1 lists all cases in which cv-qualifiers can be
+ // applied to a reference type.
+ // FIXME: This removes all qualifiers, not just cv-qualifiers!
+ if (T->isFunctionType() || T->isReferenceType())
+ return T;
// Suppress Objective-C lifetime qualifiers if they don't make sense for the
// resulting type.
if (Quals.hasObjCLifetime()) {
- if (!Result->isObjCLifetimeType() && !Result->isDependentType())
+ if (!T->isObjCLifetimeType() && !T->isDependentType())
Quals.removeObjCLifetime();
- else if (Result.getObjCLifetime()) {
+ else if (T.getObjCLifetime()) {
// Objective-C ARC:
// A lifetime qualifier applied to a substituted template parameter
// overrides the lifetime qualifier from the template argument.
const AutoType *AutoTy;
if (const SubstTemplateTypeParmType *SubstTypeParam
- = dyn_cast<SubstTemplateTypeParmType>(Result)) {
+ = dyn_cast<SubstTemplateTypeParmType>(T)) {
QualType Replacement = SubstTypeParam->getReplacementType();
Qualifiers Qs = Replacement.getQualifiers();
Qs.removeObjCLifetime();
- Replacement
- = SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(),
- Qs);
- Result = SemaRef.Context.getSubstTemplateTypeParmType(
- SubstTypeParam->getReplacedParameter(),
- Replacement);
- TLB.TypeWasModifiedSafely(Result);
- } else if ((AutoTy = dyn_cast<AutoType>(Result)) && AutoTy->isDeduced()) {
+ Replacement = SemaRef.Context.getQualifiedType(
+ Replacement.getUnqualifiedType(), Qs);
+ T = SemaRef.Context.getSubstTemplateTypeParmType(
+ SubstTypeParam->getReplacedParameter(), Replacement);
+ } else if ((AutoTy = dyn_cast<AutoType>(T)) && AutoTy->isDeduced()) {
// 'auto' types behave the same way as template parameters.
QualType Deduced = AutoTy->getDeducedType();
Qualifiers Qs = Deduced.getQualifiers();
Qs.removeObjCLifetime();
- Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(),
- Qs);
- Result = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(),
- AutoTy->isDependentType());
- TLB.TypeWasModifiedSafely(Result);
+ Deduced =
+ SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs);
+ T = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(),
+ AutoTy->isDependentType());
} else {
// Otherwise, complain about the addition of a qualifier to an
// already-qualified type.
- SourceRange R = T.getUnqualifiedLoc().getSourceRange();
- SemaRef.Diag(R.getBegin(), diag::err_attr_objc_ownership_redundant)
- << Result << R;
-
+ // FIXME: Why is this check not in Sema::BuildQualifiedType?
+ SemaRef.Diag(Loc, diag::err_attr_objc_ownership_redundant) << T;
Quals.removeObjCLifetime();
}
}
}
- if (!Quals.empty()) {
- Result = SemaRef.BuildQualifiedType(Result, T.getBeginLoc(), Quals);
- // BuildQualifiedType might not add qualifiers if they are invalid.
- if (Result.hasLocalQualifiers())
- TLB.push<QualifiedTypeLoc>(Result);
- // No location information to preserve.
- }
- return Result;
+ return SemaRef.BuildQualifiedType(T, Loc, Quals);
}
template<typename Derived>
@@ -4153,11 +4312,9 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
TemplateSpecializationTypeLoc SpecTL =
TL.castAs<TemplateSpecializationTypeLoc>();
- TemplateName Template
- = getDerived().TransformTemplateName(SS,
- SpecTL.getTypePtr()->getTemplateName(),
- SpecTL.getTemplateNameLoc(),
- ObjectType, UnqualLookup);
+ TemplateName Template = getDerived().TransformTemplateName(
+ SS, SpecTL.getTypePtr()->getTemplateName(), SpecTL.getTemplateNameLoc(),
+ ObjectType, UnqualLookup, /*AllowInjectedClassName*/true);
if (Template.isNull())
return nullptr;
@@ -4171,7 +4328,8 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
= getDerived().RebuildTemplateName(SS,
*SpecTL.getTypePtr()->getIdentifier(),
SpecTL.getTemplateNameLoc(),
- ObjectType, UnqualLookup);
+ ObjectType, UnqualLookup,
+ /*AllowInjectedClassName*/true);
if (Template.isNull())
return nullptr;
@@ -4435,8 +4593,8 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
Expr *Size = TL.getSizeExpr();
if (Size) {
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
Size = getDerived().TransformExpr(Size).template getAs<Expr>();
Size = SemaRef.ActOnConstantExpression(Size).get();
}
@@ -4482,8 +4640,15 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
if (ElementType.isNull())
return QualType();
- ExprResult SizeResult
- = getDerived().TransformExpr(T->getSizeExpr());
+ ExprResult SizeResult;
+ {
+ EnterExpressionEvaluationContext Context(
+ SemaRef, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ SizeResult = getDerived().TransformExpr(T->getSizeExpr());
+ }
+ if (SizeResult.isInvalid())
+ return QualType();
+ SizeResult = SemaRef.ActOnFinishFullExpr(SizeResult.get());
if (SizeResult.isInvalid())
return QualType();
@@ -4522,8 +4687,8 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB,
return QualType();
// Array bounds are constant expressions.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
// Prefer the expression from the TypeLoc; the other may have been uniqued.
Expr *origSize = TL.getSizeExpr();
@@ -4572,8 +4737,8 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
return QualType();
// Vector sizes are constant expressions.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Size = getDerived().TransformExpr(T->getSizeExpr());
Size = SemaRef.ActOnConstantExpression(Size);
@@ -5040,8 +5205,8 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
// Instantiate a dynamic noexcept expression, if any.
if (ESI.Type == EST_ComputedNoexcept) {
- EnterExpressionEvaluationContext Unevaluated(getSema(),
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ getSema(), Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult NoexceptExpr = getDerived().TransformExpr(ESI.NoexceptExpr);
if (NoexceptExpr.isInvalid())
return true;
@@ -5208,8 +5373,9 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
TypeOfExprTypeLoc TL) {
// typeof expressions are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
- Sema::ReuseLambdaContextDecl);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
ExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr());
if (E.isInvalid())
@@ -5266,8 +5432,9 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
const DecltypeType *T = TL.getTypePtr();
// decltype expressions are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
- nullptr, /*IsDecltype=*/ true);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, nullptr,
+ /*IsDecltype=*/true);
ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
if (E.isInvalid())
@@ -5342,6 +5509,37 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
}
template<typename Derived>
+QualType TreeTransform<Derived>::TransformDeducedTemplateSpecializationType(
+ TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {
+ const DeducedTemplateSpecializationType *T = TL.getTypePtr();
+
+ CXXScopeSpec SS;
+ TemplateName TemplateName = getDerived().TransformTemplateName(
+ SS, T->getTemplateName(), TL.getTemplateNameLoc());
+ if (TemplateName.isNull())
+ return QualType();
+
+ QualType OldDeduced = T->getDeducedType();
+ QualType NewDeduced;
+ if (!OldDeduced.isNull()) {
+ NewDeduced = getDerived().TransformType(OldDeduced);
+ if (NewDeduced.isNull())
+ return QualType();
+ }
+
+ QualType Result = getDerived().RebuildDeducedTemplateSpecializationType(
+ TemplateName, NewDeduced);
+ if (Result.isNull())
+ return QualType();
+
+ DeducedTemplateSpecializationTypeLoc NewTL =
+ TLB.push<DeducedTemplateSpecializationTypeLoc>(Result);
+ NewTL.setTemplateNameLoc(TL.getTemplateNameLoc());
+
+ return Result;
+}
+
+template<typename Derived>
QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB,
RecordTypeLoc TL) {
const RecordType *T = TL.getTypePtr();
@@ -5811,8 +6009,14 @@ TreeTransform<Derived>::TransformParenType(TypeLocBuilder &TLB,
}
template<typename Derived>
-QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
- DependentNameTypeLoc TL) {
+QualType TreeTransform<Derived>::TransformDependentNameType(
+ TypeLocBuilder &TLB, DependentNameTypeLoc TL) {
+ return TransformDependentNameType(TLB, TL, false);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformDependentNameType(
+ TypeLocBuilder &TLB, DependentNameTypeLoc TL, bool DeducedTSTContext) {
const DependentNameType *T = TL.getTypePtr();
NestedNameSpecifierLoc QualifierLoc
@@ -5825,7 +6029,8 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
TL.getElaboratedKeywordLoc(),
QualifierLoc,
T->getIdentifier(),
- TL.getNameLoc());
+ TL.getNameLoc(),
+ DeducedTSTContext);
if (Result.isNull())
return QualType();
@@ -5879,12 +6084,10 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB,
NewTemplateArgs))
return QualType();
- QualType Result
- = getDerived().RebuildDependentTemplateSpecializationType(T->getKeyword(),
- QualifierLoc,
- T->getIdentifier(),
- TL.getTemplateNameLoc(),
- NewTemplateArgs);
+ QualType Result = getDerived().RebuildDependentTemplateSpecializationType(
+ T->getKeyword(), QualifierLoc, T->getIdentifier(),
+ TL.getTemplateNameLoc(), NewTemplateArgs,
+ /*AllowInjectedClassName*/ false);
if (Result.isNull())
return QualType();
@@ -6206,8 +6409,8 @@ StmtResult
TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) {
ExprResult LHS, RHS;
{
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
// Transform the left-hand case value.
LHS = getDerived().TransformExpr(S->getLHS());
@@ -6667,9 +6870,114 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
- // The coroutine body should be re-formed by the caller if necessary.
- // FIXME: The coroutine body is always rebuilt by ActOnFinishFunctionBody
- return getDerived().TransformStmt(S->getBody());
+ auto *ScopeInfo = SemaRef.getCurFunction();
+ auto *FD = cast<FunctionDecl>(SemaRef.CurContext);
+ assert(FD && ScopeInfo && !ScopeInfo->CoroutinePromise &&
+ ScopeInfo->NeedsCoroutineSuspends &&
+ ScopeInfo->CoroutineSuspends.first == nullptr &&
+ ScopeInfo->CoroutineSuspends.second == nullptr &&
+ "expected clean scope info");
+
+ // Set that we have (possibly-invalid) suspend points before we do anything
+ // that may fail.
+ ScopeInfo->setNeedsCoroutineSuspends(false);
+
+ // The new CoroutinePromise object needs to be built and put into the current
+ // FunctionScopeInfo before any transformations or rebuilding occurs.
+ auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation());
+ if (!Promise)
+ return StmtError();
+ getDerived().transformedLocalDecl(S->getPromiseDecl(), Promise);
+ ScopeInfo->CoroutinePromise = Promise;
+
+ // Transform the implicit coroutine statements we built during the initial
+ // parse.
+ StmtResult InitSuspend = getDerived().TransformStmt(S->getInitSuspendStmt());
+ if (InitSuspend.isInvalid())
+ return StmtError();
+ StmtResult FinalSuspend =
+ getDerived().TransformStmt(S->getFinalSuspendStmt());
+ if (FinalSuspend.isInvalid())
+ return StmtError();
+ ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
+ assert(isa<Expr>(InitSuspend.get()) && isa<Expr>(FinalSuspend.get()));
+
+ StmtResult BodyRes = getDerived().TransformStmt(S->getBody());
+ if (BodyRes.isInvalid())
+ return StmtError();
+
+ CoroutineStmtBuilder Builder(SemaRef, *FD, *ScopeInfo, BodyRes.get());
+ if (Builder.isInvalid())
+ return StmtError();
+
+ Expr *ReturnObject = S->getReturnValueInit();
+ assert(ReturnObject && "the return object is expected to be valid");
+ ExprResult Res = getDerived().TransformInitializer(ReturnObject,
+ /*NoCopyInit*/ false);
+ if (Res.isInvalid())
+ return StmtError();
+ Builder.ReturnValue = Res.get();
+
+ if (S->hasDependentPromiseType()) {
+ assert(!Promise->getType()->isDependentType() &&
+ "the promise type must no longer be dependent");
+ assert(!S->getFallthroughHandler() && !S->getExceptionHandler() &&
+ !S->getReturnStmtOnAllocFailure() && !S->getDeallocate() &&
+ "these nodes should not have been built yet");
+ if (!Builder.buildDependentStatements())
+ return StmtError();
+ } else {
+ if (auto *OnFallthrough = S->getFallthroughHandler()) {
+ StmtResult Res = getDerived().TransformStmt(OnFallthrough);
+ if (Res.isInvalid())
+ return StmtError();
+ Builder.OnFallthrough = Res.get();
+ }
+
+ if (auto *OnException = S->getExceptionHandler()) {
+ StmtResult Res = getDerived().TransformStmt(OnException);
+ if (Res.isInvalid())
+ return StmtError();
+ Builder.OnException = Res.get();
+ }
+
+ if (auto *OnAllocFailure = S->getReturnStmtOnAllocFailure()) {
+ StmtResult Res = getDerived().TransformStmt(OnAllocFailure);
+ if (Res.isInvalid())
+ return StmtError();
+ Builder.ReturnStmtOnAllocFailure = Res.get();
+ }
+
+ // Transform any additional statements we may have already built
+ assert(S->getAllocate() && S->getDeallocate() &&
+ "allocation and deallocation calls must already be built");
+ ExprResult AllocRes = getDerived().TransformExpr(S->getAllocate());
+ if (AllocRes.isInvalid())
+ return StmtError();
+ Builder.Allocate = AllocRes.get();
+
+ ExprResult DeallocRes = getDerived().TransformExpr(S->getDeallocate());
+ if (DeallocRes.isInvalid())
+ return StmtError();
+ Builder.Deallocate = DeallocRes.get();
+
+ assert(S->getResultDecl() && "ResultDecl must already be built");
+ StmtResult ResultDecl = getDerived().TransformStmt(S->getResultDecl());
+ if (ResultDecl.isInvalid())
+ return StmtError();
+ Builder.ResultDecl = ResultDecl.get();
+
+ if (auto *ReturnStmt = S->getReturnStmt()) {
+ StmtResult Res = getDerived().TransformStmt(ReturnStmt);
+ if (Res.isInvalid())
+ return StmtError();
+ Builder.ReturnStmt = Res.get();
+ }
+ }
+ if (!Builder.buildParameterMoves())
+ return StmtError();
+
+ return getDerived().RebuildCoroutineBodyStmt(Builder);
}
template<typename Derived>
@@ -6682,7 +6990,8 @@ TreeTransform<Derived>::TransformCoreturnStmt(CoreturnStmt *S) {
// Always rebuild; we don't know if this needs to be injected into a new
// context or if the promise type has changed.
- return getDerived().RebuildCoreturnStmt(S->getKeywordLoc(), Result.get());
+ return getDerived().RebuildCoreturnStmt(S->getKeywordLoc(), Result.get(),
+ S->isImplicit());
}
template<typename Derived>
@@ -6695,7 +7004,29 @@ TreeTransform<Derived>::TransformCoawaitExpr(CoawaitExpr *E) {
// Always rebuild; we don't know if this needs to be injected into a new
// context or if the promise type has changed.
- return getDerived().RebuildCoawaitExpr(E->getKeywordLoc(), Result.get());
+ return getDerived().RebuildCoawaitExpr(E->getKeywordLoc(), Result.get(),
+ E->isImplicit());
+}
+
+template <typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformDependentCoawaitExpr(DependentCoawaitExpr *E) {
+ ExprResult OperandResult = getDerived().TransformInitializer(E->getOperand(),
+ /*NotCopyInit*/ false);
+ if (OperandResult.isInvalid())
+ return ExprError();
+
+ ExprResult LookupResult = getDerived().TransformUnresolvedLookupExpr(
+ E->getOperatorCoawaitLookup());
+
+ if (LookupResult.isInvalid())
+ return ExprError();
+
+ // Always rebuild; we don't know if this needs to be injected into a new
+ // context or if the promise type has changed.
+ return getDerived().RebuildDependentCoawaitExpr(
+ E->getKeywordLoc(), OperandResult.get(),
+ cast<UnresolvedLookupExpr>(LookupResult.get()));
}
template<typename Derived>
@@ -7239,8 +7570,12 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(
StmtResult Body;
{
Sema::CompoundScopeRAII CompoundScope(getSema());
- Body = getDerived().TransformStmt(
- cast<CapturedStmt>(D->getAssociatedStmt())->getCapturedStmt());
+ int ThisCaptureLevel =
+ Sema::getOpenMPCaptureLevels(D->getDirectiveKind());
+ Stmt *CS = D->getAssociatedStmt();
+ while (--ThisCaptureLevel >= 0)
+ CS = cast<CapturedStmt>(CS)->getCapturedStmt();
+ Body = getDerived().TransformStmt(CS);
}
AssociatedStmt =
getDerived().getSema().ActOnOpenMPRegionEnd(Body, TClauses);
@@ -8080,6 +8415,51 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
}
template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPTaskReductionClause(
+ OMPTaskReductionClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ CXXScopeSpec ReductionIdScopeSpec;
+ ReductionIdScopeSpec.Adopt(C->getQualifierLoc());
+
+ DeclarationNameInfo NameInfo = C->getNameInfo();
+ if (NameInfo.getName()) {
+ NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
+ if (!NameInfo.getName())
+ return nullptr;
+ }
+ // Build a list of all UDR decls with the same names ranged by the Scopes.
+ // The Scope boundary is a duplication of the previous decl.
+ llvm::SmallVector<Expr *, 16> UnresolvedReductions;
+ for (auto *E : C->reduction_ops()) {
+ // Transform all the decls.
+ if (E) {
+ auto *ULE = cast<UnresolvedLookupExpr>(E);
+ UnresolvedSet<8> Decls;
+ for (auto *D : ULE->decls()) {
+ NamedDecl *InstD =
+ cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D));
+ Decls.addDecl(InstD, InstD->getAccess());
+ }
+ UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
+ /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end()));
+ } else
+ UnresolvedReductions.push_back(nullptr);
+ }
+ return getDerived().RebuildOMPTaskReductionClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
+ C->getLocEnd(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions);
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
@@ -8642,8 +9022,9 @@ TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(
// C++0x [expr.sizeof]p1:
// The operand is either an expression, which is an unevaluated operand
// [...]
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
- Sema::ReuseLambdaContextDecl);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
// Try to recover if we have something like sizeof(T::X) where X is a type.
// Notably, there must be *exactly* one set of parens if X is a type.
@@ -8855,7 +9236,7 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
return E;
Sema::FPContractStateRAII FPContractState(getSema());
- getSema().FPFeatures.fp_contract = E->isFPContractable();
+ getSema().FPFeatures = E->getFPFeatures();
return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
LHS.get(), RHS.get());
@@ -9335,7 +9716,7 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
return SemaRef.MaybeBindToTemporary(E);
Sema::FPContractStateRAII FPContractState(getSema());
- getSema().FPFeatures.fp_contract = E->isFPContractable();
+ getSema().FPFeatures = E->getFPFeatures();
return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
E->getOperatorLoc(),
@@ -9435,7 +9816,8 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
CXXFunctionalCastExpr *E) {
- TypeSourceInfo *Type = getDerived().TransformType(E->getTypeInfoAsWritten());
+ TypeSourceInfo *Type =
+ getDerived().TransformTypeWithDeducedTST(E->getTypeInfoAsWritten());
if (!Type)
return ExprError();
@@ -9478,8 +9860,9 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
// after we perform semantic analysis. We speculatively assume it is
// unevaluated; it will get fixed later if the subexpression is in fact
// potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
- Sema::ReuseLambdaContextDecl);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
if (SubExpr.isInvalid())
@@ -9514,7 +9897,8 @@ TreeTransform<Derived>::TransformCXXUuidofExpr(CXXUuidofExpr *E) {
E->getLocEnd());
}
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand());
if (SubExpr.isInvalid())
@@ -9624,8 +10008,8 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// Transform the type that we're allocating
- TypeSourceInfo *AllocTypeInfo
- = getDerived().TransformType(E->getAllocatedTypeSourceInfo());
+ TypeSourceInfo *AllocTypeInfo =
+ getDerived().TransformTypeWithDeducedTST(E->getAllocatedTypeSourceInfo());
if (!AllocTypeInfo)
return ExprError();
@@ -10128,7 +10512,8 @@ TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
ExprResult SubExpr;
{
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
SubExpr = getDerived().TransformExpr(E->getDimensionExpression());
if (SubExpr.isInvalid())
return ExprError();
@@ -10149,7 +10534,8 @@ ExprResult
TreeTransform<Derived>::TransformExpressionTraitExpr(ExpressionTraitExpr *E) {
ExprResult SubExpr;
{
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
SubExpr = getDerived().TransformExpr(E->getQueriedExpression());
if (SubExpr.isInvalid())
return ExprError();
@@ -10336,7 +10722,8 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
CXXTemporaryObjectExpr *E) {
- TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo());
+ TypeSourceInfo *T =
+ getDerived().TransformTypeWithDeducedTST(E->getTypeSourceInfo());
if (!T)
return ExprError();
@@ -10384,8 +10771,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
C != CEnd; ++C) {
if (!E->isInitCapture(C))
continue;
- EnterExpressionEvaluationContext EEEC(getSema(),
- Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext EEEC(
+ getSema(), Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
ExprResult NewExprInitResult = getDerived().TransformInitializer(
C->getCapturedVar()->getInit(),
C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
@@ -10461,7 +10848,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
auto *P = NewCallOperator->getParamDecl(I);
if (P->hasUninstantiatedDefaultArg()) {
EnterExpressionEvaluationContext Eval(
- getSema(), Sema::PotentiallyEvaluatedIfUsed, P);
+ getSema(),
+ Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, P);
ExprResult R = getDerived().TransformExpr(
E->getCallOperator()->getParamDecl(I)->getDefaultArg());
P->setDefaultArg(R.get());
@@ -10601,7 +10989,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Enter a new evaluation context to insulate the lambda from any
// cleanups from the enclosing full-expression.
- getSema().PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ getSema().PushExpressionEvaluationContext(
+ Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
// Instantiate the body of the lambda expression.
StmtResult Body =
@@ -10633,7 +11022,8 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *E) {
- TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo());
+ TypeSourceInfo *T =
+ getDerived().TransformTypeWithDeducedTST(E->getTypeSourceInfo());
if (!T)
return ExprError();
@@ -10836,7 +11226,8 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) {
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
ExprResult SubExpr = getDerived().TransformExpr(E->getOperand());
if (SubExpr.isInvalid())
return ExprError();
@@ -10869,7 +11260,8 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
if (!E->isValueDependent())
return E;
- EnterExpressionEvaluationContext Unevaluated(getSema(), Sema::Unevaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ getSema(), Sema::ExpressionEvaluationContext::Unevaluated);
ArrayRef<TemplateArgument> PackArgs;
TemplateArgument ArgStorage;
@@ -12018,7 +12410,8 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
const IdentifierInfo &Name,
SourceLocation NameLoc,
QualType ObjectType,
- NamedDecl *FirstQualifierInScope) {
+ NamedDecl *FirstQualifierInScope,
+ bool AllowInjectedClassName) {
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&Name, NameLoc);
Sema::TemplateTy Template;
@@ -12027,7 +12420,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
SS, TemplateKWLoc, TemplateName,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
- Template);
+ Template, AllowInjectedClassName);
return Template.get();
}
@@ -12036,7 +12429,8 @@ TemplateName
TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
OverloadedOperatorKind Operator,
SourceLocation NameLoc,
- QualType ObjectType) {
+ QualType ObjectType,
+ bool AllowInjectedClassName) {
UnqualifiedId Name;
// FIXME: Bogus location information.
SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc };
@@ -12047,7 +12441,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
SS, TemplateKWLoc, Name,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
- Template);
+ Template, AllowInjectedClassName);
return Template.get();
}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp
index ecd249c..684ec24 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp
@@ -147,9 +147,6 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::OCLQueue:
ID = PREDEF_TYPE_QUEUE_ID;
break;
- case BuiltinType::OCLNDRange:
- ID = PREDEF_TYPE_NDRANGE_ID;
- break;
case BuiltinType::OCLReserveID:
ID = PREDEF_TYPE_RESERVE_ID_ID;
break;
@@ -254,6 +251,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::VarTemplateSpecialization:
case Decl::VarTemplatePartialSpecialization:
case Decl::Function:
+ case Decl::CXXDeductionGuide:
case Decl::CXXMethod:
case Decl::CXXConstructor:
case Decl::CXXDestructor:
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
index 53224e2..50be74f 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
@@ -26,6 +26,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/ODRHash.h"
#include "clang/AST/RawCommentList.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
@@ -36,6 +37,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Sanitizers.h"
@@ -72,6 +74,7 @@
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -289,6 +292,33 @@ static bool checkLanguageOptions(const LangOptions &LangOpts,
return true;
}
+ // Sanitizer feature mismatches are treated as compatible differences. If
+ // compatible differences aren't allowed, we still only want to check for
+ // mismatches of non-modular sanitizers (the only ones which can affect AST
+ // generation).
+ if (!AllowCompatibleDifferences) {
+ SanitizerMask ModularSanitizers = getPPTransparentSanitizers();
+ SanitizerSet ExistingSanitizers = ExistingLangOpts.Sanitize;
+ SanitizerSet ImportedSanitizers = LangOpts.Sanitize;
+ ExistingSanitizers.clear(ModularSanitizers);
+ ImportedSanitizers.clear(ModularSanitizers);
+ if (ExistingSanitizers.Mask != ImportedSanitizers.Mask) {
+ const std::string Flag = "-fsanitize=";
+ if (Diags) {
+#define SANITIZER(NAME, ID) \
+ { \
+ bool InExistingModule = ExistingSanitizers.has(SanitizerKind::ID); \
+ bool InImportedModule = ImportedSanitizers.has(SanitizerKind::ID); \
+ if (InExistingModule != InImportedModule) \
+ Diags->Report(diag::err_pch_targetopt_feature_mismatch) \
+ << InExistingModule << (Flag + NAME); \
+ }
+#include "clang/Basic/Sanitizers.def"
+ }
+ return true;
+ }
+ }
+
return false;
}
@@ -461,19 +491,9 @@ static bool checkDiagnosticMappings(DiagnosticsEngine &StoredDiags,
return checkDiagnosticGroupMappings(StoredDiags, Diags, Complain);
}
-bool PCHValidator::ReadDiagnosticOptions(
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
- DiagnosticsEngine &ExistingDiags = PP.getDiagnostics();
- IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs());
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagIDs, DiagOpts.get()));
- // This should never fail, because we would have processed these options
- // before writing them to an ASTFile.
- ProcessWarningOptions(*Diags, *DiagOpts, /*Report*/false);
-
- ModuleManager &ModuleMgr = Reader.getModuleManager();
- assert(ModuleMgr.size() >= 1 && "what ASTFile is this then");
-
+/// Return the top import module if it is implicit, nullptr otherwise.
+static Module *getTopImportImplicitModule(ModuleManager &ModuleMgr,
+ Preprocessor &PP) {
// If the original import came from a file explicitly generated by the user,
// don't check the diagnostic mappings.
// FIXME: currently this is approximated by checking whether this is not a
@@ -481,21 +501,41 @@ bool PCHValidator::ReadDiagnosticOptions(
// Note: ModuleMgr.rbegin() may not be the current module, but it must be in
// the transitive closure of its imports, since unrelated modules cannot be
// imported until after this module finishes validation.
- ModuleFile *TopImport = *ModuleMgr.rbegin();
+ ModuleFile *TopImport = &*ModuleMgr.rbegin();
while (!TopImport->ImportedBy.empty())
TopImport = TopImport->ImportedBy[0];
if (TopImport->Kind != MK_ImplicitModule)
- return false;
+ return nullptr;
StringRef ModuleName = TopImport->ModuleName;
assert(!ModuleName.empty() && "diagnostic options read before module name");
Module *M = PP.getHeaderSearchInfo().lookupModule(ModuleName);
assert(M && "missing module");
+ return M;
+}
+
+bool PCHValidator::ReadDiagnosticOptions(
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
+ DiagnosticsEngine &ExistingDiags = PP.getDiagnostics();
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagIDs, DiagOpts.get()));
+ // This should never fail, because we would have processed these options
+ // before writing them to an ASTFile.
+ ProcessWarningOptions(*Diags, *DiagOpts, /*Report*/false);
+
+ ModuleManager &ModuleMgr = Reader.getModuleManager();
+ assert(ModuleMgr.size() >= 1 && "what ASTFile is this then");
+
+ Module *TopM = getTopImportImplicitModule(ModuleMgr, PP);
+ if (!TopM)
+ return false;
// FIXME: if the diagnostics are incompatible, save a DiagnosticOptions that
// contains the union of their flags.
- return checkDiagnosticMappings(*Diags, ExistingDiags, M->IsSystem, Complain);
+ return checkDiagnosticMappings(*Diags, ExistingDiags, TopM->IsSystem,
+ Complain);
}
/// \brief Collect the macro definitions provided by the given preprocessor
@@ -816,7 +856,7 @@ static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II,
II.isPoisoned() ||
(IsModule ? II.hasRevertedBuiltin() : II.getObjCOrBuiltinID()) ||
II.hasRevertedTokenIDToIdentifier() ||
- (!(IsModule && Reader.getContext().getLangOpts().CPlusPlus) &&
+ (!(IsModule && Reader.getPreprocessor().getLangOpts().CPlusPlus) &&
II.getFETokenInfo<void>());
}
@@ -943,6 +983,10 @@ DeclarationNameKey::DeclarationNameKey(DeclarationName Name)
case DeclarationName::CXXLiteralOperatorName:
Data = (uint64_t)Name.getCXXLiteralIdentifier();
break;
+ case DeclarationName::CXXDeductionGuideName:
+ Data = (uint64_t)Name.getCXXDeductionGuideTemplate()
+ ->getDeclName().getAsIdentifierInfo();
+ break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
@@ -959,6 +1003,7 @@ unsigned DeclarationNameKey::getHash() const {
switch (Kind) {
case DeclarationName::Identifier:
case DeclarationName::CXXLiteralOperatorName:
+ case DeclarationName::CXXDeductionGuideName:
ID.AddString(((IdentifierInfo*)Data)->getName());
break;
case DeclarationName::ObjCZeroArgSelector:
@@ -1002,6 +1047,8 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) {
uint64_t Data;
switch (Kind) {
case DeclarationName::Identifier:
+ case DeclarationName::CXXLiteralOperatorName:
+ case DeclarationName::CXXDeductionGuideName:
Data = (uint64_t)Reader.getLocalIdentifier(
F, endian::readNext<uint32_t, little, unaligned>(d));
break;
@@ -1016,10 +1063,6 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) {
case DeclarationName::CXXOperatorName:
Data = *d++; // OverloadedOperatorKind
break;
- case DeclarationName::CXXLiteralOperatorName:
- Data = (uint64_t)Reader.getLocalIdentifier(
- F, endian::readNext<uint32_t, little, unaligned>(d));
- break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
@@ -1103,9 +1146,9 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M,
return false;
}
-void ASTReader::Error(StringRef Msg) {
+void ASTReader::Error(StringRef Msg) const {
Error(diag::err_fe_pch_malformed, Msg);
- if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight() &&
+ if (PP.getLangOpts().Modules && !Diags.isDiagnosticInFlight() &&
!PP.getHeaderSearchInfo().getModuleCachePath().empty()) {
Diag(diag::note_module_cache_path)
<< PP.getHeaderSearchInfo().getModuleCachePath();
@@ -1113,7 +1156,7 @@ void ASTReader::Error(StringRef Msg) {
}
void ASTReader::Error(unsigned DiagID,
- StringRef Arg1, StringRef Arg2) {
+ StringRef Arg1, StringRef Arg2) const {
if (Diags.isDiagnosticInFlight())
Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2);
else
@@ -1278,10 +1321,15 @@ bool ASTReader::ReadSLocEntry(int ID) {
unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob);
if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) {
+ if (!llvm::zlib::isAvailable()) {
+ Error("zlib is not available");
+ return nullptr;
+ }
SmallString<0> Uncompressed;
- if (llvm::zlib::uncompress(Blob, Uncompressed, Record[0]) !=
- llvm::zlib::StatusOK) {
- Error("could not decompress embedded file contents");
+ if (llvm::Error E =
+ llvm::zlib::uncompress(Blob, Uncompressed, Record[0])) {
+ Error("could not decompress embedded file contents: " +
+ llvm::toString(std::move(E)));
return nullptr;
}
return llvm::MemoryBuffer::getMemBufferCopy(Uncompressed, Name);
@@ -1343,15 +1391,14 @@ bool ASTReader::ReadSLocEntry(int ID) {
const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
unsigned NumFileDecls = Record[7];
- if (NumFileDecls) {
+ if (NumFileDecls && ContextObj) {
assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
NumFileDecls));
}
const SrcMgr::ContentCache *ContentCache
- = SourceMgr.getOrCreateContentCache(File,
- /*isSystemFile=*/FileCharacter != SrcMgr::C_User);
+ = SourceMgr.getOrCreateContentCache(File, isSystem(FileCharacter));
if (OverriddenBuffer && !ContentCache->BufferOverridden &&
ContentCache->ContentsEntry == ContentCache->OrigEntry &&
!ContentCache->getRawBuffer()) {
@@ -1473,7 +1520,7 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
Stream.JumpToBit(Offset);
RecordData Record;
- SmallVector<IdentifierInfo*, 16> MacroArgs;
+ SmallVector<IdentifierInfo*, 16> MacroParams;
MacroInfo *Macro = nullptr;
while (true) {
@@ -1513,9 +1560,8 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
return Macro;
unsigned NextIndex = 1; // Skip identifier ID.
- SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]);
SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
- MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID);
+ MacroInfo *MI = PP.AllocateMacroInfo(Loc);
MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex));
MI->setIsUsed(Record[NextIndex++]);
MI->setUsedForHeaderGuard(Record[NextIndex++]);
@@ -1525,17 +1571,17 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
bool isC99VarArgs = Record[NextIndex++];
bool isGNUVarArgs = Record[NextIndex++];
bool hasCommaPasting = Record[NextIndex++];
- MacroArgs.clear();
+ MacroParams.clear();
unsigned NumArgs = Record[NextIndex++];
for (unsigned i = 0; i != NumArgs; ++i)
- MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++]));
+ MacroParams.push_back(getLocalIdentifier(F, Record[NextIndex++]));
// Install function-like macro info.
MI->setIsFunctionLike();
if (isC99VarArgs) MI->setIsC99Varargs();
if (isGNUVarArgs) MI->setIsGNUVarargs();
if (hasCommaPasting) MI->setHasCommaPasting();
- MI->setArgumentList(MacroArgs, PP.getPreprocessorAllocator());
+ MI->setParameterList(MacroParams, PP.getPreprocessorAllocator());
}
// Remember that we saw this macro last so that we add the tokens that
@@ -1575,7 +1621,11 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
}
PreprocessedEntityID
-ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const {
+ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M,
+ unsigned LocalID) const {
+ if (!M.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(M);
+
ContinuousRangeMap<uint32_t, int, 2>::const_iterator
I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS);
assert(I != M.PreprocessedEntityRemap.end()
@@ -1646,9 +1696,9 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
HeaderFileInfo HFI;
unsigned Flags = *d++;
// FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp.
- HFI.isImport |= (Flags >> 4) & 0x01;
- HFI.isPragmaOnce |= (Flags >> 3) & 0x01;
- HFI.DirInfo = (Flags >> 1) & 0x03;
+ HFI.isImport |= (Flags >> 5) & 0x01;
+ HFI.isPragmaOnce |= (Flags >> 4) & 0x01;
+ HFI.DirInfo = (Flags >> 1) & 0x07;
HFI.IndexHeaderMapHeader = Flags & 0x01;
// FIXME: Find a better way to handle this. Maybe just store a
// "has been included" flag?
@@ -1707,15 +1757,15 @@ void ASTReader::ReadDefinedMacros() {
// Note that we are loading defined macros.
Deserializing Macros(this);
- for (auto &I : llvm::reverse(ModuleMgr)) {
- BitstreamCursor &MacroCursor = I->MacroCursor;
+ for (ModuleFile &I : llvm::reverse(ModuleMgr)) {
+ BitstreamCursor &MacroCursor = I.MacroCursor;
// If there was no preprocessor block, skip this file.
if (MacroCursor.getBitcodeBytes().empty())
continue;
BitstreamCursor Cursor = MacroCursor;
- Cursor.JumpToBit(I->MacroStartOffset);
+ Cursor.JumpToBit(I.MacroStartOffset);
RecordData Record;
while (true) {
@@ -1737,7 +1787,7 @@ void ASTReader::ReadDefinedMacros() {
case PP_MACRO_OBJECT_LIKE:
case PP_MACRO_FUNCTION_LIKE: {
- IdentifierInfo *II = getLocalIdentifier(*I, Record[0]);
+ IdentifierInfo *II = getLocalIdentifier(I, Record[0]);
if (II->isOutOfDate())
updateOutOfDateIdentifier(*II);
break;
@@ -1978,6 +2028,7 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
R.StoredTime = static_cast<time_t>(Record[2]);
R.Overridden = static_cast<bool>(Record[3]);
R.Transient = static_cast<bool>(Record[4]);
+ R.TopLevelModuleMap = static_cast<bool>(Record[5]);
R.Filename = Blob;
ResolveImportedPath(F, R.Filename);
return R;
@@ -2149,7 +2200,7 @@ static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) {
ASTReader::ASTReadResult ASTReader::ReadOptionsBlock(
BitstreamCursor &Stream, unsigned ClientLoadCapabilities,
bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener,
- std::string &SuggestedPredefines, bool ValidateDiagnosticOptions) {
+ std::string &SuggestedPredefines) {
if (Stream.EnterSubBlock(OPTIONS_BLOCK_ID))
return Failure;
@@ -2191,15 +2242,6 @@ ASTReader::ASTReadResult ASTReader::ReadOptionsBlock(
break;
}
- case DIAGNOSTIC_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
- if (ValidateDiagnosticOptions &&
- !AllowCompatibleConfigurationMismatch &&
- ParseDiagnosticOptions(Record, Complain, Listener))
- return OutOfDate;
- break;
- }
-
case FILE_SYSTEM_OPTIONS: {
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
if (!AllowCompatibleConfigurationMismatch &&
@@ -2240,6 +2282,23 @@ ASTReader::ReadControlBlock(ModuleFile &F,
return Failure;
}
+ // Lambda to read the unhashed control block the first time it's called.
+ //
+ // For PCM files, the unhashed control block cannot be read until after the
+ // MODULE_NAME record. However, PCH files have no MODULE_NAME, and yet still
+ // need to look ahead before reading the IMPORTS record. For consistency,
+ // this block is always read somehow (see BitstreamEntry::EndBlock).
+ bool HasReadUnhashedControlBlock = false;
+ auto readUnhashedControlBlockOnce = [&]() {
+ if (!HasReadUnhashedControlBlock) {
+ HasReadUnhashedControlBlock = true;
+ if (ASTReadResult Result =
+ readUnhashedControlBlock(F, ImportedBy, ClientLoadCapabilities))
+ return Result;
+ }
+ return Success;
+ };
+
// Read all of the records and blocks in the control block.
RecordData Record;
unsigned NumInputs = 0;
@@ -2252,6 +2311,11 @@ ASTReader::ReadControlBlock(ModuleFile &F,
Error("malformed block record in AST file");
return Failure;
case llvm::BitstreamEntry::EndBlock: {
+ // Validate the module before returning. This call catches an AST with
+ // no module name and no imports.
+ if (ASTReadResult Result = readUnhashedControlBlockOnce())
+ return Result;
+
// Validate input files.
const HeaderSearchOptions &HSOpts =
PP.getHeaderSearchInfo().getHeaderSearchOpts();
@@ -2323,13 +2387,10 @@ ASTReader::ReadControlBlock(ModuleFile &F,
// FIXME: Allow this for files explicitly specified with -include-pch.
bool AllowCompatibleConfigurationMismatch =
F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule;
- const HeaderSearchOptions &HSOpts =
- PP.getHeaderSearchInfo().getHeaderSearchOpts();
Result = ReadOptionsBlock(Stream, ClientLoadCapabilities,
AllowCompatibleConfigurationMismatch,
- *Listener, SuggestedPredefines,
- HSOpts.ModulesValidateDiagnosticOptions);
+ *Listener, SuggestedPredefines);
if (Result == Failure) {
Error("malformed block record in AST file");
return Result;
@@ -2403,12 +2464,13 @@ ASTReader::ReadControlBlock(ModuleFile &F,
break;
}
- case SIGNATURE:
- assert((!F.Signature || F.Signature == Record[0]) && "signature changed");
- F.Signature = Record[0];
- break;
-
case IMPORTS: {
+ // Validate the AST before processing any imports (otherwise, untangling
+ // them can be error-prone and expensive). A module will have a name and
+ // will already have been validated, but this catches the PCH case.
+ if (ASTReadResult Result = readUnhashedControlBlockOnce())
+ return Result;
+
// Load each of the imported PCH files.
unsigned Idx = 0, N = Record.size();
while (Idx < N) {
@@ -2421,7 +2483,10 @@ ASTReader::ReadControlBlock(ModuleFile &F,
ReadUntranslatedSourceLocation(Record[Idx++]);
off_t StoredSize = (off_t)Record[Idx++];
time_t StoredModTime = (time_t)Record[Idx++];
- ASTFileSignature StoredSignature = Record[Idx++];
+ ASTFileSignature StoredSignature = {
+ {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
+ (uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
+ (uint32_t)Record[Idx++]}}};
auto ImportedFile = ReadPath(F, Record, Idx);
// If our client can't cope with us being out of date, we can't cope with
@@ -2473,6 +2538,12 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.ModuleName = Blob;
if (Listener)
Listener->ReadModuleName(F.ModuleName);
+
+ // Validate the AST as soon as we have a name so we can exit early on
+ // failure.
+ if (ASTReadResult Result = readUnhashedControlBlockOnce())
+ return Result;
+
break;
case MODULE_DIRECTORY: {
@@ -2513,6 +2584,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.InputFileOffsets =
(const llvm::support::unaligned_uint64_t *)Blob.data();
F.InputFilesLoaded.resize(NumInputs);
+ F.NumUserInputFiles = NumUserInputs;
break;
}
}
@@ -2542,10 +2614,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// contains any declarations lexically within it (which it always does!).
// This usually has no cost, since we very rarely need the lookup map for
// the translation unit outside C++.
- DeclContext *DC = Context.getTranslationUnitDecl();
- if (DC->hasExternalLexicalStorage() &&
- !getContext().getLangOpts().CPlusPlus)
- DC->setMustBuildLookupTable();
+ if (ASTContext *Ctx = ContextObj) {
+ DeclContext *DC = Ctx->getTranslationUnitDecl();
+ if (DC->hasExternalLexicalStorage() && !Ctx->getLangOpts().CPlusPlus)
+ DC->setMustBuildLookupTable();
+ }
return Success;
}
@@ -2601,7 +2674,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
case SUBMODULE_BLOCK_ID:
- if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities))
+ if (ASTReadResult Result =
+ ReadSubmoduleBlock(F, ClientLoadCapabilities))
return Result;
break;
@@ -2633,7 +2707,33 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Read and process a record.
Record.clear();
StringRef Blob;
- switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
+ auto RecordType =
+ (ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob);
+
+ // If we're not loading an AST context, we don't care about most records.
+ if (!ContextObj) {
+ switch (RecordType) {
+ case IDENTIFIER_TABLE:
+ case IDENTIFIER_OFFSET:
+ case INTERESTING_IDENTIFIERS:
+ case STATISTICS:
+ case PP_CONDITIONAL_STACK:
+ case PP_COUNTER_VALUE:
+ case SOURCE_LOCATION_OFFSETS:
+ case MODULE_OFFSET_MAP:
+ case SOURCE_MANAGER_LINE_TABLE:
+ case SOURCE_LOCATION_PRELOADS:
+ case PPD_ENTITIES_OFFSETS:
+ case HEADER_SEARCH_TABLE:
+ case IMPORTED_MODULES:
+ case MACRO_OFFSET:
+ break;
+ default:
+ continue;
+ }
+ }
+
+ switch (RecordType) {
default: // Default behavior: ignore.
break;
@@ -2692,7 +2792,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
case TU_UPDATE_LEXICAL: {
- DeclContext *TU = Context.getTranslationUnitDecl();
+ DeclContext *TU = ContextObj->getTranslationUnitDecl();
LexicalContents Contents(
reinterpret_cast<const llvm::support::unaligned_uint32_t *>(
Blob.data()),
@@ -2710,7 +2810,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
- PendingUpdateRecords.push_back(std::make_pair(ID, D));
+ PendingUpdateRecords.push_back(
+ PendingUpdateRecord(ID, D, /*JustLoaded=*/false));
break;
}
@@ -2766,6 +2867,14 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
+ case MODULAR_CODEGEN_DECLS:
+ // FIXME: Skip reading this record if our ASTConsumer doesn't care about
+ // them (ie: if we're not codegenerating this module).
+ if (F.Kind == MK_MainFile)
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
case SPECIAL_TYPES:
if (SpecialTypes.empty()) {
for (unsigned I = 0, N = Record.size(); I != N; ++I)
@@ -2870,6 +2979,21 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
break;
+ case PP_CONDITIONAL_STACK:
+ if (!Record.empty()) {
+ SmallVector<PPConditionalInfo, 4> ConditionalStack;
+ for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) {
+ auto Loc = ReadSourceLocation(F, Record, Idx);
+ bool WasSkipping = Record[Idx++];
+ bool FoundNonSkip = Record[Idx++];
+ bool FoundElse = Record[Idx++];
+ ConditionalStack.push_back(
+ {Loc, WasSkipping, FoundNonSkip, FoundElse});
+ }
+ PP.setReplayablePreambleConditionalStack(ConditionalStack);
+ }
+ break;
+
case PP_COUNTER_VALUE:
if (!Record.empty() && Listener)
Listener->ReadCounter(F, Record[0]);
@@ -2916,80 +3040,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
}
- case MODULE_OFFSET_MAP: {
- // Additional remapping information.
- const unsigned char *Data = (const unsigned char*)Blob.data();
- const unsigned char *DataEnd = Data + Blob.size();
-
- // If we see this entry before SOURCE_LOCATION_OFFSETS, add placeholders.
- if (F.SLocRemap.find(0) == F.SLocRemap.end()) {
- F.SLocRemap.insert(std::make_pair(0U, 0));
- F.SLocRemap.insert(std::make_pair(2U, 1));
- }
-
- // Continuous range maps we may be updating in our module.
- typedef ContinuousRangeMap<uint32_t, int, 2>::Builder
- RemapBuilder;
- RemapBuilder SLocRemap(F.SLocRemap);
- RemapBuilder IdentifierRemap(F.IdentifierRemap);
- RemapBuilder MacroRemap(F.MacroRemap);
- RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap);
- RemapBuilder SubmoduleRemap(F.SubmoduleRemap);
- RemapBuilder SelectorRemap(F.SelectorRemap);
- RemapBuilder DeclRemap(F.DeclRemap);
- RemapBuilder TypeRemap(F.TypeRemap);
-
- while (Data < DataEnd) {
- using namespace llvm::support;
- uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data);
- StringRef Name = StringRef((const char*)Data, Len);
- Data += Len;
- ModuleFile *OM = ModuleMgr.lookup(Name);
- if (!OM) {
- Error("SourceLocation remap refers to unknown module");
- return Failure;
- }
-
- uint32_t SLocOffset =
- endian::readNext<uint32_t, little, unaligned>(Data);
- uint32_t IdentifierIDOffset =
- endian::readNext<uint32_t, little, unaligned>(Data);
- uint32_t MacroIDOffset =
- endian::readNext<uint32_t, little, unaligned>(Data);
- uint32_t PreprocessedEntityIDOffset =
- endian::readNext<uint32_t, little, unaligned>(Data);
- uint32_t SubmoduleIDOffset =
- endian::readNext<uint32_t, little, unaligned>(Data);
- uint32_t SelectorIDOffset =
- endian::readNext<uint32_t, little, unaligned>(Data);
- uint32_t DeclIDOffset =
- endian::readNext<uint32_t, little, unaligned>(Data);
- uint32_t TypeIndexOffset =
- endian::readNext<uint32_t, little, unaligned>(Data);
-
- uint32_t None = std::numeric_limits<uint32_t>::max();
-
- auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset,
- RemapBuilder &Remap) {
- if (Offset != None)
- Remap.insert(std::make_pair(Offset,
- static_cast<int>(BaseOffset - Offset)));
- };
- mapOffset(SLocOffset, OM->SLocEntryBaseOffset, SLocRemap);
- mapOffset(IdentifierIDOffset, OM->BaseIdentifierID, IdentifierRemap);
- mapOffset(MacroIDOffset, OM->BaseMacroID, MacroRemap);
- mapOffset(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID,
- PreprocessedEntityRemap);
- mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap);
- mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap);
- mapOffset(DeclIDOffset, OM->BaseDeclID, DeclRemap);
- mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap);
-
- // Global -> local mappings.
- F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
- }
+ case MODULE_OFFSET_MAP:
+ F.ModuleOffsetMap = Blob;
break;
- }
case SOURCE_MANAGER_LINE_TABLE:
if (ParseLineTable(F, Record))
@@ -3103,7 +3156,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// If we've already loaded the decl, perform the updates when we finish
// loading this block.
if (Decl *D = GetExistingDecl(ID))
- PendingUpdateRecords.push_back(std::make_pair(ID, D));
+ PendingUpdateRecords.push_back(
+ PendingUpdateRecord(ID, D, /*JustLoaded=*/false));
}
break;
}
@@ -3123,14 +3177,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
F.ObjCCategories.swap(Record);
break;
- case DIAG_PRAGMA_MAPPINGS:
- if (F.PragmaDiagMappings.empty())
- F.PragmaDiagMappings.swap(Record);
- else
- F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(),
- Record.begin(), Record.end());
- break;
-
case CUDA_SPECIAL_DECL_REFS:
// Later tables overwrite earlier ones.
// FIXME: Modules will have trouble with this.
@@ -3245,8 +3291,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
for (unsigned I = 0, N = Record.size(); I != N; /**/) {
unsigned GlobalID = getGlobalSubmoduleID(F, Record[I++]);
SourceLocation Loc = ReadSourceLocation(F, Record, I);
- if (GlobalID)
+ if (GlobalID) {
ImportedModules.push_back(ImportedSubmodule(GlobalID, Loc));
+ if (DeserializationListener)
+ DeserializationListener->ModuleImportRead(GlobalID, Loc);
+ }
}
}
break;
@@ -3319,7 +3368,110 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
ForceCUDAHostDeviceDepth = Record[0];
break;
+
+ case PACK_PRAGMA_OPTIONS: {
+ if (Record.size() < 3) {
+ Error("invalid pragma pack record");
+ return Failure;
+ }
+ PragmaPackCurrentValue = Record[0];
+ PragmaPackCurrentLocation = ReadSourceLocation(F, Record[1]);
+ unsigned NumStackEntries = Record[2];
+ unsigned Idx = 3;
+ // Reset the stack when importing a new module.
+ PragmaPackStack.clear();
+ for (unsigned I = 0; I < NumStackEntries; ++I) {
+ PragmaPackStackEntry Entry;
+ Entry.Value = Record[Idx++];
+ Entry.Location = ReadSourceLocation(F, Record[Idx++]);
+ PragmaPackStrings.push_back(ReadString(Record, Idx));
+ Entry.SlotLabel = PragmaPackStrings.back();
+ PragmaPackStack.push_back(Entry);
+ }
+ break;
+ }
+ }
+ }
+}
+
+void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const {
+ assert(!F.ModuleOffsetMap.empty() && "no module offset map to read");
+
+ // Additional remapping information.
+ const unsigned char *Data = (const unsigned char*)F.ModuleOffsetMap.data();
+ const unsigned char *DataEnd = Data + F.ModuleOffsetMap.size();
+ F.ModuleOffsetMap = StringRef();
+
+ // If we see this entry before SOURCE_LOCATION_OFFSETS, add placeholders.
+ if (F.SLocRemap.find(0) == F.SLocRemap.end()) {
+ F.SLocRemap.insert(std::make_pair(0U, 0));
+ F.SLocRemap.insert(std::make_pair(2U, 1));
+ }
+
+ // Continuous range maps we may be updating in our module.
+ typedef ContinuousRangeMap<uint32_t, int, 2>::Builder
+ RemapBuilder;
+ RemapBuilder SLocRemap(F.SLocRemap);
+ RemapBuilder IdentifierRemap(F.IdentifierRemap);
+ RemapBuilder MacroRemap(F.MacroRemap);
+ RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap);
+ RemapBuilder SubmoduleRemap(F.SubmoduleRemap);
+ RemapBuilder SelectorRemap(F.SelectorRemap);
+ RemapBuilder DeclRemap(F.DeclRemap);
+ RemapBuilder TypeRemap(F.TypeRemap);
+
+ while (Data < DataEnd) {
+ // FIXME: Looking up dependency modules by filename is horrible.
+ using namespace llvm::support;
+ uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data);
+ StringRef Name = StringRef((const char*)Data, Len);
+ Data += Len;
+ ModuleFile *OM = ModuleMgr.lookup(Name);
+ if (!OM) {
+ std::string Msg =
+ "SourceLocation remap refers to unknown module, cannot find ";
+ Msg.append(Name);
+ Error(Msg);
+ return;
}
+
+ uint32_t SLocOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t IdentifierIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t MacroIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t PreprocessedEntityIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t SubmoduleIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t SelectorIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t DeclIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t TypeIndexOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+
+ uint32_t None = std::numeric_limits<uint32_t>::max();
+
+ auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset,
+ RemapBuilder &Remap) {
+ if (Offset != None)
+ Remap.insert(std::make_pair(Offset,
+ static_cast<int>(BaseOffset - Offset)));
+ };
+ mapOffset(SLocOffset, OM->SLocEntryBaseOffset, SLocRemap);
+ mapOffset(IdentifierIDOffset, OM->BaseIdentifierID, IdentifierRemap);
+ mapOffset(MacroIDOffset, OM->BaseMacroID, MacroRemap);
+ mapOffset(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID,
+ PreprocessedEntityRemap);
+ mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap);
+ mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap);
+ mapOffset(DeclIDOffset, OM->BaseDeclID, DeclRemap);
+ mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap);
+
+ // Global -> local mappings.
+ F.GlobalToLocalDeclIDs[OM] = DeclIDOffset;
}
}
@@ -3330,20 +3482,13 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
unsigned Idx = 0;
F.ModuleMapPath = ReadPath(F, Record, Idx);
- if (F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule) {
- // For an explicitly-loaded module, we don't care whether the original
- // module map file exists or matches.
- return Success;
- }
-
// Try to resolve ModuleName in the current header search context and
// verify that it is found in the same module map file as we saved. If the
// top-level AST file is a main file, skip this check because there is no
// usable header search context.
assert(!F.ModuleName.empty() &&
"MODULE_NAME should come before MODULE_MAP_FILE");
- if (F.Kind == MK_ImplicitModule &&
- (*ModuleMgr.begin())->Kind != MK_MainFile) {
+ if (F.Kind == MK_ImplicitModule && ModuleMgr.begin()->Kind != MK_MainFile) {
// An implicitly-loaded module file should have its module listed in some
// module map file that we've already loaded.
Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
@@ -3456,8 +3601,8 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) {
assert(Owner->NameVisibility != Module::Hidden && "nothing to make visible?");
for (Decl *D : Names) {
- bool wasHidden = D->Hidden;
- D->Hidden = false;
+ bool wasHidden = D->isHidden();
+ D->setVisibleDespiteOwningModule();
if (wasHidden && SemaObj) {
if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) {
@@ -3524,7 +3669,7 @@ void ASTReader::mergeDefinitionVisibility(NamedDecl *Def,
if (Def->isHidden()) {
// If MergedDef is visible or becomes visible, make the definition visible.
if (!MergedDef->isHidden())
- Def->Hidden = false;
+ Def->setVisibleDespiteOwningModule();
else if (getContext().getLangOpts().ModulesLocalVisibility) {
getContext().mergeDefinitionIntoModule(
Def, MergedDef->getImportedOwningModule(),
@@ -3543,7 +3688,7 @@ bool ASTReader::loadGlobalIndex() {
return false;
if (TriedLoadingGlobalIndex || !UseGlobalIndex ||
- !Context.getLangOpts().Modules)
+ !PP.getLangOpts().Modules)
return true;
// Try to load the global index.
@@ -3561,7 +3706,7 @@ bool ASTReader::loadGlobalIndex() {
}
bool ASTReader::isGlobalIndexUnavailable() const {
- return Context.getLangOpts().Modules && UseGlobalIndex &&
+ return PP.getLangOpts().Modules && UseGlobalIndex &&
!hasGlobalIndex() && TriedLoadingGlobalIndex;
}
@@ -3573,6 +3718,8 @@ static void updateModuleTimestamp(ModuleFile &MF) {
if (EC)
return;
OS << "Timestamp file\n";
+ OS.close();
+ OS.clear_error(); // Avoid triggering a fatal error.
}
/// \brief Given a cursor at the start of an AST file, scan ahead and drop the
@@ -3617,14 +3764,16 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
Deserializing AnASTFile(this);
// Bump the generation number.
- unsigned PreviousGeneration = incrementGeneration(Context);
+ unsigned PreviousGeneration = 0;
+ if (ContextObj)
+ PreviousGeneration = incrementGeneration(*ContextObj);
unsigned NumModules = ModuleMgr.size();
SmallVector<ImportedModule, 4> Loaded;
- switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
- /*ImportedBy=*/nullptr, Loaded,
- 0, 0, 0,
- ClientLoadCapabilities)) {
+ switch (ASTReadResult ReadResult =
+ ReadASTCore(FileName, Type, ImportLoc,
+ /*ImportedBy=*/nullptr, Loaded, 0, 0,
+ ASTFileSignature(), ClientLoadCapabilities)) {
case Failure:
case Missing:
case OutOfDate:
@@ -3635,11 +3784,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
for (const ImportedModule &IM : Loaded)
LoadedSet.insert(IM.Mod);
- ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(),
- LoadedSet,
- Context.getLangOpts().Modules
- ? &PP.getHeaderSearchInfo().getModuleMap()
- : nullptr);
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, LoadedSet,
+ PP.getLangOpts().Modules
+ ? &PP.getHeaderSearchInfo().getModuleMap()
+ : nullptr);
// If we find that any modules are unusable, the global index is going
// to be out-of-date. Just remove it.
@@ -3685,6 +3833,13 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
SourceMgr.getLoadedSLocEntryByID(Index);
}
+ // Map the original source file ID into the ID space of the current
+ // compilation.
+ if (F.OriginalSourceFileID.isValid()) {
+ F.OriginalSourceFileID = FileID::get(
+ F.SLocEntryBaseID + F.OriginalSourceFileID.getOpaqueValue() - 1);
+ }
+
// Preload all the pending interesting identifiers by marking them out of
// date.
for (auto Offset : F.PreloadIdentifierOffsets) {
@@ -3726,7 +3881,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
F.ImportLoc = TranslateSourceLocation(*M->ImportedBy, M->ImportLoc);
}
- if (!Context.getLangOpts().CPlusPlus ||
+ if (!PP.getLangOpts().CPlusPlus ||
(Type != MK_ImplicitModule && Type != MK_ExplicitModule &&
Type != MK_PrebuiltModule)) {
// Mark all of the identifiers in the identifier table as being out of date,
@@ -3783,7 +3938,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
// Might be unnecessary as use declarations are only used to build the
// module itself.
- InitializeContext();
+ if (ContextObj)
+ InitializeContext();
if (SemaObj)
UpdateSema();
@@ -3793,10 +3949,6 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule();
if (PrimaryModule.OriginalSourceFileID.isValid()) {
- PrimaryModule.OriginalSourceFileID
- = FileID::get(PrimaryModule.SLocEntryBaseID
- + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1);
-
// If this AST file is a precompiled preamble, then set the
// preamble file ID of the source manager to the file source file
// from which the preamble was built.
@@ -3809,10 +3961,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
// For any Objective-C class definitions we have already loaded, make sure
// that we load any additional categories.
- for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) {
- loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(),
- ObjCClassesLoaded[I],
- PreviousGeneration);
+ if (ContextObj) {
+ for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) {
+ loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(),
+ ObjCClassesLoaded[I],
+ PreviousGeneration);
+ }
}
if (PP.getHeaderSearchInfo()
@@ -3986,6 +4140,12 @@ ASTReader::ReadASTCore(StringRef FileName,
Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc));
return Success;
+ case UNHASHED_CONTROL_BLOCK_ID:
+ // This block is handled using look-ahead during ReadControlBlock. We
+ // shouldn't get here!
+ Error("malformed block record in AST file");
+ return Failure;
+
default:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
@@ -3998,6 +4158,122 @@ ASTReader::ReadASTCore(StringRef FileName,
return Success;
}
+ASTReader::ASTReadResult
+ASTReader::readUnhashedControlBlock(ModuleFile &F, bool WasImportedBy,
+ unsigned ClientLoadCapabilities) {
+ const HeaderSearchOptions &HSOpts =
+ PP.getHeaderSearchInfo().getHeaderSearchOpts();
+ bool AllowCompatibleConfigurationMismatch =
+ F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule;
+
+ ASTReadResult Result = readUnhashedControlBlockImpl(
+ &F, F.Data, ClientLoadCapabilities, AllowCompatibleConfigurationMismatch,
+ Listener.get(),
+ WasImportedBy ? false : HSOpts.ModulesValidateDiagnosticOptions);
+
+ // If F was directly imported by another module, it's implicitly validated by
+ // the importing module.
+ if (DisableValidation || WasImportedBy ||
+ (AllowConfigurationMismatch && Result == ConfigurationMismatch))
+ return Success;
+
+ if (Result == Failure) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ if (Result == OutOfDate && F.Kind == MK_ImplicitModule) {
+ // If this module has already been finalized in the PCMCache, we're stuck
+ // with it; we can only load a single version of each module.
+ //
+ // This can happen when a module is imported in two contexts: in one, as a
+ // user module; in another, as a system module (due to an import from
+ // another module marked with the [system] flag). It usually indicates a
+ // bug in the module map: this module should also be marked with [system].
+ //
+ // If -Wno-system-headers (the default), and the first import is as a
+ // system module, then validation will fail during the as-user import,
+ // since -Werror flags won't have been validated. However, it's reasonable
+ // to treat this consistently as a system module.
+ //
+ // If -Wsystem-headers, the PCM on disk was built with
+ // -Wno-system-headers, and the first import is as a user module, then
+ // validation will fail during the as-system import since the PCM on disk
+ // doesn't guarantee that -Werror was respected. However, the -Werror
+ // flags were checked during the initial as-user import.
+ if (PCMCache.isBufferFinal(F.FileName)) {
+ Diag(diag::warn_module_system_bit_conflict) << F.FileName;
+ return Success;
+ }
+ }
+
+ return Result;
+}
+
+ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl(
+ ModuleFile *F, llvm::StringRef StreamData, unsigned ClientLoadCapabilities,
+ bool AllowCompatibleConfigurationMismatch, ASTReaderListener *Listener,
+ bool ValidateDiagnosticOptions) {
+ // Initialize a stream.
+ BitstreamCursor Stream(StreamData);
+
+ // Sniff for the signature.
+ if (!startsWithASTFileMagic(Stream))
+ return Failure;
+
+ // Scan for the UNHASHED_CONTROL_BLOCK_ID block.
+ if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID))
+ return Failure;
+
+ // Read all of the records in the options block.
+ RecordData Record;
+ ASTReadResult Result = Success;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ case llvm::BitstreamEntry::SubBlock:
+ return Failure;
+
+ case llvm::BitstreamEntry::EndBlock:
+ return Result;
+
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ switch (
+ (UnhashedControlBlockRecordTypes)Stream.readRecord(Entry.ID, Record)) {
+ case SIGNATURE: {
+ if (F)
+ std::copy(Record.begin(), Record.end(), F->Signature.data());
+ break;
+ }
+ case DIAGNOSTIC_OPTIONS: {
+ bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
+ if (Listener && ValidateDiagnosticOptions &&
+ !AllowCompatibleConfigurationMismatch &&
+ ParseDiagnosticOptions(Record, Complain, *Listener))
+ Result = OutOfDate; // Don't return early. Read the signature.
+ break;
+ }
+ case DIAG_PRAGMA_MAPPINGS:
+ if (!F)
+ break;
+ if (F->PragmaDiagMappings.empty())
+ F->PragmaDiagMappings.swap(Record);
+ else
+ F->PragmaDiagMappings.insert(F->PragmaDiagMappings.end(),
+ Record.begin(), Record.end());
+ break;
+ }
+ }
+}
+
/// Parse a record and blob containing module file extension metadata.
static bool parseModuleFileExtensionMetadata(
const SmallVectorImpl<uint64_t> &Record,
@@ -4070,6 +4346,9 @@ ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) {
}
void ASTReader::InitializeContext() {
+ assert(ContextObj && "no context to initialize");
+ ASTContext &Context = *ContextObj;
+
// If there's a listener, notify them that we "read" the translation unit.
if (DeserializationListener)
DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID,
@@ -4214,23 +4493,24 @@ void ASTReader::finalizeForWriting() {
static ASTFileSignature readASTFileSignature(StringRef PCH) {
BitstreamCursor Stream(PCH);
if (!startsWithASTFileMagic(Stream))
- return 0;
+ return ASTFileSignature();
- // Scan for the CONTROL_BLOCK_ID block.
- if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID))
- return 0;
+ // Scan for the UNHASHED_CONTROL_BLOCK_ID block.
+ if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID))
+ return ASTFileSignature();
- // Scan for SIGNATURE inside the control block.
+ // Scan for SIGNATURE inside the diagnostic options block.
ASTReader::RecordData Record;
while (true) {
llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
if (Entry.Kind != llvm::BitstreamEntry::Record)
- return 0;
+ return ASTFileSignature();
Record.clear();
StringRef Blob;
if (SIGNATURE == Stream.readRecord(Entry.ID, Record, &Blob))
- return Record[0];
+ return {{{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2],
+ (uint32_t)Record[3], (uint32_t)Record[4]}}};
}
}
@@ -4349,7 +4629,8 @@ bool ASTReader::readASTFileControlBlock(
}
// Initialize the stream
- BitstreamCursor Stream(PCHContainerRdr.ExtractPCH(**Buffer));
+ StringRef Bytes = PCHContainerRdr.ExtractPCH(**Buffer);
+ BitstreamCursor Stream(Bytes);
// Sniff for the signature.
if (!startsWithASTFileMagic(Stream))
@@ -4377,8 +4658,7 @@ bool ASTReader::readASTFileControlBlock(
std::string IgnoredSuggestedPredefines;
if (ReadOptionsBlock(Stream, ARR_ConfigurationMismatch | ARR_OutOfDate,
/*AllowCompatibleConfigurationMismatch*/ false,
- Listener, IgnoredSuggestedPredefines,
- ValidateDiagnosticOptions) != Success)
+ Listener, IgnoredSuggestedPredefines) != Success)
return true;
break;
}
@@ -4499,6 +4779,7 @@ bool ASTReader::readASTFileControlBlock(
// Look for module file extension blocks, if requested.
if (FindModuleFileExtensions) {
+ BitstreamCursor SavedStream = Stream;
while (!SkipCursorToBlock(Stream, EXTENSION_BLOCK_ID)) {
bool DoneWithExtensionBlock = false;
while (!DoneWithExtensionBlock) {
@@ -4537,16 +4818,25 @@ bool ASTReader::readASTFileControlBlock(
}
}
}
+ Stream = SavedStream;
}
+ // Scan for the UNHASHED_CONTROL_BLOCK_ID block.
+ if (readUnhashedControlBlockImpl(
+ nullptr, Bytes, ARR_ConfigurationMismatch | ARR_OutOfDate,
+ /*AllowCompatibleConfigurationMismatch*/ false, &Listener,
+ ValidateDiagnosticOptions) != Success)
+ return true;
+
return false;
}
-bool ASTReader::isAcceptableASTFile(
- StringRef Filename, FileManager &FileMgr,
- const PCHContainerReader &PCHContainerRdr, const LangOptions &LangOpts,
- const TargetOptions &TargetOpts, const PreprocessorOptions &PPOpts,
- std::string ExistingModuleCachePath) {
+bool ASTReader::isAcceptableASTFile(StringRef Filename, FileManager &FileMgr,
+ const PCHContainerReader &PCHContainerRdr,
+ const LangOptions &LangOpts,
+ const TargetOptions &TargetOpts,
+ const PreprocessorOptions &PPOpts,
+ StringRef ExistingModuleCachePath) {
SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts,
ExistingModuleCachePath, FileMgr);
return !readASTFileControlBlock(Filename, FileMgr, PCHContainerRdr,
@@ -4566,6 +4856,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
bool First = true;
Module *CurrentModule = nullptr;
+ Module::ModuleKind ModuleKind = Module::ModuleMapModule;
RecordData Record;
while (true) {
llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks();
@@ -4628,8 +4919,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Retrieve this (sub)module from the module map, creating it if
// necessary.
- CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, IsFramework,
- IsExplicit).first;
+ CurrentModule =
+ ModMap.findOrCreateModule(Name, ParentModule, IsFramework, IsExplicit)
+ .first;
// FIXME: set the definition loc for CurrentModule, or call
// ModMap.setInferredModuleAllowedBy()
@@ -4655,8 +4947,10 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
CurrentModule->setASTFile(F.File);
+ CurrentModule->PresumedModuleMapFile = F.ModuleMapPath;
}
+ CurrentModule->Kind = ModuleKind;
CurrentModule->Signature = F.Signature;
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
@@ -4696,13 +4990,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
if (!CurrentModule->getUmbrellaHeader())
ModMap.setUmbrellaHeader(CurrentModule, Umbrella, Blob);
else if (CurrentModule->getUmbrellaHeader().Entry != Umbrella) {
- // This can be a spurious difference caused by changing the VFS to
- // point to a different copy of the file, and it is too late to
- // to rebuild safely.
- // FIXME: If we wrote the virtual paths instead of the 'real' paths,
- // after input file validation only real problems would remain and we
- // could just error. For now, assume it's okay.
- break;
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Error("mismatched umbrella headers in submodule");
+ return OutOfDate;
}
}
break;
@@ -4759,6 +5049,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules);
}
+ ModuleKind = (Module::ModuleKind)Record[2];
break;
}
@@ -4792,8 +5083,8 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
}
case SUBMODULE_REQUIRES: {
- CurrentModule->addRequirement(Blob, Record[0], Context.getLangOpts(),
- Context.getTargetInfo());
+ CurrentModule->addRequirement(Blob, Record[0], PP.getLangOpts(),
+ PP.getTargetInfo());
break;
}
@@ -4819,10 +5110,12 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
}
case SUBMODULE_INITIALIZERS:
+ if (!ContextObj)
+ break;
SmallVector<uint32_t, 16> Inits;
for (auto &ID : Record)
Inits.push_back(getGlobalDeclID(F, ID));
- Context.addLazyModuleInitializers(CurrentModule, Inits);
+ ContextObj->addLazyModuleInitializers(CurrentModule, Inits);
break;
}
}
@@ -4950,6 +5243,8 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
HSOpts.ModuleCachePath = ReadString(Record, Idx);
HSOpts.ModuleUserBuildPath = ReadString(Record, Idx);
HSOpts.DisableModuleHash = Record[Idx++];
+ HSOpts.ImplicitModuleMaps = Record[Idx++];
+ HSOpts.ModuleMapFileHomeIsCwd = Record[Idx++];
HSOpts.UseBuiltinIncludes = Record[Idx++];
HSOpts.UseStandardSystemIncludes = Record[Idx++];
HSOpts.UseStandardCXXIncludes = Record[Idx++];
@@ -5288,48 +5583,141 @@ HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
}
void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
- // FIXME: Make it work properly with modules.
- SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
- for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
- ModuleFile &F = *(*I);
+ using DiagState = DiagnosticsEngine::DiagState;
+ SmallVector<DiagState *, 32> DiagStates;
+
+ for (ModuleFile &F : ModuleMgr) {
unsigned Idx = 0;
+ auto &Record = F.PragmaDiagMappings;
+ if (Record.empty())
+ continue;
+
DiagStates.clear();
- assert(!Diag.DiagStates.empty());
- DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one.
- while (Idx < F.PragmaDiagMappings.size()) {
- SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
- unsigned DiagStateID = F.PragmaDiagMappings[Idx++];
- if (DiagStateID != 0) {
- Diag.DiagStatePoints.push_back(
- DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1],
- FullSourceLoc(Loc, SourceMgr)));
- continue;
- }
- assert(DiagStateID == 0);
+ auto ReadDiagState =
+ [&](const DiagState &BasedOn, SourceLocation Loc,
+ bool IncludeNonPragmaStates) -> DiagnosticsEngine::DiagState * {
+ unsigned BackrefID = Record[Idx++];
+ if (BackrefID != 0)
+ return DiagStates[BackrefID - 1];
+
// A new DiagState was created here.
- Diag.DiagStates.push_back(*Diag.GetCurDiagState());
- DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back();
+ Diag.DiagStates.push_back(BasedOn);
+ DiagState *NewState = &Diag.DiagStates.back();
DiagStates.push_back(NewState);
- Diag.DiagStatePoints.push_back(
- DiagnosticsEngine::DiagStatePoint(NewState,
- FullSourceLoc(Loc, SourceMgr)));
- while (true) {
- assert(Idx < F.PragmaDiagMappings.size() &&
- "Invalid data, didn't find '-1' marking end of diag/map pairs");
- if (Idx >= F.PragmaDiagMappings.size()) {
- break; // Something is messed up but at least avoid infinite loop in
- // release build.
- }
- unsigned DiagID = F.PragmaDiagMappings[Idx++];
- if (DiagID == (unsigned)-1) {
- break; // no more diag/map pairs for this location.
+ unsigned Size = Record[Idx++];
+ assert(Idx + Size * 2 <= Record.size() &&
+ "Invalid data, not enough diag/map pairs");
+ while (Size--) {
+ unsigned DiagID = Record[Idx++];
+ DiagnosticMapping NewMapping =
+ DiagnosticMapping::deserialize(Record[Idx++]);
+ if (!NewMapping.isPragma() && !IncludeNonPragmaStates)
+ continue;
+
+ DiagnosticMapping &Mapping = NewState->getOrAddMapping(DiagID);
+
+ // If this mapping was specified as a warning but the severity was
+ // upgraded due to diagnostic settings, simulate the current diagnostic
+ // settings (and use a warning).
+ if (NewMapping.wasUpgradedFromWarning() && !Mapping.isErrorOrFatal()) {
+ NewMapping.setSeverity(diag::Severity::Warning);
+ NewMapping.setUpgradedFromWarning(false);
}
- diag::Severity Map = (diag::Severity)F.PragmaDiagMappings[Idx++];
- DiagnosticMapping Mapping = Diag.makeUserMapping(Map, Loc);
- Diag.GetCurDiagState()->setMapping(DiagID, Mapping);
+
+ Mapping = NewMapping;
+ }
+ return NewState;
+ };
+
+ // Read the first state.
+ DiagState *FirstState;
+ if (F.Kind == MK_ImplicitModule) {
+ // Implicitly-built modules are reused with different diagnostic
+ // settings. Use the initial diagnostic state from Diag to simulate this
+ // compilation's diagnostic settings.
+ FirstState = Diag.DiagStatesByLoc.FirstDiagState;
+ DiagStates.push_back(FirstState);
+
+ // Skip the initial diagnostic state from the serialized module.
+ assert(Record[1] == 0 &&
+ "Invalid data, unexpected backref in initial state");
+ Idx = 3 + Record[2] * 2;
+ assert(Idx < Record.size() &&
+ "Invalid data, not enough state change pairs in initial state");
+ } else if (F.isModule()) {
+ // For an explicit module, preserve the flags from the module build
+ // command line (-w, -Weverything, -Werror, ...) along with any explicit
+ // -Wblah flags.
+ unsigned Flags = Record[Idx++];
+ DiagState Initial;
+ Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1;
+ Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1;
+ Initial.WarningsAsErrors = Flags & 1; Flags >>= 1;
+ Initial.EnableAllWarnings = Flags & 1; Flags >>= 1;
+ Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1;
+ Initial.ExtBehavior = (diag::Severity)Flags;
+ FirstState = ReadDiagState(Initial, SourceLocation(), true);
+
+ // Set up the root buffer of the module to start with the initial
+ // diagnostic state of the module itself, to cover files that contain no
+ // explicit transitions (for which we did not serialize anything).
+ Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID]
+ .StateTransitions.push_back({FirstState, 0});
+ } else {
+ // For prefix ASTs, start with whatever the user configured on the
+ // command line.
+ Idx++; // Skip flags.
+ FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState,
+ SourceLocation(), false);
+ }
+
+ // Read the state transitions.
+ unsigned NumLocations = Record[Idx++];
+ while (NumLocations--) {
+ assert(Idx < Record.size() &&
+ "Invalid data, missing pragma diagnostic states");
+ SourceLocation Loc = ReadSourceLocation(F, Record[Idx++]);
+ auto IDAndOffset = SourceMgr.getDecomposedLoc(Loc);
+ assert(IDAndOffset.second == 0 && "not a start location for a FileID");
+ unsigned Transitions = Record[Idx++];
+
+ // Note that we don't need to set up Parent/ParentOffset here, because
+ // we won't be changing the diagnostic state within imported FileIDs
+ // (other than perhaps appending to the main source file, which has no
+ // parent).
+ auto &F = Diag.DiagStatesByLoc.Files[IDAndOffset.first];
+ F.StateTransitions.reserve(F.StateTransitions.size() + Transitions);
+ for (unsigned I = 0; I != Transitions; ++I) {
+ unsigned Offset = Record[Idx++];
+ auto *State =
+ ReadDiagState(*FirstState, Loc.getLocWithOffset(Offset), false);
+ F.StateTransitions.push_back({State, Offset});
}
}
+
+ // Read the final state.
+ assert(Idx < Record.size() &&
+ "Invalid data, missing final pragma diagnostic state");
+ SourceLocation CurStateLoc =
+ ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
+ auto *CurState = ReadDiagState(*FirstState, CurStateLoc, false);
+
+ if (!F.isModule()) {
+ Diag.DiagStatesByLoc.CurDiagState = CurState;
+ Diag.DiagStatesByLoc.CurDiagStateLoc = CurStateLoc;
+
+ // Preserve the property that the imaginary root file describes the
+ // current state.
+ auto &T = Diag.DiagStatesByLoc.Files[FileID()].StateTransitions;
+ if (T.empty())
+ T.push_back({CurState, 0});
+ else
+ T[0].State = CurState;
+ }
+
+ // Don't try to read these mappings again.
+ Record.clear();
}
}
@@ -5348,6 +5736,8 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
/// location. It is a helper routine for GetType, which deals with reading type
/// IDs.
QualType ASTReader::readTypeRecord(unsigned Index) {
+ assert(ContextObj && "reading type with no AST context");
+ ASTContext &Context = *ContextObj;
RecordLocation Loc = TypeCursorForIndex(Index);
BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
@@ -5508,13 +5898,13 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
}
case TYPE_FUNCTION_NO_PROTO: {
- if (Record.size() != 6) {
+ if (Record.size() != 7) {
Error("incorrect encoding of no-proto function type");
return QualType();
}
QualType ResultType = readType(*Loc.F, Record, Idx);
FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
- (CallingConv)Record[4], Record[5]);
+ (CallingConv)Record[4], Record[5], Record[6]);
return Context.getFunctionNoProtoType(ResultType, Info);
}
@@ -5526,9 +5916,10 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
/*hasregparm*/ Record[2],
/*regparm*/ Record[3],
static_cast<CallingConv>(Record[4]),
- /*produces*/ Record[5]);
+ /*produces*/ Record[5],
+ /*nocallersavedregs*/ Record[6]);
- unsigned Idx = 6;
+ unsigned Idx = 7;
EPI.Variadic = Record[Idx++];
EPI.HasTrailingReturn = Record[Idx++];
@@ -5606,6 +5997,14 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
return Context.getAutoType(Deduced, Keyword, IsDependent);
}
+ case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: {
+ TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
+ QualType Deduced = readType(*Loc.F, Record, Idx);
+ bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
+ return Context.getDeducedTemplateSpecializationType(Name, Deduced,
+ IsDependent);
+ }
+
case TYPE_RECORD: {
if (Record.size() != 2) {
Error("incorrect encoding of record type");
@@ -5840,6 +6239,17 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
return Context.getPipeType(ElementType, ReadOnly);
}
+ case TYPE_DEPENDENT_SIZED_EXT_VECTOR: {
+ unsigned Idx = 0;
+
+ // DependentSizedExtVectorType
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ Expr *SizeExpr = ReadExpr(*Loc.F);
+ SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx);
+
+ return Context.getDependentSizedExtVectorType(ElementType, SizeExpr,
+ AttrLoc);
+ }
}
llvm_unreachable("Invalid TypeCode!");
}
@@ -6037,6 +6447,11 @@ void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation());
}
+void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc(
+ DeducedTemplateSpecializationTypeLoc TL) {
+ TL.setTemplateNameLoc(ReadSourceLocation());
+}
+
void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation());
}
@@ -6179,6 +6594,9 @@ ASTReader::GetTypeSourceInfo(ModuleFile &F, const ASTReader::RecordData &Record,
}
QualType ASTReader::GetType(TypeID ID) {
+ assert(ContextObj && "reading type with no AST context");
+ ASTContext &Context = *ContextObj;
+
unsigned FastQuals = ID & Qualifiers::FastMask;
unsigned Index = ID >> Qualifiers::FastWidth;
@@ -6304,9 +6722,6 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_QUEUE_ID:
T = Context.OCLQueueTy;
break;
- case PREDEF_TYPE_NDRANGE_ID:
- T = Context.OCLNDRangeTy;
- break;
case PREDEF_TYPE_RESERVE_ID_ID:
T = Context.OCLReserveIDTy;
break;
@@ -6363,6 +6778,9 @@ ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const {
if (LocalIndex < NUM_PREDEF_TYPE_IDS)
return LocalID;
+ if (!F.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(F);
+
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS);
assert(I != F.TypeRemap.end() && "Invalid index into type index remap");
@@ -6437,12 +6855,6 @@ Decl *ASTReader::GetExternalDecl(uint32_t ID) {
return GetDecl(ID);
}
-template<typename TemplateSpecializationDecl>
-static void completeRedeclChainForTemplateSpecialization(Decl *D) {
- if (auto *TSD = dyn_cast<TemplateSpecializationDecl>(D))
- TSD->getSpecializedTemplate()->LoadLazySpecializations();
-}
-
void ASTReader::CompleteRedeclChain(const Decl *D) {
if (NumCurrentElementsDeserializing) {
// We arrange to not care about the complete redeclaration chain while we're
@@ -6516,6 +6928,9 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) {
}
CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
+ assert(ContextObj && "reading base specifiers with no AST context");
+ ASTContext &Context = *ContextObj;
+
RecordLocation Loc = getLocalBitOffset(Offset);
BitstreamCursor &Cursor = Loc.F->DeclsCursor;
SavedStreamPosition SavedPosition(Cursor);
@@ -6543,6 +6958,9 @@ ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const {
if (LocalID < NUM_PREDEF_DECL_IDS)
return LocalID;
+ if (!F.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(F);
+
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS);
assert(I != F.DeclRemap.end() && "Invalid index into decl index remap");
@@ -6644,8 +7062,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
}
Decl *ASTReader::GetExistingDecl(DeclID ID) {
+ assert(ContextObj && "reading decl with no AST context");
if (ID < NUM_PREDEF_DECL_IDS) {
- Decl *D = getPredefinedDecl(Context, (PredefinedDeclIDs)ID);
+ Decl *D = getPredefinedDecl(*ContextObj, (PredefinedDeclIDs)ID);
if (D) {
// Track that we have merged the declaration with ID \p ID into the
// pre-existing predefined declaration \p D.
@@ -6728,6 +7147,9 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) {
// Offset here is a global offset across the entire chain.
RecordLocation Loc = getLocalBitOffset(Offset);
Loc.F->DeclsCursor.JumpToBit(Loc.Offset);
+ assert(NumCurrentElementsDeserializing == 0 &&
+ "should not be called while already deserializing");
+ Deserializing D(this);
return ReadStmtFromStream(*Loc.F);
}
@@ -6920,31 +7342,6 @@ static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD,
Consumer->HandleInterestingDecl(DeclGroupRef(ImplD));
}
-void ASTReader::PassInterestingDeclsToConsumer() {
- assert(Consumer);
-
- if (PassingDeclsToConsumer)
- return;
-
- // Guard variable to avoid recursively redoing the process of passing
- // decls to consumer.
- SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
- true);
-
- // Ensure that we've loaded all potentially-interesting declarations
- // that need to be eagerly loaded.
- for (auto ID : EagerlyDeserializedDecls)
- GetDecl(ID);
- EagerlyDeserializedDecls.clear();
-
- while (!InterestingDecls.empty()) {
- Decl *D = InterestingDecls.front();
- InterestingDecls.pop_front();
-
- PassInterestingDeclToConsumer(D);
- }
-}
-
void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
PassObjCImplDeclToConsumer(ImplD, Consumer);
@@ -7062,7 +7459,7 @@ void ASTReader::PrintStats() {
}
template<typename Key, typename ModuleFile, unsigned InitialCapacity>
-static void
+LLVM_DUMP_METHOD static void
dumpModuleIDMap(StringRef Name,
const ContinuousRangeMap<Key, ModuleFile *,
InitialCapacity> &Map) {
@@ -7092,18 +7489,15 @@ LLVM_DUMP_METHOD void ASTReader::dump() {
GlobalPreprocessedEntityMap);
llvm::errs() << "\n*** PCH/Modules Loaded:";
- for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(),
- MEnd = ModuleMgr.end();
- M != MEnd; ++M)
- (*M)->dump();
+ for (ModuleFile &M : ModuleMgr)
+ M.dump();
}
/// Return the amount of memory used by memory buffers, breaking down
/// by heap-backed versus mmap'ed memory.
void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {
- for (ModuleConstIterator I = ModuleMgr.begin(),
- E = ModuleMgr.end(); I != E; ++I) {
- if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) {
+ for (ModuleFile &I : ModuleMgr) {
+ if (llvm::MemoryBuffer *buf = I.Buffer) {
size_t bytes = buf->getBufferSize();
switch (buf->getBufferKind()) {
case llvm::MemoryBuffer::MemoryBuffer_Malloc:
@@ -7132,7 +7526,7 @@ void ASTReader::InitializeSema(Sema &S) {
// FIXME: What happens if these are changed by a module import?
if (!FPPragmaOptions.empty()) {
assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS");
- SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0];
+ SemaObj->FPFeatures = FPOptions(FPPragmaOptions[0]);
}
SemaObj->OpenCLFeatures.copy(OpenCLExtensions);
@@ -7173,6 +7567,34 @@ void ASTReader::UpdateSema() {
PointersToMembersPragmaLocation);
}
SemaObj->ForceCUDAHostDeviceDepth = ForceCUDAHostDeviceDepth;
+
+ if (PragmaPackCurrentValue) {
+ // The bottom of the stack might have a default value. It must be adjusted
+ // to the current value to ensure that the packing state is preserved after
+ // popping entries that were included/imported from a PCH/module.
+ bool DropFirst = false;
+ if (!PragmaPackStack.empty() &&
+ PragmaPackStack.front().Location.isInvalid()) {
+ assert(PragmaPackStack.front().Value == SemaObj->PackStack.DefaultValue &&
+ "Expected a default alignment value");
+ SemaObj->PackStack.Stack.emplace_back(
+ PragmaPackStack.front().SlotLabel, SemaObj->PackStack.CurrentValue,
+ SemaObj->PackStack.CurrentPragmaLocation);
+ DropFirst = true;
+ }
+ for (const auto &Entry :
+ llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0))
+ SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value,
+ Entry.Location);
+ if (PragmaPackCurrentLocation.isInvalid()) {
+ assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue &&
+ "Expected a default alignment value");
+ // Keep the current values.
+ } else {
+ SemaObj->PackStack.CurrentValue = *PragmaPackCurrentValue;
+ SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation;
+ }
+ }
}
IdentifierInfo *ASTReader::get(StringRef Name) {
@@ -7187,7 +7609,7 @@ IdentifierInfo *ASTReader::get(StringRef Name) {
// all interesting declarations, and don't need to use the scope for name
// lookups). Perform the lookup in PCH files, though, since we don't build
// a complete initial identifier table if we're carrying on from a PCH.
- if (Context.getLangOpts().CPlusPlus) {
+ if (PP.getLangOpts().CPlusPlus) {
for (auto F : ModuleMgr.pch_modules())
if (Visitor(*F))
break;
@@ -7720,6 +8142,9 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
if (LocalID < NUM_PREDEF_IDENT_IDS)
return LocalID;
+ if (!M.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(M);
+
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS);
assert(I != M.IdentifierRemap.end()
@@ -7758,6 +8183,9 @@ MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) {
if (LocalID < NUM_PREDEF_MACRO_IDS)
return LocalID;
+ if (!M.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(M);
+
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS);
assert(I != M.MacroRemap.end() && "Invalid index into macro index remap");
@@ -7770,6 +8198,9 @@ ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) {
if (LocalID < NUM_PREDEF_SUBMODULE_IDS)
return LocalID;
+ if (!M.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(M);
+
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS);
assert(I != M.SubmoduleRemap.end()
@@ -7832,8 +8263,9 @@ ASTReader::getSourceDescriptor(unsigned ID) {
return ExternalASTSource::ASTSourceDescriptor(*M);
// If there is only a single PCH, return it instead.
- // Chained PCH are not suported.
- if (ModuleMgr.size() == 1) {
+ // Chained PCH are not supported.
+ const auto &PCHChain = ModuleMgr.pch_modules();
+ if (std::distance(std::begin(PCHChain), std::end(PCHChain))) {
ModuleFile &MF = ModuleMgr.getPrimaryModule();
StringRef ModuleName = llvm::sys::path::filename(MF.OriginalSourceFileName);
StringRef FileName = llvm::sys::path::filename(MF.FileName);
@@ -7843,6 +8275,13 @@ ASTReader::getSourceDescriptor(unsigned ID) {
return None;
}
+ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) {
+ auto I = BodySource.find(FD);
+ if (I == BodySource.end())
+ return EK_ReplyHazy;
+ return I->second ? EK_Never : EK_Always;
+}
+
Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
return DecodeSelector(getGlobalSelectorID(M, LocalID));
}
@@ -7886,6 +8325,9 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
if (LocalID < NUM_PREDEF_SELECTOR_IDS)
return LocalID;
+ if (!M.ModuleOffsetMap.empty())
+ ReadModuleOffsetMap(M);
+
ContinuousRangeMap<uint32_t, int, 2>::iterator I
= M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS);
assert(I != M.SelectorRemap.end()
@@ -7897,6 +8339,7 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const {
DeclarationName
ASTReader::ReadDeclarationName(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
+ ASTContext &Context = getContext();
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
switch (Kind) {
case DeclarationName::Identifier:
@@ -7915,6 +8358,10 @@ ASTReader::ReadDeclarationName(ModuleFile &F,
return Context.DeclarationNames.getCXXDestructorName(
Context.getCanonicalType(readType(F, Record, Idx)));
+ case DeclarationName::CXXDeductionGuideName:
+ return Context.DeclarationNames.getCXXDeductionGuideName(
+ ReadDeclAs<TemplateDecl>(F, Record, Idx));
+
case DeclarationName::CXXConversionFunctionName:
return Context.DeclarationNames.getCXXConversionFunctionName(
Context.getCanonicalType(readType(F, Record, Idx)));
@@ -7962,6 +8409,7 @@ void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
break;
}
}
@@ -7982,7 +8430,8 @@ void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
unsigned NumTPLists = Record[Idx++];
Info.NumTemplParamLists = NumTPLists;
if (NumTPLists) {
- Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists];
+ Info.TemplParamLists =
+ new (getContext()) TemplateParameterList *[NumTPLists];
for (unsigned i = 0; i != NumTPLists; ++i)
Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx);
}
@@ -7991,6 +8440,7 @@ void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info,
TemplateName
ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
+ ASTContext &Context = getContext();
TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++];
switch (Kind) {
case TemplateName::Template:
@@ -8051,6 +8501,7 @@ TemplateArgument ASTReader::ReadTemplateArgument(ModuleFile &F,
const RecordData &Record,
unsigned &Idx,
bool Canonicalize) {
+ ASTContext &Context = getContext();
if (Canonicalize) {
// The caller wants a canonical template argument. Sometimes the AST only
// wants template arguments in canonical form (particularly as the template
@@ -8114,9 +8565,8 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F,
Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
// TODO: Concepts
- TemplateParameterList* TemplateParams =
- TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- Params, RAngleLoc, nullptr);
+ TemplateParameterList *TemplateParams = TemplateParameterList::Create(
+ getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr);
return TemplateParams;
}
@@ -8135,11 +8585,11 @@ ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set,
const RecordData &Record, unsigned &Idx) {
unsigned NumDecls = Record[Idx++];
- Set.reserve(Context, NumDecls);
+ Set.reserve(getContext(), NumDecls);
while (NumDecls--) {
DeclID ID = ReadDeclID(F, Record, Idx);
AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
- Set.addLazyDecl(Context, ID, AS);
+ Set.addLazyDecl(getContext(), ID, AS);
}
}
@@ -8162,6 +8612,7 @@ ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
CXXCtorInitializer **
ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
+ ASTContext &Context = getContext();
unsigned NumInitializers = Record[Idx++];
assert(NumInitializers && "wrote ctor initializers but have no inits");
auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers];
@@ -8227,6 +8678,7 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
NestedNameSpecifier *
ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
+ ASTContext &Context = getContext();
unsigned N = Record[Idx++];
NestedNameSpecifier *NNS = nullptr, *Prev = nullptr;
for (unsigned I = 0; I != N; ++I) {
@@ -8282,6 +8734,7 @@ ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
NestedNameSpecifierLoc
ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
+ ASTContext &Context = getContext();
unsigned N = Record[Idx++];
NestedNameSpecifierLocBuilder Builder;
for (unsigned I = 0; I != N; ++I) {
@@ -8403,14 +8856,14 @@ CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F,
const RecordData &Record,
unsigned &Idx) {
CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx);
- return CXXTemporary::Create(Context, Decl);
+ return CXXTemporary::Create(getContext(), Decl);
}
-DiagnosticBuilder ASTReader::Diag(unsigned DiagID) {
+DiagnosticBuilder ASTReader::Diag(unsigned DiagID) const {
return Diag(CurrentImportLoc, DiagID);
}
-DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) {
+DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) const {
return Diags.Report(Loc, DiagID);
}
@@ -8439,6 +8892,7 @@ void ASTReader::ClearSwitchCaseIDs() {
}
void ASTReader::ReadComments() {
+ ASTContext &Context = getContext();
std::vector<RawComment *> Comments;
for (SmallVectorImpl<std::pair<BitstreamCursor,
serialization::ModuleFile *> >::iterator
@@ -8493,6 +8947,34 @@ void ASTReader::ReadComments() {
}
}
+void ASTReader::visitInputFiles(serialization::ModuleFile &MF,
+ bool IncludeSystem, bool Complain,
+ llvm::function_ref<void(const serialization::InputFile &IF,
+ bool isSystem)> Visitor) {
+ unsigned NumUserInputs = MF.NumUserInputFiles;
+ unsigned NumInputs = MF.InputFilesLoaded.size();
+ assert(NumUserInputs <= NumInputs);
+ unsigned N = IncludeSystem ? NumInputs : NumUserInputs;
+ for (unsigned I = 0; I < N; ++I) {
+ bool IsSystem = I >= NumUserInputs;
+ InputFile IF = getInputFile(MF, I+1, Complain);
+ Visitor(IF, IsSystem);
+ }
+}
+
+void ASTReader::visitTopLevelModuleMaps(
+ serialization::ModuleFile &MF,
+ llvm::function_ref<void(const FileEntry *FE)> Visitor) {
+ unsigned NumInputs = MF.InputFilesLoaded.size();
+ for (unsigned I = 0; I < NumInputs; ++I) {
+ InputFileInfo IFI = readInputFileInfo(MF, I + 1);
+ if (IFI.TopLevelModuleMap)
+ // FIXME: This unnecessarily re-reads the InputFileInfo.
+ if (auto *FE = getInputFile(MF, I + 1).getFile())
+ Visitor(FE);
+ }
+}
+
std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
// If we know the owning module, use it.
if (Module *M = D->getImportedOwningModule())
@@ -8583,7 +9065,7 @@ void ASTReader::finishPendingActions() {
while (!PendingUpdateRecords.empty()) {
auto Update = PendingUpdateRecords.pop_back_val();
ReadingKindTracker ReadingKind(Read_Decl, *this);
- loadDeclUpdateRecords(Update.first, Update.second);
+ loadDeclUpdateRecords(Update);
}
}
@@ -8651,9 +9133,9 @@ void ASTReader::finishPendingActions() {
// FIXME: Check for =delete/=default?
// FIXME: Complain about ODR violations here?
const FunctionDecl *Defn = nullptr;
- if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn))
+ if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) {
FD->setLazyBody(PB->second);
- else
+ } else
mergeDefinitionVisibility(const_cast<FunctionDecl*>(Defn), FD);
continue;
}
@@ -8789,24 +9271,796 @@ void ASTReader::diagnoseOdrViolations() {
continue;
bool Diagnosed = false;
- for (auto *RD : Merge.second) {
+ CXXRecordDecl *FirstRecord = Merge.first;
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
+ for (CXXRecordDecl *SecondRecord : Merge.second) {
// Multiple different declarations got merged together; tell the user
// where they came from.
- if (Merge.first != RD) {
- // FIXME: Walk the definition, figure out what's different,
- // and diagnose that.
- if (!Diagnosed) {
- std::string Module = getOwningModuleNameForDiagnostic(Merge.first);
- Diag(Merge.first->getLocation(),
- diag::err_module_odr_violation_different_definitions)
- << Merge.first << Module.empty() << Module;
- Diagnosed = true;
+ if (FirstRecord == SecondRecord)
+ continue;
+
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
+ using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>;
+ DeclHashes FirstHashes;
+ DeclHashes SecondHashes;
+ ODRHash Hash;
+
+ auto PopulateHashes = [&Hash, FirstRecord](DeclHashes &Hashes,
+ CXXRecordDecl *Record) {
+ for (auto *D : Record->decls()) {
+ // Due to decl merging, the first CXXRecordDecl is the parent of
+ // Decls in both records.
+ if (!ODRHash::isWhitelistedDecl(D, FirstRecord))
+ continue;
+ Hash.clear();
+ Hash.AddSubDecl(D);
+ Hashes.emplace_back(D, Hash.CalculateHash());
+ }
+ };
+ PopulateHashes(FirstHashes, FirstRecord);
+ PopulateHashes(SecondHashes, SecondRecord);
+
+ // Used with err_module_odr_violation_mismatch_decl and
+ // note_module_odr_violation_mismatch_decl
+ // This list should be the same Decl's as in ODRHash::isWhiteListedDecl
+ enum {
+ EndOfClass,
+ PublicSpecifer,
+ PrivateSpecifer,
+ ProtectedSpecifer,
+ StaticAssert,
+ Field,
+ CXXMethod,
+ TypeAlias,
+ TypeDef,
+ Var,
+ Friend,
+ Other
+ } FirstDiffType = Other,
+ SecondDiffType = Other;
+
+ auto DifferenceSelector = [](Decl *D) {
+ assert(D && "valid Decl required");
+ switch (D->getKind()) {
+ default:
+ return Other;
+ case Decl::AccessSpec:
+ switch (D->getAccess()) {
+ case AS_public:
+ return PublicSpecifer;
+ case AS_private:
+ return PrivateSpecifer;
+ case AS_protected:
+ return ProtectedSpecifer;
+ case AS_none:
+ break;
+ }
+ llvm_unreachable("Invalid access specifier");
+ case Decl::StaticAssert:
+ return StaticAssert;
+ case Decl::Field:
+ return Field;
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ return CXXMethod;
+ case Decl::TypeAlias:
+ return TypeAlias;
+ case Decl::Typedef:
+ return TypeDef;
+ case Decl::Var:
+ return Var;
+ case Decl::Friend:
+ return Friend;
}
+ };
+
+ Decl *FirstDecl = nullptr;
+ Decl *SecondDecl = nullptr;
+ auto FirstIt = FirstHashes.begin();
+ auto SecondIt = SecondHashes.begin();
+
+ // If there is a diagnoseable difference, FirstDiffType and
+ // SecondDiffType will not be Other and FirstDecl and SecondDecl will be
+ // filled in if not EndOfClass.
+ while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) {
+ if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() &&
+ FirstIt->second == SecondIt->second) {
+ ++FirstIt;
+ ++SecondIt;
+ continue;
+ }
+
+ FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first;
+ SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first;
- Diag(RD->getLocation(),
+ FirstDiffType = FirstDecl ? DifferenceSelector(FirstDecl) : EndOfClass;
+ SecondDiffType =
+ SecondDecl ? DifferenceSelector(SecondDecl) : EndOfClass;
+
+ break;
+ }
+
+ if (FirstDiffType == Other || SecondDiffType == Other) {
+ // Reaching this point means an unexpected Decl was encountered
+ // or no difference was detected. This causes a generic error
+ // message to be emitted.
+ Diag(FirstRecord->getLocation(),
+ diag::err_module_odr_violation_different_definitions)
+ << FirstRecord << FirstModule.empty() << FirstModule;
+
+ if (FirstDecl) {
+ Diag(FirstDecl->getLocation(), diag::note_first_module_difference)
+ << FirstRecord << FirstDecl->getSourceRange();
+ }
+
+ Diag(SecondRecord->getLocation(),
diag::note_module_odr_violation_different_definitions)
- << getOwningModuleNameForDiagnostic(RD);
+ << SecondModule;
+
+ if (SecondDecl) {
+ Diag(SecondDecl->getLocation(), diag::note_second_module_difference)
+ << SecondDecl->getSourceRange();
+ }
+
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstDiffType != SecondDiffType) {
+ SourceLocation FirstLoc;
+ SourceRange FirstRange;
+ if (FirstDiffType == EndOfClass) {
+ FirstLoc = FirstRecord->getBraceRange().getEnd();
+ } else {
+ FirstLoc = FirstIt->first->getLocation();
+ FirstRange = FirstIt->first->getSourceRange();
+ }
+ Diag(FirstLoc, diag::err_module_odr_violation_mismatch_decl)
+ << FirstRecord << FirstModule.empty() << FirstModule << FirstRange
+ << FirstDiffType;
+
+ SourceLocation SecondLoc;
+ SourceRange SecondRange;
+ if (SecondDiffType == EndOfClass) {
+ SecondLoc = SecondRecord->getBraceRange().getEnd();
+ } else {
+ SecondLoc = SecondDecl->getLocation();
+ SecondRange = SecondDecl->getSourceRange();
+ }
+ Diag(SecondLoc, diag::note_module_odr_violation_mismatch_decl)
+ << SecondModule << SecondRange << SecondDiffType;
+ Diagnosed = true;
+ break;
+ }
+
+ assert(FirstDiffType == SecondDiffType);
+
+ // Used with err_module_odr_violation_mismatch_decl_diff and
+ // note_module_odr_violation_mismatch_decl_diff
+ enum ODRDeclDifference{
+ StaticAssertCondition,
+ StaticAssertMessage,
+ StaticAssertOnlyMessage,
+ FieldName,
+ FieldTypeName,
+ FieldSingleBitField,
+ FieldDifferentWidthBitField,
+ FieldSingleMutable,
+ FieldSingleInitializer,
+ FieldDifferentInitializers,
+ MethodName,
+ MethodDeleted,
+ MethodVirtual,
+ MethodStatic,
+ MethodVolatile,
+ MethodConst,
+ MethodInline,
+ MethodNumberParameters,
+ MethodParameterType,
+ MethodParameterName,
+ MethodParameterSingleDefaultArgument,
+ MethodParameterDifferentDefaultArgument,
+ TypedefName,
+ TypedefType,
+ VarName,
+ VarType,
+ VarSingleInitializer,
+ VarDifferentInitializer,
+ VarConstexpr,
+ FriendTypeFunction,
+ FriendType,
+ FriendFunction,
+ };
+
+ // These lambdas have the common portions of the ODR diagnostics. This
+ // has the same return as Diag(), so addition parameters can be passed
+ // in with operator<<
+ auto ODRDiagError = [FirstRecord, &FirstModule, this](
+ SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_mismatch_decl_diff)
+ << FirstRecord << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto ODRDiagNote = [&SecondModule, this](
+ SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_mismatch_decl_diff)
+ << SecondModule << Range << DiffType;
+ };
+
+ auto ComputeODRHash = [&Hash](const Stmt* S) {
+ assert(S);
+ Hash.clear();
+ Hash.AddStmt(S);
+ return Hash.CalculateHash();
+ };
+
+ auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
+ Hash.clear();
+ Hash.AddQualType(Ty);
+ return Hash.CalculateHash();
+ };
+
+ switch (FirstDiffType) {
+ case Other:
+ case EndOfClass:
+ case PublicSpecifer:
+ case PrivateSpecifer:
+ case ProtectedSpecifer:
+ llvm_unreachable("Invalid diff type");
+
+ case StaticAssert: {
+ StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(FirstDecl);
+ StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(SecondDecl);
+
+ Expr *FirstExpr = FirstSA->getAssertExpr();
+ Expr *SecondExpr = SecondSA->getAssertExpr();
+ unsigned FirstODRHash = ComputeODRHash(FirstExpr);
+ unsigned SecondODRHash = ComputeODRHash(SecondExpr);
+ if (FirstODRHash != SecondODRHash) {
+ ODRDiagError(FirstExpr->getLocStart(), FirstExpr->getSourceRange(),
+ StaticAssertCondition);
+ ODRDiagNote(SecondExpr->getLocStart(),
+ SecondExpr->getSourceRange(), StaticAssertCondition);
+ Diagnosed = true;
+ break;
+ }
+
+ StringLiteral *FirstStr = FirstSA->getMessage();
+ StringLiteral *SecondStr = SecondSA->getMessage();
+ assert((FirstStr || SecondStr) && "Both messages cannot be empty");
+ if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) {
+ SourceLocation FirstLoc, SecondLoc;
+ SourceRange FirstRange, SecondRange;
+ if (FirstStr) {
+ FirstLoc = FirstStr->getLocStart();
+ FirstRange = FirstStr->getSourceRange();
+ } else {
+ FirstLoc = FirstSA->getLocStart();
+ FirstRange = FirstSA->getSourceRange();
+ }
+ if (SecondStr) {
+ SecondLoc = SecondStr->getLocStart();
+ SecondRange = SecondStr->getSourceRange();
+ } else {
+ SecondLoc = SecondSA->getLocStart();
+ SecondRange = SecondSA->getSourceRange();
+ }
+ ODRDiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage)
+ << (FirstStr == nullptr);
+ ODRDiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage)
+ << (SecondStr == nullptr);
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstStr && SecondStr &&
+ FirstStr->getString() != SecondStr->getString()) {
+ ODRDiagError(FirstStr->getLocStart(), FirstStr->getSourceRange(),
+ StaticAssertMessage);
+ ODRDiagNote(SecondStr->getLocStart(), SecondStr->getSourceRange(),
+ StaticAssertMessage);
+ Diagnosed = true;
+ break;
+ }
+ break;
+ }
+ case Field: {
+ FieldDecl *FirstField = cast<FieldDecl>(FirstDecl);
+ FieldDecl *SecondField = cast<FieldDecl>(SecondDecl);
+ IdentifierInfo *FirstII = FirstField->getIdentifier();
+ IdentifierInfo *SecondII = SecondField->getIdentifier();
+ if (FirstII->getName() != SecondII->getName()) {
+ ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
+ FieldName)
+ << FirstII;
+ ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
+ FieldName)
+ << SecondII;
+
+ Diagnosed = true;
+ break;
+ }
+
+ assert(getContext().hasSameType(FirstField->getType(),
+ SecondField->getType()));
+
+ QualType FirstType = FirstField->getType();
+ QualType SecondType = SecondField->getType();
+ if (ComputeQualTypeODRHash(FirstType) !=
+ ComputeQualTypeODRHash(SecondType)) {
+ ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
+ FieldTypeName)
+ << FirstII << FirstType;
+ ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
+ FieldTypeName)
+ << SecondII << SecondType;
+
+ Diagnosed = true;
+ break;
+ }
+
+ const bool IsFirstBitField = FirstField->isBitField();
+ const bool IsSecondBitField = SecondField->isBitField();
+ if (IsFirstBitField != IsSecondBitField) {
+ ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
+ FieldSingleBitField)
+ << FirstII << IsFirstBitField;
+ ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
+ FieldSingleBitField)
+ << SecondII << IsSecondBitField;
+ Diagnosed = true;
+ break;
+ }
+
+ if (IsFirstBitField && IsSecondBitField) {
+ ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
+ FieldDifferentWidthBitField)
+ << FirstII << FirstField->getBitWidth()->getSourceRange();
+ ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
+ FieldDifferentWidthBitField)
+ << SecondII << SecondField->getBitWidth()->getSourceRange();
+ Diagnosed = true;
+ break;
+ }
+
+ const bool IsFirstMutable = FirstField->isMutable();
+ const bool IsSecondMutable = SecondField->isMutable();
+ if (IsFirstMutable != IsSecondMutable) {
+ ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
+ FieldSingleMutable)
+ << FirstII << IsFirstMutable;
+ ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
+ FieldSingleMutable)
+ << SecondII << IsSecondMutable;
+ Diagnosed = true;
+ break;
+ }
+
+ const Expr *FirstInitializer = FirstField->getInClassInitializer();
+ const Expr *SecondInitializer = SecondField->getInClassInitializer();
+ if ((!FirstInitializer && SecondInitializer) ||
+ (FirstInitializer && !SecondInitializer)) {
+ ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
+ FieldSingleInitializer)
+ << FirstII << (FirstInitializer != nullptr);
+ ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
+ FieldSingleInitializer)
+ << SecondII << (SecondInitializer != nullptr);
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstInitializer && SecondInitializer) {
+ unsigned FirstInitHash = ComputeODRHash(FirstInitializer);
+ unsigned SecondInitHash = ComputeODRHash(SecondInitializer);
+ if (FirstInitHash != SecondInitHash) {
+ ODRDiagError(FirstField->getLocation(),
+ FirstField->getSourceRange(),
+ FieldDifferentInitializers)
+ << FirstII << FirstInitializer->getSourceRange();
+ ODRDiagNote(SecondField->getLocation(),
+ SecondField->getSourceRange(),
+ FieldDifferentInitializers)
+ << SecondII << SecondInitializer->getSourceRange();
+ Diagnosed = true;
+ break;
+ }
+ }
+
+ break;
}
+ case CXXMethod: {
+ enum {
+ DiagMethod,
+ DiagConstructor,
+ DiagDestructor,
+ } FirstMethodType,
+ SecondMethodType;
+ auto GetMethodTypeForDiagnostics = [](const CXXMethodDecl* D) {
+ if (isa<CXXConstructorDecl>(D)) return DiagConstructor;
+ if (isa<CXXDestructorDecl>(D)) return DiagDestructor;
+ return DiagMethod;
+ };
+ const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl);
+ const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl);
+ FirstMethodType = GetMethodTypeForDiagnostics(FirstMethod);
+ SecondMethodType = GetMethodTypeForDiagnostics(SecondMethod);
+ auto FirstName = FirstMethod->getDeclName();
+ auto SecondName = SecondMethod->getDeclName();
+ if (FirstMethodType != SecondMethodType || FirstName != SecondName) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodName)
+ << FirstMethodType << FirstName;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodName)
+ << SecondMethodType << SecondName;
+
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstDeleted = FirstMethod->isDeleted();
+ const bool SecondDeleted = SecondMethod->isDeleted();
+ if (FirstDeleted != SecondDeleted) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodDeleted)
+ << FirstMethodType << FirstName << FirstDeleted;
+
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodDeleted)
+ << SecondMethodType << SecondName << SecondDeleted;
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstVirtual = FirstMethod->isVirtualAsWritten();
+ const bool SecondVirtual = SecondMethod->isVirtualAsWritten();
+ const bool FirstPure = FirstMethod->isPure();
+ const bool SecondPure = SecondMethod->isPure();
+ if ((FirstVirtual || SecondVirtual) &&
+ (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodVirtual)
+ << FirstMethodType << FirstName << FirstPure << FirstVirtual;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodVirtual)
+ << SecondMethodType << SecondName << SecondPure << SecondVirtual;
+ Diagnosed = true;
+ break;
+ }
+
+ // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging,
+ // FirstDecl is the canonical Decl of SecondDecl, so the storage
+ // class needs to be checked instead.
+ const auto FirstStorage = FirstMethod->getStorageClass();
+ const auto SecondStorage = SecondMethod->getStorageClass();
+ const bool FirstStatic = FirstStorage == SC_Static;
+ const bool SecondStatic = SecondStorage == SC_Static;
+ if (FirstStatic != SecondStatic) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodStatic)
+ << FirstMethodType << FirstName << FirstStatic;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodStatic)
+ << SecondMethodType << SecondName << SecondStatic;
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstVolatile = FirstMethod->isVolatile();
+ const bool SecondVolatile = SecondMethod->isVolatile();
+ if (FirstVolatile != SecondVolatile) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodVolatile)
+ << FirstMethodType << FirstName << FirstVolatile;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodVolatile)
+ << SecondMethodType << SecondName << SecondVolatile;
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstConst = FirstMethod->isConst();
+ const bool SecondConst = SecondMethod->isConst();
+ if (FirstConst != SecondConst) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodConst)
+ << FirstMethodType << FirstName << FirstConst;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodConst)
+ << SecondMethodType << SecondName << SecondConst;
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstInline = FirstMethod->isInlineSpecified();
+ const bool SecondInline = SecondMethod->isInlineSpecified();
+ if (FirstInline != SecondInline) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodInline)
+ << FirstMethodType << FirstName << FirstInline;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodInline)
+ << SecondMethodType << SecondName << SecondInline;
+ Diagnosed = true;
+ break;
+ }
+
+ const unsigned FirstNumParameters = FirstMethod->param_size();
+ const unsigned SecondNumParameters = SecondMethod->param_size();
+ if (FirstNumParameters != SecondNumParameters) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodNumberParameters)
+ << FirstMethodType << FirstName << FirstNumParameters;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodNumberParameters)
+ << SecondMethodType << SecondName << SecondNumParameters;
+ Diagnosed = true;
+ break;
+ }
+
+ // Need this status boolean to know when break out of the switch.
+ bool ParameterMismatch = false;
+ for (unsigned I = 0; I < FirstNumParameters; ++I) {
+ const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
+ const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
+
+ QualType FirstParamType = FirstParam->getType();
+ QualType SecondParamType = SecondParam->getType();
+ if (FirstParamType != SecondParamType &&
+ ComputeQualTypeODRHash(FirstParamType) !=
+ ComputeQualTypeODRHash(SecondParamType)) {
+ if (const DecayedType *ParamDecayedType =
+ FirstParamType->getAs<DecayedType>()) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodParameterType)
+ << FirstMethodType << FirstName << (I + 1) << FirstParamType
+ << true << ParamDecayedType->getOriginalType();
+ } else {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodParameterType)
+ << FirstMethodType << FirstName << (I + 1) << FirstParamType
+ << false;
+ }
+
+ if (const DecayedType *ParamDecayedType =
+ SecondParamType->getAs<DecayedType>()) {
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodParameterType)
+ << SecondMethodType << SecondName << (I + 1)
+ << SecondParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodParameterType)
+ << SecondMethodType << SecondName << (I + 1)
+ << SecondParamType << false;
+ }
+ ParameterMismatch = true;
+ break;
+ }
+
+ DeclarationName FirstParamName = FirstParam->getDeclName();
+ DeclarationName SecondParamName = SecondParam->getDeclName();
+ if (FirstParamName != SecondParamName) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodParameterName)
+ << FirstMethodType << FirstName << (I + 1) << FirstParamName;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodParameterName)
+ << SecondMethodType << SecondName << (I + 1) << SecondParamName;
+ ParameterMismatch = true;
+ break;
+ }
+
+ const Expr *FirstInit = FirstParam->getInit();
+ const Expr *SecondInit = SecondParam->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(),
+ MethodParameterSingleDefaultArgument)
+ << FirstMethodType << FirstName << (I + 1)
+ << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(),
+ MethodParameterSingleDefaultArgument)
+ << SecondMethodType << SecondName << (I + 1)
+ << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ ParameterMismatch = true;
+ break;
+ }
+
+ if (FirstInit && SecondInit &&
+ ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(),
+ MethodParameterDifferentDefaultArgument)
+ << FirstMethodType << FirstName << (I + 1)
+ << FirstInit->getSourceRange();
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(),
+ MethodParameterDifferentDefaultArgument)
+ << SecondMethodType << SecondName << (I + 1)
+ << SecondInit->getSourceRange();
+ ParameterMismatch = true;
+ break;
+
+ }
+ }
+
+ if (ParameterMismatch) {
+ Diagnosed = true;
+ break;
+ }
+
+ break;
+ }
+ case TypeAlias:
+ case TypeDef: {
+ TypedefNameDecl *FirstTD = cast<TypedefNameDecl>(FirstDecl);
+ TypedefNameDecl *SecondTD = cast<TypedefNameDecl>(SecondDecl);
+ auto FirstName = FirstTD->getDeclName();
+ auto SecondName = SecondTD->getDeclName();
+ if (FirstName != SecondName) {
+ ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(),
+ TypedefName)
+ << (FirstDiffType == TypeAlias) << FirstName;
+ ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(),
+ TypedefName)
+ << (FirstDiffType == TypeAlias) << SecondName;
+ Diagnosed = true;
+ break;
+ }
+
+ QualType FirstType = FirstTD->getUnderlyingType();
+ QualType SecondType = SecondTD->getUnderlyingType();
+ if (ComputeQualTypeODRHash(FirstType) !=
+ ComputeQualTypeODRHash(SecondType)) {
+ ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(),
+ TypedefType)
+ << (FirstDiffType == TypeAlias) << FirstName << FirstType;
+ ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(),
+ TypedefType)
+ << (FirstDiffType == TypeAlias) << SecondName << SecondType;
+ Diagnosed = true;
+ break;
+ }
+ break;
+ }
+ case Var: {
+ VarDecl *FirstVD = cast<VarDecl>(FirstDecl);
+ VarDecl *SecondVD = cast<VarDecl>(SecondDecl);
+ auto FirstName = FirstVD->getDeclName();
+ auto SecondName = SecondVD->getDeclName();
+ if (FirstName != SecondName) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarName)
+ << FirstName;
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarName)
+ << SecondName;
+ Diagnosed = true;
+ break;
+ }
+
+ QualType FirstType = FirstVD->getType();
+ QualType SecondType = SecondVD->getType();
+ if (ComputeQualTypeODRHash(FirstType) !=
+ ComputeQualTypeODRHash(SecondType)) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarType)
+ << FirstName << FirstType;
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarType)
+ << SecondName << SecondType;
+ Diagnosed = true;
+ break;
+ }
+
+ const Expr *FirstInit = FirstVD->getInit();
+ const Expr *SecondInit = SecondVD->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarSingleInitializer)
+ << FirstName << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange(): SourceRange());
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarSingleInitializer)
+ << SecondName << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstInit && SecondInit &&
+ ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarDifferentInitializer)
+ << FirstName << FirstInit->getSourceRange();
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarDifferentInitializer)
+ << SecondName << SecondInit->getSourceRange();
+ Diagnosed = true;
+ break;
+ }
+
+ const bool FirstIsConstexpr = FirstVD->isConstexpr();
+ const bool SecondIsConstexpr = SecondVD->isConstexpr();
+ if (FirstIsConstexpr != SecondIsConstexpr) {
+ ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+ VarConstexpr)
+ << FirstName << FirstIsConstexpr;
+ ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+ VarConstexpr)
+ << SecondName << SecondIsConstexpr;
+ Diagnosed = true;
+ break;
+ }
+ break;
+ }
+ case Friend: {
+ FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl);
+ FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl);
+
+ NamedDecl *FirstND = FirstFriend->getFriendDecl();
+ NamedDecl *SecondND = SecondFriend->getFriendDecl();
+
+ TypeSourceInfo *FirstTSI = FirstFriend->getFriendType();
+ TypeSourceInfo *SecondTSI = SecondFriend->getFriendType();
+
+ if (FirstND && SecondND) {
+ ODRDiagError(FirstFriend->getFriendLoc(),
+ FirstFriend->getSourceRange(), FriendFunction)
+ << FirstND;
+ ODRDiagNote(SecondFriend->getFriendLoc(),
+ SecondFriend->getSourceRange(), FriendFunction)
+ << SecondND;
+
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstTSI && SecondTSI) {
+ QualType FirstFriendType = FirstTSI->getType();
+ QualType SecondFriendType = SecondTSI->getType();
+ assert(ComputeQualTypeODRHash(FirstFriendType) !=
+ ComputeQualTypeODRHash(SecondFriendType));
+ ODRDiagError(FirstFriend->getFriendLoc(),
+ FirstFriend->getSourceRange(), FriendType)
+ << FirstFriendType;
+ ODRDiagNote(SecondFriend->getFriendLoc(),
+ SecondFriend->getSourceRange(), FriendType)
+ << SecondFriendType;
+ Diagnosed = true;
+ break;
+ }
+
+ ODRDiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
+ FriendTypeFunction)
+ << (FirstTSI == nullptr);
+ ODRDiagNote(SecondFriend->getFriendLoc(),
+ SecondFriend->getSourceRange(), FriendTypeFunction)
+ << (SecondTSI == nullptr);
+
+ Diagnosed = true;
+ break;
+ }
+ }
+
+ if (Diagnosed == true)
+ continue;
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule << FirstDiffType << SecondDecl->getSourceRange();
+ Diagnosed = true;
}
if (!Diagnosed) {
@@ -8847,10 +10101,10 @@ void ASTReader::FinishedDeserializing() {
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
auto ESI = FPT->getExtProtoInfo().ExceptionSpec;
- if (auto *Listener = Context.getASTMutationListener())
+ if (auto *Listener = getContext().getASTMutationListener())
Listener->ResolvedExceptionSpec(cast<FunctionDecl>(Update.second));
for (auto *Redecl : Update.second->redecls())
- Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
+ getContext().adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
}
}
@@ -8892,7 +10146,7 @@ void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
}
}
-ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
+ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context,
const PCHContainerReader &PCHContainerRdr,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
StringRef isysroot, bool DisableValidation,
@@ -8905,8 +10159,10 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
: cast<ASTReaderListener>(new PCHValidator(PP, *this))),
SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()), PP(PP),
- Context(Context), ModuleMgr(PP.getFileManager(), PCHContainerRdr),
- DummyIdResolver(PP), ReadTimer(std::move(ReadTimer)), isysroot(isysroot),
+ ContextObj(Context),
+ ModuleMgr(PP.getFileManager(), PP.getPCMCache(), PCHContainerRdr),
+ PCMCache(PP.getPCMCache()), DummyIdResolver(PP),
+ ReadTimer(std::move(ReadTimer)), isysroot(isysroot),
DisableValidation(DisableValidation),
AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
AllowConfigurationMismatch(AllowConfigurationMismatch),
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp
index 707a924..0853415 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -119,12 +119,16 @@ namespace clang {
}
void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update);
- void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data);
+ void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
+ const CXXRecordDecl *D);
void MergeDefinitionData(CXXRecordDecl *D,
struct CXXRecordDecl::DefinitionData &&NewDD);
void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data);
void MergeDefinitionData(ObjCInterfaceDecl *D,
struct ObjCInterfaceDecl::DefinitionData &&NewDD);
+ void ReadObjCDefinitionData(struct ObjCProtocolDecl::DefinitionData &Data);
+ void MergeDefinitionData(ObjCProtocolDecl *D,
+ struct ObjCProtocolDecl::DefinitionData &&NewDD);
static NamedDecl *getAnonymousDeclForMerging(ASTReader &Reader,
DeclContext *DC,
@@ -215,6 +219,30 @@ namespace clang {
TypedefNameForLinkage(nullptr), HasPendingBody(false),
IsDeclMarkedUsed(false) {}
+ template <typename T> static
+ void AddLazySpecializations(T *D,
+ SmallVectorImpl<serialization::DeclID>& IDs) {
+ if (IDs.empty())
+ return;
+
+ // FIXME: We should avoid this pattern of getting the ASTContext.
+ ASTContext &C = D->getASTContext();
+
+ auto *&LazySpecializations = D->getCommonPtr()->LazySpecializations;
+
+ if (auto &Old = LazySpecializations) {
+ IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]);
+ std::sort(IDs.begin(), IDs.end());
+ IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
+ }
+
+ auto *Result = new (C) serialization::DeclID[1 + IDs.size()];
+ *Result = IDs.size();
+ std::copy(IDs.begin(), IDs.end(), Result + 1);
+
+ LazySpecializations = Result;
+ }
+
template <typename DeclT>
static Decl *getMostRecentDeclImpl(Redeclarable<DeclT> *D);
static Decl *getMostRecentDeclImpl(...);
@@ -240,9 +268,10 @@ namespace clang {
/// \brief Determine whether this declaration has a pending body.
bool hasPendingBody() const { return HasPendingBody; }
+ void ReadFunctionDefinition(FunctionDecl *FD);
void Visit(Decl *D);
- void UpdateDecl(Decl *D);
+ void UpdateDecl(Decl *D, llvm::SmallVectorImpl<serialization::DeclID>&);
static void setNextObjCCategory(ObjCCategoryDecl *Cat,
ObjCCategoryDecl *Next) {
@@ -292,6 +321,7 @@ namespace clang {
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitDeclaratorDecl(DeclaratorDecl *DD);
void VisitFunctionDecl(FunctionDecl *FD);
+ void VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *GD);
void VisitCXXMethodDecl(CXXMethodDecl *D);
void VisitCXXConstructorDecl(CXXConstructorDecl *D);
void VisitCXXDestructorDecl(CXXDestructorDecl *D);
@@ -421,6 +451,19 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() {
return Loc.F->DeclsCursor.GetCurrentBitNo() + Loc.F->GlobalBitOffset;
}
+void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) {
+ if (Record.readInt())
+ Reader.BodySource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile;
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ CD->NumCtorInitializers = Record.readInt();
+ if (CD->NumCtorInitializers)
+ CD->CtorInitializers = ReadGlobalOffset();
+ }
+ // Store the offset of the body so we can lazily load it later.
+ Reader.PendingBodies[FD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
+}
+
void ASTDeclReader::Visit(Decl *D) {
DeclVisitor<ASTDeclReader, void>::Visit(D);
@@ -457,15 +500,8 @@ void ASTDeclReader::Visit(Decl *D) {
// We only read it if FD doesn't already have a body (e.g., from another
// module).
// FIXME: Can we diagnose ODR violations somehow?
- if (Record.readInt()) {
- if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
- CD->NumCtorInitializers = Record.readInt();
- if (CD->NumCtorInitializers)
- CD->CtorInitializers = ReadGlobalOffset();
- }
- Reader.PendingBodies[FD] = GetCurrentCursorOffset();
- HasPendingBody = true;
- }
+ if (Record.readInt())
+ ReadFunctionDefinition(FD);
}
}
@@ -513,32 +549,32 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->setTopLevelDeclInObjCContainer(Record.readInt());
D->setAccess((AccessSpecifier)Record.readInt());
D->FromASTFile = true;
- D->setModulePrivate(Record.readInt());
- D->Hidden = D->isModulePrivate();
+ bool ModulePrivate = Record.readInt();
// Determine whether this declaration is part of a (sub)module. If so, it
// may not yet be visible.
if (unsigned SubmoduleID = readSubmoduleID()) {
// Store the owning submodule ID in the declaration.
+ D->setModuleOwnershipKind(
+ ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate
+ : Decl::ModuleOwnershipKind::VisibleWhenImported);
D->setOwningModuleID(SubmoduleID);
- if (D->Hidden) {
- // Module-private declarations are never visible, so there is no work to do.
+ if (ModulePrivate) {
+ // Module-private declarations are never visible, so there is no work to
+ // do.
} else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
// If local visibility is being tracked, this declaration will become
- // hidden and visible as the owning module does. Inform Sema that this
- // declaration might not be visible.
- D->Hidden = true;
+ // hidden and visible as the owning module does.
} else if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
- if (Owner->NameVisibility != Module::AllVisible) {
- // The owning module is not visible. Mark this declaration as hidden.
- D->Hidden = true;
-
- // Note that this declaration was hidden because its owning module is
- // not yet visible.
+ // Mark the declaration as visible when its owning module becomes visible.
+ if (Owner->NameVisibility == Module::AllVisible)
+ D->setVisibleDespiteOwningModule();
+ else
Reader.HiddenNamesMap[Owner].push_back(D);
- }
}
+ } else if (ModulePrivate) {
+ D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
}
}
@@ -592,6 +628,11 @@ ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) {
TD->setModedTypeSourceInfo(TInfo, modedT);
} else
TD->setTypeSourceInfo(TInfo);
+ // Read and discard the declaration for which this is a typedef name for
+ // linkage, if it exists. We cannot rely on our type to pull in this decl,
+ // because it might have been merged with a type from another module and
+ // thus might not refer to our version of the declaration.
+ ReadDecl();
return Redecl;
}
@@ -738,6 +779,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->SClass = (StorageClass)Record.readInt();
FD->IsInline = Record.readInt();
FD->IsInlineSpecified = Record.readInt();
+ FD->IsExplicitSpecified = Record.readInt();
FD->IsVirtualAsWritten = Record.readInt();
FD->IsPure = Record.readInt();
FD->HasInheritedPrototype = Record.readInt();
@@ -1032,18 +1074,8 @@ void ASTDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
IVD->setSynthesize(synth);
}
-void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
- RedeclarableResult Redecl = VisitRedeclarable(PD);
- VisitObjCContainerDecl(PD);
- mergeRedeclarable(PD, Redecl);
-
- if (Record.readInt()) {
- // Read the definition.
- PD->allocateDefinitionData();
-
- // Set the definition data of the canonical declaration, so other
- // redeclarations will see it.
- PD->getCanonicalDecl()->Data = PD->Data;
+void ASTDeclReader::ReadObjCDefinitionData(
+ struct ObjCProtocolDecl::DefinitionData &Data) {
unsigned NumProtoRefs = Record.readInt();
SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
@@ -1054,9 +1086,37 @@ void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
ProtoLocs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
ProtoLocs.push_back(ReadSourceLocation());
- PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
- Reader.getContext());
+ Data.ReferencedProtocols.set(ProtoRefs.data(), NumProtoRefs,
+ ProtoLocs.data(), Reader.getContext());
+}
+
+void ASTDeclReader::MergeDefinitionData(ObjCProtocolDecl *D,
+ struct ObjCProtocolDecl::DefinitionData &&NewDD) {
+ // FIXME: odr checking?
+}
+
+void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
+ RedeclarableResult Redecl = VisitRedeclarable(PD);
+ VisitObjCContainerDecl(PD);
+ mergeRedeclarable(PD, Redecl);
+
+ if (Record.readInt()) {
+ // Read the definition.
+ PD->allocateDefinitionData();
+
+ ReadObjCDefinitionData(PD->data());
+ ObjCProtocolDecl *Canon = PD->getCanonicalDecl();
+ if (Canon->Data.getPointer()) {
+ // If we already have a definition, keep the definition invariant and
+ // merge the data.
+ MergeDefinitionData(Canon, std::move(PD->data()));
+ PD->Data = Canon->Data;
+ } else {
+ // Set the definition data of the canonical declaration, so other
+ // redeclarations will see it.
+ PD->getCanonicalDecl()->Data = PD->Data;
+ }
// Note that we have deserialized a definition.
Reader.PendingDefinitions.insert(PD);
} else {
@@ -1112,8 +1172,12 @@ void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
(ObjCPropertyDecl::PropertyAttributeKind)Record.readInt());
D->setPropertyImplementation(
(ObjCPropertyDecl::PropertyControl)Record.readInt());
- D->setGetterName(Record.readDeclarationName().getObjCSelector());
- D->setSetterName(Record.readDeclarationName().getObjCSelector());
+ DeclarationName GetterName = Record.readDeclarationName();
+ SourceLocation GetterLoc = ReadSourceLocation();
+ D->setGetterName(GetterName.getObjCSelector(), GetterLoc);
+ DeclarationName SetterName = Record.readDeclarationName();
+ SourceLocation SetterLoc = ReadSourceLocation();
+ D->setSetterName(SetterName.getObjCSelector(), SetterLoc);
D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>());
D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>());
D->setPropertyIvarDecl(ReadDeclAs<ObjCIvarDecl>());
@@ -1126,7 +1190,6 @@ void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
VisitObjCImplDecl(D);
- D->setIdentifier(Record.getIdentifierInfo());
D->CategoryNameLoc = ReadSourceLocation();
}
@@ -1211,6 +1274,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->NonParmVarDeclBits.IsConstexpr = Record.readInt();
VD->NonParmVarDeclBits.IsInitCapture = Record.readInt();
VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope = Record.readInt();
+ VD->NonParmVarDeclBits.ImplicitParamKind = Record.readInt();
}
Linkage VarLinkage = Linkage(Record.readInt());
VD->setCachedLinkage(VarLinkage);
@@ -1473,7 +1537,7 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
}
void ASTDeclReader::ReadCXXDefinitionData(
- struct CXXRecordDecl::DefinitionData &Data) {
+ struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D) {
// Note: the caller has deserialized the IsLambda bit already.
Data.UserDeclaredConstructor = Record.readInt();
Data.UserDeclaredSpecialMembers = Record.readInt();
@@ -1495,9 +1559,11 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasUninitializedFields = Record.readInt();
Data.HasInheritedConstructor = Record.readInt();
Data.HasInheritedAssignment = Record.readInt();
+ Data.NeedOverloadResolutionForCopyConstructor = Record.readInt();
Data.NeedOverloadResolutionForMoveConstructor = Record.readInt();
Data.NeedOverloadResolutionForMoveAssignment = Record.readInt();
Data.NeedOverloadResolutionForDestructor = Record.readInt();
+ Data.DefaultedCopyConstructorIsDeleted = Record.readInt();
Data.DefaultedMoveConstructorIsDeleted = Record.readInt();
Data.DefaultedMoveAssignmentIsDeleted = Record.readInt();
Data.DefaultedDestructorIsDeleted = Record.readInt();
@@ -1506,16 +1572,26 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasIrrelevantDestructor = Record.readInt();
Data.HasConstexprNonCopyMoveConstructor = Record.readInt();
Data.HasDefaultedDefaultConstructor = Record.readInt();
+ Data.CanPassInRegisters = Record.readInt();
Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt();
Data.HasConstexprDefaultConstructor = Record.readInt();
Data.HasNonLiteralTypeFieldsOrBases = Record.readInt();
Data.ComputedVisibleConversions = Record.readInt();
Data.UserProvidedDefaultConstructor = Record.readInt();
Data.DeclaredSpecialMembers = Record.readInt();
- Data.ImplicitCopyConstructorHasConstParam = Record.readInt();
+ Data.ImplicitCopyConstructorCanHaveConstParamForVBase = Record.readInt();
+ Data.ImplicitCopyConstructorCanHaveConstParamForNonVBase = Record.readInt();
Data.ImplicitCopyAssignmentHasConstParam = Record.readInt();
Data.HasDeclaredCopyConstructorWithConstParam = Record.readInt();
Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt();
+ Data.ODRHash = Record.readInt();
+ Data.HasODRHash = true;
+
+ if (Record.readInt()) {
+ Reader.BodySource[D] = Loc.F->Kind == ModuleKind::MK_MainFile
+ ? ExternalASTSource::EK_Never
+ : ExternalASTSource::EK_Always;
+ }
Data.NumBases = Record.readInt();
if (Data.NumBases)
@@ -1540,8 +1616,8 @@ void ASTDeclReader::ReadCXXDefinitionData(
Lambda.NumExplicitCaptures = Record.readInt();
Lambda.ManglingNumber = Record.readInt();
Lambda.ContextDecl = ReadDeclID();
- Lambda.Captures
- = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
+ Lambda.Captures = (Capture *)Reader.getContext().Allocate(
+ sizeof(Capture) * Lambda.NumCaptures);
Capture *ToCapture = Lambda.Captures;
Lambda.MethodTyInfo = GetTypeSourceInfo();
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
@@ -1624,9 +1700,11 @@ void ASTDeclReader::MergeDefinitionData(
MATCH_FIELD(HasUninitializedFields)
MATCH_FIELD(HasInheritedConstructor)
MATCH_FIELD(HasInheritedAssignment)
+ MATCH_FIELD(NeedOverloadResolutionForCopyConstructor)
MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
MATCH_FIELD(NeedOverloadResolutionForDestructor)
+ MATCH_FIELD(DefaultedCopyConstructorIsDeleted)
MATCH_FIELD(DefaultedMoveConstructorIsDeleted)
MATCH_FIELD(DefaultedMoveAssignmentIsDeleted)
MATCH_FIELD(DefaultedDestructorIsDeleted)
@@ -1635,13 +1713,15 @@ void ASTDeclReader::MergeDefinitionData(
MATCH_FIELD(HasIrrelevantDestructor)
OR_FIELD(HasConstexprNonCopyMoveConstructor)
OR_FIELD(HasDefaultedDefaultConstructor)
+ MATCH_FIELD(CanPassInRegisters)
MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
OR_FIELD(HasConstexprDefaultConstructor)
MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
// ComputedVisibleConversions is handled below.
MATCH_FIELD(UserProvidedDefaultConstructor)
OR_FIELD(DeclaredSpecialMembers)
- MATCH_FIELD(ImplicitCopyConstructorHasConstParam)
+ MATCH_FIELD(ImplicitCopyConstructorCanHaveConstParamForVBase)
+ MATCH_FIELD(ImplicitCopyConstructorCanHaveConstParamForNonVBase)
MATCH_FIELD(ImplicitCopyAssignmentHasConstParam)
OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
@@ -1669,6 +1749,10 @@ void ASTDeclReader::MergeDefinitionData(
// when they occur within the body of a function template specialization).
}
+ if (D->getODRHash() != MergeDD.ODRHash) {
+ DetectedOdrViolation = true;
+ }
+
if (DetectedOdrViolation)
Reader.PendingOdrMergeFailures[DD.Definition].push_back(MergeDD.Definition);
}
@@ -1686,7 +1770,7 @@ void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) {
else
DD = new (C) struct CXXRecordDecl::DefinitionData(D);
- ReadCXXDefinitionData(*DD);
+ ReadCXXDefinitionData(*DD, D);
// We might already have a definition for this record. This can happen either
// because we're reading an update record, or because we've already done some
@@ -1775,6 +1859,10 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
return Redecl;
}
+void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+ VisitFunctionDecl(D);
+}
+
void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
VisitFunctionDecl(D);
@@ -1804,8 +1892,6 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
}
VisitCXXMethodDecl(D);
-
- D->IsExplicitSpecified = Record.readInt();
}
void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
@@ -1821,7 +1907,6 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
VisitCXXMethodDecl(D);
- D->IsExplicitSpecified = Record.readInt();
}
void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
@@ -1831,7 +1916,7 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
SourceLocation *StoredLocs = D->getTrailingObjects<SourceLocation>();
for (unsigned I = 0, N = Record.back(); I != N; ++I)
StoredLocs[I] = ReadSourceLocation();
- (void)Record.readInt(); // The number of stored source locations.
+ Record.skipInts(1); // The number of stored source locations.
}
void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
@@ -1873,6 +1958,7 @@ DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
DeclID PatternID = ReadDeclID();
NamedDecl *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
TemplateParameterList *TemplateParams = Record.readTemplateParameterList();
+ // FIXME handle associated constraints
D->init(TemplatedDecl, TemplateParams);
return PatternID;
@@ -1917,21 +2003,6 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
return Redecl;
}
-static DeclID *newDeclIDList(ASTContext &Context, DeclID *Old,
- SmallVectorImpl<DeclID> &IDs) {
- assert(!IDs.empty() && "no IDs to add to list");
- if (Old) {
- IDs.insert(IDs.end(), Old + 1, Old + 1 + Old[0]);
- std::sort(IDs.begin(), IDs.end());
- IDs.erase(std::unique(IDs.begin(), IDs.end()), IDs.end());
- }
-
- auto *Result = new (Context) DeclID[1 + IDs.size()];
- *Result = IDs.size();
- std::copy(IDs.begin(), IDs.end(), Result + 1);
- return Result;
-}
-
void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
@@ -1940,19 +2011,14 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// the specializations.
SmallVector<serialization::DeclID, 32> SpecIDs;
ReadDeclIDList(SpecIDs);
-
- if (!SpecIDs.empty()) {
- auto *CommonPtr = D->getCommonPtr();
- CommonPtr->LazySpecializations = newDeclIDList(
- Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
- }
+ ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
if (D->getTemplatedDecl()->TemplateOrInstantiation) {
// We were loaded before our templated declaration was. We've not set up
// its corresponding type yet (see VisitCXXRecordDeclImpl), so reconstruct
// it now.
- Reader.Context.getInjectedClassNameType(
+ Reader.getContext().getInjectedClassNameType(
D->getTemplatedDecl(), D->getInjectedClassNameSpecialization());
}
}
@@ -1972,12 +2038,7 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
// the specializations.
SmallVector<serialization::DeclID, 32> SpecIDs;
ReadDeclIDList(SpecIDs);
-
- if (!SpecIDs.empty()) {
- auto *CommonPtr = D->getCommonPtr();
- CommonPtr->LazySpecializations = newDeclIDList(
- Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
- }
+ ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
}
@@ -2083,12 +2144,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// This FunctionTemplateDecl owns a CommonPtr; read it.
SmallVector<serialization::DeclID, 32> SpecIDs;
ReadDeclIDList(SpecIDs);
-
- if (!SpecIDs.empty()) {
- auto *CommonPtr = D->getCommonPtr();
- CommonPtr->LazySpecializations = newDeclIDList(
- Reader.getContext(), CommonPtr->LazySpecializations, SpecIDs);
- }
+ ASTDeclReader::AddLazySpecializations(D, SpecIDs);
}
}
@@ -2439,8 +2495,8 @@ void ASTDeclReader::mergeMergeable(Mergeable<T> *D) {
if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
if (T *Existing = ExistingRes)
- Reader.Context.setPrimaryMergedDecl(static_cast<T*>(D),
- Existing->getCanonicalDecl());
+ Reader.getContext().setPrimaryMergedDecl(static_cast<T *>(D),
+ Existing->getCanonicalDecl());
}
void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
@@ -2471,12 +2527,12 @@ void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
//===----------------------------------------------------------------------===//
/// \brief Reads attributes from the current stream position.
-void ASTReader::ReadAttributes(ModuleFile &F, AttrVec &Attrs,
- const RecordData &Record, unsigned &Idx) {
- for (unsigned i = 0, e = Record[Idx++]; i != e; ++i) {
+void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) {
+ for (unsigned i = 0, e = Record.readInt(); i != e; ++i) {
Attr *New = nullptr;
- attr::Kind Kind = (attr::Kind)Record[Idx++];
- SourceRange Range = ReadSourceRange(F, Record, Idx);
+ attr::Kind Kind = (attr::Kind)Record.readInt();
+ SourceRange Range = Record.readSourceRange();
+ ASTContext &Context = getContext();
#include "clang/Serialization/AttrPCHRead.inc"
@@ -2531,7 +2587,11 @@ static bool isConsumerInterestedIn(ASTContext &Ctx, Decl *D, bool HasBody) {
Var->isThisDeclarationADefinition() == VarDecl::Definition;
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
return Func->doesThisDeclarationHaveABody() || HasBody;
-
+
+ if (auto *ES = D->getASTContext().getExternalSource())
+ if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never)
+ return true;
+
return false;
}
@@ -2648,6 +2708,45 @@ static bool isSameTemplateParameterList(const TemplateParameterList *X,
return true;
}
+/// Determine whether the attributes we can overload on are identical for A and
+/// B. Will ignore any overloadable attrs represented in the type of A and B.
+static bool hasSameOverloadableAttrs(const FunctionDecl *A,
+ const FunctionDecl *B) {
+ // Note that pass_object_size attributes are represented in the function's
+ // ExtParameterInfo, so we don't need to check them here.
+
+ SmallVector<const EnableIfAttr *, 4> AEnableIfs;
+ // Since this is an equality check, we can ignore that enable_if attrs show up
+ // in reverse order.
+ for (const auto *EIA : A->specific_attrs<EnableIfAttr>())
+ AEnableIfs.push_back(EIA);
+
+ SmallVector<const EnableIfAttr *, 4> BEnableIfs;
+ for (const auto *EIA : B->specific_attrs<EnableIfAttr>())
+ BEnableIfs.push_back(EIA);
+
+ // Two very common cases: either we have 0 enable_if attrs, or we have an
+ // unequal number of enable_if attrs.
+ if (AEnableIfs.empty() && BEnableIfs.empty())
+ return true;
+
+ if (AEnableIfs.size() != BEnableIfs.size())
+ return false;
+
+ llvm::FoldingSetNodeID Cand1ID, Cand2ID;
+ for (unsigned I = 0, E = AEnableIfs.size(); I != E; ++I) {
+ Cand1ID.clear();
+ Cand2ID.clear();
+
+ AEnableIfs[I]->getCond()->Profile(Cand1ID, A->getASTContext(), true);
+ BEnableIfs[I]->getCond()->Profile(Cand2ID, B->getASTContext(), true);
+ if (Cand1ID != Cand2ID)
+ return false;
+ }
+
+ return true;
+}
+
/// \brief Determine whether the two declarations refer to the same entity.
static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!");
@@ -2703,8 +2802,24 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
CtorY->getInheritedConstructor().getConstructor()))
return false;
}
- return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) &&
- FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
+ ASTContext &C = FuncX->getASTContext();
+ if (!C.hasSameType(FuncX->getType(), FuncY->getType())) {
+ // We can get functions with different types on the redecl chain in C++17
+ // if they have differing exception specifications and at least one of
+ // the excpetion specs is unresolved.
+ // FIXME: Do we need to check for C++14 deduced return types here too?
+ auto *XFPT = FuncX->getType()->getAs<FunctionProtoType>();
+ auto *YFPT = FuncY->getType()->getAs<FunctionProtoType>();
+ if (C.getLangOpts().CPlusPlus1z && XFPT && YFPT &&
+ (isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) ||
+ isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) &&
+ C.hasSameFunctionTypeIgnoringExceptionSpec(FuncX->getType(),
+ FuncY->getType()))
+ return true;
+ return false;
+ }
+ return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() &&
+ hasSameOverloadableAttrs(FuncX, FuncY);
}
// Variables with the same type and linkage match.
@@ -2816,7 +2931,7 @@ DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
// commit to DC being the canonical definition now, and will fix this when
// we load the update record.
if (!DD) {
- DD = new (Reader.Context) struct CXXRecordDecl::DefinitionData(RD);
+ DD = new (Reader.getContext()) struct CXXRecordDecl::DefinitionData(RD);
RD->IsCompleteDefinition = true;
RD->DefinitionData = DD;
RD->getCanonicalDecl()->DefinitionData = DD;
@@ -3261,6 +3376,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
ASTDeclReader Reader(*this, Record, Loc, ID, DeclLoc);
unsigned Code = DeclsCursor.ReadCode();
+ ASTContext &Context = getContext();
Decl *D = nullptr;
switch ((DeclCode)Record.readRecord(DeclsCursor, Code)) {
case DECL_CONTEXT_LEXICAL:
@@ -3323,6 +3439,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_CXX_RECORD:
D = CXXRecordDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_CXX_DEDUCTION_GUIDE:
+ D = CXXDeductionGuideDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_CXX_METHOD:
D = CXXMethodDecl::CreateDeserialized(Context, ID);
break;
@@ -3517,7 +3636,8 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
assert(Record.getIdx() == Record.size());
// Load any relevant update records.
- PendingUpdateRecords.push_back(std::make_pair(ID, D));
+ PendingUpdateRecords.push_back(
+ PendingUpdateRecord(ID, D, /*JustLoaded=*/true));
// Load the categories after recursive loading is finished.
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D))
@@ -3531,23 +3651,58 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// AST consumer might need to know about, queue it.
// We don't pass it to the consumer immediately because we may be in recursive
// loading, and some declarations may still be initializing.
- if (isConsumerInterestedIn(Context, D, Reader.hasPendingBody()))
- InterestingDecls.push_back(D);
+ PotentiallyInterestingDecls.push_back(
+ InterestingDecl(D, Reader.hasPendingBody()));
return D;
}
-void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
+void ASTReader::PassInterestingDeclsToConsumer() {
+ assert(Consumer);
+
+ if (PassingDeclsToConsumer)
+ return;
+
+ // Guard variable to avoid recursively redoing the process of passing
+ // decls to consumer.
+ SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
+ true);
+
+ // Ensure that we've loaded all potentially-interesting declarations
+ // that need to be eagerly loaded.
+ for (auto ID : EagerlyDeserializedDecls)
+ GetDecl(ID);
+ EagerlyDeserializedDecls.clear();
+
+ while (!PotentiallyInterestingDecls.empty()) {
+ InterestingDecl D = PotentiallyInterestingDecls.front();
+ PotentiallyInterestingDecls.pop_front();
+ if (isConsumerInterestedIn(getContext(), D.getDecl(), D.hasPendingBody()))
+ PassInterestingDeclToConsumer(D.getDecl());
+ }
+}
+
+void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
// The declaration may have been modified by files later in the chain.
// If this is the case, read the record containing the updates from each file
// and pass it to ASTDeclReader to make the modifications.
+ serialization::GlobalDeclID ID = Record.ID;
+ Decl *D = Record.D;
ProcessingUpdatesRAIIObj ProcessingUpdates(*this);
DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
+
+ llvm::SmallVector<serialization::DeclID, 8> PendingLazySpecializationIDs;
+
if (UpdI != DeclUpdateOffsets.end()) {
auto UpdateOffsets = std::move(UpdI->second);
DeclUpdateOffsets.erase(UpdI);
- bool WasInteresting = isConsumerInterestedIn(Context, D, false);
+ // Check if this decl was interesting to the consumer. If we just loaded
+ // the declaration, then we know it was interesting and we skip the call
+ // to isConsumerInterestedIn because it is unsafe to call in the
+ // current ASTReader state.
+ bool WasInteresting =
+ Record.JustLoaded || isConsumerInterestedIn(getContext(), D, false);
for (auto &FileAndOffset : UpdateOffsets) {
ModuleFile *F = FileAndOffset.first;
uint64_t Offset = FileAndOffset.second;
@@ -3562,17 +3717,29 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID,
SourceLocation());
- Reader.UpdateDecl(D);
+ Reader.UpdateDecl(D, PendingLazySpecializationIDs);
// We might have made this declaration interesting. If so, remember that
// we need to hand it off to the consumer.
if (!WasInteresting &&
- isConsumerInterestedIn(Context, D, Reader.hasPendingBody())) {
- InterestingDecls.push_back(D);
+ isConsumerInterestedIn(getContext(), D, Reader.hasPendingBody())) {
+ PotentiallyInterestingDecls.push_back(
+ InterestingDecl(D, Reader.hasPendingBody()));
WasInteresting = true;
}
}
}
+ // Add the lazy specializations to the template.
+ assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) ||
+ isa<FunctionTemplateDecl>(D) || isa<VarTemplateDecl>(D)) &&
+ "Must not have pending specializations");
+ if (auto *CTD = dyn_cast<ClassTemplateDecl>(D))
+ ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs);
+ else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ ASTDeclReader::AddLazySpecializations(FTD, PendingLazySpecializationIDs);
+ else if (auto *VTD = dyn_cast<VarTemplateDecl>(D))
+ ASTDeclReader::AddLazySpecializations(VTD, PendingLazySpecializationIDs);
+ PendingLazySpecializationIDs.clear();
// Load the pending visible updates for this decl context, if it has any.
auto I = PendingVisibleUpdates.find(ID);
@@ -3769,7 +3936,8 @@ static void forAllLaterRedecls(DeclT *D, Fn F) {
}
}
-void ASTDeclReader::UpdateDecl(Decl *D) {
+void ASTDeclReader::UpdateDecl(Decl *D,
+ llvm::SmallVectorImpl<serialization::DeclID> &PendingLazySpecializationIDs) {
while (Record.getIdx() < Record.size()) {
switch ((DeclUpdateKind)Record.readInt()) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
@@ -3785,8 +3953,8 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
}
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
- // It will be added to the template's specializations set when loaded.
- (void)Record.readDecl();
+ // It will be added to the template's lazy specialization set.
+ PendingLazySpecializationIDs.push_back(ReadDeclID());
break;
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
@@ -3804,10 +3972,21 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
break;
}
- case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
- cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation(
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: {
+ VarDecl *VD = cast<VarDecl>(D);
+ VD->getMemberSpecializationInfo()->setPointOfInstantiation(
ReadSourceLocation());
+ uint64_t Val = Record.readInt();
+ if (Val && !VD->getInit()) {
+ VD->setInit(Record.readExpr());
+ if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2, IsInitICE = 3
+ EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
+ Eval->CheckedICE = true;
+ Eval->IsICE = Val == 3;
+ }
+ }
break;
+ }
case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: {
auto Param = cast<ParmVarDecl>(D);
@@ -3858,14 +4037,7 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
});
}
FD->setInnerLocStart(ReadSourceLocation());
- if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
- CD->NumCtorInitializers = Record.readInt();
- if (CD->NumCtorInitializers)
- CD->CtorInitializers = ReadGlobalOffset();
- }
- // Store the offset of the body so we can lazily load it later.
- Reader.PendingBodies[FD] = GetCurrentCursorOffset();
- HasPendingBody = true;
+ ReadFunctionDefinition(FD);
assert(Record.getIdx() == Record.size() && "lazy body must be last");
break;
}
@@ -3951,7 +4123,7 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
// FIXME: If the exception specification is already present, check that it
// matches.
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
- FD->setType(Reader.Context.getFunctionType(
+ FD->setType(Reader.getContext().getFunctionType(
FPT->getReturnType(), FPT->getParamTypes(),
FPT->getExtProtoInfo().withExceptionSpec(ESI)));
@@ -3969,28 +4141,31 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
for (auto *Redecl : merged_redecls(D)) {
// FIXME: If the return type is already deduced, check that it matches.
FunctionDecl *FD = cast<FunctionDecl>(Redecl);
- Reader.Context.adjustDeducedFunctionResultType(FD, DeducedResultType);
+ Reader.getContext().adjustDeducedFunctionResultType(FD,
+ DeducedResultType);
}
break;
}
case UPD_DECL_MARKED_USED: {
// Maintain AST consistency: any later redeclarations are used too.
- D->markUsed(Reader.Context);
+ D->markUsed(Reader.getContext());
break;
}
case UPD_MANGLING_NUMBER:
- Reader.Context.setManglingNumber(cast<NamedDecl>(D), Record.readInt());
+ Reader.getContext().setManglingNumber(cast<NamedDecl>(D),
+ Record.readInt());
break;
case UPD_STATIC_LOCAL_NUMBER:
- Reader.Context.setStaticLocalNumber(cast<VarDecl>(D), Record.readInt());
+ Reader.getContext().setStaticLocalNumber(cast<VarDecl>(D),
+ Record.readInt());
break;
case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
- D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
- Reader.Context, ReadSourceRange()));
+ D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(Reader.getContext(),
+ ReadSourceRange()));
break;
case UPD_DECL_EXPORTED: {
@@ -4010,7 +4185,7 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
Reader.HiddenNamesMap[Owner].push_back(Exported);
} else {
// The declaration is now visible.
- Exported->Hidden = false;
+ Exported->setVisibleDespiteOwningModule();
}
break;
}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp
index 686a69b..3f5da02 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -367,23 +367,45 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
}
void ASTStmtReader::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+ VisitStmt(S);
+ assert(Record.peekInt() == S->NumParams);
+ Record.skipInts(1);
+ auto *StoredStmts = S->getStoredStmts();
+ for (unsigned i = 0;
+ i < CoroutineBodyStmt::SubStmt::FirstParamMove + S->NumParams; ++i)
+ StoredStmts[i] = Record.readSubStmt();
}
void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+ VisitStmt(S);
+ S->CoreturnLoc = Record.readSourceLocation();
+ for (auto &SubStmt: S->SubStmts)
+ SubStmt = Record.readSubStmt();
+ S->IsImplicit = Record.readInt() != 0;
}
-void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *E) {
+ VisitExpr(E);
+ E->KeywordLoc = ReadSourceLocation();
+ for (auto &SubExpr: E->SubExprs)
+ SubExpr = Record.readSubStmt();
+ E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt());
+ E->setIsImplicit(Record.readInt() != 0);
+}
+
+void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *E) {
+ VisitExpr(E);
+ E->KeywordLoc = ReadSourceLocation();
+ for (auto &SubExpr: E->SubExprs)
+ SubExpr = Record.readSubStmt();
+ E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt());
}
-void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
+ VisitExpr(E);
+ E->KeywordLoc = ReadSourceLocation();
+ for (auto &SubExpr: E->SubExprs)
+ SubExpr = Record.readSubStmt();
}
void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
@@ -665,7 +687,7 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
E->setRHS(Record.readSubExpr());
E->setOpcode((BinaryOperator::Opcode)Record.readInt());
E->setOperatorLoc(ReadSourceLocation());
- E->setFPContractable((bool)Record.readInt());
+ E->setFPFeatures(FPOptions(Record.readInt()));
}
void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
@@ -1220,7 +1242,7 @@ void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
E->Operator = (OverloadedOperatorKind)Record.readInt();
E->Range = Record.readSourceRange();
- E->setFPContractable((bool)Record.readInt());
+ E->setFPFeatures(FPOptions(Record.readInt()));
}
void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
@@ -1829,6 +1851,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_reduction:
C = OMPReductionClause::CreateEmpty(Context, Reader->Record.readInt());
break;
+ case OMPC_task_reduction:
+ C = OMPTaskReductionClause::CreateEmpty(Context, Reader->Record.readInt());
+ break;
case OMPC_linear:
C = OMPLinearClause::CreateEmpty(Context, Reader->Record.readInt());
break;
@@ -1928,7 +1953,8 @@ OMPClause *OMPClauseReader::readClause() {
}
void OMPClauseReader::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) {
- C->setPreInitStmt(Reader->Record.readSubStmt());
+ C->setPreInitStmt(Reader->Record.readSubStmt(),
+ static_cast<OpenMPDirectiveKind>(Reader->Record.readInt()));
}
void OMPClauseReader::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) {
@@ -1937,6 +1963,7 @@ void OMPClauseReader::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) {
}
void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setNameModifier(static_cast<OpenMPDirectiveKind>(Reader->Record.readInt()));
C->setNameModifierLoc(Reader->ReadSourceLocation());
C->setColonLoc(Reader->ReadSourceLocation());
@@ -1950,6 +1977,7 @@ void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) {
}
void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setNumThreads(Reader->Record.readSubExpr());
C->setLParenLoc(Reader->ReadSourceLocation());
}
@@ -2130,6 +2158,40 @@ void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
C->setReductionOps(Vars);
}
+void OMPClauseReader::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) {
+ VisitOMPClauseWithPostUpdate(C);
+ C->setLParenLoc(Reader->ReadSourceLocation());
+ C->setColonLoc(Reader->ReadSourceLocation());
+ NestedNameSpecifierLoc NNSL = Reader->Record.readNestedNameSpecifierLoc();
+ DeclarationNameInfo DNI;
+ Reader->ReadDeclarationNameInfo(DNI);
+ C->setQualifierLoc(NNSL);
+ C->setNameInfo(DNI);
+
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setPrivates(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setLHSExprs(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setRHSExprs(Vars);
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars; ++I)
+ Vars.push_back(Reader->Record.readSubExpr());
+ C->setReductionOps(Vars);
+}
+
void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
VisitOMPClauseWithPostUpdate(C);
C->setLParenLoc(Reader->ReadSourceLocation());
@@ -2297,11 +2359,13 @@ void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) {
}
void OMPClauseReader::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setNumTeams(Reader->Record.readSubExpr());
C->setLParenLoc(Reader->ReadSourceLocation());
}
void OMPClauseReader::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setThreadLimit(Reader->Record.readSubExpr());
C->setLParenLoc(Reader->ReadSourceLocation());
}
@@ -2566,6 +2630,15 @@ void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) {
if (isOpenMPLoopBoundSharingDirective(D->getDirectiveKind())) {
D->setPrevLowerBoundVariable(Record.readSubExpr());
D->setPrevUpperBoundVariable(Record.readSubExpr());
+ D->setDistInc(Record.readSubExpr());
+ D->setPrevEnsureUpperBound(Record.readSubExpr());
+ D->setCombinedLowerBoundVariable(Record.readSubExpr());
+ D->setCombinedUpperBoundVariable(Record.readSubExpr());
+ D->setCombinedEnsureUpperBound(Record.readSubExpr());
+ D->setCombinedInit(Record.readSubExpr());
+ D->setCombinedCond(Record.readSubExpr());
+ D->setCombinedNextLowerBound(Record.readSubExpr());
+ D->setCombinedNextUpperBound(Record.readSubExpr());
}
SmallVector<Expr *, 4> Sub;
unsigned CollapsedNum = D->getCollapsedNumber();
@@ -2690,6 +2763,8 @@ void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
void ASTStmtReader::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) {
VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ Record.skipInts(1);
VisitOMPExecutableDirective(D);
}
@@ -2909,7 +2984,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
llvm::BitstreamCursor &Cursor = F.DeclsCursor;
// Map of offset to previously deserialized stmt. The offset points
- /// just after the stmt record.
+ // just after the stmt record.
llvm::DenseMap<uint64_t, Stmt *> StmtEntries;
#ifndef NDEBUG
@@ -2935,6 +3010,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ ASTContext &Context = getContext();
Stmt *S = nullptr;
bool Finished = false;
bool IsStmtReference = false;
@@ -3459,7 +3535,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case STMT_OMP_TASKGROUP_DIRECTIVE:
- S = OMPTaskgroupDirective::CreateEmpty(Context, Empty);
+ S = OMPTaskgroupDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
break;
case STMT_OMP_FLUSH_DIRECTIVE:
@@ -3887,6 +3964,29 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = LambdaExpr::CreateDeserialized(Context, NumCaptures);
break;
}
+
+ case STMT_COROUTINE_BODY: {
+ unsigned NumParams = Record[ASTStmtReader::NumStmtFields];
+ S = CoroutineBodyStmt::Create(Context, Empty, NumParams);
+ break;
+ }
+
+ case STMT_CORETURN:
+ S = new (Context) CoreturnStmt(Empty);
+ break;
+
+ case EXPR_COAWAIT:
+ S = new (Context) CoawaitExpr(Empty);
+ break;
+
+ case EXPR_COYIELD:
+ S = new (Context) CoyieldExpr(Empty);
+ break;
+
+ case EXPR_DEPENDENT_COAWAIT:
+ S = new (Context) DependentCoawaitExpr(Empty);
+ break;
+
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp
index 886523e..128e53b 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp
@@ -18,8 +18,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTUnresolvedSet.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -33,8 +33,9 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
-#include "clang/Basic/LangOptions.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/SourceManager.h"
@@ -64,20 +65,22 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitCodes.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/SHA1.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
@@ -252,6 +255,7 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
// FIXME: need to stabilize encoding of calling convention...
Record.push_back(C.getCC());
Record.push_back(C.getProducesResult());
+ Record.push_back(C.getNoCallerSavedRegs());
if (C.getHasRegParm() || C.getRegParm() || C.getProducesResult())
AbbrevToUse = 0;
@@ -348,6 +352,15 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) {
Code = TYPE_AUTO;
}
+void ASTTypeWriter::VisitDeducedTemplateSpecializationType(
+ const DeducedTemplateSpecializationType *T) {
+ Record.AddTemplateName(T->getTemplateName());
+ Record.AddTypeRef(T->getDeducedType());
+ if (T->getDeducedType().isNull())
+ Record.push_back(T->isDependentType());
+ Code = TYPE_DEDUCED_TEMPLATE_SPECIALIZATION;
+}
+
void ASTTypeWriter::VisitTagType(const TagType *T) {
Record.push_back(T->isDependentType());
Record.AddDeclRef(T->getDecl()->getCanonicalDecl());
@@ -414,8 +427,10 @@ ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
void
ASTTypeWriter::VisitDependentSizedExtVectorType(
const DependentSizedExtVectorType *T) {
- // FIXME: Serialize this type (C++ only)
- llvm_unreachable("Cannot serialize dependent sized extended vector types");
+ Record.AddTypeRef(T->getElementType());
+ Record.AddStmt(T->getSizeExpr());
+ Record.AddSourceLocation(T->getAttributeLoc());
+ Code = TYPE_DEPENDENT_SIZED_EXT_VECTOR;
}
void
@@ -682,6 +697,11 @@ void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
Record.AddSourceLocation(TL.getNameLoc());
}
+void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc(
+ DeducedTemplateSpecializationTypeLoc TL) {
+ Record.AddSourceLocation(TL.getTemplateNameLoc());
+}
+
void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
Record.AddSourceLocation(TL.getNameLoc());
}
@@ -820,6 +840,7 @@ void ASTWriter::WriteTypeAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // RegParm
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // CC
Abv->Add(BitCodeAbbrevOp(0)); // ProducesResult
+ Abv->Add(BitCodeAbbrevOp(0)); // NoCallerSavedRegs
// FunctionProtoType
Abv->Add(BitCodeAbbrevOp(0)); // IsVariadic
Abv->Add(BitCodeAbbrevOp(0)); // HasTrailingReturn
@@ -1001,7 +1022,6 @@ void ASTWriter::WriteBlockInfoBlock() {
// Control Block.
BLOCK(CONTROL_BLOCK);
RECORD(METADATA);
- RECORD(SIGNATURE);
RECORD(MODULE_NAME);
RECORD(MODULE_DIRECTORY);
RECORD(MODULE_MAP_FILE);
@@ -1014,7 +1034,6 @@ void ASTWriter::WriteBlockInfoBlock() {
BLOCK(OPTIONS_BLOCK);
RECORD(LANGUAGE_OPTIONS);
RECORD(TARGET_OPTIONS);
- RECORD(DIAGNOSTIC_OPTIONS);
RECORD(FILE_SYSTEM_OPTIONS);
RECORD(HEADER_SEARCH_OPTIONS);
RECORD(PREPROCESSOR_OPTIONS);
@@ -1029,6 +1048,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(IDENTIFIER_OFFSET);
RECORD(IDENTIFIER_TABLE);
RECORD(EAGERLY_DESERIALIZED_DECLS);
+ RECORD(MODULAR_CODEGEN_DECLS);
RECORD(SPECIAL_TYPES);
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
@@ -1049,7 +1069,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(UPDATE_VISIBLE);
RECORD(DECL_UPDATE_OFFSETS);
RECORD(DECL_UPDATES);
- RECORD(DIAG_PRAGMA_MAPPINGS);
RECORD(CUDA_SPECIAL_DECL_REFS);
RECORD(HEADER_SEARCH_TABLE);
RECORD(FP_PRAGMA_OPTIONS);
@@ -1074,6 +1093,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES);
RECORD(DELETE_EXPRS_TO_ANALYZE);
RECORD(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH);
+ RECORD(PP_CONDITIONAL_STACK);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -1242,6 +1262,11 @@ void ASTWriter::WriteBlockInfoBlock() {
BLOCK(EXTENSION_BLOCK);
RECORD(EXTENSION_METADATA);
+ BLOCK(UNHASHED_CONTROL_BLOCK);
+ RECORD(SIGNATURE);
+ RECORD(DIAGNOSTIC_OPTIONS);
+ RECORD(DIAG_PRAGMA_MAPPINGS);
+
#undef RECORD
#undef BLOCK
Stream.ExitBlock();
@@ -1304,21 +1329,73 @@ adjustFilenameForRelocatableAST(const char *Filename, StringRef BaseDir) {
return Filename + Pos;
}
-static ASTFileSignature getSignature() {
- while (true) {
- if (ASTFileSignature S = llvm::sys::Process::GetRandomNumber())
- return S;
- // Rely on GetRandomNumber to eventually return non-zero...
+ASTFileSignature ASTWriter::createSignature(StringRef Bytes) {
+ // Calculate the hash till start of UNHASHED_CONTROL_BLOCK.
+ llvm::SHA1 Hasher;
+ Hasher.update(ArrayRef<uint8_t>(Bytes.bytes_begin(), Bytes.size()));
+ auto Hash = Hasher.result();
+
+ // Convert to an array [5*i32].
+ ASTFileSignature Signature;
+ auto LShift = [&](unsigned char Val, unsigned Shift) {
+ return (uint32_t)Val << Shift;
+ };
+ for (int I = 0; I != 5; ++I)
+ Signature[I] = LShift(Hash[I * 4 + 0], 24) | LShift(Hash[I * 4 + 1], 16) |
+ LShift(Hash[I * 4 + 2], 8) | LShift(Hash[I * 4 + 3], 0);
+
+ return Signature;
+}
+
+ASTFileSignature ASTWriter::writeUnhashedControlBlock(Preprocessor &PP,
+ ASTContext &Context) {
+ // Flush first to prepare the PCM hash (signature).
+ Stream.FlushToWord();
+ auto StartOfUnhashedControl = Stream.GetCurrentBitNo() >> 3;
+
+ // Enter the block and prepare to write records.
+ RecordData Record;
+ Stream.EnterSubblock(UNHASHED_CONTROL_BLOCK_ID, 5);
+
+ // For implicit modules, write the hash of the PCM as its signature.
+ ASTFileSignature Signature;
+ if (WritingModule &&
+ PP.getHeaderSearchInfo().getHeaderSearchOpts().ModulesHashContent) {
+ Signature = createSignature(StringRef(Buffer.begin(), StartOfUnhashedControl));
+ Record.append(Signature.begin(), Signature.end());
+ Stream.EmitRecord(SIGNATURE, Record);
+ Record.clear();
}
+
+ // Diagnostic options.
+ const auto &Diags = Context.getDiagnostics();
+ const DiagnosticOptions &DiagOpts = Diags.getDiagnosticOptions();
+#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ Record.push_back(static_cast<unsigned>(DiagOpts.get##Name()));
+#include "clang/Basic/DiagnosticOptions.def"
+ Record.push_back(DiagOpts.Warnings.size());
+ for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
+ AddString(DiagOpts.Warnings[I], Record);
+ Record.push_back(DiagOpts.Remarks.size());
+ for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I)
+ AddString(DiagOpts.Remarks[I], Record);
+ // Note: we don't serialize the log or serialization file names, because they
+ // are generally transient files and will almost always be overridden.
+ Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
+
+ // Write out the diagnostic/pragma mappings.
+ WritePragmaDiagnosticMappings(Diags, /* IsModule = */ WritingModule);
+
+ // Leave the options block.
+ Stream.ExitBlock();
+ return Signature;
}
/// \brief Write the control block.
-uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
- ASTContext &Context,
- StringRef isysroot,
- const std::string &OutputFile) {
- ASTFileSignature Signature = 0;
-
+void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
+ StringRef isysroot,
+ const std::string &OutputFile) {
using namespace llvm;
Stream.EnterSubblock(CONTROL_BLOCK_ID, 5);
RecordData Record;
@@ -1345,17 +1422,8 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
getClangFullRepositoryVersion());
}
- if (WritingModule) {
- // For implicit modules we output a signature that we can use to ensure
- // duplicate module builds don't collide in the cache as their output order
- // is non-deterministic.
- // FIXME: Remove this when output is deterministic.
- if (Context.getLangOpts().ImplicitModules) {
- Signature = getSignature();
- RecordData::value_type Record[] = {Signature};
- Stream.EmitRecord(SIGNATURE, Record);
- }
+ if (WritingModule) {
// Module name
auto Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
@@ -1394,13 +1462,14 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
}
// Module map file
- if (WritingModule) {
+ if (WritingModule && WritingModule->Kind == Module::ModuleMapModule) {
Record.clear();
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
-
- // Primary module map file.
- AddPath(Map.getModuleMapFileForUniquing(WritingModule)->getName(), Record);
+ AddPath(WritingModule->PresumedModuleMapFile.empty()
+ ? Map.getModuleMapFileForUniquing(WritingModule)->getName()
+ : StringRef(WritingModule->PresumedModuleMapFile),
+ Record);
// Additional module map files.
if (auto *AdditionalModMaps =
@@ -1420,17 +1489,23 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
serialization::ModuleManager &Mgr = Chain->getModuleManager();
Record.clear();
- for (auto *M : Mgr) {
+ for (ModuleFile &M : Mgr) {
// Skip modules that weren't directly imported.
- if (!M->isDirectlyImported())
+ if (!M.isDirectlyImported())
continue;
- Record.push_back((unsigned)M->Kind); // FIXME: Stable encoding
- AddSourceLocation(M->ImportLoc, Record);
- Record.push_back(M->File->getSize());
- Record.push_back(getTimestampForOutput(M->File));
- Record.push_back(M->Signature);
- AddPath(M->FileName, Record);
+ Record.push_back((unsigned)M.Kind); // FIXME: Stable encoding
+ AddSourceLocation(M.ImportLoc, Record);
+
+ // If we have calculated signature, there is no need to store
+ // the size or timestamp.
+ Record.push_back(M.Signature ? 0 : M.File->getSize());
+ Record.push_back(M.Signature ? 0 : getTimestampForOutput(M.File));
+
+ for (auto I : M.Signature)
+ Record.push_back(I);
+
+ AddPath(M.FileName, Record);
}
Stream.EmitRecord(IMPORTS, Record);
}
@@ -1492,24 +1567,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
}
Stream.EmitRecord(TARGET_OPTIONS, Record);
- // Diagnostic options.
- Record.clear();
- const DiagnosticOptions &DiagOpts
- = Context.getDiagnostics().getDiagnosticOptions();
-#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name);
-#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
- Record.push_back(static_cast<unsigned>(DiagOpts.get##Name()));
-#include "clang/Basic/DiagnosticOptions.def"
- Record.push_back(DiagOpts.Warnings.size());
- for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
- AddString(DiagOpts.Warnings[I], Record);
- Record.push_back(DiagOpts.Remarks.size());
- for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I)
- AddString(DiagOpts.Remarks[I], Record);
- // Note: we don't serialize the log or serialization file names, because they
- // are generally transient files and will almost always be overridden.
- Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
-
// File system options.
Record.clear();
const FileSystemOptions &FSOpts =
@@ -1544,6 +1601,8 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
AddString(HSOpts.ModuleCachePath, Record);
AddString(HSOpts.ModuleUserBuildPath, Record);
Record.push_back(HSOpts.DisableModuleHash);
+ Record.push_back(HSOpts.ImplicitModuleMaps);
+ Record.push_back(HSOpts.ModuleMapFileHomeIsCwd);
Record.push_back(HSOpts.UseBuiltinIncludes);
Record.push_back(HSOpts.UseStandardSystemIncludes);
Record.push_back(HSOpts.UseStandardCXXIncludes);
@@ -1623,7 +1682,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP,
PP.getHeaderSearchInfo().getHeaderSearchOpts(),
PP.getLangOpts().Modules);
Stream.ExitBlock();
- return Signature;
}
namespace {
@@ -1634,6 +1692,7 @@ namespace {
bool IsSystemFile;
bool IsTransient;
bool BufferOverridden;
+ bool IsTopLevelModuleMap;
};
} // end anonymous namespace
@@ -1652,6 +1711,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Transient
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Module map
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(std::move(IFAbbrev));
@@ -1666,7 +1726,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
// We only care about file entries that were not overridden.
if (!SLoc->isFile())
continue;
- const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
+ const SrcMgr::FileInfo &File = SLoc->getFile();
+ const SrcMgr::ContentCache *Cache = File.getContentCache();
if (!Cache->OrigEntry)
continue;
@@ -1675,6 +1736,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
Entry.IsSystemFile = Cache->IsSystemFile;
Entry.IsTransient = Cache->IsTransient;
Entry.BufferOverridden = Cache->BufferOverridden;
+ Entry.IsTopLevelModuleMap = isModuleMap(File.getFileCharacteristic()) &&
+ File.getIncludeLoc().isInvalid();
if (Cache->IsSystemFile)
SortedFiles.push_back(Entry);
else
@@ -1705,7 +1768,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
(uint64_t)Entry.File->getSize(),
(uint64_t)getTimestampForOutput(Entry.File),
Entry.BufferOverridden,
- Entry.IsTransient};
+ Entry.IsTransient,
+ Entry.IsTopLevelModuleMap};
EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
}
@@ -1740,7 +1804,7 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
// FileEntry fields.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID
@@ -1759,7 +1823,7 @@ static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) {
Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob
return Stream.EmitAbbrev(std::move(Abbrev));
@@ -1800,24 +1864,31 @@ namespace {
// Trait used for the on-disk hash table of header search information.
class HeaderFileInfoTrait {
ASTWriter &Writer;
- const HeaderSearch &HS;
// Keep track of the framework names we've used during serialization.
SmallVector<char, 128> FrameworkStringData;
llvm::StringMap<unsigned> FrameworkNameOffset;
public:
- HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS)
- : Writer(Writer), HS(HS) { }
-
+ HeaderFileInfoTrait(ASTWriter &Writer) : Writer(Writer) {}
+
struct key_type {
- const FileEntry *FE;
StringRef Filename;
+ off_t Size;
+ time_t ModTime;
};
typedef const key_type &key_type_ref;
+
+ using UnresolvedModule =
+ llvm::PointerIntPair<Module *, 2, ModuleMap::ModuleHeaderRole>;
- typedef HeaderFileInfo data_type;
+ struct data_type {
+ const HeaderFileInfo &HFI;
+ ArrayRef<ModuleMap::KnownHeader> KnownHeaders;
+ UnresolvedModule Unresolved;
+ };
typedef const data_type &data_type_ref;
+
typedef unsigned hash_value_type;
typedef unsigned offset_type;
@@ -1825,8 +1896,7 @@ namespace {
// The hash is based only on size/time of the file, so that the reader can
// match even when symlinking or excess path elements ("foo/../", "../")
// change the form of the name. However, complete path is still the key.
- return llvm::hash_combine(key.FE->getSize(),
- Writer.getTimestampForOutput(key.FE));
+ return llvm::hash_combine(key.Size, key.ModTime);
}
std::pair<unsigned,unsigned>
@@ -1836,68 +1906,74 @@ namespace {
unsigned KeyLen = key.Filename.size() + 1 + 8 + 8;
LE.write<uint16_t>(KeyLen);
unsigned DataLen = 1 + 2 + 4 + 4;
- for (auto ModInfo : HS.getModuleMap().findAllModulesForHeader(key.FE))
+ for (auto ModInfo : Data.KnownHeaders)
if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule()))
DataLen += 4;
+ if (Data.Unresolved.getPointer())
+ DataLen += 4;
LE.write<uint8_t>(DataLen);
return std::make_pair(KeyLen, DataLen);
}
-
+
void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
- LE.write<uint64_t>(key.FE->getSize());
+ LE.write<uint64_t>(key.Size);
KeyLen -= 8;
- LE.write<uint64_t>(Writer.getTimestampForOutput(key.FE));
+ LE.write<uint64_t>(key.ModTime);
KeyLen -= 8;
Out.write(key.Filename.data(), KeyLen);
}
-
+
void EmitData(raw_ostream &Out, key_type_ref key,
data_type_ref Data, unsigned DataLen) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
uint64_t Start = Out.tell(); (void)Start;
- unsigned char Flags = (Data.isImport << 4)
- | (Data.isPragmaOnce << 3)
- | (Data.DirInfo << 1)
- | Data.IndexHeaderMapHeader;
+ unsigned char Flags = (Data.HFI.isImport << 5)
+ | (Data.HFI.isPragmaOnce << 4)
+ | (Data.HFI.DirInfo << 1)
+ | Data.HFI.IndexHeaderMapHeader;
LE.write<uint8_t>(Flags);
- LE.write<uint16_t>(Data.NumIncludes);
+ LE.write<uint16_t>(Data.HFI.NumIncludes);
- if (!Data.ControllingMacro)
- LE.write<uint32_t>(Data.ControllingMacroID);
+ if (!Data.HFI.ControllingMacro)
+ LE.write<uint32_t>(Data.HFI.ControllingMacroID);
else
- LE.write<uint32_t>(Writer.getIdentifierRef(Data.ControllingMacro));
-
+ LE.write<uint32_t>(Writer.getIdentifierRef(Data.HFI.ControllingMacro));
+
unsigned Offset = 0;
- if (!Data.Framework.empty()) {
+ if (!Data.HFI.Framework.empty()) {
// If this header refers into a framework, save the framework name.
llvm::StringMap<unsigned>::iterator Pos
- = FrameworkNameOffset.find(Data.Framework);
+ = FrameworkNameOffset.find(Data.HFI.Framework);
if (Pos == FrameworkNameOffset.end()) {
Offset = FrameworkStringData.size() + 1;
- FrameworkStringData.append(Data.Framework.begin(),
- Data.Framework.end());
+ FrameworkStringData.append(Data.HFI.Framework.begin(),
+ Data.HFI.Framework.end());
FrameworkStringData.push_back(0);
- FrameworkNameOffset[Data.Framework] = Offset;
+ FrameworkNameOffset[Data.HFI.Framework] = Offset;
} else
Offset = Pos->second;
}
LE.write<uint32_t>(Offset);
- // FIXME: If the header is excluded, we should write out some
- // record of that fact.
- for (auto ModInfo : HS.getModuleMap().findAllModulesForHeader(key.FE)) {
- if (uint32_t ModID =
- Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) {
- uint32_t Value = (ModID << 2) | (unsigned)ModInfo.getRole();
+ auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role) {
+ if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M)) {
+ uint32_t Value = (ModID << 2) | (unsigned)Role;
assert((Value >> 2) == ModID && "overflow in header module info");
LE.write<uint32_t>(Value);
}
- }
+ };
+
+ // FIXME: If the header is excluded, we should write out some
+ // record of that fact.
+ for (auto ModInfo : Data.KnownHeaders)
+ EmitModule(ModInfo.getModule(), ModInfo.getRole());
+ if (Data.Unresolved.getPointer())
+ EmitModule(Data.Unresolved.getPointer(), Data.Unresolved.getInt());
assert(Out.tell() - Start == DataLen && "Wrong data length");
}
@@ -1912,16 +1988,72 @@ namespace {
///
/// \param HS The header search structure to save.
void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
+ HeaderFileInfoTrait GeneratorTrait(*this);
+ llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
+ SmallVector<const char *, 4> SavedStrings;
+ unsigned NumHeaderSearchEntries = 0;
+
+ // Find all unresolved headers for the current module. We generally will
+ // have resolved them before we get here, but not necessarily: we might be
+ // compiling a preprocessed module, where there is no requirement for the
+ // original files to exist any more.
+ const HeaderFileInfo Empty; // So we can take a reference.
+ if (WritingModule) {
+ llvm::SmallVector<Module *, 16> Worklist(1, WritingModule);
+ while (!Worklist.empty()) {
+ Module *M = Worklist.pop_back_val();
+ if (!M->isAvailable())
+ continue;
+
+ // Map to disk files where possible, to pick up any missing stat
+ // information. This also means we don't need to check the unresolved
+ // headers list when emitting resolved headers in the first loop below.
+ // FIXME: It'd be preferable to avoid doing this if we were given
+ // sufficient stat information in the module map.
+ HS.getModuleMap().resolveHeaderDirectives(M);
+
+ // If the file didn't exist, we can still create a module if we were given
+ // enough information in the module map.
+ for (auto U : M->MissingHeaders) {
+ // Check that we were given enough information to build a module
+ // without this file existing on disk.
+ if (!U.Size || (!U.ModTime && IncludeTimestamps)) {
+ PP->Diag(U.FileNameLoc, diag::err_module_no_size_mtime_for_header)
+ << WritingModule->getFullModuleName() << U.Size.hasValue()
+ << U.FileName;
+ continue;
+ }
+
+ // Form the effective relative pathname for the file.
+ SmallString<128> Filename(M->Directory->getName());
+ llvm::sys::path::append(Filename, U.FileName);
+ PreparePathForOutput(Filename);
+
+ StringRef FilenameDup = strdup(Filename.c_str());
+ SavedStrings.push_back(FilenameDup.data());
+
+ HeaderFileInfoTrait::key_type Key = {
+ FilenameDup, *U.Size, IncludeTimestamps ? *U.ModTime : 0
+ };
+ HeaderFileInfoTrait::data_type Data = {
+ Empty, {}, {M, ModuleMap::headerKindToRole(U.Kind)}
+ };
+ // FIXME: Deal with cases where there are multiple unresolved header
+ // directives in different submodules for the same header.
+ Generator.insert(Key, Data, GeneratorTrait);
+ ++NumHeaderSearchEntries;
+ }
+
+ Worklist.append(M->submodule_begin(), M->submodule_end());
+ }
+ }
+
SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
if (FilesByUID.size() > HS.header_file_size())
FilesByUID.resize(HS.header_file_size());
-
- HeaderFileInfoTrait GeneratorTrait(*this, HS);
- llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
- SmallVector<const char *, 4> SavedStrings;
- unsigned NumHeaderSearchEntries = 0;
+
for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) {
const FileEntry *File = FilesByUID[UID];
if (!File)
@@ -1948,11 +2080,16 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
SavedStrings.push_back(Filename.data());
}
- HeaderFileInfoTrait::key_type key = { File, Filename };
- Generator.insert(key, *HFI, GeneratorTrait);
+ HeaderFileInfoTrait::key_type Key = {
+ Filename, File->getSize(), getTimestampForOutput(File)
+ };
+ HeaderFileInfoTrait::data_type Data = {
+ *HFI, HS.getModuleMap().findAllModulesForHeader(File), {}
+ };
+ Generator.insert(Key, Data, GeneratorTrait);
++NumHeaderSearchEntries;
}
-
+
// Create the on-disk hash table in a buffer.
SmallString<4096> TableData;
uint32_t BucketOffset;
@@ -1986,6 +2123,30 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
free(const_cast<char *>(SavedStrings[I]));
}
+static void emitBlob(llvm::BitstreamWriter &Stream, StringRef Blob,
+ unsigned SLocBufferBlobCompressedAbbrv,
+ unsigned SLocBufferBlobAbbrv) {
+ typedef ASTWriter::RecordData::value_type RecordDataType;
+
+ // Compress the buffer if possible. We expect that almost all PCM
+ // consumers will not want its contents.
+ SmallString<0> CompressedBuffer;
+ if (llvm::zlib::isAvailable()) {
+ llvm::Error E = llvm::zlib::compress(Blob.drop_back(1), CompressedBuffer);
+ if (!E) {
+ RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED,
+ Blob.size() - 1};
+ Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record,
+ CompressedBuffer);
+ return;
+ }
+ llvm::consumeError(std::move(E));
+ }
+
+ RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB};
+ Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, Blob);
+}
+
/// \brief Writes the block containing the serialized form of the
/// source manager.
///
@@ -2094,20 +2255,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
const llvm::MemoryBuffer *Buffer =
Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
StringRef Blob(Buffer->getBufferStart(), Buffer->getBufferSize() + 1);
-
- // Compress the buffer if possible. We expect that almost all PCM
- // consumers will not want its contents.
- SmallString<0> CompressedBuffer;
- if (llvm::zlib::compress(Blob.drop_back(1), CompressedBuffer) ==
- llvm::zlib::StatusOK) {
- RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED,
- Blob.size() - 1};
- Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record,
- CompressedBuffer);
- } else {
- RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB};
- Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, Blob);
- }
+ emitBlob(Stream, Blob, SLocBufferBlobCompressedAbbrv,
+ SLocBufferBlobAbbrv);
}
} else {
// The source location entry is a macro expansion.
@@ -2236,6 +2385,18 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
Stream.EmitRecord(PP_COUNTER_VALUE, Record);
}
+ if (PP.isRecordingPreamble() && PP.hasRecordedPreamble()) {
+ assert(!IsModule);
+ for (const auto &Cond : PP.getPreambleConditionalStack()) {
+ AddSourceLocation(Cond.IfLoc, Record);
+ Record.push_back(Cond.WasSkipping);
+ Record.push_back(Cond.FoundNonSkip);
+ Record.push_back(Cond.FoundElse);
+ }
+ Stream.EmitRecord(PP_CONDITIONAL_STACK, Record);
+ Record.clear();
+ }
+
// Enter the preprocessor block.
Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
@@ -2347,7 +2508,6 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
}
AddIdentifierRef(Name, Record);
- Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
AddSourceLocation(MI->getDefinitionLoc(), Record);
AddSourceLocation(MI->getDefinitionEndLoc(), Record);
Record.push_back(MI->isUsed());
@@ -2361,9 +2521,9 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
Record.push_back(MI->isC99Varargs());
Record.push_back(MI->isGNUVarargs());
Record.push_back(MI->hasCommaPasting());
- Record.push_back(MI->getNumArgs());
- for (const IdentifierInfo *Arg : MI->args())
- AddIdentifierRef(Arg, Record);
+ Record.push_back(MI->getNumParams());
+ for (const IdentifierInfo *Param : MI->params())
+ AddIdentifierRef(Param, Record);
}
// If we have a detailed preprocessing record, record the macro definition
@@ -2516,7 +2676,8 @@ unsigned ASTWriter::getLocalOrImportedSubmoduleID(Module *Mod) {
auto *Top = Mod->getTopLevelModule();
if (Top != WritingModule &&
- !Top->fullModuleNameIs(StringRef(getLangOpts().CurrentModule)))
+ (getLangOpts().CompilingPCH ||
+ !Top->fullModuleNameIs(StringRef(getLangOpts().CurrentModule))))
return 0;
return SubmoduleIDs[Mod] = NextSubmoduleID++;
@@ -2629,9 +2790,10 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
unsigned ConflictAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
// Write the submodule metadata block.
- RecordData::value_type Record[] = {getNumberOfModules(WritingModule),
- FirstSubmoduleID -
- NUM_PREDEF_SUBMODULE_IDS};
+ RecordData::value_type Record[] = {
+ getNumberOfModules(WritingModule),
+ FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS,
+ (unsigned)WritingModule->Kind};
Stream.EmitRecord(SUBMODULE_METADATA, Record);
// Write all of the submodules.
@@ -2650,11 +2812,17 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
// Emit the definition of the block.
{
- RecordData::value_type Record[] = {
- SUBMODULE_DEFINITION, ID, ParentID, Mod->IsFramework, Mod->IsExplicit,
- Mod->IsSystem, Mod->IsExternC, Mod->InferSubmodules,
- Mod->InferExplicitSubmodules, Mod->InferExportWildcard,
- Mod->ConfigMacrosExhaustive};
+ RecordData::value_type Record[] = {SUBMODULE_DEFINITION,
+ ID,
+ ParentID,
+ Mod->IsFramework,
+ Mod->IsExplicit,
+ Mod->IsSystem,
+ Mod->IsExternC,
+ Mod->InferSubmodules,
+ Mod->InferExplicitSubmodules,
+ Mod->InferExportWildcard,
+ Mod->ConfigMacrosExhaustive};
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
}
@@ -2768,64 +2936,89 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
"non-imported submodule?");
}
-serialization::SubmoduleID
-ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
- if (Loc.isInvalid() || !WritingModule)
- return 0; // No submodule
-
- // Find the module that owns this location.
- ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap();
- Module *OwningMod
- = ModMap.inferModuleFromLocation(FullSourceLoc(Loc,PP->getSourceManager()));
- if (!OwningMod)
- return 0;
-
- // Check whether this submodule is part of our own module.
- if (WritingModule != OwningMod && !OwningMod->isSubModuleOf(WritingModule))
- return 0;
-
- return getSubmoduleID(OwningMod);
-}
-
void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
bool isModule) {
- // Make sure set diagnostic pragmas don't affect the translation unit that
- // imports the module.
- // FIXME: Make diagnostic pragma sections work properly with modules.
- if (isModule)
- return;
-
llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64>
DiagStateIDMap;
unsigned CurrID = 0;
- DiagStateIDMap[&Diag.DiagStates.front()] = ++CurrID; // the command-line one.
RecordData Record;
- for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
- I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end();
- I != E; ++I) {
- const DiagnosticsEngine::DiagStatePoint &point = *I;
- if (point.Loc.isInvalid())
- continue;
- AddSourceLocation(point.Loc, Record);
- unsigned &DiagStateID = DiagStateIDMap[point.State];
+ auto EncodeDiagStateFlags =
+ [](const DiagnosticsEngine::DiagState *DS) -> unsigned {
+ unsigned Result = (unsigned)DS->ExtBehavior;
+ for (unsigned Val :
+ {(unsigned)DS->IgnoreAllWarnings, (unsigned)DS->EnableAllWarnings,
+ (unsigned)DS->WarningsAsErrors, (unsigned)DS->ErrorsAsFatal,
+ (unsigned)DS->SuppressSystemWarnings})
+ Result = (Result << 1) | Val;
+ return Result;
+ };
+
+ unsigned Flags = EncodeDiagStateFlags(Diag.DiagStatesByLoc.FirstDiagState);
+ Record.push_back(Flags);
+
+ auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State,
+ bool IncludeNonPragmaStates) {
+ // Ensure that the diagnostic state wasn't modified since it was created.
+ // We will not correctly round-trip this information otherwise.
+ assert(Flags == EncodeDiagStateFlags(State) &&
+ "diag state flags vary in single AST file");
+
+ unsigned &DiagStateID = DiagStateIDMap[State];
Record.push_back(DiagStateID);
-
+
if (DiagStateID == 0) {
DiagStateID = ++CurrID;
- for (const auto &I : *(point.State)) {
- if (I.second.isPragma()) {
+
+ // Add a placeholder for the number of mappings.
+ auto SizeIdx = Record.size();
+ Record.emplace_back();
+ for (const auto &I : *State) {
+ if (I.second.isPragma() || IncludeNonPragmaStates) {
Record.push_back(I.first);
- Record.push_back((unsigned)I.second.getSeverity());
+ Record.push_back(I.second.serialize());
}
}
- Record.push_back(-1); // mark the end of the diag/map pairs for this
- // location.
+ // Update the placeholder.
+ Record[SizeIdx] = (Record.size() - SizeIdx) / 2;
+ }
+ };
+
+ AddDiagState(Diag.DiagStatesByLoc.FirstDiagState, isModule);
+
+ // Reserve a spot for the number of locations with state transitions.
+ auto NumLocationsIdx = Record.size();
+ Record.emplace_back();
+
+ // Emit the state transitions.
+ unsigned NumLocations = 0;
+ for (auto &FileIDAndFile : Diag.DiagStatesByLoc.Files) {
+ if (!FileIDAndFile.first.isValid() ||
+ !FileIDAndFile.second.HasLocalTransitions)
+ continue;
+ ++NumLocations;
+ AddSourceLocation(Diag.SourceMgr->getLocForStartOfFile(FileIDAndFile.first),
+ Record);
+ Record.push_back(FileIDAndFile.second.StateTransitions.size());
+ for (auto &StatePoint : FileIDAndFile.second.StateTransitions) {
+ Record.push_back(StatePoint.Offset);
+ AddDiagState(StatePoint.State, false);
}
}
- if (!Record.empty())
- Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record);
+ // Backpatch the number of locations.
+ Record[NumLocationsIdx] = NumLocations;
+
+ // Emit CurDiagStateLoc. Do it last in order to match source order.
+ //
+ // This also protects against a hypothetical corner case with simulating
+ // -Werror settings for implicit modules in the ASTReader, where reading
+ // CurDiagState out of context could change whether warning pragmas are
+ // treated as errors.
+ AddSourceLocation(Diag.DiagStatesByLoc.CurDiagStateLoc, Record);
+ AddDiagState(Diag.DiagStatesByLoc.CurDiagState, false);
+
+ Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record);
}
//===----------------------------------------------------------------------===//
@@ -3559,6 +3752,7 @@ public:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXLiteralOperatorName:
+ case DeclarationName::CXXDeductionGuideName:
KeyLen += 4;
break;
case DeclarationName::CXXOperatorName:
@@ -3588,6 +3782,7 @@ public:
switch (Name.getKind()) {
case DeclarationName::Identifier:
case DeclarationName::CXXLiteralOperatorName:
+ case DeclarationName::CXXDeductionGuideName:
LE.write<uint32_t>(Writer.getIdentifierRef(Name.getIdentifier()));
return;
case DeclarationName::ObjCZeroArgSelector:
@@ -3931,7 +4126,7 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
/// \brief Write an FP_PRAGMA_OPTIONS block for the given FPOptions.
void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) {
- RecordData::value_type Record[] = {Opts.fp_contract};
+ RecordData::value_type Record[] = {Opts.getInt()};
Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record);
}
@@ -4086,6 +4281,25 @@ void ASTWriter::WriteMSPointersToMembersPragmaOptions(Sema &SemaRef) {
Stream.EmitRecord(POINTERS_TO_MEMBERS_PRAGMA_OPTIONS, Record);
}
+/// \brief Write the state of 'pragma pack' at the end of the module.
+void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) {
+ // Don't serialize pragma pack state for modules, since it should only take
+ // effect on a per-submodule basis.
+ if (WritingModule)
+ return;
+
+ RecordData Record;
+ Record.push_back(SemaRef.PackStack.CurrentValue);
+ AddSourceLocation(SemaRef.PackStack.CurrentPragmaLocation, Record);
+ Record.push_back(SemaRef.PackStack.Stack.size());
+ for (const auto &StackEntry : SemaRef.PackStack.Stack) {
+ Record.push_back(StackEntry.Value);
+ AddSourceLocation(StackEntry.PragmaLocation, Record);
+ AddString(StackEntry.StackSlotLabel, Record);
+ }
+ Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record);
+}
+
void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
ModuleFileExtensionWriter &Writer) {
// Enter the extension block.
@@ -4223,9 +4437,11 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
}
ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream,
+ SmallVectorImpl<char> &Buffer, MemoryBufferCache &PCMCache,
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
bool IncludeTimestamps)
- : Stream(Stream), IncludeTimestamps(IncludeTimestamps) {
+ : Stream(Stream), Buffer(Buffer), PCMCache(PCMCache),
+ IncludeTimestamps(IncludeTimestamps) {
for (const auto &Ext : Extensions) {
if (auto Writer = Ext->createExtensionWriter(*this))
ModuleFileExtensionWriters.push_back(std::move(Writer));
@@ -4245,9 +4461,10 @@ time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const {
return IncludeTimestamps ? E->getModificationTime() : 0;
}
-uint64_t ASTWriter::WriteAST(Sema &SemaRef, const std::string &OutputFile,
- Module *WritingModule, StringRef isysroot,
- bool hasErrors) {
+ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef,
+ const std::string &OutputFile,
+ Module *WritingModule, StringRef isysroot,
+ bool hasErrors) {
WritingAST = true;
ASTHasCompilerErrors = hasErrors;
@@ -4271,6 +4488,12 @@ uint64_t ASTWriter::WriteAST(Sema &SemaRef, const std::string &OutputFile,
this->BaseDirectory.clear();
WritingAST = false;
+ if (SemaRef.Context.getLangOpts().ImplicitModules && WritingModule) {
+ // Construct MemoryBuffer and update buffer manager.
+ PCMCache.addBuffer(OutputFile,
+ llvm::MemoryBuffer::getMemBufferCopy(
+ StringRef(Buffer.begin(), Buffer.size())));
+ }
return Signature;
}
@@ -4283,9 +4506,9 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
}
}
-uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
- const std::string &OutputFile,
- Module *WritingModule) {
+ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
+ const std::string &OutputFile,
+ Module *WritingModule) {
using namespace llvm;
bool isModule = WritingModule != nullptr;
@@ -4433,7 +4656,7 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
}
// Write the control block
- uint64_t Signature = WriteControlBlock(PP, Context, isysroot, OutputFile);
+ WriteControlBlock(PP, Context, isysroot, OutputFile);
// Write the remaining AST contents.
Stream.EnterSubblock(AST_BLOCK_ID, 5);
@@ -4573,10 +4796,10 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
SmallString<2048> Buffer;
{
llvm::raw_svector_ostream Out(Buffer);
- for (ModuleFile *M : Chain->ModuleMgr) {
+ for (ModuleFile &M : Chain->ModuleMgr) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
- StringRef FileName = M->FileName;
+ StringRef FileName = M.FileName;
LE.write<uint16_t>(FileName.size());
Out.write(FileName.data(), FileName.size());
@@ -4594,15 +4817,15 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
// These values should be unique within a chain, since they will be read
// as keys into ContinuousRangeMaps.
- writeBaseIDOrNone(M->SLocEntryBaseOffset, M->LocalNumSLocEntries);
- writeBaseIDOrNone(M->BaseIdentifierID, M->LocalNumIdentifiers);
- writeBaseIDOrNone(M->BaseMacroID, M->LocalNumMacros);
- writeBaseIDOrNone(M->BasePreprocessedEntityID,
- M->NumPreprocessedEntities);
- writeBaseIDOrNone(M->BaseSubmoduleID, M->LocalNumSubmodules);
- writeBaseIDOrNone(M->BaseSelectorID, M->LocalNumSelectors);
- writeBaseIDOrNone(M->BaseDeclID, M->LocalNumDecls);
- writeBaseIDOrNone(M->BaseTypeIndex, M->LocalNumTypes);
+ writeBaseIDOrNone(M.SLocEntryBaseOffset, M.LocalNumSLocEntries);
+ writeBaseIDOrNone(M.BaseIdentifierID, M.LocalNumIdentifiers);
+ writeBaseIDOrNone(M.BaseMacroID, M.LocalNumMacros);
+ writeBaseIDOrNone(M.BasePreprocessedEntityID,
+ M.NumPreprocessedEntities);
+ writeBaseIDOrNone(M.BaseSubmoduleID, M.LocalNumSubmodules);
+ writeBaseIDOrNone(M.BaseSelectorID, M.LocalNumSelectors);
+ writeBaseIDOrNone(M.BaseDeclID, M.LocalNumDecls);
+ writeBaseIDOrNone(M.BaseTypeIndex, M.LocalNumTypes);
}
}
RecordData::value_type Record[] = {MODULE_OFFSET_MAP};
@@ -4650,7 +4873,6 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
WriteOpenCLExtensionTypes(SemaRef);
WriteOpenCLExtensionDecls(SemaRef);
WriteCUDAPragmas(SemaRef);
- WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule);
// If we're emitting a module, write out the submodule information.
if (WritingModule)
@@ -4662,6 +4884,9 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
if (!EagerlyDeserializedDecls.empty())
Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls);
+ if (!ModularCodegenDecls.empty())
+ Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls);
+
// Write the record containing tentative definitions.
if (!TentativeDefinitions.empty())
Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);
@@ -4765,6 +4990,7 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
WriteMSStructPragmaOptions(SemaRef);
WriteMSPointersToMembersPragmaOptions(SemaRef);
}
+ WritePackPragmaOptions(SemaRef);
// Some simple statistics
RecordData::value_type Record[] = {
@@ -4776,7 +5002,7 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
for (const auto &ExtWriter : ModuleFileExtensionWriters)
WriteModuleFileExtension(SemaRef, *ExtWriter);
- return Signature;
+ return writeUnhashedControlBlock(PP, Context);
}
void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
@@ -4813,9 +5039,18 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
case UPD_CXX_ADDED_FUNCTION_DEFINITION:
break;
- case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: {
+ const VarDecl *VD = cast<VarDecl>(D);
Record.AddSourceLocation(Update.getLoc());
+ if (VD->getInit()) {
+ Record.push_back(!VD->isInitKnownICE() ? 1
+ : (VD->isInitICE() ? 3 : 2));
+ Record.AddStmt(const_cast<Expr*>(VD->getInit()));
+ } else {
+ Record.push_back(0);
+ }
break;
+ }
case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT:
Record.AddStmt(const_cast<Expr *>(
@@ -5229,6 +5464,10 @@ void ASTRecordWriter::AddDeclarationName(DeclarationName Name) {
AddTypeRef(Name.getCXXNameType());
break;
+ case DeclarationName::CXXDeductionGuideName:
+ AddDeclRef(Name.getCXXDeductionGuideTemplate());
+ break;
+
case DeclarationName::CXXOperatorName:
Record->push_back(Name.getCXXOverloadedOperator());
break;
@@ -5290,6 +5529,7 @@ void ASTRecordWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc,
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXUsingDirective:
+ case DeclarationName::CXXDeductionGuideName:
break;
}
}
@@ -5634,9 +5874,11 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
Record->push_back(Data.HasUninitializedFields);
Record->push_back(Data.HasInheritedConstructor);
Record->push_back(Data.HasInheritedAssignment);
+ Record->push_back(Data.NeedOverloadResolutionForCopyConstructor);
Record->push_back(Data.NeedOverloadResolutionForMoveConstructor);
Record->push_back(Data.NeedOverloadResolutionForMoveAssignment);
Record->push_back(Data.NeedOverloadResolutionForDestructor);
+ Record->push_back(Data.DefaultedCopyConstructorIsDeleted);
Record->push_back(Data.DefaultedMoveConstructorIsDeleted);
Record->push_back(Data.DefaultedMoveAssignmentIsDeleted);
Record->push_back(Data.DefaultedDestructorIsDeleted);
@@ -5645,16 +5887,27 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
Record->push_back(Data.HasIrrelevantDestructor);
Record->push_back(Data.HasConstexprNonCopyMoveConstructor);
Record->push_back(Data.HasDefaultedDefaultConstructor);
+ Record->push_back(Data.CanPassInRegisters);
Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr);
Record->push_back(Data.HasConstexprDefaultConstructor);
Record->push_back(Data.HasNonLiteralTypeFieldsOrBases);
Record->push_back(Data.ComputedVisibleConversions);
Record->push_back(Data.UserProvidedDefaultConstructor);
Record->push_back(Data.DeclaredSpecialMembers);
- Record->push_back(Data.ImplicitCopyConstructorHasConstParam);
+ Record->push_back(Data.ImplicitCopyConstructorCanHaveConstParamForVBase);
+ Record->push_back(Data.ImplicitCopyConstructorCanHaveConstParamForNonVBase);
Record->push_back(Data.ImplicitCopyAssignmentHasConstParam);
Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
+
+ // getODRHash will compute the ODRHash if it has not been previously computed.
+ Record->push_back(D->getODRHash());
+ bool ModulesDebugInfo = Writer->Context->getLangOpts().ModulesDebugInfo &&
+ Writer->WritingModule && !D->isDependentType();
+ Record->push_back(ModulesDebugInfo);
+ if (ModulesDebugInfo)
+ Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D));
+
// IsLambda bit is already saved.
Record->push_back(Data.NumBases);
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp
index d8466e9..ec21ca2 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -86,6 +86,7 @@ namespace clang {
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitDeclaratorDecl(DeclaratorDecl *D);
void VisitFunctionDecl(FunctionDecl *D);
+ void VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D);
void VisitCXXMethodDecl(CXXMethodDecl *D);
void VisitCXXConstructorDecl(CXXConstructorDecl *D);
void VisitCXXDestructorDecl(CXXDestructorDecl *D);
@@ -298,7 +299,7 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.push_back(D->isTopLevelDeclInObjCContainer());
Record.push_back(D->getAccess());
Record.push_back(D->isModulePrivate());
- Record.push_back(Writer.inferSubmoduleIDFromLocation(D->getLocation()));
+ Record.push_back(Writer.getSubmoduleID(D->getOwningModule()));
// If this declaration injected a name into a context different from its
// lexical context, and that context is an imported namespace, we need to
@@ -368,6 +369,7 @@ void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) {
Record.push_back(D->isModed());
if (D->isModed())
Record.AddTypeRef(D->getUnderlyingType());
+ Record.AddDeclRef(D->getAnonDeclWithTypedefName(false));
}
void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
@@ -519,6 +521,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back((int)D->SClass); // FIXME: stable encoding
Record.push_back(D->IsInline);
Record.push_back(D->IsInlineSpecified);
+ Record.push_back(D->IsExplicitSpecified);
Record.push_back(D->IsVirtualAsWritten);
Record.push_back(D->IsPure);
Record.push_back(D->HasInheritedPrototype);
@@ -607,6 +610,11 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Code = serialization::DECL_FUNCTION;
}
+void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+ VisitFunctionDecl(D);
+ Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
+}
+
void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
VisitNamedDecl(D);
// FIXME: convert to LazyStmtPtr?
@@ -791,7 +799,9 @@ void ASTDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
// FIXME: stable encoding
Record.push_back((unsigned)D->getPropertyImplementation());
Record.AddDeclarationName(D->getGetterName());
+ Record.AddSourceLocation(D->getGetterNameLoc());
Record.AddDeclarationName(D->getSetterName());
+ Record.AddSourceLocation(D->getSetterNameLoc());
Record.AddDeclRef(D->getGetterMethodDecl());
Record.AddDeclRef(D->getSetterMethodDecl());
Record.AddDeclRef(D->getPropertyIvarDecl());
@@ -806,7 +816,6 @@ void ASTDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) {
void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
VisitObjCImplDecl(D);
- Record.AddIdentifierRef(D->getIdentifier());
Record.AddSourceLocation(D->getCategoryNameLoc());
Code = serialization::DECL_OBJC_CATEGORY_IMPL;
}
@@ -906,6 +915,10 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isConstexpr());
Record.push_back(D->isInitCapture());
Record.push_back(D->isPreviousDeclInSameBlockScope());
+ if (const auto *IPD = dyn_cast<ImplicitParamDecl>(D))
+ Record.push_back(static_cast<unsigned>(IPD->getParameterKind()));
+ else
+ Record.push_back(0);
}
Record.push_back(D->getLinkageInternal());
@@ -1268,8 +1281,6 @@ void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
VisitCXXMethodDecl(D);
- Record.push_back(D->IsExplicitSpecified);
-
Code = D->isInheritingConstructor()
? serialization::DECL_CXX_INHERITED_CONSTRUCTOR
: serialization::DECL_CXX_CONSTRUCTOR;
@@ -1285,7 +1296,6 @@ void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
VisitCXXMethodDecl(D);
- Record.push_back(D->IsExplicitSpecified);
Code = serialization::DECL_CXX_CONVERSION;
}
@@ -1983,6 +1993,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture
Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
+ Abv->Add(BitCodeAbbrevOp(0)); // ImplicitParamKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // IsInitICE (local)
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // VarKind (local enum)
@@ -2023,6 +2034,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InlineSpecified
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitSpecified
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // VirtualAsWritten
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure
Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto
@@ -2221,6 +2233,21 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
Writer->ClearSwitchCaseIDs();
assert(FD->doesThisDeclarationHaveABody());
+ bool ModulesCodegen = false;
+ if (Writer->WritingModule && !FD->isDependentContext()) {
+ // Under -fmodules-codegen, codegen is performed for all defined functions.
+ // When building a C++ Modules TS module interface unit, a strong definition
+ // in the module interface is provided by the compilation of that module
+ // interface unit, not by its users. (Inline functions are still emitted
+ // in module users.)
+ ModulesCodegen =
+ Writer->Context->getLangOpts().ModulesCodegen ||
+ (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit &&
+ Writer->Context->GetGVALinkageForFunction(FD) == GVA_StrongExternal);
+ }
+ Record->push_back(ModulesCodegen);
+ if (ModulesCodegen)
+ Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(FD));
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
Record->push_back(CD->getNumCtorInitializers());
if (CD->getNumCtorInitializers())
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp
index 01fd98c..6971339 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -286,7 +286,7 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
}
// Outputs
- for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
Record.AddStmt(S->getOutputExpr(I));
Record.AddString(S->getOutputConstraint(I));
}
@@ -300,24 +300,48 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
Code = serialization::STMT_MSASM;
}
-void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *CoroStmt) {
+ VisitStmt(CoroStmt);
+ Record.push_back(CoroStmt->getParamMoves().size());
+ for (Stmt *S : CoroStmt->children())
+ Record.AddStmt(S);
+ Code = serialization::STMT_COROUTINE_BODY;
}
void ASTStmtWriter::VisitCoreturnStmt(CoreturnStmt *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+ VisitStmt(S);
+ Record.AddSourceLocation(S->getKeywordLoc());
+ Record.AddStmt(S->getOperand());
+ Record.AddStmt(S->getPromiseCall());
+ Record.push_back(S->isImplicit());
+ Code = serialization::STMT_CORETURN;
}
-void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtWriter::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E) {
+ VisitExpr(E);
+ Record.AddSourceLocation(E->getKeywordLoc());
+ for (Stmt *S : E->children())
+ Record.AddStmt(S);
+ Record.AddStmt(E->getOpaqueValue());
}
-void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *S) {
- // FIXME: Implement coroutine serialization.
- llvm_unreachable("unimplemented");
+void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *E) {
+ VisitCoroutineSuspendExpr(E);
+ Record.push_back(E->isImplicit());
+ Code = serialization::EXPR_COAWAIT;
+}
+
+void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *E) {
+ VisitCoroutineSuspendExpr(E);
+ Code = serialization::EXPR_COYIELD;
+}
+
+void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
+ VisitExpr(E);
+ Record.AddSourceLocation(E->getKeywordLoc());
+ for (Stmt *S : E->children())
+ Record.AddStmt(S);
+ Code = serialization::EXPR_DEPENDENT_COAWAIT;
}
void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
@@ -645,7 +669,7 @@ void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
Record.AddStmt(E->getRHS());
Record.push_back(E->getOpcode()); // FIXME: stable encoding
Record.AddSourceLocation(E->getOperatorLoc());
- Record.push_back(E->isFPContractable());
+ Record.push_back(E->getFPFeatures().getInt());
Code = serialization::EXPR_BINARY_OPERATOR;
}
@@ -1213,7 +1237,7 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
Record.push_back(E->getOperator());
Record.AddSourceRange(E->Range);
- Record.push_back(E->isFPContractable());
+ Record.push_back(E->getFPFeatures().getInt());
Code = serialization::EXPR_CXX_OPERATOR_CALL;
}
@@ -1794,6 +1818,7 @@ void OMPClauseWriter::writeClause(OMPClause *C) {
}
void OMPClauseWriter::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) {
+ Record.push_back(C->getCaptureRegion());
Record.AddStmt(C->getPreInitStmt());
}
@@ -1803,6 +1828,7 @@ void OMPClauseWriter::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) {
}
void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.push_back(C->getNameModifier());
Record.AddSourceLocation(C->getNameModifierLoc());
Record.AddSourceLocation(C->getColonLoc());
@@ -1816,6 +1842,7 @@ void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) {
}
void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.AddStmt(C->getNumThreads());
Record.AddSourceLocation(C->getLParenLoc());
}
@@ -1955,6 +1982,25 @@ void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) {
Record.AddStmt(E);
}
+void OMPClauseWriter::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) {
+ Record.push_back(C->varlist_size());
+ VisitOMPClauseWithPostUpdate(C);
+ Record.AddSourceLocation(C->getLParenLoc());
+ Record.AddSourceLocation(C->getColonLoc());
+ Record.AddNestedNameSpecifierLoc(C->getQualifierLoc());
+ Record.AddDeclarationNameInfo(C->getNameInfo());
+ for (auto *VE : C->varlists())
+ Record.AddStmt(VE);
+ for (auto *VE : C->privates())
+ Record.AddStmt(VE);
+ for (auto *E : C->lhs_exprs())
+ Record.AddStmt(E);
+ for (auto *E : C->rhs_exprs())
+ Record.AddStmt(E);
+ for (auto *E : C->reduction_ops())
+ Record.AddStmt(E);
+}
+
void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
Record.push_back(C->varlist_size());
VisitOMPClauseWithPostUpdate(C);
@@ -2064,11 +2110,13 @@ void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) {
}
void OMPClauseWriter::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.AddStmt(C->getNumTeams());
Record.AddSourceLocation(C->getLParenLoc());
}
void OMPClauseWriter::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.AddStmt(C->getThreadLimit());
Record.AddSourceLocation(C->getLParenLoc());
}
@@ -2236,6 +2284,15 @@ void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) {
if (isOpenMPLoopBoundSharingDirective(D->getDirectiveKind())) {
Record.AddStmt(D->getPrevLowerBoundVariable());
Record.AddStmt(D->getPrevUpperBoundVariable());
+ Record.AddStmt(D->getDistInc());
+ Record.AddStmt(D->getPrevEnsureUpperBound());
+ Record.AddStmt(D->getCombinedLowerBoundVariable());
+ Record.AddStmt(D->getCombinedUpperBoundVariable());
+ Record.AddStmt(D->getCombinedEnsureUpperBound());
+ Record.AddStmt(D->getCombinedInit());
+ Record.AddStmt(D->getCombinedCond());
+ Record.AddStmt(D->getCombinedNextLowerBound());
+ Record.AddStmt(D->getCombinedNextUpperBound());
}
for (auto I : D->counters()) {
Record.AddStmt(I);
@@ -2421,6 +2478,7 @@ void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
void ASTStmtWriter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) {
VisitStmt(D);
+ Record.push_back(D->getNumClauses());
VisitOMPExecutableDirective(D);
Code = serialization::STMT_OMP_TASKGROUP_DIRECTIVE;
}
diff --git a/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp
index 7f1b750..2e00765 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp
@@ -27,10 +27,11 @@ PCHGenerator::PCHGenerator(
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
bool AllowASTWithErrors, bool IncludeTimestamps)
: PP(PP), OutputFile(OutputFile), isysroot(isysroot.str()),
- SemaPtr(nullptr), Buffer(Buffer), Stream(Buffer->Data),
- Writer(Stream, Extensions, IncludeTimestamps),
+ SemaPtr(nullptr), Buffer(std::move(Buffer)), Stream(this->Buffer->Data),
+ Writer(Stream, this->Buffer->Data, PP.getPCMCache(), Extensions,
+ IncludeTimestamps),
AllowASTWithErrors(AllowASTWithErrors) {
- Buffer->IsComplete = false;
+ this->Buffer->IsComplete = false;
}
PCHGenerator::~PCHGenerator() {
diff --git a/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp b/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp
index ae5796e..6978e7e 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -376,6 +376,15 @@ namespace {
/// \brief The set of modules on which this module depends. Each entry is
/// a module ID.
SmallVector<unsigned, 4> Dependencies;
+ ASTFileSignature Signature;
+ };
+
+ struct ImportedModuleFileInfo {
+ off_t StoredSize;
+ time_t StoredModTime;
+ ASTFileSignature StoredSignature;
+ ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig)
+ : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {}
};
/// \brief Builder that generates the global module index file.
@@ -383,12 +392,20 @@ namespace {
FileManager &FileMgr;
const PCHContainerReader &PCHContainerRdr;
- /// \brief Mapping from files to module file information.
+ /// Mapping from files to module file information.
typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap;
- /// \brief Information about each of the known module files.
+ /// Information about each of the known module files.
ModuleFilesMap ModuleFiles;
+ /// \brief Mapping from the imported module file to the imported
+ /// information.
+ typedef std::multimap<const FileEntry *, ImportedModuleFileInfo>
+ ImportedModuleFilesMap;
+
+ /// \brief Information about each importing of a module file.
+ ImportedModuleFilesMap ImportedModuleFiles;
+
/// \brief Mapping from identifiers to the list of module file IDs that
/// consider this identifier to be interesting.
typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
@@ -424,7 +441,8 @@ namespace {
bool loadModuleFile(const FileEntry *File);
/// \brief Write the index to the given bitstream.
- void writeIndex(llvm::BitstreamWriter &Stream);
+ /// \returns true if an error occurred, false otherwise.
+ bool writeIndex(llvm::BitstreamWriter &Stream);
};
}
@@ -515,7 +533,7 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
unsigned ID = getModuleFileInfo(File).ID;
// Search for the blocks and records we care about.
- enum { Other, ControlBlock, ASTBlock } State = Other;
+ enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other;
bool Done = false;
while (!Done) {
llvm::BitstreamEntry Entry = InStream.advance();
@@ -553,6 +571,15 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
continue;
}
+ if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) {
+ if (InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID))
+ return true;
+
+ // Found the Diagnostic Options block.
+ State = DiagnosticOptionsBlock;
+ continue;
+ }
+
if (InStream.SkipBlock())
return true;
@@ -587,7 +614,10 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
// Skip the stored signature.
// FIXME: we could read the signature out of the import and validate it.
- Idx++;
+ ASTFileSignature StoredSignature = {
+ {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
+ (uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
+ (uint32_t)Record[Idx++]}}};
// Retrieve the imported file name.
unsigned Length = Record[Idx++];
@@ -599,11 +629,16 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
const FileEntry *DependsOnFile
= FileMgr.getFile(ImportedFile, /*openFile=*/false,
/*cacheFailure=*/false);
- if (!DependsOnFile ||
- (StoredSize != DependsOnFile->getSize()) ||
- (StoredModTime != DependsOnFile->getModificationTime()))
+
+ if (!DependsOnFile)
return true;
+ // Save the information in ImportedModuleFileInfo so we can verify after
+ // loading all pcms.
+ ImportedModuleFiles.insert(std::make_pair(
+ DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,
+ StoredSignature)));
+
// Record the dependency.
unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID;
getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
@@ -632,6 +667,12 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
}
}
+ // Get Signature.
+ if (State == DiagnosticOptionsBlock && Code == SIGNATURE)
+ getModuleFileInfo(File).Signature = {
+ {{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2],
+ (uint32_t)Record[3], (uint32_t)Record[4]}}};
+
// We don't care about this record.
}
@@ -680,7 +721,20 @@ public:
}
-void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
+bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
+ for (auto MapEntry : ImportedModuleFiles) {
+ auto *File = MapEntry.first;
+ ImportedModuleFileInfo &Info = MapEntry.second;
+ if (getModuleFileInfo(File).Signature) {
+ if (getModuleFileInfo(File).Signature != Info.StoredSignature)
+ // Verify Signature.
+ return true;
+ } else if (Info.StoredSize != File->getSize() ||
+ Info.StoredModTime != File->getModificationTime())
+ // Verify Size and ModTime.
+ return true;
+ }
+
using namespace llvm;
// Emit the file header.
@@ -756,6 +810,7 @@ void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
}
Stream.ExitBlock();
+ return false;
}
GlobalModuleIndex::ErrorCode
@@ -816,7 +871,8 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
SmallVector<char, 16> OutputBuffer;
{
llvm::BitstreamWriter OutputStream(OutputBuffer);
- Builder.writeIndex(OutputStream);
+ if (Builder.writeIndex(OutputStream))
+ return EC_IOError;
}
// Write the global index file to a temporary file.
diff --git a/contrib/llvm/tools/clang/lib/Serialization/Module.cpp b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp
index 72b0861..5a44d26 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/Module.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp
@@ -19,28 +19,6 @@ using namespace clang;
using namespace serialization;
using namespace reader;
-ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
- : Kind(Kind), File(nullptr), Signature(0), DirectlyImported(false),
- Generation(Generation), SizeInBits(0),
- LocalNumSLocEntries(0), SLocEntryBaseID(0),
- SLocEntryBaseOffset(0), SLocEntryOffsets(nullptr),
- LocalNumIdentifiers(0),
- IdentifierOffsets(nullptr), BaseIdentifierID(0),
- IdentifierTableData(nullptr), IdentifierLookupTable(nullptr),
- LocalNumMacros(0), MacroOffsets(nullptr),
- BasePreprocessedEntityID(0),
- PreprocessedEntityOffsets(nullptr), NumPreprocessedEntities(0),
- LocalNumHeaderFileInfos(0),
- HeaderFileInfoTableData(nullptr), HeaderFileInfoTable(nullptr),
- LocalNumSubmodules(0), BaseSubmoduleID(0),
- LocalNumSelectors(0), SelectorOffsets(nullptr), BaseSelectorID(0),
- SelectorLookupTableData(nullptr), SelectorLookupTable(nullptr),
- LocalNumDecls(0), DeclOffsets(nullptr), BaseDeclID(0),
- FileSortedDecls(nullptr), NumFileSortedDecls(0),
- ObjCCategoriesMap(nullptr), LocalNumObjCCategoriesInMap(0),
- LocalNumTypes(0), TypeOffsets(nullptr), BaseTypeIndex(0)
-{}
-
ModuleFile::~ModuleFile() {
delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable);
delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable);
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp
index 722b547..1dee4d0 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp
+++ b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ModuleManager.h"
+#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Frontend/PCHContainerOperations.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/ModuleMap.h"
@@ -27,7 +28,7 @@
using namespace clang;
using namespace serialization;
-ModuleFile *ModuleManager::lookup(StringRef Name) {
+ModuleFile *ModuleManager::lookup(StringRef Name) const {
const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
/*cacheFailure=*/false);
if (Entry)
@@ -36,9 +37,8 @@ ModuleFile *ModuleManager::lookup(StringRef Name) {
return nullptr;
}
-ModuleFile *ModuleManager::lookup(const FileEntry *File) {
- llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known
- = Modules.find(File);
+ModuleFile *ModuleManager::lookup(const FileEntry *File) const {
+ auto Known = Modules.find(File);
if (Known == Modules.end())
return nullptr;
@@ -52,6 +52,30 @@ ModuleManager::lookupBuffer(StringRef Name) {
return std::move(InMemoryBuffers[Entry]);
}
+static bool checkSignature(ASTFileSignature Signature,
+ ASTFileSignature ExpectedSignature,
+ std::string &ErrorStr) {
+ if (!ExpectedSignature || Signature == ExpectedSignature)
+ return false;
+
+ ErrorStr =
+ Signature ? "signature mismatch" : "could not read module signature";
+ return true;
+}
+
+static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy,
+ SourceLocation ImportLoc) {
+ if (ImportedBy) {
+ MF.ImportedBy.insert(ImportedBy);
+ ImportedBy->Imports.insert(&MF);
+ } else {
+ if (!MF.DirectlyImported)
+ MF.ImportLoc = ImportLoc;
+
+ MF.DirectlyImported = true;
+ }
+}
+
ModuleManager::AddModuleResult
ModuleManager::addModule(StringRef FileName, ModuleKind Type,
SourceLocation ImportLoc, ModuleFile *ImportedBy,
@@ -84,141 +108,133 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
}
// Check whether we already loaded this module, before
- ModuleFile *ModuleEntry = Modules[Entry];
- bool NewModule = false;
- if (!ModuleEntry) {
- // Allocate a new module.
- NewModule = true;
- ModuleEntry = new ModuleFile(Type, Generation);
- ModuleEntry->Index = Chain.size();
- ModuleEntry->FileName = FileName.str();
- ModuleEntry->File = Entry;
- ModuleEntry->ImportLoc = ImportLoc;
- ModuleEntry->InputFilesValidationTimestamp = 0;
-
- if (ModuleEntry->Kind == MK_ImplicitModule) {
- std::string TimestampFilename = ModuleEntry->getTimestampFilename();
- vfs::Status Status;
- // A cached stat value would be fine as well.
- if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
- ModuleEntry->InputFilesValidationTimestamp =
- llvm::sys::toTimeT(Status.getLastModificationTime());
- }
-
- // Load the contents of the module
- if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
- // The buffer was already provided for us.
- ModuleEntry->Buffer = std::move(Buffer);
- } else {
- // Open the AST file.
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf(
- (std::error_code()));
- if (FileName == "-") {
- Buf = llvm::MemoryBuffer::getSTDIN();
- } else {
- // Leave the FileEntry open so if it gets read again by another
- // ModuleManager it must be the same underlying file.
- // FIXME: Because FileManager::getFile() doesn't guarantee that it will
- // give us an open file, this may not be 100% reliable.
- Buf = FileMgr.getBufferForFile(ModuleEntry->File,
- /*IsVolatile=*/false,
- /*ShouldClose=*/false);
- }
-
- if (!Buf) {
- ErrorStr = Buf.getError().message();
- delete ModuleEntry;
- return Missing;
- }
-
- ModuleEntry->Buffer = std::move(*Buf);
- }
+ if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) {
+ // Check the stored signature.
+ if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
+ return OutOfDate;
- // Initialize the stream.
- ModuleEntry->Data = PCHContainerRdr.ExtractPCH(*ModuleEntry->Buffer);
+ Module = ModuleEntry;
+ updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
+ return AlreadyLoaded;
}
- if (ExpectedSignature) {
- // If we've not read the control block yet, read the signature eagerly now
- // so that we can check it.
- if (!ModuleEntry->Signature)
- ModuleEntry->Signature = ReadSignature(ModuleEntry->Data);
+ // Allocate a new module.
+ auto NewModule = llvm::make_unique<ModuleFile>(Type, Generation);
+ NewModule->Index = Chain.size();
+ NewModule->FileName = FileName.str();
+ NewModule->File = Entry;
+ NewModule->ImportLoc = ImportLoc;
+ NewModule->InputFilesValidationTimestamp = 0;
+
+ if (NewModule->Kind == MK_ImplicitModule) {
+ std::string TimestampFilename = NewModule->getTimestampFilename();
+ vfs::Status Status;
+ // A cached stat value would be fine as well.
+ if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
+ NewModule->InputFilesValidationTimestamp =
+ llvm::sys::toTimeT(Status.getLastModificationTime());
+ }
- if (ModuleEntry->Signature != ExpectedSignature) {
- ErrorStr = ModuleEntry->Signature ? "signature mismatch"
- : "could not read module signature";
+ // Load the contents of the module
+ if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
+ // The buffer was already provided for us.
+ NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(Buffer));
+ } else if (llvm::MemoryBuffer *Buffer = PCMCache->lookupBuffer(FileName)) {
+ NewModule->Buffer = Buffer;
+ } else {
+ // Open the AST file.
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code()));
+ if (FileName == "-") {
+ Buf = llvm::MemoryBuffer::getSTDIN();
+ } else {
+ // Leave the FileEntry open so if it gets read again by another
+ // ModuleManager it must be the same underlying file.
+ // FIXME: Because FileManager::getFile() doesn't guarantee that it will
+ // give us an open file, this may not be 100% reliable.
+ Buf = FileMgr.getBufferForFile(NewModule->File,
+ /*IsVolatile=*/false,
+ /*ShouldClose=*/false);
+ }
- if (NewModule)
- delete ModuleEntry;
- return OutOfDate;
+ if (!Buf) {
+ ErrorStr = Buf.getError().message();
+ return Missing;
}
- }
- if (ImportedBy) {
- ModuleEntry->ImportedBy.insert(ImportedBy);
- ImportedBy->Imports.insert(ModuleEntry);
- } else {
- if (!ModuleEntry->DirectlyImported)
- ModuleEntry->ImportLoc = ImportLoc;
-
- ModuleEntry->DirectlyImported = true;
+ NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(*Buf));
}
- Module = ModuleEntry;
+ // Initialize the stream.
+ NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
+
+ // Read the signature eagerly now so that we can check it. Avoid calling
+ // ReadSignature unless there's something to check though.
+ if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
+ ExpectedSignature, ErrorStr)) {
+ // Try to remove the buffer. If it can't be removed, then it was already
+ // validated by this process.
+ if (!PCMCache->tryToRemoveBuffer(NewModule->FileName))
+ FileMgr.invalidateCache(NewModule->File);
+ return OutOfDate;
+ }
- if (!NewModule)
- return AlreadyLoaded;
+ // We're keeping this module. Store it everywhere.
+ Module = Modules[Entry] = NewModule.get();
- assert(!Modules[Entry] && "module loaded twice");
- Modules[Entry] = ModuleEntry;
+ updateModuleImports(*NewModule, ImportedBy, ImportLoc);
- Chain.push_back(ModuleEntry);
- if (!ModuleEntry->isModule())
- PCHChain.push_back(ModuleEntry);
+ if (!NewModule->isModule())
+ PCHChain.push_back(NewModule.get());
if (!ImportedBy)
- Roots.push_back(ModuleEntry);
+ Roots.push_back(NewModule.get());
+ Chain.push_back(std::move(NewModule));
return NewlyLoaded;
}
void ModuleManager::removeModules(
- ModuleIterator first, ModuleIterator last,
+ ModuleIterator First,
llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
ModuleMap *modMap) {
- if (first == last)
+ auto Last = end();
+ if (First == Last)
return;
+
// Explicitly clear VisitOrder since we might not notice it is stale.
VisitOrder.clear();
// Collect the set of module file pointers that we'll be removing.
- llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
+ llvm::SmallPtrSet<ModuleFile *, 4> victimSet(
+ (llvm::pointer_iterator<ModuleIterator>(First)),
+ (llvm::pointer_iterator<ModuleIterator>(Last)));
auto IsVictim = [&](ModuleFile *MF) {
return victimSet.count(MF);
};
// Remove any references to the now-destroyed modules.
- for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
- Chain[i]->ImportedBy.remove_if(IsVictim);
+ for (auto I = begin(); I != First; ++I) {
+ I->Imports.remove_if(IsVictim);
+ I->ImportedBy.remove_if(IsVictim);
}
Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim),
Roots.end());
// Remove the modules from the PCH chain.
- for (auto I = first; I != last; ++I) {
- if (!(*I)->isModule()) {
- PCHChain.erase(std::find(PCHChain.begin(), PCHChain.end(), *I),
+ for (auto I = First; I != Last; ++I) {
+ if (!I->isModule()) {
+ PCHChain.erase(std::find(PCHChain.begin(), PCHChain.end(), &*I),
PCHChain.end());
break;
}
}
// Delete the modules and erase them from the various structures.
- for (ModuleIterator victim = first; victim != last; ++victim) {
- Modules.erase((*victim)->File);
+ for (ModuleIterator victim = First; victim != Last; ++victim) {
+ Modules.erase(victim->File);
if (modMap) {
- StringRef ModuleName = (*victim)->ModuleName;
+ StringRef ModuleName = victim->ModuleName;
if (Module *mod = modMap->findModule(ModuleName)) {
mod->setASTFile(nullptr);
}
@@ -227,14 +243,17 @@ void ModuleManager::removeModules(
// Files that didn't make it through ReadASTCore successfully will be
// rebuilt (or there was an error). Invalidate them so that we can load the
// new files that will be renamed over the old ones.
- if (LoadedSuccessfully.count(*victim) == 0)
- FileMgr.invalidateCache((*victim)->File);
-
- delete *victim;
+ //
+ // The PCMCache tracks whether the module was successfully loaded in another
+ // thread/context; in that case, it won't need to be rebuilt (and we can't
+ // safely invalidate it anyway).
+ if (LoadedSuccessfully.count(&*victim) == 0 &&
+ !PCMCache->tryToRemoveBuffer(victim->FileName))
+ FileMgr.invalidateCache(victim->File);
}
- // Remove the modules from the chain.
- Chain.erase(first, last);
+ // Delete the modules.
+ Chain.erase(Chain.begin() + (First - begin()), Chain.end());
}
void
@@ -274,11 +293,9 @@ void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
// Notify the global module index about all of the modules we've already
// loaded.
- for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- if (!GlobalIndex->loadedModuleFile(Chain[I])) {
- ModulesInCommonWithGlobalIndex.push_back(Chain[I]);
- }
- }
+ for (ModuleFile &M : *this)
+ if (!GlobalIndex->loadedModuleFile(&M))
+ ModulesInCommonWithGlobalIndex.push_back(&M);
}
void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
@@ -288,16 +305,12 @@ void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
ModulesInCommonWithGlobalIndex.push_back(MF);
}
-ModuleManager::ModuleManager(FileManager &FileMgr,
+ModuleManager::ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache,
const PCHContainerReader &PCHContainerRdr)
- : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr), GlobalIndex(),
- FirstVisitState(nullptr) {}
+ : FileMgr(FileMgr), PCMCache(&PCMCache), PCHContainerRdr(PCHContainerRdr),
+ GlobalIndex(), FirstVisitState(nullptr) {}
-ModuleManager::~ModuleManager() {
- for (unsigned i = 0, e = Chain.size(); i != e; ++i)
- delete Chain[e - i - 1];
- delete FirstVisitState;
-}
+ModuleManager::~ModuleManager() { delete FirstVisitState; }
void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
@@ -314,11 +327,11 @@ void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
Queue.reserve(N);
llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
UnusedIncomingEdges.resize(size());
- for (ModuleFile *M : llvm::reverse(*this)) {
- unsigned Size = M->ImportedBy.size();
- UnusedIncomingEdges[M->Index] = Size;
+ for (ModuleFile &M : llvm::reverse(*this)) {
+ unsigned Size = M.ImportedBy.size();
+ UnusedIncomingEdges[M.Index] = Size;
if (!Size)
- Queue.push_back(M);
+ Queue.push_back(&M);
}
// Traverse the graph, making sure to visit a module before visiting any
@@ -433,7 +446,7 @@ namespace llvm {
struct GraphTraits<ModuleManager> {
typedef ModuleFile *NodeRef;
typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType;
- typedef ModuleManager::ModuleConstIterator nodes_iterator;
+ typedef pointer_iterator<ModuleManager::ModuleConstIterator> nodes_iterator;
static ChildIteratorType child_begin(NodeRef Node) {
return Node->Imports.begin();
@@ -444,11 +457,11 @@ namespace llvm {
}
static nodes_iterator nodes_begin(const ModuleManager &Manager) {
- return Manager.begin();
+ return nodes_iterator(Manager.begin());
}
static nodes_iterator nodes_end(const ModuleManager &Manager) {
- return Manager.end();
+ return nodes_iterator(Manager.end());
}
};
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
index e6592a2..90d5c0e 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
@@ -24,16 +24,29 @@ using namespace ento;
namespace {
-class AnalysisOrderChecker : public Checker< check::PreStmt<CastExpr>,
- check::PostStmt<CastExpr>,
- check::PreStmt<ArraySubscriptExpr>,
- check::PostStmt<ArraySubscriptExpr>> {
- bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const {
- AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions();
+class AnalysisOrderChecker
+ : public Checker<check::PreStmt<CastExpr>,
+ check::PostStmt<CastExpr>,
+ check::PreStmt<ArraySubscriptExpr>,
+ check::PostStmt<ArraySubscriptExpr>,
+ check::Bind,
+ check::RegionChanges> {
+ bool isCallbackEnabled(AnalyzerOptions &Opts, StringRef CallbackName) const {
return Opts.getBooleanOption("*", false, this) ||
Opts.getBooleanOption(CallbackName, false, this);
}
+ bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const {
+ AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions();
+ return isCallbackEnabled(Opts, CallbackName);
+ }
+
+ bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const {
+ AnalyzerOptions &Opts = State->getStateManager().getOwningEngine()
+ ->getAnalysisManager().getAnalyzerOptions();
+ return isCallbackEnabled(Opts, CallbackName);
+ }
+
public:
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const {
if (isCallbackEnabled(C, "PreStmtCastExpr"))
@@ -47,17 +60,35 @@ public:
<< ")\n";
}
- void checkPreStmt(const ArraySubscriptExpr *SubExpr, CheckerContext &C) const {
+ void checkPreStmt(const ArraySubscriptExpr *SubExpr,
+ CheckerContext &C) const {
if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr"))
llvm::errs() << "PreStmt<ArraySubscriptExpr>\n";
}
- void checkPostStmt(const ArraySubscriptExpr *SubExpr, CheckerContext &C) const {
+ void checkPostStmt(const ArraySubscriptExpr *SubExpr,
+ CheckerContext &C) const {
if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr"))
llvm::errs() << "PostStmt<ArraySubscriptExpr>\n";
}
+
+ void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
+ if (isCallbackEnabled(C, "Bind"))
+ llvm::errs() << "Bind\n";
+ }
+
+ ProgramStateRef
+ checkRegionChanges(ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx, const CallEvent *Call) const {
+ if (isCallbackEnabled(State, "RegionChanges"))
+ llvm::errs() << "RegionChanges\n";
+ return State;
+ }
};
-}
+} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Registration.
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 1ea85d6..3711877 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -233,19 +233,16 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (StringSelectors.empty()) {
ASTContext &Ctx = C.getASTContext();
Selector Sels[] = {
- getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
- getKeywordSelector(Ctx, "compare", nullptr),
- getKeywordSelector(Ctx, "compare", "options", nullptr),
- getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
- getKeywordSelector(Ctx, "compare", "options", "range", "locale",
- nullptr),
- getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
- nullptr),
- getKeywordSelector(Ctx, "initWithFormat",
- nullptr),
- getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
- getKeywordSelector(Ctx, "localizedCompare", nullptr),
- getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
+ getKeywordSelector(Ctx, "caseInsensitiveCompare"),
+ getKeywordSelector(Ctx, "compare"),
+ getKeywordSelector(Ctx, "compare", "options"),
+ getKeywordSelector(Ctx, "compare", "options", "range"),
+ getKeywordSelector(Ctx, "compare", "options", "range", "locale"),
+ getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet"),
+ getKeywordSelector(Ctx, "initWithFormat"),
+ getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare"),
+ getKeywordSelector(Ctx, "localizedCompare"),
+ getKeywordSelector(Ctx, "localizedStandardCompare"),
};
for (Selector KnownSel : Sels)
StringSelectors[KnownSel] = 0;
@@ -262,16 +259,15 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (ArrayWithObjectSel.isNull()) {
ASTContext &Ctx = C.getASTContext();
- ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
- AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
+ ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject");
+ AddObjectSel = getKeywordSelector(Ctx, "addObject");
InsertObjectAtIndexSel =
- getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
+ getKeywordSelector(Ctx, "insertObject", "atIndex");
ReplaceObjectAtIndexWithObjectSel =
- getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
+ getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject");
SetObjectAtIndexedSubscriptSel =
- getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
- ArrayByAddingObjectSel =
- getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
+ getKeywordSelector(Ctx, "setObject", "atIndexedSubscript");
+ ArrayByAddingObjectSel = getKeywordSelector(Ctx, "arrayByAddingObject");
}
if (S == ArrayWithObjectSel || S == AddObjectSel ||
@@ -292,13 +288,11 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (DictionaryWithObjectForKeySel.isNull()) {
ASTContext &Ctx = C.getASTContext();
DictionaryWithObjectForKeySel =
- getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
- SetObjectForKeySel =
- getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
+ getKeywordSelector(Ctx, "dictionaryWithObject", "forKey");
+ SetObjectForKeySel = getKeywordSelector(Ctx, "setObject", "forKey");
SetObjectForKeyedSubscriptSel =
- getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
- RemoveObjectForKeySel =
- getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
+ getKeywordSelector(Ctx, "setObject", "forKeyedSubscript");
+ RemoveObjectForKeySel = getKeywordSelector(Ctx, "removeObjectForKey");
}
if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index 082a487..d19630e 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -29,7 +29,9 @@ namespace {
class BlockInCriticalSectionChecker : public Checker<check::PostCall,
check::PreCall> {
- CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn;
+ CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn,
+ PthreadLockFn, PthreadTryLockFn, PthreadUnlockFn,
+ MtxLock, MtxTimedLock, MtxTryLock, MtxUnlock;
std::unique_ptr<BugType> BlockInCritSectionBugType;
@@ -40,6 +42,10 @@ class BlockInCriticalSectionChecker : public Checker<check::PostCall,
public:
BlockInCriticalSectionChecker();
+ bool isBlockingFunction(const CallEvent &Call) const;
+ bool isLockFunction(const CallEvent &Call) const;
+ bool isUnlockFunction(const CallEvent &Call) const;
+
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
/// Process unlock.
@@ -55,34 +61,69 @@ REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
: LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
- FgetsFn("fgets"), ReadFn("read"), RecvFn("recv") {
+ FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"),
+ PthreadLockFn("pthread_mutex_lock"),
+ PthreadTryLockFn("pthread_mutex_trylock"),
+ PthreadUnlockFn("pthread_mutex_unlock"),
+ MtxLock("mtx_lock"),
+ MtxTimedLock("mtx_timedlock"),
+ MtxTryLock("mtx_trylock"),
+ MtxUnlock("mtx_unlock") {
// Initialize the bug type.
BlockInCritSectionBugType.reset(
new BugType(this, "Call to blocking function in critical section",
"Blocking Error"));
}
+bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) const {
+ if (Call.isCalled(SleepFn)
+ || Call.isCalled(GetcFn)
+ || Call.isCalled(FgetsFn)
+ || Call.isCalled(ReadFn)
+ || Call.isCalled(RecvFn)) {
+ return true;
+ }
+ return false;
+}
+
+bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const {
+ if (Call.isCalled(LockFn)
+ || Call.isCalled(PthreadLockFn)
+ || Call.isCalled(PthreadTryLockFn)
+ || Call.isCalled(MtxLock)
+ || Call.isCalled(MtxTimedLock)
+ || Call.isCalled(MtxTryLock)) {
+ return true;
+ }
+ return false;
+}
+
+bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) const {
+ if (Call.isCalled(UnlockFn)
+ || Call.isCalled(PthreadUnlockFn)
+ || Call.isCalled(MtxUnlock)) {
+ return true;
+ }
+ return false;
+}
+
void BlockInCriticalSectionChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
}
void BlockInCriticalSectionChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
- if (!Call.isCalled(LockFn)
- && !Call.isCalled(SleepFn)
- && !Call.isCalled(GetcFn)
- && !Call.isCalled(FgetsFn)
- && !Call.isCalled(ReadFn)
- && !Call.isCalled(RecvFn)
- && !Call.isCalled(UnlockFn))
+ if (!isBlockingFunction(Call)
+ && !isLockFunction(Call)
+ && !isUnlockFunction(Call))
return;
ProgramStateRef State = C.getState();
unsigned mutexCount = State->get<MutexCounter>();
- if (Call.isCalled(UnlockFn) && mutexCount > 0) {
+ if (isUnlockFunction(Call) && mutexCount > 0) {
State = State->set<MutexCounter>(--mutexCount);
C.addTransition(State);
- } else if (Call.isCalled(LockFn)) {
+ } else if (isLockFunction(Call)) {
State = State->set<MutexCounter>(++mutexCount);
C.addTransition(State);
} else if (mutexCount > 0) {
@@ -97,8 +138,11 @@ void BlockInCriticalSectionChecker::reportBlockInCritSection(
if (!ErrNode)
return;
- auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType,
- "A blocking function %s is called inside a critical section.", ErrNode);
+ std::string msg;
+ llvm::raw_string_ostream os(msg);
+ os << "Call to blocking function '" << Call.getCalleeIdentifier()->getName()
+ << "' inside of critical section";
+ auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType, os.str(), ErrNode);
R->addRange(Call.getSourceRange());
R->markInteresting(BlockDescSym);
C.emitReport(std::move(R));
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 8c2aef2..097d419 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -41,6 +41,24 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
default:
return false;
+ case Builtin::BI__builtin_assume: {
+ assert (CE->arg_begin() != CE->arg_end());
+ SVal ArgSVal = state->getSVal(CE->getArg(0), LCtx);
+ if (ArgSVal.isUndef())
+ return true; // Return true to model purity.
+
+ state = state->assume(ArgSVal.castAs<DefinedOrUnknownSVal>(), true);
+ // FIXME: do we want to warn here? Not right now. The most reports might
+ // come from infeasible paths, thus being false positives.
+ if (!state) {
+ C.generateSink(C.getState(), C.getPredecessor());
+ return true;
+ }
+
+ C.addTransition(state);
+ return true;
+ }
+
case Builtin::BI__builtin_unpredictable:
case Builtin::BI__builtin_expect:
case Builtin::BI__builtin_assume_aligned:
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 238032c..77c2462 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -68,6 +68,7 @@ public:
const InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) const;
typedef void (CStringChecker::*FnCheck)(CheckerContext &,
@@ -119,6 +120,7 @@ public:
void evalStdCopy(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemset(CheckerContext &C, const CallExpr *CE) const;
// Utility methods
std::pair<ProgramStateRef , ProgramStateRef >
@@ -1943,8 +1945,12 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
// Overwrite the search string pointer. The new value is either an address
// further along in the same string, or NULL if there are no more tokens.
State = State->bindLoc(*SearchStrLoc,
- SVB.conjureSymbolVal(getTag(), CE, LCtx, CharPtrTy,
- C.blockCount()));
+ SVB.conjureSymbolVal(getTag(),
+ CE,
+ LCtx,
+ CharPtrTy,
+ C.blockCount()),
+ LCtx);
} else {
assert(SearchStrVal.isUnknown());
// Conjure a symbolic value. It's the best we can do.
@@ -1994,6 +2000,54 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
C.addTransition(State);
}
+void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() != 3)
+ return;
+
+ CurrentFunctionDescription = "memory set function";
+
+ const Expr *Mem = CE->getArg(0);
+ const Expr *Size = CE->getArg(2);
+ ProgramStateRef State = C.getState();
+
+ // See if the size argument is zero.
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal SizeVal = State->getSVal(Size, LCtx);
+ QualType SizeTy = Size->getType();
+
+ ProgramStateRef StateZeroSize, StateNonZeroSize;
+ std::tie(StateZeroSize, StateNonZeroSize) =
+ assumeZero(C, State, SizeVal, SizeTy);
+
+ // Get the value of the memory area.
+ SVal MemVal = State->getSVal(Mem, LCtx);
+
+ // If the size is zero, there won't be any actual memory access, so
+ // just bind the return value to the Mem buffer and return.
+ if (StateZeroSize && !StateNonZeroSize) {
+ StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal);
+ C.addTransition(StateZeroSize);
+ return;
+ }
+
+ // Ensure the memory area is not null.
+ // If it is NULL there will be a NULL pointer dereference.
+ State = checkNonNull(C, StateNonZeroSize, Mem, MemVal);
+ if (!State)
+ return;
+
+ State = CheckBufferAccess(C, State, Size, Mem);
+ if (!State)
+ return;
+ State = InvalidateBuffer(C, State, Mem, C.getSVal(Mem),
+ /*IsSourceBuffer*/false, Size);
+ if (!State)
+ return;
+
+ State = State->BindExpr(CE, LCtx, MemVal);
+ C.addTransition(State);
+}
+
static bool isCPPStdLibraryFunction(const FunctionDecl *FD, StringRef Name) {
IdentifierInfo *II = FD->getIdentifier();
if (!II)
@@ -2027,6 +2081,8 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
evalFunction = &CStringChecker::evalMemcmp;
else if (C.isCLibraryFunction(FDecl, "memmove"))
evalFunction = &CStringChecker::evalMemmove;
+ else if (C.isCLibraryFunction(FDecl, "memset"))
+ evalFunction = &CStringChecker::evalMemset;
else if (C.isCLibraryFunction(FDecl, "strcpy"))
evalFunction = &CStringChecker::evalStrcpy;
else if (C.isCLibraryFunction(FDecl, "strncpy"))
@@ -2116,6 +2172,7 @@ CStringChecker::checkRegionChanges(ProgramStateRef state,
const InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) const {
CStringLengthTy Entries = state->get<CStringLength>();
if (Entries.isEmpty())
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index 3db1994..391b843 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -36,25 +36,24 @@ class WalkAST: public StmtVisitor<WalkAST> {
AnalysisDeclContext* AC;
/// Check if two expressions refer to the same declaration.
- inline bool sameDecl(const Expr *A1, const Expr *A2) {
- if (const DeclRefExpr *D1 = dyn_cast<DeclRefExpr>(A1->IgnoreParenCasts()))
- if (const DeclRefExpr *D2 = dyn_cast<DeclRefExpr>(A2->IgnoreParenCasts()))
+ bool sameDecl(const Expr *A1, const Expr *A2) {
+ if (const auto *D1 = dyn_cast<DeclRefExpr>(A1->IgnoreParenCasts()))
+ if (const auto *D2 = dyn_cast<DeclRefExpr>(A2->IgnoreParenCasts()))
return D1->getDecl() == D2->getDecl();
return false;
}
/// Check if the expression E is a sizeof(WithArg).
- inline bool isSizeof(const Expr *E, const Expr *WithArg) {
- if (const UnaryExprOrTypeTraitExpr *UE =
- dyn_cast<UnaryExprOrTypeTraitExpr>(E))
- if (UE->getKind() == UETT_SizeOf)
+ bool isSizeof(const Expr *E, const Expr *WithArg) {
+ if (const auto *UE = dyn_cast<UnaryExprOrTypeTraitExpr>(E))
+ if (UE->getKind() == UETT_SizeOf && !UE->isArgumentType())
return sameDecl(UE->getArgumentExpr(), WithArg);
return false;
}
/// Check if the expression E is a strlen(WithArg).
- inline bool isStrlen(const Expr *E, const Expr *WithArg) {
- if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ bool isStrlen(const Expr *E, const Expr *WithArg) {
+ if (const auto *CE = dyn_cast<CallExpr>(E)) {
const FunctionDecl *FD = CE->getDirectCallee();
if (!FD)
return false;
@@ -65,14 +64,14 @@ class WalkAST: public StmtVisitor<WalkAST> {
}
/// Check if the expression is an integer literal with value 1.
- inline bool isOne(const Expr *E) {
- if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
+ bool isOne(const Expr *E) {
+ if (const auto *IL = dyn_cast<IntegerLiteral>(E))
return (IL->getValue().isIntN(1));
return false;
}
- inline StringRef getPrintableName(const Expr *E) {
- if (const DeclRefExpr *D = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+ StringRef getPrintableName(const Expr *E) {
+ if (const auto *D = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
return D->getDecl()->getName();
return StringRef();
}
@@ -82,8 +81,8 @@ class WalkAST: public StmtVisitor<WalkAST> {
bool containsBadStrncatPattern(const CallExpr *CE);
public:
- WalkAST(const CheckerBase *checker, BugReporter &br, AnalysisDeclContext *ac)
- : Checker(checker), BR(br), AC(ac) {}
+ WalkAST(const CheckerBase *Checker, BugReporter &BR, AnalysisDeclContext *AC)
+ : Checker(Checker), BR(BR), AC(AC) {}
// Statement visitor methods.
void VisitChildren(Stmt *S);
@@ -108,8 +107,7 @@ bool WalkAST::containsBadStrncatPattern(const CallExpr *CE) {
const Expr *LenArg = CE->getArg(2);
// Identify wrong size expressions, which are commonly used instead.
- if (const BinaryOperator *BE =
- dyn_cast<BinaryOperator>(LenArg->IgnoreParenCasts())) {
+ if (const auto *BE = dyn_cast<BinaryOperator>(LenArg->IgnoreParenCasts())) {
// - sizeof(dst) - strlen(dst)
if (BE->getOpcode() == BO_Sub) {
const Expr *L = BE->getLHS();
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp
index 7631322..668e772 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp
@@ -51,9 +51,9 @@ void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const {
State->getSVal(SVB.getCXXThis(MD, LCtx->getCurrentStackFrame()));
auto Param = SVB.makeLoc(State->getRegion(MD->getParamDecl(0), LCtx));
auto ParamVal = State->getSVal(Param);
- ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal);
+ ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, LCtx);
C.addTransition(SelfAssignState);
- ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal);
+ ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, LCtx);
C.addTransition(NonSelfAssignState);
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index f474857..07285d2 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -71,7 +72,7 @@ public:
private:
bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
- const Expr *ArgEx, bool IsFirstArgument,
+ const Expr *ArgEx, int ArgumentNumber,
bool CheckUninitFields, const CallEvent &Call,
std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl) const;
@@ -89,9 +90,10 @@ private:
BT.reset(new BuiltinBug(this, desc));
}
bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
- SourceRange ArgRange,
- const Expr *ArgEx, std::unique_ptr<BugType> &BT,
- const ParmVarDecl *ParamDecl, const char *BD) const;
+ SourceRange ArgRange, const Expr *ArgEx,
+ std::unique_ptr<BugType> &BT,
+ const ParmVarDecl *ParamDecl, const char *BD,
+ int ArgumentNumber) const;
};
} // end anonymous namespace
@@ -111,38 +113,45 @@ void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
C.emitReport(std::move(R));
}
-static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
- bool IsFirstArgument) {
+static void describeUninitializedArgumentInCall(const CallEvent &Call,
+ int ArgumentNumber,
+ llvm::raw_svector_ostream &Os) {
switch (Call.getKind()) {
case CE_ObjCMessage: {
const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
switch (Msg.getMessageKind()) {
case OCM_Message:
- return "Argument in message expression is an uninitialized value";
+ Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
+ << " argument in message expression is an uninitialized value";
+ return;
case OCM_PropertyAccess:
assert(Msg.isSetter() && "Getters have no args");
- return "Argument for property setter is an uninitialized value";
+ Os << "Argument for property setter is an uninitialized value";
+ return;
case OCM_Subscript:
- if (Msg.isSetter() && IsFirstArgument)
- return "Argument for subscript setter is an uninitialized value";
- return "Subscript index is an uninitialized value";
+ if (Msg.isSetter() && (ArgumentNumber == 0))
+ Os << "Argument for subscript setter is an uninitialized value";
+ else
+ Os << "Subscript index is an uninitialized value";
+ return;
}
llvm_unreachable("Unknown message kind.");
}
case CE_Block:
- return "Block call argument is an uninitialized value";
+ Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
+ << " block call argument is an uninitialized value";
+ return;
default:
- return "Function call argument is an uninitialized value";
+ Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
+ << " function call argument is an uninitialized value";
+ return;
}
}
-bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
- const SVal &V,
- SourceRange ArgRange,
- const Expr *ArgEx,
- std::unique_ptr<BugType> &BT,
- const ParmVarDecl *ParamDecl,
- const char *BD) const {
+bool CallAndMessageChecker::uninitRefOrPointer(
+ CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
+ std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
+ int ArgumentNumber) const {
if (!Filter.Check_CallAndMessageUnInitRefArg)
return false;
@@ -153,12 +162,15 @@ bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
// If parameter is declared as pointer to const in function declaration,
// then check if corresponding argument in function call is
// pointing to undefined symbol value (uninitialized memory).
- StringRef Message;
+ SmallString<200> Buf;
+ llvm::raw_svector_ostream Os(Buf);
if (ParamDecl->getType()->isPointerType()) {
- Message = "Function call argument is a pointer to uninitialized value";
+ Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
+ << " function call argument is a pointer to uninitialized value";
} else if (ParamDecl->getType()->isReferenceType()) {
- Message = "Function call argument is an uninitialized value";
+ Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
+ << " function call argument is an uninitialized value";
} else
return false;
@@ -171,7 +183,7 @@ bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
if (PSV.isUndef()) {
if (ExplodedNode *N = C.generateErrorNode()) {
LazyInit_BT(BD, BT);
- auto R = llvm::make_unique<BugReport>(*BT, Message, N);
+ auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
R->addRange(ArgRange);
if (ArgEx) {
bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
@@ -188,7 +200,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
SVal V,
SourceRange ArgRange,
const Expr *ArgEx,
- bool IsFirstArgument,
+ int ArgumentNumber,
bool CheckUninitFields,
const CallEvent &Call,
std::unique_ptr<BugType> &BT,
@@ -196,17 +208,19 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
) const {
const char *BD = "Uninitialized argument value";
- if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
+ if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
+ ArgumentNumber))
return true;
if (V.isUndef()) {
if (ExplodedNode *N = C.generateErrorNode()) {
LazyInit_BT(BD, BT);
-
// Generate a report for this bug.
- StringRef Desc =
- describeUninitializedArgumentInCall(Call, IsFirstArgument);
- auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
+ SmallString<200> Buf;
+ llvm::raw_svector_ostream Os(Buf);
+ describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
+ auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
+
R->addRange(ArgRange);
if (ArgEx)
bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
@@ -435,7 +449,7 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
if(FD && i < FD->getNumParams())
ParamDecl = FD->getParamDecl(i);
if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
- Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
+ Call.getArgExpr(i), i,
checkUninitFields, Call, *BT, ParamDecl))
return;
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 16a475a..65e8131 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -84,6 +84,10 @@ bool CastToStructVisitor::VisitCastExpr(const CastExpr *CE) {
if (!VD || VD->getType()->isReferenceType())
return true;
+ if (ToPointeeTy->isIncompleteType() ||
+ OrigPointeeTy->isIncompleteType())
+ return true;
+
// Warn when there is widening cast.
unsigned ToWidth = Ctx.getTypeInfo(ToPointeeTy).Width;
unsigned OrigWidth = Ctx.getTypeInfo(OrigPointeeTy).Width;
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
index 86764c9..95b6c4d 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
@@ -231,14 +231,6 @@ public:
/// check::LiveSymbols
void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const {}
- /// \brief Called to determine if the checker currently needs to know if when
- /// contents of any regions change.
- ///
- /// Since it is not necessarily cheap to compute which regions are being
- /// changed, this allows the analyzer core to skip the more expensive
- /// #checkRegionChanges when no checkers are tracking any state.
- bool wantsRegionChangeUpdate(ProgramStateRef St) const { return true; }
-
/// \brief Called when the contents of one or more regions change.
///
/// This can occur in many different ways: an explicit bind, a blanket
@@ -255,18 +247,18 @@ public:
/// by this change. For a simple bind, this list will be the same as
/// \p ExplicitRegions, since a bind does not affect the contents of
/// anything accessible through the base region.
+ /// \param LCtx LocationContext that is useful for getting various contextual
+ /// info, like callstack, CFG etc.
/// \param Call The opaque call triggering this invalidation. Will be 0 if the
/// change was not triggered by a call.
///
- /// Note that this callback will not be invoked unless
- /// #wantsRegionChangeUpdate returns \c true.
- ///
/// check::RegionChanges
ProgramStateRef
checkRegionChanges(ProgramStateRef State,
const InvalidatedSymbols *Invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) const {
return State;
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
index 6fa5732..83955c58 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
@@ -38,14 +38,15 @@ public:
void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
AnalysisManager &Mgr, BugReporter &BR) const;
- /// \brief Reports all clones to the user.
+ /// Reports all clones to the user.
void reportClones(BugReporter &BR, AnalysisManager &Mgr,
- int MinComplexity) const;
+ std::vector<CloneDetector::CloneGroup> &CloneGroups) const;
- /// \brief Reports only suspicious clones to the user along with informaton
- /// that explain why they are suspicious.
- void reportSuspiciousClones(BugReporter &BR, AnalysisManager &Mgr,
- int MinComplexity) const;
+ /// Reports only suspicious clones to the user along with informaton
+ /// that explain why they are suspicious.
+ void reportSuspiciousClones(
+ BugReporter &BR, AnalysisManager &Mgr,
+ std::vector<CloneDetector::CloneGroup> &CloneGroups) const;
};
} // end anonymous namespace
@@ -72,11 +73,35 @@ void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
bool ReportNormalClones = Mgr.getAnalyzerOptions().getBooleanOption(
"ReportNormalClones", true, this);
+ StringRef IgnoredFilesPattern = Mgr.getAnalyzerOptions().getOptionAsString(
+ "IgnoredFilesPattern", "", this);
+
+ // Let the CloneDetector create a list of clones from all the analyzed
+ // statements. We don't filter for matching variable patterns at this point
+ // because reportSuspiciousClones() wants to search them for errors.
+ std::vector<CloneDetector::CloneGroup> AllCloneGroups;
+
+ Detector.findClones(AllCloneGroups,
+ FilenamePatternConstraint(IgnoredFilesPattern),
+ RecursiveCloneTypeIIConstraint(),
+ MinComplexityConstraint(MinComplexity),
+ MinGroupSizeConstraint(2), OnlyLargestCloneConstraint());
+
if (ReportSuspiciousClones)
- reportSuspiciousClones(BR, Mgr, MinComplexity);
+ reportSuspiciousClones(BR, Mgr, AllCloneGroups);
+
+ // We are done for this translation unit unless we also need to report normal
+ // clones.
+ if (!ReportNormalClones)
+ return;
+
+ // Now that the suspicious clone detector has checked for pattern errors,
+ // we also filter all clones who don't have matching patterns
+ CloneDetector::constrainClones(AllCloneGroups,
+ MatchingVariablePatternConstraint(),
+ MinGroupSizeConstraint(2));
- if (ReportNormalClones)
- reportClones(BR, Mgr, MinComplexity);
+ reportClones(BR, Mgr, AllCloneGroups);
}
static PathDiagnosticLocation makeLocation(const StmtSequence &S,
@@ -87,37 +112,55 @@ static PathDiagnosticLocation makeLocation(const StmtSequence &S,
Mgr.getAnalysisDeclContext(ACtx.getTranslationUnitDecl()));
}
-void CloneChecker::reportClones(BugReporter &BR, AnalysisManager &Mgr,
- int MinComplexity) const {
-
- std::vector<CloneDetector::CloneGroup> CloneGroups;
- Detector.findClones(CloneGroups, MinComplexity);
+void CloneChecker::reportClones(
+ BugReporter &BR, AnalysisManager &Mgr,
+ std::vector<CloneDetector::CloneGroup> &CloneGroups) const {
if (!BT_Exact)
BT_Exact.reset(new BugType(this, "Exact code clone", "Code clone"));
- for (CloneDetector::CloneGroup &Group : CloneGroups) {
+ for (const CloneDetector::CloneGroup &Group : CloneGroups) {
// We group the clones by printing the first as a warning and all others
// as a note.
- auto R = llvm::make_unique<BugReport>(
- *BT_Exact, "Duplicate code detected",
- makeLocation(Group.Sequences.front(), Mgr));
- R->addRange(Group.Sequences.front().getSourceRange());
-
- for (unsigned i = 1; i < Group.Sequences.size(); ++i)
- R->addNote("Similar code here",
- makeLocation(Group.Sequences[i], Mgr),
- Group.Sequences[i].getSourceRange());
+ auto R = llvm::make_unique<BugReport>(*BT_Exact, "Duplicate code detected",
+ makeLocation(Group.front(), Mgr));
+ R->addRange(Group.front().getSourceRange());
+
+ for (unsigned i = 1; i < Group.size(); ++i)
+ R->addNote("Similar code here", makeLocation(Group[i], Mgr),
+ Group[i].getSourceRange());
BR.emitReport(std::move(R));
}
}
-void CloneChecker::reportSuspiciousClones(BugReporter &BR,
- AnalysisManager &Mgr,
- int MinComplexity) const {
-
- std::vector<CloneDetector::SuspiciousClonePair> Clones;
- Detector.findSuspiciousClones(Clones, MinComplexity);
+void CloneChecker::reportSuspiciousClones(
+ BugReporter &BR, AnalysisManager &Mgr,
+ std::vector<CloneDetector::CloneGroup> &CloneGroups) const {
+ std::vector<VariablePattern::SuspiciousClonePair> Pairs;
+
+ for (const CloneDetector::CloneGroup &Group : CloneGroups) {
+ for (unsigned i = 0; i < Group.size(); ++i) {
+ VariablePattern PatternA(Group[i]);
+
+ for (unsigned j = i + 1; j < Group.size(); ++j) {
+ VariablePattern PatternB(Group[j]);
+
+ VariablePattern::SuspiciousClonePair ClonePair;
+ // For now, we only report clones which break the variable pattern just
+ // once because multiple differences in a pattern are an indicator that
+ // those differences are maybe intended (e.g. because it's actually a
+ // different algorithm).
+ // FIXME: In very big clones even multiple variables can be unintended,
+ // so replacing this number with a percentage could better handle such
+ // cases. On the other hand it could increase the false-positive rate
+ // for all clones if the percentage is too high.
+ if (PatternA.countPatternDifferences(PatternB, &ClonePair) == 1) {
+ Pairs.push_back(ClonePair);
+ break;
+ }
+ }
+ }
+ }
if (!BT_Suspicious)
BT_Suspicious.reset(
@@ -128,7 +171,7 @@ void CloneChecker::reportSuspiciousClones(BugReporter &BR,
AnalysisDeclContext *ADC =
Mgr.getAnalysisDeclContext(ACtx.getTranslationUnitDecl());
- for (CloneDetector::SuspiciousClonePair &Pair : Clones) {
+ for (VariablePattern::SuspiciousClonePair &Pair : Pairs) {
// FIXME: We are ignoring the suggestions currently, because they are
// only 50% accurate (even if the second suggestion is unavailable),
// which may confuse the user.
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
index 2bb9e85..ea894c8 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
@@ -41,7 +41,8 @@ private:
mutable std::unique_ptr<BuiltinBug> BT;
// Is there loss of precision
- bool isLossOfPrecision(const ImplicitCastExpr *Cast, CheckerContext &C) const;
+ bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType,
+ CheckerContext &C) const;
// Is there loss of sign
bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const;
@@ -73,16 +74,30 @@ void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
// Loss of sign/precision in binary operation.
if (const auto *B = dyn_cast<BinaryOperator>(Parent)) {
BinaryOperator::Opcode Opc = B->getOpcode();
- if (Opc == BO_Assign || Opc == BO_AddAssign || Opc == BO_SubAssign ||
- Opc == BO_MulAssign) {
+ if (Opc == BO_Assign) {
LossOfSign = isLossOfSign(Cast, C);
- LossOfPrecision = isLossOfPrecision(Cast, C);
+ LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
+ } else if (Opc == BO_AddAssign || Opc == BO_SubAssign) {
+ // No loss of sign.
+ LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
+ } else if (Opc == BO_MulAssign) {
+ LossOfSign = isLossOfSign(Cast, C);
+ LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
+ } else if (Opc == BO_DivAssign || Opc == BO_RemAssign) {
+ LossOfSign = isLossOfSign(Cast, C);
+ // No loss of precision.
+ } else if (Opc == BO_AndAssign) {
+ LossOfSign = isLossOfSign(Cast, C);
+ // No loss of precision.
+ } else if (Opc == BO_OrAssign || Opc == BO_XorAssign) {
+ LossOfSign = isLossOfSign(Cast, C);
+ LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->getType(), C);
} else if (B->isRelationalOp() || B->isMultiplicativeOp()) {
LossOfSign = isLossOfSign(Cast, C);
}
} else if (isa<DeclStmt>(Parent)) {
LossOfSign = isLossOfSign(Cast, C);
- LossOfPrecision = isLossOfPrecision(Cast, C);
+ LossOfPrecision = isLossOfPrecision(Cast, Cast->getType(), C);
}
if (LossOfSign || LossOfPrecision) {
@@ -113,6 +128,13 @@ static bool isGreaterEqual(CheckerContext &C, const Expr *E,
unsigned long long Val) {
ProgramStateRef State = C.getState();
SVal EVal = C.getSVal(E);
+ if (EVal.isUnknownOrUndef())
+ return false;
+ if (!EVal.getAs<NonLoc>() && EVal.getAs<Loc>()) {
+ ProgramStateManager &Mgr = C.getStateManager();
+ EVal =
+ Mgr.getStoreManager().getBinding(State->getStore(), EVal.castAs<Loc>());
+ }
if (EVal.isUnknownOrUndef() || !EVal.getAs<NonLoc>())
return false;
@@ -153,22 +175,22 @@ static bool isNegative(CheckerContext &C, const Expr *E) {
}
bool ConversionChecker::isLossOfPrecision(const ImplicitCastExpr *Cast,
- CheckerContext &C) const {
+ QualType DestType,
+ CheckerContext &C) const {
// Don't warn about explicit loss of precision.
if (Cast->isEvaluatable(C.getASTContext()))
return false;
- QualType CastType = Cast->getType();
QualType SubType = Cast->IgnoreParenImpCasts()->getType();
- if (!CastType->isIntegerType() || !SubType->isIntegerType())
+ if (!DestType->isIntegerType() || !SubType->isIntegerType())
return false;
- if (C.getASTContext().getIntWidth(CastType) >=
+ if (C.getASTContext().getIntWidth(DestType) >=
C.getASTContext().getIntWidth(SubType))
return false;
- unsigned W = C.getASTContext().getIntWidth(CastType);
+ unsigned W = C.getASTContext().getIntWidth(DestType);
if (W == 1 || W >= 64U)
return false;
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 8ca2a24..f7b5f61 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -189,6 +189,7 @@ public:
case DeadIncrement:
BugType = "Dead increment";
+ LLVM_FALLTHROUGH;
case Standard:
if (!BugType) BugType = "Dead assignment";
os << "Value stored to '" << *V << "' is never read";
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 2d5cb60..32040e7 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ScopedPrinter.h"
using namespace clang;
using namespace ento;
@@ -71,8 +72,8 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE,
&ExprInspectionChecker::analyzerWarnIfReached)
.Case("clang_analyzer_warnOnDeadSymbol",
&ExprInspectionChecker::analyzerWarnOnDeadSymbol)
- .Case("clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain)
- .Case("clang_analyzer_dump", &ExprInspectionChecker::analyzerDump)
+ .StartsWith("clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain)
+ .StartsWith("clang_analyzer_dump", &ExprInspectionChecker::analyzerDump)
.Case("clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent)
.Case("clang_analyzer_printState",
&ExprInspectionChecker::analyzerPrintState)
@@ -269,7 +270,7 @@ void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
unsigned NumTimesReached = Item.second.NumTimesReached;
ExplodedNode *N = Item.second.ExampleNode;
- reportBug(std::to_string(NumTimesReached), BR, N);
+ reportBug(llvm::to_string(NumTimesReached), BR, N);
}
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index 8c8acc6..883c6a6 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -65,9 +65,8 @@ private:
/// and thus, is tainted.
static bool isStdin(const Expr *E, CheckerContext &C);
- /// \brief Given a pointer argument, get the symbol of the value it contains
- /// (points to).
- static SymbolRef getPointedToSymbol(CheckerContext &C, const Expr *Arg);
+ /// \brief Given a pointer argument, return the value it points to.
+ static Optional<SVal> getPointedToSVal(CheckerContext &C, const Expr *Arg);
/// Functions defining the attack surface.
typedef ProgramStateRef (GenericTaintChecker::*FnCheck)(const CallExpr *,
@@ -101,6 +100,22 @@ private:
bool generateReportIfTainted(const Expr *E, const char Msg[],
CheckerContext &C) const;
+ /// The bug visitor prints a diagnostic message at the location where a given
+ /// variable was tainted.
+ class TaintBugVisitor
+ : public BugReporterVisitorImpl<TaintBugVisitor> {
+ private:
+ const SVal V;
+
+ public:
+ TaintBugVisitor(const SVal V) : V(V) {}
+ void Profile(llvm::FoldingSetNodeID &ID) const override { ID.Add(V); }
+
+ std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
+ };
typedef SmallVector<unsigned, 2> ArgVector;
@@ -158,9 +173,14 @@ private:
static inline bool isTaintedOrPointsToTainted(const Expr *E,
ProgramStateRef State,
CheckerContext &C) {
- return (State->isTainted(E, C.getLocationContext()) || isStdin(E, C) ||
- (E->getType().getTypePtr()->isPointerType() &&
- State->isTainted(getPointedToSymbol(C, E))));
+ if (State->isTainted(E, C.getLocationContext()) || isStdin(E, C))
+ return true;
+
+ if (!E->getType().getTypePtr()->isPointerType())
+ return false;
+
+ Optional<SVal> V = getPointedToSVal(C, E);
+ return (V && State->isTainted(*V));
}
/// \brief Pre-process a function which propagates taint according to the
@@ -194,6 +214,28 @@ const char GenericTaintChecker::MsgTaintedBufferSize[] =
/// points to data, which should be tainted on return.
REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
+std::shared_ptr<PathDiagnosticPiece>
+GenericTaintChecker::TaintBugVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) {
+
+ // Find the ExplodedNode where the taint was first introduced
+ if (!N->getState()->isTainted(V) || PrevN->getState()->isTainted(V))
+ return nullptr;
+
+ const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ if (!S)
+ return nullptr;
+
+ const LocationContext *NCtx = N->getLocationContext();
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::createBegin(S, BRC.getSourceManager(), NCtx);
+ if (!L.isValid() || !L.asLocation().isValid())
+ return nullptr;
+
+ return std::make_shared<PathDiagnosticEventPiece>(
+ L, "Taint originated here");
+}
+
GenericTaintChecker::TaintPropagationRule
GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
const FunctionDecl *FDecl,
@@ -350,9 +392,9 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
if (CE->getNumArgs() < (ArgNum + 1))
return false;
const Expr* Arg = CE->getArg(ArgNum);
- SymbolRef Sym = getPointedToSymbol(C, Arg);
- if (Sym)
- State = State->addTaint(Sym);
+ Optional<SVal> V = getPointedToSVal(C, Arg);
+ if (V)
+ State = State->addTaint(*V);
}
// Clear up the taint info from the state.
@@ -423,22 +465,20 @@ bool GenericTaintChecker::checkPre(const CallExpr *CE, CheckerContext &C) const{
return false;
}
-SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
- const Expr* Arg) {
+Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C,
+ const Expr* Arg) {
ProgramStateRef State = C.getState();
SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext());
if (AddrVal.isUnknownOrUndef())
- return nullptr;
+ return None;
Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
if (!AddrLoc)
- return nullptr;
+ return None;
const PointerType *ArgTy =
dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr());
- SVal Val = State->getSVal(*AddrLoc,
- ArgTy ? ArgTy->getPointeeType(): QualType());
- return Val.getAsSymbol();
+ return State->getSVal(*AddrLoc, ArgTy ? ArgTy->getPointeeType(): QualType());
}
ProgramStateRef
@@ -558,9 +598,9 @@ ProgramStateRef GenericTaintChecker::postScanf(const CallExpr *CE,
// The arguments are pointer arguments. The data they are pointing at is
// tainted after the call.
const Expr* Arg = CE->getArg(i);
- SymbolRef Sym = getPointedToSymbol(C, Arg);
- if (Sym)
- State = State->addTaint(Sym);
+ Optional<SVal> V = getPointedToSVal(C, Arg);
+ if (V)
+ State = State->addTaint(*V);
}
return State;
}
@@ -635,8 +675,13 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
// Check for taint.
ProgramStateRef State = C.getState();
- if (!State->isTainted(getPointedToSymbol(C, E)) &&
- !State->isTainted(E, C.getLocationContext()))
+ Optional<SVal> PointedToSVal = getPointedToSVal(C, E);
+ SVal TaintedSVal;
+ if (PointedToSVal && State->isTainted(*PointedToSVal))
+ TaintedSVal = *PointedToSVal;
+ else if (State->isTainted(E, C.getLocationContext()))
+ TaintedSVal = C.getSVal(E);
+ else
return false;
// Generate diagnostic.
@@ -644,6 +689,7 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
initBugType();
auto report = llvm::make_unique<BugReport>(*BT, Msg, N);
report->addRange(E->getSourceRange());
+ report->addVisitor(llvm::make_unique<TaintBugVisitor>(TaintedSVal));
C.emitReport(std::move(report));
return true;
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
new file mode 100644
index 0000000..0f9b749
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
@@ -0,0 +1,833 @@
+//===-- IteratorChecker.cpp ---------------------------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a checker for using iterators outside their range (past end). Usage
+// means here dereferencing, incrementing etc.
+//
+//===----------------------------------------------------------------------===//
+//
+// In the code, iterator can be represented as a:
+// * type-I: typedef-ed pointer. Operations over such iterator, such as
+// comparisons or increments, are modeled straightforwardly by the
+// analyzer.
+// * type-II: structure with its method bodies available. Operations over such
+// iterator are inlined by the analyzer, and results of modeling
+// these operations are exposing implementation details of the
+// iterators, which is not necessarily helping.
+// * type-III: completely opaque structure. Operations over such iterator are
+// modeled conservatively, producing conjured symbols everywhere.
+//
+// To handle all these types in a common way we introduce a structure called
+// IteratorPosition which is an abstraction of the position the iterator
+// represents using symbolic expressions. The checker handles all the
+// operations on this structure.
+//
+// Additionally, depending on the circumstances, operators of types II and III
+// can be represented as:
+// * type-IIa, type-IIIa: conjured structure symbols - when returned by value
+// from conservatively evaluated methods such as
+// `.begin()`.
+// * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as
+// variables or temporaries, when the iterator object is
+// currently treated as an lvalue.
+// * type-IIc, type-IIIc: compound values of iterator-typed objects, when the
+// iterator object is treated as an rvalue taken of a
+// particular lvalue, eg. a copy of "type-a" iterator
+// object, or an iterator that existed before the
+// analysis has started.
+//
+// To handle any of these three different representations stored in an SVal we
+// use setter and getters functions which separate the three cases. To store
+// them we use a pointer union of symbol and memory region.
+//
+// The checker works the following way: We record the past-end iterator for
+// all containers whenever their `.end()` is called. Since the Constraint
+// Manager cannot handle SVals we need to take over its role. We post-check
+// equality and non-equality comparisons and propagate the position of the
+// iterator to the other side of the comparison if it is past-end and we are in
+// the 'equal' branch (true-branch for `==` and false-branch for `!=`).
+//
+// In case of type-I or type-II iterators we get a concrete integer as a result
+// of the comparison (1 or 0) but in case of type-III we only get a Symbol. In
+// this latter case we record the symbol and reload it in evalAssume() and do
+// the propagation there. We also handle (maybe double) negated comparisons
+// which are represented in the form of (x == 0 or x !=0 ) where x is the
+// comparison itself.
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+// Abstract position of an iterator. This helps to handle all three kinds
+// of operators in a common way by using a symbolic position.
+struct IteratorPosition {
+private:
+
+ // Container the iterator belongs to
+ const MemRegion *Cont;
+
+ // Abstract offset
+ SymbolRef Offset;
+
+ IteratorPosition(const MemRegion *C, SymbolRef Of)
+ : Cont(C), Offset(Of) {}
+
+public:
+ const MemRegion *getContainer() const { return Cont; }
+ SymbolRef getOffset() const { return Offset; }
+
+ static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
+ return IteratorPosition(C, Of);
+ }
+
+ IteratorPosition setTo(SymbolRef NewOf) const {
+ return IteratorPosition(Cont, NewOf);
+ }
+
+ bool operator==(const IteratorPosition &X) const {
+ return Cont == X.Cont && Offset == X.Offset;
+ }
+
+ bool operator!=(const IteratorPosition &X) const {
+ return Cont != X.Cont || Offset != X.Offset;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(Cont);
+ ID.Add(Offset);
+ }
+};
+
+typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
+
+// Structure to record the symbolic end position of a container
+struct ContainerData {
+private:
+ SymbolRef End;
+
+ ContainerData(SymbolRef E) : End(E) {}
+
+public:
+ static ContainerData fromEnd(SymbolRef E) {
+ return ContainerData(E);
+ }
+
+ SymbolRef getEnd() const { return End; }
+
+ ContainerData newEnd(SymbolRef E) const { return ContainerData(E); }
+
+ bool operator==(const ContainerData &X) const {
+ return End == X.End;
+ }
+
+ bool operator!=(const ContainerData &X) const {
+ return End != X.End;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.Add(End);
+ }
+};
+
+// Structure fo recording iterator comparisons. We needed to retrieve the
+// original comparison expression in assumptions.
+struct IteratorComparison {
+private:
+ RegionOrSymbol Left, Right;
+ bool Equality;
+
+public:
+ IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq)
+ : Left(L), Right(R), Equality(Eq) {}
+
+ RegionOrSymbol getLeft() const { return Left; }
+ RegionOrSymbol getRight() const { return Right; }
+ bool isEquality() const { return Equality; }
+ bool operator==(const IteratorComparison &X) const {
+ return Left == X.Left && Right == X.Right && Equality == X.Equality;
+ }
+ bool operator!=(const IteratorComparison &X) const {
+ return Left != X.Left || Right != X.Right || Equality != X.Equality;
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); }
+};
+
+class IteratorChecker
+ : public Checker<check::PreCall, check::PostCall,
+ check::PostStmt<MaterializeTemporaryExpr>,
+ check::DeadSymbols,
+ eval::Assume> {
+
+ std::unique_ptr<BugType> OutOfRangeBugType;
+
+ void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal,
+ const SVal &RVal, OverloadedOperatorKind Op) const;
+ void verifyDereference(CheckerContext &C, const SVal &Val) const;
+ void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal,
+ const SVal &Cont) const;
+ void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
+ const MemRegion *Cont) const;
+ void reportOutOfRangeBug(const StringRef &Message, const SVal &Val,
+ CheckerContext &C, ExplodedNode *ErrNode) const;
+
+public:
+ IteratorChecker();
+
+ enum CheckKind {
+ CK_IteratorRangeChecker,
+ CK_NumCheckKinds
+ };
+
+ DefaultBool ChecksEnabled[CK_NumCheckKinds];
+ CheckName CheckNames[CK_NumCheckKinds];
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPostStmt(const MaterializeTemporaryExpr *MTE,
+ CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
+ ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const;
+};
+} // namespace
+
+REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
+REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
+ IteratorPosition)
+
+REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData)
+
+REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *,
+ IteratorComparison)
+
+namespace {
+
+bool isIteratorType(const QualType &Type);
+bool isIterator(const CXXRecordDecl *CRD);
+bool isEndCall(const FunctionDecl *Func);
+bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
+bool isDereferenceOperator(OverloadedOperatorKind OK);
+BinaryOperator::Opcode getOpcode(const SymExpr *SE);
+const RegionOrSymbol getRegionOrSymbol(const SVal &Val);
+const ProgramStateRef processComparison(ProgramStateRef State,
+ RegionOrSymbol LVal,
+ RegionOrSymbol RVal, bool Equal);
+const ProgramStateRef saveComparison(ProgramStateRef State,
+ const SymExpr *Condition, const SVal &LVal,
+ const SVal &RVal, bool Eq);
+const IteratorComparison *loadComparison(ProgramStateRef State,
+ const SymExpr *Condition);
+SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
+ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
+ const SymbolRef Sym);
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ const SVal &Val);
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym);
+ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
+ const IteratorPosition &Pos);
+ProgramStateRef setIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ const IteratorPosition &Pos);
+ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
+ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ const IteratorPosition &Pos, bool Equal);
+ProgramStateRef relateIteratorPositions(ProgramStateRef State,
+ const IteratorPosition &Pos1,
+ const IteratorPosition &Pos2,
+ bool Equal);
+const ContainerData *getContainerData(ProgramStateRef State,
+ const MemRegion *Cont);
+ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
+ const ContainerData &CData);
+bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos);
+} // namespace
+
+IteratorChecker::IteratorChecker() {
+ OutOfRangeBugType.reset(
+ new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
+ OutOfRangeBugType->setSuppressOnSink(true);
+}
+
+void IteratorChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Check for out of range access
+ const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!Func)
+ return;
+
+ if (Func->isOverloadedOperator()) {
+ if (ChecksEnabled[CK_IteratorRangeChecker] &&
+ isDereferenceOperator(Func->getOverloadedOperator())) {
+ // Check for dereference of out-of-range iterators
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ verifyDereference(C, InstCall->getCXXThisVal());
+ } else {
+ verifyDereference(C, Call.getArgSVal(0));
+ }
+ }
+ }
+}
+
+void IteratorChecker::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Record new iterator positions and iterator position changes
+ const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!Func)
+ return;
+
+ if (Func->isOverloadedOperator()) {
+ const auto Op = Func->getOverloadedOperator();
+ if (isSimpleComparisonOperator(Op)) {
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ handleComparison(C, Call.getReturnValue(), InstCall->getCXXThisVal(),
+ Call.getArgSVal(0), Op);
+ } else {
+ handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
+ Call.getArgSVal(1), Op);
+ }
+ }
+ } else {
+ const auto *OrigExpr = Call.getOriginExpr();
+ if (!OrigExpr)
+ return;
+
+ if (!isIteratorType(Call.getResultType()))
+ return;
+
+ auto State = C.getState();
+ // Already bound to container?
+ if (getIteratorPosition(State, Call.getReturnValue()))
+ return;
+
+ if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
+ if (isEndCall(Func)) {
+ handleEnd(C, OrigExpr, Call.getReturnValue(),
+ InstCall->getCXXThisVal());
+ return;
+ }
+ }
+
+ // Copy-like and move constructors
+ if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) {
+ if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) {
+ State = setIteratorPosition(State, Call.getReturnValue(), *Pos);
+ if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) {
+ State = removeIteratorPosition(State, Call.getArgSVal(0));
+ }
+ C.addTransition(State);
+ return;
+ }
+ }
+
+ // Assumption: if return value is an iterator which is not yet bound to a
+ // container, then look for the first iterator argument, and
+ // bind the return value to the same container. This approach
+ // works for STL algorithms.
+ // FIXME: Add a more conservative mode
+ for (unsigned i = 0; i < Call.getNumArgs(); ++i) {
+ if (isIteratorType(Call.getArgExpr(i)->getType())) {
+ if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
+ assignToContainer(C, OrigExpr, Call.getReturnValue(),
+ Pos->getContainer());
+ return;
+ }
+ }
+ }
+ }
+}
+
+void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
+ CheckerContext &C) const {
+ /* Transfer iterator state to temporary objects */
+ auto State = C.getState();
+ const auto *LCtx = C.getLocationContext();
+ const auto *Pos =
+ getIteratorPosition(State, State->getSVal(MTE->GetTemporaryExpr(), LCtx));
+ if (!Pos)
+ return;
+ State = setIteratorPosition(State, State->getSVal(MTE, LCtx), *Pos);
+ C.addTransition(State);
+}
+
+void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
+ CheckerContext &C) const {
+ // Cleanup
+ auto State = C.getState();
+
+ auto RegionMap = State->get<IteratorRegionMap>();
+ for (const auto Reg : RegionMap) {
+ if (!SR.isLiveRegion(Reg.first)) {
+ State = State->remove<IteratorRegionMap>(Reg.first);
+ }
+ }
+
+ auto SymbolMap = State->get<IteratorSymbolMap>();
+ for (const auto Sym : SymbolMap) {
+ if (!SR.isLive(Sym.first)) {
+ State = State->remove<IteratorSymbolMap>(Sym.first);
+ }
+ }
+
+ auto ContMap = State->get<ContainerMap>();
+ for (const auto Cont : ContMap) {
+ if (!SR.isLiveRegion(Cont.first)) {
+ State = State->remove<ContainerMap>(Cont.first);
+ }
+ }
+
+ auto ComparisonMap = State->get<IteratorComparisonMap>();
+ for (const auto Comp : ComparisonMap) {
+ if (!SR.isLive(Comp.first)) {
+ State = State->remove<IteratorComparisonMap>(Comp.first);
+ }
+ }
+}
+
+ProgramStateRef IteratorChecker::evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const {
+ // Load recorded comparison and transfer iterator state between sides
+ // according to comparison operator and assumption
+ const auto *SE = Cond.getAsSymExpr();
+ if (!SE)
+ return State;
+
+ auto Opc = getOpcode(SE);
+ if (Opc != BO_EQ && Opc != BO_NE)
+ return State;
+
+ bool Negated = false;
+ const auto *Comp = loadComparison(State, SE);
+ if (!Comp) {
+ // Try negated comparison, which is a SymExpr to 0 integer comparison
+ const auto *SIE = dyn_cast<SymIntExpr>(SE);
+ if (!SIE)
+ return State;
+
+ if (SIE->getRHS() != 0)
+ return State;
+
+ SE = SIE->getLHS();
+ Negated = SIE->getOpcode() == BO_EQ; // Equal to zero means negation
+ Opc = getOpcode(SE);
+ if (Opc != BO_EQ && Opc != BO_NE)
+ return State;
+
+ Comp = loadComparison(State, SE);
+ if (!Comp)
+ return State;
+ }
+
+ return processComparison(State, Comp->getLeft(), Comp->getRight(),
+ (Comp->isEquality() == Assumption) != Negated);
+}
+
+void IteratorChecker::handleComparison(CheckerContext &C, const SVal &RetVal,
+ const SVal &LVal, const SVal &RVal,
+ OverloadedOperatorKind Op) const {
+ // Record the operands and the operator of the comparison for the next
+ // evalAssume, if the result is a symbolic expression. If it is a concrete
+ // value (only one branch is possible), then transfer the state between
+ // the operands according to the operator and the result
+ auto State = C.getState();
+ if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
+ const auto *LPos = getIteratorPosition(State, LVal);
+ const auto *RPos = getIteratorPosition(State, RVal);
+ if (!LPos && !RPos)
+ return;
+ State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
+ C.addTransition(State);
+ } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
+ if ((State = processComparison(
+ State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
+ (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
+ C.addTransition(State);
+ } else {
+ C.generateSink(State, C.getPredecessor());
+ }
+ }
+}
+
+void IteratorChecker::verifyDereference(CheckerContext &C,
+ const SVal &Val) const {
+ auto State = C.getState();
+ const auto *Pos = getIteratorPosition(State, Val);
+ if (Pos && isOutOfRange(State, *Pos)) {
+ // If I do not put a tag here, some range tests will fail
+ static CheckerProgramPointTag Tag("IteratorRangeChecker",
+ "IteratorOutOfRange");
+ auto *N = C.generateNonFatalErrorNode(State, &Tag);
+ if (!N) {
+ return;
+ }
+ reportOutOfRangeBug("Iterator accessed outside of its range.", Val, C, N);
+ }
+}
+
+void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE,
+ const SVal &RetVal, const SVal &Cont) const {
+ const auto *ContReg = Cont.getAsRegion();
+ if (!ContReg)
+ return;
+
+ while (const auto *CBOR = ContReg->getAs<CXXBaseObjectRegion>()) {
+ ContReg = CBOR->getSuperRegion();
+ }
+
+ // If the container already has an end symbol then use it. Otherwise first
+ // create a new one.
+ auto State = C.getState();
+ auto EndSym = getContainerEnd(State, ContReg);
+ if (!EndSym) {
+ auto &SymMgr = C.getSymbolManager();
+ EndSym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
+ C.getASTContext().LongTy, C.blockCount());
+ State = createContainerEnd(State, ContReg, EndSym);
+ }
+ State = setIteratorPosition(State, RetVal,
+ IteratorPosition::getPosition(ContReg, EndSym));
+ C.addTransition(State);
+}
+
+void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE,
+ const SVal &RetVal,
+ const MemRegion *Cont) const {
+ while (const auto *CBOR = Cont->getAs<CXXBaseObjectRegion>()) {
+ Cont = CBOR->getSuperRegion();
+ }
+
+ auto State = C.getState();
+ auto &SymMgr = C.getSymbolManager();
+ auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
+ C.getASTContext().LongTy, C.blockCount());
+ State = setIteratorPosition(State, RetVal,
+ IteratorPosition::getPosition(Cont, Sym));
+ C.addTransition(State);
+}
+
+void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
+ const SVal &Val, CheckerContext &C,
+ ExplodedNode *ErrNode) const {
+ auto R = llvm::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
+ R->markInteresting(Val);
+ C.emitReport(std::move(R));
+}
+
+namespace {
+
+bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
+bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
+ BinaryOperator::Opcode Opc);
+
+bool isIteratorType(const QualType &Type) {
+ if (Type->isPointerType())
+ return true;
+
+ const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
+ return isIterator(CRD);
+}
+
+bool isIterator(const CXXRecordDecl *CRD) {
+ if (!CRD)
+ return false;
+
+ const auto Name = CRD->getName();
+ if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
+ Name.endswith_lower("it")))
+ return false;
+
+ bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
+ HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
+ for (const auto *Method : CRD->methods()) {
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
+ if (Ctor->isCopyConstructor()) {
+ HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
+ }
+ continue;
+ }
+ if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
+ HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
+ continue;
+ }
+ if (Method->isCopyAssignmentOperator()) {
+ HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
+ continue;
+ }
+ if (!Method->isOverloadedOperator())
+ continue;
+ const auto OPK = Method->getOverloadedOperator();
+ if (OPK == OO_PlusPlus) {
+ HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
+ HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
+ continue;
+ }
+ if (OPK == OO_Star) {
+ HasDerefOp = (Method->getNumParams() == 0);
+ continue;
+ }
+ }
+
+ return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
+ HasPostIncrOp && HasDerefOp;
+}
+
+bool isEndCall(const FunctionDecl *Func) {
+ const auto *IdInfo = Func->getIdentifier();
+ if (!IdInfo)
+ return false;
+ return IdInfo->getName().endswith_lower("end");
+}
+
+bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
+ return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
+}
+
+bool isDereferenceOperator(OverloadedOperatorKind OK) {
+ return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
+ OK == OO_Subscript;
+}
+
+BinaryOperator::Opcode getOpcode(const SymExpr *SE) {
+ if (const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
+ return BSE->getOpcode();
+ } else if (const auto *SC = dyn_cast<SymbolConjured>(SE)) {
+ const auto *COE = dyn_cast<CXXOperatorCallExpr>(SC->getStmt());
+ if (!COE)
+ return BO_Comma; // Extremal value, neither EQ nor NE
+ if (COE->getOperator() == OO_EqualEqual) {
+ return BO_EQ;
+ } else if (COE->getOperator() == OO_ExclaimEqual) {
+ return BO_NE;
+ }
+ return BO_Comma; // Extremal value, neither EQ nor NE
+ }
+ return BO_Comma; // Extremal value, neither EQ nor NE
+}
+
+const RegionOrSymbol getRegionOrSymbol(const SVal &Val) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return Reg;
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return Sym;
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return LCVal->getRegion();
+ }
+ return RegionOrSymbol();
+}
+
+const ProgramStateRef processComparison(ProgramStateRef State,
+ RegionOrSymbol LVal,
+ RegionOrSymbol RVal, bool Equal) {
+ const auto *LPos = getIteratorPosition(State, LVal);
+ const auto *RPos = getIteratorPosition(State, RVal);
+ if (LPos && !RPos) {
+ State = adjustIteratorPosition(State, RVal, *LPos, Equal);
+ } else if (!LPos && RPos) {
+ State = adjustIteratorPosition(State, LVal, *RPos, Equal);
+ } else if (LPos && RPos) {
+ State = relateIteratorPositions(State, *LPos, *RPos, Equal);
+ }
+ return State;
+}
+
+const ProgramStateRef saveComparison(ProgramStateRef State,
+ const SymExpr *Condition, const SVal &LVal,
+ const SVal &RVal, bool Eq) {
+ const auto Left = getRegionOrSymbol(LVal);
+ const auto Right = getRegionOrSymbol(RVal);
+ if (!Left || !Right)
+ return State;
+ return State->set<IteratorComparisonMap>(Condition,
+ IteratorComparison(Left, Right, Eq));
+}
+
+const IteratorComparison *loadComparison(ProgramStateRef State,
+ const SymExpr *Condition) {
+ return State->get<IteratorComparisonMap>(Condition);
+}
+
+SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
+ const auto *CDataPtr = getContainerData(State, Cont);
+ if (!CDataPtr)
+ return nullptr;
+
+ return CDataPtr->getEnd();
+}
+
+ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
+ const SymbolRef Sym) {
+ // Only create if it does not exist
+ const auto *CDataPtr = getContainerData(State, Cont);
+ if (CDataPtr) {
+ if (CDataPtr->getEnd()) {
+ return State;
+ } else {
+ const auto CData = CDataPtr->newEnd(Sym);
+ return setContainerData(State, Cont, CData);
+ }
+ } else {
+ const auto CData = ContainerData::fromEnd(Sym);
+ return setContainerData(State, Cont, CData);
+ }
+}
+
+const ContainerData *getContainerData(ProgramStateRef State,
+ const MemRegion *Cont) {
+ return State->get<ContainerMap>(Cont);
+}
+
+ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
+ const ContainerData &CData) {
+ return State->set<ContainerMap>(Cont, CData);
+}
+
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ const SVal &Val) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return State->get<IteratorRegionMap>(Reg);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->get<IteratorSymbolMap>(Sym);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->get<IteratorRegionMap>(LCVal->getRegion());
+ }
+ return nullptr;
+}
+
+const IteratorPosition *getIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym) {
+ if (RegOrSym.is<const MemRegion *>()) {
+ return State->get<IteratorRegionMap>(RegOrSym.get<const MemRegion *>());
+ } else if (RegOrSym.is<SymbolRef>()) {
+ return State->get<IteratorSymbolMap>(RegOrSym.get<SymbolRef>());
+ }
+ return nullptr;
+}
+
+ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
+ const IteratorPosition &Pos) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return State->set<IteratorRegionMap>(Reg, Pos);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->set<IteratorSymbolMap>(Sym, Pos);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
+ }
+ return nullptr;
+}
+
+ProgramStateRef setIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ const IteratorPosition &Pos) {
+ if (RegOrSym.is<const MemRegion *>()) {
+ return State->set<IteratorRegionMap>(RegOrSym.get<const MemRegion *>(),
+ Pos);
+ } else if (RegOrSym.is<SymbolRef>()) {
+ return State->set<IteratorSymbolMap>(RegOrSym.get<SymbolRef>(), Pos);
+ }
+ return nullptr;
+}
+
+ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
+ if (const auto Reg = Val.getAsRegion()) {
+ return State->remove<IteratorRegionMap>(Reg);
+ } else if (const auto Sym = Val.getAsSymbol()) {
+ return State->remove<IteratorSymbolMap>(Sym);
+ } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
+ return State->remove<IteratorRegionMap>(LCVal->getRegion());
+ }
+ return nullptr;
+}
+
+ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
+ RegionOrSymbol RegOrSym,
+ const IteratorPosition &Pos,
+ bool Equal) {
+ if (Equal) {
+ return setIteratorPosition(State, RegOrSym, Pos);
+ } else {
+ return State;
+ }
+}
+
+ProgramStateRef relateIteratorPositions(ProgramStateRef State,
+ const IteratorPosition &Pos1,
+ const IteratorPosition &Pos2,
+ bool Equal) {
+ // Try to compare them and get a defined value
+ auto &SVB = State->getStateManager().getSValBuilder();
+ const auto comparison =
+ SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Pos1.getOffset()),
+ nonloc::SymbolVal(Pos2.getOffset()), SVB.getConditionType())
+ .getAs<DefinedSVal>();
+ if (comparison) {
+ return State->assume(*comparison, Equal);
+ }
+
+ return State;
+}
+
+bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos) {
+ const auto *Cont = Pos.getContainer();
+ const auto *CData = getContainerData(State, Cont);
+ if (!CData)
+ return false;
+
+ // Out of range means less than the begin symbol or greater or equal to the
+ // end symbol.
+
+ const auto End = CData->getEnd();
+ if (End) {
+ if (isGreaterOrEqual(State, Pos.getOffset(), End)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool isGreaterOrEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) {
+ return compare(State, Sym1, Sym2, BO_GE);
+}
+
+bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
+ BinaryOperator::Opcode Opc) {
+ auto &SMgr = State->getStateManager();
+ auto &SVB = SMgr.getSValBuilder();
+
+ const auto comparison =
+ SVB.evalBinOp(State, Opc, nonloc::SymbolVal(Sym1),
+ nonloc::SymbolVal(Sym2), SVB.getConditionType())
+ .getAs<DefinedSVal>();
+
+ if(comparison) {
+ return !!State->assume(*comparison, true);
+ }
+
+ return false;
+}
+
+} // namespace
+
+#define REGISTER_CHECKER(name) \
+ void ento::register##name(CheckerManager &Mgr) { \
+ auto *checker = Mgr.registerChecker<IteratorChecker>(); \
+ checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \
+ checker->CheckNames[IteratorChecker::CK_##name] = \
+ Mgr.getCurrentCheckName(); \
+ }
+
+REGISTER_CHECKER(IteratorRangeChecker)
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp
deleted file mode 100644
index 531054a..0000000
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorPastEndChecker.cpp
+++ /dev/null
@@ -1,842 +0,0 @@
-//===-- IteratorPastEndChecker.cpp --------------------------------*- C++ -*--//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines a checker for using iterators outside their range (past end). Usage
-// means here dereferencing, incrementing etc.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-
-#include <utility>
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-struct IteratorPosition {
-private:
- enum Kind { InRange, OutofRange } K;
- IteratorPosition(Kind InK) : K(InK) {}
-
-public:
- bool isInRange() const { return K == InRange; }
- bool isOutofRange() const { return K == OutofRange; }
-
- static IteratorPosition getInRange() { return IteratorPosition(InRange); }
- static IteratorPosition getOutofRange() {
- return IteratorPosition(OutofRange);
- }
-
- bool operator==(const IteratorPosition &X) const { return K == X.K; }
- bool operator!=(const IteratorPosition &X) const { return K != X.K; }
- void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); }
-};
-
-typedef llvm::PointerUnion<const MemRegion *, SymbolRef> RegionOrSymbol;
-
-struct IteratorComparison {
-private:
- RegionOrSymbol Left, Right;
- bool Equality;
-
-public:
- IteratorComparison(RegionOrSymbol L, RegionOrSymbol R, bool Eq)
- : Left(L), Right(R), Equality(Eq) {}
-
- RegionOrSymbol getLeft() const { return Left; }
- RegionOrSymbol getRight() const { return Right; }
- bool isEquality() const { return Equality; }
- bool operator==(const IteratorComparison &X) const {
- return Left == X.Left && Right == X.Right && Equality == X.Equality;
- }
- bool operator!=(const IteratorComparison &X) const {
- return Left != X.Left || Right != X.Right || Equality != X.Equality;
- }
- void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Equality); }
-};
-
-class IteratorPastEndChecker
- : public Checker<
- check::PreCall, check::PostCall, check::PreStmt<CXXOperatorCallExpr>,
- check::PostStmt<CXXConstructExpr>, check::PostStmt<DeclStmt>,
- check::PostStmt<MaterializeTemporaryExpr>, check::BeginFunction,
- check::DeadSymbols, eval::Assume, eval::Call> {
- mutable IdentifierInfo *II_find = nullptr,
- *II_find_end = nullptr, *II_find_first_of = nullptr,
- *II_find_if = nullptr, *II_find_if_not = nullptr,
- *II_lower_bound = nullptr, *II_upper_bound = nullptr,
- *II_search = nullptr, *II_search_n = nullptr;
-
- std::unique_ptr<BugType> PastEndBugType;
-
- void handleComparison(CheckerContext &C, const SVal &RetVal, const SVal &LVal,
- const SVal &RVal, OverloadedOperatorKind Op) const;
- void handleAccess(CheckerContext &C, const SVal &Val) const;
- void handleDecrement(CheckerContext &C, const SVal &Val) const;
- void handleEnd(CheckerContext &C, const SVal &RetVal) const;
-
- bool evalFind(CheckerContext &C, const CallExpr *CE) const;
- bool evalFindEnd(CheckerContext &C, const CallExpr *CE) const;
- bool evalFindFirstOf(CheckerContext &C, const CallExpr *CE) const;
- bool evalFindIf(CheckerContext &C, const CallExpr *CE) const;
- bool evalFindIfNot(CheckerContext &C, const CallExpr *CE) const;
- bool evalLowerBound(CheckerContext &C, const CallExpr *CE) const;
- bool evalUpperBound(CheckerContext &C, const CallExpr *CE) const;
- bool evalSearch(CheckerContext &C, const CallExpr *CE) const;
- bool evalSearchN(CheckerContext &C, const CallExpr *CE) const;
- void Find(CheckerContext &C, const CallExpr *CE) const;
-
- void reportPastEndBug(const StringRef &Message, const SVal &Val,
- CheckerContext &C, ExplodedNode *ErrNode) const;
- void initIdentifiers(ASTContext &Ctx) const;
-
-public:
- IteratorPastEndChecker();
-
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
- void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
- void checkPreStmt(const CXXOperatorCallExpr *COCE, CheckerContext &C) const;
- void checkBeginFunction(CheckerContext &C) const;
- void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const;
- void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const;
- void checkPostStmt(const MaterializeTemporaryExpr *MTE,
- CheckerContext &C) const;
- void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
- ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
- bool Assumption) const;
- bool evalCall(const CallExpr *CE, CheckerContext &C) const;
-};
-}
-
-REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition)
-REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *,
- IteratorPosition)
-
-REGISTER_MAP_WITH_PROGRAMSTATE(IteratorComparisonMap, const SymExpr *,
- IteratorComparison)
-
-#define INIT_ID(Id) \
- if (!II_##Id) \
- II_##Id = &Ctx.Idents.get(#Id)
-
-namespace {
-
-bool isIteratorType(const QualType &Type);
-bool isIterator(const CXXRecordDecl *CRD);
-bool isEndCall(const FunctionDecl *Func);
-bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
-bool isAccessOperator(OverloadedOperatorKind OK);
-bool isDecrementOperator(OverloadedOperatorKind OK);
-BinaryOperator::Opcode getOpcode(const SymExpr *SE);
-const RegionOrSymbol getRegionOrSymbol(const SVal &Val);
-const ProgramStateRef processComparison(ProgramStateRef State,
- RegionOrSymbol LVal,
- RegionOrSymbol RVal, bool Equal);
-const ProgramStateRef saveComparison(ProgramStateRef State,
- const SymExpr *Condition, const SVal &LVal,
- const SVal &RVal, bool Eq);
-const IteratorComparison *loadComparison(ProgramStateRef State,
- const SymExpr *Condition);
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- const SVal &Val);
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym);
-ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
- IteratorPosition Pos);
-ProgramStateRef setIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym,
- IteratorPosition Pos);
-ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym,
- IteratorPosition Pos, bool Equal);
-bool contradictingIteratorPositions(IteratorPosition Pos1,
- IteratorPosition Pos2, bool Equal);
-}
-
-IteratorPastEndChecker::IteratorPastEndChecker() {
- PastEndBugType.reset(
- new BugType(this, "Iterator Past End", "Misuse of STL APIs"));
- PastEndBugType->setSuppressOnSink(true);
-}
-
-void IteratorPastEndChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
- // Check for access past end
- const auto *Func = Call.getDecl()->getAsFunction();
- if (!Func)
- return;
- if (Func->isOverloadedOperator()) {
- if (isAccessOperator(Func->getOverloadedOperator())) {
- if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- handleAccess(C, InstCall->getCXXThisVal());
- } else {
- handleAccess(C, Call.getArgSVal(0));
- }
- }
- }
-}
-
-void IteratorPastEndChecker::checkPostCall(const CallEvent &Call,
- CheckerContext &C) const {
- // Record end() iterators, iterator decrementation and comparison
- const auto *Func = Call.getDecl()->getAsFunction();
- if (!Func)
- return;
- if (Func->isOverloadedOperator()) {
- const auto Op = Func->getOverloadedOperator();
- if (isSimpleComparisonOperator(Op)) {
- if (Func->isCXXInstanceMember()) {
- const auto &InstCall = static_cast<const CXXInstanceCall &>(Call);
- handleComparison(C, InstCall.getReturnValue(), InstCall.getCXXThisVal(),
- InstCall.getArgSVal(0), Op);
- } else {
- handleComparison(C, Call.getReturnValue(), Call.getArgSVal(0),
- Call.getArgSVal(1), Op);
- }
- } else if (isDecrementOperator(Func->getOverloadedOperator())) {
- if (Func->isCXXInstanceMember()) {
- const auto &InstCall = static_cast<const CXXInstanceCall &>(Call);
- handleDecrement(C, InstCall.getCXXThisVal());
- } else {
- handleDecrement(C, Call.getArgSVal(0));
- }
- }
- } else if (Func->isCXXInstanceMember()) {
- if (!isEndCall(Func))
- return;
- if (!isIteratorType(Call.getResultType()))
- return;
- handleEnd(C, Call.getReturnValue());
- }
-}
-
-void IteratorPastEndChecker::checkPreStmt(const CXXOperatorCallExpr *COCE,
- CheckerContext &C) const {
- const auto *ThisExpr = COCE->getArg(0);
-
- auto State = C.getState();
- const auto *LCtx = C.getPredecessor()->getLocationContext();
-
- const auto CurrentThis = State->getSVal(ThisExpr, LCtx);
- if (const auto *Reg = CurrentThis.getAsRegion()) {
- if (!Reg->getAs<CXXTempObjectRegion>())
- return;
- const auto OldState = C.getPredecessor()->getFirstPred()->getState();
- const auto OldThis = OldState->getSVal(ThisExpr, LCtx);
- const auto *Pos = getIteratorPosition(OldState, OldThis);
- if (!Pos)
- return;
- State = setIteratorPosition(State, CurrentThis, *Pos);
- C.addTransition(State);
- }
-}
-
-void IteratorPastEndChecker::checkBeginFunction(CheckerContext &C) const {
- // Copy state of iterator arguments to iterator parameters
- auto State = C.getState();
- const auto *LCtx = C.getLocationContext();
-
- const auto *Site = cast<StackFrameContext>(LCtx)->getCallSite();
- if (!Site)
- return;
-
- const auto *FD = dyn_cast<FunctionDecl>(LCtx->getDecl());
- if (!FD)
- return;
-
- const auto *CE = dyn_cast<CallExpr>(Site);
- if (!CE)
- return;
-
- bool Change = false;
- int idx = 0;
- for (const auto P : FD->parameters()) {
- auto Param = State->getLValue(P, LCtx);
- auto Arg = State->getSVal(CE->getArg(idx++), LCtx->getParent());
- const auto *Pos = getIteratorPosition(State, Arg);
- if (!Pos)
- continue;
- State = setIteratorPosition(State, Param, *Pos);
- Change = true;
- }
- if (Change) {
- C.addTransition(State);
- }
-}
-
-void IteratorPastEndChecker::checkPostStmt(const CXXConstructExpr *CCE,
- CheckerContext &C) const {
- // Transfer iterator state in case of copy or move by constructor
- const auto *ctr = CCE->getConstructor();
- if (!ctr->isCopyOrMoveConstructor())
- return;
- const auto *RHSExpr = CCE->getArg(0);
-
- auto State = C.getState();
- const auto *LCtx = C.getLocationContext();
-
- const auto RetVal = State->getSVal(CCE, LCtx);
-
- const auto RHSVal = State->getSVal(RHSExpr, LCtx);
- const auto *RHSPos = getIteratorPosition(State, RHSVal);
- if (!RHSPos)
- return;
- State = setIteratorPosition(State, RetVal, *RHSPos);
- C.addTransition(State);
-}
-
-void IteratorPastEndChecker::checkPostStmt(const DeclStmt *DS,
- CheckerContext &C) const {
- // Transfer iterator state to new variable declaration
- for (const auto *D : DS->decls()) {
- const auto *VD = dyn_cast<VarDecl>(D);
- if (!VD || !VD->hasInit())
- continue;
-
- auto State = C.getState();
- const auto *LCtx = C.getPredecessor()->getLocationContext();
- const auto *Pos =
- getIteratorPosition(State, State->getSVal(VD->getInit(), LCtx));
- if (!Pos)
- continue;
- State = setIteratorPosition(State, State->getLValue(VD, LCtx), *Pos);
- C.addTransition(State);
- }
-}
-
-void IteratorPastEndChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE,
- CheckerContext &C) const {
- /* Transfer iterator state for to temporary objects */
- auto State = C.getState();
- const auto *LCtx = C.getPredecessor()->getLocationContext();
- const auto *Pos =
- getIteratorPosition(State, State->getSVal(MTE->GetTemporaryExpr(), LCtx));
- if (!Pos)
- return;
- State = setIteratorPosition(State, State->getSVal(MTE, LCtx), *Pos);
- C.addTransition(State);
-}
-
-void IteratorPastEndChecker::checkDeadSymbols(SymbolReaper &SR,
- CheckerContext &C) const {
- auto State = C.getState();
-
- auto RegionMap = State->get<IteratorRegionMap>();
- for (const auto Reg : RegionMap) {
- if (!SR.isLiveRegion(Reg.first)) {
- State = State->remove<IteratorRegionMap>(Reg.first);
- }
- }
-
- auto SymbolMap = State->get<IteratorSymbolMap>();
- for (const auto Sym : SymbolMap) {
- if (SR.isDead(Sym.first)) {
- State = State->remove<IteratorSymbolMap>(Sym.first);
- }
- }
-
- auto ComparisonMap = State->get<IteratorComparisonMap>();
- for (const auto Comp : ComparisonMap) {
- if (SR.isDead(Comp.first)) {
- State = State->remove<IteratorComparisonMap>(Comp.first);
- }
- }
-}
-
-ProgramStateRef IteratorPastEndChecker::evalAssume(ProgramStateRef State,
- SVal Cond,
- bool Assumption) const {
- // Load recorded comparison and transfer iterator state between sides
- // according to comparison operator and assumption
- const auto *SE = Cond.getAsSymExpr();
- if (!SE)
- return State;
-
- auto Opc = getOpcode(SE);
- if (Opc != BO_EQ && Opc != BO_NE)
- return State;
-
- bool Negated = false;
- const auto *Comp = loadComparison(State, SE);
- if (!Comp) {
- // Try negated comparison, which is a SymExpr to 0 integer comparison
- const auto *SIE = dyn_cast<SymIntExpr>(SE);
- if (!SIE)
- return State;
-
- if (SIE->getRHS() != 0)
- return State;
-
- SE = SIE->getLHS();
- Negated = SIE->getOpcode() == BO_EQ; // Equal to zero means negation
- Opc = getOpcode(SE);
- if (Opc != BO_EQ && Opc != BO_NE)
- return State;
-
- Comp = loadComparison(State, SE);
- if (!Comp)
- return State;
- }
-
- return processComparison(State, Comp->getLeft(), Comp->getRight(),
- (Comp->isEquality() == Assumption) != Negated);
-}
-
-// FIXME: Evaluation of these STL calls should be moved to StdCLibraryFunctions
-// checker (see patch r284960) or another similar checker for C++ STL
-// functions (e.g. StdCXXLibraryFunctions or StdCppLibraryFunctions).
-bool IteratorPastEndChecker::evalCall(const CallExpr *CE,
- CheckerContext &C) const {
- const FunctionDecl *FD = C.getCalleeDecl(CE);
- if (!FD)
- return false;
-
- ASTContext &Ctx = C.getASTContext();
- initIdentifiers(Ctx);
-
- if (FD->getKind() == Decl::Function) {
- if (FD->isInStdNamespace()) {
- if (FD->getIdentifier() == II_find) {
- return evalFind(C, CE);
- } else if (FD->getIdentifier() == II_find_end) {
- return evalFindEnd(C, CE);
- } else if (FD->getIdentifier() == II_find_first_of) {
- return evalFindFirstOf(C, CE);
- } else if (FD->getIdentifier() == II_find_if) {
- return evalFindIf(C, CE);
- } else if (FD->getIdentifier() == II_find_if) {
- return evalFindIf(C, CE);
- } else if (FD->getIdentifier() == II_find_if_not) {
- return evalFindIfNot(C, CE);
- } else if (FD->getIdentifier() == II_upper_bound) {
- return evalUpperBound(C, CE);
- } else if (FD->getIdentifier() == II_lower_bound) {
- return evalLowerBound(C, CE);
- } else if (FD->getIdentifier() == II_search) {
- return evalSearch(C, CE);
- } else if (FD->getIdentifier() == II_search_n) {
- return evalSearchN(C, CE);
- }
- }
- }
-
- return false;
-}
-
-void IteratorPastEndChecker::handleComparison(CheckerContext &C,
- const SVal &RetVal,
- const SVal &LVal,
- const SVal &RVal,
- OverloadedOperatorKind Op) const {
- // Record the operands and the operator of the comparison for the next
- // evalAssume, if the result is a symbolic expression. If it is a concrete
- // value (only one branch is possible), then transfer the state between
- // the operands according to the operator and the result
- auto State = C.getState();
- if (const auto *Condition = RetVal.getAsSymbolicExpression()) {
- const auto *LPos = getIteratorPosition(State, LVal);
- const auto *RPos = getIteratorPosition(State, RVal);
- if (!LPos && !RPos)
- return;
- State = saveComparison(State, Condition, LVal, RVal, Op == OO_EqualEqual);
- C.addTransition(State);
- } else if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
- if ((State = processComparison(
- State, getRegionOrSymbol(LVal), getRegionOrSymbol(RVal),
- (Op == OO_EqualEqual) == (TruthVal->getValue() != 0)))) {
- C.addTransition(State);
- } else {
- C.generateSink(State, C.getPredecessor());
- }
- }
-}
-
-void IteratorPastEndChecker::handleAccess(CheckerContext &C,
- const SVal &Val) const {
- auto State = C.getState();
- const auto *Pos = getIteratorPosition(State, Val);
- if (Pos && Pos->isOutofRange()) {
- auto *N = C.generateNonFatalErrorNode(State);
- if (!N) {
- return;
- }
- reportPastEndBug("Iterator accessed past its end.", Val, C, N);
- }
-}
-
-void IteratorPastEndChecker::handleDecrement(CheckerContext &C,
- const SVal &Val) const {
- auto State = C.getState();
- const auto *Pos = getIteratorPosition(State, Val);
- if (Pos && Pos->isOutofRange()) {
- State = setIteratorPosition(State, Val, IteratorPosition::getInRange());
- // FIXME: We could also check for iterators ahead of their beginnig in the
- // future, but currently we do not care for such errors. We also
- // assume that the iterator is not past its end by more then one
- // position.
- C.addTransition(State);
- }
-}
-
-void IteratorPastEndChecker::handleEnd(CheckerContext &C,
- const SVal &RetVal) const {
- auto State = C.getState();
- State = setIteratorPosition(State, RetVal, IteratorPosition::getOutofRange());
- C.addTransition(State);
-}
-
-bool IteratorPastEndChecker::evalFind(CheckerContext &C,
- const CallExpr *CE) const {
- if (CE->getNumArgs() == 3 && isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalFindEnd(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType()) &&
- isIteratorType(CE->getArg(2)->getType()) &&
- isIteratorType(CE->getArg(3)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalFindFirstOf(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType()) &&
- isIteratorType(CE->getArg(2)->getType()) &&
- isIteratorType(CE->getArg(3)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalFindIf(CheckerContext &C,
- const CallExpr *CE) const {
- if (CE->getNumArgs() == 3 && isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalFindIfNot(CheckerContext &C,
- const CallExpr *CE) const {
- if (CE->getNumArgs() == 3 && isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalLowerBound(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 3 || CE->getNumArgs() == 4) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalUpperBound(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 3 || CE->getNumArgs() == 4) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalSearch(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType()) &&
- isIteratorType(CE->getArg(2)->getType()) &&
- isIteratorType(CE->getArg(3)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-bool IteratorPastEndChecker::evalSearchN(CheckerContext &C,
- const CallExpr *CE) const {
- if ((CE->getNumArgs() == 4 || CE->getNumArgs() == 5) &&
- isIteratorType(CE->getArg(0)->getType()) &&
- isIteratorType(CE->getArg(1)->getType())) {
- Find(C, CE);
- return true;
- }
- return false;
-}
-
-void IteratorPastEndChecker::Find(CheckerContext &C, const CallExpr *CE) const {
- auto state = C.getState();
- auto &svalBuilder = C.getSValBuilder();
- const auto *LCtx = C.getLocationContext();
-
- auto RetVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
- auto SecondParam = state->getSVal(CE->getArg(1), LCtx);
-
- auto stateFound = state->BindExpr(CE, LCtx, RetVal);
- auto stateNotFound = state->BindExpr(CE, LCtx, SecondParam);
-
- C.addTransition(stateFound);
- C.addTransition(stateNotFound);
-}
-
-void IteratorPastEndChecker::reportPastEndBug(const StringRef &Message,
- const SVal &Val,
- CheckerContext &C,
- ExplodedNode *ErrNode) const {
- auto R = llvm::make_unique<BugReport>(*PastEndBugType, Message, ErrNode);
- R->markInteresting(Val);
- C.emitReport(std::move(R));
-}
-
-void IteratorPastEndChecker::initIdentifiers(ASTContext &Ctx) const {
- INIT_ID(find);
- INIT_ID(find_end);
- INIT_ID(find_first_of);
- INIT_ID(find_if);
- INIT_ID(find_if_not);
- INIT_ID(lower_bound);
- INIT_ID(upper_bound);
- INIT_ID(search);
- INIT_ID(search_n);
-}
-
-namespace {
-
-bool isIteratorType(const QualType &Type) {
- if (Type->isPointerType())
- return true;
-
- const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
- return isIterator(CRD);
-}
-
-bool isIterator(const CXXRecordDecl *CRD) {
- if (!CRD)
- return false;
-
- const auto Name = CRD->getName();
- if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
- Name.endswith_lower("it")))
- return false;
-
- bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
- HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
- for (const auto *Method : CRD->methods()) {
- if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
- if (Ctor->isCopyConstructor()) {
- HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
- }
- continue;
- }
- if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
- HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
- continue;
- }
- if (Method->isCopyAssignmentOperator()) {
- HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
- continue;
- }
- if (!Method->isOverloadedOperator())
- continue;
- const auto OPK = Method->getOverloadedOperator();
- if (OPK == OO_PlusPlus) {
- HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
- HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
- continue;
- }
- if (OPK == OO_Star) {
- HasDerefOp = (Method->getNumParams() == 0);
- continue;
- }
- }
-
- return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
- HasPostIncrOp && HasDerefOp;
-}
-
-bool isEndCall(const FunctionDecl *Func) {
- const auto *IdInfo = Func->getIdentifier();
- if (!IdInfo)
- return false;
- return IdInfo->getName().endswith_lower("end");
-}
-
-bool isSimpleComparisonOperator(OverloadedOperatorKind OK) {
- return OK == OO_EqualEqual || OK == OO_ExclaimEqual;
-}
-
-bool isAccessOperator(OverloadedOperatorKind OK) {
- return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
- OK == OO_Plus || OK == OO_PlusEqual || OK == OO_PlusPlus ||
- OK == OO_Subscript;
-}
-
-bool isDecrementOperator(OverloadedOperatorKind OK) {
- return OK == OO_MinusEqual || OK == OO_MinusMinus;
-}
-
-BinaryOperator::Opcode getOpcode(const SymExpr *SE) {
- if (const auto *BSE = dyn_cast<BinarySymExpr>(SE)) {
- return BSE->getOpcode();
- } else if (const auto *SC = dyn_cast<SymbolConjured>(SE)) {
- const auto *COE = dyn_cast<CXXOperatorCallExpr>(SC->getStmt());
- if (!COE)
- return BO_Comma; // Extremal value, neither EQ nor NE
- if (COE->getOperator() == OO_EqualEqual) {
- return BO_EQ;
- } else if (COE->getOperator() == OO_ExclaimEqual) {
- return BO_NE;
- }
- return BO_Comma; // Extremal value, neither EQ nor NE
- }
- return BO_Comma; // Extremal value, neither EQ nor NE
-}
-
-const RegionOrSymbol getRegionOrSymbol(const SVal &Val) {
- if (const auto Reg = Val.getAsRegion()) {
- return Reg;
- } else if (const auto Sym = Val.getAsSymbol()) {
- return Sym;
- } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
- return LCVal->getRegion();
- }
- return RegionOrSymbol();
-}
-
-const ProgramStateRef processComparison(ProgramStateRef State,
- RegionOrSymbol LVal,
- RegionOrSymbol RVal, bool Equal) {
- const auto *LPos = getIteratorPosition(State, LVal);
- const auto *RPos = getIteratorPosition(State, RVal);
- if (LPos && !RPos) {
- State = adjustIteratorPosition(State, RVal, *LPos, Equal);
- } else if (!LPos && RPos) {
- State = adjustIteratorPosition(State, LVal, *RPos, Equal);
- } else if (LPos && RPos) {
- if (contradictingIteratorPositions(*LPos, *RPos, Equal)) {
- return nullptr;
- }
- }
- return State;
-}
-
-const ProgramStateRef saveComparison(ProgramStateRef State,
- const SymExpr *Condition, const SVal &LVal,
- const SVal &RVal, bool Eq) {
- const auto Left = getRegionOrSymbol(LVal);
- const auto Right = getRegionOrSymbol(RVal);
- if (!Left || !Right)
- return State;
- return State->set<IteratorComparisonMap>(Condition,
- IteratorComparison(Left, Right, Eq));
-}
-
-const IteratorComparison *loadComparison(ProgramStateRef State,
- const SymExpr *Condition) {
- return State->get<IteratorComparisonMap>(Condition);
-}
-
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- const SVal &Val) {
- if (const auto Reg = Val.getAsRegion()) {
- return State->get<IteratorRegionMap>(Reg);
- } else if (const auto Sym = Val.getAsSymbol()) {
- return State->get<IteratorSymbolMap>(Sym);
- } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
- return State->get<IteratorRegionMap>(LCVal->getRegion());
- }
- return nullptr;
-}
-
-const IteratorPosition *getIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym) {
- if (RegOrSym.is<const MemRegion *>()) {
- return State->get<IteratorRegionMap>(RegOrSym.get<const MemRegion *>());
- } else if (RegOrSym.is<SymbolRef>()) {
- return State->get<IteratorSymbolMap>(RegOrSym.get<SymbolRef>());
- }
- return nullptr;
-}
-
-ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
- IteratorPosition Pos) {
- if (const auto Reg = Val.getAsRegion()) {
- return State->set<IteratorRegionMap>(Reg, Pos);
- } else if (const auto Sym = Val.getAsSymbol()) {
- return State->set<IteratorSymbolMap>(Sym, Pos);
- } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
- return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
- }
- return nullptr;
-}
-
-ProgramStateRef setIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym,
- IteratorPosition Pos) {
- if (RegOrSym.is<const MemRegion *>()) {
- return State->set<IteratorRegionMap>(RegOrSym.get<const MemRegion *>(),
- Pos);
- } else if (RegOrSym.is<SymbolRef>()) {
- return State->set<IteratorSymbolMap>(RegOrSym.get<SymbolRef>(), Pos);
- }
- return nullptr;
-}
-
-ProgramStateRef adjustIteratorPosition(ProgramStateRef State,
- RegionOrSymbol RegOrSym,
- IteratorPosition Pos, bool Equal) {
-
- if ((Pos.isInRange() && Equal) || (Pos.isOutofRange() && !Equal)) {
- return setIteratorPosition(State, RegOrSym, IteratorPosition::getInRange());
- } else if (Pos.isOutofRange() && Equal) {
- return setIteratorPosition(State, RegOrSym,
- IteratorPosition::getOutofRange());
- } else {
- return State;
- }
-}
-
-bool contradictingIteratorPositions(IteratorPosition Pos1,
- IteratorPosition Pos2, bool Equal) {
- return ((Pos1 != Pos2) && Equal) ||
- ((Pos1.isOutofRange() && Pos2.isOutofRange()) && !Equal);
-}
-}
-
-void ento::registerIteratorPastEndChecker(CheckerManager &Mgr) {
- Mgr.registerChecker<IteratorPastEndChecker>();
-}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index af35c2b..655ce33 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -57,7 +57,7 @@ public:
};
class NonLocalizedStringChecker
- : public Checker<check::PostCall, check::PreObjCMessage,
+ : public Checker<check::PreCall, check::PostCall, check::PreObjCMessage,
check::PostObjCMessage,
check::PostStmt<ObjCStringLiteral>> {
@@ -79,9 +79,10 @@ class NonLocalizedStringChecker
void setNonLocalizedState(SVal S, CheckerContext &C) const;
void setLocalizedState(SVal S, CheckerContext &C) const;
- bool isAnnotatedAsLocalized(const Decl *D) const;
- void reportLocalizationError(SVal S, const ObjCMethodCall &M,
- CheckerContext &C, int argumentNumber = 0) const;
+ bool isAnnotatedAsReturningLocalized(const Decl *D) const;
+ bool isAnnotatedAsTakingLocalized(const Decl *D) const;
+ void reportLocalizationError(SVal S, const CallEvent &M, CheckerContext &C,
+ int argumentNumber = 0) const;
int getLocalizedArgumentForSelector(const IdentifierInfo *Receiver,
Selector S) const;
@@ -97,6 +98,7 @@ public:
void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
void checkPostStmt(const ObjCStringLiteral *SL, CheckerContext &C) const;
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
};
@@ -281,6 +283,9 @@ void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const {
IdentifierInfo *setLabelNSSegmentedControl[] = {
&Ctx.Idents.get("setLabel"), &Ctx.Idents.get("forSegment")};
ADD_METHOD(NSSegmentedControl, setLabelNSSegmentedControl, 2, 0)
+ IdentifierInfo *setToolTipNSSegmentedControl[] = {
+ &Ctx.Idents.get("setToolTip"), &Ctx.Idents.get("forSegment")};
+ ADD_METHOD(NSSegmentedControl, setToolTipNSSegmentedControl, 2, 0)
NEW_RECEIVER(NSButtonCell)
ADD_UNARY_METHOD(NSButtonCell, setTitle, 0)
@@ -562,6 +567,46 @@ void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const {
IdentifierInfo *setTitleUISegmentedControl[] = {
&Ctx.Idents.get("setTitle"), &Ctx.Idents.get("forSegmentAtIndex")};
ADD_METHOD(UISegmentedControl, setTitleUISegmentedControl, 2, 0)
+
+ NEW_RECEIVER(NSAccessibilityCustomRotorItemResult)
+ IdentifierInfo
+ *initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult[] = {
+ &Ctx.Idents.get("initWithItemLoadingToken"),
+ &Ctx.Idents.get("customLabel")};
+ ADD_METHOD(NSAccessibilityCustomRotorItemResult,
+ initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult, 2, 1)
+ ADD_UNARY_METHOD(NSAccessibilityCustomRotorItemResult, setCustomLabel, 0)
+
+ NEW_RECEIVER(UIContextualAction)
+ IdentifierInfo *contextualActionWithStyleUIContextualAction[] = {
+ &Ctx.Idents.get("contextualActionWithStyle"), &Ctx.Idents.get("title"),
+ &Ctx.Idents.get("handler")};
+ ADD_METHOD(UIContextualAction, contextualActionWithStyleUIContextualAction, 3,
+ 1)
+ ADD_UNARY_METHOD(UIContextualAction, setTitle, 0)
+
+ NEW_RECEIVER(NSAccessibilityCustomRotor)
+ IdentifierInfo *initWithLabelNSAccessibilityCustomRotor[] = {
+ &Ctx.Idents.get("initWithLabel"), &Ctx.Idents.get("itemSearchDelegate")};
+ ADD_METHOD(NSAccessibilityCustomRotor,
+ initWithLabelNSAccessibilityCustomRotor, 2, 0)
+ ADD_UNARY_METHOD(NSAccessibilityCustomRotor, setLabel, 0)
+
+ NEW_RECEIVER(NSWindowTab)
+ ADD_UNARY_METHOD(NSWindowTab, setTitle, 0)
+ ADD_UNARY_METHOD(NSWindowTab, setToolTip, 0)
+
+ NEW_RECEIVER(NSAccessibilityCustomAction)
+ IdentifierInfo *initWithNameNSAccessibilityCustomAction[] = {
+ &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("handler")};
+ ADD_METHOD(NSAccessibilityCustomAction,
+ initWithNameNSAccessibilityCustomAction, 2, 0)
+ IdentifierInfo *initWithNameTargetNSAccessibilityCustomAction[] = {
+ &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("target"),
+ &Ctx.Idents.get("selector")};
+ ADD_METHOD(NSAccessibilityCustomAction,
+ initWithNameTargetNSAccessibilityCustomAction, 3, 0)
+ ADD_UNARY_METHOD(NSAccessibilityCustomAction, setName, 0)
}
#define LSF_INSERT(function_name) LSF.insert(&Ctx.Idents.get(function_name));
@@ -601,7 +646,8 @@ void NonLocalizedStringChecker::initLocStringsMethods(ASTContext &Ctx) const {
/// Checks to see if the method / function declaration includes
/// __attribute__((annotate("returns_localized_nsstring")))
-bool NonLocalizedStringChecker::isAnnotatedAsLocalized(const Decl *D) const {
+bool NonLocalizedStringChecker::isAnnotatedAsReturningLocalized(
+ const Decl *D) const {
if (!D)
return false;
return std::any_of(
@@ -611,6 +657,19 @@ bool NonLocalizedStringChecker::isAnnotatedAsLocalized(const Decl *D) const {
});
}
+/// Checks to see if the method / function declaration includes
+/// __attribute__((annotate("takes_localized_nsstring")))
+bool NonLocalizedStringChecker::isAnnotatedAsTakingLocalized(
+ const Decl *D) const {
+ if (!D)
+ return false;
+ return std::any_of(
+ D->specific_attr_begin<AnnotateAttr>(),
+ D->specific_attr_end<AnnotateAttr>(), [](const AnnotateAttr *Ann) {
+ return Ann->getAnnotation() == "takes_localized_nsstring";
+ });
+}
+
/// Returns true if the given SVal is marked as Localized in the program state
bool NonLocalizedStringChecker::hasLocalizedState(SVal S,
CheckerContext &C) const {
@@ -690,8 +749,7 @@ static bool isDebuggingContext(CheckerContext &C) {
/// Reports a localization error for the passed in method call and SVal
void NonLocalizedStringChecker::reportLocalizationError(
- SVal S, const ObjCMethodCall &M, CheckerContext &C,
- int argumentNumber) const {
+ SVal S, const CallEvent &M, CheckerContext &C, int argumentNumber) const {
// Don't warn about localization errors in classes and methods that
// may be debug code.
@@ -789,7 +847,21 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
}
}
- if (argumentNumber < 0) // There was no match in UIMethods
+ if (argumentNumber < 0) { // There was no match in UIMethods
+ if (const Decl *D = msg.getDecl()) {
+ if (const ObjCMethodDecl *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
+ auto formals = OMD->parameters();
+ for (unsigned i = 0, ei = formals.size(); i != ei; ++i) {
+ if (isAnnotatedAsTakingLocalized(formals[i])) {
+ argumentNumber = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (argumentNumber < 0) // Still no match
return;
SVal svTitle = msg.getArgSVal(argumentNumber);
@@ -812,6 +884,25 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
}
}
+void NonLocalizedStringChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const Decl *D = Call.getDecl();
+ if (D && isa<FunctionDecl>(D)) {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ auto formals = FD->parameters();
+ for (unsigned i = 0,
+ ei = std::min(unsigned(formals.size()), Call.getNumArgs());
+ i != ei; ++i) {
+ if (isAnnotatedAsTakingLocalized(formals[i])) {
+ auto actual = Call.getArgSVal(i);
+ if (hasNonLocalizedState(actual, C)) {
+ reportLocalizationError(actual, Call, C, i + 1);
+ }
+ }
+ }
+ }
+}
+
static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
@@ -863,7 +954,7 @@ void NonLocalizedStringChecker::checkPostCall(const CallEvent &Call,
const IdentifierInfo *Identifier = Call.getCalleeIdentifier();
SVal sv = Call.getReturnValue();
- if (isAnnotatedAsLocalized(D) || LSF.count(Identifier) != 0) {
+ if (isAnnotatedAsReturningLocalized(D) || LSF.count(Identifier) != 0) {
setLocalizedState(sv, C);
} else if (isNSStringType(RT, C.getASTContext()) &&
!hasLocalizedState(sv, C)) {
@@ -897,7 +988,8 @@ void NonLocalizedStringChecker::checkPostObjCMessage(const ObjCMethodCall &msg,
std::pair<const IdentifierInfo *, Selector> MethodDescription = {odInfo, S};
- if (LSM.count(MethodDescription) || isAnnotatedAsLocalized(msg.getDecl())) {
+ if (LSM.count(MethodDescription) ||
+ isAnnotatedAsReturningLocalized(msg.getDecl())) {
SVal sv = msg.getReturnValue();
setLocalizedState(sv, C);
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
index c667b9e..696cf39 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
@@ -153,9 +153,9 @@ void MPIChecker::allRegionsUsedByWait(
MemRegionManager *const RegionManager = MR->getMemRegionManager();
if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
- const MemRegion *SuperRegion{nullptr};
+ const SubRegion *SuperRegion{nullptr};
if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
- SuperRegion = ER->getSuperRegion();
+ SuperRegion = cast<SubRegion>(ER->getSuperRegion());
}
// A single request is passed to MPI_Waitall.
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index f1aa163..f8473db 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -28,7 +28,8 @@ using namespace ento;
namespace {
class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
check::PostStmt<CallExpr>,
- check::DeadSymbols> {
+ check::DeadSymbols,
+ eval::Assume> {
mutable std::unique_ptr<BugType> BT;
public:
@@ -57,6 +58,10 @@ public:
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
+ ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
+ bool Assumption) const;
+ void printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const;
private:
typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
@@ -106,19 +111,6 @@ private:
std::unique_ptr<BugReport> generateAllocatedDataNotReleasedReport(
const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const;
- /// Check if RetSym evaluates to an error value in the current state.
- bool definitelyReturnedError(SymbolRef RetSym,
- ProgramStateRef State,
- SValBuilder &Builder,
- bool noError = false) const;
-
- /// Check if RetSym evaluates to a NoErr value in the current state.
- bool definitelyDidnotReturnError(SymbolRef RetSym,
- ProgramStateRef State,
- SValBuilder &Builder) const {
- return definitelyReturnedError(RetSym, State, Builder, true);
- }
-
/// Mark an AllocationPair interesting for diagnostic reporting.
void markInteresting(BugReport *R, const AllocationPair &AP) const {
R->markInteresting(AP.first);
@@ -221,24 +213,6 @@ static SymbolRef getAsPointeeSymbol(const Expr *Expr,
return nullptr;
}
-// When checking for error code, we need to consider the following cases:
-// 1) noErr / [0]
-// 2) someErr / [1, inf]
-// 3) unknown
-// If noError, returns true iff (1).
-// If !noError, returns true iff (2).
-bool MacOSKeychainAPIChecker::definitelyReturnedError(SymbolRef RetSym,
- ProgramStateRef State,
- SValBuilder &Builder,
- bool noError) const {
- DefinedOrUnknownSVal NoErrVal = Builder.makeIntVal(NoErr,
- Builder.getSymbolManager().getType(RetSym));
- DefinedOrUnknownSVal NoErr = Builder.evalEQ(State, NoErrVal,
- nonloc::SymbolVal(RetSym));
- ProgramStateRef ErrState = State->assume(NoErr, noError);
- return ErrState == State;
-}
-
// Report deallocator mismatch. Remove the region from tracking - reporting a
// missing free error after this one is redundant.
void MacOSKeychainAPIChecker::
@@ -289,27 +263,25 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
const Expr *ArgExpr = CE->getArg(paramIdx);
if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C))
if (const AllocationState *AS = State->get<AllocatedData>(V)) {
- if (!definitelyReturnedError(AS->Region, State, C.getSValBuilder())) {
- // Remove the value from the state. The new symbol will be added for
- // tracking when the second allocator is processed in checkPostStmt().
- State = State->remove<AllocatedData>(V);
- ExplodedNode *N = C.generateNonFatalErrorNode(State);
- if (!N)
- return;
- initBugType();
- SmallString<128> sbuf;
- llvm::raw_svector_ostream os(sbuf);
- unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
- os << "Allocated data should be released before another call to "
- << "the allocator: missing a call to '"
- << FunctionsToTrack[DIdx].Name
- << "'.";
- auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
- Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(V));
- Report->addRange(ArgExpr->getSourceRange());
- Report->markInteresting(AS->Region);
- C.emitReport(std::move(Report));
- }
+ // Remove the value from the state. The new symbol will be added for
+ // tracking when the second allocator is processed in checkPostStmt().
+ State = State->remove<AllocatedData>(V);
+ ExplodedNode *N = C.generateNonFatalErrorNode(State);
+ if (!N)
+ return;
+ initBugType();
+ SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+ unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
+ os << "Allocated data should be released before another call to "
+ << "the allocator: missing a call to '"
+ << FunctionsToTrack[DIdx].Name
+ << "'.";
+ auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
+ Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(V));
+ Report->addRange(ArgExpr->getSourceRange());
+ Report->markInteresting(AS->Region);
+ C.emitReport(std::move(Report));
}
return;
}
@@ -344,13 +316,12 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
// Is the argument to the call being tracked?
const AllocationState *AS = State->get<AllocatedData>(ArgSM);
- if (!AS && FunctionsToTrack[idx].Kind != ValidAPI) {
+ if (!AS)
return;
- }
- // If trying to free data which has not been allocated yet, report as a bug.
- // TODO: We might want a more precise diagnostic for double free
+
+ // TODO: We might want to report double free here.
// (that would involve tracking all the freed symbols in the checker state).
- if (!AS || RegionArgIsBad) {
+ if (RegionArgIsBad) {
// It is possible that this is a false positive - the argument might
// have entered as an enclosing function parameter.
if (isEnclosingFunctionParam(ArgExpr))
@@ -418,23 +389,6 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
return;
}
- // If the buffer can be null and the return status can be an error,
- // report a bad call to free.
- if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) &&
- !definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
- ExplodedNode *N = C.generateNonFatalErrorNode(State);
- if (!N)
- return;
- initBugType();
- auto Report = llvm::make_unique<BugReport>(
- *BT, "Only call free if a valid (non-NULL) buffer was returned.", N);
- Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(ArgSM));
- Report->addRange(ArgExpr->getSourceRange());
- Report->markInteresting(AS->Region);
- C.emitReport(std::move(Report));
- return;
- }
-
C.addTransition(State);
}
@@ -540,27 +494,63 @@ MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
return Report;
}
+/// If the return symbol is assumed to be error, remove the allocated info
+/// from consideration.
+ProgramStateRef MacOSKeychainAPIChecker::evalAssume(ProgramStateRef State,
+ SVal Cond,
+ bool Assumption) const {
+ AllocatedDataTy AMap = State->get<AllocatedData>();
+ if (AMap.isEmpty())
+ return State;
+
+ auto *CondBSE = dyn_cast_or_null<BinarySymExpr>(Cond.getAsSymExpr());
+ if (!CondBSE)
+ return State;
+ BinaryOperator::Opcode OpCode = CondBSE->getOpcode();
+ if (OpCode != BO_EQ && OpCode != BO_NE)
+ return State;
+
+ // Match for a restricted set of patterns for cmparison of error codes.
+ // Note, the comparisons of type '0 == st' are transformed into SymIntExpr.
+ SymbolRef ReturnSymbol = nullptr;
+ if (auto *SIE = dyn_cast<SymIntExpr>(CondBSE)) {
+ const llvm::APInt &RHS = SIE->getRHS();
+ bool ErrorIsReturned = (OpCode == BO_EQ && RHS != NoErr) ||
+ (OpCode == BO_NE && RHS == NoErr);
+ if (!Assumption)
+ ErrorIsReturned = !ErrorIsReturned;
+ if (ErrorIsReturned)
+ ReturnSymbol = SIE->getLHS();
+ }
+
+ if (ReturnSymbol)
+ for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) {
+ if (ReturnSymbol == I->second.Region)
+ State = State->remove<AllocatedData>(I->first);
+ }
+
+ return State;
+}
+
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
- AllocatedDataTy ASet = State->get<AllocatedData>();
- if (ASet.isEmpty())
+ AllocatedDataTy AMap = State->get<AllocatedData>();
+ if (AMap.isEmpty())
return;
bool Changed = false;
AllocationPairVec Errors;
- for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
- if (SR.isLive(I->first))
+ for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) {
+ if (!SR.isDead(I->first))
continue;
Changed = true;
State = State->remove<AllocatedData>(I->first);
- // If the allocated symbol is null or if the allocation call might have
- // returned an error, do not report.
+ // If the allocated symbol is null do not report.
ConstraintManager &CMgr = State->getConstraintManager();
ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey());
- if (AllocFailed.isConstrainedTrue() ||
- definitelyReturnedError(I->second.Region, State, C.getSValBuilder()))
+ if (AllocFailed.isConstrainedTrue())
continue;
Errors.push_back(std::make_pair(I->first, &I->second));
}
@@ -612,6 +602,22 @@ MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
"Data is allocated here.");
}
+void MacOSKeychainAPIChecker::printState(raw_ostream &Out,
+ ProgramStateRef State,
+ const char *NL,
+ const char *Sep) const {
+
+ AllocatedDataTy AMap = State->get<AllocatedData>();
+
+ if (!AMap.isEmpty()) {
+ Out << Sep << "KeychainAPIChecker :" << NL;
+ for (auto I = AMap.begin(), E = AMap.end(); I != E; ++I) {
+ I.getKey()->dumpToStream(Out);
+ }
+ }
+}
+
+
void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) {
mgr.registerChecker<MacOSKeychainAPIChecker>();
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 8e839a1..8511140 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@@ -174,7 +175,13 @@ public:
II_valloc(nullptr), II_reallocf(nullptr), II_strndup(nullptr),
II_strdup(nullptr), II_win_strdup(nullptr), II_kmalloc(nullptr),
II_if_nameindex(nullptr), II_if_freenameindex(nullptr),
- II_wcsdup(nullptr), II_win_wcsdup(nullptr) {}
+ II_wcsdup(nullptr), II_win_wcsdup(nullptr), II_g_malloc(nullptr),
+ II_g_malloc0(nullptr), II_g_realloc(nullptr), II_g_try_malloc(nullptr),
+ II_g_try_malloc0(nullptr), II_g_try_realloc(nullptr),
+ II_g_free(nullptr), II_g_memdup(nullptr), II_g_malloc_n(nullptr),
+ II_g_malloc0_n(nullptr), II_g_realloc_n(nullptr),
+ II_g_try_malloc_n(nullptr), II_g_try_malloc0_n(nullptr),
+ II_g_try_realloc_n(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
@@ -236,7 +243,12 @@ private:
*II_realloc, *II_calloc, *II_valloc, *II_reallocf,
*II_strndup, *II_strdup, *II_win_strdup, *II_kmalloc,
*II_if_nameindex, *II_if_freenameindex, *II_wcsdup,
- *II_win_wcsdup;
+ *II_win_wcsdup, *II_g_malloc, *II_g_malloc0,
+ *II_g_realloc, *II_g_try_malloc, *II_g_try_malloc0,
+ *II_g_try_realloc, *II_g_free, *II_g_memdup,
+ *II_g_malloc_n, *II_g_malloc0_n, *II_g_realloc_n,
+ *II_g_try_malloc_n, *II_g_try_malloc0_n,
+ *II_g_try_realloc_n;
mutable Optional<uint64_t> KernelZeroFlagVal;
void initIdentifierInfo(ASTContext &C) const;
@@ -316,9 +328,12 @@ private:
bool &ReleasedAllocated,
bool ReturnsNullOnFailure = false) const;
- ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
- bool FreesMemOnFailure,
- ProgramStateRef State) const;
+ ProgramStateRef ReallocMemAux(CheckerContext &C, const CallExpr *CE,
+ bool FreesMemOnFailure,
+ ProgramStateRef State,
+ bool SuffixWithN = false) const;
+ static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
+ const Expr *BlockBytes);
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State);
@@ -387,6 +402,9 @@ private:
void ReportUseZeroAllocated(CheckerContext &C, SourceRange Range,
SymbolRef Sym) const;
+ void ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
+ SourceRange Range, const Expr *FreeExpr) const;
+
/// Find the location of the allocation for Sym on the path leading to the
/// exploded node N.
LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
@@ -554,6 +572,22 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
II_win_strdup = &Ctx.Idents.get("_strdup");
II_win_wcsdup = &Ctx.Idents.get("_wcsdup");
II_win_alloca = &Ctx.Idents.get("_alloca");
+
+ // Glib
+ II_g_malloc = &Ctx.Idents.get("g_malloc");
+ II_g_malloc0 = &Ctx.Idents.get("g_malloc0");
+ II_g_realloc = &Ctx.Idents.get("g_realloc");
+ II_g_try_malloc = &Ctx.Idents.get("g_try_malloc");
+ II_g_try_malloc0 = &Ctx.Idents.get("g_try_malloc0");
+ II_g_try_realloc = &Ctx.Idents.get("g_try_realloc");
+ II_g_free = &Ctx.Idents.get("g_free");
+ II_g_memdup = &Ctx.Idents.get("g_memdup");
+ II_g_malloc_n = &Ctx.Idents.get("g_malloc_n");
+ II_g_malloc0_n = &Ctx.Idents.get("g_malloc0_n");
+ II_g_realloc_n = &Ctx.Idents.get("g_realloc_n");
+ II_g_try_malloc_n = &Ctx.Idents.get("g_try_malloc_n");
+ II_g_try_malloc0_n = &Ctx.Idents.get("g_try_malloc0_n");
+ II_g_try_realloc_n = &Ctx.Idents.get("g_try_realloc_n");
}
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
@@ -589,7 +623,8 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
initIdentifierInfo(C);
if (Family == AF_Malloc && CheckFree) {
- if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf)
+ if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf ||
+ FunI == II_g_free)
return true;
}
@@ -597,7 +632,14 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
if (FunI == II_malloc || FunI == II_realloc || FunI == II_reallocf ||
FunI == II_calloc || FunI == II_valloc || FunI == II_strdup ||
FunI == II_win_strdup || FunI == II_strndup || FunI == II_wcsdup ||
- FunI == II_win_wcsdup || FunI == II_kmalloc)
+ FunI == II_win_wcsdup || FunI == II_kmalloc ||
+ FunI == II_g_malloc || FunI == II_g_malloc0 ||
+ FunI == II_g_realloc || FunI == II_g_try_malloc ||
+ FunI == II_g_try_malloc0 || FunI == II_g_try_realloc ||
+ FunI == II_g_memdup || FunI == II_g_malloc_n ||
+ FunI == II_g_malloc0_n || FunI == II_g_realloc_n ||
+ FunI == II_g_try_malloc_n || FunI == II_g_try_malloc0_n ||
+ FunI == II_g_try_realloc_n)
return true;
}
@@ -747,6 +789,17 @@ llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(
return None;
}
+SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
+ const Expr *BlockBytes) {
+ SValBuilder &SB = C.getSValBuilder();
+ SVal BlocksVal = C.getSVal(Blocks);
+ SVal BlockBytesVal = C.getSVal(BlockBytes);
+ ProgramStateRef State = C.getState();
+ SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
+ SB.getContext().getSizeType());
+ return TotalSize;
+}
+
void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
if (C.wasInlined)
return;
@@ -762,7 +815,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
initIdentifierInfo(C.getASTContext());
IdentifierInfo *FunI = FD->getIdentifier();
- if (FunI == II_malloc) {
+ if (FunI == II_malloc || FunI == II_g_malloc || FunI == II_g_try_malloc) {
if (CE->getNumArgs() < 1)
return;
if (CE->getNumArgs() < 3) {
@@ -791,17 +844,18 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
State = ProcessZeroAllocation(C, CE, 0, State);
- } else if (FunI == II_realloc) {
- State = ReallocMem(C, CE, false, State);
+ } else if (FunI == II_realloc || FunI == II_g_realloc ||
+ FunI == II_g_try_realloc) {
+ State = ReallocMemAux(C, CE, false, State);
State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_reallocf) {
- State = ReallocMem(C, CE, true, State);
+ State = ReallocMemAux(C, CE, true, State);
State = ProcessZeroAllocation(C, CE, 1, State);
} else if (FunI == II_calloc) {
State = CallocMem(C, CE, State);
State = ProcessZeroAllocation(C, CE, 0, State);
State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_free) {
+ } else if (FunI == II_free || FunI == II_g_free) {
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
} else if (FunI == II_strdup || FunI == II_win_strdup ||
FunI == II_wcsdup || FunI == II_win_wcsdup) {
@@ -841,6 +895,37 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
AF_IfNameIndex);
} else if (FunI == II_if_freenameindex) {
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
+ } else if (FunI == II_g_malloc0 || FunI == II_g_try_malloc0) {
+ if (CE->getNumArgs() < 1)
+ return;
+ SValBuilder &svalBuilder = C.getSValBuilder();
+ SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
+ State = MallocMemAux(C, CE, CE->getArg(0), zeroVal, State);
+ State = ProcessZeroAllocation(C, CE, 0, State);
+ } else if (FunI == II_g_memdup) {
+ if (CE->getNumArgs() < 2)
+ return;
+ State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State);
+ State = ProcessZeroAllocation(C, CE, 1, State);
+ } else if (FunI == II_g_malloc_n || FunI == II_g_try_malloc_n ||
+ FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
+ if (CE->getNumArgs() < 2)
+ return;
+ SVal Init = UndefinedVal();
+ if (FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
+ SValBuilder &SB = C.getSValBuilder();
+ Init = SB.makeZeroVal(SB.getContext().CharTy);
+ }
+ SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
+ State = MallocMemAux(C, CE, TotalSize, Init, State);
+ State = ProcessZeroAllocation(C, CE, 0, State);
+ State = ProcessZeroAllocation(C, CE, 1, State);
+ } else if (FunI == II_g_realloc_n || FunI == II_g_try_realloc_n) {
+ if (CE->getNumArgs() < 3)
+ return;
+ State = ReallocMemAux(C, CE, false, State, true);
+ State = ProcessZeroAllocation(C, CE, 1, State);
+ State = ProcessZeroAllocation(C, CE, 2, State);
}
}
@@ -1154,7 +1239,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
// Fill the region with the initialization value.
- State = State->bindDefault(RetVal, Init);
+ State = State->bindDefault(RetVal, Init, LCtx);
// Set the region's extent equal to the Size parameter.
const SymbolicRegion *R =
@@ -1483,6 +1568,11 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
}
}
+ if (SymBase->getType()->isFunctionPointerType()) {
+ ReportFunctionPointerFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
+ return nullptr;
+ }
+
ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() ||
RsBase->isAllocatedOfSizeZero());
@@ -1664,8 +1754,8 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_BadFree[*CheckKind])
- BT_BadFree[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error"));
+ BT_BadFree[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Bad free", categories::MemoryError));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -1709,8 +1799,8 @@ void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_FreeAlloca[*CheckKind])
- BT_FreeAlloca[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Free alloca()", "Memory Error"));
+ BT_FreeAlloca[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Free alloca()", categories::MemoryError));
auto R = llvm::make_unique<BugReport>(
*BT_FreeAlloca[*CheckKind],
@@ -1735,7 +1825,7 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
if (!BT_MismatchedDealloc)
BT_MismatchedDealloc.reset(
new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
- "Bad deallocator", "Memory Error"));
+ "Bad deallocator", categories::MemoryError));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -1795,8 +1885,8 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
return;
if (!BT_OffsetFree[*CheckKind])
- BT_OffsetFree[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Offset free", "Memory Error"));
+ BT_OffsetFree[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Offset free", categories::MemoryError));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -1847,7 +1937,7 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_UseFree[*CheckKind])
BT_UseFree[*CheckKind].reset(new BugType(
- CheckNames[*CheckKind], "Use-after-free", "Memory Error"));
+ CheckNames[*CheckKind], "Use-after-free", categories::MemoryError));
auto R = llvm::make_unique<BugReport>(*BT_UseFree[*CheckKind],
"Use of memory after it is freed", N);
@@ -1873,8 +1963,8 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_DoubleFree[*CheckKind])
- BT_DoubleFree[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Double free", "Memory Error"));
+ BT_DoubleFree[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Double free", categories::MemoryError));
auto R = llvm::make_unique<BugReport>(
*BT_DoubleFree[*CheckKind],
@@ -1902,7 +1992,8 @@ void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_DoubleDelete)
BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker],
- "Double delete", "Memory Error"));
+ "Double delete",
+ categories::MemoryError));
auto R = llvm::make_unique<BugReport>(
*BT_DoubleDelete, "Attempt to delete released memory", N);
@@ -1928,8 +2019,9 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_UseZerroAllocated[*CheckKind])
- BT_UseZerroAllocated[*CheckKind].reset(new BugType(
- CheckNames[*CheckKind], "Use of zero allocated", "Memory Error"));
+ BT_UseZerroAllocated[*CheckKind].reset(
+ new BugType(CheckNames[*CheckKind], "Use of zero allocated",
+ categories::MemoryError));
auto R = llvm::make_unique<BugReport>(*BT_UseZerroAllocated[*CheckKind],
"Use of zero-allocated memory", N);
@@ -1943,14 +2035,52 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C,
}
}
-ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
- const CallExpr *CE,
- bool FreesOnFail,
- ProgramStateRef State) const {
+void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
+ SourceRange Range,
+ const Expr *FreeExpr) const {
+ if (!ChecksEnabled[CK_MallocChecker])
+ return;
+
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, FreeExpr);
+ if (!CheckKind.hasValue())
+ return;
+
+ if (ExplodedNode *N = C.generateErrorNode()) {
+ if (!BT_BadFree[*CheckKind])
+ BT_BadFree[*CheckKind].reset(
+ new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error"));
+
+ SmallString<100> Buf;
+ llvm::raw_svector_ostream Os(Buf);
+
+ const MemRegion *MR = ArgVal.getAsRegion();
+ while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
+ MR = ER->getSuperRegion();
+
+ Os << "Argument to ";
+ if (!printAllocDeallocName(Os, C, FreeExpr))
+ Os << "deallocator";
+
+ Os << " is a function pointer";
+
+ auto R = llvm::make_unique<BugReport>(*BT_BadFree[*CheckKind], Os.str(), N);
+ R->markInteresting(MR);
+ R->addRange(Range);
+ C.emitReport(std::move(R));
+ }
+}
+
+ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C,
+ const CallExpr *CE,
+ bool FreesOnFail,
+ ProgramStateRef State,
+ bool SuffixWithN) const {
if (!State)
return nullptr;
- if (CE->getNumArgs() < 2)
+ if (SuffixWithN && CE->getNumArgs() < 3)
+ return nullptr;
+ else if (CE->getNumArgs() < 2)
return nullptr;
const Expr *arg0Expr = CE->getArg(0);
@@ -1965,20 +2095,19 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
DefinedOrUnknownSVal PtrEQ =
svalBuilder.evalEQ(State, arg0Val, svalBuilder.makeNull());
- // Get the size argument. If there is no size arg then give up.
+ // Get the size argument.
const Expr *Arg1 = CE->getArg(1);
- if (!Arg1)
- return nullptr;
// Get the value of the size argument.
- SVal Arg1ValG = State->getSVal(Arg1, LCtx);
- if (!Arg1ValG.getAs<DefinedOrUnknownSVal>())
+ SVal TotalSize = State->getSVal(Arg1, LCtx);
+ if (SuffixWithN)
+ TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));
+ if (!TotalSize.getAs<DefinedOrUnknownSVal>())
return nullptr;
- DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();
// Compare the size argument to 0.
DefinedOrUnknownSVal SizeZero =
- svalBuilder.evalEQ(State, Arg1Val,
+ svalBuilder.evalEQ(State, TotalSize.castAs<DefinedOrUnknownSVal>(),
svalBuilder.makeIntValWithPtrWidth(0, false));
ProgramStateRef StatePtrIsNull, StatePtrNotNull;
@@ -1992,8 +2121,8 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
// If the ptr is NULL and the size is not 0, the call is equivalent to
// malloc(size).
- if ( PrtIsNull && !SizeIsZero) {
- ProgramStateRef stateMalloc = MallocMemAux(C, CE, CE->getArg(1),
+ if (PrtIsNull && !SizeIsZero) {
+ ProgramStateRef stateMalloc = MallocMemAux(C, CE, TotalSize,
UndefinedVal(), StatePtrIsNull);
return stateMalloc;
}
@@ -2026,7 +2155,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
if (ProgramStateRef stateFree =
FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) {
- ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
+ ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize,
UnknownVal(), stateFree);
if (!stateRealloc)
return nullptr;
@@ -2057,12 +2186,8 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
return nullptr;
SValBuilder &svalBuilder = C.getSValBuilder();
- const LocationContext *LCtx = C.getLocationContext();
- SVal count = State->getSVal(CE->getArg(0), LCtx);
- SVal elementSize = State->getSVal(CE->getArg(1), LCtx);
- SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, count, elementSize,
- svalBuilder.getContext().getSizeType());
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
+ SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
return MallocMemAux(C, CE, TotalSize, zeroVal, State);
}
@@ -2131,8 +2256,8 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
assert(N);
if (!BT_Leak[*CheckKind]) {
- BT_Leak[*CheckKind].reset(
- new BugType(CheckNames[*CheckKind], "Memory leak", "Memory Error"));
+ BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak",
+ categories::MemoryError));
// Leaks should not be reported if they are post-dominated by a sink:
// (1) Sinks are higher importance bugs.
// (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
new file mode 100644
index 0000000..decc552
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
@@ -0,0 +1,481 @@
+// MisusedMovedObjectChecker.cpp - Check use of moved-from objects. - C++ -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines checker which checks for potential misuses of a moved-from
+// object. That means method calls on the object or copying it in moved-from
+// state.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+struct RegionState {
+private:
+ enum Kind { Moved, Reported } K;
+ RegionState(Kind InK) : K(InK) {}
+
+public:
+ bool isReported() const { return K == Reported; }
+ bool isMoved() const { return K == Moved; }
+
+ static RegionState getReported() { return RegionState(Reported); }
+ static RegionState getMoved() { return RegionState(Moved); }
+
+ bool operator==(const RegionState &X) const { return K == X.K; }
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); }
+};
+
+class MisusedMovedObjectChecker
+ : public Checker<check::PreCall, check::PostCall, check::EndFunction,
+ check::DeadSymbols, check::RegionChanges> {
+public:
+ void checkEndFunction(CheckerContext &C) const;
+ void checkPreCall(const CallEvent &MC, CheckerContext &C) const;
+ void checkPostCall(const CallEvent &MC, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
+ ProgramStateRef
+ checkRegionChanges(ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx, const CallEvent *Call) const;
+
+private:
+ class MovedBugVisitor : public BugReporterVisitorImpl<MovedBugVisitor> {
+ public:
+ MovedBugVisitor(const MemRegion *R) : Region(R), Found(false) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ static int X = 0;
+ ID.AddPointer(&X);
+ ID.AddPointer(Region);
+ }
+
+ std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
+
+ private:
+ // The tracked region.
+ const MemRegion *Region;
+ bool Found;
+ };
+
+ mutable std::unique_ptr<BugType> BT;
+ ExplodedNode *reportBug(const MemRegion *Region, const CallEvent &Call,
+ CheckerContext &C, bool isCopy) const;
+ bool isInMoveSafeContext(const LocationContext *LC) const;
+ bool isStateResetMethod(const CXXMethodDecl *MethodDec) const;
+ bool isMoveSafeMethod(const CXXMethodDecl *MethodDec) const;
+ const ExplodedNode *getMoveLocation(const ExplodedNode *N,
+ const MemRegion *Region,
+ CheckerContext &C) const;
+};
+} // end anonymous namespace
+
+REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, RegionState)
+
+// If a region is removed all of the subregions needs to be removed too.
+static ProgramStateRef removeFromState(ProgramStateRef State,
+ const MemRegion *Region) {
+ if (!Region)
+ return State;
+ // Note: The isSubRegionOf function is not reflexive.
+ State = State->remove<TrackedRegionMap>(Region);
+ for (auto &E : State->get<TrackedRegionMap>()) {
+ if (E.first->isSubRegionOf(Region))
+ State = State->remove<TrackedRegionMap>(E.first);
+ }
+ return State;
+}
+
+static bool isAnyBaseRegionReported(ProgramStateRef State,
+ const MemRegion *Region) {
+ for (auto &E : State->get<TrackedRegionMap>()) {
+ if (Region->isSubRegionOf(E.first) && E.second.isReported())
+ return true;
+ }
+ return false;
+}
+
+std::shared_ptr<PathDiagnosticPiece>
+MisusedMovedObjectChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ // We need only the last move of the reported object's region.
+ // The visitor walks the ExplodedGraph backwards.
+ if (Found)
+ return nullptr;
+ ProgramStateRef State = N->getState();
+ ProgramStateRef StatePrev = PrevN->getState();
+ const RegionState *TrackedObject = State->get<TrackedRegionMap>(Region);
+ const RegionState *TrackedObjectPrev =
+ StatePrev->get<TrackedRegionMap>(Region);
+ if (!TrackedObject)
+ return nullptr;
+ if (TrackedObjectPrev && TrackedObject)
+ return nullptr;
+
+ // Retrieve the associated statement.
+ const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ if (!S)
+ return nullptr;
+ Found = true;
+
+ std::string ObjectName;
+ if (const auto DecReg = Region->getAs<DeclRegion>()) {
+ const auto *RegionDecl = dyn_cast<NamedDecl>(DecReg->getDecl());
+ ObjectName = RegionDecl->getNameAsString();
+ }
+ std::string InfoText;
+ if (ObjectName != "")
+ InfoText = "'" + ObjectName + "' became 'moved-from' here";
+ else
+ InfoText = "Became 'moved-from' here";
+
+ // Generate the extra diagnostic.
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
+ N->getLocationContext());
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText, true);
+}
+
+const ExplodedNode *MisusedMovedObjectChecker::getMoveLocation(
+ const ExplodedNode *N, const MemRegion *Region, CheckerContext &C) const {
+ // Walk the ExplodedGraph backwards and find the first node that referred to
+ // the tracked region.
+ const ExplodedNode *MoveNode = N;
+
+ while (N) {
+ ProgramStateRef State = N->getState();
+ if (!State->get<TrackedRegionMap>(Region))
+ break;
+ MoveNode = N;
+ N = N->pred_empty() ? nullptr : *(N->pred_begin());
+ }
+ return MoveNode;
+}
+
+ExplodedNode *MisusedMovedObjectChecker::reportBug(const MemRegion *Region,
+ const CallEvent &Call,
+ CheckerContext &C,
+ bool isCopy = false) const {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+ if (!BT)
+ BT.reset(new BugType(this, "Usage of a 'moved-from' object",
+ "C++ move semantics"));
+
+ // Uniqueing report to the same object.
+ PathDiagnosticLocation LocUsedForUniqueing;
+ const ExplodedNode *MoveNode = getMoveLocation(N, Region, C);
+
+ if (const Stmt *MoveStmt = PathDiagnosticLocation::getStmt(MoveNode))
+ LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
+ MoveStmt, C.getSourceManager(), MoveNode->getLocationContext());
+
+ // Creating the error message.
+ std::string ErrorMessage;
+ if (isCopy)
+ ErrorMessage = "Copying a 'moved-from' object";
+ else
+ ErrorMessage = "Method call on a 'moved-from' object";
+ if (const auto DecReg = Region->getAs<DeclRegion>()) {
+ const auto *RegionDecl = dyn_cast<NamedDecl>(DecReg->getDecl());
+ ErrorMessage += " '" + RegionDecl->getNameAsString() + "'";
+ }
+
+ auto R =
+ llvm::make_unique<BugReport>(*BT, ErrorMessage, N, LocUsedForUniqueing,
+ MoveNode->getLocationContext()->getDecl());
+ R->addVisitor(llvm::make_unique<MovedBugVisitor>(Region));
+ C.emitReport(std::move(R));
+ return N;
+ }
+ return nullptr;
+}
+
+// Removing the function parameters' MemRegion from the state. This is needed
+// for PODs where the trivial destructor does not even created nor executed.
+void MisusedMovedObjectChecker::checkEndFunction(CheckerContext &C) const {
+ auto State = C.getState();
+ TrackedRegionMapTy Objects = State->get<TrackedRegionMap>();
+ if (Objects.isEmpty())
+ return;
+
+ auto LC = C.getLocationContext();
+
+ const auto LD = dyn_cast_or_null<FunctionDecl>(LC->getDecl());
+ if (!LD)
+ return;
+ llvm::SmallSet<const MemRegion *, 8> InvalidRegions;
+
+ for (auto Param : LD->parameters()) {
+ auto Type = Param->getType().getTypePtrOrNull();
+ if (!Type)
+ continue;
+ if (!Type->isPointerType() && !Type->isReferenceType()) {
+ InvalidRegions.insert(State->getLValue(Param, LC).getAsRegion());
+ }
+ }
+
+ if (InvalidRegions.empty())
+ return;
+
+ for (const auto &E : State->get<TrackedRegionMap>()) {
+ if (InvalidRegions.count(E.first->getBaseRegion()))
+ State = State->remove<TrackedRegionMap>(E.first);
+ }
+
+ C.addTransition(State);
+}
+
+void MisusedMovedObjectChecker::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const auto *AFC = dyn_cast<AnyFunctionCall>(&Call);
+ if (!AFC)
+ return;
+
+ ProgramStateRef State = C.getState();
+ const auto MethodDecl = dyn_cast_or_null<CXXMethodDecl>(AFC->getDecl());
+ if (!MethodDecl)
+ return;
+
+ const auto *ConstructorDecl = dyn_cast<CXXConstructorDecl>(MethodDecl);
+
+ const auto *CC = dyn_cast_or_null<CXXConstructorCall>(&Call);
+ // Check if an object became moved-from.
+ // Object can become moved from after a call to move assignment operator or
+ // move constructor .
+ if (ConstructorDecl && !ConstructorDecl->isMoveConstructor())
+ return;
+
+ if (!ConstructorDecl && !MethodDecl->isMoveAssignmentOperator())
+ return;
+
+ const auto ArgRegion = AFC->getArgSVal(0).getAsRegion();
+ if (!ArgRegion)
+ return;
+
+ // Skip moving the object to itself.
+ if (CC && CC->getCXXThisVal().getAsRegion() == ArgRegion)
+ return;
+ if (const auto *IC = dyn_cast<CXXInstanceCall>(AFC))
+ if (IC->getCXXThisVal().getAsRegion() == ArgRegion)
+ return;
+
+ const MemRegion *BaseRegion = ArgRegion->getBaseRegion();
+ // Skip temp objects because of their short lifetime.
+ if (BaseRegion->getAs<CXXTempObjectRegion>() ||
+ AFC->getArgExpr(0)->isRValue())
+ return;
+ // If it has already been reported do not need to modify the state.
+
+ if (State->get<TrackedRegionMap>(ArgRegion))
+ return;
+ // Mark object as moved-from.
+ State = State->set<TrackedRegionMap>(ArgRegion, RegionState::getMoved());
+ C.addTransition(State);
+}
+
+bool MisusedMovedObjectChecker::isMoveSafeMethod(
+ const CXXMethodDecl *MethodDec) const {
+ // We abandon the cases where bool/void/void* conversion happens.
+ if (const auto *ConversionDec =
+ dyn_cast_or_null<CXXConversionDecl>(MethodDec)) {
+ const Type *Tp = ConversionDec->getConversionType().getTypePtrOrNull();
+ if (!Tp)
+ return false;
+ if (Tp->isBooleanType() || Tp->isVoidType() || Tp->isVoidPointerType())
+ return true;
+ }
+ // Function call `empty` can be skipped.
+ if (MethodDec && MethodDec->getDeclName().isIdentifier() &&
+ (MethodDec->getName().lower() == "empty" ||
+ MethodDec->getName().lower() == "isempty"))
+ return true;
+
+ return false;
+}
+
+bool MisusedMovedObjectChecker::isStateResetMethod(
+ const CXXMethodDecl *MethodDec) const {
+ if (MethodDec && MethodDec->getDeclName().isIdentifier()) {
+ std::string MethodName = MethodDec->getName().lower();
+ if (MethodName == "reset" || MethodName == "clear" ||
+ MethodName == "destroy")
+ return true;
+ }
+ return false;
+}
+
+// Don't report an error inside a move related operation.
+// We assume that the programmer knows what she does.
+bool MisusedMovedObjectChecker::isInMoveSafeContext(
+ const LocationContext *LC) const {
+ do {
+ const auto *CtxDec = LC->getDecl();
+ auto *CtorDec = dyn_cast_or_null<CXXConstructorDecl>(CtxDec);
+ auto *DtorDec = dyn_cast_or_null<CXXDestructorDecl>(CtxDec);
+ auto *MethodDec = dyn_cast_or_null<CXXMethodDecl>(CtxDec);
+ if (DtorDec || (CtorDec && CtorDec->isCopyOrMoveConstructor()) ||
+ (MethodDec && MethodDec->isOverloadedOperator() &&
+ MethodDec->getOverloadedOperator() == OO_Equal) ||
+ isStateResetMethod(MethodDec) || isMoveSafeMethod(MethodDec))
+ return true;
+ } while ((LC = LC->getParent()));
+ return false;
+}
+
+void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ const LocationContext *LC = C.getLocationContext();
+ ExplodedNode *N = nullptr;
+
+ // Remove the MemRegions from the map on which a ctor/dtor call or assignement
+ // happened.
+
+ // Checking constructor calls.
+ if (const auto *CC = dyn_cast<CXXConstructorCall>(&Call)) {
+ State = removeFromState(State, CC->getCXXThisVal().getAsRegion());
+ auto CtorDec = CC->getDecl();
+ // Check for copying a moved-from object and report the bug.
+ if (CtorDec && CtorDec->isCopyOrMoveConstructor()) {
+ const MemRegion *ArgRegion = CC->getArgSVal(0).getAsRegion();
+ const RegionState *ArgState = State->get<TrackedRegionMap>(ArgRegion);
+ if (ArgState && ArgState->isMoved()) {
+ if (!isInMoveSafeContext(LC)) {
+ N = reportBug(ArgRegion, Call, C, /*isCopy=*/true);
+ State = State->set<TrackedRegionMap>(ArgRegion,
+ RegionState::getReported());
+ }
+ }
+ }
+ C.addTransition(State, N);
+ return;
+ }
+
+ const auto IC = dyn_cast<CXXInstanceCall>(&Call);
+ if (!IC)
+ return;
+ // In case of destructor call we do not track the object anymore.
+ const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
+ if (dyn_cast_or_null<CXXDestructorDecl>(Call.getDecl())) {
+ State = removeFromState(State, IC->getCXXThisVal().getAsRegion());
+ C.addTransition(State);
+ return;
+ }
+
+ const auto MethodDecl = dyn_cast_or_null<CXXMethodDecl>(IC->getDecl());
+ if (!MethodDecl)
+ return;
+ // Checking assignment operators.
+ bool OperatorEq = MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal;
+ // Remove the tracked object for every assignment operator, but report bug
+ // only for move or copy assignment's argument.
+ if (OperatorEq) {
+ State = removeFromState(State, ThisRegion);
+ if (MethodDecl->isCopyAssignmentOperator() ||
+ MethodDecl->isMoveAssignmentOperator()) {
+ const RegionState *ArgState =
+ State->get<TrackedRegionMap>(IC->getArgSVal(0).getAsRegion());
+ if (ArgState && ArgState->isMoved() && !isInMoveSafeContext(LC)) {
+ const MemRegion *ArgRegion = IC->getArgSVal(0).getAsRegion();
+ N = reportBug(ArgRegion, Call, C, /*isCopy=*/true);
+ State =
+ State->set<TrackedRegionMap>(ArgRegion, RegionState::getReported());
+ }
+ }
+ C.addTransition(State, N);
+ return;
+ }
+
+ // The remaining part is check only for method call on a moved-from object.
+ if (isMoveSafeMethod(MethodDecl))
+ return;
+
+ if (isStateResetMethod(MethodDecl)) {
+ State = State->remove<TrackedRegionMap>(ThisRegion);
+ C.addTransition(State);
+ return;
+ }
+
+ // If it is already reported then we dont report the bug again.
+ const RegionState *ThisState = State->get<TrackedRegionMap>(ThisRegion);
+ if (!(ThisState && ThisState->isMoved()))
+ return;
+
+ // Dont report it in case if any base region is already reported
+ if (isAnyBaseRegionReported(State, ThisRegion))
+ return;
+
+ if (isInMoveSafeContext(LC))
+ return;
+
+ N = reportBug(ThisRegion, Call, C);
+ State = State->set<TrackedRegionMap>(ThisRegion, RegionState::getReported());
+ C.addTransition(State, N);
+}
+
+void MisusedMovedObjectChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
+ for (TrackedRegionMapTy::value_type E : TrackedRegions) {
+ const MemRegion *Region = E.first;
+ bool IsRegDead = !SymReaper.isLiveRegion(Region);
+
+ // Remove the dead regions from the region map.
+ if (IsRegDead) {
+ State = State->remove<TrackedRegionMap>(Region);
+ }
+ }
+ C.addTransition(State);
+}
+
+ProgramStateRef MisusedMovedObjectChecker::checkRegionChanges(
+ ProgramStateRef State, const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
+ const CallEvent *Call) const {
+ // In case of an InstanceCall don't remove the ThisRegion from the GDM since
+ // it is handled in checkPreCall and checkPostCall.
+ const MemRegion *ThisRegion = nullptr;
+ if (const auto *IC = dyn_cast_or_null<CXXInstanceCall>(Call)) {
+ ThisRegion = IC->getCXXThisVal().getAsRegion();
+ }
+
+ for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
+ E = ExplicitRegions.end();
+ I != E; ++I) {
+ const auto *Region = *I;
+ if (ThisRegion != Region) {
+ State = removeFromState(State, Region);
+ }
+ }
+
+ return State;
+}
+
+void ento::registerMisusedMovedObjectChecker(CheckerManager &mgr) {
+ mgr.registerChecker<MisusedMovedObjectChecker>();
+}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index c1deade..8a5c769 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -123,14 +123,14 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
case 4:
lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(),
"handleFailureInFunction", "file", "lineNumber",
- "description", nullptr);
+ "description");
if (Sel != HandleFailureInFunctionSel)
return;
break;
case 5:
lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
"handleFailureInMethod", "object", "file",
- "lineNumber", "description", nullptr);
+ "lineNumber", "description");
if (Sel != HandleFailureInMethodSel)
return;
break;
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index 1f82ab9..6d05159 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -73,7 +73,7 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
for (unsigned idx = 0; idx < NumArgs; ++idx) {
// Check if the parameter is a reference. We want to report when reference
- // to a null pointer is passed as a paramter.
+ // to a null pointer is passed as a parameter.
bool haveRefTypeParam = false;
if (TyI != TyE) {
haveRefTypeParam = (*TyI)->isReferenceType();
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index c14a87c..fa9a317 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -49,7 +49,7 @@ namespace {
enum class Nullability : char {
Contradicted, // Tracked nullability is contradicted by an explicit cast. Do
// not report any nullability related issue for this symbol.
- // This nullability is propagated agressively to avoid false
+ // This nullability is propagated aggressively to avoid false
// positive results. See the comment on getMostNullable method.
Nullable,
Unspecified,
@@ -57,7 +57,7 @@ enum class Nullability : char {
};
/// Returns the most nullable nullability. This is used for message expressions
-/// like [reciever method], where the nullability of this expression is either
+/// like [receiver method], where the nullability of this expression is either
/// the nullability of the receiver or the nullability of the return type of the
/// method, depending on which is more nullable. Contradicted is considered to
/// be the most nullable, to avoid false positive results.
@@ -178,7 +178,7 @@ private:
const MemRegion *Region, BugReporter &BR,
const Stmt *ValueExpr = nullptr) const {
if (!BT)
- BT.reset(new BugType(this, "Nullability", "Memory error"));
+ BT.reset(new BugType(this, "Nullability", categories::MemoryError));
auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
if (Region) {
@@ -326,7 +326,7 @@ NullabilityChecker::NullabilityBugVisitor::VisitNode(const ExplodedNode *N,
// Retrieve the associated statement.
const Stmt *S = TrackedNullab->getNullabilitySource();
- if (!S) {
+ if (!S || S->getLocStart().isInvalid()) {
S = PathDiagnosticLocation::getStmt(N);
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
index b9857e5..dfd2c9a 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
@@ -58,8 +58,7 @@ void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D,
if (const ObjCInterfaceDecl *IntD =
dyn_cast<ObjCInterfaceDecl>(D->getDeclContext())) {
ImplD = IntD->getImplementation();
- } else {
- const ObjCCategoryDecl *CatD = cast<ObjCCategoryDecl>(D->getDeclContext());
+ } else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) {
ImplD = CatD->getClassInterface()->getImplementation();
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 7ef79c6..0e3a649 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -25,7 +25,13 @@ using namespace ento;
namespace {
struct LockState {
- enum Kind { Destroyed, Locked, Unlocked } K;
+ enum Kind {
+ Destroyed,
+ Locked,
+ Unlocked,
+ UntouchedAndPossiblyDestroyed,
+ UnlockedAndPossiblyDestroyed
+ } K;
private:
LockState(Kind K) : K(K) {}
@@ -34,6 +40,12 @@ public:
static LockState getLocked() { return LockState(Locked); }
static LockState getUnlocked() { return LockState(Unlocked); }
static LockState getDestroyed() { return LockState(Destroyed); }
+ static LockState getUntouchedAndPossiblyDestroyed() {
+ return LockState(UntouchedAndPossiblyDestroyed);
+ }
+ static LockState getUnlockedAndPossiblyDestroyed() {
+ return LockState(UnlockedAndPossiblyDestroyed);
+ }
bool operator==(const LockState &X) const {
return K == X.K;
@@ -42,13 +54,20 @@ public:
bool isLocked() const { return K == Locked; }
bool isUnlocked() const { return K == Unlocked; }
bool isDestroyed() const { return K == Destroyed; }
+ bool isUntouchedAndPossiblyDestroyed() const {
+ return K == UntouchedAndPossiblyDestroyed;
+ }
+ bool isUnlockedAndPossiblyDestroyed() const {
+ return K == UnlockedAndPossiblyDestroyed;
+ }
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(K);
}
};
-class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
+class PthreadLockChecker
+ : public Checker<check::PostStmt<CallExpr>, check::DeadSymbols> {
mutable std::unique_ptr<BugType> BT_doublelock;
mutable std::unique_ptr<BugType> BT_doubleunlock;
mutable std::unique_ptr<BugType> BT_destroylock;
@@ -61,22 +80,31 @@ class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
};
public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock,
bool isTryLock, enum LockingSemantics semantics) const;
void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const;
- void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
+ void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock,
+ enum LockingSemantics semantics) const;
void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
void reportUseDestroyedBug(CheckerContext &C, const CallExpr *CE) const;
+ ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state,
+ const MemRegion *lockR,
+ const SymbolRef *sym) const;
};
} // end anonymous namespace
-// GDM Entry for tracking lock state.
+// A stack of locks for tracking lock-unlock order.
REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *)
+// An entry for tracking lock states.
REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState)
+// Return values for unresolved calls to pthread_mutex_destroy().
+REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef)
+
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
ProgramStateRef state = C.getState();
@@ -113,13 +141,49 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
FName == "lck_mtx_unlock" ||
FName == "lck_rw_done")
ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
- else if (FName == "pthread_mutex_destroy" ||
- FName == "lck_mtx_destroy")
- DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
+ else if (FName == "pthread_mutex_destroy")
+ DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx), PthreadSemantics);
+ else if (FName == "lck_mtx_destroy")
+ DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx), XNUSemantics);
else if (FName == "pthread_mutex_init")
InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
}
+// When a lock is destroyed, in some semantics(like PthreadSemantics) we are not
+// sure if the destroy call has succeeded or failed, and the lock enters one of
+// the 'possibly destroyed' state. There is a short time frame for the
+// programmer to check the return value to see if the lock was successfully
+// destroyed. Before we model the next operation over that lock, we call this
+// function to see if the return value was checked by now and set the lock state
+// - either to destroyed state or back to its previous state.
+
+// In PthreadSemantics, pthread_mutex_destroy() returns zero if the lock is
+// successfully destroyed and it returns a non-zero value otherwise.
+ProgramStateRef PthreadLockChecker::resolvePossiblyDestroyedMutex(
+ ProgramStateRef state, const MemRegion *lockR, const SymbolRef *sym) const {
+ const LockState *lstate = state->get<LockMap>(lockR);
+ // Existence in DestroyRetVal ensures existence in LockMap.
+ // Existence in Destroyed also ensures that the lock state for lockR is either
+ // UntouchedAndPossiblyDestroyed or UnlockedAndPossiblyDestroyed.
+ assert(lstate->isUntouchedAndPossiblyDestroyed() ||
+ lstate->isUnlockedAndPossiblyDestroyed());
+
+ ConstraintManager &CMgr = state->getConstraintManager();
+ ConditionTruthVal retZero = CMgr.isNull(state, *sym);
+ if (retZero.isConstrainedFalse()) {
+ if (lstate->isUntouchedAndPossiblyDestroyed())
+ state = state->remove<LockMap>(lockR);
+ else if (lstate->isUnlockedAndPossiblyDestroyed())
+ state = state->set<LockMap>(lockR, LockState::getUnlocked());
+ } else
+ state = state->set<LockMap>(lockR, LockState::getDestroyed());
+
+ // Removing the map entry (lockR, sym) from DestroyRetVal as the lock state is
+ // now resolved.
+ state = state->remove<DestroyRetVal>(lockR);
+ return state;
+}
+
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
SVal lock, bool isTryLock,
enum LockingSemantics semantics) const {
@@ -129,6 +193,9 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
return;
ProgramStateRef state = C.getState();
+ const SymbolRef *sym = state->get<DestroyRetVal>(lockR);
+ if (sym)
+ state = resolvePossiblyDestroyedMutex(state, lockR, sym);
SVal X = state->getSVal(CE, C.getLocationContext());
if (X.isUnknownOrUndef())
@@ -197,6 +264,9 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
return;
ProgramStateRef state = C.getState();
+ const SymbolRef *sym = state->get<DestroyRetVal>(lockR);
+ if (sym)
+ state = resolvePossiblyDestroyedMutex(state, lockR, sym);
if (const LockState *LState = state->get<LockMap>(lockR)) {
if (LState->isUnlocked()) {
@@ -245,7 +315,8 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
}
void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
- SVal Lock) const {
+ SVal Lock,
+ enum LockingSemantics semantics) const {
const MemRegion *LockR = Lock.getAsRegion();
if (!LockR)
@@ -253,13 +324,38 @@ void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State = C.getState();
+ const SymbolRef *sym = State->get<DestroyRetVal>(LockR);
+ if (sym)
+ State = resolvePossiblyDestroyedMutex(State, LockR, sym);
+
const LockState *LState = State->get<LockMap>(LockR);
- if (!LState || LState->isUnlocked()) {
- State = State->set<LockMap>(LockR, LockState::getDestroyed());
- C.addTransition(State);
- return;
+ // Checking the return value of the destroy method only in the case of
+ // PthreadSemantics
+ if (semantics == PthreadSemantics) {
+ if (!LState || LState->isUnlocked()) {
+ SymbolRef sym = C.getSVal(CE).getAsSymbol();
+ if (!sym) {
+ State = State->remove<LockMap>(LockR);
+ C.addTransition(State);
+ return;
+ }
+ State = State->set<DestroyRetVal>(LockR, sym);
+ if (LState && LState->isUnlocked())
+ State = State->set<LockMap>(
+ LockR, LockState::getUnlockedAndPossiblyDestroyed());
+ else
+ State = State->set<LockMap>(
+ LockR, LockState::getUntouchedAndPossiblyDestroyed());
+ C.addTransition(State);
+ return;
+ }
+ } else {
+ if (!LState || LState->isUnlocked()) {
+ State = State->set<LockMap>(LockR, LockState::getDestroyed());
+ C.addTransition(State);
+ return;
+ }
}
-
StringRef Message;
if (LState->isLocked()) {
@@ -288,6 +384,10 @@ void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State = C.getState();
+ const SymbolRef *sym = State->get<DestroyRetVal>(LockR);
+ if (sym)
+ State = resolvePossiblyDestroyedMutex(State, LockR, sym);
+
const struct LockState *LState = State->get<LockMap>(LockR);
if (!LState || LState->isDestroyed()) {
State = State->set<LockMap>(LockR, LockState::getUnlocked());
@@ -328,6 +428,26 @@ void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C,
C.emitReport(std::move(Report));
}
+void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ // TODO: Clean LockMap when a mutex region dies.
+
+ DestroyRetValTy TrackedSymbols = State->get<DestroyRetVal>();
+ for (DestroyRetValTy::iterator I = TrackedSymbols.begin(),
+ E = TrackedSymbols.end();
+ I != E; ++I) {
+ const SymbolRef Sym = I->second;
+ const MemRegion *lockR = I->first;
+ bool IsSymDead = SymReaper.isDead(Sym);
+ // Remove the dead symbol from the return value symbols map.
+ if (IsSymDead)
+ State = resolvePossiblyDestroyedMutex(State, lockR, &Sym);
+ }
+ C.addTransition(State);
+}
+
void ento::registerPthreadLockChecker(CheckerManager &mgr) {
mgr.registerChecker<PthreadLockChecker>();
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index eb101e1..21ccf21 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -703,31 +703,30 @@ private:
ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
+ template <typename... Keywords>
void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries,
- const RetainSummary *Summ, va_list argp) {
- Selector S = getKeywordSelector(Ctx, argp);
+ const RetainSummary *Summ, Keywords *... Kws) {
+ Selector S = getKeywordSelector(Ctx, Kws...);
Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
- void addInstMethSummary(const char* Cls, const RetainSummary * Summ, ...) {
- va_list argp;
- va_start(argp, Summ);
- addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
- va_end(argp);
+ template <typename... Keywords>
+ void addInstMethSummary(const char *Cls, const RetainSummary *Summ,
+ Keywords *... Kws) {
+ addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, Kws...);
}
- void addClsMethSummary(const char* Cls, const RetainSummary * Summ, ...) {
- va_list argp;
- va_start(argp, Summ);
- addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp);
- va_end(argp);
+ template <typename... Keywords>
+ void addClsMethSummary(const char *Cls, const RetainSummary *Summ,
+ Keywords *... Kws) {
+ addMethodSummary(&Ctx.Idents.get(Cls), ObjCClassMethodSummaries, Summ,
+ Kws...);
}
- void addClsMethSummary(IdentifierInfo *II, const RetainSummary * Summ, ...) {
- va_list argp;
- va_start(argp, Summ);
- addMethodSummary(II, ObjCClassMethodSummaries, Summ, argp);
- va_end(argp);
+ template <typename... Keywords>
+ void addClsMethSummary(IdentifierInfo *II, const RetainSummary *Summ,
+ Keywords *... Kws) {
+ addMethodSummary(II, ObjCClassMethodSummaries, Summ, Kws...);
}
public:
@@ -1305,6 +1304,21 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
DoNothing, DoNothing);
}
+/// Returns true if the declaration 'D' is annotated with 'rcAnnotation'.
+static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
+ for (const auto *Ann : D->specific_attrs<AnnotateAttr>()) {
+ if (Ann->getAnnotation() == rcAnnotation)
+ return true;
+ }
+ return false;
+}
+
+/// Returns true if the function declaration 'FD' contains
+/// 'rc_ownership_trusted_implementation' annotate attribute.
+static bool isTrustedReferenceCountImplementation(const FunctionDecl *FD) {
+ return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
+}
+
//===----------------------------------------------------------------------===//
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
@@ -1640,20 +1654,16 @@ void RetainSummaryManager::InitializeMethodSummaries() {
addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);
// Create summaries QCRenderer/QCView -createSnapShotImageOfType:
- addInstMethSummary("QCRenderer", AllocSumm,
- "createSnapshotImageOfType", nullptr);
- addInstMethSummary("QCView", AllocSumm,
- "createSnapshotImageOfType", nullptr);
+ addInstMethSummary("QCRenderer", AllocSumm, "createSnapshotImageOfType");
+ addInstMethSummary("QCView", AllocSumm, "createSnapshotImageOfType");
// Create summaries for CIContext, 'createCGImage' and
// 'createCGLayerWithSize'. These objects are CF objects, and are not
// automatically garbage collected.
- addInstMethSummary("CIContext", CFAllocSumm,
- "createCGImage", "fromRect", nullptr);
+ addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect");
addInstMethSummary("CIContext", CFAllocSumm, "createCGImage", "fromRect",
- "format", "colorSpace", nullptr);
- addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info",
- nullptr);
+ "format", "colorSpace");
+ addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");
}
//===----------------------------------------------------------------------===//
@@ -2661,6 +2671,7 @@ public:
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext* LCtx,
const CallEvent *Call) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
@@ -3384,6 +3395,9 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// See if it's one of the specific functions we know how to eval.
bool canEval = false;
+ // See if the function has 'rc_ownership_trusted_implementation'
+ // annotate attribute. If it does, we will not inline it.
+ bool hasTrustedImplementationAnnotation = false;
QualType ResultTy = CE->getCallReturnType(C.getASTContext());
if (ResultTy->isObjCIdType()) {
@@ -3399,6 +3413,11 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
cocoa::isRefType(ResultTy, "CV", FName)) {
canEval = isRetain(FD, FName) || isAutorelease(FD, FName) ||
isMakeCollectable(FD, FName);
+ } else {
+ if (FD->getDefinition()) {
+ canEval = isTrustedReferenceCountImplementation(FD->getDefinition());
+ hasTrustedImplementationAnnotation = canEval;
+ }
}
}
@@ -3408,8 +3427,11 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Bind the return value.
const LocationContext *LCtx = C.getLocationContext();
SVal RetVal = state->getSVal(CE->getArg(0), LCtx);
- if (RetVal.isUnknown()) {
- // If the receiver is unknown, conjure a return value.
+ if (RetVal.isUnknown() ||
+ (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
+ // If the receiver is unknown or the function has
+ // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
+ // return value.
SValBuilder &SVB = C.getSValBuilder();
RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
}
@@ -3425,8 +3447,9 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
Binding = getRefBinding(state, Sym);
// Invalidate the argument region.
- state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx,
- /*CausesPointerEscape*/ false);
+ state = state->invalidateRegions(
+ ArgRegion, CE, C.blockCount(), LCtx,
+ /*CausesPointerEscape*/ hasTrustedImplementationAnnotation);
// Restore the refcount status of the argument.
if (Binding)
@@ -3647,7 +3670,7 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// same state.
SVal StoredVal = state->getSVal(regionLoc->getRegion());
if (StoredVal != val)
- escapes = (state == (state->bindLoc(*regionLoc, val)));
+ escapes = (state == (state->bindLoc(*regionLoc, val, C.getLocationContext())));
}
if (!escapes) {
// Case 4: We do not currently model what happens when a symbol is
@@ -3714,10 +3737,11 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
ProgramStateRef
RetainCountChecker::checkRegionChanges(ProgramStateRef state,
- const InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const {
+ const InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
+ const CallEvent *Call) const {
if (!invalidated)
return state;
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SelectorExtras.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SelectorExtras.h
index 41f70d7..b11d070 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SelectorExtras.h
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/SelectorExtras.h
@@ -11,48 +11,26 @@
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_SELECTOREXTRAS_H
#include "clang/AST/ASTContext.h"
-#include <cstdarg>
namespace clang {
namespace ento {
-static inline Selector getKeywordSelectorImpl(ASTContext &Ctx,
- const char *First,
- va_list argp) {
- SmallVector<IdentifierInfo*, 10> II;
- II.push_back(&Ctx.Idents.get(First));
-
- while (const char *s = va_arg(argp, const char *))
- II.push_back(&Ctx.Idents.get(s));
+template <typename... IdentifierInfos>
+static inline Selector getKeywordSelector(ASTContext &Ctx,
+ IdentifierInfos *... IIs) {
+ static_assert(sizeof...(IdentifierInfos),
+ "keyword selectors must have at least one argument");
+ SmallVector<IdentifierInfo *, 10> II({&Ctx.Idents.get(IIs)...});
return Ctx.Selectors.getSelector(II.size(), &II[0]);
}
-static inline Selector getKeywordSelector(ASTContext &Ctx, va_list argp) {
- const char *First = va_arg(argp, const char *);
- assert(First && "keyword selectors must have at least one argument");
- return getKeywordSelectorImpl(Ctx, First, argp);
-}
-
-LLVM_END_WITH_NULL
-static inline Selector getKeywordSelector(ASTContext &Ctx,
- const char *First, ...) {
- va_list argp;
- va_start(argp, First);
- Selector result = getKeywordSelectorImpl(Ctx, First, argp);
- va_end(argp);
- return result;
-}
-
-LLVM_END_WITH_NULL
+template <typename... IdentifierInfos>
static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx,
- const char *First, ...) {
+ IdentifierInfos *... IIs) {
if (!Sel.isNull())
return;
- va_list argp;
- va_start(argp, First);
- Sel = getKeywordSelectorImpl(Ctx, First, argp);
- va_end(argp);
+ Sel = getKeywordSelector(Ctx, IIs...);
}
static inline void lazyInitNullarySelector(Selector &Sel, ASTContext &Ctx,
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 93ad17c..2f9f5d2 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -440,7 +440,10 @@ StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
BasicValueFactory &BVF = SVB.getBasicValueFactory();
initFunctionSummaries(BVF);
- std::string Name = FD->getQualifiedNameAsString();
+ IdentifierInfo *II = FD->getIdentifier();
+ if (!II)
+ return None;
+ StringRef Name = II->getName();
if (Name.empty() || !C.isCLibraryFunction(FD, Name))
return None;
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 38d2aa6..f3c2ffc 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -35,6 +35,30 @@ public:
};
} // end anonymous namespace
+static bool isArrayIndexOutOfBounds(CheckerContext &C, const Expr *Ex) {
+ ProgramStateRef state = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
+
+ if (!isa<ArraySubscriptExpr>(Ex))
+ return false;
+
+ SVal Loc = state->getSVal(Ex, LCtx);
+ if (!Loc.isValid())
+ return false;
+
+ const MemRegion *MR = Loc.castAs<loc::MemRegionVal>().getRegion();
+ const ElementRegion *ER = dyn_cast<ElementRegion>(MR);
+ if (!ER)
+ return false;
+
+ DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
+ DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements(
+ state, ER->getSuperRegion(), ER->getValueType());
+ ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
+ ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
+ return StOutBound && !StInBound;
+}
+
void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
CheckerContext &C) const {
ProgramStateRef state = C.getState();
@@ -77,6 +101,8 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
<< " operand of '"
<< BinaryOperator::getOpcodeStr(B->getOpcode())
<< "' is a garbage value";
+ if (isArrayIndexOutOfBounds(C, Ex))
+ OS << " due to array index out of bounds";
}
else {
// Neither operand was undefined, but the result is undefined.
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 26bf597..7f9a00f 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -45,6 +45,8 @@ class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
mutable Optional<uint64_t> Val_O_CREAT;
public:
+ DefaultBool CheckMisuse, CheckPortability;
+
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
@@ -437,29 +439,42 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE,
if (FName.empty())
return;
- SubChecker SC =
- llvm::StringSwitch<SubChecker>(FName)
- .Case("open", &UnixAPIChecker::CheckOpen)
- .Case("openat", &UnixAPIChecker::CheckOpenAt)
- .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
- .Case("calloc", &UnixAPIChecker::CheckCallocZero)
- .Case("malloc", &UnixAPIChecker::CheckMallocZero)
- .Case("realloc", &UnixAPIChecker::CheckReallocZero)
- .Case("reallocf", &UnixAPIChecker::CheckReallocfZero)
- .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
- .Case("__builtin_alloca_with_align",
- &UnixAPIChecker::CheckAllocaWithAlignZero)
- .Case("valloc", &UnixAPIChecker::CheckVallocZero)
- .Default(nullptr);
-
- if (SC)
- (this->*SC)(C, CE);
+ if (CheckMisuse) {
+ if (SubChecker SC =
+ llvm::StringSwitch<SubChecker>(FName)
+ .Case("open", &UnixAPIChecker::CheckOpen)
+ .Case("openat", &UnixAPIChecker::CheckOpenAt)
+ .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
+ .Default(nullptr)) {
+ (this->*SC)(C, CE);
+ }
+ }
+ if (CheckPortability) {
+ if (SubChecker SC =
+ llvm::StringSwitch<SubChecker>(FName)
+ .Case("calloc", &UnixAPIChecker::CheckCallocZero)
+ .Case("malloc", &UnixAPIChecker::CheckMallocZero)
+ .Case("realloc", &UnixAPIChecker::CheckReallocZero)
+ .Case("reallocf", &UnixAPIChecker::CheckReallocfZero)
+ .Cases("alloca", "__builtin_alloca",
+ &UnixAPIChecker::CheckAllocaZero)
+ .Case("__builtin_alloca_with_align",
+ &UnixAPIChecker::CheckAllocaWithAlignZero)
+ .Case("valloc", &UnixAPIChecker::CheckVallocZero)
+ .Default(nullptr)) {
+ (this->*SC)(C, CE);
+ }
+ }
}
//===----------------------------------------------------------------------===//
// Registration.
//===----------------------------------------------------------------------===//
-void ento::registerUnixAPIChecker(CheckerManager &mgr) {
- mgr.registerChecker<UnixAPIChecker>();
-}
+#define REGISTER_CHECKER(Name) \
+ void ento::registerUnixAPI##Name##Checker(CheckerManager &mgr) { \
+ mgr.registerChecker<UnixAPIChecker>()->Check##Name = true; \
+ }
+
+REGISTER_CHECKER(Misuse)
+REGISTER_CHECKER(Portability)
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
index 0b7a486..06c4ef7 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
@@ -54,11 +54,11 @@ public:
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
private:
- const MemRegion *getVAListAsRegion(SVal SV, CheckerContext &C) const;
+ const MemRegion *getVAListAsRegion(SVal SV, const Expr *VAExpr,
+ bool &IsSymbolic, CheckerContext &C) const;
StringRef getVariableNameFromRegion(const MemRegion *Reg) const;
const ExplodedNode *getStartCallSite(const ExplodedNode *N,
- const MemRegion *Reg,
- CheckerContext &C) const;
+ const MemRegion *Reg) const;
void reportUninitializedAccess(const MemRegion *VAList, StringRef Msg,
CheckerContext &C) const;
@@ -138,14 +138,21 @@ void ValistChecker::checkPreCall(const CallEvent &Call,
for (auto FuncInfo : VAListAccepters) {
if (!Call.isCalled(FuncInfo.Func))
continue;
+ bool Symbolic;
const MemRegion *VAList =
- getVAListAsRegion(Call.getArgSVal(FuncInfo.VAListPos), C);
+ getVAListAsRegion(Call.getArgSVal(FuncInfo.VAListPos),
+ Call.getArgExpr(FuncInfo.VAListPos), Symbolic, C);
if (!VAList)
return;
if (C.getState()->contains<InitializedVALists>(VAList))
return;
+ // We did not see va_start call, but the source of the region is unknown.
+ // Be conservative and assume the best.
+ if (Symbolic)
+ return;
+
SmallString<80> Errmsg("Function '");
Errmsg += FuncInfo.Func.getFunctionName();
Errmsg += "' is called with an uninitialized va_list argument";
@@ -155,13 +162,41 @@ void ValistChecker::checkPreCall(const CallEvent &Call,
}
}
+const MemRegion *ValistChecker::getVAListAsRegion(SVal SV, const Expr *E,
+ bool &IsSymbolic,
+ CheckerContext &C) const {
+ const MemRegion *Reg = SV.getAsRegion();
+ if (!Reg)
+ return nullptr;
+ // TODO: In the future this should be abstracted away by the analyzer.
+ bool VaListModelledAsArray = false;
+ if (const auto *Cast = dyn_cast<CastExpr>(E)) {
+ QualType Ty = Cast->getType();
+ VaListModelledAsArray =
+ Ty->isPointerType() && Ty->getPointeeType()->isRecordType();
+ }
+ if (const auto *DeclReg = Reg->getAs<DeclRegion>()) {
+ if (isa<ParmVarDecl>(DeclReg->getDecl()))
+ Reg = C.getState()->getSVal(SV.castAs<Loc>()).getAsRegion();
+ }
+ IsSymbolic = Reg && Reg->getAs<SymbolicRegion>();
+ // Some VarRegion based VA lists reach here as ElementRegions.
+ const auto *EReg = dyn_cast_or_null<ElementRegion>(Reg);
+ return (EReg && VaListModelledAsArray) ? EReg->getSuperRegion() : Reg;
+}
+
void ValistChecker::checkPreStmt(const VAArgExpr *VAA,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
- SVal VAListSVal = State->getSVal(VAA->getSubExpr(), C.getLocationContext());
- const MemRegion *VAList = getVAListAsRegion(VAListSVal, C);
+ const Expr *VASubExpr = VAA->getSubExpr();
+ SVal VAListSVal = State->getSVal(VASubExpr, C.getLocationContext());
+ bool Symbolic;
+ const MemRegion *VAList =
+ getVAListAsRegion(VAListSVal, VASubExpr, Symbolic, C);
if (!VAList)
return;
+ if (Symbolic)
+ return;
if (!State->contains<InitializedVALists>(VAList))
reportUninitializedAccess(
VAList, "va_arg() is called on an uninitialized va_list", C);
@@ -183,22 +218,13 @@ void ValistChecker::checkDeadSymbols(SymbolReaper &SR,
N);
}
-const MemRegion *ValistChecker::getVAListAsRegion(SVal SV,
- CheckerContext &C) const {
- const MemRegion *Reg = SV.getAsRegion();
- const auto *TReg = dyn_cast_or_null<TypedValueRegion>(Reg);
- // Some VarRegion based VLAs reach here as ElementRegions.
- const auto *EReg = dyn_cast_or_null<ElementRegion>(TReg);
- return EReg ? EReg->getSuperRegion() : TReg;
-}
-
// This function traverses the exploded graph backwards and finds the node where
// the va_list is initialized. That node is used for uniquing the bug paths.
// It is not likely that there are several different va_lists that belongs to
// different stack frames, so that case is not yet handled.
-const ExplodedNode *ValistChecker::getStartCallSite(const ExplodedNode *N,
- const MemRegion *Reg,
- CheckerContext &C) const {
+const ExplodedNode *
+ValistChecker::getStartCallSite(const ExplodedNode *N,
+ const MemRegion *Reg) const {
const LocationContext *LeakContext = N->getLocationContext();
const ExplodedNode *StartCallNode = N;
@@ -230,7 +256,7 @@ void ValistChecker::reportUninitializedAccess(const MemRegion *VAList,
if (!BT_uninitaccess)
BT_uninitaccess.reset(new BugType(CheckNames[CK_Uninitialized],
"Uninitialized va_list",
- "Memory Error"));
+ categories::MemoryError));
auto R = llvm::make_unique<BugReport>(*BT_uninitaccess, Msg, N);
R->markInteresting(VAList);
R->addVisitor(llvm::make_unique<ValistBugVisitor>(VAList));
@@ -248,11 +274,12 @@ void ValistChecker::reportLeakedVALists(const RegionVector &LeakedVALists,
for (auto Reg : LeakedVALists) {
if (!BT_leakedvalist) {
BT_leakedvalist.reset(new BugType(CheckNames[CK_Unterminated],
- "Leaked va_list", "Memory Error"));
+ "Leaked va_list",
+ categories::MemoryError));
BT_leakedvalist->setSuppressOnSink(true);
}
- const ExplodedNode *StartNode = getStartCallSite(N, Reg, C);
+ const ExplodedNode *StartNode = getStartCallSite(N, Reg);
PathDiagnosticLocation LocUsedForUniqueing;
if (const Stmt *StartCallStmt = PathDiagnosticLocation::getStmt(StartNode))
@@ -278,13 +305,17 @@ void ValistChecker::reportLeakedVALists(const RegionVector &LeakedVALists,
void ValistChecker::checkVAListStartCall(const CallEvent &Call,
CheckerContext &C, bool IsCopy) const {
- const MemRegion *VAList = getVAListAsRegion(Call.getArgSVal(0), C);
- ProgramStateRef State = C.getState();
+ bool Symbolic;
+ const MemRegion *VAList =
+ getVAListAsRegion(Call.getArgSVal(0), Call.getArgExpr(0), Symbolic, C);
if (!VAList)
return;
+ ProgramStateRef State = C.getState();
+
if (IsCopy) {
- const MemRegion *Arg2 = getVAListAsRegion(Call.getArgSVal(1), C);
+ const MemRegion *Arg2 =
+ getVAListAsRegion(Call.getArgSVal(1), Call.getArgExpr(1), Symbolic, C);
if (Arg2) {
if (ChecksEnabled[CK_CopyToSelf] && VAList == Arg2) {
RegionVector LeakedVALists{VAList};
@@ -292,7 +323,7 @@ void ValistChecker::checkVAListStartCall(const CallEvent &Call,
reportLeakedVALists(LeakedVALists, "va_list",
" is copied onto itself", C, N, true);
return;
- } else if (!State->contains<InitializedVALists>(Arg2)) {
+ } else if (!State->contains<InitializedVALists>(Arg2) && !Symbolic) {
if (State->contains<InitializedVALists>(VAList)) {
State = State->remove<InitializedVALists>(VAList);
RegionVector LeakedVALists{VAList};
@@ -321,10 +352,17 @@ void ValistChecker::checkVAListStartCall(const CallEvent &Call,
void ValistChecker::checkVAListEndCall(const CallEvent &Call,
CheckerContext &C) const {
- const MemRegion *VAList = getVAListAsRegion(Call.getArgSVal(0), C);
+ bool Symbolic;
+ const MemRegion *VAList =
+ getVAListAsRegion(Call.getArgSVal(0), Call.getArgExpr(0), Symbolic, C);
if (!VAList)
return;
+ // We did not see va_start call, but the source of the region is unknown.
+ // Be conservative and assume the best.
+ if (Symbolic)
+ return;
+
if (!C.getState()->contains<InitializedVALists>(VAList)) {
reportUninitializedAccess(
VAList, "va_end() is called on an uninitialized va_list", C);
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 54634fd..83e6766 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -23,9 +23,10 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
AnalyzerOptions &Options,
CodeInjector *injector)
: AnaCtxMgr(Options.UnoptimizedCFG,
- /*AddImplicitDtors=*/true,
+ Options.includeImplicitDtorsInCFG(),
/*AddInitializers=*/true,
Options.includeTemporaryDtorsInCFG(),
+ Options.includeLifetimeInCFG(),
Options.shouldSynthesizeBodies(),
Options.shouldConditionalizeStaticInitializers(),
/*addCXXNewAllocator=*/true,
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 1542263..6f48fcb 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -172,6 +172,17 @@ bool AnalyzerOptions::includeTemporaryDtorsInCFG() {
/* Default = */ false);
}
+bool AnalyzerOptions::includeImplicitDtorsInCFG() {
+ return getBooleanOption(IncludeImplicitDtorsInCFG,
+ "cfg-implicit-dtors",
+ /* Default = */ true);
+}
+
+bool AnalyzerOptions::includeLifetimeInCFG() {
+ return getBooleanOption(IncludeLifetimeInCFG, "cfg-lifetime",
+ /* Default = */ false);
+}
+
bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
return getBooleanOption(InlineCXXStandardLibrary,
"c++-stdlib-inlining",
@@ -230,7 +241,7 @@ bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() {
bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() {
return getBooleanOption(SuppressFromCXXStandardLibrary,
"suppress-c++-stdlib",
- /* Default = */ false);
+ /* Default = */ true);
}
bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() {
@@ -293,7 +304,7 @@ unsigned AnalyzerOptions::getMaxInlinableSize() {
DefaultValue = 4;
break;
case UMK_Deep:
- DefaultValue = 50;
+ DefaultValue = 100;
break;
}
@@ -332,7 +343,7 @@ unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() {
DefaultValue = 75000;
break;
case UMK_Deep:
- DefaultValue = 150000;
+ DefaultValue = 225000;
break;
}
MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue);
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index 2114033..d8fca00 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -1671,9 +1671,15 @@ static bool GenerateAlternateExtensivePathDiagnostic(
// Add an edge to the start of the function.
const StackFrameContext *CalleeLC = CE->getCalleeContext();
const Decl *D = CalleeLC->getDecl();
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PathDiagnosticLocation::createBegin(D, SM),
- CalleeLC);
+ // Add the edge only when the callee has body. We jump to the beginning
+ // of the *declaration*, however we expect it to be followed by the
+ // body. This isn't the case for autosynthesized property accessors in
+ // Objective-C. No need for a similar extra check for CallExit points
+ // because the exit edge comes from a statement (i.e. return),
+ // not from declaration.
+ if (D->hasBody())
+ addEdgeToPath(PD.getActivePath(), PrevLoc,
+ PathDiagnosticLocation::createBegin(D, SM), CalleeLC);
// Did we visit an entire call?
bool VisitedEntireCall = PD.isWithinCall();
@@ -3448,14 +3454,12 @@ void BugReporter::FlushReport(BugReport *exampleReport,
// the BugReporterVisitors may mark this bug as a false positive.
assert(!bugReports.empty());
- MaxBugClassSize =
- std::max(bugReports.size(), static_cast<size_t>(MaxBugClassSize));
+ MaxBugClassSize.updateMax(bugReports.size());
if (!generatePathDiagnostic(*D.get(), PD, bugReports))
return;
- MaxValidBugClassSize =
- std::max(bugReports.size(), static_cast<size_t>(MaxValidBugClassSize));
+ MaxValidBugClassSize.updateMax(bugReports.size());
// Examine the report and see if the last piece is in a header. Reset the
// report location to the last piece in the main source file.
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index c3c3f2f..d00182a 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -61,7 +61,9 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) {
return U->getSubExpr()->IgnoreParenCasts();
}
else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) {
+ if (ME->isImplicitAccess()) {
+ return ME;
+ } else if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) {
return ME->getBase()->IgnoreParenCasts();
} else {
// If we have a member expr with a dot, the base must have been
@@ -73,9 +75,9 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) {
return IvarRef->getBase()->IgnoreParenCasts();
}
else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) {
- return AE->getBase();
+ return getDerefExpr(AE->getBase());
}
- else if (isDeclRefExprToReference(E)) {
+ else if (isa<DeclRefExpr>(E)) {
return E;
}
break;
@@ -961,7 +963,24 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
const Expr *Inner = nullptr;
if (const Expr *Ex = dyn_cast<Expr>(S)) {
Ex = Ex->IgnoreParenCasts();
- if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
+
+ // Performing operator `&' on an lvalue expression is essentially a no-op.
+ // Then, if we are taking addresses of fields or elements, these are also
+ // unlikely to matter.
+ // FIXME: There's a hack in our Store implementation that always computes
+ // field offsets around null pointers as if they are always equal to 0.
+ // The idea here is to report accesses to fields as null dereferences
+ // even though the pointer value that's being dereferenced is actually
+ // the offset of the field rather than exactly 0.
+ // See the FIXME in StoreManager's getLValueFieldOrIvar() method.
+ // This code interacts heavily with this hack; otherwise the value
+ // would not be null at all for most fields, so we'd be unable to track it.
+ if (const auto *Op = dyn_cast<UnaryOperator>(Ex))
+ if (Op->getOpcode() == UO_AddrOf && Op->getSubExpr()->isLValue())
+ if (const Expr *DerefEx = getDerefExpr(Op->getSubExpr()))
+ Ex = DerefEx;
+
+ if (Ex && (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex)))
Inner = Ex;
}
@@ -1027,7 +1046,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion();
// If this is a C++ reference to a null pointer, we are tracking the
- // pointer. In additon, we should find the store at which the reference
+ // pointer. In addition, we should find the store at which the reference
// got initialized.
if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) {
if (Optional<KnownSVal> KV = LVal.getAs<KnownSVal>())
@@ -1290,7 +1309,7 @@ std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitTerminator(
break;
case Stmt::BinaryOperatorClass:
// When we encounter a logical operator (&& or ||) as a CFG terminator,
- // then the condition is actually its LHS; otheriwse, we'd encounter
+ // then the condition is actually its LHS; otherwise, we'd encounter
// the parent, such as if-statement, as a terminator.
const auto *BO = cast<BinaryOperator>(Term);
assert(BO->isLogicalOp() &&
@@ -1659,7 +1678,7 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
// The analyzer issues a false use-after-free when std::list::pop_front
// or std::list::pop_back are called multiple times because we cannot
- // reason about the internal invariants of the datastructure.
+ // reason about the internal invariants of the data structure.
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
const CXXRecordDecl *CD = MD->getParent();
if (CD->getName() == "list") {
@@ -1690,7 +1709,7 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
// and
// std::u16string s; s += u'a';
// because we cannot reason about the internal invariants of the
- // datastructure.
+ // data structure.
if (CD->getName() == "basic_string") {
BR.markInvalid(getTag(), nullptr);
return nullptr;
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 420e2a6..1858bfd 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -212,9 +212,12 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
bool CallEvent::isCalled(const CallDescription &CD) const {
assert(getKind() != CE_ObjCMessage && "Obj-C methods are not supported");
- if (!CD.II)
+ if (!CD.IsLookupDone) {
+ CD.IsLookupDone = true;
CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName);
- if (getCalleeIdentifier() != CD.II)
+ }
+ const IdentifierInfo *II = getCalleeIdentifier();
+ if (!II || II != CD.II)
return false;
return (CD.RequiredArgs == CallDescription::NoArgRequirement ||
CD.RequiredArgs == getNumArgs());
@@ -692,13 +695,15 @@ void ObjCMethodCall::getExtraInvalidatedValues(
if (const ObjCPropertyDecl *PropDecl = getAccessedProperty()) {
if (const ObjCIvarDecl *PropIvar = PropDecl->getPropertyIvarDecl()) {
SVal IvarLVal = getState()->getLValue(PropIvar, getReceiverSVal());
- const MemRegion *IvarRegion = IvarLVal.getAsRegion();
- ETraits->setTrait(
+ if (const MemRegion *IvarRegion = IvarLVal.getAsRegion()) {
+ ETraits->setTrait(
IvarRegion,
RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
- ETraits->setTrait(IvarRegion,
- RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
- Values.push_back(IvarLVal);
+ ETraits->setTrait(
+ IvarRegion,
+ RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
+ Values.push_back(IvarLVal);
+ }
return;
}
}
@@ -896,6 +901,38 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
llvm_unreachable("The while loop should always terminate.");
}
+static const ObjCMethodDecl *findDefiningRedecl(const ObjCMethodDecl *MD) {
+ if (!MD)
+ return MD;
+
+ // Find the redeclaration that defines the method.
+ if (!MD->hasBody()) {
+ for (auto I : MD->redecls())
+ if (I->hasBody())
+ MD = cast<ObjCMethodDecl>(I);
+ }
+ return MD;
+}
+
+static bool isCallToSelfClass(const ObjCMessageExpr *ME) {
+ const Expr* InstRec = ME->getInstanceReceiver();
+ if (!InstRec)
+ return false;
+ const auto *InstRecIg = dyn_cast<DeclRefExpr>(InstRec->IgnoreParenImpCasts());
+
+ // Check that receiver is called 'self'.
+ if (!InstRecIg || !InstRecIg->getFoundDecl() ||
+ !InstRecIg->getFoundDecl()->getName().equals("self"))
+ return false;
+
+ // Check that the method name is 'class'.
+ if (ME->getSelector().getNumArgs() != 0 ||
+ !ME->getSelector().getNameForSlot(0).equals("class"))
+ return false;
+
+ return true;
+}
+
RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
const ObjCMessageExpr *E = getOriginExpr();
assert(E);
@@ -910,6 +947,7 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
const MemRegion *Receiver = nullptr;
if (!SupersType.isNull()) {
+ // The receiver is guaranteed to be 'super' in this case.
// Super always means the type of immediate predecessor to the method
// where the call occurs.
ReceiverT = cast<ObjCObjectPointerType>(SupersType);
@@ -919,9 +957,15 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
return RuntimeDefinition();
DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver);
+ if (!DTI.isValid()) {
+ assert(isa<AllocaRegion>(Receiver) &&
+ "Unhandled untyped region class!");
+ return RuntimeDefinition();
+ }
+
QualType DynType = DTI.getType();
CanBeSubClassed = DTI.canBeASubClass();
- ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType);
+ ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType.getCanonicalType());
if (ReceiverT && CanBeSubClassed)
if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl())
@@ -929,7 +973,32 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
CanBeSubClassed = false;
}
- // Lookup the method implementation.
+ // Handle special cases of '[self classMethod]' and
+ // '[[self class] classMethod]', which are treated by the compiler as
+ // instance (not class) messages. We will statically dispatch to those.
+ if (auto *PT = dyn_cast_or_null<ObjCObjectPointerType>(ReceiverT)) {
+ // For [self classMethod], return the compiler visible declaration.
+ if (PT->getObjectType()->isObjCClass() &&
+ Receiver == getSelfSVal().getAsRegion())
+ return RuntimeDefinition(findDefiningRedecl(E->getMethodDecl()));
+
+ // Similarly, handle [[self class] classMethod].
+ // TODO: We are currently doing a syntactic match for this pattern with is
+ // limiting as the test cases in Analysis/inlining/InlineObjCClassMethod.m
+ // shows. A better way would be to associate the meta type with the symbol
+ // using the dynamic type info tracking and use it here. We can add a new
+ // SVal for ObjC 'Class' values that know what interface declaration they
+ // come from. Then 'self' in a class method would be filled in with
+ // something meaningful in ObjCMethodCall::getReceiverSVal() and we could
+ // do proper dynamic dispatch for class methods just like we do for
+ // instance methods now.
+ if (E->getInstanceReceiver())
+ if (const auto *M = dyn_cast<ObjCMessageExpr>(E->getInstanceReceiver()))
+ if (isCallToSelfClass(M))
+ return RuntimeDefinition(findDefiningRedecl(E->getMethodDecl()));
+ }
+
+ // Lookup the instance method implementation.
if (ReceiverT)
if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) {
// Repeatedly calling lookupPrivateMethod() is expensive, especially
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 79e204c..49f3ede 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -521,17 +521,19 @@ void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
/// \brief Run checkers for region changes.
ProgramStateRef
CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
- const InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) {
+ const InvalidatedSymbols *invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
+ const CallEvent *Call) {
for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
if (!state)
return nullptr;
state = RegionChangesCheckers[i](state, invalidated,
- ExplicitRegions, Regions, Call);
+ ExplicitRegions, Regions,
+ LCtx, Call);
}
return state;
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
index 3cb9323..421dfa4 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
@@ -16,5 +16,6 @@ const char * const CoreFoundationObjectiveC = "Core Foundation/Objective-C";
const char * const LogicError = "Logic error";
const char * const MemoryCoreFoundationObjectiveC =
"Memory (Core Foundation/Objective-C)";
+const char * const MemoryError = "Memory error";
const char * const UnixAPI = "Unix API";
}}}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
index b7db833..8de2b0e 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
@@ -20,8 +20,8 @@ ConstraintManager::~ConstraintManager() {}
static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
SymbolRef Sym) {
- const MemRegion *R = State->getStateManager().getRegionManager()
- .getSymbolicRegion(Sym);
+ const MemRegion *R =
+ State->getStateManager().getRegionManager().getSymbolicRegion(Sym);
return loc::MemRegionVal(R);
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp
index fd35b66..a01ff36 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines APIs that track and query dynamic type information. This
-// information can be used to devirtualize calls during the symbolic exection
+// information can be used to devirtualize calls during the symbolic execution
// or do type checking.
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index d563f8e..eee5400 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -182,19 +182,25 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
ProgramStateRef
ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
const LocationContext *LC,
- const Expr *Ex,
+ const Expr *InitWithAdjustments,
const Expr *Result) {
- SVal V = State->getSVal(Ex, LC);
+ // FIXME: This function is a hack that works around the quirky AST
+ // we're often having with respect to C++ temporaries. If only we modelled
+ // the actual execution order of statements properly in the CFG,
+ // all the hassle with adjustments would not be necessary,
+ // and perhaps the whole function would be removed.
+ SVal InitValWithAdjustments = State->getSVal(InitWithAdjustments, LC);
if (!Result) {
// If we don't have an explicit result expression, we're in "if needed"
// mode. Only create a region if the current value is a NonLoc.
- if (!V.getAs<NonLoc>())
+ if (!InitValWithAdjustments.getAs<NonLoc>())
return State;
- Result = Ex;
+ Result = InitWithAdjustments;
} else {
// We need to create a region no matter what. For sanity, make sure we don't
// try to stuff a Loc into a non-pointer temporary region.
- assert(!V.getAs<Loc>() || Loc::isLocType(Result->getType()) ||
+ assert(!InitValWithAdjustments.getAs<Loc>() ||
+ Loc::isLocType(Result->getType()) ||
Result->getType()->isMemberPointerType());
}
@@ -226,7 +232,8 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
- const Expr *Init = Ex->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+ const Expr *Init = InitWithAdjustments->skipRValueSubobjectAdjustments(
+ CommaLHSs, Adjustments);
const TypedValueRegion *TR = nullptr;
if (const MaterializeTemporaryExpr *MT =
@@ -241,6 +248,7 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
TR = MRMgr.getCXXTempObjectRegion(Init, LC);
SVal Reg = loc::MemRegionVal(TR);
+ SVal BaseReg = Reg;
// Make the necessary adjustments to obtain the sub-object.
for (auto I = Adjustments.rbegin(), E = Adjustments.rend(); I != E; ++I) {
@@ -254,19 +262,47 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
break;
case SubobjectAdjustment::MemberPointerAdjustment:
// FIXME: Unimplemented.
- State->bindDefault(Reg, UnknownVal());
+ State = State->bindDefault(Reg, UnknownVal(), LC);
return State;
}
}
- // Try to recover some path sensitivity in case we couldn't compute the value.
- if (V.isUnknown())
- V = getSValBuilder().conjureSymbolVal(Result, LC, TR->getValueType(),
- currBldrCtx->blockCount());
- // Bind the value of the expression to the sub-object region, and then bind
- // the sub-object region to our expression.
- State = State->bindLoc(Reg, V);
+ // What remains is to copy the value of the object to the new region.
+ // FIXME: In other words, what we should always do is copy value of the
+ // Init expression (which corresponds to the bigger object) to the whole
+ // temporary region TR. However, this value is often no longer present
+ // in the Environment. If it has disappeared, we instead invalidate TR.
+ // Still, what we can do is assign the value of expression Ex (which
+ // corresponds to the sub-object) to the TR's sub-region Reg. At least,
+ // values inside Reg would be correct.
+ SVal InitVal = State->getSVal(Init, LC);
+ if (InitVal.isUnknown()) {
+ InitVal = getSValBuilder().conjureSymbolVal(Result, LC, Init->getType(),
+ currBldrCtx->blockCount());
+ State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false);
+
+ // Then we'd need to take the value that certainly exists and bind it over.
+ if (InitValWithAdjustments.isUnknown()) {
+ // Try to recover some path sensitivity in case we couldn't
+ // compute the value.
+ InitValWithAdjustments = getSValBuilder().conjureSymbolVal(
+ Result, LC, InitWithAdjustments->getType(),
+ currBldrCtx->blockCount());
+ }
+ State =
+ State->bindLoc(Reg.castAs<Loc>(), InitValWithAdjustments, LC, false);
+ } else {
+ State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false);
+ }
+
+ // The result expression would now point to the correct sub-region of the
+ // newly created temporary region. Do this last in order to getSVal of Init
+ // correctly in case (Result == Init).
State = State->BindExpr(Result, LC, Reg);
+
+ // Notify checkers once for two bindLoc()s.
+ State = processRegionChange(State, TR, LC);
+
return State;
}
@@ -286,9 +322,11 @@ ExprEngine::processRegionChanges(ProgramStateRef state,
const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
const CallEvent *Call) {
return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
- Explicits, Regions, Call);
+ Explicits, Regions,
+ LCtx, Call);
}
void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State,
@@ -324,6 +362,8 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
case CFGElement::TemporaryDtor:
ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
return;
+ case CFGElement::LifetimeEnds:
+ return;
}
}
@@ -613,7 +653,15 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion();
if (varType->isReferenceType()) {
- Region = state->getSVal(Region).getAsRegion()->getBaseRegion();
+ const MemRegion *ValueRegion = state->getSVal(Region).getAsRegion();
+ if (!ValueRegion) {
+ // FIXME: This should not happen. The language guarantees a presence
+ // of a valid initializer here, so the reference shall not be undefined.
+ // It seems that we're calling destructors over variables that
+ // were not initialized yet.
+ return;
+ }
+ Region = ValueRegion->getBaseRegion();
varType = cast<TypedValueRegion>(Region)->getValueType();
}
@@ -767,7 +815,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens());
switch (S->getStmtClass()) {
- // C++ and ARC stuff we don't support yet.
+ // C++, OpenMP and ARC stuff we don't support yet.
case Expr::ObjCIndirectCopyRestoreExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXInheritedCtorInitExprClass:
@@ -790,41 +838,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::FunctionParmPackExprClass:
case Stmt::CoroutineBodyStmtClass:
case Stmt::CoawaitExprClass:
+ case Stmt::DependentCoawaitExprClass:
case Stmt::CoreturnStmtClass:
case Stmt::CoyieldExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHLeaveStmtClass:
- case Stmt::SEHFinallyStmtClass: {
- const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
- Engine.addAbortedBlock(node, currBldrCtx->getBlock());
- break;
- }
-
- case Stmt::ParenExprClass:
- llvm_unreachable("ParenExprs already handled.");
- case Stmt::GenericSelectionExprClass:
- llvm_unreachable("GenericSelectionExprs already handled.");
- // Cases that should never be evaluated simply because they shouldn't
- // appear in the CFG.
- case Stmt::BreakStmtClass:
- case Stmt::CaseStmtClass:
- case Stmt::CompoundStmtClass:
- case Stmt::ContinueStmtClass:
- case Stmt::CXXForRangeStmtClass:
- case Stmt::DefaultStmtClass:
- case Stmt::DoStmtClass:
- case Stmt::ForStmtClass:
- case Stmt::GotoStmtClass:
- case Stmt::IfStmtClass:
- case Stmt::IndirectGotoStmtClass:
- case Stmt::LabelStmtClass:
- case Stmt::NoStmtClass:
- case Stmt::NullStmtClass:
- case Stmt::SwitchStmtClass:
- case Stmt::WhileStmtClass:
- case Expr::MSDependentExistsStmtClass:
- case Stmt::CapturedStmtClass:
+ case Stmt::SEHFinallyStmtClass:
case Stmt::OMPParallelDirectiveClass:
case Stmt::OMPSimdDirectiveClass:
case Stmt::OMPForDirectiveClass:
@@ -872,6 +892,36 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
+ case Stmt::CapturedStmtClass:
+ {
+ const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
+ Engine.addAbortedBlock(node, currBldrCtx->getBlock());
+ break;
+ }
+
+ case Stmt::ParenExprClass:
+ llvm_unreachable("ParenExprs already handled.");
+ case Stmt::GenericSelectionExprClass:
+ llvm_unreachable("GenericSelectionExprs already handled.");
+ // Cases that should never be evaluated simply because they shouldn't
+ // appear in the CFG.
+ case Stmt::BreakStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::CompoundStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::GotoStmtClass:
+ case Stmt::IfStmtClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::LabelStmtClass:
+ case Stmt::NoStmtClass:
+ case Stmt::NullStmtClass:
+ case Stmt::SwitchStmtClass:
+ case Stmt::WhileStmtClass:
+ case Expr::MSDependentExistsStmtClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
case Stmt::ObjCSubscriptRefExprClass:
@@ -1128,6 +1178,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
}
}
// FALLTHROUGH
+ LLVM_FALLTHROUGH;
}
case Stmt::CallExprClass:
case Stmt::CXXMemberCallExprClass:
@@ -1856,8 +1907,8 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
// Evaluate the LHS of the case value.
llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext());
- assert(V1.getBitWidth() == getContext().getTypeSize(CondE->getType()));
-
+ assert(V1.getBitWidth() == getContext().getIntWidth(CondE->getType()));
+
// Get the RHS of the case, if it exists.
llvm::APSInt V2;
if (const Expr *E = Case->getRHS())
@@ -2165,7 +2216,9 @@ public:
// (3) We are binding to a MemRegion with stack storage that the store
// does not understand.
ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
- SVal Loc, SVal Val) {
+ SVal Loc,
+ SVal Val,
+ const LocationContext *LCtx) {
// Are we storing to something that causes the value to "escape"?
bool escapes = true;
@@ -2181,7 +2234,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
// same state.
SVal StoredVal = State->getSVal(regionLoc->getRegion());
if (StoredVal != Val)
- escapes = (State == (State->bindLoc(*regionLoc, Val)));
+ escapes = (State == (State->bindLoc(*regionLoc, Val, LCtx)));
}
}
@@ -2278,7 +2331,7 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/nullptr,
/*tag*/nullptr);
ProgramStateRef state = Pred->getState();
- state = processPointerEscapedOnBind(state, location, Val);
+ state = processPointerEscapedOnBind(state, location, Val, LC);
Bldr.generateNode(L, state, Pred);
return;
}
@@ -2288,13 +2341,13 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
ExplodedNode *PredI = *I;
ProgramStateRef state = PredI->getState();
- state = processPointerEscapedOnBind(state, location, Val);
+ state = processPointerEscapedOnBind(state, location, Val, LC);
// When binding the value, pass on the hint that this is a initialization.
// For initializations, we do not need to inform clients of region
// changes.
state = state->bindLoc(location.castAs<Loc>(),
- Val, /* notifyChanges = */ !atDeclInit);
+ Val, LC, /* notifyChanges = */ !atDeclInit);
const MemRegion *LocReg = nullptr;
if (Optional<loc::MemRegionVal> LocRegVal =
@@ -2520,7 +2573,7 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
assert (!X.getAs<NonLoc>()); // Should be an Lval, or unknown, undef.
if (Optional<Loc> LV = X.getAs<Loc>())
- state = state->bindLoc(*LV, UnknownVal());
+ state = state->bindLoc(*LV, UnknownVal(), Pred->getLocationContext());
}
Bldr.generateNode(A, Pred, state);
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 89fab1d..6f1e839 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -227,12 +227,13 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
if (capturedR != originalR) {
SVal originalV;
+ const LocationContext *LCtx = Pred->getLocationContext();
if (copyExpr) {
- originalV = State->getSVal(copyExpr, Pred->getLocationContext());
+ originalV = State->getSVal(copyExpr, LCtx);
} else {
originalV = State->getSVal(loc::MemRegionVal(originalR));
}
- State = State->bindLoc(loc::MemRegionVal(capturedR), originalV);
+ State = State->bindLoc(loc::MemRegionVal(capturedR), originalV, LCtx);
}
}
}
@@ -534,7 +535,7 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
} else {
assert(isa<InitListExpr>(Init));
Loc CLLoc = State->getLValue(CL, LCtx);
- State = State->bindLoc(CLLoc, V);
+ State = State->bindLoc(CLLoc, V, LCtx);
if (CL->isGLValue())
V = CLLoc;
@@ -979,10 +980,9 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
// transfer functions as "0 == E".
SVal Result;
if (Optional<Loc> LV = V.getAs<Loc>()) {
- Loc X = svalBuilder.makeNull();
+ Loc X = svalBuilder.makeNullWithType(Ex->getType());
Result = evalBinOp(state, BO_EQ, *LV, X, U->getType());
- }
- else if (Ex->getType()->isFloatingType()) {
+ } else if (Ex->getType()->isFloatingType()) {
// FIXME: handle floating point types.
Result = UnknownVal();
} else {
@@ -1053,7 +1053,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
// Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown()){
DefinedOrUnknownSVal SymVal =
- svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
+ svalBuilder.conjureSymbolVal(nullptr, U, LCtx,
currBldrCtx->blockCount());
Result = SymVal;
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 7e9b203..03e0095 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -317,7 +317,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
// actually make things worse. Placement new makes this tricky as well,
// since it's then possible to be initializing one part of a multi-
// dimensional array.
- State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal);
+ State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal, LCtx);
Bldr.generateNode(CE, *I, State, /*tag=*/nullptr,
ProgramPoint::PreStmtKind);
}
@@ -512,7 +512,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
if (CNE->isArray()) {
// FIXME: allocating an array requires simulating the constructors.
// For now, just return a symbolicated region.
- const MemRegion *NewReg = symVal.castAs<loc::MemRegionVal>().getRegion();
+ const SubRegion *NewReg =
+ symVal.castAs<loc::MemRegionVal>().getRegionAs<SubRegion>();
QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
const ElementRegion *EleReg =
getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
@@ -572,7 +573,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS,
SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(),
currBldrCtx->blockCount());
ProgramStateRef state = Pred->getState();
- state = state->bindLoc(state->getLValue(VD, LCtx), V);
+ state = state->bindLoc(state->getLValue(VD, LCtx), V, LCtx);
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(CS, Pred, state);
@@ -627,7 +628,7 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
InitVal = State->getSVal(SizeExpr, LocCtxt);
}
- State = State->bindLoc(FieldLoc, InitVal);
+ State = State->bindLoc(FieldLoc, InitVal, LocCtxt);
}
// Decay the Loc into an RValue, because there might be a
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 39d88bf..caf86b2 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -447,6 +447,7 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
Bldr.takeNodes(Pred);
NumInlinedCalls++;
+ Engine.FunctionSummaries->bumpNumTimesInlined(D);
// Mark the decl as visited.
if (VisitedCallees)
@@ -868,8 +869,6 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
|| IsRecursive))
return false;
- Engine.FunctionSummaries->bumpNumTimesInlined(D);
-
return true;
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index 92c5fe6..f5e64f4 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -115,11 +115,11 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T,
currBldrCtx->blockCount());
SVal V = svalBuilder.makeLoc(Sym);
- hasElems = hasElems->bindLoc(elementV, V);
+ hasElems = hasElems->bindLoc(elementV, V, LCtx);
// Bind the location to 'nil' on the false branch.
SVal nilV = svalBuilder.makeIntVal(0, T);
- noElems = noElems->bindLoc(elementV, nilV);
+ noElems = noElems->bindLoc(elementV, nilV, LCtx);
}
// Create the new nodes.
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index d6e8fe5..7bc186d 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -31,54 +31,56 @@ using namespace ento;
// MemRegion Construction.
//===----------------------------------------------------------------------===//
-template <typename RegionTy, typename A1>
-RegionTy* MemRegionManager::getSubRegion(const A1 a1,
- const MemRegion *superRegion) {
+template <typename RegionTy, typename SuperTy, typename Arg1Ty>
+RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1,
+ const SuperTy *superRegion) {
llvm::FoldingSetNodeID ID;
- RegionTy::ProfileRegion(ID, a1, superRegion);
+ RegionTy::ProfileRegion(ID, arg1, superRegion);
void *InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
if (!R) {
R = A.Allocate<RegionTy>();
- new (R) RegionTy(a1, superRegion);
+ new (R) RegionTy(arg1, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
-template <typename RegionTy, typename A1, typename A2>
-RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2,
- const MemRegion *superRegion) {
+template <typename RegionTy, typename SuperTy, typename Arg1Ty, typename Arg2Ty>
+RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const SuperTy *superRegion) {
llvm::FoldingSetNodeID ID;
- RegionTy::ProfileRegion(ID, a1, a2, superRegion);
+ RegionTy::ProfileRegion(ID, arg1, arg2, superRegion);
void *InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
if (!R) {
R = A.Allocate<RegionTy>();
- new (R) RegionTy(a1, a2, superRegion);
+ new (R) RegionTy(arg1, arg2, superRegion);
Regions.InsertNode(R, InsertPos);
}
return R;
}
-template <typename RegionTy, typename A1, typename A2, typename A3>
-RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3,
- const MemRegion *superRegion) {
+template <typename RegionTy, typename SuperTy,
+ typename Arg1Ty, typename Arg2Ty, typename Arg3Ty>
+RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+ const Arg3Ty arg3,
+ const SuperTy *superRegion) {
llvm::FoldingSetNodeID ID;
- RegionTy::ProfileRegion(ID, a1, a2, a3, superRegion);
+ RegionTy::ProfileRegion(ID, arg1, arg2, arg3, superRegion);
void *InsertPos;
RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
InsertPos));
if (!R) {
R = A.Allocate<RegionTy>();
- new (R) RegionTy(a1, a2, a3, superRegion);
+ new (R) RegionTy(arg1, arg2, arg3, superRegion);
Regions.InsertNode(R, InsertPos);
}
@@ -180,8 +182,8 @@ DefinedOrUnknownSVal StringRegion::getExtent(SValBuilder &svalBuilder) const {
svalBuilder.getArrayIndexType());
}
-ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg)
- : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
+ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
+ : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
const ObjCIvarDecl *ObjCIvarRegion::getDecl() const {
return cast<ObjCIvarDecl>(D);
@@ -379,10 +381,8 @@ void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
//===----------------------------------------------------------------------===//
void GlobalsSpaceRegion::anchor() { }
-void HeapSpaceRegion::anchor() { }
-void UnknownSpaceRegion::anchor() { }
-void StackLocalsSpaceRegion::anchor() { }
-void StackArgumentsSpaceRegion::anchor() { }
+void NonStaticGlobalSpaceRegion::anchor() { }
+void StackSpaceRegion::anchor() { }
void TypedRegion::anchor() { }
void TypedValueRegion::anchor() { }
void CodeTextRegion::anchor() { }
@@ -737,12 +737,14 @@ const CodeSpaceRegion *MemRegionManager::getCodeRegion() {
// Constructing regions.
//===----------------------------------------------------------------------===//
const StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str){
- return getSubRegion<StringRegion>(Str, getGlobalsRegion());
+ return getSubRegion<StringRegion>(
+ Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
}
const ObjCStringRegion *
MemRegionManager::getObjCStringRegion(const ObjCStringLiteral* Str){
- return getSubRegion<ObjCStringRegion>(Str, getGlobalsRegion());
+ return getSubRegion<ObjCStringRegion>(
+ Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
}
/// Look through a chain of LocationContexts to either find the
@@ -871,7 +873,7 @@ const BlockDataRegion *
MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,
const LocationContext *LC,
unsigned blockCount) {
- const MemRegion *sReg = nullptr;
+ const MemSpaceRegion *sReg = nullptr;
const BlockDecl *BD = BC->getDecl();
if (!BD->hasCaptures()) {
// This handles 'static' blocks.
@@ -904,7 +906,7 @@ MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) {
const CompoundLiteralRegion*
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
const LocationContext *LC) {
- const MemRegion *sReg = nullptr;
+ const MemSpaceRegion *sReg = nullptr;
if (CL->isFileScope())
sReg = getGlobalsRegion();
@@ -919,7 +921,7 @@ MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
const ElementRegion*
MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
- const MemRegion* superRegion,
+ const SubRegion* superRegion,
ASTContext &Ctx){
QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType();
@@ -962,13 +964,13 @@ const SymbolicRegion *MemRegionManager::getSymbolicHeapRegion(SymbolRef Sym) {
const FieldRegion*
MemRegionManager::getFieldRegion(const FieldDecl *d,
- const MemRegion* superRegion){
+ const SubRegion* superRegion){
return getSubRegion<FieldRegion>(d, superRegion);
}
const ObjCIvarRegion*
MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl *d,
- const MemRegion* superRegion) {
+ const SubRegion* superRegion) {
return getSubRegion<ObjCIvarRegion>(d, superRegion);
}
@@ -1004,7 +1006,7 @@ static bool isValidBaseClass(const CXXRecordDecl *BaseClass,
const CXXBaseObjectRegion *
MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
- const MemRegion *Super,
+ const SubRegion *Super,
bool IsVirtual) {
if (isa<TypedValueRegion>(Super)) {
assert(isValidBaseClass(RD, dyn_cast<TypedValueRegion>(Super), IsVirtual));
@@ -1015,7 +1017,7 @@ MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
// are different.
while (const CXXBaseObjectRegion *Base =
dyn_cast<CXXBaseObjectRegion>(Super)) {
- Super = Base->getSuperRegion();
+ Super = cast<SubRegion>(Base->getSuperRegion());
}
assert(Super && !isa<MemSpaceRegion>(Super));
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index 7c5ee3b..d91786f 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -578,6 +578,7 @@ getLocationForCaller(const StackFrameContext *SFC,
}
case CFGElement::TemporaryDtor:
case CFGElement::NewAllocator:
+ case CFGElement::LifetimeEnds:
llvm_unreachable("not yet implemented!");
}
@@ -694,7 +695,30 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
return PathDiagnosticLocation(S, SMng, P.getLocationContext());
}
+static const LocationContext *
+findTopAutosynthesizedParentContext(const LocationContext *LC) {
+ assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized());
+ const LocationContext *ParentLC = LC->getParent();
+ assert(ParentLC && "We don't start analysis from autosynthesized code");
+ while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
+ LC = ParentLC;
+ ParentLC = LC->getParent();
+ assert(ParentLC && "We don't start analysis from autosynthesized code");
+ }
+ return LC;
+}
+
const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
+ // We cannot place diagnostics on autosynthesized code.
+ // Put them onto the call site through which we jumped into autosynthesized
+ // code for the first time.
+ const LocationContext *LC = N->getLocationContext();
+ if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
+ // It must be a stack frame because we only autosynthesize functions.
+ return cast<StackFrameContext>(findTopAutosynthesizedParentContext(LC))
+ ->getCallSite();
+ }
+ // Otherwise, see if the node's program point directly points to a statement.
ProgramPoint P = N->getLocation();
if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
return SP->getStmt();
@@ -912,6 +936,17 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
+
+ // Autosynthesized property accessors are special because we'd never
+ // pop back up to non-autosynthesized code until we leave them.
+ // This is not generally true for autosynthesized callees, which may call
+ // non-autosynthesized callbacks.
+ // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag
+ // defaults to false.
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Callee))
+ IsCalleeAnAutosynthesizedPropertyAccessor = (
+ MD->isPropertyAccessor() &&
+ CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());
}
static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
@@ -986,7 +1021,11 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
std::shared_ptr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallEnterEvent() const {
- if (!Callee)
+ // We do not produce call enters and call exits for autosynthesized property
+ // accessors. We do generally produce them for other functions coming from
+ // the body farm because they may call callbacks that bring us back into
+ // visible code.
+ if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor)
return nullptr;
SmallString<256> buf;
@@ -1020,7 +1059,11 @@ PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
std::shared_ptr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallExitEvent() const {
- if (NoExit)
+ // We do not produce call enters and call exits for autosynthesized property
+ // accessors. We do generally produce them for other functions coming from
+ // the body farm because they may call callbacks that bring us back into
+ // visible code.
+ if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor)
return nullptr;
SmallString<256> buf;
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index 03ace35..3215c3c 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -111,24 +111,29 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state,
return ConstraintMgr->removeDeadBindings(Result, SymReaper);
}
-ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const {
+ProgramStateRef ProgramState::bindLoc(Loc LV,
+ SVal V,
+ const LocationContext *LCtx,
+ bool notifyChanges) const {
ProgramStateManager &Mgr = getStateManager();
ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
LV, V));
const MemRegion *MR = LV.getAsRegion();
if (MR && Mgr.getOwningEngine() && notifyChanges)
- return Mgr.getOwningEngine()->processRegionChange(newState, MR);
+ return Mgr.getOwningEngine()->processRegionChange(newState, MR, LCtx);
return newState;
}
-ProgramStateRef ProgramState::bindDefault(SVal loc, SVal V) const {
+ProgramStateRef ProgramState::bindDefault(SVal loc,
+ SVal V,
+ const LocationContext *LCtx) const {
ProgramStateManager &Mgr = getStateManager();
const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();
const StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V);
ProgramStateRef new_state = makeWithStore(newStore);
return Mgr.getOwningEngine() ?
- Mgr.getOwningEngine()->processRegionChange(new_state, R) :
+ Mgr.getOwningEngine()->processRegionChange(new_state, R, LCtx) :
new_state;
}
@@ -202,7 +207,7 @@ ProgramState::invalidateRegionsImpl(ValueList Values,
}
return Eng->processRegionChanges(newState, IS, TopLevelInvalidated,
- Invalidated, Call);
+ Invalidated, LCtx, Call);
}
const StoreRef &newStore =
@@ -639,15 +644,33 @@ ProgramStateRef ProgramState::addTaint(const Stmt *S,
if (const Expr *E = dyn_cast_or_null<Expr>(S))
S = E->IgnoreParens();
- SymbolRef Sym = getSVal(S, LCtx).getAsSymbol();
+ return addTaint(getSVal(S, LCtx), Kind);
+}
+
+ProgramStateRef ProgramState::addTaint(SVal V,
+ TaintTagType Kind) const {
+ SymbolRef Sym = V.getAsSymbol();
if (Sym)
return addTaint(Sym, Kind);
- const MemRegion *R = getSVal(S, LCtx).getAsRegion();
- addTaint(R, Kind);
+ // If the SVal represents a structure, try to mass-taint all values within the
+ // structure. For now it only works efficiently on lazy compound values that
+ // were conjured during a conservative evaluation of a function - either as
+ // return values of functions that return structures or arrays by value, or as
+ // values of structures or arrays passed into the function by reference,
+ // directly or through pointer aliasing. Such lazy compound values are
+ // characterized by having exactly one binding in their captured store within
+ // their parent region, which is a conjured symbol default-bound to the base
+ // region of the parent region.
+ if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
+ if (Optional<SVal> binding = getStateManager().StoreMgr->getDefaultBinding(*LCV)) {
+ if (SymbolRef Sym = binding->getAsSymbol())
+ return addPartialTaint(Sym, LCV->getRegion(), Kind);
+ }
+ }
- // Cannot add taint, so just return the state.
- return this;
+ const MemRegion *R = V.getAsRegion();
+ return addTaint(R, Kind);
}
ProgramStateRef ProgramState::addTaint(const MemRegion *R,
@@ -669,6 +692,27 @@ ProgramStateRef ProgramState::addTaint(SymbolRef Sym,
return NewState;
}
+ProgramStateRef ProgramState::addPartialTaint(SymbolRef ParentSym,
+ const SubRegion *SubRegion,
+ TaintTagType Kind) const {
+ // Ignore partial taint if the entire parent symbol is already tainted.
+ if (contains<TaintMap>(ParentSym) && *get<TaintMap>(ParentSym) == Kind)
+ return this;
+
+ // Partial taint applies if only a portion of the symbol is tainted.
+ if (SubRegion == SubRegion->getBaseRegion())
+ return addTaint(ParentSym, Kind);
+
+ const TaintedSubRegions *SavedRegs = get<DerivedSymTaint>(ParentSym);
+ TaintedSubRegions Regs =
+ SavedRegs ? *SavedRegs : stateMgr->TSRFactory.getEmptyMap();
+
+ Regs = stateMgr->TSRFactory.add(Regs, SubRegion, Kind);
+ ProgramStateRef NewState = set<DerivedSymTaint>(ParentSym, Regs);
+ assert(NewState);
+ return NewState;
+}
+
bool ProgramState::isTainted(const Stmt *S, const LocationContext *LCtx,
TaintTagType Kind) const {
if (const Expr *E = dyn_cast_or_null<Expr>(S))
@@ -709,31 +753,52 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
return false;
// Traverse all the symbols this symbol depends on to see if any are tainted.
- bool Tainted = false;
for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end();
SI != SE; ++SI) {
if (!isa<SymbolData>(*SI))
continue;
- const TaintTagType *Tag = get<TaintMap>(*SI);
- Tainted = (Tag && *Tag == Kind);
+ if (const TaintTagType *Tag = get<TaintMap>(*SI)) {
+ if (*Tag == Kind)
+ return true;
+ }
- // If this is a SymbolDerived with a tainted parent, it's also tainted.
- if (const SymbolDerived *SD = dyn_cast<SymbolDerived>(*SI))
- Tainted = Tainted || isTainted(SD->getParentSymbol(), Kind);
+ if (const SymbolDerived *SD = dyn_cast<SymbolDerived>(*SI)) {
+ // If this is a SymbolDerived with a tainted parent, it's also tainted.
+ if (isTainted(SD->getParentSymbol(), Kind))
+ return true;
+
+ // If this is a SymbolDerived with the same parent symbol as another
+ // tainted SymbolDerived and a region that's a sub-region of that tainted
+ // symbol, it's also tainted.
+ if (const TaintedSubRegions *Regs =
+ get<DerivedSymTaint>(SD->getParentSymbol())) {
+ const TypedValueRegion *R = SD->getRegion();
+ for (auto I : *Regs) {
+ // FIXME: The logic to identify tainted regions could be more
+ // complete. For example, this would not currently identify
+ // overlapping fields in a union as tainted. To identify this we can
+ // check for overlapping/nested byte offsets.
+ if (Kind == I.second &&
+ (R == I.first || R->isSubRegionOf(I.first)))
+ return true;
+ }
+ }
+ }
// If memory region is tainted, data is also tainted.
- if (const SymbolRegionValue *SRV = dyn_cast<SymbolRegionValue>(*SI))
- Tainted = Tainted || isTainted(SRV->getRegion(), Kind);
-
- // If If this is a SymbolCast from a tainted value, it's also tainted.
- if (const SymbolCast *SC = dyn_cast<SymbolCast>(*SI))
- Tainted = Tainted || isTainted(SC->getOperand(), Kind);
+ if (const SymbolRegionValue *SRV = dyn_cast<SymbolRegionValue>(*SI)) {
+ if (isTainted(SRV->getRegion(), Kind))
+ return true;
+ }
- if (Tainted)
- return true;
+ // If this is a SymbolCast from a tainted value, it's also tainted.
+ if (const SymbolCast *SC = dyn_cast<SymbolCast>(*SI)) {
+ if (isTainted(SC->getOperand(), Kind))
+ return true;
+ }
}
- return Tainted;
+ return false;
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 15073bb..e0ad2d8 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "SimpleConstraintManager.h"
+#include "RangedConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
@@ -282,12 +282,31 @@ REGISTER_TRAIT_WITH_PROGRAMSTATE(ConstraintRange,
RangeSet))
namespace {
-class RangeConstraintManager : public SimpleConstraintManager {
- RangeSet getRange(ProgramStateRef State, SymbolRef Sym);
-
+class RangeConstraintManager : public RangedConstraintManager {
public:
RangeConstraintManager(SubEngine *SE, SValBuilder &SVB)
- : SimpleConstraintManager(SE, SVB) {}
+ : RangedConstraintManager(SE, SVB) {}
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from ConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ bool canReasonAbout(SVal X) const override;
+
+ ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override;
+
+ const llvm::APSInt *getSymVal(ProgramStateRef State,
+ SymbolRef Sym) const override;
+
+ ProgramStateRef removeDeadBindings(ProgramStateRef State,
+ SymbolReaper &SymReaper) override;
+
+ void print(ProgramStateRef State, raw_ostream &Out, const char *nl,
+ const char *sep) override;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from RangedConstraintManager.
+ //===------------------------------------------------------------------===//
ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
@@ -313,26 +332,19 @@ public:
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) override;
- ProgramStateRef assumeSymbolWithinInclusiveRange(
+ ProgramStateRef assumeSymWithinInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
const llvm::APSInt &To, const llvm::APSInt &Adjustment) override;
- ProgramStateRef assumeSymbolOutOfInclusiveRange(
+ ProgramStateRef assumeSymOutsideInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
const llvm::APSInt &To, const llvm::APSInt &Adjustment) override;
- const llvm::APSInt *getSymVal(ProgramStateRef St,
- SymbolRef Sym) const override;
- ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override;
-
- ProgramStateRef removeDeadBindings(ProgramStateRef St,
- SymbolReaper &SymReaper) override;
-
- void print(ProgramStateRef St, raw_ostream &Out, const char *nl,
- const char *sep) override;
-
private:
RangeSet::Factory F;
+
+ RangeSet getRange(ProgramStateRef State, SymbolRef Sym);
+
RangeSet getSymLTRange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment);
@@ -356,10 +368,46 @@ ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
return llvm::make_unique<RangeConstraintManager>(Eng, StMgr.getSValBuilder());
}
-const llvm::APSInt *RangeConstraintManager::getSymVal(ProgramStateRef St,
- SymbolRef Sym) const {
- const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(Sym);
- return T ? T->getConcreteValue() : nullptr;
+bool RangeConstraintManager::canReasonAbout(SVal X) const {
+ Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
+ if (SymVal && SymVal->isExpression()) {
+ const SymExpr *SE = SymVal->getSymbol();
+
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
+ switch (SIE->getOpcode()) {
+ // We don't reason yet about bitwise-constraints on symbolic values.
+ case BO_And:
+ case BO_Or:
+ case BO_Xor:
+ return false;
+ // We don't reason yet about these arithmetic constraints on
+ // symbolic values.
+ case BO_Mul:
+ case BO_Div:
+ case BO_Rem:
+ case BO_Shl:
+ case BO_Shr:
+ return false;
+ // All other cases.
+ default:
+ return true;
+ }
+ }
+
+ if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
+ if (BinaryOperator::isComparisonOp(SSE->getOpcode())) {
+ // We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc.
+ if (Loc::isLocType(SSE->getLHS()->getType())) {
+ assert(Loc::isLocType(SSE->getRHS()->getType()));
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ return true;
}
ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,
@@ -386,6 +434,12 @@ ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,
return ConditionTruthVal();
}
+const llvm::APSInt *RangeConstraintManager::getSymVal(ProgramStateRef St,
+ SymbolRef Sym) const {
+ const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(Sym);
+ return T ? T->getConcreteValue() : nullptr;
+}
+
/// Scan all symbols referenced by the constraints. If the symbol is not alive
/// as marked in LSymbols, mark it as dead in DSymbols.
ProgramStateRef
@@ -429,7 +483,7 @@ RangeSet RangeConstraintManager::getRange(ProgramStateRef State,
}
//===------------------------------------------------------------------------===
-// assumeSymX methods: public interface for RangeConstraintManager.
+// assumeSymX methods: protected interface for RangeConstraintManager.
//===------------------------------------------------------------------------===/
// The syntax for ranges below is mathematical, using [x, y] for closed ranges
@@ -646,7 +700,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
-ProgramStateRef RangeConstraintManager::assumeSymbolWithinInclusiveRange(
+ProgramStateRef RangeConstraintManager::assumeSymWithinInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
const llvm::APSInt &To, const llvm::APSInt &Adjustment) {
RangeSet New = getSymGERange(State, Sym, From, Adjustment);
@@ -656,7 +710,7 @@ ProgramStateRef RangeConstraintManager::assumeSymbolWithinInclusiveRange(
return New.isEmpty() ? nullptr : State->set<ConstraintRange>(Sym, New);
}
-ProgramStateRef RangeConstraintManager::assumeSymbolOutOfInclusiveRange(
+ProgramStateRef RangeConstraintManager::assumeSymOutsideInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
const llvm::APSInt &To, const llvm::APSInt &Adjustment) {
RangeSet RangeLT = getSymLTRange(State, Sym, From, Adjustment);
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
new file mode 100644
index 0000000..1304116
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
@@ -0,0 +1,204 @@
+//== RangedConstraintManager.cpp --------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines RangedConstraintManager, a class that provides a
+// range-based constraint manager interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RangedConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+
+namespace clang {
+
+namespace ento {
+
+RangedConstraintManager::~RangedConstraintManager() {}
+
+ProgramStateRef RangedConstraintManager::assumeSym(ProgramStateRef State,
+ SymbolRef Sym,
+ bool Assumption) {
+ // Handle SymbolData.
+ if (isa<SymbolData>(Sym)) {
+ return assumeSymUnsupported(State, Sym, Assumption);
+
+ // Handle symbolic expression.
+ } else if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(Sym)) {
+ // We can only simplify expressions whose RHS is an integer.
+
+ BinaryOperator::Opcode op = SIE->getOpcode();
+ if (BinaryOperator::isComparisonOp(op)) {
+ if (!Assumption)
+ op = BinaryOperator::negateComparisonOp(op);
+
+ return assumeSymRel(State, SIE->getLHS(), op, SIE->getRHS());
+ }
+
+ } else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(Sym)) {
+ // Translate "a != b" to "(b - a) != 0".
+ // We invert the order of the operands as a heuristic for how loop
+ // conditions are usually written ("begin != end") as compared to length
+ // calculations ("end - begin"). The more correct thing to do would be to
+ // canonicalize "a - b" and "b - a", which would allow us to treat
+ // "a != b" and "b != a" the same.
+ SymbolManager &SymMgr = getSymbolManager();
+ BinaryOperator::Opcode Op = SSE->getOpcode();
+ assert(BinaryOperator::isComparisonOp(Op));
+
+ // For now, we only support comparing pointers.
+ assert(Loc::isLocType(SSE->getLHS()->getType()));
+ assert(Loc::isLocType(SSE->getRHS()->getType()));
+ QualType DiffTy = SymMgr.getContext().getPointerDiffType();
+ SymbolRef Subtraction =
+ SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub, SSE->getLHS(), DiffTy);
+
+ const llvm::APSInt &Zero = getBasicVals().getValue(0, DiffTy);
+ Op = BinaryOperator::reverseComparisonOp(Op);
+ if (!Assumption)
+ Op = BinaryOperator::negateComparisonOp(Op);
+ return assumeSymRel(State, Subtraction, Op, Zero);
+ }
+
+ // If we get here, there's nothing else we can do but treat the symbol as
+ // opaque.
+ return assumeSymUnsupported(State, Sym, Assumption);
+}
+
+ProgramStateRef RangedConstraintManager::assumeSymInclusiveRange(
+ ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
+ const llvm::APSInt &To, bool InRange) {
+ // Get the type used for calculating wraparound.
+ BasicValueFactory &BVF = getBasicVals();
+ APSIntType WraparoundType = BVF.getAPSIntType(Sym->getType());
+
+ llvm::APSInt Adjustment = WraparoundType.getZeroValue();
+ SymbolRef AdjustedSym = Sym;
+ computeAdjustment(AdjustedSym, Adjustment);
+
+ // Convert the right-hand side integer as necessary.
+ APSIntType ComparisonType = std::max(WraparoundType, APSIntType(From));
+ llvm::APSInt ConvertedFrom = ComparisonType.convert(From);
+ llvm::APSInt ConvertedTo = ComparisonType.convert(To);
+
+ // Prefer unsigned comparisons.
+ if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
+ ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
+ Adjustment.setIsSigned(false);
+
+ if (InRange)
+ return assumeSymWithinInclusiveRange(State, AdjustedSym, ConvertedFrom,
+ ConvertedTo, Adjustment);
+ return assumeSymOutsideInclusiveRange(State, AdjustedSym, ConvertedFrom,
+ ConvertedTo, Adjustment);
+}
+
+ProgramStateRef
+RangedConstraintManager::assumeSymUnsupported(ProgramStateRef State,
+ SymbolRef Sym, bool Assumption) {
+ BasicValueFactory &BVF = getBasicVals();
+ QualType T = Sym->getType();
+
+ // Non-integer types are not supported.
+ if (!T->isIntegralOrEnumerationType())
+ return State;
+
+ // Reverse the operation and add directly to state.
+ const llvm::APSInt &Zero = BVF.getValue(0, T);
+ if (Assumption)
+ return assumeSymNE(State, Sym, Zero, Zero);
+ else
+ return assumeSymEQ(State, Sym, Zero, Zero);
+}
+
+ProgramStateRef RangedConstraintManager::assumeSymRel(ProgramStateRef State,
+ SymbolRef Sym,
+ BinaryOperator::Opcode Op,
+ const llvm::APSInt &Int) {
+ assert(BinaryOperator::isComparisonOp(Op) &&
+ "Non-comparison ops should be rewritten as comparisons to zero.");
+
+ // Simplification: translate an assume of a constraint of the form
+ // "(exp comparison_op expr) != 0" to true into an assume of
+ // "exp comparison_op expr" to true. (And similarly, an assume of the form
+ // "(exp comparison_op expr) == 0" to true into an assume of
+ // "exp comparison_op expr" to false.)
+ if (Int == 0 && (Op == BO_EQ || Op == BO_NE)) {
+ if (const BinarySymExpr *SE = dyn_cast<BinarySymExpr>(Sym))
+ if (BinaryOperator::isComparisonOp(SE->getOpcode()))
+ return assumeSym(State, Sym, (Op == BO_NE ? true : false));
+ }
+
+ // Get the type used for calculating wraparound.
+ BasicValueFactory &BVF = getBasicVals();
+ APSIntType WraparoundType = BVF.getAPSIntType(Sym->getType());
+
+ // We only handle simple comparisons of the form "$sym == constant"
+ // or "($sym+constant1) == constant2".
+ // The adjustment is "constant1" in the above expression. It's used to
+ // "slide" the solution range around for modular arithmetic. For example,
+ // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
+ // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to
+ // the subclasses of SimpleConstraintManager to handle the adjustment.
+ llvm::APSInt Adjustment = WraparoundType.getZeroValue();
+ computeAdjustment(Sym, Adjustment);
+
+ // Convert the right-hand side integer as necessary.
+ APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int));
+ llvm::APSInt ConvertedInt = ComparisonType.convert(Int);
+
+ // Prefer unsigned comparisons.
+ if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
+ ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
+ Adjustment.setIsSigned(false);
+
+ switch (Op) {
+ default:
+ llvm_unreachable("invalid operation not caught by assertion above");
+
+ case BO_EQ:
+ return assumeSymEQ(State, Sym, ConvertedInt, Adjustment);
+
+ case BO_NE:
+ return assumeSymNE(State, Sym, ConvertedInt, Adjustment);
+
+ case BO_GT:
+ return assumeSymGT(State, Sym, ConvertedInt, Adjustment);
+
+ case BO_GE:
+ return assumeSymGE(State, Sym, ConvertedInt, Adjustment);
+
+ case BO_LT:
+ return assumeSymLT(State, Sym, ConvertedInt, Adjustment);
+
+ case BO_LE:
+ return assumeSymLE(State, Sym, ConvertedInt, Adjustment);
+ } // end switch
+}
+
+void RangedConstraintManager::computeAdjustment(SymbolRef &Sym,
+ llvm::APSInt &Adjustment) {
+ // Is it a "($sym+constant1)" expression?
+ if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(Sym)) {
+ BinaryOperator::Opcode Op = SE->getOpcode();
+ if (Op == BO_Add || Op == BO_Sub) {
+ Sym = SE->getLHS();
+ Adjustment = APSIntType(Adjustment).convert(SE->getRHS());
+
+ // Don't forget to negate the adjustment if it's being subtracted.
+ // This should happen /after/ promotion, in case the value being
+ // subtracted is, say, CHAR_MIN, and the promoted type is 'int'.
+ if (Op == BO_Sub)
+ Adjustment = -Adjustment;
+ }
+ }
+}
+
+} // end of namespace ento
+
+} // end of namespace clang
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.h
index 1128e77..a4e6062 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.h
@@ -1,4 +1,4 @@
-//== SimpleConstraintManager.h ----------------------------------*- C++ -*--==//
+//== RangedConstraintManager.h ----------------------------------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
@@ -7,59 +7,55 @@
//
//===----------------------------------------------------------------------===//
//
-// Code shared between BasicConstraintManager and RangeConstraintManager.
+// Ranged constraint manager, built on SimpleConstraintManager.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_SIMPLECONSTRAINTMANAGER_H
-#define LLVM_CLANG_LIB_STATICANALYZER_CORE_SIMPLECONSTRAINTMANAGER_H
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_RANGEDCONSTRAINTMANAGER_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CORE_RANGEDCONSTRAINTMANAGER_H
-#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h"
namespace clang {
namespace ento {
-class SimpleConstraintManager : public ConstraintManager {
- SubEngine *SU;
- SValBuilder &SVB;
-
+class RangedConstraintManager : public SimpleConstraintManager {
public:
- SimpleConstraintManager(SubEngine *SE, SValBuilder &SB) : SU(SE), SVB(SB) {}
- ~SimpleConstraintManager() override;
+ RangedConstraintManager(SubEngine *SE, SValBuilder &SB)
+ : SimpleConstraintManager(SE, SB) {}
+
+ ~RangedConstraintManager() override;
//===------------------------------------------------------------------===//
- // Common implementation for the interface provided by ConstraintManager.
+ // Implementation for interface from SimpleConstraintManager.
//===------------------------------------------------------------------===//
- ProgramStateRef assume(ProgramStateRef State, DefinedSVal Cond,
- bool Assumption) override;
+ ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override;
- ProgramStateRef assume(ProgramStateRef State, NonLoc Cond, bool Assumption);
+ ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) override;
- ProgramStateRef assumeInclusiveRange(ProgramStateRef State, NonLoc Value,
- const llvm::APSInt &From,
- const llvm::APSInt &To,
- bool InRange) override;
+ ProgramStateRef assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override;
- ProgramStateRef assumeSymRel(ProgramStateRef State, const SymExpr *LHS,
- BinaryOperator::Opcode Op,
+protected:
+ /// Assume a constraint between a symbolic expression and a concrete integer.
+ virtual ProgramStateRef assumeSymRel(ProgramStateRef State, SymbolRef Sym,
+ BinaryOperator::Opcode op,
const llvm::APSInt &Int);
- ProgramStateRef assumeSymWithinInclusiveRange(ProgramStateRef State,
- SymbolRef Sym,
- const llvm::APSInt &From,
- const llvm::APSInt &To,
- bool InRange);
-
-protected:
//===------------------------------------------------------------------===//
// Interface that subclasses must implement.
//===------------------------------------------------------------------===//
// Each of these is of the form "$Sym+Adj <> V", where "<>" is the comparison
// operation for the method being invoked.
+
virtual ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) = 0;
@@ -84,28 +80,19 @@ protected:
const llvm::APSInt &V,
const llvm::APSInt &Adjustment) = 0;
- virtual ProgramStateRef assumeSymbolWithinInclusiveRange(
+ virtual ProgramStateRef assumeSymWithinInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
- virtual ProgramStateRef assumeSymbolOutOfInclusiveRange(
+ virtual ProgramStateRef assumeSymOutsideInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
//===------------------------------------------------------------------===//
// Internal implementation.
//===------------------------------------------------------------------===//
-
- BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); }
- SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); }
-
- bool canReasonAbout(SVal X) const override;
-
- ProgramStateRef assumeAux(ProgramStateRef State, NonLoc Cond,
- bool Assumption);
-
- ProgramStateRef assumeAuxForSymbol(ProgramStateRef State, SymbolRef Sym,
- bool Assumption);
+private:
+ static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment);
};
} // end GR namespace
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 934cc5c..11902f6 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -409,6 +409,19 @@ public: // Part of public interface to class.
// BindDefault is only used to initialize a region with a default value.
StoreRef BindDefault(Store store, const MemRegion *R, SVal V) override {
+ // FIXME: The offsets of empty bases can be tricky because of
+ // of the so called "empty base class optimization".
+ // If a base class has been optimized out
+ // we should not try to create a binding, otherwise we should.
+ // Unfortunately, at the moment ASTRecordLayout doesn't expose
+ // the actual sizes of the empty bases
+ // and trying to infer them from offsets/alignments
+ // seems to be error-prone and non-trivial because of the trailing padding.
+ // As a temporary mitigation we don't create bindings for empty bases.
+ if (R->getKind() == MemRegion::CXXBaseObjectRegionKind &&
+ cast<CXXBaseObjectRegion>(R)->getDecl()->isEmpty())
+ return StoreRef(store, *this);
+
RegionBindingsRef B = getRegionBindings(store);
assert(!B.lookup(R, BindingKey::Direct));
@@ -494,6 +507,14 @@ public: // Part of public interface to class.
return getBinding(getRegionBindings(S), L, T);
}
+ Optional<SVal> getDefaultBinding(Store S, const MemRegion *R) override {
+ RegionBindingsRef B = getRegionBindings(S);
+ // Default bindings are always applied over a base region so look up the
+ // base region's default binding, otherwise the lookup will fail when R
+ // is at an offset from R->getBaseRegion().
+ return B.getDefaultBinding(R->getBaseRegion());
+ }
+
SVal getBinding(RegionBindingsConstRef B, Loc L, QualType T = QualType());
SVal getBindingForElement(RegionBindingsConstRef B, const ElementRegion *R);
@@ -1333,10 +1354,14 @@ RegionStoreManager::getSizeInElements(ProgramStateRef state,
/// the array). This is called by ExprEngine when evaluating casts
/// from arrays to pointers.
SVal RegionStoreManager::ArrayToPointer(Loc Array, QualType T) {
+ if (Array.getAs<loc::ConcreteInt>())
+ return Array;
+
if (!Array.getAs<loc::MemRegionVal>())
return UnknownVal();
- const MemRegion* R = Array.castAs<loc::MemRegionVal>().getRegion();
+ const SubRegion *R =
+ cast<SubRegion>(Array.castAs<loc::MemRegionVal>().getRegion());
NonLoc ZeroIdx = svalBuilder.makeZeroArrayIndex();
return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, R, Ctx));
}
@@ -1379,7 +1404,7 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
T = SR->getSymbol()->getType();
}
}
- MR = GetElementZeroRegion(MR, T);
+ MR = GetElementZeroRegion(cast<SubRegion>(MR), T);
}
// FIXME: Perhaps this method should just take a 'const MemRegion*' argument
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index ffaa0ed..04452e3 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -325,6 +325,7 @@ Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
}
}
// FALLTHROUGH
+ LLVM_FALLTHROUGH;
}
// If we don't have a special case, fall back to the AST's constant evaluator.
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 0e512ff..adb4017 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -7,12 +7,12 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines SimpleConstraintManager, a class that holds code shared
-// between BasicConstraintManager and RangeConstraintManager.
+// This file defines SimpleConstraintManager, a class that provides a
+// simplified constraint manager interface, compared to ConstraintManager.
//
//===----------------------------------------------------------------------===//
-#include "SimpleConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
@@ -23,48 +23,6 @@ namespace ento {
SimpleConstraintManager::~SimpleConstraintManager() {}
-bool SimpleConstraintManager::canReasonAbout(SVal X) const {
- Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
- if (SymVal && SymVal->isExpression()) {
- const SymExpr *SE = SymVal->getSymbol();
-
- if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
- switch (SIE->getOpcode()) {
- // We don't reason yet about bitwise-constraints on symbolic values.
- case BO_And:
- case BO_Or:
- case BO_Xor:
- return false;
- // We don't reason yet about these arithmetic constraints on
- // symbolic values.
- case BO_Mul:
- case BO_Div:
- case BO_Rem:
- case BO_Shl:
- case BO_Shr:
- return false;
- // All other cases.
- default:
- return true;
- }
- }
-
- if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
- if (BinaryOperator::isComparisonOp(SSE->getOpcode())) {
- // We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc.
- if (Loc::isLocType(SSE->getLHS()->getType())) {
- assert(Loc::isLocType(SSE->getRHS()->getType()));
- return true;
- }
- }
- }
-
- return false;
- }
-
- return true;
-}
-
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
DefinedSVal Cond,
bool Assumption) {
@@ -92,23 +50,6 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
return State;
}
-ProgramStateRef
-SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State,
- SymbolRef Sym, bool Assumption) {
- BasicValueFactory &BVF = getBasicVals();
- QualType T = Sym->getType();
-
- // None of the constraint solvers currently support non-integer types.
- if (!T->isIntegralOrEnumerationType())
- return State;
-
- const llvm::APSInt &zero = BVF.getValue(0, T);
- if (Assumption)
- return assumeSymNE(State, Sym, zero, zero);
- else
- return assumeSymEQ(State, Sym, zero, zero);
-}
-
ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State,
NonLoc Cond,
bool Assumption) {
@@ -118,7 +59,8 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State,
if (!canReasonAbout(Cond)) {
// Just add the constraint to the expression without trying to simplify.
SymbolRef Sym = Cond.getAsSymExpr();
- return assumeAuxForSymbol(State, Sym, Assumption);
+ assert(Sym);
+ return assumeSymUnsupported(State, Sym, Assumption);
}
switch (Cond.getSubKind()) {
@@ -129,51 +71,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State,
nonloc::SymbolVal SV = Cond.castAs<nonloc::SymbolVal>();
SymbolRef Sym = SV.getSymbol();
assert(Sym);
-
- // Handle SymbolData.
- if (!SV.isExpression()) {
- return assumeAuxForSymbol(State, Sym, Assumption);
-
- // Handle symbolic expression.
- } else if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(Sym)) {
- // We can only simplify expressions whose RHS is an integer.
-
- BinaryOperator::Opcode Op = SE->getOpcode();
- if (BinaryOperator::isComparisonOp(Op)) {
- if (!Assumption)
- Op = BinaryOperator::negateComparisonOp(Op);
-
- return assumeSymRel(State, SE->getLHS(), Op, SE->getRHS());
- }
-
- } else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(Sym)) {
- // Translate "a != b" to "(b - a) != 0".
- // We invert the order of the operands as a heuristic for how loop
- // conditions are usually written ("begin != end") as compared to length
- // calculations ("end - begin"). The more correct thing to do would be to
- // canonicalize "a - b" and "b - a", which would allow us to treat
- // "a != b" and "b != a" the same.
- SymbolManager &SymMgr = getSymbolManager();
- BinaryOperator::Opcode Op = SSE->getOpcode();
- assert(BinaryOperator::isComparisonOp(Op));
-
- // For now, we only support comparing pointers.
- assert(Loc::isLocType(SSE->getLHS()->getType()));
- assert(Loc::isLocType(SSE->getRHS()->getType()));
- QualType DiffTy = SymMgr.getContext().getPointerDiffType();
- SymbolRef Subtraction =
- SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub, SSE->getLHS(), DiffTy);
-
- const llvm::APSInt &Zero = getBasicVals().getValue(0, DiffTy);
- Op = BinaryOperator::reverseComparisonOp(Op);
- if (!Assumption)
- Op = BinaryOperator::negateComparisonOp(Op);
- return assumeSymRel(State, Subtraction, Op, Zero);
- }
-
- // If we get here, there's nothing else we can do but treat the symbol as
- // opaque.
- return assumeAuxForSymbol(State, Sym, Assumption);
+ return assumeSym(State, Sym, Assumption);
}
case nonloc::ConcreteIntKind: {
@@ -206,7 +104,7 @@ ProgramStateRef SimpleConstraintManager::assumeInclusiveRange(
// Just add the constraint to the expression without trying to simplify.
SymbolRef Sym = Value.getAsSymExpr();
assert(Sym);
- return assumeSymWithinInclusiveRange(State, Sym, From, To, InRange);
+ return assumeSymInclusiveRange(State, Sym, From, To, InRange);
}
switch (Value.getSubKind()) {
@@ -217,7 +115,7 @@ ProgramStateRef SimpleConstraintManager::assumeInclusiveRange(
case nonloc::LocAsIntegerKind:
case nonloc::SymbolValKind: {
if (SymbolRef Sym = Value.getAsSymbol())
- return assumeSymWithinInclusiveRange(State, Sym, From, To, InRange);
+ return assumeSymInclusiveRange(State, Sym, From, To, InRange);
return State;
} // end switch
@@ -230,118 +128,6 @@ ProgramStateRef SimpleConstraintManager::assumeInclusiveRange(
} // end switch
}
-static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment) {
- // Is it a "($sym+constant1)" expression?
- if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(Sym)) {
- BinaryOperator::Opcode Op = SE->getOpcode();
- if (Op == BO_Add || Op == BO_Sub) {
- Sym = SE->getLHS();
- Adjustment = APSIntType(Adjustment).convert(SE->getRHS());
-
- // Don't forget to negate the adjustment if it's being subtracted.
- // This should happen /after/ promotion, in case the value being
- // subtracted is, say, CHAR_MIN, and the promoted type is 'int'.
- if (Op == BO_Sub)
- Adjustment = -Adjustment;
- }
- }
-}
-
-ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef State,
- const SymExpr *LHS,
- BinaryOperator::Opcode Op,
- const llvm::APSInt &Int) {
- assert(BinaryOperator::isComparisonOp(Op) &&
- "Non-comparison ops should be rewritten as comparisons to zero.");
-
- SymbolRef Sym = LHS;
-
- // Simplification: translate an assume of a constraint of the form
- // "(exp comparison_op expr) != 0" to true into an assume of
- // "exp comparison_op expr" to true. (And similarly, an assume of the form
- // "(exp comparison_op expr) == 0" to true into an assume of
- // "exp comparison_op expr" to false.)
- if (Int == 0 && (Op == BO_EQ || Op == BO_NE)) {
- if (const BinarySymExpr *SE = dyn_cast<BinarySymExpr>(Sym))
- if (BinaryOperator::isComparisonOp(SE->getOpcode()))
- return assume(State, nonloc::SymbolVal(Sym), (Op == BO_NE ? true : false));
- }
-
- // Get the type used for calculating wraparound.
- BasicValueFactory &BVF = getBasicVals();
- APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType());
-
- // We only handle simple comparisons of the form "$sym == constant"
- // or "($sym+constant1) == constant2".
- // The adjustment is "constant1" in the above expression. It's used to
- // "slide" the solution range around for modular arithmetic. For example,
- // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
- // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to
- // the subclasses of SimpleConstraintManager to handle the adjustment.
- llvm::APSInt Adjustment = WraparoundType.getZeroValue();
- computeAdjustment(Sym, Adjustment);
-
- // Convert the right-hand side integer as necessary.
- APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int));
- llvm::APSInt ConvertedInt = ComparisonType.convert(Int);
-
- // Prefer unsigned comparisons.
- if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
- ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
- Adjustment.setIsSigned(false);
-
- switch (Op) {
- default:
- llvm_unreachable("invalid operation not caught by assertion above");
-
- case BO_EQ:
- return assumeSymEQ(State, Sym, ConvertedInt, Adjustment);
-
- case BO_NE:
- return assumeSymNE(State, Sym, ConvertedInt, Adjustment);
-
- case BO_GT:
- return assumeSymGT(State, Sym, ConvertedInt, Adjustment);
-
- case BO_GE:
- return assumeSymGE(State, Sym, ConvertedInt, Adjustment);
-
- case BO_LT:
- return assumeSymLT(State, Sym, ConvertedInt, Adjustment);
-
- case BO_LE:
- return assumeSymLE(State, Sym, ConvertedInt, Adjustment);
- } // end switch
-}
-
-ProgramStateRef SimpleConstraintManager::assumeSymWithinInclusiveRange(
- ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
- const llvm::APSInt &To, bool InRange) {
- // Get the type used for calculating wraparound.
- BasicValueFactory &BVF = getBasicVals();
- APSIntType WraparoundType = BVF.getAPSIntType(Sym->getType());
-
- llvm::APSInt Adjustment = WraparoundType.getZeroValue();
- SymbolRef AdjustedSym = Sym;
- computeAdjustment(AdjustedSym, Adjustment);
-
- // Convert the right-hand side integer as necessary.
- APSIntType ComparisonType = std::max(WraparoundType, APSIntType(From));
- llvm::APSInt ConvertedFrom = ComparisonType.convert(From);
- llvm::APSInt ConvertedTo = ComparisonType.convert(To);
-
- // Prefer unsigned comparisons.
- if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
- ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
- Adjustment.setIsSigned(false);
-
- if (InRange)
- return assumeSymbolWithinInclusiveRange(State, AdjustedSym, ConvertedFrom,
- ConvertedTo, Adjustment);
- return assumeSymbolOutOfInclusiveRange(State, AdjustedSym, ConvertedFrom,
- ConvertedTo, Adjustment);
-}
-
} // end of namespace ento
} // end of namespace clang
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 28b43dd..f09f969 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
using namespace clang;
using namespace ento;
@@ -44,6 +45,10 @@ public:
/// (integer) value, that value is returned. Otherwise, returns NULL.
const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V) override;
+ /// Recursively descends into symbolic expressions and replaces symbols
+ /// with their known values (in the sense of the getKnownValue() method).
+ SVal simplifySVal(ProgramStateRef State, SVal V) override;
+
SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op,
const llvm::APSInt &RHS, QualType resultTy);
};
@@ -66,18 +71,15 @@ SVal SimpleSValBuilder::dispatchCast(SVal Val, QualType CastTy) {
}
SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
-
bool isLocType = Loc::isLocType(castTy);
-
if (val.getAs<nonloc::PointerToMember>())
return val;
if (Optional<nonloc::LocAsInteger> LI = val.getAs<nonloc::LocAsInteger>()) {
if (isLocType)
return LI->getLoc();
-
// FIXME: Correctly support promotions/truncations.
- unsigned castSize = Context.getTypeSize(castTy);
+ unsigned castSize = Context.getIntWidth(castTy);
if (castSize == LI->getNumBits())
return val;
return makeLocAsInteger(LI->getLoc(), castSize);
@@ -158,6 +160,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
return nonloc::SymbolVal(SymR->getSymbol());
// FALL-THROUGH
+ LLVM_FALLTHROUGH;
}
case loc::GotoLabelKind:
@@ -167,7 +170,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
}
if (castTy->isIntegralOrEnumerationType()) {
- unsigned BitWidth = Context.getTypeSize(castTy);
+ unsigned BitWidth = Context.getIntWidth(castTy);
if (!val.getAs<loc::ConcreteInt>())
return makeLocAsInteger(val, BitWidth);
@@ -362,6 +365,9 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
resultTy);
case nonloc::ConcreteIntKind: {
// Transform the integer into a location and compare.
+ // FIXME: This only makes sense for comparisons. If we want to, say,
+ // add 1 to a LocAsInteger, we'd better unpack the Loc and add to it,
+ // then pack it back into a LocAsInteger.
llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue();
BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
@@ -534,11 +540,12 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
// Does the symbolic expression simplify to a constant?
// If so, "fold" the constant by setting 'lhs' to a ConcreteInt
// and try again.
- ConstraintManager &CMgr = state->getConstraintManager();
- if (const llvm::APSInt *Constant = CMgr.getSymVal(state, Sym)) {
- lhs = nonloc::ConcreteInt(*Constant);
- continue;
- }
+ SVal simplifiedLhs = simplifySVal(state, lhs);
+ if (simplifiedLhs != lhs)
+ if (auto simplifiedLhsAsNonLoc = simplifiedLhs.getAs<NonLoc>()) {
+ lhs = *simplifiedLhsAsNonLoc;
+ continue;
+ }
// Is the RHS a constant?
if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs))
@@ -941,20 +948,26 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
if (const MemRegion *region = lhs.getAsRegion()) {
rhs = convertToArrayIndex(rhs).castAs<NonLoc>();
SVal index = UnknownVal();
- const MemRegion *superR = nullptr;
+ const SubRegion *superR = nullptr;
+ // We need to know the type of the pointer in order to add an integer to it.
+ // Depending on the type, different amount of bytes is added.
QualType elementType;
if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) {
assert(op == BO_Add || op == BO_Sub);
index = evalBinOpNN(state, op, elemReg->getIndex(), rhs,
getArrayIndexType());
- superR = elemReg->getSuperRegion();
+ superR = cast<SubRegion>(elemReg->getSuperRegion());
elementType = elemReg->getElementType();
}
else if (isa<SubRegion>(region)) {
assert(op == BO_Add || op == BO_Sub);
index = (op == BO_Add) ? rhs : evalMinus(rhs);
- superR = region;
+ superR = cast<SubRegion>(region);
+ // TODO: Is this actually reliable? Maybe improving our MemRegion
+ // hierarchy to provide typed regions for all non-void pointers would be
+ // better. For instance, we cannot extend this towards LocAsInteger
+ // operations, where result type of the expression is integer.
if (resultTy->isAnyPointerType())
elementType = resultTy->getPointeeType();
}
@@ -984,3 +997,74 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
// FIXME: Add support for SymExprs.
return nullptr;
}
+
+SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
+ // For now, this function tries to constant-fold symbols inside a
+ // nonloc::SymbolVal, and does nothing else. More simplifications should
+ // be possible, such as constant-folding an index in an ElementRegion.
+
+ class Simplifier : public FullSValVisitor<Simplifier, SVal> {
+ ProgramStateRef State;
+ SValBuilder &SVB;
+
+ public:
+ Simplifier(ProgramStateRef State)
+ : State(State), SVB(State->getStateManager().getSValBuilder()) {}
+
+ SVal VisitSymbolData(const SymbolData *S) {
+ if (const llvm::APSInt *I =
+ SVB.getKnownValue(State, nonloc::SymbolVal(S)))
+ return Loc::isLocType(S->getType()) ? (SVal)SVB.makeIntLocVal(*I)
+ : (SVal)SVB.makeIntVal(*I);
+ return nonloc::SymbolVal(S);
+ }
+
+ // TODO: Support SymbolCast. Support IntSymExpr when/if we actually
+ // start producing them.
+
+ SVal VisitSymIntExpr(const SymIntExpr *S) {
+ SVal LHS = Visit(S->getLHS());
+ SVal RHS;
+ // By looking at the APSInt in the right-hand side of S, we cannot
+ // figure out if it should be treated as a Loc or as a NonLoc.
+ // So make our guess by recalling that we cannot multiply pointers
+ // or compare a pointer to an integer.
+ if (Loc::isLocType(S->getLHS()->getType()) &&
+ BinaryOperator::isComparisonOp(S->getOpcode())) {
+ // The usual conversion of $sym to &SymRegion{$sym}, as they have
+ // the same meaning for Loc-type symbols, but the latter form
+ // is preferred in SVal computations for being Loc itself.
+ if (SymbolRef Sym = LHS.getAsSymbol()) {
+ assert(Loc::isLocType(Sym->getType()));
+ LHS = SVB.makeLoc(Sym);
+ }
+ RHS = SVB.makeIntLocVal(S->getRHS());
+ } else {
+ RHS = SVB.makeIntVal(S->getRHS());
+ }
+ return SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType());
+ }
+
+ SVal VisitSymSymExpr(const SymSymExpr *S) {
+ SVal LHS = Visit(S->getLHS());
+ SVal RHS = Visit(S->getRHS());
+ return SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType());
+ }
+
+ SVal VisitSymExpr(SymbolRef S) { return nonloc::SymbolVal(S); }
+
+ SVal VisitMemRegion(const MemRegion *R) { return loc::MemRegionVal(R); }
+
+ SVal VisitNonLocSymbolVal(nonloc::SymbolVal V) {
+ // Simplification is much more costly than computing complexity.
+ // For high complexity, it may be not worth it.
+ if (V.getSymbol()->computeComplexity() > 100)
+ return V;
+ return Visit(V.getSymbol());
+ }
+
+ SVal VisitSVal(SVal V) { return V; }
+ };
+
+ return Simplifier(State).Visit(V);
+}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp
index aca6e3b..1af49f6 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -42,8 +42,9 @@ StoreRef StoreManager::enterStackFrame(Store OldStore,
return Store;
}
-const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
- QualType EleTy, uint64_t index) {
+const ElementRegion *StoreManager::MakeElementRegion(const SubRegion *Base,
+ QualType EleTy,
+ uint64_t index) {
NonLoc idx = svalBuilder.makeArrayIndex(index);
return MRMgr.getElementRegion(EleTy, idx, Base, svalBuilder.getContext());
}
@@ -52,7 +53,7 @@ StoreRef StoreManager::BindDefault(Store store, const MemRegion *R, SVal V) {
return StoreRef(store, *this);
}
-const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R,
+const ElementRegion *StoreManager::GetElementZeroRegion(const SubRegion *R,
QualType T) {
NonLoc idx = svalBuilder.makeZeroArrayIndex();
assert(!T.isNull());
@@ -126,7 +127,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
case MemRegion::VarRegionKind:
case MemRegion::CXXTempObjectRegionKind:
case MemRegion::CXXBaseObjectRegionKind:
- return MakeElementRegion(R, PointeeTy);
+ return MakeElementRegion(cast<SubRegion>(R), PointeeTy);
case MemRegion::ElementRegionKind: {
// If we are casting from an ElementRegion to another type, the
@@ -171,7 +172,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
}
// Otherwise, create a new ElementRegion at offset 0.
- return MakeElementRegion(baseR, PointeeTy);
+ return MakeElementRegion(cast<SubRegion>(baseR), PointeeTy);
}
// We have a non-zero offset from the base region. We want to determine
@@ -202,10 +203,11 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
if (!newSuperR) {
// Create an intermediate ElementRegion to represent the raw byte.
// This will be the super region of the final ElementRegion.
- newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off.getQuantity());
+ newSuperR = MakeElementRegion(cast<SubRegion>(baseR), Ctx.CharTy,
+ off.getQuantity());
}
- return MakeElementRegion(newSuperR, PointeeTy, newIndex);
+ return MakeElementRegion(cast<SubRegion>(newSuperR), PointeeTy, newIndex);
}
}
@@ -271,9 +273,8 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType,
BaseDecl = BaseType->getAsCXXRecordDecl();
assert(BaseDecl && "not a C++ object?");
- const MemRegion *BaseReg =
- MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion(),
- IsVirtual);
+ const MemRegion *BaseReg = MRMgr.getCXXBaseObjectRegion(
+ BaseDecl, cast<SubRegion>(DerivedRegVal->getRegion()), IsVirtual);
return loc::MemRegionVal(BaseReg);
}
@@ -390,11 +391,11 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
return Base;
Loc BaseL = Base.castAs<Loc>();
- const MemRegion* BaseR = nullptr;
+ const SubRegion* BaseR = nullptr;
switch (BaseL.getSubKind()) {
case loc::MemRegionValKind:
- BaseR = BaseL.castAs<loc::MemRegionVal>().getRegion();
+ BaseR = cast<SubRegion>(BaseL.castAs<loc::MemRegionVal>().getRegion());
break;
case loc::GotoLabelKind:
@@ -403,9 +404,15 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
case loc::ConcreteIntKind:
// While these seem funny, this can happen through casts.
- // FIXME: What we should return is the field offset. For example,
- // add the field offset to the integer value. That way funny things
+ // FIXME: What we should return is the field offset, not base. For example,
+ // add the field offset to the integer value. That way things
// like this work properly: &(((struct foo *) 0xa)->f)
+ // However, that's not easy to fix without reducing our abilities
+ // to catch null pointer dereference. Eg., ((struct foo *)0x0)->f = 7
+ // is a null dereference even though we're dereferencing offset of f
+ // rather than null. Coming up with an approach that computes offsets
+ // over null pointers properly while still being able to catch null
+ // dereferences might be worth it.
return Base;
default:
@@ -430,11 +437,12 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
// If the base is an unknown or undefined value, just return it back.
// FIXME: For absolute pointer addresses, we just return that value back as
// well, although in reality we should return the offset added to that
- // value.
+ // value. See also the similar FIXME in getLValueFieldOrIvar().
if (Base.isUnknownOrUndef() || Base.getAs<loc::ConcreteInt>())
return Base;
- const MemRegion* BaseRegion = Base.castAs<loc::MemRegionVal>().getRegion();
+ const SubRegion *BaseRegion =
+ Base.castAs<loc::MemRegionVal>().getRegionAs<SubRegion>();
// Pointer of any type can be cast and used as array base.
const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
@@ -471,9 +479,8 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
if (isa<ElementRegion>(BaseRegion->StripCasts()))
return UnknownVal();
- return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
- ElemR->getSuperRegion(),
- Ctx));
+ return loc::MemRegionVal(MRMgr.getElementRegion(
+ elementType, Offset, cast<SubRegion>(ElemR->getSuperRegion()), Ctx));
}
const llvm::APSInt& OffI = Offset.castAs<nonloc::ConcreteInt>().getValue();
@@ -484,7 +491,7 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
OffI));
// Construct the new ElementRegion.
- const MemRegion *ArrayR = ElemR->getSuperRegion();
+ const SubRegion *ArrayR = cast<SubRegion>(ElemR->getSuperRegion());
return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR,
Ctx));
}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp
new file mode 100644
index 0000000..f9f9057
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Z3ConstraintManager.cpp
@@ -0,0 +1,1618 @@
+//== Z3ConstraintManager.cpp --------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h"
+
+#include "clang/Config/config.h"
+
+using namespace clang;
+using namespace ento;
+
+#if CLANG_ANALYZER_WITH_Z3
+
+#include <z3.h>
+
+// Forward declarations
+namespace {
+class Z3Expr;
+class ConstraintZ3 {};
+} // end anonymous namespace
+
+typedef llvm::ImmutableSet<std::pair<SymbolRef, Z3Expr>> ConstraintZ3Ty;
+
+// Expansion of REGISTER_TRAIT_WITH_PROGRAMSTATE(ConstraintZ3, Z3SetPair)
+namespace clang {
+namespace ento {
+template <>
+struct ProgramStateTrait<ConstraintZ3>
+ : public ProgramStatePartialTrait<ConstraintZ3Ty> {
+ static void *GDMIndex() {
+ static int Index;
+ return &Index;
+ }
+};
+} // end namespace ento
+} // end namespace clang
+
+namespace {
+
+class Z3Config {
+ friend class Z3Context;
+
+ Z3_config Config;
+
+public:
+ Z3Config() : Config(Z3_mk_config()) {
+ // Enable model finding
+ Z3_set_param_value(Config, "model", "true");
+ // Disable proof generation
+ Z3_set_param_value(Config, "proof", "false");
+ // Set timeout to 15000ms = 15s
+ Z3_set_param_value(Config, "timeout", "15000");
+ }
+
+ ~Z3Config() { Z3_del_config(Config); }
+}; // end class Z3Config
+
+class Z3Context {
+ Z3_context ZC_P;
+
+public:
+ static Z3_context ZC;
+
+ Z3Context() : ZC_P(Z3_mk_context_rc(Z3Config().Config)) { ZC = ZC_P; }
+
+ ~Z3Context() {
+ Z3_del_context(ZC);
+ Z3_finalize_memory();
+ ZC_P = nullptr;
+ }
+}; // end class Z3Context
+
+class Z3Sort {
+ friend class Z3Expr;
+
+ Z3_sort Sort;
+
+ Z3Sort() : Sort(nullptr) {}
+ Z3Sort(Z3_sort ZS) : Sort(ZS) {
+ Z3_inc_ref(Z3Context::ZC, reinterpret_cast<Z3_ast>(Sort));
+ }
+
+public:
+ /// Override implicit copy constructor for correct reference counting.
+ Z3Sort(const Z3Sort &Copy) : Sort(Copy.Sort) {
+ Z3_inc_ref(Z3Context::ZC, reinterpret_cast<Z3_ast>(Sort));
+ }
+
+ /// Provide move constructor
+ Z3Sort(Z3Sort &&Move) : Sort(nullptr) { *this = std::move(Move); }
+
+ /// Provide move assignment constructor
+ Z3Sort &operator=(Z3Sort &&Move) {
+ if (this != &Move) {
+ if (Sort)
+ Z3_dec_ref(Z3Context::ZC, reinterpret_cast<Z3_ast>(Sort));
+ Sort = Move.Sort;
+ Move.Sort = nullptr;
+ }
+ return *this;
+ }
+
+ ~Z3Sort() {
+ if (Sort)
+ Z3_dec_ref(Z3Context::ZC, reinterpret_cast<Z3_ast>(Sort));
+ }
+
+ // Return a boolean sort.
+ static Z3Sort getBoolSort() { return Z3Sort(Z3_mk_bool_sort(Z3Context::ZC)); }
+
+ // Return an appropriate bitvector sort for the given bitwidth.
+ static Z3Sort getBitvectorSort(unsigned BitWidth) {
+ return Z3Sort(Z3_mk_bv_sort(Z3Context::ZC, BitWidth));
+ }
+
+ // Return an appropriate floating-point sort for the given bitwidth.
+ static Z3Sort getFloatSort(unsigned BitWidth) {
+ Z3_sort Sort;
+
+ switch (BitWidth) {
+ default:
+ llvm_unreachable("Unsupported floating-point bitwidth!");
+ break;
+ case 16:
+ Sort = Z3_mk_fpa_sort_16(Z3Context::ZC);
+ break;
+ case 32:
+ Sort = Z3_mk_fpa_sort_32(Z3Context::ZC);
+ break;
+ case 64:
+ Sort = Z3_mk_fpa_sort_64(Z3Context::ZC);
+ break;
+ case 128:
+ Sort = Z3_mk_fpa_sort_128(Z3Context::ZC);
+ break;
+ }
+ return Z3Sort(Sort);
+ }
+
+ // Return an appropriate sort for the given AST.
+ static Z3Sort getSort(Z3_ast AST) {
+ return Z3Sort(Z3_get_sort(Z3Context::ZC, AST));
+ }
+
+ Z3_sort_kind getSortKind() const {
+ return Z3_get_sort_kind(Z3Context::ZC, Sort);
+ }
+
+ unsigned getBitvectorSortSize() const {
+ assert(getSortKind() == Z3_BV_SORT && "Not a bitvector sort!");
+ return Z3_get_bv_sort_size(Z3Context::ZC, Sort);
+ }
+
+ unsigned getFloatSortSize() const {
+ assert(getSortKind() == Z3_FLOATING_POINT_SORT &&
+ "Not a floating-point sort!");
+ return Z3_fpa_get_ebits(Z3Context::ZC, Sort) +
+ Z3_fpa_get_sbits(Z3Context::ZC, Sort);
+ }
+
+ bool operator==(const Z3Sort &Other) const {
+ return Z3_is_eq_sort(Z3Context::ZC, Sort, Other.Sort);
+ }
+
+ Z3Sort &operator=(const Z3Sort &Move) {
+ Z3_inc_ref(Z3Context::ZC, reinterpret_cast<Z3_ast>(Move.Sort));
+ Z3_dec_ref(Z3Context::ZC, reinterpret_cast<Z3_ast>(Sort));
+ Sort = Move.Sort;
+ return *this;
+ }
+
+ void print(raw_ostream &OS) const {
+ OS << Z3_sort_to_string(Z3Context::ZC, Sort);
+ }
+
+ LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
+}; // end class Z3Sort
+
+class Z3Expr {
+ friend class Z3Model;
+ friend class Z3Solver;
+
+ Z3_ast AST;
+
+ Z3Expr(Z3_ast ZA) : AST(ZA) { Z3_inc_ref(Z3Context::ZC, AST); }
+
+ // Return an appropriate floating-point rounding mode.
+ static Z3Expr getFloatRoundingMode() {
+ // TODO: Don't assume nearest ties to even rounding mode
+ return Z3Expr(Z3_mk_fpa_rne(Z3Context::ZC));
+ }
+
+ // Determine whether two float semantics are equivalent
+ static bool areEquivalent(const llvm::fltSemantics &LHS,
+ const llvm::fltSemantics &RHS) {
+ return (llvm::APFloat::semanticsPrecision(LHS) ==
+ llvm::APFloat::semanticsPrecision(RHS)) &&
+ (llvm::APFloat::semanticsMinExponent(LHS) ==
+ llvm::APFloat::semanticsMinExponent(RHS)) &&
+ (llvm::APFloat::semanticsMaxExponent(LHS) ==
+ llvm::APFloat::semanticsMaxExponent(RHS)) &&
+ (llvm::APFloat::semanticsSizeInBits(LHS) ==
+ llvm::APFloat::semanticsSizeInBits(RHS));
+ }
+
+public:
+ /// Override implicit copy constructor for correct reference counting.
+ Z3Expr(const Z3Expr &Copy) : AST(Copy.AST) { Z3_inc_ref(Z3Context::ZC, AST); }
+
+ /// Provide move constructor
+ Z3Expr(Z3Expr &&Move) : AST(nullptr) { *this = std::move(Move); }
+
+ /// Provide move assignment constructor
+ Z3Expr &operator=(Z3Expr &&Move) {
+ if (this != &Move) {
+ if (AST)
+ Z3_dec_ref(Z3Context::ZC, AST);
+ AST = Move.AST;
+ Move.AST = nullptr;
+ }
+ return *this;
+ }
+
+ ~Z3Expr() {
+ if (AST)
+ Z3_dec_ref(Z3Context::ZC, AST);
+ }
+
+ /// Get the corresponding IEEE floating-point type for a given bitwidth.
+ static const llvm::fltSemantics &getFloatSemantics(unsigned BitWidth) {
+ switch (BitWidth) {
+ default:
+ llvm_unreachable("Unsupported floating-point semantics!");
+ break;
+ case 16:
+ return llvm::APFloat::IEEEhalf();
+ case 32:
+ return llvm::APFloat::IEEEsingle();
+ case 64:
+ return llvm::APFloat::IEEEdouble();
+ case 128:
+ return llvm::APFloat::IEEEquad();
+ }
+ }
+
+ /// Construct a Z3Expr from a unary operator, given a Z3_context.
+ static Z3Expr fromUnOp(const UnaryOperator::Opcode Op, const Z3Expr &Exp) {
+ Z3_ast AST;
+
+ switch (Op) {
+ default:
+ llvm_unreachable("Unimplemented opcode");
+ break;
+
+ case UO_Minus:
+ AST = Z3_mk_bvneg(Z3Context::ZC, Exp.AST);
+ break;
+
+ case UO_Not:
+ AST = Z3_mk_bvnot(Z3Context::ZC, Exp.AST);
+ break;
+
+ case UO_LNot:
+ AST = Z3_mk_not(Z3Context::ZC, Exp.AST);
+ break;
+ }
+
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from a floating-point unary operator, given a
+ /// Z3_context.
+ static Z3Expr fromFloatUnOp(const UnaryOperator::Opcode Op,
+ const Z3Expr &Exp) {
+ Z3_ast AST;
+
+ switch (Op) {
+ default:
+ llvm_unreachable("Unimplemented opcode");
+ break;
+
+ case UO_Minus:
+ AST = Z3_mk_fpa_neg(Z3Context::ZC, Exp.AST);
+ break;
+
+ case UO_LNot:
+ return Z3Expr::fromUnOp(Op, Exp);
+ }
+
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from a n-ary binary operator.
+ static Z3Expr fromNBinOp(const BinaryOperator::Opcode Op,
+ const std::vector<Z3_ast> &ASTs) {
+ Z3_ast AST;
+
+ switch (Op) {
+ default:
+ llvm_unreachable("Unimplemented opcode");
+ break;
+
+ case BO_LAnd:
+ AST = Z3_mk_and(Z3Context::ZC, ASTs.size(), ASTs.data());
+ break;
+
+ case BO_LOr:
+ AST = Z3_mk_or(Z3Context::ZC, ASTs.size(), ASTs.data());
+ break;
+ }
+
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from a binary operator, given a Z3_context.
+ static Z3Expr fromBinOp(const Z3Expr &LHS, const BinaryOperator::Opcode Op,
+ const Z3Expr &RHS, bool isSigned) {
+ Z3_ast AST;
+
+ assert(Z3Sort::getSort(LHS.AST) == Z3Sort::getSort(RHS.AST) &&
+ "AST's must have the same sort!");
+
+ switch (Op) {
+ default:
+ llvm_unreachable("Unimplemented opcode");
+ break;
+
+ // Multiplicative operators
+ case BO_Mul:
+ AST = Z3_mk_bvmul(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_Div:
+ AST = isSigned ? Z3_mk_bvsdiv(Z3Context::ZC, LHS.AST, RHS.AST)
+ : Z3_mk_bvudiv(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_Rem:
+ AST = isSigned ? Z3_mk_bvsrem(Z3Context::ZC, LHS.AST, RHS.AST)
+ : Z3_mk_bvurem(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+
+ // Additive operators
+ case BO_Add:
+ AST = Z3_mk_bvadd(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_Sub:
+ AST = Z3_mk_bvsub(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+
+ // Bitwise shift operators
+ case BO_Shl:
+ AST = Z3_mk_bvshl(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_Shr:
+ AST = isSigned ? Z3_mk_bvashr(Z3Context::ZC, LHS.AST, RHS.AST)
+ : Z3_mk_bvlshr(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+
+ // Relational operators
+ case BO_LT:
+ AST = isSigned ? Z3_mk_bvslt(Z3Context::ZC, LHS.AST, RHS.AST)
+ : Z3_mk_bvult(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_GT:
+ AST = isSigned ? Z3_mk_bvsgt(Z3Context::ZC, LHS.AST, RHS.AST)
+ : Z3_mk_bvugt(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_LE:
+ AST = isSigned ? Z3_mk_bvsle(Z3Context::ZC, LHS.AST, RHS.AST)
+ : Z3_mk_bvule(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_GE:
+ AST = isSigned ? Z3_mk_bvsge(Z3Context::ZC, LHS.AST, RHS.AST)
+ : Z3_mk_bvuge(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+
+ // Equality operators
+ case BO_EQ:
+ AST = Z3_mk_eq(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_NE:
+ return Z3Expr::fromUnOp(UO_LNot,
+ Z3Expr::fromBinOp(LHS, BO_EQ, RHS, isSigned));
+ break;
+
+ // Bitwise operators
+ case BO_And:
+ AST = Z3_mk_bvand(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_Xor:
+ AST = Z3_mk_bvxor(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_Or:
+ AST = Z3_mk_bvor(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+
+ // Logical operators
+ case BO_LAnd:
+ case BO_LOr: {
+ std::vector<Z3_ast> Args = {LHS.AST, RHS.AST};
+ return Z3Expr::fromNBinOp(Op, Args);
+ }
+ }
+
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from a special floating-point binary operator, given
+ /// a Z3_context.
+ static Z3Expr fromFloatSpecialBinOp(const Z3Expr &LHS,
+ const BinaryOperator::Opcode Op,
+ const llvm::APFloat::fltCategory &RHS) {
+ Z3_ast AST;
+
+ switch (Op) {
+ default:
+ llvm_unreachable("Unimplemented opcode");
+ break;
+
+ // Equality operators
+ case BO_EQ:
+ switch (RHS) {
+ case llvm::APFloat::fcInfinity:
+ AST = Z3_mk_fpa_is_infinite(Z3Context::ZC, LHS.AST);
+ break;
+ case llvm::APFloat::fcNaN:
+ AST = Z3_mk_fpa_is_nan(Z3Context::ZC, LHS.AST);
+ break;
+ case llvm::APFloat::fcNormal:
+ AST = Z3_mk_fpa_is_normal(Z3Context::ZC, LHS.AST);
+ break;
+ case llvm::APFloat::fcZero:
+ AST = Z3_mk_fpa_is_zero(Z3Context::ZC, LHS.AST);
+ break;
+ }
+ break;
+ case BO_NE:
+ return Z3Expr::fromFloatUnOp(
+ UO_LNot, Z3Expr::fromFloatSpecialBinOp(LHS, BO_EQ, RHS));
+ break;
+ }
+
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from a floating-point binary operator, given a
+ /// Z3_context.
+ static Z3Expr fromFloatBinOp(const Z3Expr &LHS,
+ const BinaryOperator::Opcode Op,
+ const Z3Expr &RHS) {
+ Z3_ast AST;
+
+ assert(Z3Sort::getSort(LHS.AST) == Z3Sort::getSort(RHS.AST) &&
+ "AST's must have the same sort!");
+
+ switch (Op) {
+ default:
+ llvm_unreachable("Unimplemented opcode");
+ break;
+
+ // Multiplicative operators
+ case BO_Mul: {
+ Z3Expr RoundingMode = Z3Expr::getFloatRoundingMode();
+ AST = Z3_mk_fpa_mul(Z3Context::ZC, RoundingMode.AST, LHS.AST, RHS.AST);
+ break;
+ }
+ case BO_Div: {
+ Z3Expr RoundingMode = Z3Expr::getFloatRoundingMode();
+ AST = Z3_mk_fpa_div(Z3Context::ZC, RoundingMode.AST, LHS.AST, RHS.AST);
+ break;
+ }
+ case BO_Rem:
+ AST = Z3_mk_fpa_rem(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+
+ // Additive operators
+ case BO_Add: {
+ Z3Expr RoundingMode = Z3Expr::getFloatRoundingMode();
+ AST = Z3_mk_fpa_add(Z3Context::ZC, RoundingMode.AST, LHS.AST, RHS.AST);
+ break;
+ }
+ case BO_Sub: {
+ Z3Expr RoundingMode = Z3Expr::getFloatRoundingMode();
+ AST = Z3_mk_fpa_sub(Z3Context::ZC, RoundingMode.AST, LHS.AST, RHS.AST);
+ break;
+ }
+
+ // Relational operators
+ case BO_LT:
+ AST = Z3_mk_fpa_lt(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_GT:
+ AST = Z3_mk_fpa_gt(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_LE:
+ AST = Z3_mk_fpa_leq(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_GE:
+ AST = Z3_mk_fpa_geq(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+
+ // Equality operators
+ case BO_EQ:
+ AST = Z3_mk_fpa_eq(Z3Context::ZC, LHS.AST, RHS.AST);
+ break;
+ case BO_NE:
+ return Z3Expr::fromFloatUnOp(UO_LNot,
+ Z3Expr::fromFloatBinOp(LHS, BO_EQ, RHS));
+ break;
+
+ // Logical operators
+ case BO_LAnd:
+ case BO_LOr:
+ return Z3Expr::fromBinOp(LHS, Op, RHS, false);
+ }
+
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from a SymbolData, given a Z3_context.
+ static Z3Expr fromData(const SymbolID ID, bool isBool, bool isFloat,
+ uint64_t BitWidth) {
+ llvm::Twine Name = "$" + llvm::Twine(ID);
+
+ Z3Sort Sort;
+ if (isBool)
+ Sort = Z3Sort::getBoolSort();
+ else if (isFloat)
+ Sort = Z3Sort::getFloatSort(BitWidth);
+ else
+ Sort = Z3Sort::getBitvectorSort(BitWidth);
+
+ Z3_symbol Symbol = Z3_mk_string_symbol(Z3Context::ZC, Name.str().c_str());
+ Z3_ast AST = Z3_mk_const(Z3Context::ZC, Symbol, Sort.Sort);
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from a SymbolCast, given a Z3_context.
+ static Z3Expr fromCast(const Z3Expr &Exp, QualType ToTy, uint64_t ToBitWidth,
+ QualType FromTy, uint64_t FromBitWidth) {
+ Z3_ast AST;
+
+ if ((FromTy->isIntegralOrEnumerationType() &&
+ ToTy->isIntegralOrEnumerationType()) ||
+ (FromTy->isAnyPointerType() ^ ToTy->isAnyPointerType()) ||
+ (FromTy->isBlockPointerType() ^ ToTy->isBlockPointerType()) ||
+ (FromTy->isReferenceType() ^ ToTy->isReferenceType())) {
+ // Special case: Z3 boolean type is distinct from bitvector type, so
+ // must use if-then-else expression instead of direct cast
+ if (FromTy->isBooleanType()) {
+ assert(ToBitWidth > 0 && "BitWidth must be positive!");
+ Z3Expr Zero = Z3Expr::fromInt("0", ToBitWidth);
+ Z3Expr One = Z3Expr::fromInt("1", ToBitWidth);
+ AST = Z3_mk_ite(Z3Context::ZC, Exp.AST, One.AST, Zero.AST);
+ } else if (ToBitWidth > FromBitWidth) {
+ AST = FromTy->isSignedIntegerOrEnumerationType()
+ ? Z3_mk_sign_ext(Z3Context::ZC, ToBitWidth - FromBitWidth,
+ Exp.AST)
+ : Z3_mk_zero_ext(Z3Context::ZC, ToBitWidth - FromBitWidth,
+ Exp.AST);
+ } else if (ToBitWidth < FromBitWidth) {
+ AST = Z3_mk_extract(Z3Context::ZC, ToBitWidth - 1, 0, Exp.AST);
+ } else {
+ // Both are bitvectors with the same width, ignore the type cast
+ return Exp;
+ }
+ } else if (FromTy->isRealFloatingType() && ToTy->isRealFloatingType()) {
+ if (ToBitWidth != FromBitWidth) {
+ Z3Expr RoundingMode = Z3Expr::getFloatRoundingMode();
+ Z3Sort Sort = Z3Sort::getFloatSort(ToBitWidth);
+ AST = Z3_mk_fpa_to_fp_float(Z3Context::ZC, RoundingMode.AST, Exp.AST,
+ Sort.Sort);
+ } else {
+ return Exp;
+ }
+ } else if (FromTy->isIntegralOrEnumerationType() &&
+ ToTy->isRealFloatingType()) {
+ Z3Expr RoundingMode = Z3Expr::getFloatRoundingMode();
+ Z3Sort Sort = Z3Sort::getFloatSort(ToBitWidth);
+ AST = FromTy->isSignedIntegerOrEnumerationType()
+ ? Z3_mk_fpa_to_fp_signed(Z3Context::ZC, RoundingMode.AST,
+ Exp.AST, Sort.Sort)
+ : Z3_mk_fpa_to_fp_unsigned(Z3Context::ZC, RoundingMode.AST,
+ Exp.AST, Sort.Sort);
+ } else if (FromTy->isRealFloatingType() &&
+ ToTy->isIntegralOrEnumerationType()) {
+ Z3Expr RoundingMode = Z3Expr::getFloatRoundingMode();
+ AST = ToTy->isSignedIntegerOrEnumerationType()
+ ? Z3_mk_fpa_to_sbv(Z3Context::ZC, RoundingMode.AST, Exp.AST,
+ ToBitWidth)
+ : Z3_mk_fpa_to_ubv(Z3Context::ZC, RoundingMode.AST, Exp.AST,
+ ToBitWidth);
+ } else {
+ llvm_unreachable("Unsupported explicit type cast!");
+ }
+
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from a boolean, given a Z3_context.
+ static Z3Expr fromBoolean(const bool Bool) {
+ Z3_ast AST = Bool ? Z3_mk_true(Z3Context::ZC) : Z3_mk_false(Z3Context::ZC);
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from a finite APFloat, given a Z3_context.
+ static Z3Expr fromAPFloat(const llvm::APFloat &Float) {
+ Z3_ast AST;
+ Z3Sort Sort = Z3Sort::getFloatSort(
+ llvm::APFloat::semanticsSizeInBits(Float.getSemantics()));
+
+ llvm::APSInt Int = llvm::APSInt(Float.bitcastToAPInt(), true);
+ Z3Expr Z3Int = Z3Expr::fromAPSInt(Int);
+ AST = Z3_mk_fpa_to_fp_bv(Z3Context::ZC, Z3Int.AST, Sort.Sort);
+
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from an APSInt, given a Z3_context.
+ static Z3Expr fromAPSInt(const llvm::APSInt &Int) {
+ Z3Sort Sort = Z3Sort::getBitvectorSort(Int.getBitWidth());
+ Z3_ast AST =
+ Z3_mk_numeral(Z3Context::ZC, Int.toString(10).c_str(), Sort.Sort);
+ return Z3Expr(AST);
+ }
+
+ /// Construct a Z3Expr from an integer, given a Z3_context.
+ static Z3Expr fromInt(const char *Int, uint64_t BitWidth) {
+ Z3Sort Sort = Z3Sort::getBitvectorSort(BitWidth);
+ Z3_ast AST = Z3_mk_numeral(Z3Context::ZC, Int, Sort.Sort);
+ return Z3Expr(AST);
+ }
+
+ /// Construct an APFloat from a Z3Expr, given the AST representation
+ static bool toAPFloat(const Z3Sort &Sort, const Z3_ast &AST,
+ llvm::APFloat &Float, bool useSemantics = true) {
+ assert(Sort.getSortKind() == Z3_FLOATING_POINT_SORT &&
+ "Unsupported sort to floating-point!");
+
+ llvm::APSInt Int(Sort.getFloatSortSize(), true);
+ const llvm::fltSemantics &Semantics =
+ Z3Expr::getFloatSemantics(Sort.getFloatSortSize());
+ Z3Sort BVSort = Z3Sort::getBitvectorSort(Sort.getFloatSortSize());
+ if (!Z3Expr::toAPSInt(BVSort, AST, Int, true)) {
+ return false;
+ }
+
+ if (useSemantics &&
+ !Z3Expr::areEquivalent(Float.getSemantics(), Semantics)) {
+ assert(false && "Floating-point types don't match!");
+ return false;
+ }
+
+ Float = llvm::APFloat(Semantics, Int);
+ return true;
+ }
+
+ /// Construct an APSInt from a Z3Expr, given the AST representation
+ static bool toAPSInt(const Z3Sort &Sort, const Z3_ast &AST, llvm::APSInt &Int,
+ bool useSemantics = true) {
+ switch (Sort.getSortKind()) {
+ default:
+ llvm_unreachable("Unsupported sort to integer!");
+ case Z3_BV_SORT: {
+ if (useSemantics && Int.getBitWidth() != Sort.getBitvectorSortSize()) {
+ assert(false && "Bitvector types don't match!");
+ return false;
+ }
+
+ uint64_t Value[2];
+ // Force cast because Z3 defines __uint64 to be a unsigned long long
+ // type, which isn't compatible with a unsigned long type, even if they
+ // are the same size.
+ Z3_get_numeral_uint64(Z3Context::ZC, AST,
+ reinterpret_cast<__uint64 *>(&Value[0]));
+ if (Sort.getBitvectorSortSize() <= 64) {
+ Int = llvm::APSInt(llvm::APInt(Int.getBitWidth(), Value[0]), true);
+ } else if (Sort.getBitvectorSortSize() == 128) {
+ Z3Expr ASTHigh = Z3Expr(Z3_mk_extract(Z3Context::ZC, 127, 64, AST));
+ Z3_get_numeral_uint64(Z3Context::ZC, AST,
+ reinterpret_cast<__uint64 *>(&Value[1]));
+ Int = llvm::APSInt(llvm::APInt(Int.getBitWidth(), Value), true);
+ } else {
+ assert(false && "Bitwidth not supported!");
+ return false;
+ }
+ return true;
+ }
+ case Z3_BOOL_SORT:
+ if (useSemantics && Int.getBitWidth() < 1) {
+ assert(false && "Boolean type doesn't match!");
+ return false;
+ }
+ Int = llvm::APSInt(
+ llvm::APInt(Int.getBitWidth(),
+ Z3_get_bool_value(Z3Context::ZC, AST) == Z3_L_TRUE ? 1
+ : 0),
+ true);
+ return true;
+ }
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(Z3_get_ast_hash(Z3Context::ZC, AST));
+ }
+
+ bool operator<(const Z3Expr &Other) const {
+ llvm::FoldingSetNodeID ID1, ID2;
+ Profile(ID1);
+ Other.Profile(ID2);
+ return ID1 < ID2;
+ }
+
+ /// Comparison of AST equality, not model equivalence.
+ bool operator==(const Z3Expr &Other) const {
+ assert(Z3_is_eq_sort(Z3Context::ZC, Z3_get_sort(Z3Context::ZC, AST),
+ Z3_get_sort(Z3Context::ZC, Other.AST)) &&
+ "AST's must have the same sort");
+ return Z3_is_eq_ast(Z3Context::ZC, AST, Other.AST);
+ }
+
+ /// Override implicit move constructor for correct reference counting.
+ Z3Expr &operator=(const Z3Expr &Move) {
+ Z3_inc_ref(Z3Context::ZC, Move.AST);
+ Z3_dec_ref(Z3Context::ZC, AST);
+ AST = Move.AST;
+ return *this;
+ }
+
+ void print(raw_ostream &OS) const {
+ OS << Z3_ast_to_string(Z3Context::ZC, AST);
+ }
+
+ LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
+}; // end class Z3Expr
+
+class Z3Model {
+ Z3_model Model;
+
+public:
+ Z3Model(Z3_model ZM) : Model(ZM) { Z3_model_inc_ref(Z3Context::ZC, Model); }
+
+ /// Override implicit copy constructor for correct reference counting.
+ Z3Model(const Z3Model &Copy) : Model(Copy.Model) {
+ Z3_model_inc_ref(Z3Context::ZC, Model);
+ }
+
+ /// Provide move constructor
+ Z3Model(Z3Model &&Move) : Model(nullptr) { *this = std::move(Move); }
+
+ /// Provide move assignment constructor
+ Z3Model &operator=(Z3Model &&Move) {
+ if (this != &Move) {
+ if (Model)
+ Z3_model_dec_ref(Z3Context::ZC, Model);
+ Model = Move.Model;
+ Move.Model = nullptr;
+ }
+ return *this;
+ }
+
+ ~Z3Model() {
+ if (Model)
+ Z3_model_dec_ref(Z3Context::ZC, Model);
+ }
+
+ /// Given an expression, extract the value of this operand in the model.
+ bool getInterpretation(const Z3Expr &Exp, llvm::APSInt &Int) const {
+ Z3_func_decl Func =
+ Z3_get_app_decl(Z3Context::ZC, Z3_to_app(Z3Context::ZC, Exp.AST));
+ if (Z3_model_has_interp(Z3Context::ZC, Model, Func) != Z3_L_TRUE)
+ return false;
+
+ Z3_ast Assign = Z3_model_get_const_interp(Z3Context::ZC, Model, Func);
+ Z3Sort Sort = Z3Sort::getSort(Assign);
+ return Z3Expr::toAPSInt(Sort, Assign, Int, true);
+ }
+
+ /// Given an expression, extract the value of this operand in the model.
+ bool getInterpretation(const Z3Expr &Exp, llvm::APFloat &Float) const {
+ Z3_func_decl Func =
+ Z3_get_app_decl(Z3Context::ZC, Z3_to_app(Z3Context::ZC, Exp.AST));
+ if (Z3_model_has_interp(Z3Context::ZC, Model, Func) != Z3_L_TRUE)
+ return false;
+
+ Z3_ast Assign = Z3_model_get_const_interp(Z3Context::ZC, Model, Func);
+ Z3Sort Sort = Z3Sort::getSort(Assign);
+ return Z3Expr::toAPFloat(Sort, Assign, Float, true);
+ }
+
+ void print(raw_ostream &OS) const {
+ OS << Z3_model_to_string(Z3Context::ZC, Model);
+ }
+
+ LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
+}; // end class Z3Model
+
+class Z3Solver {
+ friend class Z3ConstraintManager;
+
+ Z3_solver Solver;
+
+ Z3Solver(Z3_solver ZS) : Solver(ZS) {
+ Z3_solver_inc_ref(Z3Context::ZC, Solver);
+ }
+
+public:
+ /// Override implicit copy constructor for correct reference counting.
+ Z3Solver(const Z3Solver &Copy) : Solver(Copy.Solver) {
+ Z3_solver_inc_ref(Z3Context::ZC, Solver);
+ }
+
+ /// Provide move constructor
+ Z3Solver(Z3Solver &&Move) : Solver(nullptr) { *this = std::move(Move); }
+
+ /// Provide move assignment constructor
+ Z3Solver &operator=(Z3Solver &&Move) {
+ if (this != &Move) {
+ if (Solver)
+ Z3_solver_dec_ref(Z3Context::ZC, Solver);
+ Solver = Move.Solver;
+ Move.Solver = nullptr;
+ }
+ return *this;
+ }
+
+ ~Z3Solver() {
+ if (Solver)
+ Z3_solver_dec_ref(Z3Context::ZC, Solver);
+ }
+
+ /// Given a constraint, add it to the solver
+ void addConstraint(const Z3Expr &Exp) {
+ Z3_solver_assert(Z3Context::ZC, Solver, Exp.AST);
+ }
+
+ /// Given a program state, construct the logical conjunction and add it to
+ /// the solver
+ void addStateConstraints(ProgramStateRef State) {
+ // TODO: Don't add all the constraints, only the relevant ones
+ ConstraintZ3Ty CZ = State->get<ConstraintZ3>();
+ ConstraintZ3Ty::iterator I = CZ.begin(), IE = CZ.end();
+
+ // Construct the logical AND of all the constraints
+ if (I != IE) {
+ std::vector<Z3_ast> ASTs;
+
+ while (I != IE)
+ ASTs.push_back(I++->second.AST);
+
+ Z3Expr Conj = Z3Expr::fromNBinOp(BO_LAnd, ASTs);
+ addConstraint(Conj);
+ }
+ }
+
+ /// Check if the constraints are satisfiable
+ Z3_lbool check() { return Z3_solver_check(Z3Context::ZC, Solver); }
+
+ /// Push the current solver state
+ void push() { return Z3_solver_push(Z3Context::ZC, Solver); }
+
+ /// Pop the previous solver state
+ void pop(unsigned NumStates = 1) {
+ assert(Z3_solver_get_num_scopes(Z3Context::ZC, Solver) >= NumStates);
+ return Z3_solver_pop(Z3Context::ZC, Solver, NumStates);
+ }
+
+ /// Get a model from the solver. Caller should check the model is
+ /// satisfiable.
+ Z3Model getModel() {
+ return Z3Model(Z3_solver_get_model(Z3Context::ZC, Solver));
+ }
+
+ /// Reset the solver and remove all constraints.
+ void reset() { Z3_solver_reset(Z3Context::ZC, Solver); }
+}; // end class Z3Solver
+
+void Z3ErrorHandler(Z3_context Context, Z3_error_code Error) {
+ llvm::report_fatal_error("Z3 error: " +
+ llvm::Twine(Z3_get_error_msg_ex(Context, Error)));
+}
+
+class Z3ConstraintManager : public SimpleConstraintManager {
+ Z3Context Context;
+ mutable Z3Solver Solver;
+
+public:
+ Z3ConstraintManager(SubEngine *SE, SValBuilder &SB)
+ : SimpleConstraintManager(SE, SB),
+ Solver(Z3_mk_simple_solver(Z3Context::ZC)) {
+ Z3_set_error_handler(Z3Context::ZC, Z3ErrorHandler);
+ }
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from ConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ bool canReasonAbout(SVal X) const override;
+
+ ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override;
+
+ const llvm::APSInt *getSymVal(ProgramStateRef State,
+ SymbolRef Sym) const override;
+
+ ProgramStateRef removeDeadBindings(ProgramStateRef St,
+ SymbolReaper &SymReaper) override;
+
+ void print(ProgramStateRef St, raw_ostream &Out, const char *nl,
+ const char *sep) override;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from SimpleConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ ProgramStateRef assumeSym(ProgramStateRef state, SymbolRef Sym,
+ bool Assumption) override;
+
+ ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) override;
+
+ ProgramStateRef assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override;
+
+private:
+ //===------------------------------------------------------------------===//
+ // Internal implementation.
+ //===------------------------------------------------------------------===//
+
+ // Check whether a new model is satisfiable, and update the program state.
+ ProgramStateRef assumeZ3Expr(ProgramStateRef State, SymbolRef Sym,
+ const Z3Expr &Exp);
+
+ // Generate and check a Z3 model, using the given constraint.
+ Z3_lbool checkZ3Model(ProgramStateRef State, const Z3Expr &Exp) const;
+
+ // Generate a Z3Expr that represents the given symbolic expression.
+ // Sets the hasComparison parameter if the expression has a comparison
+ // operator.
+ // Sets the RetTy parameter to the final return type after promotions and
+ // casts.
+ Z3Expr getZ3Expr(SymbolRef Sym, QualType *RetTy = nullptr,
+ bool *hasComparison = nullptr) const;
+
+ // Generate a Z3Expr that takes the logical not of an expression.
+ Z3Expr getZ3NotExpr(const Z3Expr &Exp) const;
+
+ // Generate a Z3Expr that compares the expression to zero.
+ Z3Expr getZ3ZeroExpr(const Z3Expr &Exp, QualType RetTy,
+ bool Assumption) const;
+
+ // Recursive implementation to unpack and generate symbolic expression.
+ // Sets the hasComparison and RetTy parameters. See getZ3Expr().
+ Z3Expr getZ3SymExpr(SymbolRef Sym, QualType *RetTy,
+ bool *hasComparison) const;
+
+ // Wrapper to generate Z3Expr from SymbolData.
+ Z3Expr getZ3DataExpr(const SymbolID ID, QualType Ty) const;
+
+ // Wrapper to generate Z3Expr from SymbolCast.
+ Z3Expr getZ3CastExpr(const Z3Expr &Exp, QualType FromTy, QualType Ty) const;
+
+ // Wrapper to generate Z3Expr from BinarySymExpr.
+ // Sets the hasComparison and RetTy parameters. See getZ3Expr().
+ Z3Expr getZ3SymBinExpr(const BinarySymExpr *BSE, bool *hasComparison,
+ QualType *RetTy) const;
+
+ // Wrapper to generate Z3Expr from unpacked binary symbolic expression.
+ // Sets the RetTy parameter. See getZ3Expr().
+ Z3Expr getZ3BinExpr(const Z3Expr &LHS, QualType LTy,
+ BinaryOperator::Opcode Op, const Z3Expr &RHS,
+ QualType RTy, QualType *RetTy) const;
+
+ //===------------------------------------------------------------------===//
+ // Helper functions.
+ //===------------------------------------------------------------------===//
+
+ // Recover the QualType of an APSInt.
+ // TODO: Refactor to put elsewhere
+ QualType getAPSIntType(const llvm::APSInt &Int) const;
+
+ // Perform implicit type conversion on binary symbolic expressions.
+ // May modify all input parameters.
+ // TODO: Refactor to use built-in conversion functions
+ void doTypeConversion(Z3Expr &LHS, Z3Expr &RHS, QualType &LTy,
+ QualType &RTy) const;
+
+ // Perform implicit integer type conversion.
+ // May modify all input parameters.
+ // TODO: Refactor to use Sema::handleIntegerConversion()
+ template <typename T,
+ T(doCast)(const T &, QualType, uint64_t, QualType, uint64_t)>
+ void doIntTypeConversion(T &LHS, QualType &LTy, T &RHS, QualType &RTy) const;
+
+ // Perform implicit floating-point type conversion.
+ // May modify all input parameters.
+ // TODO: Refactor to use Sema::handleFloatConversion()
+ template <typename T,
+ T(doCast)(const T &, QualType, uint64_t, QualType, uint64_t)>
+ void doFloatTypeConversion(T &LHS, QualType &LTy, T &RHS,
+ QualType &RTy) const;
+
+ // Callback function for doCast parameter on APSInt type.
+ static llvm::APSInt castAPSInt(const llvm::APSInt &V, QualType ToTy,
+ uint64_t ToWidth, QualType FromTy,
+ uint64_t FromWidth);
+}; // end class Z3ConstraintManager
+
+Z3_context Z3Context::ZC;
+
+} // end anonymous namespace
+
+ProgramStateRef Z3ConstraintManager::assumeSym(ProgramStateRef State,
+ SymbolRef Sym, bool Assumption) {
+ QualType RetTy;
+ bool hasComparison;
+
+ Z3Expr Exp = getZ3Expr(Sym, &RetTy, &hasComparison);
+ // Create zero comparison for implicit boolean cast, with reversed assumption
+ if (!hasComparison && !RetTy->isBooleanType())
+ return assumeZ3Expr(State, Sym, getZ3ZeroExpr(Exp, RetTy, !Assumption));
+
+ return assumeZ3Expr(State, Sym, Assumption ? Exp : getZ3NotExpr(Exp));
+}
+
+ProgramStateRef Z3ConstraintManager::assumeSymInclusiveRange(
+ ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
+ const llvm::APSInt &To, bool InRange) {
+ QualType RetTy;
+ // The expression may be casted, so we cannot call getZ3DataExpr() directly
+ Z3Expr Exp = getZ3Expr(Sym, &RetTy);
+
+ assert((getAPSIntType(From) == getAPSIntType(To)) &&
+ "Range values have different types!");
+ QualType RTy = getAPSIntType(From);
+ bool isSignedTy = RetTy->isSignedIntegerOrEnumerationType();
+ Z3Expr FromExp = Z3Expr::fromAPSInt(From);
+ Z3Expr ToExp = Z3Expr::fromAPSInt(To);
+
+ // Construct single (in)equality
+ if (From == To)
+ return assumeZ3Expr(State, Sym,
+ getZ3BinExpr(Exp, RetTy, InRange ? BO_EQ : BO_NE,
+ FromExp, RTy, nullptr));
+
+ // Construct two (in)equalities, and a logical and/or
+ Z3Expr LHS =
+ getZ3BinExpr(Exp, RetTy, InRange ? BO_GE : BO_LT, FromExp, RTy, nullptr);
+ Z3Expr RHS =
+ getZ3BinExpr(Exp, RetTy, InRange ? BO_LE : BO_GT, ToExp, RTy, nullptr);
+ return assumeZ3Expr(
+ State, Sym,
+ Z3Expr::fromBinOp(LHS, InRange ? BO_LAnd : BO_LOr, RHS, isSignedTy));
+}
+
+ProgramStateRef Z3ConstraintManager::assumeSymUnsupported(ProgramStateRef State,
+ SymbolRef Sym,
+ bool Assumption) {
+ // Skip anything that is unsupported
+ return State;
+}
+
+bool Z3ConstraintManager::canReasonAbout(SVal X) const {
+ const TargetInfo &TI = getBasicVals().getContext().getTargetInfo();
+
+ Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
+ if (!SymVal)
+ return true;
+
+ const SymExpr *Sym = SymVal->getSymbol();
+ do {
+ QualType Ty = Sym->getType();
+
+ // Complex types are not modeled
+ if (Ty->isComplexType() || Ty->isComplexIntegerType())
+ return false;
+
+ // Non-IEEE 754 floating-point types are not modeled
+ if ((Ty->isSpecificBuiltinType(BuiltinType::LongDouble) &&
+ (&TI.getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended() ||
+ &TI.getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble())))
+ return false;
+
+ if (isa<SymbolData>(Sym)) {
+ break;
+ } else if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
+ Sym = SC->getOperand();
+ } else if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
+ Sym = SIE->getLHS();
+ } else if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
+ Sym = ISE->getRHS();
+ } else if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
+ return canReasonAbout(nonloc::SymbolVal(SSM->getLHS())) &&
+ canReasonAbout(nonloc::SymbolVal(SSM->getRHS()));
+ } else {
+ llvm_unreachable("Unsupported binary expression to reason about!");
+ }
+ } else {
+ llvm_unreachable("Unsupported expression to reason about!");
+ }
+ } while (Sym);
+
+ return true;
+}
+
+ConditionTruthVal Z3ConstraintManager::checkNull(ProgramStateRef State,
+ SymbolRef Sym) {
+ QualType RetTy;
+ // The expression may be casted, so we cannot call getZ3DataExpr() directly
+ Z3Expr VarExp = getZ3Expr(Sym, &RetTy);
+ Z3Expr Exp = getZ3ZeroExpr(VarExp, RetTy, true);
+ // Negate the constraint
+ Z3Expr NotExp = getZ3ZeroExpr(VarExp, RetTy, false);
+
+ Solver.reset();
+ Solver.addStateConstraints(State);
+
+ Solver.push();
+ Solver.addConstraint(Exp);
+ Z3_lbool isSat = Solver.check();
+
+ Solver.pop();
+ Solver.addConstraint(NotExp);
+ Z3_lbool isNotSat = Solver.check();
+
+ // Zero is the only possible solution
+ if (isSat == Z3_L_TRUE && isNotSat == Z3_L_FALSE)
+ return true;
+ // Zero is not a solution
+ else if (isSat == Z3_L_FALSE && isNotSat == Z3_L_TRUE)
+ return false;
+
+ // Zero may be a solution
+ return ConditionTruthVal();
+}
+
+const llvm::APSInt *Z3ConstraintManager::getSymVal(ProgramStateRef State,
+ SymbolRef Sym) const {
+ BasicValueFactory &BV = getBasicVals();
+ ASTContext &Ctx = BV.getContext();
+
+ if (const SymbolData *SD = dyn_cast<SymbolData>(Sym)) {
+ QualType Ty = Sym->getType();
+ assert(!Ty->isRealFloatingType());
+ llvm::APSInt Value(Ctx.getTypeSize(Ty),
+ !Ty->isSignedIntegerOrEnumerationType());
+
+ Z3Expr Exp = getZ3DataExpr(SD->getSymbolID(), Ty);
+
+ Solver.reset();
+ Solver.addStateConstraints(State);
+
+ // Constraints are unsatisfiable
+ if (Solver.check() != Z3_L_TRUE)
+ return nullptr;
+
+ Z3Model Model = Solver.getModel();
+ // Model does not assign interpretation
+ if (!Model.getInterpretation(Exp, Value))
+ return nullptr;
+
+ // A value has been obtained, check if it is the only value
+ Z3Expr NotExp = Z3Expr::fromBinOp(
+ Exp, BO_NE,
+ Ty->isBooleanType() ? Z3Expr::fromBoolean(Value.getBoolValue())
+ : Z3Expr::fromAPSInt(Value),
+ false);
+
+ Solver.addConstraint(NotExp);
+ if (Solver.check() == Z3_L_TRUE)
+ return nullptr;
+
+ // This is the only solution, store it
+ return &BV.getValue(Value);
+ } else if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
+ SymbolRef CastSym = SC->getOperand();
+ QualType CastTy = SC->getType();
+ // Skip the void type
+ if (CastTy->isVoidType())
+ return nullptr;
+
+ const llvm::APSInt *Value;
+ if (!(Value = getSymVal(State, CastSym)))
+ return nullptr;
+ return &BV.Convert(SC->getType(), *Value);
+ } else if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
+ const llvm::APSInt *LHS, *RHS;
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
+ LHS = getSymVal(State, SIE->getLHS());
+ RHS = &SIE->getRHS();
+ } else if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
+ LHS = &ISE->getLHS();
+ RHS = getSymVal(State, ISE->getRHS());
+ } else if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
+ // Early termination to avoid expensive call
+ LHS = getSymVal(State, SSM->getLHS());
+ RHS = LHS ? getSymVal(State, SSM->getRHS()) : nullptr;
+ } else {
+ llvm_unreachable("Unsupported binary expression to get symbol value!");
+ }
+
+ if (!LHS || !RHS)
+ return nullptr;
+
+ llvm::APSInt ConvertedLHS = *LHS, ConvertedRHS = *RHS;
+ QualType LTy = getAPSIntType(*LHS), RTy = getAPSIntType(*RHS);
+ doIntTypeConversion<llvm::APSInt, Z3ConstraintManager::castAPSInt>(
+ ConvertedLHS, LTy, ConvertedRHS, RTy);
+ return BV.evalAPSInt(BSE->getOpcode(), ConvertedLHS, ConvertedRHS);
+ }
+
+ llvm_unreachable("Unsupported expression to get symbol value!");
+}
+
+ProgramStateRef
+Z3ConstraintManager::removeDeadBindings(ProgramStateRef State,
+ SymbolReaper &SymReaper) {
+ ConstraintZ3Ty CZ = State->get<ConstraintZ3>();
+ ConstraintZ3Ty::Factory &CZFactory = State->get_context<ConstraintZ3>();
+
+ for (ConstraintZ3Ty::iterator I = CZ.begin(), E = CZ.end(); I != E; ++I) {
+ if (SymReaper.maybeDead(I->first))
+ CZ = CZFactory.remove(CZ, *I);
+ }
+
+ return State->set<ConstraintZ3>(CZ);
+}
+
+//===------------------------------------------------------------------===//
+// Internal implementation.
+//===------------------------------------------------------------------===//
+
+ProgramStateRef Z3ConstraintManager::assumeZ3Expr(ProgramStateRef State,
+ SymbolRef Sym,
+ const Z3Expr &Exp) {
+ // Check the model, avoid simplifying AST to save time
+ if (checkZ3Model(State, Exp) == Z3_L_TRUE)
+ return State->add<ConstraintZ3>(std::make_pair(Sym, Exp));
+
+ return nullptr;
+}
+
+Z3_lbool Z3ConstraintManager::checkZ3Model(ProgramStateRef State,
+ const Z3Expr &Exp) const {
+ Solver.reset();
+ Solver.addConstraint(Exp);
+ Solver.addStateConstraints(State);
+ return Solver.check();
+}
+
+Z3Expr Z3ConstraintManager::getZ3Expr(SymbolRef Sym, QualType *RetTy,
+ bool *hasComparison) const {
+ if (hasComparison) {
+ *hasComparison = false;
+ }
+
+ return getZ3SymExpr(Sym, RetTy, hasComparison);
+}
+
+Z3Expr Z3ConstraintManager::getZ3NotExpr(const Z3Expr &Exp) const {
+ return Z3Expr::fromUnOp(UO_LNot, Exp);
+}
+
+Z3Expr Z3ConstraintManager::getZ3ZeroExpr(const Z3Expr &Exp, QualType Ty,
+ bool Assumption) const {
+ ASTContext &Ctx = getBasicVals().getContext();
+ if (Ty->isRealFloatingType()) {
+ llvm::APFloat Zero = llvm::APFloat::getZero(Ctx.getFloatTypeSemantics(Ty));
+ return Z3Expr::fromFloatBinOp(Exp, Assumption ? BO_EQ : BO_NE,
+ Z3Expr::fromAPFloat(Zero));
+ } else if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() ||
+ Ty->isBlockPointerType() || Ty->isReferenceType()) {
+ bool isSigned = Ty->isSignedIntegerOrEnumerationType();
+ // Skip explicit comparison for boolean types
+ if (Ty->isBooleanType())
+ return Assumption ? getZ3NotExpr(Exp) : Exp;
+ return Z3Expr::fromBinOp(Exp, Assumption ? BO_EQ : BO_NE,
+ Z3Expr::fromInt("0", Ctx.getTypeSize(Ty)),
+ isSigned);
+ }
+
+ llvm_unreachable("Unsupported type for zero value!");
+}
+
+Z3Expr Z3ConstraintManager::getZ3SymExpr(SymbolRef Sym, QualType *RetTy,
+ bool *hasComparison) const {
+ if (const SymbolData *SD = dyn_cast<SymbolData>(Sym)) {
+ if (RetTy)
+ *RetTy = Sym->getType();
+
+ return getZ3DataExpr(SD->getSymbolID(), Sym->getType());
+ } else if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
+ if (RetTy)
+ *RetTy = Sym->getType();
+
+ QualType FromTy;
+ Z3Expr Exp = getZ3SymExpr(SC->getOperand(), &FromTy, hasComparison);
+ // Casting an expression with a comparison invalidates it. Note that this
+ // must occur after the recursive call above.
+ // e.g. (signed char) (x > 0)
+ if (hasComparison)
+ *hasComparison = false;
+ return getZ3CastExpr(Exp, FromTy, Sym->getType());
+ } else if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
+ Z3Expr Exp = getZ3SymBinExpr(BSE, hasComparison, RetTy);
+ // Set the hasComparison parameter, in post-order traversal order.
+ if (hasComparison)
+ *hasComparison = BinaryOperator::isComparisonOp(BSE->getOpcode());
+ return Exp;
+ }
+
+ llvm_unreachable("Unsupported SymbolRef type!");
+}
+
+Z3Expr Z3ConstraintManager::getZ3DataExpr(const SymbolID ID,
+ QualType Ty) const {
+ ASTContext &Ctx = getBasicVals().getContext();
+ return Z3Expr::fromData(ID, Ty->isBooleanType(), Ty->isRealFloatingType(),
+ Ctx.getTypeSize(Ty));
+}
+
+Z3Expr Z3ConstraintManager::getZ3CastExpr(const Z3Expr &Exp, QualType FromTy,
+ QualType ToTy) const {
+ ASTContext &Ctx = getBasicVals().getContext();
+ return Z3Expr::fromCast(Exp, ToTy, Ctx.getTypeSize(ToTy), FromTy,
+ Ctx.getTypeSize(FromTy));
+}
+
+Z3Expr Z3ConstraintManager::getZ3SymBinExpr(const BinarySymExpr *BSE,
+ bool *hasComparison,
+ QualType *RetTy) const {
+ QualType LTy, RTy;
+ BinaryOperator::Opcode Op = BSE->getOpcode();
+
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
+ RTy = getAPSIntType(SIE->getRHS());
+ Z3Expr LHS = getZ3SymExpr(SIE->getLHS(), &LTy, hasComparison);
+ Z3Expr RHS = Z3Expr::fromAPSInt(SIE->getRHS());
+ return getZ3BinExpr(LHS, LTy, Op, RHS, RTy, RetTy);
+ } else if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
+ LTy = getAPSIntType(ISE->getLHS());
+ Z3Expr LHS = Z3Expr::fromAPSInt(ISE->getLHS());
+ Z3Expr RHS = getZ3SymExpr(ISE->getRHS(), &RTy, hasComparison);
+ return getZ3BinExpr(LHS, LTy, Op, RHS, RTy, RetTy);
+ } else if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
+ Z3Expr LHS = getZ3SymExpr(SSM->getLHS(), &LTy, hasComparison);
+ Z3Expr RHS = getZ3SymExpr(SSM->getRHS(), &RTy, hasComparison);
+ return getZ3BinExpr(LHS, LTy, Op, RHS, RTy, RetTy);
+ } else {
+ llvm_unreachable("Unsupported BinarySymExpr type!");
+ }
+}
+
+Z3Expr Z3ConstraintManager::getZ3BinExpr(const Z3Expr &LHS, QualType LTy,
+ BinaryOperator::Opcode Op,
+ const Z3Expr &RHS, QualType RTy,
+ QualType *RetTy) const {
+ Z3Expr NewLHS = LHS;
+ Z3Expr NewRHS = RHS;
+ doTypeConversion(NewLHS, NewRHS, LTy, RTy);
+ // Update the return type parameter if the output type has changed.
+ if (RetTy) {
+ // A boolean result can be represented as an integer type in C/C++, but at
+ // this point we only care about the Z3 type. Set it as a boolean type to
+ // avoid subsequent Z3 errors.
+ if (BinaryOperator::isComparisonOp(Op) || BinaryOperator::isLogicalOp(Op)) {
+ ASTContext &Ctx = getBasicVals().getContext();
+ *RetTy = Ctx.BoolTy;
+ } else {
+ *RetTy = LTy;
+ }
+
+ // If the two operands are pointers and the operation is a subtraction, the
+ // result is of type ptrdiff_t, which is signed
+ if (LTy->isAnyPointerType() && LTy == RTy && Op == BO_Sub) {
+ ASTContext &Ctx = getBasicVals().getContext();
+ *RetTy = Ctx.getIntTypeForBitwidth(Ctx.getTypeSize(LTy), true);
+ }
+ }
+
+ return LTy->isRealFloatingType()
+ ? Z3Expr::fromFloatBinOp(NewLHS, Op, NewRHS)
+ : Z3Expr::fromBinOp(NewLHS, Op, NewRHS,
+ LTy->isSignedIntegerOrEnumerationType());
+}
+
+//===------------------------------------------------------------------===//
+// Helper functions.
+//===------------------------------------------------------------------===//
+
+QualType Z3ConstraintManager::getAPSIntType(const llvm::APSInt &Int) const {
+ ASTContext &Ctx = getBasicVals().getContext();
+ return Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned());
+}
+
+void Z3ConstraintManager::doTypeConversion(Z3Expr &LHS, Z3Expr &RHS,
+ QualType &LTy, QualType &RTy) const {
+ ASTContext &Ctx = getBasicVals().getContext();
+
+ // Perform type conversion
+ if (LTy->isIntegralOrEnumerationType() &&
+ RTy->isIntegralOrEnumerationType()) {
+ if (LTy->isArithmeticType() && RTy->isArithmeticType())
+ return doIntTypeConversion<Z3Expr, Z3Expr::fromCast>(LHS, LTy, RHS, RTy);
+ } else if (LTy->isRealFloatingType() || RTy->isRealFloatingType()) {
+ return doFloatTypeConversion<Z3Expr, Z3Expr::fromCast>(LHS, LTy, RHS, RTy);
+ } else if ((LTy->isAnyPointerType() || RTy->isAnyPointerType()) ||
+ (LTy->isBlockPointerType() || RTy->isBlockPointerType()) ||
+ (LTy->isReferenceType() || RTy->isReferenceType())) {
+ // TODO: Refactor to Sema::FindCompositePointerType(), and
+ // Sema::CheckCompareOperands().
+
+ uint64_t LBitWidth = Ctx.getTypeSize(LTy);
+ uint64_t RBitWidth = Ctx.getTypeSize(RTy);
+
+ // Cast the non-pointer type to the pointer type.
+ // TODO: Be more strict about this.
+ if ((LTy->isAnyPointerType() ^ RTy->isAnyPointerType()) ||
+ (LTy->isBlockPointerType() ^ RTy->isBlockPointerType()) ||
+ (LTy->isReferenceType() ^ RTy->isReferenceType())) {
+ if (LTy->isNullPtrType() || LTy->isBlockPointerType() ||
+ LTy->isReferenceType()) {
+ LHS = Z3Expr::fromCast(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ } else {
+ RHS = Z3Expr::fromCast(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ }
+ }
+
+ // Cast the void pointer type to the non-void pointer type.
+ // For void types, this assumes that the casted value is equal to the value
+ // of the original pointer, and does not account for alignment requirements.
+ if (LTy->isVoidPointerType() ^ RTy->isVoidPointerType()) {
+ assert((Ctx.getTypeSize(LTy) == Ctx.getTypeSize(RTy)) &&
+ "Pointer types have different bitwidths!");
+ if (RTy->isVoidPointerType())
+ RTy = LTy;
+ else
+ LTy = RTy;
+ }
+
+ if (LTy == RTy)
+ return;
+ }
+
+ // Fallback: for the solver, assume that these types don't really matter
+ if ((LTy.getCanonicalType() == RTy.getCanonicalType()) ||
+ (LTy->isObjCObjectPointerType() && RTy->isObjCObjectPointerType())) {
+ LTy = RTy;
+ return;
+ }
+
+ // TODO: Refine behavior for invalid type casts
+}
+
+template <typename T,
+ T(doCast)(const T &, QualType, uint64_t, QualType, uint64_t)>
+void Z3ConstraintManager::doIntTypeConversion(T &LHS, QualType &LTy, T &RHS,
+ QualType &RTy) const {
+ ASTContext &Ctx = getBasicVals().getContext();
+
+ uint64_t LBitWidth = Ctx.getTypeSize(LTy);
+ uint64_t RBitWidth = Ctx.getTypeSize(RTy);
+
+ // Always perform integer promotion before checking type equality.
+ // Otherwise, e.g. (bool) a + (bool) b could trigger a backend assertion
+ if (LTy->isPromotableIntegerType()) {
+ QualType NewTy = Ctx.getPromotedIntegerType(LTy);
+ uint64_t NewBitWidth = Ctx.getTypeSize(NewTy);
+ LHS = (*doCast)(LHS, NewTy, NewBitWidth, LTy, LBitWidth);
+ LTy = NewTy;
+ LBitWidth = NewBitWidth;
+ }
+ if (RTy->isPromotableIntegerType()) {
+ QualType NewTy = Ctx.getPromotedIntegerType(RTy);
+ uint64_t NewBitWidth = Ctx.getTypeSize(NewTy);
+ RHS = (*doCast)(RHS, NewTy, NewBitWidth, RTy, RBitWidth);
+ RTy = NewTy;
+ RBitWidth = NewBitWidth;
+ }
+
+ if (LTy == RTy)
+ return;
+
+ // Perform integer type conversion
+ // Note: Safe to skip updating bitwidth because this must terminate
+ bool isLSignedTy = LTy->isSignedIntegerOrEnumerationType();
+ bool isRSignedTy = RTy->isSignedIntegerOrEnumerationType();
+
+ int order = Ctx.getIntegerTypeOrder(LTy, RTy);
+ if (isLSignedTy == isRSignedTy) {
+ // Same signedness; use the higher-ranked type
+ if (order == 1) {
+ RHS = (*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else {
+ LHS = (*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ }
+ } else if (order != (isLSignedTy ? 1 : -1)) {
+ // The unsigned type has greater than or equal rank to the
+ // signed type, so use the unsigned type
+ if (isRSignedTy) {
+ RHS = (*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else {
+ LHS = (*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ }
+ } else if (LBitWidth != RBitWidth) {
+ // The two types are different widths; if we are here, that
+ // means the signed type is larger than the unsigned type, so
+ // use the signed type.
+ if (isLSignedTy) {
+ RHS = (*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else {
+ LHS = (*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ }
+ } else {
+ // The signed type is higher-ranked than the unsigned type,
+ // but isn't actually any bigger (like unsigned int and long
+ // on most 32-bit systems). Use the unsigned type corresponding
+ // to the signed type.
+ QualType NewTy = Ctx.getCorrespondingUnsignedType(isLSignedTy ? LTy : RTy);
+ RHS = (*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = NewTy;
+ LHS = (*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = NewTy;
+ }
+}
+
+template <typename T,
+ T(doCast)(const T &, QualType, uint64_t, QualType, uint64_t)>
+void Z3ConstraintManager::doFloatTypeConversion(T &LHS, QualType &LTy, T &RHS,
+ QualType &RTy) const {
+ ASTContext &Ctx = getBasicVals().getContext();
+
+ uint64_t LBitWidth = Ctx.getTypeSize(LTy);
+ uint64_t RBitWidth = Ctx.getTypeSize(RTy);
+
+ // Perform float-point type promotion
+ if (!LTy->isRealFloatingType()) {
+ LHS = (*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ LBitWidth = RBitWidth;
+ }
+ if (!RTy->isRealFloatingType()) {
+ RHS = (*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ RBitWidth = LBitWidth;
+ }
+
+ if (LTy == RTy)
+ return;
+
+ // If we have two real floating types, convert the smaller operand to the
+ // bigger result
+ // Note: Safe to skip updating bitwidth because this must terminate
+ int order = Ctx.getFloatingTypeOrder(LTy, RTy);
+ if (order > 0) {
+ RHS = Z3Expr::fromCast(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else if (order == 0) {
+ LHS = Z3Expr::fromCast(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ } else {
+ llvm_unreachable("Unsupported floating-point type cast!");
+ }
+}
+
+llvm::APSInt Z3ConstraintManager::castAPSInt(const llvm::APSInt &V,
+ QualType ToTy, uint64_t ToWidth,
+ QualType FromTy,
+ uint64_t FromWidth) {
+ APSIntType TargetType(ToWidth, !ToTy->isSignedIntegerOrEnumerationType());
+ return TargetType.convert(V);
+}
+
+//==------------------------------------------------------------------------==/
+// Pretty-printing.
+//==------------------------------------------------------------------------==/
+
+void Z3ConstraintManager::print(ProgramStateRef St, raw_ostream &OS,
+ const char *nl, const char *sep) {
+
+ ConstraintZ3Ty CZ = St->get<ConstraintZ3>();
+
+ OS << nl << sep << "Constraints:";
+ for (ConstraintZ3Ty::iterator I = CZ.begin(), E = CZ.end(); I != E; ++I) {
+ OS << nl << ' ' << I->first << " : ";
+ I->second.print(OS);
+ }
+ OS << nl;
+}
+
+#endif
+
+std::unique_ptr<ConstraintManager>
+ento::CreateZ3ConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
+#if CLANG_ANALYZER_WITH_Z3
+ return llvm::make_unique<Z3ConstraintManager>(Eng, StMgr.getSValBuilder());
+#else
+ llvm::report_fatal_error("Clang was not compiled with Z3 support!", false);
+ return nullptr;
+#endif
+}
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index b3e287e..c47edc7 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -615,8 +615,8 @@ std::string AnalysisConsumer::getFunctionName(const Decl *D) {
<< OC->getIdentifier()->getNameStart() << ')';
}
} else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) {
- OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '('
- << OCD->getIdentifier()->getNameStart() << ')';
+ OS << OCD->getClassInterface()->getName() << '('
+ << OCD->getName() << ')';
} else if (isa<ObjCProtocolDecl>(DC)) {
// We can extract the type of the class from the self pointer.
if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) {
@@ -674,10 +674,8 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
DisplayFunction(D, Mode, IMode);
CFG *DeclCFG = Mgr->getCFG(D);
- if (DeclCFG) {
- unsigned CFGSize = DeclCFG->size();
- MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize;
- }
+ if (DeclCFG)
+ MaxCFGSize.updateMax(DeclCFG->size());
BugReporter BR(*Mgr);
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
index c6f3baa..cdb1ed9 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
@@ -65,7 +65,7 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) {
auto Invocation = std::make_shared<CompilerInvocation>(CI.getInvocation());
FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
- InputKind IK = IK_CXX; // FIXME
+ InputKind IK = InputKind::CXX; // FIXME
FrontendOpts.Inputs.clear();
FrontendOpts.Inputs.emplace_back(fileName, IK);
FrontendOpts.DisableFree = true;
diff --git a/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp b/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp
index 48b925c..ac9fd3c 100644
--- a/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp
+++ b/contrib/llvm/tools/clang/lib/Tooling/ArgumentsAdjusters.cpp
@@ -42,7 +42,7 @@ ArgumentsAdjuster getClangStripOutputAdjuster() {
AdjustedArgs.push_back(Args[i]);
if (Arg == "-o") {
- // Output is specified as -o foo. Skip the next argument also.
+ // Output is specified as -o foo. Skip the next argument too.
++i;
}
// Else, the output is specified as -ofoo. Just do nothing.
@@ -51,6 +51,26 @@ ArgumentsAdjuster getClangStripOutputAdjuster() {
};
}
+ArgumentsAdjuster getClangStripDependencyFileAdjuster() {
+ return [](const CommandLineArguments &Args, StringRef /*unused*/) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ StringRef Arg = Args[i];
+ // All dependency-file options begin with -M. These include -MM,
+ // -MF, -MG, -MP, -MT, -MQ, -MD, and -MMD.
+ if (!Arg.startswith("-M"))
+ AdjustedArgs.push_back(Args[i]);
+
+ if ((Arg == "-MF") || (Arg == "-MT") || (Arg == "-MQ") ||
+ (Arg == "-MD") || (Arg == "-MMD")) {
+ // Output is specified as -MX foo. Skip the next argument also.
+ ++i;
+ }
+ }
+ return AdjustedArgs;
+ };
+}
+
ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra,
ArgumentInsertPosition Pos) {
return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) {
@@ -83,4 +103,3 @@ ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
} // end namespace tooling
} // end namespace clang
-
diff --git a/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp b/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp
index 5a44061..9e9689e 100644
--- a/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp
+++ b/contrib/llvm/tools/clang/lib/Tooling/CommonOptionsParser.cpp
@@ -116,7 +116,11 @@ CommonOptionsParser::CommonOptionsParser(
cl::HideUnrelatedOptions(Category);
- Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv));
+ std::string ErrorMessage;
+ Compilations =
+ FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage);
+ if (!Compilations && !ErrorMessage.empty())
+ llvm::errs() << ErrorMessage;
cl::ParseCommandLineOptions(argc, argv, Overview);
cl::PrintOptionValues();
@@ -125,7 +129,6 @@ CommonOptionsParser::CommonOptionsParser(
SourcePathList.empty())
return;
if (!Compilations) {
- std::string ErrorMessage;
if (!BuildPath.empty()) {
Compilations =
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
diff --git a/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp b/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp
index 8ca0b2d..0e83557 100644
--- a/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp
+++ b/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp
@@ -27,6 +27,7 @@
#include "llvm/Option/Arg.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include <sstream>
#include <system_error>
using namespace clang;
@@ -150,23 +151,21 @@ private:
// options.
class UnusedInputDiagConsumer : public DiagnosticConsumer {
public:
- UnusedInputDiagConsumer() : Other(nullptr) {}
-
- // Useful for debugging, chain diagnostics to another consumer after
- // recording for our own purposes.
- UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {}
+ UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {}
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) override {
if (Info.getID() == clang::diag::warn_drv_input_file_unused) {
// Arg 1 for this diagnostic is the option that didn't get used.
UnusedInputs.push_back(Info.getArgStdStr(0));
+ } else if (DiagLevel >= DiagnosticsEngine::Error) {
+ // If driver failed to create compilation object, show the diagnostics
+ // to user.
+ Other.HandleDiagnostic(DiagLevel, Info);
}
- if (Other)
- Other->HandleDiagnostic(DiagLevel, Info);
}
- DiagnosticConsumer *Other;
+ DiagnosticConsumer &Other;
SmallVector<std::string, 2> UnusedInputs;
};
@@ -205,9 +204,12 @@ private:
/// \li false if \c Args cannot be used for compilation jobs (e.g.
/// contains an option like -E or -version).
static bool stripPositionalArgs(std::vector<const char *> Args,
- std::vector<std::string> &Result) {
+ std::vector<std::string> &Result,
+ std::string &ErrorMsg) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
- UnusedInputDiagConsumer DiagClient;
+ llvm::raw_string_ostream Output(ErrorMsg);
+ TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
+ UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
DiagnosticsEngine Diagnostics(
IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
&*DiagOpts, &DiagClient, false);
@@ -245,21 +247,24 @@ static bool stripPositionalArgs(std::vector<const char *> Args,
const std::unique_ptr<driver::Compilation> Compilation(
NewDriver->BuildCompilation(Args));
+ if (!Compilation)
+ return false;
const driver::JobList &Jobs = Compilation->getJobs();
CompileJobAnalyzer CompileAnalyzer;
for (const auto &Cmd : Jobs) {
- // Collect only for Assemble jobs. If we do all jobs we get duplicates
- // since Link jobs point to Assemble jobs as inputs.
- if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass)
+ // Collect only for Assemble and Compile jobs. If we do all jobs we get
+ // duplicates since Link jobs point to Assemble jobs as inputs.
+ if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass ||
+ Cmd.getSource().getKind() == driver::Action::CompileJobClass) {
CompileAnalyzer.run(&Cmd.getSource());
+ }
}
if (CompileAnalyzer.Inputs.empty()) {
- // No compile jobs found.
- // FIXME: Emit a warning of some kind?
+ ErrorMsg = "warning: no compile jobs found\n";
return false;
}
@@ -280,8 +285,14 @@ static bool stripPositionalArgs(std::vector<const char *> Args,
return true;
}
-FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine(
- int &Argc, const char *const *Argv, Twine Directory) {
+std::unique_ptr<FixedCompilationDatabase>
+FixedCompilationDatabase::loadFromCommandLine(int &Argc,
+ const char *const *Argv,
+ std::string &ErrorMsg,
+ Twine Directory) {
+ ErrorMsg.clear();
+ if (Argc == 0)
+ return nullptr;
const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
if (DoubleDash == Argv + Argc)
return nullptr;
@@ -289,9 +300,10 @@ FixedCompilationDatabase *FixedCompilationDatabase::loadFromCommandLine(
Argc = DoubleDash - Argv;
std::vector<std::string> StrippedArgs;
- if (!stripPositionalArgs(CommandLine, StrippedArgs))
+ if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
return nullptr;
- return new FixedCompilationDatabase(Directory, StrippedArgs);
+ return std::unique_ptr<FixedCompilationDatabase>(
+ new FixedCompilationDatabase(Directory, StrippedArgs));
}
FixedCompilationDatabase::
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp
index 3bbc2b9..9e4833f 100644
--- a/contrib/llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp
+++ b/contrib/llvm/tools/clang/lib/Tooling/Core/Diagnostic.cpp
@@ -35,9 +35,9 @@ Diagnostic::Diagnostic(llvm::StringRef DiagnosticName,
BuildDirectory(BuildDirectory) {}
Diagnostic::Diagnostic(llvm::StringRef DiagnosticName,
- DiagnosticMessage &Message,
- llvm::StringMap<Replacements> &Fix,
- SmallVector<DiagnosticMessage, 1> &Notes,
+ const DiagnosticMessage &Message,
+ const llvm::StringMap<Replacements> &Fix,
+ const SmallVector<DiagnosticMessage, 1> &Notes,
Level DiagLevel, llvm::StringRef BuildDirectory)
: DiagnosticName(DiagnosticName), Message(Message), Fix(Fix), Notes(Notes),
DiagLevel(DiagLevel), BuildDirectory(BuildDirectory) {}
diff --git a/contrib/llvm/tools/clang/lib/Tooling/JSONCompilationDatabase.cpp b/contrib/llvm/tools/clang/lib/Tooling/JSONCompilationDatabase.cpp
index 738e610..f9a230e 100644
--- a/contrib/llvm/tools/clang/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/contrib/llvm/tools/clang/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);
}
};
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring.cpp
index 308c1ac..db34c95 100644
--- a/contrib/llvm/tools/clang/lib/Tooling/Refactoring.cpp
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring.cpp
@@ -28,7 +28,7 @@ namespace tooling {
RefactoringTool::RefactoringTool(
const CompilationDatabase &Compilations, ArrayRef<std::string> SourcePaths,
std::shared_ptr<PCHContainerOperations> PCHContainerOps)
- : ClangTool(Compilations, SourcePaths, PCHContainerOps) {}
+ : ClangTool(Compilations, SourcePaths, std::move(PCHContainerOps)) {}
std::map<std::string, Replacements> &RefactoringTool::getReplacements() {
return FileToReplaces;
@@ -68,8 +68,8 @@ int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
}
bool formatAndApplyAllReplacements(
- const std::map<std::string, Replacements> &FileToReplaces, Rewriter &Rewrite,
- StringRef Style) {
+ const std::map<std::string, Replacements> &FileToReplaces,
+ Rewriter &Rewrite, StringRef Style) {
SourceManager &SM = Rewrite.getSourceMgr();
FileManager &Files = SM.getFileManager();
@@ -83,9 +83,14 @@ bool formatAndApplyAllReplacements(
FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User);
StringRef Code = SM.getBufferData(ID);
- format::FormatStyle CurStyle = format::getStyle(Style, FilePath, "LLVM");
+ auto CurStyle = format::getStyle(Style, FilePath, "LLVM");
+ if (!CurStyle) {
+ llvm::errs() << llvm::toString(CurStyle.takeError()) << "\n";
+ return false;
+ }
+
auto NewReplacements =
- format::formatReplacements(Code, CurReplaces, CurStyle);
+ format::formatReplacements(Code, CurReplaces, *CurStyle);
if (!NewReplacements) {
llvm::errs() << llvm::toString(NewReplacements.takeError()) << "\n";
return false;
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp
new file mode 100644
index 0000000..79dd346
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/AtomicChange.cpp
@@ -0,0 +1,177 @@
+//===--- AtomicChange.cpp - AtomicChange implementation -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/ReplacementsYaml.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <string>
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange)
+
+namespace {
+/// \brief Helper to (de)serialize an AtomicChange since we don't have direct
+/// access to its data members.
+/// Data members of a normalized AtomicChange can be directly mapped from/to
+/// YAML string.
+struct NormalizedAtomicChange {
+ NormalizedAtomicChange() = default;
+
+ NormalizedAtomicChange(const llvm::yaml::IO &) {}
+
+ // This converts AtomicChange's internal implementation of the replacements
+ // set to a vector of replacements.
+ NormalizedAtomicChange(const llvm::yaml::IO &,
+ const clang::tooling::AtomicChange &E)
+ : Key(E.getKey()), FilePath(E.getFilePath()), Error(E.getError()),
+ InsertedHeaders(E.getInsertedHeaders()),
+ RemovedHeaders(E.getRemovedHeaders()),
+ Replaces(E.getReplacements().begin(), E.getReplacements().end()) {}
+
+ // This is not expected to be called but needed for template instantiation.
+ clang::tooling::AtomicChange denormalize(const llvm::yaml::IO &) {
+ llvm_unreachable("Do not convert YAML to AtomicChange directly with '>>'. "
+ "Use AtomicChange::convertFromYAML instead.");
+ }
+ std::string Key;
+ std::string FilePath;
+ std::string Error;
+ std::vector<std::string> InsertedHeaders;
+ std::vector<std::string> RemovedHeaders;
+ std::vector<clang::tooling::Replacement> Replaces;
+};
+} // anonymous namespace
+
+namespace llvm {
+namespace yaml {
+
+/// \brief Specialized MappingTraits to describe how an AtomicChange is
+/// (de)serialized.
+template <> struct MappingTraits<NormalizedAtomicChange> {
+ static void mapping(IO &Io, NormalizedAtomicChange &Doc) {
+ Io.mapRequired("Key", Doc.Key);
+ Io.mapRequired("FilePath", Doc.FilePath);
+ Io.mapRequired("Error", Doc.Error);
+ Io.mapRequired("InsertedHeaders", Doc.InsertedHeaders);
+ Io.mapRequired("RemovedHeaders", Doc.RemovedHeaders);
+ Io.mapRequired("Replacements", Doc.Replaces);
+ }
+};
+
+/// \brief Specialized MappingTraits to describe how an AtomicChange is
+/// (de)serialized.
+template <> struct MappingTraits<clang::tooling::AtomicChange> {
+ static void mapping(IO &Io, clang::tooling::AtomicChange &Doc) {
+ MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange>
+ Keys(Io, Doc);
+ Io.mapRequired("Key", Keys->Key);
+ Io.mapRequired("FilePath", Keys->FilePath);
+ Io.mapRequired("Error", Keys->Error);
+ Io.mapRequired("InsertedHeaders", Keys->InsertedHeaders);
+ Io.mapRequired("RemovedHeaders", Keys->RemovedHeaders);
+ Io.mapRequired("Replacements", Keys->Replaces);
+ }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+namespace clang {
+namespace tooling {
+
+AtomicChange::AtomicChange(const SourceManager &SM,
+ SourceLocation KeyPosition) {
+ const FullSourceLoc FullKeyPosition(KeyPosition, SM);
+ std::pair<FileID, unsigned> FileIDAndOffset =
+ FullKeyPosition.getSpellingLoc().getDecomposedLoc();
+ const FileEntry *FE = SM.getFileEntryForID(FileIDAndOffset.first);
+ assert(FE && "Cannot create AtomicChange with invalid location.");
+ FilePath = FE->getName();
+ Key = FilePath + ":" + std::to_string(FileIDAndOffset.second);
+}
+
+AtomicChange::AtomicChange(std::string Key, std::string FilePath,
+ std::string Error,
+ std::vector<std::string> InsertedHeaders,
+ std::vector<std::string> RemovedHeaders,
+ clang::tooling::Replacements Replaces)
+ : Key(std::move(Key)), FilePath(std::move(FilePath)),
+ Error(std::move(Error)), InsertedHeaders(std::move(InsertedHeaders)),
+ RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) {
+}
+
+std::string AtomicChange::toYAMLString() {
+ std::string YamlContent;
+ llvm::raw_string_ostream YamlContentStream(YamlContent);
+
+ llvm::yaml::Output YAML(YamlContentStream);
+ YAML << *this;
+ YamlContentStream.flush();
+ return YamlContent;
+}
+
+AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) {
+ NormalizedAtomicChange NE;
+ llvm::yaml::Input YAML(YAMLContent);
+ YAML >> NE;
+ AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders,
+ NE.RemovedHeaders, tooling::Replacements());
+ for (const auto &R : NE.Replaces) {
+ llvm::Error Err = E.Replaces.add(R);
+ if (Err)
+ llvm_unreachable(
+ "Failed to add replacement when Converting YAML to AtomicChange.");
+ llvm::consumeError(std::move(Err));
+ }
+ return E;
+}
+
+llvm::Error AtomicChange::replace(const SourceManager &SM,
+ const CharSourceRange &Range,
+ llvm::StringRef ReplacementText) {
+ return Replaces.add(Replacement(SM, Range, ReplacementText));
+}
+
+llvm::Error AtomicChange::replace(const SourceManager &SM, SourceLocation Loc,
+ unsigned Length, llvm::StringRef Text) {
+ return Replaces.add(Replacement(SM, Loc, Length, Text));
+}
+
+llvm::Error AtomicChange::insert(const SourceManager &SM, SourceLocation Loc,
+ llvm::StringRef Text, bool InsertAfter) {
+ if (Text.empty())
+ return llvm::Error::success();
+ Replacement R(SM, Loc, 0, Text);
+ llvm::Error Err = Replaces.add(R);
+ if (Err) {
+ return llvm::handleErrors(
+ std::move(Err), [&](const ReplacementError &RE) -> llvm::Error {
+ if (RE.get() != replacement_error::insert_conflict)
+ return llvm::make_error<ReplacementError>(RE);
+ unsigned NewOffset = Replaces.getShiftedCodePosition(R.getOffset());
+ if (!InsertAfter)
+ NewOffset -=
+ RE.getExistingReplacement()->getReplacementText().size();
+ Replacement NewR(R.getFilePath(), NewOffset, 0, Text);
+ Replaces = Replaces.merge(Replacements(NewR));
+ return llvm::Error::success();
+ });
+ }
+ return llvm::Error::success();
+}
+
+void AtomicChange::addHeader(llvm::StringRef Header) {
+ InsertedHeaders.push_back(Header);
+}
+
+void AtomicChange::removeHeader(llvm::StringRef Header) {
+ RemovedHeaders.push_back(Header);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
new file mode 100644
index 0000000..de6aba9
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
@@ -0,0 +1,134 @@
+//===--- RenamingAction.cpp - Clang refactoring library -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to rename every symbol at a point.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+class RenamingASTConsumer : public ASTConsumer {
+public:
+ RenamingASTConsumer(
+ const std::vector<std::string> &NewNames,
+ const std::vector<std::string> &PrevNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces,
+ bool PrintLocations)
+ : NewNames(NewNames), PrevNames(PrevNames), USRList(USRList),
+ FileToReplaces(FileToReplaces), PrintLocations(PrintLocations) {}
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ for (unsigned I = 0; I < NewNames.size(); ++I)
+ HandleOneRename(Context, NewNames[I], PrevNames[I], USRList[I]);
+ }
+
+ void HandleOneRename(ASTContext &Context, const std::string &NewName,
+ const std::string &PrevName,
+ const std::vector<std::string> &USRs) {
+ const SourceManager &SourceMgr = Context.getSourceManager();
+ std::vector<SourceLocation> RenamingCandidates;
+ std::vector<SourceLocation> NewCandidates;
+
+ NewCandidates = tooling::getLocationsOfUSRs(
+ USRs, PrevName, Context.getTranslationUnitDecl());
+ RenamingCandidates.insert(RenamingCandidates.end(), NewCandidates.begin(),
+ NewCandidates.end());
+
+ unsigned PrevNameLen = PrevName.length();
+ for (const auto &Loc : RenamingCandidates) {
+ if (PrintLocations) {
+ FullSourceLoc FullLoc(Loc, SourceMgr);
+ errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc)
+ << ":" << FullLoc.getSpellingLineNumber() << ":"
+ << FullLoc.getSpellingColumnNumber() << "\n";
+ }
+ // FIXME: better error handling.
+ tooling::Replacement Replace(SourceMgr, Loc, PrevNameLen, NewName);
+ llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace);
+ if (Err)
+ llvm::errs() << "Renaming failed in " << Replace.getFilePath() << "! "
+ << llvm::toString(std::move(Err)) << "\n";
+ }
+ }
+
+private:
+ const std::vector<std::string> &NewNames, &PrevNames;
+ const std::vector<std::vector<std::string>> &USRList;
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+ bool PrintLocations;
+};
+
+// A renamer to rename symbols which are identified by a give USRList to
+// new name.
+//
+// FIXME: Merge with the above RenamingASTConsumer.
+class USRSymbolRenamer : public ASTConsumer {
+public:
+ USRSymbolRenamer(const std::vector<std::string> &NewNames,
+ const std::vector<std::vector<std::string>> &USRList,
+ std::map<std::string, tooling::Replacements> &FileToReplaces)
+ : NewNames(NewNames), USRList(USRList), FileToReplaces(FileToReplaces) {
+ assert(USRList.size() == NewNames.size());
+ }
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ for (unsigned I = 0; I < NewNames.size(); ++I) {
+ // FIXME: Apply AtomicChanges directly once the refactoring APIs are
+ // ready.
+ auto AtomicChanges = tooling::createRenameAtomicChanges(
+ USRList[I], NewNames[I], Context.getTranslationUnitDecl());
+ for (const auto AtomicChange : AtomicChanges) {
+ for (const auto &Replace : AtomicChange.getReplacements()) {
+ llvm::Error Err = FileToReplaces[Replace.getFilePath()].add(Replace);
+ if (Err) {
+ llvm::errs() << "Renaming failed in " << Replace.getFilePath()
+ << "! " << llvm::toString(std::move(Err)) << "\n";
+ }
+ }
+ }
+ }
+ }
+
+private:
+ const std::vector<std::string> &NewNames;
+ const std::vector<std::vector<std::string>> &USRList;
+ std::map<std::string, tooling::Replacements> &FileToReplaces;
+};
+
+std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() {
+ return llvm::make_unique<RenamingASTConsumer>(NewNames, PrevNames, USRList,
+ FileToReplaces, PrintLocations);
+}
+
+std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newASTConsumer() {
+ return llvm::make_unique<USRSymbolRenamer>(NewNames, USRList, FileToReplaces);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
new file mode 100644
index 0000000..3bfb5bb
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
@@ -0,0 +1,146 @@
+//===--- USRFinder.cpp - Clang refactoring library ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file Implements a recursive AST visitor that finds the USR of a symbol at a
+/// point.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Index/USRGeneration.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+/// Recursively visits each AST node to find the symbol underneath the cursor.
+class NamedDeclOccurrenceFindingVisitor
+ : public RecursiveSymbolVisitor<NamedDeclOccurrenceFindingVisitor> {
+public:
+ // \brief Finds the NamedDecl at a point in the source.
+ // \param Point the location in the source to search for the NamedDecl.
+ explicit NamedDeclOccurrenceFindingVisitor(const SourceLocation Point,
+ const ASTContext &Context)
+ : RecursiveSymbolVisitor(Context.getSourceManager(),
+ Context.getLangOpts()),
+ Point(Point), Context(Context) {}
+
+ bool visitSymbolOccurrence(const NamedDecl *ND,
+ ArrayRef<SourceRange> NameRanges) {
+ if (!ND)
+ return true;
+ for (const auto &Range : NameRanges) {
+ SourceLocation Start = Range.getBegin();
+ SourceLocation End = Range.getEnd();
+ if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
+ !End.isFileID() || !isPointWithin(Start, End))
+ return true;
+ }
+ Result = ND;
+ return false;
+ }
+
+ const NamedDecl *getNamedDecl() const { return Result; }
+
+private:
+ // \brief Determines if the Point is within Start and End.
+ bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
+ // FIXME: Add tests for Point == End.
+ return Point == Start || Point == End ||
+ (Context.getSourceManager().isBeforeInTranslationUnit(Start,
+ Point) &&
+ Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
+ }
+
+ const NamedDecl *Result = nullptr;
+ const SourceLocation Point; // The location to find the NamedDecl.
+ const ASTContext &Context;
+};
+
+} // end anonymous namespace
+
+const NamedDecl *getNamedDeclAt(const ASTContext &Context,
+ const SourceLocation Point) {
+ const SourceManager &SM = Context.getSourceManager();
+ NamedDeclOccurrenceFindingVisitor Visitor(Point, Context);
+
+ // Try to be clever about pruning down the number of top-level declarations we
+ // see. If both start and end is either before or after the point we're
+ // looking for the point cannot be inside of this decl. Don't even look at it.
+ for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
+ SourceLocation StartLoc = CurrDecl->getLocStart();
+ SourceLocation EndLoc = CurrDecl->getLocEnd();
+ if (StartLoc.isValid() && EndLoc.isValid() &&
+ SM.isBeforeInTranslationUnit(StartLoc, Point) !=
+ SM.isBeforeInTranslationUnit(EndLoc, Point))
+ Visitor.TraverseDecl(CurrDecl);
+ }
+
+ return Visitor.getNamedDecl();
+}
+
+namespace {
+
+/// Recursively visits each NamedDecl node to find the declaration with a
+/// specific name.
+class NamedDeclFindingVisitor
+ : public RecursiveASTVisitor<NamedDeclFindingVisitor> {
+public:
+ explicit NamedDeclFindingVisitor(StringRef Name) : Name(Name) {}
+
+ // We don't have to traverse the uses to find some declaration with a
+ // specific name, so just visit the named declarations.
+ bool VisitNamedDecl(const NamedDecl *ND) {
+ if (!ND)
+ return true;
+ // Fully qualified name is used to find the declaration.
+ if (Name != ND->getQualifiedNameAsString() &&
+ Name != "::" + ND->getQualifiedNameAsString())
+ return true;
+ Result = ND;
+ return false;
+ }
+
+ const NamedDecl *getNamedDecl() const { return Result; }
+
+private:
+ const NamedDecl *Result = nullptr;
+ StringRef Name;
+};
+
+} // end anonymous namespace
+
+const NamedDecl *getNamedDeclFor(const ASTContext &Context,
+ const std::string &Name) {
+ NamedDeclFindingVisitor Visitor(Name);
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ return Visitor.getNamedDecl();
+}
+
+std::string getUSRForDecl(const Decl *Decl) {
+ llvm::SmallVector<char, 128> Buff;
+
+ // FIXME: Add test for the nullptr case.
+ if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
+ return "";
+
+ return std::string(Buff.data(), Buff.size());
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
new file mode 100644
index 0000000..2769802
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
@@ -0,0 +1,236 @@
+//===--- USRFindingAction.cpp - Clang refactoring library -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provides an action to find USR for the symbol at <offset>, as well as
+/// all additional USRs.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "clang/Tooling/Tooling.h"
+
+#include <algorithm>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+// \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to
+// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given
+// Decl refers to class and adds USRs of all overridden methods if Decl refers
+// to virtual method.
+class AdditionalUSRFinder : public RecursiveASTVisitor<AdditionalUSRFinder> {
+public:
+ AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context)
+ : FoundDecl(FoundDecl), Context(Context) {}
+
+ std::vector<std::string> Find() {
+ // Fill OverriddenMethods and PartialSpecs storages.
+ TraverseDecl(Context.getTranslationUnitDecl());
+ if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
+ addUSRsOfOverridenFunctions(MethodDecl);
+ for (const auto &OverriddenMethod : OverriddenMethods) {
+ if (checkIfOverriddenFunctionAscends(OverriddenMethod))
+ USRSet.insert(getUSRForDecl(OverriddenMethod));
+ }
+ } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) {
+ handleCXXRecordDecl(RecordDecl);
+ } else if (const auto *TemplateDecl =
+ dyn_cast<ClassTemplateDecl>(FoundDecl)) {
+ handleClassTemplateDecl(TemplateDecl);
+ } else {
+ USRSet.insert(getUSRForDecl(FoundDecl));
+ }
+ return std::vector<std::string>(USRSet.begin(), USRSet.end());
+ }
+
+ bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) {
+ if (MethodDecl->isVirtual())
+ OverriddenMethods.push_back(MethodDecl);
+ return true;
+ }
+
+ bool VisitClassTemplatePartialSpecializationDecl(
+ const ClassTemplatePartialSpecializationDecl *PartialSpec) {
+ PartialSpecs.push_back(PartialSpec);
+ return true;
+ }
+
+private:
+ void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) {
+ RecordDecl = RecordDecl->getDefinition();
+ if (const auto *ClassTemplateSpecDecl =
+ dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl))
+ handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate());
+ addUSRsOfCtorDtors(RecordDecl);
+ }
+
+ void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) {
+ for (const auto *Specialization : TemplateDecl->specializations())
+ addUSRsOfCtorDtors(Specialization);
+
+ for (const auto *PartialSpec : PartialSpecs) {
+ if (PartialSpec->getSpecializedTemplate() == TemplateDecl)
+ addUSRsOfCtorDtors(PartialSpec);
+ }
+ addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl());
+ }
+
+ void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) {
+ RecordDecl = RecordDecl->getDefinition();
+
+ // Skip if the CXXRecordDecl doesn't have definition.
+ if (!RecordDecl)
+ return;
+
+ for (const auto *CtorDecl : RecordDecl->ctors())
+ USRSet.insert(getUSRForDecl(CtorDecl));
+
+ USRSet.insert(getUSRForDecl(RecordDecl->getDestructor()));
+ USRSet.insert(getUSRForDecl(RecordDecl));
+ }
+
+ void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) {
+ USRSet.insert(getUSRForDecl(MethodDecl));
+ // Recursively visit each OverridenMethod.
+ for (const auto &OverriddenMethod : MethodDecl->overridden_methods())
+ addUSRsOfOverridenFunctions(OverriddenMethod);
+ }
+
+ bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) {
+ for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) {
+ if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end())
+ return true;
+ return checkIfOverriddenFunctionAscends(OverriddenMethod);
+ }
+ return false;
+ }
+
+ const Decl *FoundDecl;
+ ASTContext &Context;
+ std::set<std::string> USRSet;
+ std::vector<const CXXMethodDecl *> OverriddenMethods;
+ std::vector<const ClassTemplatePartialSpecializationDecl *> PartialSpecs;
+};
+} // namespace
+
+class NamedDeclFindingConsumer : public ASTConsumer {
+public:
+ NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets,
+ ArrayRef<std::string> QualifiedNames,
+ std::vector<std::string> &SpellingNames,
+ std::vector<std::vector<std::string>> &USRList,
+ bool Force, bool &ErrorOccurred)
+ : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
+ SpellingNames(SpellingNames), USRList(USRList), Force(Force),
+ ErrorOccurred(ErrorOccurred) {}
+
+private:
+ bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr,
+ unsigned SymbolOffset, const std::string &QualifiedName) {
+ DiagnosticsEngine &Engine = Context.getDiagnostics();
+ const FileID MainFileID = SourceMgr.getMainFileID();
+
+ if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) {
+ ErrorOccurred = true;
+ unsigned InvalidOffset = Engine.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "SourceLocation in file %0 at offset %1 is invalid");
+ Engine.Report(SourceLocation(), InvalidOffset)
+ << SourceMgr.getFileEntryForID(MainFileID)->getName() << SymbolOffset;
+ return false;
+ }
+
+ const SourceLocation Point = SourceMgr.getLocForStartOfFile(MainFileID)
+ .getLocWithOffset(SymbolOffset);
+ const NamedDecl *FoundDecl = QualifiedName.empty()
+ ? getNamedDeclAt(Context, Point)
+ : getNamedDeclFor(Context, QualifiedName);
+
+ if (FoundDecl == nullptr) {
+ if (QualifiedName.empty()) {
+ FullSourceLoc FullLoc(Point, SourceMgr);
+ unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "clang-rename could not find symbol (offset %0)");
+ Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset;
+ ErrorOccurred = true;
+ return false;
+ }
+
+ if (Force)
+ return true;
+
+ unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID(
+ DiagnosticsEngine::Error, "clang-rename could not find symbol %0");
+ Engine.Report(CouldNotFindSymbolNamed) << QualifiedName;
+ ErrorOccurred = true;
+ return false;
+ }
+
+ // If FoundDecl is a constructor or destructor, we want to instead take
+ // the Decl of the corresponding class.
+ if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
+ FoundDecl = CtorDecl->getParent();
+ else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
+ FoundDecl = DtorDecl->getParent();
+
+ SpellingNames.push_back(FoundDecl->getNameAsString());
+ AdditionalUSRFinder Finder(FoundDecl, Context);
+ USRList.push_back(Finder.Find());
+ return true;
+ }
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ const SourceManager &SourceMgr = Context.getSourceManager();
+ for (unsigned Offset : SymbolOffsets) {
+ if (!FindSymbol(Context, SourceMgr, Offset, ""))
+ return;
+ }
+ for (const std::string &QualifiedName : QualifiedNames) {
+ if (!FindSymbol(Context, SourceMgr, 0, QualifiedName))
+ return;
+ }
+ }
+
+ ArrayRef<unsigned> SymbolOffsets;
+ ArrayRef<std::string> QualifiedNames;
+ std::vector<std::string> &SpellingNames;
+ std::vector<std::vector<std::string>> &USRList;
+ bool Force;
+ bool &ErrorOccurred;
+};
+
+std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
+ return llvm::make_unique<NamedDeclFindingConsumer>(
+ SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force,
+ ErrorOccurred);
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
new file mode 100644
index 0000000..dc21a94
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp
@@ -0,0 +1,451 @@
+//===--- USRLocFinder.cpp - Clang refactoring library ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Methods for finding all instances of a USR. Our strategy is very
+/// simple; we just compare the USR at every relevant AST node with the one
+/// provided.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Core/Lookup.h"
+#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
+#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include <cstddef>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+// \brief This visitor recursively searches for all instances of a USR in a
+// translation unit and stores them for later usage.
+class USRLocFindingASTVisitor
+ : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> {
+public:
+ explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs,
+ StringRef PrevName,
+ const ASTContext &Context)
+ : RecursiveSymbolVisitor(Context.getSourceManager(),
+ Context.getLangOpts()),
+ USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
+ }
+
+ bool visitSymbolOccurrence(const NamedDecl *ND,
+ ArrayRef<SourceRange> NameRanges) {
+ if (USRSet.find(getUSRForDecl(ND)) != USRSet.end()) {
+ assert(NameRanges.size() == 1 &&
+ "Multiple name pieces are not supported yet!");
+ SourceLocation Loc = NameRanges[0].getBegin();
+ const SourceManager &SM = Context.getSourceManager();
+ // TODO: Deal with macro occurrences correctly.
+ if (Loc.isMacroID())
+ Loc = SM.getSpellingLoc(Loc);
+ checkAndAddLocation(Loc);
+ }
+ return true;
+ }
+
+ // Non-visitors:
+
+ // \brief Returns a list of unique locations. Duplicate or overlapping
+ // locations are erroneous and should be reported!
+ const std::vector<clang::SourceLocation> &getLocationsFound() const {
+ return LocationsFound;
+ }
+
+private:
+ void checkAndAddLocation(SourceLocation Loc) {
+ const SourceLocation BeginLoc = Loc;
+ const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
+ StringRef TokenName =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
+ Context.getSourceManager(), Context.getLangOpts());
+ size_t Offset = TokenName.find(PrevName);
+
+ // The token of the source location we find actually has the old
+ // name.
+ if (Offset != StringRef::npos)
+ LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset));
+ }
+
+ const std::set<std::string> USRSet;
+ const std::string PrevName;
+ std::vector<clang::SourceLocation> LocationsFound;
+ const ASTContext &Context;
+};
+
+SourceLocation StartLocationForType(TypeLoc TL) {
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the
+ // `struct` but including the namespace qualifier, `a::`.
+ if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) {
+ NestedNameSpecifierLoc NestedNameSpecifier =
+ ElaboratedTypeLoc.getQualifierLoc();
+ if (NestedNameSpecifier.getNestedNameSpecifier())
+ return NestedNameSpecifier.getBeginLoc();
+ TL = TL.getNextTypeLoc();
+ }
+ return TL.getLocStart();
+}
+
+SourceLocation EndLocationForType(TypeLoc TL) {
+ // Dig past any namespace or keyword qualifications.
+ while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
+ TL.getTypeLocClass() == TypeLoc::Qualified)
+ TL = TL.getNextTypeLoc();
+
+ // The location for template specializations (e.g. Foo<int>) includes the
+ // templated types in its location range. We want to restrict this to just
+ // before the `<` character.
+ if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
+ return TL.castAs<TemplateSpecializationTypeLoc>()
+ .getLAngleLoc()
+ .getLocWithOffset(-1);
+ }
+ return TL.getEndLoc();
+}
+
+NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
+ // Dig past any keyword qualifications.
+ while (TL.getTypeLocClass() == TypeLoc::Qualified)
+ TL = TL.getNextTypeLoc();
+
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the
+ // `struct` but including the namespace qualifier, `a::`.
+ if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>())
+ return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
+ return nullptr;
+}
+
+// Find all locations identified by the given USRs for rename.
+//
+// This class will traverse the AST and find every AST node whose USR is in the
+// given USRs' set.
+class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> {
+public:
+ RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
+ : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
+
+ // A structure records all information of a symbol reference being renamed.
+ // We try to add as few prefix qualifiers as possible.
+ struct RenameInfo {
+ // The begin location of a symbol being renamed.
+ SourceLocation Begin;
+ // The end location of a symbol being renamed.
+ SourceLocation End;
+ // The declaration of a symbol being renamed (can be nullptr).
+ const NamedDecl *FromDecl;
+ // The declaration in which the nested name is contained (can be nullptr).
+ const Decl *Context;
+ // The nested name being replaced (can be nullptr).
+ const NestedNameSpecifier *Specifier;
+ };
+
+ // FIXME: Currently, prefix qualifiers will be added to the renamed symbol
+ // definition (e.g. "class Foo {};" => "class b::Bar {};" when renaming
+ // "a::Foo" to "b::Bar").
+ // For renaming declarations/definitions, prefix qualifiers should be filtered
+ // out.
+ bool VisitNamedDecl(const NamedDecl *Decl) {
+ // UsingDecl has been handled in other place.
+ if (llvm::isa<UsingDecl>(Decl))
+ return true;
+
+ // DestructorDecl has been handled in Typeloc.
+ if (llvm::isa<CXXDestructorDecl>(Decl))
+ return true;
+
+ if (Decl->isImplicit())
+ return true;
+
+ if (isInUSRSet(Decl)) {
+ RenameInfo Info = {Decl->getLocation(), Decl->getLocation(), nullptr,
+ nullptr, nullptr};
+ RenameInfos.push_back(Info);
+ }
+ return true;
+ }
+
+ bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
+ const NamedDecl *Decl = Expr->getFoundDecl();
+ if (isInUSRSet(Decl)) {
+ RenameInfo Info = {Expr->getSourceRange().getBegin(),
+ Expr->getSourceRange().getEnd(), Decl,
+ getClosestAncestorDecl(*Expr), Expr->getQualifier()};
+ RenameInfos.push_back(Info);
+ }
+
+ return true;
+ }
+
+ bool VisitUsingDecl(const UsingDecl *Using) {
+ for (const auto *UsingShadow : Using->shadows()) {
+ if (isInUSRSet(UsingShadow->getTargetDecl())) {
+ UsingDecls.push_back(Using);
+ break;
+ }
+ }
+ return true;
+ }
+
+ bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
+ if (!NestedLoc.getNestedNameSpecifier()->getAsType())
+ return true;
+ if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc()))
+ return true;
+
+ if (const auto *TargetDecl =
+ getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
+ if (isInUSRSet(TargetDecl)) {
+ RenameInfo Info = {NestedLoc.getBeginLoc(),
+ EndLocationForType(NestedLoc.getTypeLoc()),
+ TargetDecl, getClosestAncestorDecl(NestedLoc),
+ NestedLoc.getNestedNameSpecifier()->getPrefix()};
+ RenameInfos.push_back(Info);
+ }
+ }
+ return true;
+ }
+
+ bool VisitTypeLoc(TypeLoc Loc) {
+ if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc))
+ return true;
+
+ auto Parents = Context.getParents(Loc);
+ TypeLoc ParentTypeLoc;
+ if (!Parents.empty()) {
+ // Handle cases of nested name specificier locations.
+ //
+ // The VisitNestedNameSpecifierLoc interface is not impelmented in
+ // RecursiveASTVisitor, we have to handle it explicitly.
+ if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
+ VisitNestedNameSpecifierLocations(*NSL);
+ return true;
+ }
+
+ if (const auto *TL = Parents[0].get<TypeLoc>())
+ ParentTypeLoc = *TL;
+ }
+
+ // Handle the outermost TypeLoc which is directly linked to the interesting
+ // declaration and don't handle nested name specifier locations.
+ if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
+ if (isInUSRSet(TargetDecl)) {
+ // Only handle the outermost typeLoc.
+ //
+ // For a type like "a::Foo", there will be two typeLocs for it.
+ // One ElaboratedType, the other is RecordType:
+ //
+ // ElaboratedType 0x33b9390 'a::Foo' sugar
+ // `-RecordType 0x338fef0 'class a::Foo'
+ // `-CXXRecord 0x338fe58 'Foo'
+ //
+ // Skip if this is an inner typeLoc.
+ if (!ParentTypeLoc.isNull() &&
+ isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
+ return true;
+ RenameInfo Info = {StartLocationForType(Loc), EndLocationForType(Loc),
+ TargetDecl, getClosestAncestorDecl(Loc),
+ GetNestedNameForType(Loc)};
+ RenameInfos.push_back(Info);
+ return true;
+ }
+ }
+
+ // Handle specific template class specialiation cases.
+ if (const auto *TemplateSpecType =
+ dyn_cast<TemplateSpecializationType>(Loc.getType())) {
+ TypeLoc TargetLoc = Loc;
+ if (!ParentTypeLoc.isNull()) {
+ if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
+ TargetLoc = ParentTypeLoc;
+ }
+
+ if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
+ TypeLoc TargetLoc = Loc;
+ // FIXME: Find a better way to handle this case.
+ // For the qualified template class specification type like
+ // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc
+ // (ElaboratedType) of the TemplateSpecializationType in order to
+ // catch the prefix qualifiers "ns::".
+ if (!ParentTypeLoc.isNull() &&
+ llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
+ TargetLoc = ParentTypeLoc;
+ RenameInfo Info = {
+ StartLocationForType(TargetLoc), EndLocationForType(TargetLoc),
+ TemplateSpecType->getTemplateName().getAsTemplateDecl(),
+ getClosestAncestorDecl(
+ ast_type_traits::DynTypedNode::create(TargetLoc)),
+ GetNestedNameForType(TargetLoc)};
+ RenameInfos.push_back(Info);
+ }
+ }
+ return true;
+ }
+
+ // Returns a list of RenameInfo.
+ const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }
+
+ // Returns a list of using declarations which are needed to update.
+ const std::vector<const UsingDecl *> &getUsingDecls() const {
+ return UsingDecls;
+ }
+
+private:
+ // FIXME: This method may not be suitable for renaming other types like alias
+ // types. Need to figure out a way to handle it.
+ bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL) const {
+ while (!TL.isNull()) {
+ // SubstTemplateTypeParm is the TypeLocation class for a substituted type
+ // inside a template expansion so we ignore these. For example:
+ //
+ // template<typename T> struct S {
+ // T t; // <-- this T becomes a TypeLoc(int) with class
+ // // SubstTemplateTypeParm when S<int> is instantiated
+ // }
+ if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
+ return true;
+
+ // Typedef is the TypeLocation class for a type which is a typedef to the
+ // type we want to replace. We ignore the use of the typedef as we will
+ // replace the definition of it. For example:
+ //
+ // typedef int T;
+ // T a; // <--- This T is a TypeLoc(int) with class Typedef.
+ if (TL.getTypeLocClass() == TypeLoc::Typedef)
+ return true;
+ TL = TL.getNextTypeLoc();
+ }
+ return false;
+ }
+
+ // Get the supported declaration from a given typeLoc. If the declaration type
+ // is not supported, returns nullptr.
+ //
+ // FIXME: support more types, e.g. enum, type alias.
+ const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
+ if (const auto *RD = Loc.getType()->getAsCXXRecordDecl())
+ return RD;
+ return nullptr;
+ }
+
+ // Get the closest ancester which is a declaration of a given AST node.
+ template <typename ASTNodeType>
+ const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
+ auto Parents = Context.getParents(Node);
+ // FIXME: figure out how to handle it when there are multiple parents.
+ if (Parents.size() != 1)
+ return nullptr;
+ if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
+ Parents[0].getNodeKind()))
+ return Parents[0].template get<Decl>();
+ return getClosestAncestorDecl(Parents[0]);
+ }
+
+ // Get the parent typeLoc of a given typeLoc. If there is no such parent,
+ // return nullptr.
+ const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
+ auto Parents = Context.getParents(Loc);
+ // FIXME: figure out how to handle it when there are multiple parents.
+ if (Parents.size() != 1)
+ return nullptr;
+ return Parents[0].get<TypeLoc>();
+ }
+
+ // Check whether the USR of a given Decl is in the USRSet.
+ bool isInUSRSet(const Decl *Decl) const {
+ auto USR = getUSRForDecl(Decl);
+ if (USR.empty())
+ return false;
+ return llvm::is_contained(USRSet, USR);
+ }
+
+ const std::set<std::string> USRSet;
+ ASTContext &Context;
+ std::vector<RenameInfo> RenameInfos;
+ // Record all interested using declarations which contains the using-shadow
+ // declarations of the symbol declarations being renamed.
+ std::vector<const UsingDecl *> UsingDecls;
+};
+
+} // namespace
+
+std::vector<SourceLocation>
+getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef PrevName,
+ Decl *Decl) {
+ USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
+ Visitor.TraverseDecl(Decl);
+ return Visitor.getLocationsFound();
+}
+
+std::vector<tooling::AtomicChange>
+createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
+ llvm::StringRef NewName, Decl *TranslationUnitDecl) {
+ RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
+ Finder.TraverseDecl(TranslationUnitDecl);
+
+ const SourceManager &SM =
+ TranslationUnitDecl->getASTContext().getSourceManager();
+
+ std::vector<tooling::AtomicChange> AtomicChanges;
+ auto Replace = [&](SourceLocation Start, SourceLocation End,
+ llvm::StringRef Text) {
+ tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);
+ llvm::Error Err = ReplaceChange.replace(
+ SM, CharSourceRange::getTokenRange(Start, End), Text);
+ if (Err) {
+ llvm::errs() << "Faile to add replacement to AtomicChange: "
+ << llvm::toString(std::move(Err)) << "\n";
+ return;
+ }
+ AtomicChanges.push_back(std::move(ReplaceChange));
+ };
+
+ for (const auto &RenameInfo : Finder.getRenameInfos()) {
+ std::string ReplacedName = NewName.str();
+ if (RenameInfo.FromDecl && RenameInfo.Context) {
+ if (!llvm::isa<clang::TranslationUnitDecl>(
+ RenameInfo.Context->getDeclContext())) {
+ ReplacedName = tooling::replaceNestedName(
+ RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
+ RenameInfo.FromDecl,
+ NewName.startswith("::") ? NewName.str() : ("::" + NewName).str());
+ }
+ }
+ // If the NewName contains leading "::", add it back.
+ if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
+ ReplacedName = NewName.str();
+ Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
+ }
+
+ // Hanlde using declarations explicitly as "using a::Foo" don't trigger
+ // typeLoc for "a::Foo".
+ for (const auto *Using : Finder.getUsingDecls())
+ Replace(Using->getLocStart(), Using->getLocEnd(), "using " + NewName.str());
+
+ return AtomicChanges;
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/RefactoringCallbacks.cpp b/contrib/llvm/tools/clang/lib/Tooling/RefactoringCallbacks.cpp
index e900c23..9fd333c 100644
--- a/contrib/llvm/tools/clang/lib/Tooling/RefactoringCallbacks.cpp
+++ b/contrib/llvm/tools/clang/lib/Tooling/RefactoringCallbacks.cpp
@@ -9,8 +9,13 @@
//
//
//===----------------------------------------------------------------------===//
-#include "clang/Lex/Lexer.h"
#include "clang/Tooling/RefactoringCallbacks.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+
+using llvm::StringError;
+using llvm::make_error;
namespace clang {
namespace tooling {
@@ -20,18 +25,62 @@ tooling::Replacements &RefactoringCallback::getReplacements() {
return Replace;
}
-static Replacement replaceStmtWithText(SourceManager &Sources,
- const Stmt &From,
+ASTMatchRefactorer::ASTMatchRefactorer(
+ std::map<std::string, Replacements> &FileToReplaces)
+ : FileToReplaces(FileToReplaces) {}
+
+void ASTMatchRefactorer::addDynamicMatcher(
+ const ast_matchers::internal::DynTypedMatcher &Matcher,
+ RefactoringCallback *Callback) {
+ MatchFinder.addDynamicMatcher(Matcher, Callback);
+ Callbacks.push_back(Callback);
+}
+
+class RefactoringASTConsumer : public ASTConsumer {
+public:
+ explicit RefactoringASTConsumer(ASTMatchRefactorer &Refactoring)
+ : Refactoring(Refactoring) {}
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ // The ASTMatchRefactorer is re-used between translation units.
+ // Clear the matchers so that each Replacement is only emitted once.
+ for (const auto &Callback : Refactoring.Callbacks) {
+ Callback->getReplacements().clear();
+ }
+ Refactoring.MatchFinder.matchAST(Context);
+ for (const auto &Callback : Refactoring.Callbacks) {
+ for (const auto &Replacement : Callback->getReplacements()) {
+ llvm::Error Err =
+ Refactoring.FileToReplaces[Replacement.getFilePath()].add(
+ Replacement);
+ if (Err) {
+ llvm::errs() << "Skipping replacement " << Replacement.toString()
+ << " due to this error:\n"
+ << toString(std::move(Err)) << "\n";
+ }
+ }
+ }
+ }
+
+private:
+ ASTMatchRefactorer &Refactoring;
+};
+
+std::unique_ptr<ASTConsumer> ASTMatchRefactorer::newASTConsumer() {
+ return llvm::make_unique<RefactoringASTConsumer>(*this);
+}
+
+static Replacement replaceStmtWithText(SourceManager &Sources, const Stmt &From,
StringRef Text) {
- return tooling::Replacement(Sources, CharSourceRange::getTokenRange(
- From.getSourceRange()), Text);
+ return tooling::Replacement(
+ Sources, CharSourceRange::getTokenRange(From.getSourceRange()), Text);
}
-static Replacement replaceStmtWithStmt(SourceManager &Sources,
- const Stmt &From,
+static Replacement replaceStmtWithStmt(SourceManager &Sources, const Stmt &From,
const Stmt &To) {
- return replaceStmtWithText(Sources, From, Lexer::getSourceText(
- CharSourceRange::getTokenRange(To.getSourceRange()),
- Sources, LangOptions()));
+ return replaceStmtWithText(
+ Sources, From,
+ Lexer::getSourceText(CharSourceRange::getTokenRange(To.getSourceRange()),
+ Sources, LangOptions()));
}
ReplaceStmtWithText::ReplaceStmtWithText(StringRef FromId, StringRef ToText)
@@ -103,5 +152,90 @@ void ReplaceIfStmtWithItsBody::run(
}
}
+ReplaceNodeWithTemplate::ReplaceNodeWithTemplate(
+ llvm::StringRef FromId, std::vector<TemplateElement> Template)
+ : FromId(FromId), Template(std::move(Template)) {}
+
+llvm::Expected<std::unique_ptr<ReplaceNodeWithTemplate>>
+ReplaceNodeWithTemplate::create(StringRef FromId, StringRef ToTemplate) {
+ std::vector<TemplateElement> ParsedTemplate;
+ for (size_t Index = 0; Index < ToTemplate.size();) {
+ if (ToTemplate[Index] == '$') {
+ if (ToTemplate.substr(Index, 2) == "$$") {
+ Index += 2;
+ ParsedTemplate.push_back(
+ TemplateElement{TemplateElement::Literal, "$"});
+ } else if (ToTemplate.substr(Index, 2) == "${") {
+ size_t EndOfIdentifier = ToTemplate.find("}", Index);
+ if (EndOfIdentifier == std::string::npos) {
+ return make_error<StringError>(
+ "Unterminated ${...} in replacement template near " +
+ ToTemplate.substr(Index),
+ llvm::inconvertibleErrorCode());
+ }
+ std::string SourceNodeName =
+ ToTemplate.substr(Index + 2, EndOfIdentifier - Index - 2);
+ ParsedTemplate.push_back(
+ TemplateElement{TemplateElement::Identifier, SourceNodeName});
+ Index = EndOfIdentifier + 1;
+ } else {
+ return make_error<StringError>(
+ "Invalid $ in replacement template near " +
+ ToTemplate.substr(Index),
+ llvm::inconvertibleErrorCode());
+ }
+ } else {
+ size_t NextIndex = ToTemplate.find('$', Index + 1);
+ ParsedTemplate.push_back(
+ TemplateElement{TemplateElement::Literal,
+ ToTemplate.substr(Index, NextIndex - Index)});
+ Index = NextIndex;
+ }
+ }
+ return std::unique_ptr<ReplaceNodeWithTemplate>(
+ new ReplaceNodeWithTemplate(FromId, std::move(ParsedTemplate)));
+}
+
+void ReplaceNodeWithTemplate::run(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ const auto &NodeMap = Result.Nodes.getMap();
+
+ std::string ToText;
+ for (const auto &Element : Template) {
+ switch (Element.Type) {
+ case TemplateElement::Literal:
+ ToText += Element.Value;
+ break;
+ case TemplateElement::Identifier: {
+ auto NodeIter = NodeMap.find(Element.Value);
+ if (NodeIter == NodeMap.end()) {
+ llvm::errs() << "Node " << Element.Value
+ << " used in replacement template not bound in Matcher \n";
+ llvm::report_fatal_error("Unbound node in replacement template.");
+ }
+ CharSourceRange Source =
+ CharSourceRange::getTokenRange(NodeIter->second.getSourceRange());
+ ToText += Lexer::getSourceText(Source, *Result.SourceManager,
+ Result.Context->getLangOpts());
+ break;
+ }
+ }
+ }
+ if (NodeMap.count(FromId) == 0) {
+ llvm::errs() << "Node to be replaced " << FromId
+ << " not bound in query.\n";
+ llvm::report_fatal_error("FromId node not bound in MatchResult");
+ }
+ auto Replacement =
+ tooling::Replacement(*Result.SourceManager, &NodeMap.at(FromId), ToText,
+ Result.Context->getLangOpts());
+ llvm::Error Err = Replace.add(Replacement);
+ if (Err) {
+ llvm::errs() << "Query and replace failed in " << Replacement.getFilePath()
+ << "! " << llvm::toString(std::move(Err)) << "\n";
+ llvm::report_fatal_error("Replacement failed");
+ }
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp
index 25cee98..662f02d 100644
--- a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp
+++ b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp
@@ -100,7 +100,6 @@ clang::CompilerInvocation *newInvocation(
*Diagnostics);
Invocation->getFrontendOpts().DisableFree = false;
Invocation->getCodeGenOpts().DisableFree = false;
- Invocation->getDependencyOutputOpts() = DependencyOutputOptions();
return Invocation;
}
@@ -140,9 +139,11 @@ bool runToolOnCodeWithArgs(
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
llvm::IntrusiveRefCntPtr<FileManager> Files(
new FileManager(FileSystemOptions(), OverlayFileSystem));
- ToolInvocation Invocation(getSyntaxOnlyToolArgs(ToolName, Args, FileNameRef),
- ToolAction, Files.get(),
- std::move(PCHContainerOps));
+ ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster();
+ ToolInvocation Invocation(
+ getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef),
+ ToolAction, Files.get(),
+ std::move(PCHContainerOps));
SmallString<1024> CodeStorage;
InMemoryFileSystem->addFile(FileNameRef, 0,
@@ -244,7 +245,7 @@ bool ToolInvocation::run() {
const char *const BinaryName = Argv[0];
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
unsigned MissingArgIndex, MissingArgCount;
- std::unique_ptr<llvm::opt::OptTable> Opts(driver::createDriverOptTable());
+ std::unique_ptr<llvm::opt::OptTable> Opts = driver::createDriverOptTable();
llvm::opt::InputArgList ParsedArgs = Opts->ParseArgs(
ArrayRef<const char *>(Argv).slice(1), MissingArgIndex, MissingArgCount);
ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
@@ -260,6 +261,8 @@ bool ToolInvocation::run() {
Driver->setCheckInputsExist(false);
const std::unique_ptr<clang::driver::Compilation> Compilation(
Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
+ if (!Compilation)
+ return false;
const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
&Diagnostics, Compilation.get());
if (!CC1Args) {
@@ -333,6 +336,7 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations,
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
appendArgumentsAdjuster(getClangStripOutputAdjuster());
appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
+ appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
}
ClangTool::~ClangTool() {}
@@ -508,7 +512,8 @@ buildASTFromCode(const Twine &Code, const Twine &FileName,
std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
const Twine &Code, const std::vector<std::string> &Args,
const Twine &FileName, const Twine &ToolName,
- std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ ArgumentsAdjuster Adjuster) {
SmallString<16> FileNameStorage;
StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
@@ -521,8 +526,10 @@ std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs(
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
llvm::IntrusiveRefCntPtr<FileManager> Files(
new FileManager(FileSystemOptions(), OverlayFileSystem));
- ToolInvocation Invocation(getSyntaxOnlyToolArgs(ToolName, Args, FileNameRef),
- &Action, Files.get(), std::move(PCHContainerOps));
+
+ ToolInvocation Invocation(
+ getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef),
+ &Action, Files.get(), std::move(PCHContainerOps));
SmallString<1024> CodeStorage;
InMemoryFileSystem->addFile(FileNameRef, 0,
diff --git a/contrib/llvm/tools/clang/tools/clang-format/ClangFormat.cpp b/contrib/llvm/tools/clang/tools/clang-format/ClangFormat.cpp
index 6c50daf..14bff19 100644
--- a/contrib/llvm/tools/clang/tools/clang-format/ClangFormat.cpp
+++ b/contrib/llvm/tools/clang/tools/clang-format/ClangFormat.cpp
@@ -236,8 +236,15 @@ static void outputReplacementsXML(const Replacements &Replaces) {
// Returns true on error.
static bool format(StringRef FileName) {
+ if (!OutputXML && Inplace && FileName == "-") {
+ errs() << "error: cannot use -i when reading from stdin.\n";
+ return false;
+ }
+ // On Windows, overwriting a file with an open file mapping doesn't work,
+ // so read the whole file into memory when formatting in-place.
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
- MemoryBuffer::getFileOrSTDIN(FileName);
+ !OutputXML && Inplace ? MemoryBuffer::getFileAsStream(FileName) :
+ MemoryBuffer::getFileOrSTDIN(FileName);
if (std::error_code EC = CodeOrErr.getError()) {
errs() << EC.message() << "\n";
return true;
@@ -249,12 +256,18 @@ static bool format(StringRef FileName) {
if (fillRanges(Code.get(), Ranges))
return true;
StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName;
- FormatStyle FormatStyle =
+
+ llvm::Expected<FormatStyle> FormatStyle =
getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer());
+ if (!FormatStyle) {
+ llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
+ return true;
+ }
+
if (SortIncludes.getNumOccurrences() != 0)
- FormatStyle.SortIncludes = SortIncludes;
+ FormatStyle->SortIncludes = SortIncludes;
unsigned CursorPosition = Cursor;
- Replacements Replaces = sortIncludes(FormatStyle, Code->getBuffer(), Ranges,
+ Replacements Replaces = sortIncludes(*FormatStyle, Code->getBuffer(), Ranges,
AssumedFileName, &CursorPosition);
auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces);
if (!ChangedCode) {
@@ -263,14 +276,17 @@ static bool format(StringRef FileName) {
}
// Get new affected ranges after sorting `#includes`.
Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
- bool IncompleteFormat = false;
- Replacements FormatChanges = reformat(FormatStyle, *ChangedCode, Ranges,
- AssumedFileName, &IncompleteFormat);
+ FormattingAttemptStatus Status;
+ Replacements FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges,
+ AssumedFileName, &Status);
Replaces = Replaces.merge(FormatChanges);
if (OutputXML) {
outs() << "<?xml version='1.0'?>\n<replacements "
"xml:space='preserve' incomplete_format='"
- << (IncompleteFormat ? "true" : "false") << "'>\n";
+ << (Status.FormatComplete ? "false" : "true") << "'";
+ if (!Status.FormatComplete)
+ outs() << " line=" << Status.Line;
+ outs() << ">\n";
if (Cursor.getNumOccurrences() != 0)
outs() << "<cursor>"
<< FormatChanges.getShiftedCodePosition(CursorPosition)
@@ -291,16 +307,18 @@ static bool format(StringRef FileName) {
Rewriter Rewrite(Sources, LangOptions());
tooling::applyAllReplacements(Replaces, Rewrite);
if (Inplace) {
- if (FileName == "-")
- errs() << "error: cannot use -i when reading from stdin.\n";
- else if (Rewrite.overwriteChangedFiles())
+ if (Rewrite.overwriteChangedFiles())
return true;
} else {
- if (Cursor.getNumOccurrences() != 0)
+ if (Cursor.getNumOccurrences() != 0) {
outs() << "{ \"Cursor\": "
<< FormatChanges.getShiftedCodePosition(CursorPosition)
<< ", \"IncompleteFormat\": "
- << (IncompleteFormat ? "true" : "false") << " }\n";
+ << (Status.FormatComplete ? "false" : "true");
+ if (!Status.FormatComplete)
+ outs() << ", \"Line\": " << Status.Line;
+ outs() << " }\n";
+ }
Rewrite.getEditBuffer(ID).write(outs());
}
}
@@ -334,10 +352,15 @@ int main(int argc, const char **argv) {
cl::PrintHelpMessage();
if (DumpConfig) {
- std::string Config =
- clang::format::configurationAsText(clang::format::getStyle(
+ llvm::Expected<clang::format::FormatStyle> FormatStyle =
+ clang::format::getStyle(
Style, FileNames.empty() ? AssumeFileName : FileNames[0],
- FallbackStyle));
+ FallbackStyle);
+ if (!FormatStyle) {
+ llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
+ return 1;
+ }
+ std::string Config = clang::format::configurationAsText(*FormatStyle);
outs() << Config << "\n";
return 0;
}
diff --git a/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp b/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp
index 2637513..2fc2b50 100644
--- a/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp
+++ b/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp
@@ -88,12 +88,13 @@ struct AssemblerInvocation {
unsigned NoInitialTextSection : 1;
unsigned SaveTemporaryLabels : 1;
unsigned GenDwarfForAssembly : 1;
- unsigned CompressDebugSections : 1;
unsigned RelaxELFRelocations : 1;
unsigned DwarfVersion;
std::string DwarfDebugFlags;
std::string DwarfDebugProducer;
std::string DebugCompilationDir;
+ llvm::DebugCompressionType CompressDebugSections =
+ llvm::DebugCompressionType::None;
std::string MainFileName;
/// @}
@@ -201,7 +202,22 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
// Any DebugInfoKind implies GenDwarfForAssembly.
Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
- Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections);
+
+ if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
+ OPT_compress_debug_sections_EQ)) {
+ if (A->getOption().getID() == OPT_compress_debug_sections) {
+ // TODO: be more clever about the compression type auto-detection
+ Opts.CompressDebugSections = llvm::DebugCompressionType::GNU;
+ } else {
+ Opts.CompressDebugSections =
+ llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
+ .Case("none", llvm::DebugCompressionType::None)
+ .Case("zlib", llvm::DebugCompressionType::Z)
+ .Case("zlib-gnu", llvm::DebugCompressionType::GNU)
+ .Default(llvm::DebugCompressionType::None);
+ }
+ }
+
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
@@ -212,13 +228,11 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Frontend Options
if (Args.hasArg(OPT_INPUT)) {
bool First = true;
- for (arg_iterator it = Args.filtered_begin(OPT_INPUT),
- ie = Args.filtered_end();
- it != ie; ++it, First = false) {
- const Arg *A = it;
- if (First)
+ for (const Arg *A : Args.filtered(OPT_INPUT)) {
+ if (First) {
Opts.InputFile = A->getValue();
- else {
+ First = false;
+ } else {
Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
Success = false;
}
@@ -316,8 +330,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
// Ensure MCAsmInfo initialization occurs before any use, otherwise sections
// may be created with a combination of default and explicit settings.
- if (Opts.CompressDebugSections)
- MAI->setCompressDebugSections(DebugCompressionType::DCT_ZlibGnu);
+ MAI->setCompressDebugSections(Opts.CompressDebugSections);
MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
@@ -508,12 +521,12 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// FIXME: Remove this, one day.
if (!Asm.LLVMArgs.empty()) {
unsigned NumArgs = Asm.LLVMArgs.size();
- const char **Args = new const char*[NumArgs + 2];
+ auto Args = llvm::make_unique<const char*[]>(NumArgs + 2);
Args[0] = "clang (LLVM option parsing)";
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Asm.LLVMArgs[i].c_str();
Args[NumArgs + 1] = nullptr;
- llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
}
// Execute the invocation, unless there were parsing errors.
diff --git a/contrib/llvm/tools/clang/tools/driver/driver.cpp b/contrib/llvm/tools/clang/tools/driver/driver.cpp
index 61613028..9f37c42 100644
--- a/contrib/llvm/tools/clang/tools/driver/driver.cpp
+++ b/contrib/llvm/tools/clang/tools/driver/driver.cpp
@@ -53,8 +53,15 @@ using namespace clang::driver;
using namespace llvm::opt;
std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
- if (!CanonicalPrefixes)
- return Argv0;
+ if (!CanonicalPrefixes) {
+ SmallString<128> ExecutablePath(Argv0);
+ // Do a PATH lookup if Argv0 isn't a valid path.
+ if (!llvm::sys::fs::exists(ExecutablePath))
+ if (llvm::ErrorOr<std::string> P =
+ llvm::sys::findProgramByName(ExecutablePath))
+ ExecutablePath = *P;
+ return ExecutablePath.str();
+ }
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
@@ -454,39 +461,41 @@ int main(int argc_, const char **argv_) {
SetBackdoorDriverOutputsFromEnvVars(TheDriver);
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
- int Res = 0;
- SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
- if (C.get())
+ int Res = 1;
+ if (C && !C->containsError()) {
+ SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
- // Force a crash to test the diagnostics.
- if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) {
- Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH";
+ // Force a crash to test the diagnostics.
+ if (TheDriver.GenReproducer) {
+ Diags.Report(diag::err_drv_force_crash)
+ << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
- // Pretend that every command failed.
- FailingCommands.clear();
- for (const auto &J : C->getJobs())
- if (const Command *C = dyn_cast<Command>(&J))
- FailingCommands.push_back(std::make_pair(-1, C));
- }
+ // Pretend that every command failed.
+ FailingCommands.clear();
+ for (const auto &J : C->getJobs())
+ if (const Command *C = dyn_cast<Command>(&J))
+ FailingCommands.push_back(std::make_pair(-1, C));
+ }
- for (const auto &P : FailingCommands) {
- int CommandRes = P.first;
- const Command *FailingCommand = P.second;
- if (!Res)
- Res = CommandRes;
-
- // If result status is < 0, then the driver command signalled an error.
- // If result status is 70, then the driver command reported a fatal error.
- // On Windows, abort will return an exit code of 3. In these cases,
- // generate additional diagnostic information if possible.
- bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
+ for (const auto &P : FailingCommands) {
+ int CommandRes = P.first;
+ const Command *FailingCommand = P.second;
+ if (!Res)
+ Res = CommandRes;
+
+ // If result status is < 0, then the driver command signalled an error.
+ // If result status is 70, then the driver command reported a fatal error.
+ // On Windows, abort will return an exit code of 3. In these cases,
+ // generate additional diagnostic information if possible.
+ bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
#ifdef LLVM_ON_WIN32
- DiagnoseCrash |= CommandRes == 3;
+ DiagnoseCrash |= CommandRes == 3;
#endif
- if (DiagnoseCrash) {
- TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
- break;
+ if (DiagnoseCrash) {
+ TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
+ break;
+ }
}
}
diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp
index 27ab34c..b6d2988 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -12,13 +12,15 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
@@ -90,13 +92,13 @@ GetFlattenedSpellings(const Record &Attr) {
static std::string ReadPCHRecord(StringRef type) {
return StringSwitch<std::string>(type)
- .EndsWith("Decl *", "GetLocalDeclAs<"
- + std::string(type, 0, type.size()-1) + ">(F, Record[Idx++])")
- .Case("TypeSourceInfo *", "GetTypeSourceInfo(F, Record, Idx)")
- .Case("Expr *", "ReadExpr(F)")
- .Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)")
- .Case("StringRef", "ReadString(Record, Idx)")
- .Default("Record[Idx++]");
+ .EndsWith("Decl *", "Record.GetLocalDeclAs<"
+ + std::string(type, 0, type.size()-1) + ">(Record.readInt())")
+ .Case("TypeSourceInfo *", "Record.getTypeSourceInfo()")
+ .Case("Expr *", "Record.readExpr()")
+ .Case("IdentifierInfo *", "Record.getIdentifierInfo()")
+ .Case("StringRef", "Record.readString()")
+ .Default("Record.readInt()");
}
// Get a type that is suitable for storing an object of the specified type.
@@ -310,7 +312,7 @@ namespace {
}
void writeDump(raw_ostream &OS) const override {
- if (type == "FunctionDecl *") {
+ if (type == "FunctionDecl *" || type == "NamedDecl *") {
OS << " OS << \" \";\n";
OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n";
} else if (type == "IdentifierInfo *") {
@@ -413,7 +415,7 @@ namespace {
void writePCHReadDecls(raw_ostream &OS) const override {
OS << " std::string " << getLowerName()
- << "= ReadString(Record, Idx);\n";
+ << "= Record.readString();\n";
}
void writePCHReadArgs(raw_ostream &OS) const override {
@@ -539,13 +541,13 @@ namespace {
}
void writePCHReadDecls(raw_ostream &OS) const override {
- OS << " bool is" << getLowerName() << "Expr = Record[Idx++];\n";
+ OS << " bool is" << getLowerName() << "Expr = Record.readInt();\n";
OS << " void *" << getLowerName() << "Ptr;\n";
OS << " if (is" << getLowerName() << "Expr)\n";
- OS << " " << getLowerName() << "Ptr = ReadExpr(F);\n";
+ OS << " " << getLowerName() << "Ptr = Record.readExpr();\n";
OS << " else\n";
OS << " " << getLowerName()
- << "Ptr = GetTypeSourceInfo(F, Record, Idx);\n";
+ << "Ptr = Record.getTypeSourceInfo();\n";
}
void writePCHWrite(raw_ostream &OS) const override {
@@ -658,7 +660,7 @@ namespace {
}
void writePCHReadDecls(raw_ostream &OS) const override {
- OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n";
+ OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n";
OS << " SmallVector<" << getType() << ", 4> "
<< getLowerName() << ";\n";
OS << " " << getLowerName() << ".reserve(" << getLowerName()
@@ -716,9 +718,9 @@ namespace {
};
// Unique the enums, but maintain the original declaration ordering.
- std::vector<std::string>
- uniqueEnumsInOrder(const std::vector<std::string> &enums) {
- std::vector<std::string> uniques;
+ std::vector<StringRef>
+ uniqueEnumsInOrder(const std::vector<StringRef> &enums) {
+ std::vector<StringRef> uniques;
SmallDenseSet<StringRef, 8> unique_set;
for (const auto &i : enums) {
if (unique_set.insert(i).second)
@@ -729,7 +731,8 @@ namespace {
class EnumArgument : public Argument {
std::string type;
- std::vector<std::string> values, enums, uniques;
+ std::vector<StringRef> values, enums, uniques;
+
public:
EnumArgument(const Record &Arg, StringRef Attr)
: Argument(Arg, Attr), type(Arg.getValueAsString("Type")),
@@ -783,7 +786,7 @@ namespace {
void writePCHReadDecls(raw_ostream &OS) const override {
OS << " " << getAttrName() << "Attr::" << type << " " << getLowerName()
<< "(static_cast<" << getAttrName() << "Attr::" << type
- << ">(Record[Idx++]));\n";
+ << ">(Record.readInt()));\n";
}
void writePCHReadArgs(raw_ostream &OS) const override {
@@ -848,7 +851,7 @@ namespace {
class VariadicEnumArgument: public VariadicArgument {
std::string type, QualifiedTypeName;
- std::vector<std::string> values, enums, uniques;
+ std::vector<StringRef> values, enums, uniques;
protected:
void writeValueImpl(raw_ostream &OS) const override {
@@ -906,14 +909,14 @@ namespace {
}
void writePCHReadDecls(raw_ostream &OS) const override {
- OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n";
+ OS << " unsigned " << getLowerName() << "Size = Record.readInt();\n";
OS << " SmallVector<" << QualifiedTypeName << ", 4> " << getLowerName()
<< ";\n";
OS << " " << getLowerName() << ".reserve(" << getLowerName()
<< "Size);\n";
OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n";
OS << " " << getLowerName() << ".push_back(" << "static_cast<"
- << QualifiedTypeName << ">(Record[Idx++]));\n";
+ << QualifiedTypeName << ">(Record.readInt()));\n";
}
void writePCHWrite(raw_ostream &OS) const override {
@@ -996,7 +999,7 @@ namespace {
void writePCHReadDecls(raw_ostream &OS) const override {
OS << " VersionTuple " << getLowerName()
- << "= ReadVersionTuple(Record, Idx);\n";
+ << "= Record.readVersionTuple();\n";
}
void writePCHReadArgs(raw_ostream &OS) const override {
@@ -1036,7 +1039,7 @@ namespace {
OS << " " << getType() << " tempInst" << getUpperName() << ";\n";
OS << " {\n";
OS << " EnterExpressionEvaluationContext "
- << "Unevaluated(S, Sema::Unevaluated);\n";
+ << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n";
OS << " ExprResult " << "Result = S.SubstExpr("
<< "A->get" << getUpperName() << "(), TemplateArgs);\n";
OS << " tempInst" << getUpperName() << " = "
@@ -1083,7 +1086,7 @@ namespace {
<< "[A->" << getLowerName() << "_size()];\n";
OS << " {\n";
OS << " EnterExpressionEvaluationContext "
- << "Unevaluated(S, Sema::Unevaluated);\n";
+ << "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n";
OS << " " << getType() << " *TI = tempInst" << getUpperName()
<< ";\n";
OS << " " << getType() << " *I = A->" << getLowerName()
@@ -1179,6 +1182,8 @@ createArgument(const Record &Arg, StringRef Attr,
Ptr = llvm::make_unique<ExprArgument>(Arg, Attr);
else if (ArgName == "FunctionArgument")
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *");
+ else if (ArgName == "NamedArgument")
+ Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "NamedDecl *");
else if (ArgName == "IdentifierArgument")
Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *");
else if (ArgName == "DefaultBoolArgument")
@@ -1522,6 +1527,409 @@ static void emitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS)
OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n";
}
+static bool hasGNUorCXX11Spelling(const Record &Attribute) {
+ std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute);
+ for (const auto &I : Spellings) {
+ if (I.variety() == "GNU" || I.variety() == "CXX11")
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+struct AttributeSubjectMatchRule {
+ const Record *MetaSubject;
+ const Record *Constraint;
+
+ AttributeSubjectMatchRule(const Record *MetaSubject, const Record *Constraint)
+ : MetaSubject(MetaSubject), Constraint(Constraint) {
+ assert(MetaSubject && "Missing subject");
+ }
+
+ bool isSubRule() const { return Constraint != nullptr; }
+
+ std::vector<Record *> getSubjects() const {
+ return (Constraint ? Constraint : MetaSubject)
+ ->getValueAsListOfDefs("Subjects");
+ }
+
+ std::vector<Record *> getLangOpts() const {
+ if (Constraint) {
+ // Lookup the options in the sub-rule first, in case the sub-rule
+ // overrides the rules options.
+ std::vector<Record *> Opts = Constraint->getValueAsListOfDefs("LangOpts");
+ if (!Opts.empty())
+ return Opts;
+ }
+ return MetaSubject->getValueAsListOfDefs("LangOpts");
+ }
+
+ // Abstract rules are used only for sub-rules
+ bool isAbstractRule() const { return getSubjects().empty(); }
+
+ std::string getName() const {
+ return (Constraint ? Constraint : MetaSubject)->getValueAsString("Name");
+ }
+
+ bool isNegatedSubRule() const {
+ assert(isSubRule() && "Not a sub-rule");
+ return Constraint->getValueAsBit("Negated");
+ }
+
+ std::string getSpelling() const {
+ std::string Result = MetaSubject->getValueAsString("Name");
+ if (isSubRule()) {
+ Result += '(';
+ if (isNegatedSubRule())
+ Result += "unless(";
+ Result += getName();
+ if (isNegatedSubRule())
+ Result += ')';
+ Result += ')';
+ }
+ return Result;
+ }
+
+ std::string getEnumValueName() const {
+ SmallString<128> Result;
+ Result += "SubjectMatchRule_";
+ Result += MetaSubject->getValueAsString("Name");
+ if (isSubRule()) {
+ Result += "_";
+ if (isNegatedSubRule())
+ Result += "not_";
+ Result += Constraint->getValueAsString("Name");
+ }
+ if (isAbstractRule())
+ Result += "_abstract";
+ return Result.str();
+ }
+
+ std::string getEnumValue() const { return "attr::" + getEnumValueName(); }
+
+ static const char *EnumName;
+};
+
+const char *AttributeSubjectMatchRule::EnumName = "attr::SubjectMatchRule";
+
+struct PragmaClangAttributeSupport {
+ std::vector<AttributeSubjectMatchRule> Rules;
+
+ class RuleOrAggregateRuleSet {
+ std::vector<AttributeSubjectMatchRule> Rules;
+ bool IsRule;
+ RuleOrAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules,
+ bool IsRule)
+ : Rules(Rules), IsRule(IsRule) {}
+
+ public:
+ bool isRule() const { return IsRule; }
+
+ const AttributeSubjectMatchRule &getRule() const {
+ assert(IsRule && "not a rule!");
+ return Rules[0];
+ }
+
+ ArrayRef<AttributeSubjectMatchRule> getAggregateRuleSet() const {
+ return Rules;
+ }
+
+ static RuleOrAggregateRuleSet
+ getRule(const AttributeSubjectMatchRule &Rule) {
+ return RuleOrAggregateRuleSet(Rule, /*IsRule=*/true);
+ }
+ static RuleOrAggregateRuleSet
+ getAggregateRuleSet(ArrayRef<AttributeSubjectMatchRule> Rules) {
+ return RuleOrAggregateRuleSet(Rules, /*IsRule=*/false);
+ }
+ };
+ llvm::DenseMap<const Record *, RuleOrAggregateRuleSet> SubjectsToRules;
+
+ PragmaClangAttributeSupport(RecordKeeper &Records);
+
+ bool isAttributedSupported(const Record &Attribute);
+
+ void emitMatchRuleList(raw_ostream &OS);
+
+ std::string generateStrictConformsTo(const Record &Attr, raw_ostream &OS);
+
+ void generateParsingHelpers(raw_ostream &OS);
+};
+
+} // end anonymous namespace
+
+static bool doesDeclDeriveFrom(const Record *D, const Record *Base) {
+ const Record *CurrentBase = D->getValueAsDef("Base");
+ if (!CurrentBase)
+ return false;
+ if (CurrentBase == Base)
+ return true;
+ return doesDeclDeriveFrom(CurrentBase, Base);
+}
+
+PragmaClangAttributeSupport::PragmaClangAttributeSupport(
+ RecordKeeper &Records) {
+ std::vector<Record *> MetaSubjects =
+ Records.getAllDerivedDefinitions("AttrSubjectMatcherRule");
+ auto MapFromSubjectsToRules = [this](const Record *SubjectContainer,
+ const Record *MetaSubject,
+ const Record *Constraint) {
+ Rules.emplace_back(MetaSubject, Constraint);
+ std::vector<Record *> ApplicableSubjects =
+ SubjectContainer->getValueAsListOfDefs("Subjects");
+ for (const auto *Subject : ApplicableSubjects) {
+ bool Inserted =
+ SubjectsToRules
+ .try_emplace(Subject, RuleOrAggregateRuleSet::getRule(
+ AttributeSubjectMatchRule(MetaSubject,
+ Constraint)))
+ .second;
+ if (!Inserted) {
+ PrintFatalError("Attribute subject match rules should not represent"
+ "same attribute subjects.");
+ }
+ }
+ };
+ for (const auto *MetaSubject : MetaSubjects) {
+ MapFromSubjectsToRules(MetaSubject, MetaSubject, /*Constraints=*/nullptr);
+ std::vector<Record *> Constraints =
+ MetaSubject->getValueAsListOfDefs("Constraints");
+ for (const auto *Constraint : Constraints)
+ MapFromSubjectsToRules(Constraint, MetaSubject, Constraint);
+ }
+
+ std::vector<Record *> Aggregates =
+ Records.getAllDerivedDefinitions("AttrSubjectMatcherAggregateRule");
+ std::vector<Record *> DeclNodes = Records.getAllDerivedDefinitions("DDecl");
+ for (const auto *Aggregate : Aggregates) {
+ Record *SubjectDecl = Aggregate->getValueAsDef("Subject");
+
+ // Gather sub-classes of the aggregate subject that act as attribute
+ // subject rules.
+ std::vector<AttributeSubjectMatchRule> Rules;
+ for (const auto *D : DeclNodes) {
+ if (doesDeclDeriveFrom(D, SubjectDecl)) {
+ auto It = SubjectsToRules.find(D);
+ if (It == SubjectsToRules.end())
+ continue;
+ if (!It->second.isRule() || It->second.getRule().isSubRule())
+ continue; // Assume that the rule will be included as well.
+ Rules.push_back(It->second.getRule());
+ }
+ }
+
+ bool Inserted =
+ SubjectsToRules
+ .try_emplace(SubjectDecl,
+ RuleOrAggregateRuleSet::getAggregateRuleSet(Rules))
+ .second;
+ if (!Inserted) {
+ PrintFatalError("Attribute subject match rules should not represent"
+ "same attribute subjects.");
+ }
+ }
+}
+
+static PragmaClangAttributeSupport &
+getPragmaAttributeSupport(RecordKeeper &Records) {
+ static PragmaClangAttributeSupport Instance(Records);
+ return Instance;
+}
+
+void PragmaClangAttributeSupport::emitMatchRuleList(raw_ostream &OS) {
+ OS << "#ifndef ATTR_MATCH_SUB_RULE\n";
+ OS << "#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, "
+ "IsNegated) "
+ << "ATTR_MATCH_RULE(Value, Spelling, IsAbstract)\n";
+ OS << "#endif\n";
+ for (const auto &Rule : Rules) {
+ OS << (Rule.isSubRule() ? "ATTR_MATCH_SUB_RULE" : "ATTR_MATCH_RULE") << '(';
+ OS << Rule.getEnumValueName() << ", \"" << Rule.getSpelling() << "\", "
+ << Rule.isAbstractRule();
+ if (Rule.isSubRule())
+ OS << ", "
+ << AttributeSubjectMatchRule(Rule.MetaSubject, nullptr).getEnumValue()
+ << ", " << Rule.isNegatedSubRule();
+ OS << ")\n";
+ }
+ OS << "#undef ATTR_MATCH_SUB_RULE\n";
+}
+
+bool PragmaClangAttributeSupport::isAttributedSupported(
+ const Record &Attribute) {
+ if (Attribute.getValueAsBit("ForcePragmaAttributeSupport"))
+ return true;
+ // Opt-out rules:
+ // FIXME: The documentation check should be moved before
+ // the ForcePragmaAttributeSupport check after annotate is documented.
+ // No documentation present.
+ if (Attribute.isValueUnset("Documentation"))
+ return false;
+ std::vector<Record *> Docs = Attribute.getValueAsListOfDefs("Documentation");
+ if (Docs.empty())
+ return false;
+ if (Docs.size() == 1 && Docs[0]->getName() == "Undocumented")
+ return false;
+ // An attribute requires delayed parsing (LateParsed is on)
+ if (Attribute.getValueAsBit("LateParsed"))
+ return false;
+ // An attribute has no GNU/CXX11 spelling
+ if (!hasGNUorCXX11Spelling(Attribute))
+ return false;
+ // An attribute subject list has a subject that isn't covered by one of the
+ // subject match rules or has no subjects at all.
+ if (Attribute.isValueUnset("Subjects"))
+ return false;
+ const Record *SubjectObj = Attribute.getValueAsDef("Subjects");
+ std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
+ if (Subjects.empty())
+ return false;
+ for (const auto *Subject : Subjects) {
+ if (SubjectsToRules.find(Subject) == SubjectsToRules.end())
+ return false;
+ }
+ return true;
+}
+
+std::string
+PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr,
+ raw_ostream &OS) {
+ if (!isAttributedSupported(Attr))
+ return "nullptr";
+ // Generate a function that constructs a set of matching rules that describe
+ // to which declarations the attribute should apply to.
+ std::string FnName = "matchRulesFor" + Attr.getName().str();
+ std::stringstream SS;
+ SS << "static void " << FnName << "(llvm::SmallVectorImpl<std::pair<"
+ << AttributeSubjectMatchRule::EnumName
+ << ", bool>> &MatchRules, const LangOptions &LangOpts) {\n";
+ if (Attr.isValueUnset("Subjects")) {
+ SS << "}\n\n";
+ OS << SS.str();
+ return FnName;
+ }
+ const Record *SubjectObj = Attr.getValueAsDef("Subjects");
+ std::vector<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
+ for (const auto *Subject : Subjects) {
+ auto It = SubjectsToRules.find(Subject);
+ assert(It != SubjectsToRules.end() &&
+ "This attribute is unsupported by #pragma clang attribute");
+ for (const auto &Rule : It->getSecond().getAggregateRuleSet()) {
+ // The rule might be language specific, so only subtract it from the given
+ // rules if the specific language options are specified.
+ std::vector<Record *> LangOpts = Rule.getLangOpts();
+ SS << " MatchRules.push_back(std::make_pair(" << Rule.getEnumValue()
+ << ", /*IsSupported=*/";
+ if (!LangOpts.empty()) {
+ for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
+ std::string Part = (*I)->getValueAsString("Name");
+ if ((*I)->getValueAsBit("Negated"))
+ SS << "!";
+ SS << "LangOpts." + Part;
+ if (I + 1 != E)
+ SS << " || ";
+ }
+ } else
+ SS << "true";
+ SS << "));\n";
+ }
+ }
+ SS << "}\n\n";
+ OS << SS.str();
+ return FnName;
+}
+
+void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) {
+ // Generate routines that check the names of sub-rules.
+ OS << "Optional<attr::SubjectMatchRule> "
+ "defaultIsAttributeSubjectMatchSubRuleFor(StringRef, bool) {\n";
+ OS << " return None;\n";
+ OS << "}\n\n";
+
+ std::map<const Record *, std::vector<AttributeSubjectMatchRule>>
+ SubMatchRules;
+ for (const auto &Rule : Rules) {
+ if (!Rule.isSubRule())
+ continue;
+ SubMatchRules[Rule.MetaSubject].push_back(Rule);
+ }
+
+ for (const auto &SubMatchRule : SubMatchRules) {
+ OS << "Optional<attr::SubjectMatchRule> isAttributeSubjectMatchSubRuleFor_"
+ << SubMatchRule.first->getValueAsString("Name")
+ << "(StringRef Name, bool IsUnless) {\n";
+ OS << " if (IsUnless)\n";
+ OS << " return "
+ "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n";
+ for (const auto &Rule : SubMatchRule.second) {
+ if (Rule.isNegatedSubRule())
+ OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue()
+ << ").\n";
+ }
+ OS << " Default(None);\n";
+ OS << " return "
+ "llvm::StringSwitch<Optional<attr::SubjectMatchRule>>(Name).\n";
+ for (const auto &Rule : SubMatchRule.second) {
+ if (!Rule.isNegatedSubRule())
+ OS << " Case(\"" << Rule.getName() << "\", " << Rule.getEnumValue()
+ << ").\n";
+ }
+ OS << " Default(None);\n";
+ OS << "}\n\n";
+ }
+
+ // Generate the function that checks for the top-level rules.
+ OS << "std::pair<Optional<attr::SubjectMatchRule>, "
+ "Optional<attr::SubjectMatchRule> (*)(StringRef, "
+ "bool)> isAttributeSubjectMatchRule(StringRef Name) {\n";
+ OS << " return "
+ "llvm::StringSwitch<std::pair<Optional<attr::SubjectMatchRule>, "
+ "Optional<attr::SubjectMatchRule> (*) (StringRef, "
+ "bool)>>(Name).\n";
+ for (const auto &Rule : Rules) {
+ if (Rule.isSubRule())
+ continue;
+ std::string SubRuleFunction;
+ if (SubMatchRules.count(Rule.MetaSubject))
+ SubRuleFunction = "isAttributeSubjectMatchSubRuleFor_" + Rule.getName();
+ else
+ SubRuleFunction = "defaultIsAttributeSubjectMatchSubRuleFor";
+ OS << " Case(\"" << Rule.getName() << "\", std::make_pair("
+ << Rule.getEnumValue() << ", " << SubRuleFunction << ")).\n";
+ }
+ OS << " Default(std::make_pair(None, "
+ "defaultIsAttributeSubjectMatchSubRuleFor));\n";
+ OS << "}\n\n";
+
+ // Generate the function that checks for the submatch rules.
+ OS << "const char *validAttributeSubjectMatchSubRules("
+ << AttributeSubjectMatchRule::EnumName << " Rule) {\n";
+ OS << " switch (Rule) {\n";
+ for (const auto &SubMatchRule : SubMatchRules) {
+ OS << " case "
+ << AttributeSubjectMatchRule(SubMatchRule.first, nullptr).getEnumValue()
+ << ":\n";
+ OS << " return \"'";
+ bool IsFirst = true;
+ for (const auto &Rule : SubMatchRule.second) {
+ if (!IsFirst)
+ OS << ", '";
+ IsFirst = false;
+ if (Rule.isNegatedSubRule())
+ OS << "unless(";
+ OS << Rule.getName();
+ if (Rule.isNegatedSubRule())
+ OS << ')';
+ OS << "'";
+ }
+ OS << "\";\n";
+ }
+ OS << " default: return nullptr;\n";
+ OS << " }\n";
+ OS << "}\n\n";
+}
+
template <typename Fn>
static void forEachUniqueSpelling(const Record &Attr, Fn &&F) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
@@ -2109,6 +2517,17 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
OS << "#undef PRAGMA_SPELLING_ATTR\n";
}
+// Emits the enumeration list for attributes.
+void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader(
+ "List of all attribute subject matching rules that Clang recognizes", OS);
+ PragmaClangAttributeSupport &PragmaAttributeSupport =
+ getPragmaAttributeSupport(Records);
+ emitDefaultDefine(OS, "ATTR_MATCH_RULE", nullptr);
+ PragmaAttributeSupport.emitMatchRuleList(OS);
+ OS << "#undef ATTR_MATCH_RULE\n";
+}
+
// Emits the code to read an attribute from a precompiled header.
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Attribute deserialization code", OS);
@@ -2126,9 +2545,9 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
OS << " case attr::" << R.getName() << ": {\n";
if (R.isSubClassOf(InhClass))
- OS << " bool isInherited = Record[Idx++];\n";
- OS << " bool isImplicit = Record[Idx++];\n";
- OS << " unsigned Spelling = Record[Idx++];\n";
+ OS << " bool isInherited = Record.readInt();\n";
+ OS << " bool isImplicit = Record.readInt();\n";
+ OS << " unsigned Spelling = Record.readInt();\n";
ArgRecords = R.getValueAsListOfDefs("Args");
Args.clear();
for (const auto *Arg : ArgRecords) {
@@ -2186,7 +2605,7 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
// append a unique suffix to distinguish this set of target checks from other
// TargetSpecificAttr records.
static void GenerateTargetSpecificAttrChecks(const Record *R,
- std::vector<std::string> &Arches,
+ std::vector<StringRef> &Arches,
std::string &Test,
std::string *FnName) {
// It is assumed that there will be an llvm::Triple object
@@ -2196,8 +2615,9 @@ static void GenerateTargetSpecificAttrChecks(const Record *R,
Test += "(";
for (auto I = Arches.begin(), E = Arches.end(); I != E; ++I) {
- std::string Part = *I;
- Test += "T.getArch() == llvm::Triple::" + Part;
+ StringRef Part = *I;
+ Test += "T.getArch() == llvm::Triple::";
+ Test += Part;
if (I + 1 != E)
Test += " || ";
if (FnName)
@@ -2210,11 +2630,12 @@ static void GenerateTargetSpecificAttrChecks(const Record *R,
// We know that there was at least one arch test, so we need to and in the
// OS tests.
Test += " && (";
- std::vector<std::string> OSes = R->getValueAsListOfStrings("OSes");
+ std::vector<StringRef> OSes = R->getValueAsListOfStrings("OSes");
for (auto I = OSes.begin(), E = OSes.end(); I != E; ++I) {
- std::string Part = *I;
+ StringRef Part = *I;
- Test += "T.getOS() == llvm::Triple::" + Part;
+ Test += "T.getOS() == llvm::Triple::";
+ Test += Part;
if (I + 1 != E)
Test += " || ";
if (FnName)
@@ -2226,10 +2647,11 @@ static void GenerateTargetSpecificAttrChecks(const Record *R,
// If one or more CXX ABIs are specified, check those as well.
if (!R->isValueUnset("CXXABIs")) {
Test += " && (";
- std::vector<std::string> CXXABIs = R->getValueAsListOfStrings("CXXABIs");
+ std::vector<StringRef> CXXABIs = R->getValueAsListOfStrings("CXXABIs");
for (auto I = CXXABIs.begin(), E = CXXABIs.end(); I != E; ++I) {
- std::string Part = *I;
- Test += "Target.getCXXABI().getKind() == TargetCXXABI::" + Part;
+ StringRef Part = *I;
+ Test += "Target.getCXXABI().getKind() == TargetCXXABI::";
+ Test += Part;
if (I + 1 != E)
Test += " || ";
if (FnName)
@@ -2267,7 +2689,7 @@ static void GenerateHasAttrSpellingStringSwitch(
std::string Test;
if (Attr->isSubClassOf("TargetSpecificAttr")) {
const Record *R = Attr->getValueAsDef("Target");
- std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches");
+ std::vector<StringRef> Arches = R->getValueAsListOfStrings("Arches");
GenerateTargetSpecificAttrChecks(R, Arches, Test, nullptr);
// If this is the C++11 variety, also add in the LangOpts test.
@@ -2451,26 +2873,19 @@ void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) {
OS << "#endif // ATTR_VISITOR_DECLS_ONLY\n";
}
-// Emits code to instantiate dependent attributes on templates.
-void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
- emitSourceFileHeader("Template instantiation code for attributes", OS);
-
- std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
-
- OS << "namespace clang {\n"
- << "namespace sema {\n\n"
- << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
- << "Sema &S,\n"
- << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"
- << " switch (At->getKind()) {\n";
+void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs,
+ raw_ostream &OS,
+ bool AppliesToDecl) {
+ OS << " switch (At->getKind()) {\n";
for (const auto *Attr : Attrs) {
const Record &R = *Attr;
if (!R.getValueAsBit("ASTNode"))
continue;
-
OS << " case attr::" << R.getName() << ": {\n";
- bool ShouldClone = R.getValueAsBit("Clone");
+ bool ShouldClone = R.getValueAsBit("Clone") &&
+ (!AppliesToDecl ||
+ R.getValueAsBit("MeaningfulToClassTemplateDefinition"));
if (!ShouldClone) {
OS << " return nullptr;\n";
@@ -2507,8 +2922,27 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
}
OS << " } // end switch\n"
<< " llvm_unreachable(\"Unknown attribute!\");\n"
- << " return nullptr;\n"
- << "}\n\n"
+ << " return nullptr;\n";
+}
+
+// Emits code to instantiate dependent attributes on templates.
+void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Template instantiation code for attributes", OS);
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+
+ OS << "namespace clang {\n"
+ << "namespace sema {\n\n"
+ << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
+ << "Sema &S,\n"
+ << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
+ EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/false);
+ OS << "}\n\n"
+ << "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n"
+ << " ASTContext &C, Sema &S,\n"
+ << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
+ EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/true);
+ OS << "}\n\n"
<< "} // end namespace sema\n"
<< "} // end namespace clang\n";
}
@@ -2584,7 +3018,8 @@ static std::string CalculateDiagnostic(const Record &S) {
Field = 1U << 12,
CXXMethod = 1U << 13,
ObjCProtocol = 1U << 14,
- Enum = 1U << 15
+ Enum = 1U << 15,
+ Named = 1U << 16,
};
uint32_t SubMask = 0;
@@ -2619,6 +3054,7 @@ static std::string CalculateDiagnostic(const Record &S) {
.Case("Field", Field)
.Case("CXXMethod", CXXMethod)
.Case("Enum", Enum)
+ .Case("Named", Named)
.Default(0);
if (!V) {
// Something wasn't in our mapping, so be helpful and let the developer
@@ -2674,9 +3110,14 @@ static std::string CalculateDiagnostic(const Record &S) {
" : ExpectedVariableOrFunction))";
case ObjCMethod | ObjCProp: return "ExpectedMethodOrProperty";
+ case Func | ObjCMethod | ObjCProp:
+ return "ExpectedFunctionOrMethodOrProperty";
case ObjCProtocol | ObjCInterface:
return "ExpectedObjectiveCInterfaceOrProtocol";
case Field | Var: return "ExpectedFieldOrGlobalVar";
+
+ case Named:
+ return "ExpectedNamedDecl";
}
PrintFatalError(S.getLoc(),
@@ -2692,9 +3133,13 @@ static std::string GetSubjectWithSuffix(const Record *R) {
return B + "Decl";
}
+static std::string functionNameForCustomAppertainsTo(const Record &Subject) {
+ return "is" + Subject.getName().str();
+}
+
static std::string GenerateCustomAppertainsTo(const Record &Subject,
raw_ostream &OS) {
- std::string FnName = "is" + Subject.getName().str();
+ std::string FnName = functionNameForCustomAppertainsTo(Subject);
// If this code has already been generated, simply return the previous
// instance of it.
@@ -2779,6 +3224,42 @@ static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
return FnName;
}
+static void
+emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport,
+ raw_ostream &OS) {
+ OS << "static bool checkAttributeMatchRuleAppliesTo(const Decl *D, "
+ << AttributeSubjectMatchRule::EnumName << " rule) {\n";
+ OS << " switch (rule) {\n";
+ for (const auto &Rule : PragmaAttributeSupport.Rules) {
+ if (Rule.isAbstractRule()) {
+ OS << " case " << Rule.getEnumValue() << ":\n";
+ OS << " assert(false && \"Abstract matcher rule isn't allowed\");\n";
+ OS << " return false;\n";
+ continue;
+ }
+ std::vector<Record *> Subjects = Rule.getSubjects();
+ assert(!Subjects.empty() && "Missing subjects");
+ OS << " case " << Rule.getEnumValue() << ":\n";
+ OS << " return ";
+ for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) {
+ // If the subject has custom code associated with it, use the function
+ // that was generated for GenerateAppertainsTo to check if the declaration
+ // is valid.
+ if ((*I)->isSubClassOf("SubsetSubject"))
+ OS << functionNameForCustomAppertainsTo(**I) << "(D)";
+ else
+ OS << "isa<" << GetSubjectWithSuffix(*I) << ">(D)";
+
+ if (I + 1 != E)
+ OS << " || ";
+ }
+ OS << ";\n";
+ }
+ OS << " }\n";
+ OS << " llvm_unreachable(\"Invalid match rule\");\nreturn false;\n";
+ OS << "}\n\n";
+}
+
static void GenerateDefaultLangOptRequirements(raw_ostream &OS) {
OS << "static bool defaultDiagnoseLangOpts(Sema &, ";
OS << "const AttributeList &) {\n";
@@ -2847,7 +3328,7 @@ static std::string GenerateTargetRequirements(const Record &Attr,
// Get the list of architectures to be tested for.
const Record *R = Attr.getValueAsDef("Target");
- std::vector<std::string> Arches = R->getValueAsListOfStrings("Arches");
+ std::vector<StringRef> Arches = R->getValueAsListOfStrings("Arches");
if (Arches.empty()) {
PrintError(Attr.getLoc(), "Empty list of target architectures for a "
"target-specific attr");
@@ -2864,9 +3345,10 @@ static std::string GenerateTargetRequirements(const Record &Attr,
std::string APK = Attr.getValueAsString("ParseKind");
for (const auto &I : Dupes) {
if (I.first == APK) {
- std::vector<std::string> DA = I.second->getValueAsDef("Target")
- ->getValueAsListOfStrings("Arches");
- std::move(DA.begin(), DA.end(), std::back_inserter(Arches));
+ std::vector<StringRef> DA =
+ I.second->getValueAsDef("Target")->getValueAsListOfStrings(
+ "Arches");
+ Arches.insert(Arches.end(), DA.begin(), DA.end());
}
}
}
@@ -2937,6 +3419,9 @@ static bool IsKnownToGCC(const Record &Attr) {
void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Parsed attribute helpers", OS);
+ PragmaClangAttributeSupport &PragmaAttributeSupport =
+ getPragmaAttributeSupport(Records);
+
// Get the list of parsed attributes, and accept the optional list of
// duplicates due to the ParseKind.
ParsedAttrMap Dupes;
@@ -2970,10 +3455,13 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
SS << ", " << I->second->isSubClassOf("TypeAttr");
SS << ", " << I->second->isSubClassOf("StmtAttr");
SS << ", " << IsKnownToGCC(*I->second);
+ SS << ", " << PragmaAttributeSupport.isAttributedSupported(*I->second);
SS << ", " << GenerateAppertainsTo(*I->second, OS);
SS << ", " << GenerateLangOptRequirements(*I->second, OS);
SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS);
SS << ", " << GenerateSpellingIndexToSemanticSpelling(*I->second, OS);
+ SS << ", "
+ << PragmaAttributeSupport.generateStrictConformsTo(*I->second, OS);
SS << " }";
if (I + 1 != E)
@@ -2985,6 +3473,9 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n";
OS << SS.str();
OS << "};\n\n";
+
+ // Generate the attribute match rules.
+ emitAttributeMatchRules(PragmaAttributeSupport, OS);
}
// Emits the kind list of parsed attributes
@@ -3124,6 +3615,11 @@ void EmitClangAttrParserStringSwitches(RecordKeeper &Records,
emitClangAttrLateParsedList(Records, OS);
}
+void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
+ raw_ostream &OS) {
+ getPragmaAttributeSupport(Records).generateParsingHelpers(OS);
+}
+
class DocumentationData {
public:
const Record *Documentation;
@@ -3155,8 +3651,8 @@ enum SpellingKind {
Pragma = 1 << 5
};
-static void WriteDocumentation(const DocumentationData &Doc,
- raw_ostream &OS) {
+static void WriteDocumentation(RecordKeeper &Records,
+ const DocumentationData &Doc, raw_ostream &OS) {
// FIXME: there is no way to have a per-spelling category for the attribute
// documentation. This may not be a limiting factor since the spellings
// should generally be consistently applied across the category.
@@ -3238,7 +3734,7 @@ static void WriteDocumentation(const DocumentationData &Doc,
// List what spelling syntaxes the attribute supports.
OS << ".. csv-table:: Supported Syntaxes\n";
OS << " :header: \"GNU\", \"C++11\", \"__declspec\", \"Keyword\",";
- OS << " \"Pragma\"\n\n";
+ OS << " \"Pragma\", \"Pragma clang attribute\"\n\n";
OS << " \"";
if (SupportedSpellings & GNU) OS << "X";
OS << "\",\"";
@@ -3249,6 +3745,9 @@ static void WriteDocumentation(const DocumentationData &Doc,
if (SupportedSpellings & Keyword) OS << "X";
OS << "\", \"";
if (SupportedSpellings & Pragma) OS << "X";
+ OS << "\", \"";
+ if (getPragmaAttributeSupport(Records).isAttributedSupported(*Doc.Attribute))
+ OS << "X";
OS << "\"\n\n";
// If the attribute is deprecated, print a message about it, and possibly
@@ -3315,7 +3814,50 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) {
// Walk over each of the attributes in the category and write out their
// documentation.
for (const auto &Doc : I.second)
- WriteDocumentation(Doc, OS);
+ WriteDocumentation(Records, Doc, OS);
+ }
+}
+
+void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records,
+ raw_ostream &OS) {
+ PragmaClangAttributeSupport Support = getPragmaAttributeSupport(Records);
+ ParsedAttrMap Attrs = getParsedAttrList(Records);
+ unsigned NumAttrs = 0;
+ for (const auto &I : Attrs) {
+ if (Support.isAttributedSupported(*I.second))
+ ++NumAttrs;
+ }
+ OS << "#pragma clang attribute supports " << NumAttrs << " attributes:\n";
+ for (const auto &I : Attrs) {
+ if (!Support.isAttributedSupported(*I.second))
+ continue;
+ OS << I.first;
+ if (I.second->isValueUnset("Subjects")) {
+ OS << " ()\n";
+ continue;
+ }
+ const Record *SubjectObj = I.second->getValueAsDef("Subjects");
+ std::vector<Record *> Subjects =
+ SubjectObj->getValueAsListOfDefs("Subjects");
+ OS << " (";
+ for (const auto &Subject : llvm::enumerate(Subjects)) {
+ if (Subject.index())
+ OS << ", ";
+ PragmaClangAttributeSupport::RuleOrAggregateRuleSet &RuleSet =
+ Support.SubjectsToRules.find(Subject.value())->getSecond();
+ if (RuleSet.isRule()) {
+ OS << RuleSet.getRule().getEnumValueName();
+ continue;
+ }
+ OS << "(";
+ for (const auto &Rule : llvm::enumerate(RuleSet.getAggregateRuleSet())) {
+ if (Rule.index())
+ OS << ", ";
+ OS << Rule.value().getEnumValueName();
+ }
+ OS << ")";
+ }
+ OS << ")\n";
}
}
diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
index cad08af..d9d99e0 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -1277,8 +1277,8 @@ void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
bool IsSynonym = GroupInfo.DiagsInGroup.empty() &&
GroupInfo.SubGroups.size() == 1;
- writeHeader((IsRemarkGroup ? "-R" : "-W") +
- G->getValueAsString("GroupName"),
+ writeHeader(((IsRemarkGroup ? "-R" : "-W") +
+ G->getValueAsString("GroupName")).str(),
OS);
if (!IsSynonym) {
diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangOptionDocEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangOptionDocEmitter.cpp
new file mode 100644
index 0000000..5931451
--- /dev/null
+++ b/contrib/llvm/tools/clang/utils/TableGen/ClangOptionDocEmitter.cpp
@@ -0,0 +1,392 @@
+//===- ClangOptionDocEmitter.cpp - Documentation for command line flags ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// FIXME: Once this has stabilized, consider moving it to LLVM.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TableGen/Error.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <cctype>
+#include <cstring>
+#include <map>
+
+using namespace llvm;
+
+namespace clang {
+namespace docs {
+namespace {
+struct DocumentedOption {
+ Record *Option;
+ std::vector<Record*> Aliases;
+};
+struct DocumentedGroup;
+struct Documentation {
+ std::vector<DocumentedGroup> Groups;
+ std::vector<DocumentedOption> Options;
+};
+struct DocumentedGroup : Documentation {
+ Record *Group;
+};
+
+// Reorganize the records into a suitable form for emitting documentation.
+Documentation extractDocumentation(RecordKeeper &Records) {
+ Documentation Result;
+
+ // Build the tree of groups. The root in the tree is the fake option group
+ // (Record*)nullptr, which contains all top-level groups and options.
+ std::map<Record*, std::vector<Record*> > OptionsInGroup;
+ std::map<Record*, std::vector<Record*> > GroupsInGroup;
+ std::map<Record*, std::vector<Record*> > Aliases;
+
+ std::map<std::string, Record*> OptionsByName;
+ for (Record *R : Records.getAllDerivedDefinitions("Option"))
+ OptionsByName[R->getValueAsString("Name")] = R;
+
+ auto Flatten = [](Record *R) {
+ return R->getValue("DocFlatten") && R->getValueAsBit("DocFlatten");
+ };
+
+ auto SkipFlattened = [&](Record *R) -> Record* {
+ while (R && Flatten(R)) {
+ auto *G = dyn_cast<DefInit>(R->getValueInit("Group"));
+ if (!G)
+ return nullptr;
+ R = G->getDef();
+ }
+ return R;
+ };
+
+ for (Record *R : Records.getAllDerivedDefinitions("OptionGroup")) {
+ if (Flatten(R))
+ continue;
+
+ Record *Group = nullptr;
+ if (auto *G = dyn_cast<DefInit>(R->getValueInit("Group")))
+ Group = SkipFlattened(G->getDef());
+ GroupsInGroup[Group].push_back(R);
+ }
+
+ for (Record *R : Records.getAllDerivedDefinitions("Option")) {
+ if (auto *A = dyn_cast<DefInit>(R->getValueInit("Alias"))) {
+ Aliases[A->getDef()].push_back(R);
+ continue;
+ }
+
+ // Pretend no-X and Xno-Y options are aliases of X and XY.
+ std::string Name = R->getValueAsString("Name");
+ if (Name.size() >= 4) {
+ if (Name.substr(0, 3) == "no-" && OptionsByName[Name.substr(3)]) {
+ Aliases[OptionsByName[Name.substr(3)]].push_back(R);
+ continue;
+ }
+ if (Name.substr(1, 3) == "no-" && OptionsByName[Name[0] + Name.substr(4)]) {
+ Aliases[OptionsByName[Name[0] + Name.substr(4)]].push_back(R);
+ continue;
+ }
+ }
+
+ Record *Group = nullptr;
+ if (auto *G = dyn_cast<DefInit>(R->getValueInit("Group")))
+ Group = SkipFlattened(G->getDef());
+ OptionsInGroup[Group].push_back(R);
+ }
+
+ auto CompareByName = [](Record *A, Record *B) {
+ return A->getValueAsString("Name") < B->getValueAsString("Name");
+ };
+
+ auto CompareByLocation = [](Record *A, Record *B) {
+ return A->getLoc()[0].getPointer() < B->getLoc()[0].getPointer();
+ };
+
+ auto DocumentationForOption = [&](Record *R) -> DocumentedOption {
+ auto &A = Aliases[R];
+ std::sort(A.begin(), A.end(), CompareByName);
+ return {R, std::move(A)};
+ };
+
+ std::function<Documentation(Record *)> DocumentationForGroup =
+ [&](Record *R) -> Documentation {
+ Documentation D;
+
+ auto &Groups = GroupsInGroup[R];
+ std::sort(Groups.begin(), Groups.end(), CompareByLocation);
+ for (Record *G : Groups) {
+ D.Groups.emplace_back();
+ D.Groups.back().Group = G;
+ Documentation &Base = D.Groups.back();
+ Base = DocumentationForGroup(G);
+ }
+
+ auto &Options = OptionsInGroup[R];
+ std::sort(Options.begin(), Options.end(), CompareByName);
+ for (Record *O : Options)
+ D.Options.push_back(DocumentationForOption(O));
+
+ return D;
+ };
+
+ return DocumentationForGroup(nullptr);
+}
+
+// Get the first and successive separators to use for an OptionKind.
+std::pair<StringRef,StringRef> getSeparatorsForKind(const Record *OptionKind) {
+ return StringSwitch<std::pair<StringRef, StringRef>>(OptionKind->getName())
+ .Cases("KIND_JOINED", "KIND_JOINED_OR_SEPARATE",
+ "KIND_JOINED_AND_SEPARATE",
+ "KIND_REMAINING_ARGS_JOINED", {"", " "})
+ .Case("KIND_COMMAJOINED", {"", ","})
+ .Default({" ", " "});
+}
+
+const unsigned UnlimitedArgs = unsigned(-1);
+
+// Get the number of arguments expected for an option, or -1 if any number of
+// arguments are accepted.
+unsigned getNumArgsForKind(Record *OptionKind, const Record *Option) {
+ return StringSwitch<unsigned>(OptionKind->getName())
+ .Cases("KIND_JOINED", "KIND_JOINED_OR_SEPARATE", "KIND_SEPARATE", 1)
+ .Cases("KIND_REMAINING_ARGS", "KIND_REMAINING_ARGS_JOINED",
+ "KIND_COMMAJOINED", UnlimitedArgs)
+ .Case("KIND_JOINED_AND_SEPARATE", 2)
+ .Case("KIND_MULTIARG", Option->getValueAsInt("NumArgs"))
+ .Default(0);
+}
+
+bool hasFlag(const Record *OptionOrGroup, StringRef OptionFlag) {
+ for (const Record *Flag : OptionOrGroup->getValueAsListOfDefs("Flags"))
+ if (Flag->getName() == OptionFlag)
+ return true;
+ return false;
+}
+
+bool isExcluded(const Record *OptionOrGroup, const Record *DocInfo) {
+ // FIXME: Provide a flag to specify the set of exclusions.
+ for (StringRef Exclusion : DocInfo->getValueAsListOfStrings("ExcludedFlags"))
+ if (hasFlag(OptionOrGroup, Exclusion))
+ return true;
+ return false;
+}
+
+std::string escapeRST(StringRef Str) {
+ std::string Out;
+ for (auto K : Str) {
+ if (StringRef("`*|_[]\\").count(K))
+ Out.push_back('\\');
+ Out.push_back(K);
+ }
+ return Out;
+}
+
+StringRef getSphinxOptionID(StringRef OptionName) {
+ for (auto I = OptionName.begin(), E = OptionName.end(); I != E; ++I)
+ if (!isalnum(*I) && *I != '-')
+ return OptionName.substr(0, I - OptionName.begin());
+ return OptionName;
+}
+
+bool canSphinxCopeWithOption(const Record *Option) {
+ // HACK: Work arond sphinx's inability to cope with punctuation-only options
+ // such as /? by suppressing them from the option list.
+ for (char C : Option->getValueAsString("Name"))
+ if (isalnum(C))
+ return true;
+ return false;
+}
+
+void emitHeading(int Depth, std::string Heading, raw_ostream &OS) {
+ assert(Depth < 8 && "groups nested too deeply");
+ OS << Heading << '\n'
+ << std::string(Heading.size(), "=~-_'+<>"[Depth]) << "\n";
+}
+
+/// Get the value of field \p Primary, if possible. If \p Primary does not
+/// exist, get the value of \p Fallback and escape it for rST emission.
+std::string getRSTStringWithTextFallback(const Record *R, StringRef Primary,
+ StringRef Fallback) {
+ for (auto Field : {Primary, Fallback}) {
+ if (auto *V = R->getValue(Field)) {
+ StringRef Value;
+ if (auto *SV = dyn_cast_or_null<StringInit>(V->getValue()))
+ Value = SV->getValue();
+ else if (auto *CV = dyn_cast_or_null<CodeInit>(V->getValue()))
+ Value = CV->getValue();
+ if (!Value.empty())
+ return Field == Primary ? Value.str() : escapeRST(Value);
+ }
+ }
+ return StringRef();
+}
+
+void emitOptionWithArgs(StringRef Prefix, const Record *Option,
+ ArrayRef<StringRef> Args, raw_ostream &OS) {
+ OS << Prefix << escapeRST(Option->getValueAsString("Name"));
+
+ std::pair<StringRef, StringRef> Separators =
+ getSeparatorsForKind(Option->getValueAsDef("Kind"));
+
+ StringRef Separator = Separators.first;
+ for (auto Arg : Args) {
+ OS << Separator << escapeRST(Arg);
+ Separator = Separators.second;
+ }
+}
+
+void emitOptionName(StringRef Prefix, const Record *Option, raw_ostream &OS) {
+ // Find the arguments to list after the option.
+ unsigned NumArgs = getNumArgsForKind(Option->getValueAsDef("Kind"), Option);
+
+ std::vector<std::string> Args;
+ if (!Option->isValueUnset("MetaVarName"))
+ Args.push_back(Option->getValueAsString("MetaVarName"));
+ else if (NumArgs == 1)
+ Args.push_back("<arg>");
+
+ while (Args.size() < NumArgs) {
+ Args.push_back(("<arg" + Twine(Args.size() + 1) + ">").str());
+ // Use '--args <arg1> <arg2>...' if any number of args are allowed.
+ if (Args.size() == 2 && NumArgs == UnlimitedArgs) {
+ Args.back() += "...";
+ break;
+ }
+ }
+
+ emitOptionWithArgs(Prefix, Option, std::vector<StringRef>(Args.begin(), Args.end()), OS);
+
+ auto AliasArgs = Option->getValueAsListOfStrings("AliasArgs");
+ if (!AliasArgs.empty()) {
+ Record *Alias = Option->getValueAsDef("Alias");
+ OS << " (equivalent to ";
+ emitOptionWithArgs(
+ Alias->getValueAsListOfStrings("Prefixes").front(), Alias,
+ AliasArgs, OS);
+ OS << ")";
+ }
+}
+
+bool emitOptionNames(const Record *Option, raw_ostream &OS, bool EmittedAny) {
+ for (auto &Prefix : Option->getValueAsListOfStrings("Prefixes")) {
+ if (EmittedAny)
+ OS << ", ";
+ emitOptionName(Prefix, Option, OS);
+ EmittedAny = true;
+ }
+ return EmittedAny;
+}
+
+template <typename Fn>
+void forEachOptionName(const DocumentedOption &Option, const Record *DocInfo,
+ Fn F) {
+ F(Option.Option);
+
+ for (auto *Alias : Option.Aliases)
+ if (!isExcluded(Alias, DocInfo) && canSphinxCopeWithOption(Option.Option))
+ F(Alias);
+}
+
+void emitOption(const DocumentedOption &Option, const Record *DocInfo,
+ raw_ostream &OS) {
+ if (isExcluded(Option.Option, DocInfo))
+ return;
+ if (Option.Option->getValueAsDef("Kind")->getName() == "KIND_UNKNOWN" ||
+ Option.Option->getValueAsDef("Kind")->getName() == "KIND_INPUT")
+ return;
+ if (!canSphinxCopeWithOption(Option.Option))
+ return;
+
+ // HACK: Emit a different program name with each option to work around
+ // sphinx's inability to cope with options that differ only by punctuation
+ // (eg -ObjC vs -ObjC++, -G vs -G=).
+ std::vector<std::string> SphinxOptionIDs;
+ forEachOptionName(Option, DocInfo, [&](const Record *Option) {
+ for (auto &Prefix : Option->getValueAsListOfStrings("Prefixes"))
+ SphinxOptionIDs.push_back(
+ getSphinxOptionID((Prefix + Option->getValueAsString("Name")).str()));
+ });
+ assert(!SphinxOptionIDs.empty() && "no flags for option");
+ static std::map<std::string, int> NextSuffix;
+ int SphinxWorkaroundSuffix = NextSuffix[*std::max_element(
+ SphinxOptionIDs.begin(), SphinxOptionIDs.end(),
+ [&](const std::string &A, const std::string &B) {
+ return NextSuffix[A] < NextSuffix[B];
+ })];
+ for (auto &S : SphinxOptionIDs)
+ NextSuffix[S] = SphinxWorkaroundSuffix + 1;
+ if (SphinxWorkaroundSuffix)
+ OS << ".. program:: " << DocInfo->getValueAsString("Program")
+ << SphinxWorkaroundSuffix << "\n";
+
+ // Emit the names of the option.
+ OS << ".. option:: ";
+ bool EmittedAny = false;
+ forEachOptionName(Option, DocInfo, [&](const Record *Option) {
+ EmittedAny = emitOptionNames(Option, OS, EmittedAny);
+ });
+ if (SphinxWorkaroundSuffix)
+ OS << "\n.. program:: " << DocInfo->getValueAsString("Program");
+ OS << "\n\n";
+
+ // Emit the description, if we have one.
+ std::string Description =
+ getRSTStringWithTextFallback(Option.Option, "DocBrief", "HelpText");
+ if (!Description.empty())
+ OS << Description << "\n\n";
+}
+
+void emitDocumentation(int Depth, const Documentation &Doc,
+ const Record *DocInfo, raw_ostream &OS);
+
+void emitGroup(int Depth, const DocumentedGroup &Group, const Record *DocInfo,
+ raw_ostream &OS) {
+ if (isExcluded(Group.Group, DocInfo))
+ return;
+
+ emitHeading(Depth,
+ getRSTStringWithTextFallback(Group.Group, "DocName", "Name"), OS);
+
+ // Emit the description, if we have one.
+ std::string Description =
+ getRSTStringWithTextFallback(Group.Group, "DocBrief", "HelpText");
+ if (!Description.empty())
+ OS << Description << "\n\n";
+
+ // Emit contained options and groups.
+ emitDocumentation(Depth + 1, Group, DocInfo, OS);
+}
+
+void emitDocumentation(int Depth, const Documentation &Doc,
+ const Record *DocInfo, raw_ostream &OS) {
+ for (auto &O : Doc.Options)
+ emitOption(O, DocInfo, OS);
+ for (auto &G : Doc.Groups)
+ emitGroup(Depth, G, DocInfo, OS);
+}
+
+} // namespace
+} // namespace docs
+
+void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS) {
+ using namespace docs;
+
+ const Record *DocInfo = Records.getDef("GlobalDocumentation");
+ if (!DocInfo) {
+ PrintFatalError("The GlobalDocumentation top-level definition is missing, "
+ "no documentation will be generated.");
+ return;
+ }
+ OS << DocInfo->getValueAsString("Intro") << "\n";
+ OS << ".. program:: " << DocInfo->getValueAsString("Program") << "\n";
+
+ emitDocumentation(0, extractDocumentation(Records), DocInfo, OS);
+}
+} // end namespace clang
diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangSACheckersEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangSACheckersEmitter.cpp
index 115527a..8f3de0b 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/ClangSACheckersEmitter.cpp
+++ b/contrib/llvm/tools/clang/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -51,7 +51,8 @@ static std::string getParentPackageFullName(const Record *R) {
static std::string getPackageFullName(const Record *R) {
std::string name = getParentPackageFullName(R);
if (!name.empty()) name += ".";
- return name + R->getValueAsString("PackageName");
+ name += R->getValueAsString("PackageName");
+ return name;
}
static std::string getCheckerFullName(const Record *R) {
diff --git a/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp b/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp
index 6fb5b00..781518d 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp
+++ b/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp
@@ -25,8 +25,10 @@ using namespace clang;
enum ActionType {
GenClangAttrClasses,
GenClangAttrParserStringSwitches,
+ GenClangAttrSubjectMatchRulesParserStringSwitches,
GenClangAttrImpl,
GenClangAttrList,
+ GenClangAttrSubjectMatchRuleList,
GenClangAttrPCHRead,
GenClangAttrPCHWrite,
GenClangAttrHasAttributeImpl,
@@ -53,7 +55,9 @@ enum ActionType {
GenArmNeonSema,
GenArmNeonTest,
GenAttrDocs,
- GenDiagDocs
+ GenDiagDocs,
+ GenOptDocs,
+ GenTestPragmaAttributeSupportedAttributes
};
namespace {
@@ -65,10 +69,17 @@ cl::opt<ActionType> Action(
clEnumValN(GenClangAttrParserStringSwitches,
"gen-clang-attr-parser-string-switches",
"Generate all parser-related attribute string switches"),
+ clEnumValN(GenClangAttrSubjectMatchRulesParserStringSwitches,
+ "gen-clang-attr-subject-match-rules-parser-string-switches",
+ "Generate all parser-related attribute subject match rule"
+ "string switches"),
clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl",
"Generate clang attribute implementations"),
clEnumValN(GenClangAttrList, "gen-clang-attr-list",
"Generate a clang attribute list"),
+ clEnumValN(GenClangAttrSubjectMatchRuleList,
+ "gen-clang-attr-subject-match-rule-list",
+ "Generate a clang attribute subject match rule list"),
clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read",
"Generate clang PCH attribute reader"),
clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
@@ -79,8 +90,7 @@ cl::opt<ActionType> Action(
clEnumValN(GenClangAttrSpellingListIndex,
"gen-clang-attr-spelling-index",
"Generate a clang attribute spelling index"),
- clEnumValN(GenClangAttrASTVisitor,
- "gen-clang-attr-ast-visitor",
+ clEnumValN(GenClangAttrASTVisitor, "gen-clang-attr-ast-visitor",
"Generate a recursive AST visitor for clang attributes"),
clEnumValN(GenClangAttrTemplateInstantiate,
"gen-clang-attr-template-instantiate",
@@ -135,7 +145,12 @@ cl::opt<ActionType> Action(
clEnumValN(GenAttrDocs, "gen-attr-docs",
"Generate attribute documentation"),
clEnumValN(GenDiagDocs, "gen-diag-docs",
- "Generate attribute documentation")));
+ "Generate diagnostic documentation"),
+ clEnumValN(GenOptDocs, "gen-opt-docs", "Generate option documentation"),
+ clEnumValN(GenTestPragmaAttributeSupportedAttributes,
+ "gen-clang-test-pragma-attribute-supported-attributes",
+ "Generate a list of attributes supported by #pragma clang "
+ "attribute for testing purposes")));
cl::opt<std::string>
ClangComponent("clang-component",
@@ -150,12 +165,18 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrParserStringSwitches:
EmitClangAttrParserStringSwitches(Records, OS);
break;
+ case GenClangAttrSubjectMatchRulesParserStringSwitches:
+ EmitClangAttrSubjectMatchRulesParserStringSwitches(Records, OS);
+ break;
case GenClangAttrImpl:
EmitClangAttrImpl(Records, OS);
break;
case GenClangAttrList:
EmitClangAttrList(Records, OS);
break;
+ case GenClangAttrSubjectMatchRuleList:
+ EmitClangAttrSubjectMatchRuleList(Records, OS);
+ break;
case GenClangAttrPCHRead:
EmitClangAttrPCHRead(Records, OS);
break;
@@ -238,6 +259,12 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenDiagDocs:
EmitClangDiagDocs(Records, OS);
break;
+ case GenOptDocs:
+ EmitClangOptDocs(Records, OS);
+ break;
+ case GenTestPragmaAttributeSupportedAttributes:
+ EmitTestPragmaAttributeSupportedAttributes(Records, OS);
+ break;
}
return false;
diff --git a/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h b/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h
index 0305ed1..e1b7d0e 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h
+++ b/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h
@@ -33,9 +33,12 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
const std::string &N, const std::string &S);
void EmitClangAttrParserStringSwitches(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
+ raw_ostream &OS);
void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS);
@@ -70,6 +73,10 @@ void EmitNeonTest2(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS);
void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS);
+
+void EmitTestPragmaAttributeSupportedAttributes(RecordKeeper &Records,
+ raw_ostream &OS);
} // end namespace clang
diff --git a/contrib/llvm/tools/llc/llc.cpp b/contrib/llvm/tools/llc/llc.cpp
index a76d324..f13a192 100644
--- a/contrib/llvm/tools/llc/llc.cpp
+++ b/contrib/llvm/tools/llc/llc.cpp
@@ -62,6 +62,9 @@ static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
static cl::opt<std::string>
+InputLanguage("x", cl::desc("Input language ('ir' or 'mir')"));
+
+static cl::opt<std::string>
OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
static cl::opt<unsigned>
@@ -90,6 +93,11 @@ OptLevel("O",
static cl::opt<std::string>
TargetTriple("mtriple", cl::desc("Override target triple for module"));
+static cl::opt<std::string> SplitDwarfFile(
+ "split-dwarf-file",
+ cl::desc(
+ "Specify the name of the .dwo file to encode in the DWARF output"));
+
static cl::opt<bool> NoVerify("disable-verify", cl::Hidden,
cl::desc("Do not verify input module"));
@@ -136,6 +144,21 @@ static cl::opt<std::string> StartAfter("start-after",
static cl::list<std::string> IncludeDirs("I", cl::desc("include search path"));
+static cl::opt<bool> PassRemarksWithHotness(
+ "pass-remarks-with-hotness",
+ cl::desc("With PGO, include profile count in optimization remarks"),
+ cl::Hidden);
+
+static cl::opt<unsigned> PassRemarksHotnessThreshold(
+ "pass-remarks-hotness-threshold",
+ cl::desc("Minimum profile count required for an optimization remark to be output"),
+ cl::Hidden);
+
+static cl::opt<std::string>
+ RemarksFilename("pass-remarks-output",
+ cl::desc("YAML output filename for pass remarks"),
+ cl::value_desc("filename"));
+
namespace {
static ManagedStatic<std::vector<std::string>> RunPassNames;
@@ -233,12 +256,29 @@ static void DiagnosticHandler(const DiagnosticInfo &DI, void *Context) {
if (DI.getSeverity() == DS_Error)
*HasError = true;
+ if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI))
+ if (!Remark->isEnabled())
+ return;
+
DiagnosticPrinterRawOStream DP(errs());
errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
DI.print(DP);
errs() << "\n";
}
+static void InlineAsmDiagHandler(const SMDiagnostic &SMD, void *Context,
+ unsigned LocCookie) {
+ bool *HasError = static_cast<bool *>(Context);
+ if (SMD.getKind() == SourceMgr::DK_Error)
+ *HasError = true;
+
+ SMD.print(nullptr, errs());
+
+ // For testing purposes, we print the LocCookie here.
+ if (LocCookie)
+ errs() << "note: !srcloc = " << LocCookie << "\n";
+}
+
// main - Entry point for the llc compiler.
//
int main(int argc, char **argv) {
@@ -267,6 +307,13 @@ int main(int argc, char **argv) {
initializeCountingFunctionInserterPass(*Registry);
initializeUnreachableBlockElimLegacyPassPass(*Registry);
initializeConstantHoistingLegacyPassPass(*Registry);
+ initializeScalarOpts(*Registry);
+ initializeVectorization(*Registry);
+ initializeScalarizeMaskedMemIntrinPass(*Registry);
+ initializeExpandReductionsPass(*Registry);
+
+ // Initialize debugging passes.
+ initializeScavengerTestPass(*Registry);
// Register the target printer for --version.
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
@@ -278,12 +325,41 @@ int main(int argc, char **argv) {
// Set a diagnostic handler that doesn't exit on the first error
bool HasError = false;
Context.setDiagnosticHandler(DiagnosticHandler, &HasError);
+ Context.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, &HasError);
+
+ if (PassRemarksWithHotness)
+ Context.setDiagnosticsHotnessRequested(true);
+
+ if (PassRemarksHotnessThreshold)
+ Context.setDiagnosticsHotnessThreshold(PassRemarksHotnessThreshold);
+
+ std::unique_ptr<tool_output_file> YamlFile;
+ if (RemarksFilename != "") {
+ std::error_code EC;
+ YamlFile = llvm::make_unique<tool_output_file>(RemarksFilename, EC,
+ sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
+ return 1;
+ }
+ Context.setDiagnosticsOutputFile(
+ llvm::make_unique<yaml::Output>(YamlFile->os()));
+ }
+
+ if (InputLanguage != "" && InputLanguage != "ir" &&
+ InputLanguage != "mir") {
+ errs() << argv[0] << "Input language must be '', 'IR' or 'MIR'\n";
+ return 1;
+ }
// Compile the module TimeCompilations times to give better compile time
// metrics.
for (unsigned I = TimeCompilations; I; --I)
if (int RetVal = compileModule(argv, Context))
return RetVal;
+
+ if (YamlFile)
+ YamlFile->keep();
return 0;
}
@@ -300,9 +376,7 @@ static bool addPass(PassManagerBase &PM, const char *argv0,
}
Pass *P;
- if (PI->getTargetMachineCtor())
- P = PI->getTargetMachineCtor()(&TPC.getTM<TargetMachine>());
- else if (PI->getNormalCtor())
+ if (PI->getNormalCtor())
P = PI->getNormalCtor()();
else {
errs() << argv0 << ": cannot create pass: " << PI->getPassName() << "\n";
@@ -341,10 +415,11 @@ static int compileModule(char **argv, LLVMContext &Context) {
// If user just wants to list available options, skip module loading
if (!SkipModule) {
- if (StringRef(InputFilename).endswith_lower(".mir")) {
+ if (InputLanguage == "mir" ||
+ (InputLanguage == "" && StringRef(InputFilename).endswith(".mir"))) {
MIR = createMIRParserFromFile(InputFilename, Err, Context);
if (MIR)
- M = MIR->parseLLVMModule();
+ M = MIR->parseIRModule();
} else
M = parseIRFile(InputFilename, Err, Context);
if (!M) {
@@ -401,6 +476,7 @@ static int compileModule(char **argv, LLVMContext &Context) {
Options.MCOptions.AsmVerbose = AsmVerbose;
Options.MCOptions.PreserveAsmComments = PreserveComments;
Options.MCOptions.IASSearchPaths = IncludeDirs;
+ Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
std::unique_ptr<TargetMachine> Target(
TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, FeaturesStr,
@@ -460,54 +536,67 @@ static int compileModule(char **argv, LLVMContext &Context) {
OS = BOS.get();
}
- if (!RunPassNames->empty()) {
- if (!StartAfter.empty() || !StopAfter.empty() || !StartBefore.empty() ||
- !StopBefore.empty()) {
- errs() << argv[0] << ": start-after and/or stop-after passes are "
- "redundant when run-pass is specified.\n";
- return 1;
- }
- if (!MIR) {
- errs() << argv[0] << ": run-pass needs a .mir input.\n";
- return 1;
- }
+ const char *argv0 = argv[0];
+ AnalysisID StartBeforeID = getPassID(argv0, "start-before", StartBefore);
+ AnalysisID StartAfterID = getPassID(argv0, "start-after", StartAfter);
+ AnalysisID StopAfterID = getPassID(argv0, "stop-after", StopAfter);
+ AnalysisID StopBeforeID = getPassID(argv0, "stop-before", StopBefore);
+ if (StartBeforeID && StartAfterID) {
+ errs() << argv0 << ": -start-before and -start-after specified!\n";
+ return 1;
+ }
+ if (StopBeforeID && StopAfterID) {
+ errs() << argv0 << ": -stop-before and -stop-after specified!\n";
+ return 1;
+ }
+
+ if (MIR) {
+ // Construct a custom pass pipeline that starts after instruction
+ // selection.
LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine&>(*Target);
TargetPassConfig &TPC = *LLVMTM.createPassConfig(PM);
+ TPC.setDisableVerify(NoVerify);
PM.add(&TPC);
MachineModuleInfo *MMI = new MachineModuleInfo(&LLVMTM);
- MMI->setMachineFunctionInitializer(MIR.get());
+ if (MIR->parseMachineFunctions(*M, *MMI))
+ return 1;
PM.add(MMI);
TPC.printAndVerify("");
- for (const std::string &RunPassName : *RunPassNames) {
- if (addPass(PM, argv[0], RunPassName, TPC))
+ if (!RunPassNames->empty()) {
+ if (!StartAfter.empty() || !StopAfter.empty() || !StartBefore.empty() ||
+ !StopBefore.empty()) {
+ errs() << argv0 << ": start-after and/or stop-after passes are "
+ "redundant when run-pass is specified.\n";
return 1;
+ }
+
+ for (const std::string &RunPassName : *RunPassNames) {
+ if (addPass(PM, argv0, RunPassName, TPC))
+ return 1;
+ }
+ } else {
+ TPC.setStartStopPasses(StartBeforeID, StartAfterID, StopBeforeID,
+ StopAfterID);
+ TPC.addISelPasses();
+ TPC.addMachinePasses();
}
- PM.add(createPrintMIRPass(*OS));
- } else {
- const char *argv0 = argv[0];
- AnalysisID StartBeforeID = getPassID(argv0, "start-before", StartBefore);
- AnalysisID StartAfterID = getPassID(argv0, "start-after", StartAfter);
- AnalysisID StopAfterID = getPassID(argv0, "stop-after", StopAfter);
- AnalysisID StopBeforeID = getPassID(argv0, "stop-before", StopBefore);
-
- if (StartBeforeID && StartAfterID) {
- errs() << argv[0] << ": -start-before and -start-after specified!\n";
- return 1;
- }
- if (StopBeforeID && StopAfterID) {
- errs() << argv[0] << ": -stop-before and -stop-after specified!\n";
- return 1;
- }
+ TPC.setInitialized();
- // Ask the target to add backend passes as necessary.
- if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify,
- StartBeforeID, StartAfterID, StopBeforeID,
- StopAfterID, MIR.get())) {
- errs() << argv[0] << ": target does not support generation of this"
+ if (!StopBefore.empty() || !StopAfter.empty() || !RunPassNames->empty()) {
+ PM.add(createPrintMIRPass(*OS));
+ } else if (LLVMTM.addAsmPrinter(PM, *OS, FileType, MMI->getContext())) {
+ errs() << argv0 << ": target does not support generation of this"
<< " file type!\n";
return 1;
}
+ PM.add(createFreeMachineFunctionPass());
+ } else if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify,
+ StartBeforeID, StartAfterID,
+ StopBeforeID, StopAfterID)) {
+ errs() << argv0 << ": target does not support generation of this"
+ << " file type!\n";
+ return 1;
}
// Before executing passes, print the final values of the LLVM options.
diff --git a/contrib/llvm/tools/lld/CMakeLists.txt b/contrib/llvm/tools/lld/CMakeLists.txt
index be424ef..e2ab0e3 100644
--- a/contrib/llvm/tools/lld/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/CMakeLists.txt
@@ -11,8 +11,11 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH")
endif()
- execute_process(COMMAND "${LLVM_CONFIG_PATH}" "--obj-root" "--includedir"
+ execute_process(COMMAND "${LLVM_CONFIG_PATH}"
+ "--obj-root"
+ "--includedir"
"--cmakedir"
+ "--src-root"
RESULT_VARIABLE HAD_ERROR
OUTPUT_VARIABLE LLVM_CONFIG_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -25,9 +28,11 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
list(GET LLVM_CONFIG_OUTPUT 0 OBJ_ROOT)
list(GET LLVM_CONFIG_OUTPUT 1 MAIN_INCLUDE_DIR)
list(GET LLVM_CONFIG_OUTPUT 2 LLVM_CMAKE_PATH)
+ list(GET LLVM_CONFIG_OUTPUT 3 MAIN_SRC_DIR)
set(LLVM_OBJ_ROOT ${OBJ_ROOT} CACHE PATH "path to LLVM build tree")
set(LLVM_MAIN_INCLUDE_DIR ${MAIN_INCLUDE_DIR} CACHE PATH "path to llvm/include")
+ set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
file(TO_CMAKE_PATH ${LLVM_OBJ_ROOT} LLVM_BINARY_DIR)
@@ -49,6 +54,67 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
include(AddLLVM)
include(TableGen)
include(HandleLLVMOptions)
+
+ if(LLVM_INCLUDE_TESTS)
+ set(Python_ADDITIONAL_VERSIONS 2.7)
+ include(FindPythonInterp)
+ if(NOT PYTHONINTERP_FOUND)
+ message(FATAL_ERROR
+"Unable to find Python interpreter, required for testing.
+
+Please install Python or specify the PYTHON_EXECUTABLE CMake variable.")
+ endif()
+
+ if(${PYTHON_VERSION_STRING} VERSION_LESS 2.7)
+ message(FATAL_ERROR "Python 2.7 or newer is required")
+ endif()
+
+ # Check prebuilt llvm/utils.
+ if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX}
+ AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX})
+ set(LLVM_UTILS_PROVIDED ON)
+ endif()
+
+ if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+ # Note: path not really used, except for checking if lit was found
+ set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+ if(NOT LLVM_UTILS_PROVIDED)
+ add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck)
+ add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not)
+ set(LLVM_UTILS_PROVIDED ON)
+ set(LLD_TEST_DEPS FileCheck not)
+ endif()
+ set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest)
+ if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h
+ AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}
+ AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt)
+ add_subdirectory(${UNITTEST_DIR} utils/unittest)
+ endif()
+ else()
+ # Seek installed Lit.
+ find_program(LLVM_LIT
+ NAMES llvm-lit lit.py lit
+ PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit"
+ DOC "Path to lit.py")
+ endif()
+
+ if(LLVM_LIT)
+ # Define the default arguments to use with 'lit', and an option for the user
+ # to override.
+ set(LIT_ARGS_DEFAULT "-sv")
+ if (MSVC OR XCODE)
+ set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
+ endif()
+ set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
+
+ # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools.
+ if(WIN32 AND NOT CYGWIN)
+ set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools")
+ endif()
+ else()
+ set(LLVM_INCLUDE_TESTS OFF)
+ endif()
+ endif()
endif()
set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
@@ -155,3 +221,4 @@ endif()
add_subdirectory(docs)
add_subdirectory(COFF)
add_subdirectory(ELF)
+
diff --git a/contrib/llvm/tools/lld/COFF/CMakeLists.txt b/contrib/llvm/tools/lld/COFF/CMakeLists.txt
index 70a33b9..e565934 100644
--- a/contrib/llvm/tools/lld/COFF/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/COFF/CMakeLists.txt
@@ -14,9 +14,9 @@ add_lld_library(lldCOFF
Error.cpp
ICF.cpp
InputFiles.cpp
- Librarian.cpp
+ LTO.cpp
+ MapFile.cpp
MarkLive.cpp
- ModuleDef.cpp
PDB.cpp
Strings.cpp
SymbolTable.cpp
@@ -25,6 +25,8 @@ add_lld_library(lldCOFF
LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
+ BinaryFormat
+ BitReader
Core
DebugInfoCodeView
DebugInfoMSF
@@ -40,7 +42,7 @@ add_lld_library(lldCOFF
LINK_LIBS
lldCore
- ${PTHREAD_LIB}
+ ${LLVM_PTHREAD_LIB}
DEPENDS
COFFOptionsTableGen
diff --git a/contrib/llvm/tools/lld/COFF/Chunks.cpp b/contrib/llvm/tools/lld/COFF/Chunks.cpp
index 7f0dfa9..7d93c28 100644
--- a/contrib/llvm/tools/lld/COFF/Chunks.cpp
+++ b/contrib/llvm/tools/lld/COFF/Chunks.cpp
@@ -11,8 +11,10 @@
#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
+#include "Writer.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
#include "llvm/Object/COFF.h"
-#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
@@ -36,18 +38,43 @@ SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H)
Align = Header->getAlignment();
- // Only COMDAT sections are subject of dead-stripping.
- Live = !isCOMDAT();
+ // Chunks may be discarded during comdat merging.
+ Discarded = false;
+
+ // If linker GC is disabled, every chunk starts out alive. If linker GC is
+ // enabled, treat non-comdat sections as roots. Generally optimized object
+ // files will be built with -ffunction-sections or /Gy, so most things worth
+ // stripping will be in a comdat.
+ Live = !Config->DoGC || !isCOMDAT();
}
static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
+static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); }
+
+static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
+ OutputSection *OS, uint64_t S) {
+ if (!OS) {
+ if (Sec->isCodeView())
+ return;
+ fatal("SECREL relocation cannot be applied to absolute symbols");
+ }
+ uint64_t SecRel = S - OS->getRVA();
+ assert(SecRel < INT32_MAX && "overflow in SECREL relocation");
+ add32(Off, SecRel);
+}
+
+static void applySecIdx(uint8_t *Off, OutputSection *OS) {
+ // If we have no output section, this must be an absolute symbol. Use the
+ // sentinel absolute symbol section index.
+ uint16_t SecIdx = OS ? OS->SectionIndex : DefinedAbsolute::OutputSectionIndex;
+ add16(Off, SecIdx);
+}
-void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym,
- uint64_t P) const {
- uint64_t S = Sym->getRVA();
+void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS,
+ uint64_t S, uint64_t P) const {
switch (Type) {
case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break;
case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break;
@@ -58,25 +85,24 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break;
case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break;
case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break;
- case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break;
- case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break;
+ case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break;
+ case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break;
default:
- fatal("unsupported relocation type");
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
}
-void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym,
- uint64_t P) const {
- uint64_t S = Sym->getRVA();
+void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS,
+ uint64_t S, uint64_t P) const {
switch (Type) {
case IMAGE_REL_I386_ABSOLUTE: break;
case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break;
case IMAGE_REL_I386_DIR32NB: add32(Off, S); break;
case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break;
- case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break;
- case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break;
+ case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break;
+ case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break;
default:
- fatal("unsupported relocation type");
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
}
@@ -121,22 +147,58 @@ static void applyBranch24T(uint8_t *Off, int32_t V) {
write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
}
-void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym,
- uint64_t P) const {
- uint64_t S = Sym->getRVA();
+void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
+ uint64_t S, uint64_t P) const {
// Pointer to thumb code must have the LSB set.
- if (Sym->isExecutable())
- S |= 1;
+ uint64_t SX = S;
+ if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE))
+ SX |= 1;
+ switch (Type) {
+ case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break;
+ case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break;
+ case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break;
+ case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break;
+ case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break;
+ case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break;
+ case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break;
+ case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break;
+ default:
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
+ }
+}
+
+static void applyArm64Addr(uint8_t *Off, uint64_t Imm) {
+ uint32_t ImmLo = (Imm & 0x3) << 29;
+ uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
+ uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
+ write32le(Off, (read32le(Off) & ~Mask) | ImmLo | ImmHi);
+}
+
+// Update the immediate field in a AARCH64 ldr, str, and add instruction.
+static void applyArm64Imm(uint8_t *Off, uint64_t Imm) {
+ uint32_t Orig = read32le(Off);
+ Imm += (Orig >> 10) & 0xFFF;
+ Orig &= ~(0xFFF << 10);
+ write32le(Off, Orig | ((Imm & 0xFFF) << 10));
+}
+
+static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) {
+ int Size = read32le(Off) >> 30;
+ Imm >>= Size;
+ applyArm64Imm(Off, Imm);
+}
+
+void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
+ uint64_t S, uint64_t P) const {
switch (Type) {
- case IMAGE_REL_ARM_ADDR32: add32(Off, S + Config->ImageBase); break;
- case IMAGE_REL_ARM_ADDR32NB: add32(Off, S); break;
- case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, S + Config->ImageBase); break;
- case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break;
- case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break;
- case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break;
- case IMAGE_REL_ARM_SECREL: add32(Off, Sym->getSecrel()); break;
+ case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, (S >> 12) - (P >> 12)); break;
+ case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff); break;
+ case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break;
+ case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break;
+ case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break;
default:
- fatal("unsupported relocation type");
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
}
@@ -148,20 +210,52 @@ void SectionChunk::writeTo(uint8_t *Buf) const {
memcpy(Buf + OutputSectionOff, A.data(), A.size());
// Apply relocations.
+ size_t InputSize = getSize();
for (const coff_relocation &Rel : Relocs) {
+ // Check for an invalid relocation offset. This check isn't perfect, because
+ // we don't have the relocation size, which is only known after checking the
+ // machine and relocation type. As a result, a relocation may overwrite the
+ // beginning of the following input section.
+ if (Rel.VirtualAddress >= InputSize)
+ fatal("relocation points beyond the end of its parent section");
+
uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress;
+
+ // Get the output section of the symbol for this relocation. The output
+ // section is needed to compute SECREL and SECTION relocations used in debug
+ // info.
SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex);
Defined *Sym = cast<Defined>(Body);
+ Chunk *C = Sym->getChunk();
+ OutputSection *OS = C ? C->getOutputSection() : nullptr;
+
+ // Only absolute and __ImageBase symbols lack an output section. For any
+ // other symbol, this indicates that the chunk was discarded. Normally
+ // relocations against discarded sections are an error. However, debug info
+ // sections are not GC roots and can end up with these kinds of relocations.
+ // Skip these relocations.
+ if (!OS && !isa<DefinedAbsolute>(Sym) && !isa<DefinedSynthetic>(Sym)) {
+ if (isCodeView() || isDWARF())
+ continue;
+ fatal("relocation against symbol in discarded section: " +
+ Sym->getName());
+ }
+ uint64_t S = Sym->getRVA();
+
+ // Compute the RVA of the relocation for relative relocations.
uint64_t P = RVA + Rel.VirtualAddress;
switch (Config->Machine) {
case AMD64:
- applyRelX64(Off, Rel.Type, Sym, P);
+ applyRelX64(Off, Rel.Type, OS, S, P);
break;
case I386:
- applyRelX86(Off, Rel.Type, Sym, P);
+ applyRelX86(Off, Rel.Type, OS, S, P);
break;
case ARMNT:
- applyRelARM(Off, Rel.Type, Sym, P);
+ applyRelARM(Off, Rel.Type, OS, S, P);
+ break;
+ case ARM64:
+ applyRelARM64(Off, Rel.Type, OS, S, P);
break;
default:
llvm_unreachable("unknown machine type");
@@ -189,6 +283,10 @@ static uint8_t getBaserelType(const coff_relocation &Rel) {
if (Rel.Type == IMAGE_REL_ARM_MOV32T)
return IMAGE_REL_BASED_ARM_MOV32T;
return IMAGE_REL_BASED_ABSOLUTE;
+ case ARM64:
+ if (Rel.Type == IMAGE_REL_ARM64_ADDR64)
+ return IMAGE_REL_BASED_DIR64;
+ return IMAGE_REL_BASED_ABSOLUTE;
default:
llvm_unreachable("unknown machine type");
}
@@ -225,8 +323,12 @@ bool SectionChunk::isCOMDAT() const {
void SectionChunk::printDiscardedMessage() const {
// Removed by dead-stripping. If it's removed by ICF, ICF already
// printed out the name, so don't repeat that here.
- if (Sym && this == Repl)
- outs() << "Discarded " << Sym->getName() << "\n";
+ if (Sym && this == Repl) {
+ if (Discarded)
+ message("Discarded comdat symbol " + Sym->getName());
+ else if (!Live)
+ message("Discarded " + Sym->getName());
+ }
}
StringRef SectionChunk::getDebugName() {
@@ -294,6 +396,14 @@ void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase);
}
+void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
+ int64_t PageOff = (ImpSymbol->getRVA() >> 12) - (RVA >> 12);
+ int64_t Off = ImpSymbol->getRVA() & 0xfff;
+ memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64));
+ applyArm64Addr(Buf + OutputSectionOff, PageOff);
+ applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
+}
+
void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
Res->emplace_back(getRVA());
}
@@ -318,8 +428,45 @@ void SEHTableChunk::writeTo(uint8_t *Buf) const {
std::sort(Begin, Begin + Cnt);
}
-// Windows-specific.
-// This class represents a block in .reloc section.
+// Windows-specific. This class represents a block in .reloc section.
+// The format is described here.
+//
+// On Windows, each DLL is linked against a fixed base address and
+// usually loaded to that address. However, if there's already another
+// DLL that overlaps, the loader has to relocate it. To do that, DLLs
+// contain .reloc sections which contain offsets that need to be fixed
+// up at runtime. If the loader finds that a DLL cannot be loaded to its
+// desired base address, it loads it to somewhere else, and add <actual
+// base address> - <desired base address> to each offset that is
+// specified by the .reloc section. In ELF terms, .reloc sections
+// contain relative relocations in REL format (as opposed to RELA.)
+//
+// This already significantly reduces the size of relocations compared
+// to ELF .rel.dyn, but Windows does more to reduce it (probably because
+// it was invented for PCs in the late '80s or early '90s.) Offsets in
+// .reloc are grouped by page where the page size is 12 bits, and
+// offsets sharing the same page address are stored consecutively to
+// represent them with less space. This is very similar to the page
+// table which is grouped by (multiple stages of) pages.
+//
+// For example, let's say we have 0x00030, 0x00500, 0x00700, 0x00A00,
+// 0x20004, and 0x20008 in a .reloc section for x64. The uppermost 4
+// bits have a type IMAGE_REL_BASED_DIR64 or 0xA. In the section, they
+// are represented like this:
+//
+// 0x00000 -- page address (4 bytes)
+// 16 -- size of this block (4 bytes)
+// 0xA030 -- entries (2 bytes each)
+// 0xA500
+// 0xA700
+// 0xAA00
+// 0x20000 -- page address (4 bytes)
+// 12 -- size of this block (4 bytes)
+// 0xA004 -- entries (2 bytes each)
+// 0xA008
+//
+// Usually we have a lot of relocations for each page, so the number of
+// bytes for one .reloc entry is close to 2 bytes on average.
BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) {
// Block header consists of 4 byte page RVA and 4 byte block size.
// Each entry is 2 byte. Last entry may be padding.
diff --git a/contrib/llvm/tools/lld/COFF/Chunks.h b/contrib/llvm/tools/lld/COFF/Chunks.h
index 59e36b8..ece5419 100644
--- a/contrib/llvm/tools/lld/COFF/Chunks.h
+++ b/contrib/llvm/tools/lld/COFF/Chunks.h
@@ -64,7 +64,6 @@ public:
uint64_t getRVA() const { return RVA; }
uint32_t getAlign() const { return Align; }
void setRVA(uint64_t V) { RVA = V; }
- void setOutputSectionOff(uint64_t V) { OutputSectionOff = V; }
// Returns true if this has non-zero data. BSS chunks return
// false. If false is returned, the space occupied by this chunk
@@ -97,21 +96,23 @@ protected:
Chunk(Kind K = OtherKind) : ChunkKind(K) {}
const Kind ChunkKind;
+ // The alignment of this chunk. The writer uses the value.
+ uint32_t Align = 1;
+
// The RVA of this chunk in the output. The writer sets a value.
uint64_t RVA = 0;
+public:
// The offset from beginning of the output section. The writer sets a value.
uint64_t OutputSectionOff = 0;
+protected:
// The output section for this chunk.
OutputSection *Out = nullptr;
-
- // The alignment of this chunk. The writer uses the value.
- uint32_t Align = 1;
};
// A chunk corresponding a section of an input file.
-class SectionChunk : public Chunk {
+class SectionChunk final : public Chunk {
// Identical COMDAT Folding feature accesses section internal data.
friend class ICF;
@@ -144,9 +145,14 @@ public:
StringRef getSectionName() const override { return SectionName; }
void getBaserels(std::vector<Baserel> *Res) override;
bool isCOMDAT() const;
- void applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const;
- void applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const;
- void applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const;
+ void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+ uint64_t P) const;
+ void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+ uint64_t P) const;
+ void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+ uint64_t P) const;
+ void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
+ uint64_t P) const;
// Called if the garbage collector decides to not include this chunk
// in a final output. It's supposed to print out a log message to stdout.
@@ -159,13 +165,32 @@ public:
StringRef getDebugName() override;
void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; }
+ // Returns true if the chunk was not dropped by GC or COMDAT deduplication.
+ bool isLive() { return Live && !Discarded; }
+
// Used by the garbage collector.
- bool isLive() { return !Config->DoGC || Live; }
void markLive() {
+ assert(Config->DoGC && "should only mark things live from GC");
assert(!isLive() && "Cannot mark an already live section!");
Live = true;
}
+ // Returns true if this chunk was dropped by COMDAT deduplication.
+ bool isDiscarded() const { return Discarded; }
+
+ // Used by the SymbolTable when discarding unused comdat sections. This is
+ // redundant when GC is enabled, as all comdat sections will start out dead.
+ void markDiscarded() { Discarded = true; }
+
+ // True if this is a codeview debug info chunk. These will not be laid out in
+ // the image. Instead they will end up in the PDB, if one is requested.
+ bool isCodeView() const {
+ return SectionName == ".debug" || SectionName.startswith(".debug$");
+ }
+
+ // True if this is a DWARF debug info chunk.
+ bool isDWARF() const { return SectionName.startswith(".debug_"); }
+
// Allow iteration over the bodies of this chunk's relocated symbols.
llvm::iterator_range<symbol_iterator> symbols() const {
return llvm::make_range(symbol_iterator(File, Relocs.begin()),
@@ -187,21 +212,24 @@ public:
const coff_section *Header;
-private:
- // A file this chunk was created from.
+ // The file that this chunk was created from.
ObjectFile *File;
+private:
StringRef SectionName;
std::vector<SectionChunk *> AssocChildren;
llvm::iterator_range<const coff_relocation *> Relocs;
size_t NumRelocs;
+ // True if this chunk was discarded because it was a duplicate comdat section.
+ bool Discarded;
+
// Used by the garbage collector.
bool Live;
// Used for ICF (Identical COMDAT Folding)
void replace(SectionChunk *Other);
- uint32_t Color[2] = {0, 0};
+ uint32_t Class[2] = {0, 0};
// Sym points to a section symbol if this is a COMDAT chunk.
DefinedRegular *Sym = nullptr;
@@ -241,6 +269,12 @@ static const uint8_t ImportThunkARM[] = {
0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
};
+static const uint8_t ImportThunkARM64[] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, #0
+ 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16]
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+};
+
// Windows-specific.
// A chunk for DLL import jump table entry. In a final output, it's
// contents will be a JMP instruction to some __imp_ symbol.
@@ -276,6 +310,16 @@ private:
Defined *ImpSymbol;
};
+class ImportThunkChunkARM64 : public Chunk {
+public:
+ explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {}
+ size_t getSize() const override { return sizeof(ImportThunkARM64); }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *ImpSymbol;
+};
+
// Windows-specific.
// See comments for DefinedLocalImport class.
class LocalImportChunk : public Chunk {
diff --git a/contrib/llvm/tools/lld/COFF/Config.h b/contrib/llvm/tools/lld/COFF/Config.h
index 0fa3338..7f8259d 100644
--- a/contrib/llvm/tools/lld/COFF/Config.h
+++ b/contrib/llvm/tools/lld/COFF/Config.h
@@ -31,6 +31,7 @@ class SymbolBody;
// Short aliases.
static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
+static const auto ARM64 = llvm::COFF::IMAGE_FILE_MACHINE_ARM64;
static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
@@ -43,6 +44,7 @@ struct Export {
bool Noname = false;
bool Data = false;
bool Private = false;
+ bool Constant = false;
// If an export is a form of /export:foo=dllname.bar, that means
// that foo should be exported as an alias to bar in the DLL.
@@ -72,7 +74,7 @@ enum class DebugType {
// Global configuration.
struct Configuration {
enum ManifestKind { SideBySide, Embed, No };
- bool is64() { return Machine == AMD64; }
+ bool is64() { return Machine == AMD64 || Machine == ARM64; }
llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
bool Verbose = false;
@@ -80,14 +82,18 @@ struct Configuration {
SymbolBody *Entry = nullptr;
bool NoEntry = false;
std::string OutputFile;
+ std::string ImportName;
+ bool ColorDiagnostics;
bool DoGC = true;
bool DoICF = true;
+ uint64_t ErrorLimit = 20;
bool Relocatable = true;
bool Force = false;
bool Debug = false;
bool WriteSymtab = true;
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
- StringRef PDBPath;
+ llvm::SmallString<128> PDBPath;
+ std::vector<llvm::StringRef> Argv;
// Symbols in this set are considered as live by the garbage collector.
std::set<SymbolBody *> GCRoot;
@@ -103,6 +109,8 @@ struct Configuration {
std::map<std::string, int> DLLOrder;
SymbolBody *DelayLoadHelper = nullptr;
+ bool SaveTemps = false;
+
// Used for SafeSEH.
Symbol *SEHTable = nullptr;
Symbol *SEHCount = nullptr;
@@ -111,7 +119,9 @@ struct Configuration {
unsigned LTOOptLevel = 2;
// Used for /opt:lldltojobs=N
- unsigned LTOJobs = 1;
+ unsigned LTOJobs = 0;
+ // Used for /opt:lldltopartitions=N
+ unsigned LTOPartitions = 1;
// Used for /merge:from=to (e.g. /merge:.rdata=.text)
std::map<StringRef, StringRef> Merge;
@@ -120,7 +130,7 @@ struct Configuration {
std::map<StringRef, uint32_t> Section;
// Options for manifest files.
- ManifestKind Manifest = SideBySide;
+ ManifestKind Manifest = No;
int ManifestID = 1;
StringRef ManifestDependency;
bool ManifestUAC = true;
@@ -135,6 +145,9 @@ struct Configuration {
// Used for /alternatename.
std::map<StringRef, StringRef> AlternateNames;
+ // Used for /lldmap.
+ std::string MapFile;
+
uint64_t ImageBase = -1;
uint64_t StackReserve = 1024 * 1024;
uint64_t StackCommit = 4096;
@@ -145,16 +158,12 @@ struct Configuration {
uint32_t MajorOSVersion = 6;
uint32_t MinorOSVersion = 0;
bool DynamicBase = true;
- bool AllowBind = true;
bool NxCompat = true;
bool AllowIsolation = true;
bool TerminalServerAware = true;
bool LargeAddressAware = false;
bool HighEntropyVA = false;
-
- // This is for debugging.
- bool DebugPdb = false;
- bool DumpPdb = false;
+ bool AppContainer = false;
};
extern Configuration *Config;
diff --git a/contrib/llvm/tools/lld/COFF/DLL.cpp b/contrib/llvm/tools/lld/COFF/DLL.cpp
index f93dc5c..d76410b 100644
--- a/contrib/llvm/tools/lld/COFF/DLL.cpp
+++ b/contrib/llvm/tools/lld/COFF/DLL.cpp
@@ -136,9 +136,9 @@ binImports(const std::vector<DefinedImportData *> &Imports) {
M[Sym->getDLLName().lower()].push_back(Sym);
std::vector<std::vector<DefinedImportData *>> V;
- for (auto &P : M) {
+ for (auto &KV : M) {
// Sort symbols by name for each group.
- std::vector<DefinedImportData *> &Syms = P.second;
+ std::vector<DefinedImportData *> &Syms = KV.second;
std::sort(Syms.begin(), Syms.end(),
[](DefinedImportData *A, DefinedImportData *B) {
return A->getName() < B->getName();
@@ -383,21 +383,15 @@ uint64_t IdataContents::getIATSize() {
// See Microsoft PE/COFF spec 5.4 for details.
std::vector<Chunk *> IdataContents::getChunks() {
create();
- std::vector<Chunk *> V;
+
// The loader assumes a specific order of data.
// Add each type in the correct order.
- for (std::unique_ptr<Chunk> &C : Dirs)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Lookups)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Addresses)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Hints)
- V.push_back(C.get());
- for (auto &P : DLLNames) {
- std::unique_ptr<Chunk> &C = P.second;
- V.push_back(C.get());
- }
+ std::vector<Chunk *> V;
+ V.insert(V.end(), Dirs.begin(), Dirs.end());
+ V.insert(V.end(), Lookups.begin(), Lookups.end());
+ V.insert(V.end(), Addresses.begin(), Addresses.end());
+ V.insert(V.end(), Hints.begin(), Hints.end());
+ V.insert(V.end(), DLLNames.begin(), DLLNames.end());
return V;
}
@@ -406,8 +400,6 @@ void IdataContents::create() {
// Create .idata contents for each DLL.
for (std::vector<DefinedImportData *> &Syms : V) {
- StringRef Name = Syms[0]->getDLLName();
-
// Create lookup and address tables. If they have external names,
// we need to create HintName chunks to store the names.
// If they don't (if they are import-by-ordinals), we store only
@@ -416,55 +408,46 @@ void IdataContents::create() {
for (DefinedImportData *S : Syms) {
uint16_t Ord = S->getOrdinal();
if (S->getExternalName().empty()) {
- Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
- Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
+ Lookups.push_back(make<OrdinalOnlyChunk>(Ord));
+ Addresses.push_back(make<OrdinalOnlyChunk>(Ord));
continue;
}
- auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
- Lookups.push_back(make_unique<LookupChunk>(C.get()));
- Addresses.push_back(make_unique<LookupChunk>(C.get()));
- Hints.push_back(std::move(C));
+ auto *C = make<HintNameChunk>(S->getExternalName(), Ord);
+ Lookups.push_back(make<LookupChunk>(C));
+ Addresses.push_back(make<LookupChunk>(C));
+ Hints.push_back(C);
}
// Terminate with null values.
- Lookups.push_back(make_unique<NullChunk>(ptrSize()));
- Addresses.push_back(make_unique<NullChunk>(ptrSize()));
+ Lookups.push_back(make<NullChunk>(ptrSize()));
+ Addresses.push_back(make<NullChunk>(ptrSize()));
for (int I = 0, E = Syms.size(); I < E; ++I)
- Syms[I]->setLocation(Addresses[Base + I].get());
+ Syms[I]->setLocation(Addresses[Base + I]);
// Create the import table header.
- if (!DLLNames.count(Name))
- DLLNames[Name] = make_unique<StringChunk>(Name);
- auto Dir = make_unique<ImportDirectoryChunk>(DLLNames[Name].get());
- Dir->LookupTab = Lookups[Base].get();
- Dir->AddressTab = Addresses[Base].get();
- Dirs.push_back(std::move(Dir));
+ DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
+ auto *Dir = make<ImportDirectoryChunk>(DLLNames.back());
+ Dir->LookupTab = Lookups[Base];
+ Dir->AddressTab = Addresses[Base];
+ Dirs.push_back(Dir);
}
// Add null terminator.
- Dirs.push_back(make_unique<NullChunk>(sizeof(ImportDirectoryTableEntry)));
+ Dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry)));
}
std::vector<Chunk *> DelayLoadContents::getChunks() {
std::vector<Chunk *> V;
- for (std::unique_ptr<Chunk> &C : Dirs)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Names)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : HintNames)
- V.push_back(C.get());
- for (auto &P : DLLNames) {
- std::unique_ptr<Chunk> &C = P.second;
- V.push_back(C.get());
- }
+ V.insert(V.end(), Dirs.begin(), Dirs.end());
+ V.insert(V.end(), Names.begin(), Names.end());
+ V.insert(V.end(), HintNames.begin(), HintNames.end());
+ V.insert(V.end(), DLLNames.begin(), DLLNames.end());
return V;
}
std::vector<Chunk *> DelayLoadContents::getDataChunks() {
std::vector<Chunk *> V;
- for (std::unique_ptr<Chunk> &C : ModuleHandles)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Addresses)
- V.push_back(C.get());
+ V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end());
+ V.insert(V.end(), Addresses.begin(), Addresses.end());
return V;
}
@@ -478,55 +461,51 @@ void DelayLoadContents::create(Defined *H) {
// Create .didat contents for each DLL.
for (std::vector<DefinedImportData *> &Syms : V) {
- StringRef Name = Syms[0]->getDLLName();
-
// Create the delay import table header.
- if (!DLLNames.count(Name))
- DLLNames[Name] = make_unique<StringChunk>(Name);
- auto Dir = make_unique<DelayDirectoryChunk>(DLLNames[Name].get());
+ DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
+ auto *Dir = make<DelayDirectoryChunk>(DLLNames.back());
size_t Base = Addresses.size();
for (DefinedImportData *S : Syms) {
- Chunk *T = newThunkChunk(S, Dir.get());
- auto A = make_unique<DelayAddressChunk>(T);
- Addresses.push_back(std::move(A));
- Thunks.push_back(std::unique_ptr<Chunk>(T));
+ Chunk *T = newThunkChunk(S, Dir);
+ auto *A = make<DelayAddressChunk>(T);
+ Addresses.push_back(A);
+ Thunks.push_back(T);
StringRef ExtName = S->getExternalName();
if (ExtName.empty()) {
- Names.push_back(make_unique<OrdinalOnlyChunk>(S->getOrdinal()));
+ Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal()));
} else {
- auto C = make_unique<HintNameChunk>(ExtName, 0);
- Names.push_back(make_unique<LookupChunk>(C.get()));
- HintNames.push_back(std::move(C));
+ auto *C = make<HintNameChunk>(ExtName, 0);
+ Names.push_back(make<LookupChunk>(C));
+ HintNames.push_back(C);
}
}
// Terminate with null values.
- Addresses.push_back(make_unique<NullChunk>(8));
- Names.push_back(make_unique<NullChunk>(8));
+ Addresses.push_back(make<NullChunk>(8));
+ Names.push_back(make<NullChunk>(8));
for (int I = 0, E = Syms.size(); I < E; ++I)
- Syms[I]->setLocation(Addresses[Base + I].get());
- auto *MH = new NullChunk(8);
+ Syms[I]->setLocation(Addresses[Base + I]);
+ auto *MH = make<NullChunk>(8);
MH->setAlign(8);
- ModuleHandles.push_back(std::unique_ptr<Chunk>(MH));
+ ModuleHandles.push_back(MH);
// Fill the delay import table header fields.
Dir->ModuleHandle = MH;
- Dir->AddressTab = Addresses[Base].get();
- Dir->NameTab = Names[Base].get();
- Dirs.push_back(std::move(Dir));
+ Dir->AddressTab = Addresses[Base];
+ Dir->NameTab = Names[Base];
+ Dirs.push_back(Dir);
}
// Add null terminator.
- Dirs.push_back(
- make_unique<NullChunk>(sizeof(delay_import_directory_table_entry)));
+ Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
}
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
switch (Config->Machine) {
case AMD64:
- return new ThunkChunkX64(S, Dir, Helper);
+ return make<ThunkChunkX64>(S, Dir, Helper);
case I386:
- return new ThunkChunkX86(S, Dir, Helper);
+ return make<ThunkChunkX86>(S, Dir, Helper);
default:
llvm_unreachable("unsupported machine type");
}
@@ -537,34 +516,32 @@ EdataContents::EdataContents() {
for (Export &E : Config->Exports)
MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
- auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile));
- auto *AddressTab = new AddressTableChunk(MaxOrdinal);
+ auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile));
+ auto *AddressTab = make<AddressTableChunk>(MaxOrdinal);
std::vector<Chunk *> Names;
for (Export &E : Config->Exports)
if (!E.Noname)
- Names.push_back(new StringChunk(E.ExportName));
+ Names.push_back(make<StringChunk>(E.ExportName));
std::vector<Chunk *> Forwards;
for (Export &E : Config->Exports) {
if (E.ForwardTo.empty())
continue;
- E.ForwardChunk = new StringChunk(E.ForwardTo);
+ E.ForwardChunk = make<StringChunk>(E.ForwardTo);
Forwards.push_back(E.ForwardChunk);
}
- auto *NameTab = new NamePointersChunk(Names);
- auto *OrdinalTab = new ExportOrdinalChunk(Names.size());
- auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName,
- AddressTab, NameTab, OrdinalTab);
- Chunks.push_back(std::unique_ptr<Chunk>(Dir));
- Chunks.push_back(std::unique_ptr<Chunk>(DLLName));
- Chunks.push_back(std::unique_ptr<Chunk>(AddressTab));
- Chunks.push_back(std::unique_ptr<Chunk>(NameTab));
- Chunks.push_back(std::unique_ptr<Chunk>(OrdinalTab));
- for (Chunk *C : Names)
- Chunks.push_back(std::unique_ptr<Chunk>(C));
- for (Chunk *C : Forwards)
- Chunks.push_back(std::unique_ptr<Chunk>(C));
+ auto *NameTab = make<NamePointersChunk>(Names);
+ auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size());
+ auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName,
+ AddressTab, NameTab, OrdinalTab);
+ Chunks.push_back(Dir);
+ Chunks.push_back(DLLName);
+ Chunks.push_back(AddressTab);
+ Chunks.push_back(NameTab);
+ Chunks.push_back(OrdinalTab);
+ Chunks.insert(Chunks.end(), Names.begin(), Names.end());
+ Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end());
}
} // namespace coff
diff --git a/contrib/llvm/tools/lld/COFF/DLL.h b/contrib/llvm/tools/lld/COFF/DLL.h
index 83a12df..ad31278 100644
--- a/contrib/llvm/tools/lld/COFF/DLL.h
+++ b/contrib/llvm/tools/lld/COFF/DLL.h
@@ -35,11 +35,11 @@ private:
void create();
std::vector<DefinedImportData *> Imports;
- std::vector<std::unique_ptr<Chunk>> Dirs;
- std::vector<std::unique_ptr<Chunk>> Lookups;
- std::vector<std::unique_ptr<Chunk>> Addresses;
- std::vector<std::unique_ptr<Chunk>> Hints;
- std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
+ std::vector<Chunk *> Dirs;
+ std::vector<Chunk *> Lookups;
+ std::vector<Chunk *> Addresses;
+ std::vector<Chunk *> Hints;
+ std::vector<Chunk *> DLLNames;
};
// Windows-specific.
@@ -51,7 +51,7 @@ public:
void create(Defined *Helper);
std::vector<Chunk *> getChunks();
std::vector<Chunk *> getDataChunks();
- std::vector<std::unique_ptr<Chunk>> &getCodeChunks() { return Thunks; }
+ ArrayRef<Chunk *> getCodeChunks() { return Thunks; }
uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
uint64_t getDirSize();
@@ -61,13 +61,13 @@ private:
Defined *Helper;
std::vector<DefinedImportData *> Imports;
- std::vector<std::unique_ptr<Chunk>> Dirs;
- std::vector<std::unique_ptr<Chunk>> ModuleHandles;
- std::vector<std::unique_ptr<Chunk>> Addresses;
- std::vector<std::unique_ptr<Chunk>> Names;
- std::vector<std::unique_ptr<Chunk>> HintNames;
- std::vector<std::unique_ptr<Chunk>> Thunks;
- std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
+ std::vector<Chunk *> Dirs;
+ std::vector<Chunk *> ModuleHandles;
+ std::vector<Chunk *> Addresses;
+ std::vector<Chunk *> Names;
+ std::vector<Chunk *> HintNames;
+ std::vector<Chunk *> Thunks;
+ std::vector<Chunk *> DLLNames;
};
// Windows-specific.
@@ -75,7 +75,7 @@ private:
class EdataContents {
public:
EdataContents();
- std::vector<std::unique_ptr<Chunk>> Chunks;
+ std::vector<Chunk *> Chunks;
};
} // namespace coff
diff --git a/contrib/llvm/tools/lld/COFF/Driver.cpp b/contrib/llvm/tools/lld/COFF/Driver.cpp
index 4dabd9e..854c3e6 100644
--- a/contrib/llvm/tools/lld/COFF/Driver.cpp
+++ b/contrib/llvm/tools/lld/COFF/Driver.cpp
@@ -18,7 +18,10 @@
#include "lld/Driver/Driver.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/LibDriver/LibDriver.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/COFFModuleDefinition.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
@@ -28,22 +31,16 @@
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
#include <algorithm>
#include <memory>
-#ifdef _MSC_VER
-// <future> depends on <eh.h> for __uncaught_exception.
-#include <eh.h>
-#endif
-
#include <future>
using namespace llvm;
+using namespace llvm::object;
using namespace llvm::COFF;
using llvm::sys::Process;
-using llvm::sys::fs::OpenFlags;
-using llvm::sys::fs::file_magic;
-using llvm::sys::fs::identify_magic;
namespace lld {
namespace coff {
@@ -55,11 +52,16 @@ BumpPtrAllocator BAlloc;
StringSaver Saver{BAlloc};
std::vector<SpecificAllocBase *> SpecificAllocBase::Instances;
-bool link(ArrayRef<const char *> Args) {
+bool link(ArrayRef<const char *> Args, raw_ostream &Diag) {
+ ErrorCount = 0;
+ ErrorOS = &Diag;
Config = make<Configuration>();
+ Config->Argv = {Args.begin(), Args.end()};
+ Config->ColorDiagnostics =
+ (ErrorOS == &llvm::errs() && Process::StandardErrHasColors());
Driver = make<LinkerDriver>();
Driver->link(Args);
- return true;
+ return !ErrorCount;
}
// Drop directory components and replace extension with ".exe" or ".dll".
@@ -97,12 +99,11 @@ static std::future<MBErrPair> createFutureForFile(std::string Path) {
MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
MemoryBufferRef MBRef = *MB;
- OwningMBs.push_back(std::move(MB));
+ make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership
if (Driver->Tar)
Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()),
MBRef.getBuffer());
-
return MBRef;
}
@@ -121,10 +122,12 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB) {
return Symtab.addFile(make<ArchiveFile>(MBRef));
if (Magic == file_magic::bitcode)
return Symtab.addFile(make<BitcodeFile>(MBRef));
+
if (Magic == file_magic::coff_cl_gl_object)
- fatal(MBRef.getBufferIdentifier() + ": is not a native COFF file. "
+ error(MBRef.getBufferIdentifier() + ": is not a native COFF file. "
"Recompile without /GL");
- Symtab.addFile(make<ObjectFile>(MBRef));
+ else
+ Symtab.addFile(make<ObjectFile>(MBRef));
}
void LinkerDriver::enqueuePath(StringRef Path) {
@@ -134,12 +137,10 @@ void LinkerDriver::enqueuePath(StringRef Path) {
enqueueTask([=]() {
auto MBOrErr = Future->get();
if (MBOrErr.second)
- fatal(MBOrErr.second, "could not open " + PathStr);
- Driver->addBuffer(std::move(MBOrErr.first));
+ error("could not open " + PathStr + ": " + MBOrErr.second.message());
+ else
+ Driver->addBuffer(std::move(MBOrErr.first));
});
-
- if (Config->OutputFile == "")
- Config->OutputFile = getOutputPath(Path);
}
void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
@@ -151,17 +152,18 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
}
InputFile *Obj;
- if (Magic == file_magic::coff_object)
+ if (Magic == file_magic::coff_object) {
Obj = make<ObjectFile>(MB);
- else if (Magic == file_magic::bitcode)
+ } else if (Magic == file_magic::bitcode) {
Obj = make<BitcodeFile>(MB);
- else
- fatal("unknown file type: " + MB.getBufferIdentifier());
+ } else {
+ error("unknown file type: " + MB.getBufferIdentifier());
+ return;
+ }
Obj->ParentName = ParentName;
Symtab.addFile(Obj);
- if (Config->Verbose)
- outs() << "Loaded " << toString(Obj) << " for " << SymName << "\n";
+ log("Loaded " + toString(Obj) + " for " + SymName);
}
void LinkerDriver::enqueueArchiveMember(const Archive::Child &C,
@@ -234,7 +236,7 @@ void LinkerDriver::parseDirectives(StringRef S) {
case OPT_throwingnew:
break;
default:
- fatal(Arg->getSpelling() + " is not allowed in .drectve");
+ error(Arg->getSpelling() + " is not allowed in .drectve");
}
}
}
@@ -402,7 +404,8 @@ static unsigned parseDebugType(StringRef Arg) {
DebugTypes |= StringSwitch<unsigned>(Type.lower())
.Case("cv", static_cast<unsigned>(DebugType::CV))
.Case("pdata", static_cast<unsigned>(DebugType::PData))
- .Case("fixup", static_cast<unsigned>(DebugType::Fixup));
+ .Case("fixup", static_cast<unsigned>(DebugType::Fixup))
+ .Default(0);
return DebugTypes;
}
@@ -418,6 +421,243 @@ static std::string getMapFile(const opt::InputArgList &Args) {
return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str();
}
+static std::string getImplibPath() {
+ if (!Config->Implib.empty())
+ return Config->Implib;
+ SmallString<128> Out = StringRef(Config->OutputFile);
+ sys::path::replace_extension(Out, ".lib");
+ return Out.str();
+}
+
+//
+// The import name is caculated as the following:
+//
+// | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY
+// -----+----------------+---------------------+------------------
+// LINK | {value} | {value}.{.dll/.exe} | {output name}
+// LIB | {value} | {value}.dll | {output name}.dll
+//
+static std::string getImportName(bool AsLib) {
+ SmallString<128> Out;
+
+ if (Config->ImportName.empty()) {
+ Out.assign(sys::path::filename(Config->OutputFile));
+ if (AsLib)
+ sys::path::replace_extension(Out, ".dll");
+ } else {
+ Out.assign(Config->ImportName);
+ if (!sys::path::has_extension(Out))
+ sys::path::replace_extension(Out,
+ (Config->DLL || AsLib) ? ".dll" : ".exe");
+ }
+
+ return Out.str();
+}
+
+static void createImportLibrary(bool AsLib) {
+ std::vector<COFFShortExport> Exports;
+ for (Export &E1 : Config->Exports) {
+ COFFShortExport E2;
+ E2.Name = E1.Name;
+ E2.SymbolName = E1.SymbolName;
+ E2.ExtName = E1.ExtName;
+ E2.Ordinal = E1.Ordinal;
+ E2.Noname = E1.Noname;
+ E2.Data = E1.Data;
+ E2.Private = E1.Private;
+ E2.Constant = E1.Constant;
+ Exports.push_back(E2);
+ }
+
+ writeImportLibrary(getImportName(AsLib), getImplibPath(), Exports,
+ Config->Machine, false);
+}
+
+static void parseModuleDefs(StringRef Path) {
+ std::unique_ptr<MemoryBuffer> MB = check(
+ MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+ COFFModuleDefinition M =
+ check(parseCOFFModuleDefinition(MB->getMemBufferRef(), Config->Machine));
+
+ if (Config->OutputFile.empty())
+ Config->OutputFile = Saver.save(M.OutputFile);
+ Config->ImportName = Saver.save(M.ImportName);
+ if (M.ImageBase)
+ Config->ImageBase = M.ImageBase;
+ if (M.StackReserve)
+ Config->StackReserve = M.StackReserve;
+ if (M.StackCommit)
+ Config->StackCommit = M.StackCommit;
+ if (M.HeapReserve)
+ Config->HeapReserve = M.HeapReserve;
+ if (M.HeapCommit)
+ Config->HeapCommit = M.HeapCommit;
+ if (M.MajorImageVersion)
+ Config->MajorImageVersion = M.MajorImageVersion;
+ if (M.MinorImageVersion)
+ Config->MinorImageVersion = M.MinorImageVersion;
+ if (M.MajorOSVersion)
+ Config->MajorOSVersion = M.MajorOSVersion;
+ if (M.MinorOSVersion)
+ Config->MinorOSVersion = M.MinorOSVersion;
+
+ for (COFFShortExport E1 : M.Exports) {
+ Export E2;
+ E2.Name = Saver.save(E1.Name);
+ if (E1.isWeak())
+ E2.ExtName = Saver.save(E1.ExtName);
+ E2.Ordinal = E1.Ordinal;
+ E2.Noname = E1.Noname;
+ E2.Data = E1.Data;
+ E2.Private = E1.Private;
+ E2.Constant = E1.Constant;
+ Config->Exports.push_back(E2);
+ }
+}
+
+std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) {
+ std::vector<MemoryBufferRef> V;
+ Error Err = Error::success();
+ for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
+ Archive::Child C =
+ check(COrErr,
+ File->getFileName() + ": could not get the child of the archive");
+ MemoryBufferRef MBRef =
+ check(C.getMemoryBufferRef(),
+ File->getFileName() +
+ ": could not get the buffer for a child of the archive");
+ V.push_back(MBRef);
+ }
+ if (Err)
+ fatal(File->getFileName() +
+ ": Archive::children failed: " + toString(std::move(Err)));
+ return V;
+}
+
+// A helper function for filterBitcodeFiles.
+static bool needsRebuilding(MemoryBufferRef MB) {
+ // The MSVC linker doesn't support thin archives, so if it's a thin
+ // archive, we always need to rebuild it.
+ std::unique_ptr<Archive> File =
+ check(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier());
+ if (File->isThin())
+ return true;
+
+ // Returns true if the archive contains at least one bitcode file.
+ for (MemoryBufferRef Member : getArchiveMembers(File.get()))
+ if (identify_magic(Member.getBuffer()) == file_magic::bitcode)
+ return true;
+ return false;
+}
+
+// Opens a given path as an archive file and removes bitcode files
+// from them if exists. This function is to appease the MSVC linker as
+// their linker doesn't like archive files containing non-native
+// object files.
+//
+// If a given archive doesn't contain bitcode files, the archive path
+// is returned as-is. Otherwise, a new temporary file is created and
+// its path is returned.
+static Optional<std::string>
+filterBitcodeFiles(StringRef Path, std::vector<std::string> &TemporaryFiles) {
+ std::unique_ptr<MemoryBuffer> MB = check(
+ MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+ MemoryBufferRef MBRef = MB->getMemBufferRef();
+ file_magic Magic = identify_magic(MBRef.getBuffer());
+
+ if (Magic == file_magic::bitcode)
+ return None;
+ if (Magic != file_magic::archive)
+ return Path.str();
+ if (!needsRebuilding(MBRef))
+ return Path.str();
+
+ std::unique_ptr<Archive> File =
+ check(Archive::create(MBRef),
+ MBRef.getBufferIdentifier() + ": failed to parse archive");
+
+ std::vector<NewArchiveMember> New;
+ for (MemoryBufferRef Member : getArchiveMembers(File.get()))
+ if (identify_magic(Member.getBuffer()) != file_magic::bitcode)
+ New.emplace_back(Member);
+
+ if (New.empty())
+ return None;
+
+ log("Creating a temporary archive for " + Path + " to remove bitcode files");
+
+ SmallString<128> S;
+ if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path),
+ ".lib", S))
+ fatal(EC, "cannot create a temporary file");
+ std::string Temp = S.str();
+ TemporaryFiles.push_back(Temp);
+
+ std::pair<StringRef, std::error_code> Ret =
+ llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU,
+ /*Deterministics=*/true,
+ /*Thin=*/false);
+ if (Ret.second)
+ error("failed to create a new archive " + S.str() + ": " + Ret.first);
+ return Temp;
+}
+
+// Create response file contents and invoke the MSVC linker.
+void LinkerDriver::invokeMSVC(opt::InputArgList &Args) {
+ std::string Rsp = "/nologo\n";
+ std::vector<std::string> Temps;
+
+ // Write out archive members that we used in symbol resolution and pass these
+ // to MSVC before any archives, so that MSVC uses the same objects to satisfy
+ // references.
+ for (const auto *O : Symtab.ObjectFiles) {
+ if (O->ParentName.empty())
+ continue;
+ SmallString<128> S;
+ int Fd;
+ if (auto EC = sys::fs::createTemporaryFile(
+ "lld-" + sys::path::filename(O->ParentName), ".obj", Fd, S))
+ fatal(EC, "cannot create a temporary file");
+ raw_fd_ostream OS(Fd, /*shouldClose*/ true);
+ OS << O->MB.getBuffer();
+ Temps.push_back(S.str());
+ Rsp += quote(S) + "\n";
+ }
+
+ for (auto *Arg : Args) {
+ switch (Arg->getOption().getID()) {
+ case OPT_linkrepro:
+ case OPT_lldmap:
+ case OPT_lldmap_file:
+ case OPT_lldsavetemps:
+ case OPT_msvclto:
+ // LLD-specific options are stripped.
+ break;
+ case OPT_opt:
+ if (!StringRef(Arg->getValue()).startswith("lld"))
+ Rsp += toString(Arg) + " ";
+ break;
+ case OPT_INPUT: {
+ if (Optional<StringRef> Path = doFindFile(Arg->getValue())) {
+ if (Optional<std::string> S = filterBitcodeFiles(*Path, Temps))
+ Rsp += quote(*S) + "\n";
+ continue;
+ }
+ Rsp += quote(Arg->getValue()) + "\n";
+ break;
+ }
+ default:
+ Rsp += toString(Arg) + "\n";
+ }
+ }
+
+ std::vector<StringRef> ObjectFiles = Symtab.compileBitcodeFiles();
+ runMSVCLinker(Rsp, ObjectFiles);
+
+ for (StringRef Path : Temps)
+ sys::fs::remove(Path);
+}
+
void LinkerDriver::enqueueTask(std::function<void()> Task) {
TaskQueue.push_back(std::move(Task));
}
@@ -451,6 +691,22 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Parse command line options.
opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
+ // Parse and evaluate -mllvm options.
+ std::vector<const char *> V;
+ V.push_back("lld-link (LLVM option parsing)");
+ for (auto *Arg : Args.filtered(OPT_mllvm))
+ V.push_back(Arg->getValue());
+ cl::ParseCommandLineOptions(V.size(), V.data());
+
+ // Handle /errorlimit early, because error() depends on it.
+ if (auto *Arg = Args.getLastArg(OPT_errorlimit)) {
+ int N = 20;
+ StringRef S = Arg->getValue();
+ if (S.getAsInteger(10, N))
+ error(Arg->getSpelling() + " number expected, but got " + S);
+ Config->ErrorLimit = N;
+ }
+
// Handle /help
if (Args.hasArg(OPT_help)) {
printHelp(ArgsArr[0]);
@@ -467,13 +723,17 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (ErrOrWriter) {
Tar = std::move(*ErrOrWriter);
} else {
- errs() << "/linkrepro: failed to open " << Path << ": "
- << toString(ErrOrWriter.takeError()) << '\n';
+ error("/linkrepro: failed to open " + Path + ": " +
+ toString(ErrOrWriter.takeError()));
}
}
- if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end())
- fatal("no input files");
+ if (!Args.hasArgNoClaim(OPT_INPUT)) {
+ if (Args.hasArgNoClaim(OPT_deffile))
+ Config->NoEntry = true;
+ else
+ fatal("no input files");
+ }
// Construct search path list.
SearchPaths.push_back("");
@@ -508,9 +768,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /noentry
if (Args.hasArg(OPT_noentry)) {
- if (!Args.hasArg(OPT_dll))
- fatal("/noentry must be specified with /dll");
- Config->NoEntry = true;
+ if (Args.hasArg(OPT_dll))
+ Config->NoEntry = true;
+ else
+ error("/noentry must be specified with /dll");
}
// Handle /dll
@@ -521,12 +782,17 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /fixed
if (Args.hasArg(OPT_fixed)) {
- if (Args.hasArg(OPT_dynamicbase))
- fatal("/fixed must not be specified with /dynamicbase");
- Config->Relocatable = false;
- Config->DynamicBase = false;
+ if (Args.hasArg(OPT_dynamicbase)) {
+ error("/fixed must not be specified with /dynamicbase");
+ } else {
+ Config->Relocatable = false;
+ Config->DynamicBase = false;
+ }
}
+ if (Args.hasArg(OPT_appcontainer))
+ Config->AppContainer = true;
+
// Handle /machine
if (auto *Arg = Args.getLastArg(OPT_machine))
Config->Machine = getMachineType(Arg->getValue());
@@ -596,20 +862,31 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
StringRef OptLevel = StringRef(S).substr(7);
if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
Config->LTOOptLevel > 3)
- fatal("/opt:lldlto: invalid optimization level: " + OptLevel);
+ error("/opt:lldlto: invalid optimization level: " + OptLevel);
continue;
}
if (StringRef(S).startswith("lldltojobs=")) {
StringRef Jobs = StringRef(S).substr(11);
if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0)
- fatal("/opt:lldltojobs: invalid job count: " + Jobs);
+ error("/opt:lldltojobs: invalid job count: " + Jobs);
+ continue;
+ }
+ if (StringRef(S).startswith("lldltopartitions=")) {
+ StringRef N = StringRef(S).substr(17);
+ if (N.getAsInteger(10, Config->LTOPartitions) ||
+ Config->LTOPartitions == 0)
+ error("/opt:lldltopartitions: invalid partition count: " + N);
continue;
}
if (S != "ref" && S != "lbr" && S != "nolbr")
- fatal("/opt: unknown option: " + S);
+ error("/opt: unknown option: " + S);
}
}
+ // Handle /lldsavetemps
+ if (Args.hasArg(OPT_lldsavetemps))
+ Config->SaveTemps = true;
+
// Handle /failifmismatch
for (auto *Arg : Args.filtered(OPT_failifmismatch))
checkFailIfMismatch(Arg->getValue());
@@ -622,18 +899,25 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
for (auto *Arg : Args.filtered(OPT_section))
parseSection(Arg->getValue());
- // Handle /manifest
- if (auto *Arg = Args.getLastArg(OPT_manifest_colon))
- parseManifest(Arg->getValue());
+ // Handle /manifestdependency. This enables /manifest unless /manifest:no is
+ // also passed.
+ if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) {
+ Config->ManifestDependency = Arg->getValue();
+ Config->Manifest = Configuration::SideBySide;
+ }
+
+ // Handle /manifest and /manifest:
+ if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) {
+ if (Arg->getOption().getID() == OPT_manifest)
+ Config->Manifest = Configuration::SideBySide;
+ else
+ parseManifest(Arg->getValue());
+ }
// Handle /manifestuac
if (auto *Arg = Args.getLastArg(OPT_manifestuac))
parseManifestUAC(Arg->getValue());
- // Handle /manifestdependency
- if (auto *Arg = Args.getLastArg(OPT_manifestdependency))
- Config->ManifestDependency = Arg->getValue();
-
// Handle /manifestfile
if (auto *Arg = Args.getLastArg(OPT_manifestfile))
Config->ManifestFile = Arg->getValue();
@@ -642,9 +926,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
for (auto *Arg : Args.filtered(OPT_manifestinput))
Config->ManifestInput.push_back(Arg->getValue());
+ if (!Config->ManifestInput.empty() &&
+ Config->Manifest != Configuration::Embed) {
+ fatal("/MANIFESTINPUT: requires /MANIFEST:EMBED");
+ }
+
// Handle miscellaneous boolean flags.
- if (Args.hasArg(OPT_allowbind_no))
- Config->AllowBind = false;
if (Args.hasArg(OPT_allowisolation_no))
Config->AllowIsolation = false;
if (Args.hasArg(OPT_dynamicbase_no))
@@ -655,8 +942,11 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->TerminalServerAware = false;
if (Args.hasArg(OPT_nosymtab))
Config->WriteSymtab = false;
- Config->DumpPdb = Args.hasArg(OPT_dumppdb);
- Config->DebugPdb = Args.hasArg(OPT_debugpdb);
+
+ Config->MapFile = getMapFile(Args);
+
+ if (ErrorCount)
+ return;
// Create a list of input files. Files can be given as arguments
// for /defaultlib option.
@@ -678,13 +968,13 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// We should have inferred a machine type by now from the input files, but if
// not we assume x64.
if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
- errs() << "warning: /machine is not specified. x64 is assumed.\n";
+ warn("/machine is not specified. x64 is assumed");
Config->Machine = AMD64;
}
- // Windows specific -- Input files can be Windows resource files (.res files).
- // We invoke cvtres.exe to convert resource files to a regular COFF file
- // then link the result file normally.
+ // Input files can be Windows resource files (.res files). We use
+ // WindowsResource to convert resource files to a regular COFF file,
+ // then link the resulting file normally.
if (!Resources.empty())
addBuffer(convertResToCOFF(Resources));
@@ -715,8 +1005,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (S.empty())
fatal("entry point must be defined");
Config->Entry = addUndefined(S);
- if (Config->Verbose)
- outs() << "Entry name inferred: " << S << "\n";
+ log("Entry name inferred: " + S);
}
// Handle /export
@@ -734,9 +1023,14 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /def
if (auto *Arg = Args.getLastArg(OPT_deffile)) {
// parseModuleDefs mutates Config object.
- parseModuleDefs(
- takeBuffer(check(MemoryBuffer::getFile(Arg->getValue()),
- Twine("could not open ") + Arg->getValue())));
+ parseModuleDefs(Arg->getValue());
+ }
+
+ // Handle generation of import library from a def file.
+ if (!Args.hasArgNoClaim(OPT_INPUT)) {
+ fixupExports();
+ createImportLibrary(/*AsLib=*/true);
+ exit(0);
}
// Handle /delayload
@@ -749,21 +1043,41 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
}
}
+ // Set default image name if neither /out or /def set it.
+ if (Config->OutputFile.empty()) {
+ Config->OutputFile =
+ getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue());
+ }
+
+ // Put the PDB next to the image if no /pdb flag was passed.
+ if (Config->Debug && Config->PDBPath.empty()) {
+ Config->PDBPath = Config->OutputFile;
+ sys::path::replace_extension(Config->PDBPath, ".pdb");
+ }
+
+ // Disable PDB generation if the user requested it.
+ if (Args.hasArg(OPT_nopdb))
+ Config->PDBPath = "";
+
// Set default image base if /base is not given.
if (Config->ImageBase == uint64_t(-1))
Config->ImageBase = getDefaultImageBase();
- Symtab.addRelative(mangle("__ImageBase"), 0);
+ Symtab.addSynthetic(mangle("__ImageBase"), nullptr);
if (Config->Machine == I386) {
- Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0);
- Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0);
+ Symtab.addAbsolute("___safe_se_handler_table", 0);
+ Symtab.addAbsolute("___safe_se_handler_count", 0);
}
// We do not support /guard:cf (control flow protection) yet.
// Define CFG symbols anyway so that we can link MSVC 2015 CRT.
- Symtab.addAbsolute(mangle("__guard_fids_table"), 0);
Symtab.addAbsolute(mangle("__guard_fids_count"), 0);
+ Symtab.addAbsolute(mangle("__guard_fids_table"), 0);
Symtab.addAbsolute(mangle("__guard_flags"), 0x100);
+ Symtab.addAbsolute(mangle("__guard_iat_count"), 0);
+ Symtab.addAbsolute(mangle("__guard_iat_table"), 0);
+ Symtab.addAbsolute(mangle("__guard_longjmp_count"), 0);
+ Symtab.addAbsolute(mangle("__guard_longjmp_table"), 0);
// This code may add new undefined symbols to the link, which may enqueue more
// symbol resolution tasks, so we need to continue executing tasks until we
@@ -801,6 +1115,16 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
addUndefined(mangle("_load_config_used"));
} while (run());
+ if (ErrorCount)
+ return;
+
+ // If /msvclto is given, we use the MSVC linker to link LTO output files.
+ // This is useful because MSVC link.exe can generate complete PDBs.
+ if (Args.hasArg(OPT_msvclto)) {
+ invokeMSVC(Args);
+ exit(0);
+ }
+
// Do LTO by compiling bitcode input files to a set of native COFF files then
// link those files.
Symtab.addCombinedLTOObjects();
@@ -818,16 +1142,19 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
}
// Handle /safeseh.
- if (Args.hasArg(OPT_safeseh))
+ if (Args.hasArg(OPT_safeseh)) {
for (ObjectFile *File : Symtab.ObjectFiles)
if (!File->SEHCompat)
- fatal("/safeseh: " + File->getName() + " is not compatible with SEH");
+ error("/safeseh: " + File->getName() + " is not compatible with SEH");
+ if (ErrorCount)
+ return;
+ }
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file.
if (!Config->Exports.empty() || Config->DLL) {
fixupExports();
- writeImportLibrary();
+ createImportLibrary(/*AsLib=*/false);
assignExportOrdinals();
}
@@ -846,17 +1173,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Write the result.
writeResult(&Symtab);
- // Create a symbol map file containing symbol VAs and their names
- // to help debugging.
- std::string MapFile = getMapFile(Args);
- if (!MapFile.empty()) {
- std::error_code EC;
- raw_fd_ostream Out(MapFile, EC, OpenFlags::F_Text);
- if (EC)
- fatal(EC, "could not create the symbol map " + MapFile);
- Symtab.printMap(Out);
- }
-
// Call exit to avoid calling destructors.
exit(0);
}
diff --git a/contrib/llvm/tools/lld/COFF/Driver.h b/contrib/llvm/tools/lld/COFF/Driver.h
index 4489426..6879be2 100644
--- a/contrib/llvm/tools/lld/COFF/Driver.h
+++ b/contrib/llvm/tools/lld/COFF/Driver.h
@@ -34,7 +34,6 @@ extern LinkerDriver *Driver;
using llvm::COFF::MachineTypes;
using llvm::COFF::WindowsSubsystem;
using llvm::Optional;
-class InputFile;
// Implemented in MarkLive.cpp.
void markLive(const std::vector<Chunk *> &Chunks);
@@ -48,7 +47,7 @@ public:
llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args);
// Concatenate LINK environment varirable and given arguments and parse them.
- llvm::opt::InputArgList parseLINK(llvm::ArrayRef<const char *> Args);
+ llvm::opt::InputArgList parseLINK(std::vector<const char *> Args);
// Tokenizes a given string and then parses as command line options.
llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
@@ -107,6 +106,8 @@ private:
StringRef findDefaultEntry();
WindowsSubsystem inferSubsystem();
+ void invokeMSVC(llvm::opt::InputArgList &Args);
+
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB);
void addBuffer(std::unique_ptr<MemoryBuffer> MB);
void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
@@ -117,18 +118,11 @@ private:
void enqueueTask(std::function<void()> Task);
bool run();
- // Driver is the owner of all opened files.
- // InputFiles have MemoryBufferRefs to them.
- std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
-
std::list<std::function<void()>> TaskQueue;
std::vector<StringRef> FilePaths;
std::vector<MemoryBufferRef> Resources;
};
-void parseModuleDefs(MemoryBufferRef MB);
-void writeImportLibrary();
-
// Functions below this line are defined in DriverUtils.cpp.
void printHelp(const char *Argv0);
@@ -178,10 +172,12 @@ void checkFailIfMismatch(StringRef Arg);
std::unique_ptr<MemoryBuffer>
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs);
+void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects);
+
// Create enum with OPT_xxx values for each option in Options.td
enum {
OPT_INVALID = 0,
-#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
#include "Options.inc"
#undef OPTION
};
diff --git a/contrib/llvm/tools/lld/COFF/DriverUtils.cpp b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
index 14dd004..39d5824 100644
--- a/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
+++ b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp
@@ -20,12 +20,15 @@
#include "Symbols.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/COFF.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Object/WindowsResource.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
@@ -41,34 +44,37 @@ namespace lld {
namespace coff {
namespace {
+const uint16_t SUBLANG_ENGLISH_US = 0x0409;
+const uint16_t RT_MANIFEST = 24;
+
class Executor {
public:
- explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {}
- void add(StringRef S) { Args.push_back(Saver.save(S).data()); }
- void add(std::string &S) { Args.push_back(Saver.save(S).data()); }
- void add(Twine S) { Args.push_back(Saver.save(S).data()); }
- void add(const char *S) { Args.push_back(Saver.save(S).data()); }
+ explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
+ void add(StringRef S) { Args.push_back(Saver.save(S)); }
+ void add(std::string &S) { Args.push_back(Saver.save(S)); }
+ void add(Twine S) { Args.push_back(Saver.save(S)); }
+ void add(const char *S) { Args.push_back(Saver.save(S)); }
void run() {
ErrorOr<std::string> ExeOrErr = sys::findProgramByName(Prog);
if (auto EC = ExeOrErr.getError())
fatal(EC, "unable to find " + Prog + " in PATH: ");
- const char *Exe = Saver.save(*ExeOrErr).data();
+ StringRef Exe = Saver.save(*ExeOrErr);
Args.insert(Args.begin(), Exe);
- Args.push_back(nullptr);
- if (sys::ExecuteAndWait(Args[0], Args.data()) != 0) {
- for (const char *S : Args)
- if (S)
- errs() << S << " ";
- fatal("ExecuteAndWait failed");
- }
+
+ std::vector<const char *> Vec;
+ for (StringRef S : Args)
+ Vec.push_back(S.data());
+ Vec.push_back(nullptr);
+
+ if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0)
+ fatal("ExecuteAndWait failed: " +
+ llvm::join(Args.begin(), Args.end(), " "));
}
private:
- BumpPtrAllocator Alloc;
- StringSaver Saver;
StringRef Prog;
- std::vector<const char *> Args;
+ std::vector<StringRef> Args;
};
} // anonymous namespace
@@ -79,6 +85,7 @@ MachineTypes getMachineType(StringRef S) {
.Cases("x64", "amd64", AMD64)
.Cases("x86", "i386", I386)
.Case("arm", ARMNT)
+ .Case("arm64", ARM64)
.Default(IMAGE_FILE_MACHINE_UNKNOWN);
if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
return MT;
@@ -89,6 +96,8 @@ StringRef machineToStr(MachineTypes MT) {
switch (MT) {
case ARMNT:
return "arm";
+ case ARM64:
+ return "arm64";
case AMD64:
return "x64";
case I386:
@@ -167,8 +176,7 @@ void parseMerge(StringRef S) {
if (!Inserted) {
StringRef Existing = Pair.first->second;
if (Existing != To)
- errs() << "warning: " << S << ": already merged into " << Existing
- << "\n";
+ warn(S + ": already merged into " + Existing);
}
}
@@ -258,35 +266,23 @@ void parseManifestUAC(StringRef Arg) {
}
}
-// Quote each line with "". Existing double-quote is converted
-// to two double-quotes.
-static void quoteAndPrint(raw_ostream &Out, StringRef S) {
- while (!S.empty()) {
- StringRef Line;
- std::tie(Line, S) = S.split("\n");
- if (Line.empty())
- continue;
- Out << '\"';
- for (int I = 0, E = Line.size(); I != E; ++I) {
- if (Line[I] == '\"') {
- Out << "\"\"";
- } else {
- Out << Line[I];
- }
- }
- Out << "\"\n";
- }
-}
-
// An RAII temporary file class that automatically removes a temporary file.
namespace {
class TemporaryFile {
public:
- TemporaryFile(StringRef Prefix, StringRef Extn) {
+ TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") {
SmallString<128> S;
if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S))
fatal(EC, "cannot create a temporary file");
Path = S.str();
+
+ if (!Contents.empty()) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+ if (EC)
+ fatal(EC, "failed to open " + Path);
+ OS << Contents;
+ }
}
TemporaryFile(TemporaryFile &&Obj) {
@@ -383,38 +379,62 @@ static std::string createManifestXml() {
return readFile(File2.Path);
}
+static std::unique_ptr<MemoryBuffer>
+createMemoryBufferForManifestRes(size_t ManifestSize) {
+ size_t ResSize = alignTo(
+ object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
+ sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
+ sizeof(object::WinResHeaderSuffix) + ManifestSize,
+ object::WIN_RES_DATA_ALIGNMENT);
+ return MemoryBuffer::getNewMemBuffer(ResSize);
+}
+
+static void writeResFileHeader(char *&Buf) {
+ memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));
+ Buf += sizeof(COFF::WinResMagic);
+ memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);
+ Buf += object::WIN_RES_NULL_ENTRY_SIZE;
+}
+
+static void writeResEntryHeader(char *&Buf, size_t ManifestSize) {
+ // Write the prefix.
+ auto *Prefix = reinterpret_cast<object::WinResHeaderPrefix *>(Buf);
+ Prefix->DataSize = ManifestSize;
+ Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
+ sizeof(object::WinResIDs) +
+ sizeof(object::WinResHeaderSuffix);
+ Buf += sizeof(object::WinResHeaderPrefix);
+
+ // Write the Type/Name IDs.
+ auto *IDs = reinterpret_cast<object::WinResIDs *>(Buf);
+ IDs->setType(RT_MANIFEST);
+ IDs->setName(Config->ManifestID);
+ Buf += sizeof(object::WinResIDs);
+
+ // Write the suffix.
+ auto *Suffix = reinterpret_cast<object::WinResHeaderSuffix *>(Buf);
+ Suffix->DataVersion = 0;
+ Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
+ Suffix->Language = SUBLANG_ENGLISH_US;
+ Suffix->Version = 0;
+ Suffix->Characteristics = 0;
+ Buf += sizeof(object::WinResHeaderSuffix);
+}
+
// Create a resource file containing a manifest XML.
std::unique_ptr<MemoryBuffer> createManifestRes() {
- // Create a temporary file for the resource script file.
- TemporaryFile RCFile("manifest", "rc");
+ std::string Manifest = createManifestXml();
- // Open the temporary file for writing.
- std::error_code EC;
- raw_fd_ostream Out(RCFile.Path, EC, sys::fs::F_Text);
- if (EC)
- fatal(EC, "failed to open " + RCFile.Path);
-
- // Write resource script to the RC file.
- Out << "#define LANG_ENGLISH 9\n"
- << "#define SUBLANG_DEFAULT 1\n"
- << "#define APP_MANIFEST " << Config->ManifestID << "\n"
- << "#define RT_MANIFEST 24\n"
- << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"
- << "APP_MANIFEST RT_MANIFEST {\n";
- quoteAndPrint(Out, createManifestXml());
- Out << "}\n";
- Out.close();
-
- // Create output resource file.
- TemporaryFile ResFile("output-resource", "res");
-
- Executor E("rc.exe");
- E.add("/fo");
- E.add(ResFile.Path);
- E.add("/nologo");
- E.add(RCFile.Path);
- E.run();
- return ResFile.getMemoryBuffer();
+ std::unique_ptr<MemoryBuffer> Res =
+ createMemoryBufferForManifestRes(Manifest.size());
+
+ char *Buf = const_cast<char *>(Res->getBufferStart());
+ writeResFileHeader(Buf);
+ writeResEntryHeader(Buf, Manifest.size());
+
+ // Copy the manifest data into the .res file.
+ std::copy(Manifest.begin(), Manifest.end(), Buf);
+ return Res;
}
void createSideBySideManifest() {
@@ -470,6 +490,10 @@ Export parseExport(StringRef Arg) {
E.Data = true;
continue;
}
+ if (Tok.equals_lower("constant")) {
+ E.Constant = true;
+ continue;
+ }
if (Tok.equals_lower("private")) {
E.Private = true;
continue;
@@ -511,7 +535,7 @@ void fixupExports() {
for (Export &E : Config->Exports) {
SymbolBody *Sym = E.Sym;
- if (!E.ForwardTo.empty()) {
+ if (!E.ForwardTo.empty() || !Sym) {
E.SymbolName = E.Name;
} else {
if (auto *U = dyn_cast<Undefined>(Sym))
@@ -542,7 +566,7 @@ void fixupExports() {
Export *Existing = Pair.first->second;
if (E == *Existing || E.Name != Existing->Name)
continue;
- errs() << "warning: duplicate /export option: " << E.Name << "\n";
+ warn("duplicate /export option: " + E.Name);
}
Config->Exports = std::move(V);
@@ -581,40 +605,42 @@ void checkFailIfMismatch(StringRef Arg) {
// using cvtres.exe.
std::unique_ptr<MemoryBuffer>
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
- // Create an output file path.
- TemporaryFile File("resource-file", "obj");
+ object::WindowsResourceParser Parser;
- // Execute cvtres.exe.
- Executor E("cvtres.exe");
- E.add("/machine:" + machineToStr(Config->Machine));
- E.add("/readonly");
- E.add("/nologo");
- E.add("/out:" + Twine(File.Path));
-
- // We must create new files because the memory buffers we have may have no
- // underlying file still existing on the disk.
- // It happens if it was created from a TemporaryFile, which usually delete
- // the file just after creating the MemoryBuffer.
- std::vector<TemporaryFile> ResFiles;
- ResFiles.reserve(MBs.size());
for (MemoryBufferRef MB : MBs) {
- // We store the temporary file in a vector to avoid deletion
- // before running cvtres
- ResFiles.emplace_back("resource-file", "res");
- TemporaryFile& ResFile = ResFiles.back();
- // Write the content of the resource in a temporary file
- std::error_code EC;
- raw_fd_ostream OS(ResFile.Path, EC, sys::fs::F_None);
- if (EC)
- fatal(EC, "failed to open " + ResFile.Path);
- OS << MB.getBuffer();
- OS.close();
-
- E.add(ResFile.Path);
+ std::unique_ptr<object::Binary> Bin = check(object::createBinary(MB));
+ object::WindowsResource *RF = dyn_cast<object::WindowsResource>(Bin.get());
+ if (!RF)
+ fatal("cannot compile non-resource file as resource");
+ if (auto EC = Parser.parse(RF))
+ fatal(EC, "failed to parse .res file");
+ }
+
+ Expected<std::unique_ptr<MemoryBuffer>> E =
+ llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser);
+ if (!E)
+ fatal(errorToErrorCode(E.takeError()), "failed to write .res to COFF");
+ return std::move(E.get());
+}
+
+// Run MSVC link.exe for given in-memory object files.
+// Command line options are copied from those given to LLD.
+// This is for the /msvclto option.
+void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects) {
+ // Write the in-memory object files to disk.
+ std::vector<TemporaryFile> Temps;
+ for (StringRef S : Objects) {
+ Temps.emplace_back("lto", "obj", S);
+ Rsp += quote(Temps.back().Path) + "\n";
}
+ log("link.exe " + Rsp);
+
+ // Run MSVC link.exe.
+ Temps.emplace_back("lto", "rsp", Rsp);
+ Executor E("link.exe");
+ E.add(Twine("@" + Temps.back().Path));
E.run();
- return File.getMemoryBuffer();
}
// Create OptTable
@@ -626,11 +652,9 @@ convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
// Create table mapping all options defined in Options.td
static const llvm::opt::OptTable::Info infoTable[] = {
-#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \
- { \
- X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \
- OPT_##GROUP, OPT_##ALIAS, X6 \
- },
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
+ {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
#include "Options.inc"
#undef OPTION
};
@@ -653,30 +677,33 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
// Print the real command line if response files are expanded.
if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) {
- outs() << "Command line:";
+ std::string Msg = "Command line:";
for (const char *S : Argv)
- outs() << " " << S;
- outs() << "\n";
+ Msg += " " + std::string(S);
+ message(Msg);
}
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
- errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
+ warn("ignoring unknown argument: " + Arg->getSpelling());
return Args;
}
-// link.exe has an interesting feature. If LINK environment exists,
-// its contents are handled as a command line string. So you can pass
-// extra arguments using the environment variable.
-opt::InputArgList ArgParser::parseLINK(ArrayRef<const char *> Args) {
+// link.exe has an interesting feature. If LINK or _LINK_ environment
+// variables exist, their contents are handled as command line strings.
+// So you can pass extra arguments using them.
+opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Args) {
// Concatenate LINK env and command line arguments, and then parse them.
- Optional<std::string> Env = Process::GetEnv("LINK");
- if (!Env)
- return parse(Args);
- std::vector<const char *> V = tokenize(*Env);
- V.insert(V.end(), Args.begin(), Args.end());
- return parse(V);
+ if (Optional<std::string> S = Process::GetEnv("LINK")) {
+ std::vector<const char *> V = tokenize(*S);
+ Args.insert(Args.begin(), V.begin(), V.end());
+ }
+ if (Optional<std::string> S = Process::GetEnv("_LINK_")) {
+ std::vector<const char *> V = tokenize(*S);
+ Args.insert(Args.begin(), V.begin(), V.end());
+ }
+ return parse(Args);
}
std::vector<const char *> ArgParser::tokenize(StringRef S) {
diff --git a/contrib/llvm/tools/lld/COFF/Error.cpp b/contrib/llvm/tools/lld/COFF/Error.cpp
index b2bd557..34abc28 100644
--- a/contrib/llvm/tools/lld/COFF/Error.cpp
+++ b/contrib/llvm/tools/lld/COFF/Error.cpp
@@ -8,11 +8,14 @@
//===----------------------------------------------------------------------===//
#include "Error.h"
+#include "Config.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
+#include <mutex>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
@@ -21,10 +24,68 @@
using namespace llvm;
namespace lld {
+// The functions defined in this file can be called from multiple threads,
+// but outs() or errs() are not thread-safe. We protect them using a mutex.
+static std::mutex Mu;
+
namespace coff {
+uint64_t ErrorCount;
+raw_ostream *ErrorOS;
+
+static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) {
+ // Dealloc/destroy ManagedStatic variables before calling
+ // _exit(). In a non-LTO build, this is a nop. In an LTO
+ // build allows us to get the output of -time-passes.
+ llvm_shutdown();
+
+ outs().flush();
+ errs().flush();
+ _exit(Val);
+}
+
+static void print(StringRef S, raw_ostream::Colors C) {
+ *ErrorOS << Config->Argv[0] << ": ";
+ if (Config->ColorDiagnostics) {
+ ErrorOS->changeColor(C, true);
+ *ErrorOS << S;
+ ErrorOS->resetColor();
+ } else {
+ *ErrorOS << S;
+ }
+}
+
+void log(const Twine &Msg) {
+ if (Config->Verbose) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ outs() << Config->Argv[0] << ": " << Msg << "\n";
+ outs().flush();
+ }
+}
+
+void message(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ outs() << Msg << "\n";
+ outs().flush();
+}
+
+void error(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+
+ if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << Msg << "\n";
+ } else if (ErrorCount == Config->ErrorLimit) {
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << "too many errors emitted, stopping now"
+ << " (use /ERRORLIMIT:0 to see all errors)\n";
+ exitLld(1);
+ }
+
+ ++ErrorCount;
+}
void fatal(const Twine &Msg) {
- if (sys::Process::StandardErrHasColors()) {
+ if (Config->ColorDiagnostics) {
errs().changeColor(raw_ostream::RED, /*bold=*/true);
errs() << "error: ";
errs().resetColor();
@@ -32,10 +93,7 @@ void fatal(const Twine &Msg) {
errs() << "error: ";
}
errs() << Msg << "\n";
-
- outs().flush();
- errs().flush();
- _exit(1);
+ exitLld(1);
}
void fatal(std::error_code EC, const Twine &Msg) {
@@ -46,5 +104,11 @@ void fatal(llvm::Error &Err, const Twine &Msg) {
fatal(errorToErrorCode(std::move(Err)), Msg);
}
+void warn(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ print("warning: ", raw_ostream::MAGENTA);
+ *ErrorOS << Msg << "\n";
+}
+
} // namespace coff
} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/Error.h b/contrib/llvm/tools/lld/COFF/Error.h
index 4754932..e1e4c1e 100644
--- a/contrib/llvm/tools/lld/COFF/Error.h
+++ b/contrib/llvm/tools/lld/COFF/Error.h
@@ -16,11 +16,18 @@
namespace lld {
namespace coff {
+extern uint64_t ErrorCount;
+extern llvm::raw_ostream *ErrorOS;
+
+void log(const Twine &Msg);
+void message(const Twine &Msg);
+void warn(const Twine &Msg);
+void error(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix);
-template <class T> T check(ErrorOr<T> &&V, const Twine &Prefix) {
+template <class T> T check(ErrorOr<T> V, const Twine &Prefix) {
if (auto EC = V.getError())
fatal(EC, Prefix);
return std::move(*V);
diff --git a/contrib/llvm/tools/lld/COFF/ICF.cpp b/contrib/llvm/tools/lld/COFF/ICF.cpp
index 196fbe2..da8ca36 100644
--- a/contrib/llvm/tools/lld/COFF/ICF.cpp
+++ b/contrib/llvm/tools/lld/COFF/ICF.cpp
@@ -21,9 +21,9 @@
#include "Chunks.h"
#include "Error.h"
#include "Symbols.h"
-#include "lld/Core/Parallel.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Parallel.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <atomic>
@@ -49,14 +49,13 @@ private:
size_t findBoundary(size_t Begin, size_t End);
- void forEachColorRange(size_t Begin, size_t End,
+ void forEachClassRange(size_t Begin, size_t End,
std::function<void(size_t, size_t)> Fn);
- void forEachColor(std::function<void(size_t, size_t)> Fn);
+ void forEachClass(std::function<void(size_t, size_t)> Fn);
std::vector<SectionChunk *> Chunks;
int Cnt = 0;
- std::atomic<uint32_t> NextId = {1};
std::atomic<bool> Repeat = {false};
};
@@ -71,13 +70,21 @@ uint32_t ICF::getHash(SectionChunk *C) {
}
// Returns true if section S is subject of ICF.
+//
+// Microsoft's documentation
+// (https://msdn.microsoft.com/en-us/library/bxwfs976.aspx; visited April
+// 2017) says that /opt:icf folds both functions and read-only data.
+// Despite that, the MSVC linker folds only functions. We found
+// a few instances of programs that are not safe for data merging.
+// Therefore, we merge only functions just like the MSVC tool.
bool ICF::isEligible(SectionChunk *C) {
bool Global = C->Sym && C->Sym->isExternal();
+ bool Executable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE;
bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
- return C->isCOMDAT() && C->isLive() && Global && !Writable;
+ return C->isCOMDAT() && C->isLive() && Global && Executable && !Writable;
}
-// Split a range into smaller ranges by recoloring sections
+// Split an equivalence class into smaller classes.
void ICF::segregate(size_t Begin, size_t End, bool Constant) {
while (Begin < End) {
// Divide [Begin, End) into two. Let Mid be the start index of the
@@ -90,10 +97,10 @@ void ICF::segregate(size_t Begin, size_t End, bool Constant) {
});
size_t Mid = Bound - Chunks.begin();
- // Split [Begin, End) into [Begin, Mid) and [Mid, End).
- uint32_t Id = NextId++;
+ // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an
+ // equivalence class ID because every group ends with a unique index.
for (size_t I = Begin; I < Mid; ++I)
- Chunks[I]->Color[(Cnt + 1) % 2] = Id;
+ Chunks[I]->Class[(Cnt + 1) % 2] = Mid;
// If we created a group, we need to iterate the main loop again.
if (Mid != End)
@@ -122,7 +129,7 @@ bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
if (auto *D1 = dyn_cast<DefinedRegular>(B1))
if (auto *D2 = dyn_cast<DefinedRegular>(B2))
return D1->getValue() == D2->getValue() &&
- D1->getChunk()->Color[Cnt % 2] == D2->getChunk()->Color[Cnt % 2];
+ D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
return false;
};
if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq))
@@ -147,7 +154,7 @@ bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
return true;
if (auto *D1 = dyn_cast<DefinedRegular>(B1))
if (auto *D2 = dyn_cast<DefinedRegular>(B2))
- return D1->getChunk()->Color[Cnt % 2] == D2->getChunk()->Color[Cnt % 2];
+ return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
return false;
};
return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq);
@@ -155,12 +162,12 @@ bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
size_t ICF::findBoundary(size_t Begin, size_t End) {
for (size_t I = Begin + 1; I < End; ++I)
- if (Chunks[Begin]->Color[Cnt % 2] != Chunks[I]->Color[Cnt % 2])
+ if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2])
return I;
return End;
}
-void ICF::forEachColorRange(size_t Begin, size_t End,
+void ICF::forEachClassRange(size_t Begin, size_t End,
std::function<void(size_t, size_t)> Fn) {
if (Begin > 0)
Begin = findBoundary(Begin - 1, End);
@@ -172,22 +179,24 @@ void ICF::forEachColorRange(size_t Begin, size_t End,
}
}
-// Call Fn on each color group.
-void ICF::forEachColor(std::function<void(size_t, size_t)> Fn) {
+// Call Fn on each class group.
+void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
// If the number of sections are too small to use threading,
// call Fn sequentially.
if (Chunks.size() < 1024) {
- forEachColorRange(0, Chunks.size(), Fn);
+ forEachClassRange(0, Chunks.size(), Fn);
+ ++Cnt;
return;
}
// Split sections into 256 shards and call Fn in parallel.
size_t NumShards = 256;
size_t Step = Chunks.size() / NumShards;
- parallel_for(size_t(0), NumShards, [&](size_t I) {
- forEachColorRange(I * Step, (I + 1) * Step, Fn);
+ for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) {
+ size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step;
+ forEachClassRange(I * Step, End, Fn);
});
- forEachColorRange(Step * NumShards, Chunks.size(), Fn);
+ ++Cnt;
}
// Merge identical COMDAT sections.
@@ -195,55 +204,48 @@ void ICF::forEachColor(std::function<void(size_t, size_t)> Fn) {
// contents and relocations are all the same.
void ICF::run(const std::vector<Chunk *> &Vec) {
// Collect only mergeable sections and group by hash value.
+ uint32_t NextId = 1;
for (Chunk *C : Vec) {
- auto *SC = dyn_cast<SectionChunk>(C);
- if (!SC)
- continue;
-
- if (isEligible(SC)) {
- // Set MSB to 1 to avoid collisions with non-hash colors.
- SC->Color[0] = getHash(SC) | (1 << 31);
- Chunks.push_back(SC);
- } else {
- SC->Color[0] = NextId++;
+ if (auto *SC = dyn_cast<SectionChunk>(C)) {
+ if (isEligible(SC))
+ Chunks.push_back(SC);
+ else
+ SC->Class[0] = NextId++;
}
}
- if (Chunks.empty())
- return;
+ // Initially, we use hash values to partition sections.
+ for (SectionChunk *SC : Chunks)
+ // Set MSB to 1 to avoid collisions with non-hash classs.
+ SC->Class[0] = getHash(SC) | (1 << 31);
// From now on, sections in Chunks are ordered so that sections in
// the same group are consecutive in the vector.
std::stable_sort(Chunks.begin(), Chunks.end(),
[](SectionChunk *A, SectionChunk *B) {
- return A->Color[0] < B->Color[0];
+ return A->Class[0] < B->Class[0];
});
// Compare static contents and assign unique IDs for each static content.
- forEachColor([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
- ++Cnt;
+ forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
// Split groups by comparing relocations until convergence is obtained.
do {
Repeat = false;
- forEachColor(
+ forEachClass(
[&](size_t Begin, size_t End) { segregate(Begin, End, false); });
- ++Cnt;
} while (Repeat);
- if (Config->Verbose)
- outs() << "\nICF needed " << Cnt << " iterations\n";
+ log("ICF needed " + Twine(Cnt) + " iterations");
- // Merge sections in the same colors.
- forEachColor([&](size_t Begin, size_t End) {
+ // Merge sections in the same classs.
+ forEachClass([&](size_t Begin, size_t End) {
if (End - Begin == 1)
return;
- if (Config->Verbose)
- outs() << "Selected " << Chunks[Begin]->getDebugName() << "\n";
+ log("Selected " + Chunks[Begin]->getDebugName());
for (size_t I = Begin + 1; I < End; ++I) {
- if (Config->Verbose)
- outs() << " Removed " << Chunks[I]->getDebugName() << "\n";
+ log(" Removed " + Chunks[I]->getDebugName());
Chunks[Begin]->replace(Chunks[I]);
}
});
diff --git a/contrib/llvm/tools/lld/COFF/InputFiles.cpp b/contrib/llvm/tools/lld/COFF/InputFiles.cpp
index cde355c..7d41cae 100644
--- a/contrib/llvm/tools/lld/COFF/InputFiles.cpp
+++ b/contrib/llvm/tools/lld/COFF/InputFiles.cpp
@@ -19,11 +19,9 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/LTO/legacy/LTOModule.h"
+#include "llvm/BinaryFormat/COFF.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
-#include "llvm/Support/COFF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
@@ -41,13 +39,21 @@ using namespace llvm::support::endian;
using llvm::Triple;
using llvm::support::ulittle32_t;
-using llvm::sys::fs::file_magic;
-using llvm::sys::fs::identify_magic;
namespace lld {
namespace coff {
-LLVMContext BitcodeFile::Context;
+/// Checks that Source is compatible with being a weak alias to Target.
+/// If Source is Undefined and has no weak alias set, makes it a weak
+/// alias to Target.
+static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,
+ SymbolBody *Source, SymbolBody *Target) {
+ if (auto *U = dyn_cast<Undefined>(Source)) {
+ if (U->WeakAlias && U->WeakAlias != Target)
+ Symtab->reportDuplicate(Source->symbol(), F);
+ U->WeakAlias = Target;
+ }
+}
ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
@@ -126,17 +132,17 @@ void ObjectFile::initializeChunks() {
if (!Config->Debug && Name.startswith(".debug"))
continue;
- // CodeView sections are stored to a different vector because they are
- // not linked in the regular manner.
- if (Name == ".debug" || Name.startswith(".debug$")) {
- DebugChunks.push_back(new (Alloc) SectionChunk(this, Sec));
- continue;
- }
-
if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
continue;
- auto *C = new (Alloc) SectionChunk(this, Sec);
- Chunks.push_back(C);
+ auto *C = make<SectionChunk>(this, Sec);
+
+ // CodeView sections are stored to a different vector because they are not
+ // linked in the regular manner.
+ if (C->isCodeView())
+ DebugChunks.push_back(C);
+ else
+ Chunks.push_back(C);
+
SparseChunks[I] = C;
}
}
@@ -145,8 +151,10 @@ void ObjectFile::initializeSymbols() {
uint32_t NumSymbols = COFFObj->getNumberOfSymbols();
SymbolBodies.reserve(NumSymbols);
SparseSymbolBodies.resize(NumSymbols);
+
SmallVector<std::pair<SymbolBody *, uint32_t>, 8> WeakAliases;
int32_t LastSectionNumber = 0;
+
for (uint32_t I = 0; I < NumSymbols; ++I) {
// Get a COFFSymbolRef object.
ErrorOr<COFFSymbolRef> SymOrErr = COFFObj->getSymbol(I);
@@ -177,14 +185,11 @@ void ObjectFile::initializeSymbols() {
I += Sym.getNumberOfAuxSymbols();
LastSectionNumber = Sym.getSectionNumber();
}
- for (auto WeakAlias : WeakAliases) {
- auto *U = dyn_cast<Undefined>(WeakAlias.first);
- if (!U)
- continue;
- // Report an error if two undefined symbols have different weak aliases.
- if (U->WeakAlias && U->WeakAlias != SparseSymbolBodies[WeakAlias.second])
- Symtab->reportDuplicate(U->symbol(), this);
- U->WeakAlias = SparseSymbolBodies[WeakAlias.second];
+
+ for (auto &KV : WeakAliases) {
+ SymbolBody *Sym = KV.first;
+ uint32_t Idx = KV.second;
+ checkAndSetWeakAlias(Symtab, this, Sym, SparseSymbolBodies[Idx]);
}
}
@@ -198,9 +203,12 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
bool IsFirst) {
StringRef Name;
if (Sym.isCommon()) {
- auto *C = new (Alloc) CommonChunk(Sym);
+ auto *C = make<CommonChunk>(Sym);
Chunks.push_back(C);
- return Symtab->addCommon(this, Sym, C)->body();
+ COFFObj->getSymbolName(Sym, Name);
+ Symbol *S =
+ Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C);
+ return S->body();
}
if (Sym.isAbsolute()) {
COFFObj->getSymbolName(Sym, Name);
@@ -216,7 +224,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
if (Sym.isExternal())
return Symtab->addAbsolute(Name, Sym)->body();
else
- return new (Alloc) DefinedAbsolute(Name, Sym);
+ return make<DefinedAbsolute>(Name, Sym);
}
int32_t SectionNumber = Sym.getSectionNumber();
if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
@@ -241,16 +249,24 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
auto *Aux = reinterpret_cast<const coff_aux_section_definition *>(AuxP);
if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
if (auto *ParentSC = cast_or_null<SectionChunk>(
- SparseChunks[Aux->getNumber(Sym.isBigObj())]))
+ SparseChunks[Aux->getNumber(Sym.isBigObj())])) {
ParentSC->addAssociative(SC);
+ // If we already discarded the parent, discard the child.
+ if (ParentSC->isDiscarded())
+ SC->markDiscarded();
+ }
SC->Checksum = Aux->CheckSum;
}
DefinedRegular *B;
- if (Sym.isExternal())
- B = cast<DefinedRegular>(Symtab->addRegular(this, Sym, SC)->body());
- else
- B = new (Alloc) DefinedRegular(this, Sym, SC);
+ if (Sym.isExternal()) {
+ COFFObj->getSymbolName(Sym, Name);
+ Symbol *S =
+ Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC);
+ B = cast<DefinedRegular>(S->body());
+ } else
+ B = make<DefinedRegular>(this, /*Name*/ "", SC->isCOMDAT(),
+ /*IsExternal*/ false, Sym.getGeneric(), SC);
if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
SC->setSymbol(B);
@@ -292,8 +308,8 @@ void ImportFile::parse() {
fatal("broken import library");
// Read names and create an __imp_ symbol.
- StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr)));
- StringRef ImpName = StringAlloc.save("__imp_" + Name);
+ StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr)));
+ StringRef ImpName = Saver.save("__imp_" + Name);
const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
DLLName = StringRef(NameStart);
StringRef ExtName;
@@ -318,6 +334,9 @@ void ImportFile::parse() {
ImpSym = cast<DefinedImportData>(
Symtab->addImportData(ImpName, this)->body());
+ if (Hdr->getType() == llvm::COFF::IMPORT_CONST)
+ ConstSym =
+ cast<DefinedImportData>(Symtab->addImportData(Name, this)->body());
// If type is function, we need to create a thunk which jump to an
// address pointed by the __imp_ symbol. (This allows you to call
@@ -329,45 +348,40 @@ void ImportFile::parse() {
}
void BitcodeFile::parse() {
- Context.enableDebugTypeODRUniquing();
- ErrorOr<std::unique_ptr<LTOModule>> ModOrErr = LTOModule::createFromBuffer(
- Context, MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions());
- M = check(std::move(ModOrErr), "could not create LTO module");
-
- StringSaver Saver(Alloc);
- for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) {
- lto_symbol_attributes Attrs = M->getSymbolAttributes(I);
- if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
- continue;
-
- StringRef SymName = Saver.save(M->getSymbolName(I));
- int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK;
- if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) {
- SymbolBodies.push_back(Symtab->addUndefined(SymName, this, false)->body());
+ Obj = check(lto::InputFile::create(MemoryBufferRef(
+ MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier()))));
+ for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) {
+ StringRef SymName = Saver.save(ObjSym.getName());
+ Symbol *Sym;
+ if (ObjSym.isUndefined()) {
+ Sym = Symtab->addUndefined(SymName, this, false);
+ } else if (ObjSym.isCommon()) {
+ Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize());
+ } else if (ObjSym.isWeak() && ObjSym.isIndirect()) {
+ // Weak external.
+ Sym = Symtab->addUndefined(SymName, this, true);
+ std::string Fallback = ObjSym.getCOFFWeakExternalFallback();
+ SymbolBody *Alias = Symtab->addUndefined(Saver.save(Fallback));
+ checkAndSetWeakAlias(Symtab, this, Sym->body(), Alias);
} else {
- bool Replaceable =
- (SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common
- (Attrs & LTO_SYMBOL_COMDAT) || // comdat
- (SymbolDef == LTO_SYMBOL_DEFINITION_WEAK && // weak external
- (Attrs & LTO_SYMBOL_ALIAS)));
- SymbolBodies.push_back(
- Symtab->addBitcode(this, SymName, Replaceable)->body());
+ bool IsCOMDAT = ObjSym.getComdatIndex() != -1;
+ Sym = Symtab->addRegular(this, SymName, IsCOMDAT);
}
+ SymbolBodies.push_back(Sym->body());
}
-
- Directives = M->getLinkerOpts();
+ Directives = Obj->getCOFFLinkerOpts();
}
MachineTypes BitcodeFile::getMachineType() {
- if (!M)
- return IMAGE_FILE_MACHINE_UNKNOWN;
- switch (Triple(M->getTargetTriple()).getArch()) {
+ switch (Triple(Obj->getTargetTriple()).getArch()) {
case Triple::x86_64:
return AMD64;
case Triple::x86:
return I386;
case Triple::arm:
return ARMNT;
+ case Triple::aarch64:
+ return ARM64;
default:
return IMAGE_FILE_MACHINE_UNKNOWN;
}
diff --git a/contrib/llvm/tools/lld/COFF/InputFiles.h b/contrib/llvm/tools/lld/COFF/InputFiles.h
index 1b5d429..99868d9 100644
--- a/contrib/llvm/tools/lld/COFF/InputFiles.h
+++ b/contrib/llvm/tools/lld/COFF/InputFiles.h
@@ -10,11 +10,11 @@
#ifndef LLD_COFF_INPUT_FILES_H
#define LLD_COFF_INPUT_FILES_H
+#include "Config.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/LTO/legacy/LTOModule.h"
+#include "llvm/LTO/LTO.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/StringSaver.h"
@@ -22,10 +22,15 @@
#include <set>
#include <vector>
+namespace llvm {
+namespace pdb {
+class DbiModuleDescriptorBuilder;
+}
+}
+
namespace lld {
namespace coff {
-using llvm::LTOModule;
using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
using llvm::COFF::MachineTypes;
using llvm::object::Archive;
@@ -60,6 +65,8 @@ public:
// Returns the CPU type this file was compiled to.
virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; }
+ MemoryBufferRef MB;
+
// An archive file name if this file is created from an archive.
StringRef ParentName;
@@ -69,7 +76,6 @@ public:
protected:
InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
- MemoryBufferRef MB;
std::string Directives;
private:
@@ -122,6 +128,12 @@ public:
// COFF-specific and x86-only.
std::set<SymbolBody *> SEHandlers;
+ // Pointer to the PDB module descriptor builder. Various debug info records
+ // will reference object files by "module index", which is here. Things like
+ // source files and section contributions are also recorded here. Will be null
+ // if we are not producing a PDB.
+ llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr;
+
private:
void initializeChunks();
void initializeSymbols();
@@ -131,7 +143,6 @@ private:
SymbolBody *createUndefined(COFFSymbolRef Sym);
std::unique_ptr<COFFObjectFile> COFFObj;
- llvm::BumpPtrAllocator Alloc;
const coff_section *SXData = nullptr;
// List of all chunks defined by this file. This includes both section
@@ -164,24 +175,30 @@ private:
class ImportFile : public InputFile {
public:
explicit ImportFile(MemoryBufferRef M)
- : InputFile(ImportKind, M), StringAlloc(StringAllocAux) {}
+ : InputFile(ImportKind, M), Live(!Config->DoGC) {}
+
static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
DefinedImportData *ImpSym = nullptr;
+ DefinedImportData *ConstSym = nullptr;
DefinedImportThunk *ThunkSym = nullptr;
std::string DLLName;
private:
void parse() override;
- llvm::BumpPtrAllocator Alloc;
- llvm::BumpPtrAllocator StringAllocAux;
- llvm::StringSaver StringAlloc;
-
public:
StringRef ExternalName;
const coff_import_header *Hdr;
Chunk *Location = nullptr;
+
+ // We want to eliminate dllimported symbols if no one actually refers them.
+ // This "Live" bit is used to keep track of which import library members
+ // are actually in use.
+ //
+ // If the Live bit is turned off by MarkLive, Writer will ignore dllimported
+ // symbols provided by this import library member.
+ bool Live;
};
// Used for LTO.
@@ -191,16 +208,12 @@ public:
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
std::vector<SymbolBody *> &getSymbols() { return SymbolBodies; }
MachineTypes getMachineType() override;
- std::unique_ptr<LTOModule> takeModule() { return std::move(M); }
-
- static llvm::LLVMContext Context;
+ std::unique_ptr<llvm::lto::InputFile> Obj;
private:
void parse() override;
std::vector<SymbolBody *> SymbolBodies;
- llvm::BumpPtrAllocator Alloc;
- std::unique_ptr<LTOModule> M;
};
} // namespace coff
diff --git a/contrib/llvm/tools/lld/COFF/LTO.cpp b/contrib/llvm/tools/lld/COFF/LTO.cpp
new file mode 100644
index 0000000..6883b3b
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/LTO.cpp
@@ -0,0 +1,140 @@
+//===- LTO.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LTO.h"
+#include "Config.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "lld/Core/TargetOptionsCommandFlags.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::coff;
+
+static void diagnosticHandler(const DiagnosticInfo &DI) {
+ SmallString<128> ErrStorage;
+ raw_svector_ostream OS(ErrStorage);
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+ warn(ErrStorage);
+}
+
+static void checkError(Error E) {
+ handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
+ error(EIB.message());
+ return Error::success();
+ });
+}
+
+static void saveBuffer(StringRef Buffer, const Twine &Path) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
+ if (EC)
+ error("cannot create " + Path + ": " + EC.message());
+ OS << Buffer;
+}
+
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config Conf;
+ Conf.Options = InitTargetOptionsFromCodeGenFlags();
+ Conf.RelocModel = Reloc::PIC_;
+ Conf.DisableVerify = true;
+ Conf.DiagHandler = diagnosticHandler;
+ Conf.OptLevel = Config->LTOOptLevel;
+ if (Config->SaveTemps)
+ checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
+ /*UseInputModulePath*/ true));
+ lto::ThinBackend Backend;
+ if (Config->LTOJobs != 0)
+ Backend = lto::createInProcessThinBackend(Config->LTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
+ Config->LTOPartitions);
+}
+
+BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+
+BitcodeCompiler::~BitcodeCompiler() = default;
+
+static void undefine(Symbol *S) {
+ replaceBody<Undefined>(S, S->body()->getName());
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+ lto::InputFile &Obj = *F.Obj;
+ unsigned SymNum = 0;
+ std::vector<SymbolBody *> SymBodies = F.getSymbols();
+ std::vector<lto::SymbolResolution> Resols(SymBodies.size());
+
+ // Provide a resolution to the LTO API for each symbol.
+ for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
+ SymbolBody *B = SymBodies[SymNum];
+ Symbol *Sym = B->symbol();
+ lto::SymbolResolution &R = Resols[SymNum];
+ ++SymNum;
+
+ // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+ // reports two symbols for module ASM defined. Without this check, lld
+ // flags an undefined in IR with a definition in ASM as prevailing.
+ // Once IRObjectFile is fixed to report only one symbol this hack can
+ // be removed.
+ R.Prevailing = !ObjSym.isUndefined() && B->getFile() == &F;
+ R.VisibleToRegularObj = Sym->IsUsedInRegularObj;
+ if (R.Prevailing)
+ undefine(Sym);
+ }
+ checkError(LTOObj->add(std::move(F.Obj), Resols));
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting objects.
+std::vector<StringRef> BitcodeCompiler::compile() {
+ unsigned MaxTasks = LTOObj->getMaxTasks();
+ Buff.resize(MaxTasks);
+
+ checkError(LTOObj->run([&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ }));
+
+ std::vector<StringRef> Ret;
+ for (unsigned I = 0; I != MaxTasks; ++I) {
+ if (Buff[I].empty())
+ continue;
+ if (Config->SaveTemps) {
+ if (I == 0)
+ saveBuffer(Buff[I], Config->OutputFile + ".lto.obj");
+ else
+ saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj");
+ }
+ Ret.emplace_back(Buff[I].data(), Buff[I].size());
+ }
+ return Ret;
+}
diff --git a/contrib/llvm/tools/lld/COFF/LTO.h b/contrib/llvm/tools/lld/COFF/LTO.h
new file mode 100644
index 0000000..194a4cc
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/LTO.h
@@ -0,0 +1,56 @@
+//===- LTO.h ----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a way to combine bitcode files into one COFF
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular COFF files
+// but instead LLVM bitcode files. In that case, the linker has to
+// convert bitcode files into the native format so that we can create
+// a COFF file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_LTO_H
+#define LLD_COFF_LTO_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace lto {
+class LTO;
+}
+}
+
+namespace lld {
+namespace coff {
+
+class BitcodeFile;
+class InputFile;
+
+class BitcodeCompiler {
+public:
+ BitcodeCompiler();
+ ~BitcodeCompiler();
+
+ void add(BitcodeFile &F);
+ std::vector<StringRef> compile();
+
+private:
+ std::unique_ptr<llvm::lto::LTO> LTOObj;
+ std::vector<SmallString<0>> Buff;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/Librarian.cpp b/contrib/llvm/tools/lld/COFF/Librarian.cpp
deleted file mode 100644
index 4c597fa..0000000
--- a/contrib/llvm/tools/lld/COFF/Librarian.cpp
+++ /dev/null
@@ -1,494 +0,0 @@
-//===- Librarian.cpp ------------------------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains functions for the Librarian. The librarian creates and
-// manages libraries of the Common Object File Format (COFF) object files. It
-// primarily is used for creating static libraries and import libraries.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Config.h"
-#include "Driver.h"
-#include "Error.h"
-#include "Symbols.h"
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/ArchiveWriter.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/Path.h"
-
-#include <vector>
-
-using namespace lld::coff;
-using namespace llvm::COFF;
-using namespace llvm::object;
-using namespace llvm;
-
-static bool is32bit() {
- switch (Config->Machine) {
- default:
- llvm_unreachable("unsupported machine");
- case IMAGE_FILE_MACHINE_AMD64:
- return false;
- case IMAGE_FILE_MACHINE_ARMNT:
- case IMAGE_FILE_MACHINE_I386:
- return true;
- }
-}
-
-static uint16_t getImgRelRelocation() {
- switch (Config->Machine) {
- default:
- llvm_unreachable("unsupported machine");
- case IMAGE_FILE_MACHINE_AMD64:
- return IMAGE_REL_AMD64_ADDR32NB;
- case IMAGE_FILE_MACHINE_ARMNT:
- return IMAGE_REL_ARM_ADDR32NB;
- case IMAGE_FILE_MACHINE_I386:
- return IMAGE_REL_I386_DIR32NB;
- }
-}
-
-template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
- size_t S = B.size();
- B.resize(S + sizeof(T));
- memcpy(&B[S], &Data, sizeof(T));
-}
-
-static void writeStringTable(std::vector<uint8_t> &B,
- ArrayRef<const std::string> Strings) {
- // The COFF string table consists of a 4-byte value which is the size of the
- // table, including the length field itself. This value is followed by the
- // string content itself, which is an array of null-terminated C-style
- // strings. The termination is important as they are referenced to by offset
- // by the symbol entity in the file format.
-
- std::vector<uint8_t>::size_type Pos = B.size();
- std::vector<uint8_t>::size_type Offset = B.size();
-
- // Skip over the length field, we will fill it in later as we will have
- // computed the length while emitting the string content itself.
- Pos += sizeof(uint32_t);
-
- for (const auto &S : Strings) {
- B.resize(Pos + S.length() + 1);
- strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
- Pos += S.length() + 1;
- }
-
- // Backfill the length of the table now that it has been computed.
- support::ulittle32_t Length(B.size() - Offset);
- memcpy(&B[Offset], &Length, sizeof(Length));
-}
-
-static std::string getImplibPath() {
- if (!Config->Implib.empty())
- return Config->Implib;
- SmallString<128> Out = StringRef(Config->OutputFile);
- sys::path::replace_extension(Out, ".lib");
- return Out.str();
-}
-
-static ImportNameType getNameType(StringRef Sym, StringRef ExtName) {
- if (Sym != ExtName)
- return IMPORT_NAME_UNDECORATE;
- if (Config->Machine == I386 && Sym.startswith("_"))
- return IMPORT_NAME_NOPREFIX;
- return IMPORT_NAME;
-}
-
-static std::string replace(StringRef S, StringRef From, StringRef To) {
- size_t Pos = S.find(From);
- assert(Pos != StringRef::npos);
- return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
-}
-
-static const std::string NullImportDescriptorSymbolName =
- "__NULL_IMPORT_DESCRIPTOR";
-
-namespace {
-// This class constructs various small object files necessary to support linking
-// symbols imported from a DLL. The contents are pretty strictly defined and
-// nearly entirely static. The details of the structures files are defined in
-// WINNT.h and the PE/COFF specification.
-class ObjectFactory {
- using u16 = support::ulittle16_t;
- using u32 = support::ulittle32_t;
-
- BumpPtrAllocator Alloc;
- StringRef DLLName;
- StringRef Library;
- std::string ImportDescriptorSymbolName;
- std::string NullThunkSymbolName;
-
-public:
- ObjectFactory(StringRef S)
- : DLLName(S), Library(S.drop_back(4)),
- ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
- NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
-
- // Creates an Import Descriptor. This is a small object file which contains a
- // reference to the terminators and contains the library name (entry) for the
- // import name table. It will force the linker to construct the necessary
- // structure to import symbols from the DLL.
- NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
-
- // Creates a NULL import descriptor. This is a small object file whcih
- // contains a NULL import descriptor. It is used to terminate the imports
- // from a specific DLL.
- NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
-
- // Create a NULL Thunk Entry. This is a small object file which contains a
- // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
- // is used to terminate the IAT and ILT.
- NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
-
- // Create a short import file which is described in PE/COFF spec 7. Import
- // Library Format.
- NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
- ImportNameType NameType, bool isData);
-};
-}
-
-NewArchiveMember
-ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
- static const uint32_t NumberOfSections = 2;
- static const uint32_t NumberOfSymbols = 7;
- static const uint32_t NumberOfRelocations = 3;
-
- // COFF Header
- coff_file_header Header{
- u16(Config->Machine), u16(NumberOfSections), u32(0),
- u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
- // .idata$2
- sizeof(coff_import_directory_table_entry) +
- NumberOfRelocations * sizeof(coff_relocation) +
- // .idata$4
- (DLLName.size() + 1)),
- u32(NumberOfSymbols), u16(0),
- u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
- };
- append(Buffer, Header);
-
- // Section Header Table
- static const coff_section SectionTable[NumberOfSections] = {
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
- u32(0),
- u32(0),
- u32(sizeof(coff_import_directory_table_entry)),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
- sizeof(coff_import_directory_table_entry)),
- u32(0),
- u16(NumberOfRelocations),
- u16(0),
- u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
- IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
- u32(0),
- u32(0),
- u32(DLLName.size() + 1),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
- sizeof(coff_import_directory_table_entry) +
- NumberOfRelocations * sizeof(coff_relocation)),
- u32(0),
- u32(0),
- u16(0),
- u16(0),
- u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
- IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
- };
- append(Buffer, SectionTable);
-
- // .idata$2
- static const coff_import_directory_table_entry ImportDescriptor{
- u32(0), u32(0), u32(0), u32(0), u32(0),
- };
- append(Buffer, ImportDescriptor);
-
- static const coff_relocation RelocationTable[NumberOfRelocations] = {
- {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
- u16(getImgRelRelocation())},
- {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
- u32(3), u16(getImgRelRelocation())},
- {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
- u32(4), u16(getImgRelRelocation())},
- };
- append(Buffer, RelocationTable);
-
- // .idata$6
- auto S = Buffer.size();
- Buffer.resize(S + DLLName.size() + 1);
- memcpy(&Buffer[S], DLLName.data(), DLLName.size());
- Buffer[S + DLLName.size()] = '\0';
-
- // Symbol Table
- coff_symbol16 SymbolTable[NumberOfSymbols] = {
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(1),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
- u32(0),
- u16(1),
- u16(0),
- IMAGE_SYM_CLASS_SECTION,
- 0},
- {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
- u32(0),
- u16(2),
- u16(0),
- IMAGE_SYM_CLASS_STATIC,
- 0},
- {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_SECTION,
- 0},
- {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_SECTION,
- 0},
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- };
- reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
- sizeof(uint32_t);
- reinterpret_cast<StringTableOffset &>(SymbolTable[5].Name).Offset =
- sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
- reinterpret_cast<StringTableOffset &>(SymbolTable[6].Name).Offset =
- sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
- NullImportDescriptorSymbolName.length() + 1;
- append(Buffer, SymbolTable);
-
- // String Table
- writeStringTable(Buffer,
- {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
- NullThunkSymbolName});
-
- StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
- return {MemoryBufferRef(F, DLLName)};
-}
-
-NewArchiveMember
-ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
- static const uint32_t NumberOfSections = 1;
- static const uint32_t NumberOfSymbols = 1;
-
- // COFF Header
- coff_file_header Header{
- u16(Config->Machine), u16(NumberOfSections), u32(0),
- u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
- // .idata$3
- sizeof(coff_import_directory_table_entry)),
- u32(NumberOfSymbols), u16(0),
- u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
- };
- append(Buffer, Header);
-
- // Section Header Table
- static const coff_section SectionTable[NumberOfSections] = {
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
- u32(0),
- u32(0),
- u32(sizeof(coff_import_directory_table_entry)),
- u32(sizeof(coff_file_header) +
- (NumberOfSections * sizeof(coff_section))),
- u32(0),
- u32(0),
- u16(0),
- u16(0),
- u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
- IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
- };
- append(Buffer, SectionTable);
-
- // .idata$3
- static const coff_import_directory_table_entry ImportDescriptor{
- u32(0), u32(0), u32(0), u32(0), u32(0),
- };
- append(Buffer, ImportDescriptor);
-
- // Symbol Table
- coff_symbol16 SymbolTable[NumberOfSymbols] = {
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(1),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- };
- reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
- sizeof(uint32_t);
- append(Buffer, SymbolTable);
-
- // String Table
- writeStringTable(Buffer, {NullImportDescriptorSymbolName});
-
- StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
- return {MemoryBufferRef(F, DLLName)};
-}
-
-NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
- static const uint32_t NumberOfSections = 2;
- static const uint32_t NumberOfSymbols = 1;
- uint32_t VASize = is32bit() ? 4 : 8;
-
- // COFF Header
- coff_file_header Header{
- u16(Config->Machine), u16(NumberOfSections), u32(0),
- u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
- // .idata$5
- VASize +
- // .idata$4
- VASize),
- u32(NumberOfSymbols), u16(0),
- u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
- };
- append(Buffer, Header);
-
- // Section Header Table
- static const coff_section SectionTable[NumberOfSections] = {
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
- u32(0),
- u32(0),
- u32(VASize),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
- u32(0),
- u32(0),
- u16(0),
- u16(0),
- u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) |
- IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
- IMAGE_SCN_MEM_WRITE)},
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
- u32(0),
- u32(0),
- u32(VASize),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
- VASize),
- u32(0),
- u32(0),
- u16(0),
- u16(0),
- u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) |
- IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
- IMAGE_SCN_MEM_WRITE)},
- };
- append(Buffer, SectionTable);
-
- // .idata$5, ILT
- append(Buffer, u32(0));
- if (!is32bit())
- append(Buffer, u32(0));
-
- // .idata$4, IAT
- append(Buffer, u32(0));
- if (!is32bit())
- append(Buffer, u32(0));
-
- // Symbol Table
- coff_symbol16 SymbolTable[NumberOfSymbols] = {
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(1),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- };
- reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
- sizeof(uint32_t);
- append(Buffer, SymbolTable);
-
- // String Table
- writeStringTable(Buffer, {NullThunkSymbolName});
-
- StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
- return {MemoryBufferRef{F, DLLName}};
-}
-
-NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
- uint16_t Ordinal,
- ImportNameType NameType,
- bool isData) {
- size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs
- size_t Size = sizeof(coff_import_header) + ImpSize;
- char *Buf = Alloc.Allocate<char>(Size);
- memset(Buf, 0, Size);
- char *P = Buf;
-
- // Write short import library.
- auto *Imp = reinterpret_cast<coff_import_header *>(P);
- P += sizeof(*Imp);
- Imp->Sig2 = 0xFFFF;
- Imp->Machine = Config->Machine;
- Imp->SizeOfData = ImpSize;
- if (Ordinal > 0)
- Imp->OrdinalHint = Ordinal;
- Imp->TypeInfo = (isData ? IMPORT_DATA : IMPORT_CODE);
- Imp->TypeInfo |= NameType << 2;
-
- // Write symbol name and DLL name.
- memcpy(P, Sym.data(), Sym.size());
- P += Sym.size() + 1;
- memcpy(P, DLLName.data(), DLLName.size());
-
- return {MemoryBufferRef(StringRef(Buf, Size), DLLName)};
-}
-
-// Creates an import library for a DLL. In this function, we first
-// create an empty import library using lib.exe and then adds short
-// import files to that file.
-void lld::coff::writeImportLibrary() {
- std::vector<NewArchiveMember> Members;
-
- std::string Path = getImplibPath();
- std::string DLLName = sys::path::filename(Config->OutputFile);
- ObjectFactory OF(DLLName);
-
- std::vector<uint8_t> ImportDescriptor;
- Members.push_back(OF.createImportDescriptor(ImportDescriptor));
-
- std::vector<uint8_t> NullImportDescriptor;
- Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
-
- std::vector<uint8_t> NullThunk;
- Members.push_back(OF.createNullThunk(NullThunk));
-
- for (Export &E : Config->Exports) {
- if (E.Private)
- continue;
-
- ImportNameType Type = getNameType(E.SymbolName, E.Name);
- std::string Name = E.ExtName.empty()
- ? std::string(E.SymbolName)
- : replace(E.SymbolName, E.Name, E.ExtName);
- Members.push_back(OF.createShortImport(Name, E.Ordinal, Type, E.Data));
- }
-
- std::pair<StringRef, std::error_code> Result =
- writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU,
- /*Deterministic*/ true, /*Thin*/ false);
- if (auto EC = Result.second)
- fatal(EC, "failed to write " + Path);
-}
diff --git a/contrib/llvm/tools/lld/COFF/MapFile.cpp b/contrib/llvm/tools/lld/COFF/MapFile.cpp
new file mode 100644
index 0000000..b63d467
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/MapFile.cpp
@@ -0,0 +1,125 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the /lldmap option. It shows lists in order and
+// hierarchically the output sections, input sections, input files and
+// symbol:
+//
+// Address Size Align Out File Symbol
+// 00201000 00000015 4 .text
+// 00201000 0000000e 4 test.o:(.text)
+// 0020100e 00000000 0 local
+// 00201005 00000000 0 f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "Error.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::coff;
+
+typedef DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>
+ SymbolMapTy;
+
+// Print out the first three columns of a line.
+static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
+ uint64_t Align) {
+ OS << format("%08llx %08llx %5lld ", Addr, Size, Align);
+}
+
+static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }
+
+// Returns a list of all symbols that we want to print out.
+static std::vector<DefinedRegular *> getSymbols() {
+ std::vector<DefinedRegular *> V;
+ for (coff::ObjectFile *File : Symtab->ObjectFiles)
+ for (SymbolBody *B : File->getSymbols())
+ if (auto *Sym = dyn_cast<DefinedRegular>(B))
+ if (Sym && !Sym->getCOFFSymbol().isSectionDefinition())
+ V.push_back(Sym);
+ return V;
+}
+
+// Returns a map from sections to their symbols.
+static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
+ SymbolMapTy Ret;
+ for (DefinedRegular *S : Syms)
+ Ret[S->getChunk()].push_back(S);
+
+ // Sort symbols by address.
+ for (auto &It : Ret) {
+ SmallVectorImpl<DefinedRegular *> &V = It.second;
+ std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
+ return A->getRVA() < B->getRVA();
+ });
+ }
+ return Ret;
+}
+
+// Construct a map from symbols to their stringified representations.
+static DenseMap<DefinedRegular *, std::string>
+getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
+ std::vector<std::string> Str(Syms.size());
+ for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) {
+ raw_string_ostream OS(Str[I]);
+ writeHeader(OS, Syms[I]->getRVA(), 0, 0);
+ OS << indent(2) << toString(*Syms[I]);
+ });
+
+ DenseMap<DefinedRegular *, std::string> Ret;
+ for (size_t I = 0, E = Syms.size(); I < E; ++I)
+ Ret[Syms[I]] = std::move(Str[I]);
+ return Ret;
+}
+
+void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
+ if (Config->MapFile.empty())
+ return;
+
+ std::error_code EC;
+ raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
+ if (EC)
+ fatal("cannot open " + Config->MapFile + ": " + EC.message());
+
+ // Collect symbol info that we want to print out.
+ std::vector<DefinedRegular *> Syms = getSymbols();
+ SymbolMapTy SectionSyms = getSectionSyms(Syms);
+ DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings(Syms);
+
+ // Print out the header line.
+ OS << "Address Size Align Out In Symbol\n";
+
+ // Print out file contents.
+ for (OutputSection *Sec : OutputSections) {
+ writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize);
+ OS << Sec->getName() << '\n';
+
+ for (Chunk *C : Sec->getChunks()) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (!SC)
+ continue;
+
+ writeHeader(OS, SC->getRVA(), SC->getSize(), SC->getAlign());
+ OS << indent(1) << SC->File->getName() << ":(" << SC->getSectionName()
+ << ")\n";
+ for (DefinedRegular *Sym : SectionSyms[SC])
+ OS << SymStr[Sym] << '\n';
+ }
+ }
+}
diff --git a/contrib/llvm/tools/lld/COFF/MapFile.h b/contrib/llvm/tools/lld/COFF/MapFile.h
new file mode 100644
index 0000000..0d0d68c
--- /dev/null
+++ b/contrib/llvm/tools/lld/COFF/MapFile.h
@@ -0,0 +1,22 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_MAPFILE_H
+#define LLD_COFF_MAPFILE_H
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+class OutputSection;
+void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/lld/COFF/MarkLive.cpp b/contrib/llvm/tools/lld/COFF/MarkLive.cpp
index 0156d23..a2756e5 100644
--- a/contrib/llvm/tools/lld/COFF/MarkLive.cpp
+++ b/contrib/llvm/tools/lld/COFF/MarkLive.cpp
@@ -37,19 +37,33 @@ void markLive(const std::vector<Chunk *> &Chunks) {
Worklist.push_back(C);
};
+ auto AddSym = [&](SymbolBody *B) {
+ if (auto *Sym = dyn_cast<DefinedRegular>(B))
+ Enqueue(Sym->getChunk());
+ else if (auto *Sym = dyn_cast<DefinedImportData>(B))
+ Sym->File->Live = true;
+ else if (auto *Sym = dyn_cast<DefinedImportThunk>(B))
+ Sym->WrappedSym->File->Live = true;
+ };
+
// Add GC root chunks.
for (SymbolBody *B : Config->GCRoot)
- if (auto *D = dyn_cast<DefinedRegular>(B))
- Enqueue(D->getChunk());
+ AddSym(B);
while (!Worklist.empty()) {
SectionChunk *SC = Worklist.pop_back_val();
+
+ // If this section was discarded, there are relocations referring to
+ // discarded sections. Ignore these sections to avoid crashing. They will be
+ // diagnosed during relocation processing.
+ if (SC->isDiscarded())
+ continue;
+
assert(SC->isLive() && "We mark as live when pushing onto the worklist!");
// Mark all symbols listed in the relocation table for this section.
- for (SymbolBody *S : SC->symbols())
- if (auto *D = dyn_cast<DefinedRegular>(S))
- Enqueue(D->getChunk());
+ for (SymbolBody *B : SC->symbols())
+ AddSym(B);
// Mark associative sections if any.
for (SectionChunk *C : SC->children())
diff --git a/contrib/llvm/tools/lld/COFF/ModuleDef.cpp b/contrib/llvm/tools/lld/COFF/ModuleDef.cpp
deleted file mode 100644
index a273b6f..0000000
--- a/contrib/llvm/tools/lld/COFF/ModuleDef.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-//===- COFF/ModuleDef.cpp -------------------------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Windows-specific.
-// A parser for the module-definition file (.def file).
-// Parsed results are directly written to Config global variable.
-//
-// The format of module-definition files are described in this document:
-// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
-//
-//===----------------------------------------------------------------------===//
-
-#include "Config.h"
-#include "Error.h"
-#include "Memory.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/StringSaver.h"
-#include "llvm/Support/raw_ostream.h"
-#include <system_error>
-
-using namespace llvm;
-
-namespace lld {
-namespace coff {
-namespace {
-
-enum Kind {
- Unknown,
- Eof,
- Identifier,
- Comma,
- Equal,
- KwBase,
- KwData,
- KwExports,
- KwHeapsize,
- KwLibrary,
- KwName,
- KwNoname,
- KwPrivate,
- KwStacksize,
- KwVersion,
-};
-
-struct Token {
- explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
- Kind K;
- StringRef Value;
-};
-
-static bool isDecorated(StringRef Sym) {
- return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
-}
-
-class Lexer {
-public:
- explicit Lexer(StringRef S) : Buf(S) {}
-
- Token lex() {
- Buf = Buf.trim();
- if (Buf.empty())
- return Token(Eof);
-
- switch (Buf[0]) {
- case '\0':
- return Token(Eof);
- case ';': {
- size_t End = Buf.find('\n');
- Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
- return lex();
- }
- case '=':
- Buf = Buf.drop_front();
- return Token(Equal, "=");
- case ',':
- Buf = Buf.drop_front();
- return Token(Comma, ",");
- case '"': {
- StringRef S;
- std::tie(S, Buf) = Buf.substr(1).split('"');
- return Token(Identifier, S);
- }
- default: {
- size_t End = Buf.find_first_of("=,\r\n \t\v");
- StringRef Word = Buf.substr(0, End);
- Kind K = llvm::StringSwitch<Kind>(Word)
- .Case("BASE", KwBase)
- .Case("DATA", KwData)
- .Case("EXPORTS", KwExports)
- .Case("HEAPSIZE", KwHeapsize)
- .Case("LIBRARY", KwLibrary)
- .Case("NAME", KwName)
- .Case("NONAME", KwNoname)
- .Case("PRIVATE", KwPrivate)
- .Case("STACKSIZE", KwStacksize)
- .Case("VERSION", KwVersion)
- .Default(Identifier);
- Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
- return Token(K, Word);
- }
- }
- }
-
-private:
- StringRef Buf;
-};
-
-class Parser {
-public:
- explicit Parser(StringRef S) : Lex(S) {}
-
- void parse() {
- do {
- parseOne();
- } while (Tok.K != Eof);
- }
-
-private:
- void read() {
- if (Stack.empty()) {
- Tok = Lex.lex();
- return;
- }
- Tok = Stack.back();
- Stack.pop_back();
- }
-
- void readAsInt(uint64_t *I) {
- read();
- if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
- fatal("integer expected");
- }
-
- void expect(Kind Expected, StringRef Msg) {
- read();
- if (Tok.K != Expected)
- fatal(Msg);
- }
-
- void unget() { Stack.push_back(Tok); }
-
- void parseOne() {
- read();
- switch (Tok.K) {
- case Eof:
- return;
- case KwExports:
- for (;;) {
- read();
- if (Tok.K != Identifier) {
- unget();
- return;
- }
- parseExport();
- }
- case KwHeapsize:
- parseNumbers(&Config->HeapReserve, &Config->HeapCommit);
- return;
- case KwLibrary:
- parseName(&Config->OutputFile, &Config->ImageBase);
- if (!StringRef(Config->OutputFile).endswith_lower(".dll"))
- Config->OutputFile += ".dll";
- return;
- case KwStacksize:
- parseNumbers(&Config->StackReserve, &Config->StackCommit);
- return;
- case KwName:
- parseName(&Config->OutputFile, &Config->ImageBase);
- return;
- case KwVersion:
- parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
- return;
- default:
- fatal("unknown directive: " + Tok.Value);
- }
- }
-
- void parseExport() {
- Export E;
- E.Name = Tok.Value;
- read();
- if (Tok.K == Equal) {
- read();
- if (Tok.K != Identifier)
- fatal("identifier expected, but got " + Tok.Value);
- E.ExtName = E.Name;
- E.Name = Tok.Value;
- } else {
- unget();
- }
-
- if (Config->Machine == I386) {
- if (!isDecorated(E.Name))
- E.Name = Saver.save("_" + E.Name);
- if (!E.ExtName.empty() && !isDecorated(E.ExtName))
- E.ExtName = Saver.save("_" + E.ExtName);
- }
-
- for (;;) {
- read();
- if (Tok.K == Identifier && Tok.Value[0] == '@') {
- Tok.Value.drop_front().getAsInteger(10, E.Ordinal);
- read();
- if (Tok.K == KwNoname) {
- E.Noname = true;
- } else {
- unget();
- }
- continue;
- }
- if (Tok.K == KwData) {
- E.Data = true;
- continue;
- }
- if (Tok.K == KwPrivate) {
- E.Private = true;
- continue;
- }
- unget();
- Config->Exports.push_back(E);
- return;
- }
- }
-
- // HEAPSIZE/STACKSIZE reserve[,commit]
- void parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
- readAsInt(Reserve);
- read();
- if (Tok.K != Comma) {
- unget();
- Commit = nullptr;
- return;
- }
- readAsInt(Commit);
- }
-
- // NAME outputPath [BASE=address]
- void parseName(std::string *Out, uint64_t *Baseaddr) {
- read();
- if (Tok.K == Identifier) {
- *Out = Tok.Value;
- } else {
- *Out = "";
- unget();
- return;
- }
- read();
- if (Tok.K == KwBase) {
- expect(Equal, "'=' expected");
- readAsInt(Baseaddr);
- } else {
- unget();
- *Baseaddr = 0;
- }
- }
-
- // VERSION major[.minor]
- void parseVersion(uint32_t *Major, uint32_t *Minor) {
- read();
- if (Tok.K != Identifier)
- fatal("identifier expected, but got " + Tok.Value);
- StringRef V1, V2;
- std::tie(V1, V2) = Tok.Value.split('.');
- if (V1.getAsInteger(10, *Major))
- fatal("integer expected, but got " + Tok.Value);
- if (V2.empty())
- *Minor = 0;
- else if (V2.getAsInteger(10, *Minor))
- fatal("integer expected, but got " + Tok.Value);
- }
-
- Lexer Lex;
- Token Tok;
- std::vector<Token> Stack;
-};
-
-} // anonymous namespace
-
-void parseModuleDefs(MemoryBufferRef MB) { Parser(MB.getBuffer()).parse(); }
-
-} // namespace coff
-} // namespace lld
diff --git a/contrib/llvm/tools/lld/COFF/Options.td b/contrib/llvm/tools/lld/COFF/Options.td
index 9dfbcc8..61523c4f 100644
--- a/contrib/llvm/tools/lld/COFF/Options.td
+++ b/contrib/llvm/tools/lld/COFF/Options.td
@@ -21,6 +21,8 @@ def base : P<"base", "Base address of the program">;
def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
def delayload : P<"delayload", "Delay loaded DLL name">;
def entry : P<"entry", "Name of entry point symbol">;
+def errorlimit : P<"errorlimit",
+ "Maximum number of errors to emit before stopping (0 = no limit)">;
def export : P<"export", "Export a function">;
// No help text because /failifmismatch is not intended to be used by the user.
def failifmismatch : P<"failifmismatch", "">;
@@ -28,6 +30,8 @@ def heap : P<"heap", "Size of the heap">;
def implib : P<"implib", "Import library name">;
def libpath : P<"libpath", "Additional library search path">;
def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
+def lldsavetemps : F<"lldsavetemps">,
+ HelpText<"Save temporary files instead of deleting them">;
def machine : P<"machine", "Specify target platform">;
def merge : P<"merge", "Combine sections">;
def mllvm : P<"mllvm", "Options to pass to LLVM">;
@@ -78,6 +82,8 @@ def force_unresolved : F<"force:unresolved">;
defm allowbind: B<"allowbind", "Disable DLL binding">;
defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
+defm appcontainer : B<"appcontainer",
+ "Image can only be run in an app container">;
defm dynamicbase : B<"dynamicbase",
"Disable address space layout randomization">;
defm fixed : B<"fixed", "Enable base relocations">;
@@ -91,11 +97,11 @@ def help : F<"help">;
def help_q : Flag<["/?", "-?"], "">, Alias<help>;
// LLD extensions
+def nopdb : F<"nopdb">, HelpText<"Disable PDB generation for DWARF users">;
def nosymtab : F<"nosymtab">;
+def msvclto : F<"msvclto">;
// Flags for debugging
-def debugpdb : F<"debugpdb">;
-def dumppdb : Joined<["/", "-"], "dumppdb">;
def lldmap : F<"lldmap">;
def lldmap_file : Joined<["/", "-"], "lldmap:">;
diff --git a/contrib/llvm/tools/lld/COFF/PDB.cpp b/contrib/llvm/tools/lld/COFF/PDB.cpp
index 923fc64..89462da 100644
--- a/contrib/llvm/tools/lld/COFF/PDB.cpp
+++ b/contrib/llvm/tools/lld/COFF/PDB.cpp
@@ -14,26 +14,34 @@
#include "SymbolTable.h"
#include "Symbols.h"
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
-#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>
@@ -41,20 +49,89 @@ using namespace lld;
using namespace lld::coff;
using namespace llvm;
using namespace llvm::codeview;
-using namespace llvm::support;
-using namespace llvm::support::endian;
using llvm::object::coff_section;
static ExitOnError ExitOnErr;
+namespace {
+/// Map from type index and item index in a type server PDB to the
+/// corresponding index in the destination PDB.
+struct CVIndexMap {
+ SmallVector<TypeIndex, 0> TPIMap;
+ SmallVector<TypeIndex, 0> IPIMap;
+ bool IsTypeServerMap = false;
+};
+
+class PDBLinker {
+public:
+ PDBLinker(SymbolTable *Symtab)
+ : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc),
+ IDTable(Alloc) {}
+
+ /// Emit the basic PDB structure: initial streams, headers, etc.
+ void initialize(const llvm::codeview::DebugInfo *DI);
+
+ /// Link CodeView from each object file in the symbol table into the PDB.
+ void addObjectsToPDB();
+
+ /// Link CodeView from a single object file into the PDB.
+ void addObjectFile(ObjectFile *File);
+
+ /// Produce a mapping from the type and item indices used in the object
+ /// file to those in the destination PDB.
+ ///
+ /// If the object file uses a type server PDB (compiled with /Zi), merge TPI
+ /// and IPI from the type server PDB and return a map for it. Each unique type
+ /// server PDB is merged at most once, so this may return an existing index
+ /// mapping.
+ ///
+ /// If the object does not use a type server PDB (compiled with /Z7), we merge
+ /// all the type and item records from the .debug$S stream and fill in the
+ /// caller-provided ObjectIndexMap.
+ const CVIndexMap &mergeDebugT(ObjectFile *File, CVIndexMap &ObjectIndexMap);
+
+ const CVIndexMap &maybeMergeTypeServerPDB(ObjectFile *File,
+ TypeServer2Record &TS);
+
+ /// Add the section map and section contributions to the PDB.
+ void addSections(ArrayRef<uint8_t> SectionTable);
+
+ /// Write the PDB to disk.
+ void commit();
+
+private:
+ BumpPtrAllocator Alloc;
+
+ SymbolTable *Symtab;
+
+ pdb::PDBFileBuilder Builder;
+
+ /// Type records that will go into the PDB TPI stream.
+ TypeTableBuilder TypeTable;
+
+ /// Item records that will go into the PDB IPI stream.
+ TypeTableBuilder IDTable;
+
+ /// PDBs use a single global string table for filenames in the file checksum
+ /// table.
+ DebugStringTableSubsection PDBStrTab;
+
+ llvm::SmallString<128> NativePath;
+
+ std::vector<pdb::SecMapEntry> SectionMap;
+
+ /// Type index mappings of type server PDBs that we've loaded so far.
+ std::map<GUID, CVIndexMap> TypeServerIndexMappings;
+};
+}
+
// Returns a list of all SectionChunks.
-static std::vector<coff_section> getInputSections(SymbolTable *Symtab) {
- std::vector<coff_section> V;
+static void addSectionContribs(SymbolTable *Symtab,
+ pdb::DbiStreamBuilder &DbiBuilder) {
for (Chunk *C : Symtab->getChunks())
if (auto *SC = dyn_cast<SectionChunk>(C))
- V.push_back(*SC->Header);
- return V;
+ DbiBuilder.addSectionContrib(SC->File->ModuleDBI, SC->Header);
}
static SectionChunk *findByName(std::vector<SectionChunk *> &Sections,
@@ -65,109 +142,480 @@ static SectionChunk *findByName(std::vector<SectionChunk *> &Sections,
return nullptr;
}
-static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
- SectionChunk *Sec = findByName(File->getDebugChunks(), SecName);
- if (!Sec)
- return {};
-
+static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data,
+ StringRef SecName) {
// First 4 bytes are section magic.
- ArrayRef<uint8_t> Data = Sec->getContents();
if (Data.size() < 4)
fatal(SecName + " too short");
- if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
+ if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
fatal(SecName + " has an invalid magic");
return Data.slice(4);
}
-// Merge .debug$T sections and returns it.
-static std::vector<uint8_t> mergeDebugT(SymbolTable *Symtab) {
- ScopedPrinter W(outs());
-
- // Visit all .debug$T sections to add them to Builder.
- codeview::TypeTableBuilder Builder(BAlloc);
- for (ObjectFile *File : Symtab->ObjectFiles) {
- ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
- if (Data.empty())
- continue;
+static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
+ if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName))
+ return consumeDebugMagic(Sec->getContents(), SecName);
+ return {};
+}
- msf::ByteStream Stream(Data);
- codeview::CVTypeArray Types;
- msf::StreamReader Reader(Stream);
- if (auto EC = Reader.readArray(Types, Reader.getLength()))
- fatal(EC, "Reader::readArray failed");
- if (!codeview::mergeTypeStreams(Builder, Types))
- fatal("codeview::mergeTypeStreams failed");
- }
+static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
+ TypeTableBuilder &TypeTable) {
+ // Start the TPI or IPI stream header.
+ TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
- // Construct section contents.
- std::vector<uint8_t> V;
- Builder.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
- V.insert(V.end(), Rec.begin(), Rec.end());
+ // Flatten the in memory type table.
+ TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
+ // FIXME: Hash types.
+ TpiBuilder.addTypeRecord(Rec, None);
});
- return V;
}
-static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
- ListScope LS(W, "DebugT");
+static Optional<TypeServer2Record>
+maybeReadTypeServerRecord(CVTypeArray &Types) {
+ auto I = Types.begin();
+ if (I == Types.end())
+ return None;
+ const CVType &Type = *I;
+ if (Type.kind() != LF_TYPESERVER2)
+ return None;
+ TypeServer2Record TS;
+ if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type), TS))
+ fatal(EC, "error reading type server record");
+ return std::move(TS);
+}
+
+const CVIndexMap &PDBLinker::mergeDebugT(ObjectFile *File,
+ CVIndexMap &ObjectIndexMap) {
ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
if (Data.empty())
- return;
+ return ObjectIndexMap;
+
+ BinaryByteStream Stream(Data, support::little);
+ CVTypeArray Types;
+ BinaryStreamReader Reader(Stream);
+ if (auto EC = Reader.readArray(Types, Reader.getLength()))
+ fatal(EC, "Reader::readArray failed");
+
+ // Look through type servers. If we've already seen this type server, don't
+ // merge any type information.
+ if (Optional<TypeServer2Record> TS = maybeReadTypeServerRecord(Types))
+ return maybeMergeTypeServerPDB(File, *TS);
+
+ // This is a /Z7 object. Fill in the temporary, caller-provided
+ // ObjectIndexMap.
+ if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable,
+ ObjectIndexMap.TPIMap, Types))
+ fatal(Err, "codeview::mergeTypeAndIdRecords failed");
+ return ObjectIndexMap;
+}
- TypeDatabase TDB;
- TypeDumpVisitor TDV(TDB, &W, false);
- CVTypeDumper TypeDumper(TDB);
- if (auto EC = TypeDumper.dump(Data, TDV))
- fatal(EC, "CVTypeDumper::dump failed");
+static Expected<std::unique_ptr<pdb::NativeSession>>
+tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) {
+ std::unique_ptr<pdb::IPDBSession> ThisSession;
+ if (auto EC =
+ pdb::loadDataForPDB(pdb::PDB_ReaderType::Native, TSPath, ThisSession))
+ return std::move(EC);
+
+ std::unique_ptr<pdb::NativeSession> NS(
+ static_cast<pdb::NativeSession *>(ThisSession.release()));
+ pdb::PDBFile &File = NS->getPDBFile();
+ auto ExpectedInfo = File.getPDBInfoStream();
+ // All PDB Files should have an Info stream.
+ if (!ExpectedInfo)
+ return ExpectedInfo.takeError();
+
+ // Just because a file with a matching name was found and it was an actual
+ // PDB file doesn't mean it matches. For it to match the InfoStream's GUID
+ // must match the GUID specified in the TypeServer2 record.
+ if (ExpectedInfo->getGuid() != GuidFromObj)
+ return make_error<pdb::GenericError>(
+ pdb::generic_error_code::type_server_not_found, TSPath);
+
+ return std::move(NS);
}
-static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
- ListScope LS(W, "DebugS");
- ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$S");
- if (Data.empty())
+const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjectFile *File,
+ TypeServer2Record &TS) {
+ // First, check if we already loaded a PDB with this GUID. Return the type
+ // index mapping if we have it.
+ auto Insertion = TypeServerIndexMappings.insert({TS.getGuid(), CVIndexMap()});
+ CVIndexMap &IndexMap = Insertion.first->second;
+ if (!Insertion.second)
+ return IndexMap;
+
+ // Mark this map as a type server map.
+ IndexMap.IsTypeServerMap = true;
+
+ // Check for a PDB at:
+ // 1. The given file path
+ // 2. Next to the object file or archive file
+ auto ExpectedSession = tryToLoadPDB(TS.getGuid(), TS.getName());
+ if (!ExpectedSession) {
+ consumeError(ExpectedSession.takeError());
+ StringRef LocalPath =
+ !File->ParentName.empty() ? File->ParentName : File->getName();
+ SmallString<128> Path = sys::path::parent_path(LocalPath);
+ sys::path::append(
+ Path, sys::path::filename(TS.getName(), sys::path::Style::windows));
+ ExpectedSession = tryToLoadPDB(TS.getGuid(), Path);
+ }
+ if (auto E = ExpectedSession.takeError())
+ fatal(E, "Type server PDB was not found");
+
+ // Merge TPI first, because the IPI stream will reference type indices.
+ auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream();
+ if (auto E = ExpectedTpi.takeError())
+ fatal(E, "Type server does not have TPI stream");
+ if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap,
+ ExpectedTpi->typeArray()))
+ fatal(Err, "codeview::mergeTypeRecords failed");
+
+ // Merge IPI.
+ auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream();
+ if (auto E = ExpectedIpi.takeError())
+ fatal(E, "Type server does not have TPI stream");
+ if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap,
+ ExpectedIpi->typeArray()))
+ fatal(Err, "codeview::mergeIdRecords failed");
+
+ return IndexMap;
+}
+
+static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
+ if (TI.isSimple())
+ return true;
+ if (TI.toArrayIndex() >= TypeIndexMap.size())
+ return false;
+ TI = TypeIndexMap[TI.toArrayIndex()];
+ return true;
+}
+
+static void remapTypesInSymbolRecord(ObjectFile *File,
+ MutableArrayRef<uint8_t> Contents,
+ const CVIndexMap &IndexMap,
+ ArrayRef<TiReference> TypeRefs) {
+ for (const TiReference &Ref : TypeRefs) {
+ unsigned ByteSize = Ref.Count * sizeof(TypeIndex);
+ if (Contents.size() < Ref.Offset + ByteSize)
+ fatal("symbol record too short");
+
+ // This can be an item index or a type index. Choose the appropriate map.
+ ArrayRef<TypeIndex> TypeOrItemMap = IndexMap.TPIMap;
+ if (Ref.Kind == TiRefKind::IndexRef && IndexMap.IsTypeServerMap)
+ TypeOrItemMap = IndexMap.IPIMap;
+
+ MutableArrayRef<TypeIndex> TIs(
+ reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count);
+ for (TypeIndex &TI : TIs) {
+ if (!remapTypeIndex(TI, TypeOrItemMap)) {
+ TI = TypeIndex(SimpleTypeKind::NotTranslated);
+ log("ignoring symbol record in " + File->getName() +
+ " with bad type index 0x" + utohexstr(TI.getIndex()));
+ continue;
+ }
+ }
+ }
+}
+
+/// MSVC translates S_PROC_ID_END to S_END.
+uint16_t canonicalizeSymbolKind(SymbolKind Kind) {
+ if (Kind == SymbolKind::S_PROC_ID_END)
+ return SymbolKind::S_END;
+ return Kind;
+}
+
+/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned.
+/// The object file may not be aligned.
+static MutableArrayRef<uint8_t> copySymbolForPdb(const CVSymbol &Sym,
+ BumpPtrAllocator &Alloc) {
+ size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb));
+ assert(Size >= 4 && "record too short");
+ assert(Size <= MaxRecordLength && "record too long");
+ void *Mem = Alloc.Allocate(Size, 4);
+
+ // Copy the symbol record and zero out any padding bytes.
+ MutableArrayRef<uint8_t> NewData(reinterpret_cast<uint8_t *>(Mem), Size);
+ memcpy(NewData.data(), Sym.data().data(), Sym.length());
+ memset(NewData.data() + Sym.length(), 0, Size - Sym.length());
+
+ // Update the record prefix length. It should point to the beginning of the
+ // next record. MSVC does some canonicalization of the record kind, so we do
+ // that as well.
+ auto *Prefix = reinterpret_cast<RecordPrefix *>(Mem);
+ Prefix->RecordKind = canonicalizeSymbolKind(Sym.kind());
+ Prefix->RecordLen = Size - 2;
+ return NewData;
+}
+
+/// Return true if this symbol opens a scope. This implies that the symbol has
+/// "parent" and "end" fields, which contain the offset of the S_END or
+/// S_INLINESITE_END record.
+static bool symbolOpensScope(SymbolKind Kind) {
+ switch (Kind) {
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32:
+ case SymbolKind::S_LPROC32_ID:
+ case SymbolKind::S_GPROC32_ID:
+ case SymbolKind::S_BLOCK32:
+ case SymbolKind::S_SEPCODE:
+ case SymbolKind::S_THUNK32:
+ case SymbolKind::S_INLINESITE:
+ case SymbolKind::S_INLINESITE2:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool symbolEndsScope(SymbolKind Kind) {
+ switch (Kind) {
+ case SymbolKind::S_END:
+ case SymbolKind::S_PROC_ID_END:
+ case SymbolKind::S_INLINESITE_END:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+struct ScopeRecord {
+ ulittle32_t PtrParent;
+ ulittle32_t PtrEnd;
+};
+
+struct SymbolScope {
+ ScopeRecord *OpeningRecord;
+ uint32_t ScopeOffset;
+};
+
+static void scopeStackOpen(SmallVectorImpl<SymbolScope> &Stack,
+ uint32_t CurOffset, CVSymbol &Sym) {
+ assert(symbolOpensScope(Sym.kind()));
+ SymbolScope S;
+ S.ScopeOffset = CurOffset;
+ S.OpeningRecord = const_cast<ScopeRecord *>(
+ reinterpret_cast<const ScopeRecord *>(Sym.content().data()));
+ S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset;
+ Stack.push_back(S);
+}
+
+static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack,
+ uint32_t CurOffset, ObjectFile *File) {
+ if (Stack.empty()) {
+ warn("symbol scopes are not balanced in " + File->getName());
return;
+ }
+ SymbolScope S = Stack.pop_back_val();
+ S.OpeningRecord->PtrEnd = CurOffset;
+}
- msf::ByteStream Stream(Data);
- CVSymbolArray Symbols;
- msf::StreamReader Reader(Stream);
- if (auto EC = Reader.readArray(Symbols, Reader.getLength()))
- fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");
+static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
+ const CVIndexMap &IndexMap,
+ BinaryStreamRef SymData) {
+ // FIXME: Improve error recovery by warning and skipping records when
+ // possible.
+ CVSymbolArray Syms;
+ BinaryStreamReader Reader(SymData);
+ ExitOnErr(Reader.readArray(Syms, Reader.getLength()));
+ SmallVector<SymbolScope, 4> Scopes;
+ for (const CVSymbol &Sym : Syms) {
+ // Discover type index references in the record. Skip it if we don't know
+ // where they are.
+ SmallVector<TiReference, 32> TypeRefs;
+ if (!discoverTypeIndices(Sym, TypeRefs)) {
+ log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind()));
+ continue;
+ }
+
+ // Copy the symbol record so we can mutate it.
+ MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
+
+ // Re-map all the type index references.
+ MutableArrayRef<uint8_t> Contents =
+ NewData.drop_front(sizeof(RecordPrefix));
+ remapTypesInSymbolRecord(File, Contents, IndexMap, TypeRefs);
- TypeDatabase TDB;
- CVSymbolDumper SymbolDumper(W, TDB, nullptr, false);
- if (auto EC = SymbolDumper.dump(Symbols))
- fatal(EC, "CVSymbolDumper::dump failed");
+ // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
+ CVSymbol NewSym(Sym.kind(), NewData);
+ if (symbolOpensScope(Sym.kind()))
+ scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym);
+ else if (symbolEndsScope(Sym.kind()))
+ scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
+
+ // Add the symbol to the module.
+ File->ModuleDBI->addSymbol(NewSym);
+ }
}
-// Dump CodeView debug info. This is for debugging.
-static void dumpCodeView(SymbolTable *Symtab) {
- ScopedPrinter W(outs());
+// Allocate memory for a .debug$S section and relocate it.
+static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc,
+ SectionChunk *DebugChunk) {
+ uint8_t *Buffer = Alloc.Allocate<uint8_t>(DebugChunk->getSize());
+ assert(DebugChunk->OutputSectionOff == 0 &&
+ "debug sections should not be in output sections");
+ DebugChunk->writeTo(Buffer);
+ return consumeDebugMagic(makeArrayRef(Buffer, DebugChunk->getSize()),
+ ".debug$S");
+}
+
+void PDBLinker::addObjectFile(ObjectFile *File) {
+ // Add a module descriptor for every object file. We need to put an absolute
+ // path to the object into the PDB. If this is a plain object, we make its
+ // path absolute. If it's an object in an archive, we make the archive path
+ // absolute.
+ bool InArchive = !File->ParentName.empty();
+ SmallString<128> Path = InArchive ? File->ParentName : File->getName();
+ sys::fs::make_absolute(Path);
+ sys::path::native(Path, sys::path::Style::windows);
+ StringRef Name = InArchive ? File->getName() : StringRef(Path);
+
+ File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
+ File->ModuleDBI->setObjFileName(Path);
+
+ // Before we can process symbol substreams from .debug$S, we need to process
+ // type information, file checksums, and the string table. Add type info to
+ // the PDB first, so that we can get the map from object file type and item
+ // indices to PDB type and item indices.
+ CVIndexMap ObjectIndexMap;
+ const CVIndexMap &IndexMap = mergeDebugT(File, ObjectIndexMap);
+
+ // Now do all live .debug$S sections.
+ for (SectionChunk *DebugChunk : File->getDebugChunks()) {
+ if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S")
+ continue;
- for (ObjectFile *File : Symtab->ObjectFiles) {
- dumpDebugT(W, File);
- dumpDebugS(W, File);
+ ArrayRef<uint8_t> RelocatedDebugContents =
+ relocateDebugChunk(Alloc, DebugChunk);
+ if (RelocatedDebugContents.empty())
+ continue;
+
+ DebugSubsectionArray Subsections;
+ BinaryStreamReader Reader(RelocatedDebugContents, support::little);
+ ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size()));
+
+ DebugStringTableSubsectionRef CVStrTab;
+ DebugChecksumsSubsectionRef Checksums;
+ for (const DebugSubsectionRecord &SS : Subsections) {
+ switch (SS.kind()) {
+ case DebugSubsectionKind::StringTable:
+ ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+ break;
+ case DebugSubsectionKind::FileChecksums:
+ ExitOnErr(Checksums.initialize(SS.getRecordData()));
+ break;
+ case DebugSubsectionKind::Lines:
+ // We can add the relocated line table directly to the PDB without
+ // modification because the file checksum offsets will stay the same.
+ File->ModuleDBI->addDebugSubsection(SS);
+ break;
+ case DebugSubsectionKind::Symbols:
+ mergeSymbolRecords(Alloc, File, IndexMap, SS.getRecordData());
+ break;
+ default:
+ // FIXME: Process the rest of the subsections.
+ break;
+ }
+ }
+
+ if (Checksums.valid()) {
+ // Make a new file checksum table that refers to offsets in the PDB-wide
+ // string table. Generally the string table subsection appears after the
+ // checksum table, so we have to do this after looping over all the
+ // subsections.
+ if (!CVStrTab.valid())
+ fatal(".debug$S sections must have both a string table subsection "
+ "and a checksum subsection table or neither");
+ auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab);
+ for (FileChecksumEntry &FC : Checksums) {
+ StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
+ ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI,
+ FileName));
+ NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
+ }
+ File->ModuleDBI->addDebugSubsection(std::move(NewChecksums));
+ }
}
}
-static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
- ArrayRef<uint8_t> Data) {
- msf::ByteStream Stream(Data);
- codeview::CVTypeArray Records;
- msf::StreamReader Reader(Stream);
- if (auto EC = Reader.readArray(Records, Reader.getLength()))
- fatal(EC, "Reader.readArray failed");
- for (const codeview::CVType &Rec : Records)
- TpiBuilder.addTypeRecord(Rec);
+// Add all object files to the PDB. Merge .debug$T sections into IpiData and
+// TpiData.
+void PDBLinker::addObjectsToPDB() {
+ for (ObjectFile *File : Symtab->ObjectFiles)
+ addObjectFile(File);
+
+ Builder.getStringTableBuilder().setStrings(PDBStrTab);
+
+ // Construct TPI stream contents.
+ addTypeInfo(Builder.getTpiBuilder(), TypeTable);
+
+ // Construct IPI stream contents.
+ addTypeInfo(Builder.getIpiBuilder(), IDTable);
+
+ // Add public and symbol records stream.
+
+ // For now we don't actually write any thing useful to the publics stream, but
+ // the act of "getting" it also creates it lazily so that we write an empty
+ // stream.
+ (void)Builder.getPublicsBuilder();
+}
+
+static void addLinkerModuleSymbols(StringRef Path,
+ pdb::DbiModuleDescriptorBuilder &Mod,
+ BumpPtrAllocator &Allocator) {
+ codeview::SymbolSerializer Serializer(Allocator, CodeViewContainer::Pdb);
+ codeview::ObjNameSym ONS(SymbolRecordKind::ObjNameSym);
+ codeview::Compile3Sym CS(SymbolRecordKind::Compile3Sym);
+ codeview::EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym);
+
+ ONS.Name = "* Linker *";
+ ONS.Signature = 0;
+
+ CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386;
+ CS.Flags = CompileSym3Flags::None;
+ CS.VersionBackendBuild = 0;
+ CS.VersionBackendMajor = 0;
+ CS.VersionBackendMinor = 0;
+ CS.VersionBackendQFE = 0;
+ CS.VersionFrontendBuild = 0;
+ CS.VersionFrontendMajor = 0;
+ CS.VersionFrontendMinor = 0;
+ CS.VersionFrontendQFE = 0;
+ CS.Version = "LLVM Linker";
+ CS.setLanguage(SourceLanguage::Link);
+
+ ArrayRef<StringRef> Args = makeArrayRef(Config->Argv).drop_front();
+ std::string ArgStr = llvm::join(Args, " ");
+ EBS.Fields.push_back("cwd");
+ SmallString<64> cwd;
+ sys::fs::current_path(cwd);
+ EBS.Fields.push_back(cwd);
+ EBS.Fields.push_back("exe");
+ EBS.Fields.push_back(Config->Argv[0]);
+ EBS.Fields.push_back("pdb");
+ EBS.Fields.push_back(Path);
+ EBS.Fields.push_back("cmd");
+ EBS.Fields.push_back(ArgStr);
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ ONS, Allocator, CodeViewContainer::Pdb));
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ CS, Allocator, CodeViewContainer::Pdb));
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ EBS, Allocator, CodeViewContainer::Pdb));
}
// Creates a PDB file.
-void coff::createPDB(StringRef Path, SymbolTable *Symtab,
- ArrayRef<uint8_t> SectionTable,
+void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable,
const llvm::codeview::DebugInfo *DI) {
- if (Config->DumpPdb)
- dumpCodeView(Symtab);
+ PDBLinker PDB(Symtab);
+ PDB.initialize(DI);
+ PDB.addObjectsToPDB();
+ PDB.addSections(SectionTable);
+ PDB.commit();
+}
- BumpPtrAllocator Alloc;
- pdb::PDBFileBuilder Builder(Alloc);
+void PDBLinker::initialize(const llvm::codeview::DebugInfo *DI) {
ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize
// Create streams in MSF for predefined streams, namely
@@ -177,49 +625,48 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
// Add an Info stream.
auto &InfoBuilder = Builder.getInfoBuilder();
- InfoBuilder.setAge(DI->PDB70.Age);
- InfoBuilder.setGuid(
- *reinterpret_cast<const pdb::PDB_UniqueId *>(&DI->PDB70.Signature));
- // Should be the current time, but set 0 for reproducibilty.
- InfoBuilder.setSignature(0);
- InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
+ InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);
- // Add an empty DPI stream.
- auto &DbiBuilder = Builder.getDbiBuilder();
- DbiBuilder.setVersionHeader(pdb::PdbDbiV110);
-
- // Add an empty TPI stream.
- auto &TpiBuilder = Builder.getTpiBuilder();
- TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
- std::vector<uint8_t> TpiData;
- if (Config->DebugPdb) {
- TpiData = mergeDebugT(Symtab);
- addTypeInfo(TpiBuilder, TpiData);
- }
+ GUID uuid{};
+ if (DI)
+ memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
+ InfoBuilder.setGuid(uuid);
+ InfoBuilder.setSignature(time(nullptr));
+ InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
- // Add an empty IPI stream.
- auto &IpiBuilder = Builder.getIpiBuilder();
- IpiBuilder.setVersionHeader(pdb::PdbTpiV80);
+ // Add an empty DBI stream.
+ pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
+ DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
+ ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {}));
+}
+void PDBLinker::addSections(ArrayRef<uint8_t> SectionTable) {
// Add Section Contributions.
- std::vector<pdb::SectionContrib> Contribs =
- pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab));
- DbiBuilder.setSectionContribs(Contribs);
+ pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
+ addSectionContribs(Symtab, DbiBuilder);
// Add Section Map stream.
ArrayRef<object::coff_section> Sections = {
(const object::coff_section *)SectionTable.data(),
SectionTable.size() / sizeof(object::coff_section)};
- std::vector<pdb::SecMapEntry> SectionMap =
- pdb::DbiStreamBuilder::createSectionMap(Sections);
+ SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections);
DbiBuilder.setSectionMap(SectionMap);
- ExitOnErr(DbiBuilder.addModuleInfo("", "* Linker *"));
+ // It's not entirely clear what this is, but the * Linker * module uses it.
+ NativePath = Config->PDBPath;
+ sys::fs::make_absolute(NativePath);
+ sys::path::native(NativePath, sys::path::Style::windows);
+ uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
+ auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
+ LinkerModule.setPdbFilePathNI(PdbFilePathNI);
+ addLinkerModuleSymbols(NativePath, LinkerModule, Alloc);
// Add COFF section header stream.
ExitOnErr(
DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));
+}
+void PDBLinker::commit() {
// Write to a file.
- ExitOnErr(Builder.commit(Path));
+ ExitOnErr(Builder.commit(Config->PDBPath));
}
diff --git a/contrib/llvm/tools/lld/COFF/PDB.h b/contrib/llvm/tools/lld/COFF/PDB.h
index c9c3791..9aaa317 100644
--- a/contrib/llvm/tools/lld/COFF/PDB.h
+++ b/contrib/llvm/tools/lld/COFF/PDB.h
@@ -23,8 +23,7 @@ namespace lld {
namespace coff {
class SymbolTable;
-void createPDB(llvm::StringRef Path, SymbolTable *Symtab,
- llvm::ArrayRef<uint8_t> SectionTable,
+void createPDB(SymbolTable *Symtab, llvm::ArrayRef<uint8_t> SectionTable,
const llvm::codeview::DebugInfo *DI);
}
}
diff --git a/contrib/llvm/tools/lld/COFF/Strings.cpp b/contrib/llvm/tools/lld/COFF/Strings.cpp
index d055841..84f9b9a 100644
--- a/contrib/llvm/tools/lld/COFF/Strings.cpp
+++ b/contrib/llvm/tools/lld/COFF/Strings.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "Strings.h"
+#include <mutex>
#if defined(_MSC_VER)
#include <Windows.h>
@@ -21,6 +22,10 @@ using namespace llvm;
Optional<std::string> coff::demangle(StringRef S) {
#if defined(_MSC_VER)
+ // UnDecorateSymbolName is not thread-safe, so we need a mutex.
+ static std::mutex Mu;
+ std::lock_guard<std::mutex> Lock(Mu);
+
char Buf[4096];
if (S.startswith("?"))
if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0))
diff --git a/contrib/llvm/tools/lld/COFF/SymbolTable.cpp b/contrib/llvm/tools/lld/COFF/SymbolTable.cpp
index 9cc0b75..c06e42b 100644
--- a/contrib/llvm/tools/lld/COFF/SymbolTable.cpp
+++ b/contrib/llvm/tools/lld/COFF/SymbolTable.cpp
@@ -11,10 +11,10 @@
#include "Config.h"
#include "Driver.h"
#include "Error.h"
+#include "LTO.h"
#include "Memory.h"
#include "Symbols.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/LTO/legacy/LTOCodeGenerator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <utility>
@@ -24,11 +24,40 @@ using namespace llvm;
namespace lld {
namespace coff {
+enum SymbolPreference {
+ SP_EXISTING = -1,
+ SP_CONFLICT = 0,
+ SP_NEW = 1,
+};
+
+/// Checks if an existing symbol S should be kept or replaced by a new symbol.
+/// Returns SP_EXISTING when S should be kept, SP_NEW when the new symbol
+/// should be kept, and SP_CONFLICT if no valid resolution exists.
+static SymbolPreference compareDefined(Symbol *S, bool WasInserted,
+ bool NewIsCOMDAT) {
+ // If the symbol wasn't previously known, the new symbol wins by default.
+ if (WasInserted || !isa<Defined>(S->body()))
+ return SP_NEW;
+
+ // If the existing symbol is a DefinedRegular, both it and the new symbol
+ // must be comdats. In that case, we have no reason to prefer one symbol
+ // over the other, and we keep the existing one. If one of the symbols
+ // is not a comdat, we report a conflict.
+ if (auto *R = dyn_cast<DefinedRegular>(S->body())) {
+ if (NewIsCOMDAT && R->isCOMDAT())
+ return SP_EXISTING;
+ else
+ return SP_CONFLICT;
+ }
+
+ // Existing symbol is not a DefinedRegular; new symbol wins.
+ return SP_NEW;
+}
+
SymbolTable *Symtab;
void SymbolTable::addFile(InputFile *File) {
- if (Config->Verbose)
- outs() << "Reading " << toString(File) << "\n";
+ log("Reading " + toString(File));
File->parse();
MachineTypes MT = File->getMachineType();
@@ -51,8 +80,7 @@ void SymbolTable::addFile(InputFile *File) {
if (S.empty())
return;
- if (Config->Verbose)
- outs() << "Directives: " << toString(File) << ": " << S << "\n";
+ log("Directives: " + toString(File) + ": " + S);
Driver->parseDirectives(S);
}
@@ -106,12 +134,11 @@ void SymbolTable::reportRemainingUndefines() {
return;
for (SymbolBody *B : Config->GCRoot)
if (Undefs.count(B))
- errs() << "<root>: undefined symbol: " << B->getName() << "\n";
+ warn("<root>: undefined symbol: " + B->getName());
for (ObjectFile *File : ObjectFiles)
for (SymbolBody *Sym : File->getSymbols())
if (Undefs.count(Sym))
- errs() << toString(File) << ": undefined symbol: " << Sym->getName()
- << "\n";
+ warn(toString(File) + ": undefined symbol: " + Sym->getName());
if (!Config->Force)
fatal("link failed");
}
@@ -163,7 +190,7 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
}
void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
- fatal("duplicate symbol: " + toString(*Existing->body()) + " in " +
+ error("duplicate symbol: " + toString(*Existing->body()) + " in " +
toString(Existing->body()->getFile()) + " and in " +
(NewFile ? toString(NewFile) : "(internal)"));
}
@@ -192,71 +219,53 @@ Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
return S;
}
-Symbol *SymbolTable::addRelative(StringRef N, uint64_t VA) {
+Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
- replaceBody<DefinedRelative>(S, N, VA);
+ replaceBody<DefinedSynthetic>(S, N, C);
else if (!isa<DefinedCOFF>(S->body()))
reportDuplicate(S, nullptr);
return S;
}
-Symbol *SymbolTable::addRegular(ObjectFile *F, COFFSymbolRef Sym,
+Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+ const coff_symbol_generic *Sym,
SectionChunk *C) {
- StringRef Name;
- F->getCOFFObj()->getSymbolName(Sym, Name);
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- S->IsUsedInRegularObj = true;
- if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
- replaceBody<DefinedRegular>(S, F, Sym, C);
- else if (auto *R = dyn_cast<DefinedRegular>(S->body())) {
- if (!C->isCOMDAT() || !R->isCOMDAT())
- reportDuplicate(S, F);
- } else if (auto *B = dyn_cast<DefinedBitcode>(S->body())) {
- if (B->IsReplaceable)
- replaceBody<DefinedRegular>(S, F, Sym, C);
- else if (!C->isCOMDAT())
- reportDuplicate(S, F);
- } else
- replaceBody<DefinedRegular>(S, F, Sym, C);
- return S;
-}
-
-Symbol *SymbolTable::addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N);
- if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) {
- replaceBody<DefinedBitcode>(S, F, N, IsReplaceable);
- return S;
+ if (!isa<BitcodeFile>(F))
+ S->IsUsedInRegularObj = true;
+ SymbolPreference SP = compareDefined(S, WasInserted, IsCOMDAT);
+ if (SP == SP_CONFLICT) {
+ reportDuplicate(S, F);
+ } else if (SP == SP_NEW) {
+ replaceBody<DefinedRegular>(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C);
+ } else if (SP == SP_EXISTING && IsCOMDAT && C) {
+ C->markDiscarded();
+ // Discard associative chunks that we've parsed so far. No need to recurse
+ // because an associative section cannot have children.
+ for (SectionChunk *Child : C->children())
+ Child->markDiscarded();
}
- if (isa<DefinedCommon>(S->body()))
- return S;
- if (IsReplaceable)
- if (isa<DefinedRegular>(S->body()) || isa<DefinedBitcode>(S->body()))
- return S;
- reportDuplicate(S, F);
return S;
}
-Symbol *SymbolTable::addCommon(ObjectFile *F, COFFSymbolRef Sym,
- CommonChunk *C) {
- StringRef Name;
- F->getCOFFObj()->getSymbolName(Sym, Name);
+Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
+ const coff_symbol_generic *Sym, CommonChunk *C) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(N);
+ if (!isa<BitcodeFile>(F))
+ S->IsUsedInRegularObj = true;
if (WasInserted || !isa<DefinedCOFF>(S->body()))
- replaceBody<DefinedCommon>(S, F, Sym, C);
+ replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
else if (auto *DC = dyn_cast<DefinedCommon>(S->body()))
- if (Sym.getValue() > DC->getSize())
- replaceBody<DefinedCommon>(S, F, Sym, C);
+ if (Size > DC->getSize())
+ replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
return S;
}
@@ -345,75 +354,21 @@ SymbolBody *SymbolTable::addUndefined(StringRef Name) {
return addUndefined(Name, nullptr, false)->body();
}
-void SymbolTable::printMap(llvm::raw_ostream &OS) {
- for (ObjectFile *File : ObjectFiles) {
- OS << toString(File) << ":\n";
- for (SymbolBody *Body : File->getSymbols())
- if (auto *R = dyn_cast<DefinedRegular>(Body))
- if (R->getChunk()->isLive())
- OS << Twine::utohexstr(Config->ImageBase + R->getRVA())
- << " " << R->getName() << "\n";
- }
+std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
+ LTO.reset(new BitcodeCompiler);
+ for (BitcodeFile *F : BitcodeFiles)
+ LTO->add(*F);
+ return LTO->compile();
}
void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFiles.empty())
return;
-
- // Create an object file and add it to the symbol table by replacing any
- // DefinedBitcode symbols with the definitions in the object file.
- LTOCodeGenerator CG(BitcodeFile::Context);
- CG.setOptLevel(Config->LTOOptLevel);
- for (ObjectFile *Obj : createLTOObjects(&CG))
+ for (StringRef Object : compileBitcodeFiles()) {
+ auto *Obj = make<ObjectFile>(MemoryBufferRef(Object, "lto.tmp"));
Obj->parse();
-}
-
-// Combine and compile bitcode files and then return the result
-// as a vector of regular COFF object files.
-std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) {
- // All symbols referenced by non-bitcode objects, including GC roots, must be
- // preserved. We must also replace bitcode symbols with undefined symbols so
- // that they may be replaced with real definitions without conflicting.
- for (BitcodeFile *File : BitcodeFiles)
- for (SymbolBody *Body : File->getSymbols()) {
- if (!isa<DefinedBitcode>(Body))
- continue;
- if (Body->symbol()->IsUsedInRegularObj)
- CG->addMustPreserveSymbol(Body->getName());
- replaceBody<Undefined>(Body->symbol(), Body->getName());
- }
-
- CG->setModule(BitcodeFiles[0]->takeModule());
- for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I)
- CG->addModule(BitcodeFiles[I]->takeModule().get());
-
- bool DisableVerify = true;
-#ifdef NDEBUG
- DisableVerify = false;
-#endif
- if (!CG->optimize(DisableVerify, false, false, false))
- fatal(""); // optimize() should have emitted any error message.
-
- Objs.resize(Config->LTOJobs);
- // Use std::list to avoid invalidation of pointers in OSPtrs.
- std::list<raw_svector_ostream> OSs;
- std::vector<raw_pwrite_stream *> OSPtrs;
- for (SmallString<0> &Obj : Objs) {
- OSs.emplace_back(Obj);
- OSPtrs.push_back(&OSs.back());
+ ObjectFiles.push_back(Obj);
}
-
- if (!CG->compileOptimized(OSPtrs))
- fatal(""); // compileOptimized() should have emitted any error message.
-
- std::vector<ObjectFile *> ObjFiles;
- for (SmallString<0> &Obj : Objs) {
- auto *ObjFile = make<ObjectFile>(MemoryBufferRef(Obj, "<LTO object>"));
- ObjectFiles.push_back(ObjFile);
- ObjFiles.push_back(ObjFile);
- }
-
- return ObjFiles;
}
} // namespace coff
diff --git a/contrib/llvm/tools/lld/COFF/SymbolTable.h b/contrib/llvm/tools/lld/COFF/SymbolTable.h
index 703821f..ea74678 100644
--- a/contrib/llvm/tools/lld/COFF/SymbolTable.h
+++ b/contrib/llvm/tools/lld/COFF/SymbolTable.h
@@ -11,10 +11,10 @@
#define LLD_COFF_SYMBOL_TABLE_H
#include "InputFiles.h"
+#include "LTO.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
-#include "llvm/Support/Allocator.h"
#include "llvm/Support/raw_ostream.h"
namespace llvm {
@@ -69,13 +69,11 @@ public:
void mangleMaybe(SymbolBody *B);
StringRef findMangle(StringRef Name);
- // Print a layout map to OS.
- void printMap(llvm::raw_ostream &OS);
-
// Build a set of COFF objects representing the combined contents of
// BitcodeFiles and add them to the symbol table. Called after all files are
// added and before the writer writes results to a file.
void addCombinedLTOObjects();
+ std::vector<StringRef> compileBitcodeFiles();
// The writer needs to handle DLL import libraries specially in
// order to create the import descriptor table.
@@ -87,15 +85,18 @@ public:
// Creates an Undefined symbol for a given name.
SymbolBody *addUndefined(StringRef Name);
- Symbol *addRelative(StringRef N, uint64_t VA);
+ Symbol *addSynthetic(StringRef N, Chunk *C);
Symbol *addAbsolute(StringRef N, uint64_t VA);
Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias);
void addLazy(ArchiveFile *F, const Archive::Symbol Sym);
Symbol *addAbsolute(StringRef N, COFFSymbolRef S);
- Symbol *addRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C);
- Symbol *addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable);
- Symbol *addCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C);
+ Symbol *addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+ const llvm::object::coff_symbol_generic *S = nullptr,
+ SectionChunk *C = nullptr);
+ Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size,
+ const llvm::object::coff_symbol_generic *S = nullptr,
+ CommonChunk *C = nullptr);
Symbol *addImportData(StringRef N, ImportFile *F);
Symbol *addImportThunk(StringRef Name, DefinedImportData *S,
uint16_t Machine);
@@ -106,19 +107,13 @@ public:
std::vector<Chunk *> LocalImportChunks;
private:
- void readArchive();
- void readObjects();
-
std::pair<Symbol *, bool> insert(StringRef Name);
StringRef findByPrefix(StringRef Prefix);
- void addCombinedLTOObject(ObjectFile *Obj);
- std::vector<ObjectFile *> createLTOObjects(llvm::LTOCodeGenerator *CG);
-
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> Symtab;
std::vector<BitcodeFile *> BitcodeFiles;
- std::vector<SmallString<0>> Objs;
+ std::unique_ptr<BitcodeCompiler> LTO;
};
extern SymbolTable *Symtab;
diff --git a/contrib/llvm/tools/lld/COFF/Symbols.cpp b/contrib/llvm/tools/lld/COFF/Symbols.cpp
index c44537d..9b59079 100644
--- a/contrib/llvm/tools/lld/COFF/Symbols.cpp
+++ b/contrib/llvm/tools/lld/COFF/Symbols.cpp
@@ -30,7 +30,7 @@ namespace lld {
namespace coff {
StringRef SymbolBody::getName() {
- // DefinedCOFF names are read lazily for a performance reason.
+ // COFF symbol names are read lazily for a performance reason.
// Non-external symbol names are never used by the linker except for logging
// or debugging. Their internal references are resolved not by name but by
// symbol index. And because they are not external, no one can refer them by
@@ -39,7 +39,7 @@ StringRef SymbolBody::getName() {
// is a waste of time.
if (Name.empty()) {
auto *D = cast<DefinedCOFF>(this);
- D->File->getCOFFObj()->getSymbolName(D->Sym, Name);
+ cast<ObjectFile>(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name);
}
return Name;
}
@@ -47,31 +47,37 @@ StringRef SymbolBody::getName() {
InputFile *SymbolBody::getFile() {
if (auto *Sym = dyn_cast<DefinedCOFF>(this))
return Sym->File;
- if (auto *Sym = dyn_cast<DefinedBitcode>(this))
- return Sym->File;
if (auto *Sym = dyn_cast<Lazy>(this))
return Sym->File;
return nullptr;
}
COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
- size_t SymSize = File->getCOFFObj()->getSymbolTableEntrySize();
+ size_t SymSize =
+ cast<ObjectFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
if (SymSize == sizeof(coff_symbol16))
return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym));
assert(SymSize == sizeof(coff_symbol32));
return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));
}
+uint16_t DefinedAbsolute::OutputSectionIndex = 0;
+
+static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) {
+ if (Machine == AMD64)
+ return make<ImportThunkChunkX64>(S);
+ if (Machine == I386)
+ return make<ImportThunkChunkX86>(S);
+ if (Machine == ARM64)
+ return make<ImportThunkChunkARM64>(S);
+ assert(Machine == ARMNT);
+ return make<ImportThunkChunkARM>(S);
+}
+
DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S,
uint16_t Machine)
- : Defined(DefinedImportThunkKind, Name) {
- switch (Machine) {
- case AMD64: Data = make<ImportThunkChunkX64>(S); return;
- case I386: Data = make<ImportThunkChunkX86>(S); return;
- case ARMNT: Data = make<ImportThunkChunkARM>(S); return;
- default: llvm_unreachable("unknown machine type");
- }
-}
+ : Defined(DefinedImportThunkKind, Name), WrappedSym(S),
+ Data(makeImportThunk(S, Machine)) {}
Defined *Undefined::getWeakAlias() {
// A weak alias may be a weak alias to another symbol, so check recursively.
diff --git a/contrib/llvm/tools/lld/COFF/Symbols.h b/contrib/llvm/tools/lld/COFF/Symbols.h
index 1ca7366..a12ae1c 100644
--- a/contrib/llvm/tools/lld/COFF/Symbols.h
+++ b/contrib/llvm/tools/lld/COFF/Symbols.h
@@ -30,7 +30,6 @@ using llvm::object::coff_import_header;
using llvm::object::coff_symbol_generic;
class ArchiveFile;
-class BitcodeFile;
class InputFile;
class ObjectFile;
struct Symbol;
@@ -51,14 +50,13 @@ public:
DefinedImportThunkKind,
DefinedImportDataKind,
DefinedAbsoluteKind,
- DefinedRelativeKind,
- DefinedBitcodeKind,
+ DefinedSyntheticKind,
UndefinedKind,
LazyKind,
LastDefinedCOFFKind = DefinedCommonKind,
- LastDefinedKind = DefinedBitcodeKind,
+ LastDefinedKind = DefinedSyntheticKind,
};
Kind kind() const { return static_cast<Kind>(SymbolKind); }
@@ -81,7 +79,7 @@ protected:
friend SymbolTable;
explicit SymbolBody(Kind K, StringRef N = "")
: SymbolKind(K), IsExternal(true), IsCOMDAT(false),
- IsReplaceable(false), WrittenToSymtab(false), Name(N) {}
+ WrittenToSymtab(false), Name(N) {}
const unsigned SymbolKind : 8;
unsigned IsExternal : 1;
@@ -89,11 +87,9 @@ protected:
// This bit is used by the \c DefinedRegular subclass.
unsigned IsCOMDAT : 1;
- // This bit is used by the \c DefinedBitcode subclass.
- unsigned IsReplaceable : 1;
-
public:
- // This bit is used by Writer::createSymbolAndStringTable().
+ // This bit is used by Writer::createSymbolAndStringTable() to prevent
+ // symbols from being written to the symbol table more than once.
unsigned WrittenToSymtab : 1;
protected:
@@ -104,7 +100,7 @@ protected:
// etc.
class Defined : public SymbolBody {
public:
- Defined(Kind K, StringRef N = "") : SymbolBody(K, N) {}
+ Defined(Kind K, StringRef N) : SymbolBody(K, N) {}
static bool classof(const SymbolBody *S) {
return S->kind() <= LastDefinedKind;
@@ -114,35 +110,30 @@ public:
// writer sets and uses RVAs.
uint64_t getRVA();
- // Returns the RVA relative to the beginning of the output section.
- // Used to implement SECREL relocation type.
- uint64_t getSecrel();
-
- // Returns the output section index.
- // Used to implement SECTION relocation type.
- uint64_t getSectionIndex();
-
- // Returns true if this symbol points to an executable (e.g. .text) section.
- // Used to implement ARM relocations.
- bool isExecutable();
+ // Returns the chunk containing this symbol. Absolute symbols and __ImageBase
+ // do not have chunks, so this may return null.
+ Chunk *getChunk();
};
-// Symbols defined via a COFF object file.
+// Symbols defined via a COFF object file or bitcode file. For COFF files, this
+// stores a coff_symbol_generic*, and names of internal symbols are lazily
+// loaded through that. For bitcode files, Sym is nullptr and the name is stored
+// as a StringRef.
class DefinedCOFF : public Defined {
friend SymbolBody;
public:
- DefinedCOFF(Kind K, ObjectFile *F, COFFSymbolRef S)
- : Defined(K), File(F), Sym(S.getGeneric()) {}
+ DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S)
+ : Defined(K, N), File(F), Sym(S) {}
static bool classof(const SymbolBody *S) {
return S->kind() <= LastDefinedCOFFKind;
}
- ObjectFile *getFile() { return File; }
+ InputFile *getFile() { return File; }
COFFSymbolRef getCOFFSymbol();
- ObjectFile *File;
+ InputFile *File;
protected:
const coff_symbol_generic *Sym;
@@ -151,10 +142,13 @@ protected:
// Regular defined symbols read from object file symbol tables.
class DefinedRegular : public DefinedCOFF {
public:
- DefinedRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C)
- : DefinedCOFF(DefinedRegularKind, F, S), Data(&C->Repl) {
- IsExternal = S.isExternal();
- IsCOMDAT = C->isCOMDAT();
+ DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+ bool IsExternal = false,
+ const coff_symbol_generic *S = nullptr,
+ SectionChunk *C = nullptr)
+ : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) {
+ this->IsExternal = IsExternal;
+ this->IsCOMDAT = IsCOMDAT;
}
static bool classof(const SymbolBody *S) {
@@ -172,9 +166,11 @@ private:
class DefinedCommon : public DefinedCOFF {
public:
- DefinedCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C)
- : DefinedCOFF(DefinedCommonKind, F, S), Data(C) {
- IsExternal = S.isExternal();
+ DefinedCommon(InputFile *F, StringRef N, uint64_t Size,
+ const coff_symbol_generic *S = nullptr,
+ CommonChunk *C = nullptr)
+ : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) {
+ this->IsExternal = true;
}
static bool classof(const SymbolBody *S) {
@@ -182,11 +178,13 @@ public:
}
uint64_t getRVA() { return Data->getRVA(); }
+ Chunk *getChunk() { return Data; }
private:
friend SymbolTable;
- uint64_t getSize() { return Sym->Value; }
+ uint64_t getSize() const { return Size; }
CommonChunk *Data;
+ uint64_t Size;
};
// Absolute symbols.
@@ -207,28 +205,34 @@ public:
uint64_t getRVA() { return VA - Config->ImageBase; }
void setVA(uint64_t V) { VA = V; }
+ // The sentinel absolute symbol section index. Section index relocations
+ // against absolute symbols resolve to this 16 bit number, and it is the
+ // largest valid section index plus one. This is written by the Writer.
+ static uint16_t OutputSectionIndex;
+ uint16_t getSecIdx() { return OutputSectionIndex; }
+
private:
uint64_t VA;
};
-// This is a kind of absolute symbol but relative to the image base.
-// Unlike absolute symbols, relocations referring this kind of symbols
-// are subject of the base relocation. This type is used rarely --
-// mainly for __ImageBase.
-class DefinedRelative : public Defined {
+// This symbol is used for linker-synthesized symbols like __ImageBase and
+// __safe_se_handler_table.
+class DefinedSynthetic : public Defined {
public:
- explicit DefinedRelative(StringRef Name, uint64_t V = 0)
- : Defined(DefinedRelativeKind, Name), RVA(V) {}
+ explicit DefinedSynthetic(StringRef Name, Chunk *C)
+ : Defined(DefinedSyntheticKind, Name), C(C) {}
static bool classof(const SymbolBody *S) {
- return S->kind() == DefinedRelativeKind;
+ return S->kind() == DefinedSyntheticKind;
}
- uint64_t getRVA() { return RVA; }
- void setRVA(uint64_t V) { RVA = V; }
+ // A null chunk indicates that this is __ImageBase. Otherwise, this is some
+ // other synthesized chunk, like SEHTableChunk.
+ uint32_t getRVA() { return C ? C->getRVA() : 0; }
+ Chunk *getChunk() { return C; }
private:
- uint64_t RVA;
+ Chunk *C;
};
// This class represents a symbol defined in an archive file. It is
@@ -290,12 +294,13 @@ public:
}
uint64_t getRVA() { return File->Location->getRVA(); }
+ Chunk *getChunk() { return File->Location; }
+ void setLocation(Chunk *AddressTable) { File->Location = AddressTable; }
+
StringRef getDLLName() { return File->DLLName; }
StringRef getExternalName() { return File->ExternalName; }
- void setLocation(Chunk *AddressTable) { File->Location = AddressTable; }
uint16_t getOrdinal() { return File->Hdr->OrdinalHint; }
-private:
ImportFile *File;
};
@@ -315,6 +320,8 @@ public:
uint64_t getRVA() { return Data->getRVA(); }
Chunk *getChunk() { return Data; }
+ DefinedImportData *WrappedSym;
+
private:
Chunk *Data;
};
@@ -340,32 +347,12 @@ private:
LocalImportChunk *Data;
};
-class DefinedBitcode : public Defined {
- friend SymbolBody;
-public:
- DefinedBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable)
- : Defined(DefinedBitcodeKind, N), File(F) {
- // IsReplaceable tracks whether the bitcode symbol may be replaced with some
- // other (defined, common or bitcode) symbol. This is the case for common,
- // comdat and weak external symbols. We try to replace bitcode symbols with
- // "real" symbols (see SymbolTable::add{Regular,Bitcode}), and resolve the
- // result against the real symbol from the combined LTO object.
- this->IsReplaceable = IsReplaceable;
- }
-
- static bool classof(const SymbolBody *S) {
- return S->kind() == DefinedBitcodeKind;
- }
-
- BitcodeFile *File;
-};
-
inline uint64_t Defined::getRVA() {
switch (kind()) {
case DefinedAbsoluteKind:
return cast<DefinedAbsolute>(this)->getRVA();
- case DefinedRelativeKind:
- return cast<DefinedRelative>(this)->getRVA();
+ case DefinedSyntheticKind:
+ return cast<DefinedSynthetic>(this)->getRVA();
case DefinedImportDataKind:
return cast<DefinedImportData>(this)->getRVA();
case DefinedImportThunkKind:
@@ -376,8 +363,6 @@ inline uint64_t Defined::getRVA() {
return cast<DefinedCommon>(this)->getRVA();
case DefinedRegularKind:
return cast<DefinedRegular>(this)->getRVA();
- case DefinedBitcodeKind:
- llvm_unreachable("There is no address for a bitcode symbol.");
case LazyKind:
case UndefinedKind:
llvm_unreachable("Cannot get the address for an undefined symbol.");
@@ -385,6 +370,29 @@ inline uint64_t Defined::getRVA() {
llvm_unreachable("unknown symbol kind");
}
+inline Chunk *Defined::getChunk() {
+ switch (kind()) {
+ case DefinedRegularKind:
+ return cast<DefinedRegular>(this)->getChunk();
+ case DefinedAbsoluteKind:
+ return nullptr;
+ case DefinedSyntheticKind:
+ return cast<DefinedSynthetic>(this)->getChunk();
+ case DefinedImportDataKind:
+ return cast<DefinedImportData>(this)->getChunk();
+ case DefinedImportThunkKind:
+ return cast<DefinedImportThunk>(this)->getChunk();
+ case DefinedLocalImportKind:
+ return cast<DefinedLocalImport>(this)->getChunk();
+ case DefinedCommonKind:
+ return cast<DefinedCommon>(this)->getChunk();
+ case LazyKind:
+ case UndefinedKind:
+ llvm_unreachable("Cannot get the chunk of an undefined symbol.");
+ }
+ llvm_unreachable("unknown symbol kind");
+}
+
// A real symbol object, SymbolBody, is usually stored within a Symbol. There's
// always one Symbol for each symbol name. The resolver updates the SymbolBody
// stored in the Body field of this object as it resolves symbols. Symbol also
@@ -401,10 +409,9 @@ struct Symbol {
// This field is used to store the Symbol's SymbolBody. This instantiation of
// AlignedCharArrayUnion gives us a struct with a char array field that is
// large and aligned enough to store any derived class of SymbolBody.
- llvm::AlignedCharArrayUnion<DefinedRegular, DefinedCommon, DefinedAbsolute,
- DefinedRelative, Lazy, Undefined,
- DefinedImportData, DefinedImportThunk,
- DefinedLocalImport, DefinedBitcode>
+ llvm::AlignedCharArrayUnion<
+ DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedSynthetic, Lazy,
+ Undefined, DefinedImportData, DefinedImportThunk, DefinedLocalImport>
Body;
SymbolBody *body() {
diff --git a/contrib/llvm/tools/lld/COFF/Writer.cpp b/contrib/llvm/tools/lld/COFF/Writer.cpp
index 71217eb..a6a5e27 100644
--- a/contrib/llvm/tools/lld/COFF/Writer.cpp
+++ b/contrib/llvm/tools/lld/COFF/Writer.cpp
@@ -12,17 +12,18 @@
#include "DLL.h"
#include "Error.h"
#include "InputFiles.h"
+#include "MapFile.h"
#include "Memory.h"
#include "PDB.h"
#include "SymbolTable.h"
#include "Symbols.h"
-#include "lld/Core/Parallel.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Parallel.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -39,7 +40,6 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::coff;
-static const int PageSize = 4096;
static const int SectorSize = 512;
static const int DOSStubSize = 64;
static const int NumberfOfDataDirectory = 16;
@@ -48,8 +48,7 @@ namespace {
class DebugDirectoryChunk : public Chunk {
public:
- DebugDirectoryChunk(const std::vector<std::unique_ptr<Chunk>> &R)
- : Records(R) {}
+ DebugDirectoryChunk(const std::vector<Chunk *> &R) : Records(R) {}
size_t getSize() const override {
return Records.size() * sizeof(debug_directory);
@@ -58,7 +57,7 @@ public:
void writeTo(uint8_t *B) const override {
auto *D = reinterpret_cast<debug_directory *>(B + OutputSectionOff);
- for (const std::unique_ptr<Chunk> &Record : Records) {
+ for (const Chunk *Record : Records) {
D->Characteristics = 0;
D->TimeDateStamp = 0;
D->MajorVersion = 0;
@@ -74,7 +73,7 @@ public:
}
private:
- const std::vector<std::unique_ptr<Chunk>> &Records;
+ const std::vector<Chunk *> &Records;
};
class CVDebugRecordChunk : public Chunk {
@@ -121,7 +120,6 @@ private:
void writeSections();
void sortExceptionTable();
void writeBuildId();
- void applyRelocations();
llvm::Optional<coff_symbol16> createSymbol(Defined *D);
size_t addEntryToStringTable(StringRef Str);
@@ -142,10 +140,10 @@ private:
IdataContents Idata;
DelayLoadContents DelayIdata;
EdataContents Edata;
- std::unique_ptr<SEHTableChunk> SEHTable;
+ SEHTableChunk *SEHTable = nullptr;
- std::unique_ptr<Chunk> DebugDirectory;
- std::vector<std::unique_ptr<Chunk>> DebugRecords;
+ Chunk *DebugDirectory = nullptr;
+ std::vector<Chunk *> DebugRecords;
CVDebugRecordChunk *BuildId = nullptr;
ArrayRef<uint8_t> SectionTable;
@@ -153,8 +151,6 @@ private:
uint32_t PointerToSymbolTable = 0;
uint64_t SizeOfImage;
uint64_t SizeOfHeaders;
-
- std::vector<std::unique_ptr<Chunk>> Chunks;
};
} // anonymous namespace
@@ -163,51 +159,6 @@ namespace coff {
void writeResult(SymbolTable *T) { Writer(T).run(); }
-// OutputSection represents a section in an output file. It's a
-// container of chunks. OutputSection and Chunk are 1:N relationship.
-// Chunks cannot belong to more than one OutputSections. The writer
-// creates multiple OutputSections and assign them unique,
-// non-overlapping file offsets and RVAs.
-class OutputSection {
-public:
- OutputSection(StringRef N) : Name(N), Header({}) {}
- void setRVA(uint64_t);
- void setFileOffset(uint64_t);
- void addChunk(Chunk *C);
- StringRef getName() { return Name; }
- std::vector<Chunk *> &getChunks() { return Chunks; }
- void addPermissions(uint32_t C);
- void setPermissions(uint32_t C);
- uint32_t getPermissions() { return Header.Characteristics & PermMask; }
- uint32_t getCharacteristics() { return Header.Characteristics; }
- uint64_t getRVA() { return Header.VirtualAddress; }
- uint64_t getFileOff() { return Header.PointerToRawData; }
- void writeHeaderTo(uint8_t *Buf);
-
- // Returns the size of this section in an executable memory image.
- // This may be smaller than the raw size (the raw size is multiple
- // of disk sector size, so there may be padding at end), or may be
- // larger (if that's the case, the loader reserves spaces after end
- // of raw data).
- uint64_t getVirtualSize() { return Header.VirtualSize; }
-
- // Returns the size of the section in the output file.
- uint64_t getRawSize() { return Header.SizeOfRawData; }
-
- // Set offset into the string table storing this section name.
- // Used only when the name is longer than 8 bytes.
- void setStringTableOff(uint32_t V) { StringTableOff = V; }
-
- // N.B. The section index is one based.
- uint32_t SectionIndex = 0;
-
-private:
- StringRef Name;
- coff_section Header;
- uint32_t StringTableOff = 0;
- std::vector<Chunk *> Chunks;
-};
-
void OutputSection::setRVA(uint64_t RVA) {
Header.VirtualAddress = RVA;
for (Chunk *C : Chunks)
@@ -229,7 +180,7 @@ void OutputSection::addChunk(Chunk *C) {
uint64_t Off = Header.VirtualSize;
Off = alignTo(Off, C->getAlign());
C->setRVA(Off);
- C->setOutputSectionOff(Off);
+ C->OutputSectionOff = Off;
Off += C->getSize();
Header.VirtualSize = Off;
if (C->hasData())
@@ -258,25 +209,6 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) {
}
}
-uint64_t Defined::getSecrel() {
- if (auto *D = dyn_cast<DefinedRegular>(this))
- return getRVA() - D->getChunk()->getOutputSection()->getRVA();
- fatal("SECREL relocation points to a non-regular symbol");
-}
-
-uint64_t Defined::getSectionIndex() {
- if (auto *D = dyn_cast<DefinedRegular>(this))
- return D->getChunk()->getOutputSection()->SectionIndex;
- fatal("SECTION relocation points to a non-regular symbol");
-}
-
-bool Defined::isExecutable() {
- const auto X = IMAGE_SCN_MEM_EXECUTE;
- if (auto *D = dyn_cast<DefinedRegular>(this))
- return D->getChunk()->getOutputSection()->getPermissions() & X;
- return isa<DefinedImportThunk>(this);
-}
-
} // namespace coff
} // namespace lld
@@ -303,8 +235,14 @@ void Writer::run() {
sortExceptionTable();
writeBuildId();
- if (!Config->PDBPath.empty())
- createPDB(Config->PDBPath, Symtab, SectionTable, BuildId->DI);
+ if (!Config->PDBPath.empty() && Config->Debug) {
+ const llvm::codeview::DebugInfo *DI = nullptr;
+ if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV))
+ DI = BuildId->DI;
+ createPDB(Symtab, SectionTable, DI);
+ }
+
+ writeMapFile(OutputSections);
if (auto EC = Buffer->commit())
fatal(EC, "failed to write the output file");
@@ -363,19 +301,19 @@ void Writer::createMiscChunks() {
// Create Debug Information Chunks
if (Config->Debug) {
- DebugDirectory = llvm::make_unique<DebugDirectoryChunk>(DebugRecords);
+ DebugDirectory = make<DebugDirectoryChunk>(DebugRecords);
// TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV)) {
- auto Chunk = llvm::make_unique<CVDebugRecordChunk>();
+ auto *Chunk = make<CVDebugRecordChunk>();
- BuildId = Chunk.get();
- DebugRecords.push_back(std::move(Chunk));
+ BuildId = Chunk;
+ DebugRecords.push_back(Chunk);
}
- RData->addChunk(DebugDirectory.get());
- for (const std::unique_ptr<Chunk> &C : DebugRecords)
- RData->addChunk(C.get());
+ RData->addChunk(DebugDirectory);
+ for (Chunk *C : DebugRecords)
+ RData->addChunk(C);
}
// Create SEH table. x86-only.
@@ -387,12 +325,19 @@ void Writer::createMiscChunks() {
for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) {
if (!File->SEHCompat)
return;
- for (SymbolBody *B : File->SEHandlers)
- Handlers.insert(cast<Defined>(B));
+ for (SymbolBody *B : File->SEHandlers) {
+ // Make sure the handler is still live. Assume all handlers are regular
+ // symbols.
+ auto *D = dyn_cast<DefinedRegular>(B);
+ if (D && D->getChunk()->isLive())
+ Handlers.insert(D);
+ }
}
- SEHTable.reset(new SEHTableChunk(Handlers));
- RData->addChunk(SEHTable.get());
+ if (!Handlers.empty()) {
+ SEHTable = make<SEHTableChunk>(Handlers);
+ RData->addChunk(SEHTable);
+ }
}
// Create .idata section for the DLL-imported symbol table.
@@ -407,6 +352,9 @@ void Writer::createImportTables() {
// the same order as in the command line. (That affects DLL
// initialization order, and this ordering is MSVC-compatible.)
for (ImportFile *File : Symtab->ImportFiles) {
+ if (!File->Live)
+ continue;
+
std::string DLL = StringRef(File->DLLName).lower();
if (Config->DLLOrder.count(DLL) == 0)
Config->DLLOrder[DLL] = Config->DLLOrder.size();
@@ -414,19 +362,28 @@ void Writer::createImportTables() {
OutputSection *Text = createSection(".text");
for (ImportFile *File : Symtab->ImportFiles) {
+ if (!File->Live)
+ continue;
+
if (DefinedImportThunk *Thunk = File->ThunkSym)
Text->addChunk(Thunk->getChunk());
+
if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
+ if (!File->ThunkSym)
+ fatal("cannot delay-load " + toString(File) +
+ " due to import of data: " + toString(*File->ImpSym));
DelayIdata.add(File->ImpSym);
} else {
Idata.add(File->ImpSym);
}
}
+
if (!Idata.empty()) {
OutputSection *Sec = createSection(".idata");
for (Chunk *C : Idata.getChunks())
Sec->addChunk(C);
}
+
if (!DelayIdata.empty()) {
Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
DelayIdata.create(Helper);
@@ -437,8 +394,8 @@ void Writer::createImportTables() {
for (Chunk *C : DelayIdata.getDataChunks())
Sec->addChunk(C);
Sec = createSection(".text");
- for (std::unique_ptr<Chunk> &C : DelayIdata.getCodeChunks())
- Sec->addChunk(C.get());
+ for (Chunk *C : DelayIdata.getCodeChunks())
+ Sec->addChunk(C);
}
}
@@ -446,8 +403,8 @@ void Writer::createExportTable() {
if (Config->Exports.empty())
return;
OutputSection *Sec = createSection(".edata");
- for (std::unique_ptr<Chunk> &C : Edata.Chunks)
- Sec->addChunk(C.get());
+ for (Chunk *C : Edata.Chunks)
+ Sec->addChunk(C);
}
// The Windows loader doesn't seem to like empty sections,
@@ -472,11 +429,22 @@ size_t Writer::addEntryToStringTable(StringRef Str) {
Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
// Relative symbols are unrepresentable in a COFF symbol table.
- if (isa<DefinedRelative>(Def))
+ if (isa<DefinedSynthetic>(Def))
return None;
- if (auto *D = dyn_cast<DefinedRegular>(Def))
- if (!D->getChunk()->isLive())
+ if (auto *D = dyn_cast<DefinedRegular>(Def)) {
+ // Don't write dead symbols or symbols in codeview sections to the symbol
+ // table.
+ if (!D->getChunk()->isLive() || D->getChunk()->isCodeView())
+ return None;
+ }
+
+ if (auto *Sym = dyn_cast<DefinedImportData>(Def))
+ if (!Sym->File->Live)
+ return None;
+
+ if (auto *Sym = dyn_cast<DefinedImportThunk>(Def))
+ if (!Sym->WrappedSym->File->Live)
return None;
coff_symbol16 Sym;
@@ -533,14 +501,17 @@ void Writer::createSymbolAndStringTable() {
Sec->setStringTableOff(addEntryToStringTable(Name));
}
- for (lld::coff::ObjectFile *File : Symtab->ObjectFiles)
- for (SymbolBody *B : File->getSymbols())
- if (auto *D = dyn_cast<Defined>(B))
- if (!D->WrittenToSymtab) {
- D->WrittenToSymtab = true;
- if (Optional<coff_symbol16> Sym = createSymbol(D))
- OutputSymtab.push_back(*Sym);
- }
+ for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) {
+ for (SymbolBody *B : File->getSymbols()) {
+ auto *D = dyn_cast<Defined>(B);
+ if (!D || D->WrittenToSymtab)
+ continue;
+ D->WrittenToSymtab = true;
+
+ if (Optional<coff_symbol16> Sym = createSymbol(D))
+ OutputSymtab.push_back(*Sym);
+ }
+ }
OutputSection *LastSection = OutputSections.back();
// We position the symbol table to be adjacent to the end of the last section.
@@ -618,6 +589,15 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
auto *PE = reinterpret_cast<PEHeaderTy *>(Buf);
Buf += sizeof(*PE);
PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;
+
+ // If {Major,Minor}LinkerVersion is left at 0.0, then for some
+ // reason signing the resulting PE file with Authenticode produces a
+ // signature that fails to validate on Windows 7 (but is OK on 10).
+ // Set it to 14.0, which is what VS2015 outputs, and which avoids
+ // that problem.
+ PE->MajorLinkerVersion = 14;
+ PE->MinorLinkerVersion = 0;
+
PE->ImageBase = Config->ImageBase;
PE->SectionAlignment = PageSize;
PE->FileAlignment = SectorSize;
@@ -641,12 +621,19 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
PE->SizeOfStackCommit = Config->StackCommit;
PE->SizeOfHeapReserve = Config->HeapReserve;
PE->SizeOfHeapCommit = Config->HeapCommit;
+
+ // Import Descriptor Tables and Import Address Tables are merged
+ // in our output. That's not compatible with the Binding feature
+ // that is sort of prelinking. Setting this flag to make it clear
+ // that our outputs are not for the Binding.
+ PE->DLLCharacteristics = IMAGE_DLL_CHARACTERISTICS_NO_BIND;
+
+ if (Config->AppContainer)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
if (Config->DynamicBase)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
if (Config->HighEntropyVA)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
- if (!Config->AllowBind)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;
if (Config->NxCompat)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
if (!Config->AllowIsolation)
@@ -755,10 +742,13 @@ void Writer::openFile(StringRef Path) {
void Writer::fixSafeSEHSymbols() {
if (!SEHTable)
return;
- if (auto *T = dyn_cast<DefinedRelative>(Config->SEHTable->body()))
- T->setRVA(SEHTable->getRVA());
- if (auto *C = dyn_cast<DefinedAbsolute>(Config->SEHCount->body()))
- C->setVA(SEHTable->getSize() / 4);
+ // Replace the absolute table symbol with a synthetic symbol pointing to the
+ // SEHTable chunk so that we can emit base relocations for it and resolve
+ // section relative relocations.
+ Symbol *T = Symtab->find("___safe_se_handler_table");
+ Symbol *C = Symtab->find("___safe_se_handler_count");
+ replaceBody<DefinedSynthetic>(T, T->body()->getName(), SEHTable);
+ cast<DefinedAbsolute>(C->body())->setVA(SEHTable->getSize() / 4);
}
// Handles /section options to allow users to overwrite
@@ -774,6 +764,10 @@ void Writer::setSectionPermissions() {
// Write section contents to a mmap'ed file.
void Writer::writeSections() {
+ // Record the section index that should be used when resolving a section
+ // relocation against an absolute symbol.
+ DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1;
+
uint8_t *Buf = Buffer->getBufferStart();
for (OutputSection *Sec : OutputSections) {
uint8_t *SecBuf = Buf + Sec->getFileOff();
@@ -782,8 +776,8 @@ void Writer::writeSections() {
// ADD instructions).
if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE)
memset(SecBuf, 0xCC, Sec->getRawSize());
- parallel_for_each(Sec->getChunks().begin(), Sec->getChunks().end(),
- [&](Chunk *C) { C->writeTo(SecBuf); });
+ for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(),
+ [&](Chunk *C) { C->writeTo(SecBuf); });
}
}
@@ -797,16 +791,14 @@ void Writer::sortExceptionTable() {
uint8_t *End = Begin + Sec->getVirtualSize();
if (Config->Machine == AMD64) {
struct Entry { ulittle32_t Begin, End, Unwind; };
- parallel_sort(
- (Entry *)Begin, (Entry *)End,
- [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ sort(parallel::par, (Entry *)Begin, (Entry *)End,
+ [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
return;
}
if (Config->Machine == ARMNT) {
struct Entry { ulittle32_t Begin, Unwind; };
- parallel_sort(
- (Entry *)Begin, (Entry *)End,
- [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ sort(parallel::par, (Entry *)Begin, (Entry *)End,
+ [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
return;
}
errs() << "warning: don't know how to handle .pdata.\n";
@@ -819,19 +811,15 @@ void Writer::writeBuildId() {
if (BuildId == nullptr)
return;
- MD5 Hash;
- MD5::MD5Result Res;
-
- Hash.update(ArrayRef<uint8_t>{Buffer->getBufferStart(),
- Buffer->getBufferEnd()});
- Hash.final(Res);
-
assert(BuildId->DI->Signature.CVSignature == OMF::Signature::PDB70 &&
"only PDB 7.0 is supported");
- assert(sizeof(Res) == sizeof(BuildId->DI->PDB70.Signature) &&
+ assert(sizeof(BuildId->DI->PDB70.Signature) == 16 &&
"signature size mismatch");
- memcpy(BuildId->DI->PDB70.Signature, Res,
- sizeof(codeview::PDB70DebugInfo::Signature));
+
+ // Compute an MD5 hash.
+ ArrayRef<uint8_t> Buf(Buffer->getBufferStart(), Buffer->getBufferEnd());
+ memcpy(BuildId->DI->PDB70.Signature, MD5::hash(Buf).data(), 16);
+
// TODO(compnerd) track the Age
BuildId->DI->PDB70.Age = 1;
}
diff --git a/contrib/llvm/tools/lld/COFF/Writer.h b/contrib/llvm/tools/lld/COFF/Writer.h
index 0d26090..fef5754 100644
--- a/contrib/llvm/tools/lld/COFF/Writer.h
+++ b/contrib/llvm/tools/lld/COFF/Writer.h
@@ -10,14 +10,65 @@
#ifndef LLD_COFF_WRITER_H
#define LLD_COFF_WRITER_H
+#include "Chunks.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include <cstdint>
#include <vector>
namespace lld {
namespace coff {
class SymbolTable;
+static const int PageSize = 4096;
+
void writeResult(SymbolTable *T);
+// OutputSection represents a section in an output file. It's a
+// container of chunks. OutputSection and Chunk are 1:N relationship.
+// Chunks cannot belong to more than one OutputSections. The writer
+// creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and RVAs.
+class OutputSection {
+public:
+ OutputSection(llvm::StringRef N) : Name(N), Header({}) {}
+ void setRVA(uint64_t);
+ void setFileOffset(uint64_t);
+ void addChunk(Chunk *C);
+ llvm::StringRef getName() { return Name; }
+ std::vector<Chunk *> &getChunks() { return Chunks; }
+ void addPermissions(uint32_t C);
+ void setPermissions(uint32_t C);
+ uint32_t getPermissions() { return Header.Characteristics & PermMask; }
+ uint32_t getCharacteristics() { return Header.Characteristics; }
+ uint64_t getRVA() { return Header.VirtualAddress; }
+ uint64_t getFileOff() { return Header.PointerToRawData; }
+ void writeHeaderTo(uint8_t *Buf);
+
+ // Returns the size of this section in an executable memory image.
+ // This may be smaller than the raw size (the raw size is multiple
+ // of disk sector size, so there may be padding at end), or may be
+ // larger (if that's the case, the loader reserves spaces after end
+ // of raw data).
+ uint64_t getVirtualSize() { return Header.VirtualSize; }
+
+ // Returns the size of the section in the output file.
+ uint64_t getRawSize() { return Header.SizeOfRawData; }
+
+ // Set offset into the string table storing this section name.
+ // Used only when the name is longer than 8 bytes.
+ void setStringTableOff(uint32_t V) { StringTableOff = V; }
+
+ // N.B. The section index is one based.
+ uint32_t SectionIndex = 0;
+
+private:
+ llvm::StringRef Name;
+ llvm::object::coff_section Header;
+ uint32_t StringTableOff = 0;
+ std::vector<Chunk *> Chunks;
+};
+
}
}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp b/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp
new file mode 100644
index 0000000..b26cf08
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp
@@ -0,0 +1,376 @@
+//===- AArch64.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+// Page(Expr) is the page address of the expression Expr, defined
+// as (Expr & ~0xFFF). (This applies even if the machine page size
+// supported by the platform has a different value.)
+uint64_t elf::getAArch64Page(uint64_t Expr) {
+ return Expr & ~static_cast<uint64_t>(0xFFF);
+}
+
+namespace {
+class AArch64 final : public TargetInfo {
+public:
+ AArch64();
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ bool isPicRel(uint32_t Type) const override;
+ void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ bool usesOnlyLowPageBits(uint32_t Type) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+AArch64::AArch64() {
+ CopyRel = R_AARCH64_COPY;
+ RelativeRel = R_AARCH64_RELATIVE;
+ IRelativeRel = R_AARCH64_IRELATIVE;
+ GotRel = R_AARCH64_GLOB_DAT;
+ PltRel = R_AARCH64_JUMP_SLOT;
+ TlsDescRel = R_AARCH64_TLSDESC;
+ TlsGotRel = R_AARCH64_TLS_TPREL64;
+ GotEntrySize = 8;
+ GotPltEntrySize = 8;
+ PltEntrySize = 16;
+ PltHeaderSize = 32;
+ DefaultMaxPageSize = 65536;
+
+ // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant
+ // 1 of the tls structures and the tcb size is 16.
+ TcbSize = 16;
+}
+
+RelExpr AArch64::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ return R_TLSDESC_PAGE;
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ return R_TLSDESC;
+ case R_AARCH64_TLSDESC_CALL:
+ return R_TLSDESC_CALL;
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ return R_TLS;
+ case R_AARCH64_CALL26:
+ case R_AARCH64_CONDBR19:
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_TSTBR14:
+ return R_PLT_PC;
+ case R_AARCH64_PREL16:
+ case R_AARCH64_PREL32:
+ case R_AARCH64_PREL64:
+ case R_AARCH64_ADR_PREL_LO21:
+ return R_PC;
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ return R_PAGE_PC;
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ return R_GOT;
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ return R_GOT_PAGE_PC;
+ case R_AARCH64_NONE:
+ return R_NONE;
+ }
+}
+
+RelExpr AArch64::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ if (Expr == R_RELAX_TLS_GD_TO_IE) {
+ if (Type == R_AARCH64_TLSDESC_ADR_PAGE21)
+ return R_RELAX_TLS_GD_TO_IE_PAGE_PC;
+ return R_RELAX_TLS_GD_TO_IE_ABS;
+ }
+ return Expr;
+}
+
+bool AArch64::usesOnlyLowPageBits(uint32_t Type) const {
+ switch (Type) {
+ default:
+ return false;
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ return true;
+ }
+}
+
+bool AArch64::isPicRel(uint32_t Type) const {
+ return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64;
+}
+
+void AArch64::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+ write64le(Buf, InX::Plt->getVA());
+}
+
+void AArch64::writePltHeader(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]!
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2]))
+ 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))]
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2]))
+ 0x20, 0x02, 0x1f, 0xd6, // br x17
+ 0x1f, 0x20, 0x03, 0xd5, // nop
+ 0x1f, 0x20, 0x03, 0xd5, // nop
+ 0x1f, 0x20, 0x03, 0xd5 // nop
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+
+ uint64_t Got = InX::GotPlt->getVA();
+ uint64_t Plt = InX::Plt->getVA();
+ relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
+ getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
+ relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
+ relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
+}
+
+void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Inst[] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
+ 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))]
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n]))
+ 0x20, 0x02, 0x1f, 0xd6 // br x17
+ };
+ memcpy(Buf, Inst, sizeof(Inst));
+
+ relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
+ getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr));
+ relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr);
+ relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr);
+}
+
+static void write32AArch64Addr(uint8_t *L, uint64_t Imm) {
+ uint32_t ImmLo = (Imm & 0x3) << 29;
+ uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
+ uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
+ write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
+}
+
+// Return the bits [Start, End] from Val shifted Start bits.
+// For instance, getBits(0xF0, 4, 8) returns 0xF.
+static uint64_t getBits(uint64_t Val, int Start, int End) {
+ uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1;
+ return (Val >> Start) & Mask;
+}
+
+static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
+
+// Update the immediate field in a AARCH64 ldr, str, and add instruction.
+static void or32AArch64Imm(uint8_t *L, uint64_t Imm) {
+ or32le(L, (Imm & 0xFFF) << 10);
+}
+
+void AArch64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ switch (Type) {
+ case R_AARCH64_ABS16:
+ case R_AARCH64_PREL16:
+ checkIntUInt<16>(Loc, Val, Type);
+ write16le(Loc, Val);
+ break;
+ case R_AARCH64_ABS32:
+ case R_AARCH64_PREL32:
+ checkIntUInt<32>(Loc, Val, Type);
+ write32le(Loc, Val);
+ break;
+ case R_AARCH64_ABS64:
+ case R_AARCH64_GLOB_DAT:
+ case R_AARCH64_PREL64:
+ write64le(Loc, Val);
+ break;
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ or32AArch64Imm(Loc, Val);
+ break;
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ checkInt<33>(Loc, Val, Type);
+ write32AArch64Addr(Loc, Val >> 12);
+ break;
+ case R_AARCH64_ADR_PREL_LO21:
+ checkInt<21>(Loc, Val, Type);
+ write32AArch64Addr(Loc, Val);
+ break;
+ case R_AARCH64_CALL26:
+ case R_AARCH64_JUMP26:
+ checkInt<28>(Loc, Val, Type);
+ or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
+ break;
+ case R_AARCH64_CONDBR19:
+ checkInt<21>(Loc, Val, Type);
+ or32le(Loc, (Val & 0x1FFFFC) << 3);
+ break;
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ checkAlignment<8>(Loc, Val, Type);
+ or32le(Loc, (Val & 0xFF8) << 7);
+ break;
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ or32AArch64Imm(Loc, getBits(Val, 0, 11));
+ break;
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ or32AArch64Imm(Loc, getBits(Val, 1, 11));
+ break;
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ or32AArch64Imm(Loc, getBits(Val, 2, 11));
+ break;
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ or32AArch64Imm(Loc, getBits(Val, 3, 11));
+ break;
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ or32AArch64Imm(Loc, getBits(Val, 4, 11));
+ break;
+ case R_AARCH64_MOVW_UABS_G0_NC:
+ or32le(Loc, (Val & 0xFFFF) << 5);
+ break;
+ case R_AARCH64_MOVW_UABS_G1_NC:
+ or32le(Loc, (Val & 0xFFFF0000) >> 11);
+ break;
+ case R_AARCH64_MOVW_UABS_G2_NC:
+ or32le(Loc, (Val & 0xFFFF00000000) >> 27);
+ break;
+ case R_AARCH64_MOVW_UABS_G3:
+ or32le(Loc, (Val & 0xFFFF000000000000) >> 43);
+ break;
+ case R_AARCH64_TSTBR14:
+ checkInt<16>(Loc, Val, Type);
+ or32le(Loc, (Val & 0xFFFC) << 3);
+ break;
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ checkInt<24>(Loc, Val, Type);
+ or32AArch64Imm(Loc, Val >> 12);
+ break;
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ or32AArch64Imm(Loc, Val);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+void AArch64::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ // TLSDESC Global-Dynamic relocation are in the form:
+ // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
+ // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12]
+ // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12]
+ // .tlsdesccall [R_AARCH64_TLSDESC_CALL]
+ // blr x1
+ // And it can optimized to:
+ // movz x0, #0x0, lsl #16
+ // movk x0, #0x10
+ // nop
+ // nop
+ checkUInt<32>(Loc, Val, Type);
+
+ switch (Type) {
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ case R_AARCH64_TLSDESC_CALL:
+ write32le(Loc, 0xd503201f); // nop
+ return;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz
+ return;
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk
+ return;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+void AArch64::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ // TLSDESC Global-Dynamic relocation are in the form:
+ // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
+ // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12]
+ // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12]
+ // .tlsdesccall [R_AARCH64_TLSDESC_CALL]
+ // blr x1
+ // And it can optimized to:
+ // adrp x0, :gottprel:v
+ // ldr x0, [x0, :gottprel_lo12:v]
+ // nop
+ // nop
+
+ switch (Type) {
+ case R_AARCH64_TLSDESC_ADD_LO12:
+ case R_AARCH64_TLSDESC_CALL:
+ write32le(Loc, 0xd503201f); // nop
+ break;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ write32le(Loc, 0x90000000); // adrp
+ relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val);
+ break;
+ case R_AARCH64_TLSDESC_LD64_LO12:
+ write32le(Loc, 0xf9400000); // ldr
+ relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val);
+ break;
+ default:
+ llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
+ }
+}
+
+void AArch64::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ checkUInt<32>(Loc, Val, Type);
+
+ if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
+ // Generate MOVZ.
+ uint32_t RegNo = read32le(Loc) & 0x1f;
+ write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5));
+ return;
+ }
+ if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) {
+ // Generate MOVK.
+ uint32_t RegNo = read32le(Loc) & 0x1f;
+ write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5));
+ return;
+ }
+ llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
+}
+
+TargetInfo *elf::getAArch64TargetInfo() {
+ static AArch64 Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp b/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp
new file mode 100644
index 0000000..de566c6
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp
@@ -0,0 +1,84 @@
+//===- AMDGPU.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class AMDGPU final : public TargetInfo {
+public:
+ AMDGPU();
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+};
+} // namespace
+
+AMDGPU::AMDGPU() {
+ RelativeRel = R_AMDGPU_REL64;
+ GotRel = R_AMDGPU_ABS64;
+ GotEntrySize = 8;
+}
+
+void AMDGPU::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ switch (Type) {
+ case R_AMDGPU_ABS32:
+ case R_AMDGPU_GOTPCREL:
+ case R_AMDGPU_GOTPCREL32_LO:
+ case R_AMDGPU_REL32:
+ case R_AMDGPU_REL32_LO:
+ write32le(Loc, Val);
+ break;
+ case R_AMDGPU_ABS64:
+ write64le(Loc, Val);
+ break;
+ case R_AMDGPU_GOTPCREL32_HI:
+ case R_AMDGPU_REL32_HI:
+ write32le(Loc, Val >> 32);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+RelExpr AMDGPU::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_AMDGPU_ABS32:
+ case R_AMDGPU_ABS64:
+ return R_ABS;
+ case R_AMDGPU_REL32:
+ case R_AMDGPU_REL32_LO:
+ case R_AMDGPU_REL32_HI:
+ return R_PC;
+ case R_AMDGPU_GOTPCREL:
+ case R_AMDGPU_GOTPCREL32_LO:
+ case R_AMDGPU_GOTPCREL32_HI:
+ return R_GOT_PC;
+ default:
+ error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+ return R_HINT;
+ }
+}
+
+TargetInfo *elf::getAMDGPUTargetInfo() {
+ static AMDGPU Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp b/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp
new file mode 100644
index 0000000..106021d
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp
@@ -0,0 +1,480 @@
+//===- ARM.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class ARM final : public TargetInfo {
+public:
+ ARM();
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ bool isPicRel(uint32_t Type) const override;
+ uint32_t getDynRel(uint32_t Type) const override;
+ int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override;
+ void addPltHeaderSymbols(InputSectionBase *ISD) const override;
+ bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
+ const SymbolBody &S) const override;
+ bool inBranchRange(uint32_t RelocType, uint64_t Src,
+ uint64_t Dst) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+ARM::ARM() {
+ CopyRel = R_ARM_COPY;
+ RelativeRel = R_ARM_RELATIVE;
+ IRelativeRel = R_ARM_IRELATIVE;
+ GotRel = R_ARM_GLOB_DAT;
+ PltRel = R_ARM_JUMP_SLOT;
+ TlsGotRel = R_ARM_TLS_TPOFF32;
+ TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
+ TlsOffsetRel = R_ARM_TLS_DTPOFF32;
+ GotEntrySize = 4;
+ GotPltEntrySize = 4;
+ PltEntrySize = 16;
+ PltHeaderSize = 20;
+ TrapInstr = 0xd4d4d4d4;
+ // ARM uses Variant 1 TLS
+ TcbSize = 8;
+ NeedsThunks = true;
+}
+
+RelExpr ARM::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_ARM_THM_JUMP11:
+ return R_PC;
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_PREL31:
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_CALL:
+ return R_PLT_PC;
+ case R_ARM_GOTOFF32:
+ // (S + A) - GOT_ORG
+ return R_GOTREL;
+ case R_ARM_GOT_BREL:
+ // GOT(S) + A - GOT_ORG
+ return R_GOT_OFF;
+ case R_ARM_GOT_PREL:
+ case R_ARM_TLS_IE32:
+ // GOT(S) + A - P
+ return R_GOT_PC;
+ case R_ARM_SBREL32:
+ return R_ARM_SBREL;
+ case R_ARM_TARGET1:
+ return Config->Target1Rel ? R_PC : R_ABS;
+ case R_ARM_TARGET2:
+ if (Config->Target2 == Target2Policy::Rel)
+ return R_PC;
+ if (Config->Target2 == Target2Policy::Abs)
+ return R_ABS;
+ return R_GOT_PC;
+ case R_ARM_TLS_GD32:
+ return R_TLSGD_PC;
+ case R_ARM_TLS_LDM32:
+ return R_TLSLD_PC;
+ case R_ARM_BASE_PREL:
+ // B(S) + A - P
+ // FIXME: currently B(S) assumed to be .got, this may not hold for all
+ // platforms.
+ return R_GOTONLY_PC;
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL:
+ case R_ARM_REL32:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL:
+ return R_PC;
+ case R_ARM_NONE:
+ return R_NONE;
+ case R_ARM_TLS_LE32:
+ return R_TLS;
+ }
+}
+
+bool ARM::isPicRel(uint32_t Type) const {
+ return (Type == R_ARM_TARGET1 && !Config->Target1Rel) ||
+ (Type == R_ARM_ABS32);
+}
+
+uint32_t ARM::getDynRel(uint32_t Type) const {
+ if (Type == R_ARM_TARGET1 && !Config->Target1Rel)
+ return R_ARM_ABS32;
+ if (Type == R_ARM_ABS32)
+ return Type;
+ // Keep it going with a dummy value so that we can find more reloc errors.
+ return R_ARM_ABS32;
+}
+
+void ARM::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+ write32le(Buf, InX::Plt->getVA());
+}
+
+void ARM::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ // An ARM entry is the address of the ifunc resolver function.
+ write32le(Buf, S.getVA());
+}
+
+void ARM::writePltHeader(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]!
+ 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2
+ 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr
+ 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8]
+ 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t GotPlt = InX::GotPlt->getVA();
+ uint64_t L1 = InX::Plt->getVA() + 8;
+ write32le(Buf + 16, GotPlt - L1 - 8);
+}
+
+void ARM::addPltHeaderSymbols(InputSectionBase *ISD) const {
+ auto *IS = cast<InputSection>(ISD);
+ addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS);
+ addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS);
+}
+
+void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ // FIXME: Using simple code sequence with simple relocations.
+ // There is a more optimal sequence but it requires support for the group
+ // relocations. See ELF for the ARM Architecture Appendix A.3
+ const uint8_t PltData[] = {
+ 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2
+ 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+ 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t L1 = PltEntryAddr + 4;
+ write32le(Buf + 12, GotPltEntryAddr - L1 - 8);
+}
+
+void ARM::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const {
+ auto *IS = cast<InputSection>(ISD);
+ addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS);
+ addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS);
+}
+
+bool ARM::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
+ const SymbolBody &S) const {
+ // If S is an undefined weak symbol in an executable we don't need a Thunk.
+ // In a DSO calls to undefined symbols, including weak ones get PLT entries
+ // which may need a thunk.
+ if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() &&
+ !Config->Shared)
+ return false;
+ // A state change from ARM to Thumb and vice versa must go through an
+ // interworking thunk if the relocation type is not R_ARM_CALL or
+ // R_ARM_THM_CALL.
+ switch (RelocType) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_JUMP24:
+ // Source is ARM, all PLT entries are ARM so no interworking required.
+ // Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
+ if (Expr == R_PC && ((S.getVA() & 1) == 1))
+ return true;
+ break;
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ // Source is Thumb, all PLT entries are ARM so interworking is required.
+ // Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
+ if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0))
+ return true;
+ break;
+ }
+ return false;
+}
+
+bool ARM::inBranchRange(uint32_t RelocType, uint64_t Src, uint64_t Dst) const {
+ uint64_t Range;
+ uint64_t InstrSize;
+
+ switch (RelocType) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_JUMP24:
+ case R_ARM_CALL:
+ Range = 0x2000000;
+ InstrSize = 4;
+ break;
+ case R_ARM_THM_JUMP19:
+ Range = 0x100000;
+ InstrSize = 2;
+ break;
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_CALL:
+ Range = 0x1000000;
+ InstrSize = 2;
+ break;
+ default:
+ return true;
+ }
+ // PC at Src is 2 instructions ahead, immediate of branch is signed
+ if (Src > Dst)
+ Range -= 2 * InstrSize;
+ else
+ Range += InstrSize;
+
+ if ((Dst & 0x1) == 0)
+ // Destination is ARM, if ARM caller then Src is already 4-byte aligned.
+ // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure
+ // destination will be 4 byte aligned.
+ Src &= ~0x3;
+ else
+ // Bit 0 == 1 denotes Thumb state, it is not part of the range
+ Dst &= ~0x1;
+
+ uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src;
+ return Distance <= Range;
+}
+
+void ARM::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ switch (Type) {
+ case R_ARM_ABS32:
+ case R_ARM_BASE_PREL:
+ case R_ARM_GLOB_DAT:
+ case R_ARM_GOTOFF32:
+ case R_ARM_GOT_BREL:
+ case R_ARM_GOT_PREL:
+ case R_ARM_REL32:
+ case R_ARM_RELATIVE:
+ case R_ARM_SBREL32:
+ case R_ARM_TARGET1:
+ case R_ARM_TARGET2:
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LDM32:
+ case R_ARM_TLS_LDO32:
+ case R_ARM_TLS_LE32:
+ case R_ARM_TLS_TPOFF32:
+ case R_ARM_TLS_DTPOFF32:
+ write32le(Loc, Val);
+ break;
+ case R_ARM_TLS_DTPMOD32:
+ write32le(Loc, 1);
+ break;
+ case R_ARM_PREL31:
+ checkInt<31>(Loc, Val, Type);
+ write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
+ break;
+ case R_ARM_CALL:
+ // R_ARM_CALL is used for BL and BLX instructions, depending on the
+ // value of bit 0 of Val, we must select a BL or BLX instruction
+ if (Val & 1) {
+ // If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
+ // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
+ checkInt<26>(Loc, Val, Type);
+ write32le(Loc, 0xfa000000 | // opcode
+ ((Val & 2) << 23) | // H
+ ((Val >> 2) & 0x00ffffff)); // imm24
+ break;
+ }
+ if ((read32le(Loc) & 0xfe000000) == 0xfa000000)
+ // BLX (always unconditional) instruction to an ARM Target, select an
+ // unconditional BL.
+ write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff));
+ // fall through as BL encoding is shared with B
+ LLVM_FALLTHROUGH;
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ checkInt<26>(Loc, Val, Type);
+ write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
+ break;
+ case R_ARM_THM_JUMP11:
+ checkInt<12>(Loc, Val, Type);
+ write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
+ break;
+ case R_ARM_THM_JUMP19:
+ // Encoding T3: Val = S:J2:J1:imm6:imm11:0
+ checkInt<21>(Loc, Val, Type);
+ write16le(Loc,
+ (read16le(Loc) & 0xfbc0) | // opcode cond
+ ((Val >> 10) & 0x0400) | // S
+ ((Val >> 12) & 0x003f)); // imm6
+ write16le(Loc + 2,
+ 0x8000 | // opcode
+ ((Val >> 8) & 0x0800) | // J2
+ ((Val >> 5) & 0x2000) | // J1
+ ((Val >> 1) & 0x07ff)); // imm11
+ break;
+ case R_ARM_THM_CALL:
+ // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the
+ // value of bit 0 of Val, we must select a BL or BLX instruction
+ if ((Val & 1) == 0) {
+ // Ensure BLX destination is 4-byte aligned. As BLX instruction may
+ // only be two byte aligned. This must be done before overflow check
+ Val = alignTo(Val, 4);
+ }
+ // Bit 12 is 0 for BLX, 1 for BL
+ write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12);
+ // Fall through as rest of encoding is the same as B.W
+ LLVM_FALLTHROUGH;
+ case R_ARM_THM_JUMP24:
+ // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
+ // FIXME: Use of I1 and I2 require v6T2ops
+ checkInt<25>(Loc, Val, Type);
+ write16le(Loc,
+ 0xf000 | // opcode
+ ((Val >> 14) & 0x0400) | // S
+ ((Val >> 12) & 0x03ff)); // imm10
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0xd000) | // opcode
+ (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1
+ (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2
+ ((Val >> 1) & 0x07ff)); // imm11
+ break;
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVW_PREL_NC:
+ write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) |
+ (Val & 0x0fff));
+ break;
+ case R_ARM_MOVT_ABS:
+ case R_ARM_MOVT_PREL:
+ checkInt<32>(Loc, Val, Type);
+ write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
+ (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
+ break;
+ case R_ARM_THM_MOVT_ABS:
+ case R_ARM_THM_MOVT_PREL:
+ // Encoding T1: A = imm4:i:imm3:imm8
+ checkInt<32>(Loc, Val, Type);
+ write16le(Loc,
+ 0xf2c0 | // opcode
+ ((Val >> 17) & 0x0400) | // i
+ ((Val >> 28) & 0x000f)); // imm4
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0x8f00) | // opcode
+ ((Val >> 12) & 0x7000) | // imm3
+ ((Val >> 16) & 0x00ff)); // imm8
+ break;
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVW_PREL_NC:
+ // Encoding T3: A = imm4:i:imm3:imm8
+ write16le(Loc,
+ 0xf240 | // opcode
+ ((Val >> 1) & 0x0400) | // i
+ ((Val >> 12) & 0x000f)); // imm4
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0x8f00) | // opcode
+ ((Val << 4) & 0x7000) | // imm3
+ (Val & 0x00ff)); // imm8
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+int64_t ARM::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
+ switch (Type) {
+ default:
+ return 0;
+ case R_ARM_ABS32:
+ case R_ARM_BASE_PREL:
+ case R_ARM_GOTOFF32:
+ case R_ARM_GOT_BREL:
+ case R_ARM_GOT_PREL:
+ case R_ARM_REL32:
+ case R_ARM_TARGET1:
+ case R_ARM_TARGET2:
+ case R_ARM_TLS_GD32:
+ case R_ARM_TLS_LDM32:
+ case R_ARM_TLS_LDO32:
+ case R_ARM_TLS_IE32:
+ case R_ARM_TLS_LE32:
+ return SignExtend64<32>(read32le(Buf));
+ case R_ARM_PREL31:
+ return SignExtend64<31>(read32le(Buf));
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ return SignExtend64<26>(read32le(Buf) << 2);
+ case R_ARM_THM_JUMP11:
+ return SignExtend64<12>(read16le(Buf) << 1);
+ case R_ARM_THM_JUMP19: {
+ // Encoding T3: A = S:J2:J1:imm10:imm6:0
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<20>(((Hi & 0x0400) << 10) | // S
+ ((Lo & 0x0800) << 8) | // J2
+ ((Lo & 0x2000) << 5) | // J1
+ ((Hi & 0x003f) << 12) | // imm6
+ ((Lo & 0x07ff) << 1)); // imm11:0
+ }
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24: {
+ // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0
+ // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)
+ // FIXME: I1 and I2 require v6T2ops
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<24>(((Hi & 0x0400) << 14) | // S
+ (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1
+ (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2
+ ((Hi & 0x003ff) << 12) | // imm0
+ ((Lo & 0x007ff) << 1)); // imm11:0
+ }
+ // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and
+ // MOVT is in the range -32768 <= A < 32768
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL: {
+ uint64_t Val = read32le(Buf) & 0x000f0fff;
+ return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff));
+ }
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL: {
+ // Encoding T3: A = imm4:i:imm3:imm8
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4
+ ((Hi & 0x0400) << 1) | // i
+ ((Lo & 0x7000) >> 4) | // imm3
+ (Lo & 0x00ff)); // imm8
+ }
+ }
+}
+
+TargetInfo *elf::getARMTargetInfo() {
+ static ARM Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp b/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp
new file mode 100644
index 0000000..3853248
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp
@@ -0,0 +1,80 @@
+//===- AVR.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// AVR is a Harvard-architecture 8-bit micrcontroller designed for small
+// baremetal programs. All AVR-family processors have 32 8-bit registers.
+// The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest
+// one supports up to 2^24 data address space and 2^22 code address space.
+//
+// Since it is a baremetal programming, there's usually no loader to load
+// ELF files on AVRs. You are expected to link your program against address
+// 0 and pull out a .text section from the result using objcopy, so that you
+// can write the linked code to on-chip flush memory. You can do that with
+// the following commands:
+//
+// ld.lld -Ttext=0 -o foo foo.o
+// objcopy -O binary --only-section=.text foo output.bin
+//
+// Note that the current AVR support is very preliminary so you can't
+// link any useful program yet, though.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class AVR final : public TargetInfo {
+public:
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+RelExpr AVR::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_AVR_CALL:
+ return R_ABS;
+ default:
+ error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+ return R_HINT;
+ }
+}
+
+void AVR::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ switch (Type) {
+ case R_AVR_CALL: {
+ uint16_t Hi = Val >> 17;
+ uint16_t Lo = Val >> 1;
+ write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1));
+ write16le(Loc + 2, Lo);
+ break;
+ }
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+ }
+}
+
+TargetInfo *elf::getAVRTargetInfo() {
+ static AVR Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp b/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp
new file mode 100644
index 0000000..b8d796f
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp
@@ -0,0 +1,423 @@
+//===- MIPS.cpp -----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "OutputSections.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "Thunks.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+template <class ELFT> class MIPS final : public TargetInfo {
+public:
+ MIPS();
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ bool isPicRel(uint32_t Type) const override;
+ uint32_t getDynRel(uint32_t Type) const override;
+ void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
+ const SymbolBody &S) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ bool usesOnlyLowPageBits(uint32_t Type) const override;
+};
+} // namespace
+
+template <class ELFT> MIPS<ELFT>::MIPS() {
+ GotPltHeaderEntriesNum = 2;
+ DefaultMaxPageSize = 65536;
+ GotEntrySize = sizeof(typename ELFT::uint);
+ GotPltEntrySize = sizeof(typename ELFT::uint);
+ PltEntrySize = 16;
+ PltHeaderSize = 32;
+ CopyRel = R_MIPS_COPY;
+ PltRel = R_MIPS_JUMP_SLOT;
+ NeedsThunks = true;
+ TrapInstr = 0xefefefef;
+
+ if (ELFT::Is64Bits) {
+ RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
+ TlsGotRel = R_MIPS_TLS_TPREL64;
+ TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64;
+ TlsOffsetRel = R_MIPS_TLS_DTPREL64;
+ } else {
+ RelativeRel = R_MIPS_REL32;
+ TlsGotRel = R_MIPS_TLS_TPREL32;
+ TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32;
+ TlsOffsetRel = R_MIPS_TLS_DTPREL32;
+ }
+}
+
+template <class ELFT>
+RelExpr MIPS<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ // See comment in the calculateMipsRelChain.
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
+ Type &= 0xff;
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_MIPS_JALR:
+ return R_HINT;
+ case R_MIPS_GPREL16:
+ case R_MIPS_GPREL32:
+ return R_MIPS_GOTREL;
+ case R_MIPS_26:
+ return R_PLT;
+ case R_MIPS_HI16:
+ case R_MIPS_LO16:
+ // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
+ // offset between start of function and 'gp' value which by default
+ // equal to the start of .got section. In that case we consider these
+ // relocations as relative.
+ if (&S == ElfSym::MipsGpDisp)
+ return R_MIPS_GOT_GP_PC;
+ if (&S == ElfSym::MipsLocalGp)
+ return R_MIPS_GOT_GP;
+ LLVM_FALLTHROUGH;
+ case R_MIPS_GOT_OFST:
+ return R_ABS;
+ case R_MIPS_PC32:
+ case R_MIPS_PC16:
+ case R_MIPS_PC19_S2:
+ case R_MIPS_PC21_S2:
+ case R_MIPS_PC26_S2:
+ case R_MIPS_PCHI16:
+ case R_MIPS_PCLO16:
+ return R_PC;
+ case R_MIPS_GOT16:
+ if (S.isLocal())
+ return R_MIPS_GOT_LOCAL_PAGE;
+ LLVM_FALLTHROUGH;
+ case R_MIPS_CALL16:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_TLS_GOTTPREL:
+ return R_MIPS_GOT_OFF;
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_CALL_LO16:
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_GOT_LO16:
+ return R_MIPS_GOT_OFF32;
+ case R_MIPS_GOT_PAGE:
+ return R_MIPS_GOT_LOCAL_PAGE;
+ case R_MIPS_TLS_GD:
+ return R_MIPS_TLSGD;
+ case R_MIPS_TLS_LDM:
+ return R_MIPS_TLSLD;
+ }
+}
+
+template <class ELFT> bool MIPS<ELFT>::isPicRel(uint32_t Type) const {
+ return Type == R_MIPS_32 || Type == R_MIPS_64;
+}
+
+template <class ELFT> uint32_t MIPS<ELFT>::getDynRel(uint32_t Type) const {
+ return RelativeRel;
+}
+
+template <class ELFT>
+void MIPS<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
+ write32<ELFT::TargetEndianness>(Buf, InX::Plt->getVA());
+}
+
+template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
+static int64_t getPcRelocAddend(const uint8_t *Loc) {
+ uint32_t Instr = read32<E>(Loc);
+ uint32_t Mask = 0xffffffff >> (32 - BSIZE);
+ return SignExtend64<BSIZE + SHIFT>((Instr & Mask) << SHIFT);
+}
+
+template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
+static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) {
+ uint32_t Mask = 0xffffffff >> (32 - BSIZE);
+ uint32_t Instr = read32<E>(Loc);
+ if (SHIFT > 0)
+ checkAlignment<(1 << SHIFT)>(Loc, V, Type);
+ checkInt<BSIZE + SHIFT>(Loc, V, Type);
+ write32<E>(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask));
+}
+
+template <endianness E> static void writeMipsHi16(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ uint16_t Res = ((V + 0x8000) >> 16) & 0xffff;
+ write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E> static void writeMipsHigher(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff;
+ write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E> static void writeMipsHighest(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff;
+ write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E> static void writeMipsLo16(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
+}
+
+template <class ELFT> static bool isMipsR6() {
+ const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
+ uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH;
+ return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
+}
+
+template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
+ const endianness E = ELFT::TargetEndianness;
+ if (Config->MipsN32Abi) {
+ write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14)
+ write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
+ write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14
+ } else {
+ write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
+ write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
+ write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
+ write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28
+ }
+
+ write32<E>(Buf + 16, 0x03e07825); // move $15, $31
+ write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
+ write32<E>(Buf + 24, 0x0320f809); // jalr $25
+ write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
+
+ uint64_t GotPlt = InX::GotPlt->getVA();
+ writeMipsHi16<E>(Buf, GotPlt);
+ writeMipsLo16<E>(Buf + 4, GotPlt);
+ writeMipsLo16<E>(Buf + 8, GotPlt);
+}
+
+template <class ELFT>
+void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const endianness E = ELFT::TargetEndianness;
+ write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
+ write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
+ // jr $25
+ write32<E>(Buf + 8, isMipsR6<ELFT>() ? 0x03200009 : 0x03200008);
+ write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
+ writeMipsHi16<E>(Buf, GotPltEntryAddr);
+ writeMipsLo16<E>(Buf + 4, GotPltEntryAddr);
+ writeMipsLo16<E>(Buf + 12, GotPltEntryAddr);
+}
+
+template <class ELFT>
+bool MIPS<ELFT>::needsThunk(RelExpr Expr, uint32_t Type, const InputFile *File,
+ const SymbolBody &S) const {
+ // Any MIPS PIC code function is invoked with its address in register $t9.
+ // So if we have a branch instruction from non-PIC code to the PIC one
+ // we cannot make the jump directly and need to create a small stubs
+ // to save the target function address.
+ // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ if (Type != R_MIPS_26)
+ return false;
+ auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
+ if (!F)
+ return false;
+ // If current file has PIC code, LA25 stub is not required.
+ if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
+ return false;
+ auto *D = dyn_cast<DefinedRegular>(&S);
+ // LA25 is required if target file has PIC code
+ // or target symbol is a PIC symbol.
+ return D && D->isMipsPIC<ELFT>();
+}
+
+template <class ELFT>
+int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
+ const endianness E = ELFT::TargetEndianness;
+ switch (Type) {
+ default:
+ return 0;
+ case R_MIPS_32:
+ case R_MIPS_GPREL32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ return SignExtend64<32>(read32<E>(Buf));
+ case R_MIPS_26:
+ // FIXME (simon): If the relocation target symbol is not a PLT entry
+ // we should use another expression for calculation:
+ // ((A << 2) | (P & 0xf0000000)) >> 2
+ return SignExtend64<28>((read32<E>(Buf) & 0x3ffffff) << 2);
+ case R_MIPS_GPREL16:
+ case R_MIPS_LO16:
+ case R_MIPS_PCLO16:
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS_TLS_TPREL_LO16:
+ return SignExtend64<16>(read32<E>(Buf));
+ case R_MIPS_PC16:
+ return getPcRelocAddend<E, 16, 2>(Buf);
+ case R_MIPS_PC19_S2:
+ return getPcRelocAddend<E, 19, 2>(Buf);
+ case R_MIPS_PC21_S2:
+ return getPcRelocAddend<E, 21, 2>(Buf);
+ case R_MIPS_PC26_S2:
+ return getPcRelocAddend<E, 26, 2>(Buf);
+ case R_MIPS_PC32:
+ return getPcRelocAddend<E, 32, 0>(Buf);
+ }
+}
+
+static std::pair<uint32_t, uint64_t>
+calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) {
+ // MIPS N64 ABI packs multiple relocations into the single relocation
+ // record. In general, all up to three relocations can have arbitrary
+ // types. In fact, Clang and GCC uses only a few combinations. For now,
+ // we support two of them. That is allow to pass at least all LLVM
+ // test suite cases.
+ // <any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16
+ // <any relocation> / R_MIPS_64 / R_MIPS_NONE
+ // The first relocation is a 'real' relocation which is calculated
+ // using the corresponding symbol's value. The second and the third
+ // relocations used to modify result of the first one: extend it to
+ // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation
+ // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf
+ uint32_t Type2 = (Type >> 8) & 0xff;
+ uint32_t Type3 = (Type >> 16) & 0xff;
+ if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE)
+ return std::make_pair(Type, Val);
+ if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE)
+ return std::make_pair(Type2, Val);
+ if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
+ return std::make_pair(Type3, -Val);
+ error(getErrorLocation(Loc) + "unsupported relocations combination " +
+ Twine(Type));
+ return std::make_pair(Type & 0xff, Val);
+}
+
+template <class ELFT>
+void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ const endianness E = ELFT::TargetEndianness;
+ // Thread pointer and DRP offsets from the start of TLS data area.
+ // https://www.linux-mips.org/wiki/NPTL
+ if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 ||
+ Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64)
+ Val -= 0x8000;
+ else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 ||
+ Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64)
+ Val -= 0x7000;
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
+ std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
+ switch (Type) {
+ case R_MIPS_32:
+ case R_MIPS_GPREL32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ write32<E>(Loc, Val);
+ break;
+ case R_MIPS_64:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
+ write64<E>(Loc, Val);
+ break;
+ case R_MIPS_26:
+ write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff));
+ break;
+ case R_MIPS_GOT16:
+ // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode
+ // is updated addend (not a GOT index). In that case write high 16 bits
+ // to store a correct addend value.
+ if (Config->Relocatable)
+ writeMipsHi16<E>(Loc, Val);
+ else {
+ checkInt<16>(Loc, Val, Type);
+ writeMipsLo16<E>(Loc, Val);
+ }
+ break;
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_PAGE:
+ case R_MIPS_GPREL16:
+ case R_MIPS_TLS_GD:
+ case R_MIPS_TLS_LDM:
+ checkInt<16>(Loc, Val, Type);
+ LLVM_FALLTHROUGH;
+ case R_MIPS_CALL16:
+ case R_MIPS_CALL_LO16:
+ case R_MIPS_GOT_LO16:
+ case R_MIPS_GOT_OFST:
+ case R_MIPS_LO16:
+ case R_MIPS_PCLO16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_GOTTPREL:
+ case R_MIPS_TLS_TPREL_LO16:
+ writeMipsLo16<E>(Loc, Val);
+ break;
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_HI16:
+ case R_MIPS_PCHI16:
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_TPREL_HI16:
+ writeMipsHi16<E>(Loc, Val);
+ break;
+ case R_MIPS_HIGHER:
+ writeMipsHigher<E>(Loc, Val);
+ break;
+ case R_MIPS_HIGHEST:
+ writeMipsHighest<E>(Loc, Val);
+ break;
+ case R_MIPS_JALR:
+ // Ignore this optimization relocation for now
+ break;
+ case R_MIPS_PC16:
+ applyMipsPcReloc<E, 16, 2>(Loc, Type, Val);
+ break;
+ case R_MIPS_PC19_S2:
+ applyMipsPcReloc<E, 19, 2>(Loc, Type, Val);
+ break;
+ case R_MIPS_PC21_S2:
+ applyMipsPcReloc<E, 21, 2>(Loc, Type, Val);
+ break;
+ case R_MIPS_PC26_S2:
+ applyMipsPcReloc<E, 26, 2>(Loc, Type, Val);
+ break;
+ case R_MIPS_PC32:
+ applyMipsPcReloc<E, 32, 0>(Loc, Type, Val);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+template <class ELFT>
+bool MIPS<ELFT>::usesOnlyLowPageBits(uint32_t Type) const {
+ return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST;
+}
+
+template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
+ static MIPS<ELFT> Target;
+ return &Target;
+}
+
+template TargetInfo *elf::getMipsTargetInfo<ELF32LE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF32BE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF64LE>();
+template TargetInfo *elf::getMipsTargetInfo<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/Mips.cpp b/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp
index ac65672..3d1dc1d 100644
--- a/contrib/llvm/tools/lld/ELF/Mips.cpp
+++ b/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp
@@ -1,4 +1,4 @@
-//===- Mips.cpp ----------------------------------------------------------===//
+//===- MipsArchTree.cpp --------------------------------------------------===//
//
// The LLVM Linker
//
@@ -16,8 +16,8 @@
#include "SymbolTable.h"
#include "Writer.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/MipsABIFlags.h"
using namespace llvm;
@@ -37,7 +37,7 @@ struct FileFlags {
StringRef Filename;
uint32_t Flags;
};
-}
+} // namespace
static StringRef getAbiName(uint32_t Flags) {
switch (Flags) {
@@ -337,8 +337,8 @@ uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
return NewFlag;
if (compareMipsFpAbi(OldFlag, NewFlag) < 0)
error("target floating point ABI '" + getMipsFpAbiName(OldFlag) +
- "' is incompatible with '" + getMipsFpAbiName(NewFlag) + "': " +
- FileName);
+ "' is incompatible with '" + getMipsFpAbiName(NewFlag) +
+ "': " + FileName);
return OldFlag;
}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp b/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp
new file mode 100644
index 0000000..19e1072
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp
@@ -0,0 +1,65 @@
+//===- PPC.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class PPC final : public TargetInfo {
+public:
+ PPC() { GotBaseSymOff = 0x8000; }
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+};
+} // namespace
+
+void PPC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ switch (Type) {
+ case R_PPC_ADDR16_HA:
+ write16be(Loc, (Val + 0x8000) >> 16);
+ break;
+ case R_PPC_ADDR16_LO:
+ write16be(Loc, Val);
+ break;
+ case R_PPC_ADDR32:
+ case R_PPC_REL32:
+ write32be(Loc, Val);
+ break;
+ case R_PPC_REL24:
+ write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC));
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+RelExpr PPC::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_PPC_REL24:
+ case R_PPC_REL32:
+ return R_PC;
+ default:
+ return R_ABS;
+ }
+}
+
+TargetInfo *elf::getPPCTargetInfo() {
+ static PPC Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp
new file mode 100644
index 0000000..bf414d7
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp
@@ -0,0 +1,217 @@
+//===- PPC64.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+static uint64_t PPC64TocOffset = 0x8000;
+
+uint64_t elf::getPPC64TocBase() {
+ // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
+ // TOC starts where the first of these sections starts. We always create a
+ // .got when we see a relocation that uses it, so for us the start is always
+ // the .got.
+ uint64_t TocVA = InX::Got->getVA();
+
+ // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
+ // thus permitting a full 64 Kbytes segment. Note that the glibc startup
+ // code (crt1.o) assumes that you can get from the TOC base to the
+ // start of the .toc section with only a single (signed) 16-bit relocation.
+ return TocVA + PPC64TocOffset;
+}
+
+namespace {
+class PPC64 final : public TargetInfo {
+public:
+ PPC64();
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+// Relocation masks following the #lo(value), #hi(value), #ha(value),
+// #higher(value), #highera(value), #highest(value), and #highesta(value)
+// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
+// document.
+static uint16_t applyPPCLo(uint64_t V) { return V; }
+static uint16_t applyPPCHi(uint64_t V) { return V >> 16; }
+static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; }
+static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; }
+static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; }
+static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
+static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
+
+PPC64::PPC64() {
+ PltRel = GotRel = R_PPC64_GLOB_DAT;
+ RelativeRel = R_PPC64_RELATIVE;
+ GotEntrySize = 8;
+ GotPltEntrySize = 8;
+ PltEntrySize = 32;
+ PltHeaderSize = 0;
+
+ // We need 64K pages (at least under glibc/Linux, the loader won't
+ // set different permissions on a finer granularity than that).
+ DefaultMaxPageSize = 65536;
+
+ // The PPC64 ELF ABI v1 spec, says:
+ //
+ // It is normally desirable to put segments with different characteristics
+ // in separate 256 Mbyte portions of the address space, to give the
+ // operating system full paging flexibility in the 64-bit address space.
+ //
+ // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
+ // use 0x10000000 as the starting address.
+ DefaultImageBase = 0x10000000;
+}
+
+RelExpr PPC64::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ default:
+ return R_ABS;
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_LO_DS:
+ return R_GOTREL;
+ case R_PPC64_TOC:
+ return R_PPC_TOC;
+ case R_PPC64_REL24:
+ return R_PPC_PLT_OPD;
+ }
+}
+
+void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
+
+ // FIXME: What we should do, in theory, is get the offset of the function
+ // descriptor in the .opd section, and use that as the offset from %r2 (the
+ // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
+ // be a pointer to the function descriptor in the .opd section. Using
+ // this scheme is simpler, but requires an extra indirection per PLT dispatch.
+
+ write32be(Buf, 0xf8410028); // std %r2, 40(%r1)
+ write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
+ write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
+ write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
+ write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
+ write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
+ write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
+ write32be(Buf + 28, 0x4e800420); // bctr
+}
+
+static std::pair<uint32_t, uint64_t> toAddr16Rel(uint32_t Type, uint64_t Val) {
+ uint64_t V = Val - PPC64TocOffset;
+ switch (Type) {
+ case R_PPC64_TOC16:
+ return {R_PPC64_ADDR16, V};
+ case R_PPC64_TOC16_DS:
+ return {R_PPC64_ADDR16_DS, V};
+ case R_PPC64_TOC16_HA:
+ return {R_PPC64_ADDR16_HA, V};
+ case R_PPC64_TOC16_HI:
+ return {R_PPC64_ADDR16_HI, V};
+ case R_PPC64_TOC16_LO:
+ return {R_PPC64_ADDR16_LO, V};
+ case R_PPC64_TOC16_LO_DS:
+ return {R_PPC64_ADDR16_LO_DS, V};
+ default:
+ return {Type, Val};
+ }
+}
+
+void PPC64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ // For a TOC-relative relocation, proceed in terms of the corresponding
+ // ADDR16 relocation type.
+ std::tie(Type, Val) = toAddr16Rel(Type, Val);
+
+ switch (Type) {
+ case R_PPC64_ADDR14: {
+ checkAlignment<4>(Loc, Val, Type);
+ // Preserve the AA/LK bits in the branch instruction
+ uint8_t AALK = Loc[3];
+ write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
+ break;
+ }
+ case R_PPC64_ADDR16:
+ checkInt<16>(Loc, Val, Type);
+ write16be(Loc, Val);
+ break;
+ case R_PPC64_ADDR16_DS:
+ checkInt<16>(Loc, Val, Type);
+ write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
+ break;
+ case R_PPC64_ADDR16_HA:
+ case R_PPC64_REL16_HA:
+ write16be(Loc, applyPPCHa(Val));
+ break;
+ case R_PPC64_ADDR16_HI:
+ case R_PPC64_REL16_HI:
+ write16be(Loc, applyPPCHi(Val));
+ break;
+ case R_PPC64_ADDR16_HIGHER:
+ write16be(Loc, applyPPCHigher(Val));
+ break;
+ case R_PPC64_ADDR16_HIGHERA:
+ write16be(Loc, applyPPCHighera(Val));
+ break;
+ case R_PPC64_ADDR16_HIGHEST:
+ write16be(Loc, applyPPCHighest(Val));
+ break;
+ case R_PPC64_ADDR16_HIGHESTA:
+ write16be(Loc, applyPPCHighesta(Val));
+ break;
+ case R_PPC64_ADDR16_LO:
+ write16be(Loc, applyPPCLo(Val));
+ break;
+ case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_REL16_LO:
+ write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3));
+ break;
+ case R_PPC64_ADDR32:
+ case R_PPC64_REL32:
+ checkInt<32>(Loc, Val, Type);
+ write32be(Loc, Val);
+ break;
+ case R_PPC64_ADDR64:
+ case R_PPC64_REL64:
+ case R_PPC64_TOC:
+ write64be(Loc, Val);
+ break;
+ case R_PPC64_REL24: {
+ uint32_t Mask = 0x03FFFFFC;
+ checkInt<24>(Loc, Val, Type);
+ write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
+ break;
+ }
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+TargetInfo *elf::getPPC64TargetInfo() {
+ static PPC64 Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp b/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp
new file mode 100644
index 0000000..1f977c1
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp
@@ -0,0 +1,149 @@
+//===- SPARCV9.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class SPARCV9 final : public TargetInfo {
+public:
+ SPARCV9();
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+SPARCV9::SPARCV9() {
+ CopyRel = R_SPARC_COPY;
+ GotRel = R_SPARC_GLOB_DAT;
+ PltRel = R_SPARC_JMP_SLOT;
+ RelativeRel = R_SPARC_RELATIVE;
+ GotEntrySize = 8;
+ PltEntrySize = 32;
+ PltHeaderSize = 4 * PltEntrySize;
+
+ PageSize = 8192;
+ DefaultMaxPageSize = 0x100000;
+ DefaultImageBase = 0x100000;
+}
+
+RelExpr SPARCV9::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ return R_ABS;
+ case R_SPARC_PC10:
+ case R_SPARC_PC22:
+ case R_SPARC_DISP32:
+ case R_SPARC_WDISP30:
+ return R_PC;
+ case R_SPARC_GOT10:
+ return R_GOT_OFF;
+ case R_SPARC_GOT22:
+ return R_GOT_OFF;
+ case R_SPARC_WPLT30:
+ return R_PLT_PC;
+ case R_SPARC_NONE:
+ return R_NONE;
+ default:
+ error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+ return R_HINT;
+ }
+}
+
+void SPARCV9::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ switch (Type) {
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ // V-word32
+ checkUInt<32>(Loc, Val, Type);
+ write32be(Loc, Val);
+ break;
+ case R_SPARC_DISP32:
+ // V-disp32
+ checkInt<32>(Loc, Val, Type);
+ write32be(Loc, Val);
+ break;
+ case R_SPARC_WDISP30:
+ case R_SPARC_WPLT30:
+ // V-disp30
+ checkInt<32>(Loc, Val, Type);
+ write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff));
+ break;
+ case R_SPARC_22:
+ // V-imm22
+ checkUInt<22>(Loc, Val, Type);
+ write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff));
+ break;
+ case R_SPARC_GOT22:
+ case R_SPARC_PC22:
+ // T-imm22
+ write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff));
+ break;
+ case R_SPARC_WDISP19:
+ // V-disp19
+ checkInt<21>(Loc, Val, Type);
+ write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff));
+ break;
+ case R_SPARC_GOT10:
+ case R_SPARC_PC10:
+ // T-simm10
+ write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff));
+ break;
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ case R_SPARC_GLOB_DAT:
+ // V-xword64
+ write64be(Loc, Val);
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
+ }
+}
+
+void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t PltData[] = {
+ 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1
+ 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00, // nop
+ 0x01, 0x00, 0x00, 0x00 // nop
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+
+ uint64_t Off = PltHeaderSize + Index * PltEntrySize;
+ relocateOne(Buf, R_SPARC_22, Off);
+ relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize));
+}
+
+TargetInfo *elf::getSPARCV9TargetInfo() {
+ static SPARCV9 Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/X86.cpp b/contrib/llvm/tools/lld/ELF/Arch/X86.cpp
new file mode 100644
index 0000000..a1e9bca
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/X86.cpp
@@ -0,0 +1,364 @@
+//===- X86.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+class X86 final : public TargetInfo {
+public:
+ X86();
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ void writeGotPltHeader(uint8_t *Buf) const override;
+ uint32_t getDynRel(uint32_t Type) const override;
+ void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+
+ RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+};
+} // namespace
+
+X86::X86() {
+ GotBaseSymOff = -1;
+ CopyRel = R_386_COPY;
+ GotRel = R_386_GLOB_DAT;
+ PltRel = R_386_JUMP_SLOT;
+ IRelativeRel = R_386_IRELATIVE;
+ RelativeRel = R_386_RELATIVE;
+ TlsGotRel = R_386_TLS_TPOFF;
+ TlsModuleIndexRel = R_386_TLS_DTPMOD32;
+ TlsOffsetRel = R_386_TLS_DTPOFF32;
+ GotEntrySize = 4;
+ GotPltEntrySize = 4;
+ PltEntrySize = 16;
+ PltHeaderSize = 16;
+ TlsGdRelaxSkip = 2;
+ TrapInstr = 0xcccccccc; // 0xcc = INT3
+}
+
+RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_386_8:
+ case R_386_16:
+ case R_386_32:
+ case R_386_TLS_LDO_32:
+ return R_ABS;
+ case R_386_TLS_GD:
+ return R_TLSGD;
+ case R_386_TLS_LDM:
+ return R_TLSLD;
+ case R_386_PLT32:
+ return R_PLT_PC;
+ case R_386_PC8:
+ case R_386_PC16:
+ case R_386_PC32:
+ return R_PC;
+ case R_386_GOTPC:
+ return R_GOTONLY_PC_FROM_END;
+ case R_386_TLS_IE:
+ return R_GOT;
+ case R_386_GOT32:
+ case R_386_GOT32X:
+ // These relocations can be calculated in two different ways.
+ // Usual calculation is G + A - GOT what means an offset in GOT table
+ // (R_GOT_FROM_END). When instruction pointed by relocation has no base
+ // register, then relocations can be used when PIC code is disabled. In that
+ // case calculation is G + A, it resolves to an address of entry in GOT
+ // (R_GOT) and not an offset.
+ //
+ // To check that instruction has no base register we scan ModR/M byte.
+ // See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte"
+ // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
+ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
+ if ((Loc[-1] & 0xc7) != 0x5)
+ return R_GOT_FROM_END;
+ if (Config->Pic)
+ error(toString(S.File) + ": relocation " + toString(Type) + " against '" +
+ S.getName() +
+ "' without base register can not be used when PIC enabled");
+ return R_GOT;
+ case R_386_TLS_GOTIE:
+ return R_GOT_FROM_END;
+ case R_386_GOTOFF:
+ return R_GOTREL_FROM_END;
+ case R_386_TLS_LE:
+ return R_TLS;
+ case R_386_TLS_LE_32:
+ return R_NEG_TLS;
+ case R_386_NONE:
+ return R_NONE;
+ default:
+ error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+ return R_HINT;
+ }
+}
+
+RelExpr X86::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const {
+ switch (Expr) {
+ default:
+ return Expr;
+ case R_RELAX_TLS_GD_TO_IE:
+ return R_RELAX_TLS_GD_TO_IE_END;
+ case R_RELAX_TLS_GD_TO_LE:
+ return R_RELAX_TLS_GD_TO_LE_NEG;
+ }
+}
+
+void X86::writeGotPltHeader(uint8_t *Buf) const {
+ write32le(Buf, InX::Dynamic->getVA());
+}
+
+void X86::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ // Entries in .got.plt initially points back to the corresponding
+ // PLT entries with a fixed offset to skip the first instruction.
+ write32le(Buf, S.getPltVA() + 6);
+}
+
+void X86::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ // An x86 entry is the address of the ifunc resolver function.
+ write32le(Buf, S.getVA());
+}
+
+uint32_t X86::getDynRel(uint32_t Type) const {
+ if (Type == R_386_TLS_LE)
+ return R_386_TLS_TPOFF;
+ if (Type == R_386_TLS_LE_32)
+ return R_386_TLS_TPOFF32;
+ return Type;
+}
+
+void X86::writePltHeader(uint8_t *Buf) const {
+ if (Config->Pic) {
+ const uint8_t V[] = {
+ 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx)
+ 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx)
+ 0x90, 0x90, 0x90, 0x90 // nop
+ };
+ memcpy(Buf, V, sizeof(V));
+
+ uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ uint32_t GotPlt = InX::GotPlt->getVA() - Ebx;
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 8, GotPlt + 8);
+ return;
+ }
+
+ const uint8_t PltData[] = {
+ 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOTPLT+4)
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOTPLT+8)
+ 0x90, 0x90, 0x90, 0x90 // nop
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint32_t GotPlt = InX::GotPlt->getVA();
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 8, GotPlt + 8);
+}
+
+void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Inst[] = {
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx)
+ 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset
+ 0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0@PC
+ };
+ memcpy(Buf, Inst, sizeof(Inst));
+
+ if (Config->Pic) {
+ // jmp *foo@GOT(%ebx)
+ uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ Buf[1] = 0xa3;
+ write32le(Buf + 2, GotPltEntryAddr - Ebx);
+ } else {
+ // jmp *foo_in_GOT
+ Buf[1] = 0x25;
+ write32le(Buf + 2, GotPltEntryAddr);
+ }
+
+ write32le(Buf + 7, RelOff);
+ write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+}
+
+int64_t X86::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
+ switch (Type) {
+ default:
+ return 0;
+ case R_386_8:
+ case R_386_PC8:
+ return SignExtend64<8>(*Buf);
+ case R_386_16:
+ case R_386_PC16:
+ return SignExtend64<16>(read16le(Buf));
+ case R_386_32:
+ case R_386_GOT32:
+ case R_386_GOT32X:
+ case R_386_GOTOFF:
+ case R_386_GOTPC:
+ case R_386_PC32:
+ case R_386_PLT32:
+ case R_386_TLS_LDO_32:
+ case R_386_TLS_LE:
+ return SignExtend64<32>(read32le(Buf));
+ }
+}
+
+void X86::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
+ // being used for some 16-bit programs such as boot loaders, so
+ // we want to support them.
+ switch (Type) {
+ case R_386_8:
+ checkUInt<8>(Loc, Val, Type);
+ *Loc = Val;
+ break;
+ case R_386_PC8:
+ checkInt<8>(Loc, Val, Type);
+ *Loc = Val;
+ break;
+ case R_386_16:
+ checkUInt<16>(Loc, Val, Type);
+ write16le(Loc, Val);
+ break;
+ case R_386_PC16:
+ // R_386_PC16 is normally used with 16 bit code. In that situation
+ // the PC is 16 bits, just like the addend. This means that it can
+ // point from any 16 bit address to any other if the possibility
+ // of wrapping is included.
+ // The only restriction we have to check then is that the destination
+ // address fits in 16 bits. That is impossible to do here. The problem is
+ // that we are passed the final value, which already had the
+ // current location subtracted from it.
+ // We just check that Val fits in 17 bits. This misses some cases, but
+ // should have no false positives.
+ checkInt<17>(Loc, Val, Type);
+ write16le(Loc, Val);
+ break;
+ default:
+ checkInt<32>(Loc, Val, Type);
+ write32le(Loc, Val);
+ }
+}
+
+void X86::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ // Convert
+ // leal x@tlsgd(, %ebx, 1),
+ // call __tls_get_addr@plt
+ // to
+ // movl %gs:0,%eax
+ // subl $x@ntpoff,%eax
+ const uint8_t Inst[] = {
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
+ 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax
+ };
+ memcpy(Loc - 3, Inst, sizeof(Inst));
+ write32le(Loc + 5, Val);
+}
+
+void X86::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ // Convert
+ // leal x@tlsgd(, %ebx, 1),
+ // call __tls_get_addr@plt
+ // to
+ // movl %gs:0, %eax
+ // addl x@gotntpoff(%ebx), %eax
+ const uint8_t Inst[] = {
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
+ 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax
+ };
+ memcpy(Loc - 3, Inst, sizeof(Inst));
+ write32le(Loc + 5, Val);
+}
+
+// In some conditions, relocations can be optimized to avoid using GOT.
+// This function does that for Initial Exec to Local Exec case.
+void X86::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ // Ulrich's document section 6.2 says that @gotntpoff can
+ // be used with MOVL or ADDL instructions.
+ // @indntpoff is similar to @gotntpoff, but for use in
+ // position dependent code.
+ uint8_t Reg = (Loc[-1] >> 3) & 7;
+
+ if (Type == R_386_TLS_IE) {
+ if (Loc[-1] == 0xa1) {
+ // "movl foo@indntpoff,%eax" -> "movl $foo,%eax"
+ // This case is different from the generic case below because
+ // this is a 5 byte instruction while below is 6 bytes.
+ Loc[-1] = 0xb8;
+ } else if (Loc[-2] == 0x8b) {
+ // "movl foo@indntpoff,%reg" -> "movl $foo,%reg"
+ Loc[-2] = 0xc7;
+ Loc[-1] = 0xc0 | Reg;
+ } else {
+ // "addl foo@indntpoff,%reg" -> "addl $foo,%reg"
+ Loc[-2] = 0x81;
+ Loc[-1] = 0xc0 | Reg;
+ }
+ } else {
+ assert(Type == R_386_TLS_GOTIE);
+ if (Loc[-2] == 0x8b) {
+ // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg"
+ Loc[-2] = 0xc7;
+ Loc[-1] = 0xc0 | Reg;
+ } else {
+ // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg"
+ Loc[-2] = 0x8d;
+ Loc[-1] = 0x80 | (Reg << 3) | Reg;
+ }
+ }
+ write32le(Loc, Val);
+}
+
+void X86::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ if (Type == R_386_TLS_LDO_32) {
+ write32le(Loc, Val);
+ return;
+ }
+
+ // Convert
+ // leal foo(%reg),%eax
+ // call ___tls_get_addr
+ // to
+ // movl %gs:0,%eax
+ // nop
+ // leal 0(%esi,1),%esi
+ const uint8_t Inst[] = {
+ 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
+ 0x90, // nop
+ 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi
+ };
+ memcpy(Loc - 2, Inst, sizeof(Inst));
+}
+
+TargetInfo *elf::getX86TargetInfo() {
+ static X86 Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp b/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp
new file mode 100644
index 0000000..10179f5
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp
@@ -0,0 +1,473 @@
+//===- X86_64.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+template <class ELFT> class X86_64 final : public TargetInfo {
+public:
+ X86_64();
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ bool isPicRel(uint32_t Type) const override;
+ void writeGotPltHeader(uint8_t *Buf) const override;
+ void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+
+ RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr Expr) const override;
+ void relaxGot(uint8_t *Loc, uint64_t Val) const override;
+ void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+ void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+
+private:
+ void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
+ uint8_t ModRm) const;
+};
+} // namespace
+
+template <class ELFT> X86_64<ELFT>::X86_64() {
+ GotBaseSymOff = -1;
+ CopyRel = R_X86_64_COPY;
+ GotRel = R_X86_64_GLOB_DAT;
+ PltRel = R_X86_64_JUMP_SLOT;
+ RelativeRel = R_X86_64_RELATIVE;
+ IRelativeRel = R_X86_64_IRELATIVE;
+ TlsGotRel = R_X86_64_TPOFF64;
+ TlsModuleIndexRel = R_X86_64_DTPMOD64;
+ TlsOffsetRel = R_X86_64_DTPOFF64;
+ GotEntrySize = 8;
+ GotPltEntrySize = 8;
+ PltEntrySize = 16;
+ PltHeaderSize = 16;
+ TlsGdRelaxSkip = 2;
+ TrapInstr = 0xcccccccc; // 0xcc = INT3
+
+ // Align to the large page size (known as a superpage or huge page).
+ // FreeBSD automatically promotes large, superpage-aligned allocations.
+ DefaultImageBase = 0x200000;
+}
+
+template <class ELFT>
+RelExpr X86_64<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_X86_64_8:
+ case R_X86_64_16:
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ case R_X86_64_64:
+ case R_X86_64_DTPOFF32:
+ case R_X86_64_DTPOFF64:
+ return R_ABS;
+ case R_X86_64_TPOFF32:
+ return R_TLS;
+ case R_X86_64_TLSLD:
+ return R_TLSLD_PC;
+ case R_X86_64_TLSGD:
+ return R_TLSGD_PC;
+ case R_X86_64_SIZE32:
+ case R_X86_64_SIZE64:
+ return R_SIZE;
+ case R_X86_64_PLT32:
+ return R_PLT_PC;
+ case R_X86_64_PC32:
+ case R_X86_64_PC64:
+ return R_PC;
+ case R_X86_64_GOT32:
+ case R_X86_64_GOT64:
+ return R_GOT_FROM_END;
+ case R_X86_64_GOTPCREL:
+ case R_X86_64_GOTPCRELX:
+ case R_X86_64_REX_GOTPCRELX:
+ case R_X86_64_GOTTPOFF:
+ return R_GOT_PC;
+ case R_X86_64_NONE:
+ return R_NONE;
+ default:
+ error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+ return R_HINT;
+ }
+}
+
+template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
+ // The first entry holds the value of _DYNAMIC. It is not clear why that is
+ // required, but it is documented in the psabi and the glibc dynamic linker
+ // seems to use it (note that this is relevant for linking ld.so, not any
+ // other program).
+ write64le(Buf, InX::Dynamic->getVA());
+}
+
+template <class ELFT>
+void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
+ // See comments in X86TargetInfo::writeGotPlt.
+ write32le(Buf, S.getPltVA() + 6);
+}
+
+template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOTPLT+8(%rip)
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOTPLT+16(%rip)
+ 0x0f, 0x1f, 0x40, 0x00 // nop
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+ uint64_t GotPlt = InX::GotPlt->getVA();
+ uint64_t Plt = InX::Plt->getVA();
+ write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8
+ write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16
+}
+
+template <class ELFT>
+void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Inst[] = {
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
+ 0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index>
+ 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0]
+ };
+ memcpy(Buf, Inst, sizeof(Inst));
+
+ write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6);
+ write32le(Buf + 7, Index);
+ write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
+}
+
+template <class ELFT> bool X86_64<ELFT>::isPicRel(uint32_t Type) const {
+ return Type != R_X86_64_PC32 && Type != R_X86_64_32 &&
+ Type != R_X86_64_TPOFF32;
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // Convert
+ // .byte 0x66
+ // leaq x@tlsgd(%rip), %rdi
+ // .word 0x6666
+ // rex64
+ // call __tls_get_addr@plt
+ // to
+ // mov %fs:0x0,%rax
+ // lea x@tpoff,%rax
+ const uint8_t Inst[] = {
+ 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
+ 0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax
+ };
+ memcpy(Loc - 4, Inst, sizeof(Inst));
+
+ // The original code used a pc relative relocation and so we have to
+ // compensate for the -4 in had in the addend.
+ write32le(Loc + 8, Val + 4);
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // Convert
+ // .byte 0x66
+ // leaq x@tlsgd(%rip), %rdi
+ // .word 0x6666
+ // rex64
+ // call __tls_get_addr@plt
+ // to
+ // mov %fs:0x0,%rax
+ // addq x@tpoff,%rax
+ const uint8_t Inst[] = {
+ 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
+ 0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax
+ };
+ memcpy(Loc - 4, Inst, sizeof(Inst));
+
+ // Both code sequences are PC relatives, but since we are moving the constant
+ // forward by 8 bytes we have to subtract the value by 8.
+ write32le(Loc + 8, Val - 8);
+}
+
+// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
+// R_X86_64_TPOFF32 so that it does not use GOT.
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ uint8_t *Inst = Loc - 3;
+ uint8_t Reg = Loc[-1] >> 3;
+ uint8_t *RegSlot = Loc - 1;
+
+ // Note that ADD with RSP or R12 is converted to ADD instead of LEA
+ // because LEA with these registers needs 4 bytes to encode and thus
+ // wouldn't fit the space.
+
+ if (memcmp(Inst, "\x48\x03\x25", 3) == 0) {
+ // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
+ memcpy(Inst, "\x48\x81\xc4", 3);
+ } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) {
+ // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12"
+ memcpy(Inst, "\x49\x81\xc4", 3);
+ } else if (memcmp(Inst, "\x4c\x03", 2) == 0) {
+ // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
+ memcpy(Inst, "\x4d\x8d", 2);
+ *RegSlot = 0x80 | (Reg << 3) | Reg;
+ } else if (memcmp(Inst, "\x48\x03", 2) == 0) {
+ // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
+ memcpy(Inst, "\x48\x8d", 2);
+ *RegSlot = 0x80 | (Reg << 3) | Reg;
+ } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) {
+ // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
+ memcpy(Inst, "\x49\xc7", 2);
+ *RegSlot = 0xc0 | Reg;
+ } else if (memcmp(Inst, "\x48\x8b", 2) == 0) {
+ // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg"
+ memcpy(Inst, "\x48\xc7", 2);
+ *RegSlot = 0xc0 | Reg;
+ } else {
+ error(getErrorLocation(Loc - 3) +
+ "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
+ }
+
+ // The original code used a PC relative relocation.
+ // Need to compensate for the -4 it had in the addend.
+ write32le(Loc, Val + 4);
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ // Convert
+ // leaq bar@tlsld(%rip), %rdi
+ // callq __tls_get_addr@PLT
+ // leaq bar@dtpoff(%rax), %rcx
+ // to
+ // .word 0x6666
+ // .byte 0x66
+ // mov %fs:0,%rax
+ // leaq bar@tpoff(%rax), %rcx
+ if (Type == R_X86_64_DTPOFF64) {
+ write64le(Loc, Val);
+ return;
+ }
+ if (Type == R_X86_64_DTPOFF32) {
+ write32le(Loc, Val);
+ return;
+ }
+
+ const uint8_t Inst[] = {
+ 0x66, 0x66, // .word 0x6666
+ 0x66, // .byte 0x66
+ 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax
+ };
+ memcpy(Loc - 3, Inst, sizeof(Inst));
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
+ uint64_t Val) const {
+ switch (Type) {
+ case R_X86_64_8:
+ checkUInt<8>(Loc, Val, Type);
+ *Loc = Val;
+ break;
+ case R_X86_64_16:
+ checkUInt<16>(Loc, Val, Type);
+ write16le(Loc, Val);
+ break;
+ case R_X86_64_32:
+ checkUInt<32>(Loc, Val, Type);
+ write32le(Loc, Val);
+ break;
+ case R_X86_64_32S:
+ case R_X86_64_TPOFF32:
+ case R_X86_64_GOT32:
+ case R_X86_64_GOTPCREL:
+ case R_X86_64_GOTPCRELX:
+ case R_X86_64_REX_GOTPCRELX:
+ case R_X86_64_PC32:
+ case R_X86_64_GOTTPOFF:
+ case R_X86_64_PLT32:
+ case R_X86_64_TLSGD:
+ case R_X86_64_TLSLD:
+ case R_X86_64_DTPOFF32:
+ case R_X86_64_SIZE32:
+ checkInt<32>(Loc, Val, Type);
+ write32le(Loc, Val);
+ break;
+ case R_X86_64_64:
+ case R_X86_64_DTPOFF64:
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_PC64:
+ case R_X86_64_SIZE64:
+ case R_X86_64_GOT64:
+ write64le(Loc, Val);
+ break;
+ default:
+ llvm_unreachable("unexpected relocation");
+ }
+}
+
+template <class ELFT>
+RelExpr X86_64<ELFT>::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
+ RelExpr RelExpr) const {
+ if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX)
+ return RelExpr;
+ const uint8_t Op = Data[-2];
+ const uint8_t ModRm = Data[-1];
+
+ // FIXME: When PIC is disabled and foo is defined locally in the
+ // lower 32 bit address space, memory operand in mov can be converted into
+ // immediate operand. Otherwise, mov must be changed to lea. We support only
+ // latter relaxation at this moment.
+ if (Op == 0x8b)
+ return R_RELAX_GOT_PC;
+
+ // Relax call and jmp.
+ if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25))
+ return R_RELAX_GOT_PC;
+
+ // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor.
+ // If PIC then no relaxation is available.
+ // We also don't relax test/binop instructions without REX byte,
+ // they are 32bit operations and not common to have.
+ assert(Type == R_X86_64_REX_GOTPCRELX);
+ return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC;
+}
+
+// A subset of relaxations can only be applied for no-PIC. This method
+// handles such relaxations. Instructions encoding information was taken from:
+// "Intel 64 and IA-32 Architectures Software Developer's Manual V2"
+// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
+// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
+template <class ELFT>
+void X86_64<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
+ uint8_t ModRm) const {
+ const uint8_t Rex = Loc[-3];
+ // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg".
+ if (Op == 0x85) {
+ // See "TEST-Logical Compare" (4-428 Vol. 2B),
+ // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension).
+
+ // ModR/M byte has form XX YYY ZZZ, where
+ // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1).
+ // XX has different meanings:
+ // 00: The operand's memory address is in reg1.
+ // 01: The operand's memory address is reg1 + a byte-sized displacement.
+ // 10: The operand's memory address is reg1 + a word-sized displacement.
+ // 11: The operand is reg1 itself.
+ // If an instruction requires only one operand, the unused reg2 field
+ // holds extra opcode bits rather than a register code
+ // 0xC0 == 11 000 000 binary.
+ // 0x38 == 00 111 000 binary.
+ // We transfer reg2 to reg1 here as operand.
+ // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3).
+ Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte.
+
+ // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32
+ // See "TEST-Logical Compare" (4-428 Vol. 2B).
+ Loc[-2] = 0xf7;
+
+ // Move R bit to the B bit in REX byte.
+ // REX byte is encoded as 0100WRXB, where
+ // 0100 is 4bit fixed pattern.
+ // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the
+ // default operand size is used (which is 32-bit for most but not all
+ // instructions).
+ // REX.R This 1-bit value is an extension to the MODRM.reg field.
+ // REX.X This 1-bit value is an extension to the SIB.index field.
+ // REX.B This 1-bit value is an extension to the MODRM.rm field or the
+ // SIB.base field.
+ // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A).
+ Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
+ write32le(Loc, Val);
+ return;
+ }
+
+ // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub
+ // or xor operations.
+
+ // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg".
+ // Logic is close to one for test instruction above, but we also
+ // write opcode extension here, see below for details.
+ Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte.
+
+ // Primary opcode is 0x81, opcode extension is one of:
+ // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB,
+ // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP.
+ // This value was wrote to MODRM.reg in a line above.
+ // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15),
+ // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for
+ // descriptions about each operation.
+ Loc[-2] = 0x81;
+ Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
+ write32le(Loc, Val);
+}
+
+template <class ELFT>
+void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
+ const uint8_t Op = Loc[-2];
+ const uint8_t ModRm = Loc[-1];
+
+ // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg".
+ if (Op == 0x8b) {
+ Loc[-2] = 0x8d;
+ write32le(Loc, Val);
+ return;
+ }
+
+ if (Op != 0xff) {
+ // We are relaxing a rip relative to an absolute, so compensate
+ // for the old -4 addend.
+ assert(!Config->Pic);
+ relaxGotNoPic(Loc, Val + 4, Op, ModRm);
+ return;
+ }
+
+ // Convert call/jmp instructions.
+ if (ModRm == 0x15) {
+ // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo".
+ // Instead we convert to "addr32 call foo" where addr32 is an instruction
+ // prefix. That makes result expression to be a single instruction.
+ Loc[-2] = 0x67; // addr32 prefix
+ Loc[-1] = 0xe8; // call
+ write32le(Loc, Val);
+ return;
+ }
+
+ // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop".
+ // jmp doesn't return, so it is fine to use nop here, it is just a stub.
+ assert(ModRm == 0x25);
+ Loc[-2] = 0xe9; // jmp
+ Loc[3] = 0x90; // nop
+ write32le(Loc - 1, Val + 1);
+}
+
+TargetInfo *elf::getX32TargetInfo() {
+ static X86_64<ELF32LE> Target;
+ return &Target;
+}
+
+TargetInfo *elf::getX86_64TargetInfo() {
+ static X86_64<ELF64LE> Target;
+ return &Target;
+}
diff --git a/contrib/llvm/tools/lld/ELF/CMakeLists.txt b/contrib/llvm/tools/lld/ELF/CMakeLists.txt
index 2e9d2b9..77243bd 100644
--- a/contrib/llvm/tools/lld/ELF/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/ELF/CMakeLists.txt
@@ -7,20 +7,33 @@ if(NOT LLD_BUILT_STANDALONE)
endif()
add_lld_library(lldELF
+ Arch/AArch64.cpp
+ Arch/AMDGPU.cpp
+ Arch/ARM.cpp
+ Arch/AVR.cpp
+ Arch/Mips.cpp
+ Arch/MipsArchTree.cpp
+ Arch/PPC.cpp
+ Arch/PPC64.cpp
+ Arch/SPARCV9.cpp
+ Arch/X86.cpp
+ Arch/X86_64.cpp
Driver.cpp
DriverUtils.cpp
EhFrame.cpp
Error.cpp
+ Filesystem.cpp
GdbIndex.cpp
ICF.cpp
InputFiles.cpp
InputSection.cpp
LTO.cpp
LinkerScript.cpp
+ MapFile.cpp
MarkLive.cpp
- Mips.cpp
OutputSections.cpp
Relocations.cpp
+ ScriptLexer.cpp
ScriptParser.cpp
Strings.cpp
SymbolTable.cpp
@@ -33,6 +46,7 @@ add_lld_library(lldELF
LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
Analysis
+ BinaryFormat
BitReader
BitWriter
Codegen
@@ -53,7 +67,7 @@ add_lld_library(lldELF
LINK_LIBS
lldConfig
lldCore
- ${PTHREAD_LIB}
+ ${LLVM_PTHREAD_LIB}
DEPENDS
ELFOptionsTableGen
diff --git a/contrib/llvm/tools/lld/ELF/Config.h b/contrib/llvm/tools/lld/ELF/Config.h
index b770620..23627dd 100644
--- a/contrib/llvm/tools/lld/ELF/Config.h
+++ b/contrib/llvm/tools/lld/ELF/Config.h
@@ -13,7 +13,10 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/Support/ELF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/CachePruning.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Endian.h"
#include <vector>
@@ -34,14 +37,14 @@ enum ELFKind {
// For --build-id.
enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
-// For --discard-{all,locals,none} and --retain-symbols-file.
-enum class DiscardPolicy { Default, All, Locals, RetainFile, None };
+// For --discard-{all,locals,none}.
+enum class DiscardPolicy { Default, All, Locals, None };
// For --strip-{all,debug}.
enum class StripPolicy { None, All, Debug };
// For --unresolved-symbols.
-enum class UnresolvedPolicy { NoUndef, ReportError, Warn, Ignore };
+enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll };
// For --sort-section and linkerscript sorting rules.
enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
@@ -58,11 +61,16 @@ struct SymbolVersion {
// This struct contains symbols version definition that
// can be found in version script if it is used for link.
struct VersionDefinition {
- VersionDefinition(llvm::StringRef Name, uint16_t Id) : Name(Name), Id(Id) {}
llvm::StringRef Name;
- uint16_t Id;
+ uint16_t Id = 0;
std::vector<SymbolVersion> Globals;
- size_t NameOff; // Offset in string table.
+ size_t NameOff = 0; // Offset in the string table
+};
+
+// Structure for mapping renamed symbols
+struct RenamedSymbol {
+ Symbol *Target;
+ uint8_t OriginalBinding;
};
// This struct contains the global configuration for the linker.
@@ -72,6 +80,7 @@ struct VersionDefinition {
struct Configuration {
InputFile *FirstElf = nullptr;
uint8_t OSABI = 0;
+ llvm::CachePruningPolicy ThinLTOCachePolicy;
llvm::StringMap<uint64_t> SectionStartMap;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
@@ -80,52 +89,57 @@ struct Configuration {
llvm::StringRef Init;
llvm::StringRef LTOAAPipeline;
llvm::StringRef LTONewPmPasses;
+ llvm::StringRef MapFile;
llvm::StringRef OutputFile;
+ llvm::StringRef OptRemarksFilename;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
- llvm::StringSet<> RetainSymbolsFile;
- std::string RPath;
+ llvm::StringRef ThinLTOCacheDir;
+ std::string Rpath;
std::vector<VersionDefinition> VersionDefinitions;
+ std::vector<llvm::StringRef> Argv;
std::vector<llvm::StringRef> AuxiliaryList;
+ std::vector<llvm::StringRef> FilterList;
std::vector<llvm::StringRef> SearchPaths;
std::vector<llvm::StringRef> SymbolOrderingFile;
std::vector<llvm::StringRef> Undefined;
std::vector<SymbolVersion> VersionScriptGlobals;
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
+ llvm::MapVector<Symbol *, RenamedSymbol> RenamedSymbols;
bool AllowMultipleDefinition;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
bool ColorDiagnostics = false;
+ bool CompressDebugSections;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;
bool EhFrameHdr;
+ bool EmitRelocs;
bool EnableNewDtags;
bool ExportDynamic;
bool FatalWarnings;
bool GcSections;
bool GdbIndex;
- bool GnuHash = false;
+ bool GnuHash;
bool ICF;
- bool Mips64EL = false;
bool MipsN32Abi = false;
bool NoGnuUnique;
bool NoUndefinedVersion;
bool Nostdlib;
bool OFormatBinary;
- bool OMagic;
- bool Pic;
+ bool Omagic;
+ bool OptRemarksWithHotness;
bool Pie;
bool PrintGcSections;
- bool Rela;
bool Relocatable;
bool SaveTemps;
bool SingleRoRx;
bool Shared;
bool Static = false;
- bool SysvHash = true;
+ bool SysvHash;
bool Target1Rel;
bool Threads;
bool Trace;
@@ -134,17 +148,21 @@ struct Configuration {
bool WarnMissingEntry;
bool ZCombreloc;
bool ZExecstack;
+ bool ZNocopyreloc;
bool ZNodelete;
+ bool ZNodlopen;
bool ZNow;
bool ZOrigin;
bool ZRelro;
+ bool ZRodynamic;
+ bool ZText;
bool ExitEarly;
bool ZWxneeded;
DiscardPolicy Discard;
SortSectionPolicy SortSection;
- StripPolicy Strip = StripPolicy::None;
+ StripPolicy Strip;
UnresolvedPolicy UnresolvedSymbols;
- Target2Policy Target2 = Target2Policy::GotRel;
+ Target2Policy Target2;
BuildIdKind BuildId = BuildIdKind::None;
ELFKind EKind = ELFNoneKind;
uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
@@ -157,6 +175,58 @@ struct Configuration {
unsigned LTOO;
unsigned Optimize;
unsigned ThinLTOJobs;
+
+ // The following config options do not directly correspond to any
+ // particualr command line options.
+
+ // True if we need to pass through relocations in input files to the
+ // output file. Usually false because we consume relocations.
+ bool CopyRelocs;
+
+ // True if the target is ELF64. False if ELF32.
+ bool Is64;
+
+ // True if the target is little-endian. False if big-endian.
+ bool IsLE;
+
+ // endianness::little if IsLE is true. endianness::big otherwise.
+ llvm::support::endianness Endianness;
+
+ // True if the target is the little-endian MIPS64.
+ //
+ // The reason why we have this variable only for the MIPS is because
+ // we use this often. Some ELF headers for MIPS64EL are in a
+ // mixed-endian (which is horrible and I'd say that's a serious spec
+ // bug), and we need to know whether we are reading MIPS ELF files or
+ // not in various places.
+ //
+ // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official
+ // name whatever that means. A fun hypothesis is that "EL" is short for
+ // little-endian written in the little-endian order, but I don't know
+ // if that's true.)
+ bool IsMips64EL;
+
+ // The ELF spec defines two types of relocation table entries, RELA and
+ // REL. RELA is a triplet of (offset, info, addend) while REL is a
+ // tuple of (offset, info). Addends for REL are implicit and read from
+ // the location where the relocations are applied. So, REL is more
+ // compact than RELA but requires a bit of more work to process.
+ //
+ // (From the linker writer's view, this distinction is not necessary.
+ // If the ELF had chosen whichever and sticked with it, it would have
+ // been easier to write code to process relocations, but it's too late
+ // to change the spec.)
+ //
+ // Each ABI defines its relocation type. IsRela is true if target
+ // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A
+ // few 32-bit ABIs are using RELA too.
+ bool IsRela;
+
+ // True if we are creating position-independent code.
+ bool Pic;
+
+ // 4 for ELF32, 8 for ELF64.
+ int Wordsize;
};
// The only instance of Configuration struct.
diff --git a/contrib/llvm/tools/lld/ELF/Driver.cpp b/contrib/llvm/tools/lld/ELF/Driver.cpp
index 4f4466a..be5bd8a 100644
--- a/contrib/llvm/tools/lld/ELF/Driver.cpp
+++ b/contrib/llvm/tools/lld/ELF/Driver.cpp
@@ -6,17 +6,37 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+//
+// The driver drives the entire linking process. It is responsible for
+// parsing command line options and doing whatever it is instructed to do.
+//
+// One notable thing in the LLD's driver when compared to other linkers is
+// that the LLD's driver is agnostic on the host operating system.
+// Other linkers usually have implicit default values (such as a dynamic
+// linker path or library paths) for each host OS.
+//
+// I don't think implicit default values are useful because they are
+// usually explicitly specified by the compiler driver. They can even
+// be harmful when you are doing cross-linking. Therefore, in LLD, we
+// simply trust the compiler driver to pass all required options and
+// don't try to make effort on our side.
+//
+//===----------------------------------------------------------------------===//
#include "Driver.h"
#include "Config.h"
#include "Error.h"
+#include "Filesystem.h"
#include "ICF.h"
#include "InputFiles.h"
#include "InputSection.h"
#include "LinkerScript.h"
#include "Memory.h"
+#include "OutputSections.h"
+#include "ScriptParser.h"
#include "Strings.h"
#include "SymbolTable.h"
+#include "SyntheticSections.h"
#include "Target.h"
#include "Threads.h"
#include "Writer.h"
@@ -24,8 +44,8 @@
#include "lld/Driver/Driver.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Object/Decompressor.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
@@ -48,16 +68,19 @@ BumpPtrAllocator elf::BAlloc;
StringSaver elf::Saver{BAlloc};
std::vector<SpecificAllocBase *> elf::SpecificAllocBase::Instances;
+static void setConfigs();
+
bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
ErrorCount = 0;
ErrorOS = &Error;
- Argv0 = Args[0];
+ InputSections.clear();
Tar = nullptr;
Config = make<Configuration>();
Driver = make<LinkerDriver>();
- ScriptConfig = make<ScriptConfiguration>();
+ Script = make<LinkerScript>();
+ Config->Argv = {Args.begin(), Args.end()};
Driver->main(Args, CanExitEarly);
freeArena();
@@ -76,12 +99,10 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
std::pair<ELFKind, uint16_t> Ret =
StringSwitch<std::pair<ELFKind, uint16_t>>(S)
.Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
- .Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM})
+ .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
- .Case("elf32btsmip", {ELF32BEKind, EM_MIPS})
- .Case("elf32ltsmip", {ELF32LEKind, EM_MIPS})
- .Case("elf32btsmipn32", {ELF32BEKind, EM_MIPS})
- .Case("elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
+ .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
+ .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
.Case("elf32ppc", {ELF32BEKind, EM_PPC})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
@@ -102,13 +123,13 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
// Returns slices of MB by parsing MB as an archive file.
// Each slice consists of a member file in the archive.
-std::vector<MemoryBufferRef>
-LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
+std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers(
+ MemoryBufferRef MB) {
std::unique_ptr<Archive> File =
check(Archive::create(MB),
MB.getBufferIdentifier() + ": failed to parse archive");
- std::vector<MemoryBufferRef> V;
+ std::vector<std::pair<MemoryBufferRef, uint64_t>> V;
Error Err = Error::success();
for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
Archive::Child C =
@@ -118,7 +139,7 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
check(C.getMemoryBufferRef(),
MB.getBufferIdentifier() +
": could not get the buffer for a child of the archive");
- V.push_back(MBRef);
+ V.push_back(std::make_pair(MBRef, C.getChildOffset()));
}
if (Err)
fatal(MB.getBufferIdentifier() + ": Archive::children failed: " +
@@ -131,9 +152,8 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
return V;
}
-// Opens and parses a file. Path has to be resolved already.
-// Newly created memory buffers are owned by this driver.
-void LinkerDriver::addFile(StringRef Path) {
+// Opens a file and create a file object. Path has to be resolved already.
+void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
using namespace sys::fs;
Optional<MemoryBufferRef> Buffer = readFile(Path);
@@ -150,24 +170,53 @@ void LinkerDriver::addFile(StringRef Path) {
case file_magic::unknown:
readLinkerScript(MBRef);
return;
- case file_magic::archive:
+ case file_magic::archive: {
+ // Handle -whole-archive.
if (InWholeArchive) {
- for (MemoryBufferRef MB : getArchiveMembers(MBRef))
- Files.push_back(createObjectFile(MB, Path));
+ for (const auto &P : getArchiveMembers(MBRef))
+ Files.push_back(createObjectFile(P.first, Path, P.second));
return;
}
- Files.push_back(make<ArchiveFile>(MBRef));
+
+ std::unique_ptr<Archive> File =
+ check(Archive::create(MBRef), Path + ": failed to parse archive");
+
+ // If an archive file has no symbol table, it is likely that a user
+ // is attempting LTO and using a default ar command that doesn't
+ // understand the LLVM bitcode file. It is a pretty common error, so
+ // we'll handle it as if it had a symbol table.
+ if (!File->isEmpty() && !File->hasSymbolTable()) {
+ for (const auto &P : getArchiveMembers(MBRef))
+ Files.push_back(make<LazyObjectFile>(P.first, Path, P.second));
+ return;
+ }
+
+ // Handle the regular case.
+ Files.push_back(make<ArchiveFile>(std::move(File)));
return;
+ }
case file_magic::elf_shared_object:
if (Config->Relocatable) {
error("attempted static link of dynamic object " + Path);
return;
}
- Files.push_back(createSharedFile(MBRef));
+
+ // DSOs usually have DT_SONAME tags in their ELF headers, and the
+ // sonames are used to identify DSOs. But if they are missing,
+ // they are identified by filenames. We don't know whether the new
+ // file has a DT_SONAME or not because we haven't parsed it yet.
+ // Here, we set the default soname for the file because we might
+ // need it later.
+ //
+ // If a file was specified by -lfoo, the directory part is not
+ // significant, as a user did not specify it. This behavior is
+ // compatible with GNU.
+ Files.push_back(
+ createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path));
return;
default:
if (InLib)
- Files.push_back(make<LazyObjectFile>(MBRef));
+ Files.push_back(make<LazyObjectFile>(MBRef, "", 0));
else
Files.push_back(createObjectFile(MBRef));
}
@@ -176,7 +225,7 @@ void LinkerDriver::addFile(StringRef Path) {
// Add a given library by searching it from input search paths.
void LinkerDriver::addLibrary(StringRef Name) {
if (Optional<std::string> Path = searchLibrary(Name))
- addFile(*Path);
+ addFile(*Path, /*WithLOption=*/true);
else
error("unable to find library -l" + Name);
}
@@ -210,6 +259,12 @@ static void checkOptions(opt::InputArgList &Args) {
if (Config->Pie && Config->Shared)
error("-shared and -pie may not be used together");
+ if (!Config->Shared && !Config->FilterList.empty())
+ error("-F may not be used without -shared");
+
+ if (!Config->Shared && !Config->AuxiliaryList.empty())
+ error("-f may not be used without -shared");
+
if (Config->Relocatable) {
if (Config->Shared)
error("-r and -shared may not be used together");
@@ -222,18 +277,11 @@ static void checkOptions(opt::InputArgList &Args) {
}
}
-static StringRef getString(opt::InputArgList &Args, unsigned Key,
- StringRef Default = "") {
- if (auto *Arg = Args.getLastArg(Key))
- return Arg->getValue();
- return Default;
-}
-
static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
int V = Default;
if (auto *Arg = Args.getLastArg(Key)) {
StringRef S = Arg->getValue();
- if (S.getAsInteger(10, V))
+ if (!to_integer(S, V, 10))
error(Arg->getSpelling() + ": number expected, but got " + S);
}
return V;
@@ -255,13 +303,11 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) {
static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key,
uint64_t Default) {
for (auto *Arg : Args.filtered(OPT_z)) {
- StringRef Value = Arg->getValue();
- size_t Pos = Value.find("=");
- if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) {
- Value = Value.substr(Pos + 1);
- uint64_t Result;
- if (Value.getAsInteger(0, Result))
- error("invalid " + Key + ": " + Value);
+ std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('=');
+ if (KV.first == Key) {
+ uint64_t Result = Default;
+ if (!to_integer(KV.second, Result))
+ error("invalid " + Key + ": " + KV.second);
return Result;
}
}
@@ -297,7 +343,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
// of Libtool. We cannot convince every software developer to migrate to
// the latest version and re-generate scripts. So we have this hack.
if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
- outs() << getLLDVersion() << " (compatible with GNU linkers)\n";
+ message(getLLDVersion() + " (compatible with GNU linkers)");
// ld.bfd always exits after printing out the version string.
// ld.gold proceeds if a given option is -v. Because gold's behavior
@@ -327,6 +373,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
initLLVM(Args);
createFiles(Args);
inferMachineType();
+ setConfigs();
checkOptions(Args);
if (ErrorCount)
return;
@@ -349,36 +396,76 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
}
}
-static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) {
+static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
+ bool Default) {
+ if (auto *Arg = Args.getLastArg(K1, K2))
+ return Arg->getOption().getID() == K1;
+ return Default;
+}
+
+static std::vector<StringRef> getArgs(opt::InputArgList &Args, int Id) {
+ std::vector<StringRef> V;
+ for (auto *Arg : Args.filtered(Id))
+ V.push_back(Arg->getValue());
+ return V;
+}
+
+static std::string getRpath(opt::InputArgList &Args) {
+ std::vector<StringRef> V = getArgs(Args, OPT_rpath);
+ return llvm::join(V.begin(), V.end(), ":");
+}
+
+// Determines what we should do if there are remaining unresolved
+// symbols after the name resolution.
+static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) {
+ // -noinhibit-exec or -r imply some default values.
if (Args.hasArg(OPT_noinhibit_exec))
- return UnresolvedPolicy::Warn;
- if (Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs"))
- return UnresolvedPolicy::NoUndef;
- if (Config->Relocatable)
- return UnresolvedPolicy::Ignore;
+ return UnresolvedPolicy::WarnAll;
+ if (Args.hasArg(OPT_relocatable))
+ return UnresolvedPolicy::IgnoreAll;
- if (auto *Arg = Args.getLastArg(OPT_unresolved_symbols)) {
- StringRef S = Arg->getValue();
- if (S == "ignore-all" || S == "ignore-in-object-files")
- return UnresolvedPolicy::Ignore;
- if (S == "ignore-in-shared-libs" || S == "report-all")
- return UnresolvedPolicy::ReportError;
- error("unknown --unresolved-symbols value: " + S);
+ UnresolvedPolicy ErrorOrWarn = getArg(Args, OPT_error_unresolved_symbols,
+ OPT_warn_unresolved_symbols, true)
+ ? UnresolvedPolicy::ReportError
+ : UnresolvedPolicy::Warn;
+
+ // Process the last of -unresolved-symbols, -no-undefined or -z defs.
+ for (auto *Arg : llvm::reverse(Args)) {
+ switch (Arg->getOption().getID()) {
+ case OPT_unresolved_symbols: {
+ StringRef S = Arg->getValue();
+ if (S == "ignore-all" || S == "ignore-in-object-files")
+ return UnresolvedPolicy::Ignore;
+ if (S == "ignore-in-shared-libs" || S == "report-all")
+ return ErrorOrWarn;
+ error("unknown --unresolved-symbols value: " + S);
+ continue;
+ }
+ case OPT_no_undefined:
+ return ErrorOrWarn;
+ case OPT_z:
+ if (StringRef(Arg->getValue()) == "defs")
+ return ErrorOrWarn;
+ continue;
+ }
}
- return UnresolvedPolicy::ReportError;
+
+ // -shared implies -unresolved-symbols=ignore-all because missing
+ // symbols are likely to be resolved at runtime using other DSOs.
+ if (Config->Shared)
+ return UnresolvedPolicy::Ignore;
+ return ErrorOrWarn;
}
-static Target2Policy getTarget2Option(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_target2)) {
- StringRef S = Arg->getValue();
- if (S == "rel")
- return Target2Policy::Rel;
- if (S == "abs")
- return Target2Policy::Abs;
- if (S == "got-rel")
- return Target2Policy::GotRel;
- error("unknown --target2 option: " + S);
- }
+static Target2Policy getTarget2(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_target2, "got-rel");
+ if (S == "rel")
+ return Target2Policy::Rel;
+ if (S == "abs")
+ return Target2Policy::Abs;
+ if (S == "got-rel")
+ return Target2Policy::GotRel;
+ error("unknown --target2 option: " + S);
return Target2Policy::GotRel;
}
@@ -392,16 +479,10 @@ static bool isOutputFormatBinary(opt::InputArgList &Args) {
return false;
}
-static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
- bool Default) {
- if (auto *Arg = Args.getLastArg(K1, K2))
- return Arg->getOption().getID() == K1;
- return Default;
-}
-
-static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
- if (Config->Relocatable)
+static DiscardPolicy getDiscard(opt::InputArgList &Args) {
+ if (Args.hasArg(OPT_relocatable))
return DiscardPolicy::None;
+
auto *Arg =
Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none);
if (!Arg)
@@ -413,20 +494,30 @@ static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
return DiscardPolicy::None;
}
-static StripPolicy getStripOption(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug)) {
- if (Arg->getOption().getID() == OPT_strip_all)
- return StripPolicy::All;
- return StripPolicy::Debug;
- }
- return StripPolicy::None;
+static StringRef getDynamicLinker(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
+ if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker)
+ return "";
+ return Arg->getValue();
+}
+
+static StripPolicy getStrip(opt::InputArgList &Args) {
+ if (Args.hasArg(OPT_relocatable))
+ return StripPolicy::None;
+
+ auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug);
+ if (!Arg)
+ return StripPolicy::None;
+ if (Arg->getOption().getID() == OPT_strip_all)
+ return StripPolicy::All;
+ return StripPolicy::Debug;
}
static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) {
uint64_t VA = 0;
if (S.startswith("0x"))
S = S.drop_front(2);
- if (S.getAsInteger(16, VA))
+ if (!to_integer(S, VA, 16))
error("invalid argument: " + toString(Arg));
return VA;
}
@@ -449,8 +540,8 @@ static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) {
return Ret;
}
-static SortSectionPolicy getSortKind(opt::InputArgList &Args) {
- StringRef S = getString(Args, OPT_sort_section);
+static SortSectionPolicy getSortSection(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_sort_section);
if (S == "alignment")
return SortSectionPolicy::Alignment;
if (S == "name")
@@ -460,6 +551,44 @@ static SortSectionPolicy getSortKind(opt::InputArgList &Args) {
return SortSectionPolicy::Default;
}
+static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_hash_style, "sysv");
+ if (S == "sysv")
+ return {true, false};
+ if (S == "gnu")
+ return {false, true};
+ if (S != "both")
+ error("unknown -hash-style: " + S);
+ return {true, true};
+}
+
+// Parse --build-id or --build-id=<style>. We handle "tree" as a
+// synonym for "sha1" because all our hash functions including
+// -build-id=sha1 are actually tree hashes for performance reasons.
+static std::pair<BuildIdKind, std::vector<uint8_t>>
+getBuildId(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq);
+ if (!Arg)
+ return {BuildIdKind::None, {}};
+
+ if (Arg->getOption().getID() == OPT_build_id)
+ return {BuildIdKind::Fast, {}};
+
+ StringRef S = Arg->getValue();
+ if (S == "md5")
+ return {BuildIdKind::Md5, {}};
+ if (S == "sha1" || S == "tree")
+ return {BuildIdKind::Sha1, {}};
+ if (S == "uuid")
+ return {BuildIdKind::Uuid, {}};
+ if (S.startswith("0x"))
+ return {BuildIdKind::Hexstring, parseHex(S.substr(2))};
+
+ if (S != "none")
+ error("unknown --build-id style: " + S);
+ return {BuildIdKind::None, {}};
+}
+
static std::vector<StringRef> getLines(MemoryBufferRef MB) {
SmallVector<StringRef, 0> Arr;
MB.getBuffer().split(Arr, '\n');
@@ -473,174 +602,166 @@ static std::vector<StringRef> getLines(MemoryBufferRef MB) {
return Ret;
}
+static bool getCompressDebugSections(opt::InputArgList &Args) {
+ StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none");
+ if (S == "none")
+ return false;
+ if (S != "zlib")
+ error("unknown --compress-debug-sections value: " + S);
+ if (!zlib::isAvailable())
+ error("--compress-debug-sections: zlib is not available");
+ return true;
+}
+
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
- for (auto *Arg : Args.filtered(OPT_L))
- Config->SearchPaths.push_back(Arg->getValue());
-
- std::vector<StringRef> RPaths;
- for (auto *Arg : Args.filtered(OPT_rpath))
- RPaths.push_back(Arg->getValue());
- if (!RPaths.empty())
- Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":");
-
- if (auto *Arg = Args.getLastArg(OPT_m)) {
- // Parse ELF{32,64}{LE,BE} and CPU type.
- StringRef S = Arg->getValue();
- std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
- parseEmulation(S);
- Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");
- Config->Emulation = S;
- }
-
- Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
+ Config->AllowMultipleDefinition =
+ Args.hasArg(OPT_allow_multiple_definition) || hasZOption(Args, "muldefs");
+ Config->AuxiliaryList = getArgs(Args, OPT_auxiliary);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ Config->CompressDebugSections = getCompressDebugSections(Args);
+ Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
+ !Args.hasArg(OPT_relocatable));
Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
+ Config->Discard = getDiscard(Args);
+ Config->DynamicLinker = getDynamicLinker(Args);
Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
+ Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
- Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);
- Config->FatalWarnings = Args.hasArg(OPT_fatal_warnings);
+ Config->Entry = Args.getLastArgValue(OPT_entry);
+ Config->ExportDynamic =
+ getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false);
+ Config->FatalWarnings =
+ getArg(Args, OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+ Config->FilterList = getArgs(Args, OPT_filter);
+ Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false);
Config->GdbIndex = Args.hasArg(OPT_gdb_index);
- Config->ICF = Args.hasArg(OPT_icf);
+ Config->ICF = getArg(Args, OPT_icf_all, OPT_icf_none, false);
+ Config->Init = Args.getLastArgValue(OPT_init, "_init");
+ Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline);
+ Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes);
+ Config->LTOO = getInteger(Args, OPT_lto_O, 2);
+ Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
+ Config->MapFile = Args.getLastArgValue(OPT_Map);
Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
Config->Nostdlib = Args.hasArg(OPT_nostdlib);
- Config->OMagic = Args.hasArg(OPT_omagic);
+ Config->OFormatBinary = isOutputFormatBinary(Args);
+ Config->Omagic = Args.hasArg(OPT_omagic);
+ Config->OptRemarksFilename = Args.getLastArgValue(OPT_opt_remarks_filename);
+ Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness);
+ Config->Optimize = getInteger(Args, OPT_O, 1);
+ Config->OutputFile = Args.getLastArgValue(OPT_o);
Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false);
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
+ Config->Rpath = getRpath(Args);
Config->Relocatable = Args.hasArg(OPT_relocatable);
- Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
- !Config->Relocatable);
- Config->Discard = getDiscardOption(Args);
Config->SaveTemps = Args.hasArg(OPT_save_temps);
- Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
+ Config->SearchPaths = getArgs(Args, OPT_L);
+ Config->SectionStartMap = getSectionStartMap(Args);
Config->Shared = Args.hasArg(OPT_shared);
+ Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
+ Config->SoName = Args.getLastArgValue(OPT_soname);
+ Config->SortSection = getSortSection(Args);
+ Config->Strip = getStrip(Args);
+ Config->Sysroot = Args.getLastArgValue(OPT_sysroot);
Config->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false);
+ Config->Target2 = getTarget2(Args);
+ Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
+ Config->ThinLTOCachePolicy = check(
+ parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
+ "--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true);
Config->Trace = Args.hasArg(OPT_trace);
+ Config->Undefined = getArgs(Args, OPT_undefined);
+ Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
Config->Verbose = Args.hasArg(OPT_verbose);
Config->WarnCommon = Args.hasArg(OPT_warn_common);
-
- Config->DynamicLinker = getString(Args, OPT_dynamic_linker);
- Config->Entry = getString(Args, OPT_entry);
- Config->Fini = getString(Args, OPT_fini, "_fini");
- Config->Init = getString(Args, OPT_init, "_init");
- Config->LTOAAPipeline = getString(Args, OPT_lto_aa_pipeline);
- Config->LTONewPmPasses = getString(Args, OPT_lto_newpm_passes);
- Config->OutputFile = getString(Args, OPT_o);
- Config->SoName = getString(Args, OPT_soname);
- Config->Sysroot = getString(Args, OPT_sysroot);
-
- Config->Optimize = getInteger(Args, OPT_O, 1);
- Config->LTOO = getInteger(Args, OPT_lto_O, 2);
- if (Config->LTOO > 3)
- error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O));
- Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
- if (Config->LTOPartitions == 0)
- error("--lto-partitions: number of threads must be > 0");
- Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
- if (Config->ThinLTOJobs == 0)
- error("--thinlto-jobs: number of threads must be > 0");
-
Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
Config->ZExecstack = hasZOption(Args, "execstack");
+ Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
Config->ZNodelete = hasZOption(Args, "nodelete");
+ Config->ZNodlopen = hasZOption(Args, "nodlopen");
Config->ZNow = hasZOption(Args, "now");
Config->ZOrigin = hasZOption(Args, "origin");
Config->ZRelro = !hasZOption(Args, "norelro");
- Config->ZStackSize = getZOptionValue(Args, "stack-size", -1);
+ Config->ZRodynamic = hasZOption(Args, "rodynamic");
+ Config->ZStackSize = getZOptionValue(Args, "stack-size", 0);
+ Config->ZText = !hasZOption(Args, "notext");
Config->ZWxneeded = hasZOption(Args, "wxneeded");
- Config->OFormatBinary = isOutputFormatBinary(Args);
- Config->SectionStartMap = getSectionStartMap(Args);
- Config->SortSection = getSortKind(Args);
- Config->Target2 = getTarget2Option(Args);
- Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args);
+ if (Config->LTOO > 3)
+ error("invalid optimization level for LTO: " +
+ Args.getLastArgValue(OPT_lto_O));
+ if (Config->LTOPartitions == 0)
+ error("--lto-partitions: number of threads must be > 0");
+ if (Config->ThinLTOJobs == 0)
+ error("--thinlto-jobs: number of threads must be > 0");
+
+ if (auto *Arg = Args.getLastArg(OPT_m)) {
+ // Parse ELF{32,64}{LE,BE} and CPU type.
+ StringRef S = Arg->getValue();
+ std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
+ parseEmulation(S);
+ Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");
+ Config->Emulation = S;
+ }
+
+ if (Args.hasArg(OPT_print_map))
+ Config->MapFile = "-";
// --omagic is an option to create old-fashioned executables in which
// .text segments are writable. Today, the option is still in use to
// create special-purpose programs such as boot loaders. It doesn't
// make sense to create PT_GNU_RELRO for such executables.
- if (Config->OMagic)
+ if (Config->Omagic)
Config->ZRelro = false;
- if (!Config->Relocatable)
- Config->Strip = getStripOption(Args);
-
- // Config->Pic is true if we are generating position-independent code.
- Config->Pic = Config->Pie || Config->Shared;
-
- if (auto *Arg = Args.getLastArg(OPT_hash_style)) {
- StringRef S = Arg->getValue();
- if (S == "gnu") {
- Config->GnuHash = true;
- Config->SysvHash = false;
- } else if (S == "both") {
- Config->GnuHash = true;
- } else if (S != "sysv")
- error("unknown hash style: " + S);
- }
-
- // Parse --build-id or --build-id=<style>.
- if (Args.hasArg(OPT_build_id))
- Config->BuildId = BuildIdKind::Fast;
- if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {
- StringRef S = Arg->getValue();
- if (S == "md5") {
- Config->BuildId = BuildIdKind::Md5;
- } else if (S == "sha1" || S == "tree") {
- Config->BuildId = BuildIdKind::Sha1;
- } else if (S == "uuid") {
- Config->BuildId = BuildIdKind::Uuid;
- } else if (S == "none") {
- Config->BuildId = BuildIdKind::None;
- } else if (S.startswith("0x")) {
- Config->BuildId = BuildIdKind::Hexstring;
- Config->BuildIdVector = parseHex(S.substr(2));
- } else {
- error("unknown --build-id style: " + S);
- }
- }
-
- for (auto *Arg : Args.filtered(OPT_auxiliary))
- Config->AuxiliaryList.push_back(Arg->getValue());
- if (!Config->Shared && !Config->AuxiliaryList.empty())
- error("-f may not be used without -shared");
-
- for (auto *Arg : Args.filtered(OPT_undefined))
- Config->Undefined.push_back(Arg->getValue());
-
- if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
- if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
- readDynamicList(*Buffer);
+ std::tie(Config->SysvHash, Config->GnuHash) = getHashStyle(Args);
+ std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args);
if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
Config->SymbolOrderingFile = getLines(*Buffer);
- // If --retain-symbol-file is used, we'll retail only the symbols listed in
+ // If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) {
- Config->Discard = DiscardPolicy::RetainFile;
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
for (StringRef S : getLines(*Buffer))
- Config->RetainSymbolsFile.insert(S);
+ Config->VersionScriptGlobals.push_back(
+ {S, /*IsExternCpp*/ false, /*HasWildcard*/ false});
}
- for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
- Config->VersionScriptGlobals.push_back(
- {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
-
- // Dynamic lists are a simplified linker script that doesn't need the
- // "global:" and implicitly ends with a "local:*". Set the variables needed to
- // simulate that.
- if (Args.hasArg(OPT_dynamic_list) || Args.hasArg(OPT_export_dynamic_symbol)) {
- Config->ExportDynamic = true;
- if (!Config->Shared)
- Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ bool HasExportDynamic =
+ getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false);
+
+ // Parses -dynamic-list and -export-dynamic-symbol. They make some
+ // symbols private. Note that -export-dynamic takes precedence over them
+ // as it says all symbols should be exported.
+ if (!HasExportDynamic) {
+ for (auto *Arg : Args.filtered(OPT_dynamic_list))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readDynamicList(*Buffer);
+
+ for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
+ Config->VersionScriptGlobals.push_back(
+ {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
+
+ // Dynamic lists are a simplified linker script that doesn't need the
+ // "global:" and implicitly ends with a "local:*". Set the variables
+ // needed to simulate that.
+ if (Args.hasArg(OPT_dynamic_list) ||
+ Args.hasArg(OPT_export_dynamic_symbol)) {
+ Config->ExportDynamic = true;
+ if (!Config->Shared)
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ }
}
if (auto *Arg = Args.getLastArg(OPT_version_script))
@@ -648,6 +769,29 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
readVersionScript(*Buffer);
}
+// Some Config members do not directly correspond to any particular
+// command line options, but computed based on other Config values.
+// This function initialize such members. See Config.h for the details
+// of these values.
+static void setConfigs() {
+ ELFKind Kind = Config->EKind;
+ uint16_t Machine = Config->EMachine;
+
+ // There is an ILP32 ABI for x86-64, although it's not very popular.
+ // It is called the x32 ABI.
+ bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
+
+ Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);
+ Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind);
+ Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind);
+ Config->Endianness =
+ Config->IsLE ? support::endianness::little : support::endianness::big;
+ Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS);
+ Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi;
+ Config->Pic = Config->Pie || Config->Shared;
+ Config->Wordsize = Config->Is64 ? 8 : 4;
+}
+
// Returns a value of "-format" option.
static bool getBinaryOption(StringRef S) {
if (S == "binary")
@@ -666,7 +810,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
addLibrary(Arg->getValue());
break;
case OPT_INPUT:
- addFile(Arg->getValue());
+ addFile(Arg->getValue(), /*WithLOption=*/false);
break;
case OPT_alias_script_T:
case OPT_script:
@@ -745,7 +889,7 @@ static uint64_t getImageBase(opt::InputArgList &Args) {
StringRef S = Arg->getValue();
uint64_t V;
- if (S.getAsInteger(0, V)) {
+ if (!to_integer(S, V)) {
error("-image-base: number expected, but got " + S);
return 0;
}
@@ -754,18 +898,63 @@ static uint64_t getImageBase(opt::InputArgList &Args) {
return V;
}
+// Parses --defsym=alias option.
+static std::vector<std::pair<StringRef, StringRef>>
+getDefsym(opt::InputArgList &Args) {
+ std::vector<std::pair<StringRef, StringRef>> Ret;
+ for (auto *Arg : Args.filtered(OPT_defsym)) {
+ StringRef From;
+ StringRef To;
+ std::tie(From, To) = StringRef(Arg->getValue()).split('=');
+ if (!isValidCIdentifier(To))
+ error("--defsym: symbol name expected, but got " + To);
+ Ret.push_back({From, To});
+ }
+ return Ret;
+}
+
+// Parses `--exclude-libs=lib,lib,...`.
+// The library names may be delimited by commas or colons.
+static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) {
+ DenseSet<StringRef> Ret;
+ for (auto *Arg : Args.filtered(OPT_exclude_libs)) {
+ StringRef S = Arg->getValue();
+ for (;;) {
+ size_t Pos = S.find_first_of(",:");
+ if (Pos == StringRef::npos)
+ break;
+ Ret.insert(S.substr(0, Pos));
+ S = S.substr(Pos + 1);
+ }
+ Ret.insert(S);
+ }
+ return Ret;
+}
+
+// Handles the -exclude-libs option. If a static library file is specified
+// by the -exclude-libs option, all public symbols from the archive become
+// private unless otherwise specified by version scripts or something.
+// A special library name "ALL" means all archive files.
+//
+// This is not a popular option, but some programs such as bionic libc use it.
+static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) {
+ DenseSet<StringRef> Libs = getExcludeLibs(Args);
+ bool All = Libs.count("ALL");
+
+ for (InputFile *File : Files)
+ if (auto *F = dyn_cast<ArchiveFile>(File))
+ if (All || Libs.count(path::filename(F->getName())))
+ for (Symbol *Sym : F->getSymbols())
+ Sym->VersionId = VER_NDX_LOCAL;
+}
+
// Do actual linking. Note that when this function is called,
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
SymbolTable<ELFT> Symtab;
elf::Symtab<ELFT>::X = &Symtab;
- Target = createTarget();
- ScriptBase = Script<ELFT>::X = make<LinkerScript<ELFT>>();
+ Target = getTarget();
- Config->Rela =
- ELFT::Is64Bits || Config->EMachine == EM_X86_64 || Config->MipsN32Abi;
- Config->Mips64EL =
- (Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind);
Config->MaxPageSize = getMaxPageSize(Args);
Config->ImageBase = getImageBase(Args);
@@ -773,6 +962,16 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (Config->OutputFile.empty())
Config->OutputFile = "a.out";
+ // Fail early if the output file or map file is not writable. If a user has a
+ // long link, e.g. due to a large LTO link, they do not wish to run it and
+ // find that it failed because there was a mistake in their command-line.
+ if (auto E = tryCreateFile(Config->OutputFile))
+ error("cannot open output file " + Config->OutputFile + ": " + E.message());
+ if (auto E = tryCreateFile(Config->MapFile))
+ error("cannot open map file " + Config->MapFile + ": " + E.message());
+ if (ErrorCount)
+ return;
+
// Use default entry point name if no name was given via the command
// line nor linker scripts. For some reason, MIPS entry point name is
// different from others.
@@ -800,46 +999,64 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (ErrorCount)
return;
+ // Handle the `--undefined <sym>` options.
Symtab.scanUndefinedFlags();
+
+ // Handle undefined symbols in DSOs.
Symtab.scanShlibUndefined();
+
+ // Handle the -exclude-libs option.
+ if (Args.hasArg(OPT_exclude_libs))
+ excludeLibs(Args, Files);
+
+ // Apply version scripts.
Symtab.scanVersionScript();
+ // Create wrapped symbols for -wrap option.
+ for (auto *Arg : Args.filtered(OPT_wrap))
+ Symtab.addSymbolWrap(Arg->getValue());
+
+ // Create alias symbols for -defsym option.
+ for (std::pair<StringRef, StringRef> &Def : getDefsym(Args))
+ Symtab.addSymbolAlias(Def.first, Def.second);
+
Symtab.addCombinedLTOObject();
if (ErrorCount)
return;
- for (auto *Arg : Args.filtered(OPT_wrap))
- Symtab.wrap(Arg->getValue());
+ // Some symbols (such as __ehdr_start) are defined lazily only when there
+ // are undefined symbols for them, so we add these to trigger that logic.
+ for (StringRef Sym : Script->Opt.ReferencedSymbols)
+ Symtab.addUndefined(Sym);
+
+ // Apply symbol renames for -wrap and -defsym
+ Symtab.applySymbolRenames();
// Now that we have a complete list of input files.
// Beyond this point, no new files are added.
// Aggregate all input sections into one place.
for (elf::ObjectFile<ELFT> *F : Symtab.getObjectFiles())
- for (InputSectionBase<ELFT> *S : F->getSections())
- if (S && S != &InputSection<ELFT>::Discarded)
- Symtab.Sections.push_back(S);
+ for (InputSectionBase *S : F->getSections())
+ if (S && S != &InputSection::Discarded)
+ InputSections.push_back(S);
for (BinaryFile *F : Symtab.getBinaryFiles())
- for (InputSectionData *S : F->getSections())
- Symtab.Sections.push_back(cast<InputSection<ELFT>>(S));
+ for (InputSectionBase *S : F->getSections())
+ InputSections.push_back(cast<InputSection>(S));
- // Do size optimizations: garbage collection and identical code folding.
+ // This adds a .comment section containing a version string. We have to add it
+ // before decompressAndMergeSections because the .comment section is a
+ // mergeable section.
+ if (!Config->Relocatable)
+ InputSections.push_back(createCommentSection<ELFT>());
+
+ // Do size optimizations: garbage collection, merging of SHF_MERGE sections
+ // and identical code folding.
if (Config->GcSections)
markLive<ELFT>();
+ decompressAndMergeSections();
if (Config->ICF)
doIcf<ELFT>();
- // MergeInputSection::splitIntoPieces needs to be called before
- // any call of MergeInputSection::getOffset. Do that.
- forEach(Symtab.Sections.begin(), Symtab.Sections.end(),
- [](InputSectionBase<ELFT> *S) {
- if (!S->Live)
- return;
- if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
- S->uncompress();
- if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S))
- MS->splitIntoPieces();
- });
-
// Write the result to the file.
writeResult<ELFT>();
}
diff --git a/contrib/llvm/tools/lld/ELF/Driver.h b/contrib/llvm/tools/lld/ELF/Driver.h
index b600fae..62d2edf 100644
--- a/contrib/llvm/tools/lld/ELF/Driver.h
+++ b/contrib/llvm/tools/lld/ELF/Driver.h
@@ -27,11 +27,10 @@ extern class LinkerDriver *Driver;
class LinkerDriver {
public:
void main(ArrayRef<const char *> Args, bool CanExitEarly);
- void addFile(StringRef Path);
+ void addFile(StringRef Path, bool WithLOption);
void addLibrary(StringRef Name);
private:
- std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB);
void readConfigs(llvm::opt::InputArgList &Args);
void createFiles(llvm::opt::InputArgList &Args);
void inferMachineType();
@@ -59,14 +58,12 @@ public:
// Create enum with OPT_xxx values for each option in Options.td
enum {
OPT_INVALID = 0,
-#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
#include "ELF/Options.inc"
#undef OPTION
};
void printHelp(const char *Argv0);
-std::vector<uint8_t> parseHexstring(StringRef S);
-
std::string createResponseFile(const llvm::opt::InputArgList &Args);
llvm::Optional<std::string> findFromSearchPaths(StringRef Path);
diff --git a/contrib/llvm/tools/lld/ELF/DriverUtils.cpp b/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
index 1fbba7c..d1ff70b 100644
--- a/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
+++ b/contrib/llvm/tools/lld/ELF/DriverUtils.cpp
@@ -16,7 +16,6 @@
#include "Driver.h"
#include "Error.h"
#include "Memory.h"
-#include "ScriptParser.h"
#include "lld/Config/Version.h"
#include "lld/Core/Reproduce.h"
#include "llvm/ADT/Optional.h"
@@ -43,9 +42,9 @@ using namespace lld::elf;
// Create table mapping all options defined in Options.td
static const opt::OptTable::Info OptInfo[] = {
-#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \
- {X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, \
- X8, X7, OPT_##GROUP, OPT_##ALIAS, X6},
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
+ {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
+ X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
#include "ELF/Options.inc"
#undef OPTION
};
@@ -54,12 +53,10 @@ ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics.
static bool getColorDiagnostics(opt::InputArgList &Args) {
- bool Default = (ErrorOS == &errs() && Process::StandardErrHasColors());
-
auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
OPT_no_color_diagnostics);
if (!Arg)
- return Default;
+ return ErrorOS->has_colors();
if (Arg->getOption().getID() == OPT_color_diagnostics)
return true;
if (Arg->getOption().getID() == OPT_no_color_diagnostics)
@@ -67,7 +64,7 @@ static bool getColorDiagnostics(opt::InputArgList &Args) {
StringRef S = Arg->getValue();
if (S == "auto")
- return Default;
+ return ErrorOS->has_colors();
if (S == "always")
return true;
if (S != "never")
@@ -123,17 +120,17 @@ void elf::printHelp(const char *Argv0) {
outs() << "\n";
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
- // recent version as of March 2017) expect /supported targets:.* elf/ in
- // a message for the -help option. If it doesn't match, the scripts
+ // recent version as of March 2017) expect /: supported targets:.* elf/
+ // in a message for the -help option. If it doesn't match, the scripts
// assume that the linker doesn't support very basic features such as
// shared libraries. Therefore, we need to print out at least "elf".
// Here, we print out all the targets that we support.
outs() << Argv0 << ": supported targets: "
- << "elf32-i386 elf32-iamcu elf32-littlearm elf32-powerpc "
- << "elf32-tradbigmips elf32-tradlittlemips "
- << "elf32-ntradbigmips elf32-ntradlittlemips elf32-x86-64 "
- << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc "
- << "elf64-tradbigmips elf64-tradlittlemips elf64-x86-64\n";
+ << "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips "
+ << "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips "
+ << "elf32-tradlittlemips elf32-x86-64 "
+ << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips "
+ << "elf64-tradlittlemips elf64-x86-64\n";
}
// Reconstructs command line arguments so that so that you can re-run
@@ -150,6 +147,13 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) {
case OPT_INPUT:
OS << quote(rewritePath(Arg->getValue())) << "\n";
break;
+ case OPT_o:
+ // If -o path contains directories, "lld @response.txt" will likely
+ // fail because the archive we are creating doesn't contain empty
+ // directories for the output path (-o doesn't create directories).
+ // Strip directories to prevent the issue.
+ OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
+ break;
case OPT_L:
case OPT_dynamic_list:
case OPT_rpath:
diff --git a/contrib/llvm/tools/lld/ELF/EhFrame.cpp b/contrib/llvm/tools/lld/ELF/EhFrame.cpp
index 2428473..c4e3f65 100644
--- a/contrib/llvm/tools/lld/ELF/EhFrame.cpp
+++ b/contrib/llvm/tools/lld/ELF/EhFrame.cpp
@@ -22,8 +22,8 @@
#include "Relocations.h"
#include "Strings.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
@@ -38,13 +38,14 @@ using namespace lld::elf;
namespace {
template <class ELFT> class EhReader {
public:
- EhReader(InputSectionBase<ELFT> *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
+ EhReader(InputSectionBase *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
size_t readEhRecordSize();
uint8_t getFdeEncoding();
private:
template <class P> void failOn(const P *Loc, const Twine &Msg) {
- fatal(IS->getLocation((const uint8_t *)Loc - IS->Data.data()) + ": " + Msg);
+ fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " +
+ IS->getObjMsg<ELFT>((const uint8_t *)Loc - IS->Data.data()));
}
uint8_t readByte();
@@ -53,15 +54,16 @@ private:
void skipLeb128();
void skipAugP();
- InputSectionBase<ELFT> *IS;
+ InputSectionBase *IS;
ArrayRef<uint8_t> D;
};
}
template <class ELFT>
-size_t elf::readEhRecordSize(InputSectionBase<ELFT> *S, size_t Off) {
+size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) {
return EhReader<ELFT>(S, S->Data.slice(Off)).readEhRecordSize();
}
+
// .eh_frame section is a sequence of records. Each record starts with
// a 4 byte length field. This function reads the length.
template <class ELFT> size_t EhReader<ELFT>::readEhRecordSize() {
@@ -121,11 +123,11 @@ template <class ELFT> void EhReader<ELFT>::skipLeb128() {
failOn(ErrPos, "corrupted CIE (failed to read LEB128)");
}
-template <class ELFT> static size_t getAugPSize(unsigned Enc) {
+static size_t getAugPSize(unsigned Enc) {
switch (Enc & 0x0f) {
case DW_EH_PE_absptr:
case DW_EH_PE_signed:
- return ELFT::Is64Bits ? 8 : 4;
+ return Config->Wordsize;
case DW_EH_PE_udata2:
case DW_EH_PE_sdata2:
return 2;
@@ -143,7 +145,7 @@ template <class ELFT> void EhReader<ELFT>::skipAugP() {
uint8_t Enc = readByte();
if ((Enc & 0xf0) == DW_EH_PE_aligned)
failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported");
- size_t Size = getAugPSize<ELFT>(Enc);
+ size_t Size = getAugPSize(Enc);
if (Size == 0)
failOn(D.data() - 1, "unknown FDE encoding");
if (Size >= D.size())
@@ -152,7 +154,7 @@ template <class ELFT> void EhReader<ELFT>::skipAugP() {
}
template <class ELFT> uint8_t elf::getFdeEncoding(EhSectionPiece *P) {
- auto *IS = static_cast<InputSectionBase<ELFT> *>(P->ID);
+ auto *IS = static_cast<InputSectionBase *>(P->ID);
return EhReader<ELFT>(IS, P->data()).getFdeEncoding();
}
@@ -199,14 +201,10 @@ template <class ELFT> uint8_t EhReader<ELFT>::getFdeEncoding() {
return DW_EH_PE_absptr;
}
-template size_t elf::readEhRecordSize<ELF32LE>(InputSectionBase<ELF32LE> *S,
- size_t Off);
-template size_t elf::readEhRecordSize<ELF32BE>(InputSectionBase<ELF32BE> *S,
- size_t Off);
-template size_t elf::readEhRecordSize<ELF64LE>(InputSectionBase<ELF64LE> *S,
- size_t Off);
-template size_t elf::readEhRecordSize<ELF64BE>(InputSectionBase<ELF64BE> *S,
- size_t Off);
+template size_t elf::readEhRecordSize<ELF32LE>(InputSectionBase *S, size_t Off);
+template size_t elf::readEhRecordSize<ELF32BE>(InputSectionBase *S, size_t Off);
+template size_t elf::readEhRecordSize<ELF64LE>(InputSectionBase *S, size_t Off);
+template size_t elf::readEhRecordSize<ELF64BE>(InputSectionBase *S, size_t Off);
template uint8_t elf::getFdeEncoding<ELF32LE>(EhSectionPiece *P);
template uint8_t elf::getFdeEncoding<ELF32BE>(EhSectionPiece *P);
diff --git a/contrib/llvm/tools/lld/ELF/EhFrame.h b/contrib/llvm/tools/lld/ELF/EhFrame.h
index cadc93d..07d1aaa 100644
--- a/contrib/llvm/tools/lld/ELF/EhFrame.h
+++ b/contrib/llvm/tools/lld/ELF/EhFrame.h
@@ -14,13 +14,12 @@
namespace lld {
namespace elf {
-template <class ELFT> class InputSectionBase;
+class InputSectionBase;
struct EhSectionPiece;
-template <class ELFT>
-size_t readEhRecordSize(InputSectionBase<ELFT> *S, size_t Off);
+template <class ELFT> size_t readEhRecordSize(InputSectionBase *S, size_t Off);
template <class ELFT> uint8_t getFdeEncoding(EhSectionPiece *P);
-}
-}
+} // namespace elf
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/Error.cpp b/contrib/llvm/tools/lld/ELF/Error.cpp
index d9b41f9..224570e 100644
--- a/contrib/llvm/tools/lld/ELF/Error.cpp
+++ b/contrib/llvm/tools/lld/ELF/Error.cpp
@@ -20,21 +20,32 @@
#include <unistd.h>
#endif
-using namespace lld::elf;
using namespace llvm;
-namespace lld {
+using namespace lld;
+using namespace lld::elf;
uint64_t elf::ErrorCount;
raw_ostream *elf::ErrorOS;
-StringRef elf::Argv0;
// The functions defined in this file can be called from multiple threads,
// but outs() or errs() are not thread-safe. We protect them using a mutex.
static std::mutex Mu;
+// Prints "\n" or does nothing, depending on Msg contents of
+// the previous call of this function.
+static void newline(const Twine &Msg) {
+ // True if the previous error message contained "\n".
+ // We want to separate multi-line error messages with a newline.
+ static bool Flag;
+
+ if (Flag)
+ *ErrorOS << "\n";
+ Flag = (StringRef(Msg.str()).find('\n') != StringRef::npos);
+}
+
static void print(StringRef S, raw_ostream::Colors C) {
- *ErrorOS << Argv0 + ": ";
+ *ErrorOS << Config->Argv[0] << ": ";
if (Config->ColorDiagnostics) {
ErrorOS->changeColor(C, true);
*ErrorOS << S;
@@ -45,9 +56,17 @@ static void print(StringRef S, raw_ostream::Colors C) {
}
void elf::log(const Twine &Msg) {
+ if (Config->Verbose) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ outs() << Config->Argv[0] << ": " << Msg << "\n";
+ outs().flush();
+ }
+}
+
+void elf::message(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
- if (Config->Verbose)
- outs() << Argv0 << ": " << Msg << "\n";
+ outs() << Msg << "\n";
+ outs().flush();
}
void elf::warn(const Twine &Msg) {
@@ -55,13 +74,16 @@ void elf::warn(const Twine &Msg) {
error(Msg);
return;
}
+
std::lock_guard<std::mutex> Lock(Mu);
+ newline(Msg);
print("warning: ", raw_ostream::MAGENTA);
*ErrorOS << Msg << "\n";
}
void elf::error(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
+ newline(Msg);
if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
print("error: ", raw_ostream::RED);
@@ -77,10 +99,6 @@ void elf::error(const Twine &Msg) {
++ErrorCount;
}
-void elf::error(std::error_code EC, const Twine &Prefix) {
- error(Prefix + ": " + EC.message());
-}
-
void elf::exitLld(int Val) {
// Dealloc/destroy ManagedStatic variables before calling
// _exit(). In a non-LTO build, this is a nop. In an LTO
@@ -93,18 +111,6 @@ void elf::exitLld(int Val) {
}
void elf::fatal(const Twine &Msg) {
- std::lock_guard<std::mutex> Lock(Mu);
- print("error: ", raw_ostream::RED);
- *ErrorOS << Msg << "\n";
+ error(Msg);
exitLld(1);
}
-
-void elf::fatal(std::error_code EC, const Twine &Prefix) {
- fatal(Prefix + ": " + EC.message());
-}
-
-void elf::fatal(Error &E, const Twine &Prefix) {
- fatal(Prefix + ": " + llvm::toString(std::move(E)));
-}
-
-} // namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/Error.h b/contrib/llvm/tools/lld/ELF/Error.h
index f18cf45..89bc211 100644
--- a/contrib/llvm/tools/lld/ELF/Error.h
+++ b/contrib/llvm/tools/lld/ELF/Error.h
@@ -15,10 +15,14 @@
// Error prints out an error message and increment a global variable
// ErrorCount to record the fact that we met an error condition. It does
// not exit, so it is safe for a lld-as-a-library use case. It is generally
-// useful because it can report more than one errors in a single run.
+// useful because it can report more than one error in a single run.
//
// Warn doesn't do anything but printing out a given message.
//
+// It is not recommended to use llvm::outs() or llvm::errs() directly
+// in LLD because they are not thread-safe. The functions declared in
+// this file are mutually excluded, so you want to use them instead.
+//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_ERROR_H
@@ -33,18 +37,14 @@ namespace elf {
extern uint64_t ErrorCount;
extern llvm::raw_ostream *ErrorOS;
-extern llvm::StringRef Argv0;
void log(const Twine &Msg);
+void message(const Twine &Msg);
void warn(const Twine &Msg);
-
void error(const Twine &Msg);
-void error(std::error_code EC, const Twine &Prefix);
+LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
-LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
-LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
-LLVM_ATTRIBUTE_NORETURN void fatal(Error &E, const Twine &Prefix);
// check() functions are convenient functions to strip errors
// from error-or-value objects.
@@ -68,7 +68,7 @@ template <class T> T check(ErrorOr<T> E, const Twine &Prefix) {
template <class T> T check(Expected<T> E, const Twine &Prefix) {
if (!E)
- fatal(Prefix + ": " + errorToErrorCode(E.takeError()).message());
+ fatal(Prefix + ": " + toString(E.takeError()));
return std::move(*E);
}
diff --git a/contrib/llvm/tools/lld/ELF/Filesystem.cpp b/contrib/llvm/tools/lld/ELF/Filesystem.cpp
new file mode 100644
index 0000000..d468ae0
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Filesystem.cpp
@@ -0,0 +1,77 @@
+//===- Filesystem.cpp -----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a few utility functions to handle files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Filesystem.h"
+#include "Config.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <thread>
+
+using namespace llvm;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Removes a given file asynchronously. This is a performance hack,
+// so remove this when operating systems are improved.
+//
+// On Linux (and probably on other Unix-like systems), unlink(2) is a
+// noticeably slow system call. As of 2016, unlink takes 250
+// milliseconds to remove a 1 GB file on ext4 filesystem on my machine.
+//
+// To create a new result file, we first remove existing file. So, if
+// you repeatedly link a 1 GB program in a regular compile-link-debug
+// cycle, every cycle wastes 250 milliseconds only to remove a file.
+// Since LLD can link a 1 GB binary in about 5 seconds, that waste
+// actually counts.
+//
+// This function spawns a background thread to call unlink.
+// The calling thread returns almost immediately.
+void elf::unlinkAsync(StringRef Path) {
+ if (!Config->Threads || !sys::fs::exists(Config->OutputFile) ||
+ !sys::fs::is_regular_file(Config->OutputFile))
+ return;
+
+ // First, rename Path to avoid race condition. We cannot remove
+ // Path from a different thread because we are now going to create
+ // Path as a new file. If we do that in a different thread, the new
+ // thread can remove the new file.
+ SmallString<128> TempPath;
+ if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath))
+ return;
+ if (sys::fs::rename(Path, TempPath)) {
+ sys::fs::remove(TempPath);
+ return;
+ }
+
+ // Remove TempPath in background.
+ std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach();
+}
+
+// Simulate file creation to see if Path is writable.
+//
+// Determining whether a file is writable or not is amazingly hard,
+// and after all the only reliable way of doing that is to actually
+// create a file. But we don't want to do that in this function
+// because LLD shouldn't update any file if it will end in a failure.
+// We also don't want to reimplement heuristics to determine if a
+// file is writable. So we'll let FileOutputBuffer do the work.
+//
+// FileOutputBuffer doesn't touch a desitnation file until commit()
+// is called. We use that class without calling commit() to predict
+// if the given file is writable.
+std::error_code elf::tryCreateFile(StringRef Path) {
+ if (Path.empty())
+ return std::error_code();
+ return FileOutputBuffer::create(Path, 1).getError();
+}
diff --git a/contrib/llvm/tools/lld/ELF/Filesystem.h b/contrib/llvm/tools/lld/ELF/Filesystem.h
new file mode 100644
index 0000000..dbeadac
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/Filesystem.h
@@ -0,0 +1,22 @@
+//===- Filesystem.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_FILESYSTEM_H
+#define LLD_ELF_FILESYSTEM_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+void unlinkAsync(StringRef Path);
+std::error_code tryCreateFile(StringRef Path);
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/GdbIndex.cpp b/contrib/llvm/tools/lld/ELF/GdbIndex.cpp
index 762144d..99e02d0 100644
--- a/contrib/llvm/tools/lld/ELF/GdbIndex.cpp
+++ b/contrib/llvm/tools/lld/ELF/GdbIndex.cpp
@@ -7,199 +7,43 @@
//
//===----------------------------------------------------------------------===//
//
-// File contains classes for implementation of --gdb-index command line option.
+// The -gdb-index option instructs the linker to emit a .gdb_index section.
+// The section contains information to make gdb startup faster.
+// The format of the section is described at
+// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html.
//
-// If that option is used, linker should emit a .gdb_index section that allows
-// debugger to locate and read .dwo files, containing neccessary debug
-// information.
-// More information about implementation can be found in DWARF specification,
-// latest version is available at http://dwarfstd.org.
-//
-// .gdb_index section format:
-// (Information is based on/taken from
-// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html (*))
-//
-// A mapped index consists of several areas, laid out in order:
-// 1) The file header.
-// 2) "The CU (compilation unit) list. This is a sequence of pairs of 64-bit
-// little-endian values, sorted by the CU offset. The first element in each
-// pair is the offset of a CU in the .debug_info section. The second element
-// in each pair is the length of that CU. References to a CU elsewhere in the
-// map are done using a CU index, which is just the 0-based index into this
-// table. Note that if there are type CUs, then conceptually CUs and type CUs
-// form a single list for the purposes of CU indices."(*)
-// 3) The types CU list. Depricated as .debug_types does not appear in the DWARF
-// v5 specification.
-// 4) The address area. The address area is a sequence of address
-// entries, where each entrie contains low address, high address and CU
-// index.
-// 5) "The symbol table. This is an open-addressed hash table. The size of the
-// hash table is always a power of 2. Each slot in the hash table consists of
-// a pair of offset_type values. The first value is the offset of the
-// symbol's name in the constant pool. The second value is the offset of the
-// CU vector in the constant pool."(*)
-// 6) "The constant pool. This is simply a bunch of bytes. It is organized so
-// that alignment is correct: CU vectors are stored first, followed by
-// strings." (*)
-//
-// For constructing the .gdb_index section following steps should be performed:
-// 1) For file header nothing special should be done. It contains the offsets to
-// the areas below.
-// 2) Scan the compilation unit headers of the .debug_info sections to build a
-// list of compilation units.
-// 3) CU Types are no longer needed as DWARF skeleton type units never made it
-// into the standard. lld does nothing to support parsing of .debug_types
-// and generates empty types CU area in .gdb_index section.
-// 4) Address area entries are extracted from DW_TAG_compile_unit DIEs of
-// .debug_info sections.
-// 5) For building the symbol table linker extracts the public names from the
-// .debug_gnu_pubnames and .debug_gnu_pubtypes sections. Then it builds the
-// hashtable in according to .gdb_index format specification.
-// 6) Constant pool is populated at the same time as symbol table.
//===----------------------------------------------------------------------===//
#include "GdbIndex.h"
+#include "Memory.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/ELFObjectFile.h"
using namespace llvm;
using namespace llvm::object;
+using namespace lld;
using namespace lld::elf;
-template <class ELFT>
-GdbIndexBuilder<ELFT>::GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec)
- : DebugInfoSec(DebugInfoSec) {
- if (Expected<std::unique_ptr<object::ObjectFile>> Obj =
- object::ObjectFile::createObjectFile(DebugInfoSec->getFile()->MB))
- Dwarf.reset(new DWARFContextInMemory(*Obj.get(), this));
- else
- error(toString(DebugInfoSec->getFile()) + ": error creating DWARF context");
-}
-
-template <class ELFT>
-std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>>
-GdbIndexBuilder<ELFT>::readCUList() {
- std::vector<std::pair<uintX_t, uintX_t>> Ret;
- for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units())
- Ret.push_back(
- {DebugInfoSec->OutSecOff + CU->getOffset(), CU->getLength() + 4});
- return Ret;
-}
-
-template <class ELFT>
-std::vector<std::pair<StringRef, uint8_t>>
-GdbIndexBuilder<ELFT>::readPubNamesAndTypes() {
- const bool IsLE = ELFT::TargetEndianness == llvm::support::little;
- StringRef Data[] = {Dwarf->getGnuPubNamesSection(),
- Dwarf->getGnuPubTypesSection()};
-
- std::vector<std::pair<StringRef, uint8_t>> Ret;
- for (StringRef D : Data) {
- DWARFDebugPubTable PubTable(D, IsLE, true);
- for (const DWARFDebugPubTable::Set &S : PubTable.getData())
- for (const DWARFDebugPubTable::Entry &E : S.Entries)
- Ret.push_back({E.Name, E.Descriptor.toBits()});
- }
- return Ret;
-}
-
std::pair<bool, GdbSymbol *> GdbHashTab::add(uint32_t Hash, size_t Offset) {
- if (Size * 4 / 3 >= Table.size())
- expand();
-
- GdbSymbol **Slot = findSlot(Hash, Offset);
- bool New = false;
- if (*Slot == nullptr) {
- ++Size;
- *Slot = new (Alloc) GdbSymbol(Hash, Offset);
- New = true;
+ GdbSymbol *&Sym = Map[Offset];
+ if (Sym)
+ return {false, Sym};
+ Sym = make<GdbSymbol>(Hash, Offset);
+ return {true, Sym};
+}
+
+void GdbHashTab::finalizeContents() {
+ uint32_t Size = std::max<uint32_t>(1024, NextPowerOf2(Map.size() * 4 / 3));
+ uint32_t Mask = Size - 1;
+ Table.resize(Size);
+
+ for (auto &P : Map) {
+ GdbSymbol *Sym = P.second;
+ uint32_t I = Sym->NameHash & Mask;
+ uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1;
+
+ while (Table[I])
+ I = (I + Step) & Mask;
+ Table[I] = Sym;
}
- return {New, *Slot};
-}
-
-void GdbHashTab::expand() {
- if (Table.empty()) {
- Table.resize(InitialSize);
- return;
- }
- std::vector<GdbSymbol *> NewTable(Table.size() * 2);
- NewTable.swap(Table);
-
- for (GdbSymbol *Sym : NewTable) {
- if (!Sym)
- continue;
- GdbSymbol **Slot = findSlot(Sym->NameHash, Sym->NameOffset);
- *Slot = Sym;
- }
-}
-
-// Methods finds a slot for symbol with given hash. The step size used to find
-// the next candidate slot when handling a hash collision is specified in
-// .gdb_index section format. The hash value for a table entry is computed by
-// applying an iterative hash function to the symbol's name.
-GdbSymbol **GdbHashTab::findSlot(uint32_t Hash, size_t Offset) {
- uint32_t Index = Hash & (Table.size() - 1);
- uint32_t Step = ((Hash * 17) & (Table.size() - 1)) | 1;
-
- for (;;) {
- GdbSymbol *S = Table[Index];
- if (!S || ((S->NameOffset == Offset) && (S->NameHash == Hash)))
- return &Table[Index];
- Index = (Index + Step) & (Table.size() - 1);
- }
-}
-
-template <class ELFT>
-static InputSectionBase<ELFT> *
-findSection(ArrayRef<InputSectionBase<ELFT> *> Arr, uint64_t Offset) {
- for (InputSectionBase<ELFT> *S : Arr)
- if (S && S != &InputSection<ELFT>::Discarded)
- if (Offset >= S->Offset && Offset < S->Offset + S->getSize())
- return S;
- return nullptr;
-}
-
-template <class ELFT>
-std::vector<AddressEntry<ELFT>>
-GdbIndexBuilder<ELFT>::readAddressArea(size_t CurrentCU) {
- std::vector<AddressEntry<ELFT>> Ret;
- for (const auto &CU : Dwarf->compile_units()) {
- DWARFAddressRangesVector Ranges;
- CU->collectAddressRanges(Ranges);
-
- ArrayRef<InputSectionBase<ELFT> *> Sections =
- DebugInfoSec->getFile()->getSections();
-
- for (std::pair<uint64_t, uint64_t> &R : Ranges)
- if (InputSectionBase<ELFT> *S = findSection(Sections, R.first))
- Ret.push_back(
- {S, R.first - S->Offset, R.second - S->Offset, CurrentCU});
- ++CurrentCU;
- }
- return Ret;
-}
-
-// We return file offset as load address for allocatable sections. That is
-// currently used for collecting address ranges in readAddressArea(). We are
-// able then to find section index that range belongs to.
-template <class ELFT>
-uint64_t GdbIndexBuilder<ELFT>::getSectionLoadAddress(
- const object::SectionRef &Sec) const {
- if (static_cast<const ELFSectionRef &>(Sec).getFlags() & ELF::SHF_ALLOC)
- return static_cast<const ELFSectionRef &>(Sec).getOffset();
- return 0;
-}
-
-template <class ELFT>
-std::unique_ptr<LoadedObjectInfo> GdbIndexBuilder<ELFT>::clone() const {
- return {};
-}
-
-namespace lld {
-namespace elf {
-template class GdbIndexBuilder<ELF32LE>;
-template class GdbIndexBuilder<ELF32BE>;
-template class GdbIndexBuilder<ELF64LE>;
-template class GdbIndexBuilder<ELF64BE>;
-}
}
diff --git a/contrib/llvm/tools/lld/ELF/GdbIndex.h b/contrib/llvm/tools/lld/ELF/GdbIndex.h
index c761ea1..bc024e6 100644
--- a/contrib/llvm/tools/lld/ELF/GdbIndex.h
+++ b/contrib/llvm/tools/lld/ELF/GdbIndex.h
@@ -11,52 +11,44 @@
#define LLD_ELF_GDB_INDEX_H
#include "InputFiles.h"
-#include "llvm/Object/ELF.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Object/ELF.h"
namespace lld {
namespace elf {
-template <class ELFT> class InputSection;
+class InputSection;
// Struct represents single entry of address area of gdb index.
-template <class ELFT> struct AddressEntry {
- InputSectionBase<ELFT> *Section;
+struct AddressEntry {
+ InputSection *Section;
uint64_t LowAddress;
uint64_t HighAddress;
- size_t CuIndex;
+ uint32_t CuIndex;
};
-// GdbIndexBuilder is a helper class used for extracting data required
-// for building .gdb_index section from objects.
-template <class ELFT> class GdbIndexBuilder : public llvm::LoadedObjectInfo {
- typedef typename ELFT::uint uintX_t;
-
- InputSection<ELFT> *DebugInfoSec;
-
- std::unique_ptr<llvm::DWARFContext> Dwarf;
-
-public:
- GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec);
-
- // Extracts the compilation units. Each first element of pair is a offset of a
- // CU in the .debug_info section and second is the length of that CU.
- std::vector<std::pair<uintX_t, uintX_t>> readCUList();
-
- // Extracts the vector of address area entries. Accepts global index of last
- // parsed CU.
- std::vector<AddressEntry<ELFT>> readAddressArea(size_t CurrentCU);
+// Struct represents single entry of compilation units list area of gdb index.
+// It consist of CU offset in .debug_info section and it's size.
+struct CompilationUnitEntry {
+ uint64_t CuOffset;
+ uint64_t CuLength;
+};
- // Method extracts public names and types. It returns list of name and
- // gnu_pub* kind pairs.
- std::vector<std::pair<StringRef, uint8_t>> readPubNamesAndTypes();
+// Represents data about symbol and type names which are used
+// to build symbol table and constant pool area of gdb index.
+struct NameTypeEntry {
+ StringRef Name;
+ uint8_t Type;
+};
-private:
- // Method returns section file offset as a load addres for DWARF parser. That
- // allows to find the target section index for address ranges.
- uint64_t
- getSectionLoadAddress(const llvm::object::SectionRef &Sec) const override;
- std::unique_ptr<llvm::LoadedObjectInfo> clone() const override;
+// We fill one GdbIndexDataChunk for each object where scan of
+// debug information performed. That information futher used
+// for filling gdb index section areas.
+struct GdbIndexChunk {
+ InputSection *DebugInfoSec;
+ std::vector<AddressEntry> AddressArea;
+ std::vector<CompilationUnitEntry> CompilationUnits;
+ std::vector<NameTypeEntry> NamesAndTypes;
};
// Element of GdbHashTab hash table.
@@ -75,22 +67,13 @@ class GdbHashTab final {
public:
std::pair<bool, GdbSymbol *> add(uint32_t Hash, size_t Offset);
+ void finalizeContents();
size_t getCapacity() { return Table.size(); }
GdbSymbol *getSymbol(size_t I) { return Table[I]; }
private:
- void expand();
-
- GdbSymbol **findSlot(uint32_t Hash, size_t Offset);
-
- llvm::BumpPtrAllocator Alloc;
+ llvm::DenseMap<size_t, GdbSymbol *> Map;
std::vector<GdbSymbol *> Table;
-
- // Size keeps the amount of filled entries in Table.
- size_t Size = 0;
-
- // Initial size must be a power of 2.
- static const int32_t InitialSize = 1024;
};
} // namespace elf
diff --git a/contrib/llvm/tools/lld/ELF/ICF.cpp b/contrib/llvm/tools/lld/ELF/ICF.cpp
index 32cd0f8..09512a8 100644
--- a/contrib/llvm/tools/lld/ELF/ICF.cpp
+++ b/contrib/llvm/tools/lld/ELF/ICF.cpp
@@ -77,10 +77,9 @@
#include "Config.h"
#include "SymbolTable.h"
#include "Threads.h"
-
#include "llvm/ADT/Hashing.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/ELF.h"
#include <algorithm>
#include <atomic>
@@ -99,14 +98,15 @@ private:
void segregate(size_t Begin, size_t End, bool Constant);
template <class RelTy>
- bool constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB);
+ bool constantEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB);
template <class RelTy>
- bool variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
- const InputSection<ELFT> *B, ArrayRef<RelTy> RelsB);
+ bool variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB);
- bool equalsConstant(const InputSection<ELFT> *A, const InputSection<ELFT> *B);
- bool equalsVariable(const InputSection<ELFT> *A, const InputSection<ELFT> *B);
+ bool equalsConstant(const InputSection *A, const InputSection *B);
+ bool equalsVariable(const InputSection *A, const InputSection *B);
size_t findBoundary(size_t Begin, size_t End);
@@ -115,7 +115,7 @@ private:
void forEachClass(std::function<void(size_t, size_t)> Fn);
- std::vector<InputSection<ELFT> *> Sections;
+ std::vector<InputSection *> Sections;
// We repeat the main loop while `Repeat` is true.
std::atomic<bool> Repeat;
@@ -154,17 +154,17 @@ private:
// Returns a hash value for S. Note that the information about
// relocation targets is not included in the hash value.
-template <class ELFT> static uint32_t getHash(InputSection<ELFT> *S) {
+template <class ELFT> static uint32_t getHash(InputSection *S) {
return hash_combine(S->Flags, S->getSize(), S->NumRelocations);
}
// Returns true if section S is subject of ICF.
-template <class ELFT> static bool isEligible(InputSection<ELFT> *S) {
+static bool isEligible(InputSection *S) {
// .init and .fini contains instructions that must be executed to
// initialize and finalize the process. They cannot and should not
// be merged.
- return S->Live && (S->Flags & SHF_ALLOC) && !(S->Flags & SHF_WRITE) &&
- S->Name != ".init" && S->Name != ".fini";
+ return S->Live && (S->Flags & SHF_ALLOC) && (S->Flags & SHF_EXECINSTR) &&
+ !(S->Flags & SHF_WRITE) && S->Name != ".init" && S->Name != ".fini";
}
// Split an equivalence class into smaller classes.
@@ -181,17 +181,17 @@ void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) {
while (Begin < End) {
// Divide [Begin, End) into two. Let Mid be the start index of the
// second group.
- auto Bound = std::stable_partition(
- Sections.begin() + Begin + 1, Sections.begin() + End,
- [&](InputSection<ELFT> *S) {
- if (Constant)
- return equalsConstant(Sections[Begin], S);
- return equalsVariable(Sections[Begin], S);
- });
+ auto Bound =
+ std::stable_partition(Sections.begin() + Begin + 1,
+ Sections.begin() + End, [&](InputSection *S) {
+ if (Constant)
+ return equalsConstant(Sections[Begin], S);
+ return equalsVariable(Sections[Begin], S);
+ });
size_t Mid = Bound - Sections.begin();
// Now we split [Begin, End) into [Begin, Mid) and [Mid, End) by
- // updating the sections in [Begin, End). We use Mid as an equivalence
+ // updating the sections in [Begin, Mid). We use Mid as an equivalence
// class ID because every group ends with a unique index.
for (size_t I = Begin; I < Mid; ++I)
Sections[I]->Class[Next] = Mid;
@@ -207,11 +207,53 @@ void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) {
// Compare two lists of relocations.
template <class ELFT>
template <class RelTy>
-bool ICF<ELFT>::constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
- auto Eq = [](const RelTy &A, const RelTy &B) {
- return A.r_offset == B.r_offset &&
- A.getType(Config->Mips64EL) == B.getType(Config->Mips64EL) &&
- getAddend<ELFT>(A) == getAddend<ELFT>(B);
+bool ICF<ELFT>::constantEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB) {
+ auto Eq = [&](const RelTy &RA, const RelTy &RB) {
+ if (RA.r_offset != RB.r_offset ||
+ RA.getType(Config->IsMips64EL) != RB.getType(Config->IsMips64EL))
+ return false;
+ uint64_t AddA = getAddend<ELFT>(RA);
+ uint64_t AddB = getAddend<ELFT>(RB);
+
+ SymbolBody &SA = A->template getFile<ELFT>()->getRelocTargetSym(RA);
+ SymbolBody &SB = B->template getFile<ELFT>()->getRelocTargetSym(RB);
+ if (&SA == &SB)
+ return AddA == AddB;
+
+ auto *DA = dyn_cast<DefinedRegular>(&SA);
+ auto *DB = dyn_cast<DefinedRegular>(&SB);
+ if (!DA || !DB)
+ return false;
+
+ // Relocations referring to absolute symbols are constant-equal if their
+ // values are equal.
+ if (!DA->Section || !DB->Section)
+ return !DA->Section && !DB->Section &&
+ DA->Value + AddA == DB->Value + AddB;
+
+ if (DA->Section->kind() != DB->Section->kind())
+ return false;
+
+ // Relocations referring to InputSections are constant-equal if their
+ // section offsets are equal.
+ if (isa<InputSection>(DA->Section))
+ return DA->Value + AddA == DB->Value + AddB;
+
+ // Relocations referring to MergeInputSections are constant-equal if their
+ // offsets in the output section are equal.
+ auto *X = dyn_cast<MergeInputSection>(DA->Section);
+ if (!X)
+ return false;
+ auto *Y = cast<MergeInputSection>(DB->Section);
+ if (X->getParent() != Y->getParent())
+ return false;
+
+ uint64_t OffsetA =
+ SA.isSection() ? X->getOffset(AddA) : X->getOffset(DA->Value) + AddA;
+ uint64_t OffsetB =
+ SB.isSection() ? Y->getOffset(AddB) : Y->getOffset(DB->Value) + AddB;
+ return OffsetA == OffsetB;
};
return RelsA.size() == RelsB.size() &&
@@ -221,42 +263,42 @@ bool ICF<ELFT>::constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
// Compare "non-moving" part of two InputSections, namely everything
// except relocation targets.
template <class ELFT>
-bool ICF<ELFT>::equalsConstant(const InputSection<ELFT> *A,
- const InputSection<ELFT> *B) {
+bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) {
if (A->NumRelocations != B->NumRelocations || A->Flags != B->Flags ||
A->getSize() != B->getSize() || A->Data != B->Data)
return false;
if (A->AreRelocsRela)
- return constantEq(A->relas(), B->relas());
- return constantEq(A->rels(), B->rels());
+ return constantEq(A, A->template relas<ELFT>(), B,
+ B->template relas<ELFT>());
+ return constantEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>());
}
// Compare two lists of relocations. Returns true if all pairs of
// relocations point to the same section in terms of ICF.
template <class ELFT>
template <class RelTy>
-bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
- const InputSection<ELFT> *B, ArrayRef<RelTy> RelsB) {
+bool ICF<ELFT>::variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB) {
auto Eq = [&](const RelTy &RA, const RelTy &RB) {
// The two sections must be identical.
- SymbolBody &SA = A->getFile()->getRelocTargetSym(RA);
- SymbolBody &SB = B->getFile()->getRelocTargetSym(RB);
+ SymbolBody &SA = A->template getFile<ELFT>()->getRelocTargetSym(RA);
+ SymbolBody &SB = B->template getFile<ELFT>()->getRelocTargetSym(RB);
if (&SA == &SB)
return true;
- // Or, the two sections must be in the same equivalence class.
- auto *DA = dyn_cast<DefinedRegular<ELFT>>(&SA);
- auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB);
- if (!DA || !DB)
- return false;
- if (DA->Value != DB->Value)
- return false;
+ auto *DA = cast<DefinedRegular>(&SA);
+ auto *DB = cast<DefinedRegular>(&SB);
- auto *X = dyn_cast<InputSection<ELFT>>(DA->Section);
- auto *Y = dyn_cast<InputSection<ELFT>>(DB->Section);
- if (!X || !Y)
- return false;
+ // We already dealt with absolute and non-InputSection symbols in
+ // constantEq, and for InputSections we have already checked everything
+ // except the equivalence class.
+ if (!DA->Section)
+ return true;
+ auto *X = dyn_cast<InputSection>(DA->Section);
+ if (!X)
+ return true;
+ auto *Y = cast<InputSection>(DB->Section);
// Ineligible sections are in the special equivalence class 0.
// They can never be the same in terms of the equivalence class.
@@ -271,11 +313,11 @@ bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
// Compare "moving" part of two InputSections, namely relocation targets.
template <class ELFT>
-bool ICF<ELFT>::equalsVariable(const InputSection<ELFT> *A,
- const InputSection<ELFT> *B) {
+bool ICF<ELFT>::equalsVariable(const InputSection *A, const InputSection *B) {
if (A->AreRelocsRela)
- return variableEq(A, A->relas(), B, B->relas());
- return variableEq(A, A->rels(), B, B->rels());
+ return variableEq(A, A->template relas<ELFT>(), B,
+ B->template relas<ELFT>());
+ return variableEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>());
}
template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
@@ -291,7 +333,7 @@ template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
// groups of sections, grouped by the class.
//
// This function calls Fn on every group that starts within [Begin, End).
-// Note that a group must starts in that range but doesn't necessarily
+// Note that a group must start in that range but doesn't necessarily
// have to end before End.
template <class ELFT>
void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
@@ -323,29 +365,30 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
// Split sections into 256 shards and call Fn in parallel.
size_t NumShards = 256;
size_t Step = Sections.size() / NumShards;
- forLoop(0, NumShards,
- [&](size_t I) { forEachClassRange(I * Step, (I + 1) * Step, Fn); });
- forEachClassRange(Step * NumShards, Sections.size(), Fn);
+ parallelForEachN(0, NumShards, [&](size_t I) {
+ size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step;
+ forEachClassRange(I * Step, End, Fn);
+ });
++Cnt;
}
// The main function of ICF.
template <class ELFT> void ICF<ELFT>::run() {
// Collect sections to merge.
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections)
- if (auto *S = dyn_cast<InputSection<ELFT>>(Sec))
+ for (InputSectionBase *Sec : InputSections)
+ if (auto *S = dyn_cast<InputSection>(Sec))
if (isEligible(S))
Sections.push_back(S);
// Initially, we use hash values to partition sections.
- for (InputSection<ELFT> *S : Sections)
+ for (InputSection *S : Sections)
// Set MSB to 1 to avoid collisions with non-hash IDs.
- S->Class[0] = getHash(S) | (1 << 31);
+ S->Class[0] = getHash<ELFT>(S) | (1 << 31);
// From now on, sections in Sections vector are ordered so that sections
// in the same equivalence class are consecutive in the vector.
std::stable_sort(Sections.begin(), Sections.end(),
- [](InputSection<ELFT> *A, InputSection<ELFT> *B) {
+ [](InputSection *A, InputSection *B) {
return A->Class[0] < B->Class[0];
});
@@ -372,6 +415,15 @@ template <class ELFT> void ICF<ELFT>::run() {
Sections[Begin]->replace(Sections[I]);
}
});
+
+ // Mark ARM Exception Index table sections that refer to folded code
+ // sections as not live. These sections have an implict dependency
+ // via the link order dependency.
+ if (Config->EMachine == EM_ARM)
+ for (InputSectionBase *Sec : InputSections)
+ if (auto *S = dyn_cast<InputSection>(Sec))
+ if (S->Flags & SHF_LINK_ORDER)
+ S->Live = S->getLinkOrderDep()->Live;
}
// ICF entry point function.
diff --git a/contrib/llvm/tools/lld/ELF/ICF.h b/contrib/llvm/tools/lld/ELF/ICF.h
index 502e128..2421985 100644
--- a/contrib/llvm/tools/lld/ELF/ICF.h
+++ b/contrib/llvm/tools/lld/ELF/ICF.h
@@ -14,6 +14,6 @@ namespace lld {
namespace elf {
template <class ELFT> void doIcf();
}
-}
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.cpp b/contrib/llvm/tools/lld/ELF/InputFiles.cpp
index f3afb1c..c609615 100644
--- a/contrib/llvm/tools/lld/ELF/InputFiles.cpp
+++ b/contrib/llvm/tools/lld/ELF/InputFiles.cpp
@@ -16,7 +16,6 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/IR/LLVMContext.h"
@@ -38,32 +37,30 @@ using namespace lld::elf;
TarWriter *elf::Tar;
+InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+
namespace {
// In ELF object file all section addresses are zero. If we have multiple
// .text sections (when using -ffunction-section or comdat group) then
// LLVM DWARF parser will not be able to parse .debug_line correctly, unless
// we assign each section some unique address. This callback method assigns
// each section an address equal to its offset in ELF object file.
-class ObjectInfo : public LoadedObjectInfo {
+class ObjectInfo : public LoadedObjectInfoHelper<ObjectInfo> {
public:
uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override {
return static_cast<const ELFSectionRef &>(Sec).getOffset();
}
- std::unique_ptr<LoadedObjectInfo> clone() const override {
- return std::unique_ptr<LoadedObjectInfo>();
- }
};
}
Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
- if (Config->Verbose)
- outs() << Path << "\n";
-
+ log(Path);
auto MBOrErr = MemoryBuffer::getFile(Path);
if (auto EC = MBOrErr.getError()) {
- error(EC, "cannot open " + Path);
+ error("cannot open " + Path + ": " + EC.message());
return None;
}
+
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
MemoryBufferRef MBRef = MB->getMemBufferRef();
make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
@@ -75,15 +72,13 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
std::unique_ptr<object::ObjectFile> Obj =
- check(object::ObjectFile::createObjectFile(this->MB),
- "createObjectFile failed");
+ check(object::ObjectFile::createObjectFile(this->MB), toString(this));
ObjectInfo ObjInfo;
DWARFContextInMemory Dwarf(*Obj, &ObjInfo);
- DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs));
- DataExtractor LineData(Dwarf.getLineSection().Data,
- ELFT::TargetEndianness == support::little,
- ELFT::Is64Bits ? 8 : 4);
+ DwarfLine.reset(new DWARFDebugLine);
+ DWARFDataExtractor LineData(Dwarf.getLineSection(), Config->IsLE,
+ Config->Wordsize);
// The second parameter is offset in .debug_line section
// for compilation unit (CU) of interest. We have only one
@@ -94,45 +89,57 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
// Returns source line information for a given offset
// using DWARF debug info.
template <class ELFT>
-std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase<ELFT> *S,
- uintX_t Offset) {
- if (!DwarfLine)
- initializeDwarfLine();
+Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S,
+ uint64_t Offset) {
+ llvm::call_once(InitDwarfLine, [this]() { initializeDwarfLine(); });
// The offset to CU is 0.
const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
if (!Tbl)
- return "";
+ return None;
// Use fake address calcuated by adding section file offset and offset in
// section. See comments for ObjectInfo class.
DILineInfo Info;
Tbl->getFileLineInfoForAddress(
- S->Offset + Offset, nullptr,
+ S->getOffsetInFile() + Offset, nullptr,
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info);
if (Info.Line == 0)
- return "";
- return Info.FileName + ":" + std::to_string(Info.Line);
+ return None;
+ return Info;
}
-// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
+// Returns source line information for a given offset
+// using DWARF debug info.
+template <class ELFT>
+std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S,
+ uint64_t Offset) {
+ if (Optional<DILineInfo> Info = getDILineInfo(S, Offset))
+ return Info->FileName + ":" + std::to_string(Info->Line);
+ return "";
+}
+
+// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
std::string lld::toString(const InputFile *F) {
if (!F)
- return "(internal)";
- if (!F->ArchiveName.empty())
- return (F->ArchiveName + "(" + F->getName() + ")").str();
- return F->getName();
-}
+ return "<internal>";
-template <class ELFT> static ELFKind getELFKind() {
- if (ELFT::TargetEndianness == support::little)
- return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
- return ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
+ if (F->ToStringCache.empty()) {
+ if (F->ArchiveName.empty())
+ F->ToStringCache = F->getName();
+ else
+ F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str();
+ }
+ return F->ToStringCache;
}
template <class ELFT>
ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) {
- EKind = getELFKind<ELFT>();
+ if (ELFT::TargetEndianness == support::little)
+ EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
+ else
+ EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
+
EMachine = getObj().getHeader()->e_machine;
OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI];
}
@@ -144,27 +151,26 @@ typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalSymbols() {
template <class ELFT>
uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
- return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX));
+ return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX),
+ toString(this));
}
template <class ELFT>
void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr *Symtab) {
FirstNonLocal = Symtab->sh_info;
- Symbols = check(getObj().symbols(Symtab));
+ Symbols = check(getObj().symbols(Symtab), toString(this));
if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size())
fatal(toString(this) + ": invalid sh_info in symbol table");
- StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections));
+ StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections),
+ toString(this));
}
template <class ELFT>
-elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
- : ELFFileBase<ELFT>(Base::ObjectKind, M) {}
-
-template <class ELFT>
-ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getNonLocalSymbols() {
- return makeArrayRef(this->SymbolBodies).slice(this->FirstNonLocal);
+elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M, StringRef ArchiveName)
+ : ELFFileBase<ELFT>(Base::ObjectKind, M) {
+ this->ArchiveName = ArchiveName;
}
template <class ELFT>
@@ -195,20 +201,35 @@ template <class ELFT>
StringRef
elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec) {
+ // Group signatures are stored as symbol names in object files.
+ // sh_info contains a symbol index, so we fetch a symbol and read its name.
if (this->Symbols.empty())
- this->initSymtab(Sections,
- check(object::getSection<ELFT>(Sections, Sec.sh_link)));
- const Elf_Sym *Sym =
- check(object::getSymbol<ELFT>(this->Symbols, Sec.sh_info));
- return check(Sym->getName(this->StringTable));
+ this->initSymtab(
+ Sections,
+ check(object::getSection<ELFT>(Sections, Sec.sh_link), toString(this)));
+
+ const Elf_Sym *Sym = check(
+ object::getSymbol<ELFT>(this->Symbols, Sec.sh_info), toString(this));
+ StringRef Signature = check(Sym->getName(this->StringTable), toString(this));
+
+ // As a special case, if a symbol is a section symbol and has no name,
+ // we use a section name as a signature.
+ //
+ // Such SHT_GROUP sections are invalid from the perspective of the ELF
+ // standard, but GNU gold 1.14 (the neweset version as of July 2017) or
+ // older produce such sections as outputs for the -r option, so we need
+ // a bug-compatibility.
+ if (Signature.empty() && Sym->getType() == STT_SECTION)
+ return getSectionName(Sec);
+ return Signature;
}
template <class ELFT>
ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word>
elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
const ELFFile<ELFT> &Obj = this->getObj();
- ArrayRef<Elf_Word> Entries =
- check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec));
+ ArrayRef<Elf_Word> Entries = check(
+ Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), toString(this));
if (Entries.empty() || Entries[0] != GRP_COMDAT)
fatal(toString(this) + ": unsupported SHT_GROUP format");
return Entries.slice(1);
@@ -242,14 +263,14 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
// the section does not hold a table of fixed-size entries". We know
// that Rust 1.13 produces a string mergeable section with a zero
// sh_entsize. Here we just accept it rather than being picky about it.
- uintX_t EntSize = Sec.sh_entsize;
+ uint64_t EntSize = Sec.sh_entsize;
if (EntSize == 0)
return false;
if (Sec.sh_size % EntSize)
fatal(toString(this) +
": SHF_MERGE section size must be a multiple of sh_entsize");
- uintX_t Flags = Sec.sh_flags;
+ uint64_t Flags = Sec.sh_flags;
if (!(Flags & SHF_MERGE))
return false;
if (Flags & SHF_WRITE)
@@ -270,76 +291,92 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
template <class ELFT>
void elf::ObjectFile<ELFT>::initializeSections(
DenseSet<CachedHashStringRef> &ComdatGroups) {
- ArrayRef<Elf_Shdr> ObjSections = check(this->getObj().sections());
const ELFFile<ELFT> &Obj = this->getObj();
+
+ ArrayRef<Elf_Shdr> ObjSections =
+ check(this->getObj().sections(), toString(this));
uint64_t Size = ObjSections.size();
- Sections.resize(Size);
- unsigned I = -1;
- StringRef SectionStringTable = check(Obj.getSectionStringTable(ObjSections));
- for (const Elf_Shdr &Sec : ObjSections) {
- ++I;
- if (Sections[I] == &InputSection<ELFT>::Discarded)
+ this->Sections.resize(Size);
+ this->SectionStringTable =
+ check(Obj.getSectionStringTable(ObjSections), toString(this));
+
+ for (size_t I = 0, E = ObjSections.size(); I < E; I++) {
+ if (this->Sections[I] == &InputSection::Discarded)
continue;
+ const Elf_Shdr &Sec = ObjSections[I];
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) {
- Sections[I] = &InputSection<ELFT>::Discarded;
+ this->Sections[I] = &InputSection::Discarded;
continue;
}
switch (Sec.sh_type) {
- case SHT_GROUP:
- Sections[I] = &InputSection<ELFT>::Discarded;
- if (ComdatGroups.insert(CachedHashStringRef(
- getShtGroupSignature(ObjSections, Sec)))
- .second)
+ case SHT_GROUP: {
+ // De-duplicate section groups by their signatures.
+ StringRef Signature = getShtGroupSignature(ObjSections, Sec);
+ bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
+ this->Sections[I] = &InputSection::Discarded;
+
+ // If it is a new section group, we want to keep group members.
+ // Group leader sections, which contain indices of group members, are
+ // discarded because they are useless beyond this point. The only
+ // exception is the -r option because in order to produce re-linkable
+ // object files, we want to pass through basically everything.
+ if (IsNew) {
+ if (Config->Relocatable)
+ this->Sections[I] = createInputSection(Sec);
continue;
+ }
+
+ // Otherwise, discard group members.
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
if (SecIndex >= Size)
- fatal(toString(this) + ": invalid section index in group: " +
- Twine(SecIndex));
- Sections[SecIndex] = &InputSection<ELFT>::Discarded;
+ fatal(toString(this) +
+ ": invalid section index in group: " + Twine(SecIndex));
+ this->Sections[SecIndex] = &InputSection::Discarded;
}
break;
+ }
case SHT_SYMTAB:
this->initSymtab(ObjSections, &Sec);
break;
case SHT_SYMTAB_SHNDX:
- this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, ObjSections));
+ this->SymtabSHNDX =
+ check(Obj.getSHNDXTable(Sec, ObjSections), toString(this));
break;
case SHT_STRTAB:
case SHT_NULL:
break;
default:
- Sections[I] = createInputSection(Sec, SectionStringTable);
+ this->Sections[I] = createInputSection(Sec);
}
// .ARM.exidx sections have a reverse dependency on the InputSection they
// have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
if (Sec.sh_flags & SHF_LINK_ORDER) {
- if (Sec.sh_link >= Sections.size())
+ if (Sec.sh_link >= this->Sections.size())
fatal(toString(this) + ": invalid sh_link index: " +
Twine(Sec.sh_link));
- auto *IS = cast<InputSection<ELFT>>(Sections[Sec.sh_link]);
- IS->DependentSection = Sections[I];
+ this->Sections[Sec.sh_link]->DependentSections.push_back(
+ this->Sections[I]);
}
}
}
template <class ELFT>
-InputSectionBase<ELFT> *
-elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
+InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
uint32_t Idx = Sec.sh_info;
- if (Idx >= Sections.size())
+ if (Idx >= this->Sections.size())
fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx));
- InputSectionBase<ELFT> *Target = Sections[Idx];
+ InputSectionBase *Target = this->Sections[Idx];
// Strictly speaking, a relocation section must be included in the
// group of the section it relocates. However, LLVM 3.3 and earlier
// would fail to do so, so we gracefully handle that case.
- if (Target == &InputSection<ELFT>::Discarded)
+ if (Target == &InputSection::Discarded)
return nullptr;
if (!Target)
@@ -347,12 +384,19 @@ elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
return Target;
}
+// Create a regular InputSection class that has the same contents
+// as a given section.
+InputSectionBase *toRegularSection(MergeInputSection *Sec) {
+ auto *Ret = make<InputSection>(Sec->Flags, Sec->Type, Sec->Alignment,
+ Sec->Data, Sec->Name);
+ Ret->File = Sec->File;
+ return Ret;
+}
+
template <class ELFT>
-InputSectionBase<ELFT> *
-elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
- StringRef SectionStringTable) {
- StringRef Name =
- check(this->getObj().getSectionName(&Sec, SectionStringTable));
+InputSectionBase *
+elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
+ StringRef Name = getSectionName(Sec);
switch (Sec.sh_type) {
case SHT_ARM_ATTRIBUTES:
@@ -360,63 +404,110 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
// we see. The eglibc ARM dynamic loaders require the presence of an
// attribute section for dlopen to work.
// In a full implementation we would merge all attribute sections.
- if (In<ELFT>::ARMAttributes == nullptr) {
- In<ELFT>::ARMAttributes = make<InputSection<ELFT>>(this, &Sec, Name);
- return In<ELFT>::ARMAttributes;
+ if (InX::ARMAttributes == nullptr) {
+ InX::ARMAttributes = make<InputSection>(this, &Sec, Name);
+ return InX::ARMAttributes;
}
- return &InputSection<ELFT>::Discarded;
+ return &InputSection::Discarded;
case SHT_RELA:
case SHT_REL: {
+ // Find the relocation target section and associate this
+ // section with it. Target can be discarded, for example
+ // if it is a duplicated member of SHT_GROUP section, we
+ // do not create or proccess relocatable sections then.
+ InputSectionBase *Target = getRelocTarget(Sec);
+ if (!Target)
+ return nullptr;
+
// This section contains relocation information.
// If -r is given, we do not interpret or apply relocation
// but just copy relocation sections to output.
if (Config->Relocatable)
- return make<InputSection<ELFT>>(this, &Sec, Name);
+ return make<InputSection>(this, &Sec, Name);
- // Find the relocation target section and associate this
- // section with it.
- InputSectionBase<ELFT> *Target = getRelocTarget(Sec);
- if (!Target)
- return nullptr;
if (Target->FirstRelocation)
fatal(toString(this) +
": multiple relocation sections to one section are not supported");
- if (!isa<InputSection<ELFT>>(Target) && !isa<EhInputSection<ELFT>>(Target))
- fatal(toString(this) +
- ": relocations pointing to SHF_MERGE are not supported");
+
+ // Mergeable sections with relocations are tricky because relocations
+ // need to be taken into account when comparing section contents for
+ // merging. It's not worth supporting such mergeable sections because
+ // they are rare and it'd complicates the internal design (we usually
+ // have to determine if two sections are mergeable early in the link
+ // process much before applying relocations). We simply handle mergeable
+ // sections with relocations as non-mergeable.
+ if (auto *MS = dyn_cast<MergeInputSection>(Target)) {
+ Target = toRegularSection(MS);
+ this->Sections[Sec.sh_info] = Target;
+ }
size_t NumRelocations;
if (Sec.sh_type == SHT_RELA) {
- ArrayRef<Elf_Rela> Rels = check(this->getObj().relas(&Sec));
+ ArrayRef<Elf_Rela> Rels =
+ check(this->getObj().relas(&Sec), toString(this));
Target->FirstRelocation = Rels.begin();
NumRelocations = Rels.size();
Target->AreRelocsRela = true;
} else {
- ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec));
+ ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec), toString(this));
Target->FirstRelocation = Rels.begin();
NumRelocations = Rels.size();
Target->AreRelocsRela = false;
}
assert(isUInt<31>(NumRelocations));
Target->NumRelocations = NumRelocations;
+
+ // Relocation sections processed by the linker are usually removed
+ // from the output, so returning `nullptr` for the normal case.
+ // However, if -emit-relocs is given, we need to leave them in the output.
+ // (Some post link analysis tools need this information.)
+ if (Config->EmitRelocs) {
+ InputSection *RelocSec = make<InputSection>(this, &Sec, Name);
+ // We will not emit relocation section if target was discarded.
+ Target->DependentSections.push_back(RelocSec);
+ return RelocSec;
+ }
return nullptr;
}
}
- // .note.GNU-stack is a marker section to control the presence of
- // PT_GNU_STACK segment in outputs. Since the presence of the segment
- // is controlled only by the command line option (-z execstack) in LLD,
- // .note.GNU-stack is ignored.
+ // The GNU linker uses .note.GNU-stack section as a marker indicating
+ // that the code in the object file does not expect that the stack is
+ // executable (in terms of NX bit). If all input files have the marker,
+ // the GNU linker adds a PT_GNU_STACK segment to tells the loader to
+ // make the stack non-executable. Most object files have this section as
+ // of 2017.
+ //
+ // But making the stack non-executable is a norm today for security
+ // reasons. Failure to do so may result in a serious security issue.
+ // Therefore, we make LLD always add PT_GNU_STACK unless it is
+ // explicitly told to do otherwise (by -z execstack). Because the stack
+ // executable-ness is controlled solely by command line options,
+ // .note.GNU-stack sections are simply ignored.
if (Name == ".note.GNU-stack")
- return &InputSection<ELFT>::Discarded;
+ return &InputSection::Discarded;
+ // Split stacks is a feature to support a discontiguous stack. At least
+ // as of 2017, it seems that the feature is not being used widely.
+ // Only GNU gold supports that. We don't. For the details about that,
+ // see https://gcc.gnu.org/wiki/SplitStacks
if (Name == ".note.GNU-split-stack") {
- error("objects using splitstacks are not supported");
- return &InputSection<ELFT>::Discarded;
+ error(toString(this) +
+ ": object file compiled with -fsplit-stack is not supported");
+ return &InputSection::Discarded;
}
if (Config->Strip != StripPolicy::None && Name.startswith(".debug"))
- return &InputSection<ELFT>::Discarded;
+ return &InputSection::Discarded;
+
+ // If -gdb-index is given, LLD creates .gdb_index section, and that
+ // section serves the same purpose as .debug_gnu_pub{names,types} sections.
+ // If that's the case, we want to eliminate .debug_gnu_pub{names,types}
+ // because they are redundant and can waste large amount of disk space
+ // (for example, they are about 400 MiB in total for a clang debug build.)
+ if (Config->GdbIndex &&
+ (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes"))
+ return &InputSection::Discarded;
// The linkonce feature is a sort of proto-comdat. Some glibc i386 object
// files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce
@@ -424,17 +515,23 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
// FIXME: This is glibc PR20543, we should remove this hack once that has been
// fixed for a while.
if (Name.startswith(".gnu.linkonce."))
- return &InputSection<ELFT>::Discarded;
+ return &InputSection::Discarded;
// The linker merges EH (exception handling) frames and creates a
// .eh_frame_hdr section for runtime. So we handle them with a special
// class. For relocatable outputs, they are just passed through.
if (Name == ".eh_frame" && !Config->Relocatable)
- return make<EhInputSection<ELFT>>(this, &Sec, Name);
+ return make<EhInputSection>(this, &Sec, Name);
if (shouldMerge(Sec))
- return make<MergeInputSection<ELFT>>(this, &Sec, Name);
- return make<InputSection<ELFT>>(this, &Sec, Name);
+ return make<MergeInputSection>(this, &Sec, Name);
+ return make<InputSection>(this, &Sec, Name);
+}
+
+template <class ELFT>
+StringRef elf::ObjectFile<ELFT>::getSectionName(const Elf_Shdr &Sec) {
+ return check(this->getObj().getSectionName(&Sec, SectionStringTable),
+ toString(this));
}
template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
@@ -444,12 +541,11 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
}
template <class ELFT>
-InputSectionBase<ELFT> *
-elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
+InputSectionBase *elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
uint32_t Index = this->getSectionIndex(Sym);
- if (Index >= Sections.size())
+ if (Index >= this->Sections.size())
fatal(toString(this) + ": invalid section index: " + Twine(Index));
- InputSectionBase<ELFT> *S = Sections[Index];
+ InputSectionBase *S = this->Sections[Index];
// We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could
// generate broken objects. STT_SECTION/STT_NOTYPE symbols can be
@@ -463,7 +559,7 @@ elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
fatal(toString(this) + ": invalid section index: " + Twine(Index));
}
- if (S == &InputSection<ELFT>::Discarded)
+ if (S == &InputSection::Discarded)
return S;
return S->Repl;
}
@@ -471,30 +567,29 @@ elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
template <class ELFT>
SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
int Binding = Sym->getBinding();
- InputSectionBase<ELFT> *Sec = getSection(*Sym);
+ InputSectionBase *Sec = getSection(*Sym);
uint8_t StOther = Sym->st_other;
uint8_t Type = Sym->getType();
- uintX_t Value = Sym->st_value;
- uintX_t Size = Sym->st_size;
+ uint64_t Value = Sym->st_value;
+ uint64_t Size = Sym->st_size;
if (Binding == STB_LOCAL) {
if (Sym->getType() == STT_FILE)
- SourceFile = check(Sym->getName(this->StringTable));
+ SourceFile = check(Sym->getName(this->StringTable), toString(this));
if (this->StringTable.size() <= Sym->st_name)
fatal(toString(this) + ": invalid symbol name offset");
StringRefZ Name = this->StringTable.data() + Sym->st_name;
if (Sym->st_shndx == SHN_UNDEF)
- return new (BAlloc)
- Undefined<ELFT>(Name, /*IsLocal=*/true, StOther, Type, this);
+ return make<Undefined>(Name, /*IsLocal=*/true, StOther, Type, this);
- return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther,
- Type, Value, Size, Sec, this);
+ return make<DefinedRegular>(Name, /*IsLocal=*/true, StOther, Type, Value,
+ Size, Sec, this);
}
- StringRef Name = check(Sym->getName(this->StringTable));
+ StringRef Name = check(Sym->getName(this->StringTable), toString(this));
switch (Sym->st_shndx) {
case SHN_UNDEF:
@@ -517,7 +612,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
case STB_GLOBAL:
case STB_WEAK:
case STB_GNU_UNIQUE:
- if (Sec == &InputSection<ELFT>::Discarded)
+ if (Sec == &InputSection::Discarded)
return elf::Symtab<ELFT>::X
->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type,
/*CanOmitFromDynSym=*/false, this)
@@ -528,55 +623,62 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
}
}
-template <class ELFT> void ArchiveFile::parse() {
- File = check(Archive::create(MB),
- MB.getBufferIdentifier() + ": failed to parse archive");
+ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File)
+ : InputFile(ArchiveKind, File->getMemoryBufferRef()),
+ File(std::move(File)) {}
- // Read the symbol table to construct Lazy objects.
+template <class ELFT> void ArchiveFile::parse() {
+ Symbols.reserve(File->getNumberOfSymbols());
for (const Archive::Symbol &Sym : File->symbols())
- Symtab<ELFT>::X->addLazyArchive(this, Sym);
+ Symbols.push_back(Symtab<ELFT>::X->addLazyArchive(this, Sym));
}
// Returns a buffer pointing to a member file containing a given symbol.
std::pair<MemoryBufferRef, uint64_t>
ArchiveFile::getMember(const Archive::Symbol *Sym) {
Archive::Child C =
- check(Sym->getMember(),
- "could not get the member for symbol " + Sym->getName());
+ check(Sym->getMember(), toString(this) +
+ ": could not get the member for symbol " +
+ Sym->getName());
if (!Seen.insert(C.getChildOffset()).second)
return {MemoryBufferRef(), 0};
MemoryBufferRef Ret =
check(C.getMemoryBufferRef(),
- "could not get the buffer for the member defining symbol " +
+ toString(this) +
+ ": could not get the buffer for the member defining symbol " +
Sym->getName());
if (C.getParent()->isThin() && Tar)
- Tar->append(relativeToRoot(check(C.getFullName())), Ret.getBuffer());
+ Tar->append(relativeToRoot(check(C.getFullName(), toString(this))),
+ Ret.getBuffer());
if (C.getParent()->isThin())
return {Ret, 0};
return {Ret, C.getChildOffset()};
}
template <class ELFT>
-SharedFile<ELFT>::SharedFile(MemoryBufferRef M)
- : ELFFileBase<ELFT>(Base::SharedKind, M), AsNeeded(Config->AsNeeded) {}
+SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName)
+ : ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName),
+ AsNeeded(Config->AsNeeded) {}
template <class ELFT>
const typename ELFT::Shdr *
SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
return check(
- this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX));
+ this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX),
+ toString(this));
}
// Partially parse the shared object file so that we can call
// getSoName on this object.
template <class ELFT> void SharedFile<ELFT>::parseSoName() {
const Elf_Shdr *DynamicSec = nullptr;
-
const ELFFile<ELFT> Obj = this->getObj();
- ArrayRef<Elf_Shdr> Sections = check(Obj.sections());
+ ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
+
+ // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d.
for (const Elf_Shdr &Sec : Sections) {
switch (Sec.sh_type) {
default:
@@ -588,7 +690,8 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
DynamicSec = &Sec;
break;
case SHT_SYMTAB_SHNDX:
- this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, Sections));
+ this->SymtabSHNDX =
+ check(Obj.getSHNDXTable(Sec, Sections), toString(this));
break;
case SHT_GNU_versym:
this->VersymSec = &Sec;
@@ -602,23 +705,18 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
if (this->VersymSec && this->Symbols.empty())
error("SHT_GNU_versym should be associated with symbol table");
- // DSOs are identified by soname, and they usually contain
- // DT_SONAME tag in their header. But if they are missing,
- // filenames are used as default sonames.
- SoName = sys::path::filename(this->getName());
-
+ // Search for a DT_SONAME tag to initialize this->SoName.
if (!DynamicSec)
return;
-
ArrayRef<Elf_Dyn> Arr =
check(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec),
- toString(this) + ": getSectionContentsAsArray failed");
+ toString(this));
for (const Elf_Dyn &Dyn : Arr) {
if (Dyn.d_tag == DT_SONAME) {
- uintX_t Val = Dyn.getVal();
+ uint64_t Val = Dyn.getVal();
if (Val >= this->StringTable.size())
fatal(toString(this) + ": invalid DT_SONAME entry");
- SoName = StringRef(this->StringTable.data() + Val);
+ SoName = this->StringTable.data() + Val;
return;
}
}
@@ -681,7 +779,7 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
bool Hidden = VersymIndex & VERSYM_HIDDEN;
VersymIndex = VersymIndex & ~VERSYM_HIDDEN;
- StringRef Name = check(Sym.getName(this->StringTable));
+ StringRef Name = check(Sym.getName(this->StringTable), toString(this));
if (Sym.isUndefined()) {
Undefs.push_back(Name);
continue;
@@ -701,26 +799,27 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
// with explicit versions.
if (V) {
StringRef VerName = this->StringTable.data() + V->getAux()->vda_name;
- Name = Saver.save(Twine(Name) + "@" + VerName);
+ Name = Saver.save(Name + "@" + VerName);
elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V);
}
}
}
-static ELFKind getBitcodeELFKind(MemoryBufferRef MB) {
- Triple T(check(getBitcodeTargetTriple(MB)));
+static ELFKind getBitcodeELFKind(const Triple &T) {
if (T.isLittleEndian())
return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind;
return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind;
}
-static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) {
- Triple T(check(getBitcodeTargetTriple(MB)));
+static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
switch (T.getArch()) {
case Triple::aarch64:
return EM_AARCH64;
case Triple::arm:
+ case Triple::thumb:
return EM_ARM;
+ case Triple::avr:
+ return EM_AVR;
case Triple::mips:
case Triple::mipsel:
case Triple::mips64:
@@ -735,14 +834,32 @@ static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) {
case Triple::x86_64:
return EM_X86_64;
default:
- fatal(MB.getBufferIdentifier() +
- ": could not infer e_machine from bitcode target triple " + T.str());
+ fatal(Path + ": could not infer e_machine from bitcode target triple " +
+ T.str());
}
}
-BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) {
- EKind = getBitcodeELFKind(MB);
- EMachine = getBitcodeMachineKind(MB);
+BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
+ uint64_t OffsetInArchive)
+ : InputFile(BitcodeKind, MB) {
+ this->ArchiveName = ArchiveName;
+
+ // Here we pass a new MemoryBufferRef which is identified by ArchiveName
+ // (the fully resolved path of the archive) + member name + offset of the
+ // member in the archive.
+ // ThinLTO uses the MemoryBufferRef identifier to access its internal
+ // data structures and if two archives define two members with the same name,
+ // this causes a collision which result in only one of the objects being
+ // taken into consideration at LTO time (which very likely causes undefined
+ // symbols later in the link stage).
+ MemoryBufferRef MBRef(MB.getBuffer(),
+ Saver.save(ArchiveName + MB.getBufferIdentifier() +
+ utostr(OffsetInArchive)));
+ Obj = check(lto::InputFile::create(MBRef), toString(this));
+
+ Triple T(Obj->getTargetTriple());
+ EKind = getBitcodeELFKind(T);
+ EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T);
}
static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
@@ -762,25 +879,24 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
const lto::InputFile::Symbol &ObjSym,
BitcodeFile *F) {
StringRef NameRef = Saver.save(ObjSym.getName());
- uint32_t Flags = ObjSym.getFlags();
- uint32_t Binding = (Flags & BasicSymbolRef::SF_Weak) ? STB_WEAK : STB_GLOBAL;
+ uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL;
uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
uint8_t Visibility = mapVisibility(ObjSym.getVisibility());
bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable();
- int C = check(ObjSym.getComdatIndex());
+ int C = ObjSym.getComdatIndex();
if (C != -1 && !KeptComdats[C])
return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
Visibility, Type, CanOmitFromDynSym,
F);
- if (Flags & BasicSymbolRef::SF_Undefined)
+ if (ObjSym.isUndefined())
return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
Visibility, Type, CanOmitFromDynSym,
F);
- if (Flags & BasicSymbolRef::SF_Common)
+ if (ObjSym.isCommon())
return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(),
ObjSym.getCommonAlignment(), Binding,
Visibility, STT_OBJECT, F);
@@ -791,84 +907,58 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
template <class ELFT>
void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
-
- // Here we pass a new MemoryBufferRef which is identified by ArchiveName
- // (the fully resolved path of the archive) + member name + offset of the
- // member in the archive.
- // ThinLTO uses the MemoryBufferRef identifier to access its internal
- // data structures and if two archives define two members with the same name,
- // this causes a collision which result in only one of the objects being
- // taken into consideration at LTO time (which very likely causes undefined
- // symbols later in the link stage).
- Obj = check(lto::InputFile::create(MemoryBufferRef(
- MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() +
- utostr(OffsetInArchive)))));
-
std::vector<bool> KeptComdats;
- for (StringRef S : Obj->getComdatTable()) {
- StringRef N = Saver.save(S);
- KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(N)).second);
- }
+ for (StringRef S : Obj->getComdatTable())
+ KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second);
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this));
}
-template <template <class> class T>
-static InputFile *createELFFile(MemoryBufferRef MB) {
+static ELFKind getELFKind(MemoryBufferRef MB) {
unsigned char Size;
unsigned char Endian;
std::tie(Size, Endian) = getElfArchType(MB.getBuffer());
+
if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB)
fatal(MB.getBufferIdentifier() + ": invalid data encoding");
+ if (Size != ELFCLASS32 && Size != ELFCLASS64)
+ fatal(MB.getBufferIdentifier() + ": invalid file class");
size_t BufSize = MB.getBuffer().size();
if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) ||
(Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr)))
fatal(MB.getBufferIdentifier() + ": file is too short");
- InputFile *Obj;
- if (Size == ELFCLASS32 && Endian == ELFDATA2LSB)
- Obj = make<T<ELF32LE>>(MB);
- else if (Size == ELFCLASS32 && Endian == ELFDATA2MSB)
- Obj = make<T<ELF32BE>>(MB);
- else if (Size == ELFCLASS64 && Endian == ELFDATA2LSB)
- Obj = make<T<ELF64LE>>(MB);
- else if (Size == ELFCLASS64 && Endian == ELFDATA2MSB)
- Obj = make<T<ELF64BE>>(MB);
- else
- fatal(MB.getBufferIdentifier() + ": invalid file class");
-
- if (!Config->FirstElf)
- Config->FirstElf = Obj;
- return Obj;
+ if (Size == ELFCLASS32)
+ return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind;
+ return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind;
}
template <class ELFT> void BinaryFile::parse() {
- StringRef Buf = MB.getBuffer();
- ArrayRef<uint8_t> Data =
- makeArrayRef<uint8_t>((const uint8_t *)Buf.data(), Buf.size());
-
- std::string Filename = MB.getBufferIdentifier();
- std::transform(Filename.begin(), Filename.end(), Filename.begin(),
- [](char C) { return isalnum(C) ? C : '_'; });
- Filename = "_binary_" + Filename;
- StringRef StartName = Saver.save(Twine(Filename) + "_start");
- StringRef EndName = Saver.save(Twine(Filename) + "_end");
- StringRef SizeName = Saver.save(Twine(Filename) + "_size");
-
- auto *Section = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- 8, Data, ".data");
+ ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer());
+ auto *Section =
+ make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data");
Sections.push_back(Section);
- elf::Symtab<ELFT>::X->addRegular(StartName, STV_DEFAULT, STT_OBJECT, 0, 0,
- STB_GLOBAL, Section, nullptr);
- elf::Symtab<ELFT>::X->addRegular(EndName, STV_DEFAULT, STT_OBJECT,
- Data.size(), 0, STB_GLOBAL, Section,
- nullptr);
- elf::Symtab<ELFT>::X->addRegular(SizeName, STV_DEFAULT, STT_OBJECT,
- Data.size(), 0, STB_GLOBAL, nullptr,
+ // For each input file foo that is embedded to a result as a binary
+ // blob, we define _binary_foo_{start,end,size} symbols, so that
+ // user programs can access blobs by name. Non-alphanumeric
+ // characters in a filename are replaced with underscore.
+ std::string S = "_binary_" + MB.getBufferIdentifier().str();
+ for (size_t I = 0; I < S.size(); ++I)
+ if (!isalnum(S[I]))
+ S[I] = '_';
+
+ elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_start"), STV_DEFAULT,
+ STT_OBJECT, 0, 0, STB_GLOBAL, Section,
nullptr);
+ elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_end"), STV_DEFAULT,
+ STT_OBJECT, Data.size(), 0, STB_GLOBAL,
+ Section, nullptr);
+ elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_size"), STV_DEFAULT,
+ STT_OBJECT, Data.size(), 0, STB_GLOBAL,
+ nullptr, nullptr);
}
static bool isBitcode(MemoryBufferRef MB) {
@@ -878,15 +968,36 @@ static bool isBitcode(MemoryBufferRef MB) {
InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
uint64_t OffsetInArchive) {
- InputFile *F =
- isBitcode(MB) ? make<BitcodeFile>(MB) : createELFFile<ObjectFile>(MB);
- F->ArchiveName = ArchiveName;
- F->OffsetInArchive = OffsetInArchive;
- return F;
+ if (isBitcode(MB))
+ return make<BitcodeFile>(MB, ArchiveName, OffsetInArchive);
+
+ switch (getELFKind(MB)) {
+ case ELF32LEKind:
+ return make<ObjectFile<ELF32LE>>(MB, ArchiveName);
+ case ELF32BEKind:
+ return make<ObjectFile<ELF32BE>>(MB, ArchiveName);
+ case ELF64LEKind:
+ return make<ObjectFile<ELF64LE>>(MB, ArchiveName);
+ case ELF64BEKind:
+ return make<ObjectFile<ELF64BE>>(MB, ArchiveName);
+ default:
+ llvm_unreachable("getELFKind");
+ }
}
-InputFile *elf::createSharedFile(MemoryBufferRef MB) {
- return createELFFile<SharedFile>(MB);
+InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) {
+ switch (getELFKind(MB)) {
+ case ELF32LEKind:
+ return make<SharedFile<ELF32LE>>(MB, DefaultSoName);
+ case ELF32BEKind:
+ return make<SharedFile<ELF32BE>>(MB, DefaultSoName);
+ case ELF64LEKind:
+ return make<SharedFile<ELF64LE>>(MB, DefaultSoName);
+ case ELF64BEKind:
+ return make<SharedFile<ELF64BE>>(MB, DefaultSoName);
+ default:
+ llvm_unreachable("getELFKind");
+ }
}
MemoryBufferRef LazyObjectFile::getBuffer() {
@@ -896,6 +1007,13 @@ MemoryBufferRef LazyObjectFile::getBuffer() {
return MB;
}
+InputFile *LazyObjectFile::fetch() {
+ MemoryBufferRef MBRef = getBuffer();
+ if (MBRef.getBuffer().empty())
+ return nullptr;
+ return createObjectFile(MBRef, ArchiveName, OffsetInArchive);
+}
+
template <class ELFT> void LazyObjectFile::parse() {
for (StringRef Sym : getSymbols())
Symtab<ELFT>::X->addLazyObject(Sym, *this);
@@ -907,27 +1025,31 @@ template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
typedef typename ELFT::SymRange Elf_Sym_Range;
const ELFFile<ELFT> Obj(this->MB.getBuffer());
- ArrayRef<Elf_Shdr> Sections = check(Obj.sections());
+ ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
for (const Elf_Shdr &Sec : Sections) {
if (Sec.sh_type != SHT_SYMTAB)
continue;
- Elf_Sym_Range Syms = check(Obj.symbols(&Sec));
+
+ Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this));
uint32_t FirstNonLocal = Sec.sh_info;
- StringRef StringTable = check(Obj.getStringTableForSymtab(Sec, Sections));
+ StringRef StringTable =
+ check(Obj.getStringTableForSymtab(Sec, Sections), toString(this));
std::vector<StringRef> V;
+
for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
if (Sym.st_shndx != SHN_UNDEF)
- V.push_back(check(Sym.getName(StringTable)));
+ V.push_back(check(Sym.getName(StringTable), toString(this)));
return V;
}
return {};
}
std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
- std::unique_ptr<lto::InputFile> Obj = check(lto::InputFile::create(this->MB));
+ std::unique_ptr<lto::InputFile> Obj =
+ check(lto::InputFile::create(this->MB), toString(this));
std::vector<StringRef> V;
for (const lto::InputFile::Symbol &Sym : Obj->symbols())
- if (!(Sym.getFlags() & BasicSymbolRef::SF_Undefined))
+ if (!Sym.isUndefined())
V.push_back(Saver.save(Sym.getName()));
return V;
}
@@ -937,17 +1059,18 @@ std::vector<StringRef> LazyObjectFile::getSymbols() {
if (isBitcode(this->MB))
return getBitcodeSymbols();
- unsigned char Size;
- unsigned char Endian;
- std::tie(Size, Endian) = getElfArchType(this->MB.getBuffer());
- if (Size == ELFCLASS32) {
- if (Endian == ELFDATA2LSB)
- return getElfSymbols<ELF32LE>();
+ switch (getELFKind(this->MB)) {
+ case ELF32LEKind:
+ return getElfSymbols<ELF32LE>();
+ case ELF32BEKind:
return getElfSymbols<ELF32BE>();
- }
- if (Endian == ELFDATA2LSB)
+ case ELF64LEKind:
return getElfSymbols<ELF64LE>();
- return getElfSymbols<ELF64BE>();
+ case ELF64BEKind:
+ return getElfSymbols<ELF64BE>();
+ default:
+ llvm_unreachable("getELFKind");
+ }
}
template void ArchiveFile::parse<ELF32LE>();
diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.h b/contrib/llvm/tools/lld/ELF/InputFiles.h
index 9588806..006218b 100644
--- a/contrib/llvm/tools/lld/ELF/InputFiles.h
+++ b/contrib/llvm/tools/lld/ELF/InputFiles.h
@@ -11,8 +11,8 @@
#define LLD_ELF_INPUT_FILES_H
#include "Config.h"
-#include "InputSection.h"
#include "Error.h"
+#include "InputSection.h"
#include "Symbols.h"
#include "lld/Core/LLVM.h"
@@ -24,16 +24,18 @@
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/Threading.h"
#include <map>
namespace llvm {
class DWARFDebugLine;
class TarWriter;
+struct DILineInfo;
namespace lto {
class InputFile;
}
-}
+} // namespace llvm
namespace lld {
namespace elf {
@@ -74,25 +76,30 @@ public:
StringRef getName() const { return MB.getBufferIdentifier(); }
MemoryBufferRef MB;
+ // Returns sections. It is a runtime error to call this function
+ // on files that don't have the notion of sections.
+ ArrayRef<InputSectionBase *> getSections() const {
+ assert(FileKind == ObjectKind || FileKind == BinaryKind);
+ return Sections;
+ }
+
// Filename of .a which contained this file. If this file was
// not in an archive file, it is the empty string. We use this
// string for creating error messages.
StringRef ArchiveName;
- // If this file is in an archive, the member contains the offset of
- // the file in the archive. Otherwise, it's just zero. We store this
- // field so that we can pass it to lib/LTO in order to disambiguate
- // between objects.
- uint64_t OffsetInArchive;
-
// If this is an architecture-specific file, the following members
// have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
ELFKind EKind = ELFNoneKind;
uint16_t EMachine = llvm::ELF::EM_NONE;
uint8_t OSABI = 0;
+ // Cache for toString(). Only toString() should use this member.
+ mutable std::string ToStringCache;
+
protected:
- InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+ InputFile(Kind K, MemoryBufferRef M);
+ std::vector<InputSectionBase *> Sections;
private:
const Kind FileKind;
@@ -136,9 +143,7 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::Word Elf_Word;
- typedef typename ELFT::uint uintX_t;
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec);
@@ -151,13 +156,11 @@ public:
ArrayRef<SymbolBody *> getSymbols();
ArrayRef<SymbolBody *> getLocalSymbols();
- ArrayRef<SymbolBody *> getNonLocalSymbols();
- explicit ObjectFile(MemoryBufferRef M);
+ ObjectFile(MemoryBufferRef M, StringRef ArchiveName);
void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
- ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
- InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
+ InputSectionBase *getSection(const Elf_Sym &Sym) const;
SymbolBody &getSymbolBody(uint32_t SymbolIndex) const {
if (SymbolIndex >= SymbolBodies.size())
@@ -167,13 +170,14 @@ public:
template <typename RelT>
SymbolBody &getRelocTargetSym(const RelT &Rel) const {
- uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL);
+ uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
return getSymbolBody(SymIndex);
}
// Returns source line information for a given offset.
// If no information is available, returns "".
- std::string getLineInfo(InputSectionBase<ELFT> *S, uintX_t Offset);
+ std::string getLineInfo(InputSectionBase *S, uint64_t Offset);
+ llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
// MIPS GP0 value defined by this file. This value represents the gp value
// used to create the relocatable object and required to support
@@ -190,24 +194,25 @@ private:
initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
void initializeSymbols();
void initializeDwarfLine();
- InputSectionBase<ELFT> *getRelocTarget(const Elf_Shdr &Sec);
- InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec,
- StringRef SectionStringTable);
+ InputSectionBase *getRelocTarget(const Elf_Shdr &Sec);
+ InputSectionBase *createInputSection(const Elf_Shdr &Sec);
+ StringRef getSectionName(const Elf_Shdr &Sec);
bool shouldMerge(const Elf_Shdr &Sec);
SymbolBody *createSymbolBody(const Elf_Sym *Sym);
- // List of all sections defined by this file.
- std::vector<InputSectionBase<ELFT> *> Sections;
-
// List of all symbols referenced or defined by this file.
std::vector<SymbolBody *> SymbolBodies;
+ // .shstrtab contents.
+ StringRef SectionStringTable;
+
// Debugging information to retrieve source file and line for error
// reporting. Linker may find reasonable number of errors in a
// single object file, so we cache debugging information in order to
// parse it only once for each object file we link.
std::unique_ptr<llvm::DWARFDebugLine> DwarfLine;
+ llvm::once_flag InitDwarfLine;
};
// LazyObjectFile is analogous to ArchiveFile in the sense that
@@ -219,7 +224,11 @@ private:
// archive file semantics.
class LazyObjectFile : public InputFile {
public:
- explicit LazyObjectFile(MemoryBufferRef M) : InputFile(LazyObjectKind, M) {}
+ LazyObjectFile(MemoryBufferRef M, StringRef ArchiveName,
+ uint64_t OffsetInArchive)
+ : InputFile(LazyObjectKind, M), OffsetInArchive(OffsetInArchive) {
+ this->ArchiveName = ArchiveName;
+ }
static bool classof(const InputFile *F) {
return F->kind() == LazyObjectKind;
@@ -227,6 +236,7 @@ public:
template <class ELFT> void parse();
MemoryBufferRef getBuffer();
+ InputFile *fetch();
private:
std::vector<StringRef> getSymbols();
@@ -234,14 +244,16 @@ private:
std::vector<StringRef> getBitcodeSymbols();
bool Seen = false;
+ uint64_t OffsetInArchive;
};
// An ArchiveFile object represents a .a file.
class ArchiveFile : public InputFile {
public:
- explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
+ explicit ArchiveFile(std::unique_ptr<Archive> &&File);
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
template <class ELFT> void parse();
+ ArrayRef<Symbol *> getSymbols() { return Symbols; }
// Returns a memory buffer for a given symbol and the offset in the archive
// for the member. An empty memory buffer and an offset of zero
@@ -252,11 +264,13 @@ public:
private:
std::unique_ptr<Archive> File;
llvm::DenseSet<uint64_t> Seen;
+ std::vector<Symbol *> Symbols;
};
class BitcodeFile : public InputFile {
public:
- explicit BitcodeFile(MemoryBufferRef M);
+ BitcodeFile(MemoryBufferRef M, StringRef ArchiveName,
+ uint64_t OffsetInArchive);
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
template <class ELFT>
void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
@@ -276,16 +290,14 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Versym Elf_Versym;
- typedef typename ELFT::Word Elf_Word;
- typedef typename ELFT::uint uintX_t;
std::vector<StringRef> Undefs;
- StringRef SoName;
const Elf_Shdr *VersymSec = nullptr;
const Elf_Shdr *VerdefSec = nullptr;
public:
- StringRef getSoName() const { return SoName; }
+ std::string SoName;
+
const Elf_Shdr *getSection(const Elf_Sym &Sym) const;
llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; }
@@ -293,7 +305,7 @@ public:
return F->kind() == Base::SharedKind;
}
- explicit SharedFile(MemoryBufferRef M);
+ SharedFile(MemoryBufferRef M, StringRef DefaultSoName);
void parseSoName();
void parseRest();
@@ -322,15 +334,11 @@ public:
explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == BinaryKind; }
template <class ELFT> void parse();
- ArrayRef<InputSectionData *> getSections() const { return Sections; }
-
-private:
- std::vector<InputSectionData *> Sections;
};
InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "",
uint64_t OffsetInArchive = 0);
-InputFile *createSharedFile(MemoryBufferRef MB);
+InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName);
} // namespace elf
} // namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.cpp b/contrib/llvm/tools/lld/ELF/InputSection.cpp
index e6e86d5..c6a539b 100644
--- a/contrib/llvm/tools/lld/ELF/InputSection.cpp
+++ b/contrib/llvm/tools/lld/ELF/InputSection.cpp
@@ -20,8 +20,11 @@
#include "Target.h"
#include "Thunks.h"
#include "llvm/Object/Decompressor.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Threading.h"
#include <mutex>
using namespace llvm;
@@ -29,17 +32,16 @@ using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
+using namespace llvm::sys;
using namespace lld;
using namespace lld::elf;
+std::vector<InputSectionBase *> elf::InputSections;
+
// Returns a string to construct an error message.
-template <class ELFT>
-std::string lld::toString(const InputSectionBase<ELFT> *Sec) {
- // File can be absent if section is synthetic.
- std::string FileName =
- Sec->getFile() ? Sec->getFile()->getName() : "<internal>";
- return (FileName + ":(" + Sec->Name + ")").str();
+std::string lld::toString(const InputSectionBase *Sec) {
+ return (toString(Sec->File) + ":(" + Sec->Name + ")").str();
}
template <class ELFT>
@@ -50,91 +52,131 @@ static ArrayRef<uint8_t> getSectionContents(elf::ObjectFile<ELFT> *File,
return check(File->getObj().getSectionContents(Hdr));
}
-template <class ELFT>
-InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
- uintX_t Flags, uint32_t Type,
- uintX_t Entsize, uint32_t Link,
- uint32_t Info, uintX_t Addralign,
- ArrayRef<uint8_t> Data, StringRef Name,
- Kind SectionKind)
- : InputSectionData(SectionKind, Name, Data,
- !Config->GcSections || !(Flags & SHF_ALLOC)),
- File(File), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link),
- Info(Info), Repl(this) {
+InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
+ uint32_t Type, uint64_t Entsize,
+ uint32_t Link, uint32_t Info,
+ uint32_t Alignment, ArrayRef<uint8_t> Data,
+ StringRef Name, Kind SectionKind)
+ : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info,
+ Link),
+ File(File), Data(Data), Repl(this) {
+ Live = !Config->GcSections || !(Flags & SHF_ALLOC);
+ Assigned = false;
NumRelocations = 0;
AreRelocsRela = false;
// The ELF spec states that a value of 0 means the section has
// no alignment constraits.
- uint64_t V = std::max<uint64_t>(Addralign, 1);
+ uint32_t V = std::max<uint64_t>(Alignment, 1);
if (!isPowerOf2_64(V))
fatal(toString(File) + ": section sh_addralign is not a power of 2");
+ this->Alignment = V;
+}
+
+// Drop SHF_GROUP bit unless we are producing a re-linkable object file.
+// SHF_GROUP is a marker that a section belongs to some comdat group.
+// That flag doesn't make sense in an executable.
+static uint64_t getFlags(uint64_t Flags) {
+ Flags &= ~(uint64_t)SHF_INFO_LINK;
+ if (!Config->Relocatable)
+ Flags &= ~(uint64_t)SHF_GROUP;
+ return Flags;
+}
+// GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of
+// March 2017) fail to infer section types for sections starting with
+// ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of
+// SHF_INIT_ARRAY. As a result, the following assembler directive
+// creates ".init_array.100" with SHT_PROGBITS, for example.
+//
+// .section .init_array.100, "aw"
+//
+// This function forces SHT_{INIT,FINI}_ARRAY so that we can handle
+// incorrect inputs as if they were correct from the beginning.
+static uint64_t getType(uint64_t Type, StringRef Name) {
+ if (Type == SHT_PROGBITS && Name.startswith(".init_array."))
+ return SHT_INIT_ARRAY;
+ if (Type == SHT_PROGBITS && Name.startswith(".fini_array."))
+ return SHT_FINI_ARRAY;
+ return Type;
+}
+
+template <class ELFT>
+InputSectionBase::InputSectionBase(elf::ObjectFile<ELFT> *File,
+ const typename ELFT::Shdr *Hdr,
+ StringRef Name, Kind SectionKind)
+ : InputSectionBase(File, getFlags(Hdr->sh_flags),
+ getType(Hdr->sh_type, Name), Hdr->sh_entsize,
+ Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign,
+ getSectionContents(File, Hdr), Name, SectionKind) {
// We reject object files having insanely large alignments even though
// they are allowed by the spec. I think 4GB is a reasonable limitation.
// We might want to relax this in the future.
- if (V > UINT32_MAX)
+ if (Hdr->sh_addralign > UINT32_MAX)
fatal(toString(File) + ": section sh_addralign is too large");
- Alignment = V;
-
- // If it is not a mergeable section, overwrite the flag so that the flag
- // is consistent with the class. This inconsistency could occur when
- // string merging is disabled using -O0 flag.
- if (!Config->Relocatable && !isa<MergeInputSection<ELFT>>(this))
- this->Flags &= ~(SHF_MERGE | SHF_STRINGS);
}
-template <class ELFT>
-InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
- const Elf_Shdr *Hdr, StringRef Name,
- Kind SectionKind)
- : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK, Hdr->sh_type,
- Hdr->sh_entsize, Hdr->sh_link, Hdr->sh_info,
- Hdr->sh_addralign, getSectionContents(File, Hdr), Name,
- SectionKind) {
- this->Offset = Hdr->sh_offset;
-}
-
-template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const {
- if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this))
+size_t InputSectionBase::getSize() const {
+ if (auto *S = dyn_cast<SyntheticSection>(this))
return S->getSize();
- if (auto *D = dyn_cast<InputSection<ELFT>>(this))
- if (D->getThunksSize() > 0)
- return D->getThunkOff() + D->getThunksSize();
-
return Data.size();
}
-template <class ELFT>
-typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const {
+uint64_t InputSectionBase::getOffsetInFile() const {
+ const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart();
+ const uint8_t *SecStart = Data.begin();
+ return SecStart - FileStart;
+}
+
+uint64_t SectionBase::getOffset(uint64_t Offset) const {
switch (kind()) {
+ case Output: {
+ auto *OS = cast<OutputSection>(this);
+ // For output sections we treat offset -1 as the end of the section.
+ return Offset == uint64_t(-1) ? OS->Size : Offset;
+ }
case Regular:
- return cast<InputSection<ELFT>>(this)->OutSecOff + Offset;
- case Synthetic:
+ return cast<InputSection>(this)->OutSecOff + Offset;
+ case Synthetic: {
+ auto *IS = cast<InputSection>(this);
// For synthetic sections we treat offset -1 as the end of the section.
- // The same approach is used for synthetic symbols (DefinedSynthetic).
- return cast<InputSection<ELFT>>(this)->OutSecOff +
- (Offset == uintX_t(-1) ? getSize() : Offset);
+ return IS->OutSecOff + (Offset == uint64_t(-1) ? IS->getSize() : Offset);
+ }
case EHFrame:
// The file crtbeginT.o has relocations pointing to the start of an empty
// .eh_frame that is known to be the first in the link. It does that to
// identify the start of the output .eh_frame.
return Offset;
case Merge:
- return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
+ const MergeInputSection *MS = cast<MergeInputSection>(this);
+ if (InputSection *IS = MS->getParent())
+ return IS->OutSecOff + MS->getOffset(Offset);
+ return MS->getOffset(Offset);
}
llvm_unreachable("invalid section kind");
}
+OutputSection *SectionBase::getOutputSection() {
+ InputSection *Sec;
+ if (auto *IS = dyn_cast<InputSection>(this))
+ Sec = IS;
+ else if (auto *MS = dyn_cast<MergeInputSection>(this))
+ Sec = MS->getParent();
+ else if (auto *EH = dyn_cast<EhInputSection>(this))
+ Sec = EH->getParent();
+ else
+ return cast<OutputSection>(this);
+ return Sec ? Sec->getParent() : nullptr;
+}
+
// Uncompress section contents. Note that this function is called
// from parallel_for_each, so it must be thread-safe.
-template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
- Decompressor Decompressor = check(Decompressor::create(
- Name, toStringRef(Data), ELFT::TargetEndianness == llvm::support::little,
- ELFT::Is64Bits));
+void InputSectionBase::uncompress() {
+ Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data),
+ Config->IsLE, Config->Is64));
- size_t Size = Decompressor.getDecompressedSize();
+ size_t Size = Dec.getDecompressedSize();
char *OutputBuf;
{
static std::mutex Mu;
@@ -142,41 +184,51 @@ template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
OutputBuf = BAlloc.Allocate<char>(Size);
}
- if (Error E = Decompressor.decompress({OutputBuf, Size}))
- fatal(E, toString(this));
- Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size);
+ if (Error E = Dec.decompress({OutputBuf, Size}))
+ fatal(toString(this) +
+ ": decompress failed: " + llvm::toString(std::move(E)));
+ this->Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size);
+ this->Flags &= ~(uint64_t)SHF_COMPRESSED;
}
-template <class ELFT>
-typename ELFT::uint
-InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const {
+uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const {
return getOffset(Sym.Value);
}
-template <class ELFT>
-InputSectionBase<ELFT> *InputSectionBase<ELFT>::getLinkOrderDep() const {
- if ((Flags & SHF_LINK_ORDER) && Link != 0)
- return getFile()->getSections()[Link];
+InputSection *InputSectionBase::getLinkOrderDep() const {
+ if ((Flags & SHF_LINK_ORDER) && Link != 0) {
+ InputSectionBase *L = File->getSections()[Link];
+ if (auto *IS = dyn_cast<InputSection>(L))
+ return IS;
+ error(
+ "Merge and .eh_frame sections are not supported with SHF_LINK_ORDER " +
+ toString(L));
+ }
return nullptr;
}
// Returns a source location string. Used to construct an error message.
template <class ELFT>
-std::string InputSectionBase<ELFT>::getLocation(typename ELFT::uint Offset) {
+std::string InputSectionBase::getLocation(uint64_t Offset) {
+ // We don't have file for synthetic sections.
+ if (getFile<ELFT>() == nullptr)
+ return (Config->OutputFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")")
+ .str();
+
// First check if we can get desired values from debugging information.
- std::string LineInfo = File->getLineInfo(this, Offset);
+ std::string LineInfo = getFile<ELFT>()->getLineInfo(this, Offset);
if (!LineInfo.empty())
return LineInfo;
// File->SourceFile contains STT_FILE symbol that contains a
// source file name. If it's missing, we use an object file name.
- std::string SrcFile = File->SourceFile;
+ std::string SrcFile = getFile<ELFT>()->SourceFile;
if (SrcFile.empty())
SrcFile = toString(File);
// Find a function symbol that encloses a given location.
- for (SymbolBody *B : File->getSymbols())
- if (auto *D = dyn_cast<DefinedRegular<ELFT>>(B))
+ for (SymbolBody *B : getFile<ELFT>()->getSymbols())
+ if (auto *D = dyn_cast<DefinedRegular>(B))
if (D->Section == this && D->Type == STT_FUNC)
if (D->Value <= Offset && Offset < D->Value + D->Size)
return SrcFile + ":(function " + toString(*D) + ")";
@@ -185,75 +237,180 @@ std::string InputSectionBase<ELFT>::getLocation(typename ELFT::uint Offset) {
return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
}
-template <class ELFT>
-InputSection<ELFT>::InputSection() : InputSectionBase<ELFT>() {}
-
-template <class ELFT>
-InputSection<ELFT>::InputSection(uintX_t Flags, uint32_t Type,
- uintX_t Addralign, ArrayRef<uint8_t> Data,
- StringRef Name, Kind K)
- : InputSectionBase<ELFT>(nullptr, Flags, Type,
- /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Addralign,
- Data, Name, K) {}
+// Returns a source location string. This function is intended to be
+// used for constructing an error message. The returned message looks
+// like this:
+//
+// foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42)
+//
+// Returns an empty string if there's no way to get line info.
+template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) {
+ // Synthetic sections don't have input files.
+ elf::ObjectFile<ELFT> *File = getFile<ELFT>();
+ if (!File)
+ return "";
+
+ Optional<DILineInfo> Info = File->getDILineInfo(this, Offset);
+
+ // File->SourceFile contains STT_FILE symbol, and that is a last resort.
+ if (!Info)
+ return File->SourceFile;
+
+ std::string Path = Info->FileName;
+ std::string Filename = path::filename(Path);
+ std::string Lineno = ":" + std::to_string(Info->Line);
+ if (Filename == Path)
+ return Filename + Lineno;
+ return Filename + Lineno + " (" + Path + Lineno + ")";
+}
-template <class ELFT>
-InputSection<ELFT>::InputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header, StringRef Name)
- : InputSectionBase<ELFT>(F, Header, Name, Base::Regular) {}
+// Returns a filename string along with an optional section name. This
+// function is intended to be used for constructing an error
+// message. The returned message looks like this:
+//
+// path/to/foo.o:(function bar)
+//
+// or
+//
+// path/to/foo.o:(function bar) in archive path/to/bar.a
+template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) {
+ // Synthetic sections don't have input files.
+ elf::ObjectFile<ELFT> *File = getFile<ELFT>();
+ if (!File)
+ return ("(internal):(" + Name + "+0x" + utohexstr(Off) + ")").str();
+ std::string Filename = File->getName();
+
+ std::string Archive;
+ if (!File->ArchiveName.empty())
+ Archive = (" in archive " + File->ArchiveName).str();
+
+ // Find a symbol that encloses a given location.
+ for (SymbolBody *B : getFile<ELFT>()->getSymbols())
+ if (auto *D = dyn_cast<DefinedRegular>(B))
+ if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size)
+ return Filename + ":(" + toString(*D) + ")" + Archive;
-template <class ELFT>
-bool InputSection<ELFT>::classof(const InputSectionData *S) {
- return S->kind() == Base::Regular || S->kind() == Base::Synthetic;
+ // If there's no symbol, print out the offset in the section.
+ return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive)
+ .str();
}
+InputSectionBase InputSectionBase::Discarded;
+
+InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
+ ArrayRef<uint8_t> Data, StringRef Name, Kind K)
+ : InputSectionBase(nullptr, Flags, Type,
+ /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data,
+ Name, K) {}
+
template <class ELFT>
-InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
- assert(this->Type == SHT_RELA || this->Type == SHT_REL);
- ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections();
- return Sections[this->Info];
+InputSection::InputSection(elf::ObjectFile<ELFT> *F,
+ const typename ELFT::Shdr *Header, StringRef Name)
+ : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {}
+
+bool InputSection::classof(const SectionBase *S) {
+ return S->kind() == SectionBase::Regular ||
+ S->kind() == SectionBase::Synthetic;
}
-template <class ELFT> void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) {
- Thunks.push_back(T);
+bool InputSectionBase::classof(const SectionBase *S) {
+ return S->kind() != Output;
}
-template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const {
- return this->Data.size();
+OutputSection *InputSection::getParent() const {
+ return cast_or_null<OutputSection>(Parent);
}
-template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const {
- uint64_t Total = 0;
- for (const Thunk<ELFT> *T : Thunks)
- Total += T->size();
- return Total;
+// Copy SHT_GROUP section contents. Used only for the -r option.
+template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) {
+ // ELFT::Word is the 32-bit integral type in the target endianness.
+ typedef typename ELFT::Word u32;
+ ArrayRef<u32> From = getDataAs<u32>();
+ auto *To = reinterpret_cast<u32 *>(Buf);
+
+ // The first entry is not a section number but a flag.
+ *To++ = From[0];
+
+ // Adjust section numbers because section numbers in an input object
+ // files are different in the output.
+ ArrayRef<InputSectionBase *> Sections = this->File->getSections();
+ for (uint32_t Idx : From.slice(1))
+ *To++ = Sections[Idx]->getOutputSection()->SectionIndex;
}
-// This is used for -r. We can't use memcpy to copy relocations because we need
-// to update symbol table offset and section index for each relocation. So we
-// copy relocations one by one.
-template <class ELFT>
-template <class RelTy>
-void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
- InputSectionBase<ELFT> *RelocatedSection = getRelocatedSection();
+InputSectionBase *InputSection::getRelocatedSection() {
+ assert(this->Type == SHT_RELA || this->Type == SHT_REL);
+ ArrayRef<InputSectionBase *> Sections = this->File->getSections();
+ return Sections[this->Info];
+}
+// This is used for -r and --emit-relocs. We can't use memcpy to copy
+// relocations because we need to update symbol table offset and section index
+// for each relocation. So we copy relocations one by one.
+template <class ELFT, class RelTy>
+void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+ InputSectionBase *RelocatedSection = getRelocatedSection();
+
+ // Loop is slow and have complexity O(N*M), where N - amount of
+ // relocations and M - amount of symbols in symbol table.
+ // That happens because getSymbolIndex(...) call below performs
+ // simple linear search.
for (const RelTy &Rel : Rels) {
- uint32_t Type = Rel.getType(Config->Mips64EL);
- SymbolBody &Body = this->File->getRelocTargetSym(Rel);
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
+ SymbolBody &Body = this->getFile<ELFT>()->getRelocTargetSym(Rel);
- Elf_Rela *P = reinterpret_cast<Elf_Rela *>(Buf);
+ auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf);
Buf += sizeof(RelTy);
- if (Config->Rela)
+ if (Config->IsRela)
P->r_addend = getAddend<ELFT>(Rel);
- P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
- P->setSymbolAndType(In<ELFT>::SymTab->getSymbolIndex(&Body), Type,
- Config->Mips64EL);
+
+ // Output section VA is zero for -r, so r_offset is an offset within the
+ // section, but for --emit-relocs it is an virtual address.
+ P->r_offset = RelocatedSection->getOutputSection()->Addr +
+ RelocatedSection->getOffset(Rel.r_offset);
+ P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Body), Type,
+ Config->IsMips64EL);
+
+ if (Body.Type == STT_SECTION) {
+ // We combine multiple section symbols into only one per
+ // section. This means we have to update the addend. That is
+ // trivial for Elf_Rela, but for Elf_Rel we have to write to the
+ // section data. We do that by adding to the Relocation vector.
+
+ // .eh_frame is horribly special and can reference discarded sections. To
+ // avoid having to parse and recreate .eh_frame, we just replace any
+ // relocation in it pointing to discarded sections with R_*_NONE, which
+ // hopefully creates a frame that is ignored at runtime.
+ SectionBase *Section = cast<DefinedRegular>(Body).Section;
+ if (Section == &InputSection::Discarded) {
+ P->setSymbolAndType(0, 0, false);
+ continue;
+ }
+
+ if (Config->IsRela) {
+ P->r_addend += Body.getVA() - Section->getOutputSection()->Addr;
+ } else if (Config->Relocatable) {
+ const uint8_t *BufLoc = RelocatedSection->Data.begin() + Rel.r_offset;
+ RelocatedSection->Relocations.push_back(
+ {R_ABS, Type, Rel.r_offset, Target->getImplicitAddend(BufLoc, Type),
+ &Body});
+ }
+ }
+
}
}
+// The ARM and AArch64 ABI handle pc-relative relocations to undefined weak
+// references specially. The general rule is that the value of the symbol in
+// this context is the address of the place P. A further special case is that
+// branch relocations to an undefined weak reference resolve to the next
+// instruction.
static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A,
uint32_t P) {
switch (Type) {
+ // Unresolved branch relocations to weak references resolve to next
+ // instruction, this will be either 2 or 4 bytes on from P.
case R_ARM_THM_JUMP11:
return P + 2 + A;
case R_ARM_CALL:
@@ -267,89 +424,128 @@ static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A,
case R_ARM_THM_CALL:
// We don't want an interworking BLX to ARM
return P + 5 + A;
- default:
+ // Unresolved non branch pc-relative relocations
+ // R_ARM_TARGET2 which can be resolved relatively is not present as it never
+ // targets a weak-reference.
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL:
+ case R_ARM_REL32:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL:
return P + A;
}
+ llvm_unreachable("ARM pc-relative relocation expected\n");
}
+// The comment above getARMUndefinedRelativeWeakVA applies to this function.
static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
uint64_t P) {
switch (Type) {
+ // Unresolved branch relocations to weak references resolve to next
+ // instruction, this is 4 bytes on from P.
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
case R_AARCH64_JUMP26:
case R_AARCH64_TSTBR14:
return P + 4 + A;
- default:
+ // Unresolved non branch pc-relative relocations
+ case R_AARCH64_PREL16:
+ case R_AARCH64_PREL32:
+ case R_AARCH64_PREL64:
+ case R_AARCH64_ADR_PREL_LO21:
return P + A;
}
+ llvm_unreachable("AArch64 pc-relative relocation expected\n");
}
-template <class ELFT>
-static typename ELFT::uint
-getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
- const SymbolBody &Body, RelExpr Expr) {
+// ARM SBREL relocations are of the form S + A - B where B is the static base
+// The ARM ABI defines base to be "addressing origin of the output segment
+// defining the symbol S". We defined the "addressing origin"/static base to be
+// the base of the PT_LOAD segment containing the Body.
+// The procedure call standard only defines a Read Write Position Independent
+// RWPI variant so in practice we should expect the static base to be the base
+// of the RW segment.
+static uint64_t getARMStaticBase(const SymbolBody &Body) {
+ OutputSection *OS = Body.getOutputSection();
+ if (!OS || !OS->FirstInPtLoad)
+ fatal("SBREL relocation to " + Body.getName() + " without static base");
+ return OS->FirstInPtLoad->Addr;
+}
+
+static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P,
+ const SymbolBody &Body, RelExpr Expr) {
switch (Expr) {
case R_ABS:
case R_RELAX_GOT_PC_NOPIC:
- return Body.getVA<ELFT>(A);
+ return Body.getVA(A);
+ case R_ARM_SBREL:
+ return Body.getVA(A) - getARMStaticBase(Body);
case R_GOT:
case R_RELAX_TLS_GD_TO_IE_ABS:
- return Body.getGotVA<ELFT>() + A;
+ return Body.getGotVA() + A;
case R_GOTONLY_PC:
- return In<ELFT>::Got->getVA() + A - P;
+ return InX::Got->getVA() + A - P;
case R_GOTONLY_PC_FROM_END:
- return In<ELFT>::Got->getVA() + A - P + In<ELFT>::Got->getSize();
+ return InX::Got->getVA() + A - P + InX::Got->getSize();
case R_GOTREL:
- return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA();
+ return Body.getVA(A) - InX::Got->getVA();
case R_GOTREL_FROM_END:
- return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA() -
- In<ELFT>::Got->getSize();
+ return Body.getVA(A) - InX::Got->getVA() - InX::Got->getSize();
case R_GOT_FROM_END:
case R_RELAX_TLS_GD_TO_IE_END:
- return Body.getGotOffset<ELFT>() + A - In<ELFT>::Got->getSize();
+ return Body.getGotOffset() + A - InX::Got->getSize();
case R_GOT_OFF:
- return Body.getGotOffset<ELFT>() + A;
+ return Body.getGotOffset() + A;
case R_GOT_PAGE_PC:
case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
- return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
+ return getAArch64Page(Body.getGotVA() + A) - getAArch64Page(P);
case R_GOT_PC:
case R_RELAX_TLS_GD_TO_IE:
- return Body.getGotVA<ELFT>() + A - P;
+ return Body.getGotVA() + A - P;
case R_HINT:
+ case R_NONE:
case R_TLSDESC_CALL:
llvm_unreachable("cannot relocate hint relocs");
case R_MIPS_GOTREL:
- return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getGp();
+ return Body.getVA(A) - InX::MipsGot->getGp();
+ case R_MIPS_GOT_GP:
+ return InX::MipsGot->getGp() + A;
+ case R_MIPS_GOT_GP_PC: {
+ // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
+ // is _gp_disp symbol. In that case we should use the following
+ // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ uint64_t V = InX::MipsGot->getGp() + A - P;
+ if (Type == R_MIPS_LO16)
+ V += 4;
+ return V;
+ }
case R_MIPS_GOT_LOCAL_PAGE:
// If relocation against MIPS local symbol requires GOT entry, this entry
// should be initialized by 'page address'. This address is high 16-bits
// of sum the symbol's value and the addend.
- return In<ELFT>::MipsGot->getVA() +
- In<ELFT>::MipsGot->getPageEntryOffset(Body, A) -
- In<ELFT>::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Body, A) -
+ InX::MipsGot->getGp();
case R_MIPS_GOT_OFF:
case R_MIPS_GOT_OFF32:
// In case of MIPS if a GOT relocation has non-zero addend this addend
// should be applied to the GOT entry content not to the GOT entry offset.
// That is why we use separate expression type.
- return In<ELFT>::MipsGot->getVA() +
- In<ELFT>::MipsGot->getBodyEntryOffset(Body, A) -
- In<ELFT>::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getBodyEntryOffset(Body, A) -
+ InX::MipsGot->getGp();
case R_MIPS_TLSGD:
- return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
- In<ELFT>::MipsGot->getGlobalDynOffset(Body) -
- In<ELFT>::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
+ InX::MipsGot->getGlobalDynOffset(Body) - InX::MipsGot->getGp();
case R_MIPS_TLSLD:
- return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
- In<ELFT>::MipsGot->getTlsIndexOff() - In<ELFT>::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
+ InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp();
case R_PAGE_PC:
case R_PLT_PAGE_PC: {
uint64_t Dest;
if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
Dest = getAArch64Page(A);
else
- Dest = getAArch64Page(Body.getVA<ELFT>(A));
+ Dest = getAArch64Page(Body.getVA(A));
return Dest - getAArch64Page(P);
}
case R_PC: {
@@ -362,39 +558,39 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
else if (Config->EMachine == EM_AARCH64)
Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P);
else
- Dest = Body.getVA<ELFT>(A);
+ Dest = Body.getVA(A);
} else {
- Dest = Body.getVA<ELFT>(A);
+ Dest = Body.getVA(A);
}
return Dest - P;
}
case R_PLT:
- return Body.getPltVA<ELFT>() + A;
+ return Body.getPltVA() + A;
case R_PLT_PC:
case R_PPC_PLT_OPD:
- return Body.getPltVA<ELFT>() + A - P;
+ return Body.getPltVA() + A - P;
case R_PPC_OPD: {
- uint64_t SymVA = Body.getVA<ELFT>(A);
+ uint64_t SymVA = Body.getVA(A);
// If we have an undefined weak symbol, we might get here with a symbol
// address of zero. That could overflow, but the code must be unreachable,
// so don't bother doing anything at all.
if (!SymVA)
return 0;
- if (Out<ELF64BE>::Opd) {
+ if (Out::Opd) {
// If this is a local call, and we currently have the address of a
// function-descriptor, get the underlying code address instead.
- uint64_t OpdStart = Out<ELF64BE>::Opd->Addr;
- uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->Size;
+ uint64_t OpdStart = Out::Opd->Addr;
+ uint64_t OpdEnd = OpdStart + Out::Opd->Size;
bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
if (InOpd)
- SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]);
+ SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]);
}
return SymVA - P;
}
case R_PPC_TOC:
return getPPC64TocBase() + A;
case R_RELAX_GOT_PC:
- return Body.getVA<ELFT>(A) - P;
+ return Body.getVA(A) - P;
case R_RELAX_TLS_GD_TO_LE:
case R_RELAX_TLS_IE_TO_LE:
case R_RELAX_TLS_LD_TO_LE:
@@ -408,33 +604,26 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
Body.symbol()->isWeak())
return 0;
if (Target->TcbSize)
- return Body.getVA<ELFT>(A) +
- alignTo(Target->TcbSize, Out<ELFT>::TlsPhdr->p_align);
- return Body.getVA<ELFT>(A) - Out<ELFT>::TlsPhdr->p_memsz;
+ return Body.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align);
+ return Body.getVA(A) - Out::TlsPhdr->p_memsz;
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
- return Out<ELF32LE>::TlsPhdr->p_memsz - Body.getVA<ELFT>(A);
+ return Out::TlsPhdr->p_memsz - Body.getVA(A);
case R_SIZE:
- return Body.getSize<ELFT>() + A;
- case R_THUNK_ABS:
- return Body.getThunkVA<ELFT>() + A;
- case R_THUNK_PC:
- case R_THUNK_PLT_PC:
- return Body.getThunkVA<ELFT>() + A - P;
+ return A; // Body.getSize was already folded into the addend.
case R_TLSDESC:
- return In<ELFT>::Got->getGlobalDynAddr(Body) + A;
+ return InX::Got->getGlobalDynAddr(Body) + A;
case R_TLSDESC_PAGE:
- return getAArch64Page(In<ELFT>::Got->getGlobalDynAddr(Body) + A) -
+ return getAArch64Page(InX::Got->getGlobalDynAddr(Body) + A) -
getAArch64Page(P);
case R_TLSGD:
- return In<ELFT>::Got->getGlobalDynOffset(Body) + A -
- In<ELFT>::Got->getSize();
+ return InX::Got->getGlobalDynOffset(Body) + A - InX::Got->getSize();
case R_TLSGD_PC:
- return In<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+ return InX::Got->getGlobalDynAddr(Body) + A - P;
case R_TLSLD:
- return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
+ return InX::Got->getTlsIndexOff() + A - InX::Got->getSize();
case R_TLSLD_PC:
- return In<ELFT>::Got->getTlsIndexVA() + A - P;
+ return InX::Got->getTlsIndexVA() + A - P;
}
llvm_unreachable("Invalid expression");
}
@@ -446,57 +635,71 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
// treatement such as GOT or PLT (because at runtime no one refers them).
// So, we handle relocations for non-alloc sections directly in this
// function as a performance optimization.
-template <class ELFT>
-template <class RelTy>
-void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+template <class ELFT, class RelTy>
+void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
for (const RelTy &Rel : Rels) {
- uint32_t Type = Rel.getType(Config->Mips64EL);
- uintX_t Offset = this->getOffset(Rel.r_offset);
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
+ uint64_t Offset = getOffset(Rel.r_offset);
uint8_t *BufLoc = Buf + Offset;
- uintX_t Addend = getAddend<ELFT>(Rel);
+ int64_t Addend = getAddend<ELFT>(Rel);
if (!RelTy::IsRela)
Addend += Target->getImplicitAddend(BufLoc, Type);
- SymbolBody &Sym = this->File->getRelocTargetSym(Rel);
- if (Target->getRelExpr(Type, Sym) != R_ABS) {
- error(this->getLocation(Offset) + ": has non-ABS reloc");
+ SymbolBody &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel);
+ RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
+ if (Expr == R_NONE)
+ continue;
+ if (Expr != R_ABS) {
+ error(this->getLocation<ELFT>(Offset) + ": has non-ABS reloc");
return;
}
- uintX_t AddrLoc = this->OutSec->Addr + Offset;
+ uint64_t AddrLoc = getParent()->Addr + Offset;
uint64_t SymVA = 0;
- if (!Sym.isTls() || Out<ELFT>::TlsPhdr)
- SymVA = SignExtend64<sizeof(uintX_t) * 8>(
- getRelocTargetVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS));
+ if (!Sym.isTls() || Out::TlsPhdr)
+ SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>(
+ getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS));
Target->relocateOne(BufLoc, Type, SymVA);
}
}
+template <class ELFT> elf::ObjectFile<ELFT> *InputSectionBase::getFile() const {
+ return cast_or_null<elf::ObjectFile<ELFT>>(File);
+}
+
template <class ELFT>
-void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+ if (Flags & SHF_ALLOC)
+ relocateAlloc(Buf, BufEnd);
+ else
+ relocateNonAlloc<ELFT>(Buf, BufEnd);
+}
+
+template <class ELFT>
+void InputSectionBase::relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd) {
// scanReloc function in Writer.cpp constructs Relocations
// vector only for SHF_ALLOC'ed sections. For other sections,
// we handle relocations directly here.
- auto *IS = dyn_cast<InputSection<ELFT>>(this);
- if (IS && !(IS->Flags & SHF_ALLOC)) {
- if (IS->AreRelocsRela)
- IS->relocateNonAlloc(Buf, IS->relas());
- else
- IS->relocateNonAlloc(Buf, IS->rels());
- return;
- }
+ auto *IS = cast<InputSection>(this);
+ assert(!(IS->Flags & SHF_ALLOC));
+ if (IS->AreRelocsRela)
+ IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>());
+ else
+ IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>());
+}
- const unsigned Bits = sizeof(uintX_t) * 8;
+void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
+ assert(Flags & SHF_ALLOC);
+ const unsigned Bits = Config->Wordsize * 8;
for (const Relocation &Rel : Relocations) {
- uintX_t Offset = getOffset(Rel.Offset);
+ uint64_t Offset = getOffset(Rel.Offset);
uint8_t *BufLoc = Buf + Offset;
uint32_t Type = Rel.Type;
- uintX_t A = Rel.Addend;
- uintX_t AddrLoc = OutSec->Addr + Offset;
+ uint64_t AddrLoc = getOutputSection()->Addr + Offset;
RelExpr Expr = Rel.Expr;
- uint64_t TargetVA = SignExtend64<Bits>(
- getRelocTargetVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr));
+ uint64_t TargetVA = SignExtend64(
+ getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits);
switch (Expr) {
case R_RELAX_GOT_PC:
@@ -523,7 +726,7 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
// Patch a nop (0x60000000) to a ld.
if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000)
write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
- // fallthrough
+ LLVM_FALLTHROUGH;
default:
Target->relocateOne(BufLoc, Type, TargetVA);
break;
@@ -531,67 +734,64 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
}
}
-template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
if (this->Type == SHT_NOBITS)
return;
- if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this)) {
+ if (auto *S = dyn_cast<SyntheticSection>(this)) {
S->writeTo(Buf + OutSecOff);
return;
}
- // If -r is given, then an InputSection may be a relocation section.
+ // If -r or --emit-relocs is given, then an InputSection
+ // may be a relocation section.
if (this->Type == SHT_RELA) {
- copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rela>());
+ copyRelocations<ELFT>(Buf + OutSecOff,
+ this->template getDataAs<typename ELFT::Rela>());
return;
}
if (this->Type == SHT_REL) {
- copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rel>());
+ copyRelocations<ELFT>(Buf + OutSecOff,
+ this->template getDataAs<typename ELFT::Rel>());
return;
}
- // Copy section contents from source object file to output file.
- ArrayRef<uint8_t> Data = this->Data;
- memcpy(Buf + OutSecOff, Data.data(), Data.size());
+ // If -r is given, we may have a SHT_GROUP section.
+ if (this->Type == SHT_GROUP) {
+ copyShtGroup<ELFT>(Buf + OutSecOff);
+ return;
+ }
- // Iterate over all relocation sections that apply to this section.
+ // Copy section contents from source object file to output file
+ // and then apply relocations.
+ memcpy(Buf + OutSecOff, Data.data(), Data.size());
uint8_t *BufEnd = Buf + OutSecOff + Data.size();
- this->relocate(Buf, BufEnd);
-
- // The section might have a data/code generated by the linker and need
- // to be written after the section. Usually these are thunks - small piece
- // of code used to jump between "incompatible" functions like PIC and non-PIC
- // or if the jump target too far and its address does not fit to the short
- // jump istruction.
- if (!Thunks.empty()) {
- Buf += OutSecOff + getThunkOff();
- for (const Thunk<ELFT> *T : Thunks) {
- T->writeTo(Buf);
- Buf += T->size();
- }
- }
+ this->relocate<ELFT>(Buf, BufEnd);
}
-template <class ELFT>
-void InputSection<ELFT>::replace(InputSection<ELFT> *Other) {
+void InputSection::replace(InputSection *Other) {
this->Alignment = std::max(this->Alignment, Other->Alignment);
Other->Repl = this->Repl;
Other->Live = false;
}
template <class ELFT>
-EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header, StringRef Name)
- : InputSectionBase<ELFT>(F, Header, Name, InputSectionBase<ELFT>::EHFrame) {
+EhInputSection::EhInputSection(elf::ObjectFile<ELFT> *F,
+ const typename ELFT::Shdr *Header,
+ StringRef Name)
+ : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {
// Mark .eh_frame sections as live by default because there are
// usually no relocations that point to .eh_frames. Otherwise,
// the garbage collector would drop all .eh_frame sections.
this->Live = true;
}
-template <class ELFT>
-bool EhInputSection<ELFT>::classof(const InputSectionData *S) {
- return S->kind() == InputSectionBase<ELFT>::EHFrame;
+SyntheticSection *EhInputSection::getParent() const {
+ return cast_or_null<SyntheticSection>(Parent);
+}
+
+bool EhInputSection::classof(const SectionBase *S) {
+ return S->kind() == InputSectionBase::EHFrame;
}
// Returns the index of the first relocation that points to a region between
@@ -615,24 +815,23 @@ static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
// .eh_frame is a sequence of CIE or FDE records.
// This function splits an input section into records and returns them.
-template <class ELFT> void EhInputSection<ELFT>::split() {
+template <class ELFT> void EhInputSection::split() {
// Early exit if already split.
if (!this->Pieces.empty())
return;
if (this->NumRelocations) {
if (this->AreRelocsRela)
- split(this->relas());
+ split<ELFT>(this->relas<ELFT>());
else
- split(this->rels());
+ split<ELFT>(this->rels<ELFT>());
return;
}
- split(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr));
+ split<ELFT>(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr));
}
-template <class ELFT>
-template <class RelTy>
-void EhInputSection<ELFT>::split(ArrayRef<RelTy> Rels) {
+template <class ELFT, class RelTy>
+void EhInputSection::split(ArrayRef<RelTy> Rels) {
ArrayRef<uint8_t> Data = this->Data;
unsigned RelI = 0;
for (size_t Off = 0, End = Data.size(); Off != End;) {
@@ -659,11 +858,13 @@ static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) {
return StringRef::npos;
}
+SyntheticSection *MergeInputSection::getParent() const {
+ return cast_or_null<SyntheticSection>(Parent);
+}
+
// Split SHF_STRINGS section. Such section is a sequence of
// null-terminated strings.
-template <class ELFT>
-void MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data,
- size_t EntSize) {
+void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) {
size_t Off = 0;
bool IsAlloc = this->Flags & SHF_ALLOC;
while (!Data.empty()) {
@@ -680,9 +881,8 @@ void MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data,
// Split non-SHF_STRINGS section. Such section is a sequence of
// fixed size records.
-template <class ELFT>
-void MergeInputSection<ELFT>::splitNonStrings(ArrayRef<uint8_t> Data,
- size_t EntSize) {
+void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data,
+ size_t EntSize) {
size_t Size = Data.size();
assert((Size % EntSize) == 0);
bool IsAlloc = this->Flags & SHF_ALLOC;
@@ -693,10 +893,10 @@ void MergeInputSection<ELFT>::splitNonStrings(ArrayRef<uint8_t> Data,
}
template <class ELFT>
-MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header,
- StringRef Name)
- : InputSectionBase<ELFT>(F, Header, Name, InputSectionBase<ELFT>::Merge) {}
+MergeInputSection::MergeInputSection(elf::ObjectFile<ELFT> *F,
+ const typename ELFT::Shdr *Header,
+ StringRef Name)
+ : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {}
// This function is called after we obtain a complete list of input sections
// that need to be linked. This is responsible to split section contents
@@ -704,28 +904,26 @@ MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F,
//
// Note that this function is called from parallel_for_each. This must be
// thread-safe (i.e. no memory allocation from the pools).
-template <class ELFT> void MergeInputSection<ELFT>::splitIntoPieces() {
+void MergeInputSection::splitIntoPieces() {
ArrayRef<uint8_t> Data = this->Data;
- uintX_t EntSize = this->Entsize;
+ uint64_t EntSize = this->Entsize;
if (this->Flags & SHF_STRINGS)
splitStrings(Data, EntSize);
else
splitNonStrings(Data, EntSize);
if (Config->GcSections && (this->Flags & SHF_ALLOC))
- for (uintX_t Off : LiveOffsets)
+ for (uint64_t Off : LiveOffsets)
this->getSectionPiece(Off)->Live = true;
}
-template <class ELFT>
-bool MergeInputSection<ELFT>::classof(const InputSectionData *S) {
- return S->kind() == InputSectionBase<ELFT>::Merge;
+bool MergeInputSection::classof(const SectionBase *S) {
+ return S->kind() == InputSectionBase::Merge;
}
// Do binary search to get a section piece at a given input offset.
-template <class ELFT>
-SectionPiece *MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) {
- auto *This = static_cast<const MergeInputSection<ELFT> *>(this);
+SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
+ auto *This = static_cast<const MergeInputSection *>(this);
return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
}
@@ -742,17 +940,15 @@ static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
return Comp(Value, *First) ? First : First + 1;
}
-template <class ELFT>
-const SectionPiece *
-MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
- uintX_t Size = this->Data.size();
+const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const {
+ uint64_t Size = this->Data.size();
if (Offset >= Size)
fatal(toString(this) + ": entry is past the end of the section");
// Find the element this offset points to.
auto I = fastUpperBound(
Pieces.begin(), Pieces.end(), Offset,
- [](const uintX_t &A, const SectionPiece &B) { return A < B.InputOff; });
+ [](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
return &*I;
}
@@ -760,10 +956,9 @@ MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
// Returns the offset in an output section for a given input offset.
// Because contents of a mergeable section is not contiguous in output,
// it is not just an addition to a base output offset.
-template <class ELFT>
-typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+uint64_t MergeInputSection::getOffset(uint64_t Offset) const {
// Initialize OffsetMap lazily.
- std::call_once(InitOffsetMap, [&] {
+ llvm::call_once(InitOffsetMap, [&] {
OffsetMap.reserve(Pieces.size());
for (const SectionPiece &Piece : Pieces)
OffsetMap[Piece.InputOff] = Piece.OutputOff;
@@ -783,31 +978,63 @@ typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
if (!Piece.Live)
return 0;
- uintX_t Addend = Offset - Piece.InputOff;
+ uint64_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}
-template class elf::InputSectionBase<ELF32LE>;
-template class elf::InputSectionBase<ELF32BE>;
-template class elf::InputSectionBase<ELF64LE>;
-template class elf::InputSectionBase<ELF64BE>;
-
-template class elf::InputSection<ELF32LE>;
-template class elf::InputSection<ELF32BE>;
-template class elf::InputSection<ELF64LE>;
-template class elf::InputSection<ELF64BE>;
-
-template class elf::EhInputSection<ELF32LE>;
-template class elf::EhInputSection<ELF32BE>;
-template class elf::EhInputSection<ELF64LE>;
-template class elf::EhInputSection<ELF64BE>;
-
-template class elf::MergeInputSection<ELF32LE>;
-template class elf::MergeInputSection<ELF32BE>;
-template class elf::MergeInputSection<ELF64LE>;
-template class elf::MergeInputSection<ELF64BE>;
-
-template std::string lld::toString(const InputSectionBase<ELF32LE> *);
-template std::string lld::toString(const InputSectionBase<ELF32BE> *);
-template std::string lld::toString(const InputSectionBase<ELF64LE> *);
-template std::string lld::toString(const InputSectionBase<ELF64BE> *);
+template InputSection::InputSection(elf::ObjectFile<ELF32LE> *,
+ const ELF32LE::Shdr *, StringRef);
+template InputSection::InputSection(elf::ObjectFile<ELF32BE> *,
+ const ELF32BE::Shdr *, StringRef);
+template InputSection::InputSection(elf::ObjectFile<ELF64LE> *,
+ const ELF64LE::Shdr *, StringRef);
+template InputSection::InputSection(elf::ObjectFile<ELF64BE> *,
+ const ELF64BE::Shdr *, StringRef);
+
+template std::string InputSectionBase::getLocation<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF64BE>(uint64_t);
+
+template std::string InputSectionBase::getSrcMsg<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getSrcMsg<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getSrcMsg<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getSrcMsg<ELF64BE>(uint64_t);
+
+template std::string InputSectionBase::getObjMsg<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getObjMsg<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getObjMsg<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getObjMsg<ELF64BE>(uint64_t);
+
+template void InputSection::writeTo<ELF32LE>(uint8_t *);
+template void InputSection::writeTo<ELF32BE>(uint8_t *);
+template void InputSection::writeTo<ELF64LE>(uint8_t *);
+template void InputSection::writeTo<ELF64BE>(uint8_t *);
+
+template elf::ObjectFile<ELF32LE> *InputSectionBase::getFile<ELF32LE>() const;
+template elf::ObjectFile<ELF32BE> *InputSectionBase::getFile<ELF32BE>() const;
+template elf::ObjectFile<ELF64LE> *InputSectionBase::getFile<ELF64LE>() const;
+template elf::ObjectFile<ELF64BE> *InputSectionBase::getFile<ELF64BE>() const;
+
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32LE> *,
+ const ELF32LE::Shdr *, StringRef);
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32BE> *,
+ const ELF32BE::Shdr *, StringRef);
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64LE> *,
+ const ELF64LE::Shdr *, StringRef);
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64BE> *,
+ const ELF64BE::Shdr *, StringRef);
+
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF32LE> *,
+ const ELF32LE::Shdr *, StringRef);
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF32BE> *,
+ const ELF32BE::Shdr *, StringRef);
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF64LE> *,
+ const ELF64LE::Shdr *, StringRef);
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF64BE> *,
+ const ELF64BE::Shdr *, StringRef);
+
+template void EhInputSection::split<ELF32LE>();
+template void EhInputSection::split<ELF32BE>();
+template void EhInputSection::split<ELF64LE>();
+template void EhInputSection::split<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.h b/contrib/llvm/tools/lld/ELF/InputSection.h
index 3f3a055..d262b58 100644
--- a/contrib/llvm/tools/lld/ELF/InputSection.h
+++ b/contrib/llvm/tools/lld/ELF/InputSection.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Object/ELF.h"
+#include "llvm/Support/Threading.h"
#include <mutex>
namespace lld {
@@ -27,97 +28,120 @@ class DefinedCommon;
class SymbolBody;
struct SectionPiece;
-template <class ELFT> class DefinedRegular;
+class DefinedRegular;
+class SyntheticSection;
+template <class ELFT> class EhFrameSection;
+class MergeSyntheticSection;
template <class ELFT> class ObjectFile;
-template <class ELFT> class OutputSection;
-class OutputSectionBase;
-
-// We need non-template input section class to store symbol layout
-// in linker script parser structures, where we do not have ELFT
-// template parameter. For each scripted output section symbol we
-// store pointer to preceding InputSectionData object or nullptr,
-// if symbol should be placed at the very beginning of the output
-// section
-class InputSectionData {
+class OutputSection;
+
+// This is the base class of all sections that lld handles. Some are sections in
+// input files, some are sections in the produced output file and some exist
+// just as a convenience for implementing special ways of combining some
+// sections.
+class SectionBase {
public:
- enum Kind { Regular, EHFrame, Merge, Synthetic, };
+ enum Kind { Regular, EHFrame, Merge, Synthetic, Output };
- // The garbage collector sets sections' Live bits.
- // If GC is disabled, all sections are considered live by default.
- InputSectionData(Kind SectionKind, StringRef Name, ArrayRef<uint8_t> Data,
- bool Live)
- : SectionKind(SectionKind), Live(Live), Assigned(false), Name(Name),
- Data(Data) {}
+ Kind kind() const { return (Kind)SectionKind; }
+
+ StringRef Name;
-private:
unsigned SectionKind : 3;
-public:
- Kind kind() const { return (Kind)SectionKind; }
+ // The next two bit fields are only used by InputSectionBase, but we
+ // put them here so the struct packs better.
+
+ // The garbage collector sets sections' Live bits.
+ // If GC is disabled, all sections are considered live by default.
+ unsigned Live : 1; // for garbage collection
+ unsigned Assigned : 1; // for linker script
- unsigned Live : 1; // for garbage collection
- unsigned Assigned : 1; // for linker script
uint32_t Alignment;
- StringRef Name;
- ArrayRef<uint8_t> Data;
- template <typename T> llvm::ArrayRef<T> getDataAs() const {
- size_t S = Data.size();
- assert(S % sizeof(T) == 0);
- return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
+ // These corresponds to the fields in Elf_Shdr.
+ uint64_t Flags;
+ uint64_t Entsize;
+ uint32_t Type;
+ uint32_t Link;
+ uint32_t Info;
+
+ OutputSection *getOutputSection();
+ const OutputSection *getOutputSection() const {
+ return const_cast<SectionBase *>(this)->getOutputSection();
}
- std::vector<Relocation> Relocations;
+ // Translate an offset in the input section to an offset in the output
+ // section.
+ uint64_t getOffset(uint64_t Offset) const;
+
+ uint64_t getOffset(const DefinedRegular &Sym) const;
+
+protected:
+ SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags,
+ uint64_t Entsize, uint64_t Alignment, uint32_t Type,
+ uint32_t Info, uint32_t Link)
+ : Name(Name), SectionKind(SectionKind), Alignment(Alignment),
+ Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) {
+ Live = false;
+ Assigned = false;
+ }
};
// This corresponds to a section of an input file.
-template <class ELFT> class InputSectionBase : public InputSectionData {
-protected:
- typedef typename ELFT::Chdr Elf_Chdr;
- typedef typename ELFT::Rel Elf_Rel;
- typedef typename ELFT::Rela Elf_Rela;
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::uint uintX_t;
+class InputSectionBase : public SectionBase {
+public:
+ static bool classof(const SectionBase *S);
// The file this section is from.
- ObjectFile<ELFT> *File;
+ InputFile *File;
-public:
- // These corresponds to the fields in Elf_Shdr.
- uintX_t Flags;
- uintX_t Offset = 0;
- uintX_t Entsize;
- uint32_t Type;
- uint32_t Link;
- uint32_t Info;
+ ArrayRef<uint8_t> Data;
+ uint64_t getOffsetInFile() const;
+
+ static InputSectionBase Discarded;
InputSectionBase()
- : InputSectionData(Regular, "", ArrayRef<uint8_t>(), false), Repl(this) {
+ : SectionBase(Regular, "", /*Flags*/ 0, /*Entsize*/ 0, /*Alignment*/ 0,
+ /*Type*/ 0,
+ /*Info*/ 0, /*Link*/ 0),
+ Repl(this) {
+ Live = false;
+ Assigned = false;
NumRelocations = 0;
AreRelocsRela = false;
}
- InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+ template <class ELFT>
+ InputSectionBase(ObjectFile<ELFT> *File, const typename ELFT::Shdr *Header,
StringRef Name, Kind SectionKind);
- InputSectionBase(ObjectFile<ELFT> *File, uintX_t Flags, uint32_t Type,
- uintX_t Entsize, uint32_t Link, uint32_t Info,
- uintX_t Addralign, ArrayRef<uint8_t> Data, StringRef Name,
+
+ InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type,
+ uint64_t Entsize, uint32_t Link, uint32_t Info,
+ uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name,
Kind SectionKind);
- OutputSectionBase *OutSec = nullptr;
+
+ // Input sections are part of an output section. Special sections
+ // like .eh_frame and merge sections are first combined into a
+ // synthetic section that is then added to an output section. In all
+ // cases this points one level up.
+ SectionBase *Parent = nullptr;
// Relocations that refer to this section.
- const Elf_Rel *FirstRelocation = nullptr;
+ const void *FirstRelocation = nullptr;
unsigned NumRelocations : 31;
unsigned AreRelocsRela : 1;
- ArrayRef<Elf_Rel> rels() const {
+ template <class ELFT> ArrayRef<typename ELFT::Rel> rels() const {
assert(!AreRelocsRela);
- return llvm::makeArrayRef(FirstRelocation, NumRelocations);
+ return llvm::makeArrayRef(
+ static_cast<const typename ELFT::Rel *>(FirstRelocation),
+ NumRelocations);
}
- ArrayRef<Elf_Rela> relas() const {
+ template <class ELFT> ArrayRef<typename ELFT::Rela> relas() const {
assert(AreRelocsRela);
- return llvm::makeArrayRef(static_cast<const Elf_Rela *>(FirstRelocation),
- NumRelocations);
+ return llvm::makeArrayRef(
+ static_cast<const typename ELFT::Rela *>(FirstRelocation),
+ NumRelocations);
}
// This pointer points to the "real" instance of this instance.
@@ -125,25 +149,40 @@ public:
// Repl pointer of one section points to another section. So,
// if you need to get a pointer to this instance, do not use
// this but instead this->Repl.
- InputSectionBase<ELFT> *Repl;
+ InputSectionBase *Repl;
+
+ // InputSections that are dependent on us (reverse dependency for GC)
+ llvm::TinyPtrVector<InputSectionBase *> DependentSections;
// Returns the size of this section (even if this is a common or BSS.)
size_t getSize() const;
- ObjectFile<ELFT> *getFile() const { return File; }
- llvm::object::ELFFile<ELFT> getObj() const { return File->getObj(); }
- uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
- InputSectionBase *getLinkOrderDep() const;
- // Translate an offset in the input section to an offset in the output
- // section.
- uintX_t getOffset(uintX_t Offset) const;
+ template <class ELFT> ObjectFile<ELFT> *getFile() const;
+
+ template <class ELFT> llvm::object::ELFFile<ELFT> getObj() const {
+ return getFile<ELFT>()->getObj();
+ }
+
+ InputSection *getLinkOrderDep() const;
void uncompress();
// Returns a source location string. Used to construct an error message.
- std::string getLocation(uintX_t Offset);
+ template <class ELFT> std::string getLocation(uint64_t Offset);
+ template <class ELFT> std::string getSrcMsg(uint64_t Offset);
+ template <class ELFT> std::string getObjMsg(uint64_t Offset);
+
+ template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd);
+ void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd);
+ template <class ELFT> void relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd);
+
+ std::vector<Relocation> Relocations;
- void relocate(uint8_t *Buf, uint8_t *BufEnd);
+ template <typename T> llvm::ArrayRef<T> getDataAs() const {
+ size_t S = Data.size();
+ assert(S % sizeof(T) == 0);
+ return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
+ }
};
// SectionPiece represents a piece of splittable section contents.
@@ -162,26 +201,23 @@ static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t),
"SectionPiece is too big");
// This corresponds to a SHF_MERGE section of an input file.
-template <class ELFT> class MergeInputSection : public InputSectionBase<ELFT> {
- typedef typename ELFT::uint uintX_t;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::Shdr Elf_Shdr;
-
+class MergeInputSection : public InputSectionBase {
public:
- MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header,
+ template <class ELFT>
+ MergeInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
StringRef Name);
- static bool classof(const InputSectionData *S);
+ static bool classof(const SectionBase *S);
void splitIntoPieces();
// Mark the piece at a given offset live. Used by GC.
- void markLiveAt(uintX_t Offset) {
+ void markLiveAt(uint64_t Offset) {
assert(this->Flags & llvm::ELF::SHF_ALLOC);
LiveOffsets.insert(Offset);
}
// Translate an offset in the input section to an offset
// in the output section.
- uintX_t getOffset(uintX_t Offset) const;
+ uint64_t getOffset(uint64_t Offset) const;
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
@@ -203,8 +239,10 @@ public:
}
// Returns the SectionPiece at a given input section offset.
- SectionPiece *getSectionPiece(uintX_t Offset);
- const SectionPiece *getSectionPiece(uintX_t Offset) const;
+ SectionPiece *getSectionPiece(uint64_t Offset);
+ const SectionPiece *getSectionPiece(uint64_t Offset) const;
+
+ SyntheticSection *getParent() const;
private:
void splitStrings(ArrayRef<uint8_t> A, size_t Size);
@@ -212,18 +250,18 @@ private:
std::vector<uint32_t> Hashes;
- mutable llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
- mutable std::once_flag InitOffsetMap;
+ mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap;
+ mutable llvm::once_flag InitOffsetMap;
- llvm::DenseSet<uintX_t> LiveOffsets;
+ llvm::DenseSet<uint64_t> LiveOffsets;
};
struct EhSectionPiece : public SectionPiece {
- EhSectionPiece(size_t Off, InputSectionData *ID, uint32_t Size,
+ EhSectionPiece(size_t Off, InputSectionBase *ID, uint32_t Size,
unsigned FirstRelocation)
: SectionPiece(Off, false), ID(ID), Size(Size),
FirstRelocation(FirstRelocation) {}
- InputSectionData *ID;
+ InputSectionBase *ID;
uint32_t Size;
uint32_t size() const { return Size; }
@@ -232,85 +270,70 @@ struct EhSectionPiece : public SectionPiece {
};
// This corresponds to a .eh_frame section of an input file.
-template <class ELFT> class EhInputSection : public InputSectionBase<ELFT> {
+class EhInputSection : public InputSectionBase {
public:
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::uint uintX_t;
- EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name);
- static bool classof(const InputSectionData *S);
- void split();
- template <class RelTy> void split(ArrayRef<RelTy> Rels);
+ template <class ELFT>
+ EhInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
+ StringRef Name);
+ static bool classof(const SectionBase *S);
+ template <class ELFT> void split();
+ template <class ELFT, class RelTy> void split(ArrayRef<RelTy> Rels);
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
std::vector<EhSectionPiece> Pieces;
-};
-// This corresponds to a non SHF_MERGE section of an input file.
-template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
- typedef InputSectionBase<ELFT> Base;
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Rela Elf_Rela;
- typedef typename ELFT::Rel Elf_Rel;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::uint uintX_t;
- typedef InputSectionData::Kind Kind;
+ SyntheticSection *getParent() const;
+};
+// This is a section that is added directly to an output section
+// instead of needing special combination via a synthetic section. This
+// includes all input sections with the exceptions of SHF_MERGE and
+// .eh_frame. It also includes the synthetic sections themselves.
+class InputSection : public InputSectionBase {
public:
- InputSection();
- InputSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
- ArrayRef<uint8_t> Data, StringRef Name,
- Kind K = InputSectionData::Regular);
- InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name);
-
- static InputSection<ELFT> Discarded;
+ InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
+ ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular);
+ template <class ELFT>
+ InputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
+ StringRef Name);
// Write this section to a mmap'ed file, assuming Buf is pointing to
// beginning of the output section.
- void writeTo(uint8_t *Buf);
+ template <class ELFT> void writeTo(uint8_t *Buf);
+
+ OutputSection *getParent() const;
// The offset from beginning of the output sections this section was assigned
// to. The writer sets a value.
uint64_t OutSecOff = 0;
- // InputSection that is dependent on us (reverse dependency for GC)
- InputSectionBase<ELFT> *DependentSection = nullptr;
-
- static bool classof(const InputSectionData *S);
+ static bool classof(const SectionBase *S);
- InputSectionBase<ELFT> *getRelocatedSection();
+ InputSectionBase *getRelocatedSection();
- // Register thunk related to the symbol. When the section is written
- // to a mmap'ed file, target is requested to write an actual thunk code.
- // Now thunks is supported for MIPS and ARM target only.
- void addThunk(const Thunk<ELFT> *T);
-
- // The offset of synthetic thunk code from beginning of this section.
- uint64_t getThunkOff() const;
-
- // Size of chunk with thunks code.
- uint64_t getThunksSize() const;
-
- template <class RelTy>
+ template <class ELFT, class RelTy>
void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
// Used by ICF.
uint32_t Class[2] = {0, 0};
// Called by ICF to merge two input sections.
- void replace(InputSection<ELFT> *Other);
+ void replace(InputSection *Other);
private:
- template <class RelTy>
+ template <class ELFT, class RelTy>
void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
- llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks;
+ template <class ELFT> void copyShtGroup(uint8_t *Buf);
};
-template <class ELFT> InputSection<ELFT> InputSection<ELFT>::Discarded;
+// The list of all input sections.
+extern std::vector<InputSectionBase *> InputSections;
+
} // namespace elf
-template <class ELFT> std::string toString(const elf::InputSectionBase<ELFT> *);
+std::string toString(const elf::InputSectionBase *);
} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/LTO.cpp b/contrib/llvm/tools/lld/ELF/LTO.cpp
index b342b61..3a53627 100644
--- a/contrib/llvm/tools/lld/ELF/LTO.cpp
+++ b/contrib/llvm/tools/lld/ELF/LTO.cpp
@@ -12,17 +12,18 @@
#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
+#include "lld/Core/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Caching.h"
#include "llvm/LTO/Config.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/SymbolicFile.h"
#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -46,7 +47,7 @@ static void saveBuffer(StringRef Buffer, const Twine &Path) {
std::error_code EC;
raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
if (EC)
- error(EC, "cannot create " + Path);
+ error("cannot create " + Path + ": " + EC.message());
OS << Buffer;
}
@@ -72,7 +73,13 @@ static std::unique_ptr<lto::LTO> createLTO() {
Conf.Options = InitTargetOptionsFromCodeGenFlags();
Conf.Options.RelaxELFRelocations = true;
- Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static;
+ if (Config->Relocatable)
+ Conf.RelocModel = None;
+ else if (Config->Pic)
+ Conf.RelocModel = Reloc::PIC_;
+ else
+ Conf.RelocModel = Reloc::Static;
+ Conf.CodeModel = GetCodeModelFromCMModel();
Conf.DisableVerify = Config->DisableVerify;
Conf.DiagHandler = diagnosticHandler;
Conf.OptLevel = Config->LTOO;
@@ -81,6 +88,10 @@ static std::unique_ptr<lto::LTO> createLTO() {
Conf.OptPipeline = Config->LTONewPmPasses;
Conf.AAPipeline = Config->LTOAAPipeline;
+ // Set up optimization remarks if we've been asked to.
+ Conf.RemarksFilename = Config->OptRemarksFilename;
+ Conf.RemarksWithHotness = Config->OptRemarksWithHotness;
+
if (Config->SaveTemps)
checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
/*UseInputModulePath*/ true));
@@ -96,12 +107,12 @@ BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
-template <class ELFT> static void undefine(Symbol *S) {
- replaceBody<Undefined<ELFT>>(S, S->body()->getName(), /*IsLocal=*/false,
- STV_DEFAULT, S->body()->Type, nullptr);
+static void undefine(Symbol *S) {
+ replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
+ STV_DEFAULT, S->body()->Type, nullptr);
}
-template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
+void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
unsigned SymNum = 0;
std::vector<Symbol *> Syms = F.getSymbols();
@@ -119,14 +130,13 @@ template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
// flags an undefined in IR with a definition in ASM as prevailing.
// Once IRObjectFile is fixed to report only one symbol this hack can
// be removed.
- R.Prevailing =
- !(ObjSym.getFlags() & object::BasicSymbolRef::SF_Undefined) &&
- B->File == &F;
+ R.Prevailing = !ObjSym.isUndefined() && B->File == &F;
R.VisibleToRegularObj =
Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
if (R.Prevailing)
- undefine<ELFT>(Sym);
+ undefine(Sym);
+ R.LinkerRedefined = Config->RenamedSymbols.count(Sym);
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
@@ -137,17 +147,34 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
std::vector<InputFile *> Ret;
unsigned MaxTasks = LTOObj->getMaxTasks();
Buff.resize(MaxTasks);
-
- checkError(LTOObj->run([&](size_t Task) {
- return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buff[Task]));
- }));
+ Files.resize(MaxTasks);
+
+ // The --thinlto-cache-dir option specifies the path to a directory in which
+ // to cache native object files for ThinLTO incremental builds. If a path was
+ // specified, configure LTO to use it as the cache directory.
+ lto::NativeObjectCache Cache;
+ if (!Config->ThinLTOCacheDir.empty())
+ Cache = check(
+ lto::localCache(Config->ThinLTOCacheDir,
+ [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
+
+ checkError(LTOObj->run(
+ [&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ },
+ Cache));
+
+ if (!Config->ThinLTOCacheDir.empty())
+ pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
for (unsigned I = 0; I != MaxTasks; ++I) {
if (Buff[I].empty())
continue;
if (Config->SaveTemps) {
- if (MaxTasks == 1)
+ if (I == 0)
saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
else
saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
@@ -155,10 +182,10 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp"));
Ret.push_back(Obj);
}
+
+ for (std::unique_ptr<MemoryBuffer> &File : Files)
+ if (File)
+ Ret.push_back(createObjectFile(*File));
+
return Ret;
}
-
-template void BitcodeCompiler::template add<ELF32LE>(BitcodeFile &);
-template void BitcodeCompiler::template add<ELF32BE>(BitcodeFile &);
-template void BitcodeCompiler::template add<ELF64LE>(BitcodeFile &);
-template void BitcodeCompiler::template add<ELF64BE>(BitcodeFile &);
diff --git a/contrib/llvm/tools/lld/ELF/LTO.h b/contrib/llvm/tools/lld/ELF/LTO.h
index 3cb7636..d19923c 100644
--- a/contrib/llvm/tools/lld/ELF/LTO.h
+++ b/contrib/llvm/tools/lld/ELF/LTO.h
@@ -30,7 +30,7 @@ namespace llvm {
namespace lto {
class LTO;
}
-}
+} // namespace llvm
namespace lld {
namespace elf {
@@ -43,14 +43,15 @@ public:
BitcodeCompiler();
~BitcodeCompiler();
- template <class ELFT> void add(BitcodeFile &F);
+ void add(BitcodeFile &F);
std::vector<InputFile *> compile();
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
std::vector<SmallString<0>> Buff;
+ std::vector<std::unique_ptr<MemoryBuffer>> Files;
};
-}
-}
+} // namespace elf
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
index 3cc2353..8bdbd8d 100644
--- a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
+++ b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp
@@ -13,27 +13,24 @@
#include "LinkerScript.h"
#include "Config.h"
-#include "Driver.h"
#include "InputSection.h"
#include "Memory.h"
#include "OutputSections.h"
-#include "ScriptParser.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
+#include "Threads.h"
#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
-#include "llvm/Support/ELF.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include <algorithm>
#include <cassert>
@@ -41,9 +38,7 @@
#include <cstdint>
#include <iterator>
#include <limits>
-#include <memory>
#include <string>
-#include <tuple>
#include <vector>
using namespace llvm;
@@ -53,77 +48,141 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
-LinkerScriptBase *elf::ScriptBase;
-ScriptConfiguration *elf::ScriptConfig;
+LinkerScript *elf::Script;
-template <class ELFT> static SymbolBody *addRegular(SymbolAssignment *Cmd) {
- uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
- Symbol *Sym = Symtab<ELFT>::X->addUndefined(
- Cmd->Name, /*IsLocal=*/false, STB_GLOBAL, Visibility,
- /*Type*/ 0,
- /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
-
- replaceBody<DefinedRegular<ELFT>>(Sym, Cmd->Name, /*IsLocal=*/false,
- Visibility, STT_NOTYPE, 0, 0, nullptr,
- nullptr);
- return Sym->body();
+uint64_t ExprValue::getValue() const {
+ if (Sec) {
+ if (OutputSection *OS = Sec->getOutputSection())
+ return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment);
+ error(Loc + ": unable to evaluate expression: input section " + Sec->Name +
+ " has no output section assigned");
+ }
+ return alignTo(Val, Alignment);
+}
+
+uint64_t ExprValue::getSecAddr() const {
+ if (Sec)
+ return Sec->getOffset(0) + Sec->getOutputSection()->Addr;
+ return 0;
}
-template <class ELFT> static SymbolBody *addSynthetic(SymbolAssignment *Cmd) {
+template <class ELFT> static SymbolBody *addRegular(SymbolAssignment *Cmd) {
+ Symbol *Sym;
uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
- const OutputSectionBase *Sec =
- ScriptConfig->HasSections ? nullptr : Cmd->Expression.Section();
- Symbol *Sym = Symtab<ELFT>::X->addUndefined(
- Cmd->Name, /*IsLocal=*/false, STB_GLOBAL, Visibility,
- /*Type*/ 0,
- /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
-
- replaceBody<DefinedSynthetic>(Sym, Cmd->Name, 0, Sec);
+ std::tie(Sym, std::ignore) = Symtab<ELFT>::X->insert(
+ Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false,
+ /*File*/ nullptr);
+ Sym->Binding = STB_GLOBAL;
+ ExprValue Value = Cmd->Expression();
+ SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec;
+
+ // We want to set symbol values early if we can. This allows us to use symbols
+ // as variables in linker scripts. Doing so allows us to write expressions
+ // like this: `alignment = 16; . = ALIGN(., alignment)`
+ uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0;
+ replaceBody<DefinedRegular>(Sym, Cmd->Name, /*IsLocal=*/false, Visibility,
+ STT_NOTYPE, SymValue, 0, Sec, nullptr);
return Sym->body();
}
-static bool isUnderSysroot(StringRef Path) {
- if (Config->Sysroot == "")
- return false;
- for (; !Path.empty(); Path = sys::path::parent_path(Path))
- if (sys::fs::equivalent(Config->Sysroot, Path))
- return true;
- return false;
+OutputSectionCommand *
+LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) {
+ OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
+ OutputSectionCommand *Cmd;
+ if (CmdRef && CmdRef->Location.empty()) {
+ // There was a forward reference.
+ Cmd = CmdRef;
+ } else {
+ Cmd = make<OutputSectionCommand>(Name);
+ if (!CmdRef)
+ CmdRef = Cmd;
+ }
+ Cmd->Location = Location;
+ return Cmd;
}
-template <class ELFT> static void assignSymbol(SymbolAssignment *Cmd) {
- // If there are sections, then let the value be assigned later in
- // `assignAddresses`.
- if (ScriptConfig->HasSections)
+OutputSectionCommand *
+LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) {
+ OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
+ if (!CmdRef)
+ CmdRef = make<OutputSectionCommand>(Name);
+ return CmdRef;
+}
+
+void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
+ uint64_t Val = E().getValue();
+ if (Val < Dot && InSec)
+ error(Loc + ": unable to move location counter backward for: " +
+ CurAddressState->OutSec->Name);
+ Dot = Val;
+ // Update to location counter means update to section size.
+ if (InSec)
+ CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr;
+}
+
+// Sets value of a symbol. Two kinds of symbols are processed: synthetic
+// symbols, whose value is an offset from beginning of section and regular
+// symbols whose value is absolute.
+void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) {
+ if (Cmd->Name == ".") {
+ setDot(Cmd->Expression, Cmd->Location, InSec);
+ return;
+ }
+
+ if (!Cmd->Sym)
return;
- uint64_t Value = Cmd->Expression(0);
- if (Cmd->Expression.IsAbsolute()) {
- cast<DefinedRegular<ELFT>>(Cmd->Sym)->Value = Value;
+ auto *Sym = cast<DefinedRegular>(Cmd->Sym);
+ ExprValue V = Cmd->Expression();
+ if (V.isAbsolute()) {
+ Sym->Value = V.getValue();
} else {
- const OutputSectionBase *Sec = Cmd->Expression.Section();
- if (Sec)
- cast<DefinedSynthetic>(Cmd->Sym)->Value = Value - Sec->Addr;
+ Sym->Section = V.Sec;
+ Sym->Value = alignTo(V.Val, V.Alignment);
+ }
+}
+
+static SymbolBody *findSymbol(StringRef S) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return Symtab<ELF32LE>::X->find(S);
+ case ELF32BEKind:
+ return Symtab<ELF32BE>::X->find(S);
+ case ELF64LEKind:
+ return Symtab<ELF64LE>::X->find(S);
+ case ELF64BEKind:
+ return Symtab<ELF64BE>::X->find(S);
+ default:
+ llvm_unreachable("unknown Config->EKind");
+ }
+}
+
+static SymbolBody *addRegularSymbol(SymbolAssignment *Cmd) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return addRegular<ELF32LE>(Cmd);
+ case ELF32BEKind:
+ return addRegular<ELF32BE>(Cmd);
+ case ELF64LEKind:
+ return addRegular<ELF64LE>(Cmd);
+ case ELF64BEKind:
+ return addRegular<ELF64BE>(Cmd);
+ default:
+ llvm_unreachable("unknown Config->EKind");
}
}
-template <class ELFT> static void addSymbol(SymbolAssignment *Cmd) {
+void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
if (Cmd->Name == ".")
return;
// If a symbol was in PROVIDE(), we need to define it only when
// it is a referenced undefined symbol.
- SymbolBody *B = Symtab<ELFT>::X->find(Cmd->Name);
+ SymbolBody *B = findSymbol(Cmd->Name);
if (Cmd->Provide && (!B || B->isDefined()))
return;
- // Otherwise, create a new symbol if one does not exist or an
- // undefined one does exist.
- if (Cmd->Expression.IsAbsolute())
- Cmd->Sym = addRegular<ELFT>(Cmd);
- else
- Cmd->Sym = addSynthetic<ELFT>(Cmd);
- assignSymbol<ELFT>(Cmd);
+ Cmd->Sym = addRegularSymbol(Cmd);
}
bool SymbolAssignment::classof(const BaseCommand *C) {
@@ -134,6 +193,15 @@ bool OutputSectionCommand::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind;
}
+// Fill [Buf, Buf + Size) with Filler.
+// This is used for linker script "=fillexp" command.
+static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
+ size_t I = 0;
+ for (; I + 4 < Size; I += 4)
+ memcpy(Buf + I, &Filler, 4);
+ memcpy(Buf + I, &Filler, Size - I);
+}
+
bool InputSectionDescription::classof(const BaseCommand *C) {
return C->Kind == InputSectionKind;
}
@@ -146,17 +214,13 @@ bool BytesDataCommand::classof(const BaseCommand *C) {
return C->Kind == BytesDataKind;
}
-template <class ELFT> LinkerScript<ELFT>::LinkerScript() = default;
-template <class ELFT> LinkerScript<ELFT>::~LinkerScript() = default;
-
-template <class ELFT> static StringRef basename(InputSectionBase<ELFT> *S) {
- if (S->getFile())
- return sys::path::filename(S->getFile()->getName());
+static StringRef basename(InputSectionBase *S) {
+ if (S->File)
+ return sys::path::filename(S->File->getName());
return "";
}
-template <class ELFT>
-bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
+bool LinkerScript::shouldKeep(InputSectionBase *S) {
for (InputSectionDescription *ID : Opt.KeptSections)
if (ID->FilePat.match(basename(S)))
for (SectionPattern &P : ID->SectionPatterns)
@@ -165,73 +229,95 @@ bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
return false;
}
-static bool comparePriority(InputSectionData *A, InputSectionData *B) {
- return getPriority(A->Name) < getPriority(B->Name);
-}
-
-static bool compareName(InputSectionData *A, InputSectionData *B) {
- return A->Name < B->Name;
-}
-
-static bool compareAlignment(InputSectionData *A, InputSectionData *B) {
- // ">" is not a mistake. Larger alignments are placed before smaller
- // alignments in order to reduce the amount of padding necessary.
- // This is compatible with GNU.
- return A->Alignment > B->Alignment;
+// If an input string is in the form of "foo.N" where N is a number,
+// return N. Otherwise, returns 65536, which is one greater than the
+// lowest priority.
+static int getPriority(StringRef S) {
+ size_t Pos = S.rfind('.');
+ if (Pos == StringRef::npos)
+ return 65536;
+ int V;
+ if (!to_integer(S.substr(Pos + 1), V, 10))
+ return 65536;
+ return V;
}
-static std::function<bool(InputSectionData *, InputSectionData *)>
+// A helper function for the SORT() command.
+static std::function<bool(InputSectionBase *, InputSectionBase *)>
getComparator(SortSectionPolicy K) {
switch (K) {
case SortSectionPolicy::Alignment:
- return compareAlignment;
+ return [](InputSectionBase *A, InputSectionBase *B) {
+ // ">" is not a mistake. Sections with larger alignments are placed
+ // before sections with smaller alignments in order to reduce the
+ // amount of padding necessary. This is compatible with GNU.
+ return A->Alignment > B->Alignment;
+ };
case SortSectionPolicy::Name:
- return compareName;
+ return [](InputSectionBase *A, InputSectionBase *B) {
+ return A->Name < B->Name;
+ };
case SortSectionPolicy::Priority:
- return comparePriority;
+ return [](InputSectionBase *A, InputSectionBase *B) {
+ return getPriority(A->Name) < getPriority(B->Name);
+ };
default:
llvm_unreachable("unknown sort policy");
}
}
-template <class ELFT>
-static bool matchConstraints(ArrayRef<InputSectionBase<ELFT> *> Sections,
+// A helper function for the SORT() command.
+static bool matchConstraints(ArrayRef<InputSectionBase *> Sections,
ConstraintKind Kind) {
if (Kind == ConstraintKind::NoConstraint)
return true;
- bool IsRW = llvm::any_of(Sections, [=](InputSectionData *Sec2) {
- auto *Sec = static_cast<InputSectionBase<ELFT> *>(Sec2);
- return Sec->Flags & SHF_WRITE;
+
+ bool IsRW = llvm::any_of(Sections, [](InputSectionBase *Sec) {
+ return static_cast<InputSectionBase *>(Sec)->Flags & SHF_WRITE;
});
+
return (IsRW && Kind == ConstraintKind::ReadWrite) ||
(!IsRW && Kind == ConstraintKind::ReadOnly);
}
-static void sortSections(InputSectionData **Begin, InputSectionData **End,
+static void sortSections(InputSection **Begin, InputSection **End,
SortSectionPolicy K) {
if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None)
std::stable_sort(Begin, End, getComparator(K));
}
// Compute and remember which sections the InputSectionDescription matches.
-template <class ELFT>
-void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
- // Collects all sections that satisfy constraints of I
- // and attach them to I.
- for (SectionPattern &Pat : I->SectionPatterns) {
- size_t SizeBefore = I->Sections.size();
-
- for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections) {
- if (!S->Live || S->Assigned)
+std::vector<InputSection *>
+LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
+ std::vector<InputSection *> Ret;
+
+ // Collects all sections that satisfy constraints of Cmd.
+ for (const SectionPattern &Pat : Cmd->SectionPatterns) {
+ size_t SizeBefore = Ret.size();
+
+ for (InputSectionBase *Sec : InputSections) {
+ if (Sec->Assigned)
+ continue;
+
+ if (!Sec->Live) {
+ reportDiscarded(Sec);
continue;
+ }
- StringRef Filename = basename(S);
- if (!I->FilePat.match(Filename) || Pat.ExcludedFilePat.match(Filename))
+ // For -emit-relocs we have to ignore entries like
+ // .rela.dyn : { *(.rela.data) }
+ // which are common because they are in the default bfd script.
+ if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
continue;
- if (!Pat.SectionPat.match(S->Name))
+
+ StringRef Filename = basename(Sec);
+ if (!Cmd->FilePat.match(Filename) ||
+ Pat.ExcludedFilePat.match(Filename) ||
+ !Pat.SectionPat.match(Sec->Name))
continue;
- I->Sections.push_back(S);
- S->Assigned = true;
+
+ Ret.push_back(cast<InputSection>(Sec));
+ Sec->Assigned = true;
}
// Sort sections as instructed by SORT-family commands and --sort-section
@@ -245,8 +331,8 @@ void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
// --sort-section is handled as an inner SORT command.
// 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
// 4. If no SORT command is given, sort according to --sort-section.
- InputSectionData **Begin = I->Sections.data() + SizeBefore;
- InputSectionData **End = I->Sections.data() + I->Sections.size();
+ InputSection **Begin = Ret.data() + SizeBefore;
+ InputSection **End = Ret.data() + Ret.size();
if (Pat.SortOuter != SortSectionPolicy::None) {
if (Pat.SortInner == SortSectionPolicy::Default)
sortSections(Begin, End, Config->SortSection);
@@ -255,68 +341,65 @@ void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
sortSections(Begin, End, Pat.SortOuter);
}
}
+ return Ret;
}
-template <class ELFT>
-void LinkerScript<ELFT>::discard(ArrayRef<InputSectionBase<ELFT> *> V) {
- for (InputSectionBase<ELFT> *S : V) {
+void LinkerScript::discard(ArrayRef<InputSectionBase *> V) {
+ for (InputSectionBase *S : V) {
S->Live = false;
- reportDiscarded(S);
+ if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab ||
+ S == InX::DynStrTab)
+ error("discarding " + S->Name + " section is not allowed");
+ discard(S->DependentSections);
}
}
-template <class ELFT>
-std::vector<InputSectionBase<ELFT> *>
-LinkerScript<ELFT>::createInputSectionList(OutputSectionCommand &OutCmd) {
- std::vector<InputSectionBase<ELFT> *> Ret;
+std::vector<InputSectionBase *>
+LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) {
+ std::vector<InputSectionBase *> Ret;
- for (const std::unique_ptr<BaseCommand> &Base : OutCmd.Commands) {
- auto *Cmd = dyn_cast<InputSectionDescription>(Base.get());
+ for (BaseCommand *Base : OutCmd.Commands) {
+ auto *Cmd = dyn_cast<InputSectionDescription>(Base);
if (!Cmd)
continue;
- computeInputSections(Cmd);
- for (InputSectionData *S : Cmd->Sections)
- Ret.push_back(static_cast<InputSectionBase<ELFT> *>(S));
+
+ Cmd->Sections = computeInputSections(Cmd);
+ Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end());
}
return Ret;
}
-template <class ELFT>
-void LinkerScript<ELFT>::addSection(OutputSectionFactory<ELFT> &Factory,
- InputSectionBase<ELFT> *Sec,
- StringRef Name) {
- OutputSectionBase *OutSec;
- bool IsNew;
- std::tie(OutSec, IsNew) = Factory.create(Sec, Name);
- if (IsNew)
- OutputSections->push_back(OutSec);
- OutSec->addSection(Sec);
-}
-
-template <class ELFT>
-void LinkerScript<ELFT>::processCommands(OutputSectionFactory<ELFT> &Factory) {
- for (unsigned I = 0; I < Opt.Commands.size(); ++I) {
- auto Iter = Opt.Commands.begin() + I;
- const std::unique_ptr<BaseCommand> &Base1 = *Iter;
+void LinkerScript::processCommands(OutputSectionFactory &Factory) {
+ // A symbol can be assigned before any section is mentioned in the linker
+ // script. In an DSO, the symbol values are addresses, so the only important
+ // section values are:
+ // * SHN_UNDEF
+ // * SHN_ABS
+ // * Any value meaning a regular section.
+ // To handle that, create a dummy aether section that fills the void before
+ // the linker scripts switches to another section. It has an index of one
+ // which will map to whatever the first actual section is.
+ Aether = make<OutputSection>("", 0, SHF_ALLOC);
+ Aether->SectionIndex = 1;
+ auto State = make_unique<AddressState>(Opt);
+ // CurAddressState captures the local AddressState and makes it accessible
+ // deliberately. This is needed as there are some cases where we cannot just
+ // thread the current state through to a lambda function created by the
+ // script parser.
+ CurAddressState = State.get();
+ CurAddressState->OutSec = Aether;
+ Dot = 0;
+ for (size_t I = 0; I < Opt.Commands.size(); ++I) {
// Handle symbol assignments outside of any output section.
- if (auto *Cmd = dyn_cast<SymbolAssignment>(Base1.get())) {
- addSymbol<ELFT>(Cmd);
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Opt.Commands[I])) {
+ addSymbol(Cmd);
continue;
}
- if (auto *Cmd = dyn_cast<AssertCommand>(Base1.get())) {
- // If we don't have SECTIONS then output sections have already been
- // created by Writer<ELFT>. The LinkerScript<ELFT>::assignAddresses
- // will not be called, so ASSERT should be evaluated now.
- if (!Opt.HasSections)
- Cmd->Expression(0);
- continue;
- }
-
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base1.get())) {
- std::vector<InputSectionBase<ELFT> *> V = createInputSectionList(*Cmd);
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I])) {
+ std::vector<InputSectionBase *> V = createInputSectionList(*Cmd);
// The output section name `/DISCARD/' is special.
// Any input section assigned to it is discarded.
@@ -332,211 +415,288 @@ void LinkerScript<ELFT>::processCommands(OutputSectionFactory<ELFT> &Factory) {
//
// Because we'll iterate over Commands many more times, the easiest
// way to "make it as if it wasn't present" is to just remove it.
- if (!matchConstraints<ELFT>(V, Cmd->Constraint)) {
- for (InputSectionBase<ELFT> *S : V)
+ if (!matchConstraints(V, Cmd->Constraint)) {
+ for (InputSectionBase *S : V)
S->Assigned = false;
- Opt.Commands.erase(Iter);
+ Opt.Commands.erase(Opt.Commands.begin() + I);
--I;
continue;
}
// A directive may contain symbol definitions like this:
// ".foo : { ...; bar = .; }". Handle them.
- for (const std::unique_ptr<BaseCommand> &Base : Cmd->Commands)
- if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base.get()))
- addSymbol<ELFT>(OutCmd);
+ for (BaseCommand *Base : Cmd->Commands)
+ if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base))
+ addSymbol(OutCmd);
// Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
// is given, input sections are aligned to that value, whether the
// given value is larger or smaller than the original section alignment.
if (Cmd->SubalignExpr) {
- uint32_t Subalign = Cmd->SubalignExpr(0);
- for (InputSectionBase<ELFT> *S : V)
+ uint32_t Subalign = Cmd->SubalignExpr().getValue();
+ for (InputSectionBase *S : V)
S->Alignment = Subalign;
}
// Add input sections to an output section.
- for (InputSectionBase<ELFT> *S : V)
- addSection(Factory, S, Cmd->Name);
+ for (InputSectionBase *S : V)
+ Factory.addInputSec(S, Cmd->Name, Cmd->Sec);
+ if (OutputSection *Sec = Cmd->Sec) {
+ assert(Sec->SectionIndex == INT_MAX);
+ Sec->SectionIndex = I;
+ if (Cmd->Noload)
+ Sec->Type = SHT_NOBITS;
+ SecToCommand[Sec] = Cmd;
+ }
+ }
+ }
+ CurAddressState = nullptr;
+}
+
+void LinkerScript::fabricateDefaultCommands() {
+ std::vector<BaseCommand *> Commands;
+
+ // Define start address
+ uint64_t StartAddr = -1;
+
+ // The Sections with -T<section> have been sorted in order of ascending
+ // address. We must lower StartAddr if the lowest -T<section address> as
+ // calls to setDot() must be monotonically increasing.
+ for (auto &KV : Config->SectionStartMap)
+ StartAddr = std::min(StartAddr, KV.second);
+
+ Commands.push_back(make<SymbolAssignment>(
+ ".",
+ [=] {
+ return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize());
+ },
+ ""));
+
+ // For each OutputSection that needs a VA fabricate an OutputSectionCommand
+ // with an InputSectionDescription describing the InputSections
+ for (OutputSection *Sec : OutputSections) {
+ auto *OSCmd = createOutputSectionCommand(Sec->Name, "<internal>");
+ OSCmd->Sec = Sec;
+ SecToCommand[Sec] = OSCmd;
+
+ Commands.push_back(OSCmd);
+ if (Sec->Sections.size()) {
+ auto *ISD = make<InputSectionDescription>("");
+ OSCmd->Commands.push_back(ISD);
+ for (InputSection *ISec : Sec->Sections) {
+ ISD->Sections.push_back(ISec);
+ ISec->Assigned = true;
+ }
}
}
+ // SECTIONS commands run before other non SECTIONS commands
+ Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end());
+ Opt.Commands = std::move(Commands);
}
// Add sections that didn't match any sections command.
-template <class ELFT>
-void LinkerScript<ELFT>::addOrphanSections(
- OutputSectionFactory<ELFT> &Factory) {
- for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections)
- if (S->Live && !S->OutSec)
- addSection(Factory, S, getOutputSectionName(S->Name));
-}
-
-// Sets value of a section-defined symbol. Two kinds of
-// symbols are processed: synthetic symbols, whose value
-// is an offset from beginning of section and regular
-// symbols whose value is absolute.
-template <class ELFT>
-static void assignSectionSymbol(SymbolAssignment *Cmd,
- typename ELFT::uint Value) {
- if (!Cmd->Sym)
- return;
-
- if (auto *Body = dyn_cast<DefinedSynthetic>(Cmd->Sym)) {
- Body->Section = Cmd->Expression.Section();
- Body->Value = Cmd->Expression(Value) - Body->Section->Addr;
- return;
+void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
+ unsigned NumCommands = Opt.Commands.size();
+ for (InputSectionBase *S : InputSections) {
+ if (!S->Live || S->Parent)
+ continue;
+ StringRef Name = getOutputSectionName(S->Name);
+ auto End = Opt.Commands.begin() + NumCommands;
+ auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ return Cmd->Name == Name;
+ return false;
+ });
+ OutputSectionCommand *Cmd;
+ if (I == End) {
+ Factory.addInputSec(S, Name);
+ OutputSection *Sec = S->getOutputSection();
+ assert(Sec->SectionIndex == INT_MAX);
+ OutputSectionCommand *&CmdRef = SecToCommand[Sec];
+ if (!CmdRef) {
+ CmdRef = createOutputSectionCommand(Sec->Name, "<internal>");
+ CmdRef->Sec = Sec;
+ Opt.Commands.push_back(CmdRef);
+ }
+ Cmd = CmdRef;
+ } else {
+ Cmd = cast<OutputSectionCommand>(*I);
+ Factory.addInputSec(S, Name, Cmd->Sec);
+ if (OutputSection *Sec = Cmd->Sec) {
+ SecToCommand[Sec] = Cmd;
+ unsigned Index = std::distance(Opt.Commands.begin(), I);
+ assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index);
+ Sec->SectionIndex = Index;
+ }
+ }
+ auto *ISD = make<InputSectionDescription>("");
+ ISD->Sections.push_back(cast<InputSection>(S));
+ Cmd->Commands.push_back(ISD);
}
- auto *Body = cast<DefinedRegular<ELFT>>(Cmd->Sym);
- Body->Value = Cmd->Expression(Value);
}
-template <class ELFT> static bool isTbss(OutputSectionBase *Sec) {
- return (Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS;
-}
+uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) {
+ bool IsTbss = (CurAddressState->OutSec->Flags & SHF_TLS) &&
+ CurAddressState->OutSec->Type == SHT_NOBITS;
+ uint64_t Start = IsTbss ? Dot + CurAddressState->ThreadBssOffset : Dot;
+ Start = alignTo(Start, Align);
+ uint64_t End = Start + Size;
-template <class ELFT> void LinkerScript<ELFT>::output(InputSection<ELFT> *S) {
- if (!AlreadyOutputIS.insert(S).second)
- return;
- bool IsTbss = isTbss<ELFT>(CurOutSec);
+ if (IsTbss)
+ CurAddressState->ThreadBssOffset = End - Dot;
+ else
+ Dot = End;
+ return End;
+}
- uintX_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot;
- Pos = alignTo(Pos, S->Alignment);
- S->OutSecOff = Pos - CurOutSec->Addr;
- Pos += S->getSize();
+void LinkerScript::output(InputSection *S) {
+ uint64_t Pos = advance(S->getSize(), S->Alignment);
+ S->OutSecOff = Pos - S->getSize() - CurAddressState->OutSec->Addr;
// Update output section size after adding each section. This is so that
// SIZEOF works correctly in the case below:
// .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
- CurOutSec->Size = Pos - CurOutSec->Addr;
-
- if (IsTbss)
- ThreadBssOffset = Pos - Dot;
- else
- Dot = Pos;
-}
-
-template <class ELFT> void LinkerScript<ELFT>::flush() {
- if (!CurOutSec || !AlreadyOutputOS.insert(CurOutSec).second)
- return;
- if (auto *OutSec = dyn_cast<OutputSection<ELFT>>(CurOutSec)) {
- for (InputSection<ELFT> *I : OutSec->Sections)
- output(I);
- } else {
- Dot += CurOutSec->Size;
+ CurAddressState->OutSec->Size = Pos - CurAddressState->OutSec->Addr;
+
+ // If there is a memory region associated with this input section, then
+ // place the section in that region and update the region index.
+ if (CurAddressState->MemRegion) {
+ uint64_t &CurOffset =
+ CurAddressState->MemRegionOffset[CurAddressState->MemRegion];
+ CurOffset += CurAddressState->OutSec->Size;
+ uint64_t CurSize = CurOffset - CurAddressState->MemRegion->Origin;
+ if (CurSize > CurAddressState->MemRegion->Length) {
+ uint64_t OverflowAmt = CurSize - CurAddressState->MemRegion->Length;
+ error("section '" + CurAddressState->OutSec->Name +
+ "' will not fit in region '" + CurAddressState->MemRegion->Name +
+ "': overflowed by " + Twine(OverflowAmt) + " bytes");
+ }
}
}
-template <class ELFT>
-void LinkerScript<ELFT>::switchTo(OutputSectionBase *Sec) {
- if (CurOutSec == Sec)
- return;
- if (AlreadyOutputOS.count(Sec))
+void LinkerScript::switchTo(OutputSection *Sec) {
+ if (CurAddressState->OutSec == Sec)
return;
- flush();
- CurOutSec = Sec;
-
- Dot = alignTo(Dot, CurOutSec->Addralign);
- CurOutSec->Addr = isTbss<ELFT>(CurOutSec) ? Dot + ThreadBssOffset : Dot;
+ CurAddressState->OutSec = Sec;
+ CurAddressState->OutSec->Addr =
+ advance(0, CurAddressState->OutSec->Alignment);
// If neither AT nor AT> is specified for an allocatable section, the linker
// will set the LMA such that the difference between VMA and LMA for the
// section is the same as the preceding output section in the same region
// https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
- CurOutSec->setLMAOffset(LMAOffset);
+ if (CurAddressState->LMAOffset)
+ CurAddressState->OutSec->LMAOffset = CurAddressState->LMAOffset();
}
-template <class ELFT> void LinkerScript<ELFT>::process(BaseCommand &Base) {
- // This handles the assignments to symbol or to a location counter (.)
- if (auto *AssignCmd = dyn_cast<SymbolAssignment>(&Base)) {
- if (AssignCmd->Name == ".") {
- // Update to location counter means update to section size.
- uintX_t Val = AssignCmd->Expression(Dot);
- if (Val < Dot)
- error("unable to move location counter backward for: " +
- CurOutSec->Name);
- Dot = Val;
- CurOutSec->Size = Dot - CurOutSec->Addr;
- return;
- }
- assignSectionSymbol<ELFT>(AssignCmd, Dot);
+void LinkerScript::process(BaseCommand &Base) {
+ // This handles the assignments to symbol or to the dot.
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(&Base)) {
+ assignSymbol(Cmd, true);
return;
}
// Handle BYTE(), SHORT(), LONG(), or QUAD().
- if (auto *DataCmd = dyn_cast<BytesDataCommand>(&Base)) {
- DataCmd->Offset = Dot - CurOutSec->Addr;
- Dot += DataCmd->Size;
- CurOutSec->Size = Dot - CurOutSec->Addr;
+ if (auto *Cmd = dyn_cast<BytesDataCommand>(&Base)) {
+ Cmd->Offset = Dot - CurAddressState->OutSec->Addr;
+ Dot += Cmd->Size;
+ CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr;
return;
}
- if (auto *AssertCmd = dyn_cast<AssertCommand>(&Base)) {
- AssertCmd->Expression(Dot);
+ // Handle ASSERT().
+ if (auto *Cmd = dyn_cast<AssertCommand>(&Base)) {
+ Cmd->Expression();
return;
}
- // It handles single input section description command,
- // calculates and assigns the offsets for each section and also
+ // Handle a single input section description command.
+ // It calculates and assigns the offsets for each section and also
// updates the output section size.
- auto &ICmd = cast<InputSectionDescription>(Base);
- for (InputSectionData *ID : ICmd.Sections) {
+ auto &Cmd = cast<InputSectionDescription>(Base);
+ for (InputSection *Sec : Cmd.Sections) {
// We tentatively added all synthetic sections at the beginning and removed
// empty ones afterwards (because there is no way to know whether they were
// going be empty or not other than actually running linker scripts.)
// We need to ignore remains of empty sections.
- if (auto *Sec = dyn_cast<SyntheticSection<ELFT>>(ID))
- if (Sec->empty())
+ if (auto *S = dyn_cast<SyntheticSection>(Sec))
+ if (S->empty())
continue;
- auto *IB = static_cast<InputSectionBase<ELFT> *>(ID);
- switchTo(IB->OutSec);
- if (auto *I = dyn_cast<InputSection<ELFT>>(IB))
- output(I);
- else
- flush();
+ if (!Sec->Live)
+ continue;
+ assert(CurAddressState->OutSec == Sec->getParent());
+ output(Sec);
+ }
+}
+
+// This function searches for a memory region to place the given output
+// section in. If found, a pointer to the appropriate memory region is
+// returned. Otherwise, a nullptr is returned.
+MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) {
+ // If a memory region name was specified in the output section command,
+ // then try to find that region first.
+ if (!Cmd->MemoryRegionName.empty()) {
+ auto It = Opt.MemoryRegions.find(Cmd->MemoryRegionName);
+ if (It != Opt.MemoryRegions.end())
+ return &It->second;
+ error("memory region '" + Cmd->MemoryRegionName + "' not declared");
+ return nullptr;
}
-}
-template <class ELFT>
-static std::vector<OutputSectionBase *>
-findSections(StringRef Name, const std::vector<OutputSectionBase *> &Sections) {
- std::vector<OutputSectionBase *> Ret;
- for (OutputSectionBase *Sec : Sections)
- if (Sec->getName() == Name)
- Ret.push_back(Sec);
- return Ret;
+ // If at least one memory region is defined, all sections must
+ // belong to some memory region. Otherwise, we don't need to do
+ // anything for memory regions.
+ if (Opt.MemoryRegions.empty())
+ return nullptr;
+
+ OutputSection *Sec = Cmd->Sec;
+ // See if a region can be found by matching section flags.
+ for (auto &Pair : Opt.MemoryRegions) {
+ MemoryRegion &M = Pair.second;
+ if ((M.Flags & Sec->Flags) && (M.NegFlags & Sec->Flags) == 0)
+ return &M;
+ }
+
+ // Otherwise, no suitable region was found.
+ if (Sec->Flags & SHF_ALLOC)
+ error("no memory region specified for section '" + Sec->Name + "'");
+ return nullptr;
}
// This function assigns offsets to input sections and an output section
// for a single sections command (e.g. ".text { *(.text); }").
-template <class ELFT>
-void LinkerScript<ELFT>::assignOffsets(OutputSectionCommand *Cmd) {
- if (Cmd->LMAExpr)
- LMAOffset = Cmd->LMAExpr(Dot) - Dot;
- std::vector<OutputSectionBase *> Sections =
- findSections<ELFT>(Cmd->Name, *OutputSections);
- if (Sections.empty())
+void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) {
+ OutputSection *Sec = Cmd->Sec;
+ if (!Sec)
return;
- switchTo(Sections[0]);
-
- // Find the last section output location. We will output orphan sections
- // there so that end symbols point to the correct location.
- auto E = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
- [](const std::unique_ptr<BaseCommand> &Cmd) {
- return !isa<SymbolAssignment>(*Cmd);
- })
- .base();
- for (auto I = Cmd->Commands.begin(); I != E; ++I)
- process(**I);
- for (OutputSectionBase *Base : Sections)
- switchTo(Base);
- flush();
- std::for_each(E, Cmd->Commands.end(),
- [this](std::unique_ptr<BaseCommand> &B) { process(*B.get()); });
+
+ if (!(Sec->Flags & SHF_ALLOC))
+ Dot = 0;
+ else if (Cmd->AddrExpr)
+ setDot(Cmd->AddrExpr, Cmd->Location, false);
+
+ if (Cmd->LMAExpr) {
+ uint64_t D = Dot;
+ CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; };
+ }
+
+ CurAddressState->MemRegion = Cmd->MemRegion;
+ if (CurAddressState->MemRegion)
+ Dot = CurAddressState->MemRegionOffset[CurAddressState->MemRegion];
+ switchTo(Sec);
+
+ // We do not support custom layout for compressed debug sectons.
+ // At this point we already know their size and have compressed content.
+ if (CurAddressState->OutSec->Flags & SHF_COMPRESSED)
+ return;
+
+ for (BaseCommand *C : Cmd->Commands)
+ process(*C);
}
-template <class ELFT> void LinkerScript<ELFT>::removeEmptyCommands() {
+void LinkerScript::removeEmptyCommands() {
// It is common practice to use very generic linker scripts. So for any
// given run some of the output sections in the script will be empty.
// We could create corresponding empty output sections, but that would
@@ -544,51 +704,57 @@ template <class ELFT> void LinkerScript<ELFT>::removeEmptyCommands() {
// We instead remove trivially empty sections. The bfd linker seems even
// more aggressive at removing them.
auto Pos = std::remove_if(
- Opt.Commands.begin(), Opt.Commands.end(),
- [&](const std::unique_ptr<BaseCommand> &Base) {
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
- return findSections<ELFT>(Cmd->Name, *OutputSections).empty();
+ Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ return Cmd->Sec == nullptr;
return false;
});
Opt.Commands.erase(Pos, Opt.Commands.end());
}
static bool isAllSectionDescription(const OutputSectionCommand &Cmd) {
- for (const std::unique_ptr<BaseCommand> &I : Cmd.Commands)
- if (!isa<InputSectionDescription>(*I))
+ for (BaseCommand *Base : Cmd.Commands)
+ if (!isa<InputSectionDescription>(*Base))
return false;
return true;
}
-template <class ELFT> void LinkerScript<ELFT>::adjustSectionsBeforeSorting() {
+void LinkerScript::adjustSectionsBeforeSorting() {
// If the output section contains only symbol assignments, create a
// corresponding output section. The bfd linker seems to only create them if
// '.' is assigned to, but creating these section should not have any bad
// consequeces and gives us a section to put the symbol in.
- uintX_t Flags = SHF_ALLOC;
- uint32_t Type = SHT_NOBITS;
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+ uint64_t Flags = SHF_ALLOC;
+
+ for (int I = 0, E = Opt.Commands.size(); I != E; ++I) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]);
if (!Cmd)
continue;
- std::vector<OutputSectionBase *> Secs =
- findSections<ELFT>(Cmd->Name, *OutputSections);
- if (!Secs.empty()) {
- Flags = Secs[0]->Flags;
- Type = Secs[0]->Type;
+ if (OutputSection *Sec = Cmd->Sec) {
+ Flags = Sec->Flags;
continue;
}
if (isAllSectionDescription(*Cmd))
continue;
- auto *OutSec = make<OutputSection<ELFT>>(Cmd->Name, Type, Flags);
- OutputSections->push_back(OutSec);
+ auto *OutSec = make<OutputSection>(Cmd->Name, SHT_PROGBITS, Flags);
+ OutSec->SectionIndex = I;
+ Cmd->Sec = OutSec;
+ SecToCommand[OutSec] = Cmd;
}
}
-template <class ELFT> void LinkerScript<ELFT>::adjustSectionsAfterSorting() {
- placeOrphanSections();
+void LinkerScript::adjustSectionsAfterSorting() {
+ // Try and find an appropriate memory region to assign offsets in.
+ for (BaseCommand *Base : Opt.Commands) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) {
+ Cmd->MemRegion = findMemoryRegion(Cmd);
+ // Handle align (e.g. ".foo : ALIGN(16) { ... }").
+ if (Cmd->AlignExpr)
+ Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue());
+ }
+ }
// If output section command doesn't specify any segments,
// and we haven't previously assigned any section to segment,
@@ -605,149 +771,119 @@ template <class ELFT> void LinkerScript<ELFT>::adjustSectionsAfterSorting() {
// Walk the commands and propagate the program headers to commands that don't
// explicitly specify them.
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+ for (BaseCommand *Base : Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd)
continue;
- if (Cmd->Phdrs.empty())
- Cmd->Phdrs = DefPhdrs;
- else
+
+ if (Cmd->Phdrs.empty()) {
+ OutputSection *Sec = Cmd->Sec;
+ // To match the bfd linker script behaviour, only propagate program
+ // headers to sections that are allocated.
+ if (Sec && (Sec->Flags & SHF_ALLOC))
+ Cmd->Phdrs = DefPhdrs;
+ } else {
DefPhdrs = Cmd->Phdrs;
+ }
}
removeEmptyCommands();
}
-// When placing orphan sections, we want to place them after symbol assignments
-// so that an orphan after
-// begin_foo = .;
-// foo : { *(foo) }
-// end_foo = .;
-// doesn't break the intended meaning of the begin/end symbols.
-// We don't want to go over sections since Writer<ELFT>::sortSections is the
-// one in charge of deciding the order of the sections.
-// We don't want to go over alignments, since doing so in
-// rx_sec : { *(rx_sec) }
-// . = ALIGN(0x1000);
-// /* The RW PT_LOAD starts here*/
-// rw_sec : { *(rw_sec) }
-// would mean that the RW PT_LOAD would become unaligned.
-static bool shouldSkip(const BaseCommand &Cmd) {
- if (isa<OutputSectionCommand>(Cmd))
- return false;
- const auto *Assign = dyn_cast<SymbolAssignment>(&Cmd);
- if (!Assign)
- return true;
- return Assign->Name != ".";
+void LinkerScript::processNonSectionCommands() {
+ for (BaseCommand *Base : Opt.Commands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
+ assignSymbol(Cmd, false);
+ else if (auto *Cmd = dyn_cast<AssertCommand>(Base))
+ Cmd->Expression();
+ }
}
-// Orphan sections are sections present in the input files which are not
-// explicitly placed into the output file by the linker script. This just
-// places them in the order already decided in OutputSections.
-template <class ELFT> void LinkerScript<ELFT>::placeOrphanSections() {
- // The OutputSections are already in the correct order.
- // This loops creates or moves commands as needed so that they are in the
- // correct order.
- int CmdIndex = 0;
-
- // As a horrible special case, skip the first . assignment if it is before any
- // section. We do this because it is common to set a load address by starting
- // the script with ". = 0xabcd" and the expectation is that every section is
- // after that.
- auto FirstSectionOrDotAssignment =
- std::find_if(Opt.Commands.begin(), Opt.Commands.end(),
- [](const std::unique_ptr<BaseCommand> &Cmd) {
- if (isa<OutputSectionCommand>(*Cmd))
- return true;
- const auto *Assign = dyn_cast<SymbolAssignment>(Cmd.get());
- if (!Assign)
- return false;
- return Assign->Name == ".";
- });
- if (FirstSectionOrDotAssignment != Opt.Commands.end()) {
- CmdIndex = FirstSectionOrDotAssignment - Opt.Commands.begin();
- if (isa<SymbolAssignment>(**FirstSectionOrDotAssignment))
- ++CmdIndex;
+void LinkerScript::allocateHeaders(std::vector<PhdrEntry> &Phdrs) {
+ uint64_t Min = std::numeric_limits<uint64_t>::max();
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
+ if (Sec->Flags & SHF_ALLOC)
+ Min = std::min<uint64_t>(Min, Sec->Addr);
}
- for (OutputSectionBase *Sec : *OutputSections) {
- StringRef Name = Sec->getName();
+ auto FirstPTLoad = llvm::find_if(
+ Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
+ if (FirstPTLoad == Phdrs.end())
+ return;
- // Find the last spot where we can insert a command and still get the
- // correct result.
- auto CmdIter = Opt.Commands.begin() + CmdIndex;
- auto E = Opt.Commands.end();
- while (CmdIter != E && shouldSkip(**CmdIter)) {
- ++CmdIter;
- ++CmdIndex;
- }
+ uint64_t HeaderSize = getHeaderSize();
+ if (HeaderSize <= Min || Script->hasPhdrsCommands()) {
+ Min = alignDown(Min - HeaderSize, Config->MaxPageSize);
+ Out::ElfHeader->Addr = Min;
+ Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size;
+ return;
+ }
- auto Pos =
- std::find_if(CmdIter, E, [&](const std::unique_ptr<BaseCommand> &Base) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
- return Cmd && Cmd->Name == Name;
- });
- if (Pos == E) {
- Opt.Commands.insert(CmdIter,
- llvm::make_unique<OutputSectionCommand>(Name));
- ++CmdIndex;
- continue;
+ assert(FirstPTLoad->First == Out::ElfHeader);
+ OutputSection *ActualFirst = nullptr;
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
+ if (Sec->FirstInPtLoad == Out::ElfHeader) {
+ ActualFirst = Sec;
+ break;
+ }
+ }
+ if (ActualFirst) {
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
+ if (Sec->FirstInPtLoad == Out::ElfHeader)
+ Sec->FirstInPtLoad = ActualFirst;
}
+ FirstPTLoad->First = ActualFirst;
+ } else {
+ Phdrs.erase(FirstPTLoad);
+ }
- // Continue from where we found it.
- CmdIndex = (Pos - Opt.Commands.begin()) + 1;
+ auto PhdrI = llvm::find_if(
+ Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_PHDR; });
+ if (PhdrI != Phdrs.end())
+ Phdrs.erase(PhdrI);
+}
+
+LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) {
+ for (auto &MRI : Opt.MemoryRegions) {
+ const MemoryRegion *MR = &MRI.second;
+ MemRegionOffset[MR] = MR->Origin;
}
}
-template <class ELFT>
-void LinkerScript<ELFT>::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
+void LinkerScript::assignAddresses() {
// Assign addresses as instructed by linker script SECTIONS sub-commands.
Dot = 0;
-
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get())) {
- if (Cmd->Name == ".") {
- Dot = Cmd->Expression(Dot);
- } else if (Cmd->Sym) {
- assignSectionSymbol<ELFT>(Cmd, Dot);
- }
+ auto State = make_unique<AddressState>(Opt);
+ // CurAddressState captures the local AddressState and makes it accessible
+ // deliberately. This is needed as there are some cases where we cannot just
+ // thread the current state through to a lambda function created by the
+ // script parser.
+ CurAddressState = State.get();
+ ErrorOnMissingSection = true;
+ switchTo(Aether);
+
+ for (BaseCommand *Base : Opt.Commands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ assignSymbol(Cmd, false);
continue;
}
- if (auto *Cmd = dyn_cast<AssertCommand>(Base.get())) {
- Cmd->Expression(Dot);
+ if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
+ Cmd->Expression();
continue;
}
- auto *Cmd = cast<OutputSectionCommand>(Base.get());
- if (Cmd->AddrExpr)
- Dot = Cmd->AddrExpr(Dot);
+ auto *Cmd = cast<OutputSectionCommand>(Base);
assignOffsets(Cmd);
}
-
- uintX_t MinVA = std::numeric_limits<uintX_t>::max();
- for (OutputSectionBase *Sec : *OutputSections) {
- if (Sec->Flags & SHF_ALLOC)
- MinVA = std::min<uint64_t>(MinVA, Sec->Addr);
- else
- Sec->Addr = 0;
- }
-
- uintX_t HeaderSize = getHeaderSize();
- // If the linker script doesn't have PHDRS, add ElfHeader and ProgramHeaders
- // now that we know we have space.
- if (HeaderSize <= MinVA && !hasPhdrsCommands())
- allocateHeaders<ELFT>(Phdrs, *OutputSections);
-
- // ELF and Program headers need to be right before the first section in
- // memory. Set their addresses accordingly.
- MinVA = alignDown(MinVA - HeaderSize, Config->MaxPageSize);
- Out<ELFT>::ElfHeader->Addr = MinVA;
- Out<ELFT>::ProgramHeaders->Addr = Out<ELFT>::ElfHeader->Size + MinVA;
+ CurAddressState = nullptr;
}
// Creates program headers as instructed by PHDRS linker script command.
-template <class ELFT> std::vector<PhdrEntry> LinkerScript<ELFT>::createPhdrs() {
+std::vector<PhdrEntry> LinkerScript::createPhdrs() {
std::vector<PhdrEntry> Ret;
// Process PHDRS and FILEHDR keywords because they are not
@@ -757,23 +893,21 @@ template <class ELFT> std::vector<PhdrEntry> LinkerScript<ELFT>::createPhdrs() {
PhdrEntry &Phdr = Ret.back();
if (Cmd.HasFilehdr)
- Phdr.add(Out<ELFT>::ElfHeader);
+ Phdr.add(Out::ElfHeader);
if (Cmd.HasPhdrs)
- Phdr.add(Out<ELFT>::ProgramHeaders);
+ Phdr.add(Out::ProgramHeaders);
if (Cmd.LMAExpr) {
- Phdr.p_paddr = Cmd.LMAExpr(0);
+ Phdr.p_paddr = Cmd.LMAExpr().getValue();
Phdr.HasLMA = true;
}
}
// Add output sections to program headers.
- for (OutputSectionBase *Sec : *OutputSections) {
- if (!(Sec->Flags & SHF_ALLOC))
- break;
-
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
// Assign headers specified by linker script
- for (size_t Id : getPhdrIndices(Sec->getName())) {
+ for (size_t Id : getPhdrIndices(Cmd)) {
+ OutputSection *Sec = Cmd->Sec;
Ret[Id].add(Sec);
if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
Ret[Id].p_flags |= Sec->getPhdrFlags();
@@ -782,1177 +916,340 @@ template <class ELFT> std::vector<PhdrEntry> LinkerScript<ELFT>::createPhdrs() {
return Ret;
}
-template <class ELFT> bool LinkerScript<ELFT>::ignoreInterpSection() {
+bool LinkerScript::ignoreInterpSection() {
// Ignore .interp section in case we have PHDRS specification
// and PT_INTERP isn't listed.
- return !Opt.PhdrsCommands.empty() &&
- llvm::find_if(Opt.PhdrsCommands, [](const PhdrsCommand &Cmd) {
- return Cmd.Type == PT_INTERP;
- }) == Opt.PhdrsCommands.end();
-}
-
-template <class ELFT> uint32_t LinkerScript<ELFT>::getFiller(StringRef Name) {
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
- if (Cmd->Name == Name)
- return Cmd->Filler;
- return 0;
-}
-
-template <class ELFT>
-static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
- const endianness E = ELFT::TargetEndianness;
-
- switch (Size) {
- case 1:
- *Buf = (uint8_t)Data;
- break;
- case 2:
- write16<E>(Buf, Data);
- break;
- case 4:
- write32<E>(Buf, Data);
- break;
- case 8:
- write64<E>(Buf, Data);
- break;
- default:
- llvm_unreachable("unsupported Size argument");
- }
+ if (Opt.PhdrsCommands.empty())
+ return false;
+ for (PhdrsCommand &Cmd : Opt.PhdrsCommands)
+ if (Cmd.Type == PT_INTERP)
+ return false;
+ return true;
}
-template <class ELFT>
-void LinkerScript<ELFT>::writeDataBytes(StringRef Name, uint8_t *Buf) {
- int I = getSectionIndex(Name);
- if (I == INT_MAX)
- return;
-
- auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I].get());
- for (const std::unique_ptr<BaseCommand> &Base : Cmd->Commands)
- if (auto *Data = dyn_cast<BytesDataCommand>(Base.get()))
- writeInt<ELFT>(Buf + Data->Offset, Data->Expression(0), Data->Size);
+OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {
+ auto I = SecToCommand.find(Sec);
+ if (I == SecToCommand.end())
+ return nullptr;
+ return I->second;
}
-template <class ELFT> bool LinkerScript<ELFT>::hasLMA(StringRef Name) {
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
- if (Cmd->LMAExpr && Cmd->Name == Name)
- return true;
- return false;
-}
+void OutputSectionCommand::sort(std::function<int(InputSectionBase *S)> Order) {
+ typedef std::pair<unsigned, InputSection *> Pair;
+ auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
-// Returns the index of the given section name in linker script
-// SECTIONS commands. Sections are laid out as the same order as they
-// were in the script. If a given name did not appear in the script,
-// it returns INT_MAX, so that it will be laid out at end of file.
-template <class ELFT> int LinkerScript<ELFT>::getSectionIndex(StringRef Name) {
- for (int I = 0, E = Opt.Commands.size(); I != E; ++I)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I].get()))
- if (Cmd->Name == Name)
- return I;
- return INT_MAX;
+ std::vector<Pair> V;
+ assert(Commands.size() == 1);
+ auto *ISD = cast<InputSectionDescription>(Commands[0]);
+ for (InputSection *S : ISD->Sections)
+ V.push_back({Order(S), S});
+ std::stable_sort(V.begin(), V.end(), Comp);
+ ISD->Sections.clear();
+ for (Pair &P : V)
+ ISD->Sections.push_back(P.second);
}
-template <class ELFT> bool LinkerScript<ELFT>::hasPhdrsCommands() {
- return !Opt.PhdrsCommands.empty();
+// Returns true if S matches /Filename.?\.o$/.
+static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
+ if (!S.endswith(".o"))
+ return false;
+ S = S.drop_back(2);
+ if (S.endswith(Filename))
+ return true;
+ return !S.empty() && S.drop_back().endswith(Filename);
}
-template <class ELFT>
-const OutputSectionBase *LinkerScript<ELFT>::getOutputSection(const Twine &Loc,
- StringRef Name) {
- static OutputSectionBase FakeSec("", 0, 0);
-
- for (OutputSectionBase *Sec : *OutputSections)
- if (Sec->getName() == Name)
- return Sec;
+static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
+static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
- error(Loc + ": undefined section " + Name);
- return &FakeSec;
-}
-
-// This function is essentially the same as getOutputSection(Name)->Size,
-// but it won't print out an error message if a given section is not found.
+// .ctors and .dtors are sorted by this priority from highest to lowest.
//
-// Linker script does not create an output section if its content is empty.
-// We want to allow SIZEOF(.foo) where .foo is a section which happened to
-// be empty. That is why this function is different from getOutputSection().
-template <class ELFT>
-uint64_t LinkerScript<ELFT>::getOutputSectionSize(StringRef Name) {
- for (OutputSectionBase *Sec : *OutputSections)
- if (Sec->getName() == Name)
- return Sec->Size;
- return 0;
-}
-
-template <class ELFT> uint64_t LinkerScript<ELFT>::getHeaderSize() {
- return elf::getHeaderSize<ELFT>();
-}
-
-template <class ELFT>
-uint64_t LinkerScript<ELFT>::getSymbolValue(const Twine &Loc, StringRef S) {
- if (SymbolBody *B = Symtab<ELFT>::X->find(S))
- return B->getVA<ELFT>();
- error(Loc + ": symbol not found: " + S);
+// 1. The section was contained in crtbegin (crtbegin contains
+// some sentinel value in its .ctors and .dtors so that the runtime
+// can find the beginning of the sections.)
+//
+// 2. The section has an optional priority value in the form of ".ctors.N"
+// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
+// they are compared as string rather than number.
+//
+// 3. The section is just ".ctors" or ".dtors".
+//
+// 4. The section was contained in crtend, which contains an end marker.
+//
+// In an ideal world, we don't need this function because .init_array and
+// .ctors are duplicate features (and .init_array is newer.) However, there
+// are too many real-world use cases of .ctors, so we had no choice to
+// support that with this rather ad-hoc semantics.
+static bool compCtors(const InputSection *A, const InputSection *B) {
+ bool BeginA = isCrtbegin(A->File->getName());
+ bool BeginB = isCrtbegin(B->File->getName());
+ if (BeginA != BeginB)
+ return BeginA;
+ bool EndA = isCrtend(A->File->getName());
+ bool EndB = isCrtend(B->File->getName());
+ if (EndA != EndB)
+ return EndB;
+ StringRef X = A->Name;
+ StringRef Y = B->Name;
+ assert(X.startswith(".ctors") || X.startswith(".dtors"));
+ assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
+ X = X.substr(6);
+ Y = Y.substr(6);
+ if (X.empty() && Y.empty())
+ return false;
+ return X < Y;
+}
+
+// Sorts input sections by the special rules for .ctors and .dtors.
+// Unfortunately, the rules are different from the one for .{init,fini}_array.
+// Read the comment above.
+void OutputSectionCommand::sortCtorsDtors() {
+ assert(Commands.size() == 1);
+ auto *ISD = cast<InputSectionDescription>(Commands[0]);
+ std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors);
+}
+
+// Sorts input sections by section name suffixes, so that .foo.N comes
+// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
+// We want to keep the original order if the priorities are the same
+// because the compiler keeps the original initialization order in a
+// translation unit and we need to respect that.
+// For more detail, read the section of the GCC's manual about init_priority.
+void OutputSectionCommand::sortInitFini() {
+ // Sort sections by priority.
+ sort([](InputSectionBase *S) { return getPriority(S->Name); });
+}
+
+uint32_t OutputSectionCommand::getFiller() {
+ if (Filler)
+ return *Filler;
+ if (Sec->Flags & SHF_EXECINSTR)
+ return Target->TrapInstr;
return 0;
}
-template <class ELFT> bool LinkerScript<ELFT>::isDefined(StringRef S) {
- return Symtab<ELFT>::X->find(S) != nullptr;
-}
-
-template <class ELFT> bool LinkerScript<ELFT>::isAbsolute(StringRef S) {
- SymbolBody *Sym = Symtab<ELFT>::X->find(S);
- auto *DR = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym);
- return DR && !DR->Section;
+static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
+ if (Size == 1)
+ *Buf = Data;
+ else if (Size == 2)
+ write16(Buf, Data, Config->Endianness);
+ else if (Size == 4)
+ write32(Buf, Data, Config->Endianness);
+ else if (Size == 8)
+ write64(Buf, Data, Config->Endianness);
+ else
+ llvm_unreachable("unsupported Size argument");
}
-// Gets section symbol belongs to. Symbol "." doesn't belong to any
-// specific section but isn't absolute at the same time, so we try
-// to find suitable section for it as well.
-template <class ELFT>
-const OutputSectionBase *LinkerScript<ELFT>::getSymbolSection(StringRef S) {
- SymbolBody *Sym = Symtab<ELFT>::X->find(S);
- if (!Sym) {
- if (OutputSections->empty())
- return nullptr;
- return CurOutSec ? CurOutSec : (*OutputSections)[0];
- }
-
- return SymbolTableSection<ELFT>::getOutputSection(Sym);
+static bool compareByFilePosition(InputSection *A, InputSection *B) {
+ // Synthetic doesn't have link order dependecy, stable_sort will keep it last
+ if (A->kind() == InputSectionBase::Synthetic ||
+ B->kind() == InputSectionBase::Synthetic)
+ return false;
+ InputSection *LA = A->getLinkOrderDep();
+ InputSection *LB = B->getLinkOrderDep();
+ OutputSection *AOut = LA->getParent();
+ OutputSection *BOut = LB->getParent();
+ if (AOut != BOut)
+ return AOut->SectionIndex < BOut->SectionIndex;
+ return LA->OutSecOff < LB->OutSecOff;
}
-// Returns indices of ELF headers containing specific section, identified
-// by Name. Each index is a zero based number of ELF header listed within
-// PHDRS {} script block.
template <class ELFT>
-std::vector<size_t> LinkerScript<ELFT>::getPhdrIndices(StringRef SectionName) {
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
- if (!Cmd || Cmd->Name != SectionName)
- continue;
+static void finalizeShtGroup(OutputSection *OS,
+ ArrayRef<InputSection *> Sections) {
+ assert(Config->Relocatable && Sections.size() == 1);
+
+ // sh_link field for SHT_GROUP sections should contain the section index of
+ // the symbol table.
+ OS->Link = InX::SymTab->getParent()->SectionIndex;
+
+ // sh_info then contain index of an entry in symbol table section which
+ // provides signature of the section group.
+ elf::ObjectFile<ELFT> *Obj = Sections[0]->getFile<ELFT>();
+ ArrayRef<SymbolBody *> Symbols = Obj->getSymbols();
+ OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]);
+}
+
+template <class ELFT> void OutputSectionCommand::finalize() {
+ // Link order may be distributed across several InputSectionDescriptions
+ // but sort must consider them all at once.
+ std::vector<InputSection **> ScriptSections;
+ std::vector<InputSection *> Sections;
+ for (BaseCommand *Base : Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ for (InputSection *&IS : ISD->Sections) {
+ ScriptSections.push_back(&IS);
+ Sections.push_back(IS);
+ }
- std::vector<size_t> Ret;
- for (StringRef PhdrName : Cmd->Phdrs)
- Ret.push_back(getPhdrIndex(Cmd->Location, PhdrName));
- return Ret;
- }
- return {};
-}
+ if ((Sec->Flags & SHF_LINK_ORDER)) {
+ std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition);
+ for (int I = 0, N = Sections.size(); I < N; ++I)
+ *ScriptSections[I] = Sections[I];
-template <class ELFT>
-size_t LinkerScript<ELFT>::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
- size_t I = 0;
- for (PhdrsCommand &Cmd : Opt.PhdrsCommands) {
- if (Cmd.Name == PhdrName)
- return I;
- ++I;
+ // We must preserve the link order dependency of sections with the
+ // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
+ // need to translate the InputSection sh_link to the OutputSection sh_link,
+ // all InputSections in the OutputSection have the same dependency.
+ if (auto *D = Sections.front()->getLinkOrderDep())
+ Sec->Link = D->getParent()->SectionIndex;
}
- error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
- return 0;
-}
-
-class elf::ScriptParser final : public ScriptParserBase {
- typedef void (ScriptParser::*Handler)();
-
-public:
- ScriptParser(MemoryBufferRef MB)
- : ScriptParserBase(MB),
- IsUnderSysroot(isUnderSysroot(MB.getBufferIdentifier())) {}
-
- void readLinkerScript();
- void readVersionScript();
- void readDynamicList();
-
-private:
- void addFile(StringRef Path);
-
- void readAsNeeded();
- void readEntry();
- void readExtern();
- void readGroup();
- void readInclude();
- void readOutput();
- void readOutputArch();
- void readOutputFormat();
- void readPhdrs();
- void readSearchDir();
- void readSections();
- void readVersion();
- void readVersionScriptCommand();
-
- SymbolAssignment *readAssignment(StringRef Name);
- BytesDataCommand *readBytesDataCommand(StringRef Tok);
- uint32_t readFill();
- OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
- uint32_t readOutputSectionFiller(StringRef Tok);
- std::vector<StringRef> readOutputSectionPhdrs();
- InputSectionDescription *readInputSectionDescription(StringRef Tok);
- StringMatcher readFilePatterns();
- std::vector<SectionPattern> readInputSectionsList();
- InputSectionDescription *readInputSectionRules(StringRef FilePattern);
- unsigned readPhdrType();
- SortSectionPolicy readSortKind();
- SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
- SymbolAssignment *readProvideOrAssignment(StringRef Tok);
- void readSort();
- Expr readAssert();
-
- Expr readExpr();
- Expr readExpr1(Expr Lhs, int MinPrec);
- StringRef readParenLiteral();
- Expr readPrimary();
- Expr readTernary(Expr Cond);
- Expr readParenExpr();
-
- // For parsing version script.
- std::vector<SymbolVersion> readVersionExtern();
- void readAnonymousDeclaration();
- void readVersionDeclaration(StringRef VerStr);
- std::vector<SymbolVersion> readSymbols();
- void readLocals();
-
- ScriptConfiguration &Opt = *ScriptConfig;
- bool IsUnderSysroot;
-};
-
-void ScriptParser::readDynamicList() {
- expect("{");
- readAnonymousDeclaration();
- if (!atEOF())
- setError("EOF expected, but got " + next());
-}
-void ScriptParser::readVersionScript() {
- readVersionScriptCommand();
- if (!atEOF())
- setError("EOF expected, but got " + next());
-}
-
-void ScriptParser::readVersionScriptCommand() {
- if (consume("{")) {
- readAnonymousDeclaration();
+ uint32_t Type = Sec->Type;
+ if (Type == SHT_GROUP) {
+ finalizeShtGroup<ELFT>(Sec, Sections);
return;
}
- while (!atEOF() && !Error && peek() != "}") {
- StringRef VerStr = next();
- if (VerStr == "{") {
- setError("anonymous version definition is used in "
- "combination with other version definitions");
- return;
- }
- expect("{");
- readVersionDeclaration(VerStr);
- }
-}
-
-void ScriptParser::readVersion() {
- expect("{");
- readVersionScriptCommand();
- expect("}");
-}
+ if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
+ return;
-void ScriptParser::readLinkerScript() {
- while (!atEOF()) {
- StringRef Tok = next();
- if (Tok == ";")
- continue;
+ InputSection *First = Sections[0];
+ if (isa<SyntheticSection>(First))
+ return;
- if (Tok == "ASSERT") {
- Opt.Commands.emplace_back(new AssertCommand(readAssert()));
- } else if (Tok == "ENTRY") {
- readEntry();
- } else if (Tok == "EXTERN") {
- readExtern();
- } else if (Tok == "GROUP" || Tok == "INPUT") {
- readGroup();
- } else if (Tok == "INCLUDE") {
- readInclude();
- } else if (Tok == "OUTPUT") {
- readOutput();
- } else if (Tok == "OUTPUT_ARCH") {
- readOutputArch();
- } else if (Tok == "OUTPUT_FORMAT") {
- readOutputFormat();
- } else if (Tok == "PHDRS") {
- readPhdrs();
- } else if (Tok == "SEARCH_DIR") {
- readSearchDir();
- } else if (Tok == "SECTIONS") {
- readSections();
- } else if (Tok == "VERSION") {
- readVersion();
- } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
- Opt.Commands.emplace_back(Cmd);
- } else {
- setError("unknown directive: " + Tok);
- }
- }
+ Sec->Link = InX::SymTab->getParent()->SectionIndex;
+ // sh_info for SHT_REL[A] sections should contain the section header index of
+ // the section to which the relocation applies.
+ InputSectionBase *S = First->getRelocatedSection();
+ Sec->Info = S->getOutputSection()->SectionIndex;
+ Sec->Flags |= SHF_INFO_LINK;
}
-void ScriptParser::addFile(StringRef S) {
- if (IsUnderSysroot && S.startswith("/")) {
- SmallString<128> PathData;
- StringRef Path = (Config->Sysroot + S).toStringRef(PathData);
- if (sys::fs::exists(Path)) {
- Driver->addFile(Saver.save(Path));
- return;
- }
- }
-
- if (sys::path::is_absolute(S)) {
- Driver->addFile(S);
- } else if (S.startswith("=")) {
- if (Config->Sysroot.empty())
- Driver->addFile(S.substr(1));
- else
- Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
- } else if (S.startswith("-l")) {
- Driver->addLibrary(S.substr(2));
- } else if (sys::fs::exists(S)) {
- Driver->addFile(S);
- } else {
- if (Optional<std::string> Path = findFromSearchPaths(S))
- Driver->addFile(Saver.save(*Path));
- else
- setError("unable to find " + S);
- }
-}
+// Compress section contents if this section contains debug info.
+template <class ELFT> void OutputSectionCommand::maybeCompress() {
+ typedef typename ELFT::Chdr Elf_Chdr;
-void ScriptParser::readAsNeeded() {
- expect("(");
- bool Orig = Config->AsNeeded;
- Config->AsNeeded = true;
- while (!Error && !consume(")"))
- addFile(unquote(next()));
- Config->AsNeeded = Orig;
-}
+ // Compress only DWARF debug sections.
+ if (!Config->CompressDebugSections || (Sec->Flags & SHF_ALLOC) ||
+ !Name.startswith(".debug_"))
+ return;
-void ScriptParser::readEntry() {
- // -e <symbol> takes predecence over ENTRY(<symbol>).
- expect("(");
- StringRef Tok = next();
- if (Config->Entry.empty())
- Config->Entry = Tok;
- expect(")");
-}
+ // Create a section header.
+ Sec->ZDebugHeader.resize(sizeof(Elf_Chdr));
+ auto *Hdr = reinterpret_cast<Elf_Chdr *>(Sec->ZDebugHeader.data());
+ Hdr->ch_type = ELFCOMPRESS_ZLIB;
+ Hdr->ch_size = Sec->Size;
+ Hdr->ch_addralign = Sec->Alignment;
-void ScriptParser::readExtern() {
- expect("(");
- while (!Error && !consume(")"))
- Config->Undefined.push_back(next());
-}
+ // Write section contents to a temporary buffer and compress it.
+ std::vector<uint8_t> Buf(Sec->Size);
+ writeTo<ELFT>(Buf.data());
+ if (Error E = zlib::compress(toStringRef(Buf), Sec->CompressedData))
+ fatal("compress failed: " + llvm::toString(std::move(E)));
-void ScriptParser::readGroup() {
- expect("(");
- while (!Error && !consume(")")) {
- StringRef Tok = next();
- if (Tok == "AS_NEEDED")
- readAsNeeded();
- else
- addFile(unquote(Tok));
- }
+ // Update section headers.
+ Sec->Size = sizeof(Elf_Chdr) + Sec->CompressedData.size();
+ Sec->Flags |= SHF_COMPRESSED;
}
-void ScriptParser::readInclude() {
- StringRef Tok = unquote(next());
-
- // https://sourceware.org/binutils/docs/ld/File-Commands.html:
- // The file will be searched for in the current directory, and in any
- // directory specified with the -L option.
- if (sys::fs::exists(Tok)) {
- if (Optional<MemoryBufferRef> MB = readFile(Tok))
- tokenize(*MB);
+template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
+ if (Sec->Type == SHT_NOBITS)
return;
- }
- if (Optional<std::string> Path = findFromSearchPaths(Tok)) {
- if (Optional<MemoryBufferRef> MB = readFile(*Path))
- tokenize(*MB);
- return;
- }
- setError("cannot open " + Tok);
-}
-
-void ScriptParser::readOutput() {
- // -o <file> takes predecence over OUTPUT(<file>).
- expect("(");
- StringRef Tok = next();
- if (Config->OutputFile.empty())
- Config->OutputFile = unquote(Tok);
- expect(")");
-}
-void ScriptParser::readOutputArch() {
- // Error checking only for now.
- expect("(");
- skip();
- expect(")");
-}
+ Sec->Loc = Buf;
-void ScriptParser::readOutputFormat() {
- // Error checking only for now.
- expect("(");
- skip();
- StringRef Tok = next();
- if (Tok == ")")
- return;
- if (Tok != ",") {
- setError("unexpected token: " + Tok);
+ // If -compress-debug-section is specified and if this is a debug seciton,
+ // we've already compressed section contents. If that's the case,
+ // just write it down.
+ if (!Sec->CompressedData.empty()) {
+ memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size());
+ memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(),
+ Sec->CompressedData.size());
return;
}
- skip();
- expect(",");
- skip();
- expect(")");
-}
-
-void ScriptParser::readPhdrs() {
- expect("{");
- while (!Error && !consume("}")) {
- StringRef Tok = next();
- Opt.PhdrsCommands.push_back(
- {Tok, PT_NULL, false, false, UINT_MAX, nullptr});
- PhdrsCommand &PhdrCmd = Opt.PhdrsCommands.back();
-
- PhdrCmd.Type = readPhdrType();
- do {
- Tok = next();
- if (Tok == ";")
- break;
- if (Tok == "FILEHDR")
- PhdrCmd.HasFilehdr = true;
- else if (Tok == "PHDRS")
- PhdrCmd.HasPhdrs = true;
- else if (Tok == "AT")
- PhdrCmd.LMAExpr = readParenExpr();
- else if (Tok == "FLAGS") {
- expect("(");
- // Passing 0 for the value of dot is a bit of a hack. It means that
- // we accept expressions like ".|1".
- PhdrCmd.Flags = readExpr()(0);
- expect(")");
- } else
- setError("unexpected header attribute: " + Tok);
- } while (!Error);
- }
-}
-void ScriptParser::readSearchDir() {
- expect("(");
- StringRef Tok = next();
- if (!Config->Nostdlib)
- Config->SearchPaths.push_back(unquote(Tok));
- expect(")");
-}
-
-void ScriptParser::readSections() {
- Opt.HasSections = true;
- // -no-rosegment is used to avoid placing read only non-executable sections in
- // their own segment. We do the same if SECTIONS command is present in linker
- // script. See comment for computeFlags().
- Config->SingleRoRx = true;
-
- expect("{");
- while (!Error && !consume("}")) {
- StringRef Tok = next();
- BaseCommand *Cmd = readProvideOrAssignment(Tok);
- if (!Cmd) {
- if (Tok == "ASSERT")
- Cmd = new AssertCommand(readAssert());
+ // Write leading padding.
+ std::vector<InputSection *> Sections;
+ for (BaseCommand *Cmd : Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
+ for (InputSection *IS : ISD->Sections)
+ if (IS->Live)
+ Sections.push_back(IS);
+ uint32_t Filler = getFiller();
+ if (Filler)
+ fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler);
+
+ parallelForEachN(0, Sections.size(), [=](size_t I) {
+ InputSection *IS = Sections[I];
+ IS->writeTo<ELFT>(Buf);
+
+ // Fill gaps between sections.
+ if (Filler) {
+ uint8_t *Start = Buf + IS->OutSecOff + IS->getSize();
+ uint8_t *End;
+ if (I + 1 == Sections.size())
+ End = Buf + Sec->Size;
else
- Cmd = readOutputSectionDescription(Tok);
- }
- Opt.Commands.emplace_back(Cmd);
- }
-}
-
-static int precedence(StringRef Op) {
- return StringSwitch<int>(Op)
- .Cases("*", "/", 5)
- .Cases("+", "-", 4)
- .Cases("<<", ">>", 3)
- .Cases("<", "<=", ">", ">=", "==", "!=", 2)
- .Cases("&", "|", 1)
- .Default(-1);
-}
-
-StringMatcher ScriptParser::readFilePatterns() {
- std::vector<StringRef> V;
- while (!Error && !consume(")"))
- V.push_back(next());
- return StringMatcher(V);
-}
-
-SortSectionPolicy ScriptParser::readSortKind() {
- if (consume("SORT") || consume("SORT_BY_NAME"))
- return SortSectionPolicy::Name;
- if (consume("SORT_BY_ALIGNMENT"))
- return SortSectionPolicy::Alignment;
- if (consume("SORT_BY_INIT_PRIORITY"))
- return SortSectionPolicy::Priority;
- if (consume("SORT_NONE"))
- return SortSectionPolicy::None;
- return SortSectionPolicy::Default;
-}
-
-// Method reads a list of sequence of excluded files and section globs given in
-// a following form: ((EXCLUDE_FILE(file_pattern+))? section_pattern+)+
-// Example: *(.foo.1 EXCLUDE_FILE (*a.o) .foo.2 EXCLUDE_FILE (*b.o) .foo.3)
-// The semantics of that is next:
-// * Include .foo.1 from every file.
-// * Include .foo.2 from every file but a.o
-// * Include .foo.3 from every file but b.o
-std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
- std::vector<SectionPattern> Ret;
- while (!Error && peek() != ")") {
- StringMatcher ExcludeFilePat;
- if (consume("EXCLUDE_FILE")) {
- expect("(");
- ExcludeFilePat = readFilePatterns();
- }
-
- std::vector<StringRef> V;
- while (!Error && peek() != ")" && peek() != "EXCLUDE_FILE")
- V.push_back(next());
-
- if (!V.empty())
- Ret.push_back({std::move(ExcludeFilePat), StringMatcher(V)});
- else
- setError("section pattern is expected");
- }
- return Ret;
-}
-
-// Reads contents of "SECTIONS" directive. That directive contains a
-// list of glob patterns for input sections. The grammar is as follows.
-//
-// <patterns> ::= <section-list>
-// | <sort> "(" <section-list> ")"
-// | <sort> "(" <sort> "(" <section-list> ")" ")"
-//
-// <sort> ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT"
-// | "SORT_BY_INIT_PRIORITY" | "SORT_NONE"
-//
-// <section-list> is parsed by readInputSectionsList().
-InputSectionDescription *
-ScriptParser::readInputSectionRules(StringRef FilePattern) {
- auto *Cmd = new InputSectionDescription(FilePattern);
- expect("(");
- while (!Error && !consume(")")) {
- SortSectionPolicy Outer = readSortKind();
- SortSectionPolicy Inner = SortSectionPolicy::Default;
- std::vector<SectionPattern> V;
- if (Outer != SortSectionPolicy::Default) {
- expect("(");
- Inner = readSortKind();
- if (Inner != SortSectionPolicy::Default) {
- expect("(");
- V = readInputSectionsList();
- expect(")");
- } else {
- V = readInputSectionsList();
- }
- expect(")");
- } else {
- V = readInputSectionsList();
- }
-
- for (SectionPattern &Pat : V) {
- Pat.SortInner = Inner;
- Pat.SortOuter = Outer;
- }
-
- std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns));
- }
- return Cmd;
-}
-
-InputSectionDescription *
-ScriptParser::readInputSectionDescription(StringRef Tok) {
- // Input section wildcard can be surrounded by KEEP.
- // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
- if (Tok == "KEEP") {
- expect("(");
- StringRef FilePattern = next();
- InputSectionDescription *Cmd = readInputSectionRules(FilePattern);
- expect(")");
- Opt.KeptSections.push_back(Cmd);
- return Cmd;
- }
- return readInputSectionRules(Tok);
-}
-
-void ScriptParser::readSort() {
- expect("(");
- expect("CONSTRUCTORS");
- expect(")");
-}
-
-Expr ScriptParser::readAssert() {
- expect("(");
- Expr E = readExpr();
- expect(",");
- StringRef Msg = unquote(next());
- expect(")");
- return [=](uint64_t Dot) {
- uint64_t V = E(Dot);
- if (!V)
- error(Msg);
- return V;
- };
-}
-
-// Reads a FILL(expr) command. We handle the FILL command as an
-// alias for =fillexp section attribute, which is different from
-// what GNU linkers do.
-// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
-uint32_t ScriptParser::readFill() {
- expect("(");
- uint32_t V = readOutputSectionFiller(next());
- expect(")");
- expect(";");
- return V;
-}
-
-OutputSectionCommand *
-ScriptParser::readOutputSectionDescription(StringRef OutSec) {
- OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec);
- Cmd->Location = getCurrentLocation();
-
- // Read an address expression.
- // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html#Output-Section-Address
- if (peek() != ":")
- Cmd->AddrExpr = readExpr();
-
- expect(":");
-
- if (consume("AT"))
- Cmd->LMAExpr = readParenExpr();
- if (consume("ALIGN"))
- Cmd->AlignExpr = readParenExpr();
- if (consume("SUBALIGN"))
- Cmd->SubalignExpr = readParenExpr();
-
- // Parse constraints.
- if (consume("ONLY_IF_RO"))
- Cmd->Constraint = ConstraintKind::ReadOnly;
- if (consume("ONLY_IF_RW"))
- Cmd->Constraint = ConstraintKind::ReadWrite;
- expect("{");
-
- while (!Error && !consume("}")) {
- StringRef Tok = next();
- if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) {
- Cmd->Commands.emplace_back(Assignment);
- } else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) {
- Cmd->Commands.emplace_back(Data);
- } else if (Tok == "ASSERT") {
- Cmd->Commands.emplace_back(new AssertCommand(readAssert()));
- expect(";");
- } else if (Tok == "FILL") {
- Cmd->Filler = readFill();
- } else if (Tok == "SORT") {
- readSort();
- } else if (peek() == "(") {
- Cmd->Commands.emplace_back(readInputSectionDescription(Tok));
- } else {
- setError("unknown command " + Tok);
+ End = Buf + Sections[I + 1]->OutSecOff;
+ fill(Start, End - Start, Filler);
}
- }
- Cmd->Phdrs = readOutputSectionPhdrs();
-
- if (consume("="))
- Cmd->Filler = readOutputSectionFiller(next());
- else if (peek().startswith("="))
- Cmd->Filler = readOutputSectionFiller(next().drop_front());
-
- return Cmd;
-}
-
-// Read "=<number>" where <number> is an octal/decimal/hexadecimal number.
-// https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html
-//
-// ld.gold is not fully compatible with ld.bfd. ld.bfd handles
-// hexstrings as blobs of arbitrary sizes, while ld.gold handles them
-// as 32-bit big-endian values. We will do the same as ld.gold does
-// because it's simpler than what ld.bfd does.
-uint32_t ScriptParser::readOutputSectionFiller(StringRef Tok) {
- uint32_t V;
- if (!Tok.getAsInteger(0, V))
- return V;
- setError("invalid filler expression: " + Tok);
- return 0;
-}
-
-SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
- expect("(");
- SymbolAssignment *Cmd = readAssignment(next());
- Cmd->Provide = Provide;
- Cmd->Hidden = Hidden;
- expect(")");
- expect(";");
- return Cmd;
-}
-
-SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
- SymbolAssignment *Cmd = nullptr;
- if (peek() == "=" || peek() == "+=") {
- Cmd = readAssignment(Tok);
- expect(";");
- } else if (Tok == "PROVIDE") {
- Cmd = readProvideHidden(true, false);
- } else if (Tok == "HIDDEN") {
- Cmd = readProvideHidden(false, true);
- } else if (Tok == "PROVIDE_HIDDEN") {
- Cmd = readProvideHidden(true, true);
- }
- return Cmd;
-}
+ });
-static uint64_t getSymbolValue(const Twine &Loc, StringRef S, uint64_t Dot) {
- if (S == ".")
- return Dot;
- return ScriptBase->getSymbolValue(Loc, S);
+ // Linker scripts may have BYTE()-family commands with which you
+ // can write arbitrary bytes to the output. Process them if any.
+ for (BaseCommand *Base : Commands)
+ if (auto *Data = dyn_cast<BytesDataCommand>(Base))
+ writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
}
-static bool isAbsolute(StringRef S) {
+ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
if (S == ".")
- return false;
- return ScriptBase->isAbsolute(S);
-}
-
-SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
- StringRef Op = next();
- Expr E;
- assert(Op == "=" || Op == "+=");
- if (consume("ABSOLUTE")) {
- // The RHS may be something like "ABSOLUTE(.) & 0xff".
- // Call readExpr1 to read the whole expression.
- E = readExpr1(readParenExpr(), 0);
- E.IsAbsolute = [] { return true; };
- } else {
- E = readExpr();
- }
- if (Op == "+=") {
- std::string Loc = getCurrentLocation();
- E = [=](uint64_t Dot) {
- return getSymbolValue(Loc, Name, Dot) + E(Dot);
- };
- }
- return new SymbolAssignment(Name, E);
-}
-
-// This is an operator-precedence parser to parse a linker
-// script expression.
-Expr ScriptParser::readExpr() { return readExpr1(readPrimary(), 0); }
-
-static Expr combine(StringRef Op, Expr L, Expr R) {
- if (Op == "*")
- return [=](uint64_t Dot) { return L(Dot) * R(Dot); };
- if (Op == "/") {
- return [=](uint64_t Dot) -> uint64_t {
- uint64_t RHS = R(Dot);
- if (RHS == 0) {
- error("division by zero");
- return 0;
- }
- return L(Dot) / RHS;
- };
- }
- if (Op == "+")
- return {[=](uint64_t Dot) { return L(Dot) + R(Dot); },
- [=] { return L.IsAbsolute() && R.IsAbsolute(); },
- [=] {
- const OutputSectionBase *S = L.Section();
- return S ? S : R.Section();
- }};
- if (Op == "-")
- return [=](uint64_t Dot) { return L(Dot) - R(Dot); };
- if (Op == "<<")
- return [=](uint64_t Dot) { return L(Dot) << R(Dot); };
- if (Op == ">>")
- return [=](uint64_t Dot) { return L(Dot) >> R(Dot); };
- if (Op == "<")
- return [=](uint64_t Dot) { return L(Dot) < R(Dot); };
- if (Op == ">")
- return [=](uint64_t Dot) { return L(Dot) > R(Dot); };
- if (Op == ">=")
- return [=](uint64_t Dot) { return L(Dot) >= R(Dot); };
- if (Op == "<=")
- return [=](uint64_t Dot) { return L(Dot) <= R(Dot); };
- if (Op == "==")
- return [=](uint64_t Dot) { return L(Dot) == R(Dot); };
- if (Op == "!=")
- return [=](uint64_t Dot) { return L(Dot) != R(Dot); };
- if (Op == "&")
- return [=](uint64_t Dot) { return L(Dot) & R(Dot); };
- if (Op == "|")
- return [=](uint64_t Dot) { return L(Dot) | R(Dot); };
- llvm_unreachable("invalid operator");
-}
-
-// This is a part of the operator-precedence parser. This function
-// assumes that the remaining token stream starts with an operator.
-Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) {
- while (!atEOF() && !Error) {
- // Read an operator and an expression.
- if (consume("?"))
- return readTernary(Lhs);
- StringRef Op1 = peek();
- if (precedence(Op1) < MinPrec)
- break;
- skip();
- Expr Rhs = readPrimary();
-
- // Evaluate the remaining part of the expression first if the
- // next operator has greater precedence than the previous one.
- // For example, if we have read "+" and "3", and if the next
- // operator is "*", then we'll evaluate 3 * ... part first.
- while (!atEOF()) {
- StringRef Op2 = peek();
- if (precedence(Op2) <= precedence(Op1))
- break;
- Rhs = readExpr1(Rhs, precedence(Op2));
- }
-
- Lhs = combine(Op1, Lhs, Rhs);
+ return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc};
+ if (SymbolBody *B = findSymbol(S)) {
+ if (auto *D = dyn_cast<DefinedRegular>(B))
+ return {D->Section, D->Value, Loc};
+ if (auto *C = dyn_cast<DefinedCommon>(B))
+ return {InX::Common, C->Offset, Loc};
}
- return Lhs;
-}
-
-uint64_t static getConstant(StringRef S) {
- if (S == "COMMONPAGESIZE")
- return Target->PageSize;
- if (S == "MAXPAGESIZE")
- return Config->MaxPageSize;
- error("unknown constant: " + S);
+ error(Loc + ": symbol not found: " + S);
return 0;
}
-// Parses Tok as an integer. Returns true if successful.
-// It recognizes hexadecimal (prefixed with "0x" or suffixed with "H")
-// and decimal numbers. Decimal numbers may have "K" (kilo) or
-// "M" (mega) prefixes.
-static bool readInteger(StringRef Tok, uint64_t &Result) {
- // Negative number
- if (Tok.startswith("-")) {
- if (!readInteger(Tok.substr(1), Result))
- return false;
- Result = -Result;
- return true;
- }
-
- // Hexadecimal
- if (Tok.startswith_lower("0x"))
- return !Tok.substr(2).getAsInteger(16, Result);
- if (Tok.endswith_lower("H"))
- return !Tok.drop_back().getAsInteger(16, Result);
-
- // Decimal
- int Suffix = 1;
- if (Tok.endswith_lower("K")) {
- Suffix = 1024;
- Tok = Tok.drop_back();
- } else if (Tok.endswith_lower("M")) {
- Suffix = 1024 * 1024;
- Tok = Tok.drop_back();
- }
- if (Tok.getAsInteger(10, Result))
- return false;
- Result *= Suffix;
- return true;
-}
-
-BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) {
- int Size = StringSwitch<unsigned>(Tok)
- .Case("BYTE", 1)
- .Case("SHORT", 2)
- .Case("LONG", 4)
- .Case("QUAD", 8)
- .Default(-1);
- if (Size == -1)
- return nullptr;
-
- return new BytesDataCommand(readParenExpr(), Size);
-}
-
-StringRef ScriptParser::readParenLiteral() {
- expect("(");
- StringRef Tok = next();
- expect(")");
- return Tok;
-}
-
-Expr ScriptParser::readPrimary() {
- if (peek() == "(")
- return readParenExpr();
-
- StringRef Tok = next();
- std::string Location = getCurrentLocation();
-
- if (Tok == "~") {
- Expr E = readPrimary();
- return [=](uint64_t Dot) { return ~E(Dot); };
- }
- if (Tok == "-") {
- Expr E = readPrimary();
- return [=](uint64_t Dot) { return -E(Dot); };
- }
-
- // Built-in functions are parsed here.
- // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
- if (Tok == "ADDR") {
- StringRef Name = readParenLiteral();
- return {[=](uint64_t Dot) {
- return ScriptBase->getOutputSection(Location, Name)->Addr;
- },
- [=] { return false; },
- [=] { return ScriptBase->getOutputSection(Location, Name); }};
- }
- if (Tok == "LOADADDR") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) {
- return ScriptBase->getOutputSection(Location, Name)->getLMA();
- };
- }
- if (Tok == "ASSERT")
- return readAssert();
- if (Tok == "ALIGN") {
- expect("(");
- Expr E = readExpr();
- if (consume(",")) {
- Expr E2 = readExpr();
- expect(")");
- return [=](uint64_t Dot) { return alignTo(E(Dot), E2(Dot)); };
- }
- expect(")");
- return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
- }
- if (Tok == "CONSTANT") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) { return getConstant(Name); };
- }
- if (Tok == "DEFINED") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) { return ScriptBase->isDefined(Name) ? 1 : 0; };
- }
- if (Tok == "SEGMENT_START") {
- expect("(");
- skip();
- expect(",");
- Expr E = readExpr();
- expect(")");
- return [=](uint64_t Dot) { return E(Dot); };
- }
- if (Tok == "DATA_SEGMENT_ALIGN") {
- expect("(");
- Expr E = readExpr();
- expect(",");
- readExpr();
- expect(")");
- return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
- }
- if (Tok == "DATA_SEGMENT_END") {
- expect("(");
- expect(".");
- expect(")");
- return [](uint64_t Dot) { return Dot; };
- }
- // GNU linkers implements more complicated logic to handle
- // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and just align to
- // the next page boundary for simplicity.
- if (Tok == "DATA_SEGMENT_RELRO_END") {
- expect("(");
- readExpr();
- expect(",");
- readExpr();
- expect(")");
- return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); };
- }
- if (Tok == "SIZEOF") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) { return ScriptBase->getOutputSectionSize(Name); };
- }
- if (Tok == "ALIGNOF") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) {
- return ScriptBase->getOutputSection(Location, Name)->Addralign;
- };
- }
- if (Tok == "SIZEOF_HEADERS")
- return [=](uint64_t Dot) { return ScriptBase->getHeaderSize(); };
-
- // Tok is a literal number.
- uint64_t V;
- if (readInteger(Tok, V))
- return [=](uint64_t Dot) { return V; };
-
- // Tok is a symbol name.
- if (Tok != "." && !isValidCIdentifier(Tok))
- setError("malformed number: " + Tok);
- return {[=](uint64_t Dot) { return getSymbolValue(Location, Tok, Dot); },
- [=] { return isAbsolute(Tok); },
- [=] { return ScriptBase->getSymbolSection(Tok); }};
-}
-
-Expr ScriptParser::readTernary(Expr Cond) {
- Expr L = readExpr();
- expect(":");
- Expr R = readExpr();
- return [=](uint64_t Dot) { return Cond(Dot) ? L(Dot) : R(Dot); };
-}
-
-Expr ScriptParser::readParenExpr() {
- expect("(");
- Expr E = readExpr();
- expect(")");
- return E;
-}
-
-std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() {
- std::vector<StringRef> Phdrs;
- while (!Error && peek().startswith(":")) {
- StringRef Tok = next();
- Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1));
- }
- return Phdrs;
-}
-
-// Read a program header type name. The next token must be a
-// name of a program header type or a constant (e.g. "0x3").
-unsigned ScriptParser::readPhdrType() {
- StringRef Tok = next();
- uint64_t Val;
- if (readInteger(Tok, Val))
- return Val;
-
- unsigned Ret = StringSwitch<unsigned>(Tok)
- .Case("PT_NULL", PT_NULL)
- .Case("PT_LOAD", PT_LOAD)
- .Case("PT_DYNAMIC", PT_DYNAMIC)
- .Case("PT_INTERP", PT_INTERP)
- .Case("PT_NOTE", PT_NOTE)
- .Case("PT_SHLIB", PT_SHLIB)
- .Case("PT_PHDR", PT_PHDR)
- .Case("PT_TLS", PT_TLS)
- .Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
- .Case("PT_GNU_STACK", PT_GNU_STACK)
- .Case("PT_GNU_RELRO", PT_GNU_RELRO)
- .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
- .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
- .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
- .Default(-1);
-
- if (Ret == (unsigned)-1) {
- setError("invalid program header type: " + Tok);
- return PT_NULL;
- }
- return Ret;
-}
-
-// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };".
-void ScriptParser::readAnonymousDeclaration() {
- // Read global symbols first. "global:" is default, so if there's
- // no label, we assume global symbols.
- if (consume("global:") || peek() != "local:")
- Config->VersionScriptGlobals = readSymbols();
+bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; }
- readLocals();
- expect("}");
- expect(";");
-}
+static const size_t NoPhdr = -1;
-void ScriptParser::readLocals() {
- if (!consume("local:"))
- return;
- std::vector<SymbolVersion> Locals = readSymbols();
- for (SymbolVersion V : Locals) {
- if (V.Name == "*") {
- Config->DefaultSymbolVersion = VER_NDX_LOCAL;
- continue;
- }
- Config->VersionScriptLocals.push_back(V);
- }
-}
-
-// Reads a list of symbols, e.g. "VerStr { global: foo; bar; local: *; };".
-void ScriptParser::readVersionDeclaration(StringRef VerStr) {
- // Identifiers start at 2 because 0 and 1 are reserved
- // for VER_NDX_LOCAL and VER_NDX_GLOBAL constants.
- uint16_t VersionId = Config->VersionDefinitions.size() + 2;
- Config->VersionDefinitions.push_back({VerStr, VersionId});
-
- // Read global symbols.
- if (consume("global:") || peek() != "local:")
- Config->VersionDefinitions.back().Globals = readSymbols();
-
- readLocals();
- expect("}");
-
- // Each version may have a parent version. For example, "Ver2"
- // defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1"
- // as a parent. This version hierarchy is, probably against your
- // instinct, purely for hint; the runtime doesn't care about it
- // at all. In LLD, we simply ignore it.
- if (peek() != ";")
- skip();
- expect(";");
-}
-
-// Reads a list of symbols for a versions cript.
-std::vector<SymbolVersion> ScriptParser::readSymbols() {
- std::vector<SymbolVersion> Ret;
- for (;;) {
- if (consume("extern")) {
- for (SymbolVersion V : readVersionExtern())
- Ret.push_back(V);
- continue;
- }
-
- if (peek() == "}" || peek() == "local:" || Error)
- break;
- StringRef Tok = next();
- Ret.push_back({unquote(Tok), false, hasWildcard(Tok)});
- expect(";");
+// Returns indices of ELF headers containing specific section. Each index is a
+// zero based number of ELF header listed within PHDRS {} script block.
+std::vector<size_t> LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) {
+ std::vector<size_t> Ret;
+ for (StringRef PhdrName : Cmd->Phdrs) {
+ size_t Index = getPhdrIndex(Cmd->Location, PhdrName);
+ if (Index != NoPhdr)
+ Ret.push_back(Index);
}
return Ret;
}
-// Reads an "extern C++" directive, e.g.,
-// "extern "C++" { ns::*; "f(int, double)"; };"
-std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
- StringRef Tok = next();
- bool IsCXX = Tok == "\"C++\"";
- if (!IsCXX && Tok != "\"C\"")
- setError("Unknown language");
- expect("{");
-
- std::vector<SymbolVersion> Ret;
- while (!Error && peek() != "}") {
- StringRef Tok = next();
- bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
- Ret.push_back({unquote(Tok), IsCXX, HasWildcard});
- expect(";");
+// Returns the index of the segment named PhdrName if found otherwise
+// NoPhdr. When not found, if PhdrName is not the special case value 'NONE'
+// (which can be used to explicitly specify that a section isn't assigned to a
+// segment) then error.
+size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
+ size_t I = 0;
+ for (PhdrsCommand &Cmd : Opt.PhdrsCommands) {
+ if (Cmd.Name == PhdrName)
+ return I;
+ ++I;
}
-
- expect("}");
- expect(";");
- return Ret;
-}
-
-void elf::readLinkerScript(MemoryBufferRef MB) {
- ScriptParser(MB).readLinkerScript();
+ if (PhdrName != "NONE")
+ error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
+ return NoPhdr;
}
-void elf::readVersionScript(MemoryBufferRef MB) {
- ScriptParser(MB).readVersionScript();
-}
+template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf);
+template void OutputSectionCommand::writeTo<ELF32BE>(uint8_t *Buf);
+template void OutputSectionCommand::writeTo<ELF64LE>(uint8_t *Buf);
+template void OutputSectionCommand::writeTo<ELF64BE>(uint8_t *Buf);
-void elf::readDynamicList(MemoryBufferRef MB) {
- ScriptParser(MB).readDynamicList();
-}
+template void OutputSectionCommand::maybeCompress<ELF32LE>();
+template void OutputSectionCommand::maybeCompress<ELF32BE>();
+template void OutputSectionCommand::maybeCompress<ELF64LE>();
+template void OutputSectionCommand::maybeCompress<ELF64BE>();
-template class elf::LinkerScript<ELF32LE>;
-template class elf::LinkerScript<ELF32BE>;
-template class elf::LinkerScript<ELF64LE>;
-template class elf::LinkerScript<ELF64BE>;
+template void OutputSectionCommand::finalize<ELF32LE>();
+template void OutputSectionCommand::finalize<ELF32BE>();
+template void OutputSectionCommand::finalize<ELF64LE>();
+template void OutputSectionCommand::finalize<ELF64BE>();
diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.h b/contrib/llvm/tools/lld/ELF/LinkerScript.h
index 505162f..dd5a7d7 100644
--- a/contrib/llvm/tools/lld/ELF/LinkerScript.h
+++ b/contrib/llvm/tools/lld/ELF/LinkerScript.h
@@ -15,6 +15,7 @@
#include "Writer.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -28,45 +29,36 @@ namespace lld {
namespace elf {
class DefinedCommon;
-class ScriptParser;
class SymbolBody;
-template <class ELFT> class InputSectionBase;
-template <class ELFT> class InputSection;
-class OutputSectionBase;
-template <class ELFT> class OutputSectionFactory;
-class InputSectionData;
+class InputSectionBase;
+class InputSection;
+class OutputSection;
+class OutputSectionFactory;
+class InputSectionBase;
+class SectionBase;
+
+struct ExprValue {
+ SectionBase *Sec;
+ uint64_t Val;
+ bool ForceAbsolute;
+ uint64_t Alignment = 1;
+ std::string Loc;
+
+ ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val,
+ const Twine &Loc)
+ : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Loc(Loc.str()) {}
+ ExprValue(SectionBase *Sec, uint64_t Val, const Twine &Loc)
+ : ExprValue(Sec, false, Val, Loc) {}
+ ExprValue(uint64_t Val) : ExprValue(nullptr, Val, "") {}
+ bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; }
+ uint64_t getValue() const;
+ uint64_t getSecAddr() const;
+};
// This represents an expression in the linker script.
// ScriptParser::readExpr reads an expression and returns an Expr.
-// Later, we evaluate the expression by calling the function
-// with the value of special context variable ".".
-struct Expr {
- std::function<uint64_t(uint64_t)> Val;
- std::function<bool()> IsAbsolute;
-
- // If expression is section-relative the function below is used
- // to get the output section pointer.
- std::function<const OutputSectionBase *()> Section;
-
- uint64_t operator()(uint64_t Dot) const { return Val(Dot); }
- operator bool() const { return (bool)Val; }
-
- Expr(std::function<uint64_t(uint64_t)> Val, std::function<bool()> IsAbsolute,
- std::function<const OutputSectionBase *()> Section)
- : Val(Val), IsAbsolute(IsAbsolute), Section(Section) {}
- template <typename T>
- Expr(T V) : Expr(V, [] { return true; }, [] { return nullptr; }) {}
- Expr() : Expr(nullptr) {}
-};
-
-// Parses a linker script. Calling this function updates
-// Config and ScriptConfig.
-void readLinkerScript(MemoryBufferRef MB);
-
-// Parses a version script.
-void readVersionScript(MemoryBufferRef MB);
-
-void readDynamicList(MemoryBufferRef MB);
+// Later, we evaluate the expression by calling the function.
+typedef std::function<ExprValue()> Expr;
// This enum is used to implement linker script SECTIONS command.
// https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
@@ -80,16 +72,13 @@ enum SectionsCommandKind {
struct BaseCommand {
BaseCommand(int K) : Kind(K) {}
-
- virtual ~BaseCommand() = default;
-
int Kind;
};
// This represents ". = <expr>" or "<symbol> = <expr>".
struct SymbolAssignment : BaseCommand {
- SymbolAssignment(StringRef Name, Expr E)
- : BaseCommand(AssignmentKind), Name(Name), Expression(E) {}
+ SymbolAssignment(StringRef Name, Expr E, std::string Loc)
+ : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {}
static bool classof(const BaseCommand *C);
@@ -103,6 +92,9 @@ struct SymbolAssignment : BaseCommand {
// Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN.
bool Provide = false;
bool Hidden = false;
+
+ // Holds file name and line number for error reporting.
+ std::string Location;
};
// Linker scripts allow additional constraints to be put on ouput sections.
@@ -111,22 +103,46 @@ struct SymbolAssignment : BaseCommand {
// with ONLY_IF_RW is created if all input sections are RW.
enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
+// This struct is used to represent the location and size of regions of
+// target memory. Instances of the struct are created by parsing the
+// MEMORY command.
+struct MemoryRegion {
+ std::string Name;
+ uint64_t Origin;
+ uint64_t Length;
+ uint32_t Flags;
+ uint32_t NegFlags;
+};
+
struct OutputSectionCommand : BaseCommand {
OutputSectionCommand(StringRef Name)
: BaseCommand(OutputSectionKind), Name(Name) {}
static bool classof(const BaseCommand *C);
+ OutputSection *Sec = nullptr;
+ MemoryRegion *MemRegion = nullptr;
StringRef Name;
Expr AddrExpr;
Expr AlignExpr;
Expr LMAExpr;
Expr SubalignExpr;
- std::vector<std::unique_ptr<BaseCommand>> Commands;
+ std::vector<BaseCommand *> Commands;
std::vector<StringRef> Phdrs;
- uint32_t Filler = 0;
+ llvm::Optional<uint32_t> Filler;
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
+ std::string MemoryRegionName;
+ bool Noload = false;
+
+ template <class ELFT> void finalize();
+ template <class ELFT> void writeTo(uint8_t *Buf);
+ template <class ELFT> void maybeCompress();
+ uint32_t getFiller();
+
+ void sort(std::function<int(InputSectionBase *S)> Order);
+ void sortInitFini();
+ void sortCtorsDtors();
};
// This struct represents one section match pattern in SECTIONS() command.
@@ -154,7 +170,7 @@ struct InputSectionDescription : BaseCommand {
// will be associated with this InputSectionDescription.
std::vector<SectionPattern> SectionPatterns;
- std::vector<InputSectionData *> Sections;
+ std::vector<InputSection *> Sections;
};
// Represents an ASSERT().
@@ -187,25 +203,10 @@ struct PhdrsCommand {
Expr LMAExpr;
};
-class LinkerScriptBase {
-protected:
- ~LinkerScriptBase() = default;
-
-public:
- virtual uint64_t getHeaderSize() = 0;
- virtual uint64_t getSymbolValue(const Twine &Loc, StringRef S) = 0;
- virtual bool isDefined(StringRef S) = 0;
- virtual bool isAbsolute(StringRef S) = 0;
- virtual const OutputSectionBase *getSymbolSection(StringRef S) = 0;
- virtual const OutputSectionBase *getOutputSection(const Twine &Loc,
- StringRef S) = 0;
- virtual uint64_t getOutputSectionSize(StringRef S) = 0;
-};
-
// ScriptConfiguration holds linker script parse results.
struct ScriptConfiguration {
// Used to assign addresses to sections.
- std::vector<std::unique_ptr<BaseCommand>> Commands;
+ std::vector<BaseCommand *> Commands;
// Used to assign sections to headers.
std::vector<PhdrsCommand> PhdrsCommands;
@@ -215,20 +216,69 @@ struct ScriptConfiguration {
// List of section patterns specified with KEEP commands. They will
// be kept even if they are unused and --gc-sections is specified.
std::vector<InputSectionDescription *> KeptSections;
+
+ // A map from memory region name to a memory region descriptor.
+ llvm::DenseMap<llvm::StringRef, MemoryRegion> MemoryRegions;
+
+ // A list of symbols referenced by the script.
+ std::vector<llvm::StringRef> ReferencedSymbols;
};
-extern ScriptConfiguration *ScriptConfig;
+class LinkerScript final {
+ // Temporary state used in processCommands() and assignAddresses()
+ // that must be reinitialized for each call to the above functions, and must
+ // not be used outside of the scope of a call to the above functions.
+ struct AddressState {
+ uint64_t ThreadBssOffset = 0;
+ OutputSection *OutSec = nullptr;
+ MemoryRegion *MemRegion = nullptr;
+ llvm::DenseMap<const MemoryRegion *, uint64_t> MemRegionOffset;
+ std::function<uint64_t()> LMAOffset;
+ AddressState(const ScriptConfiguration &Opt);
+ };
+ llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
+ llvm::DenseMap<StringRef, OutputSectionCommand *> NameToOutputSectionCommand;
+
+ void assignSymbol(SymbolAssignment *Cmd, bool InSec);
+ void setDot(Expr E, const Twine &Loc, bool InSec);
+
+ std::vector<InputSection *>
+ computeInputSections(const InputSectionDescription *);
+
+ std::vector<InputSectionBase *>
+ createInputSectionList(OutputSectionCommand &Cmd);
-// This is a runner of the linker script.
-template <class ELFT> class LinkerScript final : public LinkerScriptBase {
- typedef typename ELFT::uint uintX_t;
+ std::vector<size_t> getPhdrIndices(OutputSectionCommand *Cmd);
+ size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
+
+ MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
+
+ void switchTo(OutputSection *Sec);
+ uint64_t advance(uint64_t Size, unsigned Align);
+ void output(InputSection *Sec);
+ void process(BaseCommand &Base);
+
+ AddressState *CurAddressState = nullptr;
+ OutputSection *Aether;
+
+ uint64_t Dot;
public:
- LinkerScript();
- ~LinkerScript();
+ bool ErrorOnMissingSection = false;
+ OutputSectionCommand *createOutputSectionCommand(StringRef Name,
+ StringRef Location);
+ OutputSectionCommand *getOrCreateOutputSectionCommand(StringRef Name);
+
+ OutputSectionCommand *getCmd(OutputSection *Sec) const;
+ bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
+ uint64_t getDot() { return Dot; }
+ void discard(ArrayRef<InputSectionBase *> V);
- void processCommands(OutputSectionFactory<ELFT> &Factory);
- void addOrphanSections(OutputSectionFactory<ELFT> &Factory);
+ ExprValue getSymbolValue(const Twine &Loc, StringRef S);
+ bool isDefined(StringRef S);
+
+ void fabricateDefaultCommands();
+ void addOrphanSections(OutputSectionFactory &Factory);
void removeEmptyCommands();
void adjustSectionsBeforeSorting();
void adjustSectionsAfterSorting();
@@ -236,61 +286,19 @@ public:
std::vector<PhdrEntry> createPhdrs();
bool ignoreInterpSection();
- uint32_t getFiller(StringRef Name);
- void writeDataBytes(StringRef Name, uint8_t *Buf);
- bool hasLMA(StringRef Name);
- bool shouldKeep(InputSectionBase<ELFT> *S);
+ bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd);
- void placeOrphanSections();
- void assignAddresses(std::vector<PhdrEntry> &Phdrs);
- bool hasPhdrsCommands();
- uint64_t getHeaderSize() override;
- uint64_t getSymbolValue(const Twine &Loc, StringRef S) override;
- bool isDefined(StringRef S) override;
- bool isAbsolute(StringRef S) override;
- const OutputSectionBase *getSymbolSection(StringRef S) override;
- const OutputSectionBase *getOutputSection(const Twine &Loc,
- StringRef S) override;
- uint64_t getOutputSectionSize(StringRef S) override;
-
- std::vector<OutputSectionBase *> *OutputSections;
-
- int getSectionIndex(StringRef Name);
-
-private:
- void computeInputSections(InputSectionDescription *);
-
- void addSection(OutputSectionFactory<ELFT> &Factory,
- InputSectionBase<ELFT> *Sec, StringRef Name);
- void discard(ArrayRef<InputSectionBase<ELFT> *> V);
-
- std::vector<InputSectionBase<ELFT> *>
- createInputSectionList(OutputSectionCommand &Cmd);
-
- // "ScriptConfig" is a bit too long, so define a short name for it.
- ScriptConfiguration &Opt = *ScriptConfig;
-
- std::vector<size_t> getPhdrIndices(StringRef SectionName);
- size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
-
- uintX_t Dot;
- uintX_t LMAOffset = 0;
- OutputSectionBase *CurOutSec = nullptr;
- uintX_t ThreadBssOffset = 0;
- void switchTo(OutputSectionBase *Sec);
- void flush();
- void output(InputSection<ELFT> *Sec);
- void process(BaseCommand &Base);
- llvm::DenseSet<OutputSectionBase *> AlreadyOutputOS;
- llvm::DenseSet<InputSectionData *> AlreadyOutputIS;
+ void processNonSectionCommands();
+ void assignAddresses();
+ void allocateHeaders(std::vector<PhdrEntry> &Phdrs);
+ void addSymbol(SymbolAssignment *Cmd);
+ void processCommands(OutputSectionFactory &Factory);
+
+ // Parsed linker script configurations are set to this struct.
+ ScriptConfiguration Opt;
};
-// Variable template is a C++14 feature, so we can't template
-// a global variable. Use a struct to workaround.
-template <class ELFT> struct Script { static LinkerScript<ELFT> *X; };
-template <class ELFT> LinkerScript<ELFT> *Script<ELFT>::X;
-
-extern LinkerScriptBase *ScriptBase;
+extern LinkerScript *Script;
} // end namespace elf
} // end namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/MapFile.cpp b/contrib/llvm/tools/lld/ELF/MapFile.cpp
new file mode 100644
index 0000000..2b2a95c
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/MapFile.cpp
@@ -0,0 +1,150 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the -Map option. It shows lists in order and
+// hierarchically the output sections, input sections, input files and
+// symbol:
+//
+// Address Size Align Out In Symbol
+// 00201000 00000015 4 .text
+// 00201000 0000000e 4 test.o:(.text)
+// 0020100e 00000000 0 local
+// 00201005 00000000 0 f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "Threads.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::elf;
+
+typedef DenseMap<const SectionBase *, SmallVector<DefinedRegular *, 4>>
+ SymbolMapTy;
+
+// Print out the first three columns of a line.
+template <class ELFT>
+static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
+ uint64_t Align) {
+ int W = ELFT::Is64Bits ? 16 : 8;
+ OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align);
+}
+
+static std::string indent(int Depth) { return std::string(Depth * 8, ' '); }
+
+// Returns a list of all symbols that we want to print out.
+template <class ELFT> std::vector<DefinedRegular *> getSymbols() {
+ std::vector<DefinedRegular *> V;
+ for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles())
+ for (SymbolBody *B : File->getSymbols())
+ if (B->File == File && !B->isSection())
+ if (auto *Sym = dyn_cast<DefinedRegular>(B))
+ if (Sym->Section && Sym->Section->Live)
+ V.push_back(Sym);
+ return V;
+}
+
+// Returns a map from sections to their symbols.
+template <class ELFT>
+SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
+ SymbolMapTy Ret;
+ for (DefinedRegular *S : Syms)
+ Ret[S->Section].push_back(S);
+
+ // Sort symbols by address. We want to print out symbols in the
+ // order in the output file rather than the order they appeared
+ // in the input files.
+ for (auto &It : Ret) {
+ SmallVectorImpl<DefinedRegular *> &V = It.second;
+ std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
+ return A->getVA() < B->getVA();
+ });
+ }
+ return Ret;
+}
+
+// Construct a map from symbols to their stringified representations.
+// Demangling symbols (which is what toString() does) is slow, so
+// we do that in batch using parallel-for.
+template <class ELFT>
+DenseMap<DefinedRegular *, std::string>
+getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
+ std::vector<std::string> Str(Syms.size());
+ parallelForEachN(0, Syms.size(), [&](size_t I) {
+ raw_string_ostream OS(Str[I]);
+ writeHeader<ELFT>(OS, Syms[I]->getVA(), Syms[I]->template getSize<ELFT>(),
+ 0);
+ OS << indent(2) << toString(*Syms[I]);
+ });
+
+ DenseMap<DefinedRegular *, std::string> Ret;
+ for (size_t I = 0, E = Syms.size(); I < E; ++I)
+ Ret[Syms[I]] = std::move(Str[I]);
+ return Ret;
+}
+
+template <class ELFT>
+void elf::writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script) {
+ if (Config->MapFile.empty())
+ return;
+
+ // Open a map file for writing.
+ std::error_code EC;
+ raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
+ if (EC) {
+ error("cannot open " + Config->MapFile + ": " + EC.message());
+ return;
+ }
+
+ // Collect symbol info that we want to print out.
+ std::vector<DefinedRegular *> Syms = getSymbols<ELFT>();
+ SymbolMapTy SectionSyms = getSectionSyms<ELFT>(Syms);
+ DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings<ELFT>(Syms);
+
+ // Print out the header line.
+ int W = ELFT::Is64Bits ? 16 : 8;
+ OS << left_justify("Address", W) << ' ' << left_justify("Size", W)
+ << " Align Out In Symbol\n";
+
+ // Print out file contents.
+ for (OutputSectionCommand *Cmd : Script) {
+ OutputSection *OSec = Cmd->Sec;
+ writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment);
+ OS << OSec->Name << '\n';
+
+ // Dump symbols for each input section.
+ for (BaseCommand *Base : Cmd->Commands) {
+ auto *ISD = dyn_cast<InputSectionDescription>(Base);
+ if (!ISD)
+ continue;
+ for (InputSection *IS : ISD->Sections) {
+ writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(),
+ IS->Alignment);
+ OS << indent(1) << toString(IS) << '\n';
+ for (DefinedRegular *Sym : SectionSyms[IS])
+ OS << SymStr[Sym] << '\n';
+ }
+ }
+ }
+}
+
+template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSectionCommand *>);
+template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSectionCommand *>);
+template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSectionCommand *>);
+template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSectionCommand *>);
diff --git a/contrib/llvm/tools/lld/ELF/MapFile.h b/contrib/llvm/tools/lld/ELF/MapFile.h
new file mode 100644
index 0000000..460848f
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/MapFile.h
@@ -0,0 +1,23 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_MAPFILE_H
+#define LLD_ELF_MAPFILE_H
+
+#include <llvm/ADT/ArrayRef.h>
+
+namespace lld {
+namespace elf {
+struct OutputSectionCommand;
+template <class ELFT>
+void writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script);
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/MarkLive.cpp b/contrib/llvm/tools/lld/ELF/MarkLive.cpp
index 8d129fc..bde3eef 100644
--- a/contrib/llvm/tools/lld/ELF/MarkLive.cpp
+++ b/contrib/llvm/tools/lld/ELF/MarkLive.cpp
@@ -22,6 +22,7 @@
#include "InputSection.h"
#include "LinkerScript.h"
+#include "Memory.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
@@ -44,51 +45,59 @@ using namespace lld::elf;
namespace {
// A resolved relocation. The Sec and Offset fields are set if the relocation
// was resolved to an offset within a section.
-template <class ELFT> struct ResolvedReloc {
- InputSectionBase<ELFT> *Sec;
- typename ELFT::uint Offset;
+struct ResolvedReloc {
+ InputSectionBase *Sec;
+ uint64_t Offset;
};
} // end anonymous namespace
template <class ELFT>
-static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
+static typename ELFT::uint getAddend(InputSectionBase &Sec,
const typename ELFT::Rel &Rel) {
return Target->getImplicitAddend(Sec.Data.begin() + Rel.r_offset,
- Rel.getType(Config->Mips64EL));
+ Rel.getType(Config->IsMips64EL));
}
template <class ELFT>
-static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
+static typename ELFT::uint getAddend(InputSectionBase &Sec,
const typename ELFT::Rela &Rel) {
return Rel.r_addend;
}
+// There are normally few input sections whose names are valid C
+// identifiers, so we just store a std::vector instead of a multimap.
+static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections;
+
template <class ELFT, class RelT>
-static ResolvedReloc<ELFT> resolveReloc(InputSectionBase<ELFT> &Sec,
- RelT &Rel) {
- SymbolBody &B = Sec.getFile()->getRelocTargetSym(Rel);
- auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
- if (!D || !D->Section)
- return {nullptr, 0};
- typename ELFT::uint Offset = D->Value;
- if (D->isSection())
- Offset += getAddend(Sec, Rel);
- return {D->Section->Repl, Offset};
+static void resolveReloc(InputSectionBase &Sec, RelT &Rel,
+ std::function<void(ResolvedReloc)> Fn) {
+ SymbolBody &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+ if (auto *D = dyn_cast<DefinedRegular>(&B)) {
+ if (!D->Section)
+ return;
+ typename ELFT::uint Offset = D->Value;
+ if (D->isSection())
+ Offset += getAddend<ELFT>(Sec, Rel);
+ Fn({cast<InputSectionBase>(D->Section), Offset});
+ } else if (auto *U = dyn_cast<Undefined>(&B)) {
+ for (InputSectionBase *Sec : CNamedSections.lookup(U->getName()))
+ Fn({Sec, 0});
+ }
}
// Calls Fn for each section that Sec refers to via relocations.
template <class ELFT>
-static void forEachSuccessor(InputSection<ELFT> &Sec,
- std::function<void(ResolvedReloc<ELFT>)> Fn) {
+static void forEachSuccessor(InputSection &Sec,
+ std::function<void(ResolvedReloc)> Fn) {
if (Sec.AreRelocsRela) {
- for (const typename ELFT::Rela &Rel : Sec.relas())
- Fn(resolveReloc(Sec, Rel));
+ for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>())
+ resolveReloc<ELFT>(Sec, Rel, Fn);
} else {
- for (const typename ELFT::Rel &Rel : Sec.rels())
- Fn(resolveReloc(Sec, Rel));
+ for (const typename ELFT::Rel &Rel : Sec.template rels<ELFT>())
+ resolveReloc<ELFT>(Sec, Rel, Fn);
}
- if (Sec.DependentSection)
- Fn({Sec.DependentSection, 0});
+ for (InputSectionBase *IS : Sec.DependentSections)
+ Fn({IS, 0});
}
// The .eh_frame section is an unfortunate special case.
@@ -106,9 +115,8 @@ static void forEachSuccessor(InputSection<ELFT> &Sec,
// the gc pass. With that we would be able to also gc some sections holding
// LSDAs and personality functions if we found that they were unused.
template <class ELFT, class RelTy>
-static void
-scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
- std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+static void scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
+ std::function<void(ResolvedReloc)> Enqueue) {
const endianness E = ELFT::TargetEndianness;
for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
EhSectionPiece &Piece = EH.Pieces[I];
@@ -118,7 +126,7 @@ scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
if (read32<E>(Piece.data().data() + 4) == 0) {
// This is a CIE, we only need to worry about the first relocation. It is
// known to point to the personality function.
- Enqueue(resolveReloc(EH, Rels[FirstRelI]));
+ resolveReloc<ELFT>(EH, Rels[FirstRelI], Enqueue);
continue;
}
// This is a FDE. The relocations point to the described function or to
@@ -129,37 +137,37 @@ scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
const RelTy &Rel = Rels[I2];
if (Rel.r_offset >= PieceEnd)
break;
- ResolvedReloc<ELFT> R = resolveReloc(EH, Rels[I2]);
- if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
- continue;
- if (R.Sec->Flags & SHF_EXECINSTR)
- continue;
- Enqueue({R.Sec, 0});
+ resolveReloc<ELFT>(EH, Rels[I2], [&](ResolvedReloc R) {
+ if (!R.Sec || R.Sec == &InputSection::Discarded)
+ return;
+ if (R.Sec->Flags & SHF_EXECINSTR)
+ return;
+ Enqueue({R.Sec, 0});
+ });
}
}
}
template <class ELFT>
-static void
-scanEhFrameSection(EhInputSection<ELFT> &EH,
- std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+static void scanEhFrameSection(EhInputSection &EH,
+ std::function<void(ResolvedReloc)> Enqueue) {
if (!EH.NumRelocations)
return;
// Unfortunately we need to split .eh_frame early since some relocations in
// .eh_frame keep other section alive and some don't.
- EH.split();
+ EH.split<ELFT>();
if (EH.AreRelocsRela)
- scanEhFrameSection(EH, EH.relas(), Enqueue);
+ scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Enqueue);
else
- scanEhFrameSection(EH, EH.rels(), Enqueue);
+ scanEhFrameSection<ELFT>(EH, EH.template rels<ELFT>(), Enqueue);
}
// We do not garbage-collect two types of sections:
// 1) Sections used by the loader (.init, .fini, .ctors, .dtors or .jcr)
// 2) Non-allocatable sections which typically contain debugging information
-template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
+template <class ELFT> static bool isReserved(InputSectionBase *Sec) {
switch (Sec->Type) {
case SHT_FINI_ARRAY:
case SHT_INIT_ARRAY:
@@ -170,12 +178,7 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
if (!(Sec->Flags & SHF_ALLOC))
return true;
- // We do not want to reclaim sections if they can be referred
- // by __start_* and __stop_* symbols.
StringRef S = Sec->Name;
- if (isValidCIdentifier(S))
- return true;
-
return S.startswith(".ctors") || S.startswith(".dtors") ||
S.startswith(".init") || S.startswith(".fini") ||
S.startswith(".jcr");
@@ -186,14 +189,15 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
// Starting from GC-root sections, this function visits all reachable
// sections to set their "Live" bits.
template <class ELFT> void elf::markLive() {
- SmallVector<InputSection<ELFT> *, 256> Q;
+ SmallVector<InputSection *, 256> Q;
+ CNamedSections.clear();
- auto Enqueue = [&](ResolvedReloc<ELFT> R) {
+ auto Enqueue = [&](ResolvedReloc R) {
// Skip over discarded sections. This in theory shouldn't happen, because
// the ELF spec doesn't allow a relocation to point to a deduplicated
// COMDAT section directly. Unfortunately this happens in practice (e.g.
// .eh_frame) so we need to add a check.
- if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+ if (R.Sec == &InputSection::Discarded)
return;
// We don't gc non alloc sections.
@@ -203,20 +207,21 @@ template <class ELFT> void elf::markLive() {
// Usually, a whole section is marked as live or dead, but in mergeable
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
- if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(R.Sec))
+ if (auto *MS = dyn_cast<MergeInputSection>(R.Sec))
MS->markLiveAt(R.Offset);
if (R.Sec->Live)
return;
R.Sec->Live = true;
// Add input section to the queue.
- if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(R.Sec))
+ if (InputSection *S = dyn_cast<InputSection>(R.Sec))
Q.push_back(S);
};
auto MarkSymbol = [&](const SymbolBody *Sym) {
- if (auto *D = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym))
- Enqueue({D->Section, D->Value});
+ if (auto *D = dyn_cast_or_null<DefinedRegular>(Sym))
+ if (auto *IS = cast_or_null<InputSectionBase>(D->Section))
+ Enqueue({IS, D->Value});
};
// Add GC root symbols.
@@ -225,6 +230,8 @@ template <class ELFT> void elf::markLive() {
MarkSymbol(Symtab<ELFT>::X->find(Config->Fini));
for (StringRef S : Config->Undefined)
MarkSymbol(Symtab<ELFT>::X->find(S));
+ for (StringRef S : Script->Opt.ReferencedSymbols)
+ MarkSymbol(Symtab<ELFT>::X->find(S));
// Preserve externally-visible symbols if the symbols defined by this
// file can interrupt other ELF file's symbols at runtime.
@@ -234,14 +241,20 @@ template <class ELFT> void elf::markLive() {
// Preserve special sections and those which are specified in linker
// script KEEP command.
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
+ for (InputSectionBase *Sec : InputSections) {
// .eh_frame is always marked as live now, but also it can reference to
// sections that contain personality. We preserve all non-text sections
// referred by .eh_frame here.
- if (auto *EH = dyn_cast_or_null<EhInputSection<ELFT>>(Sec))
+ if (auto *EH = dyn_cast_or_null<EhInputSection>(Sec))
scanEhFrameSection<ELFT>(*EH, Enqueue);
- if (isReserved(Sec) || Script<ELFT>::X->shouldKeep(Sec))
+ if (Sec->Flags & SHF_LINK_ORDER)
+ continue;
+ if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec))
Enqueue({Sec, 0});
+ else if (isValidCIdentifier(Sec->Name)) {
+ CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec);
+ CNamedSections[Saver.save("__end_" + Sec->Name)].push_back(Sec);
+ }
}
// Mark all reachable sections.
diff --git a/contrib/llvm/tools/lld/ELF/Memory.h b/contrib/llvm/tools/lld/ELF/Memory.h
index e5a04ed..4000f2f 100644
--- a/contrib/llvm/tools/lld/ELF/Memory.h
+++ b/contrib/llvm/tools/lld/ELF/Memory.h
@@ -61,7 +61,7 @@ inline void freeArena() {
Alloc->reset();
BAlloc.Reset();
}
-}
-}
+} // namespace elf
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/Options.td b/contrib/llvm/tools/lld/ELF/Options.td
index 77ed4c7..1400a20 100644
--- a/contrib/llvm/tools/lld/ELF/Options.td
+++ b/contrib/llvm/tools/lld/ELF/Options.td
@@ -22,6 +22,11 @@ def build_id: F<"build-id">, HelpText<"Generate build ID note">;
def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+def compress_debug_sections : J<"compress-debug-sections=">,
+ HelpText<"Compress DWARF debug sections">;
+
+def defsym: J<"defsym=">, HelpText<"Define a symbol alias">;
+
def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
HelpText<"Add a directory to the library search path">;
@@ -48,6 +53,8 @@ def color_diagnostics_eq: J<"color-diagnostics=">,
def define_common: F<"define-common">,
HelpText<"Assign space to common symbols">;
+def demangle: F<"demangle">, HelpText<"Demangle symbol names">;
+
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@@ -68,6 +75,8 @@ def dynamic_list: S<"dynamic-list">,
def eh_frame_hdr: F<"eh-frame-hdr">,
HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
+def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
+
def enable_new_dtags: F<"enable-new-dtags">,
HelpText<"Enable new dynamic tags">;
@@ -80,6 +89,12 @@ def entry: S<"entry">, MetaVarName<"<entry>">,
def error_limit: S<"error-limit">,
HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+def error_unresolved_symbols: F<"error-unresolved-symbols">,
+ HelpText<"Report unresolved symbols as errors">;
+
+def exclude_libs: S<"exclude-libs">,
+ HelpText<"Exclude static libraries from automatic export">;
+
def export_dynamic: F<"export-dynamic">,
HelpText<"Put symbols in the dynamic symbol table">;
@@ -89,6 +104,8 @@ def export_dynamic_symbol: S<"export-dynamic-symbol">,
def fatal_warnings: F<"fatal-warnings">,
HelpText<"Treat warnings as errors">;
+def filter: J<"filter=">, HelpText<"Set DT_FILTER field to the specified name">;
+
def fini: S<"fini">, MetaVarName<"<symbol>">,
HelpText<"Specify a finalizer function">;
@@ -109,7 +126,9 @@ def hash_style: S<"hash-style">,
def help: F<"help">, HelpText<"Print option help">;
-def icf: F<"icf=all">, HelpText<"Enable identical code folding">;
+def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">;
+
+def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">;
def image_base : J<"image-base=">, HelpText<"Set the base address">;
@@ -124,6 +143,8 @@ def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+def Map: JS<"Map">, HelpText<"Print a link map to the specified file">;
+
def nostdlib: F<"nostdlib">,
HelpText<"Only search directories specified on the command line">;
@@ -139,6 +160,12 @@ def no_define_common: F<"no-define-common">,
def no_demangle: F<"no-demangle">,
HelpText<"Do not demangle symbol names">;
+def no_dynamic_linker: F<"no-dynamic-linker">,
+ HelpText<"Inhibit output of .interp section">;
+
+def no_export_dynamic: F<"no-export-dynamic">;
+def no_fatal_warnings: F<"no-fatal-warnings">;
+
def no_gc_sections: F<"no-gc-sections">,
HelpText<"Disable garbage collection of unused sections">;
@@ -170,7 +197,7 @@ def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
HelpText<"Specify the binary format for the output object file">;
-def omagic: F<"omagic">, MetaVarName<"<magic>">,
+def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
HelpText<"Set the text and data sections to be readable and writable">;
def pie: F<"pie">, HelpText<"Create a position independent executable">;
@@ -178,6 +205,9 @@ def pie: F<"pie">, HelpText<"Create a position independent executable">;
def print_gc_sections: F<"print-gc-sections">,
HelpText<"List removed unused sections">;
+def print_map: F<"print-map">,
+ HelpText<"Print a link map to the standard output">;
+
def reproduce: S<"reproduce">,
HelpText<"Dump linker invocation and input files for debugging">;
@@ -221,7 +251,7 @@ def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
-def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">;
+def trace_symbol : S<"trace-symbol">, HelpText<"Trace references to symbols">;
def undefined: S<"undefined">,
HelpText<"Force undefined symbol during linking">;
@@ -244,6 +274,9 @@ def version_script: S<"version-script">,
def warn_common: F<"warn-common">,
HelpText<"Warn about duplicate common symbols">;
+def warn_unresolved_symbols: F<"warn-unresolved-symbols">,
+ HelpText<"Report unresolved symbols as warnings">;
+
def whole_archive: F<"whole-archive">,
HelpText<"Force load of all members in a static library">;
@@ -264,25 +297,32 @@ def alias_L__library_path: J<"library-path=">, Alias<L>;
def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>;
def alias_define_common_dc: F<"dc">, Alias<define_common>;
def alias_define_common_dp: F<"dp">, Alias<define_common>;
+def alias_defsym: S<"defsym">, Alias<defsym>;
def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
+def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_entry_entry: J<"entry=">, Alias<entry>;
def alias_error_limit: J<"error-limit=">, Alias<error_limit>;
+def alias_exclude_libs: J<"exclude-libs=">, Alias<exclude_libs>;
def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>;
def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">,
Alias<export_dynamic_symbol>;
+def alias_filter: Separate<["-"], "F">, Alias<filter>;
def alias_fini_fini: J<"fini=">, Alias<fini>;
def alias_format_b: S<"b">, Alias<format>;
def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>;
def alias_init_init: J<"init=">, Alias<init>;
def alias_l__library: J<"library=">, Alias<l>;
+def alias_Map_eq: J<"Map=">, Alias<Map>;
def alias_omagic: Flag<["-"], "N">, Alias<omagic>;
def alias_o_output: Joined<["--"], "output=">, Alias<o>;
def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
+def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;
def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
+def alias_reproduce_eq: J<"reproduce=">, Alias<reproduce>;
def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>;
def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;
def alias_rpath_rpath: J<"rpath=">, Alias<rpath>;
@@ -297,12 +337,14 @@ def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
def alias_Tbss: J<"Tbss=">, Alias<Tbss>;
def alias_Tdata: J<"Tdata=">, Alias<Tdata>;
def alias_trace: Flag<["-"], "t">, Alias<trace>;
+def trace_trace_symbol_eq : J<"trace-symbol=">, Alias<trace_symbol>;
def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
def alias_Ttext: J<"Ttext=">, Alias<Ttext>;
def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>;
def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias<Ttext>;
def alias_undefined_eq: J<"undefined=">, Alias<undefined>;
def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
+def alias_version_script_eq: J<"version-script=">, Alias<version_script>;
def alias_version_V: Flag<["-"], "V">, Alias<version>;
def alias_wrap_wrap: J<"wrap=">, Alias<wrap>;
@@ -314,6 +356,26 @@ def end_group_paren: Flag<["-"], ")">;
def start_group: F<"start-group">;
def start_group_paren: Flag<["-"], "(">;
+// LTO-related options.
+def lto_aa_pipeline: J<"lto-aa-pipeline=">,
+ HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
+def lto_newpm_passes: J<"lto-newpm-passes=">,
+ HelpText<"Passes to run during LTO">;
+def lto_partitions: J<"lto-partitions=">,
+ HelpText<"Number of LTO codegen partitions">;
+def disable_verify: F<"disable-verify">;
+def mllvm: S<"mllvm">;
+def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
+ HelpText<"YAML output file for optimization remarks">;
+def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
+ HelpText<"Include hotness informations in the optimization remarks file">;
+def save_temps: F<"save-temps">;
+def thinlto_cache_dir: J<"thinlto-cache-dir=">,
+ HelpText<"Path to ThinLTO cached object file directory">;
+def thinlto_cache_policy: S<"thinlto-cache-policy">,
+ HelpText<"Pruning policy for the ThinLTO cache">;
+def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+
// Ignore LTO plugin-related options.
// clang -flto passes -plugin and -plugin-opt to the linker. This is required
// for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't
@@ -329,17 +391,13 @@ def plugin_opt_eq: J<"plugin-opt=">;
// Options listed below are silently ignored for now for compatibility.
def allow_shlib_undefined: F<"allow-shlib-undefined">;
def cref: Flag<["--"], "cref">;
-def demangle: F<"demangle">;
def detect_odr_violations: F<"detect-odr-violations">;
def g: Flag<["-"], "g">;
-def M: Flag<["-"], "M">;
-def Map: JS<"Map">;
def no_add_needed: F<"no-add-needed">;
def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">,
Alias<no_add_needed>;
-def no_dynamic_linker: F<"no-dynamic-linker">;
-def no_fatal_warnings: F<"no-fatal-warnings">;
+def no_keep_memory: F<"no-keep-memory">;
def no_mmap_output_file: F<"no-mmap-output-file">;
def no_warn_common: F<"no-warn-common">;
def no_warn_mismatch: F<"no-warn-mismatch">;
@@ -354,19 +412,3 @@ def EL : F<"EL">;
def G: JoinedOrSeparate<["-"], "G">;
def Qy : F<"Qy">;
-// Aliases for ignored options
-def alias_Map_eq: J<"Map=">, Alias<Map>;
-def alias_version_script_version_script: J<"version-script=">,
- Alias<version_script>;
-
-// LTO-related options.
-def lto_aa_pipeline: J<"lto-aa-pipeline=">,
- HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">;
-def lto_newpm_passes: J<"lto-newpm-passes=">,
- HelpText<"Passes to run during LTO">;
-def lto_partitions: J<"lto-partitions=">,
- HelpText<"Number of LTO codegen partitions">;
-def disable_verify: F<"disable-verify">;
-def mllvm: S<"mllvm">;
-def save_temps: F<"save-temps">;
-def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
diff --git a/contrib/llvm/tools/lld/ELF/OutputSections.cpp b/contrib/llvm/tools/lld/ELF/OutputSections.cpp
index 7c708ce..abe5481 100644
--- a/contrib/llvm/tools/lld/ELF/OutputSections.cpp
+++ b/contrib/llvm/tools/lld/ELF/OutputSections.cpp
@@ -9,7 +9,6 @@
#include "OutputSections.h"
#include "Config.h"
-#include "EhFrame.h"
#include "LinkerScript.h"
#include "Memory.h"
#include "Strings.h"
@@ -17,7 +16,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Threads.h"
-#include "llvm/Support/Dwarf.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SHA1.h"
@@ -31,15 +30,21 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-OutputSectionBase::OutputSectionBase(StringRef Name, uint32_t Type,
- uint64_t Flags)
- : Name(Name) {
- this->Type = Type;
- this->Flags = Flags;
- this->Addralign = 1;
-}
-
-uint32_t OutputSectionBase::getPhdrFlags() const {
+uint8_t Out::First;
+OutputSection *Out::Opd;
+uint8_t *Out::OpdBuf;
+PhdrEntry *Out::TlsPhdr;
+OutputSection *Out::DebugInfo;
+OutputSection *Out::ElfHeader;
+OutputSection *Out::ProgramHeaders;
+OutputSection *Out::PreinitArray;
+OutputSection *Out::InitArray;
+OutputSection *Out::FiniArray;
+
+std::vector<OutputSection *> elf::OutputSections;
+std::vector<OutputSectionCommand *> elf::OutputSectionCommands;
+
+uint32_t OutputSection::getPhdrFlags() const {
uint32_t Ret = PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
@@ -49,9 +54,9 @@ uint32_t OutputSectionBase::getPhdrFlags() const {
}
template <class ELFT>
-void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
+void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
Shdr->sh_entsize = Entsize;
- Shdr->sh_addralign = Addralign;
+ Shdr->sh_addralign = Alignment;
Shdr->sh_type = Type;
Shdr->sh_offset = Offset;
Shdr->sh_flags = Flags;
@@ -62,490 +67,41 @@ void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
Shdr->sh_name = ShName;
}
-template <class ELFT> static uint64_t getEntsize(uint32_t Type) {
- switch (Type) {
- case SHT_RELA:
- return sizeof(typename ELFT::Rela);
- case SHT_REL:
- return sizeof(typename ELFT::Rel);
- case SHT_MIPS_REGINFO:
- return sizeof(Elf_Mips_RegInfo<ELFT>);
- case SHT_MIPS_OPTIONS:
- return sizeof(Elf_Mips_Options<ELFT>) + sizeof(Elf_Mips_RegInfo<ELFT>);
- case SHT_MIPS_ABIFLAGS:
- return sizeof(Elf_Mips_ABIFlags<ELFT>);
- default:
- return 0;
- }
-}
+OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
+ : SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
+ /*Info*/ 0,
+ /*Link*/ 0),
+ SectionIndex(INT_MAX) {}
-template <class ELFT>
-OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
- : OutputSectionBase(Name, Type, Flags) {
- this->Entsize = getEntsize<ELFT>(Type);
-}
-
-template <typename ELFT>
-static bool compareByFilePosition(InputSection<ELFT> *A,
- InputSection<ELFT> *B) {
- // Synthetic doesn't have link order dependecy, stable_sort will keep it last
- if (A->kind() == InputSectionData::Synthetic ||
- B->kind() == InputSectionData::Synthetic)
- return false;
- auto *LA = cast<InputSection<ELFT>>(A->getLinkOrderDep());
- auto *LB = cast<InputSection<ELFT>>(B->getLinkOrderDep());
- OutputSectionBase *AOut = LA->OutSec;
- OutputSectionBase *BOut = LB->OutSec;
- if (AOut != BOut)
- return AOut->SectionIndex < BOut->SectionIndex;
- return LA->OutSecOff < LB->OutSecOff;
+static uint64_t updateOffset(uint64_t Off, InputSection *S) {
+ Off = alignTo(Off, S->Alignment);
+ S->OutSecOff = Off;
+ return Off + S->getSize();
}
-template <class ELFT> void OutputSection<ELFT>::finalize() {
- if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
- std::sort(Sections.begin(), Sections.end(), compareByFilePosition<ELFT>);
- Size = 0;
- assignOffsets();
-
- // We must preserve the link order dependency of sections with the
- // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
- // need to translate the InputSection sh_link to the OutputSection sh_link,
- // all InputSections in the OutputSection have the same dependency.
- if (auto *D = this->Sections.front()->getLinkOrderDep())
- this->Link = D->OutSec->SectionIndex;
- }
-
- uint32_t Type = this->Type;
- if (!Config->Relocatable || (Type != SHT_RELA && Type != SHT_REL))
- return;
-
- this->Link = In<ELFT>::SymTab->OutSec->SectionIndex;
- // sh_info for SHT_REL[A] sections should contain the section header index of
- // the section to which the relocation applies.
- InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection();
- this->Info = S->OutSec->SectionIndex;
-}
-
-template <class ELFT>
-void OutputSection<ELFT>::addSection(InputSectionData *C) {
- assert(C->Live);
- auto *S = cast<InputSection<ELFT>>(C);
+void OutputSection::addSection(InputSection *S) {
+ assert(S->Live);
Sections.push_back(S);
- S->OutSec = this;
+ S->Parent = this;
this->updateAlignment(S->Alignment);
- // Keep sh_entsize value of the input section to be able to perform merging
- // later during a final linking using the generated relocatable object.
- if (Config->Relocatable && (S->Flags & SHF_MERGE))
- this->Entsize = S->Entsize;
-}
-
-// This function is called after we sort input sections
-// and scan relocations to setup sections' offsets.
-template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
- uintX_t Off = this->Size;
- for (InputSection<ELFT> *S : Sections) {
- Off = alignTo(Off, S->Alignment);
- S->OutSecOff = Off;
- Off += S->getSize();
- }
- this->Size = Off;
-}
-
-template <class ELFT>
-void OutputSection<ELFT>::sort(
- std::function<int(InputSection<ELFT> *S)> Order) {
- typedef std::pair<unsigned, InputSection<ELFT> *> Pair;
- auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
-
- std::vector<Pair> V;
- for (InputSection<ELFT> *S : Sections)
- V.push_back({Order(S), S});
- std::stable_sort(V.begin(), V.end(), Comp);
- Sections.clear();
- for (Pair &P : V)
- Sections.push_back(P.second);
-}
-
-// Sorts input sections by section name suffixes, so that .foo.N comes
-// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
-// We want to keep the original order if the priorities are the same
-// because the compiler keeps the original initialization order in a
-// translation unit and we need to respect that.
-// For more detail, read the section of the GCC's manual about init_priority.
-template <class ELFT> void OutputSection<ELFT>::sortInitFini() {
- // Sort sections by priority.
- sort([](InputSection<ELFT> *S) { return getPriority(S->Name); });
-}
-
-// Returns true if S matches /Filename.?\.o$/.
-static bool isCrtBeginEnd(StringRef S, StringRef Filename) {
- if (!S.endswith(".o"))
- return false;
- S = S.drop_back(2);
- if (S.endswith(Filename))
- return true;
- return !S.empty() && S.drop_back().endswith(Filename);
-}
-
-static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); }
-static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
-
-// .ctors and .dtors are sorted by this priority from highest to lowest.
-//
-// 1. The section was contained in crtbegin (crtbegin contains
-// some sentinel value in its .ctors and .dtors so that the runtime
-// can find the beginning of the sections.)
-//
-// 2. The section has an optional priority value in the form of ".ctors.N"
-// or ".dtors.N" where N is a number. Unlike .{init,fini}_array,
-// they are compared as string rather than number.
-//
-// 3. The section is just ".ctors" or ".dtors".
-//
-// 4. The section was contained in crtend, which contains an end marker.
-//
-// In an ideal world, we don't need this function because .init_array and
-// .ctors are duplicate features (and .init_array is newer.) However, there
-// are too many real-world use cases of .ctors, so we had no choice to
-// support that with this rather ad-hoc semantics.
-template <class ELFT>
-static bool compCtors(const InputSection<ELFT> *A,
- const InputSection<ELFT> *B) {
- bool BeginA = isCrtbegin(A->getFile()->getName());
- bool BeginB = isCrtbegin(B->getFile()->getName());
- if (BeginA != BeginB)
- return BeginA;
- bool EndA = isCrtend(A->getFile()->getName());
- bool EndB = isCrtend(B->getFile()->getName());
- if (EndA != EndB)
- return EndB;
- StringRef X = A->Name;
- StringRef Y = B->Name;
- assert(X.startswith(".ctors") || X.startswith(".dtors"));
- assert(Y.startswith(".ctors") || Y.startswith(".dtors"));
- X = X.substr(6);
- Y = Y.substr(6);
- if (X.empty() && Y.empty())
- return false;
- return X < Y;
-}
-
-// Sorts input sections by the special rules for .ctors and .dtors.
-// Unfortunately, the rules are different from the one for .{init,fini}_array.
-// Read the comment above.
-template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
- std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
-}
-
-// Fill [Buf, Buf + Size) with Filler. Filler is written in big
-// endian order. This is used for linker script "=fillexp" command.
-void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
- uint8_t V[4];
- write32be(V, Filler);
- size_t I = 0;
- for (; I + 4 < Size; I += 4)
- memcpy(Buf + I, V, 4);
- memcpy(Buf + I, V, Size - I);
-}
-
-template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
- Loc = Buf;
- if (uint32_t Filler = Script<ELFT>::X->getFiller(this->Name))
- fill(Buf, this->Size, Filler);
-
- auto Fn = [=](InputSection<ELFT> *IS) { IS->writeTo(Buf); };
- forEach(Sections.begin(), Sections.end(), Fn);
-
- // Linker scripts may have BYTE()-family commands with which you
- // can write arbitrary bytes to the output. Process them if any.
- Script<ELFT>::X->writeDataBytes(this->Name, Buf);
-}
-
-template <class ELFT>
-EhOutputSection<ELFT>::EhOutputSection()
- : OutputSectionBase(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
-
-// Search for an existing CIE record or create a new one.
-// CIE records from input object files are uniquified by their contents
-// and where their relocations point to.
-template <class ELFT>
-template <class RelTy>
-CieRecord *EhOutputSection<ELFT>::addCie(EhSectionPiece &Piece,
- ArrayRef<RelTy> Rels) {
- auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
- const endianness E = ELFT::TargetEndianness;
- if (read32<E>(Piece.data().data() + 4) != 0)
- fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
-
- SymbolBody *Personality = nullptr;
- unsigned FirstRelI = Piece.FirstRelocation;
- if (FirstRelI != (unsigned)-1)
- Personality = &Sec->getFile()->getRelocTargetSym(Rels[FirstRelI]);
-
- // Search for an existing CIE by CIE contents/relocation target pair.
- CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
-
- // If not found, create a new one.
- if (Cie->Piece == nullptr) {
- Cie->Piece = &Piece;
- Cies.push_back(Cie);
- }
- return Cie;
-}
-
-// There is one FDE per function. Returns true if a given FDE
-// points to a live function.
-template <class ELFT>
-template <class RelTy>
-bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
- ArrayRef<RelTy> Rels) {
- auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
- unsigned FirstRelI = Piece.FirstRelocation;
- if (FirstRelI == (unsigned)-1)
- fatal(toString(Sec) + ": FDE doesn't reference another section");
- const RelTy &Rel = Rels[FirstRelI];
- SymbolBody &B = Sec->getFile()->getRelocTargetSym(Rel);
- auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
- if (!D || !D->Section)
- return false;
- InputSectionBase<ELFT> *Target = D->Section->Repl;
- return Target && Target->Live;
-}
-
-// .eh_frame is a sequence of CIE or FDE records. In general, there
-// is one CIE record per input object file which is followed by
-// a list of FDEs. This function searches an existing CIE or create a new
-// one and associates FDEs to the CIE.
-template <class ELFT>
-template <class RelTy>
-void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> Rels) {
- const endianness E = ELFT::TargetEndianness;
-
- DenseMap<size_t, CieRecord *> OffsetToCie;
- for (EhSectionPiece &Piece : Sec->Pieces) {
- // The empty record is the end marker.
- if (Piece.size() == 4)
- return;
-
- size_t Offset = Piece.InputOff;
- uint32_t ID = read32<E>(Piece.data().data() + 4);
- if (ID == 0) {
- OffsetToCie[Offset] = addCie(Piece, Rels);
- continue;
- }
-
- uint32_t CieOffset = Offset + 4 - ID;
- CieRecord *Cie = OffsetToCie[CieOffset];
- if (!Cie)
- fatal(toString(Sec) + ": invalid CIE reference");
-
- if (!isFdeLive(Piece, Rels))
- continue;
- Cie->FdePieces.push_back(&Piece);
- NumFdes++;
- }
-}
-
-template <class ELFT>
-void EhOutputSection<ELFT>::addSection(InputSectionData *C) {
- auto *Sec = cast<EhInputSection<ELFT>>(C);
- Sec->OutSec = this;
- this->updateAlignment(Sec->Alignment);
- Sections.push_back(Sec);
-
- // .eh_frame is a sequence of CIE or FDE records. This function
- // splits it into pieces so that we can call
- // SplitInputSection::getSectionPiece on the section.
- Sec->split();
- if (Sec->Pieces.empty())
- return;
-
- if (Sec->NumRelocations) {
- if (Sec->AreRelocsRela)
- addSectionAux(Sec, Sec->relas());
- else
- addSectionAux(Sec, Sec->rels());
- return;
- }
- addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
-}
-
-template <class ELFT>
-static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
- memcpy(Buf, D.data(), D.size());
- // Fix the size field. -4 since size does not include the size field itself.
- const endianness E = ELFT::TargetEndianness;
- write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
-}
-
-template <class ELFT> void EhOutputSection<ELFT>::finalize() {
- if (this->Size)
- return; // Already finalized.
-
- size_t Off = 0;
- for (CieRecord *Cie : Cies) {
- Cie->Piece->OutputOff = Off;
- Off += alignTo(Cie->Piece->size(), sizeof(uintX_t));
-
- for (EhSectionPiece *Fde : Cie->FdePieces) {
- Fde->OutputOff = Off;
- Off += alignTo(Fde->size(), sizeof(uintX_t));
- }
- }
- this->Size = Off;
-}
-
-template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
- const endianness E = ELFT::TargetEndianness;
- switch (Size) {
- case DW_EH_PE_udata2:
- return read16<E>(Buf);
- case DW_EH_PE_udata4:
- return read32<E>(Buf);
- case DW_EH_PE_udata8:
- return read64<E>(Buf);
- case DW_EH_PE_absptr:
- if (ELFT::Is64Bits)
- return read64<E>(Buf);
- return read32<E>(Buf);
- }
- fatal("unknown FDE size encoding");
-}
-
-// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
-// We need it to create .eh_frame_hdr section.
-template <class ELFT>
-typename ELFT::uint EhOutputSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
- uint8_t Enc) {
- // The starting address to which this FDE applies is
- // stored at FDE + 8 byte.
- size_t Off = FdeOff + 8;
- uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
- if ((Enc & 0x70) == DW_EH_PE_absptr)
- return Addr;
- if ((Enc & 0x70) == DW_EH_PE_pcrel)
- return Addr + this->Addr + Off;
- fatal("unknown FDE size relative encoding");
-}
-
-template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- const endianness E = ELFT::TargetEndianness;
- for (CieRecord *Cie : Cies) {
- size_t CieOffset = Cie->Piece->OutputOff;
- writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
-
- for (EhSectionPiece *Fde : Cie->FdePieces) {
- size_t Off = Fde->OutputOff;
- writeCieFde<ELFT>(Buf + Off, Fde->data());
-
- // FDE's second word should have the offset to an associated CIE.
- // Write it.
- write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
- }
- }
-
- for (EhInputSection<ELFT> *S : Sections)
- S->relocate(Buf, nullptr);
-
- // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
- // to get a FDE from an address to which FDE is applied. So here
- // we obtain two addresses and pass them to EhFrameHdr object.
- if (In<ELFT>::EhFrameHdr) {
- for (CieRecord *Cie : Cies) {
- uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
- for (SectionPiece *Fde : Cie->FdePieces) {
- uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
- uintX_t FdeVA = this->Addr + Fde->OutputOff;
- In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
- }
- }
- }
-}
-
-template <class ELFT>
-MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
- uintX_t Flags, uintX_t Alignment)
- : OutputSectionBase(Name, Type, Flags),
- Builder(StringTableBuilder::RAW, Alignment) {}
-
-template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- Builder.write(Buf);
-}
-
-template <class ELFT>
-void MergeOutputSection<ELFT>::addSection(InputSectionData *C) {
- auto *Sec = cast<MergeInputSection<ELFT>>(C);
- Sec->OutSec = this;
- this->updateAlignment(Sec->Alignment);
- this->Entsize = Sec->Entsize;
- Sections.push_back(Sec);
-}
-
-template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
- return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
-}
-
-template <class ELFT> void MergeOutputSection<ELFT>::finalizeTailMerge() {
- // Add all string pieces to the string table builder to create section
- // contents.
- for (MergeInputSection<ELFT> *Sec : Sections)
- for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
- if (Sec->Pieces[I].Live)
- Builder.add(Sec->getData(I));
-
- // Fix the string table content. After this, the contents will never change.
- Builder.finalize();
- this->Size = Builder.getSize();
-
- // finalize() fixed tail-optimized strings, so we can now get
- // offsets of strings. Get an offset for each string and save it
- // to a corresponding StringPiece for easy access.
- for (MergeInputSection<ELFT> *Sec : Sections)
- for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
- if (Sec->Pieces[I].Live)
- Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
-}
-
-template <class ELFT> void MergeOutputSection<ELFT>::finalizeNoTailMerge() {
- // Add all string pieces to the string table builder to create section
- // contents. Because we are not tail-optimizing, offsets of strings are
- // fixed when they are added to the builder (string table builder contains
- // a hash table from strings to offsets).
- for (MergeInputSection<ELFT> *Sec : Sections)
- for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
- if (Sec->Pieces[I].Live)
- Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
-
- Builder.finalizeInOrder();
- this->Size = Builder.getSize();
-}
+ // The actual offsets will be computed by assignAddresses. For now, use
+ // crude approximation so that it is at least easy for other code to know the
+ // section order. It is also used to calculate the output section size early
+ // for compressed debug sections.
+ this->Size = updateOffset(Size, S);
-template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
- if (shouldTailMerge())
- finalizeTailMerge();
- else
- finalizeNoTailMerge();
+ // If this section contains a table of fixed-size entries, sh_entsize
+ // holds the element size. Consequently, if this contains two or more
+ // input sections, all of them must have the same sh_entsize. However,
+ // you can put different types of input sections into one output
+ // sectin by using linker scripts. I don't know what to do here.
+ // Probably we sholuld handle that as an error. But for now we just
+ // pick the largest sh_entsize.
+ this->Entsize = std::max(this->Entsize, S->Entsize);
}
-template <class ELFT>
-static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
- return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
-}
-
-namespace llvm {
-template <> struct DenseMapInfo<lld::elf::SectionKey> {
- static lld::elf::SectionKey getEmptyKey();
- static lld::elf::SectionKey getTombstoneKey();
- static unsigned getHashValue(const lld::elf::SectionKey &Val);
- static bool isEqual(const lld::elf::SectionKey &LHS,
- const lld::elf::SectionKey &RHS);
-};
-}
-
-template <class ELFT>
-static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
+static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
// The ELF spec just says
// ----------------------------------------------------------------
// In the first phase, input sections that match in name, type and
@@ -588,81 +144,109 @@ static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
//
// Given the above issues, we instead merge sections by name and error on
// incompatible types and flags.
- //
- // The exception being SHF_MERGE, where we create different output sections
- // for each alignment. This makes each output section simple. In case of
- // relocatable object generation we do not try to perform merging and treat
- // SHF_MERGE sections as regular ones, but also create different output
- // sections for them to allow merging at final linking stage.
- //
- // Fortunately, creating symbols in the middle of a merge section is not
- // supported by bfd or gold, so the SHF_MERGE exception should not cause
- // problems with most linker scripts.
- typedef typename ELFT::uint uintX_t;
- uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
-
- uintX_t Alignment = 0;
- if (isa<MergeInputSection<ELFT>>(C) ||
- (Config->Relocatable && (C->Flags & SHF_MERGE)))
- Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
+ uint32_t Alignment = 0;
+ uint64_t Flags = 0;
+ if (Config->Relocatable && (C->Flags & SHF_MERGE)) {
+ Alignment = std::max<uint64_t>(C->Alignment, C->Entsize);
+ Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
+ }
return SectionKey{OutsecName, Flags, Alignment};
}
-template <class ELFT> OutputSectionFactory<ELFT>::OutputSectionFactory() {}
+OutputSectionFactory::OutputSectionFactory() {}
-template <class ELFT> OutputSectionFactory<ELFT>::~OutputSectionFactory() {}
+static uint64_t getIncompatibleFlags(uint64_t Flags) {
+ return Flags & (SHF_ALLOC | SHF_TLS);
+}
-template <class ELFT>
-std::pair<OutputSectionBase *, bool>
-OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
- StringRef OutsecName) {
- SectionKey Key = createKey(C, OutsecName);
- return create(Key, C);
+// We allow sections of types listed below to merged into a
+// single progbits section. This is typically done by linker
+// scripts. Merging nobits and progbits will force disk space
+// to be allocated for nobits sections. Other ones don't require
+// any special treatment on top of progbits, so there doesn't
+// seem to be a harm in merging them.
+static bool canMergeToProgbits(unsigned Type) {
+ return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY ||
+ Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY ||
+ Type == SHT_NOTE;
}
-static uint64_t getIncompatibleFlags(uint64_t Flags) {
- return Flags & (SHF_ALLOC | SHF_TLS);
+void elf::reportDiscarded(InputSectionBase *IS) {
+ if (!Config->PrintGcSections)
+ return;
+ message("removing unused section from '" + IS->Name + "' in file '" +
+ IS->File->getName() + "'");
+}
+
+void OutputSectionFactory::addInputSec(InputSectionBase *IS,
+ StringRef OutsecName) {
+ // Sections with the SHT_GROUP attribute reach here only when the - r option
+ // is given. Such sections define "section groups", and InputFiles.cpp has
+ // dedup'ed section groups by their signatures. For the -r, we want to pass
+ // through all SHT_GROUP sections without merging them because merging them
+ // creates broken section contents.
+ if (IS->Type == SHT_GROUP) {
+ OutputSection *Out = nullptr;
+ addInputSec(IS, OutsecName, Out);
+ return;
+ }
+
+ // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have
+ // relocation sections .rela.foo and .rela.bar for example. Most tools do
+ // not allow multiple REL[A] sections for output section. Hence we
+ // should combine these relocation sections into single output.
+ // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any
+ // other REL[A] sections created by linker itself.
+ if (!isa<SyntheticSection>(IS) &&
+ (IS->Type == SHT_REL || IS->Type == SHT_RELA)) {
+ auto *Sec = cast<InputSection>(IS);
+ OutputSection *Out = Sec->getRelocatedSection()->getOutputSection();
+ addInputSec(IS, OutsecName, Out->RelocationSection);
+ return;
+ }
+
+ SectionKey Key = createKey(IS, OutsecName);
+ OutputSection *&Sec = Map[Key];
+ addInputSec(IS, OutsecName, Sec);
}
-template <class ELFT>
-std::pair<OutputSectionBase *, bool>
-OutputSectionFactory<ELFT>::create(const SectionKey &Key,
- InputSectionBase<ELFT> *C) {
- uintX_t Flags = getOutFlags(C);
- OutputSectionBase *&Sec = Map[Key];
- if (Sec) {
- if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(C->Flags))
- error("Section has flags incompatible with others with the same name " +
- toString(C));
- // Convert notbits to progbits if they are mixed. This happens is some
- // linker scripts.
- if (Sec->Type == SHT_NOBITS && C->Type == SHT_PROGBITS)
- Sec->Type = SHT_PROGBITS;
- if (Sec->Type != C->Type &&
- !(Sec->Type == SHT_PROGBITS && C->Type == SHT_NOBITS))
- error("Section has different type from others with the same name " +
- toString(C));
- Sec->Flags |= Flags;
- return {Sec, false};
+void OutputSectionFactory::addInputSec(InputSectionBase *IS,
+ StringRef OutsecName,
+ OutputSection *&Sec) {
+ if (!IS->Live) {
+ reportDiscarded(IS);
+ return;
}
- uint32_t Type = C->Type;
- switch (C->kind()) {
- case InputSectionBase<ELFT>::Regular:
- case InputSectionBase<ELFT>::Synthetic:
- Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
- break;
- case InputSectionBase<ELFT>::EHFrame:
- return {Out<ELFT>::EhFrame, false};
- case InputSectionBase<ELFT>::Merge:
- Sec = make<MergeOutputSection<ELFT>>(Key.Name, Type, Flags, Key.Alignment);
- break;
+ if (Sec) {
+ if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))
+ error("incompatible section flags for " + Sec->Name + "\n>>> " +
+ toString(IS) + ": 0x" + utohexstr(IS->Flags) +
+ "\n>>> output section " + Sec->Name + ": 0x" +
+ utohexstr(Sec->Flags));
+ if (Sec->Type != IS->Type) {
+ if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type))
+ Sec->Type = SHT_PROGBITS;
+ else
+ error("section type mismatch for " + IS->Name + "\n>>> " +
+ toString(IS) + ": " +
+ getELFSectionTypeName(Config->EMachine, IS->Type) +
+ "\n>>> output section " + Sec->Name + ": " +
+ getELFSectionTypeName(Config->EMachine, Sec->Type));
+ }
+ Sec->Flags |= IS->Flags;
+ } else {
+ Sec = make<OutputSection>(OutsecName, IS->Type, IS->Flags);
+ OutputSections.push_back(Sec);
}
- return {Sec, true};
+
+ Sec->addSection(cast<InputSection>(IS));
}
+OutputSectionFactory::~OutputSectionFactory() {}
+
SectionKey DenseMapInfo<SectionKey>::getEmptyKey() {
return SectionKey{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
}
@@ -681,32 +265,13 @@ bool DenseMapInfo<SectionKey>::isEqual(const SectionKey &LHS,
LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment;
}
-namespace lld {
-namespace elf {
-
-template void OutputSectionBase::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
-template void OutputSectionBase::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
-template void OutputSectionBase::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
-template void OutputSectionBase::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
-
-template class OutputSection<ELF32LE>;
-template class OutputSection<ELF32BE>;
-template class OutputSection<ELF64LE>;
-template class OutputSection<ELF64BE>;
-
-template class EhOutputSection<ELF32LE>;
-template class EhOutputSection<ELF32BE>;
-template class EhOutputSection<ELF64LE>;
-template class EhOutputSection<ELF64BE>;
-
-template class MergeOutputSection<ELF32LE>;
-template class MergeOutputSection<ELF32BE>;
-template class MergeOutputSection<ELF64LE>;
-template class MergeOutputSection<ELF64BE>;
-
-template class OutputSectionFactory<ELF32LE>;
-template class OutputSectionFactory<ELF32BE>;
-template class OutputSectionFactory<ELF64LE>;
-template class OutputSectionFactory<ELF64BE>;
-}
+uint64_t elf::getHeaderSize() {
+ if (Config->OFormatBinary)
+ return 0;
+ return Out::ElfHeader->Size + Out::ProgramHeaders->Size;
}
+
+template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
diff --git a/contrib/llvm/tools/lld/ELF/OutputSections.h b/contrib/llvm/tools/lld/ELF/OutputSections.h
index 5c494bb..68b46eb 100644
--- a/contrib/llvm/tools/lld/ELF/OutputSections.h
+++ b/contrib/llvm/tools/lld/ELF/OutputSections.h
@@ -11,6 +11,7 @@
#define LLD_ELF_OUTPUT_SECTIONS_H
#include "Config.h"
+#include "InputSection.h"
#include "Relocations.h"
#include "lld/Core/LLVM.h"
@@ -23,248 +24,130 @@ namespace elf {
struct PhdrEntry;
class SymbolBody;
struct EhSectionPiece;
-template <class ELFT> class EhInputSection;
-template <class ELFT> class InputSection;
-template <class ELFT> class InputSectionBase;
-template <class ELFT> class MergeInputSection;
-template <class ELFT> class OutputSection;
+class EhInputSection;
+class InputSection;
+class InputSectionBase;
+class MergeInputSection;
+class OutputSection;
template <class ELFT> class ObjectFile;
template <class ELFT> class SharedFile;
-template <class ELFT> class SharedSymbol;
-template <class ELFT> class DefinedRegular;
+class SharedSymbol;
+class DefinedRegular;
// This represents a section in an output file.
-// Different sub classes represent different types of sections. Some contain
-// input sections, others are created by the linker.
+// It is composed of multiple InputSections.
// The writer creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
-class OutputSectionBase {
+class OutputSection final : public SectionBase {
public:
- enum Kind {
- Base,
- EHFrame,
- Merge,
- Regular,
- };
+ OutputSection(StringRef Name, uint32_t Type, uint64_t Flags);
+
+ static bool classof(const SectionBase *S) {
+ return S->kind() == SectionBase::Output;
+ }
- OutputSectionBase(StringRef Name, uint32_t Type, uint64_t Flags);
- void setLMAOffset(uint64_t LMAOff) { LMAOffset = LMAOff; }
uint64_t getLMA() const { return Addr + LMAOffset; }
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
- StringRef getName() const { return Name; }
-
- virtual void addSection(InputSectionData *C) {}
- virtual Kind getKind() const { return Base; }
- static bool classof(const OutputSectionBase *B) {
- return B->getKind() == Base;
- }
unsigned SectionIndex;
+ unsigned SortRank;
uint32_t getPhdrFlags() const;
- void updateAlignment(uint64_t Alignment) {
- if (Alignment > Addralign)
- Addralign = Alignment;
+ void updateAlignment(uint32_t Val) {
+ if (Val > Alignment)
+ Alignment = Val;
}
- // If true, this section will be page aligned on disk.
- // Typically the first section of each PT_LOAD segment has this flag.
- bool PageAlign = false;
-
// Pointer to the first section in PT_LOAD segment, which this section
// also resides in. This field is used to correctly compute file offset
// of a section. When two sections share the same load segment, difference
// between their file offsets should be equal to difference between their
// virtual addresses. To compute some section offset we use the following
// formula: Off = Off_first + VA - VA_first.
- OutputSectionBase *FirstInPtLoad = nullptr;
+ OutputSection *FirstInPtLoad = nullptr;
- virtual void finalize() {}
- virtual void assignOffsets() {}
- virtual void writeTo(uint8_t *Buf) {}
- virtual ~OutputSectionBase() = default;
-
- StringRef Name;
+ // Pointer to a relocation section for this section. Usually nullptr because
+ // we consume relocations, but if --emit-relocs is specified (which is rare),
+ // it may have a non-null value.
+ OutputSection *RelocationSection = nullptr;
// The following fields correspond to Elf_Shdr members.
uint64_t Size = 0;
- uint64_t Entsize = 0;
- uint64_t Addralign = 0;
uint64_t Offset = 0;
- uint64_t Flags = 0;
uint64_t LMAOffset = 0;
uint64_t Addr = 0;
uint32_t ShName = 0;
- uint32_t Type = 0;
- uint32_t Info = 0;
- uint32_t Link = 0;
-};
-template <class ELFT> class OutputSection final : public OutputSectionBase {
+ void addSection(InputSection *S);
+ std::vector<InputSection *> Sections;
-public:
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::Rel Elf_Rel;
- typedef typename ELFT::Rela Elf_Rela;
- typedef typename ELFT::uint uintX_t;
- OutputSection(StringRef Name, uint32_t Type, uintX_t Flags);
- void addSection(InputSectionData *C) override;
- void sort(std::function<int(InputSection<ELFT> *S)> Order);
- void sortInitFini();
- void sortCtorsDtors();
- void writeTo(uint8_t *Buf) override;
- void finalize() override;
- void assignOffsets() override;
- Kind getKind() const override { return Regular; }
- static bool classof(const OutputSectionBase *B) {
- return B->getKind() == Regular;
- }
- std::vector<InputSection<ELFT> *> Sections;
+ // Used for implementation of --compress-debug-sections option.
+ std::vector<uint8_t> ZDebugHeader;
+ llvm::SmallVector<char, 1> CompressedData;
// Location in the output buffer.
uint8_t *Loc = nullptr;
};
-template <class ELFT>
-class MergeOutputSection final : public OutputSectionBase {
- typedef typename ELFT::uint uintX_t;
-
-public:
- MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
- uintX_t Alignment);
- void addSection(InputSectionData *S) override;
- void writeTo(uint8_t *Buf) override;
- void finalize() override;
- bool shouldTailMerge() const;
- Kind getKind() const override { return Merge; }
- static bool classof(const OutputSectionBase *B) {
- return B->getKind() == Merge;
- }
-
-private:
- void finalizeTailMerge();
- void finalizeNoTailMerge();
-
- llvm::StringTableBuilder Builder;
- std::vector<MergeInputSection<ELFT> *> Sections;
-};
-
-struct CieRecord {
- EhSectionPiece *Piece = nullptr;
- std::vector<EhSectionPiece *> FdePieces;
-};
-
-// Output section for .eh_frame.
-template <class ELFT> class EhOutputSection final : public OutputSectionBase {
- typedef typename ELFT::uint uintX_t;
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Rel Elf_Rel;
- typedef typename ELFT::Rela Elf_Rela;
-
-public:
- EhOutputSection();
- void writeTo(uint8_t *Buf) override;
- void finalize() override;
- bool empty() const { return Sections.empty(); }
-
- void addSection(InputSectionData *S) override;
- Kind getKind() const override { return EHFrame; }
- static bool classof(const OutputSectionBase *B) {
- return B->getKind() == EHFrame;
- }
-
- size_t NumFdes = 0;
-
-private:
- template <class RelTy>
- void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
-
- template <class RelTy>
- CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
-
- template <class RelTy>
- bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
-
- uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
-
- std::vector<EhInputSection<ELFT> *> Sections;
- std::vector<CieRecord *> Cies;
-
- // CIE records are uniquified by their contents and personality functions.
- llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
-};
-
-// All output sections that are hadnled by the linker specially are
+// All output sections that are handled by the linker specially are
// globally accessible. Writer initializes them, so don't use them
// until Writer is initialized.
-template <class ELFT> struct Out {
- typedef typename ELFT::uint uintX_t;
- typedef typename ELFT::Phdr Elf_Phdr;
-
+struct Out {
static uint8_t First;
- static EhOutputSection<ELFT> *EhFrame;
- static OutputSection<ELFT> *Bss;
- static OutputSection<ELFT> *BssRelRo;
- static OutputSectionBase *Opd;
+ static OutputSection *Opd;
static uint8_t *OpdBuf;
static PhdrEntry *TlsPhdr;
- static OutputSectionBase *DebugInfo;
- static OutputSectionBase *ElfHeader;
- static OutputSectionBase *ProgramHeaders;
- static OutputSectionBase *PreinitArray;
- static OutputSectionBase *InitArray;
- static OutputSectionBase *FiniArray;
+ static OutputSection *DebugInfo;
+ static OutputSection *ElfHeader;
+ static OutputSection *ProgramHeaders;
+ static OutputSection *PreinitArray;
+ static OutputSection *InitArray;
+ static OutputSection *FiniArray;
};
struct SectionKey {
StringRef Name;
uint64_t Flags;
- uint64_t Alignment;
+ uint32_t Alignment;
+};
+} // namespace elf
+} // namespace lld
+namespace llvm {
+template <> struct DenseMapInfo<lld::elf::SectionKey> {
+ static lld::elf::SectionKey getEmptyKey();
+ static lld::elf::SectionKey getTombstoneKey();
+ static unsigned getHashValue(const lld::elf::SectionKey &Val);
+ static bool isEqual(const lld::elf::SectionKey &LHS,
+ const lld::elf::SectionKey &RHS);
};
+} // namespace llvm
+namespace lld {
+namespace elf {
// This class knows how to create an output section for a given
// input section. Output section type is determined by various
// factors, including input section's sh_flags, sh_type and
// linker scripts.
-template <class ELFT> class OutputSectionFactory {
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::uint uintX_t;
-
+class OutputSectionFactory {
public:
OutputSectionFactory();
~OutputSectionFactory();
- std::pair<OutputSectionBase *, bool> create(InputSectionBase<ELFT> *C,
- StringRef OutsecName);
- std::pair<OutputSectionBase *, bool> create(const SectionKey &Key,
- InputSectionBase<ELFT> *C);
+
+ void addInputSec(InputSectionBase *IS, StringRef OutsecName);
+ void addInputSec(InputSectionBase *IS, StringRef OutsecName,
+ OutputSection *&Sec);
private:
- llvm::SmallDenseMap<SectionKey, OutputSectionBase *> Map;
+ llvm::SmallDenseMap<SectionKey, OutputSection *> Map;
};
-template <class ELFT> uint64_t getHeaderSize() {
- if (Config->OFormatBinary)
- return 0;
- return Out<ELFT>::ElfHeader->Size + Out<ELFT>::ProgramHeaders->Size;
-}
+uint64_t getHeaderSize();
+void reportDiscarded(InputSectionBase *IS);
-template <class ELFT> uint8_t Out<ELFT>::First;
-template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
-template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
-template <class ELFT> OutputSection<ELFT> *Out<ELFT>::BssRelRo;
-template <class ELFT> OutputSectionBase *Out<ELFT>::Opd;
-template <class ELFT> uint8_t *Out<ELFT>::OpdBuf;
-template <class ELFT> PhdrEntry *Out<ELFT>::TlsPhdr;
-template <class ELFT> OutputSectionBase *Out<ELFT>::DebugInfo;
-template <class ELFT> OutputSectionBase *Out<ELFT>::ElfHeader;
-template <class ELFT> OutputSectionBase *Out<ELFT>::ProgramHeaders;
-template <class ELFT> OutputSectionBase *Out<ELFT>::PreinitArray;
-template <class ELFT> OutputSectionBase *Out<ELFT>::InitArray;
-template <class ELFT> OutputSectionBase *Out<ELFT>::FiniArray;
+extern std::vector<OutputSection *> OutputSections;
+extern std::vector<OutputSectionCommand *> OutputSectionCommands;
} // namespace elf
} // namespace lld
-
#endif
diff --git a/contrib/llvm/tools/lld/ELF/Relocations.cpp b/contrib/llvm/tools/lld/ELF/Relocations.cpp
index cecd11e..e5fcb2d 100644
--- a/contrib/llvm/tools/lld/ELF/Relocations.cpp
+++ b/contrib/llvm/tools/lld/ELF/Relocations.cpp
@@ -43,6 +43,8 @@
#include "Relocations.h"
#include "Config.h"
+#include "LinkerScript.h"
+#include "Memory.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
@@ -52,20 +54,30 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support::endian;
-namespace lld {
-namespace elf {
+using namespace lld;
+using namespace lld::elf;
-static bool refersToGotEntry(RelExpr Expr) {
- return isRelExprOneOf<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
- R_MIPS_GOT_OFF32, R_MIPS_TLSGD, R_MIPS_TLSLD,
- R_GOT_PAGE_PC, R_GOT_PC, R_GOT_FROM_END, R_TLSGD,
- R_TLSGD_PC, R_TLSDESC, R_TLSDESC_PAGE>(Expr);
+// Construct a message in the following format.
+//
+// >>> defined in /home/alice/src/foo.o
+// >>> referenced by bar.c:12 (/home/alice/src/bar.c:12)
+// >>> /home/alice/src/bar.o:(.text+0x1)
+template <class ELFT>
+static std::string getLocation(InputSectionBase &S, const SymbolBody &Sym,
+ uint64_t Off) {
+ std::string Msg =
+ "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by ";
+ std::string Src = S.getSrcMsg<ELFT>(Off);
+ if (!Src.empty())
+ Msg += Src + "\n>>> ";
+ return Msg + S.getObjMsg<ELFT>(Off);
}
static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
@@ -84,44 +96,92 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
return Body.isPreemptible();
}
-// This function is similar to the `handleTlsRelocation`. ARM and MIPS do not
-// support any relaxations for TLS relocations so by factoring out ARM and MIPS
+// This function is similar to the `handleTlsRelocation`. MIPS does not
+// support any relaxations for TLS relocations so by factoring out MIPS
// handling in to the separate function we can simplify the code and do not
-// pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements.
-template <class ELFT, class GOT>
-static unsigned handleNoRelaxTlsRelocation(
- GOT *Got, uint32_t Type, SymbolBody &Body, InputSectionBase<ELFT> &C,
- typename ELFT::uint Offset, typename ELFT::uint Addend, RelExpr Expr) {
- typedef typename ELFT::uint uintX_t;
- auto addModuleReloc = [](SymbolBody &Body, GOT *Got, uintX_t Off, bool LD) {
- // The Dynamic TLS Module Index Relocation can be statically resolved to 1
- // if we know that we are linking an executable. For ARM we resolve the
- // relocation when writing the Got. MIPS has a custom Got implementation
- // that writes the Module index in directly.
- if (!Body.isPreemptible() && !Config->Pic && Config->EMachine == EM_ARM)
- Got->Relocations.push_back(
- {R_ABS, Target->TlsModuleIndexRel, Off, 0, &Body});
- else {
- SymbolBody *Dest = LD ? nullptr : &Body;
+// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
+// Mips has a custom MipsGotSection that handles the writing of GOT entries
+// without dynamic relocations.
+template <class ELFT>
+static unsigned handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
+ InputSectionBase &C, uint64_t Offset,
+ int64_t Addend, RelExpr Expr) {
+ if (Expr == R_MIPS_TLSLD) {
+ if (InX::MipsGot->addTlsIndex() && Config->Pic)
+ In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot,
+ InX::MipsGot->getTlsIndexOff(), false,
+ nullptr, 0});
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+ return 1;
+ }
+
+ if (Expr == R_MIPS_TLSGD) {
+ if (InX::MipsGot->addDynTlsEntry(Body) && Body.isPreemptible()) {
+ uint64_t Off = InX::MipsGot->getGlobalDynOffset(Body);
In<ELFT>::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, Got, Off, false, Dest, 0});
+ {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Body, 0});
+ if (Body.isPreemptible())
+ In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot,
+ Off + Config->Wordsize, false, &Body, 0});
}
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+ return 1;
+ }
+ return 0;
+}
+
+// This function is similar to the `handleMipsTlsRelocation`. ARM also does not
+// support any relaxations for TLS relocations. ARM is logically similar to Mips
+// in how it handles TLS, but Mips uses its own custom GOT which handles some
+// of the cases that ARM uses GOT relocations for.
+//
+// We look for TLS global dynamic and local dynamic relocations, these may
+// require the generation of a pair of GOT entries that have associated
+// dynamic relocations. When the results of the dynamic relocations can be
+// resolved at static link time we do so. This is necessary for static linking
+// as there will be no dynamic loader to resolve them at load-time.
+//
+// The pair of GOT entries created are of the form
+// GOT[e0] Module Index (Used to find pointer to TLS block at run-time)
+// GOT[e1] Offset of symbol in TLS block
+template <class ELFT>
+static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body,
+ InputSectionBase &C, uint64_t Offset,
+ int64_t Addend, RelExpr Expr) {
+ // The Dynamic TLS Module Index Relocation for a symbol defined in an
+ // executable is always 1. If the target Symbol is not preemtible then
+ // we know the offset into the TLS block at static link time.
+ bool NeedDynId = Body.isPreemptible() || Config->Shared;
+ bool NeedDynOff = Body.isPreemptible();
+
+ auto AddTlsReloc = [&](uint64_t Off, uint32_t Type, SymbolBody *Dest,
+ bool Dyn) {
+ if (Dyn)
+ In<ELFT>::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0});
+ else
+ InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
};
- if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) {
- if (Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM))
- addModuleReloc(Body, Got, Got->getTlsIndexOff(), true);
+
+ // Local Dynamic is for access to module local TLS variables, while still
+ // being suitable for being dynamically loaded via dlopen.
+ // GOT[e0] is the module index, with a special value of 0 for the current
+ // module. GOT[e1] is unused. There only needs to be one module index entry.
+ if (Expr == R_TLSLD_PC && InX::Got->addTlsIndex()) {
+ AddTlsReloc(InX::Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
+ NeedDynId ? nullptr : &Body, NeedDynId);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
- if (Target->isTlsGlobalDynamicRel(Type)) {
- if (Got->addDynTlsEntry(Body) &&
- (Body.isPreemptible() || Config->EMachine == EM_ARM)) {
- uintX_t Off = Got->getGlobalDynOffset(Body);
- addModuleReloc(Body, Got, Off, false);
- if (Body.isPreemptible())
- In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Got,
- Off + (uintX_t)sizeof(uintX_t), false,
- &Body, 0});
+
+ // Global Dynamic is the most general purpose access model. When we know
+ // the module index and offset of symbol in TLS block we can fill these in
+ // using static GOT relocations.
+ if (Expr == R_TLSGD_PC) {
+ if (InX::Got->addDynTlsEntry(Body)) {
+ uint64_t Off = InX::Got->getGlobalDynOffset(Body);
+ AddTlsReloc(Off, Target->TlsModuleIndexRel, &Body, NeedDynId);
+ AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Body,
+ NeedDynOff);
}
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
@@ -131,76 +191,71 @@ static unsigned handleNoRelaxTlsRelocation(
// Returns the number of relocations processed.
template <class ELFT>
-static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
- InputSectionBase<ELFT> &C,
- typename ELFT::uint Offset,
- typename ELFT::uint Addend, RelExpr Expr) {
+static unsigned
+handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
+ typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) {
if (!(C.Flags & SHF_ALLOC))
return 0;
if (!Body.isTls())
return 0;
- typedef typename ELFT::uint uintX_t;
-
if (Config->EMachine == EM_ARM)
- return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::Got, Type, Body, C,
- Offset, Addend, Expr);
+ return handleARMTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
if (Config->EMachine == EM_MIPS)
- return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::MipsGot, Type, Body, C,
- Offset, Addend, Expr);
+ return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
bool IsPreemptible = isPreemptible(Body, Type);
- if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC_CALL) &&
+ if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
Config->Shared) {
- if (In<ELFT>::Got->addDynTlsEntry(Body)) {
- uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
- In<ELFT>::RelaDyn->addReloc({Target->TlsDescRel, In<ELFT>::Got, Off,
- !IsPreemptible, &Body, 0});
+ if (InX::Got->addDynTlsEntry(Body)) {
+ uint64_t Off = InX::Got->getGlobalDynOffset(Body);
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->TlsDescRel, InX::Got, Off, !IsPreemptible, &Body, 0});
}
if (Expr != R_TLSDESC_CALL)
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
- if (Expr == R_TLSLD_PC || Expr == R_TLSLD) {
+ if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) {
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
C.Relocations.push_back(
{R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
return 2;
}
- if (In<ELFT>::Got->addTlsIndex())
- In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::Got,
- In<ELFT>::Got->getTlsIndexOff(), false,
- nullptr, 0});
+ if (InX::Got->addTlsIndex())
+ In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got,
+ InX::Got->getTlsIndexOff(), false, nullptr,
+ 0});
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
// Local-Dynamic relocs can be relaxed to Local-Exec.
- if (Target->isTlsLocalDynamicRel(Type) && !Config->Shared) {
+ if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) {
C.Relocations.push_back(
{R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
return 1;
}
- if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_TLSDESC_CALL ||
- Target->isTlsGlobalDynamicRel(Type)) {
+ if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD,
+ R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
- if (In<ELFT>::Got->addDynTlsEntry(Body)) {
- uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
+ if (InX::Got->addDynTlsEntry(Body)) {
+ uint64_t Off = InX::Got->getGlobalDynOffset(Body);
In<ELFT>::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, In<ELFT>::Got, Off, false, &Body, 0});
+ {Target->TlsModuleIndexRel, InX::Got, Off, false, &Body, 0});
// If the symbol is preemptible we need the dynamic linker to write
// the offset too.
- uintX_t OffsetOff = Off + (uintX_t)sizeof(uintX_t);
+ uint64_t OffsetOff = Off + Config->Wordsize;
if (IsPreemptible)
- In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::Got,
- OffsetOff, false, &Body, 0});
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Body, 0});
else
- In<ELFT>::Got->Relocations.push_back(
+ InX::Got->Relocations.push_back(
{R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Body});
}
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
@@ -214,36 +269,34 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
Offset, Addend, &Body});
if (!Body.isInGot()) {
- In<ELFT>::Got->addEntry(Body);
- In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, In<ELFT>::Got,
- Body.getGotOffset<ELFT>(), false, &Body,
- 0});
+ InX::Got->addEntry(Body);
+ In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, InX::Got,
+ Body.getGotOffset(), false, &Body, 0});
}
- return Target->TlsGdRelaxSkip;
+ } else {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type,
+ Offset, Addend, &Body});
}
- C.Relocations.push_back(
- {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type,
- Offset, Addend, &Body});
return Target->TlsGdRelaxSkip;
}
// Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
// defined.
- if (Target->isTlsInitialExecRel(Type) && !Config->Shared && !IsPreemptible) {
+ if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_GOT_PAGE_PC>(Expr) &&
+ !Config->Shared && !IsPreemptible) {
C.Relocations.push_back(
{R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
return 1;
}
- return 0;
-}
-template <endianness E> static int16_t readSignedLo16(const uint8_t *Loc) {
- return read32<E>(Loc) & 0xffff;
+ if (Expr == R_TLSDESC_CALL)
+ return 1;
+ return 0;
}
-template <class RelTy>
-static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
- switch (Rel->getType(Config->Mips64EL)) {
+static uint32_t getMipsPairType(uint32_t Type, const SymbolBody &Sym) {
+ switch (Type) {
case R_MIPS_HI16:
return R_MIPS_LO16;
case R_MIPS_GOT16:
@@ -257,72 +310,60 @@ static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
}
}
-template <class ELFT, class RelTy>
-static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc,
- SymbolBody &Sym, const RelTy *Rel,
- const RelTy *End) {
- uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL);
- uint32_t Type = getMipsPairType(Rel, Sym);
-
- // Some MIPS relocations use addend calculated from addend of the relocation
- // itself and addend of paired relocation. ABI requires to compute such
- // combined addend in case of REL relocation record format only.
- // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (RelTy::IsRela || Type == R_MIPS_NONE)
- return 0;
-
- for (const RelTy *RI = Rel; RI != End; ++RI) {
- if (RI->getType(Config->Mips64EL) != Type)
- continue;
- if (RI->getSymbol(Config->Mips64EL) != SymIndex)
- continue;
- const endianness E = ELFT::TargetEndianness;
- return ((read32<E>(BufLoc) & 0xffff) << 16) +
- readSignedLo16<E>(Buf + RI->r_offset);
- }
- warn("can't find matching " + toString(Type) + " relocation for " +
- toString(Rel->getType(Config->Mips64EL)));
- return 0;
-}
-
// True if non-preemptable symbol always has the same value regardless of where
// the DSO is loaded.
-template <class ELFT> static bool isAbsolute(const SymbolBody &Body) {
+static bool isAbsolute(const SymbolBody &Body) {
if (Body.isUndefined())
return !Body.isLocal() && Body.symbol()->isWeak();
- if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(&Body))
+ if (const auto *DR = dyn_cast<DefinedRegular>(&Body))
return DR->Section == nullptr; // Absolute symbol.
return false;
}
-template <class ELFT> static bool isAbsoluteValue(const SymbolBody &Body) {
- return isAbsolute<ELFT>(Body) || Body.isTls();
+static bool isAbsoluteValue(const SymbolBody &Body) {
+ return isAbsolute(Body) || Body.isTls();
}
+// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC,
- R_THUNK_PLT_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr);
+}
+
+// Returns true if Expr refers a GOT entry. Note that this function
+// returns false for TLS variables even though they need GOT, because
+// TLS variables uses GOT differently than the regular variables.
+static bool needsGot(RelExpr Expr) {
+ return isRelExprOneOf<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
+ R_MIPS_GOT_OFF32, R_GOT_PAGE_PC, R_GOT_PC,
+ R_GOT_FROM_END>(Expr);
}
// True if this expression is of the form Sym - X, where X is a position in the
// file (PC, or GOT for example).
static bool isRelExpr(RelExpr Expr) {
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
- R_PAGE_PC, R_RELAX_GOT_PC, R_THUNK_PC, R_THUNK_PLT_PC>(
- Expr);
+ R_PAGE_PC, R_RELAX_GOT_PC>(Expr);
}
+// Returns true if a given relocation can be computed at link-time.
+//
+// For instance, we know the offset from a relocation to its target at
+// link-time if the relocation is PC-relative and refers a
+// non-interposable function in the same executable. This function
+// will return true for such relocation.
+//
+// If this function returns false, that means we need to emit a
+// dynamic relocation so that the relocation will be fixed at load-time.
template <class ELFT>
static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
const SymbolBody &Body,
- InputSectionBase<ELFT> &S,
- typename ELFT::uint RelOff) {
+ InputSectionBase &S, uint64_t RelOff) {
// These expressions always compute a constant
if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
- R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_TLSGD,
- R_GOT_PAGE_PC, R_GOT_PC, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
- R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
- R_THUNK_PC, R_THUNK_PLT_PC>(E))
+ R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
+ R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
+ R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
+ R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
return true;
// These never do, except if the entire file is position dependent or if
@@ -332,16 +373,19 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
if (isPreemptible(Body, Type))
return false;
-
if (!Config->Pic)
return true;
- bool AbsVal = isAbsoluteValue<ELFT>(Body);
+ // For the target and the relocation, we want to know if they are
+ // absolute or relative.
+ bool AbsVal = isAbsoluteValue(Body);
bool RelE = isRelExpr(E);
if (AbsVal && !RelE)
return true;
if (!AbsVal && RelE)
return true;
+ if (!AbsVal && !RelE)
+ return Target->usesOnlyLowPageBits(Type);
// Relative relocation to an absolute value. This is normally unrepresentable,
// but if the relocation refers to a weak undefined symbol, we allow it to
@@ -351,18 +395,13 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
// Another special case is MIPS _gp_disp symbol which represents offset
// between start of a function and '_gp' value and defined as absolute just
// to simplify the code.
- if (AbsVal && RelE) {
- if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
- return true;
- if (&Body == ElfSym<ELFT>::MipsGpDisp)
- return true;
- error(S.getLocation(RelOff) + ": relocation " + toString(Type) +
- " cannot refer to absolute symbol '" + toString(Body) +
- "' defined in " + toString(Body.File));
+ assert(AbsVal && RelE);
+ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
return true;
- }
- return Target->usesOnlyLowPageBits(Type);
+ error("relocation " + toString(Type) + " cannot refer to absolute symbol: " +
+ toString(Body) + getLocation<ELFT>(S, Body, RelOff));
+ return true;
}
static RelExpr toPlt(RelExpr Expr) {
@@ -389,23 +428,14 @@ static RelExpr fromPlt(RelExpr Expr) {
return Expr;
}
-template <class ELFT> static uint32_t getAlignment(SharedSymbol<ELFT> *SS) {
- typedef typename ELFT::uint uintX_t;
-
- uintX_t SecAlign = SS->file()->getSection(SS->Sym)->sh_addralign;
- uintX_t SymValue = SS->Sym.st_value;
- int TrailingZeros =
- std::min(countTrailingZeros(SecAlign), countTrailingZeros(SymValue));
- return 1 << TrailingZeros;
-}
-
-template <class ELFT> static bool isReadOnly(SharedSymbol<ELFT> *SS) {
- typedef typename ELFT::uint uintX_t;
+// Returns true if a given shared symbol is in a read-only segment in a DSO.
+template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {
typedef typename ELFT::Phdr Elf_Phdr;
+ uint64_t Value = SS->getValue<ELFT>();
// Determine if the symbol is read-only by scanning the DSO's program headers.
- uintX_t Value = SS->Sym.st_value;
- for (const Elf_Phdr &Phdr : check(SS->file()->getObj().program_headers()))
+ auto *File = cast<SharedFile<ELFT>>(SS->File);
+ for (const Elf_Phdr &Phdr : check(File->getObj().program_headers()))
if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
!(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr &&
Value < Phdr.p_vaddr + Phdr.p_memsz)
@@ -413,62 +443,112 @@ template <class ELFT> static bool isReadOnly(SharedSymbol<ELFT> *SS) {
return false;
}
-// Reserve space in .bss or .bss.rel.ro for copy relocation.
-template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) {
- typedef typename ELFT::uint uintX_t;
+// Returns symbols at the same offset as a given symbol, including SS itself.
+//
+// If two or more symbols are at the same offset, and at least one of
+// them are copied by a copy relocation, all of them need to be copied.
+// Otherwise, they would refer different places at runtime.
+template <class ELFT>
+static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {
typedef typename ELFT::Sym Elf_Sym;
+ auto *File = cast<SharedFile<ELFT>>(SS->File);
+ uint64_t Shndx = SS->getShndx<ELFT>();
+ uint64_t Value = SS->getValue<ELFT>();
+
+ std::vector<SharedSymbol *> Ret;
+ for (const Elf_Sym &S : File->getGlobalSymbols()) {
+ if (S.st_shndx != Shndx || S.st_value != Value)
+ continue;
+ StringRef Name = check(S.getName(File->getStringTable()));
+ SymbolBody *Sym = Symtab<ELFT>::X->find(Name);
+ if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym))
+ Ret.push_back(Alias);
+ }
+ return Ret;
+}
+
+// Reserve space in .bss or .bss.rel.ro for copy relocation.
+//
+// The copy relocation is pretty much a hack. If you use a copy relocation
+// in your program, not only the symbol name but the symbol's size, RW/RO
+// bit and alignment become part of the ABI. In addition to that, if the
+// symbol has aliases, the aliases become part of the ABI. That's subtle,
+// but if you violate that implicit ABI, that can cause very counter-
+// intuitive consequences.
+//
+// So, what is the copy relocation? It's for linking non-position
+// independent code to DSOs. In an ideal world, all references to data
+// exported by DSOs should go indirectly through GOT. But if object files
+// are compiled as non-PIC, all data references are direct. There is no
+// way for the linker to transform the code to use GOT, as machine
+// instructions are already set in stone in object files. This is where
+// the copy relocation takes a role.
+//
+// A copy relocation instructs the dynamic linker to copy data from a DSO
+// to a specified address (which is usually in .bss) at load-time. If the
+// static linker (that's us) finds a direct data reference to a DSO
+// symbol, it creates a copy relocation, so that the symbol can be
+// resolved as if it were in .bss rather than in a DSO.
+//
+// As you can see in this function, we create a copy relocation for the
+// dynamic linker, and the relocation contains not only symbol name but
+// various other informtion about the symbol. So, such attributes become a
+// part of the ABI.
+//
+// Note for application developers: I can give you a piece of advice if
+// you are writing a shared library. You probably should export only
+// functions from your library. You shouldn't export variables.
+//
+// As an example what can happen when you export variables without knowing
+// the semantics of copy relocations, assume that you have an exported
+// variable of type T. It is an ABI-breaking change to add new members at
+// end of T even though doing that doesn't change the layout of the
+// existing members. That's because the space for the new members are not
+// reserved in .bss unless you recompile the main program. That means they
+// are likely to overlap with other data that happens to be laid out next
+// to the variable in .bss. This kind of issue is sometimes very hard to
+// debug. What's a solution? Instead of exporting a varaible V from a DSO,
+// define an accessor getV().
+template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {
// Copy relocation against zero-sized symbol doesn't make sense.
- uintX_t SymSize = SS->template getSize<ELFT>();
+ uint64_t SymSize = SS->template getSize<ELFT>();
if (SymSize == 0)
fatal("cannot create a copy relocation for symbol " + toString(*SS));
// See if this symbol is in a read-only segment. If so, preserve the symbol's
// memory protection by reserving space in the .bss.rel.ro section.
- bool IsReadOnly = isReadOnly(SS);
- OutputSection<ELFT> *CopySec =
- IsReadOnly ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss;
-
- uintX_t Alignment = getAlignment(SS);
- uintX_t Off = alignTo(CopySec->Size, Alignment);
- CopySec->Size = Off + SymSize;
- CopySec->updateAlignment(Alignment);
- uintX_t Shndx = SS->Sym.st_shndx;
- uintX_t Value = SS->Sym.st_value;
+ bool IsReadOnly = isReadOnly<ELFT>(SS);
+ BssSection *Sec = IsReadOnly ? InX::BssRelRo : InX::Bss;
+ uint64_t Off = Sec->reserveSpace(SymSize, SS->getAlignment<ELFT>());
+
// Look through the DSO's dynamic symbol table for aliases and create a
// dynamic symbol for each one. This causes the copy relocation to correctly
// interpose any aliases.
- for (const Elf_Sym &S : SS->file()->getGlobalSymbols()) {
- if (S.st_shndx != Shndx || S.st_value != Value)
- continue;
- auto *Alias = dyn_cast_or_null<SharedSymbol<ELFT>>(
- Symtab<ELFT>::X->find(check(S.getName(SS->file()->getStringTable()))));
- if (!Alias)
- continue;
- Alias->CopyIsInBssRelRo = IsReadOnly;
- Alias->CopyOffset = Off;
- Alias->NeedsCopyOrPltAddr = true;
- Alias->symbol()->IsUsedInRegularObj = true;
+ for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) {
+ Sym->NeedsCopy = true;
+ Sym->CopyRelSec = Sec;
+ Sym->CopyRelSecOff = Off;
+ Sym->symbol()->IsUsedInRegularObj = true;
}
- In<ELFT>::RelaDyn->addReloc({Target->CopyRel, CopySec, Off, false, SS, 0});
+
+ In<ELFT>::RelaDyn->addReloc({Target->CopyRel, Sec, Off, false, SS, 0});
}
template <class ELFT>
-static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
- bool IsWrite, RelExpr Expr, uint32_t Type,
- const uint8_t *Data, InputSectionBase<ELFT> &S,
+static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type,
+ const uint8_t *Data, InputSectionBase &S,
typename ELFT::uint RelOff) {
- bool Preemptible = isPreemptible(Body, Type);
if (Body.isGnuIFunc()) {
Expr = toPlt(Expr);
- } else if (!Preemptible) {
+ } else if (!isPreemptible(Body, Type)) {
if (needsPlt(Expr))
Expr = fromPlt(Expr);
- if (Expr == R_GOT_PC && !isAbsoluteValue<ELFT>(Body))
+ if (Expr == R_GOT_PC && !isAbsoluteValue(Body))
Expr = Target->adjustRelaxExpr(Type, Data, Expr);
}
- Expr = Target->getThunkExpr(Expr, Type, File, Body);
+ bool IsWrite = !Config->ZText || (S.Flags & SHF_WRITE);
if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff))
return Expr;
@@ -476,25 +556,34 @@ static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
// only memory. We can hack around it if we are producing an executable and
// the refered symbol can be preemepted to refer to the executable.
if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) {
- error(S.getLocation(RelOff) + ": can't create dynamic relocation " +
- toString(Type) + " against " +
- (Body.getName().empty() ? "local symbol in readonly segment"
- : "symbol '" + toString(Body) + "'") +
- " defined in " + toString(Body.File));
+ error("can't create dynamic relocation " + toString(Type) + " against " +
+ (Body.getName().empty() ? "local symbol"
+ : "symbol: " + toString(Body)) +
+ " in readonly segment" + getLocation<ELFT>(S, Body, RelOff));
return Expr;
}
+
if (Body.getVisibility() != STV_DEFAULT) {
- error(S.getLocation(RelOff) + ": cannot preempt symbol '" + toString(Body) +
- "' defined in " + toString(Body.File));
+ error("cannot preempt symbol: " + toString(Body) +
+ getLocation<ELFT>(S, Body, RelOff));
return Expr;
}
+
if (Body.isObject()) {
// Produce a copy relocation.
- auto *B = cast<SharedSymbol<ELFT>>(&Body);
- if (!B->needsCopy())
- addCopyRelSymbol(B);
+ auto *B = cast<SharedSymbol>(&Body);
+ if (!B->NeedsCopy) {
+ if (Config->ZNocopyreloc)
+ error("unresolvable relocation " + toString(Type) +
+ " against symbol '" + toString(*B) +
+ "'; recompile with -fPIC or remove '-z nocopyreloc'" +
+ getLocation<ELFT>(S, Body, RelOff));
+
+ addCopyRelSymbol<ELFT>(B);
+ }
return Expr;
}
+
if (Body.isFunc()) {
// This handles a non PIC program call to function in a shared library. In
// an ideal world, we could just report an error saying the relocation can
@@ -516,61 +605,98 @@ static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
// that points to the real function is a dedicated got entry used by the
// plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
// R_386_JMP_SLOT, etc).
- Body.NeedsCopyOrPltAddr = true;
+ Body.NeedsPltAddr = true;
return toPlt(Expr);
}
- error("symbol '" + toString(Body) + "' defined in " + toString(Body.File) +
- " is missing type");
+ error("symbol '" + toString(Body) + "' defined in " + toString(Body.File) +
+ " has no type");
return Expr;
}
+// Returns an addend of a given relocation. If it is RELA, an addend
+// is in a relocation itself. If it is REL, we need to read it from an
+// input section.
+template <class ELFT, class RelTy>
+static int64_t computeAddend(const RelTy &Rel, const uint8_t *Buf) {
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
+ int64_t A = RelTy::IsRela
+ ? getAddend<ELFT>(Rel)
+ : Target->getImplicitAddend(Buf + Rel.r_offset, Type);
+
+ if (Config->EMachine == EM_PPC64 && Config->Pic && Type == R_PPC64_TOC)
+ A += getPPC64TocBase();
+ return A;
+}
+
+// MIPS has an odd notion of "paired" relocations to calculate addends.
+// For example, if a relocation is of R_MIPS_HI16, there must be a
+// R_MIPS_LO16 relocation after that, and an addend is calculated using
+// the two relocations.
template <class ELFT, class RelTy>
-static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File,
- const uint8_t *SectionData,
- const RelTy *End, const RelTy &RI,
- RelExpr Expr, SymbolBody &Body) {
- typedef typename ELFT::uint uintX_t;
-
- uint32_t Type = RI.getType(Config->Mips64EL);
- uintX_t Addend = getAddend<ELFT>(RI);
- const uint8_t *BufLoc = SectionData + RI.r_offset;
- if (!RelTy::IsRela)
- Addend += Target->getImplicitAddend(BufLoc, Type);
- if (Config->EMachine == EM_MIPS) {
- Addend += findMipsPairedAddend<ELFT>(SectionData, BufLoc, Body, &RI, End);
- if (Type == R_MIPS_LO16 && Expr == R_PC)
- // R_MIPS_LO16 expression has R_PC type iif the target is _gp_disp
- // symbol. In that case we should use the following formula for
- // calculation "AHL + GP - P + 4". Let's add 4 right here.
- // For details see p. 4-19 at
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- Addend += 4;
- if (Expr == R_MIPS_GOTREL && Body.isLocal())
- Addend += File.MipsGp0;
+static int64_t computeMipsAddend(const RelTy &Rel, InputSectionBase &Sec,
+ RelExpr Expr, SymbolBody &Body,
+ const RelTy *End) {
+ if (Expr == R_MIPS_GOTREL && Body.isLocal())
+ return Sec.getFile<ELFT>()->MipsGp0;
+
+ // The ABI says that the paired relocation is used only for REL.
+ // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ if (RelTy::IsRela)
+ return 0;
+
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
+ uint32_t PairTy = getMipsPairType(Type, Body);
+ if (PairTy == R_MIPS_NONE)
+ return 0;
+
+ const uint8_t *Buf = Sec.Data.data();
+ uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
+
+ // To make things worse, paired relocations might not be contiguous in
+ // the relocation table, so we need to do linear search. *sigh*
+ for (const RelTy *RI = &Rel; RI != End; ++RI) {
+ if (RI->getType(Config->IsMips64EL) != PairTy)
+ continue;
+ if (RI->getSymbol(Config->IsMips64EL) != SymIndex)
+ continue;
+
+ endianness E = Config->Endianness;
+ int32_t Hi = (read32(Buf + Rel.r_offset, E) & 0xffff) << 16;
+ int32_t Lo = SignExtend32<16>(read32(Buf + RI->r_offset, E));
+ return Hi + Lo;
}
- if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC)
- Addend += getPPC64TocBase();
- return Addend;
+
+ warn("can't find matching " + toString(PairTy) + " relocation for " +
+ toString(Type));
+ return 0;
}
template <class ELFT>
-static void reportUndefined(SymbolBody &Sym, InputSectionBase<ELFT> &S,
- typename ELFT::uint Offset) {
- if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
+static void reportUndefined(SymbolBody &Sym, InputSectionBase &S,
+ uint64_t Offset) {
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll)
return;
- if (Config->Shared && Sym.symbol()->Visibility == STV_DEFAULT &&
- Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef)
+ bool CanBeExternal = Sym.symbol()->computeBinding() != STB_LOCAL &&
+ Sym.getVisibility() == STV_DEFAULT;
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
return;
std::string Msg =
- S.getLocation(Offset) + ": undefined symbol '" + toString(Sym) + "'";
+ "undefined symbol: " + toString(Sym) + "\n>>> referenced by ";
+
+ std::string Src = S.getSrcMsg<ELFT>(Offset);
+ if (!Src.empty())
+ Msg += Src + "\n>>> ";
+ Msg += S.getObjMsg<ELFT>(Offset);
- if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn)
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::WarnAll ||
+ (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal)) {
warn(Msg);
- else
+ } else {
error(Msg);
+ }
}
template <class RelTy>
@@ -584,11 +710,95 @@ mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) {
uint32_t Processed = 0;
for (; I != E && Offset == I->r_offset; ++I) {
++Processed;
- Type |= I->getType(Config->Mips64EL) << (8 * Processed);
+ Type |= I->getType(Config->IsMips64EL) << (8 * Processed);
}
return std::make_pair(Type, Processed);
}
+// .eh_frame sections are mergeable input sections, so their input
+// offsets are not linearly mapped to output section. For each input
+// offset, we need to find a section piece containing the offset and
+// add the piece's base address to the input offset to compute the
+// output offset. That isn't cheap.
+//
+// This class is to speed up the offset computation. When we process
+// relocations, we access offsets in the monotonically increasing
+// order. So we can optimize for that access pattern.
+//
+// For sections other than .eh_frame, this class doesn't do anything.
+namespace {
+class OffsetGetter {
+public:
+ explicit OffsetGetter(InputSectionBase &Sec) {
+ if (auto *Eh = dyn_cast<EhInputSection>(&Sec)) {
+ P = Eh->Pieces;
+ Size = Eh->Pieces.size();
+ }
+ }
+
+ // Translates offsets in input sections to offsets in output sections.
+ // Given offset must increase monotonically. We assume that P is
+ // sorted by InputOff.
+ uint64_t get(uint64_t Off) {
+ if (P.empty())
+ return Off;
+
+ while (I != Size && P[I].InputOff + P[I].size() <= Off)
+ ++I;
+ if (I == Size)
+ return Off;
+
+ // P must be contiguous, so there must be no holes in between.
+ assert(P[I].InputOff <= Off && "Relocation not in any piece");
+
+ // Offset -1 means that the piece is dead (i.e. garbage collected).
+ if (P[I].OutputOff == -1)
+ return -1;
+ return P[I].OutputOff + Off - P[I].InputOff;
+ }
+
+private:
+ ArrayRef<EhSectionPiece> P;
+ size_t I = 0;
+ size_t Size;
+};
+} // namespace
+
+template <class ELFT, class GotPltSection>
+static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
+ RelocationSection<ELFT> *Rel, uint32_t Type,
+ SymbolBody &Sym, bool UseSymVA) {
+ Plt->addEntry<ELFT>(Sym);
+ GotPlt->addEntry(Sym);
+ Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0});
+}
+
+template <class ELFT>
+static void addGotEntry(SymbolBody &Sym, bool Preemptible) {
+ InX::Got->addEntry(Sym);
+
+ uint64_t Off = Sym.getGotOffset();
+ uint32_t DynType;
+ RelExpr Expr = R_ABS;
+
+ if (Sym.isTls()) {
+ DynType = Target->TlsGotRel;
+ Expr = R_TLS;
+ } else if (!Preemptible && Config->Pic && !isAbsolute(Sym)) {
+ DynType = Target->RelativeRel;
+ } else {
+ DynType = Target->GotRel;
+ }
+
+ bool Constant = !Preemptible && !(Config->Pic && !isAbsolute(Sym));
+ if (!Constant)
+ In<ELFT>::RelaDyn->addReloc(
+ {DynType, InX::Got, Off, !Preemptible, &Sym, 0});
+
+ if (Constant || (!Config->IsRela && !Preemptible))
+ InX::Got->Relocations.push_back({Expr, DynType, Off, 0, &Sym});
+}
+
// The reason we have to do this early scan is as follows
// * To mmap the output file, we need to know the size
// * For that, we need to know how many dynamic relocs we will have.
@@ -603,114 +813,104 @@ mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) {
// complicates things for the dynamic linker and means we would have to reserve
// space for the extra PT_LOAD even if we end up not using it.
template <class ELFT, class RelTy>
-static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
- typedef typename ELFT::uint uintX_t;
-
- bool IsWrite = C.Flags & SHF_WRITE;
-
- auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) {
- In<ELFT>::RelaDyn->addReloc(Reloc);
- };
-
- const elf::ObjectFile<ELFT> *File = C.getFile();
- ArrayRef<uint8_t> SectionData = C.Data;
- const uint8_t *Buf = SectionData.begin();
-
- ArrayRef<EhSectionPiece> Pieces;
- if (auto *Eh = dyn_cast<EhInputSection<ELFT>>(&C))
- Pieces = Eh->Pieces;
+static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
+ OffsetGetter GetOffset(Sec);
- ArrayRef<EhSectionPiece>::iterator PieceI = Pieces.begin();
- ArrayRef<EhSectionPiece>::iterator PieceE = Pieces.end();
-
- for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
- const RelTy &RI = *I;
- SymbolBody &Body = File->getRelocTargetSym(RI);
- uint32_t Type = RI.getType(Config->Mips64EL);
+ for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) {
+ const RelTy &Rel = *I;
+ SymbolBody &Body = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
if (Config->MipsN32Abi) {
uint32_t Processed;
std::tie(Type, Processed) =
- mergeMipsN32RelTypes(Type, RI.r_offset, I + 1, E);
+ mergeMipsN32RelTypes(Type, Rel.r_offset, I + 1, End);
I += Processed;
}
- // We only report undefined symbols if they are referenced somewhere in the
- // code.
+ // Compute the offset of this section in the output section.
+ uint64_t Offset = GetOffset.get(Rel.r_offset);
+ if (Offset == uint64_t(-1))
+ continue;
+
+ // Report undefined symbols. The fact that we report undefined
+ // symbols here means that we report undefined symbols only when
+ // they have relocations pointing to them. We don't care about
+ // undefined symbols that are in dead-stripped sections.
if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak())
- reportUndefined(Body, C, RI.r_offset);
+ reportUndefined<ELFT>(Body, Sec, Rel.r_offset);
+
+ RelExpr Expr =
+ Target->getRelExpr(Type, Body, Sec.Data.begin() + Rel.r_offset);
+
+ // Ignore "hint" relocations because they are only markers for relaxation.
+ if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
+ continue;
- RelExpr Expr = Target->getRelExpr(Type, Body);
bool Preemptible = isPreemptible(Body, Type);
- Expr = adjustExpr(*File, Body, IsWrite, Expr, Type, Buf + RI.r_offset, C,
- RI.r_offset);
+ Expr = adjustExpr<ELFT>(Body, Expr, Type, Sec.Data.data() + Rel.r_offset,
+ Sec, Rel.r_offset);
if (ErrorCount)
continue;
- // Skip a relocation that points to a dead piece
- // in a eh_frame section.
- while (PieceI != PieceE &&
- (PieceI->InputOff + PieceI->size() <= RI.r_offset))
- ++PieceI;
-
- // Compute the offset of this section in the output section. We do it here
- // to try to compute it only once.
- uintX_t Offset;
- if (PieceI != PieceE) {
- assert(PieceI->InputOff <= RI.r_offset && "Relocation not in any piece");
- if (PieceI->OutputOff == -1)
- continue;
- Offset = PieceI->OutputOff + RI.r_offset - PieceI->InputOff;
- } else {
- Offset = RI.r_offset;
- }
-
// This relocation does not require got entry, but it is relative to got and
// needs it to be created. Here we request for that.
- if (Expr == R_GOTONLY_PC || Expr == R_GOTONLY_PC_FROM_END ||
- Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || Expr == R_PPC_TOC)
- In<ELFT>::Got->HasGotOffRel = true;
+ if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
+ R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
+ InX::Got->HasGotOffRel = true;
- uintX_t Addend = computeAddend(*File, Buf, E, RI, Expr, Body);
+ // Read an addend.
+ int64_t Addend = computeAddend<ELFT>(Rel, Sec.Data.data());
+ if (Config->EMachine == EM_MIPS)
+ Addend += computeMipsAddend<ELFT>(Rel, Sec, Expr, Body, End);
+ // Process some TLS relocations, including relaxing TLS relocations.
+ // Note that this function does not handle all TLS relocations.
if (unsigned Processed =
- handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
+ handleTlsRelocation<ELFT>(Type, Body, Sec, Offset, Addend, Expr)) {
I += (Processed - 1);
continue;
}
- // Ignore "hint" and TLS Descriptor call relocation because they are
- // only markers for relaxation.
- if (isRelExprOneOf<R_HINT, R_TLSDESC_CALL>(Expr))
- continue;
+ // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
+ if (needsPlt(Expr) && !Body.isInPlt()) {
+ if (Body.isGnuIFunc() && !Preemptible)
+ addPltEntry(InX::Iplt, InX::IgotPlt, In<ELFT>::RelaIplt,
+ Target->IRelativeRel, Body, true);
+ else
+ addPltEntry(InX::Plt, InX::GotPlt, In<ELFT>::RelaPlt, Target->PltRel,
+ Body, !Preemptible);
+ }
- if (needsPlt(Expr) ||
- isRelExprOneOf<R_THUNK_ABS, R_THUNK_PC, R_THUNK_PLT_PC>(Expr) ||
- refersToGotEntry(Expr) || !isPreemptible(Body, Type)) {
- // If the relocation points to something in the file, we can process it.
- bool Constant =
- isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, C, RI.r_offset);
-
- // If the output being produced is position independent, the final value
- // is still not known. In that case we still need some help from the
- // dynamic linker. We can however do better than just copying the incoming
- // relocation. We can process some of it and and just ask the dynamic
- // linker to add the load address.
- if (!Constant)
- AddDyn({Target->RelativeRel, &C, Offset, true, &Body, Addend});
-
- // If the produced value is a constant, we just remember to write it
- // when outputting this section. We also have to do it if the format
- // uses Elf_Rel, since in that case the written value is the addend.
- if (Constant || !RelTy::IsRela)
- C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
- } else {
+ // Create a GOT slot if a relocation needs GOT.
+ if (needsGot(Expr)) {
+ if (Config->EMachine == EM_MIPS) {
+ // MIPS ABI has special rules to process GOT entries and doesn't
+ // require relocation entries for them. A special case is TLS
+ // relocations. In that case dynamic loader applies dynamic
+ // relocations to initialize TLS GOT entries.
+ // See "Global Offset Table" in Chapter 5 in the following document
+ // for detailed description:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ InX::MipsGot->addEntry(Body, Addend, Expr);
+ if (Body.isTls() && Body.isPreemptible())
+ In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot,
+ Body.getGotOffset(), false, &Body, 0});
+ } else if (!Body.isInGot()) {
+ addGotEntry<ELFT>(Body, Preemptible);
+ }
+ }
+
+ if (!needsPlt(Expr) && !needsGot(Expr) && isPreemptible(Body, Type)) {
// We don't know anything about the finaly symbol. Just ask the dynamic
// linker to handle the relocation for us.
if (!Target->isPicRel(Type))
- error(C.getLocation(Offset) + ": relocation " + toString(Type) +
- " cannot be used against shared object; recompile with -fPIC.");
- AddDyn({Target->getDynRel(Type), &C, Offset, false, &Body, Addend});
+ error("relocation " + toString(Type) +
+ " cannot be used against shared object; recompile with -fPIC" +
+ getLocation<ELFT>(Sec, Body, Offset));
+
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->getDynRel(Type), &Sec, Offset, false, &Body, Addend});
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
@@ -728,118 +928,217 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
// a dynamic relocation.
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
if (Config->EMachine == EM_MIPS)
- In<ELFT>::MipsGot->addEntry(Body, Addend, Expr);
+ InX::MipsGot->addEntry(Body, Addend, Expr);
continue;
}
- // At this point we are done with the relocated position. Some relocations
- // also require us to create a got or plt entry.
+ // If the relocation points to something in the file, we can process it.
+ bool IsConstant =
+ isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, Sec, Rel.r_offset);
- // If a relocation needs PLT, we create a PLT and a GOT slot for the symbol.
- if (needsPlt(Expr)) {
- if (Body.isInPlt())
- continue;
+ // The size is not going to change, so we fold it in here.
+ if (Expr == R_SIZE)
+ Addend += Body.getSize<ELFT>();
- if (Body.isGnuIFunc() && !Preemptible) {
- In<ELFT>::Iplt->addEntry(Body);
- In<ELFT>::IgotPlt->addEntry(Body);
- In<ELFT>::RelaIplt->addReloc({Target->IRelativeRel, In<ELFT>::IgotPlt,
- Body.getGotPltOffset<ELFT>(),
- !Preemptible, &Body, 0});
- } else {
- In<ELFT>::Plt->addEntry(Body);
- In<ELFT>::GotPlt->addEntry(Body);
- In<ELFT>::RelaPlt->addReloc({Target->PltRel, In<ELFT>::GotPlt,
- Body.getGotPltOffset<ELFT>(), !Preemptible,
- &Body, 0});
- }
- continue;
- }
-
- if (refersToGotEntry(Expr)) {
- if (Config->EMachine == EM_MIPS) {
- // MIPS ABI has special rules to process GOT entries and doesn't
- // require relocation entries for them. A special case is TLS
- // relocations. In that case dynamic loader applies dynamic
- // relocations to initialize TLS GOT entries.
- // See "Global Offset Table" in Chapter 5 in the following document
- // for detailed description:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- In<ELFT>::MipsGot->addEntry(Body, Addend, Expr);
- if (Body.isTls() && Body.isPreemptible())
- AddDyn({Target->TlsGotRel, In<ELFT>::MipsGot,
- Body.getGotOffset<ELFT>(), false, &Body, 0});
- continue;
- }
-
- if (Body.isInGot())
- continue;
+ // If the output being produced is position independent, the final value
+ // is still not known. In that case we still need some help from the
+ // dynamic linker. We can however do better than just copying the incoming
+ // relocation. We can process some of it and and just ask the dynamic
+ // linker to add the load address.
+ if (!IsConstant)
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->RelativeRel, &Sec, Offset, true, &Body, Addend});
- In<ELFT>::Got->addEntry(Body);
- uintX_t Off = Body.getGotOffset<ELFT>();
- uint32_t DynType;
- RelExpr GotRE = R_ABS;
- if (Body.isTls()) {
- DynType = Target->TlsGotRel;
- GotRE = R_TLS;
- } else if (!Preemptible && Config->Pic && !isAbsolute<ELFT>(Body))
- DynType = Target->RelativeRel;
- else
- DynType = Target->GotRel;
-
- // FIXME: this logic is almost duplicated above.
- bool Constant = !Preemptible && !(Config->Pic && !isAbsolute<ELFT>(Body));
- if (!Constant)
- AddDyn({DynType, In<ELFT>::Got, Off, !Preemptible, &Body, 0});
- if (Constant || (!RelTy::IsRela && !Preemptible))
- In<ELFT>::Got->Relocations.push_back({GotRE, DynType, Off, 0, &Body});
- continue;
- }
+ // If the produced value is a constant, we just remember to write it
+ // when outputting this section. We also have to do it if the format
+ // uses Elf_Rel, since in that case the written value is the addend.
+ if (IsConstant || !RelTy::IsRela)
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
}
}
-template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &S) {
+template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
if (S.AreRelocsRela)
- scanRelocs(S, S.relas());
+ scanRelocs<ELFT>(S, S.relas<ELFT>());
else
- scanRelocs(S, S.rels());
+ scanRelocs<ELFT>(S, S.rels<ELFT>());
}
-template <class ELFT, class RelTy>
-static void createThunks(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
- const elf::ObjectFile<ELFT> *File = C.getFile();
- for (const RelTy &Rel : Rels) {
- SymbolBody &Body = File->getRelocTargetSym(Rel);
- uint32_t Type = Rel.getType(Config->Mips64EL);
- RelExpr Expr = Target->getRelExpr(Type, Body);
- if (!isPreemptible(Body, Type) && needsPlt(Expr))
- Expr = fromPlt(Expr);
- Expr = Target->getThunkExpr(Expr, Type, *File, Body);
- // Some targets might require creation of thunks for relocations.
- // Now we support only MIPS which requires LA25 thunk to call PIC
- // code from non-PIC one, and ARM which requires interworking.
- if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) {
- auto *Sec = cast<InputSection<ELFT>>(&C);
- addThunk<ELFT>(Type, Body, *Sec);
- }
+// Insert the Thunks for OutputSection OS into their designated place
+// in the Sections vector, and recalculate the InputSection output section
+// offsets.
+// This may invalidate any output section offsets stored outside of InputSection
+void ThunkCreator::mergeThunks() {
+ for (auto &KV : ThunkSections) {
+ std::vector<InputSection *> *ISR = KV.first;
+ std::vector<ThunkSection *> &Thunks = KV.second;
+
+ // Order Thunks in ascending OutSecOff
+ auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) {
+ return A->OutSecOff < B->OutSecOff;
+ };
+ std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp);
+
+ // Merge sorted vectors of Thunks and InputSections by OutSecOff
+ std::vector<InputSection *> Tmp;
+ Tmp.reserve(ISR->size() + Thunks.size());
+ auto MergeCmp = [](const InputSection *A, const InputSection *B) {
+ // std::merge requires a strict weak ordering.
+ if (A->OutSecOff < B->OutSecOff)
+ return true;
+ if (A->OutSecOff == B->OutSecOff)
+ // Check if Thunk is immediately before any specific Target InputSection
+ // for example Mips LA25 Thunks.
+ if (auto *TA = dyn_cast<ThunkSection>(A))
+ if (TA && TA->getTargetInputSection() == B)
+ return true;
+ return false;
+ };
+ std::merge(ISR->begin(), ISR->end(), Thunks.begin(), Thunks.end(),
+ std::back_inserter(Tmp), MergeCmp);
+ *ISR = std::move(Tmp);
}
}
-template <class ELFT> void createThunks(InputSectionBase<ELFT> &S) {
- if (S.AreRelocsRela)
- createThunks(S, S.relas());
- else
- createThunks(S, S.rels());
+static uint32_t findEndOfFirstNonExec(OutputSectionCommand &Cmd) {
+ for (BaseCommand *Base : Cmd.Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ for (auto *IS : ISD->Sections)
+ if ((IS->Flags & SHF_EXECINSTR) == 0)
+ return IS->OutSecOff + IS->getSize();
+ return 0;
}
-template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &);
-template void scanRelocations<ELF32BE>(InputSectionBase<ELF32BE> &);
-template void scanRelocations<ELF64LE>(InputSectionBase<ELF64LE> &);
-template void scanRelocations<ELF64BE>(InputSectionBase<ELF64BE> &);
+ThunkSection *ThunkCreator::getOSThunkSec(OutputSectionCommand *Cmd,
+ std::vector<InputSection *> *ISR) {
+ if (CurTS == nullptr) {
+ uint32_t Off = findEndOfFirstNonExec(*Cmd);
+ CurTS = addThunkSection(Cmd->Sec, ISR, Off);
+ }
+ return CurTS;
+}
-template void createThunks<ELF32LE>(InputSectionBase<ELF32LE> &);
-template void createThunks<ELF32BE>(InputSectionBase<ELF32BE> &);
-template void createThunks<ELF64LE>(InputSectionBase<ELF64LE> &);
-template void createThunks<ELF64BE>(InputSectionBase<ELF64BE> &);
+ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) {
+ ThunkSection *TS = ThunkedSections.lookup(IS);
+ if (TS)
+ return TS;
+ auto *TOS = IS->getParent();
+
+ // Find InputSectionRange within TOS that IS is in
+ OutputSectionCommand *C = Script->getCmd(TOS);
+ std::vector<InputSection *> *Range = nullptr;
+ for (BaseCommand *BC : C->Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
+ InputSection *first = ISD->Sections.front();
+ InputSection *last = ISD->Sections.back();
+ if (IS->OutSecOff >= first->OutSecOff &&
+ IS->OutSecOff <= last->OutSecOff) {
+ Range = &ISD->Sections;
+ break;
+ }
+ }
+ TS = addThunkSection(TOS, Range, IS->OutSecOff);
+ ThunkedSections[IS] = TS;
+ return TS;
}
+
+ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
+ std::vector<InputSection *> *ISR,
+ uint64_t Off) {
+ auto *TS = make<ThunkSection>(OS, Off);
+ ThunkSections[ISR].push_back(TS);
+ return TS;
+}
+
+std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body,
+ uint32_t Type) {
+ auto Res = ThunkedSymbols.insert({&Body, std::vector<Thunk *>()});
+ if (!Res.second) {
+ // Check existing Thunks for Body to see if they can be reused
+ for (Thunk *ET : Res.first->second)
+ if (ET->isCompatibleWith(Type))
+ return std::make_pair(ET, false);
+ }
+ // No existing compatible Thunk in range, create a new one
+ Thunk *T = addThunk(Type, Body);
+ Res.first->second.push_back(T);
+ return std::make_pair(T, true);
}
+
+// Call Fn on every executable InputSection accessed via the linker script
+// InputSectionDescription::Sections.
+void ThunkCreator::forEachExecInputSection(
+ ArrayRef<OutputSectionCommand *> OutputSections,
+ std::function<void(OutputSectionCommand *, std::vector<InputSection *> *,
+ InputSection *)>
+ Fn) {
+ for (OutputSectionCommand *Cmd : OutputSections) {
+ OutputSection *OS = Cmd->Sec;
+ if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
+ continue;
+ for (BaseCommand *BC : Cmd->Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
+ CurTS = nullptr;
+ for (InputSection *IS : ISD->Sections)
+ Fn(Cmd, &ISD->Sections, IS);
+ }
+ }
+}
+
+// Process all relocations from the InputSections that have been assigned
+// to OutputSections and redirect through Thunks if needed.
+//
+// createThunks must be called after scanRelocs has created the Relocations for
+// each InputSection. It must be called before the static symbol table is
+// finalized. If any Thunks are added to an OutputSection the output section
+// offsets of the InputSections will change.
+//
+// FIXME: All Thunks are assumed to be in range of the relocation. Range
+// extension Thunks are not yet supported.
+bool ThunkCreator::createThunks(
+ ArrayRef<OutputSectionCommand *> OutputSections) {
+ if (Pass > 0)
+ ThunkSections.clear();
+
+ // Create all the Thunks and insert them into synthetic ThunkSections. The
+ // ThunkSections are later inserted back into the OutputSection.
+
+ // We separate the creation of ThunkSections from the insertion of the
+ // ThunkSections back into the OutputSection as ThunkSections are not always
+ // inserted into the same OutputSection as the caller.
+ forEachExecInputSection(OutputSections, [&](OutputSectionCommand *Cmd,
+ std::vector<InputSection *> *ISR,
+ InputSection *IS) {
+ for (Relocation &Rel : IS->Relocations) {
+ SymbolBody &Body = *Rel.Sym;
+ if (Thunks.find(&Body) != Thunks.end() ||
+ !Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body))
+ continue;
+ Thunk *T;
+ bool IsNew;
+ std::tie(T, IsNew) = getThunk(Body, Rel.Type);
+ if (IsNew) {
+ // Find or create a ThunkSection for the new Thunk
+ ThunkSection *TS;
+ if (auto *TIS = T->getTargetInputSection())
+ TS = getISThunkSec(TIS, Cmd->Sec);
+ else
+ TS = getOSThunkSec(Cmd, ISR);
+ TS->addThunk(T);
+ Thunks[T->ThunkSym] = T;
+ }
+ // Redirect relocation to Thunk, we never go via the PLT to a Thunk
+ Rel.Sym = T->ThunkSym;
+ Rel.Expr = fromPlt(Rel.Expr);
+ }
+ });
+ // Merge all created synthetic ThunkSections back into OutputSection
+ mergeThunks();
+ ++Pass;
+ return !ThunkSections.empty();
+}
+
+template void elf::scanRelocations<ELF32LE>(InputSectionBase &);
+template void elf::scanRelocations<ELF32BE>(InputSectionBase &);
+template void elf::scanRelocations<ELF64LE>(InputSectionBase &);
+template void elf::scanRelocations<ELF64BE>(InputSectionBase &);
diff --git a/contrib/llvm/tools/lld/ELF/Relocations.h b/contrib/llvm/tools/lld/ELF/Relocations.h
index 6f5afc3..ea046d2 100644
--- a/contrib/llvm/tools/lld/ELF/Relocations.h
+++ b/contrib/llvm/tools/lld/ELF/Relocations.h
@@ -11,19 +11,24 @@
#define LLD_ELF_RELOCATIONS_H
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include <map>
+#include <vector>
namespace lld {
namespace elf {
class SymbolBody;
-class InputSectionData;
-template <class ELFT> class InputSection;
-template <class ELFT> class InputSectionBase;
+class InputSection;
+class InputSectionBase;
+class OutputSection;
+struct OutputSectionCommand;
// List of target-independent relocation types. Relocations read
// from files are converted to these types so that the main code
// doesn't have to know about architecture-specific details.
enum RelExpr {
R_ABS,
+ R_ARM_SBREL,
R_GOT,
R_GOTONLY_PC,
R_GOTONLY_PC_FROM_END,
@@ -35,12 +40,15 @@ enum RelExpr {
R_GOT_PC,
R_HINT,
R_MIPS_GOTREL,
+ R_MIPS_GOT_GP,
+ R_MIPS_GOT_GP_PC,
R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOT_OFF,
R_MIPS_GOT_OFF32,
R_MIPS_TLSGD,
R_MIPS_TLSLD,
R_NEG_TLS,
+ R_NONE,
R_PAGE_PC,
R_PC,
R_PLT,
@@ -60,9 +68,6 @@ enum RelExpr {
R_RELAX_TLS_IE_TO_LE,
R_RELAX_TLS_LD_TO_LE,
R_SIZE,
- R_THUNK_ABS,
- R_THUNK_PC,
- R_THUNK_PLT_PC,
R_TLS,
R_TLSDESC,
R_TLSDESC_CALL,
@@ -98,7 +103,8 @@ struct RelExprMaskBuilder<Head, Tail...> {
// RelExpr's as a constant bit mask and test for membership with a
// couple cheap bitwise operations.
template <RelExpr... Exprs> bool isRelExprOneOf(RelExpr Expr) {
- assert(0 <= Expr && (int)Expr < 64 && "RelExpr is too large for 64-bit mask!");
+ assert(0 <= Expr && (int)Expr < 64 &&
+ "RelExpr is too large for 64-bit mask!");
return (uint64_t(1) << Expr) & RelExprMaskBuilder<Exprs...>::build();
}
@@ -107,24 +113,73 @@ struct Relocation {
RelExpr Expr;
uint32_t Type;
uint64_t Offset;
- uint64_t Addend;
+ int64_t Addend;
SymbolBody *Sym;
};
-template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &);
+template <class ELFT> void scanRelocations(InputSectionBase &);
-template <class ELFT> void createThunks(InputSectionBase<ELFT> &);
+class ThunkSection;
+class Thunk;
+class ThunkCreator {
+public:
+ // Return true if Thunks have been added to OutputSections
+ bool createThunks(ArrayRef<OutputSectionCommand *> OutputSections);
+
+ // The number of completed passes of createThunks this permits us
+ // to do one time initialization on Pass 0 and put a limit on the
+ // number of times it can be called to prevent infinite loops.
+ uint32_t Pass = 0;
+
+private:
+ void mergeThunks();
+ ThunkSection *getOSThunkSec(OutputSectionCommand *Cmd,
+ std::vector<InputSection *> *ISR);
+ ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS);
+ void forEachExecInputSection(
+ ArrayRef<OutputSectionCommand *> OutputSections,
+ std::function<void(OutputSectionCommand *, std::vector<InputSection *> *,
+ InputSection *)>
+ Fn);
+ std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type);
+ ThunkSection *addThunkSection(OutputSection *OS,
+ std::vector<InputSection *> *, uint64_t Off);
+ // Record all the available Thunks for a Symbol
+ llvm::DenseMap<SymbolBody *, std::vector<Thunk *>> ThunkedSymbols;
+
+ // Find a Thunk from the Thunks symbol definition, we can use this to find
+ // the Thunk from a relocation to the Thunks symbol definition.
+ llvm::DenseMap<SymbolBody *, Thunk *> Thunks;
+
+ // Track InputSections that have an inline ThunkSection placed in front
+ // an inline ThunkSection may have control fall through to the section below
+ // so we need to make sure that there is only one of them.
+ // The Mips LA25 Thunk is an example of an inline ThunkSection.
+ llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections;
+
+ // All the ThunkSections that we have created, organised by OutputSection
+ // will contain a mix of ThunkSections that have been created this pass, and
+ // ThunkSections that have been merged into the OutputSection on previous
+ // passes
+ std::map<std::vector<InputSection *> *, std::vector<ThunkSection *>>
+ ThunkSections;
+
+ // The ThunkSection for this vector of InputSections
+ ThunkSection *CurTS;
+};
+
+// Return a int64_t to make sure we get the sign extension out of the way as
+// early as possible.
template <class ELFT>
-static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) {
+static inline int64_t getAddend(const typename ELFT::Rel &Rel) {
return 0;
}
-
template <class ELFT>
-static inline typename ELFT::uint getAddend(const typename ELFT::Rela &Rel) {
+static inline int64_t getAddend(const typename ELFT::Rela &Rel) {
return Rel.r_addend;
}
-}
-}
+} // namespace elf
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp b/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp
new file mode 100644
index 0000000..86720de
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/ScriptLexer.cpp
@@ -0,0 +1,285 @@
+//===- ScriptLexer.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a lexer for the linker script.
+//
+// The linker script's grammar is not complex but ambiguous due to the
+// lack of the formal specification of the language. What we are trying to
+// do in this and other files in LLD is to make a "reasonable" linker
+// script processor.
+//
+// Among simplicity, compatibility and efficiency, we put the most
+// emphasis on simplicity when we wrote this lexer. Compatibility with the
+// GNU linkers is important, but we did not try to clone every tiny corner
+// case of their lexers, as even ld.bfd and ld.gold are subtly different
+// in various corner cases. We do not care much about efficiency because
+// the time spent in parsing linker scripts is usually negligible.
+//
+// Our grammar of the linker script is LL(2), meaning that it needs at
+// most two-token lookahead to parse. The only place we need two-token
+// lookahead is labels in version scripts, where we need to parse "local :"
+// as if "local:".
+//
+// Overall, this lexer works fine for most linker scripts. There might
+// be room for improving compatibility, but that's probably not at the
+// top of our todo list.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptLexer.h"
+#include "Error.h"
+#include "llvm/ADT/Twine.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+// Returns a whole line containing the current token.
+StringRef ScriptLexer::getLine() {
+ StringRef S = getCurrentMB().getBuffer();
+ StringRef Tok = Tokens[Pos - 1];
+
+ size_t Pos = S.rfind('\n', Tok.data() - S.data());
+ if (Pos != StringRef::npos)
+ S = S.substr(Pos + 1);
+ return S.substr(0, S.find_first_of("\r\n"));
+}
+
+// Returns 1-based line number of the current token.
+size_t ScriptLexer::getLineNumber() {
+ StringRef S = getCurrentMB().getBuffer();
+ StringRef Tok = Tokens[Pos - 1];
+ return S.substr(0, Tok.data() - S.data()).count('\n') + 1;
+}
+
+// Returns 0-based column number of the current token.
+size_t ScriptLexer::getColumnNumber() {
+ StringRef Tok = Tokens[Pos - 1];
+ return Tok.data() - getLine().data();
+}
+
+std::string ScriptLexer::getCurrentLocation() {
+ std::string Filename = getCurrentMB().getBufferIdentifier();
+ if (!Pos)
+ return Filename;
+ return (Filename + ":" + Twine(getLineNumber())).str();
+}
+
+ScriptLexer::ScriptLexer(MemoryBufferRef MB) { tokenize(MB); }
+
+// We don't want to record cascading errors. Keep only the first one.
+void ScriptLexer::setError(const Twine &Msg) {
+ if (Error)
+ return;
+ Error = true;
+
+ if (!Pos) {
+ error(getCurrentLocation() + ": " + Msg);
+ return;
+ }
+
+ std::string S = getCurrentLocation() + ": ";
+ error(S + Msg);
+ error(S + getLine());
+ error(S + std::string(getColumnNumber(), ' ') + "^");
+}
+
+// Split S into linker script tokens.
+void ScriptLexer::tokenize(MemoryBufferRef MB) {
+ std::vector<StringRef> Vec;
+ MBs.push_back(MB);
+ StringRef S = MB.getBuffer();
+ StringRef Begin = S;
+
+ for (;;) {
+ S = skipSpace(S);
+ if (S.empty())
+ break;
+
+ // Quoted token. Note that double-quote characters are parts of a token
+ // because, in a glob match context, only unquoted tokens are interpreted
+ // as glob patterns. Double-quoted tokens are literal patterns in that
+ // context.
+ if (S.startswith("\"")) {
+ size_t E = S.find("\"", 1);
+ if (E == StringRef::npos) {
+ StringRef Filename = MB.getBufferIdentifier();
+ size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n');
+ error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote");
+ return;
+ }
+
+ Vec.push_back(S.take_front(E + 1));
+ S = S.substr(E + 1);
+ continue;
+ }
+
+ // Unquoted token. This is more relaxed than tokens in C-like language,
+ // so that you can write "file-name.cpp" as one bare token, for example.
+ size_t Pos = S.find_first_not_of(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789_.$/\\~=+[]*?-!<>^:");
+
+ // A character that cannot start a word (which is usually a
+ // punctuation) forms a single character token.
+ if (Pos == 0)
+ Pos = 1;
+ Vec.push_back(S.substr(0, Pos));
+ S = S.substr(Pos);
+ }
+
+ Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end());
+}
+
+// Skip leading whitespace characters or comments.
+StringRef ScriptLexer::skipSpace(StringRef S) {
+ for (;;) {
+ if (S.startswith("/*")) {
+ size_t E = S.find("*/", 2);
+ if (E == StringRef::npos) {
+ error("unclosed comment in a linker script");
+ return "";
+ }
+ S = S.substr(E + 2);
+ continue;
+ }
+ if (S.startswith("#")) {
+ size_t E = S.find('\n', 1);
+ if (E == StringRef::npos)
+ E = S.size() - 1;
+ S = S.substr(E + 1);
+ continue;
+ }
+ size_t Size = S.size();
+ S = S.ltrim();
+ if (S.size() == Size)
+ return S;
+ }
+}
+
+// An erroneous token is handled as if it were the last token before EOF.
+bool ScriptLexer::atEOF() { return Error || Tokens.size() == Pos; }
+
+// Split a given string as an expression.
+// This function returns "3", "*" and "5" for "3*5" for example.
+static std::vector<StringRef> tokenizeExpr(StringRef S) {
+ StringRef Ops = "+-*/:"; // List of operators
+
+ // Quoted strings are literal strings, so we don't want to split it.
+ if (S.startswith("\""))
+ return {S};
+
+ // Split S with +-*/ as separators.
+ std::vector<StringRef> Ret;
+ while (!S.empty()) {
+ size_t E = S.find_first_of(Ops);
+
+ // No need to split if there is no operator.
+ if (E == StringRef::npos) {
+ Ret.push_back(S);
+ break;
+ }
+
+ // Get a token before the opreator.
+ if (E != 0)
+ Ret.push_back(S.substr(0, E));
+
+ // Get the operator as a token.
+ Ret.push_back(S.substr(E, 1));
+ S = S.substr(E + 1);
+ }
+ return Ret;
+}
+
+// In contexts where expressions are expected, the lexer should apply
+// different tokenization rules than the default one. By default,
+// arithmetic operator characters are regular characters, but in the
+// expression context, they should be independent tokens.
+//
+// For example, "foo*3" should be tokenized to "foo", "*" and "3" only
+// in the expression context.
+//
+// This function may split the current token into multiple tokens.
+void ScriptLexer::maybeSplitExpr() {
+ if (!InExpr || Error || atEOF())
+ return;
+
+ std::vector<StringRef> V = tokenizeExpr(Tokens[Pos]);
+ if (V.size() == 1)
+ return;
+ Tokens.erase(Tokens.begin() + Pos);
+ Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
+}
+
+StringRef ScriptLexer::next() {
+ maybeSplitExpr();
+
+ if (Error)
+ return "";
+ if (atEOF()) {
+ setError("unexpected EOF");
+ return "";
+ }
+ return Tokens[Pos++];
+}
+
+StringRef ScriptLexer::peek() {
+ StringRef Tok = next();
+ if (Error)
+ return "";
+ Pos = Pos - 1;
+ return Tok;
+}
+
+bool ScriptLexer::consume(StringRef Tok) {
+ if (peek() == Tok) {
+ skip();
+ return true;
+ }
+ return false;
+}
+
+// Consumes Tok followed by ":". Space is allowed between Tok and ":".
+bool ScriptLexer::consumeLabel(StringRef Tok) {
+ if (consume((Tok + ":").str()))
+ return true;
+ if (Tokens.size() >= Pos + 2 && Tokens[Pos] == Tok &&
+ Tokens[Pos + 1] == ":") {
+ Pos += 2;
+ return true;
+ }
+ return false;
+}
+
+void ScriptLexer::skip() { (void)next(); }
+
+void ScriptLexer::expect(StringRef Expect) {
+ if (Error)
+ return;
+ StringRef Tok = next();
+ if (Tok != Expect)
+ setError(Expect + " expected, but got " + Tok);
+}
+
+// Returns true if S encloses T.
+static bool encloses(StringRef S, StringRef T) {
+ return S.bytes_begin() <= T.bytes_begin() && T.bytes_end() <= S.bytes_end();
+}
+
+MemoryBufferRef ScriptLexer::getCurrentMB() {
+ // Find input buffer containing the current token.
+ assert(!MBs.empty());
+ if (!Pos)
+ return MBs[0];
+
+ for (MemoryBufferRef MB : MBs)
+ if (encloses(MB.getBuffer(), Tokens[Pos - 1]))
+ return MB;
+ llvm_unreachable("getCurrentMB: failed to find a token");
+}
diff --git a/contrib/llvm/tools/lld/ELF/ScriptLexer.h b/contrib/llvm/tools/lld/ELF/ScriptLexer.h
new file mode 100644
index 0000000..64d6d92
--- /dev/null
+++ b/contrib/llvm/tools/lld/ELF/ScriptLexer.h
@@ -0,0 +1,56 @@
+//===- ScriptLexer.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SCRIPT_LEXER_H
+#define LLD_ELF_SCRIPT_LEXER_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <utility>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class ScriptLexer {
+public:
+ explicit ScriptLexer(MemoryBufferRef MB);
+
+ void setError(const Twine &Msg);
+ void tokenize(MemoryBufferRef MB);
+ static StringRef skipSpace(StringRef S);
+ bool atEOF();
+ StringRef next();
+ StringRef peek();
+ void skip();
+ bool consume(StringRef Tok);
+ void expect(StringRef Expect);
+ bool consumeLabel(StringRef Tok);
+ std::string getCurrentLocation();
+
+ std::vector<MemoryBufferRef> MBs;
+ std::vector<StringRef> Tokens;
+ bool InExpr = false;
+ size_t Pos = 0;
+ bool Error = false;
+
+private:
+ void maybeSplitExpr();
+ StringRef getLine();
+ size_t getLineNumber();
+ size_t getColumnNumber();
+
+ MemoryBufferRef getCurrentMB();
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm/tools/lld/ELF/ScriptParser.cpp b/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
index c740685..b384708 100644
--- a/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
+++ b/contrib/llvm/tools/lld/ELF/ScriptParser.cpp
@@ -7,194 +7,1241 @@
//
//===----------------------------------------------------------------------===//
//
-// This file contains the base parser class for linker script and dynamic
-// list.
+// This file contains a recursive-descendent parser for linker scripts.
+// Parsed results are stored to Config and Script global objects.
//
//===----------------------------------------------------------------------===//
#include "ScriptParser.h"
-#include "Error.h"
-#include "llvm/ADT/Twine.h"
+#include "Config.h"
+#include "Driver.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "ScriptLexer.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <cassert>
+#include <limits>
+#include <vector>
using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
-// Returns a whole line containing the current token.
-StringRef ScriptParserBase::getLine() {
- StringRef S = getCurrentMB().getBuffer();
- StringRef Tok = Tokens[Pos - 1];
+static bool isUnderSysroot(StringRef Path);
- size_t Pos = S.rfind('\n', Tok.data() - S.data());
- if (Pos != StringRef::npos)
- S = S.substr(Pos + 1);
- return S.substr(0, S.find_first_of("\r\n"));
+namespace {
+class ScriptParser final : ScriptLexer {
+public:
+ ScriptParser(MemoryBufferRef MB)
+ : ScriptLexer(MB),
+ IsUnderSysroot(isUnderSysroot(MB.getBufferIdentifier())) {}
+
+ void readLinkerScript();
+ void readVersionScript();
+ void readDynamicList();
+
+private:
+ void addFile(StringRef Path);
+ OutputSection *checkSection(OutputSectionCommand *Cmd, StringRef Loccation);
+
+ void readAsNeeded();
+ void readEntry();
+ void readExtern();
+ void readGroup();
+ void readInclude();
+ void readMemory();
+ void readOutput();
+ void readOutputArch();
+ void readOutputFormat();
+ void readPhdrs();
+ void readSearchDir();
+ void readSections();
+ void readVersion();
+ void readVersionScriptCommand();
+
+ SymbolAssignment *readAssignment(StringRef Name);
+ BytesDataCommand *readBytesDataCommand(StringRef Tok);
+ uint32_t readFill();
+ uint32_t parseFill(StringRef Tok);
+ void readSectionAddressType(OutputSectionCommand *Cmd);
+ OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
+ std::vector<StringRef> readOutputSectionPhdrs();
+ InputSectionDescription *readInputSectionDescription(StringRef Tok);
+ StringMatcher readFilePatterns();
+ std::vector<SectionPattern> readInputSectionsList();
+ InputSectionDescription *readInputSectionRules(StringRef FilePattern);
+ unsigned readPhdrType();
+ SortSectionPolicy readSortKind();
+ SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
+ SymbolAssignment *readProvideOrAssignment(StringRef Tok);
+ void readSort();
+ AssertCommand *readAssert();
+ Expr readAssertExpr();
+
+ uint64_t readMemoryAssignment(StringRef, StringRef, StringRef);
+ std::pair<uint32_t, uint32_t> readMemoryAttributes();
+
+ Expr readExpr();
+ Expr readExpr1(Expr Lhs, int MinPrec);
+ StringRef readParenLiteral();
+ Expr readPrimary();
+ Expr readTernary(Expr Cond);
+ Expr readParenExpr();
+
+ // For parsing version script.
+ std::vector<SymbolVersion> readVersionExtern();
+ void readAnonymousDeclaration();
+ void readVersionDeclaration(StringRef VerStr);
+
+ std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>>
+ readSymbols();
+
+ bool IsUnderSysroot;
+};
+} // namespace
+
+static StringRef unquote(StringRef S) {
+ if (S.startswith("\""))
+ return S.substr(1, S.size() - 2);
+ return S;
+}
+
+static bool isUnderSysroot(StringRef Path) {
+ if (Config->Sysroot == "")
+ return false;
+ for (; !Path.empty(); Path = sys::path::parent_path(Path))
+ if (sys::fs::equivalent(Config->Sysroot, Path))
+ return true;
+ return false;
+}
+
+// Some operations only support one non absolute value. Move the
+// absolute one to the right hand side for convenience.
+static void moveAbsRight(ExprValue &A, ExprValue &B) {
+ if (A.isAbsolute())
+ std::swap(A, B);
+ if (!B.isAbsolute())
+ error(A.Loc + ": at least one side of the expression must be absolute");
}
-// Returns 1-based line number of the current token.
-size_t ScriptParserBase::getLineNumber() {
- StringRef S = getCurrentMB().getBuffer();
- StringRef Tok = Tokens[Pos - 1];
- return S.substr(0, Tok.data() - S.data()).count('\n') + 1;
+static ExprValue add(ExprValue A, ExprValue B) {
+ moveAbsRight(A, B);
+ return {A.Sec, A.ForceAbsolute, A.Val + B.getValue(), A.Loc};
}
-// Returns 0-based column number of the current token.
-size_t ScriptParserBase::getColumnNumber() {
- StringRef Tok = Tokens[Pos - 1];
- return Tok.data() - getLine().data();
+static ExprValue sub(ExprValue A, ExprValue B) {
+ return {A.Sec, A.Val - B.getValue(), A.Loc};
}
-std::string ScriptParserBase::getCurrentLocation() {
- std::string Filename = getCurrentMB().getBufferIdentifier();
- if (!Pos)
- return Filename;
- return (Filename + ":" + Twine(getLineNumber())).str();
+static ExprValue mul(ExprValue A, ExprValue B) {
+ return A.getValue() * B.getValue();
}
-ScriptParserBase::ScriptParserBase(MemoryBufferRef MB) { tokenize(MB); }
+static ExprValue div(ExprValue A, ExprValue B) {
+ if (uint64_t BV = B.getValue())
+ return A.getValue() / BV;
+ error("division by zero");
+ return 0;
+}
-// We don't want to record cascading errors. Keep only the first one.
-void ScriptParserBase::setError(const Twine &Msg) {
- if (Error)
+static ExprValue bitAnd(ExprValue A, ExprValue B) {
+ moveAbsRight(A, B);
+ return {A.Sec, A.ForceAbsolute,
+ (A.getValue() & B.getValue()) - A.getSecAddr(), A.Loc};
+}
+
+static ExprValue bitOr(ExprValue A, ExprValue B) {
+ moveAbsRight(A, B);
+ return {A.Sec, A.ForceAbsolute,
+ (A.getValue() | B.getValue()) - A.getSecAddr(), A.Loc};
+}
+
+void ScriptParser::readDynamicList() {
+ expect("{");
+ readAnonymousDeclaration();
+ if (!atEOF())
+ setError("EOF expected, but got " + next());
+}
+
+void ScriptParser::readVersionScript() {
+ readVersionScriptCommand();
+ if (!atEOF())
+ setError("EOF expected, but got " + next());
+}
+
+void ScriptParser::readVersionScriptCommand() {
+ if (consume("{")) {
+ readAnonymousDeclaration();
return;
- Error = true;
+ }
+
+ while (!atEOF() && !Error && peek() != "}") {
+ StringRef VerStr = next();
+ if (VerStr == "{") {
+ setError("anonymous version definition is used in "
+ "combination with other version definitions");
+ return;
+ }
+ expect("{");
+ readVersionDeclaration(VerStr);
+ }
+}
+
+void ScriptParser::readVersion() {
+ expect("{");
+ readVersionScriptCommand();
+ expect("}");
+}
- if (!Pos) {
- error(getCurrentLocation() + ": " + Msg);
+void ScriptParser::readLinkerScript() {
+ while (!atEOF()) {
+ StringRef Tok = next();
+ if (Tok == ";")
+ continue;
+
+ if (Tok == "ASSERT") {
+ Script->Opt.Commands.push_back(readAssert());
+ } else if (Tok == "ENTRY") {
+ readEntry();
+ } else if (Tok == "EXTERN") {
+ readExtern();
+ } else if (Tok == "GROUP" || Tok == "INPUT") {
+ readGroup();
+ } else if (Tok == "INCLUDE") {
+ readInclude();
+ } else if (Tok == "MEMORY") {
+ readMemory();
+ } else if (Tok == "OUTPUT") {
+ readOutput();
+ } else if (Tok == "OUTPUT_ARCH") {
+ readOutputArch();
+ } else if (Tok == "OUTPUT_FORMAT") {
+ readOutputFormat();
+ } else if (Tok == "PHDRS") {
+ readPhdrs();
+ } else if (Tok == "SEARCH_DIR") {
+ readSearchDir();
+ } else if (Tok == "SECTIONS") {
+ readSections();
+ } else if (Tok == "VERSION") {
+ readVersion();
+ } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
+ Script->Opt.Commands.push_back(Cmd);
+ } else {
+ setError("unknown directive: " + Tok);
+ }
+ }
+}
+
+void ScriptParser::addFile(StringRef S) {
+ if (IsUnderSysroot && S.startswith("/")) {
+ SmallString<128> PathData;
+ StringRef Path = (Config->Sysroot + S).toStringRef(PathData);
+ if (sys::fs::exists(Path)) {
+ Driver->addFile(Saver.save(Path), /*WithLOption=*/false);
+ return;
+ }
+ }
+
+ if (sys::path::is_absolute(S)) {
+ Driver->addFile(S, /*WithLOption=*/false);
+ } else if (S.startswith("=")) {
+ if (Config->Sysroot.empty())
+ Driver->addFile(S.substr(1), /*WithLOption=*/false);
+ else
+ Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)),
+ /*WithLOption=*/false);
+ } else if (S.startswith("-l")) {
+ Driver->addLibrary(S.substr(2));
+ } else if (sys::fs::exists(S)) {
+ Driver->addFile(S, /*WithLOption=*/false);
+ } else {
+ if (Optional<std::string> Path = findFromSearchPaths(S))
+ Driver->addFile(Saver.save(*Path), /*WithLOption=*/true);
+ else
+ setError("unable to find " + S);
+ }
+}
+
+void ScriptParser::readAsNeeded() {
+ expect("(");
+ bool Orig = Config->AsNeeded;
+ Config->AsNeeded = true;
+ while (!Error && !consume(")"))
+ addFile(unquote(next()));
+ Config->AsNeeded = Orig;
+}
+
+void ScriptParser::readEntry() {
+ // -e <symbol> takes predecence over ENTRY(<symbol>).
+ expect("(");
+ StringRef Tok = next();
+ if (Config->Entry.empty())
+ Config->Entry = Tok;
+ expect(")");
+}
+
+void ScriptParser::readExtern() {
+ expect("(");
+ while (!Error && !consume(")"))
+ Config->Undefined.push_back(next());
+}
+
+void ScriptParser::readGroup() {
+ expect("(");
+ while (!Error && !consume(")")) {
+ if (consume("AS_NEEDED"))
+ readAsNeeded();
+ else
+ addFile(unquote(next()));
+ }
+}
+
+void ScriptParser::readInclude() {
+ StringRef Tok = unquote(next());
+
+ // https://sourceware.org/binutils/docs/ld/File-Commands.html:
+ // The file will be searched for in the current directory, and in any
+ // directory specified with the -L option.
+ if (sys::fs::exists(Tok)) {
+ if (Optional<MemoryBufferRef> MB = readFile(Tok))
+ tokenize(*MB);
return;
}
+ if (Optional<std::string> Path = findFromSearchPaths(Tok)) {
+ if (Optional<MemoryBufferRef> MB = readFile(*Path))
+ tokenize(*MB);
+ return;
+ }
+ setError("cannot open " + Tok);
+}
- std::string S = getCurrentLocation() + ": ";
- error(S + Msg);
- error(S + getLine());
- error(S + std::string(getColumnNumber(), ' ') + "^");
+void ScriptParser::readOutput() {
+ // -o <file> takes predecence over OUTPUT(<file>).
+ expect("(");
+ StringRef Tok = next();
+ if (Config->OutputFile.empty())
+ Config->OutputFile = unquote(Tok);
+ expect(")");
}
-// Split S into linker script tokens.
-void ScriptParserBase::tokenize(MemoryBufferRef MB) {
- std::vector<StringRef> Vec;
- MBs.push_back(MB);
- StringRef S = MB.getBuffer();
- StringRef Begin = S;
+void ScriptParser::readOutputArch() {
+ // OUTPUT_ARCH is ignored for now.
+ expect("(");
+ while (!Error && !consume(")"))
+ skip();
+}
- for (;;) {
- S = skipSpace(S);
- if (S.empty())
- break;
+void ScriptParser::readOutputFormat() {
+ // Error checking only for now.
+ expect("(");
+ skip();
+ if (consume(")"))
+ return;
+ expect(",");
+ skip();
+ expect(",");
+ skip();
+ expect(")");
+}
- // Quoted token. Note that double-quote characters are parts of a token
- // because, in a glob match context, only unquoted tokens are interpreted
- // as glob patterns. Double-quoted tokens are literal patterns in that
- // context.
- if (S.startswith("\"")) {
- size_t E = S.find("\"", 1);
- if (E == StringRef::npos) {
- StringRef Filename = MB.getBufferIdentifier();
- size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n');
- error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote");
- return;
- }
+void ScriptParser::readPhdrs() {
+ expect("{");
+ while (!Error && !consume("}")) {
+ Script->Opt.PhdrsCommands.push_back(
+ {next(), PT_NULL, false, false, UINT_MAX, nullptr});
- Vec.push_back(S.take_front(E + 1));
- S = S.substr(E + 1);
- continue;
+ PhdrsCommand &PhdrCmd = Script->Opt.PhdrsCommands.back();
+ PhdrCmd.Type = readPhdrType();
+
+ while (!Error && !consume(";")) {
+ if (consume("FILEHDR"))
+ PhdrCmd.HasFilehdr = true;
+ else if (consume("PHDRS"))
+ PhdrCmd.HasPhdrs = true;
+ else if (consume("AT"))
+ PhdrCmd.LMAExpr = readParenExpr();
+ else if (consume("FLAGS"))
+ PhdrCmd.Flags = readParenExpr()().getValue();
+ else
+ setError("unexpected header attribute: " + next());
}
+ }
+}
+
+void ScriptParser::readSearchDir() {
+ expect("(");
+ StringRef Tok = next();
+ if (!Config->Nostdlib)
+ Config->SearchPaths.push_back(unquote(Tok));
+ expect(")");
+}
+
+void ScriptParser::readSections() {
+ Script->Opt.HasSections = true;
- // Unquoted token. This is more relaxed than tokens in C-like language,
- // so that you can write "file-name.cpp" as one bare token, for example.
- size_t Pos = S.find_first_not_of(
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789_.$/\\~=+[]*?-:!<>^");
+ // -no-rosegment is used to avoid placing read only non-executable sections in
+ // their own segment. We do the same if SECTIONS command is present in linker
+ // script. See comment for computeFlags().
+ Config->SingleRoRx = true;
- // A character that cannot start a word (which is usually a
- // punctuation) forms a single character token.
- if (Pos == 0)
- Pos = 1;
- Vec.push_back(S.substr(0, Pos));
- S = S.substr(Pos);
+ expect("{");
+ while (!Error && !consume("}")) {
+ StringRef Tok = next();
+ BaseCommand *Cmd = readProvideOrAssignment(Tok);
+ if (!Cmd) {
+ if (Tok == "ASSERT")
+ Cmd = readAssert();
+ else
+ Cmd = readOutputSectionDescription(Tok);
+ }
+ Script->Opt.Commands.push_back(Cmd);
}
+}
+
+static int precedence(StringRef Op) {
+ return StringSwitch<int>(Op)
+ .Cases("*", "/", 5)
+ .Cases("+", "-", 4)
+ .Cases("<<", ">>", 3)
+ .Cases("<", "<=", ">", ">=", "==", "!=", 2)
+ .Cases("&", "|", 1)
+ .Default(-1);
+}
+
+StringMatcher ScriptParser::readFilePatterns() {
+ std::vector<StringRef> V;
+ while (!Error && !consume(")"))
+ V.push_back(next());
+ return StringMatcher(V);
+}
- Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end());
+SortSectionPolicy ScriptParser::readSortKind() {
+ if (consume("SORT") || consume("SORT_BY_NAME"))
+ return SortSectionPolicy::Name;
+ if (consume("SORT_BY_ALIGNMENT"))
+ return SortSectionPolicy::Alignment;
+ if (consume("SORT_BY_INIT_PRIORITY"))
+ return SortSectionPolicy::Priority;
+ if (consume("SORT_NONE"))
+ return SortSectionPolicy::None;
+ return SortSectionPolicy::Default;
}
-// Skip leading whitespace characters or comments.
-StringRef ScriptParserBase::skipSpace(StringRef S) {
- for (;;) {
- if (S.startswith("/*")) {
- size_t E = S.find("*/", 2);
- if (E == StringRef::npos) {
- error("unclosed comment in a linker script");
- return "";
+// Reads SECTIONS command contents in the following form:
+//
+// <contents> ::= <elem>*
+// <elem> ::= <exclude>? <glob-pattern>
+// <exclude> ::= "EXCLUDE_FILE" "(" <glob-pattern>+ ")"
+//
+// For example,
+//
+// *(.foo EXCLUDE_FILE (a.o) .bar EXCLUDE_FILE (b.o) .baz)
+//
+// is parsed as ".foo", ".bar" with "a.o", and ".baz" with "b.o".
+// The semantics of that is section .foo in any file, section .bar in
+// any file but a.o, and section .baz in any file but b.o.
+std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
+ std::vector<SectionPattern> Ret;
+ while (!Error && peek() != ")") {
+ StringMatcher ExcludeFilePat;
+ if (consume("EXCLUDE_FILE")) {
+ expect("(");
+ ExcludeFilePat = readFilePatterns();
+ }
+
+ std::vector<StringRef> V;
+ while (!Error && peek() != ")" && peek() != "EXCLUDE_FILE")
+ V.push_back(next());
+
+ if (!V.empty())
+ Ret.push_back({std::move(ExcludeFilePat), StringMatcher(V)});
+ else
+ setError("section pattern is expected");
+ }
+ return Ret;
+}
+
+// Reads contents of "SECTIONS" directive. That directive contains a
+// list of glob patterns for input sections. The grammar is as follows.
+//
+// <patterns> ::= <section-list>
+// | <sort> "(" <section-list> ")"
+// | <sort> "(" <sort> "(" <section-list> ")" ")"
+//
+// <sort> ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT"
+// | "SORT_BY_INIT_PRIORITY" | "SORT_NONE"
+//
+// <section-list> is parsed by readInputSectionsList().
+InputSectionDescription *
+ScriptParser::readInputSectionRules(StringRef FilePattern) {
+ auto *Cmd = make<InputSectionDescription>(FilePattern);
+ expect("(");
+
+ while (!Error && !consume(")")) {
+ SortSectionPolicy Outer = readSortKind();
+ SortSectionPolicy Inner = SortSectionPolicy::Default;
+ std::vector<SectionPattern> V;
+ if (Outer != SortSectionPolicy::Default) {
+ expect("(");
+ Inner = readSortKind();
+ if (Inner != SortSectionPolicy::Default) {
+ expect("(");
+ V = readInputSectionsList();
+ expect(")");
+ } else {
+ V = readInputSectionsList();
}
- S = S.substr(E + 2);
- continue;
+ expect(")");
+ } else {
+ V = readInputSectionsList();
}
- if (S.startswith("#")) {
- size_t E = S.find('\n', 1);
- if (E == StringRef::npos)
- E = S.size() - 1;
- S = S.substr(E + 1);
- continue;
+
+ for (SectionPattern &Pat : V) {
+ Pat.SortInner = Inner;
+ Pat.SortOuter = Outer;
+ }
+
+ std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns));
+ }
+ return Cmd;
+}
+
+InputSectionDescription *
+ScriptParser::readInputSectionDescription(StringRef Tok) {
+ // Input section wildcard can be surrounded by KEEP.
+ // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
+ if (Tok == "KEEP") {
+ expect("(");
+ StringRef FilePattern = next();
+ InputSectionDescription *Cmd = readInputSectionRules(FilePattern);
+ expect(")");
+ Script->Opt.KeptSections.push_back(Cmd);
+ return Cmd;
+ }
+ return readInputSectionRules(Tok);
+}
+
+void ScriptParser::readSort() {
+ expect("(");
+ expect("CONSTRUCTORS");
+ expect(")");
+}
+
+AssertCommand *ScriptParser::readAssert() {
+ return make<AssertCommand>(readAssertExpr());
+}
+
+Expr ScriptParser::readAssertExpr() {
+ expect("(");
+ Expr E = readExpr();
+ expect(",");
+ StringRef Msg = unquote(next());
+ expect(")");
+
+ return [=] {
+ if (!E().getValue())
+ error(Msg);
+ return Script->getDot();
+ };
+}
+
+// Reads a FILL(expr) command. We handle the FILL command as an
+// alias for =fillexp section attribute, which is different from
+// what GNU linkers do.
+// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
+uint32_t ScriptParser::readFill() {
+ expect("(");
+ uint32_t V = parseFill(next());
+ expect(")");
+ return V;
+}
+
+// Reads an expression and/or the special directive "(NOLOAD)" for an
+// output section definition.
+//
+// An output section name can be followed by an address expression
+// and/or by "(NOLOAD)". This grammar is not LL(1) because "(" can be
+// interpreted as either the beginning of some expression or "(NOLOAD)".
+//
+// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
+// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
+void ScriptParser::readSectionAddressType(OutputSectionCommand *Cmd) {
+ if (consume("(")) {
+ if (consume("NOLOAD")) {
+ expect(")");
+ Cmd->Noload = true;
+ return;
+ }
+ Cmd->AddrExpr = readExpr();
+ expect(")");
+ } else {
+ Cmd->AddrExpr = readExpr();
+ }
+
+ if (consume("(")) {
+ expect("NOLOAD");
+ expect(")");
+ Cmd->Noload = true;
+ }
+}
+
+OutputSectionCommand *
+ScriptParser::readOutputSectionDescription(StringRef OutSec) {
+ OutputSectionCommand *Cmd =
+ Script->createOutputSectionCommand(OutSec, getCurrentLocation());
+
+ if (peek() != ":")
+ readSectionAddressType(Cmd);
+ expect(":");
+
+ if (consume("AT"))
+ Cmd->LMAExpr = readParenExpr();
+ if (consume("ALIGN"))
+ Cmd->AlignExpr = readParenExpr();
+ if (consume("SUBALIGN"))
+ Cmd->SubalignExpr = readParenExpr();
+
+ // Parse constraints.
+ if (consume("ONLY_IF_RO"))
+ Cmd->Constraint = ConstraintKind::ReadOnly;
+ if (consume("ONLY_IF_RW"))
+ Cmd->Constraint = ConstraintKind::ReadWrite;
+ expect("{");
+
+ while (!Error && !consume("}")) {
+ StringRef Tok = next();
+ if (Tok == ";") {
+ // Empty commands are allowed. Do nothing here.
+ } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) {
+ Cmd->Commands.push_back(Assign);
+ } else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) {
+ Cmd->Commands.push_back(Data);
+ } else if (Tok == "ASSERT") {
+ Cmd->Commands.push_back(readAssert());
+ expect(";");
+ } else if (Tok == "CONSTRUCTORS") {
+ // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
+ // by name. This is for very old file formats such as ECOFF/XCOFF.
+ // For ELF, we should ignore.
+ } else if (Tok == "FILL") {
+ Cmd->Filler = readFill();
+ } else if (Tok == "SORT") {
+ readSort();
+ } else if (peek() == "(") {
+ Cmd->Commands.push_back(readInputSectionDescription(Tok));
+ } else {
+ setError("unknown command " + Tok);
}
- size_t Size = S.size();
- S = S.ltrim();
- if (S.size() == Size)
- return S;
}
+
+ if (consume(">"))
+ Cmd->MemoryRegionName = next();
+
+ Cmd->Phdrs = readOutputSectionPhdrs();
+
+ if (consume("="))
+ Cmd->Filler = parseFill(next());
+ else if (peek().startswith("="))
+ Cmd->Filler = parseFill(next().drop_front());
+
+ // Consume optional comma following output section command.
+ consume(",");
+
+ return Cmd;
+}
+
+// Parses a given string as a octal/decimal/hexadecimal number and
+// returns it as a big-endian number. Used for `=<fillexp>`.
+// https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html
+//
+// When reading a hexstring, ld.bfd handles it as a blob of arbitrary
+// size, while ld.gold always handles it as a 32-bit big-endian number.
+// We are compatible with ld.gold because it's easier to implement.
+uint32_t ScriptParser::parseFill(StringRef Tok) {
+ uint32_t V = 0;
+ if (!to_integer(Tok, V))
+ setError("invalid filler expression: " + Tok);
+
+ uint32_t Buf;
+ write32be(&Buf, V);
+ return Buf;
+}
+
+SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
+ expect("(");
+ SymbolAssignment *Cmd = readAssignment(next());
+ Cmd->Provide = Provide;
+ Cmd->Hidden = Hidden;
+ expect(")");
+ expect(";");
+ return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
+ SymbolAssignment *Cmd = nullptr;
+ if (peek() == "=" || peek() == "+=") {
+ Cmd = readAssignment(Tok);
+ expect(";");
+ } else if (Tok == "PROVIDE") {
+ Cmd = readProvideHidden(true, false);
+ } else if (Tok == "HIDDEN") {
+ Cmd = readProvideHidden(false, true);
+ } else if (Tok == "PROVIDE_HIDDEN") {
+ Cmd = readProvideHidden(true, true);
+ }
+ return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
+ StringRef Op = next();
+ assert(Op == "=" || Op == "+=");
+ Expr E = readExpr();
+ if (Op == "+=") {
+ std::string Loc = getCurrentLocation();
+ E = [=] { return add(Script->getSymbolValue(Loc, Name), E()); };
+ }
+ return make<SymbolAssignment>(Name, E, getCurrentLocation());
+}
+
+// This is an operator-precedence parser to parse a linker
+// script expression.
+Expr ScriptParser::readExpr() {
+ // Our lexer is context-aware. Set the in-expression bit so that
+ // they apply different tokenization rules.
+ bool Orig = InExpr;
+ InExpr = true;
+ Expr E = readExpr1(readPrimary(), 0);
+ InExpr = Orig;
+ return E;
+}
+
+static Expr combine(StringRef Op, Expr L, Expr R) {
+ if (Op == "+")
+ return [=] { return add(L(), R()); };
+ if (Op == "-")
+ return [=] { return sub(L(), R()); };
+ if (Op == "*")
+ return [=] { return mul(L(), R()); };
+ if (Op == "/")
+ return [=] { return div(L(), R()); };
+ if (Op == "<<")
+ return [=] { return L().getValue() << R().getValue(); };
+ if (Op == ">>")
+ return [=] { return L().getValue() >> R().getValue(); };
+ if (Op == "<")
+ return [=] { return L().getValue() < R().getValue(); };
+ if (Op == ">")
+ return [=] { return L().getValue() > R().getValue(); };
+ if (Op == ">=")
+ return [=] { return L().getValue() >= R().getValue(); };
+ if (Op == "<=")
+ return [=] { return L().getValue() <= R().getValue(); };
+ if (Op == "==")
+ return [=] { return L().getValue() == R().getValue(); };
+ if (Op == "!=")
+ return [=] { return L().getValue() != R().getValue(); };
+ if (Op == "&")
+ return [=] { return bitAnd(L(), R()); };
+ if (Op == "|")
+ return [=] { return bitOr(L(), R()); };
+ llvm_unreachable("invalid operator");
+}
+
+// This is a part of the operator-precedence parser. This function
+// assumes that the remaining token stream starts with an operator.
+Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) {
+ while (!atEOF() && !Error) {
+ // Read an operator and an expression.
+ if (consume("?"))
+ return readTernary(Lhs);
+ StringRef Op1 = peek();
+ if (precedence(Op1) < MinPrec)
+ break;
+ skip();
+ Expr Rhs = readPrimary();
+
+ // Evaluate the remaining part of the expression first if the
+ // next operator has greater precedence than the previous one.
+ // For example, if we have read "+" and "3", and if the next
+ // operator is "*", then we'll evaluate 3 * ... part first.
+ while (!atEOF()) {
+ StringRef Op2 = peek();
+ if (precedence(Op2) <= precedence(Op1))
+ break;
+ Rhs = readExpr1(Rhs, precedence(Op2));
+ }
+
+ Lhs = combine(Op1, Lhs, Rhs);
+ }
+ return Lhs;
+}
+
+uint64_t static getConstant(StringRef S) {
+ if (S == "COMMONPAGESIZE")
+ return Target->PageSize;
+ if (S == "MAXPAGESIZE")
+ return Config->MaxPageSize;
+ error("unknown constant: " + S);
+ return 0;
}
-// An erroneous token is handled as if it were the last token before EOF.
-bool ScriptParserBase::atEOF() { return Error || Tokens.size() == Pos; }
+// Parses Tok as an integer. It recognizes hexadecimal (prefixed with
+// "0x" or suffixed with "H") and decimal numbers. Decimal numbers may
+// have "K" (Ki) or "M" (Mi) suffixes.
+static Optional<uint64_t> parseInt(StringRef Tok) {
+ // Negative number
+ if (Tok.startswith("-")) {
+ if (Optional<uint64_t> Val = parseInt(Tok.substr(1)))
+ return -*Val;
+ return None;
+ }
+
+ // Hexadecimal
+ uint64_t Val;
+ if (Tok.startswith_lower("0x") && to_integer(Tok.substr(2), Val, 16))
+ return Val;
+ if (Tok.endswith_lower("H") && to_integer(Tok.drop_back(), Val, 16))
+ return Val;
-StringRef ScriptParserBase::next() {
- if (Error)
- return "";
- if (atEOF()) {
- setError("unexpected EOF");
- return "";
+ // Decimal
+ if (Tok.endswith_lower("K")) {
+ if (!to_integer(Tok.drop_back(), Val, 10))
+ return None;
+ return Val * 1024;
+ }
+ if (Tok.endswith_lower("M")) {
+ if (!to_integer(Tok.drop_back(), Val, 10))
+ return None;
+ return Val * 1024 * 1024;
}
- return Tokens[Pos++];
+ if (!to_integer(Tok, Val, 10))
+ return None;
+ return Val;
}
-StringRef ScriptParserBase::peek() {
+BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) {
+ int Size = StringSwitch<int>(Tok)
+ .Case("BYTE", 1)
+ .Case("SHORT", 2)
+ .Case("LONG", 4)
+ .Case("QUAD", 8)
+ .Default(-1);
+ if (Size == -1)
+ return nullptr;
+
+ return make<BytesDataCommand>(readParenExpr(), Size);
+}
+
+StringRef ScriptParser::readParenLiteral() {
+ expect("(");
StringRef Tok = next();
- if (Error)
- return "";
- --Pos;
+ expect(")");
return Tok;
}
-bool ScriptParserBase::consume(StringRef Tok) {
- if (peek() == Tok) {
+OutputSection *ScriptParser::checkSection(OutputSectionCommand *Cmd,
+ StringRef Location) {
+ if (Cmd->Location.empty() && Script->ErrorOnMissingSection)
+ error(Location + ": undefined section " + Cmd->Name);
+ if (Cmd->Sec)
+ return Cmd->Sec;
+ static OutputSection Dummy("", 0, 0);
+ return &Dummy;
+}
+
+Expr ScriptParser::readPrimary() {
+ if (peek() == "(")
+ return readParenExpr();
+
+ if (consume("~")) {
+ Expr E = readPrimary();
+ return [=] { return ~E().getValue(); };
+ }
+ if (consume("-")) {
+ Expr E = readPrimary();
+ return [=] { return -E().getValue(); };
+ }
+
+ StringRef Tok = next();
+ std::string Location = getCurrentLocation();
+
+ // Built-in functions are parsed here.
+ // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
+ if (Tok == "ABSOLUTE") {
+ Expr Inner = readParenExpr();
+ return [=] {
+ ExprValue I = Inner();
+ I.ForceAbsolute = true;
+ return I;
+ };
+ }
+ if (Tok == "ADDR") {
+ StringRef Name = readParenLiteral();
+ OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
+ return [=]() -> ExprValue {
+ return {checkSection(Cmd, Location), 0, Location};
+ };
+ }
+ if (Tok == "ALIGN") {
+ expect("(");
+ Expr E = readExpr();
+ if (consume(")"))
+ return [=] { return alignTo(Script->getDot(), E().getValue()); };
+ expect(",");
+ Expr E2 = readExpr();
+ expect(")");
+ return [=] {
+ ExprValue V = E();
+ V.Alignment = E2().getValue();
+ return V;
+ };
+ }
+ if (Tok == "ALIGNOF") {
+ StringRef Name = readParenLiteral();
+ OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
+ return [=] { return checkSection(Cmd, Location)->Alignment; };
+ }
+ if (Tok == "ASSERT")
+ return readAssertExpr();
+ if (Tok == "CONSTANT") {
+ StringRef Name = readParenLiteral();
+ return [=] { return getConstant(Name); };
+ }
+ if (Tok == "DATA_SEGMENT_ALIGN") {
+ expect("(");
+ Expr E = readExpr();
+ expect(",");
+ readExpr();
+ expect(")");
+ return [=] { return alignTo(Script->getDot(), E().getValue()); };
+ }
+ if (Tok == "DATA_SEGMENT_END") {
+ expect("(");
+ expect(".");
+ expect(")");
+ return [] { return Script->getDot(); };
+ }
+ if (Tok == "DATA_SEGMENT_RELRO_END") {
+ // GNU linkers implements more complicated logic to handle
+ // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and
+ // just align to the next page boundary for simplicity.
+ expect("(");
+ readExpr();
+ expect(",");
+ readExpr();
+ expect(")");
+ return [] { return alignTo(Script->getDot(), Target->PageSize); };
+ }
+ if (Tok == "DEFINED") {
+ StringRef Name = readParenLiteral();
+ return [=] { return Script->isDefined(Name) ? 1 : 0; };
+ }
+ if (Tok == "LENGTH") {
+ StringRef Name = readParenLiteral();
+ if (Script->Opt.MemoryRegions.count(Name) == 0)
+ setError("memory region not defined: " + Name);
+ return [=] { return Script->Opt.MemoryRegions[Name].Length; };
+ }
+ if (Tok == "LOADADDR") {
+ StringRef Name = readParenLiteral();
+ OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
+ return [=] { return checkSection(Cmd, Location)->getLMA(); };
+ }
+ if (Tok == "ORIGIN") {
+ StringRef Name = readParenLiteral();
+ if (Script->Opt.MemoryRegions.count(Name) == 0)
+ setError("memory region not defined: " + Name);
+ return [=] { return Script->Opt.MemoryRegions[Name].Origin; };
+ }
+ if (Tok == "SEGMENT_START") {
+ expect("(");
skip();
- return true;
+ expect(",");
+ Expr E = readExpr();
+ expect(")");
+ return [=] { return E(); };
}
- return false;
+ if (Tok == "SIZEOF") {
+ StringRef Name = readParenLiteral();
+ OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name);
+ // Linker script does not create an output section if its content is empty.
+ // We want to allow SIZEOF(.foo) where .foo is a section which happened to
+ // be empty.
+ return [=] { return Cmd->Sec ? Cmd->Sec->Size : 0; };
+ }
+ if (Tok == "SIZEOF_HEADERS")
+ return [=] { return elf::getHeaderSize(); };
+
+ // Tok is the dot.
+ if (Tok == ".")
+ return [=] { return Script->getSymbolValue(Location, Tok); };
+
+ // Tok is a literal number.
+ if (Optional<uint64_t> Val = parseInt(Tok))
+ return [=] { return *Val; };
+
+ // Tok is a symbol name.
+ if (!isValidCIdentifier(Tok))
+ setError("malformed number: " + Tok);
+ Script->Opt.ReferencedSymbols.push_back(Tok);
+ return [=] { return Script->getSymbolValue(Location, Tok); };
}
-void ScriptParserBase::skip() { (void)next(); }
+Expr ScriptParser::readTernary(Expr Cond) {
+ Expr L = readExpr();
+ expect(":");
+ Expr R = readExpr();
+ return [=] { return Cond().getValue() ? L() : R(); };
+}
-void ScriptParserBase::expect(StringRef Expect) {
- if (Error)
- return;
+Expr ScriptParser::readParenExpr() {
+ expect("(");
+ Expr E = readExpr();
+ expect(")");
+ return E;
+}
+
+std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() {
+ std::vector<StringRef> Phdrs;
+ while (!Error && peek().startswith(":")) {
+ StringRef Tok = next();
+ Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1));
+ }
+ return Phdrs;
+}
+
+// Read a program header type name. The next token must be a
+// name of a program header type or a constant (e.g. "0x3").
+unsigned ScriptParser::readPhdrType() {
StringRef Tok = next();
- if (Tok != Expect)
- setError(Expect + " expected, but got " + Tok);
+ if (Optional<uint64_t> Val = parseInt(Tok))
+ return *Val;
+
+ unsigned Ret = StringSwitch<unsigned>(Tok)
+ .Case("PT_NULL", PT_NULL)
+ .Case("PT_LOAD", PT_LOAD)
+ .Case("PT_DYNAMIC", PT_DYNAMIC)
+ .Case("PT_INTERP", PT_INTERP)
+ .Case("PT_NOTE", PT_NOTE)
+ .Case("PT_SHLIB", PT_SHLIB)
+ .Case("PT_PHDR", PT_PHDR)
+ .Case("PT_TLS", PT_TLS)
+ .Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
+ .Case("PT_GNU_STACK", PT_GNU_STACK)
+ .Case("PT_GNU_RELRO", PT_GNU_RELRO)
+ .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
+ .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
+ .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
+ .Default(-1);
+
+ if (Ret == (unsigned)-1) {
+ setError("invalid program header type: " + Tok);
+ return PT_NULL;
+ }
+ return Ret;
}
-// Returns true if S encloses T.
-static bool encloses(StringRef S, StringRef T) {
- return S.bytes_begin() <= T.bytes_begin() && T.bytes_end() <= S.bytes_end();
+// Reads an anonymous version declaration.
+void ScriptParser::readAnonymousDeclaration() {
+ std::vector<SymbolVersion> Locals;
+ std::vector<SymbolVersion> Globals;
+ std::tie(Locals, Globals) = readSymbols();
+
+ for (SymbolVersion V : Locals) {
+ if (V.Name == "*")
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ else
+ Config->VersionScriptLocals.push_back(V);
+ }
+
+ for (SymbolVersion V : Globals)
+ Config->VersionScriptGlobals.push_back(V);
+
+ expect(";");
}
-MemoryBufferRef ScriptParserBase::getCurrentMB() {
- // Find input buffer containing the current token.
- assert(!MBs.empty());
- if (!Pos)
- return MBs[0];
+// Reads a non-anonymous version definition,
+// e.g. "VerStr { global: foo; bar; local: *; };".
+void ScriptParser::readVersionDeclaration(StringRef VerStr) {
+ // Read a symbol list.
+ std::vector<SymbolVersion> Locals;
+ std::vector<SymbolVersion> Globals;
+ std::tie(Locals, Globals) = readSymbols();
+
+ for (SymbolVersion V : Locals) {
+ if (V.Name == "*")
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ else
+ Config->VersionScriptLocals.push_back(V);
+ }
+
+ // Create a new version definition and add that to the global symbols.
+ VersionDefinition Ver;
+ Ver.Name = VerStr;
+ Ver.Globals = Globals;
+
+ // User-defined version number starts from 2 because 0 and 1 are
+ // reserved for VER_NDX_LOCAL and VER_NDX_GLOBAL, respectively.
+ Ver.Id = Config->VersionDefinitions.size() + 2;
+ Config->VersionDefinitions.push_back(Ver);
+
+ // Each version may have a parent version. For example, "Ver2"
+ // defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1"
+ // as a parent. This version hierarchy is, probably against your
+ // instinct, purely for hint; the runtime doesn't care about it
+ // at all. In LLD, we simply ignore it.
+ if (peek() != ";")
+ skip();
+ expect(";");
+}
+
+static bool hasWildcard(StringRef S) {
+ return S.find_first_of("?*[") != StringRef::npos;
+}
+
+// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };".
+std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>>
+ScriptParser::readSymbols() {
+ std::vector<SymbolVersion> Locals;
+ std::vector<SymbolVersion> Globals;
+ std::vector<SymbolVersion> *V = &Globals;
+
+ while (!Error) {
+ if (consume("}"))
+ break;
+ if (consumeLabel("local")) {
+ V = &Locals;
+ continue;
+ }
+ if (consumeLabel("global")) {
+ V = &Globals;
+ continue;
+ }
+
+ if (consume("extern")) {
+ std::vector<SymbolVersion> Ext = readVersionExtern();
+ V->insert(V->end(), Ext.begin(), Ext.end());
+ } else {
+ StringRef Tok = next();
+ V->push_back({unquote(Tok), false, hasWildcard(Tok)});
+ }
+ expect(";");
+ }
+ return {Locals, Globals};
+}
+
+// Reads an "extern C++" directive, e.g.,
+// "extern "C++" { ns::*; "f(int, double)"; };"
+std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
+ StringRef Tok = next();
+ bool IsCXX = Tok == "\"C++\"";
+ if (!IsCXX && Tok != "\"C\"")
+ setError("Unknown language");
+ expect("{");
+
+ std::vector<SymbolVersion> Ret;
+ while (!Error && peek() != "}") {
+ StringRef Tok = next();
+ bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
+ Ret.push_back({unquote(Tok), IsCXX, HasWildcard});
+ expect(";");
+ }
+
+ expect("}");
+ return Ret;
+}
+
+uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2,
+ StringRef S3) {
+ if (!consume(S1) && !consume(S2) && !consume(S3)) {
+ setError("expected one of: " + S1 + ", " + S2 + ", or " + S3);
+ return 0;
+ }
+ expect("=");
+ return readExpr()().getValue();
+}
+
+// Parse the MEMORY command as specified in:
+// https://sourceware.org/binutils/docs/ld/MEMORY.html
+//
+// MEMORY { name [(attr)] : ORIGIN = origin, LENGTH = len ... }
+void ScriptParser::readMemory() {
+ expect("{");
+ while (!Error && !consume("}")) {
+ StringRef Name = next();
+
+ uint32_t Flags = 0;
+ uint32_t NegFlags = 0;
+ if (consume("(")) {
+ std::tie(Flags, NegFlags) = readMemoryAttributes();
+ expect(")");
+ }
+ expect(":");
+
+ uint64_t Origin = readMemoryAssignment("ORIGIN", "org", "o");
+ expect(",");
+ uint64_t Length = readMemoryAssignment("LENGTH", "len", "l");
+
+ // Add the memory region to the region map (if it doesn't already exist).
+ auto It = Script->Opt.MemoryRegions.find(Name);
+ if (It != Script->Opt.MemoryRegions.end())
+ setError("region '" + Name + "' already defined");
+ else
+ Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, Flags, NegFlags};
+ }
+}
+
+// This function parses the attributes used to match against section
+// flags when placing output sections in a memory region. These flags
+// are only used when an explicit memory region name is not used.
+std::pair<uint32_t, uint32_t> ScriptParser::readMemoryAttributes() {
+ uint32_t Flags = 0;
+ uint32_t NegFlags = 0;
+ bool Invert = false;
+
+ for (char C : next().lower()) {
+ uint32_t Flag = 0;
+ if (C == '!')
+ Invert = !Invert;
+ else if (C == 'w')
+ Flag = SHF_WRITE;
+ else if (C == 'x')
+ Flag = SHF_EXECINSTR;
+ else if (C == 'a')
+ Flag = SHF_ALLOC;
+ else if (C != 'r')
+ setError("invalid memory region attribute");
+
+ if (Invert)
+ NegFlags |= Flag;
+ else
+ Flags |= Flag;
+ }
+ return {Flags, NegFlags};
+}
+
+void elf::readLinkerScript(MemoryBufferRef MB) {
+ ScriptParser(MB).readLinkerScript();
+}
+
+void elf::readVersionScript(MemoryBufferRef MB) {
+ ScriptParser(MB).readVersionScript();
+}
- for (MemoryBufferRef MB : MBs)
- if (encloses(MB.getBuffer(), Tokens[Pos - 1]))
- return MB;
- llvm_unreachable("getCurrentMB: failed to find a token");
+void elf::readDynamicList(MemoryBufferRef MB) {
+ ScriptParser(MB).readDynamicList();
}
diff --git a/contrib/llvm/tools/lld/ELF/ScriptParser.h b/contrib/llvm/tools/lld/ELF/ScriptParser.h
index 264c497..02f3a2b 100644
--- a/contrib/llvm/tools/lld/ELF/ScriptParser.h
+++ b/contrib/llvm/tools/lld/ELF/ScriptParser.h
@@ -11,41 +11,19 @@
#define LLD_ELF_SCRIPT_PARSER_H
#include "lld/Core/LLVM.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
-#include <utility>
-#include <vector>
namespace lld {
namespace elf {
-class ScriptParserBase {
-public:
- explicit ScriptParserBase(MemoryBufferRef MB);
-
- void setError(const Twine &Msg);
- void tokenize(MemoryBufferRef MB);
- static StringRef skipSpace(StringRef S);
- bool atEOF();
- StringRef next();
- StringRef peek();
- void skip();
- bool consume(StringRef Tok);
- void expect(StringRef Expect);
- std::string getCurrentLocation();
-
- std::vector<MemoryBufferRef> MBs;
- std::vector<StringRef> Tokens;
- size_t Pos = 0;
- bool Error = false;
-
-private:
- StringRef getLine();
- size_t getLineNumber();
- size_t getColumnNumber();
-
- MemoryBufferRef getCurrentMB();
-};
+// Parses a linker script. Calling this function updates
+// Config and ScriptConfig.
+void readLinkerScript(MemoryBufferRef MB);
+
+// Parses a version script.
+void readVersionScript(MemoryBufferRef MB);
+
+void readDynamicList(MemoryBufferRef MB);
} // namespace elf
} // namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/Strings.cpp b/contrib/llvm/tools/lld/ELF/Strings.cpp
index ec3d1f1..bca8638 100644
--- a/contrib/llvm/tools/lld/ELF/Strings.cpp
+++ b/contrib/llvm/tools/lld/ELF/Strings.cpp
@@ -38,29 +38,6 @@ bool StringMatcher::match(StringRef S) const {
return false;
}
-// If an input string is in the form of "foo.N" where N is a number,
-// return N. Otherwise, returns 65536, which is one greater than the
-// lowest priority.
-int elf::getPriority(StringRef S) {
- size_t Pos = S.rfind('.');
- if (Pos == StringRef::npos)
- return 65536;
- int V;
- if (S.substr(Pos + 1).getAsInteger(10, V))
- return 65536;
- return V;
-}
-
-bool elf::hasWildcard(StringRef S) {
- return S.find_first_of("?*[") != StringRef::npos;
-}
-
-StringRef elf::unquote(StringRef S) {
- if (!S.startswith("\""))
- return S;
- return S.substr(1, S.size() - 2);
-}
-
// Converts a hex string (e.g. "deadbeef") to a vector.
std::vector<uint8_t> elf::parseHex(StringRef S) {
std::vector<uint8_t> Hex;
@@ -68,7 +45,7 @@ std::vector<uint8_t> elf::parseHex(StringRef S) {
StringRef B = S.substr(0, 2);
S = S.substr(2);
uint8_t H;
- if (B.getAsInteger(16, H)) {
+ if (!to_integer(B, H, 16)) {
error("not a hexadecimal value: " + B);
return {};
}
@@ -91,9 +68,9 @@ bool elf::isValidCIdentifier(StringRef S) {
// Returns the demangled C++ symbol name for Name.
Optional<std::string> elf::demangle(StringRef Name) {
- // __cxa_demangle can be used to demangle strings other than symbol
+ // itaniumDemangle can be used to demangle strings other than symbol
// names which do not necessarily start with "_Z". Name can be
- // either a C or C++ symbol. Don't call __cxa_demangle if the name
+ // either a C or C++ symbol. Don't call itaniumDemangle if the name
// does not look like a C++ symbol name to avoid getting unexpected
// result for a C symbol that happens to match a mangled type name.
if (!Name.startswith("_Z"))
diff --git a/contrib/llvm/tools/lld/ELF/Strings.h b/contrib/llvm/tools/lld/ELF/Strings.h
index 934b642..68ccafa 100644
--- a/contrib/llvm/tools/lld/ELF/Strings.h
+++ b/contrib/llvm/tools/lld/ELF/Strings.h
@@ -21,11 +21,8 @@
namespace lld {
namespace elf {
-int getPriority(StringRef S);
-bool hasWildcard(StringRef S);
std::vector<uint8_t> parseHex(StringRef S);
bool isValidCIdentifier(StringRef S);
-StringRef unquote(StringRef S);
// This is a lazy version of StringRef. String size is computed lazily
// when it is needed. It is more efficient than StringRef to instantiate
@@ -73,10 +70,10 @@ private:
// name, it returns Optional::None.
llvm::Optional<std::string> demangle(StringRef Name);
-inline StringRef toStringRef(ArrayRef<uint8_t> Arr) {
- return {(const char *)Arr.data(), Arr.size()};
-}
-}
+inline ArrayRef<uint8_t> toArrayRef(StringRef S) {
+ return {(const uint8_t *)S.data(), S.size()};
}
+} // namespace elf
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
index ce25793..0c93240 100644
--- a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
+++ b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp
@@ -52,6 +52,9 @@ template <class ELFT> static bool isCompatible(InputFile *F) {
// Add symbols in File to the symbol table.
template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
+ if (!Config->FirstElf && isa<ELFFileBase<ELFT>>(File))
+ Config->FirstElf = File;
+
if (!isCompatible<ELFT>(File))
return;
@@ -75,13 +78,13 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
}
if (Config->Trace)
- outs() << toString(File) << "\n";
+ message(toString(File));
// .so file
if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
// DSOs are uniquified not by filename but by soname.
F->parseSoName();
- if (ErrorCount || !SoNames.insert(F->getSoName()).second)
+ if (ErrorCount || !SoNames.insert(F->SoName).second)
return;
SharedFiles.push_back(F);
F->parseRest();
@@ -115,7 +118,7 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
// Compile bitcode files and replace bitcode symbols.
LTO.reset(new BitcodeCompiler);
for (BitcodeFile *F : BitcodeFiles)
- LTO->add<ELFT>(*F);
+ LTO->add(*F);
for (InputFile *File : LTO->compile()) {
ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File);
@@ -126,19 +129,19 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
}
template <class ELFT>
-DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name,
- uint8_t Visibility,
- uint8_t Binding) {
+DefinedRegular *SymbolTable<ELFT>::addAbsolute(StringRef Name,
+ uint8_t Visibility,
+ uint8_t Binding) {
Symbol *Sym =
addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr);
- return cast<DefinedRegular<ELFT>>(Sym->body());
+ return cast<DefinedRegular>(Sym->body());
}
// Add Name as an "ignored" symbol. An ignored symbol is a regular
// linker-synthesized defined symbol, but is only defined if needed.
template <class ELFT>
-DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name,
- uint8_t Visibility) {
+DefinedRegular *SymbolTable<ELFT>::addIgnored(StringRef Name,
+ uint8_t Visibility) {
SymbolBody *S = find(Name);
if (!S || S->isInCurrentDSO())
return nullptr;
@@ -153,7 +156,7 @@ template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) {
// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
// Used to implement --wrap.
-template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
+template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) {
SymbolBody *B = find(Name);
if (!B)
return;
@@ -161,11 +164,40 @@ template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) {
Symbol *Real = addUndefined(Saver.save("__real_" + Name));
Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
- // We rename symbols by replacing the old symbol's SymbolBody with the new
- // symbol's SymbolBody. This causes all SymbolBody pointers referring to the
- // old symbol to instead refer to the new symbol.
- memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body));
- memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body));
+ // Tell LTO not to eliminate this symbol
+ Wrap->IsUsedInRegularObj = true;
+
+ Config->RenamedSymbols[Real] = {Sym, Real->Binding};
+ Config->RenamedSymbols[Sym] = {Wrap, Sym->Binding};
+}
+
+// Creates alias for symbol. Used to implement --defsym=ALIAS=SYM.
+template <class ELFT>
+void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias, StringRef Name) {
+ SymbolBody *B = find(Name);
+ if (!B) {
+ error("-defsym: undefined symbol: " + Name);
+ return;
+ }
+ Symbol *Sym = B->symbol();
+ Symbol *AliasSym = addUndefined(Alias);
+
+ // Tell LTO not to eliminate this symbol
+ Sym->IsUsedInRegularObj = true;
+ Config->RenamedSymbols[AliasSym] = {Sym, AliasSym->Binding};
+}
+
+// Apply symbol renames created by -wrap and -defsym. The renames are created
+// before LTO in addSymbolWrap() and addSymbolAlias() to have a chance to inform
+// LTO (if LTO is running) not to include these symbols in IPO. Now that the
+// symbols are finalized, we can perform the replacement.
+template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() {
+ for (auto &KV : Config->RenamedSymbols) {
+ Symbol *Dst = KV.first;
+ Symbol *Src = KV.second.Target;
+ Dst->body()->copy(Src->body());
+ Dst->Binding = KV.second.OriginalBinding;
+ }
}
static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
@@ -179,6 +211,12 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
// Find an existing symbol or create and insert a new one.
template <class ELFT>
std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
+ // <name>@@<version> means the symbol is the default version. In that
+ // case <name>@@<version> will be used to resolve references to <name>.
+ size_t Pos = Name.find("@@");
+ if (Pos != StringRef::npos)
+ Name = Name.take_front(Pos);
+
auto P = Symtab.insert(
{CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)});
SymIndex &V = P.first->second;
@@ -191,7 +229,7 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
Symbol *Sym;
if (IsNew) {
- Sym = new (BAlloc) Symbol;
+ Sym = make<Symbol>();
Sym->InVersionScript = false;
Sym->Binding = STB_WEAK;
Sym->Visibility = STV_DEFAULT;
@@ -206,13 +244,6 @@ std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
return {Sym, IsNew};
}
-// Construct a string in the form of "Sym in File1 and File2".
-// Used to construct an error message.
-static std::string conflictMsg(SymbolBody *Existing, InputFile *NewFile) {
- return "'" + toString(*Existing) + "' in " + toString(Existing->File) +
- " and " + toString(NewFile);
-}
-
// Find an existing symbol or create and insert a new one, then apply the given
// attributes.
template <class ELFT>
@@ -226,13 +257,19 @@ SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
// Merge in the new symbol's visibility.
S->Visibility = getMinVisibility(S->Visibility, Visibility);
+
if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic))
S->ExportDynamic = true;
+
if (IsUsedInRegularObj)
S->IsUsedInRegularObj = true;
+
if (!WasInserted && S->body()->Type != SymbolBody::UnknownType &&
- ((Type == STT_TLS) != S->body()->isTls()))
- error("TLS attribute mismatch for symbol " + conflictMsg(S->body(), File));
+ ((Type == STT_TLS) != S->body()->isTls())) {
+ error("TLS attribute mismatch: " + toString(*S->body()) +
+ "\n>>> defined in " + toString(S->body()->File) +
+ "\n>>> defined in " + toString(File));
+ }
return {S, WasInserted};
}
@@ -252,18 +289,23 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
InputFile *File) {
Symbol *S;
bool WasInserted;
+ uint8_t Visibility = getVisibility(StOther);
std::tie(S, WasInserted) =
- insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, File);
- if (WasInserted) {
+ insert(Name, Type, Visibility, CanOmitFromDynSym, File);
+ // An undefined symbol with non default visibility must be satisfied
+ // in the same DSO.
+ if (WasInserted ||
+ (isa<SharedSymbol>(S->body()) && Visibility != STV_DEFAULT)) {
S->Binding = Binding;
- replaceBody<Undefined<ELFT>>(S, Name, IsLocal, StOther, Type, File);
+ replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File);
return S;
}
if (Binding != STB_WEAK) {
- if (S->body()->isShared() || S->body()->isLazy())
+ SymbolBody *B = S->body();
+ if (B->isShared() || B->isLazy() || B->isUndefined())
S->Binding = Binding;
- if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(S->body()))
- SS->file()->IsUsed = true;
+ if (auto *SS = dyn_cast<SharedSymbol>(B))
+ cast<SharedFile<ELFT>>(SS->File)->IsUsed = true;
}
if (auto *L = dyn_cast<Lazy>(S->body())) {
// An undefined weak will not fetch archive members, but we have to remember
@@ -276,15 +318,36 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
return S;
}
+// Using .symver foo,foo@@VER unfortunately creates two symbols: foo and
+// foo@@VER. We want to effectively ignore foo, so give precedence to
+// foo@@VER.
+// FIXME: If users can transition to using
+// .symver foo,foo@@@VER
+// we can delete this hack.
+static int compareVersion(Symbol *S, StringRef Name) {
+ if (Name.find("@@") != StringRef::npos &&
+ S->body()->getName().find("@@") == StringRef::npos)
+ return 1;
+ if (Name.find("@@") == StringRef::npos &&
+ S->body()->getName().find("@@") != StringRef::npos)
+ return -1;
+ return 0;
+}
+
// We have a new defined symbol with the specified binding. Return 1 if the new
// symbol should win, -1 if the new symbol should lose, or 0 if both symbols are
// strong defined symbols.
-static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
+static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding,
+ StringRef Name) {
if (WasInserted)
return 1;
SymbolBody *Body = S->body();
- if (Body->isLazy() || !Body->isInCurrentDSO())
+ if (!Body->isInCurrentDSO())
return 1;
+
+ if (int R = compareVersion(S, Name))
+ return R;
+
if (Binding == STB_WEAK)
return -1;
if (S->isWeak())
@@ -297,8 +360,9 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) {
// is a conflict. If the new symbol wins, also update the binding.
template <typename ELFT>
static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
- bool IsAbsolute, typename ELFT::uint Value) {
- if (int Cmp = compareDefined(S, WasInserted, Binding)) {
+ bool IsAbsolute, typename ELFT::uint Value,
+ StringRef Name) {
+ if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) {
if (Cmp > 0)
S->Binding = Binding;
return Cmp;
@@ -309,7 +373,7 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
if (Config->WarnCommon)
warn("common " + S->body()->getName() + " is overridden");
return 1;
- } else if (auto *R = dyn_cast<DefinedRegular<ELFT>>(B)) {
+ } else if (auto *R = dyn_cast<DefinedRegular>(B)) {
if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute &&
R->Value == Value)
return -1;
@@ -319,14 +383,14 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
template <class ELFT>
Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
- uint64_t Alignment, uint8_t Binding,
+ uint32_t Alignment, uint8_t Binding,
uint8_t StOther, uint8_t Type,
InputFile *File) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
- int Cmp = compareDefined(S, WasInserted, Binding);
+ int Cmp = compareDefined(S, WasInserted, Binding, N);
if (Cmp > 0) {
S->Binding = Binding;
replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File);
@@ -349,73 +413,72 @@ Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
return S;
}
-static void print(const Twine &Msg) {
+static void warnOrError(const Twine &Msg) {
if (Config->AllowMultipleDefinition)
warn(Msg);
else
error(Msg);
}
-static void reportDuplicate(SymbolBody *Existing, InputFile *NewFile) {
- print("duplicate symbol " + conflictMsg(Existing, NewFile));
+static void reportDuplicate(SymbolBody *Sym, InputFile *NewFile) {
+ warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+ toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
}
template <class ELFT>
-static void reportDuplicate(SymbolBody *Existing,
- InputSectionBase<ELFT> *ErrSec,
+static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec,
typename ELFT::uint ErrOffset) {
- DefinedRegular<ELFT> *D = dyn_cast<DefinedRegular<ELFT>>(Existing);
+ DefinedRegular *D = dyn_cast<DefinedRegular>(Sym);
if (!D || !D->Section || !ErrSec) {
- reportDuplicate(Existing, ErrSec ? ErrSec->getFile() : nullptr);
+ reportDuplicate(Sym, ErrSec ? ErrSec->getFile<ELFT>() : nullptr);
return;
}
- std::string OldLoc = D->Section->getLocation(D->Value);
- std::string NewLoc = ErrSec->getLocation(ErrOffset);
-
- print(NewLoc + ": duplicate symbol '" + toString(*Existing) + "'");
- print(OldLoc + ": previous definition was here");
+ // Construct and print an error message in the form of:
+ //
+ // ld.lld: error: duplicate symbol: foo
+ // >>> defined at bar.c:30
+ // >>> bar.o (/home/alice/src/bar.o)
+ // >>> defined at baz.c:563
+ // >>> baz.o in archive libbaz.a
+ auto *Sec1 = cast<InputSectionBase>(D->Section);
+ std::string Src1 = Sec1->getSrcMsg<ELFT>(D->Value);
+ std::string Obj1 = Sec1->getObjMsg<ELFT>(D->Value);
+ std::string Src2 = ErrSec->getSrcMsg<ELFT>(ErrOffset);
+ std::string Obj2 = ErrSec->getObjMsg<ELFT>(ErrOffset);
+
+ std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at ";
+ if (!Src1.empty())
+ Msg += Src1 + "\n>>> ";
+ Msg += Obj1 + "\n>>> defined at ";
+ if (!Src2.empty())
+ Msg += Src2 + "\n>>> ";
+ Msg += Obj2;
+ warnOrError(Msg);
}
template <typename ELFT>
Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t StOther,
- uint8_t Type, uintX_t Value, uintX_t Size,
- uint8_t Binding,
- InputSectionBase<ELFT> *Section,
- InputFile *File) {
+ uint8_t Type, uint64_t Value,
+ uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
- Section == nullptr, Value);
+ Section == nullptr, Value, Name);
if (Cmp > 0)
- replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type,
- Value, Size, Section, File);
+ replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type,
+ Value, Size, Section, File);
else if (Cmp == 0)
- reportDuplicate(S->body(), Section, Value);
+ reportDuplicate<ELFT>(S->body(),
+ dyn_cast_or_null<InputSectionBase>(Section), Value);
return S;
}
template <typename ELFT>
-Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N,
- const OutputSectionBase *Section,
- uintX_t Value, uint8_t StOther) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(N, STT_NOTYPE, getVisibility(StOther),
- /*CanOmitFromDynSym*/ false, nullptr);
- int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, STB_GLOBAL,
- /*IsAbsolute*/ false, /*Value*/ 0);
- if (Cmp > 0)
- replaceBody<DefinedSynthetic>(S, N, Value, Section);
- else if (Cmp == 0)
- reportDuplicate(S->body(), nullptr);
- return S;
-}
-
-template <typename ELFT>
-void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
+void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *File, StringRef Name,
const Elf_Sym &Sym,
const typename ELFT::Verdef *Verdef) {
// DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
@@ -423,15 +486,21 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *F, StringRef Name,
// unchanged.
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) =
- insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, F);
+ std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT,
+ /*CanOmitFromDynSym*/ true, File);
// Make sure we preempt DSO symbols with default visibility.
if (Sym.getVisibility() == STV_DEFAULT)
S->ExportDynamic = true;
- if (WasInserted || isa<Undefined<ELFT>>(S->body())) {
- replaceBody<SharedSymbol<ELFT>>(S, F, Name, Sym, Verdef);
+
+ SymbolBody *Body = S->body();
+ // An undefined symbol with non default visibility must be satisfied
+ // in the same DSO.
+ if (WasInserted ||
+ (isa<Undefined>(Body) && Body->getVisibility() == STV_DEFAULT)) {
+ replaceBody<SharedSymbol>(S, File, Name, Sym.st_other, Sym.getType(), &Sym,
+ Verdef);
if (!S->isWeak())
- F->IsUsed = true;
+ File->IsUsed = true;
}
}
@@ -444,10 +513,10 @@ Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, uint8_t Binding,
std::tie(S, WasInserted) =
insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F);
int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
- /*IsAbs*/ false, /*Value*/ 0);
+ /*IsAbs*/ false, /*Value*/ 0, Name);
if (Cmp > 0)
- replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type,
- 0, 0, nullptr, F);
+ replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0,
+ nullptr, F);
else if (Cmp == 0)
reportDuplicate(S->body(), F);
return S;
@@ -472,18 +541,18 @@ SymbolBody *SymbolTable<ELFT>::findInCurrentDSO(StringRef Name) {
}
template <class ELFT>
-void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
- const object::Archive::Symbol Sym) {
+Symbol *SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
+ const object::Archive::Symbol Sym) {
Symbol *S;
bool WasInserted;
StringRef Name = Sym.getName();
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType);
- return;
+ return S;
}
if (!S->body()->isUndefined())
- return;
+ return S;
// Weak undefined symbols should not fetch members from archives. If we were
// to keep old symbol we would not know that an archive member was available
@@ -494,11 +563,12 @@ void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
// to preserve its type. FIXME: Move the Type field to Symbol.
if (S->isWeak()) {
replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
- return;
+ return S;
}
std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym);
if (!MBInfo.first.getBuffer().empty())
addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second));
+ return S;
}
template <class ELFT>
@@ -514,13 +584,10 @@ void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) {
return;
// See comment for addLazyArchive above.
- if (S->isWeak()) {
+ if (S->isWeak())
replaceBody<LazyObject>(S, Name, Obj, S->body()->Type);
- } else {
- MemoryBufferRef MBRef = Obj.getBuffer();
- if (!MBRef.getBuffer().empty())
- addFile(createObjectFile(MBRef));
- }
+ else if (InputFile *F = Obj.fetch())
+ addFile(F);
}
// Process undefined (-u) flags by loading lazy symbols named by those flags.
@@ -539,11 +606,20 @@ template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() {
// shared libraries can find them.
// Except this, we ignore undefined symbols in DSOs.
template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
- for (SharedFile<ELFT> *File : SharedFiles)
- for (StringRef U : File->getUndefinedSymbols())
- if (SymbolBody *Sym = find(U))
- if (Sym->isDefined())
- Sym->symbol()->ExportDynamic = true;
+ for (SharedFile<ELFT> *File : SharedFiles) {
+ for (StringRef U : File->getUndefinedSymbols()) {
+ SymbolBody *Sym = find(U);
+ if (!Sym || !Sym->isDefined())
+ continue;
+ Sym->symbol()->ExportDynamic = true;
+
+ // If -dynamic-list is given, the default version is set to
+ // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym.
+ // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were
+ // specified by -dynamic-list.
+ Sym->symbol()->VersionId = VER_NDX_GLOBAL;
+ }
+ }
}
// Initialize DemangledSyms with a map from demangled symbols to symbol
@@ -624,7 +700,8 @@ template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() {
// Set symbol versions to symbols. This function handles patterns
// containing no wildcard characters.
template <class ELFT>
-void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
+void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver,
+ uint16_t VersionId,
StringRef VersionName) {
if (Ver.HasWildcard)
return;
@@ -640,6 +717,12 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, uint16_t VersionId
// Assign the version.
for (SymbolBody *B : Syms) {
+ // Skip symbols containing version info because symbol versions
+ // specified by symbol names take precedence over version scripts.
+ // See parseSymbolVersion().
+ if (B->getName().find('@') != StringRef::npos)
+ continue;
+
Symbol *Sym = B->symbol();
if (Sym->InVersionScript)
warn("duplicate symbol '" + Ver.Name + "' in version script");
@@ -653,12 +736,11 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
uint16_t VersionId) {
if (!Ver.HasWildcard)
return;
- std::vector<SymbolBody *> Syms = findAllByVersion(Ver);
// Exact matching takes precendence over fuzzy matching,
// so we set a version to a symbol only if no version has been assigned
// to the symbol. This behavior is compatible with GNU.
- for (SymbolBody *B : Syms)
+ for (SymbolBody *B : findAllByVersion(Ver))
if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
B->symbol()->VersionId = VersionId;
}
@@ -666,19 +748,9 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
// This function processes version scripts by updating VersionId
// member of symbols.
template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
- // Symbol themselves might know their versions because symbols
- // can contain versions in the form of <name>@<version>.
- // Let them parse their names.
- if (!Config->VersionDefinitions.empty())
- for (Symbol *Sym : SymVector)
- Sym->body()->parseSymbolVersion();
-
// Handle edge cases first.
handleAnonymousVersion();
- if (Config->VersionDefinitions.empty())
- return;
-
// Now we have version definitions, so we need to set version ids to symbols.
// Each version definition has a glob pattern, and all symbols that match
// with the pattern get that version.
@@ -696,6 +768,12 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions))
for (SymbolVersion &Ver : V.Globals)
assignWildcardVersion(Ver, V.Id);
+
+ // Symbol themselves might know their versions because symbols
+ // can contain versions in the form of <name>@<version>.
+ // Let them parse and update their names to exclude version suffix.
+ for (Symbol *Sym : SymVector)
+ Sym->body()->parseSymbolVersion();
}
template class elf::SymbolTable<ELF32LE>;
diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.h b/contrib/llvm/tools/lld/ELF/SymbolTable.h
index f39dbd1..4ba101f 100644
--- a/contrib/llvm/tools/lld/ELF/SymbolTable.h
+++ b/contrib/llvm/tools/lld/ELF/SymbolTable.h
@@ -18,8 +18,7 @@
namespace lld {
namespace elf {
-class Lazy;
-class OutputSectionBase;
+
struct Symbol;
// SymbolTable is a bucket of all known symbols, including defined,
@@ -36,22 +35,24 @@ struct Symbol;
// is one add* function per symbol type.
template <class ELFT> class SymbolTable {
typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::uint uintX_t;
public:
void addFile(InputFile *File);
void addCombinedLTOObject();
+ void addSymbolAlias(StringRef Alias, StringRef Name);
+ void addSymbolWrap(StringRef Name);
+ void applySymbolRenames();
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
ArrayRef<ObjectFile<ELFT> *> getObjectFiles() const { return ObjectFiles; }
ArrayRef<BinaryFile *> getBinaryFiles() const { return BinaryFiles; }
ArrayRef<SharedFile<ELFT> *> getSharedFiles() const { return SharedFiles; }
- DefinedRegular<ELFT> *addAbsolute(StringRef Name,
- uint8_t Visibility = llvm::ELF::STV_HIDDEN,
- uint8_t Binding = llvm::ELF::STB_GLOBAL);
- DefinedRegular<ELFT> *addIgnored(StringRef Name,
- uint8_t Visibility = llvm::ELF::STV_HIDDEN);
+ DefinedRegular *addAbsolute(StringRef Name,
+ uint8_t Visibility = llvm::ELF::STV_HIDDEN,
+ uint8_t Binding = llvm::ELF::STB_GLOBAL);
+ DefinedRegular *addIgnored(StringRef Name,
+ uint8_t Visibility = llvm::ELF::STV_HIDDEN);
Symbol *addUndefined(StringRef Name);
Symbol *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding,
@@ -59,24 +60,26 @@ public:
InputFile *File);
Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
- uintX_t Value, uintX_t Size, uint8_t Binding,
- InputSectionBase<ELFT> *Section, InputFile *File);
-
- Symbol *addSynthetic(StringRef N, const OutputSectionBase *Section,
- uintX_t Value, uint8_t StOther);
+ uint64_t Value, uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File);
void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
const typename ELFT::Verdef *Verdef);
- void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
+ Symbol *addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S);
void addLazyObject(StringRef Name, LazyObjectFile &Obj);
Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther,
uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File);
- Symbol *addCommon(StringRef N, uint64_t Size, uint64_t Alignment,
+ Symbol *addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
uint8_t Binding, uint8_t StOther, uint8_t Type,
InputFile *File);
+ std::pair<Symbol *, bool> insert(StringRef Name);
+ std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
+ uint8_t Visibility, bool CanOmitFromDynSym,
+ InputFile *File);
+
void scanUndefinedFlags();
void scanShlibUndefined();
void scanVersionScript();
@@ -85,16 +88,8 @@ public:
SymbolBody *findInCurrentDSO(StringRef Name);
void trace(StringRef Name);
- void wrap(StringRef Name);
-
- std::vector<InputSectionBase<ELFT> *> Sections;
private:
- std::pair<Symbol *, bool> insert(StringRef Name);
- std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
- uint8_t Visibility, bool CanOmitFromDynSym,
- InputFile *File);
-
std::vector<SymbolBody *> findByVersion(SymbolVersion Ver);
std::vector<SymbolBody *> findAllByVersion(SymbolVersion Ver);
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.cpp b/contrib/llvm/tools/lld/ELF/Symbols.cpp
index 43af44e..c69007e 100644
--- a/contrib/llvm/tools/lld/ELF/Symbols.cpp
+++ b/contrib/llvm/tools/lld/ELF/Symbols.cpp
@@ -28,62 +28,90 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-template <class ELFT>
-static typename ELFT::uint getSymVA(const SymbolBody &Body,
- typename ELFT::uint &Addend) {
- typedef typename ELFT::uint uintX_t;
-
+DefinedRegular *ElfSym::Bss;
+DefinedRegular *ElfSym::Etext1;
+DefinedRegular *ElfSym::Etext2;
+DefinedRegular *ElfSym::Edata1;
+DefinedRegular *ElfSym::Edata2;
+DefinedRegular *ElfSym::End1;
+DefinedRegular *ElfSym::End2;
+DefinedRegular *ElfSym::GlobalOffsetTable;
+DefinedRegular *ElfSym::MipsGp;
+DefinedRegular *ElfSym::MipsGpDisp;
+DefinedRegular *ElfSym::MipsLocalGp;
+
+static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) {
switch (Body.kind()) {
- case SymbolBody::DefinedSyntheticKind: {
- auto &D = cast<DefinedSynthetic>(Body);
- const OutputSectionBase *Sec = D.Section;
- if (!Sec)
- return D.Value;
- if (D.Value == uintX_t(-1))
- return Sec->Addr + Sec->Size;
- return Sec->Addr + D.Value;
- }
case SymbolBody::DefinedRegularKind: {
- auto &D = cast<DefinedRegular<ELFT>>(Body);
- InputSectionBase<ELFT> *IS = D.Section;
+ auto &D = cast<DefinedRegular>(Body);
+ SectionBase *IS = D.Section;
+ if (auto *ISB = dyn_cast_or_null<InputSectionBase>(IS))
+ IS = ISB->Repl;
// According to the ELF spec reference to a local symbol from outside
// the group are not allowed. Unfortunately .eh_frame breaks that rule
// and must be treated specially. For now we just replace the symbol with
// 0.
- if (IS == &InputSection<ELFT>::Discarded)
+ if (IS == &InputSection::Discarded)
return 0;
// This is an absolute symbol.
if (!IS)
return D.Value;
- uintX_t Offset = D.Value;
+ uint64_t Offset = D.Value;
+
+ // An object in an SHF_MERGE section might be referenced via a
+ // section symbol (as a hack for reducing the number of local
+ // symbols).
+ // Depending on the addend, the reference via a section symbol
+ // refers to a different object in the merge section.
+ // Since the objects in the merge section are not necessarily
+ // contiguous in the output, the addend can thus affect the final
+ // VA in a non-linear way.
+ // To make this work, we incorporate the addend into the section
+ // offset (and zero out the addend for later processing) so that
+ // we find the right object in the section.
if (D.isSection()) {
Offset += Addend;
Addend = 0;
}
- uintX_t VA = (IS->OutSec ? IS->OutSec->Addr : 0) + IS->getOffset(Offset);
+
+ const OutputSection *OutSec = IS->getOutputSection();
+
+ // In the typical case, this is actually very simple and boils
+ // down to adding together 3 numbers:
+ // 1. The address of the output section.
+ // 2. The offset of the input section within the output section.
+ // 3. The offset within the input section (this addition happens
+ // inside InputSection::getOffset).
+ //
+ // If you understand the data structures involved with this next
+ // line (and how they get built), then you have a pretty good
+ // understanding of the linker.
+ uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset);
+
if (D.isTls() && !Config->Relocatable) {
- if (!Out<ELFT>::TlsPhdr)
+ if (!Out::TlsPhdr)
fatal(toString(D.File) +
- " has a STT_TLS symbol but doesn't have a PT_TLS section");
- return VA - Out<ELFT>::TlsPhdr->p_vaddr;
+ " has an STT_TLS symbol but doesn't have an SHF_TLS section");
+ return VA - Out::TlsPhdr->p_vaddr;
}
return VA;
}
case SymbolBody::DefinedCommonKind:
if (!Config->DefineCommon)
return 0;
- return In<ELFT>::Common->OutSec->Addr + In<ELFT>::Common->OutSecOff +
+ return InX::Common->getParent()->Addr + InX::Common->OutSecOff +
cast<DefinedCommon>(Body).Offset;
case SymbolBody::SharedKind: {
- auto &SS = cast<SharedSymbol<ELFT>>(Body);
- if (!SS.NeedsCopyOrPltAddr)
- return 0;
- if (SS.isFunc())
- return Body.getPltVA<ELFT>();
- return SS.getBssSectionForCopy()->Addr + SS.CopyOffset;
+ auto &SS = cast<SharedSymbol>(Body);
+ if (SS.NeedsCopy)
+ return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff +
+ SS.CopyRelSecOff;
+ if (SS.NeedsPltAddr)
+ return Body.getPltVA();
+ return 0;
}
case SymbolBody::UndefinedKind:
return 0;
@@ -97,10 +125,9 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type)
- : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal),
+ : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal),
IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
- IsInIgot(false), CopyIsInBssRelRo(false), Type(Type), StOther(StOther),
- Name(Name) {}
+ IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {}
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
@@ -112,7 +139,7 @@ bool SymbolBody::isPreemptible() const {
// symbols with copy relocations (which resolve to .bss) or preempt plt
// entries (which resolve to that plt entry).
if (isShared())
- return !NeedsCopyOrPltAddr;
+ return !NeedsCopy && !NeedsPltAddr;
// That's all that can be preempted in a non-DSO.
if (!Config->Shared)
@@ -132,65 +159,76 @@ bool SymbolBody::isPreemptible() const {
return true;
}
-template <class ELFT> bool SymbolBody::hasThunk() const {
- if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
- return DR->ThunkData != nullptr;
- if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
- return S->ThunkData != nullptr;
- return false;
+// Overwrites all attributes with Other's so that this symbol becomes
+// an alias to Other. This is useful for handling some options such as
+// --wrap.
+void SymbolBody::copy(SymbolBody *Other) {
+ memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer,
+ sizeof(Symbol::Body));
}
-template <class ELFT>
-typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const {
- typename ELFT::uint OutVA = getSymVA<ELFT>(*this, Addend);
+uint64_t SymbolBody::getVA(int64_t Addend) const {
+ uint64_t OutVA = getSymVA(*this, Addend);
return OutVA + Addend;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
- return In<ELFT>::Got->getVA() + getGotOffset<ELFT>();
+uint64_t SymbolBody::getGotVA() const {
+ return InX::Got->getVA() + getGotOffset();
}
-template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
+uint64_t SymbolBody::getGotOffset() const {
return GotIndex * Target->GotEntrySize;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
+uint64_t SymbolBody::getGotPltVA() const {
if (this->IsInIgot)
- return In<ELFT>::IgotPlt->getVA() + getGotPltOffset<ELFT>();
- return In<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
+ return InX::IgotPlt->getVA() + getGotPltOffset();
+ return InX::GotPlt->getVA() + getGotPltOffset();
}
-template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
+uint64_t SymbolBody::getGotPltOffset() const {
return GotPltIndex * Target->GotPltEntrySize;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
+uint64_t SymbolBody::getPltVA() const {
if (this->IsInIplt)
- return In<ELFT>::Iplt->getVA() + PltIndex * Target->PltEntrySize;
- return In<ELFT>::Plt->getVA() + Target->PltHeaderSize +
+ return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
+ return InX::Plt->getVA() + Target->PltHeaderSize +
PltIndex * Target->PltEntrySize;
}
-template <class ELFT> typename ELFT::uint SymbolBody::getThunkVA() const {
- if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
- return DR->ThunkData->getVA();
- if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
- return S->ThunkData->getVA();
- if (const auto *S = dyn_cast<Undefined<ELFT>>(this))
- return S->ThunkData->getVA();
- fatal("getThunkVA() not supported for Symbol class\n");
-}
-
template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
if (const auto *C = dyn_cast<DefinedCommon>(this))
return C->Size;
- if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
+ if (const auto *DR = dyn_cast<DefinedRegular>(this))
return DR->Size;
- if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
- return S->Sym.st_size;
+ if (const auto *S = dyn_cast<SharedSymbol>(this))
+ return S->getSize<ELFT>();
return 0;
}
+OutputSection *SymbolBody::getOutputSection() const {
+ if (auto *S = dyn_cast<DefinedRegular>(this)) {
+ if (S->Section)
+ return S->Section->getOutputSection();
+ return nullptr;
+ }
+
+ if (auto *S = dyn_cast<SharedSymbol>(this)) {
+ if (S->NeedsCopy)
+ return S->CopyRelSec->getParent();
+ return nullptr;
+ }
+
+ if (isa<DefinedCommon>(this)) {
+ if (Config->DefineCommon)
+ return InX::Common->getParent();
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
// If a symbol name contains '@', the characters after that is
// a symbol version name. This function parses that.
void SymbolBody::parseSymbolVersion() {
@@ -227,34 +265,36 @@ void SymbolBody::parseSymbolVersion() {
}
// It is an error if the specified version is not defined.
- error(toString(File) + ": symbol " + S + " has undefined version " + Verstr);
+ // Usually version script is not provided when linking executable,
+ // but we may still want to override a versioned symbol from DSO,
+ // so we do not report error in this case.
+ if (Config->Shared)
+ error(toString(File) + ": symbol " + S + " has undefined version " +
+ Verstr);
}
Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
uint8_t Type)
: SymbolBody(K, Name, IsLocal, StOther, Type) {}
-template <class ELFT> bool DefinedRegular<ELFT>::isMipsPIC() const {
+template <class ELFT> bool DefinedRegular::isMipsPIC() const {
+ typedef typename ELFT::Ehdr Elf_Ehdr;
if (!Section || !isFunc())
return false;
+
+ auto *Sec = cast<InputSectionBase>(Section);
+ const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader();
return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
- (Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC);
+ (Hdr->e_flags & EF_MIPS_PIC);
}
-template <typename ELFT>
-Undefined<ELFT>::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
- uint8_t Type, InputFile *File)
+Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther,
+ uint8_t Type, InputFile *File)
: SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) {
this->File = File;
}
-template <typename ELFT>
-OutputSection<ELFT> *SharedSymbol<ELFT>::getBssSectionForCopy() const {
- assert(needsCopy());
- return CopyIsInBssRelRo ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss;
-}
-
-DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment,
+DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment,
uint8_t StOther, uint8_t Type, InputFile *File)
: Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther,
Type),
@@ -262,6 +302,17 @@ DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint64_t Alignment,
this->File = File;
}
+// If a shared symbol is referred via a copy relocation, its alignment
+// becomes part of the ABI. This function returns a symbol alignment.
+// Because symbols don't have alignment attributes, we need to infer that.
+template <class ELFT> uint32_t SharedSymbol::getAlignment() const {
+ auto *File = cast<SharedFile<ELFT>>(this->File);
+ uint32_t SecAlign = File->getSection(getSym<ELFT>())->sh_addralign;
+ uint64_t SymValue = getSym<ELFT>().st_value;
+ uint32_t SymAlign = uint32_t(1) << countTrailingZeros(SymValue);
+ return std::min(SecAlign, SymAlign);
+}
+
InputFile *Lazy::fetch() {
if (auto *S = dyn_cast<LazyArchive>(this))
return S->fetch();
@@ -289,20 +340,14 @@ InputFile *LazyArchive::fetch() {
return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second);
}
-InputFile *LazyObject::fetch() {
- MemoryBufferRef MBRef = file()->getBuffer();
- if (MBRef.getBuffer().empty())
- return nullptr;
- return createObjectFile(MBRef);
-}
+InputFile *LazyObject::fetch() { return file()->fetch(); }
uint8_t Symbol::computeBinding() const {
if (Config->Relocatable)
return Binding;
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
- const SymbolBody *Body = body();
- if (VersionId == VER_NDX_LOCAL && Body->isInCurrentDSO())
+ if (VersionId == VER_NDX_LOCAL && body()->isInCurrentDSO())
return STB_LOCAL;
if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
@@ -319,15 +364,15 @@ bool Symbol::includeInDynsym() const {
// Print out a log message for --trace-symbol.
void elf::printTraceSymbol(Symbol *Sym) {
SymbolBody *B = Sym->body();
- outs() << toString(B->File);
-
+ std::string S;
if (B->isUndefined())
- outs() << ": reference to ";
+ S = ": reference to ";
else if (B->isCommon())
- outs() << ": common definition of ";
+ S = ": common definition of ";
else
- outs() << ": definition of ";
- outs() << B->getName() << "\n";
+ S = ": definition of ";
+
+ message(toString(B->File) + S + B->getName());
}
// Returns a symbol for an error message.
@@ -338,62 +383,17 @@ std::string lld::toString(const SymbolBody &B) {
return B.getName();
}
-template bool SymbolBody::hasThunk<ELF32LE>() const;
-template bool SymbolBody::hasThunk<ELF32BE>() const;
-template bool SymbolBody::hasThunk<ELF64LE>() const;
-template bool SymbolBody::hasThunk<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
-template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
-template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
-template uint64_t SymbolBody::template getVA<ELF64BE>(uint64_t) const;
-
-template uint32_t SymbolBody::template getGotVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getGotVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getGotVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getGotVA<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getGotOffset<ELF32LE>() const;
-template uint32_t SymbolBody::template getGotOffset<ELF32BE>() const;
-template uint64_t SymbolBody::template getGotOffset<ELF64LE>() const;
-template uint64_t SymbolBody::template getGotOffset<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getGotPltVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getGotPltVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getGotPltVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getGotPltVA<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getThunkVA<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getGotPltOffset<ELF32LE>() const;
-template uint32_t SymbolBody::template getGotPltOffset<ELF32BE>() const;
-template uint64_t SymbolBody::template getGotPltOffset<ELF64LE>() const;
-template uint64_t SymbolBody::template getGotPltOffset<ELF64BE>() const;
-
-template uint32_t SymbolBody::template getPltVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getPltVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getPltVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getPltVA<ELF64BE>() const;
-
template uint32_t SymbolBody::template getSize<ELF32LE>() const;
template uint32_t SymbolBody::template getSize<ELF32BE>() const;
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
template uint64_t SymbolBody::template getSize<ELF64BE>() const;
-template class elf::Undefined<ELF32LE>;
-template class elf::Undefined<ELF32BE>;
-template class elf::Undefined<ELF64LE>;
-template class elf::Undefined<ELF64BE>;
-
-template class elf::SharedSymbol<ELF32LE>;
-template class elf::SharedSymbol<ELF32BE>;
-template class elf::SharedSymbol<ELF64LE>;
-template class elf::SharedSymbol<ELF64BE>;
+template bool DefinedRegular::template isMipsPIC<ELF32LE>() const;
+template bool DefinedRegular::template isMipsPIC<ELF32BE>() const;
+template bool DefinedRegular::template isMipsPIC<ELF64LE>() const;
+template bool DefinedRegular::template isMipsPIC<ELF64BE>() const;
-template class elf::DefinedRegular<ELF32LE>;
-template class elf::DefinedRegular<ELF32BE>;
-template class elf::DefinedRegular<ELF64LE>;
-template class elf::DefinedRegular<ELF64BE>;
+template uint32_t SharedSymbol::template getAlignment<ELF32LE>() const;
+template uint32_t SharedSymbol::template getAlignment<ELF32BE>() const;
+template uint32_t SharedSymbol::template getAlignment<ELF64LE>() const;
+template uint32_t SharedSymbol::template getAlignment<ELF64BE>() const;
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.h b/contrib/llvm/tools/lld/ELF/Symbols.h
index 7acb89a..a1b3a6f 100644
--- a/contrib/llvm/tools/lld/ELF/Symbols.h
+++ b/contrib/llvm/tools/lld/ELF/Symbols.h
@@ -30,8 +30,7 @@ class BitcodeFile;
class InputFile;
class LazyObjectFile;
template <class ELFT> class ObjectFile;
-template <class ELFT> class OutputSection;
-class OutputSectionBase;
+class OutputSection;
template <class ELFT> class SharedFile;
struct Symbol;
@@ -44,8 +43,7 @@ public:
DefinedRegularKind = DefinedFirst,
SharedKind,
DefinedCommonKind,
- DefinedSyntheticKind,
- DefinedLast = DefinedSyntheticKind,
+ DefinedLast = DefinedCommonKind,
UndefinedKind,
LazyArchiveKind,
LazyObjectKind,
@@ -67,27 +65,28 @@ public:
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
}
bool isShared() const { return SymbolKind == SharedKind; }
- bool isInCurrentDSO() const { return !isUndefined() && !isShared(); }
+ bool isInCurrentDSO() const {
+ return !isUndefined() && !isShared() && !isLazy();
+ }
bool isLocal() const { return IsLocal; }
bool isPreemptible() const;
StringRef getName() const { return Name; }
uint8_t getVisibility() const { return StOther & 0x3; }
void parseSymbolVersion();
+ void copy(SymbolBody *Other);
bool isInGot() const { return GotIndex != -1U; }
bool isInPlt() const { return PltIndex != -1U; }
- template <class ELFT> bool hasThunk() const;
- template <class ELFT>
- typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const;
+ uint64_t getVA(int64_t Addend = 0) const;
- template <class ELFT> typename ELFT::uint getGotOffset() const;
- template <class ELFT> typename ELFT::uint getGotVA() const;
- template <class ELFT> typename ELFT::uint getGotPltOffset() const;
- template <class ELFT> typename ELFT::uint getGotPltVA() const;
- template <class ELFT> typename ELFT::uint getPltVA() const;
- template <class ELFT> typename ELFT::uint getThunkVA() const;
+ uint64_t getGotOffset() const;
+ uint64_t getGotVA() const;
+ uint64_t getGotPltOffset() const;
+ uint64_t getGotPltVA() const;
+ uint64_t getPltVA() const;
template <class ELFT> typename ELFT::uint getSize() const;
+ OutputSection *getOutputSection() const;
// The file from which this symbol was created.
InputFile *File = nullptr;
@@ -105,9 +104,13 @@ protected:
const unsigned SymbolKind : 8;
public:
- // True if the linker has to generate a copy relocation for this shared
- // symbol or if the symbol should point to its plt entry.
- unsigned NeedsCopyOrPltAddr : 1;
+ // True if the linker has to generate a copy relocation.
+ // For SharedSymbol only.
+ unsigned NeedsCopy : 1;
+
+ // True the symbol should point to its PLT entry.
+ // For SharedSymbol only.
+ unsigned NeedsPltAddr : 1;
// True if this is a local symbol.
unsigned IsLocal : 1;
@@ -124,11 +127,6 @@ public:
// True if this symbol is in the Igot sub-section of the .got.plt or .got.
unsigned IsInIgot : 1;
- // True if this is a shared symbol in a read-only segment which requires a
- // copy relocation. This causes space for the symbol to be allocated in the
- // .bss.rel.ro section.
- unsigned CopyIsInBssRelRo : 1;
-
// The following fields have the same meaning as the ELF symbol attributes.
uint8_t Type; // symbol type
uint8_t StOther; // st_other field value
@@ -160,7 +158,7 @@ public:
class DefinedCommon : public Defined {
public:
- DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t StOther,
+ DefinedCommon(StringRef N, uint64_t Size, uint32_t Alignment, uint8_t StOther,
uint8_t Type, InputFile *File);
static bool classof(const SymbolBody *S) {
@@ -172,77 +170,35 @@ public:
uint64_t Offset;
// The maximum alignment we have seen for this symbol.
- uint64_t Alignment;
+ uint32_t Alignment;
uint64_t Size;
};
// Regular defined symbols read from object file symbol tables.
-template <class ELFT> class DefinedRegular : public Defined {
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::uint uintX_t;
-
+class DefinedRegular : public Defined {
public:
DefinedRegular(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
- uintX_t Value, uintX_t Size, InputSectionBase<ELFT> *Section,
+ uint64_t Value, uint64_t Size, SectionBase *Section,
InputFile *File)
: Defined(SymbolBody::DefinedRegularKind, Name, IsLocal, StOther, Type),
- Value(Value), Size(Size),
- Section(Section ? Section->Repl : NullInputSection) {
+ Value(Value), Size(Size), Section(Section) {
this->File = File;
}
// Return true if the symbol is a PIC function.
- bool isMipsPIC() const;
+ template <class ELFT> bool isMipsPIC() const;
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedRegularKind;
}
- uintX_t Value;
- uintX_t Size;
-
- // The input section this symbol belongs to. Notice that this is
- // a reference to a pointer. We are using two levels of indirections
- // because of ICF. If ICF decides two sections need to be merged, it
- // manipulates this Section pointers so that they point to the same
- // section. This is a bit tricky, so be careful to not be confused.
- // If this is null, the symbol is an absolute symbol.
- InputSectionBase<ELFT> *&Section;
-
- // If non-null the symbol has a Thunk that may be used as an alternative
- // destination for callers of this Symbol.
- Thunk<ELFT> *ThunkData = nullptr;
-
-private:
- static InputSectionBase<ELFT> *NullInputSection;
-};
-
-template <class ELFT>
-InputSectionBase<ELFT> *DefinedRegular<ELFT>::NullInputSection;
-
-// DefinedSynthetic is a class to represent linker-generated ELF symbols.
-// The difference from the regular symbol is that DefinedSynthetic symbols
-// don't belong to any input files or sections. Thus, its constructor
-// takes an output section to calculate output VA, etc.
-// If Section is null, this symbol is relative to the image base.
-class DefinedSynthetic : public Defined {
-public:
- DefinedSynthetic(StringRef Name, uint64_t Value,
- const OutputSectionBase *Section)
- : Defined(SymbolBody::DefinedSyntheticKind, Name, /*IsLocal=*/false,
- llvm::ELF::STV_HIDDEN, 0 /* Type */),
- Value(Value), Section(Section) {}
-
- static bool classof(const SymbolBody *S) {
- return S->kind() == SymbolBody::DefinedSyntheticKind;
- }
-
uint64_t Value;
- const OutputSectionBase *Section;
+ uint64_t Size;
+ SectionBase *Section;
};
-template <class ELFT> class Undefined : public SymbolBody {
+class Undefined : public SymbolBody {
public:
Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type,
InputFile *F);
@@ -250,53 +206,51 @@ public:
static bool classof(const SymbolBody *S) {
return S->kind() == UndefinedKind;
}
-
- // If non-null the symbol has a Thunk that may be used as an alternative
- // destination for callers of this Symbol. When linking a DSO undefined
- // symbols are implicitly imported, the symbol lookup will be performed by
- // the dynamic loader. A call to an undefined symbol will be given a PLT
- // entry and on ARM this may need a Thunk if the caller is in Thumb state.
- Thunk<ELFT> *ThunkData = nullptr;
- InputFile *file() { return this->File; }
};
-template <class ELFT> class SharedSymbol : public Defined {
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::Verdef Elf_Verdef;
- typedef typename ELFT::uint uintX_t;
-
+class SharedSymbol : public Defined {
public:
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::SharedKind;
}
- SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym,
- const Elf_Verdef *Verdef)
- : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, Sym.st_other,
- Sym.getType()),
- Sym(Sym), Verdef(Verdef) {
+ SharedSymbol(InputFile *File, StringRef Name, uint8_t StOther, uint8_t Type,
+ const void *ElfSym, const void *Verdef)
+ : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, StOther, Type),
+ Verdef(Verdef), ElfSym(ElfSym) {
// IFuncs defined in DSOs are treated as functions by the static linker.
if (isGnuIFunc())
- Type = llvm::ELF::STT_FUNC;
- this->File = F;
+ this->Type = llvm::ELF::STT_FUNC;
+ this->File = File;
+ }
+
+ template <class ELFT> uint64_t getShndx() const {
+ return getSym<ELFT>().st_shndx;
+ }
+
+ template <class ELFT> uint64_t getValue() const {
+ return getSym<ELFT>().st_value;
}
- SharedFile<ELFT> *file() { return (SharedFile<ELFT> *)this->File; }
+ template <class ELFT> uint64_t getSize() const {
+ return getSym<ELFT>().st_size;
+ }
- const Elf_Sym &Sym;
+ template <class ELFT> uint32_t getAlignment() const;
// This field is a pointer to the symbol's version definition.
- const Elf_Verdef *Verdef;
+ const void *Verdef;
- // CopyOffset is significant only when needsCopy() is true.
- uintX_t CopyOffset = 0;
+ // CopyRelSec and CopyRelSecOff are significant only when NeedsCopy is true.
+ InputSection *CopyRelSec;
+ uint64_t CopyRelSecOff;
- // If non-null the symbol has a Thunk that may be used as an alternative
- // destination for callers of this Symbol.
- Thunk<ELFT> *ThunkData = nullptr;
- bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); }
+private:
+ template <class ELFT> const typename ELFT::Sym &getSym() const {
+ return *(const typename ELFT::Sym *)ElfSym;
+ }
- OutputSection<ELFT> *getBssSectionForCopy() const;
+ const void *ElfSym;
};
// This class represents a symbol defined in an archive file. It is
@@ -350,39 +304,33 @@ public:
// Some linker-generated symbols need to be created as
// DefinedRegular symbols.
-template <class ELFT> struct ElfSym {
- // The content for __ehdr_start symbol.
- static DefinedRegular<ELFT> *EhdrStart;
-
- // The content for _etext and etext symbols.
- static DefinedRegular<ELFT> *Etext;
- static DefinedRegular<ELFT> *Etext2;
-
- // The content for _edata and edata symbols.
- static DefinedRegular<ELFT> *Edata;
- static DefinedRegular<ELFT> *Edata2;
-
- // The content for _end and end symbols.
- static DefinedRegular<ELFT> *End;
- static DefinedRegular<ELFT> *End2;
-
- // The content for _gp_disp/__gnu_local_gp symbols for MIPS target.
- static DefinedRegular<ELFT> *MipsGpDisp;
- static DefinedRegular<ELFT> *MipsLocalGp;
- static DefinedRegular<ELFT> *MipsGp;
+struct ElfSym {
+ // __bss_start
+ static DefinedRegular *Bss;
+
+ // etext and _etext
+ static DefinedRegular *Etext1;
+ static DefinedRegular *Etext2;
+
+ // edata and _edata
+ static DefinedRegular *Edata1;
+ static DefinedRegular *Edata2;
+
+ // end and _end
+ static DefinedRegular *End1;
+ static DefinedRegular *End2;
+
+ // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
+ // be at some offset from the base of the .got section, usually 0 or
+ // the end of the .got.
+ static DefinedRegular *GlobalOffsetTable;
+
+ // _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS.
+ static DefinedRegular *MipsGp;
+ static DefinedRegular *MipsGpDisp;
+ static DefinedRegular *MipsLocalGp;
};
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::EhdrStart;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext2;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGpDisp;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsLocalGp;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGp;
-
// A real symbol object, SymbolBody, is usually stored within a Symbol. There's
// always one Symbol for each symbol name. The resolver updates the SymbolBody
// stored in the Body field of this object as it resolves symbols. Symbol also
@@ -426,13 +374,9 @@ struct Symbol {
// This field is used to store the Symbol's SymbolBody. This instantiation of
// AlignedCharArrayUnion gives us a struct with a char array field that is
- // large and aligned enough to store any derived class of SymbolBody. We
- // assume that the size and alignment of ELF64LE symbols is sufficient for any
- // ELFT, and we verify this with the static_asserts in replaceBody.
- llvm::AlignedCharArrayUnion<
- DefinedCommon, DefinedRegular<llvm::object::ELF64LE>, DefinedSynthetic,
- Undefined<llvm::object::ELF64LE>, SharedSymbol<llvm::object::ELF64LE>,
- LazyArchive, LazyObject>
+ // large and aligned enough to store any derived class of SymbolBody.
+ llvm::AlignedCharArrayUnion<DefinedCommon, DefinedRegular, Undefined,
+ SharedSymbol, LazyArchive, LazyObject>
Body;
SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); }
diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
index b673a4e..4bbec4a 100644
--- a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
+++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
@@ -27,7 +27,10 @@
#include "Threads.h"
#include "Writer.h"
#include "lld/Config/Version.h"
-#include "llvm/Support/Dwarf.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/Object/Decompressor.h"
+#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/RandomNumberGenerator.h"
@@ -45,6 +48,12 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
+uint64_t SyntheticSection::getVA() const {
+ if (OutputSection *Sec = getParent())
+ return Sec->Addr + OutSecOff;
+ return 0;
+}
+
template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() {
std::vector<DefinedCommon *> V;
for (Symbol *S : Symtab<ELFT>::X->getSymbols())
@@ -54,35 +63,24 @@ template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() {
}
// Find all common symbols and allocate space for them.
-template <class ELFT> InputSection<ELFT> *elf::createCommonSection() {
- auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 1,
- ArrayRef<uint8_t>(), "COMMON");
- Ret->Live = true;
-
+template <class ELFT> InputSection *elf::createCommonSection() {
if (!Config->DefineCommon)
- return Ret;
+ return nullptr;
// Sort the common symbols by alignment as an heuristic to pack them better.
std::vector<DefinedCommon *> Syms = getCommonSymbols<ELFT>();
+ if (Syms.empty())
+ return nullptr;
+
std::stable_sort(Syms.begin(), Syms.end(),
[](const DefinedCommon *A, const DefinedCommon *B) {
return A->Alignment > B->Alignment;
});
- // Assign offsets to symbols.
- size_t Size = 0;
- size_t Alignment = 1;
- for (DefinedCommon *Sym : Syms) {
- Alignment = std::max<size_t>(Alignment, Sym->Alignment);
- Size = alignTo(Size, Sym->Alignment);
-
- // Compute symbol offset relative to beginning of input section.
- Sym->Offset = Size;
- Size += Sym->Size;
- }
- Ret->Alignment = Alignment;
- Ret->Data = makeArrayRef<uint8_t>(nullptr, Size);
- return Ret;
+ BssSection *Sec = make<BssSection>("COMMON");
+ for (DefinedCommon *Sym : Syms)
+ Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment);
+ return Sec;
}
// Returns an LLD version string.
@@ -100,16 +98,17 @@ static ArrayRef<uint8_t> getVersion() {
// Creates a .comment section containing LLD version info.
// With this feature, you can identify LLD-generated binaries easily
-// by "objdump -s -j .comment <file>".
+// by "readelf --string-dump .comment <file>".
// The returned object is a mergeable string section.
-template <class ELFT> MergeInputSection<ELFT> *elf::createCommentSection() {
+template <class ELFT> MergeInputSection *elf::createCommentSection() {
typename ELFT::Shdr Hdr = {};
Hdr.sh_flags = SHF_MERGE | SHF_STRINGS;
Hdr.sh_type = SHT_PROGBITS;
Hdr.sh_entsize = 1;
Hdr.sh_addralign = 1;
- auto *Ret = make<MergeInputSection<ELFT>>(/*file=*/nullptr, &Hdr, ".comment");
+ auto *Ret =
+ make<MergeInputSection>((ObjectFile<ELFT> *)nullptr, &Hdr, ".comment");
Ret->Data = getVersion();
Ret->splitIntoPieces();
return Ret;
@@ -118,8 +117,10 @@ template <class ELFT> MergeInputSection<ELFT> *elf::createCommentSection() {
// .MIPS.abiflags section.
template <class ELFT>
MipsAbiFlagsSection<ELFT>::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags)
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"),
- Flags(Flags) {}
+ : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"),
+ Flags(Flags) {
+ this->Entsize = sizeof(Elf_Mips_ABIFlags);
+}
template <class ELFT> void MipsAbiFlagsSection<ELFT>::writeTo(uint8_t *Buf) {
memcpy(Buf, &Flags, sizeof(Flags));
@@ -130,13 +131,13 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
Elf_Mips_ABIFlags Flags = {};
bool Create = false;
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
- if (!Sec->Live || Sec->Type != SHT_MIPS_ABIFLAGS)
+ for (InputSectionBase *Sec : InputSections) {
+ if (Sec->Type != SHT_MIPS_ABIFLAGS)
continue;
Sec->Live = false;
Create = true;
- std::string Filename = toString(Sec->getFile());
+ std::string Filename = toString(Sec->getFile<ELFT>());
const size_t Size = Sec->Data.size();
// Older version of BFD (such as the default FreeBSD linker) concatenate
// .MIPS.abiflags instead of merging. To allow for this case (or potential
@@ -175,8 +176,10 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
// .MIPS.options section.
template <class ELFT>
MipsOptionsSection<ELFT>::MipsOptionsSection(Elf_Mips_RegInfo Reginfo)
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"),
- Reginfo(Reginfo) {}
+ : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"),
+ Reginfo(Reginfo) {
+ this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo);
+}
template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
auto *Options = reinterpret_cast<Elf_Mips_Options *>(Buf);
@@ -184,7 +187,7 @@ template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
Options->size = getSize();
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
+ Reginfo.ri_gp_value = InX::MipsGot->getGp();
memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
}
@@ -197,13 +200,13 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
Elf_Mips_RegInfo Reginfo = {};
bool Create = false;
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
- if (!Sec->Live || Sec->Type != SHT_MIPS_OPTIONS)
+ for (InputSectionBase *Sec : InputSections) {
+ if (Sec->Type != SHT_MIPS_OPTIONS)
continue;
Sec->Live = false;
Create = true;
- std::string Filename = toString(Sec->getFile());
+ std::string Filename = toString(Sec->getFile<ELFT>());
ArrayRef<uint8_t> D = Sec->Data;
while (!D.empty()) {
@@ -217,7 +220,7 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
if (Config->Relocatable && Opt->getRegInfo().ri_gp_value)
error(Filename + ": unsupported non-zero ri_gp_value");
Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask;
- Sec->getFile()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
+ Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value;
break;
}
@@ -235,12 +238,14 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
// MIPS .reginfo section.
template <class ELFT>
MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"),
- Reginfo(Reginfo) {}
+ : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"),
+ Reginfo(Reginfo) {
+ this->Entsize = sizeof(Elf_Mips_RegInfo);
+}
template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
if (!Config->Relocatable)
- Reginfo.ri_gp_value = In<ELFT>::MipsGot->getGp();
+ Reginfo.ri_gp_value = InX::MipsGot->getGp();
memcpy(Buf, &Reginfo, sizeof(Reginfo));
}
@@ -253,22 +258,24 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
Elf_Mips_RegInfo Reginfo = {};
bool Create = false;
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
- if (!Sec->Live || Sec->Type != SHT_MIPS_REGINFO)
+ for (InputSectionBase *Sec : InputSections) {
+ if (Sec->Type != SHT_MIPS_REGINFO)
continue;
Sec->Live = false;
Create = true;
if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) {
- error(toString(Sec->getFile()) + ": invalid size of .reginfo section");
+ error(toString(Sec->getFile<ELFT>()) +
+ ": invalid size of .reginfo section");
return nullptr;
}
auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
if (Config->Relocatable && R->ri_gp_value)
- error(toString(Sec->getFile()) + ": unsupported non-zero ri_gp_value");
+ error(toString(Sec->getFile<ELFT>()) +
+ ": unsupported non-zero ri_gp_value");
Reginfo.ri_gprmask |= R->ri_gprmask;
- Sec->getFile()->MipsGp0 = R->ri_gp_value;
+ Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value;
};
if (Create)
@@ -276,15 +283,24 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
return nullptr;
}
-template <class ELFT> InputSection<ELFT> *elf::createInterpSection() {
- auto *Ret = make<InputSection<ELFT>>(SHF_ALLOC, SHT_PROGBITS, 1,
- ArrayRef<uint8_t>(), ".interp");
- Ret->Live = true;
-
+InputSection *elf::createInterpSection() {
// StringSaver guarantees that the returned string ends with '\0'.
StringRef S = Saver.save(Config->DynamicLinker);
- Ret->Data = {(const uint8_t *)S.data(), S.size() + 1};
- return Ret;
+ ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1};
+
+ auto *Sec =
+ make<InputSection>(SHF_ALLOC, SHT_PROGBITS, 1, Contents, ".interp");
+ Sec->Live = true;
+ return Sec;
+}
+
+SymbolBody *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase *Section) {
+ auto *S = make<DefinedRegular>(Name, /*IsLocal*/ true, STV_DEFAULT, Type,
+ Value, Size, Section, nullptr);
+ if (InX::SymTab)
+ InX::SymTab->addSymbol(S);
+ return S;
}
static size_t getHashSize() {
@@ -303,16 +319,15 @@ static size_t getHashSize() {
}
}
-template <class ELFT>
-BuildIdSection<ELFT>::BuildIdSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"),
+BuildIdSection::BuildIdSection()
+ : SyntheticSection(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"),
HashSize(getHashSize()) {}
-template <class ELFT> void BuildIdSection<ELFT>::writeTo(uint8_t *Buf) {
- const endianness E = ELFT::TargetEndianness;
- write32<E>(Buf, 4); // Name size
- write32<E>(Buf + 4, HashSize); // Content size
- write32<E>(Buf + 8, NT_GNU_BUILD_ID); // Type
+void BuildIdSection::writeTo(uint8_t *Buf) {
+ endianness E = Config->Endianness;
+ write32(Buf, 4, E); // Name size
+ write32(Buf + 4, HashSize, E); // Content size
+ write32(Buf + 8, NT_GNU_BUILD_ID, E); // Type
memcpy(Buf + 12, "GNU", 4); // Name string
HashBuf = Buf + 16;
}
@@ -334,23 +349,33 @@ static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> Arr,
// In order to utilize multiple cores, we first split data into 1MB
// chunks, compute a hash for each chunk, and then compute a hash value
// of the hash values.
-template <class ELFT>
-void BuildIdSection<ELFT>::computeHash(
+void BuildIdSection::computeHash(
llvm::ArrayRef<uint8_t> Data,
std::function<void(uint8_t *Dest, ArrayRef<uint8_t> Arr)> HashFn) {
std::vector<ArrayRef<uint8_t>> Chunks = split(Data, 1024 * 1024);
std::vector<uint8_t> Hashes(Chunks.size() * HashSize);
// Compute hash values.
- forLoop(0, Chunks.size(),
- [&](size_t I) { HashFn(Hashes.data() + I * HashSize, Chunks[I]); });
+ parallelForEachN(0, Chunks.size(), [&](size_t I) {
+ HashFn(Hashes.data() + I * HashSize, Chunks[I]);
+ });
// Write to the final output buffer.
HashFn(HashBuf, Hashes);
}
-template <class ELFT>
-void BuildIdSection<ELFT>::writeBuildId(ArrayRef<uint8_t> Buf) {
+BssSection::BssSection(StringRef Name)
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 0, Name) {}
+
+size_t BssSection::reserveSpace(uint64_t Size, uint32_t Alignment) {
+ if (OutputSection *Sec = getParent())
+ Sec->updateAlignment(Alignment);
+ this->Size = alignTo(this->Size, Alignment) + Size;
+ this->Alignment = std::max(this->Alignment, Alignment);
+ return this->Size - Size;
+}
+
+void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) {
switch (Config->BuildId) {
case BuildIdKind::Fast:
computeHash(Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) {
@@ -380,16 +405,229 @@ void BuildIdSection<ELFT>::writeBuildId(ArrayRef<uint8_t> Buf) {
}
template <class ELFT>
-GotSection<ELFT>::GotSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotEntrySize, ".got") {}
+EhFrameSection<ELFT>::EhFrameSection()
+ : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {}
+
+// Search for an existing CIE record or create a new one.
+// CIE records from input object files are uniquified by their contents
+// and where their relocations point to.
+template <class ELFT>
+template <class RelTy>
+CieRecord *EhFrameSection<ELFT>::addCie(EhSectionPiece &Piece,
+ ArrayRef<RelTy> Rels) {
+ auto *Sec = cast<EhInputSection>(Piece.ID);
+ const endianness E = ELFT::TargetEndianness;
+ if (read32<E>(Piece.data().data() + 4) != 0)
+ fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
+
+ SymbolBody *Personality = nullptr;
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI != (unsigned)-1)
+ Personality =
+ &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
+
+ // Search for an existing CIE by CIE contents/relocation target pair.
+ CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
+
+ // If not found, create a new one.
+ if (Cie->Piece == nullptr) {
+ Cie->Piece = &Piece;
+ Cies.push_back(Cie);
+ }
+ return Cie;
+}
+
+// There is one FDE per function. Returns true if a given FDE
+// points to a live function.
+template <class ELFT>
+template <class RelTy>
+bool EhFrameSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
+ ArrayRef<RelTy> Rels) {
+ auto *Sec = cast<EhInputSection>(Piece.ID);
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI == (unsigned)-1)
+ return false;
+ const RelTy &Rel = Rels[FirstRelI];
+ SymbolBody &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel);
+ auto *D = dyn_cast<DefinedRegular>(&B);
+ if (!D || !D->Section)
+ return false;
+ auto *Target =
+ cast<InputSectionBase>(cast<InputSectionBase>(D->Section)->Repl);
+ return Target && Target->Live;
+}
-template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
+// .eh_frame is a sequence of CIE or FDE records. In general, there
+// is one CIE record per input object file which is followed by
+// a list of FDEs. This function searches an existing CIE or create a new
+// one and associates FDEs to the CIE.
+template <class ELFT>
+template <class RelTy>
+void EhFrameSection<ELFT>::addSectionAux(EhInputSection *Sec,
+ ArrayRef<RelTy> Rels) {
+ const endianness E = ELFT::TargetEndianness;
+
+ DenseMap<size_t, CieRecord *> OffsetToCie;
+ for (EhSectionPiece &Piece : Sec->Pieces) {
+ // The empty record is the end marker.
+ if (Piece.size() == 4)
+ return;
+
+ size_t Offset = Piece.InputOff;
+ uint32_t ID = read32<E>(Piece.data().data() + 4);
+ if (ID == 0) {
+ OffsetToCie[Offset] = addCie(Piece, Rels);
+ continue;
+ }
+
+ uint32_t CieOffset = Offset + 4 - ID;
+ CieRecord *Cie = OffsetToCie[CieOffset];
+ if (!Cie)
+ fatal(toString(Sec) + ": invalid CIE reference");
+
+ if (!isFdeLive(Piece, Rels))
+ continue;
+ Cie->FdePieces.push_back(&Piece);
+ NumFdes++;
+ }
+}
+
+template <class ELFT>
+void EhFrameSection<ELFT>::addSection(InputSectionBase *C) {
+ auto *Sec = cast<EhInputSection>(C);
+ Sec->Parent = this;
+ updateAlignment(Sec->Alignment);
+ Sections.push_back(Sec);
+ for (auto *DS : Sec->DependentSections)
+ DependentSections.push_back(DS);
+
+ // .eh_frame is a sequence of CIE or FDE records. This function
+ // splits it into pieces so that we can call
+ // SplitInputSection::getSectionPiece on the section.
+ Sec->split<ELFT>();
+ if (Sec->Pieces.empty())
+ return;
+
+ if (Sec->NumRelocations) {
+ if (Sec->AreRelocsRela)
+ addSectionAux(Sec, Sec->template relas<ELFT>());
+ else
+ addSectionAux(Sec, Sec->template rels<ELFT>());
+ return;
+ }
+ addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
+}
+
+template <class ELFT>
+static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
+ memcpy(Buf, D.data(), D.size());
+
+ // Fix the size field. -4 since size does not include the size field itself.
+ const endianness E = ELFT::TargetEndianness;
+ write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
+}
+
+template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() {
+ if (this->Size)
+ return; // Already finalized.
+
+ size_t Off = 0;
+ for (CieRecord *Cie : Cies) {
+ Cie->Piece->OutputOff = Off;
+ Off += alignTo(Cie->Piece->size(), Config->Wordsize);
+
+ for (EhSectionPiece *Fde : Cie->FdePieces) {
+ Fde->OutputOff = Off;
+ Off += alignTo(Fde->size(), Config->Wordsize);
+ }
+ }
+
+ // The LSB standard does not allow a .eh_frame section with zero
+ // Call Frame Information records. Therefore add a CIE record length
+ // 0 as a terminator if this .eh_frame section is empty.
+ if (Off == 0)
+ Off = 4;
+
+ this->Size = Off;
+}
+
+template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
+ const endianness E = ELFT::TargetEndianness;
+ switch (Size) {
+ case DW_EH_PE_udata2:
+ return read16<E>(Buf);
+ case DW_EH_PE_udata4:
+ return read32<E>(Buf);
+ case DW_EH_PE_udata8:
+ return read64<E>(Buf);
+ case DW_EH_PE_absptr:
+ if (ELFT::Is64Bits)
+ return read64<E>(Buf);
+ return read32<E>(Buf);
+ }
+ fatal("unknown FDE size encoding");
+}
+
+// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
+// We need it to create .eh_frame_hdr section.
+template <class ELFT>
+uint64_t EhFrameSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
+ uint8_t Enc) {
+ // The starting address to which this FDE applies is
+ // stored at FDE + 8 byte.
+ size_t Off = FdeOff + 8;
+ uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
+ if ((Enc & 0x70) == DW_EH_PE_absptr)
+ return Addr;
+ if ((Enc & 0x70) == DW_EH_PE_pcrel)
+ return Addr + getParent()->Addr + Off;
+ fatal("unknown FDE size relative encoding");
+}
+
+template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) {
+ const endianness E = ELFT::TargetEndianness;
+ for (CieRecord *Cie : Cies) {
+ size_t CieOffset = Cie->Piece->OutputOff;
+ writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
+
+ for (EhSectionPiece *Fde : Cie->FdePieces) {
+ size_t Off = Fde->OutputOff;
+ writeCieFde<ELFT>(Buf + Off, Fde->data());
+
+ // FDE's second word should have the offset to an associated CIE.
+ // Write it.
+ write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
+ }
+ }
+
+ for (EhInputSection *S : Sections)
+ S->relocateAlloc(Buf, nullptr);
+
+ // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
+ // to get a FDE from an address to which FDE is applied. So here
+ // we obtain two addresses and pass them to EhFrameHdr object.
+ if (In<ELFT>::EhFrameHdr) {
+ for (CieRecord *Cie : Cies) {
+ uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
+ for (SectionPiece *Fde : Cie->FdePieces) {
+ uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
+ uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
+ In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
+ }
+ }
+ }
+}
+
+GotSection::GotSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotEntrySize, ".got") {}
+
+void GotSection::addEntry(SymbolBody &Sym) {
Sym.GotIndex = NumEntries;
++NumEntries;
}
-template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+bool GotSection::addDynTlsEntry(SymbolBody &Sym) {
if (Sym.GlobalDynIndex != -1U)
return false;
Sym.GlobalDynIndex = NumEntries;
@@ -400,48 +638,42 @@ template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
// Reserves TLS entries for a TLS module ID and a TLS block offset.
// In total it takes two GOT slots.
-template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
+bool GotSection::addTlsIndex() {
if (TlsIndexOff != uint32_t(-1))
return false;
- TlsIndexOff = NumEntries * sizeof(uintX_t);
+ TlsIndexOff = NumEntries * Config->Wordsize;
NumEntries += 2;
return true;
}
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
- return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
+uint64_t GotSection::getGlobalDynAddr(const SymbolBody &B) const {
+ return this->getVA() + B.GlobalDynIndex * Config->Wordsize;
}
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
- return B.GlobalDynIndex * sizeof(uintX_t);
+uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const {
+ return B.GlobalDynIndex * Config->Wordsize;
}
-template <class ELFT> void GotSection<ELFT>::finalize() {
- Size = NumEntries * sizeof(uintX_t);
-}
+void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; }
-template <class ELFT> bool GotSection<ELFT>::empty() const {
+bool GotSection::empty() const {
// If we have a relocation that is relative to GOT (such as GOTOFFREL),
// we need to emit a GOT even if it's empty.
return NumEntries == 0 && !HasGotOffRel;
}
-template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
- this->relocate(Buf, Buf + Size);
+void GotSection::writeTo(uint8_t *Buf) {
+ // Buf points to the start of this section's buffer,
+ // whereas InputSectionBase::relocateAlloc() expects its argument
+ // to point to the start of the output section.
+ relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
}
-template <class ELFT>
-MipsGotSection<ELFT>::MipsGotSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL,
- SHT_PROGBITS, 16, ".got") {}
+MipsGotSection::MipsGotSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
+ ".got") {}
-template <class ELFT>
-void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend,
- RelExpr Expr) {
+void MipsGotSection::addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr) {
// For "true" local symbols which can be referenced from the same module
// only compiler creates two instructions for address loading:
//
@@ -472,7 +704,7 @@ void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend,
// sections referenced by GOT relocations. Then later in the `finalize`
// method calculate number of "pages" required to cover all saved output
// section and allocate appropriate number of GOT entries.
- PageIndexMap.insert({cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec, 0});
+ PageIndexMap.insert({Sym.getOutputSection(), 0});
return;
}
if (Sym.isTls()) {
@@ -483,7 +715,7 @@ void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend,
TlsEntries.push_back(&Sym);
return;
}
- auto AddEntry = [&](SymbolBody &S, uintX_t A, GotEntries &Items) {
+ auto AddEntry = [&](SymbolBody &S, uint64_t A, GotEntries &Items) {
if (S.isInGot() && !A)
return;
size_t NewIndex = Items.size();
@@ -508,8 +740,7 @@ void MipsGotSection<ELFT>::addEntry(SymbolBody &Sym, uintX_t Addend,
}
}
-template <class ELFT>
-bool MipsGotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
+bool MipsGotSection::addDynTlsEntry(SymbolBody &Sym) {
if (Sym.GlobalDynIndex != -1U)
return false;
Sym.GlobalDynIndex = TlsEntries.size();
@@ -521,10 +752,10 @@ bool MipsGotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
// Reserves TLS entries for a TLS module ID and a TLS block offset.
// In total it takes two GOT slots.
-template <class ELFT> bool MipsGotSection<ELFT>::addTlsIndex() {
+bool MipsGotSection::addTlsIndex() {
if (TlsIndexOff != uint32_t(-1))
return false;
- TlsIndexOff = TlsEntries.size() * sizeof(uintX_t);
+ TlsIndexOff = TlsEntries.size() * Config->Wordsize;
TlsEntries.push_back(nullptr);
TlsEntries.push_back(nullptr);
return true;
@@ -538,25 +769,20 @@ static uint64_t getMipsPageCount(uint64_t Size) {
return (Size + 0xfffe) / 0xffff + 1;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t
-MipsGotSection<ELFT>::getPageEntryOffset(const SymbolBody &B,
- uintX_t Addend) const {
- const OutputSectionBase *OutSec =
- cast<DefinedRegular<ELFT>>(&B)->Section->OutSec;
- uintX_t SecAddr = getMipsPageAddr(OutSec->Addr);
- uintX_t SymAddr = getMipsPageAddr(B.getVA<ELFT>(Addend));
- uintX_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
+uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &B,
+ int64_t Addend) const {
+ const OutputSection *OutSec = B.getOutputSection();
+ uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
+ uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend));
+ uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
assert(Index < PageEntriesNum);
- return (HeaderEntriesNum + Index) * sizeof(uintX_t);
+ return (HeaderEntriesNum + Index) * Config->Wordsize;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t
-MipsGotSection<ELFT>::getBodyEntryOffset(const SymbolBody &B,
- uintX_t Addend) const {
+uint64_t MipsGotSection::getBodyEntryOffset(const SymbolBody &B,
+ int64_t Addend) const {
// Calculate offset of the GOT entries block: TLS, global, local.
- uintX_t Index = HeaderEntriesNum + PageEntriesNum;
+ uint64_t Index = HeaderEntriesNum + PageEntriesNum;
if (B.isTls())
Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size();
else if (B.IsInGlobalMipsGot)
@@ -571,35 +797,31 @@ MipsGotSection<ELFT>::getBodyEntryOffset(const SymbolBody &B,
assert(It != EntryIndexMap.end());
Index += It->second;
}
- return Index * sizeof(uintX_t);
+ return Index * Config->Wordsize;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t
-MipsGotSection<ELFT>::getTlsOffset() const {
- return (getLocalEntriesNum() + GlobalEntries.size()) * sizeof(uintX_t);
+uint64_t MipsGotSection::getTlsOffset() const {
+ return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t
-MipsGotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
- return B.GlobalDynIndex * sizeof(uintX_t);
+uint64_t MipsGotSection::getGlobalDynOffset(const SymbolBody &B) const {
+ return B.GlobalDynIndex * Config->Wordsize;
}
-template <class ELFT>
-const SymbolBody *MipsGotSection<ELFT>::getFirstGlobalEntry() const {
+const SymbolBody *MipsGotSection::getFirstGlobalEntry() const {
return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first;
}
-template <class ELFT>
-unsigned MipsGotSection<ELFT>::getLocalEntriesNum() const {
+unsigned MipsGotSection::getLocalEntriesNum() const {
return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() +
LocalEntries32.size();
}
-template <class ELFT> void MipsGotSection<ELFT>::finalize() {
+void MipsGotSection::finalizeContents() { updateAllocSize(); }
+
+void MipsGotSection::updateAllocSize() {
PageEntriesNum = 0;
- for (std::pair<const OutputSectionBase *, size_t> &P : PageIndexMap) {
+ for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) {
// For each output section referenced by GOT page relocations calculate
// and save into PageIndexMap an upper bound of MIPS GOT entries required
// to store page addresses of local symbols. We assume the worst case -
@@ -610,27 +832,31 @@ template <class ELFT> void MipsGotSection<ELFT>::finalize() {
PageEntriesNum += getMipsPageCount(P.first->Size);
}
Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
- sizeof(uintX_t);
+ Config->Wordsize;
}
-template <class ELFT> bool MipsGotSection<ELFT>::empty() const {
+bool MipsGotSection::empty() const {
// We add the .got section to the result for dynamic MIPS target because
// its address and properties are mentioned in the .dynamic section.
return Config->Relocatable;
}
-template <class ELFT>
-typename MipsGotSection<ELFT>::uintX_t MipsGotSection<ELFT>::getGp() const {
- return ElfSym<ELFT>::MipsGp->template getVA<ELFT>(0);
+uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); }
+
+static uint64_t readUint(uint8_t *Buf) {
+ if (Config->Is64)
+ return read64(Buf, Config->Endianness);
+ return read32(Buf, Config->Endianness);
}
-template <class ELFT>
-static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
- typedef typename ELFT::uint uintX_t;
- write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val);
+static void writeUint(uint8_t *Buf, uint64_t Val) {
+ if (Config->Is64)
+ write64(Buf, Val, Config->Endianness);
+ else
+ write32(Buf, Val, Config->Endianness);
}
-template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) {
+void MipsGotSection::writeTo(uint8_t *Buf) {
// Set the MSB of the second GOT slot. This is not required by any
// MIPS ABI documentation, though.
//
@@ -645,25 +871,24 @@ template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) {
// we've been doing this for years, it is probably a safe bet to
// keep doing this for now. We really need to revisit this to see
// if we had to do this.
- auto *P = reinterpret_cast<typename ELFT::Off *>(Buf);
- P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
- Buf += HeaderEntriesNum * sizeof(uintX_t);
+ writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
+ Buf += HeaderEntriesNum * Config->Wordsize;
// Write 'page address' entries to the local part of the GOT.
- for (std::pair<const OutputSectionBase *, size_t> &L : PageIndexMap) {
+ for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) {
size_t PageCount = getMipsPageCount(L.first->Size);
- uintX_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+ uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
for (size_t PI = 0; PI < PageCount; ++PI) {
- uint8_t *Entry = Buf + (L.second + PI) * sizeof(uintX_t);
- writeUint<ELFT>(Entry, FirstPageAddr + PI * 0x10000);
+ uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize;
+ writeUint(Entry, FirstPageAddr + PI * 0x10000);
}
}
- Buf += PageEntriesNum * sizeof(uintX_t);
+ Buf += PageEntriesNum * Config->Wordsize;
auto AddEntry = [&](const GotEntry &SA) {
uint8_t *Entry = Buf;
- Buf += sizeof(uintX_t);
+ Buf += Config->Wordsize;
const SymbolBody *Body = SA.first;
- uintX_t VA = Body->template getVA<ELFT>(SA.second);
- writeUint<ELFT>(Entry, VA);
+ uint64_t VA = Body->getVA(SA.second);
+ writeUint(Entry, VA);
};
std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry);
std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry);
@@ -674,86 +899,83 @@ template <class ELFT> void MipsGotSection<ELFT>::writeTo(uint8_t *Buf) {
// for thread-local storage.
// https://www.linux-mips.org/wiki/NPTL
if (TlsIndexOff != -1U && !Config->Pic)
- writeUint<ELFT>(Buf + TlsIndexOff, 1);
+ writeUint(Buf + TlsIndexOff, 1);
for (const SymbolBody *B : TlsEntries) {
if (!B || B->isPreemptible())
continue;
- uintX_t VA = B->getVA<ELFT>();
+ uint64_t VA = B->getVA();
if (B->GotIndex != -1U) {
- uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
- writeUint<ELFT>(Entry, VA - 0x7000);
+ uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize;
+ writeUint(Entry, VA - 0x7000);
}
if (B->GlobalDynIndex != -1U) {
- uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
- writeUint<ELFT>(Entry, 1);
- Entry += sizeof(uintX_t);
- writeUint<ELFT>(Entry, VA - 0x8000);
+ uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize;
+ writeUint(Entry, 1);
+ Entry += Config->Wordsize;
+ writeUint(Entry, VA - 0x8000);
}
}
}
-template <class ELFT>
-GotPltSection<ELFT>::GotPltSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize, ".got.plt") {}
+GotPltSection::GotPltSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotPltEntrySize, ".got.plt") {}
-template <class ELFT> void GotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
+void GotPltSection::addEntry(SymbolBody &Sym) {
Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size();
Entries.push_back(&Sym);
}
-template <class ELFT> size_t GotPltSection<ELFT>::getSize() const {
+size_t GotPltSection::getSize() const {
return (Target->GotPltHeaderEntriesNum + Entries.size()) *
Target->GotPltEntrySize;
}
-template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
+void GotPltSection::writeTo(uint8_t *Buf) {
Target->writeGotPltHeader(Buf);
Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize;
for (const SymbolBody *B : Entries) {
Target->writeGotPlt(Buf, *B);
- Buf += sizeof(uintX_t);
+ Buf += Config->Wordsize;
}
}
// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
// part of the .got.plt
-template <class ELFT>
-IgotPltSection<ELFT>::IgotPltSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- Target->GotPltEntrySize,
- Config->EMachine == EM_ARM ? ".got" : ".got.plt") {
-}
+IgotPltSection::IgotPltSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+ Target->GotPltEntrySize,
+ Config->EMachine == EM_ARM ? ".got" : ".got.plt") {}
-template <class ELFT> void IgotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
+void IgotPltSection::addEntry(SymbolBody &Sym) {
Sym.IsInIgot = true;
Sym.GotPltIndex = Entries.size();
Entries.push_back(&Sym);
}
-template <class ELFT> size_t IgotPltSection<ELFT>::getSize() const {
+size_t IgotPltSection::getSize() const {
return Entries.size() * Target->GotPltEntrySize;
}
-template <class ELFT> void IgotPltSection<ELFT>::writeTo(uint8_t *Buf) {
+void IgotPltSection::writeTo(uint8_t *Buf) {
for (const SymbolBody *B : Entries) {
Target->writeIgotPlt(Buf, *B);
- Buf += sizeof(uintX_t);
+ Buf += Config->Wordsize;
}
}
-template <class ELFT>
-StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic)
- : SyntheticSection<ELFT>(Dynamic ? (uintX_t)SHF_ALLOC : 0, SHT_STRTAB, 1,
- Name),
- Dynamic(Dynamic) {}
+StringTableSection::StringTableSection(StringRef Name, bool Dynamic)
+ : SyntheticSection(Dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name),
+ Dynamic(Dynamic) {
+ // ELF string tables start with a NUL byte.
+ addString("");
+}
// Adds a string to the string table. If HashIt is true we hash and check for
// duplicates. It is optional because the name of global symbols are already
// uniqued and hashing them again has a big cost for a small value: uniquing
// them with some other string that happens to be the same.
-template <class ELFT>
-unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
+unsigned StringTableSection::addString(StringRef S, bool HashIt) {
if (HashIt) {
auto R = StringMap.insert(std::make_pair(S, this->Size));
if (!R.second)
@@ -765,9 +987,7 @@ unsigned StringTableSection<ELFT>::addString(StringRef S, bool HashIt) {
return Ret;
}
-template <class ELFT> void StringTableSection<ELFT>::writeTo(uint8_t *Buf) {
- // ELF string tables start with NUL byte, so advance the pointer by one.
- ++Buf;
+void StringTableSection::writeTo(uint8_t *Buf) {
for (StringRef S : Strings) {
memcpy(Buf, S.data(), S.size());
Buf += S.size() + 1;
@@ -781,13 +1001,15 @@ static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
template <class ELFT>
DynamicSection<ELFT>::DynamicSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC,
- sizeof(uintX_t), ".dynamic") {
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, Config->Wordsize,
+ ".dynamic") {
this->Entsize = ELFT::Is64Bits ? 16 : 8;
- // .dynamic section is not writable on MIPS.
+
+ // .dynamic section is not writable on MIPS and on Fuchsia OS
+ // which passes -z rodynamic.
// See "Special Section" in Chapter 4 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (Config->EMachine == EM_MIPS)
+ if (Config->EMachine == EM_MIPS || Config->ZRodynamic)
this->Flags = SHF_ALLOC;
addEntries();
@@ -798,16 +1020,18 @@ DynamicSection<ELFT>::DynamicSection()
template <class ELFT> void DynamicSection<ELFT>::addEntries() {
// Add strings to .dynstr early so that .dynstr's size will be
// fixed early.
+ for (StringRef S : Config->FilterList)
+ add({DT_FILTER, InX::DynStrTab->addString(S)});
for (StringRef S : Config->AuxiliaryList)
- add({DT_AUXILIARY, In<ELFT>::DynStrTab->addString(S)});
- if (!Config->RPath.empty())
+ add({DT_AUXILIARY, InX::DynStrTab->addString(S)});
+ if (!Config->Rpath.empty())
add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
- In<ELFT>::DynStrTab->addString(Config->RPath)});
+ InX::DynStrTab->addString(Config->Rpath)});
for (SharedFile<ELFT> *F : Symtab<ELFT>::X->getSharedFiles())
if (F->isNeeded())
- add({DT_NEEDED, In<ELFT>::DynStrTab->addString(F->getSoName())});
+ add({DT_NEEDED, InX::DynStrTab->addString(F->SoName)});
if (!Config->SoName.empty())
- add({DT_SONAME, In<ELFT>::DynStrTab->addString(Config->SoName)});
+ add({DT_SONAME, InX::DynStrTab->addString(Config->SoName)});
// Set DT_FLAGS and DT_FLAGS_1.
uint32_t DtFlags = 0;
@@ -816,6 +1040,8 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() {
DtFlags |= DF_SYMBOLIC;
if (Config->ZNodelete)
DtFlags1 |= DF_1_NODELETE;
+ if (Config->ZNodlopen)
+ DtFlags1 |= DF_1_NOOPEN;
if (Config->ZNow) {
DtFlags |= DF_BIND_NOW;
DtFlags1 |= DF_1_NOW;
@@ -830,22 +1056,31 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() {
if (DtFlags1)
add({DT_FLAGS_1, DtFlags1});
- if (!Config->Shared && !Config->Relocatable)
+ // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We
+ // need it for each process, so we don't write it for DSOs. The loader writes
+ // the pointer into this entry.
+ //
+ // DT_DEBUG is the only .dynamic entry that needs to be written to. Some
+ // systems (currently only Fuchsia OS) provide other means to give the
+ // debugger this information. Such systems may choose make .dynamic read-only.
+ // If the target is such a system (used -z rodynamic) don't write DT_DEBUG.
+ if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)
add({DT_DEBUG, (uint64_t)0});
}
// Add remaining entries to complete .dynamic contents.
-template <class ELFT> void DynamicSection<ELFT>::finalize() {
+template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (this->Size)
return; // Already finalized.
- this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
- if (In<ELFT>::RelaDyn->OutSec->Size > 0) {
- bool IsRela = Config->Rela;
+ this->Link = InX::DynStrTab->getParent()->SectionIndex;
+ if (In<ELFT>::RelaDyn->getParent() && !In<ELFT>::RelaDyn->empty()) {
+ bool IsRela = Config->IsRela;
add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
- add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->OutSec->Size});
+ add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent(),
+ Entry::SecSize});
add({IsRela ? DT_RELAENT : DT_RELENT,
- uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
+ uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
// MIPS dynamic loader does not support RELCOUNT tag.
// The problem is in the tight relation between dynamic
@@ -856,34 +1091,45 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels});
}
}
- if (In<ELFT>::RelaPlt->OutSec->Size > 0) {
+ if (In<ELFT>::RelaPlt->getParent() && !In<ELFT>::RelaPlt->empty()) {
add({DT_JMPREL, In<ELFT>::RelaPlt});
- add({DT_PLTRELSZ, In<ELFT>::RelaPlt->OutSec->Size});
- add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
- In<ELFT>::GotPlt});
- add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)});
+ add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent(), Entry::SecSize});
+ switch (Config->EMachine) {
+ case EM_MIPS:
+ add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt});
+ break;
+ case EM_SPARCV9:
+ add({DT_PLTGOT, In<ELFT>::Plt});
+ break;
+ default:
+ add({DT_PLTGOT, In<ELFT>::GotPlt});
+ break;
+ }
+ add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)});
}
- add({DT_SYMTAB, In<ELFT>::DynSymTab});
+ add({DT_SYMTAB, InX::DynSymTab});
add({DT_SYMENT, sizeof(Elf_Sym)});
- add({DT_STRTAB, In<ELFT>::DynStrTab});
- add({DT_STRSZ, In<ELFT>::DynStrTab->getSize()});
- if (In<ELFT>::GnuHashTab)
- add({DT_GNU_HASH, In<ELFT>::GnuHashTab});
+ add({DT_STRTAB, InX::DynStrTab});
+ add({DT_STRSZ, InX::DynStrTab->getSize()});
+ if (!Config->ZText)
+ add({DT_TEXTREL, (uint64_t)0});
+ if (InX::GnuHashTab)
+ add({DT_GNU_HASH, InX::GnuHashTab});
if (In<ELFT>::HashTab)
add({DT_HASH, In<ELFT>::HashTab});
- if (Out<ELFT>::PreinitArray) {
- add({DT_PREINIT_ARRAY, Out<ELFT>::PreinitArray});
- add({DT_PREINIT_ARRAYSZ, Out<ELFT>::PreinitArray, Entry::SecSize});
+ if (Out::PreinitArray) {
+ add({DT_PREINIT_ARRAY, Out::PreinitArray});
+ add({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize});
}
- if (Out<ELFT>::InitArray) {
- add({DT_INIT_ARRAY, Out<ELFT>::InitArray});
- add({DT_INIT_ARRAYSZ, Out<ELFT>::InitArray, Entry::SecSize});
+ if (Out::InitArray) {
+ add({DT_INIT_ARRAY, Out::InitArray});
+ add({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize});
}
- if (Out<ELFT>::FiniArray) {
- add({DT_FINI_ARRAY, Out<ELFT>::FiniArray});
- add({DT_FINI_ARRAYSZ, Out<ELFT>::FiniArray, Entry::SecSize});
+ if (Out::FiniArray) {
+ add({DT_FINI_ARRAY, Out::FiniArray});
+ add({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize});
}
if (SymbolBody *B = Symtab<ELFT>::X->findInCurrentDSO(Config->Init))
@@ -907,19 +1153,18 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
add({DT_MIPS_RLD_VERSION, 1});
add({DT_MIPS_FLAGS, RHF_NOTPOT});
add({DT_MIPS_BASE_ADDRESS, Config->ImageBase});
- add({DT_MIPS_SYMTABNO, In<ELFT>::DynSymTab->getNumSymbols()});
- add({DT_MIPS_LOCAL_GOTNO, In<ELFT>::MipsGot->getLocalEntriesNum()});
- if (const SymbolBody *B = In<ELFT>::MipsGot->getFirstGlobalEntry())
+ add({DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols()});
+ add({DT_MIPS_LOCAL_GOTNO, InX::MipsGot->getLocalEntriesNum()});
+ if (const SymbolBody *B = InX::MipsGot->getFirstGlobalEntry())
add({DT_MIPS_GOTSYM, B->DynsymIndex});
else
- add({DT_MIPS_GOTSYM, In<ELFT>::DynSymTab->getNumSymbols()});
- add({DT_PLTGOT, In<ELFT>::MipsGot});
- if (In<ELFT>::MipsRldMap)
- add({DT_MIPS_RLD_MAP, In<ELFT>::MipsRldMap});
+ add({DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols()});
+ add({DT_PLTGOT, InX::MipsGot});
+ if (InX::MipsRldMap)
+ add({DT_MIPS_RLD_MAP, InX::MipsRldMap});
}
- this->OutSec->Entsize = this->Entsize;
- this->OutSec->Link = this->Link;
+ getParent()->Link = this->Link;
// +1 for DT_NULL
this->Size = (Entries.size() + 1) * this->Entsize;
@@ -935,13 +1180,13 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
P->d_un.d_ptr = E.OutSec->Addr;
break;
case Entry::InSecAddr:
- P->d_un.d_ptr = E.InSec->OutSec->Addr + E.InSec->OutSecOff;
+ P->d_un.d_ptr = E.InSec->getParent()->Addr + E.InSec->OutSecOff;
break;
case Entry::SecSize:
P->d_un.d_val = E.OutSec->Size;
break;
case Entry::SymAddr:
- P->d_un.d_ptr = E.Sym->template getVA<ELFT>();
+ P->d_un.d_ptr = E.Sym->getVA();
break;
case Entry::PlainInt:
P->d_un.d_val = E.Val;
@@ -951,21 +1196,17 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
}
}
-template <class ELFT>
-typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
- if (OutputSec)
- return OutputSec->Addr + OffsetInSec;
- return InputSec->OutSec->Addr + InputSec->getOffset(OffsetInSec);
+uint64_t DynamicReloc::getOffset() const {
+ return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec);
}
-template <class ELFT>
-typename ELFT::uint DynamicReloc<ELFT>::getAddend() const {
+int64_t DynamicReloc::getAddend() const {
if (UseSymVA)
- return Sym->getVA<ELFT>(Addend);
+ return Sym->getVA(Addend);
return Addend;
}
-template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const {
+uint32_t DynamicReloc::getSymIndex() const {
if (Sym && !UseSymVA)
return Sym->DynsymIndex;
return 0;
@@ -973,14 +1214,14 @@ template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const {
template <class ELFT>
RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
- : SyntheticSection<ELFT>(SHF_ALLOC, Config->Rela ? SHT_RELA : SHT_REL,
- sizeof(uintX_t), Name),
+ : SyntheticSection(SHF_ALLOC, Config->IsRela ? SHT_RELA : SHT_REL,
+ Config->Wordsize, Name),
Sort(Sort) {
- this->Entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+ this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
}
template <class ELFT>
-void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
+void RelocationSection<ELFT>::addReloc(const DynamicReloc &Reloc) {
if (Reloc.Type == Target->RelativeRel)
++NumRelativeRelocs;
Relocs.push_back(Reloc);
@@ -988,33 +1229,33 @@ void RelocationSection<ELFT>::addReloc(const DynamicReloc<ELFT> &Reloc) {
template <class ELFT, class RelTy>
static bool compRelocations(const RelTy &A, const RelTy &B) {
- bool AIsRel = A.getType(Config->Mips64EL) == Target->RelativeRel;
- bool BIsRel = B.getType(Config->Mips64EL) == Target->RelativeRel;
+ bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel;
+ bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel;
if (AIsRel != BIsRel)
return AIsRel;
- return A.getSymbol(Config->Mips64EL) < B.getSymbol(Config->Mips64EL);
+ return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL);
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
uint8_t *BufBegin = Buf;
- for (const DynamicReloc<ELFT> &Rel : Relocs) {
+ for (const DynamicReloc &Rel : Relocs) {
auto *P = reinterpret_cast<Elf_Rela *>(Buf);
- Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+ Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
- if (Config->Rela)
+ if (Config->IsRela)
P->r_addend = Rel.getAddend();
P->r_offset = Rel.getOffset();
- if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In<ELFT>::MipsGot)
+ if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot)
// Dynamic relocation against MIPS GOT section make deal TLS entries
// allocated in the end of the GOT. We need to adjust the offset to take
// in account 'local' and 'global' GOT entries.
- P->r_offset += In<ELFT>::MipsGot->getTlsOffset();
- P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
+ P->r_offset += InX::MipsGot->getTlsOffset();
+ P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
}
if (Sort) {
- if (Config->Rela)
+ if (Config->IsRela)
std::stable_sort((Elf_Rela *)BufBegin,
(Elf_Rela *)BufBegin + Relocs.size(),
compRelocations<ELFT, Elf_Rela>);
@@ -1028,314 +1269,284 @@ template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
return this->Entsize * Relocs.size();
}
-template <class ELFT> void RelocationSection<ELFT>::finalize() {
- this->Link = In<ELFT>::DynSymTab ? In<ELFT>::DynSymTab->OutSec->SectionIndex
- : In<ELFT>::SymTab->OutSec->SectionIndex;
+template <class ELFT> void RelocationSection<ELFT>::finalizeContents() {
+ this->Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex
+ : InX::SymTab->getParent()->SectionIndex;
// Set required output section properties.
- this->OutSec->Link = this->Link;
- this->OutSec->Entsize = this->Entsize;
+ getParent()->Link = this->Link;
}
-template <class ELFT>
-SymbolTableSection<ELFT>::SymbolTableSection(
- StringTableSection<ELFT> &StrTabSec)
- : SyntheticSection<ELFT>(StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0,
- StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
- sizeof(uintX_t),
- StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
- StrTabSec(StrTabSec) {
- this->Entsize = sizeof(Elf_Sym);
-}
+SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec)
+ : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0,
+ StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
+ Config->Wordsize,
+ StrTabSec.isDynamic() ? ".dynsym" : ".symtab"),
+ StrTabSec(StrTabSec) {}
// Orders symbols according to their positions in the GOT,
// in compliance with MIPS ABI rules.
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-static bool sortMipsSymbols(const SymbolBody *L, const SymbolBody *R) {
+static bool sortMipsSymbols(const SymbolTableEntry &L,
+ const SymbolTableEntry &R) {
// Sort entries related to non-local preemptible symbols by GOT indexes.
// All other entries go to the first part of GOT in arbitrary order.
- bool LIsInLocalGot = !L->IsInGlobalMipsGot;
- bool RIsInLocalGot = !R->IsInGlobalMipsGot;
+ bool LIsInLocalGot = !L.Symbol->IsInGlobalMipsGot;
+ bool RIsInLocalGot = !R.Symbol->IsInGlobalMipsGot;
if (LIsInLocalGot || RIsInLocalGot)
return !RIsInLocalGot;
- return L->GotIndex < R->GotIndex;
-}
-
-template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
- this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex;
- this->OutSec->Info = this->Info = NumLocals + 1;
- this->OutSec->Entsize = this->Entsize;
-
- if (Config->Relocatable)
- return;
+ return L.Symbol->GotIndex < R.Symbol->GotIndex;
+}
+
+// Finalize a symbol table. The ELF spec requires that all local
+// symbols precede global symbols, so we sort symbol entries in this
+// function. (For .dynsym, we don't do that because symbols for
+// dynamic linking are inherently all globals.)
+void SymbolTableBaseSection::finalizeContents() {
+ getParent()->Link = StrTabSec.getParent()->SectionIndex;
+
+ // If it is a .dynsym, there should be no local symbols, but we need
+ // to do a few things for the dynamic linker.
+ if (this->Type == SHT_DYNSYM) {
+ // Section's Info field has the index of the first non-local symbol.
+ // Because the first symbol entry is a null entry, 1 is the first.
+ getParent()->Info = 1;
+
+ if (InX::GnuHashTab) {
+ // NB: It also sorts Symbols to meet the GNU hash table requirements.
+ InX::GnuHashTab->addSymbols(Symbols);
+ } else if (Config->EMachine == EM_MIPS) {
+ std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
+ }
- if (!StrTabSec.isDynamic()) {
- auto GlobBegin = Symbols.begin() + NumLocals;
- auto It = std::stable_partition(
- GlobBegin, Symbols.end(), [](const SymbolTableEntry &S) {
- return S.Symbol->symbol()->computeBinding() == STB_LOCAL;
- });
- // update sh_info with number of Global symbols output with computed
- // binding of STB_LOCAL
- this->OutSec->Info = this->Info = 1 + It - Symbols.begin();
+ size_t I = 0;
+ for (const SymbolTableEntry &S : Symbols)
+ S.Symbol->DynsymIndex = ++I;
return;
}
-
- if (In<ELFT>::GnuHashTab)
- // NB: It also sorts Symbols to meet the GNU hash table requirements.
- In<ELFT>::GnuHashTab->addSymbols(Symbols);
- else if (Config->EMachine == EM_MIPS)
- std::stable_sort(Symbols.begin(), Symbols.end(),
- [](const SymbolTableEntry &L, const SymbolTableEntry &R) {
- return sortMipsSymbols(L.Symbol, R.Symbol);
- });
- size_t I = 0;
- for (const SymbolTableEntry &S : Symbols)
- S.Symbol->DynsymIndex = ++I;
}
-template <class ELFT> void SymbolTableSection<ELFT>::addGlobal(SymbolBody *B) {
- Symbols.push_back({B, StrTabSec.addString(B->getName(), false)});
+void SymbolTableBaseSection::postThunkContents() {
+ if (this->Type == SHT_DYNSYM)
+ return;
+ // move all local symbols before global symbols.
+ auto It = std::stable_partition(
+ Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
+ return S.Symbol->isLocal() ||
+ S.Symbol->symbol()->computeBinding() == STB_LOCAL;
+ });
+ size_t NumLocals = It - Symbols.begin();
+ getParent()->Info = NumLocals + 1;
}
-template <class ELFT> void SymbolTableSection<ELFT>::addLocal(SymbolBody *B) {
- assert(!StrTabSec.isDynamic());
- ++NumLocals;
- Symbols.push_back({B, StrTabSec.addString(B->getName())});
+void SymbolTableBaseSection::addSymbol(SymbolBody *B) {
+ // Adding a local symbol to a .dynsym is a bug.
+ assert(this->Type != SHT_DYNSYM || !B->isLocal());
+
+ bool HashIt = B->isLocal();
+ Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)});
}
-template <class ELFT>
-size_t SymbolTableSection<ELFT>::getSymbolIndex(SymbolBody *Body) {
- auto I = llvm::find_if(
- Symbols, [&](const SymbolTableEntry &E) { return E.Symbol == Body; });
+size_t SymbolTableBaseSection::getSymbolIndex(SymbolBody *Body) {
+ auto I = llvm::find_if(Symbols, [&](const SymbolTableEntry &E) {
+ if (E.Symbol == Body)
+ return true;
+ // This is used for -r, so we have to handle multiple section
+ // symbols being combined.
+ if (Body->Type == STT_SECTION && E.Symbol->Type == STT_SECTION)
+ return Body->getOutputSection() == E.Symbol->getOutputSection();
+ return false;
+ });
if (I == Symbols.end())
return 0;
return I - Symbols.begin() + 1;
}
+template <class ELFT>
+SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec)
+ : SymbolTableBaseSection(StrTabSec) {
+ this->Entsize = sizeof(Elf_Sym);
+}
+
+// Write the internal symbol table contents to the output symbol table.
template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
+ // The first entry is a null entry as per the ELF spec.
Buf += sizeof(Elf_Sym);
- // All symbols with STB_LOCAL binding precede the weak and global symbols.
- // .dynsym only contains global symbols.
- if (Config->Discard != DiscardPolicy::All && !StrTabSec.isDynamic())
- writeLocalSymbols(Buf);
-
- writeGlobalSymbols(Buf);
-}
-
-template <class ELFT>
-void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
- // Iterate over all input object files to copy their local symbols
- // to the output symbol table pointed by Buf.
+ auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
- for (auto I = Symbols.begin(); I != Symbols.begin() + NumLocals; ++I) {
- const DefinedRegular<ELFT> &Body = *cast<DefinedRegular<ELFT>>(I->Symbol);
- InputSectionBase<ELFT> *Section = Body.Section;
- auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+ for (SymbolTableEntry &Ent : Symbols) {
+ SymbolBody *Body = Ent.Symbol;
- if (!Section) {
- ESym->st_shndx = SHN_ABS;
- ESym->st_value = Body.Value;
+ // Set st_info and st_other.
+ if (Body->isLocal()) {
+ ESym->setBindingAndType(STB_LOCAL, Body->Type);
} else {
- const OutputSectionBase *OutSec = Section->OutSec;
- ESym->st_shndx = OutSec->SectionIndex;
- ESym->st_value = OutSec->Addr + Section->getOffset(Body);
+ ESym->setBindingAndType(Body->symbol()->computeBinding(), Body->Type);
+ ESym->setVisibility(Body->symbol()->Visibility);
}
- ESym->st_name = I->StrTabOffset;
- ESym->st_size = Body.template getSize<ELFT>();
- ESym->setBindingAndType(STB_LOCAL, Body.Type);
- Buf += sizeof(*ESym);
- }
-}
-
-template <class ELFT>
-void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
- // Write the internal symbol table contents to the output symbol table
- // pointed by Buf.
- auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
-
- for (auto I = Symbols.begin() + NumLocals; I != Symbols.end(); ++I) {
- const SymbolTableEntry &S = *I;
- SymbolBody *Body = S.Symbol;
- size_t StrOff = S.StrTabOffset;
- uint8_t Type = Body->Type;
- uintX_t Size = Body->getSize<ELFT>();
+ ESym->st_name = Ent.StrTabOffset;
- ESym->setBindingAndType(Body->symbol()->computeBinding(), Type);
- ESym->st_size = Size;
- ESym->st_name = StrOff;
- ESym->setVisibility(Body->symbol()->Visibility);
- ESym->st_value = Body->getVA<ELFT>();
-
- if (const OutputSectionBase *OutSec = getOutputSection(Body)) {
+ // Set a section index.
+ if (const OutputSection *OutSec = Body->getOutputSection())
ESym->st_shndx = OutSec->SectionIndex;
- } else if (isa<DefinedRegular<ELFT>>(Body)) {
+ else if (isa<DefinedRegular>(Body))
ESym->st_shndx = SHN_ABS;
- } else if (isa<DefinedCommon>(Body)) {
+ else if (isa<DefinedCommon>(Body))
ESym->st_shndx = SHN_COMMON;
+
+ // Copy symbol size if it is a defined symbol. st_size is not significant
+ // for undefined symbols, so whether copying it or not is up to us if that's
+ // the case. We'll leave it as zero because by not setting a value, we can
+ // get the exact same outputs for two sets of input files that differ only
+ // in undefined symbol size in DSOs.
+ if (ESym->st_shndx != SHN_UNDEF)
+ ESym->st_size = Body->getSize<ELFT>();
+
+ // st_value is usually an address of a symbol, but that has a
+ // special meaining for uninstantiated common symbols (this can
+ // occur if -r is given).
+ if (!Config->DefineCommon && isa<DefinedCommon>(Body))
ESym->st_value = cast<DefinedCommon>(Body)->Alignment;
- }
+ else
+ ESym->st_value = Body->getVA();
- if (Config->EMachine == EM_MIPS) {
- // On MIPS we need to mark symbol which has a PLT entry and requires
- // pointer equality by STO_MIPS_PLT flag. That is necessary to help
- // dynamic linker distinguish such symbols and MIPS lazy-binding stubs.
- // https://sourceware.org/ml/binutils/2008-07/txt00000.txt
- if (Body->isInPlt() && Body->NeedsCopyOrPltAddr)
- ESym->st_other |= STO_MIPS_PLT;
- if (Config->Relocatable) {
- auto *D = dyn_cast<DefinedRegular<ELFT>>(Body);
- if (D && D->isMipsPIC())
- ESym->st_other |= STO_MIPS_PIC;
- }
- }
++ESym;
}
-}
-template <class ELFT>
-const OutputSectionBase *
-SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
- switch (Sym->kind()) {
- case SymbolBody::DefinedSyntheticKind:
- return cast<DefinedSynthetic>(Sym)->Section;
- case SymbolBody::DefinedRegularKind: {
- auto &D = cast<DefinedRegular<ELFT>>(*Sym);
- if (D.Section)
- return D.Section->OutSec;
- break;
- }
- case SymbolBody::DefinedCommonKind:
- if (!Config->DefineCommon)
- return nullptr;
- return In<ELFT>::Common->OutSec;
- case SymbolBody::SharedKind: {
- auto &SS = cast<SharedSymbol<ELFT>>(*Sym);
- if (SS.needsCopy())
- return SS.getBssSectionForCopy();
- break;
- }
- case SymbolBody::UndefinedKind:
- case SymbolBody::LazyArchiveKind:
- case SymbolBody::LazyObjectKind:
- break;
- }
- return nullptr;
-}
-
-template <class ELFT>
-GnuHashTableSection<ELFT>::GnuHashTableSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_HASH, sizeof(uintX_t),
- ".gnu.hash") {
- this->Entsize = ELFT::Is64Bits ? 0 : 4;
-}
-
-template <class ELFT>
-unsigned GnuHashTableSection<ELFT>::calcNBuckets(unsigned NumHashed) {
- if (!NumHashed)
- return 0;
-
- // These values are prime numbers which are not greater than 2^(N-1) + 1.
- // In result, for any particular NumHashed we return a prime number
- // which is not greater than NumHashed.
- static const unsigned Primes[] = {
- 1, 1, 3, 3, 7, 13, 31, 61, 127, 251,
- 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071};
-
- return Primes[std::min<unsigned>(Log2_32_Ceil(NumHashed),
- array_lengthof(Primes) - 1)];
-}
-
-// Bloom filter estimation: at least 8 bits for each hashed symbol.
-// GNU Hash table requirement: it should be a power of 2,
-// the minimum value is 1, even for an empty table.
-// Expected results for a 32-bit target:
-// calcMaskWords(0..4) = 1
-// calcMaskWords(5..8) = 2
-// calcMaskWords(9..16) = 4
-// For a 64-bit target:
-// calcMaskWords(0..8) = 1
-// calcMaskWords(9..16) = 2
-// calcMaskWords(17..32) = 4
-template <class ELFT>
-unsigned GnuHashTableSection<ELFT>::calcMaskWords(unsigned NumHashed) {
- if (!NumHashed)
- return 1;
- return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off));
-}
+ // On MIPS we need to mark symbol which has a PLT entry and requires
+ // pointer equality by STO_MIPS_PLT flag. That is necessary to help
+ // dynamic linker distinguish such symbols and MIPS lazy-binding stubs.
+ // https://sourceware.org/ml/binutils/2008-07/txt00000.txt
+ if (Config->EMachine == EM_MIPS) {
+ auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
-template <class ELFT> void GnuHashTableSection<ELFT>::finalize() {
- unsigned NumHashed = Symbols.size();
- NBuckets = calcNBuckets(NumHashed);
- MaskWords = calcMaskWords(NumHashed);
- // Second hash shift estimation: just predefined values.
- Shift2 = ELFT::Is64Bits ? 6 : 5;
+ for (SymbolTableEntry &Ent : Symbols) {
+ SymbolBody *Body = Ent.Symbol;
+ if (Body->isInPlt() && Body->NeedsPltAddr)
+ ESym->st_other |= STO_MIPS_PLT;
- this->OutSec->Entsize = this->Entsize;
- this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
- this->Size = sizeof(Elf_Word) * 4 // Header
- + sizeof(Elf_Off) * MaskWords // Bloom Filter
- + sizeof(Elf_Word) * NBuckets // Hash Buckets
- + sizeof(Elf_Word) * NumHashed; // Hash Values
+ if (Config->Relocatable)
+ if (auto *D = dyn_cast<DefinedRegular>(Body))
+ if (D->isMipsPIC<ELFT>())
+ ESym->st_other |= STO_MIPS_PIC;
+ ++ESym;
+ }
+ }
}
-template <class ELFT> void GnuHashTableSection<ELFT>::writeTo(uint8_t *Buf) {
- writeHeader(Buf);
+// .hash and .gnu.hash sections contain on-disk hash tables that map
+// symbol names to their dynamic symbol table indices. Their purpose
+// is to help the dynamic linker resolve symbols quickly. If ELF files
+// don't have them, the dynamic linker has to do linear search on all
+// dynamic symbols, which makes programs slower. Therefore, a .hash
+// section is added to a DSO by default. A .gnu.hash is added if you
+// give the -hash-style=gnu or -hash-style=both option.
+//
+// The Unix semantics of resolving dynamic symbols is somewhat expensive.
+// Each ELF file has a list of DSOs that the ELF file depends on and a
+// list of dynamic symbols that need to be resolved from any of the
+// DSOs. That means resolving all dynamic symbols takes O(m)*O(n)
+// where m is the number of DSOs and n is the number of dynamic
+// symbols. For modern large programs, both m and n are large. So
+// making each step faster by using hash tables substiantially
+// improves time to load programs.
+//
+// (Note that this is not the only way to design the shared library.
+// For instance, the Windows DLL takes a different approach. On
+// Windows, each dynamic symbol has a name of DLL from which the symbol
+// has to be resolved. That makes the cost of symbol resolution O(n).
+// This disables some hacky techniques you can use on Unix such as
+// LD_PRELOAD, but this is arguably better semantics than the Unix ones.)
+//
+// Due to historical reasons, we have two different hash tables, .hash
+// and .gnu.hash. They are for the same purpose, and .gnu.hash is a new
+// and better version of .hash. .hash is just an on-disk hash table, but
+// .gnu.hash has a bloom filter in addition to a hash table to skip
+// DSOs very quickly. If you are sure that your dynamic linker knows
+// about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a
+// safe bet is to specify -hash-style=both for backward compatibilty.
+GnuHashTableSection::GnuHashTableSection()
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") {
+}
+
+void GnuHashTableSection::finalizeContents() {
+ getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+
+ // Computes bloom filter size in word size. We want to allocate 8
+ // bits for each symbol. It must be a power of two.
if (Symbols.empty())
- return;
+ MaskWords = 1;
+ else
+ MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize);
+
+ Size = 16; // Header
+ Size += Config->Wordsize * MaskWords; // Bloom filter
+ Size += NBuckets * 4; // Hash buckets
+ Size += Symbols.size() * 4; // Hash values
+}
+
+void GnuHashTableSection::writeTo(uint8_t *Buf) {
+ // Write a header.
+ write32(Buf, NBuckets, Config->Endianness);
+ write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size(),
+ Config->Endianness);
+ write32(Buf + 8, MaskWords, Config->Endianness);
+ write32(Buf + 12, getShift2(), Config->Endianness);
+ Buf += 16;
+
+ // Write a bloom filter and a hash table.
writeBloomFilter(Buf);
+ Buf += Config->Wordsize * MaskWords;
writeHashTable(Buf);
}
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHeader(uint8_t *&Buf) {
- auto *P = reinterpret_cast<Elf_Word *>(Buf);
- *P++ = NBuckets;
- *P++ = In<ELFT>::DynSymTab->getNumSymbols() - Symbols.size();
- *P++ = MaskWords;
- *P++ = Shift2;
- Buf = reinterpret_cast<uint8_t *>(P);
-}
-
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeBloomFilter(uint8_t *&Buf) {
- unsigned C = sizeof(Elf_Off) * 8;
-
- auto *Masks = reinterpret_cast<Elf_Off *>(Buf);
- for (const SymbolData &Sym : Symbols) {
- size_t Pos = (Sym.Hash / C) & (MaskWords - 1);
- uintX_t V = (uintX_t(1) << (Sym.Hash % C)) |
- (uintX_t(1) << ((Sym.Hash >> Shift2) % C));
- Masks[Pos] |= V;
+// This function writes a 2-bit bloom filter. This bloom filter alone
+// usually filters out 80% or more of all symbol lookups [1].
+// The dynamic linker uses the hash table only when a symbol is not
+// filtered out by a bloom filter.
+//
+// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
+// p.9, https://www.akkadia.org/drepper/dsohowto.pdf
+void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
+ const unsigned C = Config->Wordsize * 8;
+ for (const Entry &Sym : Symbols) {
+ size_t I = (Sym.Hash / C) & (MaskWords - 1);
+ uint64_t Val = readUint(Buf + I * Config->Wordsize);
+ Val |= uint64_t(1) << (Sym.Hash % C);
+ Val |= uint64_t(1) << ((Sym.Hash >> getShift2()) % C);
+ writeUint(Buf + I * Config->Wordsize, Val);
}
- Buf += sizeof(Elf_Off) * MaskWords;
}
-template <class ELFT>
-void GnuHashTableSection<ELFT>::writeHashTable(uint8_t *Buf) {
- Elf_Word *Buckets = reinterpret_cast<Elf_Word *>(Buf);
- Elf_Word *Values = Buckets + NBuckets;
-
- int PrevBucket = -1;
- int I = 0;
- for (const SymbolData &Sym : Symbols) {
- int Bucket = Sym.Hash % NBuckets;
- assert(PrevBucket <= Bucket);
- if (Bucket != PrevBucket) {
- Buckets[Bucket] = Sym.Body->DynsymIndex;
- PrevBucket = Bucket;
- if (I > 0)
- Values[I - 1] |= 1;
- }
- Values[I] = Sym.Hash & ~1;
- ++I;
+void GnuHashTableSection::writeHashTable(uint8_t *Buf) {
+ // Group symbols by hash value.
+ std::vector<std::vector<Entry>> Syms(NBuckets);
+ for (const Entry &Ent : Symbols)
+ Syms[Ent.Hash % NBuckets].push_back(Ent);
+
+ // Write hash buckets. Hash buckets contain indices in the following
+ // hash value table.
+ uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf);
+ for (size_t I = 0; I < NBuckets; ++I)
+ if (!Syms[I].empty())
+ write32(Buckets + I, Syms[I][0].Body->DynsymIndex, Config->Endianness);
+
+ // Write a hash value table. It represents a sequence of chains that
+ // share the same hash modulo value. The last element of each chain
+ // is terminated by LSB 1.
+ uint32_t *Values = Buckets + NBuckets;
+ size_t I = 0;
+ for (std::vector<Entry> &Vec : Syms) {
+ if (Vec.empty())
+ continue;
+ for (const Entry &Ent : makeArrayRef(Vec).drop_back())
+ write32(Values + I++, Ent.Hash & ~1, Config->Endianness);
+ write32(Values + I++, Vec.back().Hash | 1, Config->Endianness);
}
- if (I > 0)
- Values[I - 1] |= 1;
}
static uint32_t hashGnu(StringRef Name) {
@@ -1345,58 +1556,76 @@ static uint32_t hashGnu(StringRef Name) {
return H;
}
+// Returns a number of hash buckets to accomodate given number of elements.
+// We want to choose a moderate number that is not too small (which
+// causes too many hash collisions) and not too large (which wastes
+// disk space.)
+//
+// We return a prime number because it (is believed to) achieve good
+// hash distribution.
+static size_t getBucketSize(size_t NumSymbols) {
+ // List of largest prime numbers that are not greater than 2^n + 1.
+ for (size_t N : {131071, 65521, 32749, 16381, 8191, 4093, 2039, 1021, 509,
+ 251, 127, 61, 31, 13, 7, 3, 1})
+ if (N <= NumSymbols)
+ return N;
+ return 0;
+}
+
// Add symbols to this symbol hash table. Note that this function
// destructively sort a given vector -- which is needed because
// GNU-style hash table places some sorting requirements.
-template <class ELFT>
-void GnuHashTableSection<ELFT>::addSymbols(std::vector<SymbolTableEntry> &V) {
- // Ideally this will just be 'auto' but GCC 6.1 is not able
- // to deduce it correctly.
+void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) {
+ // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce
+ // its type correctly.
std::vector<SymbolTableEntry>::iterator Mid =
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) {
return S.Symbol->isUndefined();
});
if (Mid == V.end())
return;
- for (auto I = Mid, E = V.end(); I != E; ++I) {
- SymbolBody *B = I->Symbol;
- size_t StrOff = I->StrTabOffset;
- Symbols.push_back({B, StrOff, hashGnu(B->getName())});
+
+ for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) {
+ SymbolBody *B = Ent.Symbol;
+ Symbols.push_back({B, Ent.StrTabOffset, hashGnu(B->getName())});
}
- unsigned NBuckets = calcNBuckets(Symbols.size());
+ NBuckets = getBucketSize(Symbols.size());
std::stable_sort(Symbols.begin(), Symbols.end(),
- [&](const SymbolData &L, const SymbolData &R) {
+ [&](const Entry &L, const Entry &R) {
return L.Hash % NBuckets < R.Hash % NBuckets;
});
V.erase(Mid, V.end());
- for (const SymbolData &Sym : Symbols)
- V.push_back({Sym.Body, Sym.STName});
+ for (const Entry &Ent : Symbols)
+ V.push_back({Ent.Body, Ent.StrTabOffset});
}
template <class ELFT>
HashTableSection<ELFT>::HashTableSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_HASH, sizeof(Elf_Word), ".hash") {
- this->Entsize = sizeof(Elf_Word);
+ : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") {
+ this->Entsize = 4;
}
-template <class ELFT> void HashTableSection<ELFT>::finalize() {
- this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
- this->OutSec->Entsize = this->Entsize;
+template <class ELFT> void HashTableSection<ELFT>::finalizeContents() {
+ getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
- unsigned NumEntries = 2; // nbucket and nchain.
- NumEntries += In<ELFT>::DynSymTab->getNumSymbols(); // The chain entries.
+ unsigned NumEntries = 2; // nbucket and nchain.
+ NumEntries += InX::DynSymTab->getNumSymbols(); // The chain entries.
// Create as many buckets as there are symbols.
// FIXME: This is simplistic. We can try to optimize it, but implementing
// support for SHT_GNU_HASH is probably even more profitable.
- NumEntries += In<ELFT>::DynSymTab->getNumSymbols();
- this->Size = NumEntries * sizeof(Elf_Word);
+ NumEntries += InX::DynSymTab->getNumSymbols();
+ this->Size = NumEntries * 4;
}
template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
- unsigned NumSymbols = In<ELFT>::DynSymTab->getNumSymbols();
+ // A 32-bit integer type in the target endianness.
+ typedef typename ELFT::Word Elf_Word;
+
+ unsigned NumSymbols = InX::DynSymTab->getNumSymbols();
+
auto *P = reinterpret_cast<Elf_Word *>(Buf);
*P++ = NumSymbols; // nbucket
*P++ = NumSymbols; // nchain
@@ -1404,7 +1633,7 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
Elf_Word *Buckets = P;
Elf_Word *Chains = P + NumSymbols;
- for (const SymbolTableEntry &S : In<ELFT>::DynSymTab->getSymbols()) {
+ for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
SymbolBody *Body = S.Symbol;
StringRef Name = Body->getName();
unsigned I = Body->DynsymIndex;
@@ -1414,78 +1643,69 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) {
}
}
-template <class ELFT>
-PltSection<ELFT>::PltSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
- ".plt") {}
+PltSection::PltSection(size_t S)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
+ HeaderSize(S) {
+ // The PLT needs to be writable on SPARC as the dynamic linker will
+ // modify the instructions in the PLT entries.
+ if (Config->EMachine == EM_SPARCV9)
+ this->Flags |= SHF_WRITE;
+}
-template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
- // At beginning of PLT, we have code to call the dynamic linker
- // to resolve dynsyms at runtime. Write such code.
- Target->writePltHeader(Buf);
- size_t Off = Target->PltHeaderSize;
+void PltSection::writeTo(uint8_t *Buf) {
+ // At beginning of PLT but not the IPLT, we have code to call the dynamic
+ // linker to resolve dynsyms at runtime. Write such code.
+ if (HeaderSize != 0)
+ Target->writePltHeader(Buf);
+ size_t Off = HeaderSize;
+ // The IPlt is immediately after the Plt, account for this in RelOff
+ unsigned PltOff = getPltRelocOff();
for (auto &I : Entries) {
const SymbolBody *B = I.first;
- unsigned RelOff = I.second;
- uint64_t Got = B->getGotPltVA<ELFT>();
+ unsigned RelOff = I.second + PltOff;
+ uint64_t Got = B->getGotPltVA();
uint64_t Plt = this->getVA() + Off;
Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
Off += Target->PltEntrySize;
}
}
-template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody &Sym) {
+template <class ELFT> void PltSection::addEntry(SymbolBody &Sym) {
Sym.PltIndex = Entries.size();
- unsigned RelOff = In<ELFT>::RelaPlt->getRelocOffset();
+ RelocationSection<ELFT> *PltRelocSection = In<ELFT>::RelaPlt;
+ if (HeaderSize == 0) {
+ PltRelocSection = In<ELFT>::RelaIplt;
+ Sym.IsInIplt = true;
+ }
+ unsigned RelOff = PltRelocSection->getRelocOffset();
Entries.push_back(std::make_pair(&Sym, RelOff));
}
-template <class ELFT> size_t PltSection<ELFT>::getSize() const {
- return Target->PltHeaderSize + Entries.size() * Target->PltEntrySize;
+size_t PltSection::getSize() const {
+ return HeaderSize + Entries.size() * Target->PltEntrySize;
}
-template <class ELFT>
-IpltSection<ELFT>::IpltSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
- ".plt") {}
-
-template <class ELFT> void IpltSection<ELFT>::writeTo(uint8_t *Buf) {
- // The IRelative relocations do not support lazy binding so no header is
- // needed
- size_t Off = 0;
- for (auto &I : Entries) {
- const SymbolBody *B = I.first;
- unsigned RelOff = I.second + In<ELFT>::Plt->getSize();
- uint64_t Got = B->getGotPltVA<ELFT>();
- uint64_t Plt = this->getVA() + Off;
- Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
+// Some architectures such as additional symbols in the PLT section. For
+// example ARM uses mapping symbols to aid disassembly
+void PltSection::addSymbols() {
+ // The PLT may have symbols defined for the Header, the IPLT has no header
+ if (HeaderSize != 0)
+ Target->addPltHeaderSymbols(this);
+ size_t Off = HeaderSize;
+ for (size_t I = 0; I < Entries.size(); ++I) {
+ Target->addPltSymbols(this, Off);
Off += Target->PltEntrySize;
}
}
-template <class ELFT> void IpltSection<ELFT>::addEntry(SymbolBody &Sym) {
- Sym.PltIndex = Entries.size();
- Sym.IsInIplt = true;
- unsigned RelOff = In<ELFT>::RelaIplt->getRelocOffset();
- Entries.push_back(std::make_pair(&Sym, RelOff));
+unsigned PltSection::getPltRelocOff() const {
+ return (HeaderSize == 0) ? InX::Plt->getSize() : 0;
}
-template <class ELFT> size_t IpltSection<ELFT>::getSize() const {
- return Entries.size() * Target->PltEntrySize;
-}
-
-template <class ELFT>
-GdbIndexSection<ELFT>::GdbIndexSection()
- : SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index"),
- StringPool(llvm::StringTableBuilder::ELF) {}
-
-template <class ELFT> void GdbIndexSection<ELFT>::parseDebugSections() {
- for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections)
- if (InputSection<ELFT> *IS = dyn_cast<InputSection<ELFT>>(S))
- if (IS->OutSec && IS->Name == ".debug_info")
- readDwarf(IS);
-}
+GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks)
+ : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"),
+ StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(Chunks)) {}
// Iterative hash function for symbol's name is described in .gdb_index format
// specification. Note that we use one for version 5 to 7 here, it is different
@@ -1497,57 +1717,149 @@ static uint32_t hash(StringRef Str) {
return R;
}
-template <class ELFT>
-void GdbIndexSection<ELFT>::readDwarf(InputSection<ELFT> *I) {
- GdbIndexBuilder<ELFT> Builder(I);
- if (ErrorCount)
- return;
+static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf) {
+ std::vector<CompilationUnitEntry> Ret;
+ for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units())
+ Ret.push_back({CU->getOffset(), CU->getLength() + 4});
+ return Ret;
+}
+
+static std::vector<AddressEntry> readAddressArea(DWARFContext &Dwarf,
+ InputSection *Sec) {
+ std::vector<AddressEntry> Ret;
+
+ uint32_t CurrentCu = 0;
+ for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) {
+ DWARFAddressRangesVector Ranges;
+ CU->collectAddressRanges(Ranges);
+
+ ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
+ for (DWARFAddressRange &R : Ranges) {
+ InputSectionBase *S = Sections[R.SectionIndex];
+ if (!S || S == &InputSection::Discarded || !S->Live)
+ continue;
+ // Range list with zero size has no effect.
+ if (R.LowPC == R.HighPC)
+ continue;
+ Ret.push_back({cast<InputSection>(S), R.LowPC, R.HighPC, CurrentCu});
+ }
+ ++CurrentCu;
+ }
+ return Ret;
+}
+
+static std::vector<NameTypeEntry> readPubNamesAndTypes(DWARFContext &Dwarf,
+ bool IsLE) {
+ StringRef Data[] = {Dwarf.getGnuPubNamesSection(),
+ Dwarf.getGnuPubTypesSection()};
- size_t CuId = CompilationUnits.size();
- std::vector<std::pair<uintX_t, uintX_t>> CuList = Builder.readCUList();
- CompilationUnits.insert(CompilationUnits.end(), CuList.begin(), CuList.end());
+ std::vector<NameTypeEntry> Ret;
+ for (StringRef D : Data) {
+ DWARFDebugPubTable PubTable(D, IsLE, true);
+ for (const DWARFDebugPubTable::Set &Set : PubTable.getData())
+ for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
+ Ret.push_back({Ent.Name, Ent.Descriptor.toBits()});
+ }
+ return Ret;
+}
- std::vector<AddressEntry<ELFT>> AddrArea = Builder.readAddressArea(CuId);
- AddressArea.insert(AddressArea.end(), AddrArea.begin(), AddrArea.end());
+static std::vector<InputSection *> getDebugInfoSections() {
+ std::vector<InputSection *> Ret;
+ for (InputSectionBase *S : InputSections)
+ if (InputSection *IS = dyn_cast<InputSection>(S))
+ if (IS->Name == ".debug_info")
+ Ret.push_back(IS);
+ return Ret;
+}
- std::vector<std::pair<StringRef, uint8_t>> NamesAndTypes =
- Builder.readPubNamesAndTypes();
+void GdbIndexSection::buildIndex() {
+ if (Chunks.empty())
+ return;
- for (std::pair<StringRef, uint8_t> &Pair : NamesAndTypes) {
- uint32_t Hash = hash(Pair.first);
- size_t Offset = StringPool.add(Pair.first);
+ uint32_t CuId = 0;
+ for (GdbIndexChunk &D : Chunks) {
+ for (AddressEntry &E : D.AddressArea)
+ E.CuIndex += CuId;
+
+ // Populate constant pool area.
+ for (NameTypeEntry &NameType : D.NamesAndTypes) {
+ uint32_t Hash = hash(NameType.Name);
+ size_t Offset = StringPool.add(NameType.Name);
+
+ bool IsNew;
+ GdbSymbol *Sym;
+ std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
+ if (IsNew) {
+ Sym->CuVectorIndex = CuVectors.size();
+ CuVectors.resize(CuVectors.size() + 1);
+ }
- bool IsNew;
- GdbSymbol *Sym;
- std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);
- if (IsNew) {
- Sym->CuVectorIndex = CuVectors.size();
- CuVectors.push_back({{CuId, Pair.second}});
- continue;
+ CuVectors[Sym->CuVectorIndex].insert(CuId | (NameType.Type << 24));
}
- std::vector<std::pair<uint32_t, uint8_t>> &CuVec =
- CuVectors[Sym->CuVectorIndex];
- CuVec.push_back({CuId, Pair.second});
+ CuId += D.CompilationUnits.size();
+ }
+}
+
+static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) {
+ GdbIndexChunk Ret;
+ Ret.DebugInfoSec = Sec;
+ Ret.CompilationUnits = readCuList(Dwarf);
+ Ret.AddressArea = readAddressArea(Dwarf, Sec);
+ Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE);
+ return Ret;
+}
+
+template <class ELFT> GdbIndexSection *elf::createGdbIndex() {
+ std::vector<GdbIndexChunk> Chunks;
+ for (InputSection *Sec : getDebugInfoSections()) {
+ InputFile *F = Sec->File;
+ std::error_code EC;
+ ELFObjectFile<ELFT> Obj(F->MB, EC);
+ if (EC)
+ fatal(EC.message());
+ DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) {
+ error(toString(F) + ": error parsing DWARF data:\n>>> " +
+ toString(std::move(E)));
+ return ErrorPolicy::Continue;
+ });
+ Chunks.push_back(readDwarf(Dwarf, Sec));
}
+ return make<GdbIndexSection>(std::move(Chunks));
+}
+
+static size_t getCuSize(std::vector<GdbIndexChunk> &C) {
+ size_t Ret = 0;
+ for (GdbIndexChunk &D : C)
+ Ret += D.CompilationUnits.size();
+ return Ret;
}
-template <class ELFT> void GdbIndexSection<ELFT>::finalize() {
+static size_t getAddressAreaSize(std::vector<GdbIndexChunk> &C) {
+ size_t Ret = 0;
+ for (GdbIndexChunk &D : C)
+ Ret += D.AddressArea.size();
+ return Ret;
+}
+
+void GdbIndexSection::finalizeContents() {
if (Finalized)
return;
Finalized = true;
- parseDebugSections();
+ buildIndex();
+
+ SymbolTable.finalizeContents();
// GdbIndex header consist from version fields
// and 5 more fields with different kinds of offsets.
- CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize;
- SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize;
+ CuTypesOffset = CuListOffset + getCuSize(Chunks) * CompilationUnitSize;
+ SymTabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * AddressEntrySize;
ConstantPoolOffset =
SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize;
- for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
+ for (std::set<uint32_t> &CuVec : CuVectors) {
CuVectorsOffset.push_back(CuVectorsSize);
CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1);
}
@@ -1556,12 +1868,12 @@ template <class ELFT> void GdbIndexSection<ELFT>::finalize() {
StringPool.finalizeInOrder();
}
-template <class ELFT> size_t GdbIndexSection<ELFT>::getSize() const {
- const_cast<GdbIndexSection<ELFT> *>(this)->finalize();
+size_t GdbIndexSection::getSize() const {
+ const_cast<GdbIndexSection *>(this)->finalizeContents();
return StringPoolOffset + StringPool.getSize();
}
-template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
+void GdbIndexSection::writeTo(uint8_t *Buf) {
write32le(Buf, 7); // Write version.
write32le(Buf + 4, CuListOffset); // CU list offset.
write32le(Buf + 8, CuTypesOffset); // Types CU list offset.
@@ -1571,19 +1883,24 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
Buf += 24;
// Write the CU list.
- for (std::pair<uintX_t, uintX_t> CU : CompilationUnits) {
- write64le(Buf, CU.first);
- write64le(Buf + 8, CU.second);
- Buf += 16;
+ for (GdbIndexChunk &D : Chunks) {
+ for (CompilationUnitEntry &Cu : D.CompilationUnits) {
+ write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset);
+ write64le(Buf + 8, Cu.CuLength);
+ Buf += 16;
+ }
}
// Write the address area.
- for (AddressEntry<ELFT> &E : AddressArea) {
- uintX_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0);
- write64le(Buf, BaseAddr + E.LowAddress);
- write64le(Buf + 8, BaseAddr + E.HighAddress);
- write32le(Buf + 16, E.CuIndex);
- Buf += 20;
+ for (GdbIndexChunk &D : Chunks) {
+ for (AddressEntry &E : D.AddressArea) {
+ uint64_t BaseAddr =
+ E.Section->getParent()->Addr + E.Section->getOffset(0);
+ write64le(Buf, BaseAddr + E.LowAddress);
+ write64le(Buf + 8, BaseAddr + E.HighAddress);
+ write32le(Buf + 16, E.CuIndex);
+ Buf += 20;
+ }
}
// Write the symbol table.
@@ -1600,14 +1917,11 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
}
// Write the CU vectors into the constant pool.
- for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) {
+ for (std::set<uint32_t> &CuVec : CuVectors) {
write32le(Buf, CuVec.size());
Buf += 4;
- for (std::pair<uint32_t, uint8_t> &P : CuVec) {
- uint32_t Index = P.first;
- uint8_t Flags = P.second;
- Index |= Flags << 24;
- write32le(Buf, Index);
+ for (uint32_t Val : CuVec) {
+ write32le(Buf, Val);
Buf += 4;
}
}
@@ -1615,13 +1929,11 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
StringPool.write(Buf);
}
-template <class ELFT> bool GdbIndexSection<ELFT>::empty() const {
- return !Out<ELFT>::DebugInfo;
-}
+bool GdbIndexSection::empty() const { return !Out::DebugInfo; }
template <class ELFT>
EhFrameHeader<ELFT>::EhFrameHeader()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {}
+ : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {}
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
// Each entry of the search table consists of two values,
@@ -1642,11 +1954,11 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
Buf[2] = DW_EH_PE_udata4;
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
- write32<E>(Buf + 4, Out<ELFT>::EhFrame->Addr - this->getVA() - 4);
+ write32<E>(Buf + 4, In<ELFT>::EhFrame->getParent()->Addr - this->getVA() - 4);
write32<E>(Buf + 8, Fdes.size());
Buf += 12;
- uintX_t VA = this->getVA();
+ uint64_t VA = this->getVA();
for (FdeData &Fde : Fdes) {
write32<E>(Buf, Fde.Pc - VA);
write32<E>(Buf + 4, Fde.FdeVA - VA);
@@ -1656,7 +1968,7 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
template <class ELFT> size_t EhFrameHeader<ELFT>::getSize() const {
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
- return 12 + Out<ELFT>::EhFrame->NumFdes * 8;
+ return 12 + In<ELFT>::EhFrame->NumFdes * 8;
}
template <class ELFT>
@@ -1665,13 +1977,13 @@ void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) {
}
template <class ELFT> bool EhFrameHeader<ELFT>::empty() const {
- return Out<ELFT>::EhFrame->empty();
+ return In<ELFT>::EhFrame->empty();
}
template <class ELFT>
VersionDefinitionSection<ELFT>::VersionDefinitionSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
- ".gnu.version_d") {}
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
+ ".gnu.version_d") {}
static StringRef getFileDefName() {
if (!Config->SoName.empty())
@@ -1679,17 +1991,17 @@ static StringRef getFileDefName() {
return Config->OutputFile;
}
-template <class ELFT> void VersionDefinitionSection<ELFT>::finalize() {
- FileDefNameOff = In<ELFT>::DynStrTab->addString(getFileDefName());
+template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() {
+ FileDefNameOff = InX::DynStrTab->addString(getFileDefName());
for (VersionDefinition &V : Config->VersionDefinitions)
- V.NameOff = In<ELFT>::DynStrTab->addString(V.Name);
+ V.NameOff = InX::DynStrTab->addString(V.Name);
- this->OutSec->Link = this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
+ getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
// sh_info should be set to the number of definitions. This fact is missed in
// documentation, but confirmed by binutils community:
// https://sourceware.org/ml/binutils/2014-11/msg00355.html
- this->OutSec->Info = this->Info = getVerDefNum();
+ getParent()->Info = getVerDefNum();
}
template <class ELFT>
@@ -1729,23 +2041,24 @@ template <class ELFT> size_t VersionDefinitionSection<ELFT>::getSize() const {
template <class ELFT>
VersionTableSection<ELFT>::VersionTableSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
- ".gnu.version") {}
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
+ ".gnu.version") {
+ this->Entsize = sizeof(Elf_Versym);
+}
-template <class ELFT> void VersionTableSection<ELFT>::finalize() {
- this->OutSec->Entsize = this->Entsize = sizeof(Elf_Versym);
+template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() {
// At the moment of june 2016 GNU docs does not mention that sh_link field
// should be set, but Sun docs do. Also readelf relies on this field.
- this->OutSec->Link = this->Link = In<ELFT>::DynSymTab->OutSec->SectionIndex;
+ getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
}
template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
- return sizeof(Elf_Versym) * (In<ELFT>::DynSymTab->getSymbols().size() + 1);
+ return sizeof(Elf_Versym) * (InX::DynSymTab->getSymbols().size() + 1);
}
template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
- for (const SymbolTableEntry &S : In<ELFT>::DynSymTab->getSymbols()) {
+ for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
OutVersym->vs_index = S.Symbol->symbol()->VersionId;
++OutVersym;
}
@@ -1757,8 +2070,8 @@ template <class ELFT> bool VersionTableSection<ELFT>::empty() const {
template <class ELFT>
VersionNeedSection<ELFT>::VersionNeedSection()
- : SyntheticSection<ELFT>(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t),
- ".gnu.version_r") {
+ : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t),
+ ".gnu.version_r") {
// Identifiers in verneed section start at 2 because 0 and 1 are reserved
// for VER_NDX_LOCAL and VER_NDX_GLOBAL.
// First identifiers are reserved by verdef section if it exist.
@@ -1766,24 +2079,27 @@ VersionNeedSection<ELFT>::VersionNeedSection()
}
template <class ELFT>
-void VersionNeedSection<ELFT>::addSymbol(SharedSymbol<ELFT> *SS) {
- if (!SS->Verdef) {
+void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) {
+ auto *Ver = reinterpret_cast<const typename ELFT::Verdef *>(SS->Verdef);
+ if (!Ver) {
SS->symbol()->VersionId = VER_NDX_GLOBAL;
return;
}
- SharedFile<ELFT> *F = SS->file();
+
+ auto *File = cast<SharedFile<ELFT>>(SS->File);
+
// If we don't already know that we need an Elf_Verneed for this DSO, prepare
// to create one by adding it to our needed list and creating a dynstr entry
// for the soname.
- if (F->VerdefMap.empty())
- Needed.push_back({F, In<ELFT>::DynStrTab->addString(F->getSoName())});
- typename SharedFile<ELFT>::NeededVer &NV = F->VerdefMap[SS->Verdef];
+ if (File->VerdefMap.empty())
+ Needed.push_back({File, InX::DynStrTab->addString(File->SoName)});
+ typename SharedFile<ELFT>::NeededVer &NV = File->VerdefMap[Ver];
// If we don't already know that we need an Elf_Vernaux for this Elf_Verdef,
// prepare to create one by allocating a version identifier and creating a
// dynstr entry for the version name.
if (NV.Index == 0) {
- NV.StrTab = In<ELFT>::DynStrTab->addString(
- SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name);
+ NV.StrTab = InX::DynStrTab->addString(File->getStringTable().data() +
+ Ver->getAux()->vda_name);
NV.Index = NextIndex++;
}
SS->symbol()->VersionId = NV.Index;
@@ -1824,9 +2140,9 @@ template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
Verneed[-1].vn_next = 0;
}
-template <class ELFT> void VersionNeedSection<ELFT>::finalize() {
- this->OutSec->Link = this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
- this->OutSec->Info = this->Info = Needed.size();
+template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
+ getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
+ getParent()->Info = Needed.size();
}
template <class ELFT> size_t VersionNeedSection<ELFT>::getSize() const {
@@ -1840,53 +2156,219 @@ template <class ELFT> bool VersionNeedSection<ELFT>::empty() const {
return getNeedNum() == 0;
}
-template <class ELFT>
-MipsRldMapSection<ELFT>::MipsRldMapSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- sizeof(typename ELFT::uint), ".rld_map") {}
+MergeSyntheticSection::MergeSyntheticSection(StringRef Name, uint32_t Type,
+ uint64_t Flags, uint32_t Alignment)
+ : SyntheticSection(Flags, Type, Alignment, Name),
+ Builder(StringTableBuilder::RAW, Alignment) {}
+
+void MergeSyntheticSection::addSection(MergeInputSection *MS) {
+ MS->Parent = this;
+ Sections.push_back(MS);
+}
+
+void MergeSyntheticSection::writeTo(uint8_t *Buf) { Builder.write(Buf); }
+
+bool MergeSyntheticSection::shouldTailMerge() const {
+ return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
+}
+
+void MergeSyntheticSection::finalizeTailMerge() {
+ // Add all string pieces to the string table builder to create section
+ // contents.
+ for (MergeInputSection *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Builder.add(Sec->getData(I));
+
+ // Fix the string table content. After this, the contents will never change.
+ Builder.finalize();
+
+ // finalize() fixed tail-optimized strings, so we can now get
+ // offsets of strings. Get an offset for each string and save it
+ // to a corresponding StringPiece for easy access.
+ for (MergeInputSection *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
+}
+
+void MergeSyntheticSection::finalizeNoTailMerge() {
+ // Add all string pieces to the string table builder to create section
+ // contents. Because we are not tail-optimizing, offsets of strings are
+ // fixed when they are added to the builder (string table builder contains
+ // a hash table from strings to offsets).
+ for (MergeInputSection *Sec : Sections)
+ for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
+ if (Sec->Pieces[I].Live)
+ Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
+
+ Builder.finalizeInOrder();
+}
+
+void MergeSyntheticSection::finalizeContents() {
+ if (shouldTailMerge())
+ finalizeTailMerge();
+ else
+ finalizeNoTailMerge();
+}
+
+size_t MergeSyntheticSection::getSize() const { return Builder.getSize(); }
+
+// This function decompresses compressed sections and scans over the input
+// sections to create mergeable synthetic sections. It removes
+// MergeInputSections from the input section array and adds new synthetic
+// sections at the location of the first input section that it replaces. It then
+// finalizes each synthetic section in order to compute an output offset for
+// each piece of each input section.
+void elf::decompressAndMergeSections() {
+ // splitIntoPieces needs to be called on each MergeInputSection before calling
+ // finalizeContents(). Do that first.
+ parallelForEach(InputSections.begin(), InputSections.end(),
+ [](InputSectionBase *S) {
+ if (!S->Live)
+ return;
+ if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
+ S->uncompress();
+ if (auto *MS = dyn_cast<MergeInputSection>(S))
+ MS->splitIntoPieces();
+ });
+
+ std::vector<MergeSyntheticSection *> MergeSections;
+ for (InputSectionBase *&S : InputSections) {
+ MergeInputSection *MS = dyn_cast<MergeInputSection>(S);
+ if (!MS)
+ continue;
+
+ // We do not want to handle sections that are not alive, so just remove
+ // them instead of trying to merge.
+ if (!MS->Live)
+ continue;
+
+ StringRef OutsecName = getOutputSectionName(MS->Name);
+ uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP;
+ uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
+
+ auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
+ return Sec->Name == OutsecName && Sec->Flags == Flags &&
+ Sec->Alignment == Alignment;
+ });
+ if (I == MergeSections.end()) {
+ MergeSyntheticSection *Syn =
+ make<MergeSyntheticSection>(OutsecName, MS->Type, Flags, Alignment);
+ MergeSections.push_back(Syn);
+ I = std::prev(MergeSections.end());
+ S = Syn;
+ } else {
+ S = nullptr;
+ }
+ (*I)->addSection(MS);
+ }
+ for (auto *MS : MergeSections)
+ MS->finalizeContents();
-template <class ELFT> void MipsRldMapSection<ELFT>::writeTo(uint8_t *Buf) {
- // Apply filler from linker script.
- uint64_t Filler = Script<ELFT>::X->getFiller(this->Name);
- Filler = (Filler << 32) | Filler;
- memcpy(Buf, &Filler, getSize());
+ std::vector<InputSectionBase *> &V = InputSections;
+ V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
}
-template <class ELFT>
-ARMExidxSentinelSection<ELFT>::ARMExidxSentinelSection()
- : SyntheticSection<ELFT>(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
- sizeof(typename ELFT::uint), ".ARM.exidx") {}
+MipsRldMapSection::MipsRldMapSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,
+ ".rld_map") {}
+
+ARMExidxSentinelSection::ARMExidxSentinelSection()
+ : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,
+ Config->Wordsize, ".ARM.exidx") {}
// Write a terminating sentinel entry to the end of the .ARM.exidx table.
// This section will have been sorted last in the .ARM.exidx table.
// This table entry will have the form:
// | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND |
-template <class ELFT>
-void ARMExidxSentinelSection<ELFT>::writeTo(uint8_t *Buf) {
- // Get the InputSection before us, we are by definition last
- auto RI = cast<OutputSection<ELFT>>(this->OutSec)->Sections.rbegin();
- InputSection<ELFT> *LE = *(++RI);
- InputSection<ELFT> *LC = cast<InputSection<ELFT>>(LE->getLinkOrderDep());
- uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize());
- uint64_t P = this->getVA();
+// The sentinel must have the PREL31 value of an address higher than any
+// address described by any other table entry.
+void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {
+ // The Sections are sorted in order of ascending PREL31 address with the
+ // sentinel last. We need to find the InputSection that precedes the
+ // sentinel. By construction the Sentinel is in the last
+ // InputSectionDescription as the InputSection that precedes it.
+ OutputSectionCommand *C = Script->getCmd(getParent());
+ auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(),
+ [](const BaseCommand *Base) {
+ return isa<InputSectionDescription>(Base);
+ });
+ auto L = cast<InputSectionDescription>(*ISD);
+ InputSection *Highest = L->Sections[L->Sections.size() - 2];
+ InputSection *LS = Highest->getLinkOrderDep();
+ uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize());
+ uint64_t P = getVA();
Target->relocateOne(Buf, R_ARM_PREL31, S - P);
write32le(Buf + 4, 0x1);
}
-template InputSection<ELF32LE> *elf::createCommonSection();
-template InputSection<ELF32BE> *elf::createCommonSection();
-template InputSection<ELF64LE> *elf::createCommonSection();
-template InputSection<ELF64BE> *elf::createCommonSection();
-
-template InputSection<ELF32LE> *elf::createInterpSection();
-template InputSection<ELF32BE> *elf::createInterpSection();
-template InputSection<ELF64LE> *elf::createInterpSection();
-template InputSection<ELF64BE> *elf::createInterpSection();
-
-template MergeInputSection<ELF32LE> *elf::createCommentSection();
-template MergeInputSection<ELF32BE> *elf::createCommentSection();
-template MergeInputSection<ELF64LE> *elf::createCommentSection();
-template MergeInputSection<ELF64BE> *elf::createCommentSection();
+ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS,
+ Config->Wordsize, ".text.thunk") {
+ this->Parent = OS;
+ this->OutSecOff = Off;
+}
+
+void ThunkSection::addThunk(Thunk *T) {
+ uint64_t Off = alignTo(Size, T->Alignment);
+ T->Offset = Off;
+ Thunks.push_back(T);
+ T->addSymbols(*this);
+ Size = Off + T->size();
+}
+
+void ThunkSection::writeTo(uint8_t *Buf) {
+ for (const Thunk *T : Thunks)
+ T->writeTo(Buf + T->Offset, *this);
+}
+
+InputSection *ThunkSection::getTargetInputSection() const {
+ const Thunk *T = Thunks.front();
+ return T->getTargetInputSection();
+}
+
+InputSection *InX::ARMAttributes;
+BssSection *InX::Bss;
+BssSection *InX::BssRelRo;
+BuildIdSection *InX::BuildId;
+InputSection *InX::Common;
+SyntheticSection *InX::Dynamic;
+StringTableSection *InX::DynStrTab;
+SymbolTableBaseSection *InX::DynSymTab;
+InputSection *InX::Interp;
+GdbIndexSection *InX::GdbIndex;
+GotSection *InX::Got;
+GotPltSection *InX::GotPlt;
+GnuHashTableSection *InX::GnuHashTab;
+IgotPltSection *InX::IgotPlt;
+MipsGotSection *InX::MipsGot;
+MipsRldMapSection *InX::MipsRldMap;
+PltSection *InX::Plt;
+PltSection *InX::Iplt;
+StringTableSection *InX::ShStrTab;
+StringTableSection *InX::StrTab;
+SymbolTableBaseSection *InX::SymTab;
+
+template GdbIndexSection *elf::createGdbIndex<ELF32LE>();
+template GdbIndexSection *elf::createGdbIndex<ELF32BE>();
+template GdbIndexSection *elf::createGdbIndex<ELF64LE>();
+template GdbIndexSection *elf::createGdbIndex<ELF64BE>();
+
+template void PltSection::addEntry<ELF32LE>(SymbolBody &Sym);
+template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym);
+template void PltSection::addEntry<ELF64LE>(SymbolBody &Sym);
+template void PltSection::addEntry<ELF64BE>(SymbolBody &Sym);
+
+template InputSection *elf::createCommonSection<ELF32LE>();
+template InputSection *elf::createCommonSection<ELF32BE>();
+template InputSection *elf::createCommonSection<ELF64LE>();
+template InputSection *elf::createCommonSection<ELF64BE>();
+
+template MergeInputSection *elf::createCommentSection<ELF32LE>();
+template MergeInputSection *elf::createCommentSection<ELF32BE>();
+template MergeInputSection *elf::createCommentSection<ELF64LE>();
+template MergeInputSection *elf::createCommentSection<ELF64BE>();
template class elf::MipsAbiFlagsSection<ELF32LE>;
template class elf::MipsAbiFlagsSection<ELF32BE>;
@@ -1903,36 +2385,6 @@ template class elf::MipsReginfoSection<ELF32BE>;
template class elf::MipsReginfoSection<ELF64LE>;
template class elf::MipsReginfoSection<ELF64BE>;
-template class elf::BuildIdSection<ELF32LE>;
-template class elf::BuildIdSection<ELF32BE>;
-template class elf::BuildIdSection<ELF64LE>;
-template class elf::BuildIdSection<ELF64BE>;
-
-template class elf::GotSection<ELF32LE>;
-template class elf::GotSection<ELF32BE>;
-template class elf::GotSection<ELF64LE>;
-template class elf::GotSection<ELF64BE>;
-
-template class elf::MipsGotSection<ELF32LE>;
-template class elf::MipsGotSection<ELF32BE>;
-template class elf::MipsGotSection<ELF64LE>;
-template class elf::MipsGotSection<ELF64BE>;
-
-template class elf::GotPltSection<ELF32LE>;
-template class elf::GotPltSection<ELF32BE>;
-template class elf::GotPltSection<ELF64LE>;
-template class elf::GotPltSection<ELF64BE>;
-
-template class elf::IgotPltSection<ELF32LE>;
-template class elf::IgotPltSection<ELF32BE>;
-template class elf::IgotPltSection<ELF64LE>;
-template class elf::IgotPltSection<ELF64BE>;
-
-template class elf::StringTableSection<ELF32LE>;
-template class elf::StringTableSection<ELF32BE>;
-template class elf::StringTableSection<ELF64LE>;
-template class elf::StringTableSection<ELF64BE>;
-
template class elf::DynamicSection<ELF32LE>;
template class elf::DynamicSection<ELF32BE>;
template class elf::DynamicSection<ELF64LE>;
@@ -1948,31 +2400,11 @@ template class elf::SymbolTableSection<ELF32BE>;
template class elf::SymbolTableSection<ELF64LE>;
template class elf::SymbolTableSection<ELF64BE>;
-template class elf::GnuHashTableSection<ELF32LE>;
-template class elf::GnuHashTableSection<ELF32BE>;
-template class elf::GnuHashTableSection<ELF64LE>;
-template class elf::GnuHashTableSection<ELF64BE>;
-
template class elf::HashTableSection<ELF32LE>;
template class elf::HashTableSection<ELF32BE>;
template class elf::HashTableSection<ELF64LE>;
template class elf::HashTableSection<ELF64BE>;
-template class elf::PltSection<ELF32LE>;
-template class elf::PltSection<ELF32BE>;
-template class elf::PltSection<ELF64LE>;
-template class elf::PltSection<ELF64BE>;
-
-template class elf::IpltSection<ELF32LE>;
-template class elf::IpltSection<ELF32BE>;
-template class elf::IpltSection<ELF64LE>;
-template class elf::IpltSection<ELF64BE>;
-
-template class elf::GdbIndexSection<ELF32LE>;
-template class elf::GdbIndexSection<ELF32BE>;
-template class elf::GdbIndexSection<ELF64LE>;
-template class elf::GdbIndexSection<ELF64BE>;
-
template class elf::EhFrameHeader<ELF32LE>;
template class elf::EhFrameHeader<ELF32BE>;
template class elf::EhFrameHeader<ELF64LE>;
@@ -1993,12 +2425,7 @@ template class elf::VersionDefinitionSection<ELF32BE>;
template class elf::VersionDefinitionSection<ELF64LE>;
template class elf::VersionDefinitionSection<ELF64BE>;
-template class elf::MipsRldMapSection<ELF32LE>;
-template class elf::MipsRldMapSection<ELF32BE>;
-template class elf::MipsRldMapSection<ELF64LE>;
-template class elf::MipsRldMapSection<ELF64BE>;
-
-template class elf::ARMExidxSentinelSection<ELF32LE>;
-template class elf::ARMExidxSentinelSection<ELF32BE>;
-template class elf::ARMExidxSentinelSection<ELF64LE>;
-template class elf::ARMExidxSentinelSection<ELF64BE>;
+template class elf::EhFrameSection<ELF32LE>;
+template class elf::EhFrameSection<ELF32BE>;
+template class elf::EhFrameSection<ELF64LE>;
+template class elf::EhFrameSection<ELF64BE>;
diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.h b/contrib/llvm/tools/lld/ELF/SyntheticSections.h
index df67e07..ddd8ca9 100644
--- a/contrib/llvm/tools/lld/ELF/SyntheticSections.h
+++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.h
@@ -6,75 +6,135 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+//
+// Synthetic sections represent chunks of linker-created data. If you
+// need to create a chunk of data that to be included in some section
+// in the result, you probably want to create that as a synthetic section.
+//
+// Synthetic sections are designed as input sections as opposed to
+// output sections because we want to allow them to be manipulated
+// using linker scripts just like other input sections from regular
+// files.
+//
+//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_SYNTHETIC_SECTION_H
#define LLD_ELF_SYNTHETIC_SECTION_H
+#include "EhFrame.h"
#include "GdbIndex.h"
#include "InputSection.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/MC/StringTableBuilder.h"
+#include <set>
+
namespace lld {
namespace elf {
-template <class ELFT> class SyntheticSection : public InputSection<ELFT> {
- typedef typename ELFT::uint uintX_t;
-
+class SyntheticSection : public InputSection {
public:
- SyntheticSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
+ SyntheticSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
StringRef Name)
- : InputSection<ELFT>(Flags, Type, Addralign, ArrayRef<uint8_t>(), Name,
- InputSectionData::Synthetic) {
+ : InputSection(Flags, Type, Alignment, {}, Name,
+ InputSectionBase::Synthetic) {
this->Live = true;
}
virtual ~SyntheticSection() = default;
virtual void writeTo(uint8_t *Buf) = 0;
virtual size_t getSize() const = 0;
- virtual void finalize() {}
+ virtual void finalizeContents() {}
+ // If the section has the SHF_ALLOC flag and the size may be changed if
+ // thunks are added, update the section size.
+ virtual void updateAllocSize() {}
+ // If any additional finalization of contents are needed post thunk creation.
+ virtual void postThunkContents() {}
virtual bool empty() const { return false; }
+ uint64_t getVA() const;
- uintX_t getVA() const {
- return this->OutSec ? this->OutSec->Addr + this->OutSecOff : 0;
+ static bool classof(const SectionBase *D) {
+ return D->kind() == InputSectionBase::Synthetic;
}
+};
- static bool classof(const InputSectionData *D) {
- return D->kind() == InputSectionData::Synthetic;
- }
+struct CieRecord {
+ EhSectionPiece *Piece = nullptr;
+ std::vector<EhSectionPiece *> FdePieces;
};
-template <class ELFT> class GotSection final : public SyntheticSection<ELFT> {
- typedef typename ELFT::uint uintX_t;
+// Section for .eh_frame.
+template <class ELFT> class EhFrameSection final : public SyntheticSection {
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Rel Elf_Rel;
+ typedef typename ELFT::Rela Elf_Rela;
+
+ void updateAlignment(uint64_t Val) {
+ if (Val > this->Alignment)
+ this->Alignment = Val;
+ }
public:
- GotSection();
+ EhFrameSection();
void writeTo(uint8_t *Buf) override;
+ void finalizeContents() override;
+ bool empty() const override { return Sections.empty(); }
+ size_t getSize() const override { return Size; }
+
+ void addSection(InputSectionBase *S);
+
+ size_t NumFdes = 0;
+
+ std::vector<EhInputSection *> Sections;
+
+private:
+ uint64_t Size = 0;
+ template <class RelTy>
+ void addSectionAux(EhInputSection *S, llvm::ArrayRef<RelTy> Rels);
+
+ template <class RelTy>
+ CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
+
+ template <class RelTy>
+ bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
+
+ uint64_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
+
+ std::vector<CieRecord *> Cies;
+
+ // CIE records are uniquified by their contents and personality functions.
+ llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
+};
+
+class GotSection : public SyntheticSection {
+public:
+ GotSection();
size_t getSize() const override { return Size; }
- void finalize() override;
+ void finalizeContents() override;
bool empty() const override;
+ void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody &Sym);
bool addDynTlsEntry(SymbolBody &Sym);
bool addTlsIndex();
- uintX_t getGlobalDynAddr(const SymbolBody &B) const;
- uintX_t getGlobalDynOffset(const SymbolBody &B) const;
+ uint64_t getGlobalDynAddr(const SymbolBody &B) const;
+ uint64_t getGlobalDynOffset(const SymbolBody &B) const;
- uintX_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; }
+ uint64_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; }
uint32_t getTlsIndexOff() const { return TlsIndexOff; }
// Flag to force GOT to be in output if we have relocations
// that relies on its address.
bool HasGotOffRel = false;
-private:
+protected:
size_t NumEntries = 0;
uint32_t TlsIndexOff = -1;
- uintX_t Size = 0;
+ uint64_t Size = 0;
};
// .note.gnu.build-id section.
-template <class ELFT> class BuildIdSection : public SyntheticSection<ELFT> {
+class BuildIdSection : public SyntheticSection {
// First 16 bytes are a header.
static const unsigned HeaderSize = 16;
@@ -92,22 +152,36 @@ private:
uint8_t *HashBuf;
};
-template <class ELFT>
-class MipsGotSection final : public SyntheticSection<ELFT> {
- typedef typename ELFT::uint uintX_t;
+// BssSection is used to reserve space for copy relocations and common symbols.
+// We create three instances of this class for .bss, .bss.rel.ro and "COMMON",
+// that are used for writable symbols, read-only symbols and common symbols,
+// respectively.
+class BssSection final : public SyntheticSection {
+public:
+ BssSection(StringRef Name);
+ void writeTo(uint8_t *) override {}
+ bool empty() const override { return getSize() == 0; }
+ size_t reserveSpace(uint64_t Size, uint32_t Alignment);
+ size_t getSize() const override { return Size; }
+
+private:
+ uint64_t Size = 0;
+};
+class MipsGotSection final : public SyntheticSection {
public:
MipsGotSection();
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return Size; }
- void finalize() override;
+ void updateAllocSize() override;
+ void finalizeContents() override;
bool empty() const override;
- void addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
+ void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr);
bool addDynTlsEntry(SymbolBody &Sym);
bool addTlsIndex();
- uintX_t getPageEntryOffset(const SymbolBody &B, uintX_t Addend) const;
- uintX_t getBodyEntryOffset(const SymbolBody &B, uintX_t Addend) const;
- uintX_t getGlobalDynOffset(const SymbolBody &B) const;
+ uint64_t getPageEntryOffset(const SymbolBody &B, int64_t Addend) const;
+ uint64_t getBodyEntryOffset(const SymbolBody &B, int64_t Addend) const;
+ uint64_t getGlobalDynOffset(const SymbolBody &B) const;
// Returns the symbol which corresponds to the first entry of the global part
// of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
@@ -121,11 +195,11 @@ public:
// Returns offset of TLS part of the MIPS GOT table. This part goes
// after 'local' and 'global' entries.
- uintX_t getTlsOffset() const;
+ uint64_t getTlsOffset() const;
uint32_t getTlsIndexOff() const { return TlsIndexOff; }
- uintX_t getGp() const;
+ uint64_t getGp() const;
private:
// MIPS GOT consists of three parts: local, global and tls. Each part
@@ -171,9 +245,9 @@ private:
uint32_t PageEntriesNum = 0;
// Map output sections referenced by MIPS GOT relocations
// to the first index of "Page" entries allocated for this section.
- llvm::SmallMapVector<const OutputSectionBase *, size_t, 16> PageIndexMap;
+ llvm::SmallMapVector<const OutputSection *, size_t, 16> PageIndexMap;
- typedef std::pair<const SymbolBody *, uintX_t> GotEntry;
+ typedef std::pair<const SymbolBody *, uint64_t> GotEntry;
typedef std::vector<GotEntry> GotEntries;
// Map from Symbol-Addend pair to the GOT index.
llvm::DenseMap<GotEntry, size_t> EntryIndexMap;
@@ -189,13 +263,10 @@ private:
std::vector<const SymbolBody *> TlsEntries;
uint32_t TlsIndexOff = -1;
- uintX_t Size = 0;
+ uint64_t Size = 0;
};
-template <class ELFT>
-class GotPltSection final : public SyntheticSection<ELFT> {
- typedef typename ELFT::uint uintX_t;
-
+class GotPltSection final : public SyntheticSection {
public:
GotPltSection();
void addEntry(SymbolBody &Sym);
@@ -207,14 +278,11 @@ private:
std::vector<const SymbolBody *> Entries;
};
-// The IgotPltSection is a Got associated with the IpltSection for GNU Ifunc
+// The IgotPltSection is a Got associated with the PltSection for GNU Ifunc
// Symbols that will be relocated by Target->IRelativeRel.
// On most Targets the IgotPltSection will immediately follow the GotPltSection
// on ARM the IgotPltSection will immediately follow the GotSection.
-template <class ELFT>
-class IgotPltSection final : public SyntheticSection<ELFT> {
- typedef typename ELFT::uint uintX_t;
-
+class IgotPltSection final : public SyntheticSection {
public:
IgotPltSection();
void addEntry(SymbolBody &Sym);
@@ -226,10 +294,8 @@ private:
std::vector<const SymbolBody *> Entries;
};
-template <class ELFT>
-class StringTableSection final : public SyntheticSection<ELFT> {
+class StringTableSection final : public SyntheticSection {
public:
- typedef typename ELFT::uint uintX_t;
StringTableSection(StringRef Name, bool Dynamic);
unsigned addString(StringRef S, bool HashIt = true);
void writeTo(uint8_t *Buf) override;
@@ -239,54 +305,41 @@ public:
private:
const bool Dynamic;
- // ELF string tables start with a NUL byte, so 1.
- uintX_t Size = 1;
+ uint64_t Size = 0;
llvm::DenseMap<StringRef, unsigned> StringMap;
std::vector<StringRef> Strings;
};
-template <class ELFT> class DynamicReloc {
- typedef typename ELFT::uint uintX_t;
-
+class DynamicReloc {
public:
- DynamicReloc(uint32_t Type, const InputSectionBase<ELFT> *InputSec,
- uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
- uintX_t Addend)
+ DynamicReloc(uint32_t Type, const InputSectionBase *InputSec,
+ uint64_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
+ int64_t Addend)
: Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
UseSymVA(UseSymVA), Addend(Addend) {}
- DynamicReloc(uint32_t Type, const OutputSectionBase *OutputSec,
- uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
- uintX_t Addend)
- : Type(Type), Sym(Sym), OutputSec(OutputSec), OffsetInSec(OffsetInSec),
- UseSymVA(UseSymVA), Addend(Addend) {}
-
- uintX_t getOffset() const;
- uintX_t getAddend() const;
+ uint64_t getOffset() const;
+ int64_t getAddend() const;
uint32_t getSymIndex() const;
- const OutputSectionBase *getOutputSec() const { return OutputSec; }
- const InputSectionBase<ELFT> *getInputSec() const { return InputSec; }
+ const InputSectionBase *getInputSec() const { return InputSec; }
uint32_t Type;
private:
SymbolBody *Sym;
- const InputSectionBase<ELFT> *InputSec = nullptr;
- const OutputSectionBase *OutputSec = nullptr;
- uintX_t OffsetInSec;
+ const InputSectionBase *InputSec = nullptr;
+ uint64_t OffsetInSec;
bool UseSymVA;
- uintX_t Addend;
+ int64_t Addend;
};
-template <class ELFT>
-class DynamicSection final : public SyntheticSection<ELFT> {
+template <class ELFT> class DynamicSection final : public SyntheticSection {
typedef typename ELFT::Dyn Elf_Dyn;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::uint uintX_t;
// The .dynamic section contains information for the dynamic linker.
// The section consists of fixed size entries, which consist of
@@ -295,49 +348,45 @@ class DynamicSection final : public SyntheticSection<ELFT> {
struct Entry {
int32_t Tag;
union {
- OutputSectionBase *OutSec;
- InputSection<ELFT> *InSec;
+ OutputSection *OutSec;
+ InputSection *InSec;
uint64_t Val;
const SymbolBody *Sym;
};
enum KindT { SecAddr, SecSize, SymAddr, PlainInt, InSecAddr } Kind;
- Entry(int32_t Tag, OutputSectionBase *OutSec, KindT Kind = SecAddr)
+ Entry(int32_t Tag, OutputSection *OutSec, KindT Kind = SecAddr)
: Tag(Tag), OutSec(OutSec), Kind(Kind) {}
- Entry(int32_t Tag, InputSection<ELFT> *Sec)
+ Entry(int32_t Tag, InputSection *Sec)
: Tag(Tag), InSec(Sec), Kind(InSecAddr) {}
Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {}
Entry(int32_t Tag, const SymbolBody *Sym)
: Tag(Tag), Sym(Sym), Kind(SymAddr) {}
};
- // finalize() fills this vector with the section contents. finalize()
- // cannot directly create final section contents because when the
- // function is called, symbol or section addresses are not fixed yet.
+ // finalizeContents() fills this vector with the section contents.
std::vector<Entry> Entries;
public:
DynamicSection();
- void finalize() override;
+ void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override { return Size; }
private:
void addEntries();
void add(Entry E) { Entries.push_back(E); }
- uintX_t Size = 0;
+ uint64_t Size = 0;
};
-template <class ELFT>
-class RelocationSection final : public SyntheticSection<ELFT> {
+template <class ELFT> class RelocationSection final : public SyntheticSection {
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
- typedef typename ELFT::uint uintX_t;
public:
RelocationSection(StringRef Name, bool Sort);
- void addReloc(const DynamicReloc<ELFT> &Reloc);
+ void addReloc(const DynamicReloc &Reloc);
unsigned getRelocOffset();
- void finalize() override;
+ void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
bool empty() const override { return Relocs.empty(); }
size_t getSize() const override { return Relocs.size() * this->Entsize; }
@@ -346,7 +395,7 @@ public:
private:
bool Sort;
size_t NumRelativeRelocs = 0;
- std::vector<DynamicReloc<ELFT>> Relocs;
+ std::vector<DynamicReloc> Relocs;
};
struct SymbolTableEntry {
@@ -354,125 +403,99 @@ struct SymbolTableEntry {
size_t StrTabOffset;
};
-template <class ELFT>
-class SymbolTableSection final : public SyntheticSection<ELFT> {
+class SymbolTableBaseSection : public SyntheticSection {
public:
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::SymRange Elf_Sym_Range;
- typedef typename ELFT::uint uintX_t;
- SymbolTableSection(StringTableSection<ELFT> &StrTabSec);
-
- void finalize() override;
- void writeTo(uint8_t *Buf) override;
- size_t getSize() const override { return getNumSymbols() * sizeof(Elf_Sym); }
- void addGlobal(SymbolBody *Body);
- void addLocal(SymbolBody *Body);
- StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; }
+ SymbolTableBaseSection(StringTableSection &StrTabSec);
+ void finalizeContents() override;
+ void postThunkContents() override;
+ size_t getSize() const override { return getNumSymbols() * Entsize; }
+ void addSymbol(SymbolBody *Body);
unsigned getNumSymbols() const { return Symbols.size() + 1; }
size_t getSymbolIndex(SymbolBody *Body);
-
ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
- static const OutputSectionBase *getOutputSection(SymbolBody *Sym);
-
-private:
- void writeLocalSymbols(uint8_t *&Buf);
- void writeGlobalSymbols(uint8_t *Buf);
-
+protected:
// A vector of symbols and their string table offsets.
std::vector<SymbolTableEntry> Symbols;
- StringTableSection<ELFT> &StrTabSec;
+ StringTableSection &StrTabSec;
+};
+
+template <class ELFT>
+class SymbolTableSection final : public SymbolTableBaseSection {
+ typedef typename ELFT::Sym Elf_Sym;
- unsigned NumLocals = 0;
+public:
+ SymbolTableSection(StringTableSection &StrTabSec);
+ void writeTo(uint8_t *Buf) override;
};
// Outputs GNU Hash section. For detailed explanation see:
// https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
-template <class ELFT>
-class GnuHashTableSection final : public SyntheticSection<ELFT> {
- typedef typename ELFT::Off Elf_Off;
- typedef typename ELFT::Word Elf_Word;
- typedef typename ELFT::uint uintX_t;
-
+class GnuHashTableSection final : public SyntheticSection {
public:
GnuHashTableSection();
- void finalize() override;
+ void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
- size_t getSize() const override { return this->Size; }
+ size_t getSize() const override { return Size; }
// Adds symbols to the hash table.
// Sorts the input to satisfy GNU hash section requirements.
void addSymbols(std::vector<SymbolTableEntry> &Symbols);
private:
- static unsigned calcNBuckets(unsigned NumHashed);
- static unsigned calcMaskWords(unsigned NumHashed);
+ size_t getShift2() const { return Config->Is64 ? 6 : 5; }
- void writeHeader(uint8_t *&Buf);
- void writeBloomFilter(uint8_t *&Buf);
+ void writeBloomFilter(uint8_t *Buf);
void writeHashTable(uint8_t *Buf);
- struct SymbolData {
+ struct Entry {
SymbolBody *Body;
- size_t STName;
+ size_t StrTabOffset;
uint32_t Hash;
};
- std::vector<SymbolData> Symbols;
-
- unsigned MaskWords;
- unsigned NBuckets;
- unsigned Shift2;
- uintX_t Size = 0;
+ std::vector<Entry> Symbols;
+ size_t MaskWords;
+ size_t NBuckets = 0;
+ size_t Size = 0;
};
-template <class ELFT>
-class HashTableSection final : public SyntheticSection<ELFT> {
- typedef typename ELFT::Word Elf_Word;
-
+template <class ELFT> class HashTableSection final : public SyntheticSection {
public:
HashTableSection();
- void finalize() override;
+ void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
- size_t getSize() const override { return this->Size; }
+ size_t getSize() const override { return Size; }
private:
size_t Size = 0;
};
-template <class ELFT> class PltSection final : public SyntheticSection<ELFT> {
+// The PltSection is used for both the Plt and Iplt. The former always has a
+// header as its first entry that is used at run-time to resolve lazy binding.
+// The latter is used for GNU Ifunc symbols, that will be subject to a
+// Target->IRelativeRel.
+class PltSection : public SyntheticSection {
public:
- PltSection();
+ PltSection(size_t HeaderSize);
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
- void addEntry(SymbolBody &Sym);
bool empty() const override { return Entries.empty(); }
+ void addSymbols();
-private:
- std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
-};
-
-// The IpltSection is a variant of Plt for recording entries for GNU Ifunc
-// symbols that will be subject to a Target->IRelativeRel
-// The IpltSection immediately follows the Plt section in the Output Section
-template <class ELFT> class IpltSection final : public SyntheticSection<ELFT> {
-public:
- IpltSection();
- void writeTo(uint8_t *Buf) override;
- size_t getSize() const override;
- void addEntry(SymbolBody &Sym);
- bool empty() const override { return Entries.empty(); }
+ template <class ELFT> void addEntry(SymbolBody &Sym);
private:
+ void writeHeader(uint8_t *Buf){};
+ void addHeaderSymbols(){};
+ unsigned getPltRelocOff() const;
std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
+ // Iplt always has HeaderSize of 0, the Plt HeaderSize is always non-zero
+ size_t HeaderSize;
};
-template <class ELFT>
-class GdbIndexSection final : public SyntheticSection<ELFT> {
- typedef typename ELFT::uint uintX_t;
-
+class GdbIndexSection final : public SyntheticSection {
const unsigned OffsetTypeSize = 4;
const unsigned CuListOffset = 6 * OffsetTypeSize;
const unsigned CompilationUnitSize = 16;
@@ -480,27 +503,28 @@ class GdbIndexSection final : public SyntheticSection<ELFT> {
const unsigned SymTabEntrySize = 2 * OffsetTypeSize;
public:
- GdbIndexSection();
- void finalize() override;
+ GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks);
+ void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
bool empty() const override;
- // Pairs of [CU Offset, CU length].
- std::vector<std::pair<uintX_t, uintX_t>> CompilationUnits;
-
- llvm::StringTableBuilder StringPool;
-
+ // Symbol table is a hash table for types and names.
+ // It is the area of gdb index.
GdbHashTab SymbolTable;
- // The CU vector portion of the constant pool.
- std::vector<std::vector<std::pair<uint32_t, uint8_t>>> CuVectors;
+ // CU vector is a part of constant pool area of section.
+ std::vector<std::set<uint32_t>> CuVectors;
- std::vector<AddressEntry<ELFT>> AddressArea;
+ // String pool is also a part of constant pool, it follows CU vectors.
+ llvm::StringTableBuilder StringPool;
+
+ // Each chunk contains information gathered from a debug sections of single
+ // object and used to build different areas of gdb index.
+ std::vector<GdbIndexChunk> Chunks;
private:
- void parseDebugSections();
- void readDwarf(InputSection<ELFT> *I);
+ void buildIndex();
uint32_t CuTypesOffset;
uint32_t SymTabOffset;
@@ -513,6 +537,8 @@ private:
bool Finalized = false;
};
+template <class ELFT> GdbIndexSection *createGdbIndex();
+
// --eh-frame-hdr option tells linker to construct a header for all the
// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
// and also to a PT_GNU_EH_FRAME segment.
@@ -522,10 +548,7 @@ private:
// Detailed info about internals can be found in Ian Lance Taylor's blog:
// http://www.airs.com/blog/archives/460 (".eh_frame")
// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
-template <class ELFT>
-class EhFrameHeader final : public SyntheticSection<ELFT> {
- typedef typename ELFT::uint uintX_t;
-
+template <class ELFT> class EhFrameHeader final : public SyntheticSection {
public:
EhFrameHeader();
void writeTo(uint8_t *Buf) override;
@@ -551,13 +574,13 @@ private:
// The section shall contain an array of Elf_Verdef structures, optionally
// followed by an array of Elf_Verdaux structures.
template <class ELFT>
-class VersionDefinitionSection final : public SyntheticSection<ELFT> {
+class VersionDefinitionSection final : public SyntheticSection {
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Verdaux Elf_Verdaux;
public:
VersionDefinitionSection();
- void finalize() override;
+ void finalizeContents() override;
size_t getSize() const override;
void writeTo(uint8_t *Buf) override;
@@ -574,12 +597,12 @@ private:
// The values 0 and 1 are reserved. All other values are used for versions in
// the own object or in any of the dependencies.
template <class ELFT>
-class VersionTableSection final : public SyntheticSection<ELFT> {
+class VersionTableSection final : public SyntheticSection {
typedef typename ELFT::Versym Elf_Versym;
public:
VersionTableSection();
- void finalize() override;
+ void finalizeContents() override;
size_t getSize() const override;
void writeTo(uint8_t *Buf) override;
bool empty() const override;
@@ -590,8 +613,7 @@ public:
// Elf_Verneed specifies the version requirements for a single DSO, and contains
// a reference to a linked list of Elf_Vernaux data structures which define the
// mapping from version identifiers to version names.
-template <class ELFT>
-class VersionNeedSection final : public SyntheticSection<ELFT> {
+template <class ELFT> class VersionNeedSection final : public SyntheticSection {
typedef typename ELFT::Verneed Elf_Verneed;
typedef typename ELFT::Vernaux Elf_Vernaux;
@@ -604,17 +626,39 @@ class VersionNeedSection final : public SyntheticSection<ELFT> {
public:
VersionNeedSection();
- void addSymbol(SharedSymbol<ELFT> *SS);
- void finalize() override;
+ void addSymbol(SharedSymbol *SS);
+ void finalizeContents() override;
void writeTo(uint8_t *Buf) override;
size_t getSize() const override;
size_t getNeedNum() const { return Needed.size(); }
bool empty() const override;
};
+// MergeSyntheticSection is a class that allows us to put mergeable sections
+// with different attributes in a single output sections. To do that
+// we put them into MergeSyntheticSection synthetic input sections which are
+// attached to regular output sections.
+class MergeSyntheticSection final : public SyntheticSection {
+public:
+ MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags,
+ uint32_t Alignment);
+ void addSection(MergeInputSection *MS);
+ void writeTo(uint8_t *Buf) override;
+ void finalizeContents() override;
+ bool shouldTailMerge() const;
+ size_t getSize() const override;
+
+private:
+ void finalizeTailMerge();
+ void finalizeNoTailMerge();
+
+ llvm::StringTableBuilder Builder;
+ std::vector<MergeInputSection *> Sections;
+};
+
// .MIPS.abiflags section.
template <class ELFT>
-class MipsAbiFlagsSection final : public SyntheticSection<ELFT> {
+class MipsAbiFlagsSection final : public SyntheticSection {
typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags;
public:
@@ -629,8 +673,7 @@ private:
};
// .MIPS.options section.
-template <class ELFT>
-class MipsOptionsSection final : public SyntheticSection<ELFT> {
+template <class ELFT> class MipsOptionsSection final : public SyntheticSection {
typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
@@ -649,8 +692,7 @@ private:
};
// MIPS .reginfo section.
-template <class ELFT>
-class MipsReginfoSection final : public SyntheticSection<ELFT> {
+template <class ELFT> class MipsReginfoSection final : public SyntheticSection {
typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo;
public:
@@ -668,79 +710,92 @@ private:
// of executable file which is pointed to by the DT_MIPS_RLD_MAP entry.
// See "Dynamic section" in Chapter 5 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-template <class ELFT> class MipsRldMapSection : public SyntheticSection<ELFT> {
+class MipsRldMapSection : public SyntheticSection {
public:
MipsRldMapSection();
- size_t getSize() const override { return sizeof(typename ELFT::uint); }
- void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return Config->Wordsize; }
+ void writeTo(uint8_t *Buf) override {}
};
-template <class ELFT> class ARMExidxSentinelSection : public SyntheticSection<ELFT> {
+class ARMExidxSentinelSection : public SyntheticSection {
public:
ARMExidxSentinelSection();
size_t getSize() const override { return 8; }
void writeTo(uint8_t *Buf) override;
};
-template <class ELFT> InputSection<ELFT> *createCommonSection();
-template <class ELFT> InputSection<ELFT> *createInterpSection();
-template <class ELFT> MergeInputSection<ELFT> *createCommentSection();
+// A container for one or more linker generated thunks. Instances of these
+// thunks including ARM interworking and Mips LA25 PI to non-PI thunks.
+class ThunkSection : public SyntheticSection {
+public:
+ // ThunkSection in OS, with desired OutSecOff of Off
+ ThunkSection(OutputSection *OS, uint64_t Off);
+
+ // Add a newly created Thunk to this container:
+ // Thunk is given offset from start of this InputSection
+ // Thunk defines a symbol in this InputSection that can be used as target
+ // of a relocation
+ void addThunk(Thunk *T);
+ size_t getSize() const override { return Size; }
+ void writeTo(uint8_t *Buf) override;
+ InputSection *getTargetInputSection() const;
+
+private:
+ std::vector<const Thunk *> Thunks;
+ size_t Size = 0;
+};
+
+template <class ELFT> InputSection *createCommonSection();
+InputSection *createInterpSection();
+template <class ELFT> MergeInputSection *createCommentSection();
+void decompressAndMergeSections();
+
+SymbolBody *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value,
+ uint64_t Size, InputSectionBase *Section);
// Linker generated sections which can be used as inputs.
-template <class ELFT> struct In {
- static InputSection<ELFT> *ARMAttributes;
- static BuildIdSection<ELFT> *BuildId;
- static InputSection<ELFT> *Common;
- static DynamicSection<ELFT> *Dynamic;
- static StringTableSection<ELFT> *DynStrTab;
- static SymbolTableSection<ELFT> *DynSymTab;
+struct InX {
+ static InputSection *ARMAttributes;
+ static BssSection *Bss;
+ static BssSection *BssRelRo;
+ static BuildIdSection *BuildId;
+ static InputSection *Common;
+ static SyntheticSection *Dynamic;
+ static StringTableSection *DynStrTab;
+ static SymbolTableBaseSection *DynSymTab;
+ static GnuHashTableSection *GnuHashTab;
+ static InputSection *Interp;
+ static GdbIndexSection *GdbIndex;
+ static GotSection *Got;
+ static GotPltSection *GotPlt;
+ static IgotPltSection *IgotPlt;
+ static MipsGotSection *MipsGot;
+ static MipsRldMapSection *MipsRldMap;
+ static PltSection *Plt;
+ static PltSection *Iplt;
+ static StringTableSection *ShStrTab;
+ static StringTableSection *StrTab;
+ static SymbolTableBaseSection *SymTab;
+};
+
+template <class ELFT> struct In : public InX {
static EhFrameHeader<ELFT> *EhFrameHdr;
- static GnuHashTableSection<ELFT> *GnuHashTab;
- static GdbIndexSection<ELFT> *GdbIndex;
- static GotSection<ELFT> *Got;
- static MipsGotSection<ELFT> *MipsGot;
- static GotPltSection<ELFT> *GotPlt;
- static IgotPltSection<ELFT> *IgotPlt;
+ static EhFrameSection<ELFT> *EhFrame;
static HashTableSection<ELFT> *HashTab;
- static InputSection<ELFT> *Interp;
- static MipsRldMapSection<ELFT> *MipsRldMap;
- static PltSection<ELFT> *Plt;
- static IpltSection<ELFT> *Iplt;
static RelocationSection<ELFT> *RelaDyn;
static RelocationSection<ELFT> *RelaPlt;
static RelocationSection<ELFT> *RelaIplt;
- static StringTableSection<ELFT> *ShStrTab;
- static StringTableSection<ELFT> *StrTab;
- static SymbolTableSection<ELFT> *SymTab;
static VersionDefinitionSection<ELFT> *VerDef;
static VersionTableSection<ELFT> *VerSym;
static VersionNeedSection<ELFT> *VerNeed;
};
-template <class ELFT> InputSection<ELFT> *In<ELFT>::ARMAttributes;
-template <class ELFT> BuildIdSection<ELFT> *In<ELFT>::BuildId;
-template <class ELFT> InputSection<ELFT> *In<ELFT>::Common;
-template <class ELFT> DynamicSection<ELFT> *In<ELFT>::Dynamic;
-template <class ELFT> StringTableSection<ELFT> *In<ELFT>::DynStrTab;
-template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::DynSymTab;
template <class ELFT> EhFrameHeader<ELFT> *In<ELFT>::EhFrameHdr;
-template <class ELFT> GdbIndexSection<ELFT> *In<ELFT>::GdbIndex;
-template <class ELFT> GnuHashTableSection<ELFT> *In<ELFT>::GnuHashTab;
-template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
-template <class ELFT> MipsGotSection<ELFT> *In<ELFT>::MipsGot;
-template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt;
-template <class ELFT> IgotPltSection<ELFT> *In<ELFT>::IgotPlt;
+template <class ELFT> EhFrameSection<ELFT> *In<ELFT>::EhFrame;
template <class ELFT> HashTableSection<ELFT> *In<ELFT>::HashTab;
-template <class ELFT> InputSection<ELFT> *In<ELFT>::Interp;
-template <class ELFT> MipsRldMapSection<ELFT> *In<ELFT>::MipsRldMap;
-template <class ELFT> PltSection<ELFT> *In<ELFT>::Plt;
-template <class ELFT> IpltSection<ELFT> *In<ELFT>::Iplt;
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaDyn;
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaPlt;
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaIplt;
-template <class ELFT> StringTableSection<ELFT> *In<ELFT>::ShStrTab;
-template <class ELFT> StringTableSection<ELFT> *In<ELFT>::StrTab;
-template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::SymTab;
template <class ELFT> VersionDefinitionSection<ELFT> *In<ELFT>::VerDef;
template <class ELFT> VersionTableSection<ELFT> *In<ELFT>::VerSym;
template <class ELFT> VersionNeedSection<ELFT> *In<ELFT>::VerNeed;
diff --git a/contrib/llvm/tools/lld/ELF/Target.cpp b/contrib/llvm/tools/lld/ELF/Target.cpp
index 55fcf17..11986ef 100644
--- a/contrib/llvm/tools/lld/ELF/Target.cpp
+++ b/contrib/llvm/tools/lld/ELF/Target.cpp
@@ -27,283 +27,111 @@
#include "Target.h"
#include "Error.h"
#include "InputFiles.h"
-#include "Memory.h"
#include "OutputSections.h"
#include "SymbolTable.h"
#include "Symbols.h"
-#include "SyntheticSections.h"
-#include "Thunks.h"
-#include "Writer.h"
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/ELF.h"
-#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::object;
-using namespace llvm::support::endian;
using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
-std::string lld::toString(uint32_t Type) {
- return getELFRelocationTypeName(elf::Config->EMachine, Type);
-}
-
-namespace lld {
-namespace elf {
-
-TargetInfo *Target;
-
-static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
-static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); }
-
-template <class ELFT> static std::string getErrorLoc(uint8_t *Loc) {
- for (InputSectionData *D : Symtab<ELFT>::X->Sections) {
- auto *IS = dyn_cast_or_null<InputSection<ELFT>>(D);
- if (!IS || !IS->OutSec)
- continue;
-
- uint8_t *ISLoc = cast<OutputSection<ELFT>>(IS->OutSec)->Loc + IS->OutSecOff;
- if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
- return IS->getLocation(Loc - ISLoc) + ": ";
- }
- return "";
-}
-
-static std::string getErrorLocation(uint8_t *Loc) {
- switch (Config->EKind) {
- case ELF32LEKind:
- return getErrorLoc<ELF32LE>(Loc);
- case ELF32BEKind:
- return getErrorLoc<ELF32BE>(Loc);
- case ELF64LEKind:
- return getErrorLoc<ELF64LE>(Loc);
- case ELF64BEKind:
- return getErrorLoc<ELF64BE>(Loc);
- default:
- llvm_unreachable("unknown ELF type");
- }
-}
-
-template <unsigned N>
-static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) {
- if (!isInt<N>(V))
- error(getErrorLocation(Loc) + "relocation " + toString(Type) +
- " out of range");
-}
-
-template <unsigned N>
-static void checkUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
- if (!isUInt<N>(V))
- error(getErrorLocation(Loc) + "relocation " + toString(Type) +
- " out of range");
-}
+TargetInfo *elf::Target;
-template <unsigned N>
-static void checkIntUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
- if (!isInt<N>(V) && !isUInt<N>(V))
- error(getErrorLocation(Loc) + "relocation " + toString(Type) +
- " out of range");
-}
-
-template <unsigned N>
-static void checkAlignment(uint8_t *Loc, uint64_t V, uint32_t Type) {
- if ((V & (N - 1)) != 0)
- error(getErrorLocation(Loc) + "improper alignment for relocation " +
- toString(Type));
+std::string lld::toString(uint32_t Type) {
+ StringRef S = getELFRelocationTypeName(elf::Config->EMachine, Type);
+ if (S == "Unknown")
+ return ("Unknown (" + Twine(Type) + ")").str();
+ return S;
}
-namespace {
-class X86TargetInfo final : public TargetInfo {
-public:
- X86TargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
- void writeGotPltHeader(uint8_t *Buf) const override;
- uint32_t getDynRel(uint32_t Type) const override;
- bool isTlsLocalDynamicRel(uint32_t Type) const override;
- bool isTlsGlobalDynamicRel(uint32_t Type) const override;
- bool isTlsInitialExecRel(uint32_t Type) const override;
- void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
- void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
- void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
- void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
-
- RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
- RelExpr Expr) const override;
- void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
-};
-
-template <class ELFT> class X86_64TargetInfo final : public TargetInfo {
-public:
- X86_64TargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- bool isPicRel(uint32_t Type) const override;
- bool isTlsLocalDynamicRel(uint32_t Type) const override;
- bool isTlsGlobalDynamicRel(uint32_t Type) const override;
- bool isTlsInitialExecRel(uint32_t Type) const override;
- void writeGotPltHeader(uint8_t *Buf) const override;
- void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
- void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
- void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
-
- RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
- RelExpr Expr) const override;
- void relaxGot(uint8_t *Loc, uint64_t Val) const override;
- void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
-
-private:
- void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
- uint8_t ModRm) const;
-};
-
-class PPCTargetInfo final : public TargetInfo {
-public:
- PPCTargetInfo();
- void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
-};
-
-class PPC64TargetInfo final : public TargetInfo {
-public:
- PPC64TargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
- void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
-};
-
-class AArch64TargetInfo final : public TargetInfo {
-public:
- AArch64TargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- bool isPicRel(uint32_t Type) const override;
- bool isTlsInitialExecRel(uint32_t Type) const override;
- void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
- void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
- bool usesOnlyLowPageBits(uint32_t Type) const override;
- void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
- RelExpr Expr) const override;
- void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
-};
-
-class AMDGPUTargetInfo final : public TargetInfo {
-public:
- AMDGPUTargetInfo();
- void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
-};
-
-class ARMTargetInfo final : public TargetInfo {
-public:
- ARMTargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- bool isPicRel(uint32_t Type) const override;
- uint32_t getDynRel(uint32_t Type) const override;
- uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
- bool isTlsLocalDynamicRel(uint32_t Type) const override;
- bool isTlsGlobalDynamicRel(uint32_t Type) const override;
- bool isTlsInitialExecRel(uint32_t Type) const override;
- void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
- void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
- void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
- RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
- const SymbolBody &S) const override;
- void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
-};
-
-template <class ELFT> class MipsTargetInfo final : public TargetInfo {
-public:
- MipsTargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
- bool isPicRel(uint32_t Type) const override;
- uint32_t getDynRel(uint32_t Type) const override;
- bool isTlsLocalDynamicRel(uint32_t Type) const override;
- bool isTlsGlobalDynamicRel(uint32_t Type) const override;
- void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
- void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
- int32_t Index, unsigned RelOff) const override;
- RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
- const SymbolBody &S) const override;
- void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- bool usesOnlyLowPageBits(uint32_t Type) const override;
-};
-} // anonymous namespace
-
-TargetInfo *createTarget() {
+TargetInfo *elf::getTarget() {
switch (Config->EMachine) {
case EM_386:
case EM_IAMCU:
- return make<X86TargetInfo>();
+ return getX86TargetInfo();
case EM_AARCH64:
- return make<AArch64TargetInfo>();
+ return getAArch64TargetInfo();
case EM_AMDGPU:
- return make<AMDGPUTargetInfo>();
+ return getAMDGPUTargetInfo();
case EM_ARM:
- return make<ARMTargetInfo>();
+ return getARMTargetInfo();
+ case EM_AVR:
+ return getAVRTargetInfo();
case EM_MIPS:
switch (Config->EKind) {
case ELF32LEKind:
- return make<MipsTargetInfo<ELF32LE>>();
+ return getMipsTargetInfo<ELF32LE>();
case ELF32BEKind:
- return make<MipsTargetInfo<ELF32BE>>();
+ return getMipsTargetInfo<ELF32BE>();
case ELF64LEKind:
- return make<MipsTargetInfo<ELF64LE>>();
+ return getMipsTargetInfo<ELF64LE>();
case ELF64BEKind:
- return make<MipsTargetInfo<ELF64BE>>();
+ return getMipsTargetInfo<ELF64BE>();
default:
fatal("unsupported MIPS target");
}
case EM_PPC:
- return make<PPCTargetInfo>();
+ return getPPCTargetInfo();
case EM_PPC64:
- return make<PPC64TargetInfo>();
+ return getPPC64TargetInfo();
+ case EM_SPARCV9:
+ return getSPARCV9TargetInfo();
case EM_X86_64:
if (Config->EKind == ELF32LEKind)
- return make<X86_64TargetInfo<ELF32LE>>();
- return make<X86_64TargetInfo<ELF64LE>>();
+ return getX32TargetInfo();
+ return getX86_64TargetInfo();
}
fatal("unknown target machine");
}
+template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) {
+ for (InputSectionBase *D : InputSections) {
+ auto *IS = dyn_cast_or_null<InputSection>(D);
+ if (!IS || !IS->getParent())
+ continue;
+
+ uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff;
+ if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
+ return IS->template getLocation<ELFT>(Loc - ISLoc) + ": ";
+ }
+ return "";
+}
+
+std::string elf::getErrorLocation(const uint8_t *Loc) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return getErrorLoc<ELF32LE>(Loc);
+ case ELF32BEKind:
+ return getErrorLoc<ELF32BE>(Loc);
+ case ELF64LEKind:
+ return getErrorLoc<ELF64LE>(Loc);
+ case ELF64BEKind:
+ return getErrorLoc<ELF64BE>(Loc);
+ default:
+ llvm_unreachable("unknown ELF type");
+ }
+}
+
TargetInfo::~TargetInfo() {}
-uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf,
- uint32_t Type) const {
+int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
return 0;
}
bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
-RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
- const InputFile &File,
- const SymbolBody &S) const {
- return Expr;
+bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
+ const InputFile *File, const SymbolBody &S) const {
+ return false;
}
-bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
-
-bool TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return false; }
-
-bool TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const { return false; }
+bool TargetInfo::inBranchRange(uint32_t RelocType, uint64_t Src,
+ uint64_t Dst) const {
+ return true;
+}
void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
writeGotPlt(Buf, S);
@@ -337,2031 +165,3 @@ void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
llvm_unreachable("Should not have claimed to be relaxable");
}
-
-X86TargetInfo::X86TargetInfo() {
- CopyRel = R_386_COPY;
- GotRel = R_386_GLOB_DAT;
- PltRel = R_386_JUMP_SLOT;
- IRelativeRel = R_386_IRELATIVE;
- RelativeRel = R_386_RELATIVE;
- TlsGotRel = R_386_TLS_TPOFF;
- TlsModuleIndexRel = R_386_TLS_DTPMOD32;
- TlsOffsetRel = R_386_TLS_DTPOFF32;
- GotEntrySize = 4;
- GotPltEntrySize = 4;
- PltEntrySize = 16;
- PltHeaderSize = 16;
- TlsGdRelaxSkip = 2;
-}
-
-RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
- switch (Type) {
- case R_386_16:
- case R_386_32:
- case R_386_TLS_LDO_32:
- return R_ABS;
- case R_386_TLS_GD:
- return R_TLSGD;
- case R_386_TLS_LDM:
- return R_TLSLD;
- case R_386_PLT32:
- return R_PLT_PC;
- case R_386_PC16:
- case R_386_PC32:
- return R_PC;
- case R_386_GOTPC:
- return R_GOTONLY_PC_FROM_END;
- case R_386_TLS_IE:
- return R_GOT;
- case R_386_GOT32:
- case R_386_GOT32X:
- case R_386_TLS_GOTIE:
- return R_GOT_FROM_END;
- case R_386_GOTOFF:
- return R_GOTREL_FROM_END;
- case R_386_TLS_LE:
- return R_TLS;
- case R_386_TLS_LE_32:
- return R_NEG_TLS;
- case R_386_NONE:
- return R_HINT;
- default:
- error("do not know how to handle relocation '" + toString(Type) + "' (" +
- Twine(Type) + ")");
- return R_HINT;
- }
-}
-
-RelExpr X86TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
- RelExpr Expr) const {
- switch (Expr) {
- default:
- return Expr;
- case R_RELAX_TLS_GD_TO_IE:
- return R_RELAX_TLS_GD_TO_IE_END;
- case R_RELAX_TLS_GD_TO_LE:
- return R_RELAX_TLS_GD_TO_LE_NEG;
- }
-}
-
-void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
- write32le(Buf, In<ELF32LE>::Dynamic->getVA());
-}
-
-void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
- // Entries in .got.plt initially points back to the corresponding
- // PLT entries with a fixed offset to skip the first instruction.
- write32le(Buf, S.getPltVA<ELF32LE>() + 6);
-}
-
-void X86TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
- // An x86 entry is the address of the ifunc resolver function.
- write32le(Buf, S.getVA<ELF32LE>());
-}
-
-uint32_t X86TargetInfo::getDynRel(uint32_t Type) const {
- if (Type == R_386_TLS_LE)
- return R_386_TLS_TPOFF;
- if (Type == R_386_TLS_LE_32)
- return R_386_TLS_TPOFF32;
- return Type;
-}
-
-bool X86TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
- return Type == R_386_TLS_GD;
-}
-
-bool X86TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const {
- return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM;
-}
-
-bool X86TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
- return Type == R_386_TLS_IE || Type == R_386_TLS_GOTIE;
-}
-
-void X86TargetInfo::writePltHeader(uint8_t *Buf) const {
- // Executable files and shared object files have
- // separate procedure linkage tables.
- if (Config->Pic) {
- const uint8_t V[] = {
- 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
- 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx)
- 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
- };
- memcpy(Buf, V, sizeof(V));
- return;
- }
-
- const uint8_t PltData[] = {
- 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOT+4)
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOT+8)
- 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
- };
- memcpy(Buf, PltData, sizeof(PltData));
- uint32_t Got = In<ELF32LE>::GotPlt->getVA();
- write32le(Buf + 2, Got + 4);
- write32le(Buf + 8, Got + 8);
-}
-
-void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
- const uint8_t Inst[] = {
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx)
- 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset
- 0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0@PC
- };
- memcpy(Buf, Inst, sizeof(Inst));
-
- // jmp *foo@GOT(%ebx) or jmp *foo_in_GOT
- Buf[1] = Config->Pic ? 0xa3 : 0x25;
- uint32_t Got = In<ELF32LE>::GotPlt->getVA();
- write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
- write32le(Buf + 7, RelOff);
- write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
-}
-
-uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
- uint32_t Type) const {
- switch (Type) {
- default:
- return 0;
- case R_386_16:
- case R_386_PC16:
- return read16le(Buf);
- case R_386_32:
- case R_386_GOT32:
- case R_386_GOT32X:
- case R_386_GOTOFF:
- case R_386_GOTPC:
- case R_386_PC32:
- case R_386_PLT32:
- case R_386_TLS_LE:
- return read32le(Buf);
- }
-}
-
-void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- checkInt<32>(Loc, Val, Type);
-
- // R_386_PC16 and R_386_16 are not part of the current i386 psABI. They are
- // used by 16-bit x86 objects, like boot loaders.
- if (Type == R_386_16 || Type == R_386_PC16) {
- write16le(Loc, Val);
- return;
- }
- write32le(Loc, Val);
-}
-
-void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- // Convert
- // leal x@tlsgd(, %ebx, 1),
- // call __tls_get_addr@plt
- // to
- // movl %gs:0,%eax
- // subl $x@ntpoff,%eax
- const uint8_t Inst[] = {
- 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
- 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax
- };
- memcpy(Loc - 3, Inst, sizeof(Inst));
- relocateOne(Loc + 5, R_386_32, Val);
-}
-
-void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- // Convert
- // leal x@tlsgd(, %ebx, 1),
- // call __tls_get_addr@plt
- // to
- // movl %gs:0, %eax
- // addl x@gotntpoff(%ebx), %eax
- const uint8_t Inst[] = {
- 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
- 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax
- };
- memcpy(Loc - 3, Inst, sizeof(Inst));
- relocateOne(Loc + 5, R_386_32, Val);
-}
-
-// In some conditions, relocations can be optimized to avoid using GOT.
-// This function does that for Initial Exec to Local Exec case.
-void X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- // Ulrich's document section 6.2 says that @gotntpoff can
- // be used with MOVL or ADDL instructions.
- // @indntpoff is similar to @gotntpoff, but for use in
- // position dependent code.
- uint8_t Reg = (Loc[-1] >> 3) & 7;
-
- if (Type == R_386_TLS_IE) {
- if (Loc[-1] == 0xa1) {
- // "movl foo@indntpoff,%eax" -> "movl $foo,%eax"
- // This case is different from the generic case below because
- // this is a 5 byte instruction while below is 6 bytes.
- Loc[-1] = 0xb8;
- } else if (Loc[-2] == 0x8b) {
- // "movl foo@indntpoff,%reg" -> "movl $foo,%reg"
- Loc[-2] = 0xc7;
- Loc[-1] = 0xc0 | Reg;
- } else {
- // "addl foo@indntpoff,%reg" -> "addl $foo,%reg"
- Loc[-2] = 0x81;
- Loc[-1] = 0xc0 | Reg;
- }
- } else {
- assert(Type == R_386_TLS_GOTIE);
- if (Loc[-2] == 0x8b) {
- // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg"
- Loc[-2] = 0xc7;
- Loc[-1] = 0xc0 | Reg;
- } else {
- // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg"
- Loc[-2] = 0x8d;
- Loc[-1] = 0x80 | (Reg << 3) | Reg;
- }
- }
- relocateOne(Loc, R_386_TLS_LE, Val);
-}
-
-void X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- if (Type == R_386_TLS_LDO_32) {
- relocateOne(Loc, R_386_TLS_LE, Val);
- return;
- }
-
- // Convert
- // leal foo(%reg),%eax
- // call ___tls_get_addr
- // to
- // movl %gs:0,%eax
- // nop
- // leal 0(%esi,1),%esi
- const uint8_t Inst[] = {
- 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
- 0x90, // nop
- 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi
- };
- memcpy(Loc - 2, Inst, sizeof(Inst));
-}
-
-template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() {
- CopyRel = R_X86_64_COPY;
- GotRel = R_X86_64_GLOB_DAT;
- PltRel = R_X86_64_JUMP_SLOT;
- RelativeRel = R_X86_64_RELATIVE;
- IRelativeRel = R_X86_64_IRELATIVE;
- TlsGotRel = R_X86_64_TPOFF64;
- TlsModuleIndexRel = R_X86_64_DTPMOD64;
- TlsOffsetRel = R_X86_64_DTPOFF64;
- GotEntrySize = 8;
- GotPltEntrySize = 8;
- PltEntrySize = 16;
- PltHeaderSize = 16;
- TlsGdRelaxSkip = 2;
- // Align to the large page size (known as a superpage or huge page).
- // FreeBSD automatically promotes large, superpage-aligned allocations.
- DefaultImageBase = 0x200000;
-}
-
-template <class ELFT>
-RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
- const SymbolBody &S) const {
- switch (Type) {
- case R_X86_64_32:
- case R_X86_64_32S:
- case R_X86_64_64:
- case R_X86_64_DTPOFF32:
- case R_X86_64_DTPOFF64:
- return R_ABS;
- case R_X86_64_TPOFF32:
- return R_TLS;
- case R_X86_64_TLSLD:
- return R_TLSLD_PC;
- case R_X86_64_TLSGD:
- return R_TLSGD_PC;
- case R_X86_64_SIZE32:
- case R_X86_64_SIZE64:
- return R_SIZE;
- case R_X86_64_PLT32:
- return R_PLT_PC;
- case R_X86_64_PC32:
- case R_X86_64_PC64:
- return R_PC;
- case R_X86_64_GOT32:
- case R_X86_64_GOT64:
- return R_GOT_FROM_END;
- case R_X86_64_GOTPCREL:
- case R_X86_64_GOTPCRELX:
- case R_X86_64_REX_GOTPCRELX:
- case R_X86_64_GOTTPOFF:
- return R_GOT_PC;
- case R_X86_64_NONE:
- return R_HINT;
- default:
- error("do not know how to handle relocation '" + toString(Type) + "' (" +
- Twine(Type) + ")");
- return R_HINT;
- }
-}
-
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
- // The first entry holds the value of _DYNAMIC. It is not clear why that is
- // required, but it is documented in the psabi and the glibc dynamic linker
- // seems to use it (note that this is relevant for linking ld.so, not any
- // other program).
- write64le(Buf, In<ELFT>::Dynamic->getVA());
-}
-
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::writeGotPlt(uint8_t *Buf,
- const SymbolBody &S) const {
- // See comments in X86TargetInfo::writeGotPlt.
- write32le(Buf, S.getPltVA<ELFT>() + 6);
-}
-
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
- const uint8_t PltData[] = {
- 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
- 0x0f, 0x1f, 0x40, 0x00 // nopl 0x0(rax)
- };
- memcpy(Buf, PltData, sizeof(PltData));
- uint64_t Got = In<ELFT>::GotPlt->getVA();
- uint64_t Plt = In<ELFT>::Plt->getVA();
- write32le(Buf + 2, Got - Plt + 2); // GOT+8
- write32le(Buf + 8, Got - Plt + 4); // GOT+16
-}
-
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
- const uint8_t Inst[] = {
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
- 0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index>
- 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0]
- };
- memcpy(Buf, Inst, sizeof(Inst));
-
- write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6);
- write32le(Buf + 7, Index);
- write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
-}
-
-template <class ELFT>
-bool X86_64TargetInfo<ELFT>::isPicRel(uint32_t Type) const {
- return Type != R_X86_64_PC32 && Type != R_X86_64_32;
-}
-
-template <class ELFT>
-bool X86_64TargetInfo<ELFT>::isTlsInitialExecRel(uint32_t Type) const {
- return Type == R_X86_64_GOTTPOFF;
-}
-
-template <class ELFT>
-bool X86_64TargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
- return Type == R_X86_64_TLSGD;
-}
-
-template <class ELFT>
-bool X86_64TargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
- return Type == R_X86_64_DTPOFF32 || Type == R_X86_64_DTPOFF64 ||
- Type == R_X86_64_TLSLD;
-}
-
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- // Convert
- // .byte 0x66
- // leaq x@tlsgd(%rip), %rdi
- // .word 0x6666
- // rex64
- // call __tls_get_addr@plt
- // to
- // mov %fs:0x0,%rax
- // lea x@tpoff,%rax
- const uint8_t Inst[] = {
- 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
- 0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax
- };
- memcpy(Loc - 4, Inst, sizeof(Inst));
- // The original code used a pc relative relocation and so we have to
- // compensate for the -4 in had in the addend.
- relocateOne(Loc + 8, R_X86_64_TPOFF32, Val + 4);
-}
-
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- // Convert
- // .byte 0x66
- // leaq x@tlsgd(%rip), %rdi
- // .word 0x6666
- // rex64
- // call __tls_get_addr@plt
- // to
- // mov %fs:0x0,%rax
- // addq x@tpoff,%rax
- const uint8_t Inst[] = {
- 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
- 0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax
- };
- memcpy(Loc - 4, Inst, sizeof(Inst));
- // Both code sequences are PC relatives, but since we are moving the constant
- // forward by 8 bytes we have to subtract the value by 8.
- relocateOne(Loc + 8, R_X86_64_PC32, Val - 8);
-}
-
-// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
-// R_X86_64_TPOFF32 so that it does not use GOT.
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- uint8_t *Inst = Loc - 3;
- uint8_t Reg = Loc[-1] >> 3;
- uint8_t *RegSlot = Loc - 1;
-
- // Note that ADD with RSP or R12 is converted to ADD instead of LEA
- // because LEA with these registers needs 4 bytes to encode and thus
- // wouldn't fit the space.
-
- if (memcmp(Inst, "\x48\x03\x25", 3) == 0) {
- // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp"
- memcpy(Inst, "\x48\x81\xc4", 3);
- } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) {
- // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12"
- memcpy(Inst, "\x49\x81\xc4", 3);
- } else if (memcmp(Inst, "\x4c\x03", 2) == 0) {
- // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]"
- memcpy(Inst, "\x4d\x8d", 2);
- *RegSlot = 0x80 | (Reg << 3) | Reg;
- } else if (memcmp(Inst, "\x48\x03", 2) == 0) {
- // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg"
- memcpy(Inst, "\x48\x8d", 2);
- *RegSlot = 0x80 | (Reg << 3) | Reg;
- } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) {
- // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]"
- memcpy(Inst, "\x49\xc7", 2);
- *RegSlot = 0xc0 | Reg;
- } else if (memcmp(Inst, "\x48\x8b", 2) == 0) {
- // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg"
- memcpy(Inst, "\x48\xc7", 2);
- *RegSlot = 0xc0 | Reg;
- } else {
- error(getErrorLocation(Loc - 3) +
- "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only");
- }
-
- // The original code used a PC relative relocation.
- // Need to compensate for the -4 it had in the addend.
- relocateOne(Loc, R_X86_64_TPOFF32, Val + 4);
-}
-
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- // Convert
- // leaq bar@tlsld(%rip), %rdi
- // callq __tls_get_addr@PLT
- // leaq bar@dtpoff(%rax), %rcx
- // to
- // .word 0x6666
- // .byte 0x66
- // mov %fs:0,%rax
- // leaq bar@tpoff(%rax), %rcx
- if (Type == R_X86_64_DTPOFF64) {
- write64le(Loc, Val);
- return;
- }
- if (Type == R_X86_64_DTPOFF32) {
- relocateOne(Loc, R_X86_64_TPOFF32, Val);
- return;
- }
-
- const uint8_t Inst[] = {
- 0x66, 0x66, // .word 0x6666
- 0x66, // .byte 0x66
- 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax
- };
- memcpy(Loc - 3, Inst, sizeof(Inst));
-}
-
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- switch (Type) {
- case R_X86_64_32:
- checkUInt<32>(Loc, Val, Type);
- write32le(Loc, Val);
- break;
- case R_X86_64_32S:
- case R_X86_64_TPOFF32:
- case R_X86_64_GOT32:
- case R_X86_64_GOTPCREL:
- case R_X86_64_GOTPCRELX:
- case R_X86_64_REX_GOTPCRELX:
- case R_X86_64_PC32:
- case R_X86_64_GOTTPOFF:
- case R_X86_64_PLT32:
- case R_X86_64_TLSGD:
- case R_X86_64_TLSLD:
- case R_X86_64_DTPOFF32:
- case R_X86_64_SIZE32:
- checkInt<32>(Loc, Val, Type);
- write32le(Loc, Val);
- break;
- case R_X86_64_64:
- case R_X86_64_DTPOFF64:
- case R_X86_64_GLOB_DAT:
- case R_X86_64_PC64:
- case R_X86_64_SIZE64:
- case R_X86_64_GOT64:
- write64le(Loc, Val);
- break;
- default:
- llvm_unreachable("unexpected relocation");
- }
-}
-
-template <class ELFT>
-RelExpr X86_64TargetInfo<ELFT>::adjustRelaxExpr(uint32_t Type,
- const uint8_t *Data,
- RelExpr RelExpr) const {
- if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX)
- return RelExpr;
- const uint8_t Op = Data[-2];
- const uint8_t ModRm = Data[-1];
- // FIXME: When PIC is disabled and foo is defined locally in the
- // lower 32 bit address space, memory operand in mov can be converted into
- // immediate operand. Otherwise, mov must be changed to lea. We support only
- // latter relaxation at this moment.
- if (Op == 0x8b)
- return R_RELAX_GOT_PC;
- // Relax call and jmp.
- if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25))
- return R_RELAX_GOT_PC;
-
- // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor.
- // If PIC then no relaxation is available.
- // We also don't relax test/binop instructions without REX byte,
- // they are 32bit operations and not common to have.
- assert(Type == R_X86_64_REX_GOTPCRELX);
- return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC;
-}
-
-// A subset of relaxations can only be applied for no-PIC. This method
-// handles such relaxations. Instructions encoding information was taken from:
-// "Intel 64 and IA-32 Architectures Software Developer's Manual V2"
-// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
-// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val,
- uint8_t Op, uint8_t ModRm) const {
- const uint8_t Rex = Loc[-3];
- // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg".
- if (Op == 0x85) {
- // See "TEST-Logical Compare" (4-428 Vol. 2B),
- // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension).
-
- // ModR/M byte has form XX YYY ZZZ, where
- // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1).
- // XX has different meanings:
- // 00: The operand's memory address is in reg1.
- // 01: The operand's memory address is reg1 + a byte-sized displacement.
- // 10: The operand's memory address is reg1 + a word-sized displacement.
- // 11: The operand is reg1 itself.
- // If an instruction requires only one operand, the unused reg2 field
- // holds extra opcode bits rather than a register code
- // 0xC0 == 11 000 000 binary.
- // 0x38 == 00 111 000 binary.
- // We transfer reg2 to reg1 here as operand.
- // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3).
- Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte.
-
- // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32
- // See "TEST-Logical Compare" (4-428 Vol. 2B).
- Loc[-2] = 0xf7;
-
- // Move R bit to the B bit in REX byte.
- // REX byte is encoded as 0100WRXB, where
- // 0100 is 4bit fixed pattern.
- // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the
- // default operand size is used (which is 32-bit for most but not all
- // instructions).
- // REX.R This 1-bit value is an extension to the MODRM.reg field.
- // REX.X This 1-bit value is an extension to the SIB.index field.
- // REX.B This 1-bit value is an extension to the MODRM.rm field or the
- // SIB.base field.
- // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A).
- Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
- relocateOne(Loc, R_X86_64_PC32, Val);
- return;
- }
-
- // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub
- // or xor operations.
-
- // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg".
- // Logic is close to one for test instruction above, but we also
- // write opcode extension here, see below for details.
- Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte.
-
- // Primary opcode is 0x81, opcode extension is one of:
- // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB,
- // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP.
- // This value was wrote to MODRM.reg in a line above.
- // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15),
- // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for
- // descriptions about each operation.
- Loc[-2] = 0x81;
- Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
- relocateOne(Loc, R_X86_64_PC32, Val);
-}
-
-template <class ELFT>
-void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
- const uint8_t Op = Loc[-2];
- const uint8_t ModRm = Loc[-1];
-
- // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg".
- if (Op == 0x8b) {
- Loc[-2] = 0x8d;
- relocateOne(Loc, R_X86_64_PC32, Val);
- return;
- }
-
- if (Op != 0xff) {
- // We are relaxing a rip relative to an absolute, so compensate
- // for the old -4 addend.
- assert(!Config->Pic);
- relaxGotNoPic(Loc, Val + 4, Op, ModRm);
- return;
- }
-
- // Convert call/jmp instructions.
- if (ModRm == 0x15) {
- // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo".
- // Instead we convert to "addr32 call foo" where addr32 is an instruction
- // prefix. That makes result expression to be a single instruction.
- Loc[-2] = 0x67; // addr32 prefix
- Loc[-1] = 0xe8; // call
- relocateOne(Loc, R_X86_64_PC32, Val);
- return;
- }
-
- // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop".
- // jmp doesn't return, so it is fine to use nop here, it is just a stub.
- assert(ModRm == 0x25);
- Loc[-2] = 0xe9; // jmp
- Loc[3] = 0x90; // nop
- relocateOne(Loc - 1, R_X86_64_PC32, Val + 1);
-}
-
-// Relocation masks following the #lo(value), #hi(value), #ha(value),
-// #higher(value), #highera(value), #highest(value), and #highesta(value)
-// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi
-// document.
-static uint16_t applyPPCLo(uint64_t V) { return V; }
-static uint16_t applyPPCHi(uint64_t V) { return V >> 16; }
-static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; }
-static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; }
-static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; }
-static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
-static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
-
-PPCTargetInfo::PPCTargetInfo() {}
-
-void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- switch (Type) {
- case R_PPC_ADDR16_HA:
- write16be(Loc, applyPPCHa(Val));
- break;
- case R_PPC_ADDR16_LO:
- write16be(Loc, applyPPCLo(Val));
- break;
- case R_PPC_ADDR32:
- case R_PPC_REL32:
- write32be(Loc, Val);
- break;
- case R_PPC_REL24:
- or32be(Loc, Val & 0x3FFFFFC);
- break;
- default:
- error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
- }
-}
-
-RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
- switch (Type) {
- case R_PPC_REL24:
- case R_PPC_REL32:
- return R_PC;
- default:
- return R_ABS;
- }
-}
-
-PPC64TargetInfo::PPC64TargetInfo() {
- PltRel = GotRel = R_PPC64_GLOB_DAT;
- RelativeRel = R_PPC64_RELATIVE;
- GotEntrySize = 8;
- GotPltEntrySize = 8;
- PltEntrySize = 32;
- PltHeaderSize = 0;
-
- // We need 64K pages (at least under glibc/Linux, the loader won't
- // set different permissions on a finer granularity than that).
- DefaultMaxPageSize = 65536;
-
- // The PPC64 ELF ABI v1 spec, says:
- //
- // It is normally desirable to put segments with different characteristics
- // in separate 256 Mbyte portions of the address space, to give the
- // operating system full paging flexibility in the 64-bit address space.
- //
- // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers
- // use 0x10000000 as the starting address.
- DefaultImageBase = 0x10000000;
-}
-
-static uint64_t PPC64TocOffset = 0x8000;
-
-uint64_t getPPC64TocBase() {
- // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
- // TOC starts where the first of these sections starts. We always create a
- // .got when we see a relocation that uses it, so for us the start is always
- // the .got.
- uint64_t TocVA = In<ELF64BE>::Got->getVA();
-
- // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
- // thus permitting a full 64 Kbytes segment. Note that the glibc startup
- // code (crt1.o) assumes that you can get from the TOC base to the
- // start of the .toc section with only a single (signed) 16-bit relocation.
- return TocVA + PPC64TocOffset;
-}
-
-RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
- switch (Type) {
- default:
- return R_ABS;
- case R_PPC64_TOC16:
- case R_PPC64_TOC16_DS:
- case R_PPC64_TOC16_HA:
- case R_PPC64_TOC16_HI:
- case R_PPC64_TOC16_LO:
- case R_PPC64_TOC16_LO_DS:
- return R_GOTREL;
- case R_PPC64_TOC:
- return R_PPC_TOC;
- case R_PPC64_REL24:
- return R_PPC_PLT_OPD;
- }
-}
-
-void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
- uint64_t Off = GotEntryAddr - getPPC64TocBase();
-
- // FIXME: What we should do, in theory, is get the offset of the function
- // descriptor in the .opd section, and use that as the offset from %r2 (the
- // TOC-base pointer). Instead, we have the GOT-entry offset, and that will
- // be a pointer to the function descriptor in the .opd section. Using
- // this scheme is simpler, but requires an extra indirection per PLT dispatch.
-
- write32be(Buf, 0xf8410028); // std %r2, 40(%r1)
- write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha
- write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11)
- write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12)
- write32be(Buf + 16, 0x7d6903a6); // mtctr %r11
- write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12)
- write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12)
- write32be(Buf + 28, 0x4e800420); // bctr
-}
-
-static std::pair<uint32_t, uint64_t> toAddr16Rel(uint32_t Type, uint64_t Val) {
- uint64_t V = Val - PPC64TocOffset;
- switch (Type) {
- case R_PPC64_TOC16:
- return {R_PPC64_ADDR16, V};
- case R_PPC64_TOC16_DS:
- return {R_PPC64_ADDR16_DS, V};
- case R_PPC64_TOC16_HA:
- return {R_PPC64_ADDR16_HA, V};
- case R_PPC64_TOC16_HI:
- return {R_PPC64_ADDR16_HI, V};
- case R_PPC64_TOC16_LO:
- return {R_PPC64_ADDR16_LO, V};
- case R_PPC64_TOC16_LO_DS:
- return {R_PPC64_ADDR16_LO_DS, V};
- default:
- return {Type, Val};
- }
-}
-
-void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- // For a TOC-relative relocation, proceed in terms of the corresponding
- // ADDR16 relocation type.
- std::tie(Type, Val) = toAddr16Rel(Type, Val);
-
- switch (Type) {
- case R_PPC64_ADDR14: {
- checkAlignment<4>(Loc, Val, Type);
- // Preserve the AA/LK bits in the branch instruction
- uint8_t AALK = Loc[3];
- write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
- break;
- }
- case R_PPC64_ADDR16:
- checkInt<16>(Loc, Val, Type);
- write16be(Loc, Val);
- break;
- case R_PPC64_ADDR16_DS:
- checkInt<16>(Loc, Val, Type);
- write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
- break;
- case R_PPC64_ADDR16_HA:
- case R_PPC64_REL16_HA:
- write16be(Loc, applyPPCHa(Val));
- break;
- case R_PPC64_ADDR16_HI:
- case R_PPC64_REL16_HI:
- write16be(Loc, applyPPCHi(Val));
- break;
- case R_PPC64_ADDR16_HIGHER:
- write16be(Loc, applyPPCHigher(Val));
- break;
- case R_PPC64_ADDR16_HIGHERA:
- write16be(Loc, applyPPCHighera(Val));
- break;
- case R_PPC64_ADDR16_HIGHEST:
- write16be(Loc, applyPPCHighest(Val));
- break;
- case R_PPC64_ADDR16_HIGHESTA:
- write16be(Loc, applyPPCHighesta(Val));
- break;
- case R_PPC64_ADDR16_LO:
- write16be(Loc, applyPPCLo(Val));
- break;
- case R_PPC64_ADDR16_LO_DS:
- case R_PPC64_REL16_LO:
- write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3));
- break;
- case R_PPC64_ADDR32:
- case R_PPC64_REL32:
- checkInt<32>(Loc, Val, Type);
- write32be(Loc, Val);
- break;
- case R_PPC64_ADDR64:
- case R_PPC64_REL64:
- case R_PPC64_TOC:
- write64be(Loc, Val);
- break;
- case R_PPC64_REL24: {
- uint32_t Mask = 0x03FFFFFC;
- checkInt<24>(Loc, Val, Type);
- write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
- break;
- }
- default:
- error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
- }
-}
-
-AArch64TargetInfo::AArch64TargetInfo() {
- CopyRel = R_AARCH64_COPY;
- RelativeRel = R_AARCH64_RELATIVE;
- IRelativeRel = R_AARCH64_IRELATIVE;
- GotRel = R_AARCH64_GLOB_DAT;
- PltRel = R_AARCH64_JUMP_SLOT;
- TlsDescRel = R_AARCH64_TLSDESC;
- TlsGotRel = R_AARCH64_TLS_TPREL64;
- GotEntrySize = 8;
- GotPltEntrySize = 8;
- PltEntrySize = 16;
- PltHeaderSize = 32;
- DefaultMaxPageSize = 65536;
-
- // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant
- // 1 of the tls structures and the tcb size is 16.
- TcbSize = 16;
-}
-
-RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
- const SymbolBody &S) const {
- switch (Type) {
- default:
- return R_ABS;
- case R_AARCH64_TLSDESC_ADR_PAGE21:
- return R_TLSDESC_PAGE;
- case R_AARCH64_TLSDESC_LD64_LO12_NC:
- case R_AARCH64_TLSDESC_ADD_LO12_NC:
- return R_TLSDESC;
- case R_AARCH64_TLSDESC_CALL:
- return R_TLSDESC_CALL;
- case R_AARCH64_TLSLE_ADD_TPREL_HI12:
- case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
- return R_TLS;
- case R_AARCH64_CALL26:
- case R_AARCH64_CONDBR19:
- case R_AARCH64_JUMP26:
- case R_AARCH64_TSTBR14:
- return R_PLT_PC;
- case R_AARCH64_PREL16:
- case R_AARCH64_PREL32:
- case R_AARCH64_PREL64:
- case R_AARCH64_ADR_PREL_LO21:
- return R_PC;
- case R_AARCH64_ADR_PREL_PG_HI21:
- return R_PAGE_PC;
- case R_AARCH64_LD64_GOT_LO12_NC:
- case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- return R_GOT;
- case R_AARCH64_ADR_GOT_PAGE:
- case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- return R_GOT_PAGE_PC;
- }
-}
-
-RelExpr AArch64TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
- RelExpr Expr) const {
- if (Expr == R_RELAX_TLS_GD_TO_IE) {
- if (Type == R_AARCH64_TLSDESC_ADR_PAGE21)
- return R_RELAX_TLS_GD_TO_IE_PAGE_PC;
- return R_RELAX_TLS_GD_TO_IE_ABS;
- }
- return Expr;
-}
-
-bool AArch64TargetInfo::usesOnlyLowPageBits(uint32_t Type) const {
- switch (Type) {
- default:
- return false;
- case R_AARCH64_ADD_ABS_LO12_NC:
- case R_AARCH64_LD64_GOT_LO12_NC:
- case R_AARCH64_LDST128_ABS_LO12_NC:
- case R_AARCH64_LDST16_ABS_LO12_NC:
- case R_AARCH64_LDST32_ABS_LO12_NC:
- case R_AARCH64_LDST64_ABS_LO12_NC:
- case R_AARCH64_LDST8_ABS_LO12_NC:
- case R_AARCH64_TLSDESC_ADD_LO12_NC:
- case R_AARCH64_TLSDESC_LD64_LO12_NC:
- case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- return true;
- }
-}
-
-bool AArch64TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
- return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
- Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
-}
-
-bool AArch64TargetInfo::isPicRel(uint32_t Type) const {
- return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64;
-}
-
-void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
- write64le(Buf, In<ELF64LE>::Plt->getVA());
-}
-
-// Page(Expr) is the page address of the expression Expr, defined
-// as (Expr & ~0xFFF). (This applies even if the machine page size
-// supported by the platform has a different value.)
-uint64_t getAArch64Page(uint64_t Expr) {
- return Expr & (~static_cast<uint64_t>(0xFFF));
-}
-
-void AArch64TargetInfo::writePltHeader(uint8_t *Buf) const {
- const uint8_t PltData[] = {
- 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]!
- 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2]))
- 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))]
- 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2]))
- 0x20, 0x02, 0x1f, 0xd6, // br x17
- 0x1f, 0x20, 0x03, 0xd5, // nop
- 0x1f, 0x20, 0x03, 0xd5, // nop
- 0x1f, 0x20, 0x03, 0xd5 // nop
- };
- memcpy(Buf, PltData, sizeof(PltData));
-
- uint64_t Got = In<ELF64LE>::GotPlt->getVA();
- uint64_t Plt = In<ELF64LE>::Plt->getVA();
- relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
- getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
- relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
- relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
-}
-
-void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
- const uint8_t Inst[] = {
- 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
- 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))]
- 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n]))
- 0x20, 0x02, 0x1f, 0xd6 // br x17
- };
- memcpy(Buf, Inst, sizeof(Inst));
-
- relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
- getAArch64Page(GotEntryAddr) - getAArch64Page(PltEntryAddr));
- relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotEntryAddr);
- relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotEntryAddr);
-}
-
-static void write32AArch64Addr(uint8_t *L, uint64_t Imm) {
- uint32_t ImmLo = (Imm & 0x3) << 29;
- uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
- uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
- write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi);
-}
-
-// Return the bits [Start, End] from Val shifted Start bits.
-// For instance, getBits(0xF0, 4, 8) returns 0xF.
-static uint64_t getBits(uint64_t Val, int Start, int End) {
- uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1;
- return (Val >> Start) & Mask;
-}
-
-// Update the immediate field in a AARCH64 ldr, str, and add instruction.
-static void or32AArch64Imm(uint8_t *L, uint64_t Imm) {
- or32le(L, (Imm & 0xFFF) << 10);
-}
-
-void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- switch (Type) {
- case R_AARCH64_ABS16:
- case R_AARCH64_PREL16:
- checkIntUInt<16>(Loc, Val, Type);
- write16le(Loc, Val);
- break;
- case R_AARCH64_ABS32:
- case R_AARCH64_PREL32:
- checkIntUInt<32>(Loc, Val, Type);
- write32le(Loc, Val);
- break;
- case R_AARCH64_ABS64:
- case R_AARCH64_GLOB_DAT:
- case R_AARCH64_PREL64:
- write64le(Loc, Val);
- break;
- case R_AARCH64_ADD_ABS_LO12_NC:
- or32AArch64Imm(Loc, Val);
- break;
- case R_AARCH64_ADR_GOT_PAGE:
- case R_AARCH64_ADR_PREL_PG_HI21:
- case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- case R_AARCH64_TLSDESC_ADR_PAGE21:
- checkInt<33>(Loc, Val, Type);
- write32AArch64Addr(Loc, Val >> 12);
- break;
- case R_AARCH64_ADR_PREL_LO21:
- checkInt<21>(Loc, Val, Type);
- write32AArch64Addr(Loc, Val);
- break;
- case R_AARCH64_CALL26:
- case R_AARCH64_JUMP26:
- checkInt<28>(Loc, Val, Type);
- or32le(Loc, (Val & 0x0FFFFFFC) >> 2);
- break;
- case R_AARCH64_CONDBR19:
- checkInt<21>(Loc, Val, Type);
- or32le(Loc, (Val & 0x1FFFFC) << 3);
- break;
- case R_AARCH64_LD64_GOT_LO12_NC:
- case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case R_AARCH64_TLSDESC_LD64_LO12_NC:
- checkAlignment<8>(Loc, Val, Type);
- or32le(Loc, (Val & 0xFF8) << 7);
- break;
- case R_AARCH64_LDST8_ABS_LO12_NC:
- or32AArch64Imm(Loc, getBits(Val, 0, 11));
- break;
- case R_AARCH64_LDST16_ABS_LO12_NC:
- or32AArch64Imm(Loc, getBits(Val, 1, 11));
- break;
- case R_AARCH64_LDST32_ABS_LO12_NC:
- or32AArch64Imm(Loc, getBits(Val, 2, 11));
- break;
- case R_AARCH64_LDST64_ABS_LO12_NC:
- or32AArch64Imm(Loc, getBits(Val, 3, 11));
- break;
- case R_AARCH64_LDST128_ABS_LO12_NC:
- or32AArch64Imm(Loc, getBits(Val, 4, 11));
- break;
- case R_AARCH64_MOVW_UABS_G0_NC:
- or32le(Loc, (Val & 0xFFFF) << 5);
- break;
- case R_AARCH64_MOVW_UABS_G1_NC:
- or32le(Loc, (Val & 0xFFFF0000) >> 11);
- break;
- case R_AARCH64_MOVW_UABS_G2_NC:
- or32le(Loc, (Val & 0xFFFF00000000) >> 27);
- break;
- case R_AARCH64_MOVW_UABS_G3:
- or32le(Loc, (Val & 0xFFFF000000000000) >> 43);
- break;
- case R_AARCH64_TSTBR14:
- checkInt<16>(Loc, Val, Type);
- or32le(Loc, (Val & 0xFFFC) << 3);
- break;
- case R_AARCH64_TLSLE_ADD_TPREL_HI12:
- checkInt<24>(Loc, Val, Type);
- or32AArch64Imm(Loc, Val >> 12);
- break;
- case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
- case R_AARCH64_TLSDESC_ADD_LO12_NC:
- or32AArch64Imm(Loc, Val);
- break;
- default:
- error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
- }
-}
-
-void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- // TLSDESC Global-Dynamic relocation are in the form:
- // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
- // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC]
- // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC]
- // .tlsdesccall [R_AARCH64_TLSDESC_CALL]
- // blr x1
- // And it can optimized to:
- // movz x0, #0x0, lsl #16
- // movk x0, #0x10
- // nop
- // nop
- checkUInt<32>(Loc, Val, Type);
-
- switch (Type) {
- case R_AARCH64_TLSDESC_ADD_LO12_NC:
- case R_AARCH64_TLSDESC_CALL:
- write32le(Loc, 0xd503201f); // nop
- return;
- case R_AARCH64_TLSDESC_ADR_PAGE21:
- write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz
- return;
- case R_AARCH64_TLSDESC_LD64_LO12_NC:
- write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk
- return;
- default:
- llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
- }
-}
-
-void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- // TLSDESC Global-Dynamic relocation are in the form:
- // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21]
- // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC]
- // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC]
- // .tlsdesccall [R_AARCH64_TLSDESC_CALL]
- // blr x1
- // And it can optimized to:
- // adrp x0, :gottprel:v
- // ldr x0, [x0, :gottprel_lo12:v]
- // nop
- // nop
-
- switch (Type) {
- case R_AARCH64_TLSDESC_ADD_LO12_NC:
- case R_AARCH64_TLSDESC_CALL:
- write32le(Loc, 0xd503201f); // nop
- break;
- case R_AARCH64_TLSDESC_ADR_PAGE21:
- write32le(Loc, 0x90000000); // adrp
- relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val);
- break;
- case R_AARCH64_TLSDESC_LD64_LO12_NC:
- write32le(Loc, 0xf9400000); // ldr
- relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val);
- break;
- default:
- llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
- }
-}
-
-void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- checkUInt<32>(Loc, Val, Type);
-
- if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
- // Generate MOVZ.
- uint32_t RegNo = read32le(Loc) & 0x1f;
- write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5));
- return;
- }
- if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) {
- // Generate MOVK.
- uint32_t RegNo = read32le(Loc) & 0x1f;
- write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5));
- return;
- }
- llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
-}
-
-AMDGPUTargetInfo::AMDGPUTargetInfo() {
- RelativeRel = R_AMDGPU_REL64;
- GotRel = R_AMDGPU_ABS64;
- GotEntrySize = 8;
-}
-
-void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- switch (Type) {
- case R_AMDGPU_ABS32:
- case R_AMDGPU_GOTPCREL:
- case R_AMDGPU_GOTPCREL32_LO:
- case R_AMDGPU_REL32:
- case R_AMDGPU_REL32_LO:
- write32le(Loc, Val);
- break;
- case R_AMDGPU_ABS64:
- write64le(Loc, Val);
- break;
- case R_AMDGPU_GOTPCREL32_HI:
- case R_AMDGPU_REL32_HI:
- write32le(Loc, Val >> 32);
- break;
- default:
- error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
- }
-}
-
-RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
- switch (Type) {
- case R_AMDGPU_ABS32:
- case R_AMDGPU_ABS64:
- return R_ABS;
- case R_AMDGPU_REL32:
- case R_AMDGPU_REL32_LO:
- case R_AMDGPU_REL32_HI:
- return R_PC;
- case R_AMDGPU_GOTPCREL:
- case R_AMDGPU_GOTPCREL32_LO:
- case R_AMDGPU_GOTPCREL32_HI:
- return R_GOT_PC;
- default:
- fatal("do not know how to handle relocation " + Twine(Type));
- }
-}
-
-ARMTargetInfo::ARMTargetInfo() {
- CopyRel = R_ARM_COPY;
- RelativeRel = R_ARM_RELATIVE;
- IRelativeRel = R_ARM_IRELATIVE;
- GotRel = R_ARM_GLOB_DAT;
- PltRel = R_ARM_JUMP_SLOT;
- TlsGotRel = R_ARM_TLS_TPOFF32;
- TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
- TlsOffsetRel = R_ARM_TLS_DTPOFF32;
- GotEntrySize = 4;
- GotPltEntrySize = 4;
- PltEntrySize = 16;
- PltHeaderSize = 20;
- // ARM uses Variant 1 TLS
- TcbSize = 8;
- NeedsThunks = true;
-}
-
-RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
- switch (Type) {
- default:
- return R_ABS;
- case R_ARM_THM_JUMP11:
- return R_PC;
- case R_ARM_CALL:
- case R_ARM_JUMP24:
- case R_ARM_PC24:
- case R_ARM_PLT32:
- case R_ARM_PREL31:
- case R_ARM_THM_JUMP19:
- case R_ARM_THM_JUMP24:
- case R_ARM_THM_CALL:
- return R_PLT_PC;
- case R_ARM_GOTOFF32:
- // (S + A) - GOT_ORG
- return R_GOTREL;
- case R_ARM_GOT_BREL:
- // GOT(S) + A - GOT_ORG
- return R_GOT_OFF;
- case R_ARM_GOT_PREL:
- case R_ARM_TLS_IE32:
- // GOT(S) + A - P
- return R_GOT_PC;
- case R_ARM_TARGET1:
- return Config->Target1Rel ? R_PC : R_ABS;
- case R_ARM_TARGET2:
- if (Config->Target2 == Target2Policy::Rel)
- return R_PC;
- if (Config->Target2 == Target2Policy::Abs)
- return R_ABS;
- return R_GOT_PC;
- case R_ARM_TLS_GD32:
- return R_TLSGD_PC;
- case R_ARM_TLS_LDM32:
- return R_TLSLD_PC;
- case R_ARM_BASE_PREL:
- // B(S) + A - P
- // FIXME: currently B(S) assumed to be .got, this may not hold for all
- // platforms.
- return R_GOTONLY_PC;
- case R_ARM_MOVW_PREL_NC:
- case R_ARM_MOVT_PREL:
- case R_ARM_REL32:
- case R_ARM_THM_MOVW_PREL_NC:
- case R_ARM_THM_MOVT_PREL:
- return R_PC;
- case R_ARM_NONE:
- return R_HINT;
- case R_ARM_TLS_LE32:
- return R_TLS;
- }
-}
-
-bool ARMTargetInfo::isPicRel(uint32_t Type) const {
- return (Type == R_ARM_TARGET1 && !Config->Target1Rel) ||
- (Type == R_ARM_ABS32);
-}
-
-uint32_t ARMTargetInfo::getDynRel(uint32_t Type) const {
- if (Type == R_ARM_TARGET1 && !Config->Target1Rel)
- return R_ARM_ABS32;
- if (Type == R_ARM_ABS32)
- return Type;
- // Keep it going with a dummy value so that we can find more reloc errors.
- return R_ARM_ABS32;
-}
-
-void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
- write32le(Buf, In<ELF32LE>::Plt->getVA());
-}
-
-void ARMTargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
- // An ARM entry is the address of the ifunc resolver function.
- write32le(Buf, S.getVA<ELF32LE>());
-}
-
-void ARMTargetInfo::writePltHeader(uint8_t *Buf) const {
- const uint8_t PltData[] = {
- 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]!
- 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2
- 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr
- 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8]
- 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8
- };
- memcpy(Buf, PltData, sizeof(PltData));
- uint64_t GotPlt = In<ELF32LE>::GotPlt->getVA();
- uint64_t L1 = In<ELF32LE>::Plt->getVA() + 8;
- write32le(Buf + 16, GotPlt - L1 - 8);
-}
-
-void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
- // FIXME: Using simple code sequence with simple relocations.
- // There is a more optimal sequence but it requires support for the group
- // relocations. See ELF for the ARM Architecture Appendix A.3
- const uint8_t PltData[] = {
- 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2
- 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
- 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip]
- 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8
- };
- memcpy(Buf, PltData, sizeof(PltData));
- uint64_t L1 = PltEntryAddr + 4;
- write32le(Buf + 12, GotEntryAddr - L1 - 8);
-}
-
-RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
- const InputFile &File,
- const SymbolBody &S) const {
- // If S is an undefined weak symbol in an executable we don't need a Thunk.
- // In a DSO calls to undefined symbols, including weak ones get PLT entries
- // which may need a thunk.
- if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak()
- && !Config->Shared)
- return Expr;
- // A state change from ARM to Thumb and vice versa must go through an
- // interworking thunk if the relocation type is not R_ARM_CALL or
- // R_ARM_THM_CALL.
- switch (RelocType) {
- case R_ARM_PC24:
- case R_ARM_PLT32:
- case R_ARM_JUMP24:
- // Source is ARM, all PLT entries are ARM so no interworking required.
- // Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
- if (Expr == R_PC && ((S.getVA<ELF32LE>() & 1) == 1))
- return R_THUNK_PC;
- break;
- case R_ARM_THM_JUMP19:
- case R_ARM_THM_JUMP24:
- // Source is Thumb, all PLT entries are ARM so interworking is required.
- // Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
- if (Expr == R_PLT_PC)
- return R_THUNK_PLT_PC;
- if ((S.getVA<ELF32LE>() & 1) == 0)
- return R_THUNK_PC;
- break;
- }
- return Expr;
-}
-
-void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- switch (Type) {
- case R_ARM_ABS32:
- case R_ARM_BASE_PREL:
- case R_ARM_GLOB_DAT:
- case R_ARM_GOTOFF32:
- case R_ARM_GOT_BREL:
- case R_ARM_GOT_PREL:
- case R_ARM_REL32:
- case R_ARM_RELATIVE:
- case R_ARM_TARGET1:
- case R_ARM_TARGET2:
- case R_ARM_TLS_GD32:
- case R_ARM_TLS_IE32:
- case R_ARM_TLS_LDM32:
- case R_ARM_TLS_LDO32:
- case R_ARM_TLS_LE32:
- case R_ARM_TLS_TPOFF32:
- write32le(Loc, Val);
- break;
- case R_ARM_TLS_DTPMOD32:
- write32le(Loc, 1);
- break;
- case R_ARM_PREL31:
- checkInt<31>(Loc, Val, Type);
- write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));
- break;
- case R_ARM_CALL:
- // R_ARM_CALL is used for BL and BLX instructions, depending on the
- // value of bit 0 of Val, we must select a BL or BLX instruction
- if (Val & 1) {
- // If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
- // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
- checkInt<26>(Loc, Val, Type);
- write32le(Loc, 0xfa000000 | // opcode
- ((Val & 2) << 23) | // H
- ((Val >> 2) & 0x00ffffff)); // imm24
- break;
- }
- if ((read32le(Loc) & 0xfe000000) == 0xfa000000)
- // BLX (always unconditional) instruction to an ARM Target, select an
- // unconditional BL.
- write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff));
- // fall through as BL encoding is shared with B
- case R_ARM_JUMP24:
- case R_ARM_PC24:
- case R_ARM_PLT32:
- checkInt<26>(Loc, Val, Type);
- write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff));
- break;
- case R_ARM_THM_JUMP11:
- checkInt<12>(Loc, Val, Type);
- write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff));
- break;
- case R_ARM_THM_JUMP19:
- // Encoding T3: Val = S:J2:J1:imm6:imm11:0
- checkInt<21>(Loc, Val, Type);
- write16le(Loc,
- (read16le(Loc) & 0xfbc0) | // opcode cond
- ((Val >> 10) & 0x0400) | // S
- ((Val >> 12) & 0x003f)); // imm6
- write16le(Loc + 2,
- 0x8000 | // opcode
- ((Val >> 8) & 0x0800) | // J2
- ((Val >> 5) & 0x2000) | // J1
- ((Val >> 1) & 0x07ff)); // imm11
- break;
- case R_ARM_THM_CALL:
- // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the
- // value of bit 0 of Val, we must select a BL or BLX instruction
- if ((Val & 1) == 0) {
- // Ensure BLX destination is 4-byte aligned. As BLX instruction may
- // only be two byte aligned. This must be done before overflow check
- Val = alignTo(Val, 4);
- }
- // Bit 12 is 0 for BLX, 1 for BL
- write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12);
- // Fall through as rest of encoding is the same as B.W
- case R_ARM_THM_JUMP24:
- // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
- // FIXME: Use of I1 and I2 require v6T2ops
- checkInt<25>(Loc, Val, Type);
- write16le(Loc,
- 0xf000 | // opcode
- ((Val >> 14) & 0x0400) | // S
- ((Val >> 12) & 0x03ff)); // imm10
- write16le(Loc + 2,
- (read16le(Loc + 2) & 0xd000) | // opcode
- (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1
- (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2
- ((Val >> 1) & 0x07ff)); // imm11
- break;
- case R_ARM_MOVW_ABS_NC:
- case R_ARM_MOVW_PREL_NC:
- write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) |
- (Val & 0x0fff));
- break;
- case R_ARM_MOVT_ABS:
- case R_ARM_MOVT_PREL:
- checkInt<32>(Loc, Val, Type);
- write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
- (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
- break;
- case R_ARM_THM_MOVT_ABS:
- case R_ARM_THM_MOVT_PREL:
- // Encoding T1: A = imm4:i:imm3:imm8
- checkInt<32>(Loc, Val, Type);
- write16le(Loc,
- 0xf2c0 | // opcode
- ((Val >> 17) & 0x0400) | // i
- ((Val >> 28) & 0x000f)); // imm4
- write16le(Loc + 2,
- (read16le(Loc + 2) & 0x8f00) | // opcode
- ((Val >> 12) & 0x7000) | // imm3
- ((Val >> 16) & 0x00ff)); // imm8
- break;
- case R_ARM_THM_MOVW_ABS_NC:
- case R_ARM_THM_MOVW_PREL_NC:
- // Encoding T3: A = imm4:i:imm3:imm8
- write16le(Loc,
- 0xf240 | // opcode
- ((Val >> 1) & 0x0400) | // i
- ((Val >> 12) & 0x000f)); // imm4
- write16le(Loc + 2,
- (read16le(Loc + 2) & 0x8f00) | // opcode
- ((Val << 4) & 0x7000) | // imm3
- (Val & 0x00ff)); // imm8
- break;
- default:
- error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
- }
-}
-
-uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
- uint32_t Type) const {
- switch (Type) {
- default:
- return 0;
- case R_ARM_ABS32:
- case R_ARM_BASE_PREL:
- case R_ARM_GOTOFF32:
- case R_ARM_GOT_BREL:
- case R_ARM_GOT_PREL:
- case R_ARM_REL32:
- case R_ARM_TARGET1:
- case R_ARM_TARGET2:
- case R_ARM_TLS_GD32:
- case R_ARM_TLS_LDM32:
- case R_ARM_TLS_LDO32:
- case R_ARM_TLS_IE32:
- case R_ARM_TLS_LE32:
- return SignExtend64<32>(read32le(Buf));
- case R_ARM_PREL31:
- return SignExtend64<31>(read32le(Buf));
- case R_ARM_CALL:
- case R_ARM_JUMP24:
- case R_ARM_PC24:
- case R_ARM_PLT32:
- return SignExtend64<26>(read32le(Buf) << 2);
- case R_ARM_THM_JUMP11:
- return SignExtend64<12>(read16le(Buf) << 1);
- case R_ARM_THM_JUMP19: {
- // Encoding T3: A = S:J2:J1:imm10:imm6:0
- uint16_t Hi = read16le(Buf);
- uint16_t Lo = read16le(Buf + 2);
- return SignExtend64<20>(((Hi & 0x0400) << 10) | // S
- ((Lo & 0x0800) << 8) | // J2
- ((Lo & 0x2000) << 5) | // J1
- ((Hi & 0x003f) << 12) | // imm6
- ((Lo & 0x07ff) << 1)); // imm11:0
- }
- case R_ARM_THM_CALL:
- case R_ARM_THM_JUMP24: {
- // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0
- // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)
- // FIXME: I1 and I2 require v6T2ops
- uint16_t Hi = read16le(Buf);
- uint16_t Lo = read16le(Buf + 2);
- return SignExtend64<24>(((Hi & 0x0400) << 14) | // S
- (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1
- (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2
- ((Hi & 0x003ff) << 12) | // imm0
- ((Lo & 0x007ff) << 1)); // imm11:0
- }
- // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and
- // MOVT is in the range -32768 <= A < 32768
- case R_ARM_MOVW_ABS_NC:
- case R_ARM_MOVT_ABS:
- case R_ARM_MOVW_PREL_NC:
- case R_ARM_MOVT_PREL: {
- uint64_t Val = read32le(Buf) & 0x000f0fff;
- return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff));
- }
- case R_ARM_THM_MOVW_ABS_NC:
- case R_ARM_THM_MOVT_ABS:
- case R_ARM_THM_MOVW_PREL_NC:
- case R_ARM_THM_MOVT_PREL: {
- // Encoding T3: A = imm4:i:imm3:imm8
- uint16_t Hi = read16le(Buf);
- uint16_t Lo = read16le(Buf + 2);
- return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4
- ((Hi & 0x0400) << 1) | // i
- ((Lo & 0x7000) >> 4) | // imm3
- (Lo & 0x00ff)); // imm8
- }
- }
-}
-
-bool ARMTargetInfo::isTlsLocalDynamicRel(uint32_t Type) const {
- return Type == R_ARM_TLS_LDO32 || Type == R_ARM_TLS_LDM32;
-}
-
-bool ARMTargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
- return Type == R_ARM_TLS_GD32;
-}
-
-bool ARMTargetInfo::isTlsInitialExecRel(uint32_t Type) const {
- return Type == R_ARM_TLS_IE32;
-}
-
-template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
- GotPltHeaderEntriesNum = 2;
- DefaultMaxPageSize = 65536;
- GotEntrySize = sizeof(typename ELFT::uint);
- GotPltEntrySize = sizeof(typename ELFT::uint);
- PltEntrySize = 16;
- PltHeaderSize = 32;
- CopyRel = R_MIPS_COPY;
- PltRel = R_MIPS_JUMP_SLOT;
- NeedsThunks = true;
- if (ELFT::Is64Bits) {
- RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
- TlsGotRel = R_MIPS_TLS_TPREL64;
- TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64;
- TlsOffsetRel = R_MIPS_TLS_DTPREL64;
- } else {
- RelativeRel = R_MIPS_REL32;
- TlsGotRel = R_MIPS_TLS_TPREL32;
- TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32;
- TlsOffsetRel = R_MIPS_TLS_DTPREL32;
- }
-}
-
-template <class ELFT>
-RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
- const SymbolBody &S) const {
- // See comment in the calculateMipsRelChain.
- if (ELFT::Is64Bits || Config->MipsN32Abi)
- Type &= 0xff;
- switch (Type) {
- default:
- return R_ABS;
- case R_MIPS_JALR:
- return R_HINT;
- case R_MIPS_GPREL16:
- case R_MIPS_GPREL32:
- return R_MIPS_GOTREL;
- case R_MIPS_26:
- return R_PLT;
- case R_MIPS_HI16:
- case R_MIPS_LO16:
- case R_MIPS_GOT_OFST:
- // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
- // offset between start of function and 'gp' value which by default
- // equal to the start of .got section. In that case we consider these
- // relocations as relative.
- if (&S == ElfSym<ELFT>::MipsGpDisp)
- return R_PC;
- return R_ABS;
- case R_MIPS_PC32:
- case R_MIPS_PC16:
- case R_MIPS_PC19_S2:
- case R_MIPS_PC21_S2:
- case R_MIPS_PC26_S2:
- case R_MIPS_PCHI16:
- case R_MIPS_PCLO16:
- return R_PC;
- case R_MIPS_GOT16:
- if (S.isLocal())
- return R_MIPS_GOT_LOCAL_PAGE;
- // fallthrough
- case R_MIPS_CALL16:
- case R_MIPS_GOT_DISP:
- case R_MIPS_TLS_GOTTPREL:
- return R_MIPS_GOT_OFF;
- case R_MIPS_CALL_HI16:
- case R_MIPS_CALL_LO16:
- case R_MIPS_GOT_HI16:
- case R_MIPS_GOT_LO16:
- return R_MIPS_GOT_OFF32;
- case R_MIPS_GOT_PAGE:
- return R_MIPS_GOT_LOCAL_PAGE;
- case R_MIPS_TLS_GD:
- return R_MIPS_TLSGD;
- case R_MIPS_TLS_LDM:
- return R_MIPS_TLSLD;
- }
-}
-
-template <class ELFT> bool MipsTargetInfo<ELFT>::isPicRel(uint32_t Type) const {
- return Type == R_MIPS_32 || Type == R_MIPS_64;
-}
-
-template <class ELFT>
-uint32_t MipsTargetInfo<ELFT>::getDynRel(uint32_t Type) const {
- return RelativeRel;
-}
-
-template <class ELFT>
-bool MipsTargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
- return Type == R_MIPS_TLS_LDM;
-}
-
-template <class ELFT>
-bool MipsTargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
- return Type == R_MIPS_TLS_GD;
-}
-
-template <class ELFT>
-void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
- write32<ELFT::TargetEndianness>(Buf, In<ELFT>::Plt->getVA());
-}
-
-template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
-static int64_t getPcRelocAddend(const uint8_t *Loc) {
- uint32_t Instr = read32<E>(Loc);
- uint32_t Mask = 0xffffffff >> (32 - BSIZE);
- return SignExtend64<BSIZE + SHIFT>((Instr & Mask) << SHIFT);
-}
-
-template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
-static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) {
- uint32_t Mask = 0xffffffff >> (32 - BSIZE);
- uint32_t Instr = read32<E>(Loc);
- if (SHIFT > 0)
- checkAlignment<(1 << SHIFT)>(Loc, V, Type);
- checkInt<BSIZE + SHIFT>(Loc, V, Type);
- write32<E>(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask));
-}
-
-template <endianness E> static void writeMipsHi16(uint8_t *Loc, uint64_t V) {
- uint32_t Instr = read32<E>(Loc);
- uint16_t Res = ((V + 0x8000) >> 16) & 0xffff;
- write32<E>(Loc, (Instr & 0xffff0000) | Res);
-}
-
-template <endianness E> static void writeMipsHigher(uint8_t *Loc, uint64_t V) {
- uint32_t Instr = read32<E>(Loc);
- uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff;
- write32<E>(Loc, (Instr & 0xffff0000) | Res);
-}
-
-template <endianness E> static void writeMipsHighest(uint8_t *Loc, uint64_t V) {
- uint32_t Instr = read32<E>(Loc);
- uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff;
- write32<E>(Loc, (Instr & 0xffff0000) | Res);
-}
-
-template <endianness E> static void writeMipsLo16(uint8_t *Loc, uint64_t V) {
- uint32_t Instr = read32<E>(Loc);
- write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
-}
-
-template <class ELFT> static bool isMipsR6() {
- const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
- uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH;
- return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
-}
-
-template <class ELFT>
-void MipsTargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
- const endianness E = ELFT::TargetEndianness;
- if (Config->MipsN32Abi) {
- write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
- write32<E>(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14)
- write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
- write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14
- } else {
- write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
- write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
- write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
- write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28
- }
- write32<E>(Buf + 16, 0x03e07825); // move $15, $31
- write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
- write32<E>(Buf + 24, 0x0320f809); // jalr $25
- write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
- uint64_t Got = In<ELFT>::GotPlt->getVA();
- writeMipsHi16<E>(Buf, Got);
- writeMipsLo16<E>(Buf + 4, Got);
- writeMipsLo16<E>(Buf + 8, Got);
-}
-
-template <class ELFT>
-void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
- uint64_t PltEntryAddr, int32_t Index,
- unsigned RelOff) const {
- const endianness E = ELFT::TargetEndianness;
- write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
- write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
- // jr $25
- write32<E>(Buf + 8, isMipsR6<ELFT>() ? 0x03200009 : 0x03200008);
- write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
- writeMipsHi16<E>(Buf, GotEntryAddr);
- writeMipsLo16<E>(Buf + 4, GotEntryAddr);
- writeMipsLo16<E>(Buf + 12, GotEntryAddr);
-}
-
-template <class ELFT>
-RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type,
- const InputFile &File,
- const SymbolBody &S) const {
- // Any MIPS PIC code function is invoked with its address in register $t9.
- // So if we have a branch instruction from non-PIC code to the PIC one
- // we cannot make the jump directly and need to create a small stubs
- // to save the target function address.
- // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (Type != R_MIPS_26)
- return Expr;
- auto *F = dyn_cast<ELFFileBase<ELFT>>(&File);
- if (!F)
- return Expr;
- // If current file has PIC code, LA25 stub is not required.
- if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
- return Expr;
- auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
- // LA25 is required if target file has PIC code
- // or target symbol is a PIC symbol.
- return D && D->isMipsPIC() ? R_THUNK_ABS : Expr;
-}
-
-template <class ELFT>
-uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
- uint32_t Type) const {
- const endianness E = ELFT::TargetEndianness;
- switch (Type) {
- default:
- return 0;
- case R_MIPS_32:
- case R_MIPS_GPREL32:
- case R_MIPS_TLS_DTPREL32:
- case R_MIPS_TLS_TPREL32:
- return read32<E>(Buf);
- case R_MIPS_26:
- // FIXME (simon): If the relocation target symbol is not a PLT entry
- // we should use another expression for calculation:
- // ((A << 2) | (P & 0xf0000000)) >> 2
- return SignExtend64<28>((read32<E>(Buf) & 0x3ffffff) << 2);
- case R_MIPS_GPREL16:
- case R_MIPS_LO16:
- case R_MIPS_PCLO16:
- case R_MIPS_TLS_DTPREL_HI16:
- case R_MIPS_TLS_DTPREL_LO16:
- case R_MIPS_TLS_TPREL_HI16:
- case R_MIPS_TLS_TPREL_LO16:
- return SignExtend64<16>(read32<E>(Buf));
- case R_MIPS_PC16:
- return getPcRelocAddend<E, 16, 2>(Buf);
- case R_MIPS_PC19_S2:
- return getPcRelocAddend<E, 19, 2>(Buf);
- case R_MIPS_PC21_S2:
- return getPcRelocAddend<E, 21, 2>(Buf);
- case R_MIPS_PC26_S2:
- return getPcRelocAddend<E, 26, 2>(Buf);
- case R_MIPS_PC32:
- return getPcRelocAddend<E, 32, 0>(Buf);
- }
-}
-
-static std::pair<uint32_t, uint64_t>
-calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) {
- // MIPS N64 ABI packs multiple relocations into the single relocation
- // record. In general, all up to three relocations can have arbitrary
- // types. In fact, Clang and GCC uses only a few combinations. For now,
- // we support two of them. That is allow to pass at least all LLVM
- // test suite cases.
- // <any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16
- // <any relocation> / R_MIPS_64 / R_MIPS_NONE
- // The first relocation is a 'real' relocation which is calculated
- // using the corresponding symbol's value. The second and the third
- // relocations used to modify result of the first one: extend it to
- // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation
- // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf
- uint32_t Type2 = (Type >> 8) & 0xff;
- uint32_t Type3 = (Type >> 16) & 0xff;
- if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE)
- return std::make_pair(Type, Val);
- if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE)
- return std::make_pair(Type2, Val);
- if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
- return std::make_pair(Type3, -Val);
- error(getErrorLocation(Loc) + "unsupported relocations combination " +
- Twine(Type));
- return std::make_pair(Type & 0xff, Val);
-}
-
-template <class ELFT>
-void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
- uint64_t Val) const {
- const endianness E = ELFT::TargetEndianness;
- // Thread pointer and DRP offsets from the start of TLS data area.
- // https://www.linux-mips.org/wiki/NPTL
- if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 ||
- Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64)
- Val -= 0x8000;
- else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 ||
- Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64)
- Val -= 0x7000;
- if (ELFT::Is64Bits || Config->MipsN32Abi)
- std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
- switch (Type) {
- case R_MIPS_32:
- case R_MIPS_GPREL32:
- case R_MIPS_TLS_DTPREL32:
- case R_MIPS_TLS_TPREL32:
- write32<E>(Loc, Val);
- break;
- case R_MIPS_64:
- case R_MIPS_TLS_DTPREL64:
- case R_MIPS_TLS_TPREL64:
- write64<E>(Loc, Val);
- break;
- case R_MIPS_26:
- write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff));
- break;
- case R_MIPS_GOT_DISP:
- case R_MIPS_GOT_PAGE:
- case R_MIPS_GOT16:
- case R_MIPS_GPREL16:
- case R_MIPS_TLS_GD:
- case R_MIPS_TLS_LDM:
- checkInt<16>(Loc, Val, Type);
- // fallthrough
- case R_MIPS_CALL16:
- case R_MIPS_CALL_LO16:
- case R_MIPS_GOT_LO16:
- case R_MIPS_GOT_OFST:
- case R_MIPS_LO16:
- case R_MIPS_PCLO16:
- case R_MIPS_TLS_DTPREL_LO16:
- case R_MIPS_TLS_GOTTPREL:
- case R_MIPS_TLS_TPREL_LO16:
- writeMipsLo16<E>(Loc, Val);
- break;
- case R_MIPS_CALL_HI16:
- case R_MIPS_GOT_HI16:
- case R_MIPS_HI16:
- case R_MIPS_PCHI16:
- case R_MIPS_TLS_DTPREL_HI16:
- case R_MIPS_TLS_TPREL_HI16:
- writeMipsHi16<E>(Loc, Val);
- break;
- case R_MIPS_HIGHER:
- writeMipsHigher<E>(Loc, Val);
- break;
- case R_MIPS_HIGHEST:
- writeMipsHighest<E>(Loc, Val);
- break;
- case R_MIPS_JALR:
- // Ignore this optimization relocation for now
- break;
- case R_MIPS_PC16:
- applyMipsPcReloc<E, 16, 2>(Loc, Type, Val);
- break;
- case R_MIPS_PC19_S2:
- applyMipsPcReloc<E, 19, 2>(Loc, Type, Val);
- break;
- case R_MIPS_PC21_S2:
- applyMipsPcReloc<E, 21, 2>(Loc, Type, Val);
- break;
- case R_MIPS_PC26_S2:
- applyMipsPcReloc<E, 26, 2>(Loc, Type, Val);
- break;
- case R_MIPS_PC32:
- applyMipsPcReloc<E, 32, 0>(Loc, Type, Val);
- break;
- default:
- error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
- }
-}
-
-template <class ELFT>
-bool MipsTargetInfo<ELFT>::usesOnlyLowPageBits(uint32_t Type) const {
- return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST;
-}
-}
-}
diff --git a/contrib/llvm/tools/lld/ELF/Target.h b/contrib/llvm/tools/lld/ELF/Target.h
index 752f9cd..1658a81 100644
--- a/contrib/llvm/tools/lld/ELF/Target.h
+++ b/contrib/llvm/tools/lld/ELF/Target.h
@@ -10,28 +10,25 @@
#ifndef LLD_ELF_TARGET_H
#define LLD_ELF_TARGET_H
+#include "Error.h"
#include "InputSection.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/Object/ELF.h"
-#include <memory>
-
namespace lld {
+std::string toString(uint32_t RelType);
+
namespace elf {
class InputFile;
class SymbolBody;
class TargetInfo {
public:
- virtual bool isTlsInitialExecRel(uint32_t Type) const;
- virtual bool isTlsLocalDynamicRel(uint32_t Type) const;
- virtual bool isTlsGlobalDynamicRel(uint32_t Type) const;
virtual bool isPicRel(uint32_t Type) const { return true; }
virtual uint32_t getDynRel(uint32_t Type) const { return Type; }
virtual void writeGotPltHeader(uint8_t *Buf) const {}
virtual void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {};
virtual void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const;
- virtual uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const;
+ virtual int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const;
// If lazy binding is supported, the first entry of the PLT has code
// to call the dynamic linker to resolve PLT entries the first time
@@ -41,7 +38,8 @@ public:
virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {}
-
+ virtual void addPltHeaderSymbols(InputSectionBase *IS) const {}
+ virtual void addPltSymbols(InputSectionBase *IS, uint64_t Off) const {}
// Returns true if a relocation only uses the low bits of a value such that
// all those bits are in in the same page. For example, if the relocation
// only uses the low 12 bits in a system with 4k pages. If this is true, the
@@ -50,15 +48,14 @@ public:
virtual bool usesOnlyLowPageBits(uint32_t Type) const;
// Decide whether a Thunk is needed for the relocation from File
- // targeting S. Returns one of:
- // Expr if there is no Thunk required
- // R_THUNK_ABS if thunk is required and expression is absolute
- // R_THUNK_PC if thunk is required and expression is pc rel
- // R_THUNK_PLT_PC if thunk is required to PLT entry and expression is pc rel
- virtual RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType,
- const InputFile &File,
- const SymbolBody &S) const;
- virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0;
+ // targeting S.
+ virtual bool needsThunk(RelExpr Expr, uint32_t RelocType,
+ const InputFile *File, const SymbolBody &S) const;
+ // Return true if we can reach Dst from Src with Relocation RelocType
+ virtual bool inBranchRange(uint32_t RelocType, uint64_t Src,
+ uint64_t Dst) const;
+ virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const = 0;
virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
virtual ~TargetInfo();
@@ -72,6 +69,10 @@ public:
// Given that, the smallest value that can be used in here is 0x10000.
uint64_t DefaultImageBase = 0x10000;
+ // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for
+ // end of .got
+ uint64_t GotBaseSymOff = 0;
+
uint32_t CopyRel;
uint32_t GotRel;
uint32_t PltRel;
@@ -95,6 +96,10 @@ public:
bool NeedsThunks = false;
+ // A 4-byte field corresponding to one or more trap instructions, used to pad
+ // executable OutputSections.
+ uint32_t TrapInstr = 0;
+
virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data,
RelExpr Expr) const;
virtual void relaxGot(uint8_t *Loc, uint64_t Val) const;
@@ -104,14 +109,54 @@ public:
virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
};
+TargetInfo *getAArch64TargetInfo();
+TargetInfo *getAMDGPUTargetInfo();
+TargetInfo *getARMTargetInfo();
+TargetInfo *getAVRTargetInfo();
+TargetInfo *getPPC64TargetInfo();
+TargetInfo *getPPCTargetInfo();
+TargetInfo *getSPARCV9TargetInfo();
+TargetInfo *getX32TargetInfo();
+TargetInfo *getX86TargetInfo();
+TargetInfo *getX86_64TargetInfo();
+template <class ELFT> TargetInfo *getMipsTargetInfo();
+
+std::string getErrorLocation(const uint8_t *Loc);
+
uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t Expr);
extern TargetInfo *Target;
-TargetInfo *createTarget();
+TargetInfo *getTarget();
+
+template <unsigned N>
+static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) {
+ if (!llvm::isInt<N>(V))
+ error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) +
+ " out of range");
}
-std::string toString(uint32_t RelType);
+template <unsigned N>
+static void checkUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
+ if (!llvm::isUInt<N>(V))
+ error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) +
+ " out of range");
+}
+
+template <unsigned N>
+static void checkIntUInt(uint8_t *Loc, uint64_t V, uint32_t Type) {
+ if (!llvm::isInt<N>(V) && !llvm::isUInt<N>(V))
+ error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) +
+ " out of range");
+}
+
+template <unsigned N>
+static void checkAlignment(uint8_t *Loc, uint64_t V, uint32_t Type) {
+ if ((V & (N - 1)) != 0)
+ error(getErrorLocation(Loc) + "improper alignment for relocation " +
+ lld::toString(Type));
}
+} // namespace elf
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/Threads.h b/contrib/llvm/tools/lld/ELF/Threads.h
index c03e152..9feb868 100644
--- a/contrib/llvm/tools/lld/ELF/Threads.h
+++ b/contrib/llvm/tools/lld/ELF/Threads.h
@@ -15,7 +15,7 @@
//
// That said, we don't want to do "too clever" things using threads.
// Complex multi-threaded algorithms are sometimes extremely hard to
-// justify the correctness and can easily mess up the entire design.
+// reason about and can easily mess up the entire design.
//
// Fortunately, when a linker links large programs (when the link time is
// most critical), it spends most of the time to work on massive number of
@@ -34,7 +34,7 @@
// instead of std::for_each (or a plain for loop). Because tasks are
// completely independent from each other, we can run them in parallel
// without any coordination between them. That's very easy to understand
-// and justify.
+// and reason about.
//
// For the cases such as the latter, we can use parallel algorithms to
// deal with massive data. We have to write code for a tailored algorithm
@@ -61,30 +61,28 @@
#include "Config.h"
-#include "lld/Core/Parallel.h"
-#include <algorithm>
+#include "llvm/Support/Parallel.h"
#include <functional>
namespace lld {
namespace elf {
template <class IterTy, class FuncTy>
-void forEach(IterTy Begin, IterTy End, FuncTy Fn) {
+void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn) {
if (Config->Threads)
- parallel_for_each(Begin, End, Fn);
+ for_each(llvm::parallel::par, Begin, End, Fn);
else
- std::for_each(Begin, End, Fn);
+ for_each(llvm::parallel::seq, Begin, End, Fn);
}
-inline void forLoop(size_t Begin, size_t End, std::function<void(size_t)> Fn) {
- if (Config->Threads) {
- parallel_for(Begin, End, Fn);
- } else {
- for (size_t I = Begin; I < End; ++I)
- Fn(I);
- }
-}
-}
+inline void parallelForEachN(size_t Begin, size_t End,
+ std::function<void(size_t)> Fn) {
+ if (Config->Threads)
+ for_each_n(llvm::parallel::par, Begin, End, Fn);
+ else
+ for_each_n(llvm::parallel::seq, Begin, End, Fn);
}
+} // namespace elf
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/ELF/Thunks.cpp b/contrib/llvm/tools/lld/ELF/Thunks.cpp
index 397a0ee..07289d0 100644
--- a/contrib/llvm/tools/lld/ELF/Thunks.cpp
+++ b/contrib/llvm/tools/lld/ELF/Thunks.cpp
@@ -28,9 +28,10 @@
#include "Memory.h"
#include "OutputSections.h"
#include "Symbols.h"
+#include "SyntheticSections.h"
#include "Target.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
@@ -49,149 +50,195 @@ namespace {
// Specific ARM Thunk implementations. The naming convention is:
// Source State, TargetState, Target Requirement, ABS or PI, Range
-template <class ELFT>
-class ARMToThumbV7ABSLongThunk final : public Thunk<ELFT> {
+class ARMV7ABSLongThunk final : public Thunk {
public:
- ARMToThumbV7ABSLongThunk(const SymbolBody &Dest,
- const InputSection<ELFT> &Owner)
- : Thunk<ELFT>(Dest, Owner) {}
+ ARMV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) {}
uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
};
-template <class ELFT> class ARMToThumbV7PILongThunk final : public Thunk<ELFT> {
+class ARMV7PILongThunk final : public Thunk {
public:
- ARMToThumbV7PILongThunk(const SymbolBody &Dest,
- const InputSection<ELFT> &Owner)
- : Thunk<ELFT>(Dest, Owner) {}
+ ARMV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) {}
uint32_t size() const override { return 16; }
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
};
-template <class ELFT>
-class ThumbToARMV7ABSLongThunk final : public Thunk<ELFT> {
+class ThumbV7ABSLongThunk final : public Thunk {
public:
- ThumbToARMV7ABSLongThunk(const SymbolBody &Dest,
- const InputSection<ELFT> &Owner)
- : Thunk<ELFT>(Dest, Owner) {}
+ ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) { Alignment = 2; }
uint32_t size() const override { return 10; }
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
};
-template <class ELFT> class ThumbToARMV7PILongThunk final : public Thunk<ELFT> {
+class ThumbV7PILongThunk final : public Thunk {
public:
- ThumbToARMV7PILongThunk(const SymbolBody &Dest,
- const InputSection<ELFT> &Owner)
- : Thunk<ELFT>(Dest, Owner) {}
+ ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) { Alignment = 2; }
uint32_t size() const override { return 12; }
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
};
// MIPS LA25 thunk
-template <class ELFT> class MipsThunk final : public Thunk<ELFT> {
+class MipsThunk final : public Thunk {
public:
- MipsThunk(const SymbolBody &Dest, const InputSection<ELFT> &Owner)
- : Thunk<ELFT>(Dest, Owner) {}
+ MipsThunk(const SymbolBody &Dest) : Thunk(Dest) {}
uint32_t size() const override { return 16; }
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
+ void addSymbols(ThunkSection &IS) override;
+ InputSection *getTargetInputSection() const override;
};
} // end anonymous namespace
// ARM Target Thunks
-template <class ELFT> static uint64_t getARMThunkDestVA(const SymbolBody &S) {
- uint64_t V = S.isInPlt() ? S.getPltVA<ELFT>() : S.getVA<ELFT>();
+static uint64_t getARMThunkDestVA(const SymbolBody &S) {
+ uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA();
return SignExtend64<32>(V);
}
-template <class ELFT>
-void ARMToThumbV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
+void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
0x1c, 0xff, 0x2f, 0xe1, // bx ip
};
- uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
+ uint64_t S = getARMThunkDestVA(Destination);
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S);
Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S);
}
-template <class ELFT>
-void ThumbToARMV7ABSLongThunk<ELFT>::writeTo(uint8_t *Buf) const {
+void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) {
+ ThunkSym = addSyntheticLocal(
+ Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
+ Offset, size(), &IS);
+ addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS);
+}
+
+bool ARMV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
0x60, 0x47, // bx ip
};
- uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
+ uint64_t S = getARMThunkDestVA(Destination);
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S);
Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S);
}
-template <class ELFT>
-void ARMToThumbV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
+void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) {
+ ThunkSym = addSyntheticLocal(
+ Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC,
+ Offset | 0x1, size(), &IS);
+ addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
+}
+
+bool ThumbV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // ARM branch relocations can't use BLX
+ return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 &&
+ RelocType != R_ARM_PLT32;
+}
+
+void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8)
0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P+4) +8)
0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
0x1c, 0xff, 0x2f, 0xe1, // bx r12
};
- uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
- uint64_t P = this->getVA();
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = ThunkSym->getVA();
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16);
Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12);
}
-template <class ELFT>
-void ThumbToARMV7PILongThunk<ELFT>::writeTo(uint8_t *Buf) const {
+void ARMV7PILongThunk::addSymbols(ThunkSection &IS) {
+ ThunkSym = addSyntheticLocal(
+ Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC,
+ Offset, size(), &IS);
+ addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS);
+}
+
+bool ARMV7PILongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const {
const uint8_t Data[] = {
0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P+4) + 4)
0xfc, 0x44, // L1: add r12, pc
0x60, 0x47, // bx r12
};
- uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
- uint64_t P = this->getVA();
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = ThunkSym->getVA() & ~0x1;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12);
Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8);
}
+void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
+ ThunkSym = addSyntheticLocal(
+ Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC,
+ Offset | 0x1, size(), &IS);
+ addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS);
+}
+
+bool ThumbV7PILongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // ARM branch relocations can't use BLX
+ return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 &&
+ RelocType != R_ARM_PLT32;
+}
+
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
-template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const {
- const endianness E = ELFT::TargetEndianness;
-
- uint64_t S = this->Destination.template getVA<ELFT>();
- write32<E>(Buf, 0x3c190000); // lui $25, %hi(func)
- write32<E>(Buf + 4, 0x08000000 | (S >> 2)); // j func
- write32<E>(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
- write32<E>(Buf + 12, 0x00000000); // nop
+void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {
+ uint64_t S = Destination.getVA();
+ write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func)
+ write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j func
+ write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func)
+ write32(Buf + 12, 0x00000000, Config->Endianness); // nop
Target->relocateOne(Buf, R_MIPS_HI16, S);
Target->relocateOne(Buf + 8, R_MIPS_LO16, S);
}
-template <class ELFT>
-Thunk<ELFT>::Thunk(const SymbolBody &D, const InputSection<ELFT> &O)
- : Destination(D), Owner(O), Offset(O.getThunkOff() + O.getThunksSize()) {}
+void MipsThunk::addSymbols(ThunkSection &IS) {
+ ThunkSym =
+ addSyntheticLocal(Saver.save("__LA25Thunk_" + Destination.getName()),
+ STT_FUNC, Offset, size(), &IS);
+}
-template <class ELFT> typename ELFT::uint Thunk<ELFT>::getVA() const {
- return Owner.OutSec->Addr + Owner.OutSecOff + Offset;
+InputSection *MipsThunk::getTargetInputSection() const {
+ auto *DR = dyn_cast<DefinedRegular>(&Destination);
+ return dyn_cast<InputSection>(DR->Section);
}
-template <class ELFT> Thunk<ELFT>::~Thunk() = default;
+Thunk::Thunk(const SymbolBody &D) : Destination(D), Offset(0) {}
+
+Thunk::~Thunk() = default;
// Creates a thunk for Thumb-ARM interworking.
-template <class ELFT>
-static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S,
- InputSection<ELFT> &IS) {
+static Thunk *addThunkArm(uint32_t Reloc, SymbolBody &S) {
// ARM relocations need ARM to Thumb interworking Thunks.
// Thumb relocations need Thumb to ARM relocations.
// Use position independent Thunks if we require position independent code.
@@ -200,76 +247,27 @@ static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S,
case R_ARM_PLT32:
case R_ARM_JUMP24:
if (Config->Pic)
- return new (BAlloc) ARMToThumbV7PILongThunk<ELFT>(S, IS);
- return new (BAlloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS);
+ return make<ARMV7PILongThunk>(S);
+ return make<ARMV7ABSLongThunk>(S);
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
if (Config->Pic)
- return new (BAlloc) ThumbToARMV7PILongThunk<ELFT>(S, IS);
- return new (BAlloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS);
+ return make<ThumbV7PILongThunk>(S);
+ return make<ThumbV7ABSLongThunk>(S);
}
fatal("unrecognized relocation type");
}
-template <class ELFT>
-static void addThunkARM(uint32_t Reloc, SymbolBody &S, InputSection<ELFT> &IS) {
- // Only one Thunk supported per symbol.
- if (S.hasThunk<ELFT>())
- return;
-
- // ARM Thunks are added to the same InputSection as the relocation. This
- // isn't strictly necessary but it makes it more likely that a limited range
- // branch can reach the Thunk, and it makes Thunks to the PLT section easier
- Thunk<ELFT> *T = createThunkArm(Reloc, S, IS);
- IS.addThunk(T);
- if (auto *Sym = dyn_cast<DefinedRegular<ELFT>>(&S))
- Sym->ThunkData = T;
- else if (auto *Sym = dyn_cast<SharedSymbol<ELFT>>(&S))
- Sym->ThunkData = T;
- else if (auto *Sym = dyn_cast<Undefined<ELFT>>(&S))
- Sym->ThunkData = T;
- else
- fatal("symbol not DefinedRegular or Shared");
-}
+static Thunk *addThunkMips(SymbolBody &S) { return make<MipsThunk>(S); }
-template <class ELFT>
-static void addThunkMips(uint32_t RelocType, SymbolBody &S,
- InputSection<ELFT> &IS) {
- // Only one Thunk supported per symbol.
- if (S.hasThunk<ELFT>())
- return;
-
- // Mips Thunks are added to the InputSection defining S.
- auto *R = cast<DefinedRegular<ELFT>>(&S);
- auto *Sec = cast<InputSection<ELFT>>(R->Section);
- auto *T = new (BAlloc) MipsThunk<ELFT>(S, *Sec);
- Sec->addThunk(T);
- R->ThunkData = T;
-}
-
-template <class ELFT>
-void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &IS) {
+Thunk *addThunk(uint32_t RelocType, SymbolBody &S) {
if (Config->EMachine == EM_ARM)
- addThunkARM<ELFT>(RelocType, S, IS);
+ return addThunkArm(RelocType, S);
else if (Config->EMachine == EM_MIPS)
- addThunkMips<ELFT>(RelocType, S, IS);
- else
- llvm_unreachable("add Thunk only supported for ARM and Mips");
+ return addThunkMips(S);
+ llvm_unreachable("add Thunk only supported for ARM and Mips");
+ return nullptr;
}
-template void addThunk<ELF32LE>(uint32_t, SymbolBody &,
- InputSection<ELF32LE> &);
-template void addThunk<ELF32BE>(uint32_t, SymbolBody &,
- InputSection<ELF32BE> &);
-template void addThunk<ELF64LE>(uint32_t, SymbolBody &,
- InputSection<ELF64LE> &);
-template void addThunk<ELF64BE>(uint32_t, SymbolBody &,
- InputSection<ELF64BE> &);
-
-template class Thunk<ELF32LE>;
-template class Thunk<ELF32BE>;
-template class Thunk<ELF64LE>;
-template class Thunk<ELF64BE>;
-
} // end namespace elf
} // end namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/Thunks.h b/contrib/llvm/tools/lld/ELF/Thunks.h
index b937d79..21eba69 100644
--- a/contrib/llvm/tools/lld/ELF/Thunks.h
+++ b/contrib/llvm/tools/lld/ELF/Thunks.h
@@ -15,8 +15,7 @@
namespace lld {
namespace elf {
class SymbolBody;
-template <class ELFT> class InputSection;
-
+class ThunkSection;
// Class to describe an instance of a Thunk.
// A Thunk is a code-sequence inserted by the linker in between a caller and
// the callee. The relocation to the callee is redirected to the Thunk, which
@@ -24,31 +23,39 @@ template <class ELFT> class InputSection;
// include transferring control from non-pi to pi and changing state on
// targets like ARM.
//
-// Thunks can be created for DefinedRegular and Shared Symbols. The Thunk
-// is stored in a field of the Symbol Destination.
-// Thunks to be written to an InputSection are recorded by the InputSection.
-template <class ELFT> class Thunk {
- typedef typename ELFT::uint uintX_t;
-
+// Thunks can be created for DefinedRegular, Shared and Undefined Symbols.
+// Thunks are assigned to synthetic ThunkSections
+class Thunk {
public:
- Thunk(const SymbolBody &Destination, const InputSection<ELFT> &Owner);
+ Thunk(const SymbolBody &Destination);
virtual ~Thunk();
virtual uint32_t size() const { return 0; }
- virtual void writeTo(uint8_t *Buf) const {}
- uintX_t getVA() const;
+ virtual void writeTo(uint8_t *Buf, ThunkSection &IS) const {}
+
+ // All Thunks must define at least one symbol ThunkSym so that we can
+ // redirect relocations to it.
+ virtual void addSymbols(ThunkSection &IS) {}
+
+ // Some Thunks must be placed immediately before their Target as they elide
+ // a branch and fall through to the first Symbol in the Target.
+ virtual InputSection *getTargetInputSection() const { return nullptr; }
+
+ // To reuse a Thunk the caller as identified by the RelocType must be
+ // compatible with it.
+ virtual bool isCompatibleWith(uint32_t RelocType) const { return true; }
-protected:
+ // The alignment requirement for this Thunk, defaults to the size of the
+ // typical code section alignment.
const SymbolBody &Destination;
- const InputSection<ELFT> &Owner;
+ SymbolBody *ThunkSym;
uint64_t Offset;
+ uint32_t Alignment = 4;
};
-// For a Relocation to symbol S from InputSection Src, create a Thunk and
-// update the fields of S and the InputSection that the Thunk body will be
-// written to. At present there are implementations for ARM and Mips Thunks.
-template <class ELFT>
-void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &Src);
+// For a Relocation to symbol S create a Thunk to be added to a synthetic
+// ThunkSection. At present there are implementations for ARM and Mips Thunks.
+Thunk *addThunk(uint32_t RelocType, SymbolBody &S);
} // namespace elf
} // namespace lld
diff --git a/contrib/llvm/tools/lld/ELF/Writer.cpp b/contrib/llvm/tools/lld/ELF/Writer.cpp
index 01f6f8e..1853f99 100644
--- a/contrib/llvm/tools/lld/ELF/Writer.cpp
+++ b/contrib/llvm/tools/lld/ELF/Writer.cpp
@@ -9,7 +9,9 @@
#include "Writer.h"
#include "Config.h"
+#include "Filesystem.h"
#include "LinkerScript.h"
+#include "MapFile.h"
#include "Memory.h"
#include "OutputSections.h"
#include "Relocations.h"
@@ -17,13 +19,12 @@
#include "SymbolTable.h"
#include "SyntheticSections.h"
#include "Target.h"
+#include "Threads.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <climits>
-#include <thread>
using namespace llvm;
using namespace llvm::ELF;
@@ -38,22 +39,20 @@ namespace {
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
- typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Ehdr Elf_Ehdr;
typedef typename ELFT::Phdr Elf_Phdr;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::SymRange Elf_Sym_Range;
- typedef typename ELFT::Rela Elf_Rela;
+
void run();
private:
+ void clearOutputSections();
void createSyntheticSections();
void copyLocalSymbols();
+ void addSectionSymbols();
void addReservedSymbols();
- void addInputSec(InputSectionBase<ELFT> *S);
void createSections();
- void forEachRelSec(std::function<void(InputSectionBase<ELFT> &)> Fn);
+ void forEachRelSec(std::function<void(InputSectionBase &)> Fn);
void sortSections();
void finalizeSections();
void addPredefinedSections();
@@ -61,13 +60,11 @@ private:
std::vector<PhdrEntry> createPhdrs();
void removeEmptyPTLoad();
void addPtArmExid(std::vector<PhdrEntry> &Phdrs);
- void assignAddresses();
void assignFileOffsets();
void assignFileOffsetsBinary();
void setPhdrs();
- void fixHeaders();
void fixSectionAlignments();
- void fixAbsoluteSymbols();
+ void fixPredefinedSymbols();
void openFile();
void writeHeader();
void writeSections();
@@ -76,31 +73,37 @@ private:
std::unique_ptr<FileOutputBuffer> Buffer;
- std::vector<OutputSectionBase *> OutputSections;
- OutputSectionFactory<ELFT> Factory;
+ OutputSectionFactory Factory;
void addRelIpltSymbols();
void addStartEndSymbols();
- void addStartStopSymbols(OutputSectionBase *Sec);
- uintX_t getEntryAddr();
- OutputSectionBase *findSection(StringRef Name);
+ void addStartStopSymbols(OutputSection *Sec);
+ uint64_t getEntryAddr();
+ OutputSection *findSectionInScript(StringRef Name);
+ OutputSectionCommand *findSectionCommand(StringRef Name);
std::vector<PhdrEntry> Phdrs;
- uintX_t FileSize;
- uintX_t SectionHeaderOff;
- bool AllocateHeader = true;
+ uint64_t FileSize;
+ uint64_t SectionHeaderOff;
+
+ bool HasGotBaseSym = false;
};
} // anonymous namespace
StringRef elf::getOutputSectionName(StringRef Name) {
+ // ".zdebug_" is a prefix for ZLIB-compressed sections.
+ // Because we decompressed input sections, we want to remove 'z'.
+ if (Name.startswith(".zdebug_"))
+ return Saver.save("." + Name.substr(2));
+
if (Config->Relocatable)
return Name;
for (StringRef V :
- {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.",
- ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
- ".gcc_except_table.", ".tdata.", ".ARM.exidx."}) {
+ {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
+ ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
+ ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) {
StringRef Prefix = V.drop_back();
if (Name.startswith(V) || Name == Prefix)
return Prefix;
@@ -111,24 +114,12 @@ StringRef elf::getOutputSectionName(StringRef Name) {
if (Name == "COMMON")
return ".bss";
- // ".zdebug_" is a prefix for ZLIB-compressed sections.
- // Because we decompressed input sections, we want to remove 'z'.
- if (Name.startswith(".zdebug_"))
- return Saver.save(Twine(".") + Name.substr(2));
return Name;
}
-template <class ELFT> void elf::reportDiscarded(InputSectionBase<ELFT> *IS) {
- if (!Config->PrintGcSections)
- return;
- errs() << "removing unused section from '" << IS->Name << "' in file '"
- << IS->getFile()->getName() << "'\n";
-}
-
template <class ELFT> static bool needsInterpSection() {
return !Symtab<ELFT>::X->getSharedFiles().empty() &&
- !Config->DynamicLinker.empty() &&
- !Script<ELFT>::X->ignoreInterpSection();
+ !Config->DynamicLinker.empty() && !Script->ignoreInterpSection();
}
template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); }
@@ -139,49 +130,72 @@ template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
return false;
if (!P.First)
return true;
- uintX_t Size = P.Last->Addr + P.Last->Size - P.First->Addr;
+ uint64_t Size = P.Last->Addr + P.Last->Size - P.First->Addr;
return Size == 0;
});
Phdrs.erase(I, Phdrs.end());
}
+template <class ELFT> static void combineEhFrameSections() {
+ for (InputSectionBase *&S : InputSections) {
+ EhInputSection *ES = dyn_cast<EhInputSection>(S);
+ if (!ES || !ES->Live)
+ continue;
+
+ In<ELFT>::EhFrame->addSection(ES);
+ S = nullptr;
+ }
+
+ std::vector<InputSectionBase *> &V = InputSections;
+ V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
+}
+
+template <class ELFT> void Writer<ELFT>::clearOutputSections() {
+ // Clear the OutputSections to make sure it is not used anymore. Any
+ // code from this point on should be using the linker script
+ // commands.
+ for (OutputSection *Sec : OutputSections)
+ Sec->Sections.clear();
+ OutputSections.clear();
+}
+
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
// Create linker-synthesized sections such as .got or .plt.
// Such sections are of type input section.
createSyntheticSections();
+ if (!Config->Relocatable)
+ combineEhFrameSections<ELFT>();
+
// We need to create some reserved symbols such as _end. Create them.
if (!Config->Relocatable)
addReservedSymbols();
- // Some architectures use small displacements for jump instructions.
- // It is linker's responsibility to create thunks containing long
- // jump instructions if jump targets are too far. Create thunks.
- if (Target->NeedsThunks)
- forEachRelSec(createThunks<ELFT>);
-
// Create output sections.
- Script<ELFT>::X->OutputSections = &OutputSections;
- if (ScriptConfig->HasSections) {
+ if (Script->Opt.HasSections) {
// If linker script contains SECTIONS commands, let it create sections.
- Script<ELFT>::X->processCommands(Factory);
+ Script->processCommands(Factory);
// Linker scripts may have left some input sections unassigned.
// Assign such sections using the default rule.
- Script<ELFT>::X->addOrphanSections(Factory);
+ Script->addOrphanSections(Factory);
} else {
// If linker script does not contain SECTIONS commands, create
// output sections by default rules. We still need to give the
// linker script a chance to run, because it might contain
// non-SECTIONS commands such as ASSERT.
+ Script->processCommands(Factory);
createSections();
- Script<ELFT>::X->processCommands(Factory);
}
+ clearOutputSections();
if (Config->Discard != DiscardPolicy::All)
copyLocalSymbols();
+ if (Config->CopyRelocs)
+ addSectionSymbols();
+
// Now that we have a complete set of output sections. This function
// completes section contents. For example, we need to add strings
// to the string table, and add entries to .got and .plt.
@@ -190,34 +204,46 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount)
return;
- if (Config->Relocatable) {
- assignFileOffsets();
- } else {
- if (ScriptConfig->HasSections) {
- Script<ELFT>::X->assignAddresses(Phdrs);
- } else {
- fixSectionAlignments();
- assignAddresses();
- }
+ if (!Script->Opt.HasSections && !Config->Relocatable)
+ fixSectionAlignments();
- // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
- // 0 sized region. This has to be done late since only after assignAddresses
- // we know the size of the sections.
- removeEmptyPTLoad();
+ // If -compressed-debug-sections is specified, we need to compress
+ // .debug_* sections. Do it right now because it changes the size of
+ // output sections.
+ parallelForEach(
+ OutputSectionCommands.begin(), OutputSectionCommands.end(),
+ [](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); });
- if (!Config->OFormatBinary)
- assignFileOffsets();
- else
- assignFileOffsetsBinary();
+ Script->assignAddresses();
+ Script->allocateHeaders(Phdrs);
+
+ // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
+ // 0 sized region. This has to be done late since only after assignAddresses
+ // we know the size of the sections.
+ removeEmptyPTLoad();
+
+ if (!Config->OFormatBinary)
+ assignFileOffsets();
+ else
+ assignFileOffsetsBinary();
+
+ setPhdrs();
- setPhdrs();
- fixAbsoluteSymbols();
+ if (Config->Relocatable) {
+ for (OutputSectionCommand *Cmd : OutputSectionCommands)
+ Cmd->Sec->Addr = 0;
+ } else {
+ fixPredefinedSymbols();
}
+ // It does not make sense try to open the file if we have error already.
+ if (ErrorCount)
+ return;
// Write the result down to a file.
openFile();
if (ErrorCount)
return;
+
if (!Config->OFormatBinary) {
writeHeader();
writeSections();
@@ -231,8 +257,13 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount)
return;
+ // Handle -Map option.
+ writeMapFile<ELFT>(OutputSectionCommands);
+ if (ErrorCount)
+ return;
+
if (auto EC = Buffer->commit())
- error(EC, "failed to write to the output file");
+ error("failed to write to the output file: " + EC.message());
// Flush the output streams and exit immediately. A full shutdown
// is a good test that we are keeping track of all allocated memory,
@@ -241,156 +272,158 @@ template <class ELFT> void Writer<ELFT>::run() {
exitLld(0);
}
-// Initialize Out<ELFT> members.
+// Initialize Out members.
template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
// Initialize all pointers with NULL. This is needed because
// you can call lld::elf::main more than once as a library.
- memset(&Out<ELFT>::First, 0, sizeof(Out<ELFT>));
-
- // Create singleton output sections.
- Out<ELFT>::Bss =
- make<OutputSection<ELFT>>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
- Out<ELFT>::BssRelRo = make<OutputSection<ELFT>>(".bss.rel.ro", SHT_NOBITS,
- SHF_ALLOC | SHF_WRITE);
- In<ELFT>::DynStrTab = make<StringTableSection<ELFT>>(".dynstr", true);
- In<ELFT>::Dynamic = make<DynamicSection<ELFT>>();
- Out<ELFT>::EhFrame = make<EhOutputSection<ELFT>>();
+ memset(&Out::First, 0, sizeof(Out));
+
+ auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); };
+
+ InX::DynStrTab = make<StringTableSection>(".dynstr", true);
+ InX::Dynamic = make<DynamicSection<ELFT>>();
In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>(
- Config->Rela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
- In<ELFT>::ShStrTab = make<StringTableSection<ELFT>>(".shstrtab", false);
+ Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
+ InX::ShStrTab = make<StringTableSection>(".shstrtab", false);
- Out<ELFT>::ElfHeader = make<OutputSectionBase>("", 0, SHF_ALLOC);
- Out<ELFT>::ElfHeader->Size = sizeof(Elf_Ehdr);
- Out<ELFT>::ProgramHeaders = make<OutputSectionBase>("", 0, SHF_ALLOC);
- Out<ELFT>::ProgramHeaders->updateAlignment(sizeof(uintX_t));
+ Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
+ Out::ElfHeader->Size = sizeof(Elf_Ehdr);
+ Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC);
+ Out::ProgramHeaders->updateAlignment(Config->Wordsize);
if (needsInterpSection<ELFT>()) {
- In<ELFT>::Interp = createInterpSection<ELFT>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Interp);
+ InX::Interp = createInterpSection();
+ Add(InX::Interp);
} else {
- In<ELFT>::Interp = nullptr;
+ InX::Interp = nullptr;
}
- if (!Config->Relocatable)
- Symtab<ELFT>::X->Sections.push_back(createCommentSection<ELFT>());
-
if (Config->Strip != StripPolicy::All) {
- In<ELFT>::StrTab = make<StringTableSection<ELFT>>(".strtab", false);
- In<ELFT>::SymTab = make<SymbolTableSection<ELFT>>(*In<ELFT>::StrTab);
+ InX::StrTab = make<StringTableSection>(".strtab", false);
+ InX::SymTab = make<SymbolTableSection<ELFT>>(*InX::StrTab);
}
if (Config->BuildId != BuildIdKind::None) {
- In<ELFT>::BuildId = make<BuildIdSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::BuildId);
+ InX::BuildId = make<BuildIdSection>();
+ Add(InX::BuildId);
}
- InputSection<ELFT> *Common = createCommonSection<ELFT>();
- if (!Common->Data.empty()) {
- In<ELFT>::Common = Common;
- Symtab<ELFT>::X->Sections.push_back(Common);
- }
+ InX::Common = createCommonSection<ELFT>();
+ if (InX::Common)
+ Add(InX::Common);
+
+ InX::Bss = make<BssSection>(".bss");
+ Add(InX::Bss);
+ InX::BssRelRo = make<BssSection>(".bss.rel.ro");
+ Add(InX::BssRelRo);
// Add MIPS-specific sections.
- bool HasDynSymTab = !Symtab<ELFT>::X->getSharedFiles().empty() || Config->Pic;
+ bool HasDynSymTab = !Symtab<ELFT>::X->getSharedFiles().empty() ||
+ Config->Pic || Config->ExportDynamic;
if (Config->EMachine == EM_MIPS) {
if (!Config->Shared && HasDynSymTab) {
- In<ELFT>::MipsRldMap = make<MipsRldMapSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::MipsRldMap);
+ InX::MipsRldMap = make<MipsRldMapSection>();
+ Add(InX::MipsRldMap);
}
if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
- Symtab<ELFT>::X->Sections.push_back(Sec);
+ Add(Sec);
if (auto *Sec = MipsOptionsSection<ELFT>::create())
- Symtab<ELFT>::X->Sections.push_back(Sec);
+ Add(Sec);
if (auto *Sec = MipsReginfoSection<ELFT>::create())
- Symtab<ELFT>::X->Sections.push_back(Sec);
+ Add(Sec);
}
if (HasDynSymTab) {
- In<ELFT>::DynSymTab = make<SymbolTableSection<ELFT>>(*In<ELFT>::DynStrTab);
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::DynSymTab);
+ InX::DynSymTab = make<SymbolTableSection<ELFT>>(*InX::DynStrTab);
+ Add(InX::DynSymTab);
In<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::VerSym);
+ Add(In<ELFT>::VerSym);
if (!Config->VersionDefinitions.empty()) {
In<ELFT>::VerDef = make<VersionDefinitionSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::VerDef);
+ Add(In<ELFT>::VerDef);
}
In<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::VerNeed);
+ Add(In<ELFT>::VerNeed);
if (Config->GnuHash) {
- In<ELFT>::GnuHashTab = make<GnuHashTableSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::GnuHashTab);
+ InX::GnuHashTab = make<GnuHashTableSection>();
+ Add(InX::GnuHashTab);
}
if (Config->SysvHash) {
In<ELFT>::HashTab = make<HashTableSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::HashTab);
+ Add(In<ELFT>::HashTab);
}
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Dynamic);
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::DynStrTab);
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaDyn);
+ Add(InX::Dynamic);
+ Add(InX::DynStrTab);
+ Add(In<ELFT>::RelaDyn);
}
// Add .got. MIPS' .got is so different from the other archs,
// it has its own class.
if (Config->EMachine == EM_MIPS) {
- In<ELFT>::MipsGot = make<MipsGotSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::MipsGot);
+ InX::MipsGot = make<MipsGotSection>();
+ Add(InX::MipsGot);
} else {
- In<ELFT>::Got = make<GotSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Got);
+ InX::Got = make<GotSection>();
+ Add(InX::Got);
}
- In<ELFT>::GotPlt = make<GotPltSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::GotPlt);
- In<ELFT>::IgotPlt = make<IgotPltSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::IgotPlt);
+ InX::GotPlt = make<GotPltSection>();
+ Add(InX::GotPlt);
+ InX::IgotPlt = make<IgotPltSection>();
+ Add(InX::IgotPlt);
if (Config->GdbIndex) {
- In<ELFT>::GdbIndex = make<GdbIndexSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::GdbIndex);
+ InX::GdbIndex = createGdbIndex<ELFT>();
+ Add(InX::GdbIndex);
}
// We always need to add rel[a].plt to output if it has entries.
// Even for static linking it can contain R_[*]_IRELATIVE relocations.
In<ELFT>::RelaPlt = make<RelocationSection<ELFT>>(
- Config->Rela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaPlt);
+ Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
+ Add(In<ELFT>::RelaPlt);
// The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
// that the IRelative relocations are processed last by the dynamic loader
In<ELFT>::RelaIplt = make<RelocationSection<ELFT>>(
(Config->EMachine == EM_ARM) ? ".rel.dyn" : In<ELFT>::RelaPlt->Name,
false /*Sort*/);
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaIplt);
+ Add(In<ELFT>::RelaIplt);
- In<ELFT>::Plt = make<PltSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Plt);
- In<ELFT>::Iplt = make<IpltSection<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Iplt);
+ InX::Plt = make<PltSection>(Target->PltHeaderSize);
+ Add(InX::Plt);
+ InX::Iplt = make<PltSection>(0);
+ Add(InX::Iplt);
- if (Config->EhFrameHdr) {
- In<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>();
- Symtab<ELFT>::X->Sections.push_back(In<ELFT>::EhFrameHdr);
+ if (!Config->Relocatable) {
+ if (Config->EhFrameHdr) {
+ In<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>();
+ Add(In<ELFT>::EhFrameHdr);
+ }
+ In<ELFT>::EhFrame = make<EhFrameSection<ELFT>>();
+ Add(In<ELFT>::EhFrame);
}
+
+ if (InX::SymTab)
+ Add(InX::SymTab);
+ Add(InX::ShStrTab);
+ if (InX::StrTab)
+ Add(InX::StrTab);
}
-template <class ELFT>
-static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
+static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName,
const SymbolBody &B) {
- if (B.isFile())
+ if (B.isFile() || B.isSection())
return false;
- // We keep sections in symtab for relocatable output.
- if (B.isSection())
- return Config->Relocatable;
-
// If sym references a section in a discarded group, don't keep it.
- if (Sec == &InputSection<ELFT>::Discarded)
+ if (Sec == &InputSection::Discarded)
return false;
if (Config->Discard == DiscardPolicy::None)
@@ -410,24 +443,23 @@ static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
return !Sec || !(Sec->Flags & SHF_MERGE);
}
-template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
+static bool includeInSymtab(const SymbolBody &B) {
if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj)
return false;
- // If --retain-symbols-file is given, we'll keep only symbols listed in that
- // file.
- if (Config->Discard == DiscardPolicy::RetainFile &&
- !Config->RetainSymbolsFile.count(B.getName()))
- return false;
-
- if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
+ if (auto *D = dyn_cast<DefinedRegular>(&B)) {
// Always include absolute symbols.
- if (!D->Section)
+ SectionBase *Sec = D->Section;
+ if (!Sec)
return true;
- // Exclude symbols pointing to garbage-collected sections.
- if (!D->Section->Live)
- return false;
- if (auto *S = dyn_cast<MergeInputSection<ELFT>>(D->Section))
+ if (auto *IS = dyn_cast<InputSectionBase>(Sec)) {
+ Sec = IS->Repl;
+ IS = cast<InputSectionBase>(Sec);
+ // Exclude symbols pointing to garbage-collected sections.
+ if (!IS->Live)
+ return false;
+ }
+ if (auto *S = dyn_cast<MergeInputSection>(Sec))
if (!S->getSectionPiece(D->Value)->Live)
return false;
}
@@ -437,239 +469,313 @@ template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
// Local symbols are not in the linker's symbol table. This function scans
// each object file's symbol table to copy local symbols to the output.
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
- if (!In<ELFT>::SymTab)
+ if (!InX::SymTab)
return;
for (elf::ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles()) {
for (SymbolBody *B : F->getLocalSymbols()) {
if (!B->IsLocal)
fatal(toString(F) +
": broken object: getLocalSymbols returns a non-local symbol");
- auto *DR = dyn_cast<DefinedRegular<ELFT>>(B);
+ auto *DR = dyn_cast<DefinedRegular>(B);
// No reason to keep local undefined symbol in symtab.
if (!DR)
continue;
- if (!includeInSymtab<ELFT>(*B))
+ if (!includeInSymtab(*B))
continue;
- InputSectionBase<ELFT> *Sec = DR->Section;
- if (!shouldKeepInSymtab<ELFT>(Sec, B->getName(), *B))
+ SectionBase *Sec = DR->Section;
+ if (!shouldKeepInSymtab(Sec, B->getName(), *B))
continue;
- In<ELFT>::SymTab->addLocal(B);
+ InX::SymTab->addSymbol(B);
}
}
}
-// PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections that
-// we would like to make sure appear is a specific order to maximize their
-// coverage by a single signed 16-bit offset from the TOC base pointer.
-// Conversely, the special .tocbss section should be first among all SHT_NOBITS
-// sections. This will put it next to the loaded special PPC64 sections (and,
-// thus, within reach of the TOC base pointer).
-static int getPPC64SectionRank(StringRef SectionName) {
- return StringSwitch<int>(SectionName)
- .Case(".tocbss", 0)
- .Case(".branch_lt", 2)
- .Case(".toc", 3)
- .Case(".toc1", 4)
- .Case(".opd", 5)
- .Default(1);
-}
+template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
+ // Create one STT_SECTION symbol for each output section we might
+ // have a relocation with.
+ for (BaseCommand *Base : Script->Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ if (!Cmd)
+ continue;
+ auto I = llvm::find_if(Cmd->Commands, [](BaseCommand *Base) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Base))
+ return !ISD->Sections.empty();
+ return false;
+ });
+ if (I == Cmd->Commands.end())
+ continue;
+ InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0];
+ if (isa<SyntheticSection>(IS) || IS->Type == SHT_REL ||
+ IS->Type == SHT_RELA)
+ continue;
-// All sections with SHF_MIPS_GPREL flag should be grouped together
-// because data in these sections is addressable with a gp relative address.
-static int getMipsSectionRank(const OutputSectionBase *S) {
- if ((S->Flags & SHF_MIPS_GPREL) == 0)
- return 0;
- if (S->getName() == ".got")
- return 1;
- return 2;
+ auto *Sym =
+ make<DefinedRegular>("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION,
+ /*Value=*/0, /*Size=*/0, IS, nullptr);
+ InX::SymTab->addSymbol(Sym);
+ }
}
-template <class ELFT> bool elf::isRelroSection(const OutputSectionBase *Sec) {
+// Today's loaders have a feature to make segments read-only after
+// processing dynamic relocations to enhance security. PT_GNU_RELRO
+// is defined for that.
+//
+// This function returns true if a section needs to be put into a
+// PT_GNU_RELRO segment.
+bool elf::isRelroSection(const OutputSection *Sec) {
if (!Config->ZRelro)
return false;
+
uint64_t Flags = Sec->Flags;
+
+ // Non-allocatable or non-writable sections don't need RELRO because
+ // they are not writable or not even mapped to memory in the first place.
+ // RELRO is for sections that are essentially read-only but need to
+ // be writable only at process startup to allow dynamic linker to
+ // apply relocations.
if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE))
return false;
+
+ // Once initialized, TLS data segments are used as data templates
+ // for a thread-local storage. For each new thread, runtime
+ // allocates memory for a TLS and copy templates there. No thread
+ // are supposed to use templates directly. Thus, it can be in RELRO.
if (Flags & SHF_TLS)
return true;
+
+ // .init_array, .preinit_array and .fini_array contain pointers to
+ // functions that are executed on process startup or exit. These
+ // pointers are set by the static linker, and they are not expected
+ // to change at runtime. But if you are an attacker, you could do
+ // interesting things by manipulating pointers in .fini_array, for
+ // example. So they are put into RELRO.
uint32_t Type = Sec->Type;
if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY ||
Type == SHT_PREINIT_ARRAY)
return true;
- if (Sec == In<ELFT>::GotPlt->OutSec)
- return Config->ZNow;
- if (Sec == In<ELFT>::Dynamic->OutSec)
+
+ // .got contains pointers to external symbols. They are resolved by
+ // the dynamic linker when a module is loaded into memory, and after
+ // that they are not expected to change. So, it can be in RELRO.
+ if (InX::Got && Sec == InX::Got->getParent())
return true;
- if (In<ELFT>::Got && Sec == In<ELFT>::Got->OutSec)
+
+ // .got.plt contains pointers to external function symbols. They are
+ // by default resolved lazily, so we usually cannot put it into RELRO.
+ // However, if "-z now" is given, the lazy symbol resolution is
+ // disabled, which enables us to put it into RELRO.
+ if (Sec == InX::GotPlt->getParent())
+ return Config->ZNow;
+
+ // .dynamic section contains data for the dynamic linker, and
+ // there's no need to write to it at runtime, so it's better to put
+ // it into RELRO.
+ if (Sec == InX::Dynamic->getParent())
return true;
- if (Sec == Out<ELFT>::BssRelRo)
+
+ // .bss.rel.ro is used for copy relocations for read-only symbols.
+ // Since the dynamic linker needs to process copy relocations, the
+ // section cannot be read-only, but once initialized, they shouldn't
+ // change.
+ if (Sec == InX::BssRelRo->getParent())
return true;
- StringRef S = Sec->getName();
+
+ // Sections with some special names are put into RELRO. This is a
+ // bit unfortunate because section names shouldn't be significant in
+ // ELF in spirit. But in reality many linker features depend on
+ // magic section names.
+ StringRef S = Sec->Name;
return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" ||
S == ".eh_frame" || S == ".openbsd.randomdata";
}
-template <class ELFT>
-static bool compareSectionsNonScript(const OutputSectionBase *A,
- const OutputSectionBase *B) {
+// We compute a rank for each section. The rank indicates where the
+// section should be placed in the file. Instead of using simple
+// numbers (0,1,2...), we use a series of flags. One for each decision
+// point when placing the section.
+// Using flags has two key properties:
+// * It is easy to check if a give branch was taken.
+// * It is easy two see how similar two ranks are (see getRankProximity).
+enum RankFlags {
+ RF_NOT_ADDR_SET = 1 << 16,
+ RF_NOT_INTERP = 1 << 15,
+ RF_NOT_ALLOC = 1 << 14,
+ RF_WRITE = 1 << 13,
+ RF_EXEC_WRITE = 1 << 12,
+ RF_EXEC = 1 << 11,
+ RF_NON_TLS_BSS = 1 << 10,
+ RF_NON_TLS_BSS_RO = 1 << 9,
+ RF_NOT_TLS = 1 << 8,
+ RF_BSS = 1 << 7,
+ RF_PPC_NOT_TOCBSS = 1 << 6,
+ RF_PPC_OPD = 1 << 5,
+ RF_PPC_TOCL = 1 << 4,
+ RF_PPC_TOC = 1 << 3,
+ RF_PPC_BRANCH_LT = 1 << 2,
+ RF_MIPS_GPREL = 1 << 1,
+ RF_MIPS_NOT_GOT = 1 << 0
+};
+
+static unsigned getSectionRank(const OutputSection *Sec) {
+ unsigned Rank = 0;
+
+ // We want to put section specified by -T option first, so we
+ // can start assigning VA starting from them later.
+ if (Config->SectionStartMap.count(Sec->Name))
+ return Rank;
+ Rank |= RF_NOT_ADDR_SET;
+
// Put .interp first because some loaders want to see that section
// on the first page of the executable file when loaded into memory.
- bool AIsInterp = A->getName() == ".interp";
- bool BIsInterp = B->getName() == ".interp";
- if (AIsInterp != BIsInterp)
- return AIsInterp;
+ if (Sec->Name == ".interp")
+ return Rank;
+ Rank |= RF_NOT_INTERP;
// Allocatable sections go first to reduce the total PT_LOAD size and
// so debug info doesn't change addresses in actual code.
- bool AIsAlloc = A->Flags & SHF_ALLOC;
- bool BIsAlloc = B->Flags & SHF_ALLOC;
- if (AIsAlloc != BIsAlloc)
- return AIsAlloc;
-
- // We don't have any special requirements for the relative order of two non
- // allocatable sections.
- if (!AIsAlloc)
- return false;
-
- // We want to put section specified by -T option first, so we
- // can start assigning VA starting from them later.
- auto AAddrSetI = Config->SectionStartMap.find(A->getName());
- auto BAddrSetI = Config->SectionStartMap.find(B->getName());
- bool AHasAddrSet = AAddrSetI != Config->SectionStartMap.end();
- bool BHasAddrSet = BAddrSetI != Config->SectionStartMap.end();
- if (AHasAddrSet != BHasAddrSet)
- return AHasAddrSet;
- if (AHasAddrSet)
- return AAddrSetI->second < BAddrSetI->second;
-
- // We want the read only sections first so that they go in the PT_LOAD
- // covering the program headers at the start of the file.
- bool AIsWritable = A->Flags & SHF_WRITE;
- bool BIsWritable = B->Flags & SHF_WRITE;
- if (AIsWritable != BIsWritable)
- return BIsWritable;
-
- if (!Config->SingleRoRx) {
- // For a corresponding reason, put non exec sections first (the program
- // header PT_LOAD is not executable).
- // We only do that if we are not using linker scripts, since with linker
- // scripts ro and rx sections are in the same PT_LOAD, so their relative
- // order is not important. The same applies for -no-rosegment.
- bool AIsExec = A->Flags & SHF_EXECINSTR;
- bool BIsExec = B->Flags & SHF_EXECINSTR;
- if (AIsExec != BIsExec)
- return BIsExec;
+ if (!(Sec->Flags & SHF_ALLOC))
+ return Rank | RF_NOT_ALLOC;
+
+ // Sort sections based on their access permission in the following
+ // order: R, RX, RWX, RW. This order is based on the following
+ // considerations:
+ // * Read-only sections come first such that they go in the
+ // PT_LOAD covering the program headers at the start of the file.
+ // * Read-only, executable sections come next, unless the
+ // -no-rosegment option is used.
+ // * Writable, executable sections follow such that .plt on
+ // architectures where it needs to be writable will be placed
+ // between .text and .data.
+ // * Writable sections come last, such that .bss lands at the very
+ // end of the last PT_LOAD.
+ bool IsExec = Sec->Flags & SHF_EXECINSTR;
+ bool IsWrite = Sec->Flags & SHF_WRITE;
+
+ if (IsExec) {
+ if (IsWrite)
+ Rank |= RF_EXEC_WRITE;
+ else if (!Config->SingleRoRx)
+ Rank |= RF_EXEC;
+ } else {
+ if (IsWrite)
+ Rank |= RF_WRITE;
}
// If we got here we know that both A and B are in the same PT_LOAD.
- bool AIsTls = A->Flags & SHF_TLS;
- bool BIsTls = B->Flags & SHF_TLS;
- bool AIsNoBits = A->Type == SHT_NOBITS;
- bool BIsNoBits = B->Type == SHT_NOBITS;
+ bool IsTls = Sec->Flags & SHF_TLS;
+ bool IsNoBits = Sec->Type == SHT_NOBITS;
// The first requirement we have is to put (non-TLS) nobits sections last. The
// reason is that the only thing the dynamic linker will see about them is a
// p_memsz that is larger than p_filesz. Seeing that it zeros the end of the
// PT_LOAD, so that has to correspond to the nobits sections.
- bool AIsNonTlsNoBits = AIsNoBits && !AIsTls;
- bool BIsNonTlsNoBits = BIsNoBits && !BIsTls;
- if (AIsNonTlsNoBits != BIsNonTlsNoBits)
- return BIsNonTlsNoBits;
+ bool IsNonTlsNoBits = IsNoBits && !IsTls;
+ if (IsNonTlsNoBits)
+ Rank |= RF_NON_TLS_BSS;
// We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo
// sections after r/w ones, so that the RelRo sections are contiguous.
- bool AIsRelRo = isRelroSection<ELFT>(A);
- bool BIsRelRo = isRelroSection<ELFT>(B);
- if (AIsRelRo != BIsRelRo)
- return AIsNonTlsNoBits ? AIsRelRo : BIsRelRo;
+ bool IsRelRo = isRelroSection(Sec);
+ if (IsNonTlsNoBits && !IsRelRo)
+ Rank |= RF_NON_TLS_BSS_RO;
+ if (!IsNonTlsNoBits && IsRelRo)
+ Rank |= RF_NON_TLS_BSS_RO;
// The TLS initialization block needs to be a single contiguous block in a R/W
// PT_LOAD, so stick TLS sections directly before the other RelRo R/W
// sections. The TLS NOBITS sections are placed here as they don't take up
// virtual address space in the PT_LOAD.
- if (AIsTls != BIsTls)
- return AIsTls;
+ if (!IsTls)
+ Rank |= RF_NOT_TLS;
// Within the TLS initialization block, the non-nobits sections need to appear
// first.
- if (AIsNoBits != BIsNoBits)
- return BIsNoBits;
-
- // Some architectures have additional ordering restrictions for sections
- // within the same PT_LOAD.
- if (Config->EMachine == EM_PPC64)
- return getPPC64SectionRank(A->getName()) <
- getPPC64SectionRank(B->getName());
- if (Config->EMachine == EM_MIPS)
- return getMipsSectionRank(A) < getMipsSectionRank(B);
+ if (IsNoBits)
+ Rank |= RF_BSS;
+
+ // // Some architectures have additional ordering restrictions for sections
+ // // within the same PT_LOAD.
+ if (Config->EMachine == EM_PPC64) {
+ // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections
+ // that we would like to make sure appear is a specific order to maximize
+ // their coverage by a single signed 16-bit offset from the TOC base
+ // pointer. Conversely, the special .tocbss section should be first among
+ // all SHT_NOBITS sections. This will put it next to the loaded special
+ // PPC64 sections (and, thus, within reach of the TOC base pointer).
+ StringRef Name = Sec->Name;
+ if (Name != ".tocbss")
+ Rank |= RF_PPC_NOT_TOCBSS;
+
+ if (Name == ".opd")
+ Rank |= RF_PPC_OPD;
+
+ if (Name == ".toc1")
+ Rank |= RF_PPC_TOCL;
+
+ if (Name == ".toc")
+ Rank |= RF_PPC_TOC;
+
+ if (Name == ".branch_lt")
+ Rank |= RF_PPC_BRANCH_LT;
+ }
+ if (Config->EMachine == EM_MIPS) {
+ // All sections with SHF_MIPS_GPREL flag should be grouped together
+ // because data in these sections is addressable with a gp relative address.
+ if (Sec->Flags & SHF_MIPS_GPREL)
+ Rank |= RF_MIPS_GPREL;
- return false;
-}
+ if (Sec->Name != ".got")
+ Rank |= RF_MIPS_NOT_GOT;
+ }
-// Output section ordering is determined by this function.
-template <class ELFT>
-static bool compareSections(const OutputSectionBase *A,
- const OutputSectionBase *B) {
- // For now, put sections mentioned in a linker script first.
- int AIndex = Script<ELFT>::X->getSectionIndex(A->getName());
- int BIndex = Script<ELFT>::X->getSectionIndex(B->getName());
- bool AInScript = AIndex != INT_MAX;
- bool BInScript = BIndex != INT_MAX;
- if (AInScript != BInScript)
- return AInScript;
- // If both are in the script, use that order.
- if (AInScript)
- return AIndex < BIndex;
-
- return compareSectionsNonScript<ELFT>(A, B);
+ return Rank;
}
-// Program header entry
-PhdrEntry::PhdrEntry(unsigned Type, unsigned Flags) {
- p_type = Type;
- p_flags = Flags;
+static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) {
+ const OutputSection *A = cast<OutputSectionCommand>(ACmd)->Sec;
+ const OutputSection *B = cast<OutputSectionCommand>(BCmd)->Sec;
+ if (A->SortRank != B->SortRank)
+ return A->SortRank < B->SortRank;
+ if (!(A->SortRank & RF_NOT_ADDR_SET))
+ return Config->SectionStartMap.lookup(A->Name) <
+ Config->SectionStartMap.lookup(B->Name);
+ return false;
}
-void PhdrEntry::add(OutputSectionBase *Sec) {
+void PhdrEntry::add(OutputSection *Sec) {
Last = Sec;
if (!First)
First = Sec;
- p_align = std::max(p_align, Sec->Addralign);
+ p_align = std::max(p_align, Sec->Alignment);
if (p_type == PT_LOAD)
Sec->FirstInPtLoad = First;
}
template <class ELFT>
-static void addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec,
- typename ELFT::uint Val,
- uint8_t StOther = STV_HIDDEN) {
- if (SymbolBody *S = Symtab<ELFT>::X->find(Name))
- if (!S->isInCurrentDSO())
- Symtab<ELFT>::X->addSynthetic(Name, Sec, Val, StOther);
-}
-
-template <class ELFT>
-static Symbol *addRegular(StringRef Name, InputSectionBase<ELFT> *Sec,
- typename ELFT::uint Value) {
+static Symbol *addRegular(StringRef Name, SectionBase *Sec, uint64_t Value,
+ uint8_t StOther = STV_HIDDEN,
+ uint8_t Binding = STB_WEAK) {
// The linker generated symbols are added as STB_WEAK to allow user defined
// ones to override them.
- return Symtab<ELFT>::X->addRegular(Name, STV_HIDDEN, STT_NOTYPE, Value,
- /*Size=*/0, STB_WEAK, Sec,
+ return Symtab<ELFT>::X->addRegular(Name, StOther, STT_NOTYPE, Value,
+ /*Size=*/0, Binding, Sec,
/*File=*/nullptr);
}
template <class ELFT>
-static Symbol *addOptionalRegular(StringRef Name, InputSectionBase<ELFT> *IS,
- typename ELFT::uint Value) {
+static DefinedRegular *
+addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val,
+ uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_GLOBAL) {
SymbolBody *S = Symtab<ELFT>::X->find(Name);
if (!S)
return nullptr;
if (S->isInCurrentDSO())
- return S->symbol();
- return addRegular(Name, IS, Value);
+ return nullptr;
+ return cast<DefinedRegular>(
+ addRegular<ELFT>(Name, Sec, Val, StOther, Binding)->body());
}
// The beginning and the ending of .rel[a].plt section are marked
@@ -679,13 +785,13 @@ static Symbol *addOptionalRegular(StringRef Name, InputSectionBase<ELFT> *IS,
// need these symbols, since IRELATIVE relocs are resolved through GOT
// and PLT. For details, see http://www.airs.com/blog/archives/403.
template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
- if (In<ELFT>::DynSymTab)
+ if (InX::DynSymTab)
return;
- StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
- addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0);
+ StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start";
+ addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
- S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
- addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, -1);
+ S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end";
+ addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, -1, STV_HIDDEN, STB_WEAK);
}
// The linker is expected to define some symbols depending on
@@ -697,15 +803,12 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
// to GOT. Default offset is 0x7ff0.
// See "Global Data Symbols" in Chapter 6 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- ElfSym<ELFT>::MipsGp =
- Symtab<ELFT>::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL);
+ ElfSym::MipsGp = Symtab<ELFT>::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL);
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
- // start of function and 'gp' pointer into GOT. To simplify relocation
- // calculation we assign _gp value to it and calculate corresponding
- // relocations as relative to this value.
+ // start of function and 'gp' pointer into GOT.
if (Symtab<ELFT>::X->find("_gp_disp"))
- ElfSym<ELFT>::MipsGpDisp =
+ ElfSym::MipsGpDisp =
Symtab<ELFT>::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL);
// The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
@@ -713,74 +816,70 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
// in case of using -mno-shared option.
// https://sourceware.org/ml/binutils/2004-12/msg00094.html
if (Symtab<ELFT>::X->find("__gnu_local_gp"))
- ElfSym<ELFT>::MipsLocalGp =
+ ElfSym::MipsLocalGp =
Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL);
}
- // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
- // is magical and is used to produce a R_386_GOTPC relocation.
- // The R_386_GOTPC relocation value doesn't actually depend on the
- // symbol value, so it could use an index of STN_UNDEF which, according
- // to the spec, means the symbol value is 0.
- // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
- // the object file.
- // The situation is even stranger on x86_64 where the assembly doesn't
- // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
- // an undefined symbol in the .o files.
- // Given that the symbol is effectively unused, we just create a dummy
- // hidden one to avoid the undefined symbol error.
- Symtab<ELFT>::X->addIgnored("_GLOBAL_OFFSET_TABLE_");
+ // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
+ // be at some offset from the base of the .got section, usually 0 or the end
+ // of the .got
+ InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
+ : cast<InputSection>(InX::Got);
+ ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>(
+ "_GLOBAL_OFFSET_TABLE_", GotSection, Target->GotBaseSymOff);
// __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
// static linking the linker is required to optimize away any references to
// __tls_get_addr, so it's not defined anywhere. Create a hidden definition
- // to avoid the undefined symbol error. As usual special cases are ARM and
- // MIPS - the libc for these targets defines __tls_get_addr itself because
- // there are no TLS optimizations for these targets.
- if (!In<ELFT>::DynSymTab &&
- (Config->EMachine != EM_MIPS && Config->EMachine != EM_ARM))
+ // to avoid the undefined symbol error.
+ if (!InX::DynSymTab)
Symtab<ELFT>::X->addIgnored("__tls_get_addr");
+ // __ehdr_start is the location of ELF file headers. Note that we define
+ // this symbol unconditionally even when using a linker script, which
+ // differs from the behavior implemented by GNU linker which only define
+ // this symbol if ELF headers are in the memory mapped segment.
+ // __executable_start is not documented, but the expectation of at
+ // least the android libc is that it points to the elf header too.
+ // __dso_handle symbol is passed to cxa_finalize as a marker to identify
+ // each DSO. The address of the symbol doesn't matter as long as they are
+ // different in different DSOs, so we chose the start address of the DSO.
+ for (const char *Name :
+ {"__ehdr_start", "__executable_start", "__dso_handle"})
+ addOptionalRegular<ELFT>(Name, Out::ElfHeader, 0, STV_HIDDEN);
+
// If linker script do layout we do not need to create any standart symbols.
- if (ScriptConfig->HasSections)
+ if (Script->Opt.HasSections)
return;
- ElfSym<ELFT>::EhdrStart = Symtab<ELFT>::X->addIgnored("__ehdr_start");
-
- auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1,
- DefinedRegular<ELFT> *&Sym2) {
- Sym1 = Symtab<ELFT>::X->addIgnored(S, STV_DEFAULT);
-
- // The name without the underscore is not a reserved name,
- // so it is defined only when there is a reference against it.
- assert(S.startswith("_"));
- S = S.substr(1);
- if (SymbolBody *B = Symtab<ELFT>::X->find(S))
- if (B->isUndefined())
- Sym2 = Symtab<ELFT>::X->addAbsolute(S, STV_DEFAULT);
+ auto Add = [](StringRef S) {
+ return addOptionalRegular<ELFT>(S, Out::ElfHeader, 0, STV_DEFAULT);
};
- Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2);
- Define("_etext", ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2);
- Define("_edata", ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2);
+ ElfSym::Bss = Add("__bss_start");
+ ElfSym::End1 = Add("end");
+ ElfSym::End2 = Add("_end");
+ ElfSym::Etext1 = Add("etext");
+ ElfSym::Etext2 = Add("_etext");
+ ElfSym::Edata1 = Add("edata");
+ ElfSym::Edata2 = Add("_edata");
}
// Sort input sections by section name suffixes for
// __attribute__((init_priority(N))).
-template <class ELFT> static void sortInitFini(OutputSectionBase *S) {
- if (S)
- reinterpret_cast<OutputSection<ELFT> *>(S)->sortInitFini();
+static void sortInitFini(OutputSectionCommand *Cmd) {
+ if (Cmd)
+ Cmd->sortInitFini();
}
// Sort input sections by the special rule for .ctors and .dtors.
-template <class ELFT> static void sortCtorsDtors(OutputSectionBase *S) {
- if (S)
- reinterpret_cast<OutputSection<ELFT> *>(S)->sortCtorsDtors();
+static void sortCtorsDtors(OutputSectionCommand *Cmd) {
+ if (Cmd)
+ Cmd->sortCtorsDtors();
}
// Sort input sections using the list provided by --symbol-ordering-file.
-template <class ELFT>
-static void sortBySymbolsOrder(ArrayRef<OutputSectionBase *> OutputSections) {
+template <class ELFT> static void sortBySymbolsOrder() {
if (Config->SymbolOrderingFile.empty())
return;
@@ -793,10 +892,10 @@ static void sortBySymbolsOrder(ArrayRef<OutputSectionBase *> OutputSections) {
SymbolOrder.insert({S, Priority++});
// Build a map from sections to their priorities.
- DenseMap<InputSectionBase<ELFT> *, int> SectionOrder;
+ DenseMap<SectionBase *, int> SectionOrder;
for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles()) {
for (SymbolBody *Body : File->getSymbols()) {
- auto *D = dyn_cast<DefinedRegular<ELFT>>(Body);
+ auto *D = dyn_cast<DefinedRegular>(Body);
if (!D || !D->Section)
continue;
int &Priority = SectionOrder[D->Section];
@@ -805,15 +904,14 @@ static void sortBySymbolsOrder(ArrayRef<OutputSectionBase *> OutputSections) {
}
// Sort sections by priority.
- for (OutputSectionBase *Base : OutputSections)
- if (auto *Sec = dyn_cast<OutputSection<ELFT>>(Base))
- Sec->sort([&](InputSection<ELFT> *S) { return SectionOrder.lookup(S); });
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); });
}
template <class ELFT>
-void Writer<ELFT>::forEachRelSec(
- std::function<void(InputSectionBase<ELFT> &)> Fn) {
- for (InputSectionBase<ELFT> *IS : Symtab<ELFT>::X->Sections) {
+void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) {
+ for (InputSectionBase *IS : InputSections) {
if (!IS->Live)
continue;
// Scan all relocations. Each relocation goes through a series
@@ -823,75 +921,142 @@ void Writer<ELFT>::forEachRelSec(
// processed by InputSection::relocateNonAlloc.
if (!(IS->Flags & SHF_ALLOC))
continue;
- if (isa<InputSection<ELFT>>(IS) || isa<EhInputSection<ELFT>>(IS))
+ if (isa<InputSection>(IS) || isa<EhInputSection>(IS))
Fn(*IS);
}
-}
-template <class ELFT>
-void Writer<ELFT>::addInputSec(InputSectionBase<ELFT> *IS) {
- if (!IS)
- return;
-
- if (!IS->Live) {
- reportDiscarded(IS);
- return;
+ if (!Config->Relocatable) {
+ for (EhInputSection *ES : In<ELFT>::EhFrame->Sections)
+ Fn(*ES);
}
- OutputSectionBase *Sec;
- bool IsNew;
- StringRef OutsecName = getOutputSectionName(IS->Name);
- std::tie(Sec, IsNew) = Factory.create(IS, OutsecName);
- if (IsNew)
- OutputSections.push_back(Sec);
- Sec->addSection(IS);
}
template <class ELFT> void Writer<ELFT>::createSections() {
- for (InputSectionBase<ELFT> *IS : Symtab<ELFT>::X->Sections)
- addInputSec(IS);
-
- sortBySymbolsOrder<ELFT>(OutputSections);
- sortInitFini<ELFT>(findSection(".init_array"));
- sortInitFini<ELFT>(findSection(".fini_array"));
- sortCtorsDtors<ELFT>(findSection(".ctors"));
- sortCtorsDtors<ELFT>(findSection(".dtors"));
+ for (InputSectionBase *IS : InputSections)
+ if (IS)
+ Factory.addInputSec(IS, getOutputSectionName(IS->Name));
+
+ Script->fabricateDefaultCommands();
+ sortBySymbolsOrder<ELFT>();
+ sortInitFini(findSectionCommand(".init_array"));
+ sortInitFini(findSectionCommand(".fini_array"));
+ sortCtorsDtors(findSectionCommand(".ctors"));
+ sortCtorsDtors(findSectionCommand(".dtors"));
+}
- for (OutputSectionBase *Sec : OutputSections)
- Sec->assignOffsets();
+// We want to find how similar two ranks are.
+// The more branches in getSectionRank that match, the more similar they are.
+// Since each branch corresponds to a bit flag, we can just use
+// countLeadingZeros.
+static int getRankProximity(OutputSection *A, OutputSection *B) {
+ return countLeadingZeros(A->SortRank ^ B->SortRank);
}
-template <class ELFT>
-static bool canSharePtLoad(const OutputSectionBase &S1,
- const OutputSectionBase &S2) {
- if (!(S1.Flags & SHF_ALLOC) || !(S2.Flags & SHF_ALLOC))
- return false;
+static int getRankProximity(OutputSection *A, BaseCommand *B) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(B))
+ if (Cmd->Sec)
+ return getRankProximity(A, Cmd->Sec);
+ return -1;
+}
- bool S1IsWrite = S1.Flags & SHF_WRITE;
- bool S2IsWrite = S2.Flags & SHF_WRITE;
- if (S1IsWrite != S2IsWrite)
+// When placing orphan sections, we want to place them after symbol assignments
+// so that an orphan after
+// begin_foo = .;
+// foo : { *(foo) }
+// end_foo = .;
+// doesn't break the intended meaning of the begin/end symbols.
+// We don't want to go over sections since findOrphanPos is the
+// one in charge of deciding the order of the sections.
+// We don't want to go over changes to '.', since doing so in
+// rx_sec : { *(rx_sec) }
+// . = ALIGN(0x1000);
+// /* The RW PT_LOAD starts here*/
+// rw_sec : { *(rw_sec) }
+// would mean that the RW PT_LOAD would become unaligned.
+static bool shouldSkip(BaseCommand *Cmd) {
+ if (isa<OutputSectionCommand>(Cmd))
return false;
+ if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd))
+ return Assign->Name != ".";
+ return true;
+}
- if (!S1IsWrite)
- return true; // RO and RX share a PT_LOAD with linker scripts.
- return (S1.Flags & SHF_EXECINSTR) == (S2.Flags & SHF_EXECINSTR);
+// We want to place orphan sections so that they share as much
+// characteristics with their neighbors as possible. For example, if
+// both are rw, or both are tls.
+template <typename ELFT>
+static std::vector<BaseCommand *>::iterator
+findOrphanPos(std::vector<BaseCommand *>::iterator B,
+ std::vector<BaseCommand *>::iterator E) {
+ OutputSection *Sec = cast<OutputSectionCommand>(*E)->Sec;
+
+ // Find the first element that has as close a rank as possible.
+ auto I = std::max_element(B, E, [=](BaseCommand *A, BaseCommand *B) {
+ return getRankProximity(Sec, A) < getRankProximity(Sec, B);
+ });
+ if (I == E)
+ return E;
+
+ // Consider all existing sections with the same proximity.
+ int Proximity = getRankProximity(Sec, *I);
+ for (; I != E; ++I) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(*I);
+ if (!Cmd || !Cmd->Sec)
+ continue;
+ if (getRankProximity(Sec, Cmd->Sec) != Proximity ||
+ Sec->SortRank < Cmd->Sec->SortRank)
+ break;
+ }
+ auto J = std::find_if(
+ llvm::make_reverse_iterator(I), llvm::make_reverse_iterator(B),
+ [](BaseCommand *Cmd) { return isa<OutputSectionCommand>(Cmd); });
+ I = J.base();
+ while (I != E && shouldSkip(*I))
+ ++I;
+ return I;
}
template <class ELFT> void Writer<ELFT>::sortSections() {
+ if (Script->Opt.HasSections)
+ Script->adjustSectionsBeforeSorting();
+
// Don't sort if using -r. It is not necessary and we want to preserve the
// relative order for SHF_LINK_ORDER sections.
if (Config->Relocatable)
return;
- if (!ScriptConfig->HasSections) {
- std::stable_sort(OutputSections.begin(), OutputSections.end(),
- compareSectionsNonScript<ELFT>);
+
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ if (OutputSection *Sec = Cmd->Sec)
+ Sec->SortRank = getSectionRank(Sec);
+
+ if (!Script->Opt.HasSections) {
+ // We know that all the OutputSectionCommands are contiguous in
+ // this case.
+ auto E = Script->Opt.Commands.end();
+ auto I = Script->Opt.Commands.begin();
+ auto IsSection = [](BaseCommand *Base) {
+ return isa<OutputSectionCommand>(Base);
+ };
+ I = std::find_if(I, E, IsSection);
+ E = std::find_if(llvm::make_reverse_iterator(E),
+ llvm::make_reverse_iterator(I), IsSection)
+ .base();
+ std::stable_sort(I, E, compareSections);
return;
}
- Script<ELFT>::X->adjustSectionsBeforeSorting();
+ // Orphan sections are sections present in the input files which are
+ // not explicitly placed into the output file by the linker script.
+ //
+ // The sections in the linker script are already in the correct
+ // order. We have to figuere out where to insert the orphan
+ // sections.
+ //
// The order of the sections in the script is arbitrary and may not agree with
- // compareSectionsNonScript. This means that we cannot easily define a
- // strict weak ordering. To see why, consider a comparison of a section in the
- // script and one not in the script. We have a two simple options:
+ // compareSections. This means that we cannot easily define a strict weak
+ // ordering. To see why, consider a comparison of a section in the script and
+ // one not in the script. We have a two simple options:
// * Make them equivalent (a is not less than b, and b is not less than a).
// The problem is then that equivalence has to be transitive and we can
// have sections a, b and c with only b in a script and a less than c
@@ -906,136 +1071,171 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
// .d (ro) # not in script
//
// The way we define an order then is:
- // * First put script sections at the start and sort the script and
- // non-script sections independently.
- // * Move each non-script section to its preferred position. We try
+ // * Sort only the orphan sections. They are in the end right now.
+ // * Move each orphan section to its preferred position. We try
// to put each section in the last position where it it can share
// a PT_LOAD.
+ //
+ // There is some ambiguity as to where exactly a new entry should be
+ // inserted, because Opt.Commands contains not only output section
+ // commands but also other types of commands such as symbol assignment
+ // expressions. There's no correct answer here due to the lack of the
+ // formal specification of the linker script. We use heuristics to
+ // determine whether a new output command should be added before or
+ // after another commands. For the details, look at shouldSkip
+ // function.
+
+ auto I = Script->Opt.Commands.begin();
+ auto E = Script->Opt.Commands.end();
+ auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ return Cmd->Sec && Cmd->Sec->SectionIndex == INT_MAX;
+ return false;
+ });
- std::stable_sort(OutputSections.begin(), OutputSections.end(),
- compareSections<ELFT>);
+ // Sort the orphan sections.
+ std::stable_sort(NonScriptI, E, compareSections);
+
+ // As a horrible special case, skip the first . assignment if it is before any
+ // section. We do this because it is common to set a load address by starting
+ // the script with ". = 0xabcd" and the expectation is that every section is
+ // after that.
+ auto FirstSectionOrDotAssignment =
+ std::find_if(I, E, [](BaseCommand *Cmd) { return !shouldSkip(Cmd); });
+ if (FirstSectionOrDotAssignment != E &&
+ isa<SymbolAssignment>(**FirstSectionOrDotAssignment))
+ ++FirstSectionOrDotAssignment;
+ I = FirstSectionOrDotAssignment;
- auto I = OutputSections.begin();
- auto E = OutputSections.end();
- auto NonScriptI =
- std::find_if(OutputSections.begin(), E, [](OutputSectionBase *S) {
- return Script<ELFT>::X->getSectionIndex(S->getName()) == INT_MAX;
- });
while (NonScriptI != E) {
- auto BestPos = std::max_element(
- I, NonScriptI, [&](OutputSectionBase *&A, OutputSectionBase *&B) {
- bool ACanSharePtLoad = canSharePtLoad<ELFT>(**NonScriptI, *A);
- bool BCanSharePtLoad = canSharePtLoad<ELFT>(**NonScriptI, *B);
- if (ACanSharePtLoad != BCanSharePtLoad)
- return BCanSharePtLoad;
-
- bool ACmp = compareSectionsNonScript<ELFT>(*NonScriptI, A);
- bool BCmp = compareSectionsNonScript<ELFT>(*NonScriptI, B);
- if (ACmp != BCmp)
- return BCmp; // FIXME: missing test
-
- size_t PosA = &A - &OutputSections[0];
- size_t PosB = &B - &OutputSections[0];
- return ACmp ? PosA > PosB : PosA < PosB;
- });
-
- // max_element only returns NonScriptI if the range is empty. If the range
- // is not empty we should consider moving the the element forward one
- // position.
- if (BestPos != NonScriptI &&
- !compareSectionsNonScript<ELFT>(*NonScriptI, *BestPos))
- ++BestPos;
- std::rotate(BestPos, NonScriptI, NonScriptI + 1);
- ++NonScriptI;
+ auto Pos = findOrphanPos<ELFT>(I, NonScriptI);
+ OutputSection *Orphan = cast<OutputSectionCommand>(*NonScriptI)->Sec;
+
+ // As an optimization, find all sections with the same sort rank
+ // and insert them with one rotate.
+ unsigned Rank = Orphan->SortRank;
+ auto End = std::find_if(NonScriptI + 1, E, [=](BaseCommand *Cmd) {
+ return cast<OutputSectionCommand>(Cmd)->Sec->SortRank != Rank;
+ });
+ std::rotate(Pos, NonScriptI, End);
+ NonScriptI = End;
}
- Script<ELFT>::X->adjustSectionsAfterSorting();
+ Script->adjustSectionsAfterSorting();
}
-template <class ELFT>
-static void
-finalizeSynthetic(const std::vector<SyntheticSection<ELFT> *> &Sections) {
- for (SyntheticSection<ELFT> *SS : Sections)
- if (SS && SS->OutSec && !SS->empty()) {
- SS->finalize();
- SS->OutSec->Size = 0;
- SS->OutSec->assignOffsets();
- }
+static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
+ std::function<void(SyntheticSection *)> Fn) {
+ for (SyntheticSection *SS : Sections)
+ if (SS && SS->getParent() && !SS->empty())
+ Fn(SS);
}
// We need to add input synthetic sections early in createSyntheticSections()
// to make them visible from linkescript side. But not all sections are always
// required to be in output. For example we don't need dynamic section content
-// sometimes. This function filters out such unused sections from output.
-template <class ELFT>
-static void removeUnusedSyntheticSections(std::vector<OutputSectionBase *> &V) {
- // Input synthetic sections are placed after all regular ones. We iterate over
- // them all and exit at first non-synthetic.
- for (InputSectionBase<ELFT> *S : llvm::reverse(Symtab<ELFT>::X->Sections)) {
- SyntheticSection<ELFT> *SS = dyn_cast<SyntheticSection<ELFT>>(S);
+// sometimes. This function filters out such unused sections from the output.
+static void removeUnusedSyntheticSections() {
+ // All input synthetic sections that can be empty are placed after
+ // all regular ones. We iterate over them all and exit at first
+ // non-synthetic.
+ for (InputSectionBase *S : llvm::reverse(InputSections)) {
+ SyntheticSection *SS = dyn_cast<SyntheticSection>(S);
if (!SS)
return;
- if (!SS->empty() || !SS->OutSec)
+ OutputSection *OS = SS->getParent();
+ if (!SS->empty() || !OS)
+ continue;
+ if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable)
continue;
- OutputSection<ELFT> *OutSec = cast<OutputSection<ELFT>>(SS->OutSec);
- OutSec->Sections.erase(
- std::find(OutSec->Sections.begin(), OutSec->Sections.end(), SS));
- // If there is no other sections in output section, remove it from output.
- if (OutSec->Sections.empty())
- V.erase(std::find(V.begin(), V.end(), OutSec));
+ OutputSectionCommand *Cmd = Script->getCmd(OS);
+ std::vector<BaseCommand *>::iterator Empty = Cmd->Commands.end();
+ for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) {
+ BaseCommand *B = *I;
+ if (auto *ISD = dyn_cast<InputSectionDescription>(B)) {
+ auto P = std::find(ISD->Sections.begin(), ISD->Sections.end(), SS);
+ if (P != ISD->Sections.end())
+ ISD->Sections.erase(P);
+ if (ISD->Sections.empty())
+ Empty = I;
+ }
+ }
+ if (Empty != Cmd->Commands.end())
+ Cmd->Commands.erase(Empty);
+
+ // If there are no other sections in the output section, remove it from the
+ // output.
+ if (Cmd->Commands.empty()) {
+ // Also remove script commands matching the output section.
+ auto &Cmds = Script->Opt.Commands;
+ auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd) {
+ if (auto *OSCmd = dyn_cast<OutputSectionCommand>(Cmd))
+ return OSCmd->Sec == OS;
+ return false;
+ });
+ Cmds.erase(I, Cmds.end());
+ }
}
}
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::finalizeSections() {
- Out<ELFT>::DebugInfo = findSection(".debug_info");
- Out<ELFT>::PreinitArray = findSection(".preinit_array");
- Out<ELFT>::InitArray = findSection(".init_array");
- Out<ELFT>::FiniArray = findSection(".fini_array");
+ Out::DebugInfo = findSectionInScript(".debug_info");
+ Out::PreinitArray = findSectionInScript(".preinit_array");
+ Out::InitArray = findSectionInScript(".init_array");
+ Out::FiniArray = findSectionInScript(".fini_array");
// The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop
// symbols for sections, so that the runtime can get the start and end
// addresses of each section by section name. Add such symbols.
if (!Config->Relocatable) {
addStartEndSymbols();
- for (OutputSectionBase *Sec : OutputSections)
- addStartStopSymbols(Sec);
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ if (Cmd->Sec)
+ addStartStopSymbols(Cmd->Sec);
}
// Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
// It should be okay as no one seems to care about the type.
// Even the author of gold doesn't remember why gold behaves that way.
// https://sourceware.org/ml/binutils/2002-03/msg00360.html
- if (In<ELFT>::DynSymTab)
- addRegular("_DYNAMIC", In<ELFT>::Dynamic, 0);
+ if (InX::DynSymTab)
+ addRegular<ELFT>("_DYNAMIC", InX::Dynamic, 0);
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
- if (!Out<ELFT>::EhFrame->empty()) {
- OutputSections.push_back(Out<ELFT>::EhFrame);
- Out<ELFT>::EhFrame->finalize();
- }
+ // This responsible for splitting up .eh_frame section into
+ // pieces. The relocation scan uses those pieces, so this has to be
+ // earlier.
+ applySynthetic({In<ELFT>::EhFrame},
+ [](SyntheticSection *SS) { SS->finalizeContents(); });
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
forEachRelSec(scanRelocations<ELFT>);
- // Now that we have defined all possible symbols including linker-
+ if (InX::Plt && !InX::Plt->empty())
+ InX::Plt->addSymbols();
+ if (InX::Iplt && !InX::Iplt->empty())
+ InX::Iplt->addSymbols();
+
+ // Now that we have defined all possible global symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
for (Symbol *S : Symtab<ELFT>::X->getSymbols()) {
SymbolBody *Body = S->body();
- if (!includeInSymtab<ELFT>(*Body))
+ if (!includeInSymtab(*Body))
continue;
- if (In<ELFT>::SymTab)
- In<ELFT>::SymTab->addGlobal(Body);
+ if (InX::SymTab)
+ InX::SymTab->addSymbol(Body);
- if (In<ELFT>::DynSymTab && S->includeInDynsym()) {
- In<ELFT>::DynSymTab->addGlobal(Body);
- if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(Body))
- if (SS->file()->isNeeded())
+ if (InX::DynSymTab && S->includeInDynsym()) {
+ InX::DynSymTab->addSymbol(Body);
+ if (auto *SS = dyn_cast<SharedSymbol>(Body))
+ if (cast<SharedFile<ELFT>>(SS->File)->isNeeded())
In<ELFT>::VerNeed->addSymbol(SS);
}
}
@@ -1044,79 +1244,127 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (ErrorCount)
return;
- // So far we have added sections from input object files.
- // This function adds linker-created Out<ELFT>::* sections.
addPredefinedSections();
- removeUnusedSyntheticSections<ELFT>(OutputSections);
+ removeUnusedSyntheticSections();
sortSections();
+ // Now that we have the final list, create a list of all the
+ // OutputSectionCommands for convenience.
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ OutputSectionCommands.push_back(Cmd);
+
+ // Prefer command line supplied address over other constraints.
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ auto I = Config->SectionStartMap.find(Cmd->Name);
+ if (I != Config->SectionStartMap.end())
+ Cmd->AddrExpr = [=] { return I->second; };
+ }
+
+ // This is a bit of a hack. A value of 0 means undef, so we set it
+ // to 1 t make __ehdr_start defined. The section number is not
+ // particularly relevant.
+ Out::ElfHeader->SectionIndex = 1;
+
unsigned I = 1;
- for (OutputSectionBase *Sec : OutputSections) {
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
Sec->SectionIndex = I++;
- Sec->ShName = In<ELFT>::ShStrTab->addString(Sec->getName());
+ Sec->ShName = InX::ShStrTab->addString(Sec->Name);
}
// Binary and relocatable output does not have PHDRS.
// The headers have to be created before finalize as that can influence the
// image base and the dynamic section on mips includes the image base.
if (!Config->Relocatable && !Config->OFormatBinary) {
- Phdrs = Script<ELFT>::X->hasPhdrsCommands() ? Script<ELFT>::X->createPhdrs()
- : createPhdrs();
+ Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs();
addPtArmExid(Phdrs);
- fixHeaders();
+ Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
+ }
+
+ // Dynamic section must be the last one in this list and dynamic
+ // symbol table section (DynSymTab) must be the first one.
+ applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo,
+ InX::GnuHashTab, In<ELFT>::HashTab, InX::SymTab,
+ InX::ShStrTab, InX::StrTab, In<ELFT>::VerDef,
+ InX::DynStrTab, InX::GdbIndex, InX::Got,
+ InX::MipsGot, InX::IgotPlt, InX::GotPlt,
+ In<ELFT>::RelaDyn, In<ELFT>::RelaIplt, In<ELFT>::RelaPlt,
+ InX::Plt, InX::Iplt, In<ELFT>::EhFrameHdr,
+ In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic},
+ [](SyntheticSection *SS) { SS->finalizeContents(); });
+
+ // Some architectures use small displacements for jump instructions.
+ // It is linker's responsibility to create thunks containing long
+ // jump instructions if jump targets are too far. Create thunks.
+ if (Target->NeedsThunks) {
+ // FIXME: only ARM Interworking and Mips LA25 Thunks are implemented,
+ // these
+ // do not require address information. To support range extension Thunks
+ // we need to assign addresses so that we can tell if jump instructions
+ // are out of range. This will need to turn into a loop that converges
+ // when no more Thunks are added
+ ThunkCreator TC;
+ Script->assignAddresses();
+ if (TC.createThunks(OutputSectionCommands)) {
+ applySynthetic({InX::MipsGot},
+ [](SyntheticSection *SS) { SS->updateAllocSize(); });
+ if (TC.createThunks(OutputSectionCommands))
+ fatal("All non-range thunks should be created in first call");
+ }
}
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
// of finalizing other sections.
- for (OutputSectionBase *Sec : OutputSections)
- Sec->finalize();
+ for (OutputSectionCommand *Cmd : OutputSectionCommands)
+ Cmd->finalize<ELFT>();
- // Dynamic section must be the last one in this list and dynamic
- // symbol table section (DynSymTab) must be the first one.
- finalizeSynthetic<ELFT>(
- {In<ELFT>::DynSymTab, In<ELFT>::GnuHashTab, In<ELFT>::HashTab,
- In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab,
- In<ELFT>::VerDef, In<ELFT>::DynStrTab, In<ELFT>::GdbIndex,
- In<ELFT>::Got, In<ELFT>::MipsGot, In<ELFT>::IgotPlt,
- In<ELFT>::GotPlt, In<ELFT>::RelaDyn, In<ELFT>::RelaIplt,
- In<ELFT>::RelaPlt, In<ELFT>::Plt, In<ELFT>::Iplt,
- In<ELFT>::Plt, In<ELFT>::EhFrameHdr, In<ELFT>::VerSym,
- In<ELFT>::VerNeed, In<ELFT>::Dynamic});
+ // createThunks may have added local symbols to the static symbol table
+ applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},
+ [](SyntheticSection *SS) { SS->postThunkContents(); });
}
template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
- if (Out<ELFT>::Bss->Size > 0)
- OutputSections.push_back(Out<ELFT>::Bss);
- if (Out<ELFT>::BssRelRo->Size > 0)
- OutputSections.push_back(Out<ELFT>::BssRelRo);
-
- auto OS = dyn_cast_or_null<OutputSection<ELFT>>(findSection(".ARM.exidx"));
- if (OS && !OS->Sections.empty() && !Config->Relocatable)
- OS->addSection(make<ARMExidxSentinelSection<ELFT>>());
-
- addInputSec(In<ELFT>::SymTab);
- addInputSec(In<ELFT>::ShStrTab);
- addInputSec(In<ELFT>::StrTab);
+ // ARM ABI requires .ARM.exidx to be terminated by some piece of data.
+ // We have the terminater synthetic section class. Add that at the end.
+ OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx");
+ if (!Cmd || !Cmd->Sec || Config->Relocatable)
+ return;
+
+ auto *Sentinel = make<ARMExidxSentinelSection>();
+ Cmd->Sec->addSection(Sentinel);
+ // Add the sentinel to the last of these too.
+ auto ISD = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
+ [](const BaseCommand *Base) {
+ return isa<InputSectionDescription>(Base);
+ });
+ cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel);
}
// The linker is expected to define SECNAME_start and SECNAME_end
// symbols for a few sections. This function defines them.
template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
- auto Define = [&](StringRef Start, StringRef End, OutputSectionBase *OS) {
+ auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) {
// These symbols resolve to the image base if the section does not exist.
// A special value -1 indicates end of the section.
- addOptionalSynthetic<ELFT>(Start, OS, 0);
- addOptionalSynthetic<ELFT>(End, OS, OS ? -1 : 0);
+ if (OS) {
+ addOptionalRegular<ELFT>(Start, OS, 0);
+ addOptionalRegular<ELFT>(End, OS, -1);
+ } else {
+ if (Config->Pic)
+ OS = Out::ElfHeader;
+ addOptionalRegular<ELFT>(Start, OS, 0);
+ addOptionalRegular<ELFT>(End, OS, 0);
+ }
};
- Define("__preinit_array_start", "__preinit_array_end",
- Out<ELFT>::PreinitArray);
- Define("__init_array_start", "__init_array_end", Out<ELFT>::InitArray);
- Define("__fini_array_start", "__fini_array_end", Out<ELFT>::FiniArray);
+ Define("__preinit_array_start", "__preinit_array_end", Out::PreinitArray);
+ Define("__init_array_start", "__init_array_end", Out::InitArray);
+ Define("__fini_array_start", "__fini_array_end", Out::FiniArray);
- if (OutputSectionBase *Sec = findSection(".ARM.exidx"))
+ if (OutputSection *Sec = findSectionInScript(".ARM.exidx"))
Define("__exidx_start", "__exidx_end", Sec);
}
@@ -1126,23 +1374,31 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
// respectively. This is not requested by the ELF standard, but GNU ld and
// gold provide the feature, and used by many programs.
template <class ELFT>
-void Writer<ELFT>::addStartStopSymbols(OutputSectionBase *Sec) {
- StringRef S = Sec->getName();
+void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
+ StringRef S = Sec->Name;
if (!isValidCIdentifier(S))
return;
- addOptionalSynthetic<ELFT>(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT);
- addOptionalSynthetic<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
+ addOptionalRegular<ELFT>(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT);
+ addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
}
template <class ELFT>
-OutputSectionBase *Writer<ELFT>::findSection(StringRef Name) {
- for (OutputSectionBase *Sec : OutputSections)
- if (Sec->getName() == Name)
- return Sec;
+OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) {
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ if (Cmd->Name == Name)
+ return Cmd;
return nullptr;
}
-template <class ELFT> static bool needsPtLoad(OutputSectionBase *Sec) {
+template <class ELFT>
+OutputSection *Writer<ELFT>::findSectionInScript(StringRef Name) {
+ if (OutputSectionCommand *Cmd = findSectionCommand(Name))
+ return Cmd->Sec;
+ return nullptr;
+}
+
+static bool needsPtLoad(OutputSection *Sec) {
if (!(Sec->Flags & SHF_ALLOC))
return false;
@@ -1158,13 +1414,12 @@ template <class ELFT> static bool needsPtLoad(OutputSectionBase *Sec) {
// linker scripts are designed for creating two PT_LOADs only, one RX and one
// RW. This means that there is no alignment in the RO to RX transition and we
// cannot create a PT_LOAD there.
-template <class ELFT>
-static typename ELFT::uint computeFlags(typename ELFT::uint F) {
- if (Config->OMagic)
+static uint64_t computeFlags(uint64_t Flags) {
+ if (Config->Omagic)
return PF_R | PF_W | PF_X;
- if (Config->SingleRoRx && !(F & PF_W))
- return F | PF_X;
- return F;
+ if (Config->SingleRoRx && !(Flags & PF_W))
+ return Flags | PF_X;
+ return Flags;
}
// Decide which program headers to create and which sections to include in each
@@ -1177,33 +1432,25 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
};
// The first phdr entry is PT_PHDR which describes the program header itself.
- PhdrEntry &Hdr = *AddHdr(PT_PHDR, PF_R);
- Hdr.add(Out<ELFT>::ProgramHeaders);
+ AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders);
// PT_INTERP must be the second entry if exists.
- if (OutputSectionBase *Sec = findSection(".interp")) {
- PhdrEntry &Hdr = *AddHdr(PT_INTERP, Sec->getPhdrFlags());
- Hdr.add(Sec);
- }
+ if (OutputSection *Sec = findSectionInScript(".interp"))
+ AddHdr(PT_INTERP, Sec->getPhdrFlags())->add(Sec);
// Add the first PT_LOAD segment for regular output sections.
- uintX_t Flags = computeFlags<ELFT>(PF_R);
+ uint64_t Flags = computeFlags(PF_R);
PhdrEntry *Load = AddHdr(PT_LOAD, Flags);
- PhdrEntry TlsHdr(PT_TLS, PF_R);
- PhdrEntry RelRo(PT_GNU_RELRO, PF_R);
- PhdrEntry Note(PT_NOTE, PF_R);
- for (OutputSectionBase *Sec : OutputSections) {
+ // Add the headers. We will remove them if they don't fit.
+ Load->add(Out::ElfHeader);
+ Load->add(Out::ProgramHeaders);
+
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
if (!(Sec->Flags & SHF_ALLOC))
break;
-
- // If we meet TLS section then we create TLS header
- // and put all TLS sections inside for further use when
- // assign addresses.
- if (Sec->Flags & SHF_TLS)
- TlsHdr.add(Sec);
-
- if (!needsPtLoad<ELFT>(Sec))
+ if (!needsPtLoad(Sec))
continue;
// Segments are contiguous memory regions that has the same attributes
@@ -1211,58 +1458,62 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
// Therefore, we need to create a new phdr when the next section has
// different flags or is loaded at a discontiguous address using AT linker
// script command.
- uintX_t NewFlags = computeFlags<ELFT>(Sec->getPhdrFlags());
- if (Script<ELFT>::X->hasLMA(Sec->getName()) || Flags != NewFlags) {
+ uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
+ if (Cmd->LMAExpr || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
Flags = NewFlags;
}
Load->add(Sec);
-
- if (isRelroSection<ELFT>(Sec))
- RelRo.add(Sec);
- if (Sec->Type == SHT_NOTE)
- Note.add(Sec);
}
- // Add the TLS segment unless it's empty.
+ // Add a TLS segment if any.
+ PhdrEntry TlsHdr(PT_TLS, PF_R);
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
+ if (Sec->Flags & SHF_TLS)
+ TlsHdr.add(Sec);
+ }
if (TlsHdr.First)
Ret.push_back(std::move(TlsHdr));
// Add an entry for .dynamic.
- if (In<ELFT>::DynSymTab) {
- PhdrEntry &H =
- *AddHdr(PT_DYNAMIC, In<ELFT>::Dynamic->OutSec->getPhdrFlags());
- H.add(In<ELFT>::Dynamic->OutSec);
- }
+ if (InX::DynSymTab)
+ AddHdr(PT_DYNAMIC, InX::Dynamic->getParent()->getPhdrFlags())
+ ->add(InX::Dynamic->getParent());
// PT_GNU_RELRO includes all sections that should be marked as
// read-only by dynamic linker after proccessing relocations.
+ PhdrEntry RelRo(PT_GNU_RELRO, PF_R);
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
+ if (needsPtLoad(Sec) && isRelroSection(Sec))
+ RelRo.add(Sec);
+ }
if (RelRo.First)
Ret.push_back(std::move(RelRo));
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
- if (!Out<ELFT>::EhFrame->empty() && In<ELFT>::EhFrameHdr) {
- PhdrEntry &Hdr =
- *AddHdr(PT_GNU_EH_FRAME, In<ELFT>::EhFrameHdr->OutSec->getPhdrFlags());
- Hdr.add(In<ELFT>::EhFrameHdr->OutSec);
- }
+ if (!In<ELFT>::EhFrame->empty() && In<ELFT>::EhFrameHdr &&
+ In<ELFT>::EhFrame->getParent() && In<ELFT>::EhFrameHdr->getParent())
+ AddHdr(PT_GNU_EH_FRAME, In<ELFT>::EhFrameHdr->getParent()->getPhdrFlags())
+ ->add(In<ELFT>::EhFrameHdr->getParent());
- // PT_OPENBSD_RANDOMIZE specifies the location and size of a part of the
- // memory image of the program that must be filled with random data before any
- // code in the object is executed.
- if (OutputSectionBase *Sec = findSection(".openbsd.randomdata")) {
- PhdrEntry &Hdr = *AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags());
- Hdr.add(Sec);
- }
+ // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes
+ // the dynamic linker fill the segment with random data.
+ if (OutputSection *Sec = findSectionInScript(".openbsd.randomdata"))
+ AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags())->add(Sec);
// PT_GNU_STACK is a special section to tell the loader to make the
- // pages for the stack non-executable.
- if (!Config->ZExecstack) {
- PhdrEntry &Hdr = *AddHdr(PT_GNU_STACK, PF_R | PF_W);
- if (Config->ZStackSize != uint64_t(-1))
- Hdr.p_memsz = Config->ZStackSize;
- }
+ // pages for the stack non-executable. If you really want an executable
+ // stack, you can pass -z execstack, but that's not recommended for
+ // security reasons.
+ unsigned Perm;
+ if (Config->ZExecstack)
+ Perm = PF_R | PF_W | PF_X;
+ else
+ Perm = PF_R | PF_W;
+ AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize;
// PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable
// is expected to perform W^X violations, such as calling mprotect(2) or
@@ -1271,8 +1522,18 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() {
if (Config->ZWxneeded)
AddHdr(PT_OPENBSD_WXNEEDED, PF_X);
- if (Note.First)
- Ret.push_back(std::move(Note));
+ // Create one PT_NOTE per a group of contiguous .note sections.
+ PhdrEntry *Note = nullptr;
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
+ if (Sec->Type == SHT_NOTE) {
+ if (!Note || Cmd->LMAExpr)
+ Note = AddHdr(PT_NOTE, PF_R);
+ Note->add(Sec);
+ } else {
+ Note = nullptr;
+ }
+ }
return Ret;
}
@@ -1280,15 +1541,15 @@ template <class ELFT>
void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) {
if (Config->EMachine != EM_ARM)
return;
- auto I = std::find_if(
- OutputSections.begin(), OutputSections.end(),
- [](OutputSectionBase *Sec) { return Sec->Type == SHT_ARM_EXIDX; });
- if (I == OutputSections.end())
+ auto I = llvm::find_if(OutputSectionCommands, [](OutputSectionCommand *Cmd) {
+ return Cmd->Sec->Type == SHT_ARM_EXIDX;
+ });
+ if (I == OutputSectionCommands.end())
return;
// PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME
PhdrEntry ARMExidx(PT_ARM_EXIDX, PF_R);
- ARMExidx.add(*I);
+ ARMExidx.add((*I)->Sec);
Phdrs.push_back(ARMExidx);
}
@@ -1296,102 +1557,33 @@ void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) {
// first section after PT_GNU_RELRO have to be page aligned so that the dynamic
// linker can set the permissions.
template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
+ auto PageAlign = [](OutputSection *Sec) {
+ OutputSectionCommand *Cmd = Script->getCmd(Sec);
+ if (Cmd && !Cmd->AddrExpr)
+ Cmd->AddrExpr = [=] {
+ return alignTo(Script->getDot(), Config->MaxPageSize);
+ };
+ };
+
for (const PhdrEntry &P : Phdrs)
if (P.p_type == PT_LOAD && P.First)
- P.First->PageAlign = true;
+ PageAlign(P.First);
for (const PhdrEntry &P : Phdrs) {
if (P.p_type != PT_GNU_RELRO)
continue;
if (P.First)
- P.First->PageAlign = true;
+ PageAlign(P.First);
// Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
// have to align it to a page.
- auto End = OutputSections.end();
- auto I = std::find(OutputSections.begin(), End, P.Last);
+ auto End = OutputSectionCommands.end();
+ auto I =
+ std::find(OutputSectionCommands.begin(), End, Script->getCmd(P.Last));
if (I == End || (I + 1) == End)
continue;
- OutputSectionBase *Sec = *(I + 1);
- if (needsPtLoad<ELFT>(Sec))
- Sec->PageAlign = true;
- }
-}
-
-template <class ELFT>
-void elf::allocateHeaders(MutableArrayRef<PhdrEntry> Phdrs,
- ArrayRef<OutputSectionBase *> OutputSections) {
- auto FirstPTLoad =
- std::find_if(Phdrs.begin(), Phdrs.end(),
- [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
- if (FirstPTLoad == Phdrs.end())
- return;
- if (FirstPTLoad->First)
- for (OutputSectionBase *Sec : OutputSections)
- if (Sec->FirstInPtLoad == FirstPTLoad->First)
- Sec->FirstInPtLoad = Out<ELFT>::ElfHeader;
- FirstPTLoad->First = Out<ELFT>::ElfHeader;
- if (!FirstPTLoad->Last)
- FirstPTLoad->Last = Out<ELFT>::ProgramHeaders;
-}
-
-// We should set file offsets and VAs for elf header and program headers
-// sections. These are special, we do not include them into output sections
-// list, but have them to simplify the code.
-template <class ELFT> void Writer<ELFT>::fixHeaders() {
- Out<ELFT>::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
- // If the script has SECTIONS, assignAddresses will compute the values.
- if (ScriptConfig->HasSections)
- return;
-
- uintX_t HeaderSize = getHeaderSize<ELFT>();
- // When -T<section> option is specified, lower the base to make room for those
- // sections.
- if (!Config->SectionStartMap.empty()) {
- uint64_t Min = -1;
- for (const auto &P : Config->SectionStartMap)
- Min = std::min(Min, P.second);
- if (HeaderSize < Min)
- Min -= HeaderSize;
- else
- AllocateHeader = false;
- if (Min < Config->ImageBase)
- Config->ImageBase = alignDown(Min, Config->MaxPageSize);
- }
-
- if (AllocateHeader)
- allocateHeaders<ELFT>(Phdrs, OutputSections);
-
- uintX_t BaseVA = Config->ImageBase;
- Out<ELFT>::ElfHeader->Addr = BaseVA;
- Out<ELFT>::ProgramHeaders->Addr = BaseVA + Out<ELFT>::ElfHeader->Size;
-}
-
-// Assign VAs (addresses at run-time) to output sections.
-template <class ELFT> void Writer<ELFT>::assignAddresses() {
- uintX_t VA = Config->ImageBase;
- if (AllocateHeader)
- VA += getHeaderSize<ELFT>();
- uintX_t ThreadBssOffset = 0;
- for (OutputSectionBase *Sec : OutputSections) {
- uintX_t Alignment = Sec->Addralign;
- if (Sec->PageAlign)
- Alignment = std::max<uintX_t>(Alignment, Config->MaxPageSize);
-
- auto I = Config->SectionStartMap.find(Sec->getName());
- if (I != Config->SectionStartMap.end())
- VA = I->second;
-
- // We only assign VAs to allocated sections.
- if (needsPtLoad<ELFT>(Sec)) {
- VA = alignTo(VA, Alignment);
- Sec->Addr = VA;
- VA += Sec->Size;
- } else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) {
- uintX_t TVA = VA + ThreadBssOffset;
- TVA = alignTo(TVA, Alignment);
- Sec->Addr = TVA;
- ThreadBssOffset = TVA - VA + Sec->Size;
- }
+ OutputSection *Sec = (*(I + 1))->Sec;
+ if (needsPtLoad(Sec))
+ PageAlign(Sec);
}
}
@@ -1399,12 +1591,11 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
// its new file offset. The file offset must be the same with its
// virtual address (modulo the page size) so that the loader can load
// executables without any address adjustment.
-template <class ELFT, class uintX_t>
-static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase *Sec) {
- OutputSectionBase *First = Sec->FirstInPtLoad;
+static uint64_t getFileAlignment(uint64_t Off, OutputSection *Sec) {
+ OutputSection *First = Sec->FirstInPtLoad;
// If the section is not in a PT_LOAD, we just have to align it.
if (!First)
- return alignTo(Off, Sec->Addralign);
+ return alignTo(Off, Sec->Alignment);
// The first section in a PT_LOAD has to have congruent offset and address
// module the page size.
@@ -1416,45 +1607,47 @@ static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase *Sec) {
return First->Offset + Sec->Addr - First->Addr;
}
-template <class ELFT, class uintX_t>
-void setOffset(OutputSectionBase *Sec, uintX_t &Off) {
+static uint64_t setOffset(OutputSection *Sec, uint64_t Off) {
if (Sec->Type == SHT_NOBITS) {
Sec->Offset = Off;
- return;
+ return Off;
}
- Off = getFileAlignment<ELFT>(Off, Sec);
+ Off = getFileAlignment(Off, Sec);
Sec->Offset = Off;
- Off += Sec->Size;
+ return Off + Sec->Size;
}
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
- uintX_t Off = 0;
- for (OutputSectionBase *Sec : OutputSections)
+ uint64_t Off = 0;
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
if (Sec->Flags & SHF_ALLOC)
- setOffset<ELFT>(Sec, Off);
- FileSize = alignTo(Off, sizeof(uintX_t));
+ Off = setOffset(Sec, Off);
+ }
+ FileSize = alignTo(Off, Config->Wordsize);
}
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
- uintX_t Off = 0;
- setOffset<ELFT>(Out<ELFT>::ElfHeader, Off);
- setOffset<ELFT>(Out<ELFT>::ProgramHeaders, Off);
+ uint64_t Off = 0;
+ Off = setOffset(Out::ElfHeader, Off);
+ Off = setOffset(Out::ProgramHeaders, Off);
- for (OutputSectionBase *Sec : OutputSections)
- setOffset<ELFT>(Sec, Off);
+ for (OutputSectionCommand *Cmd : OutputSectionCommands)
+ Off = setOffset(Cmd->Sec, Off);
- SectionHeaderOff = alignTo(Off, sizeof(uintX_t));
- FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
+ SectionHeaderOff = alignTo(Off, Config->Wordsize);
+ FileSize =
+ SectionHeaderOff + (OutputSectionCommands.size() + 1) * sizeof(Elf_Shdr);
}
// Finalize the program headers. We call this function after we assign
// file offsets and VAs to all sections.
template <class ELFT> void Writer<ELFT>::setPhdrs() {
for (PhdrEntry &P : Phdrs) {
- OutputSectionBase *First = P.First;
- OutputSectionBase *Last = P.Last;
+ OutputSection *First = P.First;
+ OutputSection *Last = P.Last;
if (First) {
P.p_filesz = Last->Offset - First->Offset;
if (Last->Type != SHT_NOBITS)
@@ -1467,13 +1660,18 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
}
if (P.p_type == PT_LOAD)
P.p_align = Config->MaxPageSize;
- else if (P.p_type == PT_GNU_RELRO)
+ else if (P.p_type == PT_GNU_RELRO) {
P.p_align = 1;
+ // The glibc dynamic loader rounds the size down, so we need to round up
+ // to protect the last page. This is a no-op on FreeBSD which always
+ // rounds up.
+ P.p_memsz = alignTo(P.p_memsz, Target->PageSize);
+ }
// The TLS pointer goes after PT_TLS. At least glibc will align it,
// so round up the size to make sure the offsets are correct.
if (P.p_type == PT_TLS) {
- Out<ELFT>::TlsPhdr = &P;
+ Out::TlsPhdr = &P;
if (P.p_memsz)
P.p_memsz = alignTo(P.p_memsz, P.p_align);
}
@@ -1487,17 +1685,17 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
// 3. the value of the symbol start, if present;
// 4. the address of the first byte of the .text section, if present;
// 5. the address 0.
-template <class ELFT> typename ELFT::uint Writer<ELFT>::getEntryAddr() {
+template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() {
// Case 1, 2 or 3. As a special case, if the symbol is actually
// a number, we'll use that number as an address.
if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Entry))
- return B->getVA<ELFT>();
+ return B->getVA();
uint64_t Addr;
- if (!Config->Entry.getAsInteger(0, Addr))
+ if (to_integer(Config->Entry, Addr))
return Addr;
// Case 4
- if (OutputSectionBase *Sec = findSection(".text")) {
+ if (OutputSection *Sec = findSectionInScript(".text")) {
if (Config->WarnMissingEntry)
warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" +
utohexstr(Sec->Addr));
@@ -1511,12 +1709,6 @@ template <class ELFT> typename ELFT::uint Writer<ELFT>::getEntryAddr() {
return 0;
}
-template <class ELFT> static uint8_t getELFEncoding() {
- if (ELFT::TargetEndianness == llvm::support::little)
- return ELFDATA2LSB;
- return ELFDATA2MSB;
-}
-
static uint16_t getELFType() {
if (Config->Pic)
return ET_DYN;
@@ -1526,52 +1718,60 @@ static uint16_t getELFType() {
}
// This function is called after we have assigned address and size
-// to each section. This function fixes some predefined absolute
+// to each section. This function fixes some predefined
// symbol values that depend on section address and size.
-template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
- // __ehdr_start is the location of program headers.
- if (ElfSym<ELFT>::EhdrStart)
- ElfSym<ELFT>::EhdrStart->Value = Out<ELFT>::ProgramHeaders->Addr;
-
- auto Set = [](DefinedRegular<ELFT> *S1, DefinedRegular<ELFT> *S2, uintX_t V) {
- if (S1)
- S1->Value = V;
- if (S2)
- S2->Value = V;
- };
-
+template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
// _etext is the first location after the last read-only loadable segment.
// _edata is the first location after the last read-write loadable segment.
// _end is the first location after the uninitialized data region.
+ PhdrEntry *Last = nullptr;
+ PhdrEntry *LastRO = nullptr;
+ PhdrEntry *LastRW = nullptr;
for (PhdrEntry &P : Phdrs) {
if (P.p_type != PT_LOAD)
continue;
- Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, P.p_vaddr + P.p_memsz);
-
- uintX_t Val = P.p_vaddr + P.p_filesz;
+ Last = &P;
if (P.p_flags & PF_W)
- Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, Val);
+ LastRW = &P;
else
- Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, Val);
+ LastRO = &P;
+ }
+
+ auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) {
+ if (S) {
+ S->Section = Sec;
+ S->Value = Value;
+ }
+ };
+
+ if (Last) {
+ Set(ElfSym::End1, Last->First, Last->p_memsz);
+ Set(ElfSym::End2, Last->First, Last->p_memsz);
+ }
+ if (LastRO) {
+ Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz);
+ Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz);
}
+ if (LastRW) {
+ Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz);
+ Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz);
+ }
+
+ if (ElfSym::Bss)
+ ElfSym::Bss->Section = findSectionInScript(".bss");
// Setup MIPS _gp_disp/__gnu_local_gp symbols which should
// be equal to the _gp symbol's value.
- if (Config->EMachine == EM_MIPS) {
- if (!ElfSym<ELFT>::MipsGp->Value) {
- // Find GP-relative section with the lowest address
- // and use this address to calculate default _gp value.
- uintX_t Gp = -1;
- for (const OutputSectionBase * OS : OutputSections)
- if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp)
- Gp = OS->Addr;
- if (Gp != (uintX_t)-1)
- ElfSym<ELFT>::MipsGp->Value = Gp + 0x7ff0;
+ if (Config->EMachine == EM_MIPS && !ElfSym::MipsGp->Value) {
+ // Find GP-relative section with the lowest address
+ // and use this address to calculate default _gp value.
+ for (const OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *OS = Cmd->Sec;
+ if (OS->Flags & SHF_MIPS_GPREL) {
+ ElfSym::MipsGp->Value = OS->Addr + 0x7ff0;
+ break;
+ }
}
- if (ElfSym<ELFT>::MipsGpDisp)
- ElfSym<ELFT>::MipsGpDisp->Value = ElfSym<ELFT>::MipsGp->Value;
- if (ElfSym<ELFT>::MipsLocalGp)
- ElfSym<ELFT>::MipsLocalGp->Value = ElfSym<ELFT>::MipsGp->Value;
}
}
@@ -1581,8 +1781,8 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
// Write the ELF header.
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Buf);
- EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
- EHdr->e_ident[EI_DATA] = getELFEncoding<ELFT>();
+ EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32;
+ EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB;
EHdr->e_ident[EI_VERSION] = EV_CURRENT;
EHdr->e_ident[EI_OSABI] = Config->OSABI;
EHdr->e_type = getELFType();
@@ -1593,8 +1793,8 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
EHdr->e_ehsize = sizeof(Elf_Ehdr);
EHdr->e_phnum = Phdrs.size();
EHdr->e_shentsize = sizeof(Elf_Shdr);
- EHdr->e_shnum = OutputSections.size() + 1;
- EHdr->e_shstrndx = In<ELFT>::ShStrTab->OutSec->SectionIndex;
+ EHdr->e_shnum = OutputSectionCommands.size() + 1;
+ EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex;
if (Config->EMachine == EM_ARM)
// We don't currently use any features incompatible with EF_ARM_EABI_VER5,
@@ -1625,63 +1825,35 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
// Write the section header table. Note that the first table entry is null.
auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff);
- for (OutputSectionBase *Sec : OutputSections)
- Sec->writeHeaderTo<ELFT>(++SHdrs);
+ for (OutputSectionCommand *Cmd : OutputSectionCommands)
+ Cmd->Sec->writeHeaderTo<ELFT>(++SHdrs);
}
-// Removes a given file asynchronously. This is a performance hack,
-// so remove this when operating systems are improved.
-//
-// On Linux (and probably on other Unix-like systems), unlink(2) is a
-// noticeably slow system call. As of 2016, unlink takes 250
-// milliseconds to remove a 1 GB file on ext4 filesystem on my machine.
-//
-// To create a new result file, we first remove existing file. So, if
-// you repeatedly link a 1 GB program in a regular compile-link-debug
-// cycle, every cycle wastes 250 milliseconds only to remove a file.
-// Since LLD can link a 1 GB binary in about 5 seconds, that waste
-// actually counts.
-//
-// This function spawns a background thread to call unlink.
-// The calling thread returns almost immediately.
-static void unlinkAsync(StringRef Path) {
- if (!Config->Threads || !sys::fs::exists(Config->OutputFile))
- return;
-
- // First, rename Path to avoid race condition. We cannot remove
- // Path from a different thread because we are now going to create
- // Path as a new file. If we do that in a different thread, the new
- // thread can remove the new file.
- SmallString<128> TempPath;
- if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath))
- return;
- if (sys::fs::rename(Path, TempPath)) {
- sys::fs::remove(TempPath);
+// Open a result file.
+template <class ELFT> void Writer<ELFT>::openFile() {
+ if (!Config->Is64 && FileSize > UINT32_MAX) {
+ error("output file too large: " + Twine(FileSize) + " bytes");
return;
}
- // Remove TempPath in background.
- std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach();
-}
-
-// Open a result file.
-template <class ELFT> void Writer<ELFT>::openFile() {
unlinkAsync(Config->OutputFile);
ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
FileOutputBuffer::create(Config->OutputFile, FileSize,
FileOutputBuffer::F_executable);
if (auto EC = BufferOrErr.getError())
- error(EC, "failed to open " + Config->OutputFile);
+ error("failed to open " + Config->OutputFile + ": " + EC.message());
else
Buffer = std::move(*BufferOrErr);
}
template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
uint8_t *Buf = Buffer->getBufferStart();
- for (OutputSectionBase *Sec : OutputSections)
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
if (Sec->Flags & SHF_ALLOC)
- Sec->writeTo(Buf + Sec->Offset);
+ Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+ }
}
// Write section contents to a mmap'ed file.
@@ -1690,54 +1862,52 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
// PPC64 needs to process relocations in the .opd section
// before processing relocations in code-containing sections.
- Out<ELFT>::Opd = findSection(".opd");
- if (Out<ELFT>::Opd) {
- Out<ELFT>::OpdBuf = Buf + Out<ELFT>::Opd->Offset;
- Out<ELFT>::Opd->writeTo(Buf + Out<ELFT>::Opd->Offset);
+ if (auto *OpdCmd = findSectionCommand(".opd")) {
+ Out::Opd = OpdCmd->Sec;
+ Out::OpdBuf = Buf + Out::Opd->Offset;
+ OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
}
- OutputSectionBase *EhFrameHdr =
- In<ELFT>::EhFrameHdr ? In<ELFT>::EhFrameHdr->OutSec : nullptr;
- for (OutputSectionBase *Sec : OutputSections)
- if (Sec != Out<ELFT>::Opd && Sec != EhFrameHdr)
- Sec->writeTo(Buf + Sec->Offset);
+ OutputSection *EhFrameHdr =
+ (In<ELFT>::EhFrameHdr && !In<ELFT>::EhFrameHdr->empty())
+ ? In<ELFT>::EhFrameHdr->getParent()
+ : nullptr;
+
+ // In -r or -emit-relocs mode, write the relocation sections first as in
+ // ELf_Rel targets we might find out that we need to modify the relocated
+ // section while doing it.
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
+ if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
+ Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+ }
+
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
+ if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
+ Sec->Type != SHT_RELA)
+ Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+ }
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
// it should be written after .eh_frame is written.
- if (!Out<ELFT>::EhFrame->empty() && EhFrameHdr)
- EhFrameHdr->writeTo(Buf + EhFrameHdr->Offset);
+ if (EhFrameHdr) {
+ OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr);
+ Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
+ }
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {
- if (!In<ELFT>::BuildId || !In<ELFT>::BuildId->OutSec)
+ if (!InX::BuildId || !InX::BuildId->getParent())
return;
// Compute a hash of all sections of the output file.
uint8_t *Start = Buffer->getBufferStart();
uint8_t *End = Start + FileSize;
- In<ELFT>::BuildId->writeBuildId({Start, End});
+ InX::BuildId->writeBuildId({Start, End});
}
template void elf::writeResult<ELF32LE>();
template void elf::writeResult<ELF32BE>();
template void elf::writeResult<ELF64LE>();
template void elf::writeResult<ELF64BE>();
-
-template void elf::allocateHeaders<ELF32LE>(MutableArrayRef<PhdrEntry>,
- ArrayRef<OutputSectionBase *>);
-template void elf::allocateHeaders<ELF32BE>(MutableArrayRef<PhdrEntry>,
- ArrayRef<OutputSectionBase *>);
-template void elf::allocateHeaders<ELF64LE>(MutableArrayRef<PhdrEntry>,
- ArrayRef<OutputSectionBase *>);
-template void elf::allocateHeaders<ELF64BE>(MutableArrayRef<PhdrEntry>,
- ArrayRef<OutputSectionBase *>);
-
-template bool elf::isRelroSection<ELF32LE>(const OutputSectionBase *);
-template bool elf::isRelroSection<ELF32BE>(const OutputSectionBase *);
-template bool elf::isRelroSection<ELF64LE>(const OutputSectionBase *);
-template bool elf::isRelroSection<ELF64BE>(const OutputSectionBase *);
-
-template void elf::reportDiscarded<ELF32LE>(InputSectionBase<ELF32LE> *);
-template void elf::reportDiscarded<ELF32BE>(InputSectionBase<ELF32BE> *);
-template void elf::reportDiscarded<ELF64LE>(InputSectionBase<ELF64LE> *);
-template void elf::reportDiscarded<ELF64BE>(InputSectionBase<ELF64BE> *);
diff --git a/contrib/llvm/tools/lld/ELF/Writer.h b/contrib/llvm/tools/lld/ELF/Writer.h
index 718e313..7fa56be 100644
--- a/contrib/llvm/tools/lld/ELF/Writer.h
+++ b/contrib/llvm/tools/lld/ELF/Writer.h
@@ -18,49 +18,44 @@
namespace lld {
namespace elf {
class InputFile;
-class OutputSectionBase;
-template <class ELFT> class InputSectionBase;
+class OutputSection;
+class InputSectionBase;
template <class ELFT> class ObjectFile;
template <class ELFT> class SymbolTable;
template <class ELFT> void writeResult();
template <class ELFT> void markLive();
-template <class ELFT> bool isRelroSection(const OutputSectionBase *Sec);
+bool isRelroSection(const OutputSection *Sec);
// This describes a program header entry.
// Each contains type, access flags and range of output sections that will be
// placed in it.
struct PhdrEntry {
- PhdrEntry(unsigned Type, unsigned Flags);
- void add(OutputSectionBase *Sec);
+ PhdrEntry(unsigned Type, unsigned Flags) : p_type(Type), p_flags(Flags) {}
+ void add(OutputSection *Sec);
uint64_t p_paddr = 0;
uint64_t p_vaddr = 0;
- uint64_t p_align = 0;
uint64_t p_memsz = 0;
uint64_t p_filesz = 0;
uint64_t p_offset = 0;
+ uint32_t p_align = 0;
uint32_t p_type = 0;
uint32_t p_flags = 0;
- OutputSectionBase *First = nullptr;
- OutputSectionBase *Last = nullptr;
+ OutputSection *First = nullptr;
+ OutputSection *Last = nullptr;
bool HasLMA = false;
};
llvm::StringRef getOutputSectionName(llvm::StringRef Name);
-template <class ELFT>
-void allocateHeaders(llvm::MutableArrayRef<PhdrEntry>,
- llvm::ArrayRef<OutputSectionBase *>);
-template <class ELFT> void reportDiscarded(InputSectionBase<ELFT> *IS);
-
template <class ELFT> uint32_t getMipsEFlags();
uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
llvm::StringRef FileName);
bool isMipsN32Abi(const InputFile *F);
-}
-}
+} // namespace elf
+} // namespace lld
#endif
diff --git a/contrib/llvm/tools/lld/README.md b/contrib/llvm/tools/lld/README.md
index dc05cde..38a6b48b 100644
--- a/contrib/llvm/tools/lld/README.md
+++ b/contrib/llvm/tools/lld/README.md
@@ -8,3 +8,4 @@ infrastructure project.
lld is open source software. You may freely distribute it under the terms of
the license agreement found in LICENSE.txt.
+
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Parallel.h b/contrib/llvm/tools/lld/include/lld/Core/Parallel.h
deleted file mode 100644
index f241453..0000000
--- a/contrib/llvm/tools/lld/include/lld/Core/Parallel.h
+++ /dev/null
@@ -1,336 +0,0 @@
-//===- lld/Core/Parallel.h - Parallel utilities ---------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_CORE_PARALLEL_H
-#define LLD_CORE_PARALLEL_H
-
-#include "lld/Core/Instrumentation.h"
-#include "lld/Core/LLVM.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/thread.h"
-
-#include <algorithm>
-#include <atomic>
-#include <condition_variable>
-#include <mutex>
-#include <stack>
-
-#if defined(_MSC_VER) && LLVM_ENABLE_THREADS
-#include <concrt.h>
-#include <ppl.h>
-#endif
-
-namespace lld {
-/// \brief Allows one or more threads to wait on a potentially unknown number of
-/// events.
-///
-/// A latch starts at \p count. inc() increments this, and dec() decrements it.
-/// All calls to sync() will block while the count is not 0.
-///
-/// Calling dec() on a Latch with a count of 0 has undefined behaivor.
-class Latch {
- uint32_t _count;
- mutable std::mutex _condMut;
- mutable std::condition_variable _cond;
-
-public:
- explicit Latch(uint32_t count = 0) : _count(count) {}
- ~Latch() { sync(); }
-
- void inc() {
- std::unique_lock<std::mutex> lock(_condMut);
- ++_count;
- }
-
- void dec() {
- std::unique_lock<std::mutex> lock(_condMut);
- if (--_count == 0)
- _cond.notify_all();
- }
-
- void sync() const {
- std::unique_lock<std::mutex> lock(_condMut);
- _cond.wait(lock, [&] {
- return _count == 0;
- });
- }
-};
-
-// Classes in this namespace are implementation details of this header.
-namespace internal {
-
-/// \brief An abstract class that takes closures and runs them asynchronously.
-class Executor {
-public:
- virtual ~Executor() = default;
- virtual void add(std::function<void()> func) = 0;
-};
-
-#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
-class SyncExecutor : public Executor {
-public:
- virtual void add(std::function<void()> func) {
- func();
- }
-};
-
-inline Executor *getDefaultExecutor() {
- static SyncExecutor exec;
- return &exec;
-}
-#elif defined(_MSC_VER)
-/// \brief An Executor that runs tasks via ConcRT.
-class ConcRTExecutor : public Executor {
- struct Taskish {
- Taskish(std::function<void()> task) : _task(task) {}
-
- std::function<void()> _task;
-
- static void run(void *p) {
- Taskish *self = static_cast<Taskish *>(p);
- self->_task();
- concurrency::Free(self);
- }
- };
-
-public:
- virtual void add(std::function<void()> func) {
- Concurrency::CurrentScheduler::ScheduleTask(Taskish::run,
- new (concurrency::Alloc(sizeof(Taskish))) Taskish(func));
- }
-};
-
-inline Executor *getDefaultExecutor() {
- static ConcRTExecutor exec;
- return &exec;
-}
-#else
-/// \brief An implementation of an Executor that runs closures on a thread pool
-/// in filo order.
-class ThreadPoolExecutor : public Executor {
-public:
- explicit ThreadPoolExecutor(unsigned threadCount =
- std::thread::hardware_concurrency())
- : _stop(false), _done(threadCount) {
- // Spawn all but one of the threads in another thread as spawning threads
- // can take a while.
- std::thread([&, threadCount] {
- for (size_t i = 1; i < threadCount; ++i) {
- std::thread([=] {
- work();
- }).detach();
- }
- work();
- }).detach();
- }
-
- ~ThreadPoolExecutor() override {
- std::unique_lock<std::mutex> lock(_mutex);
- _stop = true;
- lock.unlock();
- _cond.notify_all();
- // Wait for ~Latch.
- }
-
- void add(std::function<void()> f) override {
- std::unique_lock<std::mutex> lock(_mutex);
- _workStack.push(f);
- lock.unlock();
- _cond.notify_one();
- }
-
-private:
- void work() {
- while (true) {
- std::unique_lock<std::mutex> lock(_mutex);
- _cond.wait(lock, [&] {
- return _stop || !_workStack.empty();
- });
- if (_stop)
- break;
- auto task = _workStack.top();
- _workStack.pop();
- lock.unlock();
- task();
- }
- _done.dec();
- }
-
- std::atomic<bool> _stop;
- std::stack<std::function<void()>> _workStack;
- std::mutex _mutex;
- std::condition_variable _cond;
- Latch _done;
-};
-
-inline Executor *getDefaultExecutor() {
- static ThreadPoolExecutor exec;
- return &exec;
-}
-#endif
-
-} // namespace internal
-
-/// \brief Allows launching a number of tasks and waiting for them to finish
-/// either explicitly via sync() or implicitly on destruction.
-class TaskGroup {
- Latch _latch;
-
-public:
- void spawn(std::function<void()> f) {
- _latch.inc();
- internal::getDefaultExecutor()->add([&, f] {
- f();
- _latch.dec();
- });
- }
-
- void sync() const { _latch.sync(); }
-};
-
-#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
-template <class RandomAccessIterator, class Comp>
-void parallel_sort(
- RandomAccessIterator start, RandomAccessIterator end,
- const Comp &comp = std::less<
- typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
- std::sort(start, end, comp);
-}
-#elif defined(_MSC_VER)
-// Use ppl parallel_sort on Windows.
-template <class RandomAccessIterator, class Comp>
-void parallel_sort(
- RandomAccessIterator start, RandomAccessIterator end,
- const Comp &comp = std::less<
- typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
- concurrency::parallel_sort(start, end, comp);
-}
-#else
-namespace detail {
-const ptrdiff_t minParallelSize = 1024;
-
-/// \brief Inclusive median.
-template <class RandomAccessIterator, class Comp>
-RandomAccessIterator medianOf3(RandomAccessIterator start,
- RandomAccessIterator end, const Comp &comp) {
- RandomAccessIterator mid = start + (std::distance(start, end) / 2);
- return comp(*start, *(end - 1))
- ? (comp(*mid, *(end - 1)) ? (comp(*start, *mid) ? mid : start)
- : end - 1)
- : (comp(*mid, *start) ? (comp(*(end - 1), *mid) ? mid : end - 1)
- : start);
-}
-
-template <class RandomAccessIterator, class Comp>
-void parallel_quick_sort(RandomAccessIterator start, RandomAccessIterator end,
- const Comp &comp, TaskGroup &tg, size_t depth) {
- // Do a sequential sort for small inputs.
- if (std::distance(start, end) < detail::minParallelSize || depth == 0) {
- std::sort(start, end, comp);
- return;
- }
-
- // Partition.
- auto pivot = medianOf3(start, end, comp);
- // Move pivot to end.
- std::swap(*(end - 1), *pivot);
- pivot = std::partition(start, end - 1, [&comp, end](decltype(*start) v) {
- return comp(v, *(end - 1));
- });
- // Move pivot to middle of partition.
- std::swap(*pivot, *(end - 1));
-
- // Recurse.
- tg.spawn([=, &comp, &tg] {
- parallel_quick_sort(start, pivot, comp, tg, depth - 1);
- });
- parallel_quick_sort(pivot + 1, end, comp, tg, depth - 1);
-}
-}
-
-template <class RandomAccessIterator, class Comp>
-void parallel_sort(
- RandomAccessIterator start, RandomAccessIterator end,
- const Comp &comp = std::less<
- typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
- TaskGroup tg;
- detail::parallel_quick_sort(start, end, comp, tg,
- llvm::Log2_64(std::distance(start, end)) + 1);
-}
-#endif
-
-template <class T> void parallel_sort(T *start, T *end) {
- parallel_sort(start, end, std::less<T>());
-}
-
-#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
-template <class IterTy, class FuncTy>
-void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) {
- std::for_each(Begin, End, Fn);
-}
-
-template <class IndexTy, class FuncTy>
-void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) {
- for (IndexTy I = Begin; I != End; ++I)
- Fn(I);
-}
-#elif defined(_MSC_VER)
-// Use ppl parallel_for_each on Windows.
-template <class IterTy, class FuncTy>
-void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) {
- concurrency::parallel_for_each(Begin, End, Fn);
-}
-
-template <class IndexTy, class FuncTy>
-void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) {
- concurrency::parallel_for(Begin, End, Fn);
-}
-#else
-template <class IterTy, class FuncTy>
-void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) {
- // TaskGroup has a relatively high overhead, so we want to reduce
- // the number of spawn() calls. We'll create up to 1024 tasks here.
- // (Note that 1024 is an arbitrary number. This code probably needs
- // improving to take the number of available cores into account.)
- ptrdiff_t TaskSize = std::distance(Begin, End) / 1024;
- if (TaskSize == 0)
- TaskSize = 1;
-
- TaskGroup Tg;
- while (TaskSize <= std::distance(Begin, End)) {
- Tg.spawn([=, &Fn] { std::for_each(Begin, Begin + TaskSize, Fn); });
- Begin += TaskSize;
- }
- Tg.spawn([=, &Fn] { std::for_each(Begin, End, Fn); });
-}
-
-template <class IndexTy, class FuncTy>
-void parallel_for(IndexTy Begin, IndexTy End, FuncTy Fn) {
- ptrdiff_t TaskSize = (End - Begin) / 1024;
- if (TaskSize == 0)
- TaskSize = 1;
-
- TaskGroup Tg;
- IndexTy I = Begin;
- for (; I < End; I += TaskSize) {
- Tg.spawn([=, &Fn] {
- for (IndexTy J = I, E = I + TaskSize; J != E; ++J)
- Fn(J);
- });
- Begin += TaskSize;
- }
- Tg.spawn([=, &Fn] {
- for (IndexTy J = I; J < End; ++J)
- Fn(J);
- });
-}
-#endif
-} // end namespace lld
-
-#endif // LLD_CORE_PARALLEL_H
diff --git a/contrib/llvm/tools/lld/include/lld/Core/Reader.h b/contrib/llvm/tools/lld/include/lld/Core/Reader.h
index 5105eb1..32d0424 100644
--- a/contrib/llvm/tools/lld/include/lld/Core/Reader.h
+++ b/contrib/llvm/tools/lld/include/lld/Core/Reader.h
@@ -13,14 +13,13 @@
#include "lld/Core/LLVM.h"
#include "lld/Core/Reference.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>
#include <vector>
-using llvm::sys::fs::file_magic;
-
namespace llvm {
namespace yaml {
class IO;
@@ -45,7 +44,7 @@ public:
/// The method is called with:
/// 1) the file_magic enumeration returned by identify_magic()
/// 2) the whole file content buffer if the above is not enough.
- virtual bool canParse(file_magic magic, MemoryBufferRef mb) const = 0;
+ virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0;
/// \brief Parse a supplied buffer (already filled with the contents of a
/// file) and create a File object.
diff --git a/contrib/llvm/tools/lld/include/lld/Core/TargetOptionsCommandFlags.h b/contrib/llvm/tools/lld/include/lld/Core/TargetOptionsCommandFlags.h
new file mode 100644
index 0000000..9ba99d9
--- /dev/null
+++ b/contrib/llvm/tools/lld/include/lld/Core/TargetOptionsCommandFlags.h
@@ -0,0 +1,20 @@
+//===-- TargetOptionsCommandFlags.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper to create TargetOptions from command line flags.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Target/TargetOptions.h"
+
+namespace lld {
+llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
+llvm::CodeModel::Model GetCodeModelFromCMModel();
+}
diff --git a/contrib/llvm/tools/lld/include/lld/Driver/Driver.h b/contrib/llvm/tools/lld/include/lld/Driver/Driver.h
index a3265c8..4ba0994 100644
--- a/contrib/llvm/tools/lld/include/lld/Driver/Driver.h
+++ b/contrib/llvm/tools/lld/include/lld/Driver/Driver.h
@@ -15,7 +15,8 @@
namespace lld {
namespace coff {
-bool link(llvm::ArrayRef<const char *> Args);
+bool link(llvm::ArrayRef<const char *> Args,
+ llvm::raw_ostream &Diag = llvm::errs());
}
namespace elf {
diff --git a/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h
index a9e80f5..9eefa8c 100644
--- a/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h
+++ b/contrib/llvm/tools/lld/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -16,8 +16,8 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MachO.h"
#include <set>
using llvm::MachO::HeaderFileType;
diff --git a/contrib/llvm/tools/lld/include/lld/Support/Memory.h b/contrib/llvm/tools/lld/include/lld/Support/Memory.h
deleted file mode 100644
index 46db4a3..0000000
--- a/contrib/llvm/tools/lld/include/lld/Support/Memory.h
+++ /dev/null
@@ -1,63 +0,0 @@
-//===- Memory.h -------------------------------------------------*- C++ -*-===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines arena allocators.
-//
-// Almost all large objects, such as files, sections or symbols, are
-// used for the entire lifetime of the linker once they are created.
-// This usage characteristic makes arena allocator an attractive choice
-// where the entire linker is one arena. With an arena, newly created
-// objects belong to the arena and freed all at once when everything is done.
-// Arena allocators are efficient and easy to understand.
-// Most objects are allocated using the arena allocators defined by this file.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_MEMORY_H
-#define LLD_MEMORY_H
-
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/StringSaver.h"
-#include <vector>
-
-namespace lld {
-
-// Use this arena if your object doesn't have a destructor.
-extern llvm::BumpPtrAllocator BAlloc;
-extern llvm::StringSaver Saver;
-
-// These two classes are hack to keep track of all
-// SpecificBumpPtrAllocator instances.
-struct SpecificAllocBase {
- SpecificAllocBase() { Instances.push_back(this); }
- virtual ~SpecificAllocBase() = default;
- virtual void reset() = 0;
- static std::vector<SpecificAllocBase *> Instances;
-};
-
-template <class T> struct SpecificAlloc : public SpecificAllocBase {
- void reset() override { Alloc.DestroyAll(); }
- llvm::SpecificBumpPtrAllocator<T> Alloc;
-};
-
-// Use this arena if your object has a destructor.
-// Your destructor will be invoked from freeArena().
-template <typename T, typename... U> inline T *make(U &&... Args) {
- static SpecificAlloc<T> Alloc;
- return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...);
-}
-
-inline void freeArena() {
- for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances)
- Alloc->reset();
- BAlloc.Reset();
-}
-}
-
-#endif
diff --git a/contrib/llvm/tools/lld/lib/Core/CMakeLists.txt b/contrib/llvm/tools/lld/lib/Core/CMakeLists.txt
index 7f4c47f..85046b9 100644
--- a/contrib/llvm/tools/lld/lib/Core/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/lib/Core/CMakeLists.txt
@@ -1,3 +1,7 @@
+if(NOT LLD_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
add_lld_library(lldCore
DefinedAtom.cpp
Error.cpp
@@ -7,11 +11,20 @@ add_lld_library(lldCore
Reproduce.cpp
Resolver.cpp
SymbolTable.cpp
+ TargetOptionsCommandFlags.cpp
Writer.cpp
ADDITIONAL_HEADER_DIRS
${LLD_INCLUDE_DIR}/lld/Core
LINK_COMPONENTS
+ BinaryFormat
+ MC
Support
+
+ LINK_LIBS
+ ${LLVM_PTHREAD_LIB}
+
+ DEPENDS
+ ${tablegen_deps}
)
diff --git a/contrib/llvm/tools/lld/lib/Core/Reader.cpp b/contrib/llvm/tools/lld/lib/Core/Reader.cpp
index 24652ab..5d8bbbb 100644
--- a/contrib/llvm/tools/lld/lib/Core/Reader.cpp
+++ b/contrib/llvm/tools/lld/lib/Core/Reader.cpp
@@ -11,12 +11,16 @@
#include "lld/Core/File.h"
#include "lld/Core/Reference.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include <algorithm>
#include <memory>
+using llvm::file_magic;
+using llvm::identify_magic;
+
namespace lld {
YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() = default;
@@ -33,7 +37,7 @@ ErrorOr<std::unique_ptr<File>>
Registry::loadFile(std::unique_ptr<MemoryBuffer> mb) const {
// Get file magic.
StringRef content(mb->getBufferStart(), mb->getBufferSize());
- llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content);
+ file_magic fileType = identify_magic(content);
// Ask each registered reader if it can handle this file type or extension.
for (const std::unique_ptr<Reader> &reader : _readers) {
diff --git a/contrib/llvm/tools/lld/lib/Core/SymbolTable.cpp b/contrib/llvm/tools/lld/lib/Core/SymbolTable.cpp
index cacea5f..583c65a 100644
--- a/contrib/llvm/tools/lld/lib/Core/SymbolTable.cpp
+++ b/contrib/llvm/tools/lld/lib/Core/SymbolTable.cpp
@@ -161,7 +161,7 @@ bool SymbolTable::addByName(const Atom &newAtom) {
llvm::errs() << "Size mismatch: "
<< existing->name() << " (" << existingSize << ") "
<< newAtom.name() << " (" << newSize << ")\n";
- // fallthrough
+ LLVM_FALLTHROUGH;
}
case MCR_Error:
llvm::errs() << "Duplicate symbols: "
diff --git a/contrib/llvm/tools/lld/lib/Core/TargetOptionsCommandFlags.cpp b/contrib/llvm/tools/lld/lib/Core/TargetOptionsCommandFlags.cpp
new file mode 100644
index 0000000..e0f2676
--- /dev/null
+++ b/contrib/llvm/tools/lld/lib/Core/TargetOptionsCommandFlags.cpp
@@ -0,0 +1,32 @@
+//===-- TargetOptionsCommandFlags.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file exists as a place for global variables defined in LLVM's
+// CodeGen/CommandFlags.h. By putting the resulting object file in
+// an archive and linking with it, the definitions will automatically be
+// included when needed and skipped when already present.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/TargetOptionsCommandFlags.h"
+
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/Target/TargetOptions.h"
+
+// Define an externally visible version of
+// InitTargetOptionsFromCodeGenFlags, so that its functionality can be
+// used without having to include llvm/CodeGen/CommandFlags.h, which
+// would lead to multiple definitions of the command line flags.
+llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() {
+ return ::InitTargetOptionsFromCodeGenFlags();
+}
+
+llvm::CodeModel::Model lld::GetCodeModelFromCMModel() {
+ return CMModel;
+}
diff --git a/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp b/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
index 9b4aede..f564d8c 100644
--- a/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
+++ b/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp
@@ -18,30 +18,30 @@
#include "lld/Core/File.h"
#include "lld/Core/Instrumentation.h"
#include "lld/Core/LLVM.h"
+#include "lld/Core/LinkingContext.h"
#include "lld/Core/Node.h"
#include "lld/Core/PassManager.h"
#include "lld/Core/Resolver.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/Core/Simple.h"
-#include "lld/Core/LinkingContext.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
-#include "llvm/Option/Option.h"
#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -61,9 +61,9 @@ namespace {
// Create enum with OPT_xxx values for each option in DarwinLdOptions.td
enum {
OPT_INVALID = 0,
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELP, META) \
- OPT_##ID,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELP, META, VALUES) \
+ OPT_##ID,
#include "DarwinLdOptions.inc"
#undef OPTION
};
@@ -75,10 +75,12 @@ enum {
// Create table mapping all options defined in DarwinLdOptions.td
static const llvm::opt::OptTable::Info infoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) \
- { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, \
+ OPT_##ALIAS, ALIASARGS, VALUES},
#include "DarwinLdOptions.inc"
#undef OPTION
};
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
index 799f947..762d087 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
@@ -11,15 +11,16 @@
#include "lld/Core/File.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Reader.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Object/Archive.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/Error.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <set>
@@ -30,6 +31,8 @@
#include <vector>
using llvm::object::Archive;
+using llvm::file_magic;
+using llvm::identify_magic;
namespace lld {
@@ -201,7 +204,7 @@ public:
ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
bool canParse(file_magic magic, MemoryBufferRef) const override {
- return magic == llvm::sys::fs::file_magic::archive;
+ return magic == file_magic::archive;
}
ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb,
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
index 392a1be..10360b5 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
@@ -51,11 +51,7 @@ public:
canBypassGOT = true;
return true;
case delta32ToGOT:
- canBypassGOT = false;
- return true;
case unwindCIEToPersonalityFunction:
- canBypassGOT = false;
- return true;
case imageOffsetGot:
canBypassGOT = false;
return true;
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
index c940ea5..2272bff 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -118,14 +118,7 @@ public:
normalized::Relocations &relocs) override;
bool isDataInCodeTransition(Reference::KindValue refKind) override {
- switch (refKind) {
- case modeCode:
- case modeData:
- return true;
- default:
- return false;
- break;
- }
+ return refKind == modeCode || refKind == modeData;
}
Reference::KindValue dataInCodeTransitionStart(
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt
index 3b06985..5a96d87 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/CMakeLists.txt
@@ -28,7 +28,7 @@ add_lld_library(lldMachO
LINK_LIBS
lldCore
lldYAML
- ${PTHREAD_LIB}
+ ${LLVM_PTHREAD_LIB}
)
include_directories(.)
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h
index acced33..ab14e6d 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ExecutableAtoms.h
@@ -13,7 +13,7 @@
#include "Atoms.h"
#include "File.h"
-#include "llvm/Support/MachO.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
index 24dbf79..7bca07e 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -9,12 +9,12 @@
#include "LayoutPass.h"
#include "lld/Core/Instrumentation.h"
-#include "lld/Core/Parallel.h"
#include "lld/Core/PassManager.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Parallel.h"
#include <algorithm>
#include <set>
#include <utility>
@@ -461,10 +461,10 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
});
std::vector<LayoutPass::SortKey> vec = decorate(atomRange);
- parallel_sort(vec.begin(), vec.end(),
- [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
- return compareAtoms(l, r, _customSorter);
- });
+ sort(llvm::parallel::par, vec.begin(), vec.end(),
+ [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool {
+ return compareAtoms(l, r, _customSorter);
+ });
DEBUG(checkTransitivity(vec, _customSorter));
undecorate(atomRange, vec);
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index db4a968..7e7b559 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -22,11 +22,11 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/Path.h"
#include <algorithm>
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
index 60d76d4..31b24df 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
@@ -48,10 +48,10 @@
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/YAMLTraits.h"
using llvm::BumpPtrAllocator;
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
index 23c7ea1..b540547 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -21,24 +21,25 @@
/// | normalized |
/// +------------+
-#include "MachONormalizedFile.h"
#include "ArchHandler.h"
+#include "MachONormalizedFile.h"
#include "MachONormalizedFileBinaryUtils.h"
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
@@ -46,6 +47,7 @@
using namespace llvm::MachO;
using llvm::object::ExportEntry;
+using llvm::file_magic;
using llvm::object::MachOObjectFile;
namespace lld {
@@ -506,9 +508,9 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
if (dyldInfo) {
// If any exports, extract and add to normalized exportInfo vector.
if (dyldInfo->export_size) {
- const uint8_t *trieStart = reinterpret_cast<const uint8_t*>(start +
- dyldInfo->export_off);
- ArrayRef<uint8_t> trie(trieStart, dyldInfo->export_size);
+ const uint8_t *trieStart = reinterpret_cast<const uint8_t *>(
+ start + read32(&dyldInfo->export_off, isBig));
+ ArrayRef<uint8_t> trie(trieStart, read32(&dyldInfo->export_size, isBig));
for (const ExportEntry &trieExport : MachOObjectFile::exports(trie)) {
Export normExport;
normExport.name = trieExport.name().copy(f->ownedAllocations);
@@ -531,8 +533,7 @@ public:
MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
bool canParse(file_magic magic, MemoryBufferRef mb) const override {
- return (magic == llvm::sys::fs::file_magic::macho_object &&
- mb.getBufferSize() > 32);
+ return (magic == file_magic::macho_object && mb.getBufferSize() > 32);
}
ErrorOr<std::unique_ptr<File>>
@@ -553,8 +554,8 @@ public:
bool canParse(file_magic magic, MemoryBufferRef mb) const override {
switch (magic) {
- case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib:
- case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub:
+ case file_magic::macho_dynamically_linked_shared_lib:
+ case file_magic::macho_dynamically_linked_shared_lib_stub:
return mb.getBufferSize() > 32;
default:
return false;
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
index d69c538..b38f705 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
@@ -14,12 +14,12 @@
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/LEB128.h"
-#include "llvm/Support/MachO.h"
#include <system_error>
namespace lld {
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
index e853faf..bac41d2 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -25,11 +25,12 @@
#include "MachONormalizedFileBinaryUtils.h"
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
-#include "llvm/ADT/ilist.h"
-#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
@@ -37,7 +38,6 @@
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index ddd3259..e58e3d2 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -20,19 +20,19 @@
/// | Atoms |
/// +-------+
-#include "MachONormalizedFile.h"
#include "ArchHandler.h"
#include "DebugInfo.h"
+#include "MachONormalizedFile.h"
#include "MachONormalizedFileBinaryUtils.h"
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/MachO.h"
#include <map>
#include <system_error>
#include <unordered_set>
@@ -515,6 +515,7 @@ void Util::organizeSections() {
// Main executables, need a zero-page segment
segmentForName("__PAGEZERO");
// Fall into next case.
+ LLVM_FALLTHROUGH;
case llvm::MachO::MH_DYLIB:
case llvm::MachO::MH_BUNDLE:
// All dynamic code needs TEXT segment to hold the load commands.
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index 4b17f7b..226a25d 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -20,20 +20,20 @@
/// | Atoms |
/// +-------+
-#include "MachONormalizedFile.h"
#include "ArchHandler.h"
#include "Atoms.h"
#include "File.h"
+#include "MachONormalizedFile.h"
#include "MachONormalizedFileBinaryUtils.h"
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/Dwarf.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/raw_ostream.h"
@@ -906,6 +906,7 @@ readCompUnit(const NormalizedFile &normalizedFile,
abbrevData.getU8(&abbrevOffset);
uint32_t name;
llvm::dwarf::Form form;
+ llvm::DWARFFormParams formParams = {version, addrSize, Format};
TranslationUnitSource tu;
while ((name = abbrevData.getULEB128(&abbrevOffset)) |
(form = static_cast<llvm::dwarf::Form>(
@@ -929,8 +930,7 @@ readCompUnit(const NormalizedFile &normalizedFile,
break;
}
default:
- llvm::DWARFFormValue::skipValue(form, infoData, &offset, version,
- addrSize, Format);
+ llvm::DWARFFormValue::skipValue(form, infoData, &offset, formParams);
}
}
return tu;
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
index 2181709..5233e42 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
@@ -23,17 +23,16 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
-
using llvm::StringRef;
using namespace llvm::yaml;
using namespace llvm::MachO;
@@ -45,7 +44,6 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib)
LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation)
LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation)
LLVM_YAML_IS_SEQUENCE_VECTOR(Export)
-LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef)
LLVM_YAML_IS_SEQUENCE_VECTOR(DataInCode)
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ObjCPass.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ObjCPass.cpp
index 4712d8c..ccea081 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ObjCPass.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ObjCPass.cpp
@@ -11,6 +11,7 @@
#include "ArchHandler.h"
#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
#include "MachOPasses.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
@@ -29,7 +30,7 @@ namespace mach_o {
///
class ObjCImageInfoAtom : public SimpleDefinedAtom {
public:
- ObjCImageInfoAtom(const File &file,
+ ObjCImageInfoAtom(const File &file, bool isBig,
MachOLinkingContext::ObjCConstraint objCConstraint,
uint32_t swiftVersion)
: SimpleDefinedAtom(file) {
@@ -54,6 +55,8 @@ public:
}
Data.info.flags |= (swiftVersion << 8);
+
+ normalized::write32(Data.bytes + 4, Data.info.flags, isBig);
}
~ObjCImageInfoAtom() override = default;
@@ -109,7 +112,8 @@ public:
private:
const DefinedAtom* getImageInfo() {
- return new (_file.allocator()) ObjCImageInfoAtom(_file,
+ bool IsBig = MachOLinkingContext::isBigEndian(_ctx.arch());
+ return new (_file.allocator()) ObjCImageInfoAtom(_file, IsBig,
_ctx.objcConstraint(),
_ctx.swiftVersion());
}
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/WriterMachO.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/WriterMachO.cpp
index f08487f..c457e7b 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/WriterMachO.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/WriterMachO.cpp
@@ -12,10 +12,10 @@
#include "lld/Core/File.h"
#include "lld/Core/Writer.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
index 59ca430..4c88eb1 100644
--- a/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
+++ b/contrib/llvm/tools/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
@@ -43,6 +44,7 @@
#include <system_error>
#include <vector>
+using llvm::file_magic;
using llvm::yaml::MappingTraits;
using llvm::yaml::ScalarEnumerationTraits;
using llvm::yaml::ScalarTraits;
diff --git a/contrib/llvm/tools/lld/tools/lld/lld.cpp b/contrib/llvm/tools/lld/tools/lld/lld.cpp
index f42ccfe..b2e6b8a 100644
--- a/contrib/llvm/tools/lld/tools/lld/lld.cpp
+++ b/contrib/llvm/tools/lld/tools/lld/lld.cpp
@@ -43,9 +43,9 @@ LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
static Flavor getFlavor(StringRef S) {
return StringSwitch<Flavor>(S)
- .Cases("ld", "ld.lld", "gnu", Gnu)
- .Case("link", WinLink)
- .Case("darwin", Darwin)
+ .CasesLower("ld", "ld.lld", "gnu", Gnu)
+ .CaseLower("link", WinLink)
+ .CaseLower("darwin", Darwin)
.Default(Invalid);
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/LLDB.h b/contrib/llvm/tools/lldb/include/lldb/API/LLDB.h
index d8604cd..cf61b10 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/LLDB.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/LLDB.h
@@ -63,6 +63,8 @@
#include "lldb/API/SBThread.h"
#include "lldb/API/SBThreadCollection.h"
#include "lldb/API/SBThreadPlan.h"
+#include "lldb/API/SBTrace.h"
+#include "lldb/API/SBTraceOptions.h"
#include "lldb/API/SBType.h"
#include "lldb/API/SBTypeCategory.h"
#include "lldb/API/SBTypeEnumMember.h"
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBAddress.h b/contrib/llvm/tools/lldb/include/lldb/API/SBAddress.h
index ddbe5a7..9e697be 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBAddress.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBAddress.h
@@ -103,6 +103,8 @@ protected:
const lldb_private::Address *operator->() const;
+ friend bool operator==(const SBAddress &lhs, const SBAddress &rhs);
+
lldb_private::Address *get();
lldb_private::Address &ref();
@@ -117,6 +119,8 @@ private:
std::unique_ptr<lldb_private::Address> m_opaque_ap;
};
+bool operator==(const SBAddress &lhs, const SBAddress &rhs);
+
} // namespace lldb
#endif // LLDB_SBAddress_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBAttachInfo.h b/contrib/llvm/tools/lldb/include/lldb/API/SBAttachInfo.h
index 6c35616..7ae0069 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBAttachInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBAttachInfo.h
@@ -86,7 +86,7 @@ public:
/// This function implies that a call to SBTarget::Attach(...) will
/// be synchronous.
///
- /// @param[in] wait_for
+ /// @param[in] b
/// If \b false, attach to an existing process whose name matches.
/// If \b true, then wait for the next process whose name matches.
//------------------------------------------------------------------
@@ -99,7 +99,7 @@ public:
/// Future calls to SBTarget::Attach(...) will be synchronous or
/// asynchronous depending on the \a async argument.
///
- /// @param[in] wait_for
+ /// @param[in] b
/// If \b false, attach to an existing process whose name matches.
/// If \b true, then wait for the next process whose name matches.
///
@@ -162,7 +162,7 @@ public:
/// Get the listener that will be used to receive process events.
///
/// If no listener has been set via a call to
- /// SBLaunchInfo::SetListener(), then an invalid SBListener will be
+ /// SBAttachInfo::SetListener(), then an invalid SBListener will be
/// returned (SBListener::IsValid() will return false). If a listener
/// has been set, then the valid listener object will be returned.
//----------------------------------------------------------------------
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBBreakpoint.h b/contrib/llvm/tools/lldb/include/lldb/API/SBBreakpoint.h
index 56509c9..9abc9cd 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBBreakpoint.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBBreakpoint.h
@@ -133,19 +133,13 @@ private:
SBBreakpoint(const lldb::BreakpointSP &bp_sp);
- lldb_private::Breakpoint *operator->() const;
-
- lldb_private::Breakpoint *get() const;
-
- lldb::BreakpointSP &operator*();
-
- const lldb::BreakpointSP &operator*() const;
-
static bool PrivateBreakpointHitCallback(
void *baton, lldb_private::StoppointCallbackContext *context,
lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
- lldb::BreakpointSP m_opaque_sp;
+ lldb::BreakpointSP GetSP() const;
+
+ lldb::BreakpointWP m_opaque_wp;
};
class LLDB_API SBBreakpointList {
@@ -160,9 +154,9 @@ public:
SBBreakpoint FindBreakpointByID(lldb::break_id_t);
- void Append(const SBBreakpoint &sb_file);
+ void Append(const SBBreakpoint &sb_bkpt);
- bool AppendIfUnique(const SBBreakpoint &sb_file);
+ bool AppendIfUnique(const SBBreakpoint &sb_bkpt);
void AppendByID(lldb::break_id_t id);
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBBreakpointLocation.h b/contrib/llvm/tools/lldb/include/lldb/API/SBBreakpointLocation.h
index 344c39c..0b5ba79 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBBreakpointLocation.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBBreakpointLocation.h
@@ -78,8 +78,9 @@ private:
friend class SBBreakpoint;
void SetLocation(const lldb::BreakpointLocationSP &break_loc_sp);
+ BreakpointLocationSP GetSP() const;
- lldb::BreakpointLocationSP m_opaque_sp;
+ lldb::BreakpointLocationWP m_opaque_wp;
};
} // namespace lldb
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBDefines.h b/contrib/llvm/tools/lldb/include/lldb/API/SBDefines.h
index 25443c4..d70e912 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBDefines.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBDefines.h
@@ -79,6 +79,8 @@ class LLDB_API SBTarget;
class LLDB_API SBThread;
class LLDB_API SBThreadCollection;
class LLDB_API SBThreadPlan;
+class LLDB_API SBTrace;
+class LLDB_API SBTraceOptions;
class LLDB_API SBType;
class LLDB_API SBTypeCategory;
class LLDB_API SBTypeEnumMember;
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBError.h b/contrib/llvm/tools/lldb/include/lldb/API/SBError.h
index 7f2f3a6..a099a9b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBError.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBError.h
@@ -61,24 +61,25 @@ protected:
friend class SBProcess;
friend class SBStructuredData;
friend class SBThread;
+ friend class SBTrace;
friend class SBTarget;
friend class SBValue;
friend class SBWatchpoint;
friend class SBBreakpoint;
friend class SBBreakpointLocation;
- lldb_private::Error *get();
+ lldb_private::Status *get();
- lldb_private::Error *operator->();
+ lldb_private::Status *operator->();
- const lldb_private::Error &operator*() const;
+ const lldb_private::Status &operator*() const;
- lldb_private::Error &ref();
+ lldb_private::Status &ref();
- void SetError(const lldb_private::Error &lldb_error);
+ void SetError(const lldb_private::Status &lldb_error);
private:
- std::unique_ptr<lldb_private::Error> m_opaque_ap;
+ std::unique_ptr<lldb_private::Status> m_opaque_ap;
void CreateIfNeeded();
};
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBFrame.h b/contrib/llvm/tools/lldb/include/lldb/API/SBFrame.h
index be5c092..5833975 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBFrame.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBFrame.h
@@ -78,6 +78,10 @@ public:
const char *GetDisplayFunctionName();
const char *GetFunctionName() const;
+
+ // Return the frame function's language. If there isn't a function, then
+ // guess the language type from the mangled name.
+ lldb::LanguageType GuessLanguage() const;
/// Return true if this frame represents an inlined function.
///
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBInstruction.h b/contrib/llvm/tools/lldb/include/lldb/API/SBInstruction.h
index 0fc12eb..23daf1c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBInstruction.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBInstruction.h
@@ -53,6 +53,8 @@ public:
bool HasDelaySlot();
+ bool CanSetBreakpoint();
+
void Print(FILE *out);
bool GetDescription(lldb::SBStream &description);
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBInstructionList.h b/contrib/llvm/tools/lldb/include/lldb/API/SBInstructionList.h
index 29baef57..0323a3c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBInstructionList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBInstructionList.h
@@ -32,6 +32,15 @@ public:
lldb::SBInstruction GetInstructionAtIndex(uint32_t idx);
+ // ----------------------------------------------------------------------
+ // Returns the number of instructions between the start and end address.
+ // If canSetBreakpoint is true then the count will be the number of
+ // instructions on which a breakpoint can be set.
+ // ----------------------------------------------------------------------
+ size_t GetInstructionsCount(const SBAddress &start,
+ const SBAddress &end,
+ bool canSetBreakpoint = false);
+
void Clear();
void AppendInstruction(lldb::SBInstruction inst);
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBListener.h b/contrib/llvm/tools/lldb/include/lldb/API/SBListener.h
index 05282c2..a2f82a8 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBListener.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBListener.h
@@ -89,7 +89,7 @@ protected:
SBListener(const lldb::ListenerSP &listener_sp);
- lldb::ListenerSP GetSP() { return m_opaque_sp; }
+ lldb::ListenerSP GetSP();
private:
lldb_private::Listener *operator->() const;
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBPlatform.h b/contrib/llvm/tools/lldb/include/lldb/API/SBPlatform.h
index 3f7e1ac..952e310 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBPlatform.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBPlatform.h
@@ -156,7 +156,8 @@ protected:
void SetSP(const lldb::PlatformSP &platform_sp);
SBError ExecuteConnected(
- const std::function<lldb_private::Error(const lldb::PlatformSP &)> &func);
+ const std::function<lldb_private::Status(const lldb::PlatformSP &)>
+ &func);
lldb::PlatformSP m_opaque_sp;
};
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBProcess.h b/contrib/llvm/tools/lldb/include/lldb/API/SBProcess.h
index fd95790..d57d5ce 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBProcess.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBProcess.h
@@ -234,6 +234,33 @@ public:
bool GetDescription(lldb::SBStream &description);
+ //------------------------------------------------------------------
+ /// Start Tracing with the given SBTraceOptions.
+ ///
+ /// @param[in] options
+ /// Class containing trace options like trace buffer size, meta
+ /// data buffer size, TraceType and any custom parameters
+ /// {formatted as a JSON Dictionary}. In case of errors in
+ /// formatting, an error would be reported.
+ /// It must be noted that tracing options such as buffer sizes
+ /// or other custom parameters passed maybe invalid for some
+ /// trace technologies. In such cases the trace implementations
+ /// could choose to either throw an error or could round off to
+ /// the nearest valid options to start tracing if the passed
+ /// value is not supported. To obtain the actual used trace
+ /// options please use the GetTraceConfig API. For the custom
+ /// parameters, only the parameters recognized by the target
+ /// would be used and others would be ignored.
+ ///
+ /// @param[out] error
+ /// An error explaining what went wrong.
+ ///
+ /// @return
+ /// A SBTrace instance, which should be used
+ /// to get the trace data or other trace related operations.
+ //------------------------------------------------------------------
+ lldb::SBTrace StartTrace(SBTraceOptions &options, lldb::SBError &error);
+
uint32_t GetNumSupportedHardwareWatchpoints(lldb::SBError &error) const;
//------------------------------------------------------------------
@@ -323,7 +350,7 @@ public:
bool IsInstrumentationRuntimePresent(InstrumentationRuntimeType type);
- // Save the state of the process in a core file (or mini dump on Windows).
+ /// Save the state of the process in a core file (or mini dump on Windows).
lldb::SBError SaveCore(const char *file_name);
//------------------------------------------------------------------
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBStructuredData.h b/contrib/llvm/tools/lldb/include/lldb/API/SBStructuredData.h
index 9f0203b..f7a6469 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBStructuredData.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBStructuredData.h
@@ -13,8 +13,6 @@
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBModule.h"
-class StructuredDataImpl;
-
namespace lldb {
class SBStructuredData {
@@ -31,15 +29,78 @@ public:
bool IsValid() const;
+ lldb::SBError SetFromJSON(lldb::SBStream &stream);
+
void Clear();
lldb::SBError GetAsJSON(lldb::SBStream &stream) const;
lldb::SBError GetDescription(lldb::SBStream &stream) const;
-private:
- std::unique_ptr<StructuredDataImpl> m_impl_up;
+ //------------------------------------------------------------------
+ /// Return the type of data in this data structure
+ //------------------------------------------------------------------
+ lldb::StructuredDataType GetType() const;
+
+ //------------------------------------------------------------------
+ /// Return the size (i.e. number of elements) in this data structure
+ /// if it is an array or dictionary type. For other types, 0 will be
+ // returned.
+ //------------------------------------------------------------------
+ size_t GetSize() const;
+
+ //------------------------------------------------------------------
+ /// Return the value corresponding to a key if this data structure
+ /// is a dictionary type.
+ //------------------------------------------------------------------
+ lldb::SBStructuredData GetValueForKey(const char *key) const;
+
+ //------------------------------------------------------------------
+ /// Return the value corresponding to an index if this data structure
+ /// is array.
+ //------------------------------------------------------------------
+ lldb::SBStructuredData GetItemAtIndex(size_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Return the integer value if this data structure is an integer type.
+ //------------------------------------------------------------------
+ uint64_t GetIntegerValue(uint64_t fail_value = 0) const;
+
+ //------------------------------------------------------------------
+ /// Return the floating point value if this data structure is a floating
+ /// type.
+ //------------------------------------------------------------------
+ double GetFloatValue(double fail_value = 0.0) const;
+
+ //------------------------------------------------------------------
+ /// Return the boolean value if this data structure is a boolean type.
+ //------------------------------------------------------------------
+ bool GetBooleanValue(bool fail_value = false) const;
+
+ //------------------------------------------------------------------
+ /// Provides the string value if this data structure is a string type.
+ ///
+ /// @param[out] dst
+ /// pointer where the string value will be written. In case it is null,
+ /// nothing will be written at @dst.
+ ///
+ /// @param[in] dst_len
+ /// max number of characters that can be written at @dst. In case it is
+ /// zero, nothing will be written at @dst. If this length is not enough
+ /// to write the complete string value, (dst_len-1) bytes of the string
+ /// value will be written at @dst followed by a null character.
+ ///
+ /// @return
+ /// Returns the byte size needed to completely write the string value at
+ /// @dst in all cases.
+ //------------------------------------------------------------------
+ size_t GetStringValue(char *dst, size_t dst_len) const;
+
+protected:
+ friend class SBTraceOptions;
+
+ StructuredDataImplUP m_impl_up;
};
-}
+} // namespace lldb
#endif /* SBStructuredData_h */
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBTarget.h b/contrib/llvm/tools/lldb/include/lldb/API/SBTarget.h
index 4e8db83..62398fc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBTarget.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBTarget.h
@@ -124,9 +124,6 @@ public:
/// @param[in] envp
/// The environment array.
///
- /// @param[in] launch_flags
- /// Flags to modify the launch (@see lldb::LaunchFlags)
- ///
/// @param[in] stdin_path
/// The path to use when re-directing the STDIN of the new
/// process. If all stdXX_path arguments are nullptr, a pseudo
@@ -480,6 +477,7 @@ public:
/// Resolve a current file address into a section offset address.
///
/// @param[in] file_addr
+ /// The file address to resolve.
///
/// @return
/// An SBAddress which will be valid if...
@@ -546,7 +544,7 @@ public:
/// into this call
///
/// @param[out] error
- /// Error information is written here if the memory read fails.
+ /// Status information is written here if the memory read fails.
///
/// @return
/// The amount of data read in host bytes.
@@ -653,7 +651,7 @@ public:
/// @param[in] source_file
/// The file from which to read the breakpoints.
///
- /// @param[out] bkpt_list
+ /// @param[out] new_bps
/// A list of the newly created breakpoints.
///
/// @return
@@ -673,7 +671,7 @@ public:
/// Only read in breakpoints whose names match one of the names in this
/// list.
///
- /// @param[out] bkpt_list
+ /// @param[out] new_bps
/// A list of the newly created breakpoints.
///
/// @return
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBTrace.h b/contrib/llvm/tools/lldb/include/lldb/API/SBTrace.h
new file mode 100644
index 0000000..244a01e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBTrace.h
@@ -0,0 +1,123 @@
+//===-- SBTrace.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBTrace_h_
+#define LLDB_SBTrace_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBError.h"
+
+class TraceImpl;
+
+namespace lldb {
+
+class LLDB_API SBTrace {
+public:
+ SBTrace();
+ //------------------------------------------------------------------
+ /// Obtain the trace data as raw bytes.
+ ///
+ /// @param[out] error
+ /// An error explaining what went wrong.
+ ///
+ /// @param[in] buf
+ /// Buffer to write the trace data to.
+ ///
+ /// @param[in] size
+ /// The size of the buffer used to read the data. This is
+ /// also the size of the data intended to read. It is also
+ /// possible to partially read the trace data for some trace
+ /// technologies by specifying a smaller buffer.
+ ///
+ /// @param[in] offset
+ /// The start offset to begin reading the trace data.
+ ///
+ /// @param[in] thread_id
+ /// Tracing could be started for the complete process or a
+ /// single thread, in the first case the traceid obtained would
+ /// map to all the threads existing within the process and the
+ /// ones spawning later. The thread_id parameter can be used in
+ /// such a scenario to select the trace data for a specific
+ /// thread.
+ ///
+ /// @return
+ /// The size of the trace data effectively read by the API call.
+ //------------------------------------------------------------------
+ size_t GetTraceData(SBError &error, void *buf, size_t size, size_t offset = 0,
+ lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
+
+ //------------------------------------------------------------------
+ /// Obtain any meta data as raw bytes for the tracing instance.
+ /// The input parameter definition is similar to the previous
+ /// function.
+ //------------------------------------------------------------------
+ size_t GetMetaData(SBError &error, void *buf, size_t size, size_t offset = 0,
+ lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
+
+ //------------------------------------------------------------------
+ /// Stop the tracing instance. Stopping the trace will also
+ /// lead to deletion of any gathered trace data.
+ ///
+ /// @param[out] error
+ /// An error explaining what went wrong.
+ ///
+ /// @param[in] thread_id
+ /// The trace id could map to a tracing instance for a thread
+ /// or could also map to a group of threads being traced with
+ /// the same trace options. A thread_id is normally optional
+ /// except in the case of tracing a complete process and tracing
+ /// needs to switched off on a particular thread.
+ /// A situation could occur where initially a thread (lets say
+ /// thread A) is being individually traced with a particular
+ /// trace id and then tracing is started on the complete
+ /// process, in this case thread A will continue without any
+ /// change. All newly spawned threads would be traced with the
+ /// trace id of the process.
+ /// Now if the StopTrace API is called for the whole process,
+ /// thread A will not be stopped and must be stopped separately.
+ //------------------------------------------------------------------
+ void StopTrace(SBError &error,
+ lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
+
+ //------------------------------------------------------------------
+ /// Get the trace configuration being used for the trace instance.
+ /// The threadid in the SBTraceOptions needs to be set when the
+ /// configuration used by a specific thread is being requested.
+ ///
+ /// @param[out] options
+ /// The trace options actually used by the trace instance
+ /// would be filled by the API.
+ ///
+ /// @param[out] error
+ /// An error explaining what went wrong.
+ //------------------------------------------------------------------
+ void GetTraceConfig(SBTraceOptions &options, SBError &error);
+
+ lldb::user_id_t GetTraceUID();
+
+ bool IsValid();
+
+protected:
+ typedef std::shared_ptr<TraceImpl> TraceImplSP;
+
+ friend class SBProcess;
+
+ void SetTraceUID(lldb::user_id_t uid);
+
+ TraceImplSP m_trace_impl_sp;
+
+ lldb::ProcessSP GetSP() const;
+
+ void SetSP(const ProcessSP &process_sp);
+
+ lldb::ProcessWP m_opaque_wp;
+};
+} // namespace lldb
+
+#endif // LLDB_SBTrace_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBTraceOptions.h b/contrib/llvm/tools/lldb/include/lldb/API/SBTraceOptions.h
new file mode 100644
index 0000000..c9735e1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBTraceOptions.h
@@ -0,0 +1,58 @@
+//===-- SBTraceOptions ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SBTRACEOPTIONS_H_
+#define SBTRACEOPTIONS_H_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class LLDB_API SBTraceOptions {
+public:
+ SBTraceOptions();
+
+ lldb::TraceType getType() const;
+
+ uint64_t getTraceBufferSize() const;
+
+ /// The trace parameters consist of any custom parameters
+ /// apart from the generic parameters such as
+ /// TraceType, trace_buffer_size and meta_data_buffer_size.
+ /// The returned parameters would be formatted as a JSON Dictionary.
+ lldb::SBStructuredData getTraceParams(lldb::SBError &error);
+
+ uint64_t getMetaDataBufferSize() const;
+
+ /// SBStructuredData is meant to hold any custom parameters
+ /// apart from meta buffer size and trace size. They should
+ /// be formatted as a JSON Dictionary.
+ void setTraceParams(lldb::SBStructuredData &params);
+
+ void setType(lldb::TraceType type);
+
+ void setTraceBufferSize(uint64_t size);
+
+ void setMetaDataBufferSize(uint64_t size);
+
+ void setThreadID(lldb::tid_t thread_id);
+
+ lldb::tid_t getThreadID();
+
+ bool IsValid();
+
+protected:
+ friend class SBProcess;
+ friend class SBTrace;
+
+ lldb::TraceOptionsSP m_traceoptions_sp;
+};
+}
+
+#endif /* SBTRACEOPTIONS_H_ */
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBWatchpoint.h b/contrib/llvm/tools/lldb/include/lldb/API/SBWatchpoint.h
index 284ec12..92d4851 100644
--- a/contrib/llvm/tools/lldb/include/lldb/API/SBWatchpoint.h
+++ b/contrib/llvm/tools/lldb/include/lldb/API/SBWatchpoint.h
@@ -72,7 +72,7 @@ private:
friend class SBTarget;
friend class SBValue;
- lldb::WatchpointSP m_opaque_sp;
+ std::weak_ptr<lldb_private::Watchpoint> m_opaque_wp;
};
} // namespace lldb
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Breakpoint.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Breakpoint.h
index 9af6e58..4124133 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Breakpoint.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Breakpoint.h
@@ -26,8 +26,8 @@
#include "lldb/Breakpoint/Stoppoint.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/SearchFilter.h"
-#include "lldb/Core/StringList.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Utility/StringList.h"
+#include "lldb/Utility/StructuredData.h"
namespace lldb_private {
@@ -169,7 +169,7 @@ public:
virtual bool EvaluatePrecondition(StoppointCallbackContext &context);
- virtual Error ConfigurePrecondition(Args &options);
+ virtual Status ConfigurePrecondition(Args &options);
virtual void GetDescription(Stream &stream, lldb::DescriptionLevel level);
};
@@ -178,7 +178,7 @@ public:
// Saving & restoring breakpoints:
static lldb::BreakpointSP CreateFromStructuredData(
- Target &target, StructuredData::ObjectSP &data_object_sp, Error &error);
+ Target &target, StructuredData::ObjectSP &data_object_sp, Status &error);
static bool
SerializedBreakpointMatchesNames(StructuredData::ObjectSP &bkpt_object_sp,
@@ -613,7 +613,7 @@ public:
lldb::SearchFilterSP GetSearchFilter() { return m_filter_sp; }
- bool AddName(const char *new_name, Error &error);
+ bool AddName(llvm::StringRef new_name, Status &error);
void RemoveName(const char *name_to_remove) {
if (name_to_remove)
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointID.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointID.h
index aa4add4..57411b3 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointID.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointID.h
@@ -84,7 +84,7 @@ public:
/// \b true if the name is a breakpoint name (as opposed to an ID or
/// range) false otherwise.
//------------------------------------------------------------------
- static bool StringIsBreakpointName(llvm::StringRef str, Error &error);
+ static bool StringIsBreakpointName(llvm::StringRef str, Status &error);
//------------------------------------------------------------------
/// Takes a breakpoint ID and the breakpoint location id and returns
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocation.h
index 43aef9f..a1086aa 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocation.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocation.h
@@ -19,7 +19,7 @@
// Project includes
#include "lldb/Breakpoint/StoppointLocation.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/UserID.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
@@ -161,7 +161,7 @@ public:
//------------------------------------------------------------------
const char *GetConditionText(size_t *hash = nullptr) const;
- bool ConditionSaysStop(ExecutionContext &exe_ctx, Error &error);
+ bool ConditionSaysStop(ExecutionContext &exe_ctx, Status &error);
//------------------------------------------------------------------
/// Set the valid thread to be checked when the breakpoint is hit.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointOptions.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointOptions.h
index e053af3..420d591 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointOptions.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointOptions.h
@@ -17,9 +17,9 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Baton.h"
-#include "lldb/Core/StringList.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Utility/Baton.h"
+#include "lldb/Utility/StringList.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
@@ -50,7 +50,7 @@ public:
static std::unique_ptr<CommandData>
CreateFromStructuredData(const StructuredData::Dictionary &options_dict,
- Error &error);
+ Status &error);
StringList user_source;
std::string script_source;
@@ -119,7 +119,7 @@ public:
static std::unique_ptr<BreakpointOptions>
CreateFromStructuredData(Target &target,
const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
virtual StructuredData::ObjectSP SerializeToStructuredData();
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolver.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolver.h
index e19a213..7bcd889 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolver.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolver.h
@@ -15,12 +15,11 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/Breakpoint.h"
-#include "lldb/Breakpoint/BreakpointResolver.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/SearchFilter.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/RegularExpression.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
@@ -141,7 +140,7 @@ public:
static lldb::BreakpointResolverSP
CreateFromStructuredData(const StructuredData::Dictionary &resolver_dict,
- Error &error);
+ Status &error);
virtual StructuredData::ObjectSP SerializeToStructuredData() {
return StructuredData::ObjectSP();
@@ -193,7 +192,7 @@ public:
static const char *ResolverTyToName(enum ResolverTy);
- static ResolverTy NameToResolverTy(const char *name);
+ static ResolverTy NameToResolverTy(llvm::StringRef name);
virtual lldb::BreakpointResolverSP
CopyForBreakpoint(Breakpoint &breakpoint) = 0;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h
index 6d2d505..9d757c8 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h
@@ -39,7 +39,7 @@ public:
static BreakpointResolver *
CreateFromStructuredData(Breakpoint *bkpt,
const StructuredData::Dictionary &options_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h
index f1fdf60..f7bba3d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h
@@ -36,7 +36,7 @@ public:
static BreakpointResolver *
CreateFromStructuredData(Breakpoint *bkpt,
const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
@@ -63,6 +63,8 @@ public:
lldb::BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override;
protected:
+ void FilterContexts(SymbolContextList &sc_list);
+
friend class Breakpoint;
FileSpec m_file_spec; // This is the file spec we are looking for.
uint32_t m_line_number; // This is the line number that we are looking for.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
index 0429e26..d620e99 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
@@ -17,7 +17,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointResolver.h"
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
@@ -38,7 +38,7 @@ public:
static BreakpointResolver *
CreateFromStructuredData(Breakpoint *bkpt,
const StructuredData::Dictionary &options_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverName.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverName.h
index 4223125..c7716d5 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverName.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointResolverName.h
@@ -57,7 +57,7 @@ public:
static BreakpointResolver *
CreateFromStructuredData(Breakpoint *bkpt,
const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointSite.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointSite.h
index b334c6e..6e98756 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointSite.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointSite.h
@@ -21,7 +21,7 @@
// Project includes
#include "lldb/Breakpoint/BreakpointLocationCollection.h"
#include "lldb/Breakpoint/StoppointLocation.h"
-#include "lldb/Core/UserID.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-forward.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Stoppoint.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Stoppoint.h
index 5d131a5..3195ef9 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Stoppoint.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Stoppoint.h
@@ -14,7 +14,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/UserID.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/StoppointLocation.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/StoppointLocation.h
index ba03b4e..f64035b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/StoppointLocation.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/StoppointLocation.h
@@ -14,7 +14,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/UserID.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
// #include "lldb/Breakpoint/BreakpointOptions.h"
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Watchpoint.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Watchpoint.h
index 97f2e28..69067a5 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Watchpoint.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Watchpoint.h
@@ -19,9 +19,9 @@
// Project includes
#include "lldb/Breakpoint/StoppointLocation.h"
#include "lldb/Breakpoint/WatchpointOptions.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
@@ -100,7 +100,7 @@ public:
void DumpSnapshots(Stream *s, const char *prefix = nullptr) const;
void DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const;
Target &GetTarget() { return m_target; }
- const Error &GetError() { return m_error; }
+ const Status &GetError() { return m_error; }
//------------------------------------------------------------------
/// Returns the WatchpointOptions structure set for this watchpoint.
@@ -213,8 +213,8 @@ private:
lldb::ValueObjectSP m_old_value_sp;
lldb::ValueObjectSP m_new_value_sp;
CompilerType m_type;
- Error m_error; // An error object describing errors associated with this
- // watchpoint.
+ Status m_error; // An error object describing errors associated with this
+ // watchpoint.
WatchpointOptions
m_options; // Settable watchpoint options, which is a delegate to handle
// the callback machinery.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/WatchpointOptions.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/WatchpointOptions.h
index bfb814e..6ab1264 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/WatchpointOptions.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/WatchpointOptions.h
@@ -17,8 +17,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Baton.h"
-#include "lldb/Core/StringList.h"
+#include "lldb/Utility/Baton.h"
+#include "lldb/Utility/StringList.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Address.h b/contrib/llvm/tools/lldb/include/lldb/Core/Address.h
index 909a060..4c77458 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Address.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Address.h
@@ -10,13 +10,44 @@
#ifndef liblldb_Address_h_
#define liblldb_Address_h_
-// C Includes
-// C++ Includes
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-enumerations.h" // for AddressClass::eAddressClassInvalid
+#include "lldb/lldb-forward.h" // for SectionWP, SectionSP, ModuleSP
+#include "lldb/lldb-types.h" // for addr_t
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Symbol/SymbolContextScope.h"
-#include "lldb/lldb-private.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, UINT32_MAX, int64_t
+
+namespace lldb_private {
+class Block;
+}
+namespace lldb_private {
+class CompileUnit;
+}
+namespace lldb_private {
+class ExecutionContextScope;
+}
+namespace lldb_private {
+class Function;
+}
+namespace lldb_private {
+class SectionList;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class Symbol;
+}
+namespace lldb_private {
+class SymbolContext;
+}
+namespace lldb_private {
+class Target;
+}
+namespace lldb_private {
+struct LineEntry;
+}
namespace lldb_private {
@@ -391,6 +422,10 @@ public:
/// a section + offset. The Target's SectionLoadList object
/// is used to resolve the address.
///
+ /// @param[in] allow_section_end
+ /// If true, treat an address pointing to the end of the module as
+ /// belonging to that module.
+ ///
/// @return
/// Returns \b true if the load address was resolved to be
/// section/offset, \b false otherwise. It is often ok for an
@@ -398,11 +433,13 @@ public:
/// happens for JIT'ed code, or any load addresses on the stack
/// or heap.
//------------------------------------------------------------------
- bool SetLoadAddress(lldb::addr_t load_addr, Target *target);
+ bool SetLoadAddress(lldb::addr_t load_addr, Target *target,
+ bool allow_section_end = false);
bool SetOpcodeLoadAddress(
lldb::addr_t load_addr, Target *target,
- lldb::AddressClass addr_class = lldb::eAddressClassInvalid);
+ lldb::AddressClass addr_class = lldb::eAddressClassInvalid,
+ bool allow_section_end = false);
bool SetCallableLoadAddress(lldb::addr_t load_addr, Target *target);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/AddressRange.h b/contrib/llvm/tools/lldb/include/lldb/Core/AddressRange.h
index fa9fefb..e787d1d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/AddressRange.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/AddressRange.h
@@ -10,11 +10,21 @@
#ifndef liblldb_AddressRange_h_
#define liblldb_AddressRange_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/Address.h"
+#include "lldb/lldb-forward.h" // for SectionSP
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <stddef.h> // for size_t
+
+namespace lldb_private {
+class SectionList;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class Target;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolver.h b/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolver.h
index 5fe2ec1..432268e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolver.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolver.h
@@ -10,20 +10,20 @@
#ifndef liblldb_AddressResolver_h_
#define liblldb_AddressResolver_h_
-#include <vector>
-
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Address.h"
#include "lldb/Core/AddressRange.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/SearchFilter.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+
+#include <stddef.h> // for size_t
+#include <vector>
namespace lldb_private {
+class ModuleList;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
//----------------------------------------------------------------------
/// @class AddressResolver AddressResolver.h "lldb/Core/AddressResolver.h"
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverFileLine.h b/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverFileLine.h
index 950750e..ec15cc7 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverFileLine.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverFileLine.h
@@ -10,8 +10,22 @@
#ifndef liblldb_AddressResolverFileLine_h_
#define liblldb_AddressResolverFileLine_h_
-// Project includes
#include "lldb/Core/AddressResolver.h"
+#include "lldb/Core/SearchFilter.h" // for Searcher, Searcher::CallbackR...
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+
+#include <stdint.h> // for uint32_t
+
+namespace lldb_private {
+class Address;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class SymbolContext;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverName.h b/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverName.h
index e93d16f..aadc054 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverName.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/AddressResolverName.h
@@ -10,10 +10,21 @@
#ifndef liblldb_AddressResolverName_h_
#define liblldb_AddressResolverName_h_
-// Project includes
-
#include "lldb/Core/AddressResolver.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/SearchFilter.h" // for Searcher, Searcher::Call...
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+
+namespace lldb_private {
+class Address;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class SymbolContext;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ArchSpec.h b/contrib/llvm/tools/lldb/include/lldb/Core/ArchSpec.h
index 7f663f7..75c7079 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ArchSpec.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ArchSpec.h
@@ -12,13 +12,31 @@
#if defined(__cplusplus)
-#include "lldb/Core/ConstString.h"
-#include "lldb/lldb-forward.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "llvm/ADT/StringRef.h" // for StringRef
#include "llvm/ADT/Triple.h"
+#include <string> // for string
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
+
+namespace lldb_private {
+class Platform;
+}
namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class StringList;
+}
+namespace lldb_private {
+class Thread;
+}
-struct CoreDefinition;
+namespace lldb_private {
//----------------------------------------------------------------------
/// @class ArchSpec ArchSpec.h "lldb/Core/ArchSpec.h"
@@ -307,7 +325,7 @@ public:
/// @return A string representing target CPU for the current
/// architecture.
//------------------------------------------------------------------
- std::string GetClangTargetCPU();
+ std::string GetClangTargetCPU() const;
//------------------------------------------------------------------
/// Return a string representing target application ABI.
@@ -607,6 +625,7 @@ public:
protected:
bool IsEqualTo(const ArchSpec &rhs, bool exact_match) const;
+ void UpdateCore();
llvm::Triple m_triple;
Core m_core = kCore_invalid;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Broadcaster.h b/contrib/llvm/tools/lldb/include/lldb/Core/Broadcaster.h
index c23f12c..825287d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Broadcaster.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Broadcaster.h
@@ -10,21 +10,33 @@
#ifndef liblldb_Broadcaster_h_
#define liblldb_Broadcaster_h_
-// C Includes
-// C++ Includes
-#include <functional>
-#include <list>
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-forward.h" // for ListenerSP, EventSP, Broadcast...
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <cstdint> // for uint32_t, UINT32_MAX
#include <map>
+#include <memory> // for shared_ptr, operator==, enable...
#include <mutex>
+#include <set> // for set
#include <string>
+#include <utility> // for pair
#include <vector>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/lldb-private.h"
-
-#include "llvm/ADT/SmallVector.h"
+namespace lldb_private {
+class Broadcaster;
+}
+namespace lldb_private {
+class EventData;
+}
+namespace lldb_private {
+class Listener;
+}
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
@@ -82,8 +94,8 @@ protected:
public:
// Listeners hold onto weak pointers to their broadcaster managers. So they
- // must be
- // made into shared pointers, which you do with MakeBroadcasterManager.
+ // must be made into shared pointers, which you do with
+ // MakeBroadcasterManager.
static lldb::BroadcasterManagerSP MakeBroadcasterManager();
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Communication.h b/contrib/llvm/tools/lldb/include/lldb/Core/Communication.h
index 8a875dd..57fa483 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Communication.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Communication.h
@@ -10,19 +10,31 @@
#ifndef liblldb_Communication_h_
#define liblldb_Communication_h_
-// C Includes
-// C++ Includes
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Utility/Timeout.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for ConnectionStatus, FLAGS_ANONYMOU...
+#include "lldb/lldb-forward.h" // for ConnectionSP
+#include "lldb/lldb-types.h" // for thread_arg_t, thread_result_t
+
#include <atomic>
#include <mutex>
+#include <ratio> // for micro
#include <string>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Host/HostThread.h"
-#include "lldb/Utility/Timeout.h"
-#include "lldb/lldb-private.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint8_t
+
+namespace lldb_private {
+class Connection;
+}
+namespace lldb_private {
+class ConstString;
+}
+namespace lldb_private {
+class Status;
+}
namespace lldb_private {
@@ -59,7 +71,7 @@ namespace lldb_private {
/// reads data and caches any received bytes. To start the read thread
/// clients call:
///
-/// bool Communication::StartReadThread (Error *);
+/// bool Communication::StartReadThread (Status *);
///
/// If true is returned a read thread has been spawned that will
/// continually execute a call to the pure virtual DoRead function:
@@ -142,10 +154,10 @@ public:
/// internal error object should be filled in with an
/// appropriate value based on the result of this function.
///
- /// @see Error& Communication::GetError ();
+ /// @see Status& Communication::GetError ();
/// @see bool Connection::Connect (const char *url);
//------------------------------------------------------------------
- lldb::ConnectionStatus Connect(const char *url, Error *error_ptr);
+ lldb::ConnectionStatus Connect(const char *url, Status *error_ptr);
//------------------------------------------------------------------
/// Disconnect the communications connection if one is currently
@@ -156,10 +168,10 @@ public:
/// internal error object should be filled in with an
/// appropriate value based on the result of this function.
///
- /// @see Error& Communication::GetError ();
+ /// @see Status& Communication::GetError ();
/// @see bool Connection::Disconnect ();
//------------------------------------------------------------------
- lldb::ConnectionStatus Disconnect(Error *error_ptr = nullptr);
+ lldb::ConnectionStatus Disconnect(Status *error_ptr = nullptr);
//------------------------------------------------------------------
/// Check if the connection is valid.
@@ -205,7 +217,7 @@ public:
/// @see size_t Connection::Read (void *, size_t);
//------------------------------------------------------------------
size_t Read(void *dst, size_t dst_len, const Timeout<std::micro> &timeout,
- lldb::ConnectionStatus &status, Error *error_ptr);
+ lldb::ConnectionStatus &status, Status *error_ptr);
//------------------------------------------------------------------
/// The actual write function that attempts to write to the
@@ -225,7 +237,7 @@ public:
/// The number of bytes actually Written.
//------------------------------------------------------------------
size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status,
- Error *error_ptr);
+ Status *error_ptr);
//------------------------------------------------------------------
/// Sets the connection that it to be used by this class.
@@ -268,7 +280,7 @@ public:
/// @see void Communication::AppendBytesToCache (const uint8_t * bytes, size_t
/// len, bool broadcast);
//------------------------------------------------------------------
- virtual bool StartReadThread(Error *error_ptr = nullptr);
+ virtual bool StartReadThread(Status *error_ptr = nullptr);
//------------------------------------------------------------------
/// Stops the read thread by cancelling it.
@@ -277,9 +289,9 @@ public:
/// \b True if the read thread was successfully canceled, \b
/// false otherwise.
//------------------------------------------------------------------
- virtual bool StopReadThread(Error *error_ptr = nullptr);
+ virtual bool StopReadThread(Status *error_ptr = nullptr);
- virtual bool JoinReadThread(Error *error_ptr = nullptr);
+ virtual bool JoinReadThread(Status *error_ptr = nullptr);
//------------------------------------------------------------------
/// Checks if there is a currently running read thread.
///
@@ -349,7 +361,7 @@ protected:
size_t ReadFromConnection(void *dst, size_t dst_len,
const Timeout<std::micro> &timeout,
- lldb::ConnectionStatus &status, Error *error_ptr);
+ lldb::ConnectionStatus &status, Status *error_ptr);
//------------------------------------------------------------------
/// Append new bytes that get read from the read thread into the
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/DataBufferMemoryMap.h b/contrib/llvm/tools/lldb/include/lldb/Core/DataBufferMemoryMap.h
deleted file mode 100644
index 1b8277b..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Core/DataBufferMemoryMap.h
+++ /dev/null
@@ -1,154 +0,0 @@
-//===-- DataBufferMemoryMap.h -----------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_DataBufferMemoryMap_h_
-#define liblldb_DataBufferMemoryMap_h_
-
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/Error.h"
-#include "lldb/lldb-private.h"
-#include <string>
-
-namespace lldb_private {
-
-//----------------------------------------------------------------------
-/// @class DataBufferMemoryMap DataBufferMemoryMap.h
-/// "lldb/Core/DataBufferMemoryMap.h"
-/// @brief A subclass of DataBuffer that memory maps data.
-///
-/// This class memory maps data and stores any needed data for the
-/// memory mapping in its internal state. Memory map requests are not
-/// required to have any alignment or size constraints, this class will
-/// work around any host OS issues regarding such things.
-///
-/// This class is designed to allow pages to be faulted in as needed and
-/// works well data from large files that won't be accessed all at once.
-//----------------------------------------------------------------------
-class DataBufferMemoryMap : public DataBuffer {
-public:
- //------------------------------------------------------------------
- /// Default Constructor
- //------------------------------------------------------------------
- DataBufferMemoryMap();
-
- //------------------------------------------------------------------
- /// Destructor.
- ///
- /// Virtual destructor since this class inherits from a pure virtual
- /// base class #DataBuffer.
- //------------------------------------------------------------------
- ~DataBufferMemoryMap() override;
-
- //------------------------------------------------------------------
- /// Reverts this object to an empty state by unmapping any memory
- /// that is currently owned.
- //------------------------------------------------------------------
- void Clear();
-
- //------------------------------------------------------------------
- /// @copydoc DataBuffer::GetBytes()
- //------------------------------------------------------------------
- uint8_t *GetBytes() override;
-
- //------------------------------------------------------------------
- /// @copydoc DataBuffer::GetBytes() const
- //------------------------------------------------------------------
- const uint8_t *GetBytes() const override;
-
- //------------------------------------------------------------------
- /// @copydoc DataBuffer::GetByteSize() const
- //------------------------------------------------------------------
- lldb::offset_t GetByteSize() const override;
-
- //------------------------------------------------------------------
- /// Error get accessor.
- ///
- /// @return
- /// A const reference to Error object in case memory mapping
- /// fails.
- //------------------------------------------------------------------
- const Error &GetError() const;
-
- //------------------------------------------------------------------
- /// Memory map all or part of a file.
- ///
- /// Memory map \a length bytes from \a file starting \a offset
- /// bytes into the file. If \a length is set to \c SIZE_MAX,
- /// then map as many bytes as possible.
- ///
- /// @param[in] file
- /// The file specification from which to map data.
- ///
- /// @param[in] offset
- /// The offset in bytes from the beginning of the file where
- /// memory mapping should begin.
- ///
- /// @param[in] length
- /// The size in bytes that should be mapped starting \a offset
- /// bytes into the file. If \a length is \c SIZE_MAX, map
- /// as many bytes as possible. Even though it may be possible
- /// for a 32-bit host debugger to debug a 64-bit target, size_t
- /// still dictates the maximum possible size that can be mapped
- /// into this process. For this kind of cross-arch debugging
- /// scenario, mappings and views should be managed at a higher
- /// level.
- ///
- /// @return
- /// The number of bytes mapped starting from the \a offset.
- //------------------------------------------------------------------
- size_t MemoryMapFromFileSpec(const FileSpec *file, lldb::offset_t offset = 0,
- size_t length = SIZE_MAX,
- bool writeable = false);
-
- //------------------------------------------------------------------
- /// Memory map all or part of a file.
- ///
- /// Memory map \a length bytes from an opened file descriptor \a fd
- /// starting \a offset bytes into the file. If \a length is set to
- /// \c SIZE_MAX, then map as many bytes as possible.
- ///
- /// @param[in] fd
- /// The posix file descriptor for an already opened file
- /// from which to map data.
- ///
- /// @param[in] offset
- /// The offset in bytes from the beginning of the file where
- /// memory mapping should begin.
- ///
- /// @param[in] length
- /// The size in bytes that should be mapped starting \a offset
- /// bytes into the file. If \a length is \c SIZE_MAX, map
- /// as many bytes as possible.
- ///
- /// @return
- /// The number of bytes mapped starting from the \a offset.
- //------------------------------------------------------------------
- size_t MemoryMapFromFileDescriptor(int fd, lldb::offset_t offset,
- size_t length, bool write,
- bool fd_is_file);
-
-protected:
- //------------------------------------------------------------------
- // Classes that inherit from DataBufferMemoryMap can see and modify these
- //------------------------------------------------------------------
- uint8_t *m_mmap_addr; ///< The actual pointer that was returned from \c mmap()
- size_t m_mmap_size; ///< The actual number of bytes that were mapped when \c
- ///mmap() was called
- uint8_t *m_data; ///< The data the user requested somewhere within the memory
- ///mapped data.
- lldb::offset_t
- m_size; ///< The size of the data the user got when data was requested
-
-private:
- DISALLOW_COPY_AND_ASSIGN(DataBufferMemoryMap);
-};
-
-} // namespace lldb_private
-
-#endif // liblldb_DataBufferMemoryMap_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Debugger.h b/contrib/llvm/tools/lldb/include/lldb/Core/Debugger.h
index ccc07b3..34d35ff 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Debugger.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Debugger.h
@@ -14,9 +14,7 @@
#include <stdint.h>
// C++ Includes
-#include <map>
#include <memory>
-#include <mutex>
#include <vector>
// Other libraries and framework includes
@@ -24,21 +22,55 @@
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/IOHandler.h"
-#include "lldb/Core/Listener.h"
#include "lldb/Core/SourceManager.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/Terminal.h"
+#include "lldb/Target/ExecutionContext.h" // for ExecutionContext
#include "lldb/Target/Platform.h"
#include "lldb/Target/TargetList.h"
-#include "lldb/lldb-public.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/Utility/UserID.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for ScriptLanguage, Langua...
+#include "lldb/lldb-forward.h" // for StreamFileSP, DebuggerSP
+#include "lldb/lldb-private-enumerations.h" // for VarSetOperationType
+#include "lldb/lldb-private-types.h" // for LoadPluginCallbackType
+#include "lldb/lldb-types.h" // for LogOutputCallback, thr...
+
+#include "llvm/ADT/ArrayRef.h" // for ArrayRef
+#include "llvm/ADT/StringMap.h" // for StringMap
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/Support/DynamicLibrary.h" // for DynamicLibrary
+#include "llvm/Support/Threading.h"
+
+#include <assert.h> // for assert
+#include <stddef.h> // for size_t
+#include <stdio.h>
+namespace lldb_private {
+class Address;
+}
+namespace lldb_private {
+class CommandInterpreter;
+}
+namespace lldb_private {
+class Process;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class SymbolContext;
+}
+namespace lldb_private {
+class Target;
+}
namespace llvm {
-namespace sys {
-class DynamicLibrary;
-} // namespace sys
-} // namespace llvm
+class raw_ostream;
+}
namespace lldb_private {
@@ -190,9 +222,10 @@ public:
void SetCloseInputOnEOF(bool b);
- bool EnableLog(const char *channel, const char **categories,
- const char *log_file, uint32_t log_options,
- Stream &error_stream);
+ bool EnableLog(llvm::StringRef channel,
+ llvm::ArrayRef<const char *> categories,
+ llvm::StringRef log_file, uint32_t log_options,
+ llvm::raw_ostream &error_stream);
void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton);
@@ -206,9 +239,9 @@ public:
eStopDisassemblyTypeAlways
};
- Error SetPropertyValue(const ExecutionContext *exe_ctx,
- VarSetOperationType op, llvm::StringRef property_path,
- llvm::StringRef value) override;
+ Status SetPropertyValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op, llvm::StringRef property_path,
+ llvm::StringRef value) override;
bool GetAutoConfirm() const;
@@ -216,6 +249,8 @@ public:
const FormatEntity::Entry *GetFrameFormat() const;
+ const FormatEntity::Entry *GetFrameFormatUnique() const;
+
const FormatEntity::Entry *GetThreadFormat() const;
const FormatEntity::Entry *GetThreadStopFormat() const;
@@ -273,7 +308,7 @@ public:
const ConstString &GetInstanceName() { return m_instance_name; }
- bool LoadPlugin(const FileSpec &spec, Error &error);
+ bool LoadPlugin(const FileSpec &spec, Status &error);
void ExecuteIOHandlers();
@@ -285,7 +320,7 @@ public:
bool IsHandlingEvents() const { return m_event_handler_thread.IsJoinable(); }
- Error RunREPL(lldb::LanguageType language, const char *repl_options);
+ Status RunREPL(lldb::LanguageType language, const char *repl_options);
// This is for use in the command interpreter, when you either want the
// selected target, or if no target
@@ -363,9 +398,8 @@ protected:
std::unique_ptr<CommandInterpreter> m_command_interpreter_ap;
IOHandlerStack m_input_reader_stack;
- typedef std::map<std::string, lldb::StreamWP> LogStreamMap;
- LogStreamMap m_log_streams;
- lldb::StreamSP m_log_callback_stream_sp;
+ llvm::StringMap<std::weak_ptr<llvm::raw_ostream>> m_log_streams;
+ std::shared_ptr<llvm::raw_ostream> m_log_callback_stream_sp;
ConstString m_instance_name;
static LoadPluginCallbackType g_load_plugin_callback;
typedef std::vector<llvm::sys::DynamicLibrary> LoadedPluginsList;
@@ -374,7 +408,7 @@ protected:
HostThread m_io_handler_thread;
Broadcaster m_sync_broadcaster;
lldb::ListenerSP m_forward_listener_sp;
- std::once_flag m_clear_once;
+ llvm::once_flag m_clear_once;
//----------------------------------------------------------------------
// Events for m_sync_broadcaster
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Disassembler.h b/contrib/llvm/tools/lldb/include/lldb/Core/Disassembler.h
index c420747..addc83a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Disassembler.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Disassembler.h
@@ -10,22 +10,68 @@
#ifndef liblldb_Disassembler_h_
#define liblldb_Disassembler_h_
-// C Includes
-// C++ Includes
-#include <string>
-#include <vector>
-
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/Address.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/FormatEntity.h" // for FormatEntity
#include "lldb/Core/Opcode.h"
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Symbol/LineEntry.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Target/ExecutionContext.h" // for ExecutionContext
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for AddressClass, AddressClass...
+#include "lldb/lldb-forward.h" // for InstructionSP, DisassemblerSP
+#include "lldb/lldb-types.h" // for addr_t, offset_t
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <functional> // for function
+#include <map>
+#include <memory> // for enable_shared_from_this
+#include <set>
+#include <string>
+#include <vector>
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, int64_t
+#include <stdio.h> // for FILE
+
+namespace lldb_private {
+class AddressRange;
+}
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Debugger;
+}
+namespace lldb_private {
+class Disassembler;
+}
+namespace lldb_private {
+class Module;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class SymbolContext;
+}
+namespace lldb_private {
+class SymbolContextList;
+}
+namespace lldb_private {
+class Target;
+}
+namespace lldb_private {
+struct RegisterInfo;
+}
+namespace llvm {
+template <typename T> class SmallVectorImpl;
+}
namespace lldb_private {
@@ -127,6 +173,8 @@ public:
virtual bool HasDelaySlot();
+ bool CanSetBreakpoint ();
+
virtual size_t Decode(const Disassembler &disassembler,
const DataExtractor &data,
lldb::offset_t data_offset) = 0;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/DumpDataExtractor.h b/contrib/llvm/tools/lldb/include/lldb/Core/DumpDataExtractor.h
new file mode 100644
index 0000000..46e676c
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/DumpDataExtractor.h
@@ -0,0 +1,95 @@
+//===-- DumpDataExtractor.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_CORE_DUMPDATAEXTRACTOR_H
+#define LLDB_CORE_DUMPDATAEXTRACTOR_H
+
+#include "lldb/lldb-enumerations.h" // for Format
+#include "lldb/lldb-types.h"
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+
+namespace lldb_private {
+class DataExtractor;
+class ExecutionContextScope;
+class Stream;
+
+//------------------------------------------------------------------
+/// Dumps \a item_count objects into the stream \a s.
+///
+/// Dumps \a item_count objects using \a item_format, each of which
+/// are \a item_byte_size bytes long starting at offset \a offset
+/// bytes into the contained data, into the stream \a s. \a
+/// num_per_line objects will be dumped on each line before a new
+/// line will be output. If \a base_addr is a valid address, then
+/// each new line of output will be preceded by the address value
+/// plus appropriate offset, and a colon and space. Bitfield values
+/// can be dumped by calling this function multiple times with the
+/// same start offset, format and size, yet differing \a
+/// item_bit_size and \a item_bit_offset values.
+///
+/// @param[in] s
+/// The stream to dump the output to. This value can not be nullptr.
+///
+/// @param[in] offset
+/// The offset into the data at which to start dumping.
+///
+/// @param[in] item_format
+/// The format to use when dumping each item.
+///
+/// @param[in] item_byte_size
+/// The byte size of each item.
+///
+/// @param[in] item_count
+/// The number of items to dump.
+///
+/// @param[in] num_per_line
+/// The number of items to display on each line.
+///
+/// @param[in] base_addr
+/// The base address that gets added to the offset displayed on
+/// each line if the value is valid. Is \a base_addr is
+/// LLDB_INVALID_ADDRESS then no address values will be prepended
+/// to any lines.
+///
+/// @param[in] item_bit_size
+/// If the value to display is a bitfield, this value should
+/// be the number of bits that the bitfield item has within the
+/// item's byte size value. This function will need to be called
+/// multiple times with identical \a offset and \a item_byte_size
+/// values in order to display multiple bitfield values that
+/// exist within the same integer value. If the items being
+/// displayed are not bitfields, this value should be zero.
+///
+/// @param[in] item_bit_offset
+/// If the value to display is a bitfield, this value should
+/// be the offset in bits, or shift right amount, that the
+/// bitfield item occupies within the item's byte size value.
+/// This function will need to be called multiple times with
+/// identical \a offset and \a item_byte_size values in order
+/// to display multiple bitfield values that exist within the
+/// same integer value. If the items being displayed are not
+/// bitfields, this value should be zero.
+///
+/// @return
+/// The offset at which dumping ended.
+//------------------------------------------------------------------
+lldb::offset_t
+DumpDataExtractor(const DataExtractor &DE, Stream *s, lldb::offset_t offset,
+ lldb::Format item_format, size_t item_byte_size,
+ size_t item_count, size_t num_per_line, uint64_t base_addr,
+ uint32_t item_bit_size, uint32_t item_bit_offset,
+ ExecutionContextScope *exe_scope = nullptr);
+
+void DumpHexBytes(Stream *s, const void *src, size_t src_len,
+ uint32_t bytes_per_line, lldb::addr_t base_addr);
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/EmulateInstruction.h b/contrib/llvm/tools/lldb/include/lldb/Core/EmulateInstruction.h
index 90e66d6..bfc9ef0 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/EmulateInstruction.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/EmulateInstruction.h
@@ -15,9 +15,34 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Opcode.h"
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Core/RegisterValue.h"
-#include "lldb/lldb-private.h"
-#include "lldb/lldb-public.h"
+
+#include "lldb/Core/Address.h" // for Address
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for RegisterKind, ByteOrder
+#include "lldb/lldb-private-enumerations.h" // for InstructionType
+#include "lldb/lldb-private-types.h" // for RegisterInfo
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t, int64_t
+namespace lldb_private {
+class OptionValueDictionary;
+}
+namespace lldb_private {
+class RegisterContext;
+}
+namespace lldb_private {
+class RegisterValue;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class Target;
+}
+namespace lldb_private {
+class UnwindPlan;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Event.h b/contrib/llvm/tools/lldb/include/lldb/Core/Event.h
index 049bb3c..f4c7f47 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Event.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Event.h
@@ -10,19 +10,28 @@
#ifndef liblldb_Event_h_
#define liblldb_Event_h_
-// C Includes
-// C++ Includes
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-forward.h" // for EventDataSP, ProcessSP, Struct...
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+
#include <chrono>
#include <memory>
#include <string>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/StructuredData.h"
-#include "lldb/Host/Predicate.h"
-#include "lldb/lldb-private.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
+
+namespace lldb_private {
+class Event;
+}
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/FileLineResolver.h b/contrib/llvm/tools/lldb/include/lldb/Core/FileLineResolver.h
index e9e20c5..54bce4f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/FileLineResolver.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/FileLineResolver.h
@@ -10,9 +10,19 @@
#ifndef liblldb_FileLineResolver_h_
#define liblldb_FileLineResolver_h_
-// Project includes
-#include "lldb/Core/AddressResolver.h"
+#include "lldb/Core/SearchFilter.h" // for Searcher, Searcher::CallbackR...
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+
+#include <stdint.h> // for uint32_t, UINT32_MAX
+
+namespace lldb_private {
+class Address;
+}
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/FileSpecList.h b/contrib/llvm/tools/lldb/include/lldb/Core/FileSpecList.h
index 75995d1..3cbffca 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/FileSpecList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/FileSpecList.h
@@ -11,10 +11,16 @@
#define liblldb_FileSpecList_h_
#if defined(__cplusplus)
-#include "lldb/Host/FileSpec.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/FileSpec.h"
+
#include <vector>
+#include <stddef.h> // for size_t
+
+namespace lldb_private {
+class Stream;
+}
+
namespace lldb_private {
//----------------------------------------------------------------------
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/FormatEntity.h b/contrib/llvm/tools/lldb/include/lldb/Core/FormatEntity.h
index b6fe9ea..aa5ccb4 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/FormatEntity.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/FormatEntity.h
@@ -10,19 +10,38 @@
#ifndef liblldb_FormatEntity_h_
#define liblldb_FormatEntity_h_
-// C Includes
-// C++ Includes
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-enumerations.h" // for Format::eFormatDefault, Format
+#include "lldb/lldb-types.h" // for addr_t
+#include <algorithm> // for min
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+
#include <string>
#include <vector>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Error.h"
-#include "lldb/lldb-private.h"
-
+namespace lldb_private {
+class Address;
+}
+namespace lldb_private {
+class ExecutionContext;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class StringList;
+}
+namespace lldb_private {
+class SymbolContext;
+}
+namespace lldb_private {
+class ValueObject;
+}
namespace llvm {
class StringRef;
-} // namespace llvm
+}
namespace lldb_private {
class FormatEntity {
@@ -186,11 +205,11 @@ public:
const Address *addr, ValueObject *valobj,
bool function_changed, bool initial_function);
- static Error Parse(const llvm::StringRef &format, Entry &entry);
+ static Status Parse(const llvm::StringRef &format, Entry &entry);
- static Error ExtractVariableInfo(llvm::StringRef &format_str,
- llvm::StringRef &variable_name,
- llvm::StringRef &variable_format);
+ static Status ExtractVariableInfo(llvm::StringRef &format_str,
+ llvm::StringRef &variable_name,
+ llvm::StringRef &variable_format);
static size_t AutoComplete(llvm::StringRef s, int match_start_point,
int max_return_elements, bool &word_complete,
@@ -209,8 +228,8 @@ public:
llvm::StringRef element_format);
protected:
- static Error ParseInternal(llvm::StringRef &format, Entry &parent_entry,
- uint32_t depth);
+ static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry,
+ uint32_t depth);
};
} // namespace lldb_private
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/IOHandler.h b/contrib/llvm/tools/lldb/include/lldb/Core/IOHandler.h
index 2e6ff31..ebf56d7 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/IOHandler.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/IOHandler.h
@@ -10,26 +10,27 @@
#ifndef liblldb_IOHandler_h_
#define liblldb_IOHandler_h_
-// C Includes
-#include <string.h>
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Flags.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-forward.h" // for IOHandlerSP, StreamFileSP
+#include "llvm/ADT/StringRef.h" // for StringRef
-// C++ Includes
#include <memory>
#include <mutex>
#include <string>
#include <vector>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Flags.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StringList.h"
-#include "lldb/Core/ValueObjectList.h"
-#include "lldb/Host/Predicate.h"
-#include "lldb/lldb-enumerations.h"
-#include "lldb/lldb-public.h"
+#include <stdint.h> // for uint32_t
+#include <stdio.h> // for FILE
+
+namespace lldb_private {
+class Debugger;
+}
namespace curses {
class Application;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Listener.h b/contrib/llvm/tools/lldb/include/lldb/Core/Listener.h
index b82844e..3d12f8f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Listener.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Listener.h
@@ -10,20 +10,29 @@
#ifndef liblldb_Select_h_
#define liblldb_Select_h_
-// C Includes
-// C++ Includes
-#include <chrono>
+#include "lldb/Core/Broadcaster.h" // for Broadcaster::BroadcasterImplWP
+#include "lldb/Utility/Timeout.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-forward.h" // for BroadcasterManagerWP, EventSP
+
+#include <condition_variable>
#include <list>
#include <map>
+#include <memory> // for owner_less, enable_shared_from_this
#include <mutex>
+#include <ratio> // for micro
#include <string>
#include <vector>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Event.h"
-#include "lldb/Utility/Timeout.h"
-#include "lldb/lldb-private.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
+
+namespace lldb_private {
+class ConstString;
+}
+namespace lldb_private {
+class Event;
+}
namespace lldb_private {
@@ -39,8 +48,7 @@ public:
//------------------------------------------------------------------
//
// Listeners have to be constructed into shared pointers - at least if you
- // want them to listen to
- // Broadcasters,
+ // want them to listen to Broadcasters,
protected:
Listener(const char *name);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Log.h b/contrib/llvm/tools/lldb/include/lldb/Core/Log.h
deleted file mode 100644
index d87c263..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Log.h
+++ /dev/null
@@ -1,189 +0,0 @@
-//===-- Log.h ---------------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_Log_h_
-#define liblldb_Log_h_
-
-// C Includes
-#include <signal.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Flags.h"
-#include "lldb/Core/Logging.h"
-#include "lldb/Core/PluginInterface.h"
-#include "lldb/lldb-private.h"
-
-#include "llvm/Support/FormatVariadic.h"
-
-//----------------------------------------------------------------------
-// Logging Options
-//----------------------------------------------------------------------
-#define LLDB_LOG_OPTION_THREADSAFE (1u << 0)
-#define LLDB_LOG_OPTION_VERBOSE (1u << 1)
-#define LLDB_LOG_OPTION_DEBUG (1u << 2)
-#define LLDB_LOG_OPTION_PREPEND_SEQUENCE (1u << 3)
-#define LLDB_LOG_OPTION_PREPEND_TIMESTAMP (1u << 4)
-#define LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD (1u << 5)
-#define LLDB_LOG_OPTION_PREPEND_THREAD_NAME (1U << 6)
-#define LLDB_LOG_OPTION_BACKTRACE (1U << 7)
-#define LLDB_LOG_OPTION_APPEND (1U << 8)
-
-//----------------------------------------------------------------------
-// Logging Functions
-//----------------------------------------------------------------------
-namespace lldb_private {
-
-class Log final {
-public:
- //------------------------------------------------------------------
- // Callback definitions for abstracted plug-in log access.
- //------------------------------------------------------------------
- typedef void (*DisableCallback)(const char **categories,
- Stream *feedback_strm);
- typedef Log *(*EnableCallback)(lldb::StreamSP &log_stream_sp,
- uint32_t log_options, const char **categories,
- Stream *feedback_strm);
- typedef void (*ListCategoriesCallback)(Stream *strm);
-
- struct Callbacks {
- DisableCallback disable;
- EnableCallback enable;
- ListCategoriesCallback list_categories;
- };
-
- //------------------------------------------------------------------
- // Static accessors for logging channels
- //------------------------------------------------------------------
- static void RegisterLogChannel(const ConstString &channel,
- const Log::Callbacks &log_callbacks);
-
- static bool UnregisterLogChannel(const ConstString &channel);
-
- static bool GetLogChannelCallbacks(const ConstString &channel,
- Log::Callbacks &log_callbacks);
-
- static bool EnableLogChannel(lldb::StreamSP &log_stream_sp,
- uint32_t log_options, const char *channel,
- const char **categories, Stream &error_stream);
-
- static void EnableAllLogChannels(lldb::StreamSP &log_stream_sp,
- uint32_t log_options,
- const char **categories,
- Stream *feedback_strm);
-
- static void DisableAllLogChannels(Stream *feedback_strm);
-
- static void ListAllLogChannels(Stream *strm);
-
- static void Initialize();
-
- static void Terminate();
-
- //------------------------------------------------------------------
- // Auto completion
- //------------------------------------------------------------------
- static void AutoCompleteChannelName(const char *channel_name,
- StringList &matches);
-
- //------------------------------------------------------------------
- // Member functions
- //------------------------------------------------------------------
- Log();
-
- Log(const lldb::StreamSP &stream_sp);
-
- ~Log();
-
- void PutCString(const char *cstr);
- void PutString(llvm::StringRef str);
-
- template <typename... Args> void Format(const char *fmt, Args &&... args) {
- PutString(llvm::formatv(fmt, std::forward<Args>(args)...).str());
- }
-
- // CLEANUP: Add llvm::raw_ostream &Stream() function.
- void Printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
-
- void VAPrintf(const char *format, va_list args);
-
- void LogIf(uint32_t mask, const char *fmt, ...)
- __attribute__((format(printf, 3, 4)));
-
- void Debug(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-
- void Error(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-
- void VAError(const char *format, va_list args);
-
- void Verbose(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-
- void Warning(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-
- Flags &GetOptions();
-
- const Flags &GetOptions() const;
-
- Flags &GetMask();
-
- const Flags &GetMask() const;
-
- bool GetVerbose() const;
-
- bool GetDebug() const;
-
- void SetStream(const lldb::StreamSP &stream_sp) { m_stream_sp = stream_sp; }
-
-protected:
- //------------------------------------------------------------------
- // Member variables
- //------------------------------------------------------------------
- lldb::StreamSP m_stream_sp;
- Flags m_options;
- Flags m_mask_bits;
-
-private:
- DISALLOW_COPY_AND_ASSIGN(Log);
-};
-
-class LogChannel : public PluginInterface {
-public:
- LogChannel();
-
- ~LogChannel() override;
-
- static lldb::LogChannelSP FindPlugin(const char *plugin_name);
-
- // categories is an array of chars that ends with a NULL element.
- virtual void Disable(const char **categories, Stream *feedback_strm) = 0;
-
- virtual bool
- Enable(lldb::StreamSP &log_stream_sp, uint32_t log_options,
- Stream *feedback_strm, // Feedback stream for argument errors etc
- const char **categories) = 0; // The categories to enable within this
- // logging stream, if empty, enable
- // default set
-
- virtual void ListCategories(Stream *strm) = 0;
-
-protected:
- std::unique_ptr<Log> m_log_ap;
-
-private:
- DISALLOW_COPY_AND_ASSIGN(LogChannel);
-};
-
-} // namespace lldb_private
-
-#endif // liblldb_Log_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Mangled.h b/contrib/llvm/tools/lldb/include/lldb/Core/Mangled.h
index 4170b70..22778fa 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Mangled.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Mangled.h
@@ -11,9 +11,18 @@
#define liblldb_Mangled_h_
#if defined(__cplusplus)
-#include "lldb/Core/ConstString.h"
-#include "lldb/lldb-private.h"
-#include <vector>
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-enumerations.h" // for LanguageType
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <stddef.h> // for size_t
+
+namespace lldb_private {
+class RegularExpression;
+}
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/MappedHash.h b/contrib/llvm/tools/lldb/include/lldb/Core/MappedHash.h
index 842a116..18d383e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/MappedHash.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/MappedHash.h
@@ -22,8 +22,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Stream.h"
class MappedHash {
public:
@@ -326,7 +326,7 @@ public:
1u, // Bucket hash data collision, but key didn't match
eResultEndOfHashData = 2u, // The chain of items for this hash data in
// this bucket is terminated, search no more
- eResultError = 3u // Error parsing the hash data, abort
+ eResultError = 3u // Status parsing the hash data, abort
};
struct Pair {
@@ -353,7 +353,7 @@ public:
bool IsValid() const {
return m_header.version == 1 &&
m_header.hash_function == eHashFunctionDJB &&
- m_header.bucket_count > 0 && m_header.hashes_count > 0;
+ m_header.bucket_count > 0;
}
uint32_t GetHashIndex(uint32_t bucket_idx) const {
@@ -409,7 +409,7 @@ public:
// searching
return false;
case eResultError:
- // Error parsing the hash data, abort
+ // Status parsing the hash data, abort
return false;
}
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Module.h b/contrib/llvm/tools/lldb/include/lldb/Core/Module.h
index 90d75b6..2ffe57a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Module.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Module.h
@@ -10,29 +10,86 @@
#ifndef liblldb_Module_h_
#define liblldb_Module_h_
-#include "lldb/Symbol/SymbolContextScope.h"
-
-// Project includes
+#include "lldb/Core/Address.h" // for Address
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/UUID.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/ModuleSpec.h" // for ModuleSpec
+#include "lldb/Symbol/SymbolContextScope.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/PathMappingList.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/Utility/UUID.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for LanguageType, SymbolType
#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h" // for addr_t, offset_t
-// Other libraries and framework includes
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Chrono.h"
-// C Includes
-// C++ Includes
#include <atomic>
+#include <memory> // for enable_shared_from_this
#include <mutex>
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
#include <string>
#include <vector>
namespace lldb_private {
+class CompilerDeclContext;
+}
+namespace lldb_private {
+class Function;
+}
+namespace lldb_private {
+class Log;
+}
+namespace lldb_private {
+class ObjectFile;
+}
+namespace lldb_private {
+class RegularExpression;
+}
+namespace lldb_private {
+class SectionList;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class Symbol;
+}
+namespace lldb_private {
+class SymbolContext;
+}
+namespace lldb_private {
+class SymbolContextList;
+}
+namespace lldb_private {
+class SymbolFile;
+}
+namespace lldb_private {
+class SymbolVendor;
+}
+namespace lldb_private {
+class Symtab;
+}
+namespace lldb_private {
+class Target;
+}
+namespace lldb_private {
+class TypeList;
+}
+namespace lldb_private {
+class TypeMap;
+}
+namespace lldb_private {
+class VariableList;
+}
+
+namespace lldb_private {
//----------------------------------------------------------------------
/// @class Module Module.h "lldb/Core/Module.h"
@@ -557,6 +614,8 @@ public:
const FileSpec &GetSymbolFileFileSpec() const { return m_symfile_spec; }
+ void PreloadSymbols();
+
void SetSymbolFileFileSpec(const FileSpec &file);
const llvm::sys::TimePoint<> &GetModificationTime() const {
@@ -593,7 +652,7 @@ public:
//------------------------------------------------------------------
bool IsLoadedInTarget(Target *target);
- bool LoadScriptingResourceInTarget(Target *target, Error &error,
+ bool LoadScriptingResourceInTarget(Target *target, Status &error,
Stream *feedback_stream = nullptr);
//------------------------------------------------------------------
@@ -669,7 +728,7 @@ public:
/// failed (see the `error` for more information in that case).
//------------------------------------------------------------------
ObjectFile *GetMemoryObjectFile(const lldb::ProcessSP &process_sp,
- lldb::addr_t header_addr, Error &error,
+ lldb::addr_t header_addr, Status &error,
size_t size_to_read = 512);
//------------------------------------------------------------------
/// Get the symbol vendor interface for the current architecture.
@@ -962,6 +1021,20 @@ public:
bool RemapSourceFile(llvm::StringRef path, std::string &new_path) const;
bool RemapSourceFile(const char *, std::string &) const = delete;
+ //------------------------------------------------------------------
+ /// Loads this module to memory.
+ ///
+ /// Loads the bits needed to create an executable image to the memory.
+ /// It is useful with bare-metal targets where target does not have the
+ /// ability to start a process itself.
+ ///
+ /// @param[in] target
+ /// Target where to load the module.
+ ///
+ /// @return
+ //------------------------------------------------------------------
+ Status LoadInMemory(Target &target, bool set_pc);
+
//----------------------------------------------------------------------
/// @class LookupInfo Module.h "lldb/Core/Module.h"
/// @brief A class that encapsulates name lookup information.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ModuleChild.h b/contrib/llvm/tools/lldb/include/lldb/Core/ModuleChild.h
index f47c5ca..8f2985c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ModuleChild.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ModuleChild.h
@@ -10,7 +10,7 @@
#ifndef liblldb_ModuleChild_h_
#define liblldb_ModuleChild_h_
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-forward.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ModuleList.h b/contrib/llvm/tools/lldb/include/lldb/Core/ModuleList.h
index 4aa1674..4b637c9 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ModuleList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ModuleList.h
@@ -10,18 +10,67 @@
#ifndef liblldb_ModuleList_h_
#define liblldb_ModuleList_h_
-// C Includes
-// C++ Includes
+#include "lldb/Core/Address.h" // for Address
+#include "lldb/Core/ModuleSpec.h" // for ModuleSpec
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/Utility/Iterable.h"
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+
+#include "llvm/ADT/DenseSet.h"
+
#include <functional>
#include <list>
#include <mutex>
#include <vector>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Utility/Iterable.h"
-#include "lldb/lldb-private.h"
-#include "llvm/ADT/DenseSet.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
+
+namespace lldb_private {
+class ConstString;
+}
+namespace lldb_private {
+class FileSpecList;
+}
+namespace lldb_private {
+class Function;
+}
+namespace lldb_private {
+class Log;
+}
+namespace lldb_private {
+class Module;
+}
+namespace lldb_private {
+class RegularExpression;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class SymbolContext;
+}
+namespace lldb_private {
+class SymbolContextList;
+}
+namespace lldb_private {
+class SymbolFile;
+}
+namespace lldb_private {
+class Target;
+}
+namespace lldb_private {
+class TypeList;
+}
+namespace lldb_private {
+class UUID;
+}
+namespace lldb_private {
+class VariableList;
+}
namespace lldb_private {
@@ -481,18 +530,18 @@ public:
//------------------------------------------------------------------
size_t GetSize() const;
- bool LoadScriptingResourcesInTarget(Target *target, std::list<Error> &errors,
+ bool LoadScriptingResourcesInTarget(Target *target, std::list<Status> &errors,
Stream *feedback_stream = nullptr,
bool continue_on_error = true);
static bool ModuleIsInCache(const Module *module_ptr);
- static Error GetSharedModule(const ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
- lldb::ModuleSP *old_module_sp_ptr,
- bool *did_create_ptr,
- bool always_create = false);
+ static Status GetSharedModule(const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr,
+ bool always_create = false);
static bool RemoveSharedModule(lldb::ModuleSP &module_sp);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ModuleSpec.h b/contrib/llvm/tools/lldb/include/lldb/Core/ModuleSpec.h
index 6a9e604..ce851d8 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ModuleSpec.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ModuleSpec.h
@@ -12,10 +12,10 @@
// Project includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/UUID.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Target/PathMappingList.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/UUID.h"
// Other libraries and framework includes
#include "llvm/Support/Chrono.h"
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Opcode.h b/contrib/llvm/tools/lldb/include/lldb/Core/Opcode.h
index d5376d4..3385745 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Opcode.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Opcode.h
@@ -10,20 +10,25 @@
#ifndef lldb_Opcode_h
#define lldb_Opcode_h
-// C Includes
-#include <string.h>
+#include "lldb/Utility/Endian.h"
+#include "lldb/lldb-enumerations.h" // for ByteOrder, ByteOrder::eByteOrde...
-// C++ Includes
-// Other libraries and framework includes
#include "llvm/Support/MathExtras.h"
-// Project includes
-#include "lldb/Host/Endian.h"
-#include "lldb/lldb-public.h"
+#include <assert.h> // for assert
+#include <stdint.h> // for uint32_t, uint8_t, uint16_t
+#include <string.h>
+
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Stream;
+}
namespace lldb {
class SBInstruction;
-} // namespace lldb
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/PluginManager.h b/contrib/llvm/tools/lldb/include/lldb/Core/PluginManager.h
index e0de65a..d9851e5 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/PluginManager.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/PluginManager.h
@@ -10,13 +10,28 @@
#ifndef liblldb_PluginManager_h_
#define liblldb_PluginManager_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Host/FileSpec.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-enumerations.h" // for ScriptLanguage
+#include "lldb/lldb-forward.h" // for OptionValuePropertiesSP
+#include "lldb/lldb-private-interfaces.h" // for DebuggerInitializeCallback
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
+
+namespace lldb_private {
+class CommandInterpreter;
+}
+namespace lldb_private {
+class ConstString;
+}
+namespace lldb_private {
+class Debugger;
+}
+namespace lldb_private {
+class StringList;
+}
namespace lldb_private {
class PluginManager {
@@ -187,8 +202,8 @@ public:
static ObjectFileCreateMemoryInstance
GetObjectFileCreateMemoryCallbackForPluginName(const ConstString &name);
- static Error SaveCore(const lldb::ProcessSP &process_sp,
- const FileSpec &outfile);
+ static Status SaveCore(const lldb::ProcessSP &process_sp,
+ const FileSpec &outfile);
//------------------------------------------------------------------
// ObjectContainer
@@ -210,22 +225,6 @@ public:
GetObjectContainerGetModuleSpecificationsCallbackAtIndex(uint32_t idx);
//------------------------------------------------------------------
- // LogChannel
- //------------------------------------------------------------------
- static bool RegisterPlugin(const ConstString &name, const char *description,
- LogChannelCreateInstance create_callback);
-
- static bool UnregisterPlugin(LogChannelCreateInstance create_callback);
-
- static LogChannelCreateInstance
- GetLogChannelCreateCallbackAtIndex(uint32_t idx);
-
- static LogChannelCreateInstance
- GetLogChannelCreateCallbackForPluginName(const ConstString &name);
-
- static const char *GetLogChannelCreateNameAtIndex(uint32_t idx);
-
- //------------------------------------------------------------------
// Platform
//------------------------------------------------------------------
static bool
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/RangeMap.h b/contrib/llvm/tools/lldb/include/lldb/Core/RangeMap.h
index 73a949f..e37dcd7 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/RangeMap.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/RangeMap.h
@@ -59,6 +59,18 @@ template <typename B, typename S> struct Range {
void Slide(BaseType slide) { base += slide; }
+ bool Union(const Range &rhs)
+ {
+ if (DoesAdjoinOrIntersect(rhs))
+ {
+ auto new_end = std::max<BaseType>(GetRangeEnd(), rhs.GetRangeEnd());
+ base = std::min<BaseType>(base, rhs.base);
+ size = new_end - base;
+ return true;
+ }
+ return false;
+ }
+
BaseType GetRangeEnd() const { return base + size; }
void SetRangeEnd(BaseType end) {
@@ -348,7 +360,33 @@ public:
void Append(B base, S size) { m_entries.emplace_back(base, size); }
- bool RemoveEntrtAtIndex(uint32_t idx) {
+ // Insert an item into a sorted list and optionally combine it with any
+ // adjacent blocks if requested.
+ void Insert(const Entry &entry, bool combine) {
+ if (m_entries.empty()) {
+ m_entries.push_back(entry);
+ return;
+ }
+ auto begin = m_entries.begin();
+ auto end = m_entries.end();
+ auto pos = std::lower_bound(begin, end, entry);
+ if (combine) {
+ if (pos != end && pos->Union(entry)) {
+ CombinePrevAndNext(pos);
+ return;
+ }
+ if (pos != begin) {
+ auto prev = pos - 1;
+ if (prev->Union(entry)) {
+ CombinePrevAndNext(prev);
+ return;
+ }
+ }
+ }
+ m_entries.insert(pos, entry);
+ }
+
+ bool RemoveEntryAtIndex(uint32_t idx) {
if (idx < m_entries.size()) {
m_entries.erase(m_entries.begin() + idx);
return true;
@@ -458,6 +496,7 @@ public:
// Clients must ensure that "i" is a valid index prior to calling this
// function
+ Entry &GetEntryRef(size_t i) { return m_entries[i]; }
const Entry &GetEntryRef(size_t i) const { return m_entries[i]; }
Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); }
@@ -538,6 +577,28 @@ public:
}
protected:
+
+ void CombinePrevAndNext(typename Collection::iterator pos) {
+ // Check if the prev or next entries in case they need to be unioned with
+ // the entry pointed to by "pos".
+ if (pos != m_entries.begin()) {
+ auto prev = pos - 1;
+ if (prev->Union(*pos))
+ m_entries.erase(pos);
+ pos = prev;
+ }
+
+ auto end = m_entries.end();
+ if (pos != end) {
+ auto next = pos + 1;
+ if (next != end) {
+ if (pos->Union(*next))
+ m_entries.erase(next);
+ }
+ }
+ return;
+ }
+
Collection m_entries;
};
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/RegisterValue.h b/contrib/llvm/tools/lldb/include/lldb/Core/RegisterValue.h
index 78dfbea..a45db00 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/RegisterValue.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/RegisterValue.h
@@ -10,20 +10,28 @@
#ifndef lldb_RegisterValue_h
#define lldb_RegisterValue_h
-// C Includes
-#include <string.h>
+#include "lldb/Core/Scalar.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-enumerations.h" // for ByteOrder, Format
+#include "lldb/lldb-types.h" // for offset_t
-// C++ Includes
-// Other libraries and framework includes
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/StringRef.h" // for StringRef
-// Project includes
-#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
-#include "lldb/lldb-private.h"
-#include "lldb/lldb-public.h"
+#include <stdint.h> // for uint32_t, uint8_t, uint64_t, uin...
+#include <string.h>
namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+struct RegisterInfo;
+}
+namespace lldb_private {
class RegisterValue {
public:
@@ -97,11 +105,11 @@ public:
// into "dst".
uint32_t GetAsMemoryData(const RegisterInfo *reg_info, void *dst,
uint32_t dst_len, lldb::ByteOrder dst_byte_order,
- Error &error) const;
+ Status &error) const;
uint32_t SetFromMemoryData(const RegisterInfo *reg_info, const void *src,
uint32_t src_len, lldb::ByteOrder src_byte_order,
- Error &error);
+ Status &error);
bool GetScalarValue(Scalar &scalar) const;
@@ -233,13 +241,13 @@ public:
bool SignExtend(uint32_t sign_bitpos);
- Error SetValueFromString(const RegisterInfo *reg_info,
- llvm::StringRef value_str);
- Error SetValueFromString(const RegisterInfo *reg_info,
- const char *value_str) = delete;
+ Status SetValueFromString(const RegisterInfo *reg_info,
+ llvm::StringRef value_str);
+ Status SetValueFromString(const RegisterInfo *reg_info,
+ const char *value_str) = delete;
- Error SetValueFromData(const RegisterInfo *reg_info, DataExtractor &data,
- lldb::offset_t offset, bool partial_data_ok);
+ Status SetValueFromData(const RegisterInfo *reg_info, DataExtractor &data,
+ lldb::offset_t offset, bool partial_data_ok);
// The default value of 0 for reg_name_right_align_at means no alignment at
// all.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Scalar.h b/contrib/llvm/tools/lldb/include/lldb/Core/Scalar.h
index cee2577..943398b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Scalar.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Scalar.h
@@ -10,10 +10,23 @@
#ifndef liblldb_Scalar_h_
#define liblldb_Scalar_h_
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-enumerations.h" // for Encoding, ByteOrder
+#include "lldb/lldb-private-types.h" // for type128
+
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t, int64_t
+
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Stream;
+}
+
#define NUM_OF_WORDS_INT128 2
#define BITWIDTH_INT128 128
#define NUM_OF_WORDS_INT256 4
@@ -133,7 +146,7 @@ public:
bool GetData(DataExtractor &data, size_t limit_byte_size = UINT32_MAX) const;
size_t GetAsMemoryData(void *dst, size_t dst_len,
- lldb::ByteOrder dst_byte_order, Error &error) const;
+ lldb::ByteOrder dst_byte_order, Status &error) const;
bool IsZero() const;
@@ -259,11 +272,11 @@ public:
long double LongDouble(long double fail_value = 0.0) const;
- Error SetValueFromCString(const char *s, lldb::Encoding encoding,
- size_t byte_size);
+ Status SetValueFromCString(const char *s, lldb::Encoding encoding,
+ size_t byte_size);
- Error SetValueFromData(DataExtractor &data, lldb::Encoding encoding,
- size_t byte_size);
+ Status SetValueFromData(DataExtractor &data, lldb::Encoding encoding,
+ size_t byte_size);
static bool UIntValueIsValidForSize(uint64_t uval64, size_t total_byte_size) {
if (total_byte_size > 8)
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/SearchFilter.h b/contrib/llvm/tools/lldb/include/lldb/Core/SearchFilter.h
index 6b3a79e..5861afc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/SearchFilter.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/SearchFilter.h
@@ -10,13 +10,44 @@
#ifndef liblldb_SearchFilter_h_
#define liblldb_SearchFilter_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/FileSpecList.h"
-#include "lldb/Core/StructuredData.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/StructuredData.h"
+
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/lldb-forward.h" // for SearchFilterSP, TargetSP, Modu...
+
+#include <stdint.h> // for uint32_t
+
+namespace lldb_private {
+class Address;
+}
+namespace lldb_private {
+class Breakpoint;
+}
+namespace lldb_private {
+class CompileUnit;
+}
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class Function;
+}
+namespace lldb_private {
+class ModuleList;
+}
+namespace lldb_private {
+class SearchFilter;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class SymbolContext;
+}
+namespace lldb_private {
+class Target;
+}
namespace lldb_private {
@@ -219,7 +250,7 @@ public:
static lldb::SearchFilterSP
CreateFromStructuredData(Target &target,
const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
virtual StructuredData::ObjectSP SerializeToStructuredData() {
return StructuredData::ObjectSP();
@@ -254,7 +285,7 @@ public:
static const char *FilterTyToName(enum FilterTy);
- static FilterTy NameToFilterTy(const char *name);
+ static FilterTy NameToFilterTy(llvm::StringRef name);
protected:
// Serialization of SearchFilter options:
@@ -320,7 +351,7 @@ public:
static lldb::SearchFilterSP
CreateFromStructuredData(Target &target,
const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
@@ -374,7 +405,7 @@ public:
static lldb::SearchFilterSP
CreateFromStructuredData(Target &target,
const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
@@ -431,7 +462,7 @@ public:
static lldb::SearchFilterSP
CreateFromStructuredData(Target &target,
const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
@@ -484,7 +515,7 @@ public:
static lldb::SearchFilterSP
CreateFromStructuredData(Target &target,
const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Section.h b/contrib/llvm/tools/lldb/include/lldb/Core/Section.h
index 5afaa11..0466693 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Section.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Section.h
@@ -10,16 +10,39 @@
#ifndef liblldb_Section_h_
#define liblldb_Section_h_
-#include "lldb/Core/AddressRange.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Flags.h"
#include "lldb/Core/ModuleChild.h"
-#include "lldb/Core/RangeMap.h"
-#include "lldb/Core/UserID.h"
-#include "lldb/Core/VMRange.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/lldb-private.h"
-#include <limits.h>
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Flags.h"
+#include "lldb/Utility/UserID.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for SectionType
+#include "lldb/lldb-forward.h" // for SectionSP, ModuleSP, SectionWP
+#include "lldb/lldb-types.h" // for addr_t, offset_t, user_id_t
+
+#include <memory> // for enable_shared_from_this
+#include <vector> // for vector
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, UINT32_MAX
+
+namespace lldb_private {
+class Address;
+}
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class ObjectFile;
+}
+namespace lldb_private {
+class Section;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class Target;
+}
namespace lldb_private {
@@ -120,7 +143,8 @@ public:
lldb::addr_t GetLoadBaseAddress(Target *target) const;
- bool ResolveContainedAddress(lldb::addr_t offset, Address &so_addr) const;
+ bool ResolveContainedAddress(lldb::addr_t offset, Address &so_addr,
+ bool allow_section_end = false) const;
lldb::offset_t GetFileOffset() const { return m_file_offset; }
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/SourceManager.h b/contrib/llvm/tools/lldb/include/lldb/Core/SourceManager.h
index 9ca2a32..053badf 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/SourceManager.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/SourceManager.h
@@ -10,20 +10,33 @@
#ifndef liblldb_SourceManager_h_
#define liblldb_SourceManager_h_
-// Project includes
-#include "lldb/Host/FileSpec.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-forward.h" // for DebuggerSP, DebuggerWP, DataBufferSP
-// Other libraries and framework includes
#include "llvm/Support/Chrono.h"
-// C Includes
-// C++ Includes
+#include <cstdint> // for uint32_t, UINT32_MAX
#include <map>
#include <memory>
+#include <stddef.h> // for size_t
+#include <string> // for string
#include <vector>
namespace lldb_private {
+class RegularExpression;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class SymbolContextList;
+}
+namespace lldb_private {
+class Target;
+}
+
+namespace lldb_private {
class SourceManager {
public:
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/State.h b/contrib/llvm/tools/lldb/include/lldb/Core/State.h
index a9d7692..68f0fee 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/State.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/State.h
@@ -10,11 +10,13 @@
#ifndef liblldb_State_h_
#define liblldb_State_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/lldb-private.h"
+#include "llvm/Support/FormatProviders.h"
+
+#include "lldb/lldb-enumerations.h" // for StateType
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/Support/raw_ostream.h" // for raw_ostream
+
+#include <stdint.h> // for uint32_t
namespace lldb_private {
@@ -71,4 +73,13 @@ const char *GetPermissionsAsCString(uint32_t permissions);
} // namespace lldb_private
+namespace llvm {
+template <> struct format_provider<lldb::StateType> {
+ static void format(const lldb::StateType &state, raw_ostream &Stream,
+ StringRef Style) {
+ Stream << lldb_private::StateAsCString(state);
+ }
+};
+}
+
#endif // liblldb_State_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StreamAsynchronousIO.h b/contrib/llvm/tools/lldb/include/lldb/Core/StreamAsynchronousIO.h
index b3bb49e..29b1097 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/StreamAsynchronousIO.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/StreamAsynchronousIO.h
@@ -1,5 +1,4 @@
-//===-- StreamAsynchronousIO.h -----------------------------------*- C++
-//-*-===//
+//===-- StreamAsynchronousIO.h -----------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,9 +10,15 @@
#ifndef liblldb_StreamAsynchronousIO_h_
#define liblldb_StreamAsynchronousIO_h_
+#include "lldb/Utility/Stream.h"
+
#include <string>
-#include "lldb/Core/Stream.h"
+#include <stddef.h> // for size_t
+
+namespace lldb_private {
+class Debugger;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StreamBuffer.h b/contrib/llvm/tools/lldb/include/lldb/Core/StreamBuffer.h
index 4eef19f..3b18573 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/StreamBuffer.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/StreamBuffer.h
@@ -10,7 +10,7 @@
#ifndef liblldb_StreamBuffer_h_
#define liblldb_StreamBuffer_h_
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
#include "llvm/ADT/SmallVector.h"
#include <stdio.h>
#include <string>
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StreamFile.h b/contrib/llvm/tools/lldb/include/lldb/Core/StreamFile.h
index 8b86032..a26ae84 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/StreamFile.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/StreamFile.h
@@ -10,16 +10,13 @@
#ifndef liblldb_StreamFile_h_
#define liblldb_StreamFile_h_
-// C Includes
-// C++ Includes
-
-#include <string>
-
-// Other libraries and framework includes
-// Project includes
-
-#include "lldb/Core/Stream.h"
#include "lldb/Host/File.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for FilePermissions::eFilePermission...
+
+#include <stdint.h> // for uint32_t
+#include <stdio.h> // for size_t, FILE
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StructuredDataImpl.h b/contrib/llvm/tools/lldb/include/lldb/Core/StructuredDataImpl.h
new file mode 100644
index 0000000..819d1d9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/StructuredDataImpl.h
@@ -0,0 +1,156 @@
+//===-- StructuredDataImpl.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_StructuredDataImpl_h_
+#define liblldb_StructuredDataImpl_h_
+
+#include "lldb/Core/Event.h"
+#include "lldb/Target/StructuredDataPlugin.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringRef.h"
+
+#pragma mark--
+#pragma mark StructuredDataImpl
+
+namespace lldb_private {
+
+class StructuredDataImpl {
+public:
+ StructuredDataImpl() : m_plugin_wp(), m_data_sp() {}
+
+ StructuredDataImpl(const StructuredDataImpl &rhs) = default;
+
+ StructuredDataImpl(const lldb::EventSP &event_sp)
+ : m_plugin_wp(
+ EventDataStructuredData::GetPluginFromEvent(event_sp.get())),
+ m_data_sp(EventDataStructuredData::GetObjectFromEvent(event_sp.get())) {
+ }
+
+ ~StructuredDataImpl() = default;
+
+ StructuredDataImpl &operator=(const StructuredDataImpl &rhs) = default;
+
+ bool IsValid() const { return m_data_sp.get() != nullptr; }
+
+ void Clear() {
+ m_plugin_wp.reset();
+ m_data_sp.reset();
+ }
+
+ Status GetAsJSON(Stream &stream) const {
+ Status error;
+
+ if (!m_data_sp) {
+ error.SetErrorString("No structured data.");
+ return error;
+ }
+
+ m_data_sp->Dump(stream);
+ return error;
+ }
+
+ Status GetDescription(Stream &stream) const {
+ Status error;
+
+ if (!m_data_sp) {
+ error.SetErrorString("Cannot pretty print structured data: "
+ "no data to print.");
+ return error;
+ }
+
+ // Grab the plugin.
+ auto plugin_sp = lldb::StructuredDataPluginSP(m_plugin_wp);
+ if (!plugin_sp) {
+ error.SetErrorString("Cannot pretty print structured data: "
+ "plugin doesn't exist.");
+ return error;
+ }
+
+ // Get the data's description.
+ return plugin_sp->GetDescription(m_data_sp, stream);
+ }
+
+ StructuredData::ObjectSP GetObjectSP() { return m_data_sp; }
+
+ void SetObjectSP(const StructuredData::ObjectSP &obj) { m_data_sp = obj; }
+
+ lldb::StructuredDataType GetType() const {
+ return (m_data_sp ? m_data_sp->GetType() :
+ lldb::eStructuredDataTypeInvalid);
+ }
+
+ size_t GetSize() const {
+ if (!m_data_sp)
+ return 0;
+
+ if (m_data_sp->GetType() == lldb::eStructuredDataTypeDictionary) {
+ auto dict = m_data_sp->GetAsDictionary();
+ return (dict->GetSize());
+ } else if (m_data_sp->GetType() == lldb::eStructuredDataTypeArray) {
+ auto array = m_data_sp->GetAsArray();
+ return (array->GetSize());
+ } else
+ return 0;
+ }
+
+ StructuredData::ObjectSP GetValueForKey(const char *key) const {
+ if (m_data_sp) {
+ auto dict = m_data_sp->GetAsDictionary();
+ if (dict)
+ return dict->GetValueForKey(llvm::StringRef(key));
+ }
+ return StructuredData::ObjectSP();
+ }
+
+ StructuredData::ObjectSP GetItemAtIndex(size_t idx) const {
+ if (m_data_sp) {
+ auto array = m_data_sp->GetAsArray();
+ if (array)
+ return array->GetItemAtIndex(idx);
+ }
+ return StructuredData::ObjectSP();
+ }
+
+ uint64_t GetIntegerValue(uint64_t fail_value = 0) const {
+ return (m_data_sp ? m_data_sp->GetIntegerValue(fail_value) : fail_value);
+ }
+
+ double GetFloatValue(double fail_value = 0.0) const {
+ return (m_data_sp ? m_data_sp->GetFloatValue(fail_value) : fail_value);
+ }
+
+ bool GetBooleanValue(bool fail_value = false) const {
+ return (m_data_sp ? m_data_sp->GetBooleanValue(fail_value) : fail_value);
+ }
+
+ size_t GetStringValue(char *dst, size_t dst_len) const {
+ if (!m_data_sp)
+ return 0;
+
+ llvm::StringRef result = m_data_sp->GetStringValue();
+ if (result.empty())
+ return 0;
+
+ if (!dst || !dst_len) {
+ char s[1];
+ return (::snprintf(s, 1, "%s", result.data()));
+ }
+ return (::snprintf(dst, dst_len, "%s", result.data()));
+ }
+
+private:
+ lldb::StructuredDataPluginWP m_plugin_wp;
+ StructuredData::ObjectSP m_data_sp;
+};
+} // namespace lldb_private
+#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/UniqueCStringMap.h b/contrib/llvm/tools/lldb/include/lldb/Core/UniqueCStringMap.h
index 77a350a..e8c6c7c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/UniqueCStringMap.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/UniqueCStringMap.h
@@ -17,7 +17,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/RegularExpression.h"
namespace lldb_private {
@@ -35,13 +36,17 @@ public:
struct Entry {
Entry() {}
- Entry(llvm::StringRef cstr) : cstring(cstr), value() {}
+ Entry(ConstString cstr) : cstring(cstr), value() {}
- Entry(llvm::StringRef cstr, const T &v) : cstring(cstr), value(v) {}
+ Entry(ConstString cstr, const T &v) : cstring(cstr), value(v) {}
- bool operator<(const Entry &rhs) const { return cstring < rhs.cstring; }
+ // This is only for uniqueness, not lexicographical ordering, so we can
+ // just compare pointers.
+ bool operator<(const Entry &rhs) const {
+ return cstring.GetCString() < rhs.cstring.GetCString();
+ }
- llvm::StringRef cstring;
+ ConstString cstring;
T value;
};
@@ -50,7 +55,7 @@ public:
// this map, then later call UniqueCStringMap<T>::Sort() before doing
// any searches by name.
//------------------------------------------------------------------
- void Append(llvm::StringRef unique_cstr, const T &value) {
+ void Append(ConstString unique_cstr, const T &value) {
m_map.push_back(typename UniqueCStringMap<T>::Entry(unique_cstr, value));
}
@@ -62,7 +67,7 @@ public:
// Call this function to always keep the map sorted when putting
// entries into the map.
//------------------------------------------------------------------
- void Insert(llvm::StringRef unique_cstr, const T &value) {
+ void Insert(ConstString unique_cstr, const T &value) {
typename UniqueCStringMap<T>::Entry e(unique_cstr, value);
m_map.insert(std::upper_bound(m_map.begin(), m_map.end(), e), e);
}
@@ -85,7 +90,7 @@ public:
return false;
}
- llvm::StringRef GetCStringAtIndexUnchecked(uint32_t idx) const {
+ ConstString GetCStringAtIndexUnchecked(uint32_t idx) const {
return m_map[idx].cstring;
}
@@ -99,8 +104,8 @@ public:
return m_map[idx].value;
}
- llvm::StringRef GetCStringAtIndex(uint32_t idx) const {
- return ((idx < m_map.size()) ? m_map[idx].cstring : llvm::StringRef());
+ ConstString GetCStringAtIndex(uint32_t idx) const {
+ return ((idx < m_map.size()) ? m_map[idx].cstring : ConstString());
}
//------------------------------------------------------------------
@@ -111,7 +116,7 @@ public:
// T values and only if there is a sensible failure value that can
// be returned and that won't match any existing values.
//------------------------------------------------------------------
- T Find(llvm::StringRef unique_cstr, T fail_value) const {
+ T Find(ConstString unique_cstr, T fail_value) const {
Entry search_entry(unique_cstr);
const_iterator end = m_map.end();
const_iterator pos = std::lower_bound(m_map.begin(), end, search_entry);
@@ -129,15 +134,12 @@ public:
// The caller is responsible for ensuring that the collection does
// not change during while using the returned pointer.
//------------------------------------------------------------------
- const Entry *FindFirstValueForName(llvm::StringRef unique_cstr) const {
+ const Entry *FindFirstValueForName(ConstString unique_cstr) const {
Entry search_entry(unique_cstr);
const_iterator end = m_map.end();
const_iterator pos = std::lower_bound(m_map.begin(), end, search_entry);
- if (pos != end) {
- llvm::StringRef pos_cstr = pos->cstring;
- if (pos_cstr == unique_cstr)
- return &(*pos);
- }
+ if (pos != end && pos->cstring == unique_cstr)
+ return &(*pos);
return nullptr;
}
@@ -162,7 +164,7 @@ public:
return nullptr;
}
- size_t GetValues(llvm::StringRef unique_cstr, std::vector<T> &values) const {
+ size_t GetValues(ConstString unique_cstr, std::vector<T> &values) const {
const size_t start_size = values.size();
Entry search_entry(unique_cstr);
@@ -184,7 +186,7 @@ public:
const_iterator pos, end = m_map.end();
for (pos = m_map.begin(); pos != end; ++pos) {
- if (regex.Execute(pos->cstring))
+ if (regex.Execute(pos->cstring.GetCString()))
values.push_back(pos->value);
}
@@ -238,7 +240,7 @@ public:
}
}
- size_t Erase(llvm::StringRef unique_cstr) {
+ size_t Erase(ConstString unique_cstr) {
size_t num_removed = 0;
Entry search_entry(unique_cstr);
iterator end = m_map.end();
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/UserSettingsController.h b/contrib/llvm/tools/lldb/include/lldb/Core/UserSettingsController.h
index a30dfd4..67bc9b2 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/UserSettingsController.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/UserSettingsController.h
@@ -10,21 +10,32 @@
#ifndef liblldb_UserSettingsController_h_
#define liblldb_UserSettingsController_h_
-// C Includes
-// C++ Includes
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-forward.h" // for OptionValuePropertiesSP
+#include "lldb/lldb-private-enumerations.h" // for VarSetOperationType
+
+#include "llvm/ADT/StringRef.h" // for StringRef
-#include <string>
#include <vector>
-// Other libraries and framework includes
-// Project includes
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/StringList.h"
-#include "lldb/Interpreter/OptionValue.h"
-#include "lldb/lldb-private.h"
+namespace lldb_private {
+class CommandInterpreter;
+}
+namespace lldb_private {
+class ConstString;
+}
+namespace lldb_private {
+class ExecutionContext;
+}
+namespace lldb_private {
+class Property;
+}
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
@@ -46,15 +57,16 @@ public:
virtual lldb::OptionValueSP GetPropertyValue(const ExecutionContext *exe_ctx,
llvm::StringRef property_path,
bool will_modify,
- Error &error) const;
+ Status &error) const;
- virtual Error SetPropertyValue(const ExecutionContext *exe_ctx,
- VarSetOperationType op,
- llvm::StringRef property_path, llvm::StringRef value);
+ virtual Status SetPropertyValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ llvm::StringRef property_path,
+ llvm::StringRef value);
- virtual Error DumpPropertyValue(const ExecutionContext *exe_ctx, Stream &strm,
- llvm::StringRef property_path,
- uint32_t dump_mask);
+ virtual Status DumpPropertyValue(const ExecutionContext *exe_ctx,
+ Stream &strm, llvm::StringRef property_path,
+ uint32_t dump_mask);
virtual void DumpAllPropertyValues(const ExecutionContext *exe_ctx,
Stream &strm, uint32_t dump_mask);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Value.h b/contrib/llvm/tools/lldb/include/lldb/Core/Value.h
index 2800c4f..678b56f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Value.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/Value.h
@@ -10,17 +10,39 @@
#ifndef liblldb_Value_h_
#define liblldb_Value_h_
-// C Includes
-// C++ Includes
-#include <vector>
-
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Symbol/CompilerType.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-enumerations.h" // for ByteOrder, ByteOrder::eB...
+#include "lldb/lldb-private-enumerations.h" // for AddressType
+#include "lldb/lldb-private-types.h" // for type128, RegisterInfo
+
+#include "llvm/ADT/APInt.h" // for APInt
+
+#include <vector>
+
+#include <stdint.h> // for uint8_t, uint32_t, uint64_t
+#include <string.h> // for size_t, memcpy
+
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class ExecutionContext;
+}
+namespace lldb_private {
+class Module;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class Type;
+}
+namespace lldb_private {
+class Variable;
+}
namespace lldb_private {
@@ -197,11 +219,11 @@ public:
lldb::Format GetValueDefaultFormat();
- uint64_t GetValueByteSize(Error *error_ptr, ExecutionContext *exe_ctx);
+ uint64_t GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx);
- Error GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
- uint32_t data_offset,
- Module *module); // Can be nullptr
+ Status GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
+ uint32_t data_offset,
+ Module *module); // Can be nullptr
static const char *GetValueTypeAsCString(ValueType context_type);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObject.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObject.h
index 84b187e..fa1d148 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObject.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObject.h
@@ -10,32 +10,67 @@
#ifndef liblldb_ValueObject_h_
#define liblldb_ValueObject_h_
-// C Includes
-// C++ Includes
-#include <functional>
-#include <initializer_list>
-#include <map>
-#include <vector>
-
-// Other libraries and framework includes
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallVector.h"
-
-// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Flags.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Core/Value.h"
+#include "lldb/DataFormatters/DumpValueObjectOptions.h" // for DumpValueObj...
#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Symbol/Type.h" // for TypeImpl
#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/Process.h"
-#include "lldb/Target/StackID.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/SharedCluster.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/UserID.h"
+#include "lldb/lldb-defines.h" // for LLDB_INVALID...
+#include "lldb/lldb-enumerations.h" // for DynamicValue...
+#include "lldb/lldb-forward.h" // for ValueObjectSP
+#include "lldb/lldb-private-enumerations.h" // for AddressType
+#include "lldb/lldb-types.h" // for addr_t, offs...
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <functional>
+#include <initializer_list>
+#include <map>
+#include <mutex> // for recursive_mutex
+#include <string> // for string
+#include <utility> // for pair
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
+namespace lldb_private {
+class Declaration;
+}
+namespace lldb_private {
+class EvaluateExpressionOptions;
+}
+namespace lldb_private {
+class ExecutionContextScope;
+}
+namespace lldb_private {
+class Log;
+}
+namespace lldb_private {
+class Scalar;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class SymbolContextScope;
+}
+namespace lldb_private {
+class TypeFormatImpl;
+}
+namespace lldb_private {
+class TypeSummaryImpl;
+}
+namespace lldb_private {
+class TypeSummaryOptions;
+}
namespace lldb_private {
/// ValueObject:
@@ -427,7 +462,7 @@ public:
virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr);
- virtual bool SetValueFromCString(const char *value_str, Error &error);
+ virtual bool SetValueFromCString(const char *value_str, Status &error);
// Return the module associated with this value object in case the
// value is from an executable file and might have its data in
@@ -447,42 +482,26 @@ public:
//------------------------------------------------------------------
// The functions below should NOT be modified by subclasses
//------------------------------------------------------------------
- const Error &GetError();
+ const Status &GetError();
const ConstString &GetName() const;
virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx, bool can_create);
// this will always create the children if necessary
- lldb::ValueObjectSP
- GetChildAtIndexPath(const std::initializer_list<size_t> &idxs,
- size_t *index_of_error = nullptr);
-
- lldb::ValueObjectSP GetChildAtIndexPath(const std::vector<size_t> &idxs,
+ lldb::ValueObjectSP GetChildAtIndexPath(llvm::ArrayRef<size_t> idxs,
size_t *index_of_error = nullptr);
- lldb::ValueObjectSP GetChildAtIndexPath(
- const std::initializer_list<std::pair<size_t, bool>> &idxs,
- size_t *index_of_error = nullptr);
-
lldb::ValueObjectSP
- GetChildAtIndexPath(const std::vector<std::pair<size_t, bool>> &idxs,
+ GetChildAtIndexPath(llvm::ArrayRef<std::pair<size_t, bool>> idxs,
size_t *index_of_error = nullptr);
// this will always create the children if necessary
- lldb::ValueObjectSP
- GetChildAtNamePath(const std::initializer_list<ConstString> &names,
- ConstString *name_of_error = nullptr);
-
- lldb::ValueObjectSP GetChildAtNamePath(const std::vector<ConstString> &names,
+ lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef<ConstString> names,
ConstString *name_of_error = nullptr);
- lldb::ValueObjectSP GetChildAtNamePath(
- const std::initializer_list<std::pair<ConstString, bool>> &names,
- ConstString *name_of_error = nullptr);
-
lldb::ValueObjectSP
- GetChildAtNamePath(const std::vector<std::pair<ConstString, bool>> &names,
+ GetChildAtNamePath(llvm::ArrayRef<std::pair<ConstString, bool>> names,
ConstString *name_of_error = nullptr);
virtual lldb::ValueObjectSP GetChildMemberWithName(const ConstString &name,
@@ -501,7 +520,7 @@ public:
// return 'false' whenever you set the error, otherwise
// callers may assume true means everything is OK - this will
// break breakpoint conditions among potentially a few others
- virtual bool IsLogicalTrue(Error &error);
+ virtual bool IsLogicalTrue(Status &error);
virtual const char *GetLocationAsCString();
@@ -552,6 +571,9 @@ public:
lldb::ValueObjectSP GetSP() { return m_manager->GetSharedPointer(this); }
+ // Change the name of the current ValueObject. Should *not* be used from a
+ // synthetic child provider as it would change the name of the non synthetic
+ // child as well.
void SetName(const ConstString &name);
virtual lldb::addr_t GetAddressOf(bool scalar_is_load_address = true,
@@ -598,9 +620,15 @@ public:
virtual lldb::ValueObjectSP CreateConstantValue(const ConstString &name);
- virtual lldb::ValueObjectSP Dereference(Error &error);
+ virtual lldb::ValueObjectSP Dereference(Status &error);
+
+ // Creates a copy of the ValueObject with a new name and setting the current
+ // ValueObject as its parent. It should be used when we want to change the
+ // name of a ValueObject without modifying the actual ValueObject itself
+ // (e.g. sythetic child provider).
+ virtual lldb::ValueObjectSP Clone(const ConstString &new_name);
- virtual lldb::ValueObjectSP AddressOf(Error &error);
+ virtual lldb::ValueObjectSP AddressOf(Status &error);
virtual lldb::addr_t GetLiveAddress() { return LLDB_INVALID_ADDRESS; }
@@ -672,16 +700,16 @@ public:
bool IsCStringContainer(bool check_pointer = false);
std::pair<size_t, bool>
- ReadPointedString(lldb::DataBufferSP &buffer_sp, Error &error,
+ ReadPointedString(lldb::DataBufferSP &buffer_sp, Status &error,
uint32_t max_length = 0, bool honor_array = true,
lldb::Format item_format = lldb::eFormatCharArray);
virtual size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0,
uint32_t item_count = 1);
- virtual uint64_t GetData(DataExtractor &data, Error &error);
+ virtual uint64_t GetData(DataExtractor &data, Status &error);
- virtual bool SetData(DataExtractor &data, Error &error);
+ virtual bool SetData(DataExtractor &data, Status &error);
virtual bool GetIsConstant() const { return m_update_point.IsConstant(); }
@@ -852,8 +880,9 @@ protected:
DataExtractor
m_data; // A data extractor that can be used to extract the value.
Value m_value;
- Error m_error; // An error object that can describe any errors that occur when
- // updating values.
+ Status
+ m_error; // An error object that can describe any errors that occur when
+ // updating values.
std::string m_value_str; // Cached value string that will get cleared if/when
// the value is updated.
std::string m_old_value_str; // Cached old value string from the last time the
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectCast.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectCast.h
index 50959b9..aaa1ecb 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectCast.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectCast.h
@@ -10,11 +10,18 @@
#ifndef liblldb_ValueObjectCast_h_
#define liblldb_ValueObjectCast_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for ValueType
+#include "lldb/lldb-forward.h" // for ValueObjectSP
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+
+namespace lldb_private {
+class ConstString;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectChild.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectChild.h
index b84cb3d..ec8c9e8 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectChild.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectChild.h
@@ -10,14 +10,20 @@
#ifndef liblldb_ValueObjectChild_h_
#define liblldb_ValueObjectChild_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for ValueType
+#include "lldb/lldb-private-enumerations.h" // for LazyBool, AddressType
+#include "lldb/lldb-types.h" // for offset_t
+
#include "llvm/ADT/Optional.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t, int32_t
+
namespace lldb_private {
//----------------------------------------------------------------------
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResult.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResult.h
index 994ac47..1f56129 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResult.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResult.h
@@ -10,15 +10,31 @@
#ifndef liblldb_ValueObjectConstResult_h_
#define liblldb_ValueObjectConstResult_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
+#include "lldb/Core/Value.h" // for Value
#include "lldb/Core/ValueObject.h"
-
#include "lldb/Core/ValueObjectConstResultImpl.h"
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-enumerations.h" // for ByteOrder, Dynamic...
+#include "lldb/lldb-forward.h" // for ValueObjectSP, Dat...
+#include "lldb/lldb-private-enumerations.h" // for AddressType, Addre...
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class ExecutionContextScope;
+}
+namespace lldb_private {
+class Module;
+}
+namespace lldb_private {
//----------------------------------------------------------------------
// A frozen ValueObject copied into host memory
@@ -53,7 +69,7 @@ public:
// When an expression fails to evaluate, we return an error
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope,
- const Error &error);
+ const Status &error);
uint64_t GetByteSize() override;
@@ -69,7 +85,7 @@ public:
void SetByteSize(size_t size);
- lldb::ValueObjectSP Dereference(Error &error) override;
+ lldb::ValueObjectSP Dereference(Status &error) override;
ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member,
int32_t synthetic_index) override;
@@ -78,7 +94,7 @@ public:
uint32_t offset, const CompilerType &type, bool can_create,
ConstString name_const_str = ConstString()) override;
- lldb::ValueObjectSP AddressOf(Error &error) override;
+ lldb::ValueObjectSP AddressOf(Status &error) override;
lldb::addr_t GetAddressOf(bool scalar_is_load_address = true,
AddressType *address_type = nullptr) override;
@@ -137,7 +153,7 @@ private:
ValueObjectConstResult(ExecutionContextScope *exe_scope, const Value &value,
const ConstString &name, Module *module = nullptr);
- ValueObjectConstResult(ExecutionContextScope *exe_scope, const Error &error);
+ ValueObjectConstResult(ExecutionContextScope *exe_scope, const Status &error);
DISALLOW_COPY_AND_ASSIGN(ValueObjectConstResult);
};
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultCast.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultCast.h
index 4b2a3e2..442cce4 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultCast.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultCast.h
@@ -10,12 +10,26 @@
#ifndef liblldb_ValueObjectConstResultCast_h_
#define liblldb_ValueObjectConstResultCast_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/ValueObjectCast.h"
#include "lldb/Core/ValueObjectConstResultImpl.h"
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_...
+#include "lldb/lldb-forward.h" // for ValueObjectSP
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, int32_t
+
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class ValueObject;
+}
namespace lldb_private {
@@ -27,7 +41,7 @@ public:
~ValueObjectConstResultCast() override;
- lldb::ValueObjectSP Dereference(Error &error) override;
+ lldb::ValueObjectSP Dereference(Status &error) override;
ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member,
int32_t synthetic_index) override;
@@ -40,7 +54,7 @@ public:
uint32_t offset, const CompilerType &type, bool can_create,
ConstString name_const_str = ConstString()) override;
- lldb::ValueObjectSP AddressOf(Error &error) override;
+ lldb::ValueObjectSP AddressOf(Status &error) override;
size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0,
uint32_t item_count = 1) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultChild.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultChild.h
index 66127b9..a74da00 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultChild.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultChild.h
@@ -1,5 +1,4 @@
-//===-- ValueObjectConstResultChild.h -------------------------------*- C++
-//-*-===//
+//===-- ValueObjectConstResultChild.h ----------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,12 +10,25 @@
#ifndef liblldb_ValueObjectConstResultChild_h_
#define liblldb_ValueObjectConstResultChild_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/ValueObjectChild.h"
#include "lldb/Core/ValueObjectConstResultImpl.h"
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_...
+#include "lldb/lldb-forward.h" // for ValueObjectSP
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, int32_t
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class ValueObject;
+}
namespace lldb_private {
@@ -36,7 +48,7 @@ public:
~ValueObjectConstResultChild() override;
- lldb::ValueObjectSP Dereference(Error &error) override;
+ lldb::ValueObjectSP Dereference(Status &error) override;
ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member,
int32_t synthetic_index) override;
@@ -49,7 +61,7 @@ public:
uint32_t offset, const CompilerType &type, bool can_create,
ConstString name_const_str = ConstString()) override;
- lldb::ValueObjectSP AddressOf(Error &error) override;
+ lldb::ValueObjectSP AddressOf(Status &error) override;
size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0,
uint32_t item_count = 1) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultImpl.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultImpl.h
index c26bf41..d86f25e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultImpl.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectConstResultImpl.h
@@ -10,11 +10,26 @@
#ifndef liblldb_ValueObjectConstResultImpl_h_
#define liblldb_ValueObjectConstResultImpl_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/ValueObject.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-forward.h" // for ValueObjectSP
+#include "lldb/lldb-private-enumerations.h" // for AddressType, AddressType...
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, int32_t
+namespace lldb_private {
+class CompilerType;
+}
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class ValueObject;
+}
namespace lldb_private {
@@ -30,7 +45,7 @@ public:
virtual ~ValueObjectConstResultImpl() = default;
- lldb::ValueObjectSP Dereference(Error &error);
+ lldb::ValueObjectSP Dereference(Status &error);
ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member,
int32_t synthetic_index);
@@ -40,7 +55,7 @@ public:
bool can_create,
ConstString name_const_str = ConstString());
- lldb::ValueObjectSP AddressOf(Error &error);
+ lldb::ValueObjectSP AddressOf(Status &error);
lldb::addr_t GetLiveAddress() { return m_live_address; }
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectDynamicValue.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectDynamicValue.h
index e58e74f..018ee2c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectDynamicValue.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectDynamicValue.h
@@ -10,13 +10,30 @@
#ifndef liblldb_ValueObjectDynamicValue_h_
#define liblldb_ValueObjectDynamicValue_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
+#include "lldb/Core/Address.h" // for Address
#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
#include "lldb/Symbol/Type.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/SharingPtr.h" // for operator==
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for DynamicValueType, Langua...
+#include "lldb/lldb-forward.h" // for ValueObjectSP, VariableSP
+#include "lldb/lldb-private-enumerations.h" // for LazyBool, LazyBool::eLaz...
+#include <assert.h> // for assert
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint64_t, uint32_t
+
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Declaration;
+}
+namespace lldb_private {
+class Status;
+}
namespace lldb_private {
//----------------------------------------------------------------------
@@ -69,9 +86,9 @@ public:
m_owning_valobj_sp = owning_sp;
}
- bool SetValueFromCString(const char *value_str, Error &error) override;
+ bool SetValueFromCString(const char *value_str, Status &error) override;
- bool SetData(DataExtractor &data, Error &error) override;
+ bool SetData(DataExtractor &data, Status &error) override;
TypeImpl GetTypeImpl() override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectList.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectList.h
index c5427c6..a0d2e68 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectList.h
@@ -10,15 +10,16 @@
#ifndef liblldb_ValueObjectList_h_
#define liblldb_ValueObjectList_h_
-// C Includes
-// C++ Includes
+#include "lldb/lldb-forward.h" // for ValueObjectSP
+#include "lldb/lldb-types.h" // for user_id_t
+
#include <vector>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/UserID.h"
-#include "lldb/Target/ExecutionContextScope.h"
-#include "lldb/lldb-private.h"
+#include <stddef.h> // for size_t
+
+namespace lldb_private {
+class ValueObject;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectMemory.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectMemory.h
index f9891c4..8bb649c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectMemory.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectMemory.h
@@ -10,12 +10,21 @@
#ifndef liblldb_ValueObjectMemory_h_
#define liblldb_ValueObjectMemory_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
+#include "lldb/Core/Address.h" // for Address
#include "lldb/Core/ValueObject.h"
#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for ValueType
+#include "lldb/lldb-forward.h" // for TypeSP, ValueObjectSP, ModuleSP
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+
+namespace lldb_private {
+class ExecutionContextScope;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectRegister.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectRegister.h
index 11d2054..2aaef9b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectRegister.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectRegister.h
@@ -10,13 +10,33 @@
#ifndef liblldb_ValueObjectRegister_h_
#define liblldb_ValueObjectRegister_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/ValueObject.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for ValueType, ValueType::eValueTy...
+#include "lldb/lldb-forward.h" // for RegisterContextSP, ValueObjectSP
+#include "lldb/lldb-private-types.h" // for RegisterInfo, RegisterSet (ptr...
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t, int32_t
+
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class ExecutionContextScope;
+}
+namespace lldb_private {
+class Scalar;
+}
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
@@ -128,9 +148,9 @@ public:
size_t CalculateNumChildren(uint32_t max) override;
- bool SetValueFromCString(const char *value_str, Error &error) override;
+ bool SetValueFromCString(const char *value_str, Status &error) override;
- bool SetData(DataExtractor &data, Error &error) override;
+ bool SetData(DataExtractor &data, Status &error) override;
bool ResolveValue(Scalar &scalar) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
index 0a5a4d9..e32e140 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
@@ -10,17 +10,31 @@
#ifndef liblldb_ValueObjectSyntheticFilter_h_
#define liblldb_ValueObjectSyntheticFilter_h_
-// C Includes
-// C++ Includes
-#include <memory>
-
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/ThreadSafeSTLMap.h"
#include "lldb/Core/ThreadSafeSTLVector.h"
#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/lldb-defines.h" // for ThreadSafeSTLMap::operator=
+#include "lldb/lldb-enumerations.h" // for DynamicValueType, Langua...
+#include "lldb/lldb-forward.h" // for ValueObjectSP, Synthetic...
+#include "lldb/lldb-private-enumerations.h" // for LazyBool, LazyBool::eLaz...
+
+#include <cstdint> // for uint32_t, uint64_t
+#include <memory>
+
+#include <stddef.h> // for size_t
namespace lldb_private {
+class Declaration;
+}
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class SyntheticChildrenFrontEnd;
+}
+namespace lldb_private {
//----------------------------------------------------------------------
// A ValueObject that obtains its children from some source other than
@@ -96,7 +110,7 @@ public:
bool GetIsConstant() const override { return false; }
- bool SetValueFromCString(const char *value_str, Error &error) override;
+ bool SetValueFromCString(const char *value_str, Status &error) override;
void SetFormat(lldb::Format format) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectVariable.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectVariable.h
index b76c48a..9dd140a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectVariable.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectVariable.h
@@ -10,12 +10,34 @@
#ifndef liblldb_ValueObjectVariable_h_
#define liblldb_ValueObjectVariable_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/Value.h" // for Value
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for ValueType
+#include "lldb/lldb-forward.h" // for VariableSP, ModuleSP, ValueObj...
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Declaration;
+}
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class ExecutionContextScope;
+}
+namespace lldb_private {
+class SymbolContextScope;
+}
+
namespace lldb_private {
//----------------------------------------------------------------------
@@ -51,9 +73,9 @@ public:
const char *GetLocationAsCString() override;
- bool SetValueFromCString(const char *value_str, Error &error) override;
+ bool SetValueFromCString(const char *value_str, Status &error) override;
- bool SetData(DataExtractor &data, Error &error) override;
+ bool SetData(DataExtractor &data, Status &error) override;
virtual lldb::VariableSP GetVariable() override { return m_variable_sp; }
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/dwarf.h b/contrib/llvm/tools/lldb/include/lldb/Core/dwarf.h
index 4a935d5..651a2bc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/dwarf.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Core/dwarf.h
@@ -13,7 +13,7 @@
#include <stdint.h>
// Get the DWARF constant definitions from llvm
-#include "llvm/Support/Dwarf.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "lldb/Core/RangeMap.h"
diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/DataVisualization.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/DataVisualization.h
index 7a632d6..343099b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/DataVisualization.h
+++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/DataVisualization.h
@@ -15,9 +15,9 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/DataFormatters/FormatClasses.h"
#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
index b510a3c..00baea7 100644
--- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
+++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
@@ -27,7 +27,7 @@ namespace lldb_private {
class DumpValueObjectOptions {
public:
struct PointerDepth {
- enum class Mode { Always, Formatters, Default, Never } m_mode;
+ enum class Mode { Always, Default, Never } m_mode;
uint32_t m_count;
PointerDepth operator--() const {
@@ -37,9 +37,6 @@ public:
}
bool CanAllowExpansion() const;
-
- bool CanAllowExpansion(bool is_root, TypeSummaryImpl *entry,
- ValueObject *valobj, const std::string &summary);
};
struct PointerAsArraySettings {
diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatCache.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatCache.h
index ab369a1..9901ec9 100644
--- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatCache.h
+++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatCache.h
@@ -18,7 +18,7 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-public.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormattersContainer.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormattersContainer.h
index e432099..2df5bf4 100644
--- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormattersContainer.h
+++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormattersContainer.h
@@ -22,7 +22,6 @@
// Project includes
#include "lldb/lldb-public.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormatClasses.h"
#include "lldb/DataFormatters/TypeFormat.h"
@@ -30,6 +29,7 @@
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/DataFormatters/TypeValidator.h"
#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/StringLexer.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/StringPrinter.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/StringPrinter.h
index 4332946..8d4a099 100644
--- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/StringPrinter.h
+++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/StringPrinter.h
@@ -19,7 +19,7 @@
// Project includes
#include "lldb/lldb-forward.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/DataExtractor.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSummary.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSummary.h
index 7b2feeb..1bde565 100644
--- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSummary.h
+++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSummary.h
@@ -23,9 +23,9 @@
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-public.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/FormatEntity.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StructuredData.h"
namespace lldb_private {
class TypeSummaryOptions {
@@ -286,7 +286,7 @@ private:
struct StringSummaryFormat : public TypeSummaryImpl {
std::string m_format_str;
FormatEntity::Entry m_format;
- Error m_error;
+ Status m_error;
StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f);
diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSynthetic.h
index 6f5a8df..59fb6d3 100644
--- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSynthetic.h
+++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSynthetic.h
@@ -25,8 +25,8 @@
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-public.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ValueObject.h"
+#include "lldb/Utility/StructuredData.h"
namespace lldb_private {
class SyntheticChildrenFrontEnd {
diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
index f0d09ac..4185143 100644
--- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
+++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
@@ -19,7 +19,8 @@
#include "lldb/lldb-private.h"
#include "lldb/lldb-public.h"
-#include "lldb/Core/Flags.h"
+#include "lldb/Utility/Flags.h"
+
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
#include "lldb/Symbol/CompilerType.h"
diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/VectorIterator.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/VectorIterator.h
index 38bcfe9..fcf5aba 100644
--- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/VectorIterator.h
+++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/VectorIterator.h
@@ -13,8 +13,8 @@
#include "lldb/lldb-forward.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/DWARFExpression.h b/contrib/llvm/tools/lldb/include/lldb/Expression/DWARFExpression.h
index ea3f5cc..1816c3b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/DWARFExpression.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/DWARFExpression.h
@@ -11,10 +11,10 @@
#define liblldb_DWARFExpression_h_
#include "lldb/Core/Address.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/Scalar.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-private.h"
#include <functional>
@@ -266,7 +266,7 @@ public:
ClangExpressionDeclMap *decl_map,
lldb::addr_t loclist_base_load_addr,
const Value *initial_value_ptr, const Value *object_address_ptr,
- Value &result, Error *error_ptr) const;
+ Value &result, Status *error_ptr) const;
//------------------------------------------------------------------
/// Wrapper for the static evaluate function that uses member
@@ -277,7 +277,7 @@ public:
ClangExpressionDeclMap *decl_map, RegisterContext *reg_ctx,
lldb::addr_t loclist_base_load_addr,
const Value *initial_value_ptr, const Value *object_address_ptr,
- Value &result, Error *error_ptr) const;
+ Value &result, Status *error_ptr) const;
//------------------------------------------------------------------
/// Evaluate a DWARF location expression in a particular context
@@ -345,7 +345,7 @@ public:
DWARFCompileUnit *dwarf_cu, const lldb::offset_t offset,
const lldb::offset_t length, const lldb::RegisterKind reg_set,
const Value *initial_value_ptr, const Value *object_address_ptr,
- Value &result, Error *error_ptr);
+ Value &result, Status *error_ptr);
//------------------------------------------------------------------
/// Loads a ClangExpressionVariableList into the object
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/DiagnosticManager.h b/contrib/llvm/tools/lldb/include/lldb/Expression/DiagnosticManager.h
index d9024e6..83e67df 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/DiagnosticManager.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/DiagnosticManager.h
@@ -128,6 +128,8 @@ public:
m_diagnostics.push_back(diagnostic);
}
+ void CopyDiagnostics(DiagnosticManager &otherDiagnostics);
+
size_t Printf(DiagnosticSeverity severity, const char *format, ...)
__attribute__((format(printf, 3, 4)));
size_t PutString(DiagnosticSeverity severity, llvm::StringRef str);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/Expression.h b/contrib/llvm/tools/lldb/include/lldb/Expression/Expression.h
index f48a799..860444e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/Expression.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/Expression.h
@@ -99,6 +99,16 @@ public:
//------------------------------------------------------------------
lldb::addr_t StartAddress() { return m_jit_start_addr; }
+ //------------------------------------------------------------------
+ /// Called to notify the expression that it is about to be executed.
+ //------------------------------------------------------------------
+ virtual void WillStartExecuting() {}
+
+ //------------------------------------------------------------------
+ /// Called to notify the expression that its execution has finished.
+ //------------------------------------------------------------------
+ virtual void DidFinishExecuting() {}
+
virtual ExpressionTypeSystemHelper *GetTypeSystemHelper() { return nullptr; }
protected:
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionParser.h b/contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionParser.h
index 99f583d..19526d2 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionParser.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionParser.h
@@ -10,7 +10,7 @@
#ifndef liblldb_ExpressionParser_h_
#define liblldb_ExpressionParser_h_
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-public.h"
namespace lldb_private {
@@ -108,7 +108,7 @@ public:
/// An error code indicating the success or failure of the operation.
/// Test with Success().
//------------------------------------------------------------------
- virtual Error
+ virtual Status
PrepareForExecution(lldb::addr_t &func_addr, lldb::addr_t &func_end,
std::shared_ptr<IRExecutionUnit> &execution_unit_sp,
ExecutionContext &exe_ctx, bool &can_interpret,
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionVariable.h b/contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionVariable.h
index 3f6b020..c757093 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionVariable.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/ExpressionVariable.h
@@ -19,8 +19,8 @@
#include "llvm/ADT/DenseMap.h"
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/ValueObject.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-public.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/IRExecutionUnit.h b/contrib/llvm/tools/lldb/include/lldb/Expression/IRExecutionUnit.h
index 72c1775..b0b4d7a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/IRExecutionUnit.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/IRExecutionUnit.h
@@ -22,10 +22,10 @@
#include "llvm/IR/Module.h"
// Project includes
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Expression/IRMemoryMap.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private.h"
@@ -39,7 +39,7 @@ class ObjectCache;
namespace lldb_private {
-class Error;
+class Status;
//----------------------------------------------------------------------
/// @class IRExecutionUnit IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h"
@@ -86,7 +86,7 @@ public:
: nullptr);
}
- void GetRunnableInfo(Error &error, lldb::addr_t &func_addr,
+ void GetRunnableInfo(Status &error, lldb::addr_t &func_addr,
lldb::addr_t &func_end);
//------------------------------------------------------------------
@@ -95,7 +95,7 @@ public:
/// IRExecutionUnit unless the client explicitly chooses to free it.
//------------------------------------------------------------------
- lldb::addr_t WriteNow(const uint8_t *bytes, size_t size, Error &error);
+ lldb::addr_t WriteNow(const uint8_t *bytes, size_t size, Status &error);
void FreeNow(lldb::addr_t allocation);
@@ -240,7 +240,7 @@ private:
//------------------------------------------------------------------
bool WriteData(lldb::ProcessSP &process_sp);
- Error DisassembleFunction(Stream &stream, lldb::ProcessSP &process_sp);
+ Status DisassembleFunction(Stream &stream, lldb::ProcessSP &process_sp);
struct SearchSpec;
@@ -391,7 +391,7 @@ private:
void dump(Log *log);
};
- bool CommitOneAllocation(lldb::ProcessSP &process_sp, Error &error,
+ bool CommitOneAllocation(lldb::ProcessSP &process_sp, Status &error,
AllocationRecord &record);
typedef std::vector<AllocationRecord> RecordVector;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/IRInterpreter.h b/contrib/llvm/tools/lldb/include/lldb/Expression/IRInterpreter.h
index b821e67..36e03c6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/IRInterpreter.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/IRInterpreter.h
@@ -10,8 +10,8 @@
#ifndef liblldb_IRInterpreter_h_
#define liblldb_IRInterpreter_h_
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/lldb-public.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Pass.h"
@@ -39,20 +39,20 @@ class IRMemoryMap;
class IRInterpreter {
public:
static bool CanInterpret(llvm::Module &module, llvm::Function &function,
- lldb_private::Error &error,
+ lldb_private::Status &error,
const bool support_function_calls);
static bool Interpret(llvm::Module &module, llvm::Function &function,
llvm::ArrayRef<lldb::addr_t> args,
lldb_private::IRExecutionUnit &execution_unit,
- lldb_private::Error &error,
+ lldb_private::Status &error,
lldb::addr_t stack_frame_bottom,
lldb::addr_t stack_frame_top,
lldb_private::ExecutionContext &exe_ctx);
private:
static bool supportsFunction(llvm::Function &llvm_function,
- lldb_private::Error &err);
+ lldb_private::Status &err);
};
#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/IRMemoryMap.h b/contrib/llvm/tools/lldb/include/lldb/Expression/IRMemoryMap.h
index 405de51..abb5cd7 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/IRMemoryMap.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/IRMemoryMap.h
@@ -10,8 +10,8 @@
#ifndef lldb_IRMemoryMap_h_
#define lldb_IRMemoryMap_h_
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/UserID.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-public.h"
#include <map>
@@ -54,25 +54,25 @@ public:
};
lldb::addr_t Malloc(size_t size, uint8_t alignment, uint32_t permissions,
- AllocationPolicy policy, bool zero_memory, Error &error);
- void Leak(lldb::addr_t process_address, Error &error);
- void Free(lldb::addr_t process_address, Error &error);
+ AllocationPolicy policy, bool zero_memory, Status &error);
+ void Leak(lldb::addr_t process_address, Status &error);
+ void Free(lldb::addr_t process_address, Status &error);
void WriteMemory(lldb::addr_t process_address, const uint8_t *bytes,
- size_t size, Error &error);
+ size_t size, Status &error);
void WriteScalarToMemory(lldb::addr_t process_address, Scalar &scalar,
- size_t size, Error &error);
+ size_t size, Status &error);
void WritePointerToMemory(lldb::addr_t process_address, lldb::addr_t address,
- Error &error);
+ Status &error);
void ReadMemory(uint8_t *bytes, lldb::addr_t process_address, size_t size,
- Error &error);
+ Status &error);
void ReadScalarFromMemory(Scalar &scalar, lldb::addr_t process_address,
- size_t size, Error &error);
+ size_t size, Status &error);
void ReadPointerFromMemory(lldb::addr_t *address,
- lldb::addr_t process_address, Error &error);
+ lldb::addr_t process_address, Status &error);
bool GetAllocSize(lldb::addr_t address, size_t &size);
void GetMemoryData(DataExtractor &extractor, lldb::addr_t process_address,
- size_t size, Error &error);
+ size_t size, Status &error);
lldb::ByteOrder GetByteOrder();
uint32_t GetAddressByteSize();
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/LLVMUserExpression.h b/contrib/llvm/tools/lldb/include/lldb/Expression/LLVMUserExpression.h
index 48d0161..745d413 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/LLVMUserExpression.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/LLVMUserExpression.h
@@ -81,7 +81,7 @@ protected:
lldb::ExpressionVariableSP &result) override;
virtual void ScanContext(ExecutionContext &exe_ctx,
- lldb_private::Error &err) = 0;
+ lldb_private::Status &err) = 0;
bool PrepareToExecuteJITExpression(DiagnosticManager &diagnostic_manager,
ExecutionContext &exe_ctx,
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/Materializer.h b/contrib/llvm/tools/lldb/include/lldb/Expression/Materializer.h
index 4874929..b86bc65 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/Materializer.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/Materializer.h
@@ -17,10 +17,10 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Error.h"
#include "lldb/Expression/IRMemoryMap.h"
#include "lldb/Symbol/TaggedASTType.h"
#include "lldb/Target/StackFrame.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-types.h"
namespace lldb_private {
@@ -38,7 +38,7 @@ public:
~Dematerializer() { Wipe(); }
- void Dematerialize(Error &err, lldb::addr_t frame_top,
+ void Dematerialize(Status &err, lldb::addr_t frame_top,
lldb::addr_t frame_bottom);
void Wipe();
@@ -72,7 +72,7 @@ public:
typedef std::weak_ptr<Dematerializer> DematerializerWP;
DematerializerSP Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
- lldb::addr_t process_address, Error &err);
+ lldb::addr_t process_address, Status &err);
class PersistentVariableDelegate {
public:
@@ -83,13 +83,13 @@ public:
uint32_t
AddPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
- PersistentVariableDelegate *delegate, Error &err);
- uint32_t AddVariable(lldb::VariableSP &variable_sp, Error &err);
+ PersistentVariableDelegate *delegate, Status &err);
+ uint32_t AddVariable(lldb::VariableSP &variable_sp, Status &err);
uint32_t AddResultVariable(const CompilerType &type, bool is_lvalue,
bool keep_in_memory,
- PersistentVariableDelegate *delegate, Error &err);
- uint32_t AddSymbol(const Symbol &symbol_sp, Error &err);
- uint32_t AddRegister(const RegisterInfo &register_info, Error &err);
+ PersistentVariableDelegate *delegate, Status &err);
+ uint32_t AddSymbol(const Symbol &symbol_sp, Status &err);
+ uint32_t AddRegister(const RegisterInfo &register_info, Status &err);
uint32_t GetStructAlignment() { return m_struct_alignment; }
@@ -102,11 +102,11 @@ public:
virtual ~Entity() = default;
virtual void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
- lldb::addr_t process_address, Error &err) = 0;
+ lldb::addr_t process_address, Status &err) = 0;
virtual void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
lldb::addr_t process_address,
lldb::addr_t frame_top,
- lldb::addr_t frame_bottom, Error &err) = 0;
+ lldb::addr_t frame_bottom, Status &err) = 0;
virtual void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
Log *log) = 0;
virtual void Wipe(IRMemoryMap &map, lldb::addr_t process_address) = 0;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/REPL.h b/contrib/llvm/tools/lldb/include/lldb/Expression/REPL.h
index 56d31cf..0c1e97f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/REPL.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/REPL.h
@@ -60,7 +60,7 @@ public:
/// @return
/// The range of the containing object in the target process.
//------------------------------------------------------------------
- static lldb::REPLSP Create(Error &Error, lldb::LanguageType language,
+ static lldb::REPLSP Create(Status &Status, lldb::LanguageType language,
Debugger *debugger, Target *target,
const char *repl_options);
@@ -85,7 +85,7 @@ public:
lldb::IOHandlerSP GetIOHandler();
- Error RunLoop();
+ Status RunLoop();
//------------------------------------------------------------------
// IOHandler::Delegate functions
@@ -126,7 +126,7 @@ protected:
// Subclasses should override these functions to implement a functional REPL.
//----------------------------------------------------------------------
- virtual Error DoInitialization() = 0;
+ virtual Status DoInitialization() = 0;
virtual ConstString GetSourceFileBasename() = 0;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/UserExpression.h b/contrib/llvm/tools/lldb/include/lldb/Expression/UserExpression.h
index fca667e..ced5cb2 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/UserExpression.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/UserExpression.h
@@ -259,13 +259,13 @@ public:
static lldb::ExpressionResults
Evaluate(ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options,
llvm::StringRef expr_cstr, llvm::StringRef expr_prefix,
- lldb::ValueObjectSP &result_valobj_sp, Error &error,
+ lldb::ValueObjectSP &result_valobj_sp, Status &error,
uint32_t line_offset = 0, std::string *fixed_expression = nullptr,
lldb::ModuleSP *jit_module_sp_ptr = nullptr);
- static const Error::ValueType kNoResult =
+ static const Status::ValueType kNoResult =
0x1001; ///< ValueObject::GetError() returns this if there is no result
- ///from the expression.
+ /// from the expression.
const char *GetFixedText() {
if (m_fixed_text.empty())
@@ -281,7 +281,7 @@ protected:
lldb::ExpressionVariableSP &result) = 0;
static lldb::addr_t GetObjectPointer(lldb::StackFrameSP frame_sp,
- ConstString &object_name, Error &err);
+ ConstString &object_name, Status &err);
//------------------------------------------------------------------
/// Populate m_in_cplusplus_method and m_in_objectivec_method based on the
diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/UtilityFunction.h b/contrib/llvm/tools/lldb/include/lldb/Expression/UtilityFunction.h
index 0e2b87d..9c54db3 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Expression/UtilityFunction.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Expression/UtilityFunction.h
@@ -123,7 +123,7 @@ public:
FunctionCaller *MakeFunctionCaller(const CompilerType &return_type,
const ValueList &arg_value_list,
lldb::ThreadSP compilation_thread,
- Error &error);
+ Status &error);
// This one retrieves the function caller that is already made. If you
// haven't made it yet, this returns nullptr
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Config.h b/contrib/llvm/tools/lldb/include/lldb/Host/Config.h
deleted file mode 100644
index 16845ae..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Host/Config.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//===-- Config.h ------------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_Config_h_
-#define liblldb_Config_h_
-
-#if defined(__APPLE__)
-
-#include "lldb/Host/macosx/Config.h"
-
-#elif defined(__ANDROID__)
-
-#include "lldb/Host/android/Config.h"
-
-#elif defined(__linux__) || defined(__GNU__)
-
-#include "lldb/Host/linux/Config.h"
-
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
- defined(__OpenBSD__)
-
-#include "lldb/Host/freebsd/Config.h"
-
-#elif defined(__NetBSD__)
-
-#include "lldb/Host/netbsd/Config.h"
-
-#elif defined(__MINGW__) || defined(__MINGW32__)
-
-#include "lldb/Host/mingw/Config.h"
-
-#elif defined(_MSC_VER)
-
-#include "lldb/Host/msvc/Config.h"
-
-#else
-
-#error undefined platform
-
-#endif
-
-#endif // #ifndef liblldb_Config_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Config.h.cmake b/contrib/llvm/tools/lldb/include/lldb/Host/Config.h.cmake
new file mode 100644
index 0000000..0deedd1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/Config.h.cmake
@@ -0,0 +1,27 @@
+//===-- Config.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_HOST_CONFIG_H
+#define LLDB_HOST_CONFIG_H
+
+#cmakedefine LLDB_CONFIG_TERMIOS_SUPPORTED
+
+#cmakedefine LLDB_DISABLE_POSIX
+
+#cmakedefine01 HAVE_SYS_EVENT_H
+
+#cmakedefine01 HAVE_PPOLL
+
+#cmakedefine01 HAVE_SIGACTION
+
+#cmakedefine01 HAVE_PROCESS_VM_READV
+
+#cmakedefine01 HAVE_NR_PROCESS_VM_READV
+
+#endif // #ifndef LLDB_HOST_CONFIG_H
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Editline.h b/contrib/llvm/tools/lldb/include/lldb/Host/Editline.h
index faed373..0b75e9c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/Editline.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/Editline.h
@@ -43,7 +43,8 @@
// will only be
// used in cases where this is true. This is a compile time dependecy, for now
// selected per target Platform
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
+ defined(__OpenBSD__)
#define LLDB_EDITLINE_USE_WCHAR 1
#include <codecvt>
#else
@@ -64,8 +65,8 @@
#include <vector>
#include "lldb/Host/ConnectionFileDescriptor.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Predicate.h"
+#include "lldb/Utility/FileSpec.h"
namespace lldb_private {
namespace line_editor {
@@ -81,8 +82,14 @@ using EditLineStringStreamType = std::stringstream;
using EditLineCharType = char;
#endif
+#ifdef EL_CLIENTDATA /* editline with wide support + wide char read function */
+using EditLineGetCharType = wchar_t;
+#else
+using EditLineGetCharType = char;
+#endif
+
typedef int (*EditlineGetCharCallbackType)(::EditLine *editline,
- EditLineCharType *c);
+ EditLineGetCharType *c);
typedef unsigned char (*EditlineCommandCallbackType)(::EditLine *editline,
int ch);
typedef const char *(*EditlinePromptCallbackType)(::EditLine *editline);
@@ -269,7 +276,7 @@ private:
/// Character reading implementation for EditLine that supports our multi-line
/// editing trickery.
- int GetCharacter(EditLineCharType *c);
+ int GetCharacter(EditLineGetCharType *c);
/// Prompt implementation for EditLine.
const char *Prompt();
@@ -322,7 +329,7 @@ private:
/// single or multi-line editing.
void ConfigureEditor(bool multiline);
- bool CompleteCharacter(char ch, EditLineCharType &out);
+ bool CompleteCharacter(char ch, EditLineGetCharType &out);
private:
#if LLDB_EDITLINE_USE_WCHAR
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/File.h b/contrib/llvm/tools/lldb/include/lldb/Host/File.h
index 6fa4e56..1dfa12e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/File.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/File.h
@@ -10,18 +10,15 @@
#ifndef liblldb_File_h_
#define liblldb_File_h_
-// C Includes
-// C++ Includes
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Utility/IOObject.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-private.h"
+
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Host/IOObject.h"
-#include "lldb/Host/PosixApi.h"
-#include "lldb/lldb-private.h"
-
namespace lldb_private {
//----------------------------------------------------------------------
@@ -167,7 +164,7 @@ public:
/// @return
/// A reference to the file specification object.
//------------------------------------------------------------------
- Error GetFileSpec(FileSpec &file_spec) const;
+ Status GetFileSpec(FileSpec &file_spec) const;
//------------------------------------------------------------------
/// Open a file for read/writing with the specified options.
@@ -184,10 +181,10 @@ public:
/// @param[in] permissions
/// Options to use when opening (see File::Permissions)
//------------------------------------------------------------------
- Error Open(const char *path, uint32_t options,
- uint32_t permissions = lldb::eFilePermissionsFileDefault);
+ Status Open(const char *path, uint32_t options,
+ uint32_t permissions = lldb::eFilePermissionsFileDefault);
- Error Close() override;
+ Status Close() override;
void Clear();
@@ -219,7 +216,7 @@ public:
/// An error object that indicates success or the reason for
/// failure.
//------------------------------------------------------------------
- Error Read(void *buf, size_t &num_bytes) override;
+ Status Read(void *buf, size_t &num_bytes) override;
//------------------------------------------------------------------
/// Write bytes to a file at the current file position.
@@ -240,7 +237,7 @@ public:
/// An error object that indicates success or the reason for
/// failure.
//------------------------------------------------------------------
- Error Write(const void *buf, size_t &num_bytes) override;
+ Status Write(const void *buf, size_t &num_bytes) override;
//------------------------------------------------------------------
/// Seek to an offset relative to the beginning of the file.
@@ -256,13 +253,13 @@ public:
/// beginning of the file.
///
/// @param[in] error_ptr
- /// A pointer to a lldb_private::Error object that will be
+ /// A pointer to a lldb_private::Status object that will be
/// filled in if non-nullptr.
///
/// @return
/// The resulting seek offset, or -1 on error.
//------------------------------------------------------------------
- off_t SeekFromStart(off_t offset, Error *error_ptr = nullptr);
+ off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr);
//------------------------------------------------------------------
/// Seek to an offset relative to the current file position.
@@ -278,13 +275,13 @@ public:
/// current file position.
///
/// @param[in] error_ptr
- /// A pointer to a lldb_private::Error object that will be
+ /// A pointer to a lldb_private::Status object that will be
/// filled in if non-nullptr.
///
/// @return
/// The resulting seek offset, or -1 on error.
//------------------------------------------------------------------
- off_t SeekFromCurrent(off_t offset, Error *error_ptr = nullptr);
+ off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr);
//------------------------------------------------------------------
/// Seek to an offset relative to the end of the file.
@@ -301,13 +298,13 @@ public:
/// absolute file offset.
///
/// @param[in] error_ptr
- /// A pointer to a lldb_private::Error object that will be
+ /// A pointer to a lldb_private::Status object that will be
/// filled in if non-nullptr.
///
/// @return
/// The resulting seek offset, or -1 on error.
//------------------------------------------------------------------
- off_t SeekFromEnd(off_t offset, Error *error_ptr = nullptr);
+ off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr);
//------------------------------------------------------------------
/// Read bytes from a file from the specified file offset.
@@ -332,7 +329,7 @@ public:
/// An error object that indicates success or the reason for
/// failure.
//------------------------------------------------------------------
- Error Read(void *dst, size_t &num_bytes, off_t &offset);
+ Status Read(void *dst, size_t &num_bytes, off_t &offset);
//------------------------------------------------------------------
/// Read bytes from a file from the specified file offset.
@@ -363,8 +360,8 @@ public:
/// An error object that indicates success or the reason for
/// failure.
//------------------------------------------------------------------
- Error Read(size_t &num_bytes, off_t &offset, bool null_terminate,
- lldb::DataBufferSP &data_buffer_sp);
+ Status Read(size_t &num_bytes, off_t &offset, bool null_terminate,
+ lldb::DataBufferSP &data_buffer_sp);
//------------------------------------------------------------------
/// Write bytes to a file at the specified file offset.
@@ -391,7 +388,7 @@ public:
/// An error object that indicates success or the reason for
/// failure.
//------------------------------------------------------------------
- Error Write(const void *src, size_t &num_bytes, off_t &offset);
+ Status Write(const void *src, size_t &num_bytes, off_t &offset);
//------------------------------------------------------------------
/// Flush the current stream
@@ -400,7 +397,7 @@ public:
/// An error object that indicates success or the reason for
/// failure.
//------------------------------------------------------------------
- Error Flush();
+ Status Flush();
//------------------------------------------------------------------
/// Sync to disk.
@@ -409,7 +406,7 @@ public:
/// An error object that indicates success or the reason for
/// failure.
//------------------------------------------------------------------
- Error Sync();
+ Status Sync();
//------------------------------------------------------------------
/// Get the permissions for a this file.
@@ -418,9 +415,9 @@ public:
/// Bits logical OR'ed together from the permission bits defined
/// in lldb_private::File::Permissions.
//------------------------------------------------------------------
- uint32_t GetPermissions(Error &error) const;
+ uint32_t GetPermissions(Status &error) const;
- static uint32_t GetPermissions(const FileSpec &file_spec, Error &error);
+ static uint32_t GetPermissions(const FileSpec &file_spec, Status &error);
//------------------------------------------------------------------
/// Return true if this file is interactive.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/FileCache.h b/contrib/llvm/tools/lldb/include/lldb/Host/FileCache.h
index 1667d05..1c03540 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/FileCache.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/FileCache.h
@@ -9,13 +9,14 @@
#ifndef liblldb_Host_FileCache_h
#define liblldb_Host_FileCache_h
+#include <map>
#include <stdint.h>
#include "lldb/lldb-forward.h"
#include "lldb/lldb-types.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h"
namespace lldb_private {
class FileCache {
@@ -28,13 +29,13 @@ public:
static FileCache &GetInstance();
lldb::user_id_t OpenFile(const FileSpec &file_spec, uint32_t flags,
- uint32_t mode, Error &error);
- bool CloseFile(lldb::user_id_t fd, Error &error);
+ uint32_t mode, Status &error);
+ bool CloseFile(lldb::user_id_t fd, Status &error);
uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src,
- uint64_t src_len, Error &error);
+ uint64_t src_len, Status &error);
uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
- uint64_t dst_len, Error &error);
+ uint64_t dst_len, Status &error);
private:
static FileCache *m_instance;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/FileSystem.h b/contrib/llvm/tools/lldb/include/lldb/Host/FileSystem.h
index 6dbea6d..c13d5c8 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/FileSystem.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/FileSystem.h
@@ -10,8 +10,8 @@
#ifndef liblldb_Host_FileSystem_h
#define liblldb_Host_FileSystem_h
-#include "lldb/Core/Error.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h"
#include "llvm/Support/Chrono.h"
#include "lldb/lldb-types.h"
@@ -26,47 +26,15 @@ public:
static const char *DEV_NULL;
static const char *PATH_CONVERSION_ERROR;
- static FileSpec::PathSyntax GetNativePathSyntax();
+ static Status Symlink(const FileSpec &src, const FileSpec &dst);
+ static Status Readlink(const FileSpec &src, FileSpec &dst);
- static Error MakeDirectory(const FileSpec &file_spec, uint32_t mode);
- static Error DeleteDirectory(const FileSpec &file_spec, bool recurse);
-
- static Error GetFilePermissions(const FileSpec &file_spec,
- uint32_t &file_permissions);
- static Error SetFilePermissions(const FileSpec &file_spec,
- uint32_t file_permissions);
- static lldb::user_id_t GetFileSize(const FileSpec &file_spec);
- static bool GetFileExists(const FileSpec &file_spec);
-
- static Error Hardlink(const FileSpec &src, const FileSpec &dst);
- static int GetHardlinkCount(const FileSpec &file_spec);
- static Error Symlink(const FileSpec &src, const FileSpec &dst);
- static Error Readlink(const FileSpec &src, FileSpec &dst);
- static Error Unlink(const FileSpec &file_spec);
-
- static Error ResolveSymbolicLink(const FileSpec &src, FileSpec &dst);
-
- static bool CalculateMD5(const FileSpec &file_spec, uint64_t &low,
- uint64_t &high);
- static bool CalculateMD5(const FileSpec &file_spec, uint64_t offset,
- uint64_t length, uint64_t &low, uint64_t &high);
-
- static bool CalculateMD5AsString(const FileSpec &file_spec,
- std::string &digest_str);
- static bool CalculateMD5AsString(const FileSpec &file_spec, uint64_t offset,
- uint64_t length, std::string &digest_str);
-
- /// Return \b true if \a spec is on a locally mounted file system, \b false
- /// otherwise.
- static bool IsLocal(const FileSpec &spec);
+ static Status ResolveSymbolicLink(const FileSpec &src, FileSpec &dst);
/// Wraps ::fopen in a platform-independent way. Once opened, FILEs can be
/// manipulated and closed with the normal ::fread, ::fclose, etc. functions.
static FILE *Fopen(const char *path, const char *mode);
- /// Wraps ::stat in a platform-independent way.
- static int Stat(const char *path, struct stat *stats);
-
static llvm::sys::TimePoint<> GetModificationTime(const FileSpec &file_spec);
};
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Host.h b/contrib/llvm/tools/lldb/include/lldb/Host/Host.h
index 64c0dd6..da0b8e1 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/Host.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/Host.h
@@ -7,21 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_Host_h_
-#define liblldb_Host_h_
-#if defined(__cplusplus)
+#ifndef LLDB_HOST_HOST_H
+#define LLDB_HOST_HOST_H
-#include <stdarg.h>
-
-#include <map>
-#include <string>
-
-#include "lldb/Core/StringList.h"
#include "lldb/Host/File.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/HostThread.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/StringList.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-private.h"
+#include <cerrno>
+#include <map>
+#include <stdarg.h>
+#include <string>
+#include <type_traits>
namespace lldb_private {
@@ -29,6 +28,27 @@ class FileAction;
class ProcessLaunchInfo;
//----------------------------------------------------------------------
+// Exit Type for inferior processes
+//----------------------------------------------------------------------
+struct WaitStatus {
+ enum Type : uint8_t {
+ Exit, // The status represents the return code from normal
+ // program exit (i.e. WIFEXITED() was true)
+ Signal, // The status represents the signal number that caused
+ // the program to exit (i.e. WIFSIGNALED() was true)
+ Stop, // The status represents the signal number that caused the
+ // program to stop (i.e. WIFSTOPPED() was true)
+ };
+
+ Type type;
+ uint8_t status;
+
+ WaitStatus(Type type, uint8_t status) : type(type), status(status) {}
+
+ static WaitStatus Decode(int wstatus);
+};
+
+//----------------------------------------------------------------------
/// @class Host Host.h "lldb/Host/Host.h"
/// @brief A class that provides host computer information.
///
@@ -100,14 +120,6 @@ public:
static void Kill(lldb::pid_t pid, int signo);
//------------------------------------------------------------------
- /// Get the thread ID for the calling thread in the current process.
- ///
- /// @return
- /// The thread ID for the calling thread in the current process.
- //------------------------------------------------------------------
- static lldb::tid_t GetCurrentThreadID();
-
- //------------------------------------------------------------------
/// Get the thread token (the one returned by ThreadCreate when the thread was
/// created) for the
/// calling thread in the current process.
@@ -119,15 +131,6 @@ public:
static const char *GetSignalAsCString(int signo);
- typedef void (*ThreadLocalStorageCleanupCallback)(void *p);
-
- static lldb::thread_key_t
- ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback);
-
- static void *ThreadLocalStorageGet(lldb::thread_key_t key);
-
- static void ThreadLocalStorageSet(lldb::thread_key_t key, void *value);
-
//------------------------------------------------------------------
/// Given an address in the current process (the process that
/// is running the LLDB code), return the name of the module that
@@ -192,25 +195,9 @@ public:
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info);
-#if (defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \
- defined(__GLIBC__) || defined(__NetBSD__)) && \
- !defined(__ANDROID__)
-
- static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info);
-
- static Error LaunchProcessPosixSpawn(const char *exe_path,
- const ProcessLaunchInfo &launch_info,
- lldb::pid_t &pid);
-
- static bool AddPosixSpawnFileAction(void *file_actions,
- const FileAction *info, Log *log,
- Error &error);
-
-#endif
-
static const lldb::UnixSignalsSP &GetUnixSignals();
- static Error LaunchProcess(ProcessLaunchInfo &launch_info);
+ static Status LaunchProcess(ProcessLaunchInfo &launch_info);
//------------------------------------------------------------------
/// Perform expansion of the command-line for this launch info
@@ -219,10 +206,10 @@ public:
// argument magic the platform defines as part of its typical
// user experience
//------------------------------------------------------------------
- static Error ShellExpandArguments(ProcessLaunchInfo &launch_info);
+ static Status ShellExpandArguments(ProcessLaunchInfo &launch_info);
// TODO: Convert this function to take a StringRef.
- static Error RunShellCommand(
+ static Status RunShellCommand(
const char *command, // Shouldn't be NULL
const FileSpec &working_dir, // Pass empty FileSpec to use the current
// working directory
@@ -234,7 +221,7 @@ public:
uint32_t timeout_sec,
bool run_in_default_shell = true);
- static Error RunShellCommand(
+ static Status RunShellCommand(
const Args &args,
const FileSpec &working_dir, // Pass empty FileSpec to use the current
// working directory
@@ -246,17 +233,24 @@ public:
uint32_t timeout_sec,
bool run_in_default_shell = true);
- static lldb::DataBufferSP GetAuxvData(lldb_private::Process *process);
-
- static lldb::DataBufferSP GetAuxvData(lldb::pid_t pid);
-
static bool OpenFileInExternalEditor(const FileSpec &file_spec,
uint32_t line_no);
static size_t GetEnvironment(StringList &env);
+
+ static std::unique_ptr<Connection>
+ CreateDefaultConnection(llvm::StringRef url);
};
} // namespace lldb_private
-#endif // #if defined(__cplusplus)
-#endif // liblldb_Host_h_
+namespace llvm {
+template <> struct format_provider<lldb_private::WaitStatus> {
+ /// Options = "" gives a human readable description of the status
+ /// Options = "g" gives a gdb-remote protocol status (e.g., X09)
+ static void format(const lldb_private::WaitStatus &WS, raw_ostream &OS,
+ llvm::StringRef Options);
+};
+} // namespace llvm
+
+#endif // LLDB_HOST_HOST_H
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/HostInfo.h b/contrib/llvm/tools/lldb/include/lldb/Host/HostInfo.h
index 4646be2..b4a2f8b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/HostInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/HostInfo.h
@@ -51,6 +51,9 @@
#elif defined(__NetBSD__)
#include "lldb/Host/netbsd/HostInfoNetBSD.h"
#define HOST_INFO_TYPE HostInfoNetBSD
+#elif defined(__OpenBSD__)
+#include "lldb/Host/openbsd/HostInfoOpenBSD.h"
+#define HOST_INFO_TYPE HostInfoOpenBSD
#elif defined(__APPLE__)
#include "lldb/Host/macosx/HostInfoMacOSX.h"
#define HOST_INFO_TYPE HostInfoMacOSX
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/HostInfoBase.h b/contrib/llvm/tools/lldb/include/lldb/Host/HostInfoBase.h
index 74ac79b..42e3fc3 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/HostInfoBase.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/HostInfoBase.h
@@ -11,7 +11,7 @@
#define lldb_Host_HostInfoBase_h_
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/StringRef.h"
@@ -35,39 +35,6 @@ public:
static void Terminate();
//------------------------------------------------------------------
- /// Returns the number of CPUs on this current host.
- ///
- /// @return
- /// Number of CPUs on this current host, or zero if the number
- /// of CPUs can't be determined on this host.
- //------------------------------------------------------------------
- static uint32_t GetNumberCPUS();
-
- //------------------------------------------------------------------
- /// Returns the maximum length of a thread name on this platform.
- ///
- /// @return
- /// Maximum length of a thread name on this platform.
- //------------------------------------------------------------------
- static uint32_t GetMaxThreadNameLength();
-
- //------------------------------------------------------------------
- /// Gets the host vendor string.
- ///
- /// @return
- /// A const string object containing the host vendor name.
- //------------------------------------------------------------------
- static llvm::StringRef GetVendorString();
-
- //------------------------------------------------------------------
- /// Gets the host Operating System (OS) string.
- ///
- /// @return
- /// A const string object containing the host OS name.
- //------------------------------------------------------------------
- static llvm::StringRef GetOSString();
-
- //------------------------------------------------------------------
/// Gets the host target triple as a const string.
///
/// @return
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeProcessBase.h b/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeProcessBase.h
index 204f78e..07f98c2 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeProcessBase.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeProcessBase.h
@@ -10,8 +10,8 @@
#ifndef lldb_Host_HostNativeProcessBase_h_
#define lldb_Host_HostNativeProcessBase_h_
-#include "lldb/Core/Error.h"
#include "lldb/Host/HostProcess.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
@@ -28,8 +28,8 @@ public:
: m_process(process) {}
virtual ~HostNativeProcessBase() {}
- virtual Error Terminate() = 0;
- virtual Error GetMainModule(FileSpec &file_spec) const = 0;
+ virtual Status Terminate() = 0;
+ virtual Status GetMainModule(FileSpec &file_spec) const = 0;
virtual lldb::pid_t GetProcessId() const = 0;
virtual bool IsRunning() const = 0;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThread.h b/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThread.h
index b0411ca..e33d978 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThread.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThread.h
@@ -14,14 +14,10 @@
#if defined(_WIN32)
#include "lldb/Host/windows/HostThreadWindows.h"
-#elif defined(__linux__)
-#include "lldb/Host/linux/HostThreadLinux.h"
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include "lldb/Host/freebsd/HostThreadFreeBSD.h"
-#elif defined(__NetBSD__)
-#include "lldb/Host/netbsd/HostThreadNetBSD.h"
#elif defined(__APPLE__)
#include "lldb/Host/macosx/HostThreadMacOSX.h"
+#else
+#include "lldb/Host/posix/HostThreadPosix.h"
#endif
#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadBase.h b/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadBase.h
index 284b754..f1f89f3 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadBase.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadBase.h
@@ -10,7 +10,7 @@
#ifndef lldb_Host_HostNativeThreadBase_h_
#define lldb_Host_HostNativeThreadBase_h_
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
@@ -31,8 +31,8 @@ public:
explicit HostNativeThreadBase(lldb::thread_t thread);
virtual ~HostNativeThreadBase() {}
- virtual Error Join(lldb::thread_result_t *result) = 0;
- virtual Error Cancel() = 0;
+ virtual Status Join(lldb::thread_result_t *result) = 0;
+ virtual Status Cancel() = 0;
virtual bool IsJoinable() const;
virtual void Reset();
lldb::thread_t Release();
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadForward.h b/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadForward.h
index 5b83213..4691a22 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadForward.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/HostNativeThreadForward.h
@@ -14,18 +14,12 @@ namespace lldb_private {
#if defined(_WIN32)
class HostThreadWindows;
typedef HostThreadWindows HostNativeThread;
-#elif defined(__linux__)
-class HostThreadLinux;
-typedef HostThreadLinux HostNativeThread;
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-class HostThreadFreeBSD;
-typedef HostThreadFreeBSD HostNativeThread;
-#elif defined(__NetBSD__)
-class HostThreadNetBSD;
-typedef HostThreadNetBSD HostNativeThread;
#elif defined(__APPLE__)
class HostThreadMacOSX;
typedef HostThreadMacOSX HostNativeThread;
+#else
+class HostThreadPosix;
+typedef HostThreadPosix HostNativeThread;
#endif
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/HostProcess.h b/contrib/llvm/tools/lldb/include/lldb/Host/HostProcess.h
index 56c3ddd..dfc997b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/HostProcess.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/HostProcess.h
@@ -40,8 +40,8 @@ public:
HostProcess(lldb::process_t process);
~HostProcess();
- Error Terminate();
- Error GetMainModule(FileSpec &file_spec) const;
+ Status Terminate();
+ Status GetMainModule(FileSpec &file_spec) const;
lldb::pid_t GetProcessId() const;
bool IsRunning() const;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/HostThread.h b/contrib/llvm/tools/lldb/include/lldb/Host/HostThread.h
index d14f0f6..0d2fbe6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/HostThread.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/HostThread.h
@@ -10,8 +10,8 @@
#ifndef lldb_Host_HostThread_h_
#define lldb_Host_HostThread_h_
-#include "lldb/Core/Error.h"
#include "lldb/Host/HostNativeThreadForward.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-types.h"
#include <memory>
@@ -34,8 +34,8 @@ public:
HostThread();
HostThread(lldb::thread_t thread);
- Error Join(lldb::thread_result_t *result);
- Error Cancel();
+ Status Join(lldb::thread_result_t *result);
+ Status Cancel();
void Reset();
lldb::thread_t Release();
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/LockFileBase.h b/contrib/llvm/tools/lldb/include/lldb/Host/LockFileBase.h
index 3b2f723..4eda191 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/LockFileBase.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/LockFileBase.h
@@ -10,7 +10,7 @@
#ifndef liblldb_Host_LockFileBase_h_
#define liblldb_Host_LockFileBase_h_
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Status.h"
#include <functional>
@@ -22,30 +22,30 @@ public:
bool IsLocked() const;
- Error WriteLock(const uint64_t start, const uint64_t len);
- Error TryWriteLock(const uint64_t start, const uint64_t len);
+ Status WriteLock(const uint64_t start, const uint64_t len);
+ Status TryWriteLock(const uint64_t start, const uint64_t len);
- Error ReadLock(const uint64_t start, const uint64_t len);
- Error TryReadLock(const uint64_t start, const uint64_t len);
+ Status ReadLock(const uint64_t start, const uint64_t len);
+ Status TryReadLock(const uint64_t start, const uint64_t len);
- Error Unlock();
+ Status Unlock();
protected:
- using Locker = std::function<Error(const uint64_t, const uint64_t)>;
+ using Locker = std::function<Status(const uint64_t, const uint64_t)>;
LockFileBase(int fd);
virtual bool IsValidFile() const;
- virtual Error DoWriteLock(const uint64_t start, const uint64_t len) = 0;
- virtual Error DoTryWriteLock(const uint64_t start, const uint64_t len) = 0;
+ virtual Status DoWriteLock(const uint64_t start, const uint64_t len) = 0;
+ virtual Status DoTryWriteLock(const uint64_t start, const uint64_t len) = 0;
- virtual Error DoReadLock(const uint64_t start, const uint64_t len) = 0;
- virtual Error DoTryReadLock(const uint64_t start, const uint64_t len) = 0;
+ virtual Status DoReadLock(const uint64_t start, const uint64_t len) = 0;
+ virtual Status DoTryReadLock(const uint64_t start, const uint64_t len) = 0;
- virtual Error DoUnlock() = 0;
+ virtual Status DoUnlock() = 0;
- Error DoLock(const Locker &locker, const uint64_t start, const uint64_t len);
+ Status DoLock(const Locker &locker, const uint64_t start, const uint64_t len);
int m_fd; // not owned.
bool m_locked;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h b/contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h
index 8aa26b6..5ac145f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/MainLoop.h
@@ -10,16 +10,103 @@
#ifndef lldb_Host_MainLoop_h_
#define lldb_Host_MainLoop_h_
-#ifdef _WIN32
+#include "lldb/Host/Config.h"
#include "lldb/Host/MainLoopBase.h"
+#include "llvm/ADT/DenseMap.h"
+#include <csignal>
+
+#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H
+#define SIGNAL_POLLING_UNSUPPORTED 1
+#endif
+
namespace lldb_private {
-typedef MainLoopBase MainLoop;
-}
-#else
-#include "lldb/Host/posix/MainLoopPosix.h"
-namespace lldb_private {
-typedef MainLoopPosix MainLoop;
-}
+
+// Implementation of the MainLoopBase class. It can monitor file descriptors for
+// readability using ppoll, kqueue, poll or WSAPoll. On Windows it only supports
+// polling sockets, and will not work on generic file handles or pipes. On
+// systems without kqueue or ppoll handling singnals is not supported. In
+// addition to the common base, this class provides the ability to invoke a
+// given handler when a signal is received.
+//
+// Since this class is primarily intended to be used for single-threaded
+// processing, it does not attempt to perform any internal synchronisation and
+// any concurrent accesses must be protected externally. However, it is
+// perfectly legitimate to have more than one instance of this class running on
+// separate threads, or even a single thread (with some limitations on signal
+// monitoring).
+// TODO: Add locking if this class is to be used in a multi-threaded context.
+class MainLoop : public MainLoopBase {
+private:
+ class SignalHandle;
+
+public:
+ typedef std::unique_ptr<SignalHandle> SignalHandleUP;
+
+ MainLoop();
+ ~MainLoop() override;
+
+ ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp,
+ const Callback &callback,
+ Status &error) override;
+
+ // Listening for signals from multiple MainLoop instances is perfectly safe as
+ // long as they don't try to listen for the same signal. The callback function
+ // is invoked when the control returns to the Run() function, not when the
+ // hander is executed. This mean that you can treat the callback as a normal
+ // function and perform things which would not be safe in a signal handler.
+ // However, since the callback is not invoked synchronously, you cannot use
+ // this mechanism to handle SIGSEGV and the like.
+ SignalHandleUP RegisterSignal(int signo, const Callback &callback,
+ Status &error);
+
+ Status Run() override;
+
+ // This should only be performed from a callback. Do not attempt to terminate
+ // the processing from another thread.
+ // TODO: Add synchronization if we want to be terminated from another thread.
+ void RequestTermination() override { m_terminate_request = true; }
+
+protected:
+ void UnregisterReadObject(IOObject::WaitableHandle handle) override;
+
+ void UnregisterSignal(int signo);
+
+private:
+ void ProcessReadObject(IOObject::WaitableHandle handle);
+ void ProcessSignal(int signo);
+
+ class SignalHandle {
+ public:
+ ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); }
+
+ private:
+ SignalHandle(MainLoop &mainloop, int signo)
+ : m_mainloop(mainloop), m_signo(signo) {}
+
+ MainLoop &m_mainloop;
+ int m_signo;
+
+ friend class MainLoop;
+ DISALLOW_COPY_AND_ASSIGN(SignalHandle);
+ };
+
+ struct SignalInfo {
+ Callback callback;
+#if HAVE_SIGACTION
+ struct sigaction old_action;
#endif
+ bool was_blocked : 1;
+ };
+ class RunImpl;
+
+ llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
+ llvm::DenseMap<int, SignalInfo> m_signals;
+#if HAVE_SYS_EVENT_H
+ int m_kqueue;
+#endif
+ bool m_terminate_request : 1;
+};
+
+} // namespace lldb_private
#endif // lldb_Host_MainLoop_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/MainLoopBase.h b/contrib/llvm/tools/lldb/include/lldb/Host/MainLoopBase.h
index cd29796..a87d262 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/MainLoopBase.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/MainLoopBase.h
@@ -10,12 +10,10 @@
#ifndef lldb_Host_posix_MainLoopBase_h_
#define lldb_Host_posix_MainLoopBase_h_
-#include <functional>
-
+#include "lldb/Utility/IOObject.h"
+#include "lldb/Utility/Status.h"
#include "llvm/Support/ErrorHandling.h"
-
-#include "lldb/Core/Error.h"
-#include "lldb/Host/IOObject.h"
+#include <functional>
namespace lldb_private {
@@ -49,14 +47,14 @@ public:
virtual ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp,
const Callback &callback,
- Error &error) {
+ Status &error) {
llvm_unreachable("Not implemented");
}
// Waits for registered events and invoke the proper callbacks. Returns when
// all callbacks
// deregister themselves or when someone requests termination.
- virtual Error Run() { llvm_unreachable("Not implemented"); }
+ virtual Status Run() { llvm_unreachable("Not implemented"); }
// Requests the exit of the Run() function.
virtual void RequestTermination() { llvm_unreachable("Not implemented"); }
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/MonitoringProcessLauncher.h b/contrib/llvm/tools/lldb/include/lldb/Host/MonitoringProcessLauncher.h
index 7aa819a..9ad36e9 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/MonitoringProcessLauncher.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/MonitoringProcessLauncher.h
@@ -25,7 +25,7 @@ public:
std::unique_ptr<ProcessLauncher> delegate_launcher);
HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info,
- Error &error) override;
+ Status &error) override;
private:
std::unique_ptr<ProcessLauncher> m_delegate_launcher;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/PipeBase.h b/contrib/llvm/tools/lldb/include/lldb/Host/PipeBase.h
index e3d7c25..ad62072 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/PipeBase.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/PipeBase.h
@@ -14,7 +14,7 @@
#include <chrono>
#include <string>
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Status.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -23,17 +23,18 @@ class PipeBase {
public:
virtual ~PipeBase();
- virtual Error CreateNew(bool child_process_inherit) = 0;
- virtual Error CreateNew(llvm::StringRef name, bool child_process_inherit) = 0;
- virtual Error CreateWithUniqueName(llvm::StringRef prefix,
- bool child_process_inherit,
- llvm::SmallVectorImpl<char> &name) = 0;
+ virtual Status CreateNew(bool child_process_inherit) = 0;
+ virtual Status CreateNew(llvm::StringRef name,
+ bool child_process_inherit) = 0;
+ virtual Status CreateWithUniqueName(llvm::StringRef prefix,
+ bool child_process_inherit,
+ llvm::SmallVectorImpl<char> &name) = 0;
- virtual Error OpenAsReader(llvm::StringRef name,
- bool child_process_inherit) = 0;
+ virtual Status OpenAsReader(llvm::StringRef name,
+ bool child_process_inherit) = 0;
- Error OpenAsWriter(llvm::StringRef name, bool child_process_inherit);
- virtual Error
+ Status OpenAsWriter(llvm::StringRef name, bool child_process_inherit);
+ virtual Status
OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit,
const std::chrono::microseconds &timeout) = 0;
@@ -51,13 +52,13 @@ public:
virtual void Close() = 0;
// Delete named pipe.
- virtual Error Delete(llvm::StringRef name) = 0;
+ virtual Status Delete(llvm::StringRef name) = 0;
- virtual Error Write(const void *buf, size_t size, size_t &bytes_written) = 0;
- virtual Error ReadWithTimeout(void *buf, size_t size,
- const std::chrono::microseconds &timeout,
- size_t &bytes_read) = 0;
- Error Read(void *buf, size_t size, size_t &bytes_read);
+ virtual Status Write(const void *buf, size_t size, size_t &bytes_written) = 0;
+ virtual Status ReadWithTimeout(void *buf, size_t size,
+ const std::chrono::microseconds &timeout,
+ size_t &bytes_read) = 0;
+ Status Read(void *buf, size_t size, size_t &bytes_read);
};
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/PosixApi.h b/contrib/llvm/tools/lldb/include/lldb/Host/PosixApi.h
index 23a291c..d5c48dd6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/PosixApi.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/PosixApi.h
@@ -14,10 +14,10 @@
// to provide a minimum level of compatibility across all platforms to rely
// on various posix api functionality.
-#include "llvm/Support/Compiler.h"
-
-#if defined(LLVM_ON_WIN32)
+#if defined(_WIN32)
#include "lldb/Host/windows/PosixApi.h"
+#else
+#include <unistd.h>
#endif
#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/ProcessLauncher.h b/contrib/llvm/tools/lldb/include/lldb/Host/ProcessLauncher.h
index 12049a6..49fa841 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/ProcessLauncher.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/ProcessLauncher.h
@@ -13,14 +13,14 @@
namespace lldb_private {
class ProcessLaunchInfo;
-class Error;
+class Status;
class HostProcess;
class ProcessLauncher {
public:
virtual ~ProcessLauncher() {}
virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info,
- Error &error) = 0;
+ Status &error) = 0;
};
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/PseudoTerminal.h b/contrib/llvm/tools/lldb/include/lldb/Host/PseudoTerminal.h
index fbe9334..fdbf6df 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/PseudoTerminal.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/PseudoTerminal.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_PseudoTerminal_h_
-#define liblldb_PseudoTerminal_h_
+#ifndef LLDB_HOST_PSEUDOTERMINAL_H
+#define LLDB_HOST_PSEUDOTERMINAL_H
#if defined(__cplusplus)
#include <fcntl.h>
@@ -19,7 +19,7 @@
namespace lldb_utility {
//----------------------------------------------------------------------
-/// @class PseudoTerminal PseudoTerminal.h "lldb/Core/PseudoTerminal.h"
+/// @class PseudoTerminal PseudoTerminal.h "lldb/Host/PseudoTerminal.h"
/// @brief A pseudo terminal helper class.
///
/// The pseudo terminal class abstracts the use of pseudo terminals on
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Socket.h b/contrib/llvm/tools/lldb/include/lldb/Host/Socket.h
index 1ad3ca7..37f468f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/Socket.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/Socket.h
@@ -15,10 +15,10 @@
#include "lldb/lldb-private.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Host/IOObject.h"
#include "lldb/Host/Predicate.h"
#include "lldb/Host/SocketAddress.h"
+#include "lldb/Utility/IOObject.h"
+#include "lldb/Utility/Status.h"
#ifdef _WIN32
#include "lldb/Host/windows/windows.h"
@@ -53,36 +53,35 @@ public:
static std::unique_ptr<Socket> Create(const SocketProtocol protocol,
bool child_processes_inherit,
- Error &error);
+ Status &error);
- virtual Error Connect(llvm::StringRef name) = 0;
- virtual Error Listen(llvm::StringRef name, int backlog) = 0;
- virtual Error Accept(llvm::StringRef name, bool child_processes_inherit,
- Socket *&socket) = 0;
+ virtual Status Connect(llvm::StringRef name) = 0;
+ virtual Status Listen(llvm::StringRef name, int backlog) = 0;
+ virtual Status Accept(Socket *&socket) = 0;
// Initialize a Tcp Socket object in listening mode. listen and accept are
// implemented
// separately because the caller may wish to manipulate or query the socket
// after it is
// initialized, but before entering a blocking accept.
- static Error TcpListen(llvm::StringRef host_and_port,
- bool child_processes_inherit, Socket *&socket,
- Predicate<uint16_t> *predicate, int backlog = 5);
- static Error TcpConnect(llvm::StringRef host_and_port,
- bool child_processes_inherit, Socket *&socket);
- static Error UdpConnect(llvm::StringRef host_and_port,
- bool child_processes_inherit, Socket *&send_socket,
- Socket *&recv_socket);
- static Error UnixDomainConnect(llvm::StringRef host_and_port,
+ static Status TcpListen(llvm::StringRef host_and_port,
+ bool child_processes_inherit, Socket *&socket,
+ Predicate<uint16_t> *predicate, int backlog = 5);
+ static Status TcpConnect(llvm::StringRef host_and_port,
+ bool child_processes_inherit, Socket *&socket);
+ static Status UdpConnect(llvm::StringRef host_and_port,
+ bool child_processes_inherit, Socket *&socket);
+ static Status UnixDomainConnect(llvm::StringRef host_and_port,
+ bool child_processes_inherit,
+ Socket *&socket);
+ static Status UnixDomainAccept(llvm::StringRef host_and_port,
bool child_processes_inherit, Socket *&socket);
- static Error UnixDomainAccept(llvm::StringRef host_and_port,
- bool child_processes_inherit, Socket *&socket);
- static Error UnixAbstractConnect(llvm::StringRef host_and_port,
+ static Status UnixAbstractConnect(llvm::StringRef host_and_port,
+ bool child_processes_inherit,
+ Socket *&socket);
+ static Status UnixAbstractAccept(llvm::StringRef host_and_port,
bool child_processes_inherit,
Socket *&socket);
- static Error UnixAbstractAccept(llvm::StringRef host_and_port,
- bool child_processes_inherit,
- Socket *&socket);
int GetOption(int level, int option_name, int &option_value);
int SetOption(int level, int option_name, int option_value);
@@ -90,34 +89,36 @@ public:
NativeSocket GetNativeSocket() const { return m_socket; }
SocketProtocol GetSocketProtocol() const { return m_protocol; }
- Error Read(void *buf, size_t &num_bytes) override;
- Error Write(const void *buf, size_t &num_bytes) override;
+ Status Read(void *buf, size_t &num_bytes) override;
+ Status Write(const void *buf, size_t &num_bytes) override;
- virtual Error PreDisconnect();
- Error Close() override;
+ virtual Status PreDisconnect();
+ Status Close() override;
bool IsValid() const override { return m_socket != kInvalidSocketValue; }
WaitableHandle GetWaitableHandle() override;
static bool DecodeHostAndPort(llvm::StringRef host_and_port,
std::string &host_str, std::string &port_str,
- int32_t &port, Error *error_ptr);
+ int32_t &port, Status *error_ptr);
protected:
- Socket(NativeSocket socket, SocketProtocol protocol, bool should_close);
+ Socket(SocketProtocol protocol, bool should_close,
+ bool m_child_process_inherit);
virtual size_t Send(const void *buf, const size_t num_bytes);
- static void SetLastError(Error &error);
+ static void SetLastError(Status &error);
static NativeSocket CreateSocket(const int domain, const int type,
const int protocol,
- bool child_processes_inherit, Error &error);
+ bool child_processes_inherit, Status &error);
static NativeSocket AcceptSocket(NativeSocket sockfd, struct sockaddr *addr,
socklen_t *addrlen,
- bool child_processes_inherit, Error &error);
+ bool child_processes_inherit, Status &error);
SocketProtocol m_protocol;
NativeSocket m_socket;
+ bool m_child_processes_inherit;
};
} // namespace lldb_private
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/SocketAddress.h b/contrib/llvm/tools/lldb/include/lldb/Host/SocketAddress.h
index 3d1ed90..ebc6f4e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/SocketAddress.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/SocketAddress.h
@@ -32,15 +32,24 @@ typedef ADDRESS_FAMILY sa_family_t;
// Other libraries and framework includes
// Project includes
#include <string>
+#include <vector>
namespace lldb_private {
class SocketAddress {
public:
+ //----------------------------------------------------------------------------
+ // Static method to get all address information for a host and/or service
+ //----------------------------------------------------------------------------
+ static std::vector<SocketAddress>
+ GetAddressInfo(const char *hostname, const char *servname, int ai_family,
+ int ai_socktype, int ai_protocol, int ai_flags = 0);
+
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
SocketAddress();
+ SocketAddress(const struct addrinfo *addr_info);
SocketAddress(const struct sockaddr &s);
SocketAddress(const struct sockaddr_in &s);
SocketAddress(const struct sockaddr_in6 &s);
@@ -63,6 +72,9 @@ public:
const SocketAddress &operator=(const struct sockaddr_storage &s);
+ bool operator==(const SocketAddress &rhs) const;
+ bool operator!=(const SocketAddress &rhs) const;
+
//------------------------------------------------------------------
// Clear the contents of this socket address
//------------------------------------------------------------------
@@ -135,6 +147,16 @@ public:
bool IsValid() const;
//------------------------------------------------------------------
+ // Returns true if the socket is INADDR_ANY
+ //------------------------------------------------------------------
+ bool IsAnyAddr() const;
+
+ //------------------------------------------------------------------
+ // Returns true if the socket is INADDR_LOOPBACK
+ //------------------------------------------------------------------
+ bool IsLocalhost() const;
+
+ //------------------------------------------------------------------
// Direct access to all of the sockaddr structures
//------------------------------------------------------------------
struct sockaddr &sockaddr() {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Symbols.h b/contrib/llvm/tools/lldb/include/lldb/Host/Symbols.h
index 1339c06..5f8632d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/Symbols.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/Symbols.h
@@ -16,10 +16,14 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
namespace lldb_private {
+class ArchSpec;
+class ModuleSpec;
+class UUID;
+
class Symbols {
public:
//----------------------------------------------------------------------
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/ThisThread.h b/contrib/llvm/tools/lldb/include/lldb/Host/ThisThread.h
deleted file mode 100644
index 1392b10..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Host/ThisThread.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//===-- ThisThread.h --------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef lldb_Host_ThisThread_h_
-#define lldb_Host_ThisThread_h_
-
-#include "llvm/ADT/StringRef.h"
-
-#include <string>
-
-namespace llvm {
-template <class T> class SmallVectorImpl;
-}
-
-namespace lldb_private {
-
-class ThisThread {
-private:
- ThisThread();
-
-public:
- // ThisThread common functions.
- static void SetName(llvm::StringRef name, int max_length);
-
- // ThisThread platform-specific functions.
- static void SetName(llvm::StringRef name);
- static void GetName(llvm::SmallVectorImpl<char> &name);
-};
-}
-
-#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/ThreadLauncher.h b/contrib/llvm/tools/lldb/include/lldb/Host/ThreadLauncher.h
index 0f2cb37..b50f0e2 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/ThreadLauncher.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/ThreadLauncher.h
@@ -11,8 +11,8 @@
#ifndef lldb_Host_ThreadLauncher_h_
#define lldb_Host_ThreadLauncher_h_
-#include "lldb/Core/Error.h"
#include "lldb/Host/HostThread.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/StringRef.h"
@@ -23,7 +23,7 @@ class ThreadLauncher {
public:
static HostThread
LaunchThread(llvm::StringRef name, lldb::thread_func_t thread_function,
- lldb::thread_arg_t thread_arg, Error *error_ptr,
+ lldb::thread_arg_t thread_arg, Status *error_ptr,
size_t min_stack_byte_size = 0); // Minimum stack size in bytes,
// set stack size to zero for
// default platform thread stack
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/XML.h b/contrib/llvm/tools/lldb/include/lldb/Host/XML.h
index 4113b33..96b5227 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/XML.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/XML.h
@@ -24,8 +24,8 @@
#include "llvm/ADT/StringRef.h"
// Project includes
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpoint.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpoint.h
index 2f872e1..73639d6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpoint.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpoint.h
@@ -24,9 +24,9 @@ public:
virtual ~NativeBreakpoint();
- Error Enable();
+ Status Enable();
- Error Disable();
+ Status Disable();
lldb::addr_t GetAddress() const { return m_addr; }
@@ -38,9 +38,9 @@ protected:
const lldb::addr_t m_addr;
int32_t m_ref_count;
- virtual Error DoEnable() = 0;
+ virtual Status DoEnable() = 0;
- virtual Error DoDisable() = 0;
+ virtual Status DoDisable() = 0;
private:
bool m_enabled;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpointList.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpointList.h
index 2bb8e56..ffa659f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpointList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeBreakpointList.h
@@ -10,7 +10,7 @@
#ifndef liblldb_NativeBreakpointList_h_
#define liblldb_NativeBreakpointList_h_
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-forward.h"
// #include "lldb/Host/NativeBreakpoint.h"
@@ -19,26 +19,35 @@
#include <mutex>
namespace lldb_private {
+
+struct HardwareBreakpoint {
+ lldb::addr_t m_addr;
+ size_t m_size;
+};
+
+using HardwareBreakpointMap = std::map<lldb::addr_t, HardwareBreakpoint>;
+
class NativeBreakpointList {
public:
- typedef std::function<Error(lldb::addr_t addr, size_t size_hint,
- bool hardware, NativeBreakpointSP &breakpoint_sp)>
+ typedef std::function<Status(lldb::addr_t addr, size_t size_hint,
+ bool hardware,
+ NativeBreakpointSP &breakpoint_sp)>
CreateBreakpointFunc;
NativeBreakpointList();
- Error AddRef(lldb::addr_t addr, size_t size_hint, bool hardware,
- CreateBreakpointFunc create_func);
+ Status AddRef(lldb::addr_t addr, size_t size_hint, bool hardware,
+ CreateBreakpointFunc create_func);
- Error DecRef(lldb::addr_t addr);
+ Status DecRef(lldb::addr_t addr);
- Error EnableBreakpoint(lldb::addr_t addr);
+ Status EnableBreakpoint(lldb::addr_t addr);
- Error DisableBreakpoint(lldb::addr_t addr);
+ Status DisableBreakpoint(lldb::addr_t addr);
- Error GetBreakpoint(lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp);
+ Status GetBreakpoint(lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp);
- Error RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf, size_t size) const;
+ Status RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf, size_t size) const;
private:
typedef std::map<lldb::addr_t, NativeBreakpointSP> BreakpointMap;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeProcessProtocol.h
index a0f03b0..9671d71 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -10,14 +10,18 @@
#ifndef liblldb_NativeProcessProtocol_h_
#define liblldb_NativeProcessProtocol_h_
-#include <mutex>
-#include <vector>
-
-#include "lldb/Core/Error.h"
+#include "lldb/Host/Host.h"
#include "lldb/Host/MainLoop.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/TraceOptions.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-types.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <vector>
#include "NativeBreakpointList.h"
#include "NativeWatchpointList.h"
@@ -29,18 +33,17 @@ class ResumeActionList;
//------------------------------------------------------------------
// NativeProcessProtocol
//------------------------------------------------------------------
-class NativeProcessProtocol
- : public std::enable_shared_from_this<NativeProcessProtocol> {
+class NativeProcessProtocol {
friend class SoftwareBreakpoint;
public:
virtual ~NativeProcessProtocol() {}
- virtual Error Resume(const ResumeActionList &resume_actions) = 0;
+ virtual Status Resume(const ResumeActionList &resume_actions) = 0;
- virtual Error Halt() = 0;
+ virtual Status Halt() = 0;
- virtual Error Detach() = 0;
+ virtual Status Detach() = 0;
//------------------------------------------------------------------
/// Sends a process a UNIX signal \a signal.
@@ -48,7 +51,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error Signal(int signo) = 0;
+ virtual Status Signal(int signo) = 0;
//------------------------------------------------------------------
/// Tells a process to interrupt all operations as if by a Ctrl-C.
@@ -60,30 +63,36 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error Interrupt();
+ virtual Status Interrupt();
- virtual Error Kill() = 0;
+ virtual Status Kill() = 0;
+
+ //------------------------------------------------------------------
+ // Tells a process not to stop the inferior on given signals
+ // and just reinject them back.
+ //------------------------------------------------------------------
+ virtual Status IgnoreSignals(llvm::ArrayRef<int> signals);
//----------------------------------------------------------------------
// Memory and memory region functions
//----------------------------------------------------------------------
- virtual Error GetMemoryRegionInfo(lldb::addr_t load_addr,
- MemoryRegionInfo &range_info);
+ virtual Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info);
- virtual Error ReadMemory(lldb::addr_t addr, void *buf, size_t size,
- size_t &bytes_read) = 0;
+ virtual Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) = 0;
- virtual Error ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size,
- size_t &bytes_read) = 0;
+ virtual Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf,
+ size_t size, size_t &bytes_read) = 0;
- virtual Error WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
- size_t &bytes_written) = 0;
+ virtual Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ size_t &bytes_written) = 0;
- virtual Error AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) = 0;
+ virtual Status AllocateMemory(size_t size, uint32_t permissions,
+ lldb::addr_t &addr) = 0;
- virtual Error DeallocateMemory(lldb::addr_t addr) = 0;
+ virtual Status DeallocateMemory(lldb::addr_t addr) = 0;
virtual lldb::addr_t GetSharedLibraryInfoAddress() = 0;
@@ -96,26 +105,36 @@ public:
//----------------------------------------------------------------------
// Breakpoint functions
//----------------------------------------------------------------------
- virtual Error SetBreakpoint(lldb::addr_t addr, uint32_t size,
- bool hardware) = 0;
+ virtual Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) = 0;
- virtual Error RemoveBreakpoint(lldb::addr_t addr);
+ virtual Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false);
+
+ virtual Status EnableBreakpoint(lldb::addr_t addr);
+
+ virtual Status DisableBreakpoint(lldb::addr_t addr);
+
+ //----------------------------------------------------------------------
+ // Hardware Breakpoint functions
+ //----------------------------------------------------------------------
+ virtual const HardwareBreakpointMap &GetHardwareBreakpointMap() const;
- virtual Error EnableBreakpoint(lldb::addr_t addr);
+ virtual Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size);
- virtual Error DisableBreakpoint(lldb::addr_t addr);
+ virtual Status RemoveHardwareBreakpoint(lldb::addr_t addr);
//----------------------------------------------------------------------
// Watchpoint functions
//----------------------------------------------------------------------
virtual const NativeWatchpointList::WatchpointMap &GetWatchpointMap() const;
- virtual uint32_t GetMaxWatchpoints() const;
+ virtual llvm::Optional<std::pair<uint32_t, uint32_t>>
+ GetHardwareDebugSupportInfo() const;
- virtual Error SetWatchpoint(lldb::addr_t addr, size_t size,
- uint32_t watch_flags, bool hardware);
+ virtual Status SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware);
- virtual Error RemoveWatchpoint(lldb::addr_t addr);
+ virtual Status RemoveWatchpoint(lldb::addr_t addr);
//----------------------------------------------------------------------
// Accessors
@@ -134,15 +153,15 @@ public:
bool GetByteOrder(lldb::ByteOrder &byte_order) const;
+ virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ GetAuxvData() const = 0;
+
//----------------------------------------------------------------------
// Exit Status
//----------------------------------------------------------------------
- virtual bool GetExitStatus(lldb_private::ExitType *exit_type, int *status,
- std::string &exit_description);
+ virtual llvm::Optional<WaitStatus> GetExitStatus();
- virtual bool SetExitStatus(lldb_private::ExitType exit_type, int status,
- const char *exit_description,
- bool bNotifyStateChange);
+ virtual bool SetExitStatus(WaitStatus status, bool bNotifyStateChange);
//----------------------------------------------------------------------
// Access to threads
@@ -219,101 +238,197 @@ public:
//------------------------------------------------------------------
bool UnregisterNativeDelegate(NativeDelegate &native_delegate);
- virtual Error GetLoadedModuleFileSpec(const char *module_path,
- FileSpec &file_spec) = 0;
+ virtual Status GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) = 0;
+
+ virtual Status GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) = 0;
- virtual Error GetFileLoadAddress(const llvm::StringRef &file_name,
- lldb::addr_t &load_addr) = 0;
+ class Factory {
+ public:
+ virtual ~Factory();
+ //------------------------------------------------------------------
+ /// Launch a process for debugging.
+ ///
+ /// @param[in] launch_info
+ /// Information required to launch the process.
+ ///
+ /// @param[in] native_delegate
+ /// The delegate that will receive messages regarding the
+ /// inferior. Must outlive the NativeProcessProtocol
+ /// instance.
+ ///
+ /// @param[in] mainloop
+ /// The mainloop instance with which the process can register
+ /// callbacks. Must outlive the NativeProcessProtocol
+ /// instance.
+ ///
+ /// @return
+ /// A NativeProcessProtocol shared pointer if the operation succeeded or
+ /// an error object if it failed.
+ //------------------------------------------------------------------
+ virtual llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
+ MainLoop &mainloop) const = 0;
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process.
+ ///
+ /// @param[in] pid
+ /// pid of the process locatable
+ ///
+ /// @param[in] native_delegate
+ /// The delegate that will receive messages regarding the
+ /// inferior. Must outlive the NativeProcessProtocol
+ /// instance.
+ ///
+ /// @param[in] mainloop
+ /// The mainloop instance with which the process can register
+ /// callbacks. Must outlive the NativeProcessProtocol
+ /// instance.
+ ///
+ /// @return
+ /// A NativeProcessProtocol shared pointer if the operation succeeded or
+ /// an error object if it failed.
+ //------------------------------------------------------------------
+ virtual llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
+ MainLoop &mainloop) const = 0;
+ };
//------------------------------------------------------------------
- /// Launch a process for debugging. This method will create an concrete
- /// instance of NativeProcessProtocol, based on the host platform.
- /// (e.g. NativeProcessLinux on linux, etc.)
+ /// StartTracing API for starting a tracing instance with the
+ /// TraceOptions on a specific thread or process.
///
- /// @param[in] launch_info
- /// Information required to launch the process.
+ /// @param[in] config
+ /// The configuration to use when starting tracing.
///
- /// @param[in] native_delegate
- /// The delegate that will receive messages regarding the
- /// inferior. Must outlive the NativeProcessProtocol
- /// instance.
+ /// @param[out] error
+ /// Status indicates what went wrong.
///
- /// @param[in] mainloop
- /// The mainloop instance with which the process can register
- /// callbacks. Must outlive the NativeProcessProtocol
- /// instance.
+ /// @return
+ /// The API returns a user_id which can be used to get trace
+ /// data, trace configuration or stopping the trace instance.
+ /// The user_id is a key to identify and operate with a tracing
+ /// instance. It may refer to the complete process or a single
+ /// thread.
+ //------------------------------------------------------------------
+ virtual lldb::user_id_t StartTrace(const TraceOptions &config,
+ Status &error) {
+ error.SetErrorString("Not implemented");
+ return LLDB_INVALID_UID;
+ }
+
+ //------------------------------------------------------------------
+ /// StopTracing API as the name suggests stops a tracing instance.
+ ///
+ /// @param[in] traceid
+ /// The user id of the trace intended to be stopped. Now a
+ /// user_id may map to multiple threads in which case this API
+ /// could be used to stop the tracing for a specific thread by
+ /// supplying its thread id.
///
- /// @param[out] process_sp
- /// On successful return from the method, this parameter
- /// contains the shared pointer to the
- /// NativeProcessProtocol that can be used to manipulate
- /// the native process.
+ /// @param[in] thread
+ /// Thread is needed when the complete process is being traced
+ /// and the user wishes to stop tracing on a particular thread.
///
/// @return
- /// An error object indicating if the operation succeeded,
- /// and if not, what error occurred.
+ /// Status indicating what went wrong.
//------------------------------------------------------------------
- static Error Launch(ProcessLaunchInfo &launch_info,
- NativeDelegate &native_delegate, MainLoop &mainloop,
- NativeProcessProtocolSP &process_sp);
+ virtual Status StopTrace(lldb::user_id_t traceid,
+ lldb::tid_t thread = LLDB_INVALID_THREAD_ID) {
+ return Status("Not implemented");
+ }
//------------------------------------------------------------------
- /// Attach to an existing process. This method will create an concrete
- /// instance of NativeProcessProtocol, based on the host platform.
- /// (e.g. NativeProcessLinux on linux, etc.)
+ /// This API provides the trace data collected in the form of raw
+ /// data.
///
- /// @param[in] pid
- /// pid of the process locatable
- ///
- /// @param[in] native_delegate
- /// The delegate that will receive messages regarding the
- /// inferior. Must outlive the NativeProcessProtocol
+ /// @param[in] traceid thread
+ /// The traceid and thread provide the context for the trace
/// instance.
///
- /// @param[in] mainloop
- /// The mainloop instance with which the process can register
- /// callbacks. Must outlive the NativeProcessProtocol
- /// instance.
+ /// @param[in] buffer
+ /// The buffer provides the destination buffer where the trace
+ /// data would be read to. The buffer should be truncated to the
+ /// filled length by this function.
///
- /// @param[out] process_sp
- /// On successful return from the method, this parameter
- /// contains the shared pointer to the
- /// NativeProcessProtocol that can be used to manipulate
- /// the native process.
+ /// @param[in] offset
+ /// There is possibility to read partially the trace data from
+ /// a specified offset where in such cases the buffer provided
+ /// may be smaller than the internal trace collection container.
///
/// @return
- /// An error object indicating if the operation succeeded,
- /// and if not, what error occurred.
+ /// The size of the data actually read.
//------------------------------------------------------------------
- static Error Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
- MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
+ virtual Status GetData(lldb::user_id_t traceid, lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Status("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// Similar API as above except it aims to provide any extra data
+ /// useful for decoding the actual trace data.
+ //------------------------------------------------------------------
+ virtual Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Status("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// API to query the TraceOptions for a given user id
+ ///
+ /// @param[in] traceid
+ /// The user id of the tracing instance.
+ ///
+ /// @param[in] config
+ /// The thread id of the tracing instance, in case configuration
+ /// for a specific thread is needed should be specified in the
+ /// config.
+ ///
+ /// @param[out] error
+ /// Status indicates what went wrong.
+ ///
+ /// @param[out] config
+ /// The actual configuration being used for tracing.
+ //------------------------------------------------------------------
+ virtual Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) {
+ return Status("Not implemented");
+ }
protected:
lldb::pid_t m_pid;
std::vector<NativeThreadProtocolSP> m_threads;
- lldb::tid_t m_current_thread_id;
+ lldb::tid_t m_current_thread_id = LLDB_INVALID_THREAD_ID;
mutable std::recursive_mutex m_threads_mutex;
- lldb::StateType m_state;
+ lldb::StateType m_state = lldb::eStateInvalid;
mutable std::recursive_mutex m_state_mutex;
- lldb_private::ExitType m_exit_type;
- int m_exit_status;
- std::string m_exit_description;
+ llvm::Optional<WaitStatus> m_exit_status;
+
std::recursive_mutex m_delegates_mutex;
std::vector<NativeDelegate *> m_delegates;
NativeBreakpointList m_breakpoint_list;
NativeWatchpointList m_watchpoint_list;
+ HardwareBreakpointMap m_hw_breakpoints_map;
int m_terminal_fd;
- uint32_t m_stop_id;
+ uint32_t m_stop_id = 0;
+
+ // Set of signal numbers that LLDB directly injects back to inferior
+ // without stopping it.
+ llvm::DenseSet<int> m_signals_to_ignore;
// lldb_private::Host calls should be used to launch a process for debugging,
// and
// then the process should be attached to. When attaching to a process
// lldb_private::Host calls should be used to locate the process to attach to,
// and then this function should be called.
- NativeProcessProtocol(lldb::pid_t pid);
+ NativeProcessProtocol(lldb::pid_t pid, int terminal_fd,
+ NativeDelegate &delegate);
// -----------------------------------------------------------
// Internal interface for state handling
@@ -331,9 +446,9 @@ protected:
// -----------------------------------------------------------
// Internal interface for software breakpoints
// -----------------------------------------------------------
- Error SetSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint);
+ Status SetSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint);
- virtual Error
+ virtual Status
GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint,
size_t &actual_opcode_size,
const uint8_t *&trap_opcode_bytes) = 0;
@@ -351,11 +466,11 @@ protected:
// -----------------------------------------------------------
// Static helper methods for derived classes.
// -----------------------------------------------------------
- static Error ResolveProcessArchitecture(lldb::pid_t pid, ArchSpec &arch);
+ static Status ResolveProcessArchitecture(lldb::pid_t pid, ArchSpec &arch);
private:
void SynchronouslyNotifyProcessStateChanged(lldb::StateType state);
};
-}
+} // namespace lldb_private
#endif // #ifndef liblldb_NativeProcessProtocol_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeRegisterContext.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeRegisterContext.h
index dd583d7..982d81b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeRegisterContext.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeRegisterContext.h
@@ -53,15 +53,15 @@ public:
virtual const RegisterSet *GetRegisterSet(uint32_t set_index) const = 0;
- virtual Error ReadRegister(const RegisterInfo *reg_info,
- RegisterValue &reg_value) = 0;
+ virtual Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) = 0;
- virtual Error WriteRegister(const RegisterInfo *reg_info,
- const RegisterValue &reg_value) = 0;
+ virtual Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) = 0;
- virtual Error ReadAllRegisterValues(lldb::DataBufferSP &data_sp) = 0;
+ virtual Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) = 0;
- virtual Error WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) = 0;
+ virtual Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) = 0;
uint32_t ConvertRegisterKindToRegisterNumber(uint32_t kind,
uint32_t num) const;
@@ -75,6 +75,11 @@ public:
virtual bool ClearHardwareBreakpoint(uint32_t hw_idx);
+ virtual Status ClearAllHardwareBreakpoints();
+
+ virtual Status GetHardwareBreakHitIndex(uint32_t &bp_index,
+ lldb::addr_t trap_addr);
+
virtual uint32_t NumSupportedHardwareWatchpoints();
virtual uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
@@ -82,14 +87,14 @@ public:
virtual bool ClearHardwareWatchpoint(uint32_t hw_index);
- virtual Error ClearAllHardwareWatchpoints();
+ virtual Status ClearAllHardwareWatchpoints();
- virtual Error IsWatchpointHit(uint32_t wp_index, bool &is_hit);
+ virtual Status IsWatchpointHit(uint32_t wp_index, bool &is_hit);
- virtual Error GetWatchpointHitIndex(uint32_t &wp_index,
- lldb::addr_t trap_addr);
+ virtual Status GetWatchpointHitIndex(uint32_t &wp_index,
+ lldb::addr_t trap_addr);
- virtual Error IsWatchpointVacant(uint32_t wp_index, bool &is_vacant);
+ virtual Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant);
virtual lldb::addr_t GetWatchpointAddress(uint32_t wp_index);
@@ -109,12 +114,12 @@ public:
virtual bool HardwareSingleStep(bool enable);
- virtual Error
+ virtual Status
ReadRegisterValueFromMemory(const lldb_private::RegisterInfo *reg_info,
lldb::addr_t src_addr, size_t src_len,
RegisterValue &reg_value);
- virtual Error
+ virtual Status
WriteRegisterValueToMemory(const lldb_private::RegisterInfo *reg_info,
lldb::addr_t dst_addr, size_t dst_len,
const RegisterValue &reg_value);
@@ -136,15 +141,15 @@ public:
virtual lldb::addr_t
GetPCfromBreakpointLocation(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
- Error SetPC(lldb::addr_t pc);
+ Status SetPC(lldb::addr_t pc);
lldb::addr_t GetSP(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
- Error SetSP(lldb::addr_t sp);
+ Status SetSP(lldb::addr_t sp);
lldb::addr_t GetFP(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
- Error SetFP(lldb::addr_t fp);
+ Status SetFP(lldb::addr_t fp);
const char *GetRegisterName(uint32_t reg);
@@ -157,9 +162,9 @@ public:
lldb::addr_t ReadRegisterAsUnsigned(const RegisterInfo *reg_info,
lldb::addr_t fail_value);
- Error WriteRegisterFromUnsigned(uint32_t reg, uint64_t uval);
+ Status WriteRegisterFromUnsigned(uint32_t reg, uint64_t uval);
- Error WriteRegisterFromUnsigned(const RegisterInfo *reg_info, uint64_t uval);
+ Status WriteRegisterFromUnsigned(const RegisterInfo *reg_info, uint64_t uval);
// uint32_t
// GetStopID () const
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeThreadProtocol.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeThreadProtocol.h
index 450e746..d96f713 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeThreadProtocol.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeThreadProtocol.h
@@ -23,7 +23,7 @@ namespace lldb_private {
class NativeThreadProtocol
: public std::enable_shared_from_this<NativeThreadProtocol> {
public:
- NativeThreadProtocol(NativeProcessProtocol *process, lldb::tid_t tid);
+ NativeThreadProtocol(NativeProcessProtocol &process, lldb::tid_t tid);
virtual ~NativeThreadProtocol() {}
@@ -33,31 +33,38 @@ public:
virtual NativeRegisterContextSP GetRegisterContext() = 0;
- virtual Error ReadRegister(uint32_t reg, RegisterValue &reg_value);
+ virtual Status ReadRegister(uint32_t reg, RegisterValue &reg_value);
- virtual Error WriteRegister(uint32_t reg, const RegisterValue &reg_value);
+ virtual Status WriteRegister(uint32_t reg, const RegisterValue &reg_value);
- virtual Error SaveAllRegisters(lldb::DataBufferSP &data_sp);
+ virtual Status SaveAllRegisters(lldb::DataBufferSP &data_sp);
- virtual Error RestoreAllRegisters(lldb::DataBufferSP &data_sp);
+ virtual Status RestoreAllRegisters(lldb::DataBufferSP &data_sp);
virtual bool GetStopReason(ThreadStopInfo &stop_info,
std::string &description) = 0;
lldb::tid_t GetID() const { return m_tid; }
- NativeProcessProtocolSP GetProcess();
+ NativeProcessProtocol &GetProcess() { return m_process; }
// ---------------------------------------------------------------------
// Thread-specific watchpoints
// ---------------------------------------------------------------------
- virtual Error SetWatchpoint(lldb::addr_t addr, size_t size,
- uint32_t watch_flags, bool hardware) = 0;
+ virtual Status SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware) = 0;
- virtual Error RemoveWatchpoint(lldb::addr_t addr) = 0;
+ virtual Status RemoveWatchpoint(lldb::addr_t addr) = 0;
+
+ // ---------------------------------------------------------------------
+ // Thread-specific Hardware Breakpoint routines
+ // ---------------------------------------------------------------------
+ virtual Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) = 0;
+
+ virtual Status RemoveHardwareBreakpoint(lldb::addr_t addr) = 0;
protected:
- NativeProcessProtocolWP m_process_wp;
+ NativeProcessProtocol &m_process;
lldb::tid_t m_tid;
};
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeWatchpointList.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeWatchpointList.h
index 2424e56..02920e6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeWatchpointList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeWatchpointList.h
@@ -10,7 +10,7 @@
#ifndef liblldb_NativeWatchpointList_h_
#define liblldb_NativeWatchpointList_h_
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-forward.h"
#include <map>
@@ -25,10 +25,10 @@ struct NativeWatchpoint {
class NativeWatchpointList {
public:
- Error Add(lldb::addr_t addr, size_t size, uint32_t watch_flags,
- bool hardware);
+ Status Add(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware);
- Error Remove(lldb::addr_t addr);
+ Status Remove(lldb::addr_t addr);
using WatchpointMap = std::map<lldb::addr_t, NativeWatchpoint>;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/SoftwareBreakpoint.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/SoftwareBreakpoint.h
index 703f6bb..e0f235f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/SoftwareBreakpoint.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/SoftwareBreakpoint.h
@@ -18,18 +18,18 @@ class SoftwareBreakpoint : public NativeBreakpoint {
friend class NativeBreakpointList;
public:
- static Error CreateSoftwareBreakpoint(NativeProcessProtocol &process,
- lldb::addr_t addr, size_t size_hint,
- NativeBreakpointSP &breakpoint_spn);
+ static Status CreateSoftwareBreakpoint(NativeProcessProtocol &process,
+ lldb::addr_t addr, size_t size_hint,
+ NativeBreakpointSP &breakpoint_spn);
SoftwareBreakpoint(NativeProcessProtocol &process, lldb::addr_t addr,
const uint8_t *saved_opcodes, const uint8_t *trap_opcodes,
size_t opcode_size);
protected:
- Error DoEnable() override;
+ Status DoEnable() override;
- Error DoDisable() override;
+ Status DoDisable() override;
bool IsSoftwareBreakpoint() const override;
@@ -42,11 +42,11 @@ private:
uint8_t m_trap_opcodes[MAX_TRAP_OPCODE_SIZE];
const size_t m_opcode_size;
- static Error EnableSoftwareBreakpoint(NativeProcessProtocol &process,
- lldb::addr_t addr,
- size_t bp_opcode_size,
- const uint8_t *bp_opcode_bytes,
- uint8_t *saved_opcode_bytes);
+ static Status EnableSoftwareBreakpoint(NativeProcessProtocol &process,
+ lldb::addr_t addr,
+ size_t bp_opcode_size,
+ const uint8_t *bp_opcode_bytes,
+ uint8_t *saved_opcode_bytes);
};
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/TCPSocket.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/TCPSocket.h
index 2ce8d82..0d32a70 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/TCPSocket.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/TCPSocket.h
@@ -11,12 +11,16 @@
#define liblldb_TCPSocket_h_
#include "lldb/Host/Socket.h"
+#include "lldb/Host/SocketAddress.h"
+#include <map>
namespace lldb_private {
class TCPSocket : public Socket {
public:
- TCPSocket(NativeSocket socket, bool should_close);
- TCPSocket(bool child_processes_inherit, Error &error);
+ TCPSocket(bool should_close, bool child_processes_inherit);
+ TCPSocket(NativeSocket socket, bool should_close,
+ bool child_processes_inherit);
+ ~TCPSocket() override;
// returns port number or 0 if error
uint16_t GetLocalPortNumber() const;
@@ -35,10 +39,20 @@ public:
int SetOptionNoDelay();
int SetOptionReuseAddress();
- Error Connect(llvm::StringRef name) override;
- Error Listen(llvm::StringRef name, int backlog) override;
- Error Accept(llvm::StringRef name, bool child_processes_inherit,
- Socket *&conn_socket) override;
+ Status Connect(llvm::StringRef name) override;
+ Status Listen(llvm::StringRef name, int backlog) override;
+ Status Accept(Socket *&conn_socket) override;
+
+ Status CreateSocket(int domain);
+
+ bool IsValid() const override;
+
+private:
+ TCPSocket(NativeSocket socket, const TCPSocket &listen_socket);
+
+ void CloseListenSockets();
+
+ std::map<int, SocketAddress> m_listen_sockets;
};
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/UDPSocket.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/UDPSocket.h
index 153804b..27b2d1d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/UDPSocket.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/UDPSocket.h
@@ -15,21 +15,20 @@
namespace lldb_private {
class UDPSocket : public Socket {
public:
- UDPSocket(bool child_processes_inherit, Error &error);
+ UDPSocket(bool should_close, bool child_processes_inherit);
- static Error Connect(llvm::StringRef name, bool child_processes_inherit,
- Socket *&send_socket, Socket *&recv_socket);
+ static Status Connect(llvm::StringRef name, bool child_processes_inherit,
+ Socket *&socket);
private:
UDPSocket(NativeSocket socket);
size_t Send(const void *buf, const size_t num_bytes) override;
- Error Connect(llvm::StringRef name) override;
- Error Listen(llvm::StringRef name, int backlog) override;
- Error Accept(llvm::StringRef name, bool child_processes_inherit,
- Socket *&socket) override;
+ Status Connect(llvm::StringRef name) override;
+ Status Listen(llvm::StringRef name, int backlog) override;
+ Status Accept(Socket *&socket) override;
- SocketAddress m_send_sockaddr;
+ SocketAddress m_sockaddr;
};
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/Config.h b/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/Config.h
deleted file mode 100644
index 1e9f552..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/Config.h
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- Config.h -----------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-//----------------------------------------------------------------------
-// LLDB currently doesn't have a dynamic configuration mechanism, so we
-// are going to hardcode things for now. Eventually these files will
-// be auto generated by some configuration script that can detect
-// platform functionality availability.
-//----------------------------------------------------------------------
-
-#ifndef liblldb_Platform_Config_h_
-#define liblldb_Platform_Config_h_
-
-#define LLDB_CONFIG_TERMIOS_SUPPORTED 1
-
-#define LLDB_CONFIG_TILDE_RESOLVES_TO_USER 1
-
-//#define LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED 1
-
-//#define LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 1
-
-#endif // #ifndef liblldb_Platform_Config_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/HostInfoFreeBSD.h b/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/HostInfoFreeBSD.h
index a549f87..945ec83 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/HostInfoFreeBSD.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/HostInfoFreeBSD.h
@@ -10,14 +10,13 @@
#ifndef lldb_Host_freebsd_HostInfoFreeBSD_h_
#define lldb_Host_freebsd_HostInfoFreeBSD_h_
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/posix/HostInfoPosix.h"
+#include "lldb/Utility/FileSpec.h"
namespace lldb_private {
class HostInfoFreeBSD : public HostInfoPosix {
public:
- static uint32_t GetMaxThreadNameLength();
static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update);
static bool GetOSBuildString(std::string &s);
static bool GetOSKernelDescription(std::string &s);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/HostThreadFreeBSD.h b/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/HostThreadFreeBSD.h
deleted file mode 100644
index 2f1d6ce..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Host/freebsd/HostThreadFreeBSD.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- HostThreadFreeBSD.h -------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef lldb_Host_freebsd_HostThreadFreeBSD_h_
-#define lldb_Host_freebsd_HostThreadFreeBSD_h_
-
-#include "lldb/Host/posix/HostThreadPosix.h"
-
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringRef.h"
-
-namespace lldb_private {
-
-class HostThreadFreeBSD : public HostThreadPosix {
-public:
- HostThreadFreeBSD();
- HostThreadFreeBSD(lldb::thread_t thread);
-
- static void GetName(lldb::tid_t tid, llvm::SmallVectorImpl<char> &name);
-};
-}
-
-#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/Config.h b/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/Config.h
deleted file mode 100644
index 1e9f552..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/Config.h
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-- Config.h -----------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-//----------------------------------------------------------------------
-// LLDB currently doesn't have a dynamic configuration mechanism, so we
-// are going to hardcode things for now. Eventually these files will
-// be auto generated by some configuration script that can detect
-// platform functionality availability.
-//----------------------------------------------------------------------
-
-#ifndef liblldb_Platform_Config_h_
-#define liblldb_Platform_Config_h_
-
-#define LLDB_CONFIG_TERMIOS_SUPPORTED 1
-
-#define LLDB_CONFIG_TILDE_RESOLVES_TO_USER 1
-
-//#define LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED 1
-
-//#define LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 1
-
-#endif // #ifndef liblldb_Platform_Config_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/HostInfoNetBSD.h b/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/HostInfoNetBSD.h
index 684e54e..9ebff6b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/HostInfoNetBSD.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/HostInfoNetBSD.h
@@ -10,14 +10,13 @@
#ifndef lldb_Host_netbsd_HostInfoNetBSD_h_
#define lldb_Host_netbsd_HostInfoNetBSD_h_
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/posix/HostInfoPosix.h"
+#include "lldb/Utility/FileSpec.h"
namespace lldb_private {
class HostInfoNetBSD : public HostInfoPosix {
public:
- static uint32_t GetMaxThreadNameLength();
static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update);
static bool GetOSBuildString(std::string &s);
static bool GetOSKernelDescription(std::string &s);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/HostThreadNetBSD.h b/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/HostThreadNetBSD.h
deleted file mode 100644
index 385f014..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Host/netbsd/HostThreadNetBSD.h
+++ /dev/null
@@ -1,30 +0,0 @@
-//===-- HostThreadNetBSD.h -------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef lldb_Host_netbsd_HostThreadNetBSD_h_
-#define lldb_Host_netbsd_HostThreadNetBSD_h_
-
-#include "lldb/Host/posix/HostThreadPosix.h"
-
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringRef.h"
-
-namespace lldb_private {
-
-class HostThreadNetBSD : public HostThreadPosix {
-public:
- HostThreadNetBSD();
- HostThreadNetBSD(lldb::thread_t thread);
-
- static void SetName(lldb::thread_t tid, llvm::StringRef &name);
- static void GetName(lldb::thread_t tid, llvm::SmallVectorImpl<char> &name);
-};
-}
-
-#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/openbsd/HostInfoOpenBSD.h b/contrib/llvm/tools/lldb/include/lldb/Host/openbsd/HostInfoOpenBSD.h
new file mode 100644
index 0000000..5a0388f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/openbsd/HostInfoOpenBSD.h
@@ -0,0 +1,27 @@
+//===-- HostInfoOpenBSD.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Host_openbsd_HostInfoOpenBSD_h_
+#define lldb_Host_openbsd_HostInfoOpenBSD_h_
+
+#include "lldb/Host/posix/HostInfoPosix.h"
+#include "lldb/Utility/FileSpec.h"
+
+namespace lldb_private {
+
+class HostInfoOpenBSD : public HostInfoPosix {
+public:
+ static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update);
+ static bool GetOSBuildString(std::string &s);
+ static bool GetOSKernelDescription(std::string &s);
+ static FileSpec GetProgramFileSpec();
+};
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
index f002dd1..b7e08eb 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h
@@ -19,14 +19,14 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Connection.h"
-#include "lldb/Host/IOObject.h"
#include "lldb/Host/Pipe.h"
#include "lldb/Host/Predicate.h"
+#include "lldb/Utility/Connection.h"
+#include "lldb/Utility/IOObject.h"
namespace lldb_private {
-class Error;
+class Status;
class Socket;
class SocketAddress;
@@ -53,20 +53,20 @@ public:
bool IsConnected() const override;
- lldb::ConnectionStatus Connect(llvm::StringRef s, Error *error_ptr) override;
+ lldb::ConnectionStatus Connect(llvm::StringRef s, Status *error_ptr) override;
- lldb::ConnectionStatus Disconnect(Error *error_ptr) override;
+ lldb::ConnectionStatus Disconnect(Status *error_ptr) override;
size_t Read(void *dst, size_t dst_len, const Timeout<std::micro> &timeout,
- lldb::ConnectionStatus &status, Error *error_ptr) override;
+ lldb::ConnectionStatus &status, Status *error_ptr) override;
size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status,
- Error *error_ptr) override;
+ Status *error_ptr) override;
std::string GetURI() override;
lldb::ConnectionStatus BytesAvailable(const Timeout<std::micro> &timeout,
- Error *error_ptr);
+ Status *error_ptr);
bool InterruptRead() override;
@@ -83,21 +83,21 @@ protected:
void CloseCommandPipe();
lldb::ConnectionStatus SocketListenAndAccept(llvm::StringRef host_and_port,
- Error *error_ptr);
+ Status *error_ptr);
lldb::ConnectionStatus ConnectTCP(llvm::StringRef host_and_port,
- Error *error_ptr);
+ Status *error_ptr);
- lldb::ConnectionStatus ConnectUDP(llvm::StringRef args, Error *error_ptr);
+ lldb::ConnectionStatus ConnectUDP(llvm::StringRef args, Status *error_ptr);
lldb::ConnectionStatus NamedSocketConnect(llvm::StringRef socket_name,
- Error *error_ptr);
+ Status *error_ptr);
lldb::ConnectionStatus NamedSocketAccept(llvm::StringRef socket_name,
- Error *error_ptr);
+ Status *error_ptr);
lldb::ConnectionStatus UnixAbstractSocketConnect(llvm::StringRef socket_name,
- Error *error_ptr);
+ Status *error_ptr);
lldb::IOObjectSP m_read_sp;
lldb::IOObjectSP m_write_sp;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/DomainSocket.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/DomainSocket.h
index 3bd4e01..e66b3f9 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/DomainSocket.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/posix/DomainSocket.h
@@ -15,22 +15,20 @@
namespace lldb_private {
class DomainSocket : public Socket {
public:
- DomainSocket(bool child_processes_inherit, Error &error);
+ DomainSocket(bool should_close, bool child_processes_inherit);
- Error Connect(llvm::StringRef name) override;
- Error Listen(llvm::StringRef name, int backlog) override;
- Error Accept(llvm::StringRef name, bool child_processes_inherit,
- Socket *&socket) override;
+ Status Connect(llvm::StringRef name) override;
+ Status Listen(llvm::StringRef name, int backlog) override;
+ Status Accept(Socket *&socket) override;
protected:
- DomainSocket(SocketProtocol protocol, bool child_processes_inherit,
- Error &error);
+ DomainSocket(SocketProtocol protocol, bool child_processes_inherit);
virtual size_t GetNameOffset() const;
virtual void DeleteSocketFile(llvm::StringRef name);
private:
- DomainSocket(NativeSocket socket);
+ DomainSocket(NativeSocket socket, const DomainSocket &listen_socket);
};
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostInfoPosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostInfoPosix.h
index 6d22776..34994ae 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostInfoPosix.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostInfoPosix.h
@@ -10,8 +10,8 @@
#ifndef lldb_Host_posix_HostInfoPosix_h_
#define lldb_Host_posix_HostInfoPosix_h_
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/HostInfoBase.h"
+#include "lldb/Utility/FileSpec.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostProcessPosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostProcessPosix.h
index 1535e67..0a6d882 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostProcessPosix.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostProcessPosix.h
@@ -14,8 +14,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Error.h"
#include "lldb/Host/HostNativeProcessBase.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-types.h"
namespace lldb_private {
@@ -28,11 +28,11 @@ public:
HostProcessPosix(lldb::process_t process);
~HostProcessPosix() override;
- virtual Error Signal(int signo) const;
- static Error Signal(lldb::process_t process, int signo);
+ virtual Status Signal(int signo) const;
+ static Status Signal(lldb::process_t process, int signo);
- Error Terminate() override;
- Error GetMainModule(FileSpec &file_spec) const override;
+ Status Terminate() override;
+ Status GetMainModule(FileSpec &file_spec) const override;
lldb::pid_t GetProcessId() const override;
bool IsRunning() const override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostThreadPosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostThreadPosix.h
index 99b99d7..c230a61 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostThreadPosix.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/posix/HostThreadPosix.h
@@ -22,10 +22,10 @@ public:
HostThreadPosix(lldb::thread_t thread);
~HostThreadPosix() override;
- Error Join(lldb::thread_result_t *result) override;
- Error Cancel() override;
+ Status Join(lldb::thread_result_t *result) override;
+ Status Cancel() override;
- Error Detach();
+ Status Detach();
};
} // namespace lldb_private
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/LockFilePosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/LockFilePosix.h
index dde9bd0..a59a7fe 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/LockFilePosix.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/posix/LockFilePosix.h
@@ -20,15 +20,15 @@ public:
~LockFilePosix() override;
protected:
- Error DoWriteLock(const uint64_t start, const uint64_t len) override;
+ Status DoWriteLock(const uint64_t start, const uint64_t len) override;
- Error DoTryWriteLock(const uint64_t start, const uint64_t len) override;
+ Status DoTryWriteLock(const uint64_t start, const uint64_t len) override;
- Error DoReadLock(const uint64_t start, const uint64_t len) override;
+ Status DoReadLock(const uint64_t start, const uint64_t len) override;
- Error DoTryReadLock(const uint64_t start, const uint64_t len) override;
+ Status DoTryReadLock(const uint64_t start, const uint64_t len) override;
- Error DoUnlock() override;
+ Status DoUnlock() override;
};
} // namespace lldb_private
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/MainLoopPosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/MainLoopPosix.h
deleted file mode 100644
index 21e02be..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/MainLoopPosix.h
+++ /dev/null
@@ -1,104 +0,0 @@
-//===-- MainLoopPosix.h -----------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef lldb_Host_posix_MainLoopPosix_h_
-#define lldb_Host_posix_MainLoopPosix_h_
-
-#include "lldb/Host/MainLoopBase.h"
-
-#include "llvm/ADT/DenseMap.h"
-
-namespace lldb_private {
-
-// Posix implementation of the MainLoopBase class. It can monitor file
-// descriptors for
-// readability using pselect. In addition to the common base, this class
-// provides the ability to
-// invoke a given handler when a signal is received.
-//
-// Since this class is primarily intended to be used for single-threaded
-// processing, it does not
-// attempt to perform any internal synchronisation and any concurrent accesses
-// must be protected
-// externally. However, it is perfectly legitimate to have more than one
-// instance of this class
-// running on separate threads, or even a single thread (with some limitations
-// on signal
-// monitoring).
-// TODO: Add locking if this class is to be used in a multi-threaded context.
-class MainLoopPosix : public MainLoopBase {
-private:
- class SignalHandle;
-
-public:
- typedef std::unique_ptr<SignalHandle> SignalHandleUP;
-
- ~MainLoopPosix() override;
-
- ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp,
- const Callback &callback,
- Error &error) override;
-
- // Listening for signals from multiple MainLoopPosix instances is perfectly
- // safe as long as they
- // don't try to listen for the same signal. The callback function is invoked
- // when the control
- // returns to the Run() function, not when the hander is executed. This means
- // that you can
- // treat the callback as a normal function and perform things which would not
- // be safe in a
- // signal handler. However, since the callback is not invoked synchronously,
- // you cannot use
- // this mechanism to handle SIGSEGV and the like.
- SignalHandleUP RegisterSignal(int signo, const Callback &callback,
- Error &error);
-
- Error Run() override;
-
- // This should only be performed from a callback. Do not attempt to terminate
- // the processing
- // from another thread.
- // TODO: Add synchronization if we want to be terminated from another thread.
- void RequestTermination() override { m_terminate_request = true; }
-
-protected:
- void UnregisterReadObject(IOObject::WaitableHandle handle) override;
-
- void UnregisterSignal(int signo);
-
-private:
- class SignalHandle {
- public:
- ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); }
-
- private:
- SignalHandle(MainLoopPosix &mainloop, int signo)
- : m_mainloop(mainloop), m_signo(signo) {}
-
- MainLoopPosix &m_mainloop;
- int m_signo;
-
- friend class MainLoopPosix;
- DISALLOW_COPY_AND_ASSIGN(SignalHandle);
- };
-
- struct SignalInfo {
- Callback callback;
- struct sigaction old_action;
- bool was_blocked : 1;
- };
-
- llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds;
- llvm::DenseMap<int, SignalInfo> m_signals;
- bool m_terminate_request : 1;
-};
-
-} // namespace lldb_private
-
-#endif // lldb_Host_posix_MainLoopPosix_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/PipePosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/PipePosix.h
index 738f95e..8208b1b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/PipePosix.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/posix/PipePosix.h
@@ -35,12 +35,14 @@ public:
~PipePosix() override;
- Error CreateNew(bool child_process_inherit) override;
- Error CreateNew(llvm::StringRef name, bool child_process_inherit) override;
- Error CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit,
- llvm::SmallVectorImpl<char> &name) override;
- Error OpenAsReader(llvm::StringRef name, bool child_process_inherit) override;
- Error
+ Status CreateNew(bool child_process_inherit) override;
+ Status CreateNew(llvm::StringRef name, bool child_process_inherit) override;
+ Status CreateWithUniqueName(llvm::StringRef prefix,
+ bool child_process_inherit,
+ llvm::SmallVectorImpl<char> &name) override;
+ Status OpenAsReader(llvm::StringRef name,
+ bool child_process_inherit) override;
+ Status
OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit,
const std::chrono::microseconds &timeout) override;
@@ -57,12 +59,12 @@ public:
// Close both descriptors
void Close() override;
- Error Delete(llvm::StringRef name) override;
+ Status Delete(llvm::StringRef name) override;
- Error Write(const void *buf, size_t size, size_t &bytes_written) override;
- Error ReadWithTimeout(void *buf, size_t size,
- const std::chrono::microseconds &timeout,
- size_t &bytes_read) override;
+ Status Write(const void *buf, size_t size, size_t &bytes_written) override;
+ Status ReadWithTimeout(void *buf, size_t size,
+ const std::chrono::microseconds &timeout,
+ size_t &bytes_read) override;
private:
int m_fds[2];
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/ProcessLauncherPosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/ProcessLauncherPosixFork.h
index e481e3d..1193a20 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/ProcessLauncherPosix.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Host/posix/ProcessLauncherPosixFork.h
@@ -1,4 +1,4 @@
-//===-- ProcessLauncherPosix.h ----------------------------------*- C++ -*-===//
+//===-- ProcessLauncherPosixFork.h ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,18 +7,19 @@
//
//===----------------------------------------------------------------------===//
-#ifndef lldb_Host_posix_ProcessLauncherPosix_h_
-#define lldb_Host_posix_ProcessLauncherPosix_h_
+#ifndef lldb_Host_posix_ProcessLauncherPosixFork_h_
+#define lldb_Host_posix_ProcessLauncherPosixFork_h_
#include "lldb/Host/ProcessLauncher.h"
namespace lldb_private {
-class ProcessLauncherPosix : public ProcessLauncher {
+class ProcessLauncherPosixFork : public ProcessLauncher {
public:
HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info,
- Error &error) override;
+ Status &error) override;
};
-}
+
+} // end of namespace lldb_private
#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/Args.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/Args.h
index 6610be1..98046cd 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/Args.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/Args.h
@@ -21,13 +21,14 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
// Project includes
-#include "lldb/Core/Error.h"
-#include "lldb/Host/OptionParser.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-types.h"
#include "lldb/lldb-types.h"
namespace lldb_private {
+struct Option;
+
typedef std::vector<std::tuple<std::string, int, std::string>> OptionArgVector;
typedef std::shared_ptr<OptionArgVector> OptionArgVectorSP;
@@ -193,6 +194,15 @@ public:
const char **GetConstArgumentVector() const;
//------------------------------------------------------------------
+ /// Gets the argument as an ArrayRef. Note that the return value does *not*
+ /// have a nullptr const char * at the end, as the size of the list is
+ /// embedded in the ArrayRef object.
+ //------------------------------------------------------------------
+ llvm::ArrayRef<const char *> GetArgumentArrayRef() const {
+ return llvm::makeArrayRef(m_argv).drop_back();
+ }
+
+ //------------------------------------------------------------------
/// Appends a new argument to the end of the list argument list.
///
/// @param[in] arg_cstr
@@ -312,8 +322,8 @@ public:
///
/// @see class Options
//------------------------------------------------------------------
- Error ParseOptions(Options &options, ExecutionContext *execution_context,
- lldb::PlatformSP platform_sp, bool require_validation);
+ Status ParseOptions(Options &options, ExecutionContext *execution_context,
+ lldb::PlatformSP platform_sp, bool require_validation);
bool IsPositionalArgument(const char *arg);
@@ -367,7 +377,7 @@ public:
static lldb::addr_t StringToAddress(const ExecutionContext *exe_ctx,
llvm::StringRef s,
- lldb::addr_t fail_value, Error *error);
+ lldb::addr_t fail_value, Status *error);
static bool StringToBoolean(llvm::StringRef s, bool fail_value,
bool *success_ptr);
@@ -377,17 +387,17 @@ public:
static int64_t StringToOptionEnum(llvm::StringRef s,
OptionEnumValueElement *enum_values,
- int32_t fail_value, Error &error);
+ int32_t fail_value, Status &error);
static lldb::ScriptLanguage
StringToScriptLanguage(llvm::StringRef s, lldb::ScriptLanguage fail_value,
bool *success_ptr);
// TODO: Use StringRef
- static Error StringToFormat(const char *s, lldb::Format &format,
- size_t *byte_size_ptr); // If non-NULL, then a
- // byte size can precede
- // the format character
+ static Status StringToFormat(const char *s, lldb::Format &format,
+ size_t *byte_size_ptr); // If non-NULL, then a
+ // byte size can precede
+ // the format character
static lldb::Encoding
StringToEncoding(llvm::StringRef s,
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandCompletions.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandCompletions.h
index 2e11735..8bac3e8 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandCompletions.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandCompletions.h
@@ -17,11 +17,14 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/FileSpecList.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/SearchFilter.h"
+#include "lldb/Utility/RegularExpression.h"
#include "lldb/lldb-private.h"
+#include "llvm/ADT/Twine.h"
+
namespace lldb_private {
+class TildeExpressionResolver;
class CommandCompletions {
public:
//----------------------------------------------------------------------
@@ -76,12 +79,19 @@ public:
int max_return_elements, SearchFilter *searcher,
bool &word_complete, StringList &matches);
+ static int DiskFiles(const llvm::Twine &partial_file_name,
+ StringList &matches, TildeExpressionResolver &Resolver);
+
static int DiskDirectories(CommandInterpreter &interpreter,
llvm::StringRef partial_file_name,
int match_start_point, int max_return_elements,
SearchFilter *searcher, bool &word_complete,
StringList &matches);
+ static int DiskDirectories(const llvm::Twine &partial_file_name,
+ StringList &matches,
+ TildeExpressionResolver &Resolver);
+
static int SourceFiles(CommandInterpreter &interpreter,
llvm::StringRef partial_file_name,
int match_start_point, int max_return_elements,
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandHistory.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandHistory.h
index f1a6c85..faef220 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandHistory.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandHistory.h
@@ -18,7 +18,7 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandInterpreter.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandInterpreter.h
index 00dec51..73bd7d6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -19,13 +19,13 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/IOHandler.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandAlias.h"
#include "lldb/Interpreter/CommandHistory.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StringList.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private.h"
@@ -510,7 +510,7 @@ protected:
StringList *matches = nullptr) const;
private:
- Error PreprocessCommand(std::string &command);
+ Status PreprocessCommand(std::string &command);
// Completely resolves aliases and abbreviations, returning a pointer to the
// final command object and updating command_line to the fully substituted
@@ -539,7 +539,7 @@ private:
std::string m_repeat_command; // Stores the command that will be executed for
// an empty command string.
lldb::ScriptInterpreterSP m_script_interpreter_sp;
- std::mutex m_script_interpreter_mutex;
+ std::recursive_mutex m_script_interpreter_mutex;
lldb::IOHandlerSP m_command_io_handler_sp;
char m_comment_char;
bool m_batch_command_mode;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObject.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObject.h
index 9104fd8..ff4c829 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObject.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObject.h
@@ -18,11 +18,12 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Flags.h"
-#include "lldb/Core/StringList.h"
+#include "lldb/Utility/Flags.h"
+
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Utility/StringList.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObjectRegexCommand.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObjectRegexCommand.h
index 44dc4f2..50dbebc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObjectRegexCommand.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandObjectRegexCommand.h
@@ -16,8 +16,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Utility/RegularExpression.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandReturnObject.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandReturnObject.h
index 40db563..7b04c39 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandReturnObject.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandReturnObject.h
@@ -16,8 +16,8 @@
// Project includes
#include "lldb/Core/STLUtils.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/StreamTee.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StreamTee.h"
#include "lldb/lldb-private.h"
#include "llvm/ADT/StringRef.h"
@@ -129,7 +129,7 @@ public:
AppendError(llvm::formatv(format, std::forward<Args>(args)...).str());
}
- void SetError(const Error &error, const char *fallback_error_cstr = nullptr);
+ void SetError(const Status &error, const char *fallback_error_cstr = nullptr);
void SetError(llvm::StringRef error_cstr);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupArchitecture.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupArchitecture.h
index 742cd6d..e73a534 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupArchitecture.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupArchitecture.h
@@ -31,8 +31,8 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupBoolean.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupBoolean.h
index 931a6d7..53d08d7 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupBoolean.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupBoolean.h
@@ -38,9 +38,9 @@ public:
return llvm::ArrayRef<OptionDefinition>(&m_option_definition, 1);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFile.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFile.h
index 93e3ed7..d0c25b8 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFile.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFile.h
@@ -37,9 +37,9 @@ public:
return llvm::ArrayRef<OptionDefinition>(&m_option_definition, 1);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
@@ -70,9 +70,9 @@ public:
return llvm::ArrayRef<OptionDefinition>(&m_option_definition, 1);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFormat.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFormat.h
index f3a4203..ddf2cce 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFormat.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupFormat.h
@@ -43,9 +43,9 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupOutputFile.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupOutputFile.h
index cb891f0..19453c6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupOutputFile.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupOutputFile.h
@@ -31,9 +31,9 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupPlatform.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupPlatform.h
index c51ff5c..e796624 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupPlatform.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupPlatform.h
@@ -14,8 +14,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Interpreter/Options.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
@@ -36,15 +36,15 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
lldb::PlatformSP CreatePlatformWithOptions(CommandInterpreter &interpreter,
const ArchSpec &arch,
- bool make_selected, Error &error,
+ bool make_selected, Status &error,
ArchSpec &platform_arch) const;
bool PlatformWasSpecified() const { return !m_platform_name.empty(); }
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupString.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupString.h
index 21bfc08..01e8aa9 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupString.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupString.h
@@ -35,9 +35,9 @@ public:
return llvm::ArrayRef<OptionDefinition>(&m_option_definition, 1);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUInt64.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUInt64.h
index 3f04eac..82eb0e2 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUInt64.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUInt64.h
@@ -36,9 +36,9 @@ public:
return llvm::ArrayRef<OptionDefinition>(&m_option_definition, 1);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUUID.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUUID.h
index 9a7c6cf..def97d5 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUUID.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupUUID.h
@@ -31,9 +31,9 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h
index 694464b..0e07577 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h
@@ -31,9 +31,9 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupVariable.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupVariable.h
index 0735de4..c9e9032 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupVariable.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupVariable.h
@@ -31,9 +31,9 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
index c67c8f0..f266563 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
@@ -32,9 +32,9 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
- Error SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValue.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValue.h
index 2c1d5df..6008e1e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValue.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValue.h
@@ -14,10 +14,12 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/FormatEntity.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-defines.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "lldb/lldb-private-interfaces.h"
namespace lldb_private {
@@ -89,7 +91,7 @@ public:
virtual void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) = 0;
- virtual Error
+ virtual Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign);
@@ -106,15 +108,16 @@ public:
// Subclasses can override these functions
//-----------------------------------------------------------------
virtual lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx,
- llvm::StringRef name, bool will_modify,
- Error &error) const {
+ llvm::StringRef name,
+ bool will_modify,
+ Status &error) const {
error.SetErrorStringWithFormat("'%s' is not a value subvalue", name.str().c_str());
return lldb::OptionValueSP();
}
- virtual Error SetSubValue(const ExecutionContext *exe_ctx,
- VarSetOperationType op, llvm::StringRef name,
- llvm::StringRef value);
+ virtual Status SetSubValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op, llvm::StringRef name,
+ llvm::StringRef value);
virtual bool IsAggregateValue() const { return false; }
@@ -178,7 +181,7 @@ public:
static lldb::OptionValueSP
CreateValueFromCStringForTypeMask(const char *value_cstr, uint32_t type_mask,
- Error &error);
+ Status &error);
// Get this value as a uint64_t value if it is encoded as a boolean,
// uint64_t or int64_t. Other types will cause "fail_value" to be
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArch.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArch.h
index aa54812..e1a354d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArch.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArch.h
@@ -46,10 +46,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArray.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArray.h
index 1e568ca..bbf4e37 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArray.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueArray.h
@@ -36,10 +36,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
@@ -55,7 +55,7 @@ public:
lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx,
llvm::StringRef name, bool will_modify,
- Error &error) const override;
+ Status &error) const override;
//---------------------------------------------------------------------
// Subclass specific functions
@@ -122,7 +122,7 @@ public:
size_t GetArgs(Args &args) const;
- Error SetArgs(const Args &args, VarSetOperationType op);
+ Status SetArgs(const Args &args, VarSetOperationType op);
protected:
typedef std::vector<lldb::OptionValueSP> collection;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueBoolean.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueBoolean.h
index d429c05..1ff84dd 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueBoolean.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueBoolean.h
@@ -37,10 +37,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueChar.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueChar.h
index d186447..0c5f602 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueChar.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueChar.h
@@ -38,10 +38,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueDictionary.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueDictionary.h
index 5d015a5..4e8c860 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueDictionary.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueDictionary.h
@@ -38,7 +38,7 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
@@ -66,10 +66,10 @@ public:
lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx,
llvm::StringRef name, bool will_modify,
- Error &error) const override;
+ Status &error) const override;
- Error SetSubValue(const ExecutionContext *exe_ctx, VarSetOperationType op,
- llvm::StringRef name, llvm::StringRef value) override;
+ Status SetSubValue(const ExecutionContext *exe_ctx, VarSetOperationType op,
+ llvm::StringRef name, llvm::StringRef value) override;
bool SetValueForKey(const ConstString &key,
const lldb::OptionValueSP &value_sp,
@@ -79,7 +79,7 @@ public:
size_t GetArgs(Args &args) const;
- Error SetArgs(const Args &args, VarSetOperationType op);
+ Status SetArgs(const Args &args, VarSetOperationType op);
protected:
typedef std::map<ConstString, lldb::OptionValueSP> collection;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueEnumeration.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueEnumeration.h
index 273e69c..4aa8823 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueEnumeration.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueEnumeration.h
@@ -10,16 +10,13 @@
#ifndef liblldb_OptionValueEnumeration_h_
#define liblldb_OptionValueEnumeration_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-private-types.h"
namespace lldb_private {
@@ -47,10 +44,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpec.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpec.h
index 8020aa7..b53c034 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpec.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpec.h
@@ -12,7 +12,7 @@
#include "lldb/Interpreter/OptionValue.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
#include "llvm/Support/Chrono.h"
namespace lldb_private {
@@ -37,10 +37,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h
index 1e42362..9529fbc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h
@@ -37,10 +37,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormat.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormat.h
index 5351aec..ce79970 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormat.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormat.h
@@ -38,10 +38,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h
index 472cd9e..e5a65b7 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h
@@ -34,10 +34,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueLanguage.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueLanguage.h
index a388a6a..8f81c5d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueLanguage.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueLanguage.h
@@ -41,10 +41,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValuePathMappings.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValuePathMappings.h
index d5336aa..0e2e98d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValuePathMappings.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValuePathMappings.h
@@ -35,10 +35,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueProperties.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueProperties.h
index bb4202a..16d31aa 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueProperties.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueProperties.h
@@ -16,11 +16,11 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Interpreter/Property.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
@@ -43,7 +43,7 @@ public:
lldb::OptionValueSP DeepCopy() const override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
@@ -52,9 +52,9 @@ public:
ConstString GetName() const override { return m_name; }
- virtual Error DumpPropertyValue(const ExecutionContext *exe_ctx, Stream &strm,
- llvm::StringRef property_path,
- uint32_t dump_mask);
+ virtual Status DumpPropertyValue(const ExecutionContext *exe_ctx,
+ Stream &strm, llvm::StringRef property_path,
+ uint32_t dump_mask);
virtual void DumpAllDescriptions(CommandInterpreter &interpreter,
Stream &strm) const;
@@ -110,11 +110,12 @@ public:
bool value_will_be_modified) const;
lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx,
- llvm::StringRef name, bool value_will_be_modified,
- Error &error) const override;
+ llvm::StringRef name,
+ bool value_will_be_modified,
+ Status &error) const override;
- Error SetSubValue(const ExecutionContext *exe_ctx, VarSetOperationType op,
- llvm::StringRef path, llvm::StringRef value) override;
+ Status SetSubValue(const ExecutionContext *exe_ctx, VarSetOperationType op,
+ llvm::StringRef path, llvm::StringRef value) override;
virtual bool PredicateMatches(const ExecutionContext *exe_ctx,
llvm::StringRef predicate) const {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueRegex.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueRegex.h
index 7125daf..afe9318 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueRegex.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueRegex.h
@@ -14,8 +14,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Utility/RegularExpression.h"
namespace lldb_private {
@@ -35,10 +35,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueSInt64.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueSInt64.h
index 1e16478..a6893d2 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueSInt64.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueSInt64.h
@@ -50,10 +50,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueString.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueString.h
index 5b42003..4a9f222 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueString.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueString.h
@@ -16,14 +16,15 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Flags.h"
+#include "lldb/Utility/Flags.h"
+
#include "lldb/Interpreter/OptionValue.h"
namespace lldb_private {
class OptionValueString : public OptionValue {
public:
- typedef Error (*ValidatorCallback)(const char *string, void *baton);
+ typedef Status (*ValidatorCallback)(const char *string, void *baton);
enum Options { eOptionEncodeCharacterEscapeSequences = (1u << 0) };
@@ -84,10 +85,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
@@ -118,10 +119,10 @@ public:
const char *GetDefaultValue() const { return m_default_value.c_str(); }
llvm::StringRef GetDefaultValueAsRef() const { return m_default_value; }
- Error SetCurrentValue(const char *) = delete;
- Error SetCurrentValue(llvm::StringRef value);
+ Status SetCurrentValue(const char *) = delete;
+ Status SetCurrentValue(llvm::StringRef value);
- Error AppendToCurrentValue(const char *value);
+ Status AppendToCurrentValue(const char *value);
void SetDefaultValue(const char *value) {
if (value && value[0])
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUInt64.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUInt64.h
index cbf932b..be13ff0 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUInt64.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUInt64.h
@@ -38,8 +38,8 @@ public:
// string isn't a uint64_t value or any other error occurs, return an
// empty lldb::OptionValueSP and fill error in with the correct stuff.
//---------------------------------------------------------------------
- static lldb::OptionValueSP Create(const char *, Error &) = delete;
- static lldb::OptionValueSP Create(llvm::StringRef value_str, Error &error);
+ static lldb::OptionValueSP Create(const char *, Status &) = delete;
+ static lldb::OptionValueSP Create(llvm::StringRef value_str, Status &error);
//---------------------------------------------------------------------
// Virtual subclass pure virtual overrides
//---------------------------------------------------------------------
@@ -49,10 +49,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUUID.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUUID.h
index 841de88..6e0aeeb 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUUID.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/OptionValueUUID.h
@@ -14,7 +14,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/UUID.h"
+#include "lldb/Utility/UUID.h"
#include "lldb/Interpreter/OptionValue.h"
namespace lldb_private {
@@ -36,10 +36,10 @@ public:
void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) override;
- Error
+ Status
SetValueFromString(llvm::StringRef value,
VarSetOperationType op = eVarSetOperationAssign) override;
- Error
+ Status
SetValueFromString(const char *,
VarSetOperationType = eVarSetOperationAssign) = delete;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/Options.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/Options.h
index fc5ff97..8712100 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/Options.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/Options.h
@@ -38,7 +38,7 @@ static inline bool isprint8(int ch) {
/// Options is designed to be subclassed to contain all needed
/// options for a given command. The options can be parsed by calling:
/// \code
-/// Error Args::ParseOptions (Options &);
+/// Status Args::ParseOptions (Options &);
/// \endcode
///
/// The options are specified using the format defined for the libc
@@ -62,11 +62,11 @@ static inline bool isprint8(int ch) {
/// return g_options;
/// }
///
-/// virtual Error
+/// virtual Status
/// SetOptionValue (uint32_t option_idx, int option_val, const char
/// *option_arg)
/// {
-/// Error error;
+/// Status error;
/// switch (option_val)
/// {
/// case 'g': debug = true; break;
@@ -171,7 +171,7 @@ public:
// prone and subclasses shouldn't have to do it.
void NotifyOptionParsingStarting(ExecutionContext *execution_context);
- Error NotifyOptionParsingFinished(ExecutionContext *execution_context);
+ Status NotifyOptionParsingFinished(ExecutionContext *execution_context);
//------------------------------------------------------------------
/// Set the value of an option.
@@ -192,8 +192,8 @@ public:
/// @see Args::ParseOptions (Options&)
/// @see man getopt_long_only
//------------------------------------------------------------------
- virtual Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) = 0;
+ virtual Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) = 0;
//------------------------------------------------------------------
/// Handles the generic bits of figuring out whether we are in an
@@ -324,10 +324,10 @@ protected:
// all option settings to default values.
virtual void OptionParsingStarting(ExecutionContext *execution_context) = 0;
- virtual Error OptionParsingFinished(ExecutionContext *execution_context) {
+ virtual Status OptionParsingFinished(ExecutionContext *execution_context) {
// If subclasses need to know when the options are done being parsed
// they can implement this function to do extra checking
- Error error;
+ Status error;
return error;
}
};
@@ -340,16 +340,16 @@ public:
virtual llvm::ArrayRef<OptionDefinition> GetDefinitions() = 0;
- virtual Error SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_value,
- ExecutionContext *execution_context) = 0;
+ virtual Status SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_value,
+ ExecutionContext *execution_context) = 0;
virtual void OptionParsingStarting(ExecutionContext *execution_context) = 0;
- virtual Error OptionParsingFinished(ExecutionContext *execution_context) {
+ virtual Status OptionParsingFinished(ExecutionContext *execution_context) {
// If subclasses need to know when the options are done being parsed
// they can implement this function to do extra checking
- Error error;
+ Status error;
return error;
}
};
@@ -401,12 +401,12 @@ public:
bool DidFinalize() { return m_did_finalize; }
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override;
void OptionParsingStarting(ExecutionContext *execution_context) override;
- Error OptionParsingFinished(ExecutionContext *execution_context) override;
+ Status OptionParsingFinished(ExecutionContext *execution_context) override;
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
assert(m_did_finalize);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/Property.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/Property.h
index e09df5c..9d0dc5f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/Property.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/Property.h
@@ -10,16 +10,13 @@
#ifndef liblldb_Property_h_
#define liblldb_Property_h_
-// C Includes
-// C++ Includes
-#include <string>
-
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Flags.h"
#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Flags.h"
#include "lldb/lldb-defines.h"
+#include "lldb/lldb-private-types.h"
+
+#include <string>
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 3fdba08..335231c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -18,11 +18,11 @@
#include "lldb/Breakpoint/BreakpointOptions.h"
#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StructuredData.h"
-#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Host/PseudoTerminal.h"
namespace lldb_private {
@@ -107,24 +107,24 @@ public:
return true;
}
- virtual Error ExecuteMultipleLines(
+ virtual Status ExecuteMultipleLines(
const char *in_string,
const ExecuteScriptOptions &options = ExecuteScriptOptions()) {
- Error error;
+ Status error;
error.SetErrorString("not implemented");
return error;
}
- virtual Error
+ virtual Status
ExportFunctionDefinitionToInterpreter(StringList &function_def) {
- Error error;
+ Status error;
error.SetErrorString("not implemented");
return error;
}
- virtual Error GenerateBreakpointCommandCallbackData(StringList &input,
- std::string &output) {
- Error error;
+ virtual Status GenerateBreakpointCommandCallbackData(StringList &input,
+ std::string &output) {
+ Status error;
error.SetErrorString("not implemented");
return error;
}
@@ -235,19 +235,19 @@ public:
}
virtual StructuredData::ObjectSP
- LoadPluginModule(const FileSpec &file_spec, lldb_private::Error &error) {
+ LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) {
return StructuredData::ObjectSP();
}
virtual StructuredData::DictionarySP
GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target,
- const char *setting_name, lldb_private::Error &error) {
+ const char *setting_name, lldb_private::Status &error) {
return StructuredData::DictionarySP();
}
- virtual Error GenerateFunction(const char *signature,
- const StringList &input) {
- Error error;
+ virtual Status GenerateFunction(const char *signature,
+ const StringList &input) {
+ Status error;
error.SetErrorString("unimplemented");
return error;
}
@@ -260,22 +260,22 @@ public:
CommandReturnObject &result);
/// Set the specified text as the callback for the breakpoint.
- Error
+ Status
SetBreakpointCommandCallback(std::vector<BreakpointOptions *> &bp_options_vec,
const char *callback_text);
- virtual Error SetBreakpointCommandCallback(BreakpointOptions *bp_options,
- const char *callback_text) {
- Error error;
+ virtual Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
+ const char *callback_text) {
+ Status error;
error.SetErrorString("unimplemented");
return error;
}
/// This one is for deserialization:
- virtual Error SetBreakpointCommandCallback(
+ virtual Status SetBreakpointCommandCallback(
BreakpointOptions *bp_options,
std::unique_ptr<BreakpointOptions::CommandData> &data_up) {
- Error error;
+ Status error;
error.SetErrorString("unimplemented");
return error;
}
@@ -346,7 +346,7 @@ public:
RunScriptBasedCommand(const char *impl_function, const char *args,
ScriptedCommandSynchronicity synchronicity,
lldb_private::CommandReturnObject &cmd_retobj,
- Error &error,
+ Status &error,
const lldb_private::ExecutionContext &exe_ctx) {
return false;
}
@@ -355,40 +355,40 @@ public:
RunScriptBasedCommand(StructuredData::GenericSP impl_obj_sp, const char *args,
ScriptedCommandSynchronicity synchronicity,
lldb_private::CommandReturnObject &cmd_retobj,
- Error &error,
+ Status &error,
const lldb_private::ExecutionContext &exe_ctx) {
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function,
Process *process, std::string &output,
- Error &error) {
+ Status &error) {
error.SetErrorString("unimplemented");
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function, Thread *thread,
- std::string &output, Error &error) {
+ std::string &output, Status &error) {
error.SetErrorString("unimplemented");
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function, Target *target,
- std::string &output, Error &error) {
+ std::string &output, Status &error) {
error.SetErrorString("unimplemented");
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function,
StackFrame *frame, std::string &output,
- Error &error) {
+ Status &error) {
error.SetErrorString("unimplemented");
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function,
ValueObject *value, std::string &output,
- Error &error) {
+ Status &error) {
error.SetErrorString("unimplemented");
return false;
}
@@ -420,7 +420,7 @@ public:
virtual bool
LoadScriptingModule(const char *filename, bool can_reload, bool init_session,
- lldb_private::Error &error,
+ lldb_private::Status &error,
StructuredData::ObjectSP *module_sp = nullptr) {
error.SetErrorString("loading unimplemented");
return false;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/ArmUnwindInfo.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/ArmUnwindInfo.h
index cc80c0f..ef67a31 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/ArmUnwindInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/ArmUnwindInfo.h
@@ -12,9 +12,9 @@
#include <vector>
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/lldb-private.h"
/*
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Block.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Block.h
index eb96318..a5387cc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Block.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Block.h
@@ -18,11 +18,12 @@
// Project includes
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/RangeMap.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/LineEntry.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolContextScope.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/ClangASTContext.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/ClangASTContext.h
index 1d7d291..08f5175 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/ClangASTContext.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/ClangASTContext.h
@@ -31,9 +31,9 @@
// Project includes
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
#include "lldb/Core/ClangForward.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-enumerations.h"
class DWARFASTParserClang;
@@ -275,17 +275,16 @@ public:
bool IsValid() const {
if (args.empty())
return false;
- return args.size() == names.size();
- }
-
- size_t GetSize() const {
- if (IsValid())
- return args.size();
- return 0;
+ return args.size() == names.size() &&
+ ((bool)pack_name == (bool)packed_args) &&
+ (!packed_args || !packed_args->packed_args);
}
llvm::SmallVector<const char *, 2> names;
llvm::SmallVector<clang::TemplateArgument, 2> args;
+
+ const char * pack_name = nullptr;
+ std::unique_ptr<TemplateParameterInfos> packed_args;
};
clang::FunctionTemplateDecl *
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompactUnwindInfo.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompactUnwindInfo.h
index 133a886..6300672 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompactUnwindInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompactUnwindInfo.h
@@ -13,10 +13,10 @@
#include <mutex>
#include <vector>
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompileUnit.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompileUnit.h
index 8465f3b..e7a1ebc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompileUnit.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompileUnit.h
@@ -12,10 +12,10 @@
#include "lldb/Core/FileSpecList.h"
#include "lldb/Core/ModuleChild.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Symbol/DebugMacros.h"
#include "lldb/Symbol/Function.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-enumerations.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDecl.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDecl.h
index a612fb6..5d744d9 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDecl.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDecl.h
@@ -10,8 +10,8 @@
#ifndef liblldb_CompilerDecl_h_
#define liblldb_CompilerDecl_h_
-#include "lldb/Core/ConstString.h"
#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDeclContext.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDeclContext.h
index e4f3e74..179a1be 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDeclContext.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerDeclContext.h
@@ -12,7 +12,7 @@
#include <vector>
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerType.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerType.h
index 6822160..c5bca54 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerType.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/CompilerType.h
@@ -23,6 +23,8 @@
namespace lldb_private {
+class DataExtractor;
+
//----------------------------------------------------------------------
// A class that can carry around a clang ASTContext and a opaque clang
// QualType. A clang::QualType can be easily reconstructed from an
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
index c221a36..a1bd1bc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
@@ -14,13 +14,13 @@
#include <mutex>
#include "lldb/Core/AddressRange.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Flags.h"
+#include "lldb/Utility/Flags.h"
+
#include "lldb/Core/RangeMap.h"
-#include "lldb/Core/VMRange.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/VMRange.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
@@ -34,10 +34,11 @@ namespace lldb_private {
class DWARFCallFrameInfo {
public:
- DWARFCallFrameInfo(ObjectFile &objfile, lldb::SectionSP &section,
- lldb::RegisterKind reg_kind, bool is_eh_frame);
+ enum Type { EH, DWARF };
+
+ DWARFCallFrameInfo(ObjectFile &objfile, lldb::SectionSP &section, Type type);
- ~DWARFCallFrameInfo();
+ ~DWARFCallFrameInfo() = default;
// Locate an AddressRange that includes the provided Address in this
// object's eh_frame/debug_info
@@ -74,12 +75,20 @@ public:
private:
enum { CFI_AUG_MAX_SIZE = 8, CFI_HEADER_SIZE = 8 };
+ enum CFIVersion {
+ CFI_VERSION1 = 1, // DWARF v.2
+ CFI_VERSION3 = 3, // DWARF v.3
+ CFI_VERSION4 = 4 // DWARF v.4, v.5
+ };
struct CIE {
dw_offset_t cie_offset;
uint8_t version;
char augmentation[CFI_AUG_MAX_SIZE]; // This is typically empty or very
// short.
+ uint8_t address_size = sizeof(uint32_t); // The size of a target address.
+ uint8_t segment_size = 0; // The size of a segment selector.
+
uint32_t code_align;
int32_t data_align;
uint32_t return_addr_reg_num;
@@ -134,21 +143,24 @@ private:
ObjectFile &m_objfile;
lldb::SectionSP m_section_sp;
- lldb::RegisterKind m_reg_kind;
- Flags m_flags;
+ Flags m_flags = 0;
cie_map_t m_cie_map;
DataExtractor m_cfi_data;
- bool m_cfi_data_initialized; // only copy the section into the DE once
+ bool m_cfi_data_initialized = false; // only copy the section into the DE once
FDEEntryMap m_fde_index;
- bool m_fde_index_initialized; // only scan the section for FDEs once
+ bool m_fde_index_initialized = false; // only scan the section for FDEs once
std::mutex m_fde_index_mutex; // and isolate the thread that does it
- bool m_is_eh_frame;
+ Type m_type;
CIESP
ParseCIE(const uint32_t cie_offset);
+
+ lldb::RegisterKind GetRegisterKind() const {
+ return m_type == EH ? lldb::eRegisterKindEHFrame : lldb::eRegisterKindDWARF;
+ }
};
} // namespace lldb_private
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/DebugMacros.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/DebugMacros.h
index 4d4a327..640da02 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/DebugMacros.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/DebugMacros.h
@@ -17,7 +17,7 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/DeclVendor.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/DeclVendor.h
index 5ee8b19..16d514f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/DeclVendor.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/DeclVendor.h
@@ -11,6 +11,7 @@
#define liblldb_DeclVendor_h_
#include "lldb/Core/ClangForward.h"
+#include "lldb/lldb-defines.h"
#include <vector>
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Declaration.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Declaration.h
index 1846e2f..581176e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Declaration.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Declaration.h
@@ -10,7 +10,7 @@
#ifndef liblldb_Declaration_h_
#define liblldb_Declaration_h_
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/FuncUnwinders.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/FuncUnwinders.h
index a5b9b80..64c222c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/FuncUnwinders.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/FuncUnwinders.h
@@ -99,6 +99,13 @@ public:
Thread &thread,
int current_offset);
+ lldb::UnwindPlanSP GetDebugFrameUnwindPlan(Target &target,
+ int current_offset);
+
+ lldb::UnwindPlanSP GetDebugFrameAugmentedUnwindPlan(Target &target,
+ Thread &thread,
+ int current_offset);
+
lldb::UnwindPlanSP GetCompactUnwindUnwindPlan(Target &target,
int current_offset);
@@ -126,10 +133,12 @@ private:
lldb::UnwindPlanSP m_unwind_plan_assembly_sp;
lldb::UnwindPlanSP m_unwind_plan_eh_frame_sp;
- lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp; // augmented by
- // assembly inspection
- // so it's valid
- // everywhere
+ lldb::UnwindPlanSP m_unwind_plan_debug_frame_sp;
+
+ // augmented by assembly inspection so it's valid everywhere
+ lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp;
+ lldb::UnwindPlanSP m_unwind_plan_debug_frame_augmented_sp;
+
std::vector<lldb::UnwindPlanSP> m_unwind_plan_compact_unwind;
lldb::UnwindPlanSP m_unwind_plan_arm_unwind_sp;
lldb::UnwindPlanSP m_unwind_plan_fast_sp;
@@ -139,7 +148,9 @@ private:
// Fetching the UnwindPlans can be expensive - if we've already attempted
// to get one & failed, don't try again.
bool m_tried_unwind_plan_assembly : 1, m_tried_unwind_plan_eh_frame : 1,
+ m_tried_unwind_plan_debug_frame : 1,
m_tried_unwind_plan_eh_frame_augmented : 1,
+ m_tried_unwind_plan_debug_frame_augmented : 1,
m_tried_unwind_plan_compact_unwind : 1,
m_tried_unwind_plan_arm_unwind : 1, m_tried_unwind_fast : 1,
m_tried_unwind_arch_default : 1,
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Function.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Function.h
index 232d079..9d37600 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Function.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Function.h
@@ -12,10 +12,10 @@
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/Mangled.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Expression/DWARFExpression.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Declaration.h"
+#include "lldb/Utility/UserID.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/GoASTContext.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/GoASTContext.h
index 5530a35..6feac7a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/GoASTContext.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/GoASTContext.h
@@ -20,9 +20,9 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/JavaASTContext.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/JavaASTContext.h
index 6e97674..4fdd237 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/JavaASTContext.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/JavaASTContext.h
@@ -18,8 +18,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/LineEntry.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/LineEntry.h
index 3076ec4..b9a1a14 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/LineEntry.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/LineEntry.h
@@ -11,7 +11,7 @@
#define liblldb_LineEntry_h_
#include "lldb/Core/AddressRange.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/OCamlASTContext.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/OCamlASTContext.h
index 9560866..a261d43 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/OCamlASTContext.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/OCamlASTContext.h
@@ -21,9 +21,9 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectContainer.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectContainer.h
index 6f38b50..1103792 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectContainer.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectContainer.h
@@ -14,11 +14,11 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/ModuleChild.h"
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Host/Endian.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h
index e2e4500..a4c7b01 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h
@@ -10,14 +10,15 @@
#ifndef liblldb_ObjectFile_h_
#define liblldb_ObjectFile_h_
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/FileSpecList.h"
#include "lldb/Core/ModuleChild.h"
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Host/Endian.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Symbol/Symtab.h"
#include "lldb/Symbol/UnwindTable.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/UUID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
@@ -563,6 +564,45 @@ public:
virtual uint32_t GetNumThreadContexts() { return 0; }
+ //------------------------------------------------------------------
+ /// Some object files may have an identifier string embedded in them,
+ /// e.g. in a Mach-O core file using the LC_IDENT load command (which
+ /// is obsolete, but can still be found in some old files)
+ ///
+ /// @return
+ /// Returns the identifier string if one exists, else an empty
+ /// string.
+ //------------------------------------------------------------------
+ virtual std::string GetIdentifierString () {
+ return std::string();
+ }
+
+ //------------------------------------------------------------------
+ /// When the ObjectFile is a core file, lldb needs to locate the
+ /// "binary" in the core file. lldb can iterate over the pages looking
+ /// for a valid binary, but some core files may have metadata
+ /// describing where the main binary is exactly which removes ambiguity
+ /// when there are multiple binaries present in the captured memory pages.
+ ///
+ /// @param[out] address
+ /// If the address of the binary is specified, this will be set.
+ /// This is an address is the virtual address space of the core file
+ /// memory segments; it is not an offset into the object file.
+ /// If no address is available, will be set to LLDB_INVALID_ADDRESS.
+ ///
+ /// @param[out] uuid
+ /// If the uuid of the binary is specified, this will be set.
+ /// If no UUID is available, will be cleared.
+ ///
+ /// @return
+ /// Returns true if either address or uuid has been set.
+ //------------------------------------------------------------------
+ virtual bool GetCorefileMainBinaryInfo (lldb::addr_t &address, UUID &uuid) {
+ address = LLDB_INVALID_ADDRESS;
+ uuid.Clear();
+ return false;
+ }
+
virtual lldb::RegisterContextSP
GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) {
return lldb::RegisterContextSP();
@@ -765,15 +805,29 @@ public:
bool IsInMemory() const { return m_memory_addr != LLDB_INVALID_ADDRESS; }
// Strip linker annotations (such as @@VERSION) from symbol names.
- virtual std::string
+ virtual llvm::StringRef
StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const {
- return symbol_name.str();
+ return symbol_name;
}
static lldb::SymbolType GetSymbolTypeFromName(
llvm::StringRef name,
lldb::SymbolType symbol_type_hint = lldb::eSymbolTypeUndefined);
+ //------------------------------------------------------------------
+ /// Loads this objfile to memory.
+ ///
+ /// Loads the bits needed to create an executable image to the memory.
+ /// It is useful with bare-metal targets where target does not have the
+ /// ability to start a process itself.
+ ///
+ /// @param[in] target
+ /// Target where to load.
+ ///
+ /// @return
+ //------------------------------------------------------------------
+ virtual Status LoadInMemory(Target &target, bool set_pc);
+
protected:
//------------------------------------------------------------------
// Member variables.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Symbol.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Symbol.h
index 3f12b9a..44c67f6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Symbol.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Symbol.h
@@ -12,8 +12,8 @@
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/Mangled.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Symbol/SymbolContextScope.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolContext.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolContext.h
index 2ca3fdb..f84b7cf 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolContext.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolContext.h
@@ -234,7 +234,30 @@ public:
bool use_inline_block_range, AddressRange &range) const;
bool GetAddressRangeFromHereToEndLine(uint32_t end_line, AddressRange &range,
- Error &error);
+ Status &error);
+
+ //------------------------------------------------------------------
+ /// Find the best global data symbol visible from this context.
+ ///
+ /// Symbol priority is:
+ /// - extern symbol in the current module if there is one
+ /// - non-extern symbol in the current module if there is one
+ /// - extern symbol in the target
+ /// - non-extern symbol in the target
+ /// It is an error if the highest-priority result is ambiguous.
+ ///
+ /// @param[in] name
+ /// The name of the symbol to search for.
+ ///
+ /// @param[out] error
+ /// An error that will be populated with a message if there was an
+ /// ambiguous result. The error will not be populated if no result
+ /// was found.
+ ///
+ /// @return
+ /// The symbol that was found, or \b nullptr if none was found.
+ //------------------------------------------------------------------
+ const Symbol *FindBestGlobalDataSymbol(const ConstString &name, Status &error);
void GetDescription(Stream *s, lldb::DescriptionLevel level,
Target *target) const;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolFile.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolFile.h
index 34ae8d7..69110dc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolFile.h
@@ -180,6 +180,8 @@ public:
uint32_t type_mask,
lldb_private::TypeList &type_list) = 0;
+ virtual void PreloadSymbols();
+
virtual lldb_private::TypeSystem *
GetTypeSystemForLanguage(lldb::LanguageType language);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Symtab.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Symtab.h
index 6a8d62c..3d24862 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Symtab.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Symtab.h
@@ -40,6 +40,7 @@ public:
Symtab(ObjectFile *objfile);
~Symtab();
+ void PreloadSymbols();
void Reserve(size_t count);
Symbol *Resize(size_t count);
uint32_t AddSymbol(const Symbol &symbol);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Type.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Type.h
index b2a65fa..9740dc2 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Type.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Type.h
@@ -11,11 +11,11 @@
#define liblldb_Type_h_
#include "lldb/Core/ClangForward.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Symbol/CompilerDecl.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/Declaration.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
#include "llvm/ADT/APSInt.h"
@@ -23,7 +23,6 @@
#include <set>
namespace lldb_private {
-
//----------------------------------------------------------------------
// CompilerContext allows an array of these items to be passed to
// perform detailed lookups in SymbolVendor and SymbolFile functions.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindPlan.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindPlan.h
index dfcf55b..abb57a2 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -19,8 +19,8 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/AddressRange.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindTable.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindTable.h
index e730454..851d24b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindTable.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindTable.h
@@ -27,6 +27,7 @@ public:
~UnwindTable();
lldb_private::DWARFCallFrameInfo *GetEHFrameInfo();
+ lldb_private::DWARFCallFrameInfo *GetDebugFrameInfo();
lldb_private::CompactUnwindInfo *GetCompactUnwindInfo();
@@ -58,6 +59,8 @@ private:
void Dump(Stream &s);
void Initialize();
+ llvm::Optional<AddressRange> GetAddressRange(const Address &addr,
+ SymbolContext &sc);
typedef std::map<lldb::addr_t, lldb::FuncUnwindersSP> collection;
typedef collection::iterator iterator;
@@ -70,6 +73,7 @@ private:
std::mutex m_mutex;
std::unique_ptr<DWARFCallFrameInfo> m_eh_frame_up;
+ std::unique_ptr<DWARFCallFrameInfo> m_debug_frame_up;
std::unique_ptr<CompactUnwindInfo> m_compact_unwind_up;
std::unique_ptr<ArmUnwindInfo> m_arm_unwind_up;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Variable.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Variable.h
index 3324989..507b413 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Variable.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Variable.h
@@ -15,9 +15,9 @@
#include "lldb/Core/Mangled.h"
#include "lldb/Core/RangeMap.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Expression/DWARFExpression.h"
#include "lldb/Symbol/Declaration.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-private.h"
@@ -97,7 +97,7 @@ public:
typedef size_t (*GetVariableCallback)(void *baton, const char *name,
VariableList &var_list);
- static Error GetValuesForVariableExpressionPath(
+ static Status GetValuesForVariableExpressionPath(
llvm::StringRef variable_expr_path, ExecutionContextScope *scope,
GetVariableCallback callback, void *baton, VariableList &variable_list,
ValueObjectList &valobj_list);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ABI.h b/contrib/llvm/tools/lldb/include/lldb/Target/ABI.h
index 8a12436..0418d68 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ABI.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ABI.h
@@ -14,9 +14,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Error.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-private.h"
#include "llvm/ADT/ArrayRef.h"
@@ -77,8 +77,8 @@ public:
bool persistent = true) const;
// Set the Return value object in the current frame as though a function with
- virtual Error SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value) = 0;
+ virtual Status SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value) = 0;
protected:
// This is the method the ABI will call to actually calculate the return
@@ -92,6 +92,16 @@ protected:
virtual lldb::ValueObjectSP
GetReturnValueObjectImpl(Thread &thread, llvm::Type &ir_type) const;
+ //------------------------------------------------------------------
+ /// Request to get a Process shared pointer.
+ ///
+ /// This ABI object may not have been created with a Process object,
+ /// or the Process object may no longer be alive. Be sure to handle
+ /// the case where the shared pointer returned does not have an
+ /// object inside it.
+ //------------------------------------------------------------------
+ lldb::ProcessSP GetProcessSP() const { return m_process_wp.lock(); }
+
public:
virtual bool CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) = 0;
@@ -131,13 +141,18 @@ public:
virtual bool GetPointerReturnRegister(const char *&name) { return false; }
- static lldb::ABISP FindPlugin(const ArchSpec &arch);
+ static lldb::ABISP FindPlugin(lldb::ProcessSP process_sp, const ArchSpec &arch);
protected:
//------------------------------------------------------------------
// Classes that inherit from ABI can see and modify these
//------------------------------------------------------------------
- ABI();
+ ABI(lldb::ProcessSP process_sp) {
+ if (process_sp.get())
+ m_process_wp = process_sp;
+ }
+
+ lldb::ProcessWP m_process_wp;
private:
DISALLOW_COPY_AND_ASSIGN(ABI);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/DynamicLoader.h b/contrib/llvm/tools/lldb/include/lldb/Target/DynamicLoader.h
index 071cbe6..b589066 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/DynamicLoader.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/DynamicLoader.h
@@ -11,10 +11,38 @@
#define liblldb_DynamicLoader_h_
// Project includes
-#include "lldb/Core/Error.h"
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Core/UUID.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/UUID.h"
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-forward.h" // for ModuleSP, ThreadPlanSP
+#include "lldb/lldb-private-enumerations.h" // for LazyBool, LazyBool::eLaz...
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for int64_t
+namespace lldb_private {
+class ModuleList;
+}
+namespace lldb_private {
+class Process;
+}
+namespace lldb_private {
+class SectionList;
+}
+namespace lldb_private {
+class Symbol;
+}
+namespace lldb_private {
+class SymbolContext;
+}
+namespace lldb_private {
+class SymbolContextList;
+}
+namespace lldb_private {
+class Thread;
+}
namespace lldb_private {
@@ -185,7 +213,7 @@ public:
/// \b true if it is currently ok to try and load a shared
/// library into the process, \b false otherwise.
//------------------------------------------------------------------
- virtual Error CanLoadImage() = 0;
+ virtual Status CanLoadImage() = 0;
//------------------------------------------------------------------
/// Ask if the eh_frame information for the given SymbolContext should
@@ -331,6 +359,10 @@ protected:
// Read a pointer from memory at the given addr.
// Return LLDB_INVALID_ADDRESS if the read fails.
lldb::addr_t ReadPointer(lldb::addr_t addr);
+
+ // Calls into the Process protected method LoadOperatingSystemPlugin:
+ void LoadOperatingSystemPlugin(bool flush);
+
//------------------------------------------------------------------
// Member variables.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/FileAction.h b/contrib/llvm/tools/lldb/include/lldb/Target/FileAction.h
index 81122ec..f80f57a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/FileAction.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/FileAction.h
@@ -10,7 +10,7 @@
#ifndef liblldb_Target_FileAction_h
#define liblldb_Target_FileAction_h
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
#include <string>
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntime.h b/contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntime.h
index a40914d..21d66d5 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntime.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntime.h
@@ -18,7 +18,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private.h"
#include "lldb/lldb-types.h"
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h b/contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h
index 0a4a170..b112319 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h
@@ -16,8 +16,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StructuredData.h"
#include "lldb/Target/StopInfo.h"
+#include "lldb/Utility/StructuredData.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Language.h b/contrib/llvm/tools/lldb/include/lldb/Target/Language.h
index bcf840f..f81679f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/Language.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/Language.h
@@ -199,7 +199,7 @@ public:
// it should return an appropriate closure here
virtual DumpValueObjectOptions::DeclPrintingHelper GetDeclPrintingHelper();
- virtual LazyBool IsLogicalTrue(ValueObject &valobj, Error &error);
+ virtual LazyBool IsLogicalTrue(ValueObject &valobj, Status &error);
// for a ValueObject of some "reference type", if the value points to the
// nil/null object, this method returns true
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/LanguageRuntime.h b/contrib/llvm/tools/lldb/include/lldb/Target/LanguageRuntime.h
index a57216e..98db941 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/LanguageRuntime.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/LanguageRuntime.h
@@ -48,7 +48,7 @@ public:
static SearchFilter *
CreateFromStructuredData(Target &target,
const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData() override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Memory.h b/contrib/llvm/tools/lldb/include/lldb/Target/Memory.h
index 57275bb..af6be15 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/Memory.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/Memory.h
@@ -40,7 +40,7 @@ public:
void Flush(lldb::addr_t addr, size_t size);
- size_t Read(lldb::addr_t addr, void *dst, size_t dst_len, Error &error);
+ size_t Read(lldb::addr_t addr, void *dst, size_t dst_len, Status &error);
uint32_t GetMemoryCacheLineSize() const { return m_L2_cache_line_byte_size; }
@@ -75,6 +75,8 @@ private:
DISALLOW_COPY_AND_ASSIGN(MemoryCache);
};
+
+
class AllocatedBlock {
public:
AllocatedBlock(lldb::addr_t addr, uint32_t byte_size, uint32_t permissions,
@@ -86,32 +88,34 @@ public:
bool FreeBlock(lldb::addr_t addr);
- lldb::addr_t GetBaseAddress() const { return m_addr; }
+ lldb::addr_t GetBaseAddress() const { return m_range.GetRangeBase(); }
- uint32_t GetByteSize() const { return m_byte_size; }
+ uint32_t GetByteSize() const { return m_range.GetByteSize(); }
uint32_t GetPermissions() const { return m_permissions; }
uint32_t GetChunkSize() const { return m_chunk_size; }
bool Contains(lldb::addr_t addr) const {
- return ((addr >= m_addr) && addr < (m_addr + m_byte_size));
+ return m_range.Contains(addr);
}
protected:
- uint32_t TotalChunks() const { return m_byte_size / m_chunk_size; }
+ uint32_t TotalChunks() const { return GetByteSize() / GetChunkSize(); }
uint32_t CalculateChunksNeededForSize(uint32_t size) const {
return (size + m_chunk_size - 1) / m_chunk_size;
}
- const lldb::addr_t m_addr; // Base address of this block of memory
- const uint32_t m_byte_size; // 4GB of chunk should be enough...
- const uint32_t m_permissions; // Permissions for this memory (logical OR of
- // lldb::Permissions bits)
- const uint32_t m_chunk_size; // The size of chunks that the memory at m_addr
- // is divied up into
- typedef std::map<uint32_t, uint32_t> OffsetToChunkSize;
- OffsetToChunkSize m_offset_to_chunk_size;
+ // Base address of this block of memory 4GB of chunk should be enough.
+ Range<lldb::addr_t, uint32_t> m_range;
+ // Permissions for this memory (logical OR of lldb::Permissions bits)
+ const uint32_t m_permissions;
+ // The size of chunks that the memory at m_addr is divied up into.
+ const uint32_t m_chunk_size;
+ // A sorted list of free address ranges.
+ RangeVector<lldb::addr_t, uint32_t> m_free_blocks;
+ // A sorted list of reserved address.
+ RangeVector<lldb::addr_t, uint32_t> m_reserved_blocks;
};
//----------------------------------------------------------------------
@@ -131,7 +135,7 @@ public:
void Clear();
lldb::addr_t AllocateMemory(size_t byte_size, uint32_t permissions,
- Error &error);
+ Status &error);
bool DeallocateMemory(lldb::addr_t ptr);
@@ -139,7 +143,7 @@ protected:
typedef std::shared_ptr<AllocatedBlock> AllocatedBlockSP;
AllocatedBlockSP AllocatePage(uint32_t byte_size, uint32_t permissions,
- uint32_t chunk_size, Error &error);
+ uint32_t chunk_size, Status &error);
//------------------------------------------------------------------
// Classes that inherit from MemoryCache can see and modify these
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/MemoryRegionInfo.h b/contrib/llvm/tools/lldb/include/lldb/Target/MemoryRegionInfo.h
index be0cfa4..0824b24 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/MemoryRegionInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/MemoryRegionInfo.h
@@ -11,8 +11,9 @@
#ifndef lldb_MemoryRegionInfo_h
#define lldb_MemoryRegionInfo_h
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/RangeMap.h"
+#include "llvm/Support/FormatProviders.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Range.h"
namespace lldb_private {
@@ -100,4 +101,24 @@ protected:
};
}
+namespace llvm {
+template <>
+struct format_provider<lldb_private::MemoryRegionInfo::OptionalBool> {
+ static void format(const lldb_private::MemoryRegionInfo::OptionalBool &B,
+ raw_ostream &OS, StringRef Options) {
+ switch(B) {
+ case lldb_private::MemoryRegionInfo::eNo:
+ OS << "no";
+ return;
+ case lldb_private::MemoryRegionInfo::eYes:
+ OS << "yes";
+ return;
+ case lldb_private::MemoryRegionInfo::eDontKnow:
+ OS << "don't know";
+ return;
+ }
+ }
+};
+}
+
#endif // #ifndef lldb_MemoryRegionInfo_h
diff --git a/contrib/llvm/tools/lldb/source/Utility/ModuleCache.h b/contrib/llvm/tools/lldb/include/lldb/Target/ModuleCache.h
index 6faa5ff..4959ee8 100644
--- a/contrib/llvm/tools/lldb/source/Utility/ModuleCache.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ModuleCache.h
@@ -7,15 +7,15 @@
//
//===----------------------------------------------------------------------===//
-#ifndef utility_ModuleCache_h_
-#define utility_ModuleCache_h_
+#ifndef LLDB_TARGET_MODULECACHE_H
+#define LLDB_TARGET_MODULECACHE_H
#include "lldb/lldb-forward.h"
#include "lldb/lldb-types.h"
-#include "lldb/Core/Error.h"
#include "lldb/Host/File.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h"
#include <functional>
#include <string>
@@ -27,7 +27,7 @@ class Module;
class UUID;
//----------------------------------------------------------------------
-/// @class ModuleCache ModuleCache.h "Utility/ModuleCache.h"
+/// @class ModuleCache ModuleCache.h "lldb/Target/ModuleCache.h"
/// @brief A module cache class.
///
/// Caches locally modules that are downloaded from remote targets.
@@ -49,24 +49,24 @@ class UUID;
class ModuleCache {
public:
using ModuleDownloader =
- std::function<Error(const ModuleSpec &, const FileSpec &)>;
+ std::function<Status(const ModuleSpec &, const FileSpec &)>;
using SymfileDownloader =
- std::function<Error(const lldb::ModuleSP &, const FileSpec &)>;
+ std::function<Status(const lldb::ModuleSP &, const FileSpec &)>;
- Error GetAndPut(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec,
- const ModuleDownloader &module_downloader,
- const SymfileDownloader &symfile_downloader,
- lldb::ModuleSP &cached_module_sp, bool *did_create_ptr);
+ Status GetAndPut(const FileSpec &root_dir_spec, const char *hostname,
+ const ModuleSpec &module_spec,
+ const ModuleDownloader &module_downloader,
+ const SymfileDownloader &symfile_downloader,
+ lldb::ModuleSP &cached_module_sp, bool *did_create_ptr);
private:
- Error Put(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec, const FileSpec &tmp_file,
- const FileSpec &target_file);
+ Status Put(const FileSpec &root_dir_spec, const char *hostname,
+ const ModuleSpec &module_spec, const FileSpec &tmp_file,
+ const FileSpec &target_file);
- Error Get(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec, lldb::ModuleSP &cached_module_sp,
- bool *did_create_ptr);
+ Status Get(const FileSpec &root_dir_spec, const char *hostname,
+ const ModuleSpec &module_spec, lldb::ModuleSP &cached_module_sp,
+ bool *did_create_ptr);
std::unordered_map<std::string, lldb::ModuleWP> m_loaded_modules;
};
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ObjCLanguageRuntime.h b/contrib/llvm/tools/lldb/include/lldb/Target/ObjCLanguageRuntime.h
index 0a9ffa9..97a2a73 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ObjCLanguageRuntime.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ObjCLanguageRuntime.h
@@ -168,7 +168,7 @@ public:
bool EvaluatePrecondition(StoppointCallbackContext &context) override;
void GetDescription(Stream &stream, lldb::DescriptionLevel level) override;
- Error ConfigurePrecondition(Args &args) override;
+ Status ConfigurePrecondition(Args &args) override;
protected:
void AddClassName(const char *class_name);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/PathMappingList.h b/contrib/llvm/tools/lldb/include/lldb/Target/PathMappingList.h
index 4e5a569..b1b551f 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/PathMappingList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/PathMappingList.h
@@ -15,8 +15,8 @@
#include <map>
#include <vector>
// Other libraries and framework includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
// Project includes
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Platform.h b/contrib/llvm/tools/lldb/include/lldb/Target/Platform.h
index 9707093..f28a564 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/Platform.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/Platform.h
@@ -22,11 +22,11 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/UserSettingsController.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Interpreter/Options.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-public.h"
@@ -53,6 +53,7 @@ public:
};
typedef std::shared_ptr<PlatformProperties> PlatformPropertiesSP;
+typedef llvm::SmallVector<lldb::addr_t, 6> MmapArgList;
//----------------------------------------------------------------------
/// @class Platform Platform.h "lldb/Target/Platform.h"
@@ -111,10 +112,10 @@ public:
// Find an existing platform plug-in by name
static lldb::PlatformSP Find(const ConstString &name);
- static lldb::PlatformSP Create(const ConstString &name, Error &error);
+ static lldb::PlatformSP Create(const ConstString &name, Status &error);
static lldb::PlatformSP Create(const ArchSpec &arch,
- ArchSpec *platform_arch_ptr, Error &error);
+ ArchSpec *platform_arch_ptr, Status &error);
static uint32_t GetNumConnectedRemotePlatforms();
@@ -156,9 +157,9 @@ public:
/// Returns \b true if this Platform plug-in was able to find
/// a suitable executable, \b false otherwise.
//------------------------------------------------------------------
- virtual Error ResolveExecutable(const ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr);
+ virtual Status ResolveExecutable(const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr);
//------------------------------------------------------------------
/// Find a symbol file given a symbol file module specification.
@@ -207,8 +208,8 @@ public:
/// @return
/// Returns an error that describes success or failure.
//------------------------------------------------------------------
- virtual Error ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec,
- FileSpec &sym_file);
+ virtual Status ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec,
+ FileSpec &sym_file);
//------------------------------------------------------------------
/// Resolves the FileSpec to a (possibly) remote path. Remote
@@ -316,8 +317,8 @@ public:
/// @return
/// An error object.
//------------------------------------------------------------------
- virtual Error GetFileWithUUID(const FileSpec &platform_file,
- const UUID *uuid_ptr, FileSpec &local_file);
+ virtual Status GetFileWithUUID(const FileSpec &platform_file,
+ const UUID *uuid_ptr, FileSpec &local_file);
//----------------------------------------------------------------------
// Locate the scripting resource given a module specification.
@@ -329,18 +330,18 @@ public:
LocateExecutableScriptingResources(Target *target, Module &module,
Stream *feedback_stream);
- virtual Error GetSharedModule(const ModuleSpec &module_spec, Process *process,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
- lldb::ModuleSP *old_module_sp_ptr,
- bool *did_create_ptr);
+ virtual Status GetSharedModule(const ModuleSpec &module_spec,
+ Process *process, lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr);
virtual bool GetModuleSpec(const FileSpec &module_file_spec,
const ArchSpec &arch, ModuleSpec &module_spec);
- virtual Error ConnectRemote(Args &args);
+ virtual Status ConnectRemote(Args &args);
- virtual Error DisconnectRemote();
+ virtual Status DisconnectRemote();
//------------------------------------------------------------------
/// Get the platform's supported architectures in the order in which
@@ -367,7 +368,7 @@ public:
/// Launch a new process on a platform, not necessarily for
/// debugging, it could be just for running the process.
//------------------------------------------------------------------
- virtual Error LaunchProcess(ProcessLaunchInfo &launch_info);
+ virtual Status LaunchProcess(ProcessLaunchInfo &launch_info);
//------------------------------------------------------------------
/// Perform expansion of the command-line for this launch info
@@ -376,12 +377,12 @@ public:
// argument magic the platform defines as part of its typical
// user experience
//------------------------------------------------------------------
- virtual Error ShellExpandArguments(ProcessLaunchInfo &launch_info);
+ virtual Status ShellExpandArguments(ProcessLaunchInfo &launch_info);
//------------------------------------------------------------------
/// Kill process on a platform.
//------------------------------------------------------------------
- virtual Error KillProcess(const lldb::pid_t pid);
+ virtual Status KillProcess(const lldb::pid_t pid);
//------------------------------------------------------------------
/// Lets a platform answer if it is compatible with a given
@@ -411,13 +412,13 @@ public:
DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
Target *target, // Can be nullptr, if nullptr create a new
// target, else use existing one
- Error &error);
+ Status &error);
virtual lldb::ProcessSP ConnectProcess(llvm::StringRef connect_url,
llvm::StringRef plugin_name,
lldb_private::Debugger &debugger,
lldb_private::Target *target,
- lldb_private::Error &error);
+ lldb_private::Status &error);
//------------------------------------------------------------------
/// Attach to an existing process using a process ID.
@@ -442,7 +443,7 @@ public:
Target *target, // Can be nullptr, if nullptr
// create a new target, else
// use existing one
- Error &error) = 0;
+ Status &error) = 0;
//------------------------------------------------------------------
/// Attach to an existing process by process name.
@@ -464,7 +465,7 @@ public:
// virtual lldb::ProcessSP
// Attach (const char *process_name,
// bool wait_for_launch,
- // Error &error) = 0;
+ // Status &error) = 0;
//------------------------------------------------------------------
// The base class Platform will take care of the host platform.
@@ -552,27 +553,27 @@ public:
return false;
}
- virtual Error MakeDirectory(const FileSpec &file_spec, uint32_t permissions);
+ virtual Status MakeDirectory(const FileSpec &file_spec, uint32_t permissions);
- virtual Error GetFilePermissions(const FileSpec &file_spec,
- uint32_t &file_permissions);
+ virtual Status GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions);
- virtual Error SetFilePermissions(const FileSpec &file_spec,
- uint32_t file_permissions);
+ virtual Status SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions);
virtual lldb::user_id_t OpenFile(const FileSpec &file_spec, uint32_t flags,
- uint32_t mode, Error &error) {
+ uint32_t mode, Status &error) {
return UINT64_MAX;
}
- virtual bool CloseFile(lldb::user_id_t fd, Error &error) { return false; }
+ virtual bool CloseFile(lldb::user_id_t fd, Status &error) { return false; }
virtual lldb::user_id_t GetFileSize(const FileSpec &file_spec) {
return UINT64_MAX;
}
virtual uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
- uint64_t dst_len, Error &error) {
+ uint64_t dst_len, Status &error) {
error.SetErrorStringWithFormat(
"Platform::ReadFile() is not supported in the %s platform",
GetName().GetCString());
@@ -580,19 +581,19 @@ public:
}
virtual uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset,
- const void *src, uint64_t src_len, Error &error) {
+ const void *src, uint64_t src_len, Status &error) {
error.SetErrorStringWithFormat(
"Platform::ReadFile() is not supported in the %s platform",
GetName().GetCString());
return -1;
}
- virtual Error GetFile(const FileSpec &source, const FileSpec &destination);
+ virtual Status GetFile(const FileSpec &source, const FileSpec &destination);
- virtual Error PutFile(const FileSpec &source, const FileSpec &destination,
- uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX);
+ virtual Status PutFile(const FileSpec &source, const FileSpec &destination,
+ uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX);
- virtual Error
+ virtual Status
CreateSymlink(const FileSpec &src, // The name of the link is in src
const FileSpec &dst); // The symlink points to dst
@@ -620,16 +621,19 @@ public:
/// @return
/// An error object that describes anything that went wrong.
//----------------------------------------------------------------------
- virtual Error Install(const FileSpec &src, const FileSpec &dst);
+ virtual Status Install(const FileSpec &src, const FileSpec &dst);
virtual size_t GetEnvironment(StringList &environment);
virtual bool GetFileExists(const lldb_private::FileSpec &file_spec);
- virtual Error Unlink(const FileSpec &file_spec);
+ virtual Status Unlink(const FileSpec &file_spec);
- virtual uint64_t ConvertMmapFlagsToPlatform(const ArchSpec &arch,
- unsigned flags);
+ virtual MmapArgList GetMmapArgumentList(const ArchSpec &arch,
+ lldb::addr_t addr,
+ lldb::addr_t length,
+ unsigned prot, unsigned flags,
+ lldb::addr_t fd, lldb::addr_t offset);
virtual bool GetSupportsRSync() { return m_supports_rsync; }
@@ -664,7 +668,7 @@ public:
return nullptr;
}
- virtual lldb_private::Error RunShellCommand(
+ virtual lldb_private::Status RunShellCommand(
const char *command, // Shouldn't be nullptr
const FileSpec &working_dir, // Pass empty FileSpec to use the current
// working directory
@@ -830,14 +834,14 @@ public:
uint32_t LoadImage(lldb_private::Process *process,
const lldb_private::FileSpec &local_file,
const lldb_private::FileSpec &remote_file,
- lldb_private::Error &error);
+ lldb_private::Status &error);
virtual uint32_t DoLoadImage(lldb_private::Process *process,
const lldb_private::FileSpec &remote_file,
- lldb_private::Error &error);
+ lldb_private::Status &error);
- virtual Error UnloadImage(lldb_private::Process *process,
- uint32_t image_token);
+ virtual Status UnloadImage(lldb_private::Process *process,
+ uint32_t image_token);
//------------------------------------------------------------------
/// Connect to all processes waiting for a debugger to attach
@@ -856,7 +860,7 @@ public:
/// The number of processes we are successfully connected to.
//------------------------------------------------------------------
virtual size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger,
- lldb_private::Error &error);
+ lldb_private::Status &error);
protected:
bool m_is_host;
@@ -977,35 +981,35 @@ protected:
m_gid_map.clear();
}
- Error GetCachedExecutable(ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
- Platform &remote_platform);
+ Status GetCachedExecutable(ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ Platform &remote_platform);
- virtual Error DownloadModuleSlice(const FileSpec &src_file_spec,
- const uint64_t src_offset,
- const uint64_t src_size,
- const FileSpec &dst_file_spec);
+ virtual Status DownloadModuleSlice(const FileSpec &src_file_spec,
+ const uint64_t src_offset,
+ const uint64_t src_size,
+ const FileSpec &dst_file_spec);
- virtual Error DownloadSymbolFile(const lldb::ModuleSP &module_sp,
- const FileSpec &dst_file_spec);
+ virtual Status DownloadSymbolFile(const lldb::ModuleSP &module_sp,
+ const FileSpec &dst_file_spec);
virtual const char *GetCacheHostname();
private:
- typedef std::function<Error(const ModuleSpec &)> ModuleResolver;
+ typedef std::function<Status(const ModuleSpec &)> ModuleResolver;
- Error GetRemoteSharedModule(const ModuleSpec &module_spec, Process *process,
- lldb::ModuleSP &module_sp,
- const ModuleResolver &module_resolver,
- bool *did_create_ptr);
+ Status GetRemoteSharedModule(const ModuleSpec &module_spec, Process *process,
+ lldb::ModuleSP &module_sp,
+ const ModuleResolver &module_resolver,
+ bool *did_create_ptr);
bool GetCachedSharedModule(const ModuleSpec &module_spec,
lldb::ModuleSP &module_sp, bool *did_create_ptr);
- Error LoadCachedExecutable(const ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
- Platform &remote_platform);
+ Status LoadCachedExecutable(const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ Platform &remote_platform);
FileSpec GetModuleCacheRoot();
@@ -1088,7 +1092,7 @@ public:
~OptionGroupPlatformRSync() override = default;
- lldb_private::Error
+ lldb_private::Status
SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
ExecutionContext *execution_context) override;
@@ -1117,7 +1121,7 @@ public:
~OptionGroupPlatformSSH() override = default;
- lldb_private::Error
+ lldb_private::Status
SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
ExecutionContext *execution_context) override;
@@ -1144,7 +1148,7 @@ public:
~OptionGroupPlatformCaching() override = default;
- lldb_private::Error
+ lldb_private::Status
SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Process.h b/contrib/llvm/tools/lldb/include/lldb/Target/Process.h
index 251dfe6..df09570 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/Process.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/Process.h
@@ -30,12 +30,10 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Communication.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/Listener.h"
#include "lldb/Core/LoadedModuleInfoList.h"
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ThreadSafeValue.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Host/HostThread.h"
@@ -48,6 +46,10 @@
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/QueueList.h"
#include "lldb/Target/ThreadList.h"
+#include "lldb/Utility/NameMatches.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TraceOptions.h"
#include "lldb/lldb-private.h"
#include "llvm/ADT/ArrayRef.h"
@@ -280,8 +282,8 @@ public:
~ProcessLaunchCommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override;
void OptionParsingStarting(ExecutionContext *execution_context) override {
launch_info.Clear();
@@ -305,11 +307,11 @@ public:
class ProcessInstanceInfoMatch {
public:
ProcessInstanceInfoMatch()
- : m_match_info(), m_name_match_type(eNameMatchIgnore),
+ : m_match_info(), m_name_match_type(NameMatch::Ignore),
m_match_all_users(false) {}
ProcessInstanceInfoMatch(const char *process_name,
- NameMatchType process_name_match_type)
+ NameMatch process_name_match_type)
: m_match_info(), m_name_match_type(process_name_match_type),
m_match_all_users(false) {
m_match_info.GetExecutableFile().SetFile(process_name, false);
@@ -323,9 +325,9 @@ public:
void SetMatchAllUsers(bool b) { m_match_all_users = b; }
- NameMatchType GetNameMatchType() const { return m_name_match_type; }
+ NameMatch GetNameMatchType() const { return m_name_match_type; }
- void SetNameMatchType(NameMatchType name_match_type) {
+ void SetNameMatchType(NameMatch name_match_type) {
m_name_match_type = name_match_type;
}
@@ -338,7 +340,7 @@ public:
protected:
ProcessInstanceInfo m_match_info;
- NameMatchType m_name_match_type;
+ NameMatch m_name_match_type;
bool m_match_all_users;
};
@@ -504,6 +506,7 @@ class Process : public std::enable_shared_from_this<Process>,
public PluginInterface {
friend class FunctionCaller; // For WaitForStateChangeEventsPrivate
friend class Debugger; // For PopProcessIOHandler and ProcessIOHandlerIsActive
+ friend class DynamicLoader; // For LoadOperatingSystemPlugin
friend class ProcessEventData;
friend class StopInfo;
friend class Target;
@@ -789,12 +792,12 @@ public:
/// An error object. Call GetID() to get the process ID if
/// the error object is success.
//------------------------------------------------------------------
- virtual Error Launch(ProcessLaunchInfo &launch_info);
+ virtual Status Launch(ProcessLaunchInfo &launch_info);
- virtual Error LoadCore();
+ virtual Status LoadCore();
- virtual Error DoLoadCore() {
- Error error;
+ virtual Status DoLoadCore() {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support loading core files.",
GetPluginName().GetCString());
@@ -866,7 +869,7 @@ public:
/// Returns \a pid if attaching was successful, or
/// LLDB_INVALID_PROCESS_ID if attaching fails.
//------------------------------------------------------------------
- virtual Error Attach(ProcessAttachInfo &attach_info);
+ virtual Status Attach(ProcessAttachInfo &attach_info);
//------------------------------------------------------------------
/// Attach to a remote system via a URL
@@ -882,7 +885,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error ConnectRemote(Stream *strm, llvm::StringRef remote_url);
+ virtual Status ConnectRemote(Stream *strm, llvm::StringRef remote_url);
bool GetShouldDetach() const { return m_should_detach; }
@@ -989,9 +992,9 @@ public:
/// @see Thread:Step()
/// @see Thread:Suspend()
//------------------------------------------------------------------
- Error Resume();
+ Status Resume();
- Error ResumeSynchronous(Stream *stream);
+ Status ResumeSynchronous(Stream *stream);
//------------------------------------------------------------------
/// Halts a running process.
@@ -1013,7 +1016,7 @@ public:
/// halted.
/// otherwise the halt has failed.
//------------------------------------------------------------------
- Error Halt(bool clear_thread_plans = false, bool use_run_lock = true);
+ Status Halt(bool clear_thread_plans = false, bool use_run_lock = true);
//------------------------------------------------------------------
/// Detaches from a running or stopped process.
@@ -1027,7 +1030,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- Error Detach(bool keep_stopped);
+ Status Detach(bool keep_stopped);
//------------------------------------------------------------------
/// Kills the process and shuts down all threads that were spawned
@@ -1047,7 +1050,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- Error Destroy(bool force_kill);
+ Status Destroy(bool force_kill);
//------------------------------------------------------------------
/// Sends a process a UNIX signal \a signal.
@@ -1058,7 +1061,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- Error Signal(int signal);
+ Status Signal(int signal);
void SetUnixSignals(lldb::UnixSignalsSP &&signals_sp);
@@ -1077,7 +1080,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error WillAttachToProcessWithID(lldb::pid_t pid) { return Error(); }
+ virtual Status WillAttachToProcessWithID(lldb::pid_t pid) { return Status(); }
//------------------------------------------------------------------
/// Called before attaching to a process.
@@ -1088,9 +1091,9 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error WillAttachToProcessWithName(const char *process_name,
- bool wait_for_launch) {
- return Error();
+ virtual Status WillAttachToProcessWithName(const char *process_name,
+ bool wait_for_launch) {
+ return Status();
}
//------------------------------------------------------------------
@@ -1107,8 +1110,8 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error DoConnectRemote(Stream *strm, llvm::StringRef remote_url) {
- Error error;
+ virtual Status DoConnectRemote(Stream *strm, llvm::StringRef remote_url) {
+ Status error;
error.SetErrorString("remote connections are not supported");
return error;
}
@@ -1124,14 +1127,14 @@ public:
/// will return the uid to attach as.
///
/// @return
- /// Returns a successful Error attaching was successful, or
+ /// Returns a successful Status attaching was successful, or
/// an appropriate (possibly platform-specific) error code if
/// attaching fails.
/// hanming : need flag
//------------------------------------------------------------------
- virtual Error DoAttachToProcessWithID(lldb::pid_t pid,
- const ProcessAttachInfo &attach_info) {
- Error error;
+ virtual Status DoAttachToProcessWithID(lldb::pid_t pid,
+ const ProcessAttachInfo &attach_info) {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support attaching to a process by pid",
GetPluginName().GetCString());
@@ -1149,14 +1152,14 @@ public:
/// will return the uid to attach as.
///
/// @return
- /// Returns a successful Error attaching was successful, or
+ /// Returns a successful Status attaching was successful, or
/// an appropriate (possibly platform-specific) error code if
/// attaching fails.
//------------------------------------------------------------------
- virtual Error
+ virtual Status
DoAttachToProcessWithName(const char *process_name,
const ProcessAttachInfo &attach_info) {
- Error error;
+ Status error;
error.SetErrorString("attach by name is not supported");
return error;
}
@@ -1199,7 +1202,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error WillLaunch(Module *module) { return Error(); }
+ virtual Status WillLaunch(Module *module) { return Status(); }
//------------------------------------------------------------------
/// Launch a new process.
@@ -1217,11 +1220,11 @@ public:
/// requested launch.
///
/// @return
- /// An Error instance indicating success or failure of the
+ /// An Status instance indicating success or failure of the
/// operation.
//------------------------------------------------------------------
- virtual Error DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) {
- Error error;
+ virtual Status DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support launching processes",
GetPluginName().GetCString());
@@ -1245,7 +1248,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error WillResume() { return Error(); }
+ virtual Status WillResume() { return Status(); }
//------------------------------------------------------------------
/// Resumes all of a process's threads as configured using the
@@ -1264,8 +1267,8 @@ public:
/// @see Thread:Step()
/// @see Thread:Suspend()
//------------------------------------------------------------------
- virtual Error DoResume() {
- Error error;
+ virtual Status DoResume() {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support resuming processes",
GetPluginName().GetCString());
@@ -1289,7 +1292,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error WillHalt() { return Error(); }
+ virtual Status WillHalt() { return Status(); }
//------------------------------------------------------------------
/// Halts a running process.
@@ -1311,8 +1314,8 @@ public:
/// Returns \b true if the process successfully halts, \b false
/// otherwise.
//------------------------------------------------------------------
- virtual Error DoHalt(bool &caused_stop) {
- Error error;
+ virtual Status DoHalt(bool &caused_stop) {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support halting processes",
GetPluginName().GetCString());
@@ -1336,7 +1339,7 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error WillDetach() { return Error(); }
+ virtual Status WillDetach() { return Status(); }
//------------------------------------------------------------------
/// Detaches from a running or stopped process.
@@ -1345,8 +1348,8 @@ public:
/// Returns \b true if the process successfully detaches, \b
/// false otherwise.
//------------------------------------------------------------------
- virtual Error DoDetach(bool keep_stopped) {
- Error error;
+ virtual Status DoDetach(bool keep_stopped) {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support detaching from processes",
GetPluginName().GetCString());
@@ -1374,7 +1377,7 @@ public:
/// Process::DoSignal(int), otherwise an error describing what
/// prevents the signal from being sent.
//------------------------------------------------------------------
- virtual Error WillSignal() { return Error(); }
+ virtual Status WillSignal() { return Status(); }
//------------------------------------------------------------------
/// Sends a process a UNIX signal \a signal.
@@ -1382,17 +1385,17 @@ public:
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error DoSignal(int signal) {
- Error error;
+ virtual Status DoSignal(int signal) {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support sending signals to processes",
GetPluginName().GetCString());
return error;
}
- virtual Error WillDestroy() { return Error(); }
+ virtual Status WillDestroy() { return Status(); }
- virtual Error DoDestroy() = 0;
+ virtual Status DoDestroy() = 0;
virtual void DidDestroy() {}
@@ -1703,7 +1706,7 @@ public:
/// The number of bytes that were actually read into \a buf.
//------------------------------------------------------------------
virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
- Error &error) = 0;
+ Status &error) = 0;
//------------------------------------------------------------------
/// Read of memory from a process.
@@ -1735,7 +1738,7 @@ public:
/// returned to indicate an error.
//------------------------------------------------------------------
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
- Error &error);
+ Status &error);
//------------------------------------------------------------------
/// Read a NULL terminated string from memory
@@ -1767,7 +1770,7 @@ public:
/// The error status or the number of bytes prior to the null terminator.
//------------------------------------------------------------------
size_t ReadStringFromMemory(lldb::addr_t vm_addr, char *str, size_t max_bytes,
- Error &error, size_t type_width = 1);
+ Status &error, size_t type_width = 1);
//------------------------------------------------------------------
/// Read a NULL terminated C string from memory
@@ -1779,13 +1782,13 @@ public:
/// terminated (at most cstr_max_len - 1 bytes will be read).
//------------------------------------------------------------------
size_t ReadCStringFromMemory(lldb::addr_t vm_addr, char *cstr,
- size_t cstr_max_len, Error &error);
+ size_t cstr_max_len, Status &error);
size_t ReadCStringFromMemory(lldb::addr_t vm_addr, std::string &out_str,
- Error &error);
+ Status &error);
size_t ReadMemoryFromInferior(lldb::addr_t vm_addr, void *buf, size_t size,
- Error &error);
+ Status &error);
//------------------------------------------------------------------
/// Reads an unsigned integer of the specified byte size from
@@ -1816,15 +1819,15 @@ public:
//------------------------------------------------------------------
uint64_t ReadUnsignedIntegerFromMemory(lldb::addr_t load_addr,
size_t byte_size, uint64_t fail_value,
- Error &error);
+ Status &error);
int64_t ReadSignedIntegerFromMemory(lldb::addr_t load_addr, size_t byte_size,
- int64_t fail_value, Error &error);
+ int64_t fail_value, Status &error);
- lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Error &error);
+ lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error);
bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
- Error &error);
+ Status &error);
//------------------------------------------------------------------
/// Actually do the writing of memory to a process.
@@ -1847,7 +1850,7 @@ public:
/// The number of bytes that were actually written.
//------------------------------------------------------------------
virtual size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
- size_t size, Error &error) {
+ size_t size, Status &error) {
error.SetErrorStringWithFormat(
"error: %s does not support writing to processes",
GetPluginName().GetCString());
@@ -1887,11 +1890,11 @@ public:
/// The number of bytes that were actually written.
//------------------------------------------------------------------
size_t WriteScalarToMemory(lldb::addr_t vm_addr, const Scalar &scalar,
- size_t size, Error &error);
+ size_t size, Status &error);
size_t ReadScalarIntegerFromMemory(lldb::addr_t addr, uint32_t byte_size,
bool is_signed, Scalar &scalar,
- Error &error);
+ Status &error);
//------------------------------------------------------------------
/// Write memory to a process.
@@ -1920,7 +1923,7 @@ public:
//------------------------------------------------------------------
// TODO: change this to take an ArrayRef<uint8_t>
size_t WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
- Error &error);
+ Status &error);
//------------------------------------------------------------------
/// Actually allocate memory in the process.
@@ -1938,7 +1941,7 @@ public:
//------------------------------------------------------------------
virtual lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions,
- Error &error) {
+ Status &error) {
error.SetErrorStringWithFormat(
"error: %s does not support allocating in the debug process",
GetPluginName().GetCString());
@@ -1968,7 +1971,7 @@ public:
/// The address of the allocated buffer in the process, or
/// LLDB_INVALID_ADDRESS if the allocation failed.
//------------------------------------------------------------------
- lldb::addr_t AllocateMemory(size_t size, uint32_t permissions, Error &error);
+ lldb::addr_t AllocateMemory(size_t size, uint32_t permissions, Status &error);
//------------------------------------------------------------------
/// The public interface to allocating memory in the process, this also
@@ -1995,7 +1998,8 @@ public:
/// LLDB_INVALID_ADDRESS if the allocation failed.
//------------------------------------------------------------------
- lldb::addr_t CallocateMemory(size_t size, uint32_t permissions, Error &error);
+ lldb::addr_t CallocateMemory(size_t size, uint32_t permissions,
+ Status &error);
//------------------------------------------------------------------
/// Resolve dynamically loaded indirect functions.
@@ -2011,7 +2015,7 @@ public:
/// LLDB_INVALID_ADDRESS if the resolution failed.
//------------------------------------------------------------------
virtual lldb::addr_t ResolveIndirectFunction(const Address *address,
- Error &error);
+ Status &error);
//------------------------------------------------------------------
/// Locate the memory region that contains load_addr.
@@ -2039,9 +2043,9 @@ public:
/// @return
/// An error value.
//------------------------------------------------------------------
- virtual Error GetMemoryRegionInfo(lldb::addr_t load_addr,
- MemoryRegionInfo &range_info) {
- Error error;
+ virtual Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+ Status error;
error.SetErrorString("Process::GetMemoryRegionInfo() not supported");
return error;
}
@@ -2056,18 +2060,18 @@ public:
/// @return
/// An error value.
//------------------------------------------------------------------
- virtual Error
+ virtual Status
GetMemoryRegions(std::vector<lldb::MemoryRegionInfoSP> &region_list);
- virtual Error GetWatchpointSupportInfo(uint32_t &num) {
- Error error;
+ virtual Status GetWatchpointSupportInfo(uint32_t &num) {
+ Status error;
num = 0;
error.SetErrorString("Process::GetWatchpointSupportInfo() not supported");
return error;
}
- virtual Error GetWatchpointSupportInfo(uint32_t &num, bool &after) {
- Error error;
+ virtual Status GetWatchpointSupportInfo(uint32_t &num, bool &after) {
+ Status error;
num = 0;
after = true;
error.SetErrorString("Process::GetWatchpointSupportInfo() not supported");
@@ -2162,8 +2166,8 @@ public:
/// @return
/// \btrue if the memory was deallocated, \bfalse otherwise.
//------------------------------------------------------------------
- virtual Error DoDeallocateMemory(lldb::addr_t ptr) {
- Error error;
+ virtual Status DoDeallocateMemory(lldb::addr_t ptr) {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support deallocating in the debug process",
GetPluginName().GetCString());
@@ -2183,7 +2187,7 @@ public:
/// @return
/// \btrue if the memory was deallocated, \bfalse otherwise.
//------------------------------------------------------------------
- Error DeallocateMemory(lldb::addr_t ptr);
+ Status DeallocateMemory(lldb::addr_t ptr);
//------------------------------------------------------------------
/// Get any available STDOUT.
@@ -2215,7 +2219,7 @@ public:
/// equal to \a buf_size, another call to this function should
/// be made to retrieve more STDOUT data.
//------------------------------------------------------------------
- virtual size_t GetSTDOUT(char *buf, size_t buf_size, Error &error);
+ virtual size_t GetSTDOUT(char *buf, size_t buf_size, Status &error);
//------------------------------------------------------------------
/// Get any available STDERR.
@@ -2247,7 +2251,7 @@ public:
/// equal to \a buf_size, another call to this function should
/// be made to retrieve more STDERR data.
//------------------------------------------------------------------
- virtual size_t GetSTDERR(char *buf, size_t buf_size, Error &error);
+ virtual size_t GetSTDERR(char *buf, size_t buf_size, Status &error);
//------------------------------------------------------------------
/// Puts data into this process's STDIN.
@@ -2270,7 +2274,7 @@ public:
/// less than \a buf_size, another call to this function should
/// be made to write the rest of the data.
//------------------------------------------------------------------
- virtual size_t PutSTDIN(const char *buf, size_t buf_size, Error &error) {
+ virtual size_t PutSTDIN(const char *buf, size_t buf_size, Status &error) {
error.SetErrorString("stdin unsupported");
return 0;
}
@@ -2290,23 +2294,23 @@ public:
/// equal to \a buf_size, another call to this function should
/// be made to retrieve more profile data.
//------------------------------------------------------------------
- virtual size_t GetAsyncProfileData(char *buf, size_t buf_size, Error &error);
+ virtual size_t GetAsyncProfileData(char *buf, size_t buf_size, Status &error);
//----------------------------------------------------------------------
// Process Breakpoints
//----------------------------------------------------------------------
size_t GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site);
- virtual Error EnableBreakpointSite(BreakpointSite *bp_site) {
- Error error;
+ virtual Status EnableBreakpointSite(BreakpointSite *bp_site) {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support enabling breakpoints",
GetPluginName().GetCString());
return error;
}
- virtual Error DisableBreakpointSite(BreakpointSite *bp_site) {
- Error error;
+ virtual Status DisableBreakpointSite(BreakpointSite *bp_site) {
+ Status error;
error.SetErrorStringWithFormat(
"error: %s does not support disabling breakpoints",
GetPluginName().GetCString());
@@ -2317,13 +2321,13 @@ public:
// don't need to implement this function unless the standard flow of
// read existing opcode, write breakpoint opcode, verify breakpoint opcode
// doesn't work for a specific process plug-in.
- virtual Error EnableSoftwareBreakpoint(BreakpointSite *bp_site);
+ virtual Status EnableSoftwareBreakpoint(BreakpointSite *bp_site);
// This is implemented completely using the lldb::Process API. Subclasses
// don't need to implement this function unless the standard flow of
// restoring original opcode in memory and verifying the restored opcode
// doesn't work for a specific process plug-in.
- virtual Error DisableSoftwareBreakpoint(BreakpointSite *bp_site);
+ virtual Status DisableSoftwareBreakpoint(BreakpointSite *bp_site);
BreakpointSiteList &GetBreakpointSiteList();
@@ -2331,14 +2335,14 @@ public:
void DisableAllBreakpointSites();
- Error ClearBreakpointSiteByID(lldb::user_id_t break_id);
+ Status ClearBreakpointSiteByID(lldb::user_id_t break_id);
lldb::break_id_t CreateBreakpointSite(const lldb::BreakpointLocationSP &owner,
bool use_hardware);
- Error DisableBreakpointSiteByID(lldb::user_id_t break_id);
+ Status DisableBreakpointSiteByID(lldb::user_id_t break_id);
- Error EnableBreakpointSiteByID(lldb::user_id_t break_id);
+ Status EnableBreakpointSiteByID(lldb::user_id_t break_id);
// BreakpointLocations use RemoveOwnerFromBreakpointSite to remove
// themselves from the owner's list of this breakpoint sites.
@@ -2349,9 +2353,9 @@ public:
//----------------------------------------------------------------------
// Process Watchpoints (optional)
//----------------------------------------------------------------------
- virtual Error EnableWatchpoint(Watchpoint *wp, bool notify = true);
+ virtual Status EnableWatchpoint(Watchpoint *wp, bool notify = true);
- virtual Error DisableWatchpoint(Watchpoint *wp, bool notify = true);
+ virtual Status DisableWatchpoint(Watchpoint *wp, bool notify = true);
//------------------------------------------------------------------
// Thread Queries
@@ -2605,13 +2609,13 @@ public:
bool RunPreResumeActions();
void ClearPreResumeActions();
-
+
void ClearPreResumeAction(PreResumeActionCallback callback, void *baton);
ProcessRunLock &GetRunLock();
- virtual Error SendEventData(const char *data) {
- Error return_error("Sending an event is not supported for this process.");
+ virtual Status SendEventData(const char *data) {
+ Status return_error("Sending an event is not supported for this process.");
return return_error;
}
@@ -2662,9 +2666,9 @@ public:
/// The load address of the file if it is loaded into the
/// processes address space, LLDB_INVALID_ADDRESS otherwise.
//------------------------------------------------------------------
- virtual Error GetFileLoadAddress(const FileSpec &file, bool &is_loaded,
- lldb::addr_t &load_addr) {
- return Error("Not supported");
+ virtual Status GetFileLoadAddress(const FileSpec &file, bool &is_loaded,
+ lldb::addr_t &load_addr) {
+ return Status("Not supported");
}
size_t AddImageToken(lldb::addr_t image_ptr);
@@ -2726,7 +2730,7 @@ public:
/// @return
/// Returns the result of attempting to configure the feature.
//------------------------------------------------------------------
- virtual Error
+ virtual Status
ConfigureStructuredData(const ConstString &type_name,
const StructuredData::ObjectSP &config_sp);
@@ -2764,6 +2768,74 @@ public:
lldb::StructuredDataPluginSP
GetStructuredDataPlugin(const ConstString &type_name) const;
+ //------------------------------------------------------------------
+ /// Starts tracing with the configuration provided in options. To
+ /// enable tracing on the complete process the thread_id in the
+ /// options should be set to LLDB_INVALID_THREAD_ID. The API returns
+ /// a user_id which is needed by other API's that manipulate the
+ /// trace instance.
+ /// The handling of erroneous or unsupported configuration is left
+ /// to the trace technology implementations in the server, as they
+ /// could be returned as an error, or rounded to a valid
+ /// configuration to start tracing. In the later case the
+ /// GetTraceConfig should supply the actual used trace
+ /// configuration.
+ //------------------------------------------------------------------
+ virtual lldb::user_id_t StartTrace(const TraceOptions &options,
+ Status &error) {
+ error.SetErrorString("Not implemented");
+ return LLDB_INVALID_UID;
+ }
+
+ //------------------------------------------------------------------
+ /// Stops the tracing instance leading to deletion of the trace
+ /// data. The tracing instance is identified by the user_id which
+ /// is obtained when tracing was started from the StartTrace.
+ /// In case tracing of the complete process needs to be stopped
+ /// the thread_id should be set to LLDB_INVALID_THREAD_ID.
+ /// In the other case that tracing on an individual thread needs
+ /// to be stopped a thread_id can be supplied.
+ //------------------------------------------------------------------
+ virtual Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
+ return Status("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// Provides the trace data as raw bytes. A buffer needs to be
+ /// supplied to copy the trace data. The exact behavior of this API
+ /// may vary across trace technology, as some may support partial
+ /// reading of the trace data from a specified offset while some
+ /// may not. The thread_id should be used to select a particular
+ /// thread for trace extraction.
+ //------------------------------------------------------------------
+ virtual Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Status("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// Similar API as above except for obtaining meta data
+ //------------------------------------------------------------------
+ virtual Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) {
+ return Status("Not implemented");
+ }
+
+ //------------------------------------------------------------------
+ /// API to obtain the trace configuration used by a trace instance.
+ /// Configurations that may be specific to some trace technology
+ /// should be stored in the custom parameters. The options are
+ /// transported to the server, which shall interpret accordingly.
+ /// The thread_id can be specified in the options to obtain the
+ /// configuration used by a specific thread. The thread_id specified
+ /// should also match the uid otherwise an error will be returned.
+ //------------------------------------------------------------------
+ virtual Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) {
+ return Status("Not implemented");
+ }
+
protected:
void SetState(lldb::EventSP &event_sp);
@@ -2774,9 +2846,9 @@ protected:
/// state of m_run_lock, but just causes the process to resume.
///
/// @return
- /// An Error object describing the success or failure of the resume.
+ /// An Status object describing the success or failure of the resume.
//------------------------------------------------------------------
- Error PrivateResume();
+ Status PrivateResume();
//------------------------------------------------------------------
// Called internally
@@ -3103,7 +3175,7 @@ private:
protected:
void HandlePrivateEvent(lldb::EventSP &event_sp);
- Error HaltPrivate();
+ Status HaltPrivate();
lldb::StateType WaitForProcessStopPrivate(lldb::EventSP &event_sp,
const Timeout<std::micro> &timeout);
@@ -3120,7 +3192,7 @@ protected:
const Timeout<std::micro> &timeout);
size_t WriteMemoryPrivate(lldb::addr_t addr, const void *buf, size_t size,
- Error &error);
+ Status &error);
void AppendSTDOUT(const char *s, size_t len);
@@ -3141,7 +3213,9 @@ protected:
return static_cast<bool>(m_process_input_reader);
}
- Error StopForDestroyOrDetach(lldb::EventSP &exit_event_sp);
+ Status StopForDestroyOrDetach(lldb::EventSP &exit_event_sp);
+
+ virtual Status UpdateAutomaticSignalFiltering();
bool StateChangedIsExternallyHijacked();
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ProcessInfo.h b/contrib/llvm/tools/lldb/include/lldb/Target/ProcessInfo.h
index f8d37fa..03b1524 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ProcessInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ProcessInfo.h
@@ -12,8 +12,8 @@
// LLDB headers
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/FileSpec.h"
namespace lldb_private {
//----------------------------------------------------------------------
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ProcessLaunchInfo.h b/contrib/llvm/tools/lldb/include/lldb/Target/ProcessLaunchInfo.h
index 2c192c2..93a1a9e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ProcessLaunchInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ProcessLaunchInfo.h
@@ -14,12 +14,13 @@
#include <string>
// LLDB Headers
-#include "lldb/Core/Flags.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/Flags.h"
+
#include "lldb/Host/Host.h"
+#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Target/FileAction.h"
#include "lldb/Target/ProcessInfo.h"
-#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Utility/FileSpec.h"
namespace lldb_private {
@@ -93,7 +94,7 @@ public:
void Clear();
- bool ConvertArgumentsForLaunchingInShell(Error &error, bool localhost,
+ bool ConvertArgumentsForLaunchingInShell(Status &error, bool localhost,
bool will_debug,
bool first_arg_is_full_shell_command,
int32_t num_resumes);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/ProcessStructReader.h b/contrib/llvm/tools/lldb/include/lldb/Target/ProcessStructReader.h
index eb51263..cfc8fe1 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/ProcessStructReader.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ProcessStructReader.h
@@ -1,5 +1,4 @@
-//===---------------------ProcessStructReader.h ------------------*- C++
-//-*-===//
+//===---------------------ProcessStructReader.h ------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,17 +7,17 @@
//
//===----------------------------------------------------------------------===//
-#ifndef utility_ProcessStructReader_h_
-#define utility_ProcessStructReader_h_
+#ifndef LLDB_TARGET_PROCESSSTRUCTREADER_H
+#define LLDB_TARGET_PROCESSSTRUCTREADER_H
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Status.h"
#include <initializer_list>
#include <map>
@@ -69,7 +68,7 @@ public:
}
size_t total_size = struct_type.GetByteSize(nullptr);
lldb::DataBufferSP buffer_sp(new DataBufferHeap(total_size, 0));
- Error error;
+ Status error;
process->ReadMemoryFromInferior(base_addr, buffer_sp->GetBytes(),
total_size, error);
if (error.Fail())
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/QueueItem.h b/contrib/llvm/tools/lldb/include/lldb/Target/QueueItem.h
index f637850..acbf94e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/QueueItem.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/QueueItem.h
@@ -23,7 +23,7 @@
#include "lldb/lldb-private.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/QueueList.h b/contrib/llvm/tools/lldb/include/lldb/Target/QueueList.h
index 038463d..91cf3eb 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/QueueList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/QueueList.h
@@ -13,8 +13,8 @@
#include <mutex>
#include <vector>
-#include "lldb/Core/UserID.h"
#include "lldb/Utility/Iterable.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/RegisterCheckpoint.h b/contrib/llvm/tools/lldb/include/lldb/Target/RegisterCheckpoint.h
index 8391cad..578cf25 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/RegisterCheckpoint.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/RegisterCheckpoint.h
@@ -10,8 +10,8 @@
#ifndef liblldb_RegisterCheckpoint_h_
#define liblldb_RegisterCheckpoint_h_
-#include "lldb/Core/UserID.h"
#include "lldb/Target/StackID.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/RegisterContext.h b/contrib/llvm/tools/lldb/include/lldb/Target/RegisterContext.h
index 485645b..c438a0c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/RegisterContext.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/RegisterContext.h
@@ -138,12 +138,12 @@ public:
virtual bool HardwareSingleStep(bool enable);
- virtual Error
+ virtual Status
ReadRegisterValueFromMemory(const lldb_private::RegisterInfo *reg_info,
lldb::addr_t src_addr, uint32_t src_len,
RegisterValue &reg_value);
- virtual Error
+ virtual Status
WriteRegisterValueToMemory(const lldb_private::RegisterInfo *reg_info,
lldb::addr_t dst_addr, uint32_t dst_len,
const RegisterValue &reg_value);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/RegisterNumber.h b/contrib/llvm/tools/lldb/include/lldb/Target/RegisterNumber.h
index b3845ac..5649c80 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/RegisterNumber.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/RegisterNumber.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_RegisterNumber_h
-#define liblldb_RegisterNumber_h
+#ifndef LLDB_TARGET_REGISTERNUMBER_H
+#define LLDB_TARGET_REGISTERNUMBER_H
#include "lldb/lldb-private.h"
#include <map>
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadList.h b/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadList.h
index c232dd9..beb345b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadList.h
@@ -47,7 +47,8 @@ public:
lldb::addr_t GetSectionLoadAddress(const lldb::SectionSP &section_sp) const;
- bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr) const;
+ bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr,
+ bool allow_section_end = false) const;
bool SetSectionLoadAddress(const lldb::SectionSP &section_sp,
lldb::addr_t load_addr,
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/StackFrame.h b/contrib/llvm/tools/lldb/include/lldb/Target/StackFrame.h
index 34bd187..d970435 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/StackFrame.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/StackFrame.h
@@ -17,15 +17,16 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Flags.h"
+#include "lldb/Utility/Flags.h"
+
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/StackID.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UserID.h"
namespace lldb_private {
@@ -200,7 +201,7 @@ public:
/// Returns true if the CFA value was successfully set in value. Some
/// frames may be unable to provide this value; they will return false.
//------------------------------------------------------------------
- bool GetFrameBaseValue(Scalar &value, Error *error_ptr);
+ bool GetFrameBaseValue(Scalar &value, Status *error_ptr);
//------------------------------------------------------------------
/// Get the DWARFExpression corresponding to the Canonical Frame Address.
@@ -214,7 +215,7 @@ public:
/// @return
/// Returns the corresponding DWARF expression, or NULL.
//------------------------------------------------------------------
- DWARFExpression *GetFrameBaseExpression(Error *error_ptr);
+ DWARFExpression *GetFrameBaseExpression(Status *error_ptr);
//------------------------------------------------------------------
/// Get the current lexical scope block for this StackFrame, if possible.
@@ -314,7 +315,7 @@ public:
//------------------------------------------------------------------
lldb::ValueObjectSP GetValueForVariableExpressionPath(
llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
- uint32_t options, lldb::VariableSP &var_sp, Error &error);
+ uint32_t options, lldb::VariableSP &var_sp, Status &error);
//------------------------------------------------------------------
/// Determine whether this StackFrame has debug information available or not
@@ -341,10 +342,13 @@ public:
/// @param [in] strm
/// The Stream to print the description to.
///
+ /// @param [in] show_unique
+ /// Whether to print the function arguments or not for backtrace unique.
+ ///
/// @param [in] frame_marker
/// Optional string that will be prepended to the frame output description.
//------------------------------------------------------------------
- void DumpUsingSettingsFormat(Stream *strm,
+ void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false,
const char *frame_marker = nullptr);
//------------------------------------------------------------------
@@ -374,6 +378,10 @@ public:
/// @param[in] show_source
/// If true, print source or disassembly as per the user's settings.
///
+ /// @param[in] show_unique
+ /// If true, print using backtrace unique style, without function
+ /// arguments as per the user's settings.
+ ///
/// @param[in] frame_marker
/// Passed to DumpUsingSettingsFormat() for the frame info printing.
///
@@ -381,7 +389,7 @@ public:
/// Returns true if successful.
//------------------------------------------------------------------
bool GetStatus(Stream &strm, bool show_frame_info, bool show_source,
- const char *frame_marker = nullptr);
+ bool show_unique = false, const char *frame_marker = nullptr);
//------------------------------------------------------------------
/// Query whether this frame is a concrete frame on the call stack,
@@ -534,7 +542,7 @@ private:
SymbolContext m_sc;
Flags m_flags;
Scalar m_frame_base;
- Error m_frame_base_error;
+ Status m_frame_base_error;
bool m_cfa_is_valid; // Does this frame have a CFA? Different from CFA ==
// LLDB_INVALID_ADDRESS
uint32_t m_stop_id;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/StackFrameList.h b/contrib/llvm/tools/lldb/include/lldb/Target/StackFrameList.h
index a770346..cb9fb13 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/StackFrameList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/StackFrameList.h
@@ -70,6 +70,7 @@ public:
size_t GetStatus(Stream &strm, uint32_t first_frame, uint32_t num_frames,
bool show_frame_info, uint32_t num_frames_with_source,
+ bool show_unique = false,
const char *frame_marker = nullptr);
protected:
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/StopInfo.h b/contrib/llvm/tools/lldb/include/lldb/Target/StopInfo.h
index 46f3456..c99877c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/StopInfo.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/StopInfo.h
@@ -16,8 +16,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StructuredData.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-public.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/StructuredDataPlugin.h b/contrib/llvm/tools/lldb/include/lldb/Target/StructuredDataPlugin.h
index aa4452a..5ea265b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/StructuredDataPlugin.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/StructuredDataPlugin.h
@@ -11,7 +11,7 @@
#define StructuredDataPlugin_h
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Utility/StructuredData.h"
namespace lldb_private {
@@ -123,8 +123,8 @@ public:
/// The error if formatting the object contents failed; otherwise,
/// success.
// -------------------------------------------------------------------------
- virtual Error GetDescription(const StructuredData::ObjectSP &object_sp,
- lldb_private::Stream &stream) = 0;
+ virtual Status GetDescription(const StructuredData::ObjectSP &object_sp,
+ lldb_private::Stream &stream) = 0;
// -------------------------------------------------------------------------
/// Returns whether the plugin's features are enabled.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/SystemRuntime.h b/contrib/llvm/tools/lldb/include/lldb/Target/SystemRuntime.h
index 3a2a544..8c6c2ec 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/SystemRuntime.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/SystemRuntime.h
@@ -16,12 +16,12 @@
// Project includes
#include <vector>
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Target/QueueItem.h"
#include "lldb/Target/QueueList.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
#include "lldb/lldb-public.h"
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Target.h b/contrib/llvm/tools/lldb/include/lldb/Target/Target.h
index 8d6fc77..ff94519 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/Target.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/Target.h
@@ -82,6 +82,10 @@ public:
bool SetPreferDynamicValue(lldb::DynamicValueType d);
+ bool GetPreloadSymbols() const;
+
+ void SetPreloadSymbols(bool b);
+
bool GetDisableASLR() const;
void SetDisableASLR(bool b);
@@ -486,7 +490,7 @@ public:
// UpdateInstanceName ();
lldb::ModuleSP GetSharedModule(const ModuleSpec &module_spec,
- Error *error_ptr = nullptr);
+ Status *error_ptr = nullptr);
//----------------------------------------------------------------------
// Settings accessors
@@ -524,11 +528,11 @@ public:
void Destroy();
- Error Launch(ProcessLaunchInfo &launch_info,
- Stream *stream); // Optional stream to receive first stop info
+ Status Launch(ProcessLaunchInfo &launch_info,
+ Stream *stream); // Optional stream to receive first stop info
- Error Attach(ProcessAttachInfo &attach_info,
- Stream *stream); // Optional stream to receive first stop info
+ Status Attach(ProcessAttachInfo &attach_info,
+ Stream *stream); // Optional stream to receive first stop info
//------------------------------------------------------------------
// This part handles the breakpoints.
@@ -607,7 +611,7 @@ public:
CreateExceptionBreakpoint(enum lldb::LanguageType language, bool catch_bp,
bool throw_bp, bool internal,
Args *additional_args = nullptr,
- Error *additional_args_error = nullptr);
+ Status *additional_args_error = nullptr);
// This is the same as the func_name breakpoint except that you can specify a
// vector of names. This is cheaper
@@ -640,7 +644,7 @@ public:
// Use this to create a watchpoint:
lldb::WatchpointSP CreateWatchpoint(lldb::addr_t addr, size_t size,
const CompilerType *type, uint32_t kind,
- Error &error);
+ Status &error);
lldb::WatchpointSP GetLastCreatedWatchpoint() {
return m_last_created_watchpoint;
@@ -683,15 +687,16 @@ public:
bool IgnoreWatchpointByID(lldb::watch_id_t watch_id, uint32_t ignore_count);
- Error SerializeBreakpointsToFile(const FileSpec &file,
- const BreakpointIDList &bp_ids, bool append);
+ Status SerializeBreakpointsToFile(const FileSpec &file,
+ const BreakpointIDList &bp_ids,
+ bool append);
- Error CreateBreakpointsFromFile(const FileSpec &file,
- BreakpointIDList &new_bps);
+ Status CreateBreakpointsFromFile(const FileSpec &file,
+ BreakpointIDList &new_bps);
- Error CreateBreakpointsFromFile(const FileSpec &file,
- std::vector<std::string> &names,
- BreakpointIDList &new_bps);
+ Status CreateBreakpointsFromFile(const FileSpec &file,
+ std::vector<std::string> &names,
+ BreakpointIDList &new_bps);
//------------------------------------------------------------------
/// Get \a load_addr as a callable code load address for this target
@@ -804,7 +809,7 @@ public:
//------------------------------------------------------------------
void SetExecutableModule(lldb::ModuleSP &module_sp, bool get_dependent_files);
- bool LoadScriptingResources(std::list<Error> &errors,
+ bool LoadScriptingResources(std::list<Status> &errors,
Stream *feedback_stream = nullptr,
bool continue_on_error = true) {
return m_images.LoadScriptingResourcesInTarget(
@@ -910,7 +915,7 @@ public:
Debugger &GetDebugger() { return m_debugger; }
size_t ReadMemoryFromFileCache(const Address &addr, void *dst, size_t dst_len,
- Error &error);
+ Status &error);
// Reading memory through the target allows us to skip going to the process
// for reading memory if possible and it allows us to try and read from
@@ -923,27 +928,27 @@ public:
// 2 - if there is a valid process, try and read from its memory
// 3 - if (prefer_file_cache == false) then read from object file cache
size_t ReadMemory(const Address &addr, bool prefer_file_cache, void *dst,
- size_t dst_len, Error &error,
+ size_t dst_len, Status &error,
lldb::addr_t *load_addr_ptr = nullptr);
size_t ReadCStringFromMemory(const Address &addr, std::string &out_str,
- Error &error);
+ Status &error);
size_t ReadCStringFromMemory(const Address &addr, char *dst,
- size_t dst_max_len, Error &result_error);
+ size_t dst_max_len, Status &result_error);
size_t ReadScalarIntegerFromMemory(const Address &addr,
bool prefer_file_cache, uint32_t byte_size,
bool is_signed, Scalar &scalar,
- Error &error);
+ Status &error);
uint64_t ReadUnsignedIntegerFromMemory(const Address &addr,
bool prefer_file_cache,
size_t integer_byte_size,
- uint64_t fail_value, Error &error);
+ uint64_t fail_value, Status &error);
bool ReadPointerFromMemory(const Address &addr, bool prefer_file_cache,
- Error &error, Address &pointer_addr);
+ Status &error, Address &pointer_addr);
SectionLoadList &GetSectionLoadList() {
return m_section_load_history.GetCurrentSectionLoadList();
@@ -974,7 +979,7 @@ public:
PathMappingList &GetImageSearchPathList();
- TypeSystem *GetScratchTypeSystemForLanguage(Error *error,
+ TypeSystem *GetScratchTypeSystemForLanguage(Status *error,
lldb::LanguageType language,
bool create_on_demand = true);
@@ -989,7 +994,7 @@ public:
UserExpression *GetUserExpressionForLanguage(
llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
Expression::ResultType desired_type,
- const EvaluateExpressionOptions &options, Error &error);
+ const EvaluateExpressionOptions &options, Status &error);
// Creates a FunctionCaller for the given language, the rest of the parameters
// have the
@@ -1004,7 +1009,7 @@ public:
const CompilerType &return_type,
const Address &function_address,
const ValueList &arg_value_list,
- const char *name, Error &error);
+ const char *name, Status &error);
// Creates a UtilityFunction for the given language, the rest of the
// parameters have the
@@ -1014,7 +1019,7 @@ public:
UtilityFunction *GetUtilityFunctionForLanguage(const char *expr,
lldb::LanguageType language,
const char *name,
- Error &error);
+ Status &error);
ClangASTContext *GetScratchClangASTContext(bool create_on_demand = true);
@@ -1024,7 +1029,7 @@ public:
// Install any files through the platform that need be to installed
// prior to launching or attaching.
//----------------------------------------------------------------------
- Error Install(ProcessLaunchInfo *launch_info);
+ Status Install(ProcessLaunchInfo *launch_info);
bool ResolveFileAddress(lldb::addr_t load_addr, Address &so_addr);
@@ -1179,7 +1184,7 @@ public:
GetSearchFilterForModuleAndCUList(const FileSpecList *containingModules,
const FileSpecList *containingSourceFiles);
- lldb::REPLSP GetREPL(Error &err, lldb::LanguageType language,
+ lldb::REPLSP GetREPL(Status &err, lldb::LanguageType language,
const char *repl_options, bool can_create);
void SetREPL(lldb::LanguageType language, lldb::REPLSP repl_sp);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/TargetList.h b/contrib/llvm/tools/lldb/include/lldb/Target/TargetList.h
index 81b81db..43f4520 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/TargetList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/TargetList.h
@@ -91,10 +91,10 @@ public:
/// @return
/// An error object that indicates success or failure
//------------------------------------------------------------------
- Error CreateTarget(Debugger &debugger, llvm::StringRef user_exe_path,
- llvm::StringRef triple_str, bool get_dependent_modules,
- const OptionGroupPlatform *platform_options,
- lldb::TargetSP &target_sp);
+ Status CreateTarget(Debugger &debugger, llvm::StringRef user_exe_path,
+ llvm::StringRef triple_str, bool get_dependent_modules,
+ const OptionGroupPlatform *platform_options,
+ lldb::TargetSP &target_sp);
//------------------------------------------------------------------
/// Create a new Target.
@@ -102,9 +102,9 @@ public:
/// Same as the function above, but used when you already know the
/// platform you will be using
//------------------------------------------------------------------
- Error CreateTarget(Debugger &debugger, llvm::StringRef user_exe_path,
- const ArchSpec &arch, bool get_dependent_modules,
- lldb::PlatformSP &platform_sp, lldb::TargetSP &target_sp);
+ Status CreateTarget(Debugger &debugger, llvm::StringRef user_exe_path,
+ const ArchSpec &arch, bool get_dependent_modules,
+ lldb::PlatformSP &platform_sp, lldb::TargetSP &target_sp);
//------------------------------------------------------------------
/// Delete a Target object from the list.
@@ -211,20 +211,20 @@ protected:
private:
lldb::TargetSP GetDummyTarget(lldb_private::Debugger &debugger);
- Error CreateDummyTarget(Debugger &debugger,
- llvm::StringRef specified_arch_name,
- lldb::TargetSP &target_sp);
+ Status CreateDummyTarget(Debugger &debugger,
+ llvm::StringRef specified_arch_name,
+ lldb::TargetSP &target_sp);
- Error CreateTargetInternal(Debugger &debugger, llvm::StringRef user_exe_path,
- llvm::StringRef triple_str,
- bool get_dependent_files,
- const OptionGroupPlatform *platform_options,
- lldb::TargetSP &target_sp, bool is_dummy_target);
+ Status CreateTargetInternal(Debugger &debugger, llvm::StringRef user_exe_path,
+ llvm::StringRef triple_str,
+ bool get_dependent_files,
+ const OptionGroupPlatform *platform_options,
+ lldb::TargetSP &target_sp, bool is_dummy_target);
- Error CreateTargetInternal(Debugger &debugger, llvm::StringRef user_exe_path,
- const ArchSpec &arch, bool get_dependent_modules,
- lldb::PlatformSP &platform_sp,
- lldb::TargetSP &target_sp, bool is_dummy_target);
+ Status CreateTargetInternal(Debugger &debugger, llvm::StringRef user_exe_path,
+ const ArchSpec &arch, bool get_dependent_modules,
+ lldb::PlatformSP &platform_sp,
+ lldb::TargetSP &target_sp, bool is_dummy_target);
DISALLOW_COPY_AND_ASSIGN(TargetList);
};
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Thread.h b/contrib/llvm/tools/lldb/include/lldb/Target/Thread.h
index 63449bb..1b0b6ef 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/Thread.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/Thread.h
@@ -21,12 +21,12 @@
// Project includes
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/StructuredData.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/RegisterCheckpoint.h"
#include "lldb/Target/StackFrameList.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
#define LLDB_THREAD_MAX_STOP_EXC_DATA 8
@@ -126,6 +126,7 @@ public:
// bit of data.
lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you
// might continue with the wrong signals.
+ std::vector<lldb::ThreadPlanSP> m_completed_plan_stack;
lldb::RegisterCheckpointSP
register_backup_sp; // You need to restore the registers, of course...
uint32_t current_inlined_depth;
@@ -440,16 +441,16 @@ public:
return GetStackFrameList()->GetCurrentInlinedDepth();
}
- Error ReturnFromFrameWithIndex(uint32_t frame_idx,
- lldb::ValueObjectSP return_value_sp,
- bool broadcast = false);
+ Status ReturnFromFrameWithIndex(uint32_t frame_idx,
+ lldb::ValueObjectSP return_value_sp,
+ bool broadcast = false);
- Error ReturnFromFrame(lldb::StackFrameSP frame_sp,
- lldb::ValueObjectSP return_value_sp,
- bool broadcast = false);
+ Status ReturnFromFrame(lldb::StackFrameSP frame_sp,
+ lldb::ValueObjectSP return_value_sp,
+ bool broadcast = false);
- Error JumpToLine(const FileSpec &file, uint32_t line, bool can_leave_function,
- std::string *warnings = nullptr);
+ Status JumpToLine(const FileSpec &file, uint32_t line,
+ bool can_leave_function, std::string *warnings = nullptr);
virtual lldb::StackFrameSP GetFrameWithStackID(const StackID &stack_id) {
if (stack_id.IsValid())
@@ -529,7 +530,7 @@ public:
/// @return
/// An error that describes anything that went wrong
//------------------------------------------------------------------
- virtual Error
+ virtual Status
StepIn(bool source_step,
LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate,
LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
@@ -547,7 +548,7 @@ public:
/// @return
/// An error that describes anything that went wrong
//------------------------------------------------------------------
- virtual Error StepOver(
+ virtual Status StepOver(
bool source_step,
LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);
@@ -560,7 +561,7 @@ public:
/// @return
/// An error that describes anything that went wrong
//------------------------------------------------------------------
- virtual Error StepOut();
+ virtual Status StepOut();
//------------------------------------------------------------------
/// Retrieves the per-thread data area.
@@ -972,7 +973,7 @@ public:
/// An error if the thread plan could not be unwound.
//------------------------------------------------------------------
- Error UnwindInnermostExpression();
+ Status UnwindInnermostExpression();
//------------------------------------------------------------------
/// Gets the outer-most plan that was popped off the plan stack in the
@@ -1029,6 +1030,15 @@ public:
bool WasThreadPlanDiscarded(ThreadPlan *plan);
//------------------------------------------------------------------
+ /// Check if we have completed plan to override breakpoint stop reason
+ ///
+ /// @return
+ /// Returns true if completed plan stack is not empty
+ /// false otherwise.
+ //------------------------------------------------------------------
+ bool CompletedPlanOverridesBreakpoint();
+
+ //------------------------------------------------------------------
/// Queues a generic thread plan.
///
/// @param[in] plan_sp
@@ -1153,8 +1163,8 @@ public:
GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr);
size_t GetStatus(Stream &strm, uint32_t start_frame, uint32_t num_frames,
- uint32_t num_frames_with_source,
- bool stop_format);
+ uint32_t num_frames_with_source, bool stop_format,
+ bool only_stacks = false);
size_t GetStackFrameStatus(Stream &strm, uint32_t first_frame,
uint32_t num_frames, bool show_frame_info,
@@ -1213,6 +1223,8 @@ public:
void SetStopInfo(const lldb::StopInfoSP &stop_info_sp);
+ void ResetStopInfo();
+
void SetShouldReportStop(Vote vote);
//----------------------------------------------------------------------
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadList.h b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadList.h
index 9e3c940..2ebcd0b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadList.h
@@ -13,10 +13,10 @@
#include <mutex>
#include <vector>
-#include "lldb/Core/UserID.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadCollection.h"
#include "lldb/Utility/Iterable.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlan.h b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlan.h
index fd25cd0..acc63ff 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlan.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlan.h
@@ -17,12 +17,12 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/UserID.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanTracer.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
@@ -40,9 +40,10 @@ namespace lldb_private {
// The thread maintaining a thread plan stack, and you program the actions of a
// particular thread
// by pushing plans onto the plan stack.
-// There is always a "Current" plan, which is the head of the plan stack,
+// There is always a "Current" plan, which is the top of the plan stack,
// though in some cases
-// a plan may defer to plans higher in the stack for some piece of information.
+// a plan may defer to plans higher in the stack for some piece of information
+// (let us define that the plan stack grows downwards).
//
// The plan stack is never empty, there is always a Base Plan which persists
// through the life
@@ -109,6 +110,15 @@ namespace lldb_private {
// plans in the time between when
// your plan gets unshipped and the next resume.
//
+// Thread State Checkpoint:
+//
+// Note that calling functions on target process (ThreadPlanCallFunction) changes
+// current thread state. The function can be called either by direct user demand or
+// internally, for example lldb allocates memory on device to calculate breakpoint
+// condition expression - on Linux it is performed by calling mmap on device.
+// ThreadStateCheckpoint saves Thread state (stop info and completed
+// plan stack) to restore it after completing function call.
+//
// Over the lifetime of the plan, various methods of the ThreadPlan are then
// called in response to changes of state in
// the process we are debugging as follows:
@@ -149,7 +159,7 @@ namespace lldb_private {
// If the Current plan answers "true" then it is asked if the stop should
// percolate all the way to the
// user by calling the ShouldStop method. If the current plan doesn't explain
-// the stop, then we query down
+// the stop, then we query up
// the plan stack for a plan that does explain the stop. The plan that does
// explain the stop then needs to
// figure out what to do about the plans below it in the stack. If the stop is
@@ -170,7 +180,7 @@ namespace lldb_private {
// event it didn't directly handle
// it can designate itself a "Master" plan by responding true to IsMasterPlan,
// and then if it wants not to be
-// discarded, it can return true to OkayToDiscard, and it and all its dependent
+// discarded, it can return false to OkayToDiscard, and it and all its dependent
// plans will be preserved when
// we resume execution.
//
@@ -207,7 +217,7 @@ namespace lldb_private {
//
// If a plan says responds "true" to ShouldStop, then it is asked if it's job
// is complete by calling
-// MischiefManaged. If that returns true, the thread is popped from the plan
+// MischiefManaged. If that returns true, the plan is popped from the plan
// stack and added to the
// Completed Plan Stack. Then the next plan in the stack is asked if it
// ShouldStop, and it returns "true",
@@ -241,9 +251,9 @@ namespace lldb_private {
//
// When the process stops, the thread is given a StopReason, in the form of a
// StopInfo object. If there is a completed
-// plan corresponding to the stop, then the "actual" stop reason will be
+// plan corresponding to the stop, then the "actual" stop reason can be
// suppressed, and instead a StopInfoThreadPlan
-// object will be cons'ed up from the highest completed plan in the stack.
+// object will be cons'ed up from the top completed plan in the stack.
// However, if the plan doesn't want to be
// the stop reason, then it can call SetPlanComplete and pass in "false" for
// the "success" parameter. In that case,
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallFunction.h
index 3d43491..1c75b0a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallFunction.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallFunction.h
@@ -117,7 +117,7 @@ protected:
lldb::addr_t &start_load_addr,
lldb::addr_t &function_load_addr);
- void DoTakedown(bool success);
+ virtual void DoTakedown(bool success);
void SetBreakpoints();
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h
index f1425b2..5fe8092 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanCallUserExpression.h
@@ -35,6 +35,8 @@ public:
void GetDescription(Stream *s, lldb::DescriptionLevel level) override;
+ void DidPush() override;
+
void WillPop() override;
lldb::StopInfoSP GetRealStopInfo() override;
@@ -48,6 +50,7 @@ public:
}
protected:
+ void DoTakedown(bool success) override;
private:
lldb::UserExpressionSP
m_user_expression_sp; // This is currently just used to ensure the
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanPython.h b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanPython.h
index a053b5b..973c935 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanPython.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanPython.h
@@ -17,14 +17,14 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StructuredData.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanTracer.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadSpec.h b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadSpec.h
index 204f1f9..34baf80 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadSpec.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadSpec.h
@@ -10,13 +10,9 @@
#ifndef liblldb_ThreadSpec_h_
#define liblldb_ThreadSpec_h_
-// C Includes
-// C++ Includes
-#include <string>
-
-// Other libraries and framework includes
-// Project includes
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
+#include <string>
namespace lldb_private {
@@ -45,7 +41,7 @@ public:
static std::unique_ptr<ThreadSpec>
CreateFromStructuredData(const StructuredData::Dictionary &data_dict,
- Error &error);
+ Status &error);
StructuredData::ObjectSP SerializeToStructuredData();
@@ -55,9 +51,9 @@ public:
void SetTID(lldb::tid_t tid) { m_tid = tid; }
- void SetName(const char *name) { m_name = name; }
+ void SetName(llvm::StringRef name) { m_name = name; }
- void SetQueueName(const char *queue_name) { m_queue_name = queue_name; }
+ void SetQueueName(llvm::StringRef queue_name) { m_queue_name = queue_name; }
uint32_t GetIndex() const { return m_index; }
diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/UnixSignals.h b/contrib/llvm/tools/lldb/include/lldb/Target/UnixSignals.h
index 1c58d64..a209f35 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Target/UnixSignals.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Target/UnixSignals.h
@@ -14,11 +14,13 @@
// C++ Includes
#include <map>
#include <string>
+#include <vector>
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
+#include "llvm/ADT/Optional.h"
namespace lldb_private {
@@ -88,6 +90,19 @@ public:
void RemoveSignal(int signo);
+ // Returns a current version of the data stored in this class.
+ // Version gets incremented each time Set... method is called.
+ uint64_t GetVersion() const;
+
+ // Returns a vector of signals that meet criteria provided in arguments.
+ // Each should_[suppress|stop|notify] flag can be
+ // None - no filtering by this flag
+ // true - only signals that have it set to true are returned
+ // false - only signals that have it set to true are returned
+ std::vector<int32_t> GetFilteredSignals(llvm::Optional<bool> should_suppress,
+ llvm::Optional<bool> should_stop,
+ llvm::Optional<bool> should_notify);
+
protected:
//------------------------------------------------------------------
// Classes that inherit from UnixSignals can see and modify these
@@ -111,6 +126,12 @@ protected:
collection m_signals;
+ // This version gets incremented every time something is changing in
+ // this class, including when we call AddSignal from the constructor.
+ // So after the object is constructed m_version is going to be > 0
+ // if it has at least one signal registered in it.
+ uint64_t m_version = 0;
+
// GDBRemote signals need to be copyable.
UnixSignals(const UnixSignals &rhs);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Baton.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Baton.h
index c2ab9f7..065f296 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Baton.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Baton.h
@@ -10,12 +10,15 @@
#ifndef lldb_Baton_h_
#define lldb_Baton_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
+#include "lldb/lldb-enumerations.h" // for DescriptionLevel
#include "lldb/lldb-public.h"
+#include <memory> // for unique_ptr
+
+namespace lldb_private {
+class Stream;
+}
+
namespace lldb_private {
//----------------------------------------------------------------------
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Connection.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Connection.h
index 6ff7b00..be5641d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Connection.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Connection.h
@@ -10,19 +10,28 @@
#ifndef liblldb_Connection_h_
#define liblldb_Connection_h_
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Utility/Timeout.h"
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for ConnectionStatus
+#include "lldb/lldb-forward.h" // for IOObjectSP
-// C Includes
-// C++ Includes
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <ratio> // for micro
#include <string>
+#include <stddef.h> // for size_t
+
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+template <typename Ratio> class Timeout;
+}
+
namespace lldb_private {
//----------------------------------------------------------------------
-/// @class Connection Connection.h "lldb/Core/Connection.h"
+/// @class Connection Connection.h "lldb/Utility/Connection.h"
/// @brief A communication connection class.
///
/// A class that implements that actual communication functions for
@@ -39,7 +48,7 @@ public:
//------------------------------------------------------------------
/// Default constructor
//------------------------------------------------------------------
- Connection();
+ Connection() = default;
//------------------------------------------------------------------
/// Virtual destructor since this class gets subclassed and handed
@@ -47,8 +56,6 @@ public:
//------------------------------------------------------------------
virtual ~Connection();
- static Connection *CreateDefaultConnection(const char *url);
-
//------------------------------------------------------------------
/// Connect using the connect string \a url.
///
@@ -66,10 +73,10 @@ public:
/// internal error object should be filled in with an
/// appropriate value based on the result of this function.
///
- /// @see Error& Communication::GetError ();
+ /// @see Status& Communication::GetError ();
//------------------------------------------------------------------
virtual lldb::ConnectionStatus Connect(llvm::StringRef url,
- Error *error_ptr) = 0;
+ Status *error_ptr) = 0;
//------------------------------------------------------------------
/// Disconnect the communications connection if one is currently
@@ -85,9 +92,9 @@ public:
/// internal error object should be filled in with an
/// appropriate value based on the result of this function.
///
- /// @see Error& Communication::GetError ();
+ /// @see Status& Communication::GetError ();
//------------------------------------------------------------------
- virtual lldb::ConnectionStatus Disconnect(Error *error_ptr) = 0;
+ virtual lldb::ConnectionStatus Disconnect(Status *error_ptr) = 0;
//------------------------------------------------------------------
/// Check if the connection is valid.
@@ -128,7 +135,7 @@ public:
//------------------------------------------------------------------
virtual size_t Read(void *dst, size_t dst_len,
const Timeout<std::micro> &timeout,
- lldb::ConnectionStatus &status, Error *error_ptr) = 0;
+ lldb::ConnectionStatus &status, Status *error_ptr) = 0;
//------------------------------------------------------------------
/// The actual write function that attempts to write to the
@@ -153,7 +160,7 @@ public:
/// The number of bytes actually Written.
//------------------------------------------------------------------
virtual size_t Write(const void *dst, size_t dst_len,
- lldb::ConnectionStatus &status, Error *error_ptr) = 0;
+ lldb::ConnectionStatus &status, Status *error_ptr) = 0;
//------------------------------------------------------------------
/// Returns a URI that describes this connection object
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ConstString.h b/contrib/llvm/tools/lldb/include/lldb/Utility/ConstString.h
index c6531ca..fbf1a9b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/ConstString.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/ConstString.h
@@ -10,18 +10,22 @@
#ifndef liblldb_ConstString_h_
#define liblldb_ConstString_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatVariadic.h" // for format_provider
-// Project includes
-#include "lldb/lldb-private.h"
+#include <stddef.h> // for size_t
+
+namespace lldb_private {
+class Stream;
+}
+namespace llvm {
+class raw_ostream;
+}
namespace lldb_private {
//----------------------------------------------------------------------
-/// @class ConstString ConstString.h "lldb/Core/ConstString.h"
+/// @class ConstString ConstString.h "lldb/Utility/ConstString.h"
/// @brief A uniqued constant string class.
///
/// Provides an efficient way to store strings as uniqued strings. After
@@ -476,4 +480,11 @@ Stream &operator<<(Stream &s, const ConstString &str);
} // namespace lldb_private
+namespace llvm {
+template <> struct format_provider<lldb_private::ConstString> {
+ static void format(const lldb_private::ConstString &CS, llvm::raw_ostream &OS,
+ llvm::StringRef Options);
+};
+}
+
#endif // liblldb_ConstString_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/ConvertEnum.h b/contrib/llvm/tools/lldb/include/lldb/Utility/ConvertEnum.h
deleted file mode 100644
index 239247d..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/ConvertEnum.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- ConvertEnum.h -------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLDB_UTILITY_CONVERTENUM_H
-#define LLDB_UTILITY_CONVERTENUM_H
-
-#include "lldb/lldb-enumerations.h"
-#include "lldb/lldb-private-enumerations.h"
-
-namespace lldb_private {
-
-const char *GetVoteAsCString(Vote vote);
-const char *GetSectionTypeAsCString(lldb::SectionType sect_type);
-}
-
-#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/DataBuffer.h b/contrib/llvm/tools/lldb/include/lldb/Utility/DataBuffer.h
index ffa71c0..ffa71c0 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/DataBuffer.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/DataBuffer.h
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/DataBufferHeap.h b/contrib/llvm/tools/lldb/include/lldb/Utility/DataBufferHeap.h
index 5528ebd..20e27ef 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/DataBufferHeap.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/DataBufferHeap.h
@@ -10,10 +10,12 @@
#ifndef liblldb_DataBufferHeap_h_
#define liblldb_DataBufferHeap_h_
-#include <vector>
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/lldb-types.h" // for offset_t
+#include "llvm/ADT/StringRef.h" // for StringRef
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/lldb-private.h"
+#include <cstdint> // for uint8_t, uint64_t
+#include <vector>
namespace lldb_private {
@@ -25,7 +27,8 @@ namespace lldb_private {
/// the object. This class is best used to store chunks of data that
/// are created or read from sources that can't intelligently and lazily
/// fault new data pages in. Large amounts of data that comes from files
-/// should probably use the DataBufferMemoryMap class.
+/// should probably use DataBufferLLVM, which can intelligently determine
+/// when memory mapping is optimal.
//----------------------------------------------------------------------
class DataBufferHeap : public DataBuffer {
public:
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/DataBufferLLVM.h b/contrib/llvm/tools/lldb/include/lldb/Utility/DataBufferLLVM.h
new file mode 100644
index 0000000..737e2d0
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/DataBufferLLVM.h
@@ -0,0 +1,52 @@
+//===--- DataBufferLLVM.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_CORE_DATABUFFERLLVM_H
+#define LLDB_CORE_DATABUFFERLLVM_H
+
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/lldb-types.h" // for offset_t
+
+#include <memory>
+#include <stdint.h> // for uint8_t, uint64_t
+
+namespace llvm {
+class MemoryBuffer;
+class Twine;
+}
+
+namespace lldb_private {
+
+class DataBufferLLVM : public DataBuffer {
+public:
+ ~DataBufferLLVM();
+
+ static std::shared_ptr<DataBufferLLVM>
+ CreateSliceFromPath(const llvm::Twine &Path, uint64_t Size, uint64_t Offset, bool Private = false);
+
+ static std::shared_ptr<DataBufferLLVM>
+ CreateFromPath(const llvm::Twine &Path, bool NullTerminate = false, bool Private = false);
+
+ uint8_t *GetBytes() override;
+ const uint8_t *GetBytes() const override;
+ lldb::offset_t GetByteSize() const override;
+
+ char *GetChars() { return reinterpret_cast<char *>(GetBytes()); }
+
+private:
+ /// \brief Construct a DataBufferLLVM from \p Buffer. \p Buffer must be a
+ /// valid pointer.
+ explicit DataBufferLLVM(std::unique_ptr<llvm::MemoryBuffer> Buffer);
+ const uint8_t *GetBuffer() const;
+
+ std::unique_ptr<llvm::MemoryBuffer> Buffer;
+};
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/DataEncoder.h b/contrib/llvm/tools/lldb/include/lldb/Utility/DataEncoder.h
index a2bc4dc..ea347d8 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/DataEncoder.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/DataEncoder.h
@@ -12,8 +12,12 @@
#if defined(__cplusplus)
-#include "lldb/lldb-private.h"
-#include <limits.h>
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
+#include "lldb/lldb-enumerations.h" // for ByteOrder
+#include "lldb/lldb-forward.h" // for DataBufferSP
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <stddef.h> // for size_t
#include <stdint.h>
namespace lldb_private {
@@ -384,9 +388,9 @@ protected:
lldb::ByteOrder
m_byte_order; ///< The byte order of the data we are extracting from.
uint8_t m_addr_size; ///< The address size to use when extracting pointers or
- ///addresses
+ /// addresses
mutable lldb::DataBufferSP m_data_sp; ///< The shared pointer to data that can
- ///be shared among multiple instances
+ /// be shared among multiple instances
private:
DISALLOW_COPY_AND_ASSIGN(DataEncoder);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/DataExtractor.h b/contrib/llvm/tools/lldb/include/lldb/Utility/DataExtractor.h
index 89cc005..4ef78c1 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/DataExtractor.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/DataExtractor.h
@@ -7,20 +7,29 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_DataExtractor_h_
-#define liblldb_DataExtractor_h_
+#ifndef LLDB_UTILITY_DATAEXTRACTOR_H
+#define LLDB_UTILITY_DATAEXTRACTOR_H
-// C Includes
-#include <limits.h>
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h" // for ByteOrder
+#include "lldb/lldb-forward.h" // for DataBufferSP
+#include "lldb/lldb-types.h"
+
+#include <cassert>
#include <stdint.h>
#include <string.h>
-// C++ Includes
-// Other libraries and framework includes
-#include "llvm/ADT/SmallVector.h"
+namespace lldb_private {
+class Log;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace llvm {
+template <typename T> class SmallVectorImpl;
+}
-// Project includes
-#include "lldb/lldb-private.h"
+// C++ Includes
namespace lldb_private {
@@ -43,8 +52,6 @@ public:
//------------------------------------------------------------------
/// @typedef DataExtractor::Type
/// @brief Type enumerations used in the dump routines.
- /// @see DataExtractor::Dump()
- /// @see DataExtractor::DumpRawHexBytes()
//------------------------------------------------------------------
typedef enum {
TypeUInt8, ///< Format output as unsigned 8 bit integers
@@ -57,12 +64,6 @@ public:
TypeSLEB128 ///< Format output as SLEB128 numbers
} Type;
- static void DumpHexBytes(Stream *s, const void *src, size_t src_len,
- uint32_t bytes_per_line,
- lldb::addr_t base_addr); // Pass LLDB_INVALID_ADDRESS
- // to not show address at
- // start of line
-
//------------------------------------------------------------------
/// Default constructor.
///
@@ -172,7 +173,9 @@ public:
/// reference count on the data will be decremented, and if zero,
/// the data will be freed.
//------------------------------------------------------------------
- ~DataExtractor();
+ virtual ~DataExtractor();
+
+ uint32_t getTargetByteSize() const { return m_target_byte_size; }
//------------------------------------------------------------------
/// Clears the object state.
@@ -225,73 +228,6 @@ public:
const char *type_format = nullptr) const;
//------------------------------------------------------------------
- /// Dumps \a item_count objects into the stream \a s.
- ///
- /// Dumps \a item_count objects using \a item_format, each of which
- /// are \a item_byte_size bytes long starting at offset \a offset
- /// bytes into the contained data, into the stream \a s. \a
- /// num_per_line objects will be dumped on each line before a new
- /// line will be output. If \a base_addr is a valid address, then
- /// each new line of output will be preceded by the address value
- /// plus appropriate offset, and a colon and space. Bitfield values
- /// can be dumped by calling this function multiple times with the
- /// same start offset, format and size, yet differing \a
- /// item_bit_size and \a item_bit_offset values.
- ///
- /// @param[in] s
- /// The stream to dump the output to. This value can not be nullptr.
- ///
- /// @param[in] offset
- /// The offset into the data at which to start dumping.
- ///
- /// @param[in] item_format
- /// The format to use when dumping each item.
- ///
- /// @param[in] item_byte_size
- /// The byte size of each item.
- ///
- /// @param[in] item_count
- /// The number of items to dump.
- ///
- /// @param[in] num_per_line
- /// The number of items to display on each line.
- ///
- /// @param[in] base_addr
- /// The base address that gets added to the offset displayed on
- /// each line if the value is valid. Is \a base_addr is
- /// LLDB_INVALID_ADDRESS then no address values will be prepended
- /// to any lines.
- ///
- /// @param[in] item_bit_size
- /// If the value to display is a bitfield, this value should
- /// be the number of bits that the bitfield item has within the
- /// item's byte size value. This function will need to be called
- /// multiple times with identical \a offset and \a item_byte_size
- /// values in order to display multiple bitfield values that
- /// exist within the same integer value. If the items being
- /// displayed are not bitfields, this value should be zero.
- ///
- /// @param[in] item_bit_offset
- /// If the value to display is a bitfield, this value should
- /// be the offset in bits, or shift right amount, that the
- /// bitfield item occupies within the item's byte size value.
- /// This function will need to be called multiple times with
- /// identical \a offset and \a item_byte_size values in order
- /// to display multiple bitfield values that exist within the
- /// same integer value. If the items being displayed are not
- /// bitfields, this value should be zero.
- ///
- /// @return
- /// The offset at which dumping ended.
- //------------------------------------------------------------------
- lldb::offset_t Dump(Stream *s, lldb::offset_t offset,
- lldb::Format item_format, size_t item_byte_size,
- size_t item_count, size_t num_per_line,
- uint64_t base_addr, uint32_t item_bit_size,
- uint32_t item_bit_offset,
- ExecutionContextScope *exe_scope = nullptr) const;
-
- //------------------------------------------------------------------
/// Dump a UUID value at \a offset.
///
/// Dump a UUID starting at \a offset bytes into this object's data.
@@ -573,38 +509,6 @@ public:
long double GetLongDouble(lldb::offset_t *offset_ptr) const;
//------------------------------------------------------------------
- /// Extract a GNU encoded pointer value from \a *offset_ptr.
- ///
- /// @param[in,out] offset_ptr
- /// A pointer to an offset within the data that will be advanced
- /// by the appropriate number of bytes if the value is extracted
- /// correctly. If the offset is out of bounds or there are not
- /// enough bytes to extract this value, the offset will be left
- /// unmodified.
- ///
- /// @param[in] eh_ptr_enc
- /// The GNU pointer encoding type.
- ///
- /// @param[in] pc_rel_addr
- /// The PC relative address to use when the encoding is
- /// \c DW_GNU_EH_PE_pcrel.
- ///
- /// @param[in] text_addr
- /// The text (code) relative address to use when the encoding is
- /// \c DW_GNU_EH_PE_textrel.
- ///
- /// @param[in] data_addr
- /// The data relative address to use when the encoding is
- /// \c DW_GNU_EH_PE_datarel.
- ///
- /// @return
- /// The extracted GNU encoded pointer value.
- //------------------------------------------------------------------
- uint64_t GetGNUEHPointer(lldb::offset_t *offset_ptr, uint32_t eh_ptr_enc,
- lldb::addr_t pc_rel_addr, lldb::addr_t text_addr,
- lldb::addr_t data_addr);
-
- //------------------------------------------------------------------
/// Extract an integer of size \a byte_size from \a *offset_ptr.
///
/// Extract a single integer value and update the offset pointed to
@@ -1243,9 +1147,9 @@ protected:
lldb::ByteOrder
m_byte_order; ///< The byte order of the data we are extracting from.
uint32_t m_addr_size; ///< The address size to use when extracting pointers or
- ///addresses
+ /// addresses
mutable lldb::DataBufferSP m_data_sp; ///< The shared pointer to data that can
- ///be shared among multiple instances
+ /// be shared among multiple instances
const uint32_t m_target_byte_size;
};
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Endian.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Endian.h
index 82bc0b7..2a102b6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/Endian.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Endian.h
@@ -7,11 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_host_endian_h_
-#define liblldb_host_endian_h_
+#ifndef LLDB_UTILITY_ENDIAN_H
+#define LLDB_UTILITY_ENDIAN_H
#include "lldb/lldb-enumerations.h"
+#include <stdint.h>
+
namespace lldb_private {
namespace endian {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/FastDemangle.h b/contrib/llvm/tools/lldb/include/lldb/Utility/FastDemangle.h
index f779aaa..f779aaa 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/FastDemangle.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/FastDemangle.h
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/FileSpec.h b/contrib/llvm/tools/lldb/include/lldb/Utility/FileSpec.h
index b8df745..67926d0 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/FileSpec.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/FileSpec.h
@@ -17,13 +17,28 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/STLUtils.h"
-#include "lldb/Host/PosixApi.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/ConstString.h"
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+
+namespace lldb_private {
+class Stream;
+}
+namespace llvm {
+class Triple;
+}
+namespace llvm {
+class raw_ostream;
+}
+namespace llvm {
+template <typename T> class SmallVectorImpl;
+}
+
namespace lldb_private {
//----------------------------------------------------------------------
@@ -46,17 +61,6 @@ namespace lldb_private {
//----------------------------------------------------------------------
class FileSpec {
public:
- typedef enum FileType {
- eFileTypeInvalid = -1,
- eFileTypeUnknown = 0,
- eFileTypeDirectory,
- eFileTypePipe,
- eFileTypeRegular,
- eFileTypeSocket,
- eFileTypeSymbolicLink,
- eFileTypeOther
- } FileType;
-
enum PathSyntax {
ePathSyntaxPosix,
ePathSyntaxWindows,
@@ -85,7 +89,8 @@ public:
explicit FileSpec(llvm::StringRef path, bool resolve_path,
PathSyntax syntax = ePathSyntaxHostNative);
- explicit FileSpec(llvm::StringRef path, bool resolve_path, ArchSpec arch);
+ explicit FileSpec(llvm::StringRef path, bool resolve_path,
+ const llvm::Triple &Triple);
//------------------------------------------------------------------
/// Copy constructor
@@ -454,8 +459,6 @@ public:
//------------------------------------------------------------------
ConstString GetFileNameStrippingExtension() const;
- FileType GetFileType() const;
-
//------------------------------------------------------------------
/// Return the current permissions of the path.
///
@@ -470,20 +473,6 @@ public:
//------------------------------------------------------------------
uint32_t GetPermissions() const;
- bool IsDirectory() const {
- return GetFileType() == FileSpec::eFileTypeDirectory;
- }
-
- bool IsPipe() const { return GetFileType() == FileSpec::eFileTypePipe; }
-
- bool IsRegularFile() const {
- return GetFileType() == FileSpec::eFileTypeRegular;
- }
-
- bool IsSocket() const { return GetFileType() == FileSpec::eFileTypeSocket; }
-
- bool IsSymbolicLink() const;
-
//------------------------------------------------------------------
/// Get the memory cost of this object.
///
@@ -499,124 +488,6 @@ public:
size_t MemorySize() const;
//------------------------------------------------------------------
- /// Memory map part of, or the entire contents of, a file.
- ///
- /// Returns a shared pointer to a data buffer that contains all or
- /// part of the contents of a file. The data is memory mapped and
- /// will lazily page in data from the file as memory is accessed.
- /// The data that is mapped will start \a offset bytes into the
- /// file, and \a length bytes will be mapped. If \a length is
- /// greater than the number of bytes available in the file starting
- /// at \a offset, the number of bytes will be appropriately
- /// truncated. The final number of bytes that get mapped can be
- /// verified using the DataBuffer::GetByteSize() function on the return
- /// shared data pointer object contents.
- ///
- /// @param[in] offset
- /// The offset in bytes from the beginning of the file where
- /// memory mapping should begin.
- ///
- /// @param[in] length
- /// The size in bytes that should be mapped starting \a offset
- /// bytes into the file. If \a length is \c SIZE_MAX, map
- /// as many bytes as possible.
- ///
- /// @return
- /// A shared pointer to the memory mapped data. This shared
- /// pointer can contain a nullptr DataBuffer pointer, so the contained
- /// pointer must be checked prior to using it.
- //------------------------------------------------------------------
- lldb::DataBufferSP MemoryMapFileContents(off_t offset = 0,
- size_t length = SIZE_MAX) const;
-
- //------------------------------------------------------------------
- /// Memory map part of, or the entire contents of, a file only if
- /// the file is local (not on a network mount).
- ///
- /// Returns a shared pointer to a data buffer that contains all or
- /// part of the contents of a file. The data will be memory mapped
- /// if the file is local and will lazily page in data from the file
- /// as memory is accessed. If the data is memory mapped, the data
- /// that is mapped will start \a offset bytes into the file, and
- /// \a length bytes will be mapped. If \a length is
- /// greater than the number of bytes available in the file starting
- /// at \a offset, the number of bytes will be appropriately
- /// truncated. The final number of bytes that get mapped can be
- /// verified using the DataBuffer::GetByteSize() function on the return
- /// shared data pointer object contents.
- ///
- /// If the file is on a network mount the data will be read into a
- /// heap buffer immediately so that accesses to the data won't later
- /// cause a crash if we touch a page that isn't paged in and the
- /// network mount has been disconnected or gone away.
- ///
- /// @param[in] offset
- /// The offset in bytes from the beginning of the file where
- /// memory mapping should begin.
- ///
- /// @param[in] length
- /// The size in bytes that should be mapped starting \a offset
- /// bytes into the file. If \a length is \c SIZE_MAX, map
- /// as many bytes as possible.
- ///
- /// @return
- /// A shared pointer to the memory mapped data. This shared
- /// pointer can contain a nullptr DataBuffer pointer, so the contained
- /// pointer must be checked prior to using it.
- //------------------------------------------------------------------
- lldb::DataBufferSP MemoryMapFileContentsIfLocal(off_t file_offset,
- size_t file_size) const;
-
- //------------------------------------------------------------------
- /// Read part of, or the entire contents of, a file into a heap based data
- /// buffer.
- ///
- /// Returns a shared pointer to a data buffer that contains all or
- /// part of the contents of a file. The data copies into a heap based
- /// buffer that lives in the DataBuffer shared pointer object returned.
- /// The data that is cached will start \a offset bytes into the
- /// file, and \a length bytes will be mapped. If \a length is
- /// greater than the number of bytes available in the file starting
- /// at \a offset, the number of bytes will be appropriately
- /// truncated. The final number of bytes that get mapped can be
- /// verified using the DataBuffer::GetByteSize() function.
- ///
- /// @param[in] offset
- /// The offset in bytes from the beginning of the file where
- /// memory mapping should begin.
- ///
- /// @param[in] length
- /// The size in bytes that should be mapped starting \a offset
- /// bytes into the file. If \a length is \c SIZE_MAX, map
- /// as many bytes as possible.
- ///
- /// @return
- /// A shared pointer to the memory mapped data. This shared
- /// pointer can contain a nullptr DataBuffer pointer, so the contained
- /// pointer must be checked prior to using it.
- //------------------------------------------------------------------
- lldb::DataBufferSP ReadFileContents(off_t offset = 0,
- size_t length = SIZE_MAX,
- Error *error_ptr = nullptr) const;
-
- size_t ReadFileContents(off_t file_offset, void *dst, size_t dst_len,
- Error *error_ptr) const;
-
- //------------------------------------------------------------------
- /// Read the entire contents of a file as data that can be used
- /// as a C string.
- ///
- /// Read the entire contents of a file and ensure that the data
- /// is NULL terminated so it can be used as a C string.
- ///
- /// @return
- /// A shared pointer to the data. This shared pointer can
- /// contain a nullptr DataBuffer pointer, so the contained pointer
- /// must be checked prior to using it.
- //------------------------------------------------------------------
- lldb::DataBufferSP ReadFileContentsAsCString(Error *error_ptr = nullptr);
-
- //------------------------------------------------------------------
/// Normalize a pathname by collapsing redundant separators and
/// up-level references.
//------------------------------------------------------------------
@@ -639,7 +510,8 @@ public:
void SetFile(llvm::StringRef path, bool resolve_path,
PathSyntax syntax = ePathSyntaxHostNative);
- void SetFile(llvm::StringRef path, bool resolve_path, ArchSpec arch);
+ void SetFile(llvm::StringRef path, bool resolve_path,
+ const llvm::Triple &Triple);
bool IsResolved() const { return m_is_resolved; }
@@ -659,21 +531,6 @@ public:
void SetIsResolved(bool is_resolved) { m_is_resolved = is_resolved; }
//------------------------------------------------------------------
- /// Read the file into an array of strings, one per line.
- ///
- /// Opens and reads the file in this object into an array of strings,
- /// one string per line of the file. Returns a boolean indicating
- /// success or failure.
- ///
- /// @param[out] lines
- /// The string array into which to read the file.
- ///
- /// @result
- /// Returns the number of lines that were read from the file.
- //------------------------------------------------------------------
- size_t ReadFileLines(STLStringArray &lines);
-
- //------------------------------------------------------------------
/// Resolves user name and links in \a path, and overwrites the input
/// argument with the resolved path.
///
@@ -696,53 +553,27 @@ public:
ConstString GetLastPathComponent() const;
- //------------------------------------------------------------------
- /// Resolves the user name at the beginning of \a src_path, and writes the
- /// output
- /// to \a dst_path. Note, \a src_path can contain other path components after
- /// the
- /// user name, they will be copied over, and if the path doesn't start with
- /// "~" it
- /// will also be copied over to \a dst_path.
- ///
- /// @param[in] src_path
- /// Input path to be resolved.
- ///
- /// @param[in] dst_path
- /// Buffer to store the resolved path.
- //------------------------------------------------------------------
- static void ResolveUsername(llvm::SmallVectorImpl<char> &path);
-
- static size_t ResolvePartialUsername(llvm::StringRef partial_name,
- StringList &matches);
-
enum EnumerateDirectoryResult {
eEnumerateDirectoryResultNext, // Enumerate next entry in the current
// directory
eEnumerateDirectoryResultEnter, // Recurse into the current entry if it is a
// directory or symlink, or next if not
- eEnumerateDirectoryResultExit, // Exit from the current directory at the
- // current level.
eEnumerateDirectoryResultQuit // Stop directory enumerations at any level
};
typedef EnumerateDirectoryResult (*EnumerateDirectoryCallbackType)(
- void *baton, FileType file_type, const FileSpec &spec);
+ void *baton, llvm::sys::fs::file_type file_type, const FileSpec &spec);
- static EnumerateDirectoryResult
- EnumerateDirectory(llvm::StringRef dir_path, bool find_directories,
- bool find_files, bool find_other,
- EnumerateDirectoryCallbackType callback,
- void *callback_baton);
+ static void EnumerateDirectory(llvm::StringRef dir_path,
+ bool find_directories, bool find_files,
+ bool find_other,
+ EnumerateDirectoryCallbackType callback,
+ void *callback_baton);
- typedef std::function<EnumerateDirectoryResult(FileType file_type,
- const FileSpec &spec)>
+ typedef std::function<EnumerateDirectoryResult(
+ llvm::sys::fs::file_type file_type, const FileSpec &spec)>
DirectoryCallback;
- static EnumerateDirectoryResult
- ForEachItemInDirectory(llvm::StringRef dir_path,
- DirectoryCallback const &callback);
-
protected:
//------------------------------------------------------------------
// Member variables
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Flags.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Flags.h
index d1bf685..1b30385 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Flags.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Flags.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_Flags_h_
-#define liblldb_Flags_h_
+#ifndef LLDB_UTILITY_FLAGS_H
+#define LLDB_UTILITY_FLAGS_H
#include <cstddef>
#include <cstdint>
@@ -16,7 +16,7 @@
namespace lldb_private {
//----------------------------------------------------------------------
-/// @class Flags Flags.h "lldb/Core/Flags.h"
+/// @class Flags Flags.h "lldb/Utility/Flags.h"
/// @brief A class to manage flags.
///
/// The Flags class managed flag bits and allows testing and
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/History.h b/contrib/llvm/tools/lldb/include/lldb/Utility/History.h
index fcffcdd..c6882b6 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/History.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/History.h
@@ -10,17 +10,19 @@
#ifndef lldb_History_h_
#define lldb_History_h_
-// C Includes
-#include <stdint.h>
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
// C++ Includes
#include <mutex>
#include <stack>
#include <string>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/lldb-public.h"
+#include <stddef.h> // for size_t
+#include <stdint.h>
+
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/IOObject.h b/contrib/llvm/tools/lldb/include/lldb/Utility/IOObject.h
index 90e0bcd..61f2881 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/IOObject.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/IOObject.h
@@ -32,12 +32,12 @@ public:
IOObject(FDType type, bool should_close)
: m_fd_type(type), m_should_close_fd(should_close) {}
- virtual ~IOObject() {}
+ virtual ~IOObject();
- virtual Error Read(void *buf, size_t &num_bytes) = 0;
- virtual Error Write(const void *buf, size_t &num_bytes) = 0;
+ virtual Status Read(void *buf, size_t &num_bytes) = 0;
+ virtual Status Write(const void *buf, size_t &num_bytes) = 0;
virtual bool IsValid() const = 0;
- virtual Error Close() = 0;
+ virtual Status Close() = 0;
FDType GetFdType() const { return m_fd_type; }
@@ -51,6 +51,6 @@ protected:
private:
DISALLOW_COPY_AND_ASSIGN(IOObject);
};
-}
+} // namespace lldb_private
#endif
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/JSON.h b/contrib/llvm/tools/lldb/include/lldb/Utility/JSON.h
index 145ef48..8bf9c4b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/JSON.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/JSON.h
@@ -10,19 +10,20 @@
#ifndef utility_JSON_h_
#define utility_JSON_h_
-#include "lldb/Core/Stream.h"
#include "lldb/Utility/StringExtractor.h"
-#include <inttypes.h>
#include <map>
#include <memory>
-#include <stdint.h>
#include <string>
+#include <type_traits>
#include <vector>
-#include "llvm/Support/Casting.h"
+#include <stdint.h>
namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
class JSONValue {
public:
@@ -252,7 +253,7 @@ class JSONParser : public StringExtractor {
public:
enum Token {
Invalid,
- Error,
+ Status,
ObjectStart,
ObjectEnd,
ArrayStart,
@@ -268,7 +269,7 @@ public:
EndOfFile
};
- JSONParser(const char *cstr);
+ JSONParser(llvm::StringRef data);
int GetEscapedChar(bool &was_escaped);
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/LLDBAssert.h b/contrib/llvm/tools/lldb/include/lldb/Utility/LLDBAssert.h
index 328a4d4..9d9f3ce 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/LLDBAssert.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/LLDBAssert.h
@@ -1,5 +1,4 @@
-//===----------------- LLDBAssert.h --------------------------------*- C++
-//-*-===//
+//===----------------- LLDBAssert.h ------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,8 +10,6 @@
#ifndef utility_LLDBAssert_h_
#define utility_LLDBAssert_h_
-#include <assert.h>
-
#ifdef LLDB_CONFIGURATION_DEBUG
#define lldbassert(x) assert(x)
#else
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/Log.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Log.h
new file mode 100644
index 0000000..d856fc8
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Log.h
@@ -0,0 +1,216 @@
+//===-- Log.h ---------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_LOG_H
+#define LLDB_UTILITY_LOG_H
+
+#include "lldb/Utility/Flags.h"
+#include "lldb/Utility/Logging.h"
+#include "lldb/lldb-defines.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h" // for StringMap
+#include "llvm/ADT/StringRef.h" // for StringRef, StringLiteral
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/RWMutex.h"
+
+#include <atomic>
+#include <cstdarg>
+#include <cstdint>
+#include <memory> // for shared_ptr
+#include <string> // for string
+#include <type_traits> // for forward
+
+namespace llvm {
+class raw_ostream;
+}
+//----------------------------------------------------------------------
+// Logging Options
+//----------------------------------------------------------------------
+#define LLDB_LOG_OPTION_THREADSAFE (1u << 0)
+#define LLDB_LOG_OPTION_VERBOSE (1u << 1)
+#define LLDB_LOG_OPTION_PREPEND_SEQUENCE (1u << 3)
+#define LLDB_LOG_OPTION_PREPEND_TIMESTAMP (1u << 4)
+#define LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD (1u << 5)
+#define LLDB_LOG_OPTION_PREPEND_THREAD_NAME (1U << 6)
+#define LLDB_LOG_OPTION_BACKTRACE (1U << 7)
+#define LLDB_LOG_OPTION_APPEND (1U << 8)
+#define LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION (1U << 9)
+
+//----------------------------------------------------------------------
+// Logging Functions
+//----------------------------------------------------------------------
+namespace lldb_private {
+
+class Log final {
+public:
+ // Description of a log channel category.
+ struct Category {
+ llvm::StringLiteral name;
+ llvm::StringLiteral description;
+ uint32_t flag;
+ };
+
+ // This class describes a log channel. It also encapsulates the behavior
+ // necessary to enable a log channel in an atomic manner.
+ class Channel {
+ std::atomic<Log *> log_ptr;
+ friend class Log;
+
+ public:
+ const llvm::ArrayRef<Category> categories;
+ const uint32_t default_flags;
+
+ constexpr Channel(llvm::ArrayRef<Log::Category> categories,
+ uint32_t default_flags)
+ : log_ptr(nullptr), categories(categories),
+ default_flags(default_flags) {}
+
+ // This function is safe to call at any time
+ // If the channel is disabled after (or concurrently with) this function
+ // returning a non-null Log pointer, it is still safe to attempt to write to
+ // the Log object -- the output will be discarded.
+ Log *GetLogIfAll(uint32_t mask) {
+ Log *log = log_ptr.load(std::memory_order_relaxed);
+ if (log && log->GetMask().AllSet(mask))
+ return log;
+ return nullptr;
+ }
+
+ // This function is safe to call at any time
+ // If the channel is disabled after (or concurrently with) this function
+ // returning a non-null Log pointer, it is still safe to attempt to write to
+ // the Log object -- the output will be discarded.
+ Log *GetLogIfAny(uint32_t mask) {
+ Log *log = log_ptr.load(std::memory_order_relaxed);
+ if (log && log->GetMask().AnySet(mask))
+ return log;
+ return nullptr;
+ }
+ };
+
+ //------------------------------------------------------------------
+ // Static accessors for logging channels
+ //------------------------------------------------------------------
+ static void Register(llvm::StringRef name, Channel &channel);
+ static void Unregister(llvm::StringRef name);
+
+ static bool
+ EnableLogChannel(const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
+ uint32_t log_options, llvm::StringRef channel,
+ llvm::ArrayRef<const char *> categories,
+ llvm::raw_ostream &error_stream);
+
+ static bool DisableLogChannel(llvm::StringRef channel,
+ llvm::ArrayRef<const char *> categories,
+ llvm::raw_ostream &error_stream);
+
+ static bool ListChannelCategories(llvm::StringRef channel, llvm::raw_ostream &stream);
+
+ static void DisableAllLogChannels();
+
+ static void ListAllLogChannels(llvm::raw_ostream &stream);
+
+ //------------------------------------------------------------------
+ // Member functions
+ //
+ // These functions are safe to call at any time you have a Log* obtained from
+ // the Channel class. If logging is disabled between you obtaining the Log
+ // object and writing to it, the output will be silently discarded.
+ //------------------------------------------------------------------
+ Log(Channel &channel) : m_channel(channel) {}
+ ~Log() = default;
+
+ void PutCString(const char *cstr);
+ void PutString(llvm::StringRef str);
+
+ template <typename... Args>
+ void Format(llvm::StringRef file, llvm::StringRef function,
+ const char *format, Args &&... args) {
+ Format(file, function, llvm::formatv(format, std::forward<Args>(args)...));
+ }
+
+ void Printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
+
+ void VAPrintf(const char *format, va_list args);
+
+ void Error(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+
+ void VAError(const char *format, va_list args);
+
+ void Verbose(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+
+ void Warning(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+
+ const Flags GetOptions() const;
+
+ const Flags GetMask() const;
+
+ bool GetVerbose() const;
+
+private:
+ Channel &m_channel;
+
+ // The mutex makes sure enable/disable operations are thread-safe. The options
+ // and mask variables are atomic to enable their reading in
+ // Channel::GetLogIfAny without taking the mutex to speed up the fast path.
+ // Their modification however, is still protected by this mutex.
+ llvm::sys::RWMutex m_mutex;
+
+ std::shared_ptr<llvm::raw_ostream> m_stream_sp;
+ std::atomic<uint32_t> m_options{0};
+ std::atomic<uint32_t> m_mask{0};
+
+ void WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
+ llvm::StringRef function);
+ void WriteMessage(const std::string &message);
+
+ void Format(llvm::StringRef file, llvm::StringRef function,
+ const llvm::formatv_object_base &payload);
+
+ std::shared_ptr<llvm::raw_ostream> GetStream() {
+ llvm::sys::ScopedReader lock(m_mutex);
+ return m_stream_sp;
+ }
+
+ void Enable(const std::shared_ptr<llvm::raw_ostream> &stream_sp,
+ uint32_t options, uint32_t flags);
+
+ void Disable(uint32_t flags);
+
+ typedef llvm::StringMap<Log> ChannelMap;
+ static llvm::ManagedStatic<ChannelMap> g_channel_map;
+
+ static void ListCategories(llvm::raw_ostream &stream,
+ const ChannelMap::value_type &entry);
+ static uint32_t GetFlags(llvm::raw_ostream &stream, const ChannelMap::value_type &entry,
+ llvm::ArrayRef<const char *> categories);
+
+ Log(const Log &) = delete;
+ void operator=(const Log &) = delete;
+};
+
+} // namespace lldb_private
+
+#define LLDB_LOG(log, ...) \
+ do { \
+ ::lldb_private::Log *log_private = (log); \
+ if (log_private) \
+ log_private->Format(__FILE__, __FUNCTION__, __VA_ARGS__); \
+ } while (0)
+
+#define LLDB_LOGV(log, ...) \
+ do { \
+ ::lldb_private::Log *log_private = (log); \
+ if (log_private && log_private->GetVerbose()) \
+ log_private->Format(__FILE__, __FUNCTION__, __VA_ARGS__); \
+ } while (0)
+
+#endif // LLDB_UTILITY_LOG_H
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Logging.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Logging.h
index d93fa05..865097e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Logging.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Logging.h
@@ -7,19 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_Core_Logging_h_
-#define liblldb_Core_Logging_h_
+#ifndef LLDB_UTILITY_LOGGING_H
+#define LLDB_UTILITY_LOGGING_H
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/lldb-private.h"
+#include <cstdint>
//----------------------------------------------------------------------
// Log Bits specific to logging in lldb
//----------------------------------------------------------------------
-#define LIBLLDB_LOG_VERBOSE (1u << 0)
#define LIBLLDB_LOG_PROCESS (1u << 1)
#define LIBLLDB_LOG_THREAD (1u << 2)
#define LIBLLDB_LOG_DYNAMIC_LOADER (1u << 3)
@@ -59,7 +54,7 @@
namespace lldb_private {
-void LogIfAllCategoriesSet(uint32_t mask, const char *format, ...);
+class Log;
void LogIfAnyCategoriesSet(uint32_t mask, const char *format, ...);
@@ -67,17 +62,8 @@ Log *GetLogIfAllCategoriesSet(uint32_t mask);
Log *GetLogIfAnyCategoriesSet(uint32_t mask);
-uint32_t GetLogMask();
-
-bool IsLogVerbose();
-
-void DisableLog(const char **categories, Stream *feedback_strm);
-
-Log *EnableLog(lldb::StreamSP &log_stream_sp, uint32_t log_options,
- const char **categories, Stream *feedback_strm);
-
-void ListLogCategories(Stream *strm);
+void InitializeLog();
} // namespace lldb_private
-#endif // liblldb_Core_Logging_h_
+#endif // LLDB_UTILITY_LOGGING_H
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/NameMatches.h b/contrib/llvm/tools/lldb/include/lldb/Utility/NameMatches.h
index 50ea7ba..bc9ec70 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/NameMatches.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/NameMatches.h
@@ -9,12 +9,20 @@
#ifndef LLDB_UTILITY_NAMEMATCHES_H
#define LLDB_UTILITY_NAMEMATCHES_H
-#include "lldb/lldb-private-enumerations.h"
-
#include "llvm/ADT/StringRef.h"
namespace lldb_private {
-bool NameMatches(llvm::StringRef name, NameMatchType match_type,
+
+enum class NameMatch {
+ Ignore,
+ Equals,
+ Contains,
+ StartsWith,
+ EndsWith,
+ RegularExpression
+};
+
+bool NameMatches(llvm::StringRef name, NameMatch match_type,
llvm::StringRef match);
}
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/PriorityPointerPair.h b/contrib/llvm/tools/lldb/include/lldb/Utility/PriorityPointerPair.h
deleted file mode 100644
index 2bd369e..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/PriorityPointerPair.h
+++ /dev/null
@@ -1,86 +0,0 @@
-//===-- PriorityPointerPair.h ----------------------------------------*- C++
-//-*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_PriorityPointerPair_h_
-#define liblldb_PriorityPointerPair_h_
-
-#include "lldb/Utility/SharingPtr.h"
-#include "lldb/lldb-public.h"
-
-namespace lldb_utility {
-
-//----------------------------------------------------------------------
-// A prioritized pair of SharedPtr<T>. One of the two pointers is high
-// priority, the other is low priority.
-// The Get() method always returns high, if *high != NULL,
-// otherwise, low is returned (even if *low == NULL)
-//----------------------------------------------------------------------
-
-template <typename T> class PriorityPointerPair {
-public:
- typedef T &reference_type;
- typedef T *pointer_type;
-
- typedef typename std::shared_ptr<T> T_SP;
-
- PriorityPointerPair() : m_high(), m_low() {}
-
- PriorityPointerPair(pointer_type high, pointer_type low)
- : m_high(high), m_low(low) {}
-
- PriorityPointerPair(pointer_type low) : m_high(), m_low(low) {}
-
- PriorityPointerPair(T_SP &high, T_SP &low) : m_high(high), m_low(low) {}
-
- PriorityPointerPair(T_SP &low) : m_high(), m_low(low) {}
-
- void SwapLow(pointer_type l) { m_low.swap(l); }
-
- void SwapHigh(pointer_type h) { m_high.swap(h); }
-
- void SwapLow(T_SP l) { m_low.swap(l); }
-
- void SwapHigh(T_SP h) { m_high.swap(h); }
-
- T_SP GetLow() { return m_low; }
-
- T_SP GetHigh() { return m_high; }
-
- T_SP Get() {
- if (m_high.get())
- return m_high;
- return m_low;
- }
-
- void ResetHigh() { m_high.reset(); }
-
- void ResetLow() { m_low.reset(); }
-
- void Reset() {
- ResetLow();
- ResetHigh();
- }
-
- reference_type operator*() const { return Get().operator*(); }
-
- pointer_type operator->() const { return Get().operator->(); }
-
- ~PriorityPointerPair();
-
-private:
- T_SP m_high;
- T_SP m_low;
-
- DISALLOW_COPY_AND_ASSIGN(PriorityPointerPair);
-};
-
-} // namespace lldb_utility
-
-#endif // #ifndef liblldb_PriorityPointerPair_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/Range.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Range.h
index c13bc0d..60880db 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/Range.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Range.h
@@ -10,7 +10,6 @@
#ifndef utility_Range_h_
#define utility_Range_h_
-#include <algorithm>
#include <stdint.h>
namespace lldb_utility {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/RegularExpression.h b/contrib/llvm/tools/lldb/include/lldb/Utility/RegularExpression.h
index fe34ef5..dba7001 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/RegularExpression.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/RegularExpression.h
@@ -36,11 +36,13 @@ inline void regfree(llvm_regex_t *a) { llvm_regfree(a); }
#endif
#include <regex.h>
#endif
-#include <stdint.h>
#include <string>
#include <vector>
+#include <stddef.h> // for size_t
+#include <stdint.h>
+
namespace llvm {
class StringRef;
} // namespace llvm
@@ -48,7 +50,8 @@ class StringRef;
namespace lldb_private {
//----------------------------------------------------------------------
-/// @class RegularExpression RegularExpression.h "lldb/Core/RegularExpression.h"
+/// @class RegularExpression RegularExpression.h
+/// "lldb/Utility/RegularExpression.h"
/// @brief A C++ wrapper class for regex.
///
/// This regular expression class wraps the posix regex functions
@@ -207,7 +210,7 @@ private:
// Member variables
//------------------------------------------------------------------
std::string m_re; ///< A copy of the original regular expression text
- int m_comp_err; ///< Error code for the regular expression compilation
+ int m_comp_err; ///< Status code for the regular expression compilation
regex_t m_preg; ///< The compiled regular expression
};
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/SafeMachO.h b/contrib/llvm/tools/lldb/include/lldb/Utility/SafeMachO.h
index 5da03c1..791410a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/SafeMachO.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/SafeMachO.h
@@ -114,6 +114,6 @@
#undef CPU_SUBTYPE_MC980000_ALL
#undef CPU_SUBTYPE_MC98601
-#include "llvm/Support/MachO.h"
+#include "llvm/BinaryFormat/MachO.h"
#endif // liblldb_SafeMachO_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/SelectHelper.h b/contrib/llvm/tools/lldb/include/lldb/Utility/SelectHelper.h
index 0251c8e..12950d0 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/SelectHelper.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/SelectHelper.h
@@ -10,16 +10,13 @@
#ifndef liblldb_SelectHelper_h_
#define liblldb_SelectHelper_h_
-// C Includes
-// C++ Includes
-#include <chrono>
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-types.h" // for socket_t
-// Other libraries and framework includes
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
-// Project includes
-#include "lldb/lldb-forward.h"
+#include <chrono>
class SelectHelper {
public:
@@ -52,7 +49,7 @@ public:
// Call the system's select() to wait for descriptors using
// timeout provided in a call the SelectHelper::SetTimeout(),
// or infinite wait if no timeout was set.
- lldb_private::Error Select();
+ lldb_private::Status Select();
protected:
struct FDInfo {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/SharingPtr.h b/contrib/llvm/tools/lldb/include/lldb/Utility/SharingPtr.h
index 4e91222..49b0020 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/SharingPtr.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/SharingPtr.h
@@ -12,7 +12,6 @@
// C Includes
// C++ Includes
-#include <algorithm>
#include <memory>
// Microsoft Visual C++ currently does not enable std::atomic to work
@@ -24,6 +23,8 @@
#include <atomic>
#endif
+#include <stddef.h>
+
// Other libraries and framework includes
// Project includes
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Error.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Status.h
index 8131580..d520ebd9 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Error.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Status.h
@@ -1,4 +1,4 @@
-//===-- Error.h -------------------------------------------------*- C++ -*-===//
+//===-- Status.h ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,32 +7,33 @@
//
//===----------------------------------------------------------------------===//
-#ifndef __DCError_h__
-#define __DCError_h__
-#if defined(__cplusplus)
+#ifndef LLDB_UTILITY_STATUS_H
+#define LLDB_UTILITY_STATUS_H
-#include "llvm/Support/DataTypes.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h" // for ErrorType, ErrorType...
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
-
#include <cstdarg>
-#include <cstdio>
+#include <stdint.h> // for uint32_t
#include <string>
+#include <system_error> // for error_code
+#include <type_traits> // for forward
-#include "lldb/lldb-private.h"
-
-#include "llvm/Support/FormatVariadic.h"
+namespace llvm {
+class raw_ostream;
+}
namespace lldb_private {
-class Log;
-
//----------------------------------------------------------------------
-/// @class Error Error.h "lldb/Core/Error.h"
+/// @class Status Status.h "lldb/Utility/Status.h"
/// @brief An error handling class.
///
/// This class is designed to be able to hold any error code that can be
/// encountered on a given platform. The errors are stored as a value
-/// of type Error::ValueType. This value should be large enough to hold
+/// of type Status::ValueType. This value should be large enough to hold
/// any and all errors that the class supports. Each error has an
/// associated type that is of type lldb::ErrorType. New types
/// can be added to support new error types, and architecture specific
@@ -46,7 +47,7 @@ class Log;
/// be cached until the error is cleared of the value of the error
/// changes.
//----------------------------------------------------------------------
-class Error {
+class Status {
public:
//------------------------------------------------------------------
/// Every error value that this object can contain needs to be able
@@ -65,13 +66,17 @@ public:
/// @param[in] type
/// The type for \a err.
//------------------------------------------------------------------
- Error();
+ Status();
- explicit Error(ValueType err, lldb::ErrorType type = lldb::eErrorTypeGeneric);
+ explicit Status(ValueType err,
+ lldb::ErrorType type = lldb::eErrorTypeGeneric);
- explicit Error(const char *format, ...) __attribute__((format(printf, 2, 3)));
+ /* implicit */ Status(std::error_code EC);
- Error(const Error &rhs);
+ explicit Status(const char *format, ...)
+ __attribute__((format(printf, 2, 3)));
+
+ Status(const Status &rhs);
//------------------------------------------------------------------
/// Assignment operator.
///
@@ -81,7 +86,7 @@ public:
/// @return
/// A const reference to this object.
//------------------------------------------------------------------
- const Error &operator=(const Error &rhs);
+ const Status &operator=(const Status &rhs);
//------------------------------------------------------------------
/// Assignment operator from a kern_return_t.
@@ -94,9 +99,14 @@ public:
/// @return
/// A const reference to this object.
//------------------------------------------------------------------
- const Error &operator=(uint32_t err);
+ const Status &operator=(uint32_t err);
+
+ ~Status();
- ~Error();
+ // llvm::Error support
+ explicit Status(llvm::Error error) { *this = std::move(error); }
+ const Status &operator=(llvm::Error error);
+ llvm::Error ToError() const;
//------------------------------------------------------------------
/// Get the error string associated with the current error.
@@ -148,48 +158,6 @@ public:
lldb::ErrorType GetType() const;
//------------------------------------------------------------------
- /// Log an error to Log().
- ///
- /// Log the error given a formatted string \a format. If the this
- /// object contains an error code, update the error string to
- /// contain the prefix "error: ", followed by the formatted string,
- /// followed by the error value and any string that describes the
- /// error value. This allows more context to be given to an error
- /// string that remains cached in this object. Logging always occurs
- /// even when the error code contains a non-error value.
- ///
- /// @param[in] format
- /// A printf style format string.
- ///
- /// @param[in] ...
- /// Variable arguments that are needed for the printf style
- /// format string \a format.
- //------------------------------------------------------------------
- void PutToLog(Log *log, const char *format, ...)
- __attribute__((format(printf, 3, 4)));
-
- //------------------------------------------------------------------
- /// Log an error to Log() if the error value is an error.
- ///
- /// Log the error given a formatted string \a format only if the
- /// error value in this object describes an error condition. If the
- /// this object contains an error, update the error string to
- /// contain the prefix "error: " followed by the formatted string,
- /// followed by the error value and any string that describes the
- /// error value. This allows more context to be given to an error
- /// string that remains cached in this object.
- ///
- /// @param[in] format
- /// A printf style format string.
- ///
- /// @param[in] ...
- /// Variable arguments that are needed for the printf style
- /// format string \a format.
- //------------------------------------------------------------------
- void LogIfError(Log *log, const char *format, ...)
- __attribute__((format(printf, 3, 4)));
-
- //------------------------------------------------------------------
/// Set accessor from a kern_return_t.
///
/// Set accesssor for the error value to \a err and the error type
@@ -223,7 +191,7 @@ public:
/// Set the current error to errno.
///
/// Update the error value to be \c errno and update the type to
- /// be \c Error::POSIX.
+ /// be \c Status::POSIX.
//------------------------------------------------------------------
void SetErrorToErrno();
@@ -231,7 +199,7 @@ public:
/// Set the current error to a generic error.
///
/// Update the error value to be \c LLDB_GENERIC_ERROR and update the
- /// type to be \c Error::Generic.
+ /// type to be \c Status::Generic.
//------------------------------------------------------------------
void SetErrorToGenericError();
@@ -294,7 +262,7 @@ protected:
//------------------------------------------------------------------
/// Member variables
//------------------------------------------------------------------
- ValueType m_code; ///< Error code as an integer value.
+ ValueType m_code; ///< Status code as an integer value.
lldb::ErrorType m_type; ///< The type of the above error code.
mutable std::string m_string; ///< A string representation of the error code.
};
@@ -302,14 +270,10 @@ protected:
} // namespace lldb_private
namespace llvm {
-template <> struct format_provider<lldb_private::Error> {
- static void format(const lldb_private::Error &error, llvm::raw_ostream &OS,
- llvm::StringRef Options) {
- llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS,
- Options);
- }
+template <> struct format_provider<lldb_private::Status> {
+ static void format(const lldb_private::Status &error, llvm::raw_ostream &OS,
+ llvm::StringRef Options);
};
}
-#endif // #if defined(__cplusplus)
-#endif // #ifndef __DCError_h__
+#endif // #ifndef LLDB_UTILITY_STATUS_H
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Stream.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Stream.h
index 1bea3e1..5a00f0a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Stream.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Stream.h
@@ -10,21 +10,21 @@
#ifndef liblldb_Stream_h_
#define liblldb_Stream_h_
-// C Includes
-#include <stdarg.h>
-
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Flags.h"
-#include "lldb/lldb-private.h"
-
+#include "lldb/Utility/Flags.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h" // for ByteOrder::eByteOrderInvalid
+#include "llvm/ADT/StringRef.h" // for StringRef
#include "llvm/Support/FormatVariadic.h"
+#include <stdarg.h>
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t, uint8_t
+#include <type_traits> // for forward
+
namespace lldb_private {
//----------------------------------------------------------------------
-/// @class Stream Stream.h "lldb/Core/Stream.h"
+/// @class Stream Stream.h "lldb/Utility/Stream.h"
/// @brief A stream class that can stream formatted output to a file.
//----------------------------------------------------------------------
class Stream {
@@ -33,12 +33,8 @@ public:
/// \a m_flags bit values.
//------------------------------------------------------------------
enum {
- eVerbose = (1 << 0), ///< If set, verbose logging is enabled
- eDebug = (1 << 1), ///< If set, debug logging is enabled
- eAddPrefix = (1 << 2), ///< Add number prefixes for binary, octal and hex
- ///when eBinary is clear
- eBinary = (1 << 3) ///< Get and put data as binary instead of as the default
- ///string mode.
+ eBinary = (1 << 0) ///< Get and put data as binary instead of as the default
+ /// string mode.
};
//------------------------------------------------------------------
@@ -385,15 +381,6 @@ public:
uint32_t GetAddressByteSize() const;
//------------------------------------------------------------------
- /// Test if debug logging is enabled.
- ///
- /// @return
- // \b true if the debug flag bit is set in this stream, \b
- // false otherwise.
- //------------------------------------------------------------------
- bool GetDebug() const;
-
- //------------------------------------------------------------------
/// The flags accessor.
///
/// @return
@@ -426,15 +413,6 @@ public:
int GetIndentLevel() const;
//------------------------------------------------------------------
- /// Test if verbose logging is enabled.
- ///
- /// @return
- // \b true if the verbose flag bit is set in this stream, \b
- // false otherwise.
- //------------------------------------------------------------------
- bool GetVerbose() const;
-
- //------------------------------------------------------------------
/// Indent the current line in the stream.
///
/// Indent the current line using the current indentation level and
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StreamCallback.h b/contrib/llvm/tools/lldb/include/lldb/Utility/StreamCallback.h
index 4dc72c8..0aa9d5d 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/StreamCallback.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/StreamCallback.h
@@ -10,32 +10,25 @@
#ifndef liblldb_StreamCallback_h_
#define liblldb_StreamCallback_h_
-#include <mutex>
-#include <string>
+#include "lldb/lldb-types.h"
+#include "llvm/Support/raw_ostream.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint64_t
namespace lldb_private {
-class StreamCallback : public Stream {
+class StreamCallback : public llvm::raw_ostream {
public:
StreamCallback(lldb::LogOutputCallback callback, void *baton);
-
- ~StreamCallback() override;
-
- void Flush() override;
-
- size_t Write(const void *src, size_t src_len) override;
+ ~StreamCallback() override = default;
private:
- typedef std::map<lldb::tid_t, StreamString> collection;
lldb::LogOutputCallback m_callback;
void *m_baton;
- collection m_accumulated_data;
- std::mutex m_collection_mutex;
- StreamString &FindStreamForThread(lldb::tid_t cur_tid);
+ void write_impl(const char *Ptr, size_t Size) override;
+ uint64_t current_pos() const override;
};
} // namespace lldb_private
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StreamGDBRemote.h b/contrib/llvm/tools/lldb/include/lldb/Utility/StreamGDBRemote.h
index 150b301..79234cc 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/StreamGDBRemote.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/StreamGDBRemote.h
@@ -1,5 +1,4 @@
-//===-- StreamGDBRemote.h ----------------------------------------*- C++
-//-*-===//
+//===-- StreamGDBRemote.h ----------------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,13 +10,11 @@
#ifndef liblldb_StreamGDBRemote_h_
#define liblldb_StreamGDBRemote_h_
-// C Includes
-// C++ Includes
+#include "lldb/Utility/StreamString.h" // for StreamString
+#include "lldb/lldb-enumerations.h" // for ByteOrder
-// Other libraries and framework includes
-// Project includes
-
-#include "lldb/Core/StreamString.h"
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StreamString.h b/contrib/llvm/tools/lldb/include/lldb/Utility/StreamString.h
index 88501a1..0ae3e82 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/StreamString.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/StreamString.h
@@ -10,9 +10,14 @@
#ifndef liblldb_StreamString_h_
#define liblldb_StreamString_h_
-#include <string>
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/lldb-enumerations.h" // for ByteOrder
+#include "llvm/ADT/StringRef.h" // for StringRef
-#include "lldb/Core/Stream.h"
+#include <string> // for string
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StreamTee.h b/contrib/llvm/tools/lldb/include/lldb/Utility/StreamTee.h
index 48f92c8..676178a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/StreamTee.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/StreamTee.h
@@ -14,7 +14,7 @@
#include <mutex>
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/StringExtractor.h b/contrib/llvm/tools/lldb/include/lldb/Utility/StringExtractor.h
index 624d1ef..311cec8 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/StringExtractor.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/StringExtractor.h
@@ -10,16 +10,15 @@
#ifndef utility_StringExtractor_h_
#define utility_StringExtractor_h_
-// C Includes
-// C++ Includes
-#include <stdint.h>
-#include <string>
-
// Other libraries and framework includes
// Project includes
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
+#include <stddef.h> // for size_t
+#include <stdint.h>
+#include <string>
+
class StringExtractor {
public:
enum { BigEndian = 0, LittleEndian = 1 };
@@ -112,6 +111,8 @@ public:
size_t GetHexByteStringTerminatedBy(std::string &str, char terminator);
+ bool ConsumeFront(const llvm::StringRef &str);
+
const char *Peek() {
if (m_index < m_packet.size())
return m_packet.c_str() + m_index;
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/StringLexer.h b/contrib/llvm/tools/lldb/include/lldb/Utility/StringLexer.h
index 3a399df..e4fc81a 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/StringLexer.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/StringLexer.h
@@ -11,9 +11,9 @@
#ifndef utility_StringLexer_h_
#define utility_StringLexer_h_
-#include <initializer_list>
-#include <list>
-#include <string>
+#include <initializer_list> // for initializer_list
+#include <string> // for string
+#include <utility> // for pair
namespace lldb_utility {
@@ -41,8 +41,6 @@ public:
bool HasAtLeast(Size s);
- bool HasAny(Character c);
-
std::string GetUnlexed();
// This will assert if there are less than s characters preceding the cursor.
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StringList.h b/contrib/llvm/tools/lldb/include/lldb/Utility/StringList.h
index 2cd974d..2be9a6b 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/StringList.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/StringList.h
@@ -10,18 +10,18 @@
#ifndef liblldb_StringList_h_
#define liblldb_StringList_h_
-// C Includes
-#include <stdint.h>
+#include "llvm/ADT/StringRef.h"
-// C++ Includes
+#include <stddef.h> // for size_t
#include <string>
+#include <vector>
-// Other libraries and framework includes
-#include "llvm/ADT/StringRef.h"
-
-// Project includes
-#include "lldb/Core/STLUtils.h"
-#include "lldb/lldb-forward.h"
+namespace lldb_private {
+class Log;
+}
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
@@ -49,8 +49,6 @@ public:
void AppendList(StringList strings);
- bool ReadFileLines(FileSpec &input_file);
-
size_t GetSize() const;
void SetSize(size_t n) { m_strings.resize(n); }
@@ -133,7 +131,7 @@ public:
}
private:
- STLStringArray m_strings;
+ std::vector<std::string> m_strings;
};
} // namespace lldb_private
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StructuredData.h b/contrib/llvm/tools/lldb/include/lldb/Utility/StructuredData.h
index efd8100..2ea5fb9 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/StructuredData.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/StructuredData.h
@@ -10,27 +10,34 @@
#ifndef liblldb_StructuredData_h_
#define liblldb_StructuredData_h_
-// C Includes
-// C++ Includes
+#include "llvm/ADT/StringRef.h"
+
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/lldb-enumerations.h" // for StructuredDataType
+
+#include <cassert> // for assert
+#include <cstddef> // for size_t
+#include <cstdint> // for uint64_t
#include <functional>
#include <map>
#include <memory>
#include <string>
+#include <type_traits> // for move
#include <utility>
#include <vector>
-// Other libraries and framework includes
-#include "llvm/ADT/StringRef.h"
-
-// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/lldb-defines.h"
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
//----------------------------------------------------------------------
-/// @class StructuredData StructuredData.h "lldb/Core/StructuredData.h"
+/// @class StructuredData StructuredData.h "lldb/Utility/StructuredData.h"
/// @brief A class which can hold structured data
///
/// The StructuredData class is designed to hold the data from a JSON
@@ -64,46 +71,37 @@ public:
typedef std::shared_ptr<Dictionary> DictionarySP;
typedef std::shared_ptr<Generic> GenericSP;
- enum class Type {
- eTypeInvalid = -1,
- eTypeNull = 0,
- eTypeGeneric,
- eTypeArray,
- eTypeInteger,
- eTypeFloat,
- eTypeBoolean,
- eTypeString,
- eTypeDictionary
- };
-
class Object : public std::enable_shared_from_this<Object> {
public:
- Object(Type t = Type::eTypeInvalid) : m_type(t) {}
+ Object(lldb::StructuredDataType t = lldb::eStructuredDataTypeInvalid)
+ : m_type(t) {}
virtual ~Object() = default;
virtual bool IsValid() const { return true; }
- virtual void Clear() { m_type = Type::eTypeInvalid; }
+ virtual void Clear() { m_type = lldb::eStructuredDataTypeInvalid; }
- Type GetType() const { return m_type; }
+ lldb::StructuredDataType GetType() const { return m_type; }
- void SetType(Type t) { m_type = t; }
+ void SetType(lldb::StructuredDataType t) { m_type = t; }
Array *GetAsArray() {
- return ((m_type == Type::eTypeArray) ? static_cast<Array *>(this)
- : nullptr);
+ return ((m_type == lldb::eStructuredDataTypeArray)
+ ? static_cast<Array *>(this)
+ : nullptr);
}
Dictionary *GetAsDictionary() {
- return ((m_type == Type::eTypeDictionary)
+ return ((m_type == lldb::eStructuredDataTypeDictionary)
? static_cast<Dictionary *>(this)
: nullptr);
}
Integer *GetAsInteger() {
- return ((m_type == Type::eTypeInteger) ? static_cast<Integer *>(this)
- : nullptr);
+ return ((m_type == lldb::eStructuredDataTypeInteger)
+ ? static_cast<Integer *>(this)
+ : nullptr);
}
uint64_t GetIntegerValue(uint64_t fail_value = 0) {
@@ -112,8 +110,9 @@ public:
}
Float *GetAsFloat() {
- return ((m_type == Type::eTypeFloat) ? static_cast<Float *>(this)
- : nullptr);
+ return ((m_type == lldb::eStructuredDataTypeFloat)
+ ? static_cast<Float *>(this)
+ : nullptr);
}
double GetFloatValue(double fail_value = 0.0) {
@@ -122,8 +121,9 @@ public:
}
Boolean *GetAsBoolean() {
- return ((m_type == Type::eTypeBoolean) ? static_cast<Boolean *>(this)
- : nullptr);
+ return ((m_type == lldb::eStructuredDataTypeBoolean)
+ ? static_cast<Boolean *>(this)
+ : nullptr);
}
bool GetBooleanValue(bool fail_value = false) {
@@ -132,24 +132,23 @@ public:
}
String *GetAsString() {
- return ((m_type == Type::eTypeString) ? static_cast<String *>(this)
- : nullptr);
+ return ((m_type == lldb::eStructuredDataTypeString)
+ ? static_cast<String *>(this)
+ : nullptr);
}
- std::string GetStringValue(const char *fail_value = nullptr) {
+ llvm::StringRef GetStringValue(const char *fail_value = nullptr) {
String *s = GetAsString();
if (s)
return s->GetValue();
- if (fail_value && fail_value[0])
- return std::string(fail_value);
-
- return std::string();
+ return fail_value;
}
Generic *GetAsGeneric() {
- return ((m_type == Type::eTypeGeneric) ? static_cast<Generic *>(this)
- : nullptr);
+ return ((m_type == lldb::eStructuredDataTypeGeneric)
+ ? static_cast<Generic *>(this)
+ : nullptr);
}
ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path);
@@ -159,12 +158,12 @@ public:
virtual void Dump(Stream &s, bool pretty_print = true) const = 0;
private:
- Type m_type;
+ lldb::StructuredDataType m_type;
};
class Array : public Object {
public:
- Array() : Object(Type::eTypeArray) {}
+ Array() : Object(lldb::eStructuredDataTypeArray) {}
~Array() override = default;
@@ -213,7 +212,7 @@ public:
return success;
}
- bool GetItemAtIndexAsString(size_t idx, std::string &result) const {
+ bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result) const {
ObjectSP value_sp = GetItemAtIndex(idx);
if (value_sp.get()) {
if (auto string_value = value_sp->GetAsString()) {
@@ -224,8 +223,8 @@ public:
return false;
}
- bool GetItemAtIndexAsString(size_t idx, std::string &result,
- const std::string &default_val) const {
+ bool GetItemAtIndexAsString(size_t idx, llvm::StringRef &result,
+ llvm::StringRef default_val) const {
bool success = GetItemAtIndexAsString(idx, result);
if (!success)
result = default_val;
@@ -284,7 +283,8 @@ public:
class Integer : public Object {
public:
- Integer(uint64_t i = 0) : Object(Type::eTypeInteger), m_value(i) {}
+ Integer(uint64_t i = 0)
+ : Object(lldb::eStructuredDataTypeInteger), m_value(i) {}
~Integer() override = default;
@@ -300,7 +300,8 @@ public:
class Float : public Object {
public:
- Float(double d = 0.0) : Object(Type::eTypeFloat), m_value(d) {}
+ Float(double d = 0.0)
+ : Object(lldb::eStructuredDataTypeFloat), m_value(d) {}
~Float() override = default;
@@ -316,7 +317,8 @@ public:
class Boolean : public Object {
public:
- Boolean(bool b = false) : Object(Type::eTypeBoolean), m_value(b) {}
+ Boolean(bool b = false)
+ : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {}
~Boolean() override = default;
@@ -332,18 +334,13 @@ public:
class String : public Object {
public:
- String(const char *cstr = nullptr) : Object(Type::eTypeString), m_value() {
- if (cstr)
- m_value = cstr;
- }
-
- String(const std::string &s) : Object(Type::eTypeString), m_value(s) {}
-
- String(const std::string &&s) : Object(Type::eTypeString), m_value(s) {}
+ String() : Object(lldb::eStructuredDataTypeString) {}
+ explicit String(llvm::StringRef S)
+ : Object(lldb::eStructuredDataTypeString), m_value(S) {}
- void SetValue(const std::string &string) { m_value = string; }
+ void SetValue(llvm::StringRef S) { m_value = S; }
- const std::string &GetValue() { return m_value; }
+ llvm::StringRef GetValue() { return m_value; }
void Dump(Stream &s, bool pretty_print = true) const override;
@@ -353,7 +350,7 @@ public:
class Dictionary : public Object {
public:
- Dictionary() : Object(Type::eTypeDictionary), m_dict() {}
+ Dictionary() : Object(lldb::eStructuredDataTypeDictionary), m_dict() {}
~Dictionary() override = default;
@@ -368,13 +365,12 @@ public:
}
ObjectSP GetKeys() const {
- ObjectSP object_sp(new Array());
- Array *array = object_sp->GetAsArray();
+ auto object_sp = std::make_shared<Array>();
collection::const_iterator iter;
for (iter = m_dict.begin(); iter != m_dict.end(); ++iter) {
- ObjectSP key_object_sp(new String());
- key_object_sp->GetAsString()->SetValue(iter->first.AsCString());
- array->Push(key_object_sp);
+ auto key_object_sp = std::make_shared<String>();
+ key_object_sp->SetValue(iter->first.AsCString());
+ object_sp->Push(key_object_sp);
}
return object_sp;
}
@@ -424,7 +420,7 @@ public:
}
bool GetValueForKeyAsString(llvm::StringRef key,
- std::string &result) const {
+ llvm::StringRef &result) const {
ObjectSP value_sp = GetValueForKey(key);
if (value_sp.get()) {
if (auto string_value = value_sp->GetAsString()) {
@@ -435,14 +431,14 @@ public:
return false;
}
- bool GetValueForKeyAsString(llvm::StringRef key, std::string &result,
+ bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result,
const char *default_val) const {
bool success = GetValueForKeyAsString(key, result);
if (!success) {
if (default_val)
result = default_val;
else
- result.clear();
+ result = llvm::StringRef();
}
return success;
}
@@ -500,19 +496,19 @@ public:
}
void AddIntegerItem(llvm::StringRef key, uint64_t value) {
- AddItem(key, ObjectSP(new Integer(value)));
+ AddItem(key, std::make_shared<Integer>(value));
}
void AddFloatItem(llvm::StringRef key, double value) {
- AddItem(key, ObjectSP(new Float(value)));
+ AddItem(key, std::make_shared<Float>(value));
}
- void AddStringItem(llvm::StringRef key, std::string value) {
- AddItem(key, ObjectSP(new String(std::move(value))));
+ void AddStringItem(llvm::StringRef key, llvm::StringRef value) {
+ AddItem(key, std::make_shared<String>(std::move(value)));
}
void AddBooleanItem(llvm::StringRef key, bool value) {
- AddItem(key, ObjectSP(new Boolean(value)));
+ AddItem(key, std::make_shared<Boolean>(value));
}
void Dump(Stream &s, bool pretty_print = true) const override;
@@ -524,7 +520,7 @@ public:
class Null : public Object {
public:
- Null() : Object(Type::eTypeNull) {}
+ Null() : Object(lldb::eStructuredDataTypeNull) {}
~Null() override = default;
@@ -536,7 +532,7 @@ public:
class Generic : public Object {
public:
explicit Generic(void *object = nullptr)
- : Object(Type::eTypeGeneric), m_object(object) {}
+ : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {}
void SetValue(void *value) { m_object = value; }
@@ -552,7 +548,7 @@ public:
static ObjectSP ParseJSON(std::string json_text);
- static ObjectSP ParseJSONFromFile(const FileSpec &file, Error &error);
+ static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error);
};
} // namespace lldb_private
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/TaskPool.h b/contrib/llvm/tools/lldb/include/lldb/Utility/TaskPool.h
index db15b20..f2deaee 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/TaskPool.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/TaskPool.h
@@ -10,29 +10,13 @@
#ifndef utility_TaskPool_h_
#define utility_TaskPool_h_
-#if defined(__cplusplus) && defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
-// Compiling MSVC libraries with _HAS_EXCEPTIONS=0, eliminates most but not all
-// calls to __uncaught_exception. Unfortunately, it does seem to eliminate
-// the delcaration of __uncaught_excpeiton. Including <eh.h> ensures that it is
-// declared. This may not be necessary after MSVC 12.
-#include <eh.h>
-#endif
-
-#if defined(_MSC_VER)
-// Due to another bug in MSVC 2013, including <future> will generate hundreds of
-// warnings in the Concurrency Runtime. This can be removed when we switch to
-// MSVC 2015
-#pragma warning(push)
-#pragma warning(disable : 4062)
-#endif
-
-#include <cassert>
-#include <cstdint>
+#include "llvm/ADT/STLExtras.h"
+#include <functional> // for bind, function
#include <future>
#include <list>
-#include <queue>
-#include <thread>
-#include <vector>
+#include <memory> // for make_shared
+#include <mutex> // for mutex, unique_lock, condition_variable
+#include <type_traits> // for forward, result_of, move
// Global TaskPool class for running tasks in parallel on a set of worker thread
// created the first
@@ -70,50 +54,6 @@ private:
static void AddTaskImpl(std::function<void()> &&task_fn);
};
-// Wrapper class around the global TaskPool implementation to make it possible
-// to create a set of
-// tasks and then wait for the tasks to be completed by the
-// WaitForNextCompletedTask call. This
-// class should be used when WaitForNextCompletedTask is needed because this
-// class add no other
-// extra functionality to the TaskPool class and it have a very minor
-// performance overhead.
-template <typename T> // The return type of the tasks what will be added to this
- // task runner
- class TaskRunner {
-public:
- // Add a task to the task runner what will also add the task to the global
- // TaskPool. The
- // function doesn't return the std::future for the task because it will be
- // supplied by the
- // WaitForNextCompletedTask after the task is completed.
- template <typename F, typename... Args> void AddTask(F &&f, Args &&... args);
-
- // Wait for the next task in this task runner to finish and then return the
- // std::future what
- // belongs to the finished task. If there is no task in this task runner
- // (neither pending nor
- // comleted) then this function will return an invalid future. Usually this
- // function should be
- // called in a loop processing the results of the tasks until it returns an
- // invalid std::future
- // what means that all task in this task runner is completed.
- std::future<T> WaitForNextCompletedTask();
-
- // Convenience method to wait for all task in this TaskRunner to finish. Do
- // NOT use this class
- // just because of this method. Use TaskPool instead and wait for each
- // std::future returned by
- // AddTask in a loop.
- void WaitForAllTasks();
-
-private:
- std::list<std::future<T>> m_ready;
- std::list<std::future<T>> m_pending;
- std::mutex m_mutex;
- std::condition_variable m_cv;
-};
-
template <typename F, typename... Args>
std::future<typename std::result_of<F(Args...)>::type>
TaskPool::AddTask(F &&f, Args &&... args) {
@@ -143,68 +83,10 @@ template <> struct TaskPool::RunTaskImpl<> {
static void Run() {}
};
-template <typename T>
-template <typename F, typename... Args>
-void TaskRunner<T>::AddTask(F &&f, Args &&... args) {
- std::unique_lock<std::mutex> lock(m_mutex);
- auto it = m_pending.emplace(m_pending.end());
- *it = std::move(TaskPool::AddTask(
- [this, it](F f, Args... args) {
- T &&r = f(std::forward<Args>(args)...);
-
- std::unique_lock<std::mutex> lock(this->m_mutex);
- this->m_ready.splice(this->m_ready.end(), this->m_pending, it);
- lock.unlock();
-
- this->m_cv.notify_one();
- return r;
- },
- std::forward<F>(f), std::forward<Args>(args)...));
-}
-
-template <>
-template <typename F, typename... Args>
-void TaskRunner<void>::AddTask(F &&f, Args &&... args) {
- std::unique_lock<std::mutex> lock(m_mutex);
- auto it = m_pending.emplace(m_pending.end());
- *it = std::move(TaskPool::AddTask(
- [this, it](F f, Args... args) {
- f(std::forward<Args>(args)...);
-
- std::unique_lock<std::mutex> lock(this->m_mutex);
- this->m_ready.emplace_back(std::move(*it));
- this->m_pending.erase(it);
- lock.unlock();
-
- this->m_cv.notify_one();
- },
- std::forward<F>(f), std::forward<Args>(args)...));
-}
-
-template <typename T> std::future<T> TaskRunner<T>::WaitForNextCompletedTask() {
- std::unique_lock<std::mutex> lock(m_mutex);
- if (m_ready.empty() && m_pending.empty())
- return std::future<T>(); // No more tasks
-
- if (m_ready.empty())
- m_cv.wait(lock, [this]() { return !this->m_ready.empty(); });
-
- std::future<T> res = std::move(m_ready.front());
- m_ready.pop_front();
-
- lock.unlock();
- res.wait();
-
- return std::move(res);
-}
-
-template <typename T> void TaskRunner<T>::WaitForAllTasks() {
- while (WaitForNextCompletedTask().valid())
- ;
-}
-
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
+// Run 'func' on every value from begin .. end-1. Each worker will grab
+// 'batch_size' numbers at a time to work on, so for very fast functions, batch
+// should be large enough to avoid too much cache line contention.
+void TaskMapOverInt(size_t begin, size_t end,
+ const llvm::function_ref<void(size_t)> &func);
#endif // #ifndef utility_TaskPool_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/TildeExpressionResolver.h b/contrib/llvm/tools/lldb/include/lldb/Utility/TildeExpressionResolver.h
new file mode 100644
index 0000000..8462032
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/TildeExpressionResolver.h
@@ -0,0 +1,65 @@
+//===--------------------- TildeExpressionResolver.h ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_TILDE_EXPRESSION_RESOLVER_H
+#define LLDB_UTILITY_TILDE_EXPRESSION_RESOLVER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+
+namespace llvm {
+template <typename T> class SmallVectorImpl;
+}
+
+namespace lldb_private {
+class TildeExpressionResolver {
+public:
+ virtual ~TildeExpressionResolver();
+
+ /// \brief Resolve a Tilde Expression contained according to bash rules.
+ ///
+ /// \param Expr Contains the tilde expression to resolve. A valid tilde
+ /// expression must begin with a tilde and contain only non
+ /// separator characters.
+ ///
+ /// \param Output Contains the resolved tilde expression, or the original
+ /// input if the tilde expression could not be resolved.
+ ///
+ /// \returns true if \p Expr was successfully resolved, false otherwise.
+ virtual bool ResolveExact(llvm::StringRef Expr,
+ llvm::SmallVectorImpl<char> &Output) = 0;
+
+ /// \brief Auto-complete a tilde expression with all matching values.
+ ///
+ /// \param Expr Contains the tilde expression prefix to resolve. See
+ /// ResolveExact() for validity rules.
+ ///
+ /// \param Output Contains all matching home directories, each one
+ /// itself unresolved (i.e. you need to call ResolveExact
+ /// on each item to turn it into a real path).
+ ///
+ /// \returns true if there were any matches, false otherwise.
+ virtual bool ResolvePartial(llvm::StringRef Expr,
+ llvm::StringSet<> &Output) = 0;
+
+ /// \brief Resolve an entire path that begins with a tilde expression,
+ /// replacing the username portion with the matched result.
+ bool ResolveFullPath(llvm::StringRef Expr,
+ llvm::SmallVectorImpl<char> &Output);
+};
+
+class StandardTildeExpressionResolver : public TildeExpressionResolver {
+public:
+ bool ResolveExact(llvm::StringRef Expr,
+ llvm::SmallVectorImpl<char> &Output) override;
+ bool ResolvePartial(llvm::StringRef Expr, llvm::StringSet<> &Output) override;
+};
+}
+
+#endif // #ifndef LLDB_UTILITY_TILDE_EXPRESSION_RESOLVER_H
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/Timeout.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Timeout.h
index 6c6fd00..7b627a4 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/Timeout.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Timeout.h
@@ -11,7 +11,8 @@
#define liblldb_Timeout_h_
#include "llvm/ADT/Optional.h"
-#include <chrono>
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/FormatProviders.h"
namespace lldb_private {
@@ -52,4 +53,19 @@ public:
} // namespace lldb_private
+namespace llvm {
+template<typename Ratio>
+struct format_provider<lldb_private::Timeout<Ratio>, void> {
+ static void format(const lldb_private::Timeout<Ratio> &timeout,
+ raw_ostream &OS, StringRef Options) {
+ typedef typename lldb_private::Timeout<Ratio>::value_type Dur;
+
+ if (!timeout)
+ OS << "<infinite>";
+ else
+ format_provider<Dur>::format(*timeout, OS, Options);
+ }
+};
+}
+
#endif // liblldb_Timeout_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Timer.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Timer.h
index 854d3c3..c06ac17 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/Timer.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Timer.h
@@ -10,39 +10,38 @@
#ifndef liblldb_Timer_h_
#define liblldb_Timer_h_
-// C Includes
-#include <stdarg.h>
-#include <stdio.h>
-
-// C++ Includes
-#include <atomic>
-#include <mutex>
-
-// Other libraries and framework includes
-// Project includes
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN
#include "llvm/Support/Chrono.h"
+#include <atomic>
+#include <stdint.h> // for uint32_t
namespace lldb_private {
+class Stream;
//----------------------------------------------------------------------
-/// @class Timer Timer.h "lldb/Core/Timer.h"
+/// @class Timer Timer.h "lldb/Utility/Timer.h"
/// @brief A timer class that simplifies common timing metrics.
-///
-/// A scoped timer class that allows a variety of pthread mutex
-/// objects to have a mutex locked when a Timer::Locker
-/// object is created, and unlocked when it goes out of scope or
-/// when the Timer::Locker::Reset(pthread_mutex_t *)
-/// is called. This provides an exception safe way to lock a mutex
-/// in a scope.
//----------------------------------------------------------------------
class Timer {
public:
+ class Category {
+ public:
+ explicit Category(const char *category_name);
+
+ private:
+ friend class Timer;
+ const char *m_name;
+ std::atomic<uint64_t> m_nanos;
+ std::atomic<Category *> m_next;
+
+ DISALLOW_COPY_AND_ASSIGN(Category);
+ };
+
//--------------------------------------------------------------
/// Default constructor.
//--------------------------------------------------------------
- Timer(const char *category, const char *format, ...)
+ Timer(Category &category, const char *format, ...)
__attribute__((format(printf, 3, 4)));
//--------------------------------------------------------------
@@ -64,7 +63,7 @@ protected:
using TimePoint = std::chrono::steady_clock::time_point;
void ChildDuration(TimePoint::duration dur) { m_child_duration += dur; }
- const char *m_category;
+ Category &m_category;
TimePoint m_total_start;
TimePoint::duration m_child_duration{0};
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/TraceOptions.h b/contrib/llvm/tools/lldb/include/lldb/Utility/TraceOptions.h
new file mode 100644
index 0000000..325ff74
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/TraceOptions.h
@@ -0,0 +1,61 @@
+//===-- TraceOptions.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_TraceOptions_h_
+#define liblldb_TraceOptions_h_
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/Utility/StructuredData.h"
+
+namespace lldb_private {
+class TraceOptions {
+public:
+ TraceOptions() : m_trace_params(new StructuredData::Dictionary()) {}
+
+ const StructuredData::DictionarySP &getTraceParams() const {
+ return m_trace_params;
+ }
+
+ lldb::TraceType getType() const { return m_type; }
+
+ uint64_t getTraceBufferSize() const { return m_trace_buffer_size; }
+
+ uint64_t getMetaDataBufferSize() const { return m_meta_data_buffer_size; }
+
+ void setTraceParams(const StructuredData::DictionarySP &dict_obj) {
+ m_trace_params = dict_obj;
+ }
+
+ void setType(lldb::TraceType type) { m_type = type; }
+
+ void setTraceBufferSize(uint64_t size) { m_trace_buffer_size = size; }
+
+ void setMetaDataBufferSize(uint64_t size) { m_meta_data_buffer_size = size; }
+
+ void setThreadID(lldb::tid_t thread_id) { m_thread_id = thread_id; }
+
+ lldb::tid_t getThreadID() const { return m_thread_id; }
+
+private:
+ lldb::TraceType m_type;
+ uint64_t m_trace_buffer_size;
+ uint64_t m_meta_data_buffer_size;
+ lldb::tid_t m_thread_id;
+
+ /// m_trace_params is meant to hold any custom parameters
+ /// apart from meta buffer size and trace size.
+ /// The interpretation of such parameters is left to
+ /// the lldb-server.
+ StructuredData::DictionarySP m_trace_params;
+};
+}
+
+#endif // liblldb_TraceOptions_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/UUID.h b/contrib/llvm/tools/lldb/include/lldb/Utility/UUID.h
index 7cf5cf3..6313025 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/UUID.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/UUID.h
@@ -7,19 +7,23 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_UUID_h_
-#define liblldb_UUID_h_
+#ifndef LLDB_UTILITY_UUID_H
+#define LLDB_UTILITY_UUID_H
// C Includes
// C++ Includes
+#include <stddef.h>
+#include <stdint.h>
#include <string>
-// Other libraries and framework includes
-// Project includes
-#include "lldb/lldb-private.h"
+namespace llvm {
+ class StringRef;
+}
namespace lldb_private {
+ class Stream;
+
class UUID {
public:
// Most UUIDs are 16 bytes, but some Linux build-ids (SHA1) are 20.
@@ -50,6 +54,7 @@ public:
std::string GetAsString(const char *separator = nullptr) const;
+ size_t SetFromStringRef(llvm::StringRef str, uint32_t num_uuid_bytes = 16);
size_t SetFromCString(const char *c_str, uint32_t num_uuid_bytes = 16);
// Decode as many UUID bytes (up to 16) as possible from the C string "cstr"
@@ -93,4 +98,4 @@ bool operator>=(const UUID &lhs, const UUID &rhs);
} // namespace lldb_private
-#endif // liblldb_UUID_h_
+#endif // LLDB_UTILITY_UUID_H
diff --git a/contrib/llvm/tools/lldb/source/Utility/UriParser.h b/contrib/llvm/tools/lldb/include/lldb/Utility/UriParser.h
index 7ebf76f..db0049d 100644
--- a/contrib/llvm/tools/lldb/source/Utility/UriParser.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/UriParser.h
@@ -10,14 +10,9 @@
#ifndef utility_UriParser_h_
#define utility_UriParser_h_
-// C Includes
-// C++ Includes
-
-// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
-// Project includes
-
+namespace lldb_private {
class UriParser {
public:
// Parses
@@ -32,5 +27,6 @@ public:
llvm::StringRef &hostname, int &port,
llvm::StringRef &path);
};
+}
#endif // utility_UriParser_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/UserID.h b/contrib/llvm/tools/lldb/include/lldb/Utility/UserID.h
index 5964483..b178efd 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/UserID.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/UserID.h
@@ -10,7 +10,11 @@
#ifndef liblldb_UserID_h_
#define liblldb_UserID_h_
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_UID
+#include "lldb/lldb-types.h" // for user_id_t
+namespace lldb_private {
+class Stream;
+}
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/Utils.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Utils.h
deleted file mode 100644
index 46bc184..0000000
--- a/contrib/llvm/tools/lldb/include/lldb/Utility/Utils.h
+++ /dev/null
@@ -1,22 +0,0 @@
-//===-- Utils.h -------------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef utility_Utils_h_
-#define utility_Utils_h_
-
-// These utilities have llvm namespace.
-#include "llvm/ADT/STLExtras.h"
-
-namespace lldb_private {
-
-// Add lldb utilities here.
-
-} // namespace lldb_private
-
-#endif // utility_Utils
diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/VASPrintf.h b/contrib/llvm/tools/lldb/include/lldb/Utility/VASPrintf.h
new file mode 100644
index 0000000..6e2404e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/VASPrintf.h
@@ -0,0 +1,21 @@
+//===-- VASPrintf.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_VASPRINTF_H
+#define LLDB_UTILITY_VASPRINTF_H
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <cstdarg>
+
+namespace lldb_private {
+bool VASprintf(llvm::SmallVectorImpl<char> &buf, const char *fmt, va_list args);
+}
+
+#endif // #ifdef LLDB_UTILITY_VASPRINTF_H
diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/VMRange.h b/contrib/llvm/tools/lldb/include/lldb/Utility/VMRange.h
index 4ec64c9..f03a1b0 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Core/VMRange.h
+++ b/contrib/llvm/tools/lldb/include/lldb/Utility/VMRange.h
@@ -10,10 +10,17 @@
#ifndef liblldb_VMRange_h_
#define liblldb_VMRange_h_
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
#include <vector>
namespace lldb_private {
+class Stream;
+}
+
+namespace lldb_private {
//----------------------------------------------------------------------
// A vm address range. These can represent offsets ranges or actual
@@ -104,11 +111,6 @@ public:
static bool ContainsRange(const VMRange::collection &coll,
const VMRange &range);
- // Returns a valid index into coll when a match is found, else UINT32_MAX
- // is returned
- static size_t FindRangeIndexThatContainsValue(const VMRange::collection &coll,
- lldb::addr_t value);
-
protected:
lldb::addr_t m_base_addr;
lldb::addr_t m_byte_size;
diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h b/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h
index cf42828..14bae6c 100644
--- a/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h
+++ b/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h
@@ -454,6 +454,9 @@ enum LanguageType {
enum InstrumentationRuntimeType {
eInstrumentationRuntimeTypeAddressSanitizer = 0x0000,
eInstrumentationRuntimeTypeThreadSanitizer = 0x0001,
+ eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer = 0x0002,
+ eInstrumentationRuntimeTypeMainThreadChecker = 0x0003,
+ eInstrumentationRuntimeTypeSwiftRuntimeReporting = 0x0004,
eNumInstrumentationRuntimeTypes
};
@@ -718,6 +721,25 @@ enum BasicType {
eBasicTypeOther
};
+enum TraceType {
+ eTraceTypeNone = 0,
+
+ // Hardware Trace generated by the processor.
+ eTraceTypeProcessorTrace
+};
+
+enum StructuredDataType {
+ eStructuredDataTypeInvalid = -1,
+ eStructuredDataTypeNull = 0,
+ eStructuredDataTypeGeneric,
+ eStructuredDataTypeArray,
+ eStructuredDataTypeInteger,
+ eStructuredDataTypeFloat,
+ eStructuredDataTypeBoolean,
+ eStructuredDataTypeString,
+ eStructuredDataTypeDictionary
+};
+
FLAGS_ENUM(TypeClass){
eTypeClassInvalid = (0u), eTypeClassArray = (1u << 0),
eTypeClassBlockPointer = (1u << 1), eTypeClassBuiltin = (1u << 2),
diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-forward.h b/contrib/llvm/tools/lldb/include/lldb/lldb-forward.h
index 8f70a59..392dc64 100644
--- a/contrib/llvm/tools/lldb/include/lldb/lldb-forward.h
+++ b/contrib/llvm/tools/lldb/include/lldb/lldb-forward.h
@@ -87,7 +87,7 @@ class DynamicCheckerFunctions;
class DynamicLoader;
class Editline;
class EmulateInstruction;
-class Error;
+class Status;
class EvaluateExpressionOptions;
class Event;
class EventData;
@@ -127,7 +127,6 @@ class MemoryRegionInfo;
class LineTable;
class Listener;
class Log;
-class LogChannel;
class Mangled;
class Materializer;
class MemoryHistory;
@@ -216,6 +215,7 @@ class StreamFile;
class StreamString;
class StringList;
struct StringSummaryFormat;
+class StructuredDataImpl;
class StructuredDataPlugin;
class SystemRuntime;
class TypeSummaryImpl;
@@ -255,6 +255,7 @@ class ThreadPlanStepRange;
class ThreadPlanStepThrough;
class ThreadPlanTracer;
class ThreadSpec;
+class TraceOptions;
class Type;
class TypeAndOrName;
class TypeCategoryMap;
@@ -362,7 +363,6 @@ typedef std::unique_ptr<lldb_private::SystemRuntime> SystemRuntimeUP;
typedef std::shared_ptr<lldb_private::LineTable> LineTableSP;
typedef std::shared_ptr<lldb_private::Listener> ListenerSP;
typedef std::weak_ptr<lldb_private::Listener> ListenerWP;
-typedef std::shared_ptr<lldb_private::LogChannel> LogChannelSP;
typedef std::shared_ptr<lldb_private::MemoryHistory> MemoryHistorySP;
typedef std::shared_ptr<lldb_private::MemoryRegionInfo> MemoryRegionInfoSP;
typedef std::unique_ptr<lldb_private::MemoryRegionInfo> MemoryRegionInfoUP;
@@ -432,6 +432,7 @@ typedef std::weak_ptr<lldb_private::Stream> StreamWP;
typedef std::shared_ptr<lldb_private::StreamFile> StreamFileSP;
typedef std::shared_ptr<lldb_private::StringSummaryFormat>
StringTypeSummaryImplSP;
+typedef std::unique_ptr<lldb_private::StructuredDataImpl> StructuredDataImplUP;
typedef std::shared_ptr<lldb_private::StructuredDataPlugin>
StructuredDataPluginSP;
typedef std::weak_ptr<lldb_private::StructuredDataPlugin>
@@ -453,6 +454,7 @@ typedef std::weak_ptr<lldb_private::Thread> ThreadWP;
typedef std::shared_ptr<lldb_private::ThreadCollection> ThreadCollectionSP;
typedef std::shared_ptr<lldb_private::ThreadPlan> ThreadPlanSP;
typedef std::shared_ptr<lldb_private::ThreadPlanTracer> ThreadPlanTracerSP;
+typedef std::shared_ptr<lldb_private::TraceOptions> TraceOptionsSP;
typedef std::shared_ptr<lldb_private::Type> TypeSP;
typedef std::weak_ptr<lldb_private::Type> TypeWP;
typedef std::shared_ptr<lldb_private::TypeCategoryImpl> TypeCategoryImplSP;
diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h b/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h
index d6e30b3..983ddf3 100644
--- a/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h
+++ b/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h
@@ -10,6 +10,10 @@
#ifndef LLDB_lldb_private_enumerations_h_
#define LLDB_lldb_private_enumerations_h_
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/raw_ostream.h"
+
namespace lldb_private {
//----------------------------------------------------------------------
@@ -112,19 +116,6 @@ typedef enum LazyBool {
} LazyBool;
//------------------------------------------------------------------
-/// Name matching
-//------------------------------------------------------------------
-typedef enum NameMatchType {
- eNameMatchIgnore,
- eNameMatchEquals,
- eNameMatchContains,
- eNameMatchStartsWith,
- eNameMatchEndsWith,
- eNameMatchRegularExpression
-
-} NameMatchType;
-
-//------------------------------------------------------------------
/// Instruction types
//------------------------------------------------------------------
typedef enum InstructionType {
@@ -214,25 +205,13 @@ typedef enum MemoryModuleLoadLevel {
enum class LineStatus {
Success, // The line that was just edited if good and should be added to the
// lines
- Error, // There is an error with the current line and it needs to be re-edited
- // before it can be accepted
- Done // Lines are complete
+ Status, // There is an error with the current line and it needs to be
+ // re-edited
+ // before it can be accepted
+ Done // Lines are complete
};
//----------------------------------------------------------------------
-// Exit Type for inferior processes
-//----------------------------------------------------------------------
-typedef enum ExitType {
- eExitTypeInvalid,
- eExitTypeExit, // The exit status represents the return code from normal
- // program exit (i.e. WIFEXITED() was true)
- eExitTypeSignal, // The exit status represents the signal number that caused
- // the program to exit (i.e. WIFSIGNALED() was true)
- eExitTypeStop, // The exit status represents the stop signal that caused the
- // program to exit (i.e. WIFSTOPPED() was true)
-} ExitType;
-
-//----------------------------------------------------------------------
// Boolean result of running a Type Validator
//----------------------------------------------------------------------
enum class TypeValidatorResult : bool { Success = true, Failure = false };
@@ -257,4 +236,24 @@ enum class CompilerContextKind {
} // namespace lldb_private
+namespace llvm {
+template <> struct format_provider<lldb_private::Vote> {
+ static void format(const lldb_private::Vote &V, llvm::raw_ostream &Stream,
+ StringRef Style) {
+ switch (V) {
+ case lldb_private::eVoteNo:
+ Stream << "no";
+ return;
+ case lldb_private::eVoteNoOpinion:
+ Stream << "no opinion";
+ return;
+ case lldb_private::eVoteYes:
+ Stream << "yes";
+ return;
+ }
+ Stream << "invalid";
+ }
+};
+}
+
#endif // LLDB_lldb_private_enumerations_h_
diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-private-forward.h b/contrib/llvm/tools/lldb/include/lldb/lldb-private-forward.h
index 69a2311..296facb 100644
--- a/contrib/llvm/tools/lldb/include/lldb/lldb-private-forward.h
+++ b/contrib/llvm/tools/lldb/include/lldb/lldb-private-forward.h
@@ -30,10 +30,6 @@ class UnixSignals;
// SP/WP decls.
// ---------------------------------------------------------------
typedef std::shared_ptr<NativeBreakpoint> NativeBreakpointSP;
-typedef std::shared_ptr<lldb_private::NativeProcessProtocol>
- NativeProcessProtocolSP;
-typedef std::weak_ptr<lldb_private::NativeProcessProtocol>
- NativeProcessProtocolWP;
typedef std::shared_ptr<lldb_private::NativeRegisterContext>
NativeRegisterContextSP;
typedef std::shared_ptr<lldb_private::NativeThreadProtocol>
diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-private-interfaces.h b/contrib/llvm/tools/lldb/include/lldb/lldb-private-interfaces.h
index c0d5c85..806068e 100644
--- a/contrib/llvm/tools/lldb/include/lldb/lldb-private-interfaces.h
+++ b/contrib/llvm/tools/lldb/include/lldb/lldb-private-interfaces.h
@@ -16,10 +16,12 @@
#include "lldb/lldb-forward.h"
#include "lldb/lldb-types.h"
+#include "lldb/lldb-private-enumerations.h"
+
#include <set>
namespace lldb_private {
-typedef lldb::ABISP (*ABICreateInstance)(const ArchSpec &arch);
+typedef lldb::ABISP (*ABICreateInstance)(lldb::ProcessSP process_sp, const ArchSpec &arch);
typedef Disassembler *(*DisassemblerCreateInstance)(const ArchSpec &arch,
const char *flavor);
typedef DynamicLoader *(*DynamicLoaderCreateInstance)(Process *process,
@@ -44,8 +46,7 @@ typedef ObjectFile *(*ObjectFileCreateMemoryInstance)(
const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
const lldb::ProcessSP &process_sp, lldb::addr_t offset);
typedef bool (*ObjectFileSaveCore)(const lldb::ProcessSP &process_sp,
- const FileSpec &outfile, Error &error);
-typedef LogChannel *(*LogChannelCreateInstance)();
+ const FileSpec &outfile, Status &error);
typedef EmulateInstruction *(*EmulateInstructionCreateInstance)(
const ArchSpec &arch, InstructionType inst_type);
typedef OperatingSystem *(*OperatingSystemCreateInstance)(Process *process,
@@ -57,8 +58,8 @@ typedef lldb::CommandObjectSP (*LanguageRuntimeGetCommandObject)(
CommandInterpreter &interpreter);
typedef lldb::StructuredDataPluginSP (*StructuredDataPluginCreateInstance)(
Process &process);
-typedef Error (*StructuredDataFilterLaunchInfo)(ProcessLaunchInfo &launch_info,
- Target *target);
+typedef Status (*StructuredDataFilterLaunchInfo)(ProcessLaunchInfo &launch_info,
+ Target *target);
typedef SystemRuntime *(*SystemRuntimeCreateInstance)(Process *process);
typedef lldb::PlatformSP (*PlatformCreateInstance)(bool force,
const ArchSpec *arch);
@@ -95,7 +96,7 @@ typedef lldb::InstrumentationRuntimeSP (*InstrumentationRuntimeCreateInstance)(
const lldb::ProcessSP &process_sp);
typedef lldb::TypeSystemSP (*TypeSystemCreateInstance)(
lldb::LanguageType language, Module *module, Target *target);
-typedef lldb::REPLSP (*REPLCreateInstance)(Error &error,
+typedef lldb::REPLSP (*REPLCreateInstance)(Status &error,
lldb::LanguageType language,
Debugger *debugger, Target *target,
const char *repl_options);
diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-private-types.h b/contrib/llvm/tools/lldb/include/lldb/lldb-private-types.h
index 4f192b6..fd21641 100644
--- a/contrib/llvm/tools/lldb/include/lldb/lldb-private-types.h
+++ b/contrib/llvm/tools/lldb/include/lldb/lldb-private-types.h
@@ -27,7 +27,7 @@ class Platform;
class ExecutionContext;
typedef llvm::sys::DynamicLibrary (*LoadPluginCallbackType)(
- const lldb::DebuggerSP &debugger_sp, const FileSpec &spec, Error &error);
+ const lldb::DebuggerSP &debugger_sp, const FileSpec &spec, Status &error);
//----------------------------------------------------------------------
// Every register is described in detail including its name, alternate
diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-types.h b/contrib/llvm/tools/lldb/include/lldb/lldb-types.h
index 07e9f5ac..fc445f5 100644
--- a/contrib/llvm/tools/lldb/include/lldb/lldb-types.h
+++ b/contrib/llvm/tools/lldb/include/lldb/lldb-types.h
@@ -13,16 +13,10 @@
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
-#include <assert.h>
-#include <signal.h>
#include <stdint.h>
//----------------------------------------------------------------------
// All host systems must define:
-// lldb::condition_t The native condition type (or a substitute class)
-// for conditions on the host system.
-// lldb::mutex_t The native mutex type for mutex objects on the host
-// system.
// lldb::thread_t The native thread type for spawned threads on the
// system
// lldb::thread_arg_t The type of the one any only thread creation
@@ -34,32 +28,22 @@
// #define LLDB_INVALID_PROCESS_ID ...
// #define LLDB_INVALID_THREAD_ID ...
// #define LLDB_INVALID_HOST_THREAD ...
-// #define IS_VALID_LLDB_HOST_THREAD ...
//----------------------------------------------------------------------
// TODO: Add a bunch of ifdefs to determine the host system and what
// things should be defined. Currently MacOSX is being assumed by default
// since that is what lldb was first developed for.
-#ifndef _MSC_VER
-#include <stdbool.h>
-#include <unistd.h>
-#endif
-
#ifdef _WIN32
#include <process.h>
namespace lldb {
-typedef void *mutex_t;
-typedef void *condition_t;
typedef void *rwlock_t;
typedef void *process_t; // Process type is HANDLE
typedef void *thread_t; // Host thread type
typedef void *file_t; // Host file type
-typedef void *pipe_t; // Host pipe type
typedef unsigned int __w64 socket_t; // Host socket type
-typedef uint32_t thread_key_t;
typedef void *thread_arg_t; // Host thread argument type
typedef unsigned thread_result_t; // Host thread result type
typedef thread_result_t (*thread_func_t)(void *); // Host thread function type
@@ -73,15 +57,11 @@ namespace lldb {
//----------------------------------------------------------------------
// MacOSX Types
//----------------------------------------------------------------------
-typedef ::pthread_mutex_t mutex_t;
-typedef pthread_cond_t condition_t;
typedef pthread_rwlock_t rwlock_t;
typedef uint64_t process_t; // Process type is just a pid.
typedef pthread_t thread_t; // Host thread type
typedef int file_t; // Host file type
-typedef int pipe_t; // Host pipe type
typedef int socket_t; // Host socket type
-typedef pthread_key_t thread_key_t;
typedef void *thread_arg_t; // Host thread argument type
typedef void *thread_result_t; // Host thread result type
typedef void *(*thread_func_t)(void *); // Host thread function type
@@ -100,10 +80,6 @@ typedef bool (*ExpressionCancelCallback)(ExpressionEvaluationPhase phase,
#define LLDB_INVALID_PROCESS ((lldb::process_t)-1)
#define LLDB_INVALID_HOST_THREAD ((lldb::thread_t)NULL)
-#define IS_VALID_LLDB_HOST_THREAD(t) ((t) != LLDB_INVALID_HOST_THREAD)
-
-#define LLDB_INVALID_HOST_TIME \
- { 0, 0 }
namespace lldb {
typedef uint64_t addr_t;
diff --git a/contrib/llvm/tools/lldb/source/API/SBAddress.cpp b/contrib/llvm/tools/lldb/source/API/SBAddress.cpp
index 0ef374f..a3493d7 100644
--- a/contrib/llvm/tools/lldb/source/API/SBAddress.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBAddress.cpp
@@ -12,11 +12,11 @@
#include "lldb/API/SBSection.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/LineEntry.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -55,6 +55,12 @@ const SBAddress &SBAddress::operator=(const SBAddress &rhs) {
return *this;
}
+bool lldb::operator==(const SBAddress &lhs, const SBAddress &rhs) {
+ if (lhs.IsValid() && rhs.IsValid())
+ return lhs.ref() == rhs.ref();
+ return false;
+}
+
bool SBAddress::IsValid() const {
return m_opaque_ap.get() != NULL && m_opaque_ap->IsValid();
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBBlock.cpp b/contrib/llvm/tools/lldb/source/API/SBBlock.cpp
index 471b7fb..cd45387 100644
--- a/contrib/llvm/tools/lldb/source/API/SBBlock.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBBlock.cpp
@@ -14,7 +14,6 @@
#include "lldb/API/SBStream.h"
#include "lldb/API/SBValue.h"
#include "lldb/Core/AddressRange.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Function.h"
@@ -22,6 +21,7 @@
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBBreakpoint.cpp b/contrib/llvm/tools/lldb/source/API/SBBreakpoint.cpp
index 0eab2c2..bf96032 100644
--- a/contrib/llvm/tools/lldb/source/API/SBBreakpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBBreakpoint.cpp
@@ -26,8 +26,6 @@
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
@@ -36,6 +34,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/lldb-enumerations.h"
@@ -59,83 +59,74 @@ public:
}
};
-SBBreakpoint::SBBreakpoint() : m_opaque_sp() {}
+SBBreakpoint::SBBreakpoint() {}
SBBreakpoint::SBBreakpoint(const SBBreakpoint &rhs)
- : m_opaque_sp(rhs.m_opaque_sp) {}
+ : m_opaque_wp(rhs.m_opaque_wp) {}
SBBreakpoint::SBBreakpoint(const lldb::BreakpointSP &bp_sp)
- : m_opaque_sp(bp_sp) {}
+ : m_opaque_wp(bp_sp) {}
SBBreakpoint::~SBBreakpoint() = default;
const SBBreakpoint &SBBreakpoint::operator=(const SBBreakpoint &rhs) {
- if (this != &rhs)
- m_opaque_sp = rhs.m_opaque_sp;
+ m_opaque_wp = rhs.m_opaque_wp;
return *this;
}
bool SBBreakpoint::operator==(const lldb::SBBreakpoint &rhs) {
- if (m_opaque_sp && rhs.m_opaque_sp)
- return m_opaque_sp.get() == rhs.m_opaque_sp.get();
- return false;
+ return m_opaque_wp.lock() == rhs.m_opaque_wp.lock();
}
bool SBBreakpoint::operator!=(const lldb::SBBreakpoint &rhs) {
- if (m_opaque_sp && rhs.m_opaque_sp)
- return m_opaque_sp.get() != rhs.m_opaque_sp.get();
- return (m_opaque_sp && !rhs.m_opaque_sp) || (rhs.m_opaque_sp && !m_opaque_sp);
+ return m_opaque_wp.lock() != rhs.m_opaque_wp.lock();
}
break_id_t SBBreakpoint::GetID() const {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
break_id_t break_id = LLDB_INVALID_BREAK_ID;
- if (m_opaque_sp)
- break_id = m_opaque_sp->GetID();
-
- if (log) {
- if (break_id == LLDB_INVALID_BREAK_ID)
- log->Printf("SBBreakpoint(%p)::GetID () => LLDB_INVALID_BREAK_ID",
- static_cast<void *>(m_opaque_sp.get()));
- else
- log->Printf("SBBreakpoint(%p)::GetID () => %u",
- static_cast<void *>(m_opaque_sp.get()), break_id);
- }
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp)
+ break_id = bkpt_sp->GetID();
+ LLDB_LOG(log, "breakpoint = {0}, id = {1}", bkpt_sp.get(), break_id);
return break_id;
}
bool SBBreakpoint::IsValid() const {
- if (!m_opaque_sp)
+ BreakpointSP bkpt_sp = GetSP();
+ if (!bkpt_sp)
return false;
- else if (m_opaque_sp->GetTarget().GetBreakpointByID(m_opaque_sp->GetID()))
+ else if (bkpt_sp->GetTarget().GetBreakpointByID(bkpt_sp->GetID()))
return true;
else
return false;
}
void SBBreakpoint::ClearAllBreakpointSites() {
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->ClearAllBreakpointSites();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->ClearAllBreakpointSites();
}
}
SBBreakpointLocation SBBreakpoint::FindLocationByAddress(addr_t vm_addr) {
SBBreakpointLocation sb_bp_location;
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
if (vm_addr != LLDB_INVALID_ADDRESS) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetTarget().GetAPIMutex());
Address address;
- Target &target = m_opaque_sp->GetTarget();
+ Target &target = bkpt_sp->GetTarget();
if (!target.GetSectionLoadList().ResolveLoadAddress(vm_addr, address)) {
address.SetRawAddress(vm_addr);
}
- sb_bp_location.SetLocation(m_opaque_sp->FindLocationByAddress(address));
+ sb_bp_location.SetLocation(bkpt_sp->FindLocationByAddress(address));
}
}
return sb_bp_location;
@@ -143,16 +134,17 @@ SBBreakpointLocation SBBreakpoint::FindLocationByAddress(addr_t vm_addr) {
break_id_t SBBreakpoint::FindLocationIDByAddress(addr_t vm_addr) {
break_id_t break_id = LLDB_INVALID_BREAK_ID;
+ BreakpointSP bkpt_sp = GetSP();
- if (m_opaque_sp && vm_addr != LLDB_INVALID_ADDRESS) {
+ if (bkpt_sp && vm_addr != LLDB_INVALID_ADDRESS) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetTarget().GetAPIMutex());
Address address;
- Target &target = m_opaque_sp->GetTarget();
+ Target &target = bkpt_sp->GetTarget();
if (!target.GetSectionLoadList().ResolveLoadAddress(vm_addr, address)) {
address.SetRawAddress(vm_addr);
}
- break_id = m_opaque_sp->FindLocationIDByAddress(address);
+ break_id = bkpt_sp->FindLocationIDByAddress(address);
}
return break_id;
@@ -160,11 +152,12 @@ break_id_t SBBreakpoint::FindLocationIDByAddress(addr_t vm_addr) {
SBBreakpointLocation SBBreakpoint::FindLocationByID(break_id_t bp_loc_id) {
SBBreakpointLocation sb_bp_location;
+ BreakpointSP bkpt_sp = GetSP();
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- sb_bp_location.SetLocation(m_opaque_sp->FindLocationByID(bp_loc_id));
+ bkpt_sp->GetTarget().GetAPIMutex());
+ sb_bp_location.SetLocation(bkpt_sp->FindLocationByID(bp_loc_id));
}
return sb_bp_location;
@@ -172,11 +165,12 @@ SBBreakpointLocation SBBreakpoint::FindLocationByID(break_id_t bp_loc_id) {
SBBreakpointLocation SBBreakpoint::GetLocationAtIndex(uint32_t index) {
SBBreakpointLocation sb_bp_location;
+ BreakpointSP bkpt_sp = GetSP();
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- sb_bp_location.SetLocation(m_opaque_sp->GetLocationAtIndex(index));
+ bkpt_sp->GetTarget().GetAPIMutex());
+ sb_bp_location.SetLocation(bkpt_sp->GetLocationAtIndex(index));
}
return sb_bp_location;
@@ -184,290 +178,282 @@ SBBreakpointLocation SBBreakpoint::GetLocationAtIndex(uint32_t index) {
void SBBreakpoint::SetEnabled(bool enable) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointSP bkpt_sp = GetSP();
- if (log)
- log->Printf("SBBreakpoint(%p)::SetEnabled (enabled=%i)",
- static_cast<void *>(m_opaque_sp.get()), enable);
+ LLDB_LOG(log, "breakpoint = {0}, enable = {1}", bkpt_sp.get(), enable);
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetEnabled(enable);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->SetEnabled(enable);
}
}
bool SBBreakpoint::IsEnabled() {
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->IsEnabled();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ return bkpt_sp->IsEnabled();
} else
return false;
}
void SBBreakpoint::SetOneShot(bool one_shot) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointSP bkpt_sp = GetSP();
- if (log)
- log->Printf("SBBreakpoint(%p)::SetOneShot (one_shot=%i)",
- static_cast<void *>(m_opaque_sp.get()), one_shot);
+ LLDB_LOG(log, "breakpoint = {0}, one_shot = {1}", bkpt_sp.get(), one_shot);
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetOneShot(one_shot);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->SetOneShot(one_shot);
}
}
bool SBBreakpoint::IsOneShot() const {
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->IsOneShot();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ return bkpt_sp->IsOneShot();
} else
return false;
}
bool SBBreakpoint::IsInternal() {
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->IsInternal();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ return bkpt_sp->IsInternal();
} else
return false;
}
void SBBreakpoint::SetIgnoreCount(uint32_t count) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointSP bkpt_sp = GetSP();
- if (log)
- log->Printf("SBBreakpoint(%p)::SetIgnoreCount (count=%u)",
- static_cast<void *>(m_opaque_sp.get()), count);
+ LLDB_LOG(log, "breakpoint = {0}, count = {1}", bkpt_sp.get(), count);
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetIgnoreCount(count);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->SetIgnoreCount(count);
}
}
void SBBreakpoint::SetCondition(const char *condition) {
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetCondition(condition);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->SetCondition(condition);
}
}
const char *SBBreakpoint::GetCondition() {
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->GetConditionText();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ return bkpt_sp->GetConditionText();
}
return nullptr;
}
uint32_t SBBreakpoint::GetHitCount() const {
uint32_t count = 0;
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- count = m_opaque_sp->GetHitCount();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ count = bkpt_sp->GetHitCount();
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::GetHitCount () => %u",
- static_cast<void *>(m_opaque_sp.get()), count);
+ LLDB_LOG(log, "breakpoint = {0}, count = {1}", bkpt_sp.get(), count);
return count;
}
uint32_t SBBreakpoint::GetIgnoreCount() const {
uint32_t count = 0;
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- count = m_opaque_sp->GetIgnoreCount();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ count = bkpt_sp->GetIgnoreCount();
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::GetIgnoreCount () => %u",
- static_cast<void *>(m_opaque_sp.get()), count);
+ LLDB_LOG(log, "breakpoint = {0}, count = {1}", bkpt_sp.get(), count);
return count;
}
void SBBreakpoint::SetThreadID(tid_t tid) {
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetThreadID(tid);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->SetThreadID(tid);
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::SetThreadID (tid=0x%4.4" PRIx64 ")",
- static_cast<void *>(m_opaque_sp.get()), tid);
+ LLDB_LOG(log, "breakpoint = {0}, tid = {1:x}", bkpt_sp.get(), tid);
}
tid_t SBBreakpoint::GetThreadID() {
tid_t tid = LLDB_INVALID_THREAD_ID;
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- tid = m_opaque_sp->GetThreadID();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ tid = bkpt_sp->GetThreadID();
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::GetThreadID () => 0x%4.4" PRIx64,
- static_cast<void *>(m_opaque_sp.get()), tid);
+ LLDB_LOG(log, "breakpoint = {0}, tid = {1:x}", bkpt_sp.get(), tid);
return tid;
}
void SBBreakpoint::SetThreadIndex(uint32_t index) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::SetThreadIndex (%u)",
- static_cast<void *>(m_opaque_sp.get()), index);
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}, index = {1}", bkpt_sp.get(), index);
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->GetOptions()->GetThreadSpec()->SetIndex(index);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetOptions()->GetThreadSpec()->SetIndex(index);
}
}
uint32_t SBBreakpoint::GetThreadIndex() const {
uint32_t thread_idx = UINT32_MAX;
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetTarget().GetAPIMutex());
const ThreadSpec *thread_spec =
- m_opaque_sp->GetOptions()->GetThreadSpecNoCreate();
+ bkpt_sp->GetOptions()->GetThreadSpecNoCreate();
if (thread_spec != nullptr)
thread_idx = thread_spec->GetIndex();
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::GetThreadIndex () => %u",
- static_cast<void *>(m_opaque_sp.get()), thread_idx);
+ LLDB_LOG(log, "breakpoint = {0}, index = {1}", bkpt_sp.get(), thread_idx);
return thread_idx;
}
void SBBreakpoint::SetThreadName(const char *thread_name) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::SetThreadName (%s)",
- static_cast<void *>(m_opaque_sp.get()), thread_name);
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}, name = {1}", bkpt_sp.get(), thread_name);
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->GetOptions()->GetThreadSpec()->SetName(thread_name);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetOptions()->GetThreadSpec()->SetName(thread_name);
}
}
const char *SBBreakpoint::GetThreadName() const {
const char *name = nullptr;
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetTarget().GetAPIMutex());
const ThreadSpec *thread_spec =
- m_opaque_sp->GetOptions()->GetThreadSpecNoCreate();
+ bkpt_sp->GetOptions()->GetThreadSpecNoCreate();
if (thread_spec != nullptr)
name = thread_spec->GetName();
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::GetThreadName () => %s",
- static_cast<void *>(m_opaque_sp.get()), name);
+ LLDB_LOG(log, "breakpoint = {0}, name = {1}", bkpt_sp.get(), name);
return name;
}
void SBBreakpoint::SetQueueName(const char *queue_name) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::SetQueueName (%s)",
- static_cast<void *>(m_opaque_sp.get()), queue_name);
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}, queue_name = {1}", bkpt_sp.get(),
+ queue_name);
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->GetOptions()->GetThreadSpec()->SetQueueName(queue_name);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetOptions()->GetThreadSpec()->SetQueueName(queue_name);
}
}
const char *SBBreakpoint::GetQueueName() const {
const char *name = nullptr;
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetTarget().GetAPIMutex());
const ThreadSpec *thread_spec =
- m_opaque_sp->GetOptions()->GetThreadSpecNoCreate();
+ bkpt_sp->GetOptions()->GetThreadSpecNoCreate();
if (thread_spec)
name = thread_spec->GetQueueName();
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::GetQueueName () => %s",
- static_cast<void *>(m_opaque_sp.get()), name);
+ LLDB_LOG(log, "breakpoint = {0}, name = {1}", bkpt_sp.get(), name);
return name;
}
size_t SBBreakpoint::GetNumResolvedLocations() const {
size_t num_resolved = 0;
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- num_resolved = m_opaque_sp->GetNumResolvedLocations();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ num_resolved = bkpt_sp->GetNumResolvedLocations();
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::GetNumResolvedLocations () => %" PRIu64,
- static_cast<void *>(m_opaque_sp.get()),
- static_cast<uint64_t>(num_resolved));
+ LLDB_LOG(log, "breakpoint = {0}, num_resolved = {1}", bkpt_sp.get(),
+ num_resolved);
return num_resolved;
}
size_t SBBreakpoint::GetNumLocations() const {
+ BreakpointSP bkpt_sp = GetSP();
size_t num_locs = 0;
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- num_locs = m_opaque_sp->GetNumLocations();
+ bkpt_sp->GetTarget().GetAPIMutex());
+ num_locs = bkpt_sp->GetNumLocations();
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
- if (log)
- log->Printf("SBBreakpoint(%p)::GetNumLocations () => %" PRIu64,
- static_cast<void *>(m_opaque_sp.get()),
- static_cast<uint64_t>(num_locs));
+ LLDB_LOG(log, "breakpoint = {0}, num_locs = {1}", bkpt_sp.get(), num_locs);
return num_locs;
}
void SBBreakpoint::SetCommandLineCommands(SBStringList &commands) {
- if (!m_opaque_sp)
+ BreakpointSP bkpt_sp = GetSP();
+ if (!bkpt_sp)
return;
if (commands.GetSize() == 0)
return;
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetTarget().GetAPIMutex());
std::unique_ptr<BreakpointOptions::CommandData> cmd_data_up(
new BreakpointOptions::CommandData(*commands, eScriptLanguageNone));
- m_opaque_sp->GetOptions()->SetCommandDataCallback(cmd_data_up);
+ bkpt_sp->GetOptions()->SetCommandDataCallback(cmd_data_up);
}
bool SBBreakpoint::GetCommandLineCommands(SBStringList &commands) {
- if (!m_opaque_sp)
+ BreakpointSP bkpt_sp = GetSP();
+ if (!bkpt_sp)
return false;
StringList command_list;
bool has_commands =
- m_opaque_sp->GetOptions()->GetCommandLineCallbacks(command_list);
+ bkpt_sp->GetOptions()->GetCommandLineCallbacks(command_list);
if (has_commands)
commands.AppendList(command_list);
return has_commands;
@@ -478,14 +464,15 @@ bool SBBreakpoint::GetDescription(SBStream &s) {
}
bool SBBreakpoint::GetDescription(SBStream &s, bool include_locations) {
- if (m_opaque_sp) {
+ BreakpointSP bkpt_sp = GetSP();
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- s.Printf("SBBreakpoint: id = %i, ", m_opaque_sp->GetID());
- m_opaque_sp->GetResolverDescription(s.get());
- m_opaque_sp->GetFilterDescription(s.get());
+ bkpt_sp->GetTarget().GetAPIMutex());
+ s.Printf("SBBreakpoint: id = %i, ", bkpt_sp->GetID());
+ bkpt_sp->GetResolverDescription(s.get());
+ bkpt_sp->GetFilterDescription(s.get());
if (include_locations) {
- const size_t num_locations = m_opaque_sp->GetNumLocations();
+ const size_t num_locations = bkpt_sp->GetNumLocations();
s.Printf(", locations = %" PRIu64, (uint64_t)num_locations);
}
return true;
@@ -526,36 +513,31 @@ bool SBBreakpoint::PrivateBreakpointHitCallback(void *baton,
void SBBreakpoint::SetCallback(BreakpointHitCallback callback, void *baton) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}, callback = {1}, baton = {2}", bkpt_sp.get(),
+ callback, baton);
- if (log) {
- void *pointer = &callback;
- log->Printf("SBBreakpoint(%p)::SetCallback (callback=%p, baton=%p)",
- static_cast<void *>(m_opaque_sp.get()),
- *static_cast<void **>(&pointer), static_cast<void *>(baton));
- }
-
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetTarget().GetAPIMutex());
BatonSP baton_sp(new SBBreakpointCallbackBaton(callback, baton));
- m_opaque_sp->SetCallback(SBBreakpoint::PrivateBreakpointHitCallback,
- baton_sp, false);
+ bkpt_sp->SetCallback(SBBreakpoint::PrivateBreakpointHitCallback, baton_sp,
+ false);
}
}
void SBBreakpoint::SetScriptCallbackFunction(
const char *callback_function_name) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}, callback = {1}", bkpt_sp.get(),
+ callback_function_name);
- if (log)
- log->Printf("SBBreakpoint(%p)::SetScriptCallbackFunction (callback=%s)",
- static_cast<void *>(m_opaque_sp.get()), callback_function_name);
-
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- BreakpointOptions *bp_options = m_opaque_sp->GetOptions();
- m_opaque_sp->GetTarget()
+ bkpt_sp->GetTarget().GetAPIMutex());
+ BreakpointOptions *bp_options = bkpt_sp->GetOptions();
+ bkpt_sp->GetTarget()
.GetDebugger()
.GetCommandInterpreter()
.GetScriptInterpreter()
@@ -566,18 +548,17 @@ void SBBreakpoint::SetScriptCallbackFunction(
SBError SBBreakpoint::SetScriptCallbackBody(const char *callback_body_text) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
-
- if (log)
- log->Printf("SBBreakpoint(%p)::SetScriptCallbackBody: callback body:\n%s)",
- static_cast<void *>(m_opaque_sp.get()), callback_body_text);
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}, callback body:\n{1}", bkpt_sp.get(),
+ callback_body_text);
SBError sb_error;
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- BreakpointOptions *bp_options = m_opaque_sp->GetOptions();
- Error error =
- m_opaque_sp->GetTarget()
+ bkpt_sp->GetTarget().GetAPIMutex());
+ BreakpointOptions *bp_options = bkpt_sp->GetOptions();
+ Status error =
+ bkpt_sp->GetTarget()
.GetDebugger()
.GetCommandInterpreter()
.GetScriptInterpreter()
@@ -591,17 +572,15 @@ SBError SBBreakpoint::SetScriptCallbackBody(const char *callback_body_text) {
bool SBBreakpoint::AddName(const char *new_name) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}, name = {1}", bkpt_sp.get(), new_name);
- if (log)
- log->Printf("SBBreakpoint(%p)::AddName (name=%s)",
- static_cast<void *>(m_opaque_sp.get()), new_name);
-
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- Error error; // Think I'm just going to swallow the error here, it's
- // probably more annoying to have to provide it.
- return m_opaque_sp->AddName(new_name, error);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ Status error; // Think I'm just going to swallow the error here, it's
+ // probably more annoying to have to provide it.
+ return bkpt_sp->AddName(new_name, error);
}
return false;
@@ -609,29 +588,25 @@ bool SBBreakpoint::AddName(const char *new_name) {
void SBBreakpoint::RemoveName(const char *name_to_remove) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}, name = {1}", bkpt_sp.get(), name_to_remove);
- if (log)
- log->Printf("SBBreakpoint(%p)::RemoveName (name=%s)",
- static_cast<void *>(m_opaque_sp.get()), name_to_remove);
-
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->RemoveName(name_to_remove);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->RemoveName(name_to_remove);
}
}
bool SBBreakpoint::MatchesName(const char *name) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}, name = {1}", bkpt_sp.get(), name);
- if (log)
- log->Printf("SBBreakpoint(%p)::MatchesName (name=%s)",
- static_cast<void *>(m_opaque_sp.get()), name);
-
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->MatchesName(name);
+ bkpt_sp->GetTarget().GetAPIMutex());
+ return bkpt_sp->MatchesName(name);
}
return false;
@@ -639,36 +614,20 @@ bool SBBreakpoint::MatchesName(const char *name) {
void SBBreakpoint::GetNames(SBStringList &names) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointSP bkpt_sp = GetSP();
+ LLDB_LOG(log, "breakpoint = {0}", bkpt_sp.get());
- if (log)
- log->Printf("SBBreakpoint(%p)::GetNames ()",
- static_cast<void *>(m_opaque_sp.get()));
-
- if (m_opaque_sp) {
+ if (bkpt_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
+ bkpt_sp->GetTarget().GetAPIMutex());
std::vector<std::string> names_vec;
- m_opaque_sp->GetNames(names_vec);
+ bkpt_sp->GetNames(names_vec);
for (std::string name : names_vec) {
names.AppendString(name.c_str());
}
}
}
-lldb_private::Breakpoint *SBBreakpoint::operator->() const {
- return m_opaque_sp.get();
-}
-
-lldb_private::Breakpoint *SBBreakpoint::get() const {
- return m_opaque_sp.get();
-}
-
-lldb::BreakpointSP &SBBreakpoint::operator*() { return m_opaque_sp; }
-
-const lldb::BreakpointSP &SBBreakpoint::operator*() const {
- return m_opaque_sp;
-}
-
bool SBBreakpoint::EventIsBreakpointEvent(const lldb::SBEvent &event) {
return Breakpoint::BreakpointEventData::GetEventDataFromEvent(event.get()) !=
nullptr;
@@ -683,11 +642,10 @@ SBBreakpoint::GetBreakpointEventTypeFromEvent(const SBEvent &event) {
}
SBBreakpoint SBBreakpoint::GetBreakpointFromEvent(const lldb::SBEvent &event) {
- SBBreakpoint sb_breakpoint;
if (event.IsValid())
- sb_breakpoint.m_opaque_sp =
- Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event.GetSP());
- return sb_breakpoint;
+ return SBBreakpoint(
+ Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event.GetSP()));
+ return SBBreakpoint();
}
SBBreakpointLocation
@@ -711,6 +669,8 @@ SBBreakpoint::GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event) {
return num_locations;
}
+BreakpointSP SBBreakpoint::GetSP() const { return m_opaque_wp.lock(); }
+
// This is simple collection of breakpoint id's and their target.
class SBBreakpointListImpl {
public:
@@ -745,28 +705,28 @@ public:
return BreakpointSP();
}
- bool Append(Breakpoint &bkpt) {
+ bool Append(BreakpointSP bkpt) {
TargetSP target_sp = m_target_wp.lock();
- if (!target_sp)
+ if (!target_sp || !bkpt)
return false;
- if (bkpt.GetTargetSP() != target_sp)
+ if (bkpt->GetTargetSP() != target_sp)
return false;
- m_break_ids.push_back(bkpt.GetID());
+ m_break_ids.push_back(bkpt->GetID());
return true;
}
- bool AppendIfUnique(Breakpoint &bkpt) {
+ bool AppendIfUnique(BreakpointSP bkpt) {
TargetSP target_sp = m_target_wp.lock();
- if (!target_sp)
+ if (!target_sp || !bkpt)
return false;
- if (bkpt.GetTargetSP() != target_sp)
+ if (bkpt->GetTargetSP() != target_sp)
return false;
- lldb::break_id_t bp_id = bkpt.GetID();
+ lldb::break_id_t bp_id = bkpt->GetID();
if (find(m_break_ids.begin(), m_break_ids.end(), bp_id) ==
m_break_ids.end())
return false;
- m_break_ids.push_back(bkpt.GetID());
+ m_break_ids.push_back(bkpt->GetID());
return true;
}
@@ -827,7 +787,7 @@ void SBBreakpointList::Append(const SBBreakpoint &sb_bkpt) {
return;
if (!m_opaque_sp)
return;
- m_opaque_sp->Append(*sb_bkpt.get());
+ m_opaque_sp->Append(sb_bkpt.m_opaque_wp.lock());
}
void SBBreakpointList::AppendByID(lldb::break_id_t id) {
@@ -841,7 +801,7 @@ bool SBBreakpointList::AppendIfUnique(const SBBreakpoint &sb_bkpt) {
return false;
if (!m_opaque_sp)
return false;
- return m_opaque_sp->AppendIfUnique(*sb_bkpt.get());
+ return m_opaque_sp->AppendIfUnique(sb_bkpt.GetSP());
}
void SBBreakpointList::Clear() {
diff --git a/contrib/llvm/tools/lldb/source/API/SBBreakpointLocation.cpp b/contrib/llvm/tools/lldb/source/API/SBBreakpointLocation.cpp
index c7fac76..dc9c00d 100644
--- a/contrib/llvm/tools/lldb/source/API/SBBreakpointLocation.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBBreakpointLocation.cpp
@@ -16,118 +16,124 @@
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
-#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
using namespace lldb;
using namespace lldb_private;
-SBBreakpointLocation::SBBreakpointLocation() : m_opaque_sp() {}
+SBBreakpointLocation::SBBreakpointLocation() {}
SBBreakpointLocation::SBBreakpointLocation(
const lldb::BreakpointLocationSP &break_loc_sp)
- : m_opaque_sp(break_loc_sp) {
+ : m_opaque_wp(break_loc_sp) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
if (log) {
SBStream sstr;
GetDescription(sstr, lldb::eDescriptionLevelBrief);
- log->Printf("SBBreakpointLocation::SBBreakpointLocaiton (const "
- "lldb::BreakpointLocationsSP &break_loc_sp"
- "=%p) => this.sp = %p (%s)",
- static_cast<void *>(break_loc_sp.get()),
- static_cast<void *>(m_opaque_sp.get()), sstr.GetData());
+ LLDB_LOG(log, "location = {0} ({1})", break_loc_sp.get(), sstr.GetData());
}
}
SBBreakpointLocation::SBBreakpointLocation(const SBBreakpointLocation &rhs)
- : m_opaque_sp(rhs.m_opaque_sp) {}
+ : m_opaque_wp(rhs.m_opaque_wp) {}
const SBBreakpointLocation &SBBreakpointLocation::
operator=(const SBBreakpointLocation &rhs) {
- if (this != &rhs)
- m_opaque_sp = rhs.m_opaque_sp;
+ m_opaque_wp = rhs.m_opaque_wp;
return *this;
}
SBBreakpointLocation::~SBBreakpointLocation() {}
-bool SBBreakpointLocation::IsValid() const { return m_opaque_sp.get() != NULL; }
+BreakpointLocationSP SBBreakpointLocation::GetSP() const {
+ return m_opaque_wp.lock();
+}
+
+bool SBBreakpointLocation::IsValid() const { return bool(GetSP()); }
SBAddress SBBreakpointLocation::GetAddress() {
- if (m_opaque_sp)
- return SBAddress(&m_opaque_sp->GetAddress());
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp)
+ return SBAddress(&loc_sp->GetAddress());
else
return SBAddress();
}
addr_t SBBreakpointLocation::GetLoadAddress() {
addr_t ret_addr = LLDB_INVALID_ADDRESS;
+ BreakpointLocationSP loc_sp = GetSP();
- if (m_opaque_sp) {
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- ret_addr = m_opaque_sp->GetLoadAddress();
+ loc_sp->GetTarget().GetAPIMutex());
+ ret_addr = loc_sp->GetLoadAddress();
}
return ret_addr;
}
void SBBreakpointLocation::SetEnabled(bool enabled) {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetEnabled(enabled);
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->SetEnabled(enabled);
}
}
bool SBBreakpointLocation::IsEnabled() {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->IsEnabled();
+ loc_sp->GetTarget().GetAPIMutex());
+ return loc_sp->IsEnabled();
} else
return false;
}
uint32_t SBBreakpointLocation::GetIgnoreCount() {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->GetIgnoreCount();
+ loc_sp->GetTarget().GetAPIMutex());
+ return loc_sp->GetIgnoreCount();
} else
return 0;
}
void SBBreakpointLocation::SetIgnoreCount(uint32_t n) {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetIgnoreCount(n);
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->SetIgnoreCount(n);
}
}
void SBBreakpointLocation::SetCondition(const char *condition) {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetCondition(condition);
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->SetCondition(condition);
}
}
const char *SBBreakpointLocation::GetCondition() {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->GetConditionText();
+ loc_sp->GetTarget().GetAPIMutex());
+ return loc_sp->GetConditionText();
}
return NULL;
}
@@ -135,17 +141,15 @@ const char *SBBreakpointLocation::GetCondition() {
void SBBreakpointLocation::SetScriptCallbackFunction(
const char *callback_function_name) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ BreakpointLocationSP loc_sp = GetSP();
+ LLDB_LOG(log, "location = {0}, callback = {1}", loc_sp.get(),
+ callback_function_name);
- if (log)
- log->Printf(
- "SBBreakpointLocation(%p)::SetScriptCallbackFunction (callback=%s)",
- static_cast<void *>(m_opaque_sp.get()), callback_function_name);
-
- if (m_opaque_sp) {
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- BreakpointOptions *bp_options = m_opaque_sp->GetLocationOptions();
- m_opaque_sp->GetBreakpoint()
+ loc_sp->GetTarget().GetAPIMutex());
+ BreakpointOptions *bp_options = loc_sp->GetLocationOptions();
+ loc_sp->GetBreakpoint()
.GetTarget()
.GetDebugger()
.GetCommandInterpreter()
@@ -158,18 +162,17 @@ void SBBreakpointLocation::SetScriptCallbackFunction(
SBError
SBBreakpointLocation::SetScriptCallbackBody(const char *callback_body_text) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
-
- if (log)
- log->Printf("SBBreakpoint(%p)::SetScriptCallbackBody: callback body:\n%s)",
- static_cast<void *>(m_opaque_sp.get()), callback_body_text);
+ BreakpointLocationSP loc_sp = GetSP();
+ LLDB_LOG(log, "location = {0}: callback body:\n{1}", loc_sp.get(),
+ callback_body_text);
SBError sb_error;
- if (m_opaque_sp) {
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- BreakpointOptions *bp_options = m_opaque_sp->GetLocationOptions();
- Error error =
- m_opaque_sp->GetBreakpoint()
+ loc_sp->GetTarget().GetAPIMutex());
+ BreakpointOptions *bp_options = loc_sp->GetLocationOptions();
+ Status error =
+ loc_sp->GetBreakpoint()
.GetTarget()
.GetDebugger()
.GetCommandInterpreter()
@@ -183,80 +186,89 @@ SBBreakpointLocation::SetScriptCallbackBody(const char *callback_body_text) {
}
void SBBreakpointLocation::SetThreadID(tid_t thread_id) {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetThreadID(thread_id);
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->SetThreadID(thread_id);
}
}
tid_t SBBreakpointLocation::GetThreadID() {
tid_t tid = LLDB_INVALID_THREAD_ID;
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->GetThreadID();
+ loc_sp->GetTarget().GetAPIMutex());
+ return loc_sp->GetThreadID();
}
return tid;
}
void SBBreakpointLocation::SetThreadIndex(uint32_t index) {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetThreadIndex(index);
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->SetThreadIndex(index);
}
}
uint32_t SBBreakpointLocation::GetThreadIndex() const {
uint32_t thread_idx = UINT32_MAX;
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->GetThreadIndex();
+ loc_sp->GetTarget().GetAPIMutex());
+ return loc_sp->GetThreadIndex();
}
return thread_idx;
}
void SBBreakpointLocation::SetThreadName(const char *thread_name) {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetThreadName(thread_name);
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->SetThreadName(thread_name);
}
}
const char *SBBreakpointLocation::GetThreadName() const {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->GetThreadName();
+ loc_sp->GetTarget().GetAPIMutex());
+ return loc_sp->GetThreadName();
}
return NULL;
}
void SBBreakpointLocation::SetQueueName(const char *queue_name) {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->SetQueueName(queue_name);
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->SetQueueName(queue_name);
}
}
const char *SBBreakpointLocation::GetQueueName() const {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->GetQueueName();
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->GetQueueName();
}
return NULL;
}
bool SBBreakpointLocation::IsResolved() {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->IsResolved();
+ loc_sp->GetTarget().GetAPIMutex());
+ return loc_sp->IsResolved();
}
return false;
}
@@ -264,17 +276,18 @@ bool SBBreakpointLocation::IsResolved() {
void SBBreakpointLocation::SetLocation(
const lldb::BreakpointLocationSP &break_loc_sp) {
// Uninstall the callbacks?
- m_opaque_sp = break_loc_sp;
+ m_opaque_wp = break_loc_sp;
}
bool SBBreakpointLocation::GetDescription(SBStream &description,
DescriptionLevel level) {
Stream &strm = description.ref();
+ BreakpointLocationSP loc_sp = GetSP();
- if (m_opaque_sp) {
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- m_opaque_sp->GetDescription(&strm, level);
+ loc_sp->GetTarget().GetAPIMutex());
+ loc_sp->GetDescription(&strm, level);
strm.EOL();
} else
strm.PutCString("No value");
@@ -283,34 +296,31 @@ bool SBBreakpointLocation::GetDescription(SBStream &description,
}
break_id_t SBBreakpointLocation::GetID() {
- if (m_opaque_sp) {
+ BreakpointLocationSP loc_sp = GetSP();
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- return m_opaque_sp->GetID();
+ loc_sp->GetTarget().GetAPIMutex());
+ return loc_sp->GetID();
} else
return LLDB_INVALID_BREAK_ID;
}
SBBreakpoint SBBreakpointLocation::GetBreakpoint() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
-
- // if (log)
- // log->Printf ("SBBreakpointLocation::GetBreakpoint ()");
+ BreakpointLocationSP loc_sp = GetSP();
SBBreakpoint sb_bp;
- if (m_opaque_sp) {
+ if (loc_sp) {
std::lock_guard<std::recursive_mutex> guard(
- m_opaque_sp->GetTarget().GetAPIMutex());
- *sb_bp = m_opaque_sp->GetBreakpoint().shared_from_this();
+ loc_sp->GetTarget().GetAPIMutex());
+ sb_bp = loc_sp->GetBreakpoint().shared_from_this();
}
if (log) {
SBStream sstr;
sb_bp.GetDescription(sstr);
- log->Printf(
- "SBBreakpointLocation(%p)::GetBreakpoint () => SBBreakpoint(%p) %s",
- static_cast<void *>(m_opaque_sp.get()),
- static_cast<void *>(sb_bp.get()), sstr.GetData());
+ LLDB_LOG(log, "location = {0}, breakpoint = {1} ({2})", loc_sp.get(),
+ sb_bp.GetSP().get(), sstr.GetData());
}
return sb_bp;
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBBroadcaster.cpp b/contrib/llvm/tools/lldb/source/API/SBBroadcaster.cpp
index 5189dd7..278576b 100644
--- a/contrib/llvm/tools/lldb/source/API/SBBroadcaster.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBBroadcaster.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBEvent.h"
@@ -22,25 +22,15 @@ SBBroadcaster::SBBroadcaster() : m_opaque_sp(), m_opaque_ptr(NULL) {}
SBBroadcaster::SBBroadcaster(const char *name)
: m_opaque_sp(new Broadcaster(NULL, name)), m_opaque_ptr(NULL) {
m_opaque_ptr = m_opaque_sp.get();
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API |
- LIBLLDB_LOG_VERBOSE));
-
- if (log)
- log->Printf(
- "SBBroadcaster::SBBroadcaster (name=\"%s\") => SBBroadcaster(%p)", name,
- static_cast<void *>(m_opaque_ptr));
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ LLDB_LOGV(log, "(name=\"{0}\") => SBBroadcaster({1})", name, m_opaque_ptr);
}
SBBroadcaster::SBBroadcaster(lldb_private::Broadcaster *broadcaster, bool owns)
: m_opaque_sp(owns ? broadcaster : NULL), m_opaque_ptr(broadcaster) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API |
- LIBLLDB_LOG_VERBOSE));
-
- if (log)
- log->Printf("SBBroadcaster::SBBroadcaster (broadcaster=%p, bool owns=%i) "
- "=> SBBroadcaster(%p)",
- static_cast<void *>(broadcaster), owns,
- static_cast<void *>(m_opaque_ptr));
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ LLDB_LOGV(log, "(broadcaster={0}, owns={1}) => SBBroadcaster({2})",
+ broadcaster, owns, m_opaque_ptr);
}
SBBroadcaster::SBBroadcaster(const SBBroadcaster &rhs)
diff --git a/contrib/llvm/tools/lldb/source/API/SBCommandReturnObject.cpp b/contrib/llvm/tools/lldb/source/API/SBCommandReturnObject.cpp
index 41d5147..5a8909b 100644
--- a/contrib/llvm/tools/lldb/source/API/SBCommandReturnObject.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBCommandReturnObject.cpp
@@ -15,9 +15,10 @@
#include "lldb/API/SBError.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -181,7 +182,7 @@ bool SBCommandReturnObject::GetDescription(SBStream &description) {
Stream &strm = description.ref();
if (m_opaque_ap) {
- description.Printf("Status: ");
+ description.Printf("Error: ");
lldb::ReturnStatus status = m_opaque_ap->GetStatus();
if (status == lldb::eReturnStatusStarted)
strm.PutCString("Started");
@@ -270,7 +271,7 @@ void SBCommandReturnObject::SetError(lldb::SBError &error,
if (error.IsValid())
m_opaque_ap->SetError(error.ref(), fallback_error_cstr);
else if (fallback_error_cstr)
- m_opaque_ap->SetError(Error(), fallback_error_cstr);
+ m_opaque_ap->SetError(Status(), fallback_error_cstr);
}
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBCommunication.cpp b/contrib/llvm/tools/lldb/source/API/SBCommunication.cpp
index 9519c02..63b672e 100644
--- a/contrib/llvm/tools/lldb/source/API/SBCommunication.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBCommunication.cpp
@@ -10,8 +10,9 @@
#include "lldb/API/SBCommunication.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/Core/Communication.h"
-#include "lldb/Core/Log.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -51,7 +52,7 @@ void SBCommunication::SetCloseOnEOF(bool b) {
ConnectionStatus SBCommunication::Connect(const char *url) {
if (m_opaque) {
if (!m_opaque->HasConnection())
- m_opaque->SetConnection(Connection::CreateDefaultConnection(url));
+ m_opaque->SetConnection(Host::CreateDefaultConnection(url).release());
return m_opaque->Connect(url, NULL);
}
return eConnectionStatusNoConnection;
diff --git a/contrib/llvm/tools/lldb/source/API/SBCompileUnit.cpp b/contrib/llvm/tools/lldb/source/API/SBCompileUnit.cpp
index 12aed59..149d587 100644
--- a/contrib/llvm/tools/lldb/source/API/SBCompileUnit.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBCompileUnit.cpp
@@ -10,13 +10,13 @@
#include "lldb/API/SBCompileUnit.h"
#include "lldb/API/SBLineEntry.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineEntry.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Type.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBData.cpp b/contrib/llvm/tools/lldb/source/API/SBData.cpp
index d905d3f..a8ba580 100644
--- a/contrib/llvm/tools/lldb/source/API/SBData.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBData.cpp
@@ -13,10 +13,11 @@
#include "lldb/API/SBError.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Core/DumpDataExtractor.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -347,7 +348,7 @@ bool SBData::GetDescription(lldb::SBStream &description,
Stream &strm = description.ref();
if (m_opaque_sp) {
- m_opaque_sp->Dump(&strm, 0, lldb::eFormatBytesWithASCII, 1,
+ DumpDataExtractor(*m_opaque_sp, &strm, 0, lldb::eFormatBytesWithASCII, 1,
m_opaque_sp->GetByteSize(), 16, base_addr, 0, 0);
} else
strm.PutCString("No value");
@@ -383,7 +384,11 @@ void SBData::SetData(lldb::SBError &error, const void *buf, size_t size,
if (!m_opaque_sp.get())
m_opaque_sp.reset(new DataExtractor(buf, size, endian, addr_size));
else
+ {
m_opaque_sp->SetData(buf, size, endian);
+ m_opaque_sp->SetAddressByteSize(addr_size);
+ }
+
if (log)
log->Printf("SBData::SetData (error=%p,buf=%p,size=%" PRIu64
",endian=%d,addr_size=%c) => "
diff --git a/contrib/llvm/tools/lldb/source/API/SBDebugger.cpp b/contrib/llvm/tools/lldb/source/API/SBDebugger.cpp
index 97e6f7b..3cdb6bb 100644
--- a/contrib/llvm/tools/lldb/source/API/SBDebugger.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBDebugger.cpp
@@ -57,7 +57,7 @@ using namespace lldb_private;
static llvm::sys::DynamicLibrary LoadPlugin(const lldb::DebuggerSP &debugger_sp,
const FileSpec &spec,
- Error &error) {
+ Status &error) {
llvm::sys::DynamicLibrary dynlib =
llvm::sys::DynamicLibrary::getPermanentLibrary(spec.GetPath().c_str());
if (dynlib.isValid()) {
@@ -551,7 +551,7 @@ SBDebugger::CreateTargetWithFileAndTargetTriple(const char *filename,
TargetSP target_sp;
if (m_opaque_sp) {
const bool add_dependent_modules = true;
- Error error(m_opaque_sp->GetTargetList().CreateTarget(
+ Status error(m_opaque_sp->GetTargetList().CreateTarget(
*m_opaque_sp, filename, target_triple, add_dependent_modules, nullptr,
target_sp));
sb_target.SetSP(target_sp);
@@ -574,7 +574,7 @@ SBTarget SBDebugger::CreateTargetWithFileAndArch(const char *filename,
SBTarget sb_target;
TargetSP target_sp;
if (m_opaque_sp) {
- Error error;
+ Status error;
const bool add_dependent_modules = true;
error = m_opaque_sp->GetTargetList().CreateTarget(
@@ -600,7 +600,7 @@ SBTarget SBDebugger::CreateTarget(const char *filename) {
SBTarget sb_target;
TargetSP target_sp;
if (m_opaque_sp) {
- Error error;
+ Status error;
const bool add_dependent_modules = true;
error = m_opaque_sp->GetTargetList().CreateTarget(
*m_opaque_sp, filename, "", add_dependent_modules, nullptr, target_sp);
@@ -873,7 +873,7 @@ SBError SBDebugger::SetInternalVariable(const char *var_name, const char *value,
SBError sb_error;
DebuggerSP debugger_sp(Debugger::FindDebuggerWithInstanceName(
ConstString(debugger_instance_name)));
- Error error;
+ Status error;
if (debugger_sp) {
ExecutionContext exe_ctx(
debugger_sp->GetCommandInterpreter().GetExecutionContext());
@@ -894,7 +894,7 @@ SBDebugger::GetInternalVariableValue(const char *var_name,
SBStringList ret_value;
DebuggerSP debugger_sp(Debugger::FindDebuggerWithInstanceName(
ConstString(debugger_instance_name)));
- Error error;
+ Status error;
if (debugger_sp) {
ExecutionContext exe_ctx(
debugger_sp->GetCommandInterpreter().GetExecutionContext());
@@ -1120,13 +1120,23 @@ SBTypeSynthetic SBDebugger::GetSyntheticForType(SBTypeNameSpecifier type_name) {
}
#endif // LLDB_DISABLE_PYTHON
+static llvm::ArrayRef<const char *> GetCategoryArray(const char **categories) {
+ if (categories == nullptr)
+ return {};
+ size_t len = 0;
+ while (categories[len] != nullptr)
+ ++len;
+ return llvm::makeArrayRef(categories, len);
+}
+
bool SBDebugger::EnableLog(const char *channel, const char **categories) {
if (m_opaque_sp) {
uint32_t log_options =
LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
- StreamString errors;
- return m_opaque_sp->EnableLog(channel, categories, nullptr, log_options,
- errors);
+ std::string error;
+ llvm::raw_string_ostream error_stream(error);
+ return m_opaque_sp->EnableLog(channel, GetCategoryArray(categories), "",
+ log_options, error_stream);
} else
return false;
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBDeclaration.cpp b/contrib/llvm/tools/lldb/source/API/SBDeclaration.cpp
index fc21f83..d6e61e3 100644
--- a/contrib/llvm/tools/lldb/source/API/SBDeclaration.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBDeclaration.cpp
@@ -1,5 +1,4 @@
-//===-- SBDeclaration.cpp -----------------------------------------*- C++
-//-*-===//
+//===-- SBDeclaration.cpp ----------------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,9 +9,10 @@
#include "lldb/API/SBDeclaration.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Host/PosixApi.h"
#include "lldb/Symbol/Declaration.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
#include <limits.h>
diff --git a/contrib/llvm/tools/lldb/source/API/SBError.cpp b/contrib/llvm/tools/lldb/source/API/SBError.cpp
index 451c0a7..b2811d0 100644
--- a/contrib/llvm/tools/lldb/source/API/SBError.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBError.cpp
@@ -9,8 +9,8 @@
#include "lldb/API/SBError.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include <stdarg.h>
@@ -21,7 +21,7 @@ SBError::SBError() : m_opaque_ap() {}
SBError::SBError(const SBError &rhs) : m_opaque_ap() {
if (rhs.IsValid())
- m_opaque_ap.reset(new Error(*rhs));
+ m_opaque_ap.reset(new Status(*rhs));
}
SBError::~SBError() {}
@@ -31,7 +31,7 @@ const SBError &SBError::operator=(const SBError &rhs) {
if (m_opaque_ap.get())
*m_opaque_ap = *rhs;
else
- m_opaque_ap.reset(new Error(*rhs));
+ m_opaque_ap.reset(new Status(*rhs));
} else
m_opaque_ap.reset();
@@ -108,7 +108,7 @@ void SBError::SetError(uint32_t err, ErrorType type) {
m_opaque_ap->SetError(err, type);
}
-void SBError::SetError(const Error &lldb_error) {
+void SBError::SetError(const Status &lldb_error) {
CreateIfNeeded();
*m_opaque_ap = lldb_error;
}
@@ -141,19 +141,19 @@ bool SBError::IsValid() const { return m_opaque_ap.get() != NULL; }
void SBError::CreateIfNeeded() {
if (m_opaque_ap.get() == NULL)
- m_opaque_ap.reset(new Error());
+ m_opaque_ap.reset(new Status());
}
-lldb_private::Error *SBError::operator->() { return m_opaque_ap.get(); }
+lldb_private::Status *SBError::operator->() { return m_opaque_ap.get(); }
-lldb_private::Error *SBError::get() { return m_opaque_ap.get(); }
+lldb_private::Status *SBError::get() { return m_opaque_ap.get(); }
-lldb_private::Error &SBError::ref() {
+lldb_private::Status &SBError::ref() {
CreateIfNeeded();
return *m_opaque_ap;
}
-const lldb_private::Error &SBError::operator*() const {
+const lldb_private::Status &SBError::operator*() const {
// Be sure to call "IsValid()" before calling this function or it will crash
return *m_opaque_ap;
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBEvent.cpp b/contrib/llvm/tools/lldb/source/API/SBEvent.cpp
index e0bb68c..17a16ff 100644
--- a/contrib/llvm/tools/lldb/source/API/SBEvent.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBEvent.cpp
@@ -12,12 +12,12 @@
#include "lldb/API/SBStream.h"
#include "lldb/Breakpoint/Breakpoint.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -109,13 +109,9 @@ bool SBEvent::BroadcasterMatchesRef(const SBBroadcaster &broadcaster) {
// For logging, this gets a little chatty so only enable this when verbose
// logging is on
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API |
- LIBLLDB_LOG_VERBOSE));
- if (log)
- log->Printf(
- "SBEvent(%p)::BroadcasterMatchesRef (SBBroadcaster(%p): %s) => %i",
- static_cast<void *>(get()), static_cast<void *>(broadcaster.get()),
- broadcaster.GetName(), success);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ LLDB_LOGV(log, "({0}) (SBBroadcaster({1}): {2}) => {3}", get(),
+ broadcaster.get(), broadcaster.GetName(), success);
return success;
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBFileSpec.cpp b/contrib/llvm/tools/lldb/source/API/SBFileSpec.cpp
index 88baf3b..011b882 100644
--- a/contrib/llvm/tools/lldb/source/API/SBFileSpec.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBFileSpec.cpp
@@ -12,9 +12,10 @@
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
#include "llvm/ADT/SmallString.h"
diff --git a/contrib/llvm/tools/lldb/source/API/SBFileSpecList.cpp b/contrib/llvm/tools/lldb/source/API/SBFileSpecList.cpp
index 8ed3f6f..67d28dc 100644
--- a/contrib/llvm/tools/lldb/source/API/SBFileSpecList.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBFileSpecList.cpp
@@ -13,9 +13,10 @@
#include "lldb/API/SBFileSpecList.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/FileSpecList.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBFrame.cpp b/contrib/llvm/tools/lldb/source/API/SBFrame.cpp
index 8d8cb48..684a707 100644
--- a/contrib/llvm/tools/lldb/source/API/SBFrame.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBFrame.cpp
@@ -21,9 +21,6 @@
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObjectRegister.h"
#include "lldb/Core/ValueObjectVariable.h"
@@ -42,6 +39,9 @@
#include "lldb/Target/StackID.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/API/SBAddress.h"
#include "lldb/API/SBDebugger.h"
@@ -606,7 +606,7 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path,
frame = exe_ctx.GetFramePtr();
if (frame) {
VariableSP var_sp;
- Error error;
+ Status error;
ValueObjectSP value_sp(frame->GetValueForVariableExpressionPath(
var_path, eNoDynamicValues,
StackFrame::eExpressionPathOptionCheckPtrVsMember |
@@ -1370,6 +1370,25 @@ const char *SBFrame::GetFunctionName() {
return static_cast<const SBFrame *>(this)->GetFunctionName();
}
+lldb::LanguageType SBFrame::GuessLanguage() const {
+ std::unique_lock<std::recursive_mutex> lock;
+ ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+
+ StackFrame *frame = nullptr;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process) {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock())) {
+ frame = exe_ctx.GetFramePtr();
+ if (frame) {
+ return frame->GuessLanguage();
+ }
+ }
+ }
+ return eLanguageTypeUnknown;
+}
+
const char *SBFrame::GetFunctionName() const {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
const char *name = nullptr;
diff --git a/contrib/llvm/tools/lldb/source/API/SBFunction.cpp b/contrib/llvm/tools/lldb/source/API/SBFunction.cpp
index 9065cc3..6a24f64 100644
--- a/contrib/llvm/tools/lldb/source/API/SBFunction.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBFunction.cpp
@@ -11,7 +11,6 @@
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
@@ -19,6 +18,7 @@
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBHostOS.cpp b/contrib/llvm/tools/lldb/source/API/SBHostOS.cpp
index 8df74d9..90b75a6 100644
--- a/contrib/llvm/tools/lldb/source/API/SBHostOS.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBHostOS.cpp
@@ -9,13 +9,13 @@
#include "lldb/API/SBHostOS.h"
#include "lldb/API/SBError.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/HostNativeThread.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
@@ -80,7 +80,7 @@ lldb::thread_t SBHostOS::ThreadCreate(const char *name,
void SBHostOS::ThreadCreated(const char *name) {}
bool SBHostOS::ThreadCancel(lldb::thread_t thread, SBError *error_ptr) {
- Error error;
+ Status error;
HostThread host_thread(thread);
error = host_thread.Cancel();
if (error_ptr)
@@ -90,7 +90,7 @@ bool SBHostOS::ThreadCancel(lldb::thread_t thread, SBError *error_ptr) {
}
bool SBHostOS::ThreadDetach(lldb::thread_t thread, SBError *error_ptr) {
- Error error;
+ Status error;
#if defined(_WIN32)
if (error_ptr)
error_ptr->SetErrorString("ThreadDetach is not supported on this platform");
@@ -106,7 +106,7 @@ bool SBHostOS::ThreadDetach(lldb::thread_t thread, SBError *error_ptr) {
bool SBHostOS::ThreadJoin(lldb::thread_t thread, lldb::thread_result_t *result,
SBError *error_ptr) {
- Error error;
+ Status error;
HostThread host_thread(thread);
error = host_thread.Join(result);
if (error_ptr)
diff --git a/contrib/llvm/tools/lldb/source/API/SBInstruction.cpp b/contrib/llvm/tools/lldb/source/API/SBInstruction.cpp
index 8c616da..8b7deb7 100644
--- a/contrib/llvm/tools/lldb/source/API/SBInstruction.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBInstruction.cpp
@@ -16,8 +16,6 @@
#include "lldb/API/SBTarget.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/EmulateInstruction.h"
#include "lldb/Core/Module.h"
@@ -25,6 +23,8 @@
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
//----------------------------------------------------------------------
// We recently fixed a leak in one of the Instruction subclasses where
@@ -176,6 +176,13 @@ bool SBInstruction::HasDelaySlot() {
return false;
}
+bool SBInstruction::CanSetBreakpoint () {
+ lldb::InstructionSP inst_sp(GetOpaque());
+ if (inst_sp)
+ return inst_sp->CanSetBreakpoint();
+ return false;
+}
+
lldb::InstructionSP SBInstruction::GetOpaque() {
if (m_opaque_sp)
return m_opaque_sp->GetSP();
diff --git a/contrib/llvm/tools/lldb/source/API/SBInstructionList.cpp b/contrib/llvm/tools/lldb/source/API/SBInstructionList.cpp
index 8ab3aca..3edb9ea 100644
--- a/contrib/llvm/tools/lldb/source/API/SBInstructionList.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBInstructionList.cpp
@@ -9,11 +9,12 @@
#include "lldb/API/SBInstructionList.h"
#include "lldb/API/SBInstruction.h"
+#include "lldb/API/SBAddress.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -49,6 +50,31 @@ SBInstruction SBInstructionList::GetInstructionAtIndex(uint32_t idx) {
return inst;
}
+size_t SBInstructionList::GetInstructionsCount(const SBAddress &start,
+ const SBAddress &end,
+ bool canSetBreakpoint) {
+ size_t num_instructions = GetSize();
+ size_t i = 0;
+ SBAddress addr;
+ size_t lower_index = 0;
+ size_t upper_index = 0;
+ size_t instructions_to_skip = 0;
+ for (i = 0; i < num_instructions; ++i) {
+ addr = GetInstructionAtIndex(i).GetAddress();
+ if (start == addr)
+ lower_index = i;
+ if (end == addr)
+ upper_index = i;
+ }
+ if (canSetBreakpoint)
+ for (i = lower_index; i <= upper_index; ++i) {
+ SBInstruction insn = GetInstructionAtIndex(i);
+ if (!insn.CanSetBreakpoint())
+ ++instructions_to_skip;
+ }
+ return upper_index - lower_index - instructions_to_skip;
+}
+
void SBInstructionList::Clear() { m_opaque_sp.reset(); }
void SBInstructionList::AppendInstruction(SBInstruction insn) {}
diff --git a/contrib/llvm/tools/lldb/source/API/SBLineEntry.cpp b/contrib/llvm/tools/lldb/source/API/SBLineEntry.cpp
index 3469cec..7341d36 100644
--- a/contrib/llvm/tools/lldb/source/API/SBLineEntry.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBLineEntry.cpp
@@ -11,9 +11,10 @@
#include "lldb/API/SBLineEntry.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Host/PosixApi.h"
#include "lldb/Symbol/LineEntry.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBListener.cpp b/contrib/llvm/tools/lldb/source/API/SBListener.cpp
index 501535a..50fed4e 100644
--- a/contrib/llvm/tools/lldb/source/API/SBListener.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBListener.cpp
@@ -15,8 +15,8 @@
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Listener.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -302,6 +302,8 @@ bool SBListener::HandleBroadcastEvent(const SBEvent &event) {
return false;
}
+lldb::ListenerSP SBListener::GetSP() { return m_opaque_sp; }
+
Listener *SBListener::operator->() const { return m_opaque_sp.get(); }
Listener *SBListener::get() const { return m_opaque_sp.get(); }
diff --git a/contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfo.cpp b/contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfo.cpp
index 3e72276..c4dbaec 100644
--- a/contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfo.cpp
@@ -11,8 +11,8 @@
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBError.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfoList.cpp b/contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfoList.cpp
index f7ce81a..fff4044 100644
--- a/contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfoList.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBMemoryRegionInfoList.cpp
@@ -7,11 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/API/SBMemoryRegionInfo.h"
#include "lldb/API/SBMemoryRegionInfoList.h"
+#include "lldb/API/SBMemoryRegionInfo.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/Log.h"
#include <vector>
diff --git a/contrib/llvm/tools/lldb/source/API/SBModule.cpp b/contrib/llvm/tools/lldb/source/API/SBModule.cpp
index 8964303..17f3dcc 100644
--- a/contrib/llvm/tools/lldb/source/API/SBModule.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBModule.cpp
@@ -14,10 +14,8 @@
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBSymbolContextList.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Symbol/ObjectFile.h"
@@ -27,6 +25,8 @@
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -37,8 +37,8 @@ SBModule::SBModule(const lldb::ModuleSP &module_sp) : m_opaque_sp(module_sp) {}
SBModule::SBModule(const SBModuleSpec &module_spec) : m_opaque_sp() {
ModuleSP module_sp;
- Error error = ModuleList::GetSharedModule(*module_spec.m_opaque_ap, module_sp,
- NULL, NULL, NULL);
+ Status error = ModuleList::GetSharedModule(*module_spec.m_opaque_ap,
+ module_sp, NULL, NULL, NULL);
if (module_sp)
SetSP(module_sp);
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBModuleSpec.cpp b/contrib/llvm/tools/lldb/source/API/SBModuleSpec.cpp
index b82b822..a1c0886 100644
--- a/contrib/llvm/tools/lldb/source/API/SBModuleSpec.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBModuleSpec.cpp
@@ -11,9 +11,9 @@
#include "lldb/API/SBStream.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBPlatform.cpp b/contrib/llvm/tools/lldb/source/API/SBPlatform.cpp
index 6085cef..87cbc45 100644
--- a/contrib/llvm/tools/lldb/source/API/SBPlatform.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBPlatform.cpp
@@ -13,11 +13,13 @@
#include "lldb/API/SBLaunchInfo.h"
#include "lldb/API/SBUnixSignals.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Error.h"
#include "lldb/Host/File.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Status.h"
+
+#include "llvm/Support/FileSystem.h"
#include <functional>
@@ -203,7 +205,7 @@ const char *SBPlatformShellCommand::GetOutput() {
SBPlatform::SBPlatform() : m_opaque_sp() {}
SBPlatform::SBPlatform(const char *platform_name) : m_opaque_sp() {
- Error error;
+ Status error;
if (platform_name && platform_name[0])
m_opaque_sp = Platform::Create(ConstString(platform_name), error);
}
@@ -363,7 +365,7 @@ SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) {
if (src.Exists()) {
uint32_t permissions = src.ref().GetPermissions();
if (permissions == 0) {
- if (src.ref().GetFileType() == FileSpec::eFileTypeDirectory)
+ if (llvm::sys::fs::is_directory(src.ref().GetPath()))
permissions = eFilePermissionsDirectoryDefault;
else
permissions = eFilePermissionsFileDefault;
@@ -372,7 +374,7 @@ SBError SBPlatform::Put(SBFileSpec &src, SBFileSpec &dst) {
return platform_sp->PutFile(src.ref(), dst.ref(), permissions);
}
- Error error;
+ Status error;
error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
src.ref().GetPath().c_str());
return error;
@@ -384,7 +386,7 @@ SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) {
if (src.Exists())
return platform_sp->Install(src.ref(), dst.ref());
- Error error;
+ Status error;
error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'",
src.ref().GetPath().c_str());
return error;
@@ -395,7 +397,7 @@ SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
const char *command = shell_command.GetCommand();
if (!command)
- return Error("invalid shell command (empty)");
+ return Status("invalid shell command (empty)");
const char *working_dir = shell_command.GetWorkingDirectory();
if (working_dir == NULL) {
@@ -425,7 +427,7 @@ SBError SBPlatform::Kill(const lldb::pid_t pid) {
}
SBError SBPlatform::ExecuteConnected(
- const std::function<Error(const lldb::PlatformSP &)> &func) {
+ const std::function<Status(const lldb::PlatformSP &)> &func) {
SBError sb_error;
const auto platform_sp(GetSP());
if (platform_sp) {
diff --git a/contrib/llvm/tools/lldb/source/API/SBProcess.cpp b/contrib/llvm/tools/lldb/source/API/SBProcess.cpp
index 59dd569..caf07db 100644
--- a/contrib/llvm/tools/lldb/source/API/SBProcess.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBProcess.cpp
@@ -16,11 +16,9 @@
#include "lldb/lldb-types.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Target/MemoryRegionInfo.h"
@@ -29,6 +27,8 @@
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
// Project includes
@@ -44,6 +44,8 @@
#include "lldb/API/SBStructuredData.h"
#include "lldb/API/SBThread.h"
#include "lldb/API/SBThreadCollection.h"
+#include "lldb/API/SBTrace.h"
+#include "lldb/API/SBTraceOptions.h"
#include "lldb/API/SBUnixSignals.h"
using namespace lldb;
@@ -279,7 +281,7 @@ size_t SBProcess::PutSTDIN(const char *src, size_t src_len) {
size_t ret_val = 0;
ProcessSP process_sp(GetSP());
if (process_sp) {
- Error error;
+ Status error;
ret_val = process_sp->PutSTDIN(src, src_len, error);
}
@@ -296,7 +298,7 @@ size_t SBProcess::GetSTDOUT(char *dst, size_t dst_len) const {
size_t bytes_read = 0;
ProcessSP process_sp(GetSP());
if (process_sp) {
- Error error;
+ Status error;
bytes_read = process_sp->GetSTDOUT(dst, dst_len, error);
}
@@ -315,7 +317,7 @@ size_t SBProcess::GetSTDERR(char *dst, size_t dst_len) const {
size_t bytes_read = 0;
ProcessSP process_sp(GetSP());
if (process_sp) {
- Error error;
+ Status error;
bytes_read = process_sp->GetSTDERR(dst, dst_len, error);
}
@@ -334,7 +336,7 @@ size_t SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const {
size_t bytes_read = 0;
ProcessSP process_sp(GetSP());
if (process_sp) {
- Error error;
+ Status error;
bytes_read = process_sp->GetAsyncProfileData(dst, dst_len, error);
}
@@ -349,6 +351,25 @@ size_t SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const {
return bytes_read;
}
+lldb::SBTrace SBProcess::StartTrace(SBTraceOptions &options,
+ lldb::SBError &error) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ ProcessSP process_sp(GetSP());
+ error.Clear();
+ SBTrace trace_instance;
+ trace_instance.SetSP(process_sp);
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+
+ if (!process_sp) {
+ error.SetErrorString("invalid process");
+ } else {
+ uid = process_sp->StartTrace(*(options.m_traceoptions_sp), error.ref());
+ trace_instance.SetTraceUID(uid);
+ LLDB_LOG(log, "SBProcess::returned uid - {0}", uid);
+ }
+ return trace_instance;
+}
+
void SBProcess::ReportEventState(const SBEvent &event, FILE *out) const {
if (out == NULL)
return;
@@ -1135,22 +1156,34 @@ uint32_t SBProcess::LoadImage(lldb::SBFileSpec &sb_remote_image_spec,
uint32_t SBProcess::LoadImage(const lldb::SBFileSpec &sb_local_image_spec,
const lldb::SBFileSpec &sb_remote_image_spec,
lldb::SBError &sb_error) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
ProcessSP process_sp(GetSP());
if (process_sp) {
Process::StopLocker stop_locker;
if (stop_locker.TryLock(&process_sp->GetRunLock())) {
+ if (log)
+ log->Printf("SBProcess(%p)::LoadImage() => calling Platform::LoadImage"
+ "for: %s",
+ static_cast<void *>(process_sp.get()),
+ sb_local_image_spec.GetFilename());
+
std::lock_guard<std::recursive_mutex> guard(
- process_sp->GetTarget().GetAPIMutex());
+ process_sp->GetTarget().GetAPIMutex());
PlatformSP platform_sp = process_sp->GetTarget().GetPlatform();
return platform_sp->LoadImage(process_sp.get(), *sb_local_image_spec,
*sb_remote_image_spec, sb_error.ref());
} else {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
if (log)
log->Printf("SBProcess(%p)::LoadImage() => error: process is running",
static_cast<void *>(process_sp.get()));
sb_error.SetErrorString("process is running");
}
+ } else {
+ if (log)
+ log->Printf("SBProcess(%p)::LoadImage() => error: called with invalid"
+ " process",
+ static_cast<void *>(process_sp.get()));
+ sb_error.SetErrorString("process is invalid");
}
return LLDB_INVALID_IMAGE_TOKEN;
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBQueue.cpp b/contrib/llvm/tools/lldb/source/API/SBQueue.cpp
index c6f5305..5f85211 100644
--- a/contrib/llvm/tools/lldb/source/API/SBQueue.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBQueue.cpp
@@ -15,11 +15,11 @@
#include "lldb/API/SBQueueItem.h"
#include "lldb/API/SBThread.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Queue.h"
#include "lldb/Target/QueueItem.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBQueueItem.cpp b/contrib/llvm/tools/lldb/source/API/SBQueueItem.cpp
index 2e06bc8..87ba73f9 100644
--- a/contrib/llvm/tools/lldb/source/API/SBQueueItem.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBQueueItem.cpp
@@ -13,10 +13,10 @@
#include "lldb/API/SBQueueItem.h"
#include "lldb/API/SBThread.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/QueueItem.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBSection.cpp b/contrib/llvm/tools/lldb/source/API/SBSection.cpp
index 8124fe9..9da5d17 100644
--- a/contrib/llvm/tools/lldb/source/API/SBSection.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBSection.cpp
@@ -10,13 +10,14 @@
#include "lldb/API/SBSection.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBTarget.h"
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferLLVM.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -165,8 +166,8 @@ SBData SBSection::GetSectionData(uint64_t offset, uint64_t size) {
else
file_size = 0;
}
- DataBufferSP data_buffer_sp(
- objfile->GetFileSpec().ReadFileContents(file_offset, file_size));
+ auto data_buffer_sp = DataBufferLLVM::CreateSliceFromPath(
+ objfile->GetFileSpec().GetPath(), file_size, file_offset);
if (data_buffer_sp && data_buffer_sp->GetByteSize() > 0) {
DataExtractorSP data_extractor_sp(
new DataExtractor(data_buffer_sp, objfile->GetByteOrder(),
diff --git a/contrib/llvm/tools/lldb/source/API/SBSourceManager.cpp b/contrib/llvm/tools/lldb/source/API/SBSourceManager.cpp
index ecf532c..5804c22 100644
--- a/contrib/llvm/tools/lldb/source/API/SBSourceManager.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBSourceManager.cpp
@@ -15,8 +15,8 @@
#include "lldb/API/SBFileSpec.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/SourceManager.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/Target/Target.h"
diff --git a/contrib/llvm/tools/lldb/source/API/SBStream.cpp b/contrib/llvm/tools/lldb/source/API/SBStream.cpp
index 858e949..159ec07 100644
--- a/contrib/llvm/tools/lldb/source/API/SBStream.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBStream.cpp
@@ -9,10 +9,10 @@
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBStringList.cpp b/contrib/llvm/tools/lldb/source/API/SBStringList.cpp
index 075ee0d..9ac69b1 100644
--- a/contrib/llvm/tools/lldb/source/API/SBStringList.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBStringList.cpp
@@ -9,7 +9,7 @@
#include "lldb/API/SBStringList.h"
-#include "lldb/Core/StringList.h"
+#include "lldb/Utility/StringList.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBStructuredData.cpp b/contrib/llvm/tools/lldb/source/API/SBStructuredData.cpp
index d9ea072..d506410 100644
--- a/contrib/llvm/tools/lldb/source/API/SBStructuredData.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBStructuredData.cpp
@@ -10,80 +10,17 @@
#include "lldb/API/SBStructuredData.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Target/StructuredDataPlugin.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
#pragma mark--
-#pragma mark StructuredDataImpl
-
-class StructuredDataImpl {
-public:
- StructuredDataImpl() : m_plugin_wp(), m_data_sp() {}
-
- StructuredDataImpl(const StructuredDataImpl &rhs) = default;
-
- StructuredDataImpl(const EventSP &event_sp)
- : m_plugin_wp(
- EventDataStructuredData::GetPluginFromEvent(event_sp.get())),
- m_data_sp(EventDataStructuredData::GetObjectFromEvent(event_sp.get())) {
- }
-
- ~StructuredDataImpl() = default;
-
- StructuredDataImpl &operator=(const StructuredDataImpl &rhs) = default;
-
- bool IsValid() const { return m_data_sp.get() != nullptr; }
-
- void Clear() {
- m_plugin_wp.reset();
- m_data_sp.reset();
- }
-
- SBError GetAsJSON(lldb_private::Stream &stream) const {
- SBError sb_error;
-
- if (!m_data_sp) {
- sb_error.SetErrorString("No structured data.");
- return sb_error;
- }
-
- m_data_sp->Dump(stream);
- return sb_error;
- }
-
- Error GetDescription(lldb_private::Stream &stream) const {
- Error error;
-
- if (!m_data_sp) {
- error.SetErrorString("Cannot pretty print structured data: "
- "no data to print.");
- return error;
- }
-
- // Grab the plugin.
- auto plugin_sp = StructuredDataPluginSP(m_plugin_wp);
- if (!plugin_sp) {
- error.SetErrorString("Cannot pretty print structured data: "
- "plugin doesn't exist.");
- return error;
- }
-
- // Get the data's description.
- return plugin_sp->GetDescription(m_data_sp, stream);
- }
-
-private:
- StructuredDataPluginWP m_plugin_wp;
- StructuredData::ObjectSP m_data_sp;
-};
-
-#pragma mark--
#pragma mark SBStructuredData
SBStructuredData::SBStructuredData() : m_impl_up(new StructuredDataImpl()) {}
@@ -102,17 +39,73 @@ operator=(const lldb::SBStructuredData &rhs) {
return *this;
}
+lldb::SBError SBStructuredData::SetFromJSON(lldb::SBStream &stream) {
+ lldb::SBError error;
+ std::string json_str(stream.GetData());
+
+ StructuredData::ObjectSP json_obj = StructuredData::ParseJSON(json_str);
+ m_impl_up->SetObjectSP(json_obj);
+
+ if (!json_obj || json_obj->GetType() != eStructuredDataTypeDictionary)
+ error.SetErrorString("Invalid Syntax");
+ return error;
+}
+
bool SBStructuredData::IsValid() const { return m_impl_up->IsValid(); }
void SBStructuredData::Clear() { m_impl_up->Clear(); }
SBError SBStructuredData::GetAsJSON(lldb::SBStream &stream) const {
- return m_impl_up->GetAsJSON(stream.ref());
+ SBError error;
+ error.SetError(m_impl_up->GetAsJSON(stream.ref()));
+ return error;
}
lldb::SBError SBStructuredData::GetDescription(lldb::SBStream &stream) const {
- Error error = m_impl_up->GetDescription(stream.ref());
+ Status error = m_impl_up->GetDescription(stream.ref());
SBError sb_error;
sb_error.SetError(error);
return sb_error;
}
+
+StructuredDataType SBStructuredData::GetType() const {
+ return (m_impl_up ? m_impl_up->GetType() : eStructuredDataTypeInvalid);
+}
+
+size_t SBStructuredData::GetSize() const {
+ return (m_impl_up ? m_impl_up->GetSize() : 0);
+}
+
+lldb::SBStructuredData SBStructuredData::GetValueForKey(const char *key) const {
+ if (!m_impl_up)
+ return SBStructuredData();
+
+ SBStructuredData result;
+ result.m_impl_up->SetObjectSP(m_impl_up->GetValueForKey(key));
+ return result;
+}
+
+lldb::SBStructuredData SBStructuredData::GetItemAtIndex(size_t idx) const {
+ if (!m_impl_up)
+ return SBStructuredData();
+
+ SBStructuredData result;
+ result.m_impl_up->SetObjectSP(m_impl_up->GetItemAtIndex(idx));
+ return result;
+}
+
+uint64_t SBStructuredData::GetIntegerValue(uint64_t fail_value) const {
+ return (m_impl_up ? m_impl_up->GetIntegerValue(fail_value) : fail_value);
+}
+
+double SBStructuredData::GetFloatValue(double fail_value) const {
+ return (m_impl_up ? m_impl_up->GetFloatValue(fail_value) : fail_value);
+}
+
+bool SBStructuredData::GetBooleanValue(bool fail_value) const {
+ return (m_impl_up ? m_impl_up->GetBooleanValue(fail_value) : fail_value);
+}
+
+size_t SBStructuredData::GetStringValue(char *dst, size_t dst_len) const {
+ return (m_impl_up ? m_impl_up->GetStringValue(dst, dst_len) : 0);
+}
diff --git a/contrib/llvm/tools/lldb/source/API/SBSymbol.cpp b/contrib/llvm/tools/lldb/source/API/SBSymbol.cpp
index a4cc525..5be20a1 100644
--- a/contrib/llvm/tools/lldb/source/API/SBSymbol.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBSymbol.cpp
@@ -10,11 +10,11 @@
#include "lldb/API/SBSymbol.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBSymbolContext.cpp b/contrib/llvm/tools/lldb/source/API/SBSymbolContext.cpp
index 4748836..45dfffd 100644
--- a/contrib/llvm/tools/lldb/source/API/SBSymbolContext.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBSymbolContext.cpp
@@ -9,11 +9,11 @@
#include "lldb/API/SBSymbolContext.h"
#include "lldb/API/SBStream.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBTarget.cpp b/contrib/llvm/tools/lldb/source/API/SBTarget.cpp
index c000bf9..c706344 100644
--- a/contrib/llvm/tools/lldb/source/API/SBTarget.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBTarget.cpp
@@ -34,17 +34,14 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/STLUtils.h"
#include "lldb/Core/SearchFilter.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Core/ValueObjectVariable.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Symbol/ClangASTContext.h"
@@ -61,6 +58,9 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
#include "../source/Commands/CommandObjectBreakpoint.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -74,7 +74,7 @@ using namespace lldb_private;
namespace {
-Error AttachToProcess(ProcessAttachInfo &attach_info, Target &target) {
+Status AttachToProcess(ProcessAttachInfo &attach_info, Target &target) {
std::lock_guard<std::recursive_mutex> guard(target.GetAPIMutex());
auto process_sp = target.GetProcessSP();
@@ -85,8 +85,8 @@ Error AttachToProcess(ProcessAttachInfo &attach_info, Target &target) {
// listener, so if a valid listener is supplied, we need to error out
// to let the client know.
if (attach_info.GetListener())
- return Error("process is connected and already has a listener, pass "
- "empty listener");
+ return Status("process is connected and already has a listener, pass "
+ "empty listener");
}
}
@@ -686,7 +686,7 @@ SBTarget::BreakpointCreateByLocation(const SBFileSpec &sb_file_spec,
if (sb_module_list.GetSize() > 0) {
module_list = sb_module_list.get();
}
- *sb_bp = target_sp->CreateBreakpoint(
+ sb_bp = target_sp->CreateBreakpoint(
module_list, *sb_file_spec, line, offset, check_inlines, skip_prologue,
internal, hardware, move_to_nearest_code);
}
@@ -699,7 +699,7 @@ SBTarget::BreakpointCreateByLocation(const SBFileSpec &sb_file_spec,
log->Printf("SBTarget(%p)::BreakpointCreateByLocation ( %s:%u ) => "
"SBBreakpoint(%p): %s",
static_cast<void *>(target_sp.get()), path, line,
- static_cast<void *>(sb_bp.get()), sstr.GetData());
+ static_cast<void *>(sb_bp.GetSP().get()), sstr.GetData());
}
return sb_bp;
@@ -721,11 +721,11 @@ SBBreakpoint SBTarget::BreakpointCreateByName(const char *symbol_name,
if (module_name && module_name[0]) {
FileSpecList module_spec_list;
module_spec_list.Append(FileSpec(module_name, false));
- *sb_bp = target_sp->CreateBreakpoint(
+ sb_bp = target_sp->CreateBreakpoint(
&module_spec_list, NULL, symbol_name, eFunctionNameTypeAuto,
eLanguageTypeUnknown, offset, skip_prologue, internal, hardware);
} else {
- *sb_bp = target_sp->CreateBreakpoint(
+ sb_bp = target_sp->CreateBreakpoint(
NULL, NULL, symbol_name, eFunctionNameTypeAuto, eLanguageTypeUnknown,
offset, skip_prologue, internal, hardware);
}
@@ -735,7 +735,7 @@ SBBreakpoint SBTarget::BreakpointCreateByName(const char *symbol_name,
log->Printf("SBTarget(%p)::BreakpointCreateByName (symbol=\"%s\", "
"module=\"%s\") => SBBreakpoint(%p)",
static_cast<void *>(target_sp.get()), symbol_name, module_name,
- static_cast<void *>(sb_bp.get()));
+ static_cast<void *>(sb_bp.GetSP().get()));
return sb_bp;
}
@@ -771,7 +771,7 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByName(
const bool hardware = false;
const LazyBool skip_prologue = eLazyBoolCalculate;
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
- *sb_bp = target_sp->CreateBreakpoint(
+ sb_bp = target_sp->CreateBreakpoint(
module_list.get(), comp_unit_list.get(), symbol_name, name_type_mask,
symbol_language, 0, skip_prologue, internal, hardware);
}
@@ -780,7 +780,7 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByName(
log->Printf("SBTarget(%p)::BreakpointCreateByName (symbol=\"%s\", "
"name_type: %d) => SBBreakpoint(%p)",
static_cast<void *>(target_sp.get()), symbol_name,
- name_type_mask, static_cast<void *>(sb_bp.get()));
+ name_type_mask, static_cast<void *>(sb_bp.GetSP().get()));
return sb_bp;
}
@@ -815,7 +815,7 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByNames(
const bool internal = false;
const bool hardware = false;
const LazyBool skip_prologue = eLazyBoolCalculate;
- *sb_bp = target_sp->CreateBreakpoint(
+ sb_bp = target_sp->CreateBreakpoint(
module_list.get(), comp_unit_list.get(), symbol_names, num_names,
name_type_mask, symbol_language, offset, skip_prologue, internal,
hardware);
@@ -836,7 +836,7 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByNames(
log->Printf("\"<NULL>\"%c ", sep);
}
log->Printf("name_type: %d) => SBBreakpoint(%p)", name_type_mask,
- static_cast<void *>(sb_bp.get()));
+ static_cast<void *>(sb_bp.GetSP().get()));
}
return sb_bp;
@@ -875,7 +875,7 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByRegex(
const bool hardware = false;
const LazyBool skip_prologue = eLazyBoolCalculate;
- *sb_bp = target_sp->CreateFuncRegexBreakpoint(
+ sb_bp = target_sp->CreateFuncRegexBreakpoint(
module_list.get(), comp_unit_list.get(), regexp, symbol_language,
skip_prologue, internal, hardware);
}
@@ -884,7 +884,7 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByRegex(
log->Printf("SBTarget(%p)::BreakpointCreateByRegex (symbol_regex=\"%s\") "
"=> SBBreakpoint(%p)",
static_cast<void *>(target_sp.get()), symbol_name_regex,
- static_cast<void *>(sb_bp.get()));
+ static_cast<void *>(sb_bp.GetSP().get()));
return sb_bp;
}
@@ -897,7 +897,7 @@ SBBreakpoint SBTarget::BreakpointCreateByAddress(addr_t address) {
if (target_sp) {
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
const bool hardware = false;
- *sb_bp = target_sp->CreateBreakpoint(address, false, hardware);
+ sb_bp = target_sp->CreateBreakpoint(address, false, hardware);
}
if (log)
@@ -905,7 +905,7 @@ SBBreakpoint SBTarget::BreakpointCreateByAddress(addr_t address) {
") => SBBreakpoint(%p)",
static_cast<void *>(target_sp.get()),
static_cast<uint64_t>(address),
- static_cast<void *>(sb_bp.get()));
+ static_cast<void *>(sb_bp.GetSP().get()));
return sb_bp;
}
@@ -926,7 +926,7 @@ SBBreakpoint SBTarget::BreakpointCreateBySBAddress(SBAddress &sb_address) {
if (target_sp) {
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
const bool hardware = false;
- *sb_bp = target_sp->CreateBreakpoint(sb_address.ref(), false, hardware);
+ sb_bp = target_sp->CreateBreakpoint(sb_address.ref(), false, hardware);
}
if (log) {
@@ -935,7 +935,7 @@ SBBreakpoint SBTarget::BreakpointCreateBySBAddress(SBAddress &sb_address) {
log->Printf("SBTarget(%p)::BreakpointCreateBySBAddress (address=%s) => "
"SBBreakpoint(%p)",
static_cast<void *>(target_sp.get()), s.GetData(),
- static_cast<void *>(sb_bp.get()));
+ static_cast<void *>(sb_bp.GetSP().get()));
}
return sb_bp;
@@ -985,7 +985,7 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateBySourceRegex(
func_names_set.insert(func_names.GetStringAtIndex(i));
}
- *sb_bp = target_sp->CreateSourceRegexBreakpoint(
+ sb_bp = target_sp->CreateSourceRegexBreakpoint(
module_list.get(), source_file_list.get(), func_names_set, regexp,
false, hardware, move_to_nearest_code);
}
@@ -994,7 +994,7 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateBySourceRegex(
log->Printf("SBTarget(%p)::BreakpointCreateByRegex (source_regex=\"%s\") "
"=> SBBreakpoint(%p)",
static_cast<void *>(target_sp.get()), source_regex,
- static_cast<void *>(sb_bp.get()));
+ static_cast<void *>(sb_bp.GetSP().get()));
return sb_bp;
}
@@ -1009,7 +1009,7 @@ SBTarget::BreakpointCreateForException(lldb::LanguageType language,
if (target_sp) {
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
const bool hardware = false;
- *sb_bp = target_sp->CreateExceptionBreakpoint(language, catch_bp, throw_bp,
+ sb_bp = target_sp->CreateExceptionBreakpoint(language, catch_bp, throw_bp,
hardware);
}
@@ -1019,7 +1019,7 @@ SBTarget::BreakpointCreateForException(lldb::LanguageType language,
static_cast<void *>(target_sp.get()),
Language::GetNameForLanguageType(language),
catch_bp ? "on" : "off", throw_bp ? "on" : "off",
- static_cast<void *>(sb_bp.get()));
+ static_cast<void *>(sb_bp.GetSP().get()));
return sb_bp;
}
@@ -1038,7 +1038,7 @@ SBBreakpoint SBTarget::GetBreakpointAtIndex(uint32_t idx) const {
TargetSP target_sp(GetSP());
if (target_sp) {
// The breakpoint list is thread safe, no need to lock
- *sb_breakpoint = target_sp->GetBreakpointList().GetBreakpointAtIndex(idx);
+ sb_breakpoint = target_sp->GetBreakpointList().GetBreakpointAtIndex(idx);
}
return sb_breakpoint;
}
@@ -1068,14 +1068,14 @@ SBBreakpoint SBTarget::FindBreakpointByID(break_id_t bp_id) {
TargetSP target_sp(GetSP());
if (target_sp && bp_id != LLDB_INVALID_BREAK_ID) {
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
- *sb_breakpoint = target_sp->GetBreakpointByID(bp_id);
+ sb_breakpoint = target_sp->GetBreakpointByID(bp_id);
}
if (log)
log->Printf(
"SBTarget(%p)::FindBreakpointByID (bp_id=%d) => SBBreakpoint(%p)",
static_cast<void *>(target_sp.get()), static_cast<uint32_t>(bp_id),
- static_cast<void *>(sb_breakpoint.get()));
+ static_cast<void *>(sb_breakpoint.GetSP().get()));
return sb_breakpoint;
}
@@ -1279,7 +1279,7 @@ lldb::SBWatchpoint SBTarget::WatchAddress(lldb::addr_t addr, size_t size,
}
// Target::CreateWatchpoint() is thread safe.
- Error cw_error;
+ Status cw_error;
// This API doesn't take in a type, so we can't figure out what it is.
CompilerType *type = NULL;
watchpoint_sp =
@@ -1863,7 +1863,7 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress base_addr,
DataBufferHeap data(
target_sp->GetArchitecture().GetMaximumOpcodeByteSize() * count, 0);
bool prefer_file_cache = false;
- lldb_private::Error error;
+ lldb_private::Status error;
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
const size_t bytes_read =
target_sp->ReadMemory(*addr_ptr, prefer_file_cache, data.GetBytes(),
@@ -2170,7 +2170,7 @@ lldb::addr_t SBTarget::GetStackRedZoneSize() {
if (process_sp)
abi_sp = process_sp->GetABI();
else
- abi_sp = ABI::FindPlugin(target_sp->GetArchitecture());
+ abi_sp = ABI::FindPlugin(ProcessSP(), target_sp->GetArchitecture());
if (abi_sp)
return abi_sp->GetRedZoneSize();
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBThread.cpp b/contrib/llvm/tools/lldb/source/API/SBThread.cpp
index fbde6dd..b344896 100644
--- a/contrib/llvm/tools/lldb/source/API/SBThread.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBThread.cpp
@@ -15,9 +15,7 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/CompileUnit.h"
@@ -34,6 +32,8 @@
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Target/ThreadPlanStepRange.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/API/SBAddress.h"
#include "lldb/API/SBDebugger.h"
@@ -43,6 +43,7 @@
#include "lldb/API/SBThreadCollection.h"
#include "lldb/API/SBThreadPlan.h"
#include "lldb/API/SBValue.h"
+#include "lldb/lldb-enumerations.h"
using namespace lldb;
using namespace lldb_private;
@@ -292,10 +293,6 @@ SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) {
ThreadCollectionSP threads;
threads.reset(new ThreadCollection());
- // We currently only support ThreadSanitizer.
- if (type != eInstrumentationRuntimeTypeThreadSanitizer)
- return threads;
-
std::unique_lock<std::recursive_mutex> lock;
ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
@@ -561,26 +558,26 @@ bool SBThread::GetInfoItemByPathAsString(const char *path, SBStream &strm) {
StructuredData::ObjectSP node =
info_root_sp->GetObjectForDotSeparatedPath(path);
if (node) {
- if (node->GetType() == StructuredData::Type::eTypeString) {
- strm.Printf("%s", node->GetAsString()->GetValue().c_str());
+ if (node->GetType() == eStructuredDataTypeString) {
+ strm.Printf("%s", node->GetAsString()->GetValue().str().c_str());
success = true;
}
- if (node->GetType() == StructuredData::Type::eTypeInteger) {
+ if (node->GetType() == eStructuredDataTypeInteger) {
strm.Printf("0x%" PRIx64, node->GetAsInteger()->GetValue());
success = true;
}
- if (node->GetType() == StructuredData::Type::eTypeFloat) {
+ if (node->GetType() == eStructuredDataTypeFloat) {
strm.Printf("0x%f", node->GetAsFloat()->GetValue());
success = true;
}
- if (node->GetType() == StructuredData::Type::eTypeBoolean) {
+ if (node->GetType() == eStructuredDataTypeBoolean) {
if (node->GetAsBoolean()->GetValue() == true)
strm.Printf("true");
else
strm.Printf("false");
success = true;
}
- if (node->GetType() == StructuredData::Type::eTypeNull) {
+ if (node->GetType() == eStructuredDataTypeNull) {
strm.Printf("null");
success = true;
}
@@ -595,8 +592,8 @@ bool SBThread::GetInfoItemByPathAsString(const char *path, SBStream &strm) {
}
if (log)
- log->Printf("SBThread(%p)::GetInfoItemByPathAsString () => %s",
- static_cast<void *>(exe_ctx.GetThreadPtr()), strm.GetData());
+ log->Printf("SBThread(%p)::GetInfoItemByPathAsString (\"%s\") => \"%s\"",
+ static_cast<void *>(exe_ctx.GetThreadPtr()), path, strm.GetData());
return success;
}
@@ -1037,7 +1034,7 @@ SBError SBThread::JumpToLine(lldb::SBFileSpec &file_spec, uint32_t line) {
Thread *thread = exe_ctx.GetThreadPtr();
- Error err = thread->JumpToLine(file_spec.get(), line, true);
+ Status err = thread->JumpToLine(file_spec.get(), line, true);
sb_error.SetError(err);
return sb_error;
}
diff --git a/contrib/llvm/tools/lldb/source/API/SBThreadPlan.cpp b/contrib/llvm/tools/lldb/source/API/SBThreadPlan.cpp
index 74cabf7..a19023f 100644
--- a/contrib/llvm/tools/lldb/source/API/SBThreadPlan.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBThreadPlan.cpp
@@ -15,9 +15,7 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/SymbolContext.h"
@@ -28,12 +26,13 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
-#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanPython.h"
#include "lldb/Target/ThreadPlanStepInRange.h"
#include "lldb/Target/ThreadPlanStepInstruction.h"
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/API/SBAddress.h"
#include "lldb/API/SBDebugger.h"
diff --git a/contrib/llvm/tools/lldb/source/API/SBTrace.cpp b/contrib/llvm/tools/lldb/source/API/SBTrace.cpp
new file mode 100644
index 0000000..9a5fa4e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/API/SBTrace.cpp
@@ -0,0 +1,109 @@
+//===-- SBTrace.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/Log.h"
+
+#include "lldb/API/SBTrace.h"
+#include "lldb/API/SBTraceOptions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class TraceImpl {
+public:
+ lldb::user_id_t uid;
+};
+
+lldb::ProcessSP SBTrace::GetSP() const { return m_opaque_wp.lock(); }
+
+size_t SBTrace::GetTraceData(SBError &error, void *buf, size_t size,
+ size_t offset, lldb::tid_t thread_id) {
+ ProcessSP process_sp(GetSP());
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
+ error.Clear();
+
+ if (!process_sp) {
+ error.SetErrorString("invalid process");
+ } else {
+ error.SetError(
+ process_sp->GetData(GetTraceUID(), thread_id, buffer, offset));
+ LLDB_LOG(log, "SBTrace::bytes_read - {0}", buffer.size());
+ }
+ return buffer.size();
+}
+
+size_t SBTrace::GetMetaData(SBError &error, void *buf, size_t size,
+ size_t offset, lldb::tid_t thread_id) {
+ ProcessSP process_sp(GetSP());
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+ llvm::MutableArrayRef<uint8_t> buffer(static_cast<uint8_t *>(buf), size);
+ error.Clear();
+
+ if (!process_sp) {
+ error.SetErrorString("invalid process");
+ } else {
+
+ error.SetError(
+ process_sp->GetMetaData(GetTraceUID(), thread_id, buffer, offset));
+ LLDB_LOG(log, "SBTrace::bytes_read - {0}", buffer.size());
+ }
+ return buffer.size();
+}
+
+void SBTrace::StopTrace(SBError &error, lldb::tid_t thread_id) {
+ ProcessSP process_sp(GetSP());
+ error.Clear();
+
+ if (!process_sp) {
+ error.SetErrorString("invalid process");
+ return;
+ }
+ error.SetError(process_sp->StopTrace(GetTraceUID(), thread_id));
+}
+
+void SBTrace::GetTraceConfig(SBTraceOptions &options, SBError &error) {
+ ProcessSP process_sp(GetSP());
+ error.Clear();
+
+ if (!process_sp) {
+ error.SetErrorString("invalid process");
+ } else {
+ error.SetError(process_sp->GetTraceConfig(GetTraceUID(),
+ *(options.m_traceoptions_sp)));
+ }
+}
+
+lldb::user_id_t SBTrace::GetTraceUID() {
+ if (m_trace_impl_sp)
+ return m_trace_impl_sp->uid;
+ return LLDB_INVALID_UID;
+}
+
+void SBTrace::SetTraceUID(lldb::user_id_t uid) {
+ if (m_trace_impl_sp)
+ m_trace_impl_sp->uid = uid;
+}
+
+SBTrace::SBTrace() {
+ m_trace_impl_sp.reset(new TraceImpl);
+ if (m_trace_impl_sp)
+ m_trace_impl_sp->uid = LLDB_INVALID_UID;
+}
+
+void SBTrace::SetSP(const ProcessSP &process_sp) { m_opaque_wp = process_sp; }
+
+bool SBTrace::IsValid() {
+ if (!m_trace_impl_sp)
+ return false;
+ if (!GetSP())
+ return false;
+ return true;
+}
diff --git a/contrib/llvm/tools/lldb/source/API/SBTraceOptions.cpp b/contrib/llvm/tools/lldb/source/API/SBTraceOptions.cpp
new file mode 100644
index 0000000..20a8f25
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/API/SBTraceOptions.cpp
@@ -0,0 +1,94 @@
+//===-- SBTraceOptions.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBTraceOptions.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBStructuredData.h"
+#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/TraceOptions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBTraceOptions::SBTraceOptions() {
+ m_traceoptions_sp.reset(new TraceOptions());
+}
+
+lldb::TraceType SBTraceOptions::getType() const {
+ if (m_traceoptions_sp)
+ return m_traceoptions_sp->getType();
+ return lldb::TraceType::eTraceTypeNone;
+}
+
+uint64_t SBTraceOptions::getTraceBufferSize() const {
+ if (m_traceoptions_sp)
+ return m_traceoptions_sp->getTraceBufferSize();
+ return 0;
+}
+
+lldb::SBStructuredData SBTraceOptions::getTraceParams(lldb::SBError &error) {
+ error.Clear();
+ const lldb_private::StructuredData::DictionarySP dict_obj =
+ m_traceoptions_sp->getTraceParams();
+ lldb::SBStructuredData structData;
+ if (dict_obj && structData.m_impl_up)
+ structData.m_impl_up->SetObjectSP(dict_obj->shared_from_this());
+ else
+ error.SetErrorString("Empty trace params");
+ return structData;
+}
+
+uint64_t SBTraceOptions::getMetaDataBufferSize() const {
+ if (m_traceoptions_sp)
+ return m_traceoptions_sp->getTraceBufferSize();
+ return 0;
+}
+
+void SBTraceOptions::setTraceParams(lldb::SBStructuredData &params) {
+ if (m_traceoptions_sp && params.m_impl_up) {
+ StructuredData::ObjectSP obj_sp = params.m_impl_up->GetObjectSP();
+ if (obj_sp && obj_sp->GetAsDictionary() != nullptr)
+ m_traceoptions_sp->setTraceParams(
+ std::static_pointer_cast<StructuredData::Dictionary>(obj_sp));
+ }
+ return;
+}
+
+void SBTraceOptions::setType(lldb::TraceType type) {
+ if (m_traceoptions_sp)
+ m_traceoptions_sp->setType(type);
+}
+
+void SBTraceOptions::setTraceBufferSize(uint64_t size) {
+ if (m_traceoptions_sp)
+ m_traceoptions_sp->setTraceBufferSize(size);
+}
+
+void SBTraceOptions::setMetaDataBufferSize(uint64_t size) {
+ if (m_traceoptions_sp)
+ m_traceoptions_sp->setMetaDataBufferSize(size);
+}
+
+bool SBTraceOptions::IsValid() {
+ if (m_traceoptions_sp)
+ return true;
+ return false;
+}
+
+void SBTraceOptions::setThreadID(lldb::tid_t thread_id) {
+ if (m_traceoptions_sp)
+ m_traceoptions_sp->setThreadID(thread_id);
+}
+
+lldb::tid_t SBTraceOptions::getThreadID() {
+ if (m_traceoptions_sp)
+ return m_traceoptions_sp->getThreadID();
+ return LLDB_INVALID_THREAD_ID;
+}
diff --git a/contrib/llvm/tools/lldb/source/API/SBType.cpp b/contrib/llvm/tools/lldb/source/API/SBType.cpp
index ca63a87..e2ef07c 100644
--- a/contrib/llvm/tools/lldb/source/API/SBType.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBType.cpp
@@ -11,13 +11,13 @@
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBTypeEnumMember.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Mangled.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
#include "llvm/ADT/APSInt.h"
diff --git a/contrib/llvm/tools/lldb/source/API/SBTypeEnumMember.cpp b/contrib/llvm/tools/lldb/source/API/SBTypeEnumMember.cpp
index 787a46b..5ca9db7 100644
--- a/contrib/llvm/tools/lldb/source/API/SBTypeEnumMember.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBTypeEnumMember.cpp
@@ -7,13 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/API/SBType.h"
+#include "lldb/API/SBTypeEnumMember.h"
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBStream.h"
-#include "lldb/API/SBTypeEnumMember.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/API/SBType.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/Type.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/API/SBUnixSignals.cpp b/contrib/llvm/tools/lldb/source/API/SBUnixSignals.cpp
index bb85912..14bdd39 100644
--- a/contrib/llvm/tools/lldb/source/API/SBUnixSignals.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBUnixSignals.cpp
@@ -8,10 +8,10 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/Log.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/Log.h"
#include "lldb/lldb-defines.h"
#include "lldb/API/SBUnixSignals.h"
diff --git a/contrib/llvm/tools/lldb/source/API/SBValue.cpp b/contrib/llvm/tools/lldb/source/API/SBValue.cpp
index 0531a3f..b6f044c 100644
--- a/contrib/llvm/tools/lldb/source/API/SBValue.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBValue.cpp
@@ -17,12 +17,9 @@
#include "lldb/API/SBTypeSynthetic.h"
#include "lldb/Breakpoint/Watchpoint.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObject.h"
@@ -39,6 +36,9 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBExpressionOptions.h"
@@ -112,7 +112,7 @@ public:
lldb::ValueObjectSP GetSP(Process::StopLocker &stop_locker,
std::unique_lock<std::recursive_mutex> &lock,
- Error &error) {
+ Status &error) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
if (!m_valobj_sp) {
error.SetErrorString("invalid value object");
@@ -218,12 +218,12 @@ public:
return in_value.GetSP(m_stop_locker, m_lock, m_lock_error);
}
- Error &GetError() { return m_lock_error; }
+ Status &GetError() { return m_lock_error; }
private:
Process::StopLocker m_stop_locker;
std::unique_lock<std::recursive_mutex> m_lock;
- Error m_lock_error;
+ Status m_lock_error;
};
SBValue::SBValue() : m_opaque_sp() {}
@@ -1112,7 +1112,7 @@ SBValue SBValue::Dereference() {
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp) {
- Error error;
+ Status error;
sb_value = value_sp->Dereference(error);
}
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
@@ -1336,7 +1336,7 @@ lldb::SBValue SBValue::AddressOf() {
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp) {
- Error error;
+ Status error;
sb_value.SetSP(value_sp->AddressOf(error), GetPreferDynamicValue(),
GetPreferSyntheticValue());
}
@@ -1445,7 +1445,7 @@ lldb::SBData SBValue::GetData() {
lldb::ValueObjectSP value_sp(GetSP(locker));
if (value_sp) {
DataExtractorSP data_sp(new DataExtractor());
- Error error;
+ Status error;
value_sp->GetData(*data_sp, error);
if (error.Success())
*sb_data = data_sp;
@@ -1475,7 +1475,7 @@ bool SBValue::SetData(lldb::SBData &data, SBError &error) {
error.SetErrorString("No data to set");
ret = false;
} else {
- Error set_error;
+ Status set_error;
value_sp->SetData(*data_extractor, set_error);
@@ -1541,7 +1541,7 @@ lldb::SBWatchpoint SBValue::Watch(bool resolve_location, bool read, bool write,
if (write)
watch_type |= LLDB_WATCH_TYPE_WRITE;
- Error rc;
+ Status rc;
CompilerType type(value_sp->GetCompilerType());
WatchpointSP watchpoint_sp =
target_sp->CreateWatchpoint(addr, byte_size, &type, watch_type, rc);
diff --git a/contrib/llvm/tools/lldb/source/API/SBValueList.cpp b/contrib/llvm/tools/lldb/source/API/SBValueList.cpp
index 16289d9..0adf3bb 100644
--- a/contrib/llvm/tools/lldb/source/API/SBValueList.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBValueList.cpp
@@ -10,8 +10,8 @@
#include "lldb/API/SBValueList.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBValue.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Utility/Log.h"
#include <vector>
diff --git a/contrib/llvm/tools/lldb/source/API/SBWatchpoint.cpp b/contrib/llvm/tools/lldb/source/API/SBWatchpoint.cpp
index 50153c8..b775537 100644
--- a/contrib/llvm/tools/lldb/source/API/SBWatchpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SBWatchpoint.cpp
@@ -16,39 +16,35 @@
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Breakpoint/WatchpointList.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
using namespace lldb;
using namespace lldb_private;
-SBWatchpoint::SBWatchpoint() : m_opaque_sp() {}
+SBWatchpoint::SBWatchpoint() {}
SBWatchpoint::SBWatchpoint(const lldb::WatchpointSP &wp_sp)
- : m_opaque_sp(wp_sp) {
+ : m_opaque_wp(wp_sp) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
if (log) {
SBStream sstr;
GetDescription(sstr, lldb::eDescriptionLevelBrief);
- log->Printf("SBWatchpoint::SBWatchpoint (const lldb::WatchpointSP &wp_sp"
- "=%p) => this.sp = %p (%s)",
- static_cast<void *>(wp_sp.get()),
- static_cast<void *>(m_opaque_sp.get()), sstr.GetData());
+ LLDB_LOG(log, "watchpoint = {0} ({1})", wp_sp.get(), sstr.GetData());
}
}
SBWatchpoint::SBWatchpoint(const SBWatchpoint &rhs)
- : m_opaque_sp(rhs.m_opaque_sp) {}
+ : m_opaque_wp(rhs.m_opaque_wp) {}
const SBWatchpoint &SBWatchpoint::operator=(const SBWatchpoint &rhs) {
- if (this != &rhs)
- m_opaque_sp = rhs.m_opaque_sp;
+ m_opaque_wp = rhs.m_opaque_wp;
return *this;
}
@@ -74,7 +70,7 @@ watch_id_t SBWatchpoint::GetID() {
return watch_id;
}
-bool SBWatchpoint::IsValid() const { return (bool)m_opaque_sp; }
+bool SBWatchpoint::IsValid() const { return bool(m_opaque_wp.lock()); }
SBError SBWatchpoint::GetError() {
SBError sb_error;
@@ -223,11 +219,11 @@ bool SBWatchpoint::GetDescription(SBStream &description,
return true;
}
-void SBWatchpoint::Clear() { m_opaque_sp.reset(); }
+void SBWatchpoint::Clear() { m_opaque_wp.reset(); }
-lldb::WatchpointSP SBWatchpoint::GetSP() const { return m_opaque_sp; }
+lldb::WatchpointSP SBWatchpoint::GetSP() const { return m_opaque_wp.lock(); }
-void SBWatchpoint::SetSP(const lldb::WatchpointSP &sp) { m_opaque_sp = sp; }
+void SBWatchpoint::SetSP(const lldb::WatchpointSP &sp) { m_opaque_wp = sp; }
bool SBWatchpoint::EventIsWatchpointEvent(const lldb::SBEvent &event) {
return Watchpoint::WatchpointEventData::GetEventDataFromEvent(event.get()) !=
@@ -245,7 +241,7 @@ SBWatchpoint::GetWatchpointEventTypeFromEvent(const SBEvent &event) {
SBWatchpoint SBWatchpoint::GetWatchpointFromEvent(const lldb::SBEvent &event) {
SBWatchpoint sb_watchpoint;
if (event.IsValid())
- sb_watchpoint.m_opaque_sp =
+ sb_watchpoint =
Watchpoint::WatchpointEventData::GetWatchpointFromEvent(event.GetSP());
return sb_watchpoint;
}
diff --git a/contrib/llvm/tools/lldb/source/API/SystemInitializerFull.cpp b/contrib/llvm/tools/lldb/source/API/SystemInitializerFull.cpp
index e7faac5..eb1bc2f 100644
--- a/contrib/llvm/tools/lldb/source/API/SystemInitializerFull.cpp
+++ b/contrib/llvm/tools/lldb/source/API/SystemInitializerFull.cpp
@@ -20,7 +20,6 @@
#endif
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
#include "lldb/Initialization/SystemInitializerCommon.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -28,6 +27,7 @@
#include "lldb/Symbol/GoASTContext.h"
//#include "lldb/Symbol/JavaASTContext.h"
#include "lldb/Symbol/OCamlASTContext.h"
+#include "lldb/Utility/Timer.h"
//#include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h"
//#include "Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h"
@@ -49,8 +49,10 @@
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
//#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
-#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h"
-//#include "Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h"
+#include "Plugins/InstrumentationRuntime/ASan/ASanRuntime.h"
+//#include "Plugins/InstrumentationRuntime/TSan/TSanRuntime.h"
+#include "Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h"
+#include "Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h"
#include "Plugins/JITLoader/GDB/JITLoaderGDB.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
//#include "Plugins/Language/Go/GoLanguage.h"
@@ -74,6 +76,7 @@
//#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
//#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
//#include "Plugins/Platform/NetBSD/PlatformNetBSD.h"
+//#include "Plugins/Platform/OpenBSD/PlatformOpenBSD.h"
//#include "Plugins/Platform/Windows/PlatformWindows.h"
#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
@@ -266,6 +269,7 @@ void SystemInitializerFull::Initialize() {
platform_freebsd::PlatformFreeBSD::Initialize();
//platform_linux::PlatformLinux::Initialize();
//platform_netbsd::PlatformNetBSD::Initialize();
+//platform_openbsd::PlatformOpenBSD::Initialize();
//PlatformWindows::Initialize();
//PlatformKalimba::Initialize();
//platform_android::PlatformAndroid::Initialize();
@@ -308,6 +312,8 @@ void SystemInitializerFull::Initialize() {
MemoryHistoryASan::Initialize();
AddressSanitizerRuntime::Initialize();
//ThreadSanitizerRuntime::Initialize();
+ UndefinedBehaviorSanitizerRuntime::Initialize();
+ MainThreadCheckerRuntime::Initialize();
SymbolVendorELF::Initialize();
SymbolFileDWARF::Initialize();
@@ -398,7 +404,8 @@ void SystemInitializerFull::InitializeSWIG() {
}
void SystemInitializerFull::Terminate() {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
Debugger::SettingsTerminate();
@@ -431,6 +438,8 @@ void SystemInitializerFull::Terminate() {
MemoryHistoryASan::Terminate();
AddressSanitizerRuntime::Terminate();
//ThreadSanitizerRuntime::Terminate();
+ UndefinedBehaviorSanitizerRuntime::Terminate();
+ MainThreadCheckerRuntime::Terminate();
SymbolVendorELF::Terminate();
SymbolFileDWARF::Terminate();
//SymbolFilePDB::Terminate();
@@ -485,13 +494,14 @@ void SystemInitializerFull::Terminate() {
//OperatingSystemGo::Terminate();
platform_freebsd::PlatformFreeBSD::Terminate();
-// platform_linux::PlatformLinux::Terminate();
-// platform_netbsd::PlatformNetBSD::Terminate();
-// PlatformWindows::Terminate();
-// PlatformKalimba::Terminate();
-// platform_android::PlatformAndroid::Terminate();
-// PlatformMacOSX::Terminate();
-// PlatformRemoteiOS::Terminate();
+//platform_linux::PlatformLinux::Terminate();
+//platform_netbsd::PlatformNetBSD::Terminate();
+//platform_openbsd::PlatformOpenBSD::Terminate();
+//PlatformWindows::Terminate();
+//PlatformKalimba::Terminate();
+//platform_android::PlatformAndroid::Terminate();
+//PlatformMacOSX::Terminate();
+//PlatformRemoteiOS::Terminate();
#if defined(__APPLE__)
PlatformiOSSimulator::Terminate();
PlatformDarwinKernel::Terminate();
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/Breakpoint.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/Breakpoint.cpp
index 915756f..17c104ba0 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/Breakpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/Breakpoint.cpp
@@ -19,18 +19,19 @@
#include "lldb/Breakpoint/BreakpointResolver.h"
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/SearchFilter.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -126,7 +127,7 @@ StructuredData::ObjectSP Breakpoint::SerializeToStructuredData() {
}
lldb::BreakpointSP Breakpoint::CreateFromStructuredData(
- Target &target, StructuredData::ObjectSP &object_data, Error &error) {
+ Target &target, StructuredData::ObjectSP &object_data, Status &error) {
BreakpointSP result_sp;
StructuredData::Dictionary *breakpoint_dict = object_data->GetAsDictionary();
@@ -145,7 +146,7 @@ lldb::BreakpointSP Breakpoint::CreateFromStructuredData(
return result_sp;
}
- Error create_error;
+ Status create_error;
BreakpointResolverSP resolver_sp =
BreakpointResolver::CreateFromStructuredData(*resolver_dict,
create_error);
@@ -206,10 +207,10 @@ lldb::BreakpointSP Breakpoint::CreateFromStructuredData(
if (success && names_array) {
size_t num_names = names_array->GetSize();
for (size_t i = 0; i < num_names; i++) {
- std::string name;
- Error error;
+ llvm::StringRef name;
+ Status error;
success = names_array->GetItemAtIndexAsString(i, name);
- result_sp->AddName(name.c_str(), error);
+ result_sp->AddName(name, error);
}
}
@@ -241,7 +242,7 @@ bool Breakpoint::SerializedBreakpointMatchesNames(
std::vector<std::string>::iterator end = names.end();
for (size_t i = 0; i < num_names; i++) {
- std::string name;
+ llvm::StringRef name;
if (names_array->GetItemAtIndexAsString(i, name)) {
if (std::find(begin, end, name) != end) {
return true;
@@ -832,12 +833,12 @@ size_t Breakpoint::GetNumResolvedLocations() const {
size_t Breakpoint::GetNumLocations() const { return m_locations.GetSize(); }
-bool Breakpoint::AddName(const char *new_name, Error &error) {
- if (!new_name)
+bool Breakpoint::AddName(llvm::StringRef new_name, Status &error) {
+ if (new_name.empty())
return false;
- if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(new_name), error)) {
- error.SetErrorStringWithFormat("input name \"%s\" not a breakpoint name.",
- new_name);
+ if (!BreakpointID::StringIsBreakpointName(new_name, error)) {
+ error.SetErrorStringWithFormatv("input name \"{0}\" not a breakpoint name.",
+ new_name);
return false;
}
if (!error.Success())
@@ -996,8 +997,9 @@ bool Breakpoint::BreakpointPrecondition::EvaluatePrecondition(
void Breakpoint::BreakpointPrecondition::GetDescription(
Stream &stream, lldb::DescriptionLevel level) {}
-Error Breakpoint::BreakpointPrecondition::ConfigurePrecondition(Args &options) {
- Error error;
+Status
+Breakpoint::BreakpointPrecondition::ConfigurePrecondition(Args &options) {
+ Status error;
error.SetErrorString("Base breakpoint precondition has no options.");
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointID.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointID.cpp
index 1ea86ca..112f7c0 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointID.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointID.cpp
@@ -15,8 +15,8 @@
// Project includes
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointID.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -98,7 +98,7 @@ BreakpointID::ParseCanonicalReference(llvm::StringRef input) {
return BreakpointID(bp_id, loc_id);
}
-bool BreakpointID::StringIsBreakpointName(llvm::StringRef str, Error &error) {
+bool BreakpointID::StringIsBreakpointName(llvm::StringRef str, Status &error) {
error.Clear();
if (str.empty())
return false;
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointIDList.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointIDList.cpp
index 037b03e..7b46114 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointIDList.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointIDList.cpp
@@ -137,7 +137,7 @@ void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
}
llvm::StringRef range_expr;
- Error error;
+ Status error;
std::tie(range_from, range_to) =
BreakpointIDList::SplitIDRangeExpression(current_arg);
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointList.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointList.cpp
index 7f35588..15bcb34 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointList.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointList.cpp
@@ -139,7 +139,7 @@ BreakpointList::FindBreakpointByID(break_id_t break_id) const {
bool BreakpointList::FindBreakpointsByName(const char *name,
BreakpointList &matching_bps) {
- Error error;
+ Status error;
if (!name)
return false;
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp
index 578267a..ec8f141 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -15,9 +15,7 @@
#include "lldb/Breakpoint/BreakpointID.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/ExpressionVariable.h"
@@ -29,6 +27,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -197,7 +197,7 @@ const char *BreakpointLocation::GetConditionText(size_t *hash) const {
}
bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
- Error &error) {
+ Status &error) {
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
std::lock_guard<std::mutex> guard(m_condition_mutex);
@@ -260,7 +260,7 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
options.SetResultIsInternal(
true); // Don't generate a user variable for condition expressions.
- Error expr_error;
+ Status expr_error;
diagnostics.Clear();
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointOptions.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointOptions.cpp
index 65c16e2..bef63cc 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointOptions.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointOptions.cpp
@@ -14,14 +14,14 @@
#include "lldb/Breakpoint/BreakpointOptions.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Core/Value.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
#include "llvm/ADT/STLExtras.h"
@@ -63,7 +63,7 @@ BreakpointOptions::CommandData::SerializeToStructuredData() {
std::unique_ptr<BreakpointOptions::CommandData>
BreakpointOptions::CommandData::CreateFromStructuredData(
- const StructuredData::Dictionary &options_dict, Error &error) {
+ const StructuredData::Dictionary &options_dict, Status &error) {
std::unique_ptr<CommandData> data_up(new CommandData());
bool found_something = false;
@@ -73,7 +73,7 @@ BreakpointOptions::CommandData::CreateFromStructuredData(
if (success)
found_something = true;
- std::string interpreter_str;
+ llvm::StringRef interpreter_str;
ScriptLanguage interp_language;
success = options_dict.GetValueForKeyAsString(
GetKey(OptionNames::Interpreter), interpreter_str);
@@ -99,7 +99,7 @@ BreakpointOptions::CommandData::CreateFromStructuredData(
found_something = true;
size_t num_elems = user_source->GetSize();
for (size_t i = 0; i < num_elems; i++) {
- std::string elem_string;
+ llvm::StringRef elem_string;
success = user_source->GetItemAtIndexAsString(i, elem_string);
if (success)
data_up->user_source.AppendString(elem_string);
@@ -196,7 +196,7 @@ BreakpointOptions::~BreakpointOptions() = default;
std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
Target &target, const StructuredData::Dictionary &options_dict,
- Error &error) {
+ Status &error) {
bool enabled = true;
bool one_shot = false;
int32_t ignore_count = 0;
@@ -230,7 +230,7 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
success = options_dict.GetValueForKeyAsDictionary(
CommandData::GetSerializationKey(), cmds_dict);
if (success && cmds_dict) {
- Error cmds_error;
+ Status cmds_error;
cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error);
if (cmds_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -260,7 +260,7 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
.c_str());
return nullptr;
}
- Error script_error;
+ Status script_error;
script_error =
interp->SetBreakpointCommandCallback(bp_options.get(), cmd_data_up);
if (script_error.Fail()) {
@@ -275,7 +275,7 @@ std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
success = options_dict.GetValueForKeyAsDictionary(
ThreadSpec::GetSerializationKey(), thread_spec_dict);
if (success) {
- Error thread_spec_error;
+ Status thread_spec_error;
std::unique_ptr<ThreadSpec> thread_spec_up =
ThreadSpec::CreateFromStructuredData(*thread_spec_dict,
thread_spec_error);
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolver.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolver.cpp
index 27c663c..31aefb0 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolver.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolver.cpp
@@ -22,15 +22,15 @@
#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
#include "lldb/Breakpoint/BreakpointResolverName.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/SearchFilter.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
using namespace lldb;
@@ -56,9 +56,9 @@ const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
}
BreakpointResolver::ResolverTy
-BreakpointResolver::NameToResolverTy(const char *name) {
+BreakpointResolver::NameToResolverTy(llvm::StringRef name) {
for (size_t i = 0; i < LastKnownResolverType; i++) {
- if (strcmp(name, g_ty_to_name[i]) == 0)
+ if (name == g_ty_to_name[i])
return (ResolverTy)i;
}
return UnknownResolver;
@@ -72,14 +72,14 @@ BreakpointResolver::BreakpointResolver(Breakpoint *bkpt,
BreakpointResolver::~BreakpointResolver() {}
BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
- const StructuredData::Dictionary &resolver_dict, Error &error) {
+ const StructuredData::Dictionary &resolver_dict, Status &error) {
BreakpointResolverSP result_sp;
if (!resolver_dict.IsValid()) {
error.SetErrorString("Can't deserialize from an invalid data object.");
return result_sp;
}
- std::string subclass_name;
+ llvm::StringRef subclass_name;
bool success = resolver_dict.GetValueForKeyAsString(
GetSerializationSubclassKey(), subclass_name);
@@ -90,10 +90,10 @@ BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
return result_sp;
}
- ResolverTy resolver_type = NameToResolverTy(subclass_name.c_str());
+ ResolverTy resolver_type = NameToResolverTy(subclass_name);
if (resolver_type == UnknownResolver) {
- error.SetErrorStringWithFormat("Unknown resolver type: %s.",
- subclass_name.c_str());
+ error.SetErrorStringWithFormatv("Unknown resolver type: {0}.",
+ subclass_name);
return result_sp;
}
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
index 90d7415..32f2045 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
@@ -15,12 +15,12 @@
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -44,8 +44,8 @@ BreakpointResolverAddress::~BreakpointResolverAddress() {}
BreakpointResolver *BreakpointResolverAddress::CreateFromStructuredData(
Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
- Error &error) {
- std::string module_name;
+ Status &error) {
+ llvm::StringRef module_name;
lldb::addr_t addr_offset;
FileSpec module_filespec;
bool success;
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
index acdd297..780d25d 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -14,11 +14,11 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -38,8 +38,8 @@ BreakpointResolverFileLine::~BreakpointResolverFileLine() {}
BreakpointResolver *BreakpointResolverFileLine::CreateFromStructuredData(
Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
- Error &error) {
- std::string filename;
+ Status &error) {
+ llvm::StringRef filename;
uint32_t line_no;
bool check_inlines;
bool skip_prologue;
@@ -108,6 +108,68 @@ BreakpointResolverFileLine::SerializeToStructuredData() {
return WrapOptionsDict(options_dict_sp);
}
+// Filter the symbol context list to remove contexts where the line number was
+// moved into a new function. We do this conservatively, so if e.g. we cannot
+// resolve the function in the context (which can happen in case of
+// line-table-only debug info), we leave the context as is. The trickiest part
+// here is handling inlined functions -- in this case we need to make sure we
+// look at the declaration line of the inlined function, NOT the function it was
+// inlined into.
+void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list) {
+ if (m_exact_match)
+ return; // Nothing to do. Contexts are precise.
+
+ Log * log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
+ for(uint32_t i = 0; i < sc_list.GetSize(); ++i) {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (! sc.block)
+ continue;
+
+ FileSpec file;
+ uint32_t line;
+ const Block *inline_block = sc.block->GetContainingInlinedBlock();
+ if (inline_block) {
+ const Declaration &inline_declaration = inline_block->GetInlinedFunctionInfo()->GetDeclaration();
+ if (!inline_declaration.IsValid())
+ continue;
+ file = inline_declaration.GetFile();
+ line = inline_declaration.GetLine();
+ } else if (sc.function)
+ sc.function->GetStartLineSourceInfo(file, line);
+ else
+ continue;
+
+ if (file != sc.line_entry.file) {
+ LLDB_LOG(log, "unexpected symbol context file {0}", sc.line_entry.file);
+ continue;
+ }
+
+ // Compare the requested line number with the line of the function
+ // declaration. In case of a function declared as:
+ //
+ // int
+ // foo()
+ // {
+ // ...
+ //
+ // the compiler will set the declaration line to the "foo" line, which is
+ // the reason why we have -1 here. This can fail in case of two inline
+ // functions defined back-to-back:
+ //
+ // inline int foo1() { ... }
+ // inline int foo2() { ... }
+ //
+ // but that's the best we can do for now.
+ const int decl_line_is_too_late_fudge = 1;
+ if (m_line_number < line - decl_line_is_too_late_fudge) {
+ LLDB_LOG(log, "removing symbol context at {0}:{1}", file, line);
+ sc_list.RemoveContextAtIndex(i);
+ --i;
+ }
+ }
+}
+
Searcher::CallbackReturn
BreakpointResolverFileLine::SearchCallback(SearchFilter &filter,
SymbolContext &context,
@@ -117,24 +179,20 @@ BreakpointResolverFileLine::SearchCallback(SearchFilter &filter,
assert(m_breakpoint != NULL);
// There is a tricky bit here. You can have two compilation units that
- // #include the same file, and
- // in one of them the function at m_line_number is used (and so code and a
- // line entry for it is generated) but in the
- // other it isn't. If we considered the CU's independently, then in the
- // second inclusion, we'd move the breakpoint
- // to the next function that actually generated code in the header file. That
- // would end up being confusing.
- // So instead, we do the CU iterations by hand here, then scan through the
- // complete list of matches, and figure out
- // the closest line number match, and only set breakpoints on that match.
+ // #include the same file, and in one of them the function at m_line_number is
+ // used (and so code and a line entry for it is generated) but in the other it
+ // isn't. If we considered the CU's independently, then in the second
+ // inclusion, we'd move the breakpoint to the next function that actually
+ // generated code in the header file. That would end up being confusing. So
+ // instead, we do the CU iterations by hand here, then scan through the
+ // complete list of matches, and figure out the closest line number match, and
+ // only set breakpoints on that match.
// Note also that if file_spec only had a file name and not a directory, there
- // may be many different file spec's in
- // the resultant list. The closest line match for one will not be right for
- // some totally different file.
- // So we go through the match list and pull out the sets that have the same
- // file spec in their line_entry
- // and treat each set separately.
+ // may be many different file spec's in the resultant list. The closest line
+ // match for one will not be right for some totally different file. So we go
+ // through the match list and pull out the sets that have the same file spec
+ // in their line_entry and treat each set separately.
const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
for (size_t i = 0; i < num_comp_units; i++) {
@@ -146,6 +204,9 @@ BreakpointResolverFileLine::SearchCallback(SearchFilter &filter,
sc_list);
}
}
+
+ FilterContexts(sc_list);
+
StreamString s;
s.Printf("for %s:%d ", m_file_spec.GetFilename().AsCString("<Unknown>"),
m_line_number);
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp
index 8655296..54c05a0 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp
@@ -14,11 +14,11 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/SourceManager.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -37,10 +37,10 @@ BreakpointResolverFileRegex::~BreakpointResolverFileRegex() {}
BreakpointResolver *BreakpointResolverFileRegex::CreateFromStructuredData(
Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
- Error &error) {
+ Status &error) {
bool success;
- std::string regex_string;
+ llvm::StringRef regex_string;
success = options_dict.GetValueForKeyAsString(
GetKey(OptionNames::RegexString), regex_string);
if (!success) {
@@ -65,7 +65,7 @@ BreakpointResolver *BreakpointResolverFileRegex::CreateFromStructuredData(
if (success && names_array) {
size_t num_names = names_array->GetSize();
for (size_t i = 0; i < num_names; i++) {
- std::string name;
+ llvm::StringRef name;
success = names_array->GetItemAtIndexAsString(i, name);
if (!success) {
error.SetErrorStringWithFormat(
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp
index 6cc8f60..468de35 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp
@@ -16,13 +16,13 @@
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -92,16 +92,16 @@ BreakpointResolverName::BreakpointResolverName(
BreakpointResolver *BreakpointResolverName::CreateFromStructuredData(
Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
- Error &error) {
+ Status &error) {
LanguageType language = eLanguageTypeUnknown;
- std::string language_name;
+ llvm::StringRef language_name;
bool success = options_dict.GetValueForKeyAsString(
GetKey(OptionNames::LanguageName), language_name);
if (success) {
language = Language::GetLanguageTypeFromString(language_name);
if (language == eLanguageTypeUnknown) {
- error.SetErrorStringWithFormat("BRN::CFSD: Unknown language: %s.",
- language_name.c_str());
+ error.SetErrorStringWithFormatv("BRN::CFSD: Unknown language: {0}.",
+ language_name);
return nullptr;
}
}
@@ -122,7 +122,7 @@ BreakpointResolver *BreakpointResolverName::CreateFromStructuredData(
return nullptr;
}
- std::string regex_text;
+ llvm::StringRef regex_text;
success = options_dict.GetValueForKeyAsString(
GetKey(OptionNames::RegexString), regex_text);
if (success) {
@@ -162,7 +162,7 @@ BreakpointResolver *BreakpointResolverName::CreateFromStructuredData(
std::vector<uint32_t> name_masks;
for (size_t i = 0; i < num_elem; i++) {
uint32_t name_mask;
- std::string name;
+ llvm::StringRef name;
success = names_array->GetItemAtIndexAsString(i, name);
if (!success) {
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSite.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSite.cpp
index 28ba37b..a5c5136 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSite.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSite.cpp
@@ -18,7 +18,7 @@
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/BreakpointSiteList.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSiteList.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSiteList.cpp
index 06155ee..87ce292 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSiteList.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointSiteList.cpp
@@ -13,7 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
#include <algorithm>
using namespace lldb;
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/Watchpoint.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/Watchpoint.cpp
index 13dba8c..a141a6b 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/Watchpoint.cpp
@@ -14,7 +14,6 @@
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectMemory.h"
@@ -23,6 +22,7 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -286,7 +286,7 @@ void Watchpoint::SetCondition(const char *condition) {
m_condition_ap.reset();
} else {
// Pass nullptr for expr_prefix (no translation-unit level definitions).
- Error error;
+ Status error;
m_condition_ap.reset(m_target.GetUserExpressionForLanguage(
condition, llvm::StringRef(), lldb::eLanguageTypeUnknown,
UserExpression::eResultTypeAny, EvaluateExpressionOptions(), error));
diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/WatchpointOptions.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/WatchpointOptions.cpp
index 311dcaa..558ebc5 100644
--- a/contrib/llvm/tools/lldb/source/Breakpoint/WatchpointOptions.cpp
+++ b/contrib/llvm/tools/lldb/source/Breakpoint/WatchpointOptions.cpp
@@ -14,12 +14,12 @@
#include "lldb/Breakpoint/WatchpointOptions.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Core/Value.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp
index 10c1a24..fd84e1c 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandCompletions.cpp
@@ -16,12 +16,12 @@
// C++ Includes
// Other libraries and framework includes
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSet.h"
// Project includes
#include "lldb/Core/FileSpecList.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandCompletions.h"
@@ -31,8 +31,13 @@
#include "lldb/Symbol/Variable.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/TildeExpressionResolver.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
using namespace lldb_private;
@@ -98,181 +103,131 @@ int CommandCompletions::SourceFiles(CommandInterpreter &interpreter,
return matches.GetSize();
}
-typedef struct DiskFilesOrDirectoriesBaton {
- const char *remainder;
- char *partial_name_copy;
- bool only_directories;
- bool *saw_directory;
- StringList *matches;
- char *end_ptr;
- size_t baselen;
-} DiskFilesOrDirectoriesBaton;
-
-FileSpec::EnumerateDirectoryResult
-DiskFilesOrDirectoriesCallback(void *baton, FileSpec::FileType file_type,
- const FileSpec &spec) {
- const char *name = spec.GetFilename().AsCString();
-
- const DiskFilesOrDirectoriesBaton *parameters =
- (DiskFilesOrDirectoriesBaton *)baton;
- char *end_ptr = parameters->end_ptr;
- char *partial_name_copy = parameters->partial_name_copy;
- const char *remainder = parameters->remainder;
-
- // Omit ".", ".." and any . files if the match string doesn't start with .
- if (name[0] == '.') {
- if (name[1] == '\0')
- return FileSpec::eEnumerateDirectoryResultNext;
- else if (name[1] == '.' && name[2] == '\0')
- return FileSpec::eEnumerateDirectoryResultNext;
- else if (remainder[0] != '.')
- return FileSpec::eEnumerateDirectoryResultNext;
- }
+static int DiskFilesOrDirectories(const llvm::Twine &partial_name,
+ bool only_directories, bool &saw_directory,
+ StringList &matches,
+ TildeExpressionResolver &Resolver) {
+ matches.Clear();
+
+ llvm::SmallString<256> CompletionBuffer;
+ llvm::SmallString<256> Storage;
+ partial_name.toVector(CompletionBuffer);
+
+ if (CompletionBuffer.size() >= PATH_MAX)
+ return 0;
+
+ namespace fs = llvm::sys::fs;
+ namespace path = llvm::sys::path;
+
+ llvm::StringRef SearchDir;
+ llvm::StringRef PartialItem;
+
+ if (CompletionBuffer.startswith("~")) {
+ llvm::StringRef Buffer(CompletionBuffer);
+ size_t FirstSep =
+ Buffer.find_if([](char c) { return path::is_separator(c); });
+
+ llvm::StringRef Username = Buffer.take_front(FirstSep);
+ llvm::StringRef Remainder;
+ if (FirstSep != llvm::StringRef::npos)
+ Remainder = Buffer.drop_front(FirstSep + 1);
+
+ llvm::SmallString<PATH_MAX> Resolved;
+ if (!Resolver.ResolveExact(Username, Resolved)) {
+ // We couldn't resolve it as a full username. If there were no slashes
+ // then this might be a partial username. We try to resolve it as such
+ // but after that, we're done regardless of any matches.
+ if (FirstSep == llvm::StringRef::npos) {
+ llvm::StringSet<> MatchSet;
+ saw_directory = Resolver.ResolvePartial(Username, MatchSet);
+ for (const auto &S : MatchSet) {
+ Resolved = S.getKey();
+ path::append(Resolved, path::get_separator());
+ matches.AppendString(Resolved);
+ }
+ saw_directory = (matches.GetSize() > 0);
+ }
+ return matches.GetSize();
+ }
- // If we found a directory, we put a "/" at the end of the name.
+ // If there was no trailing slash, then we're done as soon as we resolve the
+ // expression to the correct directory. Otherwise we need to continue
+ // looking for matches within that directory.
+ if (FirstSep == llvm::StringRef::npos) {
+ // Make sure it ends with a separator.
+ path::append(CompletionBuffer, path::get_separator());
+ saw_directory = true;
+ matches.AppendString(CompletionBuffer);
+ return 1;
+ }
- if (remainder[0] == '\0' || strstr(name, remainder) == name) {
- if (strlen(name) + parameters->baselen >= PATH_MAX)
- return FileSpec::eEnumerateDirectoryResultNext;
+ // We want to keep the form the user typed, so we special case this to
+ // search in the fully resolved directory, but CompletionBuffer keeps the
+ // unmodified form that the user typed.
+ Storage = Resolved;
+ SearchDir = Resolved;
+ } else {
+ SearchDir = path::parent_path(CompletionBuffer);
+ }
- strcpy(end_ptr, name);
+ size_t FullPrefixLen = CompletionBuffer.size();
- bool isa_directory = false;
- if (file_type == FileSpec::eFileTypeDirectory)
- isa_directory = true;
- else if (file_type == FileSpec::eFileTypeSymbolicLink) {
- if (FileSpec(partial_name_copy, false).IsDirectory())
- isa_directory = true;
- }
+ PartialItem = path::filename(CompletionBuffer);
+ if (PartialItem == ".")
+ PartialItem = llvm::StringRef();
- if (isa_directory) {
- *parameters->saw_directory = true;
- size_t len = strlen(parameters->partial_name_copy);
- partial_name_copy[len] = '/';
- partial_name_copy[len + 1] = '\0';
- }
- if (parameters->only_directories && !isa_directory)
- return FileSpec::eEnumerateDirectoryResultNext;
- parameters->matches->AppendString(partial_name_copy);
+ if (SearchDir.empty()) {
+ llvm::sys::fs::current_path(Storage);
+ SearchDir = Storage;
}
+ assert(!PartialItem.contains(path::get_separator()));
- return FileSpec::eEnumerateDirectoryResultNext;
-}
+ // SearchDir now contains the directory to search in, and Prefix contains the
+ // text we want to match against items in that directory.
-static int DiskFilesOrDirectories(llvm::StringRef partial_file_name,
- bool only_directories, bool &saw_directory,
- StringList &matches) {
- // I'm going to use the "glob" function with GLOB_TILDE for user directory
- // expansion.
- // If it is not defined on your host system, you'll need to implement it
- // yourself...
-
- size_t partial_name_len = partial_file_name.size();
-
- if (partial_name_len >= PATH_MAX)
- return matches.GetSize();
-
- // This copy of the string will be cut up into the directory part, and the
- // remainder. end_ptr below will point to the place of the remainder in this
- // string. Then when we've resolved the containing directory, and opened it,
- // we'll read the directory contents and overwrite the partial_name_copy
- // starting from end_ptr with each of the matches. Thus we will preserve the
- // form the user originally typed.
-
- char partial_name_copy[PATH_MAX];
- memcpy(partial_name_copy, partial_file_name.data(), partial_name_len);
- partial_name_copy[partial_name_len] = '\0';
-
- // We'll need to save a copy of the remainder for comparison, which we do
- // here.
- char remainder[PATH_MAX];
-
- // end_ptr will point past the last / in partial_name_copy, or if there is no
- // slash to the beginning of the string.
- char *end_ptr;
-
- end_ptr = strrchr(partial_name_copy, '/');
-
- // This will store the resolved form of the containing directory
- llvm::SmallString<64> containing_part;
-
- if (end_ptr == nullptr) {
- // There's no directory. If the thing begins with a "~" then this is a bare
- // user name.
- if (*partial_name_copy == '~') {
- // Nothing here but the user name. We could just put a slash on the end,
- // but for completeness sake we'll resolve the user name and only put a
- // slash
- // on the end if it exists.
- llvm::SmallString<64> resolved_username(partial_name_copy);
- FileSpec::ResolveUsername(resolved_username);
-
- // Not sure how this would happen, a username longer than PATH_MAX?
- // Still...
- if (resolved_username.size() == 0) {
- // The user name didn't resolve, let's look in the password database for
- // matches.
- // The user name database contains duplicates, and is not in
- // alphabetical order, so
- // we'll use a set to manage that for us.
- FileSpec::ResolvePartialUsername(partial_name_copy, matches);
- if (matches.GetSize() > 0)
- saw_directory = true;
- return matches.GetSize();
- } else {
- // The thing exists, put a '/' on the end, and return it...
- // FIXME: complete user names here:
- partial_name_copy[partial_name_len] = '/';
- partial_name_copy[partial_name_len + 1] = '\0';
- matches.AppendString(partial_name_copy);
- saw_directory = true;
- return matches.GetSize();
- }
- } else {
- // The containing part is the CWD, and the whole string is the remainder.
- containing_part = ".";
- strcpy(remainder, partial_name_copy);
- end_ptr = partial_name_copy;
- }
- } else {
- if (end_ptr == partial_name_copy) {
- // We're completing a file or directory in the root volume.
- containing_part = "/";
- } else {
- containing_part.append(partial_name_copy, end_ptr);
- }
- // Push end_ptr past the final "/" and set remainder.
- end_ptr++;
- strcpy(remainder, end_ptr);
- }
+ std::error_code EC;
+ fs::directory_iterator Iter(SearchDir, EC, false);
+ fs::directory_iterator End;
+ for (; Iter != End && !EC; Iter.increment(EC)) {
+ auto &Entry = *Iter;
- // Look for a user name in the containing part, and if it's there, resolve it
- // and stick the
- // result back into the containing_part:
+ auto Name = path::filename(Entry.path());
- if (*partial_name_copy == '~') {
- FileSpec::ResolveUsername(containing_part);
- // User name doesn't exist, we're not getting any further...
- if (containing_part.empty())
- return matches.GetSize();
- }
+ // Omit ".", ".."
+ if (Name == "." || Name == ".." || !Name.startswith(PartialItem))
+ continue;
- // Okay, containing_part is now the directory we want to open and look for
- // files:
+ // We have a match.
- size_t baselen = end_ptr - partial_name_copy;
+ fs::file_status st;
+ if ((EC = Entry.status(st)))
+ continue;
- DiskFilesOrDirectoriesBaton parameters;
- parameters.remainder = remainder;
- parameters.partial_name_copy = partial_name_copy;
- parameters.only_directories = only_directories;
- parameters.saw_directory = &saw_directory;
- parameters.matches = &matches;
- parameters.end_ptr = end_ptr;
- parameters.baselen = baselen;
+ // If it's a symlink, then we treat it as a directory as long as the target
+ // is a directory.
+ bool is_dir = fs::is_directory(st);
+ if (fs::is_symlink_file(st)) {
+ fs::file_status target_st;
+ if (!fs::status(Entry.path(), target_st))
+ is_dir = fs::is_directory(target_st);
+ }
+ if (only_directories && !is_dir)
+ continue;
+
+ // Shrink it back down so that it just has the original prefix the user
+ // typed and remove the part of the name which is common to the located
+ // item and what the user typed.
+ CompletionBuffer.resize(FullPrefixLen);
+ Name = Name.drop_front(PartialItem.size());
+ CompletionBuffer.append(Name);
+
+ if (is_dir) {
+ saw_directory = true;
+ path::append(CompletionBuffer, path::get_separator());
+ }
- FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true,
- DiskFilesOrDirectoriesCallback, &parameters);
+ matches.AppendString(CompletionBuffer);
+ }
return matches.GetSize();
}
@@ -283,9 +238,17 @@ int CommandCompletions::DiskFiles(CommandInterpreter &interpreter,
int max_return_elements,
SearchFilter *searcher, bool &word_complete,
StringList &matches) {
- int ret_val =
- DiskFilesOrDirectories(partial_file_name, false, word_complete, matches);
- word_complete = !word_complete;
+ word_complete = false;
+ StandardTildeExpressionResolver Resolver;
+ return DiskFiles(partial_file_name, matches, Resolver);
+}
+
+int CommandCompletions::DiskFiles(const llvm::Twine &partial_file_name,
+ StringList &matches,
+ TildeExpressionResolver &Resolver) {
+ bool word_complete;
+ int ret_val = DiskFilesOrDirectories(partial_file_name, false, word_complete,
+ matches, Resolver);
return ret_val;
}
@@ -293,9 +256,17 @@ int CommandCompletions::DiskDirectories(
CommandInterpreter &interpreter, llvm::StringRef partial_file_name,
int match_start_point, int max_return_elements, SearchFilter *searcher,
bool &word_complete, StringList &matches) {
- int ret_val =
- DiskFilesOrDirectories(partial_file_name, true, word_complete, matches);
word_complete = false;
+ StandardTildeExpressionResolver Resolver;
+ return DiskDirectories(partial_file_name, matches, Resolver);
+}
+
+int CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name,
+ StringList &matches,
+ TildeExpressionResolver &Resolver) {
+ bool word_complete;
+ int ret_val = DiskFilesOrDirectories(partial_file_name, true, word_complete,
+ matches, Resolver);
return ret_val;
}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp
index d98a246..92c2107 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.cpp
@@ -17,6 +17,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -54,10 +55,10 @@ CommandObjectArgs::CommandOptions::CommandOptions(
CommandObjectArgs::CommandOptions::~CommandOptions() = default;
-Error CommandObjectArgs::CommandOptions::SetOptionValue(
+Status CommandObjectArgs::CommandOptions::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
- Error error;
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
error.SetErrorStringWithFormat("invalid short option character '%c'",
@@ -223,9 +224,9 @@ bool CommandObjectArgs::DoExecute(Args &args, CommandReturnObject &result) {
result.GetOutputStream().Printf("Arguments : \n");
for (auto entry : llvm::enumerate(args.entries())) {
- result.GetOutputStream().Printf("%" PRIu64 " (%s): ", (uint64_t)entry.Index,
- entry.Value.c_str());
- value_list.GetValueAtIndex(entry.Index)->Dump(&result.GetOutputStream());
+ result.GetOutputStream().Printf(
+ "%" PRIu64 " (%s): ", (uint64_t)entry.index(), entry.value().c_str());
+ value_list.GetValueAtIndex(entry.index())->Dump(&result.GetOutputStream());
result.GetOutputStream().Printf("\n");
}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.h
index a4b3f9f..aa7d241 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.h
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectArgs.h
@@ -27,8 +27,8 @@ public:
~CommandOptions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.cpp
index 941dd9a..266864d 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -18,9 +18,7 @@
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointIDList.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -33,6 +31,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -178,9 +178,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -662,7 +662,7 @@ protected:
.get();
} break;
case eSetTypeException: {
- Error precond_error;
+ Status precond_error;
bp = target
->CreateExceptionBreakpoint(
m_options.m_exception_language, m_options.m_catch_bp,
@@ -705,7 +705,7 @@ protected:
bp->GetOptions()->SetCondition(m_options.m_condition.c_str());
if (!m_options.m_breakpoint_names.empty()) {
- Error name_error;
+ Status name_error;
for (auto name : m_options.m_breakpoint_names) {
bp->AddName(name.c_str(), name_error);
if (name_error.Fail()) {
@@ -844,9 +844,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1305,9 +1305,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1452,9 +1452,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1611,9 +1611,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1751,9 +1751,9 @@ public:
return llvm::makeArrayRef(g_breakpoint_name_options);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = g_breakpoint_name_options[option_idx].short_option;
switch (short_option) {
@@ -1864,8 +1864,8 @@ protected:
lldb::break_id_t bp_id =
valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
- Error error; // We don't need to check the error here, since the option
- // parser checked it...
+ Status error; // We don't need to check the error here, since the option
+ // parser checked it...
bp_sp->AddName(m_name_options.m_name.GetCurrentValue(), error);
}
}
@@ -2093,9 +2093,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -2103,7 +2103,7 @@ public:
m_filename.assign(option_arg);
break;
case 'N': {
- Error name_error;
+ Status name_error;
if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg),
name_error)) {
error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
@@ -2150,8 +2150,8 @@ protected:
FileSpec input_spec(m_options.m_filename, true);
BreakpointIDList new_bps;
- Error error = target->CreateBreakpointsFromFile(input_spec,
- m_options.m_names, new_bps);
+ Status error = target->CreateBreakpointsFromFile(
+ input_spec, m_options.m_names, new_bps);
if (!error.Success()) {
result.AppendError(error.AsCString());
@@ -2223,9 +2223,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -2281,7 +2281,7 @@ protected:
return false;
}
}
- Error error = target->SerializeBreakpointsToFile(
+ Status error = target->SerializeBreakpointsToFile(
FileSpec(m_options.m_filename, true), valid_bp_ids, m_options.m_append);
if (!error.Success()) {
result.AppendErrorWithFormat("error serializing breakpoints: %s.",
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
index 5e4ee0b..de49119 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -19,6 +19,7 @@
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/State.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Target.h"
@@ -280,9 +281,9 @@ are no syntax errors may indicate that a function was declared but never called.
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -510,9 +511,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBugreport.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBugreport.cpp
index 04050e3..7ba8ab9 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBugreport.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBugreport.cpp
@@ -84,7 +84,7 @@ protected:
open_options |= File::eOpenOptionTruncate;
StreamFileSP outfile_stream = std::make_shared<StreamFile>();
- Error error = outfile_stream->GetFile().Open(path, open_options);
+ Status error = outfile_stream->GetFile().Open(path, open_options);
if (error.Fail()) {
result.AppendErrorWithFormat("Failed to open file '%s' for %s: %s\n",
path, append ? "append" : "write",
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp
index aa07c10..c9d71a6 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp
@@ -17,7 +17,7 @@
#include "CommandObjectHelp.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/IOHandler.h"
-#include "lldb/Core/StringList.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandHistory.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -28,6 +28,7 @@
#include "lldb/Interpreter/OptionValueUInt64.h"
#include "lldb/Interpreter/Options.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Utility/StringList.h"
using namespace lldb;
using namespace lldb_private;
@@ -49,7 +50,11 @@ class CommandObjectCommandsHistory : public CommandObjectParsed {
public:
CommandObjectCommandsHistory(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "command history",
- "Dump the history of commands in this session.",
+ "Dump the history of commands in this session.\n"
+ "Commands in the history list can be run again "
+ "using \"!<INDEX>\". \"!-<OFFSET>\" will re-run "
+ "the command that is <OFFSET> commands from the end"
+ " of the list (counting the current command).",
nullptr),
m_options() {}
@@ -66,9 +71,9 @@ protected:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -256,9 +261,9 @@ protected:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -366,9 +371,9 @@ protected:
return llvm::makeArrayRef(g_alias_options);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = GetDefinitions()[option_idx].short_option;
std::string option_str(option_value);
@@ -574,7 +579,7 @@ protected:
if (!ParseOptions(args, result))
return false;
- Error error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
+ Status error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
if (error.Fail()) {
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
@@ -1025,7 +1030,7 @@ protected:
bool check_only = false;
for (size_t i = 0; i < num_lines; ++i) {
llvm::StringRef bytes_strref(lines[i]);
- Error error = AppendRegexSubstitution(bytes_strref, check_only);
+ Status error = AppendRegexSubstitution(bytes_strref, check_only);
if (error.Fail()) {
if (!m_interpreter.GetDebugger()
.GetCommandInterpreter()
@@ -1053,7 +1058,7 @@ protected:
return false;
}
- Error error;
+ Status error;
auto name = command[0].ref;
m_regex_cmd_ap = llvm::make_unique<CommandObjectRegexCommand>(
m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0,
@@ -1096,9 +1101,9 @@ protected:
return result.Succeeded();
}
- Error AppendRegexSubstitution(const llvm::StringRef &regex_sed,
- bool check_only) {
- Error error;
+ Status AppendRegexSubstitution(const llvm::StringRef &regex_sed,
+ bool check_only) {
+ Status error;
if (!m_regex_cmd_ap) {
error.SetErrorStringWithFormat(
@@ -1210,9 +1215,9 @@ private:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1306,7 +1311,7 @@ protected:
CommandReturnObject &result) override {
ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
- Error error;
+ Status error;
result.SetStatus(eReturnStatusInvalid);
@@ -1395,7 +1400,7 @@ protected:
CommandReturnObject &result) override {
ScriptInterpreter *scripter = m_interpreter.GetScriptInterpreter();
- Error error;
+ Status error;
result.SetStatus(eReturnStatusInvalid);
@@ -1482,9 +1487,9 @@ protected:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1529,7 +1534,7 @@ protected:
}
for (auto &entry : command.entries()) {
- Error error;
+ Status error;
const bool init_session = true;
// FIXME: this is necessary because CommandObject::CheckRequirements()
@@ -1614,9 +1619,9 @@ protected:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp
index fa3a144..5d0f241 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -16,7 +16,7 @@
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/SourceManager.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -71,10 +71,10 @@ CommandObjectDisassemble::CommandOptions::CommandOptions()
CommandObjectDisassemble::CommandOptions::~CommandOptions() = default;
-Error CommandObjectDisassemble::CommandOptions::SetOptionValue(
+Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
- Error error;
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
@@ -224,11 +224,11 @@ void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
some_location_specified = false;
}
-Error CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
+Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
ExecutionContext *execution_context) {
if (!some_location_specified)
current_function = true;
- return Error();
+ return Status();
}
llvm::ArrayRef<OptionDefinition>
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.h
index db89aa2..8ca3900 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.h
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.h
@@ -32,8 +32,8 @@ public:
~CommandOptions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override;
void OptionParsingStarting(ExecutionContext *execution_context) override;
@@ -49,7 +49,7 @@ public:
return flavor_string.c_str();
}
- Error OptionParsingFinished(ExecutionContext *execution_context) override;
+ Status OptionParsingFinished(ExecutionContext *execution_context) override;
bool show_mixed; // Show mixed source/assembly
bool show_bytes;
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp
index cfb3a6d..b6e0016 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp
@@ -24,7 +24,7 @@
#include "lldb/Expression/REPL.h"
#include "lldb/Expression/UserExpression.h"
#include "lldb/Host/Host.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Symbol/ObjectFile.h"
@@ -69,10 +69,10 @@ static OptionDefinition g_expression_options[] = {
// clang-format on
};
-Error CommandObjectExpression::CommandOptions::SetOptionValue(
+Status CommandObjectExpression::CommandOptions::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
- Error error;
+ Status error;
const int short_option = GetDefinitions()[option_idx].short_option;
@@ -295,15 +295,15 @@ CommandObjectExpression::~CommandObjectExpression() = default;
Options *CommandObjectExpression::GetOptions() { return &m_option_group; }
-static lldb_private::Error
+static lldb_private::Status
CanBeUsedForElementCountPrinting(ValueObject &valobj) {
CompilerType type(valobj.GetCompilerType());
CompilerType pointee;
if (!type.IsPointerType(&pointee))
- return Error("as it does not refer to a pointer");
+ return Status("as it does not refer to a pointer");
if (pointee.IsVoidType())
- return Error("as it refers to a pointer to void");
- return Error();
+ return Status("as it refers to a pointer to void");
+ return Status();
}
bool CommandObjectExpression::EvaluateExpression(const char *expr,
@@ -384,7 +384,7 @@ bool CommandObjectExpression::EvaluateExpression(const char *expr,
result_valobj_sp->SetFormat(format);
if (m_varobj_options.elem_count > 0) {
- Error error(CanBeUsedForElementCountPrinting(*result_valobj_sp));
+ Status error(CanBeUsedForElementCountPrinting(*result_valobj_sp));
if (error.Fail()) {
result->AppendErrorWithFormat(
"expression cannot be used with --element-count %s\n",
@@ -533,7 +533,7 @@ bool CommandObjectExpression::DoExecute(const char *command,
if (!ParseOptions(args, result))
return false;
- Error error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
+ Status error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
if (error.Fail()) {
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
@@ -564,7 +564,7 @@ bool CommandObjectExpression::DoExecute(const char *command,
// interpreter,
// so just push one
bool initialize = false;
- Error repl_error;
+ Status repl_error;
REPLSP repl_sp(target->GetREPL(
repl_error, m_command_options.language, nullptr, false));
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h
index 7c21adc..0cf2a72 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h
@@ -34,8 +34,8 @@ public:
llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override;
void OptionParsingStarting(ExecutionContext *execution_context) override;
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp
index 5a35054..0bcc350 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp
@@ -17,15 +17,13 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
#include "lldb/Host/Host.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -47,6 +45,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
@@ -77,9 +77,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'r':
@@ -192,14 +192,13 @@ protected:
return false;
}
- const bool qualify_cxx_base_classes = false;
- DumpValueObjectOptions::DeclPrintingHelper helper =
- [&valobj_sp, qualify_cxx_base_classes](
- ConstString type, ConstString var,
- const DumpValueObjectOptions &opts, Stream &stream) -> bool {
+ DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp](
+ ConstString type, ConstString var, const DumpValueObjectOptions &opts,
+ Stream &stream) -> bool {
const ValueObject::GetExpressionPathFormat format = ValueObject::
GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
+ const bool qualify_cxx_base_classes = false;
valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
stream.PutCString(" =");
return true;
@@ -264,9 +263,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'r':
@@ -605,7 +604,7 @@ protected:
} else // No regex, either exact variable names or variable
// expressions.
{
- Error error;
+ Status error;
uint32_t expr_path_options =
StackFrame::eExpressionPathOptionCheckPtrVsMember |
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
@@ -656,42 +655,60 @@ protected:
if (num_variables > 0) {
for (size_t i = 0; i < num_variables; i++) {
var_sp = variable_list->GetVariableAtIndex(i);
- bool dump_variable = true;
+ switch (var_sp->GetScope()) {
+ case eValueTypeVariableGlobal:
+ if (!m_option_variable.show_globals)
+ continue;
+ break;
+ case eValueTypeVariableStatic:
+ if (!m_option_variable.show_globals)
+ continue;
+ break;
+ case eValueTypeVariableArgument:
+ if (!m_option_variable.show_args)
+ continue;
+ break;
+ case eValueTypeVariableLocal:
+ if (!m_option_variable.show_locals)
+ continue;
+ break;
+ default:
+ continue;
+ break;
+ }
std::string scope_string;
- if (dump_variable && m_option_variable.show_scope)
+ if (m_option_variable.show_scope)
scope_string = GetScopeString(var_sp).str();
- if (dump_variable) {
- // Use the variable object code to make sure we are
- // using the same APIs as the public API will be
- // using...
- valobj_sp = frame->GetValueObjectForFrameVariable(
- var_sp, m_varobj_options.use_dynamic);
- if (valobj_sp) {
- // When dumping all variables, don't print any variables
- // that are not in scope to avoid extra unneeded output
- if (valobj_sp->IsInScope()) {
- if (!valobj_sp->GetTargetSP()
- ->GetDisplayRuntimeSupportValues() &&
- valobj_sp->IsRuntimeSupportValue())
- continue;
-
- if (!scope_string.empty())
- s.PutCString(scope_string);
-
- if (m_option_variable.show_decl &&
- var_sp->GetDeclaration().GetFile()) {
- var_sp->GetDeclaration().DumpStopContext(&s, false);
- s.PutCString(": ");
- }
-
- options.SetFormat(format);
- options.SetVariableFormatDisplayLanguage(
- valobj_sp->GetPreferredDisplayLanguage());
- options.SetRootValueObjectName(
- var_sp ? var_sp->GetName().AsCString() : nullptr);
- valobj_sp->Dump(result.GetOutputStream(), options);
+ // Use the variable object code to make sure we are
+ // using the same APIs as the public API will be
+ // using...
+ valobj_sp = frame->GetValueObjectForFrameVariable(
+ var_sp, m_varobj_options.use_dynamic);
+ if (valobj_sp) {
+ // When dumping all variables, don't print any variables
+ // that are not in scope to avoid extra unneeded output
+ if (valobj_sp->IsInScope()) {
+ if (!valobj_sp->GetTargetSP()
+ ->GetDisplayRuntimeSupportValues() &&
+ valobj_sp->IsRuntimeSupportValue())
+ continue;
+
+ if (!scope_string.empty())
+ s.PutCString(scope_string);
+
+ if (m_option_variable.show_decl &&
+ var_sp->GetDeclaration().GetFile()) {
+ var_sp->GetDeclaration().DumpStopContext(&s, false);
+ s.PutCString(": ");
}
+
+ options.SetFormat(format);
+ options.SetVariableFormatDisplayLanguage(
+ valobj_sp->GetPreferredDisplayLanguage());
+ options.SetRootValueObjectName(
+ var_sp ? var_sp->GetName().AsCString() : nullptr);
+ valobj_sp->Dump(result.GetOutputStream(), options);
}
}
}
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.h
index 721917a..f1f87f8 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.h
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectHelp.h
@@ -14,6 +14,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/Options.h"
@@ -45,9 +46,9 @@ public:
~CommandOptions() override {}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.cpp
index 3fdd888..ef82d07 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectLog.cpp
@@ -13,15 +13,9 @@
// Project includes
#include "CommandObjectLog.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/Timer.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -32,6 +26,11 @@
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
@@ -41,13 +40,13 @@ static OptionDefinition g_log_options[] = {
{ LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Set the destination file to log to." },
{ LLDB_OPT_SET_1, false, "threadsafe", 't', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." },
{ LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable verbose logging." },
- { LLDB_OPT_SET_1, false, "debug", 'g', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable debug logging." },
{ LLDB_OPT_SET_1, false, "sequence", 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." },
{ LLDB_OPT_SET_1, false, "timestamp", 'T', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Prepend all log lines with a timestamp." },
{ LLDB_OPT_SET_1, false, "pid-tid", 'p', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line." },
{ LLDB_OPT_SET_1, false, "thread-name",'n', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line." },
{ LLDB_OPT_SET_1, false, "stack", 'S', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Append a stack backtrace to each log line." },
{ LLDB_OPT_SET_1, false, "append", 'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Append to the log file instead of overwriting." },
+ { LLDB_OPT_SET_1, false, "file-function",'F',OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Prepend the names of files and function that generate the logs." },
// clang-format on
};
@@ -94,9 +93,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -109,9 +108,6 @@ public:
case 'v':
log_options |= LLDB_LOG_OPTION_VERBOSE;
break;
- case 'g':
- log_options |= LLDB_LOG_OPTION_DEBUG;
- break;
case 's':
log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE;
break;
@@ -130,6 +126,9 @@ public:
case 'a':
log_options |= LLDB_LOG_OPTION_APPEND;
break;
+ case 'F':
+ log_options |= LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION;
+ break;
default:
error.SetErrorStringWithFormat("unrecognized option '%c'",
short_option);
@@ -171,9 +170,14 @@ protected:
m_options.log_file.GetPath(log_file, sizeof(log_file));
else
log_file[0] = '\0';
+
+ std::string error;
+ llvm::raw_string_ostream error_stream(error);
bool success = m_interpreter.GetDebugger().EnableLog(
- channel.c_str(), args.GetConstArgumentVector(), log_file,
- m_options.log_options, result.GetErrorStream());
+ channel, args.GetArgumentArrayRef(), log_file, m_options.log_options,
+ error_stream);
+ result.GetErrorStream() << error_stream.str();
+
if (success)
result.SetStatus(eReturnStatusSuccessFinishNoResult);
else
@@ -227,25 +231,18 @@ protected:
return false;
}
- Log::Callbacks log_callbacks;
-
const std::string channel = args[0].ref;
args.Shift(); // Shift off the channel
- if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
- log_callbacks.disable(args.GetConstArgumentVector(),
- &result.GetErrorStream());
+ if (channel == "all") {
+ Log::DisableAllLogChannels();
result.SetStatus(eReturnStatusSuccessFinishNoResult);
- } else if (channel == "all") {
- Log::DisableAllLogChannels(&result.GetErrorStream());
} else {
- LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel.data()));
- if (log_channel_sp) {
- log_channel_sp->Disable(args.GetConstArgumentVector(),
- &result.GetErrorStream());
+ std::string error;
+ llvm::raw_string_ostream error_stream(error);
+ if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(),
+ error_stream))
result.SetStatus(eReturnStatusSuccessFinishNoResult);
- } else
- result.AppendErrorWithFormat("Invalid log channel '%s'.\n",
- channel.data());
+ result.GetErrorStream() << error_stream.str();
}
return result.Succeeded();
}
@@ -280,31 +277,20 @@ public:
protected:
bool DoExecute(Args &args, CommandReturnObject &result) override {
+ std::string output;
+ llvm::raw_string_ostream output_stream(output);
if (args.empty()) {
- Log::ListAllLogChannels(&result.GetOutputStream());
+ Log::ListAllLogChannels(output_stream);
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
- for (auto &entry : args.entries()) {
- Log::Callbacks log_callbacks;
-
- if (Log::GetLogChannelCallbacks(ConstString(entry.ref),
- log_callbacks)) {
- log_callbacks.list_categories(&result.GetOutputStream());
- result.SetStatus(eReturnStatusSuccessFinishResult);
- } else if (entry.ref == "all") {
- Log::ListAllLogChannels(&result.GetOutputStream());
- result.SetStatus(eReturnStatusSuccessFinishResult);
- } else {
- LogChannelSP log_channel_sp(LogChannel::FindPlugin(entry.c_str()));
- if (log_channel_sp) {
- log_channel_sp->ListCategories(&result.GetOutputStream());
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
- } else
- result.AppendErrorWithFormat("Invalid log channel '%s'.\n",
- entry.c_str());
- }
- }
+ bool success = true;
+ for (const auto &entry : args.entries())
+ success =
+ success && Log::ListChannelCategories(entry.ref, output_stream);
+ if (success)
+ result.SetStatus(eReturnStatusSuccessFinishResult);
}
+ result.GetOutputStream() << output_stream.str();
return result.Succeeded();
}
};
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.cpp
index 49ae923..8f4c186 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMemory.cpp
@@ -17,15 +17,13 @@
// Project includes
#include "CommandObjectMemory.h"
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Debugger.h"
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -42,6 +40,9 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataBufferLLVM.h"
+#include "lldb/Utility/StreamString.h"
#include "lldb/lldb-private.h"
@@ -73,9 +74,9 @@ public:
return llvm::makeArrayRef(g_read_memory_options);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = g_read_memory_options[option_idx].short_option;
switch (short_option) {
@@ -119,8 +120,8 @@ public:
m_offset.Clear();
}
- Error FinalizeSettings(Target *target, OptionGroupFormat &format_options) {
- Error error;
+ Status FinalizeSettings(Target *target, OptionGroupFormat &format_options) {
+ Status error;
OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
OptionValueUInt64 &count_value = format_options.GetCountValue();
const bool byte_size_option_set = byte_size_value.OptionWasSet();
@@ -377,7 +378,7 @@ protected:
}
CompilerType clang_ast_type;
- Error error;
+ Status error;
const char *view_as_type_cstr =
m_memory_options.m_view_as_type.GetCurrentValue();
@@ -715,7 +716,7 @@ protected:
while (item_count < count) {
std::string buffer;
buffer.resize(item_byte_size + 1, 0);
- Error error;
+ Status error;
size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0],
item_byte_size + 1, error);
if (error.Fail()) {
@@ -861,10 +862,10 @@ protected:
}
assert(output_stream);
- size_t bytes_dumped =
- data.Dump(output_stream, 0, format, item_byte_size, item_count,
- num_per_line / target->GetArchitecture().GetDataByteSize(),
- addr, 0, 0, exe_scope);
+ size_t bytes_dumped = DumpDataExtractor(
+ data, output_stream, 0, format, item_byte_size, item_count,
+ num_per_line / target->GetArchitecture().GetDataByteSize(), addr, 0, 0,
+ exe_scope);
m_next_addr = addr + bytes_dumped;
output_stream->EOL();
return true;
@@ -908,9 +909,9 @@ public:
return llvm::makeArrayRef(g_memory_find_option_table);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option =
g_memory_find_option_table[option_idx].short_option;
@@ -1007,7 +1008,7 @@ protected:
return 0;
uint8_t retval = 0;
- Error error;
+ Status error;
if (0 ==
m_process_sp->ReadMemory(m_base_addr + offset, &retval, 1, error)) {
m_is_valid = false;
@@ -1034,7 +1035,7 @@ protected:
return false;
}
- Error error;
+ Status error;
lldb::addr_t low_addr = Args::StringToAddress(&m_exe_ctx, command[0].ref,
LLDB_INVALID_ADDRESS, &error);
if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
@@ -1131,10 +1132,10 @@ protected:
DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
process->GetByteOrder(),
process->GetAddressByteSize());
- data.Dump(&result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1,
- dumpbuffer.GetByteSize(), 16,
- found_location + m_memory_options.m_offset.GetCurrentValue(),
- 0, 0);
+ DumpDataExtractor(
+ data, &result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1,
+ dumpbuffer.GetByteSize(), 16,
+ found_location + m_memory_options.m_offset.GetCurrentValue(), 0, 0);
result.GetOutputStream().EOL();
}
@@ -1201,9 +1202,9 @@ public:
return llvm::makeArrayRef(g_memory_write_option_table);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option =
g_memory_write_option_table[option_idx].short_option;
@@ -1343,7 +1344,7 @@ protected:
OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
size_t item_byte_size = byte_size_value.GetCurrentValue();
- Error error;
+ Status error;
lldb::addr_t addr = Args::StringToAddress(&m_exe_ctx, command[0].ref,
LLDB_INVALID_ADDRESS, &error);
@@ -1358,12 +1359,13 @@ protected:
size_t length = SIZE_MAX;
if (item_byte_size > 1)
length = item_byte_size;
- lldb::DataBufferSP data_sp(m_memory_options.m_infile.ReadFileContents(
- m_memory_options.m_infile_offset, length));
+ auto data_sp = DataBufferLLVM::CreateSliceFromPath(
+ m_memory_options.m_infile.GetPath(), length,
+ m_memory_options.m_infile_offset);
if (data_sp) {
length = data_sp->GetByteSize();
if (length > 0) {
- Error error;
+ Status error;
size_t bytes_written =
process->WriteMemory(addr, data_sp->GetBytes(), length, error);
@@ -1441,8 +1443,16 @@ protected:
case eFormatHex:
case eFormatHexUppercase:
case eFormatPointer:
+ {
// Decode hex bytes
- if (entry.ref.getAsInteger(16, uval64)) {
+ // Be careful, getAsInteger with a radix of 16 rejects "0xab" so we
+ // have to special case that:
+ bool success = false;
+ if (entry.ref.startswith("0x"))
+ success = !entry.ref.getAsInteger(0, uval64);
+ if (!success)
+ success = !entry.ref.getAsInteger(16, uval64);
+ if (!success) {
result.AppendErrorWithFormat(
"'%s' is not a valid hex string value.\n", entry.c_str());
result.SetStatus(eReturnStatusFailed);
@@ -1457,7 +1467,7 @@ protected:
}
buffer.PutMaxHex64(uval64, item_byte_size);
break;
-
+ }
case eFormatBoolean:
uval64 = Args::StringToBoolean(entry.ref, false, &success);
if (!success) {
@@ -1496,7 +1506,7 @@ protected:
// Include the NULL for C strings...
if (m_format_options.GetFormat() == eFormatCString)
++len;
- Error error;
+ Status error;
if (process->WriteMemory(addr, entry.c_str(), len, error) == len) {
addr += len;
} else {
@@ -1564,7 +1574,7 @@ protected:
}
if (!buffer.GetString().empty()) {
- Error error;
+ Status error;
if (process->WriteMemory(addr, buffer.GetString().data(),
buffer.GetString().size(),
error) == buffer.GetString().size())
@@ -1631,7 +1641,7 @@ protected:
return false;
}
- Error error;
+ Status error;
lldb::addr_t addr = Args::StringToAddress(&m_exe_ctx, command[0].ref,
LLDB_INVALID_ADDRESS, &error);
@@ -1689,7 +1699,7 @@ protected:
bool DoExecute(Args &command, CommandReturnObject &result) override {
ProcessSP process_sp = m_exe_ctx.GetProcessSP();
if (process_sp) {
- Error error;
+ Status error;
lldb::addr_t load_addr = m_prev_end_addr;
m_prev_end_addr = LLDB_INVALID_ADDRESS;
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp
index 562572b..5fa851f 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlatform.cpp
@@ -13,10 +13,10 @@
// Other libraries and framework includes
// Project includes
#include "CommandObjectPlatform.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -27,9 +27,10 @@
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
-#include "lldb/Utility/Utils.h"
+#include "lldb/Utility/DataExtractor.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Threading.h"
using namespace lldb;
using namespace lldb_private;
@@ -84,10 +85,10 @@ public:
~OptionPermissions() override = default;
- lldb_private::Error
+ lldb_private::Status
SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) override {
- Error error;
+ Status error;
char short_option = (char)GetDefinitions()[option_idx].short_option;
switch (short_option) {
case 'v': {
@@ -199,7 +200,7 @@ protected:
if (platform_name && platform_name[0]) {
const bool select = true;
m_platform_options.SetPlatformName(platform_name);
- Error error;
+ Status error;
ArchSpec platform_arch;
PlatformSP platform_sp(m_platform_options.CreatePlatformWithOptions(
m_interpreter, ArchSpec(), select, error, platform_arch));
@@ -328,7 +329,7 @@ protected:
PlatformSP platform_sp(
m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
if (platform_sp) {
- Error error(platform_sp->ConnectRemote(args));
+ Status error(platform_sp->ConnectRemote(args));
if (error.Success()) {
platform_sp->GetStatus(ostrm);
result.SetStatus(eReturnStatusSuccessFinishResult);
@@ -381,7 +382,7 @@ protected:
m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
if (platform_sp) {
if (args.GetArgumentCount() == 0) {
- Error error;
+ Status error;
if (platform_sp->IsConnected()) {
// Cache the instance name if there is one since we are
@@ -497,7 +498,8 @@ public:
else
mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX |
lldb::eFilePermissionsWorldRX;
- Error error = platform_sp->MakeDirectory(FileSpec{cmd_line, false}, mode);
+ Status error =
+ platform_sp->MakeDirectory(FileSpec{cmd_line, false}, mode);
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
@@ -538,7 +540,7 @@ public:
PlatformSP platform_sp(
m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
if (platform_sp) {
- Error error;
+ Status error;
std::string cmd_line;
args.GetCommandString(cmd_line);
mode_t perms;
@@ -598,7 +600,7 @@ public:
args.GetCommandString(cmd_line);
const lldb::user_id_t fd =
StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
- Error error;
+ Status error;
bool success = platform_sp->CloseFile(fd, error);
if (success) {
result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
@@ -645,7 +647,7 @@ public:
const lldb::user_id_t fd =
StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
std::string buffer(m_options.m_count, 0);
- Error error;
+ Status error;
uint32_t retcode = platform_sp->ReadFile(
fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
result.AppendMessageWithFormat("Return = %d\n", retcode);
@@ -667,9 +669,9 @@ protected:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
char short_option = (char)m_getopt_table[option_idx].val;
switch (short_option) {
@@ -737,7 +739,7 @@ public:
if (platform_sp) {
std::string cmd_line;
args.GetCommandString(cmd_line);
- Error error;
+ Status error;
const lldb::user_id_t fd =
StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX);
uint32_t retcode =
@@ -761,9 +763,9 @@ protected:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
char short_option = (char)m_getopt_table[option_idx].val;
switch (short_option) {
@@ -888,8 +890,8 @@ public:
if (platform_sp) {
const char *remote_file_path = args.GetArgumentAtIndex(0);
const char *local_file_path = args.GetArgumentAtIndex(1);
- Error error = platform_sp->GetFile(FileSpec(remote_file_path, false),
- FileSpec(local_file_path, false));
+ Status error = platform_sp->GetFile(FileSpec(remote_file_path, false),
+ FileSpec(local_file_path, false));
if (error.Success()) {
result.AppendMessageWithFormat(
"successfully get-file from %s (remote) to %s (host)\n",
@@ -998,7 +1000,7 @@ public:
PlatformSP platform_sp(
m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
if (platform_sp) {
- Error error(platform_sp->PutFile(src_fs, dst_fs));
+ Status error(platform_sp->PutFile(src_fs, dst_fs));
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishNoResult);
} else {
@@ -1042,7 +1044,7 @@ protected:
}
if (platform_sp) {
- Error error;
+ Status error;
const size_t argc = args.GetArgumentCount();
Target *target = m_exe_ctx.GetTargetPtr();
Module *exe_module = target->GetExecutableModulePointer();
@@ -1152,7 +1154,7 @@ protected:
}
if (platform_sp) {
- Error error;
+ Status error;
if (args.GetArgumentCount() == 0) {
if (platform_sp) {
Stream &ostrm = result.GetOutputStream();
@@ -1182,21 +1184,21 @@ protected:
m_options.match_info.GetProcessInfo().GetName();
if (match_name && match_name[0]) {
switch (m_options.match_info.GetNameMatchType()) {
- case eNameMatchIgnore:
+ case NameMatch::Ignore:
break;
- case eNameMatchEquals:
+ case NameMatch::Equals:
match_desc = "matched";
break;
- case eNameMatchContains:
+ case NameMatch::Contains:
match_desc = "contained";
break;
- case eNameMatchStartsWith:
+ case NameMatch::StartsWith:
match_desc = "started with";
break;
- case eNameMatchEndsWith:
+ case NameMatch::EndsWith:
match_desc = "ended with";
break;
- case eNameMatchRegularExpression:
+ case NameMatch::RegularExpression:
match_desc = "matched the regular expression";
break;
}
@@ -1249,8 +1251,8 @@ protected:
public:
CommandOptions()
: Options(), match_info(), show_args(false), verbose(false) {
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
PosixPlatformCommandOptionValidator *posix_validator =
new PosixPlatformCommandOptionValidator();
for (auto &Option : g_platform_process_list_options) {
@@ -1270,9 +1272,9 @@ protected:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
bool success = false;
@@ -1342,31 +1344,31 @@ protected:
case 'n':
match_info.GetProcessInfo().GetExecutableFile().SetFile(option_arg,
false);
- match_info.SetNameMatchType(eNameMatchEquals);
+ match_info.SetNameMatchType(NameMatch::Equals);
break;
case 'e':
match_info.GetProcessInfo().GetExecutableFile().SetFile(option_arg,
false);
- match_info.SetNameMatchType(eNameMatchEndsWith);
+ match_info.SetNameMatchType(NameMatch::EndsWith);
break;
case 's':
match_info.GetProcessInfo().GetExecutableFile().SetFile(option_arg,
false);
- match_info.SetNameMatchType(eNameMatchStartsWith);
+ match_info.SetNameMatchType(NameMatch::StartsWith);
break;
case 'c':
match_info.GetProcessInfo().GetExecutableFile().SetFile(option_arg,
false);
- match_info.SetNameMatchType(eNameMatchContains);
+ match_info.SetNameMatchType(NameMatch::Contains);
break;
case 'r':
match_info.GetProcessInfo().GetExecutableFile().SetFile(option_arg,
false);
- match_info.SetNameMatchType(eNameMatchRegularExpression);
+ match_info.SetNameMatchType(NameMatch::RegularExpression);
break;
case 'A':
@@ -1448,7 +1450,7 @@ protected:
if (platform_sp) {
const size_t argc = args.GetArgumentCount();
if (argc > 0) {
- Error error;
+ Status error;
if (platform_sp->IsConnected()) {
Stream &ostrm = result.GetOutputStream();
@@ -1514,9 +1516,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
char short_option = (char)m_getopt_table[option_idx].val;
switch (short_option) {
case 'p': {
@@ -1585,7 +1587,7 @@ public:
if (partial_name) {
match_info.GetProcessInfo().GetExecutableFile().SetFile(
partial_name, false);
- match_info.SetNameMatchType(eNameMatchStartsWith);
+ match_info.SetNameMatchType(NameMatch::StartsWith);
}
platform_sp->FindProcesses(match_info, process_infos);
const uint32_t num_matches = process_infos.GetSize();
@@ -1623,7 +1625,7 @@ public:
PlatformSP platform_sp(
m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
if (platform_sp) {
- Error err;
+ Status err;
ProcessSP remote_process_sp = platform_sp->Attach(
m_options.attach_info, m_interpreter.GetDebugger(), nullptr, err);
if (err.Fail()) {
@@ -1699,9 +1701,9 @@ public:
return llvm::makeArrayRef(g_platform_shell_options);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const char short_option = (char)GetDefinitions()[option_idx].short_option;
@@ -1781,7 +1783,7 @@ public:
PlatformSP platform_sp(
m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
- Error error;
+ Status error;
if (platform_sp) {
FileSpec working_dir{};
std::string output;
@@ -1860,7 +1862,7 @@ public:
return false;
}
- Error error = platform_sp->Install(src, dst);
+ Status error = platform_sp->Install(src, dst);
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishNoResult);
} else {
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.cpp
index 7ae968b..7e1b7f6 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectPlugin.cpp
@@ -68,7 +68,7 @@ protected:
return false;
}
- Error error;
+ Status error;
FileSpec dylib_fspec(command[0].ref, true);
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp
index 5b7f134..9fbdd76 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp
@@ -19,6 +19,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -73,7 +74,7 @@ protected:
} else {
if (process->GetShouldDetach()) {
bool keep_stopped = false;
- Error detach_error(process->Detach(keep_stopped));
+ Status detach_error(process->Detach(keep_stopped));
if (detach_error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
process = nullptr;
@@ -84,7 +85,7 @@ protected:
result.SetStatus(eReturnStatusFailed);
}
} else {
- Error destroy_error(process->Destroy(false));
+ Status destroy_error(process->Destroy(false));
if (destroy_error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
process = nullptr;
@@ -230,7 +231,7 @@ protected:
}
StreamString stream;
- Error error = target->Launch(m_options.launch_info, &stream);
+ Status error = target->Launch(m_options.launch_info, &stream);
if (error.Success()) {
ProcessSP process_sp(target->GetProcessSP());
@@ -337,9 +338,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'c':
@@ -416,7 +417,7 @@ public:
if (partial_name) {
match_info.GetProcessInfo().GetExecutableFile().SetFile(
partial_name, false);
- match_info.SetNameMatchType(eNameMatchStartsWith);
+ match_info.SetNameMatchType(NameMatch::StartsWith);
}
platform_sp->FindProcesses(match_info, process_infos);
const size_t num_matches = process_infos.GetSize();
@@ -469,7 +470,7 @@ protected:
if (target == nullptr) {
// If there isn't a current target create one.
TargetSP new_target_sp;
- Error error;
+ Status error;
error = m_interpreter.GetDebugger().GetTargetList().CreateTarget(
m_interpreter.GetDebugger(), "", "", false,
@@ -602,9 +603,9 @@ protected:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'i':
@@ -686,7 +687,7 @@ protected:
const uint32_t iohandler_id = process->GetIOHandlerID();
StreamString stream;
- Error error;
+ Status error;
if (synchronous_execution)
error = process->ResumeSynchronous(&stream);
else
@@ -750,9 +751,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -815,7 +816,7 @@ protected:
else
keep_stopped = false;
- Error error(process->Detach(keep_stopped));
+ Status error(process->Detach(keep_stopped));
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
@@ -853,9 +854,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -918,7 +919,7 @@ protected:
if (!m_options.plugin_name.empty())
plugin_name = m_options.plugin_name.c_str();
- Error error;
+ Status error;
Debugger &debugger = m_interpreter.GetDebugger();
PlatformSP platform_sp = m_interpreter.GetPlatform(true);
ProcessSP process_sp = platform_sp->ConnectProcess(
@@ -982,9 +983,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'i':
@@ -1032,7 +1033,7 @@ protected:
Process *process = m_exe_ctx.GetProcessPtr();
for (auto &entry : command.entries()) {
- Error error;
+ Status error;
PlatformSP platform = process->GetTarget().GetPlatform();
llvm::StringRef image_path = entry.ref;
uint32_t image_token = LLDB_INVALID_IMAGE_TOKEN;
@@ -1102,7 +1103,7 @@ protected:
result.SetStatus(eReturnStatusFailed);
break;
} else {
- Error error(process->GetTarget().GetPlatform()->UnloadImage(
+ Status error(process->GetTarget().GetPlatform()->UnloadImage(
process, image_token));
if (error.Success()) {
result.AppendMessageWithFormat(
@@ -1168,7 +1169,7 @@ protected:
command.GetArgumentAtIndex(0));
result.SetStatus(eReturnStatusFailed);
} else {
- Error error(process->Signal(signo));
+ Status error(process->Signal(signo));
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
@@ -1214,7 +1215,7 @@ protected:
if (command.GetArgumentCount() == 0) {
bool clear_thread_plans = true;
- Error error(process->Halt(clear_thread_plans));
+ Status error(process->Halt(clear_thread_plans));
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
@@ -1257,7 +1258,7 @@ protected:
}
if (command.GetArgumentCount() == 0) {
- Error error(process->Destroy(true));
+ Status error(process->Destroy(true));
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
@@ -1297,7 +1298,7 @@ protected:
if (process_sp) {
if (command.GetArgumentCount() == 1) {
FileSpec output_file(command.GetArgumentAtIndex(0), false);
- Error error = PluginManager::SaveCore(process_sp, output_file);
+ Status error = PluginManager::SaveCore(process_sp, output_file);
if (error.Success()) {
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
@@ -1376,9 +1377,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp
index 0ba6526..d535742 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp
@@ -7,17 +7,11 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-#include "llvm/ADT/STLExtras.h"
-
-// Project includes
#include "CommandObjectRegister.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -31,6 +25,8 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "llvm/Support/Errno.h"
using namespace lldb;
using namespace lldb_private;
@@ -177,8 +173,8 @@ protected:
if (set_idx < reg_ctx->GetRegisterSetCount()) {
if (!DumpRegisterSet(m_exe_ctx, strm, reg_ctx, set_idx)) {
if (errno)
- result.AppendErrorWithFormat("register read failed: %s\n",
- strerror(errno));
+ result.AppendErrorWithFormatv("register read failed: {0}\n",
+ llvm::sys::StrError());
else
result.AppendError("unknown error while reading registers.\n");
result.SetStatus(eReturnStatusFailed);
@@ -256,9 +252,9 @@ protected:
alternate_name.Clear();
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = GetDefinitions()[option_idx].short_option;
switch (short_option) {
case 's': {
@@ -366,7 +362,7 @@ protected:
if (reg_info) {
RegisterValue reg_value;
- Error error(reg_value.SetValueFromString(reg_info, value_str));
+ Status error(reg_value.SetValueFromString(reg_info, value_str));
if (error.Success()) {
if (reg_ctx->WriteRegister(reg_info, reg_value)) {
// Toss all frames and anything else in the thread
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.cpp
index 23fdcb9..d42466c 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSettings.cpp
@@ -15,6 +15,7 @@
#include "llvm/ADT/StringRef.h"
// Project includes
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -101,9 +102,9 @@ insert-before or insert-after.");
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -166,7 +167,7 @@ insert-before or insert-after.");
// Complete setting value
const char *setting_var_name =
input.GetArgumentAtIndex(setting_var_idx);
- Error error;
+ Status error;
lldb::OptionValueSP value_sp(
m_interpreter.GetDebugger().GetPropertyValue(
&m_exe_ctx, setting_var_name, false, error));
@@ -210,7 +211,7 @@ protected:
const char *var_value_cstr =
Args::StripSpaces(var_value_string, true, false, false);
- Error error;
+ Status error;
if (m_options.m_global) {
error = m_interpreter.GetDebugger().SetPropertyValue(
nullptr, eVarSetOperationAssign, var_name, var_value_cstr);
@@ -295,7 +296,7 @@ protected:
if (!args.empty()) {
for (const auto &arg : args) {
- Error error(m_interpreter.GetDebugger().DumpPropertyValue(
+ Status error(m_interpreter.GetDebugger().DumpPropertyValue(
&m_exe_ctx, result.GetOutputStream(), arg.ref,
OptionValue::eDumpGroupValue));
if (error.Success()) {
@@ -493,7 +494,7 @@ protected:
const char *var_value_cstr =
Args::StripSpaces(var_value_string, true, true, false);
- Error error(m_interpreter.GetDebugger().SetPropertyValue(
+ Status error(m_interpreter.GetDebugger().SetPropertyValue(
&m_exe_ctx, eVarSetOperationRemove, var_name, var_value_cstr));
if (error.Fail()) {
result.AppendError(error.AsCString());
@@ -601,7 +602,7 @@ protected:
const char *var_value_cstr =
Args::StripSpaces(var_value_string, true, true, false);
- Error error(m_interpreter.GetDebugger().SetPropertyValue(
+ Status error(m_interpreter.GetDebugger().SetPropertyValue(
&m_exe_ctx, eVarSetOperationReplace, var_name, var_value_cstr));
if (error.Fail()) {
result.AppendError(error.AsCString());
@@ -715,7 +716,7 @@ protected:
const char *var_value_cstr =
Args::StripSpaces(var_value_string, true, true, false);
- Error error(m_interpreter.GetDebugger().SetPropertyValue(
+ Status error(m_interpreter.GetDebugger().SetPropertyValue(
&m_exe_ctx, eVarSetOperationInsertBefore, var_name, var_value_cstr));
if (error.Fail()) {
result.AppendError(error.AsCString());
@@ -826,7 +827,7 @@ protected:
const char *var_value_cstr =
Args::StripSpaces(var_value_string, true, true, false);
- Error error(m_interpreter.GetDebugger().SetPropertyValue(
+ Status error(m_interpreter.GetDebugger().SetPropertyValue(
&m_exe_ctx, eVarSetOperationInsertAfter, var_name, var_value_cstr));
if (error.Fail()) {
result.AppendError(error.AsCString());
@@ -928,7 +929,7 @@ protected:
const char *var_value_cstr =
Args::StripSpaces(var_value_string, true, true, false);
- Error error(m_interpreter.GetDebugger().SetPropertyValue(
+ Status error(m_interpreter.GetDebugger().SetPropertyValue(
&m_exe_ctx, eVarSetOperationAppend, var_name, var_value_cstr));
if (error.Fail()) {
result.AppendError(error.AsCString());
@@ -1005,7 +1006,7 @@ protected:
return false;
}
- Error error(m_interpreter.GetDebugger().SetPropertyValue(
+ Status error(m_interpreter.GetDebugger().SetPropertyValue(
&m_exe_ctx, eVarSetOperationClear, var_name, llvm::StringRef()));
if (error.Fail()) {
result.AppendError(error.AsCString());
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp
index 6ff3208..f3c92b9 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp
@@ -18,8 +18,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/SourceManager.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -31,6 +30,7 @@
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/TargetList.h"
+#include "lldb/Utility/FileSpec.h"
using namespace lldb;
using namespace lldb_private;
@@ -59,9 +59,9 @@ class CommandObjectSourceInfo : public CommandObjectParsed {
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = GetDefinitions()[option_idx].short_option;
switch (short_option) {
case 'l':
@@ -683,9 +683,9 @@ class CommandObjectSourceList : public CommandObjectParsed {
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = GetDefinitions()[option_idx].short_option;
switch (short_option) {
case 'l':
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp
index d2e53aa..a80acf1 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp
@@ -16,9 +16,9 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Interpreter/Args.h"
@@ -49,6 +49,9 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/Timer.h"
+
+#include "llvm/Support/FileSystem.h"
// C Includes
// C++ Includes
@@ -266,8 +269,8 @@ protected:
}
const char *file_path = command.GetArgumentAtIndex(0);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "(lldb) target create '%s'",
- file_path);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "(lldb) target create '%s'", file_path);
FileSpec file_spec;
if (file_path)
@@ -281,7 +284,7 @@ protected:
llvm::StringRef arch_cstr = m_arch_option.GetArchitectureName();
const bool get_dependent_files =
m_add_dependents.GetOptionValue().GetCurrentValue();
- Error error(debugger.GetTargetList().CreateTarget(
+ Status error(debugger.GetTargetList().CreateTarget(
debugger, file_path, arch_cstr, get_dependent_files, nullptr,
target_sp));
@@ -300,7 +303,7 @@ protected:
if (file_spec && file_spec.Exists()) {
// if the remote file does not exist, push it there
if (!platform_sp->GetFileExists(remote_file)) {
- Error err = platform_sp->PutFile(file_spec, remote_file);
+ Status err = platform_sp->PutFile(file_spec, remote_file);
if (err.Fail()) {
result.AppendError(err.AsCString());
result.SetStatus(eReturnStatusFailed);
@@ -321,7 +324,7 @@ protected:
}
if (file_path) {
// copy the remote file to the local file
- Error err = platform_sp->GetFile(remote_file, file_spec);
+ Status err = platform_sp->GetFile(remote_file, file_spec);
if (err.Fail()) {
result.AppendError(err.AsCString());
result.SetStatus(eReturnStatusFailed);
@@ -836,7 +839,7 @@ protected:
matches = target->GetImages().FindGlobalVariables(
regex, true, UINT32_MAX, variable_list);
} else {
- Error error(Variable::GetValuesForVariableExpressionPath(
+ Status error(Variable::GetValuesForVariableExpressionPath(
arg, m_exe_ctx.GetBestExecutionContextScope(),
GetVariableCallback, target, variable_list, valobj_list));
matches = variable_list.GetSize();
@@ -1990,9 +1993,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -2512,7 +2515,7 @@ protected:
m_symbol_file.GetOptionValue().GetCurrentValue();
if (!module_spec.GetArchitecture().IsValid())
module_spec.GetArchitecture() = target->GetArchitecture();
- Error error;
+ Status error;
ModuleSP module_sp(target->GetSharedModule(module_spec, &error));
if (!module_sp) {
const char *error_cstr = error.AsCString();
@@ -2567,6 +2570,12 @@ public:
m_option_group(),
m_file_option(LLDB_OPT_SET_1, false, "file", 'f', 0, eArgTypeName,
"Fullpath or basename for module to load.", ""),
+ m_load_option(LLDB_OPT_SET_1, false, "load", 'l',
+ "Write file contents to the memory.", false, true),
+ m_pc_option(LLDB_OPT_SET_1, false, "--set-pc-to-entry", 'p',
+ "Set PC to the entry point."
+ " Only applicable with '--load' option.",
+ false, true),
m_slide_option(LLDB_OPT_SET_1, false, "slide", 's', 0, eArgTypeOffset,
"Set the load address for all sections to be the "
"virtual address in the file plus the offset.",
@@ -2574,6 +2583,8 @@ public:
m_option_group.Append(&m_uuid_option_group, LLDB_OPT_SET_ALL,
LLDB_OPT_SET_1);
m_option_group.Append(&m_file_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append(&m_load_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append(&m_pc_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Append(&m_slide_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Finalize();
}
@@ -2585,6 +2596,8 @@ public:
protected:
bool DoExecute(Args &args, CommandReturnObject &result) override {
Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ const bool load = m_load_option.GetOptionValue().GetCurrentValue();
+ const bool set_pc = m_pc_option.GetOptionValue().GetCurrentValue();
if (target == nullptr) {
result.AppendError("invalid target, create a debug target using the "
"'target create' command");
@@ -2594,6 +2607,21 @@ protected:
const size_t argc = args.GetArgumentCount();
ModuleSpec module_spec;
bool search_using_module_spec = false;
+
+ // Allow "load" option to work without --file or --uuid
+ // option.
+ if (load) {
+ if (!m_file_option.GetOptionValue().OptionWasSet() &&
+ !m_uuid_option_group.GetOptionValue().OptionWasSet()) {
+ ModuleList &module_list = target->GetImages();
+ if (module_list.GetSize() == 1) {
+ search_using_module_spec = true;
+ module_spec.GetFileSpec() =
+ module_list.GetModuleAtIndex(0)->GetFileSpec();
+ }
+ }
+ }
+
if (m_file_option.GetOptionValue().OptionWasSet()) {
search_using_module_spec = true;
const char *arg_cstr = m_file_option.GetOptionValue().GetCurrentValue();
@@ -2721,6 +2749,13 @@ protected:
if (process)
process->Flush();
}
+ if (load) {
+ Status error = module->LoadInMemory(*target, set_pc);
+ if (error.Fail()) {
+ result.AppendError(error.AsCString());
+ return false;
+ }
+ }
} else {
module->GetFileSpec().GetPath(path, sizeof(path));
result.AppendErrorWithFormat(
@@ -2783,6 +2818,8 @@ protected:
OptionGroupOptions m_option_group;
OptionGroupUUID m_uuid_option_group;
OptionGroupString m_file_option;
+ OptionGroupBoolean m_load_option;
+ OptionGroupBoolean m_pc_option;
OptionGroupUInt64 m_slide_option;
};
@@ -2820,9 +2857,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
if (short_option == 'g') {
@@ -3183,9 +3220,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
@@ -3389,6 +3426,23 @@ protected:
result.GetOutputStream().Printf("\n");
}
+ if (UnwindPlanSP plan_sp =
+ func_unwinders_sp->GetDebugFrameUnwindPlan(*target, 0)) {
+ result.GetOutputStream().Printf("debug_frame UnwindPlan:\n");
+ plan_sp->Dump(result.GetOutputStream(), thread.get(),
+ LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ if (UnwindPlanSP plan_sp =
+ func_unwinders_sp->GetDebugFrameAugmentedUnwindPlan(*target,
+ *thread, 0)) {
+ result.GetOutputStream().Printf("debug_frame augmented UnwindPlan:\n");
+ plan_sp->Dump(result.GetOutputStream(), thread.get(),
+ LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
UnwindPlanSP arm_unwind_sp =
func_unwinders_sp->GetArmUnwindUnwindPlan(*target, 0);
if (arm_unwind_sp) {
@@ -3483,9 +3537,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
@@ -4077,7 +4131,7 @@ protected:
// Make sure we load any scripting resources that may be embedded
// in the debug info files in case the platform supports that.
- Error error;
+ Status error;
StreamString feedback_stream;
module_sp->LoadScriptingResourceInTarget(target, error,
&feedback_stream);
@@ -4102,20 +4156,21 @@ protected:
module_sp->SetSymbolFileFileSpec(FileSpec());
}
+ namespace fs = llvm::sys::fs;
if (module_spec.GetUUID().IsValid()) {
StreamString ss_symfile_uuid;
module_spec.GetUUID().Dump(&ss_symfile_uuid);
result.AppendErrorWithFormat(
"symbol file '%s' (%s) does not match any existing module%s\n",
symfile_path, ss_symfile_uuid.GetData(),
- (symbol_fspec.GetFileType() != FileSpec::eFileTypeRegular)
+ !fs::is_regular_file(symbol_fspec.GetPath())
? "\n please specify the full path to the symbol file"
: "");
} else {
result.AppendErrorWithFormat(
"symbol file '%s' does not match any existing module%s\n",
symfile_path,
- (symbol_fspec.GetFileType() != FileSpec::eFileTypeRegular)
+ !fs::is_regular_file(symbol_fspec.GetPath())
? "\n please specify the full path to the symbol file"
: "");
}
@@ -4360,9 +4415,9 @@ public:
return llvm::makeArrayRef(g_target_stop_hook_add_options);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.cpp
index 0c4072b..6a933df 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectThread.cpp
@@ -17,6 +17,7 @@
#include "lldb/Core/State.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -41,10 +42,44 @@ using namespace lldb;
using namespace lldb_private;
//-------------------------------------------------------------------------
-// CommandObjectThreadBacktrace
+// CommandObjectIterateOverThreads
//-------------------------------------------------------------------------
class CommandObjectIterateOverThreads : public CommandObjectParsed {
+
+ class UniqueStack {
+
+ public:
+ UniqueStack(std::stack<lldb::addr_t> stack_frames, uint32_t thread_index_id)
+ : m_stack_frames(stack_frames) {
+ m_thread_index_ids.push_back(thread_index_id);
+ }
+
+ void AddThread(uint32_t thread_index_id) const {
+ m_thread_index_ids.push_back(thread_index_id);
+ }
+
+ const std::vector<uint32_t> &GetUniqueThreadIndexIDs() const {
+ return m_thread_index_ids;
+ }
+
+ lldb::tid_t GetRepresentativeThread() const {
+ return m_thread_index_ids.front();
+ }
+
+ friend bool inline operator<(const UniqueStack &lhs,
+ const UniqueStack &rhs) {
+ return lhs.m_stack_frames < rhs.m_stack_frames;
+ }
+
+ protected:
+ // Mark the thread index as mutable, as we don't care about it from a const
+ // perspective, we only care about m_stack_frames so we keep our std::set
+ // sorted.
+ mutable std::vector<uint32_t> m_thread_index_ids;
+ std::stack<lldb::addr_t> m_stack_frames;
+ };
+
public:
CommandObjectIterateOverThreads(CommandInterpreter &interpreter,
const char *name, const char *help,
@@ -56,11 +91,15 @@ public:
bool DoExecute(Args &command, CommandReturnObject &result) override {
result.SetStatus(m_success_return);
+ bool all_threads = false;
if (command.GetArgumentCount() == 0) {
Thread *thread = m_exe_ctx.GetThreadPtr();
if (!HandleOneThread(thread->GetID(), result))
return false;
return result.Succeeded();
+ } else if (command.GetArgumentCount() == 1) {
+ all_threads = ::strcmp(command.GetArgumentAtIndex(0), "all") == 0;
+ m_unique_stacks = ::strcmp(command.GetArgumentAtIndex(0), "unique") == 0;
}
// Use tids instead of ThreadSPs to prevent deadlocking problems which
@@ -68,8 +107,7 @@ public:
// code while iterating over the (locked) ThreadSP list.
std::vector<lldb::tid_t> tids;
- if (command.GetArgumentCount() == 1 &&
- ::strcmp(command.GetArgumentAtIndex(0), "all") == 0) {
+ if (all_threads || m_unique_stacks) {
Process *process = m_exe_ctx.GetProcessPtr();
for (ThreadSP thread_sp : process->Threads())
@@ -107,15 +145,47 @@ public:
}
}
- uint32_t idx = 0;
- for (const lldb::tid_t &tid : tids) {
- if (idx != 0 && m_add_return)
- result.AppendMessage("");
+ if (m_unique_stacks) {
+ // Iterate over threads, finding unique stack buckets.
+ std::set<UniqueStack> unique_stacks;
+ for (const lldb::tid_t &tid : tids) {
+ if (!BucketThread(tid, unique_stacks, result)) {
+ return false;
+ }
+ }
- if (!HandleOneThread(tid, result))
- return false;
+ // Write the thread id's and unique call stacks to the output stream
+ Stream &strm = result.GetOutputStream();
+ Process *process = m_exe_ctx.GetProcessPtr();
+ for (const UniqueStack &stack : unique_stacks) {
+ // List the common thread ID's
+ const std::vector<uint32_t> &thread_index_ids =
+ stack.GetUniqueThreadIndexIDs();
+ strm.Format("{0} thread(s) ", thread_index_ids.size());
+ for (const uint32_t &thread_index_id : thread_index_ids) {
+ strm.Format("#{0} ", thread_index_id);
+ }
+ strm.EOL();
- ++idx;
+ // List the shared call stack for this set of threads
+ uint32_t representative_thread_id = stack.GetRepresentativeThread();
+ ThreadSP thread = process->GetThreadList().FindThreadByIndexID(
+ representative_thread_id);
+ if (!HandleOneThread(thread->GetID(), result)) {
+ return false;
+ }
+ }
+ } else {
+ uint32_t idx = 0;
+ for (const lldb::tid_t &tid : tids) {
+ if (idx != 0 && m_add_return)
+ result.AppendMessage("");
+
+ if (!HandleOneThread(tid, result))
+ return false;
+
+ ++idx;
+ }
}
return result.Succeeded();
}
@@ -133,7 +203,43 @@ protected:
virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result) = 0;
+ bool BucketThread(lldb::tid_t tid, std::set<UniqueStack> &unique_stacks,
+ CommandReturnObject &result) {
+ // Grab the corresponding thread for the given thread id.
+ Process *process = m_exe_ctx.GetProcessPtr();
+ Thread *thread = process->GetThreadList().FindThreadByID(tid).get();
+ if (thread == nullptr) {
+ result.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // Collect the each frame's address for this call-stack
+ std::stack<lldb::addr_t> stack_frames;
+ const uint32_t frame_count = thread->GetStackFrameCount();
+ for (uint32_t frame_index = 0; frame_index < frame_count; frame_index++) {
+ const lldb::StackFrameSP frame_sp =
+ thread->GetStackFrameAtIndex(frame_index);
+ const lldb::addr_t pc = frame_sp->GetStackID().GetPC();
+ stack_frames.push(pc);
+ }
+
+ uint32_t thread_index_id = thread->GetIndexID();
+ UniqueStack new_unique_stack(stack_frames, thread_index_id);
+
+ // Try to match the threads stack to and existing entry.
+ std::set<UniqueStack>::iterator matching_stack =
+ unique_stacks.find(new_unique_stack);
+ if (matching_stack != unique_stacks.end()) {
+ matching_stack->AddThread(thread_index_id);
+ } else {
+ unique_stacks.insert(new_unique_stack);
+ }
+ return true;
+ }
+
ReturnStatus m_success_return = eReturnStatusSuccessFinishResult;
+ bool m_unique_stacks = false;
bool m_add_return = true;
};
@@ -161,9 +267,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -217,9 +323,10 @@ public:
: CommandObjectIterateOverThreads(
interpreter, "thread backtrace",
"Show thread call stacks. Defaults to the current thread, thread "
- "indexes can be specified as arguments. Use the thread-index "
- "\"all\" "
- "to see all threads.",
+ "indexes can be specified as arguments.\n"
+ "Use the thread-index \"all\" to see all threads.\n"
+ "Use the thread-index \"unique\" to see threads grouped by unique "
+ "call stacks.",
nullptr,
eCommandRequiresProcess | eCommandRequiresThread |
eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
@@ -269,11 +376,14 @@ protected:
Stream &strm = result.GetOutputStream();
+ // Only dump stack info if we processing unique stacks.
+ const bool only_stacks = m_unique_stacks;
+
// Don't show source context when doing backtraces.
const uint32_t num_frames_with_source = 0;
const bool stop_format = true;
if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count,
- num_frames_with_source, stop_format)) {
+ num_frames_with_source, stop_format, only_stacks)) {
result.AppendErrorWithFormat(
"error displaying backtrace for thread: \"0x%4.4x\"\n",
thread->GetIndexID());
@@ -329,9 +439,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -555,7 +665,7 @@ protected:
AddressRange range;
SymbolContext sc = frame->GetSymbolContext(eSymbolContextEverything);
if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER) {
- Error error;
+ Status error;
if (!sc.GetAddressRangeFromHereToEndLine(m_options.m_end_line, range,
error)) {
result.AppendErrorWithFormat("invalid end-line option: %s.",
@@ -564,7 +674,7 @@ protected:
return false;
}
} else if (m_options.m_end_line_is_block_end) {
- Error error;
+ Status error;
Block *block = frame->GetSymbolContext(eSymbolContextBlock).block;
if (!block) {
result.AppendErrorWithFormat("Could not find the current block.");
@@ -648,7 +758,7 @@ protected:
new_plan_sp->SetOkayToDiscard(false);
if (m_options.m_step_count > 1) {
- if (new_plan_sp->SetIterationCount(m_options.m_step_count)) {
+ if (!new_plan_sp->SetIterationCount(m_options.m_step_count)) {
result.AppendWarning(
"step operation does not support iteration count.");
}
@@ -659,7 +769,7 @@ protected:
const uint32_t iohandler_id = process->GetIOHandlerID();
StreamString stream;
- Error error;
+ Status error;
if (synchronous_execution)
error = process->ResumeSynchronous(&stream);
else
@@ -840,7 +950,7 @@ public:
}
StreamString stream;
- Error error;
+ Status error;
if (synchronous_execution)
error = process->ResumeSynchronous(&stream);
else
@@ -907,9 +1017,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1173,7 +1283,7 @@ protected:
process->GetThreadList().SetSelectedThreadByID(m_options.m_thread_idx);
StreamString stream;
- Error error;
+ Status error;
if (synchronous_execution)
error = process->ResumeSynchronous(&stream);
else
@@ -1324,10 +1434,10 @@ public:
m_json_stopinfo = false;
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
const int short_option = m_getopt_table[option_idx].val;
- Error error;
+ Status error;
switch (short_option) {
case 'j':
@@ -1339,7 +1449,7 @@ public:
break;
default:
- return Error("invalid short option character '%c'", short_option);
+ return Status("invalid short option character '%c'", short_option);
}
return error;
}
@@ -1417,9 +1527,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1497,7 +1607,7 @@ protected:
"called expressions");
Thread *thread = m_exe_ctx.GetThreadPtr();
- Error error;
+ Status error;
error = thread->UnwindInnermostExpression();
if (!error.Success()) {
result.AppendErrorWithFormat("Unwinding expression failed - %s.",
@@ -1552,7 +1662,7 @@ protected:
}
}
- Error error;
+ Status error;
ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
const bool broadcast = true;
error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast);
@@ -1601,24 +1711,24 @@ public:
m_force = false;
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
const int short_option = m_getopt_table[option_idx].val;
- Error error;
+ Status error;
switch (short_option) {
case 'f':
m_filenames.AppendIfUnique(FileSpec(option_arg, false));
if (m_filenames.GetSize() > 1)
- return Error("only one source file expected.");
+ return Status("only one source file expected.");
break;
case 'l':
if (option_arg.getAsInteger(0, m_line_num))
- return Error("invalid line number: '%s'.", option_arg.str().c_str());
+ return Status("invalid line number: '%s'.", option_arg.str().c_str());
break;
case 'b':
if (option_arg.getAsInteger(0, m_line_offset))
- return Error("invalid line offset: '%s'.", option_arg.str().c_str());
+ return Status("invalid line offset: '%s'.", option_arg.str().c_str());
break;
case 'a':
m_load_addr = Args::StringToAddress(execution_context, option_arg,
@@ -1628,7 +1738,7 @@ public:
m_force = true;
break;
default:
- return Error("invalid short option character '%c'", short_option);
+ return Status("invalid short option character '%c'", short_option);
}
return error;
}
@@ -1701,7 +1811,7 @@ protected:
}
std::string warnings;
- Error err = thread->JumpToLine(file, line, m_options.m_force, &warnings);
+ Status err = thread->JumpToLine(file, line, m_options.m_force, &warnings);
if (err.Fail()) {
result.SetError(err);
@@ -1746,9 +1856,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp
index 621ef58..2d4271c 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp
@@ -16,13 +16,11 @@
#include <functional>
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/IOHandler.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/StringList.h"
#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -38,6 +36,9 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadList.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/StringList.h"
// Other libraries and framework includes
#include "llvm/ADT/STLExtras.h"
@@ -82,9 +83,9 @@ static bool WarnOnPotentialUnquotedUnsignedType(Args &command,
return false;
for (auto entry : llvm::enumerate(command.entries().drop_back())) {
- if (entry.Value.ref != "unsigned")
+ if (entry.value().ref != "unsigned")
continue;
- auto next = command.entries()[entry.Index + 1].ref;
+ auto next = command.entries()[entry.index() + 1].ref;
if (next == "int" || next == "short" || next == "char" || next == "long") {
result.AppendWarningWithFormat(
"unsigned %s being treated as two types. if you meant the combined "
@@ -126,8 +127,8 @@ private:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override;
void OptionParsingStarting(ExecutionContext *execution_context) override;
@@ -212,7 +213,7 @@ public:
options->m_flags, funct_name_str.c_str(),
lines.CopyList(" ").c_str()));
- Error error;
+ Status error;
for (size_t i = 0; i < options->m_target_types.GetSize(); i++) {
const char *type_name =
@@ -282,7 +283,7 @@ public:
static bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry,
SummaryFormatType type, std::string category,
- Error *error = nullptr);
+ Status *error = nullptr);
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override;
@@ -320,9 +321,9 @@ private:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
bool success;
@@ -463,7 +464,7 @@ protected:
DataVisualization::Categories::GetCategory(
ConstString(options->m_category.c_str()), category);
- Error error;
+ Status error;
for (size_t i = 0; i < options->m_target_types.GetSize(); i++) {
const char *type_name =
@@ -522,7 +523,7 @@ public:
static bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry,
SynthFormatType type, std::string category_name,
- Error *error);
+ Status *error);
};
//-------------------------------------------------------------------------
@@ -561,9 +562,9 @@ private:
m_custom_type_name.clear();
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option =
g_type_format_add_options[option_idx].short_option;
bool success;
@@ -768,9 +769,9 @@ protected:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -908,9 +909,9 @@ private:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1024,9 +1025,9 @@ class CommandObjectTypeFormatterList : public CommandObjectParsed {
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'w':
@@ -1188,8 +1189,7 @@ protected:
category_closure(category_sp);
} else {
DataVisualization::Categories::ForEach(
- [this, &command, &result, &category_regex, &formatter_regex,
- &category_closure](
+ [&category_regex, &category_closure](
const lldb::TypeCategoryImplSP &category) -> bool {
if (category_regex) {
bool escape = true;
@@ -1243,10 +1243,10 @@ public:
#endif // LLDB_DISABLE_PYTHON
-Error CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
+Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
- Error error;
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
bool success;
@@ -1423,7 +1423,7 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
// if I am here, script_format must point to something good, so I can add that
// as a script summary to all interested parties
- Error error;
+ Status error;
for (auto &entry : command.entries()) {
CommandObjectTypeSummaryAdd::AddSummary(
@@ -1498,7 +1498,7 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
lldb::TypeSummaryImplSP entry(string_format.release());
// now I have a valid format, let's add it to every type
- Error error;
+ Status error;
for (auto &arg_entry : command.entries()) {
if (arg_entry.ref.empty()) {
result.AppendError("empty typenames not allowed");
@@ -1681,7 +1681,7 @@ bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
TypeSummaryImplSP entry,
SummaryFormatType type,
std::string category_name,
- Error *error) {
+ Status *error) {
lldb::TypeCategoryImplSP category;
DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
category);
@@ -1799,9 +1799,9 @@ class CommandObjectTypeCategoryDefine : public CommandObjectParsed {
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -1903,9 +1903,9 @@ class CommandObjectTypeCategoryEnable : public CommandObjectParsed {
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -2080,9 +2080,9 @@ class CommandObjectTypeCategoryDisable : public CommandObjectParsed {
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -2407,7 +2407,7 @@ bool CommandObjectTypeSynthAdd::Execute_PythonClass(
DataVisualization::Categories::GetCategory(
ConstString(m_options.m_category.c_str()), category);
- Error error;
+ Status error;
for (auto &arg_entry : command.entries()) {
if (arg_entry.ref.empty()) {
@@ -2450,7 +2450,7 @@ bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
SyntheticChildrenSP entry,
SynthFormatType type,
std::string category_name,
- Error *error) {
+ Status *error) {
lldb::TypeCategoryImplSP category;
DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
category);
@@ -2512,9 +2512,9 @@ private:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
bool success;
@@ -2586,7 +2586,7 @@ private:
bool AddFilter(ConstString type_name, TypeFilterImplSP entry,
FilterFormatType type, std::string category_name,
- Error *error) {
+ Status *error) {
lldb::TypeCategoryImplSP category;
DataVisualization::Categories::GetCategory(
ConstString(category_name.c_str()), category);
@@ -2717,7 +2717,7 @@ protected:
DataVisualization::Categories::GetCategory(
ConstString(m_options.m_category.c_str()), category);
- Error error;
+ Status error;
WarnOnPotentialUnquotedUnsignedType(command, result);
@@ -2787,9 +2787,9 @@ protected:
return llvm::makeArrayRef(g_type_lookup_options);
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = g_type_lookup_options[option_idx].short_option;
@@ -2899,7 +2899,7 @@ public:
if (!ParseOptions(args, result))
return false;
- Error error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
+ Status error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
if (error.Fail()) {
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.cpp
index baa9f41..9c84c99 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpoint.cpp
@@ -20,10 +20,9 @@
// Project includes
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Breakpoint/WatchpointList.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectVariable.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -31,6 +30,7 @@
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -197,9 +197,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -245,7 +245,7 @@ protected:
if (target->GetProcessSP() && target->GetProcessSP()->IsAlive()) {
uint32_t num_supported_hardware_watchpoints;
- Error error = target->GetProcessSP()->GetWatchpointSupportInfo(
+ Status error = target->GetProcessSP()->GetWatchpointSupportInfo(
num_supported_hardware_watchpoints);
if (error.Success())
result.AppendMessageWithFormat(
@@ -561,9 +561,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -689,9 +689,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -881,7 +881,7 @@ protected:
}
// Things have checked out ok...
- Error error;
+ Status error;
uint32_t expr_path_options =
StackFrame::eExpressionPathOptionCheckPtrVsMember |
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
@@ -895,7 +895,7 @@ protected:
VariableList variable_list;
ValueObjectList valobj_list;
- Error error(Variable::GetValuesForVariableExpressionPath(
+ Status error(Variable::GetValuesForVariableExpressionPath(
command.GetArgumentAtIndex(0),
m_exe_ctx.GetBestExecutionContextScope(), GetVariableCallback, target,
variable_list, valobj_list));
@@ -1060,7 +1060,7 @@ protected:
if (!ParseOptions(args, result))
return false;
- Error error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
+ Status error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
if (error.Fail()) {
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
@@ -1135,7 +1135,7 @@ protected:
/// of the expression, so convert to that if we found a valid type.
CompilerType compiler_type(valobj_sp->GetCompilerType());
- Error error;
+ Status error;
Watchpoint *wp =
target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error)
.get();
diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
index 1860d4c..ec7e4a1 100644
--- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
+++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -19,6 +19,7 @@
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/State.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Target.h"
@@ -318,9 +319,9 @@ are no syntax errors may indicate that a function was declared but never called.
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Core/Address.cpp b/contrib/llvm/tools/lldb/source/Core/Address.cpp
index e2ccf9d..0c929c2 100644
--- a/contrib/llvm/tools/lldb/source/Core/Address.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Address.cpp
@@ -9,23 +9,53 @@
#include "lldb/Core/Address.h"
-// C Includes
-// C++ Includes
-#include "llvm/ADT/Triple.h"
-
-// Other libraries and framework includes
-// Project includes
+#include "lldb/Core/ArchSpec.h" // for ArchSpec
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h" // for ModuleList
#include "lldb/Core/Section.h"
#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Declaration.h" // for Declaration
+#include "lldb/Symbol/LineEntry.h" // for LineEntry
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h" // for Symbol
+#include "lldb/Symbol/SymbolContext.h" // for SymbolContext
#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Symtab.h" // for Symtab
+#include "lldb/Symbol/Type.h" // for Type
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h" // for ExecutionContextScope
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/DataExtractor.h" // for DataExtractor
+#include "lldb/Utility/Endian.h" // for InlHostByteOrder
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h" // for StreamString
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
+
+#include <cstdint> // for uint8_t, uint32_t
+#include <memory> // for shared_ptr, operator!=
+#include <vector> // for vector
+
+#include <assert.h> // for assert
+#include <inttypes.h> // for PRIu64, PRIx64
+#include <string.h> // for size_t, strlen
+
+namespace lldb_private {
+class CompileUnit;
+}
+namespace lldb_private {
+class Function;
+}
using namespace lldb;
using namespace lldb_private;
@@ -37,7 +67,7 @@ static size_t ReadBytes(ExecutionContextScope *exe_scope,
TargetSP target_sp(exe_scope->CalculateTarget());
if (target_sp) {
- Error error;
+ Status error;
bool prefer_file_cache = false;
return target_sp->ReadMemory(address, prefer_file_cache, dst, dst_len,
error);
@@ -143,15 +173,15 @@ static bool DumpUInt(ExecutionContextScope *exe_scope, const Address &address,
if (GetByteOrderAndAddressSize(exe_scope, address, byte_order, addr_size)) {
DataExtractor data(&buf.front(), buf.size(), byte_order, addr_size);
- data.Dump(strm,
- 0, // Start offset in "data"
- eFormatHex, // Print as characters
- buf.size(), // Size of item
- 1, // Items count
- UINT32_MAX, // num per line
- LLDB_INVALID_ADDRESS, // base address
- 0, // bitfield bit size
- 0); // bitfield bit offset
+ DumpDataExtractor(data, strm,
+ 0, // Start offset in "data"
+ eFormatHex, // Print as characters
+ buf.size(), // Size of item
+ 1, // Items count
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS, // base address
+ 0, // bitfield bit size
+ 0); // bitfield bit offset
return true;
}
@@ -181,16 +211,16 @@ static size_t ReadCStringFromMemory(ExecutionContextScope *exe_scope,
if (len > bytes_read)
len = bytes_read;
- data.Dump(strm,
- 0, // Start offset in "data"
- eFormatChar, // Print as characters
- 1, // Size of item (1 byte for a char!)
- len, // How many bytes to print?
- UINT32_MAX, // num per line
- LLDB_INVALID_ADDRESS, // base address
- 0, // bitfield bit size
+ DumpDataExtractor(data, strm,
+ 0, // Start offset in "data"
+ eFormatChar, // Print as characters
+ 1, // Size of item (1 byte for a char!)
+ len, // How many bytes to print?
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS, // base address
+ 0, // bitfield bit size
- 0); // bitfield bit offset
+ 0); // bitfield bit offset
total_len += bytes_read;
@@ -292,7 +322,7 @@ addr_t Address::GetCallableLoadAddress(Target *target, bool is_indirect) const {
if (is_indirect && target) {
ProcessSP processSP = target->GetProcessSP();
- Error error;
+ Status error;
if (processSP) {
code_addr = processSP->ResolveIndirectFunction(this, error);
if (!error.Success())
@@ -331,8 +361,9 @@ addr_t Address::GetOpcodeLoadAddress(Target *target,
}
bool Address::SetOpcodeLoadAddress(lldb::addr_t load_addr, Target *target,
- AddressClass addr_class) {
- if (SetLoadAddress(load_addr, target)) {
+ AddressClass addr_class,
+ bool allow_section_end) {
+ if (SetLoadAddress(load_addr, target, allow_section_end)) {
if (target) {
if (addr_class == eAddressClassInvalid)
addr_class = GetAddressClass();
@@ -704,7 +735,7 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
if (process) {
addr_t load_addr = GetLoadAddress(target);
if (load_addr != LLDB_INVALID_ADDRESS) {
- Error memory_error;
+ Status memory_error;
addr_t dereferenced_load_addr =
process->ReadPointerFromMemory(load_addr, memory_error);
if (dereferenced_load_addr != LLDB_INVALID_ADDRESS) {
@@ -971,9 +1002,10 @@ AddressClass Address::GetAddressClass() const {
return eAddressClassUnknown;
}
-bool Address::SetLoadAddress(lldb::addr_t load_addr, Target *target) {
- if (target &&
- target->GetSectionLoadList().ResolveLoadAddress(load_addr, *this))
+bool Address::SetLoadAddress(lldb::addr_t load_addr, Target *target,
+ bool allow_section_end) {
+ if (target && target->GetSectionLoadList().ResolveLoadAddress(
+ load_addr, *this, allow_section_end))
return true;
m_section_wp.reset();
m_offset = load_addr;
diff --git a/contrib/llvm/tools/lldb/source/Core/AddressRange.cpp b/contrib/llvm/tools/lldb/source/Core/AddressRange.cpp
index e03d721..c150779 100644
--- a/contrib/llvm/tools/lldb/source/Core/AddressRange.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/AddressRange.cpp
@@ -8,10 +8,23 @@
//===----------------------------------------------------------------------===//
#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/ArchSpec.h" // for ArchSpec
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+
+#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
+
+#include <memory> // for shared_ptr
+
+#include <inttypes.h> // for PRIx64
+
+namespace lldb_private {
+class SectionList;
+}
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/AddressResolver.cpp b/contrib/llvm/tools/lldb/source/Core/AddressResolver.cpp
index 40f4d55..8d7cc9f 100644
--- a/contrib/llvm/tools/lldb/source/Core/AddressResolver.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/AddressResolver.cpp
@@ -9,16 +9,11 @@
#include "lldb/Core/AddressResolver.h"
-// Project includes
-
-#include "lldb/Core/Address.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/ModuleList.h"
#include "lldb/Core/SearchFilter.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Target/Target.h"
+
+namespace lldb_private {
+class ModuleList;
+}
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/AddressResolverFileLine.cpp b/contrib/llvm/tools/lldb/source/Core/AddressResolverFileLine.cpp
index 939cf45..798a9b5 100644
--- a/contrib/llvm/tools/lldb/source/Core/AddressResolverFileLine.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/AddressResolverFileLine.cpp
@@ -9,11 +9,21 @@
#include "lldb/Core/AddressResolverFileLine.h"
-// Project includes
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Address.h" // for Address
+#include "lldb/Core/AddressRange.h" // for AddressRange
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineEntry.h" // for LineEntry
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet, LIB...
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-enumerations.h" // for SymbolContextItem::eSymbolCon...
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <inttypes.h> // for PRIx64
+#include <vector> // for vector
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/AddressResolverName.cpp b/contrib/llvm/tools/lldb/source/Core/AddressResolverName.cpp
index d9b6dad..9935362 100644
--- a/contrib/llvm/tools/lldb/source/Core/AddressResolverName.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/AddressResolverName.cpp
@@ -9,16 +9,25 @@
#include "lldb/Core/AddressResolverName.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Log.h"
+#include "lldb/Core/Address.h" // for Address, operator==
+#include "lldb/Core/AddressRange.h" // for AddressRange
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet, LIB...
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/lldb-enumerations.h" // for SymbolType::eSymbolTypeCode
+#include "lldb/lldb-forward.h" // for ModuleSP
+#include "lldb/lldb-types.h" // for addr_t
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <memory> // for shared_ptr
+#include <string> // for string
+#include <vector> // for vector
+
+#include <stdint.h> // for uint32_t
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/ArchSpec.cpp b/contrib/llvm/tools/lldb/source/Core/ArchSpec.cpp
index cf7afb8..bfe9750f 100644
--- a/contrib/llvm/tools/lldb/source/Core/ArchSpec.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ArchSpec.cpp
@@ -9,31 +9,30 @@
#include "lldb/Core/ArchSpec.h"
-// C Includes
-// C++ Includes
-#include <cerrno>
-#include <cstdio>
-#include <string>
-
-// Other libraries and framework includes
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/COFF.h"
-#include "llvm/Support/ELF.h"
-#include "llvm/Support/Host.h"
-
-// Project includes
-#include "Plugins/Process/Utility/ARMDefines.h"
-#include "Plugins/Process/Utility/InstructionUtils.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/StringList.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Platform.h"
-#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/NameMatches.h"
-#include "lldb/Utility/SafeMachO.h"
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StringList.h"
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_C...
+#include "lldb/lldb-forward.h" // for RegisterContextSP
+
+#include "Plugins/Process/Utility/ARMDefines.h"
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h" // for Twine
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/MachO.h" // for CPUType::CPU_T...
+#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
+#include "llvm/Support/Host.h"
+
+#include <memory> // for shared_ptr
+#include <string>
+#include <tuple> // for tie, tuple
using namespace lldb;
using namespace lldb_private;
@@ -259,7 +258,7 @@ struct ArchDefinition {
size_t ArchSpec::AutoComplete(llvm::StringRef name, StringList &matches) {
if (!name.empty()) {
for (uint32_t i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) {
- if (NameMatches(g_core_definitions[i].name, eNameMatchStartsWith, name))
+ if (NameMatches(g_core_definitions[i].name, NameMatch::StartsWith, name))
matches.AppendString(g_core_definitions[i].name);
}
} else {
@@ -657,7 +656,7 @@ void ArchSpec::SetFlags(std::string elf_abi) {
SetFlags(flag);
}
-std::string ArchSpec::GetClangTargetCPU() {
+std::string ArchSpec::GetClangTargetCPU() const {
std::string cpu;
const llvm::Triple::ArchType machine = GetMachine();
@@ -835,19 +834,7 @@ lldb::ByteOrder ArchSpec::GetByteOrder() const {
bool ArchSpec::SetTriple(const llvm::Triple &triple) {
m_triple = triple;
-
- llvm::StringRef arch_name(m_triple.getArchName());
- const CoreDefinition *core_def = FindCoreDefinition(arch_name);
- if (core_def) {
- m_core = core_def->core;
- // Set the byte order to the default byte order for an architecture.
- // This can be modified if needed for cases when cores handle both
- // big and little endian
- m_byte_order = core_def->default_byte_order;
- } else {
- Clear();
- }
-
+ UpdateCore();
return IsValid();
}
@@ -995,8 +982,10 @@ void ArchSpec::MergeFrom(const ArchSpec &other) {
GetTriple().setVendor(other.GetTriple().getVendor());
if (TripleOSIsUnspecifiedUnknown() && !other.TripleOSIsUnspecifiedUnknown())
GetTriple().setOS(other.GetTriple().getOS());
- if (GetTriple().getArch() == llvm::Triple::UnknownArch)
+ if (GetTriple().getArch() == llvm::Triple::UnknownArch) {
GetTriple().setArch(other.GetTriple().getArch());
+ UpdateCore();
+ }
if (GetTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
!TripleVendorWasSpecified()) {
if (other.TripleVendorWasSpecified())
@@ -1191,6 +1180,20 @@ bool ArchSpec::IsEqualTo(const ArchSpec &rhs, bool exact_match) const {
return false;
}
+void ArchSpec::UpdateCore() {
+ llvm::StringRef arch_name(m_triple.getArchName());
+ const CoreDefinition *core_def = FindCoreDefinition(arch_name);
+ if (core_def) {
+ m_core = core_def->core;
+ // Set the byte order to the default byte order for an architecture.
+ // This can be modified if needed for cases when cores handle both
+ // big and little endian
+ m_byte_order = core_def->default_byte_order;
+ } else {
+ Clear();
+ }
+}
+
//===----------------------------------------------------------------------===//
// Helper methods.
@@ -1380,7 +1383,7 @@ static bool cores_match(const ArchSpec::Core core1, const ArchSpec::Core core2,
if (core2 >= ArchSpec::kCore_mips32el_first &&
core2 <= ArchSpec::kCore_mips32el_last)
return true;
- try_inverse = false;
+ try_inverse = true;
}
break;
@@ -1552,7 +1555,7 @@ static void StopInfoOverrideCallbackTypeARM(lldb_private::Thread &thread) {
#if 0
// ARM mode: check for condition on intsruction
const addr_t pc = reg_ctx_sp->GetPC();
- Error error;
+ Status error;
// If we fail to read the opcode we will get UINT64_MAX as the
// result in "opcode" which we can use to detect if we read a
// valid opcode.
@@ -1632,7 +1635,7 @@ void ArchSpec::PiecewiseTripleCompare(
}
bool ArchSpec::IsAlwaysThumbInstructions() const {
- std::string Error;
+ std::string Status;
if (GetTriple().getArch() == llvm::Triple::arm ||
GetTriple().getArch() == llvm::Triple::thumb) {
// v. https://en.wikipedia.org/wiki/ARM_Cortex-M
diff --git a/contrib/llvm/tools/lldb/source/Core/Broadcaster.cpp b/contrib/llvm/tools/lldb/source/Core/Broadcaster.cpp
index d2cca7a..7a4932c 100644
--- a/contrib/llvm/tools/lldb/source/Core/Broadcaster.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Broadcaster.cpp
@@ -9,21 +9,26 @@
#include "lldb/Core/Broadcaster.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/Event.h"
#include "lldb/Core/Listener.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for GetLogIfAnyCategoriesSet, Get...
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+
+#include <algorithm> // for find_if
+#include <memory> // for make_shared
+#include <type_traits> // for move
+
+#include <assert.h> // for assert
+#include <stddef.h> // for size_t
using namespace lldb;
using namespace lldb_private;
Broadcaster::Broadcaster(BroadcasterManagerSP manager_sp, const char *name)
- : m_broadcaster_sp(new BroadcasterImpl(*this)), m_manager_sp(manager_sp),
- m_broadcaster_name(name) {
+ : m_broadcaster_sp(std::make_shared<BroadcasterImpl>(*this)),
+ m_manager_sp(manager_sp), m_broadcaster_name(name) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
if (log)
log->Printf("%p Broadcaster::Broadcaster(\"%s\")",
@@ -242,19 +247,19 @@ void Broadcaster::BroadcasterImpl::PrivateBroadcastEvent(EventSP &event_sp,
void Broadcaster::BroadcasterImpl::BroadcastEvent(uint32_t event_type,
EventData *event_data) {
- EventSP event_sp(new Event(event_type, event_data));
+ auto event_sp = std::make_shared<Event>(event_type, event_data);
PrivateBroadcastEvent(event_sp, false);
}
void Broadcaster::BroadcasterImpl::BroadcastEvent(
uint32_t event_type, const lldb::EventDataSP &event_data_sp) {
- EventSP event_sp(new Event(event_type, event_data_sp));
+ auto event_sp = std::make_shared<Event>(event_type, event_data_sp);
PrivateBroadcastEvent(event_sp, false);
}
void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(
uint32_t event_type, EventData *event_data) {
- EventSP event_sp(new Event(event_type, event_data));
+ auto event_sp = std::make_shared<Event>(event_type, event_data);
PrivateBroadcastEvent(event_sp, true);
}
@@ -329,7 +334,7 @@ operator=(const BroadcastEventSpec &rhs) = default;
BroadcasterManager::BroadcasterManager() : m_manager_mutex() {}
lldb::BroadcasterManagerSP BroadcasterManager::MakeBroadcasterManager() {
- return BroadcasterManagerSP(new BroadcasterManager());
+ return lldb::BroadcasterManagerSP(new BroadcasterManager());
}
uint32_t BroadcasterManager::RegisterListenerForEvents(
diff --git a/contrib/llvm/tools/lldb/source/Core/Communication.cpp b/contrib/llvm/tools/lldb/source/Core/Communication.cpp
index 3d3abea..38ab902 100644
--- a/contrib/llvm/tools/lldb/source/Core/Communication.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Communication.cpp
@@ -7,21 +7,30 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-#include <cstring>
-
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/Communication.h"
-#include "lldb/Core/Connection.h"
+
#include "lldb/Core/Event.h"
#include "lldb/Core/Listener.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Timer.h"
-#include "lldb/Host/Host.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Utility/Connection.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for LogIfAnyCategoriesSet, LIBLLDB...
+#include "lldb/Utility/Status.h" // for Status
+
+#include "llvm/ADT/None.h" // for None
+#include "llvm/ADT/Optional.h" // for Optional
+#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
+
+#include <algorithm> // for min
+#include <chrono> // for duration, seconds
+#include <cstring>
+#include <memory> // for shared_ptr
+
+#include <errno.h> // for EIO
+#include <inttypes.h> // for PRIu64
+#include <stdio.h> // for snprintf
using namespace lldb;
using namespace lldb_private;
@@ -66,7 +75,7 @@ void Communication::Clear() {
StopReadThread(nullptr);
}
-ConnectionStatus Communication::Connect(const char *url, Error *error_ptr) {
+ConnectionStatus Communication::Connect(const char *url, Status *error_ptr) {
Clear();
lldb_private::LogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION,
@@ -81,7 +90,7 @@ ConnectionStatus Communication::Connect(const char *url, Error *error_ptr) {
return eConnectionStatusNoConnection;
}
-ConnectionStatus Communication::Disconnect(Error *error_ptr) {
+ConnectionStatus Communication::Disconnect(Status *error_ptr) {
lldb_private::LogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION,
"%p Communication::Disconnect ()", this);
@@ -114,13 +123,12 @@ bool Communication::HasConnection() const {
size_t Communication::Read(void *dst, size_t dst_len,
const Timeout<std::micro> &timeout,
- ConnectionStatus &status, Error *error_ptr) {
- lldb_private::LogIfAnyCategoriesSet(
- LIBLLDB_LOG_COMMUNICATION,
- "%p Communication::Read (dst = %p, dst_len = %" PRIu64
- ", timeout = %u usec) connection = %p",
- this, dst, (uint64_t)dst_len, timeout ? timeout->count() : -1,
- m_connection_sp.get());
+ ConnectionStatus &status, Status *error_ptr) {
+ Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION);
+ LLDB_LOG(
+ log,
+ "this = {0}, dst = {1}, dst_len = {2}, timeout = {3}, connection = {4}",
+ this, dst, dst_len, timeout, m_connection_sp.get());
if (m_read_thread_enabled) {
// We have a dedicated read thread that is getting data for us
@@ -162,7 +170,7 @@ size_t Communication::Read(void *dst, size_t dst_len,
}
size_t Communication::Write(const void *src, size_t src_len,
- ConnectionStatus &status, Error *error_ptr) {
+ ConnectionStatus &status, Status *error_ptr) {
lldb::ConnectionSP connection_sp(m_connection_sp);
std::lock_guard<std::mutex> guard(m_write_mutex);
@@ -181,7 +189,7 @@ size_t Communication::Write(const void *src, size_t src_len,
return 0;
}
-bool Communication::StartReadThread(Error *error_ptr) {
+bool Communication::StartReadThread(Status *error_ptr) {
if (error_ptr)
error_ptr->Clear();
@@ -204,7 +212,7 @@ bool Communication::StartReadThread(Error *error_ptr) {
return m_read_thread_enabled;
}
-bool Communication::StopReadThread(Error *error_ptr) {
+bool Communication::StopReadThread(Status *error_ptr) {
if (!m_read_thread.IsJoinable())
return true;
@@ -217,15 +225,15 @@ bool Communication::StopReadThread(Error *error_ptr) {
// error = m_read_thread.Cancel();
- Error error = m_read_thread.Join(nullptr);
+ Status error = m_read_thread.Join(nullptr);
return error.Success();
}
-bool Communication::JoinReadThread(Error *error_ptr) {
+bool Communication::JoinReadThread(Status *error_ptr) {
if (!m_read_thread.IsJoinable())
return true;
- Error error = m_read_thread.Join(nullptr);
+ Status error = m_read_thread.Join(nullptr);
return error.Success();
}
@@ -272,7 +280,7 @@ void Communication::AppendBytesToCache(const uint8_t *bytes, size_t len,
size_t Communication::ReadFromConnection(void *dst, size_t dst_len,
const Timeout<std::micro> &timeout,
ConnectionStatus &status,
- Error *error_ptr) {
+ Status *error_ptr) {
lldb::ConnectionSP connection_sp(m_connection_sp);
if (connection_sp)
return connection_sp->Read(dst, dst_len, timeout, status, error_ptr);
@@ -295,7 +303,7 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) {
uint8_t buf[1024];
- Error error;
+ Status error;
ConnectionStatus status = eConnectionStatusSuccess;
bool done = false;
while (!done && comm->m_read_thread_enabled) {
@@ -322,10 +330,9 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) {
comm->Disconnect();
done = true;
}
- if (log)
- error.LogIfError(
- log, "%p Communication::ReadFromConnection () => status = %s", p,
- Communication::ConnectionStatusAsCString(status));
+ if (error.Fail())
+ LLDB_LOG(log, "error: {0}, status = {1}", error,
+ Communication::ConnectionStatusAsCString(status));
break;
case eConnectionStatusInterrupted: // Synchronization signal from
// SynchronizeWithReadThread()
@@ -340,10 +347,9 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) {
done = true;
LLVM_FALLTHROUGH;
case eConnectionStatusTimedOut: // Request timed out
- if (log)
- error.LogIfError(
- log, "%p Communication::ReadFromConnection () => status = %s", p,
- Communication::ConnectionStatusAsCString(status));
+ if (error.Fail())
+ LLDB_LOG(log, "error: {0}, status = {1}", error,
+ Communication::ConnectionStatusAsCString(status));
break;
}
}
diff --git a/contrib/llvm/tools/lldb/source/Core/Connection.cpp b/contrib/llvm/tools/lldb/source/Core/Connection.cpp
deleted file mode 100644
index 1ae046b..0000000
--- a/contrib/llvm/tools/lldb/source/Core/Connection.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//===-- Connection.cpp ------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Connection.h"
-
-#if defined(_WIN32)
-#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
-#endif
-
-#include "lldb/Host/ConnectionFileDescriptor.h"
-
-using namespace lldb_private;
-
-Connection::Connection() {}
-
-Connection::~Connection() {}
-
-Connection *Connection::CreateDefaultConnection(const char *url) {
-#if defined(_WIN32)
- if (strstr(url, "file://") == url)
- return new ConnectionGenericFile();
-#endif
- return new ConnectionFileDescriptor();
-}
diff --git a/contrib/llvm/tools/lldb/source/Core/DataBufferMemoryMap.cpp b/contrib/llvm/tools/lldb/source/Core/DataBufferMemoryMap.cpp
deleted file mode 100644
index 70e8a39..0000000
--- a/contrib/llvm/tools/lldb/source/Core/DataBufferMemoryMap.cpp
+++ /dev/null
@@ -1,307 +0,0 @@
-//===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// C Includes
-#include <fcntl.h>
-#include <sys/stat.h>
-#ifdef _WIN32
-#include "lldb/Host/windows/windows.h"
-#else
-#include <sys/mman.h>
-
-#define MAP_EXTRA_HOST_READ_FLAGS 0
-
-#if defined(__APPLE__)
-//----------------------------------------------------------------------
-// Newer versions of MacOSX have a flag that will allow us to read from
-// binaries whose code signature is invalid without crashing by using
-// the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media
-// is mapped we can avoid crashing and return zeroes to any pages we try
-// to read if the media becomes unavailable by using the
-// MAP_RESILIENT_MEDIA flag.
-//----------------------------------------------------------------------
-#if defined(MAP_RESILIENT_CODESIGN)
-#undef MAP_EXTRA_HOST_READ_FLAGS
-#if defined(MAP_RESILIENT_MEDIA)
-#define MAP_EXTRA_HOST_READ_FLAGS MAP_RESILIENT_CODESIGN | MAP_RESILIENT_MEDIA
-#else
-#define MAP_EXTRA_HOST_READ_FLAGS MAP_RESILIENT_CODESIGN
-#endif
-#endif // #if defined(MAP_RESILIENT_CODESIGN)
-#endif // #if defined (__APPLE__)
-
-#endif // #else #ifdef _WIN32
-// C++ Includes
-#include <cerrno>
-#include <climits>
-
-// Other libraries and framework includes
-#include "llvm/Support/MathExtras.h"
-
-// Project includes
-#include "lldb/Core/DataBufferMemoryMap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Host/File.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/HostInfo.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-//----------------------------------------------------------------------
-// Default Constructor
-//----------------------------------------------------------------------
-DataBufferMemoryMap::DataBufferMemoryMap()
- : m_mmap_addr(nullptr), m_mmap_size(0), m_data(nullptr), m_size(0) {}
-
-//----------------------------------------------------------------------
-// Virtual destructor since this class inherits from a pure virtual
-// base class.
-//----------------------------------------------------------------------
-DataBufferMemoryMap::~DataBufferMemoryMap() { Clear(); }
-
-//----------------------------------------------------------------------
-// Return a pointer to the bytes owned by this object, or nullptr if
-// the object contains no bytes.
-//----------------------------------------------------------------------
-uint8_t *DataBufferMemoryMap::GetBytes() { return m_data; }
-
-//----------------------------------------------------------------------
-// Return a const pointer to the bytes owned by this object, or nullptr
-// if the object contains no bytes.
-//----------------------------------------------------------------------
-const uint8_t *DataBufferMemoryMap::GetBytes() const { return m_data; }
-
-//----------------------------------------------------------------------
-// Return the number of bytes this object currently contains.
-//----------------------------------------------------------------------
-uint64_t DataBufferMemoryMap::GetByteSize() const { return m_size; }
-
-//----------------------------------------------------------------------
-// Reverts this object to an empty state by unmapping any memory
-// that is currently owned.
-//----------------------------------------------------------------------
-void DataBufferMemoryMap::Clear() {
- if (m_mmap_addr != nullptr) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MMAP));
- if (log)
- log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size "
- "= %" PRIu64 "",
- (void *)m_mmap_addr, (uint64_t)m_mmap_size);
-#ifdef _WIN32
- UnmapViewOfFile(m_mmap_addr);
-#else
- ::munmap((void *)m_mmap_addr, m_mmap_size);
-#endif
- m_mmap_addr = nullptr;
- m_mmap_size = 0;
- m_data = nullptr;
- m_size = 0;
- }
-}
-
-//----------------------------------------------------------------------
-// Memory map "length" bytes from "file" starting "offset"
-// bytes into the file. If "length" is set to SIZE_MAX, then
-// map as many bytes as possible.
-//
-// Returns the number of bytes mapped starting from the requested
-// offset.
-//----------------------------------------------------------------------
-size_t DataBufferMemoryMap::MemoryMapFromFileSpec(const FileSpec *filespec,
- lldb::offset_t offset,
- size_t length,
- bool writeable) {
- if (filespec != nullptr) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MMAP));
- if (log) {
- log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", "
- "offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i",
- filespec->GetPath().c_str(), offset, (uint64_t)length,
- writeable);
- }
- char path[PATH_MAX];
- if (filespec->GetPath(path, sizeof(path))) {
- uint32_t options = File::eOpenOptionRead;
- if (writeable)
- options |= File::eOpenOptionWrite;
-
- File file;
- Error error(file.Open(path, options));
- if (error.Success()) {
- const bool fd_is_file = true;
- return MemoryMapFromFileDescriptor(file.GetDescriptor(), offset, length,
- writeable, fd_is_file);
- }
- }
- }
- // We should only get here if there was an error
- Clear();
- return 0;
-}
-
-#ifdef _WIN32
-static size_t win32memmapalignment = 0;
-void LoadWin32MemMapAlignment() {
- SYSTEM_INFO data;
- GetSystemInfo(&data);
- win32memmapalignment = data.dwAllocationGranularity;
-}
-#endif
-
-//----------------------------------------------------------------------
-// The file descriptor FD is assumed to already be opened as read only
-// and the STAT structure is assumed to a valid pointer and already
-// containing valid data from a call to stat().
-//
-// Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into
-// the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes
-// as possible.
-//
-// RETURNS
-// Number of bytes mapped starting from the requested offset.
-//----------------------------------------------------------------------
-size_t DataBufferMemoryMap::MemoryMapFromFileDescriptor(int fd,
- lldb::offset_t offset,
- size_t length,
- bool writeable,
- bool fd_is_file) {
- Clear();
- if (fd >= 0) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MMAP |
- LIBLLDB_LOG_VERBOSE));
- if (log) {
- log->Printf("DataBufferMemoryMap::MemoryMapFromFileDescriptor(fd=%i, "
- "offset=0x%" PRIx64 ", length=0x%" PRIx64
- ", writeable=%i, fd_is_file=%i)",
- fd, offset, (uint64_t)length, writeable, fd_is_file);
- }
-#ifdef _WIN32
- HANDLE handle = (HANDLE)_get_osfhandle(fd);
- DWORD file_size_low, file_size_high;
- file_size_low = GetFileSize(handle, &file_size_high);
- const lldb::offset_t file_size =
- llvm::Make_64(file_size_high, file_size_low);
- const lldb::offset_t max_bytes_available = file_size - offset;
- const size_t max_bytes_mappable =
- (size_t)std::min<lldb::offset_t>(SIZE_MAX, max_bytes_available);
- if (length == SIZE_MAX || length > max_bytes_mappable) {
- // Cap the length if too much data was requested
- length = max_bytes_mappable;
- }
-
- if (length > 0) {
- HANDLE fileMapping = CreateFileMapping(
- handle, nullptr, writeable ? PAGE_READWRITE : PAGE_READONLY,
- file_size_high, file_size_low, nullptr);
- if (fileMapping != nullptr) {
- if (win32memmapalignment == 0)
- LoadWin32MemMapAlignment();
- lldb::offset_t realoffset = offset;
- lldb::offset_t delta = 0;
- if (realoffset % win32memmapalignment != 0) {
- realoffset = realoffset / win32memmapalignment * win32memmapalignment;
- delta = offset - realoffset;
- }
-
- LPVOID data = MapViewOfFile(fileMapping,
- writeable ? FILE_MAP_WRITE : FILE_MAP_READ,
- 0, realoffset, length + delta);
- m_mmap_addr = (uint8_t *)data;
- if (!data) {
- Error error;
- error.SetErrorToErrno();
- } else {
- m_data = m_mmap_addr + delta;
- m_size = length;
- }
- CloseHandle(fileMapping);
- }
- }
-#else
- struct stat stat;
- if (::fstat(fd, &stat) == 0) {
- if (S_ISREG(stat.st_mode) &&
- (stat.st_size > static_cast<off_t>(offset))) {
- const size_t max_bytes_available = stat.st_size - offset;
- if (length == SIZE_MAX) {
- length = max_bytes_available;
- } else if (length > max_bytes_available) {
- // Cap the length if too much data was requested
- length = max_bytes_available;
- }
-
- if (length > 0) {
- int prot = PROT_READ;
- int flags = MAP_PRIVATE;
- if (writeable)
- prot |= PROT_WRITE;
- else
- flags |= MAP_EXTRA_HOST_READ_FLAGS;
-
- if (fd_is_file)
- flags |= MAP_FILE;
-
- m_mmap_addr =
- (uint8_t *)::mmap(nullptr, length, prot, flags, fd, offset);
- Error error;
-
- if (m_mmap_addr == (void *)-1) {
- error.SetErrorToErrno();
- if (error.GetError() == EINVAL) {
- // We may still have a shot at memory mapping if we align things
- // correctly
- size_t page_offset = offset % HostInfo::GetPageSize();
- if (page_offset != 0) {
- m_mmap_addr =
- (uint8_t *)::mmap(nullptr, length + page_offset, prot,
- flags, fd, offset - page_offset);
- if (m_mmap_addr == (void *)-1) {
- // Failed to map file
- m_mmap_addr = nullptr;
- } else if (m_mmap_addr != nullptr) {
- // We recovered and were able to memory map
- // after we aligned things to page boundaries
-
- // Save the actual mmap'ed size
- m_mmap_size = length + page_offset;
- // Our data is at an offset into the mapped data
- m_data = m_mmap_addr + page_offset;
- // Our pretend size is the size that was requested
- m_size = length;
- }
- }
- }
- if (error.GetError() == ENOMEM) {
- error.SetErrorStringWithFormat("could not allocate %" PRId64
- " bytes of memory to mmap in file",
- (uint64_t)length);
- }
- } else {
- // We were able to map the requested data in one chunk
- // where our mmap and actual data are the same.
- m_mmap_size = length;
- m_data = m_mmap_addr;
- m_size = length;
- }
-
- if (log) {
- log->Printf(
- "DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = "
- "%p, m_mmap_size = %" PRIu64 ", error = %s",
- (void *)m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString());
- }
- }
- }
- }
-#endif
- }
- return GetByteSize();
-}
diff --git a/contrib/llvm/tools/lldb/source/Core/Debugger.cpp b/contrib/llvm/tools/lldb/source/Core/Debugger.cpp
index 8f888a5..d42e4df 100644
--- a/contrib/llvm/tools/lldb/source/Core/Debugger.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Debugger.cpp
@@ -9,57 +9,70 @@
#include "lldb/Core/Debugger.h"
-// C Includes
-// C++ Includes
-#include <map>
-#include <mutex>
-
-// Other libraries and framework includes
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/DynamicLibrary.h"
-
-// Project includes
+#include "lldb/Breakpoint/Breakpoint.h" // for Breakpoint, Brea...
+#include "lldb/Core/Event.h" // for Event, EventData...
#include "lldb/Core/FormatEntity.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/Listener.h" // for Listener
+#include "lldb/Core/Mangled.h" // for Mangled
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamAsynchronousIO.h"
-#include "lldb/Core/StreamCallback.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/StructuredData.h"
-#include "lldb/Core/Timer.h"
-#include "lldb/Core/ValueObject.h"
-#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/DataFormatters/DataVisualization.h"
-#include "lldb/DataFormatters/FormatManager.h"
-#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Expression/REPL.h"
-#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/File.h" // for File, File::kInv...
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValue.h" // for OptionValue, Opt...
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/OptionValueSInt64.h"
#include "lldb/Interpreter/OptionValueString.h"
-#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Interpreter/Property.h" // for PropertyDefinition
+#include "lldb/Interpreter/ScriptInterpreter.h" // for ScriptInterpreter
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
-#include "lldb/Symbol/VariableList.h"
+#include "lldb/Symbol/SymbolContext.h" // for SymbolContext
#include "lldb/Target/Language.h"
#include "lldb/Target/Process.h"
-#include "lldb/Target/RegisterContext.h"
-#include "lldb/Target/SectionLoadList.h"
-#include "lldb/Target/StopInfo.h"
#include "lldb/Target/StructuredDataPlugin.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadList.h" // for ThreadList
#include "lldb/Utility/AnsiTerminal.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/Log.h" // for LLDB_LOG_OPTION_...
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamCallback.h"
+#include "lldb/Utility/StreamString.h"
+
+#if defined(LLVM_ON_WIN32)
+#include "lldb/Host/windows/PosixApi.h" // for PATH_MAX
+#endif
+
+#include "llvm/ADT/None.h" // for None
+#include "llvm/ADT/STLExtras.h" // for make_unique
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator.h" // for iterator_facade_...
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/raw_ostream.h" // for raw_fd_ostream
+
+#include <list> // for list
+#include <memory> // for make_shared
+#include <mutex>
+#include <set> // for set
+#include <stdio.h> // for size_t, NULL
+#include <stdlib.h> // for getenv
+#include <string.h> // for strcmp
+#include <string> // for string
+#include <system_error> // for error_code
+
+namespace lldb_private {
+class Address;
+}
using namespace lldb;
using namespace lldb_private;
@@ -99,6 +112,12 @@ OptionEnumValueElement g_language_enumerators[] = {
"{ " \
"${module.file.basename}{`${function.name-with-args}" \
"{${frame.no-debug}${function.pc-offset}}}}"
+
+#define MODULE_WITH_FUNC_NO_ARGS \
+ "{ " \
+ "${module.file.basename}{`${function.name-without-args}" \
+ "{${frame.no-debug}${function.pc-offset}}}}"
+
#define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}"
#define IS_OPTIMIZED "{${function.is-optimized} [opt]}"
@@ -125,7 +144,11 @@ OptionEnumValueElement g_language_enumerators[] = {
"\\n"
#define DEFAULT_FRAME_FORMAT \
- "frame #${frame.index}:{ ${frame.no-debug}${frame.pc}}" MODULE_WITH_FUNC FILE_AND_LINE \
+ "frame #${frame.index}: ${frame.pc}" MODULE_WITH_FUNC FILE_AND_LINE \
+ IS_OPTIMIZED "\\n"
+
+#define DEFAULT_FRAME_FORMAT_NO_ARGS \
+ "frame #${frame.index}: ${frame.pc}" MODULE_WITH_FUNC_NO_ARGS FILE_AND_LINE \
IS_OPTIMIZED "\\n"
// Three parts to this disassembly format specification:
@@ -173,13 +196,15 @@ static PropertyDefinition g_properties[] = {
{"auto-confirm", OptionValue::eTypeBoolean, true, false, nullptr, nullptr,
"If true all confirmation prompts will receive their default reply."},
{"disassembly-format", OptionValue::eTypeFormatEntity, true, 0,
- DEFAULT_DISASSEMBLY_FORMAT, nullptr, "The default disassembly format "
- "string to use when disassembling "
- "instruction sequences."},
+ DEFAULT_DISASSEMBLY_FORMAT, nullptr,
+ "The default disassembly format "
+ "string to use when disassembling "
+ "instruction sequences."},
{"frame-format", OptionValue::eTypeFormatEntity, true, 0,
- DEFAULT_FRAME_FORMAT, nullptr, "The default frame format string to use "
- "when displaying stack frame information "
- "for threads."},
+ DEFAULT_FRAME_FORMAT, nullptr,
+ "The default frame format string to use "
+ "when displaying stack frame information "
+ "for threads."},
{"notify-void", OptionValue::eTypeBoolean, true, false, nullptr, nullptr,
"Notify the user explicitly if an expression returns void (default: "
"false)."},
@@ -190,18 +215,21 @@ static PropertyDefinition g_properties[] = {
nullptr, g_language_enumerators,
"The script language to be used for evaluating user-written scripts."},
{"stop-disassembly-count", OptionValue::eTypeSInt64, true, 4, nullptr,
- nullptr, "The number of disassembly lines to show when displaying a "
- "stopped context."},
+ nullptr,
+ "The number of disassembly lines to show when displaying a "
+ "stopped context."},
{"stop-disassembly-display", OptionValue::eTypeEnum, true,
Debugger::eStopDisassemblyTypeNoDebugInfo, nullptr,
g_show_disassembly_enum_values,
"Control when to display disassembly when displaying a stopped context."},
{"stop-line-count-after", OptionValue::eTypeSInt64, true, 3, nullptr,
- nullptr, "The number of sources lines to display that come after the "
- "current source line when displaying a stopped context."},
+ nullptr,
+ "The number of sources lines to display that come after the "
+ "current source line when displaying a stopped context."},
{"stop-line-count-before", OptionValue::eTypeSInt64, true, 3, nullptr,
- nullptr, "The number of sources lines to display that come before the "
- "current source line when displaying a stopped context."},
+ nullptr,
+ "The number of sources lines to display that come before the "
+ "current source line when displaying a stopped context."},
{"stop-show-column", OptionValue::eTypeEnum, false,
eStopShowColumnAnsiOrCaret, nullptr, s_stop_show_column_values,
"If true, LLDB will use the column information from the debug info to "
@@ -219,19 +247,22 @@ static PropertyDefinition g_properties[] = {
{"term-width", OptionValue::eTypeSInt64, true, 80, nullptr, nullptr,
"The maximum number of columns to use for displaying text."},
{"thread-format", OptionValue::eTypeFormatEntity, true, 0,
- DEFAULT_THREAD_FORMAT, nullptr, "The default thread format string to use "
- "when displaying thread information."},
+ DEFAULT_THREAD_FORMAT, nullptr,
+ "The default thread format string to use "
+ "when displaying thread information."},
{"thread-stop-format", OptionValue::eTypeFormatEntity, true, 0,
- DEFAULT_THREAD_STOP_FORMAT, nullptr, "The default thread format "
- "string to usewhen displaying thread "
- "information as part of the stop display."},
+ DEFAULT_THREAD_STOP_FORMAT, nullptr,
+ "The default thread format "
+ "string to use when displaying thread "
+ "information as part of the stop display."},
{"use-external-editor", OptionValue::eTypeBoolean, true, false, nullptr,
nullptr, "Whether to use an external editor or not."},
{"use-color", OptionValue::eTypeBoolean, true, true, nullptr, nullptr,
"Whether to use Ansi color codes or not."},
{"auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, nullptr,
- nullptr, "If true, LLDB will automatically display small structs in "
- "one-liner format (default: true)."},
+ nullptr,
+ "If true, LLDB will automatically display small structs in "
+ "one-liner format (default: true)."},
{"auto-indent", OptionValue::eTypeBoolean, true, true, nullptr, nullptr,
"If true, LLDB will auto indent/outdent code. Currently only supported in "
"the REPL (default: true)."},
@@ -242,8 +273,13 @@ static PropertyDefinition g_properties[] = {
"The tab size to use when indenting code in multi-line input mode "
"(default: 4)."},
{"escape-non-printables", OptionValue::eTypeBoolean, true, true, nullptr,
- nullptr, "If true, LLDB will automatically escape non-printable and "
- "escape characters when formatting strings."},
+ nullptr,
+ "If true, LLDB will automatically escape non-printable and "
+ "escape characters when formatting strings."},
+ {"frame-format-unique", OptionValue::eTypeFormatEntity, true, 0,
+ DEFAULT_FRAME_FORMAT_NO_ARGS, nullptr,
+ "The default frame format string to use when displaying stack frame"
+ "information for threads from thread backtrace unique."},
{nullptr, OptionValue::eTypeInvalid, true, 0, nullptr, nullptr, nullptr}};
enum {
@@ -269,14 +305,16 @@ enum {
ePropertyAutoIndent,
ePropertyPrintDecls,
ePropertyTabSize,
- ePropertyEscapeNonPrintables
+ ePropertyEscapeNonPrintables,
+ ePropertyFrameFormatUnique,
};
LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr;
-Error Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
- VarSetOperationType op,
- llvm::StringRef property_path, llvm::StringRef value) {
+Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ llvm::StringRef property_path,
+ llvm::StringRef value) {
bool is_load_script = (property_path == "target.load-script-from-symbol-file");
bool is_escape_non_printables = (property_path == "escape-non-printables");
TargetSP target_sp;
@@ -286,7 +324,7 @@ Error Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
load_script_old_value =
target_sp->TargetProperties::GetLoadScriptFromSymbolFile();
}
- Error error(Properties::SetPropertyValue(exe_ctx, op, property_path, value));
+ Status error(Properties::SetPropertyValue(exe_ctx, op, property_path, value));
if (error.Success()) {
// FIXME it would be nice to have "on-change" callbacks for properties
if (property_path == g_properties[ePropertyPrompt].name) {
@@ -296,9 +334,9 @@ Error Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
if (str.length())
new_prompt = str;
GetCommandInterpreter().UpdatePrompt(new_prompt);
- EventSP prompt_change_event_sp(
- new Event(CommandInterpreter::eBroadcastBitResetPrompt,
- new EventDataBytes(new_prompt)));
+ auto bytes = llvm::make_unique<EventDataBytes>(new_prompt);
+ auto prompt_change_event_sp = std::make_shared<Event>(
+ CommandInterpreter::eBroadcastBitResetPrompt, bytes.release());
GetCommandInterpreter().BroadcastEvent(prompt_change_event_sp);
} else if (property_path == g_properties[ePropertyUseColor].name) {
// use-color changed. Ping the prompt so it can reset the ansi terminal
@@ -308,7 +346,7 @@ Error Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
load_script_old_value == eLoadScriptFromSymFileWarn) {
if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() ==
eLoadScriptFromSymFileTrue) {
- std::list<Error> errors;
+ std::list<Status> errors;
StreamString feedback_stream;
if (!target_sp->LoadScriptingResources(errors, &feedback_stream)) {
StreamFileSP stream_sp(GetErrorFile());
@@ -344,6 +382,11 @@ const FormatEntity::Entry *Debugger::GetFrameFormat() const {
return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
}
+const FormatEntity::Entry *Debugger::GetFrameFormatUnique() const {
+ const uint32_t idx = ePropertyFrameFormatUnique;
+ return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
+}
+
bool Debugger::GetNotifyVoid() const {
const uint32_t idx = ePropertyNotiftVoid;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
@@ -537,7 +580,7 @@ void Debugger::SettingsInitialize() { Target::SettingsInitialize(); }
void Debugger::SettingsTerminate() { Target::SettingsTerminate(); }
-bool Debugger::LoadPlugin(const FileSpec &spec, Error &error) {
+bool Debugger::LoadPlugin(const FileSpec &spec, Status &error) {
if (g_load_plugin_callback) {
llvm::sys::DynamicLibrary dynlib =
g_load_plugin_callback(shared_from_this(), spec, error);
@@ -555,9 +598,9 @@ bool Debugger::LoadPlugin(const FileSpec &spec, Error &error) {
}
static FileSpec::EnumerateDirectoryResult
-LoadPluginCallback(void *baton, FileSpec::FileType file_type,
+LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft,
const FileSpec &file_spec) {
- Error error;
+ Status error;
static ConstString g_dylibext("dylib");
static ConstString g_solibext("so");
@@ -567,13 +610,13 @@ LoadPluginCallback(void *baton, FileSpec::FileType file_type,
Debugger *debugger = (Debugger *)baton;
+ namespace fs = llvm::sys::fs;
// If we have a regular file, a symbolic link or unknown file type, try
// and process the file. We must handle unknown as sometimes the directory
// enumeration might be enumerating a file system that doesn't have correct
// file type information.
- if (file_type == FileSpec::eFileTypeRegular ||
- file_type == FileSpec::eFileTypeSymbolicLink ||
- file_type == FileSpec::eFileTypeUnknown) {
+ if (ft == fs::file_type::regular_file || ft == fs::file_type::symlink_file ||
+ ft == fs::file_type::type_unknown) {
FileSpec plugin_file_spec(file_spec);
plugin_file_spec.ResolvePath();
@@ -582,13 +625,13 @@ LoadPluginCallback(void *baton, FileSpec::FileType file_type,
return FileSpec::eEnumerateDirectoryResultNext;
}
- Error plugin_load_error;
+ Status plugin_load_error;
debugger->LoadPlugin(plugin_file_spec, plugin_load_error);
return FileSpec::eEnumerateDirectoryResultNext;
- } else if (file_type == FileSpec::eFileTypeUnknown ||
- file_type == FileSpec::eFileTypeDirectory ||
- file_type == FileSpec::eFileTypeSymbolicLink) {
+ } else if (ft == fs::file_type::directory_file ||
+ ft == fs::file_type::symlink_file ||
+ ft == fs::file_type::type_unknown) {
// Try and recurse into anything that a directory or symbolic link.
// We must also do this for unknown as sometimes the directory enumeration
// might be enumerating a file system that doesn't have correct file type
@@ -697,16 +740,16 @@ TargetSP Debugger::FindTargetWithProcess(Process *process) {
Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
: UserID(g_unique_id++),
- Properties(OptionValuePropertiesSP(new OptionValueProperties())),
- m_input_file_sp(new StreamFile(stdin, false)),
- m_output_file_sp(new StreamFile(stdout, false)),
- m_error_file_sp(new StreamFile(stderr, false)),
+ Properties(std::make_shared<OptionValueProperties>()),
+ m_input_file_sp(std::make_shared<StreamFile>(stdin, false)),
+ m_output_file_sp(std::make_shared<StreamFile>(stdout, false)),
+ m_error_file_sp(std::make_shared<StreamFile>(stderr, false)),
m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()),
m_terminal_state(), m_target_list(*this), m_platform_list(),
m_listener_sp(Listener::MakeListener("lldb.Debugger")),
m_source_manager_ap(), m_source_file_cache(),
- m_command_interpreter_ap(
- new CommandInterpreter(*this, eScriptLanguageDefault, false)),
+ m_command_interpreter_ap(llvm::make_unique<CommandInterpreter>(
+ *this, eScriptLanguageDefault, false)),
m_input_reader_stack(), m_instance_name(), m_loaded_plugins(),
m_event_handler_thread(), m_io_handler_thread(),
m_sync_broadcaster(nullptr, "lldb.debugger.sync"),
@@ -715,7 +758,8 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID());
m_instance_name.SetCString(instance_cstr);
if (log_callback)
- m_log_callback_stream_sp.reset(new StreamCallback(log_callback, baton));
+ m_log_callback_stream_sp =
+ std::make_shared<StreamCallback>(log_callback, baton);
m_command_interpreter_ap->Initialize();
// Always add our default platform to the platform list
PlatformSP default_platform_sp(Platform::GetHostPlatform());
@@ -762,7 +806,7 @@ void Debugger::Clear() {
// static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp);
// static void Debugger::Terminate();
//----------------------------------------------------------------------
- std::call_once(m_clear_once, [this]() {
+ llvm::call_once(m_clear_once, [this]() {
ClearIOHandlers();
StopIOHandlerThread();
StopEventHandlerThread();
@@ -811,7 +855,7 @@ void Debugger::SetInputFileHandle(FILE *fh, bool tranfer_ownership) {
if (m_input_file_sp)
m_input_file_sp->GetFile().SetStream(fh, tranfer_ownership);
else
- m_input_file_sp.reset(new StreamFile(fh, tranfer_ownership));
+ m_input_file_sp = std::make_shared<StreamFile>(fh, tranfer_ownership);
File &in_file = m_input_file_sp->GetFile();
if (!in_file.IsValid())
@@ -826,7 +870,7 @@ void Debugger::SetOutputFileHandle(FILE *fh, bool tranfer_ownership) {
if (m_output_file_sp)
m_output_file_sp->GetFile().SetStream(fh, tranfer_ownership);
else
- m_output_file_sp.reset(new StreamFile(fh, tranfer_ownership));
+ m_output_file_sp = std::make_shared<StreamFile>(fh, tranfer_ownership);
File &out_file = m_output_file_sp->GetFile();
if (!out_file.IsValid())
@@ -845,7 +889,7 @@ void Debugger::SetErrorFileHandle(FILE *fh, bool tranfer_ownership) {
if (m_error_file_sp)
m_error_file_sp->GetFile().SetStream(fh, tranfer_ownership);
else
- m_error_file_sp.reset(new StreamFile(fh, tranfer_ownership));
+ m_error_file_sp = std::make_shared<StreamFile>(fh, tranfer_ownership);
File &err_file = m_error_file_sp->GetFile();
if (!err_file.IsValid())
@@ -996,7 +1040,7 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(StreamFileSP &in,
// If there is nothing, use stdin
if (!in)
- in = StreamFileSP(new StreamFile(stdin, false));
+ in = std::make_shared<StreamFile>(stdin, false);
}
// If no STDOUT has been set, then set it appropriately
if (!out) {
@@ -1007,7 +1051,7 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(StreamFileSP &in,
// If there is nothing, use stdout
if (!out)
- out = StreamFileSP(new StreamFile(stdout, false));
+ out = std::make_shared<StreamFile>(stdout, false);
}
// If no STDERR has been set, then set it appropriately
if (!err) {
@@ -1018,7 +1062,7 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(StreamFileSP &in,
// If there is nothing, use stderr
if (!err)
- err = StreamFileSP(new StreamFile(stdout, false));
+ err = std::make_shared<StreamFile>(stdout, false);
}
}
@@ -1075,11 +1119,11 @@ bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) {
}
StreamSP Debugger::GetAsyncOutputStream() {
- return StreamSP(new StreamAsynchronousIO(*this, true));
+ return std::make_shared<StreamAsynchronousIO>(*this, true);
}
StreamSP Debugger::GetAsyncErrorStream() {
- return StreamSP(new StreamAsynchronousIO(*this, false));
+ return std::make_shared<StreamAsynchronousIO>(*this, false);
}
size_t Debugger::GetNumDebuggers() {
@@ -1234,31 +1278,42 @@ void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,
// For simplicity's sake, I am not going to deal with how to close down any
// open logging streams, I just redirect everything from here on out to the
// callback.
- m_log_callback_stream_sp.reset(new StreamCallback(log_callback, baton));
+ m_log_callback_stream_sp =
+ std::make_shared<StreamCallback>(log_callback, baton);
}
-bool Debugger::EnableLog(const char *channel, const char **categories,
- const char *log_file, uint32_t log_options,
- Stream &error_stream) {
- StreamSP log_stream_sp;
+bool Debugger::EnableLog(llvm::StringRef channel,
+ llvm::ArrayRef<const char *> categories,
+ llvm::StringRef log_file, uint32_t log_options,
+ llvm::raw_ostream &error_stream) {
+ const bool should_close = true;
+ const bool unbuffered = true;
+
+ std::shared_ptr<llvm::raw_ostream> log_stream_sp;
if (m_log_callback_stream_sp) {
log_stream_sp = m_log_callback_stream_sp;
// For now when using the callback mode you always get thread & timestamp.
log_options |=
LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
- } else if (log_file == nullptr || *log_file == '\0') {
- log_stream_sp = GetOutputFile();
+ } else if (log_file.empty()) {
+ log_stream_sp = std::make_shared<llvm::raw_fd_ostream>(
+ GetOutputFile()->GetFile().GetDescriptor(), !should_close, unbuffered);
} else {
- LogStreamMap::iterator pos = m_log_streams.find(log_file);
+ auto pos = m_log_streams.find(log_file);
if (pos != m_log_streams.end())
log_stream_sp = pos->second.lock();
if (!log_stream_sp) {
- uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate |
- File::eOpenOptionCloseOnExec | File::eOpenOptionAppend;
- if (!(log_options & LLDB_LOG_OPTION_APPEND))
- options |= File::eOpenOptionTruncate;
-
- log_stream_sp.reset(new StreamFile(log_file, options));
+ llvm::sys::fs::OpenFlags flags = llvm::sys::fs::F_Text;
+ if (log_options & LLDB_LOG_OPTION_APPEND)
+ flags |= llvm::sys::fs::F_Append;
+ int FD;
+ if (std::error_code ec =
+ llvm::sys::fs::openFileForWrite(log_file, FD, flags)) {
+ error_stream << "Unable to open log file: " << ec.message();
+ return false;
+ }
+ log_stream_sp =
+ std::make_shared<llvm::raw_fd_ostream>(FD, should_close, unbuffered);
m_log_streams[log_file] = log_stream_sp;
}
}
@@ -1274,7 +1329,7 @@ bool Debugger::EnableLog(const char *channel, const char **categories,
SourceManager &Debugger::GetSourceManager() {
if (!m_source_manager_ap)
- m_source_manager_ap.reset(new SourceManager(shared_from_this()));
+ m_source_manager_ap = llvm::make_unique<SourceManager>(shared_from_this());
return *m_source_manager_ap;
}
@@ -1340,7 +1395,7 @@ size_t Debugger::GetProcessSTDOUT(Process *process, Stream *stream) {
process = target_sp->GetProcessSP().get();
}
if (process) {
- Error error;
+ Status error;
size_t len;
char stdio_buffer[1024];
while ((len = process->GetSTDOUT(stdio_buffer, sizeof(stdio_buffer),
@@ -1368,7 +1423,7 @@ size_t Debugger::GetProcessSTDERR(Process *process, Stream *stream) {
process = target_sp->GetProcessSP().get();
}
if (process) {
- Error error;
+ Status error;
size_t len;
char stdio_buffer[1024];
while ((len = process->GetSTDERR(stdio_buffer, sizeof(stdio_buffer),
@@ -1438,7 +1493,7 @@ void Debugger::HandleProcessEvent(const EventSP &event_sp) {
EventDataStructuredData::GetObjectFromEvent(event_sp.get());
if (output_stream_sp) {
StreamString content_stream;
- Error error =
+ Status error =
plugin_sp->GetDescription(structured_data_sp, content_stream);
if (error.Success()) {
if (!content_stream.GetString().empty()) {
@@ -1677,8 +1732,8 @@ Target *Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) {
return GetDummyTarget();
}
-Error Debugger::RunREPL(LanguageType language, const char *repl_options) {
- Error err;
+Status Debugger::RunREPL(LanguageType language, const char *repl_options) {
+ Status err;
FileSpec repl_executable;
if (language == eLanguageTypeUnknown) {
diff --git a/contrib/llvm/tools/lldb/source/Core/Disassembler.cpp b/contrib/llvm/tools/lldb/source/Core/Disassembler.cpp
index 7cac294..6d463d5 100644
--- a/contrib/llvm/tools/lldb/source/Core/Disassembler.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Disassembler.cpp
@@ -9,22 +9,14 @@
#include "lldb/Core/Disassembler.h"
-// C Includes
-// C++ Includes
-#include <cstdio>
-#include <cstring>
-
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/AddressRange.h" // for AddressRange
#include "lldb/Core/Debugger.h"
#include "lldb/Core/EmulateInstruction.h"
-#include "lldb/Core/Error.h"
+#include "lldb/Core/Mangled.h" // for Mangled, Mangled...
#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h" // for ModuleList
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Timer.h"
+#include "lldb/Core/SourceManager.h" // for SourceManager
#include "lldb/Host/FileSystem.h"
#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Interpreter/OptionValueArray.h"
@@ -33,13 +25,31 @@
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Interpreter/OptionValueUInt64.h"
#include "lldb/Symbol/Function.h"
-#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h" // for Symbol
+#include "lldb/Symbol/SymbolContext.h" // for SymbolContext
#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Target/Thread.h" // for Thread
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h" // for StreamString
+#include "lldb/Utility/Timer.h"
+#include "lldb/lldb-private-enumerations.h" // for InstructionType:...
+#include "lldb/lldb-private-interfaces.h" // for DisassemblerCrea...
+#include "lldb/lldb-private-types.h" // for RegisterInfo
+#include "llvm/ADT/Triple.h" // for Triple, Triple::...
+#include "llvm/Support/Compiler.h" // for LLVM_PRETTY_FUNC...
+
+#include <cstdint> // for uint32_t, UINT32...
+#include <cstring>
+#include <utility> // for pair
+
+#include <assert.h> // for assert
#define DEFAULT_DISASM_BYTE_SIZE 32
@@ -49,7 +59,8 @@ using namespace lldb_private;
DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch,
const char *flavor,
const char *plugin_name) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
arch.GetArchitectureName(), plugin_name);
@@ -330,7 +341,7 @@ bool Disassembler::ElideMixedSourceAndDisassemblyLine(
} else {
TargetSP target_sp = exe_ctx.GetTargetSP();
if (target_sp) {
- Error error;
+ Status error;
OptionValueSP value_sp = target_sp->GetDebugger().GetPropertyValue(
&exe_ctx, "target.process.thread.step-avoid-regexp", false, error);
if (value_sp && value_sp->GetType() == OptionValue::eTypeRegex) {
@@ -749,6 +760,10 @@ bool Instruction::DumpEmulation(const ArchSpec &arch) {
return false;
}
+bool Instruction::CanSetBreakpoint () {
+ return !HasDelaySlot();
+}
+
bool Instruction::HasDelaySlot() {
// Default is false.
return false;
@@ -759,7 +774,7 @@ OptionValueSP Instruction::ReadArray(FILE *in_file, Stream *out_stream,
bool done = false;
char buffer[1024];
- OptionValueSP option_value_sp(new OptionValueArray(1u << data_type));
+ auto option_value_sp = std::make_shared<OptionValueArray>(1u << data_type);
int idx = 0;
while (!done) {
@@ -797,12 +812,12 @@ OptionValueSP Instruction::ReadArray(FILE *in_file, Stream *out_stream,
OptionValueSP data_value_sp;
switch (data_type) {
case OptionValue::eTypeUInt64:
- data_value_sp.reset(new OptionValueUInt64(0, 0));
+ data_value_sp = std::make_shared<OptionValueUInt64>(0, 0);
data_value_sp->SetValueFromString(value);
break;
// Other types can be added later as needed.
default:
- data_value_sp.reset(new OptionValueString(value.c_str(), ""));
+ data_value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
break;
}
@@ -818,7 +833,7 @@ OptionValueSP Instruction::ReadDictionary(FILE *in_file, Stream *out_stream) {
bool done = false;
char buffer[1024];
- OptionValueSP option_value_sp(new OptionValueDictionary());
+ auto option_value_sp = std::make_shared<OptionValueDictionary>();
static ConstString encoding_key("data_encoding");
OptionValue::Type data_type = OptionValue::eTypeInvalid;
@@ -891,13 +906,13 @@ OptionValueSP Instruction::ReadDictionary(FILE *in_file, Stream *out_stream) {
// We've used the data_type to read an array; re-set the type to Invalid
data_type = OptionValue::eTypeInvalid;
} else if ((value[0] == '0') && (value[1] == 'x')) {
- value_sp.reset(new OptionValueUInt64(0, 0));
+ value_sp = std::make_shared<OptionValueUInt64>(0, 0);
value_sp->SetValueFromString(value);
} else {
size_t len = value.size();
if ((value[0] == '"') && (value[len - 1] == '"'))
value = value.substr(1, len - 2);
- value_sp.reset(new OptionValueString(value.c_str(), ""));
+ value_sp = std::make_shared<OptionValueString>(value.c_str(), "");
}
if (const_key == encoding_key) {
@@ -1104,7 +1119,7 @@ InstructionList::GetIndexOfNextBranchInstruction(uint32_t start,
while (i > start) {
--i;
- Error error;
+ Status error;
uint32_t inst_bytes;
bool prefer_file_cache = false; // Read from process if process is running
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
@@ -1163,18 +1178,17 @@ size_t Disassembler::ParseInstructions(const ExecutionContext *exe_ctx,
!range.GetBaseAddress().IsValid())
return 0;
- DataBufferHeap *heap_buffer = new DataBufferHeap(byte_size, '\0');
- DataBufferSP data_sp(heap_buffer);
+ auto data_sp = std::make_shared<DataBufferHeap>(byte_size, '\0');
- Error error;
+ Status error;
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
const size_t bytes_read = target->ReadMemory(
- range.GetBaseAddress(), prefer_file_cache, heap_buffer->GetBytes(),
- heap_buffer->GetByteSize(), error, &load_addr);
+ range.GetBaseAddress(), prefer_file_cache, data_sp->GetBytes(),
+ data_sp->GetByteSize(), error, &load_addr);
if (bytes_read > 0) {
- if (bytes_read != heap_buffer->GetByteSize())
- heap_buffer->SetByteSize(bytes_read);
+ if (bytes_read != data_sp->GetByteSize())
+ data_sp->SetByteSize(bytes_read);
DataExtractor data(data_sp, m_arch.GetByteOrder(),
m_arch.GetAddressByteSize());
const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
@@ -1211,7 +1225,7 @@ size_t Disassembler::ParseInstructions(const ExecutionContext *exe_ctx,
DataBufferHeap *heap_buffer = new DataBufferHeap(byte_size, '\0');
DataBufferSP data_sp(heap_buffer);
- Error error;
+ Status error;
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
const size_t bytes_read =
target->ReadMemory(start, prefer_file_cache, heap_buffer->GetBytes(),
@@ -1447,4 +1461,3 @@ std::function<bool(const Instruction::Operand &)>
lldb_private::OperandMatchers::MatchOpType(Instruction::Operand::Type type) {
return [type](const Instruction::Operand &op) { return op.m_type == type; };
}
-
diff --git a/contrib/llvm/tools/lldb/source/Core/DumpDataExtractor.cpp b/contrib/llvm/tools/lldb/source/Core/DumpDataExtractor.cpp
new file mode 100644
index 0000000..c2a9115
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Core/DumpDataExtractor.cpp
@@ -0,0 +1,825 @@
+//===-- DumpDataExtractor.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DumpDataExtractor.h"
+
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-forward.h" // for TargetSP, DisassemblerSP
+
+#include "lldb/Core/Address.h" // for Address
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/ModuleList.h" // for ModuleList
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Stream.h"
+
+#include "clang/AST/ASTContext.h" // for ASTContext
+#include "clang/AST/CanonicalType.h" // for CanQualType
+
+#include "llvm/ADT/APFloat.h" // for APFloat, APFloatBase:...
+#include "llvm/ADT/APInt.h" // for APInt
+#include "llvm/ADT/ArrayRef.h" // for ArrayRef
+#include "llvm/ADT/SmallVector.h" // for SmallVector
+
+#include <limits> // for numeric_limits, numer...
+#include <memory> // for shared_ptr
+#include <string> // for string, basic_string
+
+#include <assert.h> // for assert
+#include <ctype.h> // for isprint
+#include <inttypes.h> // for PRIu64, PRIx64, PRIX64
+#include <math.h> // for ldexpf
+
+#include <bitset>
+#include <sstream>
+
+using namespace lldb_private;
+using namespace lldb;
+
+#define NON_PRINTABLE_CHAR '.'
+
+static float half2float(uint16_t half) {
+ union {
+ float f;
+ uint32_t u;
+ } u;
+ int32_t v = (int16_t)half;
+
+ if (0 == (v & 0x7c00)) {
+ u.u = v & 0x80007FFFU;
+ return u.f * ldexpf(1, 125);
+ }
+
+ v <<= 13;
+ u.u = v | 0x70000000U;
+ return u.f * ldexpf(1, -112);
+}
+
+static bool GetAPInt(const DataExtractor &data, lldb::offset_t *offset_ptr,
+ lldb::offset_t byte_size, llvm::APInt &result) {
+ llvm::SmallVector<uint64_t, 2> uint64_array;
+ lldb::offset_t bytes_left = byte_size;
+ uint64_t u64;
+ const lldb::ByteOrder byte_order = data.GetByteOrder();
+ if (byte_order == lldb::eByteOrderLittle) {
+ while (bytes_left > 0) {
+ if (bytes_left >= 8) {
+ u64 = data.GetU64(offset_ptr);
+ bytes_left -= 8;
+ } else {
+ u64 = data.GetMaxU64(offset_ptr, (uint32_t)bytes_left);
+ bytes_left = 0;
+ }
+ uint64_array.push_back(u64);
+ }
+ result = llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
+ return true;
+ } else if (byte_order == lldb::eByteOrderBig) {
+ lldb::offset_t be_offset = *offset_ptr + byte_size;
+ lldb::offset_t temp_offset;
+ while (bytes_left > 0) {
+ if (bytes_left >= 8) {
+ be_offset -= 8;
+ temp_offset = be_offset;
+ u64 = data.GetU64(&temp_offset);
+ bytes_left -= 8;
+ } else {
+ be_offset -= bytes_left;
+ temp_offset = be_offset;
+ u64 = data.GetMaxU64(&temp_offset, (uint32_t)bytes_left);
+ bytes_left = 0;
+ }
+ uint64_array.push_back(u64);
+ }
+ *offset_ptr += byte_size;
+ result = llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
+ return true;
+ }
+ return false;
+}
+
+static lldb::offset_t DumpAPInt(Stream *s, const DataExtractor &data,
+ lldb::offset_t offset, lldb::offset_t byte_size,
+ bool is_signed, unsigned radix) {
+ llvm::APInt apint;
+ if (GetAPInt(data, &offset, byte_size, apint)) {
+ std::string apint_str(apint.toString(radix, is_signed));
+ switch (radix) {
+ case 2:
+ s->Write("0b", 2);
+ break;
+ case 8:
+ s->Write("0", 1);
+ break;
+ case 10:
+ break;
+ }
+ s->Write(apint_str.c_str(), apint_str.size());
+ }
+ return offset;
+}
+
+lldb::offset_t lldb_private::DumpDataExtractor(
+ const DataExtractor &DE, Stream *s, offset_t start_offset,
+ lldb::Format item_format, size_t item_byte_size, size_t item_count,
+ size_t num_per_line, uint64_t base_addr,
+ uint32_t item_bit_size, // If zero, this is not a bitfield value, if
+ // non-zero, the value is a bitfield
+ uint32_t item_bit_offset, // If "item_bit_size" is non-zero, this is the
+ // shift amount to apply to a bitfield
+ ExecutionContextScope *exe_scope) {
+ if (s == nullptr)
+ return start_offset;
+
+ if (item_format == eFormatPointer) {
+ if (item_byte_size != 4 && item_byte_size != 8)
+ item_byte_size = s->GetAddressByteSize();
+ }
+
+ offset_t offset = start_offset;
+
+ if (item_format == eFormatInstruction) {
+ TargetSP target_sp;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+ if (target_sp) {
+ DisassemblerSP disassembler_sp(Disassembler::FindPlugin(
+ target_sp->GetArchitecture(),
+ target_sp->GetDisassemblyFlavor(), nullptr));
+ if (disassembler_sp) {
+ lldb::addr_t addr = base_addr + start_offset;
+ lldb_private::Address so_addr;
+ bool data_from_file = true;
+ if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
+ data_from_file = false;
+ } else {
+ if (target_sp->GetSectionLoadList().IsEmpty() ||
+ !target_sp->GetImages().ResolveFileAddress(addr, so_addr))
+ so_addr.SetRawAddress(addr);
+ }
+
+ size_t bytes_consumed = disassembler_sp->DecodeInstructions(
+ so_addr, DE, start_offset, item_count, false, data_from_file);
+
+ if (bytes_consumed) {
+ offset += bytes_consumed;
+ const bool show_address = base_addr != LLDB_INVALID_ADDRESS;
+ const bool show_bytes = true;
+ ExecutionContext exe_ctx;
+ exe_scope->CalculateExecutionContext(exe_ctx);
+ disassembler_sp->GetInstructionList().Dump(s, show_address,
+ show_bytes, &exe_ctx);
+ }
+ }
+ } else
+ s->Printf("invalid target");
+
+ return offset;
+ }
+
+ if ((item_format == eFormatOSType || item_format == eFormatAddressInfo) &&
+ item_byte_size > 8)
+ item_format = eFormatHex;
+
+ lldb::offset_t line_start_offset = start_offset;
+ for (uint32_t count = 0; DE.ValidOffset(offset) && count < item_count;
+ ++count) {
+ if ((count % num_per_line) == 0) {
+ if (count > 0) {
+ if (item_format == eFormatBytesWithASCII &&
+ offset > line_start_offset) {
+ s->Printf("%*s",
+ static_cast<int>(
+ (num_per_line - (offset - line_start_offset)) * 3 + 2),
+ "");
+ DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1,
+ offset - line_start_offset, SIZE_MAX,
+ LLDB_INVALID_ADDRESS, 0, 0);
+ }
+ s->EOL();
+ }
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ s->Printf("0x%8.8" PRIx64 ": ",
+ (uint64_t)(base_addr +
+ (offset - start_offset) / DE.getTargetByteSize()));
+
+ line_start_offset = offset;
+ } else if (item_format != eFormatChar &&
+ item_format != eFormatCharPrintable &&
+ item_format != eFormatCharArray && count > 0) {
+ s->PutChar(' ');
+ }
+
+ switch (item_format) {
+ case eFormatBoolean:
+ if (item_byte_size <= 8)
+ s->Printf("%s", DE.GetMaxU64Bitfield(&offset, item_byte_size,
+ item_bit_size, item_bit_offset)
+ ? "true"
+ : "false");
+ else {
+ s->Printf("error: unsupported byte size (%" PRIu64
+ ") for boolean format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+ break;
+
+ case eFormatBinary:
+ if (item_byte_size <= 8) {
+ uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size,
+ item_bit_size, item_bit_offset);
+ // Avoid std::bitset<64>::to_string() since it is missing in
+ // earlier C++ libraries
+ std::string binary_value(64, '0');
+ std::bitset<64> bits(uval64);
+ for (uint32_t i = 0; i < 64; ++i)
+ if (bits[i])
+ binary_value[64 - 1 - i] = '1';
+ if (item_bit_size > 0)
+ s->Printf("0b%s", binary_value.c_str() + 64 - item_bit_size);
+ else if (item_byte_size > 0 && item_byte_size <= 8)
+ s->Printf("0b%s", binary_value.c_str() + 64 - item_byte_size * 8);
+ } else {
+ const bool is_signed = false;
+ const unsigned radix = 2;
+ offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatBytes:
+ case eFormatBytesWithASCII:
+ for (uint32_t i = 0; i < item_byte_size; ++i) {
+ s->Printf("%2.2x", DE.GetU8(&offset));
+ }
+
+ // Put an extra space between the groups of bytes if more than one
+ // is being dumped in a group (item_byte_size is more than 1).
+ if (item_byte_size > 1)
+ s->PutChar(' ');
+ break;
+
+ case eFormatChar:
+ case eFormatCharPrintable:
+ case eFormatCharArray: {
+ // If we are only printing one character surround it with single
+ // quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+
+ const uint64_t ch = DE.GetMaxU64Bitfield(&offset, item_byte_size,
+ item_bit_size, item_bit_offset);
+ if (isprint(ch))
+ s->Printf("%c", (char)ch);
+ else if (item_format != eFormatCharPrintable) {
+ switch (ch) {
+ case '\033':
+ s->Printf("\\e");
+ break;
+ case '\a':
+ s->Printf("\\a");
+ break;
+ case '\b':
+ s->Printf("\\b");
+ break;
+ case '\f':
+ s->Printf("\\f");
+ break;
+ case '\n':
+ s->Printf("\\n");
+ break;
+ case '\r':
+ s->Printf("\\r");
+ break;
+ case '\t':
+ s->Printf("\\t");
+ break;
+ case '\v':
+ s->Printf("\\v");
+ break;
+ case '\0':
+ s->Printf("\\0");
+ break;
+ default:
+ if (item_byte_size == 1)
+ s->Printf("\\x%2.2x", (uint8_t)ch);
+ else
+ s->Printf("%" PRIu64, ch);
+ break;
+ }
+ } else {
+ s->PutChar(NON_PRINTABLE_CHAR);
+ }
+
+ // If we are only printing one character surround it with single quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+ } break;
+
+ case eFormatEnum: // Print enum value as a signed integer when we don't get
+ // the enum type
+ case eFormatDecimal:
+ if (item_byte_size <= 8)
+ s->Printf("%" PRId64,
+ DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset));
+ else {
+ const bool is_signed = true;
+ const unsigned radix = 10;
+ offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatUnsigned:
+ if (item_byte_size <= 8)
+ s->Printf("%" PRIu64,
+ DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset));
+ else {
+ const bool is_signed = false;
+ const unsigned radix = 10;
+ offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatOctal:
+ if (item_byte_size <= 8)
+ s->Printf("0%" PRIo64,
+ DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset));
+ else {
+ const bool is_signed = false;
+ const unsigned radix = 8;
+ offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatOSType: {
+ uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size,
+ item_bit_size, item_bit_offset);
+ s->PutChar('\'');
+ for (uint32_t i = 0; i < item_byte_size; ++i) {
+ uint8_t ch = (uint8_t)(uval64 >> ((item_byte_size - i - 1) * 8));
+ if (isprint(ch))
+ s->Printf("%c", ch);
+ else {
+ switch (ch) {
+ case '\033':
+ s->Printf("\\e");
+ break;
+ case '\a':
+ s->Printf("\\a");
+ break;
+ case '\b':
+ s->Printf("\\b");
+ break;
+ case '\f':
+ s->Printf("\\f");
+ break;
+ case '\n':
+ s->Printf("\\n");
+ break;
+ case '\r':
+ s->Printf("\\r");
+ break;
+ case '\t':
+ s->Printf("\\t");
+ break;
+ case '\v':
+ s->Printf("\\v");
+ break;
+ case '\0':
+ s->Printf("\\0");
+ break;
+ default:
+ s->Printf("\\x%2.2x", ch);
+ break;
+ }
+ }
+ }
+ s->PutChar('\'');
+ } break;
+
+ case eFormatCString: {
+ const char *cstr = DE.GetCStr(&offset);
+
+ if (!cstr) {
+ s->Printf("NULL");
+ offset = LLDB_INVALID_OFFSET;
+ } else {
+ s->PutChar('\"');
+
+ while (const char c = *cstr) {
+ if (isprint(c)) {
+ s->PutChar(c);
+ } else {
+ switch (c) {
+ case '\033':
+ s->Printf("\\e");
+ break;
+ case '\a':
+ s->Printf("\\a");
+ break;
+ case '\b':
+ s->Printf("\\b");
+ break;
+ case '\f':
+ s->Printf("\\f");
+ break;
+ case '\n':
+ s->Printf("\\n");
+ break;
+ case '\r':
+ s->Printf("\\r");
+ break;
+ case '\t':
+ s->Printf("\\t");
+ break;
+ case '\v':
+ s->Printf("\\v");
+ break;
+ default:
+ s->Printf("\\x%2.2x", c);
+ break;
+ }
+ }
+
+ ++cstr;
+ }
+
+ s->PutChar('\"');
+ }
+ } break;
+
+ case eFormatPointer:
+ s->Address(DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset),
+ sizeof(addr_t));
+ break;
+
+ case eFormatComplexInteger: {
+ size_t complex_int_byte_size = item_byte_size / 2;
+
+ if (complex_int_byte_size > 0 && complex_int_byte_size <= 8) {
+ s->Printf("%" PRIu64,
+ DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
+ s->Printf(" + %" PRIu64 "i",
+ DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
+ } else {
+ s->Printf("error: unsupported byte size (%" PRIu64
+ ") for complex integer format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+ } break;
+
+ case eFormatComplex:
+ if (sizeof(float) * 2 == item_byte_size) {
+ float f32_1 = DE.GetFloat(&offset);
+ float f32_2 = DE.GetFloat(&offset);
+
+ s->Printf("%g + %gi", f32_1, f32_2);
+ break;
+ } else if (sizeof(double) * 2 == item_byte_size) {
+ double d64_1 = DE.GetDouble(&offset);
+ double d64_2 = DE.GetDouble(&offset);
+
+ s->Printf("%lg + %lgi", d64_1, d64_2);
+ break;
+ } else if (sizeof(long double) * 2 == item_byte_size) {
+ long double ld64_1 = DE.GetLongDouble(&offset);
+ long double ld64_2 = DE.GetLongDouble(&offset);
+ s->Printf("%Lg + %Lgi", ld64_1, ld64_2);
+ break;
+ } else {
+ s->Printf("error: unsupported byte size (%" PRIu64
+ ") for complex float format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+ break;
+
+ default:
+ case eFormatDefault:
+ case eFormatHex:
+ case eFormatHexUppercase: {
+ bool wantsuppercase = (item_format == eFormatHexUppercase);
+ switch (item_byte_size) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64,
+ (int)(2 * item_byte_size), (int)(2 * item_byte_size),
+ DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset));
+ break;
+ default: {
+ assert(item_bit_size == 0 && item_bit_offset == 0);
+ const uint8_t *bytes =
+ (const uint8_t *)DE.GetData(&offset, item_byte_size);
+ if (bytes) {
+ s->PutCString("0x");
+ uint32_t idx;
+ if (DE.GetByteOrder() == eByteOrderBig) {
+ for (idx = 0; idx < item_byte_size; ++idx)
+ s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[idx]);
+ } else {
+ for (idx = 0; idx < item_byte_size; ++idx)
+ s->Printf(wantsuppercase ? "%2.2X" : "%2.2x",
+ bytes[item_byte_size - 1 - idx]);
+ }
+ }
+ } break;
+ }
+ } break;
+
+ case eFormatFloat: {
+ TargetSP target_sp;
+ bool used_apfloat = false;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+ if (target_sp) {
+ ClangASTContext *clang_ast = target_sp->GetScratchClangASTContext();
+ if (clang_ast) {
+ clang::ASTContext *ast = clang_ast->getASTContext();
+ if (ast) {
+ llvm::SmallVector<char, 256> sv;
+ // Show full precision when printing float values
+ const unsigned format_precision = 0;
+ const unsigned format_max_padding = 100;
+ size_t item_bit_size = item_byte_size * 8;
+
+ if (item_bit_size == ast->getTypeSize(ast->FloatTy)) {
+ llvm::APInt apint(item_bit_size,
+ DE.GetMaxU64(&offset, item_byte_size));
+ llvm::APFloat apfloat(ast->getFloatTypeSemantics(ast->FloatTy),
+ apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ } else if (item_bit_size == ast->getTypeSize(ast->DoubleTy)) {
+ llvm::APInt apint;
+ if (GetAPInt(DE, &offset, item_byte_size, apint)) {
+ llvm::APFloat apfloat(ast->getFloatTypeSemantics(ast->DoubleTy),
+ apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ } else if (item_bit_size == ast->getTypeSize(ast->LongDoubleTy)) {
+ const auto &semantics =
+ ast->getFloatTypeSemantics(ast->LongDoubleTy);
+ const auto byte_size =
+ (llvm::APFloat::getSizeInBits(semantics) + 7) / 8;
+
+ llvm::APInt apint;
+ if (GetAPInt(DE, &offset, byte_size, apint)) {
+ llvm::APFloat apfloat(semantics, apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ } else if (item_bit_size == ast->getTypeSize(ast->HalfTy)) {
+ llvm::APInt apint(item_bit_size, DE.GetU16(&offset));
+ llvm::APFloat apfloat(ast->getFloatTypeSemantics(ast->HalfTy),
+ apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+
+ if (!sv.empty()) {
+ s->Printf("%*.*s", (int)sv.size(), (int)sv.size(), sv.data());
+ used_apfloat = true;
+ }
+ }
+ }
+ }
+
+ if (!used_apfloat) {
+ std::ostringstream ss;
+ if (item_byte_size == sizeof(float) || item_byte_size == 2) {
+ float f;
+ if (item_byte_size == 2) {
+ uint16_t half = DE.GetU16(&offset);
+ f = half2float(half);
+ } else {
+ f = DE.GetFloat(&offset);
+ }
+ ss.precision(std::numeric_limits<float>::digits10);
+ ss << f;
+ } else if (item_byte_size == sizeof(double)) {
+ ss.precision(std::numeric_limits<double>::digits10);
+ ss << DE.GetDouble(&offset);
+ } else if (item_byte_size == sizeof(long double) ||
+ item_byte_size == 10) {
+ ss.precision(std::numeric_limits<long double>::digits10);
+ ss << DE.GetLongDouble(&offset);
+ } else {
+ s->Printf("error: unsupported byte size (%" PRIu64
+ ") for float format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+ ss.flush();
+ s->Printf("%s", ss.str().c_str());
+ }
+ } break;
+
+ case eFormatUnicode16:
+ s->Printf("U+%4.4x", DE.GetU16(&offset));
+ break;
+
+ case eFormatUnicode32:
+ s->Printf("U+0x%8.8x", DE.GetU32(&offset));
+ break;
+
+ case eFormatAddressInfo: {
+ addr_t addr = DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset);
+ s->Printf("0x%*.*" PRIx64, (int)(2 * item_byte_size),
+ (int)(2 * item_byte_size), addr);
+ if (exe_scope) {
+ TargetSP target_sp(exe_scope->CalculateTarget());
+ lldb_private::Address so_addr;
+ if (target_sp) {
+ if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr,
+ so_addr)) {
+ s->PutChar(' ');
+ so_addr.Dump(s, exe_scope, Address::DumpStyleResolvedDescription,
+ Address::DumpStyleModuleWithFileAddress);
+ } else {
+ so_addr.SetOffset(addr);
+ so_addr.Dump(s, exe_scope,
+ Address::DumpStyleResolvedPointerDescription);
+ }
+ }
+ }
+ } break;
+
+ case eFormatHexFloat:
+ if (sizeof(float) == item_byte_size) {
+ char float_cstr[256];
+ llvm::APFloat ap_float(DE.GetFloat(&offset));
+ ap_float.convertToHexString(float_cstr, 0, false,
+ llvm::APFloat::rmNearestTiesToEven);
+ s->Printf("%s", float_cstr);
+ break;
+ } else if (sizeof(double) == item_byte_size) {
+ char float_cstr[256];
+ llvm::APFloat ap_float(DE.GetDouble(&offset));
+ ap_float.convertToHexString(float_cstr, 0, false,
+ llvm::APFloat::rmNearestTiesToEven);
+ s->Printf("%s", float_cstr);
+ break;
+ } else {
+ s->Printf("error: unsupported byte size (%" PRIu64
+ ") for hex float format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+ break;
+
+ // please keep the single-item formats below in sync with
+ // FormatManager::GetSingleItemFormat
+ // if you fail to do so, users will start getting different outputs
+ // depending on internal
+ // implementation details they should not care about ||
+ case eFormatVectorOfChar: // ||
+ s->PutChar('{'); // \/
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatCharArray, 1, item_byte_size,
+ item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt8:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatDecimal, 1, item_byte_size,
+ item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt8:
+ s->PutChar('{');
+ offset = DumpDataExtractor(DE, s, offset, eFormatHex, 1, item_byte_size,
+ item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt16:
+ s->PutChar('{');
+ offset = DumpDataExtractor(
+ DE, s, offset, eFormatDecimal, sizeof(uint16_t),
+ item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt16:
+ s->PutChar('{');
+ offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint16_t),
+ item_byte_size / sizeof(uint16_t),
+ item_byte_size / sizeof(uint16_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt32:
+ s->PutChar('{');
+ offset = DumpDataExtractor(
+ DE, s, offset, eFormatDecimal, sizeof(uint32_t),
+ item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt32:
+ s->PutChar('{');
+ offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint32_t),
+ item_byte_size / sizeof(uint32_t),
+ item_byte_size / sizeof(uint32_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt64:
+ s->PutChar('{');
+ offset = DumpDataExtractor(
+ DE, s, offset, eFormatDecimal, sizeof(uint64_t),
+ item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt64:
+ s->PutChar('{');
+ offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint64_t),
+ item_byte_size / sizeof(uint64_t),
+ item_byte_size / sizeof(uint64_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat16:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatFloat, 2, item_byte_size / 2,
+ item_byte_size / 2, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat32:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatFloat, 4, item_byte_size / 4,
+ item_byte_size / 4, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat64:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatFloat, 8, item_byte_size / 8,
+ item_byte_size / 8, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt128:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatHex, 16, item_byte_size / 16,
+ item_byte_size / 16, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+ }
+ }
+
+ if (item_format == eFormatBytesWithASCII && offset > line_start_offset) {
+ s->Printf("%*s", static_cast<int>(
+ (num_per_line - (offset - line_start_offset)) * 3 + 2),
+ "");
+ DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1,
+ offset - line_start_offset, SIZE_MAX,
+ LLDB_INVALID_ADDRESS, 0, 0);
+ }
+ return offset; // Return the offset at which we ended up
+}
+
+void lldb_private::DumpHexBytes(Stream *s, const void *src, size_t src_len,
+ uint32_t bytes_per_line,
+ lldb::addr_t base_addr) {
+ DataExtractor data(src, src_len, lldb::eByteOrderLittle, 4);
+ DumpDataExtractor(data, s,
+ 0, // Offset into "src"
+ lldb::eFormatBytes, // Dump as hex bytes
+ 1, // Size of each item is 1 for single bytes
+ src_len, // Number of bytes
+ bytes_per_line, // Num bytes per line
+ base_addr, // Base address
+ 0, 0); // Bitfield info
+}
diff --git a/contrib/llvm/tools/lldb/source/Core/DynamicLoader.cpp b/contrib/llvm/tools/lldb/source/Core/DynamicLoader.cpp
index 69c5ea3..5477498 100644
--- a/contrib/llvm/tools/lldb/source/Core/DynamicLoader.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/DynamicLoader.cpp
@@ -7,19 +7,25 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Target/DynamicLoader.h"
+
#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h" // for ModuleList
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h" // for ObjectFile
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/lldb-private-interfaces.h" // for DynamicLoaderCreateInstance
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <memory> // for shared_ptr, unique_ptr
+
+#include <assert.h> // for assert
using namespace lldb;
using namespace lldb_private;
@@ -78,7 +84,7 @@ ModuleSP DynamicLoader::GetTargetExecutable() {
if (executable->GetFileSpec().Exists()) {
ModuleSpec module_spec(executable->GetFileSpec(),
executable->GetArchitecture());
- ModuleSP module_sp(new Module(module_spec));
+ auto module_sp = std::make_shared<Module>(module_spec);
// Check if the executable has changed and set it to the target executable
// if they differ.
@@ -175,7 +181,7 @@ ModuleSP DynamicLoader::LoadModuleAtAddress(const FileSpec &file,
// address to read the file out of the memory instead of a load bias.
bool is_loaded = false;
lldb::addr_t load_addr;
- Error error = m_process->GetFileLoadAddress(file, is_loaded, load_addr);
+ Status error = m_process->GetFileLoadAddress(file, is_loaded, load_addr);
if (error.Success() && is_loaded) {
check_alternative_file_name = false;
base_addr = load_addr;
@@ -187,9 +193,10 @@ ModuleSP DynamicLoader::LoadModuleAtAddress(const FileSpec &file,
// different name based on the memory region info.
if (check_alternative_file_name) {
MemoryRegionInfo memory_info;
- Error error = m_process->GetMemoryRegionInfo(base_addr, memory_info);
+ Status error = m_process->GetMemoryRegionInfo(base_addr, memory_info);
if (error.Success() && memory_info.GetMapped() &&
- memory_info.GetRange().GetRangeBase() == base_addr) {
+ memory_info.GetRange().GetRangeBase() == base_addr &&
+ !(memory_info.GetName().IsEmpty())) {
ModuleSpec new_module_spec(
FileSpec(memory_info.GetName().AsCString(), false),
target.GetArchitecture());
@@ -216,7 +223,7 @@ ModuleSP DynamicLoader::LoadModuleAtAddress(const FileSpec &file,
int64_t DynamicLoader::ReadUnsignedIntWithSizeInBytes(addr_t addr,
int size_in_bytes) {
- Error error;
+ Status error;
uint64_t value =
m_process->ReadUnsignedIntegerFromMemory(addr, size_in_bytes, 0, error);
if (error.Fail())
@@ -226,10 +233,17 @@ int64_t DynamicLoader::ReadUnsignedIntWithSizeInBytes(addr_t addr,
}
addr_t DynamicLoader::ReadPointer(addr_t addr) {
- Error error;
+ Status error;
addr_t value = m_process->ReadPointerFromMemory(addr, error);
if (error.Fail())
return LLDB_INVALID_ADDRESS;
else
return value;
}
+
+void DynamicLoader::LoadOperatingSystemPlugin(bool flush)
+{
+ if (m_process)
+ m_process->LoadOperatingSystemPlugin(flush);
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Core/EmulateInstruction.cpp b/contrib/llvm/tools/lldb/source/Core/EmulateInstruction.cpp
index bc32fb2..2ee2c79 100644
--- a/contrib/llvm/tools/lldb/source/Core/EmulateInstruction.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/EmulateInstruction.cpp
@@ -9,25 +9,33 @@
#include "lldb/Core/EmulateInstruction.h"
-// C Includes
-// C++ Includes
-#include <cstring>
-
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/Address.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Target/Thread.h"
+#include "lldb/Target/StackFrame.h" // for StackFrame
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h" // for Stream, Stream::::eBinary
+#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-forward.h" // for ProcessSP
+#include "lldb/lldb-private-interfaces.h" // for EmulateInstructionCreateIn...
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <cstring>
+#include <memory> // for shared_ptr
+
+#include <inttypes.h> // for PRIx64, PRId64, PRIu64
+#include <stdio.h> // for stdout
+
+namespace lldb_private {
+class Target;
+}
using namespace lldb;
using namespace lldb_private;
@@ -255,7 +263,7 @@ size_t EmulateInstruction::ReadMemoryFrame(EmulateInstruction *instruction,
ProcessSP process_sp(frame->CalculateProcess());
if (process_sp) {
- Error error;
+ Status error;
return process_sp->ReadMemory(addr, dst, dst_len, error);
}
return 0;
@@ -272,7 +280,7 @@ size_t EmulateInstruction::WriteMemoryFrame(EmulateInstruction *instruction,
ProcessSP process_sp(frame->CalculateProcess());
if (process_sp) {
- Error error;
+ Status error;
return process_sp->WriteMemory(addr, src, src_len, error);
}
diff --git a/contrib/llvm/tools/lldb/source/Core/Event.cpp b/contrib/llvm/tools/lldb/source/Core/Event.cpp
index bd57198..8d351d8 100644
--- a/contrib/llvm/tools/lldb/source/Core/Event.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Event.cpp
@@ -7,20 +7,19 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-#include <algorithm>
+#include "lldb/Core/Event.h"
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Event.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/State.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Host/Endian.h"
-#include "lldb/Target/Process.h"
+#include "lldb/Core/DumpDataExtractor.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h" // for StreamString
+#include "lldb/lldb-enumerations.h" // for Format::eFormatBytes
+
+#include <algorithm>
+
+#include <ctype.h> // for isprint
using namespace lldb;
using namespace lldb_private;
@@ -140,8 +139,8 @@ void EventDataBytes::Dump(Stream *s) const {
} else if (!m_bytes.empty()) {
DataExtractor data;
data.SetData(m_bytes.data(), m_bytes.size(), endian::InlHostByteOrder());
- data.Dump(s, 0, eFormatBytes, 1, m_bytes.size(), 32, LLDB_INVALID_ADDRESS,
- 0, 0);
+ DumpDataExtractor(data, s, 0, eFormatBytes, 1, m_bytes.size(), 32,
+ LLDB_INVALID_ADDRESS, 0, 0);
}
}
diff --git a/contrib/llvm/tools/lldb/source/Core/FileLineResolver.cpp b/contrib/llvm/tools/lldb/source/Core/FileLineResolver.cpp
index db56cae..36f37f4 100644
--- a/contrib/llvm/tools/lldb/source/Core/FileLineResolver.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/FileLineResolver.cpp
@@ -10,10 +10,17 @@
#include "lldb/Core/FileLineResolver.h"
// Project includes
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Core/FileSpecList.h" // for FileSpecList
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/Stream.h" // for Stream
+
+#include <string> // for string
+
+namespace lldb_private {
+class Address;
+}
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/FileSpecList.cpp b/contrib/llvm/tools/lldb/source/Core/FileSpecList.cpp
index d4ce4b7..a69f490 100644
--- a/contrib/llvm/tools/lldb/source/Core/FileSpecList.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/FileSpecList.cpp
@@ -9,13 +9,12 @@
#include "lldb/Core/FileSpecList.h"
-// C Includes
-// C++ Includes
-#include <algorithm>
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/Stream.h"
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Stream.h"
+#include <utility> // for find
+
+#include <stdint.h> // for UINT32_MAX
using namespace lldb_private;
using namespace std;
@@ -150,32 +149,23 @@ size_t FileSpecList::GetFilesMatchingPartialPath(const char *path,
FileSpecList &matches) {
#if 0 // FIXME: Just sketching...
matches.Clear();
- FileSpec path_spec = FileSpec (path);
- if (path_spec.Exists ())
- {
- FileSpec::FileType type = path_spec.GetFileType();
- if (type == FileSpec::eFileTypeSymbolicLink)
- // Shouldn't there be a Resolve on a file spec that real-path's it?
- {
- }
-
- if (type == FileSpec::eFileTypeRegular
- || (type == FileSpec::eFileTypeDirectory && dir_okay))
- {
- matches.Append (path_spec);
- return 1;
- }
- else if (type == FileSpec::eFileTypeDirectory)
- {
- // Fill the match list with all the files in the directory:
- }
- else
- {
- return 0;
- }
- }
- else
- {
+ using namespace llvm::sys::fs;
+ file_status stats;
+ if (status(path, stats, false))
+ return 0;
+ if (exists(stats)) {
+ if (is_symlink_file(stats)) {
+ // Shouldn't there be a method that realpath's a file?
+ }
+ if (is_regular_file(stats) || (is_directory(stats) && dir_okay)) {
+ matches.Append(FileSpec(path));
+ return 1;
+ } else if (is_directory(stats)) {
+ // Fill the match list with all the files in the directory:
+ } else {
+ return 0;
+ }
+ } else {
ConstString dir_name = path_spec.GetDirectory();
ConstString file_name = GetFilename();
if (dir_name == nullptr)
diff --git a/contrib/llvm/tools/lldb/source/Core/FormatEntity.cpp b/contrib/llvm/tools/lldb/source/Core/FormatEntity.cpp
index 08166d2..6002efe 100644
--- a/contrib/llvm/tools/lldb/source/Core/FormatEntity.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/FormatEntity.cpp
@@ -9,33 +9,30 @@
#include "lldb/Core/FormatEntity.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringRef.h"
-
-// Project includes
#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h" // for AddressRange
+#include "lldb/Core/ArchSpec.h" // for ArchSpec
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Core/RegisterValue.h" // for RegisterValue
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/DataFormatters/FormatClasses.h" // for TypeNameSpecifier...
#include "lldb/DataFormatters/FormatManager.h"
-#include "lldb/DataFormatters/ValueObjectPrinter.h"
+#include "lldb/DataFormatters/TypeSummary.h" // for TypeSummaryImpl::...
#include "lldb/Expression/ExpressionVariable.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/CompilerType.h" // for CompilerType
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/LineEntry.h"
#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h" // for SymbolContext
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h" // for ExecutionContextS...
#include "lldb/Target/Language.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -45,6 +42,37 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/AnsiTerminal.h"
+#include "lldb/Utility/ConstString.h" // for ConstString, oper...
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h" // for Log
+#include "lldb/Utility/Logging.h" // for GetLogIfAllCatego...
+#include "lldb/Utility/SharingPtr.h" // for SharingPtr
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StringList.h" // for StringList
+#include "lldb/Utility/StructuredData.h" // for StructuredData::O...
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-forward.h" // for ValueObjectSP
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h" // for Triple, Triple::O...
+#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
+
+#include <ctype.h> // for isxdigit
+#include <inttypes.h> // for PRIu64, PRIx64
+#include <memory> // for shared_ptr, opera...
+#include <stdio.h> // for sprintf
+#include <stdlib.h> // for strtoul
+#include <string.h> // for size_t, strchr
+#include <type_traits> // for move
+#include <utility> // for pair
+
+namespace lldb_private {
+class ScriptInterpreter;
+}
+namespace lldb_private {
+struct RegisterInfo;
+}
using namespace lldb;
using namespace lldb_private;
@@ -64,14 +92,14 @@ enum FileKind { FileError = 0, Basename, Dirname, Fullpath };
#define ENTRY_CHILDREN(n, t, f, c) \
{ \
n, nullptr, FormatEntity::Entry::Type::t, \
- FormatEntity::Entry::FormatType::f, 0, llvm::array_lengthof(c), c, \
- false \
+ FormatEntity::Entry::FormatType::f, 0, \
+ static_cast<uint32_t>(llvm::array_lengthof(c)), c, false \
}
#define ENTRY_CHILDREN_KEEP_SEP(n, t, f, c) \
{ \
n, nullptr, FormatEntity::Entry::Type::t, \
- FormatEntity::Entry::FormatType::f, 0, llvm::array_lengthof(c), c, \
- true \
+ FormatEntity::Entry::FormatType::f, 0, \
+ static_cast<uint32_t>(llvm::array_lengthof(c)), c, true \
}
#define ENTRY_STRING(n, s) \
{ \
@@ -275,7 +303,7 @@ void FormatEntity::Entry::AppendText(const char *cstr) {
return AppendText(llvm::StringRef(cstr));
}
-Error FormatEntity::Parse(const llvm::StringRef &format_str, Entry &entry) {
+Status FormatEntity::Parse(const llvm::StringRef &format_str, Entry &entry) {
entry.Clear();
entry.type = Entry::Type::Root;
llvm::StringRef modifiable_format(format_str);
@@ -380,7 +408,7 @@ static bool RunScriptFormatKeyword(Stream &s, const SymbolContext *sc,
ScriptInterpreter *script_interpreter =
target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
if (script_interpreter) {
- Error error;
+ Status error;
std::string script_output;
if (script_interpreter->RunScriptFormatKeyword(script_function_name, t,
@@ -750,7 +778,7 @@ static bool DumpValue(Stream &s, const SymbolContext *sc,
var_name_final_if_array_range, index_lower,
index_higher);
- Error error;
+ Status error;
const std::string &expr_path = entry.string;
@@ -796,7 +824,7 @@ static bool DumpValue(Stream &s, const SymbolContext *sc,
// this happens when we are not going through
// GetValueForVariableExpressionPath
// to get to the target ValueObject
- Error error;
+ Status error;
target = target->Dereference(error).get();
if (error.Fail()) {
if (log)
@@ -822,8 +850,8 @@ static bool DumpValue(Stream &s, const SymbolContext *sc,
StreamString bitfield_name;
bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(),
target->GetBitfieldBitSize());
- lldb::TypeNameSpecifierImplSP type_sp(
- new TypeNameSpecifierImpl(bitfield_name.GetString(), false));
+ auto type_sp = std::make_shared<TypeNameSpecifierImpl>(
+ bitfield_name.GetString(), false);
if (val_obj_display ==
ValueObject::eValueObjectRepresentationStyleSummary &&
!DataVisualization::GetSummaryForType(type_sp))
@@ -1012,24 +1040,24 @@ static bool FormatThreadExtendedInfoRecurse(
thread_info_dictionary->GetObjectForDotSeparatedPath(path);
if (value) {
- if (value->GetType() == StructuredData::Type::eTypeInteger) {
+ if (value->GetType() == eStructuredDataTypeInteger) {
const char *token_format = "0x%4.4" PRIx64;
if (!entry.printf_format.empty())
token_format = entry.printf_format.c_str();
s.Printf(token_format, value->GetAsInteger()->GetValue());
return true;
- } else if (value->GetType() == StructuredData::Type::eTypeFloat) {
+ } else if (value->GetType() == eStructuredDataTypeFloat) {
s.Printf("%f", value->GetAsFloat()->GetValue());
return true;
- } else if (value->GetType() == StructuredData::Type::eTypeString) {
- s.Printf("%s", value->GetAsString()->GetValue().c_str());
+ } else if (value->GetType() == eStructuredDataTypeString) {
+ s.Format("{0}", value->GetAsString()->GetValue());
return true;
- } else if (value->GetType() == StructuredData::Type::eTypeArray) {
+ } else if (value->GetType() == eStructuredDataTypeArray) {
if (value->GetAsArray()->GetSize() > 0) {
s.Printf("%zu", value->GetAsArray()->GetSize());
return true;
}
- } else if (value->GetType() == StructuredData::Type::eTypeDictionary) {
+ } else if (value->GetType() == eStructuredDataTypeDictionary) {
s.Printf("%zu",
value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize());
return true;
@@ -1051,7 +1079,7 @@ bool FormatEntity::FormatStringRef(const llvm::StringRef &format_str, Stream &s,
bool initial_function) {
if (!format_str.empty()) {
FormatEntity::Entry root;
- Error error = FormatEntity::Parse(format_str, root);
+ Status error = FormatEntity::Parse(format_str, root);
if (error.Success()) {
return FormatEntity::Format(root, s, sc, exe_ctx, addr, valobj,
function_changed, initial_function);
@@ -1068,7 +1096,7 @@ bool FormatEntity::FormatCString(const char *format, Stream &s,
if (format && format[0]) {
FormatEntity::Entry root;
llvm::StringRef format_str(format);
- Error error = FormatEntity::Parse(format_str, root);
+ Status error = FormatEntity::Parse(format_str, root);
if (error.Success()) {
return FormatEntity::Format(root, s, sc, exe_ctx, addr, valobj,
function_changed, initial_function);
@@ -1187,7 +1215,8 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
? arch.GetTriple().getOS()
: llvm::Triple::UnknownOS;
if ((ostype == llvm::Triple::FreeBSD) ||
- (ostype == llvm::Triple::Linux)) {
+ (ostype == llvm::Triple::Linux) ||
+ (ostype == llvm::Triple::NetBSD)) {
format = "%" PRIu64;
}
} else {
@@ -1317,7 +1346,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
if (thread) {
StructuredData::ObjectSP object_sp = thread->GetExtendedInfo();
if (object_sp &&
- object_sp->GetType() == StructuredData::Type::eTypeDictionary) {
+ object_sp->GetType() == eStructuredDataTypeDictionary) {
if (FormatThreadExtendedInfoRecurse(entry, object_sp, sc, exe_ctx, s))
return true;
}
@@ -1837,10 +1866,10 @@ static bool DumpCommaSeparatedChildEntryNames(
return false;
}
-static Error ParseEntry(const llvm::StringRef &format_str,
- const FormatEntity::Entry::Definition *parent,
- FormatEntity::Entry &entry) {
- Error error;
+static Status ParseEntry(const llvm::StringRef &format_str,
+ const FormatEntity::Entry::Definition *parent,
+ FormatEntity::Entry &entry) {
+ Status error;
const size_t sep_pos = format_str.find_first_of(".[:");
const char sep_char =
@@ -1927,7 +1956,7 @@ static const FormatEntity::Entry::Definition *
FindEntry(const llvm::StringRef &format_str,
const FormatEntity::Entry::Definition *parent,
llvm::StringRef &remainder) {
- Error error;
+ Status error;
std::pair<llvm::StringRef, llvm::StringRef> p = format_str.split('.');
const size_t n = parent->num_children;
@@ -1954,9 +1983,9 @@ FindEntry(const llvm::StringRef &format_str,
return parent;
}
-Error FormatEntity::ParseInternal(llvm::StringRef &format, Entry &parent_entry,
- uint32_t depth) {
- Error error;
+Status FormatEntity::ParseInternal(llvm::StringRef &format, Entry &parent_entry,
+ uint32_t depth) {
+ Status error;
while (!format.empty() && error.Success()) {
const size_t non_special_chars = format.find_first_of("${}\\");
@@ -2250,10 +2279,10 @@ Error FormatEntity::ParseInternal(llvm::StringRef &format, Entry &parent_entry,
return error;
}
-Error FormatEntity::ExtractVariableInfo(llvm::StringRef &format_str,
- llvm::StringRef &variable_name,
- llvm::StringRef &variable_format) {
- Error error;
+Status FormatEntity::ExtractVariableInfo(llvm::StringRef &format_str,
+ llvm::StringRef &variable_name,
+ llvm::StringRef &variable_format) {
+ Status error;
variable_name = llvm::StringRef();
variable_format = llvm::StringRef();
diff --git a/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp b/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp
index 9c5e6ca..194fec8 100644
--- a/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
+#include "lldb/Core/IOHandler.h"
+
// C Includes
#ifndef LLDB_DISABLE_CURSES
#include <curses.h>
@@ -21,36 +23,55 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/IOHandler.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Host/File.h" // for File
+#include "lldb/Host/Predicate.h" // for Predicate, ::eBroad...
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/Utility/StreamString.h" // for StreamString
+#include "lldb/Utility/StringList.h" // for StringList
+#include "lldb/lldb-forward.h" // for StreamFileSP
+
#ifndef LLDB_DISABLE_LIBEDIT
#include "lldb/Host/Editline.h"
#endif
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#ifndef LLDB_DISABLE_CURSES
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectRegister.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
-#include "lldb/Target/RegisterContext.h"
-#include "lldb/Target/ThreadPlan.h"
-#ifndef LLDB_DISABLE_CURSES
-#include "lldb/Core/ValueObject.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#endif
+#include "llvm/ADT/StringRef.h" // for StringRef
+
#ifdef _MSC_VER
-#include <Windows.h>
+#include "lldb/Host/windows/windows.h"
#endif
+#include <memory> // for shared_ptr
+#include <mutex> // for recursive_mutex
+
+#include <assert.h> // for assert
+#include <ctype.h> // for isspace
+#include <errno.h> // for EINTR, errno
+#include <stdint.h> // for uint32_t, UINT32_MAX
+#include <stdio.h> // for size_t, fprintf, feof
+#include <string.h> // for strlen
+#include <type_traits> // for move
+
using namespace lldb;
using namespace lldb_private;
@@ -494,7 +515,7 @@ bool IOHandlerEditline::GetLines(StringList &lines, bool &interrupted) {
} else {
#endif
bool done = false;
- Error error;
+ Status error;
while (!done) {
// Show line numbers if we are asked to
diff --git a/contrib/llvm/tools/lldb/source/Core/Listener.cpp b/contrib/llvm/tools/lldb/source/Core/Listener.cpp
index 3adb677..1afa116 100644
--- a/contrib/llvm/tools/lldb/source/Core/Listener.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Listener.cpp
@@ -9,16 +9,17 @@
#include "lldb/Core/Listener.h"
-// C Includes
-// C++ Includes
-#include <algorithm>
-
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet, LIBL...
+
+#include "llvm/ADT/Optional.h" // for Optional
+
+#include <algorithm>
+#include <memory> // for make_shared
+#include <utility> // for pair, make_pair
using namespace lldb;
using namespace lldb_private;
@@ -352,11 +353,7 @@ bool Listener::GetEventInternal(
uint32_t num_broadcaster_names, uint32_t event_type_mask,
EventSP &event_sp) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
- if (log != nullptr)
- log->Printf("%p Listener::GetEventInternal (timeout = %llu us) for %s",
- static_cast<void *>(this), static_cast<unsigned long long>(
- timeout ? timeout->count() : -1),
- m_name.c_str());
+ LLDB_LOG(log, "this = {0}, timeout = {1} for {2}", this, timeout, m_name);
std::unique_lock<std::mutex> lock(m_events_mutex);
diff --git a/contrib/llvm/tools/lldb/source/Core/Log.cpp b/contrib/llvm/tools/lldb/source/Core/Log.cpp
deleted file mode 100644
index b62df3c..0000000
--- a/contrib/llvm/tools/lldb/source/Core/Log.cpp
+++ /dev/null
@@ -1,399 +0,0 @@
-//===-- Log.cpp -------------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// Project includes
-#include "lldb/Core/Log.h"
-#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/Host.h"
-#include "lldb/Host/ThisThread.h"
-#include "lldb/Interpreter/Args.h"
-#include "lldb/Utility/NameMatches.h"
-
-// Other libraries and framework includes
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Chrono.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/raw_ostream.h"
-
-// C Includes
-// C++ Includes
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
-#include <map>
-#include <mutex>
-#include <string>
-
-using namespace lldb;
-using namespace lldb_private;
-
-Log::Log() : m_stream_sp(), m_options(0), m_mask_bits(0) {}
-
-Log::Log(const StreamSP &stream_sp)
- : m_stream_sp(stream_sp), m_options(0), m_mask_bits(0) {}
-
-Log::~Log() = default;
-
-Flags &Log::GetOptions() { return m_options; }
-
-const Flags &Log::GetOptions() const { return m_options; }
-
-Flags &Log::GetMask() { return m_mask_bits; }
-
-const Flags &Log::GetMask() const { return m_mask_bits; }
-
-void Log::PutCString(const char *cstr) { Printf("%s", cstr); }
-void Log::PutString(llvm::StringRef str) { PutCString(str.str().c_str()); }
-
-//----------------------------------------------------------------------
-// Simple variable argument logging with flags.
-//----------------------------------------------------------------------
-void Log::Printf(const char *format, ...) {
- va_list args;
- va_start(args, format);
- VAPrintf(format, args);
- va_end(args);
-}
-
-//----------------------------------------------------------------------
-// All logging eventually boils down to this function call. If we have
-// a callback registered, then we call the logging callback. If we have
-// a valid file handle, we also log to the file.
-//----------------------------------------------------------------------
-void Log::VAPrintf(const char *format, va_list args) {
- // Make a copy of our stream shared pointer in case someone disables our
- // log while we are logging and releases the stream
- StreamSP stream_sp(m_stream_sp);
- if (stream_sp) {
- static uint32_t g_sequence_id = 0;
- StreamString header;
-
- // Add a sequence ID if requested
- if (m_options.Test(LLDB_LOG_OPTION_PREPEND_SEQUENCE))
- header.Printf("%u ", ++g_sequence_id);
-
- // Timestamp if requested
- if (m_options.Test(LLDB_LOG_OPTION_PREPEND_TIMESTAMP)) {
- auto now = std::chrono::duration<double>(
- std::chrono::system_clock::now().time_since_epoch());
- header.Printf("%.9f ", now.count());
- }
-
- // Add the process and thread if requested
- if (m_options.Test(LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD))
- header.Printf("[%4.4x/%4.4" PRIx64 "]: ", getpid(),
- Host::GetCurrentThreadID());
-
- // Add the thread name if requested
- if (m_options.Test(LLDB_LOG_OPTION_PREPEND_THREAD_NAME)) {
- llvm::SmallString<32> thread_name;
- ThisThread::GetName(thread_name);
- if (!thread_name.empty())
- header.Printf("%s ", thread_name.c_str());
- }
-
- header.PrintfVarArg(format, args);
- header.PutCString("\n");
-
- if (m_options.Test(LLDB_LOG_OPTION_BACKTRACE)) {
- std::string back_trace;
- llvm::raw_string_ostream stream(back_trace);
- llvm::sys::PrintStackTrace(stream);
- stream.flush();
- header.PutCString(back_trace);
- }
-
- if (m_options.Test(LLDB_LOG_OPTION_THREADSAFE)) {
- static std::recursive_mutex g_LogThreadedMutex;
- std::lock_guard<std::recursive_mutex> guard(g_LogThreadedMutex);
- stream_sp->PutCString(header.GetString());
- stream_sp->Flush();
- } else {
- stream_sp->PutCString(header.GetString());
- stream_sp->Flush();
- }
- }
-}
-
-//----------------------------------------------------------------------
-// Print debug strings if and only if the global debug option is set to
-// a non-zero value.
-//----------------------------------------------------------------------
-void Log::Debug(const char *format, ...) {
- if (!GetOptions().Test(LLDB_LOG_OPTION_DEBUG))
- return;
-
- va_list args;
- va_start(args, format);
- VAPrintf(format, args);
- va_end(args);
-}
-
-//----------------------------------------------------------------------
-// Log only if all of the bits are set
-//----------------------------------------------------------------------
-void Log::LogIf(uint32_t bits, const char *format, ...) {
- if (!m_options.AllSet(bits))
- return;
-
- va_list args;
- va_start(args, format);
- VAPrintf(format, args);
- va_end(args);
-}
-
-//----------------------------------------------------------------------
-// Printing of errors that are not fatal.
-//----------------------------------------------------------------------
-void Log::Error(const char *format, ...) {
- va_list args;
- va_start(args, format);
- VAError(format, args);
- va_end(args);
-}
-
-void Log::VAError(const char *format, va_list args) {
- char *arg_msg = nullptr;
- ::vasprintf(&arg_msg, format, args);
-
- if (arg_msg == nullptr)
- return;
-
- Printf("error: %s", arg_msg);
- free(arg_msg);
-}
-
-//----------------------------------------------------------------------
-// Printing of warnings that are not fatal only if verbose mode is
-// enabled.
-//----------------------------------------------------------------------
-void Log::Verbose(const char *format, ...) {
- if (!m_options.Test(LLDB_LOG_OPTION_VERBOSE))
- return;
-
- va_list args;
- va_start(args, format);
- VAPrintf(format, args);
- va_end(args);
-}
-
-//----------------------------------------------------------------------
-// Printing of warnings that are not fatal.
-//----------------------------------------------------------------------
-void Log::Warning(const char *format, ...) {
- char *arg_msg = nullptr;
- va_list args;
- va_start(args, format);
- ::vasprintf(&arg_msg, format, args);
- va_end(args);
-
- if (arg_msg == nullptr)
- return;
-
- Printf("warning: %s", arg_msg);
- free(arg_msg);
-}
-
-typedef std::map<ConstString, Log::Callbacks> CallbackMap;
-typedef CallbackMap::iterator CallbackMapIter;
-
-typedef std::map<ConstString, LogChannelSP> LogChannelMap;
-typedef LogChannelMap::iterator LogChannelMapIter;
-
-// Surround our callback map with a singleton function so we don't have any
-// global initializers.
-static CallbackMap &GetCallbackMap() {
- static CallbackMap g_callback_map;
- return g_callback_map;
-}
-
-static LogChannelMap &GetChannelMap() {
- static LogChannelMap g_channel_map;
- return g_channel_map;
-}
-
-void Log::RegisterLogChannel(const ConstString &channel,
- const Log::Callbacks &log_callbacks) {
- GetCallbackMap().insert(std::make_pair(channel, log_callbacks));
-}
-
-bool Log::UnregisterLogChannel(const ConstString &channel) {
- return GetCallbackMap().erase(channel) != 0;
-}
-
-bool Log::GetLogChannelCallbacks(const ConstString &channel,
- Log::Callbacks &log_callbacks) {
- CallbackMap &callback_map = GetCallbackMap();
- CallbackMapIter pos = callback_map.find(channel);
- if (pos != callback_map.end()) {
- log_callbacks = pos->second;
- return true;
- }
- ::memset(&log_callbacks, 0, sizeof(log_callbacks));
- return false;
-}
-
-bool Log::EnableLogChannel(lldb::StreamSP &log_stream_sp, uint32_t log_options,
- const char *channel, const char **categories,
- Stream &error_stream) {
- Log::Callbacks log_callbacks;
- if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
- log_callbacks.enable(log_stream_sp, log_options, categories, &error_stream);
- return true;
- }
-
- LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel));
- if (log_channel_sp) {
- if (log_channel_sp->Enable(log_stream_sp, log_options, &error_stream,
- categories)) {
- return true;
- } else {
- error_stream.Printf("Invalid log channel '%s'.\n", channel);
- return false;
- }
- } else {
- error_stream.Printf("Invalid log channel '%s'.\n", channel);
- return false;
- }
-}
-
-void Log::EnableAllLogChannels(StreamSP &log_stream_sp, uint32_t log_options,
- const char **categories, Stream *feedback_strm) {
- CallbackMap &callback_map = GetCallbackMap();
- CallbackMapIter pos, end = callback_map.end();
-
- for (pos = callback_map.begin(); pos != end; ++pos)
- pos->second.enable(log_stream_sp, log_options, categories, feedback_strm);
-
- LogChannelMap &channel_map = GetChannelMap();
- LogChannelMapIter channel_pos, channel_end = channel_map.end();
- for (channel_pos = channel_map.begin(); channel_pos != channel_end;
- ++channel_pos) {
- channel_pos->second->Enable(log_stream_sp, log_options, feedback_strm,
- categories);
- }
-}
-
-void Log::AutoCompleteChannelName(const char *channel_name,
- StringList &matches) {
- LogChannelMap &map = GetChannelMap();
- LogChannelMapIter pos, end = map.end();
- for (pos = map.begin(); pos != end; ++pos) {
- const char *pos_channel_name = pos->first.GetCString();
- if (channel_name && channel_name[0]) {
- if (NameMatches(channel_name, eNameMatchStartsWith, pos_channel_name)) {
- matches.AppendString(pos_channel_name);
- }
- } else
- matches.AppendString(pos_channel_name);
- }
-}
-
-void Log::DisableAllLogChannels(Stream *feedback_strm) {
- CallbackMap &callback_map = GetCallbackMap();
- CallbackMapIter pos, end = callback_map.end();
- const char *categories[] = {"all", nullptr};
-
- for (pos = callback_map.begin(); pos != end; ++pos)
- pos->second.disable(categories, feedback_strm);
-
- LogChannelMap &channel_map = GetChannelMap();
- LogChannelMapIter channel_pos, channel_end = channel_map.end();
- for (channel_pos = channel_map.begin(); channel_pos != channel_end;
- ++channel_pos)
- channel_pos->second->Disable(categories, feedback_strm);
-}
-
-void Log::Initialize() {
- Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories};
- Log::RegisterLogChannel(ConstString("lldb"), log_callbacks);
-}
-
-void Log::Terminate() { DisableAllLogChannels(nullptr); }
-
-void Log::ListAllLogChannels(Stream *strm) {
- CallbackMap &callback_map = GetCallbackMap();
- LogChannelMap &channel_map = GetChannelMap();
-
- if (callback_map.empty() && channel_map.empty()) {
- strm->PutCString("No logging channels are currently registered.\n");
- return;
- }
-
- CallbackMapIter pos, end = callback_map.end();
- for (pos = callback_map.begin(); pos != end; ++pos)
- pos->second.list_categories(strm);
-
- uint32_t idx = 0;
- const char *name;
- for (idx = 0;
- (name = PluginManager::GetLogChannelCreateNameAtIndex(idx)) != nullptr;
- ++idx) {
- LogChannelSP log_channel_sp(LogChannel::FindPlugin(name));
- if (log_channel_sp)
- log_channel_sp->ListCategories(strm);
- }
-}
-
-bool Log::GetVerbose() const {
- // FIXME: This has to be centralized between the stream and the log...
- if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
- return true;
-
- // Make a copy of our stream shared pointer in case someone disables our
- // log while we are logging and releases the stream
- StreamSP stream_sp(m_stream_sp);
- if (stream_sp)
- return stream_sp->GetVerbose();
- return false;
-}
-
-//------------------------------------------------------------------
-// Returns true if the debug flag bit is set in this stream.
-//------------------------------------------------------------------
-bool Log::GetDebug() const {
- // Make a copy of our stream shared pointer in case someone disables our
- // log while we are logging and releases the stream
- StreamSP stream_sp(m_stream_sp);
- if (stream_sp)
- return stream_sp->GetDebug();
- return false;
-}
-
-LogChannelSP LogChannel::FindPlugin(const char *plugin_name) {
- LogChannelSP log_channel_sp;
- LogChannelMap &channel_map = GetChannelMap();
- ConstString log_channel_name(plugin_name);
- LogChannelMapIter pos = channel_map.find(log_channel_name);
- if (pos == channel_map.end()) {
- ConstString const_plugin_name(plugin_name);
- LogChannelCreateInstance create_callback =
- PluginManager::GetLogChannelCreateCallbackForPluginName(
- const_plugin_name);
- if (create_callback) {
- log_channel_sp.reset(create_callback());
- if (log_channel_sp) {
- // Cache the one and only loaded instance of each log channel
- // plug-in after it has been loaded once.
- channel_map[log_channel_name] = log_channel_sp;
- }
- }
- } else {
- // We have already loaded an instance of this log channel class,
- // so just return the cached instance.
- log_channel_sp = pos->second;
- }
- return log_channel_sp;
-}
-
-LogChannel::LogChannel() : m_log_ap() {}
-
-LogChannel::~LogChannel() = default;
diff --git a/contrib/llvm/tools/lldb/source/Core/Logging.cpp b/contrib/llvm/tools/lldb/source/Core/Logging.cpp
deleted file mode 100644
index 4d63b60..0000000
--- a/contrib/llvm/tools/lldb/source/Core/Logging.cpp
+++ /dev/null
@@ -1,322 +0,0 @@
-//===-- Logging.cpp ---------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Core/Logging.h"
-
-// C Includes
-// C++ Includes
-#include <atomic>
-#include <cstring>
-
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Interpreter/Args.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-// We want to avoid global constructors where code needs to be run so here we
-// control access to our static g_log_sp by hiding it in a singleton function
-// that will construct the static g_lob_sp the first time this function is
-// called.
-
-static std::atomic<bool> g_log_enabled{false};
-static Log *g_log = nullptr;
-
-static Log *GetLog() {
- if (!g_log_enabled)
- return nullptr;
- return g_log;
-}
-
-uint32_t lldb_private::GetLogMask() {
- Log *log(GetLog());
- if (log)
- return log->GetMask().Get();
- return 0;
-}
-
-bool lldb_private::IsLogVerbose() {
- uint32_t mask = GetLogMask();
- return (mask & LIBLLDB_LOG_VERBOSE);
-}
-
-Log *lldb_private::GetLogIfAllCategoriesSet(uint32_t mask) {
- Log *log(GetLog());
- if (log && mask) {
- uint32_t log_mask = log->GetMask().Get();
- if ((log_mask & mask) != mask)
- return nullptr;
- }
- return log;
-}
-
-void lldb_private::LogIfAllCategoriesSet(uint32_t mask, const char *format,
- ...) {
- Log *log(GetLogIfAllCategoriesSet(mask));
- if (log) {
- va_list args;
- va_start(args, format);
- log->VAPrintf(format, args);
- va_end(args);
- }
-}
-
-void lldb_private::LogIfAnyCategoriesSet(uint32_t mask, const char *format,
- ...) {
- Log *log(GetLogIfAnyCategoriesSet(mask));
- if (log != nullptr) {
- va_list args;
- va_start(args, format);
- log->VAPrintf(format, args);
- va_end(args);
- }
-}
-
-Log *lldb_private::GetLogIfAnyCategoriesSet(uint32_t mask) {
- Log *log(GetLog());
- if (log != nullptr && mask && (mask & log->GetMask().Get()))
- return log;
- return nullptr;
-}
-
-void lldb_private::DisableLog(const char **categories, Stream *feedback_strm) {
- Log *log(GetLog());
-
- if (log != nullptr) {
- uint32_t flag_bits = 0;
- if (categories && categories[0]) {
- flag_bits = log->GetMask().Get();
- for (size_t i = 0; categories[i] != nullptr; ++i) {
- const char *arg = categories[i];
-
- if (0 == ::strcasecmp(arg, "all"))
- flag_bits &= ~LIBLLDB_LOG_ALL;
- else if (0 == ::strcasecmp(arg, "api"))
- flag_bits &= ~LIBLLDB_LOG_API;
- else if (0 == ::strncasecmp(arg, "break", 5))
- flag_bits &= ~LIBLLDB_LOG_BREAKPOINTS;
- else if (0 == ::strcasecmp(arg, "commands"))
- flag_bits &= ~LIBLLDB_LOG_COMMANDS;
- else if (0 == ::strcasecmp(arg, "default"))
- flag_bits &= ~LIBLLDB_LOG_DEFAULT;
- else if (0 == ::strcasecmp(arg, "dyld"))
- flag_bits &= ~LIBLLDB_LOG_DYNAMIC_LOADER;
- else if (0 == ::strncasecmp(arg, "event", 5))
- flag_bits &= ~LIBLLDB_LOG_EVENTS;
- else if (0 == ::strncasecmp(arg, "expr", 4))
- flag_bits &= ~LIBLLDB_LOG_EXPRESSIONS;
- else if (0 == ::strncasecmp(arg, "object", 6))
- flag_bits &= ~LIBLLDB_LOG_OBJECT;
- else if (0 == ::strcasecmp(arg, "process"))
- flag_bits &= ~LIBLLDB_LOG_PROCESS;
- else if (0 == ::strcasecmp(arg, "platform"))
- flag_bits &= ~LIBLLDB_LOG_PLATFORM;
- else if (0 == ::strcasecmp(arg, "script"))
- flag_bits &= ~LIBLLDB_LOG_SCRIPT;
- else if (0 == ::strcasecmp(arg, "state"))
- flag_bits &= ~LIBLLDB_LOG_STATE;
- else if (0 == ::strcasecmp(arg, "step"))
- flag_bits &= ~LIBLLDB_LOG_STEP;
- else if (0 == ::strcasecmp(arg, "thread"))
- flag_bits &= ~LIBLLDB_LOG_THREAD;
- else if (0 == ::strcasecmp(arg, "target"))
- flag_bits &= ~LIBLLDB_LOG_TARGET;
- else if (0 == ::strcasecmp(arg, "verbose"))
- flag_bits &= ~LIBLLDB_LOG_VERBOSE;
- else if (0 == ::strncasecmp(arg, "watch", 5))
- flag_bits &= ~LIBLLDB_LOG_WATCHPOINTS;
- else if (0 == ::strncasecmp(arg, "temp", 4))
- flag_bits &= ~LIBLLDB_LOG_TEMPORARY;
- else if (0 == ::strncasecmp(arg, "comm", 4))
- flag_bits &= ~LIBLLDB_LOG_COMMUNICATION;
- else if (0 == ::strncasecmp(arg, "conn", 4))
- flag_bits &= ~LIBLLDB_LOG_CONNECTION;
- else if (0 == ::strncasecmp(arg, "host", 4))
- flag_bits &= ~LIBLLDB_LOG_HOST;
- else if (0 == ::strncasecmp(arg, "unwind", 6))
- flag_bits &= ~LIBLLDB_LOG_UNWIND;
- else if (0 == ::strncasecmp(arg, "types", 5))
- flag_bits &= ~LIBLLDB_LOG_TYPES;
- else if (0 == ::strncasecmp(arg, "symbol", 6))
- flag_bits &= ~LIBLLDB_LOG_SYMBOLS;
- else if (0 == ::strcasecmp(arg, "system-runtime"))
- flag_bits &= ~LIBLLDB_LOG_SYSTEM_RUNTIME;
- else if (0 == ::strncasecmp(arg, "module", 6))
- flag_bits &= ~LIBLLDB_LOG_MODULES;
- else if (0 == ::strncasecmp(arg, "mmap", 4))
- flag_bits &= ~LIBLLDB_LOG_MMAP;
- else if (0 == ::strcasecmp(arg, "os"))
- flag_bits &= ~LIBLLDB_LOG_OS;
- else if (0 == ::strcasecmp(arg, "jit"))
- flag_bits &= ~LIBLLDB_LOG_JIT_LOADER;
- else if (0 == ::strcasecmp(arg, "language"))
- flag_bits &= ~LIBLLDB_LOG_LANGUAGE;
- else if (0 == ::strncasecmp(arg, "formatters", 10))
- flag_bits &= ~LIBLLDB_LOG_DATAFORMATTERS;
- else if (0 == ::strncasecmp(arg, "demangle", 8))
- flag_bits &= ~LIBLLDB_LOG_DEMANGLE;
- else {
- feedback_strm->Printf("error: unrecognized log category '%s'\n",
- arg);
- ListLogCategories(feedback_strm);
- return;
- }
- }
- }
- log->GetMask().Reset(flag_bits);
- if (flag_bits == 0) {
- log->SetStream(lldb::StreamSP());
- g_log_enabled = false;
- }
- }
-}
-
-Log *lldb_private::EnableLog(StreamSP &log_stream_sp, uint32_t log_options,
- const char **categories, Stream *feedback_strm) {
- // Try see if there already is a log - that way we can reuse its settings.
- // We could reuse the log in toto, but we don't know that the stream is the
- // same.
- uint32_t flag_bits;
- if (g_log != nullptr)
- flag_bits = g_log->GetMask().Get();
- else
- flag_bits = 0;
-
- // Now make a new log with this stream if one was provided
- if (log_stream_sp) {
- if (g_log != nullptr)
- g_log->SetStream(log_stream_sp);
- else
- g_log = new Log(log_stream_sp);
- }
-
- if (g_log != nullptr) {
- for (size_t i = 0; categories[i] != nullptr; ++i) {
- const char *arg = categories[i];
-
- if (0 == ::strcasecmp(arg, "all"))
- flag_bits |= LIBLLDB_LOG_ALL;
- else if (0 == ::strcasecmp(arg, "api"))
- flag_bits |= LIBLLDB_LOG_API;
- else if (0 == ::strncasecmp(arg, "break", 5))
- flag_bits |= LIBLLDB_LOG_BREAKPOINTS;
- else if (0 == ::strcasecmp(arg, "commands"))
- flag_bits |= LIBLLDB_LOG_COMMANDS;
- else if (0 == ::strncasecmp(arg, "commu", 5))
- flag_bits |= LIBLLDB_LOG_COMMUNICATION;
- else if (0 == ::strncasecmp(arg, "conn", 4))
- flag_bits |= LIBLLDB_LOG_CONNECTION;
- else if (0 == ::strcasecmp(arg, "default"))
- flag_bits |= LIBLLDB_LOG_DEFAULT;
- else if (0 == ::strcasecmp(arg, "dyld"))
- flag_bits |= LIBLLDB_LOG_DYNAMIC_LOADER;
- else if (0 == ::strncasecmp(arg, "event", 5))
- flag_bits |= LIBLLDB_LOG_EVENTS;
- else if (0 == ::strncasecmp(arg, "expr", 4))
- flag_bits |= LIBLLDB_LOG_EXPRESSIONS;
- else if (0 == ::strncasecmp(arg, "host", 4))
- flag_bits |= LIBLLDB_LOG_HOST;
- else if (0 == ::strncasecmp(arg, "mmap", 4))
- flag_bits |= LIBLLDB_LOG_MMAP;
- else if (0 == ::strncasecmp(arg, "module", 6))
- flag_bits |= LIBLLDB_LOG_MODULES;
- else if (0 == ::strncasecmp(arg, "object", 6))
- flag_bits |= LIBLLDB_LOG_OBJECT;
- else if (0 == ::strcasecmp(arg, "os"))
- flag_bits |= LIBLLDB_LOG_OS;
- else if (0 == ::strcasecmp(arg, "platform"))
- flag_bits |= LIBLLDB_LOG_PLATFORM;
- else if (0 == ::strcasecmp(arg, "process"))
- flag_bits |= LIBLLDB_LOG_PROCESS;
- else if (0 == ::strcasecmp(arg, "script"))
- flag_bits |= LIBLLDB_LOG_SCRIPT;
- else if (0 == ::strcasecmp(arg, "state"))
- flag_bits |= LIBLLDB_LOG_STATE;
- else if (0 == ::strcasecmp(arg, "step"))
- flag_bits |= LIBLLDB_LOG_STEP;
- else if (0 == ::strncasecmp(arg, "symbol", 6))
- flag_bits |= LIBLLDB_LOG_SYMBOLS;
- else if (0 == ::strcasecmp(arg, "system-runtime"))
- flag_bits |= LIBLLDB_LOG_SYSTEM_RUNTIME;
- else if (0 == ::strcasecmp(arg, "target"))
- flag_bits |= LIBLLDB_LOG_TARGET;
- else if (0 == ::strncasecmp(arg, "temp", 4))
- flag_bits |= LIBLLDB_LOG_TEMPORARY;
- else if (0 == ::strcasecmp(arg, "thread"))
- flag_bits |= LIBLLDB_LOG_THREAD;
- else if (0 == ::strncasecmp(arg, "types", 5))
- flag_bits |= LIBLLDB_LOG_TYPES;
- else if (0 == ::strncasecmp(arg, "unwind", 6))
- flag_bits |= LIBLLDB_LOG_UNWIND;
- else if (0 == ::strcasecmp(arg, "verbose"))
- flag_bits |= LIBLLDB_LOG_VERBOSE;
- else if (0 == ::strncasecmp(arg, "watch", 5))
- flag_bits |= LIBLLDB_LOG_WATCHPOINTS;
- else if (0 == ::strcasecmp(arg, "jit"))
- flag_bits |= LIBLLDB_LOG_JIT_LOADER;
- else if (0 == ::strcasecmp(arg, "language"))
- flag_bits |= LIBLLDB_LOG_LANGUAGE;
- else if (0 == ::strncasecmp(arg, "formatters", 10))
- flag_bits |= LIBLLDB_LOG_DATAFORMATTERS;
- else if (0 == ::strncasecmp(arg, "demangle", 8))
- flag_bits |= LIBLLDB_LOG_DEMANGLE;
- else {
- feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
- ListLogCategories(feedback_strm);
- return g_log;
- }
- }
-
- g_log->GetMask().Reset(flag_bits);
- g_log->GetOptions().Reset(log_options);
- }
- g_log_enabled = true;
- return g_log;
-}
-
-void lldb_private::ListLogCategories(Stream *strm) {
- strm->Printf(
- "Logging categories for 'lldb':\n"
- " all - turn on all available logging categories\n"
- " api - enable logging of API calls and return values\n"
- " break - log breakpoints\n"
- " commands - log command argument parsing\n"
- " communication - log communication activities\n"
- " connection - log connection details\n"
- " default - enable the default set of logging categories for liblldb\n"
- " demangle - log mangled names to catch demangler crashes\n"
- " dyld - log shared library related activities\n"
- " events - log broadcaster, listener and event queue activities\n"
- " expr - log expressions\n"
- " formatters - log data formatters related activities\n"
- " host - log host activities\n"
- " jit - log JIT events in the target\n"
- " language - log language runtime events\n"
- " mmap - log mmap related activities\n"
- " module - log module activities such as when modules are created, "
- "destroyed, replaced, and more\n"
- " object - log object construction/destruction for important objects\n"
- " os - log OperatingSystem plugin related activities\n"
- " platform - log platform events and activities\n"
- " process - log process events and activities\n"
- " script - log events about the script interpreter\n"
- " state - log private and public process state changes\n"
- " step - log step related activities\n"
- " symbol - log symbol related issues and warnings\n"
- " system-runtime - log system runtime events\n"
- " target - log target events and activities\n"
- " thread - log thread events and activities\n"
- " types - log type system related activities\n"
- " unwind - log stack unwind activities\n"
- " verbose - enable verbose logging\n"
- " watch - log watchpoint related activities\n");
-}
diff --git a/contrib/llvm/tools/lldb/source/Core/Mangled.cpp b/contrib/llvm/tools/lldb/source/Core/Mangled.cpp
index c2c63b6..211a0c3 100644
--- a/contrib/llvm/tools/lldb/source/Core/Mangled.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Mangled.cpp
@@ -7,10 +7,11 @@
//
//===----------------------------------------------------------------------===//
-// FreeBSD9-STABLE requires this to know about size_t in cxxabi.h
-#include <cstddef>
+#include "lldb/Core/Mangled.h"
+
#if defined(_WIN32)
#include "lldb/Host/windows/windows.h"
+
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
#endif
@@ -18,29 +19,55 @@
#ifdef LLDB_USE_BUILTIN_DEMANGLER
// Provide a fast-path demangler implemented in FastDemangle.cpp until it can
// replace the existing C++ demangler with a complete implementation
+#include "lldb/Utility/FastDemangle.h"
#include "llvm/Demangle/Demangle.h"
-#include "lldb/Core/FastDemangle.h"
#else
+// FreeBSD9-STABLE requires this to know about size_t in cxxabi.
+#include <cstddef>
#include <cxxabi.h>
#endif
-#include "llvm/ADT/DenseMap.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
+#include "lldb/lldb-enumerations.h" // for LanguageType
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Logging.h"
-#include "lldb/Core/Mangled.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/Timer.h"
-#include <ctype.h>
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/Support/Compiler.h" // for LLVM_PRETT...
+
+#include <mutex> // for mutex, loc...
+#include <string> // for string
+#include <utility> // for pair
+
#include <stdlib.h>
#include <string.h>
-
using namespace lldb_private;
+#if defined(_MSC_VER)
+static DWORD safeUndecorateName(const char *Mangled, char *Demangled,
+ DWORD DemangledLength) {
+ static std::mutex M;
+ std::lock_guard<std::mutex> Lock(M);
+ return ::UnDecorateSymbolName(
+ Mangled, Demangled, DemangledLength,
+ UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected
+ // keywords
+ UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall,
+ // etc keywords
+ UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
+ UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc
+ // specifiers
+ UNDNAME_NO_MS_KEYWORDS // Strip all MS extension keywords
+ );
+}
+#endif
+
static inline Mangled::ManglingScheme cstring_mangling_scheme(const char *s) {
if (s) {
if (s[0] == '?')
@@ -231,8 +258,8 @@ Mangled::GetDemangledName(lldb::LanguageType language) const {
// haven't already decoded our mangled name.
if (m_mangled && !m_demangled) {
// We need to generate and cache the demangled name.
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
- "Mangled::GetDemangledName (m_mangled = %s)",
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)",
m_mangled.GetCString());
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE);
@@ -253,17 +280,8 @@ Mangled::GetDemangledName(lldb::LanguageType language) const {
const size_t demangled_length = 2048;
demangled_name = static_cast<char *>(::malloc(demangled_length));
::ZeroMemory(demangled_name, demangled_length);
- DWORD result = ::UnDecorateSymbolName(
- mangled_name, demangled_name, demangled_length,
- UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected
- // keywords
- UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall,
- // etc keywords
- UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
- UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc
- // specifiers
- UNDNAME_NO_MS_KEYWORDS // Strip all MS extension keywords
- );
+ DWORD result =
+ safeUndecorateName(mangled_name, demangled_name, demangled_length);
if (log) {
if (demangled_name && demangled_name[0])
log->Printf("demangled msvc: %s -> \"%s\"", mangled_name,
@@ -414,6 +432,14 @@ lldb::LanguageType Mangled::GuessLanguage() const {
else if (ObjCLanguage::IsPossibleObjCMethodName(mangled_name))
return lldb::eLanguageTypeObjC;
}
+ } else {
+ // ObjC names aren't really mangled, so they won't necessarily be in the
+ // mangled name slot.
+ ConstString demangled_name = GetDemangledName(lldb::eLanguageTypeUnknown);
+ if (demangled_name
+ && ObjCLanguage::IsPossibleObjCMethodName(demangled_name.GetCString()))
+ return lldb::eLanguageTypeObjC;
+
}
return lldb::eLanguageTypeUnknown;
}
diff --git a/contrib/llvm/tools/lldb/source/Core/Module.cpp b/contrib/llvm/tools/lldb/source/Core/Module.cpp
index 28f140b..aaae470 100644
--- a/contrib/llvm/tools/lldb/source/Core/Module.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Module.cpp
@@ -9,46 +9,73 @@
#include "lldb/Core/Module.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/raw_os_ostream.h"
-
-// Project includes
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
-#include "Plugins/Language/ObjC/ObjCLanguage.h"
+#include "lldb/Core/AddressRange.h" // for AddressRange
#include "lldb/Core/AddressResolverFileLine.h"
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/Debugger.h" // for Debugger
+#include "lldb/Core/FileSpecList.h" // for FileSpecList
+#include "lldb/Core/Mangled.h" // for Mangled
#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/SearchFilter.h" // for SearchFilt...
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
-#include "lldb/Host/Symbols.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h" // for Function
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h" // for Symbol
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Symtab.h" // for Symtab
+#include "lldb/Symbol/Type.h" // for Type
+#include "lldb/Symbol/TypeList.h" // for TypeList
#include "lldb/Symbol/TypeMap.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Language.h"
+#include "lldb/Target/Platform.h" // for Platform
#include "lldb/Target/Process.h"
-#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for GetLogIfAn...
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
+
+#if defined(LLVM_ON_WIN32)
+#include "lldb/Host/windows/PosixApi.h" // for PATH_MAX
+#endif
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "Plugins/ObjectFile/JIT/ObjectFileJIT.h"
+#include "llvm/ADT/STLExtras.h" // for make_unique
+#include "llvm/Support/Compiler.h" // for LLVM_PRETT...
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h" // for raw_string...
+
+#include <assert.h> // for assert
+#include <cstdint> // for uint32_t
+#include <inttypes.h> // for PRIx64
+#include <map> // for map
+#include <stdarg.h> // for va_end
+#include <string.h> // for size_t
+#include <type_traits> // for move
+#include <utility> // for find, pair
+
+namespace lldb_private {
+class CompilerDeclContext;
+}
+namespace lldb_private {
+class VariableList;
+}
+
using namespace lldb;
using namespace lldb_private;
@@ -295,7 +322,7 @@ Module::~Module() {
}
ObjectFile *Module::GetMemoryObjectFile(const lldb::ProcessSP &process_sp,
- lldb::addr_t header_addr, Error &error,
+ lldb::addr_t header_addr, Status &error,
size_t size_to_read) {
if (m_objfile_sp) {
error.SetErrorString("object file already exists");
@@ -303,9 +330,8 @@ ObjectFile *Module::GetMemoryObjectFile(const lldb::ProcessSP &process_sp,
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (process_sp) {
m_did_load_objfile = true;
- std::unique_ptr<DataBufferHeap> data_ap(
- new DataBufferHeap(size_to_read, 0));
- Error readmem_error;
+ auto data_ap = llvm::make_unique<DataBufferHeap>(size_to_read, 0);
+ Status readmem_error;
const size_t bytes_read =
process_sp->ReadMemory(header_addr, data_ap->GetBytes(),
data_ap->GetByteSize(), readmem_error);
@@ -403,8 +429,8 @@ void Module::DumpSymbolContext(Stream *s) {
size_t Module::GetNumCompileUnits() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
- "Module::GetNumCompileUnits (module = %p)",
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "Module::GetNumCompileUnits (module = %p)",
static_cast<void *>(this));
SymbolVendor *symbols = GetSymbolVendor();
if (symbols)
@@ -427,7 +453,8 @@ CompUnitSP Module::GetCompileUnitAtIndex(size_t index) {
bool Module::ResolveFileAddress(lldb::addr_t vm_addr, Address &so_addr) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"Module::ResolveFileAddress (vm_addr = 0x%" PRIx64 ")",
vm_addr);
SectionList *section_list = GetSectionList();
@@ -590,7 +617,8 @@ uint32_t Module::ResolveSymbolContextsForFileSpec(const FileSpec &file_spec,
uint32_t resolve_scope,
SymbolContextList &sc_list) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"Module::ResolveSymbolContextForFilePath (%s:%u, "
"check_inlines = %s, resolve_scope = 0x%8.8x)",
file_spec.GetPath().c_str(), line,
@@ -719,10 +747,10 @@ Module::LookupInfo::LookupInfo(const ConstString &name, uint32_t name_type_mask,
}
// Still try and get a basename in case someone specifies a name type mask
- // of
- // eFunctionNameTypeFull and a name like "A::func"
+ // of eFunctionNameTypeFull and a name like "A::func"
if (basename.empty()) {
- if (name_type_mask & eFunctionNameTypeFull) {
+ if (name_type_mask & eFunctionNameTypeFull &&
+ !CPlusPlusLanguage::IsCPPMangledName(name_cstr)) {
CPlusPlusLanguage::MethodName cpp_method(name);
basename = cpp_method.GetBasename();
if (basename.empty())
@@ -770,30 +798,39 @@ void Module::LookupInfo::Prune(SymbolContextList &sc_list,
}
// If we have only full name matches we might have tried to set breakpoint on
- // "func"
- // and specified eFunctionNameTypeFull, but we might have found "a::func()",
- // "a::b::func()", "c::func()", "func()" and "func". Only "func()" and "func"
- // should
- // end up matching.
+ // "func" and specified eFunctionNameTypeFull, but we might have found
+ // "a::func()", "a::b::func()", "c::func()", "func()" and "func". Only
+ // "func()" and "func" should end up matching.
if (m_name_type_mask == eFunctionNameTypeFull) {
SymbolContext sc;
size_t i = start_idx;
while (i < sc_list.GetSize()) {
if (!sc_list.GetContextAtIndex(i, sc))
break;
+ // Make sure the mangled and demangled names don't match before we try
+ // to pull anything out
+ ConstString mangled_name(sc.GetFunctionName(Mangled::ePreferMangled));
ConstString full_name(sc.GetFunctionName());
- CPlusPlusLanguage::MethodName cpp_method(full_name);
- if (cpp_method.IsValid()) {
- if (cpp_method.GetContext().empty()) {
- if (cpp_method.GetBasename().compare(m_name.GetStringRef()) != 0) {
- sc_list.RemoveContextAtIndex(i);
- continue;
- }
- } else {
- std::string qualified_name = cpp_method.GetScopeQualifiedName();
- if (qualified_name.compare(m_name.GetCString()) != 0) {
- sc_list.RemoveContextAtIndex(i);
- continue;
+ if (mangled_name != m_name && full_name != m_name)
+ {
+ CPlusPlusLanguage::MethodName cpp_method(full_name);
+ if (cpp_method.IsValid()) {
+ if (cpp_method.GetContext().empty()) {
+ if (cpp_method.GetBasename().compare(m_name.GetStringRef()) != 0) {
+ sc_list.RemoveContextAtIndex(i);
+ continue;
+ }
+ } else {
+ std::string qualified_name;
+ llvm::StringRef anon_prefix("(anonymous namespace)");
+ if (cpp_method.GetContext() == anon_prefix)
+ qualified_name = cpp_method.GetBasename().str();
+ else
+ qualified_name = cpp_method.GetScopeQualifiedName();
+ if (qualified_name.compare(m_name.GetCString()) != 0) {
+ sc_list.RemoveContextAtIndex(i);
+ continue;
+ }
}
}
}
@@ -952,7 +989,8 @@ size_t Module::FindTypes_Impl(
const CompilerDeclContext *parent_decl_ctx, bool append, size_t max_matches,
llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
TypeMap &types) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
if (!sc.module_sp || sc.module_sp.get() == this) {
SymbolVendor *symbols = GetSymbolVendor();
if (symbols)
@@ -1022,7 +1060,7 @@ size_t Module::FindTypes(
// The "type_name_cstr" will have been modified if we have a valid type
// class
// prefix (like "struct", "class", "union", "typedef" etc).
- FindTypes_Impl(sc, ConstString(type_name_cstr), nullptr, append,
+ FindTypes_Impl(sc, ConstString(type_basename), nullptr, append,
max_matches, searched_symbol_files, typesmap);
typesmap.RemoveMismatchedTypes(type_class);
num_matches = typesmap.GetSize();
@@ -1043,7 +1081,8 @@ SymbolVendor *Module::GetSymbolVendor(bool can_create,
if (!m_did_load_symbol_vendor.load() && can_create) {
ObjectFile *obj_file = GetObjectFile();
if (obj_file != nullptr) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
m_symfile_ap.reset(
SymbolVendor::FindPlugin(shared_from_this(), feedback_strm));
m_did_load_symbol_vendor = true;
@@ -1243,8 +1282,8 @@ ObjectFile *Module::GetObjectFile() {
if (!m_did_load_objfile.load()) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (!m_did_load_objfile.load()) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
- "Module::GetObjectFile () module = %s",
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "Module::GetObjectFile () module = %s",
GetFileSpec().GetFilename().AsCString(""));
DataBufferSP data_sp;
lldb::offset_t data_offset = 0;
@@ -1297,15 +1336,15 @@ void Module::SectionFileAddressesChanged() {
SectionList *Module::GetUnifiedSectionList() {
// Populate m_unified_sections_ap with sections from objfile.
if (!m_sections_ap)
- m_sections_ap.reset(new SectionList());
+ m_sections_ap = llvm::make_unique<SectionList>();
return m_sections_ap.get();
}
const Symbol *Module::FindFirstSymbolWithNameAndType(const ConstString &name,
SymbolType symbol_type) {
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
- "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)",
+ func_cat, "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)",
name.AsCString(), symbol_type);
SymbolVendor *sym_vendor = GetSymbolVendor();
if (sym_vendor) {
@@ -1337,7 +1376,8 @@ void Module::SymbolIndicesToSymbolContextList(
size_t Module::FindFunctionSymbols(const ConstString &name,
uint32_t name_type_mask,
SymbolContextList &sc_list) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"Module::FindSymbolsFunctions (name = %s, mask = 0x%8.8x)",
name.AsCString(), name_type_mask);
SymbolVendor *sym_vendor = GetSymbolVendor();
@@ -1355,9 +1395,9 @@ size_t Module::FindSymbolsWithNameAndType(const ConstString &name,
// No need to protect this call using m_mutex all other method calls are
// already thread safe.
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
- "Module::FindSymbolsWithNameAndType (name = %s, type = %i)",
+ func_cat, "Module::FindSymbolsWithNameAndType (name = %s, type = %i)",
name.AsCString(), symbol_type);
const size_t initial_size = sc_list.GetSize();
SymbolVendor *sym_vendor = GetSymbolVendor();
@@ -1378,8 +1418,9 @@ size_t Module::FindSymbolsMatchingRegExAndType(const RegularExpression &regex,
// No need to protect this call using m_mutex all other method calls are
// already thread safe.
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
+ func_cat,
"Module::FindSymbolsMatchingRegExAndType (regex = %s, type = %i)",
regex.GetText().str().c_str(), symbol_type);
const size_t initial_size = sc_list.GetSize();
@@ -1397,6 +1438,22 @@ size_t Module::FindSymbolsMatchingRegExAndType(const RegularExpression &regex,
return sc_list.GetSize() - initial_size;
}
+void Module::PreloadSymbols() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ SymbolVendor * sym_vendor = GetSymbolVendor();
+ if (!sym_vendor) {
+ return;
+ }
+ // Prime the symbol file first, since it adds symbols to the symbol table.
+ if (SymbolFile *symbol_file = sym_vendor->GetSymbolFile()) {
+ symbol_file->PreloadSymbols();
+ }
+ // Now we can prime the symbol table.
+ if (Symtab * symtab = sym_vendor->GetSymtab()) {
+ symtab->PreloadSymbols();
+ }
+}
+
void Module::SetSymbolFileFileSpec(const FileSpec &file) {
if (!file.Exists())
return;
@@ -1430,7 +1487,7 @@ void Module::SetSymbolFileFileSpec(const FileSpec &file) {
// ("/tmp/a.out.dSYM/Contents/Resources/DWARF/a.out"). So we need to
// check this
- if (file.IsDirectory()) {
+ if (llvm::sys::fs::is_directory(file.GetPath())) {
std::string new_path(file.GetPath());
std::string old_path(obj_file->GetFileSpec().GetPath());
if (old_path.find(new_path) == 0) {
@@ -1486,7 +1543,7 @@ bool Module::IsLoadedInTarget(Target *target) {
return false;
}
-bool Module::LoadScriptingResourceInTarget(Target *target, Error &error,
+bool Module::LoadScriptingResourceInTarget(Target *target, Status &error,
Stream *feedback_stream) {
if (!target) {
error.SetErrorString("invalid destination Target");
@@ -1644,7 +1701,8 @@ Module::CreateJITModule(const lldb::ObjectFileJITDelegateSP &delegate_sp) {
// to the module, so we need to control the creation carefully in
// this static function
ModuleSP module_sp(new Module());
- module_sp->m_objfile_sp.reset(new ObjectFileJIT(module_sp, delegate_sp));
+ module_sp->m_objfile_sp =
+ std::make_shared<ObjectFileJIT>(module_sp, delegate_sp);
if (module_sp->m_objfile_sp) {
// Once we get the object file, update our module with the object file's
// architecture since it might differ in vendor/os if some parts were
@@ -1664,3 +1722,7 @@ bool Module::GetIsDynamicLinkEditor() {
return false;
}
+
+Status Module::LoadInMemory(Target &target, bool set_pc) {
+ return m_objfile_sp->LoadInMemory(target, set_pc);
+}
diff --git a/contrib/llvm/tools/lldb/source/Core/ModuleList.cpp b/contrib/llvm/tools/lldb/source/Core/ModuleList.cpp
index b980e15..b04299e 100644
--- a/contrib/llvm/tools/lldb/source/Core/ModuleList.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ModuleList.cpp
@@ -9,22 +9,54 @@
#include "lldb/Core/ModuleList.h"
-// C Includes
-// C++ Includes
-#include <cstdint>
-#include <mutex>
-
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Log.h"
+#include "lldb/Core/ArchSpec.h" // for ArchSpec
+#include "lldb/Core/FileSpecList.h" // for FileSpecList
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/Host.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolContext.h" // for SymbolContextList, SymbolCon...
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for GetLogIfAnyCategoriesSet
+#include "lldb/Utility/UUID.h" // for UUID, operator!=, operator==
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_INDEX32
+
+#if defined(LLVM_ON_WIN32)
+#include "lldb/Host/windows/PosixApi.h" // for PATH_MAX
+#endif
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/raw_ostream.h" // for fs
+
+#include <chrono> // for operator!=, time_point
+#include <memory> // for shared_ptr
+#include <mutex>
+#include <string> // for string
+#include <utility> // for distance
+
+namespace lldb_private {
+class Function;
+}
+namespace lldb_private {
+class RegularExpression;
+}
+namespace lldb_private {
+class Stream;
+}
+namespace lldb_private {
+class SymbolFile;
+}
+namespace lldb_private {
+class Target;
+}
+namespace lldb_private {
+class TypeList;
+}
using namespace lldb;
using namespace lldb_private;
@@ -644,8 +676,8 @@ size_t ModuleList::GetIndexForModule(const Module *module) const {
static ModuleList &GetSharedModuleList() {
static ModuleList *g_shared_module_list = nullptr;
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
// NOTE: Intentionally leak the module list so a program doesn't have to
// cleanup all modules and object files as it exits. This just wastes time
// doing a bunch of cleanup that isn't required.
@@ -672,17 +704,17 @@ size_t ModuleList::RemoveOrphanSharedModules(bool mandatory) {
return GetSharedModuleList().RemoveOrphans(mandatory);
}
-Error ModuleList::GetSharedModule(const ModuleSpec &module_spec,
- ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
- ModuleSP *old_module_sp_ptr,
- bool *did_create_ptr, bool always_create) {
+Status ModuleList::GetSharedModule(const ModuleSpec &module_spec,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr, bool always_create) {
ModuleList &shared_module_list = GetSharedModuleList();
std::lock_guard<std::recursive_mutex> guard(
shared_module_list.m_modules_mutex);
char path[PATH_MAX];
- Error error;
+ Status error;
module_sp.reset();
@@ -764,7 +796,8 @@ Error ModuleList::GetSharedModule(const ModuleSpec &module_spec,
auto search_path_spec = module_search_paths_ptr->GetFileSpecAtIndex(idx);
if (!search_path_spec.ResolvePath())
continue;
- if (!search_path_spec.Exists() || !search_path_spec.IsDirectory())
+ namespace fs = llvm::sys::fs;
+ if (!fs::is_directory(search_path_spec.GetPath()))
continue;
search_path_spec.AppendPathComponent(
module_spec.GetFileSpec().GetFilename().AsCString());
@@ -788,7 +821,7 @@ Error ModuleList::GetSharedModule(const ModuleSpec &module_spec,
*did_create_ptr = true;
shared_module_list.ReplaceEquivalent(module_sp);
- return Error();
+ return Status();
}
}
} else {
@@ -922,14 +955,14 @@ bool ModuleList::RemoveSharedModuleIfOrphaned(const Module *module_ptr) {
}
bool ModuleList::LoadScriptingResourcesInTarget(Target *target,
- std::list<Error> &errors,
+ std::list<Status> &errors,
Stream *feedback_stream,
bool continue_on_error) {
if (!target)
return false;
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
for (auto module : m_modules) {
- Error error;
+ Status error;
if (module) {
if (!module->LoadScriptingResourceInTarget(target, error,
feedback_stream)) {
diff --git a/contrib/llvm/tools/lldb/source/Core/Opcode.cpp b/contrib/llvm/tools/lldb/source/Core/Opcode.cpp
index 11b9138..b4e691c 100644
--- a/contrib/llvm/tools/lldb/source/Core/Opcode.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Opcode.cpp
@@ -9,17 +9,15 @@
#include "lldb/Core/Opcode.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-#include "llvm/ADT/Triple.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-forward.h" // for DataBufferSP
-// Project includes
-#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Host/Endian.h"
+#include <memory> // for make_shared
+
+#include <inttypes.h> // for PRIx64
using namespace lldb;
using namespace lldb_private;
@@ -132,7 +130,7 @@ uint32_t Opcode::GetData(DataExtractor &data) const {
if (buf != nullptr) {
DataBufferSP buffer_sp;
- buffer_sp.reset(new DataBufferHeap(buf, byte_size));
+ buffer_sp = std::make_shared<DataBufferHeap>(buf, byte_size);
data.SetByteOrder(GetDataByteOrder());
data.SetData(buffer_sp);
return byte_size;
diff --git a/contrib/llvm/tools/lldb/source/Core/PluginManager.cpp b/contrib/llvm/tools/lldb/source/Core/PluginManager.cpp
index b7b6b9a..9bb615b 100644
--- a/contrib/llvm/tools/lldb/source/Core/PluginManager.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/PluginManager.cpp
@@ -9,24 +9,35 @@
#include "lldb/Core/PluginManager.h"
-// C Includes
-// C++ Includes
-#include <climits>
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StringList.h" // for StringList
+
+#if defined(LLVM_ON_WIN32)
+#include "lldb/Host/windows/PosixApi.h" // for PATH_MAX
+#endif
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/FileSystem.h" // for file_type, file_...
+#include "llvm/Support/raw_ostream.h" // for fs
+
+#include <map> // for map<>::const_ite...
+#include <memory> // for shared_ptr
#include <mutex>
#include <string>
+#include <utility> // for pair
#include <vector>
-// Other libraries and framework includes
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/DynamicLibrary.h"
+#include <assert.h> // for assert
-// Project includes
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/Host.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Interpreter/OptionValueProperties.h"
+namespace lldb_private {
+class CommandInterpreter;
+}
using namespace lldb;
using namespace lldb_private;
@@ -79,18 +90,18 @@ template <typename FPtrTy> static FPtrTy CastToFPtr(void *VPtr) {
}
static FileSpec::EnumerateDirectoryResult
-LoadPluginCallback(void *baton, FileSpec::FileType file_type,
+LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft,
const FileSpec &file_spec) {
// PluginManager *plugin_manager = (PluginManager *)baton;
- Error error;
+ Status error;
+ namespace fs = llvm::sys::fs;
// If we have a regular file, a symbolic link or unknown file type, try
// and process the file. We must handle unknown as sometimes the directory
// enumeration might be enumerating a file system that doesn't have correct
// file type information.
- if (file_type == FileSpec::eFileTypeRegular ||
- file_type == FileSpec::eFileTypeSymbolicLink ||
- file_type == FileSpec::eFileTypeUnknown) {
+ if (ft == fs::file_type::regular_file || ft == fs::file_type::symlink_file ||
+ ft == fs::file_type::type_unknown) {
FileSpec plugin_file_spec(file_spec);
plugin_file_spec.ResolvePath();
@@ -135,9 +146,8 @@ LoadPluginCallback(void *baton, FileSpec::FileType file_type,
}
}
- if (file_type == FileSpec::eFileTypeUnknown ||
- file_type == FileSpec::eFileTypeDirectory ||
- file_type == FileSpec::eFileTypeSymbolicLink) {
+ if (ft == fs::file_type::directory_file ||
+ ft == fs::file_type::symlink_file || ft == fs::file_type::type_unknown) {
// Try and recurse into anything that a directory or symbolic link.
// We must also do this for unknown as sometimes the directory enumeration
// might be enumerating a file system that doesn't have correct file type
@@ -1056,9 +1066,9 @@ PluginManager::GetObjectFileCreateMemoryCallbackForPluginName(
return nullptr;
}
-Error PluginManager::SaveCore(const lldb::ProcessSP &process_sp,
- const FileSpec &outfile) {
- Error error;
+Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp,
+ const FileSpec &outfile) {
+ Status error;
std::lock_guard<std::recursive_mutex> guard(GetObjectFileMutex());
ObjectFileInstances &instances = GetObjectFileInstances();
@@ -1167,93 +1177,6 @@ PluginManager::GetObjectContainerGetModuleSpecificationsCallbackAtIndex(
return nullptr;
}
-#pragma mark LogChannel
-
-struct LogInstance {
- LogInstance() : name(), description(), create_callback(nullptr) {}
-
- ConstString name;
- std::string description;
- LogChannelCreateInstance create_callback;
-};
-
-typedef std::vector<LogInstance> LogInstances;
-
-static std::recursive_mutex &GetLogMutex() {
- static std::recursive_mutex g_instances_mutex;
- return g_instances_mutex;
-}
-
-static LogInstances &GetLogInstances() {
- static LogInstances g_instances;
- return g_instances;
-}
-
-bool PluginManager::RegisterPlugin(const ConstString &name,
- const char *description,
- LogChannelCreateInstance create_callback) {
- if (create_callback) {
- LogInstance instance;
- assert((bool)name);
- instance.name = name;
- if (description && description[0])
- instance.description = description;
- instance.create_callback = create_callback;
- std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
- GetLogInstances().push_back(instance);
- }
- return false;
-}
-
-bool PluginManager::UnregisterPlugin(LogChannelCreateInstance create_callback) {
- if (create_callback) {
- std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
- LogInstances &instances = GetLogInstances();
-
- LogInstances::iterator pos, end = instances.end();
- for (pos = instances.begin(); pos != end; ++pos) {
- if (pos->create_callback == create_callback) {
- instances.erase(pos);
- return true;
- }
- }
- }
- return false;
-}
-
-const char *PluginManager::GetLogChannelCreateNameAtIndex(uint32_t idx) {
- std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
- LogInstances &instances = GetLogInstances();
- if (idx < instances.size())
- return instances[idx].name.GetCString();
- return nullptr;
-}
-
-LogChannelCreateInstance
-PluginManager::GetLogChannelCreateCallbackAtIndex(uint32_t idx) {
- std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
- LogInstances &instances = GetLogInstances();
- if (idx < instances.size())
- return instances[idx].create_callback;
- return nullptr;
-}
-
-LogChannelCreateInstance
-PluginManager::GetLogChannelCreateCallbackForPluginName(
- const ConstString &name) {
- if (name) {
- std::lock_guard<std::recursive_mutex> gard(GetLogMutex());
- LogInstances &instances = GetLogInstances();
-
- LogInstances::iterator pos, end = instances.end();
- for (pos = instances.begin(); pos != end; ++pos) {
- if (name == pos->name)
- return pos->create_callback;
- }
- }
- return nullptr;
-}
-
#pragma mark Platform
struct PlatformInstance {
@@ -2403,7 +2326,8 @@ static lldb::OptionValuePropertiesSP GetDebuggerPropertyForPlugins(
OptionValuePropertiesSP plugin_properties_sp =
parent_properties_sp->GetSubProperty(nullptr, g_property_name);
if (!plugin_properties_sp && can_create) {
- plugin_properties_sp.reset(new OptionValueProperties(g_property_name));
+ plugin_properties_sp =
+ std::make_shared<OptionValueProperties>(g_property_name);
parent_properties_sp->AppendProperty(
g_property_name, ConstString("Settings specify to plugins."), true,
plugin_properties_sp);
@@ -2413,8 +2337,8 @@ static lldb::OptionValuePropertiesSP GetDebuggerPropertyForPlugins(
lldb::OptionValuePropertiesSP plugin_type_properties_sp =
plugin_properties_sp->GetSubProperty(nullptr, plugin_type_name);
if (!plugin_type_properties_sp && can_create) {
- plugin_type_properties_sp.reset(
- new OptionValueProperties(plugin_type_name));
+ plugin_type_properties_sp =
+ std::make_shared<OptionValueProperties>(plugin_type_name);
plugin_properties_sp->AppendProperty(plugin_type_name, plugin_type_desc,
true, plugin_type_properties_sp);
}
@@ -2437,7 +2361,8 @@ static lldb::OptionValuePropertiesSP GetDebuggerPropertyForPluginsOldStyle(
OptionValuePropertiesSP plugin_properties_sp =
parent_properties_sp->GetSubProperty(nullptr, plugin_type_name);
if (!plugin_properties_sp && can_create) {
- plugin_properties_sp.reset(new OptionValueProperties(plugin_type_name));
+ plugin_properties_sp =
+ std::make_shared<OptionValueProperties>(plugin_type_name);
parent_properties_sp->AppendProperty(plugin_type_name, plugin_type_desc,
true, plugin_properties_sp);
}
@@ -2446,8 +2371,8 @@ static lldb::OptionValuePropertiesSP GetDebuggerPropertyForPluginsOldStyle(
lldb::OptionValuePropertiesSP plugin_type_properties_sp =
plugin_properties_sp->GetSubProperty(nullptr, g_property_name);
if (!plugin_type_properties_sp && can_create) {
- plugin_type_properties_sp.reset(
- new OptionValueProperties(g_property_name));
+ plugin_type_properties_sp =
+ std::make_shared<OptionValueProperties>(g_property_name);
plugin_properties_sp->AppendProperty(
g_property_name, ConstString("Settings specific to plugins"), true,
plugin_type_properties_sp);
diff --git a/contrib/llvm/tools/lldb/source/Core/RegisterValue.cpp b/contrib/llvm/tools/lldb/source/Core/RegisterValue.cpp
index 2bc0b9d..28ce67e 100644
--- a/contrib/llvm/tools/lldb/source/Core/RegisterValue.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/RegisterValue.cpp
@@ -9,22 +9,27 @@
#include "lldb/Core/RegisterValue.h"
-// C Includes
-// C++ Includes
-#include <vector>
+#include "lldb/Core/DumpDataExtractor.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-private-types.h" // for RegisterInfo, type128
-// Other libraries and framework includes
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
-// Project includes
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Scalar.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/StringConvert.h"
-#include "lldb/Interpreter/Args.h"
+#include <cstdint> // for uint8_t, uint32_t, uint64_t
+#include <string> // for string
+#include <tuple> // for tie, tuple
+#include <vector>
+
+#include <assert.h> // for assert
+#include <inttypes.h> // for PRIx64
+#include <stdio.h> // for sscanf
using namespace lldb;
using namespace lldb_private;
@@ -76,15 +81,15 @@ bool RegisterValue::Dump(Stream *s, const RegisterInfo *reg_info,
if (format == eFormatDefault)
format = reg_info->format;
- data.Dump(s,
- 0, // Offset in "data"
- format, // Format to use when dumping
- reg_info->byte_size, // item_byte_size
- 1, // item_count
- UINT32_MAX, // num_per_line
- LLDB_INVALID_ADDRESS, // base_addr
- 0, // item_bit_size
- 0); // item_bit_offset
+ DumpDataExtractor(data, s,
+ 0, // Offset in "data"
+ format, // Format to use when dumping
+ reg_info->byte_size, // item_byte_size
+ 1, // item_count
+ UINT32_MAX, // num_per_line
+ LLDB_INVALID_ADDRESS, // base_addr
+ 0, // item_bit_size
+ 0); // item_bit_offset
return true;
}
return false;
@@ -97,7 +102,7 @@ bool RegisterValue::GetData(DataExtractor &data) const {
uint32_t RegisterValue::GetAsMemoryData(const RegisterInfo *reg_info, void *dst,
uint32_t dst_len,
lldb::ByteOrder dst_byte_order,
- Error &error) const {
+ Status &error) const {
if (reg_info == nullptr) {
error.SetErrorString("invalid register info argument.");
return 0;
@@ -143,7 +148,7 @@ uint32_t RegisterValue::GetAsMemoryData(const RegisterInfo *reg_info, void *dst,
uint32_t RegisterValue::SetFromMemoryData(const RegisterInfo *reg_info,
const void *src, uint32_t src_len,
lldb::ByteOrder src_byte_order,
- Error &error) {
+ Status &error) {
if (reg_info == nullptr) {
error.SetErrorString("invalid register info argument.");
return 0;
@@ -158,7 +163,7 @@ uint32_t RegisterValue::SetFromMemoryData(const RegisterInfo *reg_info,
//
// Case 2: src_len > dst_len
//
- // Error! (The register should always be big enough to hold the data)
+ // Status! (The register should always be big enough to hold the data)
//
// Case 3: src_len < dst_len
//
@@ -252,11 +257,11 @@ RegisterValue::Type RegisterValue::SetType(const RegisterInfo *reg_info) {
return m_type;
}
-Error RegisterValue::SetValueFromData(const RegisterInfo *reg_info,
- DataExtractor &src,
- lldb::offset_t src_offset,
- bool partial_data_ok) {
- Error error;
+Status RegisterValue::SetValueFromData(const RegisterInfo *reg_info,
+ DataExtractor &src,
+ lldb::offset_t src_offset,
+ bool partial_data_ok) {
+ Status error;
if (src.GetByteSize() == 0) {
error.SetErrorString("empty data.");
@@ -386,9 +391,9 @@ static bool ParseVectorEncoding(const RegisterInfo *reg_info,
return true;
}
-Error RegisterValue::SetValueFromString(const RegisterInfo *reg_info,
- llvm::StringRef value_str) {
- Error error;
+Status RegisterValue::SetValueFromString(const RegisterInfo *reg_info,
+ llvm::StringRef value_str) {
+ Status error;
if (reg_info == nullptr) {
error.SetErrorString("Invalid register info argument.");
return error;
diff --git a/contrib/llvm/tools/lldb/source/Core/Scalar.cpp b/contrib/llvm/tools/lldb/source/Core/Scalar.cpp
index 2b99ec1..630083b 100644
--- a/contrib/llvm/tools/lldb/source/Core/Scalar.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Scalar.cpp
@@ -9,24 +9,17 @@
#include "lldb/Core/Scalar.h"
-// C Includes
-// C++ Includes
-#include <cinttypes>
-#include <cmath>
-#include <cstdio>
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-types.h" // for offset_t
-// Other libraries and framework includes
#include "llvm/ADT/SmallString.h"
-// Project includes
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Host/Endian.h"
-#include "lldb/Host/StringConvert.h"
-#include "lldb/Interpreter/Args.h"
-
-#include "Plugins/Process/Utility/InstructionUtils.h"
+#include <cinttypes>
+#include <cstdio>
using namespace lldb;
using namespace lldb_private;
@@ -2467,9 +2460,9 @@ const Scalar lldb_private::operator>>(const Scalar &lhs, const Scalar &rhs) {
return result;
}
-Error Scalar::SetValueFromCString(const char *value_str, Encoding encoding,
- size_t byte_size) {
- Error error;
+Status Scalar::SetValueFromCString(const char *value_str, Encoding encoding,
+ size_t byte_size) {
+ Status error;
if (value_str == nullptr || value_str[0] == '\0') {
error.SetErrorString("Invalid c-string value string.");
return error;
@@ -2603,9 +2596,9 @@ Error Scalar::SetValueFromCString(const char *value_str, Encoding encoding,
return error;
}
-Error Scalar::SetValueFromData(DataExtractor &data, lldb::Encoding encoding,
- size_t byte_size) {
- Error error;
+Status Scalar::SetValueFromData(DataExtractor &data, lldb::Encoding encoding,
+ size_t byte_size) {
+ Status error;
type128 int128;
type256 int256;
@@ -2752,7 +2745,7 @@ bool Scalar::SignExtend(uint32_t sign_bit_pos) {
if (max_bit_pos == sign_bit_pos)
return true;
else if (sign_bit_pos < (max_bit_pos - 1)) {
- llvm::APInt sign_bit = llvm::APInt::getSignBit(sign_bit_pos + 1);
+ llvm::APInt sign_bit = llvm::APInt::getSignMask(sign_bit_pos + 1);
llvm::APInt bitwize_and = m_integer & sign_bit;
if (bitwize_and.getBoolValue()) {
const llvm::APInt mask =
@@ -2769,7 +2762,7 @@ bool Scalar::SignExtend(uint32_t sign_bit_pos) {
size_t Scalar::GetAsMemoryData(void *dst, size_t dst_len,
lldb::ByteOrder dst_byte_order,
- Error &error) const {
+ Status &error) const {
// Get a data extractor that points to the native scalar data
DataExtractor data;
if (!GetData(data)) {
diff --git a/contrib/llvm/tools/lldb/source/Core/SearchFilter.cpp b/contrib/llvm/tools/lldb/source/Core/SearchFilter.cpp
index 2dfb269..0701955 100644
--- a/contrib/llvm/tools/lldb/source/Core/SearchFilter.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/SearchFilter.cpp
@@ -7,16 +7,35 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/SearchFilter.h"
+
+#include "lldb/Breakpoint/Breakpoint.h" // for Breakpoint
#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h" // for ModuleList
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolContext.h" // for SymbolContext
#include "lldb/Target/Target.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/lldb-enumerations.h" // for SymbolContextItem::eSymbolCo...
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/Support/ErrorHandling.h" // for llvm_unreachable
+
+#include <memory> // for shared_ptr
+#include <mutex> // for recursive_mutex, lock_guard
+#include <string> // for string
+
+#include <inttypes.h> // for PRIu64
+#include <string.h> // for size_t, strcmp
+
+namespace lldb_private {
+class Address;
+}
+namespace lldb_private {
+class Function;
+}
using namespace lldb;
using namespace lldb_private;
@@ -36,9 +55,9 @@ const char *SearchFilter::FilterTyToName(enum FilterTy type) {
return g_ty_to_name[type];
}
-SearchFilter::FilterTy SearchFilter::NameToFilterTy(const char *name) {
+SearchFilter::FilterTy SearchFilter::NameToFilterTy(llvm::StringRef name) {
for (size_t i = 0; i <= LastKnownFilterType; i++) {
- if (strcmp(name, g_ty_to_name[i]) == 0)
+ if (name == g_ty_to_name[i])
return (FilterTy)i;
}
return UnknownFilter;
@@ -61,14 +80,14 @@ SearchFilter::~SearchFilter() = default;
SearchFilterSP SearchFilter::CreateFromStructuredData(
Target &target, const StructuredData::Dictionary &filter_dict,
- Error &error) {
+ Status &error) {
SearchFilterSP result_sp;
if (!filter_dict.IsValid()) {
error.SetErrorString("Can't deserialize from an invalid data object.");
return result_sp;
}
- std::string subclass_name;
+ llvm::StringRef subclass_name;
bool success = filter_dict.GetValueForKeyAsString(
GetSerializationSubclassKey(), subclass_name);
@@ -77,10 +96,9 @@ SearchFilterSP SearchFilter::CreateFromStructuredData(
return result_sp;
}
- FilterTy filter_type = NameToFilterTy(subclass_name.c_str());
+ FilterTy filter_type = NameToFilterTy(subclass_name);
if (filter_type == UnknownFilter) {
- error.SetErrorStringWithFormat("Unknown filter type: %s.",
- subclass_name.c_str());
+ error.SetErrorStringWithFormatv("Unknown filter type: {0}.", subclass_name);
return result_sp;
}
@@ -153,7 +171,7 @@ SearchFilter::WrapOptionsDict(StructuredData::DictionarySP options_dict_sp) {
if (!options_dict_sp || !options_dict_sp->IsValid())
return StructuredData::DictionarySP();
- StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary());
+ auto type_dict_sp = std::make_shared<StructuredData::Dictionary>();
type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetFilterName());
type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp);
@@ -169,10 +187,10 @@ void SearchFilter::SerializeFileSpecList(
if (num_modules == 0)
return;
- StructuredData::ArraySP module_array_sp(new StructuredData::Array());
+ auto module_array_sp = std::make_shared<StructuredData::Array>();
for (size_t i = 0; i < num_modules; i++) {
- module_array_sp->AddItem(StructuredData::StringSP(
- new StructuredData::String(file_list.GetFileSpecAtIndex(i).GetPath())));
+ module_array_sp->AddItem(std::make_shared<StructuredData::String>(
+ file_list.GetFileSpecAtIndex(i).GetPath()));
}
options_dict_sp->AddItem(GetKey(name), module_array_sp);
}
@@ -319,16 +337,17 @@ Searcher::CallbackReturn SearchFilter::DoFunctionIteration(
// "black list".
//----------------------------------------------------------------------
SearchFilterSP SearchFilterForUnconstrainedSearches::CreateFromStructuredData(
- Target &target, const StructuredData::Dictionary &data_dict, Error &error) {
+ Target &target, const StructuredData::Dictionary &data_dict,
+ Status &error) {
// No options for an unconstrained search.
- return SearchFilterSP(
- new SearchFilterForUnconstrainedSearches(target.shared_from_this()));
+ return std::make_shared<SearchFilterForUnconstrainedSearches>(
+ target.shared_from_this());
}
StructuredData::ObjectSP
SearchFilterForUnconstrainedSearches::SerializeToStructuredData() {
// The options dictionary is an empty dictionary:
- StructuredData::DictionarySP result_sp(new StructuredData::Dictionary());
+ auto result_sp = std::make_shared<StructuredData::Dictionary>();
return WrapOptionsDict(result_sp);
}
@@ -352,8 +371,7 @@ bool SearchFilterForUnconstrainedSearches::ModulePasses(
lldb::SearchFilterSP SearchFilterForUnconstrainedSearches::DoCopyForBreakpoint(
Breakpoint &breakpoint) {
- SearchFilterSP ret_sp(new SearchFilterForUnconstrainedSearches(*this));
- return ret_sp;
+ return std::make_shared<SearchFilterForUnconstrainedSearches>(*this);
}
//----------------------------------------------------------------------
@@ -433,13 +451,7 @@ void SearchFilterByModule::Search(Searcher &searcher) {
void SearchFilterByModule::GetDescription(Stream *s) {
s->PutCString(", module = ");
- if (s->GetVerbose()) {
- char buffer[2048];
- m_module_spec.GetPath(buffer, 2047);
- s->PutCString(buffer);
- } else {
- s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>"));
- }
+ s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>"));
}
uint32_t SearchFilterByModule::GetFilterRequiredItems() {
@@ -450,12 +462,12 @@ void SearchFilterByModule::Dump(Stream *s) const {}
lldb::SearchFilterSP
SearchFilterByModule::DoCopyForBreakpoint(Breakpoint &breakpoint) {
- SearchFilterSP ret_sp(new SearchFilterByModule(*this));
- return ret_sp;
+ return std::make_shared<SearchFilterByModule>(*this);
}
SearchFilterSP SearchFilterByModule::CreateFromStructuredData(
- Target &target, const StructuredData::Dictionary &data_dict, Error &error) {
+ Target &target, const StructuredData::Dictionary &data_dict,
+ Status &error) {
StructuredData::Array *modules_array;
bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
modules_array);
@@ -471,7 +483,7 @@ SearchFilterSP SearchFilterByModule::CreateFromStructuredData(
return nullptr;
}
- std::string module;
+ llvm::StringRef module;
success = modules_array->GetItemAtIndexAsString(0, module);
if (!success) {
error.SetErrorString("SFBM::CFSD: filter module item not a string.");
@@ -479,16 +491,15 @@ SearchFilterSP SearchFilterByModule::CreateFromStructuredData(
}
FileSpec module_spec(module, false);
- return SearchFilterSP(
- new SearchFilterByModule(target.shared_from_this(), module_spec));
+ return std::make_shared<SearchFilterByModule>(target.shared_from_this(),
+ module_spec);
}
StructuredData::ObjectSP SearchFilterByModule::SerializeToStructuredData() {
- StructuredData::DictionarySP options_dict_sp(
- new StructuredData::Dictionary());
- StructuredData::ArraySP module_array_sp(new StructuredData::Array());
- module_array_sp->AddItem(StructuredData::StringSP(
- new StructuredData::String(m_module_spec.GetPath())));
+ auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
+ auto module_array_sp = std::make_shared<StructuredData::Array>();
+ module_array_sp->AddItem(
+ std::make_shared<StructuredData::String>(m_module_spec.GetPath()));
options_dict_sp->AddItem(GetKey(OptionNames::ModList), module_array_sp);
return WrapOptionsDict(options_dict_sp);
}
@@ -591,27 +602,15 @@ void SearchFilterByModuleList::GetDescription(Stream *s) {
size_t num_modules = m_module_spec_list.GetSize();
if (num_modules == 1) {
s->Printf(", module = ");
- if (s->GetVerbose()) {
- char buffer[2048];
- m_module_spec_list.GetFileSpecAtIndex(0).GetPath(buffer, 2047);
- s->PutCString(buffer);
- } else {
- s->PutCString(
- m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
- "<Unknown>"));
- }
+ s->PutCString(
+ m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
+ "<Unknown>"));
} else {
s->Printf(", modules(%" PRIu64 ") = ", (uint64_t)num_modules);
for (size_t i = 0; i < num_modules; i++) {
- if (s->GetVerbose()) {
- char buffer[2048];
- m_module_spec_list.GetFileSpecAtIndex(i).GetPath(buffer, 2047);
- s->PutCString(buffer);
- } else {
- s->PutCString(
- m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
- "<Unknown>"));
- }
+ s->PutCString(
+ m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
+ "<Unknown>"));
if (i != num_modules - 1)
s->PutCString(", ");
}
@@ -626,12 +625,12 @@ void SearchFilterByModuleList::Dump(Stream *s) const {}
lldb::SearchFilterSP
SearchFilterByModuleList::DoCopyForBreakpoint(Breakpoint &breakpoint) {
- SearchFilterSP ret_sp(new SearchFilterByModuleList(*this));
- return ret_sp;
+ return std::make_shared<SearchFilterByModuleList>(*this);
}
SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData(
- Target &target, const StructuredData::Dictionary &data_dict, Error &error) {
+ Target &target, const StructuredData::Dictionary &data_dict,
+ Status &error) {
StructuredData::Array *modules_array;
bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
modules_array);
@@ -639,7 +638,7 @@ SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData(
if (success) {
size_t num_modules = modules_array->GetSize();
for (size_t i = 0; i < num_modules; i++) {
- std::string module;
+ llvm::StringRef module;
success = modules_array->GetItemAtIndexAsString(i, module);
if (!success) {
error.SetErrorStringWithFormat(
@@ -650,8 +649,8 @@ SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData(
}
}
- return SearchFilterSP(
- new SearchFilterByModuleList(target.shared_from_this(), modules));
+ return std::make_shared<SearchFilterByModuleList>(target.shared_from_this(),
+ modules);
}
void SearchFilterByModuleList::SerializeUnwrapped(
@@ -661,8 +660,7 @@ void SearchFilterByModuleList::SerializeUnwrapped(
}
StructuredData::ObjectSP SearchFilterByModuleList::SerializeToStructuredData() {
- StructuredData::DictionarySP options_dict_sp(
- new StructuredData::Dictionary());
+ auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
SerializeUnwrapped(options_dict_sp);
return WrapOptionsDict(options_dict_sp);
}
@@ -695,7 +693,8 @@ operator=(const SearchFilterByModuleListAndCU &rhs) {
SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU() = default;
lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData(
- Target &target, const StructuredData::Dictionary &data_dict, Error &error) {
+ Target &target, const StructuredData::Dictionary &data_dict,
+ Status &error) {
StructuredData::Array *modules_array = nullptr;
SearchFilterSP result_sp;
bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList),
@@ -704,7 +703,7 @@ lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData(
if (success) {
size_t num_modules = modules_array->GetSize();
for (size_t i = 0; i < num_modules; i++) {
- std::string module;
+ llvm::StringRef module;
success = modules_array->GetItemAtIndexAsString(i, module);
if (!success) {
error.SetErrorStringWithFormat(
@@ -726,7 +725,7 @@ lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData(
size_t num_cus = cus_array->GetSize();
FileSpecList cus;
for (size_t i = 0; i < num_cus; i++) {
- std::string cu;
+ llvm::StringRef cu;
success = cus_array->GetItemAtIndexAsString(i, cu);
if (!success) {
error.SetErrorStringWithFormat(
@@ -736,14 +735,13 @@ lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData(
cus.Append(FileSpec(cu, false));
}
- return SearchFilterSP(new SearchFilterByModuleListAndCU(
- target.shared_from_this(), modules, cus));
+ return std::make_shared<SearchFilterByModuleListAndCU>(
+ target.shared_from_this(), modules, cus);
}
StructuredData::ObjectSP
SearchFilterByModuleListAndCU::SerializeToStructuredData() {
- StructuredData::DictionarySP options_dict_sp(
- new StructuredData::Dictionary());
+ auto options_dict_sp = std::make_shared<StructuredData::Dictionary>();
SearchFilterByModuleList::SerializeUnwrapped(options_dict_sp);
SerializeFileSpecList(options_dict_sp, OptionNames::CUList, m_cu_spec_list);
return WrapOptionsDict(options_dict_sp);
@@ -827,27 +825,15 @@ void SearchFilterByModuleListAndCU::GetDescription(Stream *s) {
size_t num_modules = m_module_spec_list.GetSize();
if (num_modules == 1) {
s->Printf(", module = ");
- if (s->GetVerbose()) {
- char buffer[2048];
- m_module_spec_list.GetFileSpecAtIndex(0).GetPath(buffer, 2047);
- s->PutCString(buffer);
- } else {
- s->PutCString(
- m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
- "<Unknown>"));
- }
+ s->PutCString(
+ m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString(
+ "<Unknown>"));
} else if (num_modules > 0) {
s->Printf(", modules(%" PRIu64 ") = ", static_cast<uint64_t>(num_modules));
for (size_t i = 0; i < num_modules; i++) {
- if (s->GetVerbose()) {
- char buffer[2048];
- m_module_spec_list.GetFileSpecAtIndex(i).GetPath(buffer, 2047);
- s->PutCString(buffer);
- } else {
- s->PutCString(
- m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
- "<Unknown>"));
- }
+ s->PutCString(
+ m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString(
+ "<Unknown>"));
if (i != num_modules - 1)
s->PutCString(", ");
}
@@ -862,6 +848,5 @@ void SearchFilterByModuleListAndCU::Dump(Stream *s) const {}
lldb::SearchFilterSP
SearchFilterByModuleListAndCU::DoCopyForBreakpoint(Breakpoint &breakpoint) {
- SearchFilterSP ret_sp(new SearchFilterByModuleListAndCU(*this));
- return ret_sp;
+ return std::make_shared<SearchFilterByModuleListAndCU>(*this);
}
diff --git a/contrib/llvm/tools/lldb/source/Core/Section.cpp b/contrib/llvm/tools/lldb/source/Core/Section.cpp
index 95bcdad..3b76dd3 100644
--- a/contrib/llvm/tools/lldb/source/Core/Section.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Section.cpp
@@ -8,15 +8,119 @@
//===----------------------------------------------------------------------===//
#include "lldb/Core/Section.h"
+#include "lldb/Core/Address.h" // for Address
#include "lldb/Core/Module.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
-#include "lldb/Utility/ConvertEnum.h"
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/VMRange.h" // for VMRange
+#include <inttypes.h> // for PRIx64
+#include <limits> // for numeric_limits
+#include <utility> // for distance
+
+namespace lldb_private {
+class DataExtractor;
+}
using namespace lldb;
using namespace lldb_private;
+static const char *GetSectionTypeAsCString(lldb::SectionType sect_type) {
+ switch (sect_type) {
+ case eSectionTypeInvalid:
+ return "invalid";
+ case eSectionTypeCode:
+ return "code";
+ case eSectionTypeContainer:
+ return "container";
+ case eSectionTypeData:
+ return "data";
+ case eSectionTypeDataCString:
+ return "data-cstr";
+ case eSectionTypeDataCStringPointers:
+ return "data-cstr-ptr";
+ case eSectionTypeDataSymbolAddress:
+ return "data-symbol-addr";
+ case eSectionTypeData4:
+ return "data-4-byte";
+ case eSectionTypeData8:
+ return "data-8-byte";
+ case eSectionTypeData16:
+ return "data-16-byte";
+ case eSectionTypeDataPointers:
+ return "data-ptrs";
+ case eSectionTypeDebug:
+ return "debug";
+ case eSectionTypeZeroFill:
+ return "zero-fill";
+ case eSectionTypeDataObjCMessageRefs:
+ return "objc-message-refs";
+ case eSectionTypeDataObjCCFStrings:
+ return "objc-cfstrings";
+ case eSectionTypeDWARFDebugAbbrev:
+ return "dwarf-abbrev";
+ case eSectionTypeDWARFDebugAddr:
+ return "dwarf-addr";
+ case eSectionTypeDWARFDebugAranges:
+ return "dwarf-aranges";
+ case eSectionTypeDWARFDebugFrame:
+ return "dwarf-frame";
+ case eSectionTypeDWARFDebugInfo:
+ return "dwarf-info";
+ case eSectionTypeDWARFDebugLine:
+ return "dwarf-line";
+ case eSectionTypeDWARFDebugLoc:
+ return "dwarf-loc";
+ case eSectionTypeDWARFDebugMacInfo:
+ return "dwarf-macinfo";
+ case eSectionTypeDWARFDebugMacro:
+ return "dwarf-macro";
+ case eSectionTypeDWARFDebugPubNames:
+ return "dwarf-pubnames";
+ case eSectionTypeDWARFDebugPubTypes:
+ return "dwarf-pubtypes";
+ case eSectionTypeDWARFDebugRanges:
+ return "dwarf-ranges";
+ case eSectionTypeDWARFDebugStr:
+ return "dwarf-str";
+ case eSectionTypeDWARFDebugStrOffsets:
+ return "dwarf-str-offsets";
+ case eSectionTypeELFSymbolTable:
+ return "elf-symbol-table";
+ case eSectionTypeELFDynamicSymbols:
+ return "elf-dynamic-symbols";
+ case eSectionTypeELFRelocationEntries:
+ return "elf-relocation-entries";
+ case eSectionTypeELFDynamicLinkInfo:
+ return "elf-dynamic-link-info";
+ case eSectionTypeDWARFAppleNames:
+ return "apple-names";
+ case eSectionTypeDWARFAppleTypes:
+ return "apple-types";
+ case eSectionTypeDWARFAppleNamespaces:
+ return "apple-namespaces";
+ case eSectionTypeDWARFAppleObjC:
+ return "apple-objc";
+ case eSectionTypeEHFrame:
+ return "eh-frame";
+ case eSectionTypeARMexidx:
+ return "ARM.exidx";
+ case eSectionTypeARMextab:
+ return "ARM.extab";
+ case eSectionTypeCompactUnwind:
+ return "compact-unwind";
+ case eSectionTypeGoSymtab:
+ return "go-symtab";
+ case eSectionTypeAbsoluteAddress:
+ return "absolute";
+ case eSectionTypeOther:
+ return "regular";
+ }
+ return "unknown";
+}
+
Section::Section(const ModuleSP &module_sp, ObjectFile *obj_file,
user_id_t sect_id, const ConstString &name,
SectionType sect_type, addr_t file_addr, addr_t byte_size,
@@ -116,18 +220,18 @@ addr_t Section::GetLoadBaseAddress(Target *target) const {
return load_base_addr;
}
-bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr) const {
+bool Section::ResolveContainedAddress(addr_t offset, Address &so_addr,
+ bool allow_section_end) const {
const size_t num_children = m_children.GetSize();
- if (num_children > 0) {
- for (size_t i = 0; i < num_children; i++) {
- Section *child_section = m_children.GetSectionAtIndex(i).get();
-
- addr_t child_offset = child_section->GetOffset();
- if (child_offset <= offset &&
- offset - child_offset < child_section->GetByteSize())
- return child_section->ResolveContainedAddress(offset - child_offset,
- so_addr);
- }
+ for (size_t i = 0; i < num_children; i++) {
+ Section *child_section = m_children.GetSectionAtIndex(i).get();
+
+ addr_t child_offset = child_section->GetOffset();
+ if (child_offset <= offset &&
+ offset - child_offset <
+ child_section->GetByteSize() + (allow_section_end ? 1 : 0))
+ return child_section->ResolveContainedAddress(offset - child_offset,
+ so_addr, allow_section_end);
}
so_addr.SetOffset(offset);
so_addr.SetSection(const_cast<Section *>(this)->shared_from_this());
diff --git a/contrib/llvm/tools/lldb/source/Core/SourceManager.cpp b/contrib/llvm/tools/lldb/source/Core/SourceManager.cpp
index 603fe57..b284ff1 100644
--- a/contrib/llvm/tools/lldb/source/Core/SourceManager.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/SourceManager.cpp
@@ -9,21 +9,40 @@
#include "lldb/Core/SourceManager.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Address.h" // for Address
+#include "lldb/Core/AddressRange.h" // for AddressRange
#include "lldb/Core/Debugger.h"
+#include "lldb/Core/FormatEntity.h" // for FormatEntity
#include "lldb/Core/Module.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Core/ModuleList.h" // for ModuleList
#include "lldb/Host/FileSystem.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/LineEntry.h" // for LineEntry
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/PathMappingList.h" // for PathMappingList
#include "lldb/Target/Target.h"
-#include "lldb/Utility/AnsiTerminal.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferLLVM.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-enumerations.h" // for StopShowColumn::eStopSho...
+
+#include "llvm/ADT/Twine.h" // for Twine
+
+#include <memory>
+#include <utility> // for pair
+
+#include <assert.h> // for assert
+#include <stdio.h> // for size_t, NULL, snprintf
+
+namespace lldb_private {
+class ExecutionContext;
+}
+namespace lldb_private {
+class ValueObject;
+}
using namespace lldb;
using namespace lldb_private;
@@ -74,9 +93,9 @@ SourceManager::FileSP SourceManager::GetFile(const FileSpec &file_spec) {
// If file_sp is no good or it points to a non-existent file, reset it.
if (!file_sp || !file_sp->GetFileSpec().Exists()) {
if (target_sp)
- file_sp.reset(new File(file_spec, target_sp.get()));
+ file_sp = std::make_shared<File>(file_spec, target_sp.get());
else
- file_sp.reset(new File(file_spec, debugger_sp));
+ file_sp = std::make_shared<File>(file_spec, debugger_sp);
if (debugger_sp)
debugger_sp->GetSourceFileCache().AddSourceFile(file_sp);
@@ -404,7 +423,7 @@ void SourceManager::File::CommonInitializer(const FileSpec &file_spec,
}
if (m_mod_time != llvm::sys::TimePoint<>())
- m_data_sp = m_file_spec.ReadFileContents();
+ m_data_sp = DataBufferLLVM::CreateFromPath(m_file_spec.GetPath());
}
uint32_t SourceManager::File::GetLineOffset(uint32_t line) {
@@ -482,7 +501,7 @@ void SourceManager::File::UpdateIfNeeded() {
if (curr_mod_time != llvm::sys::TimePoint<>() &&
m_mod_time != curr_mod_time) {
m_mod_time = curr_mod_time;
- m_data_sp = m_file_spec.ReadFileContents();
+ m_data_sp = DataBufferLLVM::CreateFromPath(m_file_spec.GetPath());
m_offsets.clear();
}
}
diff --git a/contrib/llvm/tools/lldb/source/Core/State.cpp b/contrib/llvm/tools/lldb/source/Core/State.cpp
index 80497dd77..4697ca4 100644
--- a/contrib/llvm/tools/lldb/source/Core/State.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/State.cpp
@@ -12,7 +12,6 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/State.h"
-#include <stdio.h>
using namespace lldb;
using namespace lldb_private;
@@ -44,10 +43,7 @@ const char *lldb_private::StateAsCString(StateType state) {
case eStateSuspended:
return "suspended";
}
- static char unknown_state_string[64];
- snprintf(unknown_state_string, sizeof(unknown_state_string), "StateType = %i",
- state);
- return unknown_state_string;
+ return "unknown";
}
const char *lldb_private::GetPermissionsAsCString(uint32_t permissions) {
diff --git a/contrib/llvm/tools/lldb/source/Core/StreamAsynchronousIO.cpp b/contrib/llvm/tools/lldb/source/Core/StreamAsynchronousIO.cpp
index 1f7e634..aae8636 100644
--- a/contrib/llvm/tools/lldb/source/Core/StreamAsynchronousIO.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/StreamAsynchronousIO.cpp
@@ -10,7 +10,7 @@
#include "lldb/Core/StreamAsynchronousIO.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-enumerations.h" // for ByteOrder::eByteOrderBig
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/StreamCallback.cpp b/contrib/llvm/tools/lldb/source/Core/StreamCallback.cpp
deleted file mode 100644
index de78410..0000000
--- a/contrib/llvm/tools/lldb/source/Core/StreamCallback.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-//===-- StreamCallback.cpp -------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include <stdio.h>
-
-#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/Event.h"
-#include "lldb/Core/StreamCallback.h"
-#include "lldb/Host/Host.h"
-#include "lldb/lldb-private.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-StreamCallback::StreamCallback(lldb::LogOutputCallback callback, void *baton)
- : Stream(0, 4, eByteOrderBig), m_callback(callback), m_baton(baton),
- m_accumulated_data(), m_collection_mutex() {}
-
-StreamCallback::~StreamCallback() {}
-
-StreamString &StreamCallback::FindStreamForThread(lldb::tid_t cur_tid) {
- std::lock_guard<std::mutex> guard(m_collection_mutex);
- collection::iterator iter = m_accumulated_data.find(cur_tid);
- if (iter == m_accumulated_data.end()) {
- std::pair<collection::iterator, bool> ret;
- ret = m_accumulated_data.insert(
- std::pair<lldb::tid_t, StreamString>(cur_tid, StreamString()));
- iter = ret.first;
- }
- return (*iter).second;
-}
-
-void StreamCallback::Flush() {
- lldb::tid_t cur_tid = Host::GetCurrentThreadID();
- StreamString &out_stream = FindStreamForThread(cur_tid);
- m_callback(out_stream.GetData(), m_baton);
- out_stream.Clear();
-}
-
-size_t StreamCallback::Write(const void *s, size_t length) {
- lldb::tid_t cur_tid = Host::GetCurrentThreadID();
- FindStreamForThread(cur_tid).Write(s, length);
- return length;
-}
diff --git a/contrib/llvm/tools/lldb/source/Core/StreamFile.cpp b/contrib/llvm/tools/lldb/source/Core/StreamFile.cpp
index f8c7fb9..f594154 100644
--- a/contrib/llvm/tools/lldb/source/Core/StreamFile.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/StreamFile.cpp
@@ -9,12 +9,7 @@
#include "lldb/Core/StreamFile.h"
-// C Includes
#include <stdio.h>
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Error.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/Timer.cpp b/contrib/llvm/tools/lldb/source/Core/Timer.cpp
deleted file mode 100644
index ca1a2b7..0000000
--- a/contrib/llvm/tools/lldb/source/Core/Timer.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-//===-- Timer.cpp -----------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "lldb/Core/Timer.h"
-
-#include <algorithm>
-#include <map>
-#include <mutex>
-#include <vector>
-
-#include "lldb/Core/Stream.h"
-#include "lldb/Host/Host.h"
-
-#include <stdio.h>
-
-using namespace lldb_private;
-
-#define TIMER_INDENT_AMOUNT 2
-
-namespace {
-typedef std::map<const char *, std::chrono::nanoseconds> TimerCategoryMap;
-typedef std::vector<Timer *> TimerStack;
-} // end of anonymous namespace
-
-std::atomic<bool> Timer::g_quiet(true);
-std::atomic<unsigned> Timer::g_display_depth(0);
-static std::mutex &GetFileMutex() {
- static std::mutex *g_file_mutex_ptr = new std::mutex();
- return *g_file_mutex_ptr;
-}
-
-static std::mutex &GetCategoryMutex() {
- static std::mutex g_category_mutex;
- return g_category_mutex;
-}
-
-static TimerCategoryMap &GetCategoryMap() {
- static TimerCategoryMap g_category_map;
- return g_category_map;
-}
-
-static void ThreadSpecificCleanup(void *p) {
- delete static_cast<TimerStack *>(p);
-}
-
-static TimerStack *GetTimerStackForCurrentThread() {
- static lldb::thread_key_t g_key =
- Host::ThreadLocalStorageCreate(ThreadSpecificCleanup);
-
- void *timer_stack = Host::ThreadLocalStorageGet(g_key);
- if (timer_stack == NULL) {
- Host::ThreadLocalStorageSet(g_key, new TimerStack);
- timer_stack = Host::ThreadLocalStorageGet(g_key);
- }
- return (TimerStack *)timer_stack;
-}
-
-void Timer::SetQuiet(bool value) { g_quiet = value; }
-
-Timer::Timer(const char *category, const char *format, ...)
- : m_category(category), m_total_start(std::chrono::steady_clock::now()) {
- TimerStack *stack = GetTimerStackForCurrentThread();
- if (!stack)
- return;
-
- stack->push_back(this);
- if (g_quiet && stack->size() <= g_display_depth) {
- std::lock_guard<std::mutex> lock(GetFileMutex());
-
- // Indent
- ::fprintf(stdout, "%*s", int(stack->size() - 1) * TIMER_INDENT_AMOUNT, "");
- // Print formatted string
- va_list args;
- va_start(args, format);
- ::vfprintf(stdout, format, args);
- va_end(args);
-
- // Newline
- ::fprintf(stdout, "\n");
- }
-}
-
-Timer::~Timer() {
- using namespace std::chrono;
-
- TimerStack *stack = GetTimerStackForCurrentThread();
- if (!stack)
- return;
-
- auto stop_time = steady_clock::now();
- auto total_dur = stop_time - m_total_start;
- auto timer_dur = total_dur - m_child_duration;
-
- if (g_quiet && stack->size() <= g_display_depth) {
- std::lock_guard<std::mutex> lock(GetFileMutex());
- ::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n",
- int(stack->size() - 1) * TIMER_INDENT_AMOUNT, "",
- duration<double>(total_dur).count(),
- duration<double>(timer_dur).count());
- }
-
- assert(stack->back() == this);
- stack->pop_back();
- if (!stack->empty())
- stack->back()->ChildDuration(total_dur);
-
- // Keep total results for each category so we can dump results.
- {
- std::lock_guard<std::mutex> guard(GetCategoryMutex());
- TimerCategoryMap &category_map = GetCategoryMap();
- category_map[m_category] += timer_dur;
- }
-}
-
-void Timer::SetDisplayDepth(uint32_t depth) { g_display_depth = depth; }
-
-/* binary function predicate:
- * - returns whether a person is less than another person
- */
-static bool
-CategoryMapIteratorSortCriterion(const TimerCategoryMap::const_iterator &lhs,
- const TimerCategoryMap::const_iterator &rhs) {
- return lhs->second > rhs->second;
-}
-
-void Timer::ResetCategoryTimes() {
- std::lock_guard<std::mutex> guard(GetCategoryMutex());
- TimerCategoryMap &category_map = GetCategoryMap();
- category_map.clear();
-}
-
-void Timer::DumpCategoryTimes(Stream *s) {
- std::lock_guard<std::mutex> guard(GetCategoryMutex());
- TimerCategoryMap &category_map = GetCategoryMap();
- std::vector<TimerCategoryMap::const_iterator> sorted_iterators;
- TimerCategoryMap::const_iterator pos, end = category_map.end();
- for (pos = category_map.begin(); pos != end; ++pos) {
- sorted_iterators.push_back(pos);
- }
- std::sort(sorted_iterators.begin(), sorted_iterators.end(),
- CategoryMapIteratorSortCriterion);
-
- const size_t count = sorted_iterators.size();
- for (size_t i = 0; i < count; ++i) {
- const auto timer = sorted_iterators[i]->second;
- s->Printf("%.9f sec for %s\n", std::chrono::duration<double>(timer).count(),
- sorted_iterators[i]->first);
- }
-}
diff --git a/contrib/llvm/tools/lldb/source/Core/UserSettingsController.cpp b/contrib/llvm/tools/lldb/source/Core/UserSettingsController.cpp
index 92c3c84..a4661a6 100644
--- a/contrib/llvm/tools/lldb/source/Core/UserSettingsController.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/UserSettingsController.cpp
@@ -1,5 +1,4 @@
-//====-- UserSettingsController.cpp ------------------------------*- C++
-//-*-===//
+//====-- UserSettingsController.cpp ------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,37 +7,48 @@
//
//===----------------------------------------------------------------------===//
-#include <algorithm>
-#include <string.h>
-
-#include "lldb/Core/Error.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/UserSettingsController.h"
-#include "lldb/Interpreter/CommandInterpreter.h"
+
#include "lldb/Interpreter/OptionValueProperties.h"
-#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+#include <memory> // for shared_ptr
+
+namespace lldb_private {
+class CommandInterpreter;
+}
+namespace lldb_private {
+class ConstString;
+}
+namespace lldb_private {
+class ExecutionContext;
+}
+namespace lldb_private {
+class Property;
+}
using namespace lldb;
using namespace lldb_private;
lldb::OptionValueSP
-Properties::GetPropertyValue(const ExecutionContext *exe_ctx, llvm::StringRef path,
- bool will_modify, Error &error) const {
+Properties::GetPropertyValue(const ExecutionContext *exe_ctx,
+ llvm::StringRef path, bool will_modify,
+ Status &error) const {
OptionValuePropertiesSP properties_sp(GetValueProperties());
if (properties_sp)
return properties_sp->GetSubValue(exe_ctx, path, will_modify, error);
return lldb::OptionValueSP();
}
-Error Properties::SetPropertyValue(const ExecutionContext *exe_ctx,
- VarSetOperationType op, llvm::StringRef path,
- llvm::StringRef value) {
+Status Properties::SetPropertyValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ llvm::StringRef path,
+ llvm::StringRef value) {
OptionValuePropertiesSP properties_sp(GetValueProperties());
if (properties_sp)
return properties_sp->SetSubValue(exe_ctx, op, path, value);
- Error error;
+ Status error;
error.SetErrorString("no properties");
return error;
}
@@ -59,15 +69,16 @@ void Properties::DumpAllDescriptions(CommandInterpreter &interpreter,
return properties_sp->DumpAllDescriptions(interpreter, strm);
}
-Error Properties::DumpPropertyValue(const ExecutionContext *exe_ctx,
- Stream &strm, llvm::StringRef property_path,
- uint32_t dump_mask) {
+Status Properties::DumpPropertyValue(const ExecutionContext *exe_ctx,
+ Stream &strm,
+ llvm::StringRef property_path,
+ uint32_t dump_mask) {
OptionValuePropertiesSP properties_sp(GetValueProperties());
if (properties_sp) {
return properties_sp->DumpPropertyValue(exe_ctx, strm, property_path,
dump_mask);
}
- Error error;
+ Status error;
error.SetErrorString("empty property list");
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Core/Value.cpp b/contrib/llvm/tools/lldb/source/Core/Value.cpp
index a480c3c..6338551 100644
--- a/contrib/llvm/tools/lldb/source/Core/Value.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/Value.cpp
@@ -9,16 +9,10 @@
#include "lldb/Core/Value.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Address.h" // for Address
+#include "lldb/Core/ArchSpec.h" // for ArchSpec
#include "lldb/Core/Module.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
@@ -28,6 +22,20 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h" // for InlHostByteOrder
+#include "lldb/Utility/FileSpec.h" // for FileSpec
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-forward.h" // for DataBufferSP, ModuleSP
+#include "lldb/lldb-types.h" // for addr_t
+
+#include <memory> // for make_shared
+#include <string> // for string
+
+#include <inttypes.h> // for PRIx64
using namespace lldb;
using namespace lldb_private;
@@ -136,7 +144,7 @@ Type *Value::GetType() {
size_t Value::AppendDataToHostBuffer(const Value &rhs) {
size_t curr_size = m_data_buffer.GetByteSize();
- Error error;
+ Status error;
switch (rhs.GetValueType()) {
case eValueTypeScalar: {
const size_t scalar_size = rhs.m_value.GetByteSize();
@@ -199,7 +207,7 @@ bool Value::ValueOf(ExecutionContext *exe_ctx) {
return false;
}
-uint64_t Value::GetValueByteSize(Error *error_ptr, ExecutionContext *exe_ctx) {
+uint64_t Value::GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx) {
uint64_t byte_size = 0;
switch (m_context_type) {
@@ -307,11 +315,11 @@ bool Value::GetData(DataExtractor &data) {
return false;
}
-Error Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
- uint32_t data_offset, Module *module) {
+Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
+ uint32_t data_offset, Module *module) {
data.Clear();
- Error error;
+ Status error;
lldb::addr_t address = LLDB_INVALID_ADDRESS;
AddressType address_type = eAddressTypeFile;
Address file_so_addr;
@@ -538,7 +546,8 @@ Error Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
// Make sure we have enough room within "data", and if we don't make
// something large enough that does
if (!data.ValidOffsetForDataOfSize(data_offset, byte_size)) {
- DataBufferSP data_sp(new DataBufferHeap(data_offset + byte_size, '\0'));
+ auto data_sp =
+ std::make_shared<DataBufferHeap>(data_offset + byte_size, '\0');
data.SetData(data_sp);
}
@@ -614,7 +623,7 @@ Scalar &Value::ResolveValue(ExecutionContext *exe_ctx) {
{
DataExtractor data;
lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
- Error error(GetValueAsData(exe_ctx, data, 0, NULL));
+ Status error(GetValueAsData(exe_ctx, data, 0, NULL));
if (error.Success()) {
Scalar scalar;
if (compiler_type.GetValueAsScalar(data, 0, data.GetByteSize(),
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObject.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObject.cpp
index fc2312d..c09139f 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObject.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObject.cpp
@@ -9,52 +9,67 @@
#include "lldb/Core/ValueObject.h"
-// C Includes
-#include <stdlib.h>
-
-// C++ Includes
-// Other libraries and framework includes
-#include "llvm/Support/raw_ostream.h"
-
-// Project includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Core/Address.h" // for Address
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Scalar.h" // for Scalar
#include "lldb/Core/ValueObjectCast.h"
#include "lldb/Core/ValueObjectChild.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectDynamicValue.h"
-#include "lldb/Core/ValueObjectList.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Core/ValueObjectSyntheticFilter.h"
-
#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/DataFormatters/FormatManager.h" // for FormatManager
#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/DataFormatters/TypeFormat.h" // for TypeFormatImpl_F...
+#include "lldb/DataFormatters/TypeSummary.h" // for TypeSummaryOptions
+#include "lldb/DataFormatters/TypeValidator.h" // for TypeValidatorImp...
#include "lldb/DataFormatters/ValueObjectPrinter.h"
-
-#include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h"
-#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
-
-#include "lldb/Host/Endian.h"
-
-#include "lldb/Interpreter/CommandInterpreter.h"
-
+#include "lldb/Expression/ExpressionVariable.h" // for ExpressionVariable
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Symbol/Declaration.h" // for Declaration
+#include "lldb/Symbol/SymbolContext.h" // for SymbolContext
#include "lldb/Symbol/Type.h"
-
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
-#include "lldb/Target/RegisterContext.h"
-#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StackFrame.h" // for StackFrame
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadList.h" // for ThreadList
+#include "lldb/Utility/DataBuffer.h" // for DataBuffer
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Flags.h" // for Flags
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for GetLogIfAllCateg...
+#include "lldb/Utility/SharingPtr.h" // for SharingPtr
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-private-types.h" // for RegisterInfo
+
+#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
+
+#include <algorithm> // for min
+#include <cstdint> // for uint32_t, uint64_t
+#include <cstdlib> // for size_t, NULL
+#include <memory> // for shared_ptr, oper...
+#include <tuple> // for tie, tuple
+
+#include <assert.h> // for assert
+#include <inttypes.h> // for PRIu64, PRIx64
+#include <stdio.h> // for snprintf
+#include <string.h> // for memcpy, memcmp
+
+namespace lldb_private {
+class ExecutionContextScope;
+}
+namespace lldb_private {
+class SymbolContextScope;
+}
using namespace lldb;
using namespace lldb_private;
@@ -332,7 +347,7 @@ DataExtractor &ValueObject::GetDataExtractor() {
return m_data;
}
-const Error &ValueObject::GetError() {
+const Status &ValueObject::GetError() {
UpdateValueIfNeeded(false);
return m_error;
}
@@ -408,7 +423,7 @@ bool ValueObject::ResolveValue(Scalar &scalar) {
return false;
}
-bool ValueObject::IsLogicalTrue(Error &error) {
+bool ValueObject::IsLogicalTrue(Status &error) {
if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) {
LazyBool is_logical_true = language->IsLogicalTrue(*this, error);
switch (is_logical_true) {
@@ -466,21 +481,8 @@ ValueObjectSP ValueObject::GetChildAtIndex(size_t idx, bool can_create) {
return child_sp;
}
-ValueObjectSP
-ValueObject::GetChildAtIndexPath(const std::initializer_list<size_t> &idxs,
- size_t *index_of_error) {
- return GetChildAtIndexPath(std::vector<size_t>(idxs), index_of_error);
-}
-
-ValueObjectSP ValueObject::GetChildAtIndexPath(
- const std::initializer_list<std::pair<size_t, bool>> &idxs,
- size_t *index_of_error) {
- return GetChildAtIndexPath(std::vector<std::pair<size_t, bool>>(idxs),
- index_of_error);
-}
-
lldb::ValueObjectSP
-ValueObject::GetChildAtIndexPath(const std::vector<size_t> &idxs,
+ValueObject::GetChildAtIndexPath(llvm::ArrayRef<size_t> idxs,
size_t *index_of_error) {
if (idxs.size() == 0)
return GetSP();
@@ -497,7 +499,7 @@ ValueObject::GetChildAtIndexPath(const std::vector<size_t> &idxs,
}
lldb::ValueObjectSP ValueObject::GetChildAtIndexPath(
- const std::vector<std::pair<size_t, bool>> &idxs, size_t *index_of_error) {
+ llvm::ArrayRef<std::pair<size_t, bool>> idxs, size_t *index_of_error) {
if (idxs.size() == 0)
return GetSP();
ValueObjectSP root(GetSP());
@@ -513,20 +515,7 @@ lldb::ValueObjectSP ValueObject::GetChildAtIndexPath(
}
lldb::ValueObjectSP
-ValueObject::GetChildAtNamePath(const std::initializer_list<ConstString> &names,
- ConstString *name_of_error) {
- return GetChildAtNamePath(std::vector<ConstString>(names), name_of_error);
-}
-
-lldb::ValueObjectSP ValueObject::GetChildAtNamePath(
- const std::initializer_list<std::pair<ConstString, bool>> &names,
- ConstString *name_of_error) {
- return GetChildAtNamePath(std::vector<std::pair<ConstString, bool>>(names),
- name_of_error);
-}
-
-lldb::ValueObjectSP
-ValueObject::GetChildAtNamePath(const std::vector<ConstString> &names,
+ValueObject::GetChildAtNamePath(llvm::ArrayRef<ConstString> names,
ConstString *name_of_error) {
if (names.size() == 0)
return GetSP();
@@ -543,7 +532,7 @@ ValueObject::GetChildAtNamePath(const std::vector<ConstString> &names,
}
lldb::ValueObjectSP ValueObject::GetChildAtNamePath(
- const std::vector<std::pair<ConstString, bool>> &names,
+ llvm::ArrayRef<std::pair<ConstString, bool>> names,
ConstString *name_of_error) {
if (names.size() == 0)
return GetSP();
@@ -782,7 +771,7 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx,
if (item_idx == 0 && item_count == 1) // simply a deref
{
if (is_pointer_type) {
- Error error;
+ Status error;
ValueObjectSP pointee_sp = Dereference(error);
if (error.Fail() || pointee_sp.get() == NULL)
return 0;
@@ -791,13 +780,13 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx,
ValueObjectSP child_sp = GetChildAtIndex(0, true);
if (child_sp.get() == NULL)
return 0;
- Error error;
+ Status error;
return child_sp->GetData(data, error);
}
return true;
} else /* (items > 1) */
{
- Error error;
+ Status error;
lldb_private::DataBufferHeap *heap_buf_ptr = NULL;
lldb::DataBufferSP data_sp(heap_buf_ptr =
new lldb_private::DataBufferHeap());
@@ -859,7 +848,7 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx,
return 0;
}
-uint64_t ValueObject::GetData(DataExtractor &data, Error &error) {
+uint64_t ValueObject::GetData(DataExtractor &data, Status &error) {
UpdateValueIfNeeded(false);
ExecutionContext exe_ctx(GetExecutionContextRef());
error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get());
@@ -877,7 +866,7 @@ uint64_t ValueObject::GetData(DataExtractor &data, Error &error) {
return data.GetByteSize();
}
-bool ValueObject::SetData(DataExtractor &data, Error &error) {
+bool ValueObject::SetData(DataExtractor &data, Status &error) {
error.Clear();
// Make sure our value is up to date first so that our location and location
// type is valid.
@@ -895,7 +884,7 @@ bool ValueObject::SetData(DataExtractor &data, Error &error) {
switch (value_type) {
case Value::eValueTypeScalar: {
- Error set_error =
+ Status set_error =
m_value.GetScalar().SetValueFromData(data, encoding, byte_size);
if (!set_error.Success()) {
@@ -949,7 +938,7 @@ static bool CopyStringDataToBufferSP(const StreamString &source,
}
std::pair<size_t, bool>
-ValueObject::ReadPointedString(lldb::DataBufferSP &buffer_sp, Error &error,
+ValueObject::ReadPointedString(lldb::DataBufferSP &buffer_sp, Status &error,
uint32_t max_length, bool honor_array,
Format item_format) {
bool was_capped = false;
@@ -1296,7 +1285,7 @@ bool ValueObject::DumpPrintableRepresentation(
custom_format ==
eFormatVectorOfChar)) // print char[] & char* directly
{
- Error error;
+ Status error;
lldb::DataBufferSP buffer_sp;
std::pair<size_t, bool> read_string = ReadPointedString(
buffer_sp, error, 0, (custom_format == eFormatVectorOfChar) ||
@@ -1572,7 +1561,7 @@ addr_t ValueObject::GetPointerValue(AddressType *address_type) {
return address;
}
-bool ValueObject::SetValueFromCString(const char *value_str, Error &error) {
+bool ValueObject::SetValueFromCString(const char *value_str, Status &error) {
error.Clear();
// Make sure our value is up to date first so that our location and location
// type is valid.
@@ -2196,7 +2185,7 @@ ValueObjectSP ValueObject::GetValueForExpressionPath(
if ((final_task_on_target ? *final_task_on_target
: dummy_final_task_on_target) ==
ValueObject::eExpressionPathAftermathDereference) {
- Error error;
+ Status error;
ValueObjectSP final_value = ret_val->Dereference(error);
if (error.Fail() || !final_value.get()) {
if (reason_to_stop)
@@ -2213,7 +2202,7 @@ ValueObjectSP ValueObject::GetValueForExpressionPath(
}
if (*final_task_on_target ==
ValueObject::eExpressionPathAftermathTakeAddress) {
- Error error;
+ Status error;
ValueObjectSP final_value = ret_val->AddressOf(error);
if (error.Fail() || !final_value.get()) {
if (reason_to_stop)
@@ -2563,7 +2552,7 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl(
// and use this as
// a bitfield
pointee_compiler_type_info.Test(eTypeIsScalar)) {
- Error error;
+ Status error;
root = root->Dereference(error);
if (error.Fail() || !root) {
*reason_to_stop =
@@ -2708,7 +2697,7 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl(
*what_next ==
ValueObject::eExpressionPathAftermathDereference &&
pointee_compiler_type_info.Test(eTypeIsScalar)) {
- Error error;
+ Status error;
root = root->Dereference(error);
if (error.Fail() || !root) {
*reason_to_stop =
@@ -2850,7 +2839,7 @@ lldb::addr_t ValueObject::GetCPPVTableAddress(AddressType &address_type) {
return LLDB_INVALID_ADDRESS;
}
-ValueObjectSP ValueObject::Dereference(Error &error) {
+ValueObjectSP ValueObject::Dereference(Status &error) {
if (m_deref_valobj)
return m_deref_valobj->GetSP();
@@ -2889,6 +2878,11 @@ ValueObjectSP ValueObject::Dereference(Error &error) {
child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid,
language_flags);
}
+ } else if (HasSyntheticValue()) {
+ m_deref_valobj =
+ GetSyntheticValue()
+ ->GetChildMemberWithName(ConstString("$$dereference$$"), true)
+ .get();
}
if (m_deref_valobj) {
@@ -2910,7 +2904,7 @@ ValueObjectSP ValueObject::Dereference(Error &error) {
}
}
-ValueObjectSP ValueObject::AddressOf(Error &error) {
+ValueObjectSP ValueObject::AddressOf(Status &error) {
if (m_addr_of_valobj_sp)
return m_addr_of_valobj_sp;
@@ -2957,6 +2951,10 @@ ValueObjectSP ValueObject::Cast(const CompilerType &compiler_type) {
return ValueObjectCast::Create(*this, GetName(), compiler_type);
}
+lldb::ValueObjectSP ValueObject::Clone(const ConstString &new_name) {
+ return ValueObjectCast::Create(*this, new_name, GetCompilerType());
+}
+
ValueObjectSP ValueObject::CastPointerType(const char *name,
CompilerType &compiler_type) {
ValueObjectSP valobj_sp;
@@ -3193,7 +3191,7 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
if (ptr_result_valobj_sp) {
ptr_result_valobj_sp->GetValue().SetValueType(
Value::eValueTypeLoadAddress);
- Error err;
+ Status err;
ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
if (ptr_result_valobj_sp && !name.empty())
ptr_result_valobj_sp->SetName(ConstString(name));
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectCast.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectCast.cpp
index 300aeae..a489bdc 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectCast.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectCast.cpp
@@ -9,27 +9,16 @@
#include "lldb/Core/ValueObjectCast.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Module.h"
+#include "lldb/Core/Scalar.h" // for operator!=, Scalar
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObject.h"
-#include "lldb/Core/ValueObjectList.h"
-
#include "lldb/Symbol/CompilerType.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Symbol/Type.h"
-#include "lldb/Symbol/Variable.h"
-
#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/RegisterContext.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Status.h" // for Status
+
+namespace lldb_private {
+class ConstString;
+}
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectChild.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectChild.cpp
index 9b2bdd1..591bc21 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectChild.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectChild.cpp
@@ -9,18 +9,21 @@
#include "lldb/Core/ValueObjectChild.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ValueObjectList.h"
-
+#include "lldb/Core/Scalar.h" // for Scalar
+#include "lldb/Core/Value.h" // for Value, Value::ValueType::e...
#include "lldb/Symbol/CompilerType.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Symbol/Type.h"
-#include "lldb/Symbol/Variable.h"
-
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
-#include "lldb/Target/Target.h"
+#include "lldb/Utility/Flags.h" // for Flags
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-forward.h" // for ProcessSP, ModuleSP
+
+#include <functional> // for _Func_impl<>::_Mybase
+#include <memory> // for shared_ptr
+#include <vector> // for vector
+
+#include <stdio.h> // for snprintf, size_t
+#include <string.h> // for strlen
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResult.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResult.cpp
index f78574e..1023696 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResult.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResult.cpp
@@ -9,22 +9,19 @@
#include "lldb/Core/ValueObjectConstResult.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ValueObjectChild.h"
-#include "lldb/Core/ValueObjectConstResultChild.h"
+#include "lldb/Core/Scalar.h" // for Scalar
#include "lldb/Core/ValueObjectDynamicValue.h"
-#include "lldb/Core/ValueObjectList.h"
-
#include "lldb/Symbol/CompilerType.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Symbol/Type.h"
-#include "lldb/Symbol/Variable.h"
-
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h" // for ExecutionContextScope
#include "lldb/Target/Process.h"
-#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBuffer.h" // for DataBuffer
+#include "lldb/Utility/DataBufferHeap.h" // for DataBufferHeap
+#include "lldb/Utility/DataExtractor.h"
+
+namespace lldb_private {
+class Module;
+}
using namespace lldb;
using namespace lldb_private;
@@ -166,12 +163,12 @@ ValueObjectConstResult::ValueObjectConstResult(
}
ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
- const Error &error) {
+ const Status &error) {
return (new ValueObjectConstResult(exe_scope, error))->GetSP();
}
ValueObjectConstResult::ValueObjectConstResult(ExecutionContextScope *exe_scope,
- const Error &error)
+ const Status &error)
: ValueObject(exe_scope), m_type_name(), m_byte_size(0), m_impl(this) {
m_error = error;
SetIsConstant();
@@ -237,7 +234,7 @@ bool ValueObjectConstResult::IsInScope() {
return true;
}
-lldb::ValueObjectSP ValueObjectConstResult::Dereference(Error &error) {
+lldb::ValueObjectSP ValueObjectConstResult::Dereference(Status &error) {
return m_impl.Dereference(error);
}
@@ -248,7 +245,7 @@ lldb::ValueObjectSP ValueObjectConstResult::GetSyntheticChildAtOffset(
name_const_str);
}
-lldb::ValueObjectSP ValueObjectConstResult::AddressOf(Error &error) {
+lldb::ValueObjectSP ValueObjectConstResult::AddressOf(Status &error) {
return m_impl.AddressOf(error);
}
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultCast.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultCast.cpp
index 3245146..c040432 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultCast.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultCast.cpp
@@ -9,10 +9,15 @@
#include "lldb/Core/ValueObjectConstResultCast.h"
-#include "lldb/Core/ValueObjectConstResult.h"
-#include "lldb/Core/ValueObjectList.h"
-
-#include "lldb/Symbol/ClangASTContext.h"
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class ValueObject;
+}
using namespace lldb_private;
@@ -25,7 +30,7 @@ ValueObjectConstResultCast::ValueObjectConstResultCast(
ValueObjectConstResultCast::~ValueObjectConstResultCast() {}
-lldb::ValueObjectSP ValueObjectConstResultCast::Dereference(Error &error) {
+lldb::ValueObjectSP ValueObjectConstResultCast::Dereference(Status &error) {
return m_impl.Dereference(error);
}
@@ -36,7 +41,7 @@ lldb::ValueObjectSP ValueObjectConstResultCast::GetSyntheticChildAtOffset(
name_const_str);
}
-lldb::ValueObjectSP ValueObjectConstResultCast::AddressOf(Error &error) {
+lldb::ValueObjectSP ValueObjectConstResultCast::AddressOf(Status &error) {
return m_impl.AddressOf(error);
}
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultChild.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultChild.cpp
index c4c9c63..3e9f876 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultChild.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultChild.cpp
@@ -1,5 +1,4 @@
-//===-- ValueObjectConstResultChild.cpp ------------------------------*- C++
-//-*-===//
+//===-- ValueObjectConstResultChild.cpp --------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,10 +9,16 @@
#include "lldb/Core/ValueObjectConstResultChild.h"
-#include "lldb/Core/ValueObjectConstResult.h"
-#include "lldb/Core/ValueObjectList.h"
-
-#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/lldb-private-enumerations.h" // for AddressType::eAddressType
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Status;
+}
+namespace lldb_private {
+class ValueObject;
+}
using namespace lldb_private;
@@ -32,7 +37,7 @@ ValueObjectConstResultChild::ValueObjectConstResultChild(
ValueObjectConstResultChild::~ValueObjectConstResultChild() {}
-lldb::ValueObjectSP ValueObjectConstResultChild::Dereference(Error &error) {
+lldb::ValueObjectSP ValueObjectConstResultChild::Dereference(Status &error) {
return m_impl.Dereference(error);
}
@@ -43,7 +48,7 @@ lldb::ValueObjectSP ValueObjectConstResultChild::GetSyntheticChildAtOffset(
name_const_str);
}
-lldb::ValueObjectSP ValueObjectConstResultChild::AddressOf(Error &error) {
+lldb::ValueObjectSP ValueObjectConstResultChild::AddressOf(Status &error) {
return m_impl.AddressOf(error);
}
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultImpl.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultImpl.cpp
index 0e4f73f..714634e 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultImpl.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectConstResultImpl.cpp
@@ -1,5 +1,4 @@
-//===-- ValueObjectConstResultImpl.cpp ---------------------------*- C++
-//-*-===//
+//===-- ValueObjectConstResultImpl.cpp ---------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,24 +9,26 @@
#include "lldb/Core/ValueObjectConstResultImpl.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/Scalar.h" // for Scalar
+#include "lldb/Core/Value.h" // for Value, Value::Val...
+#include "lldb/Core/ValueObject.h" // for ValueObject
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectConstResultCast.h"
#include "lldb/Core/ValueObjectConstResultChild.h"
-#include "lldb/Core/ValueObjectList.h"
-#include "lldb/Core/ValueObjectMemory.h"
-
#include "lldb/Symbol/CompilerType.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Symbol/Type.h"
-#include "lldb/Symbol/Variable.h"
-
#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h" // for DataBufferHeap
+#include "lldb/Utility/Endian.h" // for InlHostByteOrder
+#include "lldb/Utility/SharingPtr.h" // for SharingPtr
+
+#include <string> // for string
+
+namespace lldb_private {
+class DataExtractor;
+}
+namespace lldb_private {
+class Status;
+}
using namespace lldb;
using namespace lldb_private;
@@ -38,7 +39,7 @@ ValueObjectConstResultImpl::ValueObjectConstResultImpl(
m_live_address_type(eAddressTypeLoad), m_load_addr_backend(),
m_address_of_backend() {}
-lldb::ValueObjectSP ValueObjectConstResultImpl::Dereference(Error &error) {
+lldb::ValueObjectSP ValueObjectConstResultImpl::Dereference(Status &error) {
if (m_impl_backend == NULL)
return lldb::ValueObjectSP();
@@ -107,7 +108,7 @@ lldb::ValueObjectSP ValueObjectConstResultImpl::GetSyntheticChildAtOffset(
offset, type, can_create, name_const_str);
}
-lldb::ValueObjectSP ValueObjectConstResultImpl::AddressOf(Error &error) {
+lldb::ValueObjectSP ValueObjectConstResultImpl::AddressOf(Status &error) {
if (m_address_of_backend.get() != NULL)
return m_address_of_backend;
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectDynamicValue.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectDynamicValue.cpp
index 1fb32d4..bb39caa 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectDynamicValue.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectDynamicValue.cpp
@@ -1,5 +1,4 @@
-//===-- ValueObjectDynamicValue.cpp ---------------------------------*- C++
-//-*-===//
+//===-- ValueObjectDynamicValue.cpp ------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,28 +9,26 @@
#include "lldb/Core/ValueObjectDynamicValue.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Module.h"
+#include "lldb/Core/ArchSpec.h" // for ArchSpec
+#include "lldb/Core/Scalar.h" // for Scalar, operator!=
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObject.h"
-#include "lldb/Core/ValueObjectList.h"
-
#include "lldb/Symbol/CompilerType.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Type.h"
-#include "lldb/Symbol/Variable.h"
-
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/Process.h"
-#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
-#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h" // for DataExtractor
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-types.h" // for addr_t, offset_t
+
+#include <string.h> // for strcmp, size_t
+namespace lldb_private {
+class Declaration;
+}
using namespace lldb_private;
@@ -278,7 +275,7 @@ bool ValueObjectDynamicValue::UpdateValue() {
bool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); }
bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str,
- Error &error) {
+ Status &error) {
if (!UpdateValueIfNeeded(false)) {
error.SetErrorString("unable to read value");
return false;
@@ -313,7 +310,7 @@ bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str,
return ret_val;
}
-bool ValueObjectDynamicValue::SetData(DataExtractor &data, Error &error) {
+bool ValueObjectDynamicValue::SetData(DataExtractor &data, Status &error) {
if (!UpdateValueIfNeeded(false)) {
error.SetErrorString("unable to read value");
return false;
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectList.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectList.cpp
index 7eae497..00aee79 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectList.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectList.cpp
@@ -9,15 +9,11 @@
#include "lldb/Core/ValueObjectList.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/ValueObjectChild.h"
-#include "lldb/Core/ValueObjectRegister.h"
-#include "lldb/Core/ValueObjectVariable.h"
-#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/Process.h"
+#include "lldb/Core/ValueObject.h" // for ValueObject
+#include "lldb/Utility/ConstString.h" // for ConstString
+#include "lldb/Utility/SharingPtr.h" // for SharingPtr
+
+#include <utility> // for back_insert_iterator, back_ins...
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectMemory.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectMemory.cpp
index 18f3c94..7137511 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectMemory.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectMemory.cpp
@@ -9,25 +9,24 @@
#include "lldb/Core/ValueObjectMemory.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Module.h"
+#include "lldb/Core/ArchSpec.h" // for ArchSpec
+#include "lldb/Core/Scalar.h" // for Scalar, operator!=
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObject.h"
-#include "lldb/Core/ValueObjectList.h"
-
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Type.h"
-#include "lldb/Symbol/Variable.h"
-
#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
-#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h" // for DataExtractor
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-types.h" // for addr_t
+#include "llvm/Support/ErrorHandling.h" // for llvm_unreachable
+
+#include <assert.h> // for assert
+#include <memory> // for shared_ptr
+
+namespace lldb_private {
+class ExecutionContextScope;
+}
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectRegister.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectRegister.cpp
index 80e00e4..05022d3 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectRegister.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectRegister.cpp
@@ -9,19 +9,28 @@
#include "lldb/Core/ValueObjectRegister.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/Module.h"
-#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Core/Scalar.h" // for Scalar
+#include "lldb/Core/Value.h" // for Value, Value::ContextType:...
#include "lldb/Symbol/CompilerType.h"
-#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/TypeSystem.h" // for TypeSystem
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h" // for StackFrame
#include "lldb/Target/Target.h"
-#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h" // for DataExtractor
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/Utility/Stream.h" // for Stream
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <assert.h> // for assert
+#include <memory> // for shared_ptr
+
+namespace lldb_private {
+class ExecutionContextScope;
+}
using namespace lldb;
using namespace lldb_private;
@@ -309,7 +318,7 @@ bool ValueObjectRegister::UpdateValue() {
}
bool ValueObjectRegister::SetValueFromCString(const char *value_str,
- Error &error) {
+ Status &error) {
// The new value will be in the m_data. Copy that into our register value.
error =
m_reg_value.SetValueFromString(&m_reg_info, llvm::StringRef(value_str));
@@ -323,7 +332,7 @@ bool ValueObjectRegister::SetValueFromCString(const char *value_str,
return false;
}
-bool ValueObjectRegister::SetData(DataExtractor &data, Error &error) {
+bool ValueObjectRegister::SetData(DataExtractor &data, Status &error) {
error = m_reg_value.SetValueFromData(&m_reg_info, data, 0, false);
if (error.Success()) {
if (m_reg_ctx_sp->WriteRegister(&m_reg_info, m_reg_value)) {
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectSyntheticFilter.cpp
index 592f1ea..87310c4 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectSyntheticFilter.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectSyntheticFilter.cpp
@@ -7,15 +7,22 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/ValueObjectSyntheticFilter.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Core/Value.h" // for Value
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Target/ExecutionContext.h" // for ExecutionContext
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h" // for GetLogIfAllCategoriesSet
+#include "lldb/Utility/SharingPtr.h" // for SharingPtr
+#include "lldb/Utility/Status.h" // for Status
+
+#include "llvm/ADT/STLExtras.h"
+
+namespace lldb_private {
+class Declaration;
+}
using namespace lldb_private;
@@ -124,7 +131,7 @@ lldb::ValueType ValueObjectSynthetic::GetValueType() const {
void ValueObjectSynthetic::CreateSynthFilter() {
m_synth_filter_ap = (m_synth_sp->GetFrontEnd(*m_parent));
if (!m_synth_filter_ap.get())
- m_synth_filter_ap.reset(new DummySyntheticFrontEnd(*m_parent));
+ m_synth_filter_ap = llvm::make_unique<DummySyntheticFrontEnd>(*m_parent);
}
bool ValueObjectSynthetic::UpdateValue() {
@@ -317,7 +324,7 @@ bool ValueObjectSynthetic::CanProvideValue() {
}
bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
- Error &error) {
+ Status &error) {
return m_parent->SetValueFromCString(value_str, error);
}
diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectVariable.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectVariable.cpp
index f8eedc3..9b9e51a 100644
--- a/contrib/llvm/tools/lldb/source/Core/ValueObjectVariable.cpp
+++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectVariable.cpp
@@ -9,28 +9,44 @@
#include "lldb/Core/ValueObjectVariable.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
+#include "lldb/Core/Address.h" // for Address
+#include "lldb/Core/AddressRange.h" // for AddressRange
+#include "lldb/Core/ArchSpec.h" // for ArchSpec
#include "lldb/Core/Module.h"
#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h" // for Scalar, operator!=
#include "lldb/Core/Value.h"
-#include "lldb/Core/ValueObjectList.h"
-
+#include "lldb/Expression/DWARFExpression.h" // for DWARFExpression
+#include "lldb/Symbol/Declaration.h" // for Declaration
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolContextScope.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/Variable.h"
-
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
-#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h" // for DataExtractor
+#include "lldb/Utility/Status.h" // for Status
+#include "lldb/lldb-private-enumerations.h" // for AddressType::eAddressTy...
+#include "lldb/lldb-types.h" // for addr_t
+
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <assert.h> // for assert
+#include <memory> // for shared_ptr
+namespace lldb_private {
+class ExecutionContextScope;
+}
+namespace lldb_private {
+class StackFrame;
+}
+namespace lldb_private {
+struct RegisterInfo;
+}
using namespace lldb_private;
lldb::ValueObjectSP
@@ -328,7 +344,7 @@ const char *ValueObjectVariable::GetLocationAsCString() {
}
bool ValueObjectVariable::SetValueFromCString(const char *value_str,
- Error &error) {
+ Status &error) {
if (!UpdateValueIfNeeded()) {
error.SetErrorString("unable to update value before writing");
return false;
@@ -357,7 +373,7 @@ bool ValueObjectVariable::SetValueFromCString(const char *value_str,
return ValueObject::SetValueFromCString(value_str, error);
}
-bool ValueObjectVariable::SetData(DataExtractor &data, Error &error) {
+bool ValueObjectVariable::SetData(DataExtractor &data, Status &error) {
if (!UpdateValueIfNeeded()) {
error.SetErrorString("unable to update value before writing");
return false;
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/CXXFunctionPointer.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/CXXFunctionPointer.cpp
index 41e9d4b..fad67a9 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/CXXFunctionPointer.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/CXXFunctionPointer.cpp
@@ -9,10 +9,10 @@
#include "lldb/DataFormatters/CXXFunctionPointer.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Stream.h"
#include <string>
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/FormatManager.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/FormatManager.cpp
index 6e5fdf9..7619b6f 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/FormatManager.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/FormatManager.cpp
@@ -17,11 +17,11 @@
// Project includes
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/LanguageCategory.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Language.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -660,11 +660,9 @@ FormatManager::GetFormat(ValueObject &valobj,
if (log) {
log->Printf(
"[FormatManager::GetFormat] Cache search success. Returning.");
- if (log->GetDebug())
- log->Printf("[FormatManager::GetFormat] Cache hits: %" PRIu64
- " - Cache Misses: %" PRIu64,
- m_format_cache.GetCacheHits(),
- m_format_cache.GetCacheMisses());
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(),
+ m_format_cache.GetCacheMisses());
}
return retval;
}
@@ -705,10 +703,8 @@ FormatManager::GetFormat(ValueObject &valobj,
match_data.GetTypeForCache().AsCString("<invalid>"));
m_format_cache.SetFormat(match_data.GetTypeForCache(), retval);
}
- if (log && log->GetDebug())
- log->Printf("[FormatManager::GetFormat] Cache hits: %" PRIu64
- " - Cache Misses: %" PRIu64,
- m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
return retval;
}
@@ -742,11 +738,9 @@ FormatManager::GetSummaryFormat(ValueObject &valobj,
if (log) {
log->Printf("[FormatManager::GetSummaryFormat] Cache search success. "
"Returning.");
- if (log->GetDebug())
- log->Printf("[FormatManager::GetSummaryFormat] Cache hits: %" PRIu64
- " - Cache Misses: %" PRIu64,
- m_format_cache.GetCacheHits(),
- m_format_cache.GetCacheMisses());
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(),
+ m_format_cache.GetCacheMisses());
}
return retval;
}
@@ -787,10 +781,8 @@ FormatManager::GetSummaryFormat(ValueObject &valobj,
match_data.GetTypeForCache().AsCString("<invalid>"));
m_format_cache.SetSummary(match_data.GetTypeForCache(), retval);
}
- if (log && log->GetDebug())
- log->Printf("[FormatManager::GetSummaryFormat] Cache hits: %" PRIu64
- " - Cache Misses: %" PRIu64,
- m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
return retval;
}
@@ -825,11 +817,9 @@ FormatManager::GetSyntheticChildren(ValueObject &valobj,
if (log) {
log->Printf("[FormatManager::GetSyntheticChildren] Cache search "
"success. Returning.");
- if (log->GetDebug())
- log->Printf(
- "[FormatManager::GetSyntheticChildren] Cache hits: %" PRIu64
- " - Cache Misses: %" PRIu64,
- m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(),
+ m_format_cache.GetCacheMisses());
}
return retval;
}
@@ -871,10 +861,8 @@ FormatManager::GetSyntheticChildren(ValueObject &valobj,
match_data.GetTypeForCache().AsCString("<invalid>"));
m_format_cache.SetSynthetic(match_data.GetTypeForCache(), retval);
}
- if (log && log->GetDebug())
- log->Printf("[FormatManager::GetSyntheticChildren] Cache hits: %" PRIu64
- " - Cache Misses: %" PRIu64,
- m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
return retval;
}
#endif
@@ -895,11 +883,9 @@ FormatManager::GetValidator(ValueObject &valobj,
if (log) {
log->Printf(
"[FormatManager::GetValidator] Cache search success. Returning.");
- if (log->GetDebug())
- log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64
- " - Cache Misses: %" PRIu64,
- m_format_cache.GetCacheHits(),
- m_format_cache.GetCacheMisses());
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(),
+ m_format_cache.GetCacheMisses());
}
return retval;
}
@@ -940,10 +926,8 @@ FormatManager::GetValidator(ValueObject &valobj,
match_data.GetTypeForCache().AsCString("<invalid>"));
m_format_cache.SetValidator(match_data.GetTypeForCache(), retval);
}
- if (log && log->GetDebug())
- log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64
- " - Cache Misses: %" PRIu64,
- m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
return retval;
}
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/FormattersHelpers.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/FormattersHelpers.cpp
index 68802b9..460a496 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/FormattersHelpers.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/FormattersHelpers.cpp
@@ -17,11 +17,11 @@
// Project includes
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/RegularExpression.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp
index 4021bd5..84143a5 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp
@@ -11,11 +11,11 @@
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Status.h"
#include "llvm/Support/ConvertUTF.h"
@@ -417,7 +417,7 @@ bool StringPrinter::ReadStringAndDumpToStream<
StringPrinter::StringElementType::ASCII>(
const ReadStringAndDumpToStreamOptions &options) {
assert(options.GetStream() && "need a Stream to print the string to");
- Error my_error;
+ Status my_error;
ProcessSP process_sp(options.GetProcessSP());
@@ -561,7 +561,7 @@ static bool ReadUTFBufferAndDumpToStream(
if (!buffer_sp->GetBytes())
return false;
- Error error;
+ Status error;
char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes());
if (needs_zero_terminator)
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategory.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategory.cpp
index db3372c..184a8c9 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategory.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategory.cpp
@@ -36,23 +36,8 @@ TypeCategoryImpl::TypeCategoryImpl(
static bool IsApplicable(lldb::LanguageType category_lang,
lldb::LanguageType valobj_lang) {
switch (category_lang) {
- // these are not languages that LLDB would ordinarily deal with
- // only allow an exact equality here, since we really don't know
- // any better
- case eLanguageTypeAda83:
- case eLanguageTypeCobol74:
- case eLanguageTypeCobol85:
- case eLanguageTypeFortran77:
- case eLanguageTypeFortran90:
- case eLanguageTypePascal83:
- case eLanguageTypeModula2:
- case eLanguageTypeJava:
- case eLanguageTypeAda95:
- case eLanguageTypeFortran95:
- case eLanguageTypePLI:
- case eLanguageTypeUPC:
- case eLanguageTypeD:
- case eLanguageTypePython:
+ // Unless we know better, allow only exact equality.
+ default:
return category_lang == valobj_lang;
// the C family, we consider it as one
@@ -80,7 +65,7 @@ static bool IsApplicable(lldb::LanguageType category_lang,
valobj_lang == eLanguageTypeC_plus_plus ||
valobj_lang == eLanguageTypeObjC;
- default:
+ // Categories with unspecified language match everything.
case eLanguageTypeUnknown:
return true;
}
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategoryMap.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategoryMap.cpp
index cc85288..d2da672 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategoryMap.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategoryMap.cpp
@@ -10,8 +10,8 @@
#include "lldb/DataFormatters/TypeCategoryMap.h"
-#include "lldb/Core/Log.h"
#include "lldb/DataFormatters/FormatClasses.h"
+#include "lldb/Utility/Log.h"
// C Includes
// C++ Includes
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/TypeFormat.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/TypeFormat.cpp
index 8bd369b..333fe91 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/TypeFormat.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/TypeFormat.cpp
@@ -19,13 +19,15 @@
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-public.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -54,15 +56,15 @@ bool TypeFormatImpl_Format::FormatObject(ValueObject *valobj,
if (context_type == Value::eContextTypeRegisterInfo) {
const RegisterInfo *reg_info = value.GetRegisterInfo();
if (reg_info) {
- Error error;
+ Status error;
valobj->GetData(data, error);
if (error.Fail())
return false;
StreamString reg_sstr;
- data.Dump(&reg_sstr, 0, GetFormat(), reg_info->byte_size, 1, UINT32_MAX,
- LLDB_INVALID_ADDRESS, 0, 0,
- exe_ctx.GetBestExecutionContextScope());
+ DumpDataExtractor(data, &reg_sstr, 0, GetFormat(), reg_info->byte_size,
+ 1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0,
+ exe_ctx.GetBestExecutionContextScope());
dest = reg_sstr.GetString();
}
} else {
@@ -80,7 +82,7 @@ bool TypeFormatImpl_Format::FormatObject(ValueObject *valobj,
TargetSP target_sp(valobj->GetTargetSP());
if (target_sp) {
size_t max_len = target_sp->GetMaximumSizeOfStringSummary();
- Error error;
+ Status error;
DataBufferSP buffer_sp(new DataBufferHeap(max_len + 1, 0));
Address address(valobj->GetPointerValue());
if (target_sp->ReadCStringFromMemory(
@@ -90,7 +92,7 @@ bool TypeFormatImpl_Format::FormatObject(ValueObject *valobj,
}
}
} else {
- Error error;
+ Status error;
valobj->GetData(data, error);
if (error.Fail())
return false;
@@ -183,7 +185,7 @@ bool TypeFormatImpl_EnumType::FormatObject(ValueObject *valobj,
if (valobj_enum_type.IsValid() == false)
return false;
DataExtractor data;
- Error error;
+ Status error;
valobj->GetData(data, error);
if (error.Fail())
return false;
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/TypeSummary.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/TypeSummary.cpp
index 610d2fe..09a7ff8 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/TypeSummary.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/TypeSummary.cpp
@@ -20,13 +20,13 @@
#include "lldb/lldb-public.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/ValueObjectPrinter.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/TypeSynthetic.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/TypeSynthetic.cpp
index 0f7bd9a..28a51da 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/TypeSynthetic.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/TypeSynthetic.cpp
@@ -19,12 +19,12 @@
#include "lldb/lldb-public.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/TypeValidator.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/TypeValidator.cpp
index 2affd73..7a5b8d5 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/TypeValidator.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/TypeValidator.cpp
@@ -15,7 +15,7 @@
// Project includes
#include "lldb/DataFormatters/TypeValidator.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/ValueObjectPrinter.cpp
index d6efe78..863ff3a 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/ValueObjectPrinter.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/ValueObjectPrinter.cpp
@@ -13,12 +13,12 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -457,7 +457,12 @@ bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,
else
object_desc = GetDescriptionForDisplay();
if (object_desc && *object_desc) {
- m_stream->Printf("%s\n", object_desc);
+ // If the description already ends with a \n don't add another one.
+ size_t object_end = strlen(object_desc) - 1;
+ if (object_desc[object_end] == '\n')
+ m_stream->Printf("%s", object_desc);
+ else
+ m_stream->Printf("%s\n", object_desc);
return true;
} else if (value_printed == false && summary_printed == false)
return true;
@@ -468,32 +473,11 @@ bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,
return true;
}
-bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion(
- bool is_root, TypeSummaryImpl *entry, ValueObject *valobj,
- const std::string &summary) {
- switch (m_mode) {
- case Mode::Always:
- return (m_count > 0);
- case Mode::Never:
- return false;
- case Mode::Default:
- if (is_root)
- m_count = std::min<decltype(m_count)>(m_count, 1);
- return m_count > 0;
- case Mode::Formatters:
- if (!entry || entry->DoesPrintChildren(valobj) || summary.empty())
- return m_count > 0;
- return false;
- }
- return false;
-}
-
bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {
switch (m_mode) {
case Mode::Always:
case Mode::Default:
- case Mode::Formatters:
- return (m_count > 0);
+ return m_count > 0;
case Mode::Never:
return false;
}
@@ -546,8 +530,7 @@ bool ValueObjectPrinter::ShouldPrintChildren(
return true;
}
- return curr_ptr_depth.CanAllowExpansion(false, entry, m_valobj,
- m_summary);
+ return curr_ptr_depth.CanAllowExpansion();
}
return (!entry || entry->DoesPrintChildren(m_valobj) || m_summary.empty());
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/VectorType.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/VectorType.cpp
index 652bde7..4fb92ca 100644
--- a/contrib/llvm/tools/lldb/source/DataFormatters/VectorType.cpp
+++ b/contrib/llvm/tools/lldb/source/DataFormatters/VectorType.cpp
@@ -204,14 +204,12 @@ public:
if (idx >= CalculateNumChildren())
return lldb::ValueObjectSP();
auto offset = idx * m_child_type.GetByteSize(nullptr);
- ValueObjectSP child_sp(
- m_backend.GetSyntheticChildAtOffset(offset, m_child_type, true));
- if (!child_sp)
- return child_sp;
-
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- child_sp->SetName(ConstString(idx_name.GetString()));
+ ValueObjectSP child_sp(m_backend.GetSyntheticChildAtOffset(
+ offset, m_child_type, true, ConstString(idx_name.GetString())));
+ if (!child_sp)
+ return child_sp;
child_sp->SetFormat(m_item_format);
diff --git a/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp b/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp
index c8b0b59..592a30c 100644
--- a/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp
@@ -15,20 +15,20 @@
// C++ Includes
#include <vector>
-#include "lldb/Core/DataEncoder.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/VMRange.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/VMRange.h"
#include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h"
#include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
+#include "lldb/Utility/Endian.h"
#include "lldb/Symbol/Function.h"
@@ -655,7 +655,7 @@ void DWARFExpression::GetDescription(Stream *s, lldb::DescriptionLevel level,
static bool ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
lldb::RegisterKind reg_kind,
- uint32_t reg_num, Error *error_ptr,
+ uint32_t reg_num, Status *error_ptr,
Value &value) {
if (reg_ctx == NULL) {
if (error_ptr)
@@ -1250,7 +1250,7 @@ bool DWARFExpression::Evaluate(ExecutionContextScope *exe_scope,
lldb::addr_t loclist_base_load_addr,
const Value *initial_value_ptr,
const Value *object_address_ptr, Value &result,
- Error *error_ptr) const {
+ Status *error_ptr) const {
ExecutionContext exe_ctx(exe_scope);
return Evaluate(&exe_ctx, expr_locals, decl_map, nullptr,
loclist_base_load_addr, initial_value_ptr, object_address_ptr,
@@ -1261,7 +1261,7 @@ bool DWARFExpression::Evaluate(
ExecutionContext *exe_ctx, ClangExpressionVariableList *expr_locals,
ClangExpressionDeclMap *decl_map, RegisterContext *reg_ctx,
lldb::addr_t loclist_base_load_addr, const Value *initial_value_ptr,
- const Value *object_address_ptr, Value &result, Error *error_ptr) const {
+ const Value *object_address_ptr, Value &result, Status *error_ptr) const {
ModuleSP module_sp = m_module_wp.lock();
if (IsLocationList()) {
@@ -1333,7 +1333,7 @@ bool DWARFExpression::Evaluate(
DWARFCompileUnit *dwarf_cu, const lldb::offset_t opcodes_offset,
const lldb::offset_t opcodes_length, const lldb::RegisterKind reg_kind,
const Value *initial_value_ptr, const Value *object_address_ptr,
- Value &result, Error *error_ptr) {
+ Value &result, Status *error_ptr) {
if (opcodes_length == 0) {
if (error_ptr)
@@ -1467,7 +1467,7 @@ bool DWARFExpression::Evaluate(
if (process) {
lldb::addr_t pointer_addr =
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
- Error error;
+ Status error;
lldb::addr_t pointer_value =
process->ReadPointerFromMemory(pointer_addr, error);
if (pointer_value != LLDB_INVALID_ADDRESS) {
@@ -1572,7 +1572,7 @@ bool DWARFExpression::Evaluate(
lldb::addr_t pointer_addr =
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
uint8_t addr_bytes[sizeof(lldb::addr_t)];
- Error error;
+ Status error;
if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) ==
size) {
DataExtractor addr_data(addr_bytes, sizeof(addr_bytes),
@@ -2568,7 +2568,7 @@ bool DWARFExpression::Evaluate(
::memset(curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
pieces.AppendDataToHostBuffer(curr_piece);
} else {
- Error error;
+ Status error;
// Extract the current piece into "curr_piece"
Value curr_piece_source_value(stack.back());
stack.pop_back();
diff --git a/contrib/llvm/tools/lldb/source/Expression/DiagnosticManager.cpp b/contrib/llvm/tools/lldb/source/Expression/DiagnosticManager.cpp
index ad06600..ae20feb 100644
--- a/contrib/llvm/tools/lldb/source/Expression/DiagnosticManager.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/DiagnosticManager.cpp
@@ -11,8 +11,8 @@
#include "llvm/Support/ErrorHandling.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
@@ -79,3 +79,12 @@ size_t DiagnosticManager::PutString(DiagnosticSeverity severity,
AddDiagnostic(str, severity, eDiagnosticOriginLLDB);
return str.size();
}
+
+void DiagnosticManager::CopyDiagnostics(DiagnosticManager &otherDiagnostics) {
+ for (const DiagnosticList::value_type &other_diagnostic:
+ otherDiagnostics.Diagnostics()) {
+ AddDiagnostic(
+ other_diagnostic->GetMessage(), other_diagnostic->GetSeverity(),
+ other_diagnostic->getKind(), other_diagnostic->GetCompilerID());
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/ExpressionSourceCode.cpp b/contrib/llvm/tools/lldb/source/Expression/ExpressionSourceCode.cpp
index 90a9ff2..d60a128 100644
--- a/contrib/llvm/tools/lldb/source/Expression/ExpressionSourceCode.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/ExpressionSourceCode.cpp
@@ -11,7 +11,6 @@
#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/DebugMacros.h"
@@ -22,6 +21,7 @@
#include "lldb/Target/Platform.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Expression/ExpressionVariable.cpp b/contrib/llvm/tools/lldb/source/Expression/ExpressionVariable.cpp
index 00e6896..a971800 100644
--- a/contrib/llvm/tools/lldb/source/Expression/ExpressionVariable.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/ExpressionVariable.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "lldb/Expression/ExpressionVariable.h"
-#include "lldb/Core/Log.h"
#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Utility/Log.h"
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Expression/FunctionCaller.cpp b/contrib/llvm/tools/lldb/source/Expression/FunctionCaller.cpp
index f218ccb..6f60f8b 100644
--- a/contrib/llvm/tools/lldb/source/Expression/FunctionCaller.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/FunctionCaller.cpp
@@ -13,8 +13,6 @@
// Project includes
#include "lldb/Expression/FunctionCaller.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/State.h"
#include "lldb/Core/ValueObject.h"
@@ -31,6 +29,8 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
using namespace lldb_private;
@@ -86,7 +86,7 @@ bool FunctionCaller::WriteFunctionWrapper(
bool can_interpret = false; // should stay that way
- Error jit_error(m_parser->PrepareForExecution(
+ Status jit_error(m_parser->PrepareForExecution(
m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
can_interpret, eExecutionPolicyAlways));
@@ -135,7 +135,7 @@ bool FunctionCaller::WriteFunctionArguments(
return false;
}
- Error error;
+ Status error;
lldb::ExpressionResults return_value = lldb::eExpressionSetupError;
Process *process = exe_ctx.GetProcessPtr();
@@ -172,7 +172,7 @@ bool FunctionCaller::WriteFunctionArguments(
// FIXME: We will need to extend this for Variadic functions.
- Error value_error;
+ Status value_error;
size_t num_args = arg_values.GetSize();
if (num_args != m_arg_values.GetSize()) {
@@ -289,7 +289,7 @@ bool FunctionCaller::FetchFunctionResults(ExecutionContext &exe_ctx,
if (process != jit_process_sp.get())
return false;
- Error error;
+ Status error;
ret_value.GetScalar() = process->ReadUnsignedIntegerFromMemory(
args_addr + m_return_offset, m_return_size, 0, error);
diff --git a/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp b/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp
index b337ea2..0c8cba2 100644
--- a/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp
@@ -21,14 +21,14 @@
// Project includes
#include "lldb/Expression/IRDynamicChecks.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Log.h"
#include "lldb/Expression/UtilityFunction.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
using namespace llvm;
using namespace lldb_private;
@@ -51,7 +51,7 @@ DynamicCheckerFunctions::~DynamicCheckerFunctions() = default;
bool DynamicCheckerFunctions::Install(DiagnosticManager &diagnostic_manager,
ExecutionContext &exe_ctx) {
- Error error;
+ Status error;
m_valid_pointer_check.reset(
exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(
g_valid_pointer_check_text, lldb::eLanguageTypeC,
diff --git a/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp b/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp
index f18d96b..e31483f 100644
--- a/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp
@@ -15,11 +15,8 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Expression/IRExecutionUnit.h"
@@ -30,7 +27,10 @@
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
#include "lldb/../../source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
@@ -50,7 +50,7 @@ IRExecutionUnit::IRExecutionUnit(std::unique_ptr<llvm::LLVMContext> &context_ap,
m_reported_allocations(false) {}
lldb::addr_t IRExecutionUnit::WriteNow(const uint8_t *bytes, size_t size,
- Error &error) {
+ Status &error) {
const bool zero_memory = false;
lldb::addr_t allocation_process_addr =
Malloc(size, 8, lldb::ePermissionsWritable | lldb::ePermissionsReadable,
@@ -62,7 +62,7 @@ lldb::addr_t IRExecutionUnit::WriteNow(const uint8_t *bytes, size_t size,
WriteMemory(allocation_process_addr, bytes, size, error);
if (!error.Success()) {
- Error err;
+ Status err;
Free(allocation_process_addr, err);
return LLDB_INVALID_ADDRESS;
@@ -71,7 +71,7 @@ lldb::addr_t IRExecutionUnit::WriteNow(const uint8_t *bytes, size_t size,
if (Log *log =
lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
DataBufferHeap my_buffer(size, 0);
- Error err;
+ Status err;
ReadMemory(my_buffer.GetBytes(), allocation_process_addr, size, err);
if (err.Success()) {
@@ -90,18 +90,18 @@ void IRExecutionUnit::FreeNow(lldb::addr_t allocation) {
if (allocation == LLDB_INVALID_ADDRESS)
return;
- Error err;
+ Status err;
Free(allocation, err);
}
-Error IRExecutionUnit::DisassembleFunction(Stream &stream,
- lldb::ProcessSP &process_wp) {
+Status IRExecutionUnit::DisassembleFunction(Stream &stream,
+ lldb::ProcessSP &process_wp) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
ExecutionContext exe_ctx(process_wp);
- Error ret;
+ Status ret;
ret.Clear();
@@ -152,7 +152,7 @@ Error IRExecutionUnit::DisassembleFunction(Stream &stream,
lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second, 0));
Process *process = exe_ctx.GetProcessPtr();
- Error err;
+ Status err;
process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(),
buffer_sp->GetByteSize(), err);
@@ -203,7 +203,7 @@ Error IRExecutionUnit::DisassembleFunction(Stream &stream,
static void ReportInlineAsmError(const llvm::SMDiagnostic &diagnostic,
void *Context, unsigned LocCookie) {
- Error *err = static_cast<Error *>(Context);
+ Status *err = static_cast<Status *>(Context);
if (err && err->Success()) {
err->SetErrorToGenericError();
@@ -216,7 +216,7 @@ void IRExecutionUnit::ReportSymbolLookupError(const ConstString &name) {
m_failed_lookups.push_back(name);
}
-void IRExecutionUnit::GetRunnableInfo(Error &error, lldb::addr_t &func_addr,
+void IRExecutionUnit::GetRunnableInfo(Status &error, lldb::addr_t &func_addr,
lldb::addr_t &func_end) {
lldb::ProcessSP process_sp(GetProcessWP().lock());
@@ -452,7 +452,7 @@ void IRExecutionUnit::GetRunnableInfo(Error &error, lldb::addr_t &func_addr,
StreamString disassembly_stream;
- Error err = DisassembleFunction(disassembly_stream, process_sp);
+ Status err = DisassembleFunction(disassembly_stream, process_sp);
if (!err.Success()) {
log->Printf("Couldn't disassemble function : %s",
@@ -467,7 +467,7 @@ void IRExecutionUnit::GetRunnableInfo(Error &error, lldb::addr_t &func_addr,
record.dump(log);
DataBufferHeap my_buffer(record.m_size, 0);
- Error err;
+ Status err;
ReadMemory(my_buffer.GetBytes(), record.m_process_address,
record.m_size, err);
@@ -643,7 +643,7 @@ uint8_t *IRExecutionUnit::MemoryManager::allocateCodeSection(
}
if (m_parent.m_reported_allocations) {
- Error err;
+ Status err;
lldb::ProcessSP process_sp =
m_parent.GetBestExecutionContextScope()->CalculateProcess();
@@ -675,7 +675,7 @@ uint8_t *IRExecutionUnit::MemoryManager::allocateDataSection(
}
if (m_parent.m_reported_allocations) {
- Error err;
+ Status err;
lldb::ProcessSP process_sp =
m_parent.GetBestExecutionContextScope()->CalculateProcess();
@@ -1104,7 +1104,7 @@ IRExecutionUnit::GetRemoteRangeForLocal(lldb::addr_t local_address) {
}
bool IRExecutionUnit::CommitOneAllocation(lldb::ProcessSP &process_sp,
- Error &error,
+ Status &error,
AllocationRecord &record) {
if (record.m_process_address != LLDB_INVALID_ADDRESS) {
return true;
@@ -1145,7 +1145,7 @@ bool IRExecutionUnit::CommitOneAllocation(lldb::ProcessSP &process_sp,
bool IRExecutionUnit::CommitAllocations(lldb::ProcessSP &process_sp) {
bool ret = true;
- lldb_private::Error err;
+ lldb_private::Status err;
for (AllocationRecord &record : m_records) {
ret = CommitOneAllocation(process_sp, err, record);
@@ -1189,7 +1189,7 @@ bool IRExecutionUnit::WriteData(lldb::ProcessSP &process_sp) {
bool wrote_something = false;
for (AllocationRecord &record : m_records) {
if (record.m_process_address != LLDB_INVALID_ADDRESS) {
- lldb_private::Error err;
+ lldb_private::Status err;
WriteMemory(record.m_process_address, (uint8_t *)record.m_host_address,
record.m_size, err);
if (err.Success())
diff --git a/contrib/llvm/tools/lldb/source/Expression/IRInterpreter.cpp b/contrib/llvm/tools/lldb/source/Expression/IRInterpreter.cpp
index e570598..6b5e223 100644
--- a/contrib/llvm/tools/lldb/source/Expression/IRInterpreter.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/IRInterpreter.cpp
@@ -8,19 +8,19 @@
//===----------------------------------------------------------------------===//
#include "lldb/Expression/IRInterpreter.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRMemoryMap.h"
-#include "lldb/Host/Endian.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
@@ -189,7 +189,7 @@ public:
size_t value_size = m_target_data.getTypeStoreSize(value->getType());
lldb_private::DataExtractor value_extractor;
- lldb_private::Error extract_error;
+ lldb_private::Status extract_error;
m_execution_unit.GetMemoryData(value_extractor, process_address,
value_size, extract_error);
@@ -224,13 +224,13 @@ public:
lldb_private::DataBufferHeap buf(value_byte_size, 0);
- lldb_private::Error get_data_error;
+ lldb_private::Status get_data_error;
if (!cast_scalar.GetAsMemoryData(buf.GetBytes(), buf.GetByteSize(),
m_byte_order, get_data_error))
return false;
- lldb_private::Error write_error;
+ lldb_private::Status write_error;
m_execution_unit.WriteMemory(process_address, buf.GetBytes(),
buf.GetByteSize(), write_error);
@@ -322,12 +322,12 @@ public:
if (data_address == LLDB_INVALID_ADDRESS)
return false;
- lldb_private::Error write_error;
+ lldb_private::Status write_error;
m_execution_unit.WritePointerToMemory(data_address, address, write_error);
if (!write_error.Success()) {
- lldb_private::Error free_error;
+ lldb_private::Status free_error;
m_execution_unit.Free(data_address, free_error);
return false;
}
@@ -356,7 +356,7 @@ public:
size_t constant_size = m_target_data.getTypeStoreSize(constant->getType());
lldb_private::DataBufferHeap buf(constant_size, 0);
- lldb_private::Error get_data_error;
+ lldb_private::Status get_data_error;
lldb_private::Scalar resolved_scalar(
resolved_value.zextOrTrunc(llvm::NextPowerOf2(constant_size) * 8));
@@ -364,7 +364,7 @@ public:
m_byte_order, get_data_error))
return false;
- lldb_private::Error write_error;
+ lldb_private::Status write_error;
m_execution_unit.WriteMemory(process_address, buf.GetBytes(),
buf.GetByteSize(), write_error);
@@ -391,7 +391,7 @@ public:
}
lldb::addr_t Malloc(llvm::Type *type) {
- lldb_private::Error alloc_error;
+ lldb_private::Status alloc_error;
return Malloc(m_target_data.getTypeAllocSize(type),
m_target_data.getPrefTypeAlignment(type));
@@ -402,7 +402,7 @@ public:
lldb_private::DataBufferHeap buf(length, 0);
- lldb_private::Error read_error;
+ lldb_private::Status read_error;
m_execution_unit.ReadMemory(buf.GetBytes(), addr, length, read_error);
@@ -433,7 +433,7 @@ public:
if (const Constant *constant = dyn_cast<Constant>(value)) {
if (!ResolveConstant(data_address, constant)) {
- lldb_private::Error free_error;
+ lldb_private::Status free_error;
m_execution_unit.Free(data_address, free_error);
return LLDB_INVALID_ADDRESS;
}
@@ -499,7 +499,7 @@ static bool CanResolveConstant(llvm::Constant *constant) {
}
bool IRInterpreter::CanInterpret(llvm::Module &module, llvm::Function &function,
- lldb_private::Error &error,
+ lldb_private::Status &error,
const bool support_function_calls) {
lldb_private::Log *log(
lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
@@ -648,7 +648,7 @@ bool IRInterpreter::CanInterpret(llvm::Module &module, llvm::Function &function,
bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
llvm::ArrayRef<lldb::addr_t> args,
lldb_private::IRExecutionUnit &execution_unit,
- lldb_private::Error &error,
+ lldb_private::Status &error,
lldb::addr_t stack_frame_bottom,
lldb::addr_t stack_frame_top,
lldb_private::ExecutionContext &exe_ctx) {
@@ -867,7 +867,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
return false;
}
- lldb_private::Error write_error;
+ lldb_private::Status write_error;
execution_unit.WritePointerToMemory(P, R, write_error);
@@ -876,7 +876,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
log->Printf("Couldn't write the result pointer for an AllocaInst");
error.SetErrorToGenericError();
error.SetErrorString(memory_write_error);
- lldb_private::Error free_error;
+ lldb_private::Status free_error;
execution_unit.Free(P, free_error);
execution_unit.Free(R, free_error);
return false;
@@ -1349,7 +1349,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
}
lldb::addr_t R;
- lldb_private::Error read_error;
+ lldb_private::Status read_error;
execution_unit.ReadPointerFromMemory(&R, P, read_error);
if (!read_error.Success()) {
@@ -1374,7 +1374,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
return false;
}
- lldb_private::Error write_error;
+ lldb_private::Status write_error;
execution_unit.WriteMemory(D, buffer.GetBytes(), buffer.GetByteSize(),
write_error);
if (!write_error.Success()) {
@@ -1442,7 +1442,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
}
lldb::addr_t R;
- lldb_private::Error read_error;
+ lldb_private::Status read_error;
execution_unit.ReadPointerFromMemory(&R, P, read_error);
if (!read_error.Success()) {
@@ -1467,7 +1467,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
return false;
}
- lldb_private::Error write_error;
+ lldb_private::Status write_error;
execution_unit.WriteMemory(R, buffer.GetBytes(), buffer.GetByteSize(),
write_error);
if (!write_error.Success()) {
diff --git a/contrib/llvm/tools/lldb/source/Expression/IRMemoryMap.cpp b/contrib/llvm/tools/lldb/source/Expression/IRMemoryMap.cpp
index 7b9d266..817c75e 100644
--- a/contrib/llvm/tools/lldb/source/Expression/IRMemoryMap.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/IRMemoryMap.cpp
@@ -8,15 +8,15 @@
//===----------------------------------------------------------------------===//
#include "lldb/Expression/IRMemoryMap.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb_private;
@@ -31,7 +31,7 @@ IRMemoryMap::~IRMemoryMap() {
if (process_sp) {
AllocationMap::iterator iter;
- Error err;
+ Status err;
while ((iter = m_allocations.begin()) != m_allocations.end()) {
err.Clear();
@@ -66,7 +66,7 @@ lldb::addr_t IRMemoryMap::FindSpace(size_t size) {
return ret;
if (process_is_alive && process_sp->CanJIT()) {
- Error alloc_error;
+ Status alloc_error;
ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable |
lldb::ePermissionsWritable,
@@ -104,7 +104,7 @@ lldb::addr_t IRMemoryMap::FindSpace(size_t size) {
end_of_memory != 0xffffffffull);
MemoryRegionInfo region_info;
- Error err = process_sp->GetMemoryRegionInfo(ret, region_info);
+ Status err = process_sp->GetMemoryRegionInfo(ret, region_info);
if (err.Success()) {
while (true) {
if (region_info.GetReadable() != MemoryRegionInfo::OptionalBool::eNo ||
@@ -297,7 +297,7 @@ IRMemoryMap::Allocation::Allocation(lldb::addr_t process_alloc,
lldb::addr_t IRMemoryMap::Malloc(size_t size, uint8_t alignment,
uint32_t permissions, AllocationPolicy policy,
- bool zero_memory, Error &error) {
+ bool zero_memory, Status &error) {
lldb_private::Log *log(
lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
error.Clear();
@@ -397,7 +397,7 @@ lldb::addr_t IRMemoryMap::Malloc(size_t size, uint8_t alignment,
permissions, alignment, policy);
if (zero_memory) {
- Error write_error;
+ Status write_error;
std::vector<uint8_t> zero_buf(size, 0);
WriteMemory(aligned_address, zero_buf.data(), size, write_error);
}
@@ -429,7 +429,7 @@ lldb::addr_t IRMemoryMap::Malloc(size_t size, uint8_t alignment,
return aligned_address;
}
-void IRMemoryMap::Leak(lldb::addr_t process_address, Error &error) {
+void IRMemoryMap::Leak(lldb::addr_t process_address, Status &error) {
error.Clear();
AllocationMap::iterator iter = m_allocations.find(process_address);
@@ -445,7 +445,7 @@ void IRMemoryMap::Leak(lldb::addr_t process_address, Error &error) {
allocation.m_leak = true;
}
-void IRMemoryMap::Free(lldb::addr_t process_address, Error &error) {
+void IRMemoryMap::Free(lldb::addr_t process_address, Status &error) {
error.Clear();
AllocationMap::iterator iter = m_allocations.find(process_address);
@@ -512,7 +512,8 @@ bool IRMemoryMap::GetAllocSize(lldb::addr_t address, size_t &size) {
}
void IRMemoryMap::WriteMemory(lldb::addr_t process_address,
- const uint8_t *bytes, size_t size, Error &error) {
+ const uint8_t *bytes, size_t size,
+ Status &error) {
error.Clear();
AllocationMap::iterator iter = FindAllocation(process_address, size);
@@ -587,7 +588,7 @@ void IRMemoryMap::WriteMemory(lldb::addr_t process_address,
void IRMemoryMap::WriteScalarToMemory(lldb::addr_t process_address,
Scalar &scalar, size_t size,
- Error &error) {
+ Status &error) {
error.Clear();
if (size == UINT32_MAX)
@@ -612,7 +613,7 @@ void IRMemoryMap::WriteScalarToMemory(lldb::addr_t process_address,
}
void IRMemoryMap::WritePointerToMemory(lldb::addr_t process_address,
- lldb::addr_t address, Error &error) {
+ lldb::addr_t address, Status &error) {
error.Clear();
Scalar scalar(address);
@@ -621,7 +622,7 @@ void IRMemoryMap::WritePointerToMemory(lldb::addr_t process_address,
}
void IRMemoryMap::ReadMemory(uint8_t *bytes, lldb::addr_t process_address,
- size_t size, Error &error) {
+ size_t size, Status &error) {
error.Clear();
AllocationMap::iterator iter = FindAllocation(process_address, size);
@@ -717,7 +718,7 @@ void IRMemoryMap::ReadMemory(uint8_t *bytes, lldb::addr_t process_address,
void IRMemoryMap::ReadScalarFromMemory(Scalar &scalar,
lldb::addr_t process_address,
- size_t size, Error &error) {
+ size_t size, Status &error) {
error.Clear();
if (size > 0) {
@@ -760,7 +761,7 @@ void IRMemoryMap::ReadScalarFromMemory(Scalar &scalar,
void IRMemoryMap::ReadPointerFromMemory(lldb::addr_t *address,
lldb::addr_t process_address,
- Error &error) {
+ Status &error) {
error.Clear();
Scalar pointer_scalar;
@@ -777,7 +778,7 @@ void IRMemoryMap::ReadPointerFromMemory(lldb::addr_t *address,
void IRMemoryMap::GetMemoryData(DataExtractor &extractor,
lldb::addr_t process_address, size_t size,
- Error &error) {
+ Status &error) {
error.Clear();
if (size > 0) {
diff --git a/contrib/llvm/tools/lldb/source/Expression/LLVMUserExpression.cpp b/contrib/llvm/tools/lldb/source/Expression/LLVMUserExpression.cpp
index c5df781..83acb82 100644
--- a/contrib/llvm/tools/lldb/source/Expression/LLVMUserExpression.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/LLVMUserExpression.cpp
@@ -12,11 +12,8 @@
// Project includes
#include "lldb/Expression/LLVMUserExpression.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/ExpressionSourceCode.h"
@@ -38,6 +35,9 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallUserExpression.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
@@ -49,7 +49,10 @@ LLVMUserExpression::LLVMUserExpression(ExecutionContextScope &exe_scope,
const EvaluateExpressionOptions &options)
: UserExpression(exe_scope, expr, prefix, language, desired_type, options),
m_stack_frame_bottom(LLDB_INVALID_ADDRESS),
- m_stack_frame_top(LLDB_INVALID_ADDRESS), m_transformed_text(),
+ m_stack_frame_top(LLDB_INVALID_ADDRESS),
+ m_allow_cxx(false),
+ m_allow_objc(false),
+ m_transformed_text(),
m_execution_unit_sp(), m_materializer_ap(), m_jit_module_wp(),
m_enforce_valid_object(true), m_in_cplusplus_method(false),
m_in_objectivec_method(false), m_in_static_method(false),
@@ -103,7 +106,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager,
return lldb::eExpressionSetupError;
}
- Error interpreter_error;
+ Status interpreter_error;
std::vector<lldb::addr_t> args;
@@ -267,7 +270,7 @@ bool LLVMUserExpression::FinalizeJITExecution(
return false;
}
- Error dematerialize_error;
+ Status dematerialize_error;
m_dematerializer_sp->Dematerialize(dematerialize_error, function_stack_bottom,
function_stack_top);
@@ -306,7 +309,7 @@ bool LLVMUserExpression::PrepareToExecuteJITExpression(
if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) {
if (m_materialized_address == LLDB_INVALID_ADDRESS) {
- Error alloc_error;
+ Status alloc_error;
IRMemoryMap::AllocationPolicy policy =
m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly
@@ -332,7 +335,7 @@ bool LLVMUserExpression::PrepareToExecuteJITExpression(
struct_address = m_materialized_address;
if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) {
- Error alloc_error;
+ Status alloc_error;
const size_t stack_frame_size = 512 * 1024;
@@ -354,7 +357,7 @@ bool LLVMUserExpression::PrepareToExecuteJITExpression(
}
}
- Error materialize_error;
+ Status materialize_error;
m_dematerializer_sp = m_materializer_ap->Materialize(
frame, *m_execution_unit_sp, struct_address, materialize_error);
diff --git a/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp b/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp
index 6ddd4a4..39fc5c8 100644
--- a/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp
@@ -12,7 +12,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Expression/Materializer.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectVariable.h"
@@ -26,6 +26,7 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
using namespace lldb_private;
@@ -73,12 +74,12 @@ public:
m_alignment = 8;
}
- void MakeAllocation(IRMemoryMap &map, Error &err) {
+ void MakeAllocation(IRMemoryMap &map, Status &err) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
// Allocate a spare memory area to store the persistent variable's contents.
- Error allocate_error;
+ Status allocate_error;
const bool zero_memory = false;
lldb::addr_t mem = map.Malloc(
@@ -111,7 +112,7 @@ public:
if (m_persistent_variable_sp->m_flags &
ExpressionVariable::EVKeepInTarget) {
- Error leak_error;
+ Status leak_error;
map.Leak(mem, leak_error);
m_persistent_variable_sp->m_flags &=
~ExpressionVariable::EVNeedsAllocation;
@@ -119,7 +120,7 @@ public:
// Write the contents of the variable to the area.
- Error write_error;
+ Status write_error;
map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
m_persistent_variable_sp->GetByteSize(), write_error);
@@ -133,8 +134,8 @@ public:
}
}
- void DestroyAllocation(IRMemoryMap &map, Error &err) {
- Error deallocate_error;
+ void DestroyAllocation(IRMemoryMap &map, Status &err) {
+ Status deallocate_error;
map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
.GetScalar()
@@ -152,7 +153,7 @@ public:
}
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
- lldb::addr_t process_address, Error &err) override {
+ lldb::addr_t process_address, Status &err) override {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
const lldb::addr_t load_addr = process_address + m_offset;
@@ -180,7 +181,7 @@ public:
m_persistent_variable_sp->m_live_sp) ||
m_persistent_variable_sp->m_flags &
ExpressionVariable::EVIsLLDBAllocated) {
- Error write_error;
+ Status write_error;
map.WriteScalarToMemory(
load_addr,
@@ -203,7 +204,7 @@ public:
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
lldb::addr_t process_address, lldb::addr_t frame_top,
- lldb::addr_t frame_bottom, Error &err) override {
+ lldb::addr_t frame_bottom, Status &err) override {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
const lldb::addr_t load_addr = process_address + m_offset;
@@ -233,7 +234,7 @@ public:
// live variable data hasn't been set up yet. Do this now.
lldb::addr_t location;
- Error read_error;
+ Status read_error;
map.ReadPointerFromMemory(&location, load_addr, read_error);
@@ -303,7 +304,7 @@ public:
m_persistent_variable_sp->ValueUpdated();
- Error read_error;
+ Status read_error;
map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
m_persistent_variable_sp->GetByteSize(), read_error);
@@ -352,7 +353,7 @@ public:
Log *log) override {
StreamString dump_stream;
- Error err;
+ Status err;
const lldb::addr_t load_addr = process_address + m_offset;
@@ -370,11 +371,8 @@ public:
if (!err.Success()) {
dump_stream.Printf(" <could not be read>\n");
} else {
- DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
- map.GetByteOrder(), map.GetAddressByteSize());
-
- extractor.DumpHexBytes(&dump_stream, data.GetBytes(),
- data.GetByteSize(), 16, load_addr);
+ DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
+ load_addr);
dump_stream.PutChar('\n');
}
@@ -398,11 +396,8 @@ public:
if (!err.Success()) {
dump_stream.Printf(" <could not be read>\n");
} else {
- DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
- map.GetByteOrder(), map.GetAddressByteSize());
-
- extractor.DumpHexBytes(&dump_stream, data.GetBytes(),
- data.GetByteSize(), 16, target_address);
+ DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
+ target_address);
dump_stream.PutChar('\n');
}
@@ -421,7 +416,7 @@ private:
uint32_t Materializer::AddPersistentVariable(
lldb::ExpressionVariableSP &persistent_variable_sp,
- PersistentVariableDelegate *delegate, Error &err) {
+ PersistentVariableDelegate *delegate, Status &err) {
EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
iter->reset(new EntityPersistentVariable(persistent_variable_sp, delegate));
uint32_t ret = AddStructMember(**iter);
@@ -444,7 +439,7 @@ public:
}
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
- lldb::addr_t process_address, Error &err) override {
+ lldb::addr_t process_address, Status &err) override {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
const lldb::addr_t load_addr = process_address + m_offset;
@@ -469,7 +464,7 @@ public:
return;
}
- Error valobj_error = valobj_sp->GetError();
+ Status valobj_error = valobj_sp->GetError();
if (valobj_error.Fail()) {
err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
@@ -480,7 +475,7 @@ public:
if (m_is_reference) {
DataExtractor valobj_extractor;
- Error extract_error;
+ Status extract_error;
valobj_sp->GetData(valobj_extractor, extract_error);
if (!extract_error.Success()) {
@@ -493,7 +488,7 @@ public:
lldb::offset_t offset = 0;
lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
- Error write_error;
+ Status write_error;
map.WritePointerToMemory(load_addr, reference_addr, write_error);
if (!write_error.Success()) {
@@ -509,7 +504,7 @@ public:
lldb::addr_t addr_of_valobj =
valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
- Error write_error;
+ Status write_error;
map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
if (!write_error.Success()) {
@@ -520,7 +515,7 @@ public:
}
} else {
DataExtractor data;
- Error extract_error;
+ Status extract_error;
valobj_sp->GetData(data, extract_error);
if (!extract_error.Success()) {
err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
@@ -559,7 +554,7 @@ public:
if (!byte_align)
byte_align = 1;
- Error alloc_error;
+ Status alloc_error;
const bool zero_memory = false;
m_temporary_allocation = map.Malloc(
@@ -579,7 +574,7 @@ public:
return;
}
- Error write_error;
+ Status write_error;
map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
data.GetByteSize(), write_error);
@@ -591,7 +586,7 @@ public:
return;
}
- Error pointer_write_error;
+ Status pointer_write_error;
map.WritePointerToMemory(load_addr, m_temporary_allocation,
pointer_write_error);
@@ -608,7 +603,7 @@ public:
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
lldb::addr_t process_address, lldb::addr_t frame_top,
- lldb::addr_t frame_bottom, Error &err) override {
+ lldb::addr_t frame_bottom, Status &err) override {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
const lldb::addr_t load_addr = process_address + m_offset;
@@ -636,7 +631,7 @@ public:
lldb_private::DataExtractor data;
- Error extract_error;
+ Status extract_error;
map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(),
extract_error);
@@ -657,7 +652,7 @@ public:
}
}
- Error set_error;
+ Status set_error;
if (actually_write) {
valobj_sp->SetData(data, set_error);
@@ -670,7 +665,7 @@ public:
}
}
- Error free_error;
+ Status free_error;
map.Free(m_temporary_allocation, free_error);
@@ -694,7 +689,7 @@ public:
const lldb::addr_t load_addr = process_address + m_offset;
dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
- Error err;
+ Status err;
lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
@@ -711,8 +706,8 @@ public:
DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
map.GetByteOrder(), map.GetAddressByteSize());
- extractor.DumpHexBytes(&dump_stream, data.GetBytes(),
- data.GetByteSize(), 16, load_addr);
+ DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
+ load_addr);
lldb::offset_t offset;
@@ -739,11 +734,8 @@ public:
if (!err.Success()) {
dump_stream.Printf(" <could not be read>\n");
} else {
- DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
- map.GetByteOrder(), map.GetAddressByteSize());
-
- extractor.DumpHexBytes(&dump_stream, data.GetBytes(),
- data.GetByteSize(), 16, load_addr);
+ DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
+ load_addr);
dump_stream.PutChar('\n');
}
@@ -754,7 +746,7 @@ public:
void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
- Error free_error;
+ Status free_error;
map.Free(m_temporary_allocation, free_error);
@@ -771,7 +763,7 @@ private:
lldb::DataBufferSP m_original_data;
};
-uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Error &err) {
+uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
iter->reset(new EntityVariable(variable_sp));
uint32_t ret = AddStructMember(**iter);
@@ -795,7 +787,7 @@ public:
}
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
- lldb::addr_t process_address, Error &err) override {
+ lldb::addr_t process_address, Status &err) override {
if (!m_is_program_reference) {
if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
err.SetErrorString("Trying to create a temporary region for the result "
@@ -814,7 +806,7 @@ public:
if (!byte_align)
byte_align = 1;
- Error alloc_error;
+ Status alloc_error;
const bool zero_memory = true;
m_temporary_allocation = map.Malloc(
@@ -830,7 +822,7 @@ public:
return;
}
- Error pointer_write_error;
+ Status pointer_write_error;
map.WritePointerToMemory(load_addr, m_temporary_allocation,
pointer_write_error);
@@ -845,7 +837,7 @@ public:
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
lldb::addr_t process_address, lldb::addr_t frame_top,
- lldb::addr_t frame_bottom, Error &err) override {
+ lldb::addr_t frame_bottom, Status &err) override {
err.Clear();
ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
@@ -857,7 +849,7 @@ public:
}
lldb::addr_t address;
- Error read_error;
+ Status read_error;
const lldb::addr_t load_addr = process_address + m_offset;
map.ReadPointerFromMemory(&address, load_addr, read_error);
@@ -875,7 +867,7 @@ public:
return;
}
- Error type_system_error;
+ Status type_system_error;
TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage(
&type_system_error, m_type.GetMinimumLanguage());
@@ -945,7 +937,7 @@ public:
ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
- Error free_error;
+ Status free_error;
map.Free(m_temporary_allocation, free_error);
}
} else {
@@ -964,7 +956,7 @@ public:
dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
- Error err;
+ Status err;
lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
@@ -981,8 +973,8 @@ public:
DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
map.GetByteOrder(), map.GetAddressByteSize());
- extractor.DumpHexBytes(&dump_stream, data.GetBytes(),
- data.GetByteSize(), 16, load_addr);
+ DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
+ load_addr);
lldb::offset_t offset;
@@ -1009,11 +1001,8 @@ public:
if (!err.Success()) {
dump_stream.Printf(" <could not be read>\n");
} else {
- DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
- map.GetByteOrder(), map.GetAddressByteSize());
-
- extractor.DumpHexBytes(&dump_stream, data.GetBytes(),
- data.GetByteSize(), 16, load_addr);
+ DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
+ load_addr);
dump_stream.PutChar('\n');
}
@@ -1024,7 +1013,7 @@ public:
void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
- Error free_error;
+ Status free_error;
map.Free(m_temporary_allocation, free_error);
}
@@ -1047,7 +1036,7 @@ uint32_t Materializer::AddResultVariable(const CompilerType &type,
bool is_program_reference,
bool keep_in_memory,
PersistentVariableDelegate *delegate,
- Error &err) {
+ Status &err) {
EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
iter->reset(new EntityResultVariable(type, is_program_reference,
keep_in_memory, delegate));
@@ -1065,7 +1054,7 @@ public:
}
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
- lldb::addr_t process_address, Error &err) override {
+ lldb::addr_t process_address, Status &err) override {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
const lldb::addr_t load_addr = process_address + m_offset;
@@ -1097,7 +1086,7 @@ public:
if (resolved_address == LLDB_INVALID_ADDRESS)
resolved_address = sym_address.GetFileAddress();
- Error pointer_write_error;
+ Status pointer_write_error;
map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
@@ -1111,7 +1100,7 @@ public:
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
lldb::addr_t process_address, lldb::addr_t frame_top,
- lldb::addr_t frame_bottom, Error &err) override {
+ lldb::addr_t frame_bottom, Status &err) override {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
const lldb::addr_t load_addr = process_address + m_offset;
@@ -1129,7 +1118,7 @@ public:
Log *log) override {
StreamString dump_stream;
- Error err;
+ Status err;
const lldb::addr_t load_addr = process_address + m_offset;
@@ -1146,11 +1135,8 @@ public:
if (!err.Success()) {
dump_stream.Printf(" <could not be read>\n");
} else {
- DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
- map.GetByteOrder(), map.GetAddressByteSize());
-
- extractor.DumpHexBytes(&dump_stream, data.GetBytes(),
- data.GetByteSize(), 16, load_addr);
+ DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
+ load_addr);
dump_stream.PutChar('\n');
}
@@ -1165,7 +1151,7 @@ private:
Symbol m_symbol;
};
-uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Error &err) {
+uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
iter->reset(new EntitySymbol(symbol_sp));
uint32_t ret = AddStructMember(**iter);
@@ -1183,7 +1169,7 @@ public:
}
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
- lldb::addr_t process_address, Error &err) override {
+ lldb::addr_t process_address, Status &err) override {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
const lldb::addr_t load_addr = process_address + m_offset;
@@ -1230,7 +1216,7 @@ public:
m_register_contents.reset(new DataBufferHeap(register_data.GetDataStart(),
register_data.GetByteSize()));
- Error write_error;
+ Status write_error;
map.WriteMemory(load_addr, register_data.GetDataStart(),
register_data.GetByteSize(), write_error);
@@ -1245,7 +1231,7 @@ public:
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
lldb::addr_t process_address, lldb::addr_t frame_top,
- lldb::addr_t frame_bottom, Error &err) override {
+ lldb::addr_t frame_bottom, Status &err) override {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
const lldb::addr_t load_addr = process_address + m_offset;
@@ -1256,7 +1242,7 @@ public:
(uint64_t)load_addr, m_register_info.name);
}
- Error extract_error;
+ Status extract_error;
DataExtractor register_data;
@@ -1305,7 +1291,7 @@ public:
Log *log) override {
StreamString dump_stream;
- Error err;
+ Status err;
const lldb::addr_t load_addr = process_address + m_offset;
@@ -1322,11 +1308,8 @@ public:
if (!err.Success()) {
dump_stream.Printf(" <could not be read>\n");
} else {
- DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
- map.GetByteOrder(), map.GetAddressByteSize());
-
- extractor.DumpHexBytes(&dump_stream, data.GetBytes(),
- data.GetByteSize(), 16, load_addr);
+ DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
+ load_addr);
dump_stream.PutChar('\n');
}
@@ -1343,7 +1326,7 @@ private:
};
uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
- Error &err) {
+ Status &err) {
EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
iter->reset(new EntityRegister(register_info));
uint32_t ret = AddStructMember(**iter);
@@ -1363,7 +1346,7 @@ Materializer::~Materializer() {
Materializer::DematerializerSP
Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
- lldb::addr_t process_address, Error &error) {
+ lldb::addr_t process_address, Status &error) {
ExecutionContextScope *exe_scope = frame_sp.get();
if (!exe_scope)
@@ -1406,7 +1389,7 @@ Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
return ret;
}
-void Materializer::Dematerializer::Dematerialize(Error &error,
+void Materializer::Dematerializer::Dematerialize(Status &error,
lldb::addr_t frame_bottom,
lldb::addr_t frame_top) {
lldb::StackFrameSP frame_sp;
diff --git a/contrib/llvm/tools/lldb/source/Expression/REPL.cpp b/contrib/llvm/tools/lldb/source/Expression/REPL.cpp
index e404537..84a6405 100644
--- a/contrib/llvm/tools/lldb/source/Expression/REPL.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/REPL.cpp
@@ -42,7 +42,7 @@ REPL::REPL(LLVMCastKind kind, Target &target) : m_target(target), m_kind(kind) {
REPL::~REPL() = default;
-lldb::REPLSP REPL::Create(Error &err, lldb::LanguageType language,
+lldb::REPLSP REPL::Create(Status &err, lldb::LanguageType language,
Debugger *debugger, Target *target,
const char *repl_options) {
uint32_t idx = 0;
@@ -309,7 +309,7 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
const char *expr_prefix = nullptr;
lldb::ValueObjectSP result_valobj_sp;
- Error error;
+ Status error;
lldb::ModuleSP jit_module_sp;
lldb::ExpressionResults execution_results =
UserExpression::Evaluate(exe_ctx, expr_options, code.c_str(),
@@ -518,8 +518,8 @@ bool QuitCommandOverrideCallback(void *baton, const char **argv) {
return false;
}
-Error REPL::RunLoop() {
- Error error;
+Status REPL::RunLoop() {
+ Status error;
error = DoInitialization();
m_repl_source_path = GetSourcePath();
diff --git a/contrib/llvm/tools/lldb/source/Expression/UserExpression.cpp b/contrib/llvm/tools/lldb/source/Expression/UserExpression.cpp
index 041caf5..3386bc4 100644
--- a/contrib/llvm/tools/lldb/source/Expression/UserExpression.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/UserExpression.cpp
@@ -17,11 +17,8 @@
#include <string>
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/ExpressionSourceCode.h"
@@ -43,6 +40,9 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallUserExpression.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
@@ -101,7 +101,7 @@ bool UserExpression::MatchesContext(ExecutionContext &exe_ctx) {
lldb::addr_t UserExpression::GetObjectPointer(lldb::StackFrameSP frame_sp,
ConstString &object_name,
- Error &err) {
+ Status &err) {
err.Clear();
if (!frame_sp) {
@@ -140,7 +140,7 @@ lldb::addr_t UserExpression::GetObjectPointer(lldb::StackFrameSP frame_sp,
lldb::ExpressionResults UserExpression::Evaluate(
ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options,
llvm::StringRef expr, llvm::StringRef prefix,
- lldb::ValueObjectSP &result_valobj_sp, Error &error, uint32_t line_offset,
+ lldb::ValueObjectSP &result_valobj_sp, Status &error, uint32_t line_offset,
std::string *fixed_expression, lldb::ModuleSP *jit_module_sp_ptr) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS |
LIBLLDB_LOG_STEP));
diff --git a/contrib/llvm/tools/lldb/source/Expression/UtilityFunction.cpp b/contrib/llvm/tools/lldb/source/Expression/UtilityFunction.cpp
index fdb21ba..52f3bfc 100644
--- a/contrib/llvm/tools/lldb/source/Expression/UtilityFunction.cpp
+++ b/contrib/llvm/tools/lldb/source/Expression/UtilityFunction.cpp
@@ -15,10 +15,7 @@
// C++ Includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/ExpressionSourceCode.h"
@@ -29,6 +26,9 @@
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
using namespace lldb;
@@ -65,7 +65,7 @@ UtilityFunction::~UtilityFunction() {
FunctionCaller *UtilityFunction::MakeFunctionCaller(
const CompilerType &return_type, const ValueList &arg_value_list,
- lldb::ThreadSP thread_to_use_sp, Error &error) {
+ lldb::ThreadSP thread_to_use_sp, Status &error) {
if (m_caller_up)
return m_caller_up.get();
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp
index 1c5c0ff..7b580dd 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp
@@ -11,16 +11,19 @@
#include <iostream>
#include <limits.h>
-#include "lldb/Core/Error.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Editline.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/SelectHelper.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StringList.h"
+#include "lldb/Utility/Timeout.h"
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Threading.h"
using namespace lldb_private;
using namespace lldb_private::line_editor;
@@ -176,9 +179,7 @@ private:
if (m_path.empty() && m_history && !m_prefix.empty()) {
FileSpec parent_path{"~/.lldb", true};
char history_path[PATH_MAX];
- if (FileSystem::MakeDirectory(parent_path,
- lldb::eFilePermissionsDirectoryDefault)
- .Success()) {
+ if (!llvm::sys::fs::create_directory(parent_path.GetPath())) {
snprintf(history_path, sizeof(history_path), "~/.lldb/%s-history",
m_prefix.c_str());
} else {
@@ -366,7 +367,7 @@ void Editline::MoveCursor(CursorLocation from, CursorLocation to) {
if (to == CursorLocation::EditingCursor) {
toColumn =
editline_cursor_position - (editline_cursor_row * m_terminal_width) + 1;
- } else if (to == CursorLocation::BlockEnd) {
+ } else if (to == CursorLocation::BlockEnd && !m_input_lines.empty()) {
toColumn =
((m_input_lines[m_input_lines.size() - 1].length() + GetPromptWidth()) %
80) +
@@ -473,7 +474,7 @@ unsigned char Editline::RecallHistory(bool earlier) {
return CC_NEWLINE;
}
-int Editline::GetCharacter(EditLineCharType *c) {
+int Editline::GetCharacter(EditLineGetCharType *c) {
const LineInfoW *info = el_wline(m_editline);
// Paint a faint version of the desired prompt over the version libedit draws
@@ -968,7 +969,7 @@ void Editline::ConfigureEditor(bool multiline) {
}));
el_wset(m_editline, EL_GETCFN, (EditlineGetCharCallbackType)([](
- EditLine *editline, EditLineCharType *c) {
+ EditLine *editline, EditLineGetCharType *c) {
return Editline::InstanceFor(editline)->GetCharacter(c);
}));
@@ -1151,8 +1152,8 @@ Editline::Editline(const char *editline_name, FILE *input_file,
if (term_fd != -1) {
static std::mutex *g_init_terminal_fds_mutex_ptr = nullptr;
static std::set<int> *g_init_terminal_fds_ptr = nullptr;
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, [&]() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, [&]() {
g_init_terminal_fds_mutex_ptr =
new std::mutex(); // NOTE: Leak to avoid C++ destructor chain issues
g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid
@@ -1359,12 +1360,12 @@ void Editline::PrintAsync(Stream *stream, const char *s, size_t len) {
}
}
-bool Editline::CompleteCharacter(char ch, EditLineCharType &out) {
+bool Editline::CompleteCharacter(char ch, EditLineGetCharType &out) {
#if !LLDB_EDITLINE_USE_WCHAR
if (ch == (char)EOF)
return false;
- out = ch;
+ out = (unsigned char)ch;
return true;
#else
std::codecvt_utf8<wchar_t> cvt;
diff --git a/contrib/llvm/tools/lldb/source/Host/common/File.cpp b/contrib/llvm/tools/lldb/source/Host/common/File.cpp
index 4eb9ae1..6ee4e89 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/File.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/File.cpp
@@ -19,17 +19,21 @@
#include "lldb/Host/windows/windows.h"
#else
#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <unistd.h>
#endif
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors()
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Host/Config.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -132,9 +136,8 @@ FILE *File::GetStream() {
m_should_close_fd = true;
}
- do {
- m_stream = ::fdopen(m_descriptor, mode);
- } while (m_stream == NULL && errno == EINTR);
+ m_stream =
+ llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, mode);
// If we got a stream, then we own the stream and should no
// longer own the descriptor because fclose() will close it for us
@@ -156,8 +159,21 @@ void File::SetStream(FILE *fh, bool transfer_ownership) {
m_own_stream = transfer_ownership;
}
-Error File::Open(const char *path, uint32_t options, uint32_t permissions) {
- Error error;
+static int DoOpen(const char *path, int flags, int mode) {
+#ifdef _MSC_VER
+ std::wstring wpath;
+ if (!llvm::ConvertUTF8toWide(path, wpath))
+ return -1;
+ int result;
+ ::_wsopen_s(&result, wpath.c_str(), flags, _SH_DENYNO, mode);
+ return result;
+#else
+ return ::open(path, flags, mode);
+#endif
+}
+
+Status File::Open(const char *path, uint32_t options, uint32_t permissions) {
+ Status error;
if (IsValid())
Close();
@@ -221,20 +237,7 @@ Error File::Open(const char *path, uint32_t options, uint32_t permissions) {
mode |= S_IXOTH;
}
- do {
-#ifdef _MSC_VER
- std::wstring wpath;
- if (!llvm::ConvertUTF8toWide(path, wpath)) {
- m_descriptor = -1;
- error.SetErrorString("Error converting path to UTF-16");
- return error;
- }
- ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode);
-#else
- m_descriptor = ::open(path, oflag, mode);
-#endif
- } while (m_descriptor < 0 && errno == EINTR);
-
+ m_descriptor = llvm::sys::RetryAfterSignal(-1, DoOpen, path, oflag, mode);
if (!DescriptorIsValid())
error.SetErrorToErrno();
else {
@@ -245,22 +248,20 @@ Error File::Open(const char *path, uint32_t options, uint32_t permissions) {
return error;
}
-uint32_t File::GetPermissions(const FileSpec &file_spec, Error &error) {
+uint32_t File::GetPermissions(const FileSpec &file_spec, Status &error) {
if (file_spec) {
- struct stat file_stats;
- int stat_result = FileSystem::Stat(file_spec.GetCString(), &file_stats);
- if (stat_result == -1)
- error.SetErrorToErrno();
- else {
- error.Clear();
- return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
- }
+ error.Clear();
+ auto Perms = llvm::sys::fs::getPermissions(file_spec.GetPath());
+ if (Perms)
+ return *Perms;
+ error = Status(Perms.getError());
+ return 0;
} else
error.SetErrorString("empty file spec");
return 0;
}
-uint32_t File::GetPermissions(Error &error) const {
+uint32_t File::GetPermissions(Status &error) const {
int fd = GetDescriptor();
if (fd != kInvalidDescriptor) {
struct stat file_stats;
@@ -276,8 +277,8 @@ uint32_t File::GetPermissions(Error &error) const {
return 0;
}
-Error File::Close() {
- Error error;
+Status File::Close() {
+ Status error;
if (StreamIsValid() && m_own_stream) {
if (::fclose(m_stream) == EOF)
error.SetErrorToErrno();
@@ -306,9 +307,9 @@ void File::Clear() {
eLazyBoolCalculate;
}
-Error File::GetFileSpec(FileSpec &file_spec) const {
- Error error;
-#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
+Status File::GetFileSpec(FileSpec &file_spec) const {
+ Status error;
+#ifdef F_GETPATH
if (IsValid()) {
char path[PATH_MAX];
if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
@@ -341,7 +342,7 @@ Error File::GetFileSpec(FileSpec &file_spec) const {
return error;
}
-off_t File::SeekFromStart(off_t offset, Error *error_ptr) {
+off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
off_t result = 0;
if (DescriptorIsValid()) {
result = ::lseek(m_descriptor, offset, SEEK_SET);
@@ -367,7 +368,7 @@ off_t File::SeekFromStart(off_t offset, Error *error_ptr) {
return result;
}
-off_t File::SeekFromCurrent(off_t offset, Error *error_ptr) {
+off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
off_t result = -1;
if (DescriptorIsValid()) {
result = ::lseek(m_descriptor, offset, SEEK_CUR);
@@ -393,7 +394,7 @@ off_t File::SeekFromCurrent(off_t offset, Error *error_ptr) {
return result;
}
-off_t File::SeekFromEnd(off_t offset, Error *error_ptr) {
+off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
off_t result = -1;
if (DescriptorIsValid()) {
result = ::lseek(m_descriptor, offset, SEEK_END);
@@ -419,15 +420,10 @@ off_t File::SeekFromEnd(off_t offset, Error *error_ptr) {
return result;
}
-Error File::Flush() {
- Error error;
+Status File::Flush() {
+ Status error;
if (StreamIsValid()) {
- int err = 0;
- do {
- err = ::fflush(m_stream);
- } while (err == EOF && errno == EINTR);
-
- if (err == EOF)
+ if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
error.SetErrorToErrno();
} else if (!DescriptorIsValid()) {
error.SetErrorString("invalid file handle");
@@ -435,20 +431,15 @@ Error File::Flush() {
return error;
}
-Error File::Sync() {
- Error error;
+Status File::Sync() {
+ Status error;
if (DescriptorIsValid()) {
#ifdef _WIN32
int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
if (err == 0)
error.SetErrorToGenericError();
#else
- int err = 0;
- do {
- err = ::fsync(m_descriptor);
- } while (err == -1 && errno == EINTR);
-
- if (err == -1)
+ if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1)
error.SetErrorToErrno();
#endif
} else {
@@ -463,8 +454,8 @@ Error File::Sync() {
#define MAX_WRITE_SIZE INT_MAX
#endif
-Error File::Read(void *buf, size_t &num_bytes) {
- Error error;
+Status File::Read(void *buf, size_t &num_bytes) {
+ Status error;
#if defined(MAX_READ_SIZE)
if (num_bytes > MAX_READ_SIZE) {
@@ -498,10 +489,7 @@ Error File::Read(void *buf, size_t &num_bytes) {
ssize_t bytes_read = -1;
if (DescriptorIsValid()) {
- do {
- bytes_read = ::read(m_descriptor, buf, num_bytes);
- } while (bytes_read < 0 && errno == EINTR);
-
+ bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes);
if (bytes_read == -1) {
error.SetErrorToErrno();
num_bytes = 0;
@@ -525,8 +513,8 @@ Error File::Read(void *buf, size_t &num_bytes) {
return error;
}
-Error File::Write(const void *buf, size_t &num_bytes) {
- Error error;
+Status File::Write(const void *buf, size_t &num_bytes) {
+ Status error;
#if defined(MAX_WRITE_SIZE)
if (num_bytes > MAX_WRITE_SIZE) {
@@ -560,10 +548,8 @@ Error File::Write(const void *buf, size_t &num_bytes) {
ssize_t bytes_written = -1;
if (DescriptorIsValid()) {
- do {
- bytes_written = ::write(m_descriptor, buf, num_bytes);
- } while (bytes_written < 0 && errno == EINTR);
-
+ bytes_written =
+ llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes);
if (bytes_written == -1) {
error.SetErrorToErrno();
num_bytes = 0;
@@ -589,8 +575,8 @@ Error File::Write(const void *buf, size_t &num_bytes) {
return error;
}
-Error File::Read(void *buf, size_t &num_bytes, off_t &offset) {
- Error error;
+Status File::Read(void *buf, size_t &num_bytes, off_t &offset) {
+ Status error;
#if defined(MAX_READ_SIZE)
if (num_bytes > MAX_READ_SIZE) {
@@ -625,11 +611,8 @@ Error File::Read(void *buf, size_t &num_bytes, off_t &offset) {
#ifndef _WIN32
int fd = GetDescriptor();
if (fd != kInvalidDescriptor) {
- ssize_t bytes_read = -1;
- do {
- bytes_read = ::pread(fd, buf, num_bytes, offset);
- } while (bytes_read < 0 && errno == EINTR);
-
+ ssize_t bytes_read =
+ llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset);
if (bytes_read < 0) {
num_bytes = 0;
error.SetErrorToErrno();
@@ -651,9 +634,9 @@ Error File::Read(void *buf, size_t &num_bytes, off_t &offset) {
return error;
}
-Error File::Read(size_t &num_bytes, off_t &offset, bool null_terminate,
- DataBufferSP &data_buffer_sp) {
- Error error;
+Status File::Read(size_t &num_bytes, off_t &offset, bool null_terminate,
+ DataBufferSP &data_buffer_sp) {
+ Status error;
if (num_bytes > 0) {
int fd = GetDescriptor();
@@ -695,8 +678,8 @@ Error File::Read(size_t &num_bytes, off_t &offset, bool null_terminate,
return error;
}
-Error File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
- Error error;
+Status File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
+ Status error;
#if defined(MAX_WRITE_SIZE)
if (num_bytes > MAX_WRITE_SIZE) {
@@ -731,11 +714,8 @@ Error File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
int fd = GetDescriptor();
if (fd != kInvalidDescriptor) {
#ifndef _WIN32
- ssize_t bytes_written = -1;
- do {
- bytes_written = ::pwrite(m_descriptor, buf, num_bytes, offset);
- } while (bytes_written < 0 && errno == EINTR);
-
+ ssize_t bytes_written =
+ llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
if (bytes_written < 0) {
num_bytes = 0;
error.SetErrorToErrno();
diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp
index db71813..b462925 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp
@@ -24,7 +24,7 @@ FileCache &FileCache::GetInstance() {
}
lldb::user_id_t FileCache::OpenFile(const FileSpec &file_spec, uint32_t flags,
- uint32_t mode, Error &error) {
+ uint32_t mode, Status &error) {
std::string path(file_spec.GetPath());
if (path.empty()) {
error.SetErrorString("empty path");
@@ -39,7 +39,7 @@ lldb::user_id_t FileCache::OpenFile(const FileSpec &file_spec, uint32_t flags,
return fd;
}
-bool FileCache::CloseFile(lldb::user_id_t fd, Error &error) {
+bool FileCache::CloseFile(lldb::user_id_t fd, Status &error) {
if (fd == UINT64_MAX) {
error.SetErrorString("invalid file descriptor");
return false;
@@ -60,7 +60,8 @@ bool FileCache::CloseFile(lldb::user_id_t fd, Error &error) {
}
uint64_t FileCache::WriteFile(lldb::user_id_t fd, uint64_t offset,
- const void *src, uint64_t src_len, Error &error) {
+ const void *src, uint64_t src_len,
+ Status &error) {
if (fd == UINT64_MAX) {
error.SetErrorString("invalid file descriptor");
return UINT64_MAX;
@@ -86,7 +87,7 @@ uint64_t FileCache::WriteFile(lldb::user_id_t fd, uint64_t offset,
}
uint64_t FileCache::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
- uint64_t dst_len, Error &error) {
+ uint64_t dst_len, Status &error) {
if (fd == UINT64_MAX) {
error.SetErrorString("invalid file descriptor");
return UINT64_MAX;
diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp
index 88f29b4..4472aec 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp
@@ -10,7 +10,6 @@
#include "lldb/Host/FileSystem.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MD5.h"
#include <algorithm>
#include <fstream>
@@ -19,79 +18,6 @@
using namespace lldb;
using namespace lldb_private;
-namespace {
-
-bool CalcMD5(const FileSpec &file_spec, uint64_t offset, uint64_t length,
- llvm::MD5::MD5Result &md5_result) {
- llvm::MD5 md5_hash;
- std::ifstream file(file_spec.GetPath(), std::ios::binary);
- if (!file.is_open())
- return false;
-
- if (offset > 0)
- file.seekg(offset, file.beg);
-
- std::vector<char> read_buf(4096);
- uint64_t total_read_bytes = 0;
- while (!file.eof()) {
- const uint64_t to_read =
- (length > 0) ? std::min(static_cast<uint64_t>(read_buf.size()),
- length - total_read_bytes)
- : read_buf.size();
- if (to_read == 0)
- break;
-
- file.read(&read_buf[0], to_read);
- const auto read_bytes = file.gcount();
- if (read_bytes == 0)
- break;
-
- md5_hash.update(llvm::StringRef(&read_buf[0], read_bytes));
- total_read_bytes += read_bytes;
- }
-
- md5_hash.final(md5_result);
- return true;
-}
-
-} // namespace
-
-bool FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low,
- uint64_t &high) {
- return CalculateMD5(file_spec, 0, 0, low, high);
-}
-
-bool FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t offset,
- uint64_t length, uint64_t &low, uint64_t &high) {
- llvm::MD5::MD5Result md5_result;
- if (!CalcMD5(file_spec, offset, length, md5_result))
- return false;
-
- const auto uint64_res = reinterpret_cast<const uint64_t *>(md5_result);
- high = uint64_res[0];
- low = uint64_res[1];
-
- return true;
-}
-
-bool FileSystem::CalculateMD5AsString(const FileSpec &file_spec,
- std::string &digest_str) {
- return CalculateMD5AsString(file_spec, 0, 0, digest_str);
-}
-
-bool FileSystem::CalculateMD5AsString(const FileSpec &file_spec,
- uint64_t offset, uint64_t length,
- std::string &digest_str) {
- llvm::MD5::MD5Result md5_result;
- if (!CalcMD5(file_spec, offset, length, md5_result))
- return false;
-
- llvm::SmallString<32> result_str;
- llvm::MD5::stringifyResult(md5_result, result_str);
- digest_str = result_str.c_str();
- return true;
-}
-
llvm::sys::TimePoint<>
FileSystem::GetModificationTime(const FileSpec &file_spec) {
llvm::sys::fs::file_status status;
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp
index 6d0ad01..8248aa3 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp
@@ -28,7 +28,8 @@
#endif
#if defined(__linux__) || defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
+ defined(__FreeBSD_kernel__) || defined(__APPLE__) || \
+ defined(__NetBSD__) || defined(__OpenBSD__)
#if !defined(__ANDROID__)
#include <spawn.h>
#endif
@@ -40,16 +41,17 @@
#include <pthread_np.h>
#endif
+#if defined(__NetBSD__)
+#include <lwp.h>
+#endif
+
// C++ Includes
+#include <csignal>
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/HostProcess.h"
@@ -57,20 +59,26 @@
#include "lldb/Host/Predicate.h"
#include "lldb/Host/ProcessLauncher.h"
#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
#include "lldb/Target/FileAction.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/DataBufferLLVM.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-forward.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#if defined(_WIN32)
+#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
#include "lldb/Host/windows/ProcessLauncherWindows.h"
-#elif defined(__linux__)
-#include "lldb/Host/linux/ProcessLauncherLinux.h"
#else
-#include "lldb/Host/posix/ProcessLauncherPosix.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
#endif
#if defined(__APPLE__)
@@ -180,7 +188,7 @@ static thread_result_t MonitorChildProcessThreadFunction(void *arg) {
delete info;
int status = -1;
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
#define __WALL 0
#endif
const int options = __WALL;
@@ -212,10 +220,9 @@ static thread_result_t MonitorChildProcessThreadFunction(void *arg) {
if (errno == EINTR)
continue;
else {
- if (log)
- log->Printf(
- "%s (arg = %p) thread exiting because waitpid failed (%s)...",
- __FUNCTION__, arg, strerror(errno));
+ LLDB_LOG(log,
+ "arg = {0}, thread exiting because waitpid failed ({1})...",
+ arg, llvm::sys::StrError());
break;
}
} else if (wait_pid > 0) {
@@ -310,25 +317,6 @@ lldb::pid_t Host::GetCurrentProcessID() { return ::getpid(); }
#ifndef _WIN32
-lldb::tid_t Host::GetCurrentThreadID() {
-#if defined(__APPLE__)
- // Calling "mach_thread_self()" bumps the reference count on the thread
- // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
- // count.
- thread_port_t thread_self = mach_thread_self();
- mach_port_deallocate(mach_task_self(), thread_self);
- return thread_self;
-#elif defined(__FreeBSD__)
- return lldb::tid_t(pthread_getthreadid_np());
-#elif defined(__ANDROID__)
- return lldb::tid_t(gettid());
-#elif defined(__linux__)
- return lldb::tid_t(syscall(SYS_gettid));
-#else
- return lldb::tid_t(pthread_self());
-#endif
-}
-
lldb::thread_t Host::GetCurrentThread() {
return lldb::thread_t(pthread_self());
}
@@ -421,25 +409,6 @@ const char *Host::GetSignalAsCString(int signo) {
#endif
-#ifndef _WIN32
-
-lldb::thread_key_t
-Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) {
- pthread_key_t key;
- ::pthread_key_create(&key, callback);
- return key;
-}
-
-void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) {
- return ::pthread_getspecific(key);
-}
-
-void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) {
- ::pthread_setspecific(key, value);
-}
-
-#endif
-
#if !defined(__APPLE__) // see Host.mm
bool Host::GetBundleDirectory(const FileSpec &file, FileSpec &bundle) {
@@ -498,19 +467,19 @@ MonitorShellCommand(std::shared_ptr<ShellInfo> shell_info, lldb::pid_t pid,
return true;
}
-Error Host::RunShellCommand(const char *command, const FileSpec &working_dir,
- int *status_ptr, int *signo_ptr,
- std::string *command_output_ptr,
- uint32_t timeout_sec, bool run_in_default_shell) {
+Status Host::RunShellCommand(const char *command, const FileSpec &working_dir,
+ int *status_ptr, int *signo_ptr,
+ std::string *command_output_ptr,
+ uint32_t timeout_sec, bool run_in_default_shell) {
return RunShellCommand(Args(command), working_dir, status_ptr, signo_ptr,
command_output_ptr, timeout_sec, run_in_default_shell);
}
-Error Host::RunShellCommand(const Args &args, const FileSpec &working_dir,
- int *status_ptr, int *signo_ptr,
- std::string *command_output_ptr,
- uint32_t timeout_sec, bool run_in_default_shell) {
- Error error;
+Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir,
+ int *status_ptr, int *signo_ptr,
+ std::string *command_output_ptr,
+ uint32_t timeout_sec, bool run_in_default_shell) {
+ Status error;
ProcessLaunchInfo launch_info;
launch_info.SetArchitecture(HostInfo::GetArchitecture());
if (run_in_default_shell) {
@@ -601,382 +570,33 @@ Error Host::RunShellCommand(const Args &args, const FileSpec &working_dir,
error.SetErrorStringWithFormat(
"shell command output is too large to fit into a std::string");
} else {
- std::vector<char> command_output(file_size);
- output_file_spec.ReadFileContents(0, command_output.data(),
- file_size, &error);
+ auto Buffer =
+ DataBufferLLVM::CreateFromPath(output_file_spec.GetPath());
if (error.Success())
- command_output_ptr->assign(command_output.data(), file_size);
+ command_output_ptr->assign(Buffer->GetChars(),
+ Buffer->GetByteSize());
}
}
}
}
}
- if (FileSystem::GetFileExists(output_file_spec))
- FileSystem::Unlink(output_file_spec);
+ llvm::sys::fs::remove(output_file_spec.GetPath());
return error;
}
-// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC
-// systems
-
-#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \
- defined(__GLIBC__) || defined(__NetBSD__)
-#if !defined(__ANDROID__)
-// this method needs to be visible to macosx/Host.cpp and
-// common/Host.cpp.
-
-short Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) {
- short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
-
-#if defined(__APPLE__)
- if (launch_info.GetFlags().Test(eLaunchFlagExec))
- flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag
-
- if (launch_info.GetFlags().Test(eLaunchFlagDebug))
- flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag
-
- if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
- flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag
-
- if (launch_info.GetLaunchInSeparateProcessGroup())
- flags |= POSIX_SPAWN_SETPGROUP;
-
-#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
-#if defined(__APPLE__) && (defined(__x86_64__) || defined(__i386__))
- static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
- if (g_use_close_on_exec_flag == eLazyBoolCalculate) {
- g_use_close_on_exec_flag = eLazyBoolNo;
-
- uint32_t major, minor, update;
- if (HostInfo::GetOSVersion(major, minor, update)) {
- // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or
- // earlier
- if (major > 10 || (major == 10 && minor > 7)) {
- // Only enable for 10.8 and later OS versions
- g_use_close_on_exec_flag = eLazyBoolYes;
- }
- }
- }
-#else
- static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
-#endif
- // Close all files exception those with file actions if this is supported.
- if (g_use_close_on_exec_flag == eLazyBoolYes)
- flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
-#endif
-#endif // #if defined (__APPLE__)
- return flags;
-}
-
-Error Host::LaunchProcessPosixSpawn(const char *exe_path,
- const ProcessLaunchInfo &launch_info,
- lldb::pid_t &pid) {
- Error error;
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
- LIBLLDB_LOG_PROCESS));
-
- posix_spawnattr_t attr;
- error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX);
-
- if (error.Fail() || log)
- error.PutToLog(log, "::posix_spawnattr_init ( &attr )");
- if (error.Fail())
- return error;
-
- // Make a quick class that will cleanup the posix spawn attributes in case
- // we return in the middle of this function.
- lldb_utility::CleanUp<posix_spawnattr_t *, int> posix_spawnattr_cleanup(
- &attr, posix_spawnattr_destroy);
-
- sigset_t no_signals;
- sigset_t all_signals;
- sigemptyset(&no_signals);
- sigfillset(&all_signals);
- ::posix_spawnattr_setsigmask(&attr, &no_signals);
-#if defined(__linux__) || defined(__FreeBSD__)
- ::posix_spawnattr_setsigdefault(&attr, &no_signals);
-#else
- ::posix_spawnattr_setsigdefault(&attr, &all_signals);
-#endif
-
- short flags = GetPosixspawnFlags(launch_info);
-
- error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX);
- if (error.Fail() || log)
- error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )",
- flags);
- if (error.Fail())
- return error;
-
-// posix_spawnattr_setbinpref_np appears to be an Apple extension per:
-// http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
-#if defined(__APPLE__) && !defined(__arm__)
-
- // Don't set the binpref if a shell was provided. After all, that's only
- // going to affect what version of the shell
- // is launched, not what fork of the binary is launched. We insert "arch
- // --arch <ARCH> as part of the shell invocation
- // to do that job on OSX.
-
- if (launch_info.GetShell() == nullptr) {
- // We don't need to do this for ARM, and we really shouldn't now that we
- // have multiple CPU subtypes and no posix_spawnattr call that allows us
- // to set which CPU subtype to launch...
- const ArchSpec &arch_spec = launch_info.GetArchitecture();
- cpu_type_t cpu = arch_spec.GetMachOCPUType();
- cpu_type_t sub = arch_spec.GetMachOCPUSubType();
- if (cpu != 0 && cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
- cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
- !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try
- // to set the CPU type or we will fail
- {
- size_t ocount = 0;
- error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount),
- eErrorTypePOSIX);
- if (error.Fail() || log)
- error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, "
- "cpu_type = 0x%8.8x, count => %llu )",
- cpu, (uint64_t)ocount);
-
- if (error.Fail() || ocount != 1)
- return error;
- }
- }
-
-#endif
-
- const char *tmp_argv[2];
- char *const *argv = const_cast<char *const *>(
- launch_info.GetArguments().GetConstArgumentVector());
- char *const *envp = const_cast<char *const *>(
- launch_info.GetEnvironmentEntries().GetConstArgumentVector());
- if (argv == NULL) {
- // posix_spawn gets very unhappy if it doesn't have at least the program
- // name in argv[0]. One of the side affects I have noticed is the
- // environment
- // variables don't make it into the child process if "argv == NULL"!!!
- tmp_argv[0] = exe_path;
- tmp_argv[1] = NULL;
- argv = const_cast<char *const *>(tmp_argv);
- }
-
+// The functions below implement process launching for non-Apple-based platforms
#if !defined(__APPLE__)
- // manage the working directory
- char current_dir[PATH_MAX];
- current_dir[0] = '\0';
-#endif
-
- FileSpec working_dir{launch_info.GetWorkingDirectory()};
- if (working_dir) {
-#if defined(__APPLE__)
- // Set the working directory on this thread only
- if (__pthread_chdir(working_dir.GetCString()) < 0) {
- if (errno == ENOENT) {
- error.SetErrorStringWithFormat("No such file or directory: %s",
- working_dir.GetCString());
- } else if (errno == ENOTDIR) {
- error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
- working_dir.GetCString());
- } else {
- error.SetErrorStringWithFormat("An unknown error occurred when "
- "changing directory for process "
- "execution.");
- }
- return error;
- }
-#else
- if (::getcwd(current_dir, sizeof(current_dir)) == NULL) {
- error.SetError(errno, eErrorTypePOSIX);
- error.LogIfError(log, "unable to save the current directory");
- return error;
- }
-
- if (::chdir(working_dir.GetCString()) == -1) {
- error.SetError(errno, eErrorTypePOSIX);
- error.LogIfError(log, "unable to change working directory to %s",
- working_dir.GetCString());
- return error;
- }
-#endif
- }
-
- ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
- const size_t num_file_actions = launch_info.GetNumFileActions();
- if (num_file_actions > 0) {
- posix_spawn_file_actions_t file_actions;
- error.SetError(::posix_spawn_file_actions_init(&file_actions),
- eErrorTypePOSIX);
- if (error.Fail() || log)
- error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )");
- if (error.Fail())
- return error;
-
- // Make a quick class that will cleanup the posix spawn attributes in case
- // we return in the middle of this function.
- lldb_utility::CleanUp<posix_spawn_file_actions_t *, int>
- posix_spawn_file_actions_cleanup(&file_actions,
- posix_spawn_file_actions_destroy);
-
- for (size_t i = 0; i < num_file_actions; ++i) {
- const FileAction *launch_file_action =
- launch_info.GetFileActionAtIndex(i);
- if (launch_file_action) {
- if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log,
- error))
- return error;
- }
- }
-
- error.SetError(
- ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),
- eErrorTypePOSIX);
-
- if (error.Fail() || log) {
- error.PutToLog(
- log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, "
- "attr = %p, argv = %p, envp = %p )",
- result_pid, exe_path, static_cast<void *>(&file_actions),
- static_cast<void *>(&attr), reinterpret_cast<const void *>(argv),
- reinterpret_cast<const void *>(envp));
- if (log) {
- for (int ii = 0; argv[ii]; ++ii)
- log->Printf("argv[%i] = '%s'", ii, argv[ii]);
- }
- }
-
- } else {
- error.SetError(
- ::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),
- eErrorTypePOSIX);
-
- if (error.Fail() || log) {
- error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', "
- "file_actions = NULL, attr = %p, argv = %p, envp = "
- "%p )",
- result_pid, exe_path, static_cast<void *>(&attr),
- reinterpret_cast<const void *>(argv),
- reinterpret_cast<const void *>(envp));
- if (log) {
- for (int ii = 0; argv[ii]; ++ii)
- log->Printf("argv[%i] = '%s'", ii, argv[ii]);
- }
- }
- }
- pid = result_pid;
-
- if (working_dir) {
-#if defined(__APPLE__)
- // No more thread specific current working directory
- __pthread_fchdir(-1);
-#else
- if (::chdir(current_dir) == -1 && error.Success()) {
- error.SetError(errno, eErrorTypePOSIX);
- error.LogIfError(log, "unable to change current directory back to %s",
- current_dir);
- }
-#endif
- }
-
- return error;
-}
-
-bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,
- Log *log, Error &error) {
- if (info == NULL)
- return false;
-
- posix_spawn_file_actions_t *file_actions =
- reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);
-
- switch (info->GetAction()) {
- case FileAction::eFileActionNone:
- error.Clear();
- break;
-
- case FileAction::eFileActionClose:
- if (info->GetFD() == -1)
- error.SetErrorString(
- "invalid fd for posix_spawn_file_actions_addclose(...)");
- else {
- error.SetError(
- ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()),
- eErrorTypePOSIX);
- if (log && (error.Fail() || log))
- error.PutToLog(log,
- "posix_spawn_file_actions_addclose (action=%p, fd=%i)",
- static_cast<void *>(file_actions), info->GetFD());
- }
- break;
-
- case FileAction::eFileActionDuplicate:
- if (info->GetFD() == -1)
- error.SetErrorString(
- "invalid fd for posix_spawn_file_actions_adddup2(...)");
- else if (info->GetActionArgument() == -1)
- error.SetErrorString(
- "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
- else {
- error.SetError(
- ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(),
- info->GetActionArgument()),
- eErrorTypePOSIX);
- if (log && (error.Fail() || log))
- error.PutToLog(
- log,
- "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)",
- static_cast<void *>(file_actions), info->GetFD(),
- info->GetActionArgument());
- }
- break;
-
- case FileAction::eFileActionOpen:
- if (info->GetFD() == -1)
- error.SetErrorString(
- "invalid fd in posix_spawn_file_actions_addopen(...)");
- else {
- int oflag = info->GetActionArgument();
-
- mode_t mode = 0;
-
- if (oflag & O_CREAT)
- mode = 0640;
-
- error.SetError(::posix_spawn_file_actions_addopen(
- file_actions, info->GetFD(),
- info->GetPath().str().c_str(), oflag, mode),
- eErrorTypePOSIX);
- if (error.Fail() || log)
- error.PutToLog(log, "posix_spawn_file_actions_addopen (action=%p, "
- "fd=%i, path='%s', oflag=%i, mode=%i)",
- static_cast<void *>(file_actions), info->GetFD(),
- info->GetPath().str().c_str(), oflag, mode);
- }
- break;
- }
- return error.Success();
-}
-#endif // !defined(__ANDROID__)
-#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) ||
- // defined (__GLIBC__) || defined(__NetBSD__)
-
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || \
- defined(__NetBSD__) || defined(_WIN32)
-// The functions below implement process launching via posix_spawn() for Linux,
-// FreeBSD and NetBSD.
-
-Error Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
+Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
std::unique_ptr<ProcessLauncher> delegate_launcher;
#if defined(_WIN32)
delegate_launcher.reset(new ProcessLauncherWindows());
-#elif defined(__linux__)
- delegate_launcher.reset(new ProcessLauncherLinux());
#else
- delegate_launcher.reset(new ProcessLauncherPosix());
+ delegate_launcher.reset(new ProcessLauncherPosixFork());
#endif
MonitoringProcessLauncher launcher(std::move(delegate_launcher));
- Error error;
+ Status error;
HostProcess process = launcher.LaunchProcess(launch_info, error);
// TODO(zturner): It would be better if the entire HostProcess were returned
@@ -986,7 +606,7 @@ Error Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
return error;
}
-#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
+#endif // !defined(__APPLE__)
#ifndef _WIN32
void Host::Kill(lldb::pid_t pid, int signo) { ::kill(pid, signo); }
@@ -1006,3 +626,59 @@ const UnixSignalsSP &Host::GetUnixSignals() {
UnixSignals::Create(HostInfo::GetArchitecture());
return s_unix_signals_sp;
}
+
+std::unique_ptr<Connection> Host::CreateDefaultConnection(llvm::StringRef url) {
+#if defined(_WIN32)
+ if (url.startswith("file://"))
+ return std::unique_ptr<Connection>(new ConnectionGenericFile());
+#endif
+ return std::unique_ptr<Connection>(new ConnectionFileDescriptor());
+}
+
+#if defined(LLVM_ON_UNIX)
+WaitStatus WaitStatus::Decode(int wstatus) {
+ if (WIFEXITED(wstatus))
+ return {Exit, uint8_t(WEXITSTATUS(wstatus))};
+ else if (WIFSIGNALED(wstatus))
+ return {Signal, uint8_t(WTERMSIG(wstatus))};
+ else if (WIFSTOPPED(wstatus))
+ return {Stop, uint8_t(WSTOPSIG(wstatus))};
+ llvm_unreachable("Unknown wait status");
+}
+#endif
+
+void llvm::format_provider<WaitStatus>::format(const WaitStatus &WS,
+ raw_ostream &OS,
+ StringRef Options) {
+ if (Options == "g") {
+ char type;
+ switch (WS.type) {
+ case WaitStatus::Exit:
+ type = 'W';
+ break;
+ case WaitStatus::Signal:
+ type = 'X';
+ break;
+ case WaitStatus::Stop:
+ type = 'S';
+ break;
+ }
+ OS << formatv("{0}{1:x-2}", type, WS.status);
+ return;
+ }
+
+ assert(Options.empty());
+ const char *desc;
+ switch(WS.type) {
+ case WaitStatus::Exit:
+ desc = "Exited with status";
+ break;
+ case WaitStatus::Signal:
+ desc = "Killed by signal";
+ break;
+ case WaitStatus::Stop:
+ desc = "Stopped by signal";
+ break;
+ }
+ OS << desc << " " << int(WS.status);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp
index 01ac870..a6c9e91 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp
@@ -10,21 +10,22 @@
#include "lldb/Host/Config.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/HostInfoBase.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
-#include <mutex> // std::once
+#include <mutex>
#include <thread>
using namespace lldb;
@@ -45,13 +46,10 @@ struct HostInfoBaseFields {
// Remove the LLDB temporary directory if we have one. Set "recurse" to
// true to all files that were created for the LLDB process can be cleaned
// up.
- FileSystem::DeleteDirectory(m_lldb_process_tmp_dir, true);
+ llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath());
}
}
- uint32_t m_number_cpus;
- std::string m_vendor_string;
- std::string m_os_string;
std::string m_host_triple;
ArchSpec m_host_arch_32;
@@ -78,37 +76,9 @@ void HostInfoBase::Terminate() {
g_fields = nullptr;
}
-uint32_t HostInfoBase::GetNumberCPUS() {
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
- g_fields->m_number_cpus = std::thread::hardware_concurrency();
- });
- return g_fields->m_number_cpus;
-}
-
-uint32_t HostInfoBase::GetMaxThreadNameLength() { return 0; }
-
-llvm::StringRef HostInfoBase::GetVendorString() {
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
- g_fields->m_vendor_string =
- HostInfo::GetArchitecture().GetTriple().getVendorName().str();
- });
- return g_fields->m_vendor_string;
-}
-
-llvm::StringRef HostInfoBase::GetOSString() {
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
- g_fields->m_os_string =
- std::move(HostInfo::GetArchitecture().GetTriple().getOSName());
- });
- return g_fields->m_os_string;
-}
-
llvm::StringRef HostInfoBase::GetTargetTriple() {
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
g_fields->m_host_triple =
HostInfo::GetArchitecture().GetTriple().getTriple();
});
@@ -116,8 +86,8 @@ llvm::StringRef HostInfoBase::GetTargetTriple() {
}
const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) {
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32,
g_fields->m_host_arch_64);
});
@@ -144,9 +114,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
FileSpec *result = nullptr;
switch (type) {
case lldb::ePathTypeLLDBShlibDir: {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
static bool success = false;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
success =
HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
@@ -158,9 +128,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
result = &g_fields->m_lldb_so_dir;
} break;
case lldb::ePathTypeSupportExecutableDir: {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
static bool success = false;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeSupportExeDirectory(
g_fields->m_lldb_support_exe_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
@@ -173,9 +143,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
result = &g_fields->m_lldb_support_exe_dir;
} break;
case lldb::ePathTypeHeaderDir: {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
static bool success = false;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
@@ -186,9 +156,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
result = &g_fields->m_lldb_headers_dir;
} break;
case lldb::ePathTypePythonDir: {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
static bool success = false;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
@@ -199,9 +169,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
result = &g_fields->m_lldb_python_dir;
} break;
case lldb::ePathTypeClangDir: {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
static bool success = false;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
success =
HostInfo::ComputeClangDirectory(g_fields->m_lldb_clang_resource_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
@@ -214,9 +184,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
result = &g_fields->m_lldb_clang_resource_dir;
} break;
case lldb::ePathTypeLLDBSystemPlugins: {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
static bool success = false;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeSystemPluginsDirectory(
g_fields->m_lldb_system_plugin_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
@@ -229,9 +199,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
result = &g_fields->m_lldb_system_plugin_dir;
} break;
case lldb::ePathTypeLLDBUserPlugins: {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
static bool success = false;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeUserPluginsDirectory(
g_fields->m_lldb_user_plugin_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
@@ -244,9 +214,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
result = &g_fields->m_lldb_user_plugin_dir;
} break;
case lldb::ePathTypeLLDBTempSystemDir: {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
static bool success = false;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeProcessTempFileDirectory(
g_fields->m_lldb_process_tmp_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
@@ -259,9 +229,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
result = &g_fields->m_lldb_process_tmp_dir;
} break;
case lldb::ePathTypeGlobalLLDBTempSystemDir: {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
static bool success = false;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeGlobalTempFileDirectory(
g_fields->m_lldb_global_tmp_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
@@ -313,9 +283,7 @@ bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
temp_file_spec.AppendPathComponent(pid_str);
- if (!FileSystem::MakeDirectory(temp_file_spec,
- eFilePermissionsDirectoryDefault)
- .Success())
+ if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
return false;
file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
@@ -337,9 +305,7 @@ bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
return false;
temp_file_spec.AppendPathComponent("lldb");
- if (!FileSystem::MakeDirectory(temp_file_spec,
- eFilePermissionsDirectoryDefault)
- .Success())
+ if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
return false;
file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp
index fd39e0d..402d3ca 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp
@@ -8,11 +8,12 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/HostNativeThreadBase.h"
-#include "lldb/Core/Log.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/ThisThread.h"
#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Utility/Log.h"
+
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Threading.h"
using namespace lldb;
using namespace lldb_private;
@@ -52,7 +53,7 @@ lldb::thread_result_t
HostNativeThreadBase::ThreadCreateTrampoline(lldb::thread_arg_t arg) {
ThreadLauncher::HostThreadCreateInfo *info =
(ThreadLauncher::HostThreadCreateInfo *)arg;
- ThisThread::SetName(info->thread_name, HostInfo::GetMaxThreadNameLength());
+ llvm::set_thread_name(info->thread_name);
thread_func_t thread_fptr = info->thread_fptr;
thread_arg_t thread_arg = info->thread_arg;
diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostProcess.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostProcess.cpp
index 2d99d8e..1540333 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/HostProcess.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/HostProcess.cpp
@@ -21,9 +21,9 @@ HostProcess::HostProcess(lldb::process_t process)
HostProcess::~HostProcess() {}
-Error HostProcess::Terminate() { return m_native_process->Terminate(); }
+Status HostProcess::Terminate() { return m_native_process->Terminate(); }
-Error HostProcess::GetMainModule(FileSpec &file_spec) const {
+Status HostProcess::GetMainModule(FileSpec &file_spec) const {
return m_native_process->GetMainModule(file_spec);
}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostThread.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostThread.cpp
index 738b7ef..02882c5 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/HostThread.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/HostThread.cpp
@@ -18,11 +18,11 @@ HostThread::HostThread() : m_native_thread(new HostNativeThread) {}
HostThread::HostThread(lldb::thread_t thread)
: m_native_thread(new HostNativeThread(thread)) {}
-Error HostThread::Join(lldb::thread_result_t *result) {
+Status HostThread::Join(lldb::thread_result_t *result) {
return m_native_thread->Join(result);
}
-Error HostThread::Cancel() { return m_native_thread->Cancel(); }
+Status HostThread::Cancel() { return m_native_thread->Cancel(); }
void HostThread::Reset() { return m_native_thread->Reset(); }
diff --git a/contrib/llvm/tools/lldb/source/Host/common/LockFileBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/LockFileBase.cpp
index b30acc5..a8d7881 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/LockFileBase.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/LockFileBase.cpp
@@ -14,9 +14,9 @@ using namespace lldb_private;
namespace {
-Error AlreadyLocked() { return Error("Already locked"); }
+Status AlreadyLocked() { return Status("Already locked"); }
-Error NotLocked() { return Error("Not locked"); }
+Status NotLocked() { return Status("Not locked"); }
}
LockFileBase::LockFileBase(int fd)
@@ -24,31 +24,31 @@ LockFileBase::LockFileBase(int fd)
bool LockFileBase::IsLocked() const { return m_locked; }
-Error LockFileBase::WriteLock(const uint64_t start, const uint64_t len) {
+Status LockFileBase::WriteLock(const uint64_t start, const uint64_t len) {
return DoLock([&](const uint64_t start,
const uint64_t len) { return DoWriteLock(start, len); },
start, len);
}
-Error LockFileBase::TryWriteLock(const uint64_t start, const uint64_t len) {
+Status LockFileBase::TryWriteLock(const uint64_t start, const uint64_t len) {
return DoLock([&](const uint64_t start,
const uint64_t len) { return DoTryWriteLock(start, len); },
start, len);
}
-Error LockFileBase::ReadLock(const uint64_t start, const uint64_t len) {
+Status LockFileBase::ReadLock(const uint64_t start, const uint64_t len) {
return DoLock([&](const uint64_t start,
const uint64_t len) { return DoReadLock(start, len); },
start, len);
}
-Error LockFileBase::TryReadLock(const uint64_t start, const uint64_t len) {
+Status LockFileBase::TryReadLock(const uint64_t start, const uint64_t len) {
return DoLock([&](const uint64_t start,
const uint64_t len) { return DoTryReadLock(start, len); },
start, len);
}
-Error LockFileBase::Unlock() {
+Status LockFileBase::Unlock() {
if (!IsLocked())
return NotLocked();
@@ -63,10 +63,10 @@ Error LockFileBase::Unlock() {
bool LockFileBase::IsValidFile() const { return m_fd != -1; }
-Error LockFileBase::DoLock(const Locker &locker, const uint64_t start,
- const uint64_t len) {
+Status LockFileBase::DoLock(const Locker &locker, const uint64_t start,
+ const uint64_t len) {
if (!IsValidFile())
- return Error("File is invalid");
+ return Status("File is invalid");
if (IsLocked())
return AlreadyLocked();
diff --git a/contrib/llvm/tools/lldb/source/Host/common/MainLoop.cpp b/contrib/llvm/tools/lldb/source/Host/common/MainLoop.cpp
new file mode 100644
index 0000000..d0e0d00
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/MainLoop.cpp
@@ -0,0 +1,387 @@
+//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Config/llvm-config.h"
+
+#include "lldb/Host/MainLoop.h"
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Utility/Status.h"
+#include <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <csignal>
+#include <time.h>
+#include <vector>
+
+// Multiplexing is implemented using kqueue on systems that support it (BSD
+// variants including OSX). On linux we use ppoll, while android uses pselect
+// (ppoll is present but not implemented properly). On windows we use WSApoll
+// (which does not support signals).
+
+#if HAVE_SYS_EVENT_H
+#include <sys/event.h>
+#elif defined(LLVM_ON_WIN32)
+#include <winsock2.h>
+#else
+#include <poll.h>
+#endif
+
+#ifdef LLVM_ON_WIN32
+#define POLL WSAPoll
+#else
+#define POLL poll
+#endif
+
+#ifdef __ANDROID__
+#define FORCE_PSELECT
+#endif
+
+#if SIGNAL_POLLING_UNSUPPORTED
+#ifdef LLVM_ON_WIN32
+typedef int sigset_t;
+typedef int siginfo_t;
+#endif
+
+int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts,
+ const sigset_t *) {
+ int timeout =
+ (timeout_ts == nullptr)
+ ? -1
+ : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
+ return POLL(fds, nfds, timeout);
+}
+
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+static sig_atomic_t g_signal_flags[NSIG];
+
+static void SignalHandler(int signo, siginfo_t *info, void *) {
+ assert(signo < NSIG);
+ g_signal_flags[signo] = 1;
+}
+
+class MainLoop::RunImpl {
+public:
+ RunImpl(MainLoop &loop);
+ ~RunImpl() = default;
+
+ Status Poll();
+ void ProcessEvents();
+
+private:
+ MainLoop &loop;
+
+#if HAVE_SYS_EVENT_H
+ std::vector<struct kevent> in_events;
+ struct kevent out_events[4];
+ int num_events = -1;
+
+#else
+#ifdef FORCE_PSELECT
+ fd_set read_fd_set;
+#else
+ std::vector<struct pollfd> read_fds;
+#endif
+
+ sigset_t get_sigmask();
+#endif
+};
+
+#if HAVE_SYS_EVENT_H
+MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) {
+ in_events.reserve(loop.m_read_fds.size());
+}
+
+Status MainLoop::RunImpl::Poll() {
+ in_events.resize(loop.m_read_fds.size());
+ unsigned i = 0;
+ for (auto &fd : loop.m_read_fds)
+ EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
+
+ num_events = kevent(loop.m_kqueue, in_events.data(), in_events.size(),
+ out_events, llvm::array_lengthof(out_events), nullptr);
+
+ if (num_events < 0)
+ return Status("kevent() failed with error %d\n", num_events);
+ return Status();
+}
+
+void MainLoop::RunImpl::ProcessEvents() {
+ assert(num_events >= 0);
+ for (int i = 0; i < num_events; ++i) {
+ if (loop.m_terminate_request)
+ return;
+ switch (out_events[i].filter) {
+ case EVFILT_READ:
+ loop.ProcessReadObject(out_events[i].ident);
+ break;
+ case EVFILT_SIGNAL:
+ loop.ProcessSignal(out_events[i].ident);
+ break;
+ default:
+ llvm_unreachable("Unknown event");
+ }
+ }
+}
+#else
+MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) {
+#ifndef FORCE_PSELECT
+ read_fds.reserve(loop.m_read_fds.size());
+#endif
+}
+
+sigset_t MainLoop::RunImpl::get_sigmask() {
+#if SIGNAL_POLLING_UNSUPPORTED
+ return 0;
+#else
+ sigset_t sigmask;
+ int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask);
+ assert(ret == 0);
+ (void) ret;
+
+ for (const auto &sig : loop.m_signals)
+ sigdelset(&sigmask, sig.first);
+ return sigmask;
+#endif
+}
+
+#ifdef FORCE_PSELECT
+Status MainLoop::RunImpl::Poll() {
+ FD_ZERO(&read_fd_set);
+ int nfds = 0;
+ for (const auto &fd : loop.m_read_fds) {
+ FD_SET(fd.first, &read_fd_set);
+ nfds = std::max(nfds, fd.first + 1);
+ }
+
+ sigset_t sigmask = get_sigmask();
+ if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 &&
+ errno != EINTR)
+ return Status(errno, eErrorTypePOSIX);
+
+ return Status();
+}
+#else
+Status MainLoop::RunImpl::Poll() {
+ read_fds.clear();
+
+ sigset_t sigmask = get_sigmask();
+
+ for (const auto &fd : loop.m_read_fds) {
+ struct pollfd pfd;
+ pfd.fd = fd.first;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ read_fds.push_back(pfd);
+ }
+
+ if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
+ errno != EINTR)
+ return Status(errno, eErrorTypePOSIX);
+
+ return Status();
+}
+#endif
+
+void MainLoop::RunImpl::ProcessEvents() {
+#ifdef FORCE_PSELECT
+ // Collect first all readable file descriptors into a separate vector and then
+ // iterate over it to invoke callbacks. Iterating directly over
+ // loop.m_read_fds is not possible because the callbacks can modify the
+ // container which could invalidate the iterator.
+ std::vector<IOObject::WaitableHandle> fds;
+ for (const auto &fd : loop.m_read_fds)
+ if (FD_ISSET(fd.first, &read_fd_set))
+ fds.push_back(fd.first);
+
+ for (const auto &handle : fds) {
+#else
+ for (const auto &fd : read_fds) {
+ if ((fd.revents & POLLIN) == 0)
+ continue;
+ IOObject::WaitableHandle handle = fd.fd;
+#endif
+ if (loop.m_terminate_request)
+ return;
+
+ loop.ProcessReadObject(handle);
+ }
+
+ std::vector<int> signals;
+ for (const auto &entry : loop.m_signals)
+ if (g_signal_flags[entry.first] != 0)
+ signals.push_back(entry.first);
+
+ for (const auto &signal : signals) {
+ if (loop.m_terminate_request)
+ return;
+ g_signal_flags[signal] = 0;
+ loop.ProcessSignal(signal);
+ }
+}
+#endif
+
+MainLoop::MainLoop() {
+#if HAVE_SYS_EVENT_H
+ m_kqueue = kqueue();
+ assert(m_kqueue >= 0);
+#endif
+}
+MainLoop::~MainLoop() {
+#if HAVE_SYS_EVENT_H
+ close(m_kqueue);
+#endif
+ assert(m_read_fds.size() == 0);
+ assert(m_signals.size() == 0);
+}
+
+MainLoop::ReadHandleUP MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
+ const Callback &callback,
+ Status &error) {
+#ifdef LLVM_ON_WIN32
+ if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
+ error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
+ return nullptr;
+ }
+#endif
+ if (!object_sp || !object_sp->IsValid()) {
+ error.SetErrorString("IO object is not valid.");
+ return nullptr;
+ }
+
+ const bool inserted =
+ m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
+ if (!inserted) {
+ error.SetErrorStringWithFormat("File descriptor %d already monitored.",
+ object_sp->GetWaitableHandle());
+ return nullptr;
+ }
+
+ return CreateReadHandle(object_sp);
+}
+
+// We shall block the signal, then install the signal handler. The signal will
+// be unblocked in
+// the Run() function to check for signal delivery.
+MainLoop::SignalHandleUP
+MainLoop::RegisterSignal(int signo, const Callback &callback, Status &error) {
+#ifdef SIGNAL_POLLING_UNSUPPORTED
+ error.SetErrorString("Signal polling is not supported on this platform.");
+ return nullptr;
+#else
+ if (m_signals.find(signo) != m_signals.end()) {
+ error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
+ return nullptr;
+ }
+
+ SignalInfo info;
+ info.callback = callback;
+ struct sigaction new_action;
+ new_action.sa_sigaction = &SignalHandler;
+ new_action.sa_flags = SA_SIGINFO;
+ sigemptyset(&new_action.sa_mask);
+ sigaddset(&new_action.sa_mask, signo);
+ sigset_t old_set;
+
+ g_signal_flags[signo] = 0;
+
+ // Even if using kqueue, the signal handler will still be invoked, so it's
+ // important to replace it with our "bening" handler.
+ int ret = sigaction(signo, &new_action, &info.old_action);
+ assert(ret == 0 && "sigaction failed");
+
+#if HAVE_SYS_EVENT_H
+ struct kevent ev;
+ EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
+ ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr);
+ assert(ret == 0);
+#endif
+
+ // If we're using kqueue, the signal needs to be unblocked in order to recieve
+ // it. If using pselect/ppoll, we need to block it, and later unblock it as a
+ // part of the system call.
+ ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK,
+ &new_action.sa_mask, &old_set);
+ assert(ret == 0 && "pthread_sigmask failed");
+ info.was_blocked = sigismember(&old_set, signo);
+ m_signals.insert({signo, info});
+
+ return SignalHandleUP(new SignalHandle(*this, signo));
+#endif
+}
+
+void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
+ bool erased = m_read_fds.erase(handle);
+ UNUSED_IF_ASSERT_DISABLED(erased);
+ assert(erased);
+}
+
+void MainLoop::UnregisterSignal(int signo) {
+#if SIGNAL_POLLING_UNSUPPORTED
+ Status("Signal polling is not supported on this platform.");
+#else
+ auto it = m_signals.find(signo);
+ assert(it != m_signals.end());
+
+ sigaction(signo, &it->second.old_action, nullptr);
+
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, signo);
+ int ret = pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK,
+ &set, nullptr);
+ assert(ret == 0);
+ (void)ret;
+
+#if HAVE_SYS_EVENT_H
+ struct kevent ev;
+ EV_SET(&ev, signo, EVFILT_SIGNAL, EV_DELETE, 0, 0, 0);
+ ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr);
+ assert(ret == 0);
+#endif
+
+ m_signals.erase(it);
+#endif
+}
+
+Status MainLoop::Run() {
+ m_terminate_request = false;
+
+ Status error;
+ RunImpl impl(*this);
+
+ // run until termination or until we run out of things to listen to
+ while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
+
+ error = impl.Poll();
+ if (error.Fail())
+ return error;
+
+ impl.ProcessEvents();
+
+ if (m_terminate_request)
+ return Status();
+ }
+ return Status();
+}
+
+void MainLoop::ProcessSignal(int signo) {
+ auto it = m_signals.find(signo);
+ if (it != m_signals.end())
+ it->second.callback(*this); // Do the work
+}
+
+void MainLoop::ProcessReadObject(IOObject::WaitableHandle handle) {
+ auto it = m_read_fds.find(handle);
+ if (it != m_read_fds.end())
+ it->second(*this); // Do the work
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp b/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp
index ae98cc8..f1fcd0b 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp
@@ -8,14 +8,16 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/MonitoringProcessLauncher.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/HostProcess.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/ProcessLaunchInfo.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+
+#include "llvm/Support/FileSystem.h"
using namespace lldb;
using namespace lldb_private;
@@ -26,7 +28,7 @@ MonitoringProcessLauncher::MonitoringProcessLauncher(
HostProcess
MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info,
- Error &error) {
+ Status &error) {
ProcessLaunchInfo resolved_info(launch_info);
error.Clear();
@@ -38,8 +40,9 @@ MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info,
FileSpec exe_spec(resolved_info.GetExecutableFile());
- FileSpec::FileType file_type = exe_spec.GetFileType();
- if (file_type != FileSpec::eFileTypeRegular) {
+ llvm::sys::fs::file_status stats;
+ status(exe_spec.GetPath(), stats);
+ if (!is_regular_file(stats)) {
ModuleSpec module_spec(exe_spec, arch_spec);
lldb::ModuleSP exe_module_sp;
error =
@@ -48,11 +51,13 @@ MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info,
if (error.Fail())
return HostProcess();
- if (exe_module_sp)
+ if (exe_module_sp) {
exe_spec = exe_module_sp->GetFileSpec();
+ status(exe_spec.GetPath(), stats);
+ }
}
- if (exe_spec.Exists()) {
+ if (exists(stats)) {
exe_spec.GetPath(exe_path, sizeof(exe_path));
} else {
resolved_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp
index d61a2f5..5eee3de 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp
@@ -9,8 +9,8 @@
#include "lldb/Host/common/NativeBreakpoint.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-defines.h"
using namespace lldb_private;
@@ -44,7 +44,7 @@ int32_t NativeBreakpoint::DecRef() {
return m_ref_count;
}
-Error NativeBreakpoint::Enable() {
+Status NativeBreakpoint::Enable() {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (m_enabled) {
@@ -53,7 +53,7 @@ Error NativeBreakpoint::Enable() {
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64
" already enabled, ignoring.",
__FUNCTION__, m_addr);
- return Error();
+ return Status();
}
// Log and enable.
@@ -61,7 +61,7 @@ Error NativeBreakpoint::Enable() {
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64 " enabling...",
__FUNCTION__, m_addr);
- Error error = DoEnable();
+ Status error = DoEnable();
if (error.Success()) {
m_enabled = true;
if (log)
@@ -76,7 +76,7 @@ Error NativeBreakpoint::Enable() {
return error;
}
-Error NativeBreakpoint::Disable() {
+Status NativeBreakpoint::Disable() {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (!m_enabled) {
@@ -85,7 +85,7 @@ Error NativeBreakpoint::Disable() {
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64
" already disabled, ignoring.",
__FUNCTION__, m_addr);
- return Error();
+ return Status();
}
// Log and disable.
@@ -93,7 +93,7 @@ Error NativeBreakpoint::Disable() {
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64 " disabling...",
__FUNCTION__, m_addr);
- Error error = DoDisable();
+ Status error = DoDisable();
if (error.Success()) {
m_enabled = false;
if (log)
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp
index df5bce8..ce5eb94 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp
@@ -9,7 +9,7 @@
#include "lldb/Host/common/NativeBreakpointList.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
#include "lldb/Host/common/NativeBreakpoint.h"
#include "lldb/Host/common/SoftwareBreakpoint.h"
@@ -19,9 +19,9 @@ using namespace lldb_private;
NativeBreakpointList::NativeBreakpointList() : m_mutex() {}
-Error NativeBreakpointList::AddRef(lldb::addr_t addr, size_t size_hint,
- bool hardware,
- CreateBreakpointFunc create_func) {
+Status NativeBreakpointList::AddRef(lldb::addr_t addr, size_t size_hint,
+ bool hardware,
+ CreateBreakpointFunc create_func) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
@@ -40,7 +40,7 @@ Error NativeBreakpointList::AddRef(lldb::addr_t addr, size_t size_hint,
__FUNCTION__, addr);
iter->second->AddRef();
- return Error();
+ return Status();
}
// Create a new breakpoint using the given create func.
@@ -51,7 +51,7 @@ Error NativeBreakpointList::AddRef(lldb::addr_t addr, size_t size_hint,
__FUNCTION__, addr, size_hint, hardware ? "true" : "false");
NativeBreakpointSP breakpoint_sp;
- Error error = create_func(addr, size_hint, hardware, breakpoint_sp);
+ Status error = create_func(addr, size_hint, hardware, breakpoint_sp);
if (error.Fail()) {
if (log)
log->Printf(
@@ -70,8 +70,8 @@ Error NativeBreakpointList::AddRef(lldb::addr_t addr, size_t size_hint,
return error;
}
-Error NativeBreakpointList::DecRef(lldb::addr_t addr) {
- Error error;
+Status NativeBreakpointList::DecRef(lldb::addr_t addr) {
+ Status error;
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
@@ -142,7 +142,7 @@ Error NativeBreakpointList::DecRef(lldb::addr_t addr) {
return error;
}
-Error NativeBreakpointList::EnableBreakpoint(lldb::addr_t addr) {
+Status NativeBreakpointList::EnableBreakpoint(lldb::addr_t addr) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
@@ -157,14 +157,14 @@ Error NativeBreakpointList::EnableBreakpoint(lldb::addr_t addr) {
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND",
__FUNCTION__, addr);
- return Error("breakpoint not found");
+ return Status("breakpoint not found");
}
// Enable it.
return iter->second->Enable();
}
-Error NativeBreakpointList::DisableBreakpoint(lldb::addr_t addr) {
+Status NativeBreakpointList::DisableBreakpoint(lldb::addr_t addr) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
@@ -179,15 +179,15 @@ Error NativeBreakpointList::DisableBreakpoint(lldb::addr_t addr) {
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND",
__FUNCTION__, addr);
- return Error("breakpoint not found");
+ return Status("breakpoint not found");
}
// Disable it.
return iter->second->Disable();
}
-Error NativeBreakpointList::GetBreakpoint(lldb::addr_t addr,
- NativeBreakpointSP &breakpoint_sp) {
+Status NativeBreakpointList::GetBreakpoint(lldb::addr_t addr,
+ NativeBreakpointSP &breakpoint_sp) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
@@ -200,16 +200,16 @@ Error NativeBreakpointList::GetBreakpoint(lldb::addr_t addr,
if (iter == m_breakpoints.end()) {
// Not found!
breakpoint_sp.reset();
- return Error("breakpoint not found");
+ return Status("breakpoint not found");
}
// Disable it.
breakpoint_sp = iter->second;
- return Error();
+ return Status();
}
-Error NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf,
- size_t size) const {
+Status NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf,
+ size_t size) const {
for (const auto &map : m_breakpoints) {
lldb::addr_t bp_addr = map.first;
// Breapoint not in range, ignore
@@ -225,5 +225,5 @@ Error NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf,
auto opcode_size = software_bp_sp->m_opcode_size;
::memcpy(opcode_addr, saved_opcodes, opcode_size);
}
- return Error();
+ return Status();
}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp
index d77b8b2..b5b6e9d 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp
@@ -10,7 +10,6 @@
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/State.h"
#include "lldb/Host/Host.h"
@@ -20,6 +19,7 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
#include "lldb/lldb-enumerations.h"
using namespace lldb;
@@ -29,15 +29,16 @@ using namespace lldb_private;
// NativeProcessProtocol Members
// -----------------------------------------------------------------------------
-NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid)
- : m_pid(pid), m_threads(), m_current_thread_id(LLDB_INVALID_THREAD_ID),
- m_threads_mutex(), m_state(lldb::eStateInvalid), m_state_mutex(),
- m_exit_type(eExitTypeInvalid), m_exit_status(0), m_exit_description(),
- m_delegates_mutex(), m_delegates(), m_breakpoint_list(),
- m_watchpoint_list(), m_terminal_fd(-1), m_stop_id(0) {}
+NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid, int terminal_fd,
+ NativeDelegate &delegate)
+ : m_pid(pid), m_terminal_fd(terminal_fd) {
+ bool registered = RegisterNativeDelegate(delegate);
+ assert(registered);
+ (void)registered;
+}
-lldb_private::Error NativeProcessProtocol::Interrupt() {
- Error error;
+lldb_private::Status NativeProcessProtocol::Interrupt() {
+ Status error;
#if !defined(SIGSTOP)
error.SetErrorString("local host does not support signaling");
return error;
@@ -46,53 +47,42 @@ lldb_private::Error NativeProcessProtocol::Interrupt() {
#endif
}
-lldb_private::Error
+Status NativeProcessProtocol::IgnoreSignals(llvm::ArrayRef<int> signals) {
+ m_signals_to_ignore.clear();
+ m_signals_to_ignore.insert(signals.begin(), signals.end());
+ return Status();
+}
+
+lldb_private::Status
NativeProcessProtocol::GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &range_info) {
// Default: not implemented.
- return Error("not implemented");
+ return Status("not implemented");
}
-bool NativeProcessProtocol::GetExitStatus(ExitType *exit_type, int *status,
- std::string &exit_description) {
- if (m_state == lldb::eStateExited) {
- *exit_type = m_exit_type;
- *status = m_exit_status;
- exit_description = m_exit_description;
- return true;
- }
+llvm::Optional<WaitStatus> NativeProcessProtocol::GetExitStatus() {
+ if (m_state == lldb::eStateExited)
+ return m_exit_status;
- *status = 0;
- return false;
+ return llvm::None;
}
-bool NativeProcessProtocol::SetExitStatus(ExitType exit_type, int status,
- const char *exit_description,
+bool NativeProcessProtocol::SetExitStatus(WaitStatus status,
bool bNotifyStateChange) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("NativeProcessProtocol::%s(%d, %d, %s, %s) called",
- __FUNCTION__, exit_type, status,
- exit_description ? exit_description : "nullptr",
- bNotifyStateChange ? "true" : "false");
+ LLDB_LOG(log, "status = {0}, notify = {1}", status, bNotifyStateChange);
// Exit status already set
if (m_state == lldb::eStateExited) {
- if (log)
- log->Printf("NativeProcessProtocol::%s exit status already set to %d, "
- "ignoring new set to %d",
- __FUNCTION__, m_exit_status, status);
+ if (m_exit_status)
+ LLDB_LOG(log, "exit status already set to {0}", *m_exit_status);
+ else
+ LLDB_LOG(log, "state is exited, but status not set");
return false;
}
m_state = lldb::eStateExited;
-
- m_exit_type = exit_type;
m_exit_status = status;
- if (exit_description && exit_description[0])
- m_exit_description = exit_description;
- else
- m_exit_description.clear();
if (bNotifyStateChange)
SynchronouslyNotifyProcessStateChanged(lldb::eStateExited);
@@ -139,11 +129,8 @@ NativeProcessProtocol::GetWatchpointMap() const {
return m_watchpoint_list.GetWatchpointMap();
}
-uint32_t NativeProcessProtocol::GetMaxWatchpoints() const {
- // This default implementation will return the number of
- // *hardware* breakpoints available. MacOSX and other OS
- // implementations that support software breakpoints will want to
- // override this correctly for their implementation.
+llvm::Optional<std::pair<uint32_t, uint32_t>>
+NativeProcessProtocol::GetHardwareDebugSupportInfo() const {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
// get any thread
@@ -154,7 +141,7 @@ uint32_t NativeProcessProtocol::GetMaxWatchpoints() const {
log->Warning("NativeProcessProtocol::%s (): failed to find a thread to "
"grab a NativeRegisterContext!",
__FUNCTION__);
- return 0;
+ return llvm::None;
}
NativeRegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
@@ -163,15 +150,16 @@ uint32_t NativeProcessProtocol::GetMaxWatchpoints() const {
log->Warning("NativeProcessProtocol::%s (): failed to get a "
"RegisterContextNativeProcess from the first thread!",
__FUNCTION__);
- return 0;
+ return llvm::None;
}
- return reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return std::make_pair(reg_ctx_sp->NumSupportedHardwareBreakpoints(),
+ reg_ctx_sp->NumSupportedHardwareWatchpoints());
}
-Error NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size,
- uint32_t watch_flags,
- bool hardware) {
+Status NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags,
+ bool hardware) {
// This default implementation assumes setting the watchpoint for
// the process will require setting the watchpoint for each of the
// threads. Furthermore, it will track watchpoints set for the
@@ -201,7 +189,7 @@ Error NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size,
if (!thread_sp)
continue;
- Error thread_error =
+ Status thread_error =
thread_sp->SetWatchpoint(addr, size, watch_flags, hardware);
if (thread_error.Fail() && hardware) {
// Try software watchpoints since we failed on hardware watchpoint setting
@@ -223,7 +211,7 @@ Error NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size,
// set so that we get back to a consistent state of "not
// set" for the watchpoint.
for (auto unwatch_thread_sp : watchpoint_established_threads) {
- Error remove_error = unwatch_thread_sp->RemoveWatchpoint(addr);
+ Status remove_error = unwatch_thread_sp->RemoveWatchpoint(addr);
if (remove_error.Fail() && log) {
log->Warning("NativeProcessProtocol::%s (): RemoveWatchpoint failed "
"for pid=%" PRIu64 ", tid=%" PRIu64 ": %s",
@@ -238,11 +226,11 @@ Error NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size,
return m_watchpoint_list.Add(addr, size, watch_flags, hardware);
}
-Error NativeProcessProtocol::RemoveWatchpoint(lldb::addr_t addr) {
+Status NativeProcessProtocol::RemoveWatchpoint(lldb::addr_t addr) {
// Update the thread list
UpdateThreads();
- Error overall_error;
+ Status overall_error;
std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
for (auto thread_sp : m_threads) {
@@ -250,7 +238,7 @@ Error NativeProcessProtocol::RemoveWatchpoint(lldb::addr_t addr) {
if (!thread_sp)
continue;
- const Error thread_error = thread_sp->RemoveWatchpoint(addr);
+ const Status thread_error = thread_sp->RemoveWatchpoint(addr);
if (thread_error.Fail()) {
// Keep track of the first thread error if any threads
// fail. We want to try to remove the watchpoint from
@@ -259,10 +247,97 @@ Error NativeProcessProtocol::RemoveWatchpoint(lldb::addr_t addr) {
overall_error = thread_error;
}
}
- const Error error = m_watchpoint_list.Remove(addr);
+ const Status error = m_watchpoint_list.Remove(addr);
return overall_error.Fail() ? overall_error : error;
}
+const HardwareBreakpointMap &
+NativeProcessProtocol::GetHardwareBreakpointMap() const {
+ return m_hw_breakpoints_map;
+}
+
+Status NativeProcessProtocol::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ // This default implementation assumes setting a hardware breakpoint for
+ // this process will require setting same hardware breakpoint for each
+ // of its existing threads. New thread will do the same once created.
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Update the thread list
+ UpdateThreads();
+
+ // Exit here if target does not have required hardware breakpoint capability.
+ auto hw_debug_cap = GetHardwareDebugSupportInfo();
+
+ if (hw_debug_cap == llvm::None || hw_debug_cap->first == 0 ||
+ hw_debug_cap->first <= m_hw_breakpoints_map.size())
+ return Status("Target does not have required no of hardware breakpoints");
+
+ // Vector below stores all thread pointer for which we have we successfully
+ // set this hardware breakpoint. If any of the current process threads fails
+ // to set this hardware breakpoint then roll back and remove this breakpoint
+ // for all the threads that had already set it successfully.
+ std::vector<NativeThreadProtocolSP> breakpoint_established_threads;
+
+ // Request to set a hardware breakpoint for each of current process threads.
+ std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
+ for (auto thread_sp : m_threads) {
+ assert(thread_sp && "thread list should not have a NULL thread!");
+ if (!thread_sp)
+ continue;
+
+ Status thread_error = thread_sp->SetHardwareBreakpoint(addr, size);
+ if (thread_error.Success()) {
+ // Remember that we set this breakpoint successfully in
+ // case we need to clear it later.
+ breakpoint_established_threads.push_back(thread_sp);
+ } else {
+ // Unset the breakpoint for each thread we successfully
+ // set so that we get back to a consistent state of "not
+ // set" for this hardware breakpoint.
+ for (auto rollback_thread_sp : breakpoint_established_threads) {
+ Status remove_error =
+ rollback_thread_sp->RemoveHardwareBreakpoint(addr);
+ if (remove_error.Fail() && log) {
+ log->Warning("NativeProcessProtocol::%s (): RemoveHardwareBreakpoint"
+ " failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s",
+ __FUNCTION__, GetID(), rollback_thread_sp->GetID(),
+ remove_error.AsCString());
+ }
+ }
+
+ return thread_error;
+ }
+ }
+
+ // Register new hardware breakpoint into hardware breakpoints map of current
+ // process.
+ m_hw_breakpoints_map[addr] = {addr, size};
+
+ return Status();
+}
+
+Status NativeProcessProtocol::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+ // Update the thread list
+ UpdateThreads();
+
+ Status error;
+
+ std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
+ for (auto thread_sp : m_threads) {
+ assert(thread_sp && "thread list should not have a NULL thread!");
+ if (!thread_sp)
+ continue;
+
+ error = thread_sp->RemoveHardwareBreakpoint(addr);
+ }
+
+ // Also remove from hardware breakpoint map of current process.
+ m_hw_breakpoints_map.erase(addr);
+
+ return error;
+}
+
bool NativeProcessProtocol::RegisterNativeDelegate(
NativeDelegate &native_delegate) {
std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
@@ -323,8 +398,8 @@ void NativeProcessProtocol::NotifyDidExec() {
}
}
-Error NativeProcessProtocol::SetSoftwareBreakpoint(lldb::addr_t addr,
- uint32_t size_hint) {
+Status NativeProcessProtocol::SetSoftwareBreakpoint(lldb::addr_t addr,
+ uint32_t size_hint) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeProcessProtocol::%s addr = 0x%" PRIx64, __FUNCTION__,
@@ -333,21 +408,25 @@ Error NativeProcessProtocol::SetSoftwareBreakpoint(lldb::addr_t addr,
return m_breakpoint_list.AddRef(
addr, size_hint, false,
[this](lldb::addr_t addr, size_t size_hint, bool /* hardware */,
- NativeBreakpointSP &breakpoint_sp) -> Error {
+ NativeBreakpointSP &breakpoint_sp) -> Status {
return SoftwareBreakpoint::CreateSoftwareBreakpoint(
*this, addr, size_hint, breakpoint_sp);
});
}
-Error NativeProcessProtocol::RemoveBreakpoint(lldb::addr_t addr) {
- return m_breakpoint_list.DecRef(addr);
+Status NativeProcessProtocol::RemoveBreakpoint(lldb::addr_t addr,
+ bool hardware) {
+ if (hardware)
+ return RemoveHardwareBreakpoint(addr);
+ else
+ return m_breakpoint_list.DecRef(addr);
}
-Error NativeProcessProtocol::EnableBreakpoint(lldb::addr_t addr) {
+Status NativeProcessProtocol::EnableBreakpoint(lldb::addr_t addr) {
return m_breakpoint_list.EnableBreakpoint(addr);
}
-Error NativeProcessProtocol::DisableBreakpoint(lldb::addr_t addr) {
+Status NativeProcessProtocol::DisableBreakpoint(lldb::addr_t addr) {
return m_breakpoint_list.DisableBreakpoint(addr);
}
@@ -389,44 +468,26 @@ void NativeProcessProtocol::DoStopIDBumped(uint32_t /* newBumpId */) {
// Default implementation does nothing.
}
-Error NativeProcessProtocol::ResolveProcessArchitecture(lldb::pid_t pid,
- ArchSpec &arch) {
+Status NativeProcessProtocol::ResolveProcessArchitecture(lldb::pid_t pid,
+ ArchSpec &arch) {
// Grab process info for the running process.
ProcessInstanceInfo process_info;
if (!Host::GetProcessInfo(pid, process_info))
- return Error("failed to get process info");
+ return Status("failed to get process info");
// Resolve the executable module.
ModuleSpecList module_specs;
if (!ObjectFile::GetModuleSpecifications(process_info.GetExecutableFile(), 0,
0, module_specs))
- return Error("failed to get module specifications");
+ return Status("failed to get module specifications");
lldbassert(module_specs.GetSize() == 1);
arch = module_specs.GetModuleSpecRefAtIndex(0).GetArchitecture();
if (arch.IsValid())
- return Error();
+ return Status();
else
- return Error("failed to retrieve a valid architecture from the exe module");
-}
-
-#ifndef __linux__
-// These need to be implemented to support lldb-gdb-server on a given platform.
-// Stubs are
-// provided to make the rest of the code link on non-supported platforms.
-
-Error NativeProcessProtocol::Launch(ProcessLaunchInfo &launch_info,
- NativeDelegate &native_delegate,
- MainLoop &mainloop,
- NativeProcessProtocolSP &process_sp) {
- llvm_unreachable("Platform has no NativeProcessProtocol support");
-}
-
-Error NativeProcessProtocol::Attach(lldb::pid_t pid,
- NativeDelegate &native_delegate,
- MainLoop &mainloop,
- NativeProcessProtocolSP &process_sp) {
- llvm_unreachable("Platform has no NativeProcessProtocol support");
+ return Status(
+ "failed to retrieve a valid architecture from the exe module");
}
-#endif
+NativeProcessProtocol::Factory::~Factory() = default;
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp
index 73b2629..629b024 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp
@@ -9,8 +9,8 @@
#include "lldb/Host/common/NativeRegisterContext.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
+#include "lldb/Utility/Log.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
@@ -138,7 +138,7 @@ NativeRegisterContext::GetPCfromBreakpointLocation(lldb::addr_t fail_value) {
return GetPC(fail_value);
}
-Error NativeRegisterContext::SetPC(lldb::addr_t pc) {
+Status NativeRegisterContext::SetPC(lldb::addr_t pc) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC);
return WriteRegisterFromUnsigned(reg, pc);
@@ -150,7 +150,7 @@ lldb::addr_t NativeRegisterContext::GetSP(lldb::addr_t fail_value) {
return ReadRegisterAsUnsigned(reg, fail_value);
}
-Error NativeRegisterContext::SetSP(lldb::addr_t sp) {
+Status NativeRegisterContext::SetSP(lldb::addr_t sp) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_SP);
return WriteRegisterFromUnsigned(reg, sp);
@@ -162,7 +162,7 @@ lldb::addr_t NativeRegisterContext::GetFP(lldb::addr_t fail_value) {
return ReadRegisterAsUnsigned(reg, fail_value);
}
-Error NativeRegisterContext::SetFP(lldb::addr_t fp) {
+Status NativeRegisterContext::SetFP(lldb::addr_t fp) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_FP);
return WriteRegisterFromUnsigned(reg, fp);
@@ -195,7 +195,7 @@ NativeRegisterContext::ReadRegisterAsUnsigned(const RegisterInfo *reg_info,
if (reg_info) {
RegisterValue value;
- Error error = ReadRegister(reg_info, value);
+ Status error = ReadRegister(reg_info, value);
if (error.Success()) {
if (log)
log->Printf("NativeRegisterContext::%s ReadRegister() succeeded, value "
@@ -215,22 +215,23 @@ NativeRegisterContext::ReadRegisterAsUnsigned(const RegisterInfo *reg_info,
return fail_value;
}
-Error NativeRegisterContext::WriteRegisterFromUnsigned(uint32_t reg,
- uint64_t uval) {
+Status NativeRegisterContext::WriteRegisterFromUnsigned(uint32_t reg,
+ uint64_t uval) {
if (reg == LLDB_INVALID_REGNUM)
- return Error("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__);
+ return Status("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__);
return WriteRegisterFromUnsigned(GetRegisterInfoAtIndex(reg), uval);
}
-Error NativeRegisterContext::WriteRegisterFromUnsigned(
- const RegisterInfo *reg_info, uint64_t uval) {
+Status
+NativeRegisterContext::WriteRegisterFromUnsigned(const RegisterInfo *reg_info,
+ uint64_t uval) {
assert(reg_info);
if (!reg_info)
- return Error("reg_info is nullptr");
+ return Status("reg_info is nullptr");
RegisterValue value;
if (!value.SetUInt(uval, reg_info->byte_size))
- return Error("RegisterValue::SetUInt () failed");
+ return Status("RegisterValue::SetUInt () failed");
return WriteRegister(reg_info, value);
}
@@ -246,10 +247,20 @@ uint32_t NativeRegisterContext::SetHardwareBreakpoint(lldb::addr_t addr,
return LLDB_INVALID_INDEX32;
}
+Status NativeRegisterContext::ClearAllHardwareBreakpoints() {
+ return Status("not implemented");
+}
+
bool NativeRegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) {
return false;
}
+Status NativeRegisterContext::GetHardwareBreakHitIndex(uint32_t &bp_index,
+ lldb::addr_t trap_addr) {
+ bp_index = LLDB_INVALID_INDEX32;
+ return Status("not implemented");
+}
+
uint32_t NativeRegisterContext::NumSupportedHardwareWatchpoints() { return 0; }
uint32_t NativeRegisterContext::SetHardwareWatchpoint(lldb::addr_t addr,
@@ -262,25 +273,25 @@ bool NativeRegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) {
return false;
}
-Error NativeRegisterContext::ClearAllHardwareWatchpoints() {
- return Error("not implemented");
+Status NativeRegisterContext::ClearAllHardwareWatchpoints() {
+ return Status("not implemented");
}
-Error NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit) {
+Status NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit) {
is_hit = false;
- return Error("not implemented");
+ return Status("not implemented");
}
-Error NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index,
- lldb::addr_t trap_addr) {
+Status NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index,
+ lldb::addr_t trap_addr) {
wp_index = LLDB_INVALID_INDEX32;
- return Error("not implemented");
+ return Status("not implemented");
}
-Error NativeRegisterContext::IsWatchpointVacant(uint32_t wp_index,
- bool &is_vacant) {
+Status NativeRegisterContext::IsWatchpointVacant(uint32_t wp_index,
+ bool &is_vacant) {
is_vacant = false;
- return Error("not implemented");
+ return Status("not implemented");
}
lldb::addr_t NativeRegisterContext::GetWatchpointAddress(uint32_t wp_index) {
@@ -293,10 +304,10 @@ lldb::addr_t NativeRegisterContext::GetWatchpointHitAddress(uint32_t wp_index) {
bool NativeRegisterContext::HardwareSingleStep(bool enable) { return false; }
-Error NativeRegisterContext::ReadRegisterValueFromMemory(
+Status NativeRegisterContext::ReadRegisterValueFromMemory(
const RegisterInfo *reg_info, lldb::addr_t src_addr, size_t src_len,
RegisterValue &reg_value) {
- Error error;
+ Status error;
if (reg_info == nullptr) {
error.SetErrorString("invalid register info argument.");
return error;
@@ -311,7 +322,7 @@ Error NativeRegisterContext::ReadRegisterValueFromMemory(
//
// Case 2: src_len > dst_len
//
- // Error! (The register should always be big enough to hold the data)
+ // Status! (The register should always be big enough to hold the data)
//
// Case 3: src_len < dst_len
//
@@ -334,17 +345,12 @@ Error NativeRegisterContext::ReadRegisterValueFromMemory(
return error;
}
- NativeProcessProtocolSP process_sp(m_thread.GetProcess());
- if (!process_sp) {
- error.SetErrorString("invalid process");
- return error;
- }
-
+ NativeProcessProtocol &process = m_thread.GetProcess();
uint8_t src[RegisterValue::kMaxRegisterByteSize];
// Read the memory
size_t bytes_read;
- error = process_sp->ReadMemory(src_addr, src, src_len, bytes_read);
+ error = process.ReadMemory(src_addr, src, src_len, bytes_read);
if (error.Fail())
return error;
@@ -363,7 +369,7 @@ Error NativeRegisterContext::ReadRegisterValueFromMemory(
// order of the memory data doesn't match the process. For now we are assuming
// they are the same.
lldb::ByteOrder byte_order;
- if (!process_sp->GetByteOrder(byte_order)) {
+ if (process.GetByteOrder(byte_order)) {
error.SetErrorString("NativeProcessProtocol::GetByteOrder () failed");
return error;
}
@@ -373,49 +379,45 @@ Error NativeRegisterContext::ReadRegisterValueFromMemory(
return error;
}
-Error NativeRegisterContext::WriteRegisterValueToMemory(
+Status NativeRegisterContext::WriteRegisterValueToMemory(
const RegisterInfo *reg_info, lldb::addr_t dst_addr, size_t dst_len,
const RegisterValue &reg_value) {
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
- Error error;
+ Status error;
- NativeProcessProtocolSP process_sp(m_thread.GetProcess());
- if (process_sp) {
+ NativeProcessProtocol &process = m_thread.GetProcess();
- // TODO: we might need to add a parameter to this function in case the byte
- // order of the memory data doesn't match the process. For now we are
- // assuming
- // they are the same.
- lldb::ByteOrder byte_order;
- if (!process_sp->GetByteOrder(byte_order))
- return Error("NativeProcessProtocol::GetByteOrder () failed");
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are
+ // assuming
+ // they are the same.
+ lldb::ByteOrder byte_order;
+ if (!process.GetByteOrder(byte_order))
+ return Status("NativeProcessProtocol::GetByteOrder () failed");
- const size_t bytes_copied =
- reg_value.GetAsMemoryData(reg_info, dst, dst_len, byte_order, error);
+ const size_t bytes_copied =
+ reg_value.GetAsMemoryData(reg_info, dst, dst_len, byte_order, error);
- if (error.Success()) {
- if (bytes_copied == 0) {
- error.SetErrorString("byte copy failed.");
- } else {
- size_t bytes_written;
- error =
- process_sp->WriteMemory(dst_addr, dst, bytes_copied, bytes_written);
- if (error.Fail())
- return error;
-
- if (bytes_written != bytes_copied) {
- // This might happen if we read _some_ bytes but not all
- error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64
- " bytes",
- static_cast<uint64_t>(bytes_written),
- static_cast<uint64_t>(bytes_copied));
- }
+ if (error.Success()) {
+ if (bytes_copied == 0) {
+ error.SetErrorString("byte copy failed.");
+ } else {
+ size_t bytes_written;
+ error = process.WriteMemory(dst_addr, dst, bytes_copied, bytes_written);
+ if (error.Fail())
+ return error;
+
+ if (bytes_written != bytes_copied) {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64
+ " bytes",
+ static_cast<uint64_t>(bytes_written),
+ static_cast<uint64_t>(bytes_copied));
}
}
- } else
- error.SetErrorString("invalid process");
+ }
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp
index 2e76cff..54ac96d 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp
@@ -16,53 +16,49 @@
using namespace lldb;
using namespace lldb_private;
-NativeThreadProtocol::NativeThreadProtocol(NativeProcessProtocol *process,
+NativeThreadProtocol::NativeThreadProtocol(NativeProcessProtocol &process,
lldb::tid_t tid)
- : m_process_wp(process->shared_from_this()), m_tid(tid) {}
+ : m_process(process), m_tid(tid) {}
-Error NativeThreadProtocol::ReadRegister(uint32_t reg,
- RegisterValue &reg_value) {
+Status NativeThreadProtocol::ReadRegister(uint32_t reg,
+ RegisterValue &reg_value) {
NativeRegisterContextSP register_context_sp = GetRegisterContext();
if (!register_context_sp)
- return Error("no register context");
+ return Status("no register context");
const RegisterInfo *const reg_info =
register_context_sp->GetRegisterInfoAtIndex(reg);
if (!reg_info)
- return Error("no register info for reg num %" PRIu32, reg);
+ return Status("no register info for reg num %" PRIu32, reg);
return register_context_sp->ReadRegister(reg_info, reg_value);
;
}
-Error NativeThreadProtocol::WriteRegister(uint32_t reg,
- const RegisterValue &reg_value) {
+Status NativeThreadProtocol::WriteRegister(uint32_t reg,
+ const RegisterValue &reg_value) {
NativeRegisterContextSP register_context_sp = GetRegisterContext();
if (!register_context_sp)
- return Error("no register context");
+ return Status("no register context");
const RegisterInfo *const reg_info =
register_context_sp->GetRegisterInfoAtIndex(reg);
if (!reg_info)
- return Error("no register info for reg num %" PRIu32, reg);
+ return Status("no register info for reg num %" PRIu32, reg);
return register_context_sp->WriteRegister(reg_info, reg_value);
}
-Error NativeThreadProtocol::SaveAllRegisters(lldb::DataBufferSP &data_sp) {
+Status NativeThreadProtocol::SaveAllRegisters(lldb::DataBufferSP &data_sp) {
NativeRegisterContextSP register_context_sp = GetRegisterContext();
if (!register_context_sp)
- return Error("no register context");
+ return Status("no register context");
return register_context_sp->WriteAllRegisterValues(data_sp);
}
-Error NativeThreadProtocol::RestoreAllRegisters(lldb::DataBufferSP &data_sp) {
+Status NativeThreadProtocol::RestoreAllRegisters(lldb::DataBufferSP &data_sp) {
NativeRegisterContextSP register_context_sp = GetRegisterContext();
if (!register_context_sp)
- return Error("no register context");
+ return Status("no register context");
return register_context_sp->ReadAllRegisterValues(data_sp);
}
-
-NativeProcessProtocolSP NativeThreadProtocol::GetProcess() {
- return m_process_wp.lock();
-}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp
index 5948adf..e6ef730 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp
@@ -9,20 +9,20 @@
#include "lldb/Host/common/NativeWatchpointList.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
-Error NativeWatchpointList::Add(addr_t addr, size_t size, uint32_t watch_flags,
- bool hardware) {
+Status NativeWatchpointList::Add(addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware) {
m_watchpoints[addr] = {addr, size, watch_flags, hardware};
- return Error();
+ return Status();
}
-Error NativeWatchpointList::Remove(addr_t addr) {
+Status NativeWatchpointList::Remove(addr_t addr) {
m_watchpoints.erase(addr);
- return Error();
+ return Status();
}
const NativeWatchpointList::WatchpointMap &
diff --git a/contrib/llvm/tools/lldb/source/Host/common/PipeBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/PipeBase.cpp
index cf7e6c9..632bfcb 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/PipeBase.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/PipeBase.cpp
@@ -13,12 +13,13 @@ using namespace lldb_private;
PipeBase::~PipeBase() = default;
-Error PipeBase::OpenAsWriter(llvm::StringRef name, bool child_process_inherit) {
+Status PipeBase::OpenAsWriter(llvm::StringRef name,
+ bool child_process_inherit) {
return OpenAsWriterWithTimeout(name, child_process_inherit,
std::chrono::microseconds::zero());
}
-Error PipeBase::Read(void *buf, size_t size, size_t &bytes_read) {
+Status PipeBase::Read(void *buf, size_t size, size_t &bytes_read) {
return ReadWithTimeout(buf, size, std::chrono::microseconds::zero(),
bytes_read);
}
diff --git a/contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp b/contrib/llvm/tools/lldb/source/Host/common/PseudoTerminal.cpp
index 4d99a56..58c32e4 100644
--- a/contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/PseudoTerminal.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Host/Config.h"
#include <errno.h>
@@ -112,8 +112,7 @@ bool PseudoTerminal::OpenFirstAvailableMaster(int oflag, char *error_str,
return true;
#else
if (error_str)
- ::snprintf(error_str, error_len, "%s",
- "pseudo terminal not supported");
+ ::snprintf(error_str, error_len, "%s", "pseudo terminal not supported");
return false;
#endif
}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp
index 79777c8..5490e9b 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp
@@ -9,14 +9,16 @@
#include "lldb/Host/Socket.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/SocketAddress.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Host/common/TCPSocket.h"
#include "lldb/Host/common/UDPSocket.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+
+#include "llvm/ADT/STLExtras.h"
#ifndef LLDB_DISABLE_POSIX
#include "lldb/Host/posix/DomainSocket.h"
@@ -27,6 +29,7 @@
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <unistd.h>
#endif
#ifdef __linux__
@@ -38,11 +41,9 @@
#include <asm-generic/errno-base.h>
#include <errno.h>
#include <linux/tcp.h>
-#if defined(ANDROID_ARM_BUILD_STATIC) || defined(ANDROID_MIPS_BUILD_STATIC)
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
-#endif // ANDROID_ARM_BUILD_STATIC || ANDROID_MIPS_BUILD_STATIC
#endif // __ANDROID__
using namespace lldb;
@@ -69,28 +70,33 @@ bool IsInterrupted() {
}
}
-Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close)
+Socket::Socket(SocketProtocol protocol, bool should_close,
+ bool child_processes_inherit)
: IOObject(eFDTypeSocket, should_close), m_protocol(protocol),
- m_socket(socket) {}
+ m_socket(kInvalidSocketValue),
+ m_child_processes_inherit(child_processes_inherit) {}
Socket::~Socket() { Close(); }
std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol,
bool child_processes_inherit,
- Error &error) {
+ Status &error) {
error.Clear();
std::unique_ptr<Socket> socket_up;
switch (protocol) {
case ProtocolTcp:
- socket_up.reset(new TCPSocket(child_processes_inherit, error));
+ socket_up =
+ llvm::make_unique<TCPSocket>(true, child_processes_inherit);
break;
case ProtocolUdp:
- socket_up.reset(new UDPSocket(child_processes_inherit, error));
+ socket_up =
+ llvm::make_unique<UDPSocket>(true, child_processes_inherit);
break;
case ProtocolUnixDomain:
#ifndef LLDB_DISABLE_POSIX
- socket_up.reset(new DomainSocket(child_processes_inherit, error));
+ socket_up =
+ llvm::make_unique<DomainSocket>(true, child_processes_inherit);
#else
error.SetErrorString(
"Unix domain sockets are not supported on this platform.");
@@ -98,7 +104,8 @@ std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol,
break;
case ProtocolUnixAbstract:
#ifdef __linux__
- socket_up.reset(new AbstractSocket(child_processes_inherit, error));
+ socket_up =
+ llvm::make_unique<AbstractSocket>(child_processes_inherit);
#else
error.SetErrorString(
"Abstract domain sockets are not supported on this platform.");
@@ -112,14 +119,14 @@ std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol,
return socket_up;
}
-Error Socket::TcpConnect(llvm::StringRef host_and_port,
- bool child_processes_inherit, Socket *&socket) {
+Status Socket::TcpConnect(llvm::StringRef host_and_port,
+ bool child_processes_inherit, Socket *&socket) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
if (log)
log->Printf("Socket::%s (host/port = %s)", __FUNCTION__,
host_and_port.data());
- Error error;
+ Status error;
std::unique_ptr<Socket> connect_socket(
Create(ProtocolTcp, child_processes_inherit, error));
if (error.Fail())
@@ -132,14 +139,14 @@ Error Socket::TcpConnect(llvm::StringRef host_and_port,
return error;
}
-Error Socket::TcpListen(llvm::StringRef host_and_port,
- bool child_processes_inherit, Socket *&socket,
- Predicate<uint16_t> *predicate, int backlog) {
+Status Socket::TcpListen(llvm::StringRef host_and_port,
+ bool child_processes_inherit, Socket *&socket,
+ Predicate<uint16_t> *predicate, int backlog) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
log->Printf("Socket::%s (%s)", __FUNCTION__, host_and_port.data());
- Error error;
+ Status error;
std::string host_str;
std::string port_str;
int32_t port = INT32_MIN;
@@ -147,7 +154,7 @@ Error Socket::TcpListen(llvm::StringRef host_and_port,
return error;
std::unique_ptr<TCPSocket> listen_socket(
- new TCPSocket(child_processes_inherit, error));
+ new TCPSocket(true, child_processes_inherit));
if (error.Fail())
return error;
@@ -173,21 +180,20 @@ Error Socket::TcpListen(llvm::StringRef host_and_port,
return error;
}
-Error Socket::UdpConnect(llvm::StringRef host_and_port,
- bool child_processes_inherit, Socket *&send_socket,
- Socket *&recv_socket) {
+Status Socket::UdpConnect(llvm::StringRef host_and_port,
+ bool child_processes_inherit, Socket *&socket) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
log->Printf("Socket::%s (host/port = %s)", __FUNCTION__,
host_and_port.data());
- return UDPSocket::Connect(host_and_port, child_processes_inherit, send_socket,
- recv_socket);
+ return UDPSocket::Connect(host_and_port, child_processes_inherit, socket);
}
-Error Socket::UnixDomainConnect(llvm::StringRef name,
- bool child_processes_inherit, Socket *&socket) {
- Error error;
+Status Socket::UnixDomainConnect(llvm::StringRef name,
+ bool child_processes_inherit,
+ Socket *&socket) {
+ Status error;
std::unique_ptr<Socket> connect_socket(
Create(ProtocolUnixDomain, child_processes_inherit, error));
if (error.Fail())
@@ -200,9 +206,9 @@ Error Socket::UnixDomainConnect(llvm::StringRef name,
return error;
}
-Error Socket::UnixDomainAccept(llvm::StringRef name,
- bool child_processes_inherit, Socket *&socket) {
- Error error;
+Status Socket::UnixDomainAccept(llvm::StringRef name,
+ bool child_processes_inherit, Socket *&socket) {
+ Status error;
std::unique_ptr<Socket> listen_socket(
Create(ProtocolUnixDomain, child_processes_inherit, error));
if (error.Fail())
@@ -212,14 +218,14 @@ Error Socket::UnixDomainAccept(llvm::StringRef name,
if (error.Fail())
return error;
- error = listen_socket->Accept(name, child_processes_inherit, socket);
+ error = listen_socket->Accept(socket);
return error;
}
-Error Socket::UnixAbstractConnect(llvm::StringRef name,
- bool child_processes_inherit,
- Socket *&socket) {
- Error error;
+Status Socket::UnixAbstractConnect(llvm::StringRef name,
+ bool child_processes_inherit,
+ Socket *&socket) {
+ Status error;
std::unique_ptr<Socket> connect_socket(
Create(ProtocolUnixAbstract, child_processes_inherit, error));
if (error.Fail())
@@ -231,10 +237,10 @@ Error Socket::UnixAbstractConnect(llvm::StringRef name,
return error;
}
-Error Socket::UnixAbstractAccept(llvm::StringRef name,
- bool child_processes_inherit,
- Socket *&socket) {
- Error error;
+Status Socket::UnixAbstractAccept(llvm::StringRef name,
+ bool child_processes_inherit,
+ Socket *&socket) {
+ Status error;
std::unique_ptr<Socket> listen_socket(
Create(ProtocolUnixAbstract, child_processes_inherit, error));
if (error.Fail())
@@ -244,18 +250,22 @@ Error Socket::UnixAbstractAccept(llvm::StringRef name,
if (error.Fail())
return error;
- error = listen_socket->Accept(name, child_processes_inherit, socket);
+ error = listen_socket->Accept(socket);
return error;
}
bool Socket::DecodeHostAndPort(llvm::StringRef host_and_port,
std::string &host_str, std::string &port_str,
- int32_t &port, Error *error_ptr) {
- static RegularExpression g_regex(llvm::StringRef("([^:]+):([0-9]+)"));
+ int32_t &port, Status *error_ptr) {
+ static RegularExpression g_regex(
+ llvm::StringRef("([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)"));
RegularExpression::Match regex_match(2);
if (g_regex.Execute(host_and_port, &regex_match)) {
if (regex_match.GetMatchAtIndex(host_and_port.data(), 1, host_str) &&
regex_match.GetMatchAtIndex(host_and_port.data(), 2, port_str)) {
+ // IPv6 addresses are wrapped in [] when specified with ports
+ if (host_str.front() == '[' && host_str.back() == ']')
+ host_str = host_str.substr(1, host_str.size() - 2);
bool ok = false;
port = StringConvert::ToUInt32(port_str.c_str(), UINT32_MAX, 10, &ok);
if (ok && port <= UINT16_MAX) {
@@ -296,8 +306,8 @@ IOObject::WaitableHandle Socket::GetWaitableHandle() {
return m_socket;
}
-Error Socket::Read(void *buf, size_t &num_bytes) {
- Error error;
+Status Socket::Read(void *buf, size_t &num_bytes) {
+ Status error;
int bytes_received = 0;
do {
bytes_received = ::recv(m_socket, static_cast<char *>(buf), num_bytes, 0);
@@ -322,8 +332,8 @@ Error Socket::Read(void *buf, size_t &num_bytes) {
return error;
}
-Error Socket::Write(const void *buf, size_t &num_bytes) {
- Error error;
+Status Socket::Write(const void *buf, size_t &num_bytes) {
+ Status error;
int bytes_sent = 0;
do {
bytes_sent = Send(buf, num_bytes);
@@ -348,13 +358,13 @@ Error Socket::Write(const void *buf, size_t &num_bytes) {
return error;
}
-Error Socket::PreDisconnect() {
- Error error;
+Status Socket::PreDisconnect() {
+ Status error;
return error;
}
-Error Socket::Close() {
- Error error;
+Status Socket::Close() {
+ Status error;
if (!IsValid() || !m_should_close_fd)
return error;
@@ -396,7 +406,7 @@ size_t Socket::Send(const void *buf, const size_t num_bytes) {
return ::send(m_socket, static_cast<const char *>(buf), num_bytes, 0);
}
-void Socket::SetLastError(Error &error) {
+void Socket::SetLastError(Status &error) {
#if defined(_WIN32)
error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32);
#else
@@ -406,14 +416,14 @@ void Socket::SetLastError(Error &error) {
NativeSocket Socket::CreateSocket(const int domain, const int type,
const int protocol,
- bool child_processes_inherit, Error &error) {
+ bool child_processes_inherit, Status &error) {
error.Clear();
- auto socketType = type;
+ auto socket_type = type;
#ifdef SOCK_CLOEXEC
if (!child_processes_inherit)
- socketType |= SOCK_CLOEXEC;
+ socket_type |= SOCK_CLOEXEC;
#endif
- auto sock = ::socket(domain, socketType, protocol);
+ auto sock = ::socket(domain, socket_type, protocol);
if (sock == kInvalidSocketValue)
SetLastError(error);
@@ -422,11 +432,15 @@ NativeSocket Socket::CreateSocket(const int domain, const int type,
NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr,
socklen_t *addrlen,
- bool child_processes_inherit, Error &error) {
+ bool child_processes_inherit, Status &error) {
error.Clear();
-#if defined(ANDROID_ARM_BUILD_STATIC) || defined(ANDROID_MIPS_BUILD_STATIC)
- // Temporary workaround for statically linking Android lldb-server with the
- // latest API.
+#if defined(ANDROID_USE_ACCEPT_WORKAROUND)
+ // Hack:
+ // This enables static linking lldb-server to an API 21 libc, but still having
+ // it run on older devices. It is necessary because API 21 libc's
+ // implementation of accept() uses the accept4 syscall(), which is not
+ // available in older kernels. Using an older libc would fix this issue, but
+ // introduce other ones, as the old libraries were quite buggy.
int fd = syscall(__NR_accept, sockfd, addr, addrlen);
if (fd >= 0 && !child_processes_inherit) {
int flags = ::fcntl(fd, F_GETFD);
@@ -441,11 +455,7 @@ NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr,
if (!child_processes_inherit) {
flags |= SOCK_CLOEXEC;
}
-#if defined(__NetBSD__)
- NativeSocket fd = ::paccept(sockfd, addr, addrlen, nullptr, flags);
-#else
NativeSocket fd = ::accept4(sockfd, addr, addrlen, flags);
-#endif
#else
NativeSocket fd = ::accept(sockfd, addr, addrlen);
#endif
diff --git a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp
index 1f5de2e..def3e03 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp
@@ -6,6 +6,12 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+//
+// Note: This file is used on Darwin by debugserver, so it needs to remain as
+// self contained as possible, and devoid of references to LLVM unless
+// there is compelling reason.
+//
+//===----------------------------------------------------------------------===//
#if defined(_MSC_VER)
#define _WINSOCK_DEPRECATED_NO_WARNINGS
@@ -89,6 +95,10 @@ SocketAddress::SocketAddress(const struct sockaddr_storage &s) {
m_socket_addr.sa_storage = s;
}
+SocketAddress::SocketAddress(const struct addrinfo *addr_info) {
+ *this = addr_info;
+}
+
//----------------------------------------------------------------------
// SocketAddress copy constructor
//----------------------------------------------------------------------
@@ -191,7 +201,7 @@ const SocketAddress &SocketAddress::
operator=(const struct addrinfo *addr_info) {
Clear();
if (addr_info && addr_info->ai_addr && addr_info->ai_addrlen > 0 &&
- addr_info->ai_addrlen <= sizeof m_socket_addr) {
+ size_t(addr_info->ai_addrlen) <= sizeof m_socket_addr) {
::memcpy(&m_socket_addr, addr_info->ai_addr, addr_info->ai_addrlen);
}
return *this;
@@ -223,6 +233,19 @@ bool SocketAddress::getaddrinfo(const char *host, const char *service,
int ai_flags) {
Clear();
+ auto addresses = GetAddressInfo(host, service, ai_family, ai_socktype,
+ ai_protocol, ai_flags);
+ if (!addresses.empty())
+ *this = addresses[0];
+ return IsValid();
+}
+
+std::vector<SocketAddress>
+SocketAddress::GetAddressInfo(const char *hostname, const char *servname,
+ int ai_family, int ai_socktype, int ai_protocol,
+ int ai_flags) {
+ std::vector<SocketAddress> addr_list;
+
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = ai_family;
@@ -230,18 +253,18 @@ bool SocketAddress::getaddrinfo(const char *host, const char *service,
hints.ai_protocol = ai_protocol;
hints.ai_flags = ai_flags;
- bool result = false;
struct addrinfo *service_info_list = NULL;
- int err = ::getaddrinfo(host, service, &hints, &service_info_list);
+ int err = ::getaddrinfo(hostname, servname, &hints, &service_info_list);
if (err == 0 && service_info_list) {
- *this = service_info_list;
- result = IsValid();
+ for (struct addrinfo *service_ptr = service_info_list; service_ptr != NULL;
+ service_ptr = service_ptr->ai_next) {
+ addr_list.emplace_back(SocketAddress(service_ptr));
+ }
}
if (service_info_list)
::freeaddrinfo(service_info_list);
-
- return result;
+ return addr_list;
}
bool SocketAddress::SetToLocalhost(sa_family_t family, uint16_t port) {
@@ -287,3 +310,36 @@ bool SocketAddress::SetToAnyAddress(sa_family_t family, uint16_t port) {
Clear();
return false;
}
+
+bool SocketAddress::IsAnyAddr() const {
+ return (GetFamily() == AF_INET)
+ ? m_socket_addr.sa_ipv4.sin_addr.s_addr == htonl(INADDR_ANY)
+ : 0 == memcmp(&m_socket_addr.sa_ipv6.sin6_addr, &in6addr_any, 16);
+}
+
+bool SocketAddress::IsLocalhost() const {
+ return (GetFamily() == AF_INET)
+ ? m_socket_addr.sa_ipv4.sin_addr.s_addr == htonl(INADDR_LOOPBACK)
+ : 0 == memcmp(&m_socket_addr.sa_ipv6.sin6_addr, &in6addr_loopback,
+ 16);
+}
+
+bool SocketAddress::operator==(const SocketAddress &rhs) const {
+ if (GetFamily() != rhs.GetFamily())
+ return false;
+ if (GetLength() != rhs.GetLength())
+ return false;
+ switch (GetFamily()) {
+ case AF_INET:
+ return m_socket_addr.sa_ipv4.sin_addr.s_addr ==
+ rhs.m_socket_addr.sa_ipv4.sin_addr.s_addr;
+ case AF_INET6:
+ return 0 == memcmp(&m_socket_addr.sa_ipv6.sin6_addr,
+ &rhs.m_socket_addr.sa_ipv6.sin6_addr, 16);
+ }
+ return false;
+}
+
+bool SocketAddress::operator!=(const SocketAddress &rhs) const {
+ return !(*this == rhs);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp
index 3d57b7d..14dbafd 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp
@@ -9,9 +9,9 @@
#include "lldb/Host/common/SoftwareBreakpoint.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Host/Debug.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
@@ -21,7 +21,7 @@ using namespace lldb_private;
// static members
// -------------------------------------------------------------------
-Error SoftwareBreakpoint::CreateSoftwareBreakpoint(
+Status SoftwareBreakpoint::CreateSoftwareBreakpoint(
NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint,
NativeBreakpointSP &breakpoint_sp) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
@@ -30,15 +30,15 @@ Error SoftwareBreakpoint::CreateSoftwareBreakpoint(
// Validate the address.
if (addr == LLDB_INVALID_ADDRESS)
- return Error("SoftwareBreakpoint::%s invalid load address specified.",
- __FUNCTION__);
+ return Status("SoftwareBreakpoint::%s invalid load address specified.",
+ __FUNCTION__);
// Ask the NativeProcessProtocol subclass to fill in the correct software
// breakpoint
// trap for the breakpoint site.
size_t bp_opcode_size = 0;
const uint8_t *bp_opcode_bytes = NULL;
- Error error = process.GetSoftwareBreakpointTrapOpcode(
+ Status error = process.GetSoftwareBreakpointTrapOpcode(
size_hint, bp_opcode_size, bp_opcode_bytes);
if (error.Fail()) {
@@ -54,10 +54,10 @@ Error SoftwareBreakpoint::CreateSoftwareBreakpoint(
if (log)
log->Printf("SoftwareBreakpoint::%s failed to retrieve any trap opcodes",
__FUNCTION__);
- return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
- "returned zero, unable to get breakpoint trap for address "
- "0x%" PRIx64,
- addr);
+ return Status("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
+ "returned zero, unable to get breakpoint trap for address "
+ "0x%" PRIx64,
+ addr);
}
if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE) {
@@ -65,10 +65,10 @@ Error SoftwareBreakpoint::CreateSoftwareBreakpoint(
log->Printf("SoftwareBreakpoint::%s cannot support %zu trapcode bytes, "
"max size is %zu",
__FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
- return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
- "returned too many trap opcode bytes: requires %zu but we "
- "only support a max of %zu",
- bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
+ return Status("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
+ "returned too many trap opcode bytes: requires %zu but we "
+ "only support a max of %zu",
+ bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
}
// Validate that we received opcodes.
@@ -76,10 +76,10 @@ Error SoftwareBreakpoint::CreateSoftwareBreakpoint(
if (log)
log->Printf("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes",
__FUNCTION__);
- return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
- "returned NULL trap opcode bytes, unable to get breakpoint "
- "trap for address 0x%" PRIx64,
- addr);
+ return Status("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() "
+ "returned NULL trap opcode bytes, unable to get breakpoint "
+ "trap for address 0x%" PRIx64,
+ addr);
}
// Enable the breakpoint.
@@ -103,10 +103,10 @@ Error SoftwareBreakpoint::CreateSoftwareBreakpoint(
// breakpoint.
breakpoint_sp.reset(new SoftwareBreakpoint(process, addr, saved_opcode_bytes,
bp_opcode_bytes, bp_opcode_size));
- return Error();
+ return Status();
}
-Error SoftwareBreakpoint::EnableSoftwareBreakpoint(
+Status SoftwareBreakpoint::EnableSoftwareBreakpoint(
NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size,
const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes) {
assert(bp_opcode_size <= MAX_TRAP_OPCODE_SIZE &&
@@ -121,7 +121,7 @@ Error SoftwareBreakpoint::EnableSoftwareBreakpoint(
// Save the original opcodes by reading them so we can restore later.
size_t bytes_read = 0;
- Error error =
+ Status error =
process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read);
if (error.Fail()) {
if (log)
@@ -138,10 +138,10 @@ Error SoftwareBreakpoint::EnableSoftwareBreakpoint(
"attempting to set breakpoint: attempted to read %zu bytes "
"but only read %zu",
__FUNCTION__, bp_opcode_size, bytes_read);
- return Error("SoftwareBreakpoint::%s failed to read memory while "
- "attempting to set breakpoint: attempted to read %zu bytes "
- "but only read %zu",
- __FUNCTION__, bp_opcode_size, bytes_read);
+ return Status("SoftwareBreakpoint::%s failed to read memory while "
+ "attempting to set breakpoint: attempted to read %zu bytes "
+ "but only read %zu",
+ __FUNCTION__, bp_opcode_size, bytes_read);
}
// Log what we read.
@@ -197,10 +197,11 @@ Error SoftwareBreakpoint::EnableSoftwareBreakpoint(
"attempting to verify breakpoint: attempted to read %zu "
"bytes but only read %zu",
__FUNCTION__, bp_opcode_size, verify_bytes_read);
- return Error("SoftwareBreakpoint::%s failed to read memory while "
- "attempting to verify breakpoint: attempted to read %zu bytes "
- "but only read %zu",
- __FUNCTION__, bp_opcode_size, verify_bytes_read);
+ return Status(
+ "SoftwareBreakpoint::%s failed to read memory while "
+ "attempting to verify breakpoint: attempted to read %zu bytes "
+ "but only read %zu",
+ __FUNCTION__, bp_opcode_size, verify_bytes_read);
}
if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0) {
@@ -209,17 +210,17 @@ Error SoftwareBreakpoint::EnableSoftwareBreakpoint(
"writing failed - trap opcodes not successfully read back "
"after writing when setting breakpoint at 0x%" PRIx64,
__FUNCTION__, addr);
- return Error("SoftwareBreakpoint::%s: verification of software breakpoint "
- "writing failed - trap opcodes not successfully read back "
- "after writing when setting breakpoint at 0x%" PRIx64,
- __FUNCTION__, addr);
+ return Status("SoftwareBreakpoint::%s: verification of software breakpoint "
+ "writing failed - trap opcodes not successfully read back "
+ "after writing when setting breakpoint at 0x%" PRIx64,
+ __FUNCTION__, addr);
}
if (log)
log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS",
__FUNCTION__, addr);
- return Error();
+ return Status();
}
// -------------------------------------------------------------------
@@ -240,13 +241,13 @@ SoftwareBreakpoint::SoftwareBreakpoint(NativeProcessProtocol &process,
::memcpy(m_trap_opcodes, trap_opcodes, opcode_size);
}
-Error SoftwareBreakpoint::DoEnable() {
+Status SoftwareBreakpoint::DoEnable() {
return EnableSoftwareBreakpoint(m_process, m_addr, m_opcode_size,
m_trap_opcodes, m_saved_opcodes);
}
-Error SoftwareBreakpoint::DoDisable() {
- Error error;
+Status SoftwareBreakpoint::DoDisable() {
+ Status error;
assert(m_addr && (m_addr != LLDB_INVALID_ADDRESS) &&
"can't remove a software breakpoint for an invalid address");
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp b/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp
index 461b15a..e7bdf08 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp
@@ -9,17 +9,17 @@
#include "lldb/Host/Symbols.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
-#include "lldb/Core/UUID.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
#include "lldb/Utility/SafeMachO.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
+#include "lldb/Utility/UUID.h"
#include "llvm/Support/FileSystem.h"
@@ -54,7 +54,9 @@ static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec,
if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) {
ModuleSpec spec;
for (size_t i = 0; i < module_specs.GetSize(); ++i) {
- assert(module_specs.GetModuleSpecAtIndex(i, spec));
+ bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
+ UNUSED_IF_ASSERT_DISABLED(got_spec);
+ assert(got_spec);
if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
(arch == NULL || (spec.GetArchitecturePtr() &&
spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
@@ -84,7 +86,6 @@ static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec,
path);
}
}
- size_t obj_file_path_length = strlen(path);
::strncat(path, ".dSYM/Contents/Resources/DWARF/",
sizeof(path) - strlen(path) - 1);
::strncat(path, exec_fspec->GetFilename().AsCString(),
@@ -103,38 +104,55 @@ static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec,
}
return true;
} else {
- path[obj_file_path_length] = '\0';
-
- char *last_dot = strrchr(path, '.');
- while (last_dot != NULL && last_dot[0]) {
- char *next_slash = strchr(last_dot, '/');
- if (next_slash != NULL) {
- *next_slash = '\0';
- ::strncat(path, ".dSYM/Contents/Resources/DWARF/",
- sizeof(path) - strlen(path) - 1);
- ::strncat(path, exec_fspec->GetFilename().AsCString(),
- sizeof(path) - strlen(path) - 1);
- dsym_fspec.SetFile(path, false);
+ FileSpec parent_dirs = exec_fspec;
+
+ // Remove the binary name from the FileSpec
+ parent_dirs.RemoveLastPathComponent();
+
+ // Add a ".dSYM" name to each directory component of the path, stripping
+ // off components. e.g. we may have a binary like
+ // /S/L/F/Foundation.framework/Versions/A/Foundation
+ // and
+ // /S/L/F/Foundation.framework.dSYM
+ //
+ // so we'll need to start with /S/L/F/Foundation.framework/Versions/A,
+ // add the .dSYM part to the "A", and if that doesn't exist, strip off
+ // the "A" and try it again with "Versions", etc., until we find a dSYM
+ // bundle or we've stripped off enough path components that there's no
+ // need to continue.
+
+ for (int i = 0; i < 4; i++) {
+ // Does this part of the path have a "." character - could it be a bundle's
+ // top level directory?
+ const char *fn = parent_dirs.GetFilename().AsCString();
+ if (fn == nullptr)
+ break;
+ if (::strchr (fn, '.') != nullptr) {
+ dsym_fspec = parent_dirs;
+ dsym_fspec.RemoveLastPathComponent();
+
+ // If the current directory name is "Foundation.framework", see if
+ // "Foundation.framework.dSYM/Contents/Resources/DWARF/Foundation"
+ // exists & has the right uuid.
+ std::string dsym_fn = fn;
+ dsym_fn += ".dSYM";
+ dsym_fspec.AppendPathComponent(dsym_fn.c_str());
+ dsym_fspec.AppendPathComponent("Contents");
+ dsym_fspec.AppendPathComponent("Resources");
+ dsym_fspec.AppendPathComponent("DWARF");
+ dsym_fspec.AppendPathComponent(exec_fspec->GetFilename().AsCString());
if (dsym_fspec.Exists() &&
- FileAtPathContainsArchAndUUID(
- dsym_fspec, module_spec.GetArchitecturePtr(),
- module_spec.GetUUIDPtr())) {
- if (log) {
- log->Printf("dSYM with matching UUID & arch found at %s",
- path);
- }
- return true;
- } else {
- *last_dot = '\0';
- char *prev_slash = strrchr(path, '/');
- if (prev_slash != NULL)
- *prev_slash = '\0';
- else
- break;
+ FileAtPathContainsArchAndUUID(
+ dsym_fspec, module_spec.GetArchitecturePtr(),
+ module_spec.GetUUIDPtr())) {
+ if (log) {
+ log->Printf("dSYM with matching UUID & arch found at %s",
+ dsym_fspec.GetPath().c_str());
+ }
+ return true;
}
- } else {
- break;
}
+ parent_dirs.RemoveLastPathComponent();
}
}
}
@@ -149,8 +167,9 @@ FileSpec LocateExecutableSymbolFileDsym(const ModuleSpec &module_spec) {
const ArchSpec *arch = module_spec.GetArchitecturePtr();
const UUID *uuid = module_spec.GetUUIDPtr();
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
+ func_cat,
"LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)",
exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>",
arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
@@ -173,9 +192,9 @@ ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) {
const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
const ArchSpec *arch = module_spec.GetArchitecturePtr();
const UUID *uuid = module_spec.GetUUIDPtr();
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
- "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
+ func_cat, "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>",
arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
@@ -210,8 +229,13 @@ FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) {
debug_file_search_paths.AppendIfUnique(FileSpec(".", true));
#ifndef LLVM_ON_WIN32
+#if defined(__NetBSD__)
+ // Add /usr/libdata/debug directory.
+ debug_file_search_paths.AppendIfUnique(FileSpec("/usr/libdata/debug", true));
+#else
// Add /usr/lib/debug directory.
debug_file_search_paths.AppendIfUnique(FileSpec("/usr/lib/debug", true));
+#endif
#endif // LLVM_ON_WIN32
std::string uuid_str;
@@ -228,7 +252,7 @@ FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) {
for (size_t idx = 0; idx < num_directories; ++idx) {
FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx);
dirspec.ResolvePath();
- if (!dirspec.Exists() || !dirspec.IsDirectory())
+ if (!llvm::sys::fs::is_directory(dirspec.GetPath()))
continue;
std::vector<std::string> files;
diff --git a/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp b/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp
index 9685cee..f896944 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp
@@ -13,8 +13,12 @@
#include "lldb/Host/common/TCPSocket.h"
-#include "lldb/Core/Log.h"
#include "lldb/Host/Config.h"
+#include "lldb/Host/MainLoop.h"
+#include "lldb/Utility/Log.h"
+
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/raw_ostream.h"
#ifndef LLDB_DISABLE_POSIX
#include <arpa/inet.h>
@@ -22,22 +26,46 @@
#include <sys/socket.h>
#endif
+#if defined(LLVM_ON_WIN32)
+#include <winsock2.h>
+#endif
+
+#ifdef LLVM_ON_WIN32
+#define CLOSE_SOCKET closesocket
+typedef const char *set_socket_option_arg_type;
+#else
+#include <unistd.h>
+#define CLOSE_SOCKET ::close
+typedef const void *set_socket_option_arg_type;
+#endif
+
using namespace lldb;
using namespace lldb_private;
namespace {
-
-const int kDomain = AF_INET;
const int kType = SOCK_STREAM;
}
-TCPSocket::TCPSocket(NativeSocket socket, bool should_close)
- : Socket(socket, ProtocolTcp, should_close) {}
+TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit)
+ : Socket(ProtocolTcp, should_close, child_processes_inherit) {}
-TCPSocket::TCPSocket(bool child_processes_inherit, Error &error)
- : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP,
- child_processes_inherit, error),
- true) {}
+TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket)
+ : Socket(ProtocolTcp, listen_socket.m_should_close_fd,
+ listen_socket.m_child_processes_inherit) {
+ m_socket = socket;
+}
+
+TCPSocket::TCPSocket(NativeSocket socket, bool should_close,
+ bool child_processes_inherit)
+ : Socket(ProtocolTcp, should_close, child_processes_inherit) {
+ m_socket = socket;
+}
+
+TCPSocket::~TCPSocket() { CloseListenSockets(); }
+
+bool TCPSocket::IsValid() const {
+ return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
+}
// Return the port number that is being used by the socket.
uint16_t TCPSocket::GetLocalPortNumber() const {
@@ -46,6 +74,12 @@ uint16_t TCPSocket::GetLocalPortNumber() const {
socklen_t sock_addr_len = sock_addr.GetMaxLength();
if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
return sock_addr.GetPort();
+ } else if (!m_listen_sockets.empty()) {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength();
+ if (::getsockname(m_listen_sockets.begin()->first, sock_addr,
+ &sock_addr_len) == 0)
+ return sock_addr.GetPort();
}
return 0;
}
@@ -84,161 +118,169 @@ std::string TCPSocket::GetRemoteIPAddress() const {
return "";
}
-Error TCPSocket::Connect(llvm::StringRef name) {
- if (m_socket == kInvalidSocketValue)
- return Error("Invalid socket");
+Status TCPSocket::CreateSocket(int domain) {
+ Status error;
+ if (IsValid())
+ error = Close();
+ if (error.Fail())
+ return error;
+ m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP,
+ m_child_processes_inherit, error);
+ return error;
+}
+
+Status TCPSocket::Connect(llvm::StringRef name) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
if (log)
log->Printf("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
- Error error;
+ Status error;
std::string host_str;
std::string port_str;
int32_t port = INT32_MIN;
if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
return error;
- struct sockaddr_in sa;
- ::memset(&sa, 0, sizeof(sa));
- sa.sin_family = kDomain;
- sa.sin_port = htons(port);
-
- int inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr);
-
- if (inet_pton_result <= 0) {
- struct hostent *host_entry = gethostbyname(host_str.c_str());
- if (host_entry)
- host_str = ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list);
- inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr);
- if (inet_pton_result <= 0) {
- if (inet_pton_result == -1)
- SetLastError(error);
- else
- error.SetErrorStringWithFormat("invalid host string: '%s'",
- host_str.c_str());
+ auto addresses = lldb_private::SocketAddress::GetAddressInfo(
+ host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
+ for (auto address : addresses) {
+ error = CreateSocket(address.GetFamily());
+ if (error.Fail())
+ continue;
- return error;
+ address.SetPort(port);
+
+ if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(),
+ address.GetLength())) {
+ CLOSE_SOCKET(GetNativeSocket());
+ continue;
}
- }
- if (-1 ==
- ::connect(GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) {
- SetLastError(error);
+ SetOptionNoDelay();
+
+ error.Clear();
return error;
}
- // Keep our TCP packets coming without any delays.
- SetOptionNoDelay();
- error.Clear();
+ error.SetErrorString("Failed to connect port");
return error;
}
-Error TCPSocket::Listen(llvm::StringRef name, int backlog) {
- Error error;
-
- // enable local address reuse
- SetOptionReuseAddress();
-
+Status TCPSocket::Listen(llvm::StringRef name, int backlog) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data());
+ Status error;
std::string host_str;
std::string port_str;
int32_t port = INT32_MIN;
if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
return error;
- SocketAddress bind_addr;
+ if (host_str == "*")
+ host_str = "0.0.0.0";
+ auto addresses = lldb_private::SocketAddress::GetAddressInfo(
+ host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
+ for (auto address : addresses) {
+ int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
+ m_child_processes_inherit, error);
+ if (error.Fail()) {
+ error.Clear();
+ continue;
+ }
- // Only bind to the loopback address if we are expecting a connection from
- // localhost to avoid any firewall issues.
- const bool bind_addr_success = (host_str == "127.0.0.1")
- ? bind_addr.SetToLocalhost(kDomain, port)
- : bind_addr.SetToAnyAddress(kDomain, port);
+ // enable local address reuse
+ int option_value = 1;
+ set_socket_option_arg_type option_value_p =
+ reinterpret_cast<set_socket_option_arg_type>(&option_value);
+ ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
+ sizeof(option_value));
+
+ SocketAddress listen_address = address;
+ if(!listen_address.IsLocalhost())
+ listen_address.SetToAnyAddress(address.GetFamily(), port);
+ else
+ listen_address.SetPort(port);
+
+ int err =
+ ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
+ if (-1 != err)
+ err = ::listen(fd, backlog);
+
+ if (-1 == err) {
+ CLOSE_SOCKET(fd);
+ continue;
+ }
- if (!bind_addr_success) {
- error.SetErrorString("Failed to bind port");
- return error;
+ if (port == 0) {
+ socklen_t sa_len = address.GetLength();
+ if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
+ port = address.GetPort();
+ }
+ m_listen_sockets[fd] = address;
}
- int err = ::bind(GetNativeSocket(), bind_addr, bind_addr.GetLength());
- if (err != -1)
- err = ::listen(GetNativeSocket(), backlog);
-
- if (err == -1)
- SetLastError(error);
-
+ if (m_listen_sockets.size() == 0)
+ error.SetErrorString("Failed to connect port");
return error;
}
-Error TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit,
- Socket *&conn_socket) {
- Error error;
- std::string host_str;
- std::string port_str;
- int32_t port;
- if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
+void TCPSocket::CloseListenSockets() {
+ for (auto socket : m_listen_sockets)
+ CLOSE_SOCKET(socket.first);
+ m_listen_sockets.clear();
+}
+
+Status TCPSocket::Accept(Socket *&conn_socket) {
+ Status error;
+ if (m_listen_sockets.size() == 0) {
+ error.SetErrorString("No open listening sockets!");
return error;
+ }
- const sa_family_t family = kDomain;
- const int socktype = kType;
- const int protocol = IPPROTO_TCP;
- SocketAddress listen_addr;
- if (host_str.empty())
- listen_addr.SetToLocalhost(family, port);
- else if (host_str.compare("*") == 0)
- listen_addr.SetToAnyAddress(family, port);
- else {
- if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family,
- socktype, protocol)) {
- error.SetErrorStringWithFormat("unable to resolve hostname '%s'",
- host_str.c_str());
+ int sock = -1;
+ int listen_sock = -1;
+ lldb_private::SocketAddress AcceptAddr;
+ MainLoop accept_loop;
+ std::vector<MainLoopBase::ReadHandleUP> handles;
+ for (auto socket : m_listen_sockets) {
+ auto fd = socket.first;
+ auto inherit = this->m_child_processes_inherit;
+ auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit));
+ handles.emplace_back(accept_loop.RegisterReadObject(
+ io_sp, [fd, inherit, &sock, &AcceptAddr, &error,
+ &listen_sock](MainLoopBase &loop) {
+ socklen_t sa_len = AcceptAddr.GetMaxLength();
+ sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit,
+ error);
+ listen_sock = fd;
+ loop.RequestTermination();
+ }, error));
+ if (error.Fail())
return error;
- }
}
bool accept_connection = false;
std::unique_ptr<TCPSocket> accepted_socket;
-
// Loop until we are happy with our connection
while (!accept_connection) {
- struct sockaddr_in accept_addr;
- ::memset(&accept_addr, 0, sizeof accept_addr);
-#if !(defined(__linux__) || defined(_WIN32))
- accept_addr.sin_len = sizeof accept_addr;
-#endif
- socklen_t accept_addr_len = sizeof accept_addr;
-
- int sock = AcceptSocket(GetNativeSocket(), (struct sockaddr *)&accept_addr,
- &accept_addr_len, child_processes_inherit, error);
-
+ accept_loop.Run();
+
if (error.Fail())
- break;
-
- bool is_same_addr = true;
-#if !(defined(__linux__) || (defined(_WIN32)))
- is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len);
-#endif
- if (is_same_addr)
- is_same_addr = (accept_addr.sin_addr.s_addr ==
- listen_addr.sockaddr_in().sin_addr.s_addr);
-
- if (is_same_addr ||
- (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY)) {
- accept_connection = true;
- accepted_socket.reset(new TCPSocket(sock, true));
- } else {
- const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr;
- const uint8_t *listen_ip =
- (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr;
- ::fprintf(stderr, "error: rejecting incoming connection from %u.%u.%u.%u "
- "(expecting %u.%u.%u.%u)\n",
- accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
- listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
- accepted_socket.reset();
+ return error;
+
+ lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];
+ if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
+ CLOSE_SOCKET(sock);
+ llvm::errs() << llvm::formatv(
+ "error: rejecting incoming connection from {0} (expecting {1})",
+ AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
+ continue;
}
+ accept_connection = true;
+ accepted_socket.reset(new TCPSocket(sock, *this));
}
if (!accepted_socket)
diff --git a/contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp b/contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp
deleted file mode 100644
index b3f9ede..0000000
--- a/contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-//===-- ThisThread.cpp ------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/ThisThread.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Host/HostInfo.h"
-
-#include "llvm/ADT/STLExtras.h"
-
-#include <algorithm>
-
-using namespace lldb;
-using namespace lldb_private;
-
-void ThisThread::SetName(llvm::StringRef name, int max_length) {
- std::string truncated_name(name.data());
-
- // Thread names are coming in like '<lldb.comm.debugger.edit>' and
- // '<lldb.comm.debugger.editline>'. So just chopping the end of the string
- // off leads to a lot of similar named threads. Go through the thread name
- // and search for the last dot and use that.
-
- if (max_length > 0 &&
- truncated_name.length() > static_cast<size_t>(max_length)) {
- // First see if we can get lucky by removing any initial or final braces.
- std::string::size_type begin = truncated_name.find_first_not_of("(<");
- std::string::size_type end = truncated_name.find_last_not_of(")>.");
- if (end - begin > static_cast<size_t>(max_length)) {
- // We're still too long. Since this is a dotted component, use everything
- // after the last
- // dot, up to a maximum of |length| characters.
- std::string::size_type last_dot = truncated_name.rfind('.');
- if (last_dot != std::string::npos)
- begin = last_dot + 1;
-
- end = std::min(end, begin + max_length);
- }
-
- std::string::size_type count = end - begin + 1;
- truncated_name = truncated_name.substr(begin, count);
- }
-
- SetName(truncated_name);
-}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp b/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp
index b91c2fe..f340101 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp
@@ -10,10 +10,9 @@
// lldb Includes
#include "lldb/Host/ThreadLauncher.h"
-#include "lldb/Core/Log.h"
#include "lldb/Host/HostNativeThread.h"
#include "lldb/Host/HostThread.h"
-#include "lldb/Host/ThisThread.h"
+#include "lldb/Utility/Log.h"
#if defined(_WIN32)
#include "lldb/Host/windows/windows.h"
@@ -25,9 +24,9 @@ using namespace lldb_private;
HostThread ThreadLauncher::LaunchThread(llvm::StringRef name,
lldb::thread_func_t thread_function,
lldb::thread_arg_t thread_arg,
- Error *error_ptr,
+ Status *error_ptr,
size_t min_stack_byte_size) {
- Error error;
+ Status error;
if (error_ptr)
error_ptr->Clear();
diff --git a/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp b/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp
index 972f87e..21dacbc 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp
@@ -9,8 +9,8 @@
#include "lldb/Host/common/UDPSocket.h"
-#include "lldb/Core/Log.h"
#include "lldb/Host/Config.h"
+#include "lldb/Utility/Log.h"
#ifndef LLDB_DISABLE_POSIX
#include <arpa/inet.h>
@@ -30,65 +30,45 @@ const int kType = SOCK_DGRAM;
static const char *g_not_supported_error = "Not supported";
}
-UDPSocket::UDPSocket(NativeSocket socket) : Socket(socket, ProtocolUdp, true) {}
+UDPSocket::UDPSocket(NativeSocket socket) : Socket(ProtocolUdp, true, true) {
+ m_socket = socket;
+}
-UDPSocket::UDPSocket(bool child_processes_inherit, Error &error)
- : UDPSocket(
- CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {}
+UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit)
+ : Socket(ProtocolUdp, should_close, child_processes_inherit) {}
size_t UDPSocket::Send(const void *buf, const size_t num_bytes) {
return ::sendto(m_socket, static_cast<const char *>(buf), num_bytes, 0,
- m_send_sockaddr, m_send_sockaddr.GetLength());
+ m_sockaddr, m_sockaddr.GetLength());
}
-Error UDPSocket::Connect(llvm::StringRef name) {
- return Error("%s", g_not_supported_error);
+Status UDPSocket::Connect(llvm::StringRef name) {
+ return Status("%s", g_not_supported_error);
}
-Error UDPSocket::Listen(llvm::StringRef name, int backlog) {
- return Error("%s", g_not_supported_error);
+Status UDPSocket::Listen(llvm::StringRef name, int backlog) {
+ return Status("%s", g_not_supported_error);
}
-Error UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit,
- Socket *&socket) {
- return Error("%s", g_not_supported_error);
+Status UDPSocket::Accept(Socket *&socket) {
+ return Status("%s", g_not_supported_error);
}
-Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit,
- Socket *&send_socket, Socket *&recv_socket) {
- std::unique_ptr<UDPSocket> final_send_socket;
- std::unique_ptr<UDPSocket> final_recv_socket;
+Status UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit,
+ Socket *&socket) {
+ std::unique_ptr<UDPSocket> final_socket;
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
log->Printf("UDPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
- Error error;
+ Status error;
std::string host_str;
std::string port_str;
int32_t port = INT32_MIN;
if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
return error;
- // Setup the receiving end of the UDP connection on this localhost
- // on port zero. After we bind to port zero we can read the port.
- final_recv_socket.reset(new UDPSocket(child_processes_inherit, error));
- if (error.Success()) {
- // Socket was created, now lets bind to the requested port
- SocketAddress addr;
- addr.SetToAnyAddress(AF_INET, 0);
-
- if (::bind(final_recv_socket->GetNativeSocket(), addr, addr.GetLength()) ==
- -1) {
- // Bind failed...
- SetLastError(error);
- }
- }
-
- assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid()));
- if (error.Fail())
- return error;
-
// At this point we have setup the receive port, now we need to
// setup the UDP send socket
@@ -118,8 +98,8 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit,
service_info_ptr->ai_family, service_info_ptr->ai_socktype,
service_info_ptr->ai_protocol, child_processes_inherit, error);
if (error.Success()) {
- final_send_socket.reset(new UDPSocket(send_fd));
- final_send_socket->m_send_sockaddr = service_info_ptr;
+ final_socket.reset(new UDPSocket(send_fd));
+ final_socket->m_sockaddr = service_info_ptr;
break;
} else
continue;
@@ -127,11 +107,31 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit,
::freeaddrinfo(service_info_list);
- if (!final_send_socket)
+ if (!final_socket)
return error;
- send_socket = final_send_socket.release();
- recv_socket = final_recv_socket.release();
+ SocketAddress bind_addr;
+
+ // Only bind to the loopback address if we are expecting a connection from
+ // localhost to avoid any firewall issues.
+ const bool bind_addr_success = (host_str == "127.0.0.1" || host_str == "localhost")
+ ? bind_addr.SetToLocalhost(kDomain, port)
+ : bind_addr.SetToAnyAddress(kDomain, port);
+
+ if (!bind_addr_success) {
+ error.SetErrorString("Failed to get hostspec to bind for");
+ return error;
+ }
+
+ bind_addr.SetPort(0); // Let the source port # be determined dynamically
+
+ err = ::bind(final_socket->GetNativeSocket(), bind_addr, bind_addr.GetLength());
+
+ struct sockaddr_in source_info;
+ socklen_t address_len = sizeof (struct sockaddr_in);
+ err = ::getsockname(final_socket->GetNativeSocket(), (struct sockaddr *) &source_info, &address_len);
+
+ socket = final_socket.release();
error.Clear();
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp b/contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp
index aeab780..037dfc7 100644
--- a/contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp
@@ -26,22 +26,19 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
-
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
#include "lldb/Utility/NameMatches.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/Support/Host.h"
@@ -52,64 +49,56 @@ extern char **environ;
using namespace lldb;
using namespace lldb_private;
-size_t Host::GetEnvironment(StringList &env) {
- char *v;
- char **var = environ;
- for (; var != NULL && *var != NULL; ++var) {
- v = strchr(*var, (int)'-');
- if (v == NULL)
- continue;
- env.AppendString(v);
- }
- return env.GetSize();
-}
-
static bool
GetFreeBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
ProcessInstanceInfo &process_info) {
- if (process_info.ProcessIDIsValid()) {
- int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS,
- (int)process_info.GetProcessID()};
-
- char arg_data[8192];
- size_t arg_data_size = sizeof(arg_data);
- if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) == 0) {
- DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),
- sizeof(void *));
- lldb::offset_t offset = 0;
- const char *cstr;
-
- cstr = data.GetCStr(&offset);
- if (cstr) {
- process_info.GetExecutableFile().SetFile(cstr, false);
-
- if (!(match_info_ptr == NULL ||
- NameMatches(
- process_info.GetExecutableFile().GetFilename().GetCString(),
- match_info_ptr->GetNameMatchType(),
- match_info_ptr->GetProcessInfo().GetName())))
- return false;
-
- Args &proc_args = process_info.GetArguments();
- while (1) {
- const uint8_t *p = data.PeekData(offset, 1);
- while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {
- ++offset;
- p = data.PeekData(offset, 1);
- }
- if (p == NULL || offset >= arg_data_size)
- return true;
-
- cstr = data.GetCStr(&offset);
- if (cstr)
- proc_args.AppendArgument(llvm::StringRef(cstr));
- else
- return true;
- }
- }
+ if (!process_info.ProcessIDIsValid())
+ return false;
+
+ int pid = process_info.GetProcessID();
+
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS, pid};
+
+ char arg_data[8192];
+ size_t arg_data_size = sizeof(arg_data);
+ if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) != 0)
+ return false;
+
+ DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),
+ sizeof(void *));
+ lldb::offset_t offset = 0;
+ const char *cstr;
+
+ cstr = data.GetCStr(&offset);
+ if (!cstr)
+ return false;
+
+ process_info.GetExecutableFile().SetFile(cstr, false);
+
+ if (!(match_info_ptr == NULL ||
+ NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),
+ match_info_ptr->GetNameMatchType(),
+ match_info_ptr->GetProcessInfo().GetName())))
+ return false;
+
+ Args &proc_args = process_info.GetArguments();
+ while (1) {
+ const uint8_t *p = data.PeekData(offset, 1);
+ while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {
+ ++offset;
+ p = data.PeekData(offset, 1);
}
+ if (p == NULL || offset >= arg_data_size)
+ break;
+
+ cstr = data.GetCStr(&offset);
+ if (!cstr)
+ break;
+
+ proc_args.AppendArgument(llvm::StringRef(cstr));
}
- return false;
+
+ return true;
}
static bool GetFreeBSDProcessCPUType(ProcessInstanceInfo &process_info) {
@@ -125,26 +114,31 @@ static bool GetFreeBSDProcessCPUType(ProcessInstanceInfo &process_info) {
static bool GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
struct kinfo_proc proc_kinfo;
size_t proc_kinfo_size;
+ const int pid = process_info.GetProcessID();
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
- if (process_info.ProcessIDIsValid()) {
- int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
- (int)process_info.GetProcessID()};
- proc_kinfo_size = sizeof(struct kinfo_proc);
-
- if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
- if (proc_kinfo_size > 0) {
- process_info.SetParentProcessID(proc_kinfo.ki_ppid);
- process_info.SetUserID(proc_kinfo.ki_ruid);
- process_info.SetGroupID(proc_kinfo.ki_rgid);
- process_info.SetEffectiveUserID(proc_kinfo.ki_uid);
- if (proc_kinfo.ki_ngroups > 0)
- process_info.SetEffectiveGroupID(proc_kinfo.ki_groups[0]);
- else
- process_info.SetEffectiveGroupID(UINT32_MAX);
- return true;
- }
- }
- }
+ if (!process_info.ProcessIDIsValid())
+ goto error;
+
+ proc_kinfo_size = sizeof(struct kinfo_proc);
+
+ if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) != 0)
+ goto error;
+
+ if (proc_kinfo_size == 0)
+ goto error;
+
+ process_info.SetParentProcessID(proc_kinfo.ki_ppid);
+ process_info.SetUserID(proc_kinfo.ki_ruid);
+ process_info.SetGroupID(proc_kinfo.ki_rgid);
+ process_info.SetEffectiveUserID(proc_kinfo.ki_uid);
+ if (proc_kinfo.ki_ngroups > 0)
+ process_info.SetEffectiveGroupID(proc_kinfo.ki_groups[0]);
+ else
+ process_info.SetEffectiveGroupID(UINT32_MAX);
+ return true;
+
+error:
process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
process_info.SetUserID(UINT32_MAX);
process_info.SetGroupID(UINT32_MAX);
@@ -155,7 +149,11 @@ static bool GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &process_infos) {
+ const ::pid_t our_pid = ::getpid();
+ const ::uid_t our_uid = ::getuid();
std::vector<struct kinfo_proc> kinfos;
+ // Special case, if lldb is being run as root we can attach to anything.
+ bool all_users = match_info.GetMatchAllUsers() || (our_uid == 0);
int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
@@ -175,29 +173,24 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
- bool all_users = match_info.GetMatchAllUsers();
- const ::pid_t our_pid = getpid();
- const uid_t our_uid = getuid();
for (size_t i = 0; i < actual_pid_count; i++) {
const struct kinfo_proc &kinfo = kinfos[i];
- const bool kinfo_user_matches = (all_users || (kinfo.ki_ruid == our_uid) ||
- // Special case, if lldb is being run as
- // root we can attach to anything.
- (our_uid == 0));
-
- if (kinfo_user_matches == false || // Make sure the user is acceptable
- kinfo.ki_pid == our_pid || // Skip this process
- kinfo.ki_pid == 0 || // Skip kernel (kernel pid is zero)
- kinfo.ki_stat == SZOMB || // Zombies are bad, they like brains...
- kinfo.ki_flag & P_TRACED || // Being debugged?
- kinfo.ki_flag & P_WEXIT) // Working on exiting
+
+ /* Make sure the user is acceptable */
+ if (!all_users && kinfo.ki_ruid != our_uid)
+ continue;
+
+ if (kinfo.ki_pid == our_pid || // Skip this process
+ kinfo.ki_pid == 0 || // Skip kernel (kernel pid is 0)
+ kinfo.ki_stat == SZOMB || // Zombies are bad
+ kinfo.ki_flag & P_TRACED || // Being debugged?
+ kinfo.ki_flag & P_WEXIT) // Working on exiting
continue;
// Every thread is a process in FreeBSD, but all the threads of a single
- // process
- // have the same pid. Do not store the process info in the result list if a
- // process
- // with given identifier is already registered there.
+ // process have the same pid. Do not store the process info in the
+ // result list if a process with given identifier is already registered
+ // there.
bool already_registered = false;
for (uint32_t pi = 0;
!already_registered && (const int)kinfo.ki_numthreads > 1 &&
@@ -243,23 +236,15 @@ bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
return false;
}
-lldb::DataBufferSP Host::GetAuxvData(lldb_private::Process *process) {
- int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, 0};
- size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo);
- DataBufferSP buf_sp;
-
- std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(auxv_size, 0));
-
- mib[3] = process->GetID();
- if (::sysctl(mib, 4, buf_ap->GetBytes(), &auxv_size, NULL, 0) == 0) {
- buf_sp.reset(buf_ap.release());
- } else {
- perror("sysctl failed on auxv");
- }
-
- return buf_sp;
+size_t Host::GetEnvironment(StringList &env) {
+ char **host_env = environ;
+ char *env_entry;
+ size_t i;
+ for (i = 0; (env_entry = host_env[i]) != NULL; ++i)
+ env.AppendString(env_entry);
+ return i;
}
-Error Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
- return Error("unimplemented");
+Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
+ return Status("unimplemented");
}
diff --git a/contrib/llvm/tools/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp
index fb9d866..9c82fcc 100644
--- a/contrib/llvm/tools/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp
@@ -14,11 +14,10 @@
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/utsname.h>
+#include <unistd.h>
using namespace lldb_private;
-uint32_t HostInfoFreeBSD::GetMaxThreadNameLength() { return 16; }
-
bool HostInfoFreeBSD::GetOSVersion(uint32_t &major, uint32_t &minor,
uint32_t &update) {
struct utsname un;
diff --git a/contrib/llvm/tools/lldb/source/Host/freebsd/HostThreadFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Host/freebsd/HostThreadFreeBSD.cpp
deleted file mode 100644
index 97d4d9d..0000000
--- a/contrib/llvm/tools/lldb/source/Host/freebsd/HostThreadFreeBSD.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-//===-- HostThreadFreeBSD.cpp -----------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// lldb Includes
-#include "lldb/Host/freebsd/HostThreadFreeBSD.h"
-#include "lldb/Host/Host.h"
-
-// C includes
-#include <errno.h>
-#include <pthread.h>
-#if defined(__FreeBSD__)
-#include <pthread_np.h>
-#endif
-#include <stdlib.h>
-#include <sys/sysctl.h>
-#include <sys/user.h>
-
-// C++ includes
-#include <string>
-
-using namespace lldb_private;
-
-HostThreadFreeBSD::HostThreadFreeBSD() {}
-
-HostThreadFreeBSD::HostThreadFreeBSD(lldb::thread_t thread)
- : HostThreadPosix(thread) {}
-
-void HostThreadFreeBSD::GetName(lldb::tid_t tid,
- llvm::SmallVectorImpl<char> &name) {
- name.clear();
- int pid = Host::GetCurrentProcessID();
-
- struct kinfo_proc *kp = nullptr, *nkp;
- size_t len = 0;
- int error;
- int ctl[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
- (int)pid};
-
- while (1) {
- error = sysctl(ctl, 4, kp, &len, nullptr, 0);
- if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
- // Add extra space in case threads are added before next call.
- len += sizeof(*kp) + len / 10;
- nkp = (struct kinfo_proc *)realloc(kp, len);
- if (nkp == nullptr) {
- free(kp);
- return;
- }
- kp = nkp;
- continue;
- }
- if (error != 0)
- len = 0;
- break;
- }
-
- for (size_t i = 0; i < len / sizeof(*kp); i++) {
- if (kp[i].ki_tid == (lwpid_t)tid) {
- name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname));
- break;
- }
- }
- free(kp);
-}
diff --git a/contrib/llvm/tools/lldb/source/Host/freebsd/ThisThread.cpp b/contrib/llvm/tools/lldb/source/Host/freebsd/ThisThread.cpp
deleted file mode 100644
index da0f237..0000000
--- a/contrib/llvm/tools/lldb/source/Host/freebsd/ThisThread.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===-- ThisThread.cpp ------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/ThisThread.h"
-#include "lldb/Host/HostNativeThread.h"
-
-#include "llvm/ADT/SmallVector.h"
-
-#include <pthread.h>
-#if defined(__FreeBSD__)
-#include <pthread_np.h>
-#endif
-
-using namespace lldb_private;
-
-void ThisThread::SetName(llvm::StringRef name) {
-#if defined(__FreeBSD__) // Kfreebsd does not have a simple alternative
- ::pthread_set_name_np(::pthread_self(), name.data());
-#endif
-}
-
-void ThisThread::GetName(llvm::SmallVectorImpl<char> &name) {
-#if defined(__FreeBSD__)
- HostNativeThread::GetName(::pthread_getthreadid_np(), name);
-#else
- // Kfreebsd
- HostNativeThread::GetName((unsigned)pthread_self(), name);
-#endif
-}
diff --git a/contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp b/contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp
index 717af9b..d927f95 100644
--- a/contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp
@@ -1,5 +1,4 @@
-//===-- source/Host/netbsd/Host.cpp ------------------------------*- C++
-//-*-===//
+//===-- source/Host/netbsd/Host.cpp -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,7 +14,6 @@
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/types.h>
-#include <sys/user.h>
#include <limits.h>
@@ -27,22 +25,19 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
-
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
#include "lldb/Utility/NameMatches.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/Support/Host.h"
@@ -54,15 +49,12 @@ using namespace lldb;
using namespace lldb_private;
size_t Host::GetEnvironment(StringList &env) {
- char *v;
- char **var = environ;
- for (; var != NULL && *var != NULL; ++var) {
- v = ::strchr(*var, (int)'-');
- if (v == NULL)
- continue;
- env.AppendString(v);
- }
- return env.GetSize();
+ char **host_env = environ;
+ char *env_entry;
+ size_t i;
+ for (i = 0; (env_entry = host_env[i]) != NULL; ++i)
+ env.AppendString(env_entry);
+ return i;
}
static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
@@ -259,10 +251,6 @@ bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
return false;
}
-lldb::DataBufferSP Host::GetAuxvData(lldb_private::Process *process) {
- return lldb::DataBufferSP();
-}
-
-Error Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
- return Error("unimplemented");
+Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
+ return Status("unimplemented");
}
diff --git a/contrib/llvm/tools/lldb/source/Host/netbsd/HostInfoNetBSD.cpp b/contrib/llvm/tools/lldb/source/Host/netbsd/HostInfoNetBSD.cpp
index 3c1385a..428183b 100644
--- a/contrib/llvm/tools/lldb/source/Host/netbsd/HostInfoNetBSD.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/netbsd/HostInfoNetBSD.cpp
@@ -21,10 +21,6 @@
using namespace lldb_private;
-uint32_t HostInfoNetBSD::GetMaxThreadNameLength() {
- return PTHREAD_MAX_NAMELEN_NP;
-}
-
bool HostInfoNetBSD::GetOSVersion(uint32_t &major, uint32_t &minor,
uint32_t &update) {
struct utsname un;
@@ -85,15 +81,15 @@ FileSpec HostInfoNetBSD::GetProgramFileSpec() {
static FileSpec g_program_filespec;
if (!g_program_filespec) {
- ssize_t len;
- static char buf[PATH_MAX];
- char name[PATH_MAX];
-
- ::snprintf(name, PATH_MAX, "/proc/%d/exe", ::getpid());
- len = ::readlink(name, buf, PATH_MAX - 1);
- if (len != -1) {
- buf[len] = '\0';
- g_program_filespec.SetFile(buf, false);
+ static const int name[] = {
+ CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME,
+ };
+ char path[MAXPATHLEN];
+ size_t len;
+
+ len = sizeof(path);
+ if (sysctl(name, __arraycount(name), path, &len, NULL, 0) != -1) {
+ g_program_filespec.SetFile(path, false);
}
}
return g_program_filespec;
diff --git a/contrib/llvm/tools/lldb/source/Host/netbsd/HostThreadNetBSD.cpp b/contrib/llvm/tools/lldb/source/Host/netbsd/HostThreadNetBSD.cpp
deleted file mode 100644
index e8c106b..0000000
--- a/contrib/llvm/tools/lldb/source/Host/netbsd/HostThreadNetBSD.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//===-- HostThreadNetBSD.cpp -----------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// lldb Includes
-#include "lldb/Host/netbsd/HostThreadNetBSD.h"
-#include "lldb/Host/Host.h"
-
-// C includes
-#include <errno.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/sysctl.h>
-#include <sys/user.h>
-
-// C++ includes
-#include <string>
-
-using namespace lldb_private;
-
-HostThreadNetBSD::HostThreadNetBSD() {}
-
-HostThreadNetBSD::HostThreadNetBSD(lldb::thread_t thread)
- : HostThreadPosix(thread) {}
-
-void HostThreadNetBSD::SetName(lldb::thread_t thread, llvm::StringRef &name) {
- ::pthread_setname_np(thread, "%s", const_cast<char *>(name.data()));
-}
-
-void HostThreadNetBSD::GetName(lldb::thread_t thread,
- llvm::SmallVectorImpl<char> &name) {
- char buf[PTHREAD_MAX_NAMELEN_NP];
- ::pthread_getname_np(thread, buf, PTHREAD_MAX_NAMELEN_NP);
-
- name.clear();
- name.append(buf, buf + strlen(buf));
-}
diff --git a/contrib/llvm/tools/lldb/source/Host/netbsd/ThisThread.cpp b/contrib/llvm/tools/lldb/source/Host/netbsd/ThisThread.cpp
deleted file mode 100644
index ea16981..0000000
--- a/contrib/llvm/tools/lldb/source/Host/netbsd/ThisThread.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-//===-- ThisThread.cpp ------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/ThisThread.h"
-#include "lldb/Host/HostNativeThread.h"
-
-#include "llvm/ADT/SmallVector.h"
-
-#include <pthread.h>
-#include <string.h>
-
-using namespace lldb_private;
-
-void ThisThread::SetName(llvm::StringRef name) {
- HostNativeThread::SetName(::pthread_self(), name);
-}
-
-void ThisThread::GetName(llvm::SmallVectorImpl<char> &name) {
- HostNativeThread::GetName(::pthread_self(), name);
-}
diff --git a/contrib/llvm/tools/lldb/source/Host/openbsd/Host.cpp b/contrib/llvm/tools/lldb/source/Host/openbsd/Host.cpp
new file mode 100644
index 0000000..0535256
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/openbsd/Host.cpp
@@ -0,0 +1,222 @@
+//===-- source/Host/openbsd/Host.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <sys/types.h>
+
+#include <sys/signal.h>
+#include <sys/exec.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <stdio.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/NameMatches.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "llvm/Support/Host.h"
+
+extern "C" {
+extern char **environ;
+}
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t Host::GetEnvironment(StringList &env) {
+ char *v;
+ char **var = environ;
+ for (; var != NULL && *var != NULL; ++var) {
+ v = strchr(*var, (int)'-');
+ if (v == NULL)
+ continue;
+ env.AppendString(v);
+ }
+ return env.GetSize();
+}
+
+static bool
+GetOpenBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
+ ProcessInstanceInfo &process_info) {
+ if (process_info.ProcessIDIsValid()) {
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS,
+ (int)process_info.GetProcessID()};
+
+ char arg_data[8192];
+ size_t arg_data_size = sizeof(arg_data);
+ if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) == 0) {
+ DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),
+ sizeof(void *));
+ lldb::offset_t offset = 0;
+ const char *cstr;
+
+ cstr = data.GetCStr(&offset);
+ if (cstr) {
+ process_info.GetExecutableFile().SetFile(cstr, false);
+
+ if (!(match_info_ptr == NULL ||
+ NameMatches(
+ process_info.GetExecutableFile().GetFilename().GetCString(),
+ match_info_ptr->GetNameMatchType(),
+ match_info_ptr->GetProcessInfo().GetName())))
+ return false;
+
+ Args &proc_args = process_info.GetArguments();
+ while (1) {
+ const uint8_t *p = data.PeekData(offset, 1);
+ while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {
+ ++offset;
+ p = data.PeekData(offset, 1);
+ }
+ if (p == NULL || offset >= arg_data_size)
+ return true;
+
+ cstr = data.GetCStr(&offset);
+ if (cstr)
+ proc_args.AppendArgument(llvm::StringRef(cstr));
+ else
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool GetOpenBSDProcessCPUType(ProcessInstanceInfo &process_info) {
+ if (process_info.ProcessIDIsValid()) {
+ process_info.GetArchitecture() =
+ HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+ return true;
+ }
+ process_info.GetArchitecture().Clear();
+ return false;
+}
+
+static bool GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
+ struct kinfo_proc proc_kinfo;
+ size_t proc_kinfo_size;
+
+ if (process_info.ProcessIDIsValid()) {
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
+ (int)process_info.GetProcessID()};
+ proc_kinfo_size = sizeof(struct kinfo_proc);
+
+ if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
+ if (proc_kinfo_size > 0) {
+ process_info.SetParentProcessID(proc_kinfo.p_ppid);
+ process_info.SetUserID(proc_kinfo.p_ruid);
+ process_info.SetGroupID(proc_kinfo.p_rgid);
+ process_info.SetEffectiveUserID(proc_kinfo.p_uid);
+ process_info.SetEffectiveGroupID(proc_kinfo.p_gid);
+ return true;
+ }
+ }
+ }
+ process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
+ process_info.SetUserID(UINT32_MAX);
+ process_info.SetGroupID(UINT32_MAX);
+ process_info.SetEffectiveUserID(UINT32_MAX);
+ process_info.SetEffectiveGroupID(UINT32_MAX);
+ return false;
+}
+
+uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos) {
+ std::vector<struct kinfo_proc> kinfos;
+
+ int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
+
+ size_t pid_data_size = 0;
+ if (::sysctl(mib, 3, NULL, &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ // Add a few extra in case a few more show up
+ const size_t estimated_pid_count =
+ (pid_data_size / sizeof(struct kinfo_proc)) + 10;
+
+ kinfos.resize(estimated_pid_count);
+ pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
+
+ if (::sysctl(mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
+
+ bool all_users = match_info.GetMatchAllUsers();
+ const ::pid_t our_pid = getpid();
+ const uid_t our_uid = getuid();
+ for (size_t i = 0; i < actual_pid_count; i++) {
+ const struct kinfo_proc &kinfo = kinfos[i];
+ const bool kinfo_user_matches = (all_users || (kinfo.p_ruid == our_uid) ||
+ // Special case, if lldb is being run as
+ // root we can attach to anything.
+ (our_uid == 0));
+
+ if (kinfo_user_matches == false || // Make sure the user is acceptable
+ kinfo.p_pid == our_pid || // Skip this process
+ kinfo.p_pid == 0 || // Skip kernel (kernel pid is zero)
+ kinfo.p_stat == SZOMB || // Zombies are bad, they like brains...
+ kinfo.p_psflags & PS_TRACED || // Being debugged?
+ kinfo.p_flag & P_WEXIT) // Working on exiting
+ continue;
+
+ ProcessInstanceInfo process_info;
+ process_info.SetProcessID(kinfo.p_pid);
+ process_info.SetParentProcessID(kinfo.p_ppid);
+ process_info.SetUserID(kinfo.p_ruid);
+ process_info.SetGroupID(kinfo.p_rgid);
+ process_info.SetEffectiveUserID(kinfo.p_svuid);
+ process_info.SetEffectiveGroupID(kinfo.p_svgid);
+
+ // Make sure our info matches before we go fetch the name and cpu type
+ if (match_info.Matches(process_info) &&
+ GetOpenBSDProcessArgs(&match_info, process_info)) {
+ GetOpenBSDProcessCPUType(process_info);
+ if (match_info.Matches(process_info))
+ process_infos.Append(process_info);
+ }
+ }
+
+ return process_infos.GetSize();
+}
+
+bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
+ process_info.SetProcessID(pid);
+
+ if (GetOpenBSDProcessArgs(NULL, process_info)) {
+ // should use libprocstat instead of going right into sysctl?
+ GetOpenBSDProcessCPUType(process_info);
+ GetOpenBSDProcessUserAndGroup(process_info);
+ return true;
+ }
+
+ process_info.Clear();
+ return false;
+}
+
+Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
+ return Status("unimplemented");
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/openbsd/HostInfoOpenBSD.cpp b/contrib/llvm/tools/lldb/source/Host/openbsd/HostInfoOpenBSD.cpp
new file mode 100644
index 0000000..5489588
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/openbsd/HostInfoOpenBSD.cpp
@@ -0,0 +1,65 @@
+//===-- HostInfoOpenBSD.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/openbsd/HostInfoOpenBSD.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+
+using namespace lldb_private;
+
+bool HostInfoOpenBSD::GetOSVersion(uint32_t &major, uint32_t &minor,
+ uint32_t &update) {
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(utsname));
+ if (uname(&un) < 0)
+ return false;
+
+ int status = sscanf(un.release, "%u.%u", &major, &minor);
+ return status == 2;
+}
+
+bool HostInfoOpenBSD::GetOSBuildString(std::string &s) {
+ int mib[2] = {CTL_KERN, KERN_OSREV};
+ char osrev_str[12];
+ uint32_t osrev = 0;
+ size_t osrev_len = sizeof(osrev);
+
+ if (::sysctl(mib, 2, &osrev, &osrev_len, NULL, 0) == 0) {
+ ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev);
+ s.assign(osrev_str);
+ return true;
+ }
+
+ s.clear();
+ return false;
+}
+
+bool HostInfoOpenBSD::GetOSKernelDescription(std::string &s) {
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(utsname));
+ s.clear();
+
+ if (uname(&un) < 0)
+ return false;
+
+ s.assign(un.version);
+
+ return true;
+}
+
+FileSpec HostInfoOpenBSD::GetProgramFileSpec() {
+ static FileSpec g_program_filespec;
+ return g_program_filespec;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
index 64101fd..3797650 100644
--- a/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
@@ -16,11 +16,10 @@
#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
#include "lldb/Host/Config.h"
-#include "lldb/Host/IOObject.h"
#include "lldb/Host/Socket.h"
#include "lldb/Host/SocketAddress.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Utility/SelectHelper.h"
+#include "lldb/Utility/Timeout.h"
// C Includes
#include <errno.h>
@@ -31,25 +30,25 @@
#ifndef LLDB_DISABLE_POSIX
#include <termios.h>
+#include <unistd.h>
#endif
// C++ Includes
#include <sstream>
// Other libraries and framework includes
+#include "llvm/Support/Errno.h"
#include "llvm/Support/ErrorHandling.h"
#if defined(__APPLE__)
#include "llvm/ADT/SmallVector.h"
#endif
// Project includes
-#include "lldb/Core/Communication.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Socket.h"
#include "lldb/Host/common/TCPSocket.h"
-#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
@@ -125,7 +124,7 @@ void ConnectionFileDescriptor::OpenCommandPipe() {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
// Make the command file descriptor here:
- Error result = m_pipe.CreateNew(m_child_processes_inherit);
+ Status result = m_pipe.CreateNew(m_child_processes_inherit);
if (!result.Success()) {
if (log)
log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not "
@@ -155,7 +154,7 @@ bool ConnectionFileDescriptor::IsConnected() const {
}
ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path,
- Error *error_ptr) {
+ Status *error_ptr) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
@@ -220,7 +219,7 @@ ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path,
// assume we don't own it.
std::unique_ptr<TCPSocket> tcp_socket;
- tcp_socket.reset(new TCPSocket(fd, false));
+ tcp_socket.reset(new TCPSocket(fd, false, false));
// Try and get a socket option from this file descriptor to
// see if this is a socket and set m_is_socket accordingly.
int resuse;
@@ -247,11 +246,7 @@ ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path,
} else if ((addr = GetURLAddress(path, FILE_SCHEME))) {
std::string addr_str = addr->str();
// file:///PATH
- int fd = -1;
- do {
- fd = ::open(addr_str.c_str(), O_RDWR);
- } while (fd == -1 && errno == EINTR);
-
+ int fd = llvm::sys::RetryAfterSignal(-1, ::open, addr_str.c_str(), O_RDWR);
if (fd == -1) {
if (error_ptr)
error_ptr->SetErrorToErrno();
@@ -301,11 +296,11 @@ ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path,
bool ConnectionFileDescriptor::InterruptRead() {
size_t bytes_written = 0;
- Error result = m_pipe.Write("i", 1, bytes_written);
+ Status result = m_pipe.Write("i", 1, bytes_written);
return result.Success();
}
-ConnectionStatus ConnectionFileDescriptor::Disconnect(Error *error_ptr) {
+ConnectionStatus ConnectionFileDescriptor::Disconnect(Status *error_ptr) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
log->Printf("%p ConnectionFileDescriptor::Disconnect ()",
@@ -339,7 +334,7 @@ ConnectionStatus ConnectionFileDescriptor::Disconnect(Error *error_ptr) {
if (!locker.try_lock()) {
if (m_pipe.CanWrite()) {
size_t bytes_written = 0;
- Error result = m_pipe.Write("q", 1, bytes_written);
+ Status result = m_pipe.Write("q", 1, bytes_written);
if (log)
log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get "
"the lock, sent 'q' to %d, error = '%s'.",
@@ -353,8 +348,8 @@ ConnectionStatus ConnectionFileDescriptor::Disconnect(Error *error_ptr) {
locker.lock();
}
- Error error = m_read_sp->Close();
- Error error2 = m_write_sp->Close();
+ Status error = m_read_sp->Close();
+ Status error2 = m_write_sp->Close();
if (error.Fail() || error2.Fail())
status = eConnectionStatusError;
if (error_ptr)
@@ -371,7 +366,7 @@ ConnectionStatus ConnectionFileDescriptor::Disconnect(Error *error_ptr) {
size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len,
const Timeout<std::micro> &timeout,
ConnectionStatus &status,
- Error *error_ptr) {
+ Status *error_ptr) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);
@@ -396,7 +391,7 @@ size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len,
if (status != eConnectionStatusSuccess)
return 0;
- Error error;
+ Status error;
size_t bytes_read = dst_len;
error = m_read_sp->Read(dst, bytes_read);
@@ -463,10 +458,8 @@ size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len,
return 0;
default:
- if (log)
- log->Printf(
- "%p ConnectionFileDescriptor::Read (), unexpected error: %s",
- static_cast<void *>(this), strerror(error_value));
+ LLDB_LOG(log, "this = {0}, unexpected error: {1}", this,
+ llvm::sys::StrError(error_value));
status = eConnectionStatusError;
break; // Break to close....
}
@@ -478,7 +471,7 @@ size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len,
size_t ConnectionFileDescriptor::Write(const void *src, size_t src_len,
ConnectionStatus &status,
- Error *error_ptr) {
+ Status *error_ptr) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
if (log)
log->Printf(
@@ -493,7 +486,7 @@ size_t ConnectionFileDescriptor::Write(const void *src, size_t src_len,
return 0;
}
- Error error;
+ Status error;
size_t bytes_sent = src_len;
error = m_write_sp->Write(src, bytes_sent);
@@ -555,16 +548,13 @@ std::string ConnectionFileDescriptor::GetURI() { return m_uri; }
ConnectionStatus
ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout,
- Error *error_ptr) {
+ Status *error_ptr) {
// Don't need to take the mutex here separately since we are only called from
// Read. If we
// ever get used more generally we will need to lock here as well.
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_CONNECTION));
- if (log)
- log->Printf(
- "%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %lu)",
- static_cast<void *>(this), long(timeout ? timeout->count() : -1));
+ LLDB_LOG(log, "this = {0}, timeout = {1}", this, timeout);
// Make a copy of the file descriptors to make sure we don't
// have another thread change these values out from under us
@@ -593,7 +583,7 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout,
while (handle == m_read_sp->GetWaitableHandle()) {
- Error error = select_helper.Select();
+ Status error = select_helper.Select();
if (error_ptr)
*error_ptr = error;
@@ -627,20 +617,17 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout,
if (select_helper.FDIsSetRead(pipe_fd)) {
// There is an interrupt or exit command in the command pipe
// Read the data from that pipe:
- char buffer[1];
+ char c;
- ssize_t bytes_read;
-
- do {
- bytes_read = ::read(pipe_fd, buffer, sizeof(buffer));
- } while (bytes_read < 0 && errno == EINTR);
-
- switch (buffer[0]) {
+ ssize_t bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1);
+ assert(bytes_read == 1);
+ (void)bytes_read;
+ switch (c) {
case 'q':
if (log)
log->Printf("%p ConnectionFileDescriptor::BytesAvailable() "
"got data: %c from the command channel.",
- static_cast<void *>(this), buffer[0]);
+ static_cast<void *>(this), c);
return eConnectionStatusEndOfFile;
case 'i':
// Interrupt the current read
@@ -658,9 +645,9 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout,
ConnectionStatus
ConnectionFileDescriptor::NamedSocketAccept(llvm::StringRef socket_name,
- Error *error_ptr) {
+ Status *error_ptr) {
Socket *socket = nullptr;
- Error error =
+ Status error =
Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket);
if (error_ptr)
*error_ptr = error;
@@ -675,9 +662,9 @@ ConnectionFileDescriptor::NamedSocketAccept(llvm::StringRef socket_name,
ConnectionStatus
ConnectionFileDescriptor::NamedSocketConnect(llvm::StringRef socket_name,
- Error *error_ptr) {
+ Status *error_ptr) {
Socket *socket = nullptr;
- Error error =
+ Status error =
Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket);
if (error_ptr)
*error_ptr = error;
@@ -692,10 +679,10 @@ ConnectionFileDescriptor::NamedSocketConnect(llvm::StringRef socket_name,
lldb::ConnectionStatus
ConnectionFileDescriptor::UnixAbstractSocketConnect(llvm::StringRef socket_name,
- Error *error_ptr) {
+ Status *error_ptr) {
Socket *socket = nullptr;
- Error error = Socket::UnixAbstractConnect(socket_name,
- m_child_processes_inherit, socket);
+ Status error = Socket::UnixAbstractConnect(socket_name,
+ m_child_processes_inherit, socket);
if (error_ptr)
*error_ptr = error;
m_write_sp.reset(socket);
@@ -709,13 +696,13 @@ ConnectionFileDescriptor::UnixAbstractSocketConnect(llvm::StringRef socket_name,
ConnectionStatus
ConnectionFileDescriptor::SocketListenAndAccept(llvm::StringRef s,
- Error *error_ptr) {
+ Status *error_ptr) {
m_port_predicate.SetValue(0, eBroadcastNever);
Socket *socket = nullptr;
m_waiting_for_accept = true;
- Error error = Socket::TcpListen(s, m_child_processes_inherit, socket,
- &m_port_predicate);
+ Status error = Socket::TcpListen(s, m_child_processes_inherit, socket,
+ &m_port_predicate);
if (error_ptr)
*error_ptr = error;
if (error.Fail())
@@ -725,7 +712,7 @@ ConnectionFileDescriptor::SocketListenAndAccept(llvm::StringRef s,
listening_socket_up.reset(socket);
socket = nullptr;
- error = listening_socket_up->Accept(s, m_child_processes_inherit, socket);
+ error = listening_socket_up->Accept(socket);
listening_socket_up.reset();
if (error_ptr)
*error_ptr = error;
@@ -737,9 +724,9 @@ ConnectionFileDescriptor::SocketListenAndAccept(llvm::StringRef s,
}
ConnectionStatus ConnectionFileDescriptor::ConnectTCP(llvm::StringRef s,
- Error *error_ptr) {
+ Status *error_ptr) {
Socket *socket = nullptr;
- Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket);
+ Status error = Socket::TcpConnect(s, m_child_processes_inherit, socket);
if (error_ptr)
*error_ptr = error;
m_write_sp.reset(socket);
@@ -752,15 +739,13 @@ ConnectionStatus ConnectionFileDescriptor::ConnectTCP(llvm::StringRef s,
}
ConnectionStatus ConnectionFileDescriptor::ConnectUDP(llvm::StringRef s,
- Error *error_ptr) {
- Socket *send_socket = nullptr;
- Socket *recv_socket = nullptr;
- Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket,
- recv_socket);
+ Status *error_ptr) {
+ Socket *socket = nullptr;
+ Status error = Socket::UdpConnect(s, m_child_processes_inherit, socket);
if (error_ptr)
*error_ptr = error;
- m_write_sp.reset(send_socket);
- m_read_sp.reset(recv_socket);
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
if (error.Fail()) {
return eConnectionStatusError;
}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp b/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp
index cb0a1d0..3e3abad 100644
--- a/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp
@@ -9,7 +9,7 @@
#include "lldb/Host/posix/DomainSocket.h"
-#include "lldb/Host/FileSystem.h"
+#include "llvm/Support/FileSystem.h"
#include <stddef.h>
#include <sys/socket.h>
@@ -56,27 +56,32 @@ bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
return true;
}
-}
-
-DomainSocket::DomainSocket(NativeSocket socket)
- : Socket(socket, ProtocolUnixDomain, true) {}
+} // namespace
-DomainSocket::DomainSocket(bool child_processes_inherit, Error &error)
- : DomainSocket(
- CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {}
+DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit)
+ : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {}
DomainSocket::DomainSocket(SocketProtocol protocol,
- bool child_processes_inherit, Error &error)
- : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error),
- protocol, true) {}
+ bool child_processes_inherit)
+ : Socket(protocol, true, child_processes_inherit) {}
+
+DomainSocket::DomainSocket(NativeSocket socket,
+ const DomainSocket &listen_socket)
+ : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd,
+ listen_socket.m_child_processes_inherit) {
+ m_socket = socket;
+}
-Error DomainSocket::Connect(llvm::StringRef name) {
+Status DomainSocket::Connect(llvm::StringRef name) {
sockaddr_un saddr_un;
socklen_t saddr_un_len;
if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
- return Error("Failed to set socket address");
+ return Status("Failed to set socket address");
- Error error;
+ Status error;
+ m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error);
+ if (error.Fail())
+ return error;
if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) <
0)
SetLastError(error);
@@ -84,15 +89,18 @@ Error DomainSocket::Connect(llvm::StringRef name) {
return error;
}
-Error DomainSocket::Listen(llvm::StringRef name, int backlog) {
+Status DomainSocket::Listen(llvm::StringRef name, int backlog) {
sockaddr_un saddr_un;
socklen_t saddr_un_len;
if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
- return Error("Failed to set socket address");
+ return Status("Failed to set socket address");
DeleteSocketFile(name);
- Error error;
+ Status error;
+ m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error);
+ if (error.Fail())
+ return error;
if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) ==
0)
if (::listen(GetNativeSocket(), backlog) == 0)
@@ -102,13 +110,12 @@ Error DomainSocket::Listen(llvm::StringRef name, int backlog) {
return error;
}
-Error DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit,
- Socket *&socket) {
- Error error;
+Status DomainSocket::Accept(Socket *&socket) {
+ Status error;
auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr,
- child_processes_inherit, error);
+ m_child_processes_inherit, error);
if (error.Success())
- socket = new DomainSocket(conn_fd);
+ socket = new DomainSocket(conn_fd, *this);
return error;
}
@@ -116,5 +123,5 @@ Error DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit,
size_t DomainSocket::GetNameOffset() const { return 0; }
void DomainSocket::DeleteSocketFile(llvm::StringRef name) {
- FileSystem::Unlink(FileSpec{name, true});
+ llvm::sys::fs::remove(name);
}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/FileSystem.cpp b/contrib/llvm/tools/lldb/source/Host/posix/FileSystem.cpp
index aaa53ce..3ece067 100644
--- a/contrib/llvm/tools/lldb/source/Host/posix/FileSystem.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/posix/FileSystem.cpp
@@ -15,6 +15,7 @@
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <unistd.h>
#ifdef __linux__
#include <linux/magic.h>
#include <sys/mount.h>
@@ -25,165 +26,26 @@
#endif
// lldb Includes
-#include "lldb/Core/Error.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Host/Host.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "llvm/Support/FileSystem.h"
using namespace lldb;
using namespace lldb_private;
const char *FileSystem::DEV_NULL = "/dev/null";
-FileSpec::PathSyntax FileSystem::GetNativePathSyntax() {
- return FileSpec::ePathSyntaxPosix;
-}
-
-Error FileSystem::MakeDirectory(const FileSpec &file_spec,
- uint32_t file_permissions) {
- if (file_spec) {
- Error error;
- if (::mkdir(file_spec.GetCString(), file_permissions) == -1) {
- error.SetErrorToErrno();
- errno = 0;
- switch (error.GetError()) {
- case ENOENT: {
- // Parent directory doesn't exist, so lets make it if we can
- // Make the parent directory and try again
- FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false};
- error = MakeDirectory(parent_file_spec, file_permissions);
- if (error.Fail())
- return error;
- // Try and make the directory again now that the parent directory was
- // made successfully
- if (::mkdir(file_spec.GetCString(), file_permissions) == -1) {
- error.SetErrorToErrno();
- }
- return error;
- } break;
- case EEXIST: {
- if (file_spec.IsDirectory())
- return Error(); // It is a directory and it already exists
- } break;
- }
- }
- return error;
- }
- return Error("empty path");
-}
-
-Error FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) {
- Error error;
- if (file_spec) {
- if (recurse) {
- // Save all sub directories in a list so we don't recursively call this
- // function
- // and possibly run out of file descriptors if the directory is too deep.
- std::vector<FileSpec> sub_directories;
-
- FileSpec::ForEachItemInDirectory(
- file_spec.GetCString(),
- [&error, &sub_directories](
- FileSpec::FileType file_type,
- const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult {
- if (file_type == FileSpec::eFileTypeDirectory) {
- // Save all directorires and process them after iterating through
- // this directory
- sub_directories.push_back(spec);
- } else {
- // Update sub_spec to point to the current file and delete it
- error = FileSystem::Unlink(spec);
- }
- // If anything went wrong, stop iterating, else process the next
- // file
- if (error.Fail())
- return FileSpec::eEnumerateDirectoryResultQuit;
- else
- return FileSpec::eEnumerateDirectoryResultNext;
- });
-
- if (error.Success()) {
- // Now delete all sub directories with separate calls that aren't
- // recursively calling into this function _while_ this function is
- // iterating through the current directory.
- for (const auto &sub_directory : sub_directories) {
- error = DeleteDirectory(sub_directory, recurse);
- if (error.Fail())
- break;
- }
- }
- }
-
- if (error.Success()) {
- if (::rmdir(file_spec.GetCString()) != 0)
- error.SetErrorToErrno();
- }
- } else {
- error.SetErrorString("empty path");
- }
- return error;
-}
-
-Error FileSystem::GetFilePermissions(const FileSpec &file_spec,
- uint32_t &file_permissions) {
- Error error;
- struct stat file_stats;
- if (::stat(file_spec.GetCString(), &file_stats) == 0) {
- // The bits in "st_mode" currently match the definitions
- // for the file mode bits in unix.
- file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
- } else {
- error.SetErrorToErrno();
- }
- return error;
-}
-
-Error FileSystem::SetFilePermissions(const FileSpec &file_spec,
- uint32_t file_permissions) {
- Error error;
- if (::chmod(file_spec.GetCString(), file_permissions) != 0)
- error.SetErrorToErrno();
- return error;
-}
-
-lldb::user_id_t FileSystem::GetFileSize(const FileSpec &file_spec) {
- return file_spec.GetByteSize();
-}
-
-bool FileSystem::GetFileExists(const FileSpec &file_spec) {
- return file_spec.Exists();
-}
-
-Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) {
- Error error;
- if (::link(dst.GetCString(), src.GetCString()) == -1)
- error.SetErrorToErrno();
- return error;
-}
-
-int FileSystem::GetHardlinkCount(const FileSpec &file_spec) {
- struct stat file_stat;
- if (::stat(file_spec.GetCString(), &file_stat) == 0)
- return file_stat.st_nlink;
-
- return -1;
-}
-
-Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) {
- Error error;
+Status FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) {
+ Status error;
if (::symlink(dst.GetCString(), src.GetCString()) == -1)
error.SetErrorToErrno();
return error;
}
-Error FileSystem::Unlink(const FileSpec &file_spec) {
- Error error;
- if (::unlink(file_spec.GetCString()) == -1)
- error.SetErrorToErrno();
- return error;
-}
-
-Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) {
- Error error;
+Status FileSystem::Readlink(const FileSpec &src, FileSpec &dst) {
+ Status error;
char buf[PATH_MAX];
ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1);
if (count < 0)
@@ -195,68 +57,24 @@ Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) {
return error;
}
-Error FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) {
+Status FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) {
char resolved_path[PATH_MAX];
if (!src.GetPath(resolved_path, sizeof(resolved_path))) {
- return Error("Couldn't get the canonical path for %s", src.GetCString());
+ return Status("Couldn't get the canonical path for %s", src.GetCString());
}
char real_path[PATH_MAX + 1];
if (realpath(resolved_path, real_path) == nullptr) {
- Error err;
+ Status err;
err.SetErrorToErrno();
return err;
}
dst = FileSpec(real_path, false);
- return Error();
-}
-
-#if defined(__NetBSD__)
-static bool IsLocal(const struct statvfs &info) {
- return (info.f_flag & MNT_LOCAL) != 0;
+ return Status();
}
-#else
-static bool IsLocal(const struct statfs &info) {
-#ifdef __linux__
-#define CIFS_MAGIC_NUMBER 0xFF534D42
- switch ((uint32_t)info.f_type) {
- case NFS_SUPER_MAGIC:
- case SMB_SUPER_MAGIC:
- case CIFS_MAGIC_NUMBER:
- return false;
- default:
- return true;
- }
-#else
- return (info.f_flags & MNT_LOCAL) != 0;
-#endif
-}
-#endif
-
-#if defined(__NetBSD__)
-bool FileSystem::IsLocal(const FileSpec &spec) {
- struct statvfs statfs_info;
- std::string path(spec.GetPath());
- if (statvfs(path.c_str(), &statfs_info) == 0)
- return ::IsLocal(statfs_info);
- return false;
-}
-#else
-bool FileSystem::IsLocal(const FileSpec &spec) {
- struct statfs statfs_info;
- std::string path(spec.GetPath());
- if (statfs(path.c_str(), &statfs_info) == 0)
- return ::IsLocal(statfs_info);
- return false;
-}
-#endif
FILE *FileSystem::Fopen(const char *path, const char *mode) {
return ::fopen(path, mode);
}
-
-int FileSystem::Stat(const char *path, struct stat *stats) {
- return ::stat(path, stats);
-}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/HostInfoPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/HostInfoPosix.cpp
index 38aac59..da9e1fb 100644
--- a/contrib/llvm/tools/lldb/source/Host/posix/HostInfoPosix.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/posix/HostInfoPosix.cpp
@@ -11,8 +11,8 @@
#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
#endif
-#include "lldb/Core/Log.h"
#include "lldb/Host/posix/HostInfoPosix.h"
+#include "lldb/Utility/Log.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/HostProcessPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/HostProcessPosix.cpp
index 9dd9fef..3c5273f 100644
--- a/contrib/llvm/tools/lldb/source/Host/posix/HostProcessPosix.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/posix/HostProcessPosix.cpp
@@ -13,7 +13,9 @@
#include "llvm/ADT/STLExtras.h"
+#include <csignal>
#include <limits.h>
+#include <unistd.h>
using namespace lldb_private;
@@ -29,9 +31,9 @@ HostProcessPosix::HostProcessPosix(lldb::process_t process)
HostProcessPosix::~HostProcessPosix() {}
-Error HostProcessPosix::Signal(int signo) const {
+Status HostProcessPosix::Signal(int signo) const {
if (m_process == kInvalidPosixProcess) {
- Error error;
+ Status error;
error.SetErrorString("HostProcessPosix refers to an invalid process");
return error;
}
@@ -39,8 +41,8 @@ Error HostProcessPosix::Signal(int signo) const {
return HostProcessPosix::Signal(m_process, signo);
}
-Error HostProcessPosix::Signal(lldb::process_t process, int signo) {
- Error error;
+Status HostProcessPosix::Signal(lldb::process_t process, int signo) {
+ Status error;
if (-1 == ::kill(process, signo))
error.SetErrorToErrno();
@@ -48,10 +50,10 @@ Error HostProcessPosix::Signal(lldb::process_t process, int signo) {
return error;
}
-Error HostProcessPosix::Terminate() { return Signal(SIGKILL); }
+Status HostProcessPosix::Terminate() { return Signal(SIGKILL); }
-Error HostProcessPosix::GetMainModule(FileSpec &file_spec) const {
- Error error;
+Status HostProcessPosix::GetMainModule(FileSpec &file_spec) const {
+ Status error;
// Use special code here because proc/[pid]/exe is a symbolic link.
char link_path[PATH_MAX];
@@ -82,7 +84,7 @@ bool HostProcessPosix::IsRunning() const {
return false;
// Send this process the null signal. If it succeeds the process is running.
- Error error = Signal(0);
+ Status error = Signal(0);
return error.Success();
}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/HostThreadPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/HostThreadPosix.cpp
index ac39899..0f4434d 100644
--- a/contrib/llvm/tools/lldb/source/Host/posix/HostThreadPosix.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/posix/HostThreadPosix.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/posix/HostThreadPosix.h"
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Status.h"
#include <errno.h>
#include <pthread.h>
@@ -23,8 +23,8 @@ HostThreadPosix::HostThreadPosix(lldb::thread_t thread)
HostThreadPosix::~HostThreadPosix() {}
-Error HostThreadPosix::Join(lldb::thread_result_t *result) {
- Error error;
+Status HostThreadPosix::Join(lldb::thread_result_t *result) {
+ Status error;
if (IsJoinable()) {
int err = ::pthread_join(m_thread, result);
error.SetError(err, lldb::eErrorTypePOSIX);
@@ -38,8 +38,8 @@ Error HostThreadPosix::Join(lldb::thread_result_t *result) {
return error;
}
-Error HostThreadPosix::Cancel() {
- Error error;
+Status HostThreadPosix::Cancel() {
+ Status error;
if (IsJoinable()) {
#ifndef __ANDROID__
#ifndef __FreeBSD__
@@ -54,8 +54,8 @@ Error HostThreadPosix::Cancel() {
return error;
}
-Error HostThreadPosix::Detach() {
- Error error;
+Status HostThreadPosix::Detach() {
+ Status error;
if (IsJoinable()) {
int err = ::pthread_detach(m_thread);
error.SetError(err, eErrorTypePOSIX);
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/LockFilePosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/LockFilePosix.cpp
index d1cc617..0542306 100644
--- a/contrib/llvm/tools/lldb/source/Host/posix/LockFilePosix.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/posix/LockFilePosix.cpp
@@ -10,14 +10,15 @@
#include "lldb/Host/posix/LockFilePosix.h"
#include <fcntl.h>
+#include <unistd.h>
using namespace lldb;
using namespace lldb_private;
namespace {
-Error fileLock(int fd, int cmd, int lock_type, const uint64_t start,
- const uint64_t len) {
+Status fileLock(int fd, int cmd, int lock_type, const uint64_t start,
+ const uint64_t len) {
struct flock fl;
fl.l_type = lock_type;
@@ -26,7 +27,7 @@ Error fileLock(int fd, int cmd, int lock_type, const uint64_t start,
fl.l_len = len;
fl.l_pid = ::getpid();
- Error error;
+ Status error;
if (::fcntl(fd, cmd, &fl) == -1)
error.SetErrorToErrno();
@@ -39,22 +40,22 @@ LockFilePosix::LockFilePosix(int fd) : LockFileBase(fd) {}
LockFilePosix::~LockFilePosix() { Unlock(); }
-Error LockFilePosix::DoWriteLock(const uint64_t start, const uint64_t len) {
+Status LockFilePosix::DoWriteLock(const uint64_t start, const uint64_t len) {
return fileLock(m_fd, F_SETLKW, F_WRLCK, start, len);
}
-Error LockFilePosix::DoTryWriteLock(const uint64_t start, const uint64_t len) {
+Status LockFilePosix::DoTryWriteLock(const uint64_t start, const uint64_t len) {
return fileLock(m_fd, F_SETLK, F_WRLCK, start, len);
}
-Error LockFilePosix::DoReadLock(const uint64_t start, const uint64_t len) {
+Status LockFilePosix::DoReadLock(const uint64_t start, const uint64_t len) {
return fileLock(m_fd, F_SETLKW, F_RDLCK, start, len);
}
-Error LockFilePosix::DoTryReadLock(const uint64_t start, const uint64_t len) {
+Status LockFilePosix::DoTryReadLock(const uint64_t start, const uint64_t len) {
return fileLock(m_fd, F_SETLK, F_RDLCK, start, len);
}
-Error LockFilePosix::DoUnlock() {
+Status LockFilePosix::DoUnlock() {
return fileLock(m_fd, F_SETLK, F_UNLCK, m_start, m_len);
}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp
deleted file mode 100644
index 08c969e..0000000
--- a/contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-//===-- MainLoopPosix.cpp ---------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/posix/MainLoopPosix.h"
-#include "lldb/Core/Error.h"
-#include <algorithm>
-#include <cassert>
-#include <cerrno>
-#include <csignal>
-#include <vector>
-#include <sys/select.h>
-
-using namespace lldb;
-using namespace lldb_private;
-
-static sig_atomic_t g_signal_flags[NSIG];
-
-static void SignalHandler(int signo, siginfo_t *info, void *) {
- assert(signo < NSIG);
- g_signal_flags[signo] = 1;
-}
-
-MainLoopPosix::~MainLoopPosix() {
- assert(m_read_fds.size() == 0);
- assert(m_signals.size() == 0);
-}
-
-MainLoopPosix::ReadHandleUP
-MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp,
- const Callback &callback, Error &error) {
- if (!object_sp || !object_sp->IsValid()) {
- error.SetErrorString("IO object is not valid.");
- return nullptr;
- }
-
- const bool inserted =
- m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
- if (!inserted) {
- error.SetErrorStringWithFormat("File descriptor %d already monitored.",
- object_sp->GetWaitableHandle());
- return nullptr;
- }
-
- return CreateReadHandle(object_sp);
-}
-
-// We shall block the signal, then install the signal handler. The signal will
-// be unblocked in
-// the Run() function to check for signal delivery.
-MainLoopPosix::SignalHandleUP
-MainLoopPosix::RegisterSignal(int signo, const Callback &callback,
- Error &error) {
- if (m_signals.find(signo) != m_signals.end()) {
- error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
- return nullptr;
- }
-
- SignalInfo info;
- info.callback = callback;
- struct sigaction new_action;
- new_action.sa_sigaction = &SignalHandler;
- new_action.sa_flags = SA_SIGINFO;
- sigemptyset(&new_action.sa_mask);
- sigaddset(&new_action.sa_mask, signo);
-
- sigset_t old_set;
- if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) {
- error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n",
- ret);
- return nullptr;
- }
-
- info.was_blocked = sigismember(&old_set, signo);
- if (sigaction(signo, &new_action, &info.old_action) == -1) {
- error.SetErrorToErrno();
- if (!info.was_blocked)
- pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr);
- return nullptr;
- }
-
- m_signals.insert({signo, info});
- g_signal_flags[signo] = 0;
-
- return SignalHandleUP(new SignalHandle(*this, signo));
-}
-
-void MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle) {
- bool erased = m_read_fds.erase(handle);
- UNUSED_IF_ASSERT_DISABLED(erased);
- assert(erased);
-}
-
-void MainLoopPosix::UnregisterSignal(int signo) {
- // We undo the actions of RegisterSignal on a best-effort basis.
- auto it = m_signals.find(signo);
- assert(it != m_signals.end());
-
- sigaction(signo, &it->second.old_action, nullptr);
-
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, signo);
- pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set,
- nullptr);
-
- m_signals.erase(it);
-}
-
-Error MainLoopPosix::Run() {
- std::vector<int> signals;
- sigset_t sigmask;
- std::vector<int> read_fds;
- fd_set read_fd_set;
- m_terminate_request = false;
-
- // run until termination or until we run out of things to listen to
- while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
- // To avoid problems with callbacks changing the things we're supposed to
- // listen to, we
- // will store the *real* list of events separately.
- signals.clear();
- read_fds.clear();
- FD_ZERO(&read_fd_set);
- int nfds = 0;
-
- if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
- return Error("pthread_sigmask failed with error %d\n", ret);
-
- for (const auto &fd : m_read_fds) {
- read_fds.push_back(fd.first);
- FD_SET(fd.first, &read_fd_set);
- nfds = std::max(nfds, fd.first + 1);
- }
-
- for (const auto &sig : m_signals) {
- signals.push_back(sig.first);
- sigdelset(&sigmask, sig.first);
- }
-
- if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) ==
- -1 &&
- errno != EINTR)
- return Error(errno, eErrorTypePOSIX);
-
- for (int sig : signals) {
- if (g_signal_flags[sig] == 0)
- continue; // No signal
- g_signal_flags[sig] = 0;
-
- auto it = m_signals.find(sig);
- if (it == m_signals.end())
- continue; // Signal must have gotten unregistered in the meantime
-
- it->second.callback(*this); // Do the work
-
- if (m_terminate_request)
- return Error();
- }
-
- for (int fd : read_fds) {
- if (!FD_ISSET(fd, &read_fd_set))
- continue; // Not ready
-
- auto it = m_read_fds.find(fd);
- if (it == m_read_fds.end())
- continue; // File descriptor must have gotten unregistered in the
- // meantime
-
- it->second(*this); // Do the work
-
- if (m_terminate_request)
- return Error();
- }
- }
- return Error();
-}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/PipePosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/PipePosix.cpp
index 4e0810c..da99fd7 100644
--- a/contrib/llvm/tools/lldb/source/Host/posix/PipePosix.cpp
+++ b/contrib/llvm/tools/lldb/source/Host/posix/PipePosix.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/posix/PipePosix.h"
-#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Utility/SelectHelper.h"
#include "llvm/ADT/SmallString.h"
@@ -83,11 +82,11 @@ PipePosix &PipePosix::operator=(PipePosix &&pipe_posix) {
PipePosix::~PipePosix() { Close(); }
-Error PipePosix::CreateNew(bool child_processes_inherit) {
+Status PipePosix::CreateNew(bool child_processes_inherit) {
if (CanRead() || CanWrite())
- return Error(EINVAL, eErrorTypePOSIX);
+ return Status(EINVAL, eErrorTypePOSIX);
- Error error;
+ Status error;
#if PIPE2_SUPPORTED
if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
return error;
@@ -112,20 +111,20 @@ Error PipePosix::CreateNew(bool child_processes_inherit) {
return error;
}
-Error PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) {
+Status PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) {
if (CanRead() || CanWrite())
- return Error("Pipe is already opened");
+ return Status("Pipe is already opened");
- Error error;
+ Status error;
if (::mkfifo(name.data(), 0660) != 0)
error.SetErrorToErrno();
return error;
}
-Error PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
- bool child_process_inherit,
- llvm::SmallVectorImpl<char> &name) {
+Status PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
+ bool child_process_inherit,
+ llvm::SmallVectorImpl<char> &name) {
llvm::SmallString<PATH_MAX> named_pipe_path;
llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
FileSpec tmpdir_file_spec;
@@ -140,7 +139,7 @@ Error PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
// It's possible that another process creates the target path after we've
// verified it's available but before we create it, in which case we
// should try again.
- Error error;
+ Status error;
do {
llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(),
named_pipe_path);
@@ -152,16 +151,16 @@ Error PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
return error;
}
-Error PipePosix::OpenAsReader(llvm::StringRef name,
- bool child_process_inherit) {
+Status PipePosix::OpenAsReader(llvm::StringRef name,
+ bool child_process_inherit) {
if (CanRead() || CanWrite())
- return Error("Pipe is already opened");
+ return Status("Pipe is already opened");
int flags = O_RDONLY | O_NONBLOCK;
if (!child_process_inherit)
flags |= O_CLOEXEC;
- Error error;
+ Status error;
int fd = ::open(name.data(), flags);
if (fd != -1)
m_fds[READ] = fd;
@@ -171,11 +170,12 @@ Error PipePosix::OpenAsReader(llvm::StringRef name,
return error;
}
-Error PipePosix::OpenAsWriterWithTimeout(
- llvm::StringRef name, bool child_process_inherit,
- const std::chrono::microseconds &timeout) {
+Status
+PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name,
+ bool child_process_inherit,
+ const std::chrono::microseconds &timeout) {
if (CanRead() || CanWrite())
- return Error("Pipe is already opened");
+ return Status("Pipe is already opened");
int flags = O_WRONLY | O_NONBLOCK;
if (!child_process_inherit)
@@ -188,7 +188,7 @@ Error PipePosix::OpenAsWriterWithTimeout(
if (timeout != microseconds::zero()) {
const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
if (dur <= 0)
- return Error("timeout exceeded - reader hasn't opened so far");
+ return Status("timeout exceeded - reader hasn't opened so far");
}
errno = 0;
@@ -197,7 +197,7 @@ Error PipePosix::OpenAsWriterWithTimeout(
const auto errno_copy = errno;
// We may get ENXIO if a reader side of the pipe hasn't opened yet.
if (errno_copy != ENXIO)
- return Error(errno_copy, eErrorTypePOSIX);
+ return Status(errno_copy, eErrorTypePOSIX);
std::this_thread::sleep_for(
milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
@@ -206,7 +206,7 @@ Error PipePosix::OpenAsWriterWithTimeout(
}
}
- return Error();
+ return Status();
}
int PipePosix::GetReadFileDescriptor() const { return m_fds[READ]; }
@@ -230,8 +230,8 @@ void PipePosix::Close() {
CloseWriteFileDescriptor();
}
-Error PipePosix::Delete(llvm::StringRef name) {
- return FileSystem::Unlink(FileSpec{name.data(), true});
+Status PipePosix::Delete(llvm::StringRef name) {
+ return llvm::sys::fs::remove(name);
}
bool PipePosix::CanRead() const {
@@ -256,12 +256,12 @@ void PipePosix::CloseWriteFileDescriptor() {
}
}
-Error PipePosix::ReadWithTimeout(void *buf, size_t size,
- const std::chrono::microseconds &timeout,
- size_t &bytes_read) {
+Status PipePosix::ReadWithTimeout(void *buf, size_t size,
+ const std::chrono::microseconds &timeout,
+ size_t &bytes_read) {
bytes_read = 0;
if (!CanRead())
- return Error(EINVAL, eErrorTypePOSIX);
+ return Status(EINVAL, eErrorTypePOSIX);
const int fd = GetReadFileDescriptor();
@@ -269,7 +269,7 @@ Error PipePosix::ReadWithTimeout(void *buf, size_t size,
select_helper.SetTimeout(timeout);
select_helper.FDSetRead(fd);
- Error error;
+ Status error;
while (error.Success()) {
error = select_helper.Select();
if (error.Success()) {
@@ -288,17 +288,17 @@ Error PipePosix::ReadWithTimeout(void *buf, size_t size,
return error;
}
-Error PipePosix::Write(const void *buf, size_t size, size_t &bytes_written) {
+Status PipePosix::Write(const void *buf, size_t size, size_t &bytes_written) {
bytes_written = 0;
if (!CanWrite())
- return Error(EINVAL, eErrorTypePOSIX);
+ return Status(EINVAL, eErrorTypePOSIX);
const int fd = GetWriteFileDescriptor();
SelectHelper select_helper;
select_helper.SetTimeout(std::chrono::seconds(0));
select_helper.FDSetWrite(fd);
- Error error;
+ Status error;
while (error.Success()) {
error = select_helper.Select();
if (error.Success()) {
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp
deleted file mode 100644
index f90bf0c..0000000
--- a/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//===-- ProcessLauncherPosix.cpp --------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/posix/ProcessLauncherPosix.h"
-#include "lldb/Host/Host.h"
-#include "lldb/Host/HostProcess.h"
-
-#include "lldb/Target/ProcessLaunchInfo.h"
-
-#include <limits.h>
-
-using namespace lldb;
-using namespace lldb_private;
-
-HostProcess
-ProcessLauncherPosix::LaunchProcess(const ProcessLaunchInfo &launch_info,
- Error &error) {
- lldb::pid_t pid;
- char exe_path[PATH_MAX];
-
- launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
-
- // TODO(zturner): Move the code from LaunchProcessPosixSpawn to here, and make
- // MacOSX re-use this
- // ProcessLauncher when it wants a posix_spawn launch.
- error = Host::LaunchProcessPosixSpawn(exe_path, launch_info, pid);
- return HostProcess(pid);
-}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
new file mode 100644
index 0000000..66c0229
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
@@ -0,0 +1,234 @@
+//===-- ProcessLauncherLinux.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/Pipe.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/Support/Errno.h"
+
+#include <limits.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <sstream>
+#include <csignal>
+
+#ifdef __ANDROID__
+#include <android/api-level.h>
+#define PT_TRACE_ME PTRACE_TRACEME
+#endif
+
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+#include <linux/personality.h>
+#elif defined(__linux__)
+#include <sys/personality.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void FixupEnvironment(Args &env) {
+#ifdef __ANDROID__
+ // If there is no PATH variable specified inside the environment then set the
+ // path to /system/bin. It is required because the default path used by
+ // execve() is wrong on android.
+ static const char *path = "PATH=";
+ for (auto &entry : env.entries()) {
+ if (entry.ref.startswith(path))
+ return;
+ }
+ env.AppendArgument(llvm::StringRef("PATH=/system/bin"));
+#endif
+}
+
+static void LLVM_ATTRIBUTE_NORETURN ExitWithError(int error_fd,
+ const char *operation) {
+ int err = errno;
+ llvm::raw_fd_ostream os(error_fd, true);
+ os << operation << " failed: " << llvm::sys::StrError(err);
+ os.flush();
+ _exit(1);
+}
+
+static void DisableASLRIfRequested(int error_fd, const ProcessLaunchInfo &info) {
+#if defined(__linux__)
+ if (info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)) {
+ const unsigned long personality_get_current = 0xffffffff;
+ int value = personality(personality_get_current);
+ if (value == -1)
+ ExitWithError(error_fd, "personality get");
+
+ value = personality(ADDR_NO_RANDOMIZE | value);
+ if (value == -1)
+ ExitWithError(error_fd, "personality set");
+ }
+#endif
+}
+
+static void DupDescriptor(int error_fd, const FileSpec &file_spec, int fd,
+ int flags) {
+ int target_fd = ::open(file_spec.GetCString(), flags, 0666);
+
+ if (target_fd == -1)
+ ExitWithError(error_fd, "DupDescriptor-open");
+
+ if (target_fd == fd)
+ return;
+
+ if (::dup2(target_fd, fd) == -1)
+ ExitWithError(error_fd, "DupDescriptor-dup2");
+
+ ::close(target_fd);
+ return;
+}
+
+static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
+ const ProcessLaunchInfo &info) {
+ // First, make sure we disable all logging. If we are logging to stdout, our
+ // logs can be mistaken for inferior output.
+ Log::DisableAllLogChannels();
+
+ // Do not inherit setgid powers.
+ if (setgid(getgid()) != 0)
+ ExitWithError(error_fd, "setgid");
+
+ if (info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)) {
+ if (setpgid(0, 0) != 0)
+ ExitWithError(error_fd, "setpgid");
+ }
+
+ for (size_t i = 0; i < info.GetNumFileActions(); ++i) {
+ const FileAction &action = *info.GetFileActionAtIndex(i);
+ switch (action.GetAction()) {
+ case FileAction::eFileActionClose:
+ if (close(action.GetFD()) != 0)
+ ExitWithError(error_fd, "close");
+ break;
+ case FileAction::eFileActionDuplicate:
+ if (dup2(action.GetFD(), action.GetActionArgument()) == -1)
+ ExitWithError(error_fd, "dup2");
+ break;
+ case FileAction::eFileActionOpen:
+ DupDescriptor(error_fd, action.GetFileSpec(), action.GetFD(),
+ action.GetActionArgument());
+ break;
+ case FileAction::eFileActionNone:
+ break;
+ }
+ }
+
+ const char **argv = info.GetArguments().GetConstArgumentVector();
+
+ // Change working directory
+ if (info.GetWorkingDirectory() &&
+ 0 != ::chdir(info.GetWorkingDirectory().GetCString()))
+ ExitWithError(error_fd, "chdir");
+
+ DisableASLRIfRequested(error_fd, info);
+ Args env = info.GetEnvironmentEntries();
+ FixupEnvironment(env);
+ const char **envp = env.GetConstArgumentVector();
+
+ // Clear the signal mask to prevent the child from being affected by
+ // any masking done by the parent.
+ sigset_t set;
+ if (sigemptyset(&set) != 0 ||
+ pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
+ ExitWithError(error_fd, "pthread_sigmask");
+
+ if (info.GetFlags().Test(eLaunchFlagDebug)) {
+ // HACK:
+ // Close everything besides stdin, stdout, and stderr that has no file
+ // action to avoid leaking. Only do this when debugging, as elsewhere we
+ // actually rely on
+ // passing open descriptors to child processes.
+ for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd)
+ if (!info.GetFileActionForFD(fd) && fd != error_fd)
+ close(fd);
+
+ // Start tracing this child that is about to exec.
+ if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1)
+ ExitWithError(error_fd, "ptrace");
+ }
+
+ // Execute. We should never return...
+ execve(argv[0], const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+
+#if defined(__linux__)
+ if (errno == ETXTBSY) {
+ // On android M and earlier we can get this error because the adb deamon can
+ // hold a write
+ // handle on the executable even after it has finished uploading it. This
+ // state lasts
+ // only a short time and happens only when there are many concurrent adb
+ // commands being
+ // issued, such as when running the test suite. (The file remains open when
+ // someone does
+ // an "adb shell" command in the fork() child before it has had a chance to
+ // exec.) Since
+ // this state should clear up quickly, wait a while and then give it one
+ // more go.
+ usleep(50000);
+ execve(argv[0], const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+ }
+#endif
+
+ // ...unless exec fails. In which case we definitely need to end the child
+ // here.
+ ExitWithError(error_fd, "execve");
+}
+
+HostProcess
+ProcessLauncherPosixFork::LaunchProcess(const ProcessLaunchInfo &launch_info,
+ Status &error) {
+ char exe_path[PATH_MAX];
+ launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
+
+ // A pipe used by the child process to report errors.
+ PipePosix pipe;
+ const bool child_processes_inherit = false;
+ error = pipe.CreateNew(child_processes_inherit);
+ if (error.Fail())
+ return HostProcess();
+
+ ::pid_t pid = ::fork();
+ if (pid == -1) {
+ // Fork failed
+ error.SetErrorStringWithFormatv("Fork failed with error message: {0}",
+ llvm::sys::StrError());
+ return HostProcess(LLDB_INVALID_PROCESS_ID);
+ }
+ if (pid == 0) {
+ // child process
+ pipe.CloseReadFileDescriptor();
+ ChildFunc(pipe.ReleaseWriteFileDescriptor(), launch_info);
+ }
+
+ // parent process
+
+ pipe.CloseWriteFileDescriptor();
+ char buf[1000];
+ int r = read(pipe.GetReadFileDescriptor(), buf, sizeof buf);
+
+ if (r == 0)
+ return HostProcess(pid); // No error. We're done.
+
+ error.SetErrorString(buf);
+
+ waitpid(pid, nullptr, 0);
+
+ return HostProcess();
+}
diff --git a/contrib/llvm/tools/lldb/source/Initialization/SystemInitializerCommon.cpp b/contrib/llvm/tools/lldb/source/Initialization/SystemInitializerCommon.cpp
index de05731..29a3fb8 100644
--- a/contrib/llvm/tools/lldb/source/Initialization/SystemInitializerCommon.cpp
+++ b/contrib/llvm/tools/lldb/source/Initialization/SystemInitializerCommon.cpp
@@ -17,16 +17,16 @@
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
//#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Timer.h"
#if defined(__APPLE__)
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
#endif
-#if defined(__linux__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#endif
@@ -70,9 +70,10 @@ void SystemInitializerCommon::Initialize() {
#endif
llvm::EnablePrettyStackTrace();
- Log::Initialize();
+ InitializeLog();
HostInfo::Initialize();
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
process_gdb_remote::ProcessGDBRemoteLog::Initialize();
@@ -93,9 +94,8 @@ void SystemInitializerCommon::Initialize() {
#if defined(__APPLE__)
ObjectFileMachO::Initialize();
#endif
-#if defined(__linux__)
- static ConstString g_linux_log_name("linux");
- ProcessPOSIXLog::Initialize(g_linux_log_name);
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ ProcessPOSIXLog::Initialize();
#endif
#if defined(_MSC_VER)
ProcessWindowsLog::Initialize();
@@ -103,7 +103,8 @@ void SystemInitializerCommon::Initialize() {
}
void SystemInitializerCommon::Terminate() {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
ObjectContainerBSDArchive::Terminate();
ObjectFileELF::Terminate();
//ObjectFilePECOFF::Terminate();
@@ -122,5 +123,5 @@ void SystemInitializerCommon::Terminate() {
#endif
HostInfo::Terminate();
- Log::Terminate();
+ Log::DisableAllLogChannels();
}
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/Args.cpp b/contrib/llvm/tools/lldb/source/Interpreter/Args.cpp
index 6984328..a23ba30 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/Args.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/Args.cpp
@@ -12,18 +12,15 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/DataFormatters/FormatManager.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/Options.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
@@ -423,10 +420,10 @@ void Args::SetArguments(const char **argv) {
SetArguments(ArgvToArgc(argv), argv);
}
-Error Args::ParseOptions(Options &options, ExecutionContext *execution_context,
- PlatformSP platform_sp, bool require_validation) {
+Status Args::ParseOptions(Options &options, ExecutionContext *execution_context,
+ PlatformSP platform_sp, bool require_validation) {
StreamString sstr;
- Error error;
+ Status error;
Option *long_options = options.GetLongOptions();
if (long_options == nullptr) {
error.SetErrorStringWithFormat("invalid long options");
@@ -550,7 +547,7 @@ void Args::Clear() {
lldb::addr_t Args::StringToAddress(const ExecutionContext *exe_ctx,
llvm::StringRef s, lldb::addr_t fail_value,
- Error *error_ptr) {
+ Status *error_ptr) {
bool error_set = false;
if (s.empty()) {
if (error_ptr)
@@ -632,10 +629,8 @@ lldb::addr_t Args::StringToAddress(const ExecutionContext *exe_ctx,
add = str[0] == '+';
if (regex_match.GetMatchAtIndex(s, 3, str)) {
- offset = StringConvert::ToUInt64(str.c_str(), 0, 0, &success);
-
- if (success) {
- Error error;
+ if (!llvm::StringRef(str).getAsInteger(0, offset)) {
+ Status error;
addr = StringToAddress(exe_ctx, name.c_str(),
LLDB_INVALID_ADDRESS, &error);
if (addr != LLDB_INVALID_ADDRESS) {
@@ -779,7 +774,7 @@ const char *Args::GetShellSafeArgument(const FileSpec &shell,
int64_t Args::StringToOptionEnum(llvm::StringRef s,
OptionEnumValueElement *enum_values,
- int32_t fail_value, Error &error) {
+ int32_t fail_value, Status &error) {
error.Clear();
if (!enum_values) {
error.SetErrorString("invalid enumeration argument");
@@ -824,10 +819,10 @@ Args::StringToScriptLanguage(llvm::StringRef s, lldb::ScriptLanguage fail_value,
return fail_value;
}
-Error Args::StringToFormat(const char *s, lldb::Format &format,
- size_t *byte_size_ptr) {
+Status Args::StringToFormat(const char *s, lldb::Format &format,
+ size_t *byte_size_ptr) {
format = eFormatInvalid;
- Error error;
+ Status error;
if (s && s[0]) {
if (byte_size_ptr) {
@@ -931,12 +926,12 @@ bool Args::ContainsEnvironmentVariable(llvm::StringRef env_var_name,
// Check each arg to see if it matches the env var name.
for (auto arg : llvm::enumerate(m_entries)) {
llvm::StringRef name, value;
- std::tie(name, value) = arg.Value.ref.split('=');
+ std::tie(name, value) = arg.value().ref.split('=');
if (name != env_var_name)
continue;
if (argument_index)
- *argument_index = arg.Index;
+ *argument_index = arg.index();
return true;
}
@@ -954,9 +949,9 @@ size_t Args::FindArgumentIndexForOption(Option *long_options,
long_options[long_options_index].definition->long_option);
for (auto entry : llvm::enumerate(m_entries)) {
- if (entry.Value.ref.startswith(short_buffer) ||
- entry.Value.ref.startswith(long_buffer))
- return entry.Index;
+ if (entry.value().ref.startswith(short_buffer) ||
+ entry.value().ref.startswith(long_buffer))
+ return entry.index();
}
return size_t(-1);
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandAlias.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandAlias.cpp
index a8f5343..2db7460 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/CommandAlias.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandAlias.cpp
@@ -11,11 +11,11 @@
#include "llvm/Support/ErrorHandling.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/Options.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandHistory.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandHistory.cpp
index c16f713..ca5c906 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/CommandHistory.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandHistory.cpp
@@ -9,7 +9,6 @@
#include <inttypes.h>
-#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/CommandHistory.h"
using namespace lldb;
@@ -48,13 +47,13 @@ CommandHistory::FindString(llvm::StringRef input_str) const {
size_t idx = 0;
if (input_str.front() == '-') {
- if (input_str.drop_front(2).getAsInteger(0, idx))
+ if (input_str.drop_front(1).getAsInteger(0, idx))
return llvm::None;
if (idx >= m_history.size())
return llvm::None;
idx = m_history.size() - idx;
} else {
- if (input_str.drop_front().getAsInteger(0, idx))
+ if (input_str.getAsInteger(0, idx))
return llvm::None;
if (idx >= m_history.size())
return llvm::None;
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp
index d44eb25..986be7f 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -42,12 +42,12 @@
#include "../Commands/CommandObjectWatchpoint.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/Timer.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
#ifndef LLDB_DISABLE_LIBEDIT
#include "lldb/Host/Editline.h"
@@ -169,7 +169,8 @@ bool CommandInterpreter::GetSpaceReplPrompts() const {
}
void CommandInterpreter::Initialize() {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
CommandReturnObject result;
@@ -391,7 +392,8 @@ const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) {
}
void CommandInterpreter::LoadCommandDictionary() {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
lldb::ScriptLanguage script_language = m_debugger.GetScriptLanguage();
@@ -645,8 +647,8 @@ void CommandInterpreter::LoadCommandDictionary() {
"gdb-remote [<hostname>:]<portnum>", 2, 0, false));
if (connect_gdb_remote_cmd_ap.get()) {
if (connect_gdb_remote_cmd_ap->AddRegexCommand(
- "^([^:]+:[[:digit:]]+)$",
- "process connect --plugin gdb-remote connect://%1") &&
+ "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
+ "process connect --plugin gdb-remote connect://%1:%2") &&
connect_gdb_remote_cmd_ap->AddRegexCommand(
"^([[:digit:]]+)$",
"process connect --plugin gdb-remote connect://localhost:%1")) {
@@ -1373,7 +1375,7 @@ CommandObject *CommandInterpreter::BuildAliasResult(
return alias_cmd_obj;
}
-Error CommandInterpreter::PreprocessCommand(std::string &command) {
+Status CommandInterpreter::PreprocessCommand(std::string &command) {
// The command preprocessor needs to do things to the command
// line before any parsing of arguments or anything else is done.
// The only current stuff that gets preprocessed is anything enclosed
@@ -1381,7 +1383,7 @@ Error CommandInterpreter::PreprocessCommand(std::string &command) {
// the result of the expression must be a scalar that can be substituted
// into the command. An example would be:
// (lldb) memory read `$rsp + 20`
- Error error; // Error for any expressions that might not evaluate
+ Status error; // Status for any expressions that might not evaluate
size_t start_backtick;
size_t pos = 0;
while ((start_backtick = command.find('`', pos)) != std::string::npos) {
@@ -1533,8 +1535,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
if (log)
log->Printf("Processing command: %s", command_line);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "Handling command: %s.",
- command_line);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "Handling command: %s.", command_line);
if (!no_context_switching)
UpdateExecutionContext(override_context);
@@ -1601,7 +1603,7 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
return true;
}
- Error error(PreprocessCommand(command_string));
+ Status error(PreprocessCommand(command_string));
if (error.Fail()) {
result.AppendError(error.AsCString());
@@ -2018,8 +2020,8 @@ void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
}
for (auto entry : llvm::enumerate(cmd_args.entries())) {
- if (!used[entry.Index] && !wants_raw_input)
- new_args.AppendArgument(entry.Value.ref);
+ if (!used[entry.index()] && !wants_raw_input)
+ new_args.AppendArgument(entry.value().ref);
}
cmd_args.Clear();
@@ -2355,8 +2357,8 @@ void CommandInterpreter::HandleCommandsFromFile(
StreamFileSP input_file_sp(new StreamFile());
std::string cmd_file_path = cmd_file.GetPath();
- Error error = input_file_sp->GetFile().Open(cmd_file_path.c_str(),
- File::eOpenOptionRead);
+ Status error = input_file_sp->GetFile().Open(cmd_file_path.c_str(),
+ File::eOpenOptionRead);
if (error.Success()) {
Debugger &debugger = GetDebugger();
@@ -2473,7 +2475,7 @@ void CommandInterpreter::HandleCommandsFromFile(
}
ScriptInterpreter *CommandInterpreter::GetScriptInterpreter(bool can_create) {
- std::lock_guard<std::mutex> locker(m_script_interpreter_mutex);
+ std::lock_guard<std::recursive_mutex> locker(m_script_interpreter_mutex);
if (!m_script_interpreter_sp) {
if (!can_create)
return nullptr;
@@ -2542,14 +2544,6 @@ void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
}
-LLVM_ATTRIBUTE_ALWAYS_INLINE
-static size_t nextWordLength(llvm::StringRef S) {
- size_t pos = S.find_first_of(' ');
- if (pos == llvm::StringRef::npos)
- return S.size();
- return pos;
-}
-
void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
llvm::StringRef separator,
llvm::StringRef help_text,
@@ -2568,6 +2562,11 @@ void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
uint32_t chars_left = max_columns;
+ auto nextWordLength = [](llvm::StringRef S) {
+ size_t pos = S.find_first_of(' ');
+ return pos == llvm::StringRef::npos ? S.size() : pos;
+ };
+
while (!text.empty()) {
if (text.front() == '\n' ||
(text.front() == ' ' && nextWordLength(text.ltrim(' ')) < chars_left)) {
@@ -2656,7 +2655,7 @@ size_t CommandInterpreter::GetProcessOutput() {
char stdio_buffer[1024];
size_t len;
size_t total_bytes = 0;
- Error error;
+ Status error;
TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
if (target_sp) {
ProcessSP process_sp(target_sp->GetProcessSP());
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp
index 944d408..f9a5b10 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp
@@ -24,9 +24,9 @@
// FIXME: Make a separate file for the completers.
#include "lldb/Core/FileSpecList.h"
#include "lldb/DataFormatters/FormatManager.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Target/Language.h"
@@ -99,7 +99,7 @@ bool CommandObject::ParseOptions(Args &args, CommandReturnObject &result) {
// See if the subclass has options?
Options *options = GetOptions();
if (options != nullptr) {
- Error error;
+ Status error;
auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
options->NotifyOptionParsingStarting(&exe_ctx);
@@ -977,10 +977,10 @@ bool CommandObjectParsed::Execute(const char *args_string,
}
if (!handled) {
for (auto entry : llvm::enumerate(cmd_args.entries())) {
- if (!entry.Value.ref.empty() && entry.Value.ref.front() == '`') {
+ if (!entry.value().ref.empty() && entry.value().ref.front() == '`') {
cmd_args.ReplaceArgumentAtIndex(
- entry.Index,
- m_interpreter.ProcessEmbeddedScriptCommands(entry.Value.c_str()));
+ entry.index(),
+ m_interpreter.ProcessEmbeddedScriptCommands(entry.value().c_str()));
}
}
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandReturnObject.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandReturnObject.cpp
index 72e66aa..75c0258 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/CommandReturnObject.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandReturnObject.cpp
@@ -13,8 +13,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Error.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -111,7 +111,7 @@ void CommandReturnObject::AppendError(llvm::StringRef in_string) {
GetErrorStream() << "error: " << in_string << "\n";
}
-void CommandReturnObject::SetError(const Error &error,
+void CommandReturnObject::SetError(const Status &error,
const char *fallback_error_cstr) {
const char *error_cstr = error.AsCString();
if (error_cstr == nullptr)
@@ -127,7 +127,7 @@ void CommandReturnObject::SetError(llvm::StringRef error_str) {
SetStatus(eReturnStatusFailed);
}
-// Similar to AppendError, but do not prepend 'Error: ' to message, and
+// Similar to AppendError, but do not prepend 'Status: ' to message, and
// don't append "\n" to the end of it.
void CommandReturnObject::AppendRawError(llvm::StringRef in_string) {
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupArchitecture.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupArchitecture.cpp
index 51245a8..d5354fe 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupArchitecture.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupArchitecture.cpp
@@ -13,7 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Utility/Utils.h"
+#include "lldb/Host/OptionParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -41,10 +41,11 @@ bool OptionGroupArchitecture::GetArchitecture(Platform *platform,
return arch.IsValid();
}
-Error OptionGroupArchitecture::SetOptionValue(
- uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error;
+Status
+OptionGroupArchitecture::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
const int short_option = g_option_table[option_idx].short_option;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupBoolean.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupBoolean.cpp
index 10b9746..5fd4ce7 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupBoolean.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupBoolean.cpp
@@ -13,6 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Host/OptionParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -39,10 +40,10 @@ OptionGroupBoolean::OptionGroupBoolean(uint32_t usage_mask, bool required,
OptionGroupBoolean::~OptionGroupBoolean() {}
-Error OptionGroupBoolean::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_value,
- ExecutionContext *execution_context) {
- Error error;
+Status OptionGroupBoolean::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_value,
+ ExecutionContext *execution_context) {
+ Status error;
if (m_option_definition.option_has_arg == OptionParser::eNoArgument) {
// Not argument, toggle the default value and mark the option as having been
// set
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFile.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFile.cpp
index 0c0b068..d45f00a 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFile.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFile.cpp
@@ -13,6 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Host/OptionParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -37,10 +38,10 @@ OptionGroupFile::OptionGroupFile(uint32_t usage_mask, bool required,
OptionGroupFile::~OptionGroupFile() {}
-Error OptionGroupFile::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error(m_file.SetValueFromString(option_arg));
+Status OptionGroupFile::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error(m_file.SetValueFromString(option_arg));
return error;
}
@@ -68,10 +69,11 @@ OptionGroupFileList::OptionGroupFileList(
OptionGroupFileList::~OptionGroupFileList() {}
-Error OptionGroupFileList::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_value,
- ExecutionContext *execution_context) {
- Error error(m_file_list.SetValueFromString(option_value));
+Status
+OptionGroupFileList::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_value,
+ ExecutionContext *execution_context) {
+ Status error(m_file_list.SetValueFromString(option_value));
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFormat.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFormat.cpp
index c97d16a..7c4239f 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFormat.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupFormat.cpp
@@ -14,10 +14,10 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ArchSpec.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
-#include "lldb/Utility/Utils.h"
using namespace lldb;
using namespace lldb_private;
@@ -58,10 +58,10 @@ llvm::ArrayRef<OptionDefinition> OptionGroupFormat::GetDefinitions() {
return result.take_front(2);
}
-Error OptionGroupFormat::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error;
+Status OptionGroupFormat::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
const int short_option = g_option_table[option_idx].short_option;
switch (short_option) {
@@ -235,32 +235,36 @@ bool OptionGroupFormat::ParserGDBFormatLetter(
m_prev_gdb_format = format_letter;
return true;
- // Size isn't used for printing instructions, so if a size is specified, and
- // the previous format was
- // 'i', then we should reset it to the default ('x'). Otherwise we'll
- // continue to print as instructions,
- // which isn't expected.
case 'b':
- byte_size = 1;
- LLVM_FALLTHROUGH;
case 'h':
- byte_size = 2;
- LLVM_FALLTHROUGH;
case 'w':
- byte_size = 4;
- LLVM_FALLTHROUGH;
case 'g':
- byte_size = 8;
-
- m_prev_gdb_size = format_letter;
- if (m_prev_gdb_format == 'i')
- m_prev_gdb_format = 'x';
- return true;
+ {
+ // Size isn't used for printing instructions, so if a size is specified, and
+ // the previous format was
+ // 'i', then we should reset it to the default ('x'). Otherwise we'll
+ // continue to print as instructions,
+ // which isn't expected.
+ if (format_letter == 'b')
+ byte_size = 1;
+ else if (format_letter == 'h')
+ byte_size = 2;
+ else if (format_letter == 'w')
+ byte_size = 4;
+ else if (format_letter == 'g')
+ byte_size = 8;
+ m_prev_gdb_size = format_letter;
+ if (m_prev_gdb_format == 'i')
+ m_prev_gdb_format = 'x';
+ return true;
+ }
break;
default:
break;
}
+
+
return false;
}
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupOutputFile.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupOutputFile.cpp
index b9538fb..fd40649 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupOutputFile.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupOutputFile.cpp
@@ -13,7 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Utility/Utils.h"
+#include "lldb/Host/OptionParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -38,10 +38,11 @@ llvm::ArrayRef<OptionDefinition> OptionGroupOutputFile::GetDefinitions() {
return llvm::makeArrayRef(g_option_table);
}
-Error OptionGroupOutputFile::SetOptionValue(
- uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error;
+Status
+OptionGroupOutputFile::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
const int short_option = g_option_table[option_idx].short_option;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupPlatform.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupPlatform.cpp
index 6231162..5747c6a 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupPlatform.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupPlatform.cpp
@@ -13,16 +13,16 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/Platform.h"
-#include "lldb/Utility/Utils.h"
using namespace lldb;
using namespace lldb_private;
PlatformSP OptionGroupPlatform::CreatePlatformWithOptions(
CommandInterpreter &interpreter, const ArchSpec &arch, bool make_selected,
- Error &error, ArchSpec &platform_arch) const {
+ Status &error, ArchSpec &platform_arch) const {
PlatformSP platform_sp;
if (!m_platform_name.empty()) {
@@ -92,10 +92,11 @@ llvm::ArrayRef<OptionDefinition> OptionGroupPlatform::GetDefinitions() {
return result.drop_front();
}
-Error OptionGroupPlatform::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error;
+Status
+OptionGroupPlatform::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
if (!m_include_platform_option)
++option_idx;
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupString.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupString.cpp
index 48a9ff1..1a16194 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupString.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupString.cpp
@@ -13,6 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Host/OptionParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -38,10 +39,10 @@ OptionGroupString::OptionGroupString(uint32_t usage_mask, bool required,
OptionGroupString::~OptionGroupString() {}
-Error OptionGroupString::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error(m_value.SetValueFromString(option_arg));
+Status OptionGroupString::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error(m_value.SetValueFromString(option_arg));
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUInt64.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUInt64.cpp
index a8501fa..ae4828c 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUInt64.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUInt64.cpp
@@ -13,6 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Host/OptionParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -38,10 +39,10 @@ OptionGroupUInt64::OptionGroupUInt64(uint32_t usage_mask, bool required,
OptionGroupUInt64::~OptionGroupUInt64() {}
-Error OptionGroupUInt64::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error(m_value.SetValueFromString(option_arg));
+Status OptionGroupUInt64::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error(m_value.SetValueFromString(option_arg));
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUUID.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUUID.cpp
index cd6c02a..bf02d1b 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUUID.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupUUID.cpp
@@ -13,7 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Utility/Utils.h"
+#include "lldb/Host/OptionParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -31,10 +31,10 @@ llvm::ArrayRef<OptionDefinition> OptionGroupUUID::GetDefinitions() {
return llvm::makeArrayRef(g_option_table);
}
-Error OptionGroupUUID::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error;
+Status OptionGroupUUID::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
const int short_option = g_option_table[option_idx].short_option;
switch (short_option) {
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
index 6d33132..ce27d94 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
@@ -14,10 +14,9 @@
// Other libraries and framework includes
// Project includes
#include "lldb/DataFormatters/ValueObjectPrinter.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/Target.h"
-#include "lldb/Utility/Utils.h"
#include "llvm/ADT/ArrayRef.h"
@@ -76,10 +75,10 @@ OptionGroupValueObjectDisplay::GetDefinitions() {
return llvm::makeArrayRef(g_option_table);
}
-Error OptionGroupValueObjectDisplay::SetOptionValue(
+Status OptionGroupValueObjectDisplay::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
- Error error;
+ Status error;
const int short_option = g_option_table[option_idx].short_option;
bool success = false;
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupVariable.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupVariable.cpp
index c257506..0793d37 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupVariable.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupVariable.cpp
@@ -13,11 +13,11 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Error.h"
#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/Target.h"
-#include "lldb/Utility/Utils.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -52,20 +52,20 @@ static OptionDefinition g_variable_options[] = {
"Specify a summary string to use to format the variable output."},
};
-static Error ValidateNamedSummary(const char *str, void *) {
+static Status ValidateNamedSummary(const char *str, void *) {
if (!str || !str[0])
- return Error("must specify a valid named summary");
+ return Status("must specify a valid named summary");
TypeSummaryImplSP summary_sp;
if (DataVisualization::NamedSummaryFormats::GetSummaryFormat(
ConstString(str), summary_sp) == false)
- return Error("must specify a valid named summary");
- return Error();
+ return Status("must specify a valid named summary");
+ return Status();
}
-static Error ValidateSummaryString(const char *str, void *) {
+static Status ValidateSummaryString(const char *str, void *) {
if (!str || !str[0])
- return Error("must specify a non-empty summary string");
- return Error();
+ return Status("must specify a non-empty summary string");
+ return Status();
}
OptionGroupVariable::OptionGroupVariable(bool show_frame_options)
@@ -74,10 +74,11 @@ OptionGroupVariable::OptionGroupVariable(bool show_frame_options)
OptionGroupVariable::~OptionGroupVariable() {}
-Error OptionGroupVariable::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error;
+Status
+OptionGroupVariable::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
if (!include_frame_options)
option_idx += 3;
const int short_option = g_variable_options[option_idx].short_option;
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupWatchpoint.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
index cda934b..dd4b8c8 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
@@ -13,8 +13,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/Args.h"
-#include "lldb/Utility/Utils.h"
#include "lldb/lldb-enumerations.h"
using namespace lldb;
@@ -56,10 +56,11 @@ OptionGroupWatchpoint::OptionGroupWatchpoint() : OptionGroup() {}
OptionGroupWatchpoint::~OptionGroupWatchpoint() {}
-Error OptionGroupWatchpoint::SetOptionValue(
- uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) {
- Error error;
+Status
+OptionGroupWatchpoint::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_arg,
+ ExecutionContext *execution_context) {
+ Status error;
const int short_option = g_option_table[option_idx].short_option;
switch (short_option) {
case 'w': {
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValue.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValue.cpp
index 58de32c..afcace2 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValue.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValue.cpp
@@ -13,8 +13,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/OptionValues.h"
+#include "lldb/Utility/StringList.h"
using namespace lldb;
using namespace lldb_private;
@@ -42,10 +42,10 @@ uint64_t OptionValue::GetUInt64Value(uint64_t fail_value, bool *success_ptr) {
return fail_value;
}
-Error OptionValue::SetSubValue(const ExecutionContext *exe_ctx,
- VarSetOperationType op, llvm::StringRef name,
- llvm::StringRef value) {
- Error error;
+Status OptionValue::SetSubValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op, llvm::StringRef name,
+ llvm::StringRef value) {
+ Status error;
error.SetErrorStringWithFormat("SetSubValue is not supported");
return error;
}
@@ -507,7 +507,7 @@ const char *OptionValue::GetBuiltinTypeAsCString(Type t) {
}
lldb::OptionValueSP OptionValue::CreateValueFromCStringForTypeMask(
- const char *value_cstr, uint32_t type_mask, Error &error) {
+ const char *value_cstr, uint32_t type_mask, Status &error) {
// If only 1 bit is set in the type mask for a dictionary or array
// then we know how to decode a value from a cstring
lldb::OptionValueSP value_sp;
@@ -582,9 +582,9 @@ size_t OptionValue::AutoComplete(CommandInterpreter &interpreter,
return matches.GetSize();
}
-Error OptionValue::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValue::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationReplace:
error.SetErrorStringWithFormat(
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArch.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArch.cpp
index 3e41300..1d920a1 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArch.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArch.cpp
@@ -38,9 +38,9 @@ void OptionValueArch::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
}
}
-Error OptionValueArch::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueArch::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArray.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArray.cpp
index 9dc4633..8b62070 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArray.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueArray.cpp
@@ -13,9 +13,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -70,18 +70,19 @@ void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
}
}
-Error OptionValueArray::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
+Status OptionValueArray::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
Args args(value.str());
- Error error = SetArgs(args, op);
+ Status error = SetArgs(args, op);
if (error.Success())
NotifyValueChanged();
return error;
}
lldb::OptionValueSP
-OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx, llvm::StringRef name,
- bool will_modify, Error &error) const {
+OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx,
+ llvm::StringRef name, bool will_modify,
+ Status &error) const {
if (name.empty() || name.front() != '[') {
error.SetErrorStringWithFormat(
"invalid value path '%s', %s values only support '[<index>]' subvalues "
@@ -149,8 +150,8 @@ size_t OptionValueArray::GetArgs(Args &args) const {
return args.GetArgumentCount();
}
-Error OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) {
- Error error;
+Status OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) {
+ Status error;
const size_t argc = args.GetArgumentCount();
switch (op) {
case eVarSetOperationInvalid:
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueBoolean.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueBoolean.cpp
index 85799fe..2cb84cd 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueBoolean.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueBoolean.cpp
@@ -13,10 +13,10 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
#include "llvm/ADT/STLExtras.h"
using namespace lldb;
@@ -35,9 +35,9 @@ void OptionValueBoolean::DumpValue(const ExecutionContext *exe_ctx,
}
}
-Error OptionValueBoolean::SetValueFromString(llvm::StringRef value_str,
- VarSetOperationType op) {
- Error error;
+Status OptionValueBoolean::SetValueFromString(llvm::StringRef value_str,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueChar.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueChar.cpp
index 6423185..27684a2 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueChar.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueChar.cpp
@@ -13,9 +13,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
#include "llvm/ADT/STLExtras.h"
using namespace lldb;
@@ -36,9 +36,9 @@ void OptionValueChar::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
}
}
-Error OptionValueChar::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueChar::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp
index dfba435..b245a09 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp
@@ -90,8 +90,9 @@ size_t OptionValueDictionary::GetArgs(Args &args) const {
return args.GetArgumentCount();
}
-Error OptionValueDictionary::SetArgs(const Args &args, VarSetOperationType op) {
- Error error;
+Status OptionValueDictionary::SetArgs(const Args &args,
+ VarSetOperationType op) {
+ Status error;
const size_t argc = args.GetArgumentCount();
switch (op) {
case eVarSetOperationClear:
@@ -197,10 +198,10 @@ Error OptionValueDictionary::SetArgs(const Args &args, VarSetOperationType op) {
return error;
}
-Error OptionValueDictionary::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
+Status OptionValueDictionary::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
Args args(value.str());
- Error error = SetArgs(args, op);
+ Status error = SetArgs(args, op);
if (error.Success())
NotifyValueChanged();
return error;
@@ -208,8 +209,8 @@ Error OptionValueDictionary::SetValueFromString(llvm::StringRef value,
lldb::OptionValueSP
OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,
- llvm::StringRef name, bool will_modify,
- Error &error) const {
+ llvm::StringRef name, bool will_modify,
+ Status &error) const {
lldb::OptionValueSP value_sp;
if (name.empty())
return nullptr;
@@ -258,10 +259,11 @@ OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,
return value_sp->GetSubValue(exe_ctx, sub_name, will_modify, error);
}
-Error OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,
- VarSetOperationType op,
- llvm::StringRef name, llvm::StringRef value) {
- Error error;
+Status OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ llvm::StringRef name,
+ llvm::StringRef value) {
+ Status error;
const bool will_modify = true;
lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error));
if (value_sp)
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp
index 679b5cc..9510f4a 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueEnumeration.cpp
@@ -13,7 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StringList.h"
+#include "lldb/Utility/StringList.h"
using namespace lldb;
using namespace lldb_private;
@@ -37,7 +37,7 @@ void OptionValueEnumeration::DumpValue(const ExecutionContext *exe_ctx,
const size_t count = m_enumerations.GetSize();
for (size_t i = 0; i < count; ++i) {
if (m_enumerations.GetValueAtIndexUnchecked(i).value == m_current_value) {
- strm.PutCString(m_enumerations.GetCStringAtIndex(i));
+ strm.PutCString(m_enumerations.GetCStringAtIndex(i).GetStringRef());
return;
}
}
@@ -45,9 +45,9 @@ void OptionValueEnumeration::DumpValue(const ExecutionContext *exe_ctx,
}
}
-Error OptionValueEnumeration::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueEnumeration::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
@@ -58,8 +58,7 @@ Error OptionValueEnumeration::SetValueFromString(llvm::StringRef value,
case eVarSetOperationAssign: {
ConstString const_enumerator_name(value.trim());
const EnumerationMapEntry *enumerator_entry =
- m_enumerations.FindFirstValueForName(
- const_enumerator_name.GetStringRef());
+ m_enumerations.FindFirstValueForName(const_enumerator_name);
if (enumerator_entry) {
m_current_value = enumerator_entry->value.value;
NotifyValueChanged();
@@ -69,10 +68,10 @@ Error OptionValueEnumeration::SetValueFromString(llvm::StringRef value,
const size_t count = m_enumerations.GetSize();
if (count) {
error_strm.Printf(", valid values are: %s",
- m_enumerations.GetCStringAtIndex(0).str().c_str());
+ m_enumerations.GetCStringAtIndex(0).GetCString());
for (size_t i = 1; i < count; ++i) {
error_strm.Printf(", %s",
- m_enumerations.GetCStringAtIndex(i).str().c_str());
+ m_enumerations.GetCStringAtIndex(i).GetCString());
}
}
error.SetErrorString(error_strm.GetString());
@@ -99,7 +98,7 @@ void OptionValueEnumeration::SetEnumerations(
ConstString const_enumerator_name(enumerators[i].string_value);
EnumeratorInfo enumerator_info = {enumerators[i].value,
enumerators[i].usage};
- m_enumerations.Append(const_enumerator_name.GetStringRef(),
+ m_enumerations.Append(const_enumerator_name,
enumerator_info);
}
m_enumerations.Sort();
@@ -119,14 +118,14 @@ size_t OptionValueEnumeration::AutoComplete(
const uint32_t num_enumerators = m_enumerations.GetSize();
if (!s.empty()) {
for (size_t i = 0; i < num_enumerators; ++i) {
- llvm::StringRef name = m_enumerations.GetCStringAtIndex(i);
+ llvm::StringRef name = m_enumerations.GetCStringAtIndex(i).GetStringRef();
if (name.startswith(s))
matches.AppendString(name);
}
} else {
// only suggest "true" or "false" by default
for (size_t i = 0; i < num_enumerators; ++i)
- matches.AppendString(m_enumerations.GetCStringAtIndex(i));
+ matches.AppendString(m_enumerations.GetCStringAtIndex(i).GetStringRef());
}
return matches.GetSize();
}
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpec.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpec.cpp
index a6eb537..b235d4a 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpec.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpec.cpp
@@ -15,6 +15,7 @@
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/DataBufferLLVM.h"
using namespace lldb;
using namespace lldb_private;
@@ -53,9 +54,9 @@ void OptionValueFileSpec::DumpValue(const ExecutionContext *exe_ctx,
}
}
-Error OptionValueFileSpec::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueFileSpec::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
@@ -118,10 +119,8 @@ OptionValueFileSpec::GetFileContents(bool null_terminate) {
const auto file_mod_time = FileSystem::GetModificationTime(m_current_value);
if (m_data_sp && m_data_mod_time == file_mod_time)
return m_data_sp;
- if (null_terminate)
- m_data_sp = m_current_value.ReadFileContentsAsCString();
- else
- m_data_sp = m_current_value.ReadFileContents();
+ m_data_sp = DataBufferLLVM::CreateFromPath(m_current_value.GetPath(),
+ null_terminate);
m_data_mod_time = file_mod_time;
}
return m_data_sp;
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpecLIst.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpecLIst.cpp
index e4bd4ba..7773bdc 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpecLIst.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFileSpecLIst.cpp
@@ -13,9 +13,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -38,9 +38,9 @@ void OptionValueFileSpecList::DumpValue(const ExecutionContext *exe_ctx,
}
}
-Error OptionValueFileSpecList::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueFileSpecList::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
Args args(value.str());
const size_t argc = args.GetArgumentCount();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormat.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormat.cpp
index 041d8a5..24dd8fd 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormat.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormat.cpp
@@ -13,9 +13,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -31,9 +31,9 @@ void OptionValueFormat::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
}
}
-Error OptionValueFormat::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueFormat::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormatEntity.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormatEntity.cpp
index 03f077c..e9431d4 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormatEntity.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueFormatEntity.cpp
@@ -14,9 +14,9 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
using namespace lldb;
using namespace lldb_private;
@@ -25,7 +25,7 @@ OptionValueFormatEntity::OptionValueFormatEntity(const char *default_format)
m_default_entry() {
if (default_format && default_format[0]) {
llvm::StringRef default_format_str(default_format);
- Error error = FormatEntity::Parse(default_format_str, m_default_entry);
+ Status error = FormatEntity::Parse(default_format_str, m_default_entry);
if (error.Success()) {
m_default_format = default_format;
m_current_format = default_format;
@@ -52,9 +52,9 @@ void OptionValueFormatEntity::DumpValue(const ExecutionContext *exe_ctx,
}
}
-Error OptionValueFormatEntity::SetValueFromString(llvm::StringRef value_str,
- VarSetOperationType op) {
- Error error;
+Status OptionValueFormatEntity::SetValueFromString(llvm::StringRef value_str,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueLanguage.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueLanguage.cpp
index b3da6d3..3290e88 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueLanguage.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueLanguage.cpp
@@ -13,10 +13,10 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Target/Language.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -32,9 +32,9 @@ void OptionValueLanguage::DumpValue(const ExecutionContext *exe_ctx,
}
}
-Error OptionValueLanguage::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueLanguage::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValuePathMappings.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValuePathMappings.cpp
index 5b9850d..5f80572 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValuePathMappings.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValuePathMappings.cpp
@@ -13,10 +13,10 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -40,9 +40,9 @@ void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
}
}
-Error OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
Args args(value.str());
const size_t argc = args.GetArgumentCount();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp
index 7e4df3a..ae76696 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -13,13 +13,14 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Flags.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StringList.h"
+#include "lldb/Utility/Flags.h"
+
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/OptionValues.h"
#include "lldb/Interpreter/Property.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
using namespace lldb;
using namespace lldb_private;
@@ -58,7 +59,7 @@ void OptionValueProperties::Initialize(const PropertyDefinition *defs) {
for (size_t i = 0; defs[i].name; ++i) {
Property property(defs[i]);
assert(property.IsValid());
- m_name_to_index.Append(property.GetName(), m_properties.size());
+ m_name_to_index.Append(ConstString(property.GetName()), m_properties.size());
property.GetValue()->SetParent(shared_from_this());
m_properties.push_back(property);
}
@@ -77,7 +78,7 @@ void OptionValueProperties::AppendProperty(const ConstString &name,
bool is_global,
const OptionValueSP &value_sp) {
Property property(name, desc, is_global, value_sp);
- m_name_to_index.Append(name.GetStringRef(), m_properties.size());
+ m_name_to_index.Append(name, m_properties.size());
m_properties.push_back(property);
value_sp->SetParent(shared_from_this());
m_name_to_index.Sort();
@@ -107,7 +108,7 @@ OptionValueProperties::GetValueForKey(const ExecutionContext *exe_ctx,
const ConstString &key,
bool will_modify) const {
lldb::OptionValueSP value_sp;
- size_t idx = m_name_to_index.Find(key.GetStringRef(), SIZE_MAX);
+ size_t idx = m_name_to_index.Find(key, SIZE_MAX);
if (idx < m_properties.size())
value_sp = GetPropertyAtIndex(exe_ctx, will_modify, idx)->GetValue();
return value_sp;
@@ -115,8 +116,8 @@ OptionValueProperties::GetValueForKey(const ExecutionContext *exe_ctx,
lldb::OptionValueSP
OptionValueProperties::GetSubValue(const ExecutionContext *exe_ctx,
- llvm::StringRef name, bool will_modify,
- Error &error) const {
+ llvm::StringRef name, bool will_modify,
+ Status &error) const {
lldb::OptionValueSP value_sp;
if (name.empty())
return OptionValueSP();
@@ -200,10 +201,11 @@ OptionValueProperties::GetSubValue(const ExecutionContext *exe_ctx,
return value_sp;
}
-Error OptionValueProperties::SetSubValue(const ExecutionContext *exe_ctx,
- VarSetOperationType op,
- llvm::StringRef name, llvm::StringRef value) {
- Error error;
+Status OptionValueProperties::SetSubValue(const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ llvm::StringRef name,
+ llvm::StringRef value) {
+ Status error;
const bool will_modify = true;
lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error));
if (value_sp)
@@ -217,7 +219,7 @@ Error OptionValueProperties::SetSubValue(const ExecutionContext *exe_ctx,
uint32_t
OptionValueProperties::GetPropertyIndex(const ConstString &name) const {
- return m_name_to_index.Find(name.GetStringRef(), SIZE_MAX);
+ return m_name_to_index.Find(name, SIZE_MAX);
}
const Property *
@@ -226,7 +228,7 @@ OptionValueProperties::GetProperty(const ExecutionContext *exe_ctx,
const ConstString &name) const {
return GetPropertyAtIndex(
exe_ctx, will_modify,
- m_name_to_index.Find(name.GetStringRef(), SIZE_MAX));
+ m_name_to_index.Find(name, SIZE_MAX));
}
const Property *OptionValueProperties::GetPropertyAtIndex(
@@ -522,9 +524,9 @@ bool OptionValueProperties::Clear() {
return true;
}
-Error OptionValueProperties::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueProperties::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
// Args args(value_cstr);
// const size_t argc = args.GetArgumentCount();
@@ -563,11 +565,11 @@ void OptionValueProperties::DumpValue(const ExecutionContext *exe_ctx,
}
}
-Error OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx,
- Stream &strm,
- llvm::StringRef property_path,
- uint32_t dump_mask) {
- Error error;
+Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx,
+ Stream &strm,
+ llvm::StringRef property_path,
+ uint32_t dump_mask) {
+ Status error;
const bool will_modify = false;
lldb::OptionValueSP value_sp(
GetSubValue(exe_ctx, property_path, will_modify, error));
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueRegex.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueRegex.cpp
index 86ef102..aee8f97 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueRegex.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueRegex.cpp
@@ -13,7 +13,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -32,9 +32,9 @@ void OptionValueRegex::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
}
}
-Error OptionValueRegex::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueRegex::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationInvalid:
case eVarSetOperationInsertBefore:
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueSInt64.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueSInt64.cpp
index 3f3844a..9dbcd58 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueSInt64.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueSInt64.cpp
@@ -13,8 +13,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -34,9 +34,9 @@ void OptionValueSInt64::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
}
}
-Error OptionValueSInt64::SetValueFromString(llvm::StringRef value_ref,
- VarSetOperationType op) {
- Error error;
+Status OptionValueSInt64::SetValueFromString(llvm::StringRef value_ref,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueString.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueString.cpp
index e61ead0..1d7332d 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueString.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueString.cpp
@@ -14,8 +14,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -46,9 +47,9 @@ void OptionValueString::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
}
}
-Error OptionValueString::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueString::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
std::string value_str = value.str();
value = value.trim();
@@ -126,27 +127,27 @@ lldb::OptionValueSP OptionValueString::DeepCopy() const {
return OptionValueSP(new OptionValueString(*this));
}
-Error OptionValueString::SetCurrentValue(llvm::StringRef value) {
+Status OptionValueString::SetCurrentValue(llvm::StringRef value) {
if (m_validator) {
- Error error(m_validator(value.str().c_str(), m_validator_baton));
+ Status error(m_validator(value.str().c_str(), m_validator_baton));
if (error.Fail())
return error;
}
m_current_value.assign(value);
- return Error();
+ return Status();
}
-Error OptionValueString::AppendToCurrentValue(const char *value) {
+Status OptionValueString::AppendToCurrentValue(const char *value) {
if (value && value[0]) {
if (m_validator) {
std::string new_value(m_current_value);
new_value.append(value);
- Error error(m_validator(value, m_validator_baton));
+ Status error(m_validator(value, m_validator_baton));
if (error.Fail())
return error;
m_current_value.assign(new_value);
} else
m_current_value.append(value);
}
- return Error();
+ return Status();
}
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUInt64.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUInt64.cpp
index 8986080..c8db1bd 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUInt64.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUInt64.cpp
@@ -14,14 +14,14 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
lldb::OptionValueSP OptionValueUInt64::Create(llvm::StringRef value_str,
- Error &error) {
+ Status &error) {
lldb::OptionValueSP value_sp(new OptionValueUInt64());
error = value_sp->SetValueFromString(value_str);
if (error.Fail())
@@ -40,9 +40,9 @@ void OptionValueUInt64::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
}
}
-Error OptionValueUInt64::SetValueFromString(llvm::StringRef value_ref,
- VarSetOperationType op) {
- Error error;
+Status OptionValueUInt64::SetValueFromString(llvm::StringRef value_ref,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUUID.cpp b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUUID.cpp
index 3519334..bec04cb 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUUID.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/OptionValueUUID.cpp
@@ -14,9 +14,9 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
using namespace lldb;
using namespace lldb_private;
@@ -32,9 +32,9 @@ void OptionValueUUID::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
}
}
-Error OptionValueUUID::SetValueFromString(llvm::StringRef value,
- VarSetOperationType op) {
- Error error;
+Status OptionValueUUID::SetValueFromString(llvm::StringRef value,
+ VarSetOperationType op) {
+ Status error;
switch (op) {
case eVarSetOperationClear:
Clear();
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp b/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp
index d26e53f..f8b1a8d 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp
@@ -18,12 +18,13 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StreamString.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -41,8 +42,8 @@ void Options::NotifyOptionParsingStarting(ExecutionContext *execution_context) {
OptionParsingStarting(execution_context);
}
-Error Options::NotifyOptionParsingFinished(
- ExecutionContext *execution_context) {
+Status
+Options::NotifyOptionParsingFinished(ExecutionContext *execution_context) {
return OptionParsingFinished(execution_context);
}
@@ -904,13 +905,13 @@ void OptionGroupOptions::Finalize() {
m_did_finalize = true;
}
-Error OptionGroupOptions::SetOptionValue(uint32_t option_idx,
- llvm::StringRef option_value,
- ExecutionContext *execution_context) {
+Status OptionGroupOptions::SetOptionValue(uint32_t option_idx,
+ llvm::StringRef option_value,
+ ExecutionContext *execution_context) {
// After calling OptionGroupOptions::Append(...), you must finalize the groups
// by calling OptionGroupOptions::Finlize()
assert(m_did_finalize);
- Error error;
+ Status error;
if (option_idx < m_option_infos.size()) {
error = m_option_infos[option_idx].option_group->SetOptionValue(
m_option_infos[option_idx].option_index, option_value,
@@ -934,10 +935,10 @@ void OptionGroupOptions::OptionParsingStarting(
}
}
}
-Error OptionGroupOptions::OptionParsingFinished(
- ExecutionContext *execution_context) {
+Status
+OptionGroupOptions::OptionParsingFinished(ExecutionContext *execution_context) {
std::set<OptionGroup *> group_set;
- Error error;
+ Status error;
OptionInfos::iterator pos, end = m_option_infos.end();
for (pos = m_option_infos.begin(); pos != end; ++pos) {
OptionGroup *group = pos->option_group;
diff --git a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreter.cpp b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreter.cpp
index d87d24e..57f7eea 100644
--- a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -13,11 +13,11 @@
#include <stdlib.h>
#include <string>
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StringList.h"
+#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
using namespace lldb;
using namespace lldb_private;
@@ -75,10 +75,10 @@ ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
return eScriptLanguageUnknown;
}
-Error ScriptInterpreter::SetBreakpointCommandCallback(
+Status ScriptInterpreter::SetBreakpointCommandCallback(
std::vector<BreakpointOptions *> &bp_options_vec,
const char *callback_text) {
- Error return_error;
+ Status return_error;
for (BreakpointOptions *bp_options : bp_options_vec) {
return_error = SetBreakpointCommandCallback(bp_options, callback_text);
if (return_error.Success())
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
index 969c7d3..fd5ee6ed 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
@@ -18,8 +18,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -31,6 +29,8 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
#include "Plugins/Process/Utility/ARMDefines.h"
#include "Utility/ARM_DWARF_Registers.h"
@@ -1326,7 +1326,7 @@ size_t ABIMacOSX_arm::GetRedZoneSize() const { return 0; }
//------------------------------------------------------------------
ABISP
-ABIMacOSX_arm::CreateInstance(const ArchSpec &arch) {
+ABIMacOSX_arm::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();
@@ -1335,7 +1335,7 @@ ABIMacOSX_arm::CreateInstance(const ArchSpec &arch) {
if ((arch_type == llvm::Triple::arm) ||
(arch_type == llvm::Triple::thumb)) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABIMacOSX_arm);
+ g_abi_sp.reset(new ABIMacOSX_arm(process_sp));
return g_abi_sp;
}
}
@@ -1533,7 +1533,7 @@ bool ABIMacOSX_arm::GetArgumentValues(Thread &thread, ValueList &values) const {
// Arguments 5 on up are on the stack
const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(
sp, arg_byte_size, is_signed, value->GetScalar(), error))
return false;
@@ -1546,16 +1546,14 @@ bool ABIMacOSX_arm::GetArgumentValues(Thread &thread, ValueList &values) const {
return true;
}
-bool ABIMacOSX_arm::IsArmv7kProcess(Thread *thread) const {
+bool ABIMacOSX_arm::IsArmv7kProcess() const {
bool is_armv7k = false;
- if (thread) {
- ProcessSP process_sp(thread->GetProcess());
- if (process_sp) {
- const ArchSpec &arch(process_sp->GetTarget().GetArchitecture());
- const ArchSpec::Core system_core = arch.GetCore();
- if (system_core == ArchSpec::eCore_arm_armv7k) {
- is_armv7k = true;
- }
+ ProcessSP process_sp(GetProcessSP());
+ if (process_sp) {
+ const ArchSpec &arch(process_sp->GetTarget().GetArchitecture());
+ const ArchSpec::Core system_core = arch.GetCore();
+ if (system_core == ArchSpec::eCore_arm_armv7k) {
+ is_armv7k = true;
}
}
return is_armv7k;
@@ -1588,7 +1586,7 @@ ValueObjectSP ABIMacOSX_arm::GetReturnValueObjectImpl(
default:
return return_valobj_sp;
case 128:
- if (IsArmv7kProcess(&thread)) {
+ if (IsArmv7kProcess()) {
// "A composite type not larger than 16 bytes is returned in r0-r3. The
// format is
// as if the result had been stored in memory at a word-aligned address
@@ -1619,7 +1617,7 @@ ValueObjectSP ABIMacOSX_arm::GetReturnValueObjectImpl(
reg_ctx->ReadRegister(r1_reg_info, r1_reg_value) &&
reg_ctx->ReadRegister(r2_reg_info, r2_reg_value) &&
reg_ctx->ReadRegister(r3_reg_info, r3_reg_value)) {
- Error error;
+ Status error;
if (r0_reg_value.GetAsMemoryData(r0_reg_info,
heap_data_ap->GetBytes() + 0,
4, byte_order, error) &&
@@ -1702,9 +1700,9 @@ ValueObjectSP ABIMacOSX_arm::GetReturnValueObjectImpl(
return return_valobj_sp;
}
-Error ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -1728,7 +1726,7 @@ Error ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
compiler_type.IsPointerType()) {
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -1755,8 +1753,7 @@ Error ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
set_it_simple = true;
}
}
- } else if (num_bytes <= 16 &&
- IsArmv7kProcess(frame_sp->GetThread().get())) {
+ } else if (num_bytes <= 16 && IsArmv7kProcess()) {
// "A composite type not larger than 16 bytes is returned in r0-r3. The
// format is
// as if the result had been stored in memory at a word-aligned address
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
index 39f57a0..d3c20e1 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
@@ -30,7 +30,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -66,7 +66,7 @@ public:
const lldb_private::RegisterInfo *
GetRegisterInfoArray(uint32_t &count) override;
- bool IsArmv7kProcess(lldb_private::Thread *thread) const;
+ bool IsArmv7kProcess() const;
//------------------------------------------------------------------
// Static Functions
@@ -76,7 +76,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -94,7 +94,7 @@ protected:
lldb_private::CompilerType &ast_type) const override;
private:
- ABIMacOSX_arm() : lldb_private::ABI() {
+ ABIMacOSX_arm(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
index ee27a7e..e301b21 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp
@@ -17,21 +17,20 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Value.h"
-#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "Utility/ARM64_DWARF_Registers.h"
@@ -1667,7 +1666,7 @@ size_t ABIMacOSX_arm64::GetRedZoneSize() const { return 128; }
//------------------------------------------------------------------
ABISP
-ABIMacOSX_arm64::CreateInstance(const ArchSpec &arch) {
+ABIMacOSX_arm64::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();
@@ -1675,7 +1674,7 @@ ABIMacOSX_arm64::CreateInstance(const ArchSpec &arch) {
if (vendor_type == llvm::Triple::Apple) {
if (arch_type == llvm::Triple::aarch64) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABIMacOSX_arm64);
+ g_abi_sp.reset(new ABIMacOSX_arm64(process_sp));
return g_abi_sp;
}
}
@@ -1841,7 +1840,7 @@ bool ABIMacOSX_arm64::GetArgumentValues(Thread &thread,
// Arguments 5 on up are on the stack
const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(
sp, arg_byte_size, is_signed, value->GetScalar(), error))
return false;
@@ -1860,9 +1859,10 @@ bool ABIMacOSX_arm64::GetArgumentValues(Thread &thread,
return true;
}
-Error ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status
+ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -1880,7 +1880,7 @@ Error ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
if (reg_ctx) {
DataExtractor data;
- Error data_error;
+ Status data_error;
const uint64_t byte_size = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -2124,7 +2124,7 @@ static bool LoadValueFromConsecutiveGPRRegisters(
std::unique_ptr<DataBufferHeap> heap_data_ap(
new DataBufferHeap(byte_size, 0));
const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
- Error error;
+ Status error;
CompilerType base_type;
const uint32_t homogeneous_count =
@@ -2305,7 +2305,7 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl(
RegisterValue x1_reg_value;
if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) &&
reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) {
- Error error;
+ Status error;
if (x0_reg_value.GetAsMemoryData(
x0_reg_info, heap_data_ap->GetBytes() + 0, 8,
byte_order, error) &&
@@ -2402,7 +2402,7 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl(
const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
RegisterValue reg_value;
if (reg_ctx->ReadRegister(v0_info, reg_value)) {
- Error error;
+ Status error;
if (reg_value.GetAsMemoryData(v0_info, heap_data_ap->GetBytes(),
heap_data_ap->GetByteSize(),
byte_order, error)) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h
index e097811..2dd7337 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h
@@ -14,8 +14,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Target/ABI.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
class ABIMacOSX_arm64 : public lldb_private::ABI {
@@ -78,7 +78,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
//------------------------------------------------------------------
// PluginInterface protocol
@@ -92,7 +92,7 @@ public:
uint32_t GetPluginVersion() override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -102,7 +102,7 @@ protected:
lldb_private::CompilerType &ast_type) const override;
private:
- ABIMacOSX_arm64() : lldb_private::ABI() {
+ ABIMacOSX_arm64(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
index 6eead6f..716a73b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
@@ -18,8 +18,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -30,6 +28,8 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -713,13 +713,13 @@ size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; }
//------------------------------------------------------------------
ABISP
-ABIMacOSX_i386::CreateInstance(const ArchSpec &arch) {
+ABIMacOSX_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
if ((arch.GetTriple().getArch() == llvm::Triple::x86) &&
(arch.GetTriple().isMacOSX() || arch.GetTriple().isiOS() ||
arch.GetTriple().isWatchOS())) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABIMacOSX_i386);
+ g_abi_sp.reset(new ABIMacOSX_i386(process_sp));
return g_abi_sp;
}
return ABISP();
@@ -746,7 +746,7 @@ bool ABIMacOSX_i386::PrepareTrivialCall(Thread &thread, addr_t sp,
// Make room for the argument(s) on the stack
- Error error;
+ Status error;
RegisterValue reg_value;
// Write any arguments onto the stack
@@ -793,7 +793,7 @@ static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
addr_t &current_stack_argument) {
uint32_t byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,
is_signed, scalar, error)) {
current_stack_argument += byte_size;
@@ -849,9 +849,9 @@ bool ABIMacOSX_i386::GetArgumentValues(Thread &thread,
return true;
}
-Error ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -875,7 +875,7 @@ Error ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
compiler_type.IsPointerType()) {
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
index 4a2555a..e026e32 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
@@ -31,7 +31,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -81,7 +81,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
//------------------------------------------------------------------
// PluginInterface protocol
@@ -101,7 +101,7 @@ protected:
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
- ABIMacOSX_i386() : lldb_private::ABI() {
+ ABIMacOSX_i386(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp
index ebd0d17..882d5cd 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp
@@ -18,8 +18,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -31,6 +29,8 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
#include "Plugins/Process/Utility/ARMDefines.h"
#include "Utility/ARM_DWARF_Registers.h"
@@ -1327,7 +1327,7 @@ size_t ABISysV_arm::GetRedZoneSize() const { return 0; }
//------------------------------------------------------------------
ABISP
-ABISysV_arm::CreateInstance(const ArchSpec &arch) {
+ABISysV_arm::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();
@@ -1336,7 +1336,7 @@ ABISysV_arm::CreateInstance(const ArchSpec &arch) {
if ((arch_type == llvm::Triple::arm) ||
(arch_type == llvm::Triple::thumb)) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_arm);
+ g_abi_sp.reset(new ABISysV_arm(process_sp));
return g_abi_sp;
}
}
@@ -1518,7 +1518,7 @@ bool ABISysV_arm::GetArgumentValues(Thread &thread, ValueList &values) const {
// Arguments 5 on up are on the stack
const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(
sp, arg_byte_size, is_signed, value->GetScalar(), error))
return false;
@@ -1534,7 +1534,7 @@ bool ABISysV_arm::GetArgumentValues(Thread &thread, ValueList &values) const {
static bool GetReturnValuePassedInMemory(Thread &thread,
RegisterContext *reg_ctx,
size_t byte_size, Value &value) {
- Error error;
+ Status error;
DataBufferHeap buffer(byte_size, 0);
const RegisterInfo *r0_reg_info =
@@ -1815,7 +1815,7 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl(
// Make sure we have enough room in "data_sp"
if ((data_offset + vfp_byte_size) <= data_sp->GetByteSize()) {
- Error error;
+ Status error;
const size_t bytes_copied = reg_value.GetAsMemoryData(
reg_info, data_sp->GetBytes() + data_offset, vfp_byte_size,
byte_order, error);
@@ -1846,9 +1846,9 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl(
return return_valobj_sp;
}
-Error ABISysV_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABISysV_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -1872,7 +1872,7 @@ Error ABISysV_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
compiler_type.IsPointerType()) {
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.h
index d85b3df..f046968 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm/ABISysV_arm.h
@@ -30,7 +30,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -76,7 +76,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -94,7 +94,7 @@ protected:
lldb_private::CompilerType &ast_type) const override;
private:
- ABISysV_arm() : lldb_private::ABI() {
+ ABISysV_arm(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
index 5e21792..f91ed85 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
@@ -18,9 +18,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -32,6 +29,9 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "Utility/ARM64_DWARF_Registers.h"
@@ -1670,7 +1670,7 @@ size_t ABISysV_arm64::GetRedZoneSize() const { return 128; }
//------------------------------------------------------------------
ABISP
-ABISysV_arm64::CreateInstance(const ArchSpec &arch) {
+ABISysV_arm64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();
@@ -1678,7 +1678,7 @@ ABISysV_arm64::CreateInstance(const ArchSpec &arch) {
if (vendor_type != llvm::Triple::Apple) {
if (arch_type == llvm::Triple::aarch64) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_arm64);
+ g_abi_sp.reset(new ABISysV_arm64(process_sp));
return g_abi_sp;
}
}
@@ -1697,7 +1697,7 @@ bool ABISysV_arm64::PrepareTrivialCall(Thread &thread, addr_t sp,
if (log) {
StreamString s;
- s.Printf("ABISysV_x86_64::PrepareTrivialCall (tid = 0x%" PRIx64
+ s.Printf("ABISysV_arm64::PrepareTrivialCall (tid = 0x%" PRIx64
", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64
", return_addr = 0x%" PRIx64,
thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,
@@ -1813,7 +1813,7 @@ bool ABISysV_arm64::GetArgumentValues(Thread &thread, ValueList &values) const {
// Arguments 5 on up are on the stack
const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(
sp, arg_byte_size, is_signed, value->GetScalar(), error))
return false;
@@ -1832,9 +1832,9 @@ bool ABISysV_arm64::GetArgumentValues(Thread &thread, ValueList &values) const {
return true;
}
-Error ABISysV_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABISysV_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -1852,7 +1852,7 @@ Error ABISysV_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
if (reg_ctx) {
DataExtractor data;
- Error data_error;
+ Status data_error;
const uint64_t byte_size = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -1951,22 +1951,20 @@ bool ABISysV_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
uint32_t lr_reg_num = arm64_dwarf::lr;
uint32_t sp_reg_num = arm64_dwarf::sp;
- uint32_t pc_reg_num = arm64_dwarf::pc;
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our previous Call Frame Address is the stack pointer
row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0);
- // Our previous PC is in the LR
- row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
-
unwind_plan.AppendRow(row);
+ unwind_plan.SetReturnAddressRegister(lr_reg_num);
// All other registers are the same.
unwind_plan.SetSourceName("arm64 at-func-entry default");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
return true;
}
@@ -2101,7 +2099,7 @@ static bool LoadValueFromConsecutiveGPRRegisters(
std::unique_ptr<DataBufferHeap> heap_data_ap(
new DataBufferHeap(byte_size, 0));
const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
- Error error;
+ Status error;
CompilerType base_type;
const uint32_t homogeneous_count =
@@ -2277,7 +2275,7 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl(
RegisterValue x1_reg_value;
if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) &&
reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) {
- Error error;
+ Status error;
if (x0_reg_value.GetAsMemoryData(
x0_reg_info, heap_data_ap->GetBytes() + 0, 8,
byte_order, error) &&
@@ -2362,32 +2360,30 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl(
if (success)
return_valobj_sp = ValueObjectConstResult::Create(
thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
- } else if (type_flags & eTypeIsVector) {
+ } else if (type_flags & eTypeIsVector && byte_size <= 16) {
if (byte_size > 0) {
const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);
if (v0_info) {
- if (byte_size <= v0_info->byte_size) {
- std::unique_ptr<DataBufferHeap> heap_data_ap(
- new DataBufferHeap(byte_size, 0));
- const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
- RegisterValue reg_value;
- if (reg_ctx->ReadRegister(v0_info, reg_value)) {
- Error error;
- if (reg_value.GetAsMemoryData(v0_info, heap_data_ap->GetBytes(),
- heap_data_ap->GetByteSize(),
- byte_order, error)) {
- DataExtractor data(DataBufferSP(heap_data_ap.release()),
- byte_order,
- exe_ctx.GetProcessRef().GetAddressByteSize());
- return_valobj_sp = ValueObjectConstResult::Create(
- &thread, return_compiler_type, ConstString(""), data);
- }
+ std::unique_ptr<DataBufferHeap> heap_data_ap(
+ new DataBufferHeap(byte_size, 0));
+ const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
+ RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(v0_info, reg_value)) {
+ Status error;
+ if (reg_value.GetAsMemoryData(v0_info, heap_data_ap->GetBytes(),
+ heap_data_ap->GetByteSize(), byte_order,
+ error)) {
+ DataExtractor data(DataBufferSP(heap_data_ap.release()), byte_order,
+ exe_ctx.GetProcessRef().GetAddressByteSize());
+ return_valobj_sp = ValueObjectConstResult::Create(
+ &thread, return_compiler_type, ConstString(""), data);
}
}
}
}
- } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) {
+ } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass ||
+ (type_flags & eTypeIsVector && byte_size > 16)) {
DataExtractor data;
uint32_t NGRN = 0; // Search ABI docs for NGRN
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
index 68c300c..8d23c24 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
@@ -31,7 +31,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -83,7 +83,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -101,7 +101,7 @@ protected:
lldb_private::CompilerType &ast_type) const override;
private:
- ABISysV_arm64() : lldb_private::ABI() {
+ ABISysV_arm64(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
index 649f19b..74274f0 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp
@@ -16,10 +16,6 @@
#include "llvm/IR/DerivedTypes.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -33,6 +29,10 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -1019,11 +1019,11 @@ size_t ABISysV_hexagon::GetRedZoneSize() const { return 0; }
//------------------------------------------------------------------
ABISP
-ABISysV_hexagon::CreateInstance(const ArchSpec &arch) {
+ABISysV_hexagon::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
if (arch.GetTriple().getArch() == llvm::Triple::hexagon) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_hexagon);
+ g_abi_sp.reset(new ABISysV_hexagon(process_sp));
return g_abi_sp;
}
return ABISP();
@@ -1073,7 +1073,7 @@ bool ABISysV_hexagon::PrepareTrivialCall(
llvm::Type &prototype, llvm::ArrayRef<ABI::CallArgument> args) const {
// default number of register passed arguments for varg functions
const int nVArgRegParams = 1;
- Error error;
+ Status error;
// grab the process so we have access to the memory for spilling
lldb::ProcessSP proc = thread.GetProcess();
@@ -1195,9 +1195,10 @@ bool ABISysV_hexagon::GetArgumentValues(Thread &thread,
return false;
}
-Error ABISysV_hexagon::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status
+ABISysV_hexagon::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h
index aed3dd7..5a68093 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h
@@ -39,7 +39,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -84,7 +84,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -106,7 +106,7 @@ protected:
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
- ABISysV_hexagon() : lldb_private::ABI() {
+ ABISysV_hexagon(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp
index 701db18..6ae3f54 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp
@@ -16,10 +16,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -33,6 +29,10 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -203,12 +203,12 @@ ABISysV_i386::GetRegisterInfoArray(uint32_t &count) {
//------------------------------------------------------------------
ABISP
-ABISysV_i386::CreateInstance(const ArchSpec &arch) {
+ABISysV_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
if ((arch.GetTriple().getArch() == llvm::Triple::x86) &&
- arch.GetTriple().isOSLinux()) {
+ (arch.GetTriple().isOSLinux() || arch.GetTriple().isOSFreeBSD())) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_i386);
+ g_abi_sp.reset(new ABISysV_i386(process_sp));
return g_abi_sp;
}
return ABISP();
@@ -237,7 +237,7 @@ bool ABISysV_i386::PrepareTrivialCall(Thread &thread, addr_t sp,
if (!reg_info_32)
return false; // TODO this should actually never happen
- Error error;
+ Status error;
RegisterValue reg_value;
// Make room for the argument(s) on the stack
@@ -280,7 +280,7 @@ static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
bool is_signed, Process *process,
addr_t &current_stack_argument) {
uint32_t byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (!process)
return false;
@@ -333,9 +333,9 @@ bool ABISysV_i386::GetArgumentValues(Thread &thread, ValueList &values) const {
return true;
}
-Error ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -351,7 +351,7 @@ Error ABISysV_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
Thread *thread = frame_sp->GetThread().get();
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
bool register_write_successful = true;
@@ -661,7 +661,7 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple(
const ByteOrder byte_order = process_sp->GetByteOrder();
RegisterValue reg_value;
if (reg_ctx->ReadRegister(vec_reg, reg_value)) {
- Error error;
+ Status error;
if (reg_value.GetAsMemoryData(vec_reg, heap_data_ap->GetBytes(),
heap_data_ap->GetByteSize(),
byte_order, error)) {
@@ -688,7 +688,7 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple(
if (reg_ctx->ReadRegister(vec_reg, reg_value) &&
reg_ctx->ReadRegister(vec_reg2, reg_value2)) {
- Error error;
+ Status error;
if (reg_value.GetAsMemoryData(vec_reg, heap_data_ap->GetBytes(),
vec_reg->byte_size, byte_order,
error) &&
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.h
index 8d1d76b..4dce54c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-i386/ABISysV_i386.h
@@ -33,7 +33,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -89,7 +89,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
//------------------------------------------------------------------
// PluginInterface protocol
@@ -109,7 +109,7 @@ protected:
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
- ABISysV_i386() : lldb_private::ABI() {
+ ABISysV_i386(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp
index b97fffe..95e2a7b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp
@@ -16,10 +16,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -33,6 +29,10 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -559,13 +559,13 @@ size_t ABISysV_mips::GetRedZoneSize() const { return 0; }
//------------------------------------------------------------------
ABISP
-ABISysV_mips::CreateInstance(const ArchSpec &arch) {
+ABISysV_mips::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
if ((arch_type == llvm::Triple::mips) ||
(arch_type == llvm::Triple::mipsel)) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_mips);
+ g_abi_sp.reset(new ABISysV_mips(process_sp));
return g_abi_sp;
}
return ABISP();
@@ -654,7 +654,7 @@ bool ABISysV_mips::PrepareTrivialCall(Thread &thread, addr_t sp,
}
}
- Error error;
+ Status error;
const RegisterInfo *pc_reg_info =
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
const RegisterInfo *sp_reg_info =
@@ -710,9 +710,9 @@ bool ABISysV_mips::GetArgumentValues(Thread &thread, ValueList &values) const {
return false;
}
-Error ABISysV_mips::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABISysV_mips::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -736,7 +736,7 @@ Error ABISysV_mips::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
compiler_type.IsPointerType()) {
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.h
index 7ac5146..0de8e77 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips/ABISysV_mips.h
@@ -31,7 +31,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -74,7 +74,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -96,7 +96,7 @@ protected:
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
- ABISysV_mips() : lldb_private::ABI() {
+ ABISysV_mips(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp
index bb83dec..749e170 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp
@@ -16,10 +16,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -33,6 +29,10 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -559,13 +559,13 @@ size_t ABISysV_mips64::GetRedZoneSize() const { return 0; }
//------------------------------------------------------------------
ABISP
-ABISysV_mips64::CreateInstance(const ArchSpec &arch) {
+ABISysV_mips64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
if ((arch_type == llvm::Triple::mips64) ||
(arch_type == llvm::Triple::mips64el)) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_mips64);
+ g_abi_sp.reset(new ABISysV_mips64(process_sp));
return g_abi_sp;
}
return ABISP();
@@ -617,7 +617,7 @@ bool ABISysV_mips64::PrepareTrivialCall(Thread &thread, addr_t sp,
sp &= ~(0xfull); // 16-byte alignment
- Error error;
+ Status error;
const RegisterInfo *pc_reg_info =
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
const RegisterInfo *sp_reg_info =
@@ -674,9 +674,9 @@ bool ABISysV_mips64::GetArgumentValues(Thread &thread,
return false;
}
-Error ABISysV_mips64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABISysV_mips64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -696,7 +696,7 @@ Error ABISysV_mips64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
error.SetErrorString("no registers are available");
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -754,7 +754,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl(
Thread &thread, CompilerType &return_compiler_type) const {
ValueObjectSP return_valobj_sp;
Value value;
- Error error;
+ Status error;
ExecutionContext exe_ctx(thread.shared_from_this());
if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h
index 672a438..6258c08 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h
@@ -31,7 +31,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -87,7 +87,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -109,7 +109,7 @@ protected:
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
- ABISysV_mips64() : lldb_private::ABI() {
+ ABISysV_mips64(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp
index 3e563c2..06a8ce9 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp
@@ -16,10 +16,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -33,6 +29,10 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -223,11 +223,11 @@ size_t ABISysV_ppc::GetRedZoneSize() const { return 224; }
//------------------------------------------------------------------
ABISP
-ABISysV_ppc::CreateInstance(const ArchSpec &arch) {
+ABISysV_ppc::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
if (arch.GetTriple().getArch() == llvm::Triple::ppc) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_ppc);
+ g_abi_sp.reset(new ABISysV_ppc(process_sp));
return g_abi_sp;
}
return ABISP();
@@ -282,7 +282,7 @@ bool ABISysV_ppc::PrepareTrivialCall(Thread &thread, addr_t sp,
sp -= 8;
- Error error;
+ Status error;
const RegisterInfo *pc_reg_info =
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
const RegisterInfo *sp_reg_info =
@@ -376,7 +376,7 @@ static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
scalar.SignExtend(bit_width);
} else {
uint32_t byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (thread.GetProcess()->ReadScalarIntegerFromMemory(
current_stack_argument, byte_size, is_signed, scalar, error)) {
current_stack_argument += byte_size;
@@ -464,9 +464,9 @@ bool ABISysV_ppc::GetArgumentValues(Thread &thread, ValueList &values) const {
return true;
}
-Error ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -492,7 +492,7 @@ Error ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -518,7 +518,7 @@ Error ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
size_t bit_width = compiler_type.GetBitSize(frame_sp.get());
if (bit_width <= 64) {
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -663,7 +663,7 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple(
const ByteOrder byte_order = process_sp->GetByteOrder();
RegisterValue reg_value;
if (reg_ctx->ReadRegister(altivec_reg, reg_value)) {
- Error error;
+ Status error;
if (reg_value.GetAsMemoryData(
altivec_reg, heap_data_ap->GetBytes(),
heap_data_ap->GetByteSize(), byte_order, error)) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h
index c9c1c98..df3ebe8 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h
@@ -31,7 +31,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -83,7 +83,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -105,7 +105,7 @@ protected:
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
- ABISysV_ppc() : lldb_private::ABI() {
+ ABISysV_ppc(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp
index 4ffcba3..c090f01 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp
@@ -16,10 +16,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -33,6 +29,10 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -223,11 +223,11 @@ size_t ABISysV_ppc64::GetRedZoneSize() const { return 224; }
//------------------------------------------------------------------
ABISP
-ABISysV_ppc64::CreateInstance(const ArchSpec &arch) {
+ABISysV_ppc64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
if (arch.GetTriple().getArch() == llvm::Triple::ppc64) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_ppc64);
+ g_abi_sp.reset(new ABISysV_ppc64(process_sp));
return g_abi_sp;
}
return ABISP();
@@ -282,7 +282,7 @@ bool ABISysV_ppc64::PrepareTrivialCall(Thread &thread, addr_t sp,
sp -= 8;
- Error error;
+ Status error;
const RegisterInfo *pc_reg_info =
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
const RegisterInfo *sp_reg_info =
@@ -376,7 +376,7 @@ static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
scalar.SignExtend(bit_width);
} else {
uint32_t byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (thread.GetProcess()->ReadScalarIntegerFromMemory(
current_stack_argument, byte_size, is_signed, scalar, error)) {
current_stack_argument += byte_size;
@@ -464,9 +464,9 @@ bool ABISysV_ppc64::GetArgumentValues(Thread &thread, ValueList &values) const {
return true;
}
-Error ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -492,7 +492,7 @@ Error ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -518,7 +518,7 @@ Error ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
size_t bit_width = compiler_type.GetBitSize(frame_sp.get());
if (bit_width <= 64) {
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -663,7 +663,7 @@ ValueObjectSP ABISysV_ppc64::GetReturnValueObjectSimple(
const ByteOrder byte_order = process_sp->GetByteOrder();
RegisterValue reg_value;
if (reg_ctx->ReadRegister(altivec_reg, reg_value)) {
- Error error;
+ Status error;
if (reg_value.GetAsMemoryData(
altivec_reg, heap_data_ap->GetBytes(),
heap_data_ap->GetByteSize(), byte_order, error)) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h
index 7f321df..21608a5 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h
@@ -31,7 +31,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -83,7 +83,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -105,7 +105,7 @@ protected:
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
- ABISysV_ppc64() : lldb_private::ABI() {
+ ABISysV_ppc64(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp
index 7e6506b..967e407 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp
@@ -16,10 +16,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -33,6 +29,10 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -205,11 +205,11 @@ size_t ABISysV_s390x::GetRedZoneSize() const { return 0; }
//------------------------------------------------------------------
ABISP
-ABISysV_s390x::CreateInstance(const ArchSpec &arch) {
+ABISysV_s390x::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
if (arch.GetTriple().getArch() == llvm::Triple::systemz) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_s390x);
+ g_abi_sp.reset(new ABISysV_s390x(process_sp));
return g_abi_sp;
}
return ABISP();
@@ -268,7 +268,7 @@ bool ABISysV_s390x::PrepareTrivialCall(Thread &thread, addr_t sp,
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
return false;
} else {
- Error error;
+ Status error;
if (log)
log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") onto stack",
static_cast<uint64_t>(i + 1), args[i]);
@@ -321,7 +321,7 @@ static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
scalar.SignExtend(bit_width);
} else {
uint32_t byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (thread.GetProcess()->ReadScalarIntegerFromMemory(
current_stack_argument + 8 - byte_size, byte_size, is_signed,
scalar, error)) {
@@ -401,9 +401,9 @@ bool ABISysV_s390x::GetArgumentValues(Thread &thread, ValueList &values) const {
return true;
}
-Error ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -429,7 +429,7 @@ Error ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r2", 0);
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -457,7 +457,7 @@ Error ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0);
RegisterValue f0_value;
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h
index 6ccabd6..5e3d20d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h
@@ -31,7 +31,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -77,7 +77,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -99,7 +99,7 @@ protected:
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
- ABISysV_s390x() : lldb_private::ABI() {
+ ABISysV_s390x(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
index 2019db2..10bbae5 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -16,10 +16,6 @@
#include "llvm/ADT/Triple.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
@@ -33,6 +29,10 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -1093,11 +1093,11 @@ size_t ABISysV_x86_64::GetRedZoneSize() const { return 128; }
//------------------------------------------------------------------
ABISP
-ABISysV_x86_64::CreateInstance(const ArchSpec &arch) {
+ABISysV_x86_64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
static ABISP g_abi_sp;
if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
if (!g_abi_sp)
- g_abi_sp.reset(new ABISysV_x86_64);
+ g_abi_sp.reset(new ABISysV_x86_64(process_sp));
return g_abi_sp;
}
return ABISP();
@@ -1152,7 +1152,7 @@ bool ABISysV_x86_64::PrepareTrivialCall(Thread &thread, addr_t sp,
sp -= 8;
- Error error;
+ Status error;
const RegisterInfo *pc_reg_info =
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
const RegisterInfo *sp_reg_info =
@@ -1246,7 +1246,7 @@ static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
scalar.SignExtend(bit_width);
} else {
uint32_t byte_size = (bit_width + (8 - 1)) / 8;
- Error error;
+ Status error;
if (thread.GetProcess()->ReadScalarIntegerFromMemory(
current_stack_argument, byte_size, is_signed, scalar, error)) {
current_stack_argument += byte_size;
@@ -1329,9 +1329,9 @@ bool ABISysV_x86_64::GetArgumentValues(Thread &thread,
return true;
}
-Error ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
- lldb::ValueObjectSP &new_value_sp) {
- Error error;
+Status ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
+ lldb::ValueObjectSP &new_value_sp) {
+ Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
@@ -1357,7 +1357,7 @@ Error ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("rax", 0);
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -1386,7 +1386,7 @@ Error ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
reg_ctx->GetRegisterInfoByName("xmm0", 0);
RegisterValue xmm0_value;
DataExtractor data;
- Error data_error;
+ Status data_error;
size_t num_bytes = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
@@ -1542,7 +1542,7 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple(
const ByteOrder byte_order = process_sp->GetByteOrder();
RegisterValue reg_value;
if (reg_ctx->ReadRegister(altivec_reg, reg_value)) {
- Error error;
+ Status error;
if (reg_value.GetAsMemoryData(
altivec_reg, heap_data_ap->GetBytes(),
heap_data_ap->GetByteSize(), byte_order, error)) {
@@ -1569,7 +1569,7 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple(
if (reg_ctx->ReadRegister(altivec_reg, reg_value) &&
reg_ctx->ReadRegister(altivec_reg2, reg_value2)) {
- Error error;
+ Status error;
if (reg_value.GetAsMemoryData(
altivec_reg, heap_data_ap->GetBytes(),
altivec_reg->byte_size, byte_order, error) &&
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
index 29f2ce1..5b67e86 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -31,7 +31,7 @@ public:
bool GetArgumentValues(lldb_private::Thread &thread,
lldb_private::ValueList &values) const override;
- lldb_private::Error
+ lldb_private::Status
SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value) override;
@@ -85,7 +85,7 @@ public:
static void Terminate();
- static lldb::ABISP CreateInstance(const lldb_private::ArchSpec &arch);
+ static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch);
static lldb_private::ConstString GetPluginNameStatic();
@@ -107,7 +107,7 @@ protected:
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info);
private:
- ABISysV_x86_64() : lldb_private::ABI() {
+ ABISysV_x86_64(lldb::ProcessSP process_sp) : lldb_private::ABI(process_sp) {
// Call CreateInstance instead.
}
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/contrib/llvm/tools/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
index b7415b4..21e19bf 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -31,10 +31,7 @@
#include "DisassemblerLLVMC.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
@@ -42,8 +39,11 @@
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Utility/RegularExpression.h"
using namespace lldb;
using namespace lldb_private;
@@ -885,9 +885,9 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler(
const char *triple, const char *cpu, const char *features_str,
unsigned flavor, DisassemblerLLVMC &owner)
: m_is_valid(true) {
- std::string Error;
+ std::string Status;
const llvm::Target *curr_target =
- llvm::TargetRegistry::lookupTarget(triple, Error);
+ llvm::TargetRegistry::lookupTarget(triple, Status);
if (!curr_target) {
m_is_valid = false;
return;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
index 3c64b2f..d0d6001 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp
@@ -11,7 +11,6 @@
// C++ Includes
// Other libraries and framework includes
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
@@ -21,6 +20,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/Log.h"
#include "DynamicLoaderHexagonDYLD.h"
@@ -213,7 +213,7 @@ ModuleSP DynamicLoaderHexagonDYLD::GetTargetExecutable() {
}
// AD: Needs to be updated?
-Error DynamicLoaderHexagonDYLD::CanLoadImage() { return Error(); }
+Status DynamicLoaderHexagonDYLD::CanLoadImage() { return Status(); }
void DynamicLoaderHexagonDYLD::UpdateLoadedSections(ModuleSP module,
addr_t link_map_addr,
@@ -558,7 +558,7 @@ const SectionList *DynamicLoaderHexagonDYLD::GetSectionListFromModule(
}
static int ReadInt(Process *process, addr_t addr) {
- Error error;
+ Status error;
int value = (int)process->ReadUnsignedIntegerFromMemory(
addr, sizeof(uint32_t), 0, error);
if (error.Fail())
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h
index 05709d0..200a4171b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h
@@ -47,7 +47,7 @@ public:
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
bool stop_others) override;
- lldb_private::Error CanLoadImage() override;
+ lldb_private::Status CanLoadImage() override;
lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module,
const lldb::ThreadSP thread,
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
index da0edc8..1ef1be5 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
@@ -11,13 +11,13 @@
// C++ Includes
// Other libraries and framework includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Process.h"
@@ -33,7 +33,7 @@ using namespace lldb_private;
static addr_t ResolveRendezvousAddress(Process *process) {
addr_t info_location;
addr_t info_addr;
- Error error;
+ Status error;
info_location = process->GetImageInfoAddress();
@@ -222,7 +222,7 @@ bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst,
size_t size) {
- Error error;
+ Status error;
*dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
if (error.Fail())
@@ -232,7 +232,7 @@ addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst,
}
addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
- Error error;
+ Status error;
*dst = m_process->ReadPointerFromMemory(addr, error);
if (error.Fail())
@@ -243,7 +243,7 @@ addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) {
std::string str;
- Error error;
+ Status error;
size_t size;
char c;
@@ -304,7 +304,7 @@ bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field,
if (addr == LLDB_INVALID_ADDRESS)
return false;
- Error error;
+ Status error;
value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
if (error.Fail())
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
index ec655c6..7dd2b57 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
@@ -7,23 +7,11 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-// C++ Includes
-// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Target/Process.h"
-
-#if defined(__linux__) || defined(__FreeBSD__)
-#include "Plugins/Process/elf-core/ProcessElfCore.h"
-#endif
-
#include "AuxVector.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -63,10 +51,10 @@ void AuxVector::ParseAuxv(DataExtractor &data) {
if (!ParseAuxvEntry(data, entry, &offset, byte_size))
break;
- if (entry.type == AT_NULL)
+ if (entry.type == AUXV_AT_NULL)
break;
- if (entry.type == AT_IGNORE)
+ if (entry.type == AUXV_AT_IGNORE)
continue;
m_auxv.push_back(entry);
@@ -110,43 +98,43 @@ void AuxVector::DumpToLog(Log *log) const {
const char *AuxVector::GetEntryName(EntryType type) {
const char *name = "AT_???";
-#define ENTRY_NAME(_type) \
- _type: \
- name = #_type
+#define ENTRY_NAME(_type) \
+ _type: \
+ name = #_type + 5
switch (type) {
- case ENTRY_NAME(AT_NULL); break;
- case ENTRY_NAME(AT_IGNORE); break;
- case ENTRY_NAME(AT_EXECFD); break;
- case ENTRY_NAME(AT_PHDR); break;
- case ENTRY_NAME(AT_PHENT); break;
- case ENTRY_NAME(AT_PHNUM); break;
- case ENTRY_NAME(AT_PAGESZ); break;
- case ENTRY_NAME(AT_BASE); break;
- case ENTRY_NAME(AT_FLAGS); break;
- case ENTRY_NAME(AT_ENTRY); break;
- case ENTRY_NAME(AT_NOTELF); break;
- case ENTRY_NAME(AT_UID); break;
- case ENTRY_NAME(AT_EUID); break;
- case ENTRY_NAME(AT_GID); break;
- case ENTRY_NAME(AT_EGID); break;
- case ENTRY_NAME(AT_CLKTCK); break;
- case ENTRY_NAME(AT_PLATFORM); break;
- case ENTRY_NAME(AT_HWCAP); break;
- case ENTRY_NAME(AT_FPUCW); break;
- case ENTRY_NAME(AT_DCACHEBSIZE); break;
- case ENTRY_NAME(AT_ICACHEBSIZE); break;
- case ENTRY_NAME(AT_UCACHEBSIZE); break;
- case ENTRY_NAME(AT_IGNOREPPC); break;
- case ENTRY_NAME(AT_SECURE); break;
- case ENTRY_NAME(AT_BASE_PLATFORM); break;
- case ENTRY_NAME(AT_RANDOM); break;
- case ENTRY_NAME(AT_EXECFN); break;
- case ENTRY_NAME(AT_SYSINFO); break;
- case ENTRY_NAME(AT_SYSINFO_EHDR); break;
- case ENTRY_NAME(AT_L1I_CACHESHAPE); break;
- case ENTRY_NAME(AT_L1D_CACHESHAPE); break;
- case ENTRY_NAME(AT_L2_CACHESHAPE); break;
- case ENTRY_NAME(AT_L3_CACHESHAPE); break;
+ case ENTRY_NAME(AUXV_AT_NULL); break;
+ case ENTRY_NAME(AUXV_AT_IGNORE); break;
+ case ENTRY_NAME(AUXV_AT_EXECFD); break;
+ case ENTRY_NAME(AUXV_AT_PHDR); break;
+ case ENTRY_NAME(AUXV_AT_PHENT); break;
+ case ENTRY_NAME(AUXV_AT_PHNUM); break;
+ case ENTRY_NAME(AUXV_AT_PAGESZ); break;
+ case ENTRY_NAME(AUXV_AT_BASE); break;
+ case ENTRY_NAME(AUXV_AT_FLAGS); break;
+ case ENTRY_NAME(AUXV_AT_ENTRY); break;
+ case ENTRY_NAME(AUXV_AT_NOTELF); break;
+ case ENTRY_NAME(AUXV_AT_UID); break;
+ case ENTRY_NAME(AUXV_AT_EUID); break;
+ case ENTRY_NAME(AUXV_AT_GID); break;
+ case ENTRY_NAME(AUXV_AT_EGID); break;
+ case ENTRY_NAME(AUXV_AT_CLKTCK); break;
+ case ENTRY_NAME(AUXV_AT_PLATFORM); break;
+ case ENTRY_NAME(AUXV_AT_HWCAP); break;
+ case ENTRY_NAME(AUXV_AT_FPUCW); break;
+ case ENTRY_NAME(AUXV_AT_DCACHEBSIZE); break;
+ case ENTRY_NAME(AUXV_AT_ICACHEBSIZE); break;
+ case ENTRY_NAME(AUXV_AT_UCACHEBSIZE); break;
+ case ENTRY_NAME(AUXV_AT_IGNOREPPC); break;
+ case ENTRY_NAME(AUXV_AT_SECURE); break;
+ case ENTRY_NAME(AUXV_AT_BASE_PLATFORM); break;
+ case ENTRY_NAME(AUXV_AT_RANDOM); break;
+ case ENTRY_NAME(AUXV_AT_EXECFN); break;
+ case ENTRY_NAME(AUXV_AT_SYSINFO); break;
+ case ENTRY_NAME(AUXV_AT_SYSINFO_EHDR); break;
+ case ENTRY_NAME(AUXV_AT_L1I_CACHESHAPE); break;
+ case ENTRY_NAME(AUXV_AT_L1D_CACHESHAPE); break;
+ case ENTRY_NAME(AUXV_AT_L2_CACHESHAPE); break;
+ case ENTRY_NAME(AUXV_AT_L3_CACHESHAPE); break;
}
#undef ENTRY_NAME
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h
index 9c3e1b0..cf9da08 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h
@@ -42,41 +42,42 @@ public:
/// Constants describing the type of entry.
/// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX information.
+ /// Added AUXV prefix to avoid potential conflicts with system-defined macros
enum EntryType {
- AT_NULL = 0, ///< End of auxv.
- AT_IGNORE = 1, ///< Ignore entry.
- AT_EXECFD = 2, ///< File descriptor of program.
- AT_PHDR = 3, ///< Program headers.
- AT_PHENT = 4, ///< Size of program header.
- AT_PHNUM = 5, ///< Number of program headers.
- AT_PAGESZ = 6, ///< Page size.
- AT_BASE = 7, ///< Interpreter base address.
- AT_FLAGS = 8, ///< Flags.
- AT_ENTRY = 9, ///< Program entry point.
- AT_NOTELF = 10, ///< Set if program is not an ELF.
- AT_UID = 11, ///< UID.
- AT_EUID = 12, ///< Effective UID.
- AT_GID = 13, ///< GID.
- AT_EGID = 14, ///< Effective GID.
- AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)).
- AT_PLATFORM = 15, ///< String identifying platform.
- AT_HWCAP = 16, ///< Machine dependent hints about processor capabilities.
- AT_FPUCW = 18, ///< Used FPU control word.
- AT_DCACHEBSIZE = 19, ///< Data cache block size.
- AT_ICACHEBSIZE = 20, ///< Instruction cache block size.
- AT_UCACHEBSIZE = 21, ///< Unified cache block size.
- AT_IGNOREPPC = 22, ///< Entry should be ignored.
- AT_SECURE = 23, ///< Boolean, was exec setuid-like?
- AT_BASE_PLATFORM = 24, ///< String identifying real platforms.
- AT_RANDOM = 25, ///< Address of 16 random bytes.
- AT_EXECFN = 31, ///< Filename of executable.
- AT_SYSINFO = 32, ///< Pointer to the global system page used for system
- ///calls and other nice things.
- AT_SYSINFO_EHDR = 33,
- AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches.
- AT_L1D_CACHESHAPE = 35,
- AT_L2_CACHESHAPE = 36,
- AT_L3_CACHESHAPE = 37,
+ AUXV_AT_NULL = 0, ///< End of auxv.
+ AUXV_AT_IGNORE = 1, ///< Ignore entry.
+ AUXV_AT_EXECFD = 2, ///< File descriptor of program.
+ AUXV_AT_PHDR = 3, ///< Program headers.
+ AUXV_AT_PHENT = 4, ///< Size of program header.
+ AUXV_AT_PHNUM = 5, ///< Number of program headers.
+ AUXV_AT_PAGESZ = 6, ///< Page size.
+ AUXV_AT_BASE = 7, ///< Interpreter base address.
+ AUXV_AT_FLAGS = 8, ///< Flags.
+ AUXV_AT_ENTRY = 9, ///< Program entry point.
+ AUXV_AT_NOTELF = 10, ///< Set if program is not an ELF.
+ AUXV_AT_UID = 11, ///< UID.
+ AUXV_AT_EUID = 12, ///< Effective UID.
+ AUXV_AT_GID = 13, ///< GID.
+ AUXV_AT_EGID = 14, ///< Effective GID.
+ AUXV_AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)).
+ AUXV_AT_PLATFORM = 15, ///< String identifying platform.
+ AUXV_AT_HWCAP = 16, ///< Machine dependent hints about processor capabilities.
+ AUXV_AT_FPUCW = 18, ///< Used FPU control word.
+ AUXV_AT_DCACHEBSIZE = 19, ///< Data cache block size.
+ AUXV_AT_ICACHEBSIZE = 20, ///< Instruction cache block size.
+ AUXV_AT_UCACHEBSIZE = 21, ///< Unified cache block size.
+ AUXV_AT_IGNOREPPC = 22, ///< Entry should be ignored.
+ AUXV_AT_SECURE = 23, ///< Boolean, was exec setuid-like?
+ AUXV_AT_BASE_PLATFORM = 24, ///< String identifying real platforms.
+ AUXV_AT_RANDOM = 25, ///< Address of 16 random bytes.
+ AUXV_AT_EXECFN = 31, ///< Filename of executable.
+ AUXV_AT_SYSINFO = 32, ///< Pointer to the global system page used for system
+ ///calls and other nice things.
+ AUXV_AT_SYSINFO_EHDR = 33,
+ AUXV_AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches.
+ AUXV_AT_L1D_CACHESHAPE = 35,
+ AUXV_AT_L2_CACHESHAPE = 36,
+ AUXV_AT_L3_CACHESHAPE = 37,
};
private:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
index 136bf65..c198697 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
@@ -11,8 +11,6 @@
// C++ Includes
// Other libraries and framework includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
@@ -20,6 +18,8 @@
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "llvm/Support/Path.h"
@@ -34,7 +34,7 @@ static addr_t ResolveRendezvousAddress(Process *process) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
addr_t info_location;
addr_t info_addr;
- Error error;
+ Status error;
if (!process) {
if (log)
@@ -379,12 +379,13 @@ bool DYLDRendezvous::RemoveSOEntries() {
}
bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) {
- // On Linux the executable is indicated by an empty path in the entry. On
- // FreeBSD and on Android it is the full path to the executable.
+ // On some systes the executable is indicated by an empty path in the entry.
+ // On others it is the full path to the executable.
auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
switch (triple.getOS()) {
case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
return entry.file_spec == m_exe_file_spec;
case llvm::Triple::Linux:
if (triple.isAndroid())
@@ -419,7 +420,7 @@ bool DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
}
addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) {
- Error error;
+ Status error;
*dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
if (error.Fail())
@@ -429,7 +430,7 @@ addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) {
}
addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
- Error error;
+ Status error;
*dst = m_process->ReadPointerFromMemory(addr, error);
if (error.Fail())
@@ -440,7 +441,7 @@ addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
std::string DYLDRendezvous::ReadStringFromMemory(addr_t addr) {
std::string str;
- Error error;
+ Status error;
if (addr == LLDB_INVALID_ADDRESS)
return std::string();
@@ -478,7 +479,7 @@ void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry,
if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) {
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
bool is_loaded = false;
- Error error =
+ Status error =
m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
if (error.Success() && is_loaded)
entry.base_addr = load_addr;
@@ -544,7 +545,7 @@ bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field,
if (addr == LLDB_INVALID_ADDRESS)
return false;
- Error error;
+ Status error;
value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
if (error.Fail())
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
index 55b8bd7..295ae55 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
@@ -16,7 +16,7 @@
#include <string>
// Other libraries and framework includes
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index fc225ee..a7afeb6 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -15,18 +15,19 @@
// Other libraries and framework includes
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/Log.h"
// C++ Includes
// C Includes
@@ -63,8 +64,9 @@ DynamicLoader *DynamicLoaderPOSIXDYLD::CreateInstance(Process *process,
if (!create) {
const llvm::Triple &triple_ref =
process->GetTarget().GetArchitecture().GetTriple();
- if (triple_ref.getOS() == llvm::Triple::Linux ||
- triple_ref.getOS() == llvm::Triple::FreeBSD)
+ if (triple_ref.getOS() == llvm::Triple::FreeBSD ||
+ triple_ref.getOS() == llvm::Triple::Linux ||
+ triple_ref.getOS() == llvm::Triple::NetBSD)
create = true;
}
@@ -221,7 +223,7 @@ void DynamicLoaderPOSIXDYLD::DidLaunch() {
}
}
-Error DynamicLoaderPOSIXDYLD::CanLoadImage() { return Error(); }
+Status DynamicLoaderPOSIXDYLD::CanLoadImage() { return Status(); }
void DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module,
addr_t link_map_addr,
@@ -483,6 +485,27 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread,
return thread_plan_sp;
}
+void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) {
+ if (m_vdso_base == LLDB_INVALID_ADDRESS)
+ return;
+
+ FileSpec file("[vdso]", false);
+
+ MemoryRegionInfo info;
+ Status status = m_process->GetMemoryRegionInfo(m_vdso_base, info);
+ if (status.Fail()) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ LLDB_LOG(log, "Failed to get vdso region info: {0}", status);
+ return;
+ }
+
+ if (ModuleSP module_sp = m_process->ReadModuleFromMemory(
+ file, m_vdso_base, info.GetRange().GetByteSize())) {
+ UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_vdso_base, false);
+ m_process->GetTarget().GetImages().AppendIfNeeded(module_sp);
+ }
+}
+
void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
DYLDRendezvous::iterator I;
DYLDRendezvous::iterator E;
@@ -501,14 +524,7 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
// that ourselves here.
ModuleSP executable = GetTargetExecutable();
m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
- if (m_vdso_base != LLDB_INVALID_ADDRESS) {
- FileSpec file_spec("[vdso]", false);
- ModuleSP module_sp = LoadModuleAtAddress(file_spec, LLDB_INVALID_ADDRESS,
- m_vdso_base, false);
- if (module_sp.get()) {
- module_list.Append(module_sp);
- }
- }
+ LoadVDSO(module_list);
std::vector<FileSpec> module_names;
for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
@@ -560,7 +576,7 @@ addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() {
}
void DynamicLoaderPOSIXDYLD::EvalVdsoStatus() {
- AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_SYSINFO_EHDR);
+ AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AUXV_AT_SYSINFO_EHDR);
if (I != m_auxv->end())
m_vdso_base = I->value;
@@ -573,7 +589,7 @@ addr_t DynamicLoaderPOSIXDYLD::GetEntryPoint() {
if (m_auxv.get() == NULL)
return LLDB_INVALID_ADDRESS;
- AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY);
+ AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AUXV_AT_ENTRY);
if (I == m_auxv->end())
return LLDB_INVALID_ADDRESS;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
index 1e8333f..2e96705 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
@@ -12,13 +12,16 @@
// C Includes
// C++ Includes
+#include <map>
+#include <memory>
+
// Other libraries and framework includes
// Project includes
+#include "DYLDRendezvous.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/ModuleList.h"
#include "lldb/Target/DynamicLoader.h"
-#include "DYLDRendezvous.h"
-
class AuxVector;
class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader {
@@ -49,7 +52,7 @@ public:
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
bool stop_others) override;
- lldb_private::Error CanLoadImage() override;
+ lldb_private::Status CanLoadImage() override;
lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module,
const lldb::ThreadSP thread,
@@ -135,6 +138,8 @@ protected:
/// of all dependent modules.
virtual void LoadAllCurrentModules();
+ void LoadVDSO(lldb_private::ModuleList &modules);
+
/// Computes a value for m_load_offset returning the computed address on
/// success and LLDB_INVALID_ADDRESS on failure.
lldb::addr_t ComputeLoadOffset();
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp
index 04f1f33..291695c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp
@@ -132,8 +132,8 @@ DynamicLoaderStatic::GetStepThroughTrampolinePlan(Thread &thread,
return ThreadPlanSP();
}
-Error DynamicLoaderStatic::CanLoadImage() {
- Error error;
+Status DynamicLoaderStatic::CanLoadImage() {
+ Status error;
error.SetErrorString("can't load images on with a static debug session");
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
index c6122edf5..2d18ec8 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
@@ -14,10 +14,10 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/UUID.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/UUID.h"
class DynamicLoaderStatic : public lldb_private::DynamicLoader {
public:
@@ -52,7 +52,7 @@ public:
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
bool stop_others) override;
- lldb_private::Error CanLoadImage() override;
+ lldb_private::Status CanLoadImage() override;
//------------------------------------------------------------------
// PluginInterface protocol
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
index 20bf360..c381326 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
@@ -61,7 +61,7 @@ void DynamicLoaderWindowsDYLD::DidAttach() {}
void DynamicLoaderWindowsDYLD::DidLaunch() {}
-Error DynamicLoaderWindowsDYLD::CanLoadImage() { return Error(); }
+Status DynamicLoaderWindowsDYLD::CanLoadImage() { return Status(); }
ConstString DynamicLoaderWindowsDYLD::GetPluginName() {
return GetPluginNameStatic();
diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
index 3494082..de6e295 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
@@ -34,7 +34,7 @@ public:
void DidAttach() override;
void DidLaunch() override;
- Error CanLoadImage() override;
+ Status CanLoadImage() override;
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
bool stop) override;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp
index c74f147..0d619e4 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp
@@ -9,10 +9,10 @@
#include "ASTDumper.h"
-#include "lldb/Core/Log.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Utility/Log.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.h b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.h
index 9a72fb6..58ba197 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.h
@@ -13,7 +13,7 @@
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeVisitor.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
#include "llvm/ADT/DenseSet.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
index f60587e..9e6a2f3 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
@@ -11,11 +11,11 @@
#include "ClangPersistentVariables.h"
-#include "lldb/Core/Log.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangASTImporter.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
#include "stdlib.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
index 7bb784e..2faeecd 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
@@ -9,7 +9,7 @@
#include "ASTStructExtractor.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
#include "stdlib.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 0f08dd3..7622791 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -12,7 +12,6 @@
#include "ASTDumper.h"
#include "ClangModulesDeclVendor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Symbol/ClangASTContext.h"
@@ -24,6 +23,7 @@
#include "lldb/Symbol/TaggedASTType.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
@@ -139,6 +139,7 @@ bool ClangASTSource::FindExternalVisibleDeclsByName(
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXDeductionGuideName:
SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
return false;
}
@@ -347,7 +348,7 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) {
GetCompleteObjCInterface(original_iface_decl);
if (complete_iface_decl && (complete_iface_decl != original_iface_decl)) {
- m_ast_importer_sp->SetDeclOrigin(interface_decl, original_iface_decl);
+ m_ast_importer_sp->SetDeclOrigin(interface_decl, complete_iface_decl);
}
}
}
@@ -471,7 +472,7 @@ void ClangASTSource::FindExternalLexicalDecls(
original_decl = complete_iface_decl;
original_ctx = &complete_iface_decl->getASTContext();
- m_ast_importer_sp->SetDeclOrigin(context_decl, original_iface_decl);
+ m_ast_importer_sp->SetDeclOrigin(context_decl, complete_iface_decl);
}
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index c1470c5..8fde410 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -15,15 +15,12 @@
#include "ClangPersistentVariables.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Expression/Materializer.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/CompilerDecl.h"
@@ -45,6 +42,9 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-private.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -191,7 +191,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl,
return false;
if (m_parser_vars->m_materializer && is_result) {
- Error err;
+ Status err;
ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
Target *target = exe_ctx.GetTargetPtr();
@@ -364,7 +364,7 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl,
if (m_parser_vars->m_materializer) {
uint32_t offset = 0;
- Error err;
+ Status err;
if (is_persistent_variable) {
ExpressionVariableSP var_sp(var->shared_from_this());
@@ -591,103 +591,6 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(const ConstString &name,
symbol_type);
}
-const Symbol *ClangExpressionDeclMap::FindGlobalDataSymbol(
- Target &target, const ConstString &name, lldb_private::Module *module) {
- SymbolContextList sc_list;
-
- if (module)
- module->FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list);
- else
- target.GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny,
- sc_list);
-
- const uint32_t matches = sc_list.GetSize();
- for (uint32_t i = 0; i < matches; ++i) {
- SymbolContext sym_ctx;
- sc_list.GetContextAtIndex(i, sym_ctx);
- if (sym_ctx.symbol) {
- const Symbol *symbol = sym_ctx.symbol;
- const Address sym_address = symbol->GetAddress();
-
- if (sym_address.IsValid()) {
- switch (symbol->GetType()) {
- case eSymbolTypeData:
- case eSymbolTypeRuntime:
- case eSymbolTypeAbsolute:
- case eSymbolTypeObjCClass:
- case eSymbolTypeObjCMetaClass:
- case eSymbolTypeObjCIVar:
- if (symbol->GetDemangledNameIsSynthesized()) {
- // If the demangled name was synthesized, then don't use it
- // for expressions. Only let the symbol match if the mangled
- // named matches for these symbols.
- if (symbol->GetMangled().GetMangledName() != name)
- break;
- }
- return symbol;
-
- case eSymbolTypeReExported: {
- ConstString reexport_name = symbol->GetReExportedSymbolName();
- if (reexport_name) {
- ModuleSP reexport_module_sp;
- ModuleSpec reexport_module_spec;
- reexport_module_spec.GetPlatformFileSpec() =
- symbol->GetReExportedSymbolSharedLibrary();
- if (reexport_module_spec.GetPlatformFileSpec()) {
- reexport_module_sp =
- target.GetImages().FindFirstModule(reexport_module_spec);
- if (!reexport_module_sp) {
- reexport_module_spec.GetPlatformFileSpec()
- .GetDirectory()
- .Clear();
- reexport_module_sp =
- target.GetImages().FindFirstModule(reexport_module_spec);
- }
- }
- // Don't allow us to try and resolve a re-exported symbol if it is
- // the same
- // as the current symbol
- if (name == symbol->GetReExportedSymbolName() &&
- module == reexport_module_sp.get())
- return NULL;
-
- return FindGlobalDataSymbol(target,
- symbol->GetReExportedSymbolName(),
- reexport_module_sp.get());
- }
- } break;
-
- case eSymbolTypeCode: // We already lookup functions elsewhere
- case eSymbolTypeVariable:
- case eSymbolTypeLocal:
- case eSymbolTypeParam:
- case eSymbolTypeTrampoline:
- case eSymbolTypeInvalid:
- case eSymbolTypeException:
- case eSymbolTypeSourceFile:
- case eSymbolTypeHeaderFile:
- case eSymbolTypeObjectFile:
- case eSymbolTypeCommonBlock:
- case eSymbolTypeBlock:
- case eSymbolTypeVariableType:
- case eSymbolTypeLineEntry:
- case eSymbolTypeLineHeader:
- case eSymbolTypeScopeBegin:
- case eSymbolTypeScopeEnd:
- case eSymbolTypeAdditional:
- case eSymbolTypeCompiler:
- case eSymbolTypeInstrumentation:
- case eSymbolTypeUndefined:
- case eSymbolTypeResolver:
- break;
- }
- }
- }
- }
-
- return NULL;
-}
-
lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable(
Target &target, ModuleSP &module, const ConstString &name,
CompilerDeclContext *namespace_decl, TypeFromUser *type) {
@@ -814,9 +717,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl,
current_id);
}
-
- if (!context.m_found.variable && !context.m_found.local_vars_nsp)
- ClangASTSource::FindExternalVisibleDecls(context);
+
+ ClangASTSource::FindExternalVisibleDecls(context);
}
void ClangExpressionDeclMap::FindExternalVisibleDecls(
@@ -1217,7 +1119,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
}
}
- if (var) {
+ if (var && !variable_found) {
variable_found = true;
valobj = ValueObjectVariable::Create(frame, var);
AddOneVariable(context, var, valobj, current_id);
@@ -1248,303 +1150,306 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
}
}
- if (!context.m_found.variable) {
- const bool include_inlines = false;
- const bool append = false;
+ const bool include_inlines = false;
+ const bool append = false;
- if (namespace_decl && module_sp) {
- const bool include_symbols = false;
+ if (namespace_decl && module_sp) {
+ const bool include_symbols = false;
- module_sp->FindFunctions(name, &namespace_decl, eFunctionNameTypeBase,
- include_symbols, include_inlines, append,
- sc_list);
- } else if (target && !namespace_decl) {
- const bool include_symbols = true;
+ module_sp->FindFunctions(name, &namespace_decl, eFunctionNameTypeBase,
+ include_symbols, include_inlines, append,
+ sc_list);
+ } else if (target && !namespace_decl) {
+ const bool include_symbols = true;
- // TODO Fix FindFunctions so that it doesn't return
- // instance methods for eFunctionNameTypeBase.
+ // TODO Fix FindFunctions so that it doesn't return
+ // instance methods for eFunctionNameTypeBase.
- target->GetImages().FindFunctions(name, eFunctionNameTypeFull,
- include_symbols, include_inlines,
- append, sc_list);
- }
+ target->GetImages().FindFunctions(name, eFunctionNameTypeFull,
+ include_symbols, include_inlines,
+ append, sc_list);
+ }
- // If we found more than one function, see if we can use the
- // frame's decl context to remove functions that are shadowed
- // by other functions which match in type but are nearer in scope.
- //
- // AddOneFunction will not add a function whose type has already been
- // added, so if there's another function in the list with a matching
- // type, check to see if their decl context is a parent of the current
- // frame's or was imported via a and using statement, and pick the
- // best match according to lookup rules.
- if (sc_list.GetSize() > 1) {
- // Collect some info about our frame's context.
- StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
- SymbolContext frame_sym_ctx;
- if (frame != nullptr)
- frame_sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
- lldb::eSymbolContextBlock);
- CompilerDeclContext frame_decl_context =
- frame_sym_ctx.block != nullptr
- ? frame_sym_ctx.block->GetDeclContext()
- : CompilerDeclContext();
-
- // We can't do this without a compiler decl context for our frame.
- if (frame_decl_context) {
- clang::DeclContext *frame_decl_ctx =
- (clang::DeclContext *)frame_decl_context.GetOpaqueDeclContext();
- ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(
- frame_decl_context.GetTypeSystem());
-
- // Structure to hold the info needed when comparing function
- // declarations.
- struct FuncDeclInfo {
- ConstString m_name;
- CompilerType m_copied_type;
- uint32_t m_decl_lvl;
- SymbolContext m_sym_ctx;
- };
-
- // First, symplify things by looping through the symbol contexts
- // to remove unwanted functions and separate out the functions we
- // want to compare and prune into a separate list.
- // Cache the info needed about the function declarations in a
- // vector for efficiency.
- SymbolContextList sc_sym_list;
- uint32_t num_indices = sc_list.GetSize();
- std::vector<FuncDeclInfo> fdi_cache;
- fdi_cache.reserve(num_indices);
- for (uint32_t index = 0; index < num_indices; ++index) {
- FuncDeclInfo fdi;
- SymbolContext sym_ctx;
- sc_list.GetContextAtIndex(index, sym_ctx);
-
- // We don't know enough about symbols to compare them,
- // but we should keep them in the list.
- Function *function = sym_ctx.function;
- if (!function) {
- sc_sym_list.Append(sym_ctx);
- continue;
- }
- // Filter out functions without declaration contexts, as well as
- // class/instance methods, since they'll be skipped in the
- // code that follows anyway.
- CompilerDeclContext func_decl_context = function->GetDeclContext();
- if (!func_decl_context ||
- func_decl_context.IsClassMethod(nullptr, nullptr, nullptr))
- continue;
- // We can only prune functions for which we can copy the type.
- CompilerType func_clang_type =
- function->GetType()->GetFullCompilerType();
- CompilerType copied_func_type = GuardedCopyType(func_clang_type);
- if (!copied_func_type) {
- sc_sym_list.Append(sym_ctx);
- continue;
- }
+ // If we found more than one function, see if we can use the
+ // frame's decl context to remove functions that are shadowed
+ // by other functions which match in type but are nearer in scope.
+ //
+ // AddOneFunction will not add a function whose type has already been
+ // added, so if there's another function in the list with a matching
+ // type, check to see if their decl context is a parent of the current
+ // frame's or was imported via a and using statement, and pick the
+ // best match according to lookup rules.
+ if (sc_list.GetSize() > 1) {
+ // Collect some info about our frame's context.
+ StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+ SymbolContext frame_sym_ctx;
+ if (frame != nullptr)
+ frame_sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
+ lldb::eSymbolContextBlock);
+ CompilerDeclContext frame_decl_context =
+ frame_sym_ctx.block != nullptr ? frame_sym_ctx.block->GetDeclContext()
+ : CompilerDeclContext();
- fdi.m_sym_ctx = sym_ctx;
- fdi.m_name = function->GetName();
- fdi.m_copied_type = copied_func_type;
- fdi.m_decl_lvl = LLDB_INVALID_DECL_LEVEL;
- if (fdi.m_copied_type && func_decl_context) {
- // Call CountDeclLevels to get the number of parent scopes we
- // have to look through before we find the function declaration.
- // When comparing functions of the same type, the one with a
- // lower count will be closer to us in the lookup scope and
- // shadows the other.
- clang::DeclContext *func_decl_ctx =
- (clang::DeclContext *)
- func_decl_context.GetOpaqueDeclContext();
- fdi.m_decl_lvl =
- ast->CountDeclLevels(frame_decl_ctx, func_decl_ctx,
- &fdi.m_name, &fdi.m_copied_type);
- }
- fdi_cache.emplace_back(fdi);
- }
+ // We can't do this without a compiler decl context for our frame.
+ if (frame_decl_context) {
+ clang::DeclContext *frame_decl_ctx =
+ (clang::DeclContext *)frame_decl_context.GetOpaqueDeclContext();
+ ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(
+ frame_decl_context.GetTypeSystem());
- // Loop through the functions in our cache looking for matching types,
- // then compare their scope levels to see which is closer.
- std::multimap<CompilerType, const FuncDeclInfo *> matches;
- for (const FuncDeclInfo &fdi : fdi_cache) {
- const CompilerType t = fdi.m_copied_type;
- auto q = matches.find(t);
- if (q != matches.end()) {
- if (q->second->m_decl_lvl > fdi.m_decl_lvl)
- // This function is closer; remove the old set.
- matches.erase(t);
- else if (q->second->m_decl_lvl < fdi.m_decl_lvl)
- // The functions in our set are closer - skip this one.
- continue;
- }
- matches.insert(std::make_pair(t, &fdi));
+ // Structure to hold the info needed when comparing function
+ // declarations.
+ struct FuncDeclInfo {
+ ConstString m_name;
+ CompilerType m_copied_type;
+ uint32_t m_decl_lvl;
+ SymbolContext m_sym_ctx;
+ };
+
+ // First, symplify things by looping through the symbol contexts
+ // to remove unwanted functions and separate out the functions we
+ // want to compare and prune into a separate list.
+ // Cache the info needed about the function declarations in a
+ // vector for efficiency.
+ SymbolContextList sc_sym_list;
+ uint32_t num_indices = sc_list.GetSize();
+ std::vector<FuncDeclInfo> fdi_cache;
+ fdi_cache.reserve(num_indices);
+ for (uint32_t index = 0; index < num_indices; ++index) {
+ FuncDeclInfo fdi;
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(index, sym_ctx);
+
+ // We don't know enough about symbols to compare them,
+ // but we should keep them in the list.
+ Function *function = sym_ctx.function;
+ if (!function) {
+ sc_sym_list.Append(sym_ctx);
+ continue;
+ }
+ // Filter out functions without declaration contexts, as well as
+ // class/instance methods, since they'll be skipped in the
+ // code that follows anyway.
+ CompilerDeclContext func_decl_context = function->GetDeclContext();
+ if (!func_decl_context ||
+ func_decl_context.IsClassMethod(nullptr, nullptr, nullptr))
+ continue;
+ // We can only prune functions for which we can copy the type.
+ CompilerType func_clang_type =
+ function->GetType()->GetFullCompilerType();
+ CompilerType copied_func_type = GuardedCopyType(func_clang_type);
+ if (!copied_func_type) {
+ sc_sym_list.Append(sym_ctx);
+ continue;
}
- // Loop through our matches and add their symbol contexts to our list.
- SymbolContextList sc_func_list;
- for (const auto &q : matches)
- sc_func_list.Append(q.second->m_sym_ctx);
+ fdi.m_sym_ctx = sym_ctx;
+ fdi.m_name = function->GetName();
+ fdi.m_copied_type = copied_func_type;
+ fdi.m_decl_lvl = LLDB_INVALID_DECL_LEVEL;
+ if (fdi.m_copied_type && func_decl_context) {
+ // Call CountDeclLevels to get the number of parent scopes we
+ // have to look through before we find the function declaration.
+ // When comparing functions of the same type, the one with a
+ // lower count will be closer to us in the lookup scope and
+ // shadows the other.
+ clang::DeclContext *func_decl_ctx =
+ (clang::DeclContext *)func_decl_context.GetOpaqueDeclContext();
+ fdi.m_decl_lvl = ast->CountDeclLevels(
+ frame_decl_ctx, func_decl_ctx, &fdi.m_name, &fdi.m_copied_type);
+ }
+ fdi_cache.emplace_back(fdi);
+ }
- // Rejoin the lists with the functions in front.
- sc_list = sc_func_list;
- sc_list.Append(sc_sym_list);
+ // Loop through the functions in our cache looking for matching types,
+ // then compare their scope levels to see which is closer.
+ std::multimap<CompilerType, const FuncDeclInfo *> matches;
+ for (const FuncDeclInfo &fdi : fdi_cache) {
+ const CompilerType t = fdi.m_copied_type;
+ auto q = matches.find(t);
+ if (q != matches.end()) {
+ if (q->second->m_decl_lvl > fdi.m_decl_lvl)
+ // This function is closer; remove the old set.
+ matches.erase(t);
+ else if (q->second->m_decl_lvl < fdi.m_decl_lvl)
+ // The functions in our set are closer - skip this one.
+ continue;
+ }
+ matches.insert(std::make_pair(t, &fdi));
}
- }
- if (sc_list.GetSize()) {
- Symbol *extern_symbol = NULL;
- Symbol *non_extern_symbol = NULL;
+ // Loop through our matches and add their symbol contexts to our list.
+ SymbolContextList sc_func_list;
+ for (const auto &q : matches)
+ sc_func_list.Append(q.second->m_sym_ctx);
- for (uint32_t index = 0, num_indices = sc_list.GetSize();
- index < num_indices; ++index) {
- SymbolContext sym_ctx;
- sc_list.GetContextAtIndex(index, sym_ctx);
+ // Rejoin the lists with the functions in front.
+ sc_list = sc_func_list;
+ sc_list.Append(sc_sym_list);
+ }
+ }
- if (sym_ctx.function) {
- CompilerDeclContext decl_ctx = sym_ctx.function->GetDeclContext();
+ if (sc_list.GetSize()) {
+ Symbol *extern_symbol = NULL;
+ Symbol *non_extern_symbol = NULL;
- if (!decl_ctx)
- continue;
+ for (uint32_t index = 0, num_indices = sc_list.GetSize();
+ index < num_indices; ++index) {
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(index, sym_ctx);
- // Filter out class/instance methods.
- if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr))
- continue;
+ if (sym_ctx.function) {
+ CompilerDeclContext decl_ctx = sym_ctx.function->GetDeclContext();
- AddOneFunction(context, sym_ctx.function, NULL, current_id);
- context.m_found.function_with_type_info = true;
- context.m_found.function = true;
- } else if (sym_ctx.symbol) {
- if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target) {
- sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target);
- if (sym_ctx.symbol == NULL)
- continue;
- }
+ if (!decl_ctx)
+ continue;
- if (sym_ctx.symbol->IsExternal())
- extern_symbol = sym_ctx.symbol;
- else
- non_extern_symbol = sym_ctx.symbol;
+ // Filter out class/instance methods.
+ if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr))
+ continue;
+
+ AddOneFunction(context, sym_ctx.function, NULL, current_id);
+ context.m_found.function_with_type_info = true;
+ context.m_found.function = true;
+ } else if (sym_ctx.symbol) {
+ if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target) {
+ sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target);
+ if (sym_ctx.symbol == NULL)
+ continue;
}
+
+ if (sym_ctx.symbol->IsExternal())
+ extern_symbol = sym_ctx.symbol;
+ else
+ non_extern_symbol = sym_ctx.symbol;
}
+ }
- if (!context.m_found.function_with_type_info) {
- for (clang::NamedDecl *decl : decls_from_modules) {
- if (llvm::isa<clang::FunctionDecl>(decl)) {
- clang::NamedDecl *copied_decl =
- llvm::cast_or_null<FunctionDecl>(m_ast_importer_sp->CopyDecl(
- m_ast_context, &decl->getASTContext(), decl));
- if (copied_decl) {
- context.AddNamedDecl(copied_decl);
- context.m_found.function_with_type_info = true;
- }
+ if (!context.m_found.function_with_type_info) {
+ for (clang::NamedDecl *decl : decls_from_modules) {
+ if (llvm::isa<clang::FunctionDecl>(decl)) {
+ clang::NamedDecl *copied_decl =
+ llvm::cast_or_null<FunctionDecl>(m_ast_importer_sp->CopyDecl(
+ m_ast_context, &decl->getASTContext(), decl));
+ if (copied_decl) {
+ context.AddNamedDecl(copied_decl);
+ context.m_found.function_with_type_info = true;
}
}
}
+ }
- if (!context.m_found.function_with_type_info) {
- if (extern_symbol) {
- AddOneFunction(context, NULL, extern_symbol, current_id);
- context.m_found.function = true;
- } else if (non_extern_symbol) {
- AddOneFunction(context, NULL, non_extern_symbol, current_id);
- context.m_found.function = true;
- }
+ if (!context.m_found.function_with_type_info) {
+ if (extern_symbol) {
+ AddOneFunction(context, NULL, extern_symbol, current_id);
+ context.m_found.function = true;
+ } else if (non_extern_symbol) {
+ AddOneFunction(context, NULL, non_extern_symbol, current_id);
+ context.m_found.function = true;
}
}
+ }
- if (!context.m_found.function_with_type_info) {
- // Try the modules next.
+ if (!context.m_found.function_with_type_info) {
+ // Try the modules next.
- do {
- if (ClangModulesDeclVendor *modules_decl_vendor =
- m_target->GetClangModulesDeclVendor()) {
- bool append = false;
- uint32_t max_matches = 1;
- std::vector<clang::NamedDecl *> decls;
+ do {
+ if (ClangModulesDeclVendor *modules_decl_vendor =
+ m_target->GetClangModulesDeclVendor()) {
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector<clang::NamedDecl *> decls;
- if (!modules_decl_vendor->FindDecls(name, append, max_matches,
- decls))
- break;
+ if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls))
+ break;
- clang::NamedDecl *const decl_from_modules = decls[0];
+ clang::NamedDecl *const decl_from_modules = decls[0];
- if (llvm::isa<clang::FunctionDecl>(decl_from_modules)) {
- if (log) {
- log->Printf(" CAS::FEVD[%u] Matching function found for "
- "\"%s\" in the modules",
- current_id, name.GetCString());
- }
+ if (llvm::isa<clang::FunctionDecl>(decl_from_modules)) {
+ if (log) {
+ log->Printf(" CAS::FEVD[%u] Matching function found for "
+ "\"%s\" in the modules",
+ current_id, name.GetCString());
+ }
- clang::Decl *copied_decl = m_ast_importer_sp->CopyDecl(
- m_ast_context, &decl_from_modules->getASTContext(),
- decl_from_modules);
- clang::FunctionDecl *copied_function_decl =
- copied_decl ? dyn_cast<clang::FunctionDecl>(copied_decl)
- : nullptr;
+ clang::Decl *copied_decl = m_ast_importer_sp->CopyDecl(
+ m_ast_context, &decl_from_modules->getASTContext(),
+ decl_from_modules);
+ clang::FunctionDecl *copied_function_decl =
+ copied_decl ? dyn_cast<clang::FunctionDecl>(copied_decl)
+ : nullptr;
- if (!copied_function_decl) {
- if (log)
- log->Printf(" CAS::FEVD[%u] - Couldn't export a function "
- "declaration from the modules",
- current_id);
+ if (!copied_function_decl) {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a function "
+ "declaration from the modules",
+ current_id);
- break;
- }
+ break;
+ }
- MaybeRegisterFunctionBody(copied_function_decl);
+ MaybeRegisterFunctionBody(copied_function_decl);
- context.AddNamedDecl(copied_function_decl);
+ context.AddNamedDecl(copied_function_decl);
- context.m_found.function_with_type_info = true;
- context.m_found.function = true;
- } else if (llvm::isa<clang::VarDecl>(decl_from_modules)) {
- if (log) {
- log->Printf(" CAS::FEVD[%u] Matching variable found for "
- "\"%s\" in the modules",
- current_id, name.GetCString());
- }
-
- clang::Decl *copied_decl = m_ast_importer_sp->CopyDecl(
- m_ast_context, &decl_from_modules->getASTContext(),
- decl_from_modules);
- clang::VarDecl *copied_var_decl =
- copied_decl ? dyn_cast_or_null<clang::VarDecl>(copied_decl)
- : nullptr;
-
- if (!copied_var_decl) {
- if (log)
- log->Printf(" CAS::FEVD[%u] - Couldn't export a variable "
- "declaration from the modules",
- current_id);
-
- break;
- }
-
- context.AddNamedDecl(copied_var_decl);
-
- context.m_found.variable = true;
+ context.m_found.function_with_type_info = true;
+ context.m_found.function = true;
+ } else if (llvm::isa<clang::VarDecl>(decl_from_modules)) {
+ if (log) {
+ log->Printf(" CAS::FEVD[%u] Matching variable found for "
+ "\"%s\" in the modules",
+ current_id, name.GetCString());
}
- }
- } while (0);
- }
- if (target && !context.m_found.variable && !namespace_decl) {
- // We couldn't find a non-symbol variable for this. Now we'll hunt for
- // a generic
- // data symbol, and -- if it is found -- treat it as a variable.
-
- const Symbol *data_symbol = FindGlobalDataSymbol(*target, name);
-
- if (data_symbol) {
- std::string warning("got name from symbols: ");
- warning.append(name.AsCString());
- const unsigned diag_id =
- m_ast_context->getDiagnostics().getCustomDiagID(
- clang::DiagnosticsEngine::Level::Warning, "%0");
- m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str();
- AddOneGenericVariable(context, *data_symbol, current_id);
- context.m_found.variable = true;
+ clang::Decl *copied_decl = m_ast_importer_sp->CopyDecl(
+ m_ast_context, &decl_from_modules->getASTContext(),
+ decl_from_modules);
+ clang::VarDecl *copied_var_decl =
+ copied_decl ? dyn_cast_or_null<clang::VarDecl>(copied_decl)
+ : nullptr;
+
+ if (!copied_var_decl) {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a variable "
+ "declaration from the modules",
+ current_id);
+
+ break;
+ }
+
+ context.AddNamedDecl(copied_var_decl);
+
+ context.m_found.variable = true;
+ }
}
+ } while (0);
+ }
+
+ if (target && !context.m_found.variable && !namespace_decl) {
+ // We couldn't find a non-symbol variable for this. Now we'll hunt for
+ // a generic
+ // data symbol, and -- if it is found -- treat it as a variable.
+ Status error;
+
+ const Symbol *data_symbol =
+ m_parser_vars->m_sym_ctx.FindBestGlobalDataSymbol(name, error);
+
+ if (!error.Success()) {
+ const unsigned diag_id =
+ m_ast_context->getDiagnostics().getCustomDiagID(
+ clang::DiagnosticsEngine::Level::Error, "%0");
+ m_ast_context->getDiagnostics().Report(diag_id) << error.AsCString();
+ }
+
+ if (data_symbol) {
+ std::string warning("got name from symbols: ");
+ warning.append(name.AsCString());
+ const unsigned diag_id =
+ m_ast_context->getDiagnostics().getCustomDiagID(
+ clang::DiagnosticsEngine::Level::Warning, "%0");
+ m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str();
+ AddOneGenericVariable(context, *data_symbol, current_id);
+ context.m_found.variable = true;
}
}
}
@@ -1637,7 +1542,7 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var,
DWARFExpression &var_location_expr = var->LocationExpression();
Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
- Error err;
+ Status err;
if (var->GetLocationIsConstantValueData()) {
DataExtractor const_value_extractor;
@@ -1994,8 +1899,33 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context,
.GetOpaqueDeclContext();
clang::FunctionDecl *src_function_decl =
llvm::dyn_cast_or_null<clang::FunctionDecl>(src_decl_context);
-
- if (src_function_decl) {
+ if (src_function_decl &&
+ src_function_decl->getTemplateSpecializationInfo()) {
+ clang::FunctionTemplateDecl *function_template =
+ src_function_decl->getTemplateSpecializationInfo()->getTemplate();
+ clang::FunctionTemplateDecl *copied_function_template =
+ llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
+ m_ast_importer_sp->CopyDecl(m_ast_context,
+ src_ast->getASTContext(),
+ function_template));
+ if (copied_function_template) {
+ if (log) {
+ ASTDumper ast_dumper((clang::Decl *)copied_function_template);
+
+ StreamString ss;
+
+ function->DumpSymbolContext(&ss);
+
+ log->Printf(" CEDM::FEVD[%u] Imported decl for function template"
+ " %s (description %s), returned %s",
+ current_id,
+ copied_function_template->getNameAsString().c_str(),
+ ss.GetData(), ast_dumper.GetCString());
+ }
+
+ context.AddNamedDecl(copied_function_template);
+ }
+ } else if (src_function_decl) {
if (clang::FunctionDecl *copied_function_decl =
llvm::dyn_cast_or_null<clang::FunctionDecl>(
m_ast_importer_sp->CopyDecl(m_ast_context,
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
index ac88c1d..e8a9ba6 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -448,24 +448,6 @@ private:
uint64_t GetParserID() { return (uint64_t) this; }
//------------------------------------------------------------------
- /// Given a target, find a data symbol that has the given name.
- ///
- /// @param[in] target
- /// The target to use as the basis for the search.
- ///
- /// @param[in] name
- /// The name as a plain C string.
- ///
- /// @param[in] module
- /// The module to limit the search to. This can be NULL
- ///
- /// @return
- /// The LLDB Symbol found, or NULL if none was found.
- //------------------------------------------------------------------
- const Symbol *FindGlobalDataSymbol(Target &target, const ConstString &name,
- Module *module = NULL);
-
- //------------------------------------------------------------------
/// Given a target, find a variable that matches the given name and
/// type.
///
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index a75e60f..4e20be7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -35,7 +35,6 @@
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/Sema/SemaConsumer.h"
-#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
@@ -68,15 +67,10 @@
#include "IRForTarget.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRInterpreter.h"
@@ -90,7 +84,12 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StringList.h"
using namespace clang;
using namespace llvm;
@@ -340,16 +339,16 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
lang_rt->GetOverrideExprOptions(m_compiler->getTargetOpts());
if (overridden_target_opts)
- if (log) {
- log->Debug(
- "Using overridden target options for the expression evaluation");
+ if (log && log->GetVerbose()) {
+ LLDB_LOGV(
+ log, "Using overridden target options for the expression evaluation");
auto opts = m_compiler->getTargetOpts();
- log->Debug("Triple: '%s'", opts.Triple.c_str());
- log->Debug("CPU: '%s'", opts.CPU.c_str());
- log->Debug("FPMath: '%s'", opts.FPMath.c_str());
- log->Debug("ABI: '%s'", opts.ABI.c_str());
- log->Debug("LinkerVersion: '%s'", opts.LinkerVersion.c_str());
+ LLDB_LOGV(log, "Triple: '{0}'", opts.Triple);
+ LLDB_LOGV(log, "CPU: '{0}'", opts.CPU);
+ LLDB_LOGV(log, "FPMath: '{0}'", opts.FPMath);
+ LLDB_LOGV(log, "ABI: '{0}'", opts.ABI);
+ LLDB_LOGV(log, "LinkerVersion: '{0}'", opts.LinkerVersion);
StringList::LogDump(log, opts.FeaturesAsWritten, "FeaturesAsWritten");
StringList::LogDump(log, opts.Features, "Features");
StringList::LogDump(log, opts.Reciprocals, "Reciprocals");
@@ -757,7 +756,7 @@ static bool FindFunctionInModule(ConstString &mangled_name,
return false;
}
-lldb_private::Error ClangExpressionParser::PrepareForExecution(
+lldb_private::Status ClangExpressionParser::PrepareForExecution(
lldb::addr_t &func_addr, lldb::addr_t &func_end,
lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx,
bool &can_interpret, ExecutionPolicy execution_policy) {
@@ -765,7 +764,7 @@ lldb_private::Error ClangExpressionParser::PrepareForExecution(
func_end = LLDB_INVALID_ADDRESS;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
- lldb_private::Error err;
+ lldb_private::Status err;
std::unique_ptr<llvm::Module> llvm_module_ap(
m_code_generator->ReleaseModule());
@@ -858,7 +857,7 @@ lldb_private::Error ClangExpressionParser::PrepareForExecution(
if (execution_policy != eExecutionPolicyAlways &&
execution_policy != eExecutionPolicyTopLevel) {
- lldb_private::Error interpret_error;
+ lldb_private::Status interpret_error;
bool interpret_function_calls =
!process ? false : process->CanInterpretFunctionCalls();
@@ -942,9 +941,9 @@ lldb_private::Error ClangExpressionParser::PrepareForExecution(
return err;
}
-lldb_private::Error ClangExpressionParser::RunStaticInitializers(
+lldb_private::Status ClangExpressionParser::RunStaticInitializers(
lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx) {
- lldb_private::Error err;
+ lldb_private::Status err;
lldbassert(execution_unit_sp.get());
lldbassert(exe_ctx.HasThreadScope());
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
index 3f01156..3e6a109 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
@@ -12,9 +12,9 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/ClangForward.h"
-#include "lldb/Core/Error.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/ExpressionParser.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-public.h"
#include <string>
@@ -110,7 +110,7 @@ public:
/// An error code indicating the success or failure of the operation.
/// Test with Success().
//------------------------------------------------------------------
- Error
+ Status
PrepareForExecution(lldb::addr_t &func_addr, lldb::addr_t &func_end,
lldb::IRExecutionUnitSP &execution_unit_sp,
ExecutionContext &exe_ctx, bool &can_interpret,
@@ -128,8 +128,8 @@ public:
/// @return
/// The error code indicating the
//------------------------------------------------------------------
- Error RunStaticInitializers(lldb::IRExecutionUnitSP &execution_unit_sp,
- ExecutionContext &exe_ctx);
+ Status RunStaticInitializers(lldb::IRExecutionUnitSP &execution_unit_sp,
+ ExecutionContext &exe_ctx);
//------------------------------------------------------------------
/// Returns a string representing current ABI.
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
index 44594cc..624cbf2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
@@ -9,13 +9,13 @@
#include "ClangExpressionVariable.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Stream.h"
#include "clang/AST/ASTContext.h"
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
index c894506..baa80d7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
@@ -25,10 +25,10 @@
// Project includes
#include "lldb/Core/ClangForward.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/Value.h"
#include "lldb/Expression/ExpressionVariable.h"
#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-public.h"
namespace llvm {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
index 8151993..a26ceda 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
@@ -26,8 +26,6 @@
#include "llvm/IR/Module.h"
// Project includes
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/State.h"
#include "lldb/Core/ValueObject.h"
@@ -44,6 +42,8 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index 64b303c..bce0eaf 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -20,19 +20,21 @@
#include "clang/Parse/Parser.h"
#include "clang/Sema/Lookup.h"
#include "clang/Serialization/ASTReader.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Threading.h"
// Project includes
#include "ClangModulesDeclVendor.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
@@ -143,9 +145,9 @@ void StoringDiagnosticConsumer::DumpDiagnostics(Stream &error_stream) {
static FileSpec GetResourceDir() {
static FileSpec g_cached_resource_dir;
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
HostInfo::GetLLDBPath(lldb::ePathTypeClangDir, g_cached_resource_dir);
});
@@ -449,16 +451,16 @@ void ClangModulesDeclVendorImpl::ForEachMacro(
bool first_arg = true;
- for (clang::MacroInfo::arg_iterator ai = macro_info->arg_begin(),
- ae = macro_info->arg_end();
- ai != ae; ++ai) {
+ for (auto pi = macro_info->param_begin(),
+ pe = macro_info->param_end();
+ pi != pe; ++pi) {
if (!first_arg) {
macro_expansion.append(", ");
} else {
first_arg = false;
}
- macro_expansion.append((*ai)->getName().str());
+ macro_expansion.append((*pi)->getName().str());
}
if (macro_info->isC99Varargs()) {
@@ -605,7 +607,7 @@ ClangModulesDeclVendor::Create(Target &target) {
{
FileSpec clang_resource_dir = GetResourceDir();
- if (clang_resource_dir.IsDirectory()) {
+ if (llvm::sys::fs::is_directory(clang_resource_dir.GetPath())) {
compiler_invocation_arguments.push_back("-resource-dir");
compiler_invocation_arguments.push_back(clang_resource_dir.GetPath());
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
index 4d30956..8ebf784 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
@@ -9,10 +9,10 @@
#include "ClangPersistentVariables.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/Value.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "clang/AST/Decl.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index 5abad71..2a6261a 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -25,12 +25,9 @@
#include "ClangModulesDeclVendor.h"
#include "ClangPersistentVariables.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Expression/ExpressionSourceCode.h"
#include "lldb/Expression/IRExecutionUnit.h"
@@ -51,6 +48,9 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallUserExpression.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -83,7 +83,7 @@ ClangUserExpression::ClangUserExpression(
ClangUserExpression::~ClangUserExpression() {}
-void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err) {
+void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
if (log)
@@ -315,7 +315,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
bool generate_debug_info) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
- Error err;
+ Status err;
InstallContext(exe_ctx);
@@ -501,7 +501,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
//
{
- Error jit_error = parser.PrepareForExecution(
+ Status jit_error = parser.PrepareForExecution(
m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
m_can_interpret, execution_policy);
@@ -517,7 +517,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
}
if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) {
- Error static_init_error =
+ Status static_init_error =
parser.RunStaticInitializers(m_execution_unit_sp, exe_ctx);
if (!static_init_error.Success()) {
@@ -603,13 +603,13 @@ bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx,
return false;
}
- Error object_ptr_error;
+ Status object_ptr_error;
object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
if (!object_ptr_error.Success()) {
exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf(
- "warning: `%s' is not accessible (subsituting 0)\n",
+ "warning: `%s' is not accessible (substituting 0)\n",
object_name.AsCString());
object_ptr = 0;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
index 155c153..88a7879 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -168,7 +168,7 @@ private:
//------------------------------------------------------------------
void ScanContext(ExecutionContext &exe_ctx,
- lldb_private::Error &err) override;
+ lldb_private::Status &err) override;
bool AddArguments(ExecutionContext &exe_ctx, std::vector<lldb::addr_t> &args,
lldb::addr_t struct_address,
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
index 73d3751..065e5db 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
@@ -19,16 +19,16 @@
// C++ Includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/ExpressionSourceCode.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Host/Host.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
@@ -118,7 +118,7 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,
bool can_interpret = false; // should stay that way
- Error jit_error = parser.PrepareForExecution(
+ Status jit_error = parser.PrepareForExecution(
m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
can_interpret, eExecutionPolicyAlways);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
index 356e2e7..13f5657 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
@@ -25,18 +25,18 @@
#include "clang/AST/ASTContext.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRInterpreter.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include <map>
@@ -512,11 +512,9 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str,
break;
default:
encoding_flags = 0x0600; /* fall back to 0x0600, kCFStringEncodingASCII */
- if (log) {
- log->Format("Encountered an Objective-C constant string with unusual "
+ LLDB_LOG(log, "Encountered an Objective-C constant string with unusual "
"element size {0}",
- string_array->getElementByteSize());
- }
+ string_array->getElementByteSize());
}
Constant *encoding_arg = ConstantInt::get(i32_ty, encoding_flags, false);
Constant *isExternal_arg =
@@ -1265,7 +1263,7 @@ bool IRForTarget::MaterializeInitializer(uint8_t *data, Constant *initializer) {
lldb_private::Scalar scalar = int_initializer->getValue().zextOrTrunc(
llvm::NextPowerOf2(constant_size) * 8);
- lldb_private::Error get_data_error;
+ lldb_private::Status get_data_error;
if (!scalar.GetAsMemoryData(data, constant_size,
lldb_private::endian::InlHostByteOrder(),
get_data_error))
@@ -1855,9 +1853,9 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) {
if (!m_decl_map->GetStructInfo(num_elements, size, alignment))
return false;
- Function::arg_iterator iter(llvm_function.getArgumentList().begin());
+ Function::arg_iterator iter(llvm_function.arg_begin());
- if (iter == llvm_function.getArgumentList().end()) {
+ if (iter == llvm_function.arg_end()) {
m_error_stream.Printf("Internal error [IRForTarget]: Wrapper takes no "
"arguments (should take at least a struct pointer)");
@@ -1869,7 +1867,7 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) {
if (argument->getName().equals("this")) {
++iter;
- if (iter == llvm_function.getArgumentList().end()) {
+ if (iter == llvm_function.arg_end()) {
m_error_stream.Printf("Internal error [IRForTarget]: Wrapper takes only "
"'this' argument (should take a struct pointer "
"too)");
@@ -1881,7 +1879,7 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) {
} else if (argument->getName().equals("self")) {
++iter;
- if (iter == llvm_function.getArgumentList().end()) {
+ if (iter == llvm_function.arg_end()) {
m_error_stream.Printf("Internal error [IRForTarget]: Wrapper takes only "
"'self' argument (should take '_cmd' and a struct "
"pointer too)");
@@ -1899,7 +1897,7 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) {
++iter;
- if (iter == llvm_function.getArgumentList().end()) {
+ if (iter == llvm_function.arg_end()) {
m_error_stream.Printf("Internal error [IRForTarget]: Wrapper takes only "
"'self' and '_cmd' arguments (should take a struct "
"pointer too)");
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h
index 20b1d1a..93ce8aa 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h
@@ -11,11 +11,11 @@
#ifndef liblldb_IRForTarget_h_
#define liblldb_IRForTarget_h_
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
#include "lldb/lldb-public.h"
#include "llvm/Pass.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp
index 327b9df..538bd05 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.cpp
@@ -12,7 +12,7 @@
#include "GoParser.h"
#include "Plugins/ExpressionParser/Go/GoAST.h"
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Status.h"
#include "llvm/ADT/SmallString.h"
using namespace lldb_private;
@@ -860,7 +860,7 @@ llvm::StringRef GoParser::CopyString(llvm::StringRef s) {
return m_strings.insert(std::make_pair(s, 'x')).first->getKey();
}
-void GoParser::GetError(Error &error) {
+void GoParser::GetError(Status &error) {
llvm::StringRef want;
if (m_failed)
want =
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.h b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.h
index bd12855..9ed2ae2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoParser.h
@@ -82,7 +82,7 @@ public:
return m_lexer.BytesRemaining() == 0 && m_pos == m_tokens.size();
}
- void GetError(Error &error);
+ void GetError(Status &error);
private:
class Rule;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp
index a448da6..f4b8cfb 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp
@@ -26,14 +26,8 @@
// Project includes
#include "GoUserExpression.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataEncoder.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectRegister.h"
#include "lldb/Expression/DiagnosticManager.h"
@@ -49,6 +43,12 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallUserExpression.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "lldb/lldb-private.h"
#include "Plugins/ExpressionParser/Go/GoAST.h"
@@ -150,7 +150,7 @@ public:
CompilerType EvaluateType(const GoASTExpr *e);
- Error &error() { return m_error; }
+ Status &error() { return m_error; }
private:
std::nullptr_t NotImplemented(const GoASTExpr *e) {
@@ -163,7 +163,7 @@ private:
lldb::StackFrameSP m_frame;
GoParser m_parser;
DynamicValueType m_use_dynamic;
- Error m_error;
+ Status m_error;
llvm::StringRef m_package;
std::vector<std::unique_ptr<GoASTStmt>> m_statements;
};
@@ -254,7 +254,7 @@ GoUserExpression::DoExecute(DiagnosticManager &diagnostic_manager,
m_interpreter->set_use_dynamic(options.GetUseDynamic());
ValueObjectSP result_val_sp = m_interpreter->Evaluate(exe_ctx);
- Error err = m_interpreter->error();
+ Status err = m_interpreter->error();
m_interpreter.reset();
if (!result_val_sp) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
index 99caca9..d0ef688 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -13,13 +13,13 @@
#include "EmulationStateARM.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Interpreter/OptionValueArray.h"
#include "lldb/Interpreter/OptionValueDictionary.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
#include "Plugins/Process/Utility/ARMDefines.h"
#include "Plugins/Process/Utility/ARMUtils.h"
@@ -44,6 +44,563 @@ using namespace lldb_private;
//
//----------------------------------------------------------------------
+static bool GetARMDWARFRegisterInfo(unsigned reg_num, RegisterInfo &reg_info) {
+ ::memset(&reg_info, 0, sizeof(RegisterInfo));
+ ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
+
+ if (reg_num >= dwarf_q0 && reg_num <= dwarf_q15) {
+ reg_info.byte_size = 16;
+ reg_info.format = eFormatVectorOfUInt8;
+ reg_info.encoding = eEncodingVector;
+ }
+
+ if (reg_num >= dwarf_d0 && reg_num <= dwarf_d31) {
+ reg_info.byte_size = 8;
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ } else if (reg_num >= dwarf_s0 && reg_num <= dwarf_s31) {
+ reg_info.byte_size = 4;
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ } else if (reg_num >= dwarf_f0 && reg_num <= dwarf_f7) {
+ reg_info.byte_size = 12;
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ } else {
+ reg_info.byte_size = 4;
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+
+ reg_info.kinds[eRegisterKindDWARF] = reg_num;
+
+ switch (reg_num) {
+ case dwarf_r0:
+ reg_info.name = "r0";
+ break;
+ case dwarf_r1:
+ reg_info.name = "r1";
+ break;
+ case dwarf_r2:
+ reg_info.name = "r2";
+ break;
+ case dwarf_r3:
+ reg_info.name = "r3";
+ break;
+ case dwarf_r4:
+ reg_info.name = "r4";
+ break;
+ case dwarf_r5:
+ reg_info.name = "r5";
+ break;
+ case dwarf_r6:
+ reg_info.name = "r6";
+ break;
+ case dwarf_r7:
+ reg_info.name = "r7";
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ break;
+ case dwarf_r8:
+ reg_info.name = "r8";
+ break;
+ case dwarf_r9:
+ reg_info.name = "r9";
+ break;
+ case dwarf_r10:
+ reg_info.name = "r10";
+ break;
+ case dwarf_r11:
+ reg_info.name = "r11";
+ break;
+ case dwarf_r12:
+ reg_info.name = "r12";
+ break;
+ case dwarf_sp:
+ reg_info.name = "sp";
+ reg_info.alt_name = "r13";
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ break;
+ case dwarf_lr:
+ reg_info.name = "lr";
+ reg_info.alt_name = "r14";
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+ break;
+ case dwarf_pc:
+ reg_info.name = "pc";
+ reg_info.alt_name = "r15";
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ break;
+ case dwarf_cpsr:
+ reg_info.name = "cpsr";
+ reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ break;
+
+ case dwarf_s0:
+ reg_info.name = "s0";
+ break;
+ case dwarf_s1:
+ reg_info.name = "s1";
+ break;
+ case dwarf_s2:
+ reg_info.name = "s2";
+ break;
+ case dwarf_s3:
+ reg_info.name = "s3";
+ break;
+ case dwarf_s4:
+ reg_info.name = "s4";
+ break;
+ case dwarf_s5:
+ reg_info.name = "s5";
+ break;
+ case dwarf_s6:
+ reg_info.name = "s6";
+ break;
+ case dwarf_s7:
+ reg_info.name = "s7";
+ break;
+ case dwarf_s8:
+ reg_info.name = "s8";
+ break;
+ case dwarf_s9:
+ reg_info.name = "s9";
+ break;
+ case dwarf_s10:
+ reg_info.name = "s10";
+ break;
+ case dwarf_s11:
+ reg_info.name = "s11";
+ break;
+ case dwarf_s12:
+ reg_info.name = "s12";
+ break;
+ case dwarf_s13:
+ reg_info.name = "s13";
+ break;
+ case dwarf_s14:
+ reg_info.name = "s14";
+ break;
+ case dwarf_s15:
+ reg_info.name = "s15";
+ break;
+ case dwarf_s16:
+ reg_info.name = "s16";
+ break;
+ case dwarf_s17:
+ reg_info.name = "s17";
+ break;
+ case dwarf_s18:
+ reg_info.name = "s18";
+ break;
+ case dwarf_s19:
+ reg_info.name = "s19";
+ break;
+ case dwarf_s20:
+ reg_info.name = "s20";
+ break;
+ case dwarf_s21:
+ reg_info.name = "s21";
+ break;
+ case dwarf_s22:
+ reg_info.name = "s22";
+ break;
+ case dwarf_s23:
+ reg_info.name = "s23";
+ break;
+ case dwarf_s24:
+ reg_info.name = "s24";
+ break;
+ case dwarf_s25:
+ reg_info.name = "s25";
+ break;
+ case dwarf_s26:
+ reg_info.name = "s26";
+ break;
+ case dwarf_s27:
+ reg_info.name = "s27";
+ break;
+ case dwarf_s28:
+ reg_info.name = "s28";
+ break;
+ case dwarf_s29:
+ reg_info.name = "s29";
+ break;
+ case dwarf_s30:
+ reg_info.name = "s30";
+ break;
+ case dwarf_s31:
+ reg_info.name = "s31";
+ break;
+
+ // FPA Registers 0-7
+ case dwarf_f0:
+ reg_info.name = "f0";
+ break;
+ case dwarf_f1:
+ reg_info.name = "f1";
+ break;
+ case dwarf_f2:
+ reg_info.name = "f2";
+ break;
+ case dwarf_f3:
+ reg_info.name = "f3";
+ break;
+ case dwarf_f4:
+ reg_info.name = "f4";
+ break;
+ case dwarf_f5:
+ reg_info.name = "f5";
+ break;
+ case dwarf_f6:
+ reg_info.name = "f6";
+ break;
+ case dwarf_f7:
+ reg_info.name = "f7";
+ break;
+
+ // Intel wireless MMX general purpose registers 0 - 7
+ // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7)
+ case dwarf_wCGR0:
+ reg_info.name = "wCGR0/ACC0";
+ break;
+ case dwarf_wCGR1:
+ reg_info.name = "wCGR1/ACC1";
+ break;
+ case dwarf_wCGR2:
+ reg_info.name = "wCGR2/ACC2";
+ break;
+ case dwarf_wCGR3:
+ reg_info.name = "wCGR3/ACC3";
+ break;
+ case dwarf_wCGR4:
+ reg_info.name = "wCGR4/ACC4";
+ break;
+ case dwarf_wCGR5:
+ reg_info.name = "wCGR5/ACC5";
+ break;
+ case dwarf_wCGR6:
+ reg_info.name = "wCGR6/ACC6";
+ break;
+ case dwarf_wCGR7:
+ reg_info.name = "wCGR7/ACC7";
+ break;
+
+ // Intel wireless MMX data registers 0 - 15
+ case dwarf_wR0:
+ reg_info.name = "wR0";
+ break;
+ case dwarf_wR1:
+ reg_info.name = "wR1";
+ break;
+ case dwarf_wR2:
+ reg_info.name = "wR2";
+ break;
+ case dwarf_wR3:
+ reg_info.name = "wR3";
+ break;
+ case dwarf_wR4:
+ reg_info.name = "wR4";
+ break;
+ case dwarf_wR5:
+ reg_info.name = "wR5";
+ break;
+ case dwarf_wR6:
+ reg_info.name = "wR6";
+ break;
+ case dwarf_wR7:
+ reg_info.name = "wR7";
+ break;
+ case dwarf_wR8:
+ reg_info.name = "wR8";
+ break;
+ case dwarf_wR9:
+ reg_info.name = "wR9";
+ break;
+ case dwarf_wR10:
+ reg_info.name = "wR10";
+ break;
+ case dwarf_wR11:
+ reg_info.name = "wR11";
+ break;
+ case dwarf_wR12:
+ reg_info.name = "wR12";
+ break;
+ case dwarf_wR13:
+ reg_info.name = "wR13";
+ break;
+ case dwarf_wR14:
+ reg_info.name = "wR14";
+ break;
+ case dwarf_wR15:
+ reg_info.name = "wR15";
+ break;
+
+ case dwarf_spsr:
+ reg_info.name = "spsr";
+ break;
+ case dwarf_spsr_fiq:
+ reg_info.name = "spsr_fiq";
+ break;
+ case dwarf_spsr_irq:
+ reg_info.name = "spsr_irq";
+ break;
+ case dwarf_spsr_abt:
+ reg_info.name = "spsr_abt";
+ break;
+ case dwarf_spsr_und:
+ reg_info.name = "spsr_und";
+ break;
+ case dwarf_spsr_svc:
+ reg_info.name = "spsr_svc";
+ break;
+
+ case dwarf_r8_usr:
+ reg_info.name = "r8_usr";
+ break;
+ case dwarf_r9_usr:
+ reg_info.name = "r9_usr";
+ break;
+ case dwarf_r10_usr:
+ reg_info.name = "r10_usr";
+ break;
+ case dwarf_r11_usr:
+ reg_info.name = "r11_usr";
+ break;
+ case dwarf_r12_usr:
+ reg_info.name = "r12_usr";
+ break;
+ case dwarf_r13_usr:
+ reg_info.name = "r13_usr";
+ break;
+ case dwarf_r14_usr:
+ reg_info.name = "r14_usr";
+ break;
+ case dwarf_r8_fiq:
+ reg_info.name = "r8_fiq";
+ break;
+ case dwarf_r9_fiq:
+ reg_info.name = "r9_fiq";
+ break;
+ case dwarf_r10_fiq:
+ reg_info.name = "r10_fiq";
+ break;
+ case dwarf_r11_fiq:
+ reg_info.name = "r11_fiq";
+ break;
+ case dwarf_r12_fiq:
+ reg_info.name = "r12_fiq";
+ break;
+ case dwarf_r13_fiq:
+ reg_info.name = "r13_fiq";
+ break;
+ case dwarf_r14_fiq:
+ reg_info.name = "r14_fiq";
+ break;
+ case dwarf_r13_irq:
+ reg_info.name = "r13_irq";
+ break;
+ case dwarf_r14_irq:
+ reg_info.name = "r14_irq";
+ break;
+ case dwarf_r13_abt:
+ reg_info.name = "r13_abt";
+ break;
+ case dwarf_r14_abt:
+ reg_info.name = "r14_abt";
+ break;
+ case dwarf_r13_und:
+ reg_info.name = "r13_und";
+ break;
+ case dwarf_r14_und:
+ reg_info.name = "r14_und";
+ break;
+ case dwarf_r13_svc:
+ reg_info.name = "r13_svc";
+ break;
+ case dwarf_r14_svc:
+ reg_info.name = "r14_svc";
+ break;
+
+ // Intel wireless MMX control register in co-processor 0 - 7
+ case dwarf_wC0:
+ reg_info.name = "wC0";
+ break;
+ case dwarf_wC1:
+ reg_info.name = "wC1";
+ break;
+ case dwarf_wC2:
+ reg_info.name = "wC2";
+ break;
+ case dwarf_wC3:
+ reg_info.name = "wC3";
+ break;
+ case dwarf_wC4:
+ reg_info.name = "wC4";
+ break;
+ case dwarf_wC5:
+ reg_info.name = "wC5";
+ break;
+ case dwarf_wC6:
+ reg_info.name = "wC6";
+ break;
+ case dwarf_wC7:
+ reg_info.name = "wC7";
+ break;
+
+ // VFP-v3/Neon
+ case dwarf_d0:
+ reg_info.name = "d0";
+ break;
+ case dwarf_d1:
+ reg_info.name = "d1";
+ break;
+ case dwarf_d2:
+ reg_info.name = "d2";
+ break;
+ case dwarf_d3:
+ reg_info.name = "d3";
+ break;
+ case dwarf_d4:
+ reg_info.name = "d4";
+ break;
+ case dwarf_d5:
+ reg_info.name = "d5";
+ break;
+ case dwarf_d6:
+ reg_info.name = "d6";
+ break;
+ case dwarf_d7:
+ reg_info.name = "d7";
+ break;
+ case dwarf_d8:
+ reg_info.name = "d8";
+ break;
+ case dwarf_d9:
+ reg_info.name = "d9";
+ break;
+ case dwarf_d10:
+ reg_info.name = "d10";
+ break;
+ case dwarf_d11:
+ reg_info.name = "d11";
+ break;
+ case dwarf_d12:
+ reg_info.name = "d12";
+ break;
+ case dwarf_d13:
+ reg_info.name = "d13";
+ break;
+ case dwarf_d14:
+ reg_info.name = "d14";
+ break;
+ case dwarf_d15:
+ reg_info.name = "d15";
+ break;
+ case dwarf_d16:
+ reg_info.name = "d16";
+ break;
+ case dwarf_d17:
+ reg_info.name = "d17";
+ break;
+ case dwarf_d18:
+ reg_info.name = "d18";
+ break;
+ case dwarf_d19:
+ reg_info.name = "d19";
+ break;
+ case dwarf_d20:
+ reg_info.name = "d20";
+ break;
+ case dwarf_d21:
+ reg_info.name = "d21";
+ break;
+ case dwarf_d22:
+ reg_info.name = "d22";
+ break;
+ case dwarf_d23:
+ reg_info.name = "d23";
+ break;
+ case dwarf_d24:
+ reg_info.name = "d24";
+ break;
+ case dwarf_d25:
+ reg_info.name = "d25";
+ break;
+ case dwarf_d26:
+ reg_info.name = "d26";
+ break;
+ case dwarf_d27:
+ reg_info.name = "d27";
+ break;
+ case dwarf_d28:
+ reg_info.name = "d28";
+ break;
+ case dwarf_d29:
+ reg_info.name = "d29";
+ break;
+ case dwarf_d30:
+ reg_info.name = "d30";
+ break;
+ case dwarf_d31:
+ reg_info.name = "d31";
+ break;
+
+ // NEON 128-bit vector registers (overlays the d registers)
+ case dwarf_q0:
+ reg_info.name = "q0";
+ break;
+ case dwarf_q1:
+ reg_info.name = "q1";
+ break;
+ case dwarf_q2:
+ reg_info.name = "q2";
+ break;
+ case dwarf_q3:
+ reg_info.name = "q3";
+ break;
+ case dwarf_q4:
+ reg_info.name = "q4";
+ break;
+ case dwarf_q5:
+ reg_info.name = "q5";
+ break;
+ case dwarf_q6:
+ reg_info.name = "q6";
+ break;
+ case dwarf_q7:
+ reg_info.name = "q7";
+ break;
+ case dwarf_q8:
+ reg_info.name = "q8";
+ break;
+ case dwarf_q9:
+ reg_info.name = "q9";
+ break;
+ case dwarf_q10:
+ reg_info.name = "q10";
+ break;
+ case dwarf_q11:
+ reg_info.name = "q11";
+ break;
+ case dwarf_q12:
+ reg_info.name = "q12";
+ break;
+ case dwarf_q13:
+ reg_info.name = "q13";
+ break;
+ case dwarf_q14:
+ reg_info.name = "q14";
+ break;
+ case dwarf_q15:
+ reg_info.name = "q15";
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
// A8.6.50
// Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition.
static uint32_t CountITSize(uint32_t ITMask) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
index 1bfc4cb..fb1867c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
@@ -11,9 +11,9 @@
#define lldb_EmulateInstructionARM_h_
#include "Plugins/Process/Utility/ARMDefines.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/EmulateInstruction.h"
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
index 9ceeb76..5e90965 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
@@ -66,7 +66,7 @@ bool EmulationStateARM::LoadPseudoRegistersFromFrame(StackFrame &frame) {
bool EmulationStateARM::StorePseudoRegisterValue(uint32_t reg_num,
uint64_t value) {
- if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
+ if (reg_num <= dwarf_cpsr)
m_gpr[reg_num - dwarf_r0] = (uint32_t)value;
else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) {
uint32_t idx = reg_num - dwarf_s0;
@@ -89,7 +89,7 @@ uint64_t EmulationStateARM::ReadPseudoRegisterValue(uint32_t reg_num,
uint64_t value = 0;
success = true;
- if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
+ if (reg_num <= dwarf_cpsr)
value = m_gpr[reg_num - dwarf_r0];
else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31)) {
uint32_t idx = reg_num - dwarf_s0;
@@ -192,15 +192,18 @@ size_t EmulationStateARM::WritePseudoMemory(
EmulationStateARM *pseudo_state = (EmulationStateARM *)baton;
if (length <= 4) {
- uint32_t value = *((const uint32_t *)dst);
+ uint32_t value;
+ memcpy (&value, dst, sizeof (uint32_t));
if (endian::InlHostByteOrder() == lldb::eByteOrderBig)
value = llvm::ByteSwap_32(value);
pseudo_state->StoreToPseudoAddress(addr, value);
return length;
} else if (length == 8) {
- uint32_t value1 = ((const uint32_t *)dst)[0];
- uint32_t value2 = ((const uint32_t *)dst)[1];
+ uint32_t value1;
+ uint32_t value2;
+ memcpy (&value1, dst, sizeof (uint32_t));
+ memcpy (&value2, (uint8_t *) dst + sizeof (uint32_t), sizeof (uint32_t));
if (endian::InlHostByteOrder() == lldb::eByteOrderBig) {
value1 = llvm::ByteSwap_32(value1);
value2 = llvm::ByteSwap_32(value2);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
index 43f2309..54dd237 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
@@ -13,10 +13,11 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Core/RegisterValue.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
#include "Plugins/Process/Utility/ARMDefines.h"
#include "Plugins/Process/Utility/ARMUtils.h"
@@ -845,7 +846,7 @@ bool EmulateInstructionARM64::EmulateLDPSTP(const uint32_t opcode) {
Context context_t2;
uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
- Error error;
+ Status error;
switch (memop) {
case MemOp_STORE: {
@@ -991,7 +992,7 @@ bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
return false;
}
- Error error;
+ Status error;
bool success = false;
uint64_t address;
uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h
index 1da3304..253bb93 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h
@@ -16,8 +16,8 @@
// Project includes
#include "Plugins/Process/Utility/ARMDefines.h"
#include "lldb/Core/EmulateInstruction.h"
-#include "lldb/Core/Error.h"
#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Utility/Status.h"
class EmulateInstructionARM64 : public lldb_private::EmulateInstruction {
public:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp b/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
index 8cc34c1..4d1d89a 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
@@ -1,5 +1,4 @@
-//===-- EmulateInstructionMIPS.cpp -------------------------------*- C++
-//-*-===//
+//===-- EmulateInstructionMIPS.cpp -------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,13 +13,14 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Opcode.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Core/RegisterValue.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Stream.h"
#include "llvm-c/Disassembler.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -63,10 +63,10 @@ EmulateInstructionMIPS::EmulateInstructionMIPS(
const lldb_private::ArchSpec &arch)
: EmulateInstruction(arch) {
/* Create instance of llvm::MCDisassembler */
- std::string Error;
+ std::string Status;
llvm::Triple triple = arch.GetTriple();
const llvm::Target *target =
- llvm::TargetRegistry::lookupTarget(triple.getTriple(), Error);
+ llvm::TargetRegistry::lookupTarget(triple.getTriple(), Status);
/*
* If we fail to get the target then we haven't registered it. The
@@ -83,7 +83,7 @@ EmulateInstructionMIPS::EmulateInstructionMIPS(
LLVMInitializeMipsAsmPrinter();
LLVMInitializeMipsTargetMC();
LLVMInitializeMipsDisassembler();
- target = llvm::TargetRegistry::lookupTarget(triple.getTriple(), Error);
+ target = llvm::TargetRegistry::lookupTarget(triple.getTriple(), Status);
}
#endif
@@ -1019,7 +1019,7 @@ bool EmulateInstructionMIPS::SetInstruction(const Opcode &insn_opcode,
if (EmulateInstruction::SetInstruction(insn_opcode, inst_addr, target)) {
if (inst_addr.GetAddressClass() == eAddressClassCodeAlternateISA) {
- Error error;
+ Status error;
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
/*
@@ -1297,7 +1297,7 @@ bool EmulateInstructionMIPS::Emulate_SW(llvm::MCInst &insn) {
context.SetRegisterToRegisterPlusOffset(reg_info_src, reg_info_base, 0);
uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
- Error error;
+ Status error;
if (!ReadRegister(&reg_info_base, data_src))
return false;
@@ -1563,7 +1563,7 @@ bool EmulateInstructionMIPS::Emulate_SWSP(llvm::MCInst &insn) {
context.SetRegisterToRegisterPlusOffset(reg_info_src, reg_info_base, 0);
uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
- Error error;
+ Status error;
if (!ReadRegister(&reg_info_base, data_src))
return false;
@@ -1646,7 +1646,7 @@ bool EmulateInstructionMIPS::Emulate_SWM16_32(llvm::MCInst &insn) {
context.SetRegisterToRegisterPlusOffset(reg_info_src, reg_info_base, 0);
uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
- Error error;
+ Status error;
if (!ReadRegister(&reg_info_base, data_src))
return false;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h b/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
index 82c6a0a..8d6e0be 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h
@@ -22,8 +22,8 @@ class MCInst;
}
#include "lldb/Core/EmulateInstruction.h"
-#include "lldb/Core/Error.h"
#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Utility/Status.h"
class EmulateInstructionMIPS : public lldb_private::EmulateInstruction {
public:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
index c054760..1e6d987 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
@@ -1,5 +1,4 @@
-//===-- EmulateInstructionMIPS64.cpp -------------------------------*- C++
-//-*-===//
+//===-- EmulateInstructionMIPS64.cpp -----------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,13 +13,14 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Opcode.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Core/RegisterValue.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Stream.h"
#include "llvm-c/Disassembler.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -63,10 +63,10 @@ EmulateInstructionMIPS64::EmulateInstructionMIPS64(
const lldb_private::ArchSpec &arch)
: EmulateInstruction(arch) {
/* Create instance of llvm::MCDisassembler */
- std::string Error;
+ std::string Status;
llvm::Triple triple = arch.GetTriple();
const llvm::Target *target =
- llvm::TargetRegistry::lookupTarget(triple.getTriple(), Error);
+ llvm::TargetRegistry::lookupTarget(triple.getTriple(), Status);
/*
* If we fail to get the target then we haven't registered it. The
@@ -83,7 +83,7 @@ EmulateInstructionMIPS64::EmulateInstructionMIPS64(
LLVMInitializeMipsAsmPrinter();
LLVMInitializeMipsTargetMC();
LLVMInitializeMipsDisassembler();
- target = llvm::TargetRegistry::lookupTarget(triple.getTriple(), Error);
+ target = llvm::TargetRegistry::lookupTarget(triple.getTriple(), Status);
}
#endif
@@ -1141,7 +1141,7 @@ bool EmulateInstructionMIPS64::Emulate_SD(llvm::MCInst &insn) {
context.SetRegisterToRegisterPlusOffset(reg_info_src, reg_info_base, 0);
uint8_t buffer[RegisterValue::kMaxRegisterByteSize];
- Error error;
+ Status error;
if (!ReadRegister(&reg_info_base, data_src))
return false;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h b/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
index 5543615..c2433d5 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
@@ -15,8 +15,8 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/EmulateInstruction.h"
-#include "lldb/Core/Error.h"
#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Utility/Status.h"
namespace llvm {
class MCDisassembler;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp
index db626b0..9a6e39b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp
@@ -1,4 +1,4 @@
-//===-- AddressSanitizerRuntime.cpp -----------------------------*- C++ -*-===//
+//===-- ASanRuntime.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,15 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#include "AddressSanitizerRuntime.h"
+#include "ASanRuntime.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/UserExpression.h"
@@ -25,6 +23,8 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
#include "llvm/ADT/StringSwitch.h"
@@ -134,7 +134,7 @@ StructuredData::ObjectSP AddressSanitizerRuntime::RetrieveReportData() {
ValueObjectSP return_value_sp;
ExecutionContext exe_ctx;
- Error eval_error;
+ Status eval_error;
frame_sp->CalculateExecutionContext(exe_ctx);
ExpressionResults result = UserExpression::Evaluate(
exe_ctx, options, address_sanitizer_retrieve_report_data_command, "",
@@ -171,7 +171,7 @@ StructuredData::ObjectSP AddressSanitizerRuntime::RetrieveReportData() {
return_value_sp->GetValueForExpressionPath(".description")
->GetValueAsUnsigned(0);
std::string description;
- Error error;
+ Status error;
process_sp->ReadCStringFromMemory(description_ptr, description, error);
StructuredData::Dictionary *dict = new StructuredData::Dictionary();
@@ -247,12 +247,16 @@ bool AddressSanitizerRuntime::NotifyBreakpointHit(
AddressSanitizerRuntime *const instance =
static_cast<AddressSanitizerRuntime *>(baton);
+ ProcessSP process_sp = instance->GetProcessSP();
+
+ if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
+ return false;
+
StructuredData::ObjectSP report = instance->RetrieveReportData();
std::string description;
if (report) {
description = instance->FormatDescription(report);
}
- ProcessSP process_sp = instance->GetProcessSP();
// Make sure this is the right process
if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) {
ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
@@ -308,13 +312,6 @@ void AddressSanitizerRuntime::Activate() {
breakpoint->SetBreakpointKind("address-sanitizer-report");
SetBreakpointID(breakpoint->GetID());
- StreamFileSP stream_sp(process_sp->GetTarget().GetDebugger().GetOutputFile());
- if (stream_sp) {
- stream_sp->Printf("AddressSanitizer debugger support is active. Memory "
- "error breakpoint has been installed and you can now use "
- "the 'memory history' command.\n");
- }
-
SetActive(true);
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h
index 9fd21c0..e9af5a6 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h
@@ -14,9 +14,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StructuredData.h"
#include "lldb/Target/InstrumentationRuntime.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt
new file mode 100644
index 0000000..dc7464f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeASan PLUGIN
+ ASanRuntime.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbExpression
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt
new file mode 100644
index 0000000..440b176
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeMainThreadChecker PLUGIN
+ MainThreadCheckerRuntime.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbExpression
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp
new file mode 100644
index 0000000..eb23841
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp
@@ -0,0 +1,276 @@
+//===-- MainThreadCheckerRuntime.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MainThreadCheckerRuntime.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "Plugins/Process/Utility/HistoryThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MainThreadCheckerRuntime::~MainThreadCheckerRuntime() {
+ Deactivate();
+}
+
+lldb::InstrumentationRuntimeSP
+MainThreadCheckerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) {
+ return InstrumentationRuntimeSP(new MainThreadCheckerRuntime(process_sp));
+}
+
+void MainThreadCheckerRuntime::Initialize() {
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(), "MainThreadChecker instrumentation runtime plugin.",
+ CreateInstance, GetTypeStatic);
+}
+
+void MainThreadCheckerRuntime::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString MainThreadCheckerRuntime::GetPluginNameStatic() {
+ return ConstString("MainThreadChecker");
+}
+
+lldb::InstrumentationRuntimeType MainThreadCheckerRuntime::GetTypeStatic() {
+ return eInstrumentationRuntimeTypeMainThreadChecker;
+}
+
+const RegularExpression &
+MainThreadCheckerRuntime::GetPatternForRuntimeLibrary() {
+ static RegularExpression regex(llvm::StringRef("libMainThreadChecker.dylib"));
+ return regex;
+}
+
+bool MainThreadCheckerRuntime::CheckIfRuntimeIsValid(
+ const lldb::ModuleSP module_sp) {
+ static ConstString test_sym("__main_thread_checker_on_report");
+ const Symbol *symbol =
+ module_sp->FindFirstSymbolWithNameAndType(test_sym, lldb::eSymbolTypeAny);
+ return symbol != nullptr;
+}
+
+StructuredData::ObjectSP
+MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) {
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return StructuredData::ObjectSP();
+
+ ThreadSP thread_sp = exe_ctx_ref.GetThreadSP();
+ StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+ ModuleSP runtime_module_sp = GetRuntimeModuleSP();
+ Target &target = process_sp->GetTarget();
+
+ if (!frame_sp)
+ return StructuredData::ObjectSP();
+
+ RegisterContextSP regctx_sp = frame_sp->GetRegisterContext();
+ if (!regctx_sp)
+ return StructuredData::ObjectSP();
+
+ const RegisterInfo *reginfo = regctx_sp->GetRegisterInfoByName("arg1");
+ if (!reginfo)
+ return StructuredData::ObjectSP();
+
+ uint64_t apiname_ptr = regctx_sp->ReadRegisterAsUnsigned(reginfo, 0);
+ if (!apiname_ptr)
+ return StructuredData::ObjectSP();
+
+ std::string apiName = "";
+ Status read_error;
+ target.ReadCStringFromMemory(apiname_ptr, apiName, read_error);
+ if (read_error.Fail())
+ return StructuredData::ObjectSP();
+
+ std::string className = "";
+ std::string selector = "";
+ if (apiName.substr(0, 2) == "-[") {
+ size_t spacePos = apiName.find(" ");
+ if (spacePos != std::string::npos) {
+ className = apiName.substr(2, spacePos - 2);
+ selector = apiName.substr(spacePos + 1, apiName.length() - spacePos - 2);
+ }
+ }
+
+ // Gather the PCs of the user frames in the backtrace.
+ StructuredData::Array *trace = new StructuredData::Array();
+ auto trace_sp = StructuredData::ObjectSP(trace);
+ StackFrameSP responsible_frame;
+ for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) {
+ StackFrameSP frame = thread_sp->GetStackFrameAtIndex(I);
+ Address addr = frame->GetFrameCodeAddress();
+ if (addr.GetModule() == runtime_module_sp) // Skip PCs from the runtime.
+ continue;
+
+ // The first non-runtime frame is responsible for the bug.
+ if (!responsible_frame)
+ responsible_frame = frame;
+
+ // First frame in stacktrace should point to a real PC, not return address.
+ if (I != 0 && trace->GetSize() == 0) {
+ addr.Slide(-1);
+ }
+
+ lldb::addr_t PC = addr.GetLoadAddress(&target);
+ trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC)));
+ }
+
+ auto *d = new StructuredData::Dictionary();
+ auto dict_sp = StructuredData::ObjectSP(d);
+ d->AddStringItem("instrumentation_class", "MainThreadChecker");
+ d->AddStringItem("api_name", apiName);
+ d->AddStringItem("class_name", className);
+ d->AddStringItem("selector", selector);
+ d->AddStringItem("description",
+ apiName + " must be used from main thread only");
+ d->AddIntegerItem("tid", thread_sp->GetIndexID());
+ d->AddItem("trace", trace_sp);
+ return dict_sp;
+}
+
+bool MainThreadCheckerRuntime::NotifyBreakpointHit(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_id) {
+ assert(baton && "null baton");
+ if (!baton)
+ return false; //< false => resume execution.
+
+ MainThreadCheckerRuntime *const instance =
+ static_cast<MainThreadCheckerRuntime *>(baton);
+
+ ProcessSP process_sp = instance->GetProcessSP();
+ ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
+ if (!process_sp || !thread_sp ||
+ process_sp != context->exe_ctx_ref.GetProcessSP())
+ return false;
+
+ if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
+ return false;
+
+ StructuredData::ObjectSP report =
+ instance->RetrieveReportData(context->exe_ctx_ref);
+
+ if (report) {
+ std::string description = report->GetAsDictionary()
+ ->GetValueForKey("description")
+ ->GetAsString()
+ ->GetValue();
+ thread_sp->SetStopInfo(
+ InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
+ *thread_sp, description, report));
+ return true;
+ }
+
+ return false;
+}
+
+void MainThreadCheckerRuntime::Activate() {
+ if (IsActive())
+ return;
+
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return;
+
+ ModuleSP runtime_module_sp = GetRuntimeModuleSP();
+
+ ConstString symbol_name("__main_thread_checker_on_report");
+ const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType(
+ symbol_name, eSymbolTypeCode);
+
+ if (symbol == nullptr)
+ return;
+
+ if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
+ return;
+
+ Target &target = process_sp->GetTarget();
+ addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
+
+ if (symbol_address == LLDB_INVALID_ADDRESS)
+ return;
+
+ Breakpoint *breakpoint =
+ process_sp->GetTarget()
+ .CreateBreakpoint(symbol_address, /*internal=*/true,
+ /*hardware=*/false)
+ .get();
+ breakpoint->SetCallback(MainThreadCheckerRuntime::NotifyBreakpointHit, this,
+ true);
+ breakpoint->SetBreakpointKind("main-thread-checker-report");
+ SetBreakpointID(breakpoint->GetID());
+
+ SetActive(true);
+}
+
+void MainThreadCheckerRuntime::Deactivate() {
+ SetActive(false);
+
+ auto BID = GetBreakpointID();
+ if (BID == LLDB_INVALID_BREAK_ID)
+ return;
+
+ if (ProcessSP process_sp = GetProcessSP()) {
+ process_sp->GetTarget().RemoveBreakpointByID(BID);
+ SetBreakpointID(LLDB_INVALID_BREAK_ID);
+ }
+}
+
+lldb::ThreadCollectionSP
+MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo(
+ StructuredData::ObjectSP info) {
+ ThreadCollectionSP threads;
+ threads.reset(new ThreadCollection());
+
+ ProcessSP process_sp = GetProcessSP();
+
+ if (info->GetObjectForDotSeparatedPath("instrumentation_class")
+ ->GetStringValue() != "MainThreadChecker")
+ return threads;
+
+ std::vector<lldb::addr_t> PCs;
+ auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray();
+ trace->ForEach([&PCs](StructuredData::Object *PC) -> bool {
+ PCs.push_back(PC->GetAsInteger()->GetValue());
+ return true;
+ });
+
+ if (PCs.empty())
+ return threads;
+
+ StructuredData::ObjectSP thread_id_obj =
+ info->GetObjectForDotSeparatedPath("tid");
+ tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;
+
+ uint32_t stop_id = 0;
+ bool stop_id_is_valid = false;
+ HistoryThread *history_thread =
+ new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid);
+ ThreadSP new_thread_sp(history_thread);
+
+ // Save this in the Process' ExtendedThreadList so a strong pointer
+ // retains the object
+ process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
+ threads->AddThread(new_thread_sp);
+
+ return threads;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h
new file mode 100644
index 0000000..516d9fe
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h
@@ -0,0 +1,68 @@
+//===-- MainThreadCheckerRuntime.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MainThreadCheckerRuntime_h_
+#define liblldb_MainThreadCheckerRuntime_h_
+
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+ class MainThreadCheckerRuntime : public lldb_private::InstrumentationRuntime {
+ public:
+ ~MainThreadCheckerRuntime() override;
+
+ static lldb::InstrumentationRuntimeSP
+ CreateInstance(const lldb::ProcessSP &process_sp);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static lldb_private::ConstString GetPluginNameStatic();
+
+ static lldb::InstrumentationRuntimeType GetTypeStatic();
+
+ lldb_private::ConstString GetPluginName() override {
+ return GetPluginNameStatic();
+ }
+
+ virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); }
+
+ uint32_t GetPluginVersion() override { return 1; }
+
+ lldb::ThreadCollectionSP
+ GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override;
+
+ private:
+ MainThreadCheckerRuntime(const lldb::ProcessSP &process_sp)
+ : lldb_private::InstrumentationRuntime(process_sp) {}
+
+ const RegularExpression &GetPatternForRuntimeLibrary() override;
+
+ bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
+
+ void Activate() override;
+
+ void Deactivate();
+
+ static bool NotifyBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref);
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_MainThreadCheckerRuntime_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt
new file mode 100644
index 0000000..4dcd341
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeTSan PLUGIN
+ TSanRuntime.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbExpression
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ lldbPluginProcessUtility
+ )
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp
index d8a46e5..cf9ba60 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp
@@ -1,4 +1,4 @@
-//===-- ThreadSanitizerRuntime.cpp ------------------------------*- C++ -*-===//
+//===-- TSanRuntime.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "ThreadSanitizerRuntime.h"
+#include "TSanRuntime.h"
#include "Plugins/Process/Utility/HistoryThread.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
@@ -15,8 +15,6 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/UserExpression.h"
@@ -30,6 +28,8 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -85,6 +85,10 @@ extern "C"
int *running, const char **name, int *parent_tid,
void **trace, unsigned long trace_size);
int __tsan_get_report_unique_tid(void *report, unsigned long idx, int *tid);
+
+ // TODO: dlsym won't work on Windows.
+ void *dlsym(void* handle, const char* symbol);
+ int (*ptr__tsan_get_report_loc_object_type)(void *report, unsigned long idx, const char **object_type);
}
const int REPORT_TRACE_SIZE = 128;
@@ -125,6 +129,7 @@ struct data {
int fd;
int suppressable;
void *trace[REPORT_TRACE_SIZE];
+ const char *object_type;
} locs[REPORT_ARRAY_SIZE];
int mutex_count;
@@ -158,6 +163,8 @@ struct data {
const char *thread_sanitizer_retrieve_report_data_command = R"(
data t = {0};
+ptr__tsan_get_report_loc_object_type = (typeof(ptr__tsan_get_report_loc_object_type))(void *)dlsym((void*)-2 /*RTLD_DEFAULT*/, "__tsan_get_report_loc_object_type");
+
t.report = __tsan_get_current_report();
__tsan_get_report_data(t.report, &t.description, &t.report_count, &t.stack_count, &t.mop_count, &t.loc_count, &t.mutex_count, &t.thread_count, &t.unique_tid_count, t.sleep_trace, REPORT_TRACE_SIZE);
@@ -177,6 +184,8 @@ if (t.loc_count > REPORT_ARRAY_SIZE) t.loc_count = REPORT_ARRAY_SIZE;
for (int i = 0; i < t.loc_count; i++) {
t.locs[i].idx = i;
__tsan_get_report_loc(t.report, i, &t.locs[i].type, &t.locs[i].addr, &t.locs[i].start, &t.locs[i].size, &t.locs[i].tid, &t.locs[i].fd, &t.locs[i].suppressable, t.locs[i].trace, REPORT_TRACE_SIZE);
+ if (ptr__tsan_get_report_loc_object_type)
+ ptr__tsan_get_report_loc_object_type(t.report, i, &t.locs[i].object_type);
}
if (t.mutex_count > REPORT_ARRAY_SIZE) t.mutex_count = REPORT_ARRAY_SIZE;
@@ -247,7 +256,7 @@ static std::string RetrieveString(ValueObjectSP return_value_sp,
return_value_sp->GetValueForExpressionPath(expression_path.c_str())
->GetValueAsUnsigned(0);
std::string str;
- Error error;
+ Status error;
process_sp->ReadCStringFromMemory(ptr, str, error);
return str;
}
@@ -316,7 +325,7 @@ ThreadSanitizerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) {
ValueObjectSP main_value;
ExecutionContext exe_ctx;
- Error eval_error;
+ Status eval_error;
frame_sp->CalculateExecutionContext(exe_ctx);
ExpressionResults result = UserExpression::Evaluate(
exe_ctx, options, thread_sanitizer_retrieve_report_data_command, "",
@@ -409,6 +418,8 @@ ThreadSanitizerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) {
o->GetValueForExpressionPath(".suppressable")
->GetValueAsUnsigned(0));
dict->AddItem("trace", StructuredData::ObjectSP(CreateStackTrace(o)));
+ dict->AddStringItem("object_type",
+ RetrieveString(o, process_sp, ".object_type"));
});
dict->AddItem("locs", StructuredData::ObjectSP(locs));
@@ -511,6 +522,10 @@ ThreadSanitizerRuntime::FormatDescription(StructuredData::ObjectSP report) {
return "Overwrite of errno in a signal handler";
} else if (description == "lock-order-inversion") {
return "Lock order inversion (potential deadlock)";
+ } else if (description == "external-race") {
+ return "Race on a library object";
+ } else if (description == "swift-access-race") {
+ return "Swift access race";
}
// for unknown report codes just show the code
@@ -568,27 +583,31 @@ static void GetSymbolDeclarationFromAddress(ProcessSP process_sp, addr_t addr,
}
addr_t ThreadSanitizerRuntime::GetFirstNonInternalFramePc(
- StructuredData::ObjectSP trace) {
+ StructuredData::ObjectSP trace, bool skip_one_frame) {
ProcessSP process_sp = GetProcessSP();
ModuleSP runtime_module_sp = GetRuntimeModuleSP();
- addr_t result = 0;
- trace->GetAsArray()->ForEach([process_sp, runtime_module_sp,
- &result](StructuredData::Object *o) -> bool {
- addr_t addr = o->GetIntegerValue();
+ StructuredData::Array *trace_array = trace->GetAsArray();
+ for (size_t i = 0; i < trace_array->GetSize(); i++) {
+ if (skip_one_frame && i == 0)
+ continue;
+
+ addr_t addr;
+ if (!trace_array->GetItemAtIndexAsInteger(i, addr))
+ continue;
+
lldb_private::Address so_addr;
if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(
addr, so_addr))
- return true;
+ continue;
if (so_addr.GetModule() == runtime_module_sp)
- return true;
+ continue;
- result = addr;
- return false;
- });
+ return addr;
+ }
- return result;
+ return 0;
}
std::string
@@ -599,6 +618,10 @@ ThreadSanitizerRuntime::GenerateSummary(StructuredData::ObjectSP report) {
->GetValueForKey("description")
->GetAsString()
->GetValue();
+ bool skip_one_frame =
+ report->GetObjectForDotSeparatedPath("issue_type")->GetStringValue() ==
+ "external-race";
+
addr_t pc = 0;
if (report->GetAsDictionary()
->GetValueForKey("mops")
@@ -609,7 +632,8 @@ ThreadSanitizerRuntime::GenerateSummary(StructuredData::ObjectSP report) {
->GetAsArray()
->GetItemAtIndex(0)
->GetAsDictionary()
- ->GetValueForKey("trace"));
+ ->GetValueForKey("trace"),
+ skip_one_frame);
if (report->GetAsDictionary()
->GetValueForKey("stacks")
@@ -620,7 +644,8 @@ ThreadSanitizerRuntime::GenerateSummary(StructuredData::ObjectSP report) {
->GetAsArray()
->GetItemAtIndex(0)
->GetAsDictionary()
- ->GetValueForKey("trace"));
+ ->GetValueForKey("trace"),
+ skip_one_frame);
if (pc != 0) {
summary = summary + " in " + GetSymbolNameFromAddress(process_sp, pc);
@@ -634,6 +659,13 @@ ThreadSanitizerRuntime::GenerateSummary(StructuredData::ObjectSP report) {
->GetValueForKey("locs")
->GetAsArray()
->GetItemAtIndex(0);
+ std::string object_type = loc->GetAsDictionary()
+ ->GetValueForKey("object_type")
+ ->GetAsString()
+ ->GetValue();
+ if (!object_type.empty()) {
+ summary = "Race on " + object_type + " object";
+ }
addr_t addr = loc->GetAsDictionary()
->GetValueForKey("address")
->GetAsInteger()
@@ -726,8 +758,17 @@ std::string ThreadSanitizerRuntime::GetLocationDescription(
->GetValueForKey("size")
->GetAsInteger()
->GetValue();
- result =
- Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr);
+ std::string object_type = loc->GetAsDictionary()
+ ->GetValueForKey("object_type")
+ ->GetAsString()
+ ->GetValue();
+ if (!object_type.empty()) {
+ result = Sprintf("Location is a %ld-byte %s object at 0x%llx", size,
+ object_type.c_str(), addr);
+ } else {
+ result =
+ Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr);
+ }
} else if (type == "stack") {
int tid = loc->GetAsDictionary()
->GetValueForKey("thread_id")
@@ -762,6 +803,11 @@ bool ThreadSanitizerRuntime::NotifyBreakpointHit(
ThreadSanitizerRuntime *const instance =
static_cast<ThreadSanitizerRuntime *>(baton);
+ ProcessSP process_sp = instance->GetProcessSP();
+
+ if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
+ return false;
+
StructuredData::ObjectSP report =
instance->RetrieveReportData(context->exe_ctx_ref);
std::string stop_reason_description;
@@ -810,7 +856,6 @@ bool ThreadSanitizerRuntime::NotifyBreakpointHit(
all_addresses_are_same);
}
- ProcessSP process_sp = instance->GetProcessSP();
// Make sure this is the right process
if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) {
ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
@@ -880,11 +925,6 @@ void ThreadSanitizerRuntime::Activate() {
breakpoint->SetBreakpointKind("thread-sanitizer-report");
SetBreakpointID(breakpoint->GetID());
- StreamFileSP stream_sp(process_sp->GetTarget().GetDebugger().GetOutputFile());
- if (stream_sp) {
- stream_sp->Printf("ThreadSanitizer debugger support is active.\n");
- }
-
SetActive(true);
}
@@ -920,9 +960,18 @@ static std::string GenerateThreadName(const std::string &path,
addr_string = "";
}
- result = Sprintf("%s%s of size %d%s by thread %d",
- is_atomic ? "atomic " : "", is_write ? "write" : "read",
- size, addr_string.c_str(), thread_id);
+ if (main_info->GetObjectForDotSeparatedPath("issue_type")
+ ->GetStringValue() == "external-race") {
+ result = Sprintf("%s access by thread %d",
+ is_write ? "mutating" : "read-only", thread_id);
+ } else if (main_info->GetObjectForDotSeparatedPath("issue_type")
+ ->GetStringValue() == "swift-access-race") {
+ result = Sprintf("modifying access by thread %d", thread_id);
+ } else {
+ result = Sprintf("%s%s of size %d%s by thread %d",
+ is_atomic ? "atomic " : "", is_write ? "write" : "read",
+ size, addr_string.c_str(), thread_id);
+ }
}
if (path == "threads") {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h
index 9b07ca6..dc737d2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h
@@ -14,9 +14,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StructuredData.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
@@ -77,7 +77,8 @@ private:
std::string &global_name,
std::string &filename, uint32_t &line);
- lldb::addr_t GetFirstNonInternalFramePc(StructuredData::ObjectSP trace);
+ lldb::addr_t GetFirstNonInternalFramePc(StructuredData::ObjectSP trace,
+ bool skip_one_frame = false);
};
} // namespace lldb_private
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt
new file mode 100644
index 0000000..984bf86
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeUBSan PLUGIN
+ UBSanRuntime.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbExpression
+ lldbInterpreter
+ lldbSymbol
+ lldbTarget
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp
new file mode 100644
index 0000000..28c28e4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp
@@ -0,0 +1,343 @@
+//===-- UBSanRuntime.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UBSanRuntime.h"
+
+#include "Plugins/Process/Utility/HistoryThread.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/UserExpression.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include <ctype.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+UndefinedBehaviorSanitizerRuntime::~UndefinedBehaviorSanitizerRuntime() {
+ Deactivate();
+}
+
+lldb::InstrumentationRuntimeSP
+UndefinedBehaviorSanitizerRuntime::CreateInstance(
+ const lldb::ProcessSP &process_sp) {
+ return InstrumentationRuntimeSP(
+ new UndefinedBehaviorSanitizerRuntime(process_sp));
+}
+
+void UndefinedBehaviorSanitizerRuntime::Initialize() {
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(),
+ "UndefinedBehaviorSanitizer instrumentation runtime plugin.",
+ CreateInstance, GetTypeStatic);
+}
+
+void UndefinedBehaviorSanitizerRuntime::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString
+UndefinedBehaviorSanitizerRuntime::GetPluginNameStatic() {
+ return ConstString("UndefinedBehaviorSanitizer");
+}
+
+lldb::InstrumentationRuntimeType
+UndefinedBehaviorSanitizerRuntime::GetTypeStatic() {
+ return eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer;
+}
+
+static const char *ub_sanitizer_retrieve_report_data_prefix = R"(
+extern "C" {
+void
+__ubsan_get_current_report_data(const char **OutIssueKind,
+ const char **OutMessage, const char **OutFilename, unsigned *OutLine,
+ unsigned *OutCol, char **OutMemoryAddr);
+}
+
+struct data {
+ const char *issue_kind;
+ const char *message;
+ const char *filename;
+ unsigned line;
+ unsigned col;
+ char *memory_addr;
+};
+)";
+
+static const char *ub_sanitizer_retrieve_report_data_command = R"(
+data t;
+__ubsan_get_current_report_data(&t.issue_kind, &t.message, &t.filename, &t.line,
+ &t.col, &t.memory_addr);
+t;
+)";
+
+static addr_t RetrieveUnsigned(ValueObjectSP return_value_sp,
+ ProcessSP process_sp,
+ const std::string &expression_path) {
+ return return_value_sp->GetValueForExpressionPath(expression_path.c_str())
+ ->GetValueAsUnsigned(0);
+}
+
+static std::string RetrieveString(ValueObjectSP return_value_sp,
+ ProcessSP process_sp,
+ const std::string &expression_path) {
+ addr_t ptr = RetrieveUnsigned(return_value_sp, process_sp, expression_path);
+ std::string str;
+ Status error;
+ process_sp->ReadCStringFromMemory(ptr, str, error);
+ return str;
+}
+
+StructuredData::ObjectSP UndefinedBehaviorSanitizerRuntime::RetrieveReportData(
+ ExecutionContextRef exe_ctx_ref) {
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return StructuredData::ObjectSP();
+
+ ThreadSP thread_sp = exe_ctx_ref.GetThreadSP();
+ StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+ ModuleSP runtime_module_sp = GetRuntimeModuleSP();
+ Target &target = process_sp->GetTarget();
+
+ if (!frame_sp)
+ return StructuredData::ObjectSP();
+
+ StreamFileSP Stream(target.GetDebugger().GetOutputFile());
+
+ EvaluateExpressionOptions options;
+ options.SetUnwindOnError(true);
+ options.SetTryAllThreads(true);
+ options.SetStopOthers(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTimeout(std::chrono::seconds(2));
+ options.SetPrefix(ub_sanitizer_retrieve_report_data_prefix);
+ options.SetAutoApplyFixIts(false);
+ options.SetLanguage(eLanguageTypeObjC_plus_plus);
+
+ ValueObjectSP main_value;
+ ExecutionContext exe_ctx;
+ Status eval_error;
+ frame_sp->CalculateExecutionContext(exe_ctx);
+ ExpressionResults result = UserExpression::Evaluate(
+ exe_ctx, options, ub_sanitizer_retrieve_report_data_command, "",
+ main_value, eval_error);
+ if (result != eExpressionCompleted) {
+ target.GetDebugger().GetAsyncOutputStream()->Printf(
+ "Warning: Cannot evaluate UndefinedBehaviorSanitizer expression:\n%s\n",
+ eval_error.AsCString());
+ return StructuredData::ObjectSP();
+ }
+
+ // Gather the PCs of the user frames in the backtrace.
+ StructuredData::Array *trace = new StructuredData::Array();
+ auto trace_sp = StructuredData::ObjectSP(trace);
+ for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) {
+ const Address FCA =
+ thread_sp->GetStackFrameAtIndex(I)->GetFrameCodeAddress();
+ if (FCA.GetModule() == runtime_module_sp) // Skip PCs from the runtime.
+ continue;
+
+ lldb::addr_t PC = FCA.GetLoadAddress(&target);
+ trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC)));
+ }
+
+ std::string IssueKind = RetrieveString(main_value, process_sp, ".issue_kind");
+ std::string ErrMessage = RetrieveString(main_value, process_sp, ".message");
+ std::string Filename = RetrieveString(main_value, process_sp, ".filename");
+ unsigned Line = RetrieveUnsigned(main_value, process_sp, ".line");
+ unsigned Col = RetrieveUnsigned(main_value, process_sp, ".col");
+ uintptr_t MemoryAddr =
+ RetrieveUnsigned(main_value, process_sp, ".memory_addr");
+
+ auto *d = new StructuredData::Dictionary();
+ auto dict_sp = StructuredData::ObjectSP(d);
+ d->AddStringItem("instrumentation_class", "UndefinedBehaviorSanitizer");
+ d->AddStringItem("description", IssueKind);
+ d->AddStringItem("summary", ErrMessage);
+ d->AddStringItem("filename", Filename);
+ d->AddIntegerItem("line", Line);
+ d->AddIntegerItem("col", Col);
+ d->AddIntegerItem("memory_address", MemoryAddr);
+ d->AddIntegerItem("tid", thread_sp->GetID());
+ d->AddItem("trace", trace_sp);
+ return dict_sp;
+}
+
+static std::string GetStopReasonDescription(StructuredData::ObjectSP report) {
+ llvm::StringRef stop_reason_description_ref;
+ report->GetAsDictionary()->GetValueForKeyAsString("description",
+ stop_reason_description_ref);
+ std::string stop_reason_description = stop_reason_description_ref;
+
+ if (!stop_reason_description.size()) {
+ stop_reason_description = "Undefined behavior detected";
+ } else {
+ stop_reason_description[0] = toupper(stop_reason_description[0]);
+ for (unsigned I = 1; I < stop_reason_description.size(); ++I)
+ if (stop_reason_description[I] == '-')
+ stop_reason_description[I] = ' ';
+ }
+ return stop_reason_description;
+}
+
+bool UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_id) {
+ assert(baton && "null baton");
+ if (!baton)
+ return false; //< false => resume execution.
+
+ UndefinedBehaviorSanitizerRuntime *const instance =
+ static_cast<UndefinedBehaviorSanitizerRuntime *>(baton);
+
+ ProcessSP process_sp = instance->GetProcessSP();
+ ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
+ if (!process_sp || !thread_sp ||
+ process_sp != context->exe_ctx_ref.GetProcessSP())
+ return false;
+
+ if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
+ return false;
+
+ StructuredData::ObjectSP report =
+ instance->RetrieveReportData(context->exe_ctx_ref);
+
+ if (report) {
+ thread_sp->SetStopInfo(
+ InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
+ *thread_sp, GetStopReasonDescription(report), report));
+ return true;
+ }
+
+ return false;
+}
+
+const RegularExpression &
+UndefinedBehaviorSanitizerRuntime::GetPatternForRuntimeLibrary() {
+ static RegularExpression regex(llvm::StringRef("libclang_rt\\.(a|t|ub)san_"));
+ return regex;
+}
+
+bool UndefinedBehaviorSanitizerRuntime::CheckIfRuntimeIsValid(
+ const lldb::ModuleSP module_sp) {
+ static ConstString ubsan_test_sym("__ubsan_on_report");
+ const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(
+ ubsan_test_sym, lldb::eSymbolTypeAny);
+ return symbol != nullptr;
+}
+
+// FIXME: Factor out all the logic we have in common with the {a,t}san plugins.
+void UndefinedBehaviorSanitizerRuntime::Activate() {
+ if (IsActive())
+ return;
+
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return;
+
+ ModuleSP runtime_module_sp = GetRuntimeModuleSP();
+
+ ConstString symbol_name("__ubsan_on_report");
+ const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType(
+ symbol_name, eSymbolTypeCode);
+
+ if (symbol == nullptr)
+ return;
+
+ if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
+ return;
+
+ Target &target = process_sp->GetTarget();
+ addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
+
+ if (symbol_address == LLDB_INVALID_ADDRESS)
+ return;
+
+ Breakpoint *breakpoint =
+ process_sp->GetTarget()
+ .CreateBreakpoint(symbol_address, /*internal=*/true,
+ /*hardware=*/false)
+ .get();
+ breakpoint->SetCallback(
+ UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit, this, true);
+ breakpoint->SetBreakpointKind("undefined-behavior-sanitizer-report");
+ SetBreakpointID(breakpoint->GetID());
+
+ SetActive(true);
+}
+
+void UndefinedBehaviorSanitizerRuntime::Deactivate() {
+ SetActive(false);
+
+ auto BID = GetBreakpointID();
+ if (BID == LLDB_INVALID_BREAK_ID)
+ return;
+
+ if (ProcessSP process_sp = GetProcessSP()) {
+ process_sp->GetTarget().RemoveBreakpointByID(BID);
+ SetBreakpointID(LLDB_INVALID_BREAK_ID);
+ }
+}
+
+lldb::ThreadCollectionSP
+UndefinedBehaviorSanitizerRuntime::GetBacktracesFromExtendedStopInfo(
+ StructuredData::ObjectSP info) {
+ ThreadCollectionSP threads;
+ threads.reset(new ThreadCollection());
+
+ ProcessSP process_sp = GetProcessSP();
+
+ if (info->GetObjectForDotSeparatedPath("instrumentation_class")
+ ->GetStringValue() != "UndefinedBehaviorSanitizer")
+ return threads;
+
+ std::vector<lldb::addr_t> PCs;
+ auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray();
+ trace->ForEach([&PCs](StructuredData::Object *PC) -> bool {
+ PCs.push_back(PC->GetAsInteger()->GetValue());
+ return true;
+ });
+
+ if (PCs.empty())
+ return threads;
+
+ StructuredData::ObjectSP thread_id_obj =
+ info->GetObjectForDotSeparatedPath("tid");
+ tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;
+
+ uint32_t stop_id = 0;
+ bool stop_id_is_valid = false;
+ HistoryThread *history_thread =
+ new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid);
+ ThreadSP new_thread_sp(history_thread);
+ std::string stop_reason_description = GetStopReasonDescription(info);
+ new_thread_sp->SetName(stop_reason_description.c_str());
+
+ // Save this in the Process' ExtendedThreadList so a strong pointer
+ // retains the object
+ process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
+ threads->AddThread(new_thread_sp);
+
+ return threads;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h
new file mode 100644
index 0000000..8f138fc
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h
@@ -0,0 +1,69 @@
+//===-- UndefinedBehaviorSanitizerRuntime.h ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_UndefinedBehaviorSanitizerRuntime_h_
+#define liblldb_UndefinedBehaviorSanitizerRuntime_h_
+
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class UndefinedBehaviorSanitizerRuntime
+ : public lldb_private::InstrumentationRuntime {
+public:
+ ~UndefinedBehaviorSanitizerRuntime() override;
+
+ static lldb::InstrumentationRuntimeSP
+ CreateInstance(const lldb::ProcessSP &process_sp);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static lldb_private::ConstString GetPluginNameStatic();
+
+ static lldb::InstrumentationRuntimeType GetTypeStatic();
+
+ lldb_private::ConstString GetPluginName() override {
+ return GetPluginNameStatic();
+ }
+
+ virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); }
+
+ uint32_t GetPluginVersion() override { return 1; }
+
+ lldb::ThreadCollectionSP
+ GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override;
+
+private:
+ UndefinedBehaviorSanitizerRuntime(const lldb::ProcessSP &process_sp)
+ : lldb_private::InstrumentationRuntime(process_sp) {}
+
+ const RegularExpression &GetPatternForRuntimeLibrary() override;
+
+ bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
+
+ void Activate() override;
+
+ void Deactivate();
+
+ static bool NotifyBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_UndefinedBehaviorSanitizerRuntime_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
index bbb445a..7ef3aec 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp
@@ -12,20 +12,22 @@
#include "llvm/Support/MathExtras.h"
#include "lldb/Breakpoint/Breakpoint.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "JITLoaderGDB.h"
@@ -101,7 +103,7 @@ bool ReadJITEntry(const addr_t from_addr, Process *process,
const size_t data_byte_size =
llvm::alignTo(sizeof(ptr_t) * 3, uint64_align_bytes) + sizeof(uint64_t);
- Error error;
+ Status error;
DataBufferHeap data(data_byte_size, 0);
size_t bytes_read = process->ReadMemory(from_addr, data.GetBytes(),
data.GetByteSize(), error);
@@ -275,7 +277,7 @@ bool JITLoaderGDB::ReadJITDescriptorImpl(bool all_entries) {
jit_descriptor<ptr_t> jit_desc;
const size_t jit_desc_size = sizeof(jit_desc);
- Error error;
+ Status error;
size_t bytes_read = m_process->DoReadMemory(m_jit_descriptor_addr, &jit_desc,
jit_desc_size, error);
if (bytes_read != jit_desc_size || !error.Success()) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp
index db7c246..5e8f051 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp
@@ -44,7 +44,7 @@ public:
return;
}
- Error err;
+ Status err;
TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage(
&err, lldb::eLanguageTypeC_plus_plus);
@@ -133,7 +133,7 @@ public:
return lldb::ValueObjectSP();
}
- Error err;
+ Status err;
ValueObjectSP struct_sp = struct_pointer_sp->Dereference(err);
if (!struct_sp || !err.Success()) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index b5527ed..1ae9418 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -23,18 +23,19 @@
#include "llvm/ADT/StringRef.h"
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/FastDemangle.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/DataFormatters/CXXFunctionPointer.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/VectorType.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FastDemangle.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
#include "BlockPointer.h"
+#include "CPlusPlusNameParser.h"
#include "CxxStringTypes.h"
#include "LibCxx.h"
#include "LibCxxAtomic.h"
@@ -84,15 +85,14 @@ void CPlusPlusLanguage::MethodName::Clear() {
m_context = llvm::StringRef();
m_arguments = llvm::StringRef();
m_qualifiers = llvm::StringRef();
- m_type = eTypeInvalid;
m_parsed = false;
m_parse_error = false;
}
-bool ReverseFindMatchingChars(const llvm::StringRef &s,
- const llvm::StringRef &left_right_chars,
- size_t &left_pos, size_t &right_pos,
- size_t pos = llvm::StringRef::npos) {
+static bool ReverseFindMatchingChars(const llvm::StringRef &s,
+ const llvm::StringRef &left_right_chars,
+ size_t &left_pos, size_t &right_pos,
+ size_t pos = llvm::StringRef::npos) {
assert(left_right_chars.size() == 2);
left_pos = llvm::StringRef::npos;
const char left_char = left_right_chars[0];
@@ -118,10 +118,9 @@ bool ReverseFindMatchingChars(const llvm::StringRef &s,
return false;
}
-static bool IsValidBasename(const llvm::StringRef &basename) {
- // Check that the basename matches with the following regular expression or is
- // an operator name:
- // "^~?([A-Za-z_][A-Za-z_0-9]*)(<.*>)?$"
+static bool IsTrivialBasename(const llvm::StringRef &basename) {
+ // Check that the basename matches with the following regular expression
+ // "^~?([A-Za-z_][A-Za-z_0-9]*)$"
// We are using a hand written implementation because it is significantly more
// efficient then
// using the general purpose regular expression library.
@@ -148,100 +147,69 @@ static bool IsValidBasename(const llvm::StringRef &basename) {
if (idx == basename.size())
return true;
- // Check for basename with template arguments
- // TODO: Improve the quality of the validation with validating the template
- // arguments
- if (basename[idx] == '<' && basename.back() == '>')
- return true;
+ return false;
+}
- // Check if the basename is a vaild C++ operator name
- if (!basename.startswith("operator"))
- return false;
+bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
+ // This method tries to parse simple method definitions
+ // which are presumably most comman in user programs.
+ // Definitions that can be parsed by this function don't have return types
+ // and templates in the name.
+ // A::B::C::fun(std::vector<T> &) const
+ size_t arg_start, arg_end;
+ llvm::StringRef full(m_full.GetCString());
+ llvm::StringRef parens("()", 2);
+ if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
+ m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
+ if (arg_end + 1 < full.size())
+ m_qualifiers = full.substr(arg_end + 1).ltrim();
+
+ if (arg_start == 0)
+ return false;
+ size_t basename_end = arg_start;
+ size_t context_start = 0;
+ size_t context_end = full.rfind(':', basename_end);
+ if (context_end == llvm::StringRef::npos)
+ m_basename = full.substr(0, basename_end);
+ else {
+ if (context_start < context_end)
+ m_context = full.substr(context_start, context_end - 1 - context_start);
+ const size_t basename_begin = context_end + 1;
+ m_basename = full.substr(basename_begin, basename_end - basename_begin);
+ }
- static RegularExpression g_operator_regex(
- llvm::StringRef("^(operator)( "
- "?)([A-Za-z_][A-Za-z_0-9]*|\\(\\)|"
- "\\[\\]|[\\^<>=!\\/"
- "*+-]+)(<.*>)?(\\[\\])?$"));
- std::string basename_str(basename.str());
- return g_operator_regex.Execute(basename_str, nullptr);
+ if (IsTrivialBasename(m_basename)) {
+ return true;
+ } else {
+ // The C++ basename doesn't match our regular expressions so this can't
+ // be a valid C++ method, clear everything out and indicate an error
+ m_context = llvm::StringRef();
+ m_basename = llvm::StringRef();
+ m_arguments = llvm::StringRef();
+ m_qualifiers = llvm::StringRef();
+ return false;
+ }
+ }
+ return false;
}
void CPlusPlusLanguage::MethodName::Parse() {
if (!m_parsed && m_full) {
- // ConstString mangled;
- // m_full.GetMangledCounterpart(mangled);
- // printf ("\n parsing = '%s'\n", m_full.GetCString());
- // if (mangled)
- // printf (" mangled = '%s'\n", mangled.GetCString());
- m_parse_error = false;
- m_parsed = true;
- llvm::StringRef full(m_full.GetCString());
-
- size_t arg_start, arg_end;
- llvm::StringRef parens("()", 2);
- if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
- m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
- if (arg_end + 1 < full.size())
- m_qualifiers = full.substr(arg_end + 1);
- if (arg_start > 0) {
- size_t basename_end = arg_start;
- size_t context_start = 0;
- size_t context_end = llvm::StringRef::npos;
- if (basename_end > 0 && full[basename_end - 1] == '>') {
- // TODO: handle template junk...
- // Templated function
- size_t template_start, template_end;
- llvm::StringRef lt_gt("<>", 2);
- if (ReverseFindMatchingChars(full, lt_gt, template_start,
- template_end, basename_end)) {
- // Check for templated functions that include return type like:
- // 'void foo<Int>()'
- context_start = full.rfind(' ', template_start);
- if (context_start == llvm::StringRef::npos)
- context_start = 0;
- else
- ++context_start;
-
- context_end = full.rfind(':', template_start);
- if (context_end == llvm::StringRef::npos ||
- context_end < context_start)
- context_end = context_start;
- } else {
- context_end = full.rfind(':', basename_end);
- }
- } else if (context_end == llvm::StringRef::npos) {
- context_end = full.rfind(':', basename_end);
- }
-
- if (context_end == llvm::StringRef::npos)
- m_basename = full.substr(0, basename_end);
- else {
- if (context_start < context_end)
- m_context =
- full.substr(context_start, context_end - 1 - context_start);
- const size_t basename_begin = context_end + 1;
- m_basename =
- full.substr(basename_begin, basename_end - basename_begin);
- }
- m_type = eTypeUnknownMethod;
+ if (TrySimplifiedParse()) {
+ m_parse_error = false;
+ } else {
+ CPlusPlusNameParser parser(m_full.GetStringRef());
+ if (auto function = parser.ParseAsFunctionDefinition()) {
+ m_basename = function.getValue().name.basename;
+ m_context = function.getValue().name.context;
+ m_arguments = function.getValue().arguments;
+ m_qualifiers = function.getValue().qualifiers;
+ m_parse_error = false;
} else {
m_parse_error = true;
- return;
- }
-
- if (!IsValidBasename(m_basename)) {
- // The C++ basename doesn't match our regular expressions so this can't
- // be a valid C++ method, clear everything out and indicate an error
- m_context = llvm::StringRef();
- m_basename = llvm::StringRef();
- m_arguments = llvm::StringRef();
- m_qualifiers = llvm::StringRef();
- m_parse_error = true;
}
- } else {
- m_parse_error = true;
}
+ m_parsed = true;
}
}
@@ -272,14 +240,13 @@ llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() {
std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
if (!m_parsed)
Parse();
- if (m_basename.empty() || m_context.empty())
- return std::string();
+ if (m_context.empty())
+ return m_basename;
std::string res;
res += m_context;
res += "::";
res += m_basename;
-
return res;
}
@@ -295,156 +262,15 @@ bool CPlusPlusLanguage::IsCPPMangledName(const char *name) {
bool CPlusPlusLanguage::ExtractContextAndIdentifier(
const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
- static RegularExpression g_basename_regex(llvm::StringRef(
- "^(([A-Za-z_][A-Za-z_0-9]*::)*)(~?[A-Za-z_~][A-Za-z_0-9]*)$"));
- RegularExpression::Match match(4);
- if (g_basename_regex.Execute(llvm::StringRef::withNullAsEmpty(name),
- &match)) {
- match.GetMatchAtIndex(name, 1, context);
- match.GetMatchAtIndex(name, 3, identifier);
+ CPlusPlusNameParser parser(name);
+ if (auto full_name = parser.ParseAsFullName()) {
+ identifier = full_name.getValue().basename;
+ context = full_name.getValue().context;
return true;
}
return false;
}
-class CPPRuntimeEquivalents {
-public:
- CPPRuntimeEquivalents() {
- m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, "
- "std::allocator<char> >")
- .GetStringRef(),
- ConstString("basic_string<char>"));
-
- // these two (with a prefixed std::) occur when c++stdlib string class
- // occurs as a template argument in some STL container
- m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, "
- "std::allocator<char> >")
- .GetStringRef(),
- ConstString("std::basic_string<char>"));
-
- m_impl.Sort();
- }
-
- void Add(ConstString &type_name, ConstString &type_equivalent) {
- m_impl.Insert(type_name.GetStringRef(), type_equivalent);
- }
-
- uint32_t FindExactMatches(ConstString &type_name,
- std::vector<ConstString> &equivalents) {
- uint32_t count = 0;
-
- for (ImplData match =
- m_impl.FindFirstValueForName(type_name.GetStringRef());
- match != nullptr; match = m_impl.FindNextValueForName(match)) {
- equivalents.push_back(match->value);
- count++;
- }
-
- return count;
- }
-
- // partial matches can occur when a name with equivalents is a template
- // argument.
- // e.g. we may have "class Foo" be a match for "struct Bar". if we have a
- // typename
- // such as "class Templatized<class Foo, Anything>" we want this to be
- // replaced with
- // "class Templatized<struct Bar, Anything>". Since partial matching is time
- // consuming
- // once we get a partial match, we add it to the exact matches list for faster
- // retrieval
- uint32_t FindPartialMatches(ConstString &type_name,
- std::vector<ConstString> &equivalents) {
- uint32_t count = 0;
-
- llvm::StringRef type_name_cstr = type_name.GetStringRef();
-
- size_t items_count = m_impl.GetSize();
-
- for (size_t item = 0; item < items_count; item++) {
- llvm::StringRef key_cstr = m_impl.GetCStringAtIndex(item);
- if (type_name_cstr.contains(key_cstr)) {
- count += AppendReplacements(type_name_cstr, key_cstr, equivalents);
- }
- }
-
- return count;
- }
-
-private:
- std::string &replace(std::string &target, std::string &pattern,
- std::string &with) {
- size_t pos;
- size_t pattern_len = pattern.size();
-
- while ((pos = target.find(pattern)) != std::string::npos)
- target.replace(pos, pattern_len, with);
-
- return target;
- }
-
- uint32_t AppendReplacements(llvm::StringRef original,
- llvm::StringRef matching_key,
- std::vector<ConstString> &equivalents) {
- std::string matching_key_str(matching_key);
- ConstString original_const(original);
-
- uint32_t count = 0;
-
- for (ImplData match = m_impl.FindFirstValueForName(matching_key);
- match != nullptr; match = m_impl.FindNextValueForName(match)) {
- std::string target(original);
- std::string equiv_class(match->value.AsCString());
-
- replace(target, matching_key_str, equiv_class);
-
- ConstString target_const(target.c_str());
-
-// you will most probably want to leave this off since it might make this map
-// grow indefinitely
-#ifdef ENABLE_CPP_EQUIVALENTS_MAP_TO_GROW
- Add(original_const, target_const);
-#endif
- equivalents.push_back(target_const);
-
- count++;
- }
-
- return count;
- }
-
- typedef UniqueCStringMap<ConstString> Impl;
- typedef const Impl::Entry *ImplData;
- Impl m_impl;
-};
-
-static CPPRuntimeEquivalents &GetEquivalentsMap() {
- static CPPRuntimeEquivalents g_equivalents_map;
- return g_equivalents_map;
-}
-
-uint32_t
-CPlusPlusLanguage::FindEquivalentNames(ConstString type_name,
- std::vector<ConstString> &equivalents) {
- uint32_t count = GetEquivalentsMap().FindExactMatches(type_name, equivalents);
-
- bool might_have_partials =
- (count == 0) // if we have a full name match just use it
- && (strchr(type_name.AsCString(), '<') !=
- nullptr // we should only have partial matches when templates are
- // involved, check that we have
- && strchr(type_name.AsCString(), '>') != nullptr); // angle brackets
- // in the type_name
- // before trying to
- // scan for partial
- // matches
-
- if (might_have_partials)
- count = GetEquivalentsMap().FindPartialMatches(type_name, equivalents);
-
- return count;
-}
-
/// Given a mangled function `mangled`, replace all the primitive function type
/// arguments of `search` with type `replace`.
static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled,
@@ -596,13 +422,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
AddCXXSynthetic(
cpp_category_sp,
- lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator,
- "libc++ std::vector<bool> synthetic children",
- ConstString(
- "^std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >$"),
- stl_synth_flags, true);
- AddCXXSynthetic(
- cpp_category_sp,
lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator,
"libc++ std::vector synthetic children",
ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_synth_flags,
@@ -620,19 +439,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
true);
AddCXXSynthetic(
cpp_category_sp,
- lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator,
- "libc++ std::vector<bool> synthetic children",
- ConstString("std::__(ndk)?1::vector<std::__(ndk)?1::allocator<bool> >"),
- stl_synth_flags);
- AddCXXSynthetic(
- cpp_category_sp,
- lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator,
- "libc++ std::vector<bool> synthetic children",
- ConstString(
- "std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >"),
- stl_synth_flags);
- AddCXXSynthetic(
- cpp_category_sp,
lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
"libc++ std::set synthetic children",
ConstString("^std::__(ndk)?1::set<.+> >(( )?&)?$"), stl_synth_flags,
@@ -689,12 +495,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
stl_summary_flags.SetDontShowChildren(false);
stl_summary_flags.SetSkipPointers(false);
- AddCXXSummary(
- cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
- "libc++ std::vector<bool> summary provider",
- ConstString(
- "std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >"),
- stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxContainerSummaryProvider,
"libc++ std::vector summary provider",
@@ -759,12 +559,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"std::vector iterator synthetic children",
ConstString("^std::__(ndk)?1::__wrap_iter<.+>$"), stl_synth_flags, true);
- AddCXXSummary(
- cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
- "libc++ std::vector<bool> summary provider",
- ConstString(
- "std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >"),
- stl_summary_flags);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator,
@@ -775,7 +569,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
AddCXXSynthetic(
cpp_category_sp, lldb_private::formatters::LibcxxFunctionFrontEndCreator,
"std::function synthetic value provider",
- ConstString("^std::__1::function<.+>$"), stl_synth_flags, true);
+ ConstString("^std::__(ndk)?1::function<.+>$"), stl_synth_flags, true);
#endif
}
@@ -1036,10 +830,10 @@ std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() {
}
lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
- static std::once_flag g_initialize;
+ static llvm::once_flag g_initialize;
static TypeCategoryImplSP g_category;
- std::call_once(g_initialize, [this]() -> void {
+ llvm::call_once(g_initialize, [this]() -> void {
DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
if (g_category) {
LoadLibCxxFormatters(g_category);
@@ -1052,11 +846,11 @@ lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
HardcodedFormatters::HardcodedSummaryFinder
CPlusPlusLanguage::GetHardcodedSummaries() {
- static std::once_flag g_initialize;
+ static llvm::once_flag g_initialize;
static ConstString g_vectortypes("VectorTypes");
static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
- std::call_once(g_initialize, []() -> void {
+ llvm::call_once(g_initialize, []() -> void {
g_formatters.push_back(
[](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
FormatManager &) -> TypeSummaryImpl::SharedPointer {
@@ -1116,11 +910,11 @@ CPlusPlusLanguage::GetHardcodedSummaries() {
HardcodedFormatters::HardcodedSyntheticFinder
CPlusPlusLanguage::GetHardcodedSynthetics() {
- static std::once_flag g_initialize;
+ static llvm::once_flag g_initialize;
static ConstString g_vectortypes("VectorTypes");
static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
- std::call_once(g_initialize, []() -> void {
+ llvm::call_once(g_initialize, []() -> void {
g_formatters.push_back([](lldb_private::ValueObject &valobj,
lldb::DynamicValueType,
FormatManager &
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index be5cbae..7380ef3 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -19,8 +19,8 @@
#include "llvm/ADT/StringRef.h"
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Target/Language.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
@@ -29,20 +29,13 @@ class CPlusPlusLanguage : public Language {
public:
class MethodName {
public:
- enum Type {
- eTypeInvalid,
- eTypeUnknownMethod,
- eTypeClassMethod,
- eTypeInstanceMethod
- };
-
MethodName()
: m_full(), m_basename(), m_context(), m_arguments(), m_qualifiers(),
- m_type(eTypeInvalid), m_parsed(false), m_parse_error(false) {}
+ m_parsed(false), m_parse_error(false) {}
MethodName(const ConstString &s)
: m_full(s), m_basename(), m_context(), m_arguments(), m_qualifiers(),
- m_type(eTypeInvalid), m_parsed(false), m_parse_error(false) {}
+ m_parsed(false), m_parse_error(false) {}
void Clear();
@@ -51,13 +44,9 @@ public:
Parse();
if (m_parse_error)
return false;
- if (m_type == eTypeInvalid)
- return false;
return (bool)m_full;
}
- Type GetType() const { return m_type; }
-
const ConstString &GetFullName() const { return m_full; }
std::string GetScopeQualifiedName();
@@ -72,6 +61,7 @@ public:
protected:
void Parse();
+ bool TrySimplifiedParse();
ConstString m_full; // Full name:
// "lldb::SBTarget::GetBreakpointAtIndex(unsigned int)
@@ -80,7 +70,6 @@ public:
llvm::StringRef m_context; // Decl context: "lldb::SBTarget"
llvm::StringRef m_arguments; // Arguments: "(unsigned int)"
llvm::StringRef m_qualifiers; // Qualifiers: "const"
- Type m_type;
bool m_parsed;
bool m_parse_error;
};
@@ -121,7 +110,7 @@ public:
// If the name is a lone C identifier (e.g. C) or a qualified C identifier
// (e.g. A::B::C) it will return true,
// and identifier will be the identifier (C and C respectively) and the
- // context will be "" and "A::B::" respectively.
+ // context will be "" and "A::B" respectively.
// If the name fails the heuristic matching for a qualified or unqualified
// C/C++ identifier, then it will return false
// and identifier and context will be unchanged.
@@ -130,18 +119,6 @@ public:
llvm::StringRef &context,
llvm::StringRef &identifier);
- // in some cases, compilers will output different names for one same type.
- // when that happens, it might be impossible
- // to construct SBType objects for a valid type, because the name that is
- // available is not the same as the name that
- // can be used as a search key in FindTypes(). the equivalents map here is
- // meant to return possible alternative names
- // for a type through which a search can be conducted. Currently, this is only
- // enabled for C++ but can be extended
- // to ObjC or other languages if necessary
- static uint32_t FindEquivalentNames(ConstString type_name,
- std::vector<ConstString> &equivalents);
-
// Given a mangled function name, calculates some alternative manglings since
// the compiler mangling may not line up with the symbol we are expecting
static uint32_t
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
new file mode 100644
index 0000000..88bdd68
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -0,0 +1,661 @@
+//===-- CPlusPlusNameParser.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CPlusPlusNameParser.h"
+
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Threading.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using llvm::Optional;
+using llvm::None;
+using ParsedFunction = lldb_private::CPlusPlusNameParser::ParsedFunction;
+using ParsedName = lldb_private::CPlusPlusNameParser::ParsedName;
+namespace tok = clang::tok;
+
+Optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() {
+ m_next_token_index = 0;
+ Optional<ParsedFunction> result(None);
+
+ // Try to parse the name as function without a return type specified
+ // e.g. main(int, char*[])
+ {
+ Bookmark start_position = SetBookmark();
+ result = ParseFunctionImpl(false);
+ if (result && !HasMoreTokens())
+ return result;
+ }
+
+ // Try to parse the name as function with function pointer return type
+ // e.g. void (*get_func(const char*))()
+ result = ParseFuncPtr(true);
+ if (result)
+ return result;
+
+ // Finally try to parse the name as a function with non-function return type
+ // e.g. int main(int, char*[])
+ result = ParseFunctionImpl(true);
+ if (HasMoreTokens())
+ return None;
+ return result;
+}
+
+Optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() {
+ m_next_token_index = 0;
+ Optional<ParsedNameRanges> name_ranges = ParseFullNameImpl();
+ if (!name_ranges)
+ return None;
+ if (HasMoreTokens())
+ return None;
+ ParsedName result;
+ result.basename = GetTextForRange(name_ranges.getValue().basename_range);
+ result.context = GetTextForRange(name_ranges.getValue().context_range);
+ return result;
+}
+
+bool CPlusPlusNameParser::HasMoreTokens() {
+ return m_next_token_index < m_tokens.size();
+}
+
+void CPlusPlusNameParser::Advance() { ++m_next_token_index; }
+
+void CPlusPlusNameParser::TakeBack() { --m_next_token_index; }
+
+bool CPlusPlusNameParser::ConsumeToken(tok::TokenKind kind) {
+ if (!HasMoreTokens())
+ return false;
+
+ if (!Peek().is(kind))
+ return false;
+
+ Advance();
+ return true;
+}
+
+template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
+ if (!HasMoreTokens())
+ return false;
+
+ if (!Peek().isOneOf(kinds...))
+ return false;
+
+ Advance();
+ return true;
+}
+
+CPlusPlusNameParser::Bookmark CPlusPlusNameParser::SetBookmark() {
+ return Bookmark(m_next_token_index);
+}
+
+size_t CPlusPlusNameParser::GetCurrentPosition() { return m_next_token_index; }
+
+clang::Token &CPlusPlusNameParser::Peek() {
+ assert(HasMoreTokens());
+ return m_tokens[m_next_token_index];
+}
+
+Optional<ParsedFunction>
+CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
+ Bookmark start_position = SetBookmark();
+ if (expect_return_type) {
+ // Consume return type if it's expected.
+ if (!ConsumeTypename())
+ return None;
+ }
+
+ auto maybe_name = ParseFullNameImpl();
+ if (!maybe_name) {
+ return None;
+ }
+
+ size_t argument_start = GetCurrentPosition();
+ if (!ConsumeArguments()) {
+ return None;
+ }
+
+ size_t qualifiers_start = GetCurrentPosition();
+ SkipFunctionQualifiers();
+ size_t end_position = GetCurrentPosition();
+
+ ParsedFunction result;
+ result.name.basename = GetTextForRange(maybe_name.getValue().basename_range);
+ result.name.context = GetTextForRange(maybe_name.getValue().context_range);
+ result.arguments = GetTextForRange(Range(argument_start, qualifiers_start));
+ result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position));
+ start_position.Remove();
+ return result;
+}
+
+Optional<ParsedFunction>
+CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
+ Bookmark start_position = SetBookmark();
+ if (expect_return_type) {
+ // Consume return type.
+ if (!ConsumeTypename())
+ return None;
+ }
+
+ if (!ConsumeToken(tok::l_paren))
+ return None;
+ if (!ConsumePtrsAndRefs())
+ return None;
+
+ {
+ Bookmark before_inner_function_pos = SetBookmark();
+ auto maybe_inner_function_name = ParseFunctionImpl(false);
+ if (maybe_inner_function_name)
+ if (ConsumeToken(tok::r_paren))
+ if (ConsumeArguments()) {
+ SkipFunctionQualifiers();
+ start_position.Remove();
+ before_inner_function_pos.Remove();
+ return maybe_inner_function_name;
+ }
+ }
+
+ auto maybe_inner_function_ptr_name = ParseFuncPtr(false);
+ if (maybe_inner_function_ptr_name)
+ if (ConsumeToken(tok::r_paren))
+ if (ConsumeArguments()) {
+ SkipFunctionQualifiers();
+ start_position.Remove();
+ return maybe_inner_function_ptr_name;
+ }
+ return None;
+}
+
+bool CPlusPlusNameParser::ConsumeArguments() {
+ return ConsumeBrackets(tok::l_paren, tok::r_paren);
+}
+
+bool CPlusPlusNameParser::ConsumeTemplateArgs() {
+ Bookmark start_position = SetBookmark();
+ if (!HasMoreTokens() || Peek().getKind() != tok::less)
+ return false;
+ Advance();
+
+ // Consuming template arguments is a bit trickier than consuming function
+ // arguments, because '<' '>' brackets are not always trivially balanced.
+ // In some rare cases tokens '<' and '>' can appear inside template arguments
+ // as arithmetic or shift operators not as template brackets.
+ // Examples: std::enable_if<(10u)<(64), bool>
+ // f<A<operator<(X,Y)::Subclass>>
+ // Good thing that compiler makes sure that really ambiguous cases of
+ // '>' usage should be enclosed within '()' brackets.
+ int template_counter = 1;
+ bool can_open_template = false;
+ while (HasMoreTokens() && template_counter > 0) {
+ tok::TokenKind kind = Peek().getKind();
+ switch (kind) {
+ case tok::greatergreater:
+ template_counter -= 2;
+ can_open_template = false;
+ Advance();
+ break;
+ case tok::greater:
+ --template_counter;
+ can_open_template = false;
+ Advance();
+ break;
+ case tok::less:
+ // '<' is an attempt to open a subteamplte
+ // check if parser is at the point where it's actually possible,
+ // otherwise it's just a part of an expression like 'sizeof(T)<(10)'.
+ // No need to do the same for '>' because compiler actually makes sure
+ // that '>' always surrounded by brackets to avoid ambiguity.
+ if (can_open_template)
+ ++template_counter;
+ can_open_template = false;
+ Advance();
+ break;
+ case tok::kw_operator: // C++ operator overloading.
+ if (!ConsumeOperator())
+ return false;
+ can_open_template = true;
+ break;
+ case tok::raw_identifier:
+ can_open_template = true;
+ Advance();
+ break;
+ case tok::l_square:
+ if (!ConsumeBrackets(tok::l_square, tok::r_square))
+ return false;
+ can_open_template = false;
+ break;
+ case tok::l_paren:
+ if (!ConsumeArguments())
+ return false;
+ can_open_template = false;
+ break;
+ default:
+ can_open_template = false;
+ Advance();
+ break;
+ }
+ }
+
+ assert(template_counter >= 0);
+ if (template_counter > 0) {
+ return false;
+ }
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeAnonymousNamespace() {
+ Bookmark start_position = SetBookmark();
+ if (!ConsumeToken(tok::l_paren)) {
+ return false;
+ }
+ constexpr llvm::StringLiteral g_anonymous("anonymous");
+ if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
+ Peek().getRawIdentifier() == g_anonymous) {
+ Advance();
+ } else {
+ return false;
+ }
+
+ if (!ConsumeToken(tok::kw_namespace)) {
+ return false;
+ }
+
+ if (!ConsumeToken(tok::r_paren)) {
+ return false;
+ }
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeLambda() {
+ Bookmark start_position = SetBookmark();
+ if (!ConsumeToken(tok::l_brace)) {
+ return false;
+ }
+ constexpr llvm::StringLiteral g_lambda("lambda");
+ if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
+ Peek().getRawIdentifier() == g_lambda) {
+ // Put the matched brace back so we can use ConsumeBrackets
+ TakeBack();
+ } else {
+ return false;
+ }
+
+ if (!ConsumeBrackets(tok::l_brace, tok::r_brace)) {
+ return false;
+ }
+
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left,
+ tok::TokenKind right) {
+ Bookmark start_position = SetBookmark();
+ if (!HasMoreTokens() || Peek().getKind() != left)
+ return false;
+ Advance();
+
+ int counter = 1;
+ while (HasMoreTokens() && counter > 0) {
+ tok::TokenKind kind = Peek().getKind();
+ if (kind == right)
+ --counter;
+ else if (kind == left)
+ ++counter;
+ Advance();
+ }
+
+ assert(counter >= 0);
+ if (counter > 0) {
+ return false;
+ }
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeOperator() {
+ Bookmark start_position = SetBookmark();
+ if (!ConsumeToken(tok::kw_operator))
+ return false;
+
+ if (!HasMoreTokens()) {
+ return false;
+ }
+
+ const auto &token = Peek();
+ switch (token.getKind()) {
+ case tok::kw_new:
+ case tok::kw_delete:
+ // This is 'new' or 'delete' operators.
+ Advance();
+ // Check for array new/delete.
+ if (HasMoreTokens() && Peek().is(tok::l_square)) {
+ // Consume the '[' and ']'.
+ if (!ConsumeBrackets(tok::l_square, tok::r_square))
+ return false;
+ }
+ break;
+
+#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
+ case tok::Token: \
+ Advance(); \
+ break;
+#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly)
+#include "clang/Basic/OperatorKinds.def"
+#undef OVERLOADED_OPERATOR
+#undef OVERLOADED_OPERATOR_MULTI
+
+ case tok::l_paren:
+ // Call operator consume '(' ... ')'.
+ if (ConsumeBrackets(tok::l_paren, tok::r_paren))
+ break;
+ return false;
+
+ case tok::l_square:
+ // This is a [] operator.
+ // Consume the '[' and ']'.
+ if (ConsumeBrackets(tok::l_square, tok::r_square))
+ break;
+ return false;
+
+ default:
+ // This might be a cast operator.
+ if (ConsumeTypename())
+ break;
+ return false;
+ }
+ start_position.Remove();
+ return true;
+}
+
+void CPlusPlusNameParser::SkipTypeQualifiers() {
+ while (ConsumeToken(tok::kw_const, tok::kw_volatile))
+ ;
+}
+
+void CPlusPlusNameParser::SkipFunctionQualifiers() {
+ while (ConsumeToken(tok::kw_const, tok::kw_volatile, tok::amp, tok::ampamp))
+ ;
+}
+
+bool CPlusPlusNameParser::ConsumeBuiltinType() {
+ bool result = false;
+ bool continue_parsing = true;
+ // Built-in types can be made of a few keywords
+ // like 'unsigned long long int'. This function
+ // consumes all built-in type keywords without
+ // checking if they make sense like 'unsigned char void'.
+ while (continue_parsing && HasMoreTokens()) {
+ switch (Peek().getKind()) {
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw___float128:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ result = true;
+ Advance();
+ break;
+ default:
+ continue_parsing = false;
+ break;
+ }
+ }
+ return result;
+}
+
+void CPlusPlusNameParser::SkipPtrsAndRefs() {
+ // Ignoring result.
+ ConsumePtrsAndRefs();
+}
+
+bool CPlusPlusNameParser::ConsumePtrsAndRefs() {
+ bool found = false;
+ SkipTypeQualifiers();
+ while (ConsumeToken(tok::star, tok::amp, tok::ampamp, tok::kw_const,
+ tok::kw_volatile)) {
+ found = true;
+ SkipTypeQualifiers();
+ }
+ return found;
+}
+
+bool CPlusPlusNameParser::ConsumeDecltype() {
+ Bookmark start_position = SetBookmark();
+ if (!ConsumeToken(tok::kw_decltype))
+ return false;
+
+ if (!ConsumeArguments())
+ return false;
+
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeTypename() {
+ Bookmark start_position = SetBookmark();
+ SkipTypeQualifiers();
+ if (!ConsumeBuiltinType() && !ConsumeDecltype()) {
+ if (!ParseFullNameImpl())
+ return false;
+ }
+ SkipPtrsAndRefs();
+ start_position.Remove();
+ return true;
+}
+
+Optional<CPlusPlusNameParser::ParsedNameRanges>
+CPlusPlusNameParser::ParseFullNameImpl() {
+ // Name parsing state machine.
+ enum class State {
+ Beginning, // start of the name
+ AfterTwoColons, // right after ::
+ AfterIdentifier, // right after alphanumerical identifier ([a-z0-9_]+)
+ AfterTemplate, // right after template brackets (<something>)
+ AfterOperator, // right after name of C++ operator
+ };
+
+ Bookmark start_position = SetBookmark();
+ State state = State::Beginning;
+ bool continue_parsing = true;
+ Optional<size_t> last_coloncolon_position = None;
+
+ while (continue_parsing && HasMoreTokens()) {
+ const auto &token = Peek();
+ switch (token.getKind()) {
+ case tok::raw_identifier: // Just a name.
+ if (state != State::Beginning && state != State::AfterTwoColons) {
+ continue_parsing = false;
+ break;
+ }
+ Advance();
+ state = State::AfterIdentifier;
+ break;
+ case tok::l_paren: {
+ if (state == State::Beginning || state == State::AfterTwoColons) {
+ // (anonymous namespace)
+ if (ConsumeAnonymousNamespace()) {
+ state = State::AfterIdentifier;
+ break;
+ }
+ }
+
+ // Type declared inside a function 'func()::Type'
+ if (state != State::AfterIdentifier && state != State::AfterTemplate &&
+ state != State::AfterOperator) {
+ continue_parsing = false;
+ break;
+ }
+ Bookmark l_paren_position = SetBookmark();
+ // Consume the '(' ... ') [const]'.
+ if (!ConsumeArguments()) {
+ continue_parsing = false;
+ break;
+ }
+ SkipFunctionQualifiers();
+
+ // Consume '::'
+ size_t coloncolon_position = GetCurrentPosition();
+ if (!ConsumeToken(tok::coloncolon)) {
+ continue_parsing = false;
+ break;
+ }
+ l_paren_position.Remove();
+ last_coloncolon_position = coloncolon_position;
+ state = State::AfterTwoColons;
+ break;
+ }
+ case tok::l_brace:
+ if (state == State::Beginning || state == State::AfterTwoColons) {
+ if (ConsumeLambda()) {
+ state = State::AfterIdentifier;
+ break;
+ }
+ }
+ continue_parsing = false;
+ break;
+ case tok::coloncolon: // Type nesting delimiter.
+ if (state != State::Beginning && state != State::AfterIdentifier &&
+ state != State::AfterTemplate) {
+ continue_parsing = false;
+ break;
+ }
+ last_coloncolon_position = GetCurrentPosition();
+ Advance();
+ state = State::AfterTwoColons;
+ break;
+ case tok::less: // Template brackets.
+ if (state != State::AfterIdentifier && state != State::AfterOperator) {
+ continue_parsing = false;
+ break;
+ }
+ if (!ConsumeTemplateArgs()) {
+ continue_parsing = false;
+ break;
+ }
+ state = State::AfterTemplate;
+ break;
+ case tok::kw_operator: // C++ operator overloading.
+ if (state != State::Beginning && state != State::AfterTwoColons) {
+ continue_parsing = false;
+ break;
+ }
+ if (!ConsumeOperator()) {
+ continue_parsing = false;
+ break;
+ }
+ state = State::AfterOperator;
+ break;
+ case tok::tilde: // Destructor.
+ if (state != State::Beginning && state != State::AfterTwoColons) {
+ continue_parsing = false;
+ break;
+ }
+ Advance();
+ if (ConsumeToken(tok::raw_identifier)) {
+ state = State::AfterIdentifier;
+ } else {
+ TakeBack();
+ continue_parsing = false;
+ }
+ break;
+ default:
+ continue_parsing = false;
+ break;
+ }
+ }
+
+ if (state == State::AfterIdentifier || state == State::AfterOperator ||
+ state == State::AfterTemplate) {
+ ParsedNameRanges result;
+ if (last_coloncolon_position) {
+ result.context_range = Range(start_position.GetSavedPosition(),
+ last_coloncolon_position.getValue());
+ result.basename_range =
+ Range(last_coloncolon_position.getValue() + 1, GetCurrentPosition());
+ } else {
+ result.basename_range =
+ Range(start_position.GetSavedPosition(), GetCurrentPosition());
+ }
+ start_position.Remove();
+ return result;
+ } else {
+ return None;
+ }
+}
+
+llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
+ if (range.empty())
+ return llvm::StringRef();
+ assert(range.begin_index < range.end_index);
+ assert(range.begin_index < m_tokens.size());
+ assert(range.end_index <= m_tokens.size());
+ clang::Token &first_token = m_tokens[range.begin_index];
+ clang::Token &last_token = m_tokens[range.end_index - 1];
+ clang::SourceLocation start_loc = first_token.getLocation();
+ clang::SourceLocation end_loc = last_token.getLocation();
+ unsigned start_pos = start_loc.getRawEncoding();
+ unsigned end_pos = end_loc.getRawEncoding() + last_token.getLength();
+ return m_text.take_front(end_pos).drop_front(start_pos);
+}
+
+static const clang::LangOptions &GetLangOptions() {
+ static clang::LangOptions g_options;
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
+ g_options.LineComment = true;
+ g_options.C99 = true;
+ g_options.C11 = true;
+ g_options.CPlusPlus = true;
+ g_options.CPlusPlus11 = true;
+ g_options.CPlusPlus14 = true;
+ g_options.CPlusPlus1z = true;
+ });
+ return g_options;
+}
+
+static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
+ static llvm::StringMap<tok::TokenKind> g_map{
+#define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
+#include "clang/Basic/TokenKinds.def"
+#undef KEYWORD
+ };
+ return g_map;
+}
+
+void CPlusPlusNameParser::ExtractTokens() {
+ clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
+ m_text.data(), m_text.data() + m_text.size());
+ const auto &kw_map = GetKeywordsMap();
+ clang::Token token;
+ for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
+ lexer.LexFromRawLexer(token)) {
+ if (token.is(clang::tok::raw_identifier)) {
+ auto it = kw_map.find(token.getRawIdentifier());
+ if (it != kw_map.end()) {
+ token.setKind(it->getValue());
+ }
+ }
+
+ m_tokens.push_back(token);
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
new file mode 100644
index 0000000..fe1d46f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
@@ -0,0 +1,182 @@
+//===-- CPlusPlusNameParser.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CPlusPlusNameParser_h_
+#define liblldb_CPlusPlusNameParser_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+// Project includes
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+// Helps to validate and obtain various parts of C++ definitions.
+class CPlusPlusNameParser {
+public:
+ CPlusPlusNameParser(llvm::StringRef text) : m_text(text) { ExtractTokens(); }
+
+ struct ParsedName {
+ llvm::StringRef basename;
+ llvm::StringRef context;
+ };
+
+ struct ParsedFunction {
+ ParsedName name;
+ llvm::StringRef arguments;
+ llvm::StringRef qualifiers;
+ };
+
+ // Treats given text as a function definition and parses it.
+ // Function definition might or might not have a return type and this should
+ // change parsing result.
+ // Examples:
+ // main(int, chat const*)
+ // T fun(int, bool)
+ // std::vector<int>::push_back(int)
+ // int& map<int, pair<short, int>>::operator[](short) const
+ // int (*get_function(const chat *))()
+ llvm::Optional<ParsedFunction> ParseAsFunctionDefinition();
+
+ // Treats given text as a potentially nested name of C++ entity (function,
+ // class, field) and parses it.
+ // Examples:
+ // main
+ // fun
+ // std::vector<int>::push_back
+ // map<int, pair<short, int>>::operator[]
+ // func<C>(int, C&)::nested_class::method
+ llvm::Optional<ParsedName> ParseAsFullName();
+
+private:
+ // A C++ definition to parse.
+ llvm::StringRef m_text;
+ // Tokens extracted from m_text.
+ llvm::SmallVector<clang::Token, 30> m_tokens;
+ // Index of the next token to look at from m_tokens.
+ size_t m_next_token_index = 0;
+
+ // Range of tokens saved in m_next_token_index.
+ struct Range {
+ size_t begin_index = 0;
+ size_t end_index = 0;
+
+ Range() {}
+ Range(size_t begin, size_t end) : begin_index(begin), end_index(end) {
+ assert(end >= begin);
+ }
+
+ size_t size() const { return end_index - begin_index; }
+
+ bool empty() const { return size() == 0; }
+ };
+
+ struct ParsedNameRanges {
+ Range basename_range;
+ Range context_range;
+ };
+
+ // Bookmark automatically restores parsing position (m_next_token_index)
+ // when destructed unless it's manually removed with Remove().
+ class Bookmark {
+ public:
+ Bookmark(size_t &position)
+ : m_position(position), m_position_value(position) {}
+ Bookmark(const Bookmark &) = delete;
+ Bookmark(Bookmark &&b)
+ : m_position(b.m_position), m_position_value(b.m_position_value),
+ m_restore(b.m_restore) {
+ b.Remove();
+ }
+ Bookmark &operator=(Bookmark &&) = delete;
+ Bookmark &operator=(const Bookmark &) = delete;
+
+ void Remove() { m_restore = false; }
+ size_t GetSavedPosition() { return m_position_value; }
+ ~Bookmark() {
+ if (m_restore) {
+ m_position = m_position_value;
+ }
+ }
+
+ private:
+ size_t &m_position;
+ size_t m_position_value;
+ bool m_restore = true;
+ };
+
+ bool HasMoreTokens();
+ void Advance();
+ void TakeBack();
+ bool ConsumeToken(clang::tok::TokenKind kind);
+ template <typename... Ts> bool ConsumeToken(Ts... kinds);
+ Bookmark SetBookmark();
+ size_t GetCurrentPosition();
+ clang::Token &Peek();
+ bool ConsumeBrackets(clang::tok::TokenKind left, clang::tok::TokenKind right);
+
+ llvm::Optional<ParsedFunction> ParseFunctionImpl(bool expect_return_type);
+
+ // Parses functions returning function pointers 'string (*f(int x))(float y)'
+ llvm::Optional<ParsedFunction> ParseFuncPtr(bool expect_return_type);
+
+ // Consumes function arguments enclosed within '(' ... ')'
+ bool ConsumeArguments();
+
+ // Consumes template arguments enclosed within '<' ... '>'
+ bool ConsumeTemplateArgs();
+
+ // Consumes '(anonymous namespace)'
+ bool ConsumeAnonymousNamespace();
+
+ // Consumes '{lambda ...}'
+ bool ConsumeLambda();
+
+ // Consumes operator declaration like 'operator *' or 'operator delete []'
+ bool ConsumeOperator();
+
+ // Skips 'const' and 'volatile'
+ void SkipTypeQualifiers();
+
+ // Skips 'const', 'volatile', '&', '&&' in the end of the function.
+ void SkipFunctionQualifiers();
+
+ // Consumes built-in types like 'int' or 'unsigned long long int'
+ bool ConsumeBuiltinType();
+
+ // Consumes types defined via decltype keyword.
+ bool ConsumeDecltype();
+
+ // Skips 'const' and 'volatile'
+ void SkipPtrsAndRefs();
+
+ // Consumes things like 'const * const &'
+ bool ConsumePtrsAndRefs();
+
+ // Consumes full type name like 'Namespace::Class<int>::Method()::InnerClass'
+ bool ConsumeTypename();
+
+ llvm::Optional<ParsedNameRanges> ParseFullNameImpl();
+ llvm::StringRef GetTextForRange(const Range &range);
+
+ // Populate m_tokens by calling clang lexer on m_text.
+ void ExtractTokens();
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CPlusPlusNameParser_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
index 346ea0b..0f6fb54 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
@@ -11,21 +11,21 @@
#include "llvm/Support/ConvertUTF.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSummary.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Host/Time.h"
#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
-#include "lldb/Utility/ProcessStructReader.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
#include <algorithm>
@@ -129,7 +129,7 @@ bool lldb_private::formatters::WCharStringSummaryProvider(
bool lldb_private::formatters::Char16SummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
DataExtractor data;
- Error error;
+ Status error;
valobj.GetData(data, error);
if (error.Fail())
@@ -155,7 +155,7 @@ bool lldb_private::formatters::Char16SummaryProvider(
bool lldb_private::formatters::Char32SummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
DataExtractor data;
- Error error;
+ Status error;
valobj.GetData(data, error);
if (error.Fail())
@@ -181,7 +181,7 @@ bool lldb_private::formatters::Char32SummaryProvider(
bool lldb_private::formatters::WCharSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
DataExtractor data;
- Error error;
+ Status error;
valobj.GetData(data, error);
if (error.Fail())
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h
index 0bee3bd..8e2ec44 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h
@@ -11,9 +11,9 @@
#ifndef liblldb_CxxStringTypes_h_
#define liblldb_CxxStringTypes_h_
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index 82441a6..11245e1 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -13,21 +13,21 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/FormatEntity.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/VectorIterator.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/Target.h"
-#include "lldb/Utility/ProcessStructReader.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -53,7 +53,7 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
return true;
} else {
bool print_pointee = false;
- Error error;
+ Status error;
ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
if (pointee_sp && error.Success()) {
if (pointee_sp->DumpPrintableRepresentation(
@@ -76,155 +76,6 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
return true;
}
-lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
- LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
- : SyntheticChildrenFrontEnd(*valobj_sp), m_bool_type(), m_exe_ctx_ref(),
- m_count(0), m_base_data_address(0), m_children() {
- if (valobj_sp) {
- Update();
- m_bool_type =
- valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
- }
-}
-
-size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
- CalculateNumChildren() {
- return m_count;
-}
-
-lldb::ValueObjectSP
-lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex(
- size_t idx) {
- auto iter = m_children.find(idx), end = m_children.end();
- if (iter != end)
- return iter->second;
- if (idx >= m_count)
- return ValueObjectSP();
- if (m_base_data_address == 0 || m_count == 0)
- return ValueObjectSP();
- if (!m_bool_type)
- return ValueObjectSP();
- size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
- size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
- lldb::addr_t byte_location = m_base_data_address + byte_idx;
- ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
- if (!process_sp)
- return ValueObjectSP();
- uint8_t byte = 0;
- uint8_t mask = 0;
- Error err;
- size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
- if (err.Fail() || bytes_read == 0)
- return ValueObjectSP();
- switch (bit_index) {
- case 0:
- mask = 1;
- break;
- case 1:
- mask = 2;
- break;
- case 2:
- mask = 4;
- break;
- case 3:
- mask = 8;
- break;
- case 4:
- mask = 16;
- break;
- case 5:
- mask = 32;
- break;
- case 6:
- mask = 64;
- break;
- case 7:
- mask = 128;
- break;
- default:
- return ValueObjectSP();
- }
- bool bit_set = ((byte & mask) != 0);
- DataBufferSP buffer_sp(
- new DataBufferHeap(m_bool_type.GetByteSize(nullptr), 0));
- if (bit_set && buffer_sp && buffer_sp->GetBytes())
- *(buffer_sp->GetBytes()) =
- 1; // regardless of endianness, anything non-zero is true
- StreamString name;
- name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- ValueObjectSP retval_sp(CreateValueObjectFromData(
- name.GetString(), DataExtractor(buffer_sp, process_sp->GetByteOrder(),
- process_sp->GetAddressByteSize()),
- m_exe_ctx_ref, m_bool_type));
- if (retval_sp)
- m_children[idx] = retval_sp;
- return retval_sp;
-}
-
-/*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
- __begin_ = 0x00000001001000e0
- __size_ = 56
- __cap_alloc_ = {
- std::__1::__libcpp_compressed_pair_imp<unsigned long,
- std::__1::allocator<unsigned long> > = {
- __first_ = 1
- }
- }
- }*/
-
-bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() {
- m_children.clear();
- ValueObjectSP valobj_sp = m_backend.GetSP();
- if (!valobj_sp)
- return false;
- m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
- ValueObjectSP size_sp(
- valobj_sp->GetChildMemberWithName(ConstString("__size_"), true));
- if (!size_sp)
- return false;
- m_count = size_sp->GetValueAsUnsigned(0);
- if (!m_count)
- return true;
- ValueObjectSP begin_sp(
- valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true));
- if (!begin_sp) {
- m_count = 0;
- return false;
- }
- m_base_data_address = begin_sp->GetValueAsUnsigned(0);
- if (!m_base_data_address) {
- m_count = 0;
- return false;
- }
- return false;
-}
-
-bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
- MightHaveChildren() {
- return true;
-}
-
-size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
- GetIndexOfChildWithName(const ConstString &name) {
- if (!m_count || !m_base_data_address)
- return UINT32_MAX;
- const char *item_name = name.GetCString();
- uint32_t idx = ExtractIndexFromString(item_name);
- if (idx < UINT32_MAX && idx >= CalculateNumChildren())
- return UINT32_MAX;
- return idx;
-}
-
-lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
- ~LibcxxVectorBoolSyntheticFrontEnd() = default;
-
-SyntheticChildrenFrontEnd *
-lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator(
- CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
- return (valobj_sp ? new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp)
- : nullptr);
-}
-
/*
(lldb) fr var ibeg --raw --ptr-depth 1
(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int,
@@ -330,7 +181,7 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
});
DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0));
ProcessSP process_sp(target_sp->GetProcessSP());
- Error error;
+ Status error;
process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error);
if (error.Fail())
return false;
@@ -544,7 +395,8 @@ static bool ExtractLibcxxStringInfo(ValueObject &valobj,
if (!D)
return false;
- ValueObjectSP layout_decider(D->GetChildAtIndexPath({0, 0}));
+ ValueObjectSP layout_decider(
+ D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0})));
// this child should exist
if (!layout_decider)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index a863851..7610212 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -11,10 +11,10 @@
#ifndef liblldb_LibCxx_h_
#define liblldb_LibCxx_h_
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
@@ -32,30 +32,6 @@ bool LibcxxSmartPointerSummaryProvider(
const TypeSummaryOptions
&options); // libc++ std::shared_ptr<> and std::weak_ptr<>
-class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
-public:
- LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
-
- size_t CalculateNumChildren() override;
-
- lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
-
- bool Update() override;
-
- bool MightHaveChildren() override;
-
- size_t GetIndexOfChildWithName(const ConstString &name) override;
-
- ~LibcxxVectorBoolSyntheticFrontEnd() override;
-
-private:
- CompilerType m_bool_type;
- ExecutionContextRef m_exe_ctx_ref;
- uint64_t m_count;
- lldb::addr_t m_base_data_address;
- std::map<size_t, lldb::ValueObjectSP> m_children;
-};
-
SyntheticChildrenFrontEnd *
LibcxxVectorBoolSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h
index e2cc011..a9d948b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h
@@ -11,10 +11,10 @@
#ifndef liblldb_LibCxxAtomic_h_
#define liblldb_LibCxxAtomic_h_
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
index b7aa70c..4e83953 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
@@ -13,9 +13,9 @@
// Project includes
#include "LibCxx.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
index 16bd631..56d8eda 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
@@ -13,15 +13,15 @@
// Project includes
#include "LibCxx.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -291,7 +291,7 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex(
// we need to copy current_sp into a new object otherwise we will end up with
// all items named __value_
DataExtractor data;
- Error error;
+ Status error;
current_sp->GetData(data, error);
if (error.Fail())
return lldb::ValueObjectSP();
@@ -312,7 +312,7 @@ bool lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update() {
m_slow_runner.SetEntry(nullptr);
m_fast_runner.SetEntry(nullptr);
- Error err;
+ Status err;
ValueObjectSP backend_addr(m_backend.AddressOf(err));
m_list_capping_size = 0;
if (m_backend.GetTargetSP())
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
index 759a700..b7215db 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -13,15 +13,15 @@
// Project includes
#include "LibCxx.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -219,6 +219,7 @@ size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
CalculateNumChildren() {
static ConstString g___pair3_("__pair3_");
static ConstString g___first_("__first_");
+ static ConstString g___value_("__value_");
if (m_count != UINT32_MAX)
return m_count;
@@ -227,7 +228,22 @@ size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
ValueObjectSP m_item(m_tree->GetChildMemberWithName(g___pair3_, true));
if (!m_item)
return 0;
- m_item = m_item->GetChildMemberWithName(g___first_, true);
+
+ switch (m_item->GetCompilerType().GetNumDirectBaseClasses()) {
+ case 1:
+ // Assume a pre llvm r300140 __compressed_pair implementation:
+ m_item = m_item->GetChildMemberWithName(g___first_, true);
+ break;
+ case 2: {
+ // Assume a post llvm r300140 __compressed_pair implementation:
+ ValueObjectSP first_elem_parent = m_item->GetChildAtIndex(0, true);
+ m_item = first_elem_parent->GetChildMemberWithName(g___value_, true);
+ break;
+ }
+ default:
+ return false;
+ }
+
if (!m_item)
return 0;
m_count = m_item->GetValueAsUnsigned(0);
@@ -243,7 +259,7 @@ bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() {
return true;
m_element_type.Clear();
ValueObjectSP deref;
- Error error;
+ Status error;
deref = m_root_node->Dereference(error);
if (!deref || error.Fail())
return false;
@@ -349,7 +365,7 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex(
}
if (GetDataType()) {
if (!need_to_skip) {
- Error error;
+ Status error;
iterated_sp = iterated_sp->Dereference(error);
if (!iterated_sp || error.Fail()) {
m_tree = nullptr;
@@ -390,7 +406,7 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex(
// we need to copy current_sp into a new object otherwise we will end up with
// all items named __value_
DataExtractor data;
- Error error;
+ Status error;
iterated_sp->GetData(data, error);
if (error.Fail()) {
m_tree = nullptr;
@@ -406,7 +422,7 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex(
case 1: {
auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
if (child0_sp && child0_sp->GetName() == g___cc)
- potential_child_sp = child0_sp;
+ potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
break;
}
case 2: {
@@ -414,11 +430,10 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex(
auto child1_sp = potential_child_sp->GetChildAtIndex(1, true);
if (child0_sp && child0_sp->GetName() == g___cc && child1_sp &&
child1_sp->GetName() == g___nc)
- potential_child_sp = child0_sp;
+ potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
break;
}
}
- potential_child_sp->SetName(ConstString(name.GetString()));
}
m_iterators[idx] = iterator;
return potential_child_sp;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 5fe4b3a..190b5f6 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -13,15 +13,15 @@
// Project includes
#include "LibCxx.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -83,7 +83,7 @@ lldb::ValueObjectSP lldb_private::formatters::
if (m_next_element == nullptr)
return lldb::ValueObjectSP();
- Error error;
+ Status error;
ValueObjectSP node_sp = m_next_element->Dereference(error);
if (!node_sp || error.Fail())
return lldb::ValueObjectSP();
@@ -94,9 +94,30 @@ lldb::ValueObjectSP lldb_private::formatters::
node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
if (!hash_sp || !value_sp) {
if (!m_element_type) {
- auto first_sp = m_backend.GetChildAtNamePath({ConstString("__table_"),
- ConstString("__p1_"),
- ConstString("__first_")});
+ auto p1_sp = m_backend.GetChildAtNamePath({ConstString("__table_"),
+ ConstString("__p1_")});
+ if (!p1_sp)
+ return nullptr;
+
+ ValueObjectSP first_sp = nullptr;
+ switch (p1_sp->GetCompilerType().GetNumDirectBaseClasses()) {
+ case 1:
+ // Assume a pre llvm r300140 __compressed_pair implementation:
+ first_sp = p1_sp->GetChildMemberWithName(ConstString("__first_"),
+ true);
+ break;
+ case 2: {
+ // Assume a post llvm r300140 __compressed_pair implementation:
+ ValueObjectSP first_elem_parent_sp =
+ p1_sp->GetChildAtIndex(0, true);
+ first_sp = p1_sp->GetChildMemberWithName(ConstString("__value_"),
+ true);
+ break;
+ }
+ default:
+ return nullptr;
+ }
+
if (!first_sp)
return nullptr;
m_element_type = first_sp->GetCompilerType();
@@ -132,7 +153,7 @@ lldb::ValueObjectSP lldb_private::formatters::
StreamString stream;
stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data;
- Error error;
+ Status error;
val_hash.first->GetData(data, error);
if (error.Fail())
return lldb::ValueObjectSP();
@@ -152,22 +173,39 @@ bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
m_backend.GetChildMemberWithName(ConstString("__table_"), true);
if (!table_sp)
return false;
- ValueObjectSP num_elements_sp = table_sp->GetChildAtNamePath(
- {ConstString("__p2_"), ConstString("__first_")});
+
+ ValueObjectSP p2_sp = table_sp->GetChildMemberWithName(
+ ConstString("__p2_"), true);
+ ValueObjectSP num_elements_sp = nullptr;
+ llvm::SmallVector<ConstString, 3> next_path;
+ switch (p2_sp->GetCompilerType().GetNumDirectBaseClasses()) {
+ case 1:
+ // Assume a pre llvm r300140 __compressed_pair implementation:
+ num_elements_sp = p2_sp->GetChildMemberWithName(
+ ConstString("__first_"), true);
+ next_path.append({ConstString("__p1_"), ConstString("__first_"),
+ ConstString("__next_")});
+ break;
+ case 2: {
+ // Assume a post llvm r300140 __compressed_pair implementation:
+ ValueObjectSP first_elem_parent = p2_sp->GetChildAtIndex(0, true);
+ num_elements_sp = first_elem_parent->GetChildMemberWithName(
+ ConstString("__value_"), true);
+ next_path.append({ConstString("__p1_"), ConstString("__value_"),
+ ConstString("__next_")});
+ break;
+ }
+ default:
+ return false;
+ }
+
if (!num_elements_sp)
return false;
m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
- m_tree =
- table_sp
- ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"),
- ConstString("__next_")})
- .get();
+ m_tree = table_sp->GetChildAtNamePath(next_path).get();
if (m_num_elements > 0)
m_next_element =
- table_sp
- ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"),
- ConstString("__next_")})
- .get();
+ table_sp->GetChildAtNamePath(next_path).get();
return false;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index b5c9b6d..6f601c9 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -13,9 +13,9 @@
// Project includes
#include "LibCxx.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
using namespace lldb;
using namespace lldb_private;
@@ -45,6 +45,29 @@ private:
CompilerType m_element_type;
uint32_t m_element_size;
};
+
+class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ size_t CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+ bool Update() override;
+
+ bool MightHaveChildren() override { return true; }
+
+ size_t GetIndexOfChildWithName(const ConstString &name) override;
+
+private:
+ CompilerType m_bool_type;
+ ExecutionContextRef m_exe_ctx_ref;
+ uint64_t m_count;
+ lldb::addr_t m_base_data_address;
+ std::map<size_t, lldb::ValueObjectSP> m_children;
+};
+
} // namespace formatters
} // namespace lldb_private
@@ -104,8 +127,25 @@ bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() {
m_backend.GetChildMemberWithName(ConstString("__end_cap_"), true));
if (!data_type_finder_sp)
return false;
- data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName(
+
+ switch (data_type_finder_sp->GetCompilerType().GetNumDirectBaseClasses()) {
+ case 1:
+ // Assume a pre llvm r300140 __compressed_pair implementation:
+ data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName(
ConstString("__first_"), true);
+ break;
+ case 2: {
+ // Assume a post llvm r300140 __compressed_pair implementation:
+ ValueObjectSP first_elem_parent_sp =
+ data_type_finder_sp->GetChildAtIndex(0, true);
+ data_type_finder_sp = first_elem_parent_sp->GetChildMemberWithName(
+ ConstString("__value_"), true);
+ break;
+ }
+ default:
+ return false;
+ }
+
if (!data_type_finder_sp)
return false;
m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();
@@ -133,9 +173,126 @@ size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
return ExtractIndexFromString(name.GetCString());
}
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
+ LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_bool_type(), m_exe_ctx_ref(),
+ m_count(0), m_base_data_address(0), m_children() {
+ if (valobj_sp) {
+ Update();
+ m_bool_type =
+ valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
+ }
+}
+
+size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
+ CalculateNumChildren() {
+ return m_count;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex(
+ size_t idx) {
+ auto iter = m_children.find(idx), end = m_children.end();
+ if (iter != end)
+ return iter->second;
+ if (idx >= m_count)
+ return ValueObjectSP();
+ if (m_base_data_address == 0 || m_count == 0)
+ return ValueObjectSP();
+ if (!m_bool_type)
+ return ValueObjectSP();
+ size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
+ size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
+ lldb::addr_t byte_location = m_base_data_address + byte_idx;
+ ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
+ if (!process_sp)
+ return ValueObjectSP();
+ uint8_t byte = 0;
+ uint8_t mask = 0;
+ Status err;
+ size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
+ if (err.Fail() || bytes_read == 0)
+ return ValueObjectSP();
+ mask = 1 << bit_index;
+ bool bit_set = ((byte & mask) != 0);
+ DataBufferSP buffer_sp(
+ new DataBufferHeap(m_bool_type.GetByteSize(nullptr), 0));
+ if (bit_set && buffer_sp && buffer_sp->GetBytes()) {
+ // regardless of endianness, anything non-zero is true
+ *(buffer_sp->GetBytes()) = 1;
+ }
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ ValueObjectSP retval_sp(CreateValueObjectFromData(
+ name.GetString(),
+ DataExtractor(buffer_sp, process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize()),
+ m_exe_ctx_ref, m_bool_type));
+ if (retval_sp)
+ m_children[idx] = retval_sp;
+ return retval_sp;
+}
+
+/*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
+ __begin_ = 0x00000001001000e0
+ __size_ = 56
+ __cap_alloc_ = {
+ std::__1::__libcpp_compressed_pair_imp<unsigned long,
+ std::__1::allocator<unsigned long> > = {
+ __first_ = 1
+ }
+ }
+ }*/
+
+bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ ValueObjectSP size_sp(
+ valobj_sp->GetChildMemberWithName(ConstString("__size_"), true));
+ if (!size_sp)
+ return false;
+ m_count = size_sp->GetValueAsUnsigned(0);
+ if (!m_count)
+ return true;
+ ValueObjectSP begin_sp(
+ valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true));
+ if (!begin_sp) {
+ m_count = 0;
+ return false;
+ }
+ m_base_data_address = begin_sp->GetValueAsUnsigned(0);
+ if (!m_base_data_address) {
+ m_count = 0;
+ return false;
+ }
+ return false;
+}
+
+size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
+ GetIndexOfChildWithName(const ConstString &name) {
+ if (!m_count || !m_base_data_address)
+ return UINT32_MAX;
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+}
+
lldb_private::SyntheticChildrenFrontEnd *
lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
- return (valobj_sp ? new LibcxxStdVectorSyntheticFrontEnd(valobj_sp)
- : nullptr);
+ if (!valobj_sp)
+ return nullptr;
+ CompilerType type = valobj_sp->GetCompilerType();
+ if (!type.IsValid() || type.GetNumTemplateArguments() == 0)
+ return nullptr;
+ TemplateArgumentKind kind;
+ CompilerType arg_type = type.GetTemplateArgument(0, kind);
+ if (arg_type.GetTypeName() == ConstString("bool"))
+ return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp);
+ return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp);
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
index f931a8d..e3018a1 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -13,16 +13,16 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/VectorIterator.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -209,7 +209,7 @@ bool VectorIteratorSyntheticFrontEnd::Update() {
return false;
if (item_ptr->GetValueAsUnsigned(0) == 0)
return false;
- Error err;
+ Status err;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
m_item_sp = CreateValueObjectFromAddress(
"item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
@@ -251,7 +251,7 @@ bool lldb_private::formatters::LibStdcppStringSummaryProvider(
return false;
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
- Error error;
+ Status error;
lldb::addr_t addr_of_data =
process_sp->ReadPointerFromMemory(addr_of_string, error);
if (error.Fail() || addr_of_data == 0 ||
@@ -308,7 +308,7 @@ bool lldb_private::formatters::LibStdcppWStringSummaryProvider(
nullptr); // Safe to pass NULL for exe_scope here
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
- Error error;
+ Status error;
lldb::addr_t addr_of_data =
process_sp->ReadPointerFromMemory(addr_of_string, error);
if (error.Fail() || addr_of_data == 0 ||
@@ -414,7 +414,7 @@ bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(
return true;
}
- Error error;
+ Status error;
ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
if (pointee_sp && error.Success()) {
if (pointee_sp->DumpPrintableRepresentation(
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
index 72e169f..1400477 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
@@ -10,10 +10,10 @@
#ifndef liblldb_LibStdCpp_h_
#define liblldb_LibStdCpp_h_
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
index c4a6e3d..943af6e 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
@@ -9,10 +9,10 @@
#include "LibStdcpp.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/ConstString.h"
#include <memory>
#include <vector>
@@ -73,9 +73,7 @@ bool LibStdcppTupleSyntheticFrontEnd::Update() {
if (value_sp) {
StreamString name;
name.Printf("[%zd]", m_members.size());
- value_sp->SetName(ConstString(name.GetString()));
-
- m_members.push_back(value_sp);
+ m_members.push_back(value_sp->Clone(ConstString(name.GetString())));
}
}
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp
index 4eb3b95..b6d664d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp
@@ -9,10 +9,10 @@
#include "LibStdcpp.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/ConstString.h"
#include <memory>
#include <vector>
@@ -70,19 +70,19 @@ bool LibStdcppUniquePtrSyntheticFrontEnd::Update() {
std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(
LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));
- m_ptr_obj = tuple_frontend->GetChildAtIndex(0);
- if (m_ptr_obj)
- m_ptr_obj->SetName(ConstString("pointer"));
+ ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(0);
+ if (ptr_obj)
+ m_ptr_obj = ptr_obj->Clone(ConstString("pointer"));
- m_del_obj = tuple_frontend->GetChildAtIndex(1);
- if (m_del_obj)
- m_del_obj->SetName(ConstString("deleter"));
+ ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1);
+ if (del_obj)
+ m_del_obj = del_obj->Clone(ConstString("deleter"));
if (m_ptr_obj) {
- Error error;
- m_obj_obj = m_ptr_obj->Dereference(error);
+ Status error;
+ ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
if (error.Success()) {
- m_obj_obj->SetName(ConstString("object"));
+ m_obj_obj = obj_obj->Clone(ConstString("object"));
}
}
@@ -94,29 +94,28 @@ bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; }
lldb::ValueObjectSP
LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
if (idx == 0)
- return m_obj_obj;
+ return m_ptr_obj;
if (idx == 1)
return m_del_obj;
if (idx == 2)
- return m_ptr_obj;
+ return m_obj_obj;
return lldb::ValueObjectSP();
}
size_t LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
if (m_del_obj)
return 2;
- if (m_ptr_obj && m_ptr_obj->GetValueAsUnsigned(0) != 0)
- return 1;
- return 0;
+ return 1;
}
size_t LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(
const ConstString &name) {
- if (name == ConstString("obj") || name == ConstString("object"))
+ if (name == ConstString("ptr") || name == ConstString("pointer"))
return 0;
if (name == ConstString("del") || name == ConstString("deleter"))
return 1;
- if (name == ConstString("ptr") || name == ConstString("pointer"))
+ if (name == ConstString("obj") || name == ConstString("object") ||
+ name == ConstString("$$dereference$$"))
return 2;
return UINT32_MAX;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.cpp
index 0f78f64..aac7520 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.cpp
@@ -96,7 +96,7 @@ bool lldb_private::formatters::GoStringSummaryProvider(
return false;
if (valobj.IsPointerType()) {
- Error err;
+ Status err;
ValueObjectSP deref = valobj.Dereference(err);
if (!err.Success())
return false;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.h b/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.h
index 596eb2a..1bf1892 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoFormatterFunctions.h
@@ -21,12 +21,12 @@
// Project includes
#include "lldb/lldb-forward.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/DataFormatters/FormatClasses.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.cpp
index 85c41d1..66b4530 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.cpp
@@ -15,14 +15,15 @@
// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Threading.h"
// Project includes
#include "GoLanguage.h"
#include "Plugins/Language/Go/GoFormatterFunctions.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Symbol/GoASTContext.h"
+#include "lldb/Utility/ConstString.h"
using namespace lldb;
using namespace lldb_private;
@@ -62,10 +63,10 @@ Language *GoLanguage::CreateInstance(lldb::LanguageType language) {
HardcodedFormatters::HardcodedSummaryFinder
GoLanguage::GetHardcodedSummaries() {
- static std::once_flag g_initialize;
+ static llvm::once_flag g_initialize;
static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
- std::call_once(g_initialize, []() -> void {
+ llvm::call_once(g_initialize, []() -> void {
g_formatters.push_back(
[](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
FormatManager &) -> TypeSummaryImpl::SharedPointer {
@@ -104,10 +105,10 @@ GoLanguage::GetHardcodedSummaries() {
HardcodedFormatters::HardcodedSyntheticFinder
GoLanguage::GetHardcodedSynthetics() {
- static std::once_flag g_initialize;
+ static llvm::once_flag g_initialize;
static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
- std::call_once(g_initialize, []() -> void {
+ llvm::call_once(g_initialize, []() -> void {
g_formatters.push_back(
[](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
FormatManager &fmt_mgr) -> SyntheticChildren::SharedPointer {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.h b/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.h
index 4dc8ed0..ebec1d7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/Go/GoLanguage.h
@@ -18,8 +18,8 @@
#include "llvm/ADT/StringRef.h"
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Target/Language.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaFormatterFunctions.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaFormatterFunctions.cpp
index 286651a..498795c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaFormatterFunctions.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaFormatterFunctions.cpp
@@ -57,7 +57,7 @@ public:
valobj->GetAddressOf() +
JavaASTContext::CalculateArrayElementOffset(type, idx);
- Error error;
+ Status error;
size_t byte_size = element_type.GetByteSize(nullptr);
DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0));
size_t bytes_read = process_sp->ReadMemory(address, buffer_sp->GetBytes(),
@@ -86,7 +86,7 @@ private:
if (!m_backend.IsPointerOrReferenceType())
return m_backend.GetSP();
- Error error;
+ Status error;
return m_backend.Dereference(error);
}
};
@@ -96,7 +96,7 @@ private:
bool lldb_private::formatters::JavaStringSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &opts) {
if (valobj.IsPointerOrReferenceType()) {
- Error error;
+ Status error;
ValueObjectSP deref = valobj.Dereference(error);
if (error.Fail())
return false;
@@ -145,7 +145,7 @@ bool lldb_private::formatters::JavaStringSummaryProvider(
bool lldb_private::formatters::JavaArraySummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
if (valobj.IsPointerOrReferenceType()) {
- Error error;
+ Status error;
ValueObjectSP deref = valobj.Dereference(error);
if (error.Fail())
return false;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.cpp
index f58b51f..b17862f 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.cpp
@@ -15,15 +15,16 @@
// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Threading.h"
// Project includes
#include "JavaFormatterFunctions.h"
#include "JavaLanguage.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Symbol/JavaASTContext.h"
+#include "lldb/Utility/ConstString.h"
using namespace lldb;
using namespace lldb_private;
@@ -64,10 +65,10 @@ bool JavaLanguage::IsNilReference(ValueObject &valobj) {
}
lldb::TypeCategoryImplSP JavaLanguage::GetFormatters() {
- static std::once_flag g_initialize;
+ static llvm::once_flag g_initialize;
static TypeCategoryImplSP g_category;
- std::call_once(g_initialize, [this]() -> void {
+ llvm::call_once(g_initialize, [this]() -> void {
DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
if (g_category) {
llvm::StringRef array_regexp("^.*\\[\\]&?$");
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.h b/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.h
index 6cf27ab..5b65250 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/Java/JavaLanguage.h
@@ -18,8 +18,8 @@
#include "llvm/ADT/StringRef.h"
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Target/Language.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/CMakeLists.txt
index e969618..e779ae2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/CMakeLists.txt
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/CMakeLists.txt
@@ -1,4 +1,12 @@
-add_lldb_library(lldbPluginOCamlLanguage
+add_lldb_library(lldbPluginOCamlLanguage PLUGIN
OCamlLanguage.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbDataFormatters
+ lldbSymbol
+ lldbTarget
+ LINK_COMPONENTS
+ Support
)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.cpp
index ef9f2b5..ec24a36 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.cpp
@@ -19,11 +19,11 @@
// Project includes
#include "OCamlLanguage.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Symbol/OCamlASTContext.h"
+#include "lldb/Utility/ConstString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.h b/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.h
index f7dc639..21837fe 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/OCaml/OCamlLanguage.h
@@ -19,8 +19,8 @@
#include "llvm/ADT/StringRef.h"
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Target/Language.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.cpp
index f67db46..9bb8eea 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.cpp
@@ -10,18 +10,18 @@
#include "CF.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -88,7 +88,7 @@ bool lldb_private::formatters::CFBagSummaryProvider(
if (is_type_ok) {
lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;
- Error error;
+ Status error;
count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
if (error.Fail())
return false;
@@ -152,7 +152,7 @@ bool lldb_private::formatters::CFBitVectorSummaryProvider(
if (is_type_ok == false)
return false;
- Error error;
+ Status error;
count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,
ptr_size, 0, error);
if (error.Fail())
@@ -281,7 +281,7 @@ bool lldb_private::formatters::CFBinaryHeapSummaryProvider(
if (is_type_ok) {
lldb::addr_t offset = 2 * ptr_size + valobj_addr;
- Error error;
+ Status error;
count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
if (error.Fail())
return false;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.h b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.h
index ea47267..6945f9e 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CF.h
@@ -10,9 +10,9 @@
#ifndef liblldb_CF_h_
#define liblldb_CF_h_
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
index b2ad8c3..8f49975 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp
@@ -13,22 +13,25 @@
// Project includes
#include "Cocoa.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/Mangled.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSummary.h"
-#include "lldb/Host/Endian.h"
+#include "lldb/Host/Time.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/Target.h"
-#include "lldb/Utility/ProcessStructReader.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+#include "llvm/ADT/APInt.h"
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
@@ -217,7 +220,7 @@ bool lldb_private::formatters::NSMachPortSummaryProvider(
if (!strcmp(class_name, "NSMachPort")) {
uint64_t offset = (ptr_size == 4 ? 12 : 20);
- Error error;
+ Status error;
port_number = process_sp->ReadUnsignedIntegerFromMemory(
offset + valobj_addr, 4, 0, error);
if (error.Success()) {
@@ -266,7 +269,7 @@ bool lldb_private::formatters::NSIndexSetSummaryProvider(
do {
if (!strcmp(class_name, "NSIndexSet") ||
!strcmp(class_name, "NSMutableIndexSet")) {
- Error error;
+ Status error;
uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(
valobj_addr + ptr_size, 4, 0, error);
if (error.Fail())
@@ -368,6 +371,28 @@ static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream,
stream.Printf("%s%" PRId64 "%s", prefix.c_str(), value, suffix.c_str());
}
+static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream,
+ const llvm::APInt &value,
+ lldb::LanguageType lang) {
+ static ConstString g_TypeHint("NSNumber:int128_t");
+
+ std::string prefix, suffix;
+ if (Language *language = Language::FindPlugin(lang)) {
+ if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
+ suffix)) {
+ prefix.clear();
+ suffix.clear();
+ }
+ }
+
+ stream.PutCString(prefix.c_str());
+ const int radix = 10;
+ const bool isSigned = true;
+ std::string str = value.toString(radix, isSigned);
+ stream.PutCString(str.c_str());
+ stream.PutCString(suffix.c_str());
+}
+
static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream,
float value, lldb::LanguageType lang) {
static ConstString g_TypeHint("NSNumber:float");
@@ -460,48 +485,100 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
}
return true;
} else {
- Error error;
- uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(
- valobj_addr + ptr_size, 1, 0, error) &
- 0x1F);
+ Status error;
+
+ AppleObjCRuntime *runtime =
+ llvm::dyn_cast_or_null<AppleObjCRuntime>(
+ process_sp->GetObjCLanguageRuntime());
+
+ const bool new_format =
+ (runtime && runtime->GetFoundationVersion() >= 1400);
+
+ enum class TypeCodes : int {
+ sint8 = 0x0,
+ sint16 = 0x1,
+ sint32 = 0x2,
+ sint64 = 0x3,
+ f32 = 0x4,
+ f64 = 0x5,
+ sint128 = 0x6
+ };
+
uint64_t data_location = valobj_addr + 2 * ptr_size;
+ TypeCodes type_code;
+
+ if (new_format) {
+ uint64_t cfinfoa =
+ process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+
+ if (error.Fail())
+ return false;
+
+ bool is_preserved_number = cfinfoa & 0x8;
+ if (is_preserved_number) {
+ lldbassert(!static_cast<bool>("We should handle preserved numbers!"));
+ return false;
+ }
+
+ type_code = static_cast<TypeCodes>(cfinfoa & 0x7);
+ } else {
+ uint8_t data_type =
+ process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1,
+ 0, error) & 0x1F;
+
+ if (error.Fail())
+ return false;
+
+ switch (data_type) {
+ case 1: type_code = TypeCodes::sint8; break;
+ case 2: type_code = TypeCodes::sint16; break;
+ case 3: type_code = TypeCodes::sint32; break;
+ case 17: data_location += 8; LLVM_FALLTHROUGH;
+ case 4: type_code = TypeCodes::sint64; break;
+ case 5: type_code = TypeCodes::f32; break;
+ case 6: type_code = TypeCodes::f64; break;
+ default: return false;
+ }
+ }
+
uint64_t value = 0;
- if (error.Fail())
- return false;
- switch (data_type) {
- case 1: // 0B00001
+ bool success = false;
+ switch (type_code) {
+ case TypeCodes::sint8:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
+ success = true;
break;
- case 2: // 0B0010
+ case TypeCodes::sint16:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatShort(valobj, stream, (short)value,
options.GetLanguage());
+ success = true;
break;
- case 3: // 0B0011
+ case TypeCodes::sint32:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
+ success = true;
break;
- case 17: // 0B10001
- data_location += 8;
- LLVM_FALLTHROUGH;
- case 4: // 0B0100
+ case TypeCodes::sint64:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
+ success = true;
break;
- case 5: // 0B0101
+ case TypeCodes::f32:
{
uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
data_location, 4, 0, error);
@@ -510,9 +587,10 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
float flt_value = 0.0f;
memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int));
NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
+ success = true;
break;
}
- case 6: // 0B0110
+ case TypeCodes::f64:
{
uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
data_location, 8, 0, error);
@@ -521,12 +599,27 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
double dbl_value = 0.0;
memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng));
NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
+ success = true;
break;
}
- default:
- return false;
+ case TypeCodes::sint128: // internally, this is the same
+ {
+ uint64_t words[2];
+ words[1] = process_sp->ReadUnsignedIntegerFromMemory(
+ data_location, 8, 0, error);
+ if (error.Fail())
+ return false;
+ words[0] = process_sp->ReadUnsignedIntegerFromMemory(
+ data_location + 8, 8, 0, error);
+ if (error.Fail())
+ return false;
+ llvm::APInt i128_value(128, words);
+ NSNumber_FormatInt128(valobj, stream, i128_value, options.GetLanguage());
+ success = true;
+ break;
}
- return true;
+ }
+ return success;
}
}
@@ -652,7 +745,7 @@ bool lldb_private::formatters::NSDateSummaryProvider(
process_sp->GetTarget().GetArchitecture().GetTriple());
uint32_t delta =
(triple.isWatchOS() && triple.isWatchABI()) ? 8 : ptr_size;
- Error error;
+ Status error;
date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
valobj_addr + delta, 8, 0, error);
memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
@@ -660,7 +753,7 @@ bool lldb_private::formatters::NSDateSummaryProvider(
return false;
}
} else if (class_name == g_NSCalendarDate) {
- Error error;
+ Status error;
date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
valobj_addr + 2 * ptr_size, 8, 0, error);
memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
@@ -787,14 +880,14 @@ bool lldb_private::formatters::NSDataSummaryProvider(
!strcmp(class_name, "NSConcreteMutableData") ||
!strcmp(class_name, "__NSCFData")) {
uint32_t offset = (is_64bit ? 16 : 8);
- Error error;
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(
valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
if (error.Fail())
return false;
} else if (!strcmp(class_name, "_NSInlineData")) {
uint32_t offset = (is_64bit ? 8 : 4);
- Error error;
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, 2,
0, error);
if (error.Fail())
@@ -817,7 +910,7 @@ bool lldb_private::formatters::ObjCBOOLSummaryProvider(
ValueObjectSP real_guy_sp = valobj.GetSP();
if (type_info & eTypeIsPointer) {
- Error err;
+ Status err;
real_guy_sp = valobj.Dereference(err);
if (err.Fail() || !real_guy_sp)
return false;
@@ -892,7 +985,7 @@ bool lldb_private::formatters::ObjCSELSummaryProvider(
exe_ctx, charstar);
} else {
DataExtractor data;
- Error error;
+ Status error;
valobj.GetData(data, error);
if (error.Fail())
return false;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.h b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.h
index 491a119..10ff3bc 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.h
@@ -11,11 +11,11 @@
#ifndef liblldb_Cocoa_h_
#define liblldb_Cocoa_h_
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp
index dacbf78..cbc38c9 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp
@@ -10,7 +10,8 @@
#include "CoreMedia.h"
-#include "lldb/Core/Flags.h"
+#include "lldb/Utility/Flags.h"
+
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Target.h"
#include <inttypes.h>
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.h b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.h
index 20de792..98561ef 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/CoreMedia.h
@@ -11,9 +11,9 @@
#ifndef liblldb_CoreMedia_h_
#define liblldb_CoreMedia_h_
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp
index 6ab6d53..27cb955 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp
@@ -16,18 +16,18 @@
#include "Cocoa.h"
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Expression/FunctionCaller.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -160,11 +160,47 @@ private:
DataDescriptor_64 *m_data_64;
};
-class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+class NSArrayMSyntheticFrontEnd_1400 : public NSArrayMSyntheticFrontEnd {
public:
- NSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+ NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp);
- ~NSArrayISyntheticFrontEnd() override = default;
+ ~NSArrayMSyntheticFrontEnd_1400() override;
+
+ bool Update() override;
+
+protected:
+ lldb::addr_t GetDataAddress() override;
+
+ uint64_t GetUsedCount() override;
+
+ uint64_t GetOffset() override;
+
+ uint64_t GetSize() override;
+
+private:
+ struct DataDescriptor_32 {
+ uint32_t used;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t list;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t used;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t list;
+ };
+
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+};
+
+class NSArrayISyntheticFrontEnd_1300 : public SyntheticChildrenFrontEnd {
+public:
+ NSArrayISyntheticFrontEnd_1300(lldb::ValueObjectSP valobj_sp);
+
+ ~NSArrayISyntheticFrontEnd_1300() override = default;
size_t CalculateNumChildren() override;
@@ -184,6 +220,45 @@ private:
CompilerType m_id_type;
};
+class NSArrayISyntheticFrontEnd_1400 : public SyntheticChildrenFrontEnd {
+public:
+ NSArrayISyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp);
+
+ ~NSArrayISyntheticFrontEnd_1400() override;
+
+ size_t CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+ bool Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(const ConstString &name) override;
+
+private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+
+ struct DataDescriptor_32 {
+ uint32_t used;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t list;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t used;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t list;
+ };
+
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ CompilerType m_id_type;
+};
+
class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
@@ -257,18 +332,32 @@ bool lldb_private::formatters::NSArraySummaryProvider(
static const ConstString g_NSArray0("__NSArray0");
static const ConstString g_NSArray1("__NSSingleObjectArrayI");
static const ConstString g_NSArrayCF("__NSCFArray");
+ static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
+ static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
if (class_name.IsEmpty())
return false;
if (class_name == g_NSArrayI) {
- Error error;
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
return false;
} else if (class_name == g_NSArrayM) {
- Error error;
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSArrayMLegacy) {
+ Status error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
+ ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ } else if (class_name == g_NSArrayMImmutable) {
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
@@ -278,7 +367,7 @@ bool lldb_private::formatters::NSArraySummaryProvider(
} else if (class_name == g_NSArray1) {
value = 1;
} else if (class_name == g_NSArrayCF) {
- Error error;
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(
valobj_addr + 2 * ptr_size, ptr_size, 0, error);
if (error.Fail())
@@ -332,6 +421,11 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::
: NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr),
m_data_64(nullptr) {}
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::
+ NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp)
+ : NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr),
+ m_data_64(nullptr) {}
+
size_t
lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren() {
return GetUsedCount();
@@ -364,7 +458,7 @@ bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_109::Update() {
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
- Error error;
+ Status error;
error.Clear();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
@@ -395,7 +489,38 @@ bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::Update() {
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
- Error error;
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ error);
+ } else {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
+bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
error.Clear();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
@@ -498,7 +623,42 @@ uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize() {
return m_data_32 ? m_data_32->_size : m_data_64->_size;
}
-lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd(
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::
+ ~NSArrayMSyntheticFrontEnd_1400() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+lldb::addr_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetDataAddress() {
+ if (!m_data_32 && !m_data_64)
+ return LLDB_INVALID_ADDRESS;
+ return m_data_32 ? m_data_32->list : m_data_64->list;
+}
+
+uint64_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetUsedCount() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->used : m_data_64->used;
+}
+
+uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetOffset() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->offset : m_data_64->offset;
+}
+
+uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetSize() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return m_data_32 ? m_data_32->size : m_data_64->size;
+}
+
+
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::NSArrayISyntheticFrontEnd_1300(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
m_items(0), m_data_ptr(0) {
@@ -516,7 +676,7 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd(
}
size_t
-lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName(
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetIndexOfChildWithName(
const ConstString &name) {
const char *item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
@@ -526,11 +686,11 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName(
}
size_t
-lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren() {
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::CalculateNumChildren() {
return m_items;
}
-bool lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() {
+bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::Update() {
m_ptr_size = 0;
m_items = 0;
m_data_ptr = 0;
@@ -538,7 +698,7 @@ bool lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() {
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
- Error error;
+ Status error;
error.Clear();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
@@ -552,12 +712,12 @@ bool lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() {
return false;
}
-bool lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren() {
+bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::MightHaveChildren() {
return true;
}
lldb::ValueObjectSP
-lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex(
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetChildAtIndex(
size_t idx) {
if (idx >= CalculateNumChildren())
return lldb::ValueObjectSP();
@@ -566,7 +726,100 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex(
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
if (!process_sp)
return lldb::ValueObjectSP();
- Error error;
+ Status error;
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
+ m_exe_ctx_ref, m_id_type);
+}
+
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::NSArrayISyntheticFrontEnd_1400(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
+ m_data_32(nullptr), m_data_64(nullptr) {
+ if (valobj_sp) {
+ CompilerType type = valobj_sp->GetCompilerType();
+ if (type) {
+ ClangASTContext *ast = valobj_sp->GetExecutionContextRef()
+ .GetTargetSP()
+ ->GetScratchClangASTContext();
+ if (ast)
+ m_id_type = CompilerType(ast->getASTContext(),
+ ast->getASTContext()->ObjCBuiltinIdTy);
+ }
+ }
+}
+
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::~NSArrayISyntheticFrontEnd_1400() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+size_t
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetIndexOfChildWithName(
+ const ConstString &name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+}
+
+size_t
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::CalculateNumChildren() {
+ return m_data_32 ? m_data_32->used : m_data_64->used;
+}
+
+bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ error);
+ } else {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
+bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetChildAtIndex(
+ size_t idx) {
+ if (idx >= CalculateNumChildren())
+ return lldb::ValueObjectSP();
+ lldb::addr_t object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
+ object_at_idx += (idx * m_ptr_size);
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
if (error.Fail())
return lldb::ValueObjectSP();
StreamString idx_name;
@@ -665,7 +918,7 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator(
Flags flags(valobj_type.GetTypeInfo());
if (flags.IsClear(eTypeIsPointer)) {
- Error error;
+ Status error;
valobj_sp = valobj_sp->AddressOf(error);
if (error.Fail() || !valobj_sp)
return nullptr;
@@ -683,17 +936,24 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator(
static const ConstString g_NSArrayM("__NSArrayM");
static const ConstString g_NSArray0("__NSArray0");
static const ConstString g_NSArray1("__NSSingleObjectArrayI");
+ static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
+ static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
if (class_name.IsEmpty())
return nullptr;
if (class_name == g_NSArrayI) {
- return (new NSArrayISyntheticFrontEnd(valobj_sp));
+ if (runtime->GetFoundationVersion() >= 1400)
+ return (new NSArrayISyntheticFrontEnd_1400(valobj_sp));
+ else
+ return (new NSArrayISyntheticFrontEnd_1300(valobj_sp));
} else if (class_name == g_NSArray0) {
return (new NSArray0SyntheticFrontEnd(valobj_sp));
} else if (class_name == g_NSArray1) {
return (new NSArray1SyntheticFrontEnd(valobj_sp));
} else if (class_name == g_NSArrayM) {
+ if (runtime->GetFoundationVersion() >= 1400)
+ return (new NSArrayMSyntheticFrontEnd_1400(valobj_sp));
if (runtime->GetFoundationVersion() >= 1100)
return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp));
else
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
index 5cc52c8..50febbe 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -17,18 +17,20 @@
// Project includes
#include "NSDictionary.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
+
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -181,6 +183,52 @@ public:
private:
struct DataDescriptor_32 {
+ uint32_t used : 26;
+ uint32_t kvo : 1;
+ uint32_t size;
+ uint32_t buffer;
+ };
+
+ struct DataDescriptor_64 {
+ uint64_t used : 58;
+ uint32_t kvo : 1;
+ uint64_t size;
+ uint64_t buffer;
+ };
+
+ struct DictionaryItemDescriptor {
+ lldb::addr_t key_ptr;
+ lldb::addr_t val_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ lldb::ByteOrder m_order;
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ CompilerType m_pair_type;
+ std::vector<DictionaryItemDescriptor> m_children;
+};
+
+class NSDictionaryMLegacySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~NSDictionaryMLegacySyntheticFrontEnd() override;
+
+ size_t CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+ bool Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(const ConstString &name) override;
+
+private:
+ struct DataDescriptor_32 {
uint32_t _used : 26;
uint32_t _kvo : 1;
uint32_t _size;
@@ -250,20 +298,22 @@ bool lldb_private::formatters::NSDictionarySummaryProvider(
static const ConstString g_DictionaryI("__NSDictionaryI");
static const ConstString g_DictionaryM("__NSDictionaryM");
+ static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
+ static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
if (class_name.IsEmpty())
return false;
- if (class_name == g_DictionaryI) {
- Error error;
+ if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
return false;
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
- } else if (class_name == g_DictionaryM) {
- Error error;
+ } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) {
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
@@ -274,7 +324,7 @@ bool lldb_private::formatters::NSDictionarySummaryProvider(
}
/*else if (!strcmp(class_name,"__NSCFDictionary"))
{
- Error error;
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ?
20 : 12), 4, 0, error);
if (error.Fail())
@@ -311,9 +361,8 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
return nullptr;
- ObjCLanguageRuntime *runtime =
- (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
- lldb::eLanguageTypeObjC);
+ AppleObjCRuntime *runtime =
+ llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
if (!runtime)
return nullptr;
@@ -321,7 +370,7 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
Flags flags(valobj_type.GetTypeInfo());
if (flags.IsClear(eTypeIsPointer)) {
- Error error;
+ Status error;
valobj_sp = valobj_sp->AddressOf(error);
if (error.Fail() || !valobj_sp)
return nullptr;
@@ -338,6 +387,8 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
static const ConstString g_DictionaryI("__NSDictionaryI");
static const ConstString g_DictionaryM("__NSDictionaryM");
static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
+ static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
+ static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
if (class_name.IsEmpty())
return nullptr;
@@ -345,7 +396,13 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
if (class_name == g_DictionaryI) {
return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
} else if (class_name == g_DictionaryM) {
- return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
+ if (runtime->GetFoundationVersion() > 1400) {
+ return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
+ } else {
+ return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp));
+ }
+ } else if (class_name == g_DictionaryMLegacy) {
+ return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp));
} else if (class_name == g_Dictionary1) {
return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
} else {
@@ -400,7 +457,7 @@ bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() {
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
- Error error;
+ Status error;
error.Clear();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
@@ -449,7 +506,7 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
if (!process_sp)
return lldb::ValueObjectSP();
- Error error;
+ Status error;
key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
if (error.Fail())
return lldb::ValueObjectSP();
@@ -553,7 +610,7 @@ lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
lldb::addr_t value_ptr = key_ptr + ptr_size;
- Error error;
+ Status error;
lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
if (error.Fail())
@@ -611,7 +668,7 @@ size_t lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::
CalculateNumChildren() {
if (!m_data_32 && !m_data_64)
return 0;
- return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+ return (m_data_32 ? m_data_32->used : m_data_64->used);
}
bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() {
@@ -625,7 +682,7 @@ bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() {
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
- Error error;
+ Status error;
error.Clear();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
@@ -655,6 +712,165 @@ bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::
lldb::ValueObjectSP
lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(
size_t idx) {
+ lldb::addr_t m_keys_ptr;
+ lldb::addr_t m_values_ptr;
+ if (m_data_32) {
+ uint32_t size = m_data_32->size;
+ m_keys_ptr = m_data_32->buffer;
+ m_values_ptr = m_data_32->buffer + (m_ptr_size * size);
+ } else {
+ uint32_t size = m_data_64->size;
+ m_keys_ptr = m_data_64->buffer;
+ m_values_ptr = m_data_64->buffer + (m_ptr_size * size);
+ }
+
+ uint32_t num_children = CalculateNumChildren();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty()) {
+ // do the scan phase
+ lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ while (tries < num_children) {
+ key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
+ val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
+ ;
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Status error;
+ key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!key_at_idx || !val_at_idx)
+ continue;
+ tries++;
+
+ DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
+ lldb::ValueObjectSP()};
+
+ m_children.push_back(descriptor);
+ }
+ }
+
+ if (idx >= m_children.size()) // should never happen
+ return lldb::ValueObjectSP();
+
+ DictionaryItemDescriptor &dict_item = m_children[idx];
+ if (!dict_item.valobj_sp) {
+ if (!m_pair_type.IsValid()) {
+ TargetSP target_sp(m_backend.GetTargetSP());
+ if (!target_sp)
+ return ValueObjectSP();
+ m_pair_type = GetLLDBNSPairType(target_sp);
+ }
+ if (!m_pair_type.IsValid())
+ return ValueObjectSP();
+
+ DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
+
+ if (m_ptr_size == 8) {
+ uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ } else {
+ uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr + 1) = dict_item.val_ptr;
+ }
+
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ DataExtractor data(buffer_sp, m_order, m_ptr_size);
+ dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+ m_exe_ctx_ref, m_pair_type);
+ }
+ return dict_item.valobj_sp;
+}
+
+
+lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
+ m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
+ m_pair_type() {}
+
+lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ ~NSDictionaryMLegacySyntheticFrontEnd() {
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+}
+
+size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ GetIndexOfChildWithName(const ConstString &name) {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+}
+
+size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ CalculateNumChildren() {
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+}
+
+bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = nullptr;
+ delete m_data_64;
+ m_data_64 = nullptr;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Status error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4) {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ error);
+ } else {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
+bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::GetChildAtIndex(
+ size_t idx) {
lldb::addr_t m_keys_ptr =
(m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
lldb::addr_t m_values_ptr =
@@ -679,7 +895,7 @@ lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
if (!process_sp)
return lldb::ValueObjectSP();
- Error error;
+ Status error;
key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
if (error.Fail())
return lldb::ValueObjectSP();
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.h b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.h
index 10318a5..6ec9a8e 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.h
@@ -11,11 +11,11 @@
#ifndef liblldb_NSDictionary_h_
#define liblldb_NSDictionary_h_
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
#include <map>
#include <memory>
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSError.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSError.cpp
index bad22b1..4365a12 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSError.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSError.cpp
@@ -15,18 +15,17 @@
// Project includes
#include "Cocoa.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/Target.h"
-
-#include "lldb/Utility/ProcessStructReader.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
#include "Plugins/Language/ObjC/NSString.h"
@@ -47,7 +46,7 @@ static lldb::addr_t DerefToNSErrorPointer(ValueObject &valobj) {
Flags pointee_flags(pointee_type.GetTypeInfo());
if (pointee_flags.AllSet(eTypeIsPointer)) {
if (ProcessSP process_sp = valobj.GetProcessSP()) {
- Error error;
+ Status error;
ptr_value = process_sp->ReadPointerFromMemory(ptr_value, error);
}
}
@@ -72,7 +71,7 @@ bool lldb_private::formatters::NSError_SummaryProvider(
lldb::addr_t code_location = ptr_value + 2 * ptr_size;
lldb::addr_t domain_location = ptr_value + 3 * ptr_size;
- Error error;
+ Status error;
uint64_t code = process_sp->ReadUnsignedIntegerFromMemory(code_location,
ptr_size, 0, error);
if (error.Fail())
@@ -153,7 +152,7 @@ public:
size_t ptr_size = process_sp->GetAddressByteSize();
userinfo_location += 4 * ptr_size;
- Error error;
+ Status error;
lldb::addr_t userinfo =
process_sp->ReadPointerFromMemory(userinfo_location, error);
if (userinfo == LLDB_INVALID_ADDRESS || error.Fail())
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSException.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSException.cpp
index 1609048..1da4f6d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSException.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSException.cpp
@@ -15,18 +15,17 @@
// Project includes
#include "Cocoa.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/Target.h"
-
-#include "lldb/Utility/ProcessStructReader.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
#include "Plugins/Language/ObjC/NSString.h"
@@ -56,7 +55,7 @@ bool lldb_private::formatters::NSException_SummaryProvider(
lldb::addr_t name_location = ptr_value + 1 * ptr_size;
lldb::addr_t reason_location = ptr_value + 2 * ptr_size;
- Error error;
+ Status error;
lldb::addr_t name = process_sp->ReadPointerFromMemory(name_location, error);
if (error.Fail() || name == LLDB_INVALID_ADDRESS)
return false;
@@ -147,7 +146,7 @@ public:
size_t ptr_size = process_sp->GetAddressByteSize();
userinfo_location += 3 * ptr_size;
- Error error;
+ Status error;
lldb::addr_t userinfo =
process_sp->ReadPointerFromMemory(userinfo_location, error);
if (userinfo == LLDB_INVALID_ADDRESS || error.Fail())
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.cpp
index 9757c58..2f33987 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.cpp
@@ -13,17 +13,18 @@
// Project includes
#include "NSSet.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -84,11 +85,12 @@ private:
std::vector<SetItemDescriptor> m_children;
};
-class NSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+template <typename D32, typename D64>
+class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
- NSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+ GenericNSSetMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
- ~NSSetMSyntheticFrontEnd() override;
+ ~GenericNSSetMSyntheticFrontEnd() override;
size_t CalculateNumChildren() override;
@@ -101,32 +103,57 @@ public:
size_t GetIndexOfChildWithName(const ConstString &name) override;
private:
+
+ struct SetItemDescriptor {
+ lldb::addr_t item_ptr;
+ lldb::ValueObjectSP valobj_sp;
+ };
+
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ D32 *m_data_32;
+ D64 *m_data_64;
+ std::vector<SetItemDescriptor> m_children;
+};
+
+namespace Foundation1300 {
struct DataDescriptor_32 {
uint32_t _used : 26;
uint32_t _size;
uint32_t _mutations;
uint32_t _objs_addr;
};
-
+
struct DataDescriptor_64 {
uint64_t _used : 58;
uint64_t _size;
uint64_t _mutations;
uint64_t _objs_addr;
};
-
- struct SetItemDescriptor {
- lldb::addr_t item_ptr;
- lldb::ValueObjectSP valobj_sp;
+
+ using NSSetMSyntheticFrontEnd =
+ GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+}
+
+namespace Foundation1400 {
+ struct DataDescriptor_32 {
+ uint32_t _used : 26;
+ uint32_t _size;
+ uint32_t _objs_addr;
+ uint32_t _mutations;
};
-
- ExecutionContextRef m_exe_ctx_ref;
- uint8_t m_ptr_size;
- DataDescriptor_32 *m_data_32;
- DataDescriptor_64 *m_data_64;
- std::vector<SetItemDescriptor> m_children;
-};
-
+
+ struct DataDescriptor_64 {
+ uint64_t _used : 58;
+ uint64_t _size;
+ uint64_t _objs_addr;
+ uint64_t _mutations;
+ };
+
+ using NSSetMSyntheticFrontEnd =
+ GenericNSSetMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
+}
+
class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
NSSetCodeRunningSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
@@ -185,14 +212,14 @@ bool lldb_private::formatters::NSSetSummaryProvider(
return false;
if (!strcmp(class_name, "__NSSetI")) {
- Error error;
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
return false;
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
} else if (!strcmp(class_name, "__NSSetM")) {
- Error error;
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
@@ -201,7 +228,7 @@ bool lldb_private::formatters::NSSetSummaryProvider(
}
/*else if (!strcmp(class_name,"__NSCFSet"))
{
- Error error;
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ?
20 : 12), 4, 0, error);
if (error.Fail())
@@ -211,7 +238,7 @@ bool lldb_private::formatters::NSSetSummaryProvider(
}
else if (!strcmp(class_name,"NSCountedSet"))
{
- Error error;
+ Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
@@ -262,7 +289,7 @@ lldb_private::formatters::NSSetSyntheticFrontEndCreator(
Flags flags(valobj_type.GetTypeInfo());
if (flags.IsClear(eTypeIsPointer)) {
- Error error;
+ Status error;
valobj_sp = valobj_sp->AddressOf(error);
if (error.Fail() || !valobj_sp)
return nullptr;
@@ -283,7 +310,12 @@ lldb_private::formatters::NSSetSyntheticFrontEndCreator(
if (!strcmp(class_name, "__NSSetI")) {
return (new NSSetISyntheticFrontEnd(valobj_sp));
} else if (!strcmp(class_name, "__NSSetM")) {
- return (new NSSetMSyntheticFrontEnd(valobj_sp));
+ AppleObjCRuntime *apple_runtime =
+ llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
+ if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1400)
+ return (new Foundation1400::NSSetMSyntheticFrontEnd(valobj_sp));
+ else
+ return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
} else {
auto &map(NSSet_Additionals::GetAdditionalSynthetics());
auto iter = map.find(class_name_cs), end = map.end();
@@ -338,7 +370,7 @@ bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
- Error error;
+ Status error;
if (valobj_sp->IsPointerType()) {
valobj_sp = valobj_sp->Dereference(error);
if (error.Fail() || !valobj_sp)
@@ -391,7 +423,7 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) {
obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
if (!process_sp)
return lldb::ValueObjectSP();
- Error error;
+ Status error;
obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
if (error.Fail())
return lldb::ValueObjectSP();
@@ -442,7 +474,9 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) {
return set_item.valobj_sp;
}
-lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd(
+template <typename D32, typename D64>
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::GenericNSSetMSyntheticFrontEnd(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
m_data_32(nullptr), m_data_64(nullptr) {
@@ -450,15 +484,19 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd(
Update();
}
-lldb_private::formatters::NSSetMSyntheticFrontEnd::~NSSetMSyntheticFrontEnd() {
+template <typename D32, typename D64>
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd() {
delete m_data_32;
m_data_32 = nullptr;
delete m_data_64;
m_data_64 = nullptr;
}
+template <typename D32, typename D64>
size_t
-lldb_private::formatters::NSSetMSyntheticFrontEnd::GetIndexOfChildWithName(
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::GetIndexOfChildWithName(
const ConstString &name) {
const char *item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
@@ -467,14 +505,19 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::GetIndexOfChildWithName(
return idx;
}
+template <typename D32, typename D64>
size_t
-lldb_private::formatters::NSSetMSyntheticFrontEnd::CalculateNumChildren() {
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::CalculateNumChildren() {
if (!m_data_32 && !m_data_64)
return 0;
return (m_data_32 ? m_data_32->_used : m_data_64->_used);
}
-bool lldb_private::formatters::NSSetMSyntheticFrontEnd::Update() {
+template <typename D32, typename D64>
+bool
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() {
m_children.clear();
ValueObjectSP valobj_sp = m_backend.GetSP();
m_ptr_size = 0;
@@ -487,7 +530,7 @@ bool lldb_private::formatters::NSSetMSyntheticFrontEnd::Update() {
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
- Error error;
+ Status error;
if (valobj_sp->IsPointerType()) {
valobj_sp = valobj_sp->Dereference(error);
if (error.Fail() || !valobj_sp)
@@ -500,12 +543,12 @@ bool lldb_private::formatters::NSSetMSyntheticFrontEnd::Update() {
m_ptr_size = process_sp->GetAddressByteSize();
uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
if (m_ptr_size == 4) {
- m_data_32 = new DataDescriptor_32();
- process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
+ m_data_32 = new D32();
+ process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
error);
} else {
- m_data_64 = new DataDescriptor_64();
- process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
+ m_data_64 = new D64();
+ process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
error);
}
if (error.Fail())
@@ -513,12 +556,17 @@ bool lldb_private::formatters::NSSetMSyntheticFrontEnd::Update() {
return false;
}
-bool lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren() {
+template <typename D32, typename D64>
+bool
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::MightHaveChildren() {
return true;
}
+template <typename D32, typename D64>
lldb::ValueObjectSP
-lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
+lldb_private::formatters::
+ GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(size_t idx) {
lldb::addr_t m_objs_addr =
(m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
@@ -542,7 +590,7 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
if (!process_sp)
return lldb::ValueObjectSP();
- Error error;
+ Status error;
obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
if (error.Fail())
return lldb::ValueObjectSP();
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.h b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.h
index dbc5dfa..00451be 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSSet.h
@@ -11,11 +11,11 @@
#ifndef liblldb_NSSet_h_
#define liblldb_NSSet_h_
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.cpp
index 4f1addc..3b4edf6 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.cpp
@@ -10,18 +10,18 @@
#include "NSString.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
+#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/Target.h"
-#include "lldb/Utility/ProcessStructReader.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -103,7 +103,7 @@ bool lldb_private::formatters::NSStringSummaryProvider(
if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
info_bits_location += 3;
- Error error;
+ Status error;
uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(
info_bits_location, 1, 0, error);
@@ -258,7 +258,7 @@ bool lldb_private::formatters::NSStringSummaryProvider(
// in this kind of string, the byte before the string content is a length
// byte
// so let's try and use it to handle the embedded NUL case
- Error error;
+ Status error;
explicit_length =
process_sp->ReadUnsignedIntegerFromMemory(location, 1, 0, error);
if (error.Fail() || explicit_length == 0)
@@ -319,7 +319,7 @@ bool lldb_private::formatters::NSAttributedStringSummaryProvider(
if (!child_ptr_sp)
return false;
DataExtractor data;
- Error error;
+ Status error;
child_ptr_sp->GetData(data, error);
if (error.Fail())
return false;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.h b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.h
index df8480a..3a923c2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSString.h
@@ -11,10 +11,10 @@
#ifndef liblldb_NSString_h_
#define liblldb_NSString_h_
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Utility/Stream.h"
namespace lldb_private {
namespace formatters {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
index 6e59a8b..ea2eec7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -15,9 +15,7 @@
// Project includes
#include "ObjCLanguage.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
@@ -25,6 +23,10 @@
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "llvm/Support/Threading.h"
#include "CF.h"
#include "Cocoa.h"
@@ -93,7 +95,7 @@ bool ObjCLanguage::MethodName::SetName(llvm::StringRef name, bool strict) {
// or '-' can be omitted
bool valid_prefix = false;
- if (name[0] == '+' || name[0] == '-') {
+ if (name.size() > 1 && (name[0] == '+' || name[0] == '-')) {
valid_prefix = name[1] == '[';
if (name[0] == '+')
m_type = eTypeClassMethod;
@@ -857,10 +859,10 @@ static void LoadCoreMediaFormatters(TypeCategoryImplSP objc_category_sp) {
}
lldb::TypeCategoryImplSP ObjCLanguage::GetFormatters() {
- static std::once_flag g_initialize;
+ static llvm::once_flag g_initialize;
static TypeCategoryImplSP g_category;
- std::call_once(g_initialize, [this]() -> void {
+ llvm::call_once(g_initialize, [this]() -> void {
DataVisualization::Categories::GetCategory(GetPluginName(), g_category);
if (g_category) {
LoadCoreMediaFormatters(g_category);
@@ -1024,6 +1026,7 @@ bool ObjCLanguage::GetFormatterPrefixSuffix(ValueObject &valobj,
static ConstString g_NSNumberShort("NSNumber:short");
static ConstString g_NSNumberInt("NSNumber:int");
static ConstString g_NSNumberLong("NSNumber:long");
+ static ConstString g_NSNumberInt128("NSNumber:int128_t");
static ConstString g_NSNumberFloat("NSNumber:float");
static ConstString g_NSNumberDouble("NSNumber:double");
@@ -1059,6 +1062,10 @@ bool ObjCLanguage::GetFormatterPrefixSuffix(ValueObject &valobj,
prefix = "(long)";
return true;
}
+ if (type_hint == g_NSNumberInt128) {
+ prefix = "(int128_t)";
+ return true;
+ }
if (type_hint == g_NSNumberFloat) {
prefix = "(float)";
return true;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
index b458b58..9782c5d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
@@ -17,8 +17,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Target/Language.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
index cb73eef..bfc22c9 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
@@ -10,8 +10,8 @@
#include "ObjCPlusPlusLanguage.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Utility/ConstString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index ddfbd864..e5a459d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -11,9 +11,6 @@
#include "ItaniumABILanguageRuntime.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
@@ -33,6 +30,9 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include <vector>
@@ -217,7 +217,7 @@ bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress(
if (process == nullptr)
return false;
- Error error;
+ Status error;
const lldb::addr_t vtable_address_point =
process->ReadPointerFromMemory(original_ptr, error);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp
index 1450835..6670f89 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp
@@ -11,9 +11,6 @@
#include "GoLanguageRuntime.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
@@ -29,6 +26,9 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "llvm/ADT/Twine.h"
#include <vector>
@@ -42,7 +42,7 @@ ValueObjectSP GetChild(ValueObject &obj, const char *name,
ConstString name_const_str(name);
ValueObjectSP result = obj.GetChildMemberWithName(name_const_str, true);
if (dereference && result && result->IsPointerType()) {
- Error err;
+ Status err;
result = result->Dereference(err);
if (err.Fail())
result.reset();
@@ -55,7 +55,7 @@ ConstString ReadString(ValueObject &str, Process *process) {
ValueObjectSP data = GetChild(str, "str", false);
ValueObjectSP len = GetChild(str, "len");
if (len && data) {
- Error err;
+ Status err;
lldb::addr_t addr = data->GetPointerValue();
if (addr == LLDB_INVALID_ADDRESS)
return result;
@@ -97,7 +97,7 @@ CompilerType LookupRuntimeType(ValueObjectSP type, ExecutionContext *exe_ctx,
*is_direct = GoASTContext::IsDirectIface(kind);
if (GoASTContext::IsPointerKind(kind)) {
CompilerType type_ptr = type->GetCompilerType().GetPointerType();
- Error err;
+ Status err;
ValueObjectSP elem =
type->CreateValueObjectFromAddress("elem", type->GetAddressOf() +
type->GetByteSize(),
@@ -138,7 +138,7 @@ bool GoLanguageRuntime::GetDynamicTypeAndAddress(
value_type = Value::eValueTypeScalar;
class_type_or_name.Clear();
if (CouldHaveDynamicValue(in_value)) {
- Error err;
+ Status err;
ValueObjectSP iface = in_value.GetStaticValue();
ValueObjectSP data_sp = GetChild(*iface, "data", false);
if (!data_sp)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
index 131f31f..ecb0b64 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
@@ -10,8 +10,8 @@
#include "AppleObjCClassDescriptorV2.h"
-#include "lldb/Core/Log.h"
#include "lldb/Expression/FunctionCaller.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -52,7 +52,7 @@ bool ClassDescriptorV2::objc_class_t::Read(Process *process,
+ ptr_size; // uintptr_t data_NEVER_USE;
DataBufferHeap objc_class_buf(objc_class_size, '\0');
- Error error;
+ Status error;
process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error);
if (error.Fail()) {
@@ -92,7 +92,7 @@ bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) {
+ ptr_size; // Class nextSiblingClass;
DataBufferHeap buffer(size, '\0');
- Error error;
+ Status error;
process->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail()) {
@@ -132,7 +132,7 @@ bool ClassDescriptorV2::class_ro_t::Read(Process *process, lldb::addr_t addr) {
+ ptr_size; // const property_list_t *baseProperties;
DataBufferHeap buffer(size, '\0');
- Error error;
+ Status error;
process->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail()) {
@@ -180,7 +180,7 @@ bool ClassDescriptorV2::Read_class_row(
class_ro.reset();
class_rw.reset();
- Error error;
+ Status error;
uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory(
objc_class.m_data_ptr, sizeof(uint32_t), 0, error);
if (!error.Success())
@@ -219,7 +219,7 @@ bool ClassDescriptorV2::method_list_t::Read(Process *process,
+ sizeof(uint32_t); // uint32_t count;
DataBufferHeap buffer(size, '\0');
- Error error;
+ Status error;
process->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail()) {
@@ -242,7 +242,7 @@ bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) {
size_t size = GetSize(process);
DataBufferHeap buffer(size, '\0');
- Error error;
+ Status error;
process->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail()) {
@@ -276,7 +276,7 @@ bool ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) {
+ sizeof(uint32_t); // uint32_t count;
DataBufferHeap buffer(size, '\0');
- Error error;
+ Status error;
process->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail()) {
@@ -299,7 +299,7 @@ bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) {
size_t size = GetSize(process);
DataBufferHeap buffer(size, '\0');
- Error error;
+ Status error;
process->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail()) {
@@ -501,10 +501,8 @@ void ClassDescriptorV2::iVarsStorage::fill(AppleObjCRuntimeV2 &runtime,
if (m_filled)
return;
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES | LIBLLDB_LOG_VERBOSE));
- if (log)
- log->Printf("[ClassDescriptorV2::iVarsStorage::fill] class_name = %s",
- descriptor.GetClassName().AsCString("<unknown"));
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
+ LLDB_LOGV(log, "class_name = {0}", descriptor.GetClassName());
m_filled = true;
ObjCLanguageRuntime::EncodingToTypeSP encoding_to_type_sp(
runtime.GetEncodingToType());
@@ -519,38 +517,29 @@ void ClassDescriptorV2::iVarsStorage::fill(AppleObjCRuntimeV2 &runtime,
uint64_t size) -> bool {
const bool for_expression = false;
const bool stop_loop = false;
- if (log)
- log->Printf("[ClassDescriptorV2::iVarsStorage::fill] name = %s, encoding "
- "= %s, offset_ptr = %" PRIx64 ", size = %" PRIu64,
- name, type, offset_ptr, size);
+ LLDB_LOGV(log, "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = {3}",
+ name, type, offset_ptr, size);
CompilerType ivar_type =
encoding_to_type_sp->RealizeType(type, for_expression);
if (ivar_type) {
- if (log)
- log->Printf("[ClassDescriptorV2::iVarsStorage::fill] name = %s, "
- "encoding = %s, offset_ptr = %" PRIx64 ", size = %" PRIu64
- " , type_size = %" PRIu64,
- name, type, offset_ptr, size,
- ivar_type.GetByteSize(nullptr));
+ LLDB_LOGV(log,
+ "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = "
+ "{3}, type_size = {4}",
+ name, type, offset_ptr, size, ivar_type.GetByteSize(nullptr));
Scalar offset_scalar;
- Error error;
+ Status error;
const int offset_ptr_size = 4;
const bool is_signed = false;
size_t read = process->ReadScalarIntegerFromMemory(
offset_ptr, offset_ptr_size, is_signed, offset_scalar, error);
if (error.Success() && 4 == read) {
- if (log)
- log->Printf(
- "[ClassDescriptorV2::iVarsStorage::fill] offset_ptr = %" PRIx64
- " --> %" PRIu32,
- offset_ptr, offset_scalar.SInt());
+ LLDB_LOGV(log, "offset_ptr = {0:x} --> {1}", offset_ptr,
+ offset_scalar.SInt());
m_ivars.push_back(
{ConstString(name), ivar_type, size, offset_scalar.SInt()});
- } else if (log)
- log->Printf(
- "[ClassDescriptorV2::iVarsStorage::fill] offset_ptr = %" PRIx64
- " --> read fail, read = %zu",
- offset_ptr, read);
+ } else
+ LLDB_LOGV(log, "offset_ptr = {0:x} --> read fail, read = %{1}",
+ offset_ptr, read);
}
return stop_loop;
});
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
index 922d192..e99fd74 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
@@ -10,13 +10,13 @@
#include "AppleObjCDeclVendor.h"
#include "Plugins/ExpressionParser/Clang/ASTDumper.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -355,9 +355,14 @@ public:
}
}
+ clang::IdentifierInfo **identifier_infos = selector_components.data();
+ if (!identifier_infos) {
+ return NULL;
+ }
+
clang::Selector sel = ast_ctx.Selectors.getSelector(
is_zero_argument ? 0 : selector_components.size(),
- selector_components.data());
+ identifier_infos);
clang::QualType ret_type =
ClangUtil::GetQualType(type_realizer_sp->RealizeType(
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
index 4a90f5c..eacc98a 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
@@ -14,15 +14,11 @@
#include "clang/AST/Type.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/FunctionCaller.h"
@@ -34,6 +30,10 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
#include <vector>
@@ -145,7 +145,7 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS;
if (!m_print_object_caller_up) {
- Error error;
+ Status error;
m_print_object_caller_up.reset(
exe_scope->CalculateTarget()->GetFunctionCallerForLanguage(
eLanguageTypeObjC, return_compiler_type, *function_address,
@@ -185,7 +185,7 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
size_t full_buffer_len = sizeof(buf) - 1;
size_t curr_len = full_buffer_len;
while (curr_len == full_buffer_len) {
- Error error;
+ Status error;
curr_len = process->ReadCStringFromMemory(result_ptr + cstr_len, buf,
sizeof(buf), error);
strm.Write(buf, curr_len);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
index 13bd245..9cac499 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
@@ -15,13 +15,9 @@
#include "clang/AST/Type.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UtilityFunction.h"
#include "lldb/Symbol/ClangASTContext.h"
@@ -31,6 +27,10 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
#include <vector>
@@ -127,7 +127,7 @@ struct BufStruct {
UtilityFunction *AppleObjCRuntimeV1::CreateObjectChecker(const char *name) {
std::unique_ptr<BufStruct> buf(new BufStruct);
- assert(snprintf(&buf->contents[0], sizeof(buf->contents),
+ int strformatsize = snprintf(&buf->contents[0], sizeof(buf->contents),
"struct __objc_class "
" \n"
"{ "
@@ -169,9 +169,11 @@ UtilityFunction *AppleObjCRuntimeV1::CreateObjectChecker(const char *name) {
" \n"
"} "
" \n",
- name) < (int)sizeof(buf->contents));
+ name);
+ assert(strformatsize < (int)sizeof(buf->contents));
+ (void)strformatsize;
- Error error;
+ Status error;
return GetTargetRef().GetUtilityFunctionForLanguage(
buf->contents, eLanguageTypeObjC, name, error);
}
@@ -195,7 +197,7 @@ void AppleObjCRuntimeV1::ClassDescriptorV1::Initialize(
m_valid = true;
- Error error;
+ Status error;
m_isa = process_sp->ReadPointerFromMemory(isa, error);
@@ -301,7 +303,7 @@ lldb::addr_t AppleObjCRuntimeV1::GetISAHashTablePointer() {
symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) {
- Error error;
+ Status error;
lldb::addr_t objc_debug_class_hash_ptr =
process->ReadPointerFromMemory(objc_debug_class_hash_addr, error);
if (objc_debug_class_hash_ptr != 0 &&
@@ -347,7 +349,7 @@ void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() {
// const void *info;
// } NXHashTable;
- Error error;
+ Status error;
DataBufferHeap buffer(1024, 0);
if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) ==
20) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index e9958a5..2a77359 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -20,26 +20,20 @@
// Project includes
#include "lldb/Core/ClangForward.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/Core/ClangForward.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UtilityFunction.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandObjectMultiword.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -55,6 +49,12 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
#include "AppleObjCClassDescriptorV2.h"
#include "AppleObjCDeclVendor.h"
@@ -338,7 +338,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
static uint64_t
ExtractRuntimeGlobalSymbol(Process *process, ConstString name,
- const ModuleSP &module_sp, Error &error,
+ const ModuleSP &module_sp, Status &error,
bool read_value = true, uint8_t byte_size = 0,
uint64_t default_value = LLDB_INVALID_ADDRESS,
SymbolType sym_type = lldb::eSymbolTypeData) {
@@ -483,9 +483,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
case 'v':
@@ -600,14 +600,12 @@ protected:
}
iterator->second->Describe(
nullptr,
- [objc_runtime, &std_out](const char *name,
- const char *type) -> bool {
+ [&std_out](const char *name, const char *type) -> bool {
std_out.Printf(" instance method name = %s type = %s\n",
name, type);
return false;
},
- [objc_runtime, &std_out](const char *name,
- const char *type) -> bool {
+ [&std_out](const char *name, const char *type) -> bool {
std_out.Printf(" class method name = %s type = %s\n", name,
type);
return false;
@@ -678,7 +676,7 @@ protected:
const char *arg_str = command.GetArgumentAtIndex(i);
if (!arg_str)
continue;
- Error error;
+ Status error;
lldb::addr_t arg_addr = Args::StringToAddress(
&exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error);
if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail())
@@ -895,8 +893,9 @@ UtilityFunction *AppleObjCRuntimeV2::CreateObjectChecker(const char *name) {
}
assert(len < (int)sizeof(check_function_code));
+ UNUSED_IF_ASSERT_DISABLED(len);
- Error error;
+ Status error;
return GetTargetRef().GetUtilityFunctionForLanguage(
check_function_code, eLanguageTypeObjC, name, error);
}
@@ -928,7 +927,7 @@ size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type,
addr_t ivar_offset_address = LLDB_INVALID_ADDRESS;
- Error error;
+ Status error;
SymbolContext ivar_offset_symbol;
if (sc_list.GetSize() == 1 &&
sc_list.GetContextAtIndex(0, ivar_offset_symbol)) {
@@ -985,7 +984,7 @@ public:
m_map_pair_size = m_process->GetAddressByteSize() * 2;
m_invalid_key =
m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX;
- Error err;
+ Status err;
// This currently holds true for all platforms we support, but we might
// need to change this to use get the actually byte size of "unsigned"
@@ -1078,7 +1077,7 @@ public:
size_t map_pair_size = m_parent.m_map_pair_size;
lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
- Error err;
+ Status err;
lldb::addr_t key =
m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
@@ -1107,7 +1106,7 @@ public:
const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
const size_t map_pair_size = m_parent.m_map_pair_size;
const lldb::addr_t invalid_key = m_parent.m_invalid_key;
- Error err;
+ Status err;
while (m_index--) {
lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
@@ -1219,7 +1218,7 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) {
Process *process = exe_ctx.GetProcessPtr();
if (process) {
- Error error;
+ Status error;
ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
if (isa != LLDB_INVALID_ADDRESS) {
objc_class_sp = GetClassDescriptorFromISA(isa);
@@ -1256,7 +1255,7 @@ lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() {
symbol->GetLoadAddress(&process->GetTarget());
if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) {
- Error error;
+ Status error;
m_isa_hash_table_ptr = process->ReadPointerFromMemory(
gdb_objc_realized_classes_ptr, error);
}
@@ -1296,7 +1295,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(
const uint32_t addr_size = process->GetAddressByteSize();
- Error err;
+ Status err;
// Read the total number of classes from the hash table
const uint32_t num_classes = hash_table.GetCount();
@@ -1316,7 +1315,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(
FunctionCaller *get_class_info_function = nullptr;
if (!m_get_class_info_code.get()) {
- Error error;
+ Status error;
m_get_class_info_code.reset(GetTargetRef().GetUtilityFunctionForLanguage(
g_get_dynamic_class_info_body, eLanguageTypeObjC,
g_get_dynamic_class_info_name, error));
@@ -1396,8 +1395,13 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(
arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress();
arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
- arguments.GetValueAtIndex(3)->GetScalar() =
- (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1);
+
+ // Only dump the runtime classes from the expression evaluation if the
+ // log is verbose:
+ Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES);
+ bool dump_log = type_log && type_log->GetVerbose();
+
+ arguments.GetValueAtIndex(3)->GetScalar() = dump_log ? 1 : 0;
bool success = false;
@@ -1543,7 +1547,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() {
const uint32_t addr_size = process->GetAddressByteSize();
- Error err;
+ Status err;
uint32_t num_class_infos = 0;
@@ -1564,7 +1568,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() {
FunctionCaller *get_shared_cache_class_info_function = nullptr;
if (!m_get_shared_cache_class_info_code.get()) {
- Error error;
+ Status error;
m_get_shared_cache_class_info_code.reset(
GetTargetRef().GetUtilityFunctionForLanguage(
g_get_shared_cache_class_info_body, eLanguageTypeObjC,
@@ -1640,8 +1644,12 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() {
arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
- arguments.GetValueAtIndex(3)->GetScalar() =
- (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1);
+ // Only dump the runtime classes from the expression evaluation if the
+ // log is verbose:
+ Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES);
+ bool dump_log = type_log && type_log->GetVerbose();
+
+ arguments.GetValueAtIndex(3)->GetScalar() = dump_log ? 1 : 0;
bool success = false;
@@ -1795,7 +1803,8 @@ lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() {
void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
// Else we need to check with our process to see when the map was updated.
Process *process = GetProcess();
@@ -2011,7 +2020,7 @@ AppleObjCRuntimeV2::NonPointerISACache::CreateInstance(
AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
Process *process(runtime.GetProcess());
- Error error;
+ Status error;
auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(
process, ConstString("objc_debug_isa_magic_mask"), objc_module_sp, error);
@@ -2042,7 +2051,7 @@ AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance(
AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
Process *process(runtime.GetProcess());
- Error error;
+ Status error;
auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(
process, ConstString("objc_debug_taggedpointer_mask"), objc_module_sp,
@@ -2254,7 +2263,7 @@ AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(
Process *process(m_runtime.GetProcess());
uintptr_t slot_ptr = slot * process->GetAddressByteSize() +
m_objc_debug_taggedpointer_classes;
- Error error;
+ Status error;
uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
if (error.Fail() || slot_data == 0 ||
slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
@@ -2341,7 +2350,7 @@ AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(
Process *process(m_runtime.GetProcess());
uintptr_t slot_ptr = slot * process->GetAddressByteSize() +
m_objc_debug_taggedpointer_ext_classes;
- Error error;
+ Status error;
uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
if (error.Fail() || slot_data == 0 ||
slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp
index 1dc20c1..a6e9c0c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp
@@ -17,9 +17,7 @@
#include "AppleThreadPlanStepThroughObjCTrampoline.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/Value.h"
@@ -27,7 +25,6 @@
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UserExpression.h"
#include "lldb/Expression/UtilityFunction.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ABI.h"
@@ -38,6 +35,9 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
#include "llvm/ADT/STLExtras.h"
@@ -299,7 +299,7 @@ void AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::SetUpRegion() {
process_sp->GetByteOrder(),
process_sp->GetAddressByteSize());
size_t actual_size = 8 + process_sp->GetAddressByteSize();
- Error error;
+ Status error;
size_t bytes_read =
process_sp->ReadMemory(m_header_addr, memory_buffer, actual_size, error);
if (bytes_read != actual_size) {
@@ -534,7 +534,7 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines(
return false;
// Now get a pointer value from the zeroth argument.
- Error error;
+ Status error;
DataExtractor data;
error = argument_values.GetValueAtIndex(0)->GetValueAsData(&exe_ctx, data,
0, NULL);
@@ -555,7 +555,7 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions() {
m_regions.clear();
if (!InitializeVTableSymbols())
return false;
- Error error;
+ Status error;
ProcessSP process_sp = GetProcessSP();
if (process_sp) {
lldb::addr_t region_addr =
@@ -770,7 +770,7 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread,
if (!m_impl_code.get()) {
if (m_lookup_implementation_function_code != NULL) {
- Error error;
+ Status error;
m_impl_code.reset(exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(
m_lookup_implementation_function_code, eLanguageTypeObjC,
g_lookup_implementation_function_name, error));
@@ -802,7 +802,7 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread,
thread.GetProcess()->GetTarget().GetScratchClangASTContext();
CompilerType clang_void_ptr_type =
clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
- Error error;
+ Status error;
impl_function_caller = m_impl_code->MakeFunctionCaller(
clang_void_ptr_type, dispatch_values, thread_sp, error);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
index e492695..a295d1b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
@@ -14,7 +14,6 @@
// Project includes
#include "AppleThreadPlanStepThroughObjCTrampoline.h"
#include "AppleObjCTrampolineHandler.h"
-#include "lldb/Core/Log.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UtilityFunction.h"
@@ -24,6 +23,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp
index b056186..654ac9a 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp
@@ -25,9 +25,9 @@
#include "clang/Basic/TargetOptions.h"
// Project includes
-#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
#include "RenderScriptExpressionOpts.h"
#include "RenderScriptRuntime.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
index ae907ac..7e46afc 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
@@ -17,15 +17,14 @@
#include "RenderScriptScriptGroup.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
#include "lldb/Expression/UserExpression.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -41,6 +40,11 @@
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataBufferLLVM.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -119,7 +123,7 @@ struct GetArgsCtx {
bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
- Error err;
+ Status err;
// get the current stack pointer
uint64_t sp = ctx.reg_ctx->GetSP();
@@ -132,7 +136,7 @@ bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
size_t arg_size = sizeof(uint32_t);
// read the argument from memory
arg.value = 0;
- Error err;
+ Status err;
size_t read =
ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), err);
if (read != arg_size || !err.Success()) {
@@ -162,7 +166,7 @@ bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
4, // eBool,
}};
- Error err;
+ Status err;
// get the current stack pointer
uint64_t sp = ctx.reg_ctx->GetSP();
@@ -226,7 +230,7 @@ bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
- Error err;
+ Status err;
// get the current stack pointer
uint64_t sp = ctx.reg_ctx->GetSP();
@@ -306,7 +310,7 @@ bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
- Error err;
+ Status err;
// find offset to arguments on the stack (+16 to skip over a0-a3 shadow space)
uint64_t sp = ctx.reg_ctx->GetSP() + 16;
@@ -351,7 +355,7 @@ bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
- Error err;
+ Status err;
// get the current stack pointer
uint64_t sp = ctx.reg_ctx->GetSP();
@@ -1185,7 +1189,7 @@ void RenderScriptRuntime::CaptureDebugHintScriptGroup2(
// parse script group name
ConstString group_name;
{
- Error err;
+ Status err;
const uint64_t len = uint64_t(args[eGroupNameSize]);
std::unique_ptr<char[]> buffer(new char[uint32_t(len + 1)]);
m_process->ReadMemory(addr_t(args[eGroupName]), buffer.get(), len, err);
@@ -1234,7 +1238,7 @@ void RenderScriptRuntime::CaptureDebugHintScriptGroup2(
// extract script group kernel addresses from the target
const addr_t ptr_addr = addr_t(args[eKernel]) + i * target_ptr_size;
uint64_t kernel_addr = 0;
- Error err;
+ Status err;
size_t read =
m_process->ReadMemory(ptr_addr, &kernel_addr, target_ptr_size, err);
if (!err.Success() || read != target_ptr_size) {
@@ -1333,7 +1337,7 @@ void RenderScriptRuntime::CaptureScriptInvokeForEachMulti(
}
const uint32_t target_ptr_size = m_process->GetAddressByteSize();
- Error err;
+ Status err;
std::vector<uint64_t> allocs;
// traverse allocation list
@@ -1520,7 +1524,7 @@ void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook,
ExecutionContext &exe_ctx) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
- Error err;
+ Status err;
Process *process = exe_ctx.GetProcessPtr();
enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr };
@@ -1752,7 +1756,7 @@ bool RenderScriptRuntime::EvalRSExpression(const char *expr,
// The result of the expression is invalid
if (!expr_result->GetError().Success()) {
- Error err = expr_result->GetError();
+ Status err = expr_result->GetError();
// Expression returned is void, so this is actually a success
if (err.GetError() == UserExpression::kNoResult) {
if (log)
@@ -1806,6 +1810,7 @@ enum ExpressionStrings {
const int jit_max_expr_size = 512;
// Retrieve the string to JIT for the given expression
+#define JIT_TEMPLATE_CONTEXT "void* ctxt = (void*)rsDebugGetContextWrapper(0x%" PRIx64 "); "
const char *JITTemplate(ExpressionStrings e) {
// Format strings containing the expressions we may need to evaluate.
static std::array<const char *, _eExprLast> runtime_expressions = {
@@ -1813,57 +1818,65 @@ const char *JITTemplate(ExpressionStrings e) {
"(int*)_"
"Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation"
"CubemapFace"
- "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)",
+ "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", // eExprGetOffsetPtr
// Type* rsaAllocationGetType(Context*, Allocation*)
- "(void*)rsaAllocationGetType(0x%" PRIx64 ", 0x%" PRIx64 ")",
+ JIT_TEMPLATE_CONTEXT "(void*)rsaAllocationGetType(ctxt, 0x%" PRIx64 ")", // eExprAllocGetType
// rsaTypeGetNativeData(Context*, Type*, void* typeData, size) Pack the
// data in the following way mHal.state.dimX; mHal.state.dimY;
// mHal.state.dimZ; mHal.state.lodCount; mHal.state.faces; mElement; into
// typeData Need to specify 32 or 64 bit for uint_t since this differs
// between devices
- "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
- ", 0x%" PRIx64 ", data, 6); data[0]", // X dim
- "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
- ", 0x%" PRIx64 ", data, 6); data[1]", // Y dim
- "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
- ", 0x%" PRIx64 ", data, 6); data[2]", // Z dim
- "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
- ", 0x%" PRIx64 ", data, 6); data[5]", // Element ptr
+ JIT_TEMPLATE_CONTEXT
+ "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
+ ", 0x%" PRIx64 ", data, 6); data[0]", // eExprTypeDimX
+ JIT_TEMPLATE_CONTEXT
+ "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
+ ", 0x%" PRIx64 ", data, 6); data[1]", // eExprTypeDimY
+ JIT_TEMPLATE_CONTEXT
+ "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
+ ", 0x%" PRIx64 ", data, 6); data[2]", // eExprTypeDimZ
+ JIT_TEMPLATE_CONTEXT
+ "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
+ ", 0x%" PRIx64 ", data, 6); data[5]", // eExprTypeElemPtr
// rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size)
// Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into
// elemData
- "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
- ", 0x%" PRIx64 ", data, 5); data[0]", // Type
- "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
- ", 0x%" PRIx64 ", data, 5); data[1]", // Kind
- "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
- ", 0x%" PRIx64 ", data, 5); data[3]", // Vector Size
- "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
- ", 0x%" PRIx64 ", data, 5); data[4]", // Field Count
+ JIT_TEMPLATE_CONTEXT
+ "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
+ ", 0x%" PRIx64 ", data, 5); data[0]", // eExprElementType
+ JIT_TEMPLATE_CONTEXT
+ "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
+ ", 0x%" PRIx64 ", data, 5); data[1]", // eExprElementKind
+ JIT_TEMPLATE_CONTEXT
+ "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
+ ", 0x%" PRIx64 ", data, 5); data[3]", // eExprElementVec
+ JIT_TEMPLATE_CONTEXT
+ "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
+ ", 0x%" PRIx64 ", data, 5); data[4]", // eExprElementFieldCount
// rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t
// *ids, const char **names, size_t *arraySizes, uint32_t dataSize)
// Needed for Allocations of structs to gather details about
// fields/Subelements Element* of field
- "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
+ JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
"]; size_t arr_size[%" PRIu32 "];"
- "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64
- ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]",
+ "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
+ ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", // eExprSubelementsId
// Name of field
- "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
+ JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
"]; size_t arr_size[%" PRIu32 "];"
- "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64
- ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]",
+ "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
+ ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", // eExprSubelementsName
// Array size of field
- "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
+ JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
"]; size_t arr_size[%" PRIu32 "];"
- "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64
- ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}};
+ "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
+ ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}}; // eExprSubelementsArrSize
return runtime_expressions[e];
}
@@ -1975,8 +1988,8 @@ bool RenderScriptRuntime::JITTypePacked(AllocationDetails *alloc,
for (uint32_t i = 0; i < num_exprs; ++i) {
const char *fmt_str = JITTemplate(ExpressionStrings(eExprTypeDimX + i));
- int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str, bits,
- *alloc->context.get(), *alloc->type_ptr.get());
+ int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str,
+ *alloc->context.get(), bits, *alloc->type_ptr.get());
if (written < 0) {
if (log)
log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
@@ -2101,7 +2114,7 @@ bool RenderScriptRuntime::JITSubelements(Element &elem,
const char *fmt_str =
JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index));
int written = snprintf(expr_buffer, jit_max_expr_size, fmt_str,
- field_count, field_count, field_count, context,
+ context, field_count, field_count, field_count,
*elem.element_ptr.get(), field_count, field_index);
if (written < 0) {
if (log)
@@ -2127,7 +2140,7 @@ bool RenderScriptRuntime::JITSubelements(Element &elem,
case 1: // Name of child
{
lldb::addr_t address = static_cast<addr_t>(results);
- Error err;
+ Status err;
std::string name;
GetProcess()->ReadCStringFromMemory(address, name, err);
if (!err.Fail())
@@ -2373,7 +2386,7 @@ void RenderScriptRuntime::FindStructTypeName(Element &elem,
if (found) {
// Dereference since our Element type isn't a pointer.
if (valobj_sp->IsPointerType()) {
- Error err;
+ Status err;
ValueObjectSP deref_valobj = valobj_sp->Dereference(err);
if (!err.Fail())
valobj_sp = deref_valobj;
@@ -2469,7 +2482,7 @@ RenderScriptRuntime::GetAllocationData(AllocationDetails *alloc,
}
// Read the inferior memory
- Error err;
+ Status err;
lldb::addr_t data_ptr = *alloc->data_ptr.get();
GetProcess()->ReadMemory(data_ptr, buffer.get(), size, err);
if (err.Fail()) {
@@ -2535,7 +2548,7 @@ bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id,
}
// Read file into data buffer
- DataBufferSP data_sp(file.ReadFileContents());
+ auto data_sp = DataBufferLLVM::CreateFromPath(file.GetPath());
// Cast start of buffer to FileHeader and use pointer to read metadata
void *file_buf = data_sp->GetBytes();
@@ -2630,7 +2643,7 @@ bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id,
// Copy file data from our buffer into the target allocation.
lldb::addr_t alloc_data = *alloc->data_ptr.get();
- Error err;
+ Status err;
size_t written = GetProcess()->WriteMemory(alloc_data, file_buf, size, err);
if (!err.Success() || written != size) {
strm.Printf("Error: Couldn't write data to allocation %s", err.AsCString());
@@ -2782,7 +2795,7 @@ bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id,
log->Printf("%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__,
(uint64_t)num_bytes);
- Error err = file.Write(&head, num_bytes);
+ Status err = file.Write(&head, num_bytes);
if (!err.Success()) {
strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
strm.EOL();
@@ -2887,7 +2900,7 @@ bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) {
const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType(
gDbgPresentStr, eSymbolTypeData);
if (debug_present) {
- Error err;
+ Status err;
uint32_t flag = 0x00000001U;
Target &target = GetProcess()->GetTarget();
addr_t addr = debug_present->GetLoadAddress(&target);
@@ -3073,7 +3086,7 @@ bool RSModuleDescriptor::ParseRSInfo() {
const addr_t size = info_sym->GetByteSize();
const FileSpec fs = m_module->GetFileSpec();
- const DataBufferSP buffer = fs.ReadFileContents(addr, size);
+ auto buffer = DataBufferLLVM::CreateSliceFromPath(fs.GetPath(), size, addr);
if (!buffer)
return false;
@@ -3128,9 +3141,8 @@ bool RSModuleDescriptor::ParseRSInfo() {
// in numeric fields at the moment
uint64_t n_lines;
if (val.getAsInteger(10, n_lines)) {
- if (log)
- log->Debug("Failed to parse non-numeric '.rs.info' section %s",
- line->str().c_str());
+ LLDB_LOGV(log, "Failed to parse non-numeric '.rs.info' section {0}",
+ line->str());
continue;
}
if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines)
@@ -3167,7 +3179,7 @@ bool RSModuleDescriptor::ParseRSInfo() {
return info_lines.size() > 0;
}
-void RenderScriptRuntime::Status(Stream &strm) const {
+void RenderScriptRuntime::DumpStatus(Stream &strm) const {
if (m_libRS) {
strm.Printf("Runtime Library discovered.");
strm.EOL();
@@ -3410,8 +3422,9 @@ bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr,
// Print the results to our stream.
expr_result->Dump(strm, expr_options);
} else {
- alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1,
- LLDB_INVALID_ADDRESS, 0, 0);
+ DumpDataExtractor(alloc_data, &strm, offset, format,
+ data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0,
+ 0);
}
offset += data_size;
}
@@ -3607,7 +3620,7 @@ RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) {
// Give RS breakpoints a specific name, so the user can manipulate them as a
// group.
- Error err;
+ Status err;
if (!bp->AddName("RenderScriptKernel", err))
if (log)
log->Printf("%s - error setting break name, '%s'.", __FUNCTION__,
@@ -3635,7 +3648,7 @@ RenderScriptRuntime::CreateReductionBreakpoint(const ConstString &name,
// Give RS breakpoints a specific name, so the user can manipulate them as a
// group.
- Error err;
+ Status err;
if (!bp->AddName("RenderScriptReduction", err))
if (log)
log->Printf("%s - error setting break name, '%s'.", __FUNCTION__,
@@ -3651,7 +3664,7 @@ bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp,
const char *var_name,
uint64_t &val) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
- Error err;
+ Status err;
VariableSP var_sp;
// Find variable in stack frame
@@ -3876,7 +3889,7 @@ RenderScriptRuntime::CreateScriptGroupBreakpoint(const ConstString &name,
m_filtersp, resolver_sp, false, false, false);
// Give RS breakpoints a specific name, so the user can manipulate them as a
// group.
- Error err;
+ Status err;
if (!bp->AddName(name.AsCString(), err))
if (log)
log->Printf("%s - error setting break name, '%s'.", __FUNCTION__,
@@ -4200,9 +4213,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *exe_ctx) override {
- Error err;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *exe_ctx) override {
+ Status err;
StreamString err_str;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -4356,9 +4369,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *exe_ctx) override {
- Error err;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *exe_ctx) override {
+ Status err;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -4637,9 +4650,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *exe_ctx) override {
- Error err;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *exe_ctx) override {
+ Status err;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -4759,9 +4772,9 @@ public:
~CommandOptions() override = default;
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *exe_ctx) override {
- Error err;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *exe_ctx) override {
+ Status err;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -4980,7 +4993,7 @@ public:
RenderScriptRuntime *runtime =
(RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
eLanguageTypeExtRenderScript);
- runtime->Status(result.GetOutputStream());
+ runtime->DumpStatus(result.GetOutputStream());
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
index 5b2bb57..0fe9134 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
@@ -374,7 +374,7 @@ public:
void SetBreakAllKernels(bool do_break, lldb::TargetSP target);
- void Status(Stream &strm) const;
+ void DumpStatus(Stream &strm) const;
void ModulesDidLoad(const ModuleList &module_list) override;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp
index a8202dd..fe4ae21 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp
@@ -8,12 +8,8 @@
//===----------------------------------------------------------------------===//
#include "lldb/Breakpoint/StoppointCallbackContext.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObjectMultiword.h"
@@ -24,6 +20,9 @@
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
#include "RenderScriptRuntime.h"
#include "RenderScriptScriptGroup.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp
index aaca045..439d372 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp
@@ -24,8 +24,8 @@
#include "llvm/Pass.h"
// Project includes
-#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/Log.h"
using namespace lldb_private;
namespace {
@@ -182,8 +182,10 @@ bool fixupX86StructRetCalls(llvm::Module &module) {
// we pass a pointer to this allocation as the StructRet param, and then
// copy its
// value into the lldb return value
+ const llvm::DataLayout &DL = module.getDataLayout();
llvm::AllocaInst *return_value_alloc = new llvm::AllocaInst(
- func->getReturnType(), "var_vector_return_alloc", call_inst);
+ func->getReturnType(), DL.getAllocaAddrSpace(), "var_vector_return_alloc",
+ call_inst);
// use the new allocation as the new first argument
new_call_args.emplace(new_call_args.begin(),
llvm::cast<llvm::Value>(return_value_alloc));
@@ -194,7 +196,8 @@ bool fixupX86StructRetCalls(llvm::Module &module) {
llvm::Instruction::BitCast, func, new_func_ptr_type);
// create an allocation for a new function pointer
llvm::AllocaInst *new_func_ptr =
- new llvm::AllocaInst(new_func_ptr_type, "new_func_ptr", call_inst);
+ new llvm::AllocaInst(new_func_ptr_type, DL.getAllocaAddrSpace(),
+ "new_func_ptr", call_inst);
// store the new_func_cast to the newly allocated space
(new llvm::StoreInst(new_func_cast, new_func_ptr, call_inst))
->setName("new_func_ptr_load_cast");
@@ -248,29 +251,26 @@ bool fixupRSAllocationStructByValCalls(llvm::Module &module) {
rs_functions.insert(call_inst->getCalledFunction());
// get the function attributes
- llvm::AttributeSet call_attribs = call_inst->getAttributes();
+ llvm::AttributeList call_attribs = call_inst->getAttributes();
// iterate over the argument attributes
- for (size_t i = 1; i <= call_attribs.getNumSlots(); ++i) {
+ for (unsigned I = call_attribs.index_begin(); I != call_attribs.index_end();
+ I++) {
// if this argument is passed by val
- if (call_attribs.hasAttribute(i, llvm::Attribute::ByVal)) {
+ if (call_attribs.hasAttribute(I, llvm::Attribute::ByVal)) {
// strip away the byval attribute
- call_inst->removeAttribute(i, llvm::Attribute::ByVal);
+ call_inst->removeAttribute(I, llvm::Attribute::ByVal);
changed = true;
}
}
}
- llvm::AttributeSet attr_byval =
- llvm::AttributeSet::get(module.getContext(), 1u, llvm::Attribute::ByVal);
-
// for all called function decls
for (auto func : rs_functions) {
// inspect all of the arguments in the call
- llvm::SymbolTableList<llvm::Argument> &arg_list = func->getArgumentList();
- for (auto &arg : arg_list) {
+ for (auto &arg : func->args()) {
if (arg.hasByValAttr()) {
- arg.removeAttr(attr_byval);
+ arg.removeAttr(llvm::Attribute::ByVal);
changed = true;
}
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/contrib/llvm/tools/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
index 35247ed..b9e49d1 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
@@ -170,7 +170,7 @@ HistoryThreads MemoryHistoryASan::GetHistoryThreads(lldb::addr_t address) {
ExecutionContext exe_ctx(frame_sp);
ValueObjectSP return_value_sp;
StreamString expr;
- Error eval_error;
+ Status eval_error;
expr.Printf(memory_history_asan_command_format, address, address);
EvaluateExpressionOptions options;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
index 5bca1de..25bfce7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -28,14 +28,16 @@ typedef struct ar_hdr {
#endif
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/DataBufferLLVM.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
+
+#include "llvm/Support/MemoryBuffer.h"
using namespace lldb;
using namespace lldb_private;
@@ -156,7 +158,7 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() {
size_t obj_idx = m_objects.size();
m_objects.push_back(obj);
// Insert all of the C strings out of order for now...
- m_object_name_to_index_map.Append(obj.ar_name.GetStringRef(), obj_idx);
+ m_object_name_to_index_map.Append(obj.ar_name, obj_idx);
offset += obj.ar_file_size;
obj.Clear();
} while (data.ValidOffset(offset));
@@ -172,8 +174,7 @@ ObjectContainerBSDArchive::Archive::FindObject(
const ConstString &object_name,
const llvm::sys::TimePoint<> &object_mod_time) {
const ObjectNameToIndexMap::Entry *match =
- m_object_name_to_index_map.FindFirstValueForName(
- object_name.GetStringRef());
+ m_object_name_to_index_map.FindFirstValueForName(object_name);
if (match) {
if (object_mod_time != llvm::sys::TimePoint<>()) {
const uint64_t object_date = llvm::sys::toTimeT(object_mod_time);
@@ -290,62 +291,66 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance(
lldb::offset_t data_offset, const FileSpec *file,
lldb::offset_t file_offset, lldb::offset_t length) {
ConstString object_name(module_sp->GetObjectName());
- if (object_name) {
- if (data_sp) {
- // We have data, which means this is the first 512 bytes of the file
- // Check to see if the magic bytes match and if they do, read the entire
- // table of contents for the archive and cache it
- DataExtractor data;
- data.SetData(data_sp, data_offset, length);
- if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data)) {
- Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
- "ObjectContainerBSDArchive::CreateInstance (module = %s, file = "
- "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
- module_sp->GetFileSpec().GetPath().c_str(),
- static_cast<const void *>(file), static_cast<uint64_t>(file_offset),
- static_cast<uint64_t>(length));
-
- // Map the entire .a file to be sure that we don't lose any data if the
- // file
- // gets updated by a new build while this .a file is being used for
- // debugging
- DataBufferSP archive_data_sp(
- file->MemoryMapFileContentsIfLocal(file_offset, length));
- lldb::offset_t archive_data_offset = 0;
-
- Archive::shared_ptr archive_sp(Archive::FindCachedArchive(
- *file, module_sp->GetArchitecture(),
- module_sp->GetModificationTime(), file_offset));
- std::unique_ptr<ObjectContainerBSDArchive> container_ap(
- new ObjectContainerBSDArchive(module_sp, archive_data_sp,
- archive_data_offset, file,
- file_offset, length));
-
- if (container_ap.get()) {
- if (archive_sp) {
- // We already have this archive in our cache, use it
- container_ap->SetArchive(archive_sp);
- return container_ap.release();
- } else if (container_ap->ParseHeader())
- return container_ap.release();
- }
- }
- } else {
- // No data, just check for a cached archive
+ if (!object_name)
+ return nullptr;
+
+ if (data_sp) {
+ // We have data, which means this is the first 512 bytes of the file
+ // Check to see if the magic bytes match and if they do, read the entire
+ // table of contents for the archive and cache it
+ DataExtractor data;
+ data.SetData(data_sp, data_offset, length);
+ if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data)) {
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(
+ func_cat,
+ "ObjectContainerBSDArchive::CreateInstance (module = %s, file = "
+ "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
+ module_sp->GetFileSpec().GetPath().c_str(),
+ static_cast<const void *>(file), static_cast<uint64_t>(file_offset),
+ static_cast<uint64_t>(length));
+
+ // Map the entire .a file to be sure that we don't lose any data if the
+ // file gets updated by a new build while this .a file is being used for
+ // debugging
+ DataBufferSP archive_data_sp =
+ DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset);
+ if (!archive_data_sp)
+ return nullptr;
+
+ lldb::offset_t archive_data_offset = 0;
+
Archive::shared_ptr archive_sp(Archive::FindCachedArchive(
*file, module_sp->GetArchitecture(), module_sp->GetModificationTime(),
file_offset));
- if (archive_sp) {
- std::unique_ptr<ObjectContainerBSDArchive> container_ap(
- new ObjectContainerBSDArchive(module_sp, data_sp, data_offset, file,
- file_offset, length));
+ std::unique_ptr<ObjectContainerBSDArchive> container_ap(
+ new ObjectContainerBSDArchive(module_sp, archive_data_sp,
+ archive_data_offset, file, file_offset,
+ length));
- if (container_ap.get()) {
+ if (container_ap.get()) {
+ if (archive_sp) {
// We already have this archive in our cache, use it
container_ap->SetArchive(archive_sp);
return container_ap.release();
- }
+ } else if (container_ap->ParseHeader())
+ return container_ap.release();
+ }
+ }
+ } else {
+ // No data, just check for a cached archive
+ Archive::shared_ptr archive_sp(Archive::FindCachedArchive(
+ *file, module_sp->GetArchitecture(), module_sp->GetModificationTime(),
+ file_offset));
+ if (archive_sp) {
+ std::unique_ptr<ObjectContainerBSDArchive> container_ap(
+ new ObjectContainerBSDArchive(module_sp, data_sp, data_offset, file,
+ file_offset, length));
+
+ if (container_ap.get()) {
+ // We already have this archive in our cache, use it
+ container_ap->SetArchive(archive_sp);
+ return container_ap.release();
}
}
}
@@ -453,63 +458,64 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications(
// table of contents for the archive and cache it
DataExtractor data;
data.SetData(data_sp, data_offset, data_sp->GetByteSize());
- if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data)) {
- const size_t initial_count = specs.GetSize();
- llvm::sys::TimePoint<> file_mod_time =
- FileSystem::GetModificationTime(file);
- Archive::shared_ptr archive_sp(Archive::FindCachedArchive(
- file, ArchSpec(), file_mod_time, file_offset));
- bool set_archive_arch = false;
- if (!archive_sp) {
- set_archive_arch = true;
- DataBufferSP data_sp(
- file.MemoryMapFileContentsIfLocal(file_offset, file_size));
+ if (!file || !data_sp || !ObjectContainerBSDArchive::MagicBytesMatch(data))
+ return 0;
+
+ const size_t initial_count = specs.GetSize();
+ llvm::sys::TimePoint<> file_mod_time = FileSystem::GetModificationTime(file);
+ Archive::shared_ptr archive_sp(
+ Archive::FindCachedArchive(file, ArchSpec(), file_mod_time, file_offset));
+ bool set_archive_arch = false;
+ if (!archive_sp) {
+ set_archive_arch = true;
+ data_sp =
+ DataBufferLLVM::CreateSliceFromPath(file.GetPath(), file_size, file_offset);
+ if (data_sp) {
data.SetData(data_sp, 0, data_sp->GetByteSize());
archive_sp = Archive::ParseAndCacheArchiveForFile(
file, ArchSpec(), file_mod_time, file_offset, data);
}
+ }
- if (archive_sp) {
- const size_t num_objects = archive_sp->GetNumObjects();
- for (size_t idx = 0; idx < num_objects; ++idx) {
- const Object *object = archive_sp->GetObjectAtIndex(idx);
- if (object) {
- const lldb::offset_t object_file_offset =
- file_offset + object->ar_file_offset;
- if (object->ar_file_offset < file_size &&
- file_size > object_file_offset) {
- if (ObjectFile::GetModuleSpecifications(
- file, object_file_offset, file_size - object_file_offset,
- specs)) {
- ModuleSpec &spec =
- specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1);
- llvm::sys::TimePoint<> object_mod_time(
- std::chrono::seconds(object->ar_date));
- spec.GetObjectName() = object->ar_name;
- spec.SetObjectOffset(object_file_offset);
- spec.SetObjectSize(file_size - object_file_offset);
- spec.GetObjectModificationTime() = object_mod_time;
- }
+ if (archive_sp) {
+ const size_t num_objects = archive_sp->GetNumObjects();
+ for (size_t idx = 0; idx < num_objects; ++idx) {
+ const Object *object = archive_sp->GetObjectAtIndex(idx);
+ if (object) {
+ const lldb::offset_t object_file_offset =
+ file_offset + object->ar_file_offset;
+ if (object->ar_file_offset < file_size &&
+ file_size > object_file_offset) {
+ if (ObjectFile::GetModuleSpecifications(
+ file, object_file_offset, file_size - object_file_offset,
+ specs)) {
+ ModuleSpec &spec =
+ specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1);
+ llvm::sys::TimePoint<> object_mod_time(
+ std::chrono::seconds(object->ar_date));
+ spec.GetObjectName() = object->ar_name;
+ spec.SetObjectOffset(object_file_offset);
+ spec.SetObjectSize(file_size - object_file_offset);
+ spec.GetObjectModificationTime() = object_mod_time;
}
}
}
}
- const size_t end_count = specs.GetSize();
- size_t num_specs_added = end_count - initial_count;
- if (set_archive_arch && num_specs_added > 0) {
- // The archive was created but we didn't have an architecture
- // so we need to set it
- for (size_t i = initial_count; i < end_count; ++i) {
- ModuleSpec module_spec;
- if (specs.GetModuleSpecAtIndex(i, module_spec)) {
- if (module_spec.GetArchitecture().IsValid()) {
- archive_sp->SetArchitecture(module_spec.GetArchitecture());
- break;
- }
+ }
+ const size_t end_count = specs.GetSize();
+ size_t num_specs_added = end_count - initial_count;
+ if (set_archive_arch && num_specs_added > 0) {
+ // The archive was created but we didn't have an architecture
+ // so we need to set it
+ for (size_t i = initial_count; i < end_count; ++i) {
+ ModuleSpec module_spec;
+ if (specs.GetModuleSpecAtIndex(i, module_spec)) {
+ if (module_spec.GetArchitecture().IsValid()) {
+ archive_sp->SetArchitecture(module_spec.GetArchitecture());
+ break;
}
}
}
- return num_specs_added;
}
- return 0;
+ return num_specs_added;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
index de0f24e..0e10d47 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
@@ -12,16 +12,18 @@
// Project includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/ConstString.h"
#include "lldb/Core/UniqueCStringMap.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Symbol/ObjectContainer.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FileSpec.h"
// Other libraries and framework includes
#include "llvm/Support/Chrono.h"
// C Includes
// C++ Includes
+#include <map>
+#include <memory>
#include <mutex>
class ObjectContainerBSDArchive : public lldb_private::ObjectContainer {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
index a3e8239..39ea492 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
@@ -9,9 +9,9 @@
#include <cstring>
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Stream.h"
#include "ELFHeader.h"
@@ -81,6 +81,39 @@ ByteOrder ELFHeader::GetByteOrder() const {
return eByteOrderInvalid;
}
+bool ELFHeader::HasHeaderExtension() const {
+ bool result = false;
+
+ // Check if any of these values looks like sentinel.
+ result |= e_phnum_hdr == 0xFFFF; // PN_XNUM
+ result |= e_shnum_hdr == SHN_UNDEF;
+ result |= e_shstrndx_hdr == SHN_XINDEX;
+
+ // If header extension is present, the section offset cannot be null.
+ result &= e_shoff != 0;
+
+ // Done.
+ return result;
+}
+
+void ELFHeader::ParseHeaderExtension(lldb_private::DataExtractor &data) {
+ // Extract section #0 header.
+ ELFSectionHeader section_zero;
+ lldb::offset_t offset = 0;
+ lldb_private::DataExtractor sh_data(data, e_shoff, e_shentsize);
+ bool ok = section_zero.Parse(sh_data, &offset);
+
+ // If we succeeded, fix the header.
+ if (ok) {
+ if (e_phnum_hdr == 0xFFFF) // PN_XNUM
+ e_phnum = section_zero.sh_info;
+ if (e_shnum_hdr == SHN_UNDEF)
+ e_shnum = section_zero.sh_size;
+ if (e_shstrndx_hdr == SHN_XINDEX)
+ e_shstrndx = section_zero.sh_link;
+ }
+}
+
bool ELFHeader::Parse(lldb_private::DataExtractor &data,
lldb::offset_t *offset) {
// Read e_ident. This provides byte order and address size info.
@@ -112,6 +145,16 @@ bool ELFHeader::Parse(lldb_private::DataExtractor &data,
if (data.GetU16(offset, &e_ehsize, 6) == NULL)
return false;
+ // Initialize e_phnum, e_shnum, and e_shstrndx with the values
+ // read from the header.
+ e_phnum = e_phnum_hdr;
+ e_shnum = e_shnum_hdr;
+ e_shstrndx = e_shstrndx_hdr;
+
+ // See if we have extended header in section #0.
+ if (HasHeaderExtension())
+ ParseHeaderExtension(data);
+
return true;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h
index 71b200f..4e2d315 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h
@@ -21,9 +21,10 @@
#ifndef liblldb_ELFHeader_h_
#define liblldb_ELFHeader_h_
-#include "llvm/Support/ELF.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-types.h"
namespace lldb_private {
class DataExtractor;
@@ -65,10 +66,17 @@ struct ELFHeader {
elf_half e_machine; ///< Target architecture.
elf_half e_ehsize; ///< Byte size of the ELF header.
elf_half e_phentsize; ///< Size of a program header table entry.
- elf_half e_phnum; ///< Number of program header entries.
+ elf_half e_phnum_hdr; ///< Number of program header entries.
elf_half e_shentsize; ///< Size of a section header table entry.
- elf_half e_shnum; ///< Number of section header entries.
- elf_half e_shstrndx; ///< String table section index.
+ elf_half e_shnum_hdr; ///< Number of section header entries.
+ elf_half e_shstrndx_hdr; ///< String table section index.
+
+ // In some cases these numbers do not fit in 16 bits and they are
+ // stored outside of the header in section #0. Here are the actual
+ // values.
+ elf_word e_phnum; ///< Number of program header entries.
+ elf_word e_shnum; ///< Number of section header entries.
+ elf_word e_shstrndx; ///< String table section index.
ELFHeader();
@@ -102,6 +110,14 @@ struct ELFHeader {
unsigned GetRelocationJumpSlotType() const;
//--------------------------------------------------------------------------
+ /// Check if there should be header extension in section header #0
+ ///
+ /// @return
+ /// True if parsing the ELFHeader requires reading header extension
+ /// and false otherwise.
+ bool HasHeaderExtension() const;
+
+ //--------------------------------------------------------------------------
/// Parse an ELFHeader entry starting at position \p offset and
/// update the data extractor with the address size and byte order
/// attributes as defined by the header.
@@ -137,6 +153,16 @@ struct ELFHeader {
/// The number of bytes forming an address in the ELF file (either 4 or
/// 8), else zero if the address size could not be determined.
static unsigned AddressSizeInBytes(const uint8_t *magic);
+
+private:
+
+ //--------------------------------------------------------------------------
+ /// Parse an ELFHeader header extension entry. This method is called
+ /// by Parse().
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from.
+ void ParseHeaderExtension(lldb_private::DataExtractor &data);
};
//------------------------------------------------------------------------------
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index eb98315..3b33cf1 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -14,25 +14,26 @@
#include <unordered_map>
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/FileSpecList.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferLLVM.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ARMBuildAttributes.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/MipsABIFlags.h"
#define CASE_AND_STREAM(s, def, width) \
@@ -51,6 +52,7 @@ namespace {
const char *const LLDB_NT_OWNER_FREEBSD = "FreeBSD";
const char *const LLDB_NT_OWNER_GNU = "GNU";
const char *const LLDB_NT_OWNER_NETBSD = "NetBSD";
+const char *const LLDB_NT_OWNER_OPENBSD = "OpenBSD";
const char *const LLDB_NT_OWNER_CSR = "csr";
const char *const LLDB_NT_OWNER_ANDROID = "Android";
const char *const LLDB_NT_OWNER_CORE = "CORE";
@@ -286,10 +288,26 @@ static uint32_t kalimbaVariantFromElfFlags(const elf::elf_word e_flags) {
return kal_arch_variant;
}
-static uint32_t mipsVariantFromElfFlags(const elf::elf_word e_flags,
- uint32_t endian) {
- const uint32_t mips_arch = e_flags & llvm::ELF::EF_MIPS_ARCH;
+static uint32_t mipsVariantFromElfFlags (const elf::ELFHeader &header) {
+ const uint32_t mips_arch = header.e_flags & llvm::ELF::EF_MIPS_ARCH;
+ uint32_t endian = header.e_ident[EI_DATA];
uint32_t arch_variant = ArchSpec::eMIPSSubType_unknown;
+ uint32_t fileclass = header.e_ident[EI_CLASS];
+
+ // If there aren't any elf flags available (e.g core elf file) then return default
+ // 32 or 64 bit arch (without any architecture revision) based on object file's class.
+ if (header.e_type == ET_CORE) {
+ switch (fileclass) {
+ case llvm::ELF::ELFCLASS32:
+ return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32el
+ : ArchSpec::eMIPSSubType_mips32;
+ case llvm::ELF::ELFCLASS64:
+ return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64el
+ : ArchSpec::eMIPSSubType_mips64;
+ default:
+ return arch_variant;
+ }
+ }
switch (mips_arch) {
case llvm::ELF::EF_MIPS_ARCH_1:
@@ -324,7 +342,7 @@ static uint32_t mipsVariantFromElfFlags(const elf::elf_word e_flags,
static uint32_t subTypeFromElfHeader(const elf::ELFHeader &header) {
if (header.e_machine == llvm::ELF::EM_MIPS)
- return mipsVariantFromElfFlags(header.e_flags, header.e_ident[EI_DATA]);
+ return mipsVariantFromElfFlags(header);
return llvm::ELF::EM_CSR_KALIMBA == header.e_machine
? kalimbaVariantFromElfFlags(header.e_flags)
@@ -386,31 +404,42 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp,
lldb::offset_t file_offset,
lldb::offset_t length) {
if (!data_sp) {
- data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
+ data_sp =
+ DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset);
+ if (!data_sp)
+ return nullptr;
data_offset = 0;
}
- if (data_sp &&
- data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT + data_offset)) {
- const uint8_t *magic = data_sp->GetBytes() + data_offset;
- if (ELFHeader::MagicBytesMatch(magic)) {
- // Update the data to contain the entire file if it doesn't already
- if (data_sp->GetByteSize() < length) {
- data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
- data_offset = 0;
- magic = data_sp->GetBytes();
- }
- unsigned address_size = ELFHeader::AddressSizeInBytes(magic);
- if (address_size == 4 || address_size == 8) {
- std::unique_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF(
- module_sp, data_sp, data_offset, file, file_offset, length));
- ArchSpec spec;
- if (objfile_ap->GetArchitecture(spec) &&
- objfile_ap->SetModulesArchitecture(spec))
- return objfile_ap.release();
- }
- }
+ assert(data_sp);
+
+ if (data_sp->GetByteSize() <= (llvm::ELF::EI_NIDENT + data_offset))
+ return nullptr;
+
+ const uint8_t *magic = data_sp->GetBytes() + data_offset;
+ if (!ELFHeader::MagicBytesMatch(magic))
+ return nullptr;
+
+ // Update the data to contain the entire file if it doesn't already
+ if (data_sp->GetByteSize() < length) {
+ data_sp =
+ DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset);
+ if (!data_sp)
+ return nullptr;
+ data_offset = 0;
+ magic = data_sp->GetBytes();
+ }
+
+ unsigned address_size = ELFHeader::AddressSizeInBytes(magic);
+ if (address_size == 4 || address_size == 8) {
+ std::unique_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF(
+ module_sp, data_sp, data_offset, file, file_offset, length));
+ ArchSpec spec;
+ if (objfile_ap->GetArchitecture(spec) &&
+ objfile_ap->SetModulesArchitecture(spec))
+ return objfile_ap.release();
}
+
return NULL;
}
@@ -610,7 +639,8 @@ size_t ObjectFileELF::GetModuleSpecifications(
DataExtractor data;
data.SetData(data_sp);
elf::ELFHeader header;
- if (header.Parse(data, &data_offset)) {
+ lldb::offset_t header_offset = data_offset;
+ if (header.Parse(data, &header_offset)) {
if (data_sp) {
ModuleSpec spec(file);
@@ -632,6 +662,7 @@ size_t ObjectFileELF::GetModuleSpecifications(
// SetArchitecture should have set the vendor to unknown
vendor = spec.GetArchitecture().GetTriple().getVendor();
assert(vendor == llvm::Triple::UnknownVendor);
+ UNUSED_IF_ASSERT_DISABLED(vendor);
//
// Validate it is ok to remove GetOsFromOSABI
@@ -644,15 +675,31 @@ size_t ObjectFileELF::GetModuleSpecifications(
__FUNCTION__, file.GetPath().c_str());
}
+ // In case there is header extension in the section #0, the header
+ // we parsed above could have sentinel values for e_phnum, e_shnum,
+ // and e_shstrndx. In this case we need to reparse the header
+ // with a bigger data source to get the actual values.
+ size_t section_header_end = header.e_shoff + header.e_shentsize;
+ if (header.HasHeaderExtension() &&
+ section_header_end > data_sp->GetByteSize()) {
+ data_sp = DataBufferLLVM::CreateSliceFromPath(
+ file.GetPath(), section_header_end, file_offset);
+ if (data_sp) {
+ data.SetData(data_sp);
+ lldb::offset_t header_offset = data_offset;
+ header.Parse(data, &header_offset);
+ }
+ }
+
// Try to get the UUID from the section list. Usually that's at the
- // end, so
- // map the file in if we don't have it already.
- size_t section_header_end =
+ // end, so map the file in if we don't have it already.
+ section_header_end =
header.e_shoff + header.e_shnum * header.e_shentsize;
if (section_header_end > data_sp->GetByteSize()) {
- data_sp = file.MemoryMapFileContentsIfLocal(file_offset,
- section_header_end);
- data.SetData(data_sp);
+ data_sp = DataBufferLLVM::CreateSliceFromPath(
+ file.GetPath(), section_header_end, file_offset);
+ if (data_sp)
+ data.SetData(data_sp);
}
uint32_t gnu_debuglink_crc = 0;
@@ -660,10 +707,7 @@ size_t ObjectFileELF::GetModuleSpecifications(
SectionHeaderColl section_headers;
lldb_private::UUID &uuid = spec.GetUUID();
- using namespace std::placeholders;
- const SetDataFunction set_data =
- std::bind(&ObjectFileELF::SetData, std::cref(data), _1, _2, _3);
- GetSectionHeaderInfo(section_headers, set_data, header, uuid,
+ GetSectionHeaderInfo(section_headers, data, header, uuid,
gnu_debuglink_file, gnu_debuglink_crc,
spec.GetArchitecture());
@@ -680,27 +724,28 @@ size_t ObjectFileELF::GetModuleSpecifications(
uint32_t core_notes_crc = 0;
if (!gnu_debuglink_crc) {
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
lldb_private::Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
+ func_cat,
"Calculating module crc32 %s with size %" PRIu64 " KiB",
file.GetLastPathComponent().AsCString(),
(file.GetByteSize() - file_offset) / 1024);
// For core files - which usually don't happen to have a
- // gnu_debuglink,
- // and are pretty bulky - calculating whole contents crc32 would
- // be too much of luxury.
- // Thus we will need to fallback to something simpler.
+ // gnu_debuglink, and are pretty bulky - calculating whole
+ // contents crc32 would be too much of luxury. Thus we will need
+ // to fallback to something simpler.
if (header.e_type == llvm::ELF::ET_CORE) {
size_t program_headers_end =
header.e_phoff + header.e_phnum * header.e_phentsize;
if (program_headers_end > data_sp->GetByteSize()) {
- data_sp = file.MemoryMapFileContentsIfLocal(
- file_offset, program_headers_end);
- data.SetData(data_sp);
+ data_sp = DataBufferLLVM::CreateSliceFromPath(
+ file.GetPath(), program_headers_end, file_offset);
+ if (data_sp)
+ data.SetData(data_sp);
}
ProgramHeaderColl program_headers;
- GetProgramHeaderInfo(program_headers, set_data, header);
+ GetProgramHeaderInfo(program_headers, data, header);
size_t segment_data_end = 0;
for (ProgramHeaderCollConstIter I = program_headers.begin();
@@ -710,20 +755,23 @@ size_t ObjectFileELF::GetModuleSpecifications(
}
if (segment_data_end > data_sp->GetByteSize()) {
- data_sp = file.MemoryMapFileContentsIfLocal(file_offset,
- segment_data_end);
- data.SetData(data_sp);
+ data_sp = DataBufferLLVM::CreateSliceFromPath(
+ file.GetPath(), segment_data_end, file_offset);
+ if (data_sp)
+ data.SetData(data_sp);
}
core_notes_crc =
CalculateELFNotesSegmentsCRC32(program_headers, data);
} else {
// Need to map entire file into memory to calculate the crc.
- data_sp =
- file.MemoryMapFileContentsIfLocal(file_offset, SIZE_MAX);
- data.SetData(data_sp);
- gnu_debuglink_crc = calc_gnu_debuglink_crc32(
- data.GetDataStart(), data.GetByteSize());
+ data_sp = DataBufferLLVM::CreateSliceFromPath(file.GetPath(), -1,
+ file_offset);
+ if (data_sp) {
+ data.SetData(data_sp);
+ gnu_debuglink_crc = calc_gnu_debuglink_crc32(
+ data.GetDataStart(), data.GetByteSize());
+ }
}
}
if (gnu_debuglink_crc) {
@@ -799,7 +847,7 @@ bool ObjectFileELF::SetLoadAddress(Target &target, lldb::addr_t value,
if (section_list) {
if (!value_is_offset) {
bool found_offset = false;
- for (size_t i = 0, count = GetProgramHeaderCount(); i < count; ++i) {
+ for (size_t i = 1, count = GetProgramHeaderCount(); i <= count; ++i) {
const elf::ELFProgramHeader *header = GetProgramHeaderByIndex(i);
if (header == nullptr)
continue;
@@ -899,29 +947,7 @@ size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const {
bool ObjectFileELF::ParseHeader() {
lldb::offset_t offset = 0;
- if (!m_header.Parse(m_data, &offset))
- return false;
-
- if (!IsInMemory())
- return true;
-
- // For in memory object files m_data might not contain the full object file.
- // Try to load it
- // until the end of the "Section header table" what is at the end of the ELF
- // file.
- addr_t file_size = m_header.e_shoff + m_header.e_shnum * m_header.e_shentsize;
- if (m_data.GetByteSize() < file_size) {
- ProcessSP process_sp(m_process_wp.lock());
- if (!process_sp)
- return false;
-
- DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size);
- if (!data_sp)
- return false;
- m_data.SetData(data_sp, 0, file_size);
- }
-
- return true;
+ return m_header.Parse(m_data, &offset);
}
bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) {
@@ -1029,7 +1055,7 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) {
if (dyn_base == LLDB_INVALID_ADDRESS)
return Address();
- Error error;
+ Status error;
if (symbol.d_tag == DT_MIPS_RLD_MAP) {
// DT_MIPS_RLD_MAP tag stores an absolute address of the debug pointer.
Address addr;
@@ -1137,7 +1163,7 @@ size_t ObjectFileELF::ParseDependentModules() {
// GetProgramHeaderInfo
//----------------------------------------------------------------------
size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
- const SetDataFunction &set_data,
+ DataExtractor &object_data,
const ELFHeader &header) {
// We have already parsed the program headers
if (!program_headers.empty())
@@ -1154,7 +1180,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
const size_t ph_size = header.e_phnum * header.e_phentsize;
const elf_off ph_offset = header.e_phoff;
DataExtractor data;
- if (set_data(data, ph_offset, ph_size) != ph_size)
+ if (data.SetData(object_data, ph_offset, ph_size) != ph_size)
return 0;
uint32_t idx;
@@ -1174,20 +1200,15 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
// ParseProgramHeaders
//----------------------------------------------------------------------
size_t ObjectFileELF::ParseProgramHeaders() {
- using namespace std::placeholders;
- return GetProgramHeaderInfo(
- m_program_headers,
- std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2,
- _3),
- m_header);
+ return GetProgramHeaderInfo(m_program_headers, m_data, m_header);
}
-lldb_private::Error
+lldb_private::Status
ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data,
lldb_private::ArchSpec &arch_spec,
lldb_private::UUID &uuid) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
- Error error;
+ Status error;
lldb::offset_t offset = 0;
@@ -1315,6 +1336,10 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data,
}
break;
}
+ if (arch_spec.IsMIPS() &&
+ arch_spec.GetTriple().getOS() == llvm::Triple::OSType::UnknownOS)
+ // The note.n_name == LLDB_NT_OWNER_GNU is valid for Linux platform
+ arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux);
}
// Process NetBSD ELF notes.
else if ((note.n_name == LLDB_NT_OWNER_NETBSD) &&
@@ -1336,6 +1361,12 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data,
"ObjectFileELF::%s detected NetBSD, min version constant %" PRIu32,
__FUNCTION__, version_info);
}
+ // Process OpenBSD ELF notes.
+ else if (note.n_name == LLDB_NT_OWNER_OPENBSD) {
+ // Set the elf OS version to OpenBSD. Also clear the vendor.
+ arch_spec.GetTriple().setOS(llvm::Triple::OSType::OpenBSD);
+ arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor);
+ }
// Process CSR kalimba notes
else if ((note.n_type == LLDB_NT_GNU_ABI_TAG) &&
(note.n_name == LLDB_NT_OWNER_CSR)) {
@@ -1410,6 +1441,12 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data,
break;
}
}
+ if (arch_spec.IsMIPS() &&
+ arch_spec.GetTriple().getOS() == llvm::Triple::OSType::UnknownOS)
+ // In case of MIPSR6, the LLDB_NT_OWNER_GNU note is missing
+ // for some cases (e.g. compile with -nostdlib)
+ // Hence set OS to Linux
+ arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux);
}
}
@@ -1495,7 +1532,7 @@ void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length,
// GetSectionHeaderInfo
//----------------------------------------------------------------------
size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
- const SetDataFunction &set_data,
+ DataExtractor &object_data,
const elf::ELFHeader &header,
lldb_private::UUID &uuid,
std::string &gnu_debuglink_file,
@@ -1524,6 +1561,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
GetOsFromOSABI(header.e_ident[EI_OSABI], ostype);
spec_ostype = arch_spec.GetTriple().getOS();
assert(spec_ostype == ostype);
+ UNUSED_IF_ASSERT_DISABLED(spec_ostype);
}
if (arch_spec.GetMachine() == llvm::Triple::mips ||
@@ -1566,7 +1604,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
const size_t sh_size = header.e_shnum * header.e_shentsize;
const elf_off sh_offset = header.e_shoff;
DataExtractor sh_data;
- if (set_data(sh_data, sh_offset, sh_size) != sh_size)
+ if (sh_data.SetData(object_data, sh_offset, sh_size) != sh_size)
return 0;
uint32_t idx;
@@ -1585,7 +1623,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
const Elf64_Off offset = sheader.sh_offset;
lldb_private::DataExtractor shstr_data;
- if (set_data(shstr_data, offset, byte_size) == byte_size) {
+ if (shstr_data.SetData(object_data, offset, byte_size) == byte_size) {
for (SectionHeaderCollIter I = section_headers.begin();
I != section_headers.end(); ++I) {
static ConstString g_sect_name_gnu_debuglink(".gnu_debuglink");
@@ -1601,8 +1639,8 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
DataExtractor data;
if (sheader.sh_type == SHT_MIPS_ABIFLAGS) {
- if (section_size && (set_data(data, sheader.sh_offset,
- section_size) == section_size)) {
+ if (section_size && (data.SetData(object_data, sheader.sh_offset,
+ section_size) == section_size)) {
// MIPS ASE Mask is at offset 12 in MIPS.abiflags section
lldb::offset_t offset = 12; // MIPS ABI Flags Version: 0
arch_flags |= data.GetU32(&offset);
@@ -1655,7 +1693,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
// ABI Mask doesn't cover N32 and N64 ABI.
if (header.e_ident[EI_CLASS] == llvm::ELF::ELFCLASS64)
arch_flags |= lldb_private::ArchSpec::eMIPSABI_N64;
- else if (header.e_flags && llvm::ELF::EF_MIPS_ABI2)
+ else if (header.e_flags & llvm::ELF::EF_MIPS_ABI2)
arch_flags |= lldb_private::ArchSpec::eMIPSABI_N32;
break;
}
@@ -1667,14 +1705,14 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
DataExtractor data;
if (sheader.sh_type == SHT_ARM_ATTRIBUTES && section_size != 0 &&
- set_data(data, sheader.sh_offset, section_size) == section_size)
+ data.SetData(object_data, sheader.sh_offset, section_size) == section_size)
ParseARMAttributes(data, section_size, arch_spec);
}
if (name == g_sect_name_gnu_debuglink) {
DataExtractor data;
- if (section_size && (set_data(data, sheader.sh_offset,
- section_size) == section_size)) {
+ if (section_size && (data.SetData(object_data, sheader.sh_offset,
+ section_size) == section_size)) {
lldb::offset_t gnu_debuglink_offset = 0;
gnu_debuglink_file = data.GetCStr(&gnu_debuglink_offset);
gnu_debuglink_offset = llvm::alignTo(gnu_debuglink_offset, 4);
@@ -1694,9 +1732,9 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
if (is_note_header) {
// Allow notes to refine module info.
DataExtractor data;
- if (section_size && (set_data(data, sheader.sh_offset,
- section_size) == section_size)) {
- Error error = RefineModuleDetailsFromNote(data, arch_spec, uuid);
+ if (section_size && (data.SetData(object_data, sheader.sh_offset,
+ section_size) == section_size)) {
+ Status error = RefineModuleDetailsFromNote(data, arch_spec, uuid);
if (error.Fail()) {
if (log)
log->Printf("ObjectFileELF::%s ELF note processing failed: %s",
@@ -1741,50 +1779,19 @@ DataExtractor ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id) {
segment_header->p_filesz);
}
-std::string
+llvm::StringRef
ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const {
size_t pos = symbol_name.find('@');
- return symbol_name.substr(0, pos).str();
+ return symbol_name.substr(0, pos);
}
//----------------------------------------------------------------------
// ParseSectionHeaders
//----------------------------------------------------------------------
size_t ObjectFileELF::ParseSectionHeaders() {
- using namespace std::placeholders;
-
- return GetSectionHeaderInfo(
- m_section_headers,
- std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2,
- _3),
- m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc, m_arch_spec);
-}
-
-lldb::offset_t ObjectFileELF::SetData(const lldb_private::DataExtractor &src,
- lldb_private::DataExtractor &dst,
- lldb::offset_t offset,
- lldb::offset_t length) {
- return dst.SetData(src, offset, length);
-}
-
-lldb::offset_t
-ObjectFileELF::SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst,
- lldb::offset_t offset,
- lldb::offset_t length) {
- if (offset + length <= m_data.GetByteSize())
- return dst.SetData(m_data, offset, length);
-
- const auto process_sp = m_process_wp.lock();
- if (process_sp != nullptr) {
- addr_t file_size = offset + length;
-
- DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size);
- if (!data_sp)
- return false;
- m_data.SetData(data_sp, 0, file_size);
- }
-
- return dst.SetData(m_data, offset, length);
+ return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid,
+ m_gnu_debuglink_file, m_gnu_debuglink_crc,
+ m_arch_spec);
}
const ObjectFileELF::ELFSectionHeaderInfo *
@@ -2351,7 +2358,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
.emplace(sect_name.GetCString(),
module_section_list->FindSectionByName(sect_name))
.first;
- if (section_it->second && section_it->second->GetFileSize())
+ if (section_it->second)
symbol_section_sp = section_it->second;
}
@@ -3065,10 +3072,10 @@ void ObjectFileELF::DumpELFHeader(Stream *s, const ELFHeader &header) {
s->Printf("e_flags = 0x%8.8x\n", header.e_flags);
s->Printf("e_ehsize = 0x%4.4x\n", header.e_ehsize);
s->Printf("e_phentsize = 0x%4.4x\n", header.e_phentsize);
- s->Printf("e_phnum = 0x%4.4x\n", header.e_phnum);
+ s->Printf("e_phnum = 0x%8.8x\n", header.e_phnum);
s->Printf("e_shentsize = 0x%4.4x\n", header.e_shentsize);
- s->Printf("e_shnum = 0x%4.4x\n", header.e_shnum);
- s->Printf("e_shstrndx = 0x%4.4x\n", header.e_shstrndx);
+ s->Printf("e_shnum = 0x%8.8x\n", header.e_shnum);
+ s->Printf("e_shstrndx = 0x%8.8x\n", header.e_shstrndx);
}
//----------------------------------------------------------------------
@@ -3315,7 +3322,7 @@ bool ObjectFileELF::GetArchitecture(ArchSpec &arch) {
// headers
// that might shed more light on the architecture
if (ParseProgramHeaders()) {
- for (size_t i = 0, count = GetProgramHeaderCount(); i < count; ++i) {
+ for (size_t i = 1, count = GetProgramHeaderCount(); i <= count; ++i) {
const elf::ELFProgramHeader *header = GetProgramHeaderByIndex(i);
if (header && header->p_type == PT_NOTE && header->p_offset != 0 &&
header->p_filesz > 0) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index 4ce5648..6d8717b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -14,15 +14,14 @@
#include <stdint.h>
// C++ Includes
-#include <functional>
#include <vector>
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/UUID.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/UUID.h"
#include "lldb/lldb-private.h"
#include "ELFHeader.h"
@@ -152,7 +151,7 @@ public:
// Returns segment data for the given index.
lldb_private::DataExtractor GetSegmentDataByIndex(lldb::user_id_t id);
- std::string
+ llvm::StringRef
StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override;
private:
@@ -182,9 +181,6 @@ private:
typedef std::map<lldb::addr_t, lldb::AddressClass>
FileAddressToAddressClassMap;
- typedef std::function<lldb::offset_t(lldb_private::DataExtractor &,
- lldb::offset_t, lldb::offset_t)>
- SetDataFunction;
/// Version of this reader common to all plugins based on this class.
static const uint32_t m_plugin_version = 1;
@@ -230,7 +226,7 @@ private:
// Parses the ELF program headers.
static size_t GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
- const SetDataFunction &set_data,
+ lldb_private::DataExtractor &object_data,
const elf::ELFHeader &header);
// Finds PT_NOTE segments and calculates their crc sum.
@@ -255,7 +251,7 @@ private:
/// Parses the elf section headers and returns the uuid, debug link name, crc,
/// archspec.
static size_t GetSectionHeaderInfo(SectionHeaderColl &section_headers,
- const SetDataFunction &set_data,
+ lldb_private::DataExtractor &object_data,
const elf::ELFHeader &header,
lldb_private::UUID &uuid,
std::string &gnu_debuglink_file,
@@ -375,18 +371,10 @@ private:
unsigned PLTRelocationType();
- static lldb_private::Error
+ static lldb_private::Status
RefineModuleDetailsFromNote(lldb_private::DataExtractor &data,
lldb_private::ArchSpec &arch_spec,
lldb_private::UUID &uuid);
-
- static lldb::offset_t SetData(const lldb_private::DataExtractor &src,
- lldb_private::DataExtractor &dst,
- lldb::offset_t offset, lldb::offset_t length);
-
- lldb::offset_t SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst,
- lldb::offset_t offset,
- lldb::offset_t length);
};
#endif // liblldb_ObjectFileELF_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp
index b5b5e38..06406c6 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp
@@ -12,27 +12,27 @@
#include "ObjectFileJIT.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FileSpecList.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
-#include "lldb/Core/UUID.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
+#include "lldb/Utility/UUID.h"
#ifndef __APPLE__
#include "Utility/UuidCompatibility.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp
index c5a3dde..75bc518 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp
@@ -18,13 +18,11 @@
#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
#include "Plugins/Process/Utility/RegisterContextMemory.h"
#include "Plugins/Process/Utility/ThreadMemory.h"
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionGroupBoolean.h"
@@ -40,6 +38,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadList.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -315,11 +315,11 @@ bool OperatingSystemGo::UpdateThreadList(ThreadList &old_thread_list,
// the
// lldb_private::Process subclass, no memory threads will be in this list.
- Error err;
+ Status err;
for (uint64_t i = 0; i < allglen; ++i) {
goroutines.push_back(CreateGoroutineAtIndex(i, err));
if (err.Fail()) {
- err.PutToLog(log, "OperatingSystemGo::UpdateThreadList");
+ LLDB_LOG(log, "error: {0}", err);
return new_thread_list.GetSize(false) > 0;
}
}
@@ -340,8 +340,8 @@ bool OperatingSystemGo::UpdateThreadList(ThreadList &old_thread_list,
memory_thread->IsValid()) {
memory_thread->ClearBackingThread();
} else {
- memory_thread.reset(new ThreadMemory(
- *m_process, goroutine.m_goid, nullptr, nullptr, goroutine.m_gobuf));
+ memory_thread.reset(new ThreadMemory(*m_process, goroutine.m_goid, "", "",
+ goroutine.m_gobuf));
}
// Search for the backing thread if the goroutine is running.
if (2 == (goroutine.m_status & 0xfff)) {
@@ -448,7 +448,7 @@ TypeSP OperatingSystemGo::FindType(TargetSP target_sp, const char *name) {
}
OperatingSystemGo::Goroutine
-OperatingSystemGo::CreateGoroutineAtIndex(uint64_t idx, Error &err) {
+OperatingSystemGo::CreateGoroutineAtIndex(uint64_t idx, Status &err) {
err.Clear();
Goroutine result = {};
ValueObjectSP g =
diff --git a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h
index d289985..5d255a3 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.h
@@ -80,7 +80,7 @@ private:
bool Init(lldb_private::ThreadList &threads);
- Goroutine CreateGoroutineAtIndex(uint64_t idx, lldb_private::Error &err);
+ Goroutine CreateGoroutineAtIndex(uint64_t idx, lldb_private::Status &err);
std::unique_ptr<DynamicRegisterInfo> m_reginfo;
lldb::ValueObjectSP m_allg_sp;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
index 69826a0..588f3f7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
@@ -18,13 +18,10 @@
#include "Plugins/Process/Utility/RegisterContextMemory.h"
#include "Plugins/Process/Utility/ThreadMemory.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegisterValue.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
@@ -35,6 +32,9 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadList.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
@@ -94,7 +94,7 @@ OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process,
char python_module_path_cstr[PATH_MAX];
python_module_path.GetPath(python_module_path_cstr,
sizeof(python_module_path_cstr));
- Error error;
+ Status error;
if (m_interpreter->LoadScriptingModule(
python_module_path_cstr, allow_reload, init_session, error)) {
// Strip the ".py" extension if there is one
@@ -240,8 +240,8 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo(
uint32_t core_number;
addr_t reg_data_addr;
- std::string name;
- std::string queue;
+ llvm::StringRef name;
+ llvm::StringRef queue;
thread_dict.GetValueForKeyAsInteger("core", core_number, UINT32_MAX);
thread_dict.GetValueForKeyAsInteger("register_data_addr", reg_data_addr,
@@ -266,8 +266,8 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo(
if (!thread_sp) {
if (did_create_ptr)
*did_create_ptr = true;
- thread_sp.reset(new ThreadMemory(*m_process, tid, name.c_str(),
- queue.c_str(), reg_data_addr));
+ thread_sp.reset(
+ new ThreadMemory(*m_process, tid, name, queue, reg_data_addr));
}
if (core_number < core_thread_list.GetSize(false)) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
index 1eec30e..2e16804 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
@@ -16,8 +16,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StructuredData.h"
#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Utility/StructuredData.h"
class DynamicRegisterInfo;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
index 9ea97a5..73c7d21 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -22,22 +22,34 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/BreakpointSite.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Host/Host.h"
+#include "lldb/Core/State.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+
+// Define these constants from FreeBSD mman.h for use when targeting
+// remote FreeBSD systems even when host has different values.
+#define MAP_PRIVATE 0x0002
+#define MAP_ANON 0x1000
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::platform_freebsd;
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+
PlatformSP PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch) {
- // The only time we create an instance is when we are creating a remote
- // freebsd platform
- const bool is_host = false;
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,
+ arch ? arch->GetArchitectureName() : "<null>",
+ arch ? arch->GetTriple().getTriple() : "<null>");
bool create = force;
if (create == false && arch && arch->IsValid()) {
@@ -47,7 +59,7 @@ PlatformSP PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch) {
create = true;
break;
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__FreeBSD__)
// Only accept "unknown" for the OS if the host is BSD and
// it "unknown" wasn't specified (it was just returned because it
// was NOT specified)
@@ -59,8 +71,10 @@ PlatformSP PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch) {
break;
}
}
- if (create)
- return PlatformSP(new PlatformFreeBSD(is_host));
+ LLDB_LOG(log, "create = {0}", create);
+ if (create) {
+ return PlatformSP(new PlatformFreeBSD(false));
+ }
return PlatformSP();
}
@@ -74,369 +88,51 @@ ConstString PlatformFreeBSD::GetPluginNameStatic(bool is_host) {
}
}
-const char *PlatformFreeBSD::GetDescriptionStatic(bool is_host) {
+const char *PlatformFreeBSD::GetPluginDescriptionStatic(bool is_host) {
if (is_host)
return "Local FreeBSD user platform plug-in.";
else
return "Remote FreeBSD user platform plug-in.";
}
-static uint32_t g_initialize_count = 0;
+ConstString PlatformFreeBSD::GetPluginName() {
+ return GetPluginNameStatic(IsHost());
+}
void PlatformFreeBSD::Initialize() {
Platform::Initialize();
if (g_initialize_count++ == 0) {
#if defined(__FreeBSD__)
- // Force a host flag to true for the default platform object.
PlatformSP default_platform_sp(new PlatformFreeBSD(true));
default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
Platform::SetHostPlatform(default_platform_sp);
#endif
- PluginManager::RegisterPlugin(PlatformFreeBSD::GetPluginNameStatic(false),
- PlatformFreeBSD::GetDescriptionStatic(false),
- PlatformFreeBSD::CreateInstance);
+ PluginManager::RegisterPlugin(
+ PlatformFreeBSD::GetPluginNameStatic(false),
+ PlatformFreeBSD::GetPluginDescriptionStatic(false),
+ PlatformFreeBSD::CreateInstance, nullptr);
}
}
void PlatformFreeBSD::Terminate() {
- if (g_initialize_count > 0 && --g_initialize_count == 0)
- PluginManager::UnregisterPlugin(PlatformFreeBSD::CreateInstance);
-
- Platform::Terminate();
-}
-
-bool PlatformFreeBSD::GetModuleSpec(const FileSpec &module_file_spec,
- const ArchSpec &arch,
- ModuleSpec &module_spec) {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch,
- module_spec);
-
- return Platform::GetModuleSpec(module_file_spec, arch, module_spec);
-}
-
-Error PlatformFreeBSD::RunShellCommand(const char *command,
- const FileSpec &working_dir,
- int *status_ptr, int *signo_ptr,
- std::string *command_output,
- uint32_t timeout_sec) {
- if (IsHost())
- return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr,
- command_output, timeout_sec);
- else {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->RunShellCommand(command, working_dir,
- status_ptr, signo_ptr,
- command_output, timeout_sec);
- else
- return Error("unable to run a remote command without a platform");
- }
-}
-
-Error PlatformFreeBSD::ResolveExecutable(
- const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp,
- const FileSpecList *module_search_paths_ptr) {
- Error error;
- // Nothing special to do here, just use the actual file and architecture
-
- char exe_path[PATH_MAX];
- ModuleSpec resolved_module_spec(module_spec);
-
- if (IsHost()) {
- // If we have "ls" as the module_spec's file, resolve the executable
- // location based on
- // the current path variables
- if (!resolved_module_spec.GetFileSpec().Exists()) {
- module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
- resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
- }
-
- if (!resolved_module_spec.GetFileSpec().Exists())
- resolved_module_spec.GetFileSpec().ResolveExecutableLocation();
-
- if (resolved_module_spec.GetFileSpec().Exists())
- error.Clear();
- else {
- error.SetErrorStringWithFormat(
- "unable to find executable for '%s'",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
- } else {
- if (m_remote_platform_sp) {
- error =
- GetCachedExecutable(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr, *m_remote_platform_sp);
- } else {
- // We may connect to a process and use the provided executable (Don't use
- // local $PATH).
-
- // Resolve any executable within a bundle on MacOSX
- Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
-
- if (resolved_module_spec.GetFileSpec().Exists()) {
- error.Clear();
- } else {
- error.SetErrorStringWithFormat(
- "the platform is not currently connected, and '%s' doesn't exist "
- "in the system root.",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
+ if (g_initialize_count > 0) {
+ if (--g_initialize_count == 0) {
+ PluginManager::UnregisterPlugin(PlatformFreeBSD::CreateInstance);
}
}
- if (error.Success()) {
- if (resolved_module_spec.GetArchitecture().IsValid()) {
- error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr, NULL, NULL);
-
- if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) {
- exe_module_sp.reset();
- error.SetErrorStringWithFormat(
- "'%s' doesn't contain the architecture %s",
- resolved_module_spec.GetFileSpec().GetPath().c_str(),
- resolved_module_spec.GetArchitecture().GetArchitectureName());
- }
- } else {
- // No valid architecture was specified, ask the platform for
- // the architectures that we should be using (in the correct order)
- // and see if we can find a match that way
- StreamString arch_names;
- for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
- idx, resolved_module_spec.GetArchitecture());
- ++idx) {
- error =
- ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr, NULL, NULL);
- // Did we find an executable using one of the
- if (error.Success()) {
- if (exe_module_sp && exe_module_sp->GetObjectFile())
- break;
- else
- error.SetErrorToGenericError();
- }
-
- if (idx > 0)
- arch_names.PutCString(", ");
- arch_names.PutCString(
- resolved_module_spec.GetArchitecture().GetArchitectureName());
- }
-
- if (error.Fail() || !exe_module_sp) {
- if (resolved_module_spec.GetFileSpec().Readable()) {
- error.SetErrorStringWithFormat(
- "'%s' doesn't contain any '%s' platform architectures: %s",
- resolved_module_spec.GetFileSpec().GetPath().c_str(),
- GetPluginName().GetCString(), arch_names.GetData());
- } else {
- error.SetErrorStringWithFormat(
- "'%s' is not readable",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
- }
- }
- }
-
- return error;
-}
-
-// From PlatformMacOSX only
-Error PlatformFreeBSD::GetFileWithUUID(const FileSpec &platform_file,
- const UUID *uuid_ptr,
- FileSpec &local_file) {
- if (IsRemote()) {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
- local_file);
- }
-
- // Default to the local case
- local_file = platform_file;
- return Error();
+ PlatformPOSIX::Terminate();
}
//------------------------------------------------------------------
/// Default Constructor
//------------------------------------------------------------------
PlatformFreeBSD::PlatformFreeBSD(bool is_host)
- : Platform(is_host), m_remote_platform_sp() {}
-
-//------------------------------------------------------------------
-/// Destructor.
-///
-/// The destructor is virtual since this class is designed to be
-/// inherited from by the plug-in instance.
-//------------------------------------------------------------------
-PlatformFreeBSD::~PlatformFreeBSD() {}
+ : PlatformPOSIX(is_host) // This is the local host platform
+{}
-// TODO:VK: inherit PlatformPOSIX
-
-bool PlatformFreeBSD::GetRemoteOSVersion() {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetOSVersion(
- m_major_os_version, m_minor_os_version, m_update_os_version);
- return false;
-}
-
-bool PlatformFreeBSD::GetRemoteOSBuildString(std::string &s) {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetRemoteOSBuildString(s);
- s.clear();
- return false;
-}
-
-bool PlatformFreeBSD::GetRemoteOSKernelDescription(std::string &s) {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetRemoteOSKernelDescription(s);
- s.clear();
- return false;
-}
-
-// Remote Platform subclasses need to override this function
-ArchSpec PlatformFreeBSD::GetRemoteSystemArchitecture() {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetRemoteSystemArchitecture();
- return ArchSpec();
-}
-
-const char *PlatformFreeBSD::GetHostname() {
- if (IsHost())
- return Platform::GetHostname();
-
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetHostname();
- return NULL;
-}
-
-bool PlatformFreeBSD::IsConnected() const {
- if (IsHost())
- return true;
- else if (m_remote_platform_sp)
- return m_remote_platform_sp->IsConnected();
- return false;
-}
-
-Error PlatformFreeBSD::ConnectRemote(Args &args) {
- Error error;
- if (IsHost()) {
- error.SetErrorStringWithFormat(
- "can't connect to the host platform '%s', always connected",
- GetPluginName().GetCString());
- } else {
- if (!m_remote_platform_sp)
- m_remote_platform_sp =
- Platform::Create(ConstString("remote-gdb-server"), error);
-
- if (m_remote_platform_sp) {
- if (error.Success()) {
- if (m_remote_platform_sp) {
- error = m_remote_platform_sp->ConnectRemote(args);
- } else {
- error.SetErrorString(
- "\"platform connect\" takes a single argument: <connect-url>");
- }
- }
- } else
- error.SetErrorString("failed to create a 'remote-gdb-server' platform");
-
- if (error.Fail())
- m_remote_platform_sp.reset();
- }
-
- return error;
-}
-
-Error PlatformFreeBSD::DisconnectRemote() {
- Error error;
-
- if (IsHost()) {
- error.SetErrorStringWithFormat(
- "can't disconnect from the host platform '%s', always connected",
- GetPluginName().GetCString());
- } else {
- if (m_remote_platform_sp)
- error = m_remote_platform_sp->DisconnectRemote();
- else
- error.SetErrorString("the platform is not currently connected");
- }
- return error;
-}
-
-bool PlatformFreeBSD::GetProcessInfo(lldb::pid_t pid,
- ProcessInstanceInfo &process_info) {
- bool success = false;
- if (IsHost()) {
- success = Platform::GetProcessInfo(pid, process_info);
- } else if (m_remote_platform_sp) {
- success = m_remote_platform_sp->GetProcessInfo(pid, process_info);
- }
- return success;
-}
-
-uint32_t
-PlatformFreeBSD::FindProcesses(const ProcessInstanceInfoMatch &match_info,
- ProcessInstanceInfoList &process_infos) {
- uint32_t match_count = 0;
- if (IsHost()) {
- // Let the base class figure out the host details
- match_count = Platform::FindProcesses(match_info, process_infos);
- } else {
- // If we are remote, we can only return results if we are connected
- if (m_remote_platform_sp)
- match_count =
- m_remote_platform_sp->FindProcesses(match_info, process_infos);
- }
- return match_count;
-}
-
-const char *PlatformFreeBSD::GetUserName(uint32_t uid) {
- // Check the cache in Platform in case we have already looked this uid up
- const char *user_name = Platform::GetUserName(uid);
- if (user_name)
- return user_name;
-
- if (IsRemote() && m_remote_platform_sp)
- return m_remote_platform_sp->GetUserName(uid);
- return NULL;
-}
-
-const char *PlatformFreeBSD::GetGroupName(uint32_t gid) {
- const char *group_name = Platform::GetGroupName(gid);
- if (group_name)
- return group_name;
-
- if (IsRemote() && m_remote_platform_sp)
- return m_remote_platform_sp->GetGroupName(gid);
- return NULL;
-}
-
-Error PlatformFreeBSD::GetSharedModule(
- const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr,
- bool *did_create_ptr) {
- Error error;
- module_sp.reset();
-
- if (IsRemote()) {
- // If we have a remote platform always, let it try and locate
- // the shared module first.
- if (m_remote_platform_sp) {
- error = m_remote_platform_sp->GetSharedModule(
- module_spec, process, module_sp, module_search_paths_ptr,
- old_module_sp_ptr, did_create_ptr);
- }
- }
-
- if (!module_sp) {
- // Fall back to the local platform and find the file locally
- error = Platform::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr,
- old_module_sp_ptr, did_create_ptr);
- }
- if (module_sp)
- module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
- return error;
-}
+PlatformFreeBSD::~PlatformFreeBSD() = default;
bool PlatformFreeBSD::GetSupportedArchitectureAtIndex(uint32_t idx,
ArchSpec &arch) {
@@ -507,26 +203,23 @@ bool PlatformFreeBSD::GetSupportedArchitectureAtIndex(uint32_t idx,
}
void PlatformFreeBSD::GetStatus(Stream &strm) {
-#ifndef LLDB_DISABLE_POSIX
- struct utsname un;
-
- strm << " Host: ";
+ Platform::GetStatus(strm);
- ::memset(&un, 0, sizeof(utsname));
- if (uname(&un) == -1)
- strm << "FreeBSD" << '\n';
+#ifndef LLDB_DISABLE_POSIX
+ // Display local kernel information only when we are running in host mode.
+ // Otherwise, we would end up printing non-FreeBSD information (when running
+ // on Mac OS for example).
+ if (IsHost()) {
+ struct utsname un;
- strm << un.sysname << ' ' << un.release;
- if (un.nodename[0] != '\0')
- strm << " (" << un.nodename << ')';
- strm << '\n';
+ if (uname(&un))
+ return;
- // Dump a common information about the platform status.
- strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version
- << '\n';
+ strm.Printf(" Kernel: %s\n", un.sysname);
+ strm.Printf(" Release: %s\n", un.release);
+ strm.Printf(" Version: %s\n", un.version);
+ }
#endif
-
- Platform::GetStatus(strm);
}
size_t
@@ -549,6 +242,12 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode(Target &target,
// FreeBSD kernel as of 10.x, does not support thumb breakpoints
return 0;
}
+
+ static const uint8_t g_arm_breakpoint_opcode[] = {0xFE, 0xDE, 0xFF, 0xE7};
+ size_t trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ assert(bp_site);
+ if (bp_site->SetTrapOpcode(g_arm_breakpoint_opcode, trap_opcode_size))
+ return trap_opcode_size;
}
LLVM_FALLTHROUGH;
default:
@@ -556,12 +255,8 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode(Target &target,
}
}
-void PlatformFreeBSD::CalculateTrapHandlerSymbolNames() {
- m_trap_handlers.push_back(ConstString("_sigtramp"));
-}
-
-Error PlatformFreeBSD::LaunchProcess(ProcessLaunchInfo &launch_info) {
- Error error;
+Status PlatformFreeBSD::LaunchProcess(ProcessLaunchInfo &launch_info) {
+ Status error;
if (IsHost()) {
error = Platform::LaunchProcess(launch_info);
} else {
@@ -575,7 +270,7 @@ Error PlatformFreeBSD::LaunchProcess(ProcessLaunchInfo &launch_info) {
lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
Debugger &debugger, Target *target,
- Error &error) {
+ Status &error) {
lldb::ProcessSP process_sp;
if (IsHost()) {
if (target == NULL) {
@@ -609,3 +304,29 @@ lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
}
return process_sp;
}
+
+// FreeBSD processes cannot yet be launched by spawning and attaching.
+bool PlatformFreeBSD::CanDebugProcess() {
+ return false;
+}
+
+void PlatformFreeBSD::CalculateTrapHandlerSymbolNames() {
+ m_trap_handlers.push_back(ConstString("_sigtramp"));
+}
+
+MmapArgList PlatformFreeBSD::GetMmapArgumentList(const ArchSpec &arch,
+ addr_t addr, addr_t length,
+ unsigned prot, unsigned flags,
+ addr_t fd, addr_t offset) {
+ uint64_t flags_platform = 0;
+
+ if (flags & eMmapFlagsPrivate)
+ flags_platform |= MAP_PRIVATE;
+ if (flags & eMmapFlagsAnon)
+ flags_platform |= MAP_ANON;
+
+ MmapArgList args({addr, length, prot, flags_platform, fd, offset});
+ if (arch.GetTriple().getArch() == llvm::Triple::x86)
+ args.push_back(0);
+ return args;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
index f0ebfbc..2743048 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
@@ -10,116 +10,61 @@
#ifndef liblldb_PlatformFreeBSD_h_
#define liblldb_PlatformFreeBSD_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Target/Platform.h"
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
namespace lldb_private {
namespace platform_freebsd {
-class PlatformFreeBSD : public Platform {
+class PlatformFreeBSD : public PlatformPOSIX {
public:
PlatformFreeBSD(bool is_host);
~PlatformFreeBSD() override;
- //------------------------------------------------------------
- // Class functions
- //------------------------------------------------------------
- static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
-
static void Initialize();
static void Terminate();
- static ConstString GetPluginNameStatic(bool is_host);
-
- static const char *GetDescriptionStatic(bool is_host);
-
//------------------------------------------------------------
// lldb_private::PluginInterface functions
//------------------------------------------------------------
- ConstString GetPluginName() override { return GetPluginNameStatic(IsHost()); }
+ static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
- uint32_t GetPluginVersion() override { return 1; }
+ static ConstString GetPluginNameStatic(bool is_host);
- const char *GetDescription() override {
- return GetDescriptionStatic(IsHost());
- }
+ static const char *GetPluginDescriptionStatic(bool is_host);
+
+ ConstString GetPluginName() override;
+
+ uint32_t GetPluginVersion() override { return 1; }
//------------------------------------------------------------
// lldb_private::Platform functions
//------------------------------------------------------------
- bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch,
- ModuleSpec &module_spec) override;
+ const char *GetDescription() override {
+ return GetPluginDescriptionStatic(IsHost());
+ }
- Error RunShellCommand(const char *command, const FileSpec &working_dir,
- int *status_ptr, int *signo_ptr,
- std::string *command_output,
- uint32_t timeout_sec) override;
+ void GetStatus(Stream &strm) override;
+
+ bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
- Error ResolveExecutable(const ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr) override;
+ bool CanDebugProcess() override;
size_t GetSoftwareBreakpointTrapOpcode(Target &target,
BreakpointSite *bp_site) override;
- bool GetRemoteOSVersion() override;
-
- bool GetRemoteOSBuildString(std::string &s) override;
-
- bool GetRemoteOSKernelDescription(std::string &s) override;
-
- // Remote Platform subclasses need to override this function
- ArchSpec GetRemoteSystemArchitecture() override;
-
- bool IsConnected() const override;
-
- Error ConnectRemote(Args &args) override;
-
- Error DisconnectRemote() override;
-
- const char *GetHostname() override;
-
- const char *GetUserName(uint32_t uid) override;
-
- const char *GetGroupName(uint32_t gid) override;
-
- bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info) override;
-
- uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info,
- ProcessInstanceInfoList &process_infos) override;
-
- Error LaunchProcess(ProcessLaunchInfo &launch_info) override;
+ Status LaunchProcess(ProcessLaunchInfo &launch_info) override;
lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger,
- Target *target, Error &error) override;
-
- // FreeBSD processes can not be launched by spawning and attaching.
- bool CanDebugProcess() override { return false; }
-
- // Only on PlatformMacOSX:
- Error GetFileWithUUID(const FileSpec &platform_file, const UUID *uuid,
- FileSpec &local_file) override;
-
- Error GetSharedModule(const ModuleSpec &module_spec, Process *process,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
- lldb::ModuleSP *old_module_sp_ptr,
- bool *did_create_ptr) override;
-
- bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
-
- void GetStatus(Stream &strm) override;
+ Target *target, Status &error) override;
void CalculateTrapHandlerSymbolNames() override;
-protected:
- lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a
- // remote freebsd OS
+ MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,
+ lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd,
+ lldb::addr_t offset) override;
private:
DISALLOW_COPY_AND_ASSIGN(PlatformFreeBSD);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp
index bc4bfd3..28ff117 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp
@@ -19,25 +19,45 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Breakpoint/BreakpointSite.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Host/Host.h"
+#include "lldb/Core/State.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+
+// Define these constants from NetBSD mman.h for use when targeting
+// remote netbsd systems even when host has different values.
+#define MAP_PRIVATE 0x0002
+#define MAP_ANON 0x1000
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::platform_netbsd;
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+
PlatformSP PlatformNetBSD::CreateInstance(bool force, const ArchSpec *arch) {
- // The only time we create an instance is when we are creating a remote
- // netbsd platform
- const bool is_host = false;
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log) {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName())
+ arch_name = arch->GetArchitectureName();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr =
+ arch ? arch->GetTriple().getTriple().c_str() : "<null>";
+
+ log->Printf("PlatformNetBSD::%s(force=%s, arch={%s,%s})", __FUNCTION__,
+ force ? "true" : "false", arch_name, triple_cstr);
+ }
bool create = force;
if (create == false && arch && arch->IsValid()) {
@@ -51,8 +71,19 @@ PlatformSP PlatformNetBSD::CreateInstance(bool force, const ArchSpec *arch) {
break;
}
}
- if (create)
- return PlatformSP(new PlatformNetBSD(is_host));
+
+ if (create) {
+ if (log)
+ log->Printf("PlatformNetBSD::%s() creating remote-netbsd platform",
+ __FUNCTION__);
+ return PlatformSP(new PlatformNetBSD(false));
+ }
+
+ if (log)
+ log->Printf(
+ "PlatformNetBSD::%s() aborting creation of remote-netbsd platform",
+ __FUNCTION__);
+
return PlatformSP();
}
@@ -66,359 +97,51 @@ ConstString PlatformNetBSD::GetPluginNameStatic(bool is_host) {
}
}
-const char *PlatformNetBSD::GetDescriptionStatic(bool is_host) {
+const char *PlatformNetBSD::GetPluginDescriptionStatic(bool is_host) {
if (is_host)
return "Local NetBSD user platform plug-in.";
else
return "Remote NetBSD user platform plug-in.";
}
-static uint32_t g_initialize_count = 0;
+ConstString PlatformNetBSD::GetPluginName() {
+ return GetPluginNameStatic(IsHost());
+}
void PlatformNetBSD::Initialize() {
- Platform::Initialize();
+ PlatformPOSIX::Initialize();
if (g_initialize_count++ == 0) {
#if defined(__NetBSD__)
- // Force a host flag to true for the default platform object.
PlatformSP default_platform_sp(new PlatformNetBSD(true));
default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
Platform::SetHostPlatform(default_platform_sp);
#endif
- PluginManager::RegisterPlugin(PlatformNetBSD::GetPluginNameStatic(false),
- PlatformNetBSD::GetDescriptionStatic(false),
- PlatformNetBSD::CreateInstance);
+ PluginManager::RegisterPlugin(
+ PlatformNetBSD::GetPluginNameStatic(false),
+ PlatformNetBSD::GetPluginDescriptionStatic(false),
+ PlatformNetBSD::CreateInstance, nullptr);
}
}
void PlatformNetBSD::Terminate() {
- if (g_initialize_count > 0 && --g_initialize_count == 0)
- PluginManager::UnregisterPlugin(PlatformNetBSD::CreateInstance);
-
- Platform::Terminate();
-}
-
-bool PlatformNetBSD::GetModuleSpec(const FileSpec &module_file_spec,
- const ArchSpec &arch,
- ModuleSpec &module_spec) {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch,
- module_spec);
-
- return Platform::GetModuleSpec(module_file_spec, arch, module_spec);
-}
-
-Error PlatformNetBSD::RunShellCommand(const char *command,
- const FileSpec &working_dir,
- int *status_ptr, int *signo_ptr,
- std::string *command_output,
- uint32_t timeout_sec) {
- if (IsHost())
- return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr,
- command_output, timeout_sec);
- else {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->RunShellCommand(command, working_dir,
- status_ptr, signo_ptr,
- command_output, timeout_sec);
- else
- return Error("unable to run a remote command without a platform");
- }
-}
-
-Error PlatformNetBSD::ResolveExecutable(
- const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp,
- const FileSpecList *module_search_paths_ptr) {
- Error error;
- // Nothing special to do here, just use the actual file and architecture
-
- char exe_path[PATH_MAX];
- ModuleSpec resolved_module_spec(module_spec);
-
- if (IsHost()) {
- // If we have "ls" as the module_spec's file, resolve the executable
- // location based on
- // the current path variables
- if (!resolved_module_spec.GetFileSpec().Exists()) {
- module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
- resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
- }
-
- if (!resolved_module_spec.GetFileSpec().Exists())
- resolved_module_spec.GetFileSpec().ResolveExecutableLocation();
-
- if (resolved_module_spec.GetFileSpec().Exists())
- error.Clear();
- else {
- error.SetErrorStringWithFormat(
- "unable to find executable for '%s'",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
- } else {
- if (m_remote_platform_sp) {
- error =
- GetCachedExecutable(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr, *m_remote_platform_sp);
- } else {
- // We may connect to a process and use the provided executable (Don't use
- // local $PATH).
-
- // Resolve any executable within a bundle on MacOSX
- Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
-
- if (resolved_module_spec.GetFileSpec().Exists()) {
- error.Clear();
- } else {
- error.SetErrorStringWithFormat(
- "the platform is not currently connected, and '%s' doesn't exist "
- "in the system root.",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
+ if (g_initialize_count > 0) {
+ if (--g_initialize_count == 0) {
+ PluginManager::UnregisterPlugin(PlatformNetBSD::CreateInstance);
}
}
- if (error.Success()) {
- if (resolved_module_spec.GetArchitecture().IsValid()) {
- error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr, NULL, NULL);
-
- if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) {
- exe_module_sp.reset();
- error.SetErrorStringWithFormat(
- "'%s' doesn't contain the architecture %s",
- resolved_module_spec.GetFileSpec().GetPath().c_str(),
- resolved_module_spec.GetArchitecture().GetArchitectureName());
- }
- } else {
- // No valid architecture was specified, ask the platform for
- // the architectures that we should be using (in the correct order)
- // and see if we can find a match that way
- StreamString arch_names;
- for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
- idx, resolved_module_spec.GetArchitecture());
- ++idx) {
- error =
- ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr, NULL, NULL);
- // Did we find an executable using one of the
- if (error.Success()) {
- if (exe_module_sp && exe_module_sp->GetObjectFile())
- break;
- else
- error.SetErrorToGenericError();
- }
-
- if (idx > 0)
- arch_names.PutCString(", ");
- arch_names.PutCString(
- resolved_module_spec.GetArchitecture().GetArchitectureName());
- }
-
- if (error.Fail() || !exe_module_sp) {
- if (resolved_module_spec.GetFileSpec().Readable()) {
- error.SetErrorStringWithFormat(
- "'%s' doesn't contain any '%s' platform architectures: %s",
- resolved_module_spec.GetFileSpec().GetPath().c_str(),
- GetPluginName().GetCString(), arch_names.GetData());
- } else {
- error.SetErrorStringWithFormat(
- "'%s' is not readable",
- resolved_module_spec.GetFileSpec().GetPath().c_str());
- }
- }
- }
- }
-
- return error;
-}
-
-// From PlatformMacOSX only
-Error PlatformNetBSD::GetFileWithUUID(const FileSpec &platform_file,
- const UUID *uuid_ptr,
- FileSpec &local_file) {
- if (IsRemote()) {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
- local_file);
- }
-
- // Default to the local case
- local_file = platform_file;
- return Error();
+ PlatformPOSIX::Terminate();
}
//------------------------------------------------------------------
/// Default Constructor
//------------------------------------------------------------------
PlatformNetBSD::PlatformNetBSD(bool is_host)
- : Platform(is_host), m_remote_platform_sp() {}
-
-bool PlatformNetBSD::GetRemoteOSVersion() {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetOSVersion(
- m_major_os_version, m_minor_os_version, m_update_os_version);
- return false;
-}
-
-bool PlatformNetBSD::GetRemoteOSBuildString(std::string &s) {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetRemoteOSBuildString(s);
- s.clear();
- return false;
-}
-
-bool PlatformNetBSD::GetRemoteOSKernelDescription(std::string &s) {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetRemoteOSKernelDescription(s);
- s.clear();
- return false;
-}
-
-// Remote Platform subclasses need to override this function
-ArchSpec PlatformNetBSD::GetRemoteSystemArchitecture() {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetRemoteSystemArchitecture();
- return ArchSpec();
-}
-
-const char *PlatformNetBSD::GetHostname() {
- if (IsHost())
- return Platform::GetHostname();
-
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetHostname();
- return NULL;
-}
-
-bool PlatformNetBSD::IsConnected() const {
- if (IsHost())
- return true;
- else if (m_remote_platform_sp)
- return m_remote_platform_sp->IsConnected();
- return false;
-}
-
-Error PlatformNetBSD::ConnectRemote(Args &args) {
- Error error;
- if (IsHost()) {
- error.SetErrorStringWithFormat(
- "can't connect to the host platform '%s', always connected",
- GetPluginName().GetCString());
- } else {
- if (!m_remote_platform_sp)
- m_remote_platform_sp =
- Platform::Create(ConstString("remote-gdb-server"), error);
-
- if (m_remote_platform_sp) {
- if (error.Success()) {
- if (m_remote_platform_sp) {
- error = m_remote_platform_sp->ConnectRemote(args);
- } else {
- error.SetErrorString(
- "\"platform connect\" takes a single argument: <connect-url>");
- }
- }
- } else
- error.SetErrorString("failed to create a 'remote-gdb-server' platform");
-
- if (error.Fail())
- m_remote_platform_sp.reset();
- }
-
- return error;
-}
+ : PlatformPOSIX(is_host) // This is the local host platform
+{}
-Error PlatformNetBSD::DisconnectRemote() {
- Error error;
-
- if (IsHost()) {
- error.SetErrorStringWithFormat(
- "can't disconnect from the host platform '%s', always connected",
- GetPluginName().GetCString());
- } else {
- if (m_remote_platform_sp)
- error = m_remote_platform_sp->DisconnectRemote();
- else
- error.SetErrorString("the platform is not currently connected");
- }
- return error;
-}
-
-bool PlatformNetBSD::GetProcessInfo(lldb::pid_t pid,
- ProcessInstanceInfo &process_info) {
- bool success = false;
- if (IsHost()) {
- success = Platform::GetProcessInfo(pid, process_info);
- } else if (m_remote_platform_sp) {
- success = m_remote_platform_sp->GetProcessInfo(pid, process_info);
- }
- return success;
-}
-
-uint32_t
-PlatformNetBSD::FindProcesses(const ProcessInstanceInfoMatch &match_info,
- ProcessInstanceInfoList &process_infos) {
- uint32_t match_count = 0;
- if (IsHost()) {
- // Let the base class figure out the host details
- match_count = Platform::FindProcesses(match_info, process_infos);
- } else {
- // If we are remote, we can only return results if we are connected
- if (m_remote_platform_sp)
- match_count =
- m_remote_platform_sp->FindProcesses(match_info, process_infos);
- }
- return match_count;
-}
-
-const char *PlatformNetBSD::GetUserName(uint32_t uid) {
- // Check the cache in Platform in case we have already looked this uid up
- const char *user_name = Platform::GetUserName(uid);
- if (user_name)
- return user_name;
-
- if (IsRemote() && m_remote_platform_sp)
- return m_remote_platform_sp->GetUserName(uid);
- return NULL;
-}
-
-const char *PlatformNetBSD::GetGroupName(uint32_t gid) {
- const char *group_name = Platform::GetGroupName(gid);
- if (group_name)
- return group_name;
-
- if (IsRemote() && m_remote_platform_sp)
- return m_remote_platform_sp->GetGroupName(gid);
- return NULL;
-}
-
-Error PlatformNetBSD::GetSharedModule(
- const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr,
- bool *did_create_ptr) {
- Error error;
- module_sp.reset();
-
- if (IsRemote()) {
- // If we have a remote platform always, let it try and locate
- // the shared module first.
- if (m_remote_platform_sp) {
- error = m_remote_platform_sp->GetSharedModule(
- module_spec, process, module_sp, module_search_paths_ptr,
- old_module_sp_ptr, did_create_ptr);
- }
- }
-
- if (!module_sp) {
- // Fall back to the local platform and find the file locally
- error = Platform::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr,
- old_module_sp_ptr, did_create_ptr);
- }
- if (module_sp)
- module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
- return error;
-}
+PlatformNetBSD::~PlatformNetBSD() = default;
bool PlatformNetBSD::GetSupportedArchitectureAtIndex(uint32_t idx,
ArchSpec &arch) {
@@ -471,79 +194,243 @@ bool PlatformNetBSD::GetSupportedArchitectureAtIndex(uint32_t idx,
}
void PlatformNetBSD::GetStatus(Stream &strm) {
+ Platform::GetStatus(strm);
+
#ifndef LLDB_DISABLE_POSIX
- struct ::utsname un;
+ // Display local kernel information only when we are running in host mode.
+ // Otherwise, we would end up printing non-NetBSD information (when running
+ // on Mac OS for example).
+ if (IsHost()) {
+ struct utsname un;
- strm << " Host: ";
+ if (uname(&un))
+ return;
- ::memset(&un, 0, sizeof(utsname));
- if (::uname(&un) == -1) {
- strm << "NetBSD" << '\n';
- } else {
- strm << un.sysname << ' ' << un.release;
- if (un.nodename[0] != '\0')
- strm << " (" << un.nodename << ')';
- strm << '\n';
-
- // Dump a common information about the platform status.
- strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version
- << '\n';
+ strm.Printf(" Kernel: %s\n", un.sysname);
+ strm.Printf(" Release: %s\n", un.release);
+ strm.Printf(" Version: %s\n", un.version);
}
#endif
-
- Platform::GetStatus(strm);
}
-void PlatformNetBSD::CalculateTrapHandlerSymbolNames() {
- m_trap_handlers.push_back(ConstString("_sigtramp"));
+int32_t
+PlatformNetBSD::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) {
+ int32_t resume_count = 0;
+
+ // Always resume past the initial stop when we use eLaunchFlagDebug
+ if (launch_info.GetFlags().Test(eLaunchFlagDebug)) {
+ // Resume past the stop for the final exec into the true inferior.
+ ++resume_count;
+ }
+
+ // If we're not launching a shell, we're done.
+ const FileSpec &shell = launch_info.GetShell();
+ if (!shell)
+ return resume_count;
+
+ std::string shell_string = shell.GetPath();
+ // We're in a shell, so for sure we have to resume past the shell exec.
+ ++resume_count;
+
+ // Figure out what shell we're planning on using.
+ const char *shell_name = strrchr(shell_string.c_str(), '/');
+ if (shell_name == NULL)
+ shell_name = shell_string.c_str();
+ else
+ shell_name++;
+
+ if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 ||
+ strcmp(shell_name, "zsh") == 0 || strcmp(shell_name, "sh") == 0) {
+ // These shells seem to re-exec themselves. Add another resume.
+ ++resume_count;
+ }
+
+ return resume_count;
}
-Error PlatformNetBSD::LaunchProcess(ProcessLaunchInfo &launch_info) {
- Error error;
+bool PlatformNetBSD::CanDebugProcess() {
if (IsHost()) {
- error = Platform::LaunchProcess(launch_info);
+ return true;
} else {
- if (m_remote_platform_sp)
- error = m_remote_platform_sp->LaunchProcess(launch_info);
- else
- error.SetErrorString("the platform is not currently connected");
+ // If we're connected, we can debug.
+ return IsConnected();
}
- return error;
}
-lldb::ProcessSP PlatformNetBSD::Attach(ProcessAttachInfo &attach_info,
- Debugger &debugger, Target *target,
- Error &error) {
- lldb::ProcessSP process_sp;
- if (IsHost()) {
- if (target == NULL) {
- TargetSP new_target_sp;
- ArchSpec emptyArchSpec;
-
- error = debugger.GetTargetList().CreateTarget(debugger, "", emptyArchSpec,
- false, m_remote_platform_sp,
- new_target_sp);
- target = new_target_sp.get();
- } else
- error.Clear();
-
- if (target && error.Success()) {
- debugger.GetTargetList().SetSelectedTarget(target);
- // The netbsd always currently uses the GDB remote debugger plug-in
- // so even when debugging locally we are debugging remotely!
- // Just like the darwin plugin.
- process_sp = target->CreateProcess(
- attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
-
- if (process_sp)
- error = process_sp->Attach(attach_info);
+// For local debugging, NetBSD will override the debug logic to use llgs-launch
+// rather than
+// lldb-launch, llgs-attach. This differs from current lldb-launch,
+// debugserver-attach
+// approach on MacOSX.
+lldb::ProcessSP PlatformNetBSD::DebugProcess(
+ ProcessLaunchInfo &launch_info, Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new
+ // target, else use existing one
+ Status &error) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("PlatformNetBSD::%s entered (target %p)", __FUNCTION__,
+ static_cast<void *>(target));
+
+ // If we're a remote host, use standard behavior from parent class.
+ if (!IsHost())
+ return PlatformPOSIX::DebugProcess(launch_info, debugger, target, error);
+
+ //
+ // For local debugging, we'll insist on having ProcessGDBRemote create the
+ // process.
+ //
+
+ ProcessSP process_sp;
+
+ // Make sure we stop at the entry point
+ launch_info.GetFlags().Set(eLaunchFlagDebug);
+
+ // We always launch the process we are going to debug in a separate process
+ // group, since then we can handle ^C interrupts ourselves w/o having to worry
+ // about the target getting them as well.
+ launch_info.SetLaunchInSeparateProcessGroup(true);
+
+ // Ensure we have a target.
+ if (target == nullptr) {
+ if (log)
+ log->Printf("PlatformNetBSD::%s creating new target", __FUNCTION__);
+
+ TargetSP new_target_sp;
+ error = debugger.GetTargetList().CreateTarget(debugger, "", "", false,
+ nullptr, new_target_sp);
+ if (error.Fail()) {
+ if (log)
+ log->Printf("PlatformNetBSD::%s failed to create new target: %s",
+ __FUNCTION__, error.AsCString());
+ return process_sp;
+ }
+
+ target = new_target_sp.get();
+ if (!target) {
+ error.SetErrorString("CreateTarget() returned nullptr");
+ if (log)
+ log->Printf("PlatformNetBSD::%s failed: %s", __FUNCTION__,
+ error.AsCString());
+ return process_sp;
}
} else {
- if (m_remote_platform_sp)
- process_sp =
- m_remote_platform_sp->Attach(attach_info, debugger, target, error);
- else
- error.SetErrorString("the platform is not currently connected");
+ if (log)
+ log->Printf("PlatformNetBSD::%s using provided target", __FUNCTION__);
+ }
+
+ // Mark target as currently selected target.
+ debugger.GetTargetList().SetSelectedTarget(target);
+
+ // Now create the gdb-remote process.
+ if (log)
+ log->Printf(
+ "PlatformNetBSD::%s having target create process with gdb-remote plugin",
+ __FUNCTION__);
+ process_sp = target->CreateProcess(
+ launch_info.GetListenerForProcess(debugger), "gdb-remote", nullptr);
+
+ if (!process_sp) {
+ error.SetErrorString("CreateProcess() failed for gdb-remote process");
+ if (log)
+ log->Printf("PlatformNetBSD::%s failed: %s", __FUNCTION__,
+ error.AsCString());
+ return process_sp;
+ } else {
+ if (log)
+ log->Printf("PlatformNetBSD::%s successfully created process",
+ __FUNCTION__);
}
+
+ // Adjust launch for a hijacker.
+ ListenerSP listener_sp;
+ if (!launch_info.GetHijackListener()) {
+ if (log)
+ log->Printf("PlatformNetBSD::%s setting up hijacker", __FUNCTION__);
+
+ listener_sp =
+ Listener::MakeListener("lldb.PlatformNetBSD.DebugProcess.hijack");
+ launch_info.SetHijackListener(listener_sp);
+ process_sp->HijackProcessEvents(listener_sp);
+ }
+
+ // Log file actions.
+ if (log) {
+ log->Printf(
+ "PlatformNetBSD::%s launching process with the following file actions:",
+ __FUNCTION__);
+
+ StreamString stream;
+ size_t i = 0;
+ const FileAction *file_action;
+ while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) {
+ file_action->Dump(stream);
+ log->PutCString(stream.GetData());
+ stream.Clear();
+ }
+ }
+
+ // Do the launch.
+ error = process_sp->Launch(launch_info);
+ if (error.Success()) {
+ // Handle the hijacking of process events.
+ if (listener_sp) {
+ const StateType state = process_sp->WaitForProcessToStop(
+ llvm::None, NULL, false, listener_sp);
+
+ if (state == eStateStopped) {
+ if (log)
+ log->Printf("PlatformNetBSD::%s pid %" PRIu64 " state %s\n",
+ __FUNCTION__, process_sp->GetID(), StateAsCString(state));
+ } else {
+ if (log)
+ log->Printf("PlatformNetBSD::%s pid %" PRIu64
+ " state is not stopped - %s\n",
+ __FUNCTION__, process_sp->GetID(), StateAsCString(state));
+ }
+ }
+
+ // Hook up process PTY if we have one (which we should for local debugging
+ // with llgs).
+ int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
+ if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd) {
+ process_sp->SetSTDIOFileDescriptor(pty_fd);
+ if (log)
+ log->Printf("PlatformNetBSD::%s pid %" PRIu64
+ " hooked up STDIO pty to process",
+ __FUNCTION__, process_sp->GetID());
+ } else {
+ if (log)
+ log->Printf("PlatformNetBSD::%s pid %" PRIu64
+ " not using process STDIO pty",
+ __FUNCTION__, process_sp->GetID());
+ }
+ } else {
+ if (log)
+ log->Printf("PlatformNetBSD::%s process launch failed: %s", __FUNCTION__,
+ error.AsCString());
+ // FIXME figure out appropriate cleanup here. Do we delete the target? Do
+ // we delete the process? Does our caller do that?
+ }
+
return process_sp;
}
+
+void PlatformNetBSD::CalculateTrapHandlerSymbolNames() {
+ m_trap_handlers.push_back(ConstString("_sigtramp"));
+}
+
+MmapArgList PlatformNetBSD::GetMmapArgumentList(const ArchSpec &arch,
+ addr_t addr, addr_t length,
+ unsigned prot, unsigned flags,
+ addr_t fd, addr_t offset) {
+ uint64_t flags_platform = 0;
+
+ if (flags & eMmapFlagsPrivate)
+ flags_platform |= MAP_PRIVATE;
+ if (flags & eMmapFlagsAnon)
+ flags_platform |= MAP_ANON;
+
+ MmapArgList args({addr, length, prot, flags_platform, fd, offset});
+ return args;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h
index ddca5eb..28a5d67 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h
@@ -10,113 +10,59 @@
#ifndef liblldb_PlatformNetBSD_h_
#define liblldb_PlatformNetBSD_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Target/Platform.h"
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
namespace lldb_private {
namespace platform_netbsd {
-class PlatformNetBSD : public Platform {
+class PlatformNetBSD : public PlatformPOSIX {
public:
PlatformNetBSD(bool is_host);
- ~PlatformNetBSD() override = default;
-
- //------------------------------------------------------------
- // Class functions
- //------------------------------------------------------------
- static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
+ ~PlatformNetBSD() override;
static void Initialize();
static void Terminate();
- static ConstString GetPluginNameStatic(bool is_host);
-
- static const char *GetDescriptionStatic(bool is_host);
-
//------------------------------------------------------------
// lldb_private::PluginInterface functions
//------------------------------------------------------------
- ConstString GetPluginName() override { return GetPluginNameStatic(IsHost()); }
+ static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
- uint32_t GetPluginVersion() override { return 1; }
+ static ConstString GetPluginNameStatic(bool is_host);
- const char *GetDescription() override {
- return GetDescriptionStatic(IsHost());
- }
+ static const char *GetPluginDescriptionStatic(bool is_host);
+
+ ConstString GetPluginName() override;
+
+ uint32_t GetPluginVersion() override { return 1; }
//------------------------------------------------------------
// lldb_private::Platform functions
//------------------------------------------------------------
- bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch,
- ModuleSpec &module_spec) override;
-
- Error RunShellCommand(const char *command, const FileSpec &working_dir,
- int *status_ptr, int *signo_ptr,
- std::string *command_output,
- uint32_t timeout_sec) override;
-
- Error ResolveExecutable(const ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr) override;
-
- bool GetRemoteOSVersion() override;
-
- bool GetRemoteOSBuildString(std::string &s) override;
-
- bool GetRemoteOSKernelDescription(std::string &s) override;
-
- // Remote Platform subclasses need to override this function
- ArchSpec GetRemoteSystemArchitecture() override;
-
- bool IsConnected() const override;
-
- Error ConnectRemote(Args &args) override;
-
- Error DisconnectRemote() override;
-
- const char *GetHostname() override;
-
- const char *GetUserName(uint32_t uid) override;
-
- const char *GetGroupName(uint32_t gid) override;
-
- bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info) override;
-
- uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info,
- ProcessInstanceInfoList &process_infos) override;
-
- Error LaunchProcess(ProcessLaunchInfo &launch_info) override;
-
- lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger,
- Target *target, Error &error) override;
+ const char *GetDescription() override {
+ return GetPluginDescriptionStatic(IsHost());
+ }
- // NetBSD processes can not be launched by spawning and attaching.
- bool CanDebugProcess() override { return false; }
+ void GetStatus(Stream &strm) override;
- // Only on PlatformMacOSX:
- Error GetFileWithUUID(const FileSpec &platform_file, const UUID *uuid,
- FileSpec &local_file) override;
+ bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
- Error GetSharedModule(const ModuleSpec &module_spec, Process *process,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
- lldb::ModuleSP *old_module_sp_ptr,
- bool *did_create_ptr) override;
+ int32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override;
- bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
+ bool CanDebugProcess() override;
- void GetStatus(Stream &strm) override;
+ lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
+ Debugger &debugger, Target *target,
+ Status &error) override;
void CalculateTrapHandlerSymbolNames() override;
-protected:
- lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a
- // remote netbsd OS
+ MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,
+ lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd,
+ lldb::addr_t offset) override;
private:
DISALLOW_COPY_AND_ASSIGN(PlatformNetBSD);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/CMakeLists.txt
new file mode 100644
index 0000000..8d49e7c4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lldb_library(lldbPluginPlatformOpenBSD PLUGIN
+ PlatformOpenBSD.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbHost
+ lldbTarget
+ )
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp
new file mode 100644
index 0000000..08e021e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp
@@ -0,0 +1,225 @@
+//===-- PlatformOpenBSD.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PlatformOpenBSD.h"
+#include "lldb/Host/Config.h"
+
+// C Includes
+#include <stdio.h>
+#ifndef LLDB_DISABLE_POSIX
+#include <sys/utsname.h>
+#endif
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+
+// Define these constants from OpenBSD mman.h for use when targeting
+// remote openbsd systems even when host has different values.
+#define MAP_PRIVATE 0x0002
+#define MAP_ANON 0x1000
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::platform_openbsd;
+
+static uint32_t g_initialize_count = 0;
+
+//------------------------------------------------------------------
+
+PlatformSP PlatformOpenBSD::CreateInstance(bool force, const ArchSpec *arch) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,
+ arch ? arch->GetArchitectureName() : "<null>",
+ arch ? arch->GetTriple().getTriple() : "<null>");
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid()) {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getOS()) {
+ case llvm::Triple::OpenBSD:
+ create = true;
+ break;
+
+#if defined(__OpenBSD__)
+ // Only accept "unknown" for the OS if the host is BSD and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::OSType::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+ LLDB_LOG(log, "create = {0}", create);
+ if (create) {
+ return PlatformSP(new PlatformOpenBSD(false));
+ }
+ return PlatformSP();
+}
+
+ConstString PlatformOpenBSD::GetPluginNameStatic(bool is_host) {
+ if (is_host) {
+ static ConstString g_host_name(Platform::GetHostPlatformName());
+ return g_host_name;
+ } else {
+ static ConstString g_remote_name("remote-openbsd");
+ return g_remote_name;
+ }
+}
+
+const char *PlatformOpenBSD::GetPluginDescriptionStatic(bool is_host) {
+ if (is_host)
+ return "Local OpenBSD user platform plug-in.";
+ else
+ return "Remote OpenBSD user platform plug-in.";
+}
+
+ConstString PlatformOpenBSD::GetPluginName() {
+ return GetPluginNameStatic(IsHost());
+}
+
+void PlatformOpenBSD::Initialize() {
+ Platform::Initialize();
+
+ if (g_initialize_count++ == 0) {
+#if defined(__OpenBSD__)
+ PlatformSP default_platform_sp(new PlatformOpenBSD(true));
+ default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
+ Platform::SetHostPlatform(default_platform_sp);
+#endif
+ PluginManager::RegisterPlugin(
+ PlatformOpenBSD::GetPluginNameStatic(false),
+ PlatformOpenBSD::GetPluginDescriptionStatic(false),
+ PlatformOpenBSD::CreateInstance, nullptr);
+ }
+}
+
+void PlatformOpenBSD::Terminate() {
+ if (g_initialize_count > 0) {
+ if (--g_initialize_count == 0) {
+ PluginManager::UnregisterPlugin(PlatformOpenBSD::CreateInstance);
+ }
+ }
+
+ PlatformPOSIX::Terminate();
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformOpenBSD::PlatformOpenBSD(bool is_host)
+ : PlatformPOSIX(is_host) // This is the local host platform
+{}
+
+PlatformOpenBSD::~PlatformOpenBSD() = default;
+
+bool PlatformOpenBSD::GetSupportedArchitectureAtIndex(uint32_t idx,
+ ArchSpec &arch) {
+ if (IsHost()) {
+ ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+ if (hostArch.GetTriple().isOSOpenBSD()) {
+ if (idx == 0) {
+ arch = hostArch;
+ return arch.IsValid();
+ }
+ }
+ } else {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch);
+
+ llvm::Triple triple;
+ // Set the OS to OpenBSD
+ triple.setOS(llvm::Triple::OpenBSD);
+ // Set the architecture
+ switch (idx) {
+ case 0:
+ triple.setArchName("x86_64");
+ break;
+ case 1:
+ triple.setArchName("i386");
+ break;
+ case 2:
+ triple.setArchName("aarch64");
+ break;
+ case 3:
+ triple.setArchName("arm");
+ break;
+ default:
+ return false;
+ }
+ // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the
+ // vendor by
+ // calling triple.SetVendorName("unknown") so that it is a "unspecified
+ // unknown".
+ // This means when someone calls triple.GetVendorName() it will return an
+ // empty string
+ // which indicates that the vendor can be set when two architectures are
+ // merged
+
+ // Now set the triple into "arch" and return true
+ arch.SetTriple(triple);
+ return true;
+ }
+ return false;
+}
+
+void PlatformOpenBSD::GetStatus(Stream &strm) {
+ Platform::GetStatus(strm);
+
+#ifndef LLDB_DISABLE_POSIX
+ // Display local kernel information only when we are running in host mode.
+ // Otherwise, we would end up printing non-OpenBSD information (when running
+ // on Mac OS for example).
+ if (IsHost()) {
+ struct utsname un;
+
+ if (uname(&un))
+ return;
+
+ strm.Printf(" Kernel: %s\n", un.sysname);
+ strm.Printf(" Release: %s\n", un.release);
+ strm.Printf(" Version: %s\n", un.version);
+ }
+#endif
+}
+
+// OpenBSD processes cannot yet be launched by spawning and attaching.
+bool PlatformOpenBSD::CanDebugProcess() {
+ return false;
+}
+
+void PlatformOpenBSD::CalculateTrapHandlerSymbolNames() {
+ m_trap_handlers.push_back(ConstString("_sigtramp"));
+}
+
+uint64_t PlatformOpenBSD::ConvertMmapFlagsToPlatform(const ArchSpec &arch,
+ unsigned flags) {
+ uint64_t flags_platform = 0;
+
+ if (flags & eMmapFlagsPrivate)
+ flags_platform |= MAP_PRIVATE;
+ if (flags & eMmapFlagsAnon)
+ flags_platform |= MAP_ANON;
+
+ MmapArgList args({addr, length, prot, flags_platform, fd, offset});
+ return args;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h
new file mode 100644
index 0000000..cb5e9bf
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h
@@ -0,0 +1,68 @@
+//===-- PlatformOpenBSD.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_PlatformOpenBSD_h_
+#define liblldb_PlatformOpenBSD_h_
+
+#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
+
+namespace lldb_private {
+namespace platform_openbsd {
+
+class PlatformOpenBSD : public PlatformPOSIX {
+public:
+ PlatformOpenBSD(bool is_host);
+
+ ~PlatformOpenBSD() override;
+
+ static void Initialize();
+
+ static void Terminate();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
+
+ static ConstString GetPluginNameStatic(bool is_host);
+
+ static const char *GetPluginDescriptionStatic(bool is_host);
+
+ ConstString GetPluginName() override;
+
+ uint32_t GetPluginVersion() override { return 1; }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ const char *GetDescription() override {
+ return GetPluginDescriptionStatic(IsHost());
+ }
+
+ void GetStatus(Stream &strm) override;
+
+ bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
+
+ bool CanDebugProcess() override;
+
+ void CalculateTrapHandlerSymbolNames() override;
+
+ MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,
+ lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd,
+ lldb::addr_t offset) override;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(PlatformOpenBSD);
+};
+
+} // namespace platform_openbsd
+} // namespace lldb_private
+
+#endif // liblldb_PlatformOpenBSD_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
index e51029c..013c33d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
@@ -14,23 +14,25 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/UserExpression.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileCache.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -86,7 +88,7 @@ bool PlatformPOSIX::IsConnected() const {
return false;
}
-lldb_private::Error PlatformPOSIX::RunShellCommand(
+lldb_private::Status PlatformPOSIX::RunShellCommand(
const char *command, // Shouldn't be NULL
const FileSpec &
working_dir, // Pass empty FileSpec to use the current working directory
@@ -107,20 +109,190 @@ lldb_private::Error PlatformPOSIX::RunShellCommand(
status_ptr, signo_ptr,
command_output, timeout_sec);
else
- return Error("unable to run a remote command without a platform");
+ return Status("unable to run a remote command without a platform");
}
}
-Error PlatformPOSIX::MakeDirectory(const FileSpec &file_spec,
- uint32_t file_permissions) {
+Status
+PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr) {
+ Status error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ char exe_path[PATH_MAX];
+ ModuleSpec resolved_module_spec(module_spec);
+
+ if (IsHost()) {
+ // If we have "ls" as the exe_file, resolve the executable location based on
+ // the current path variables
+ if (!resolved_module_spec.GetFileSpec().Exists()) {
+ resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
+ resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
+ }
+
+ if (!resolved_module_spec.GetFileSpec().Exists())
+ resolved_module_spec.GetFileSpec().ResolveExecutableLocation();
+
+ // Resolve any executable within a bundle on MacOSX
+ Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ error.Clear();
+ else {
+ const uint32_t permissions =
+ resolved_module_spec.GetFileSpec().GetPermissions();
+ if (permissions && (permissions & eFilePermissionsEveryoneR) == 0)
+ error.SetErrorStringWithFormat(
+ "executable '%s' is not readable",
+ resolved_module_spec.GetFileSpec().GetPath().c_str());
+ else
+ error.SetErrorStringWithFormat(
+ "unable to find executable for '%s'",
+ resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ } else {
+ if (m_remote_platform_sp) {
+ error =
+ GetCachedExecutable(resolved_module_spec, exe_module_sp,
+ module_search_paths_ptr, *m_remote_platform_sp);
+ } else {
+ // We may connect to a process and use the provided executable (Don't use
+ // local $PATH).
+
+ // Resolve any executable within a bundle on MacOSX
+ Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
+
+ if (resolved_module_spec.GetFileSpec().Exists())
+ error.Clear();
+ else
+ error.SetErrorStringWithFormat("the platform is not currently "
+ "connected, and '%s' doesn't exist in "
+ "the system root.",
+ exe_path);
+ }
+ }
+
+ if (error.Success()) {
+ if (resolved_module_spec.GetArchitecture().IsValid()) {
+ error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
+ module_search_paths_ptr, nullptr, nullptr);
+ if (error.Fail()) {
+ // If we failed, it may be because the vendor and os aren't known. If
+ // that is the case, try setting them to the host architecture and give
+ // it another try.
+ llvm::Triple &module_triple =
+ resolved_module_spec.GetArchitecture().GetTriple();
+ bool is_vendor_specified =
+ (module_triple.getVendor() != llvm::Triple::UnknownVendor);
+ bool is_os_specified =
+ (module_triple.getOS() != llvm::Triple::UnknownOS);
+ if (!is_vendor_specified || !is_os_specified) {
+ const llvm::Triple &host_triple =
+ HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple();
+
+ if (!is_vendor_specified)
+ module_triple.setVendorName(host_triple.getVendorName());
+ if (!is_os_specified)
+ module_triple.setOSName(host_triple.getOSName());
+
+ error = ModuleList::GetSharedModule(resolved_module_spec,
+ exe_module_sp, module_search_paths_ptr, nullptr, nullptr);
+ }
+ }
+
+ // TODO find out why exe_module_sp might be NULL
+ if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) {
+ exe_module_sp.reset();
+ error.SetErrorStringWithFormat(
+ "'%s' doesn't contain the architecture %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+ } else {
+ // No valid architecture was specified, ask the platform for
+ // the architectures that we should be using (in the correct order)
+ // and see if we can find a match that way
+ StreamString arch_names;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
+ idx, resolved_module_spec.GetArchitecture());
+ ++idx) {
+ error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
+ module_search_paths_ptr, nullptr, nullptr);
+ // Did we find an executable using one of the
+ if (error.Success()) {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString(", ");
+ arch_names.PutCString(
+ resolved_module_spec.GetArchitecture().GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp) {
+ if (resolved_module_spec.GetFileSpec().Readable()) {
+ error.SetErrorStringWithFormat(
+ "'%s' doesn't contain any '%s' platform architectures: %s",
+ resolved_module_spec.GetFileSpec().GetPath().c_str(),
+ GetPluginName().GetCString(), arch_names.GetData());
+ } else {
+ error.SetErrorStringWithFormat(
+ "'%s' is not readable",
+ resolved_module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
+Status PlatformPOSIX::GetFileWithUUID(const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file) {
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
+ local_file);
+
+ // Default to the local case
+ local_file = platform_file;
+ return Status();
+}
+
+bool PlatformPOSIX::GetProcessInfo(lldb::pid_t pid,
+ ProcessInstanceInfo &process_info) {
+ if (IsHost())
+ return Platform::GetProcessInfo(pid, process_info);
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetProcessInfo(pid, process_info);
+ return false;
+}
+
+uint32_t
+PlatformPOSIX::FindProcesses(const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos) {
+ if (IsHost())
+ return Platform::FindProcesses(match_info, process_infos);
+ if (m_remote_platform_sp)
+ return
+ m_remote_platform_sp->FindProcesses(match_info, process_infos);
+ return 0;
+}
+
+Status PlatformPOSIX::MakeDirectory(const FileSpec &file_spec,
+ uint32_t file_permissions) {
if (m_remote_platform_sp)
return m_remote_platform_sp->MakeDirectory(file_spec, file_permissions);
else
return Platform::MakeDirectory(file_spec, file_permissions);
}
-Error PlatformPOSIX::GetFilePermissions(const FileSpec &file_spec,
- uint32_t &file_permissions) {
+Status PlatformPOSIX::GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions) {
if (m_remote_platform_sp)
return m_remote_platform_sp->GetFilePermissions(file_spec,
file_permissions);
@@ -128,8 +300,8 @@ Error PlatformPOSIX::GetFilePermissions(const FileSpec &file_spec,
return Platform::GetFilePermissions(file_spec, file_permissions);
}
-Error PlatformPOSIX::SetFilePermissions(const FileSpec &file_spec,
- uint32_t file_permissions) {
+Status PlatformPOSIX::SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions) {
if (m_remote_platform_sp)
return m_remote_platform_sp->SetFilePermissions(file_spec,
file_permissions);
@@ -139,7 +311,7 @@ Error PlatformPOSIX::SetFilePermissions(const FileSpec &file_spec,
lldb::user_id_t PlatformPOSIX::OpenFile(const FileSpec &file_spec,
uint32_t flags, uint32_t mode,
- Error &error) {
+ Status &error) {
if (IsHost())
return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error);
else if (m_remote_platform_sp)
@@ -148,7 +320,7 @@ lldb::user_id_t PlatformPOSIX::OpenFile(const FileSpec &file_spec,
return Platform::OpenFile(file_spec, flags, mode, error);
}
-bool PlatformPOSIX::CloseFile(lldb::user_id_t fd, Error &error) {
+bool PlatformPOSIX::CloseFile(lldb::user_id_t fd, Status &error) {
if (IsHost())
return FileCache::GetInstance().CloseFile(fd, error);
else if (m_remote_platform_sp)
@@ -158,7 +330,7 @@ bool PlatformPOSIX::CloseFile(lldb::user_id_t fd, Error &error) {
}
uint64_t PlatformPOSIX::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
- uint64_t dst_len, Error &error) {
+ uint64_t dst_len, Status &error) {
if (IsHost())
return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error);
else if (m_remote_platform_sp)
@@ -169,7 +341,7 @@ uint64_t PlatformPOSIX::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
uint64_t PlatformPOSIX::WriteFile(lldb::user_id_t fd, uint64_t offset,
const void *src, uint64_t src_len,
- Error &error) {
+ Status &error) {
if (IsHost())
return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error);
else if (m_remote_platform_sp)
@@ -199,7 +371,7 @@ static uint32_t chown_file(Platform *platform, const char *path,
return status;
}
-lldb_private::Error
+lldb_private::Status
PlatformPOSIX::PutFile(const lldb_private::FileSpec &source,
const lldb_private::FileSpec &destination, uint32_t uid,
uint32_t gid) {
@@ -207,34 +379,34 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source,
if (IsHost()) {
if (FileSpec::Equal(source, destination, true))
- return Error();
+ return Status();
// cp src dst
// chown uid:gid dst
std::string src_path(source.GetPath());
if (src_path.empty())
- return Error("unable to get file path for source");
+ return Status("unable to get file path for source");
std::string dst_path(destination.GetPath());
if (dst_path.empty())
- return Error("unable to get file path for destination");
+ return Status("unable to get file path for destination");
StreamString command;
command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
int status;
RunShellCommand(command.GetData(), NULL, &status, NULL, NULL, 10);
if (status != 0)
- return Error("unable to perform copy");
+ return Status("unable to perform copy");
if (uid == UINT32_MAX && gid == UINT32_MAX)
- return Error();
+ return Status();
if (chown_file(this, dst_path.c_str(), uid, gid) != 0)
- return Error("unable to perform chown");
- return Error();
+ return Status("unable to perform chown");
+ return Status();
} else if (m_remote_platform_sp) {
if (GetSupportsRSync()) {
std::string src_path(source.GetPath());
if (src_path.empty())
- return Error("unable to get file path for source");
+ return Status("unable to get file path for source");
std::string dst_path(destination.GetPath());
if (dst_path.empty())
- return Error("unable to get file path for destination");
+ return Status("unable to get file path for destination");
StreamString command;
if (GetIgnoresRemoteHostname()) {
if (!GetRSyncPrefix())
@@ -253,8 +425,8 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source,
if (retcode == 0) {
// Don't chown a local file for a remote system
// if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
- // return Error("unable to perform chown");
- return Error();
+ // return Status("unable to perform chown");
+ return Status();
}
// if we are still here rsync has failed - let's try the slow way before
// giving up
@@ -264,15 +436,18 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source,
}
lldb::user_id_t PlatformPOSIX::GetFileSize(const FileSpec &file_spec) {
- if (IsHost())
- return FileSystem::GetFileSize(file_spec);
- else if (m_remote_platform_sp)
+ if (IsHost()) {
+ uint64_t Size;
+ if (llvm::sys::fs::file_size(file_spec.GetPath(), Size))
+ return 0;
+ return Size;
+ } else if (m_remote_platform_sp)
return m_remote_platform_sp->GetFileSize(file_spec);
else
return Platform::GetFileSize(file_spec);
}
-Error PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst) {
+Status PlatformPOSIX::CreateSymlink(const FileSpec &src, const FileSpec &dst) {
if (IsHost())
return FileSystem::Symlink(src, dst);
else if (m_remote_platform_sp)
@@ -290,16 +465,16 @@ bool PlatformPOSIX::GetFileExists(const FileSpec &file_spec) {
return Platform::GetFileExists(file_spec);
}
-Error PlatformPOSIX::Unlink(const FileSpec &file_spec) {
+Status PlatformPOSIX::Unlink(const FileSpec &file_spec) {
if (IsHost())
- return FileSystem::Unlink(file_spec);
+ return llvm::sys::fs::remove(file_spec.GetPath());
else if (m_remote_platform_sp)
return m_remote_platform_sp->Unlink(file_spec);
else
return Platform::Unlink(file_spec);
}
-lldb_private::Error PlatformPOSIX::GetFile(
+lldb_private::Status PlatformPOSIX::GetFile(
const lldb_private::FileSpec &source, // remote file path
const lldb_private::FileSpec &destination) // local file path
{
@@ -308,22 +483,22 @@ lldb_private::Error PlatformPOSIX::GetFile(
// Check the args, first.
std::string src_path(source.GetPath());
if (src_path.empty())
- return Error("unable to get file path for source");
+ return Status("unable to get file path for source");
std::string dst_path(destination.GetPath());
if (dst_path.empty())
- return Error("unable to get file path for destination");
+ return Status("unable to get file path for destination");
if (IsHost()) {
if (FileSpec::Equal(source, destination, true))
- return Error("local scenario->source and destination are the same file "
- "path: no operation performed");
+ return Status("local scenario->source and destination are the same file "
+ "path: no operation performed");
// cp src dst
StreamString cp_command;
cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
int status;
RunShellCommand(cp_command.GetData(), NULL, &status, NULL, NULL, 10);
if (status != 0)
- return Error("unable to perform copy");
- return Error();
+ return Status("unable to perform copy");
+ return Status();
} else if (m_remote_platform_sp) {
if (GetSupportsRSync()) {
StreamString command;
@@ -343,7 +518,7 @@ lldb_private::Error PlatformPOSIX::GetFile(
int retcode;
Host::RunShellCommand(command.GetData(), NULL, &retcode, NULL, NULL, 60);
if (retcode == 0)
- return Error();
+ return Status();
// If we are here, rsync has failed - let's try the slow way before giving
// up
}
@@ -353,12 +528,12 @@ lldb_private::Error PlatformPOSIX::GetFile(
// close dst
if (log)
log->Printf("[GetFile] Using block by block transfer....\n");
- Error error;
+ Status error;
user_id_t fd_src = OpenFile(source, File::eOpenOptionRead,
lldb::eFilePermissionsFileDefault, error);
if (fd_src == UINT64_MAX)
- return Error("unable to open source file");
+ return Status("unable to open source file");
uint32_t permissions = 0;
error = GetFilePermissions(source, permissions);
@@ -536,8 +711,8 @@ const char *PlatformPOSIX::GetGroupName(uint32_t gid) {
return NULL;
}
-Error PlatformPOSIX::ConnectRemote(Args &args) {
- Error error;
+Status PlatformPOSIX::ConnectRemote(Args &args) {
+ Status error;
if (IsHost()) {
error.SetErrorStringWithFormat(
"can't connect to the host platform '%s', always connected",
@@ -579,8 +754,8 @@ Error PlatformPOSIX::ConnectRemote(Args &args) {
return error;
}
-Error PlatformPOSIX::DisconnectRemote() {
- Error error;
+Status PlatformPOSIX::DisconnectRemote() {
+ Status error;
if (IsHost()) {
error.SetErrorStringWithFormat(
@@ -595,8 +770,8 @@ Error PlatformPOSIX::DisconnectRemote() {
return error;
}
-Error PlatformPOSIX::LaunchProcess(ProcessLaunchInfo &launch_info) {
- Error error;
+Status PlatformPOSIX::LaunchProcess(ProcessLaunchInfo &launch_info) {
+ Status error;
if (IsHost()) {
error = Platform::LaunchProcess(launch_info);
@@ -609,19 +784,19 @@ Error PlatformPOSIX::LaunchProcess(ProcessLaunchInfo &launch_info) {
return error;
}
-lldb_private::Error PlatformPOSIX::KillProcess(const lldb::pid_t pid) {
+lldb_private::Status PlatformPOSIX::KillProcess(const lldb::pid_t pid) {
if (IsHost())
return Platform::KillProcess(pid);
if (m_remote_platform_sp)
return m_remote_platform_sp->KillProcess(pid);
- return Error("the platform is not currently connected");
+ return Status("the platform is not currently connected");
}
lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info,
Debugger &debugger, Target *target,
- Error &error) {
+ Status &error) {
lldb::ProcessSP process_sp;
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
@@ -681,7 +856,7 @@ lldb::ProcessSP
PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new
// target, else use existing one
- Error &error) {
+ Status &error) {
ProcessSP process_sp;
if (IsHost()) {
@@ -707,23 +882,23 @@ void PlatformPOSIX::CalculateTrapHandlerSymbolNames() {
m_trap_handlers.push_back(ConstString("_sigtramp"));
}
-Error PlatformPOSIX::EvaluateLibdlExpression(
+Status PlatformPOSIX::EvaluateLibdlExpression(
lldb_private::Process *process, const char *expr_cstr,
- const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp) {
+ llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp) {
DynamicLoader *loader = process->GetDynamicLoader();
if (loader) {
- Error error = loader->CanLoadImage();
+ Status error = loader->CanLoadImage();
if (error.Fail())
return error;
}
ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread());
if (!thread_sp)
- return Error("Selected thread isn't valid");
+ return Status("Selected thread isn't valid");
StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0));
if (!frame_sp)
- return Error("Frame 0 isn't valid");
+ return Status("Frame 0 isn't valid");
ExecutionContext exe_ctx;
frame_sp->CalculateExecutionContext(exe_ctx);
@@ -736,7 +911,7 @@ Error PlatformPOSIX::EvaluateLibdlExpression(
// don't do the work to trap them.
expr_options.SetTimeout(std::chrono::seconds(2));
- Error expr_error;
+ Status expr_error;
ExpressionResults result =
UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix,
result_valobj_sp, expr_error);
@@ -745,12 +920,12 @@ Error PlatformPOSIX::EvaluateLibdlExpression(
if (result_valobj_sp->GetError().Fail())
return result_valobj_sp->GetError();
- return Error();
+ return Status();
}
uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
const lldb_private::FileSpec &remote_file,
- lldb_private::Error &error) {
+ lldb_private::Status &error) {
char path[PATH_MAX];
remote_file.GetPath(path, sizeof(path));
@@ -769,7 +944,7 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
the_result;
)",
path);
- const char *prefix = GetLibdlFunctionDeclarations();
+ llvm::StringRef prefix = GetLibdlFunctionDeclarations();
lldb::ValueObjectSP result_valobj_sp;
error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
result_valobj_sp);
@@ -809,18 +984,18 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
return LLDB_INVALID_IMAGE_TOKEN;
}
-Error PlatformPOSIX::UnloadImage(lldb_private::Process *process,
- uint32_t image_token) {
+Status PlatformPOSIX::UnloadImage(lldb_private::Process *process,
+ uint32_t image_token) {
const addr_t image_addr = process->GetImagePtrFromToken(image_token);
if (image_addr == LLDB_INVALID_ADDRESS)
- return Error("Invalid image token");
+ return Status("Invalid image token");
StreamString expr;
expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr);
- const char *prefix = GetLibdlFunctionDeclarations();
+ llvm::StringRef prefix = GetLibdlFunctionDeclarations();
lldb::ValueObjectSP result_valobj_sp;
- Error error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
- result_valobj_sp);
+ Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
+ result_valobj_sp);
if (error.Fail())
return error;
@@ -830,17 +1005,17 @@ Error PlatformPOSIX::UnloadImage(lldb_private::Process *process,
Scalar scalar;
if (result_valobj_sp->ResolveValue(scalar)) {
if (scalar.UInt(1))
- return Error("expression failed: \"%s\"", expr.GetData());
+ return Status("expression failed: \"%s\"", expr.GetData());
process->ResetImageToken(image_token);
}
- return Error();
+ return Status();
}
lldb::ProcessSP PlatformPOSIX::ConnectProcess(llvm::StringRef connect_url,
llvm::StringRef plugin_name,
lldb_private::Debugger &debugger,
lldb_private::Target *target,
- lldb_private::Error &error) {
+ lldb_private::Status &error) {
if (m_remote_platform_sp)
return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name,
debugger, target, error);
@@ -849,7 +1024,7 @@ lldb::ProcessSP PlatformPOSIX::ConnectProcess(llvm::StringRef connect_url,
error);
}
-const char *PlatformPOSIX::GetLibdlFunctionDeclarations() const {
+llvm::StringRef PlatformPOSIX::GetLibdlFunctionDeclarations() {
return R"(
extern "C" void* dlopen(const char*, int);
extern "C" void* dlsym(void*, const char*);
@@ -859,8 +1034,17 @@ const char *PlatformPOSIX::GetLibdlFunctionDeclarations() const {
}
size_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger,
- Error &error) {
+ Status &error) {
if (m_remote_platform_sp)
return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error);
return Platform::ConnectToWaitingProcesses(debugger, error);
}
+
+ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) {
+ if (basename.IsEmpty())
+ return basename;
+
+ StreamString stream;
+ stream.Printf("lib%s.so", basename.GetCString());
+ return ConstString(stream.GetString());
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
index 93213b2..ebc36c2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
@@ -43,29 +43,30 @@ public:
const char *GetGroupName(uint32_t gid) override;
- lldb_private::Error PutFile(const lldb_private::FileSpec &source,
- const lldb_private::FileSpec &destination,
- uint32_t uid = UINT32_MAX,
- uint32_t gid = UINT32_MAX) override;
+ lldb_private::Status PutFile(const lldb_private::FileSpec &source,
+ const lldb_private::FileSpec &destination,
+ uint32_t uid = UINT32_MAX,
+ uint32_t gid = UINT32_MAX) override;
lldb::user_id_t OpenFile(const lldb_private::FileSpec &file_spec,
uint32_t flags, uint32_t mode,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
- bool CloseFile(lldb::user_id_t fd, lldb_private::Error &error) override;
+ bool CloseFile(lldb::user_id_t fd, lldb_private::Status &error) override;
uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
- uint64_t dst_len, lldb_private::Error &error) override;
+ uint64_t dst_len, lldb_private::Status &error) override;
uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src,
- uint64_t src_len, lldb_private::Error &error) override;
+ uint64_t src_len, lldb_private::Status &error) override;
lldb::user_id_t GetFileSize(const lldb_private::FileSpec &file_spec) override;
- lldb_private::Error CreateSymlink(const lldb_private::FileSpec &src,
- const lldb_private::FileSpec &dst) override;
+ lldb_private::Status
+ CreateSymlink(const lldb_private::FileSpec &src,
+ const lldb_private::FileSpec &dst) override;
- lldb_private::Error
+ lldb_private::Status
GetFile(const lldb_private::FileSpec &source,
const lldb_private::FileSpec &destination) override;
@@ -88,7 +89,7 @@ public:
bool IsConnected() const override;
- lldb_private::Error RunShellCommand(
+ lldb_private::Status RunShellCommand(
const char *command, // Shouldn't be nullptr
const lldb_private::FileSpec &working_dir, // Pass empty FileSpec to use
// the current working
@@ -101,25 +102,39 @@ public:
uint32_t timeout_sec)
override; // Timeout in seconds to wait for shell program to finish
- lldb_private::Error MakeDirectory(const lldb_private::FileSpec &file_spec,
- uint32_t mode) override;
+ lldb_private::Status ResolveExecutable(
+ const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr) override;
- lldb_private::Error
+ lldb_private::Status
+ GetFileWithUUID(const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid,
+ lldb_private::FileSpec &local_file) override;
+
+ bool GetProcessInfo(lldb::pid_t pid, lldb_private::ProcessInstanceInfo &proc_info) override;
+
+ uint32_t FindProcesses(const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos) override;
+
+ lldb_private::Status MakeDirectory(const lldb_private::FileSpec &file_spec,
+ uint32_t mode) override;
+
+ lldb_private::Status
GetFilePermissions(const lldb_private::FileSpec &file_spec,
uint32_t &file_permissions) override;
- lldb_private::Error
+ lldb_private::Status
SetFilePermissions(const lldb_private::FileSpec &file_spec,
uint32_t file_permissions) override;
bool GetFileExists(const lldb_private::FileSpec &file_spec) override;
- lldb_private::Error Unlink(const lldb_private::FileSpec &file_spec) override;
+ lldb_private::Status Unlink(const lldb_private::FileSpec &file_spec) override;
- lldb_private::Error
+ lldb_private::Status
LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) override;
- lldb_private::Error KillProcess(const lldb::pid_t pid) override;
+ lldb_private::Status KillProcess(const lldb::pid_t pid) override;
lldb::ProcessSP Attach(lldb_private::ProcessAttachInfo &attach_info,
lldb_private::Debugger &debugger,
@@ -127,7 +142,7 @@ public:
// nullptr create a new
// target, else use
// existing one
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
lldb::ProcessSP DebugProcess(lldb_private::ProcessLaunchInfo &launch_info,
lldb_private::Debugger &debugger,
@@ -136,7 +151,7 @@ public:
// create a new
// target, else use
// existing one
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
std::string GetPlatformSpecificConnectionInformation() override;
@@ -145,25 +160,27 @@ public:
void CalculateTrapHandlerSymbolNames() override;
- lldb_private::Error ConnectRemote(lldb_private::Args &args) override;
+ lldb_private::Status ConnectRemote(lldb_private::Args &args) override;
- lldb_private::Error DisconnectRemote() override;
+ lldb_private::Status DisconnectRemote() override;
uint32_t DoLoadImage(lldb_private::Process *process,
const lldb_private::FileSpec &remote_file,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
- lldb_private::Error UnloadImage(lldb_private::Process *process,
- uint32_t image_token) override;
+ lldb_private::Status UnloadImage(lldb_private::Process *process,
+ uint32_t image_token) override;
lldb::ProcessSP ConnectProcess(llvm::StringRef connect_url,
llvm::StringRef plugin_name,
lldb_private::Debugger &debugger,
lldb_private::Target *target,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
+
+ lldb_private::ConstString GetFullNameForDylib(lldb_private::ConstString basename) override;
protected:
std::unique_ptr<lldb_private::OptionGroupPlatformRSync>
@@ -179,12 +196,12 @@ protected:
lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a
// remote POSIX-compliant OS
- lldb_private::Error
+ lldb_private::Status
EvaluateLibdlExpression(lldb_private::Process *process, const char *expr_cstr,
- const char *expr_prefix,
+ llvm::StringRef expr_prefix,
lldb::ValueObjectSP &result_valobj_sp);
- virtual const char *GetLibdlFunctionDeclarations() const;
+ virtual llvm::StringRef GetLibdlFunctionDeclarations();
private:
DISALLOW_COPY_AND_ASSIGN(PlatformPOSIX);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
index 43f7a53..759ec7f 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -15,23 +15,22 @@
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/PosixApi.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
-
-#include "Utility/UriParser.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UriParser.h"
#include "Plugins/Process/Utility/GDBRemoteSignals.h"
@@ -95,12 +94,12 @@ const char *PlatformRemoteGDBServer::GetDescription() {
return GetDescriptionStatic();
}
-Error PlatformRemoteGDBServer::ResolveExecutable(
+Status PlatformRemoteGDBServer::ResolveExecutable(
const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp,
const FileSpecList *module_search_paths_ptr) {
// copied from PlatformRemoteiOS
- Error error;
+ Status error;
// Nothing special to do here, just use the actual file and architecture
ModuleSpec resolved_module_spec(module_spec);
@@ -191,12 +190,12 @@ bool PlatformRemoteGDBServer::GetModuleSpec(const FileSpec &module_file_spec,
return true;
}
-Error PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file,
- const UUID *uuid_ptr,
- FileSpec &local_file) {
+Status PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file) {
// Default to the local case
local_file = platform_file;
- return Error();
+ return Status();
}
//------------------------------------------------------------------
@@ -293,8 +292,8 @@ bool PlatformRemoteGDBServer::IsConnected() const {
return m_gdb_client.IsConnected();
}
-Error PlatformRemoteGDBServer::ConnectRemote(Args &args) {
- Error error;
+Status PlatformRemoteGDBServer::ConnectRemote(Args &args) {
+ Status error;
if (IsConnected()) {
error.SetErrorStringWithFormat("the platform is already connected to '%s', "
"execute 'platform disconnect' to close the "
@@ -308,10 +307,10 @@ Error PlatformRemoteGDBServer::ConnectRemote(Args &args) {
std::string path;
const char *url = args.GetArgumentAtIndex(0);
if (!url)
- return Error("URL is null.");
+ return Status("URL is null.");
llvm::StringRef scheme, hostname, pathname;
if (!UriParser::Parse(url, scheme, hostname, port, pathname))
- return Error("Invalid URL: %s", url);
+ return Status("Invalid URL: %s", url);
m_platform_scheme = scheme;
m_platform_hostname = hostname;
path = pathname;
@@ -338,8 +337,8 @@ Error PlatformRemoteGDBServer::ConnectRemote(Args &args) {
return error;
}
-Error PlatformRemoteGDBServer::DisconnectRemote() {
- Error error;
+Status PlatformRemoteGDBServer::DisconnectRemote() {
+ Status error;
m_gdb_client.Disconnect(&error);
m_remote_signals_sp.reset();
return error;
@@ -388,9 +387,9 @@ bool PlatformRemoteGDBServer::GetProcessInfo(
return m_gdb_client.GetProcessInfo(pid, process_info);
}
-Error PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) {
+Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
- Error error;
+ Status error;
if (log)
log->Printf("PlatformRemoteGDBServer::%s() called", __FUNCTION__);
@@ -482,17 +481,17 @@ Error PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) {
return error;
}
-Error PlatformRemoteGDBServer::KillProcess(const lldb::pid_t pid) {
+Status PlatformRemoteGDBServer::KillProcess(const lldb::pid_t pid) {
if (!KillSpawnedProcess(pid))
- return Error("failed to kill remote spawned process");
- return Error();
+ return Status("failed to kill remote spawned process");
+ return Status();
}
lldb::ProcessSP PlatformRemoteGDBServer::DebugProcess(
ProcessLaunchInfo &launch_info, Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new target, else use
// existing one
- Error &error) {
+ Status &error) {
lldb::ProcessSP process_sp;
if (IsRemote()) {
if (IsConnected()) {
@@ -579,7 +578,7 @@ lldb::ProcessSP PlatformRemoteGDBServer::Attach(
ProcessAttachInfo &attach_info, Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new target, else use
// existing one
- Error &error) {
+ Status &error) {
lldb::ProcessSP process_sp;
if (IsRemote()) {
if (IsConnected()) {
@@ -627,9 +626,9 @@ lldb::ProcessSP PlatformRemoteGDBServer::Attach(
return process_sp;
}
-Error PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec,
- uint32_t mode) {
- Error error = m_gdb_client.MakeDirectory(file_spec, mode);
+Status PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec,
+ uint32_t mode) {
+ Status error = m_gdb_client.MakeDirectory(file_spec, mode);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
log->Printf("PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) "
@@ -639,9 +638,9 @@ Error PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec,
return error;
}
-Error PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec,
- uint32_t &file_permissions) {
- Error error = m_gdb_client.GetFilePermissions(file_spec, file_permissions);
+Status PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions) {
+ Status error = m_gdb_client.GetFilePermissions(file_spec, file_permissions);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
log->Printf("PlatformRemoteGDBServer::GetFilePermissions(path='%s', "
@@ -651,9 +650,9 @@ Error PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec,
return error;
}
-Error PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
- uint32_t file_permissions) {
- Error error = m_gdb_client.SetFilePermissions(file_spec, file_permissions);
+Status PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions) {
+ Status error = m_gdb_client.SetFilePermissions(file_spec, file_permissions);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
log->Printf("PlatformRemoteGDBServer::SetFilePermissions(path='%s', "
@@ -665,11 +664,11 @@ Error PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
lldb::user_id_t PlatformRemoteGDBServer::OpenFile(const FileSpec &file_spec,
uint32_t flags, uint32_t mode,
- Error &error) {
+ Status &error) {
return m_gdb_client.OpenFile(file_spec, flags, mode, error);
}
-bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Error &error) {
+bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Status &error) {
return m_gdb_client.CloseFile(fd, error);
}
@@ -680,27 +679,27 @@ PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) {
uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset,
void *dst, uint64_t dst_len,
- Error &error) {
+ Status &error) {
return m_gdb_client.ReadFile(fd, offset, dst, dst_len, error);
}
uint64_t PlatformRemoteGDBServer::WriteFile(lldb::user_id_t fd, uint64_t offset,
const void *src, uint64_t src_len,
- Error &error) {
+ Status &error) {
return m_gdb_client.WriteFile(fd, offset, src, src_len, error);
}
-Error PlatformRemoteGDBServer::PutFile(const FileSpec &source,
- const FileSpec &destination,
- uint32_t uid, uint32_t gid) {
+Status PlatformRemoteGDBServer::PutFile(const FileSpec &source,
+ const FileSpec &destination,
+ uint32_t uid, uint32_t gid) {
return Platform::PutFile(source, destination, uid, gid);
}
-Error PlatformRemoteGDBServer::CreateSymlink(
+Status PlatformRemoteGDBServer::CreateSymlink(
const FileSpec &src, // The name of the link is in src
const FileSpec &dst) // The symlink points to dst
{
- Error error = m_gdb_client.CreateSymlink(src, dst);
+ Status error = m_gdb_client.CreateSymlink(src, dst);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
log->Printf("PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') "
@@ -710,8 +709,8 @@ Error PlatformRemoteGDBServer::CreateSymlink(
return error;
}
-Error PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) {
- Error error = m_gdb_client.Unlink(file_spec);
+Status PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) {
+ Status error = m_gdb_client.Unlink(file_spec);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
log->Printf("PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)",
@@ -723,7 +722,7 @@ bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) {
return m_gdb_client.GetFileExists(file_spec);
}
-Error PlatformRemoteGDBServer::RunShellCommand(
+Status PlatformRemoteGDBServer::RunShellCommand(
const char *command, // Shouldn't be NULL
const FileSpec &
working_dir, // Pass empty FileSpec to use the current working directory
@@ -786,7 +785,7 @@ const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() {
if (!dict->GetValueForKeyAsInteger("signo", signo))
return false;
- std::string name;
+ llvm::StringRef name;
if (!dict->GetValueForKeyAsString("name", name))
return false;
@@ -811,7 +810,7 @@ const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() {
if (object_sp && object_sp->IsValid())
description = object_sp->GetStringValue();
- remote_signals_sp->AddSignal(signo, name.c_str(), suppress, stop,
+ remote_signals_sp->AddSignal(signo, name.str().c_str(), suppress, stop,
notify, description.c_str());
return true;
});
@@ -854,7 +853,7 @@ std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme,
lldb::ProcessSP PlatformRemoteGDBServer::ConnectProcess(
llvm::StringRef connect_url, llvm::StringRef plugin_name,
lldb_private::Debugger &debugger, lldb_private::Target *target,
- lldb_private::Error &error) {
+ lldb_private::Status &error) {
if (!IsRemote() || !IsConnected()) {
error.SetErrorString("Not connected to remote gdb server");
return nullptr;
@@ -864,7 +863,7 @@ lldb::ProcessSP PlatformRemoteGDBServer::ConnectProcess(
}
size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger,
- Error &error) {
+ Status &error) {
std::vector<std::string> connection_urls;
GetPendingGdbServerList(connection_urls);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
index edc223a..210544f 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
@@ -50,38 +50,38 @@ public:
//------------------------------------------------------------
// lldb_private::Platform functions
//------------------------------------------------------------
- Error ResolveExecutable(const ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr) override;
+ Status
+ ResolveExecutable(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr) override;
bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch,
ModuleSpec &module_spec) override;
const char *GetDescription() override;
- Error GetFileWithUUID(const FileSpec &platform_file, const UUID *uuid_ptr,
- FileSpec &local_file) override;
+ Status GetFileWithUUID(const FileSpec &platform_file, const UUID *uuid_ptr,
+ FileSpec &local_file) override;
bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info) override;
uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &process_infos) override;
- Error LaunchProcess(ProcessLaunchInfo &launch_info) override;
+ Status LaunchProcess(ProcessLaunchInfo &launch_info) override;
- Error KillProcess(const lldb::pid_t pid) override;
+ Status KillProcess(const lldb::pid_t pid) override;
lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
Debugger &debugger,
Target *target, // Can be NULL, if NULL create a
// new target, else use existing
// one
- Error &error) override;
+ Status &error) override;
lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new
// target, else use existing one
- Error &error) override;
+ Status &error) override;
bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
@@ -111,42 +111,42 @@ public:
bool IsConnected() const override;
- Error ConnectRemote(Args &args) override;
+ Status ConnectRemote(Args &args) override;
- Error DisconnectRemote() override;
+ Status DisconnectRemote() override;
- Error MakeDirectory(const FileSpec &file_spec,
- uint32_t file_permissions) override;
+ Status MakeDirectory(const FileSpec &file_spec,
+ uint32_t file_permissions) override;
- Error GetFilePermissions(const FileSpec &file_spec,
- uint32_t &file_permissions) override;
+ Status GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions) override;
- Error SetFilePermissions(const FileSpec &file_spec,
- uint32_t file_permissions) override;
+ Status SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions) override;
lldb::user_id_t OpenFile(const FileSpec &file_spec, uint32_t flags,
- uint32_t mode, Error &error) override;
+ uint32_t mode, Status &error) override;
- bool CloseFile(lldb::user_id_t fd, Error &error) override;
+ bool CloseFile(lldb::user_id_t fd, Status &error) override;
uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *data_ptr,
- uint64_t len, Error &error) override;
+ uint64_t len, Status &error) override;
uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, const void *data,
- uint64_t len, Error &error) override;
+ uint64_t len, Status &error) override;
lldb::user_id_t GetFileSize(const FileSpec &file_spec) override;
- Error PutFile(const FileSpec &source, const FileSpec &destination,
- uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX) override;
+ Status PutFile(const FileSpec &source, const FileSpec &destination,
+ uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX) override;
- Error CreateSymlink(const FileSpec &src, const FileSpec &dst) override;
+ Status CreateSymlink(const FileSpec &src, const FileSpec &dst) override;
bool GetFileExists(const FileSpec &file_spec) override;
- Error Unlink(const FileSpec &path) override;
+ Status Unlink(const FileSpec &path) override;
- Error RunShellCommand(
+ Status RunShellCommand(
const char *command, // Shouldn't be NULL
const FileSpec &working_dir, // Pass empty FileSpec to use the current
// working directory
@@ -166,10 +166,10 @@ public:
llvm::StringRef plugin_name,
lldb_private::Debugger &debugger,
lldb_private::Target *target,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
virtual size_t
GetPendingGdbServerList(std::vector<std::string> &connection_urls);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp
index 63b1ae6..c6daf6c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp
@@ -30,11 +30,12 @@
// LLDB includes
#include "lldb/lldb-enumerations.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Target/ProcessLaunchInfo.h"
-#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+#include "llvm/Support/Errno.h"
#include "CFBundle.h"
#include "CFString.h"
@@ -131,10 +132,10 @@ static bool ResolveExecutablePath(const char *path, char *resolved_path,
// TODO check if we have a general purpose fork and exec. We may be
// able to get rid of this entirely.
-static Error ForkChildForPTraceDebugging(const char *path, char const *argv[],
- char const *envp[], ::pid_t *pid,
- int *pty_fd) {
- Error error;
+static Status ForkChildForPTraceDebugging(const char *path, char const *argv[],
+ char const *envp[], ::pid_t *pid,
+ int *pty_fd) {
+ Status error;
if (!path || !argv || !envp || !pid || !pty_fd) {
error.SetErrorString("invalid arguments");
return error;
@@ -149,7 +150,7 @@ static Error ForkChildForPTraceDebugging(const char *path, char const *argv[],
*pid = static_cast<::pid_t>(pty.Fork(fork_error, sizeof(fork_error)));
if (*pid < 0) {
//--------------------------------------------------------------
- // Error during fork.
+ // Status during fork.
//--------------------------------------------------------------
*pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID);
error.SetErrorStringWithFormat("%s(): fork failed: %s", __FUNCTION__,
@@ -205,10 +206,10 @@ static Error ForkChildForPTraceDebugging(const char *path, char const *argv[],
return error;
}
-static Error
+static Status
CreatePosixSpawnFileAction(const FileAction &action,
posix_spawn_file_actions_t *file_actions) {
- Error error;
+ Status error;
// Log it.
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
@@ -270,11 +271,11 @@ CreatePosixSpawnFileAction(const FileAction &action,
return error;
}
-static Error PosixSpawnChildForPTraceDebugging(const char *path,
- ProcessLaunchInfo &launch_info,
- ::pid_t *pid,
- cpu_type_t *actual_cpu_type) {
- Error error;
+static Status PosixSpawnChildForPTraceDebugging(const char *path,
+ ProcessLaunchInfo &launch_info,
+ ::pid_t *pid,
+ cpu_type_t *actual_cpu_type) {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (!pid) {
@@ -319,13 +320,12 @@ static Error PosixSpawnChildForPTraceDebugging(const char *path,
::posix_spawnattr_setsigdefault(&attr, &all_signals);
if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) {
- if (log)
- log->Printf("::posix_spawnattr_setflags(&attr, "
- "POSIX_SPAWN_START_SUSPENDED%s) failed: %s",
- flags & _POSIX_SPAWN_DISABLE_ASLR
- ? " | _POSIX_SPAWN_DISABLE_ASLR"
- : "",
- strerror(error_code));
+ LLDB_LOG(log,
+ "::posix_spawnattr_setflags(&attr, "
+ "POSIX_SPAWN_START_SUSPENDED{0}) failed: {1}",
+ flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR"
+ : "",
+ llvm::sys::StrError(error_code));
error.SetError(error_code, eErrorTypePOSIX);
return error;
}
@@ -341,10 +341,10 @@ static Error PosixSpawnChildForPTraceDebugging(const char *path,
error_code =
::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount);
if (error_code != 0) {
- if (log)
- log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, "
- "cpu_type = 0x%8.8x, count => %llu): %s",
- desired_cpu_type, (uint64_t)ocount, strerror(error_code));
+ LLDB_LOG(log,
+ "::posix_spawnattr_setbinpref_np(&attr, 1, "
+ "cpu_type = {0:x8}, count => {1}): {2}",
+ desired_cpu_type, ocount, llvm::sys::StrError(error_code));
error.SetError(error_code, eErrorTypePOSIX);
return error;
}
@@ -361,10 +361,8 @@ static Error PosixSpawnChildForPTraceDebugging(const char *path,
posix_spawn_file_actions_t file_actions;
if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) {
- if (log)
- log->Printf("::posix_spawn_file_actions_init(&file_actions) "
- "failed: %s",
- strerror(error_code));
+ LLDB_LOG(log, "::posix_spawn_file_actions_init(&file_actions) failed: {0}",
+ llvm::sys::StrError(error_code));
error.SetError(error_code, eErrorTypePOSIX);
return error;
}
@@ -409,11 +407,11 @@ static Error PosixSpawnChildForPTraceDebugging(const char *path,
error_code = ::posix_spawnp(pid, path, &file_actions, &attr,
(char *const *)argv, (char *const *)envp);
if (error_code != 0) {
- if (log)
- log->Printf("::posix_spawnp(pid => %p, path = '%s', file_actions "
- "= %p, attr = %p, argv = %p, envp = %p) failed: %s",
- pid, path, &file_actions, &attr, argv, envp,
- strerror(error_code));
+ LLDB_LOG(log,
+ "::posix_spawnp(pid => {0}, path = '{1}', file_actions "
+ "= {2}, attr = {3}, argv = {4}, envp = {5}) failed: {6}",
+ pid, path, &file_actions, &attr, argv, envp,
+ llvm::sys::StrError(error_code));
error.SetError(error_code, eErrorTypePOSIX);
return error;
}
@@ -436,9 +434,9 @@ static Error PosixSpawnChildForPTraceDebugging(const char *path,
return error;
}
-Error LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
- LaunchFlavor *launch_flavor) {
- Error error;
+Status LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
+ LaunchFlavor *launch_flavor) {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (!launch_flavor) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h
index d1af4d0..a0e8ce5 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h
@@ -39,8 +39,9 @@ namespace darwin_process_launcher {
/// @param[out] launch_flavor
/// Contains the launch flavor used when launching the process.
// =============================================================================
-Error LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
- lldb_private::process_darwin::LaunchFlavor *launch_flavor);
+Status
+LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
+ lldb_private::process_darwin::LaunchFlavor *launch_flavor);
} // darwin_process_launcher
} // lldb_private
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.cpp
index 8170644..7d956df 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.cpp
@@ -22,11 +22,11 @@
#include <mutex>
// LLDB includes
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -211,11 +211,11 @@ bool MachException::Data::GetStopInfo(struct ThreadStopInfo *stop_info,
return true;
}
-Error MachException::Message::Receive(mach_port_t port,
- mach_msg_option_t options,
- mach_msg_timeout_t timeout,
- mach_port_t notify_port) {
- Error error;
+Status MachException::Message::Receive(mach_port_t port,
+ mach_msg_option_t options,
+ mach_msg_timeout_t timeout,
+ mach_port_t notify_port) {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
mach_msg_timeout_t mach_msg_timeout =
@@ -312,10 +312,10 @@ bool MachException::Message::CatchExceptionRaise(task_t task) {
return success;
}
-Error MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task,
- int signal) {
+Status MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task,
+ int signal) {
// Reply to the exception...
- Error error;
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
@@ -412,8 +412,8 @@ Error MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task,
#define LLDB_EXC_MASK (EXC_MASK_ALL & ~EXC_MASK_RESOURCE)
-Error MachException::PortInfo::Save(task_t task) {
- Error error;
+Status MachException::PortInfo::Save(task_t task) {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
if (log)
@@ -471,8 +471,8 @@ Error MachException::PortInfo::Save(task_t task) {
return error;
}
-Error MachException::PortInfo::Restore(task_t task) {
- Error error;
+Status MachException::PortInfo::Restore(task_t task) {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.h
index ac8cd70..2da6a36 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/MachException.h
@@ -40,9 +40,9 @@ public:
thread_state_flavor_t flavors[EXC_TYPES_COUNT];
mach_msg_type_number_t count;
- Error Save(task_t task);
+ Status Save(task_t task);
- Error Restore(task_t task);
+ Status Restore(task_t task);
};
struct Data {
@@ -96,11 +96,11 @@ public:
bool CatchExceptionRaise(task_t task);
- Error Reply(::pid_t inferior_pid, task_t inferior_task, int signal);
+ Status Reply(::pid_t inferior_pid, task_t inferior_task, int signal);
- Error Receive(mach_port_t receive_port, mach_msg_option_t options,
- mach_msg_timeout_t timeout,
- mach_port_t notify_port = MACH_PORT_NULL);
+ Status Receive(mach_port_t receive_port, mach_msg_option_t options,
+ mach_msg_timeout_t timeout,
+ mach_port_t notify_port = MACH_PORT_NULL);
void Dump(Stream &stream) const;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
index e56375e..518f0d2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
@@ -19,11 +19,11 @@
// C++ includes
// LLDB includes
-#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Target/ProcessLaunchInfo.h"
-#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "CFBundle.h"
#include "CFString.h"
@@ -31,6 +31,8 @@
#include "MachException.h"
+#include "llvm/Support/FileSystem.h"
+
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_darwin;
@@ -51,19 +53,19 @@ struct hack_task_dyld_info {
// Public Static Methods
// -----------------------------------------------------------------------------
-Error NativeProcessProtocol::Launch(
+Status NativeProcessProtocol::Launch(
ProcessLaunchInfo &launch_info,
NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop,
NativeProcessProtocolSP &native_process_sp) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
- Error error;
+ Status error;
// Verify the working directory is valid if one was specified.
FileSpec working_dir(launch_info.GetWorkingDirectory());
if (working_dir &&
(!working_dir.ResolvePath() ||
- working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) {
+ !llvm::sys::fs::is_directory(working_dir.GetPath())) {
error.SetErrorStringWithFormat("No such file or directory: %s",
working_dir.GetCString());
return error;
@@ -118,7 +120,7 @@ Error NativeProcessProtocol::Launch(
return error;
}
-Error NativeProcessProtocol::Attach(
+Status NativeProcessProtocol::Attach(
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
@@ -128,7 +130,7 @@ Error NativeProcessProtocol::Attach(
// Retrieve the architecture for the running process.
ArchSpec process_arch;
- Error error = ResolveProcessArchitecture(pid, process_arch);
+ Status error = ResolveProcessArchitecture(pid, process_arch);
if (!error.Success())
return error;
@@ -172,9 +174,9 @@ NativeProcessDarwin::~NativeProcessDarwin() {}
// Instance methods
// -----------------------------------------------------------------------------
-Error NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor,
- MainLoop &main_loop) {
- Error error;
+Status NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor,
+ MainLoop &main_loop) {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
#if 0
@@ -259,7 +261,7 @@ Error NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor,
return error;
}
-Error NativeProcessDarwin::SaveExceptionPortInfo() {
+Status NativeProcessDarwin::SaveExceptionPortInfo() {
return m_exc_port_info.Save(m_task);
}
@@ -346,7 +348,7 @@ void *NativeProcessDarwin::DoExceptionThread() {
// polling is expensive. On devices, we need to minimize overhead caused
// by the process monitor.
uint32_t num_exceptions_received = 0;
- Error error;
+ Status error;
task_t task = m_task;
mach_msg_timeout_t periodic_timeout = 0;
@@ -548,8 +550,8 @@ void *NativeProcessDarwin::DoExceptionThread() {
return nullptr;
}
-Error NativeProcessDarwin::StartExceptionThread() {
- Error error;
+Status NativeProcessDarwin::StartExceptionThread() {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__);
@@ -638,7 +640,7 @@ Error NativeProcessDarwin::StartExceptionThread() {
}
lldb::addr_t
-NativeProcessDarwin::GetDYLDAllImageInfosAddress(Error &error) const {
+NativeProcessDarwin::GetDYLDAllImageInfosAddress(Status &error) const {
error.Clear();
struct hack_task_dyld_info dyld_info;
@@ -692,7 +694,7 @@ uint32_t NativeProcessDarwin::GetCPUType() const {
task_t NativeProcessDarwin::ExceptionMessageBundleComplete() {
// We have a complete bundle of exceptions for our child process.
- Error error;
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex);
@@ -735,7 +737,7 @@ task_t NativeProcessDarwin::ExceptionMessageBundleComplete() {
const addr_t info_array_count_addr = aii_addr + 4;
uint32_t info_array_count = 0;
size_t bytes_read = 0;
- Error read_error;
+ Status read_error;
read_error = ReadMemory(info_array_count_addr, // source addr
&info_array_count, // dest addr
4, // byte count
@@ -883,8 +885,8 @@ void NativeProcessDarwin::StartSTDIOThread() {
// TODO implement
}
-Error NativeProcessDarwin::StartWaitpidThread(MainLoop &main_loop) {
- Error error;
+Status NativeProcessDarwin::StartWaitpidThread(MainLoop &main_loop) {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
// Strategy: create a thread that sits on waitpid(), waiting for the
@@ -971,7 +973,7 @@ void *NativeProcessDarwin::DoWaitpidThread() {
// Ensure we don't get CPU starved.
MaybeRaiseThreadPriority();
- Error error;
+ Status error;
int status = -1;
while (1) {
@@ -1036,9 +1038,9 @@ void *NativeProcessDarwin::DoWaitpidThread() {
return nullptr;
}
-Error NativeProcessDarwin::SendInferiorExitStatusToMainLoop(::pid_t pid,
- int status) {
- Error error;
+Status NativeProcessDarwin::SendInferiorExitStatusToMainLoop(::pid_t pid,
+ int status) {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
size_t bytes_written = 0;
@@ -1067,8 +1069,8 @@ Error NativeProcessDarwin::SendInferiorExitStatusToMainLoop(::pid_t pid,
return error;
}
-Error NativeProcessDarwin::HandleWaitpidResult() {
- Error error;
+Status NativeProcessDarwin::HandleWaitpidResult() {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
// Read the pid.
@@ -1083,8 +1085,7 @@ Error NativeProcessDarwin::HandleWaitpidResult() {
"waitpid exiting pid from the pipe. Will notify "
"as if parent process died with exit status -1.",
__FUNCTION__);
- SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result",
- notify_status);
+ SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status);
return error;
}
@@ -1097,8 +1098,7 @@ Error NativeProcessDarwin::HandleWaitpidResult() {
"waitpid exit status from the pipe. Will notify "
"as if parent process died with exit status -1.",
__FUNCTION__);
- SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result",
- notify_status);
+ SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status);
return error;
}
@@ -1109,22 +1109,11 @@ Error NativeProcessDarwin::HandleWaitpidResult() {
__FUNCTION__, pid,
(pid == m_pid) ? "the inferior" : "not the inferior", status);
- ExitType exit_type = eExitTypeInvalid;
- int exit_status = -1;
-
- if (WIFEXITED(status)) {
- exit_type = eExitTypeExit;
- exit_status = WEXITSTATUS(status);
- } else if (WIFSIGNALED(status)) {
- exit_type = eExitTypeSignal;
- exit_status = WTERMSIG(status);
- }
-
- SetExitStatus(exit_type, exit_status, nullptr, notify_status);
+ SetExitStatus(WaitStatus::Decode(status), notify_status);
return error;
}
-task_t NativeProcessDarwin::TaskPortForProcessID(Error &error,
+task_t NativeProcessDarwin::TaskPortForProcessID(Status &error,
bool force) const {
if ((m_task == TASK_NULL) || force) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
@@ -1176,12 +1165,12 @@ task_t NativeProcessDarwin::TaskPortForProcessID(Error &error,
}
void NativeProcessDarwin::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid,
- Error &error) {
+ Status &error) {
error.SetErrorString("TODO: implement");
}
-Error NativeProcessDarwin::PrivateResume() {
- Error error;
+Status NativeProcessDarwin::PrivateResume() {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex);
@@ -1223,8 +1212,8 @@ Error NativeProcessDarwin::PrivateResume() {
return error;
}
-Error NativeProcessDarwin::ReplyToAllExceptions() {
- Error error;
+Status NativeProcessDarwin::ReplyToAllExceptions() {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
TaskPortForProcessID(error);
@@ -1280,8 +1269,8 @@ Error NativeProcessDarwin::ReplyToAllExceptions() {
return error;
}
-Error NativeProcessDarwin::ResumeTask() {
- Error error;
+Status NativeProcessDarwin::ResumeTask() {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
TaskPortForProcessID(error);
@@ -1362,9 +1351,10 @@ bool NativeProcessDarwin::IsExceptionPortValid() const {
return MACH_PORT_VALID(m_exception_port);
}
-Error NativeProcessDarwin::GetTaskBasicInfo(
- task_t task, struct task_basic_info *info) const {
- Error error;
+Status
+NativeProcessDarwin::GetTaskBasicInfo(task_t task,
+ struct task_basic_info *info) const {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
// Validate args.
@@ -1410,8 +1400,8 @@ Error NativeProcessDarwin::GetTaskBasicInfo(
return error;
}
-Error NativeProcessDarwin::SuspendTask() {
- Error error;
+Status NativeProcessDarwin::SuspendTask() {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (m_task == TASK_NULL) {
@@ -1430,8 +1420,8 @@ Error NativeProcessDarwin::SuspendTask() {
return error;
}
-Error NativeProcessDarwin::Resume(const ResumeActionList &resume_actions) {
- Error error;
+Status NativeProcessDarwin::Resume(const ResumeActionList &resume_actions) {
+ Status error;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
@@ -1459,74 +1449,74 @@ Error NativeProcessDarwin::Resume(const ResumeActionList &resume_actions) {
return error;
}
-Error NativeProcessDarwin::Halt() {
- Error error;
+Status NativeProcessDarwin::Halt() {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::Detach() {
- Error error;
+Status NativeProcessDarwin::Detach() {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::Signal(int signo) {
- Error error;
+Status NativeProcessDarwin::Signal(int signo) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::Interrupt() {
- Error error;
+Status NativeProcessDarwin::Interrupt() {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::Kill() {
- Error error;
+Status NativeProcessDarwin::Kill() {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::GetMemoryRegionInfo(lldb::addr_t load_addr,
- MemoryRegionInfo &range_info) {
- Error error;
+Status NativeProcessDarwin::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
- size_t &bytes_read) {
- Error error;
+Status NativeProcessDarwin::ReadMemory(lldb::addr_t addr, void *buf,
+ size_t size, size_t &bytes_read) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf,
- size_t size,
- size_t &bytes_read) {
- Error error;
+Status NativeProcessDarwin::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf,
+ size_t size,
+ size_t &bytes_read) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::WriteMemory(lldb::addr_t addr, const void *buf,
- size_t size, size_t &bytes_written) {
- Error error;
+Status NativeProcessDarwin::WriteMemory(lldb::addr_t addr, const void *buf,
+ size_t size, size_t &bytes_written) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) {
- Error error;
+Status NativeProcessDarwin::AllocateMemory(size_t size, uint32_t permissions,
+ lldb::addr_t &addr) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::DeallocateMemory(lldb::addr_t addr) {
- Error error;
+Status NativeProcessDarwin::DeallocateMemory(lldb::addr_t addr) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
@@ -1541,25 +1531,25 @@ bool NativeProcessDarwin::GetArchitecture(ArchSpec &arch) const {
return false;
}
-Error NativeProcessDarwin::SetBreakpoint(lldb::addr_t addr, uint32_t size,
- bool hardware) {
- Error error;
+Status NativeProcessDarwin::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
void NativeProcessDarwin::DoStopIDBumped(uint32_t newBumpId) {}
-Error NativeProcessDarwin::GetLoadedModuleFileSpec(const char *module_path,
- FileSpec &file_spec) {
- Error error;
+Status NativeProcessDarwin::GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
-Error NativeProcessDarwin::GetFileLoadAddress(const llvm::StringRef &file_name,
- lldb::addr_t &load_addr) {
- Error error;
+Status NativeProcessDarwin::GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) {
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
@@ -1567,10 +1557,10 @@ Error NativeProcessDarwin::GetFileLoadAddress(const llvm::StringRef &file_name,
// -----------------------------------------------------------------
// NativeProcessProtocol protected interface
// -----------------------------------------------------------------
-Error NativeProcessDarwin::GetSoftwareBreakpointTrapOpcode(
+Status NativeProcessDarwin::GetSoftwareBreakpointTrapOpcode(
size_t trap_opcode_size_hint, size_t &actual_opcode_size,
const uint8_t *&trap_opcode_bytes) {
- Error error;
+ Status error;
error.SetErrorString("TODO: implement");
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h
index 69c1b8d..2214bbc 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h
@@ -24,11 +24,11 @@
// Other libraries and framework includes
#include "lldb/Core/ArchSpec.h"
#include "lldb/Host/Debug.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/Pipe.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-types.h"
#include "LaunchFlavor.h"
@@ -37,7 +37,7 @@
#include "NativeThreadListDarwin.h"
namespace lldb_private {
-class Error;
+class Status;
class Scalar;
namespace process_darwin {
@@ -50,11 +50,11 @@ namespace process_darwin {
///
/// Changes in the inferior process state are broadcasted.
class NativeProcessDarwin : public NativeProcessProtocol {
- friend Error NativeProcessProtocol::Launch(
+ friend Status NativeProcessProtocol::Launch(
ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
- friend Error NativeProcessProtocol::Attach(
+ friend Status NativeProcessProtocol::Attach(
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
@@ -64,34 +64,34 @@ public:
// -----------------------------------------------------------------
// NativeProcessProtocol Interface
// -----------------------------------------------------------------
- Error Resume(const ResumeActionList &resume_actions) override;
+ Status Resume(const ResumeActionList &resume_actions) override;
- Error Halt() override;
+ Status Halt() override;
- Error Detach() override;
+ Status Detach() override;
- Error Signal(int signo) override;
+ Status Signal(int signo) override;
- Error Interrupt() override;
+ Status Interrupt() override;
- Error Kill() override;
+ Status Kill() override;
- Error GetMemoryRegionInfo(lldb::addr_t load_addr,
- MemoryRegionInfo &range_info) override;
+ Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
- Error ReadMemory(lldb::addr_t addr, void *buf, size_t size,
- size_t &bytes_read) override;
+ Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
- Error ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size,
- size_t &bytes_read) override;
+ Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
- Error WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
- size_t &bytes_written) override;
+ Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ size_t &bytes_written) override;
- Error AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) override;
+ Status AllocateMemory(size_t size, uint32_t permissions,
+ lldb::addr_t &addr) override;
- Error DeallocateMemory(lldb::addr_t addr) override;
+ Status DeallocateMemory(lldb::addr_t addr) override;
lldb::addr_t GetSharedLibraryInfoAddress() override;
@@ -99,15 +99,16 @@ public:
bool GetArchitecture(ArchSpec &arch) const override;
- Error SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override;
+ Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) override;
void DoStopIDBumped(uint32_t newBumpId) override;
- Error GetLoadedModuleFileSpec(const char *module_path,
- FileSpec &file_spec) override;
+ Status GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) override;
- Error GetFileLoadAddress(const llvm::StringRef &file_name,
- lldb::addr_t &load_addr) override;
+ Status GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) override;
NativeThreadDarwinSP GetThreadByID(lldb::tid_t id);
@@ -116,9 +117,9 @@ public:
// -----------------------------------------------------------------
// Interface used by NativeRegisterContext-derived classes.
// -----------------------------------------------------------------
- static Error PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
- void *data = nullptr, size_t data_size = 0,
- long *result = nullptr);
+ static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
+ void *data = nullptr, size_t data_size = 0,
+ long *result = nullptr);
bool SupportHardwareSingleStepping() const;
@@ -126,7 +127,7 @@ protected:
// -----------------------------------------------------------------
// NativeProcessProtocol protected interface
// -----------------------------------------------------------------
- Error
+ Status
GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint,
size_t &actual_opcode_size,
const uint8_t *&trap_opcode_bytes) override;
@@ -236,19 +237,19 @@ private:
/// operations. Failure here will force termination of the
/// launched process and debugging session.
// -----------------------------------------------------------------
- Error FinalizeLaunch(LaunchFlavor launch_flavor, MainLoop &main_loop);
+ Status FinalizeLaunch(LaunchFlavor launch_flavor, MainLoop &main_loop);
- Error SaveExceptionPortInfo();
+ Status SaveExceptionPortInfo();
void ExceptionMessageReceived(const MachException::Message &message);
void MaybeRaiseThreadPriority();
- Error StartExceptionThread();
+ Status StartExceptionThread();
- Error SendInferiorExitStatusToMainLoop(::pid_t pid, int status);
+ Status SendInferiorExitStatusToMainLoop(::pid_t pid, int status);
- Error HandleWaitpidResult();
+ Status HandleWaitpidResult();
bool ProcessUsingSpringBoard() const;
@@ -258,7 +259,7 @@ private:
void *DoExceptionThread();
- lldb::addr_t GetDYLDAllImageInfosAddress(Error &error) const;
+ lldb::addr_t GetDYLDAllImageInfosAddress(Status &error) const;
static uint32_t GetCPUTypeForLocalProcess(::pid_t pid);
@@ -268,25 +269,25 @@ private:
void StartSTDIOThread();
- Error StartWaitpidThread(MainLoop &main_loop);
+ Status StartWaitpidThread(MainLoop &main_loop);
static void *WaitpidThread(void *arg);
void *DoWaitpidThread();
- task_t TaskPortForProcessID(Error &error, bool force = false) const;
+ task_t TaskPortForProcessID(Status &error, bool force = false) const;
/// Attaches to an existing process. Forms the
/// implementation of Process::DoAttach.
- void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Error &error);
+ void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error);
- ::pid_t Attach(lldb::pid_t pid, Error &error);
+ ::pid_t Attach(lldb::pid_t pid, Status &error);
- Error PrivateResume();
+ Status PrivateResume();
- Error ReplyToAllExceptions();
+ Status ReplyToAllExceptions();
- Error ResumeTask();
+ Status ResumeTask();
bool IsTaskValid() const;
@@ -296,11 +297,11 @@ private:
bool IsExceptionPortValid() const;
- Error GetTaskBasicInfo(task_t task, struct task_basic_info *info) const;
+ Status GetTaskBasicInfo(task_t task, struct task_basic_info *info) const;
- Error SuspendTask();
+ Status SuspendTask();
- static Error SetDefaultPtraceOpts(const lldb::pid_t);
+ static Status SetDefaultPtraceOpts(const lldb::pid_t);
static void *MonitorThread(void *baton);
@@ -319,7 +320,7 @@ private:
void MonitorSignal(const siginfo_t &info, NativeThreadDarwin &thread,
bool exited);
- Error SetupSoftwareSingleStepping(NativeThreadDarwin &thread);
+ Status SetupSoftwareSingleStepping(NativeThreadDarwin &thread);
#if 0
static ::ProcessMessage::CrashReason
@@ -341,22 +342,22 @@ private:
NativeThreadDarwinSP AddThread(lldb::tid_t thread_id);
- Error GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size);
+ Status GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size);
- Error FixupBreakpointPCAsNeeded(NativeThreadDarwin &thread);
+ Status FixupBreakpointPCAsNeeded(NativeThreadDarwin &thread);
/// Writes a siginfo_t structure corresponding to the given thread
/// ID to the memory region pointed to by @p siginfo.
- Error GetSignalInfo(lldb::tid_t tid, void *siginfo);
+ Status GetSignalInfo(lldb::tid_t tid, void *siginfo);
/// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
/// corresponding to the given thread ID to the memory pointed to
/// by @p message.
- Error GetEventMessage(lldb::tid_t tid, unsigned long *message);
+ Status GetEventMessage(lldb::tid_t tid, unsigned long *message);
void NotifyThreadDeath(lldb::tid_t tid);
- Error Detach(lldb::tid_t tid);
+ Status Detach(lldb::tid_t tid);
// This method is requests a stop on all threads which are still
// running. It sets up a deferred delegate notification, which will
@@ -370,8 +371,8 @@ private:
// Resume the given thread, optionally passing it the given signal.
// The type of resume operation (continue, single-step) depends on
// the state parameter.
- Error ResumeThread(NativeThreadDarwin &thread, lldb::StateType state,
- int signo);
+ Status ResumeThread(NativeThreadDarwin &thread, lldb::StateType state,
+ int signo);
void ThreadWasCreated(NativeThreadDarwin &thread);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp
index 5e7f9ae..07398ab 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp
@@ -13,7 +13,7 @@
#include <libproc.h>
// LLDB includes
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
#include "NativeProcessDarwin.h"
@@ -94,15 +94,15 @@ NativeRegisterContextSP NativeThreadDarwin::GetRegisterContext() {
return NativeRegisterContextSP();
}
-Error NativeThreadDarwin::SetWatchpoint(lldb::addr_t addr, size_t size,
- uint32_t watch_flags, bool hardware) {
- Error error;
+Status NativeThreadDarwin::SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware) {
+ Status error;
error.SetErrorString("not yet implemented");
return error;
}
-Error NativeThreadDarwin::RemoveWatchpoint(lldb::addr_t addr) {
- Error error;
+Status NativeThreadDarwin::RemoveWatchpoint(lldb::addr_t addr) {
+ Status error;
error.SetErrorString("not yet implemented");
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h
index b8d9089..f66f8fe 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h
@@ -58,10 +58,10 @@ public:
NativeRegisterContextSP GetRegisterContext() override;
- Error SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
- bool hardware) override;
+ Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware) override;
- Error RemoveWatchpoint(lldb::addr_t addr) override;
+ Status RemoveWatchpoint(lldb::addr_t addr) override;
// -----------------------------------------------------------------
// New methods that are fine for others to call.
@@ -75,11 +75,11 @@ private:
/// Resumes the thread. If @p signo is anything but
/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
- Error Resume(uint32_t signo);
+ Status Resume(uint32_t signo);
/// Single steps the thread. If @p signo is anything but
/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
- Error SingleStep(uint32_t signo);
+ Status SingleStep(uint32_t signo);
bool NotifyException(MachException::Data &exc);
@@ -117,7 +117,7 @@ private:
void SetExited();
- Error RequestStop();
+ Status RequestStop();
// -------------------------------------------------------------------------
/// Return the mach thread port number for this thread.
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp
index aa9b041..7d44ade 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp
@@ -20,9 +20,9 @@
#include <sys/sysctl.h>
// LLDB includes
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
#include "lldb/lldb-enumerations.h"
#include "NativeProcessDarwin.h"
@@ -343,7 +343,7 @@ uint32_t NativeThreadListDarwin::UpdateThreadList(NativeProcessDarwin &process,
mach_msg_type_number_t thread_list_count = 0;
task_t task = process.GetTask();
- Error error;
+ Status error;
auto mach_err = ::task_threads(task, &thread_list, &thread_list_count);
error.SetError(mach_err, eErrorTypeMachKernel);
if (error.Fail()) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h
index 2b194bc..7b59afb 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h
@@ -123,7 +123,7 @@ protected:
typedef collection::iterator iterator;
typedef collection::const_iterator const_iterator;
- // Consider having this return an lldb_private::Error.
+ // Consider having this return an lldb_private::Status.
uint32_t UpdateThreadList(NativeProcessDarwin &process, bool update,
collection *num_threads = nullptr);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
index be92a0d..f50f18b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
@@ -9,6 +9,12 @@
// C Includes
#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdlib.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/user.h>
// C++ Includes
// Other libraries and framework includes
@@ -18,16 +24,16 @@
// Project includes
#include "FreeBSDThread.h"
#include "POSIXStopInfo.h"
-#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
#include "Plugins/Process/Utility/UnwindLLDB.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
-#include "ProcessPOSIXLog.h"
#include "RegisterContextPOSIXProcessMonitor_arm.h"
#include "RegisterContextPOSIXProcessMonitor_arm64.h"
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
@@ -53,8 +59,7 @@ FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid)
: Thread(process, tid), m_frame_ap(), m_breakpoint(),
m_thread_name_valid(false), m_thread_name(), m_posix_thread(NULL) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
- if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
- log->Printf("FreeBSDThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid);
+ LLDB_LOGV(log, "tid = {0}", tid);
// Set the current watchpoints for this thread.
Target &target = GetProcess()->GetTarget();
@@ -114,9 +119,41 @@ void FreeBSDThread::SetName(const char *name) {
const char *FreeBSDThread::GetName() {
if (!m_thread_name_valid) {
- llvm::SmallString<32> thread_name;
- HostNativeThread::GetName(GetID(), thread_name);
- m_thread_name = thread_name.c_str();
+ m_thread_name.clear();
+ int pid = GetProcess()->GetID();
+
+ struct kinfo_proc *kp = nullptr, *nkp;
+ size_t len = 0;
+ int error;
+ int ctl[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
+ pid};
+
+ while (1) {
+ error = sysctl(ctl, 4, kp, &len, nullptr, 0);
+ if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
+ // Add extra space in case threads are added before next call.
+ len += sizeof(*kp) + len / 10;
+ nkp = (struct kinfo_proc *)realloc(kp, len);
+ if (nkp == nullptr) {
+ free(kp);
+ return nullptr;
+ }
+ kp = nkp;
+ continue;
+ }
+ if (error != 0)
+ len = 0;
+ break;
+ }
+
+ for (size_t i = 0; i < len / sizeof(*kp); i++) {
+ if (kp[i].ki_tid == (lwpid_t)GetID()) {
+ m_thread_name.append(kp[i].ki_tdname,
+ kp[i].ki_tdname + strlen(kp[i].ki_tdname));
+ break;
+ }
+ }
+ free(kp);
m_thread_name_valid = true;
}
@@ -138,7 +175,7 @@ lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() {
reg_interface = new RegisterInfoPOSIX_arm64(target_arch);
break;
case llvm::Triple::arm:
- reg_interface = new RegisterContextFreeBSD_arm(target_arch);
+ reg_interface = new RegisterInfoPOSIX_arm(target_arch);
break;
case llvm::Triple::ppc:
#ifndef __powerpc64__
@@ -215,8 +252,7 @@ FreeBSDThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) {
uint32_t concrete_frame_idx = 0;
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
- if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
- log->Printf("FreeBSDThread::%s ()", __FUNCTION__);
+ LLDB_LOGV(log, "called");
if (frame)
concrete_frame_idx = frame->GetConcreteFrameIndex();
@@ -339,6 +375,7 @@ void FreeBSDThread::Notify(const ProcessMessage &message) {
LimboNotify(message);
break;
+ case ProcessMessage::eCrashMessage:
case ProcessMessage::eSignalMessage:
SignalNotify(message);
break;
@@ -359,10 +396,6 @@ void FreeBSDThread::Notify(const ProcessMessage &message) {
WatchNotify(message);
break;
- case ProcessMessage::eCrashMessage:
- CrashNotify(message);
- break;
-
case ProcessMessage::eExecMessage:
ExecNotify(message);
break;
@@ -541,7 +574,14 @@ void FreeBSDThread::LimboNotify(const ProcessMessage &message) {
void FreeBSDThread::SignalNotify(const ProcessMessage &message) {
int signo = message.GetSignal();
- SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo));
+ if (message.GetKind() == ProcessMessage::eCrashMessage) {
+ std::string stop_description = GetCrashReasonString(
+ message.GetCrashReason(), message.GetFaultAddress());
+ SetStopInfo(StopInfo::CreateStopReasonWithSignal(
+ *this, signo, stop_description.c_str()));
+ } else {
+ SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo));
+ }
}
void FreeBSDThread::SignalDeliveredNotify(const ProcessMessage &message) {
@@ -549,21 +589,6 @@ void FreeBSDThread::SignalDeliveredNotify(const ProcessMessage &message) {
SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo));
}
-void FreeBSDThread::CrashNotify(const ProcessMessage &message) {
- // FIXME: Update stop reason as per bugzilla 14598
- int signo = message.GetSignal();
-
- assert(message.GetKind() == ProcessMessage::eCrashMessage);
-
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
- if (log)
- log->Printf("FreeBSDThread::%s () signo = %i, reason = '%s'", __FUNCTION__,
- signo, message.PrintCrashReason());
-
- SetStopInfo(lldb::StopInfoSP(new POSIXCrashStopInfo(
- *this, signo, message.GetCrashReason(), message.GetFaultAddress())));
-}
-
unsigned FreeBSDThread::GetRegisterIndexFromOffset(unsigned offset) {
unsigned reg = LLDB_INVALID_REGNUM;
ArchSpec arch = HostInfo::GetArchitecture();
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp
index dfbd695..9c75c26 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp
@@ -28,22 +28,6 @@ bool POSIXLimboStopInfo::ShouldStop(Event *event_ptr) { return false; }
bool POSIXLimboStopInfo::ShouldNotify(Event *event_ptr) { return false; }
//===----------------------------------------------------------------------===//
-// POSIXCrashStopInfo
-
-POSIXCrashStopInfo::POSIXCrashStopInfo(FreeBSDThread &thread, uint32_t status,
- CrashReason reason,
- lldb::addr_t fault_addr)
- : POSIXStopInfo(thread, status) {
- m_description = ::GetCrashReasonString(reason, fault_addr);
-}
-
-POSIXCrashStopInfo::~POSIXCrashStopInfo() {}
-
-lldb::StopReason POSIXCrashStopInfo::GetStopReason() const {
- return lldb::eStopReasonException;
-}
-
-//===----------------------------------------------------------------------===//
// POSIXNewThreadStopInfo
POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() {}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
index 1ee16dd..9686185 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
@@ -10,15 +10,9 @@
#ifndef liblldb_POSIXStopInfo_H_
#define liblldb_POSIXStopInfo_H_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Target/StopInfo.h"
-
-#include "CrashReason.h"
#include "FreeBSDThread.h"
-
+#include "Plugins/Process/POSIX/CrashReason.h"
+#include "lldb/Target/StopInfo.h"
#include <string>
//===----------------------------------------------------------------------===//
@@ -51,19 +45,6 @@ public:
};
//===----------------------------------------------------------------------===//
-/// @class POSIXCrashStopInfo
-/// @brief Represents the stop state of process that is ready to crash.
-///
-class POSIXCrashStopInfo : public POSIXStopInfo {
-public:
- POSIXCrashStopInfo(FreeBSDThread &thread, uint32_t status, CrashReason reason,
- lldb::addr_t fault_addr);
- ~POSIXCrashStopInfo();
-
- lldb::StopReason GetStopReason() const;
-};
-
-//===----------------------------------------------------------------------===//
/// @class POSIXNewThreadStopInfo
/// @brief Represents the stop state of process when a new thread is spawned.
///
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
index 82e45a5..3046150 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -10,12 +10,21 @@
// C Includes
#include <errno.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdlib.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <machine/elf.h>
// C++ Includes
#include <mutex>
+#include <unordered_map>
// Other libraries and framework includes
#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/State.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/ObjectFile.h"
@@ -23,11 +32,11 @@
#include "lldb/Target/Target.h"
#include "FreeBSDThread.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/FreeBSDSignals.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
-#include "ProcessPOSIXLog.h"
// Other libraries and framework includes
#include "lldb/Breakpoint/BreakpointLocation.h"
@@ -36,15 +45,19 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Host/posix/Fcntl.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Threading.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -70,12 +83,11 @@ ProcessFreeBSD::CreateInstance(lldb::TargetSP target_sp,
}
void ProcessFreeBSD::Initialize() {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance);
- ProcessPOSIXLog::Initialize(GetPluginNameStatic());
});
}
@@ -99,8 +111,8 @@ uint32_t ProcessFreeBSD::GetPluginVersion() { return 1; }
void ProcessFreeBSD::Terminate() {}
-Error ProcessFreeBSD::DoDetach(bool keep_stopped) {
- Error error;
+Status ProcessFreeBSD::DoDetach(bool keep_stopped) {
+ Status error;
if (keep_stopped) {
error.SetErrorString("Detaching with keep_stopped true is not currently "
"supported on FreeBSD.");
@@ -115,13 +127,14 @@ Error ProcessFreeBSD::DoDetach(bool keep_stopped) {
return error;
}
-Error ProcessFreeBSD::DoResume() {
+Status ProcessFreeBSD::DoResume() {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
SetPrivateState(eStateRunning);
std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex());
bool do_step = false;
+ bool software_single_step = !SupportHardwareSingleStepping();
for (tid_collection::const_iterator t_pos = m_run_tids.begin(),
t_end = m_run_tids.end();
@@ -133,6 +146,11 @@ Error ProcessFreeBSD::DoResume() {
t_pos != t_end; ++t_pos) {
m_monitor->ThreadSuspend(*t_pos, false);
do_step = true;
+ if (software_single_step) {
+ Status error = SetupSoftwareSingleStepping(*t_pos);
+ if (error.Fail())
+ return error;
+ }
}
for (tid_collection::const_iterator t_pos = m_suspend_tids.begin(),
t_end = m_suspend_tids.end();
@@ -145,12 +163,12 @@ Error ProcessFreeBSD::DoResume() {
if (log)
log->Printf("process %" PRIu64 " resuming (%s)", GetID(),
do_step ? "step" : "continue");
- if (do_step)
+ if (do_step && !software_single_step)
m_monitor->SingleStep(GetID(), m_resume_signo);
else
m_monitor->Resume(GetID(), m_resume_signo);
- return Error();
+ return Status();
}
bool ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list,
@@ -191,7 +209,7 @@ bool ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list,
return true;
}
-Error ProcessFreeBSD::WillResume() {
+Status ProcessFreeBSD::WillResume() {
m_resume_signo = 0;
m_suspend_tids.clear();
m_run_tids.clear();
@@ -275,14 +293,14 @@ bool ProcessFreeBSD::CanDebug(lldb::TargetSP target_sp,
return true;
}
-Error ProcessFreeBSD::DoAttachToProcessWithID(
- lldb::pid_t pid, const ProcessAttachInfo &attach_info) {
- Error error;
+Status
+ProcessFreeBSD::DoAttachToProcessWithID(lldb::pid_t pid,
+ const ProcessAttachInfo &attach_info) {
+ Status error;
assert(m_monitor == NULL);
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
- if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
- log->Printf("ProcessFreeBSD::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID());
+ LLDB_LOGV(log, "pid = {0}", GetID());
m_monitor = new ProcessMonitor(this, pid, error);
@@ -326,8 +344,8 @@ Error ProcessFreeBSD::DoAttachToProcessWithID(
return error;
}
-Error ProcessFreeBSD::WillLaunch(Module *module) {
- Error error;
+Status ProcessFreeBSD::WillLaunch(Module *module) {
+ Status error;
return error;
}
@@ -349,14 +367,15 @@ ProcessFreeBSD::GetFileSpec(const lldb_private::FileAction *file_action,
return file_spec;
}
-Error ProcessFreeBSD::DoLaunch(Module *module, ProcessLaunchInfo &launch_info) {
- Error error;
+Status ProcessFreeBSD::DoLaunch(Module *module,
+ ProcessLaunchInfo &launch_info) {
+ Status error;
assert(m_monitor == NULL);
FileSpec working_dir = launch_info.GetWorkingDirectory();
- if (working_dir &&
- (!working_dir.ResolvePath() ||
- working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) {
+ namespace fs = llvm::sys::fs;
+ if (working_dir && (!working_dir.ResolvePath() ||
+ !fs::is_directory(working_dir.GetPath()))) {
error.SetErrorStringWithFormat("No such file or directory: %s",
working_dir.GetCString());
return error;
@@ -439,8 +458,8 @@ addr_t ProcessFreeBSD::GetImageInfoAddress() {
return LLDB_INVALID_ADDRESS;
}
-Error ProcessFreeBSD::DoHalt(bool &caused_stop) {
- Error error;
+Status ProcessFreeBSD::DoHalt(bool &caused_stop) {
+ Status error;
if (IsStopped()) {
caused_stop = false;
@@ -453,8 +472,8 @@ Error ProcessFreeBSD::DoHalt(bool &caused_stop) {
return error;
}
-Error ProcessFreeBSD::DoSignal(int signal) {
- Error error;
+Status ProcessFreeBSD::DoSignal(int signal) {
+ Status error;
if (kill(GetID(), signal))
error.SetErrorToErrno();
@@ -462,8 +481,8 @@ Error ProcessFreeBSD::DoSignal(int signal) {
return error;
}
-Error ProcessFreeBSD::DoDestroy() {
- Error error;
+Status ProcessFreeBSD::DoDestroy() {
+ Status error;
if (!HasExited()) {
assert(m_monitor);
@@ -496,7 +515,7 @@ void ProcessFreeBSD::DoDidExec() {
target->GetArchitecture());
FileSpecList executable_search_paths(
Target::GetDefaultExecutableSearchPaths());
- Error error = platform_sp->ResolveExecutable(
+ Status error = platform_sp->ResolveExecutable(
exe_module_spec, exe_module_sp,
executable_search_paths.GetSize() ? &executable_search_paths : NULL);
if (!error.Success())
@@ -528,9 +547,7 @@ ProcessFreeBSD::CreateNewFreeBSDThread(lldb_private::Process &process,
void ProcessFreeBSD::RefreshStateAfterStop() {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
- if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
- log->Printf("ProcessFreeBSD::%s(), message_queue size = %d", __FUNCTION__,
- (int)m_message_queue.size());
+ LLDB_LOGV(log, "message_queue size = {0}", m_message_queue.size());
std::lock_guard<std::recursive_mutex> guard(m_message_mutex);
@@ -542,10 +559,8 @@ void ProcessFreeBSD::RefreshStateAfterStop() {
// Resolve the thread this message corresponds to and pass it along.
lldb::tid_t tid = message.GetTID();
- if (log)
- log->Printf(
- "ProcessFreeBSD::%s(), message_queue size = %d, pid = %" PRIi64,
- __FUNCTION__, (int)m_message_queue.size(), tid);
+ LLDB_LOGV(log, " message_queue size = {0}, pid = {1}",
+ m_message_queue.size(), tid);
m_thread_list.RefreshStateAfterStop();
@@ -557,10 +572,7 @@ void ProcessFreeBSD::RefreshStateAfterStop() {
if (message.GetKind() == ProcessMessage::eExitMessage) {
// FIXME: We should tell the user about this, but the limbo message is
// probably better for that.
- if (log)
- log->Printf("ProcessFreeBSD::%s() removing thread, tid = %" PRIi64,
- __FUNCTION__, tid);
-
+ LLDB_LOG(log, "removing thread, tid = {0}", tid);
std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex());
ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false);
@@ -579,19 +591,19 @@ bool ProcessFreeBSD::IsAlive() {
}
size_t ProcessFreeBSD::DoReadMemory(addr_t vm_addr, void *buf, size_t size,
- Error &error) {
+ Status &error) {
assert(m_monitor);
return m_monitor->ReadMemory(vm_addr, buf, size, error);
}
size_t ProcessFreeBSD::DoWriteMemory(addr_t vm_addr, const void *buf,
- size_t size, Error &error) {
+ size_t size, Status &error) {
assert(m_monitor);
return m_monitor->WriteMemory(vm_addr, buf, size, error);
}
addr_t ProcessFreeBSD::DoAllocateMemory(size_t size, uint32_t permissions,
- Error &error) {
+ Status &error) {
addr_t allocated_addr = LLDB_INVALID_ADDRESS;
unsigned prot = 0;
@@ -616,8 +628,8 @@ addr_t ProcessFreeBSD::DoAllocateMemory(size_t size, uint32_t permissions,
return allocated_addr;
}
-Error ProcessFreeBSD::DoDeallocateMemory(lldb::addr_t addr) {
- Error error;
+Status ProcessFreeBSD::DoDeallocateMemory(lldb::addr_t addr) {
+ Status error;
MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
if (pos != m_addr_to_mmap_size.end() &&
InferiorCallMunmap(this, addr, pos->second))
@@ -681,16 +693,16 @@ ProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site) {
return opcode_size;
}
-Error ProcessFreeBSD::EnableBreakpointSite(BreakpointSite *bp_site) {
+Status ProcessFreeBSD::EnableBreakpointSite(BreakpointSite *bp_site) {
return EnableSoftwareBreakpoint(bp_site);
}
-Error ProcessFreeBSD::DisableBreakpointSite(BreakpointSite *bp_site) {
+Status ProcessFreeBSD::DisableBreakpointSite(BreakpointSite *bp_site) {
return DisableSoftwareBreakpoint(bp_site);
}
-Error ProcessFreeBSD::EnableWatchpoint(Watchpoint *wp, bool notify) {
- Error error;
+Status ProcessFreeBSD::EnableWatchpoint(Watchpoint *wp, bool notify) {
+ Status error;
if (wp) {
user_id_t watchID = wp->GetID();
addr_t addr = wp->GetLoadAddress();
@@ -744,8 +756,8 @@ Error ProcessFreeBSD::EnableWatchpoint(Watchpoint *wp, bool notify) {
return error;
}
-Error ProcessFreeBSD::DisableWatchpoint(Watchpoint *wp, bool notify) {
- Error error;
+Status ProcessFreeBSD::DisableWatchpoint(Watchpoint *wp, bool notify) {
+ Status error;
if (wp) {
user_id_t watchID = wp->GetID();
addr_t addr = wp->GetLoadAddress();
@@ -787,8 +799,8 @@ Error ProcessFreeBSD::DisableWatchpoint(Watchpoint *wp, bool notify) {
return error;
}
-Error ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) {
- Error error;
+Status ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) {
+ Status error;
std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex());
FreeBSDThread *thread = static_cast<FreeBSDThread *>(
m_thread_list.GetThreadAtIndex(0, false).get());
@@ -799,8 +811,8 @@ Error ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) {
return error;
}
-Error ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num, bool &after) {
- Error error = GetWatchpointSupportInfo(num);
+Status ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num, bool &after) {
+ Status error = GetWatchpointSupportInfo(num);
// Watchpoints trigger and halt the inferior after
// the corresponding instruction has been executed.
after = true;
@@ -845,7 +857,7 @@ ByteOrder ProcessFreeBSD::GetByteOrder() const {
return m_byte_order;
}
-size_t ProcessFreeBSD::PutSTDIN(const char *buf, size_t len, Error &error) {
+size_t ProcessFreeBSD::PutSTDIN(const char *buf, size_t len, Status &error) {
ssize_t status;
if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0) {
error.SetErrorToErrno();
@@ -903,13 +915,207 @@ bool ProcessFreeBSD::IsAThreadRunning() {
const DataBufferSP ProcessFreeBSD::GetAuxvData() {
// If we're the local platform, we can ask the host for auxv data.
PlatformSP platform_sp = GetTarget().GetPlatform();
- if (platform_sp && platform_sp->IsHost())
- return lldb_private::Host::GetAuxvData(this);
-
- // Somewhat unexpected - the process is not running locally or we don't have a
- // platform.
- assert(
- false &&
- "no platform or not the host - how did we get here with ProcessFreeBSD?");
- return DataBufferSP();
+ assert(platform_sp && platform_sp->IsHost());
+
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, (int)m_process->GetID()};
+ size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo);
+ DataBufferSP buf_sp(new DataBufferHeap(auxv_size, 0));
+
+ if (::sysctl(mib, 4, buf_sp->GetBytes(), &auxv_size, NULL, 0) != 0) {
+ perror("sysctl failed on auxv");
+ buf_sp.reset();
+ }
+
+ return buf_sp;
+}
+
+struct EmulatorBaton {
+ ProcessFreeBSD *m_process;
+ RegisterContext *m_reg_context;
+
+ // eRegisterKindDWARF -> RegisterValue
+ std::unordered_map<uint32_t, RegisterValue> m_register_values;
+
+ EmulatorBaton(ProcessFreeBSD *process, RegisterContext *reg_context)
+ : m_process(process), m_reg_context(reg_context) {}
+};
+
+static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr, void *dst, size_t length) {
+ EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
+
+ Status error;
+ size_t bytes_read =
+ emulator_baton->m_process->DoReadMemory(addr, dst, length, error);
+ if (!error.Success())
+ bytes_read = 0;
+ return bytes_read;
+}
+
+static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
+
+ auto it = emulator_baton->m_register_values.find(
+ reg_info->kinds[eRegisterKindDWARF]);
+ if (it != emulator_baton->m_register_values.end()) {
+ reg_value = it->second;
+ return true;
+ }
+
+ // The emulator only fills in the dwarf register numbers (and in some cases
+ // the generic register numbers). Get the full register info from the
+ // register context based on the dwarf register numbers.
+ const RegisterInfo *full_reg_info =
+ emulator_baton->m_reg_context->GetRegisterInfo(
+ eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
+
+ bool error =
+ emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value);
+ return error;
+}
+
+static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) {
+ EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
+ emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] =
+ reg_value;
+ return true;
+}
+
+static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr, const void *dst,
+ size_t length) {
+ return length;
+}
+
+bool ProcessFreeBSD::SingleStepBreakpointHit(
+ void *baton, lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id, lldb::user_id_t break_loc_id) {
+ return false;
+}
+
+Status ProcessFreeBSD::SetSoftwareSingleStepBreakpoint(lldb::tid_t tid,
+ lldb::addr_t addr) {
+ Status error;
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ if (log) {
+ log->Printf("ProcessFreeBSD::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+ log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+ }
+
+ // Validate the address.
+ if (addr == LLDB_INVALID_ADDRESS)
+ return Status("ProcessFreeBSD::%s invalid load address specified.",
+ __FUNCTION__);
+
+ Breakpoint *const sw_step_break =
+ m_process->GetTarget().CreateBreakpoint(addr, true, false).get();
+ sw_step_break->SetCallback(SingleStepBreakpointHit, this, true);
+ sw_step_break->SetBreakpointKind("software-signle-step");
+
+ if (log)
+ log->Printf("ProcessFreeBSD::%s addr = 0x%" PRIx64 " -- SUCCESS",
+ __FUNCTION__, addr);
+
+ m_threads_stepping_with_breakpoint.insert({tid, sw_step_break->GetID()});
+ return Status();
+}
+
+bool ProcessFreeBSD::IsSoftwareStepBreakpoint(lldb::tid_t tid) {
+ ThreadSP thread = GetThreadList().FindThreadByID(tid);
+ if (!thread)
+ return false;
+
+ assert(thread->GetRegisterContext());
+ lldb::addr_t stop_pc = thread->GetRegisterContext()->GetPC();
+
+ const auto &iter = m_threads_stepping_with_breakpoint.find(tid);
+ if (iter == m_threads_stepping_with_breakpoint.end())
+ return false;
+
+ lldb::break_id_t bp_id = iter->second;
+ BreakpointSP bp = GetTarget().GetBreakpointByID(bp_id);
+ if (!bp)
+ return false;
+
+ BreakpointLocationSP bp_loc = bp->FindLocationByAddress(stop_pc);
+ if (!bp_loc)
+ return false;
+
+ GetTarget().RemoveBreakpointByID(bp_id);
+ m_threads_stepping_with_breakpoint.erase(tid);
+ return true;
+}
+
+bool ProcessFreeBSD::SupportHardwareSingleStepping() const {
+ lldb_private::ArchSpec arch = GetTarget().GetArchitecture();
+ if (arch.GetMachine() == llvm::Triple::arm ||
+ arch.GetMachine() == llvm::Triple::mips64 ||
+ arch.GetMachine() == llvm::Triple::mips64el ||
+ arch.GetMachine() == llvm::Triple::mips ||
+ arch.GetMachine() == llvm::Triple::mipsel)
+ return false;
+ return true;
+}
+
+Status ProcessFreeBSD::SetupSoftwareSingleStepping(lldb::tid_t tid) {
+ std::unique_ptr<EmulateInstruction> emulator_ap(
+ EmulateInstruction::FindPlugin(GetTarget().GetArchitecture(),
+ eInstructionTypePCModifying, nullptr));
+
+ if (emulator_ap == nullptr)
+ return Status("Instruction emulator not found!");
+
+ FreeBSDThread *thread = static_cast<FreeBSDThread *>(
+ m_thread_list.FindThreadByID(tid, false).get());
+ if (thread == NULL)
+ return Status("Thread not found not found!");
+
+ lldb::RegisterContextSP register_context_sp = thread->GetRegisterContext();
+
+ EmulatorBaton baton(this, register_context_sp.get());
+ emulator_ap->SetBaton(&baton);
+ emulator_ap->SetReadMemCallback(&ReadMemoryCallback);
+ emulator_ap->SetReadRegCallback(&ReadRegisterCallback);
+ emulator_ap->SetWriteMemCallback(&WriteMemoryCallback);
+ emulator_ap->SetWriteRegCallback(&WriteRegisterCallback);
+
+ if (!emulator_ap->ReadInstruction())
+ return Status("Read instruction failed!");
+
+ bool emulation_result =
+ emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
+ const RegisterInfo *reg_info_pc = register_context_sp->GetRegisterInfo(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ auto pc_it =
+ baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
+
+ lldb::addr_t next_pc;
+ if (emulation_result) {
+ assert(pc_it != baton.m_register_values.end() &&
+ "Emulation was successful but PC wasn't updated");
+ next_pc = pc_it->second.GetAsUInt64();
+ } else if (pc_it == baton.m_register_values.end()) {
+ // Emulate instruction failed and it haven't changed PC. Advance PC
+ // with the size of the current opcode because the emulation of all
+ // PC modifying instruction should be successful. The failure most
+ // likely caused by a not supported instruction which don't modify PC.
+ next_pc =
+ register_context_sp->GetPC() + emulator_ap->GetOpcode().GetByteSize();
+ } else {
+ // The instruction emulation failed after it modified the PC. It is an
+ // unknown error where we can't continue because the next instruction is
+ // modifying the PC but we don't know how.
+ return Status("Instruction emulation failed unexpectedly");
+ }
+
+ SetSoftwareSingleStepBreakpoint(tid, next_pc);
+ return Status();
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
index cd38989..7ed2a56 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
@@ -11,19 +11,13 @@
#ifndef liblldb_ProcessFreeBSD_H_
#define liblldb_ProcessFreeBSD_H_
-// C Includes
-
-// C++ Includes
+#include "Plugins/Process/POSIX/ProcessMessage.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ThreadList.h"
#include <mutex>
#include <queue>
#include <set>
-// Other libraries and framework includes
-#include "ProcessFreeBSD.h"
-#include "ProcessMessage.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/ThreadList.h"
-
class ProcessMonitor;
class FreeBSDThread;
@@ -53,7 +47,7 @@ public:
~ProcessFreeBSD();
- virtual lldb_private::Error WillResume() override;
+ virtual lldb_private::Status WillResume() override;
//------------------------------------------------------------------
// PluginInterface protocol
@@ -71,27 +65,27 @@ public:
bool CanDebug(lldb::TargetSP target_sp,
bool plugin_specified_by_name) override;
- lldb_private::Error WillLaunch(lldb_private::Module *module) override;
+ lldb_private::Status WillLaunch(lldb_private::Module *module) override;
- lldb_private::Error DoAttachToProcessWithID(
+ lldb_private::Status DoAttachToProcessWithID(
lldb::pid_t pid,
const lldb_private::ProcessAttachInfo &attach_info) override;
- lldb_private::Error
+ lldb_private::Status
DoLaunch(lldb_private::Module *exe_module,
lldb_private::ProcessLaunchInfo &launch_info) override;
void DidLaunch() override;
- lldb_private::Error DoResume() override;
+ lldb_private::Status DoResume() override;
- lldb_private::Error DoHalt(bool &caused_stop) override;
+ lldb_private::Status DoHalt(bool &caused_stop) override;
- lldb_private::Error DoDetach(bool keep_stopped) override;
+ lldb_private::Status DoDetach(bool keep_stopped) override;
- lldb_private::Error DoSignal(int signal) override;
+ lldb_private::Status DoSignal(int signal) override;
- lldb_private::Error DoDestroy() override;
+ lldb_private::Status DoDestroy() override;
void DoDidExec() override;
@@ -100,35 +94,35 @@ public:
bool IsAlive() override;
size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
- lldb_private::Error DoDeallocateMemory(lldb::addr_t ptr) override;
+ lldb_private::Status DoDeallocateMemory(lldb::addr_t ptr) override;
virtual size_t
GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite *bp_site);
- lldb_private::Error
+ lldb_private::Status
EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
- lldb_private::Error
+ lldb_private::Status
DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
- lldb_private::Error EnableWatchpoint(lldb_private::Watchpoint *wp,
- bool notify = true) override;
-
- lldb_private::Error DisableWatchpoint(lldb_private::Watchpoint *wp,
+ lldb_private::Status EnableWatchpoint(lldb_private::Watchpoint *wp,
bool notify = true) override;
- lldb_private::Error GetWatchpointSupportInfo(uint32_t &num) override;
+ lldb_private::Status DisableWatchpoint(lldb_private::Watchpoint *wp,
+ bool notify = true) override;
- lldb_private::Error GetWatchpointSupportInfo(uint32_t &num,
- bool &after) override;
+ lldb_private::Status GetWatchpointSupportInfo(uint32_t &num) override;
+
+ lldb_private::Status GetWatchpointSupportInfo(uint32_t &num,
+ bool &after) override;
virtual uint32_t UpdateThreadListIfNeeded();
@@ -140,7 +134,7 @@ public:
lldb::addr_t GetImageInfoAddress() override;
size_t PutSTDIN(const char *buf, size_t len,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
const lldb::DataBufferSP GetAuxvData() override;
@@ -171,7 +165,25 @@ public:
virtual FreeBSDThread *CreateNewFreeBSDThread(lldb_private::Process &process,
lldb::tid_t tid);
+ static bool SingleStepBreakpointHit(
+ void *baton, lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+ lldb_private::Status SetupSoftwareSingleStepping(lldb::tid_t tid);
+
+ lldb_private::Status SetSoftwareSingleStepBreakpoint(lldb::tid_t tid,
+ lldb::addr_t addr);
+
+ bool IsSoftwareStepBreakpoint(lldb::tid_t tid);
+
+ bool SupportHardwareSingleStepping() const;
+
+ typedef std::vector<lldb::tid_t> tid_collection;
+ tid_collection &GetStepTids() { return m_step_tids; }
+
protected:
+ static const size_t MAX_TRAP_OPCODE_SIZE = 8;
+
/// Target byte order.
lldb::ByteOrder m_byte_order;
@@ -207,10 +219,10 @@ protected:
friend class FreeBSDThread;
- typedef std::vector<lldb::tid_t> tid_collection;
tid_collection m_suspend_tids;
tid_collection m_run_tids;
tid_collection m_step_tids;
+ std::map<lldb::tid_t, lldb::break_id_t> m_threads_stepping_with_breakpoint;
int m_resume_signo;
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
index afc649d..6291d09 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -21,21 +21,22 @@
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Core/Error.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/UnixSignals.h"
-#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Utility/Status.h"
+#include "llvm/Support/Errno.h"
#include "FreeBSDThread.h"
#include "Plugins/Process/POSIX/CrashReason.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
-#include "ProcessPOSIXLog.h"
extern "C" {
extern char **environ;
@@ -154,7 +155,7 @@ PtraceWrapper((req), (pid), (addr), (data))
// functions without needed to go thru the thread funnel.
static size_t DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf,
- size_t size, Error &error) {
+ size_t size, Status &error) {
struct ptrace_io_desc pi_desc;
pi_desc.piod_op = PIOD_READ_D;
@@ -168,7 +169,7 @@ static size_t DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf,
}
static size_t DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr,
- const void *buf, size_t size, Error &error) {
+ const void *buf, size_t size, Status &error) {
struct ptrace_io_desc pi_desc;
pi_desc.piod_op = PIOD_WRITE_D;
@@ -183,7 +184,7 @@ static size_t DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr,
// Simple helper function to ensure flags are enabled on the given file
// descriptor.
-static bool EnsureFDFlags(int fd, int flags, Error &error) {
+static bool EnsureFDFlags(int fd, int flags, Status &error) {
int status;
if ((status = fcntl(fd, F_GETFL)) == -1) {
@@ -221,7 +222,7 @@ public:
/// @brief Implements ProcessMonitor::ReadMemory.
class ReadOperation : public Operation {
public:
- ReadOperation(lldb::addr_t addr, void *buff, size_t size, Error &error,
+ ReadOperation(lldb::addr_t addr, void *buff, size_t size, Status &error,
size_t &result)
: m_addr(addr), m_buff(buff), m_size(size), m_error(error),
m_result(result) {}
@@ -232,7 +233,7 @@ private:
lldb::addr_t m_addr;
void *m_buff;
size_t m_size;
- Error &m_error;
+ Status &m_error;
size_t &m_result;
};
@@ -247,8 +248,8 @@ void ReadOperation::Execute(ProcessMonitor *monitor) {
/// @brief Implements ProcessMonitor::WriteMemory.
class WriteOperation : public Operation {
public:
- WriteOperation(lldb::addr_t addr, const void *buff, size_t size, Error &error,
- size_t &result)
+ WriteOperation(lldb::addr_t addr, const void *buff, size_t size,
+ Status &error, size_t &result)
: m_addr(addr), m_buff(buff), m_size(size), m_error(error),
m_result(result) {}
@@ -258,7 +259,7 @@ private:
lldb::addr_t m_addr;
const void *m_buff;
size_t m_size;
- Error &m_error;
+ Status &m_error;
size_t &m_result;
};
@@ -529,10 +530,8 @@ void ResumeOperation::Execute(ProcessMonitor *monitor) {
if (PTRACE(PT_CONTINUE, pid, (caddr_t)1, data)) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
-
- if (log)
- log->Printf("ResumeOperation (%" PRIu64 ") failed: %s", pid,
- strerror(errno));
+ LLDB_LOG(log, "ResumeOperation ({0}) failed: {1}", pid,
+ llvm::sys::StrError(errno));
m_result = false;
} else
m_result = true;
@@ -672,12 +671,12 @@ void KillOperation::Execute(ProcessMonitor *monitor) {
/// @brief Implements ProcessMonitor::Detach.
class DetachOperation : public Operation {
public:
- DetachOperation(Error &result) : m_error(result) {}
+ DetachOperation(Status &result) : m_error(result) {}
void Execute(ProcessMonitor *monitor);
private:
- Error &m_error;
+ Status &m_error;
};
void DetachOperation::Execute(ProcessMonitor *monitor) {
@@ -731,7 +730,7 @@ ProcessMonitor::ProcessMonitor(
const FileSpec &stdout_file_spec, const FileSpec &stderr_file_spec,
const FileSpec &working_dir,
const lldb_private::ProcessLaunchInfo & /* launch_info */,
- lldb_private::Error &error)
+ lldb_private::Status &error)
: m_process(static_cast<ProcessFreeBSD *>(process)),
m_pid(LLDB_INVALID_PROCESS_ID), m_terminal_fd(-1), m_operation(0) {
using namespace std::placeholders;
@@ -747,15 +746,9 @@ ProcessMonitor::ProcessMonitor(
if (!error.Success())
return;
-WAIT_AGAIN:
- // Wait for the operation thread to initialize.
- if (sem_wait(&args->m_semaphore)) {
- if (errno == EINTR)
- goto WAIT_AGAIN;
- else {
- error.SetErrorToErrno();
- return;
- }
+ if (llvm::sys::RetryAfterSignal(-1, sem_wait, &args->m_semaphore) == -1) {
+ error.SetErrorToErrno();
+ return;
}
// Check that the launch was a success.
@@ -777,7 +770,7 @@ WAIT_AGAIN:
}
ProcessMonitor::ProcessMonitor(ProcessFreeBSD *process, lldb::pid_t pid,
- lldb_private::Error &error)
+ lldb_private::Status &error)
: m_process(static_cast<ProcessFreeBSD *>(process)), m_pid(pid),
m_terminal_fd(-1), m_operation(0) {
using namespace std::placeholders;
@@ -791,15 +784,9 @@ ProcessMonitor::ProcessMonitor(ProcessFreeBSD *process, lldb::pid_t pid,
if (!error.Success())
return;
-WAIT_AGAIN:
- // Wait for the operation thread to initialize.
- if (sem_wait(&args->m_semaphore)) {
- if (errno == EINTR)
- goto WAIT_AGAIN;
- else {
- error.SetErrorToErrno();
- return;
- }
+ if (llvm::sys::RetryAfterSignal(-1, sem_wait, &args->m_semaphore) == -1) {
+ error.SetErrorToErrno();
+ return;
}
// Check that the attach was a success.
@@ -824,7 +811,7 @@ ProcessMonitor::~ProcessMonitor() { StopMonitor(); }
//------------------------------------------------------------------------------
// Thread setup and tear down.
-void ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error) {
+void ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Status &error) {
static const char *g_thread_name = "lldb.process.freebsd.operation";
if (m_operation_thread.IsJoinable())
@@ -992,7 +979,7 @@ FINISH:
}
void ProcessMonitor::StartAttachOpThread(AttachArgs *args,
- lldb_private::Error &error) {
+ lldb_private::Status &error) {
static const char *g_thread_name = "lldb.process.freebsd.operation";
if (m_operation_thread.IsJoinable())
@@ -1132,6 +1119,10 @@ ProcessMessage ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
case 0:
case TRAP_TRACE:
+#ifdef TRAP_CAP
+ // Map TRAP_CAP to a trace trap in the absense of a more specific handler.
+ case TRAP_CAP:
+#endif
if (log)
log->Printf("ProcessMonitor::%s() received trace event, tid = %" PRIu64
" : si_code = %d",
@@ -1141,11 +1132,19 @@ ProcessMessage ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
case SI_KERNEL:
case TRAP_BRKPT:
- if (log)
- log->Printf(
- "ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64,
- __FUNCTION__, tid);
- message = ProcessMessage::Break(tid);
+ if (monitor->m_process->IsSoftwareStepBreakpoint(tid)) {
+ if (log)
+ log->Printf("ProcessMonitor::%s() received sw single step breakpoint "
+ "event, tid = %" PRIu64,
+ __FUNCTION__, tid);
+ message = ProcessMessage::Trace(tid);
+ } else {
+ if (log)
+ log->Printf(
+ "ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64,
+ __FUNCTION__, tid);
+ message = ProcessMessage::Break(tid);
+ }
break;
}
@@ -1193,7 +1192,9 @@ ProcessMessage ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
case SIGBUS:
lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
const auto reason = GetCrashReason(*info);
- return ProcessMessage::Crash(tid, reason, signo, fault_addr);
+ if (reason != CrashReason::eInvalidCrashReason) {
+ return ProcessMessage::Crash(tid, reason, signo, fault_addr);
+ } // else; Use atleast si_signo info for other si_code
}
// Everything else is "normal" and does not require any special action on
@@ -1232,7 +1233,7 @@ void ProcessMonitor::DoOperation(Operation *op) {
}
size_t ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
- Error &error) {
+ Status &error) {
size_t result;
ReadOperation op(vm_addr, buf, size, error, result);
DoOperation(&op);
@@ -1240,7 +1241,7 @@ size_t ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
}
size_t ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf,
- size_t size, lldb_private::Error &error) {
+ size_t size, lldb_private::Status &error) {
size_t result;
WriteOperation op(vm_addr, buf, size, error, result);
DoOperation(&op);
@@ -1381,8 +1382,8 @@ bool ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message) {
return result;
}
-lldb_private::Error ProcessMonitor::Detach(lldb::tid_t tid) {
- lldb_private::Error error;
+lldb_private::Status ProcessMonitor::Detach(lldb::tid_t tid) {
+ lldb_private::Status error;
if (tid != LLDB_INVALID_THREAD_ID) {
DetachOperation op(error);
DoOperation(&op);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h
index 4c2594e..0963453 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h
@@ -18,12 +18,12 @@
#include <mutex>
// Other libraries and framework includes
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/HostThread.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-types.h"
namespace lldb_private {
-class Error;
+class Status;
class Module;
class Scalar;
} // End lldb_private namespace.
@@ -54,10 +54,10 @@ public:
const lldb_private::FileSpec &stderr_file_spec,
const lldb_private::FileSpec &working_dir,
const lldb_private::ProcessLaunchInfo &launch_info,
- lldb_private::Error &error);
+ lldb_private::Status &error);
ProcessMonitor(ProcessFreeBSD *process, lldb::pid_t pid,
- lldb_private::Error &error);
+ lldb_private::Status &error);
~ProcessMonitor();
@@ -86,14 +86,14 @@ public:
///
/// This method is provided to implement Process::DoReadMemory.
size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
- lldb_private::Error &error);
+ lldb_private::Status &error);
/// Writes @p size bytes from address @p vm_adder in the inferior process
/// address space.
///
/// This method is provided to implement Process::DoWriteMemory.
size_t WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
- lldb_private::Error &error);
+ lldb_private::Status &error);
/// Reads the contents from the register identified by the given (architecture
/// dependent) offset.
@@ -178,7 +178,7 @@ public:
/// Terminate the traced process.
bool Kill();
- lldb_private::Error Detach(lldb::tid_t tid);
+ lldb_private::Status Detach(lldb::tid_t tid);
void StopMonitor();
@@ -210,7 +210,7 @@ private:
ProcessMonitor *m_monitor; // The monitor performing the attach.
sem_t m_semaphore; // Posted to once operation complete.
- lldb_private::Error m_error; // Set if process operation failed.
+ lldb_private::Status m_error; // Set if process operation failed.
};
/// @class LauchArgs
@@ -238,7 +238,7 @@ private:
const lldb_private::FileSpec m_working_dir; // Working directory or empty.
};
- void StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error);
+ void StartLaunchOpThread(LaunchArgs *args, lldb_private::Status &error);
static void *LaunchOpThread(void *arg);
@@ -252,7 +252,7 @@ private:
lldb::pid_t m_pid; // pid of the process to be attached.
};
- void StartAttachOpThread(AttachArgs *args, lldb_private::Error &error);
+ void StartAttachOpThread(AttachArgs *args, lldb_private::Status &error);
static void *AttachOpThread(void *args);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
index f8d5f2e..59d42b9 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
@@ -7,9 +7,9 @@
//
//===---------------------------------------------------------------------===//
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
@@ -75,7 +75,7 @@ bool RegisterContextPOSIXProcessMonitor_arm::WriteRegister(
// Read the full register.
if (ReadRegister(full_reg_info, full_value)) {
- Error error;
+ Status error;
ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
index 98a213a..93ffeb5 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
@@ -7,9 +7,9 @@
//
//===---------------------------------------------------------------------===//
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
#include "ProcessFreeBSD.h"
@@ -77,7 +77,7 @@ bool RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(
// Read the full register.
if (ReadRegister(full_reg_info, full_value)) {
- lldb_private::Error error;
+ lldb_private::Status error;
lldb::ByteOrder byte_order = GetByteOrder();
uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize];
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp
index 020636e..b911ee2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp
@@ -7,9 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
#include "ProcessFreeBSD.h"
@@ -76,7 +76,7 @@ bool RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(
// Read the full register.
if (ReadRegister(full_reg_info, full_value)) {
- Error error;
+ Status error;
ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
index 2f75e60..6f57b0d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
@@ -11,6 +11,7 @@
#define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_
#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
+#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h"
#include "RegisterContextPOSIX.h"
class RegisterContextPOSIXProcessMonitor_mips64
@@ -72,6 +73,8 @@ protected:
uint32_t NumSupportedHardwareWatchpoints();
private:
+ uint64_t
+ m_gpr_mips64[k_num_gpr_registers_mips64]; // general purpose registers.
ProcessMonitor &GetMonitor();
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp
index e7b01fa..bc1d4df 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp
@@ -7,9 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
@@ -88,7 +88,7 @@ bool RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(
// Read the full register.
if (ReadRegister(full_reg_info, full_value)) {
- Error error;
+ Status error;
ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp
index 976b190..1cd8f1a 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp
@@ -7,9 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "Plugins/Process/FreeBSD/ProcessFreeBSD.h"
#include "Plugins/Process/FreeBSD/ProcessMonitor.h"
@@ -130,7 +130,7 @@ bool RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(
// Read the full register.
if (ReadRegister(full_reg_info, full_value)) {
- Error error;
+ Status error;
ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/CMakeLists.txt
new file mode 100644
index 0000000..5b2cef8
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/CMakeLists.txt
@@ -0,0 +1,21 @@
+include_directories(.)
+include_directories(../POSIX)
+include_directories(../Utility)
+
+add_lldb_library(lldbPluginProcessNetBSD PLUGIN
+ NativeProcessNetBSD.cpp
+ NativeRegisterContextNetBSD.cpp
+ NativeRegisterContextNetBSD_x86_64.cpp
+ NativeThreadNetBSD.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbHost
+ lldbSymbol
+ lldbTarget
+ lldbUtility
+ lldbPluginProcessPOSIX
+ lldbPluginProcessUtility
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
new file mode 100644
index 0000000..388989a
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -0,0 +1,939 @@
+//===-- NativeProcessNetBSD.cpp ------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessNetBSD.h"
+
+// C Includes
+
+// C++ Includes
+
+// Other libraries and framework includes
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/common/NativeBreakpoint.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
+#include "lldb/Target/Process.h"
+#include "llvm/Support/Errno.h"
+
+// System includes - They have to be included after framework includes because
+// they define some
+// macros which collide with variable names in other modules
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <uvm/uvm_prot.h>
+#include <elf.h>
+#include <util.h>
+// clang-format on
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_netbsd;
+using namespace llvm;
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Status EnsureFDFlags(int fd, int flags) {
+ Status error;
+
+ int status = fcntl(fd, F_GETFL);
+ if (status == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ return error;
+}
+
+// -----------------------------------------------------------------------------
+// Public Static Methods
+// -----------------------------------------------------------------------------
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate,
+ MainLoop &mainloop) const {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+ Status status;
+ ::pid_t pid = ProcessLauncherPosixFork()
+ .LaunchProcess(launch_info, status)
+ .GetProcessId();
+ LLDB_LOG(log, "pid = {0:x}", pid);
+ if (status.Fail()) {
+ LLDB_LOG(log, "failed to launch process: {0}", status);
+ return status.ToError();
+ }
+
+ // Wait for the child process to trap on its call to execve.
+ int wstatus;
+ ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
+ assert(wpid == pid);
+ (void)wpid;
+ if (!WIFSTOPPED(wstatus)) {
+ LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
+ WaitStatus::Decode(wstatus));
+ return llvm::make_error<StringError>("Could not sync with inferior process",
+ llvm::inconvertibleErrorCode());
+ }
+ LLDB_LOG(log, "inferior started, now in stopped state");
+
+ ArchSpec arch;
+ if ((status = ResolveProcessArchitecture(pid, arch)).Fail())
+ return status.ToError();
+
+ // Set the architecture to the exe architecture.
+ LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
+ arch.GetArchitectureName());
+
+ std::unique_ptr<NativeProcessNetBSD> process_up(new NativeProcessNetBSD(
+ pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate,
+ arch, mainloop));
+
+ status = process_up->ReinitializeThreads();
+ if (status.Fail())
+ return status.ToError();
+
+ for (const auto &thread_sp : process_up->m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
+ SIGSTOP);
+ }
+ process_up->SetState(StateType::eStateStopped);
+
+ return std::move(process_up);
+}
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessNetBSD::Factory::Attach(
+ lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
+ MainLoop &mainloop) const {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ LLDB_LOG(log, "pid = {0:x}", pid);
+
+ // Retrieve the architecture for the running process.
+ ArchSpec arch;
+ Status status = ResolveProcessArchitecture(pid, arch);
+ if (!status.Success())
+ return status.ToError();
+
+ std::unique_ptr<NativeProcessNetBSD> process_up(
+ new NativeProcessNetBSD(pid, -1, native_delegate, arch, mainloop));
+
+ status = process_up->Attach();
+ if (!status.Success())
+ return status.ToError();
+
+ return std::move(process_up);
+}
+
+// -----------------------------------------------------------------------------
+// Public Instance Methods
+// -----------------------------------------------------------------------------
+
+NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd,
+ NativeDelegate &delegate,
+ const ArchSpec &arch,
+ MainLoop &mainloop)
+ : NativeProcessProtocol(pid, terminal_fd, delegate), m_arch(arch) {
+ if (m_terminal_fd != -1) {
+ Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
+ assert(status.Success());
+ }
+
+ Status status;
+ m_sigchld_handle = mainloop.RegisterSignal(
+ SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
+ assert(m_sigchld_handle && status.Success());
+}
+
+// Handles all waitpid events from the inferior process.
+void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
+ switch (signal) {
+ case SIGTRAP:
+ return MonitorSIGTRAP(pid);
+ case SIGSTOP:
+ return MonitorSIGSTOP(pid);
+ default:
+ return MonitorSignal(pid, signal);
+ }
+}
+
+void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+ LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
+
+ /* Stop Tracking All Threads attached to Process */
+ m_threads.clear();
+
+ SetExitStatus(status, true);
+
+ // Notify delegate that our process has exited.
+ SetState(StateType::eStateExited, true);
+}
+
+void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {
+ ptrace_siginfo_t info;
+
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+
+ // Get details on the signal raised.
+ if (siginfo_err.Success()) {
+ // Handle SIGSTOP from LLGS (LLDB GDB Server)
+ if (info.psi_siginfo.si_code == SI_USER &&
+ info.psi_siginfo.si_pid == ::getpid()) {
+ /* Stop Tracking All Threads attached to Process */
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
+ SIGSTOP, &info.psi_siginfo);
+ }
+ }
+ }
+}
+
+void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ ptrace_siginfo_t info;
+
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+
+ // Get details on the signal raised.
+ if (siginfo_err.Fail()) {
+ return;
+ }
+
+ switch (info.psi_siginfo.si_code) {
+ case TRAP_BRKPT:
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)
+ ->SetStoppedByBreakpoint();
+ FixupBreakpointPCAsNeeded(
+ *static_pointer_cast<NativeThreadNetBSD>(thread_sp));
+ }
+ SetState(StateType::eStateStopped, true);
+ break;
+ case TRAP_TRACE:
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedByTrace();
+ }
+ SetState(StateType::eStateStopped, true);
+ break;
+ case TRAP_EXEC: {
+ Status error = ReinitializeThreads();
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ // Let our delegate know we have just exec'd.
+ NotifyDidExec();
+
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedByExec();
+ }
+ SetState(StateType::eStateStopped, true);
+ } break;
+ case TRAP_DBREG: {
+ // If a watchpoint was hit, report it
+ uint32_t wp_index;
+ Status error =
+ static_pointer_cast<NativeThreadNetBSD>(m_threads[info.psi_lwpid])
+ ->GetRegisterContext()
+ ->GetWatchpointHitIndex(wp_index,
+ (uintptr_t)info.psi_siginfo.si_addr);
+ if (error.Fail())
+ LLDB_LOG(log,
+ "received error while checking for watchpoint hits, pid = "
+ "{0}, LWP = {1}, error = {2}",
+ GetID(), info.psi_lwpid, error);
+ if (wp_index != LLDB_INVALID_INDEX32) {
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)
+ ->SetStoppedByWatchpoint(wp_index);
+ }
+ SetState(StateType::eStateStopped, true);
+ break;
+ }
+
+ // If a breakpoint was hit, report it
+ uint32_t bp_index;
+ error = static_pointer_cast<NativeThreadNetBSD>(m_threads[info.psi_lwpid])
+ ->GetRegisterContext()
+ ->GetHardwareBreakHitIndex(bp_index,
+ (uintptr_t)info.psi_siginfo.si_addr);
+ if (error.Fail())
+ LLDB_LOG(log,
+ "received error while checking for hardware "
+ "breakpoint hits, pid = {0}, LWP = {1}, error = {2}",
+ GetID(), info.psi_lwpid, error);
+ if (bp_index != LLDB_INVALID_INDEX32) {
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)
+ ->SetStoppedByBreakpoint();
+ }
+ SetState(StateType::eStateStopped, true);
+ break;
+ }
+ } break;
+ }
+}
+
+void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
+ ptrace_siginfo_t info;
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
+ info.psi_siginfo.si_signo, &info.psi_siginfo);
+ }
+ SetState(StateType::eStateStopped, true);
+}
+
+Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
+ int data, int *result) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ Status error;
+ int ret;
+
+ errno = 0;
+ ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);
+
+ if (ret == -1)
+ error.SetErrorToErrno();
+
+ if (result)
+ *result = ret;
+
+ LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
+
+ if (error.Fail())
+ LLDB_LOG(log, "ptrace() failed: {0}", error);
+
+ return error;
+}
+
+Status NativeProcessNetBSD::GetSoftwareBreakpointPCOffset(
+ uint32_t &actual_opcode_size) {
+ // FIXME put this behind a breakpoint protocol class that can be
+ // set per architecture. Need ARM, MIPS support here.
+ static const uint8_t g_i386_opcode[] = {0xCC};
+ switch (m_arch.GetMachine()) {
+ case llvm::Triple::x86_64:
+ actual_opcode_size = static_cast<uint32_t>(sizeof(g_i386_opcode));
+ return Status();
+ default:
+ assert(false && "CPU type not supported!");
+ return Status("CPU type not supported");
+ }
+}
+
+Status
+NativeProcessNetBSD::FixupBreakpointPCAsNeeded(NativeThreadNetBSD &thread) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
+ Status error;
+ // Find out the size of a breakpoint (might depend on where we are in the
+ // code).
+ NativeRegisterContextSP context_sp = thread.GetRegisterContext();
+ if (!context_sp) {
+ error.SetErrorString("cannot get a NativeRegisterContext for the thread");
+ LLDB_LOG(log, "failed: {0}", error);
+ return error;
+ }
+ uint32_t breakpoint_size = 0;
+ error = GetSoftwareBreakpointPCOffset(breakpoint_size);
+ if (error.Fail()) {
+ LLDB_LOG(log, "GetBreakpointSize() failed: {0}", error);
+ return error;
+ } else
+ LLDB_LOG(log, "breakpoint size: {0}", breakpoint_size);
+ // First try probing for a breakpoint at a software breakpoint location: PC
+ // - breakpoint size.
+ const lldb::addr_t initial_pc_addr =
+ context_sp->GetPCfromBreakpointLocation();
+ lldb::addr_t breakpoint_addr = initial_pc_addr;
+ if (breakpoint_size > 0) {
+ // Do not allow breakpoint probe to wrap around.
+ if (breakpoint_addr >= breakpoint_size)
+ breakpoint_addr -= breakpoint_size;
+ }
+ // Check if we stopped because of a breakpoint.
+ NativeBreakpointSP breakpoint_sp;
+ error = m_breakpoint_list.GetBreakpoint(breakpoint_addr, breakpoint_sp);
+ if (!error.Success() || !breakpoint_sp) {
+ // We didn't find one at a software probe location. Nothing to do.
+ LLDB_LOG(log,
+ "pid {0} no lldb breakpoint found at current pc with "
+ "adjustment: {1}",
+ GetID(), breakpoint_addr);
+ return Status();
+ }
+ // If the breakpoint is not a software breakpoint, nothing to do.
+ if (!breakpoint_sp->IsSoftwareBreakpoint()) {
+ LLDB_LOG(
+ log,
+ "pid {0} breakpoint found at {1:x}, not software, nothing to adjust",
+ GetID(), breakpoint_addr);
+ return Status();
+ }
+ //
+ // We have a software breakpoint and need to adjust the PC.
+ //
+ // Sanity check.
+ if (breakpoint_size == 0) {
+ // Nothing to do! How did we get here?
+ LLDB_LOG(log,
+ "pid {0} breakpoint found at {1:x}, it is software, but the "
+ "size is zero, nothing to do (unexpected)",
+ GetID(), breakpoint_addr);
+ return Status();
+ }
+ //
+ // We have a software breakpoint and need to adjust the PC.
+ //
+ // Sanity check.
+ if (breakpoint_size == 0) {
+ // Nothing to do! How did we get here?
+ LLDB_LOG(log,
+ "pid {0} breakpoint found at {1:x}, it is software, but the "
+ "size is zero, nothing to do (unexpected)",
+ GetID(), breakpoint_addr);
+ return Status();
+ }
+ // Change the program counter.
+ LLDB_LOG(log, "pid {0} tid {1}: changing PC from {2:x} to {3:x}", GetID(),
+ thread.GetID(), initial_pc_addr, breakpoint_addr);
+ error = context_sp->SetPC(breakpoint_addr);
+ if (error.Fail()) {
+ LLDB_LOG(log, "pid {0} tid {1}: failed to set PC: {2}", GetID(),
+ thread.GetID(), error);
+ return error;
+ }
+ return error;
+}
+
+Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ const auto &thread_sp = m_threads[0];
+ const ResumeAction *const action =
+ resume_actions.GetActionForThread(thread_sp->GetID(), true);
+
+ if (action == nullptr) {
+ LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
+ thread_sp->GetID());
+ return Status();
+ }
+
+ Status error;
+
+ switch (action->state) {
+ case eStateRunning: {
+ // Run the thread, possibly feeding it the signal.
+ error = NativeProcessNetBSD::PtraceWrapper(PT_CONTINUE, GetID(), (void *)1,
+ action->signal);
+ if (!error.Success())
+ return error;
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetRunning();
+ }
+ SetState(eStateRunning, true);
+ break;
+ }
+ case eStateStepping:
+ // Run the thread, possibly feeding it the signal.
+ error = NativeProcessNetBSD::PtraceWrapper(PT_STEP, GetID(), (void *)1,
+ action->signal);
+ if (!error.Success())
+ return error;
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStepping();
+ }
+ SetState(eStateStepping, true);
+ break;
+
+ case eStateSuspended:
+ case eStateStopped:
+ llvm_unreachable("Unexpected state");
+
+ default:
+ return Status("NativeProcessNetBSD::%s (): unexpected state %s specified "
+ "for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString(action->state), GetID(),
+ thread_sp->GetID());
+ }
+
+ return Status();
+}
+
+Status NativeProcessNetBSD::Halt() {
+ Status error;
+
+ if (kill(GetID(), SIGSTOP) != 0)
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Status NativeProcessNetBSD::Detach() {
+ Status error;
+
+ // Stop monitoring the inferior.
+ m_sigchld_handle.reset();
+
+ // Tell ptrace to detach from the process.
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ return error;
+
+ return PtraceWrapper(PT_DETACH, GetID());
+}
+
+Status NativeProcessNetBSD::Signal(int signo) {
+ Status error;
+
+ if (kill(GetID(), signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Status NativeProcessNetBSD::Kill() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Status error;
+
+ switch (m_state) {
+ case StateType::eStateInvalid:
+ case StateType::eStateExited:
+ case StateType::eStateCrashed:
+ case StateType::eStateDetached:
+ case StateType::eStateUnloaded:
+ // Nothing to do - the process is already dead.
+ LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
+ StateAsCString(m_state));
+ return error;
+
+ case StateType::eStateConnected:
+ case StateType::eStateAttaching:
+ case StateType::eStateLaunching:
+ case StateType::eStateStopped:
+ case StateType::eStateRunning:
+ case StateType::eStateStepping:
+ case StateType::eStateSuspended:
+ // We can try to kill a process in these states.
+ break;
+ }
+
+ if (kill(GetID(), SIGKILL) != 0) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ return error;
+}
+
+Status NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+
+ if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
+ // We're done.
+ return Status("unsupported");
+ }
+
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail()) {
+ return error;
+ }
+
+ lldb::addr_t prev_base_address = 0;
+ // FIXME start by finding the last region that is <= target address using
+ // binary search. Data is sorted.
+ // There can be a ton of regions on pthreads apps with lots of threads.
+ for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
+ ++it) {
+ MemoryRegionInfo &proc_entry_info = it->first;
+ // Sanity check assumption that memory map entries are ascending.
+ assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
+ "descending memory map entries detected, unexpected");
+ prev_base_address = proc_entry_info.GetRange().GetRangeBase();
+ UNUSED_IF_ASSERT_DISABLED(prev_base_address);
+ // If the target address comes before this entry, indicate distance to
+ // next region.
+ if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
+ range_info.GetRange().SetRangeBase(load_addr);
+ range_info.GetRange().SetByteSize(
+ proc_entry_info.GetRange().GetRangeBase() - load_addr);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+ } else if (proc_entry_info.GetRange().Contains(load_addr)) {
+ // The target address is within the memory region we're processing here.
+ range_info = proc_entry_info;
+ return error;
+ }
+ // The target memory address comes somewhere after the region we just
+ // parsed.
+ }
+ // If we made it here, we didn't find an entry that contained the given
+ // address. Return the
+ // load_addr as start and the amount of bytes betwwen load address and the
+ // end of the memory as size.
+ range_info.GetRange().SetRangeBase(load_addr);
+ range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+}
+
+Status NativeProcessNetBSD::PopulateMemoryRegionCache() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ // If our cache is empty, pull the latest. There should always be at least
+ // one memory region if memory region handling is supported.
+ if (!m_mem_region_cache.empty()) {
+ LLDB_LOG(log, "reusing {0} cached memory region entries",
+ m_mem_region_cache.size());
+ return Status();
+ }
+
+ struct kinfo_vmentry *vm;
+ size_t count, i;
+ vm = kinfo_getvmmap(GetID(), &count);
+ if (vm == NULL) {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ Status error;
+ error.SetErrorString("not supported");
+ return error;
+ }
+ for (i = 0; i < count; i++) {
+ MemoryRegionInfo info;
+ info.Clear();
+ info.GetRange().SetRangeBase(vm[i].kve_start);
+ info.GetRange().SetRangeEnd(vm[i].kve_end);
+ info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+
+ if (vm[i].kve_protection & VM_PROT_READ)
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (vm[i].kve_protection & VM_PROT_WRITE)
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (vm[i].kve_protection & VM_PROT_EXECUTE)
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (vm[i].kve_path[0])
+ info.SetName(vm[i].kve_path);
+
+ m_mem_region_cache.emplace_back(
+ info, FileSpec(info.GetName().GetCString(), true));
+ }
+ free(vm);
+
+ if (m_mem_region_cache.empty()) {
+ // No entries after attempting to read them. This shouldn't happen.
+ // Assume we don't support map entries.
+ LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
+ "for memory region metadata retrieval");
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ Status error;
+ error.SetErrorString("not supported");
+ return error;
+ }
+ LLDB_LOG(log, "read {0} memory region entries from process {1}",
+ m_mem_region_cache.size(), GetID());
+ // We support memory retrieval, remember that.
+ m_supports_mem_region = LazyBool::eLazyBoolYes;
+ return Status();
+}
+
+Status NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions,
+ lldb::addr_t &addr) {
+ return Status("Unimplemented");
+}
+
+Status NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) {
+ return Status("Unimplemented");
+}
+
+lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
+ // punt on this for now
+ return LLDB_INVALID_ADDRESS;
+}
+
+size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }
+
+bool NativeProcessNetBSD::GetArchitecture(ArchSpec &arch) const {
+ arch = m_arch;
+ return true;
+}
+
+Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) {
+ if (hardware)
+ return Status("NativeProcessNetBSD does not support hardware breakpoints");
+ else
+ return SetSoftwareBreakpoint(addr, size);
+}
+
+Status NativeProcessNetBSD::GetSoftwareBreakpointTrapOpcode(
+ size_t trap_opcode_size_hint, size_t &actual_opcode_size,
+ const uint8_t *&trap_opcode_bytes) {
+ static const uint8_t g_i386_opcode[] = {0xCC};
+
+ switch (m_arch.GetMachine()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ trap_opcode_bytes = g_i386_opcode;
+ actual_opcode_size = sizeof(g_i386_opcode);
+ return Status();
+ default:
+ assert(false && "CPU type not supported!");
+ return Status("CPU type not supported");
+ }
+}
+
+Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) {
+ return Status("Unimplemented");
+}
+
+Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) {
+ load_addr = LLDB_INVALID_ADDRESS;
+ return Status();
+}
+
+void NativeProcessNetBSD::SigchldHandler() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ // Process all pending waitpid notifications.
+ int status;
+ ::pid_t wait_pid =
+ llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WALLSIG | WNOHANG);
+
+ if (wait_pid == 0)
+ return; // We are done.
+
+ if (wait_pid == -1) {
+ Status error(errno, eErrorTypePOSIX);
+ LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
+ }
+
+ WaitStatus wait_status = WaitStatus::Decode(status);
+ bool exited = wait_status.type == WaitStatus::Exit ||
+ (wait_status.type == WaitStatus::Signal &&
+ wait_pid == static_cast<::pid_t>(GetID()));
+
+ LLDB_LOG(log,
+ "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
+ GetID(), wait_pid, status, exited);
+
+ if (exited)
+ MonitorExited(wait_pid, wait_status);
+ else {
+ assert(wait_status.type == WaitStatus::Stop);
+ MonitorCallback(wait_pid, wait_status.status);
+ }
+}
+
+bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {
+ for (auto thread_sp : m_threads) {
+ assert(thread_sp && "thread list should not contain NULL threads");
+ if (thread_sp->GetID() == thread_id) {
+ // We have this thread.
+ return true;
+ }
+ }
+
+ // We don't have this thread.
+ return false;
+}
+
+NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
+
+ assert(!HasThreadNoLock(thread_id) &&
+ "attempted to add a thread by id that already exists");
+
+ // If this is the first thread, save it as the current thread
+ if (m_threads.empty())
+ SetCurrentThreadID(thread_id);
+
+ auto thread_sp = std::make_shared<NativeThreadNetBSD>(*this, thread_id);
+ m_threads.push_back(thread_sp);
+ return thread_sp;
+}
+
+Status NativeProcessNetBSD::Attach() {
+ // Attach to the requested process.
+ // An attach will cause the thread to stop with a SIGSTOP.
+ Status status = PtraceWrapper(PT_ATTACH, m_pid);
+ if (status.Fail())
+ return status;
+
+ int wstatus;
+ // Need to use WALLSIG otherwise we receive an error with errno=ECHLD
+ // At this point we should have a thread stopped if waitpid succeeds.
+ if ((wstatus = waitpid(m_pid, NULL, WALLSIG)) < 0)
+ return Status(errno, eErrorTypePOSIX);
+
+ /* Initialize threads */
+ status = ReinitializeThreads();
+ if (status.Fail())
+ return status;
+
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
+ SIGSTOP);
+ }
+
+ // Let our process instance know the thread has stopped.
+ SetState(StateType::eStateStopped);
+ return Status();
+}
+
+Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf,
+ size_t size, size_t &bytes_read) {
+ unsigned char *dst = static_cast<unsigned char *>(buf);
+ struct ptrace_io_desc io;
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_read = 0;
+ io.piod_op = PIOD_READ_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_offs = (void *)(addr + bytes_read);
+ io.piod_addr = dst + bytes_read;
+
+ Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail())
+ return error;
+
+ bytes_read = io.piod_len;
+ io.piod_len = size - bytes_read;
+ } while (bytes_read < size);
+
+ return Status();
+}
+
+Status NativeProcessNetBSD::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf,
+ size_t size,
+ size_t &bytes_read) {
+ Status error = ReadMemory(addr, buf, size, bytes_read);
+ if (error.Fail())
+ return error;
+ return m_breakpoint_list.RemoveTrapsFromBuffer(addr, buf, size);
+}
+
+Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,
+ size_t size, size_t &bytes_written) {
+ const unsigned char *src = static_cast<const unsigned char *>(buf);
+ Status error;
+ struct ptrace_io_desc io;
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_written = 0;
+ io.piod_op = PIOD_WRITE_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_addr = const_cast<void *>(static_cast<const void *>(src + bytes_written));
+ io.piod_offs = (void *)(addr + bytes_written);
+
+ Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail())
+ return error;
+
+ bytes_written = io.piod_len;
+ io.piod_len = size - bytes_written;
+ } while (bytes_written < size);
+
+ return error;
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+NativeProcessNetBSD::GetAuxvData() const {
+ /*
+ * ELF_AUX_ENTRIES is currently restricted to kernel
+ * (<sys/exec_elf.h> r. 1.155 specifies 15)
+ *
+ * ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this
+ * information isn't needed.
+ */
+ size_t auxv_size = 100 * sizeof(AuxInfo);
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> buf =
+ llvm::MemoryBuffer::getNewMemBuffer(auxv_size);
+
+ struct ptrace_io_desc io;
+ io.piod_op = PIOD_READ_AUXV;
+ io.piod_offs = 0;
+ io.piod_addr = const_cast<void *>(static_cast<const void *>(buf.get()->getBufferStart()));
+ io.piod_len = auxv_size;
+
+ Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
+
+ if (error.Fail())
+ return std::error_code(error.GetError(), std::generic_category());
+
+ if (io.piod_len < 1)
+ return std::error_code(ECANCELED, std::generic_category());
+
+ return buf;
+}
+
+Status NativeProcessNetBSD::ReinitializeThreads() {
+ // Clear old threads
+ m_threads.clear();
+
+ // Initialize new thread
+ struct ptrace_lwpinfo info = {};
+ Status error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info));
+ if (error.Fail()) {
+ return error;
+ }
+ // Reinitialize from scratch threads and register them in process
+ while (info.pl_lwpid != 0) {
+ NativeThreadNetBSDSP thread_sp = AddThread(info.pl_lwpid);
+ error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info));
+ if (error.Fail()) {
+ return error;
+ }
+ }
+
+ return error;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
new file mode 100644
index 0000000..2cbd5e3
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -0,0 +1,144 @@
+//===-- NativeProcessNetBSD.h --------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeProcessNetBSD_H_
+#define liblldb_NativeProcessNetBSD_H_
+
+// C++ Includes
+
+// Other libraries and framework includes
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/FileSpec.h"
+
+#include "NativeThreadNetBSD.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
+namespace lldb_private {
+namespace process_netbsd {
+/// @class NativeProcessNetBSD
+/// @brief Manages communication with the inferior (debugee) process.
+///
+/// Upon construction, this class prepares and launches an inferior process for
+/// debugging.
+///
+/// Changes in the inferior process state are broadcasted.
+class NativeProcessNetBSD : public NativeProcessProtocol {
+public:
+ class Factory : public NativeProcessProtocol::Factory {
+ public:
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
+ MainLoop &mainloop) const override;
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
+ MainLoop &mainloop) const override;
+ };
+
+ // ---------------------------------------------------------------------
+ // NativeProcessProtocol Interface
+ // ---------------------------------------------------------------------
+ Status Resume(const ResumeActionList &resume_actions) override;
+
+ Status Halt() override;
+
+ Status Detach() override;
+
+ Status Signal(int signo) override;
+
+ Status Kill() override;
+
+ Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
+
+ Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
+
+ Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ size_t &bytes_written) override;
+
+ Status AllocateMemory(size_t size, uint32_t permissions,
+ lldb::addr_t &addr) override;
+
+ Status DeallocateMemory(lldb::addr_t addr) override;
+
+ lldb::addr_t GetSharedLibraryInfoAddress() override;
+
+ size_t UpdateThreads() override;
+
+ bool GetArchitecture(ArchSpec &arch) const override;
+
+ Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) override;
+
+ Status GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) override;
+
+ Status GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) override;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ GetAuxvData() const override;
+
+ // ---------------------------------------------------------------------
+ // Interface used by NativeRegisterContext-derived classes.
+ // ---------------------------------------------------------------------
+ static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
+ int data = 0, int *result = nullptr);
+
+protected:
+ // ---------------------------------------------------------------------
+ // NativeProcessProtocol protected interface
+ // ---------------------------------------------------------------------
+
+ Status
+ GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint,
+ size_t &actual_opcode_size,
+ const uint8_t *&trap_opcode_bytes) override;
+
+private:
+ MainLoop::SignalHandleUP m_sigchld_handle;
+ ArchSpec m_arch;
+ LazyBool m_supports_mem_region = eLazyBoolCalculate;
+ std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
+
+ // ---------------------------------------------------------------------
+ // Private Instance Methods
+ // ---------------------------------------------------------------------
+ NativeProcessNetBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
+ const ArchSpec &arch, MainLoop &mainloop);
+
+ bool HasThreadNoLock(lldb::tid_t thread_id);
+
+ NativeThreadNetBSDSP AddThread(lldb::tid_t thread_id);
+
+ void MonitorCallback(lldb::pid_t pid, int signal);
+ void MonitorExited(lldb::pid_t pid, WaitStatus status);
+ void MonitorSIGSTOP(lldb::pid_t pid);
+ void MonitorSIGTRAP(lldb::pid_t pid);
+ void MonitorSignal(lldb::pid_t pid, int signal);
+
+ Status GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size);
+ Status FixupBreakpointPCAsNeeded(NativeThreadNetBSD &thread);
+ Status PopulateMemoryRegionCache();
+ void SigchldHandler();
+
+ Status Attach();
+ Status ReinitializeThreads();
+};
+
+} // namespace process_netbsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeProcessNetBSD_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
new file mode 100644
index 0000000..dde8688
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
@@ -0,0 +1,112 @@
+//===-- NativeRegisterContextNetBSD.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextNetBSD.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_netbsd;
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+// clang-format on
+
+NativeRegisterContextNetBSD::NativeRegisterContextNetBSD(
+ NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx,
+ RegisterInfoInterface *reg_info_interface_p)
+ : NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx,
+ reg_info_interface_p) {}
+
+Status NativeRegisterContextNetBSD::ReadGPR() {
+ void *buf = GetGPRBuffer();
+ if (!buf)
+ return Status("GPR buffer is NULL");
+
+ return DoReadGPR(buf);
+}
+
+Status NativeRegisterContextNetBSD::WriteGPR() {
+ void *buf = GetGPRBuffer();
+ if (!buf)
+ return Status("GPR buffer is NULL");
+
+ return DoWriteGPR(buf);
+}
+
+Status NativeRegisterContextNetBSD::ReadFPR() {
+ void *buf = GetFPRBuffer();
+ if (!buf)
+ return Status("FPR buffer is NULL");
+
+ return DoReadFPR(buf);
+}
+
+Status NativeRegisterContextNetBSD::WriteFPR() {
+ void *buf = GetFPRBuffer();
+ if (!buf)
+ return Status("FPR buffer is NULL");
+
+ return DoWriteFPR(buf);
+}
+
+Status NativeRegisterContextNetBSD::ReadDBR() {
+ void *buf = GetDBRBuffer();
+ if (!buf)
+ return Status("DBR buffer is NULL");
+
+ return DoReadDBR(buf);
+}
+
+Status NativeRegisterContextNetBSD::WriteDBR() {
+ void *buf = GetDBRBuffer();
+ if (!buf)
+ return Status("DBR buffer is NULL");
+
+ return DoWriteDBR(buf);
+}
+
+Status NativeRegisterContextNetBSD::DoReadGPR(void *buf) {
+ return NativeProcessNetBSD::PtraceWrapper(PT_GETREGS, GetProcessPid(), buf,
+ m_thread.GetID());
+}
+
+Status NativeRegisterContextNetBSD::DoWriteGPR(void *buf) {
+ return NativeProcessNetBSD::PtraceWrapper(PT_SETREGS, GetProcessPid(), buf,
+ m_thread.GetID());
+}
+
+Status NativeRegisterContextNetBSD::DoReadFPR(void *buf) {
+ return NativeProcessNetBSD::PtraceWrapper(PT_GETFPREGS, GetProcessPid(), buf,
+ m_thread.GetID());
+}
+
+Status NativeRegisterContextNetBSD::DoWriteFPR(void *buf) {
+ return NativeProcessNetBSD::PtraceWrapper(PT_SETFPREGS, GetProcessPid(), buf,
+ m_thread.GetID());
+}
+
+Status NativeRegisterContextNetBSD::DoReadDBR(void *buf) {
+ return NativeProcessNetBSD::PtraceWrapper(PT_GETDBREGS, GetProcessPid(), buf,
+ m_thread.GetID());
+}
+
+Status NativeRegisterContextNetBSD::DoWriteDBR(void *buf) {
+ return NativeProcessNetBSD::PtraceWrapper(PT_SETDBREGS, GetProcessPid(), buf,
+ m_thread.GetID());
+}
+
+NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() {
+ return static_cast<NativeProcessNetBSD &>(m_thread.GetProcess());
+}
+
+::pid_t NativeRegisterContextNetBSD::GetProcessPid() {
+ return GetProcess().GetID();
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
new file mode 100644
index 0000000..d96b7ae
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
@@ -0,0 +1,74 @@
+//===-- NativeRegisterContextNetBSD.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextNetBSD_h
+#define lldb_NativeRegisterContextNetBSD_h
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+namespace lldb_private {
+namespace process_netbsd {
+
+class NativeRegisterContextNetBSD : public NativeRegisterContextRegisterInfo {
+public:
+ NativeRegisterContextNetBSD(NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *reg_info_interface_p);
+
+ // This function is implemented in the NativeRegisterContextNetBSD_*
+ // subclasses to create a new instance of the host specific
+ // NativeRegisterContextNetBSD. The implementations can't collide as only one
+ // NativeRegisterContextNetBSD_* variant should be compiled into the final
+ // executable.
+ static NativeRegisterContextNetBSD *
+ CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx);
+
+protected:
+ virtual Status ReadGPR();
+ virtual Status WriteGPR();
+
+ virtual Status ReadFPR();
+ virtual Status WriteFPR();
+
+ virtual Status ReadDBR();
+ virtual Status WriteDBR();
+
+ virtual void *GetGPRBuffer() { return nullptr; }
+ virtual size_t GetGPRSize() {
+ return GetRegisterInfoInterface().GetGPRSize();
+ }
+
+ virtual void *GetFPRBuffer() { return nullptr; }
+ virtual size_t GetFPRSize() { return 0; }
+
+ virtual void *GetDBRBuffer() { return nullptr; }
+ virtual size_t GetDBRSize() { return 0; }
+
+ virtual Status DoReadGPR(void *buf);
+ virtual Status DoWriteGPR(void *buf);
+
+ virtual Status DoReadFPR(void *buf);
+ virtual Status DoWriteFPR(void *buf);
+
+ virtual Status DoReadDBR(void *buf);
+ virtual Status DoWriteDBR(void *buf);
+
+ virtual NativeProcessNetBSD &GetProcess();
+ virtual ::pid_t GetProcessPid();
+};
+
+} // namespace process_netbsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextNetBSD_h
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
new file mode 100644
index 0000000..9690da0
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
@@ -0,0 +1,940 @@
+//===-- NativeRegisterContextNetBSD_x86_64.cpp ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__x86_64__)
+
+#include "NativeRegisterContextNetBSD_x86_64.h"
+
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <x86/cpu.h>
+#include <elf.h>
+#include <err.h>
+#include <stdint.h>
+#include <stdlib.h>
+// clang-format on
+
+using namespace lldb_private;
+using namespace lldb_private::process_netbsd;
+
+// ----------------------------------------------------------------------------
+// Private namespace.
+// ----------------------------------------------------------------------------
+
+namespace {
+// x86 64-bit general purpose registers.
+static const uint32_t g_gpr_regnums_x86_64[] = {
+ lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64,
+ lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64,
+ lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64,
+ lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64,
+ lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64,
+ lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64,
+ lldb_eax_x86_64, lldb_ebx_x86_64, lldb_ecx_x86_64, lldb_edx_x86_64,
+ lldb_edi_x86_64, lldb_esi_x86_64, lldb_ebp_x86_64, lldb_esp_x86_64,
+ lldb_r8d_x86_64, // Low 32 bits or r8
+ lldb_r9d_x86_64, // Low 32 bits or r9
+ lldb_r10d_x86_64, // Low 32 bits or r10
+ lldb_r11d_x86_64, // Low 32 bits or r11
+ lldb_r12d_x86_64, // Low 32 bits or r12
+ lldb_r13d_x86_64, // Low 32 bits or r13
+ lldb_r14d_x86_64, // Low 32 bits or r14
+ lldb_r15d_x86_64, // Low 32 bits or r15
+ lldb_ax_x86_64, lldb_bx_x86_64, lldb_cx_x86_64, lldb_dx_x86_64,
+ lldb_di_x86_64, lldb_si_x86_64, lldb_bp_x86_64, lldb_sp_x86_64,
+ lldb_r8w_x86_64, // Low 16 bits or r8
+ lldb_r9w_x86_64, // Low 16 bits or r9
+ lldb_r10w_x86_64, // Low 16 bits or r10
+ lldb_r11w_x86_64, // Low 16 bits or r11
+ lldb_r12w_x86_64, // Low 16 bits or r12
+ lldb_r13w_x86_64, // Low 16 bits or r13
+ lldb_r14w_x86_64, // Low 16 bits or r14
+ lldb_r15w_x86_64, // Low 16 bits or r15
+ lldb_ah_x86_64, lldb_bh_x86_64, lldb_ch_x86_64, lldb_dh_x86_64,
+ lldb_al_x86_64, lldb_bl_x86_64, lldb_cl_x86_64, lldb_dl_x86_64,
+ lldb_dil_x86_64, lldb_sil_x86_64, lldb_bpl_x86_64, lldb_spl_x86_64,
+ lldb_r8l_x86_64, // Low 8 bits or r8
+ lldb_r9l_x86_64, // Low 8 bits or r9
+ lldb_r10l_x86_64, // Low 8 bits or r10
+ lldb_r11l_x86_64, // Low 8 bits or r11
+ lldb_r12l_x86_64, // Low 8 bits or r12
+ lldb_r13l_x86_64, // Low 8 bits or r13
+ lldb_r14l_x86_64, // Low 8 bits or r14
+ lldb_r15l_x86_64, // Low 8 bits or r15
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
+ 1 ==
+ k_num_gpr_registers_x86_64,
+ "g_gpr_regnums_x86_64 has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 };
+
+// Register sets for x86 64-bit.
+static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
+ g_gpr_regnums_x86_64},
+};
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
+
+const int fpu_present = []() -> int {
+ int mib[2];
+ int error;
+ size_t len;
+ int val;
+
+ len = sizeof(val);
+ mib[0] = CTL_MACHDEP;
+ mib[1] = CPU_FPU_PRESENT;
+
+ error = sysctl(mib, __arraycount(mib), &val, &len, NULL, 0);
+ if (error)
+ errx(EXIT_FAILURE, "sysctl");
+
+ return val;
+}();
+
+const int osfxsr = []() -> int {
+ int mib[2];
+ int error;
+ size_t len;
+ int val;
+
+ len = sizeof(val);
+ mib[0] = CTL_MACHDEP;
+ mib[1] = CPU_OSFXSR;
+
+ error = sysctl(mib, __arraycount(mib), &val, &len, NULL, 0);
+ if (error)
+ errx(EXIT_FAILURE, "sysctl");
+
+ return val;
+}();
+
+const int fpu_save = []() -> int {
+ int mib[2];
+ int error;
+ size_t len;
+ int val;
+
+ len = sizeof(val);
+ mib[0] = CTL_MACHDEP;
+ mib[1] = CPU_FPU_SAVE;
+
+ error = sysctl(mib, __arraycount(mib), &val, &len, NULL, 0);
+ if (error)
+ errx(EXIT_FAILURE, "sysctl");
+
+ return val;
+}();
+
+} // namespace
+
+NativeRegisterContextNetBSD *
+NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx) {
+ return new NativeRegisterContextNetBSD_x86_64(target_arch, native_thread,
+ concrete_frame_idx);
+}
+
+// ----------------------------------------------------------------------------
+// NativeRegisterContextNetBSD_x86_64 members.
+// ----------------------------------------------------------------------------
+
+static RegisterInfoInterface *
+CreateRegisterInfoInterface(const ArchSpec &target_arch) {
+ assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
+ "Register setting path assumes this is a 64-bit host");
+ // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the
+ // x86_64 register context.
+ return new RegisterContextNetBSD_x86_64(target_arch);
+}
+
+NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx)
+ : NativeRegisterContextNetBSD(native_thread, concrete_frame_idx,
+ CreateRegisterInfoInterface(target_arch)),
+ m_gpr_x86_64(), m_fpr_x86_64(), m_dbr_x86_64() {}
+
+// CONSIDER after local and llgs debugging are merged, register set support can
+// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
+uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const {
+ uint32_t sets = 0;
+ for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
+ if (GetSetForNativeRegNum(set_index) != -1)
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *
+NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86_64:
+ return &g_reg_sets_x86_64[set_index];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
+ int reg_num) const {
+ if (reg_num <= k_last_gpr_x86_64)
+ return GPRegSet;
+ else if (reg_num <= k_last_fpr_x86_64)
+ return (fpu_present == 1 && osfxsr == 1 && fpu_save >= 1) ? FPRegSet : -1;
+ else if (reg_num <= k_last_avx_x86_64)
+ return -1; // AVX
+ else if (reg_num <= k_last_mpxr_x86_64)
+ return -1; // MPXR
+ else if (reg_num <= k_last_mpxc_x86_64)
+ return -1; // MPXC
+ else if (reg_num <= lldb_dr7_x86_64)
+ return DBRegSet; // DBR
+ else
+ return -1;
+}
+
+int NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) {
+ switch (set) {
+ case GPRegSet:
+ ReadGPR();
+ return 0;
+ case FPRegSet:
+ ReadFPR();
+ return 0;
+ case DBRegSet:
+ ReadDBR();
+ return 0;
+ default:
+ break;
+ }
+ return -1;
+}
+int NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) {
+ switch (set) {
+ case GPRegSet:
+ WriteGPR();
+ return 0;
+ case FPRegSet:
+ WriteFPR();
+ return 0;
+ case DBRegSet:
+ WriteDBR();
+ return 0;
+ default:
+ break;
+ }
+ return -1;
+}
+
+Status
+NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
+ "register, cannot read directly",
+ reg_info->name);
+ return error;
+ }
+
+ int set = GetSetForNativeRegNum(reg);
+ if (set == -1) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ if (ReadRegisterSet(set) != 0) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat(
+ "reading register set for register \"%s\" failed", reg_info->name);
+ return error;
+ }
+
+ switch (reg) {
+ case lldb_rax_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RAX];
+ break;
+ case lldb_rbx_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBX];
+ break;
+ case lldb_rcx_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RCX];
+ break;
+ case lldb_rdx_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDX];
+ break;
+ case lldb_rdi_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDI];
+ break;
+ case lldb_rsi_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSI];
+ break;
+ case lldb_rbp_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBP];
+ break;
+ case lldb_rsp_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSP];
+ break;
+ case lldb_r8_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R8];
+ break;
+ case lldb_r9_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R9];
+ break;
+ case lldb_r10_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R10];
+ break;
+ case lldb_r11_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R11];
+ break;
+ case lldb_r12_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R12];
+ break;
+ case lldb_r13_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R13];
+ break;
+ case lldb_r14_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R14];
+ break;
+ case lldb_r15_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R15];
+ break;
+ case lldb_rip_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RIP];
+ break;
+ case lldb_rflags_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RFLAGS];
+ break;
+ case lldb_cs_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_CS];
+ break;
+ case lldb_fs_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_FS];
+ break;
+ case lldb_gs_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_GS];
+ break;
+ case lldb_ss_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_SS];
+ break;
+ case lldb_ds_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_DS];
+ break;
+ case lldb_es_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES];
+ break;
+ case lldb_fctrl_x86_64:
+ reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_cw;
+ break;
+ case lldb_fstat_x86_64:
+ reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_sw;
+ break;
+ case lldb_ftag_x86_64:
+ reg_value = (uint8_t)m_fpr_x86_64.fxstate.fx_tw;
+ break;
+ case lldb_fop_x86_64:
+ reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_opcode;
+ break;
+ case lldb_fiseg_x86_64:
+ reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_ip.fa_64;
+ break;
+ case lldb_fioff_x86_64:
+ reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off;
+ break;
+ case lldb_foseg_x86_64:
+ reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_dp.fa_64;
+ break;
+ case lldb_fooff_x86_64:
+ reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off;
+ break;
+ case lldb_mxcsr_x86_64:
+ reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr;
+ break;
+ case lldb_mxcsrmask_x86_64:
+ reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr_mask;
+ break;
+ case lldb_st0_x86_64:
+ case lldb_st1_x86_64:
+ case lldb_st2_x86_64:
+ case lldb_st3_x86_64:
+ case lldb_st4_x86_64:
+ case lldb_st5_x86_64:
+ case lldb_st6_x86_64:
+ case lldb_st7_x86_64:
+ reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
+ reg_info->byte_size, endian::InlHostByteOrder());
+ break;
+ case lldb_mm0_x86_64:
+ case lldb_mm1_x86_64:
+ case lldb_mm2_x86_64:
+ case lldb_mm3_x86_64:
+ case lldb_mm4_x86_64:
+ case lldb_mm5_x86_64:
+ case lldb_mm6_x86_64:
+ case lldb_mm7_x86_64:
+ reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_mm0_x86_64],
+ reg_info->byte_size, endian::InlHostByteOrder());
+ break;
+ case lldb_xmm0_x86_64:
+ case lldb_xmm1_x86_64:
+ case lldb_xmm2_x86_64:
+ case lldb_xmm3_x86_64:
+ case lldb_xmm4_x86_64:
+ case lldb_xmm5_x86_64:
+ case lldb_xmm6_x86_64:
+ case lldb_xmm7_x86_64:
+ case lldb_xmm8_x86_64:
+ case lldb_xmm9_x86_64:
+ case lldb_xmm10_x86_64:
+ case lldb_xmm11_x86_64:
+ case lldb_xmm12_x86_64:
+ case lldb_xmm13_x86_64:
+ case lldb_xmm14_x86_64:
+ case lldb_xmm15_x86_64:
+ reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
+ reg_info->byte_size, endian::InlHostByteOrder());
+ break;
+ case lldb_dr0_x86_64:
+ case lldb_dr1_x86_64:
+ case lldb_dr2_x86_64:
+ case lldb_dr3_x86_64:
+ case lldb_dr4_x86_64:
+ case lldb_dr5_x86_64:
+ case lldb_dr6_x86_64:
+ case lldb_dr7_x86_64:
+ reg_value = (uint64_t)m_dbr_x86_64.dr[reg - lldb_dr0_x86_64];
+ break;
+ }
+
+ return error;
+}
+
+Status NativeRegisterContextNetBSD_x86_64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+
+ Status error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
+ "register, cannot read directly",
+ reg_info->name);
+ return error;
+ }
+
+ int set = GetSetForNativeRegNum(reg);
+ if (set == -1) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ if (ReadRegisterSet(set) != 0) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat(
+ "reading register set for register \"%s\" failed", reg_info->name);
+ return error;
+ }
+
+ switch (reg) {
+ case lldb_rax_x86_64:
+ m_gpr_x86_64.regs[_REG_RAX] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rbx_x86_64:
+ m_gpr_x86_64.regs[_REG_RBX] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rcx_x86_64:
+ m_gpr_x86_64.regs[_REG_RCX] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rdx_x86_64:
+ m_gpr_x86_64.regs[_REG_RDX] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rdi_x86_64:
+ m_gpr_x86_64.regs[_REG_RDI] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rsi_x86_64:
+ m_gpr_x86_64.regs[_REG_RSI] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rbp_x86_64:
+ m_gpr_x86_64.regs[_REG_RBP] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rsp_x86_64:
+ m_gpr_x86_64.regs[_REG_RSP] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r8_x86_64:
+ m_gpr_x86_64.regs[_REG_R8] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r9_x86_64:
+ m_gpr_x86_64.regs[_REG_R9] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r10_x86_64:
+ m_gpr_x86_64.regs[_REG_R10] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r11_x86_64:
+ m_gpr_x86_64.regs[_REG_R11] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r12_x86_64:
+ m_gpr_x86_64.regs[_REG_R12] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r13_x86_64:
+ m_gpr_x86_64.regs[_REG_R13] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r14_x86_64:
+ m_gpr_x86_64.regs[_REG_R14] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r15_x86_64:
+ m_gpr_x86_64.regs[_REG_R15] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rip_x86_64:
+ m_gpr_x86_64.regs[_REG_RIP] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rflags_x86_64:
+ m_gpr_x86_64.regs[_REG_RFLAGS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_cs_x86_64:
+ m_gpr_x86_64.regs[_REG_CS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_fs_x86_64:
+ m_gpr_x86_64.regs[_REG_FS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_gs_x86_64:
+ m_gpr_x86_64.regs[_REG_GS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_ss_x86_64:
+ m_gpr_x86_64.regs[_REG_SS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_ds_x86_64:
+ m_gpr_x86_64.regs[_REG_DS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_es_x86_64:
+ m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64();
+ break;
+ case lldb_fctrl_x86_64:
+ m_fpr_x86_64.fxstate.fx_cw = reg_value.GetAsUInt16();
+ break;
+ case lldb_fstat_x86_64:
+ m_fpr_x86_64.fxstate.fx_sw = reg_value.GetAsUInt16();
+ break;
+ case lldb_ftag_x86_64:
+ m_fpr_x86_64.fxstate.fx_tw = reg_value.GetAsUInt8();
+ break;
+ case lldb_fop_x86_64:
+ m_fpr_x86_64.fxstate.fx_opcode = reg_value.GetAsUInt16();
+ break;
+ case lldb_fiseg_x86_64:
+ m_fpr_x86_64.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64();
+ break;
+ case lldb_fioff_x86_64:
+ m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32();
+ break;
+ case lldb_foseg_x86_64:
+ m_fpr_x86_64.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64();
+ break;
+ case lldb_fooff_x86_64:
+ m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32();
+ break;
+ case lldb_mxcsr_x86_64:
+ m_fpr_x86_64.fxstate.fx_mxcsr = reg_value.GetAsUInt32();
+ break;
+ case lldb_mxcsrmask_x86_64:
+ m_fpr_x86_64.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32();
+ break;
+ case lldb_st0_x86_64:
+ case lldb_st1_x86_64:
+ case lldb_st2_x86_64:
+ case lldb_st3_x86_64:
+ case lldb_st4_x86_64:
+ case lldb_st5_x86_64:
+ case lldb_st6_x86_64:
+ case lldb_st7_x86_64:
+ ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
+ reg_value.GetBytes(), reg_value.GetByteSize());
+ break;
+ case lldb_mm0_x86_64:
+ case lldb_mm1_x86_64:
+ case lldb_mm2_x86_64:
+ case lldb_mm3_x86_64:
+ case lldb_mm4_x86_64:
+ case lldb_mm5_x86_64:
+ case lldb_mm6_x86_64:
+ case lldb_mm7_x86_64:
+ ::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_mm0_x86_64],
+ reg_value.GetBytes(), reg_value.GetByteSize());
+ break;
+ case lldb_xmm0_x86_64:
+ case lldb_xmm1_x86_64:
+ case lldb_xmm2_x86_64:
+ case lldb_xmm3_x86_64:
+ case lldb_xmm4_x86_64:
+ case lldb_xmm5_x86_64:
+ case lldb_xmm6_x86_64:
+ case lldb_xmm7_x86_64:
+ case lldb_xmm8_x86_64:
+ case lldb_xmm9_x86_64:
+ case lldb_xmm10_x86_64:
+ case lldb_xmm11_x86_64:
+ case lldb_xmm12_x86_64:
+ case lldb_xmm13_x86_64:
+ case lldb_xmm14_x86_64:
+ case lldb_xmm15_x86_64:
+ ::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
+ reg_value.GetBytes(), reg_value.GetByteSize());
+ break;
+ case lldb_dr0_x86_64:
+ case lldb_dr1_x86_64:
+ case lldb_dr2_x86_64:
+ case lldb_dr3_x86_64:
+ case lldb_dr4_x86_64:
+ case lldb_dr5_x86_64:
+ case lldb_dr6_x86_64:
+ case lldb_dr7_x86_64:
+ m_dbr_x86_64.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64();
+ break;
+ }
+
+ if (WriteRegisterSet(set) != 0)
+ error.SetErrorStringWithFormat("failed to write register set");
+
+ return error;
+}
+
+Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues(
+ lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "failed to allocate DataBufferHeap instance of size %" PRIu64,
+ REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ error = ReadGPR();
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = data_sp->GetBytes();
+ if (dst == nullptr) {
+ error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
+ " returned a null pointer",
+ REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize());
+ dst += GetRegisterInfoInterface().GetGPRSize();
+
+ RegisterValue value((uint64_t)-1);
+ const RegisterInfo *reg_info =
+ GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax");
+ if (reg_info == nullptr)
+ reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax");
+ return error;
+}
+
+Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextNetBSD_x86_64::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched "
+ "data size, expected %" PRIu64 ", actual %" PRIu64,
+ __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
+ return error;
+ }
+
+ uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextNetBSD_x86_64::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+ ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize());
+
+ error = WriteGPR();
+ if (error.Fail())
+ return error;
+ src += GetRegisterInfoInterface().GetGPRSize();
+
+ return error;
+}
+
+Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index,
+ bool &is_hit) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ RegisterValue reg_value;
+ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr6_x86_64);
+ Status error = ReadRegister(reg_info, reg_value);
+ if (error.Fail()) {
+ is_hit = false;
+ return error;
+ }
+
+ uint64_t status_bits = reg_value.GetAsUInt64();
+
+ is_hit = status_bits & (1 << wp_index);
+
+ return error;
+}
+
+Status NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex(
+ uint32_t &wp_index, lldb::addr_t trap_addr) {
+ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+ for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
+ bool is_hit;
+ Status error = IsWatchpointHit(wp_index, is_hit);
+ if (error.Fail()) {
+ wp_index = LLDB_INVALID_INDEX32;
+ return error;
+ } else if (is_hit) {
+ return error;
+ }
+ }
+ wp_index = LLDB_INVALID_INDEX32;
+ return Status();
+}
+
+Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index,
+ bool &is_vacant) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ RegisterValue reg_value;
+ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr7_x86_64);
+ Status error = ReadRegister(reg_info, reg_value);
+ if (error.Fail()) {
+ is_vacant = false;
+ return error;
+ }
+
+ uint64_t control_bits = reg_value.GetAsUInt64();
+
+ is_vacant = !(control_bits & (1 << (2 * wp_index)));
+
+ return error;
+}
+
+Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
+
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ // Read only watchpoints aren't supported on x86_64. Fall back to read/write
+ // waitchpoints instead.
+ // TODO: Add logic to detect when a write happens and ignore that watchpoint
+ // hit.
+ if (watch_flags == 0x2)
+ watch_flags = 0x3;
+
+ if (watch_flags != 0x1 && watch_flags != 0x3)
+ return Status("Invalid read/write bits for watchpoint");
+
+ if (size != 1 && size != 2 && size != 4 && size != 8)
+ return Status("Invalid size for watchpoint");
+
+ bool is_vacant;
+ Status error = IsWatchpointVacant(wp_index, is_vacant);
+ if (error.Fail())
+ return error;
+ if (!is_vacant)
+ return Status("Watchpoint index not vacant");
+
+ RegisterValue reg_value;
+ const RegisterInfo *const reg_info_dr7 =
+ GetRegisterInfoAtIndex(lldb_dr7_x86_64);
+ error = ReadRegister(reg_info_dr7, reg_value);
+ if (error.Fail())
+ return error;
+
+ // for watchpoints 0, 1, 2, or 3, respectively,
+ // set bits 1, 3, 5, or 7
+ uint64_t enable_bit = 1 << (2 * wp_index);
+
+ // set bits 16-17, 20-21, 24-25, or 28-29
+ // with 0b01 for write, and 0b11 for read/write
+ uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
+
+ // set bits 18-19, 22-23, 26-27, or 30-31
+ // with 0b00, 0b01, 0b10, or 0b11
+ // for 1, 2, 8 (if supported), or 4 bytes, respectively
+ uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
+
+ uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
+
+ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+
+ control_bits |= enable_bit | rw_bits | size_bits;
+
+ const RegisterInfo *const reg_info_drN =
+ GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
+ error = WriteRegister(reg_info_drN, RegisterValue(addr));
+ if (error.Fail())
+ return error;
+
+ error = WriteRegister(reg_info_dr7, RegisterValue(control_bits));
+ if (error.Fail())
+ return error;
+
+ error.Clear();
+ return error;
+}
+
+bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint(
+ uint32_t wp_index) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return false;
+
+ RegisterValue reg_value;
+
+ // for watchpoints 0, 1, 2, or 3, respectively,
+ // clear bits 0, 1, 2, or 3 of the debug status register (DR6)
+ const RegisterInfo *const reg_info_dr6 =
+ GetRegisterInfoAtIndex(lldb_dr6_x86_64);
+ Status error = ReadRegister(reg_info_dr6, reg_value);
+ if (error.Fail())
+ return false;
+ uint64_t bit_mask = 1 << wp_index;
+ uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
+ if (error.Fail())
+ return false;
+
+ // for watchpoints 0, 1, 2, or 3, respectively,
+ // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31}
+ // of the debug control register (DR7)
+ const RegisterInfo *const reg_info_dr7 =
+ GetRegisterInfoAtIndex(lldb_dr7_x86_64);
+ error = ReadRegister(reg_info_dr7, reg_value);
+ if (error.Fail())
+ return false;
+ bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
+ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success();
+}
+
+Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() {
+ RegisterValue reg_value;
+
+ // clear bits {0-4} of the debug status register (DR6)
+ const RegisterInfo *const reg_info_dr6 =
+ GetRegisterInfoAtIndex(lldb_dr6_x86_64);
+ Status error = ReadRegister(reg_info_dr6, reg_value);
+ if (error.Fail())
+ return error;
+ uint64_t bit_mask = 0xF;
+ uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
+ if (error.Fail())
+ return error;
+
+ // clear bits {0-7,16-31} of the debug control register (DR7)
+ const RegisterInfo *const reg_info_dr7 =
+ GetRegisterInfoAtIndex(lldb_dr7_x86_64);
+ error = ReadRegister(reg_info_dr7, reg_value);
+ if (error.Fail())
+ return error;
+ bit_mask = 0xFF | (0xFFFF << 16);
+ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+ return WriteRegister(reg_info_dr7, RegisterValue(control_bits));
+}
+
+uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
+ bool is_vacant;
+ Status error = IsWatchpointVacant(wp_index, is_vacant);
+ if (is_vacant) {
+ error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
+ if (error.Success())
+ return wp_index;
+ }
+ if (error.Fail() && log) {
+ log->Printf("NativeRegisterContextNetBSD_x86_64::%s Error: %s",
+ __FUNCTION__, error.AsCString());
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+lldb::addr_t
+NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return LLDB_INVALID_ADDRESS;
+ RegisterValue reg_value;
+ const RegisterInfo *const reg_info_drN =
+ GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
+ if (ReadRegister(reg_info_drN, reg_value).Fail())
+ return LLDB_INVALID_ADDRESS;
+ return reg_value.GetAsUInt64();
+}
+
+uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() {
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
+
+#endif // defined(__x86_64__)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
new file mode 100644
index 0000000..5f5a6a0
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
@@ -0,0 +1,96 @@
+//===-- NativeRegisterContextNetBSD_x86_64.h --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__x86_64__)
+
+#ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
+#define lldb_NativeRegisterContextNetBSD_x86_64_h
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/types.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+namespace lldb_private {
+namespace process_netbsd {
+
+class NativeProcessNetBSD;
+
+class NativeRegisterContextNetBSD_x86_64 : public NativeRegisterContextNetBSD {
+public:
+ NativeRegisterContextNetBSD_x86_64(const ArchSpec &target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx);
+ uint32_t GetRegisterSetCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+
+ Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
+
+ Status GetWatchpointHitIndex(uint32_t &wp_index,
+ lldb::addr_t trap_addr) override;
+
+ Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
+
+ bool ClearHardwareWatchpoint(uint32_t wp_index) override;
+
+ Status ClearAllHardwareWatchpoints() override;
+
+ Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags,
+ uint32_t wp_index);
+
+ uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags) override;
+
+ lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
+
+ uint32_t NumSupportedHardwareWatchpoints() override;
+
+protected:
+ void *GetGPRBuffer() override { return &m_gpr_x86_64; }
+ void *GetFPRBuffer() override { return &m_fpr_x86_64; }
+ void *GetDBRBuffer() override { return &m_dbr_x86_64; }
+
+private:
+ // Private member types.
+ enum { GPRegSet, FPRegSet, DBRegSet };
+
+ // Private member variables.
+ struct reg m_gpr_x86_64;
+ struct fpreg m_fpr_x86_64;
+ struct dbreg m_dbr_x86_64;
+
+ int GetSetForNativeRegNum(int reg_num) const;
+
+ int ReadRegisterSet(uint32_t set);
+ int WriteRegisterSet(uint32_t set);
+};
+
+} // namespace process_netbsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
+
+#endif // defined(__x86_64__)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
new file mode 100644
index 0000000..1fd7400
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
@@ -0,0 +1,218 @@
+//===-- NativeThreadNetBSD.cpp -------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadNetBSD.h"
+#include "NativeRegisterContextNetBSD.h"
+
+#include "NativeProcessNetBSD.h"
+
+#include "Plugins/Process/POSIX/CrashReason.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/State.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+#include <sstream>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_netbsd;
+
+NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process,
+ lldb::tid_t tid)
+ : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
+ m_stop_info(), m_reg_context_sp(), m_stop_description() {}
+
+void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
+ const siginfo_t *info) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
+
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.details.signal.signo = signo;
+
+ m_stop_description.clear();
+ if (info) {
+ switch (signo) {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ const auto reason = GetCrashReason(*info);
+ m_stop_description = GetCrashReasonString(reason, *info);
+ break;
+ }
+ }
+}
+
+void NativeThreadNetBSD::SetStoppedByBreakpoint() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonBreakpoint;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStoppedByTrace() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonTrace;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStoppedByExec() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonExec;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
+ SetStopped();
+
+ lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
+
+ std::ostringstream ostr;
+ ostr << GetRegisterContext()->GetWatchpointAddress(wp_index) << " ";
+ ostr << wp_index;
+
+ ostr << " " << GetRegisterContext()->GetWatchpointHitAddress(wp_index);
+
+ m_stop_description = ostr.str();
+
+ m_stop_info.reason = StopReason::eStopReasonWatchpoint;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStopped() {
+ const StateType new_state = StateType::eStateStopped;
+ m_state = new_state;
+ m_stop_description.clear();
+}
+
+void NativeThreadNetBSD::SetRunning() {
+ m_state = StateType::eStateRunning;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void NativeThreadNetBSD::SetStepping() {
+ m_state = StateType::eStateStepping;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+std::string NativeThreadNetBSD::GetName() { return std::string(""); }
+
+lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
+
+bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+
+ description.clear();
+
+ switch (m_state) {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ case eStateUnloaded:
+ stop_info = m_stop_info;
+ description = m_stop_description;
+
+ return true;
+
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
+ StateAsCString(m_state));
+ return false;
+ }
+ llvm_unreachable("unhandled StateType!");
+}
+
+NativeRegisterContextSP NativeThreadNetBSD::GetRegisterContext() {
+ // Return the register context if we already created it.
+ if (m_reg_context_sp)
+ return m_reg_context_sp;
+
+ ArchSpec target_arch;
+ if (!m_process.GetArchitecture(target_arch))
+ return NativeRegisterContextSP();
+
+ const uint32_t concrete_frame_idx = 0;
+ m_reg_context_sp.reset(
+ NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
+ target_arch, *this, concrete_frame_idx));
+
+ return m_reg_context_sp;
+}
+
+Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware) {
+ if (!hardware)
+ return Status("not implemented");
+ if (m_state == eStateLaunching)
+ return Status();
+ Status error = RemoveWatchpoint(addr);
+ if (error.Fail())
+ return error;
+ NativeRegisterContextSP reg_ctx = GetRegisterContext();
+ uint32_t wp_index = reg_ctx->SetHardwareWatchpoint(addr, size, watch_flags);
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware watchpoint failed.");
+ m_watchpoint_index_map.insert({addr, wp_index});
+ return Status();
+}
+
+Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
+ auto wp = m_watchpoint_index_map.find(addr);
+ if (wp == m_watchpoint_index_map.end())
+ return Status();
+ uint32_t wp_index = wp->second;
+ m_watchpoint_index_map.erase(wp);
+ if (GetRegisterContext()->ClearHardwareWatchpoint(wp_index))
+ return Status();
+ return Status("Clearing hardware watchpoint failed.");
+}
+
+Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ if (m_state == eStateLaunching)
+ return Status();
+
+ Status error = RemoveHardwareBreakpoint(addr);
+ if (error.Fail())
+ return error;
+
+ NativeRegisterContextSP reg_ctx = GetRegisterContext();
+ uint32_t bp_index = reg_ctx->SetHardwareBreakpoint(addr, size);
+
+ if (bp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware breakpoint failed.");
+
+ m_hw_break_index_map.insert({addr, bp_index});
+ return Status();
+}
+
+Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+ auto bp = m_hw_break_index_map.find(addr);
+ if (bp == m_hw_break_index_map.end())
+ return Status();
+
+ uint32_t bp_index = bp->second;
+ if (GetRegisterContext()->ClearHardwareBreakpoint(bp_index)) {
+ m_hw_break_index_map.erase(bp);
+ return Status();
+ }
+
+ return Status("Clearing hardware breakpoint failed.");
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
new file mode 100644
index 0000000..1e3f587
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
@@ -0,0 +1,81 @@
+//===-- NativeThreadNetBSD.h ---------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeThreadNetBSD_H_
+#define liblldb_NativeThreadNetBSD_H_
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include <csignal>
+#include <map>
+#include <string>
+
+namespace lldb_private {
+namespace process_netbsd {
+
+class NativeProcessNetBSD;
+
+class NativeThreadNetBSD : public NativeThreadProtocol {
+ friend class NativeProcessNetBSD;
+
+public:
+ NativeThreadNetBSD(NativeProcessNetBSD &process, lldb::tid_t tid);
+
+ // ---------------------------------------------------------------------
+ // NativeThreadProtocol Interface
+ // ---------------------------------------------------------------------
+ std::string GetName() override;
+
+ lldb::StateType GetState() override;
+
+ bool GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) override;
+
+ NativeRegisterContextSP GetRegisterContext() override;
+
+ Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware) override;
+
+ Status RemoveWatchpoint(lldb::addr_t addr) override;
+
+ Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
+private:
+ // ---------------------------------------------------------------------
+ // Interface for friend classes
+ // ---------------------------------------------------------------------
+
+ void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
+ void SetStoppedByBreakpoint();
+ void SetStoppedByTrace();
+ void SetStoppedByExec();
+ void SetStoppedByWatchpoint(uint32_t wp_index);
+ void SetStopped();
+ void SetRunning();
+ void SetStepping();
+
+ // ---------------------------------------------------------------------
+ // Member Variables
+ // ---------------------------------------------------------------------
+ lldb::StateType m_state;
+ ThreadStopInfo m_stop_info;
+ NativeRegisterContextSP m_reg_context_sp;
+ std::string m_stop_description;
+ using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
+ WatchpointIndexMap m_watchpoint_index_map;
+ WatchpointIndexMap m_hw_break_index_map;
+};
+
+typedef std::shared_ptr<NativeThreadNetBSD> NativeThreadNetBSDSP;
+} // namespace process_netbsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeThreadNetBSD_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
index 77d6e28..864418c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
@@ -62,7 +62,6 @@ CrashReason GetCrashReasonForSIGSEGV(const siginfo_t &info) {
return CrashReason::eBoundViolation;
}
- assert(false && "unexpected si_code for SIGSEGV");
return CrashReason::eInvalidCrashReason;
}
@@ -88,7 +87,6 @@ CrashReason GetCrashReasonForSIGILL(const siginfo_t &info) {
return CrashReason::eInternalStackError;
}
- assert(false && "unexpected si_code for SIGILL");
return CrashReason::eInvalidCrashReason;
}
@@ -114,7 +112,6 @@ CrashReason GetCrashReasonForSIGFPE(const siginfo_t &info) {
return CrashReason::eFloatSubscriptRange;
}
- assert(false && "unexpected si_code for SIGFPE");
return CrashReason::eInvalidCrashReason;
}
@@ -130,7 +127,6 @@ CrashReason GetCrashReasonForSIGBUS(const siginfo_t &info) {
return CrashReason::eHardwareError;
}
- assert(false && "unexpected si_code for SIGBUS");
return CrashReason::eInvalidCrashReason;
}
}
@@ -158,7 +154,7 @@ std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) {
switch (reason) {
default:
- assert(false && "invalid CrashReason");
+ str = "unknown crash reason";
break;
case CrashReason::eInvalidAddress:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
index 9ced11c..f1beb0f 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
@@ -10,188 +10,23 @@
#include "ProcessPOSIXLog.h"
-#include <mutex>
+#include "llvm/Support/Threading.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Interpreter/Args.h"
-
-#include "ProcessPOSIXLog.h"
-
-using namespace lldb;
using namespace lldb_private;
-// We want to avoid global constructors where code needs to be run so here we
-// control access to our static g_log_sp by hiding it in a singleton function
-// that will construct the static g_log_sp the first time this function is
-// called.
-static bool g_log_enabled = false;
-static Log *g_log = NULL;
-static Log *GetLog() {
- if (!g_log_enabled)
- return NULL;
- return g_log;
-}
+static constexpr Log::Category g_categories[] = {
+ {{"break"}, {"log breakpoints"}, POSIX_LOG_BREAKPOINTS},
+ {{"memory"}, {"log memory reads and writes"}, POSIX_LOG_MEMORY},
+ {{"process"}, {"log process events and activities"}, POSIX_LOG_PROCESS},
+ {{"ptrace"}, {"log all calls to ptrace"}, POSIX_LOG_PTRACE},
+ {{"registers"}, {"log register read/writes"}, POSIX_LOG_REGISTERS},
+ {{"thread"}, {"log thread events and activities"}, POSIX_LOG_THREAD},
+ {{"watch"}, {"log watchpoint related activities"}, POSIX_LOG_WATCHPOINTS},
+};
-void ProcessPOSIXLog::Initialize(ConstString name) {
- static std::once_flag g_once_flag;
-
- std::call_once(g_once_flag, [name]() {
- Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories};
-
- Log::RegisterLogChannel(name, log_callbacks);
- RegisterPluginName(name);
- });
-}
+Log::Channel ProcessPOSIXLog::g_channel(g_categories, POSIX_LOG_DEFAULT);
-Log *ProcessPOSIXLog::GetLogIfAllCategoriesSet(uint32_t mask) {
- Log *log(GetLog());
- if (log && mask) {
- uint32_t log_mask = log->GetMask().Get();
- if ((log_mask & mask) != mask)
- return NULL;
- }
- return log;
+void ProcessPOSIXLog::Initialize() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() { Log::Register("posix", g_channel); });
}
-
-static uint32_t GetFlagBits(const char *arg) {
- if (::strcasecmp(arg, "all") == 0)
- return POSIX_LOG_ALL;
- else if (::strcasecmp(arg, "async") == 0)
- return POSIX_LOG_ASYNC;
- else if (::strncasecmp(arg, "break", 5) == 0)
- return POSIX_LOG_BREAKPOINTS;
- else if (::strncasecmp(arg, "comm", 4) == 0)
- return POSIX_LOG_COMM;
- else if (::strcasecmp(arg, "default") == 0)
- return POSIX_LOG_DEFAULT;
- else if (::strcasecmp(arg, "packets") == 0)
- return POSIX_LOG_PACKETS;
- else if (::strcasecmp(arg, "memory") == 0)
- return POSIX_LOG_MEMORY;
- else if (::strcasecmp(arg, "data-short") == 0)
- return POSIX_LOG_MEMORY_DATA_SHORT;
- else if (::strcasecmp(arg, "data-long") == 0)
- return POSIX_LOG_MEMORY_DATA_LONG;
- else if (::strcasecmp(arg, "process") == 0)
- return POSIX_LOG_PROCESS;
- else if (::strcasecmp(arg, "ptrace") == 0)
- return POSIX_LOG_PTRACE;
- else if (::strcasecmp(arg, "registers") == 0)
- return POSIX_LOG_REGISTERS;
- else if (::strcasecmp(arg, "step") == 0)
- return POSIX_LOG_STEP;
- else if (::strcasecmp(arg, "thread") == 0)
- return POSIX_LOG_THREAD;
- else if (::strcasecmp(arg, "verbose") == 0)
- return POSIX_LOG_VERBOSE;
- else if (::strncasecmp(arg, "watch", 5) == 0)
- return POSIX_LOG_WATCHPOINTS;
- return 0;
-}
-
-void ProcessPOSIXLog::DisableLog(const char **args, Stream *feedback_strm) {
- Log *log(GetLog());
- if (log) {
- uint32_t flag_bits = 0;
-
- flag_bits = log->GetMask().Get();
- for (; args && args[0]; args++) {
- const char *arg = args[0];
- uint32_t bits = GetFlagBits(arg);
-
- if (bits) {
- flag_bits &= ~bits;
- } else {
- feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
- ListLogCategories(feedback_strm);
- }
- }
-
- log->GetMask().Reset(flag_bits);
- if (flag_bits == 0)
- g_log_enabled = false;
- }
-
- return;
-}
-
-Log *ProcessPOSIXLog::EnableLog(StreamSP &log_stream_sp, uint32_t log_options,
- const char **args, Stream *feedback_strm) {
- // Try see if there already is a log - that way we can reuse its settings.
- // We could reuse the log in toto, but we don't know that the stream is the
- // same.
- uint32_t flag_bits = 0;
- if (g_log)
- flag_bits = g_log->GetMask().Get();
-
- // Now make a new log with this stream if one was provided
- if (log_stream_sp) {
- if (g_log)
- g_log->SetStream(log_stream_sp);
- else
- g_log = new Log(log_stream_sp);
- }
-
- if (g_log) {
- bool got_unknown_category = false;
- for (; args && args[0]; args++) {
- const char *arg = args[0];
- uint32_t bits = GetFlagBits(arg);
-
- if (bits) {
- flag_bits |= bits;
- } else {
- feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
- if (got_unknown_category == false) {
- got_unknown_category = true;
- ListLogCategories(feedback_strm);
- }
- }
- }
- if (flag_bits == 0)
- flag_bits = POSIX_LOG_DEFAULT;
- g_log->GetMask().Reset(flag_bits);
- g_log->GetOptions().Reset(log_options);
- g_log_enabled = true;
- }
- return g_log;
-}
-
-void ProcessPOSIXLog::ListLogCategories(Stream *strm) {
- strm->Printf(
- "Logging categories for '%s':\n"
- " all - turn on all available logging categories\n"
- " async - log asynchronous activity\n"
- " break - log breakpoints\n"
- " communication - log communication activity\n"
- " default - enable the default set of logging categories for liblldb\n"
- " packets - log gdb remote packets\n"
- " memory - log memory reads and writes\n"
- " data-short - log memory bytes for memory reads and writes for short "
- "transactions only\n"
- " data-long - log memory bytes for memory reads and writes for all "
- "transactions\n"
- " process - log process events and activities\n"
-#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
- " ptrace - log all calls to ptrace\n"
-#endif
- " registers - log register read/writes\n"
- " thread - log thread events and activities\n"
- " step - log step related activities\n"
- " verbose - enable verbose logging\n"
- " watch - log watchpoint related activities\n",
- ProcessPOSIXLog::m_pluginname);
-}
-
-void ProcessPOSIXLog::LogIf(uint32_t mask, const char *format, ...) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(mask));
- if (log) {
- va_list args;
- va_start(args, format);
- log->VAPrintf(format, args);
- va_end(args);
- }
-}
-
-int ProcessPOSIXLog::m_nestinglevel;
-const char *ProcessPOSIXLog::m_pluginname = "";
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
index 7d187da..1340135 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
@@ -16,87 +16,29 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
-#define POSIX_LOG_VERBOSE (1u << 0)
#define POSIX_LOG_PROCESS (1u << 1)
#define POSIX_LOG_THREAD (1u << 2)
-#define POSIX_LOG_PACKETS (1u << 3)
#define POSIX_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
-#define POSIX_LOG_MEMORY_DATA_SHORT \
- (1u << 5) // Log short memory reads/writes bytes
-#define POSIX_LOG_MEMORY_DATA_LONG \
- (1u << 6) // Log all memory reads/writes bytes
+#define POSIX_LOG_PTRACE (1u << 5)
+#define POSIX_LOG_REGISTERS (1u << 6)
#define POSIX_LOG_BREAKPOINTS (1u << 7)
#define POSIX_LOG_WATCHPOINTS (1u << 8)
-#define POSIX_LOG_STEP (1u << 9)
-#define POSIX_LOG_COMM (1u << 10)
-#define POSIX_LOG_ASYNC (1u << 11)
-#define POSIX_LOG_PTRACE (1u << 12)
-#define POSIX_LOG_REGISTERS (1u << 13)
#define POSIX_LOG_ALL (UINT32_MAX)
-#define POSIX_LOG_DEFAULT POSIX_LOG_PACKETS
-
-// The size which determines "short memory reads/writes".
-#define POSIX_LOG_MEMORY_SHORT_BYTES (4 * sizeof(ptrdiff_t))
+#define POSIX_LOG_DEFAULT POSIX_LOG_PROCESS
+namespace lldb_private {
class ProcessPOSIXLog {
- static int m_nestinglevel;
- static const char *m_pluginname;
+ static Log::Channel g_channel;
public:
- // ---------------------------------------------------------------------
- // Public Static Methods
- // ---------------------------------------------------------------------
- static void Initialize(lldb_private::ConstString name);
-
- static void RegisterPluginName(const char *pluginName) {
- m_pluginname = pluginName;
- }
-
- static void RegisterPluginName(lldb_private::ConstString pluginName) {
- m_pluginname = pluginName.GetCString();
- }
-
- static lldb_private::Log *GetLogIfAllCategoriesSet(uint32_t mask = 0);
-
- static void DisableLog(const char **args,
- lldb_private::Stream *feedback_strm);
-
- static lldb_private::Log *EnableLog(lldb::StreamSP &log_stream_sp,
- uint32_t log_options, const char **args,
- lldb_private::Stream *feedback_strm);
-
- static void ListLogCategories(lldb_private::Stream *strm);
-
- static void LogIf(uint32_t mask, const char *format, ...);
-
- // The following functions can be used to enable the client to limit
- // logging to only the top level function calls. This is useful for
- // recursive functions. FIXME: not thread safe!
- // Example:
- // void NestingFunc() {
- // LogSP log
- // (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_ALL));
- // if (log)
- // {
- // ProcessPOSIXLog::IncNestLevel();
- // if (ProcessPOSIXLog::AtTopNestLevel())
- // log->Print(msg);
- // }
- // NestingFunc();
- // if (log)
- // ProcessPOSIXLog::DecNestLevel();
- // }
-
- static bool AtTopNestLevel() { return m_nestinglevel == 1; }
-
- static void IncNestLevel() { ++m_nestinglevel; }
+ static void Initialize();
- static void DecNestLevel() {
- --m_nestinglevel;
- assert(m_nestinglevel >= 0);
+ static Log *GetLogIfAllCategoriesSet(uint32_t mask) {
+ return g_channel.GetLogIfAll(mask);
}
};
+}
#endif // liblldb_ProcessPOSIXLog_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
index 75f7251..1a4511a 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -14,12 +14,12 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/StringExtractor.h"
+#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
@@ -48,10 +48,10 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
if (dict.GetValueForKeyAsArray("sets", sets)) {
const uint32_t num_sets = sets->GetSize();
for (uint32_t i = 0; i < num_sets; ++i) {
- std::string set_name_str;
+ llvm::StringRef set_name_str;
ConstString set_name;
if (sets->GetItemAtIndexAsString(i, set_name_str))
- set_name.SetCString(set_name_str.c_str());
+ set_name.SetString(set_name_str);
if (set_name) {
RegisterSet new_set = {set_name.AsCString(), NULL, 0, NULL};
m_sets.push_back(new_set);
@@ -115,7 +115,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
// expression
// we can calculate the offset
bool success = false;
- std::string slice_str;
+ llvm::StringRef slice_str;
if (reg_info_dict->GetValueForKeyAsString("slice", slice_str, nullptr)) {
// Slices use the following format:
// REGNAME[MSBIT:LSBIT]
@@ -131,9 +131,9 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
llvm::StringRef reg_name_str;
std::string msbit_str;
std::string lsbit_str;
- if (regex_match.GetMatchAtIndex(slice_str.c_str(), 1, reg_name_str) &&
- regex_match.GetMatchAtIndex(slice_str.c_str(), 2, msbit_str) &&
- regex_match.GetMatchAtIndex(slice_str.c_str(), 3, lsbit_str)) {
+ if (regex_match.GetMatchAtIndex(slice_str, 1, reg_name_str) &&
+ regex_match.GetMatchAtIndex(slice_str, 2, msbit_str) &&
+ regex_match.GetMatchAtIndex(slice_str, 3, lsbit_str)) {
const uint32_t msbit =
StringConvert::ToUInt32(msbit_str.c_str(), UINT32_MAX);
const uint32_t lsbit =
@@ -269,18 +269,17 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
reg_info.byte_size = bitsize / 8;
- std::string dwarf_opcode_string;
+ llvm::StringRef dwarf_opcode_string;
if (reg_info_dict->GetValueForKeyAsString("dynamic_size_dwarf_expr_bytes",
dwarf_opcode_string)) {
- reg_info.dynamic_size_dwarf_len = dwarf_opcode_string.length() / 2;
+ reg_info.dynamic_size_dwarf_len = dwarf_opcode_string.size() / 2;
assert(reg_info.dynamic_size_dwarf_len > 0);
std::vector<uint8_t> dwarf_opcode_bytes(reg_info.dynamic_size_dwarf_len);
uint32_t j;
- StringExtractor opcode_extractor;
- // Swap "dwarf_opcode_string" over into "opcode_extractor"
- opcode_extractor.GetStringRef().swap(dwarf_opcode_string);
+ StringExtractor opcode_extractor(dwarf_opcode_string);
uint32_t ret_val = opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes);
+ UNUSED_IF_ASSERT_DISABLED(ret_val);
assert(ret_val == reg_info.dynamic_size_dwarf_len);
for (j = 0; j < reg_info.dynamic_size_dwarf_len; ++j)
@@ -289,9 +288,9 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
reg_info.dynamic_size_dwarf_expr_bytes = m_dynamic_reg_size_map[i].data();
}
- std::string format_str;
+ llvm::StringRef format_str;
if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr)) {
- if (Args::StringToFormat(format_str.c_str(), reg_info.format, NULL)
+ if (Args::StringToFormat(format_str.str().c_str(), reg_info.format, NULL)
.Fail()) {
Clear();
printf("error: invalid 'format' value in register dictionary\n");
@@ -303,7 +302,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
eFormatHex);
}
- std::string encoding_str;
+ llvm::StringRef encoding_str;
if (reg_info_dict->GetValueForKeyAsString("encoding", encoding_str))
reg_info.encoding = Args::StringToEncoding(encoding_str, eEncodingUint);
else
@@ -333,7 +332,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
reg_info.kinds[lldb::eRegisterKindEHFrame] = eh_frame_regno;
reg_info_dict->GetValueForKeyAsInteger(
"dwarf", reg_info.kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM);
- std::string generic_str;
+ llvm::StringRef generic_str;
if (reg_info_dict->GetValueForKeyAsString("generic", generic_str))
reg_info.kinds[lldb::eRegisterKindGeneric] =
Args::StringToGenericRegister(generic_str);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
index e5c22fe..228acfb 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
@@ -17,8 +17,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
class DynamicRegisterInfo {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
index d27a7b0..4983dcd 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
@@ -13,9 +13,9 @@
#include "Plugins/Process/Utility/HistoryUnwind.h"
#include "Plugins/Process/Utility/RegisterContextHistory.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrameList.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h
index 1a4898a..363ba26 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h
@@ -18,11 +18,11 @@
// Project includes
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/UserID.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/StackFrameList.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/UserID.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
index 4e1f10c..5c51a03 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -64,7 +64,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
options.SetTimeout(std::chrono::milliseconds(500));
options.SetTrapExceptions(false);
- addr_t prot_arg, flags_arg = 0;
+ addr_t prot_arg;
if (prot == eMmapProtNone)
prot_arg = PROT_NONE;
else {
@@ -77,11 +77,6 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
prot_arg |= PROT_WRITE;
}
- const ArchSpec arch = process->GetTarget().GetArchitecture();
- flags_arg =
- process->GetTarget().GetPlatform()->ConvertMmapFlagsToPlatform(arch,
- flags);
-
AddressRange mmap_range;
if (sc.GetAddressRange(range_scope, 0, use_inline_block_range,
mmap_range)) {
@@ -89,7 +84,10 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
process->GetTarget().GetScratchClangASTContext();
CompilerType clang_void_ptr_type =
clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
- lldb::addr_t args[] = {addr, length, prot_arg, flags_arg, fd, offset};
+ const ArchSpec arch = process->GetTarget().GetArchitecture();
+ MmapArgList args =
+ process->GetTarget().GetPlatform()->GetMmapArgumentList(
+ arch, addr, length, prot_arg, flags, fd, offset);
lldb::ThreadPlanSP call_plan_sp(
new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(),
clang_void_ptr_type, args, options));
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp
index 5ff596b..0b18143 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
+#include "NativeRegisterContextRegisterInfo.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-types.h"
diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeRegisterContextRegisterInfo.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h
index 908989a..c1b5974 100644
--- a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeRegisterContextRegisterInfo.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h
@@ -1,5 +1,4 @@
-//===-- NativeRegisterContextRegisterInfo.h ----------------------*- C++
-//-*-===//
+//===-- NativeRegisterContextRegisterInfo.h ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,13 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#ifndef lldb_NativeRegisterContextRegisterInfo_h
-#define lldb_NativeRegisterContextRegisterInfo_h
+#ifndef LLDB_PLUGINS_PROCESS_UTIILTY_NATIVE_REGISTER_CONTEXT_REGISTER_INFO
+#define LLDB_PLUGINS_PROCESS_UTIILTY_NATIVE_REGISTER_CONTEXT_REGISTER_INFO
#include <memory>
-#include "NativeRegisterContext.h"
-#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+#include "RegisterInfoInterface.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
namespace lldb_private {
class NativeRegisterContextRegisterInfo : public NativeRegisterContext {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp
index 9b9db51..7ed7189 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/NetBSDSignals.cpp
@@ -24,7 +24,35 @@ void NetBSDSignals::Reset() {
// ===================================================
AddSignal(32, "SIGPWR", false, true, true,
"power fail/restart (not reset when caught)");
-#ifdef SIGRTMIN /* SIGRTMAX */
- /* Kernel only; not exposed to userland yet */
-#endif
+ AddSignal(33, "SIGRTMIN", false, false, false, "real time signal 0");
+ AddSignal(34, "SIGRTMIN+1", false, false, false, "real time signal 1");
+ AddSignal(35, "SIGRTMIN+2", false, false, false, "real time signal 2");
+ AddSignal(36, "SIGRTMIN+3", false, false, false, "real time signal 3");
+ AddSignal(37, "SIGRTMIN+4", false, false, false, "real time signal 4");
+ AddSignal(38, "SIGRTMIN+5", false, false, false, "real time signal 5");
+ AddSignal(39, "SIGRTMIN+6", false, false, false, "real time signal 6");
+ AddSignal(40, "SIGRTMIN+7", false, false, false, "real time signal 7");
+ AddSignal(41, "SIGRTMIN+8", false, false, false, "real time signal 8");
+ AddSignal(42, "SIGRTMIN+9", false, false, false, "real time signal 9");
+ AddSignal(43, "SIGRTMIN+10", false, false, false, "real time signal 10");
+ AddSignal(44, "SIGRTMIN+11", false, false, false, "real time signal 11");
+ AddSignal(45, "SIGRTMIN+12", false, false, false, "real time signal 12");
+ AddSignal(46, "SIGRTMIN+13", false, false, false, "real time signal 13");
+ AddSignal(47, "SIGRTMIN+14", false, false, false, "real time signal 14");
+ AddSignal(48, "SIGRTMIN+15", false, false, false, "real time signal 15");
+ AddSignal(49, "SIGRTMIN-14", false, false, false, "real time signal 16");
+ AddSignal(50, "SIGRTMAX-13", false, false, false, "real time signal 17");
+ AddSignal(51, "SIGRTMAX-12", false, false, false, "real time signal 18");
+ AddSignal(52, "SIGRTMAX-11", false, false, false, "real time signal 19");
+ AddSignal(53, "SIGRTMAX-10", false, false, false, "real time signal 20");
+ AddSignal(54, "SIGRTMAX-9", false, false, false, "real time signal 21");
+ AddSignal(55, "SIGRTMAX-8", false, false, false, "real time signal 22");
+ AddSignal(56, "SIGRTMAX-7", false, false, false, "real time signal 23");
+ AddSignal(57, "SIGRTMAX-6", false, false, false, "real time signal 24");
+ AddSignal(58, "SIGRTMAX-5", false, false, false, "real time signal 25");
+ AddSignal(59, "SIGRTMAX-4", false, false, false, "real time signal 26");
+ AddSignal(60, "SIGRTMAX-3", false, false, false, "real time signal 27");
+ AddSignal(61, "SIGRTMAX-2", false, false, false, "real time signal 28");
+ AddSignal(62, "SIGRTMAX-1", false, false, false, "real time signal 29");
+ AddSignal(63, "SIGRTMAX", false, false, false, "real time signal 30");
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
index 52ace56..64a697f 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
@@ -17,12 +17,12 @@
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
#include "llvm/Support/Compiler.h"
#include "Plugins/Process/Utility/InstructionUtils.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
index 64983a2..0c36f1a 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
@@ -19,14 +19,14 @@
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
index f42fb00..c818fad 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
@@ -12,12 +12,12 @@
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
index 7c0bafa..50e7292 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
@@ -14,12 +14,12 @@
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp
index 93bb09b..dd6ca92 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp
@@ -10,8 +10,6 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/AddressRange.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Value.h"
@@ -28,6 +26,8 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
#include "lldb/lldb-private.h"
#include "RegisterContextDummy.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp
deleted file mode 100644
index fecfae0..0000000
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-//===-- RegisterContextFreeBSD_arm.cpp -------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===---------------------------------------------------------------------===//
-
-#include <cassert>
-#include <stddef.h>
-#include <vector>
-
-#include "lldb/lldb-defines.h"
-#include "llvm/Support/Compiler.h"
-
-#include "RegisterContextFreeBSD_arm.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-// Based on RegisterContextLinux_arm.cpp and
-// http://svnweb.freebsd.org/base/head/sys/arm/include/reg.h
-#define GPR_OFFSET(idx) ((idx)*4)
-#define FPU_OFFSET(idx) ((idx)*4 + sizeof(RegisterContextFreeBSD_arm::GPR))
-#define FPSCR_OFFSET \
- (LLVM_EXTENSION offsetof(RegisterContextFreeBSD_arm::FPU, fpscr) + \
- sizeof(RegisterContextFreeBSD_arm::GPR))
-#define EXC_OFFSET(idx) \
- ((idx)*4 + sizeof(RegisterContextFreeBSD_arm::GPR) + \
- sizeof(RegisterContextFreeBSD_arm::FPU))
-#define DBG_OFFSET(reg) \
- ((LLVM_EXTENSION offsetof(RegisterContextFreeBSD_arm::DBG, reg) + \
- sizeof(RegisterContextFreeBSD_arm::GPR) + \
- sizeof(RegisterContextFreeBSD_arm::FPU) + \
- sizeof(RegisterContextFreeBSD_arm::EXC)))
-
-#define DEFINE_DBG(reg, i) \
- #reg, NULL, sizeof(((RegisterContextFreeBSD_arm::DBG *) NULL)->reg[i]), \
- DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, \
- {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- dbg_##reg##i }, \
- NULL, NULL, NULL, 0
-#define REG_CONTEXT_SIZE \
- (sizeof(RegisterContextFreeBSD_arm::GPR) + \
- sizeof(RegisterContextFreeBSD_arm::FPU) + \
- sizeof(RegisterContextFreeBSD_arm::EXC))
-
-//-----------------------------------------------------------------------------
-// Include RegisterInfos_arm to declare our g_register_infos_arm structure.
-//-----------------------------------------------------------------------------
-#define DECLARE_REGISTER_INFOS_ARM_STRUCT
-#include "RegisterInfos_arm.h"
-#undef DECLARE_REGISTER_INFOS_ARM_STRUCT
-
-static const lldb_private::RegisterInfo *
-GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
- switch (target_arch.GetMachine()) {
- case llvm::Triple::arm:
- return g_register_infos_arm;
- default:
- assert(false && "Unhandled target architecture.");
- return NULL;
- }
-}
-
-static uint32_t
-GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
- switch (target_arch.GetMachine()) {
- case llvm::Triple::arm:
- return static_cast<uint32_t>(sizeof(g_register_infos_arm) /
- sizeof(g_register_infos_arm[0]));
- default:
- assert(false && "Unhandled target architecture.");
- return 0;
- }
-}
-
-RegisterContextFreeBSD_arm::RegisterContextFreeBSD_arm(
- const lldb_private::ArchSpec &target_arch)
- : lldb_private::RegisterInfoInterface(target_arch),
- m_register_info_p(GetRegisterInfoPtr(target_arch)),
- m_register_info_count(GetRegisterInfoCount(target_arch)) {}
-
-size_t RegisterContextFreeBSD_arm::GetGPRSize() const {
- return sizeof(struct RegisterContextFreeBSD_arm::GPR);
-}
-
-const lldb_private::RegisterInfo *
-RegisterContextFreeBSD_arm::GetRegisterInfo() const {
- return m_register_info_p;
-}
-
-uint32_t RegisterContextFreeBSD_arm::GetRegisterCount() const {
- return m_register_info_count;
-}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
index c114cfb..55a72b2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
@@ -9,11 +9,33 @@
#include "RegisterContextFreeBSD_mips64.h"
#include "RegisterContextPOSIX_mips64.h"
+#include "lldb-mips-freebsd-register-enums.h"
#include <vector>
using namespace lldb_private;
using namespace lldb;
+static const uint32_t g_gpr_regnums[] = {
+ gpr_zero_mips64, gpr_r1_mips64, gpr_r2_mips64, gpr_r3_mips64,
+ gpr_r4_mips64, gpr_r5_mips64, gpr_r6_mips64, gpr_r7_mips64,
+ gpr_r8_mips64, gpr_r9_mips64, gpr_r10_mips64, gpr_r11_mips64,
+ gpr_r12_mips64, gpr_r13_mips64, gpr_r14_mips64, gpr_r15_mips64,
+ gpr_r16_mips64, gpr_r17_mips64, gpr_r18_mips64, gpr_r19_mips64,
+ gpr_r20_mips64, gpr_r21_mips64, gpr_r22_mips64, gpr_r23_mips64,
+ gpr_r24_mips64, gpr_r25_mips64, gpr_r26_mips64, gpr_r27_mips64,
+ gpr_gp_mips64, gpr_sp_mips64, gpr_r30_mips64, gpr_ra_mips64,
+ gpr_sr_mips64, gpr_mullo_mips64, gpr_mulhi_mips64, gpr_badvaddr_mips64,
+ gpr_cause_mips64, gpr_pc_mips64, gpr_ic_mips64, gpr_dummy_mips64};
+
+// Number of register sets provided by this context.
+constexpr size_t k_num_register_sets = 1;
+
+static const RegisterSet g_reg_sets_mips64[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_mips64,
+ g_gpr_regnums},
+};
+
+
// http://svnweb.freebsd.org/base/head/sys/mips/include/regnum.h
typedef struct _GPR {
uint64_t zero;
@@ -74,6 +96,19 @@ size_t RegisterContextFreeBSD_mips64::GetGPRSize() const {
return sizeof(GPR_freebsd_mips);
}
+const RegisterSet *
+RegisterContextFreeBSD_mips64::GetRegisterSet(size_t set) const {
+ // Check if RegisterSet is available
+ if (set < k_num_register_sets)
+ return &g_reg_sets_mips64[set];
+ return nullptr;
+}
+
+size_t
+RegisterContextFreeBSD_mips64::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
const RegisterInfo *RegisterContextFreeBSD_mips64::GetRegisterInfo() const {
assert(m_target_arch.GetCore() == ArchSpec::eCore_mips64);
return g_register_infos_mips64;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
index 043e638..5e5de71 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
@@ -19,6 +19,10 @@ public:
size_t GetGPRSize() const override;
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) const;
+
+ size_t GetRegisterSetCount() const;
+
const lldb_private::RegisterInfo *GetRegisterInfo() const override;
uint32_t GetRegisterCount() const override;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp
index 0fc47fc..cc0d696 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp
@@ -10,8 +10,6 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/AddressRange.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Value.h"
@@ -28,6 +26,8 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
#include "lldb/lldb-private.h"
#include "RegisterContextHistory.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index ba84c40..bd73a29 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -9,8 +9,6 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/AddressRange.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Value.h"
@@ -31,6 +29,8 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
#include "lldb/lldb-private.h"
#include "RegisterContextLLDB.h"
@@ -297,6 +297,14 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
return;
}
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+
if (log) {
UnwindLogMsg("pc = 0x%" PRIx64, pc);
addr_t reg_val;
@@ -321,15 +329,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
}
}
- ExecutionContext exe_ctx(m_thread.shared_from_this());
- Process *process = exe_ctx.GetProcessPtr();
- // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
- // this will strip bit zero in case we read a PC from memory or from the LR.
- ABI *abi = process->GetABI().get();
- if (abi)
- pc = abi->FixCodeAddress(pc);
-
- m_current_pc.SetLoadAddress(pc, &process->GetTarget());
+ const bool allow_section_end = true;
+ m_current_pc.SetLoadAddress(pc, &process->GetTarget(), allow_section_end);
// If we don't have a Module for some reason, we're not going to find
// symbol/function information - just
@@ -477,11 +478,12 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
// Or if we're in the middle of the stack (and not "above" an asynchronous
// event like sigtramp),
// and our "current" pc is the start of a function...
- if (m_sym_ctx_valid && GetNextFrame()->m_frame_type != eTrapHandlerFrame &&
+ if (GetNextFrame()->m_frame_type != eTrapHandlerFrame &&
GetNextFrame()->m_frame_type != eDebuggerFrame &&
- addr_range.GetBaseAddress().IsValid() &&
- addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() &&
- addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()) {
+ (!m_sym_ctx_valid ||
+ (addr_range.GetBaseAddress().IsValid() &&
+ addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() &&
+ addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()))) {
decr_pc_and_recompute_addr_range = true;
}
@@ -1055,7 +1057,7 @@ bool RegisterContextLLDB::ReadRegisterValueFromRegisterLocation(
case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
llvm_unreachable("FIXME debugger inferior function call unwind");
case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: {
- Error error(ReadRegisterValueFromMemory(
+ Status error(ReadRegisterValueFromMemory(
reg_info, regloc.location.target_memory_location, reg_info->byte_size,
value));
success = error.Success();
@@ -1097,7 +1099,7 @@ bool RegisterContextLLDB::WriteRegisterValueToRegisterLocation(
case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
llvm_unreachable("FIXME debugger inferior function call unwind");
case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation: {
- Error error(WriteRegisterValueToMemory(
+ Status error(WriteRegisterValueToMemory(
reg_info, regloc.location.target_memory_location, reg_info->byte_size,
value));
success = error.Success();
@@ -1514,7 +1516,7 @@ RegisterContextLLDB::SavedLocationForRegister(
unwindplan_regloc.GetDWARFExpressionLength());
dwarfexpr.SetRegisterKind(unwindplan_registerkind);
Value result;
- Error error;
+ Status error;
if (dwarfexpr.Evaluate(&exe_ctx, nullptr, nullptr, this, 0, nullptr,
nullptr, result, &error)) {
addr_t val;
@@ -1769,7 +1771,7 @@ bool RegisterContextLLDB::ReadCFAValueForRow(
GetRegisterInfoAtIndex(cfa_reg.GetAsKind(eRegisterKindLLDB));
RegisterValue reg_value;
if (reg_info) {
- Error error = ReadRegisterValueFromMemory(
+ Status error = ReadRegisterValueFromMemory(
reg_info, cfa_reg_contents, reg_info->byte_size, reg_value);
if (error.Success()) {
cfa_value = reg_value.GetAsUInt64();
@@ -1824,7 +1826,7 @@ bool RegisterContextLLDB::ReadCFAValueForRow(
row->GetCFAValue().GetDWARFExpressionLength());
dwarfexpr.SetRegisterKind(row_register_kind);
Value result;
- Error error;
+ Status error;
if (dwarfexpr.Evaluate(&exe_ctx, nullptr, nullptr, this, 0, nullptr,
nullptr, result, &error)) {
cfa_value = result.GetScalar().ULongLong();
@@ -2015,7 +2017,18 @@ bool RegisterContextLLDB::GetStartPC(addr_t &start_pc) {
return false;
if (!m_start_pc.IsValid()) {
- return ReadPC(start_pc);
+ bool read_successfully = ReadPC (start_pc);
+ if (read_successfully)
+ {
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (process_sp)
+ {
+ ABI *abi = process_sp->GetABI().get();
+ if (abi)
+ start_pc = abi->FixCodeAddress(start_pc);
+ }
+ }
+ return read_successfully;
}
start_pc = m_start_pc.GetLoadAddress(CalculateTarget().get());
return true;
@@ -2041,12 +2054,20 @@ bool RegisterContextLLDB::ReadPC(addr_t &pc) {
// unwind past that frame to help
// find the bug.
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (process_sp)
+ {
+ ABI *abi = process_sp->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+ }
+
if (m_all_registers_available == false && above_trap_handler == false &&
(pc == 0 || pc == 1)) {
return false;
- } else {
- return true;
}
+
+ return true;
} else {
return false;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
index cb22eed..7e9e77d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -21,7 +21,7 @@
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/RegisterContext.h"
-#include "lldb/Utility/RegisterNumber.h"
+#include "lldb/Target/RegisterNumber.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.h
deleted file mode 100644
index 9065bc0..0000000
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.h
+++ /dev/null
@@ -1,62 +0,0 @@
-//===-- RegisterContextLinux_arm.h -----------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_RegisterContextLinux_arm_h_
-#define liblldb_RegisterContextLinux_arm_h_
-
-#include "RegisterInfoInterface.h"
-#include "lldb/Target/RegisterContext.h"
-#include "lldb/lldb-private.h"
-
-class RegisterContextLinux_arm : public lldb_private::RegisterInfoInterface {
-public:
- struct GPR {
- uint32_t r[16]; // R0-R15
- uint32_t cpsr; // CPSR
- };
-
- struct QReg {
- uint8_t bytes[16];
- };
-
- struct FPU {
- union {
- uint32_t s[32];
- uint64_t d[32];
- QReg q[16]; // the 128-bit NEON registers
- } floats;
- uint32_t fpscr;
- };
- struct EXC {
- uint32_t exception;
- uint32_t fsr; /* Fault status */
- uint32_t far; /* Virtual Fault Address */
- };
-
- struct DBG {
- uint32_t bvr[16];
- uint32_t bcr[16];
- uint32_t wvr[16];
- uint32_t wcr[16];
- };
-
- RegisterContextLinux_arm(const lldb_private::ArchSpec &target_arch);
-
- size_t GetGPRSize() const override;
-
- const lldb_private::RegisterInfo *GetRegisterInfo() const override;
-
- uint32_t GetRegisterCount() const override;
-
-private:
- const lldb_private::RegisterInfo *m_register_info_p;
- uint32_t m_register_info_count;
-};
-
-#endif // liblldb_RegisterContextLinux_arm_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
index 6563796..2cb17cb 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
@@ -36,8 +36,7 @@ struct GPR {
struct FPR_i386 {
uint16_t fctrl; // FPU Control Word (fcw)
uint16_t fstat; // FPU Status Word (fsw)
- uint8_t ftag; // FPU Tag Word (ftw)
- uint8_t reserved_1; // Reserved
+ uint16_t ftag; // FPU Tag Word (ftw)
uint16_t fop; // Last Instruction Opcode (fop)
union {
struct {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp
index 982eefe..7b16531 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp
@@ -29,6 +29,73 @@ using namespace lldb;
#include "RegisterInfos_mips.h"
#undef DECLARE_REGISTER_INFOS_MIPS_STRUCT
+// mips general purpose registers.
+const uint32_t g_gp_regnums_mips[] = {
+ gpr_zero_mips, gpr_r1_mips, gpr_r2_mips, gpr_r3_mips,
+ gpr_r4_mips, gpr_r5_mips, gpr_r6_mips, gpr_r7_mips,
+ gpr_r8_mips, gpr_r9_mips, gpr_r10_mips, gpr_r11_mips,
+ gpr_r12_mips, gpr_r13_mips, gpr_r14_mips, gpr_r15_mips,
+ gpr_r16_mips, gpr_r17_mips, gpr_r18_mips, gpr_r19_mips,
+ gpr_r20_mips, gpr_r21_mips, gpr_r22_mips, gpr_r23_mips,
+ gpr_r24_mips, gpr_r25_mips, gpr_r26_mips, gpr_r27_mips,
+ gpr_gp_mips, gpr_sp_mips, gpr_r30_mips, gpr_ra_mips,
+ gpr_sr_mips, gpr_mullo_mips, gpr_mulhi_mips, gpr_badvaddr_mips,
+ gpr_cause_mips, gpr_pc_mips, gpr_config5_mips,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+static_assert((sizeof(g_gp_regnums_mips) / sizeof(g_gp_regnums_mips[0])) - 1 ==
+ k_num_gpr_registers_mips,
+ "g_gp_regnums_mips has wrong number of register infos");
+// mips floating point registers.
+const uint32_t g_fp_regnums_mips[] = {
+ fpr_f0_mips, fpr_f1_mips, fpr_f2_mips, fpr_f3_mips,
+ fpr_f4_mips, fpr_f5_mips, fpr_f6_mips, fpr_f7_mips,
+ fpr_f8_mips, fpr_f9_mips, fpr_f10_mips, fpr_f11_mips,
+ fpr_f12_mips, fpr_f13_mips, fpr_f14_mips, fpr_f15_mips,
+ fpr_f16_mips, fpr_f17_mips, fpr_f18_mips, fpr_f19_mips,
+ fpr_f20_mips, fpr_f21_mips, fpr_f22_mips, fpr_f23_mips,
+ fpr_f24_mips, fpr_f25_mips, fpr_f26_mips, fpr_f27_mips,
+ fpr_f28_mips, fpr_f29_mips, fpr_f30_mips, fpr_f31_mips,
+ fpr_fcsr_mips, fpr_fir_mips, fpr_config5_mips,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+static_assert((sizeof(g_fp_regnums_mips) / sizeof(g_fp_regnums_mips[0])) - 1 ==
+ k_num_fpr_registers_mips,
+ "g_fp_regnums_mips has wrong number of register infos");
+
+// mips MSA registers.
+const uint32_t g_msa_regnums_mips[] = {
+ msa_w0_mips, msa_w1_mips, msa_w2_mips, msa_w3_mips,
+ msa_w4_mips, msa_w5_mips, msa_w6_mips, msa_w7_mips,
+ msa_w8_mips, msa_w9_mips, msa_w10_mips, msa_w11_mips,
+ msa_w12_mips, msa_w13_mips, msa_w14_mips, msa_w15_mips,
+ msa_w16_mips, msa_w17_mips, msa_w18_mips, msa_w19_mips,
+ msa_w20_mips, msa_w21_mips, msa_w22_mips, msa_w23_mips,
+ msa_w24_mips, msa_w25_mips, msa_w26_mips, msa_w27_mips,
+ msa_w28_mips, msa_w29_mips, msa_w30_mips, msa_w31_mips,
+ msa_fcsr_mips, msa_fir_mips, msa_mcsr_mips, msa_mir_mips,
+ msa_config5_mips,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+static_assert((sizeof(g_msa_regnums_mips) / sizeof(g_msa_regnums_mips[0])) -
+ 1 ==
+ k_num_msa_registers_mips,
+ "g_msa_regnums_mips has wrong number of register infos");
+
+// Number of register sets provided by this context.
+constexpr size_t k_num_register_sets = 3;
+
+// Register sets for mips.
+static const RegisterSet g_reg_sets_mips[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_mips,
+ g_gp_regnums_mips},
+ {"Floating Point Registers", "fpu", k_num_fpr_registers_mips,
+ g_fp_regnums_mips},
+ {"MSA Registers", "msa", k_num_msa_registers_mips, g_msa_regnums_mips}};
+
uint32_t GetUserRegisterInfoCount(bool msa_present) {
if (msa_present)
return static_cast<uint32_t>(k_num_user_registers_mips);
@@ -56,6 +123,25 @@ const RegisterInfo *RegisterContextLinux_mips::GetRegisterInfo() const {
}
}
+const RegisterSet *
+RegisterContextLinux_mips::GetRegisterSet(size_t set) const {
+ if (set >= k_num_register_sets)
+ return nullptr;
+ switch (m_target_arch.GetMachine()) {
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return &g_reg_sets_mips[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+size_t
+RegisterContextLinux_mips::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
uint32_t RegisterContextLinux_mips::GetRegisterCount() const {
return static_cast<uint32_t>(sizeof(g_register_infos_mips) /
sizeof(g_register_infos_mips[0]));
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h
index cba4ee6..a16c4ec 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h
@@ -22,6 +22,10 @@ public:
const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) const;
+
+ size_t GetRegisterSetCount() const;
+
uint32_t GetRegisterCount() const override;
uint32_t GetUserRegisterCount() const override;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp
index c40f694..1bb16c7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp
@@ -7,7 +7,6 @@
//
//===---------------------------------------------------------------------===//
-#if defined(__mips__)
#include <stddef.h>
#include <vector>
@@ -41,6 +40,101 @@ using namespace lldb_private;
#include "RegisterInfos_mips.h"
#undef DECLARE_REGISTER_INFOS_MIPS_STRUCT
+// mips64 general purpose registers.
+const uint32_t g_gp_regnums_mips64[] = {
+ gpr_zero_mips64, gpr_r1_mips64, gpr_r2_mips64,
+ gpr_r3_mips64, gpr_r4_mips64, gpr_r5_mips64,
+ gpr_r6_mips64, gpr_r7_mips64, gpr_r8_mips64,
+ gpr_r9_mips64, gpr_r10_mips64, gpr_r11_mips64,
+ gpr_r12_mips64, gpr_r13_mips64, gpr_r14_mips64,
+ gpr_r15_mips64, gpr_r16_mips64, gpr_r17_mips64,
+ gpr_r18_mips64, gpr_r19_mips64, gpr_r20_mips64,
+ gpr_r21_mips64, gpr_r22_mips64, gpr_r23_mips64,
+ gpr_r24_mips64, gpr_r25_mips64, gpr_r26_mips64,
+ gpr_r27_mips64, gpr_gp_mips64, gpr_sp_mips64,
+ gpr_r30_mips64, gpr_ra_mips64, gpr_sr_mips64,
+ gpr_mullo_mips64, gpr_mulhi_mips64, gpr_badvaddr_mips64,
+ gpr_cause_mips64, gpr_pc_mips64, gpr_config5_mips64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+static_assert((sizeof(g_gp_regnums_mips64) / sizeof(g_gp_regnums_mips64[0])) -
+ 1 ==
+ k_num_gpr_registers_mips64,
+ "g_gp_regnums_mips64 has wrong number of register infos");
+
+// mips64 floating point registers.
+const uint32_t g_fp_regnums_mips64[] = {
+ fpr_f0_mips64, fpr_f1_mips64, fpr_f2_mips64, fpr_f3_mips64,
+ fpr_f4_mips64, fpr_f5_mips64, fpr_f6_mips64, fpr_f7_mips64,
+ fpr_f8_mips64, fpr_f9_mips64, fpr_f10_mips64, fpr_f11_mips64,
+ fpr_f12_mips64, fpr_f13_mips64, fpr_f14_mips64, fpr_f15_mips64,
+ fpr_f16_mips64, fpr_f17_mips64, fpr_f18_mips64, fpr_f19_mips64,
+ fpr_f20_mips64, fpr_f21_mips64, fpr_f22_mips64, fpr_f23_mips64,
+ fpr_f24_mips64, fpr_f25_mips64, fpr_f26_mips64, fpr_f27_mips64,
+ fpr_f28_mips64, fpr_f29_mips64, fpr_f30_mips64, fpr_f31_mips64,
+ fpr_fcsr_mips64, fpr_fir_mips64, fpr_config5_mips64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+static_assert((sizeof(g_fp_regnums_mips64) / sizeof(g_fp_regnums_mips64[0])) -
+ 1 ==
+ k_num_fpr_registers_mips64,
+ "g_fp_regnums_mips64 has wrong number of register infos");
+
+// mips64 MSA registers.
+const uint32_t g_msa_regnums_mips64[] = {
+ msa_w0_mips64, msa_w1_mips64, msa_w2_mips64, msa_w3_mips64,
+ msa_w4_mips64, msa_w5_mips64, msa_w6_mips64, msa_w7_mips64,
+ msa_w8_mips64, msa_w9_mips64, msa_w10_mips64, msa_w11_mips64,
+ msa_w12_mips64, msa_w13_mips64, msa_w14_mips64, msa_w15_mips64,
+ msa_w16_mips64, msa_w17_mips64, msa_w18_mips64, msa_w19_mips64,
+ msa_w20_mips64, msa_w21_mips64, msa_w22_mips64, msa_w23_mips64,
+ msa_w24_mips64, msa_w25_mips64, msa_w26_mips64, msa_w27_mips64,
+ msa_w28_mips64, msa_w29_mips64, msa_w30_mips64, msa_w31_mips64,
+ msa_fcsr_mips64, msa_fir_mips64, msa_mcsr_mips64, msa_mir_mips64,
+ msa_config5_mips64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+static_assert((sizeof(g_msa_regnums_mips64) / sizeof(g_msa_regnums_mips64[0])) -
+ 1 ==
+ k_num_msa_registers_mips64,
+ "g_msa_regnums_mips64 has wrong number of register infos");
+
+// Number of register sets provided by this context.
+constexpr size_t k_num_register_sets = 3;
+
+// Register sets for mips64.
+static const RegisterSet g_reg_sets_mips64[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_mips64,
+ g_gp_regnums_mips64},
+ {"Floating Point Registers", "fpu", k_num_fpr_registers_mips64,
+ g_fp_regnums_mips64},
+ {"MSA Registers", "msa", k_num_msa_registers_mips64, g_msa_regnums_mips64},
+};
+
+const RegisterSet *
+RegisterContextLinux_mips64::GetRegisterSet(size_t set) const {
+ if (set >= k_num_register_sets)
+ return nullptr;
+
+ switch (m_target_arch.GetMachine()) {
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return &g_reg_sets_mips64[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+ return nullptr;
+}
+
+size_t
+RegisterContextLinux_mips64::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
static const RegisterInfo *GetRegisterInfoPtr(const ArchSpec &target_arch) {
switch (target_arch.GetMachine()) {
case llvm::Triple::mips64:
@@ -116,4 +210,3 @@ uint32_t RegisterContextLinux_mips64::GetUserRegisterCount() const {
return m_user_register_count;
}
-#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h
index 9669b0d..d3ca9d7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h
@@ -7,8 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#if defined(__mips__)
-
#ifndef liblldb_RegisterContextLinux_mips64_H_
#define liblldb_RegisterContextLinux_mips64_H_
@@ -24,6 +22,10 @@ public:
const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) const;
+
+ size_t GetRegisterSetCount() const;
+
uint32_t GetRegisterCount() const override;
uint32_t GetUserRegisterCount() const override;
@@ -36,4 +38,3 @@ private:
#endif
-#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
index 95b106d..2d24bda 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -12,12 +12,12 @@
// C Includes
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/StreamString.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp
index 57966e1..8f0dfd2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp
@@ -14,11 +14,11 @@
// Other libraries and framework includes
// Project includes
#include "DynamicRegisterInfo.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -101,8 +101,8 @@ bool RegisterContextMemory::WriteRegister(const RegisterInfo *reg_info,
if (m_reg_data_addr != LLDB_INVALID_ADDRESS) {
const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
addr_t reg_addr = m_reg_data_addr + reg_info->byte_offset;
- Error error(WriteRegisterValueToMemory(reg_info, reg_addr,
- reg_info->byte_size, reg_value));
+ Status error(WriteRegisterValueToMemory(reg_info, reg_addr,
+ reg_info->byte_size, reg_value));
m_reg_valid[reg_num] = false;
return error.Success();
}
@@ -113,7 +113,7 @@ bool RegisterContextMemory::ReadAllRegisterValues(DataBufferSP &data_sp) {
if (m_reg_data_addr != LLDB_INVALID_ADDRESS) {
ProcessSP process_sp(CalculateProcess());
if (process_sp) {
- Error error;
+ Status error;
if (process_sp->ReadMemory(m_reg_data_addr, data_sp->GetBytes(),
data_sp->GetByteSize(),
error) == data_sp->GetByteSize()) {
@@ -130,7 +130,7 @@ bool RegisterContextMemory::WriteAllRegisterValues(
if (m_reg_data_addr != LLDB_INVALID_ADDRESS) {
ProcessSP process_sp(CalculateProcess());
if (process_sp) {
- Error error;
+ Status error;
SetAllRegisterValid(false);
if (process_sp->WriteMemory(m_reg_data_addr, data_sp->GetBytes(),
data_sp->GetByteSize(),
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h
index 55de041..cad1592 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h
@@ -16,8 +16,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/lldb-private.h"
class DynamicRegisterInfo;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp
index 4f64a8c..ca7a013 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp
@@ -47,10 +47,14 @@ typedef struct _GPR {
uint64_t ss; /* 25 */
} GPR;
-/*
- * As of NetBSD-7.99.25 there is no support for debug registers
- * https://en.wikipedia.org/wiki/X86_debug_register
- */
+struct DBG {
+ uint64_t dr[16]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+ /* Index 8-15: reserved */
+};
/*
* src/sys/arch/amd64/include/mcontext.h
@@ -66,276 +70,21 @@ struct UserArea {
GPR gpr;
uint64_t mc_tlsbase;
FPR fpr;
+ DBG dbg;
};
-//---------------------------------------------------------------------------
-// Cherry-pick parts of RegisterInfos_x86_64.h, without debug registers
-//---------------------------------------------------------------------------
-// Computes the offset of the given GPR in the user data area.
-#define GPR_OFFSET(regname) (LLVM_EXTENSION offsetof(GPR, regname))
-
-// Computes the offset of the given FPR in the extended data area.
-#define FPR_OFFSET(regname) \
- (LLVM_EXTENSION offsetof(UserArea, fpr) + \
- LLVM_EXTENSION offsetof(FPR, xstate) + \
- LLVM_EXTENSION offsetof(FXSAVE, regname))
-
-// Computes the offset of the YMM register assembled from register halves.
-// Based on DNBArchImplX86_64.cpp from debugserver
-#define YMM_OFFSET(reg_index) \
- (LLVM_EXTENSION offsetof(UserArea, fpr) + \
- LLVM_EXTENSION offsetof(FPR, xstate) + \
- LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + (32 * reg_index))
-
-// Number of bytes needed to represent a FPR.
-#define FPR_SIZE(reg) sizeof(((FXSAVE *)nullptr)->reg)
-
-// Number of bytes needed to represent the i'th FP register.
-#define FP_SIZE sizeof(((MMSReg *)nullptr)->bytes)
-
-// Number of bytes needed to represent an XMM register.
-#define XMM_SIZE sizeof(XMMReg)
-
-// Number of bytes needed to represent a YMM register.
-#define YMM_SIZE sizeof(YMMReg)
-
-// RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB
-
-// Note that the size and offset will be updated by platform-specific classes.
-#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
- { \
- #reg, alt, sizeof(((GPR *)nullptr)->reg), \
- GPR_OFFSET(reg), eEncodingUint, eFormatHex, \
- {kind1, kind2, kind3, kind4, \
- lldb_##reg##_x86_64 }, \
- nullptr, nullptr, nullptr, 0 \
- }
-
-#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
- { \
- #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \
- {kind1, kind2, kind3, kind4, \
- lldb_##name##_x86_64 }, \
- nullptr, nullptr, nullptr, 0 \
- }
-
-#define DEFINE_FP_ST(reg, i) \
- { \
- #reg #i, nullptr, FP_SIZE, \
- LLVM_EXTENSION FPR_OFFSET( \
- stmm[i]), eEncodingVector, eFormatVectorOfUInt8, \
- {dwarf_st##i##_x86_64, dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, \
- LLDB_INVALID_REGNUM, lldb_st##i##_x86_64 }, \
- nullptr, nullptr, nullptr, 0 \
- }
-
-#define DEFINE_FP_MM(reg, i) \
- { \
- #reg #i, nullptr, sizeof(uint64_t), \
- LLVM_EXTENSION FPR_OFFSET( \
- stmm[i]), eEncodingUint, eFormatHex, \
- {dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- lldb_mm##i##_x86_64 }, \
- nullptr, nullptr, nullptr, 0 \
- }
-
-#define DEFINE_XMM(reg, i) \
- { \
- #reg #i, nullptr, XMM_SIZE, \
- LLVM_EXTENSION FPR_OFFSET( \
- reg[i]), eEncodingVector, eFormatVectorOfUInt8, \
- {dwarf_##reg##i##_x86_64, dwarf_##reg##i##_x86_64, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- lldb_##reg##i##_x86_64 }, \
- nullptr, nullptr, nullptr, 0 \
- }
-
-#define DEFINE_YMM(reg, i) \
- { \
- #reg #i, nullptr, YMM_SIZE, \
- LLVM_EXTENSION YMM_OFFSET(i), eEncodingVector, eFormatVectorOfUInt8, \
- {dwarf_##reg##i##h_x86_64, \
- dwarf_##reg##i##h_x86_64, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- lldb_##reg##i##_x86_64 }, \
- nullptr, nullptr, nullptr, 0 \
- }
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, dbg) + \
+ LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
-#define DEFINE_GPR_PSEUDO_32(reg32, reg64) \
- { \
- #reg32, nullptr, 4, \
- GPR_OFFSET(reg64), eEncodingUint, eFormatHex, \
- {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- lldb_##reg32##_x86_64 }, \
- RegisterContextPOSIX_x86::g_contained_##reg64, \
- RegisterContextPOSIX_x86::g_invalidate_##reg64, nullptr, 0 \
- }
-
-#define DEFINE_GPR_PSEUDO_16(reg16, reg64) \
- { \
- #reg16, nullptr, 2, \
- GPR_OFFSET(reg64), eEncodingUint, eFormatHex, \
- {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- lldb_##reg16##_x86_64 }, \
- RegisterContextPOSIX_x86::g_contained_##reg64, \
- RegisterContextPOSIX_x86::g_invalidate_##reg64, nullptr, 0 \
- }
-
-#define DEFINE_GPR_PSEUDO_8H(reg8, reg64) \
- { \
- #reg8, nullptr, 1, GPR_OFFSET(reg64) + 1, eEncodingUint, eFormatHex, \
- {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- lldb_##reg8##_x86_64 }, \
- RegisterContextPOSIX_x86::g_contained_##reg64, \
- RegisterContextPOSIX_x86::g_invalidate_##reg64,\
- nullptr, 0 \
- }
-
-#define DEFINE_GPR_PSEUDO_8L(reg8, reg64) \
- { \
- #reg8, nullptr, 1, GPR_OFFSET(reg64), eEncodingUint, eFormatHex, \
- {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- lldb_##reg8##_x86_64 }, \
- RegisterContextPOSIX_x86::g_contained_##reg64, \
- RegisterContextPOSIX_x86::g_invalidate_##reg64,\
- nullptr, 0 \
- }
-
-static RegisterInfo g_register_infos_x86_64[] = {
- // General purpose registers. EH_Frame, DWARF,
- // Generic, Process Plugin
- DEFINE_GPR(rax, nullptr, dwarf_rax_x86_64, dwarf_rax_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(rbx, nullptr, dwarf_rbx_x86_64, dwarf_rbx_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(rcx, "arg4", dwarf_rcx_x86_64, dwarf_rcx_x86_64,
- LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM),
- DEFINE_GPR(rdx, "arg3", dwarf_rdx_x86_64, dwarf_rdx_x86_64,
- LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM),
- DEFINE_GPR(rdi, "arg1", dwarf_rdi_x86_64, dwarf_rdi_x86_64,
- LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM),
- DEFINE_GPR(rsi, "arg2", dwarf_rsi_x86_64, dwarf_rsi_x86_64,
- LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM),
- DEFINE_GPR(rbp, "fp", dwarf_rbp_x86_64, dwarf_rbp_x86_64,
- LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM),
- DEFINE_GPR(rsp, "sp", dwarf_rsp_x86_64, dwarf_rsp_x86_64,
- LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM),
- DEFINE_GPR(r8, "arg5", dwarf_r8_x86_64, dwarf_r8_x86_64,
- LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM),
- DEFINE_GPR(r9, "arg6", dwarf_r9_x86_64, dwarf_r9_x86_64,
- LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM),
- DEFINE_GPR(r10, nullptr, dwarf_r10_x86_64, dwarf_r10_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(r11, nullptr, dwarf_r11_x86_64, dwarf_r11_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(r12, nullptr, dwarf_r12_x86_64, dwarf_r12_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(r13, nullptr, dwarf_r13_x86_64, dwarf_r13_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(r14, nullptr, dwarf_r14_x86_64, dwarf_r14_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(r15, nullptr, dwarf_r15_x86_64, dwarf_r15_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(rip, "pc", dwarf_rip_x86_64, dwarf_rip_x86_64,
- LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
- DEFINE_GPR(rflags, "flags", dwarf_rflags_x86_64, dwarf_rflags_x86_64,
- LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
- DEFINE_GPR(cs, nullptr, dwarf_cs_x86_64, dwarf_cs_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(fs, nullptr, dwarf_fs_x86_64, dwarf_fs_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(gs, nullptr, dwarf_gs_x86_64, dwarf_gs_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(ss, nullptr, dwarf_ss_x86_64, dwarf_ss_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(ds, nullptr, dwarf_ds_x86_64, dwarf_ds_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_GPR(es, nullptr, dwarf_es_x86_64, dwarf_es_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
-
- DEFINE_GPR_PSEUDO_32(eax, rax), DEFINE_GPR_PSEUDO_32(ebx, rbx),
- DEFINE_GPR_PSEUDO_32(ecx, rcx), DEFINE_GPR_PSEUDO_32(edx, rdx),
- DEFINE_GPR_PSEUDO_32(edi, rdi), DEFINE_GPR_PSEUDO_32(esi, rsi),
- DEFINE_GPR_PSEUDO_32(ebp, rbp), DEFINE_GPR_PSEUDO_32(esp, rsp),
- DEFINE_GPR_PSEUDO_32(r8d, r8), DEFINE_GPR_PSEUDO_32(r9d, r9),
- DEFINE_GPR_PSEUDO_32(r10d, r10), DEFINE_GPR_PSEUDO_32(r11d, r11),
- DEFINE_GPR_PSEUDO_32(r12d, r12), DEFINE_GPR_PSEUDO_32(r13d, r13),
- DEFINE_GPR_PSEUDO_32(r14d, r14), DEFINE_GPR_PSEUDO_32(r15d, r15),
- DEFINE_GPR_PSEUDO_16(ax, rax), DEFINE_GPR_PSEUDO_16(bx, rbx),
- DEFINE_GPR_PSEUDO_16(cx, rcx), DEFINE_GPR_PSEUDO_16(dx, rdx),
- DEFINE_GPR_PSEUDO_16(di, rdi), DEFINE_GPR_PSEUDO_16(si, rsi),
- DEFINE_GPR_PSEUDO_16(bp, rbp), DEFINE_GPR_PSEUDO_16(sp, rsp),
- DEFINE_GPR_PSEUDO_16(r8w, r8), DEFINE_GPR_PSEUDO_16(r9w, r9),
- DEFINE_GPR_PSEUDO_16(r10w, r10), DEFINE_GPR_PSEUDO_16(r11w, r11),
- DEFINE_GPR_PSEUDO_16(r12w, r12), DEFINE_GPR_PSEUDO_16(r13w, r13),
- DEFINE_GPR_PSEUDO_16(r14w, r14), DEFINE_GPR_PSEUDO_16(r15w, r15),
- DEFINE_GPR_PSEUDO_8H(ah, rax), DEFINE_GPR_PSEUDO_8H(bh, rbx),
- DEFINE_GPR_PSEUDO_8H(ch, rcx), DEFINE_GPR_PSEUDO_8H(dh, rdx),
- DEFINE_GPR_PSEUDO_8L(al, rax), DEFINE_GPR_PSEUDO_8L(bl, rbx),
- DEFINE_GPR_PSEUDO_8L(cl, rcx), DEFINE_GPR_PSEUDO_8L(dl, rdx),
- DEFINE_GPR_PSEUDO_8L(dil, rdi), DEFINE_GPR_PSEUDO_8L(sil, rsi),
- DEFINE_GPR_PSEUDO_8L(bpl, rbp), DEFINE_GPR_PSEUDO_8L(spl, rsp),
- DEFINE_GPR_PSEUDO_8L(r8l, r8), DEFINE_GPR_PSEUDO_8L(r9l, r9),
- DEFINE_GPR_PSEUDO_8L(r10l, r10), DEFINE_GPR_PSEUDO_8L(r11l, r11),
- DEFINE_GPR_PSEUDO_8L(r12l, r12), DEFINE_GPR_PSEUDO_8L(r13l, r13),
- DEFINE_GPR_PSEUDO_8L(r14l, r14), DEFINE_GPR_PSEUDO_8L(r15l, r15),
-
- // i387 Floating point registers. EH_frame,
- // DWARF, Generic, Process Plugin
- DEFINE_FPR(fctrl, fctrl, dwarf_fctrl_x86_64, dwarf_fctrl_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(fstat, fstat, dwarf_fstat_x86_64, dwarf_fstat_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(mxcsr, mxcsr, dwarf_mxcsr_x86_64, dwarf_mxcsr_x86_64,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
-
- // FP registers.
- DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2),
- DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5),
- DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), DEFINE_FP_MM(mm, 0),
- DEFINE_FP_MM(mm, 1), DEFINE_FP_MM(mm, 2), DEFINE_FP_MM(mm, 3),
- DEFINE_FP_MM(mm, 4), DEFINE_FP_MM(mm, 5), DEFINE_FP_MM(mm, 6),
- DEFINE_FP_MM(mm, 7),
-
- // XMM registers
- DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2),
- DEFINE_XMM(xmm, 3), DEFINE_XMM(xmm, 4), DEFINE_XMM(xmm, 5),
- DEFINE_XMM(xmm, 6), DEFINE_XMM(xmm, 7), DEFINE_XMM(xmm, 8),
- DEFINE_XMM(xmm, 9), DEFINE_XMM(xmm, 10), DEFINE_XMM(xmm, 11),
- DEFINE_XMM(xmm, 12), DEFINE_XMM(xmm, 13), DEFINE_XMM(xmm, 14),
- DEFINE_XMM(xmm, 15),
-
- // Copy of YMM registers assembled from xmm and ymmh
- DEFINE_YMM(ymm, 0), DEFINE_YMM(ymm, 1), DEFINE_YMM(ymm, 2),
- DEFINE_YMM(ymm, 3), DEFINE_YMM(ymm, 4), DEFINE_YMM(ymm, 5),
- DEFINE_YMM(ymm, 6), DEFINE_YMM(ymm, 7), DEFINE_YMM(ymm, 8),
- DEFINE_YMM(ymm, 9), DEFINE_YMM(ymm, 10), DEFINE_YMM(ymm, 11),
- DEFINE_YMM(ymm, 12), DEFINE_YMM(ymm, 13), DEFINE_YMM(ymm, 14),
- DEFINE_YMM(ymm, 15),
-};
//---------------------------------------------------------------------------
-// End of cherry-pick of RegisterInfos_x86_64.h
+// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64
+// structure.
//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_X86_64_STRUCT
+#include "RegisterInfos_x86_64.h"
+#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
static const RegisterInfo *
PrivateGetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp
new file mode 100644
index 0000000..1f95810
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp
@@ -0,0 +1,80 @@
+//===-- RegisterContextOpenBSD_i386.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextOpenBSD_i386.h"
+#include "RegisterContextPOSIX_x86.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// /usr/include/machine/reg.h
+struct GPR {
+ uint32_t eax;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t ebx;
+ uint32_t esp;
+ uint32_t ebp;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t cs;
+ uint32_t ss;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+};
+
+struct dbreg {
+ uint32_t dr[8]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+};
+
+using FPR_i386 = FXSAVE;
+
+struct UserArea {
+ GPR gpr;
+ FPR_i386 i387;
+};
+
+#define DR_SIZE sizeof(uint32_t)
+#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(dbreg, dr[reg_index]))
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_I386_STRUCT
+#include "RegisterInfos_i386.h"
+#undef DECLARE_REGISTER_INFOS_I386_STRUCT
+
+RegisterContextOpenBSD_i386::RegisterContextOpenBSD_i386(
+ const ArchSpec &target_arch)
+ : RegisterInfoInterface(target_arch) {}
+
+size_t RegisterContextOpenBSD_i386::GetGPRSize() const { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextOpenBSD_i386::GetRegisterInfo() const {
+ switch (m_target_arch.GetMachine()) {
+ case llvm::Triple::x86:
+ return g_register_infos_i386;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+}
+
+uint32_t RegisterContextOpenBSD_i386::GetRegisterCount() const {
+ return static_cast<uint32_t>(sizeof(g_register_infos_i386) /
+ sizeof(g_register_infos_i386[0]));
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h
new file mode 100644
index 0000000..d3c1300
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h
@@ -0,0 +1,26 @@
+//===-- RegisterContextOpenBSD_i386.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextOpenBSD_i386_H_
+#define liblldb_RegisterContextOpenBSD_i386_H_
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextOpenBSD_i386 : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextOpenBSD_i386(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp
new file mode 100644
index 0000000..e7ff073
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp
@@ -0,0 +1,107 @@
+//===-- RegisterContextOpenBSD_x86_64.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextOpenBSD_x86_64.h"
+#include "RegisterContextPOSIX_x86.h"
+#include <vector>
+
+using namespace lldb_private;
+using namespace lldb;
+
+// /usr/include/machine/reg.h
+typedef struct _GPR {
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rdx;
+ uint64_t rcx;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t rax;
+ uint64_t rsp;
+ uint64_t rip;
+ uint64_t rflags;
+ uint64_t cs;
+ uint64_t ss;
+ uint64_t ds;
+ uint64_t es;
+ uint64_t fs;
+ uint64_t gs;
+} GPR;
+
+struct DBG {
+ uint64_t dr[16]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+ /* Index 8-15: reserved */
+};
+
+struct UserArea {
+ GPR gpr;
+ FPR fpr;
+ DBG dbg;
+};
+
+#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64
+// structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_X86_64_STRUCT
+#include "RegisterInfos_x86_64.h"
+#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+static const RegisterInfo *
+PrivateGetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+PrivateGetRegisterCount(const lldb_private::ArchSpec &target_arch) {
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_x86_64) /
+ sizeof(g_register_infos_x86_64[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextOpenBSD_x86_64::RegisterContextOpenBSD_x86_64(
+ const ArchSpec &target_arch)
+ : lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(PrivateGetRegisterInfoPtr(target_arch)),
+ m_register_count(PrivateGetRegisterCount(target_arch)) {}
+
+size_t RegisterContextOpenBSD_x86_64::GetGPRSize() const { return sizeof(GPR); }
+
+const RegisterInfo *RegisterContextOpenBSD_x86_64::GetRegisterInfo() const {
+ return m_register_info_p;
+}
+
+uint32_t RegisterContextOpenBSD_x86_64::GetRegisterCount() const {
+ return m_register_count;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h
new file mode 100644
index 0000000..aa2b773
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h
@@ -0,0 +1,31 @@
+//===-- RegisterContextOpenBSD_x86_64.h -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextOpenBSD_x86_64_H_
+#define liblldb_RegisterContextOpenBSD_x86_64_H_
+
+#include "RegisterInfoInterface.h"
+
+class RegisterContextOpenBSD_x86_64
+ : public lldb_private::RegisterInfoInterface {
+public:
+ RegisterContextOpenBSD_x86_64(const lldb_private::ArchSpec &target_arch);
+
+ size_t GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+ uint32_t GetRegisterCount() const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ const uint32_t m_register_count;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
index 15d155e..bb35093 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
@@ -11,13 +11,13 @@
#include <errno.h>
#include <stdint.h>
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
#include "llvm/Support/Compiler.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
index 817649e..8c5fe9d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
@@ -16,8 +16,8 @@
// Project includes
#include "RegisterInfoInterface.h"
#include "lldb-arm-register-enums.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
class ProcessMonitor;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
index 17c9dc3..89384c8 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
@@ -11,13 +11,13 @@
#include <errno.h>
#include <stdint.h>
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
#include "llvm/Support/Compiler.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
index 923e786..27251da 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
@@ -16,8 +16,8 @@
// Project includes
#include "RegisterInfoInterface.h"
#include "lldb-arm64-register-enums.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
class ProcessMonitor;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp
index 8c67fb8..6a55947 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp
@@ -11,47 +11,33 @@
#include <errno.h>
#include <stdint.h>
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
#include "llvm/Support/Compiler.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
#include "RegisterContextPOSIX_mips64.h"
+#include "RegisterContextFreeBSD_mips64.h"
+#include "RegisterContextLinux_mips64.h"
+#include "RegisterContextLinux_mips.h"
using namespace lldb_private;
using namespace lldb;
-static const uint32_t g_gpr_regnums[] = {
- gpr_zero_mips64, gpr_r1_mips64, gpr_r2_mips64, gpr_r3_mips64,
- gpr_r4_mips64, gpr_r5_mips64, gpr_r6_mips64, gpr_r7_mips64,
- gpr_r8_mips64, gpr_r9_mips64, gpr_r10_mips64, gpr_r11_mips64,
- gpr_r12_mips64, gpr_r13_mips64, gpr_r14_mips64, gpr_r15_mips64,
- gpr_r16_mips64, gpr_r17_mips64, gpr_r18_mips64, gpr_r19_mips64,
- gpr_r20_mips64, gpr_r21_mips64, gpr_r22_mips64, gpr_r23_mips64,
- gpr_r24_mips64, gpr_r25_mips64, gpr_r26_mips64, gpr_r27_mips64,
- gpr_gp_mips64, gpr_sp_mips64, gpr_r30_mips64, gpr_ra_mips64,
- gpr_sr_mips64, gpr_mullo_mips64, gpr_mulhi_mips64, gpr_badvaddr_mips64,
- gpr_cause_mips64, gpr_pc_mips64, gpr_ic_mips64, gpr_dummy_mips64};
-
-// Number of register sets provided by this context.
-enum { k_num_register_sets = 1 };
-
-static const RegisterSet g_reg_sets_mips64[k_num_register_sets] = {
- {"General Purpose Registers", "gpr", k_num_gpr_registers_mips64,
- g_gpr_regnums},
-};
-
bool RegisterContextPOSIX_mips64::IsGPR(unsigned reg) {
- return reg <= k_num_gpr_registers_mips64; // GPR's come first.
+ return reg < m_registers_count[gpr_registers_count]; // GPR's come first.
}
bool RegisterContextPOSIX_mips64::IsFPR(unsigned reg) {
- // XXX
+ int set = GetRegisterSetCount();
+ if (set > 1)
+ return reg < (m_registers_count[fpr_registers_count]
+ + m_registers_count[gpr_registers_count]);
return false;
}
@@ -60,6 +46,19 @@ RegisterContextPOSIX_mips64::RegisterContextPOSIX_mips64(
RegisterInfoInterface *register_info)
: RegisterContext(thread, concrete_frame_idx) {
m_register_info_ap.reset(register_info);
+ m_num_registers = GetRegisterCount();
+ int set = GetRegisterSetCount();
+
+ const RegisterSet *reg_set_ptr;
+ for(int i = 0; i < set; ++i) {
+ reg_set_ptr = GetRegisterSet(i);
+ m_registers_count[i] = reg_set_ptr->num_registers;
+ }
+
+ assert(m_num_registers ==
+ static_cast<uint32_t>(m_registers_count[gpr_registers_count] +
+ m_registers_count[fpr_registers_count] +
+ m_registers_count[msa_registers_count]));
// elf-core yet to support ReadFPR()
ProcessSP base = CalculateProcess();
@@ -74,18 +73,17 @@ void RegisterContextPOSIX_mips64::Invalidate() {}
void RegisterContextPOSIX_mips64::InvalidateAllRegisters() {}
unsigned RegisterContextPOSIX_mips64::GetRegisterOffset(unsigned reg) {
- assert(reg < k_num_registers_mips64 && "Invalid register number.");
+ assert(reg < m_num_registers && "Invalid register number.");
return GetRegisterInfo()[reg].byte_offset;
}
unsigned RegisterContextPOSIX_mips64::GetRegisterSize(unsigned reg) {
- assert(reg < k_num_registers_mips64 && "Invalid register number.");
+ assert(reg < m_num_registers && "Invalid register number.");
return GetRegisterInfo()[reg].byte_size;
}
size_t RegisterContextPOSIX_mips64::GetRegisterCount() {
- size_t num_registers = k_num_registers_mips64;
- return num_registers;
+ return m_register_info_ap->GetRegisterCount();
}
size_t RegisterContextPOSIX_mips64::GetGPRSize() {
@@ -101,31 +99,59 @@ const RegisterInfo *RegisterContextPOSIX_mips64::GetRegisterInfo() {
const RegisterInfo *
RegisterContextPOSIX_mips64::GetRegisterInfoAtIndex(size_t reg) {
- if (reg < k_num_registers_mips64)
+ if (reg < m_num_registers)
return &GetRegisterInfo()[reg];
else
return NULL;
}
size_t RegisterContextPOSIX_mips64::GetRegisterSetCount() {
- size_t sets = 0;
- for (size_t set = 0; set < k_num_register_sets; ++set) {
- if (IsRegisterSetAvailable(set))
- ++sets;
+ ArchSpec target_arch = m_register_info_ap->GetTargetArchitecture();
+ switch (target_arch.GetTriple().getOS()) {
+ case llvm::Triple::Linux: {
+ if ((target_arch.GetMachine() == llvm::Triple::mipsel) ||
+ (target_arch.GetMachine() == llvm::Triple::mips)) {
+ const auto *context = static_cast<const RegisterContextLinux_mips *>
+ (m_register_info_ap.get());
+ return context->GetRegisterSetCount();
+ }
+ const auto *context = static_cast<const RegisterContextLinux_mips64 *>
+ (m_register_info_ap.get());
+ return context->GetRegisterSetCount();
+ }
+ default: {
+ const auto *context = static_cast<const RegisterContextFreeBSD_mips64 *>
+ (m_register_info_ap.get());
+ return context->GetRegisterSetCount();
+ }
+
}
-
- return sets;
}
const RegisterSet *RegisterContextPOSIX_mips64::GetRegisterSet(size_t set) {
- if (IsRegisterSetAvailable(set))
- return &g_reg_sets_mips64[set];
- else
- return NULL;
+ ArchSpec target_arch = m_register_info_ap->GetTargetArchitecture();
+ switch (target_arch.GetTriple().getOS()) {
+ case llvm::Triple::Linux: {
+ if ((target_arch.GetMachine() == llvm::Triple::mipsel) ||
+ (target_arch.GetMachine() == llvm::Triple::mips)) {
+ const auto *context = static_cast<const RegisterContextLinux_mips *>
+ (m_register_info_ap.get());
+ return context->GetRegisterSet(set);
+ }
+ const auto *context = static_cast<const RegisterContextLinux_mips64 *>
+ (m_register_info_ap.get());
+ return context->GetRegisterSet(set);
+ }
+ default: {
+ const auto *context = static_cast<const RegisterContextFreeBSD_mips64 *>
+ (m_register_info_ap.get());
+ return context->GetRegisterSet(set);
+ }
+ }
}
const char *RegisterContextPOSIX_mips64::GetRegisterName(unsigned reg) {
- assert(reg < k_num_registers_mips64 && "Invalid register offset.");
+ assert(reg < m_num_registers && "Invalid register offset.");
return GetRegisterInfo()[reg].name;
}
@@ -141,7 +167,7 @@ lldb::ByteOrder RegisterContextPOSIX_mips64::GetByteOrder() {
}
bool RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index) {
- size_t num_sets = k_num_register_sets;
+ size_t num_sets = GetRegisterSetCount();
return (set_index < num_sets);
}
@@ -150,7 +176,7 @@ bool RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index) {
// object file sections that contain register numbers in them.
uint32_t RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(
lldb::RegisterKind kind, uint32_t num) {
- const uint32_t num_regs = GetRegisterCount();
+ const uint32_t num_regs = m_num_registers;
assert(kind < kNumRegisterKinds);
for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
index 90ff9d6..1695ec9 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
@@ -16,9 +16,8 @@
// Project includes
#include "RegisterContext_mips.h"
#include "RegisterInfoInterface.h"
-#include "lldb-mips-freebsd-register-enums.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
using namespace lldb_private;
@@ -26,6 +25,14 @@ class ProcessMonitor;
class RegisterContextPOSIX_mips64 : public lldb_private::RegisterContext {
public:
+
+ enum Register_count{
+ gpr_registers_count = 0,
+ fpr_registers_count,
+ msa_registers_count,
+ register_set_count
+ };
+
RegisterContextPOSIX_mips64(
lldb_private::Thread &thread, uint32_t concrete_frame_idx,
lldb_private::RegisterInfoInterface *register_info);
@@ -56,8 +63,8 @@ public:
uint32_t num) override;
protected:
- uint64_t
- m_gpr_mips64[k_num_gpr_registers_mips64]; // general purpose registers.
+ uint32_t m_num_registers;
+ uint8_t m_registers_count[register_set_count];
std::unique_ptr<lldb_private::RegisterInfoInterface>
m_register_info_ap; // Register Info Interface (FreeBSD or Linux)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
index 6a9838a..c2b73e2 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
@@ -12,13 +12,13 @@
#include <errno.h>
#include <stdint.h>
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
#include "llvm/Support/Compiler.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
index 79bb01f..50f2346 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
@@ -16,8 +16,8 @@
// Project includes
#include "RegisterContext_powerpc.h"
#include "RegisterInfoInterface.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
class ProcessMonitor;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp
index e4dbe33..b3365ee 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp
@@ -11,14 +11,14 @@
#include <errno.h>
#include <stdint.h>
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
#include "llvm/Support/Compiler.h"
#include "RegisterContextPOSIX_s390x.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h
index 1ffc45c..d533763 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h
@@ -17,8 +17,8 @@
#include "RegisterContext_s390x.h"
#include "RegisterInfoInterface.h"
#include "lldb-s390x-register-enums.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
class ProcessMonitor;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
index 99525b6..5e1bf35 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
@@ -11,14 +11,14 @@
#include <errno.h>
#include <stdint.h>
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Host/Endian.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
-#include "lldb/Target/Process.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
#include "llvm/Support/Compiler.h"
#include "RegisterContextPOSIX_x86.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
index c5afe08..aa68927 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
@@ -17,8 +17,8 @@
#include "RegisterContext_x86.h"
#include "RegisterInfoInterface.h"
#include "lldb-x86-register-enums.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
class ProcessMonitor;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
index 2b5cb00..96ad139 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
@@ -7,10 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/Error.h"
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Status.h"
#include "lldb/lldb-private.h"
#include "RegisterContextThreadMemory.h"
@@ -194,26 +194,26 @@ bool RegisterContextThreadMemory::HardwareSingleStep(bool enable) {
return false;
}
-Error RegisterContextThreadMemory::ReadRegisterValueFromMemory(
+Status RegisterContextThreadMemory::ReadRegisterValueFromMemory(
const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr,
uint32_t src_len, RegisterValue &reg_value) {
UpdateRegisterContext();
if (m_reg_ctx_sp)
return m_reg_ctx_sp->ReadRegisterValueFromMemory(reg_info, src_addr,
src_len, reg_value);
- Error error;
+ Status error;
error.SetErrorString("invalid register context");
return error;
}
-Error RegisterContextThreadMemory::WriteRegisterValueToMemory(
+Status RegisterContextThreadMemory::WriteRegisterValueToMemory(
const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr,
uint32_t dst_len, const RegisterValue &reg_value) {
UpdateRegisterContext();
if (m_reg_ctx_sp)
return m_reg_ctx_sp->WriteRegisterValueToMemory(reg_info, dst_addr, dst_len,
reg_value);
- Error error;
+ Status error;
error.SetErrorString("invalid register context");
return error;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
index 7e0a2a9..3b3b085 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
@@ -80,13 +80,13 @@ public:
bool HardwareSingleStep(bool enable) override;
- Error ReadRegisterValueFromMemory(const lldb_private::RegisterInfo *reg_info,
- lldb::addr_t src_addr, uint32_t src_len,
- RegisterValue &reg_value) override;
+ Status ReadRegisterValueFromMemory(const lldb_private::RegisterInfo *reg_info,
+ lldb::addr_t src_addr, uint32_t src_len,
+ RegisterValue &reg_value) override;
- Error WriteRegisterValueToMemory(const lldb_private::RegisterInfo *reg_info,
- lldb::addr_t dst_addr, uint32_t dst_len,
- const RegisterValue &reg_value) override;
+ Status WriteRegisterValueToMemory(const lldb_private::RegisterInfo *reg_info,
+ lldb::addr_t dst_addr, uint32_t dst_len,
+ const RegisterValue &reg_value) override;
protected:
void UpdateRegisterContext();
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
index ab2ca2b..5f6fc29 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
@@ -257,8 +257,7 @@ struct XMMReg {
struct FXSAVE {
uint16_t fctrl; // FPU Control Word (fcw)
uint16_t fstat; // FPU Status Word (fsw)
- uint8_t ftag; // FPU Tag Word (ftw)
- uint8_t reserved_1; // Reserved
+ uint16_t ftag; // FPU Tag Word (ftw)
uint16_t fop; // Last Instruction Opcode (fop)
union {
struct {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h
index 12db366..74d5d6e 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h
@@ -13,6 +13,7 @@
#include <vector>
#include "lldb/Core/ArchSpec.h"
+#include "lldb/lldb-private-types.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
index afa105f..0111b84 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
@@ -1,4 +1,4 @@
-//===-- RegisterContextLinux_arm.cpp ---------------------------*- C++ -*-===//
+//===-- RegisterInfoPOSIX_arm.cpp ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,37 +14,35 @@
#include "lldb/lldb-defines.h"
#include "llvm/Support/Compiler.h"
-#include "RegisterContextLinux_arm.h"
+#include "RegisterInfoPOSIX_arm.h"
using namespace lldb;
using namespace lldb_private;
// Based on RegisterContextDarwin_arm.cpp
#define GPR_OFFSET(idx) ((idx)*4)
-#define FPU_OFFSET(idx) ((idx)*4 + sizeof(RegisterContextLinux_arm::GPR))
+#define FPU_OFFSET(idx) ((idx)*4 + sizeof(RegisterInfoPOSIX_arm::GPR))
#define FPSCR_OFFSET \
- (LLVM_EXTENSION offsetof(RegisterContextLinux_arm::FPU, fpscr) + \
- sizeof(RegisterContextLinux_arm::GPR))
+ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm::FPU, fpscr) + \
+ sizeof(RegisterInfoPOSIX_arm::GPR))
#define EXC_OFFSET(idx) \
- ((idx)*4 + sizeof(RegisterContextLinux_arm::GPR) + \
- sizeof(RegisterContextLinux_arm::FPU))
+ ((idx)*4 + sizeof(RegisterInfoPOSIX_arm::GPR) + \
+ sizeof(RegisterInfoPOSIX_arm::FPU))
#define DBG_OFFSET(reg) \
- ((LLVM_EXTENSION offsetof(RegisterContextLinux_arm::DBG, reg) + \
- sizeof(RegisterContextLinux_arm::GPR) + \
- sizeof(RegisterContextLinux_arm::FPU) + \
- sizeof(RegisterContextLinux_arm::EXC)))
+ ((LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm::DBG, reg) + \
+ sizeof(RegisterInfoPOSIX_arm::GPR) + sizeof(RegisterInfoPOSIX_arm::FPU) + \
+ sizeof(RegisterInfoPOSIX_arm::EXC)))
#define DEFINE_DBG(reg, i) \
- #reg, NULL, sizeof(((RegisterContextLinux_arm::DBG *) NULL)->reg[i]), \
+ #reg, NULL, sizeof(((RegisterInfoPOSIX_arm::DBG *) NULL)->reg[i]), \
DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, \
{LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
dbg_##reg##i }, \
NULL, NULL, NULL, 0
#define REG_CONTEXT_SIZE \
- (sizeof(RegisterContextLinux_arm::GPR) + \
- sizeof(RegisterContextLinux_arm::FPU) + \
- sizeof(RegisterContextLinux_arm::EXC))
+ (sizeof(RegisterInfoPOSIX_arm::GPR) + sizeof(RegisterInfoPOSIX_arm::FPU) + \
+ sizeof(RegisterInfoPOSIX_arm::EXC))
//-----------------------------------------------------------------------------
// Include RegisterInfos_arm to declare our g_register_infos_arm structure.
@@ -76,21 +74,21 @@ GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
}
}
-RegisterContextLinux_arm::RegisterContextLinux_arm(
+RegisterInfoPOSIX_arm::RegisterInfoPOSIX_arm(
const lldb_private::ArchSpec &target_arch)
: lldb_private::RegisterInfoInterface(target_arch),
m_register_info_p(GetRegisterInfoPtr(target_arch)),
m_register_info_count(GetRegisterInfoCount(target_arch)) {}
-size_t RegisterContextLinux_arm::GetGPRSize() const {
- return sizeof(struct RegisterContextLinux_arm::GPR);
+size_t RegisterInfoPOSIX_arm::GetGPRSize() const {
+ return sizeof(struct RegisterInfoPOSIX_arm::GPR);
}
const lldb_private::RegisterInfo *
-RegisterContextLinux_arm::GetRegisterInfo() const {
+RegisterInfoPOSIX_arm::GetRegisterInfo() const {
return m_register_info_p;
}
-uint32_t RegisterContextLinux_arm::GetRegisterCount() const {
+uint32_t RegisterInfoPOSIX_arm::GetRegisterCount() const {
return m_register_info_count;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
index 422ecb7..d90aec1 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
@@ -1,4 +1,4 @@
-//===-- RegisterContextFreeBSD_arm.h ----------------------------*- C++ -*-===//
+//===-- RegisterInfoPOSIX_arm.h ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,14 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#ifndef liblldb_RegisterContextFreeBSD_arm_h_
-#define liblldb_RegisterContextFreeBSD_arm_h_
+#ifndef liblldb_RegisterInfoPOSIX_arm_h_
+#define liblldb_RegisterInfoPOSIX_arm_h_
#include "RegisterInfoInterface.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/lldb-private.h"
-class RegisterContextFreeBSD_arm : public lldb_private::RegisterInfoInterface {
+class RegisterInfoPOSIX_arm : public lldb_private::RegisterInfoInterface {
public:
struct GPR {
uint32_t r[16]; // R0-R15
@@ -46,7 +46,7 @@ public:
uint32_t wcr[16];
};
- RegisterContextFreeBSD_arm(const lldb_private::ArchSpec &target_arch);
+ RegisterInfoPOSIX_arm(const lldb_private::ArchSpec &target_arch);
size_t GetGPRSize() const override;
@@ -59,4 +59,4 @@ private:
uint32_t m_register_info_count;
};
-#endif // liblldb_RegisterContextFreeBSD_arm_h_
+#endif // liblldb_RegisterInfoPOSIX_arm_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
index 2ba8059..8861ecd 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
@@ -148,7 +148,7 @@
DR_OFFSET(i), eEncodingUint, eFormatHex, \
{LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- LLDB_INVALID_REGNUM }, \
+ lldb_##reg##i##_x86_64 }, \
nullptr, nullptr, nullptr, 0 \
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
index 3b29a18..435f3d1 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -15,7 +15,6 @@
// Project includes
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ExecutionContext.h"
@@ -25,6 +24,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
index b3cac1c..5ff928c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -24,15 +24,11 @@ ThreadMemory::ThreadMemory(Process &process, tid_t tid,
: Thread(process, tid), m_backing_thread_sp(),
m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue() {}
-ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid, const char *name,
- const char *queue, lldb::addr_t register_data_addr)
+ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid,
+ llvm::StringRef name, llvm::StringRef queue,
+ lldb::addr_t register_data_addr)
: Thread(process, tid), m_backing_thread_sp(), m_thread_info_valobj_sp(),
- m_name(), m_queue(), m_register_data_addr(register_data_addr) {
- if (name)
- m_name = name;
- if (queue)
- m_queue = queue;
-}
+ m_name(name), m_queue(queue), m_register_data_addr(register_data_addr) {}
ThreadMemory::~ThreadMemory() { DestroyThread(); }
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.h
index 095544d..8922971 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.h
@@ -24,7 +24,7 @@ public:
const lldb::ValueObjectSP &thread_info_valobj_sp);
ThreadMemory(lldb_private::Process &process, lldb::tid_t tid,
- const char *name, const char *queue,
+ llvm::StringRef name, llvm::StringRef queue,
lldb::addr_t register_data_addr);
~ThreadMemory() override;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp
index 6e2a9a9..2b34bdd 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -7,7 +7,6 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/FuncUnwinders.h"
#include "lldb/Symbol/Function.h"
@@ -17,6 +16,7 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
#include "RegisterContextLLDB.h"
#include "UnwindLLDB.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h
index b932303..3f84649 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h
@@ -16,11 +16,11 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
#include "lldb/Symbol/FuncUnwinders.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-public.h"
namespace lldb_private {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
index e2691be..f907735 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
@@ -105,7 +105,7 @@ size_t UnwindMacOSXFrameBackchain::GetStackFrameData_i386(
m_cursors.push_back(cursor);
const size_t k_frame_size = sizeof(frame);
- Error error;
+ Status error;
while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) {
// Read both the FP and PC (8 bytes)
if (process->ReadMemory(frame.fp, &frame.fp, k_frame_size, error) !=
@@ -196,7 +196,7 @@ size_t UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64(
Frame_x86_64 frame = {cursor.fp, cursor.pc};
m_cursors.push_back(cursor);
- Error error;
+ Status error;
const size_t k_frame_size = sizeof(frame);
while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0)) {
// Read both the FP and PC (16 bytes)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 6ac308f..71eb643 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -14,8 +14,6 @@
#include <mutex>
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
@@ -25,8 +23,12 @@
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataBufferLLVM.h"
+#include "lldb/Utility/Log.h"
-#include "llvm/Support/ELF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/Threading.h"
#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
@@ -56,9 +58,12 @@ lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp,
lldb::ProcessSP process_sp;
if (crash_file) {
// Read enough data for a ELF32 header or ELF64 header
+ // Note: Here we care about e_type field only, so it is safe
+ // to ignore possible presence of the header extension.
const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr);
- lldb::DataBufferSP data_sp(crash_file->ReadFileContents(0, header_size));
+ auto data_sp = DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(),
+ header_size, 0);
if (data_sp && data_sp->GetByteSize() == header_size &&
elf::ELFHeader::MagicBytesMatch(data_sp->GetBytes())) {
elf::ELFHeader elf_header;
@@ -79,8 +84,8 @@ bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
// For now we are just making sure the file exists for a given module
if (!m_core_module_sp && m_core_file.Exists()) {
ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture());
- Error error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
- NULL, NULL, NULL));
+ Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
+ NULL, NULL, NULL));
if (m_core_module_sp) {
ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
@@ -152,8 +157,8 @@ lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment(
//----------------------------------------------------------------------
// Process Control
//----------------------------------------------------------------------
-Error ProcessElfCore::DoLoadCore() {
- Error error;
+Status ProcessElfCore::DoLoadCore() {
+ Status error;
if (!m_core_module_sp) {
error.SetErrorString("invalid core module");
return error;
@@ -209,16 +214,19 @@ Error ProcessElfCore::DoLoadCore() {
// Even if the architecture is set in the target, we need to override
// it to match the core file which is always single arch.
ArchSpec arch(m_core_module_sp->GetArchitecture());
- if (arch.IsValid())
- GetTarget().SetArchitecture(arch);
+ ArchSpec target_arch = GetTarget().GetArchitecture();
+ ArchSpec core_arch(m_core_module_sp->GetArchitecture());
+ target_arch.MergeFrom(core_arch);
+ GetTarget().SetArchitecture(target_arch);
+
SetUnixSignals(UnixSignals::Create(GetArchitecture()));
// Ensure we found at least one thread that was stopped on a signal.
bool siginfo_signal_found = false;
bool prstatus_signal_found = false;
// Check we found a signal in a SIGINFO note.
- for (const auto &thread_data: m_thread_data) {
+ for (const auto &thread_data : m_thread_data) {
if (thread_data.signo != 0)
siginfo_signal_found = true;
if (thread_data.prstatus_sig != 0)
@@ -228,7 +236,7 @@ Error ProcessElfCore::DoLoadCore() {
// If we don't have signal from SIGINFO use the signal from each threads
// PRSTATUS note.
if (prstatus_signal_found) {
- for (auto &thread_data: m_thread_data)
+ for (auto &thread_data : m_thread_data)
thread_data.signo = thread_data.prstatus_sig;
} else if (m_thread_data.size() > 0) {
// If all else fails force the first thread to be SIGSTOP
@@ -281,7 +289,7 @@ bool ProcessElfCore::UpdateThreadList(ThreadList &old_thread_list,
void ProcessElfCore::RefreshStateAfterStop() {}
-Error ProcessElfCore::DoDestroy() { return Error(); }
+Status ProcessElfCore::DoDestroy() { return Status(); }
//------------------------------------------------------------------
// Process Queries
@@ -293,14 +301,14 @@ bool ProcessElfCore::IsAlive() { return true; }
// Process Memory
//------------------------------------------------------------------
size_t ProcessElfCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
- Error &error) {
+ Status &error) {
// Don't allow the caching that lldb_private::Process::ReadMemory does
// since in core files we have it all cached our our core file anyway.
return DoReadMemory(addr, buf, size, error);
}
-Error ProcessElfCore::GetMemoryRegionInfo(lldb::addr_t load_addr,
- MemoryRegionInfo &region_info) {
+Status ProcessElfCore::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &region_info) {
region_info.Clear();
const VMRangeToPermissions::Entry *permission_entry =
m_core_range_infos.FindEntryThatContainsOrFollows(load_addr);
@@ -327,7 +335,7 @@ Error ProcessElfCore::GetMemoryRegionInfo(lldb::addr_t load_addr,
region_info.SetExecutable(MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eNo);
}
- return Error();
+ return Status();
}
region_info.GetRange().SetRangeBase(load_addr);
@@ -336,11 +344,11 @@ Error ProcessElfCore::GetMemoryRegionInfo(lldb::addr_t load_addr,
region_info.SetWritable(MemoryRegionInfo::eNo);
region_info.SetExecutable(MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eNo);
- return Error();
+ return Status();
}
size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
- Error &error) {
+ Status &error) {
ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
if (core_objfile == NULL)
@@ -365,6 +373,10 @@ size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
lldb::addr_t bytes_left =
0; // Number of bytes available in the core file from the given address
+ // Don't proceed if core file doesn't contain the actual data for this address range.
+ if (file_start == file_end)
+ return 0;
+
// Figure out how many on-disk bytes remain in this segment
// starting at the given offset
if (file_end > file_start + offset)
@@ -398,9 +410,9 @@ void ProcessElfCore::Clear() {
}
void ProcessElfCore::Initialize() {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance);
});
@@ -426,6 +438,10 @@ enum {
NT_FILE = 0x46494c45,
NT_PRXFPREG = 0x46e62b7f,
NT_SIGINFO = 0x53494749,
+ NT_OPENBSD_PROCINFO = 10,
+ NT_OPENBSD_AUXV = 11,
+ NT_OPENBSD_REGS = 20,
+ NT_OPENBSD_FPREGS = 21,
};
namespace FREEBSD {
@@ -440,6 +456,11 @@ enum {
};
}
+namespace NETBSD {
+
+enum { NT_PROCINFO = 1, NT_AUXV, NT_AMD64_REGS = 33, NT_AMD64_FPREGS = 35 };
+}
+
// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
static void ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
ArchSpec &arch) {
@@ -476,6 +497,28 @@ static void ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data) {
thread_data.name = data.GetCStr(&offset, 20);
}
+static void ParseNetBSDProcInfo(ThreadData &thread_data, DataExtractor &data) {
+ lldb::offset_t offset = 0;
+
+ int version = data.GetU32(&offset);
+ if (version != 1)
+ return;
+
+ offset += 4;
+ thread_data.signo = data.GetU32(&offset);
+}
+
+static void ParseOpenBSDProcInfo(ThreadData &thread_data, DataExtractor &data) {
+ lldb::offset_t offset = 0;
+
+ int version = data.GetU32(&offset);
+ if (version != 1)
+ return;
+
+ offset += 4;
+ thread_data.signo = data.GetU32(&offset);
+}
+
/// Parse Thread context from PT_NOTE segment and store it in the thread list
/// Notes:
/// 1) A PT_NOTE segment is composed of one or more NOTE entries.
@@ -497,7 +540,7 @@ static void ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data) {
/// new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
/// For case (b) there may be either one NT_PRPSINFO per thread, or a single
/// one that applies to all threads (depending on the platform type).
-Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
+Status ProcessElfCore::ParseThreadContextsFromNoteSegment(
const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) {
assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);
@@ -512,7 +555,7 @@ Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
ELFLinuxSigInfo siginfo;
size_t header_size;
size_t len;
- Error error;
+ Status error;
// Loop through the NOTE entires in the segment
while (offset < segment_header->p_filesz) {
@@ -564,6 +607,39 @@ Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
default:
break;
}
+ } else if (note.n_name.substr(0, 11) == "NetBSD-CORE") {
+ // NetBSD per-thread information is stored in notes named
+ // "NetBSD-CORE@nnn" so match on the initial part of the string.
+ m_os = llvm::Triple::NetBSD;
+ if (note.n_type == NETBSD::NT_PROCINFO) {
+ ParseNetBSDProcInfo(*thread_data, note_data);
+ } else if (note.n_type == NETBSD::NT_AUXV) {
+ m_auxv = DataExtractor(note_data);
+ } else if (arch.GetMachine() == llvm::Triple::x86_64 &&
+ note.n_type == NETBSD::NT_AMD64_REGS) {
+ thread_data->gpregset = note_data;
+ } else if (arch.GetMachine() == llvm::Triple::x86_64 &&
+ note.n_type == NETBSD::NT_AMD64_FPREGS) {
+ thread_data->fpregset = note_data;
+ }
+ } else if (note.n_name.substr(0, 7) == "OpenBSD") {
+ // OpenBSD per-thread information is stored in notes named
+ // "OpenBSD@nnn" so match on the initial part of the string.
+ m_os = llvm::Triple::OpenBSD;
+ switch (note.n_type) {
+ case NT_OPENBSD_PROCINFO:
+ ParseOpenBSDProcInfo(*thread_data, note_data);
+ break;
+ case NT_OPENBSD_AUXV:
+ m_auxv = DataExtractor(note_data);
+ break;
+ case NT_OPENBSD_REGS:
+ thread_data->gpregset = note_data;
+ break;
+ case NT_OPENBSD_FPREGS:
+ thread_data->fpregset = note_data;
+ break;
+ }
} else if (note.n_name == "CORE") {
switch (note.n_type) {
case NT_PRSTATUS:
@@ -583,6 +659,8 @@ Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
// The result from FXSAVE is in NT_PRXFPREG for i386 core files
if (arch.GetCore() == ArchSpec::eCore_x86_64_x86_64)
thread_data->fpregset = note_data;
+ else if(arch.IsMIPS())
+ thread_data->fpregset = note_data;
break;
case NT_PRPSINFO:
have_prpsinfo = true;
@@ -650,6 +728,12 @@ ArchSpec ProcessElfCore::GetArchitecture() {
(ObjectFileELF *)(m_core_module_sp->GetObjectFile());
ArchSpec arch;
core_file->GetArchitecture(arch);
+
+ ArchSpec target_arch = GetTarget().GetArchitecture();
+
+ if (target_arch.IsMIPS())
+ return target_arch;
+
return arch;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index a8dde47..dbf7f92 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -24,9 +24,9 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
#include "Plugins/ObjectFile/ELF/ELFHeader.h"
@@ -66,7 +66,7 @@ public:
//------------------------------------------------------------------
// Creating a new process, or attaching to an existing one
//------------------------------------------------------------------
- lldb_private::Error DoLoadCore() override;
+ lldb_private::Status DoLoadCore() override;
lldb_private::DynamicLoader *GetDynamicLoader() override;
@@ -80,7 +80,7 @@ public:
//------------------------------------------------------------------
// Process Control
//------------------------------------------------------------------
- lldb_private::Error DoDestroy() override;
+ lldb_private::Status DoDestroy() override;
void RefreshStateAfterStop() override;
@@ -93,12 +93,12 @@ public:
// Process Memory
//------------------------------------------------------------------
size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
- lldb_private::Error
+ lldb_private::Status
GetMemoryRegionInfo(lldb::addr_t load_addr,
lldb_private::MemoryRegionInfo &region_info) override;
@@ -160,7 +160,7 @@ private:
std::vector<NT_FILE_Entry> m_nt_file_entries;
// Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
- lldb_private::Error ParseThreadContextsFromNoteSegment(
+ lldb_private::Status ParseThreadContextsFromNoteSegment(
const elf::ELFProgramHeader *segment_header,
lldb_private::DataExtractor segment_data);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
index c0850e5..e095eac 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
@@ -15,8 +15,8 @@
// Other libraries and framework includes
// Project includes
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
class RegisterContextCorePOSIX_arm : public RegisterContextPOSIX_arm {
public:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
index da3e5bf..3a2bbdb 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
@@ -15,8 +15,8 @@
// Other libraries and framework includes
// Project includes
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 {
public:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
index 6a168d3..7549cf0 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
@@ -22,6 +22,10 @@ RegisterContextCorePOSIX_mips64::RegisterContextCorePOSIX_mips64(
new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize()));
m_gpr.SetData(m_gpr_buffer);
m_gpr.SetByteOrder(gpregset.GetByteOrder());
+ m_fpr_buffer.reset(
+ new DataBufferHeap(fpregset.GetDataStart(), fpregset.GetByteSize()));
+ m_fpr.SetData(m_fpr_buffer);
+ m_fpr.SetByteOrder(fpregset.GetByteOrder());
}
RegisterContextCorePOSIX_mips64::~RegisterContextCorePOSIX_mips64() {}
@@ -42,12 +46,24 @@ bool RegisterContextCorePOSIX_mips64::WriteFPR() {
bool RegisterContextCorePOSIX_mips64::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &value) {
+
lldb::offset_t offset = reg_info->byte_offset;
- uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
- if (offset == reg_info->byte_offset + reg_info->byte_size) {
+ lldb_private::ArchSpec arch = m_register_info_ap->GetTargetArchitecture();
+ uint64_t v;
+ if (IsGPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ if (reg_info->byte_size == 4 && !(arch.GetMachine() == llvm::Triple::mips64el))
+ // In case of 32bit core file, the register data are placed at 4 byte
+ // offset.
+ offset = offset / 2;
+ v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
value = v;
return true;
- }
+ } else if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ offset = offset - sizeof(GPR_linux_mips);
+ v =m_fpr.GetMaxU64(&offset, reg_info->byte_size);
+ value = v;
+ return true;
+ }
return false;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
index b1deca3..2cb527a 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
@@ -15,8 +15,8 @@
// Other libraries and framework includes
// Project includes
#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
class RegisterContextCorePOSIX_mips64 : public RegisterContextPOSIX_mips64 {
public:
@@ -51,7 +51,9 @@ protected:
private:
lldb::DataBufferSP m_gpr_buffer;
+ lldb::DataBufferSP m_fpr_buffer;
lldb_private::DataExtractor m_gpr;
+ lldb_private::DataExtractor m_fpr;
};
#endif // liblldb_RegisterContextCorePOSIX_mips64_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp
index edfa190..62f6413 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp
@@ -9,9 +9,9 @@
#include "RegisterContextPOSIXCore_powerpc.h"
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h
index 8e6315f..aaa95e5 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h
@@ -15,7 +15,7 @@
// Other libraries and framework includes
// Project includes
#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/DataExtractor.h"
class RegisterContextCorePOSIX_powerpc : public RegisterContextPOSIX_powerpc {
public:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp
index 6db8177..b3530a8 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp
@@ -9,9 +9,9 @@
#include "RegisterContextPOSIXCore_s390x.h"
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h
index 516e5c5..2b4ae10 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h
@@ -15,7 +15,7 @@
// Other libraries and framework includes
// Project includes
#include "Plugins/Process/Utility/RegisterContextPOSIX_s390x.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/DataExtractor.h"
class RegisterContextCorePOSIX_s390x : public RegisterContextPOSIX_s390x {
public:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
index 7f8223f..5766923 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
@@ -8,9 +8,9 @@
//===----------------------------------------------------------------------===//
#include "RegisterContextPOSIXCore_x86_64.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h"
using namespace lldb_private;
@@ -71,7 +71,7 @@ bool RegisterContextCorePOSIX_x86_64::ReadRegister(const RegisterInfo *reg_info,
return false;
}
- Error error;
+ Status error;
value.SetFromMemoryData(reg_info, src + offset, reg_info->byte_size,
lldb::eByteOrderLittle, error);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
index 0143146..2f36622 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -7,22 +7,26 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
-#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
-#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_mips64.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_mips.h"
#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
//#include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextOpenBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
#include "ProcessElfCore.h"
#include "RegisterContextPOSIXCore_arm.h"
@@ -88,7 +92,7 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
reg_interface = new RegisterInfoPOSIX_arm64(arch);
break;
case llvm::Triple::arm:
- reg_interface = new RegisterContextFreeBSD_arm(arch);
+ reg_interface = new RegisterInfoPOSIX_arm(arch);
break;
case llvm::Triple::ppc:
reg_interface = new RegisterContextFreeBSD_powerpc32(arch);
@@ -111,14 +115,33 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
break;
}
+ case llvm::Triple::NetBSD: {
+ switch (arch.GetMachine()) {
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextNetBSD_x86_64(arch);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
case llvm::Triple::Linux: {
switch (arch.GetMachine()) {
case llvm::Triple::arm:
- reg_interface = new RegisterContextLinux_arm(arch);
+ reg_interface = new RegisterInfoPOSIX_arm(arch);
break;
case llvm::Triple::aarch64:
reg_interface = new RegisterInfoPOSIX_arm64(arch);
break;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips:
+ reg_interface = new RegisterContextLinux_mips(arch);
+ break;
+ case llvm::Triple::mips64el:
+ case llvm::Triple::mips64:
+ reg_interface = new RegisterContextLinux_mips64(arch);
+ break;
// case llvm::Triple::systemz:
// reg_interface = new RegisterContextLinux_s390x(arch);
// break;
@@ -134,6 +157,26 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
break;
}
+ case llvm::Triple::OpenBSD: {
+ switch (arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ reg_interface = new RegisterInfoPOSIX_arm64(arch);
+ break;
+ case llvm::Triple::arm:
+ reg_interface = new RegisterInfoPOSIX_arm(arch);
+ break;
+ case llvm::Triple::x86:
+ reg_interface = new RegisterContextOpenBSD_i386(arch);
+ break;
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextOpenBSD_x86_64(arch);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
default:
break;
}
@@ -154,7 +197,13 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm(
*this, reg_interface, m_gpregset_data, m_fpregset_data));
break;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64(
+ *this, reg_interface, m_gpregset_data, m_fpregset_data));
+ break;
case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64(
*this, reg_interface, m_gpregset_data, m_fpregset_data));
break;
@@ -200,8 +249,33 @@ ELFLinuxPrStatus::ELFLinuxPrStatus() {
memset(this, 0, sizeof(ELFLinuxPrStatus));
}
-Error ELFLinuxPrStatus::Parse(DataExtractor &data, ArchSpec &arch) {
- Error error;
+size_t ELFLinuxPrStatus::GetSize(lldb_private::ArchSpec &arch) {
+ constexpr size_t mips_linux_pr_status_size_o32 = 96;
+ constexpr size_t mips_linux_pr_status_size_n32 = 72;
+ if (arch.IsMIPS()) {
+ std::string abi = arch.GetTargetABI();
+ assert(!abi.empty() && "ABI is not set");
+ if (!abi.compare("n64"))
+ return sizeof(ELFLinuxPrStatus);
+ else if (!abi.compare("o32"))
+ return mips_linux_pr_status_size_o32;
+ // N32 ABI
+ return mips_linux_pr_status_size_n32;
+ }
+ switch (arch.GetCore()) {
+ case lldb_private::ArchSpec::eCore_s390x_generic:
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return sizeof(ELFLinuxPrStatus);
+ case lldb_private::ArchSpec::eCore_x86_32_i386:
+ case lldb_private::ArchSpec::eCore_x86_32_i486:
+ return 72;
+ default:
+ return 0;
+ }
+}
+
+Status ELFLinuxPrStatus::Parse(DataExtractor &data, ArchSpec &arch) {
+ Status error;
if (GetSize(arch) > data.GetByteSize()) {
error.SetErrorStringWithFormat(
"NT_PRSTATUS size should be %zu, but the remaining bytes are: %" PRIu64,
@@ -239,7 +313,6 @@ Error ELFLinuxPrStatus::Parse(DataExtractor &data, ArchSpec &arch) {
pr_cstime.tv_sec = data.GetPointer(&offset);
pr_cstime.tv_usec = data.GetPointer(&offset);
-
return error;
}
@@ -250,8 +323,29 @@ ELFLinuxPrPsInfo::ELFLinuxPrPsInfo() {
memset(this, 0, sizeof(ELFLinuxPrPsInfo));
}
-Error ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch) {
- Error error;
+size_t ELFLinuxPrPsInfo::GetSize(lldb_private::ArchSpec &arch) {
+ constexpr size_t mips_linux_pr_psinfo_size_o32_n32 = 128;
+ if (arch.IsMIPS()) {
+ uint8_t address_byte_size = arch.GetAddressByteSize();
+ if (address_byte_size == 8)
+ return sizeof(ELFLinuxPrPsInfo);
+ return mips_linux_pr_psinfo_size_o32_n32;
+ }
+
+ switch (arch.GetCore()) {
+ case lldb_private::ArchSpec::eCore_s390x_generic:
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return sizeof(ELFLinuxPrPsInfo);
+ case lldb_private::ArchSpec::eCore_x86_32_i386:
+ case lldb_private::ArchSpec::eCore_x86_32_i486:
+ return 124;
+ default:
+ return 0;
+ }
+}
+
+Status ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch) {
+ Status error;
ByteOrder byteorder = data.GetByteOrder();
if (GetSize(arch) > data.GetByteSize()) {
error.SetErrorStringWithFormat(
@@ -273,9 +367,15 @@ Error ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch) {
pr_flag = data.GetPointer(&offset);
+ if (arch.IsMIPS()) {
+ // The pr_uid and pr_gid is always 32 bit irrespective of platforms
+ pr_uid = data.GetU32(&offset);
+ pr_gid = data.GetU32(&offset);
+ } else {
// 16 bit on 32 bit platforms, 32 bit on 64 bit platforms
pr_uid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1);
pr_gid = data.GetMaxU64(&offset, data.GetAddressByteSize() >> 1);
+ }
pr_pid = data.GetU32(&offset);
pr_ppid = data.GetU32(&offset);
@@ -296,12 +396,25 @@ Error ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch) {
//----------------------------------------------------------------
// Parse SIGINFO from NOTE entry
//----------------------------------------------------------------
-ELFLinuxSigInfo::ELFLinuxSigInfo() {
- memset(this, 0, sizeof(ELFLinuxSigInfo));
+ELFLinuxSigInfo::ELFLinuxSigInfo() { memset(this, 0, sizeof(ELFLinuxSigInfo)); }
+
+size_t ELFLinuxSigInfo::GetSize(const lldb_private::ArchSpec &arch) {
+ if (arch.IsMIPS())
+ return sizeof(ELFLinuxSigInfo);
+ switch (arch.GetCore()) {
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return sizeof(ELFLinuxSigInfo);
+ case lldb_private::ArchSpec::eCore_s390x_generic:
+ case lldb_private::ArchSpec::eCore_x86_32_i386:
+ case lldb_private::ArchSpec::eCore_x86_32_i486:
+ return 12;
+ default:
+ return 0;
+ }
}
-Error ELFLinuxSigInfo::Parse(DataExtractor &data, const ArchSpec &arch) {
- Error error;
+Status ELFLinuxSigInfo::Parse(DataExtractor &data, const ArchSpec &arch) {
+ Status error;
if (GetSize(arch) > data.GetByteSize()) {
error.SetErrorStringWithFormat(
"NT_SIGINFO size should be %zu, but the remaining bytes are: %" PRIu64,
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
index 1957ac2..5218754 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
@@ -16,8 +16,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h"
struct compat_timeval {
alignas(8) uint64_t tv_sec;
@@ -57,26 +57,15 @@ struct ELFLinuxPrStatus {
ELFLinuxPrStatus();
- lldb_private::Error Parse(lldb_private::DataExtractor &data,
- lldb_private::ArchSpec &arch);
+ lldb_private::Status Parse(lldb_private::DataExtractor &data,
+ lldb_private::ArchSpec &arch);
// Return the bytesize of the structure
// 64 bit - just sizeof
// 32 bit - hardcoded because we are reusing the struct, but some of the
// members are smaller -
// so the layout is not the same
- static size_t GetSize(lldb_private::ArchSpec &arch) {
- switch (arch.GetCore()) {
- case lldb_private::ArchSpec::eCore_s390x_generic:
- case lldb_private::ArchSpec::eCore_x86_64_x86_64:
- return sizeof(ELFLinuxPrStatus);
- case lldb_private::ArchSpec::eCore_x86_32_i386:
- case lldb_private::ArchSpec::eCore_x86_32_i486:
- return 72;
- default:
- return 0;
- }
- }
+ static size_t GetSize(lldb_private::ArchSpec &arch);
};
static_assert(sizeof(ELFLinuxPrStatus) == 112,
@@ -89,26 +78,15 @@ struct ELFLinuxSigInfo {
ELFLinuxSigInfo();
- lldb_private::Error Parse(lldb_private::DataExtractor &data,
- const lldb_private::ArchSpec &arch);
+ lldb_private::Status Parse(lldb_private::DataExtractor &data,
+ const lldb_private::ArchSpec &arch);
// Return the bytesize of the structure
// 64 bit - just sizeof
// 32 bit - hardcoded because we are reusing the struct, but some of the
// members are smaller -
// so the layout is not the same
- static size_t GetSize(const lldb_private::ArchSpec &arch) {
- switch (arch.GetCore()) {
- case lldb_private::ArchSpec::eCore_x86_64_x86_64:
- return sizeof(ELFLinuxSigInfo);
- case lldb_private::ArchSpec::eCore_s390x_generic:
- case lldb_private::ArchSpec::eCore_x86_32_i386:
- case lldb_private::ArchSpec::eCore_x86_32_i486:
- return 12;
- default:
- return 0;
- }
- }
+ static size_t GetSize(const lldb_private::ArchSpec &arch);
};
static_assert(sizeof(ELFLinuxSigInfo) == 12,
@@ -135,26 +113,15 @@ struct ELFLinuxPrPsInfo {
ELFLinuxPrPsInfo();
- lldb_private::Error Parse(lldb_private::DataExtractor &data,
- lldb_private::ArchSpec &arch);
+ lldb_private::Status Parse(lldb_private::DataExtractor &data,
+ lldb_private::ArchSpec &arch);
// Return the bytesize of the structure
// 64 bit - just sizeof
// 32 bit - hardcoded because we are reusing the struct, but some of the
// members are smaller -
// so the layout is not the same
- static size_t GetSize(lldb_private::ArchSpec &arch) {
- switch (arch.GetCore()) {
- case lldb_private::ArchSpec::eCore_s390x_generic:
- case lldb_private::ArchSpec::eCore_x86_64_x86_64:
- return sizeof(ELFLinuxPrPsInfo);
- case lldb_private::ArchSpec::eCore_x86_32_i386:
- case lldb_private::ArchSpec::eCore_x86_32_i486:
- return 124;
- default:
- return 0;
- }
- }
+ static size_t GetSize(lldb_private::ArchSpec &arch);
};
static_assert(sizeof(ELFLinuxPrPsInfo) == 136,
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index bd87521..0c4df7e 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -16,12 +16,8 @@
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Core/Log.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Pipe.h"
@@ -30,6 +26,10 @@
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ScopedPrinter.h"
@@ -72,7 +72,7 @@ void GDBRemoteCommunication::History::AddPacket(char packet_char,
m_packets[idx].type = type;
m_packets[idx].bytes_transmitted = bytes_transmitted;
m_packets[idx].packet_idx = m_total_packet_count;
- m_packets[idx].tid = Host::GetCurrentThreadID();
+ m_packets[idx].tid = llvm::get_threadid();
}
}
@@ -87,7 +87,7 @@ void GDBRemoteCommunication::History::AddPacket(const std::string &src,
m_packets[idx].type = type;
m_packets[idx].bytes_transmitted = bytes_transmitted;
m_packets[idx].packet_idx = m_total_packet_count;
- m_packets[idx].tid = Host::GetCurrentThreadID();
+ m_packets[idx].tid = llvm::get_threadid();
}
}
@@ -319,10 +319,9 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
Timeout<std::micro> timeout,
bool sync_on_timeout) {
uint8_t buffer[8192];
- Error error;
+ Status error;
- Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS |
- GDBR_LOG_VERBOSE));
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
// Check for a packet from our cache first without trying any reading...
if (CheckForPacket(NULL, 0, packet) != PacketType::Invalid)
@@ -334,12 +333,11 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
lldb::ConnectionStatus status = eConnectionStatusNoConnection;
size_t bytes_read = Read(buffer, sizeof(buffer), timeout, status, &error);
- if (log)
- log->Printf("%s: Read (buffer, (sizeof(buffer), timeout = %ld us, "
- "status = %s, error = %s) => bytes_read = %" PRIu64,
- LLVM_PRETTY_FUNCTION, long(timeout ? timeout->count() : -1),
- Communication::ConnectionStatusAsCString(status),
- error.AsCString(), (uint64_t)bytes_read);
+ LLDB_LOGV(log,
+ "Read(buffer, sizeof(buffer), timeout = {0}, "
+ "status = {1}, error = {2}) => bytes_read = {3}",
+ timeout, Communication::ConnectionStatusAsCString(status), error,
+ bytes_read);
if (bytes_read > 0) {
if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid)
@@ -607,10 +605,10 @@ bool GDBRemoteCommunication::DecompressPacket() {
m_compression_type == CompressionType::LZFSE ||
m_compression_type == CompressionType::LZ4)) {
compression_algorithm compression_type;
- if (m_compression_type == CompressionType::ZlibDeflate)
- compression_type = COMPRESSION_ZLIB;
- else if (m_compression_type == CompressionType::LZFSE)
+ if (m_compression_type == CompressionType::LZFSE)
compression_type = COMPRESSION_LZFSE;
+ else if (m_compression_type == CompressionType::ZlibDeflate)
+ compression_type = COMPRESSION_ZLIB;
else if (m_compression_type == CompressionType::LZ4)
compression_type = COMPRESSION_LZ4_RAW;
else if (m_compression_type == CompressionType::LZMA)
@@ -935,9 +933,9 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len,
return GDBRemoteCommunication::PacketType::Invalid;
}
-Error GDBRemoteCommunication::StartListenThread(const char *hostname,
- uint16_t port) {
- Error error;
+Status GDBRemoteCommunication::StartListenThread(const char *hostname,
+ uint16_t port) {
+ Status error;
if (m_listen_thread.IsJoinable()) {
error.SetErrorString("listen thread already running");
} else {
@@ -964,7 +962,7 @@ bool GDBRemoteCommunication::JoinListenThread() {
lldb::thread_result_t
GDBRemoteCommunication::ListenThread(lldb::thread_arg_t arg) {
GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg;
- Error error;
+ Status error;
ConnectionFileDescriptor *connection =
(ConnectionFileDescriptor *)comm->GetConnection();
@@ -977,7 +975,7 @@ GDBRemoteCommunication::ListenThread(lldb::thread_arg_t arg) {
return NULL;
}
-Error GDBRemoteCommunication::StartDebugserverProcess(
+Status GDBRemoteCommunication::StartDebugserverProcess(
const char *url, Platform *platform, ProcessLaunchInfo &launch_info,
uint16_t *port, const Args *inferior_args, int pass_comm_fd) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
@@ -986,7 +984,7 @@ Error GDBRemoteCommunication::StartDebugserverProcess(
__FUNCTION__, url ? url : "<empty>",
port ? *port : uint16_t(0));
- Error error;
+ Status error;
// If we locate debugserver, keep that located version around
static FileSpec g_debugserver_file_spec;
@@ -1085,8 +1083,7 @@ Error GDBRemoteCommunication::StartDebugserverProcess(
// port is null when debug server should listen on domain socket -
// we're not interested in port value but rather waiting for debug server
// to become available.
- if (pass_comm_fd == -1 &&
- ((port != nullptr && *port == 0) || port == nullptr)) {
+ if (pass_comm_fd == -1) {
if (url) {
// Create a temporary file to get the stdout/stderr and redirect the
// output of the command into this file. We will later read this file
@@ -1258,11 +1255,21 @@ Error GDBRemoteCommunication::StartDebugserverProcess(
port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes);
if (error.Success() && (port != nullptr)) {
assert(num_bytes > 0 && port_cstr[num_bytes - 1] == '\0');
- *port = StringConvert::ToUInt32(port_cstr, 0);
- if (log)
- log->Printf("GDBRemoteCommunication::%s() "
- "debugserver listens %u port",
- __FUNCTION__, *port);
+ uint16_t child_port = StringConvert::ToUInt32(port_cstr, 0);
+ if (*port == 0 || *port == child_port) {
+ *port = child_port;
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "debugserver listens %u port",
+ __FUNCTION__, *port);
+ } else {
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "debugserver listening on port "
+ "%d but requested port was %d",
+ __FUNCTION__, (uint32_t)child_port,
+ (uint32_t)(*port));
+ }
} else {
if (log)
log->Printf("GDBRemoteCommunication::%s() "
@@ -1303,12 +1310,20 @@ void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); }
GDBRemoteCommunication::ScopedTimeout::ScopedTimeout(
GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout)
- : m_gdb_comm(gdb_comm) {
- m_saved_timeout = m_gdb_comm.SetPacketTimeout(timeout);
+ : m_gdb_comm(gdb_comm), m_timeout_modified(false) {
+ auto curr_timeout = gdb_comm.GetPacketTimeout();
+ // Only update the timeout if the timeout is greater than the current
+ // timeout. If the current timeout is larger, then just use that.
+ if (curr_timeout < timeout) {
+ m_timeout_modified = true;
+ m_saved_timeout = m_gdb_comm.SetPacketTimeout(timeout);
+ }
}
GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout() {
- m_gdb_comm.SetPacketTimeout(m_saved_timeout);
+ // Only restore the timeout if we set it in the constructor.
+ if (m_timeout_modified)
+ m_gdb_comm.SetPacketTimeout(m_saved_timeout);
}
// This function is called via the Communications class read thread when bytes
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
index 1f3fa17..ce90de3 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -65,9 +65,9 @@ public:
enum class PacketResult {
Success = 0, // Success
- ErrorSendFailed, // Error sending the packet
+ ErrorSendFailed, // Status sending the packet
ErrorSendAck, // Didn't get an ack back after sending a packet
- ErrorReplyFailed, // Error getting the reply
+ ErrorReplyFailed, // Status getting the reply
ErrorReplyTimeout, // Timed out waiting for reply
ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that
// was sent
@@ -89,6 +89,10 @@ public:
private:
GDBRemoteCommunication &m_gdb_comm;
std::chrono::seconds m_saved_timeout;
+ // Don't ever reduce the timeout for a packet, only increase it. If the
+ // requested timeout if less than the current timeout, we don't set it
+ // and won't need to restore it.
+ bool m_timeout_modified;
};
GDBRemoteCommunication(const char *comm_name, const char *listener_name);
@@ -127,7 +131,7 @@ public:
// Start a debugserver instance on the current host using the
// supplied connection URL.
//------------------------------------------------------------------
- Error StartDebugserverProcess(
+ Status StartDebugserverProcess(
const char *url,
Platform *platform, // If non nullptr, then check with the platform for
// the GDB server binary if it can't be located
@@ -251,8 +255,8 @@ protected:
// on m_bytes. The checksum was for the compressed packet.
bool DecompressPacket();
- Error StartListenThread(const char *hostname = "127.0.0.1",
- uint16_t port = 0);
+ Status StartListenThread(const char *hostname = "127.0.0.1",
+ uint16_t port = 0);
bool JoinListenThread();
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index b70f090..e6fd386 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -18,21 +18,19 @@
#include <sstream>
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/StreamGDBRemote.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/JSON.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
// Project includes
#include "ProcessGDBRemote.h"
@@ -87,6 +85,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient()
m_supports_jThreadExtendedInfo(eLazyBoolCalculate),
m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate),
m_supports_jGetSharedCacheInfo(eLazyBoolCalculate),
+ m_supports_QPassSignals(eLazyBoolCalculate),
+ m_supports_error_string_reply(eLazyBoolCalculate),
m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true),
m_supports_qUserName(true), m_supports_qGroupName(true),
m_supports_qThreadStopInfo(true), m_supports_z0(true),
@@ -113,7 +113,7 @@ GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() {
Disconnect();
}
-bool GDBRemoteCommunicationClient::HandshakeWithServer(Error *error_ptr) {
+bool GDBRemoteCommunicationClient::HandshakeWithServer(Status *error_ptr) {
ResetDiscoverableSettings(false);
// Start the read thread after we send the handshake ack since if we
@@ -150,6 +150,13 @@ bool GDBRemoteCommunicationClient::GetEchoSupported() {
return m_supports_qEcho == eLazyBoolYes;
}
+bool GDBRemoteCommunicationClient::GetQPassSignalsSupported() {
+ if (m_supports_QPassSignals == eLazyBoolCalculate) {
+ GetRemoteQSupported();
+ }
+ return m_supports_QPassSignals == eLazyBoolYes;
+}
+
bool GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported() {
if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) {
GetRemoteQSupported();
@@ -419,6 +426,11 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
else
m_supports_qEcho = eLazyBoolNo;
+ if (::strstr(response_cstr, "QPassSignals+"))
+ m_supports_QPassSignals = eLazyBoolYes;
+ else
+ m_supports_QPassSignals = eLazyBoolNo;
+
const char *packet_size_str = ::strstr(response_cstr, "PacketSize=");
if (packet_size_str) {
StringExtractorGDBRemote packet_response(packet_size_str +
@@ -585,6 +597,21 @@ bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported() {
return m_supports_jThreadExtendedInfo;
}
+void GDBRemoteCommunicationClient::EnableErrorStringInPacket() {
+ if (m_supports_error_string_reply == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ // We try to enable error strings in remote packets
+ // but if we fail, we just work in the older way.
+ m_supports_error_string_reply = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("QEnableErrorStrings", response, false) ==
+ PacketResult::Success) {
+ if (response.IsOKResponse()) {
+ m_supports_error_string_reply = eLazyBoolYes;
+ }
+ }
+ }
+}
+
bool GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported() {
if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) {
StringExtractorGDBRemote response;
@@ -1382,8 +1409,8 @@ bool GDBRemoteCommunicationClient::DeallocateMemory(addr_t addr) {
return false;
}
-Error GDBRemoteCommunicationClient::Detach(bool keep_stopped) {
- Error error;
+Status GDBRemoteCommunicationClient::Detach(bool keep_stopped) {
+ Status error;
if (keep_stopped) {
if (m_supports_detach_stay_stopped == eLazyBoolCalculate) {
@@ -1422,9 +1449,9 @@ Error GDBRemoteCommunicationClient::Detach(bool keep_stopped) {
return error;
}
-Error GDBRemoteCommunicationClient::GetMemoryRegionInfo(
+Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
lldb::addr_t addr, lldb_private::MemoryRegionInfo &region_info) {
- Error error;
+ Status error;
region_info.Clear();
if (m_supports_memory_region_info != eLazyBoolNo) {
@@ -1491,13 +1518,18 @@ Error GDBRemoteCommunicationClient::GetMemoryRegionInfo(
}
}
- // We got a valid address range back but no permissions -- which means
- // this is an unmapped page
- if (region_info.GetRange().IsValid() && saw_permissions == false) {
- region_info.SetReadable(MemoryRegionInfo::eNo);
- region_info.SetWritable(MemoryRegionInfo::eNo);
- region_info.SetExecutable(MemoryRegionInfo::eNo);
- region_info.SetMapped(MemoryRegionInfo::eNo);
+ if (region_info.GetRange().IsValid()) {
+ // We got a valid address range back but no permissions -- which means
+ // this is an unmapped page
+ if (!saw_permissions) {
+ region_info.SetReadable(MemoryRegionInfo::eNo);
+ region_info.SetWritable(MemoryRegionInfo::eNo);
+ region_info.SetExecutable(MemoryRegionInfo::eNo);
+ region_info.SetMapped(MemoryRegionInfo::eNo);
+ }
+ } else {
+ // We got an invalid address range back
+ error.SetErrorString("Server returned invalid range");
}
} else {
m_supports_memory_region_info = eLazyBoolNo;
@@ -1512,8 +1544,8 @@ Error GDBRemoteCommunicationClient::GetMemoryRegionInfo(
return error;
}
-Error GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) {
- Error error;
+Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) {
+ Status error;
if (m_supports_watchpoint_support_info == eLazyBoolYes) {
num = m_num_supported_hardware_watchpoints;
@@ -1551,18 +1583,18 @@ Error GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) {
return error;
}
-lldb_private::Error GDBRemoteCommunicationClient::GetWatchpointSupportInfo(
+lldb_private::Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo(
uint32_t &num, bool &after, const ArchSpec &arch) {
- Error error(GetWatchpointSupportInfo(num));
+ Status error(GetWatchpointSupportInfo(num));
if (error.Success())
error = GetWatchpointsTriggerAfterInstruction(after, arch);
return error;
}
-lldb_private::Error
+lldb_private::Status
GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction(
bool &after, const ArchSpec &arch) {
- Error error;
+ Status error;
llvm::Triple::ArchType atype = arch.GetMachine();
// we assume watchpoints will happen after running the relevant opcode
@@ -1660,7 +1692,7 @@ bool GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) {
return false;
std::string cwd;
response.GetHexByteString(cwd);
- working_dir.SetFile(cwd, false, GetHostArchitecture());
+ working_dir.SetFile(cwd, false, GetHostArchitecture().GetTriple());
return !cwd.empty();
}
return false;
@@ -1907,6 +1939,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) {
llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name);
assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat);
+ assert(triple.getObjectFormat() != llvm::Triple::Wasm);
switch (triple.getObjectFormat()) {
case llvm::Triple::MachO:
m_process_arch.SetArchitecture(eArchTypeMachO, cpu, sub);
@@ -1917,6 +1950,10 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) {
case llvm::Triple::COFF:
m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub);
break;
+ case llvm::Triple::Wasm:
+ if (log)
+ log->Printf("error: not supported target architecture");
+ return false;
case llvm::Triple::UnknownObjectFormat:
if (log)
log->Printf("error: failed to determine target architecture");
@@ -1957,29 +1994,29 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses(
bool has_name_match = false;
if (name && name[0]) {
has_name_match = true;
- NameMatchType name_match_type = match_info.GetNameMatchType();
+ NameMatch name_match_type = match_info.GetNameMatchType();
switch (name_match_type) {
- case eNameMatchIgnore:
+ case NameMatch::Ignore:
has_name_match = false;
break;
- case eNameMatchEquals:
+ case NameMatch::Equals:
packet.PutCString("name_match:equals;");
break;
- case eNameMatchContains:
+ case NameMatch::Contains:
packet.PutCString("name_match:contains;");
break;
- case eNameMatchStartsWith:
+ case NameMatch::StartsWith:
packet.PutCString("name_match:starts_with;");
break;
- case eNameMatchEndsWith:
+ case NameMatch::EndsWith:
packet.PutCString("name_match:ends_with;");
break;
- case eNameMatchRegularExpression:
+ case NameMatch::RegularExpression:
packet.PutCString("name_match:regex;");
break;
}
@@ -2190,23 +2227,19 @@ void GDBRemoteCommunicationClient::TestPacketSpeed(const uint32_t num_packets,
const duration<float> standard_deviation =
calculate_standard_deviation(packet_times);
if (json) {
- strm.Printf("%s\n {\"send_size\" : %6" PRIu32
- ", \"recv_size\" : %6" PRIu32
- ", \"total_time_nsec\" : %12" PRIu64
- ", \"standard_deviation_nsec\" : %9" PRIu64 " }",
+ strm.Format("{0}\n {{\"send_size\" : {1,6}, \"recv_size\" : "
+ "{2,6}, \"total_time_nsec\" : {3,12:ns-}, "
+ "\"standard_deviation_nsec\" : {4,9:ns-f0}}",
result_idx > 0 ? "," : "", send_size, recv_size,
- duration_cast<nanoseconds>(total_time).count(),
- duration_cast<nanoseconds>(standard_deviation).count());
+ total_time, standard_deviation);
++result_idx;
} else {
- strm.Printf(
- "qSpeedTest(send=%-7u, recv=%-7u) in %.9f"
- " sec for %9.2f packets/sec (%10.6f ms per packet) with standard "
- "deviation of %10.6f ms\n",
- send_size, recv_size, duration<float>(total_time).count(),
- packets_per_second,
- duration<float, std::milli>(average_per_packet).count(),
- duration<float, std::milli>(standard_deviation).count());
+ strm.Format("qSpeedTest(send={0,7}, recv={1,7}) in {2:s+f9} for "
+ "{3,9:f2} packets/s ({4,10:ms+f6} per packet) with "
+ "standard deviation of {5,10:ms+f6}\n",
+ send_size, recv_size, duration<float>(total_time),
+ packets_per_second, duration<float>(average_per_packet),
+ standard_deviation);
}
strm.Flush();
}
@@ -2249,21 +2282,18 @@ void GDBRemoteCommunicationClient::TestPacketSpeed(const uint32_t num_packets,
const auto average_per_packet = total_time / packet_count;
if (json) {
- strm.Printf("%s\n {\"send_size\" : %6" PRIu32
- ", \"recv_size\" : %6" PRIu32
- ", \"total_time_nsec\" : %12" PRIu64 " }",
+ strm.Format("{0}\n {{\"send_size\" : {1,6}, \"recv_size\" : "
+ "{2,6}, \"total_time_nsec\" : {3,12:ns-}}",
result_idx > 0 ? "," : "", send_size, recv_size,
- duration_cast<nanoseconds>(total_time).count());
+ total_time);
++result_idx;
} else {
- strm.Printf("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to "
- "receive %2.1fMB in %.9f"
- " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per "
- "packet)\n",
+ strm.Format("qSpeedTest(send={0,7}, recv={1,7}) {2,6} packets needed "
+ "to receive {3:f1}MB in {4:s+f9} for {5} MB/sec for "
+ "{6,9:f2} packets/sec ({7,10:ms+f6} per packet)\n",
send_size, recv_size, packet_count, k_recv_amount_mb,
- duration<float>(total_time).count(), mb_second,
- packets_per_second,
- duration<float, std::milli>(average_per_packet).count());
+ duration<float>(total_time), mb_second,
+ packets_per_second, duration<float>(average_per_packet));
}
strm.Flush();
}
@@ -2524,7 +2554,7 @@ uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket(
if (response.IsOKResponse())
return 0;
- // Error while setting breakpoint, send back specific error
+ // Status while setting breakpoint, send back specific error
if (response.IsErrorResponse())
return response.GetError();
@@ -2620,7 +2650,7 @@ lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() {
return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
}
-lldb_private::Error GDBRemoteCommunicationClient::RunShellCommand(
+lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand(
const char *command, // Shouldn't be NULL
const FileSpec &
working_dir, // Pass empty FileSpec to use the current working directory
@@ -2646,32 +2676,32 @@ lldb_private::Error GDBRemoteCommunicationClient::RunShellCommand(
if (SendPacketAndWaitForResponse(stream.GetString(), response, false) ==
PacketResult::Success) {
if (response.GetChar() != 'F')
- return Error("malformed reply");
+ return Status("malformed reply");
if (response.GetChar() != ',')
- return Error("malformed reply");
+ return Status("malformed reply");
uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX);
if (exitcode == UINT32_MAX)
- return Error("unable to run remote process");
+ return Status("unable to run remote process");
else if (status_ptr)
*status_ptr = exitcode;
if (response.GetChar() != ',')
- return Error("malformed reply");
+ return Status("malformed reply");
uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX);
if (signo_ptr)
*signo_ptr = signo;
if (response.GetChar() != ',')
- return Error("malformed reply");
+ return Status("malformed reply");
std::string output;
response.GetEscapedBinaryData(output);
if (command_output)
command_output->assign(output);
- return Error();
+ return Status();
}
- return Error("unable to send packet");
+ return Status("unable to send packet");
}
-Error GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec,
- uint32_t file_permissions) {
+Status GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec,
+ uint32_t file_permissions) {
std::string path{file_spec.GetPath(false)};
lldb_private::StreamString stream;
stream.PutCString("qPlatform_mkdir:");
@@ -2683,16 +2713,17 @@ Error GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec,
if (SendPacketAndWaitForResponse(packet, response, false) !=
PacketResult::Success)
- return Error("failed to send '%s' packet", packet.str().c_str());
+ return Status("failed to send '%s' packet", packet.str().c_str());
if (response.GetChar() != 'F')
- return Error("invalid response to '%s' packet", packet.str().c_str());
+ return Status("invalid response to '%s' packet", packet.str().c_str());
- return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
+ return Status(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
}
-Error GDBRemoteCommunicationClient::SetFilePermissions(
- const FileSpec &file_spec, uint32_t file_permissions) {
+Status
+GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions) {
std::string path{file_spec.GetPath(false)};
lldb_private::StreamString stream;
stream.PutCString("qPlatform_chmod:");
@@ -2704,16 +2735,16 @@ Error GDBRemoteCommunicationClient::SetFilePermissions(
if (SendPacketAndWaitForResponse(packet, response, false) !=
PacketResult::Success)
- return Error("failed to send '%s' packet", stream.GetData());
+ return Status("failed to send '%s' packet", stream.GetData());
if (response.GetChar() != 'F')
- return Error("invalid response to '%s' packet", stream.GetData());
+ return Status("invalid response to '%s' packet", stream.GetData());
- return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
+ return Status(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
}
static uint64_t ParseHostIOPacketResponse(StringExtractorGDBRemote &response,
- uint64_t fail_result, Error &error) {
+ uint64_t fail_result, Status &error) {
response.SetFilePos(0);
if (response.GetChar() != 'F')
return fail_result;
@@ -2733,7 +2764,7 @@ static uint64_t ParseHostIOPacketResponse(StringExtractorGDBRemote &response,
lldb::user_id_t
GDBRemoteCommunicationClient::OpenFile(const lldb_private::FileSpec &file_spec,
uint32_t flags, mode_t mode,
- Error &error) {
+ Status &error) {
std::string path(file_spec.GetPath(false));
lldb_private::StreamString stream;
stream.PutCString("vFile:open:");
@@ -2752,7 +2783,8 @@ GDBRemoteCommunicationClient::OpenFile(const lldb_private::FileSpec &file_spec,
return UINT64_MAX;
}
-bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd, Error &error) {
+bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd,
+ Status &error) {
lldb_private::StreamString stream;
stream.Printf("vFile:close:%i", (int)fd);
StringExtractorGDBRemote response;
@@ -2781,10 +2813,11 @@ lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize(
return UINT64_MAX;
}
-Error GDBRemoteCommunicationClient::GetFilePermissions(
- const FileSpec &file_spec, uint32_t &file_permissions) {
+Status
+GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions) {
std::string path{file_spec.GetPath(false)};
- Error error;
+ Status error;
lldb_private::StreamString stream;
stream.PutCString("vFile:mode:");
stream.PutCStringAsRawHex8(path.c_str());
@@ -2819,7 +2852,7 @@ Error GDBRemoteCommunicationClient::GetFilePermissions(
uint64_t GDBRemoteCommunicationClient::ReadFile(lldb::user_id_t fd,
uint64_t offset, void *dst,
uint64_t dst_len,
- Error &error) {
+ Status &error) {
lldb_private::StreamString stream;
stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len,
offset);
@@ -2853,7 +2886,7 @@ uint64_t GDBRemoteCommunicationClient::WriteFile(lldb::user_id_t fd,
uint64_t offset,
const void *src,
uint64_t src_len,
- Error &error) {
+ Status &error) {
lldb_private::StreamGDBRemote stream;
stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset);
stream.PutEscapedBytes(src, src_len);
@@ -2881,10 +2914,10 @@ uint64_t GDBRemoteCommunicationClient::WriteFile(lldb::user_id_t fd,
return 0;
}
-Error GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src,
- const FileSpec &dst) {
+Status GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src,
+ const FileSpec &dst) {
std::string src_path{src.GetPath(false)}, dst_path{dst.GetPath(false)};
- Error error;
+ Status error;
lldb_private::StreamGDBRemote stream;
stream.PutCString("vFile:symlink:");
// the unix symlink() command reverses its parameters where the dst if first,
@@ -2915,9 +2948,9 @@ Error GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src,
return error;
}
-Error GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) {
+Status GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) {
std::string path{file_spec.GetPath(false)};
- Error error;
+ Status error;
lldb_private::StreamGDBRemote stream;
stream.PutCString("vFile:unlink:");
// the unix symlink() command reverses its parameters where the dst if first,
@@ -3134,6 +3167,213 @@ bool GDBRemoteCommunicationClient::SyncThreadState(lldb::tid_t tid) {
response.IsOKResponse();
}
+lldb::user_id_t
+GDBRemoteCommunicationClient::SendStartTracePacket(const TraceOptions &options,
+ Status &error) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ lldb::user_id_t ret_uid = LLDB_INVALID_UID;
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jTraceStart:");
+
+ StructuredData::Dictionary json_packet;
+ json_packet.AddIntegerItem("type", options.getType());
+ json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize());
+ json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize());
+
+ if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+ json_packet.AddIntegerItem("threadid", options.getThreadID());
+
+ StructuredData::DictionarySP custom_params = options.getTraceParams();
+ if (custom_params)
+ json_packet.AddItem("params", custom_params);
+
+ StreamString json_string;
+ json_packet.Dump(json_string, false);
+ escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (!response.IsNormalResponse()) {
+ error = response.GetStatus();
+ LLDB_LOG(log, "Target does not support Tracing , error {0}", error);
+ } else {
+ ret_uid = response.GetHexMaxU64(false, LLDB_INVALID_UID);
+ }
+ } else {
+ LLDB_LOG(log, "failed to send packet");
+ error.SetErrorStringWithFormat("failed to send packet: '%s'",
+ escaped_packet.GetData());
+ }
+ return ret_uid;
+}
+
+Status
+GDBRemoteCommunicationClient::SendStopTracePacket(lldb::user_id_t uid,
+ lldb::tid_t thread_id) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ StringExtractorGDBRemote response;
+ Status error;
+
+ StructuredData::Dictionary json_packet;
+ StreamGDBRemote escaped_packet;
+ StreamString json_string;
+ escaped_packet.PutCString("jTraceStop:");
+
+ json_packet.AddIntegerItem("traceid", uid);
+
+ if (thread_id != LLDB_INVALID_THREAD_ID)
+ json_packet.AddIntegerItem("threadid", thread_id);
+
+ json_packet.Dump(json_string, false);
+
+ escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (!response.IsOKResponse()) {
+ error = response.GetStatus();
+ LLDB_LOG(log, "stop tracing failed");
+ }
+ } else {
+ LLDB_LOG(log, "failed to send packet");
+ error.SetErrorStringWithFormat(
+ "failed to send packet: '%s' with error '%d'", escaped_packet.GetData(),
+ response.GetError());
+ }
+ return error;
+}
+
+Status GDBRemoteCommunicationClient::SendGetDataPacket(
+ lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jTraceBufferRead:");
+ return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
+}
+
+Status GDBRemoteCommunicationClient::SendGetMetaDataPacket(
+ lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jTraceMetaRead:");
+ return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
+}
+
+Status
+GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid,
+ TraceOptions &options) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ StringExtractorGDBRemote response;
+ Status error;
+
+ StreamString json_string;
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jTraceConfigRead:");
+
+ StructuredData::Dictionary json_packet;
+ json_packet.AddIntegerItem("traceid", uid);
+
+ if (options.getThreadID() != LLDB_INVALID_THREAD_ID)
+ json_packet.AddIntegerItem("threadid", options.getThreadID());
+
+ json_packet.Dump(json_string, false);
+ escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ uint64_t type = std::numeric_limits<uint64_t>::max();
+ uint64_t buffersize = std::numeric_limits<uint64_t>::max();
+ uint64_t metabuffersize = std::numeric_limits<uint64_t>::max();
+
+ auto json_object = StructuredData::ParseJSON(response.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != lldb::eStructuredDataTypeDictionary) {
+ error.SetErrorString("Invalid Configuration obtained");
+ return error;
+ }
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("metabuffersize",
+ metabuffersize);
+ options.setMetaDataBufferSize(metabuffersize);
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("buffersize", buffersize);
+ options.setTraceBufferSize(buffersize);
+
+ json_dict->GetValueForKeyAsInteger<uint64_t>("type", type);
+ options.setType(static_cast<lldb::TraceType>(type));
+
+ StructuredData::ObjectSP custom_params_sp =
+ json_dict->GetValueForKey("params");
+ if (custom_params_sp) {
+ if (custom_params_sp->GetType() !=
+ lldb::eStructuredDataTypeDictionary) {
+ error.SetErrorString("Invalid Configuration obtained");
+ return error;
+ } else
+ options.setTraceParams(
+ static_pointer_cast<StructuredData::Dictionary>(
+ custom_params_sp));
+ }
+ } else {
+ error = response.GetStatus();
+ }
+ } else {
+ LLDB_LOG(log, "failed to send packet");
+ error.SetErrorStringWithFormat("failed to send packet: '%s'",
+ escaped_packet.GetData());
+ }
+ return error;
+}
+
+Status GDBRemoteCommunicationClient::SendGetTraceDataPacket(
+ StreamGDBRemote &packet, lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer, size_t offset) {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ Status error;
+
+ StructuredData::Dictionary json_packet;
+
+ json_packet.AddIntegerItem("traceid", uid);
+ json_packet.AddIntegerItem("offset", offset);
+ json_packet.AddIntegerItem("buffersize", buffer.size());
+
+ if (thread_id != LLDB_INVALID_THREAD_ID)
+ json_packet.AddIntegerItem("threadid", thread_id);
+
+ StreamString json_string;
+ json_packet.Dump(json_string, false);
+
+ packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize());
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response, true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ size_t filled_size = response.GetHexBytesAvail(buffer);
+ buffer = llvm::MutableArrayRef<uint8_t>(buffer.data(), filled_size);
+ } else {
+ error = response.GetStatus();
+ buffer = buffer.slice(buffer.size());
+ }
+ } else {
+ LLDB_LOG(log, "failed to send packet");
+ error.SetErrorStringWithFormat("failed to send packet: '%s'",
+ packet.GetData());
+ buffer = buffer.slice(buffer.size());
+ }
+ return error;
+}
+
bool GDBRemoteCommunicationClient::GetModuleInfo(
const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec,
ModuleSpec &module_spec) {
@@ -3193,7 +3433,7 @@ bool GDBRemoteCommunicationClient::GetModuleInfo(
StringExtractor extractor(value);
std::string path;
extractor.GetHexByteString(path);
- module_spec.GetFileSpec() = FileSpec(path, false, arch_spec);
+ module_spec.GetFileSpec() = FileSpec(path, false, arch_spec.GetTriple());
}
}
@@ -3206,12 +3446,12 @@ ParseModuleSpec(StructuredData::Dictionary *dict) {
if (!dict)
return llvm::None;
- std::string string;
+ llvm::StringRef string;
uint64_t integer;
if (!dict->GetValueForKeyAsString("uuid", string))
return llvm::None;
- result.GetUUID().SetFromCString(string.c_str(), string.size());
+ result.GetUUID().SetFromStringRef(string, string.size());
if (!dict->GetValueForKeyAsInteger("file_offset", integer))
return llvm::None;
@@ -3223,11 +3463,12 @@ ParseModuleSpec(StructuredData::Dictionary *dict) {
if (!dict->GetValueForKeyAsString("triple", string))
return llvm::None;
- result.GetArchitecture().SetTriple(string.c_str());
+ result.GetArchitecture().SetTriple(string);
if (!dict->GetValueForKeyAsString("file_path", string))
return llvm::None;
- result.GetFileSpec() = FileSpec(string, false, result.GetArchitecture());
+ result.GetFileSpec() =
+ FileSpec(string, false, result.GetArchitecture().GetTriple());
return result;
}
@@ -3254,6 +3495,9 @@ GDBRemoteCommunicationClient::GetModulesInfo(
payload.PutEscapedBytes(unescaped_payload.GetString().data(),
unescaped_payload.GetSize());
+ // Increase the timeout for jModulesInfo since this packet can take longer.
+ ScopedTimeout timeout(*this, std::chrono::seconds(10));
+
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse(payload.GetString(), response, false) !=
PacketResult::Success ||
@@ -3292,7 +3536,7 @@ GDBRemoteCommunicationClient::GetModulesInfo(
bool GDBRemoteCommunicationClient::ReadExtFeature(
const lldb_private::ConstString object,
const lldb_private::ConstString annex, std::string &out,
- lldb_private::Error &err) {
+ lldb_private::Status &err) {
std::stringstream output;
StringExtractorGDBRemote chunk;
@@ -3571,9 +3815,29 @@ GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() {
: nullptr;
}
-Error GDBRemoteCommunicationClient::ConfigureRemoteStructuredData(
+Status GDBRemoteCommunicationClient::SendSignalsToIgnore(
+ llvm::ArrayRef<int32_t> signals) {
+ // Format packet:
+ // QPassSignals:<hex_sig1>;<hex_sig2>...;<hex_sigN>
+ auto range = llvm::make_range(signals.begin(), signals.end());
+ std::string packet = formatv("QPassSignals:{0:$[;]@(x-2)}", range).str();
+
+ StringExtractorGDBRemote response;
+ auto send_status = SendPacketAndWaitForResponse(packet, response, false);
+
+ if (send_status != GDBRemoteCommunication::PacketResult::Success)
+ return Status("Sending QPassSignals packet failed");
+
+ if (response.IsOKResponse()) {
+ return Status();
+ } else {
+ return Status("Unknown error happened during sending QPassSignals packet.");
+ }
+}
+
+Status GDBRemoteCommunicationClient::ConfigureRemoteStructuredData(
const ConstString &type_name, const StructuredData::ObjectSP &config_sp) {
- Error error;
+ Status error;
if (type_name.GetLength() == 0) {
error.SetErrorString("invalid type_name argument");
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 83162a6..712d85e 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -23,8 +23,9 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/StreamGDBRemote.h"
+#include "lldb/Utility/StructuredData.h"
#include "llvm/ADT/Optional.h"
@@ -41,7 +42,7 @@ public:
// After connecting, send the handshake to the server to make sure
// we are communicating with it.
//------------------------------------------------------------------
- bool HandshakeWithServer(Error *error_ptr);
+ bool HandshakeWithServer(Status *error_ptr);
// For packets which specify a range of output to be returned,
// return all of the output via a series of request packets of the form
@@ -230,17 +231,17 @@ public:
bool DeallocateMemory(lldb::addr_t addr);
- Error Detach(bool keep_stopped);
+ Status Detach(bool keep_stopped);
- Error GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info);
+ Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info);
- Error GetWatchpointSupportInfo(uint32_t &num);
+ Status GetWatchpointSupportInfo(uint32_t &num);
- Error GetWatchpointSupportInfo(uint32_t &num, bool &after,
- const ArchSpec &arch);
+ Status GetWatchpointSupportInfo(uint32_t &num, bool &after,
+ const ArchSpec &arch);
- Error GetWatchpointsTriggerAfterInstruction(bool &after,
- const ArchSpec &arch);
+ Status GetWatchpointsTriggerAfterInstruction(bool &after,
+ const ArchSpec &arch);
const ArchSpec &GetHostArchitecture();
@@ -339,6 +340,8 @@ public:
bool GetQXferAuxvReadSupported();
+ void EnableErrorStringInPacket();
+
bool GetQXferLibrariesReadSupported();
bool GetQXferLibrariesSVR4ReadSupported();
@@ -347,6 +350,8 @@ public:
bool GetEchoSupported();
+ bool GetQPassSignalsSupported();
+
bool GetAugmentedLibrariesSVR4ReadSupported();
bool GetQXferFeaturesReadSupported();
@@ -363,33 +368,33 @@ public:
bool &sequence_mutex_unavailable);
lldb::user_id_t OpenFile(const FileSpec &file_spec, uint32_t flags,
- mode_t mode, Error &error);
+ mode_t mode, Status &error);
- bool CloseFile(lldb::user_id_t fd, Error &error);
+ bool CloseFile(lldb::user_id_t fd, Status &error);
lldb::user_id_t GetFileSize(const FileSpec &file_spec);
- Error GetFilePermissions(const FileSpec &file_spec,
- uint32_t &file_permissions);
+ Status GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions);
- Error SetFilePermissions(const FileSpec &file_spec,
- uint32_t file_permissions);
+ Status SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions);
uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
- uint64_t dst_len, Error &error);
+ uint64_t dst_len, Status &error);
uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src,
- uint64_t src_len, Error &error);
+ uint64_t src_len, Status &error);
- Error CreateSymlink(const FileSpec &src, const FileSpec &dst);
+ Status CreateSymlink(const FileSpec &src, const FileSpec &dst);
- Error Unlink(const FileSpec &file_spec);
+ Status Unlink(const FileSpec &file_spec);
- Error MakeDirectory(const FileSpec &file_spec, uint32_t mode);
+ Status MakeDirectory(const FileSpec &file_spec, uint32_t mode);
bool GetFileExists(const FileSpec &file_spec);
- Error RunShellCommand(
+ Status RunShellCommand(
const char *command, // Shouldn't be nullptr
const FileSpec &working_dir, // Pass empty FileSpec to use the current
// working directory
@@ -446,10 +451,13 @@ public:
bool ReadExtFeature(const lldb_private::ConstString object,
const lldb_private::ConstString annex, std::string &out,
- lldb_private::Error &err);
+ lldb_private::Status &err);
void ServeSymbolLookups(lldb_private::Process *process);
+ // Sends QPassSignals packet to the server with given signals to ignore.
+ Status SendSignalsToIgnore(llvm::ArrayRef<int32_t> signals);
+
//------------------------------------------------------------------
/// Return the feature set supported by the gdb-remote server.
///
@@ -490,10 +498,25 @@ public:
///
/// @see \b Process::ConfigureStructuredData(...) for details.
//------------------------------------------------------------------
- Error
+ Status
ConfigureRemoteStructuredData(const ConstString &type_name,
const StructuredData::ObjectSP &config_sp);
+ lldb::user_id_t SendStartTracePacket(const TraceOptions &options,
+ Status &error);
+
+ Status SendStopTracePacket(lldb::user_id_t uid, lldb::tid_t thread_id);
+
+ Status SendGetDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0);
+
+ Status SendGetMetaDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0);
+
+ Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options);
+
protected:
LazyBool m_supports_not_sending_acks;
LazyBool m_supports_thread_suffix;
@@ -527,6 +550,8 @@ protected:
LazyBool m_supports_jThreadExtendedInfo;
LazyBool m_supports_jLoadedDynamicLibrariesInfos;
LazyBool m_supports_jGetSharedCacheInfo;
+ LazyBool m_supports_QPassSignals;
+ LazyBool m_supports_error_string_reply;
bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1,
m_supports_qUserName : 1, m_supports_qGroupName : 1,
@@ -581,6 +606,11 @@ protected:
lldb::tid_t tid, StreamString &&payload,
StringExtractorGDBRemote &response, bool send_async);
+ Status SendGetTraceDataPacket(StreamGDBRemote &packet, lldb::user_id_t uid,
+ lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset);
+
private:
DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient);
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index 934824e..4be92b7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -20,6 +20,7 @@
// Project includes
#include "ProcessGDBRemoteLog.h"
#include "Utility/StringExtractorGDBRemote.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -27,7 +28,12 @@ using namespace lldb_private::process_gdb_remote;
GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(
const char *comm_name, const char *listener_name)
- : GDBRemoteCommunication(comm_name, listener_name), m_exit_now(false) {}
+ : GDBRemoteCommunication(comm_name, listener_name), m_exit_now(false) {
+ RegisterPacketHandler(
+ StringExtractorGDBRemote::eServerPacketType_QEnableErrorStrings,
+ [this](StringExtractorGDBRemote packet, Status &error, bool &interrupt,
+ bool &quit) { return this->Handle_QErrorStringEnable(packet); });
+}
GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() {}
@@ -39,7 +45,7 @@ void GDBRemoteCommunicationServer::RegisterPacketHandler(
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::GetPacketAndSendResponse(
- Timeout<std::micro> timeout, Error &error, bool &interrupt, bool &quit) {
+ Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) {
StringExtractorGDBRemote packet;
PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false);
@@ -100,6 +106,24 @@ GDBRemoteCommunicationServer::SendErrorResponse(uint8_t err) {
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendErrorResponse(const Status &error) {
+ if (m_send_error_strings) {
+ lldb_private::StreamString packet;
+ packet.Printf("E%2.2x;", static_cast<uint8_t>(error.GetError()));
+ packet.PutCStringAsRawHex8(error.AsCString());
+ return SendPacketNoLock(packet.GetString());
+ } else
+ return SendErrorResponse(error.GetError());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QErrorStringEnable(
+ StringExtractorGDBRemote &packet) {
+ m_send_error_strings = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendIllFormedResponse(
const StringExtractorGDBRemote &failed_packet, const char *message) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index 0c583e6..a353524 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -31,8 +31,8 @@ class GDBRemoteCommunicationServer : public GDBRemoteCommunication {
public:
using PortMap = std::map<uint16_t, lldb::pid_t>;
using PacketHandler =
- std::function<PacketResult(StringExtractorGDBRemote &packet, Error &error,
- bool &interrupt, bool &quit)>;
+ std::function<PacketResult(StringExtractorGDBRemote &packet,
+ Status &error, bool &interrupt, bool &quit)>;
GDBRemoteCommunicationServer(const char *comm_name,
const char *listener_name);
@@ -44,7 +44,7 @@ public:
PacketHandler handler);
PacketResult GetPacketAndSendResponse(Timeout<std::micro> timeout,
- Error &error, bool &interrupt,
+ Status &error, bool &interrupt,
bool &quit);
// After connecting, do a little handshake with the client to make sure
@@ -57,6 +57,13 @@ protected:
bool m_exit_now; // use in asynchronous handling to indicate process should
// exit.
+ bool m_send_error_strings; // If the client enables this then
+ // we will send error strings as well.
+
+ PacketResult Handle_QErrorStringEnable(StringExtractorGDBRemote &packet);
+
+ PacketResult SendErrorResponse(const Status &error);
+
PacketResult SendUnimplementedResponse(const char *packet);
PacketResult SendErrorResponse(uint8_t error);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index e4e6810..f53db50 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -22,23 +22,22 @@
#include <cstring>
// Other libraries and framework includes
-#include "lldb/Core/Log.h"
#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/StreamGDBRemote.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Host/Config.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/FileAction.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/Endian.h"
#include "lldb/Utility/JSON.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamGDBRemote.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/Triple.h"
// Project includes
@@ -360,16 +359,15 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo(
extractor.GetHexByteString(file);
match_info.GetProcessInfo().GetExecutableFile().SetFile(file, false);
} else if (key.equals("name_match")) {
- NameMatchType name_match =
- llvm::StringSwitch<NameMatchType>(value)
- .Case("equals", eNameMatchEquals)
- .Case("starts_with", eNameMatchStartsWith)
- .Case("ends_with", eNameMatchEndsWith)
- .Case("contains", eNameMatchContains)
- .Case("regex", eNameMatchRegularExpression)
- .Default(eNameMatchIgnore);
+ NameMatch name_match = llvm::StringSwitch<NameMatch>(value)
+ .Case("equals", NameMatch::Equals)
+ .Case("starts_with", NameMatch::StartsWith)
+ .Case("ends_with", NameMatch::EndsWith)
+ .Case("contains", NameMatch::Contains)
+ .Case("regex", NameMatch::RegularExpression)
+ .Default(NameMatch::Ignore);
match_info.SetNameMatchType(name_match);
- if (name_match == eNameMatchIgnore)
+ if (name_match == NameMatch::Ignore)
return SendErrorResponse(2);
} else if (key.equals("pid")) {
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
@@ -525,7 +523,7 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Open(
File::ConvertOpenOptionsForPOSIXOpen(packet.GetHexMaxU32(false, 0));
if (packet.GetChar() == ',') {
mode_t mode = packet.GetHexMaxU32(false, 0600);
- Error error;
+ Status error;
const FileSpec path_spec{path, true};
int fd = ::open(path_spec.GetCString(), flags, mode);
const int save_errno = fd == -1 ? errno : 0;
@@ -546,7 +544,7 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Close(
StringExtractorGDBRemote &packet) {
packet.SetFilePos(::strlen("vFile:close:"));
int fd = packet.GetS32(-1);
- Error error;
+ Status error;
int err = -1;
int save_errno = 0;
if (fd >= 0) {
@@ -643,14 +641,15 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Size(
std::string path;
packet.GetHexByteString(path);
if (!path.empty()) {
- lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path, false));
+ uint64_t Size;
+ if (llvm::sys::fs::file_size(path, Size))
+ return SendErrorResponse(5);
StreamString response;
response.PutChar('F');
- response.PutHex64(retcode);
- if (retcode == UINT64_MAX) {
+ response.PutHex64(Size);
+ if (Size == UINT64_MAX) {
response.PutChar(',');
- response.PutHex64(
- retcode); // TODO: replace with Host::GetSyswideErrorCode()
+ response.PutHex64(Size); // TODO: replace with Host::GetSyswideErrorCode()
}
return SendPacketNoLock(response.GetString());
}
@@ -664,7 +663,7 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Mode(
std::string path;
packet.GetHexByteString(path);
if (!path.empty()) {
- Error error;
+ Status error;
const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error);
StreamString response;
response.Printf("F%u", mode);
@@ -682,7 +681,7 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_Exists(
std::string path;
packet.GetHexByteString(path);
if (!path.empty()) {
- bool retcode = FileSystem::GetFileExists(FileSpec(path, false));
+ bool retcode = llvm::sys::fs::exists(path);
StreamString response;
response.PutChar('F');
response.PutChar(',');
@@ -703,7 +702,7 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_symlink(
packet.GetHexByteStringTerminatedBy(dst, ',');
packet.GetChar(); // Skip ',' char
packet.GetHexByteString(src);
- Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false});
+ Status error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false});
StreamString response;
response.Printf("F%u,%u", error.GetError(), error.GetError());
return SendPacketNoLock(response.GetString());
@@ -715,7 +714,7 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_unlink(
packet.SetFilePos(::strlen("vFile:unlink:"));
std::string path;
packet.GetHexByteString(path);
- Error error = FileSystem::Unlink(FileSpec{path, true});
+ Status error(llvm::sys::fs::remove(path));
StreamString response;
response.Printf("F%u,%u", error.GetError(), error.GetError());
return SendPacketNoLock(response.GetString());
@@ -737,7 +736,7 @@ GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell(
packet.GetHexByteString(working_dir);
int status, signo;
std::string output;
- Error err =
+ Status err =
Host::RunShellCommand(path.c_str(), FileSpec{working_dir, true},
&status, &signo, &output, timeout);
StreamGDBRemote response;
@@ -772,15 +771,15 @@ GDBRemoteCommunicationServerCommon::Handle_vFile_MD5(
std::string path;
packet.GetHexByteString(path);
if (!path.empty()) {
- uint64_t a, b;
StreamGDBRemote response;
- if (!FileSystem::CalculateMD5(FileSpec(path, false), a, b)) {
+ auto Result = llvm::sys::fs::md5_contents(path);
+ if (!Result) {
response.PutCString("F,");
response.PutCString("x");
} else {
response.PutCString("F,");
- response.PutHex64(a);
- response.PutHex64(b);
+ response.PutHex64(Result->low());
+ response.PutHex64(Result->high());
}
return SendPacketNoLock(response.GetString());
}
@@ -795,7 +794,7 @@ GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir(
if (packet.GetChar() == ',') {
std::string path;
packet.GetHexByteString(path);
- Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode);
+ Status error(llvm::sys::fs::create_directory(path, mode));
StreamGDBRemote response;
response.Printf("F%u", error.GetError());
@@ -810,11 +809,12 @@ GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod(
StringExtractorGDBRemote &packet) {
packet.SetFilePos(::strlen("qPlatform_chmod:"));
- mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ auto perms =
+ static_cast<llvm::sys::fs::perms>(packet.GetHexMaxU32(false, UINT32_MAX));
if (packet.GetChar() == ',') {
std::string path;
packet.GetHexByteString(path);
- Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode);
+ Status error(llvm::sys::fs::setPermissions(path, perms));
StreamGDBRemote response;
response.Printf("F%u", error.GetError());
@@ -838,7 +838,8 @@ GDBRemoteCommunicationServerCommon::Handle_qSupported(
response.PutCString(";QThreadSuffixSupported+");
response.PutCString(";QListThreadsInStopReply+");
response.PutCString(";qEcho+");
-#if defined(__linux__)
+#if defined(__linux__) || defined(__NetBSD__)
+ response.PutCString(";QPassSignals+");
response.PutCString(";qXfer:auxv:read+");
#endif
@@ -1045,14 +1046,9 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) {
if (success) {
m_process_launch_error = LaunchProcess();
- if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
+ if (m_process_launch_error.Success())
return SendOKResponse();
- } else {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("LLGSPacketHandler::%s failed to launch exe: %s",
- __FUNCTION__, m_process_launch_error.AsCString());
- }
+ LLDB_LOG(log, "failed to launch exe: {0}", m_process_launch_error);
}
return SendErrorResponse(8);
}
@@ -1091,12 +1087,11 @@ GDBRemoteCommunicationServerCommon::Handle_qModuleInfo(
StreamGDBRemote response;
if (uuid_str.empty()) {
- std::string md5_hash;
- if (!FileSystem::CalculateMD5AsString(matched_module_spec.GetFileSpec(),
- file_offset, file_size, md5_hash))
+ auto Result = llvm::sys::fs::md5_contents(matched_module_spec.GetFileSpec().GetPath());
+ if (!Result)
return SendErrorResponse(5);
response.PutCString("md5:");
- response.PutCStringAsRawHex8(md5_hash.c_str());
+ response.PutCStringAsRawHex8(Result->digest().c_str());
} else {
response.PutCString("uuid:");
response.PutCStringAsRawHex8(uuid_str.c_str());
@@ -1140,7 +1135,7 @@ GDBRemoteCommunicationServerCommon::Handle_jModulesInfo(
packet_array->GetItemAtIndex(i)->GetAsDictionary();
if (!query)
continue;
- std::string file, triple;
+ llvm::StringRef file, triple;
if (!query->GetValueForKeyAsString("file", file) ||
!query->GetValueForKeyAsString("triple", triple))
continue;
@@ -1278,9 +1273,10 @@ FileSpec GDBRemoteCommunicationServerCommon::FindModuleFile(
#endif
}
-ModuleSpec GDBRemoteCommunicationServerCommon::GetModuleInfo(
- const std::string &module_path, const std::string &triple) {
- ArchSpec arch(triple.c_str());
+ModuleSpec
+GDBRemoteCommunicationServerCommon::GetModuleInfo(llvm::StringRef module_path,
+ llvm::StringRef triple) {
+ ArchSpec arch(triple);
const FileSpec req_module_path_spec(module_path, true);
const FileSpec module_path_spec =
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
index 321a922..e9ab8f1 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
@@ -38,7 +38,7 @@ public:
protected:
ProcessLaunchInfo m_process_launch_info;
- Error m_process_launch_error;
+ Status m_process_launch_error;
ProcessInstanceInfoList m_proc_infos;
uint32_t m_proc_infos_index;
bool m_thread_suffix_supported;
@@ -130,7 +130,7 @@ protected:
PacketResult (T::*handler)(StringExtractorGDBRemote &packet)) {
RegisterPacketHandler(packet_type,
[this, handler](StringExtractorGDBRemote packet,
- Error &error, bool &interrupt,
+ Status &error, bool &interrupt,
bool &quit) {
return (static_cast<T *>(this)->*handler)(packet);
});
@@ -144,17 +144,16 @@ protected:
/// with all the information for a child process to be launched.
///
/// @return
- /// An Error object indicating the success or failure of the
+ /// An Status object indicating the success or failure of the
/// launch.
//------------------------------------------------------------------
- virtual Error LaunchProcess() = 0;
+ virtual Status LaunchProcess() = 0;
virtual FileSpec FindModuleFile(const std::string &module_path,
const ArchSpec &arch);
private:
- ModuleSpec GetModuleInfo(const std::string &module_path,
- const std::string &triple);
+ ModuleSpec GetModuleInfo(llvm::StringRef module_path, llvm::StringRef triple);
};
} // namespace process_gdb_remote
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index bf72673..9294359 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -12,7 +12,7 @@
#include "lldb/Host/Config.h"
#include "GDBRemoteCommunicationServerLLGS.h"
-#include "lldb/Core/StreamGDBRemote.h"
+#include "lldb/Utility/StreamGDBRemote.h"
// C Includes
// C++ Includes
@@ -21,27 +21,28 @@
#include <thread>
// Other libraries and framework includes
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Debug.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/PosixApi.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Host/common/NativeRegisterContext.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Target/FileAction.h"
#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/Endian.h"
#include "lldb/Utility/JSON.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UriParser.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ScopedPrinter.h"
@@ -49,7 +50,6 @@
#include "ProcessGDBRemote.h"
#include "ProcessGDBRemoteLog.h"
#include "Utility/StringExtractorGDBRemote.h"
-#include "Utility/UriParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -74,16 +74,11 @@ enum GDBRemoteServerError {
// GDBRemoteCommunicationServerLLGS constructor
//----------------------------------------------------------------------
GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(
- MainLoop &mainloop)
+ MainLoop &mainloop, const NativeProcessProtocol::Factory &process_factory)
: GDBRemoteCommunicationServerCommon("gdb-remote.server",
"gdb-remote.server.rx_packet"),
- m_mainloop(mainloop), m_current_tid(LLDB_INVALID_THREAD_ID),
- m_continue_tid(LLDB_INVALID_THREAD_ID), m_debugged_process_mutex(),
- m_debugged_process_sp(), m_stdio_communication("process.stdio"),
- m_inferior_prev_state(StateType::eStateInvalid),
- m_active_auxv_buffer_sp(), m_saved_registers_mutex(),
- m_saved_registers_map(), m_next_saved_registers_id(1),
- m_handshake_completed(false) {
+ m_mainloop(mainloop), m_process_factory(process_factory),
+ m_stdio_communication("process.stdio") {
RegisterPacketHandlers();
}
@@ -181,37 +176,57 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
&GDBRemoteCommunicationServerLLGS::Handle_Z);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z,
&GDBRemoteCommunicationServerLLGS::Handle_z);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_QPassSignals,
+ &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
+
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceStart,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceStart);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceBufferRead,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceMetaRead,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceStop,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceStop);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
+ &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead);
RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
- [this](StringExtractorGDBRemote packet, Error &error,
+ [this](StringExtractorGDBRemote packet, Status &error,
bool &interrupt, bool &quit) {
quit = true;
return this->Handle_k(packet);
});
}
-Error GDBRemoteCommunicationServerLLGS::SetLaunchArguments(
- const char *const args[], int argc) {
+Status
+GDBRemoteCommunicationServerLLGS::SetLaunchArguments(const char *const args[],
+ int argc) {
if ((argc < 1) || !args || !args[0] || !args[0][0])
- return Error("%s: no process command line specified to launch",
- __FUNCTION__);
+ return Status("%s: no process command line specified to launch",
+ __FUNCTION__);
m_process_launch_info.SetArguments(const_cast<const char **>(args), true);
- return Error();
+ return Status();
}
-Error GDBRemoteCommunicationServerLLGS::SetLaunchFlags(
- unsigned int launch_flags) {
+Status
+GDBRemoteCommunicationServerLLGS::SetLaunchFlags(unsigned int launch_flags) {
m_process_launch_info.GetFlags().Set(launch_flags);
- return Error();
+ return Status();
}
-Error GDBRemoteCommunicationServerLLGS::LaunchProcess() {
+Status GDBRemoteCommunicationServerLLGS::LaunchProcess() {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
if (!m_process_launch_info.GetArguments().GetArgumentCount())
- return Error("%s: no process command line specified to launch",
- __FUNCTION__);
+ return Status("%s: no process command line specified to launch",
+ __FUNCTION__);
const bool should_forward_stdio =
m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr ||
@@ -223,19 +238,20 @@ Error GDBRemoteCommunicationServerLLGS::LaunchProcess() {
const bool default_to_use_pty = true;
m_process_launch_info.FinalizeFileActions(nullptr, default_to_use_pty);
- Error error;
{
std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex);
- assert(!m_debugged_process_sp && "lldb-server creating debugged "
+ assert(!m_debugged_process_up && "lldb-server creating debugged "
"process but one already exists");
- error = NativeProcessProtocol::Launch(m_process_launch_info, *this,
- m_mainloop, m_debugged_process_sp);
- }
-
- if (!error.Success()) {
- fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__,
- m_process_launch_info.GetArguments().GetArgumentAtIndex(0));
- return error;
+ auto process_or =
+ m_process_factory.Launch(m_process_launch_info, *this, m_mainloop);
+ if (!process_or) {
+ Status status(process_or.takeError());
+ llvm::errs() << llvm::formatv(
+ "failed to launch executable `{0}`: {1}",
+ m_process_launch_info.GetArguments().GetArgumentAtIndex(0), status);
+ return status;
+ }
+ m_debugged_process_up = std::move(*process_or);
}
// Handle mirroring of inferior stdout/stderr over the gdb-remote protocol
@@ -248,22 +264,21 @@ Error GDBRemoteCommunicationServerLLGS::LaunchProcess() {
// nullptr means it's not redirected to file or pty (in case of LLGS local)
// at least one of stdio will be transferred pty<->gdb-remote
// we need to give the pty master handle to this object to read and/or write
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " setting up stdout/stderr redirection via $O gdb-remote commands",
- __FUNCTION__, m_debugged_process_sp->GetID());
+ LLDB_LOG(log,
+ "pid = {0}: setting up stdout/stderr redirection via $O "
+ "gdb-remote commands",
+ m_debugged_process_up->GetID());
// Setup stdout/stderr mapping from inferior to $O
- auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor();
+ auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor();
if (terminal_fd >= 0) {
if (log)
log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting "
"inferior STDIO fd to %d",
__FUNCTION__, terminal_fd);
- error = SetSTDIOFileDescriptor(terminal_fd);
- if (error.Fail())
- return error;
+ Status status = SetSTDIOFileDescriptor(terminal_fd);
+ if (status.Fail())
+ return status;
} else {
if (log)
log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring "
@@ -271,23 +286,20 @@ Error GDBRemoteCommunicationServerLLGS::LaunchProcess() {
__FUNCTION__, terminal_fd);
}
} else {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " skipping stdout/stderr redirection via $O: inferior will "
- "communicate over client-provided file descriptors",
- __FUNCTION__, m_debugged_process_sp->GetID());
+ LLDB_LOG(log,
+ "pid = {0} skipping stdout/stderr redirection via $O: inferior "
+ "will communicate over client-provided file descriptors",
+ m_debugged_process_up->GetID());
}
printf("Launched '%s' as process %" PRIu64 "...\n",
m_process_launch_info.GetArguments().GetArgumentAtIndex(0),
- m_process_launch_info.GetProcessID());
+ m_debugged_process_up->GetID());
- return error;
+ return Status();
}
-Error GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
- Error error;
-
+Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64,
@@ -295,32 +307,33 @@ Error GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
// Before we try to attach, make sure we aren't already monitoring something
// else.
- if (m_debugged_process_sp &&
- m_debugged_process_sp->GetID() != LLDB_INVALID_PROCESS_ID)
- return Error("cannot attach to a process %" PRIu64
- " when another process with pid %" PRIu64
- " is being debugged.",
- pid, m_debugged_process_sp->GetID());
+ if (m_debugged_process_up &&
+ m_debugged_process_up->GetID() != LLDB_INVALID_PROCESS_ID)
+ return Status("cannot attach to a process %" PRIu64
+ " when another process with pid %" PRIu64
+ " is being debugged.",
+ pid, m_debugged_process_up->GetID());
// Try to attach.
- error = NativeProcessProtocol::Attach(pid, *this, m_mainloop,
- m_debugged_process_sp);
- if (!error.Success()) {
- fprintf(stderr, "%s: failed to attach to process %" PRIu64 ": %s",
- __FUNCTION__, pid, error.AsCString());
- return error;
+ auto process_or = m_process_factory.Attach(pid, *this, m_mainloop);
+ if (!process_or) {
+ Status status(process_or.takeError());
+ llvm::errs() << llvm::formatv("failed to attach to process {0}: {1}", pid,
+ status);
+ return status;
}
+ m_debugged_process_up = std::move(*process_or);
// Setup stdout/stderr mapping from inferior.
- auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor();
+ auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor();
if (terminal_fd >= 0) {
if (log)
log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting "
"inferior STDIO fd to %d",
__FUNCTION__, terminal_fd);
- error = SetSTDIOFileDescriptor(terminal_fd);
- if (error.Fail())
- return error;
+ Status status = SetSTDIOFileDescriptor(terminal_fd);
+ if (status.Fail())
+ return status;
} else {
if (log)
log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring "
@@ -329,8 +342,7 @@ Error GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
}
printf("Attached to process %" PRIu64 "...\n", pid);
-
- return error;
+ return Status();
}
void GDBRemoteCommunicationServerLLGS::InitializeDelegate(
@@ -352,53 +364,23 @@ GDBRemoteCommunicationServerLLGS::SendWResponse(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
// send W notification
- ExitType exit_type = ExitType::eExitTypeInvalid;
- int return_code = 0;
- std::string exit_description;
-
- const bool got_exit_info =
- process->GetExitStatus(&exit_type, &return_code, exit_description);
- if (!got_exit_info) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- ", failed to retrieve process exit status",
- __FUNCTION__, process->GetID());
+ auto wait_status = process->GetExitStatus();
+ if (!wait_status) {
+ LLDB_LOG(log, "pid = {0}, failed to retrieve process exit status",
+ process->GetID());
StreamGDBRemote response;
response.PutChar('E');
response.PutHex8(GDBRemoteServerError::eErrorExitStatus);
return SendPacketNoLock(response.GetString());
- } else {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- ", returning exit type %d, return code %d [%s]",
- __FUNCTION__, process->GetID(), exit_type, return_code,
- exit_description.c_str());
-
- StreamGDBRemote response;
-
- char return_type_code;
- switch (exit_type) {
- case ExitType::eExitTypeExit:
- return_type_code = 'W';
- break;
- case ExitType::eExitTypeSignal:
- return_type_code = 'X';
- break;
- case ExitType::eExitTypeStop:
- return_type_code = 'S';
- break;
- case ExitType::eExitTypeInvalid:
- return_type_code = 'E';
- break;
- }
- response.PutChar(return_type_code);
+ }
- // POSIX exit status limited to unsigned 8 bits.
- response.PutHex8(return_code);
+ LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(),
+ *wait_status);
- return SendPacketNoLock(response.GetString());
- }
+ StreamGDBRemote response;
+ response.Format("{0:g}", *wait_status);
+ return SendPacketNoLock(response.GetString());
}
static void AppendHexValue(StreamString &response, const uint8_t *buf,
@@ -415,10 +397,11 @@ static void AppendHexValue(StreamString &response, const uint8_t *buf,
static void WriteRegisterValueInHexFixedWidth(
StreamString &response, NativeRegisterContextSP &reg_ctx_sp,
- const RegisterInfo &reg_info, const RegisterValue *reg_value_p) {
+ const RegisterInfo &reg_info, const RegisterValue *reg_value_p,
+ lldb::ByteOrder byte_order) {
RegisterValue reg_value;
if (!reg_value_p) {
- Error error = reg_ctx_sp->ReadRegister(&reg_info, reg_value);
+ Status error = reg_ctx_sp->ReadRegister(&reg_info, reg_value);
if (error.Success())
reg_value_p = &reg_value;
// else log.
@@ -426,7 +409,8 @@ static void WriteRegisterValueInHexFixedWidth(
if (reg_value_p) {
AppendHexValue(response, (const uint8_t *)reg_value_p->GetBytes(),
- reg_value_p->GetByteSize(), false);
+ reg_value_p->GetByteSize(),
+ byte_order == lldb::eByteOrderLittle);
} else {
// Zero-out any unreadable values.
if (reg_info.byte_size > 0) {
@@ -436,8 +420,7 @@ static void WriteRegisterValueInHexFixedWidth(
}
}
-static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread,
- bool abridged) {
+static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
NativeRegisterContextSP reg_ctx_sp = thread.GetRegisterContext();
@@ -462,11 +445,8 @@ static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread,
static const uint32_t k_expedited_registers[] = {
LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP,
LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM};
- static const uint32_t k_abridged_expedited_registers[] = {
- LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM};
- for (const uint32_t *generic_reg_p = abridged ? k_abridged_expedited_registers
- : k_expedited_registers;
+ for (const uint32_t *generic_reg_p = k_expedited_registers;
*generic_reg_p != LLDB_INVALID_REGNUM; ++generic_reg_p) {
uint32_t reg_num = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, *generic_reg_p);
@@ -489,7 +469,7 @@ static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread,
// registers.
RegisterValue reg_value;
- Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value);
+ Status error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value);
if (error.Fail()) {
if (log)
log->Printf("%s failed to read register '%s' index %" PRIu32 ": %s",
@@ -501,7 +481,7 @@ static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread,
StreamString stream;
WriteRegisterValueInHexFixedWidth(stream, reg_ctx_sp, *reg_info_p,
- &reg_value);
+ &reg_value, lldb::eByteOrderBig);
register_object_sp->SetObject(
llvm::to_string(reg_num),
@@ -567,8 +547,10 @@ static JSONArray::SP GetJSONThreadsInfo(NativeProcessProtocol &process,
JSONObject::SP thread_obj_sp = std::make_shared<JSONObject>();
threads_array_sp->AppendObject(thread_obj_sp);
- if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp, abridged))
- thread_obj_sp->SetObject("registers", registers_sp);
+ if (!abridged) {
+ if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp))
+ thread_obj_sp->SetObject("registers", registers_sp);
+ }
thread_obj_sp->SetObject("tid", std::make_shared<JSONNumber>(tid));
if (signum != 0)
@@ -614,18 +596,15 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
// Ensure we have a debugged process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
return SendErrorResponse(50);
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64
- " tid %" PRIu64,
- __FUNCTION__, m_debugged_process_sp->GetID(), tid);
+ LLDB_LOG(log, "preparing packet for pid {0} tid {1}",
+ m_debugged_process_up->GetID(), tid);
// Ensure we can get info on the given thread.
- NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadByID(tid));
+ NativeThreadProtocolSP thread_sp(m_debugged_process_up->GetThreadByID(tid));
if (!thread_sp)
return SendErrorResponse(51);
@@ -646,13 +625,11 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
// Output the T packet with the thread
response.PutChar('T');
int signum = tid_stop_info.details.signal.signo;
- if (log) {
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " tid %" PRIu64
- " got signal signo = %d, reason = %d, exc_type = %" PRIu64,
- __FUNCTION__, m_debugged_process_sp->GetID(), tid, signum,
- tid_stop_info.reason, tid_stop_info.details.exception.type);
- }
+ LLDB_LOG(
+ log,
+ "pid {0}, tid {1}, got signal signo = {2}, reason = {3}, exc_type = {4}",
+ m_debugged_process_up->GetID(), tid, signum, int(tid_stop_info.reason),
+ tid_stop_info.details.exception.type);
// Print the signal number.
response.PutHex8(signum & 0xff);
@@ -690,9 +667,9 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
uint32_t thread_index = 0;
NativeThreadProtocolSP listed_thread_sp;
for (listed_thread_sp =
- m_debugged_process_sp->GetThreadAtIndex(thread_index);
+ m_debugged_process_up->GetThreadAtIndex(thread_index);
listed_thread_sp; ++thread_index,
- listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex(
+ listed_thread_sp = m_debugged_process_up->GetThreadAtIndex(
thread_index)) {
if (thread_index > 0)
response.PutChar(',');
@@ -709,18 +686,52 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
if (thread_index > 0) {
const bool threads_with_valid_stop_info_only = true;
JSONArray::SP threads_info_sp = GetJSONThreadsInfo(
- *m_debugged_process_sp, threads_with_valid_stop_info_only);
+ *m_debugged_process_up, threads_with_valid_stop_info_only);
if (threads_info_sp) {
response.PutCString("jstopinfo:");
StreamString unescaped_response;
threads_info_sp->Write(unescaped_response);
response.PutCStringAsRawHex8(unescaped_response.GetData());
response.PutChar(';');
- } else if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to prepare a "
- "jstopinfo field for pid %" PRIu64,
- __FUNCTION__, m_debugged_process_sp->GetID());
+ } else
+ LLDB_LOG(log, "failed to prepare a jstopinfo field for pid {0}",
+ m_debugged_process_up->GetID());
}
+
+ uint32_t i = 0;
+ response.PutCString("thread-pcs");
+ char delimiter = ':';
+ for (NativeThreadProtocolSP thread_sp;
+ (thread_sp = m_debugged_process_up->GetThreadAtIndex(i)) != nullptr;
+ ++i) {
+ NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
+ if (!reg_ctx_sp)
+ continue;
+
+ uint32_t reg_to_read = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const RegisterInfo *const reg_info_p =
+ reg_ctx_sp->GetRegisterInfoAtIndex(reg_to_read);
+
+ RegisterValue reg_value;
+ Status error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value);
+ if (error.Fail()) {
+ if (log)
+ log->Printf("%s failed to read register '%s' index %" PRIu32 ": %s",
+ __FUNCTION__,
+ reg_info_p->name ? reg_info_p->name
+ : "<unnamed-register>",
+ reg_to_read, error.AsCString());
+ continue;
+ }
+
+ response.PutChar(delimiter);
+ delimiter = ',';
+ WriteRegisterValueInHexFixedWidth(response, reg_ctx_sp, *reg_info_p,
+ &reg_value, endian::InlHostByteOrder());
+ }
+
+ response.PutChar(';');
}
//
@@ -757,11 +768,11 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
} else if (reg_info_p->value_regs == nullptr) {
// Only expediate registers that are not contained in other registers.
RegisterValue reg_value;
- Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value);
+ Status error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value);
if (error.Success()) {
response.Printf("%.02x:", *reg_num_p);
WriteRegisterValueInHexFixedWidth(response, reg_ctx_sp, *reg_info_p,
- &reg_value);
+ &reg_value, lldb::eByteOrderBig);
response.PutChar(';');
} else {
if (log)
@@ -924,7 +935,7 @@ void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() {
bool interrupt = false;
bool done = false;
- Error error;
+ Status error;
while (true) {
const PacketResult result = GetPacketAndSendResponse(
std::chrono::microseconds(0), error, interrupt, done);
@@ -942,12 +953,12 @@ void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() {
}
}
-Error GDBRemoteCommunicationServerLLGS::InitializeConnection(
+Status GDBRemoteCommunicationServerLLGS::InitializeConnection(
std::unique_ptr<Connection> &&connection) {
IOObjectSP read_object_sp = connection->GetReadObject();
GDBRemoteCommunicationServer::SetConnection(connection.release());
- Error error;
+ Status error;
m_network_handle_up = m_mainloop.RegisterReadObject(
read_object_sp, [this](MainLoopBase &) { DataAvailableCallback(); },
error);
@@ -969,8 +980,8 @@ GDBRemoteCommunicationServerLLGS::SendONotification(const char *buffer,
return SendPacketNoLock(response.GetString());
}
-Error GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor(int fd) {
- Error error;
+Status GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor(int fd) {
+ Status error;
// Set up the reading/handling of process I/O
std::unique_ptr<ConnectionFileDescriptor> conn_up(
@@ -988,7 +999,7 @@ Error GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor(int fd) {
return error;
}
- return Error();
+ return Status();
}
void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() {
@@ -996,7 +1007,7 @@ void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() {
if (!m_stdio_communication.IsConnected())
return;
- Error error;
+ Status error;
lldbassert(!m_stdio_handle_up);
m_stdio_handle_up = m_mainloop.RegisterReadObject(
m_stdio_communication.GetConnection()->GetReadObject(),
@@ -1019,7 +1030,7 @@ void GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding() {
void GDBRemoteCommunicationServerLLGS::SendProcessOutput() {
char buffer[1024];
ConnectionStatus status;
- Error error;
+ Status error;
while (true) {
size_t bytes_read = m_stdio_communication.Read(
buffer, sizeof buffer, std::chrono::microseconds(0), status, &error);
@@ -1047,14 +1058,239 @@ void GDBRemoteCommunicationServerLLGS::SendProcessOutput() {
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceStart(
+ StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ if (!packet.ConsumeFront("jTraceStart:"))
+ return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
+
+ TraceOptions options;
+ uint64_t type = std::numeric_limits<uint64_t>::max();
+ uint64_t buffersize = std::numeric_limits<uint64_t>::max();
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ uint64_t metabuffersize = std::numeric_limits<uint64_t>::max();
+
+ auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != lldb::eStructuredDataTypeDictionary)
+ return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ json_dict->GetValueForKeyAsInteger("metabuffersize", metabuffersize);
+ options.setMetaDataBufferSize(metabuffersize);
+
+ json_dict->GetValueForKeyAsInteger("buffersize", buffersize);
+ options.setTraceBufferSize(buffersize);
+
+ json_dict->GetValueForKeyAsInteger("type", type);
+ options.setType(static_cast<lldb::TraceType>(type));
+
+ json_dict->GetValueForKeyAsInteger("threadid", tid);
+ options.setThreadID(tid);
+
+ StructuredData::ObjectSP custom_params_sp =
+ json_dict->GetValueForKey("params");
+ if (custom_params_sp &&
+ custom_params_sp->GetType() != lldb::eStructuredDataTypeDictionary)
+ return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet ");
+
+ options.setTraceParams(
+ static_pointer_cast<StructuredData::Dictionary>(custom_params_sp));
+
+ if (buffersize == std::numeric_limits<uint64_t>::max() ||
+ type != lldb::TraceType::eTraceTypeProcessorTrace) {
+ LLDB_LOG(log, "Ill formed packet buffersize = {0} type = {1}", buffersize,
+ type);
+ return SendIllFormedResponse(packet, "JTrace:start: Ill formed packet ");
+ }
+
+ Status error;
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+ uid = m_debugged_process_up->StartTrace(options, error);
+ LLDB_LOG(log, "uid is {0} , error is {1}", uid, error.GetError());
+ if (error.Fail())
+ return SendErrorResponse(error);
+
+ StreamGDBRemote response;
+ response.Printf("%" PRIx64, uid);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceStop(
+ StringExtractorGDBRemote &packet) {
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ if (!packet.ConsumeFront("jTraceStop:"))
+ return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
+
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+
+ auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != lldb::eStructuredDataTypeDictionary)
+ return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ if (!json_dict->GetValueForKeyAsInteger("traceid", uid))
+ return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet ");
+
+ json_dict->GetValueForKeyAsInteger("threadid", tid);
+
+ Status error = m_debugged_process_up->StopTrace(uid, tid);
+
+ if (error.Fail())
+ return SendErrorResponse(error);
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ if (!packet.ConsumeFront("jTraceConfigRead:"))
+ return SendIllFormedResponse(packet,
+ "jTraceConfigRead: Ill formed packet ");
+
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+ lldb::tid_t threadid = LLDB_INVALID_THREAD_ID;
+
+ auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != lldb::eStructuredDataTypeDictionary)
+ return SendIllFormedResponse(packet,
+ "jTraceConfigRead: Ill formed packet ");
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ if (!json_dict->GetValueForKeyAsInteger("traceid", uid))
+ return SendIllFormedResponse(packet,
+ "jTraceConfigRead: Ill formed packet ");
+
+ json_dict->GetValueForKeyAsInteger("threadid", threadid);
+
+ TraceOptions options;
+ StreamGDBRemote response;
+
+ options.setThreadID(threadid);
+ Status error = m_debugged_process_up->GetTraceConfig(uid, options);
+
+ if (error.Fail())
+ return SendErrorResponse(error);
+
+ StreamGDBRemote escaped_response;
+ StructuredData::Dictionary json_packet;
+
+ json_packet.AddIntegerItem("type", options.getType());
+ json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize());
+ json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize());
+
+ StructuredData::DictionarySP custom_params = options.getTraceParams();
+ if (custom_params)
+ json_packet.AddItem("params", custom_params);
+
+ StreamString json_string;
+ json_packet.Dump(json_string, false);
+ escaped_response.PutEscapedBytes(json_string.GetData(),
+ json_string.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jTraceRead(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(68);
+
+ enum PacketType { MetaData, BufferData };
+ PacketType tracetype = MetaData;
+
+ if (packet.ConsumeFront("jTraceBufferRead:"))
+ tracetype = BufferData;
+ else if (packet.ConsumeFront("jTraceMetaRead:"))
+ tracetype = MetaData;
+ else {
+ return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+ }
+
+ lldb::user_id_t uid = LLDB_INVALID_UID;
+
+ uint64_t byte_count = std::numeric_limits<uint64_t>::max();
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ uint64_t offset = std::numeric_limits<uint64_t>::max();
+
+ auto json_object = StructuredData::ParseJSON(packet.Peek());
+
+ if (!json_object ||
+ json_object->GetType() != lldb::eStructuredDataTypeDictionary)
+ return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+ auto json_dict = json_object->GetAsDictionary();
+
+ if (!json_dict->GetValueForKeyAsInteger("traceid", uid) ||
+ !json_dict->GetValueForKeyAsInteger("offset", offset) ||
+ !json_dict->GetValueForKeyAsInteger("buffersize", byte_count))
+ return SendIllFormedResponse(packet, "jTrace: Ill formed packet ");
+
+ json_dict->GetValueForKeyAsInteger("threadid", tid);
+
+ // Allocate the response buffer.
+ std::unique_ptr<uint8_t[]> buffer (new (std::nothrow) uint8_t[byte_count]);
+ if (!buffer)
+ return SendErrorResponse(0x78);
+
+ StreamGDBRemote response;
+ Status error;
+ llvm::MutableArrayRef<uint8_t> buf(buffer.get(), byte_count);
+
+ if (tracetype == BufferData)
+ error = m_debugged_process_up->GetData(uid, tid, buf, offset);
+ else if (tracetype == MetaData)
+ error = m_debugged_process_up->GetMetaData(uid, tid, buf, offset);
+
+ if (error.Fail())
+ return SendErrorResponse(error);
+
+ for (auto i : buf)
+ response.PutHex8(i);
+
+ StreamGDBRemote escaped_response;
+ escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo(
StringExtractorGDBRemote &packet) {
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
return SendErrorResponse(68);
- lldb::pid_t pid = m_debugged_process_sp->GetID();
+ lldb::pid_t pid = m_debugged_process_up->GetID();
if (pid == LLDB_INVALID_PROCESS_ID)
return SendErrorResponse(1);
@@ -1071,16 +1307,16 @@ GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo(
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) {
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
return SendErrorResponse(68);
// Make sure we set the current thread so g and p packets return
// the data the gdb will expect.
- lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID();
+ lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID();
SetCurrentThreadID(tid);
- NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread();
+ NativeThreadProtocolSP thread_sp = m_debugged_process_up->GetCurrentThread();
if (!thread_sp)
return SendErrorResponse(69);
@@ -1096,20 +1332,15 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) {
StopSTDIOForwarding();
- if (!m_debugged_process_sp) {
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s No debugged process found.",
- __FUNCTION__);
+ if (!m_debugged_process_up) {
+ LLDB_LOG(log, "No debugged process found.");
return PacketResult::Success;
}
- Error error = m_debugged_process_sp->Kill();
- if (error.Fail() && log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to kill debugged "
- "process %" PRIu64 ": %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
+ Status error = m_debugged_process_up->Kill();
+ if (error.Fail())
+ LLDB_LOG(log, "Failed to kill debugged process {0}: {1}",
+ m_debugged_process_up->GetID(), error);
// No OK response for kill packet.
// return SendOKResponse ();
@@ -1157,7 +1388,7 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) {
log->Printf("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
// Ensure we have a native process.
- if (!m_debugged_process_sp) {
+ if (!m_debugged_process_up) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process "
"shared pointer",
@@ -1187,7 +1418,7 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) {
}
ResumeActionList resume_actions(StateType::eStateRunning, 0);
- Error error;
+ Status error;
// We have two branches: what to do if a continue thread is specified (in
// which case we target
@@ -1210,26 +1441,20 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) {
} else {
// Send the signal to the process since we weren't targeting a specific
// continue thread with the signal.
- error = m_debugged_process_sp->Signal(signo);
+ error = m_debugged_process_up->Signal(signo);
if (error.Fail()) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to send "
- "signal for process %" PRIu64 ": %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
+ LLDB_LOG(log, "failed to send signal for process {0}: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(0x52);
}
}
// Resume the threads.
- error = m_debugged_process_sp->Resume(resume_actions);
+ error = m_debugged_process_up->Resume(resume_actions);
if (error.Fail()) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to resume "
- "threads for process %" PRIu64 ": %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
+ LLDB_LOG(log, "failed to resume threads for process {0}: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(0x38);
}
@@ -1249,15 +1474,13 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) {
// For now just support all continue.
const bool has_continue_address = (packet.GetBytesLeft() > 0);
if (has_continue_address) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s not implemented for "
- "c{address} variant [%s remains]",
- __FUNCTION__, packet.Peek());
+ LLDB_LOG(log, "not implemented for c[address] variant [{0} remains]",
+ packet.Peek());
return SendUnimplementedResponse(packet.GetStringRef().c_str());
}
// Ensure we have a native process.
- if (!m_debugged_process_sp) {
+ if (!m_debugged_process_up) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process "
"shared pointer",
@@ -1268,22 +1491,14 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) {
// Build the ResumeActionList
ResumeActionList actions(StateType::eStateRunning, 0);
- Error error = m_debugged_process_sp->Resume(actions);
+ Status error = m_debugged_process_up->Resume(actions);
if (error.Fail()) {
- if (log) {
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s c failed for process %" PRIu64
- ": %s",
- __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString());
- }
+ LLDB_LOG(log, "c failed for process {0}: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(GDBRemoteServerError::eErrorResume);
}
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64,
- __FUNCTION__, m_debugged_process_sp->GetID());
-
+ LLDB_LOG(log, "continued process {0}", m_debugged_process_up->GetID());
// No response required from continue.
return PacketResult::Success;
}
@@ -1327,11 +1542,8 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont(
}
// Ensure we have a native process.
- if (!m_debugged_process_sp) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s no debugged process "
- "shared pointer",
- __FUNCTION__);
+ if (!m_debugged_process_up) {
+ LLDB_LOG(log, "no debugged process");
return SendErrorResponse(0x36);
}
@@ -1392,44 +1604,30 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont(
thread_actions.Append(thread_action);
}
- Error error = m_debugged_process_sp->Resume(thread_actions);
+ Status error = m_debugged_process_up->Resume(thread_actions);
if (error.Fail()) {
- if (log) {
- log->Printf("GDBRemoteCommunicationServerLLGS::%s vCont failed for "
- "process %" PRIu64 ": %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
- }
+ LLDB_LOG(log, "vCont failed for process {0}: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(GDBRemoteServerError::eErrorResume);
}
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64,
- __FUNCTION__, m_debugged_process_sp->GetID());
-
+ LLDB_LOG(log, "continued process {0}", m_debugged_process_up->GetID());
// No response required from vCont.
return PacketResult::Success;
}
void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s setting current thread "
- "id to %" PRIu64,
- __FUNCTION__, tid);
+ LLDB_LOG(log, "setting current thread id to {0}", tid);
m_current_tid = tid;
- if (m_debugged_process_sp)
- m_debugged_process_sp->SetCurrentThreadID(m_current_tid);
+ if (m_debugged_process_up)
+ m_debugged_process_up->SetCurrentThreadID(m_current_tid);
}
void GDBRemoteCommunicationServerLLGS::SetContinueThreadID(lldb::tid_t tid) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s setting continue thread "
- "id to %" PRIu64,
- __FUNCTION__, tid);
+ LLDB_LOG(log, "setting continue thread id to {0}", tid);
m_continue_tid = tid;
}
@@ -1440,10 +1638,10 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason(
// Handle the $? gdbremote command.
// If no process, indicate error
- if (!m_debugged_process_sp)
+ if (!m_debugged_process_up)
return SendErrorResponse(02);
- return SendStopReasonForState(m_debugged_process_sp->GetState());
+ return SendStopReasonForState(m_debugged_process_up->GetState());
}
GDBRemoteCommunication::PacketResult
@@ -1464,7 +1662,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState(
case eStateSuspended:
case eStateStopped:
case eStateCrashed: {
- lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID();
+ lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID();
// Make sure we set the current thread so g and p packets return
// the data the gdb will expect.
SetCurrentThreadID(tid);
@@ -1474,15 +1672,11 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState(
case eStateInvalid:
case eStateUnloaded:
case eStateExited:
- return SendWResponse(m_debugged_process_sp.get());
+ return SendWResponse(m_debugged_process_up.get());
default:
- if (log) {
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- ", current state reporting not handled: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- StateAsCString(process_state));
- }
+ LLDB_LOG(log, "pid {0}, current state reporting not handled: {1}",
+ m_debugged_process_up->GetID(), process_state);
break;
}
@@ -1493,12 +1687,12 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo(
StringExtractorGDBRemote &packet) {
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
return SendErrorResponse(68);
// Ensure we have a thread.
- NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadAtIndex(0));
+ NativeThreadProtocolSP thread_sp(m_debugged_process_up->GetThreadAtIndex(0));
if (!thread_sp)
return SendErrorResponse(69);
@@ -1702,47 +1896,33 @@ GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s() no process (%s), "
- "returning OK",
- __FUNCTION__,
- m_debugged_process_sp ? "invalid process id"
- : "null m_debugged_process_sp");
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOG(log, "no process ({0}), returning OK",
+ m_debugged_process_up ? "invalid process id"
+ : "null m_debugged_process_up");
return SendOKResponse();
}
StreamGDBRemote response;
response.PutChar('m');
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s() starting thread iteration",
- __FUNCTION__);
-
+ LLDB_LOG(log, "starting thread iteration");
NativeThreadProtocolSP thread_sp;
uint32_t thread_index;
for (thread_index = 0,
- thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_index);
+ thread_sp = m_debugged_process_up->GetThreadAtIndex(thread_index);
thread_sp; ++thread_index,
- thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_index)) {
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s() iterated thread %" PRIu32
- "(%s, tid=0x%" PRIx64 ")",
- __FUNCTION__, thread_index, thread_sp ? "is not null" : "null",
- thread_sp ? thread_sp->GetID() : LLDB_INVALID_THREAD_ID);
+ thread_sp = m_debugged_process_up->GetThreadAtIndex(thread_index)) {
+ LLDB_LOG(log, "iterated thread {0}({1}, tid={2})", thread_index,
+ thread_sp ? "is not null" : "null",
+ thread_sp ? thread_sp->GetID() : LLDB_INVALID_THREAD_ID);
if (thread_index > 0)
response.PutChar(',');
response.Printf("%" PRIx64, thread_sp->GetID());
}
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s() finished thread iteration",
- __FUNCTION__);
-
+ LLDB_LOG(log, "finished thread iteration");
return SendPacketNoLock(response.GetString());
}
@@ -1783,11 +1963,10 @@ GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) {
// Get the thread's register context.
NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext());
if (!reg_context_sp) {
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64
- " failed, no register context available for the thread",
- __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID());
+ LLDB_LOG(
+ log,
+ "pid {0} tid {1} failed, no register context available for the thread",
+ m_debugged_process_up->GetID(), thread_sp->GetID());
return SendErrorResponse(0x15);
}
@@ -1817,7 +1996,7 @@ GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) {
// Retrieve the value
RegisterValue reg_value;
- Error error = reg_context_sp->ReadRegister(reg_info, reg_value);
+ Status error = reg_context_sp->ReadRegister(reg_info, reg_value);
if (error.Fail()) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, read of "
@@ -1870,8 +2049,8 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) {
// Get process architecture.
ArchSpec process_arch;
- if (!m_debugged_process_sp ||
- !m_debugged_process_sp->GetArchitecture(process_arch)) {
+ if (!m_debugged_process_up ||
+ !m_debugged_process_up->GetArchitecture(process_arch)) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to retrieve "
"inferior architecture",
@@ -1900,7 +2079,7 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) {
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64
" failed, no register context available for the thread",
- __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID());
+ __FUNCTION__, m_debugged_process_up->GetID(), thread_sp->GetID());
return SendErrorResponse(0x15);
}
@@ -1937,7 +2116,7 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) {
StreamGDBRemote response;
RegisterValue reg_value(reg_bytes, reg_size, process_arch.GetByteOrder());
- Error error = reg_context_sp->WriteRegister(reg_info, reg_value);
+ Status error = reg_context_sp->WriteRegister(reg_info, reg_value);
if (error.Fail()) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, write of "
@@ -1954,8 +2133,8 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
if (log)
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
@@ -1998,7 +2177,7 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) {
// Ensure we have the given thread when not specifying -1 (all threads) or 0
// (any thread).
if (tid != LLDB_INVALID_THREAD_ID && tid != 0) {
- NativeThreadProtocolSP thread_sp(m_debugged_process_sp->GetThreadByID(tid));
+ NativeThreadProtocolSP thread_sp(m_debugged_process_up->GetThreadByID(tid));
if (!thread_sp) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64
@@ -2032,8 +2211,8 @@ GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
if (log)
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
@@ -2052,7 +2231,7 @@ GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) {
// TODO: enqueue this block in circular buffer and send window size to
// remote host
ConnectionStatus status;
- Error error;
+ Status error;
m_stdio_communication.Write(tmp, read, status, &error);
if (error.Fail()) {
return SendErrorResponse(0x15);
@@ -2068,30 +2247,21 @@ GDBRemoteCommunicationServerLLGS::Handle_interrupt(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
- __FUNCTION__);
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOG(log, "failed, no process available");
return SendErrorResponse(0x15);
}
// Interrupt the process.
- Error error = m_debugged_process_sp->Interrupt();
+ Status error = m_debugged_process_up->Interrupt();
if (error.Fail()) {
- if (log) {
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s failed for process %" PRIu64
- ": %s",
- __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString());
- }
+ LLDB_LOG(log, "failed for process {0}: {1}", m_debugged_process_up->GetID(),
+ error);
return SendErrorResponse(GDBRemoteServerError::eErrorResume);
}
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s stopped process %" PRIu64,
- __FUNCTION__, m_debugged_process_sp->GetID());
+ LLDB_LOG(log, "stopped process {0}", m_debugged_process_up->GetID());
// No response required from stop all.
return PacketResult::Success;
@@ -2102,8 +2272,8 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read(
StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
if (log)
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
@@ -2145,13 +2315,13 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read(
// Retrieve the process memory.
size_t bytes_read = 0;
- Error error = m_debugged_process_sp->ReadMemoryWithoutTrap(
+ Status error = m_debugged_process_up->ReadMemoryWithoutTrap(
read_addr, &buf[0], byte_count, bytes_read);
if (error.Fail()) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
" mem 0x%" PRIx64 ": failed to read. Error: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(), read_addr,
+ __FUNCTION__, m_debugged_process_up->GetID(), read_addr,
error.AsCString());
return SendErrorResponse(0x08);
}
@@ -2160,7 +2330,7 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read(
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
" mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes",
- __FUNCTION__, m_debugged_process_sp->GetID(), read_addr,
+ __FUNCTION__, m_debugged_process_up->GetID(), read_addr,
byte_count);
return SendErrorResponse(0x08);
}
@@ -2183,8 +2353,8 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
if (log)
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
@@ -2212,10 +2382,7 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) {
const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
if (byte_count == 0) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s nothing to write: "
- "zero-length packet",
- __FUNCTION__);
+ LLDB_LOG(log, "nothing to write: zero-length packet");
return PacketResult::Success;
}
@@ -2233,12 +2400,11 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) {
StreamGDBRemote response;
const uint64_t convert_count = packet.GetHexBytes(buf, 0);
if (convert_count != byte_count) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " mem 0x%" PRIx64 ": asked to write %" PRIu64
- " bytes, but only found %" PRIu64 " to convert.",
- __FUNCTION__, m_debugged_process_sp->GetID(), write_addr,
- byte_count, convert_count);
+ LLDB_LOG(log,
+ "pid {0} mem {1:x}: asked to write {2} bytes, but only found {3} "
+ "to convert.",
+ m_debugged_process_up->GetID(), write_addr, byte_count,
+ convert_count);
return SendIllFormedResponse(packet, "M content byte length specified did "
"not match hex-encoded content "
"length");
@@ -2246,23 +2412,17 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) {
// Write the process memory.
size_t bytes_written = 0;
- Error error = m_debugged_process_sp->WriteMemory(write_addr, &buf[0],
- byte_count, bytes_written);
+ Status error = m_debugged_process_up->WriteMemory(write_addr, &buf[0],
+ byte_count, bytes_written);
if (error.Fail()) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " mem 0x%" PRIx64 ": failed to write. Error: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(), write_addr,
- error.AsCString());
+ LLDB_LOG(log, "pid {0} mem {1:x}: failed to write. Error: {2}",
+ m_debugged_process_up->GetID(), write_addr, error);
return SendErrorResponse(0x09);
}
if (bytes_written == 0) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " mem 0x%" PRIx64 ": wrote 0 of %" PRIu64 " requested bytes",
- __FUNCTION__, m_debugged_process_sp->GetID(), write_addr,
- byte_count);
+ LLDB_LOG(log, "pid {0} mem {1:x}: wrote 0 of {2} requested bytes",
+ m_debugged_process_up->GetID(), write_addr, byte_count);
return SendErrorResponse(0x09);
}
@@ -2282,8 +2442,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported(
// Ensure we have a process running; otherwise, we can't figure this out
// since we won't have a NativeProcessProtocol.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
if (log)
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
@@ -2293,8 +2453,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported(
// Test if we can get any region back when asking for the region around NULL.
MemoryRegionInfo region_info;
- const Error error =
- m_debugged_process_sp->GetMemoryRegionInfo(0, region_info);
+ const Status error =
+ m_debugged_process_up->GetMemoryRegionInfo(0, region_info);
if (error.Fail()) {
// We don't support memory region info collection for this
// NativeProcessProtocol.
@@ -2310,8 +2470,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
// Ensure we have a process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
if (log)
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
@@ -2331,8 +2491,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
// Get the memory region info for the target address.
MemoryRegionInfo region_info;
- const Error error =
- m_debugged_process_sp->GetMemoryRegionInfo(read_addr, region_info);
+ const Status error =
+ m_debugged_process_up->GetMemoryRegionInfo(read_addr, region_info);
if (error.Fail()) {
// Return the error message.
@@ -2376,13 +2536,10 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) {
// Ensure we have a process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
- __FUNCTION__);
+ LLDB_LOG(log, "failed, no process available");
return SendErrorResponse(0x15);
}
@@ -2449,29 +2606,23 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) {
if (want_breakpoint) {
// Try to set the breakpoint.
- const Error error =
- m_debugged_process_sp->SetBreakpoint(addr, size, want_hardware);
+ const Status error =
+ m_debugged_process_up->SetBreakpoint(addr, size, want_hardware);
if (error.Success())
return SendOKResponse();
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " failed to set breakpoint: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
+ LLDB_LOG(log, "pid {0} failed to set breakpoint: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(0x09);
} else {
// Try to set the watchpoint.
- const Error error = m_debugged_process_sp->SetWatchpoint(
+ const Status error = m_debugged_process_up->SetWatchpoint(
addr, size, watch_flags, want_hardware);
if (error.Success())
return SendOKResponse();
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " failed to set watchpoint: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
+ LLDB_LOG(log, "pid {0} failed to set watchpoint: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(0x09);
}
}
@@ -2479,13 +2630,10 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) {
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
// Ensure we have a process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
- __FUNCTION__);
+ LLDB_LOG(log, "failed, no process available");
return SendErrorResponse(0x15);
}
@@ -2496,12 +2644,14 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
packet, "Too short z packet, missing software/hardware specifier");
bool want_breakpoint = true;
+ bool want_hardware = false;
const GDBStoppointType stoppoint_type =
GDBStoppointType(packet.GetS32(eStoppointInvalid));
switch (stoppoint_type) {
case eBreakpointHardware:
want_breakpoint = true;
+ want_hardware = true;
break;
case eBreakpointSoftware:
want_breakpoint = true;
@@ -2544,27 +2694,22 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
if (want_breakpoint) {
// Try to clear the breakpoint.
- const Error error = m_debugged_process_sp->RemoveBreakpoint(addr);
+ const Status error =
+ m_debugged_process_up->RemoveBreakpoint(addr, want_hardware);
if (error.Success())
return SendOKResponse();
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " failed to remove breakpoint: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
+ LLDB_LOG(log, "pid {0} failed to remove breakpoint: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(0x09);
} else {
// Try to clear the watchpoint.
- const Error error = m_debugged_process_sp->RemoveWatchpoint(addr);
+ const Status error = m_debugged_process_up->RemoveWatchpoint(addr);
if (error.Success())
return SendOKResponse();
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " failed to remove watchpoint: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
+ LLDB_LOG(log, "pid {0} failed to remove watchpoint: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(0x09);
}
}
@@ -2574,8 +2719,8 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
// Ensure we have a process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
if (log)
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
@@ -2594,7 +2739,7 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) {
// Double check that we have such a thread.
// TODO investigate: on MacOSX we might need to do an UpdateThreads () here.
- NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID(tid);
+ NativeThreadProtocolSP thread_sp = m_debugged_process_up->GetThreadByID(tid);
if (!thread_sp || thread_sp->GetID() != tid)
return SendErrorResponse(0x33);
@@ -2607,12 +2752,12 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) {
// All other threads stop while we're single stepping a thread.
actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
- Error error = m_debugged_process_sp->Resume(actions);
+ Status error = m_debugged_process_up->Resume(actions);
if (error.Fail()) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
" tid %" PRIu64 " Resume() failed with error: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(), tid,
+ __FUNCTION__, m_debugged_process_up->GetID(), tid,
error.AsCString());
return SendErrorResponse(0x49);
}
@@ -2625,7 +2770,7 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read(
StringExtractorGDBRemote &packet) {
// *BSD impls should be able to do this too.
-#if defined(__linux__)
+#if defined(__linux__) || defined(__NetBSD__)
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
// Parse out the offset.
@@ -2653,10 +2798,10 @@ GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read(
"qXfer:auxv:read:: packet missing length");
// Grab the auxv data if we need it.
- if (!m_active_auxv_buffer_sp) {
+ if (!m_active_auxv_buffer_up) {
// Make sure we have a valid process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
if (log)
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
@@ -2665,55 +2810,45 @@ GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read(
}
// Grab the auxv data.
- m_active_auxv_buffer_sp = Host::GetAuxvData(m_debugged_process_sp->GetID());
- if (!m_active_auxv_buffer_sp ||
- m_active_auxv_buffer_sp->GetByteSize() == 0) {
- // Hmm, no auxv data, call that an error.
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s failed, no auxv data "
- "retrieved",
- __FUNCTION__);
- m_active_auxv_buffer_sp.reset();
- return SendErrorResponse(0x11);
+ auto buffer_or_error = m_debugged_process_up->GetAuxvData();
+ if (!buffer_or_error) {
+ std::error_code ec = buffer_or_error.getError();
+ LLDB_LOG(log, "no auxv data retrieved: {0}", ec.message());
+ return SendErrorResponse(ec.value());
}
+ m_active_auxv_buffer_up = std::move(*buffer_or_error);
}
- // FIXME find out if/how I lock the stream here.
-
StreamGDBRemote response;
bool done_with_buffer = false;
- if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize()) {
+ llvm::StringRef buffer = m_active_auxv_buffer_up->getBuffer();
+ if (auxv_offset >= buffer.size()) {
// We have nothing left to send. Mark the buffer as complete.
response.PutChar('l');
done_with_buffer = true;
} else {
// Figure out how many bytes are available starting at the given offset.
- const uint64_t bytes_remaining =
- m_active_auxv_buffer_sp->GetByteSize() - auxv_offset;
-
- // Figure out how many bytes we're going to read.
- const uint64_t bytes_to_read =
- (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length;
+ buffer = buffer.drop_front(auxv_offset);
// Mark the response type according to whether we're reading the remainder
// of the auxv data.
- if (bytes_to_read >= bytes_remaining) {
+ if (auxv_length >= buffer.size()) {
// There will be nothing left to read after this
response.PutChar('l');
done_with_buffer = true;
} else {
// There will still be bytes to read after this request.
response.PutChar('m');
+ buffer = buffer.take_front(auxv_length);
}
// Now write the data in encoded binary form.
- response.PutEscapedBytes(m_active_auxv_buffer_sp->GetBytes() + auxv_offset,
- bytes_to_read);
+ response.PutEscapedBytes(buffer.data(), buffer.size());
}
if (done_with_buffer)
- m_active_auxv_buffer_sp.reset();
+ m_active_auxv_buffer_up.reset();
return SendPacketNoLock(response.GetString());
#else
@@ -2743,23 +2878,19 @@ GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState(
// Grab the register context for the thread.
NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext());
if (!reg_context_sp) {
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64
- " failed, no register context available for the thread",
- __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID());
+ LLDB_LOG(
+ log,
+ "pid {0} tid {1} failed, no register context available for the thread",
+ m_debugged_process_up->GetID(), thread_sp->GetID());
return SendErrorResponse(0x15);
}
// Save registers to a buffer.
DataBufferSP register_data_sp;
- Error error = reg_context_sp->ReadAllRegisterValues(register_data_sp);
+ Status error = reg_context_sp->ReadAllRegisterValues(register_data_sp);
if (error.Fail()) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " failed to save all register values: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
+ LLDB_LOG(log, "pid {0} failed to save all register values: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(0x75);
}
@@ -2793,10 +2924,8 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState(
const uint32_t save_id = packet.GetU32(0);
if (save_id == 0) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s QRestoreRegisterState "
- "packet has malformed save id, expecting decimal uint32_t",
- __FUNCTION__);
+ LLDB_LOG(log, "QRestoreRegisterState packet has malformed save id, "
+ "expecting decimal uint32_t");
return SendErrorResponse(0x76);
}
@@ -2814,11 +2943,10 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState(
// Grab the register context for the thread.
NativeRegisterContextSP reg_context_sp(thread_sp->GetRegisterContext());
if (!reg_context_sp) {
- if (log)
- log->Printf(
- "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64
- " failed, no register context available for the thread",
- __FUNCTION__, m_debugged_process_sp->GetID(), thread_sp->GetID());
+ LLDB_LOG(
+ log,
+ "pid {0} tid {1} failed, no register context available for the thread",
+ m_debugged_process_up->GetID(), thread_sp->GetID());
return SendErrorResponse(0x15);
}
@@ -2830,10 +2958,9 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState(
// Find the register set buffer for the given save id.
auto it = m_saved_registers_map.find(save_id);
if (it == m_saved_registers_map.end()) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " does not have a register set save buffer for id %" PRIu32,
- __FUNCTION__, m_debugged_process_sp->GetID(), save_id);
+ LLDB_LOG(log,
+ "pid {0} does not have a register set save buffer for id {1}",
+ m_debugged_process_up->GetID(), save_id);
return SendErrorResponse(0x77);
}
register_data_sp = it->second;
@@ -2842,13 +2969,10 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState(
m_saved_registers_map.erase(it);
}
- Error error = reg_context_sp->WriteAllRegisterValues(register_data_sp);
+ Status error = reg_context_sp->WriteAllRegisterValues(register_data_sp);
if (error.Fail()) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
- " failed to restore all register values: %s",
- __FUNCTION__, m_debugged_process_sp->GetID(),
- error.AsCString());
+ LLDB_LOG(log, "pid {0} failed to restore all register values: {1}",
+ m_debugged_process_up->GetID(), error);
return SendErrorResponse(0x77);
}
@@ -2877,7 +3001,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach(
"pid %" PRIu64,
__FUNCTION__, pid);
- Error error = AttachToProcess(pid);
+ Status error = AttachToProcess(pid);
if (error.Fail()) {
if (log)
@@ -2888,7 +3012,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach(
}
// Notify we attached by sending a stop packet.
- return SendStopReasonForState(m_debugged_process_sp->GetState());
+ return SendStopReasonForState(m_debugged_process_up->GetState());
}
GDBRemoteCommunication::PacketResult
@@ -2898,8 +3022,8 @@ GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) {
StopSTDIOForwarding();
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
if (log)
log->Printf(
"GDBRemoteCommunicationServerLLGS::%s failed, no process available",
@@ -2921,16 +3045,16 @@ GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) {
return SendIllFormedResponse(packet, "D failed to parse the process id");
}
- if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_sp->GetID() != pid) {
+ if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_up->GetID() != pid) {
return SendIllFormedResponse(packet, "Invalid pid");
}
- const Error error = m_debugged_process_sp->Detach();
+ const Status error = m_debugged_process_up->Detach();
if (error.Fail()) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to detach from "
"pid %" PRIu64 ": %s\n",
- __FUNCTION__, m_debugged_process_sp->GetID(),
+ __FUNCTION__, m_debugged_process_up->GetID(),
error.AsCString());
return SendErrorResponse(0x01);
}
@@ -2961,24 +3085,18 @@ GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
// Ensure we have a debugged process.
- if (!m_debugged_process_sp ||
- (m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID))
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
return SendErrorResponse(50);
-
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid "
- "%" PRIu64,
- __FUNCTION__, m_debugged_process_sp->GetID());
+ LLDB_LOG(log, "preparing packet for pid {0}", m_debugged_process_up->GetID());
StreamString response;
const bool threads_with_valid_stop_info_only = false;
JSONArray::SP threads_array_sp = GetJSONThreadsInfo(
- *m_debugged_process_sp, threads_with_valid_stop_info_only);
+ *m_debugged_process_up, threads_with_valid_stop_info_only);
if (!threads_array_sp) {
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s failed to prepare a "
- "packet for pid %" PRIu64,
- __FUNCTION__, m_debugged_process_sp->GetID());
+ LLDB_LOG(log, "failed to prepare a packet for pid {0}",
+ m_debugged_process_up->GetID());
return SendErrorResponse(52);
}
@@ -2992,8 +3110,8 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo(
StringExtractorGDBRemote &packet) {
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)
+ if (!m_debugged_process_up ||
+ m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)
return SendErrorResponse(68);
packet.SetFilePos(strlen("qWatchpointSupportInfo"));
@@ -3002,9 +3120,14 @@ GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo(
if (packet.GetChar() != ':')
return SendErrorResponse(67);
- uint32_t num = m_debugged_process_sp->GetMaxWatchpoints();
+ auto hw_debug_cap = m_debugged_process_up->GetHardwareDebugSupportInfo();
+
StreamGDBRemote response;
- response.Printf("num:%d;", num);
+ if (hw_debug_cap == llvm::None)
+ response.Printf("num:0;");
+ else
+ response.Printf("num:%d;", hw_debug_cap->second);
+
return SendPacketNoLock(response.GetString());
}
@@ -3012,8 +3135,8 @@ GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress(
StringExtractorGDBRemote &packet) {
// Fail if we don't have a current process.
- if (!m_debugged_process_sp ||
- m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)
+ if (!m_debugged_process_up ||
+ m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)
return SendErrorResponse(67);
packet.SetFilePos(strlen("qFileLoadAddress:"));
@@ -3024,8 +3147,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress(
packet.GetHexByteString(file_name);
lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS;
- Error error =
- m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address);
+ Status error =
+ m_debugged_process_up->GetFileLoadAddress(file_name, file_load_address);
if (error.Fail())
return SendErrorResponse(69);
@@ -3037,6 +3160,40 @@ GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress(
return SendPacketNoLock(response.GetString());
}
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QPassSignals(
+ StringExtractorGDBRemote &packet) {
+ std::vector<int> signals;
+ packet.SetFilePos(strlen("QPassSignals:"));
+
+ // Read sequence of hex signal numbers divided by a semicolon and
+ // optionally spaces.
+ while (packet.GetBytesLeft() > 0) {
+ int signal = packet.GetS32(-1, 16);
+ if (signal < 0)
+ return SendIllFormedResponse(packet, "Failed to parse signal number.");
+ signals.push_back(signal);
+
+ packet.SkipSpaces();
+ char separator = packet.GetChar();
+ if (separator == '\0')
+ break; // End of string
+ if (separator != ';')
+ return SendIllFormedResponse(packet, "Invalid separator,"
+ " expected semicolon.");
+ }
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_up)
+ return SendErrorResponse(68);
+
+ Status error = m_debugged_process_up->IgnoreSignals(signals);
+ if (error.Fail())
+ return SendErrorResponse(69);
+
+ return SendOKResponse();
+}
+
void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
@@ -3044,7 +3201,7 @@ void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() {
if (m_stdio_communication.IsConnected()) {
auto connection = m_stdio_communication.GetConnection();
if (connection) {
- Error error;
+ Status error;
connection->Disconnect(&error);
if (error.Success()) {
@@ -3067,8 +3224,8 @@ NativeThreadProtocolSP GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix(
NativeThreadProtocolSP thread_sp;
// We have no thread if we don't have a process.
- if (!m_debugged_process_sp ||
- m_debugged_process_sp->GetID() == LLDB_INVALID_PROCESS_ID)
+ if (!m_debugged_process_up ||
+ m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)
return thread_sp;
// If the client hasn't asked for thread suffix support, there will not be a
@@ -3080,9 +3237,9 @@ NativeThreadProtocolSP GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix(
return thread_sp;
else if (current_tid == 0) {
// Pick a thread.
- return m_debugged_process_sp->GetThreadAtIndex(0);
+ return m_debugged_process_up->GetThreadAtIndex(0);
} else
- return m_debugged_process_sp->GetThreadByID(current_tid);
+ return m_debugged_process_up->GetThreadByID(current_tid);
}
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
@@ -3112,7 +3269,7 @@ NativeThreadProtocolSP GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix(
packet.SetFilePos(packet.GetFilePos() + strlen("thread:"));
const lldb::tid_t tid = packet.GetHexMaxU64(false, 0);
if (tid != 0)
- return m_debugged_process_sp->GetThreadByID(tid);
+ return m_debugged_process_up->GetThreadByID(tid);
return thread_sp;
}
@@ -3122,9 +3279,9 @@ lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID() const {
// Use whatever the debug process says is the current thread id
// since the protocol either didn't specify or specified we want
// any/all threads marked as the current thread.
- if (!m_debugged_process_sp)
+ if (!m_debugged_process_up)
return LLDB_INVALID_THREAD_ID;
- return m_debugged_process_sp->GetCurrentThreadID();
+ return m_debugged_process_up->GetCurrentThreadID();
}
// Use the specific current thread id set by the gdb remote protocol.
return m_current_tid;
@@ -3136,28 +3293,18 @@ uint32_t GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID() {
}
void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | GDBR_LOG_PROCESS));
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s()", __FUNCTION__);
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
-// Clear any auxv cached data.
-// *BSD impls should be able to do this too.
-#if defined(__linux__)
- if (log)
- log->Printf("GDBRemoteCommunicationServerLLGS::%s clearing auxv buffer "
- "(previously %s)",
- __FUNCTION__,
- m_active_auxv_buffer_sp ? "was set" : "was not set");
- m_active_auxv_buffer_sp.reset();
-#endif
+ LLDB_LOG(log, "clearing auxv buffer: {0}", m_active_auxv_buffer_up.get());
+ m_active_auxv_buffer_up.reset();
}
FileSpec
GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path,
const ArchSpec &arch) {
- if (m_debugged_process_sp) {
+ if (m_debugged_process_up) {
FileSpec file_spec;
- if (m_debugged_process_sp
+ if (m_debugged_process_up
->GetLoadedModuleFileSpec(module_path.c_str(), file_spec)
.Success()) {
if (file_spec.Exists())
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index fa52cda..7119947 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -39,7 +39,9 @@ public:
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
- GDBRemoteCommunicationServerLLGS(MainLoop &mainloop);
+ GDBRemoteCommunicationServerLLGS(
+ MainLoop &mainloop,
+ const NativeProcessProtocol::Factory &process_factory);
//------------------------------------------------------------------
/// Specify the program to launch and its arguments.
@@ -51,10 +53,10 @@ public:
/// The number of elements in the args array of cstring pointers.
///
/// @return
- /// An Error object indicating the success or failure of making
+ /// An Status object indicating the success or failure of making
/// the setting.
//------------------------------------------------------------------
- Error SetLaunchArguments(const char *const args[], int argc);
+ Status SetLaunchArguments(const char *const args[], int argc);
//------------------------------------------------------------------
/// Specify the launch flags for the process.
@@ -63,10 +65,10 @@ public:
/// The launch flags to use when launching this process.
///
/// @return
- /// An Error object indicating the success or failure of making
+ /// An Status object indicating the success or failure of making
/// the setting.
//------------------------------------------------------------------
- Error SetLaunchFlags(unsigned int launch_flags);
+ Status SetLaunchFlags(unsigned int launch_flags);
//------------------------------------------------------------------
/// Launch a process with the current launch settings.
@@ -76,10 +78,10 @@ public:
/// with all the information for a child process to be launched.
///
/// @return
- /// An Error object indicating the success or failure of the
+ /// An Status object indicating the success or failure of the
/// launch.
//------------------------------------------------------------------
- Error LaunchProcess() override;
+ Status LaunchProcess() override;
//------------------------------------------------------------------
/// Attach to a process.
@@ -88,10 +90,10 @@ public:
/// configured Platform.
///
/// @return
- /// An Error object indicating the success or failure of the
+ /// An Status object indicating the success or failure of the
/// attach operation.
//------------------------------------------------------------------
- Error AttachToProcess(lldb::pid_t pid);
+ Status AttachToProcess(lldb::pid_t pid);
//------------------------------------------------------------------
// NativeProcessProtocol::NativeDelegate overrides
@@ -103,25 +105,26 @@ public:
void DidExec(NativeProcessProtocol *process) override;
- Error InitializeConnection(std::unique_ptr<Connection> &&connection);
+ Status InitializeConnection(std::unique_ptr<Connection> &&connection);
protected:
MainLoop &m_mainloop;
MainLoop::ReadHandleUP m_network_handle_up;
- lldb::tid_t m_current_tid;
- lldb::tid_t m_continue_tid;
+ const NativeProcessProtocol::Factory &m_process_factory;
+ lldb::tid_t m_current_tid = LLDB_INVALID_THREAD_ID;
+ lldb::tid_t m_continue_tid = LLDB_INVALID_THREAD_ID;
std::recursive_mutex m_debugged_process_mutex;
- NativeProcessProtocolSP m_debugged_process_sp;
+ std::unique_ptr<NativeProcessProtocol> m_debugged_process_up;
Communication m_stdio_communication;
MainLoop::ReadHandleUP m_stdio_handle_up;
- lldb::StateType m_inferior_prev_state;
- lldb::DataBufferSP m_active_auxv_buffer_sp;
+ lldb::StateType m_inferior_prev_state = lldb::StateType::eStateInvalid;
+ std::unique_ptr<llvm::MemoryBuffer> m_active_auxv_buffer_up;
std::mutex m_saved_registers_mutex;
std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
- uint32_t m_next_saved_registers_id;
- bool m_handshake_completed : 1;
+ uint32_t m_next_saved_registers_id = 1;
+ bool m_handshake_completed = false;
PacketResult SendONotification(const char *buffer, uint32_t len);
@@ -189,6 +192,14 @@ protected:
PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet);
+ PacketResult Handle_jTraceStart(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jTraceRead(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jTraceStop(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet);
+
PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
@@ -203,6 +214,8 @@ protected:
PacketResult Handle_qFileLoadAddress(StringExtractorGDBRemote &packet);
+ PacketResult Handle_QPassSignals(StringExtractorGDBRemote &packet);
+
void SetCurrentThreadID(lldb::tid_t tid);
lldb::tid_t GetCurrentThreadID() const;
@@ -211,7 +224,7 @@ protected:
lldb::tid_t GetContinueThreadID() const { return m_continue_tid; }
- Error SetSTDIOFileDescriptor(int fd);
+ Status SetSTDIOFileDescriptor(int fd);
FileSpec FindModuleFile(const std::string &module_path,
const ArchSpec &arch) override;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
index 1106974..977c34c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
@@ -20,25 +20,25 @@
// Other libraries and framework includes
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Threading.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamGDBRemote.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Target/FileAction.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/JSON.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamGDBRemote.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/UriParser.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
-#include "Utility/UriParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -82,8 +82,8 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
&GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);
RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
- [this](StringExtractorGDBRemote packet, Error &error,
- bool &interrupt, bool &quit) {
+ [](StringExtractorGDBRemote packet, Status &error,
+ bool &interrupt, bool &quit) {
error.SetErrorString("interrupt received");
interrupt = true;
return PacketResult::Success;
@@ -95,7 +95,7 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
//----------------------------------------------------------------------
GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() {}
-Error GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
+Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid,
uint16_t &port, std::string &socket_name) {
if (port == UINT16_MAX)
@@ -147,7 +147,7 @@ Error GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
port_ptr = nullptr;
}
- Error error = StartDebugserverProcess(
+ Status error = StartDebugserverProcess(
url.str().c_str(), nullptr, debugserver_launch_info, port_ptr, &args, -1);
pid = debugserver_launch_info.GetProcessID();
@@ -192,7 +192,7 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
std::string socket_name;
- Error error =
+ Status error =
LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name);
if (error.Fail()) {
if (log)
@@ -353,15 +353,13 @@ GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo(
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir(
StringExtractorGDBRemote &packet) {
- // If this packet is sent to a platform, then change the current working
- // directory
- char cwd[PATH_MAX];
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- return SendErrorResponse(errno);
+ llvm::SmallString<64> cwd;
+ if (std::error_code ec = llvm::sys::fs::current_path(cwd))
+ return SendErrorResponse(ec.value());
StreamString response;
- response.PutBytesAsRawHex8(cwd, strlen(cwd));
+ response.PutBytesAsRawHex8(cwd.data(), cwd.size());
return SendPacketNoLock(response.GetString());
}
@@ -372,10 +370,8 @@ GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir(
std::string path;
packet.GetHexByteString(path);
- // If this packet is sent to a platform, then change the current working
- // directory
- if (::chdir(path.c_str()) != 0)
- return SendErrorResponse(errno);
+ if (std::error_code ec = llvm::sys::fs::set_current_path(path))
+ return SendErrorResponse(ec.value());
return SendOKResponse();
}
@@ -443,10 +439,10 @@ bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped(
return true;
}
-Error GDBRemoteCommunicationServerPlatform::LaunchProcess() {
+Status GDBRemoteCommunicationServerPlatform::LaunchProcess() {
if (!m_process_launch_info.GetArguments().GetArgumentCount())
- return Error("%s: no process command line specified to launch",
- __FUNCTION__);
+ return Status("%s: no process command line specified to launch",
+ __FUNCTION__);
// specify the process monitor if not already set. This should
// generally be what happens since we need to reap started
@@ -458,7 +454,7 @@ Error GDBRemoteCommunicationServerPlatform::LaunchProcess() {
this, std::placeholders::_1),
false);
- Error error = Host::LaunchProcess(m_process_launch_info);
+ Status error = Host::LaunchProcess(m_process_launch_info);
if (!error.Success()) {
fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__,
m_process_launch_info.GetArguments().GetArgumentAtIndex(0));
@@ -532,9 +528,9 @@ bool GDBRemoteCommunicationServerPlatform::FreePortForProcess(lldb::pid_t pid) {
const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() {
static FileSpec g_domainsocket_dir;
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
const char *domainsocket_dir_env =
::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR");
if (domainsocket_dir_env != nullptr)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
index 472d86e..aed5106 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
@@ -34,7 +34,7 @@ public:
~GDBRemoteCommunicationServerPlatform() override;
- Error LaunchProcess() override;
+ Status LaunchProcess() override;
// Set both ports to zero to let the platform automatically bind to
// a port chosen by the OS.
@@ -61,9 +61,9 @@ public:
void SetInferiorArguments(const lldb_private::Args &args);
- Error LaunchGDBServer(const lldb_private::Args &args, std::string hostname,
- lldb::pid_t &pid, uint16_t &port,
- std::string &socket_name);
+ Status LaunchGDBServer(const lldb_private::Args &args, std::string hostname,
+ lldb::pid_t &pid, uint16_t &port,
+ std::string &socket_name);
void SetPendingGdbServer(lldb::pid_t pid, uint16_t port,
const std::string &socket_name);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index 27ce67d..612c714 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -12,14 +12,13 @@
// C Includes
// C++ Includes
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
-#include "lldb/Utility/Utils.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/StreamString.h"
// Project includes
#include "ProcessGDBRemote.h"
#include "ProcessGDBRemoteLog.h"
@@ -96,8 +95,8 @@ bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info,
// Read the register
if (ReadRegisterBytes(reg_info, m_reg_data)) {
const bool partial_data_ok = false;
- Error error(value.SetValueFromData(reg_info, m_reg_data,
- reg_info->byte_offset, partial_data_ok));
+ Status error(value.SetValueFromData(
+ reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok));
return error.Success();
}
return false;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
index 5b3e04e..8ef91af 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -17,9 +17,9 @@
// Other libraries and framework includes
// Project includes
#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-private.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 4b4d62d..e46bbeb 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -16,6 +16,7 @@
#include <netinet/in.h>
#include <sys/mman.h> // for mmap
#include <sys/socket.h>
+#include <unistd.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
@@ -35,14 +36,13 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Core/Value.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostThread.h"
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Host/ThreadLauncher.h"
@@ -65,7 +65,9 @@
#include "lldb/Target/TargetList.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Utility/CleanUp.h"
-#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
// Project includes
#include "GDBRemoteRegisterContext.h"
@@ -80,6 +82,7 @@
#include "lldb/Host/Host.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
#define DEBUGSERVER_BASENAME "debugserver"
@@ -96,8 +99,8 @@ namespace lldb {
// function and get the packet history dumped to a file.
void DumpProcessGDBRemotePacketHistory(void *p, const char *path) {
StreamFile strm;
- Error error(strm.GetFile().Open(path, File::eOpenOptionWrite |
- File::eOpenOptionCanCreate));
+ Status error(strm.GetFile().Open(path, File::eOpenOptionWrite |
+ File::eOpenOptionCanCreate));
if (error.Success())
((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory(strm);
}
@@ -323,7 +326,7 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition(
const FileSpec &target_definition_fspec) {
ScriptInterpreter *interpreter =
GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
- Error error;
+ Status error;
StructuredData::ObjectSP module_object_sp(
interpreter->LoadPluginModule(target_definition_fspec, error));
if (module_object_sp) {
@@ -576,7 +579,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
uint32_t ret_val =
opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes);
assert(dwarf_opcode_len == ret_val);
-
+ UNUSED_IF_ASSERT_DISABLED(ret_val);
reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data();
}
}
@@ -598,7 +601,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
// gets called in DidAttach, when the target architecture (and
// consequently the ABI we'll get from
// the process) may be wrong.
- ABISP abi_to_use = ABI::FindPlugin(arch_to_use);
+ ABISP abi_to_use = ABI::FindPlugin(shared_from_this(), arch_to_use);
AugmentRegisterInfoViaABI(reg_info, reg_name, abi_to_use);
@@ -638,23 +641,23 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
m_register_info.Finalize(GetTarget().GetArchitecture());
}
-Error ProcessGDBRemote::WillLaunch(Module *module) {
+Status ProcessGDBRemote::WillLaunch(Module *module) {
return WillLaunchOrAttach();
}
-Error ProcessGDBRemote::WillAttachToProcessWithID(lldb::pid_t pid) {
+Status ProcessGDBRemote::WillAttachToProcessWithID(lldb::pid_t pid) {
return WillLaunchOrAttach();
}
-Error ProcessGDBRemote::WillAttachToProcessWithName(const char *process_name,
- bool wait_for_launch) {
+Status ProcessGDBRemote::WillAttachToProcessWithName(const char *process_name,
+ bool wait_for_launch) {
return WillLaunchOrAttach();
}
-Error ProcessGDBRemote::DoConnectRemote(Stream *strm,
- llvm::StringRef remote_url) {
+Status ProcessGDBRemote::DoConnectRemote(Stream *strm,
+ llvm::StringRef remote_url) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
- Error error(WillLaunchOrAttach());
+ Status error(WillLaunchOrAttach());
if (error.Fail())
return error;
@@ -743,8 +746,8 @@ Error ProcessGDBRemote::DoConnectRemote(Stream *strm,
return error;
}
-Error ProcessGDBRemote::WillLaunchOrAttach() {
- Error error;
+Status ProcessGDBRemote::WillLaunchOrAttach() {
+ Status error;
m_stdio_communication.Clear();
return error;
}
@@ -752,10 +755,10 @@ Error ProcessGDBRemote::WillLaunchOrAttach() {
//----------------------------------------------------------------------
// Process Control
//----------------------------------------------------------------------
-Error ProcessGDBRemote::DoLaunch(Module *exe_module,
- ProcessLaunchInfo &launch_info) {
+Status ProcessGDBRemote::DoLaunch(Module *exe_module,
+ ProcessLaunchInfo &launch_info) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
- Error error;
+ Status error;
if (log)
log->Printf("ProcessGDBRemote::%s() entered", __FUNCTION__);
@@ -964,8 +967,8 @@ Error ProcessGDBRemote::DoLaunch(Module *exe_module,
return error;
}
-Error ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
- Error error;
+Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
+ Status error;
// Only connect if we have a valid connect URL
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
@@ -1030,6 +1033,7 @@ Error ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
m_gdb_comm.GetHostInfo();
m_gdb_comm.GetVContSupported('c');
m_gdb_comm.GetVAttachOrWaitSupported();
+ m_gdb_comm.EnableErrorStringInPacket();
// Ask the remote server for the default thread id
if (GetTarget().GetNonStopModeEnabled())
@@ -1168,10 +1172,10 @@ void ProcessGDBRemote::DidLaunch() {
DidLaunchOrAttach(process_arch);
}
-Error ProcessGDBRemote::DoAttachToProcessWithID(
+Status ProcessGDBRemote::DoAttachToProcessWithID(
lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
- Error error;
+ Status error;
if (log)
log->Printf("ProcessGDBRemote::%s()", __FUNCTION__);
@@ -1196,9 +1200,9 @@ Error ProcessGDBRemote::DoAttachToProcessWithID(
return error;
}
-Error ProcessGDBRemote::DoAttachToProcessWithName(
+Status ProcessGDBRemote::DoAttachToProcessWithName(
const char *process_name, const ProcessAttachInfo &attach_info) {
- Error error;
+ Status error;
// Clear out and clean up from any current state
Clear();
@@ -1235,6 +1239,32 @@ Error ProcessGDBRemote::DoAttachToProcessWithName(
return error;
}
+lldb::user_id_t ProcessGDBRemote::StartTrace(const TraceOptions &options,
+ Status &error) {
+ return m_gdb_comm.SendStartTracePacket(options, error);
+}
+
+Status ProcessGDBRemote::StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) {
+ return m_gdb_comm.SendStopTracePacket(uid, thread_id);
+}
+
+Status ProcessGDBRemote::GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+ return m_gdb_comm.SendGetDataPacket(uid, thread_id, buffer, offset);
+}
+
+Status ProcessGDBRemote::GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+ return m_gdb_comm.SendGetMetaDataPacket(uid, thread_id, buffer, offset);
+}
+
+Status ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid,
+ TraceOptions &options) {
+ return m_gdb_comm.SendGetTraceConfigPacket(uid, options);
+}
+
void ProcessGDBRemote::DidExit() {
// When we exit, disconnect from the GDB server communications
m_gdb_comm.Disconnect();
@@ -1246,18 +1276,18 @@ void ProcessGDBRemote::DidAttach(ArchSpec &process_arch) {
DidLaunchOrAttach(process_arch);
}
-Error ProcessGDBRemote::WillResume() {
+Status ProcessGDBRemote::WillResume() {
m_continue_c_tids.clear();
m_continue_C_tids.clear();
m_continue_s_tids.clear();
m_continue_S_tids.clear();
m_jstopinfo_sp.reset();
m_jthreadsinfo_sp.reset();
- return Error();
+ return Status();
}
-Error ProcessGDBRemote::DoResume() {
- Error error;
+Status ProcessGDBRemote::DoResume() {
+ Status error;
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
if (log)
log->Printf("ProcessGDBRemote::Resume()");
@@ -1616,9 +1646,7 @@ bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) {
// locker will keep a mutex locked until it goes out of scope
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_THREAD));
- if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
- log->Printf("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__,
- GetID());
+ LLDB_LOGV(log, "pid = {0}", GetID());
size_t num_thread_ids = m_thread_ids.size();
// The "m_thread_ids" thread ID list should always be updated after each stop
@@ -1637,39 +1665,14 @@ bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list,
old_thread_list_copy.RemoveThreadByProtocolID(tid, false));
if (!thread_sp) {
thread_sp.reset(new ThreadGDBRemote(*this, tid));
- if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
- log->Printf("ProcessGDBRemote::%s Making new thread: %p for thread "
- "ID: 0x%" PRIx64 ".\n",
- __FUNCTION__, static_cast<void *>(thread_sp.get()),
- thread_sp->GetID());
+ LLDB_LOGV(log, "Making new thread: {0} for thread ID: {1:x}.",
+ thread_sp.get(), thread_sp->GetID());
} else {
- if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
- log->Printf("ProcessGDBRemote::%s Found old thread: %p for thread "
- "ID: 0x%" PRIx64 ".\n",
- __FUNCTION__, static_cast<void *>(thread_sp.get()),
- thread_sp->GetID());
- }
- // The m_thread_pcs vector has pc values in big-endian order, not
- // target-endian, unlike most
- // of the register read/write packets in gdb-remote protocol.
- // Early in the process startup, we may not yet have set the process
- // ByteOrder so we ignore these;
- // they are a performance improvement over fetching thread register values
- // individually, the
- // method we will fall back to if needed.
- if (m_thread_ids.size() == m_thread_pcs.size() && thread_sp.get() &&
- GetByteOrder() != eByteOrderInvalid) {
- ThreadGDBRemote *gdb_thread =
- static_cast<ThreadGDBRemote *>(thread_sp.get());
- RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
- if (reg_ctx_sp) {
- uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(
- eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
- if (pc_regnum != LLDB_INVALID_REGNUM) {
- gdb_thread->PrivateSetRegisterValue(pc_regnum, m_thread_pcs[i]);
- }
- }
+ LLDB_LOGV(log, "Found old thread: {0} for thread ID: {1:x}.",
+ thread_sp.get(), thread_sp->GetID());
}
+
+ SetThreadPc(thread_sp, i);
new_thread_list.AddThreadSortedByIndexID(thread_sp);
}
}
@@ -1689,6 +1692,22 @@ bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list,
return true;
}
+void ProcessGDBRemote::SetThreadPc(const ThreadSP &thread_sp, uint64_t index) {
+ if (m_thread_ids.size() == m_thread_pcs.size() && thread_sp.get() &&
+ GetByteOrder() != eByteOrderInvalid) {
+ ThreadGDBRemote *gdb_thread =
+ static_cast<ThreadGDBRemote *>(thread_sp.get());
+ RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
+ if (reg_ctx_sp) {
+ uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ if (pc_regnum != LLDB_INVALID_REGNUM) {
+ gdb_thread->PrivateSetRegisterValue(pc_regnum, m_thread_pcs[index]);
+ }
+ }
+ }
+}
+
bool ProcessGDBRemote::GetThreadStopInfoFromJSON(
ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp) {
// See if we got thread stop infos for all threads via the "jThreadsInfo"
@@ -1774,6 +1793,11 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
static_cast<ThreadGDBRemote *>(thread_sp.get());
gdb_thread->GetRegisterContext()->InvalidateIfNeeded(true);
+ auto iter = std::find(m_thread_ids.begin(), m_thread_ids.end(), tid);
+ if (iter != m_thread_ids.end()) {
+ SetThreadPc(thread_sp, iter - m_thread_ids.begin());
+ }
+
for (const auto &pair : expedited_register_map) {
StringExtractor reg_value_extractor;
reg_value_extractor.GetStringRef() = pair.second;
@@ -2118,9 +2142,9 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
if (mem_cache_dict->GetValueForKeyAsInteger<lldb::addr_t>(
"address", mem_cache_addr)) {
if (mem_cache_addr != LLDB_INVALID_ADDRESS) {
- StringExtractor bytes;
- if (mem_cache_dict->GetValueForKeyAsString(
- "bytes", bytes.GetStringRef())) {
+ llvm::StringRef str;
+ if (mem_cache_dict->GetValueForKeyAsString("bytes", str)) {
+ StringExtractor bytes(str);
bytes.SetFilePos(0);
const size_t byte_size = bytes.GetStringRef().size() / 2;
@@ -2405,8 +2429,8 @@ void ProcessGDBRemote::RefreshStateAfterStop() {
m_thread_list_real.RefreshStateAfterStop();
}
-Error ProcessGDBRemote::DoHalt(bool &caused_stop) {
- Error error;
+Status ProcessGDBRemote::DoHalt(bool &caused_stop) {
+ Status error;
if (m_public_state.GetValue() == eStateAttaching) {
// We are being asked to halt during an attach. We need to just close
@@ -2417,8 +2441,8 @@ Error ProcessGDBRemote::DoHalt(bool &caused_stop) {
return error;
}
-Error ProcessGDBRemote::DoDetach(bool keep_stopped) {
- Error error;
+Status ProcessGDBRemote::DoDetach(bool keep_stopped) {
+ Status error;
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
if (log)
log->Printf("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped);
@@ -2446,8 +2470,8 @@ Error ProcessGDBRemote::DoDetach(bool keep_stopped) {
return error;
}
-Error ProcessGDBRemote::DoDestroy() {
- Error error;
+Status ProcessGDBRemote::DoDestroy() {
+ Status error;
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
if (log)
log->Printf("ProcessGDBRemote::DoDestroy()");
@@ -2729,18 +2753,21 @@ void ProcessGDBRemote::WillPublicStop() {
// Process Memory
//------------------------------------------------------------------
size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
- Error &error) {
+ Status &error) {
GetMaxMemorySize();
- if (size > m_max_memory_size) {
+ bool binary_memory_read = m_gdb_comm.GetxPacketSupported();
+ // M and m packets take 2 bytes for 1 byte of memory
+ size_t max_memory_size =
+ binary_memory_read ? m_max_memory_size : m_max_memory_size / 2;
+ if (size > max_memory_size) {
// Keep memory read sizes down to a sane limit. This function will be
// called multiple times in order to complete the task by
// lldb_private::Process so it is ok to do this.
- size = m_max_memory_size;
+ size = max_memory_size;
}
char packet[64];
int packet_len;
- bool binary_memory_read = m_gdb_comm.GetxPacketSupported();
packet_len = ::snprintf(packet, sizeof(packet), "%c%" PRIx64 ",%" PRIx64,
binary_memory_read ? 'x' : 'm', (uint64_t)addr,
(uint64_t)size);
@@ -2785,13 +2812,15 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
}
size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf,
- size_t size, Error &error) {
+ size_t size, Status &error) {
GetMaxMemorySize();
- if (size > m_max_memory_size) {
+ // M and m packets take 2 bytes for 1 byte of memory
+ size_t max_memory_size = m_max_memory_size / 2;
+ if (size > max_memory_size) {
// Keep memory read sizes down to a sane limit. This function will be
// called multiple times in order to complete the task by
// lldb_private::Process so it is ok to do this.
- size = m_max_memory_size;
+ size = max_memory_size;
}
StreamString packet;
@@ -2824,7 +2853,7 @@ size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf,
lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size,
uint32_t permissions,
- Error &error) {
+ Status &error) {
Log *log(
GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_EXPRESSIONS));
addr_t allocated_addr = LLDB_INVALID_ADDRESS;
@@ -2868,27 +2897,27 @@ lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size,
return allocated_addr;
}
-Error ProcessGDBRemote::GetMemoryRegionInfo(addr_t load_addr,
- MemoryRegionInfo &region_info) {
+Status ProcessGDBRemote::GetMemoryRegionInfo(addr_t load_addr,
+ MemoryRegionInfo &region_info) {
- Error error(m_gdb_comm.GetMemoryRegionInfo(load_addr, region_info));
+ Status error(m_gdb_comm.GetMemoryRegionInfo(load_addr, region_info));
return error;
}
-Error ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num) {
+Status ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num) {
- Error error(m_gdb_comm.GetWatchpointSupportInfo(num));
+ Status error(m_gdb_comm.GetWatchpointSupportInfo(num));
return error;
}
-Error ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num, bool &after) {
- Error error(m_gdb_comm.GetWatchpointSupportInfo(
+Status ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num, bool &after) {
+ Status error(m_gdb_comm.GetWatchpointSupportInfo(
num, after, GetTarget().GetArchitecture()));
return error;
}
-Error ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) {
- Error error;
+Status ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) {
+ Status error;
LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
switch (supported) {
@@ -2926,7 +2955,7 @@ Error ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) {
// Process STDIO
//------------------------------------------------------------------
size_t ProcessGDBRemote::PutSTDIN(const char *src, size_t src_len,
- Error &error) {
+ Status &error) {
if (m_stdio_communication.IsConnected()) {
ConnectionStatus status;
m_stdio_communication.Write(src, src_len, status, NULL);
@@ -2936,8 +2965,8 @@ size_t ProcessGDBRemote::PutSTDIN(const char *src, size_t src_len,
return 0;
}
-Error ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) {
- Error error;
+Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) {
+ Status error;
assert(bp_site != NULL);
// Get logging info
@@ -3074,8 +3103,8 @@ Error ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) {
return EnableSoftwareBreakpoint(bp_site);
}
-Error ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) {
- Error error;
+Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) {
+ Status error;
assert(bp_site != NULL);
addr_t addr = bp_site->GetLoadAddress();
user_id_t site_id = bp_site->GetID();
@@ -3143,8 +3172,8 @@ static GDBStoppointType GetGDBStoppointType(Watchpoint *wp) {
return eWatchpointWrite;
}
-Error ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) {
- Error error;
+Status ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) {
+ Status error;
if (wp) {
user_id_t watchID = wp->GetID();
addr_t addr = wp->GetLoadAddress();
@@ -3180,8 +3209,8 @@ Error ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) {
return error;
}
-Error ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) {
- Error error;
+Status ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) {
+ Status error;
if (wp) {
user_id_t watchID = wp->GetID();
@@ -3233,8 +3262,8 @@ void ProcessGDBRemote::Clear() {
m_thread_list.Clear();
}
-Error ProcessGDBRemote::DoSignal(int signo) {
- Error error;
+Status ProcessGDBRemote::DoSignal(int signo) {
+ Status error;
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
if (log)
log->Printf("ProcessGDBRemote::DoSignal (signal = %d)", signo);
@@ -3244,15 +3273,15 @@ Error ProcessGDBRemote::DoSignal(int signo) {
return error;
}
-Error ProcessGDBRemote::EstablishConnectionIfNeeded(
- const ProcessInfo &process_info) {
+Status
+ProcessGDBRemote::EstablishConnectionIfNeeded(const ProcessInfo &process_info) {
// Make sure we aren't already connected?
if (m_gdb_comm.IsConnected())
- return Error();
+ return Status();
PlatformSP platform_sp(GetTarget().GetPlatform());
if (platform_sp && !platform_sp->IsHost())
- return Error("Lost debug server connection");
+ return Status("Lost debug server connection");
auto error = LaunchAndConnectToDebugserver(process_info);
if (error.Fail()) {
@@ -3279,11 +3308,11 @@ static bool SetCloexecFlag(int fd) {
}
#endif
-Error ProcessGDBRemote::LaunchAndConnectToDebugserver(
+Status ProcessGDBRemote::LaunchAndConnectToDebugserver(
const ProcessInfo &process_info) {
using namespace std::placeholders; // For _1, _2, etc.
- Error error;
+ Status error;
if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) {
// If we locate debugserver, keep that located version around
static FileSpec g_debugserver_file_spec;
@@ -3429,9 +3458,9 @@ void ProcessGDBRemote::KillDebugserverProcess() {
}
void ProcessGDBRemote::Initialize() {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance,
DebuggerInitialize);
@@ -3741,6 +3770,43 @@ bool ProcessGDBRemote::NewThreadNotifyBreakpointHit(
return false;
}
+Status ProcessGDBRemote::UpdateAutomaticSignalFiltering() {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ LLDB_LOG(log, "Check if need to update ignored signals");
+
+ // QPassSignals package is not supported by the server,
+ // there is no way we can ignore any signals on server side.
+ if (!m_gdb_comm.GetQPassSignalsSupported())
+ return Status();
+
+ // No signals, nothing to send.
+ if (m_unix_signals_sp == nullptr)
+ return Status();
+
+ // Signals' version hasn't changed, no need to send anything.
+ uint64_t new_signals_version = m_unix_signals_sp->GetVersion();
+ if (new_signals_version == m_last_signals_version) {
+ LLDB_LOG(log, "Signals' version hasn't changed. version={0}",
+ m_last_signals_version);
+ return Status();
+ }
+
+ auto signals_to_ignore =
+ m_unix_signals_sp->GetFilteredSignals(false, false, false);
+ Status error = m_gdb_comm.SendSignalsToIgnore(signals_to_ignore);
+
+ LLDB_LOG(log,
+ "Signals' version changed. old version={0}, new version={1}, "
+ "signals ignored={2}, update result={3}",
+ m_last_signals_version, new_signals_version,
+ signals_to_ignore.size(), error);
+
+ if (error.Success())
+ m_last_signals_version = new_signals_version;
+
+ return error;
+}
+
bool ProcessGDBRemote::StartNoticingNewThreads() {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
if (m_thread_create_bp_sp) {
@@ -3785,11 +3851,11 @@ DynamicLoader *ProcessGDBRemote::GetDynamicLoader() {
return m_dyld_ap.get();
}
-Error ProcessGDBRemote::SendEventData(const char *data) {
+Status ProcessGDBRemote::SendEventData(const char *data) {
int return_value;
bool was_supported;
- Error error;
+ Status error;
return_value = m_gdb_comm.SendLaunchEventDataPacket(data, &was_supported);
if (return_value != 0) {
@@ -3960,7 +4026,7 @@ StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() {
return object_sp;
}
-Error ProcessGDBRemote::ConfigureStructuredData(
+Status ProcessGDBRemote::ConfigureStructuredData(
const ConstString &type_name, const StructuredData::ObjectSP &config_sp) {
return m_gdb_comm.ConfigureRemoteStructuredData(type_name, config_sp);
}
@@ -3990,6 +4056,21 @@ void ProcessGDBRemote::GetMaxMemorySize() {
stub_max_size = reasonable_largeish_default;
}
+ // Memory packet have other overheads too like Maddr,size:#NN
+ // Instead of calculating the bytes taken by size and addr every
+ // time, we take a maximum guess here.
+ if (stub_max_size > 70)
+ stub_max_size -= 32 + 32 + 6;
+ else {
+ // In unlikely scenario that max packet size is less then 70, we will
+ // hope that data being written is small enough to fit.
+ Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(
+ GDBR_LOG_COMM | GDBR_LOG_MEMORY));
+ if (log)
+ log->Warning("Packet size is too small. "
+ "LLDB may face problems while writing memory");
+ }
+
m_max_memory_size = stub_max_size;
} else {
m_max_memory_size = conservative_default;
@@ -4134,8 +4215,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type,
&reg_name, &alt_name, &set_name, &value_regs,
&invalidate_regs, &encoding_set, &format_set,
- &reg_info, &cur_reg_num, &reg_offset,
- &dwarf_opcode_bytes](
+ &reg_info, &reg_offset, &dwarf_opcode_bytes](
const llvm::StringRef &name,
const llvm::StringRef &value) -> bool {
if (name == "name") {
@@ -4215,7 +4295,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
uint32_t ret_val =
opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes);
assert(dwarf_opcode_len == ret_val);
-
+ UNUSED_IF_ASSERT_DISABLED(ret_val);
reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data();
} else {
printf("unhandled attribute %s = %s\n", name.data(), value.data());
@@ -4283,7 +4363,7 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
// request the target xml file
std::string raw;
- lldb_private::Error lldberr;
+ lldb_private::Status lldberr;
if (!comm.ReadExtFeature(ConstString("features"), ConstString("target.xml"),
raw, lldberr)) {
return false;
@@ -4297,7 +4377,7 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
XMLNode target_node = xml_document.GetRootElement("target");
if (target_node) {
XMLNode feature_node;
- target_node.ForEachChildElement([&target_info, this, &feature_node](
+ target_node.ForEachChildElement([&target_info, &feature_node](
const XMLNode &node) -> bool {
llvm::StringRef name = node.GetName();
if (name == "architecture") {
@@ -4344,7 +4424,7 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
// that context we haven't
// set the Target's architecture yet, so the ABI is also potentially
// incorrect.
- ABISP abi_to_use_sp = ABI::FindPlugin(arch_to_use);
+ ABISP abi_to_use_sp = ABI::FindPlugin(shared_from_this(), arch_to_use);
if (feature_node) {
ParseRegisters(feature_node, target_info, this->m_register_info,
abi_to_use_sp, cur_reg_num, reg_offset);
@@ -4375,10 +4455,10 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
return m_register_info.GetNumRegisters() > 0;
}
-Error ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) {
+Status ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) {
// Make sure LLDB has an XML parser it can use first
if (!XMLDocument::XMLEnabled())
- return Error(0, ErrorType::eErrorTypeGeneric);
+ return Status(0, ErrorType::eErrorTypeGeneric);
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS);
if (log)
@@ -4392,11 +4472,11 @@ Error ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) {
// request the loaded library list
std::string raw;
- lldb_private::Error lldberr;
+ lldb_private::Status lldberr;
if (!comm.ReadExtFeature(ConstString("libraries-svr4"), ConstString(""),
raw, lldberr))
- return Error(0, ErrorType::eErrorTypeGeneric);
+ return Status(0, ErrorType::eErrorTypeGeneric);
// parse the xml file in memory
if (log)
@@ -4404,11 +4484,11 @@ Error ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) {
XMLDocument doc;
if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml"))
- return Error(0, ErrorType::eErrorTypeGeneric);
+ return Status(0, ErrorType::eErrorTypeGeneric);
XMLNode root_element = doc.GetRootElement("library-list-svr4");
if (!root_element)
- return Error();
+ return Status();
// main link map structure
llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm");
@@ -4423,8 +4503,8 @@ Error ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) {
LoadedModuleInfoList::LoadedModuleInfo module;
library.ForEachAttribute(
- [log, &module](const llvm::StringRef &name,
- const llvm::StringRef &value) -> bool {
+ [&module](const llvm::StringRef &name,
+ const llvm::StringRef &value) -> bool {
if (name == "name")
module.set_name(value.str());
@@ -4479,22 +4559,22 @@ Error ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) {
// request the loaded library list
std::string raw;
- lldb_private::Error lldberr;
+ lldb_private::Status lldberr;
if (!comm.ReadExtFeature(ConstString("libraries"), ConstString(""), raw,
lldberr))
- return Error(0, ErrorType::eErrorTypeGeneric);
+ return Status(0, ErrorType::eErrorTypeGeneric);
if (log)
log->Printf("parsing: %s", raw.c_str());
XMLDocument doc;
if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml"))
- return Error(0, ErrorType::eErrorTypeGeneric);
+ return Status(0, ErrorType::eErrorTypeGeneric);
XMLNode root_element = doc.GetRootElement("library-list");
if (!root_element)
- return Error();
+ return Status();
root_element.ForEachChildElementWithName(
"library", [log, &list](const XMLNode &library) -> bool {
@@ -4535,10 +4615,10 @@ Error ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) {
log->Printf("found %" PRId32 " modules in total",
(int)list.m_list.size());
} else {
- return Error(0, ErrorType::eErrorTypeGeneric);
+ return Status(0, ErrorType::eErrorTypeGeneric);
}
- return Error();
+ return Status();
}
lldb::ModuleSP ProcessGDBRemote::LoadModuleAtAddress(const FileSpec &file,
@@ -4637,15 +4717,15 @@ size_t ProcessGDBRemote::LoadModules() {
return LoadModules(module_list);
}
-Error ProcessGDBRemote::GetFileLoadAddress(const FileSpec &file,
- bool &is_loaded,
- lldb::addr_t &load_addr) {
+Status ProcessGDBRemote::GetFileLoadAddress(const FileSpec &file,
+ bool &is_loaded,
+ lldb::addr_t &load_addr) {
is_loaded = false;
load_addr = LLDB_INVALID_ADDRESS;
std::string file_path = file.GetPath(false);
if (file_path.empty())
- return Error("Empty file name specified");
+ return Status("Empty file name specified");
StreamString packet;
packet.PutCString("qFileLoadAddress:");
@@ -4655,27 +4735,28 @@ Error ProcessGDBRemote::GetFileLoadAddress(const FileSpec &file,
if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response,
false) !=
GDBRemoteCommunication::PacketResult::Success)
- return Error("Sending qFileLoadAddress packet failed");
+ return Status("Sending qFileLoadAddress packet failed");
if (response.IsErrorResponse()) {
if (response.GetError() == 1) {
// The file is not loaded into the inferior
is_loaded = false;
load_addr = LLDB_INVALID_ADDRESS;
- return Error();
+ return Status();
}
- return Error(
+ return Status(
"Fetching file load address from remote server returned an error");
}
if (response.IsNormalResponse()) {
is_loaded = true;
load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
- return Error();
+ return Status();
}
- return Error("Unknown error happened during sending the load address packet");
+ return Status(
+ "Unknown error happened during sending the load address packet");
}
void ProcessGDBRemote::ModulesDidLoad(ModuleList &module_list) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 6423abc..54a472d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -22,18 +22,19 @@
// Project includes
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Broadcaster.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/LoadedModuleInfoList.h"
#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/StringList.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ThreadSafeValue.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamGDBRemote.h"
+#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringExtractor.h"
+#include "lldb/Utility/StringList.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private-forward.h"
#include "GDBRemoteCommunicationClient.h"
@@ -78,25 +79,25 @@ public:
//------------------------------------------------------------------
// Creating a new process, or attaching to an existing one
//------------------------------------------------------------------
- Error WillLaunch(Module *module) override;
+ Status WillLaunch(Module *module) override;
- Error DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override;
+ Status DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override;
void DidLaunch() override;
- Error WillAttachToProcessWithID(lldb::pid_t pid) override;
+ Status WillAttachToProcessWithID(lldb::pid_t pid) override;
- Error WillAttachToProcessWithName(const char *process_name,
- bool wait_for_launch) override;
+ Status WillAttachToProcessWithName(const char *process_name,
+ bool wait_for_launch) override;
- Error DoConnectRemote(Stream *strm, llvm::StringRef remote_url) override;
+ Status DoConnectRemote(Stream *strm, llvm::StringRef remote_url) override;
- Error WillLaunchOrAttach();
+ Status WillLaunchOrAttach();
- Error DoAttachToProcessWithID(lldb::pid_t pid,
- const ProcessAttachInfo &attach_info) override;
+ Status DoAttachToProcessWithID(lldb::pid_t pid,
+ const ProcessAttachInfo &attach_info) override;
- Error
+ Status
DoAttachToProcessWithName(const char *process_name,
const ProcessAttachInfo &attach_info) override;
@@ -112,19 +113,19 @@ public:
//------------------------------------------------------------------
// Process Control
//------------------------------------------------------------------
- Error WillResume() override;
+ Status WillResume() override;
- Error DoResume() override;
+ Status DoResume() override;
- Error DoHalt(bool &caused_stop) override;
+ Status DoHalt(bool &caused_stop) override;
- Error DoDetach(bool keep_stopped) override;
+ Status DoDetach(bool keep_stopped) override;
bool DetachRequiresHalt() override { return true; }
- Error DoSignal(int signal) override;
+ Status DoSignal(int signal) override;
- Error DoDestroy() override;
+ Status DoDestroy() override;
void RefreshStateAfterStop() override;
@@ -143,41 +144,56 @@ public:
// Process Memory
//------------------------------------------------------------------
size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
- Error &error) override;
+ Status &error) override;
size_t DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size,
- Error &error) override;
+ Status &error) override;
lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions,
- Error &error) override;
+ Status &error) override;
- Error GetMemoryRegionInfo(lldb::addr_t load_addr,
- MemoryRegionInfo &region_info) override;
+ Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &region_info) override;
- Error DoDeallocateMemory(lldb::addr_t ptr) override;
+ Status DoDeallocateMemory(lldb::addr_t ptr) override;
//------------------------------------------------------------------
// Process STDIO
//------------------------------------------------------------------
- size_t PutSTDIN(const char *buf, size_t buf_size, Error &error) override;
+ size_t PutSTDIN(const char *buf, size_t buf_size, Status &error) override;
//----------------------------------------------------------------------
// Process Breakpoints
//----------------------------------------------------------------------
- Error EnableBreakpointSite(BreakpointSite *bp_site) override;
+ Status EnableBreakpointSite(BreakpointSite *bp_site) override;
- Error DisableBreakpointSite(BreakpointSite *bp_site) override;
+ Status DisableBreakpointSite(BreakpointSite *bp_site) override;
//----------------------------------------------------------------------
// Process Watchpoints
//----------------------------------------------------------------------
- Error EnableWatchpoint(Watchpoint *wp, bool notify = true) override;
+ Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override;
- Error DisableWatchpoint(Watchpoint *wp, bool notify = true) override;
+ Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override;
- Error GetWatchpointSupportInfo(uint32_t &num) override;
+ Status GetWatchpointSupportInfo(uint32_t &num) override;
- Error GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
+ lldb::user_id_t StartTrace(const TraceOptions &options,
+ Status &error) override;
+
+ Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) override;
+
+ Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) override;
+
+ Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) override;
+
+ Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
+
+ Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
bool StartNoticingNewThreads() override;
@@ -185,7 +201,7 @@ public:
GDBRemoteCommunicationClient &GetGDBRemote() { return m_gdb_comm; }
- Error SendEventData(const char *data) override;
+ Status SendEventData(const char *data) override;
//----------------------------------------------------------------------
// Override DidExit so we can disconnect from the remote GDB server
@@ -207,8 +223,8 @@ public:
size_t LoadModules() override;
- Error GetFileLoadAddress(const FileSpec &file, bool &is_loaded,
- lldb::addr_t &load_addr) override;
+ Status GetFileLoadAddress(const FileSpec &file, bool &is_loaded,
+ lldb::addr_t &load_addr) override;
void ModulesDidLoad(ModuleList &module_list) override;
@@ -216,7 +232,7 @@ public:
GetLoadedDynamicLibrariesInfos(lldb::addr_t image_list_address,
lldb::addr_t image_count) override;
- Error
+ Status
ConfigureStructuredData(const ConstString &type_name,
const StructuredData::ObjectSP &config_sp) override;
@@ -315,9 +331,9 @@ protected:
bool UpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) override;
- Error EstablishConnectionIfNeeded(const ProcessInfo &process_info);
+ Status EstablishConnectionIfNeeded(const ProcessInfo &process_info);
- Error LaunchAndConnectToDebugserver(const ProcessInfo &process_info);
+ Status LaunchAndConnectToDebugserver(const ProcessInfo &process_info);
void KillDebugserverProcess();
@@ -379,7 +395,7 @@ protected:
void DidLaunchOrAttach(ArchSpec &process_arch);
- Error ConnectToDebugserver(llvm::StringRef host_port);
+ Status ConnectToDebugserver(llvm::StringRef host_port);
const char *GetDispatchQueueNameForThread(lldb::addr_t thread_dispatch_qaddr,
std::string &dispatch_queue_name);
@@ -390,19 +406,22 @@ protected:
bool GetGDBServerRegisterInfo(ArchSpec &arch);
// Query remote GDBServer for a detailed loaded library list
- Error GetLoadedModuleList(LoadedModuleInfoList &);
+ Status GetLoadedModuleList(LoadedModuleInfoList &);
lldb::ModuleSP LoadModuleAtAddress(const FileSpec &file,
lldb::addr_t link_map,
lldb::addr_t base_addr,
bool value_is_offset);
+ Status UpdateAutomaticSignalFiltering() override;
+
private:
//------------------------------------------------------------------
// For ProcessGDBRemote only
//------------------------------------------------------------------
std::string m_partial_profile_data;
std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
+ uint64_t m_last_signals_version = 0;
static bool NewThreadNotifyBreakpointHit(void *baton,
StoppointCallbackContext *context,
@@ -417,6 +436,7 @@ private:
void HandleStopReply() override;
void HandleAsyncStructuredDataPacket(llvm::StringRef data) override;
+ void SetThreadPc(const lldb::ThreadSP &thread_sp, uint64_t index);
using ModuleCacheKey = std::pair<std::string, std::string>;
// KeyInfo for the cached module spec DenseMap.
// The invariant is that all real keys will have the file and architecture
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
index 899037a..8f16b83 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
@@ -8,210 +8,37 @@
//===----------------------------------------------------------------------===//
#include "ProcessGDBRemoteLog.h"
-
-#include <mutex>
-
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Interpreter/Args.h"
-
#include "ProcessGDBRemote.h"
+#include "llvm/Support/Threading.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_gdb_remote;
-// We want to avoid global constructors where code needs to be run so here we
-// control access to our static g_log_sp by hiding it in a singleton function
-// that will construct the static g_lob_sp the first time this function is
-// called.
-static bool g_log_enabled = false;
-static Log *g_log = NULL;
-static Log *GetLog() {
- if (!g_log_enabled)
- return NULL;
- return g_log;
-}
+static constexpr Log::Category g_categories[] = {
+ {{"async"}, {"log asynchronous activity"}, GDBR_LOG_ASYNC},
+ {{"break"}, {"log breakpoints"}, GDBR_LOG_BREAKPOINTS},
+ {{"comm"}, {"log communication activity"}, GDBR_LOG_COMM},
+ {{"packets"}, {"log gdb remote packets"}, GDBR_LOG_PACKETS},
+ {{"memory"}, {"log memory reads and writes"}, GDBR_LOG_MEMORY},
+ {{"data-short"},
+ {"log memory bytes for memory reads and writes for short transactions "
+ "only"},
+ GDBR_LOG_MEMORY_DATA_SHORT},
+ {{"data-long"},
+ {"log memory bytes for memory reads and writes for all transactions"},
+ GDBR_LOG_MEMORY_DATA_LONG},
+ {{"process"}, {"log process events and activities"}, GDBR_LOG_PROCESS},
+ {{"step"}, {"log step related activities"}, GDBR_LOG_STEP},
+ {{"thread"}, {"log thread events and activities"}, GDBR_LOG_THREAD},
+ {{"watch"}, {"log watchpoint related activities"}, GDBR_LOG_WATCHPOINTS},
+};
+
+Log::Channel ProcessGDBRemoteLog::g_channel(g_categories, GDBR_LOG_DEFAULT);
void ProcessGDBRemoteLog::Initialize() {
- static ConstString g_name("gdb-remote");
- static std::once_flag g_once_flag;
-
- std::call_once(g_once_flag, []() {
- Log::Callbacks log_callbacks = {DisableLog, EnableLog, ListLogCategories};
-
- Log::RegisterLogChannel(g_name, log_callbacks);
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
+ Log::Register("gdb-remote", g_channel);
});
}
-
-Log *ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(uint32_t mask) {
- Log *log(GetLog());
- if (log && mask) {
- uint32_t log_mask = log->GetMask().Get();
- if ((log_mask & mask) != mask)
- return NULL;
- }
- return log;
-}
-
-Log *ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(uint32_t mask) {
- Log *log(GetLog());
- if (log && log->GetMask().Get() & mask)
- return log;
- return NULL;
-}
-
-void ProcessGDBRemoteLog::DisableLog(const char **categories,
- Stream *feedback_strm) {
- Log *log(GetLog());
- if (log) {
- uint32_t flag_bits = 0;
-
- if (categories && categories[0]) {
- flag_bits = log->GetMask().Get();
- for (size_t i = 0; categories[i] != NULL; ++i) {
- const char *arg = categories[i];
-
- if (::strcasecmp(arg, "all") == 0)
- flag_bits &= ~GDBR_LOG_ALL;
- else if (::strcasecmp(arg, "async") == 0)
- flag_bits &= ~GDBR_LOG_ASYNC;
- else if (::strncasecmp(arg, "break", 5) == 0)
- flag_bits &= ~GDBR_LOG_BREAKPOINTS;
- else if (::strncasecmp(arg, "comm", 4) == 0)
- flag_bits &= ~GDBR_LOG_COMM;
- else if (::strcasecmp(arg, "default") == 0)
- flag_bits &= ~GDBR_LOG_DEFAULT;
- else if (::strcasecmp(arg, "packets") == 0)
- flag_bits &= ~GDBR_LOG_PACKETS;
- else if (::strcasecmp(arg, "memory") == 0)
- flag_bits &= ~GDBR_LOG_MEMORY;
- else if (::strcasecmp(arg, "data-short") == 0)
- flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT;
- else if (::strcasecmp(arg, "data-long") == 0)
- flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG;
- else if (::strcasecmp(arg, "process") == 0)
- flag_bits &= ~GDBR_LOG_PROCESS;
- else if (::strcasecmp(arg, "step") == 0)
- flag_bits &= ~GDBR_LOG_STEP;
- else if (::strcasecmp(arg, "thread") == 0)
- flag_bits &= ~GDBR_LOG_THREAD;
- else if (::strcasecmp(arg, "verbose") == 0)
- flag_bits &= ~GDBR_LOG_VERBOSE;
- else if (::strncasecmp(arg, "watch", 5) == 0)
- flag_bits &= ~GDBR_LOG_WATCHPOINTS;
- else {
- feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
- ListLogCategories(feedback_strm);
- }
- }
- }
-
- if (flag_bits == 0)
- g_log_enabled = false;
- else
- log->GetMask().Reset(flag_bits);
- }
-
- return;
-}
-
-Log *ProcessGDBRemoteLog::EnableLog(StreamSP &log_stream_sp,
- uint32_t log_options,
- const char **categories,
- Stream *feedback_strm) {
- // Try see if there already is a log - that way we can reuse its settings.
- // We could reuse the log in toto, but we don't know that the stream is the
- // same.
- uint32_t flag_bits = 0;
- if (g_log)
- flag_bits = g_log->GetMask().Get();
-
- // Now make a new log with this stream if one was provided
- if (log_stream_sp) {
- if (g_log)
- g_log->SetStream(log_stream_sp);
- else
- g_log = new Log(log_stream_sp);
- }
-
- if (g_log) {
- bool got_unknown_category = false;
- for (size_t i = 0; categories[i] != NULL; ++i) {
- const char *arg = categories[i];
-
- if (::strcasecmp(arg, "all") == 0)
- flag_bits |= GDBR_LOG_ALL;
- else if (::strcasecmp(arg, "async") == 0)
- flag_bits |= GDBR_LOG_ASYNC;
- else if (::strncasecmp(arg, "break", 5) == 0)
- flag_bits |= GDBR_LOG_BREAKPOINTS;
- else if (::strncasecmp(arg, "comm", 4) == 0)
- flag_bits |= GDBR_LOG_COMM;
- else if (::strcasecmp(arg, "default") == 0)
- flag_bits |= GDBR_LOG_DEFAULT;
- else if (::strcasecmp(arg, "packets") == 0)
- flag_bits |= GDBR_LOG_PACKETS;
- else if (::strcasecmp(arg, "memory") == 0)
- flag_bits |= GDBR_LOG_MEMORY;
- else if (::strcasecmp(arg, "data-short") == 0)
- flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT;
- else if (::strcasecmp(arg, "data-long") == 0)
- flag_bits |= GDBR_LOG_MEMORY_DATA_LONG;
- else if (::strcasecmp(arg, "process") == 0)
- flag_bits |= GDBR_LOG_PROCESS;
- else if (::strcasecmp(arg, "step") == 0)
- flag_bits |= GDBR_LOG_STEP;
- else if (::strcasecmp(arg, "thread") == 0)
- flag_bits |= GDBR_LOG_THREAD;
- else if (::strcasecmp(arg, "verbose") == 0)
- flag_bits |= GDBR_LOG_VERBOSE;
- else if (::strncasecmp(arg, "watch", 5) == 0)
- flag_bits |= GDBR_LOG_WATCHPOINTS;
- else {
- feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
- if (got_unknown_category == false) {
- got_unknown_category = true;
- ListLogCategories(feedback_strm);
- }
- }
- }
- if (flag_bits == 0)
- flag_bits = GDBR_LOG_DEFAULT;
- g_log->GetMask().Reset(flag_bits);
- g_log->GetOptions().Reset(log_options);
- }
- g_log_enabled = true;
- return g_log;
-}
-
-void ProcessGDBRemoteLog::ListLogCategories(Stream *strm) {
- strm->Printf(
- "Logging categories for '%s':\n"
- " all - turn on all available logging categories\n"
- " async - log asynchronous activity\n"
- " break - log breakpoints\n"
- " communication - log communication activity\n"
- " default - enable the default set of logging categories for liblldb\n"
- " packets - log gdb remote packets\n"
- " memory - log memory reads and writes\n"
- " data-short - log memory bytes for memory reads and writes for short "
- "transactions only\n"
- " data-long - log memory bytes for memory reads and writes for all "
- "transactions\n"
- " process - log process events and activities\n"
- " thread - log thread events and activities\n"
- " step - log step related activities\n"
- " verbose - enable verbose logging\n"
- " watch - log watchpoint related activities\n",
- ProcessGDBRemote::GetPluginNameStatic().GetCString());
-}
-
-void ProcessGDBRemoteLog::LogIf(uint32_t mask, const char *format, ...) {
- Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(mask));
- if (log) {
- va_list args;
- va_start(args, format);
- log->VAPrintf(format, args);
- va_end(args);
- }
-}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
index f5e92b4..3c58011 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
@@ -15,9 +15,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
-#define GDBR_LOG_VERBOSE (1u << 0)
#define GDBR_LOG_PROCESS (1u << 1)
#define GDBR_LOG_THREAD (1u << 2)
#define GDBR_LOG_PACKETS (1u << 3)
@@ -37,21 +36,13 @@ namespace lldb_private {
namespace process_gdb_remote {
class ProcessGDBRemoteLog {
+ static Log::Channel g_channel;
+
public:
static void Initialize();
- static Log *GetLogIfAllCategoriesSet(uint32_t mask = 0);
-
- static Log *GetLogIfAnyCategoryIsSet(uint32_t mask);
-
- static void DisableLog(const char **categories, Stream *feedback_strm);
-
- static Log *EnableLog(lldb::StreamSP &log_stream_sp, uint32_t log_options,
- const char **categories, Stream *feedback_strm);
-
- static void ListLogCategories(Stream *strm);
-
- static void LogIf(uint32_t mask, const char *format, ...);
+ static Log *GetLogIfAllCategoriesSet(uint32_t mask) { return g_channel.GetLogIfAll(mask); }
+ static Log *GetLogIfAnyCategoryIsSet(uint32_t mask) { return g_channel.GetLogIfAny(mask); }
};
} // namespace process_gdb_remote
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
index ab55214..5197e8f 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -11,9 +11,7 @@
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -22,6 +20,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/StreamString.h"
#include "ProcessGDBRemote.h"
#include "ProcessGDBRemoteLog.h"
@@ -41,18 +41,16 @@ ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid)
m_dispatch_queue_t(LLDB_INVALID_ADDRESS), m_queue_kind(eQueueKindUnknown),
m_queue_serial_number(LLDB_INVALID_QUEUE_ID),
m_associated_with_libdispatch_queue(eLazyBoolCalculate) {
- ProcessGDBRemoteLog::LogIf(
- GDBR_LOG_THREAD,
- "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this,
- process.GetID(), GetID());
+ Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD));
+ LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this, process.GetID(),
+ GetID());
}
ThreadGDBRemote::~ThreadGDBRemote() {
ProcessSP process_sp(GetProcess());
- ProcessGDBRemoteLog::LogIf(
- GDBR_LOG_THREAD,
- "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)", this,
- process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID, GetID());
+ Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD));
+ LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this,
+ process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID, GetID());
DestroyThread();
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
index 27caf42..1a5b60a 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -16,9 +16,9 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/StructuredData.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/StructuredData.h"
class StringExtractor;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/CMakeLists.txt
index ddc89cb..61ce168 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/CMakeLists.txt
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/CMakeLists.txt
@@ -1,10 +1,19 @@
include_directories(../Utility)
-add_lldb_library(lldbPluginProcessMinidump
+add_lldb_library(lldbPluginProcessMinidump PLUGIN
MinidumpTypes.cpp
MinidumpParser.cpp
RegisterContextMinidump_x86_32.cpp
RegisterContextMinidump_x86_64.cpp
ProcessMinidump.cpp
ThreadMinidump.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbTarget
+ lldbUtility
+ lldbPluginProcessUtility
+ lldbPluginProcessElfCore
+ LINK_COMPONENTS
+ Support
)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
index 37b3709..36350fd 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -45,7 +45,7 @@ MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) {
}
const MinidumpDirectory *directory = nullptr;
- Error error;
+ Status error;
llvm::ArrayRef<uint8_t> directory_data(
data_buf_sp->GetBytes() + directory_list_offset,
sizeof(MinidumpDirectory) * header->streams_count);
@@ -126,7 +126,7 @@ MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) {
return {};
const TEB64 *wow64teb;
- Error error = consumeObject(teb_mem, wow64teb);
+ Status error = consumeObject(teb_mem, wow64teb);
if (error.Fail())
return {};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.h
index 67523a7..df6deb4 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpParser.h
@@ -16,8 +16,8 @@
// Other libraries and framework includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/Status.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
index 863d124..24ce3f9 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
@@ -19,7 +19,7 @@ using namespace minidump;
const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef<uint8_t> &data) {
const MinidumpHeader *header = nullptr;
- Error error = consumeObject(data, header);
+ Status error = consumeObject(data, header);
const MinidumpHeaderConstants signature =
static_cast<const MinidumpHeaderConstants>(
@@ -45,7 +45,7 @@ lldb_private::minidump::parseMinidumpString(llvm::ArrayRef<uint8_t> &data) {
std::string result;
const uint32_t *source_length;
- Error error = consumeObject(data, source_length);
+ Status error = consumeObject(data, source_length);
if (error.Fail() || *source_length > data.size() || *source_length % 2 != 0)
return llvm::None;
@@ -71,7 +71,7 @@ lldb_private::minidump::parseMinidumpString(llvm::ArrayRef<uint8_t> &data) {
// MinidumpThread
const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) {
const MinidumpThread *thread = nullptr;
- Error error = consumeObject(data, thread);
+ Status error = consumeObject(data, thread);
if (error.Fail())
return nullptr;
@@ -81,7 +81,7 @@ const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) {
llvm::ArrayRef<MinidumpThread>
MinidumpThread::ParseThreadList(llvm::ArrayRef<uint8_t> &data) {
const llvm::support::ulittle32_t *thread_count;
- Error error = consumeObject(data, thread_count);
+ Status error = consumeObject(data, thread_count);
if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size())
return {};
@@ -93,7 +93,7 @@ MinidumpThread::ParseThreadList(llvm::ArrayRef<uint8_t> &data) {
const MinidumpSystemInfo *
MinidumpSystemInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
const MinidumpSystemInfo *system_info;
- Error error = consumeObject(data, system_info);
+ Status error = consumeObject(data, system_info);
if (error.Fail())
return nullptr;
@@ -103,7 +103,7 @@ MinidumpSystemInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
// MinidumpMiscInfo
const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
const MinidumpMiscInfo *misc_info;
- Error error = consumeObject(data, misc_info);
+ Status error = consumeObject(data, misc_info);
if (error.Fail())
return nullptr;
@@ -147,7 +147,7 @@ lldb::pid_t LinuxProcStatus::GetPid() const { return pid; }
// Module stuff
const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef<uint8_t> &data) {
const MinidumpModule *module = nullptr;
- Error error = consumeObject(data, module);
+ Status error = consumeObject(data, module);
if (error.Fail())
return nullptr;
@@ -158,7 +158,7 @@ llvm::ArrayRef<MinidumpModule>
MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) {
const llvm::support::ulittle32_t *modules_count;
- Error error = consumeObject(data, modules_count);
+ Status error = consumeObject(data, modules_count);
if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size())
return {};
@@ -170,7 +170,7 @@ MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) {
const MinidumpExceptionStream *
MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) {
const MinidumpExceptionStream *exception_stream = nullptr;
- Error error = consumeObject(data, exception_stream);
+ Status error = consumeObject(data, exception_stream);
if (error.Fail())
return nullptr;
@@ -180,7 +180,7 @@ MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) {
llvm::ArrayRef<MinidumpMemoryDescriptor>
MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) {
const llvm::support::ulittle32_t *mem_ranges_count;
- Error error = consumeObject(data, mem_ranges_count);
+ Status error = consumeObject(data, mem_ranges_count);
if (error.Fail() ||
*mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size())
return {};
@@ -193,7 +193,7 @@ MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) {
std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
const llvm::support::ulittle64_t *mem_ranges_count;
- Error error = consumeObject(data, mem_ranges_count);
+ Status error = consumeObject(data, mem_ranges_count);
if (error.Fail() ||
*mem_ranges_count * sizeof(MinidumpMemoryDescriptor64) > data.size())
return {};
@@ -213,7 +213,7 @@ MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
std::vector<const MinidumpMemoryInfo *>
MinidumpMemoryInfo::ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data) {
const MinidumpMemoryInfoListHeader *header;
- Error error = consumeObject(data, header);
+ Status error = consumeObject(data, header);
if (error.Fail() ||
header->size_of_header < sizeof(MinidumpMemoryInfoListHeader) ||
header->size_of_entry < sizeof(MinidumpMemoryInfo))
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
index 46871a1..6de4f55 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
@@ -13,7 +13,7 @@
// Project includes
// Other libraries and framework includes
-#include "lldb/Core/Error.h"
+#include "lldb/Utility/Status.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitmaskEnum.h"
@@ -158,8 +158,8 @@ enum class MinidumpMiscInfoFlags : uint32_t {
};
template <typename T>
-Error consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) {
- Error error;
+Status consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) {
+ Status error;
if (Buffer.size() < sizeof(T)) {
error.SetErrorString("Insufficient buffer!");
return error;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
index 46d8df8..d4d65c0 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -12,8 +12,6 @@
#include "ThreadMinidump.h"
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
@@ -23,7 +21,12 @@
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/DataBufferLLVM.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Threading.h"
// C includes
// C++ includes
@@ -48,20 +51,25 @@ lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
lldb::ProcessSP process_sp;
// Read enough data for the Minidump header
- const size_t header_size = sizeof(MinidumpHeader);
- lldb::DataBufferSP data_sp(crash_file->MemoryMapFileContents(0, header_size));
- if (!data_sp)
+ constexpr size_t header_size = sizeof(MinidumpHeader);
+ auto DataPtr =
+ DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), header_size, 0);
+ if (!DataPtr)
return nullptr;
+ assert(DataPtr->GetByteSize() == header_size);
+
// first, only try to parse the header, beacuse we need to be fast
- llvm::ArrayRef<uint8_t> header_data(data_sp->GetBytes(), header_size);
- const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
+ llvm::ArrayRef<uint8_t> HeaderBytes = DataPtr->GetData();
+ const MinidumpHeader *header = MinidumpHeader::Parse(HeaderBytes);
+ if (header == nullptr)
+ return nullptr;
- if (data_sp->GetByteSize() != header_size || header == nullptr)
+ auto AllData = DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), -1, 0);
+ if (!AllData)
return nullptr;
- lldb::DataBufferSP all_data_sp(crash_file->MemoryMapFileContents());
- auto minidump_parser = MinidumpParser::Create(all_data_sp);
+ auto minidump_parser = MinidumpParser::Create(AllData);
// check if the parser object is valid
if (!minidump_parser)
return nullptr;
@@ -92,9 +100,9 @@ ProcessMinidump::~ProcessMinidump() {
}
void ProcessMinidump::Initialize() {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(),
ProcessMinidump::CreateInstance);
@@ -105,8 +113,8 @@ void ProcessMinidump::Terminate() {
PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
}
-Error ProcessMinidump::DoLoadCore() {
- Error error;
+Status ProcessMinidump::DoLoadCore() {
+ Status error;
m_thread_list = m_minidump_parser.GetThreads();
m_active_exception = m_minidump_parser.GetExceptionStream();
@@ -133,7 +141,7 @@ ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); }
uint32_t ProcessMinidump::GetPluginVersion() { return 1; }
-Error ProcessMinidump::DoDestroy() { return Error(); }
+Status ProcessMinidump::DoDestroy() { return Status(); }
void ProcessMinidump::RefreshStateAfterStop() {
if (!m_active_exception)
@@ -176,14 +184,14 @@ bool ProcessMinidump::IsAlive() { return true; }
bool ProcessMinidump::WarnBeforeDetach() const { return false; }
size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
- Error &error) {
+ Status &error) {
// Don't allow the caching that lldb_private::Process::ReadMemory does
// since we have it all cached in our dump file anyway.
return DoReadMemory(addr, buf, size, error);
}
size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
- Error &error) {
+ Status &error) {
llvm::ArrayRef<uint8_t> mem = m_minidump_parser.GetMemory(addr, size);
if (mem.empty()) {
@@ -207,9 +215,9 @@ ArchSpec ProcessMinidump::GetArchitecture() {
return ArchSpec(triple);
}
-Error ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
- MemoryRegionInfo &range_info) {
- Error error;
+Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+ Status error;
auto info = m_minidump_parser.GetMemoryRegionInfo(load_addr);
if (!info) {
error.SetErrorString("No valid MemoryRegionInfo found!");
@@ -270,7 +278,7 @@ void ProcessMinidump::ReadModuleList() {
const auto file_spec = FileSpec(name.getValue(), true);
ModuleSpec module_spec = file_spec;
- Error error;
+ Status error;
lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
if (!module_sp || error.Fail()) {
continue;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
index 78eadc8..d5c46be 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
@@ -15,11 +15,11 @@
#include "MinidumpTypes.h"
// Other libraries and framework includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
@@ -53,7 +53,7 @@ public:
bool CanDebug(lldb::TargetSP target_sp,
bool plugin_specified_by_name) override;
- Error DoLoadCore() override;
+ Status DoLoadCore() override;
DynamicLoader *GetDynamicLoader() override;
@@ -61,7 +61,7 @@ public:
uint32_t GetPluginVersion() override;
- Error DoDestroy() override;
+ Status DoDestroy() override;
void RefreshStateAfterStop() override;
@@ -70,15 +70,15 @@ public:
bool WarnBeforeDetach() const override;
size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
- Error &error) override;
+ Status &error) override;
size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
- Error &error) override;
+ Status &error) override;
ArchSpec GetArchitecture();
- Error GetMemoryRegionInfo(lldb::addr_t load_addr,
- MemoryRegionInfo &range_info) override;
+ Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
bool GetProcessInfo(ProcessInstanceInfo &info) override;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp
index 7f37682..7605f8b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp
@@ -11,7 +11,7 @@
#include "RegisterContextMinidump_x86_32.h"
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Utility/DataBufferHeap.h"
// C includes
// C++ includes
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
index 881c26a..ba1cb6d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
@@ -11,7 +11,7 @@
#include "RegisterContextMinidump_x86_64.h"
// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Utility/DataBufferHeap.h"
// C includes
// C++ includes
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp
index e42108b..9c21cc9 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp
@@ -20,12 +20,12 @@
#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
// C Includes
// C++ Includes
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp
index 2f04ec9..9ec9f43 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp
@@ -10,10 +10,12 @@
#include "ScriptInterpreterNone.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StringList.h"
+
+#include "llvm/Support/Threading.h"
#include <mutex>
@@ -39,9 +41,9 @@ void ScriptInterpreterNone::ExecuteInterpreterLoop() {
}
void ScriptInterpreterNone::Initialize() {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(),
lldb::eScriptLanguageNone, CreateInstance);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index f3453f2..966bdff 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -17,10 +17,10 @@
#include "PythonDataObjects.h"
#include "ScriptInterpreterPython.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Utility/Stream.h"
#include "llvm/Support/ConvertUTF.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
index b84996c..beeb647 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
@@ -19,11 +19,12 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Flags.h"
-#include "lldb/Core/StructuredData.h"
+#include "lldb/Utility/Flags.h"
+
#include "lldb/Host/File.h"
#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-defines.h"
#include "llvm/ADT/ArrayRef.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 357b48e..6c39690 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -33,7 +33,6 @@
#include "lldb/Core/Communication.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
@@ -44,6 +43,7 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Utility/Timer.h"
#if defined(_WIN32)
#include "lldb/Host/windows/ConnectionGenericFileWindows.h"
@@ -51,6 +51,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
using namespace lldb;
using namespace lldb_private;
@@ -142,14 +143,9 @@ public:
~InitializePythonRAII() {
if (m_was_already_initialized) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT |
- LIBLLDB_LOG_VERBOSE));
-
- if (log) {
- log->Printf("Releasing PyGILState. Returning to state = %slocked\n",
- m_was_already_initialized == PyGILState_UNLOCKED ? "un"
- : "");
- }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT));
+ LLDB_LOGV(log, "Releasing PyGILState. Returning to state = {0}locked",
+ m_was_already_initialized == PyGILState_UNLOCKED ? "un" : "");
PyGILState_Release(m_gil_state);
} else {
// We initialized the threads in this function, just unlock the GIL.
@@ -174,15 +170,12 @@ private:
void InitializeThreadsPrivate() {
if (PyEval_ThreadsInitialized()) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT |
- LIBLLDB_LOG_VERBOSE));
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT));
m_was_already_initialized = true;
m_gil_state = PyGILState_Ensure();
- if (log) {
- log->Printf("Ensured PyGILState. Previous state = %slocked\n",
- m_gil_state == PyGILState_UNLOCKED ? "un" : "");
- }
+ LLDB_LOGV(log, "Ensured PyGILState. Previous state = {0}locked\n",
+ m_gil_state == PyGILState_UNLOCKED ? "un" : "");
return;
}
@@ -212,12 +205,10 @@ ScriptInterpreterPython::Locker::Locker(ScriptInterpreterPython *py_interpreter,
}
bool ScriptInterpreterPython::Locker::DoAcquireLock() {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT |
- LIBLLDB_LOG_VERBOSE));
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT));
m_GILState = PyGILState_Ensure();
- if (log)
- log->Printf("Ensured PyGILState. Previous state = %slocked\n",
- m_GILState == PyGILState_UNLOCKED ? "un" : "");
+ LLDB_LOGV(log, "Ensured PyGILState. Previous state = {0}locked",
+ m_GILState == PyGILState_UNLOCKED ? "un" : "");
// we need to save the thread state when we first start the command
// because we might decide to interrupt it while some action is taking
@@ -239,11 +230,9 @@ bool ScriptInterpreterPython::Locker::DoInitSession(uint16_t on_entry_flags,
}
bool ScriptInterpreterPython::Locker::DoFreeLock() {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT |
- LIBLLDB_LOG_VERBOSE));
- if (log)
- log->Printf("Releasing PyGILState. Returning to state = %slocked\n",
- m_GILState == PyGILState_UNLOCKED ? "un" : "");
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT));
+ LLDB_LOGV(log, "Releasing PyGILState. Returning to state = {0}locked",
+ m_GILState == PyGILState_UNLOCKED ? "un" : "");
PyGILState_Release(m_GILState);
m_python_interpreter->DecrementLockCount();
return true;
@@ -338,9 +327,9 @@ ScriptInterpreterPython::~ScriptInterpreterPython() {
}
void ScriptInterpreterPython::Initialize() {
- static std::once_flag g_once_flag;
+ static llvm::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ llvm::call_once(g_once_flag, []() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(),
lldb::eScriptLanguagePython, CreateInstance);
@@ -734,7 +723,7 @@ bool ScriptInterpreterPython::ExecuteOneLine(
// the result object
Pipe pipe;
- Error pipe_result = pipe.CreateNew(false);
+ Status pipe_result = pipe.CreateNew(false);
if (pipe_result.Success()) {
#if defined(_WIN32)
lldb::file_t read_file = pipe.GetReadNativeHandle();
@@ -939,7 +928,8 @@ protected:
};
void ScriptInterpreterPython::ExecuteInterpreterLoop() {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
Debugger &debugger = GetCommandInterpreter().GetDebugger();
@@ -1144,9 +1134,9 @@ bool ScriptInterpreterPython::ExecuteOneLineWithReturn(
return ret_success;
}
-Error ScriptInterpreterPython::ExecuteMultipleLines(
+Status ScriptInterpreterPython::ExecuteMultipleLines(
const char *in_string, const ExecuteScriptOptions &options) {
- Error error;
+ Status error;
Locker locker(this, ScriptInterpreterPython::Locker::AcquireLock |
ScriptInterpreterPython::Locker::InitSession |
@@ -1231,10 +1221,10 @@ void ScriptInterpreterPython::SetBreakpointCommandCallbackFunction(
bp_options, oneliner.c_str());
}
-Error ScriptInterpreterPython::SetBreakpointCommandCallback(
+Status ScriptInterpreterPython::SetBreakpointCommandCallback(
BreakpointOptions *bp_options,
std::unique_ptr<BreakpointOptions::CommandData> &cmd_data_up) {
- Error error;
+ Status error;
error = GenerateBreakpointCommandCallbackData(cmd_data_up->user_source,
cmd_data_up->script_source);
if (error.Fail()) {
@@ -1248,7 +1238,7 @@ Error ScriptInterpreterPython::SetBreakpointCommandCallback(
}
// Set a Python one-liner as the callback for the breakpoint.
-Error ScriptInterpreterPython::SetBreakpointCommandCallback(
+Status ScriptInterpreterPython::SetBreakpointCommandCallback(
BreakpointOptions *bp_options, const char *command_body_text) {
auto data_ap = llvm::make_unique<CommandDataPython>();
@@ -1259,8 +1249,8 @@ Error ScriptInterpreterPython::SetBreakpointCommandCallback(
// the callback will actually invoke.
data_ap->user_source.SplitIntoLines(command_body_text);
- Error error = GenerateBreakpointCommandCallbackData(data_ap->user_source,
- data_ap->script_source);
+ Status error = GenerateBreakpointCommandCallbackData(data_ap->user_source,
+ data_ap->script_source);
if (error.Success()) {
auto baton_sp =
std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_ap));
@@ -1296,20 +1286,20 @@ void ScriptInterpreterPython::SetWatchpointCommandCallback(
return;
}
-Error ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter(
+Status ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter(
StringList &function_def) {
// Convert StringList to one long, newline delimited, const char *.
std::string function_def_string(function_def.CopyList());
- Error error = ExecuteMultipleLines(
+ Status error = ExecuteMultipleLines(
function_def_string.c_str(),
ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false));
return error;
}
-Error ScriptInterpreterPython::GenerateFunction(const char *signature,
- const StringList &input) {
- Error error;
+Status ScriptInterpreterPython::GenerateFunction(const char *signature,
+ const StringList &input) {
+ Status error;
int num_lines = input.GetSize();
if (num_lines == 0) {
error.SetErrorString("No input data.");
@@ -1841,7 +1831,7 @@ lldb::StateType ScriptInterpreterPython::ScriptedThreadPlanGetRunState(
StructuredData::ObjectSP
ScriptInterpreterPython::LoadPluginModule(const FileSpec &file_spec,
- lldb_private::Error &error) {
+ lldb_private::Status &error) {
if (!file_spec.Exists()) {
error.SetErrorString("no such file");
return StructuredData::ObjectSP();
@@ -1858,7 +1848,7 @@ ScriptInterpreterPython::LoadPluginModule(const FileSpec &file_spec,
StructuredData::DictionarySP ScriptInterpreterPython::GetDynamicSettings(
StructuredData::ObjectSP plugin_module_sp, Target *target,
- const char *setting_name, lldb_private::Error &error) {
+ const char *setting_name, lldb_private::Status &error) {
if (!plugin_module_sp || !target || !setting_name || !setting_name[0] ||
!g_swig_plugin_get)
return StructuredData::DictionarySP();
@@ -1867,14 +1857,12 @@ StructuredData::DictionarySP ScriptInterpreterPython::GetDynamicSettings(
return StructuredData::DictionarySP();
PythonObject reply_pyobj;
- {
- Locker py_lock(this,
- Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
- TargetSP target_sp(target->shared_from_this());
- reply_pyobj.Reset(PyRefType::Owned,
- (PyObject *)g_swig_plugin_get(generic->GetValue(),
- setting_name, target_sp));
- }
+ Locker py_lock(this,
+ Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+ TargetSP target_sp(target->shared_from_this());
+ reply_pyobj.Reset(PyRefType::Owned,
+ (PyObject *)g_swig_plugin_get(generic->GetValue(),
+ setting_name, target_sp));
PythonDictionary py_dict(PyRefType::Borrowed, reply_pyobj.get());
return py_dict.CreateStructuredDictionary();
@@ -1954,12 +1942,12 @@ bool ScriptInterpreterPython::GenerateTypeSynthClass(const char *oneliner,
return GenerateTypeSynthClass(input, output, name_token);
}
-Error ScriptInterpreterPython::GenerateBreakpointCommandCallbackData(
+Status ScriptInterpreterPython::GenerateBreakpointCommandCallbackData(
StringList &user_input, std::string &output) {
static uint32_t num_created_functions = 0;
user_input.RemoveBlankLines();
StreamString sstr;
- Error error;
+ Status error;
if (user_input.GetSize() == 0) {
error.SetErrorString("No input data.");
return error;
@@ -2006,7 +1994,8 @@ bool ScriptInterpreterPython::GetScriptedSummary(
StructuredData::ObjectSP &callee_wrapper_sp,
const TypeSummaryOptions &options, std::string &retval) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
if (!valobj.get()) {
retval.assign("<no object>");
@@ -2030,8 +2019,8 @@ bool ScriptInterpreterPython::GetScriptedSummary(
{
TypeSummaryOptionsSP options_sp(new TypeSummaryOptions(options));
- Timer scoped_timer("g_swig_typescript_callback",
- "g_swig_typescript_callback");
+ static Timer::Category func_cat("g_swig_typescript_callback");
+ Timer scoped_timer(func_cat, "g_swig_typescript_callback");
ret_val = g_swig_typescript_callback(
python_function_name, GetSessionDictionary().get(), valobj,
&new_callee, options_sp, retval);
@@ -2406,7 +2395,7 @@ ConstString ScriptInterpreterPython::GetSyntheticTypeName(
bool ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function,
Process *process,
std::string &output,
- Error &error) {
+ Status &error) {
bool ret_val;
if (!process) {
error.SetErrorString("no process");
@@ -2435,7 +2424,7 @@ bool ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function,
bool ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function,
Thread *thread,
std::string &output,
- Error &error) {
+ Status &error) {
bool ret_val;
if (!thread) {
error.SetErrorString("no thread");
@@ -2464,7 +2453,7 @@ bool ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function,
bool ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function,
Target *target,
std::string &output,
- Error &error) {
+ Status &error) {
bool ret_val;
if (!target) {
error.SetErrorString("no thread");
@@ -2493,7 +2482,7 @@ bool ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function,
bool ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function,
StackFrame *frame,
std::string &output,
- Error &error) {
+ Status &error) {
bool ret_val;
if (!frame) {
error.SetErrorString("no frame");
@@ -2522,7 +2511,7 @@ bool ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function,
bool ScriptInterpreterPython::RunScriptFormatKeyword(const char *impl_function,
ValueObject *value,
std::string &output,
- Error &error) {
+ Status &error) {
bool ret_val;
if (!value) {
error.SetErrorString("no value");
@@ -2562,7 +2551,7 @@ uint64_t replace_all(std::string &str, const std::string &oldStr,
bool ScriptInterpreterPython::LoadScriptingModule(
const char *pathname, bool can_reload, bool init_session,
- lldb_private::Error &error, StructuredData::ObjectSP *module_sp) {
+ lldb_private::Status &error, StructuredData::ObjectSP *module_sp) {
if (!pathname || !pathname[0]) {
error.SetErrorString("invalid pathname");
return false;
@@ -2587,9 +2576,13 @@ bool ScriptInterpreterPython::LoadScriptingModule(
Locker::NoSTDIN,
Locker::FreeAcquiredLock |
(init_session ? Locker::TearDownSession : 0));
+ namespace fs = llvm::sys::fs;
+ fs::file_status st;
+ std::error_code ec = status(target_file.GetPath(), st);
- if (target_file.GetFileType() == FileSpec::eFileTypeInvalid ||
- target_file.GetFileType() == FileSpec::eFileTypeUnknown) {
+ if (ec || st.type() == fs::file_type::status_error ||
+ st.type() == fs::file_type::type_unknown ||
+ st.type() == fs::file_type::file_not_found) {
// if not a valid file of any sort, check if it might be a filename still
// dot can't be used but / and \ can, and if either is found, reject
if (strchr(pathname, '\\') || strchr(pathname, '/')) {
@@ -2598,9 +2591,7 @@ bool ScriptInterpreterPython::LoadScriptingModule(
}
basename = pathname; // not a filename, probably a package of some sort,
// let it go through
- } else if (target_file.GetFileType() == FileSpec::eFileTypeDirectory ||
- target_file.GetFileType() == FileSpec::eFileTypeRegular ||
- target_file.GetFileType() == FileSpec::eFileTypeSymbolicLink) {
+ } else if (is_directory(st) || is_regular_file(st)) {
std::string directory = target_file.GetDirectory().GetCString();
replace_all(directory, "\\", "\\\\");
replace_all(directory, "'", "\\'");
@@ -2751,7 +2742,7 @@ ScriptInterpreterPython::SynchronicityHandler::~SynchronicityHandler() {
bool ScriptInterpreterPython::RunScriptBasedCommand(
const char *impl_function, const char *args,
ScriptedCommandSynchronicity synchronicity,
- lldb_private::CommandReturnObject &cmd_retobj, Error &error,
+ lldb_private::CommandReturnObject &cmd_retobj, Status &error,
const lldb_private::ExecutionContext &exe_ctx) {
if (!impl_function) {
error.SetErrorString("no function to execute");
@@ -2799,7 +2790,7 @@ bool ScriptInterpreterPython::RunScriptBasedCommand(
bool ScriptInterpreterPython::RunScriptBasedCommand(
StructuredData::GenericSP impl_obj_sp, const char *args,
ScriptedCommandSynchronicity synchronicity,
- lldb_private::CommandReturnObject &cmd_retobj, Error &error,
+ lldb_private::CommandReturnObject &cmd_retobj, Status &error,
const lldb_private::ExecutionContext &exe_ctx) {
if (!impl_obj_sp || !impl_obj_sp->IsValid()) {
error.SetErrorString("no function to execute");
@@ -3111,7 +3102,8 @@ void ScriptInterpreterPython::InitializePrivate() {
g_initialized = true;
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
// RAII-based initialization which correctly handles multiple-initialization,
// version-
diff --git a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
index 7b0e1b0..a71fcea 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
@@ -161,11 +161,11 @@ public:
void *ret_value,
const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;
- lldb_private::Error ExecuteMultipleLines(
+ lldb_private::Status ExecuteMultipleLines(
const char *in_string,
const ExecuteScriptOptions &options = ExecuteScriptOptions()) override;
- Error
+ Status
ExportFunctionDefinitionToInterpreter(StringList &function_def) override;
bool GenerateTypeScriptFunction(StringList &input, std::string &output,
@@ -229,12 +229,12 @@ public:
StructuredData::ObjectSP
LoadPluginModule(const FileSpec &file_spec,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
StructuredData::DictionarySP
GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target,
const char *setting_name,
- lldb_private::Error &error) override;
+ lldb_private::Status &error) override;
size_t CalculateNumChildren(const StructuredData::ObjectSP &implementor,
uint32_t max) override;
@@ -262,21 +262,21 @@ public:
RunScriptBasedCommand(const char *impl_function, const char *args,
ScriptedCommandSynchronicity synchronicity,
lldb_private::CommandReturnObject &cmd_retobj,
- Error &error,
+ Status &error,
const lldb_private::ExecutionContext &exe_ctx) override;
bool
RunScriptBasedCommand(StructuredData::GenericSP impl_obj_sp, const char *args,
ScriptedCommandSynchronicity synchronicity,
lldb_private::CommandReturnObject &cmd_retobj,
- Error &error,
+ Status &error,
const lldb_private::ExecutionContext &exe_ctx) override;
- Error GenerateFunction(const char *signature,
- const StringList &input) override;
+ Status GenerateFunction(const char *signature,
+ const StringList &input) override;
- Error GenerateBreakpointCommandCallbackData(StringList &input,
- std::string &output) override;
+ Status GenerateBreakpointCommandCallbackData(StringList &input,
+ std::string &output) override;
bool GenerateWatchpointCommandCallbackData(StringList &input,
std::string &output) override;
@@ -332,23 +332,23 @@ public:
}
bool RunScriptFormatKeyword(const char *impl_function, Process *process,
- std::string &output, Error &error) override;
+ std::string &output, Status &error) override;
bool RunScriptFormatKeyword(const char *impl_function, Thread *thread,
- std::string &output, Error &error) override;
+ std::string &output, Status &error) override;
bool RunScriptFormatKeyword(const char *impl_function, Target *target,
- std::string &output, Error &error) override;
+ std::string &output, Status &error) override;
bool RunScriptFormatKeyword(const char *impl_function, StackFrame *frame,
- std::string &output, Error &error) override;
+ std::string &output, Status &error) override;
bool RunScriptFormatKeyword(const char *impl_function, ValueObject *value,
- std::string &output, Error &error) override;
+ std::string &output, Status &error) override;
bool
LoadScriptingModule(const char *filename, bool can_reload, bool init_session,
- lldb_private::Error &error,
+ lldb_private::Status &error,
StructuredData::ObjectSP *module_sp = nullptr) override;
bool IsReservedWord(const char *word) override;
@@ -364,14 +364,14 @@ public:
CommandReturnObject &result) override;
/// Set the callback body text into the callback for the breakpoint.
- Error SetBreakpointCommandCallback(BreakpointOptions *bp_options,
- const char *callback_body) override;
+ Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
+ const char *callback_body) override;
void SetBreakpointCommandCallbackFunction(BreakpointOptions *bp_options,
const char *function_name) override;
/// This one is for deserialization:
- Error SetBreakpointCommandCallback(
+ Status SetBreakpointCommandCallback(
BreakpointOptions *bp_options,
std::unique_ptr<BreakpointOptions::CommandData> &data_up) override;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/CMakeLists.txt
index ce0e21b..4df3912 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/CMakeLists.txt
+++ b/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/CMakeLists.txt
@@ -1,5 +1,10 @@
-list(APPEND SOURCES
+add_lldb_library(lldbPluginStructuredDataDarwinLog PLUGIN
StructuredDataDarwinLog.cpp
- )
-add_lldb_library(lldbPluginStructuredDataDarwinLog ${SOURCES})
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbHost
+ lldbInterpreter
+ lldbTarget
+ )
diff --git a/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
index e459268..f1450c3 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
@@ -17,10 +17,9 @@
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObjectMultiword.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -30,6 +29,8 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanCallOnFunctionExit.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
#define DARWIN_LOG_TYPE_VALUE "DarwinLog"
@@ -208,7 +209,7 @@ public:
using OperationCreationFunc =
std::function<FilterRuleSP(bool accept, size_t attribute_index,
- const std::string &op_arg, Error &error)>;
+ const std::string &op_arg, Status &error)>;
static void RegisterOperation(const ConstString &operation,
const OperationCreationFunc &creation_func) {
@@ -217,7 +218,7 @@ public:
static FilterRuleSP CreateRule(bool match_accepts, size_t attribute,
const ConstString &operation,
- const std::string &op_arg, Error &error) {
+ const std::string &op_arg, Status &error) {
// Find the creation func for this type of filter rule.
auto map = GetCreationFuncMap();
auto find_it = map.find(operation);
@@ -303,7 +304,8 @@ protected:
private:
static FilterRuleSP CreateOperation(bool accept, size_t attribute_index,
- const std::string &op_arg, Error &error) {
+ const std::string &op_arg,
+ Status &error) {
// We treat the op_arg as a regex. Validate it.
if (op_arg.empty()) {
error.SetErrorString("regex filter type requires a regex "
@@ -357,7 +359,8 @@ protected:
private:
static FilterRuleSP CreateOperation(bool accept, size_t attribute_index,
- const std::string &op_arg, Error &error) {
+ const std::string &op_arg,
+ Status &error) {
if (op_arg.empty()) {
error.SetErrorString("exact match filter type requires an "
"argument containing the text that must "
@@ -523,9 +526,9 @@ public:
m_filter_rules.clear();
}
- Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Error error;
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -663,8 +666,8 @@ public:
bool GetBroadcastEvents() const { return m_broadcast_events; }
private:
- Error ParseFilterRule(llvm::StringRef rule_text) {
- Error error;
+ Status ParseFilterRule(llvm::StringRef rule_text) {
+ Status error;
if (rule_text.empty()) {
error.SetErrorString("invalid rule_text");
@@ -746,8 +749,8 @@ private:
int MatchAttributeIndex(llvm::StringRef attribute_name) const {
for (const auto &Item : llvm::enumerate(s_filter_attributes)) {
- if (attribute_name == Item.Value)
- return Item.Index;
+ if (attribute_name == Item.value())
+ return Item.index();
}
// We didn't match anything.
@@ -898,7 +901,7 @@ protected:
// Send configuration to the feature by way of the process.
// Construct the options we will use.
auto config_sp = m_options_sp->BuildConfigurationData(m_enable);
- const Error error =
+ const Status error =
process_sp->ConfigureStructuredData(GetDarwinLogTypeName(), config_sp);
// Report results.
@@ -1039,7 +1042,7 @@ public:
}
};
-EnableOptionsSP ParseAutoEnableOptions(Error &error, Debugger &debugger) {
+EnableOptionsSP ParseAutoEnableOptions(Status &error, Debugger &debugger) {
// We are abusing the options data model here so that we can parse
// options without requiring the Debugger instance.
@@ -1211,7 +1214,7 @@ void StructuredDataDarwinLog::HandleArrivalOfStructuredData(
// to inspect, including showing backtraces.
}
-static void SetErrorWithJSON(Error &error, const char *message,
+static void SetErrorWithJSON(Status &error, const char *message,
StructuredData::Object &object) {
if (!message) {
error.SetErrorString("Internal error: message not set.");
@@ -1225,9 +1228,9 @@ static void SetErrorWithJSON(Error &error, const char *message,
error.SetErrorStringWithFormat("%s: %s", message, object_stream.GetData());
}
-Error StructuredDataDarwinLog::GetDescription(
+Status StructuredDataDarwinLog::GetDescription(
const StructuredData::ObjectSP &object_sp, lldb_private::Stream &stream) {
- Error error;
+ Status error;
if (!object_sp) {
error.SetErrorString("No structured data.");
@@ -1482,9 +1485,9 @@ void StructuredDataDarwinLog::DebuggerInitialize(Debugger &debugger) {
}
}
-Error StructuredDataDarwinLog::FilterLaunchInfo(ProcessLaunchInfo &launch_info,
- Target *target) {
- Error error;
+Status StructuredDataDarwinLog::FilterLaunchInfo(ProcessLaunchInfo &launch_info,
+ Target *target) {
+ Status error;
// If we're not debugging this launched process, there's nothing for us
// to do here.
@@ -1814,7 +1817,7 @@ StructuredDataDarwinLog::DumpHeader(Stream &output_stream,
}
if (options_sp->GetDisplayActivityChain()) {
- std::string activity_chain;
+ llvm::StringRef activity_chain;
if (event.GetValueForKeyAsString("activity-chain", activity_chain) &&
!activity_chain.empty()) {
if (header_count > 0)
@@ -1853,7 +1856,7 @@ StructuredDataDarwinLog::DumpHeader(Stream &output_stream,
}
if (options_sp->GetDisplaySubsystem()) {
- std::string subsystem;
+ llvm::StringRef subsystem;
if (event.GetValueForKeyAsString("subsystem", subsystem) &&
!subsystem.empty()) {
if (header_count > 0)
@@ -1865,7 +1868,7 @@ StructuredDataDarwinLog::DumpHeader(Stream &output_stream,
}
if (options_sp->GetDisplayCategory()) {
- std::string category;
+ llvm::StringRef category;
if (event.GetValueForKeyAsString("category", category) &&
!category.empty()) {
if (header_count > 0)
@@ -1898,16 +1901,16 @@ size_t StructuredDataDarwinLog::HandleDisplayOfEvent(
size_t total_bytes = 0;
// Grab the message content.
- std::string message;
+ llvm::StringRef message;
if (!event.GetValueForKeyAsString("message", message))
return true;
// Display the log entry.
- const auto len = message.length();
+ const auto len = message.size();
total_bytes += DumpHeader(stream, event);
- stream.Write(message.c_str(), len);
+ stream.Write(message.data(), len);
total_bytes += len;
// Add an end of line.
@@ -1990,7 +1993,7 @@ void StructuredDataDarwinLog::EnableNow() {
// We can run it directly.
// Send configuration to the feature by way of the process.
- const Error error =
+ const Status error =
process_sp->ConfigureStructuredData(GetDarwinLogTypeName(), config_sp);
// Report results.
diff --git a/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h b/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h
index 7eaab12..77b6e7b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h
@@ -67,8 +67,8 @@ public:
Process &process, const ConstString &type_name,
const StructuredData::ObjectSP &object_sp) override;
- Error GetDescription(const StructuredData::ObjectSP &object_sp,
- lldb_private::Stream &stream) override;
+ Status GetDescription(const StructuredData::ObjectSP &object_sp,
+ lldb_private::Stream &stream) override;
bool GetEnabled(const ConstString &type_name) const override;
@@ -96,7 +96,8 @@ private:
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);
- static Error FilterLaunchInfo(ProcessLaunchInfo &launch_info, Target *target);
+ static Status FilterLaunchInfo(ProcessLaunchInfo &launch_info,
+ Target *target);
// -------------------------------------------------------------------------
// Internal helper methods used by friend classes
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index c064d61..f541876 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -21,9 +21,7 @@
#include "UniqueDWARFASTType.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/Value.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/Args.h"
@@ -38,6 +36,8 @@
#include "lldb/Symbol/TypeMap.h"
#include "lldb/Target/Language.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -1595,24 +1595,17 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
: containing_decl_ctx,
type_name_cstr, clang_type, storage, is_inline);
- // if (template_param_infos.GetSize() >
- // 0)
- // {
- // clang::FunctionTemplateDecl
- // *func_template_decl =
- // CreateFunctionTemplateDecl
- // (containing_decl_ctx,
- // function_decl,
- // type_name_cstr,
- // template_param_infos);
- //
- // CreateFunctionTemplateSpecializationInfo
- // (function_decl,
- // func_template_decl,
- // template_param_infos);
- // }
- // Add the decl to our DIE to decl context map
-
+ if (has_template_params) {
+ ClangASTContext::TemplateParameterInfos template_param_infos;
+ ParseTemplateParameterInfos(die, template_param_infos);
+ clang::FunctionTemplateDecl *func_template_decl =
+ m_ast.CreateFunctionTemplateDecl(
+ containing_decl_ctx, function_decl, type_name_cstr,
+ template_param_infos);
+ m_ast.CreateFunctionTemplateSpecializationInfo(
+ function_decl, func_template_decl, template_param_infos);
+ }
+
lldbassert(function_decl);
if (function_decl) {
@@ -1951,6 +1944,19 @@ bool DWARFASTParserClang::ParseTemplateDIE(
const dw_tag_t tag = die.Tag();
switch (tag) {
+ case DW_TAG_GNU_template_parameter_pack: {
+ template_param_infos.packed_args.reset(
+ new ClangASTContext::TemplateParameterInfos);
+ for (DWARFDIE child_die = die.GetFirstChild(); child_die.IsValid();
+ child_die = child_die.GetSibling()) {
+ if (!ParseTemplateDIE(child_die, *template_param_infos.packed_args))
+ return false;
+ }
+ if (const char *name = die.GetName()) {
+ template_param_infos.pack_name = name;
+ }
+ return true;
+ }
case DW_TAG_template_type_parameter:
case DW_TAG_template_value_parameter: {
DWARFAttributes attributes;
@@ -2040,6 +2046,7 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos(
switch (tag) {
case DW_TAG_template_type_parameter:
case DW_TAG_template_value_parameter:
+ case DW_TAG_GNU_template_parameter_pack:
ParseTemplateDIE(die, template_param_infos);
break;
@@ -3450,6 +3457,7 @@ size_t DWARFASTParserClang::ParseChildParameters(
case DW_TAG_template_type_parameter:
case DW_TAG_template_value_parameter:
+ case DW_TAG_GNU_template_parameter_pack:
// The one caller of this was never using the template_param_infos,
// and the local variable was taking up a large amount of stack space
// in SymbolFileDWARF::ParseType() so this was removed. If we ever need
@@ -3682,7 +3690,7 @@ DWARFASTParserClang::GetClangDeclContextForDIE(const DWARFDIE &die) {
break;
case DW_TAG_lexical_block:
- decl_ctx = (clang::DeclContext *)ResolveBlockDIE(die);
+ decl_ctx = GetDeclContextForBlock(die);
try_parsing_type = false;
break;
@@ -3704,6 +3712,69 @@ DWARFASTParserClang::GetClangDeclContextForDIE(const DWARFDIE &die) {
return nullptr;
}
+static bool IsSubroutine(const DWARFDIE &die) {
+ switch (die.Tag()) {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static DWARFDIE GetContainingFunctionWithAbstractOrigin(const DWARFDIE &die) {
+ for (DWARFDIE candidate = die; candidate; candidate = candidate.GetParent()) {
+ if (IsSubroutine(candidate)) {
+ if (candidate.GetReferencedDIE(DW_AT_abstract_origin)) {
+ return candidate;
+ } else {
+ return DWARFDIE();
+ }
+ }
+ }
+ assert(0 && "Shouldn't call GetContainingFunctionWithAbstractOrigin on "
+ "something not in a function");
+ return DWARFDIE();
+}
+
+static DWARFDIE FindAnyChildWithAbstractOrigin(const DWARFDIE &context) {
+ for (DWARFDIE candidate = context.GetFirstChild(); candidate.IsValid();
+ candidate = candidate.GetSibling()) {
+ if (candidate.GetReferencedDIE(DW_AT_abstract_origin)) {
+ return candidate;
+ }
+ }
+ return DWARFDIE();
+}
+
+static DWARFDIE FindFirstChildWithAbstractOrigin(const DWARFDIE &block,
+ const DWARFDIE &function) {
+ assert(IsSubroutine(function));
+ for (DWARFDIE context = block; context != function.GetParent();
+ context = context.GetParent()) {
+ assert(!IsSubroutine(context) || context == function);
+ if (DWARFDIE child = FindAnyChildWithAbstractOrigin(context)) {
+ return child;
+ }
+ }
+ return DWARFDIE();
+}
+
+clang::DeclContext *
+DWARFASTParserClang::GetDeclContextForBlock(const DWARFDIE &die) {
+ assert(die.Tag() == DW_TAG_lexical_block);
+ DWARFDIE containing_function_with_abstract_origin =
+ GetContainingFunctionWithAbstractOrigin(die);
+ if (!containing_function_with_abstract_origin) {
+ return (clang::DeclContext *)ResolveBlockDIE(die);
+ }
+ DWARFDIE child = FindFirstChildWithAbstractOrigin(
+ die, containing_function_with_abstract_origin);
+ CompilerDeclContext decl_context =
+ GetDeclContextContainingUIDFromDWARF(child);
+ return (clang::DeclContext *)decl_context.GetOpaqueDeclContext();
+}
+
clang::BlockDecl *DWARFASTParserClang::ResolveBlockDIE(const DWARFDIE &die) {
if (die && die.Tag() == DW_TAG_lexical_block) {
clang::BlockDecl *decl =
@@ -3837,10 +3908,9 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
if (src_name) {
ConstString src_const_name(src_name);
if (src_die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
- src_name_to_die_artificial.Append(src_const_name.GetStringRef(),
- src_die);
+ src_name_to_die_artificial.Append(src_const_name, src_die);
else
- src_name_to_die.Append(src_const_name.GetStringRef(), src_die);
+ src_name_to_die.Append(src_const_name, src_die);
}
}
}
@@ -3857,10 +3927,9 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
if (dst_name) {
ConstString dst_const_name(dst_name);
if (dst_die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
- dst_name_to_die_artificial.Append(dst_const_name.GetStringRef(),
- dst_die);
+ dst_name_to_die_artificial.Append(dst_const_name, dst_die);
else
- dst_name_to_die.Append(dst_const_name.GetStringRef(), dst_die);
+ dst_name_to_die.Append(dst_const_name, dst_die);
}
}
}
@@ -3973,7 +4042,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
src_name_to_die.Sort();
for (idx = 0; idx < dst_size; ++idx) {
- llvm::StringRef dst_name = dst_name_to_die.GetCStringAtIndex(idx);
+ ConstString dst_name = dst_name_to_die.GetCStringAtIndex(idx);
dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx);
src_die = src_name_to_die.Find(dst_name, DWARFDIE());
@@ -4028,7 +4097,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
dst_name_to_die_artificial.Sort();
for (idx = 0; idx < src_size_artificial; ++idx) {
- llvm::StringRef src_name_artificial =
+ ConstString src_name_artificial =
src_name_to_die_artificial.GetCStringAtIndex(idx);
src_die = src_name_to_die_artificial.GetValueAtIndexUnchecked(idx);
dst_die =
@@ -4072,13 +4141,13 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
if (dst_size_artificial) {
for (idx = 0; idx < dst_size_artificial; ++idx) {
- llvm::StringRef dst_name_artificial =
+ ConstString dst_name_artificial =
dst_name_to_die_artificial.GetCStringAtIndex(idx);
dst_die = dst_name_to_die_artificial.GetValueAtIndexUnchecked(idx);
if (log)
log->Printf("warning: need to create artificial method for 0x%8.8x for "
"method '%s'",
- dst_die.GetOffset(), dst_name_artificial.str().c_str());
+ dst_die.GetOffset(), dst_name_artificial.GetCString());
failures.Append(dst_die);
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index 3d6d08e..57c1fc0 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -66,6 +66,8 @@ protected:
class DelayedAddObjCClassProperty;
typedef std::vector<DelayedAddObjCClassProperty> DelayedPropertyList;
+ clang::DeclContext *GetDeclContextForBlock(const DWARFDIE &die);
+
clang::BlockDecl *ResolveBlockDIE(const DWARFDIE &die);
clang::NamespaceDecl *ResolveNamespaceDIE(const DWARFDIE &die);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp
index 0cf7ff2..3b1466d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp
@@ -2,14 +2,14 @@
#include "DWARFASTParserOCaml.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/TypeList.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
index 6d3ff8e..79b2acc 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -10,15 +10,16 @@
#include "DWARFCompileUnit.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
#include "DWARFDIECollection.h"
#include "DWARFDebugAbbrev.h"
@@ -134,8 +135,9 @@ size_t DWARFCompileUnit::ExtractDIEsIfNeeded(bool cu_die_only) {
if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1)
return 0; // Already parsed
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
+ func_cat,
"%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( cu_die_only = %i )",
m_offset, cu_die_only);
@@ -256,16 +258,15 @@ size_t DWARFCompileUnit::ExtractDIEsIfNeeded(bool cu_die_only) {
m_die_array.end());
exact_size_die_array.swap(m_die_array);
}
- Log *verbose_log(
- LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO | DWARF_LOG_VERBOSE));
- if (verbose_log) {
+ Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ if (log && log->GetVerbose()) {
StreamString strm;
Dump(&strm);
if (m_die_array.empty())
strm.Printf("error: no DIE for compile unit");
else
m_die_array[0].Dump(m_dwarf2Data, this, strm, UINT32_MAX);
- verbose_log->PutString(strm.GetString());
+ log->PutString(strm.GetString());
}
if (!m_dwo_symbol_file)
@@ -324,18 +325,14 @@ bool DWARFCompileUnit::Verify(Stream *s) const {
bool abbr_offset_OK =
m_dwarf2Data->get_debug_abbrev_data().ValidOffset(GetAbbrevOffset());
bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
- bool verbose = s->GetVerbose();
if (valid_offset && length_OK && version_OK && addr_size_OK &&
abbr_offset_OK) {
- if (verbose)
- s->Printf(" 0x%8.8x: OK\n", m_offset);
return true;
} else {
s->Printf(" 0x%8.8x: ", m_offset);
-
- m_dwarf2Data->get_debug_info_data().Dump(s, m_offset, lldb::eFormatHex, 1,
- Size(), 32, LLDB_INVALID_ADDRESS,
- 0, 0);
+ DumpDataExtractor(m_dwarf2Data->get_debug_info_data(), s, m_offset,
+ lldb::eFormatHex, 1, Size(), 32, LLDB_INVALID_ADDRESS, 0,
+ 0);
s->EOL();
if (valid_offset) {
if (!length_OK)
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
index 5fb6358..1e5bf61 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
@@ -11,7 +11,7 @@
#include <algorithm>
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
using namespace std;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
index 62ddbe8..46d09f1 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
@@ -11,12 +11,12 @@
#define liblldb_DWARFDataExtractor_h_
// Other libraries and framework includes.
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/DataExtractor.h"
namespace lldb_private {
-class DWARFDataExtractor : public lldb_private::DataExtractor {
+class DWARFDataExtractor : public DataExtractor {
public:
DWARFDataExtractor() : DataExtractor(), m_is_dwarf64(false) {}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
index fe6df91..d681925 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
@@ -9,7 +9,7 @@
#include "DWARFDebugAbbrev.h"
#include "DWARFDataExtractor.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
index 06b46f0..cecb69c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
@@ -10,7 +10,7 @@
#include "DWARFDebugArangeSet.h"
#include "SymbolFileDWARF.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
#include <assert.h>
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
index 5e71e9d..13c2d87 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
@@ -14,9 +14,9 @@
#include <algorithm>
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/Timer.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
#include "DWARFCompileUnit.h"
#include "DWARFDebugInfo.h"
@@ -110,7 +110,8 @@ void DWARFDebugAranges::AppendRange(dw_offset_t offset, dw_addr_t low_pc,
}
void DWARFDebugAranges::Sort(bool minimize) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s this = %p", LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION,
static_cast<void *>(this));
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
index 9dc656d..eff9850 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -12,10 +12,10 @@
#include <algorithm>
#include <set>
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
#include "DWARFCompileUnit.h"
#include "DWARFDebugAranges.h"
@@ -430,10 +430,6 @@ static dw_offset_t DumpCallback(SymbolFileDWARF *dwarf2Data,
} else {
// See if the DIE is in this compile unit?
if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) {
- // This DIE is in this compile unit!
- if (s->GetVerbose())
- cu->Dump(s); // Dump the compile unit for the DIE in verbose mode
-
return next_offset;
// // We found our compile unit that contains our DIE, just skip to
// dumping the requested DIE...
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
index a05a888..be4e18b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -15,7 +15,7 @@
#include "DWARFDIE.h"
#include "SymbolFileDWARF.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Core/STLUtils.h"
#include "lldb/lldb-private.h"
typedef std::multimap<const char *, dw_offset_t, CStringCompareFunctionObject>
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
index a824c4a..8d87c20 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -14,9 +14,9 @@
#include <algorithm>
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Expression/DWARFExpression.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/Stream.h"
#include "DWARFCompileUnit.h"
#include "DWARFDIECollection.h"
@@ -202,7 +202,7 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data,
const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset();
lldb::offset_t offset = *offset_ptr;
// if (offset >= cu_end_offset)
- // Log::Error("DIE at offset 0x%8.8x is beyond the end of the current
+ // Log::Status("DIE at offset 0x%8.8x is beyond the end of the current
// compile unit (0x%8.8x)", m_offset, cu_end_offset);
if ((offset < cu_end_offset) && debug_info_data.ValidOffset(offset)) {
m_offset = offset;
@@ -666,13 +666,9 @@ void DWARFDebugInfoEntry::DumpAttribute(
SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu,
const DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr,
Stream &s, dw_attr_t attr, dw_form_t form) {
- bool verbose = s.GetVerbose();
bool show_form = s.GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowForm);
- if (verbose)
- s.Offset(*offset_ptr);
- else
- s.Printf(" ");
+ s.Printf(" ");
s.Indent(DW_AT_value_to_name(attr));
if (show_form) {
@@ -694,35 +690,18 @@ void DWARFDebugInfoEntry::DumpAttribute(
s.PutCString("( ");
- // Always dump form value if verbose is enabled
- if (verbose) {
- form_value.Dump(s);
- }
-
// Check to see if we have any special attribute formatters
switch (attr) {
case DW_AT_stmt_list:
- if (verbose)
- s.PutCString(" ( ");
s.Printf("0x%8.8" PRIx64, form_value.Unsigned());
- if (verbose)
- s.PutCString(" )");
break;
case DW_AT_language:
- if (verbose)
- s.PutCString(" ( ");
s.PutCString(DW_LANG_value_to_name(form_value.Unsigned()));
- if (verbose)
- s.PutCString(" )");
break;
case DW_AT_encoding:
- if (verbose)
- s.PutCString(" ( ");
s.PutCString(DW_ATE_value_to_name(form_value.Unsigned()));
- if (verbose)
- s.PutCString(" )");
break;
case DW_AT_frame_base:
@@ -730,32 +709,20 @@ void DWARFDebugInfoEntry::DumpAttribute(
case DW_AT_data_member_location: {
const uint8_t *blockData = form_value.BlockData();
if (blockData) {
- if (!verbose)
- form_value.Dump(s);
-
// Location description is inlined in data in the form value
DWARFDataExtractor locationData(debug_info_data,
(*offset_ptr) - form_value.Unsigned(),
form_value.Unsigned());
- if (verbose)
- s.PutCString(" ( ");
DWARFExpression::PrintDWARFExpression(
s, locationData, DWARFCompileUnit::GetAddressByteSize(cu), 4, false);
- if (verbose)
- s.PutCString(" )");
} else {
// We have a location list offset as the value that is
// the offset into the .debug_loc section that describes
// the value over it's lifetime
uint64_t debug_loc_offset = form_value.Unsigned();
if (dwarf2Data) {
- if (!verbose)
- form_value.Dump(s);
DWARFExpression::PrintDWARFLocationList(
s, cu, dwarf2Data->get_debug_loc_data(), debug_loc_offset);
- } else {
- if (!verbose)
- form_value.Dump(s);
}
}
} break;
@@ -765,25 +732,17 @@ void DWARFDebugInfoEntry::DumpAttribute(
uint64_t abstract_die_offset = form_value.Reference();
form_value.Dump(s);
// *ostrm_ptr << HEX32 << abstract_die_offset << " ( ";
- if (verbose)
- s.PutCString(" ( ");
GetName(dwarf2Data, cu, abstract_die_offset, s);
- if (verbose)
- s.PutCString(" )");
} break;
case DW_AT_type: {
uint64_t type_die_offset = form_value.Reference();
- if (!verbose)
- form_value.Dump(s);
s.PutCString(" ( ");
AppendTypeName(dwarf2Data, cu, type_die_offset, s);
s.PutCString(" )");
} break;
case DW_AT_ranges: {
- if (!verbose)
- form_value.Dump(s);
lldb::offset_t ranges_offset = form_value.Unsigned();
dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
if (dwarf2Data)
@@ -792,8 +751,6 @@ void DWARFDebugInfoEntry::DumpAttribute(
} break;
default:
- if (!verbose)
- form_value.Dump(s);
break;
}
@@ -1690,6 +1647,8 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address,
break;
case DW_TAG_template_value_parameter:
break;
+ case DW_TAG_GNU_template_parameter_pack:
+ break;
case DW_TAG_thrown_type:
break;
case DW_TAG_try_block:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
index bce21c4..694d34f 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
@@ -13,10 +13,10 @@
#include <assert.h>
#include "lldb/Core/FileSpecList.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Timer.h"
#include "LogChannelDWARF.h"
#include "SymbolFileDWARF.h"
@@ -484,9 +484,9 @@ bool DWARFDebugLine::ParseStatementTable(
const dw_offset_t debug_line_offset = *offset_ptr;
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
- "DWARFDebugLine::ParseStatementTable (.debug_line[0x%8.8x])",
+ func_cat, "DWARFDebugLine::ParseStatementTable (.debug_line[0x%8.8x])",
debug_line_offset);
if (!ParsePrologue(debug_line_data, offset_ptr, prologue.get())) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
index d564630..19074b8 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
@@ -12,7 +12,7 @@
#include "DWARFDebugMacinfoEntry.h"
#include "SymbolFileDWARF.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
using namespace std;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
index 4549859..f078fbd 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
@@ -9,7 +9,7 @@
#include "DWARFDebugMacinfoEntry.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
using namespace std;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
index d4281ba..766899c 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
@@ -9,8 +9,8 @@
#include "DWARFDebugPubnames.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/Timer.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
#include "DWARFCompileUnit.h"
#include "DWARFDIECollection.h"
@@ -25,7 +25,8 @@ using namespace lldb_private;
DWARFDebugPubnames::DWARFDebugPubnames() : m_sets() {}
bool DWARFDebugPubnames::Extract(const DWARFDataExtractor &data) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")",
(uint64_t)data.GetByteSize());
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
@@ -52,7 +53,8 @@ bool DWARFDebugPubnames::Extract(const DWARFDataExtractor &data) {
}
bool DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF *dwarf2Data) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"DWARFDebugPubnames::GeneratePubnames (data = %p)",
static_cast<void *>(dwarf2Data));
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
index 4518d65..21e2482 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
@@ -9,8 +9,8 @@
#include "DWARFDebugPubnamesSet.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
#include "SymbolFileDWARF.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
index 9654ee3..6e7d3f3 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
@@ -11,6 +11,7 @@
#define SymbolFileDWARF_DWARFDebugPubnamesSet_h_
#include "SymbolFileDWARF.h"
+#include <map>
#include <string>
#include <vector>
#if __cplusplus >= 201103L || defined(_MSC_VER)
@@ -19,6 +20,8 @@
#include <ext/hash_map>
#endif
+#include "lldb/Core/STLUtils.h"
+
class DWARFDebugPubnamesSet {
public:
struct Header {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
index ef35668..515c083 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
@@ -9,7 +9,7 @@
#include "DWARFDebugRanges.h"
#include "SymbolFileDWARF.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
#include <assert.h>
using namespace lldb_private;
@@ -82,7 +82,6 @@ void DWARFDebugRanges::Dump(Stream &s,
lldb::offset_t *offset_ptr,
dw_addr_t cu_base_addr) {
uint32_t addr_size = s.GetAddressByteSize();
- bool verbose = s.GetVerbose();
dw_addr_t base_addr = cu_base_addr;
while (
@@ -95,10 +94,6 @@ void DWARFDebugRanges::Dump(Stream &s,
begin = LLDB_INVALID_ADDRESS;
s.Indent();
- if (verbose) {
- s.AddressRange(begin, end, sizeof(dw_addr_t), " offsets = ");
- }
-
if (begin == 0 && end == 0) {
s.PutCString(" End");
break;
@@ -111,8 +106,7 @@ void DWARFDebugRanges::Dump(Stream &s,
dw_addr_t begin_addr = begin + base_addr;
dw_addr_t end_addr = end + base_addr;
- s.AddressRange(begin_addr, end_addr, sizeof(dw_addr_t),
- verbose ? " ==> addrs = " : NULL);
+ s.AddressRange(begin_addr, end_addr, sizeof(dw_addr_t), NULL);
}
}
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
index 0d0a5a3..1f3c597 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
@@ -15,7 +15,7 @@
#include <string>
#include <vector>
// Other libraries and framework includes
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
// Project includes
#include "DWARFDefines.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp
index c5260bb..2ff0fe3 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "DWARFDefines.h"
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
#include <cstdio>
#include <cstring>
#include <string>
@@ -610,6 +610,8 @@ DW_TAG_CategoryEnum get_tag_category(uint16_t tag) {
return TagCategoryType;
case DW_TAG_template_value_parameter:
return TagCategoryType;
+ case DW_TAG_GNU_template_parameter_pack:
+ return TagCategoryType;
case DW_TAG_thrown_type:
return TagCategoryType;
case DW_TAG_try_block:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
index 39c52a8..0853671 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -9,8 +9,8 @@
#include <assert.h>
-#include "lldb/Core/Stream.h"
#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/Stream.h"
#include "DWARFCompileUnit.h"
#include "DWARFFormValue.h"
@@ -406,8 +406,6 @@ void DWARFFormValue::Dump(Stream &s) const {
uint64_t uvalue = Unsigned();
bool cu_relative_offset = false;
- bool verbose = s.GetVerbose();
-
switch (m_form) {
case DW_FORM_addr:
s.Address(uvalue, sizeof(uint64_t));
@@ -476,8 +474,6 @@ void DWARFFormValue::Dump(Stream &s) const {
case DW_FORM_strp: {
const char *dbg_str = AsCString();
if (dbg_str) {
- if (verbose)
- s.Printf(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue);
s.QuotedCString(dbg_str);
} else {
s.PutHex32(uvalue);
@@ -496,28 +492,18 @@ void DWARFFormValue::Dump(Stream &s) const {
}
case DW_FORM_ref1:
cu_relative_offset = true;
- if (verbose)
- s.Printf("cu + 0x%2.2x", (uint8_t)uvalue);
break;
case DW_FORM_ref2:
cu_relative_offset = true;
- if (verbose)
- s.Printf("cu + 0x%4.4x", (uint16_t)uvalue);
break;
case DW_FORM_ref4:
cu_relative_offset = true;
- if (verbose)
- s.Printf("cu + 0x%4.4x", (uint32_t)uvalue);
break;
case DW_FORM_ref8:
cu_relative_offset = true;
- if (verbose)
- s.Printf("cu + 0x%8.8" PRIx64, uvalue);
break;
case DW_FORM_ref_udata:
cu_relative_offset = true;
- if (verbose)
- s.Printf("cu + 0x%" PRIx64, uvalue);
break;
// All DW_FORM_indirect attributes should be resolved prior to calling this
@@ -535,9 +521,6 @@ void DWARFFormValue::Dump(Stream &s) const {
if (cu_relative_offset) {
assert(m_cu); // CU must be valid for DW_FORM_ref forms that are compile
// unit relative or we will get this wrong
- if (verbose)
- s.PutCString(" => ");
-
s.Printf("{0x%8.8" PRIx64 "}", uvalue + m_cu->GetOffset());
}
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
index c1cb30b..9595175 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
@@ -13,8 +13,8 @@
#include <vector>
#include "lldb/Core/MappedHash.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/RegularExpression.h"
#include "lldb/lldb-defines.h"
#include "DWARFDefines.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
index 1385e3d..0b06713 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
@@ -9,195 +9,35 @@
#include "LogChannelDWARF.h"
-#include "SymbolFileDWARF.h"
-#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Interpreter/Args.h"
-
-using namespace lldb;
using namespace lldb_private;
-// when the one and only logging channel is enabled, then this will be non NULL.
-static LogChannelDWARF *g_log_channel = NULL;
-
-LogChannelDWARF::LogChannelDWARF() : LogChannel() {}
-
-LogChannelDWARF::~LogChannelDWARF() {}
+static constexpr Log::Category g_categories[] = {
+ {{"aranges"},
+ {"log the parsing of .debug_aranges"},
+ DWARF_LOG_DEBUG_ARANGES},
+ {{"comp"},
+ {"log insertions of object files into DWARF debug maps"},
+ DWARF_LOG_TYPE_COMPLETION},
+ {{"info"}, {"log the parsing of .debug_info"}, DWARF_LOG_DEBUG_INFO},
+ {{"line"}, {"log the parsing of .debug_line"}, DWARF_LOG_DEBUG_LINE},
+ {{"lookups"},
+ {"log any lookups that happen by name, regex, or address"},
+ DWARF_LOG_LOOKUPS},
+ {{"map"},
+ {"log struct/unions/class type completions"},
+ DWARF_LOG_DEBUG_MAP},
+ {{"pubnames"},
+ {"log the parsing of .debug_pubnames"},
+ DWARF_LOG_DEBUG_PUBNAMES},
+ {{"pubtypes"},
+ {"log the parsing of .debug_pubtypes"},
+ DWARF_LOG_DEBUG_PUBTYPES},
+};
+
+Log::Channel LogChannelDWARF::g_channel(g_categories, DWARF_LOG_DEFAULT);
void LogChannelDWARF::Initialize() {
- PluginManager::RegisterPlugin(GetPluginNameStatic(),
- GetPluginDescriptionStatic(),
- LogChannelDWARF::CreateInstance);
-}
-
-void LogChannelDWARF::Terminate() {
- PluginManager::UnregisterPlugin(LogChannelDWARF::CreateInstance);
-}
-
-LogChannel *LogChannelDWARF::CreateInstance() { return new LogChannelDWARF(); }
-
-lldb_private::ConstString LogChannelDWARF::GetPluginNameStatic() {
- return SymbolFileDWARF::GetPluginNameStatic();
-}
-
-const char *LogChannelDWARF::GetPluginDescriptionStatic() {
- return "DWARF log channel for debugging plug-in issues.";
-}
-
-lldb_private::ConstString LogChannelDWARF::GetPluginName() {
- return GetPluginNameStatic();
+ Log::Register("dwarf", g_channel);
}
-uint32_t LogChannelDWARF::GetPluginVersion() { return 1; }
-
-void LogChannelDWARF::Delete() { g_log_channel = NULL; }
-
-void LogChannelDWARF::Disable(const char **categories, Stream *feedback_strm) {
- if (m_log_ap.get() == NULL)
- return;
-
- uint32_t flag_bits = m_log_ap->GetMask().Get();
- for (size_t i = 0; categories[i] != NULL; ++i) {
- const char *arg = categories[i];
-
- if (::strcasecmp(arg, "all") == 0)
- flag_bits &= ~DWARF_LOG_ALL;
- else if (::strcasecmp(arg, "info") == 0)
- flag_bits &= ~DWARF_LOG_DEBUG_INFO;
- else if (::strcasecmp(arg, "line") == 0)
- flag_bits &= ~DWARF_LOG_DEBUG_LINE;
- else if (::strcasecmp(arg, "pubnames") == 0)
- flag_bits &= ~DWARF_LOG_DEBUG_PUBNAMES;
- else if (::strcasecmp(arg, "pubtypes") == 0)
- flag_bits &= ~DWARF_LOG_DEBUG_PUBTYPES;
- else if (::strcasecmp(arg, "aranges") == 0)
- flag_bits &= ~DWARF_LOG_DEBUG_ARANGES;
- else if (::strcasecmp(arg, "lookups") == 0)
- flag_bits &= ~DWARF_LOG_LOOKUPS;
- else if (::strcasecmp(arg, "map") == 0)
- flag_bits &= ~DWARF_LOG_DEBUG_MAP;
- else if (::strcasecmp(arg, "default") == 0)
- flag_bits &= ~DWARF_LOG_DEFAULT;
- else if (::strcasecmp(arg, "verbose") == 0)
- flag_bits &= ~DWARF_LOG_VERBOSE;
- else if (::strncasecmp(arg, "comp", 4) == 0)
- flag_bits &= ~DWARF_LOG_TYPE_COMPLETION;
- else {
- feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
- ListCategories(feedback_strm);
- }
- }
-
- if (flag_bits == 0)
- Delete();
- else
- m_log_ap->GetMask().Reset(flag_bits);
-
- return;
-}
-
-bool LogChannelDWARF::Enable(
- StreamSP &log_stream_sp, uint32_t log_options,
- Stream *feedback_strm, // Feedback stream for argument errors etc
- const char **categories // The categories to enable within this logging
- // stream, if empty, enable default set
- ) {
- Delete();
-
- if (m_log_ap)
- m_log_ap->SetStream(log_stream_sp);
- else
- m_log_ap.reset(new Log(log_stream_sp));
-
- g_log_channel = this;
- uint32_t flag_bits = 0;
- bool got_unknown_category = false;
- for (size_t i = 0; categories[i] != NULL; ++i) {
- const char *arg = categories[i];
-
- if (::strcasecmp(arg, "all") == 0)
- flag_bits |= DWARF_LOG_ALL;
- else if (::strcasecmp(arg, "info") == 0)
- flag_bits |= DWARF_LOG_DEBUG_INFO;
- else if (::strcasecmp(arg, "line") == 0)
- flag_bits |= DWARF_LOG_DEBUG_LINE;
- else if (::strcasecmp(arg, "pubnames") == 0)
- flag_bits |= DWARF_LOG_DEBUG_PUBNAMES;
- else if (::strcasecmp(arg, "pubtypes") == 0)
- flag_bits |= DWARF_LOG_DEBUG_PUBTYPES;
- else if (::strcasecmp(arg, "aranges") == 0)
- flag_bits |= DWARF_LOG_DEBUG_ARANGES;
- else if (::strcasecmp(arg, "lookups") == 0)
- flag_bits |= DWARF_LOG_LOOKUPS;
- else if (::strcasecmp(arg, "map") == 0)
- flag_bits |= DWARF_LOG_DEBUG_MAP;
- else if (::strcasecmp(arg, "default") == 0)
- flag_bits |= DWARF_LOG_DEFAULT;
- else if (::strcasecmp(arg, "verbose") == 0)
- flag_bits |= DWARF_LOG_VERBOSE;
- else if (::strncasecmp(arg, "comp", 4) == 0)
- flag_bits |= DWARF_LOG_TYPE_COMPLETION;
- else {
- feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
- if (got_unknown_category == false) {
- got_unknown_category = true;
- ListCategories(feedback_strm);
- }
- }
- }
- if (flag_bits == 0)
- flag_bits = DWARF_LOG_DEFAULT;
- m_log_ap->GetMask().Reset(flag_bits);
- m_log_ap->GetOptions().Reset(log_options);
- return m_log_ap.get() != NULL;
-}
-
-void LogChannelDWARF::ListCategories(Stream *strm) {
- strm->Printf(
- "Logging categories for '%s':\n"
- " all - turn on all available logging categories\n"
- " info - log the parsing of .debug_info\n"
- " line - log the parsing of .debug_line\n"
- " pubnames - log the parsing of .debug_pubnames\n"
- " pubtypes - log the parsing of .debug_pubtypes\n"
- " aranges - log the parsing of .debug_aranges\n"
- " lookups - log any lookups that happen by name, regex, or address\n"
- " completion - log struct/unions/class type completions\n"
- " map - log insertions of object files into DWARF debug maps\n",
- SymbolFileDWARF::GetPluginNameStatic().GetCString());
-}
-
-Log *LogChannelDWARF::GetLog() {
- if (g_log_channel)
- return g_log_channel->m_log_ap.get();
-
- return NULL;
-}
-
-Log *LogChannelDWARF::GetLogIfAll(uint32_t mask) {
- if (g_log_channel && g_log_channel->m_log_ap.get()) {
- if (g_log_channel->m_log_ap->GetMask().AllSet(mask))
- return g_log_channel->m_log_ap.get();
- }
- return NULL;
-}
-
-Log *LogChannelDWARF::GetLogIfAny(uint32_t mask) {
- if (g_log_channel && g_log_channel->m_log_ap.get()) {
- if (g_log_channel->m_log_ap->GetMask().AnySet(mask))
- return g_log_channel->m_log_ap.get();
- }
- return NULL;
-}
-
-void LogChannelDWARF::LogIf(uint32_t mask, const char *format, ...) {
- if (g_log_channel) {
- Log *log = g_log_channel->m_log_ap.get();
- if (log && log->GetMask().AnySet(mask)) {
- va_list args;
- va_start(args, format);
- log->VAPrintf(format, args);
- va_end(args);
- }
- }
-}
+void LogChannelDWARF::Terminate() { Log::Unregister("dwarf"); }
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
index 4802f85..0293fbd 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
@@ -14,9 +14,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
-#define DWARF_LOG_VERBOSE (1u << 0)
#define DWARF_LOG_DEBUG_INFO (1u << 1)
#define DWARF_LOG_DEBUG_LINE (1u << 2)
#define DWARF_LOG_DEBUG_PUBNAMES (1u << 3)
@@ -28,47 +27,17 @@
#define DWARF_LOG_ALL (UINT32_MAX)
#define DWARF_LOG_DEFAULT (DWARF_LOG_DEBUG_INFO)
-class LogChannelDWARF : public lldb_private::LogChannel {
-public:
- LogChannelDWARF();
-
- ~LogChannelDWARF() override;
+namespace lldb_private {
+class LogChannelDWARF {
+ static Log::Channel g_channel;
+public:
static void Initialize();
-
static void Terminate();
- static lldb_private::ConstString GetPluginNameStatic();
-
- static const char *GetPluginDescriptionStatic();
-
- static lldb_private::LogChannel *CreateInstance();
-
- lldb_private::ConstString GetPluginName() override;
-
- uint32_t GetPluginVersion() override;
-
- void Disable(const char **categories,
- lldb_private::Stream *feedback_strm) override;
-
- void Delete();
-
- bool Enable(lldb::StreamSP &log_stream_sp, uint32_t log_options,
- lldb_private::Stream
- *feedback_strm, // Feedback stream for argument errors etc
- const char **categories) override; // The categories to enable
- // within this logging stream,
- // if empty, enable default set
-
- void ListCategories(lldb_private::Stream *strm) override;
-
- static lldb_private::Log *GetLog();
-
- static lldb_private::Log *GetLogIfAll(uint32_t mask);
-
- static lldb_private::Log *GetLogIfAny(uint32_t mask);
-
- static void LogIf(uint32_t mask, const char *format, ...);
+ static Log *GetLogIfAll(uint32_t mask) { return g_channel.GetLogIfAll(mask); }
+ static Log *GetLogIfAny(uint32_t mask) { return g_channel.GetLogIfAny(mask); }
};
+}
#endif // SymbolFileDWARF_LogChannelDWARF_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
index c3d90d1..c97680e 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
@@ -8,11 +8,11 @@
//===----------------------------------------------------------------------===//
#include "NameToDIE.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
#include "DWARFCompileUnit.h"
#include "DWARFDebugInfo.h"
@@ -28,11 +28,11 @@ void NameToDIE::Finalize() {
}
void NameToDIE::Insert(const ConstString &name, const DIERef &die_ref) {
- m_map.Append(name.GetStringRef(), die_ref);
+ m_map.Append(name, die_ref);
}
size_t NameToDIE::Find(const ConstString &name, DIEArray &info_array) const {
- return m_map.GetValues(name.GetStringRef(), info_array);
+ return m_map.GetValues(name, info_array);
}
size_t NameToDIE::Find(const RegularExpression &regex,
@@ -55,15 +55,15 @@ size_t NameToDIE::FindAllEntriesForCompileUnit(dw_offset_t cu_offset,
void NameToDIE::Dump(Stream *s) {
const uint32_t size = m_map.GetSize();
for (uint32_t i = 0; i < size; ++i) {
- llvm::StringRef cstr = m_map.GetCStringAtIndex(i);
+ ConstString cstr = m_map.GetCStringAtIndex(i);
const DIERef &die_ref = m_map.GetValueAtIndexUnchecked(i);
- s->Printf("%p: {0x%8.8x/0x%8.8x} \"%s\"\n", (const void *)cstr.data(),
- die_ref.cu_offset, die_ref.die_offset, cstr.str().c_str());
+ s->Printf("%p: {0x%8.8x/0x%8.8x} \"%s\"\n", (const void *)cstr.GetCString(),
+ die_ref.cu_offset, die_ref.die_offset, cstr.GetCString());
}
}
void NameToDIE::ForEach(
- std::function<bool(llvm::StringRef name, const DIERef &die_ref)> const
+ std::function<bool(ConstString name, const DIERef &die_ref)> const
&callback) const {
const uint32_t size = m_map.GetSize();
for (uint32_t i = 0; i < size; ++i) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h
index e3fe321..bba44fd 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h
@@ -43,7 +43,8 @@ public:
DIEArray &info_array) const;
void
- ForEach(std::function<bool(llvm::StringRef name, const DIERef &die_ref)> const
+ ForEach(std::function<bool(lldb_private::ConstString name,
+ const DIERef &die_ref)> const
&callback) const;
protected:
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 5c44ee03..ef18c2b 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -11,19 +11,20 @@
// Other libraries and framework includes
#include "llvm/Support/Casting.h"
+#include "llvm/Support/Threading.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Core/Value.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
@@ -71,6 +72,8 @@
#include "SymbolFileDWARFDebugMap.h"
#include "SymbolFileDWARFDwo.h"
+#include "llvm/Support/FileSystem.h"
+
#include <map>
#include <ctype.h>
@@ -190,7 +193,9 @@ static const char *resolveCompDir(const char *path_from_dwarf) {
if (!is_symlink)
return local_path;
- if (!local_path_spec.IsSymbolicLink())
+ namespace fs = llvm::sys::fs;
+ if (fs::get_file_type(local_path_spec.GetPath(), false) !=
+ fs::file_type::symlink_file)
return local_path;
FileSpec resolved_local_path_spec;
@@ -222,7 +227,7 @@ void SymbolFileDWARF::DebuggerInitialize(Debugger &debugger) {
void SymbolFileDWARF::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
- LogChannelDWARF::Initialize();
+ LogChannelDWARF::Terminate();
}
lldb_private::ConstString SymbolFileDWARF::GetPluginNameStatic() {
@@ -553,8 +558,9 @@ uint32_t SymbolFileDWARF::CalculateAbilities() {
const DWARFDataExtractor &
SymbolFileDWARF::GetCachedSectionData(lldb::SectionType sect_type,
DWARFDataSegment &data_segment) {
- std::call_once(data_segment.m_flag, &SymbolFileDWARF::LoadSectionData, this,
- sect_type, std::ref(data_segment.m_data));
+ llvm::call_once(data_segment.m_flag, [this, sect_type, &data_segment] {
+ this->LoadSectionData(sect_type, std::ref(data_segment.m_data));
+ });
return data_segment.m_data;
}
@@ -660,8 +666,9 @@ const DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() const {
DWARFDebugInfo *SymbolFileDWARF::DebugInfo() {
if (m_info.get() == NULL) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s this = %p",
- LLVM_PRETTY_FUNCTION, static_cast<void *>(this));
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION,
+ static_cast<void *>(this));
if (get_debug_info_data().GetByteSize() > 0) {
m_info.reset(new DWARFDebugInfo());
if (m_info.get()) {
@@ -697,8 +704,9 @@ SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) {
DWARFDebugRanges *SymbolFileDWARF::DebugRanges() {
if (m_ranges.get() == NULL) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s this = %p",
- LLVM_PRETTY_FUNCTION, static_cast<void *>(this));
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION,
+ static_cast<void *>(this));
if (get_debug_ranges_data().GetByteSize() > 0) {
m_ranges.reset(new DWARFDebugRanges());
if (m_ranges.get())
@@ -1593,7 +1601,7 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() {
dwo_module_spec.GetArchitecture() =
m_obj_file->GetModule()->GetArchitecture();
// printf ("Loading dwo = '%s'\n", dwo_path);
- Error error = ModuleList::GetSharedModule(
+ Status error = ModuleList::GetSharedModule(
dwo_module_spec, module_sp, NULL, NULL, NULL);
if (!module_sp) {
GetObjectFile()->GetModule()->ReportWarning(
@@ -1631,7 +1639,7 @@ SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() {
if (var_sp && !var_sp->GetLocationIsConstantValueData()) {
const DWARFExpression &location = var_sp->LocationExpression();
Value location_result;
- Error error;
+ Status error;
if (location.Evaluate(nullptr, nullptr, nullptr,
LLDB_INVALID_ADDRESS, nullptr, nullptr,
location_result, &error)) {
@@ -1660,10 +1668,12 @@ SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() {
uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr,
uint32_t resolve_scope,
SymbolContext &sc) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "SymbolFileDWARF::"
- "ResolveSymbolContext (so_addr = { "
- "section = %p, offset = 0x%" PRIx64
- " }, resolve_scope = 0x%8.8x)",
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
+ "SymbolFileDWARF::"
+ "ResolveSymbolContext (so_addr = { "
+ "section = %p, offset = 0x%" PRIx64
+ " }, resolve_scope = 0x%8.8x)",
static_cast<void *>(so_addr.GetSection().get()),
so_addr.GetOffset(), resolve_scope);
uint32_t resolved = 0;
@@ -1911,12 +1921,19 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec,
return sc_list.GetSize() - prev_size;
}
+void SymbolFileDWARF::PreloadSymbols() {
+ std::lock_guard<std::recursive_mutex> guard(
+ GetObjectFile()->GetModule()->GetMutex());
+ Index();
+}
+
void SymbolFileDWARF::Index() {
if (m_indexed)
return;
m_indexed = true;
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
- LLVM_PRETTY_FUNCTION, "SymbolFileDWARF::Index (%s)",
+ func_cat, "SymbolFileDWARF::Index (%s)",
GetObjectFile()->GetFileSpec().GetFilename().AsCString("<Unknown>"));
DWARFDebugInfo *debug_info = DebugInfo();
@@ -1934,12 +1951,14 @@ void SymbolFileDWARF::Index() {
std::vector<NameToDIE> type_index(num_compile_units);
std::vector<NameToDIE> namespace_index(num_compile_units);
- std::vector<bool> clear_cu_dies(num_compile_units, false);
- auto parser_fn = [this, debug_info, &function_basename_index,
+ // std::vector<bool> might be implemented using bit test-and-set, so use
+ // uint8_t instead.
+ std::vector<uint8_t> clear_cu_dies(num_compile_units, false);
+ auto parser_fn = [debug_info, &function_basename_index,
&function_fullname_index, &function_method_index,
&function_selector_index, &objc_class_selectors_index,
&global_index, &type_index,
- &namespace_index](uint32_t cu_idx) {
+ &namespace_index](size_t cu_idx) {
DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
if (dwarf_cu) {
dwarf_cu->Index(
@@ -1948,25 +1967,20 @@ void SymbolFileDWARF::Index() {
objc_class_selectors_index[cu_idx], global_index[cu_idx],
type_index[cu_idx], namespace_index[cu_idx]);
}
- return cu_idx;
};
- auto extract_fn = [this, debug_info, num_compile_units](uint32_t cu_idx) {
+ auto extract_fn = [debug_info, &clear_cu_dies](size_t cu_idx) {
DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
if (dwarf_cu) {
// dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the
// DIEs for a compile unit have already been parsed.
- return std::make_pair(cu_idx, dwarf_cu->ExtractDIEsIfNeeded(false) > 1);
+ if (dwarf_cu->ExtractDIEsIfNeeded(false) > 1)
+ clear_cu_dies[cu_idx] = true;
}
- return std::make_pair(cu_idx, false);
};
// Create a task runner that extracts dies for each DWARF compile unit in a
// separate thread
- TaskRunner<std::pair<uint32_t, bool>> task_runner_extract;
- for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
- task_runner_extract.AddTask(extract_fn, cu_idx);
-
//----------------------------------------------------------------------
// First figure out which compile units didn't have their DIEs already
// parsed and remember this. If no DIEs were parsed prior to this index
@@ -1976,48 +1990,37 @@ void SymbolFileDWARF::Index() {
// a DIE in one compile unit refers to another and the indexes accesses
// those DIEs.
//----------------------------------------------------------------------
- while (true) {
- auto f = task_runner_extract.WaitForNextCompletedTask();
- if (!f.valid())
- break;
- unsigned cu_idx;
- bool clear;
- std::tie(cu_idx, clear) = f.get();
- clear_cu_dies[cu_idx] = clear;
- }
+ TaskMapOverInt(0, num_compile_units, extract_fn);
// Now create a task runner that can index each DWARF compile unit in a
// separate
// thread so we can index quickly.
- TaskRunner<uint32_t> task_runner;
- for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
- task_runner.AddTask(parser_fn, cu_idx);
+ TaskMapOverInt(0, num_compile_units, parser_fn);
- while (true) {
- std::future<uint32_t> f = task_runner.WaitForNextCompletedTask();
- if (!f.valid())
- break;
- uint32_t cu_idx = f.get();
-
- m_function_basename_index.Append(function_basename_index[cu_idx]);
- m_function_fullname_index.Append(function_fullname_index[cu_idx]);
- m_function_method_index.Append(function_method_index[cu_idx]);
- m_function_selector_index.Append(function_selector_index[cu_idx]);
- m_objc_class_selectors_index.Append(objc_class_selectors_index[cu_idx]);
- m_global_index.Append(global_index[cu_idx]);
- m_type_index.Append(type_index[cu_idx]);
- m_namespace_index.Append(namespace_index[cu_idx]);
- }
+ auto finalize_fn = [](NameToDIE &index, std::vector<NameToDIE> &srcs) {
+ for (auto &src : srcs)
+ index.Append(src);
+ index.Finalize();
+ };
- TaskPool::RunTasks([&]() { m_function_basename_index.Finalize(); },
- [&]() { m_function_fullname_index.Finalize(); },
- [&]() { m_function_method_index.Finalize(); },
- [&]() { m_function_selector_index.Finalize(); },
- [&]() { m_objc_class_selectors_index.Finalize(); },
- [&]() { m_global_index.Finalize(); },
- [&]() { m_type_index.Finalize(); },
- [&]() { m_namespace_index.Finalize(); });
+ TaskPool::RunTasks(
+ [&]() {
+ finalize_fn(m_function_basename_index, function_basename_index);
+ },
+ [&]() {
+ finalize_fn(m_function_fullname_index, function_fullname_index);
+ },
+ [&]() { finalize_fn(m_function_method_index, function_method_index); },
+ [&]() {
+ finalize_fn(m_function_selector_index, function_selector_index);
+ },
+ [&]() {
+ finalize_fn(m_objc_class_selectors_index, objc_class_selectors_index);
+ },
+ [&]() { finalize_fn(m_global_index, global_index); },
+ [&]() { finalize_fn(m_type_index, type_index); },
+ [&]() { finalize_fn(m_namespace_index, namespace_index); });
//----------------------------------------------------------------------
// Keep memory down by clearing DIEs for any compile units if indexing
@@ -2391,8 +2394,8 @@ SymbolFileDWARF::FindFunctions(const ConstString &name,
const CompilerDeclContext *parent_decl_ctx,
uint32_t name_type_mask, bool include_inlines,
bool append, SymbolContextList &sc_list) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
- "SymbolFileDWARF::FindFunctions (name = '%s')",
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "SymbolFileDWARF::FindFunctions (name = '%s')",
name.AsCString());
// eFunctionNameTypeAuto should be pre-resolved by a call to
@@ -2671,8 +2674,8 @@ SymbolFileDWARF::FindFunctions(const ConstString &name,
uint32_t SymbolFileDWARF::FindFunctions(const RegularExpression &regex,
bool include_inlines, bool append,
SymbolContextList &sc_list) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
- "SymbolFileDWARF::FindFunctions (regex = '%s')",
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "SymbolFileDWARF::FindFunctions (regex = '%s')",
regex.GetText().str().c_str());
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
@@ -3045,7 +3048,13 @@ SymbolFileDWARF::GetDeclContextDIEContainingDIE(const DWARFDIE &orig_die) {
case DW_TAG_lexical_block:
case DW_TAG_subprogram:
return die;
-
+ case DW_TAG_inlined_subroutine: {
+ DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin);
+ if (abs_die) {
+ return abs_die;
+ }
+ break;
+ }
default:
break;
}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 5293769..9b1eb1d 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -21,9 +21,10 @@
// Other libraries and framework includes
#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Threading.h"
+
+#include "lldb/Utility/Flags.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Flags.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Core/dwarf.h"
@@ -31,6 +32,7 @@
#include "lldb/Symbol/DebugMacros.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
// Project includes
@@ -224,6 +226,8 @@ public:
const lldb_private::ConstString &name,
const lldb_private::CompilerDeclContext *parent_decl_ctx) override;
+ void PreloadSymbols() override;
+
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
@@ -305,7 +309,7 @@ protected:
typedef llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> ClangTypeToDIE;
struct DWARFDataSegment {
- std::once_flag m_flag;
+ llvm::once_flag m_flag;
lldb_private::DWARFDataExtractor m_data;
};
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index 16bb578..eabff86 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -19,15 +19,15 @@
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RangeMap.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Section.h"
#include "lldb/Host/FileSystem.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Timer.h"
//#define DEBUG_OSO_DMAP // DO NOT CHECKIN WITH THIS NOT COMMENTED OUT
#if defined(DEBUG_OSO_DMAP)
#include "lldb/Core/StreamFile.h"
#endif
-#include "lldb/Core/Timer.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
@@ -991,7 +991,8 @@ uint32_t SymbolFileDWARFDebugMap::FindFunctions(
const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
uint32_t name_type_mask, bool include_inlines, bool append,
SymbolContextList &sc_list) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"SymbolFileDWARFDebugMap::FindFunctions (name = %s)",
name.GetCString());
@@ -1018,7 +1019,8 @@ uint32_t SymbolFileDWARFDebugMap::FindFunctions(const RegularExpression &regex,
bool include_inlines,
bool append,
SymbolContextList &sc_list) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')",
regex.GetText().str().c_str());
@@ -1044,7 +1046,8 @@ uint32_t SymbolFileDWARFDebugMap::FindFunctions(const RegularExpression &regex,
size_t SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope,
uint32_t type_mask,
TypeList &type_list) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"SymbolFileDWARFDebugMap::GetTypes (type_mask = 0x%8.8x)",
type_mask);
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index 109da63..dcca426 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -11,6 +11,7 @@
#define SymbolFileDWARF_SymbolFileDWARFDebugMap_h_
#include <bitset>
+#include <map>
#include <vector>
#include "lldb/Core/RangeMap.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index cd99493..5e71322 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -125,9 +125,8 @@ uint32_t SymbolFilePDB::GetNumCompileUnits() {
m_cached_compile_unit_count = compilands->getChildCount();
// The linker can inject an additional "dummy" compilation unit into the
- // PDB.
- // Ignore this special compile unit for our purposes, if it is there. It is
- // always the last one.
+ // PDB. Ignore this special compile unit for our purposes, if it is there.
+ // It is always the last one.
auto last_cu = compilands->getChildAtIndex(m_cached_compile_unit_count - 1);
std::string name = last_cu->getName();
if (name == "* Linker *")
@@ -187,12 +186,10 @@ bool SymbolFilePDB::ParseCompileUnitSupportFiles(
return false;
// In theory this is unnecessary work for us, because all of this information
- // is easily
- // (and quickly) accessible from DebugInfoPDB, so caching it a second time
- // seems like a waste.
- // Unfortunately, there's no good way around this short of a moderate
- // refactor, since SymbolVendor
- // depends on being able to cache this list.
+ // is easily (and quickly) accessible from DebugInfoPDB, so caching it a
+ // second time seems like a waste. Unfortunately, there's no good way around
+ // this short of a moderate refactor since SymbolVendor depends on being able
+ // to cache this list.
auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(
sc.comp_unit->GetID());
if (!cu)
@@ -269,9 +266,8 @@ lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) {
lldb_private::CompilerDeclContext
SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) {
// PDB always uses the translation unit decl context for everything. We can
- // improve this later
- // but it's not easy because PDB doesn't provide a high enough level of type
- // fidelity in this area.
+ // improve this later but it's not easy because PDB doesn't provide a high
+ // enough level of type fidelity in this area.
return *m_tu_decl_ctx_up;
}
@@ -295,30 +291,25 @@ uint32_t SymbolFilePDB::ResolveSymbolContext(
uint32_t resolve_scope, lldb_private::SymbolContextList &sc_list) {
if (resolve_scope & lldb::eSymbolContextCompUnit) {
// Locate all compilation units with line numbers referencing the specified
- // file. For example, if
- // `file_spec` is <vector>, then this should return all source files and
- // header files that reference
- // <vector>, either directly or indirectly.
+ // file. For example, if `file_spec` is <vector>, then this should return
+ // all source files and header files that reference <vector>, either
+ // directly or indirectly.
auto compilands = m_session_up->findCompilandsForSourceFile(
file_spec.GetPath(), PDB_NameSearchFlags::NS_CaseInsensitive);
- // For each one, either find get its previously parsed data, or parse it
- // afresh and add it to
- // the symbol context list.
+ // For each one, either find its previously parsed data or parse it afresh
+ // and add it to the symbol context list.
while (auto compiland = compilands->getNext()) {
// If we're not checking inlines, then don't add line information for this
- // file unless the FileSpec
- // matches.
+ // file unless the FileSpec matches.
if (!check_inlines) {
// `getSourceFileName` returns the basename of the original source file
- // used to generate this compiland.
- // It does not return the full path. Currently the only way to get that
- // is to do a basename lookup to
- // get the IPDBSourceFile, but this is ambiguous in the case of two
- // source files with the same name
- // contributing to the same compiland. This is a moderately extreme
- // edge case, so we consider this ok
- // for now, although we need to find a long term solution.
+ // used to generate this compiland. It does not return the full path.
+ // Currently the only way to get that is to do a basename lookup to get
+ // the IPDBSourceFile, but this is ambiguous in the case of two source
+ // files with the same name contributing to the same compiland. This is
+ // a moderately extreme edge case, so we consider this OK for now,
+ // although we need to find a long-term solution.
std::string source_file = compiland->getSourceFileName();
auto pdb_file = m_session_up->findOneSourceFile(
compiland.get(), source_file,
@@ -336,8 +327,7 @@ uint32_t SymbolFilePDB::ResolveSymbolContext(
sc_list.Append(sc);
// If we were asked to resolve line entries, add all entries to the line
- // table that match the requested
- // line (or all lines if `line` == 0)
+ // table that match the requested line (or all lines if `line` == 0).
if (resolve_scope & lldb::eSymbolContextLineEntry)
ParseCompileUnitLineTable(sc, line);
}
@@ -396,9 +386,8 @@ uint32_t SymbolFilePDB::FindTypes(
std::string name_str = name.AsCString();
// If this might be a regex, we have to return EVERY symbol and process them
- // one by one, which is going
- // to destroy performance on large PDB files. So try really hard not to use a
- // regex match.
+ // one by one, which is going to destroy performance on large PDB files. So
+ // try really hard not to use a regex match.
if (name_str.find_first_of("[]?*.-+\\") != std::string::npos)
FindTypesByRegex(name_str, max_matches, types);
else
@@ -410,14 +399,11 @@ void SymbolFilePDB::FindTypesByRegex(const std::string &regex,
uint32_t max_matches,
lldb_private::TypeMap &types) {
// When searching by regex, we need to go out of our way to limit the search
- // space as much as possible, since
- // the way this is implemented is by searching EVERYTHING in the PDB and
- // manually doing a regex compare. PDB
- // library isn't optimized for regex searches or searches across multiple
- // symbol types at the same time, so the
+ // space as much as possible since this searches EVERYTHING in the PDB,
+ // manually doing regex comparisons. PDB library isn't optimized for regex
+ // searches or searches across multiple symbol types at the same time, so the
// best we can do is to search enums, then typedefs, then classes one by one,
- // and do a regex compare against all
- // of them.
+ // and do a regex comparison against each of them.
PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef,
PDB_SymType::UDT};
auto global = m_session_up->getGlobalScope();
@@ -442,9 +428,8 @@ void SymbolFilePDB::FindTypesByRegex(const std::string &regex,
else if (auto class_type = llvm::dyn_cast<PDBSymbolTypeUDT>(result.get()))
type_name = class_type->getName();
else {
- // We're only looking for types that have names. Skip symbols, as well
- // as
- // unnamed types such as arrays, pointers, etc.
+ // We're looking only for types that have names. Skip symbols, as well
+ // as unnamed types such as arrays, pointers, etc.
continue;
}
@@ -484,7 +469,7 @@ void SymbolFilePDB::FindTypesByName(const std::string &name,
case PDB_SymType::Typedef:
break;
default:
- // We're only looking for types that have names. Skip symbols, as well as
+ // We're looking only for types that have names. Skip symbols, as well as
// unnamed types such as arrays, pointers, etc.
continue;
}
@@ -553,14 +538,12 @@ lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitForSymIndex(uint32_t id) {
auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(id);
// `getSourceFileName` returns the basename of the original source file used
- // to generate this compiland. It does
- // not return the full path. Currently the only way to get that is to do a
- // basename lookup to get the
+ // to generate this compiland. It does not return the full path. Currently
+ // the only way to get that is to do a basename lookup to get the
// IPDBSourceFile, but this is ambiguous in the case of two source files with
- // the same name contributing to the
- // same compiland. This is a moderately extreme edge case, so we consider this
- // ok for now, although we need to find
- // a long term solution.
+ // the same name contributing to the same compiland. This is a moderately
+ // extreme edge case, so we consider this OK for now, although we need to find
+ // a long-term solution.
auto file =
m_session_up->findOneSourceFile(cu.get(), cu->getSourceFileName(),
PDB_NameSearchFlags::NS_CaseInsensitive);
@@ -589,12 +572,9 @@ bool SymbolFilePDB::ParseCompileUnitLineTable(
sc.comp_unit->GetID());
// LineEntry needs the *index* of the file into the list of support files
- // returned by
- // ParseCompileUnitSupportFiles. But the underlying SDK gives us a globally
- // unique
- // idenfitifier in the namespace of the PDB. So, we have to do a mapping so
- // that we
- // can hand out indices.
+ // returned by ParseCompileUnitSupportFiles. But the underlying SDK gives us
+ // a globally unique idenfitifier in the namespace of the PDB. So, we have to
+ // do a mapping so that we can hand out indices.
llvm::DenseMap<uint32_t, uint32_t> index_map;
BuildSupportFileIdToSupportFileIndexMap(*cu, index_map);
auto line_table = llvm::make_unique<LineTable>(sc.comp_unit);
@@ -604,8 +584,7 @@ bool SymbolFilePDB::ParseCompileUnitLineTable(
auto files = m_session_up->getSourceFilesForCompiland(*cu);
// For each source and header file, create a LineSequence for contributions to
- // the cu
- // from that file, and add the sequence.
+ // the cu from that file, and add the sequence.
while (auto file = files->getNext()) {
std::unique_ptr<LineSequence> sequence(
line_table->CreateLineSequenceContainer());
@@ -628,13 +607,12 @@ bool SymbolFilePDB::ParseCompileUnitLineTable(
uint32_t source_idx = index_map[source_id];
// There was a gap between the current entry and the previous entry if the
- // addresses don't perfectly line
- // up.
+ // addresses don't perfectly line up.
bool is_gap = (i > 0) && (prev_addr + prev_length < addr);
// Before inserting the current entry, insert a terminal entry at the end
- // of the previous entry's address
- // range if the current entry resulted in a gap from the previous entry.
+ // of the previous entry's address range if the current entry resulted in
+ // a gap from the previous entry.
if (is_gap && ShouldAddLine(match_line, prev_line, prev_length)) {
line_table->AppendLineEntryToSequence(
sequence.get(), prev_addr + prev_length, prev_line, 0,
@@ -684,14 +662,10 @@ void SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap(
const PDBSymbolCompiland &cu,
llvm::DenseMap<uint32_t, uint32_t> &index_map) const {
// This is a hack, but we need to convert the source id into an index into the
- // support
- // files array. We don't want to do path comparisons to avoid basename / full
- // path
- // issues that may or may not even be a problem, so we use the globally unique
- // source
- // file identifiers. Ideally we could use the global identifiers everywhere,
- // but LineEntry
- // currently assumes indices.
+ // support files array. We don't want to do path comparisons to avoid
+ // basename / full path issues that may or may not even be a problem, so we
+ // use the globally unique source file identifiers. Ideally we could use the
+ // global identifiers everywhere, but LineEntry currently assumes indices.
auto source_files = m_session_up->getSourceFilesForCompiland(cu);
int index = 0;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
index 2e59183..efd2cb0 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -10,8 +10,8 @@
#ifndef lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_
#define lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_
-#include "lldb/Core/UserID.h"
#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Utility/UserID.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
index 3907399..dbc1b9e 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -10,16 +10,15 @@
#include "SymbolFileSymtab.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Symtab.h"
#include "lldb/Symbol/TypeList.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
index 1945af9..d1887a7 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
@@ -12,6 +12,7 @@
// C Includes
// C++ Includes
+#include <map>
#include <vector>
// Other libraries and framework includes
diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
index 4934a80..f952696 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
@@ -15,11 +15,11 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
@@ -92,8 +92,8 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp,
if (file_spec_list.IsEmpty())
return NULL;
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
- "SymbolVendorELF::CreateInstance (module = %s)",
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "SymbolVendorELF::CreateInstance (module = %s)",
module_sp->GetFileSpec().GetPath().c_str());
for (size_t idx = 0; idx < file_spec_list.GetSize(); ++idx) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index be770a3..3976f40 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -11,18 +11,19 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Error.h"
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/FormatEntity.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -36,7 +37,7 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
std::vector<uint8_t> function_text(range.GetByteSize());
ProcessSP process_sp(thread.GetProcess());
if (process_sp) {
- Error error;
+ Status error;
const bool prefer_file_cache = true;
if (process_sp->GetTarget().ReadMemory(
range.GetBaseAddress(), prefer_file_cache, function_text.data(),
@@ -408,7 +409,8 @@ size_t UnwindAssemblyInstEmulation::WriteMemory(
StreamString strm;
strm.PutCString("UnwindAssemblyInstEmulation::WriteMemory (");
- data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0);
+ DumpDataExtractor(data, &strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX,
+ addr, 0, 0);
strm.PutCString(", context = ");
context.Dump(strm, instruction);
log->PutString(strm.GetString());
diff --git a/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index e298b85..c171f0f 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -16,17 +16,17 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/RegisterNumber.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/UnwindAssembly.h"
-#include "lldb/Utility/RegisterNumber.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -54,7 +54,7 @@ bool UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly(
return false;
const bool prefer_file_cache = true;
std::vector<uint8_t> function_text(func.GetByteSize());
- Error error;
+ Status error;
if (process_sp->GetTarget().ReadMemory(
func.GetBaseAddress(), prefer_file_cache, function_text.data(),
func.GetByteSize(), error) == func.GetByteSize()) {
@@ -161,7 +161,7 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite(
return false;
const bool prefer_file_cache = true;
std::vector<uint8_t> function_text(func.GetByteSize());
- Error error;
+ Status error;
if (process_sp->GetTarget().ReadMemory(
func.GetBaseAddress(), prefer_file_cache, function_text.data(),
func.GetByteSize(), error) == func.GetByteSize()) {
@@ -192,7 +192,7 @@ bool UnwindAssembly_x86::GetFastUnwindPlan(AddressRange &func, Thread &thread,
if (process_sp) {
Target &target(process_sp->GetTarget());
const bool prefer_file_cache = true;
- Error error;
+ Status error;
if (target.ReadMemory(func.GetBaseAddress(), prefer_file_cache,
opcode_data.data(), 4, error) == 4) {
uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5};
@@ -228,7 +228,7 @@ bool UnwindAssembly_x86::FirstNonPrologueInsn(
const bool prefer_file_cache = true;
std::vector<uint8_t> function_text(func.GetByteSize());
- Error error;
+ Status error;
if (target->ReadMemory(func.GetBaseAddress(), prefer_file_cache,
function_text.data(), func.GetByteSize(),
error) == func.GetByteSize()) {
diff --git a/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
index e731a5a..aa15063 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -452,6 +452,33 @@ bool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) {
return false;
}
+// lea -0x28(%ebp), %esp
+// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
+bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) {
+ uint8_t *p = m_cur_insn;
+ if (m_wordsize == 8 && *p == 0x48)
+ p++;
+
+ // Check opcode
+ if (*p != 0x8d)
+ return false;
+ ++p;
+
+ // 8 bit displacement
+ if (*p == 0x65) {
+ amount = (int8_t)p[1];
+ return true;
+ }
+
+ // 32 bit displacement
+ if (*p == 0xa5) {
+ amount = (int32_t)extract_4(p + 1);
+ return true;
+ }
+
+ return false;
+}
+
// popq %rbx
// popl %ebx
bool x86AssemblyInspectionEngine::pop_reg_p(int &regno) {
@@ -577,9 +604,10 @@ uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) {
}
bool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p,
- int &length) {
+ int &length,
+ uint32_t buffer_remaining_bytes) {
- const uint32_t max_op_byte_size = m_arch.GetMaximumOpcodeByteSize();
+ uint32_t max_op_byte_size = std::min(buffer_remaining_bytes, m_arch.GetMaximumOpcodeByteSize());
llvm::SmallVector<uint8_t, 32> opcode_data;
opcode_data.resize(max_op_byte_size);
@@ -671,8 +699,9 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
bool row_updated = false; // The UnwindPlan::Row 'row' has been updated
m_cur_insn = data + current_func_text_offset;
- if (!instruction_length(m_cur_insn, insn_len) || insn_len == 0 ||
- insn_len > kMaxInstructionByteSize) {
+ if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset)
+ || insn_len == 0
+ || insn_len > kMaxInstructionByteSize) {
// An unrecognized/junk instruction
break;
}
@@ -843,6 +872,12 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
in_epilogue = true;
}
+ else if (lea_rbp_rsp_pattern_p(stack_offset) &&
+ row->GetCFAValue().GetRegisterNumber() == m_lldb_fp_regnum) {
+ current_sp_bytes_offset_from_cfa =
+ row->GetCFAValue().GetOffset() - stack_offset;
+ }
+
else if (ret_pattern_p() && prologue_completed_row.get()) {
// Reinstate the saved prologue setup for any instructions
// that come after the ret instruction
@@ -969,8 +1004,9 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite(
while (offset < size) {
m_cur_insn = data + offset;
int insn_len;
- if (!instruction_length(m_cur_insn, insn_len) || insn_len == 0 ||
- insn_len > kMaxInstructionByteSize) {
+ if (!instruction_length(m_cur_insn, insn_len, size - offset)
+ || insn_len == 0
+ || insn_len > kMaxInstructionByteSize) {
// An unrecognized/junk instruction.
break;
}
@@ -979,11 +1015,12 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite(
offset += insn_len;
m_cur_insn = data + offset;
- if (reinstate_unwind_state) {
- // that was the last instruction of this function
- if (offset >= size)
- continue;
+ // offset is pointing beyond the bounds of the
+ // function; stop looping.
+ if (offset >= size)
+ continue;
+ if (reinstate_unwind_state) {
UnwindPlan::RowSP new_row(new UnwindPlan::Row());
*new_row = *original_last_row;
new_row->SetOffset(offset);
@@ -1180,8 +1217,9 @@ bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction(
int scratch;
m_cur_insn = data + offset;
- if (!instruction_length(m_cur_insn, insn_len) ||
- insn_len > kMaxInstructionByteSize || insn_len == 0) {
+ if (!instruction_length(m_cur_insn, insn_len, size - offset)
+ || insn_len > kMaxInstructionByteSize
+ || insn_len == 0) {
// An error parsing the instruction, i.e. probably data/garbage - stop
// scanning
break;
diff --git a/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h b/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
index 0294f5a..97441d3 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
+++ b/contrib/llvm/tools/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
@@ -17,7 +17,7 @@
#include "lldb/lldb-private.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
#include <map>
#include <vector>
@@ -102,6 +102,7 @@ private:
bool sub_rsp_pattern_p(int &amount);
bool add_rsp_pattern_p(int &amount);
bool lea_rsp_pattern_p(int &amount);
+ bool lea_rbp_rsp_pattern_p(int &amount);
bool push_reg_p(int &regno);
bool pop_reg_p(int &regno);
bool pop_rbp_pattern_p();
@@ -112,7 +113,7 @@ private:
bool ret_pattern_p();
uint32_t extract_4(uint8_t *b);
- bool instruction_length(uint8_t *insn, int &length);
+ bool instruction_length(uint8_t *insn, int &length, uint32_t buffer_remaining_bytes);
bool machine_regno_to_lldb_regno(int machine_regno, uint32_t &lldb_regno);
diff --git a/contrib/llvm/tools/lldb/source/Symbol/ArmUnwindInfo.cpp b/contrib/llvm/tools/lldb/source/Symbol/ArmUnwindInfo.cpp
index 1995149..742c057 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/ArmUnwindInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/ArmUnwindInfo.cpp
@@ -12,10 +12,10 @@
#include "Utility/ARM_DWARF_Registers.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ArmUnwindInfo.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Utility/Endian.h"
/*
* Unwind information reader and parser for the ARM exception handling ABI
diff --git a/contrib/llvm/tools/lldb/source/Symbol/Block.cpp b/contrib/llvm/tools/lldb/source/Symbol/Block.cpp
index 6c4c28d..648d8ee 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/Block.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/Block.cpp
@@ -9,13 +9,13 @@
#include "lldb/Symbol/Block.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp b/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp
index c0d9745..608ff0a 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp
@@ -14,7 +14,7 @@
// C Includes
// C++ Includes
-#include <mutex> // std::once
+#include <mutex>
#include <string>
#include <vector>
@@ -65,16 +65,17 @@
#endif
#include "llvm/Support/Signals.h"
+#include "llvm/Support/Threading.h"
#include "Plugins/ExpressionParser/Clang/ClangFunctionCaller.h"
#include "Plugins/ExpressionParser/Clang/ClangUserExpression.h"
#include "Plugins/ExpressionParser/Clang/ClangUtilityFunction.h"
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Flags.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Flags.h"
+
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ThreadSafeDenseMap.h"
@@ -92,7 +93,10 @@
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h"
//#include "Plugins/SymbolFile/PDB/PDBASTParser.h"
@@ -127,8 +131,8 @@ typedef lldb_private::ThreadSafeDenseMap<clang::ASTContext *, ClangASTContext *>
static ClangASTMap &GetASTMap() {
static ClangASTMap *g_map_ptr = nullptr;
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
g_map_ptr = new ClangASTMap(); // leaked on purpose to avoid spins
});
return *g_map_ptr;
@@ -374,10 +378,9 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) {
// Set some properties which depend solely on the input kind; it would be nice
// to move these to the language standard, and have the driver resolve the
// input kind + language standard.
- if (IK == IK_Asm) {
+ if (IK.getLanguage() == InputKind::Asm) {
Opts.AsmPreprocessor = 1;
- } else if (IK == IK_ObjC || IK == IK_ObjCXX || IK == IK_PreprocessedObjC ||
- IK == IK_PreprocessedObjCXX) {
+ } else if (IK.isObjectiveC()) {
Opts.ObjC1 = Opts.ObjC2 = 1;
}
@@ -385,30 +388,24 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) {
if (LangStd == LangStandard::lang_unspecified) {
// Based on the base language, pick one.
- switch (IK) {
- case IK_None:
- case IK_AST:
- case IK_LLVM_IR:
- case IK_RenderScript:
+ switch (IK.getLanguage()) {
+ case InputKind::Unknown:
+ case InputKind::LLVM_IR:
+ case InputKind::RenderScript:
llvm_unreachable("Invalid input kind!");
- case IK_OpenCL:
- LangStd = LangStandard::lang_opencl;
+ case InputKind::OpenCL:
+ LangStd = LangStandard::lang_opencl10;
break;
- case IK_CUDA:
- case IK_PreprocessedCuda:
+ case InputKind::CUDA:
LangStd = LangStandard::lang_cuda;
break;
- case IK_Asm:
- case IK_C:
- case IK_PreprocessedC:
- case IK_ObjC:
- case IK_PreprocessedObjC:
+ case InputKind::Asm:
+ case InputKind::C:
+ case InputKind::ObjC:
LangStd = LangStandard::lang_gnu99;
break;
- case IK_CXX:
- case IK_PreprocessedCXX:
- case IK_ObjCXX:
- case IK_PreprocessedObjCXX:
+ case InputKind::CXX:
+ case InputKind::ObjCXX:
LangStd = LangStandard::lang_gnucxx98;
break;
}
@@ -428,7 +425,7 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) {
Opts.WChar = true;
// OpenCL has some additional defaults.
- if (LangStd == LangStandard::lang_opencl) {
+ if (LangStd == LangStandard::lang_opencl10) {
Opts.OpenCL = 1;
Opts.AltiVec = 1;
Opts.CXXOperatorNames = 1;
@@ -780,8 +777,8 @@ IdentifierTable *ClangASTContext::getIdentifierTable() {
LangOptions *ClangASTContext::getLanguageOptions() {
if (m_language_options_ap.get() == nullptr) {
m_language_options_ap.reset(new LangOptions());
- ParseLangArgs(*m_language_options_ap, IK_ObjCXX, GetTargetTriple());
- // InitializeLangOptions(*m_language_options_ap, IK_ObjCXX);
+ ParseLangArgs(*m_language_options_ap, InputKind::ObjCXX, GetTargetTriple());
+ // InitializeLangOptions(*m_language_options_ap, InputKind::ObjCXX);
}
return m_language_options_ap.get();
}
@@ -954,78 +951,63 @@ ClangASTContext::GetBasicTypeEnumeration(const ConstString &name) {
if (name) {
typedef UniqueCStringMap<lldb::BasicType> TypeNameToBasicTypeMap;
static TypeNameToBasicTypeMap g_type_map;
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
// "void"
- g_type_map.Append(ConstString("void").GetStringRef(), eBasicTypeVoid);
+ g_type_map.Append(ConstString("void"), eBasicTypeVoid);
// "char"
- g_type_map.Append(ConstString("char").GetStringRef(), eBasicTypeChar);
- g_type_map.Append(ConstString("signed char").GetStringRef(),
- eBasicTypeSignedChar);
- g_type_map.Append(ConstString("unsigned char").GetStringRef(),
- eBasicTypeUnsignedChar);
- g_type_map.Append(ConstString("wchar_t").GetStringRef(), eBasicTypeWChar);
- g_type_map.Append(ConstString("signed wchar_t").GetStringRef(),
- eBasicTypeSignedWChar);
- g_type_map.Append(ConstString("unsigned wchar_t").GetStringRef(),
+ g_type_map.Append(ConstString("char"), eBasicTypeChar);
+ g_type_map.Append(ConstString("signed char"), eBasicTypeSignedChar);
+ g_type_map.Append(ConstString("unsigned char"), eBasicTypeUnsignedChar);
+ g_type_map.Append(ConstString("wchar_t"), eBasicTypeWChar);
+ g_type_map.Append(ConstString("signed wchar_t"), eBasicTypeSignedWChar);
+ g_type_map.Append(ConstString("unsigned wchar_t"),
eBasicTypeUnsignedWChar);
// "short"
- g_type_map.Append(ConstString("short").GetStringRef(), eBasicTypeShort);
- g_type_map.Append(ConstString("short int").GetStringRef(),
- eBasicTypeShort);
- g_type_map.Append(ConstString("unsigned short").GetStringRef(),
- eBasicTypeUnsignedShort);
- g_type_map.Append(ConstString("unsigned short int").GetStringRef(),
+ g_type_map.Append(ConstString("short"), eBasicTypeShort);
+ g_type_map.Append(ConstString("short int"), eBasicTypeShort);
+ g_type_map.Append(ConstString("unsigned short"), eBasicTypeUnsignedShort);
+ g_type_map.Append(ConstString("unsigned short int"),
eBasicTypeUnsignedShort);
// "int"
- g_type_map.Append(ConstString("int").GetStringRef(), eBasicTypeInt);
- g_type_map.Append(ConstString("signed int").GetStringRef(),
- eBasicTypeInt);
- g_type_map.Append(ConstString("unsigned int").GetStringRef(),
- eBasicTypeUnsignedInt);
- g_type_map.Append(ConstString("unsigned").GetStringRef(),
- eBasicTypeUnsignedInt);
+ g_type_map.Append(ConstString("int"), eBasicTypeInt);
+ g_type_map.Append(ConstString("signed int"), eBasicTypeInt);
+ g_type_map.Append(ConstString("unsigned int"), eBasicTypeUnsignedInt);
+ g_type_map.Append(ConstString("unsigned"), eBasicTypeUnsignedInt);
// "long"
- g_type_map.Append(ConstString("long").GetStringRef(), eBasicTypeLong);
- g_type_map.Append(ConstString("long int").GetStringRef(), eBasicTypeLong);
- g_type_map.Append(ConstString("unsigned long").GetStringRef(),
- eBasicTypeUnsignedLong);
- g_type_map.Append(ConstString("unsigned long int").GetStringRef(),
+ g_type_map.Append(ConstString("long"), eBasicTypeLong);
+ g_type_map.Append(ConstString("long int"), eBasicTypeLong);
+ g_type_map.Append(ConstString("unsigned long"), eBasicTypeUnsignedLong);
+ g_type_map.Append(ConstString("unsigned long int"),
eBasicTypeUnsignedLong);
// "long long"
- g_type_map.Append(ConstString("long long").GetStringRef(),
- eBasicTypeLongLong);
- g_type_map.Append(ConstString("long long int").GetStringRef(),
- eBasicTypeLongLong);
- g_type_map.Append(ConstString("unsigned long long").GetStringRef(),
+ g_type_map.Append(ConstString("long long"), eBasicTypeLongLong);
+ g_type_map.Append(ConstString("long long int"), eBasicTypeLongLong);
+ g_type_map.Append(ConstString("unsigned long long"),
eBasicTypeUnsignedLongLong);
- g_type_map.Append(ConstString("unsigned long long int").GetStringRef(),
+ g_type_map.Append(ConstString("unsigned long long int"),
eBasicTypeUnsignedLongLong);
// "int128"
- g_type_map.Append(ConstString("__int128_t").GetStringRef(),
- eBasicTypeInt128);
- g_type_map.Append(ConstString("__uint128_t").GetStringRef(),
- eBasicTypeUnsignedInt128);
+ g_type_map.Append(ConstString("__int128_t"), eBasicTypeInt128);
+ g_type_map.Append(ConstString("__uint128_t"), eBasicTypeUnsignedInt128);
// Miscellaneous
- g_type_map.Append(ConstString("bool").GetStringRef(), eBasicTypeBool);
- g_type_map.Append(ConstString("float").GetStringRef(), eBasicTypeFloat);
- g_type_map.Append(ConstString("double").GetStringRef(), eBasicTypeDouble);
- g_type_map.Append(ConstString("long double").GetStringRef(),
- eBasicTypeLongDouble);
- g_type_map.Append(ConstString("id").GetStringRef(), eBasicTypeObjCID);
- g_type_map.Append(ConstString("SEL").GetStringRef(), eBasicTypeObjCSel);
- g_type_map.Append(ConstString("nullptr").GetStringRef(),
- eBasicTypeNullPtr);
+ g_type_map.Append(ConstString("bool"), eBasicTypeBool);
+ g_type_map.Append(ConstString("float"), eBasicTypeFloat);
+ g_type_map.Append(ConstString("double"), eBasicTypeDouble);
+ g_type_map.Append(ConstString("long double"), eBasicTypeLongDouble);
+ g_type_map.Append(ConstString("id"), eBasicTypeObjCID);
+ g_type_map.Append(ConstString("SEL"), eBasicTypeObjCSel);
+ g_type_map.Append(ConstString("nullptr"), eBasicTypeNullPtr);
g_type_map.Sort();
});
- return g_type_map.Find(name.GetStringRef(), eBasicTypeInvalid);
+ return g_type_map.Find(name, eBasicTypeInvalid);
}
return eBasicTypeInvalid;
}
@@ -1412,6 +1394,12 @@ CompilerType ClangASTContext::CreateRecordType(DeclContext *decl_ctx,
return CompilerType();
}
+namespace {
+ bool IsValueParam(const clang::TemplateArgument &argument) {
+ return argument.getKind() == TemplateArgument::Integral;
+ }
+}
+
static TemplateParameterList *CreateTemplateParameterList(
ASTContext *ast,
const ClangASTContext::TemplateParameterInfos &template_param_infos,
@@ -1419,31 +1407,51 @@ static TemplateParameterList *CreateTemplateParameterList(
const bool parameter_pack = false;
const bool is_typename = false;
const unsigned depth = 0;
- const size_t num_template_params = template_param_infos.GetSize();
+ const size_t num_template_params = template_param_infos.args.size();
+ DeclContext *const decl_context =
+ ast->getTranslationUnitDecl(); // Is this the right decl context?,
for (size_t i = 0; i < num_template_params; ++i) {
const char *name = template_param_infos.names[i];
IdentifierInfo *identifier_info = nullptr;
if (name && name[0])
identifier_info = &ast->Idents.get(name);
- if (template_param_infos.args[i].getKind() == TemplateArgument::Integral) {
+ if (IsValueParam(template_param_infos.args[i])) {
template_param_decls.push_back(NonTypeTemplateParmDecl::Create(
- *ast,
- ast->getTranslationUnitDecl(), // Is this the right decl context?,
- // SourceLocation StartLoc,
+ *ast, decl_context,
SourceLocation(), SourceLocation(), depth, i, identifier_info,
template_param_infos.args[i].getIntegralType(), parameter_pack,
nullptr));
} else {
template_param_decls.push_back(TemplateTypeParmDecl::Create(
- *ast,
- ast->getTranslationUnitDecl(), // Is this the right decl context?
+ *ast, decl_context,
SourceLocation(), SourceLocation(), depth, i, identifier_info,
is_typename, parameter_pack));
}
}
-
+
+ if (template_param_infos.packed_args &&
+ template_param_infos.packed_args->args.size()) {
+ IdentifierInfo *identifier_info = nullptr;
+ if (template_param_infos.pack_name && template_param_infos.pack_name[0])
+ identifier_info = &ast->Idents.get(template_param_infos.pack_name);
+ const bool parameter_pack_true = true;
+ if (IsValueParam(template_param_infos.packed_args->args[0])) {
+ template_param_decls.push_back(NonTypeTemplateParmDecl::Create(
+ *ast, decl_context,
+ SourceLocation(), SourceLocation(), depth, num_template_params,
+ identifier_info,
+ template_param_infos.packed_args->args[0].getIntegralType(),
+ parameter_pack_true, nullptr));
+ } else {
+ template_param_decls.push_back(TemplateTypeParmDecl::Create(
+ *ast, decl_context,
+ SourceLocation(), SourceLocation(), depth, num_template_params,
+ identifier_info,
+ is_typename, parameter_pack_true));
+ }
+ }
clang::Expr *const requires_clause = nullptr; // TODO: Concepts
TemplateParameterList *template_param_list = TemplateParameterList::Create(
*ast, SourceLocation(), SourceLocation(), template_param_decls,
@@ -1553,10 +1561,19 @@ ClangASTContext::CreateClassTemplateSpecializationDecl(
DeclContext *decl_ctx, ClassTemplateDecl *class_template_decl, int kind,
const TemplateParameterInfos &template_param_infos) {
ASTContext *ast = getASTContext();
+ llvm::SmallVector<clang::TemplateArgument, 2> args(
+ template_param_infos.args.size() +
+ (template_param_infos.packed_args ? 1 : 0));
+ std::copy(template_param_infos.args.begin(), template_param_infos.args.end(),
+ args.begin());
+ if (template_param_infos.packed_args) {
+ args[args.size() - 1] = TemplateArgument::CreatePackCopy(
+ *ast, template_param_infos.packed_args->args);
+ }
ClassTemplateSpecializationDecl *class_template_specialization_decl =
ClassTemplateSpecializationDecl::Create(
*ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(),
- SourceLocation(), class_template_decl, template_param_infos.args,
+ SourceLocation(), class_template_decl, args,
nullptr);
class_template_specialization_decl->setSpecializationKind(
@@ -3921,6 +3938,11 @@ ClangASTContext::GetTypeInfo(lldb::opaque_compiler_type_t type,
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class) {
+ case clang::Type::Attributed:
+ return GetTypeInfo(
+ qual_type->getAs<clang::AttributedType>()
+ ->getModifiedType().getAsOpaquePtr(),
+ pointee_or_element_clang_type);
case clang::Type::Builtin: {
const clang::BuiltinType *builtin_type = llvm::dyn_cast<clang::BuiltinType>(
qual_type->getCanonicalTypeInternal());
@@ -4314,6 +4336,8 @@ ClangASTContext::GetTypeClass(lldb::opaque_compiler_type_t type) {
break;
case clang::Type::TemplateSpecialization:
break;
+ case clang::Type::DeducedTemplateSpecialization:
+ break;
case clang::Type::Atomic:
break;
case clang::Type::Pipe:
@@ -4474,11 +4498,12 @@ ClangASTContext::GetNumMemberFunctions(lldb::opaque_compiler_type_t type) {
case clang::Type::ObjCObjectPointer: {
const clang::ObjCObjectPointerType *objc_class_type =
- qual_type->getAsObjCInterfacePointerType();
+ qual_type->getAs<clang::ObjCObjectPointerType>();
const clang::ObjCInterfaceType *objc_interface_type =
objc_class_type->getInterfaceType();
if (objc_interface_type &&
- GetCompleteType((lldb::opaque_compiler_type_t)objc_interface_type)) {
+ GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
+ const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
clang::ObjCInterfaceDecl *class_interface_decl =
objc_interface_type->getDecl();
if (class_interface_decl) {
@@ -4582,11 +4607,12 @@ ClangASTContext::GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type,
case clang::Type::ObjCObjectPointer: {
const clang::ObjCObjectPointerType *objc_class_type =
- qual_type->getAsObjCInterfacePointerType();
+ qual_type->getAs<clang::ObjCObjectPointerType>();
const clang::ObjCInterfaceType *objc_interface_type =
objc_class_type->getInterfaceType();
if (objc_interface_type &&
- GetCompleteType((lldb::opaque_compiler_type_t)objc_interface_type)) {
+ GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
+ const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
clang::ObjCInterfaceDecl *class_interface_decl =
objc_interface_type->getDecl();
if (class_interface_decl) {
@@ -5039,7 +5065,6 @@ lldb::Encoding ClangASTContext::GetEncoding(lldb::opaque_compiler_type_t type,
case clang::BuiltinType::Kind::OCLImage3dWO:
case clang::BuiltinType::Kind::OCLImage3dRW:
case clang::BuiltinType::Kind::OCLQueue:
- case clang::BuiltinType::Kind::OCLNDRange:
case clang::BuiltinType::Kind::OCLReserveID:
case clang::BuiltinType::Kind::OCLSampler:
case clang::BuiltinType::Kind::OMPArraySection:
@@ -5123,6 +5148,7 @@ lldb::Encoding ClangASTContext::GetEncoding(lldb::opaque_compiler_type_t type,
case clang::Type::TypeOf:
case clang::Type::Decltype:
case clang::Type::TemplateSpecialization:
+ case clang::Type::DeducedTemplateSpecialization:
case clang::Type::Atomic:
case clang::Type::Adjusted:
case clang::Type::Pipe:
@@ -5272,6 +5298,7 @@ lldb::Format ClangASTContext::GetFormat(lldb::opaque_compiler_type_t type) {
case clang::Type::TypeOf:
case clang::Type::Decltype:
case clang::Type::TemplateSpecialization:
+ case clang::Type::DeducedTemplateSpecialization:
case clang::Type::Atomic:
case clang::Type::Adjusted:
case clang::Type::Pipe:
@@ -5649,11 +5676,12 @@ uint32_t ClangASTContext::GetNumFields(lldb::opaque_compiler_type_t type) {
case clang::Type::ObjCObjectPointer: {
const clang::ObjCObjectPointerType *objc_class_type =
- qual_type->getAsObjCInterfacePointerType();
+ qual_type->getAs<clang::ObjCObjectPointerType>();
const clang::ObjCInterfaceType *objc_interface_type =
objc_class_type->getInterfaceType();
if (objc_interface_type &&
- GetCompleteType((lldb::opaque_compiler_type_t)objc_interface_type)) {
+ GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
+ const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
clang::ObjCInterfaceDecl *class_interface_decl =
objc_interface_type->getDecl();
if (class_interface_decl) {
@@ -5796,11 +5824,12 @@ CompilerType ClangASTContext::GetFieldAtIndex(lldb::opaque_compiler_type_t type,
case clang::Type::ObjCObjectPointer: {
const clang::ObjCObjectPointerType *objc_class_type =
- qual_type->getAsObjCInterfacePointerType();
+ qual_type->getAs<clang::ObjCObjectPointerType>();
const clang::ObjCInterfaceType *objc_interface_type =
objc_class_type->getInterfaceType();
if (objc_interface_type &&
- GetCompleteType((lldb::opaque_compiler_type_t)objc_interface_type)) {
+ GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
+ const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
clang::ObjCInterfaceDecl *class_interface_decl =
objc_interface_type->getDecl();
if (class_interface_decl) {
@@ -6409,7 +6438,7 @@ CompilerType ClangASTContext::GetChildCompilerTypeAtIndex(
if (base_class->isVirtual()) {
bool handled = false;
if (valobj) {
- Error err;
+ Status err;
AddressType addr_type = eAddressTypeInvalid;
lldb::addr_t vtable_ptr_addr =
valobj->GetCPPVTableAddress(addr_type);
@@ -8803,7 +8832,7 @@ ClangASTContext::ConvertStringToFloatValue(lldb::opaque_compiler_type_t type,
if (dst_size >= byte_size) {
Scalar scalar = ap_float.bitcastToAPInt().zextOrTrunc(
llvm::NextPowerOf2(byte_size) * 8);
- lldb_private::Error get_data_error;
+ lldb_private::Status get_data_error;
if (scalar.GetAsMemoryData(dst, byte_size,
lldb_private::endian::InlHostByteOrder(),
get_data_error))
@@ -8821,7 +8850,7 @@ ClangASTContext::ConvertStringToFloatValue(lldb::opaque_compiler_type_t type,
void ClangASTContext::DumpValue(
lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, Stream *s,
- lldb::Format format, const lldb_private::DataExtractor &data,
+ lldb::Format format, const DataExtractor &data,
lldb::offset_t data_byte_offset, size_t data_byte_size,
uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, bool show_types,
bool show_summary, bool verbose, uint32_t depth) {
@@ -9029,8 +9058,9 @@ void ClangASTContext::DumpValue(
if (is_array_of_characters) {
s->PutChar('"');
- data.Dump(s, data_byte_offset, lldb::eFormatChar, element_byte_size,
- element_count, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ DumpDataExtractor(data, s, data_byte_offset, lldb::eFormatChar,
+ element_byte_size, element_count, UINT32_MAX,
+ LLDB_INVALID_ADDRESS, 0, 0);
s->PutChar('"');
return;
} else {
@@ -9186,8 +9216,9 @@ void ClangASTContext::DumpValue(
default:
// We are down to a scalar type that we just need to display.
- data.Dump(s, data_byte_offset, format, data_byte_size, 1, UINT32_MAX,
- LLDB_INVALID_ADDRESS, bitfield_bit_size, bitfield_bit_offset);
+ DumpDataExtractor(data, s, data_byte_offset, format, data_byte_size, 1,
+ UINT32_MAX, LLDB_INVALID_ADDRESS, bitfield_bit_size,
+ bitfield_bit_offset);
if (show_summary)
DumpSummary(type, exe_ctx, s, data, data_byte_offset, data_byte_size);
@@ -9197,8 +9228,8 @@ void ClangASTContext::DumpValue(
bool ClangASTContext::DumpTypeValue(
lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format,
- const lldb_private::DataExtractor &data, lldb::offset_t byte_offset,
- size_t byte_size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
+ const DataExtractor &data, lldb::offset_t byte_offset, size_t byte_size,
+ uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
ExecutionContextScope *exe_scope) {
if (!type)
return false;
@@ -9336,9 +9367,10 @@ bool ClangASTContext::DumpTypeValue(
byte_size = 4;
break;
}
- return data.Dump(s, byte_offset, format, byte_size, item_count,
- UINT32_MAX, LLDB_INVALID_ADDRESS, bitfield_bit_size,
- bitfield_bit_offset, exe_scope);
+ return DumpDataExtractor(data, s, byte_offset, format, byte_size,
+ item_count, UINT32_MAX, LLDB_INVALID_ADDRESS,
+ bitfield_bit_size, bitfield_bit_offset,
+ exe_scope);
}
break;
}
@@ -9364,12 +9396,12 @@ void ClangASTContext::DumpSummary(lldb::opaque_compiler_type_t type,
else
buf.resize(256);
- lldb_private::DataExtractor cstr_data(&buf.front(), buf.size(),
- process->GetByteOrder(), 4);
+ DataExtractor cstr_data(&buf.front(), buf.size(),
+ process->GetByteOrder(), 4);
buf.back() = '\0';
size_t bytes_read;
size_t total_cstr_len = 0;
- Error error;
+ Status error;
while ((bytes_read = process->ReadMemory(pointer_address, &buf.front(),
buf.size(), error)) > 0) {
const size_t len = strlen((const char *)&buf.front());
@@ -9377,8 +9409,8 @@ void ClangASTContext::DumpSummary(lldb::opaque_compiler_type_t type,
break;
if (total_cstr_len == 0)
s->PutCString(" \"");
- cstr_data.Dump(s, 0, lldb::eFormatChar, 1, len, UINT32_MAX,
- LLDB_INVALID_ADDRESS, 0, 0);
+ DumpDataExtractor(cstr_data, s, 0, lldb::eFormatChar, 1, len,
+ UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
total_cstr_len += len;
if (len < buf.size())
break;
diff --git a/contrib/llvm/tools/lldb/source/Symbol/ClangASTImporter.cpp b/contrib/llvm/tools/lldb/source/Symbol/ClangASTImporter.cpp
index c0e8fea..72ccaed 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/ClangASTImporter.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/ClangASTImporter.cpp
@@ -8,12 +8,12 @@
//===----------------------------------------------------------------------===//
#include "lldb/Symbol/ClangASTImporter.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
diff --git a/contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp b/contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp
index e39baea..c88119b 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp
@@ -40,7 +40,7 @@
#include <assert.h>
#endif
-#include "lldb/Core/Log.h"
+#include "lldb/Utility/Log.h"
#include "clang/AST/Decl.h"
using namespace clang;
@@ -61,93 +61,6 @@ bool ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(
}
std::string decl_name(clang_decl_name.getAsString());
-
- switch (clang_decl_name.getNameKind()) {
- // Normal identifiers.
- case clang::DeclarationName::Identifier:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"Identifier\", name = \"%s\")\n", decl_ctx,
- // decl_name.c_str());
- if (clang_decl_name.getAsIdentifierInfo()->getBuiltinID() != 0) {
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
- }
- break;
-
- case clang::DeclarationName::ObjCZeroArgSelector:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"ObjCZeroArgSelector\", name = \"%s\")\n",
- // decl_ctx, decl_name.c_str());
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
-
- case clang::DeclarationName::ObjCOneArgSelector:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"ObjCOneArgSelector\", name = \"%s\")\n",
- // decl_ctx, decl_name.c_str());
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
-
- case clang::DeclarationName::ObjCMultiArgSelector:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"ObjCMultiArgSelector\", name = \"%s\")\n",
- // decl_ctx, decl_name.c_str());
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
-
- case clang::DeclarationName::CXXConstructorName:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"CXXConstructorName\", name = \"%s\")\n",
- // decl_ctx, decl_name.c_str());
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
-
- case clang::DeclarationName::CXXDestructorName:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"CXXDestructorName\", name = \"%s\")\n",
- // decl_ctx, decl_name.c_str());
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
-
- case clang::DeclarationName::CXXConversionFunctionName:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"CXXConversionFunctionName\", name =
- // \"%s\")\n", decl_ctx, decl_name.c_str());
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
-
- case clang::DeclarationName::CXXOperatorName:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"CXXOperatorName\", name = \"%s\")\n",
- // decl_ctx, decl_name.c_str());
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
-
- case clang::DeclarationName::CXXLiteralOperatorName:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"CXXLiteralOperatorName\", name = \"%s\")\n",
- // decl_ctx, decl_name.c_str());
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
-
- case clang::DeclarationName::CXXUsingDirective:
- // printf
- // ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx
- // = %p, decl_name = { kind = \"CXXUsingDirective\", name = \"%s\")\n",
- // decl_ctx, decl_name.c_str());
- SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
- return false;
- }
-
SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
return false;
}
diff --git a/contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCommon.cpp b/contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCommon.cpp
index 69263fa..7a1a0f2 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCommon.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/ClangExternalASTSourceCommon.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Symbol/CompactUnwindInfo.cpp b/contrib/llvm/tools/lldb/source/Symbol/CompactUnwindInfo.cpp
index e3da6f1..bc36749 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/CompactUnwindInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/CompactUnwindInfo.cpp
@@ -12,17 +12,17 @@
#include <algorithm>
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompactUnwindInfo.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/Support/MathExtras.h"
@@ -272,7 +272,7 @@ void CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {
return;
m_section_contents_if_encrypted.reset(
new DataBufferHeap(m_section_sp->GetByteSize(), 0));
- Error error;
+ Status error;
if (process_sp->ReadMemory(
m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),
m_section_contents_if_encrypted->GetBytes(),
@@ -836,7 +836,7 @@ bool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
if (process_sp) {
Address subl_payload_addr(function_info.valid_range_offset_start, sl);
subl_payload_addr.Slide(offset_to_subl_insn);
- Error error;
+ Status error;
uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
if (large_stack_size != 0 && error.Success()) {
@@ -1100,7 +1100,7 @@ bool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
if (process_sp) {
Address subl_payload_addr(function_info.valid_range_offset_start, sl);
subl_payload_addr.Slide(offset_to_subl_insn);
- Error error;
+ Status error;
uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
if (large_stack_size != 0 && error.Success()) {
diff --git a/contrib/llvm/tools/lldb/source/Symbol/CompilerType.cpp b/contrib/llvm/tools/lldb/source/Symbol/CompilerType.cpp
index 2684db9..e3880af 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/CompilerType.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/CompilerType.cpp
@@ -9,19 +9,19 @@
#include "lldb/Symbol/CompilerType.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
#include <iterator>
#include <mutex>
@@ -744,8 +744,7 @@ size_t CompilerType::ConvertStringToFloatValue(const char *s, uint8_t *dst,
#define DEPTH_INCREMENT 2
void CompilerType::DumpValue(ExecutionContext *exe_ctx, Stream *s,
- lldb::Format format,
- const lldb_private::DataExtractor &data,
+ lldb::Format format, const DataExtractor &data,
lldb::offset_t data_byte_offset,
size_t data_byte_size, uint32_t bitfield_bit_size,
uint32_t bitfield_bit_offset, bool show_types,
@@ -759,7 +758,7 @@ void CompilerType::DumpValue(ExecutionContext *exe_ctx, Stream *s,
}
bool CompilerType::DumpTypeValue(Stream *s, lldb::Format format,
- const lldb_private::DataExtractor &data,
+ const DataExtractor &data,
lldb::offset_t byte_offset, size_t byte_size,
uint32_t bitfield_bit_size,
uint32_t bitfield_bit_offset,
@@ -772,7 +771,7 @@ bool CompilerType::DumpTypeValue(Stream *s, lldb::Format format,
}
void CompilerType::DumpSummary(ExecutionContext *exe_ctx, Stream *s,
- const lldb_private::DataExtractor &data,
+ const DataExtractor &data,
lldb::offset_t data_byte_offset,
size_t data_byte_size) {
if (IsValid())
@@ -1005,7 +1004,7 @@ bool CompilerType::ReadFromMemory(lldb_private::ExecutionContext *exe_ctx,
if (exe_ctx)
process = exe_ctx->GetProcessPtr();
if (process) {
- Error error;
+ Status error;
return process->ReadMemory(addr, dst, byte_size, error) == byte_size;
}
}
@@ -1040,7 +1039,7 @@ bool CompilerType::WriteToMemory(lldb_private::ExecutionContext *exe_ctx,
if (exe_ctx)
process = exe_ctx->GetProcessPtr();
if (process) {
- Error error;
+ Status error;
return process->WriteMemory(addr, new_value.GetData(), byte_size,
error) == byte_size;
}
diff --git a/contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp
index 9504ea1..9b1f8c6 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -12,33 +12,147 @@
#include <list>
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Section.h"
-#include "lldb/Core/Timer.h"
+#include "lldb/Core/dwarf.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
+//----------------------------------------------------------------------
+// GetDwarfEHPtr
+//
+// Used for calls when the value type is specified by a DWARF EH Frame
+// pointer encoding.
+//----------------------------------------------------------------------
+static uint64_t
+GetGNUEHPointer(const DataExtractor &DE, offset_t *offset_ptr,
+ uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr,
+ addr_t data_addr) //, BSDRelocs *data_relocs) const
+{
+ if (eh_ptr_enc == DW_EH_PE_omit)
+ return ULLONG_MAX; // Value isn't in the buffer...
+
+ uint64_t baseAddress = 0;
+ uint64_t addressValue = 0;
+ const uint32_t addr_size = DE.GetAddressByteSize();
+#ifdef LLDB_CONFIGURATION_DEBUG
+ assert(addr_size == 4 || addr_size == 8);
+#endif
+
+ bool signExtendValue = false;
+ // Decode the base part or adjust our offset
+ switch (eh_ptr_enc & 0x70) {
+ case DW_EH_PE_pcrel:
+ signExtendValue = true;
+ baseAddress = *offset_ptr;
+ if (pc_rel_addr != LLDB_INVALID_ADDRESS)
+ baseAddress += pc_rel_addr;
+ // else
+ // Log::GlobalWarning ("PC relative pointer encoding found with
+ // invalid pc relative address.");
+ break;
+
+ case DW_EH_PE_textrel:
+ signExtendValue = true;
+ if (text_addr != LLDB_INVALID_ADDRESS)
+ baseAddress = text_addr;
+ // else
+ // Log::GlobalWarning ("text relative pointer encoding being
+ // decoded with invalid text section address, setting base address
+ // to zero.");
+ break;
+
+ case DW_EH_PE_datarel:
+ signExtendValue = true;
+ if (data_addr != LLDB_INVALID_ADDRESS)
+ baseAddress = data_addr;
+ // else
+ // Log::GlobalWarning ("data relative pointer encoding being
+ // decoded with invalid data section address, setting base address
+ // to zero.");
+ break;
+
+ case DW_EH_PE_funcrel:
+ signExtendValue = true;
+ break;
+
+ case DW_EH_PE_aligned: {
+ // SetPointerSize should be called prior to extracting these so the
+ // pointer size is cached
+ assert(addr_size != 0);
+ if (addr_size) {
+ // Align to a address size boundary first
+ uint32_t alignOffset = *offset_ptr % addr_size;
+ if (alignOffset)
+ offset_ptr += addr_size - alignOffset;
+ }
+ } break;
+
+ default:
+ break;
+ }
+
+ // Decode the value part
+ switch (eh_ptr_enc & DW_EH_PE_MASK_ENCODING) {
+ case DW_EH_PE_absptr: {
+ addressValue = DE.GetAddress(offset_ptr);
+ // if (data_relocs)
+ // addressValue = data_relocs->Relocate(*offset_ptr -
+ // addr_size, *this, addressValue);
+ } break;
+ case DW_EH_PE_uleb128:
+ addressValue = DE.GetULEB128(offset_ptr);
+ break;
+ case DW_EH_PE_udata2:
+ addressValue = DE.GetU16(offset_ptr);
+ break;
+ case DW_EH_PE_udata4:
+ addressValue = DE.GetU32(offset_ptr);
+ break;
+ case DW_EH_PE_udata8:
+ addressValue = DE.GetU64(offset_ptr);
+ break;
+ case DW_EH_PE_sleb128:
+ addressValue = DE.GetSLEB128(offset_ptr);
+ break;
+ case DW_EH_PE_sdata2:
+ addressValue = (int16_t)DE.GetU16(offset_ptr);
+ break;
+ case DW_EH_PE_sdata4:
+ addressValue = (int32_t)DE.GetU32(offset_ptr);
+ break;
+ case DW_EH_PE_sdata8:
+ addressValue = (int64_t)DE.GetU64(offset_ptr);
+ break;
+ default:
+ // Unhandled encoding type
+ assert(eh_ptr_enc);
+ break;
+ }
+
+ // Since we promote everything to 64 bit, we may need to sign extend
+ if (signExtendValue && addr_size < sizeof(baseAddress)) {
+ uint64_t sign_bit = 1ull << ((addr_size * 8ull) - 1ull);
+ if (sign_bit & addressValue) {
+ uint64_t mask = ~sign_bit + 1;
+ addressValue |= mask;
+ }
+ }
+ return baseAddress + addressValue;
+}
+
DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile &objfile,
- SectionSP &section_sp,
- lldb::RegisterKind reg_kind,
- bool is_eh_frame)
- : m_objfile(objfile), m_section_sp(section_sp),
- m_reg_kind(reg_kind), // The flavor of registers that the CFI data uses
- // (enum RegisterKind)
- m_flags(), m_cie_map(), m_cfi_data(), m_cfi_data_initialized(false),
- m_fde_index(), m_fde_index_initialized(false),
- m_is_eh_frame(is_eh_frame) {}
-
-DWARFCallFrameInfo::~DWARFCallFrameInfo() {}
+ SectionSP &section_sp, Type type)
+ : m_objfile(objfile), m_section_sp(section_sp), m_type(type) {}
bool DWARFCallFrameInfo::GetUnwindPlan(Address addr, UnwindPlan &unwind_plan) {
FDEEntryMap::Entry fde_entry;
@@ -145,14 +259,20 @@ DWARFCallFrameInfo::ParseCIE(const dw_offset_t cie_offset) {
cie_id = m_cfi_data.GetU32(&offset);
end_offset = cie_offset + length + 4;
}
- if (length > 0 && ((!m_is_eh_frame && cie_id == UINT32_MAX) ||
- (m_is_eh_frame && cie_id == 0ul))) {
+ if (length > 0 && ((m_type == DWARF && cie_id == UINT32_MAX) ||
+ (m_type == EH && cie_id == 0ul))) {
size_t i;
// cie.offset = cie_offset;
// cie.length = length;
// cie.cieID = cieID;
cie_sp->ptr_encoding = DW_EH_PE_absptr; // default
cie_sp->version = m_cfi_data.GetU8(&offset);
+ if (cie_sp->version > CFI_VERSION4) {
+ Host::SystemLog(Host::eSystemLogError,
+ "CIE parse error: CFI version %d is not supported\n",
+ cie_sp->version);
+ return nullptr;
+ }
for (i = 0; i < CFI_AUG_MAX_SIZE; ++i) {
cie_sp->augmentation[i] = m_cfi_data.GetU8(&offset);
@@ -171,11 +291,23 @@ DWARFCallFrameInfo::ParseCIE(const dw_offset_t cie_offset) {
"CIE parse error: CIE augmentation string was too large "
"for the fixed sized buffer of %d bytes.\n",
CFI_AUG_MAX_SIZE);
- return cie_sp;
+ return nullptr;
+ }
+
+ // m_cfi_data uses address size from target architecture of the process
+ // may ignore these fields?
+ if (m_type == DWARF && cie_sp->version >= CFI_VERSION4) {
+ cie_sp->address_size = m_cfi_data.GetU8(&offset);
+ cie_sp->segment_size = m_cfi_data.GetU8(&offset);
}
+
cie_sp->code_align = (uint32_t)m_cfi_data.GetULEB128(&offset);
cie_sp->data_align = (int32_t)m_cfi_data.GetSLEB128(&offset);
- cie_sp->return_addr_reg_num = m_cfi_data.GetU8(&offset);
+
+ cie_sp->return_addr_reg_num =
+ m_type == DWARF && cie_sp->version >= CFI_VERSION3
+ ? static_cast<uint32_t>(m_cfi_data.GetULEB128(&offset))
+ : m_cfi_data.GetU8(&offset);
if (cie_sp->augmentation[0]) {
// Get the length of the eh_frame augmentation data
@@ -223,9 +355,9 @@ DWARFCallFrameInfo::ParseCIE(const dw_offset_t cie_offset) {
{
uint8_t arg_ptr_encoding = m_cfi_data.GetU8(&offset);
const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
- cie_sp->personality_loc = m_cfi_data.GetGNUEHPointer(
- &offset, arg_ptr_encoding, pc_rel_addr, LLDB_INVALID_ADDRESS,
- LLDB_INVALID_ADDRESS);
+ cie_sp->personality_loc = GetGNUEHPointer(
+ m_cfi_data, &offset, arg_ptr_encoding, pc_rel_addr,
+ LLDB_INVALID_ADDRESS, LLDB_INVALID_ADDRESS);
}
break;
@@ -296,7 +428,8 @@ void DWARFCallFrameInfo::GetFDEIndex() {
if (m_fde_index_initialized) // if two threads hit the locker
return;
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s - %s", LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s - %s", LLVM_PRETTY_FUNCTION,
m_objfile.GetFileSpec().GetFilename().AsCString(""));
bool clear_address_zeroth_bit = false;
@@ -337,11 +470,33 @@ void DWARFCallFrameInfo::GetFDEIndex() {
m_fde_index_initialized = true;
return;
}
+
+ // An FDE entry contains CIE_pointer in debug_frame in same place as cie_id
+ // in eh_frame. CIE_pointer is an offset into the .debug_frame section.
+ // So, variable cie_offset should be equal to cie_id for debug_frame.
+ // FDE entries with cie_id == 0 shouldn't be ignored for it.
+ if ((cie_id == 0 && m_type == EH) || cie_id == UINT32_MAX || len == 0) {
+ auto cie_sp = ParseCIE(current_entry);
+ if (!cie_sp) {
+ // Cannot parse, the reason is already logged
+ m_fde_index.Clear();
+ m_fde_index_initialized = true;
+ return;
+ }
+
+ m_cie_map[current_entry] = std::move(cie_sp);
+ offset = next_entry;
+ continue;
+ }
+
+ if (m_type == DWARF)
+ cie_offset = cie_id;
+
if (cie_offset > m_cfi_data.GetByteSize()) {
- Host::SystemLog(
- Host::eSystemLogError,
- "error: Invalid cie offset of 0x%x found in cie/fde at 0x%x\n",
- cie_offset, current_entry);
+ Host::SystemLog(Host::eSystemLogError,
+ "error: Invalid cie offset of 0x%x "
+ "found in cie/fde at 0x%x\n",
+ cie_offset, current_entry);
// Don't trust anything in this eh_frame section if we find blatantly
// invalid data.
m_fde_index.Clear();
@@ -349,26 +504,21 @@ void DWARFCallFrameInfo::GetFDEIndex() {
return;
}
- if (cie_id == 0 || cie_id == UINT32_MAX || len == 0) {
- m_cie_map[current_entry] = ParseCIE(current_entry);
- offset = next_entry;
- continue;
- }
-
const CIE *cie = GetCIE(cie_offset);
if (cie) {
const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
- lldb::addr_t addr = m_cfi_data.GetGNUEHPointer(
- &offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
+ lldb::addr_t addr =
+ GetGNUEHPointer(m_cfi_data, &offset, cie->ptr_encoding, pc_rel_addr,
+ text_addr, data_addr);
if (clear_address_zeroth_bit)
addr &= ~1ull;
- lldb::addr_t length = m_cfi_data.GetGNUEHPointer(
- &offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr,
- text_addr, data_addr);
+ lldb::addr_t length = GetGNUEHPointer(
+ m_cfi_data, &offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING,
+ pc_rel_addr, text_addr, data_addr);
FDEEntryMap::Entry fde(addr, length, current_entry);
m_fde_index.Append(fde);
} else {
@@ -406,12 +556,13 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
cie_offset = m_cfi_data.GetU32(&offset);
}
- assert(cie_offset != 0 && cie_offset != UINT32_MAX);
+ // FDE entries with zeroth cie_offset may occur for debug_frame.
+ assert(!(m_type == EH && 0 == cie_offset) && cie_offset != UINT32_MAX);
// Translate the CIE_id from the eh_frame format, which
// is relative to the FDE offset, into a __eh_frame section
// offset
- if (m_is_eh_frame) {
+ if (m_type == EH) {
unwind_plan.SetSourceName("eh_frame CFI");
cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
@@ -434,11 +585,12 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
- lldb::addr_t range_base = m_cfi_data.GetGNUEHPointer(
- &offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
- lldb::addr_t range_len = m_cfi_data.GetGNUEHPointer(
- &offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr,
- text_addr, data_addr);
+ lldb::addr_t range_base =
+ GetGNUEHPointer(m_cfi_data, &offset, cie->ptr_encoding, pc_rel_addr,
+ text_addr, data_addr);
+ lldb::addr_t range_len = GetGNUEHPointer(
+ m_cfi_data, &offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING,
+ pc_rel_addr, text_addr, data_addr);
AddressRange range(range_base, m_objfile.GetAddressByteSize(),
m_objfile.GetSectionList());
range.SetByteSize(range_len);
@@ -449,8 +601,9 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) {
offset_t saved_offset = offset;
- lsda_data_file_address = m_cfi_data.GetGNUEHPointer(
- &offset, cie->lsda_addr_encoding, pc_rel_addr, text_addr, data_addr);
+ lsda_data_file_address =
+ GetGNUEHPointer(m_cfi_data, &offset, cie->lsda_addr_encoding,
+ pc_rel_addr, text_addr, data_addr);
if (offset - saved_offset != aug_data_len) {
// There is more in the augmentation region than we know how to process;
// don't read anything.
@@ -484,7 +637,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
*cie_initial_row = cie->initial_row;
UnwindPlan::RowSP row(cie_initial_row);
- unwind_plan.SetRegisterKind(m_reg_kind);
+ unwind_plan.SetRegisterKind(GetRegisterKind());
unwind_plan.SetReturnAddressRegister(cie->return_addr_reg_num);
std::vector<UnwindPlan::RowSP> stack;
diff --git a/contrib/llvm/tools/lldb/source/Symbol/Declaration.cpp b/contrib/llvm/tools/lldb/source/Symbol/Declaration.cpp
index 5d1dbde..7cee6c5 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/Declaration.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/Declaration.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Symbol/Declaration.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
@@ -42,7 +42,7 @@ void Declaration::Dump(Stream *s, bool show_fullpaths) const {
bool Declaration::DumpStopContext(Stream *s, bool show_fullpaths) const {
if (m_file) {
- if (show_fullpaths || s->GetVerbose())
+ if (show_fullpaths)
*s << m_file;
else
m_file.GetFilename().Dump(s);
diff --git a/contrib/llvm/tools/lldb/source/Symbol/FuncUnwinders.cpp b/contrib/llvm/tools/lldb/source/Symbol/FuncUnwinders.cpp
index 0abd8a2..b9f50cd 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/FuncUnwinders.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/FuncUnwinders.cpp
@@ -19,10 +19,10 @@
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterNumber.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/UnwindAssembly.h"
-#include "lldb/Utility/RegisterNumber.h"
using namespace lldb;
using namespace lldb_private;
@@ -39,7 +39,9 @@ FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, AddressRange range)
m_unwind_plan_arch_default_sp(),
m_unwind_plan_arch_default_at_func_entry_sp(),
m_tried_unwind_plan_assembly(false), m_tried_unwind_plan_eh_frame(false),
+ m_tried_unwind_plan_debug_frame(false),
m_tried_unwind_plan_eh_frame_augmented(false),
+ m_tried_unwind_plan_debug_frame_augmented(false),
m_tried_unwind_plan_compact_unwind(false),
m_tried_unwind_plan_arm_unwind(false), m_tried_unwind_fast(false),
m_tried_unwind_arch_default(false),
@@ -56,30 +58,27 @@ UnwindPlanSP FuncUnwinders::GetUnwindPlanAtCallSite(Target &target,
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan(target, current_offset);
- if (unwind_plan_sp)
- return unwind_plan_sp;
-
- unwind_plan_sp = GetCompactUnwindUnwindPlan(target, current_offset);
- if (unwind_plan_sp)
- return unwind_plan_sp;
-
- unwind_plan_sp = GetArmUnwindUnwindPlan(target, current_offset);
- if (unwind_plan_sp)
- return unwind_plan_sp;
+ if (UnwindPlanSP plan_sp = GetEHFrameUnwindPlan(target, current_offset))
+ return plan_sp;
+ if (UnwindPlanSP plan_sp = GetDebugFrameUnwindPlan(target, current_offset))
+ return plan_sp;
+ if (UnwindPlanSP plan_sp = GetCompactUnwindUnwindPlan(target, current_offset))
+ return plan_sp;
+ if (UnwindPlanSP plan_sp = GetArmUnwindUnwindPlan(target, current_offset))
+ return plan_sp;
return nullptr;
}
UnwindPlanSP FuncUnwinders::GetCompactUnwindUnwindPlan(Target &target,
int current_offset) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_compact_unwind.size() > 0)
return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact
// unwind plans for one func
if (m_tried_unwind_plan_compact_unwind)
return UnwindPlanSP();
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_tried_unwind_plan_compact_unwind = true;
if (m_range.GetBaseAddress().IsValid()) {
Address current_pc(m_range.GetBaseAddress());
@@ -101,10 +100,10 @@ UnwindPlanSP FuncUnwinders::GetCompactUnwindUnwindPlan(Target &target,
UnwindPlanSP FuncUnwinders::GetEHFrameUnwindPlan(Target &target,
int current_offset) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame)
return m_unwind_plan_eh_frame_sp;
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_tried_unwind_plan_eh_frame = true;
if (m_range.GetBaseAddress().IsValid()) {
Address current_pc(m_range.GetBaseAddress());
@@ -121,12 +120,35 @@ UnwindPlanSP FuncUnwinders::GetEHFrameUnwindPlan(Target &target,
return m_unwind_plan_eh_frame_sp;
}
+UnwindPlanSP FuncUnwinders::GetDebugFrameUnwindPlan(Target &target,
+ int current_offset) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (m_unwind_plan_debug_frame_sp || m_tried_unwind_plan_debug_frame)
+ return m_unwind_plan_debug_frame_sp;
+
+ m_tried_unwind_plan_debug_frame = true;
+ if (m_range.GetBaseAddress().IsValid()) {
+ Address current_pc(m_range.GetBaseAddress());
+ if (current_offset != -1)
+ current_pc.SetOffset(current_pc.GetOffset() + current_offset);
+ DWARFCallFrameInfo *debug_frame = m_unwind_table.GetDebugFrameInfo();
+ if (debug_frame) {
+ m_unwind_plan_debug_frame_sp.reset(
+ new UnwindPlan(lldb::eRegisterKindGeneric));
+ if (!debug_frame->GetUnwindPlan(current_pc,
+ *m_unwind_plan_debug_frame_sp))
+ m_unwind_plan_debug_frame_sp.reset();
+ }
+ }
+ return m_unwind_plan_debug_frame_sp;
+}
+
UnwindPlanSP FuncUnwinders::GetArmUnwindUnwindPlan(Target &target,
int current_offset) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_arm_unwind_sp.get() || m_tried_unwind_plan_arm_unwind)
return m_unwind_plan_arm_unwind_sp;
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_tried_unwind_plan_arm_unwind = true;
if (m_range.GetBaseAddress().IsValid()) {
Address current_pc(m_range.GetBaseAddress());
@@ -147,6 +169,7 @@ UnwindPlanSP FuncUnwinders::GetArmUnwindUnwindPlan(Target &target,
UnwindPlanSP FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target,
Thread &thread,
int current_offset) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_eh_frame_augmented_sp.get() ||
m_tried_unwind_plan_eh_frame_augmented)
return m_unwind_plan_eh_frame_augmented_sp;
@@ -162,7 +185,6 @@ UnwindPlanSP FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target,
return m_unwind_plan_eh_frame_augmented_sp;
}
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_tried_unwind_plan_eh_frame_augmented = true;
UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan(target, current_offset);
@@ -187,15 +209,57 @@ UnwindPlanSP FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target,
return m_unwind_plan_eh_frame_augmented_sp;
}
+UnwindPlanSP
+FuncUnwinders::GetDebugFrameAugmentedUnwindPlan(Target &target, Thread &thread,
+ int current_offset) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (m_unwind_plan_debug_frame_augmented_sp.get() ||
+ m_tried_unwind_plan_debug_frame_augmented)
+ return m_unwind_plan_debug_frame_augmented_sp;
+
+ // Only supported on x86 architectures where we get debug_frame from the
+ // compiler that describes the prologue instructions perfectly, and sometimes
+ // the epilogue instructions too.
+ if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 &&
+ target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 &&
+ target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) {
+ m_tried_unwind_plan_debug_frame_augmented = true;
+ return m_unwind_plan_debug_frame_augmented_sp;
+ }
+
+ m_tried_unwind_plan_debug_frame_augmented = true;
+
+ UnwindPlanSP debug_frame_plan =
+ GetDebugFrameUnwindPlan(target, current_offset);
+ if (!debug_frame_plan)
+ return m_unwind_plan_debug_frame_augmented_sp;
+
+ m_unwind_plan_debug_frame_augmented_sp.reset(
+ new UnwindPlan(*debug_frame_plan));
+
+ // Augment the debug_frame instructions with epilogue descriptions if
+ // necessary so the UnwindPlan can be used at any instruction in the function.
+
+ UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
+ if (assembly_profiler_sp) {
+ if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
+ m_range, thread, *m_unwind_plan_debug_frame_augmented_sp)) {
+ m_unwind_plan_debug_frame_augmented_sp.reset();
+ }
+ } else
+ m_unwind_plan_debug_frame_augmented_sp.reset();
+ return m_unwind_plan_debug_frame_augmented_sp;
+}
+
UnwindPlanSP FuncUnwinders::GetAssemblyUnwindPlan(Target &target,
Thread &thread,
int current_offset) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly ||
m_unwind_table.GetAllowAssemblyEmulationUnwindPlans() == false) {
return m_unwind_plan_assembly_sp;
}
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_tried_unwind_plan_assembly = true;
UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
@@ -248,6 +312,8 @@ UnwindPlanSP FuncUnwinders::GetUnwindPlanAtNonCallSite(Target &target,
Thread &thread,
int current_offset) {
UnwindPlanSP eh_frame_sp = GetEHFrameUnwindPlan(target, current_offset);
+ if (!eh_frame_sp)
+ eh_frame_sp = GetDebugFrameUnwindPlan(target, current_offset);
UnwindPlanSP arch_default_at_entry_sp =
GetUnwindPlanArchitectureDefaultAtFunctionEntry(thread);
UnwindPlanSP arch_default_sp = GetUnwindPlanArchitectureDefault(thread);
@@ -255,28 +321,22 @@ UnwindPlanSP FuncUnwinders::GetUnwindPlanAtNonCallSite(Target &target,
GetAssemblyUnwindPlan(target, thread, current_offset);
// This point of this code is to detect when a function is using a
- // non-standard ABI, and the eh_frame
- // correctly describes that alternate ABI. This is addressing a specific
- // situation on x86_64 linux
- // systems where one function in a library pushes a value on the stack and
- // jumps to another function.
- // So using an assembly instruction based unwind will not work when you're in
- // the second function -
- // the stack has been modified in a non-ABI way. But we have eh_frame that
- // correctly describes how to
- // unwind from this location. So we're looking to see if the initial pc
- // register save location from
- // the eh_frame is different from the assembly unwind, the arch default
- // unwind, and the arch default at
- // initial function entry.
+ // non-standard ABI, and the eh_frame correctly describes that alternate ABI.
+ // This is addressing a specific situation on x86_64 linux systems where one
+ // function in a library pushes a value on the stack and jumps to another
+ // function. So using an assembly instruction based unwind will not work when
+ // you're in the second function - the stack has been modified in a non-ABI
+ // way. But we have eh_frame that correctly describes how to unwind from this
+ // location. So we're looking to see if the initial pc register save location
+ // from the eh_frame is different from the assembly unwind, the arch default
+ // unwind, and the arch default at initial function entry.
//
// We may have eh_frame that describes the entire function -- or we may have
- // eh_frame that only describes
- // the unwind after the prologue has executed -- so we need to check both the
- // arch default (once the prologue
- // has executed) and the arch default at initial function entry. And we may
- // be running on a target where
- // we have only some of the assembly/arch default unwind plans available.
+ // eh_frame that only describes the unwind after the prologue has executed --
+ // so we need to check both the arch default (once the prologue has executed)
+ // and the arch default at initial function entry. And we may be running on a
+ // target where we have only some of the assembly/arch default unwind plans
+ // available.
if (CompareUnwindPlansForIdenticalInitialPCLocation(
thread, eh_frame_sp, arch_default_at_entry_sp) == eLazyBoolNo &&
@@ -287,21 +347,22 @@ UnwindPlanSP FuncUnwinders::GetUnwindPlanAtNonCallSite(Target &target,
return eh_frame_sp;
}
- UnwindPlanSP eh_frame_augmented_sp =
- GetEHFrameAugmentedUnwindPlan(target, thread, current_offset);
- if (eh_frame_augmented_sp) {
- return eh_frame_augmented_sp;
- }
+ if (UnwindPlanSP plan_sp =
+ GetEHFrameAugmentedUnwindPlan(target, thread, current_offset))
+ return plan_sp;
+ if (UnwindPlanSP plan_sp =
+ GetDebugFrameAugmentedUnwindPlan(target, thread, current_offset))
+ return plan_sp;
return assembly_sp;
}
UnwindPlanSP FuncUnwinders::GetUnwindPlanFastUnwind(Target &target,
Thread &thread) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)
return m_unwind_plan_fast_sp;
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_tried_unwind_fast = true;
UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
@@ -316,10 +377,10 @@ UnwindPlanSP FuncUnwinders::GetUnwindPlanFastUnwind(Target &target,
}
UnwindPlanSP FuncUnwinders::GetUnwindPlanArchitectureDefault(Thread &thread) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default)
return m_unwind_plan_arch_default_sp;
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_tried_unwind_arch_default = true;
Address current_pc;
@@ -340,11 +401,11 @@ UnwindPlanSP FuncUnwinders::GetUnwindPlanArchitectureDefault(Thread &thread) {
UnwindPlanSP
FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry(Thread &thread) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_arch_default_at_func_entry_sp.get() ||
m_tried_unwind_arch_default_at_func_entry)
return m_unwind_plan_arch_default_at_func_entry_sp;
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_tried_unwind_arch_default_at_func_entry = true;
Address current_pc;
@@ -365,10 +426,10 @@ FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry(Thread &thread) {
}
Address &FuncUnwinders::GetFirstNonPrologueInsn(Target &target) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_first_non_prologue_insn.IsValid())
return m_first_non_prologue_insn;
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
ExecutionContext exe_ctx(target.shared_from_this(), false);
UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp)
diff --git a/contrib/llvm/tools/lldb/source/Symbol/Function.cpp b/contrib/llvm/tools/lldb/source/Symbol/Function.cpp
index 8fde0a4..9464cef 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/Function.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/Function.cpp
@@ -228,12 +228,15 @@ const CompileUnit *Function::GetCompileUnit() const { return m_comp_unit; }
void Function::GetDescription(Stream *s, lldb::DescriptionLevel level,
Target *target) {
- Type *func_type = GetType();
- const char *name = func_type ? func_type->GetName().AsCString() : "<unknown>";
-
- *s << "id = " << (const UserID &)*this << ", name = \"" << name
- << "\", range = ";
-
+ ConstString name = GetName();
+ ConstString mangled = m_mangled.GetMangledName();
+
+ *s << "id = " << (const UserID &)*this;
+ if (name)
+ *s << ", name = \"" << name.GetCString() << '"';
+ if (mangled)
+ *s << ", mangled = \"" << mangled.GetCString() << '"';
+ *s << ", range = ";
Address::DumpStyle fallback_style;
if (level == eDescriptionLevelVerbose)
fallback_style = Address::DumpStyleModuleWithFileAddress;
diff --git a/contrib/llvm/tools/lldb/source/Symbol/GoASTContext.cpp b/contrib/llvm/tools/lldb/source/Symbol/GoASTContext.cpp
index a28a6d7..6761a60 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/GoASTContext.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/GoASTContext.cpp
@@ -11,12 +11,12 @@
#include <utility>
#include <vector>
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Core/ValueObject.h"
-#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/GoASTContext.h"
#include "lldb/Symbol/ObjectFile.h"
@@ -25,6 +25,8 @@
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
+#include "llvm/Support/Threading.h"
+
#include "Plugins/ExpressionParser/Go/GoUserExpression.h"
#include "Plugins/SymbolFile/DWARF/DWARFASTParserGo.h"
@@ -593,36 +595,35 @@ GoASTContext::GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) {
if (name) {
typedef UniqueCStringMap<lldb::BasicType> TypeNameToBasicTypeMap;
static TypeNameToBasicTypeMap g_type_map;
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
// "void"
- g_type_map.Append(ConstString("void").GetStringRef(), eBasicTypeVoid);
+ g_type_map.Append(ConstString("void"), eBasicTypeVoid);
// "int"
- g_type_map.Append(ConstString("int").GetStringRef(), eBasicTypeInt);
- g_type_map.Append(ConstString("uint").GetStringRef(),
- eBasicTypeUnsignedInt);
+ g_type_map.Append(ConstString("int"), eBasicTypeInt);
+ g_type_map.Append(ConstString("uint"), eBasicTypeUnsignedInt);
// Miscellaneous
- g_type_map.Append(ConstString("bool").GetStringRef(), eBasicTypeBool);
+ g_type_map.Append(ConstString("bool"), eBasicTypeBool);
// Others. Should these map to C types?
- g_type_map.Append(ConstString("byte").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("uint8").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("uint16").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("uint32").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("uint64").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("int8").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("int16").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("int32").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("int64").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("float32").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("float64").GetStringRef(), eBasicTypeOther);
- g_type_map.Append(ConstString("uintptr").GetStringRef(), eBasicTypeOther);
+ g_type_map.Append(ConstString("byte"), eBasicTypeOther);
+ g_type_map.Append(ConstString("uint8"), eBasicTypeOther);
+ g_type_map.Append(ConstString("uint16"), eBasicTypeOther);
+ g_type_map.Append(ConstString("uint32"), eBasicTypeOther);
+ g_type_map.Append(ConstString("uint64"), eBasicTypeOther);
+ g_type_map.Append(ConstString("int8"), eBasicTypeOther);
+ g_type_map.Append(ConstString("int16"), eBasicTypeOther);
+ g_type_map.Append(ConstString("int32"), eBasicTypeOther);
+ g_type_map.Append(ConstString("int64"), eBasicTypeOther);
+ g_type_map.Append(ConstString("float32"), eBasicTypeOther);
+ g_type_map.Append(ConstString("float64"), eBasicTypeOther);
+ g_type_map.Append(ConstString("uintptr"), eBasicTypeOther);
g_type_map.Sort();
});
- return g_type_map.Find(name.GetStringRef(), eBasicTypeInvalid);
+ return g_type_map.Find(name, eBasicTypeInvalid);
}
return eBasicTypeInvalid;
}
@@ -1261,9 +1262,9 @@ bool GoASTContext::DumpTypeValue(lldb::opaque_compiler_type_t type, Stream *s,
byte_size = 4;
break;
}
- return data.Dump(s, byte_offset, format, byte_size, item_count, UINT32_MAX,
- LLDB_INVALID_ADDRESS, bitfield_bit_size,
- bitfield_bit_offset, exe_scope);
+ return DumpDataExtractor(data, s, byte_offset, format, byte_size,
+ item_count, UINT32_MAX, LLDB_INVALID_ADDRESS,
+ bitfield_bit_size, bitfield_bit_offset, exe_scope);
}
return 0;
}
diff --git a/contrib/llvm/tools/lldb/source/Symbol/JavaASTContext.cpp b/contrib/llvm/tools/lldb/source/Symbol/JavaASTContext.cpp
index 79073a6..ae4e9d5 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/JavaASTContext.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/JavaASTContext.cpp
@@ -10,10 +10,9 @@
#include <sstream>
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/DWARFExpression.h"
@@ -22,6 +21,7 @@
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Stream.h"
#include "Plugins/SymbolFile/DWARF/DWARFASTParserJava.h"
@@ -137,7 +137,7 @@ public:
if (m_dynamic_type_id.Evaluate(exe_ctx->GetBestExecutionContextScope(),
nullptr, nullptr, 0, &obj_load_address,
nullptr, result, nullptr)) {
- Error error;
+ Status error;
lldb::addr_t type_id_addr = result.GetScalar().UInt();
lldb::ProcessSP process_sp = exe_ctx->GetProcessSP();
@@ -303,7 +303,7 @@ public:
if (!m_length_expression.IsValid())
return UINT32_MAX;
- Error error;
+ Status error;
ValueObjectSP address_obj = value_obj->AddressOf(error);
if (error.Fail())
return UINT32_MAX;
@@ -1004,10 +1004,10 @@ bool JavaASTContext::DumpTypeValue(
size_t data_byte_size, uint32_t bitfield_bit_size,
uint32_t bitfield_bit_offset, ExecutionContextScope *exe_scope) {
if (IsScalarType(type)) {
- return data.Dump(s, data_offset, format, data_byte_size,
- 1, // count
- UINT32_MAX, LLDB_INVALID_ADDRESS, bitfield_bit_size,
- bitfield_bit_offset, exe_scope);
+ return DumpDataExtractor(data, s, data_offset, format, data_byte_size,
+ 1, // count
+ UINT32_MAX, LLDB_INVALID_ADDRESS,
+ bitfield_bit_size, bitfield_bit_offset, exe_scope);
}
return false;
}
diff --git a/contrib/llvm/tools/lldb/source/Symbol/LineTable.cpp b/contrib/llvm/tools/lldb/source/Symbol/LineTable.cpp
index 02ab0c1..3cb3053 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/LineTable.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/LineTable.cpp
@@ -11,8 +11,8 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Utility/Stream.h"
#include <algorithm>
using namespace lldb;
@@ -230,6 +230,14 @@ bool LineTable::FindLineEntryByAddress(const Address &so_addr,
}
}
}
+ else
+ {
+ // There might be code in the containing objfile before the first line
+ // table entry. Make sure that does not get considered part of the first
+ // line table entry.
+ if (pos->file_addr > so_addr.GetFileAddress())
+ return false;
+ }
// Make sure we have a valid match and that the match isn't a
// terminating
@@ -501,6 +509,7 @@ LineTable *LineTable::LinkLineTable(const FileRangeMap &file_range_map) {
if (terminate_previous_entry && !sequence.m_entries.empty()) {
assert(prev_file_addr != LLDB_INVALID_ADDRESS);
+ UNUSED_IF_ASSERT_DISABLED(prev_file_addr);
sequence.m_entries.push_back(sequence.m_entries.back());
if (prev_end_entry_linked_file_addr == LLDB_INVALID_ADDRESS)
prev_end_entry_linked_file_addr =
diff --git a/contrib/llvm/tools/lldb/source/Symbol/OCamlASTContext.cpp b/contrib/llvm/tools/lldb/source/Symbol/OCamlASTContext.cpp
index d459be3..1456ebf 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/OCamlASTContext.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/OCamlASTContext.cpp
@@ -9,7 +9,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Symbol/OCamlASTContext.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
@@ -19,6 +19,7 @@
#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
#include "Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h"
@@ -621,9 +622,9 @@ bool OCamlASTContext::DumpTypeValue(
}
if (IsScalarType(type)) {
- return data.Dump(s, byte_offset, format, byte_size, 1, SIZE_MAX,
- LLDB_INVALID_ADDRESS, bitfield_bit_size,
- bitfield_bit_offset, exe_scope);
+ return DumpDataExtractor(data, s, byte_offset, format, byte_size, 1,
+ SIZE_MAX, LLDB_INVALID_ADDRESS, bitfield_bit_size,
+ bitfield_bit_offset, exe_scope);
}
return false;
diff --git a/contrib/llvm/tools/lldb/source/Symbol/ObjectFile.cpp b/contrib/llvm/tools/lldb/source/Symbol/ObjectFile.cpp
index 0b1d6b2..fd41808 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/ObjectFile.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/ObjectFile.cpp
@@ -9,18 +9,22 @@
#include "lldb/Symbol/ObjectFile.h"
#include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h"
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Symbol/ObjectContainer.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataBufferLLVM.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Timer.h"
#include "lldb/lldb-private.h"
using namespace lldb;
@@ -33,8 +37,9 @@ ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp, const FileSpec *file,
ObjectFileSP object_file_sp;
if (module_sp) {
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
- LLVM_PRETTY_FUNCTION,
+ func_cat,
"ObjectFile::FindPlugin (module = %s, file = %p, file_offset = "
"0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
module_sp->GetFileSpec().GetPath().c_str(),
@@ -73,8 +78,8 @@ ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp, const FileSpec *file,
// and object container plug-ins can use these bytes to see if they
// can parse this file.
if (file_size > 0) {
- data_sp = file->ReadFileContents(file_offset,
- std::min<size_t>(512, file_size));
+ data_sp =
+ DataBufferLLVM::CreateSliceFromPath(file->GetPath(), 512, file_offset);
data_offset = 0;
}
}
@@ -117,7 +122,8 @@ ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp, const FileSpec *file,
}
// We failed to find any cached object files in the container
// plug-ins, so lets read the first 512 bytes and try again below...
- data_sp = archive_file.ReadFileContents(file_offset, 512);
+ data_sp = DataBufferLLVM::CreateSliceFromPath(archive_file.GetPath(),
+ 512, file_offset);
}
}
}
@@ -171,9 +177,11 @@ ObjectFileSP ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp,
ObjectFileSP object_file_sp;
if (module_sp) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "ObjectFile::FindPlugin (module = "
- "%s, process = %p, header_addr = "
- "0x%" PRIx64 ")",
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
+ "ObjectFile::FindPlugin (module = "
+ "%s, process = %p, header_addr = "
+ "0x%" PRIx64 ")",
module_sp->GetFileSpec().GetPath().c_str(),
static_cast<void *>(process_sp.get()), header_addr);
uint32_t idx;
@@ -203,7 +211,7 @@ size_t ObjectFile::GetModuleSpecifications(const FileSpec &file,
lldb::offset_t file_offset,
lldb::offset_t file_size,
ModuleSpecList &specs) {
- DataBufferSP data_sp(file.ReadFileContents(file_offset, 512));
+ DataBufferSP data_sp = DataBufferLLVM::CreateSliceFromPath(file.GetPath(), 512, file_offset);
if (data_sp) {
if (file_size == 0) {
const lldb::offset_t actual_file_size = file.GetByteSize();
@@ -449,7 +457,7 @@ DataBufferSP ObjectFile::ReadMemory(const ProcessSP &process_sp,
DataBufferSP data_sp;
if (process_sp) {
std::unique_ptr<DataBufferHeap> data_ap(new DataBufferHeap(byte_size, 0));
- Error error;
+ Status error;
const size_t bytes_read = process_sp->ReadMemory(
addr, data_ap->GetBytes(), data_ap->GetByteSize(), error);
if (bytes_read == byte_size)
@@ -488,7 +496,7 @@ size_t ObjectFile::ReadSectionData(const Section *section,
if (IsInMemory()) {
ProcessSP process_sp(m_process_wp.lock());
if (process_sp) {
- Error error;
+ Status error;
const addr_t base_load_addr =
section->GetLoadBaseAddress(&process_sp->GetTarget());
if (base_load_addr != LLDB_INVALID_ADDRESS)
@@ -648,3 +656,40 @@ ConstString ObjectFile::GetNextSyntheticSymbolName() {
file_name.GetCString());
return ConstString(ss.GetString());
}
+
+Status ObjectFile::LoadInMemory(Target &target, bool set_pc) {
+ Status error;
+ ProcessSP process = target.CalculateProcess();
+ if (!process)
+ return Status("No Process");
+ if (set_pc && !GetEntryPointAddress().IsValid())
+ return Status("No entry address in object file");
+
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return Status("No section in object file");
+ size_t section_count = section_list->GetNumSections(0);
+ for (size_t i = 0; i < section_count; ++i) {
+ SectionSP section_sp = section_list->GetSectionAtIndex(i);
+ addr_t addr = target.GetSectionLoadList().GetSectionLoadAddress(section_sp);
+ if (addr != LLDB_INVALID_ADDRESS) {
+ DataExtractor section_data;
+ // We can skip sections like bss
+ if (section_sp->GetFileSize() == 0)
+ continue;
+ section_sp->GetSectionData(section_data);
+ lldb::offset_t written = process->WriteMemory(
+ addr, section_data.GetDataStart(), section_data.GetByteSize(), error);
+ if (written != section_data.GetByteSize())
+ return error;
+ }
+ }
+ if (set_pc) {
+ ThreadList &thread_list = process->GetThreadList();
+ ThreadSP curr_thread(thread_list.GetSelectedThread());
+ RegisterContextSP reg_context(curr_thread->GetRegisterContext());
+ Address file_entry = GetEntryPointAddress();
+ reg_context->SetPC(file_entry.GetLoadAddress(&target));
+ }
+ return error;
+}
diff --git a/contrib/llvm/tools/lldb/source/Symbol/Symbol.cpp b/contrib/llvm/tools/lldb/source/Symbol/Symbol.cpp
index d243657..ab297ef 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/Symbol.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/Symbol.cpp
@@ -12,13 +12,13 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Symtab.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Symbol/SymbolContext.cpp b/contrib/llvm/tools/lldb/source/Symbol/SymbolContext.cpp
index e43a70f..4ac3501 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/SymbolContext.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/SymbolContext.cpp
@@ -9,7 +9,6 @@
#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/Host.h"
@@ -23,6 +22,7 @@
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -735,7 +735,7 @@ LineEntry SymbolContext::GetFunctionStartLineEntry() const {
bool SymbolContext::GetAddressRangeFromHereToEndLine(uint32_t end_line,
AddressRange &range,
- Error &error) {
+ Status &error) {
if (!line_entry.IsValid()) {
error.SetErrorString("Symbol context has no line table.");
return false;
@@ -799,6 +799,163 @@ bool SymbolContext::GetAddressRangeFromHereToEndLine(uint32_t end_line,
return true;
}
+const Symbol *
+SymbolContext::FindBestGlobalDataSymbol(const ConstString &name, Status &error) {
+ error.Clear();
+
+ if (!target_sp) {
+ return nullptr;
+ }
+
+ Target &target = *target_sp;
+ Module *module = module_sp.get();
+
+ auto ProcessMatches = [this, &name, &target, module]
+ (SymbolContextList &sc_list, Status &error) -> const Symbol* {
+ llvm::SmallVector<const Symbol *, 1> external_symbols;
+ llvm::SmallVector<const Symbol *, 1> internal_symbols;
+ const uint32_t matches = sc_list.GetSize();
+ for (uint32_t i = 0; i < matches; ++i) {
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(i, sym_ctx);
+ if (sym_ctx.symbol) {
+ const Symbol *symbol = sym_ctx.symbol;
+ const Address sym_address = symbol->GetAddress();
+
+ if (sym_address.IsValid()) {
+ switch (symbol->GetType()) {
+ case eSymbolTypeData:
+ case eSymbolTypeRuntime:
+ case eSymbolTypeAbsolute:
+ case eSymbolTypeObjCClass:
+ case eSymbolTypeObjCMetaClass:
+ case eSymbolTypeObjCIVar:
+ if (symbol->GetDemangledNameIsSynthesized()) {
+ // If the demangled name was synthesized, then don't use it
+ // for expressions. Only let the symbol match if the mangled
+ // named matches for these symbols.
+ if (symbol->GetMangled().GetMangledName() != name)
+ break;
+ }
+ if (symbol->IsExternal()) {
+ external_symbols.push_back(symbol);
+ } else {
+ internal_symbols.push_back(symbol);
+ }
+ break;
+ case eSymbolTypeReExported: {
+ ConstString reexport_name = symbol->GetReExportedSymbolName();
+ if (reexport_name) {
+ ModuleSP reexport_module_sp;
+ ModuleSpec reexport_module_spec;
+ reexport_module_spec.GetPlatformFileSpec() =
+ symbol->GetReExportedSymbolSharedLibrary();
+ if (reexport_module_spec.GetPlatformFileSpec()) {
+ reexport_module_sp =
+ target.GetImages().FindFirstModule(reexport_module_spec);
+ if (!reexport_module_sp) {
+ reexport_module_spec.GetPlatformFileSpec()
+ .GetDirectory()
+ .Clear();
+ reexport_module_sp =
+ target.GetImages().FindFirstModule(reexport_module_spec);
+ }
+ }
+ // Don't allow us to try and resolve a re-exported symbol if it is
+ // the same as the current symbol
+ if (name == symbol->GetReExportedSymbolName() &&
+ module == reexport_module_sp.get())
+ return nullptr;
+
+ return FindBestGlobalDataSymbol(
+ symbol->GetReExportedSymbolName(), error);
+ }
+ } break;
+
+ case eSymbolTypeCode: // We already lookup functions elsewhere
+ case eSymbolTypeVariable:
+ case eSymbolTypeLocal:
+ case eSymbolTypeParam:
+ case eSymbolTypeTrampoline:
+ case eSymbolTypeInvalid:
+ case eSymbolTypeException:
+ case eSymbolTypeSourceFile:
+ case eSymbolTypeHeaderFile:
+ case eSymbolTypeObjectFile:
+ case eSymbolTypeCommonBlock:
+ case eSymbolTypeBlock:
+ case eSymbolTypeVariableType:
+ case eSymbolTypeLineEntry:
+ case eSymbolTypeLineHeader:
+ case eSymbolTypeScopeBegin:
+ case eSymbolTypeScopeEnd:
+ case eSymbolTypeAdditional:
+ case eSymbolTypeCompiler:
+ case eSymbolTypeInstrumentation:
+ case eSymbolTypeUndefined:
+ case eSymbolTypeResolver:
+ break;
+ }
+ }
+ }
+ }
+
+ if (external_symbols.size() > 1) {
+ StreamString ss;
+ ss.Printf("Multiple external symbols found for '%s'\n", name.AsCString());
+ for (const Symbol *symbol : external_symbols) {
+ symbol->GetDescription(&ss, eDescriptionLevelFull, &target);
+ }
+ ss.PutChar('\n');
+ error.SetErrorString(ss.GetData());
+ return nullptr;
+ } else if (external_symbols.size()) {
+ return external_symbols[0];
+ } else if (internal_symbols.size() > 1) {
+ StreamString ss;
+ ss.Printf("Multiple internal symbols found for '%s'\n", name.AsCString());
+ for (const Symbol *symbol : internal_symbols) {
+ symbol->GetDescription(&ss, eDescriptionLevelVerbose, &target);
+ ss.PutChar('\n');
+ }
+ error.SetErrorString(ss.GetData());
+ return nullptr;
+ } else if (internal_symbols.size()) {
+ return internal_symbols[0];
+ } else {
+ return nullptr;
+ }
+ };
+
+ if (module) {
+ SymbolContextList sc_list;
+ module->FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list);
+ const Symbol *const module_symbol = ProcessMatches(sc_list, error);
+
+ if (!error.Success()) {
+ return nullptr;
+ } else if (module_symbol) {
+ return module_symbol;
+ }
+ }
+
+ {
+ SymbolContextList sc_list;
+ target.GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny,
+ sc_list);
+ const Symbol *const target_symbol = ProcessMatches(sc_list, error);
+
+ if (!error.Success()) {
+ return nullptr;
+ } else if (target_symbol) {
+ return target_symbol;
+ }
+ }
+
+ return nullptr; // no error; we just didn't find anything
+}
+
+
//----------------------------------------------------------------------
//
// SymbolContextSpecifier
diff --git a/contrib/llvm/tools/lldb/source/Symbol/SymbolFile.cpp b/contrib/llvm/tools/lldb/source/Symbol/SymbolFile.cpp
index 8d8b606..eb20b80 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/SymbolFile.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/SymbolFile.cpp
@@ -9,18 +9,22 @@
#include "lldb/Symbol/SymbolFile.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/TypeMap.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "lldb/lldb-private.h"
using namespace lldb_private;
+void SymbolFile::PreloadSymbols() {
+ // No-op for most implementations.
+}
+
SymbolFile *SymbolFile::FindPlugin(ObjectFile *obj_file) {
std::unique_ptr<SymbolFile> best_symfile_ap;
if (obj_file != nullptr) {
diff --git a/contrib/llvm/tools/lldb/source/Symbol/SymbolVendor.cpp b/contrib/llvm/tools/lldb/source/Symbol/SymbolVendor.cpp
index a0a40ef..f5a0873 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/SymbolVendor.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/SymbolVendor.cpp
@@ -15,10 +15,10 @@
// Project includes
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Symbol/Symtab.cpp b/contrib/llvm/tools/lldb/source/Symbol/Symtab.cpp
index 09cfd8e..3e2c965 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/Symtab.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/Symtab.cpp
@@ -13,14 +13,15 @@
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/STLUtils.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Symtab.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
@@ -219,7 +220,8 @@ void Symtab::InitNameIndexes() {
// Protected function, no need to lock mutex...
if (!m_name_indexes_computed) {
m_name_indexes_computed = true;
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s", LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION);
// Create the name index vector to be able to quickly search by name
const size_t num_symbols = m_symbols.size();
#if 1
@@ -262,36 +264,35 @@ void Symtab::InitNameIndexes() {
continue;
const Mangled &mangled = symbol->GetMangled();
- entry.cstring = mangled.GetMangledName().GetStringRef();
- if (!entry.cstring.empty()) {
+ entry.cstring = mangled.GetMangledName();
+ if (entry.cstring) {
m_name_to_index.Append(entry);
if (symbol->ContainsLinkerAnnotations()) {
// If the symbol has linker annotations, also add the version without
// the annotations.
entry.cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations(
- entry.cstring))
- .GetStringRef();
+ entry.cstring.GetStringRef()));
m_name_to_index.Append(entry);
}
const SymbolType symbol_type = symbol->GetType();
if (symbol_type == eSymbolTypeCode ||
symbol_type == eSymbolTypeResolver) {
- if (entry.cstring[0] == '_' && entry.cstring[1] == 'Z' &&
- (entry.cstring[2] != 'T' && // avoid virtual table, VTT structure,
- // typeinfo structure, and typeinfo
- // name
- entry.cstring[2] != 'G' && // avoid guard variables
- entry.cstring[2] != 'Z')) // named local entities (if we
+ llvm::StringRef entry_ref(entry.cstring.GetStringRef());
+ if (entry_ref[0] == '_' && entry_ref[1] == 'Z' &&
+ (entry_ref[2] != 'T' && // avoid virtual table, VTT structure,
+ // typeinfo structure, and typeinfo
+ // name
+ entry_ref[2] != 'G' && // avoid guard variables
+ entry_ref[2] != 'Z')) // named local entities (if we
// eventually handle eSymbolTypeData,
// we will want this back)
{
CPlusPlusLanguage::MethodName cxx_method(
mangled.GetDemangledName(lldb::eLanguageTypeC_plus_plus));
- entry.cstring =
- ConstString(cxx_method.GetBasename()).GetStringRef();
- if (!entry.cstring.empty()) {
+ entry.cstring = ConstString(cxx_method.GetBasename());
+ if (entry.cstring) {
// ConstString objects permanently store the string in the pool so
// calling
// GetCString() on the value gets us a const char * that will
@@ -299,16 +300,24 @@ void Symtab::InitNameIndexes() {
const char *const_context =
ConstString(cxx_method.GetContext()).GetCString();
- if (entry.cstring[0] == '~' ||
- !cxx_method.GetQualifiers().empty()) {
- // The first character of the demangled basename is '~' which
- // means we have a class destructor. We can use this information
- // to help us know what is a class and what isn't.
- if (class_contexts.find(const_context) == class_contexts.end())
- class_contexts.insert(const_context);
- m_method_to_index.Append(entry);
+ if (!const_context || const_context[0] == 0) {
+ // No context for this function so this has to be a basename
+ m_basename_to_index.Append(entry);
+ // If there is no context (no namespaces or class scopes that
+ // come before the function name) then this also could be a
+ // fullname.
+ m_name_to_index.Append(entry);
} else {
- if (const_context && const_context[0]) {
+ entry_ref = entry.cstring.GetStringRef();
+ if (entry_ref[0] == '~' ||
+ !cxx_method.GetQualifiers().empty()) {
+ // The first character of the demangled basename is '~' which
+ // means we have a class destructor. We can use this information
+ // to help us know what is a class and what isn't.
+ if (class_contexts.find(const_context) == class_contexts.end())
+ class_contexts.insert(const_context);
+ m_method_to_index.Append(entry);
+ } else {
if (class_contexts.find(const_context) !=
class_contexts.end()) {
// The current decl context is in our "class_contexts" which
@@ -325,9 +334,6 @@ void Symtab::InitNameIndexes() {
mangled_name_to_index.Append(entry);
symbol_contexts[entry.value] = const_context;
}
- } else {
- // No context for this function so this has to be a basename
- m_basename_to_index.Append(entry);
}
}
}
@@ -335,17 +341,15 @@ void Symtab::InitNameIndexes() {
}
}
- entry.cstring =
- mangled.GetDemangledName(symbol->GetLanguage()).GetStringRef();
- if (!entry.cstring.empty()) {
+ entry.cstring = mangled.GetDemangledName(symbol->GetLanguage());
+ if (entry.cstring) {
m_name_to_index.Append(entry);
if (symbol->ContainsLinkerAnnotations()) {
// If the symbol has linker annotations, also add the version without
// the annotations.
entry.cstring = ConstString(m_objfile->StripLinkerSymbolAnnotations(
- entry.cstring))
- .GetStringRef();
+ entry.cstring.GetStringRef()));
m_name_to_index.Append(entry);
}
}
@@ -353,15 +357,15 @@ void Symtab::InitNameIndexes() {
// If the demangled name turns out to be an ObjC name, and
// is a category name, add the version without categories to the index
// too.
- ObjCLanguage::MethodName objc_method(entry.cstring, true);
+ ObjCLanguage::MethodName objc_method(entry.cstring.GetStringRef(), true);
if (objc_method.IsValid(true)) {
- entry.cstring = objc_method.GetSelector().GetStringRef();
+ entry.cstring = objc_method.GetSelector();
m_selector_to_index.Append(entry);
ConstString objc_method_no_category(
objc_method.GetFullNameWithoutCategory(true));
if (objc_method_no_category) {
- entry.cstring = objc_method_no_category.GetStringRef();
+ entry.cstring = objc_method_no_category;
m_name_to_index.Append(entry);
}
}
@@ -421,11 +425,17 @@ void Symtab::InitNameIndexes() {
}
}
+void Symtab::PreloadSymbols() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ InitNameIndexes();
+}
+
void Symtab::AppendSymbolNamesToMap(const IndexCollection &indexes,
bool add_demangled, bool add_mangled,
NameToIndexMap &name_to_index_map) const {
if (add_demangled || add_mangled) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s", LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION);
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Create the name index vector to be able to quickly search by name
@@ -438,15 +448,14 @@ void Symtab::AppendSymbolNamesToMap(const IndexCollection &indexes,
const Mangled &mangled = symbol->GetMangled();
if (add_demangled) {
- entry.cstring =
- mangled.GetDemangledName(symbol->GetLanguage()).GetStringRef();
- if (!entry.cstring.empty())
+ entry.cstring = mangled.GetDemangledName(symbol->GetLanguage());
+ if (entry.cstring)
name_to_index_map.Append(entry);
}
if (add_mangled) {
- entry.cstring = mangled.GetMangledName().GetStringRef();
- if (!entry.cstring.empty())
+ entry.cstring = mangled.GetMangledName();
+ if (entry.cstring)
name_to_index_map.Append(entry);
}
}
@@ -588,7 +597,8 @@ void Symtab::SortSymbolIndexesByValue(std::vector<uint32_t> &indexes,
bool remove_duplicates) const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
// No need to sort if we have zero or one items...
if (indexes.size() <= 1)
return;
@@ -614,12 +624,13 @@ uint32_t Symtab::AppendSymbolIndexesWithName(const ConstString &symbol_name,
std::vector<uint32_t> &indexes) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s", LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION);
if (symbol_name) {
if (!m_name_indexes_computed)
InitNameIndexes();
- return m_name_to_index.GetValues(symbol_name.GetStringRef(), indexes);
+ return m_name_to_index.GetValues(symbol_name, indexes);
}
return 0;
}
@@ -630,7 +641,8 @@ uint32_t Symtab::AppendSymbolIndexesWithName(const ConstString &symbol_name,
std::vector<uint32_t> &indexes) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s", LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION);
if (symbol_name) {
const size_t old_size = indexes.size();
if (!m_name_indexes_computed)
@@ -638,7 +650,7 @@ uint32_t Symtab::AppendSymbolIndexesWithName(const ConstString &symbol_name,
std::vector<uint32_t> all_name_indexes;
const size_t name_match_count =
- m_name_to_index.GetValues(symbol_name.GetStringRef(), all_name_indexes);
+ m_name_to_index.GetValues(symbol_name, all_name_indexes);
for (size_t i = 0; i < name_match_count; ++i) {
if (CheckSymbolAtIndex(all_name_indexes[i], symbol_debug_type,
symbol_visibility))
@@ -759,7 +771,8 @@ Symtab::FindAllSymbolsWithNameAndType(const ConstString &name,
std::vector<uint32_t> &symbol_indexes) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s", LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION);
// Initialize all of the lookup by name indexes before converting NAME
// to a uniqued string NAME_STR below.
if (!m_name_indexes_computed)
@@ -778,7 +791,8 @@ size_t Symtab::FindAllSymbolsWithNameAndType(
Visibility symbol_visibility, std::vector<uint32_t> &symbol_indexes) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s", LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION);
// Initialize all of the lookup by name indexes before converting NAME
// to a uniqued string NAME_STR below.
if (!m_name_indexes_computed)
@@ -810,7 +824,8 @@ Symbol *Symtab::FindFirstSymbolWithNameAndType(const ConstString &name,
Visibility symbol_visibility) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- Timer scoped_timer(LLVM_PRETTY_FUNCTION, "%s", LLVM_PRETTY_FUNCTION);
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION);
if (!m_name_indexes_computed)
InitNameIndexes();
@@ -1062,8 +1077,6 @@ size_t Symtab::FindFunctionSymbols(const ConstString &name,
size_t count = 0;
std::vector<uint32_t> symbol_indexes;
- llvm::StringRef name_cstr = name.GetStringRef();
-
// eFunctionNameTypeAuto should be pre-resolved by a call to
// Module::LookupInfo::LookupInfo()
assert((name_type_mask & eFunctionNameTypeAuto) == 0);
@@ -1101,7 +1114,7 @@ size_t Symtab::FindFunctionSymbols(const ConstString &name,
if (!m_basename_to_index.IsEmpty()) {
const UniqueCStringMap<uint32_t>::Entry *match;
- for (match = m_basename_to_index.FindFirstValueForName(name_cstr);
+ for (match = m_basename_to_index.FindFirstValueForName(name);
match != nullptr;
match = m_basename_to_index.FindNextValueForName(match)) {
symbol_indexes.push_back(match->value);
@@ -1115,7 +1128,7 @@ size_t Symtab::FindFunctionSymbols(const ConstString &name,
if (!m_method_to_index.IsEmpty()) {
const UniqueCStringMap<uint32_t>::Entry *match;
- for (match = m_method_to_index.FindFirstValueForName(name_cstr);
+ for (match = m_method_to_index.FindFirstValueForName(name);
match != nullptr;
match = m_method_to_index.FindNextValueForName(match)) {
symbol_indexes.push_back(match->value);
@@ -1129,7 +1142,7 @@ size_t Symtab::FindFunctionSymbols(const ConstString &name,
if (!m_selector_to_index.IsEmpty()) {
const UniqueCStringMap<uint32_t>::Entry *match;
- for (match = m_selector_to_index.FindFirstValueForName(name_cstr);
+ for (match = m_selector_to_index.FindFirstValueForName(name);
match != nullptr;
match = m_selector_to_index.FindNextValueForName(match)) {
symbol_indexes.push_back(match->value);
diff --git a/contrib/llvm/tools/lldb/source/Symbol/Type.cpp b/contrib/llvm/tools/lldb/source/Symbol/Type.cpp
index 80d08bf7..53d9c5c 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/Type.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/Type.cpp
@@ -13,11 +13,11 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Scalar.h"
-#include "lldb/Core/StreamString.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/StreamString.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/ObjectFile.h"
@@ -410,7 +410,7 @@ bool Type::ReadFromMemory(ExecutionContext *exe_ctx, lldb::addr_t addr,
if (exe_ctx) {
Process *process = exe_ctx->GetProcessPtr();
if (process) {
- Error error;
+ Status error;
return exe_ctx->GetProcessPtr()->ReadMemory(addr, dst, byte_size,
error) == byte_size;
}
diff --git a/contrib/llvm/tools/lldb/source/Symbol/UnwindPlan.cpp b/contrib/llvm/tools/lldb/source/Symbol/UnwindPlan.cpp
index 8a20ef8..4c00143 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/UnwindPlan.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/UnwindPlan.cpp
@@ -9,11 +9,11 @@
#include "lldb/Symbol/UnwindPlan.h"
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Log.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Symbol/UnwindTable.cpp b/contrib/llvm/tools/lldb/source/Symbol/UnwindTable.cpp
index 336f0c3..405d577 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/UnwindTable.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/UnwindTable.cpp
@@ -44,38 +44,64 @@ void UnwindTable::Initialize() {
if (m_initialized) // check again once we've acquired the lock
return;
+ m_initialized = true;
SectionList *sl = m_object_file.GetSectionList();
- if (sl) {
- SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);
- if (sect.get()) {
- m_eh_frame_up.reset(new DWARFCallFrameInfo(m_object_file, sect,
- eRegisterKindEHFrame, true));
- }
- sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);
- if (sect.get()) {
- m_compact_unwind_up.reset(new CompactUnwindInfo(m_object_file, sect));
- }
- sect = sl->FindSectionByType(eSectionTypeARMexidx, true);
- if (sect.get()) {
- SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);
- if (sect_extab.get()) {
- m_arm_unwind_up.reset(
- new ArmUnwindInfo(m_object_file, sect, sect_extab));
- }
- }
+ if (!sl)
+ return;
+
+ SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);
+ if (sect.get()) {
+ m_eh_frame_up.reset(
+ new DWARFCallFrameInfo(m_object_file, sect, DWARFCallFrameInfo::EH));
}
- m_initialized = true;
+ sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true);
+ if (sect) {
+ m_debug_frame_up.reset(
+ new DWARFCallFrameInfo(m_object_file, sect, DWARFCallFrameInfo::DWARF));
+ }
+
+ sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);
+ if (sect) {
+ m_compact_unwind_up.reset(new CompactUnwindInfo(m_object_file, sect));
+ }
+
+ sect = sl->FindSectionByType(eSectionTypeARMexidx, true);
+ if (sect) {
+ SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);
+ if (sect_extab.get()) {
+ m_arm_unwind_up.reset(new ArmUnwindInfo(m_object_file, sect, sect_extab));
+ }
+ }
}
UnwindTable::~UnwindTable() {}
+llvm::Optional<AddressRange> UnwindTable::GetAddressRange(const Address &addr,
+ SymbolContext &sc) {
+ AddressRange range;
+
+ // First check the symbol context
+ if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
+ false, range) &&
+ range.GetBaseAddress().IsValid())
+ return range;
+
+ // Does the eh_frame unwind info has a function bounds for this addr?
+ if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range))
+ return range;
+
+ // Try debug_frame as well
+ if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))
+ return range;
+
+ return llvm::None;
+}
+
FuncUnwindersSP
UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,
SymbolContext &sc) {
- FuncUnwindersSP no_unwind_found;
-
Initialize();
std::lock_guard<std::mutex> guard(m_mutex);
@@ -96,23 +122,14 @@ UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,
return pos->second;
}
- AddressRange range;
- if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
- false, range) ||
- !range.GetBaseAddress().IsValid()) {
- // Does the eh_frame unwind info has a function bounds for this addr?
- if (m_eh_frame_up == nullptr ||
- !m_eh_frame_up->GetAddressRange(addr, range)) {
- return no_unwind_found;
- }
- }
+ auto range_or = GetAddressRange(addr, sc);
+ if (!range_or)
+ return nullptr;
- FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, range));
+ FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or));
m_unwinds.insert(insert_pos,
- std::make_pair(range.GetBaseAddress().GetFileAddress(),
+ std::make_pair(range_or->GetBaseAddress().GetFileAddress(),
func_unwinder_sp));
- // StreamFile s(stdout, false);
- // Dump (s);
return func_unwinder_sp;
}
@@ -121,26 +138,16 @@ UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,
// UnwindTable. This is intended for use by target modules show-unwind where we
// want to create
// new UnwindPlans, not re-use existing ones.
-
FuncUnwindersSP
UnwindTable::GetUncachedFuncUnwindersContainingAddress(const Address &addr,
SymbolContext &sc) {
- FuncUnwindersSP no_unwind_found;
Initialize();
- AddressRange range;
- if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
- false, range) ||
- !range.GetBaseAddress().IsValid()) {
- // Does the eh_frame unwind info has a function bounds for this addr?
- if (m_eh_frame_up == nullptr ||
- !m_eh_frame_up->GetAddressRange(addr, range)) {
- return no_unwind_found;
- }
- }
+ auto range_or = GetAddressRange(addr, sc);
+ if (!range_or)
+ return nullptr;
- FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, range));
- return func_unwinder_sp;
+ return std::make_shared<FuncUnwinders>(*this, *range_or);
}
void UnwindTable::Dump(Stream &s) {
@@ -161,6 +168,11 @@ DWARFCallFrameInfo *UnwindTable::GetEHFrameInfo() {
return m_eh_frame_up.get();
}
+DWARFCallFrameInfo *UnwindTable::GetDebugFrameInfo() {
+ Initialize();
+ return m_debug_frame_up.get();
+}
+
CompactUnwindInfo *UnwindTable::GetCompactUnwindInfo() {
Initialize();
return m_compact_unwind_up.get();
diff --git a/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp b/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp
index e17685e..ff32aa7 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp
@@ -10,8 +10,6 @@
#include "lldb/Symbol/Variable.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Symbol/Block.h"
@@ -30,6 +28,8 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
#include "llvm/ADT/Twine.h"
@@ -160,7 +160,7 @@ void Variable::Dump(Stream *s, bool show_context) const {
if (m_owner_scope) {
ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
if (module_sp)
- abi = ABI::FindPlugin(module_sp->GetArchitecture()).get();
+ abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture()).get();
}
m_location.GetDescription(s, lldb::eDescriptionLevelBrief,
loclist_base_addr, abi);
@@ -330,11 +330,11 @@ bool Variable::IsInScope(StackFrame *frame) {
return false;
}
-Error Variable::GetValuesForVariableExpressionPath(
+Status Variable::GetValuesForVariableExpressionPath(
llvm::StringRef variable_expr_path, ExecutionContextScope *scope,
GetVariableCallback callback, void *baton, VariableList &variable_list,
ValueObjectList &valobj_list) {
- Error error;
+ Status error;
if (!callback || variable_expr_path.empty()) {
error.SetErrorString("unknown error");
return error;
@@ -350,7 +350,7 @@ Error Variable::GetValuesForVariableExpressionPath(
return error;
}
for (uint32_t i = 0; i < valobj_list.GetSize();) {
- Error tmp_error;
+ Status tmp_error;
ValueObjectSP valobj_sp(
valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error));
if (tmp_error.Fail()) {
@@ -368,7 +368,7 @@ Error Variable::GetValuesForVariableExpressionPath(
valobj_list);
if (error.Success()) {
for (uint32_t i = 0; i < valobj_list.GetSize();) {
- Error tmp_error;
+ Status tmp_error;
ValueObjectSP valobj_sp(
valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error));
if (tmp_error.Fail()) {
@@ -471,7 +471,7 @@ bool Variable::DumpLocationForAddress(Stream *s, const Address &address) {
if (m_owner_scope) {
ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
if (module_sp)
- abi = ABI::FindPlugin(module_sp->GetArchitecture()).get();
+ abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture()).get();
}
const addr_t file_addr = address.GetFileAddress();
diff --git a/contrib/llvm/tools/lldb/source/Symbol/VariableList.cpp b/contrib/llvm/tools/lldb/source/Symbol/VariableList.cpp
index a81b95b..e7a482e 100644
--- a/contrib/llvm/tools/lldb/source/Symbol/VariableList.cpp
+++ b/contrib/llvm/tools/lldb/source/Symbol/VariableList.cpp
@@ -9,10 +9,10 @@
#include "lldb/Symbol/VariableList.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
+#include "lldb/Utility/RegularExpression.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ABI.cpp b/contrib/llvm/tools/lldb/source/Target/ABI.cpp
index 87363a3..72f58be 100644
--- a/contrib/llvm/tools/lldb/source/Target/ABI.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ABI.cpp
@@ -25,7 +25,7 @@ using namespace lldb;
using namespace lldb_private;
ABISP
-ABI::FindPlugin(const ArchSpec &arch) {
+ABI::FindPlugin(lldb::ProcessSP process_sp, const ArchSpec &arch) {
ABISP abi_sp;
ABICreateInstance create_callback;
@@ -33,7 +33,7 @@ ABI::FindPlugin(const ArchSpec &arch) {
(create_callback = PluginManager::GetABICreateCallbackAtIndex(idx)) !=
nullptr;
++idx) {
- abi_sp = create_callback(arch);
+ abi_sp = create_callback(process_sp, arch);
if (abi_sp)
return abi_sp;
@@ -42,8 +42,6 @@ ABI::FindPlugin(const ArchSpec &arch) {
return abi_sp;
}
-ABI::ABI() = default;
-
ABI::~ABI() = default;
bool ABI::GetRegisterInfoByName(const ConstString &name, RegisterInfo &info) {
diff --git a/contrib/llvm/tools/lldb/source/Target/FileAction.cpp b/contrib/llvm/tools/lldb/source/Target/FileAction.cpp
index 7c2567e..c9cc325 100644
--- a/contrib/llvm/tools/lldb/source/Target/FileAction.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/FileAction.cpp
@@ -9,9 +9,9 @@
#include <fcntl.h>
-#include "lldb/Core/Stream.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Target/FileAction.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/InstrumentationRuntime.cpp b/contrib/llvm/tools/lldb/source/Target/InstrumentationRuntime.cpp
index f3bc145..ac8b5df 100644
--- a/contrib/llvm/tools/lldb/source/Target/InstrumentationRuntime.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/InstrumentationRuntime.cpp
@@ -15,8 +15,8 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/RegularExpression.h"
#include "lldb/lldb-private.h"
using namespace lldb;
diff --git a/contrib/llvm/tools/lldb/source/Target/Language.cpp b/contrib/llvm/tools/lldb/source/Target/Language.cpp
index 938d80a..cde6f86 100644
--- a/contrib/llvm/tools/lldb/source/Target/Language.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/Language.cpp
@@ -15,10 +15,12 @@
#include "lldb/Target/Language.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Stream.h"
+
+#include "llvm/Support/Threading.h"
using namespace lldb;
using namespace lldb_private;
@@ -29,9 +31,9 @@ typedef std::map<lldb::LanguageType, LanguageUP> LanguagesMap;
static LanguagesMap &GetLanguagesMap() {
static LanguagesMap *g_map = nullptr;
- static std::once_flag g_initialize;
+ static llvm::once_flag g_initialize;
- std::call_once(g_initialize, [] {
+ llvm::call_once(g_initialize, [] {
g_map = new LanguagesMap(); // NOTE: INTENTIONAL LEAK due to global
// destructor chain
});
@@ -40,9 +42,9 @@ static LanguagesMap &GetLanguagesMap() {
}
static std::mutex &GetLanguagesMutex() {
static std::mutex *g_mutex = nullptr;
- static std::once_flag g_initialize;
+ static llvm::once_flag g_initialize;
- std::call_once(g_initialize, [] {
+ llvm::call_once(g_initialize, [] {
g_mutex = new std::mutex(); // NOTE: INTENTIONAL LEAK due to global
// destructor chain
});
@@ -385,7 +387,7 @@ DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() {
return nullptr;
}
-LazyBool Language::IsLogicalTrue(ValueObject &valobj, Error &error) {
+LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) {
return eLazyBoolCalculate;
}
diff --git a/contrib/llvm/tools/lldb/source/Target/LanguageRuntime.cpp b/contrib/llvm/tools/lldb/source/Target/LanguageRuntime.cpp
index cacb491..bd02121 100644
--- a/contrib/llvm/tools/lldb/source/Target/LanguageRuntime.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/LanguageRuntime.cpp
@@ -12,7 +12,6 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Target/LanguageRuntime.h"
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/SearchFilter.h"
@@ -90,7 +89,8 @@ ExceptionSearchFilter::DoCopyForBreakpoint(Breakpoint &breakpoint) {
}
SearchFilter *ExceptionSearchFilter::CreateFromStructuredData(
- Target &target, const StructuredData::Dictionary &data_dict, Error &error) {
+ Target &target, const StructuredData::Dictionary &data_dict,
+ Status &error) {
SearchFilter *result = nullptr;
return result;
}
diff --git a/contrib/llvm/tools/lldb/source/Target/Memory.cpp b/contrib/llvm/tools/lldb/source/Target/Memory.cpp
index 775d0b3..ced3594 100644
--- a/contrib/llvm/tools/lldb/source/Target/Memory.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/Memory.cpp
@@ -13,11 +13,11 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Core/State.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -129,7 +129,8 @@ bool MemoryCache::RemoveInvalidRange(lldb::addr_t base_addr,
return false;
}
-size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len, Error &error) {
+size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len,
+ Status &error) {
size_t bytes_left = dst_len;
// Check the L1 cache for a range that contain the entire memory read.
@@ -252,146 +253,78 @@ size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len, Error &error) {
AllocatedBlock::AllocatedBlock(lldb::addr_t addr, uint32_t byte_size,
uint32_t permissions, uint32_t chunk_size)
- : m_addr(addr), m_byte_size(byte_size), m_permissions(permissions),
- m_chunk_size(chunk_size), m_offset_to_chunk_size()
-// m_allocated (byte_size / chunk_size)
+ : m_range(addr, byte_size), m_permissions(permissions),
+ m_chunk_size(chunk_size)
{
+ // The entire address range is free to start with.
+ m_free_blocks.Append(m_range);
assert(byte_size > chunk_size);
}
AllocatedBlock::~AllocatedBlock() {}
lldb::addr_t AllocatedBlock::ReserveBlock(uint32_t size) {
- addr_t addr = LLDB_INVALID_ADDRESS;
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
- if (size <= m_byte_size) {
- const uint32_t needed_chunks = CalculateChunksNeededForSize(size);
-
- if (m_offset_to_chunk_size.empty()) {
- m_offset_to_chunk_size[0] = needed_chunks;
- if (log)
- log->Printf("[1] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) "
- "=> offset = 0x%x, %u %u bit chunks",
- (void *)this, size, size, 0, needed_chunks, m_chunk_size);
- addr = m_addr;
- } else {
- uint32_t last_offset = 0;
- OffsetToChunkSize::const_iterator pos = m_offset_to_chunk_size.begin();
- OffsetToChunkSize::const_iterator end = m_offset_to_chunk_size.end();
- while (pos != end) {
- if (pos->first > last_offset) {
- const uint32_t bytes_available = pos->first - last_offset;
- const uint32_t num_chunks =
- CalculateChunksNeededForSize(bytes_available);
- if (num_chunks >= needed_chunks) {
- m_offset_to_chunk_size[last_offset] = needed_chunks;
- if (log)
- log->Printf("[2] AllocatedBlock::ReserveBlock(%p) (size = %u "
- "(0x%x)) => offset = 0x%x, %u %u bit chunks - "
- "num_chunks %zu",
- (void *)this, size, size, last_offset, needed_chunks,
- m_chunk_size, m_offset_to_chunk_size.size());
- addr = m_addr + last_offset;
- break;
- }
- }
-
- last_offset = pos->first + pos->second * m_chunk_size;
-
- if (++pos == end) {
- // Last entry...
- const uint32_t chunks_left =
- CalculateChunksNeededForSize(m_byte_size - last_offset);
- if (chunks_left >= needed_chunks) {
- m_offset_to_chunk_size[last_offset] = needed_chunks;
- if (log)
- log->Printf("[3] AllocatedBlock::ReserveBlock(%p) (size = %u "
- "(0x%x)) => offset = 0x%x, %u %u bit chunks - "
- "num_chunks %zu",
- (void *)this, size, size, last_offset, needed_chunks,
- m_chunk_size, m_offset_to_chunk_size.size());
- addr = m_addr + last_offset;
- break;
- }
- }
+ // We must return something valid for zero bytes.
+ if (size == 0)
+ size = 1;
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ const size_t free_count = m_free_blocks.GetSize();
+ for (size_t i=0; i<free_count; ++i)
+ {
+ auto &free_block = m_free_blocks.GetEntryRef(i);
+ const lldb::addr_t range_size = free_block.GetByteSize();
+ if (range_size >= size)
+ {
+ // We found a free block that is big enough for our data. Figure out how
+ // many chunks we will need and calculate the resulting block size we will
+ // reserve.
+ addr_t addr = free_block.GetRangeBase();
+ size_t num_chunks = CalculateChunksNeededForSize(size);
+ lldb::addr_t block_size = num_chunks * m_chunk_size;
+ lldb::addr_t bytes_left = range_size - block_size;
+ if (bytes_left == 0)
+ {
+ // The newly allocated block will take all of the bytes in this
+ // available block, so we can just add it to the allocated ranges and
+ // remove the range from the free ranges.
+ m_reserved_blocks.Insert(free_block, false);
+ m_free_blocks.RemoveEntryAtIndex(i);
+ }
+ else
+ {
+ // Make the new allocated range and add it to the allocated ranges.
+ Range<lldb::addr_t, uint32_t> reserved_block(free_block);
+ reserved_block.SetByteSize(block_size);
+ // Insert the reserved range and don't combine it with other blocks
+ // in the reserved blocks list.
+ m_reserved_blocks.Insert(reserved_block, false);
+ // Adjust the free range in place since we won't change the sorted
+ // ordering of the m_free_blocks list.
+ free_block.SetRangeBase(reserved_block.GetRangeEnd());
+ free_block.SetByteSize(bytes_left);
}
+ LLDB_LOGV(log, "({0}) (size = {1} ({1:x})) => {2:x}", this, size, addr);
+ return addr;
}
- // const uint32_t total_chunks = m_allocated.size ();
- // uint32_t unallocated_idx = 0;
- // uint32_t allocated_idx = m_allocated.find_first();
- // uint32_t first_chunk_idx = UINT32_MAX;
- // uint32_t num_chunks;
- // while (1)
- // {
- // if (allocated_idx == UINT32_MAX)
- // {
- // // No more bits are set starting from unallocated_idx, so
- // we
- // // either have enough chunks for the request, or we don't.
- // // Either way we break out of the while loop...
- // num_chunks = total_chunks - unallocated_idx;
- // if (needed_chunks <= num_chunks)
- // first_chunk_idx = unallocated_idx;
- // break;
- // }
- // else if (allocated_idx > unallocated_idx)
- // {
- // // We have some allocated chunks, check if there are
- // enough
- // // free chunks to satisfy the request?
- // num_chunks = allocated_idx - unallocated_idx;
- // if (needed_chunks <= num_chunks)
- // {
- // // Yep, we have enough!
- // first_chunk_idx = unallocated_idx;
- // break;
- // }
- // }
- //
- // while (unallocated_idx < total_chunks)
- // {
- // if (m_allocated[unallocated_idx])
- // ++unallocated_idx;
- // else
- // break;
- // }
- //
- // if (unallocated_idx >= total_chunks)
- // break;
- //
- // allocated_idx = m_allocated.find_next(unallocated_idx);
- // }
- //
- // if (first_chunk_idx != UINT32_MAX)
- // {
- // const uint32_t end_bit_idx = unallocated_idx + needed_chunks;
- // for (uint32_t idx = first_chunk_idx; idx < end_bit_idx; ++idx)
- // m_allocated.set(idx);
- // return m_addr + m_chunk_size * first_chunk_idx;
- // }
}
- if (log)
- log->Printf("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => "
- "0x%16.16" PRIx64,
- (void *)this, size, size, (uint64_t)addr);
- return addr;
+ LLDB_LOGV(log, "({0}) (size = {1} ({1:x})) => {2:x}", this, size,
+ LLDB_INVALID_ADDRESS);
+ return LLDB_INVALID_ADDRESS;
}
bool AllocatedBlock::FreeBlock(addr_t addr) {
- uint32_t offset = addr - m_addr;
- OffsetToChunkSize::iterator pos = m_offset_to_chunk_size.find(offset);
bool success = false;
- if (pos != m_offset_to_chunk_size.end()) {
- m_offset_to_chunk_size.erase(pos);
+ auto entry_idx = m_reserved_blocks.FindEntryIndexThatContains(addr);
+ if (entry_idx != UINT32_MAX)
+ {
+ m_free_blocks.Insert(m_reserved_blocks.GetEntryRef(entry_idx), true);
+ m_reserved_blocks.RemoveEntryAtIndex(entry_idx);
success = true;
}
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
- if (log)
- log->Printf("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64
- ") => %i, num_chunks: %zu",
- (void *)this, (uint64_t)addr, success,
- m_offset_to_chunk_size.size());
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ LLDB_LOGV(log, "({0}) (addr = {1:x}) => {2}", this, addr, success);
return success;
}
@@ -412,7 +345,7 @@ void AllocatedMemoryCache::Clear() {
AllocatedMemoryCache::AllocatedBlockSP
AllocatedMemoryCache::AllocatePage(uint32_t byte_size, uint32_t permissions,
- uint32_t chunk_size, Error &error) {
+ uint32_t chunk_size, Status &error) {
AllocatedBlockSP block_sp;
const size_t page_size = 4096;
const size_t num_pages = (byte_size + page_size - 1) / page_size;
@@ -438,7 +371,7 @@ AllocatedMemoryCache::AllocatePage(uint32_t byte_size, uint32_t permissions,
lldb::addr_t AllocatedMemoryCache::AllocateMemory(size_t byte_size,
uint32_t permissions,
- Error &error) {
+ Status &error) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
addr_t addr = LLDB_INVALID_ADDRESS;
diff --git a/contrib/llvm/tools/lldb/source/Utility/ModuleCache.cpp b/contrib/llvm/tools/lldb/source/Target/ModuleCache.cpp
index 889cd8f..2b65477 100644
--- a/contrib/llvm/tools/lldb/source/Utility/ModuleCache.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ModuleCache.cpp
@@ -7,15 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#include "ModuleCache.h"
+#include "lldb/Target/ModuleCache.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/File.h"
-#include "lldb/Host/FileSystem.h"
#include "lldb/Host/LockFile.h"
+#include "lldb/Utility/Log.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
@@ -55,25 +54,20 @@ private:
FileSpec m_file_spec;
public:
- ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Error &error);
+ ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Status &error);
void Delete();
};
-FileSpec JoinPath(const FileSpec &path1, const char *path2) {
+static FileSpec JoinPath(const FileSpec &path1, const char *path2) {
FileSpec result_spec(path1);
result_spec.AppendPathComponent(path2);
return result_spec;
}
-Error MakeDirectory(const FileSpec &dir_path) {
- if (dir_path.Exists()) {
- if (!dir_path.IsDirectory())
- return Error("Invalid existing path");
+static Status MakeDirectory(const FileSpec &dir_path) {
+ namespace fs = llvm::sys::fs;
- return Error();
- }
-
- return FileSystem::MakeDirectory(dir_path, eFilePermissionsDirectoryDefault);
+ return fs::create_directories(dir_path.GetPath(), true, fs::perms::owner_all);
}
FileSpec GetModuleDirectory(const FileSpec &root_dir_spec, const UUID &uuid) {
@@ -98,7 +92,7 @@ void DeleteExistingModule(const FileSpec &root_dir_spec,
if (!module_uuid.IsValid())
return;
- Error error;
+ Status error;
ModuleLock lock(root_dir_spec, module_uuid, error);
if (error.Fail()) {
if (log)
@@ -106,15 +100,16 @@ void DeleteExistingModule(const FileSpec &root_dir_spec,
module_uuid.GetAsString().c_str(), error.AsCString());
}
- auto link_count = FileSystem::GetHardlinkCount(sysroot_module_path_spec);
- if (link_count == -1)
+ namespace fs = llvm::sys::fs;
+ fs::file_status st;
+ if (status(sysroot_module_path_spec.GetPath(), st))
return;
- if (link_count > 2) // module is referred by other hosts.
+ if (st.getLinkCount() > 2) // module is referred by other hosts.
return;
const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid);
- FileSystem::DeleteDirectory(module_spec_dir, true);
+ llvm::sys::fs::remove_directories(module_spec_dir.GetPath());
lock.Delete();
}
@@ -124,24 +119,23 @@ void DecrementRefExistingModule(const FileSpec &root_dir_spec,
DeleteExistingModule(root_dir_spec, sysroot_module_path_spec);
// Remove sysroot link.
- FileSystem::Unlink(sysroot_module_path_spec);
+ llvm::sys::fs::remove(sysroot_module_path_spec.GetPath());
FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec);
- if (symfile_spec.Exists()) // delete module's symbol file if exists.
- FileSystem::Unlink(symfile_spec);
+ llvm::sys::fs::remove(symfile_spec.GetPath());
}
-Error CreateHostSysRootModuleLink(const FileSpec &root_dir_spec,
- const char *hostname,
- const FileSpec &platform_module_spec,
- const FileSpec &local_module_spec,
- bool delete_existing) {
+Status CreateHostSysRootModuleLink(const FileSpec &root_dir_spec,
+ const char *hostname,
+ const FileSpec &platform_module_spec,
+ const FileSpec &local_module_spec,
+ bool delete_existing) {
const auto sysroot_module_path_spec =
JoinPath(JoinPath(root_dir_spec, hostname),
platform_module_spec.GetPath().c_str());
if (sysroot_module_path_spec.Exists()) {
if (!delete_existing)
- return Error();
+ return Status();
DecrementRefExistingModule(root_dir_spec, sysroot_module_path_spec);
}
@@ -151,13 +145,14 @@ Error CreateHostSysRootModuleLink(const FileSpec &root_dir_spec,
if (error.Fail())
return error;
- return FileSystem::Hardlink(sysroot_module_path_spec, local_module_spec);
+ return llvm::sys::fs::create_hard_link(local_module_spec.GetPath(),
+ sysroot_module_path_spec.GetPath());
}
} // namespace
ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid,
- Error &error) {
+ Status &error) {
const auto lock_dir_spec = JoinPath(root_dir_spec, kLockDirName);
error = MakeDirectory(lock_dir_spec);
if (error.Fail())
@@ -184,14 +179,14 @@ void ModuleLock::Delete() {
return;
m_file.Close();
- FileSystem::Unlink(m_file_spec);
+ llvm::sys::fs::remove(m_file_spec.GetPath());
}
/////////////////////////////////////////////////////////////////////////
-Error ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec, const FileSpec &tmp_file,
- const FileSpec &target_file) {
+Status ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname,
+ const ModuleSpec &module_spec, const FileSpec &tmp_file,
+ const FileSpec &target_file) {
const auto module_spec_dir =
GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
const auto module_file_path =
@@ -201,27 +196,27 @@ Error ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname,
const auto err_code =
llvm::sys::fs::rename(tmp_file_path, module_file_path.GetPath());
if (err_code)
- return Error("Failed to rename file %s to %s: %s", tmp_file_path.c_str(),
- module_file_path.GetPath().c_str(),
- err_code.message().c_str());
+ return Status("Failed to rename file %s to %s: %s", tmp_file_path.c_str(),
+ module_file_path.GetPath().c_str(),
+ err_code.message().c_str());
const auto error = CreateHostSysRootModuleLink(
root_dir_spec, hostname, target_file, module_file_path, true);
if (error.Fail())
- return Error("Failed to create link to %s: %s",
- module_file_path.GetPath().c_str(), error.AsCString());
- return Error();
+ return Status("Failed to create link to %s: %s",
+ module_file_path.GetPath().c_str(), error.AsCString());
+ return Status();
}
-Error ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
- const ModuleSpec &module_spec,
- ModuleSP &cached_module_sp, bool *did_create_ptr) {
+Status ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
+ const ModuleSpec &module_spec,
+ ModuleSP &cached_module_sp, bool *did_create_ptr) {
const auto find_it =
m_loaded_modules.find(module_spec.GetUUID().GetAsString());
if (find_it != m_loaded_modules.end()) {
cached_module_sp = (*find_it).second.lock();
if (cached_module_sp)
- return Error();
+ return Status();
m_loaded_modules.erase(find_it);
}
@@ -231,10 +226,10 @@ Error ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
module_spec_dir, module_spec.GetFileSpec().GetFilename().AsCString());
if (!module_file_path.Exists())
- return Error("Module %s not found", module_file_path.GetPath().c_str());
+ return Status("Module %s not found", module_file_path.GetPath().c_str());
if (module_file_path.GetByteSize() != module_spec.GetObjectSize())
- return Error("Module %s has invalid file size",
- module_file_path.GetPath().c_str());
+ return Status("Module %s has invalid file size",
+ module_file_path.GetPath().c_str());
// We may have already cached module but downloaded from an another host - in
// this case let's create a link to it.
@@ -242,8 +237,8 @@ Error ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
module_spec.GetFileSpec(),
module_file_path, false);
if (error.Fail())
- return Error("Failed to create link to %s: %s",
- module_file_path.GetPath().c_str(), error.AsCString());
+ return Status("Failed to create link to %s: %s",
+ module_file_path.GetPath().c_str(), error.AsCString());
auto cached_module_spec(module_spec);
cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5
@@ -263,16 +258,16 @@ Error ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
m_loaded_modules.insert(
std::make_pair(module_spec.GetUUID().GetAsString(), cached_module_sp));
- return Error();
+ return Status();
}
-Error ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
- const char *hostname,
- const ModuleSpec &module_spec,
- const ModuleDownloader &module_downloader,
- const SymfileDownloader &symfile_downloader,
- lldb::ModuleSP &cached_module_sp,
- bool *did_create_ptr) {
+Status ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
+ const char *hostname,
+ const ModuleSpec &module_spec,
+ const ModuleDownloader &module_downloader,
+ const SymfileDownloader &symfile_downloader,
+ lldb::ModuleSP &cached_module_sp,
+ bool *did_create_ptr) {
const auto module_spec_dir =
GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
auto error = MakeDirectory(module_spec_dir);
@@ -281,9 +276,9 @@ Error ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
ModuleLock lock(root_dir_spec, module_spec.GetUUID(), error);
if (error.Fail())
- return Error("Failed to lock module %s: %s",
- module_spec.GetUUID().GetAsString().c_str(),
- error.AsCString());
+ return Status("Failed to lock module %s: %s",
+ module_spec.GetUUID().GetAsString().c_str(),
+ error.AsCString());
const auto escaped_hostname(GetEscapedHostname(hostname));
// Check local cache for a module.
@@ -296,13 +291,13 @@ Error ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
error = module_downloader(module_spec, tmp_download_file_spec);
llvm::FileRemover tmp_file_remover(tmp_download_file_spec.GetPath());
if (error.Fail())
- return Error("Failed to download module: %s", error.AsCString());
+ return Status("Failed to download module: %s", error.AsCString());
// Put downloaded file into local module cache.
error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
tmp_download_file_spec, module_spec.GetFileSpec());
if (error.Fail())
- return Error("Failed to put module into cache: %s", error.AsCString());
+ return Status("Failed to put module into cache: %s", error.AsCString());
tmp_file_remover.releaseFile();
error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
@@ -320,17 +315,18 @@ Error ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
// module might
// contain the necessary symbols and the debugging is also possible without
// a symfile.
- return Error();
+ return Status();
error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
tmp_download_sym_file_spec,
GetSymbolFileSpec(module_spec.GetFileSpec()));
if (error.Fail())
- return Error("Failed to put symbol file into cache: %s", error.AsCString());
+ return Status("Failed to put symbol file into cache: %s",
+ error.AsCString());
tmp_symfile_remover.releaseFile();
FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
- return Error();
+ return Status();
}
diff --git a/contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp b/contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp
index 3ee4dd3..d3cc7c0 100644
--- a/contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp
@@ -8,11 +8,9 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Type.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/MappedHash.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/SymbolContext.h"
@@ -21,6 +19,8 @@
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Timer.h"
#include "llvm/ADT/StringRef.h"
@@ -250,7 +250,7 @@ ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) {
Process *process = exe_ctx.GetProcessPtr();
if (process) {
- Error error;
+ Status error;
ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
if (isa != LLDB_INVALID_ADDRESS)
objc_class_sp = GetClassDescriptorFromISA(isa);
@@ -377,9 +377,9 @@ bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(
void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(
Stream &stream, lldb::DescriptionLevel level) {}
-Error ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(
+Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(
Args &args) {
- Error error;
+ Status error;
if (args.GetArgumentCount() > 0)
error.SetErrorString(
"The ObjC Exception breakpoint doesn't support extra options.");
diff --git a/contrib/llvm/tools/lldb/source/Target/PathMappingList.cpp b/contrib/llvm/tools/lldb/source/Target/PathMappingList.cpp
index 90fff57..b834a36 100644
--- a/contrib/llvm/tools/lldb/source/Target/PathMappingList.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/PathMappingList.cpp
@@ -14,11 +14,11 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Target/PathMappingList.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/Platform.cpp b/contrib/llvm/tools/lldb/source/Target/Platform.cpp
index d8db536..1d72887 100644
--- a/contrib/llvm/tools/lldb/source/Target/Platform.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/Platform.cpp
@@ -18,30 +18,32 @@
#include "llvm/Support/Path.h"
// Project includes
-#include "Utility/ModuleCache.h"
#include "lldb/Breakpoint/BreakpointIDList.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StructuredData.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/Property.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ModuleCache.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
-#include "lldb/Utility/Utils.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StructuredData.h"
+
+#include "llvm/Support/FileSystem.h"
// Define these constants from POSIX mman.h rather than include the file
// so that they will be correct even when compiled on Linux.
@@ -168,11 +170,11 @@ void Platform::SetHostPlatform(const lldb::PlatformSP &platform_sp) {
}
}
-Error Platform::GetFileWithUUID(const FileSpec &platform_file,
- const UUID *uuid_ptr, FileSpec &local_file) {
+Status Platform::GetFileWithUUID(const FileSpec &platform_file,
+ const UUID *uuid_ptr, FileSpec &local_file) {
// Default to the local case
local_file = platform_file;
- return Error();
+ return Status();
}
FileSpecList
@@ -215,11 +217,11 @@ Platform::LocateExecutableScriptingResources(Target *target, Module &module,
// return PlatformSP();
//}
-Error Platform::GetSharedModule(const ModuleSpec &module_spec, Process *process,
- ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
- ModuleSP *old_module_sp_ptr,
- bool *did_create_ptr) {
+Status Platform::GetSharedModule(const ModuleSpec &module_spec,
+ Process *process, ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr) {
if (IsHost())
return ModuleList::GetSharedModule(
module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr,
@@ -227,7 +229,7 @@ Error Platform::GetSharedModule(const ModuleSpec &module_spec, Process *process,
return GetRemoteSharedModule(module_spec, process, module_sp,
[&](const ModuleSpec &spec) {
- Error error = ModuleList::GetSharedModule(
+ Status error = ModuleList::GetSharedModule(
spec, module_sp, module_search_paths_ptr,
old_module_sp_ptr, did_create_ptr, false);
if (error.Success() && module_sp)
@@ -265,7 +267,7 @@ PlatformSP Platform::Find(const ConstString &name) {
return PlatformSP();
}
-PlatformSP Platform::Create(const ConstString &name, Error &error) {
+PlatformSP Platform::Create(const ConstString &name, Status &error) {
PlatformCreateInstance create_callback = nullptr;
lldb::PlatformSP platform_sp;
if (name) {
@@ -293,7 +295,7 @@ PlatformSP Platform::Create(const ConstString &name, Error &error) {
}
PlatformSP Platform::Create(const ArchSpec &arch, ArchSpec *platform_arch_ptr,
- Error &error) {
+ Status &error) {
lldb::PlatformSP platform_sp;
if (arch.IsValid()) {
// Scope for locker
@@ -523,11 +525,11 @@ void Platform::AddClangModuleCompilationOptions(
FileSpec Platform::GetWorkingDirectory() {
if (IsHost()) {
- char cwd[PATH_MAX];
- if (getcwd(cwd, sizeof(cwd)))
- return FileSpec{cwd, true};
- else
+ llvm::SmallString<64> cwd;
+ if (llvm::sys::fs::current_path(cwd))
return FileSpec{};
+ else
+ return FileSpec(cwd, true);
} else {
if (!m_working_dir)
m_working_dir = GetRemoteWorkingDirectory();
@@ -538,26 +540,27 @@ FileSpec Platform::GetWorkingDirectory() {
struct RecurseCopyBaton {
const FileSpec &dst;
Platform *platform_ptr;
- Error error;
+ Status error;
};
static FileSpec::EnumerateDirectoryResult
-RecurseCopy_Callback(void *baton, FileSpec::FileType file_type,
+RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft,
const FileSpec &src) {
RecurseCopyBaton *rc_baton = (RecurseCopyBaton *)baton;
- switch (file_type) {
- case FileSpec::eFileTypePipe:
- case FileSpec::eFileTypeSocket:
+ namespace fs = llvm::sys::fs;
+ switch (ft) {
+ case fs::file_type::fifo_file:
+ case fs::file_type::socket_file:
// we have no way to copy pipes and sockets - ignore them and continue
return FileSpec::eEnumerateDirectoryResultNext;
break;
- case FileSpec::eFileTypeDirectory: {
+ case fs::file_type::directory_file: {
// make the new directory and get in there
FileSpec dst_dir = rc_baton->dst;
if (!dst_dir.GetFilename())
dst_dir.GetFilename() = src.GetLastPathComponent();
- Error error = rc_baton->platform_ptr->MakeDirectory(
+ Status error = rc_baton->platform_ptr->MakeDirectory(
dst_dir, lldb::eFilePermissionsDirectoryDefault);
if (error.Fail()) {
rc_baton->error.SetErrorStringWithFormat(
@@ -572,7 +575,8 @@ RecurseCopy_Callback(void *baton, FileSpec::FileType file_type,
// when we enumerate we can quickly fill in the filename for dst copies
FileSpec recurse_dst;
recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str());
- RecurseCopyBaton rc_baton2 = {recurse_dst, rc_baton->platform_ptr, Error()};
+ RecurseCopyBaton rc_baton2 = {recurse_dst, rc_baton->platform_ptr,
+ Status()};
FileSpec::EnumerateDirectory(src_dir_path, true, true, true,
RecurseCopy_Callback, &rc_baton2);
if (rc_baton2.error.Fail()) {
@@ -582,7 +586,7 @@ RecurseCopy_Callback(void *baton, FileSpec::FileType file_type,
return FileSpec::eEnumerateDirectoryResultNext;
} break;
- case FileSpec::eFileTypeSymbolicLink: {
+ case fs::file_type::symlink_file: {
// copy the file and keep going
FileSpec dst_file = rc_baton->dst;
if (!dst_file.GetFilename())
@@ -604,12 +608,12 @@ RecurseCopy_Callback(void *baton, FileSpec::FileType file_type,
return FileSpec::eEnumerateDirectoryResultNext;
} break;
- case FileSpec::eFileTypeRegular: {
+ case fs::file_type::regular_file: {
// copy the file and keep going
FileSpec dst_file = rc_baton->dst;
if (!dst_file.GetFilename())
dst_file.GetFilename() = src.GetFilename();
- Error err = rc_baton->platform_ptr->PutFile(src, dst_file);
+ Status err = rc_baton->platform_ptr->PutFile(src, dst_file);
if (err.Fail()) {
rc_baton->error.SetErrorString(err.AsCString());
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
@@ -617,19 +621,17 @@ RecurseCopy_Callback(void *baton, FileSpec::FileType file_type,
return FileSpec::eEnumerateDirectoryResultNext;
} break;
- case FileSpec::eFileTypeInvalid:
- case FileSpec::eFileTypeOther:
- case FileSpec::eFileTypeUnknown:
+ default:
rc_baton->error.SetErrorStringWithFormat(
"invalid file detected during copy: %s", src.GetPath().c_str());
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
break;
}
- llvm_unreachable("Unhandled FileSpec::FileType!");
+ llvm_unreachable("Unhandled file_type!");
}
-Error Platform::Install(const FileSpec &src, const FileSpec &dst) {
- Error error;
+Status Platform::Install(const FileSpec &src, const FileSpec &dst) {
+ Status error;
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
if (log)
@@ -693,10 +695,10 @@ Error Platform::Install(const FileSpec &src, const FileSpec &dst) {
if (GetSupportsRSync()) {
error = PutFile(src, dst);
} else {
- switch (src.GetFileType()) {
- case FileSpec::eFileTypeDirectory: {
- if (GetFileExists(fixed_dst))
- Unlink(fixed_dst);
+ namespace fs = llvm::sys::fs;
+ switch (fs::get_file_type(src.GetPath(), false)) {
+ case fs::file_type::directory_file: {
+ llvm::sys::fs::remove(fixed_dst.GetPath());
uint32_t permissions = src.GetPermissions();
if (permissions == 0)
permissions = eFilePermissionsDirectoryDefault;
@@ -707,36 +709,32 @@ Error Platform::Install(const FileSpec &src, const FileSpec &dst) {
FileSpec recurse_dst;
recurse_dst.GetDirectory().SetCString(fixed_dst.GetCString());
std::string src_dir_path(src.GetPath());
- RecurseCopyBaton baton = {recurse_dst, this, Error()};
+ RecurseCopyBaton baton = {recurse_dst, this, Status()};
FileSpec::EnumerateDirectory(src_dir_path, true, true, true,
RecurseCopy_Callback, &baton);
return baton.error;
}
} break;
- case FileSpec::eFileTypeRegular:
- if (GetFileExists(fixed_dst))
- Unlink(fixed_dst);
+ case fs::file_type::regular_file:
+ llvm::sys::fs::remove(fixed_dst.GetPath());
error = PutFile(src, fixed_dst);
break;
- case FileSpec::eFileTypeSymbolicLink: {
- if (GetFileExists(fixed_dst))
- Unlink(fixed_dst);
+ case fs::file_type::symlink_file: {
+ llvm::sys::fs::remove(fixed_dst.GetPath());
FileSpec src_resolved;
error = FileSystem::Readlink(src, src_resolved);
if (error.Success())
error = CreateSymlink(dst, src_resolved);
} break;
- case FileSpec::eFileTypePipe:
+ case fs::file_type::fifo_file:
error.SetErrorString("platform install doesn't handle pipes");
break;
- case FileSpec::eFileTypeSocket:
+ case fs::file_type::socket_file:
error.SetErrorString("platform install doesn't handle sockets");
break;
- case FileSpec::eFileTypeInvalid:
- case FileSpec::eFileTypeUnknown:
- case FileSpec::eFileTypeOther:
+ default:
error.SetErrorString(
"platform install doesn't handle non file or directory items");
break;
@@ -748,25 +746,24 @@ Error Platform::Install(const FileSpec &src, const FileSpec &dst) {
bool Platform::SetWorkingDirectory(const FileSpec &file_spec) {
if (IsHost()) {
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
- if (log)
- log->Printf("Platform::SetWorkingDirectory('%s')",
- file_spec.GetCString());
- if (file_spec) {
- if (::chdir(file_spec.GetCString()) == 0)
- return true;
+ LLDB_LOG(log, "{0}", file_spec);
+ if (std::error_code ec = llvm::sys::fs::set_current_path(file_spec.GetPath())) {
+ LLDB_LOG(log, "error: {0}", ec.message());
+ return false;
}
- return false;
+ return true;
} else {
m_working_dir.Clear();
return SetRemoteWorkingDirectory(file_spec);
}
}
-Error Platform::MakeDirectory(const FileSpec &file_spec, uint32_t permissions) {
+Status Platform::MakeDirectory(const FileSpec &file_spec,
+ uint32_t permissions) {
if (IsHost())
- return FileSystem::MakeDirectory(file_spec, permissions);
+ return llvm::sys::fs::create_directory(file_spec.GetPath(), permissions);
else {
- Error error;
+ Status error;
error.SetErrorStringWithFormat("remote platform %s doesn't support %s",
GetPluginName().GetCString(),
LLVM_PRETTY_FUNCTION);
@@ -774,12 +771,15 @@ Error Platform::MakeDirectory(const FileSpec &file_spec, uint32_t permissions) {
}
}
-Error Platform::GetFilePermissions(const FileSpec &file_spec,
- uint32_t &file_permissions) {
- if (IsHost())
- return FileSystem::GetFilePermissions(file_spec, file_permissions);
- else {
- Error error;
+Status Platform::GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions) {
+ if (IsHost()) {
+ auto Value = llvm::sys::fs::getPermissions(file_spec.GetPath());
+ if (Value)
+ file_permissions = Value.get();
+ return Status(Value.getError());
+ } else {
+ Status error;
error.SetErrorStringWithFormat("remote platform %s doesn't support %s",
GetPluginName().GetCString(),
LLVM_PRETTY_FUNCTION);
@@ -787,12 +787,13 @@ Error Platform::GetFilePermissions(const FileSpec &file_spec,
}
}
-Error Platform::SetFilePermissions(const FileSpec &file_spec,
- uint32_t file_permissions) {
- if (IsHost())
- return FileSystem::SetFilePermissions(file_spec, file_permissions);
- else {
- Error error;
+Status Platform::SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions) {
+ if (IsHost()) {
+ auto Perms = static_cast<llvm::sys::fs::perms>(file_permissions);
+ return llvm::sys::fs::setPermissions(file_spec.GetPath(), Perms);
+ } else {
+ Status error;
error.SetErrorStringWithFormat("remote platform %s doesn't support %s",
GetPluginName().GetCString(),
LLVM_PRETTY_FUNCTION);
@@ -878,10 +879,11 @@ bool Platform::SetOSVersion(uint32_t major, uint32_t minor, uint32_t update) {
return false;
}
-Error Platform::ResolveExecutable(const ModuleSpec &module_spec,
- lldb::ModuleSP &exe_module_sp,
- const FileSpecList *module_search_paths_ptr) {
- Error error;
+Status
+Platform::ResolveExecutable(const ModuleSpec &module_spec,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr) {
+ Status error;
if (module_spec.GetFileSpec().Exists()) {
if (module_spec.GetArchitecture().IsValid()) {
error = ModuleList::GetSharedModule(module_spec, exe_module_sp,
@@ -910,9 +912,9 @@ Error Platform::ResolveExecutable(const ModuleSpec &module_spec,
return error;
}
-Error Platform::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec,
- FileSpec &sym_file) {
- Error error;
+Status Platform::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec,
+ FileSpec &sym_file) {
+ Status error;
if (sym_spec.GetSymbolFileSpec().Exists())
sym_file = sym_spec.GetSymbolFileSpec();
else
@@ -961,8 +963,8 @@ const ArchSpec &Platform::GetSystemArchitecture() {
return m_system_arch;
}
-Error Platform::ConnectRemote(Args &args) {
- Error error;
+Status Platform::ConnectRemote(Args &args) {
+ Status error;
if (IsHost())
error.SetErrorStringWithFormat("The currently selected platform (%s) is "
"the host platform and is always connected.",
@@ -974,8 +976,8 @@ Error Platform::ConnectRemote(Args &args) {
return error;
}
-Error Platform::DisconnectRemote() {
- Error error;
+Status Platform::DisconnectRemote() {
+ Status error;
if (IsHost())
error.SetErrorStringWithFormat("The currently selected platform (%s) is "
"the host platform and is always connected.",
@@ -1006,8 +1008,8 @@ uint32_t Platform::FindProcesses(const ProcessInstanceInfoMatch &match_info,
return match_count;
}
-Error Platform::LaunchProcess(ProcessLaunchInfo &launch_info) {
- Error error;
+Status Platform::LaunchProcess(ProcessLaunchInfo &launch_info) {
+ Status error;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
if (log)
log->Printf("Platform::%s()", __FUNCTION__);
@@ -1058,13 +1060,13 @@ Error Platform::LaunchProcess(ProcessLaunchInfo &launch_info) {
return error;
}
-Error Platform::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
+Status Platform::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
if (IsHost())
return Host::ShellExpandArguments(launch_info);
- return Error("base lldb_private::Platform class can't expand arguments");
+ return Status("base lldb_private::Platform class can't expand arguments");
}
-Error Platform::KillProcess(const lldb::pid_t pid) {
+Status Platform::KillProcess(const lldb::pid_t pid) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
if (log)
log->Printf("Platform::%s, pid %" PRIu64, __FUNCTION__, pid);
@@ -1084,19 +1086,19 @@ Error Platform::KillProcess(const lldb::pid_t pid) {
}
if (!IsHost()) {
- return Error(
+ return Status(
"base lldb_private::Platform class can't kill remote processes unless "
"they are controlled by a process plugin");
}
Host::Kill(pid, SIGTERM);
- return Error();
+ return Status();
}
lldb::ProcessSP
Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
Target *target, // Can be nullptr, if nullptr create a
// new target, else use existing one
- Error &error) {
+ Status &error) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
if (log)
log->Printf("Platform::%s entered (target %p)", __FUNCTION__,
@@ -1187,7 +1189,7 @@ lldb::PlatformSP
Platform::GetPlatformForArchitecture(const ArchSpec &arch,
ArchSpec *platform_arch_ptr) {
lldb::PlatformSP platform_sp;
- Error error;
+ Status error;
if (arch.IsValid())
platform_sp = Platform::Create(arch, platform_arch_ptr, error);
return platform_sp;
@@ -1231,25 +1233,26 @@ bool Platform::IsCompatibleArchitecture(const ArchSpec &arch,
return false;
}
-Error Platform::PutFile(const FileSpec &source, const FileSpec &destination,
- uint32_t uid, uint32_t gid) {
+Status Platform::PutFile(const FileSpec &source, const FileSpec &destination,
+ uint32_t uid, uint32_t gid) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
if (log)
log->Printf("[PutFile] Using block by block transfer....\n");
uint32_t source_open_options =
File::eOpenOptionRead | File::eOpenOptionCloseOnExec;
- if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink)
+ namespace fs = llvm::sys::fs;
+ if (fs::is_symlink_file(source.GetPath()))
source_open_options |= File::eOpenOptionDontFollowSymlinks;
File source_file(source, source_open_options, lldb::eFilePermissionsUserRW);
- Error error;
+ Status error;
uint32_t permissions = source_file.GetPermissions(error);
if (permissions == 0)
permissions = lldb::eFilePermissionsFileDefault;
if (!source_file.IsValid())
- return Error("PutFile: unable to open source file");
+ return Status("PutFile: unable to open source file");
lldb::user_id_t dest_file = OpenFile(
destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite |
File::eOpenOptionTruncate | File::eOpenOptionCloseOnExec,
@@ -1260,7 +1263,7 @@ Error Platform::PutFile(const FileSpec &source, const FileSpec &destination,
if (error.Fail())
return error;
if (dest_file == UINT64_MAX)
- return Error("unable to open target file");
+ return Status("unable to open target file");
lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
uint64_t offset = 0;
for (;;) {
@@ -1291,16 +1294,16 @@ Error Platform::PutFile(const FileSpec &source, const FileSpec &destination,
return error;
}
-Error Platform::GetFile(const FileSpec &source, const FileSpec &destination) {
- Error error("unimplemented");
+Status Platform::GetFile(const FileSpec &source, const FileSpec &destination) {
+ Status error("unimplemented");
return error;
}
-Error Platform::CreateSymlink(
- const FileSpec &src, // The name of the link is in src
- const FileSpec &dst) // The symlink points to dst
+Status
+Platform::CreateSymlink(const FileSpec &src, // The name of the link is in src
+ const FileSpec &dst) // The symlink points to dst
{
- Error error("unimplemented");
+ Status error("unimplemented");
return error;
}
@@ -1308,22 +1311,26 @@ bool Platform::GetFileExists(const lldb_private::FileSpec &file_spec) {
return false;
}
-Error Platform::Unlink(const FileSpec &path) {
- Error error("unimplemented");
+Status Platform::Unlink(const FileSpec &path) {
+ Status error("unimplemented");
return error;
}
-uint64_t Platform::ConvertMmapFlagsToPlatform(const ArchSpec &arch,
- unsigned flags) {
+MmapArgList Platform::GetMmapArgumentList(const ArchSpec &arch, addr_t addr,
+ addr_t length, unsigned prot,
+ unsigned flags, addr_t fd,
+ addr_t offset) {
uint64_t flags_platform = 0;
if (flags & eMmapFlagsPrivate)
flags_platform |= MAP_PRIVATE;
if (flags & eMmapFlagsAnon)
flags_platform |= MAP_ANON;
- return flags_platform;
+
+ MmapArgList args({addr, length, prot, flags_platform, fd, offset});
+ return args;
}
-lldb_private::Error Platform::RunShellCommand(
+lldb_private::Status Platform::RunShellCommand(
const char *command, // Shouldn't be nullptr
const FileSpec &
working_dir, // Pass empty FileSpec to use the current working directory
@@ -1339,15 +1346,18 @@ lldb_private::Error Platform::RunShellCommand(
return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr,
command_output, timeout_sec);
else
- return Error("unimplemented");
+ return Status("unimplemented");
}
bool Platform::CalculateMD5(const FileSpec &file_spec, uint64_t &low,
uint64_t &high) {
- if (IsHost())
- return FileSystem::CalculateMD5(file_spec, low, high);
- else
+ if (!IsHost())
+ return false;
+ auto Result = llvm::sys::fs::md5_contents(file_spec.GetPath());
+ if (!Result)
return false;
+ std::tie(high, low) = Result->words();
+ return true;
}
void Platform::SetLocalCacheDirectory(const char *local) {
@@ -1399,11 +1409,11 @@ void OptionGroupPlatformRSync::OptionParsingStarting(
m_ignores_remote_hostname = false;
}
-lldb_private::Error
+lldb_private::Status
OptionGroupPlatformRSync::SetOptionValue(uint32_t option_idx,
llvm::StringRef option_arg,
ExecutionContext *execution_context) {
- Error error;
+ Status error;
char short_option = (char)GetDefinitions()[option_idx].short_option;
switch (short_option) {
case 'r':
@@ -1445,11 +1455,11 @@ void OptionGroupPlatformSSH::OptionParsingStarting(
m_ssh_opts.clear();
}
-lldb_private::Error
+lldb_private::Status
OptionGroupPlatformSSH::SetOptionValue(uint32_t option_idx,
llvm::StringRef option_arg,
ExecutionContext *execution_context) {
- Error error;
+ Status error;
char short_option = (char)GetDefinitions()[option_idx].short_option;
switch (short_option) {
case 's':
@@ -1477,10 +1487,10 @@ void OptionGroupPlatformCaching::OptionParsingStarting(
m_cache_dir.clear();
}
-lldb_private::Error OptionGroupPlatformCaching::SetOptionValue(
+lldb_private::Status OptionGroupPlatformCaching::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
- Error error;
+ Status error;
char short_option = (char)GetDefinitions()[option_idx].short_option;
switch (short_option) {
case 'c':
@@ -1511,10 +1521,9 @@ const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() {
return m_trap_handlers;
}
-Error Platform::GetCachedExecutable(ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
- Platform &remote_platform) {
+Status Platform::GetCachedExecutable(
+ ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr, Platform &remote_platform) {
const auto platform_spec = module_spec.GetFileSpec();
const auto error = LoadCachedExecutable(
module_spec, module_sp, module_search_paths_ptr, remote_platform);
@@ -1526,7 +1535,7 @@ Error Platform::GetCachedExecutable(ModuleSpec &module_spec,
return error;
}
-Error Platform::LoadCachedExecutable(
+Status Platform::LoadCachedExecutable(
const ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
const FileSpecList *module_search_paths_ptr, Platform &remote_platform) {
return GetRemoteSharedModule(module_spec, nullptr, module_sp,
@@ -1537,11 +1546,11 @@ Error Platform::LoadCachedExecutable(
nullptr);
}
-Error Platform::GetRemoteSharedModule(const ModuleSpec &module_spec,
- Process *process,
- lldb::ModuleSP &module_sp,
- const ModuleResolver &module_resolver,
- bool *did_create_ptr) {
+Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec,
+ Process *process,
+ lldb::ModuleSP &module_sp,
+ const ModuleResolver &module_resolver,
+ bool *did_create_ptr) {
// Get module information from a target.
ModuleSpec resolved_module_spec;
bool got_module_spec = false;
@@ -1558,7 +1567,7 @@ Error Platform::GetRemoteSharedModule(const ModuleSpec &module_spec,
}
if (module_spec.GetArchitecture().IsValid() == false) {
- Error error;
+ Status error;
// No valid architecture was specified, ask the platform for
// the architectures that we should be using (in the correct order)
// and see if we can find a match that way
@@ -1597,7 +1606,7 @@ Error Platform::GetRemoteSharedModule(const ModuleSpec &module_spec,
const auto error = module_resolver(resolved_module_spec);
if (error.Fail()) {
if (GetCachedSharedModule(resolved_module_spec, module_sp, did_create_ptr))
- return Error();
+ return Status();
}
return error;
@@ -1637,14 +1646,15 @@ bool Platform::GetCachedSharedModule(const ModuleSpec &module_spec,
return false;
}
-Error Platform::DownloadModuleSlice(const FileSpec &src_file_spec,
- const uint64_t src_offset,
- const uint64_t src_size,
- const FileSpec &dst_file_spec) {
- Error error;
+Status Platform::DownloadModuleSlice(const FileSpec &src_file_spec,
+ const uint64_t src_offset,
+ const uint64_t src_size,
+ const FileSpec &dst_file_spec) {
+ Status error;
- std::ofstream dst(dst_file_spec.GetPath(), std::ios::out | std::ios::binary);
- if (!dst.is_open()) {
+ std::error_code EC;
+ llvm::raw_fd_ostream dst(dst_file_spec.GetPath(), EC, llvm::sys::fs::F_None);
+ if (EC) {
error.SetErrorStringWithFormat("unable to open destination file: %s",
dst_file_spec.GetPath().c_str());
return error;
@@ -1678,15 +1688,15 @@ Error Platform::DownloadModuleSlice(const FileSpec &src_file_spec,
dst.write(&buffer[0], n_read);
}
- Error close_error;
+ Status close_error;
CloseFile(src_fd, close_error); // Ignoring close error.
return error;
}
-Error Platform::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
- const FileSpec &dst_file_spec) {
- return Error(
+Status Platform::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
+ const FileSpec &dst_file_spec) {
+ return Status(
"Symbol file downloading not supported by the default platform.");
}
@@ -1712,7 +1722,7 @@ const UnixSignalsSP &Platform::GetUnixSignals() {
uint32_t Platform::LoadImage(lldb_private::Process *process,
const lldb_private::FileSpec &local_file,
const lldb_private::FileSpec &remote_file,
- lldb_private::Error &error) {
+ lldb_private::Status &error) {
if (local_file && remote_file) {
// Both local and remote file was specified. Install the local file to the
// given location.
@@ -1748,21 +1758,21 @@ uint32_t Platform::LoadImage(lldb_private::Process *process,
uint32_t Platform::DoLoadImage(lldb_private::Process *process,
const lldb_private::FileSpec &remote_file,
- lldb_private::Error &error) {
+ lldb_private::Status &error) {
error.SetErrorString("LoadImage is not supported on the current platform");
return LLDB_INVALID_IMAGE_TOKEN;
}
-Error Platform::UnloadImage(lldb_private::Process *process,
- uint32_t image_token) {
- return Error("UnloadImage is not supported on the current platform");
+Status Platform::UnloadImage(lldb_private::Process *process,
+ uint32_t image_token) {
+ return Status("UnloadImage is not supported on the current platform");
}
lldb::ProcessSP Platform::ConnectProcess(llvm::StringRef connect_url,
llvm::StringRef plugin_name,
lldb_private::Debugger &debugger,
lldb_private::Target *target,
- lldb_private::Error &error) {
+ lldb_private::Status &error) {
error.Clear();
if (!target) {
@@ -1791,7 +1801,7 @@ lldb::ProcessSP Platform::ConnectProcess(llvm::StringRef connect_url,
}
size_t Platform::ConnectToWaitingProcesses(lldb_private::Debugger &debugger,
- lldb_private::Error &error) {
+ lldb_private::Status &error) {
error.Clear();
return 0;
}
diff --git a/contrib/llvm/tools/lldb/source/Target/Process.cpp b/contrib/llvm/tools/lldb/source/Target/Process.cpp
index c72662e..6cbe289 100644
--- a/contrib/llvm/tools/lldb/source/Target/Process.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/Process.cpp
@@ -14,13 +14,14 @@
// Other libraries and framework includes
#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/Threading.h"
+
// Project includes
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
@@ -33,6 +34,7 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Host/Pipe.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Host/ThreadLauncher.h"
@@ -63,6 +65,7 @@
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanBase.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/Log.h"
#include "lldb/Utility/NameMatches.h"
#include "lldb/Utility/SelectHelper.h"
@@ -412,10 +415,10 @@ void ProcessInstanceInfo::DumpAsTableRow(Stream &s, Platform *platform,
}
}
-Error ProcessLaunchCommandOptions::SetOptionValue(
+Status ProcessLaunchCommandOptions::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
- Error error;
+ Status error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
@@ -581,7 +584,7 @@ llvm::ArrayRef<OptionDefinition> ProcessLaunchCommandOptions::GetDefinitions() {
}
bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const {
- if (m_name_match_type == eNameMatchIgnore || process_name == nullptr)
+ if (m_name_match_type == NameMatch::Ignore || process_name == nullptr)
return true;
const char *match_name = m_match_info.GetName();
if (!match_name)
@@ -627,7 +630,7 @@ bool ProcessInstanceInfoMatch::Matches(
}
bool ProcessInstanceInfoMatch::MatchAllProcesses() const {
- if (m_name_match_type != eNameMatchIgnore)
+ if (m_name_match_type != NameMatch::Ignore)
return false;
if (m_match_info.ProcessIDIsValid())
@@ -659,7 +662,7 @@ bool ProcessInstanceInfoMatch::MatchAllProcesses() const {
void ProcessInstanceInfoMatch::Clear() {
m_match_info.Clear();
- m_name_match_type = eNameMatchIgnore;
+ m_name_match_type = NameMatch::Ignore;
m_match_all_users = false;
}
@@ -982,10 +985,7 @@ StateType Process::WaitForProcessToStop(const Timeout<std::micro> &timeout,
return state;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf(
- "Process::%s (timeout = %llu)", __FUNCTION__,
- static_cast<unsigned long long>(timeout ? timeout->count() : -1));
+ LLDB_LOG(log, "timeout = {0}", timeout);
if (!wait_always && StateIsStoppedState(state, true) &&
StateIsStoppedState(GetPrivateState(), true)) {
@@ -1261,11 +1261,7 @@ StateType Process::GetStateChangedEvents(EventSP &event_sp,
const Timeout<std::micro> &timeout,
ListenerSP hijack_listener_sp) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
-
- if (log)
- log->Printf(
- "Process::%s (timeout = %llu, event_sp)...", __FUNCTION__,
- static_cast<unsigned long long>(timeout ? timeout->count() : -1));
+ LLDB_LOG(log, "timeout = {0}, event_sp)...", timeout);
ListenerSP listener_sp = hijack_listener_sp;
if (!listener_sp)
@@ -1277,15 +1273,11 @@ StateType Process::GetStateChangedEvents(EventSP &event_sp,
timeout)) {
if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged)
state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
- else if (log)
- log->Printf("Process::%s got no event or was interrupted.", __FUNCTION__);
+ else
+ LLDB_LOG(log, "got no event or was interrupted.");
}
- if (log)
- log->Printf(
- "Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__,
- static_cast<unsigned long long>(timeout ? timeout->count() : -1),
- StateAsCString(state));
+ LLDB_LOG(log, "timeout = {0}, event_sp) => {1}", timeout, state);
return state;
}
@@ -1314,11 +1306,7 @@ StateType
Process::GetStateChangedEventsPrivate(EventSP &event_sp,
const Timeout<std::micro> &timeout) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
-
- if (log)
- log->Printf(
- "Process::%s (timeout = %llu, event_sp)...", __FUNCTION__,
- static_cast<unsigned long long>(timeout ? timeout->count() : -1));
+ LLDB_LOG(log, "timeout = {0}, event_sp)...", timeout);
StateType state = eStateInvalid;
if (m_private_state_listener_sp->GetEventForBroadcasterWithType(
@@ -1328,14 +1316,8 @@ Process::GetStateChangedEventsPrivate(EventSP &event_sp,
if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged)
state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
- // This is a bit of a hack, but when we wait here we could very well return
- // to the command-line, and that could disable the log, which would render the
- // log we got above invalid.
- if (log)
- log->Printf(
- "Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__,
- static_cast<unsigned long long>(timeout ? timeout->count() : -1),
- state == eStateInvalid ? "TIMEOUT" : StateAsCString(state));
+ LLDB_LOG(log, "timeout = {0}, event_sp) => {1}", timeout,
+ state == eStateInvalid ? "TIMEOUT" : StateAsCString(state));
return state;
}
@@ -1343,11 +1325,7 @@ bool Process::GetEventsPrivate(EventSP &event_sp,
const Timeout<std::micro> &timeout,
bool control_only) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
-
- if (log)
- log->Printf(
- "Process::%s (timeout = %llu, event_sp)...", __FUNCTION__,
- static_cast<unsigned long long>(timeout ? timeout->count() : -1));
+ LLDB_LOG(log, "timeout = {0}, event_sp)...", timeout);
if (control_only)
return m_private_state_listener_sp->GetEventForBroadcaster(
@@ -1632,13 +1610,13 @@ void Process::SetPublicState(StateType new_state, bool restarted) {
}
}
-Error Process::Resume() {
+Status Process::Resume() {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
LIBLLDB_LOG_PROCESS));
if (log)
log->Printf("Process::Resume -- locking run lock");
if (!m_public_run_lock.TrySetRunning()) {
- Error error("Resume request failed - process still running.");
+ Status error("Resume request failed - process still running.");
if (log)
log->Printf("Process::Resume: -- TrySetRunning failed, not resuming.");
return error;
@@ -1646,13 +1624,13 @@ Error Process::Resume() {
return PrivateResume();
}
-Error Process::ResumeSynchronous(Stream *stream) {
+Status Process::ResumeSynchronous(Stream *stream) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
LIBLLDB_LOG_PROCESS));
if (log)
log->Printf("Process::ResumeSynchronous -- locking run lock");
if (!m_public_run_lock.TrySetRunning()) {
- Error error("Resume request failed - process still running.");
+ Status error("Resume request failed - process still running.");
if (log)
log->Printf("Process::Resume: -- TrySetRunning failed, not resuming.");
return error;
@@ -1662,7 +1640,7 @@ Error Process::ResumeSynchronous(Stream *stream) {
Listener::MakeListener("lldb.Process.ResumeSynchronous.hijack"));
HijackProcessEvents(listener_sp);
- Error error = PrivateResume();
+ Status error = PrivateResume();
if (error.Success()) {
StateType state =
WaitForProcessToStop(llvm::None, NULL, true, listener_sp, stream);
@@ -1757,7 +1735,7 @@ addr_t Process::GetImageInfoAddress() { return LLDB_INVALID_ADDRESS; }
const lldb::ABISP &Process::GetABI() {
if (!m_abi_sp)
- m_abi_sp = ABI::FindPlugin(GetTarget().GetArchitecture());
+ m_abi_sp = ABI::FindPlugin(shared_from_this(), GetTarget().GetArchitecture());
return m_abi_sp;
}
@@ -1835,8 +1813,8 @@ void Process::DisableAllBreakpointSites() {
});
}
-Error Process::ClearBreakpointSiteByID(lldb::user_id_t break_id) {
- Error error(DisableBreakpointSiteByID(break_id));
+Status Process::ClearBreakpointSiteByID(lldb::user_id_t break_id) {
+ Status error(DisableBreakpointSiteByID(break_id));
if (error.Success())
m_breakpoint_site_list.Remove(break_id);
@@ -1844,8 +1822,8 @@ Error Process::ClearBreakpointSiteByID(lldb::user_id_t break_id) {
return error;
}
-Error Process::DisableBreakpointSiteByID(lldb::user_id_t break_id) {
- Error error;
+Status Process::DisableBreakpointSiteByID(lldb::user_id_t break_id) {
+ Status error;
BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID(break_id);
if (bp_site_sp) {
if (bp_site_sp->IsEnabled())
@@ -1858,8 +1836,8 @@ Error Process::DisableBreakpointSiteByID(lldb::user_id_t break_id) {
return error;
}
-Error Process::EnableBreakpointSiteByID(lldb::user_id_t break_id) {
- Error error;
+Status Process::EnableBreakpointSiteByID(lldb::user_id_t break_id) {
+ Status error;
BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID(break_id);
if (bp_site_sp) {
if (!bp_site_sp->IsEnabled())
@@ -1904,7 +1882,7 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
if (owner->ShouldResolveIndirectFunctions()) {
Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol();
if (symbol && symbol->IsIndirect()) {
- Error error;
+ Status error;
Address symbol_address = symbol->GetAddress();
load_addr = ResolveIndirectFunction(&symbol_address, error);
if (!error.Success() && show_error) {
@@ -1941,7 +1919,7 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
bp_site_sp.reset(new BreakpointSite(&m_breakpoint_site_list, owner,
load_addr, use_hardware));
if (bp_site_sp) {
- Error error = EnableBreakpointSite(bp_site_sp.get());
+ Status error = EnableBreakpointSite(bp_site_sp.get());
if (error.Success()) {
owner->SetBreakpointSite(bp_site_sp);
return m_breakpoint_site_list.Add(bp_site_sp);
@@ -1981,8 +1959,8 @@ size_t Process::RemoveBreakpointOpcodesFromBuffer(addr_t bp_addr, size_t size,
if (m_breakpoint_site_list.FindInRange(bp_addr, bp_addr + size,
bp_sites_in_range)) {
- bp_sites_in_range.ForEach([bp_addr, size, buf, &bytes_removed](
- BreakpointSite *bp_site) -> void {
+ bp_sites_in_range.ForEach([bp_addr, size,
+ buf](BreakpointSite *bp_site) -> void {
if (bp_site->GetType() == BreakpointSite::eSoftware) {
addr_t intersect_addr;
size_t intersect_size;
@@ -2011,8 +1989,8 @@ size_t Process::GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site) {
return 0;
}
-Error Process::EnableSoftwareBreakpoint(BreakpointSite *bp_site) {
- Error error;
+Status Process::EnableSoftwareBreakpoint(BreakpointSite *bp_site) {
+ Status error;
assert(bp_site != nullptr);
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
const addr_t bp_addr = bp_site->GetLoadAddress();
@@ -2087,8 +2065,8 @@ Error Process::EnableSoftwareBreakpoint(BreakpointSite *bp_site) {
return error;
}
-Error Process::DisableSoftwareBreakpoint(BreakpointSite *bp_site) {
- Error error;
+Status Process::DisableSoftwareBreakpoint(BreakpointSite *bp_site) {
+ Status error;
assert(bp_site != nullptr);
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
addr_t bp_addr = bp_site->GetLoadAddress();
@@ -2180,7 +2158,7 @@ Error Process::DisableSoftwareBreakpoint(BreakpointSite *bp_site) {
// Uncomment to verify memory caching works after making changes to caching code
//#define VERIFY_MEMORY_READS
-size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Error &error) {
+size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) {
error.Clear();
if (!GetDisableMemoryCache()) {
#if defined(VERIFY_MEMORY_READS)
@@ -2199,7 +2177,7 @@ size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Error &error) {
assert(verify_buf.size() == size);
const size_t cache_bytes_read =
m_memory_cache.Read(this, addr, buf, size, error);
- Error verify_error;
+ Status verify_error;
const size_t verify_bytes_read =
ReadMemoryFromInferior(addr, const_cast<char *>(verify_buf.data()),
verify_buf.size(), verify_error);
@@ -2222,7 +2200,7 @@ size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Error &error) {
}
size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str,
- Error &error) {
+ Status &error) {
char buf[256];
out_str.clear();
addr_t curr_addr = addr;
@@ -2242,7 +2220,7 @@ size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str,
}
size_t Process::ReadStringFromMemory(addr_t addr, char *dst, size_t max_bytes,
- Error &error, size_t type_width) {
+ Status &error, size_t type_width) {
size_t total_bytes_read = 0;
if (dst && max_bytes && type_width && max_bytes >= type_width) {
// Ensure a null terminator independent of the number of bytes that is read.
@@ -2295,13 +2273,14 @@ size_t Process::ReadStringFromMemory(addr_t addr, char *dst, size_t max_bytes,
// correct code to find
// null terminators.
size_t Process::ReadCStringFromMemory(addr_t addr, char *dst,
- size_t dst_max_len, Error &result_error) {
+ size_t dst_max_len,
+ Status &result_error) {
size_t total_cstr_len = 0;
if (dst && dst_max_len) {
result_error.Clear();
// NULL out everything just to be safe
memset(dst, 0, dst_max_len);
- Error error;
+ Status error;
addr_t curr_addr = addr;
const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize();
size_t bytes_left = dst_max_len - 1;
@@ -2340,7 +2319,7 @@ size_t Process::ReadCStringFromMemory(addr_t addr, char *dst,
}
size_t Process::ReadMemoryFromInferior(addr_t addr, void *buf, size_t size,
- Error &error) {
+ Status &error) {
if (buf == nullptr || size == 0)
return 0;
@@ -2366,7 +2345,7 @@ size_t Process::ReadMemoryFromInferior(addr_t addr, void *buf, size_t size,
uint64_t Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr,
size_t integer_byte_size,
uint64_t fail_value,
- Error &error) {
+ Status &error) {
Scalar scalar;
if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, false, scalar,
error))
@@ -2376,7 +2355,8 @@ uint64_t Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr,
int64_t Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr,
size_t integer_byte_size,
- int64_t fail_value, Error &error) {
+ int64_t fail_value,
+ Status &error) {
Scalar scalar;
if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, true, scalar,
error))
@@ -2384,7 +2364,7 @@ int64_t Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr,
return fail_value;
}
-addr_t Process::ReadPointerFromMemory(lldb::addr_t vm_addr, Error &error) {
+addr_t Process::ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error) {
Scalar scalar;
if (ReadScalarIntegerFromMemory(vm_addr, GetAddressByteSize(), false, scalar,
error))
@@ -2393,7 +2373,7 @@ addr_t Process::ReadPointerFromMemory(lldb::addr_t vm_addr, Error &error) {
}
bool Process::WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
- Error &error) {
+ Status &error) {
Scalar scalar;
const uint32_t addr_byte_size = GetAddressByteSize();
if (addr_byte_size <= 4)
@@ -2405,7 +2385,7 @@ bool Process::WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
}
size_t Process::WriteMemoryPrivate(addr_t addr, const void *buf, size_t size,
- Error &error) {
+ Status &error) {
size_t bytes_written = 0;
const uint8_t *bytes = (const uint8_t *)buf;
@@ -2421,7 +2401,7 @@ size_t Process::WriteMemoryPrivate(addr_t addr, const void *buf, size_t size,
}
size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size,
- Error &error) {
+ Status &error) {
#if defined(ENABLE_MEMORY_CACHING)
m_memory_cache.Flush(addr, size);
#endif
@@ -2500,7 +2480,7 @@ size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size,
}
size_t Process::WriteScalarToMemory(addr_t addr, const Scalar &scalar,
- size_t byte_size, Error &error) {
+ size_t byte_size, Status &error) {
if (byte_size == UINT32_MAX)
byte_size = scalar.GetByteSize();
if (byte_size > 0) {
@@ -2519,7 +2499,7 @@ size_t Process::WriteScalarToMemory(addr_t addr, const Scalar &scalar,
size_t Process::ReadScalarIntegerFromMemory(addr_t addr, uint32_t byte_size,
bool is_signed, Scalar &scalar,
- Error &error) {
+ Status &error) {
uint64_t uval = 0;
if (byte_size == 0) {
error.SetErrorString("byte size is zero");
@@ -2549,7 +2529,7 @@ size_t Process::ReadScalarIntegerFromMemory(addr_t addr, uint32_t byte_size,
#define USE_ALLOCATE_MEMORY_CACHE 1
addr_t Process::AllocateMemory(size_t size, uint32_t permissions,
- Error &error) {
+ Status &error) {
if (GetPrivateState() != eStateStopped)
return LLDB_INVALID_ADDRESS;
@@ -2570,7 +2550,7 @@ addr_t Process::AllocateMemory(size_t size, uint32_t permissions,
}
addr_t Process::CallocateMemory(size_t size, uint32_t permissions,
- Error &error) {
+ Status &error) {
addr_t return_addr = AllocateMemory(size, permissions, error);
if (error.Success()) {
std::string buffer(size, 0);
@@ -2582,7 +2562,7 @@ addr_t Process::CallocateMemory(size_t size, uint32_t permissions,
bool Process::CanJIT() {
if (m_can_jit == eCanJITDontKnow) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
- Error err;
+ Status err;
uint64_t allocated_memory = AllocateMemory(
8, ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable,
@@ -2617,8 +2597,8 @@ void Process::SetCanRunCode(bool can_run_code) {
m_can_interpret_function_calls = can_run_code;
}
-Error Process::DeallocateMemory(addr_t ptr) {
- Error error;
+Status Process::DeallocateMemory(addr_t ptr) {
+ Status error;
#if defined(USE_ALLOCATE_MEMORY_CACHE)
if (!m_allocated_memory_cache.DeallocateMemory(ptr)) {
error.SetErrorStringWithFormat(
@@ -2647,7 +2627,7 @@ ModuleSP Process::ReadModuleFromMemory(const FileSpec &file_spec,
}
ModuleSP module_sp(new Module(file_spec, ArchSpec()));
if (module_sp) {
- Error error;
+ Status error;
ObjectFile *objfile = module_sp->GetMemoryObjectFile(
shared_from_this(), header_addr, error, size_to_read);
if (objfile)
@@ -2660,7 +2640,7 @@ bool Process::GetLoadAddressPermissions(lldb::addr_t load_addr,
uint32_t &permissions) {
MemoryRegionInfo range_info;
permissions = 0;
- Error error(GetMemoryRegionInfo(load_addr, range_info));
+ Status error(GetMemoryRegionInfo(load_addr, range_info));
if (!error.Success())
return false;
if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow ||
@@ -2681,14 +2661,14 @@ bool Process::GetLoadAddressPermissions(lldb::addr_t load_addr,
return true;
}
-Error Process::EnableWatchpoint(Watchpoint *watchpoint, bool notify) {
- Error error;
+Status Process::EnableWatchpoint(Watchpoint *watchpoint, bool notify) {
+ Status error;
error.SetErrorString("watchpoints are not supported");
return error;
}
-Error Process::DisableWatchpoint(Watchpoint *watchpoint, bool notify) {
- Error error;
+Status Process::DisableWatchpoint(Watchpoint *watchpoint, bool notify) {
+ Status error;
error.SetErrorString("watchpoints are not supported");
return error;
}
@@ -2724,8 +2704,8 @@ void Process::LoadOperatingSystemPlugin(bool flush) {
Flush();
}
-Error Process::Launch(ProcessLaunchInfo &launch_info) {
- Error error;
+Status Process::Launch(ProcessLaunchInfo &launch_info) {
+ Status error;
m_abi_sp.reset();
m_dyld_ap.reset();
m_jit_loaders_ap.reset();
@@ -2798,7 +2778,12 @@ Error Process::Launch(ProcessLaunchInfo &launch_info) {
if (system_runtime)
system_runtime->DidLaunch();
- LoadOperatingSystemPlugin(false);
+ if (!m_os_ap)
+ LoadOperatingSystemPlugin(false);
+
+ // We successfully launched the process and stopped,
+ // now it the right time to set up signal filters before resuming.
+ UpdateAutomaticSignalFiltering();
// Note, the stop event was consumed above, but not handled. This
// was done
@@ -2840,8 +2825,8 @@ Error Process::Launch(ProcessLaunchInfo &launch_info) {
return error;
}
-Error Process::LoadCore() {
- Error error = DoLoadCore();
+Status Process::LoadCore() {
+ Status error = DoLoadCore();
if (error.Success()) {
ListenerSP listener_sp(
Listener::MakeListener("lldb.process.load_core_listener"));
@@ -2862,7 +2847,9 @@ Error Process::LoadCore() {
if (system_runtime)
system_runtime->DidAttach();
- m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr));
+ if (!m_os_ap)
+ LoadOperatingSystemPlugin(false);
+
// We successfully loaded a core file, now pretend we stopped so we can
// show all of the threads in the core file and explore the crashed
// state.
@@ -2992,7 +2979,7 @@ ListenerSP ProcessAttachInfo::GetListenerForProcess(Debugger &debugger) {
return debugger.GetListener();
}
-Error Process::Attach(ProcessAttachInfo &attach_info) {
+Status Process::Attach(ProcessAttachInfo &attach_info) {
m_abi_sp.reset();
m_process_input_reader.reset();
m_dyld_ap.reset();
@@ -3002,7 +2989,7 @@ Error Process::Attach(ProcessAttachInfo &attach_info) {
m_stop_info_override_callback = nullptr;
lldb::pid_t attach_pid = attach_info.GetProcessID();
- Error error;
+ Status error;
if (attach_pid == LLDB_INVALID_PROCESS_ID) {
char process_name[PATH_MAX];
@@ -3046,7 +3033,7 @@ Error Process::Attach(ProcessAttachInfo &attach_info) {
if (platform_sp) {
ProcessInstanceInfoMatch match_info;
match_info.GetProcessInfo() = attach_info;
- match_info.SetNameMatchType(eNameMatchEquals);
+ match_info.SetNameMatchType(NameMatch::Equals);
platform_sp->FindProcesses(match_info, process_infos);
const uint32_t num_matches = process_infos.GetSize();
if (num_matches == 1) {
@@ -3205,7 +3192,8 @@ void Process::CompleteAttach() {
}
}
- m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr));
+ if (!m_os_ap)
+ LoadOperatingSystemPlugin(false);
// Figure out which one is the executable, and set that in our target:
const ModuleList &target_modules = GetTarget().GetImages();
std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
@@ -3235,14 +3223,14 @@ void Process::CompleteAttach() {
m_stop_info_override_callback = process_arch.GetStopInfoOverrideCallback();
}
-Error Process::ConnectRemote(Stream *strm, llvm::StringRef remote_url) {
+Status Process::ConnectRemote(Stream *strm, llvm::StringRef remote_url) {
m_abi_sp.reset();
m_process_input_reader.reset();
// Find the process and its architecture. Make sure it matches the
// architecture of the current Target, and if not adjust it.
- Error error(DoConnectRemote(strm, remote_url));
+ Status error(DoConnectRemote(strm, remote_url));
if (error.Success()) {
if (GetID() != LLDB_INVALID_PROCESS_ID) {
EventSP event_sp;
@@ -3267,7 +3255,7 @@ Error Process::ConnectRemote(Stream *strm, llvm::StringRef remote_url) {
return error;
}
-Error Process::PrivateResume() {
+Status Process::PrivateResume() {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS |
LIBLLDB_LOG_STEP));
if (log)
@@ -3276,7 +3264,11 @@ Error Process::PrivateResume() {
m_mod_id.GetStopID(), StateAsCString(m_public_state.GetValue()),
StateAsCString(m_private_state.GetValue()));
- Error error(WillResume());
+ // If signals handing status changed we might want to update
+ // our signal filters before resuming.
+ UpdateAutomaticSignalFiltering();
+
+ Status error(WillResume());
// Tell the process it is about to resume before the thread list
if (error.Success()) {
// Now let the thread list know we are about to resume so it
@@ -3321,9 +3313,9 @@ Error Process::PrivateResume() {
return error;
}
-Error Process::Halt(bool clear_thread_plans, bool use_run_lock) {
+Status Process::Halt(bool clear_thread_plans, bool use_run_lock) {
if (!StateIsRunningState(m_public_state.GetValue()))
- return Error("Process is not running.");
+ return Status("Process is not running.");
// Don't clear the m_clear_thread_plans_on_stop, only set it to true if
// in case it was already set and some thread plan logic calls halt on its
@@ -3344,7 +3336,7 @@ Error Process::Halt(bool clear_thread_plans, bool use_run_lock) {
RestoreProcessEvents();
SetExitStatus(SIGKILL, "Cancelled async attach.");
Destroy(false);
- return Error();
+ return Status();
}
// Wait for 10 second for the process to stop.
@@ -3354,16 +3346,16 @@ Error Process::Halt(bool clear_thread_plans, bool use_run_lock) {
if (state == eStateInvalid || !event_sp) {
// We timed out and didn't get a stop event...
- return Error("Halt timed out. State = %s", StateAsCString(GetState()));
+ return Status("Halt timed out. State = %s", StateAsCString(GetState()));
}
BroadcastEvent(event_sp);
- return Error();
+ return Status();
}
-Error Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) {
- Error error;
+Status Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) {
+ Status error;
// Check both the public & private states here. If we're hung evaluating an
// expression, for instance, then
@@ -3410,18 +3402,19 @@ Error Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) {
// then continue on.
StateType private_state = m_private_state.GetValue();
if (private_state != eStateStopped) {
- return Error("Attempt to stop the target in order to detach timed out. "
- "State = %s",
- StateAsCString(GetState()));
+ return Status(
+ "Attempt to stop the target in order to detach timed out. "
+ "State = %s",
+ StateAsCString(GetState()));
}
}
}
return error;
}
-Error Process::Detach(bool keep_stopped) {
+Status Process::Detach(bool keep_stopped) {
EventSP exit_event_sp;
- Error error;
+ Status error;
m_destroy_in_process = true;
error = WillDetach();
@@ -3473,7 +3466,7 @@ Error Process::Detach(bool keep_stopped) {
return error;
}
-Error Process::Destroy(bool force_kill) {
+Status Process::Destroy(bool force_kill) {
// Tell ourselves we are in the process of destroying the process, so that we
// don't do any unnecessary work
@@ -3493,7 +3486,7 @@ Error Process::Destroy(bool force_kill) {
m_destroy_in_process = true;
- Error error(WillDestroy());
+ Status error(WillDestroy());
if (error.Success()) {
EventSP exit_event_sp;
if (DestroyRequiresHalt()) {
@@ -3548,8 +3541,8 @@ Error Process::Destroy(bool force_kill) {
return error;
}
-Error Process::Signal(int signal) {
- Error error(WillSignal());
+Status Process::Signal(int signal) {
+ Status error(WillSignal());
if (error.Success()) {
error = DoSignal(signal);
if (error.Success())
@@ -3754,8 +3747,8 @@ bool Process::StartPrivateStateThread(bool is_secondary_thread) {
// Create a thread that watches our internal state and controls which
// events make it to clients (into the DCProcess event queue).
char thread_name[1024];
-
- if (HostInfo::GetMaxThreadNameLength() <= 30) {
+ uint32_t max_len = llvm::get_max_thread_name_length();
+ if (max_len > 0 && max_len <= 30) {
// On platforms with abbreviated thread name lengths, choose thread names
// that fit within the limit.
if (already_running)
@@ -3977,9 +3970,9 @@ void Process::HandlePrivateEvent(EventSP &event_sp) {
}
}
-Error Process::HaltPrivate() {
+Status Process::HaltPrivate() {
EventSP event_sp;
- Error error(WillHalt());
+ Status error(WillHalt());
if (error.Fail())
return error;
@@ -4047,7 +4040,7 @@ thread_result_t Process::RunPrivateStateThread(bool is_secondary_thread) {
log->Printf("Process::%s (arg = %p, pid = %" PRIu64
") woke up with an interrupt - Halting.",
__FUNCTION__, static_cast<void *>(this), GetID());
- Error error = HaltPrivate();
+ Status error = HaltPrivate();
if (error.Fail() && log)
log->Printf("Process::%s (arg = %p, pid = %" PRIu64
") failed to halt the process: %s",
@@ -4487,7 +4480,7 @@ Process::GetStructuredDataPlugin(const ConstString &type_name) const {
return StructuredDataPluginSP();
}
-size_t Process::GetAsyncProfileData(char *buf, size_t buf_size, Error &error) {
+size_t Process::GetAsyncProfileData(char *buf, size_t buf_size, Status &error) {
std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex);
if (m_profile_data.empty())
return 0;
@@ -4515,7 +4508,7 @@ size_t Process::GetAsyncProfileData(char *buf, size_t buf_size, Error &error) {
// Process STDIO
//------------------------------------------------------------------
-size_t Process::GetSTDOUT(char *buf, size_t buf_size, Error &error) {
+size_t Process::GetSTDOUT(char *buf, size_t buf_size, Status &error) {
std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex);
size_t bytes_available = m_stdout_data.size();
if (bytes_available > 0) {
@@ -4535,7 +4528,7 @@ size_t Process::GetSTDOUT(char *buf, size_t buf_size, Error &error) {
return bytes_available;
}
-size_t Process::GetSTDERR(char *buf, size_t buf_size, Error &error) {
+size_t Process::GetSTDERR(char *buf, size_t buf_size, Status &error) {
std::lock_guard<std::recursive_mutex> gaurd(m_stdio_communication_mutex);
size_t bytes_available = m_stderr_data.size();
if (bytes_available > 0) {
@@ -4598,7 +4591,7 @@ public:
SelectHelper select_helper;
select_helper.FDSetRead(read_fd);
select_helper.FDSetRead(pipe_read_fd);
- Error error = select_helper.Select();
+ Status error = select_helper.Select();
if (error.Fail()) {
SetIsDone(true);
@@ -4616,7 +4609,7 @@ public:
if (select_helper.FDIsSetRead(pipe_read_fd)) {
size_t bytes_read;
// Consume the interrupt byte
- Error error = m_pipe.Read(&ch, 1, bytes_read);
+ Status error = m_pipe.Read(&ch, 1, bytes_read);
if (error.Success()) {
switch (ch) {
case 'q':
@@ -4667,7 +4660,7 @@ public:
if (m_active) {
char ch = 'i'; // Send 'i' for interrupt
size_t bytes_written = 0;
- Error result = m_pipe.Write(&ch, 1, bytes_written);
+ Status result = m_pipe.Write(&ch, 1, bytes_written);
return result.Success();
} else {
// This IOHandler might be pushed on the stack, but not being run
@@ -4830,6 +4823,48 @@ GetExpressionTimeout(const EvaluateExpressionOptions &options,
return *options.GetTimeout() - GetOneThreadExpressionTimeout(options);
}
+static llvm::Optional<ExpressionResults>
+HandleStoppedEvent(Thread &thread, const ThreadPlanSP &thread_plan_sp,
+ RestorePlanState &restorer, const EventSP &event_sp,
+ EventSP &event_to_broadcast_sp,
+ const EvaluateExpressionOptions &options, bool handle_interrupts) {
+ Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS);
+
+ ThreadPlanSP plan = thread.GetCompletedPlan();
+ if (plan == thread_plan_sp && plan->PlanSucceeded()) {
+ LLDB_LOG(log, "execution completed successfully");
+
+ // Restore the plan state so it will get reported as intended when we are
+ // done.
+ restorer.Clean();
+ return eExpressionCompleted;
+ }
+
+ StopInfoSP stop_info_sp = thread.GetStopInfo();
+ if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint &&
+ stop_info_sp->ShouldNotify(event_sp.get())) {
+ LLDB_LOG(log, "stopped for breakpoint: {0}.", stop_info_sp->GetDescription());
+ if (!options.DoesIgnoreBreakpoints()) {
+ // Restore the plan state and then force Private to false. We are going
+ // to stop because of this plan so we need it to become a public plan or
+ // it won't report correctly when we continue to its termination later on.
+ restorer.Clean();
+ thread_plan_sp->SetPrivate(false);
+ event_to_broadcast_sp = event_sp;
+ }
+ return eExpressionHitBreakpoint;
+ }
+
+ if (!handle_interrupts &&
+ Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get()))
+ return llvm::None;
+
+ LLDB_LOG(log, "thread plan did not successfully complete");
+ if (!options.DoesUnwindOnError())
+ event_to_broadcast_sp = event_sp;
+ return eExpressionInterrupted;
+}
+
ExpressionResults
Process::RunThreadPlan(ExecutionContext &exe_ctx,
lldb::ThreadPlanSP &thread_plan_sp,
@@ -5092,7 +5127,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
if (do_resume) {
num_resumes++;
- Error resume_error = PrivateResume();
+ Status resume_error = PrivateResume();
if (!resume_error.Success()) {
diagnostic_manager.Printf(
eDiagnosticSeverityError,
@@ -5235,69 +5270,22 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
"but our thread (index-id=%u) has vanished.",
thread_idx_id);
return_value = eExpressionInterrupted;
- } else {
+ } else if (Process::ProcessEventData::GetRestartedFromEvent(
+ event_sp.get())) {
// If we were restarted, we just need to go back up to fetch
// another event.
- if (Process::ProcessEventData::GetRestartedFromEvent(
- event_sp.get())) {
- if (log) {
- log->Printf("Process::RunThreadPlan(): Got a stop and "
- "restart, so we'll continue waiting.");
- }
- keep_going = true;
- do_resume = false;
- handle_running_event = true;
- } else {
- StopInfoSP stop_info_sp(thread_sp->GetStopInfo());
- StopReason stop_reason = eStopReasonInvalid;
- if (stop_info_sp)
- stop_reason = stop_info_sp->GetStopReason();
-
- // FIXME: We only check if the stop reason is plan complete,
- // should we make sure that
- // it is OUR plan that is complete?
- if (stop_reason == eStopReasonPlanComplete) {
- if (log)
- log->PutCString("Process::RunThreadPlan(): execution "
- "completed successfully.");
-
- // Restore the plan state so it will get reported as
- // intended when we are done.
- thread_plan_restorer.Clean();
-
- return_value = eExpressionCompleted;
- } else {
- // Something restarted the target, so just wait for it to
- // stop for real.
- if (stop_reason == eStopReasonBreakpoint) {
- if (log)
- log->Printf("Process::RunThreadPlan() stopped for "
- "breakpoint: %s.",
- stop_info_sp->GetDescription());
- return_value = eExpressionHitBreakpoint;
- if (!options.DoesIgnoreBreakpoints()) {
- // Restore the plan state and then force Private to
- // false. We are
- // going to stop because of this plan so we need it to
- // become a public
- // plan or it won't report correctly when we continue to
- // its termination
- // later on.
- thread_plan_restorer.Clean();
- if (thread_plan_sp)
- thread_plan_sp->SetPrivate(false);
- event_to_broadcast_sp = event_sp;
- }
- } else {
- if (log)
- log->PutCString("Process::RunThreadPlan(): thread plan "
- "didn't successfully complete.");
- if (!options.DoesUnwindOnError())
- event_to_broadcast_sp = event_sp;
- return_value = eExpressionInterrupted;
- }
- }
+ if (log) {
+ log->Printf("Process::RunThreadPlan(): Got a stop and "
+ "restart, so we'll continue waiting.");
}
+ keep_going = true;
+ do_resume = false;
+ handle_running_event = true;
+ } else {
+ const bool handle_interrupts = true;
+ return_value = *HandleStoppedEvent(
+ *thread, thread_plan_sp, thread_plan_restorer, event_sp,
+ event_to_broadcast_sp, options, handle_interrupts);
}
} break;
@@ -5348,19 +5336,16 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
if (log) {
if (options.GetTryAllThreads()) {
if (before_first_timeout) {
- log->Printf("Process::RunThreadPlan(): Running function with "
- "one thread timeout timed out.");
+ LLDB_LOG(log,
+ "Running function with one thread timeout timed out.");
} else
- log->Printf("Process::RunThreadPlan(): Restarting function with "
- "all threads enabled "
- "and timeout: %" PRIu64
- " timed out, abandoning execution.",
- timeout ? timeout->count() : -1);
+ LLDB_LOG(log, "Restarting function with all threads enabled and "
+ "timeout: {0} timed out, abandoning execution.",
+ timeout);
} else
- log->Printf("Process::RunThreadPlan(): Running function with "
- "timeout: %" PRIu64 " timed out, "
- "abandoning execution.",
- timeout ? timeout->count() : -1);
+ LLDB_LOG(log, "Running function with timeout: {0} timed out, "
+ "abandoning execution.",
+ timeout);
}
// It is possible that between the time we issued the Halt, and we get
@@ -5378,7 +5363,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
bool do_halt = true;
const uint32_t num_retries = 5;
while (try_halt_again < num_retries) {
- Error halt_error;
+ Status halt_error;
if (do_halt) {
if (log)
log->Printf("Process::RunThreadPlan(): Running Halt.");
@@ -5406,20 +5391,6 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
}
if (stop_state == lldb::eStateStopped) {
- // Between the time we initiated the Halt and the time we
- // delivered it, the process could have
- // already finished its job. Check that here:
-
- if (thread->IsThreadPlanDone(thread_plan_sp.get())) {
- if (log)
- log->PutCString("Process::RunThreadPlan(): Even though we "
- "timed out, the call plan was done. "
- "Exiting wait loop.");
- return_value = eExpressionCompleted;
- back_to_top = false;
- break;
- }
-
if (Process::ProcessEventData::GetRestartedFromEvent(
event_sp.get())) {
if (log)
@@ -5433,6 +5404,18 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
continue;
}
+ // Between the time we initiated the Halt and the time we
+ // delivered it, the process could have
+ // already finished its job. Check that here:
+ const bool handle_interrupts = false;
+ if (auto result = HandleStoppedEvent(
+ *thread, thread_plan_sp, thread_plan_restorer, event_sp,
+ event_to_broadcast_sp, options, handle_interrupts)) {
+ return_value = *result;
+ back_to_top = false;
+ break;
+ }
+
if (!options.GetTryAllThreads()) {
if (log)
log->PutCString("Process::RunThreadPlan(): try_all_threads "
@@ -5490,7 +5473,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
// plan, shut it down now.
if (backup_private_state_thread.IsJoinable()) {
StopPrivateStateThread();
- Error error;
+ Status error;
m_private_state_thread = backup_private_state_thread;
if (stopper_base_plan_sp) {
thread->DiscardThreadPlansUpToPlan(stopper_base_plan_sp);
@@ -5879,7 +5862,7 @@ void Process::DidExec() {
target.DidExec();
}
-addr_t Process::ResolveIndirectFunction(const Address *address, Error &error) {
+addr_t Process::ResolveIndirectFunction(const Address *address, Status &error) {
if (address == nullptr) {
error.SetErrorString("Invalid address argument");
return LLDB_INVALID_ADDRESS;
@@ -6107,10 +6090,10 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr,
return retval;
}
-Error Process::GetMemoryRegions(
- std::vector<lldb::MemoryRegionInfoSP> &region_list) {
+Status
+Process::GetMemoryRegions(std::vector<lldb::MemoryRegionInfoSP> &region_list) {
- Error error;
+ Status error;
lldb::addr_t range_end = 0;
@@ -6133,12 +6116,13 @@ Error Process::GetMemoryRegions(
return error;
}
-Error Process::ConfigureStructuredData(
- const ConstString &type_name, const StructuredData::ObjectSP &config_sp) {
+Status
+Process::ConfigureStructuredData(const ConstString &type_name,
+ const StructuredData::ObjectSP &config_sp) {
// If you get this, the Process-derived class needs to implement a method
// to enable an already-reported asynchronous structured data feature.
// See ProcessGDBRemote for an example implementation over gdb-remote.
- return Error("unimplemented");
+ return Status("unimplemented");
}
void Process::MapSupportedStructuredDataPlugins(
@@ -6175,8 +6159,7 @@ void Process::MapSupportedStructuredDataPlugins(
}
const_type_names.insert(ConstString(type_name->GetValue()));
- if (log)
- log->Printf("- %s", type_name->GetValue().c_str());
+ LLDB_LOG(log, "- {0}", type_name->GetValue());
return true;
});
@@ -6245,3 +6228,9 @@ bool Process::RouteAsyncStructuredData(
find_it->second->HandleArrivalOfStructuredData(*this, type_name, object_sp);
return true;
}
+
+Status Process::UpdateAutomaticSignalFiltering() {
+ // Default implementation does nothign.
+ // No automatic signal filtering to speak of.
+ return Status();
+}
diff --git a/contrib/llvm/tools/lldb/source/Target/ProcessInfo.cpp b/contrib/llvm/tools/lldb/source/Target/ProcessInfo.cpp
index 5c4b2f07..0d986bc 100644
--- a/contrib/llvm/tools/lldb/source/Target/ProcessInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ProcessInfo.cpp
@@ -15,8 +15,8 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
#include "lldb/Host/PosixApi.h"
+#include "lldb/Utility/Stream.h"
#include "llvm/ADT/SmallString.h"
diff --git a/contrib/llvm/tools/lldb/source/Target/ProcessLaunchInfo.cpp b/contrib/llvm/tools/lldb/source/Target/ProcessLaunchInfo.cpp
index 92d9371..3fa40dc 100644
--- a/contrib/llvm/tools/lldb/source/Target/ProcessLaunchInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ProcessLaunchInfo.cpp
@@ -14,15 +14,17 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/FileAction.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/FileSystem.h"
#if !defined(_WIN32)
#include <limits.h>
@@ -328,7 +330,7 @@ void ProcessLaunchInfo::FinalizeFileActions(Target *target,
}
bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell(
- Error &error, bool localhost, bool will_debug,
+ Status &error, bool localhost, bool will_debug,
bool first_arg_is_full_shell_command, int32_t num_resumes) {
error.Clear();
@@ -368,10 +370,8 @@ bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell(
if (working_dir) {
new_path += working_dir.GetPath();
} else {
- char current_working_dir[PATH_MAX];
- const char *cwd =
- getcwd(current_working_dir, sizeof(current_working_dir));
- if (cwd && cwd[0])
+ llvm::SmallString<64> cwd;
+ if (! llvm::sys::fs::current_path(cwd))
new_path += cwd;
}
std::string curr_path;
diff --git a/contrib/llvm/tools/lldb/source/Target/RegisterContext.cpp b/contrib/llvm/tools/lldb/source/Target/RegisterContext.cpp
index 4cce4dd..66164c1 100644
--- a/contrib/llvm/tools/lldb/source/Target/RegisterContext.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/RegisterContext.cpp
@@ -12,18 +12,18 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Target/RegisterContext.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Value.h"
#include "lldb/Expression/DWARFExpression.h"
-#include "lldb/Host/Endian.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
using namespace lldb;
using namespace lldb_private;
@@ -91,7 +91,7 @@ RegisterContext::UpdateDynamicRegisterSize(const lldb_private::ArchSpec &arch,
DWARFExpression dwarf_expr(opcode_ctx, dwarf_data, nullptr, 0,
dwarf_opcode_len);
Value result;
- Error error;
+ Status error;
const lldb::offset_t offset = 0;
if (dwarf_expr.Evaluate(&exe_ctx, nullptr, nullptr, this, opcode_ctx,
dwarf_data, nullptr, offset, dwarf_opcode_len,
@@ -299,11 +299,10 @@ bool RegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) {
bool RegisterContext::HardwareSingleStep(bool enable) { return false; }
-Error RegisterContext::ReadRegisterValueFromMemory(const RegisterInfo *reg_info,
- lldb::addr_t src_addr,
- uint32_t src_len,
- RegisterValue &reg_value) {
- Error error;
+Status RegisterContext::ReadRegisterValueFromMemory(
+ const RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len,
+ RegisterValue &reg_value) {
+ Status error;
if (reg_info == nullptr) {
error.SetErrorString("invalid register info argument.");
return error;
@@ -318,7 +317,7 @@ Error RegisterContext::ReadRegisterValueFromMemory(const RegisterInfo *reg_info,
//
// Case 2: src_len > dst_len
//
- // Error! (The register should always be big enough to hold the data)
+ // Status! (The register should always be big enough to hold the data)
//
// Case 3: src_len < dst_len
//
@@ -371,12 +370,12 @@ Error RegisterContext::ReadRegisterValueFromMemory(const RegisterInfo *reg_info,
return error;
}
-Error RegisterContext::WriteRegisterValueToMemory(
+Status RegisterContext::WriteRegisterValueToMemory(
const RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len,
const RegisterValue &reg_value) {
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
- Error error;
+ Status error;
ProcessSP process_sp(m_thread.GetProcess());
if (process_sp) {
diff --git a/contrib/llvm/tools/lldb/source/Utility/RegisterNumber.cpp b/contrib/llvm/tools/lldb/source/Target/RegisterNumber.cpp
index 07dd223..d1bb8ad 100644
--- a/contrib/llvm/tools/lldb/source/Utility/RegisterNumber.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/RegisterNumber.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Utility/RegisterNumber.h"
+#include "lldb/Target/RegisterNumber.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
diff --git a/contrib/llvm/tools/lldb/source/Target/SectionLoadHistory.cpp b/contrib/llvm/tools/lldb/source/Target/SectionLoadHistory.cpp
index 49a7cef..740f48b 100644
--- a/contrib/llvm/tools/lldb/source/Target/SectionLoadHistory.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/SectionLoadHistory.cpp
@@ -13,8 +13,8 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/SectionLoadList.cpp b/contrib/llvm/tools/lldb/source/Target/SectionLoadList.cpp
index a3599dd..31ccf17 100644
--- a/contrib/llvm/tools/lldb/source/Target/SectionLoadList.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/SectionLoadList.cpp
@@ -13,13 +13,13 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -67,21 +67,13 @@ SectionLoadList::GetSectionLoadAddress(const lldb::SectionSP &section) const {
bool SectionLoadList::SetSectionLoadAddress(const lldb::SectionSP &section,
addr_t load_addr,
bool warn_multiple) {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER |
- LIBLLDB_LOG_VERBOSE));
-
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
ModuleSP module_sp(section->GetModule());
if (module_sp) {
- if (log) {
- const FileSpec &module_file_spec(module_sp->GetFileSpec());
- log->Printf("SectionLoadList::%s (section = %p (%s.%s), load_addr = "
- "0x%16.16" PRIx64 ") module = %p",
- __FUNCTION__, static_cast<void *>(section.get()),
- module_file_spec.GetPath().c_str(),
- section->GetName().AsCString(), load_addr,
- static_cast<void *>(module_sp.get()));
- }
+ LLDB_LOGV(log, "(section = {0} ({1}.{2}), load_addr = {3:x}) module = {4}",
+ section.get(), module_sp->GetFileSpec(), section->GetName(),
+ load_addr, module_sp.get());
if (section->GetByteSize() == 0)
return false; // No change
@@ -147,10 +139,9 @@ size_t SectionLoadList::SetSectionUnloaded(const lldb::SectionSP &section_sp) {
size_t unload_count = 0;
if (section_sp) {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER |
- LIBLLDB_LOG_VERBOSE));
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
- if (log) {
+ if (log && log->GetVerbose()) {
ModuleSP module_sp = section_sp->GetModule();
std::string module_name("<Unknown>");
if (module_sp) {
@@ -183,10 +174,9 @@ size_t SectionLoadList::SetSectionUnloaded(const lldb::SectionSP &section_sp) {
bool SectionLoadList::SetSectionUnloaded(const lldb::SectionSP &section_sp,
addr_t load_addr) {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER |
- LIBLLDB_LOG_VERBOSE));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
- if (log) {
+ if (log && log->GetVerbose()) {
ModuleSP module_sp = section_sp->GetModule();
std::string module_name("<Unknown>");
if (module_sp) {
@@ -217,8 +207,8 @@ bool SectionLoadList::SetSectionUnloaded(const lldb::SectionSP &section_sp,
return erased;
}
-bool SectionLoadList::ResolveLoadAddress(addr_t load_addr,
- Address &so_addr) const {
+bool SectionLoadList::ResolveLoadAddress(addr_t load_addr, Address &so_addr,
+ bool allow_section_end) const {
// First find the top level section that this load address exists in
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (!m_addr_to_sect.empty()) {
@@ -230,10 +220,11 @@ bool SectionLoadList::ResolveLoadAddress(addr_t load_addr,
const addr_t pos_load_addr = pos->first;
if (load_addr >= pos_load_addr) {
addr_t offset = load_addr - pos_load_addr;
- if (offset < pos->second->GetByteSize()) {
+ if (offset < pos->second->GetByteSize() + (allow_section_end ? 1 : 0)) {
// We have found the top level section, now we need to find the
// deepest child section.
- return pos->second->ResolveContainedAddress(offset, so_addr);
+ return pos->second->ResolveContainedAddress(offset, so_addr,
+ allow_section_end);
}
}
} else {
@@ -243,10 +234,12 @@ bool SectionLoadList::ResolveLoadAddress(addr_t load_addr,
m_addr_to_sect.rbegin();
if (load_addr >= rpos->first) {
addr_t offset = load_addr - rpos->first;
- if (offset < rpos->second->GetByteSize()) {
+ if (offset <
+ rpos->second->GetByteSize() + (allow_section_end ? 1 : 0)) {
// We have found the top level section, now we need to find the
// deepest child section.
- return rpos->second->ResolveContainedAddress(offset, so_addr);
+ return rpos->second->ResolveContainedAddress(offset, so_addr,
+ allow_section_end);
}
}
}
diff --git a/contrib/llvm/tools/lldb/source/Target/StackFrame.cpp b/contrib/llvm/tools/lldb/source/Target/StackFrame.cpp
index ec30fd6..30fceb1 100644
--- a/contrib/llvm/tools/lldb/source/Target/StackFrame.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/StackFrame.cpp
@@ -17,6 +17,7 @@
#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectMemory.h"
@@ -190,9 +191,10 @@ const Address &StackFrame::GetFrameCodeAddress() {
if (thread_sp) {
TargetSP target_sp(thread_sp->CalculateTarget());
if (target_sp) {
+ const bool allow_section_end = true;
if (m_frame_code_addr.SetOpcodeLoadAddress(
m_frame_code_addr.GetOffset(), target_sp.get(),
- eAddressClassCode)) {
+ eAddressClassCode, allow_section_end)) {
ModuleSP module_sp(m_frame_code_addr.GetModule());
if (module_sp) {
m_sc.module_sp = module_sp;
@@ -221,18 +223,20 @@ bool StackFrame::ChangePC(addr_t pc) {
const char *StackFrame::Disassemble() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (m_disassembly.Empty())
- return nullptr;
-
- ExecutionContext exe_ctx(shared_from_this());
- Target *target = exe_ctx.GetTargetPtr();
- if (target) {
- const char *plugin_name = nullptr;
- const char *flavor = nullptr;
- Disassembler::Disassemble(target->GetDebugger(), target->GetArchitecture(),
- plugin_name, flavor, exe_ctx, 0, false, 0, 0,
- m_disassembly);
+ if (m_disassembly.Empty()) {
+ ExecutionContext exe_ctx(shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target) {
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ Disassembler::Disassemble(target->GetDebugger(),
+ target->GetArchitecture(), plugin_name, flavor,
+ exe_ctx, 0, false, 0, 0, m_disassembly);
+ }
+ if (m_disassembly.Empty())
+ return nullptr;
}
+
return m_disassembly.GetData();
}
@@ -425,7 +429,7 @@ VariableList *StackFrame::GetVariableList(bool get_file_globals) {
m_variable_list_sp.reset(new VariableList());
frame_block->AppendBlockVariables(can_create, get_child_variables,
stop_if_child_block_is_inlined_function,
- [this](Variable *v) { return true; },
+ [](Variable *v) { return true; },
m_variable_list_sp.get());
}
}
@@ -485,7 +489,7 @@ StackFrame::GetInScopeVariableList(bool get_file_globals,
ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
llvm::StringRef var_expr, DynamicValueType use_dynamic, uint32_t options,
- VariableSP &var_sp, Error &error) {
+ VariableSP &var_sp, Status &error) {
llvm::StringRef original_var_expr = var_expr;
// We can't fetch variable information for a history stack frame.
if (m_is_history_frame)
@@ -604,8 +608,10 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// Calculate the next separator index ahead of time
ValueObjectSP child_valobj_sp;
const char separator_type = var_expr[0];
+ bool expr_is_ptr = false;
switch (separator_type) {
case '-':
+ expr_is_ptr = true;
if (var_expr.size() >= 2 && var_expr[1] != '>')
return ValueObjectSP();
@@ -622,11 +628,32 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
return ValueObjectSP();
}
}
+
+ // If we have a non pointer type with a sythetic value then lets check if
+ // we have an sythetic dereference specified.
+ if (!valobj_sp->IsPointerType() && valobj_sp->HasSyntheticValue()) {
+ Status deref_error;
+ if (valobj_sp->GetCompilerType().IsReferenceType()) {
+ valobj_sp = valobj_sp->GetSyntheticValue()->Dereference(deref_error);
+ if (error.Fail()) {
+ error.SetErrorStringWithFormatv(
+ "Failed to dereference reference type: %s", deref_error);
+ return ValueObjectSP();
+ }
+ }
+
+ valobj_sp = valobj_sp->Dereference(deref_error);
+ if (error.Fail()) {
+ error.SetErrorStringWithFormatv(
+ "Failed to dereference sythetic value: %s", deref_error);
+ return ValueObjectSP();
+ }
+ expr_is_ptr = false;
+ }
+
var_expr = var_expr.drop_front(); // Remove the '-'
LLVM_FALLTHROUGH;
case '.': {
- const bool expr_is_ptr = var_expr[0] == '>';
-
var_expr = var_expr.drop_front(); // Remove the '.' or '>'
separator_idx = var_expr.find_first_of(".-[");
ConstString child_name(var_expr.substr(0, var_expr.find_first_of(".-[")));
@@ -749,7 +776,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// what we have is *ptr[low]. the most similar C++ syntax is to deref
// ptr and extract bit low out of it. reading array item low would be
// done by saying ptr[low], without a deref * sign
- Error error;
+ Status error;
ValueObjectSP temp(valobj_sp->Dereference(error));
if (error.Fail()) {
valobj_sp->GetExpressionPath(var_expr_path_strm, false);
@@ -768,7 +795,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// (an operation that is equivalent to deref-ing arr)
// and extract bit low out of it. reading array item low
// would be done by saying arr[low], without a deref * sign
- Error error;
+ Status error;
ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true));
if (error.Fail()) {
valobj_sp->GetExpressionPath(var_expr_path_strm, false);
@@ -951,7 +978,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// deref ptr and extract bits low thru high out of it. reading array
// items low thru high would be done by saying ptr[low-high], without
// a deref * sign
- Error error;
+ Status error;
ValueObjectSP temp(valobj_sp->Dereference(error));
if (error.Fail()) {
valobj_sp->GetExpressionPath(var_expr_path_strm, false);
@@ -968,7 +995,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// arr[0] (an operation that is equivalent to deref-ing arr) and extract
// bits low thru high out of it. reading array items low thru high would
// be done by saying arr[low-high], without a deref * sign
- Error error;
+ Status error;
ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true));
if (error.Fail()) {
valobj_sp->GetExpressionPath(var_expr_path_strm, false);
@@ -1039,7 +1066,7 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
return valobj_sp;
}
-bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Error *error_ptr) {
+bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Status *error_ptr) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (!m_cfa_is_valid) {
m_frame_base_error.SetErrorString(
@@ -1085,7 +1112,7 @@ bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Error *error_ptr) {
return m_frame_base_error.Success();
}
-DWARFExpression *StackFrame::GetFrameBaseExpression(Error *error_ptr) {
+DWARFExpression *StackFrame::GetFrameBaseExpression(Status *error_ptr) {
if (!m_sc.function) {
if (error_ptr) {
error_ptr->SetErrorString("No function in symbol context.");
@@ -1186,9 +1213,14 @@ lldb::LanguageType StackFrame::GuessLanguage() {
LanguageType lang_type = GetLanguage();
if (lang_type == eLanguageTypeUnknown) {
- Function *f = GetSymbolContext(eSymbolContextFunction).function;
- if (f) {
- lang_type = f->GetMangled().GuessLanguage();
+ SymbolContext sc = GetSymbolContext(eSymbolContextFunction
+ | eSymbolContextSymbol);
+ if (sc.function) {
+ lang_type = sc.function->GetMangled().GuessLanguage();
+ }
+ else if (sc.symbol)
+ {
+ lang_type = sc.symbol->GetMangled().GuessLanguage();
}
}
@@ -1289,7 +1321,7 @@ lldb::ValueObjectSP StackFrame::GuessValueForAddress(lldb::addr_t addr) {
DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
target_arch, plugin_name, flavor, exe_ctx, pc_range, prefer_file_cache);
- if (!disassembler_sp->GetInstructionList().GetSize()) {
+ if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) {
return ValueObjectSP();
}
@@ -1395,7 +1427,7 @@ ValueObjectSP GetValueForDereferincingOffset(StackFrame &frame,
return ValueObjectSP();
}
- Error error;
+ Status error;
ValueObjectSP pointee = base->Dereference(error);
if (!pointee) {
@@ -1712,7 +1744,7 @@ void StackFrame::CalculateExecutionContext(ExecutionContext &exe_ctx) {
exe_ctx.SetContext(shared_from_this());
}
-void StackFrame::DumpUsingSettingsFormat(Stream *strm,
+void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique,
const char *frame_marker) {
if (strm == nullptr)
return;
@@ -1726,8 +1758,13 @@ void StackFrame::DumpUsingSettingsFormat(Stream *strm,
const FormatEntity::Entry *frame_format = nullptr;
Target *target = exe_ctx.GetTargetPtr();
- if (target)
- frame_format = target->GetDebugger().GetFrameFormat();
+ if (target) {
+ if (show_unique) {
+ frame_format = target->GetDebugger().GetFrameFormatUnique();
+ } else {
+ frame_format = target->GetDebugger().GetFrameFormat();
+ }
+ }
if (frame_format && FormatEntity::Format(*frame_format, s, &m_sc, &exe_ctx,
nullptr, nullptr, false, false)) {
strm->PutCString(s.GetString());
@@ -1809,11 +1846,10 @@ bool StackFrame::HasCachedData() const {
}
bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source,
- const char *frame_marker) {
-
+ bool show_unique, const char *frame_marker) {
if (show_frame_info) {
strm.Indent();
- DumpUsingSettingsFormat(&strm, frame_marker);
+ DumpUsingSettingsFormat(&strm, show_unique, frame_marker);
}
if (show_source) {
diff --git a/contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp b/contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp
index 146b2b0..be7fa80 100644
--- a/contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/StackFrameList.cpp
@@ -14,7 +14,6 @@
#include "lldb/Target/StackFrameList.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Symbol/Block.h"
@@ -27,6 +26,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/Log.h"
//#define DEBUG_STACK_FRAMES 1
@@ -802,6 +802,7 @@ StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) {
size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
uint32_t num_frames, bool show_frame_info,
uint32_t num_frames_with_source,
+ bool show_unique,
const char *selected_frame_marker) {
size_t num_frames_displayed = 0;
@@ -842,7 +843,7 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
if (!frame_sp->GetStatus(strm, show_frame_info,
num_frames_with_source > (first_frame - frame_idx),
- marker))
+ show_unique, marker))
break;
++num_frames_displayed;
}
diff --git a/contrib/llvm/tools/lldb/source/Target/StackID.cpp b/contrib/llvm/tools/lldb/source/Target/StackID.cpp
index 0d215ed..889cf89 100644
--- a/contrib/llvm/tools/lldb/source/Target/StackID.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/StackID.cpp
@@ -12,10 +12,10 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Target/StackID.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/StopInfo.cpp b/contrib/llvm/tools/lldb/source/Target/StopInfo.cpp
index 23dea41..6af5ce1 100644
--- a/contrib/llvm/tools/lldb/source/Target/StopInfo.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/StopInfo.cpp
@@ -18,8 +18,6 @@
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/UserExpression.h"
#include "lldb/Target/Process.h"
@@ -28,6 +26,8 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
@@ -269,6 +269,7 @@ protected:
if (!m_should_perform_action)
return;
m_should_perform_action = false;
+ bool internal_breakpoint = true;
ThreadSP thread_sp(m_thread_wp.lock());
@@ -434,7 +435,7 @@ protected:
// shouldn't stop that will win.
if (bp_loc_sp->GetConditionText() != nullptr) {
- Error condition_error;
+ Status condition_error;
bool condition_says_stop =
bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error);
@@ -495,6 +496,9 @@ protected:
if (callback_says_stop)
m_should_stop = true;
+ if (m_should_stop && !bp_loc_sp->GetBreakpoint().IsInternal())
+ internal_breakpoint = false;
+
// If we are going to stop for this breakpoint, then remove the
// breakpoint.
if (callback_says_stop && bp_loc_sp &&
@@ -526,6 +530,20 @@ protected:
"Process::%s could not find breakpoint site id: %" PRId64 "...",
__FUNCTION__, m_value);
}
+
+ if ((m_should_stop == false || internal_breakpoint)
+ && thread_sp->CompletedPlanOverridesBreakpoint()) {
+
+ // Override should_stop decision when we have
+ // completed step plan additionally to the breakpoint
+ m_should_stop = true;
+
+ // Here we clean the preset stop info so the next
+ // GetStopInfo call will find the appropriate stop info,
+ // which should be the stop info related to the completed plan
+ thread_sp->ResetStopInfo();
+ }
+
if (log)
log->Printf("Process::%s returning from action with m_should_stop: %d.",
__FUNCTION__, m_should_stop);
@@ -778,7 +796,7 @@ protected:
expr_options.SetUnwindOnError(true);
expr_options.SetIgnoreBreakpoints(true);
ValueObjectSP result_value_sp;
- Error error;
+ Status error;
result_code = UserExpression::Evaluate(
exe_ctx, expr_options, wp_sp->GetConditionText(),
llvm::StringRef(), result_value_sp, error);
diff --git a/contrib/llvm/tools/lldb/source/Target/Target.cpp b/contrib/llvm/tools/lldb/source/Target/Target.cpp
index 078fa6a..d97f651 100644
--- a/contrib/llvm/tools/lldb/source/Target/Target.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/Target.cpp
@@ -24,20 +24,17 @@
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/REPL.h"
#include "lldb/Expression/UserExpression.h"
-#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/PosixApi.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionGroupWatchpoint.h"
@@ -57,7 +54,11 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
@@ -182,7 +183,7 @@ const lldb::ProcessSP &Target::CreateProcess(ListenerSP listener_sp,
const lldb::ProcessSP &Target::GetProcessSP() const { return m_process_sp; }
-lldb::REPLSP Target::GetREPL(Error &err, lldb::LanguageType language,
+lldb::REPLSP Target::GetREPL(Status &err, lldb::LanguageType language,
const char *repl_options, bool can_create) {
if (language == eLanguageTypeUnknown) {
std::set<LanguageType> repl_languages;
@@ -547,7 +548,7 @@ BreakpointSP Target::CreateFuncRegexBreakpoint(
lldb::BreakpointSP
Target::CreateExceptionBreakpoint(enum lldb::LanguageType language,
bool catch_bp, bool throw_bp, bool internal,
- Args *additional_args, Error *error) {
+ Args *additional_args, Status *error) {
BreakpointSP exc_bkpt_sp = LanguageRuntime::CreateExceptionBreakpoint(
*this, language, catch_bp, throw_bp, internal);
if (exc_bkpt_sp && additional_args) {
@@ -604,9 +605,9 @@ bool Target::ProcessIsValid() {
return (m_process_sp && m_process_sp->IsAlive());
}
-static bool CheckIfWatchpointsExhausted(Target *target, Error &error) {
+static bool CheckIfWatchpointsExhausted(Target *target, Status &error) {
uint32_t num_supported_hardware_watchpoints;
- Error rc = target->GetProcessSP()->GetWatchpointSupportInfo(
+ Status rc = target->GetProcessSP()->GetWatchpointSupportInfo(
num_supported_hardware_watchpoints);
if (num_supported_hardware_watchpoints == 0) {
error.SetErrorStringWithFormat(
@@ -621,7 +622,7 @@ static bool CheckIfWatchpointsExhausted(Target *target, Error &error) {
// the OptionGroupWatchpoint::WatchType enum type.
WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size,
const CompilerType *type, uint32_t kind,
- Error &error) {
+ Status &error) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
if (log)
log->Printf("Target::%s (addr = 0x%8.8" PRIx64 " size = %" PRIu64
@@ -797,10 +798,10 @@ bool Target::EnableBreakpointByID(break_id_t break_id) {
return false;
}
-Error Target::SerializeBreakpointsToFile(const FileSpec &file,
- const BreakpointIDList &bp_ids,
- bool append) {
- Error error;
+Status Target::SerializeBreakpointsToFile(const FileSpec &file,
+ const BreakpointIDList &bp_ids,
+ bool append) {
+ Status error;
if (!file) {
error.SetErrorString("Invalid FileSpec.");
@@ -891,19 +892,19 @@ Error Target::SerializeBreakpointsToFile(const FileSpec &file,
return error;
}
-Error Target::CreateBreakpointsFromFile(const FileSpec &file,
- BreakpointIDList &new_bps) {
+Status Target::CreateBreakpointsFromFile(const FileSpec &file,
+ BreakpointIDList &new_bps) {
std::vector<std::string> no_names;
return CreateBreakpointsFromFile(file, no_names, new_bps);
}
-Error Target::CreateBreakpointsFromFile(const FileSpec &file,
- std::vector<std::string> &names,
- BreakpointIDList &new_bps) {
+Status Target::CreateBreakpointsFromFile(const FileSpec &file,
+ std::vector<std::string> &names,
+ BreakpointIDList &new_bps) {
std::unique_lock<std::recursive_mutex> lock;
GetBreakpointList().GetListMutex(lock);
- Error error;
+ Status error;
StructuredData::ObjectSP input_data_sp =
StructuredData::ParseJSONFromFile(file, error);
if (!error.Success()) {
@@ -979,7 +980,7 @@ bool Target::RemoveAllWatchpoints(bool end_to_end) {
if (!wp_sp)
return false;
- Error rc = m_process_sp->DisableWatchpoint(wp_sp.get());
+ Status rc = m_process_sp->DisableWatchpoint(wp_sp.get());
if (rc.Fail())
return false;
}
@@ -1011,7 +1012,7 @@ bool Target::DisableAllWatchpoints(bool end_to_end) {
if (!wp_sp)
return false;
- Error rc = m_process_sp->DisableWatchpoint(wp_sp.get());
+ Status rc = m_process_sp->DisableWatchpoint(wp_sp.get());
if (rc.Fail())
return false;
}
@@ -1041,7 +1042,7 @@ bool Target::EnableAllWatchpoints(bool end_to_end) {
if (!wp_sp)
return false;
- Error rc = m_process_sp->EnableWatchpoint(wp_sp.get());
+ Status rc = m_process_sp->EnableWatchpoint(wp_sp.get());
if (rc.Fail())
return false;
}
@@ -1114,7 +1115,7 @@ bool Target::DisableWatchpointByID(lldb::watch_id_t watch_id) {
WatchpointSP wp_sp = m_watchpoint_list.FindByID(watch_id);
if (wp_sp) {
- Error rc = m_process_sp->DisableWatchpoint(wp_sp.get());
+ Status rc = m_process_sp->DisableWatchpoint(wp_sp.get());
if (rc.Success())
return true;
@@ -1134,7 +1135,7 @@ bool Target::EnableWatchpointByID(lldb::watch_id_t watch_id) {
WatchpointSP wp_sp = m_watchpoint_list.FindByID(watch_id);
if (wp_sp) {
- Error rc = m_process_sp->EnableWatchpoint(wp_sp.get());
+ Status rc = m_process_sp->EnableWatchpoint(wp_sp.get());
if (rc.Success())
return true;
@@ -1198,7 +1199,7 @@ Module *Target::GetExecutableModulePointer() {
static void LoadScriptingResourceForModule(const ModuleSP &module_sp,
Target *target) {
- Error error;
+ Status error;
StreamString feedback_stream;
if (module_sp &&
!module_sp->LoadScriptingResourceInTarget(target, error,
@@ -1235,7 +1236,8 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
ClearModules(false);
if (executable_sp) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
"Target::SetExecutableModule (executable = '%s')",
executable_sp->GetFileSpec().GetPath().c_str());
@@ -1335,9 +1337,9 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec) {
arch_spec.GetArchitectureName(),
arch_spec.GetTriple().getTriple().c_str());
ModuleSpec module_spec(executable_sp->GetFileSpec(), other);
- Error error = ModuleList::GetSharedModule(module_spec, executable_sp,
- &GetExecutableSearchPaths(),
- nullptr, nullptr);
+ Status error = ModuleList::GetSharedModule(module_spec, executable_sp,
+ &GetExecutableSearchPaths(),
+ nullptr, nullptr);
if (!error.Fail() && executable_sp) {
SetExecutableModule(executable_sp, true);
@@ -1474,7 +1476,7 @@ bool Target::ModuleIsExcludedForUnconstrainedSearches(
}
size_t Target::ReadMemoryFromFileCache(const Address &addr, void *dst,
- size_t dst_len, Error &error) {
+ size_t dst_len, Status &error) {
SectionSP section_sp(addr.GetSection());
if (section_sp) {
// If the contents of this section are encrypted, the on-disk file is
@@ -1506,7 +1508,7 @@ size_t Target::ReadMemoryFromFileCache(const Address &addr, void *dst,
}
size_t Target::ReadMemory(const Address &addr, bool prefer_file_cache,
- void *dst, size_t dst_len, Error &error,
+ void *dst, size_t dst_len, Status &error,
lldb::addr_t *load_addr_ptr) {
error.Clear();
@@ -1598,7 +1600,7 @@ size_t Target::ReadMemory(const Address &addr, bool prefer_file_cache,
}
size_t Target::ReadCStringFromMemory(const Address &addr, std::string &out_str,
- Error &error) {
+ Status &error) {
char buf[256];
out_str.clear();
addr_t curr_addr = addr.GetLoadAddress(this);
@@ -1620,13 +1622,13 @@ size_t Target::ReadCStringFromMemory(const Address &addr, std::string &out_str,
}
size_t Target::ReadCStringFromMemory(const Address &addr, char *dst,
- size_t dst_max_len, Error &result_error) {
+ size_t dst_max_len, Status &result_error) {
size_t total_cstr_len = 0;
if (dst && dst_max_len) {
result_error.Clear();
// NULL out everything just to be safe
memset(dst, 0, dst_max_len);
- Error error;
+ Status error;
addr_t curr_addr = addr.GetLoadAddress(this);
Address address(addr);
@@ -1675,7 +1677,7 @@ size_t Target::ReadCStringFromMemory(const Address &addr, char *dst,
size_t Target::ReadScalarIntegerFromMemory(const Address &addr,
bool prefer_file_cache,
uint32_t byte_size, bool is_signed,
- Scalar &scalar, Error &error) {
+ Scalar &scalar, Status &error) {
uint64_t uval;
if (byte_size <= sizeof(uval)) {
@@ -1705,7 +1707,7 @@ uint64_t Target::ReadUnsignedIntegerFromMemory(const Address &addr,
bool prefer_file_cache,
size_t integer_byte_size,
uint64_t fail_value,
- Error &error) {
+ Status &error) {
Scalar scalar;
if (ReadScalarIntegerFromMemory(addr, prefer_file_cache, integer_byte_size,
false, scalar, error))
@@ -1714,7 +1716,7 @@ uint64_t Target::ReadUnsignedIntegerFromMemory(const Address &addr,
}
bool Target::ReadPointerFromMemory(const Address &addr, bool prefer_file_cache,
- Error &error, Address &pointer_addr) {
+ Status &error, Address &pointer_addr) {
Scalar scalar;
if (ReadScalarIntegerFromMemory(addr, prefer_file_cache,
m_arch.GetAddressByteSize(), false, scalar,
@@ -1744,10 +1746,10 @@ bool Target::ReadPointerFromMemory(const Address &addr, bool prefer_file_cache,
}
ModuleSP Target::GetSharedModule(const ModuleSpec &module_spec,
- Error *error_ptr) {
+ Status *error_ptr) {
ModuleSP module_sp;
- Error error;
+ Status error;
// First see if we already have this module in our module list. If we do,
// then we're done, we don't need
@@ -1870,6 +1872,11 @@ ModuleSP Target::GetSharedModule(const ModuleSpec &module_spec,
}
}
+ // Preload symbols outside of any lock, so hopefully we can do this for
+ // each library in parallel.
+ if (GetPreloadSymbols())
+ module_sp->PreloadSymbols();
+
if (old_module_sp &&
m_images.GetIndexForModule(old_module_sp.get()) !=
LLDB_INVALID_INDEX32) {
@@ -1913,7 +1920,7 @@ void Target::ImageSearchPathsChanged(const PathMappingList &path_list,
target->SetExecutableModule(exe_module_sp, true);
}
-TypeSystem *Target::GetScratchTypeSystemForLanguage(Error *error,
+TypeSystem *Target::GetScratchTypeSystemForLanguage(Status *error,
lldb::LanguageType language,
bool create_on_demand) {
if (!m_valid)
@@ -1963,8 +1970,8 @@ Target::GetPersistentExpressionStateForLanguage(lldb::LanguageType language) {
UserExpression *Target::GetUserExpressionForLanguage(
llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
Expression::ResultType desired_type,
- const EvaluateExpressionOptions &options, Error &error) {
- Error type_system_error;
+ const EvaluateExpressionOptions &options, Status &error) {
+ Status type_system_error;
TypeSystem *type_system =
GetScratchTypeSystemForLanguage(&type_system_error, language);
@@ -1991,8 +1998,8 @@ UserExpression *Target::GetUserExpressionForLanguage(
FunctionCaller *Target::GetFunctionCallerForLanguage(
lldb::LanguageType language, const CompilerType &return_type,
const Address &function_address, const ValueList &arg_value_list,
- const char *name, Error &error) {
- Error type_system_error;
+ const char *name, Status &error) {
+ Status type_system_error;
TypeSystem *type_system =
GetScratchTypeSystemForLanguage(&type_system_error, language);
FunctionCaller *persistent_fn = nullptr;
@@ -2018,8 +2025,8 @@ FunctionCaller *Target::GetFunctionCallerForLanguage(
UtilityFunction *
Target::GetUtilityFunctionForLanguage(const char *text,
lldb::LanguageType language,
- const char *name, Error &error) {
- Error type_system_error;
+ const char *name, Status &error) {
+ Status type_system_error;
TypeSystem *type_system =
GetScratchTypeSystemForLanguage(&type_system_error, language);
UtilityFunction *utility_fn = nullptr;
@@ -2157,7 +2164,7 @@ ExpressionResults Target::EvaluateExpression(
execution_results = eExpressionCompleted;
} else {
const char *prefix = GetExpressionPrefixContentsAsCString();
- Error error;
+ Status error;
execution_results = UserExpression::Evaluate(exe_ctx, options, expr, prefix,
result_valobj_sp, error,
0, // Line Number
@@ -2173,7 +2180,7 @@ lldb::ExpressionVariableSP
Target::GetPersistentVariable(const ConstString &name) {
lldb::ExpressionVariableSP variable_sp;
m_scratch_type_system_map.ForEach(
- [this, name, &variable_sp](TypeSystem *type_system) -> bool {
+ [name, &variable_sp](TypeSystem *type_system) -> bool {
if (PersistentExpressionState *persistent_state =
type_system->GetPersistentExpressionState()) {
variable_sp = persistent_state->GetVariable(name);
@@ -2190,7 +2197,7 @@ lldb::addr_t Target::GetPersistentSymbol(const ConstString &name) {
lldb::addr_t address = LLDB_INVALID_ADDRESS;
m_scratch_type_system_map.ForEach(
- [this, name, &address](TypeSystem *type_system) -> bool {
+ [name, &address](TypeSystem *type_system) -> bool {
if (PersistentExpressionState *persistent_state =
type_system->GetPersistentExpressionState()) {
address = persistent_state->LookupSymbol(name);
@@ -2648,8 +2655,8 @@ const TargetPropertiesSP &Target::GetGlobalProperties() {
return *g_settings_sp_ptr;
}
-Error Target::Install(ProcessLaunchInfo *launch_info) {
- Error error;
+Status Target::Install(ProcessLaunchInfo *launch_info) {
+ Status error;
PlatformSP platform_sp(GetPlatform());
if (platform_sp) {
if (platform_sp->IsRemote()) {
@@ -2779,8 +2786,8 @@ bool Target::SetSectionUnloaded(const lldb::SectionSP &section_sp,
void Target::ClearAllLoadedSections() { m_section_load_history.Clear(); }
-Error Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
- Error error;
+Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
+ Status error;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET));
if (log)
@@ -2928,7 +2935,7 @@ Error Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
error = m_process_sp->PrivateResume();
}
if (!error.Success()) {
- Error error2;
+ Status error2;
error2.SetErrorStringWithFormat(
"process resume at entry point failed: %s", error.AsCString());
error = error2;
@@ -2966,7 +2973,7 @@ Error Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
}
m_process_sp->RestoreProcessEvents();
} else {
- Error error2;
+ Status error2;
error2.SetErrorStringWithFormat("process launch failed: %s",
error.AsCString());
error = error2;
@@ -2974,15 +2981,15 @@ Error Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
return error;
}
-Error Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
+Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
auto state = eStateInvalid;
auto process_sp = GetProcessSP();
if (process_sp) {
state = process_sp->GetState();
if (process_sp->IsAlive() && state != eStateConnected) {
if (state == eStateAttaching)
- return Error("process attach is in progress");
- return Error("a process is already being debugged");
+ return Status("process attach is in progress");
+ return Status("a process is already being debugged");
}
}
@@ -2996,8 +3003,8 @@ Error Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
old_exec_module_sp->GetPlatformFileSpec().GetFilename();
if (!attach_info.ProcessInfoSpecified()) {
- return Error("no process specified, create a target with a file, or "
- "specify the --pid or --name");
+ return Status("no process specified, create a target with a file, or "
+ "specify the --pid or --name");
}
}
@@ -3011,7 +3018,7 @@ Error Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
attach_info.SetHijackListener(hijack_listener_sp);
}
- Error error;
+ Status error;
if (state != eStateConnected && platform_sp != nullptr &&
platform_sp->CanDebugProcess()) {
SetPlatform(platform_sp);
@@ -3277,6 +3284,8 @@ static PropertyDefinition g_properties[] = {
{"detach-on-error", OptionValue::eTypeBoolean, false, true, nullptr,
nullptr, "debugserver will detach (rather than killing) a process if it "
"loses connection with lldb."},
+ {"preload-symbols", OptionValue::eTypeBoolean, false, true, nullptr, nullptr,
+ "Enable loading of symbol tables before they are needed."},
{"disable-aslr", OptionValue::eTypeBoolean, false, true, nullptr, nullptr,
"Disable Address Space Layout Randomization (ASLR)"},
{"disable-stdio", OptionValue::eTypeBoolean, false, false, nullptr, nullptr,
@@ -3379,6 +3388,7 @@ enum {
ePropertyOutputPath,
ePropertyErrorPath,
ePropertyDetachOnError,
+ ePropertyPreloadSymbols,
ePropertyDisableASLR,
ePropertyDisableSTDIO,
ePropertyInlineStrategy,
@@ -3641,6 +3651,17 @@ bool TargetProperties::SetPreferDynamicValue(lldb::DynamicValueType d) {
return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, d);
}
+bool TargetProperties::GetPreloadSymbols() const {
+ const uint32_t idx = ePropertyPreloadSymbols;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void TargetProperties::SetPreloadSymbols(bool b) {
+ const uint32_t idx = ePropertyPreloadSymbols;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
+}
+
bool TargetProperties::GetDisableASLR() const {
const uint32_t idx = ePropertyDisableASLR;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
diff --git a/contrib/llvm/tools/lldb/source/Target/TargetList.cpp b/contrib/llvm/tools/lldb/source/Target/TargetList.cpp
index 0637cff..5c652ac 100644
--- a/contrib/llvm/tools/lldb/source/Target/TargetList.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/TargetList.cpp
@@ -7,19 +7,14 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-#include "llvm/ADT/SmallString.h"
-
// Project includes
+#include "lldb/Target/TargetList.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Interpreter/CommandInterpreter.h"
@@ -27,7 +22,12 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
-#include "lldb/Target/TargetList.h"
+#include "lldb/Utility/TildeExpressionResolver.h"
+#include "lldb/Utility/Timer.h"
+
+// Other libraries and framework includes
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
using namespace lldb;
using namespace lldb_private;
@@ -55,33 +55,33 @@ TargetList::~TargetList() {
m_target_list.clear();
}
-Error TargetList::CreateTarget(Debugger &debugger,
- llvm::StringRef user_exe_path,
- llvm::StringRef triple_str,
- bool get_dependent_files,
- const OptionGroupPlatform *platform_options,
- TargetSP &target_sp) {
+Status TargetList::CreateTarget(Debugger &debugger,
+ llvm::StringRef user_exe_path,
+ llvm::StringRef triple_str,
+ bool get_dependent_files,
+ const OptionGroupPlatform *platform_options,
+ TargetSP &target_sp) {
return CreateTargetInternal(debugger, user_exe_path, triple_str,
get_dependent_files, platform_options, target_sp,
false);
}
-Error TargetList::CreateTarget(Debugger &debugger,
- llvm::StringRef user_exe_path,
- const ArchSpec &specified_arch,
- bool get_dependent_files,
- PlatformSP &platform_sp, TargetSP &target_sp) {
+Status TargetList::CreateTarget(Debugger &debugger,
+ llvm::StringRef user_exe_path,
+ const ArchSpec &specified_arch,
+ bool get_dependent_files,
+ PlatformSP &platform_sp, TargetSP &target_sp) {
return CreateTargetInternal(debugger, user_exe_path, specified_arch,
get_dependent_files, platform_sp, target_sp,
false);
}
-Error TargetList::CreateTargetInternal(
+Status TargetList::CreateTargetInternal(
Debugger &debugger, llvm::StringRef user_exe_path,
llvm::StringRef triple_str, bool get_dependent_files,
const OptionGroupPlatform *platform_options, TargetSP &target_sp,
bool is_dummy_target) {
- Error error;
+ Status error;
PlatformSP platform_sp;
// This is purposely left empty unless it is specified by triple_cstr.
@@ -302,34 +302,34 @@ lldb::TargetSP TargetList::GetDummyTarget(lldb_private::Debugger &debugger) {
ArchSpec arch(Target::GetDefaultArchitecture());
if (!arch.IsValid())
arch = HostInfo::GetArchitecture();
- Error err = CreateDummyTarget(
+ Status err = CreateDummyTarget(
debugger, arch.GetTriple().getTriple().c_str(), m_dummy_target_sp);
}
return m_dummy_target_sp;
}
-Error TargetList::CreateDummyTarget(Debugger &debugger,
- llvm::StringRef specified_arch_name,
- lldb::TargetSP &target_sp) {
+Status TargetList::CreateDummyTarget(Debugger &debugger,
+ llvm::StringRef specified_arch_name,
+ lldb::TargetSP &target_sp) {
PlatformSP host_platform_sp(Platform::GetHostPlatform());
return CreateTargetInternal(
debugger, (const char *)nullptr, specified_arch_name, false,
(const OptionGroupPlatform *)nullptr, target_sp, true);
}
-Error TargetList::CreateTargetInternal(Debugger &debugger,
- llvm::StringRef user_exe_path,
- const ArchSpec &specified_arch,
- bool get_dependent_files,
- lldb::PlatformSP &platform_sp,
- lldb::TargetSP &target_sp,
- bool is_dummy_target) {
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
- "TargetList::CreateTarget (file = '%s', arch = '%s')",
- user_exe_path.str().c_str(),
- specified_arch.GetArchitectureName());
- Error error;
+Status TargetList::CreateTargetInternal(Debugger &debugger,
+ llvm::StringRef user_exe_path,
+ const ArchSpec &specified_arch,
+ bool get_dependent_files,
+ lldb::PlatformSP &platform_sp,
+ lldb::TargetSP &target_sp,
+ bool is_dummy_target) {
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(
+ func_cat, "TargetList::CreateTarget (file = '%s', arch = '%s')",
+ user_exe_path.str().c_str(), specified_arch.GetArchitectureName());
+ Status error;
ArchSpec arch(specified_arch);
@@ -348,10 +348,10 @@ Error TargetList::CreateTargetInternal(Debugger &debugger,
FileSpec file(user_exe_path, false);
if (!file.Exists() && user_exe_path.startswith("~")) {
// we want to expand the tilde but we don't want to resolve any symbolic
- // links
- // so we can't use the FileSpec constructor's resolve flag
- llvm::SmallString<64> unglobbed_path(user_exe_path);
- FileSpec::ResolveUsername(unglobbed_path);
+ // links so we can't use the FileSpec constructor's resolve flag
+ llvm::SmallString<64> unglobbed_path;
+ StandardTildeExpressionResolver Resolver;
+ Resolver.ResolveFullPath(user_exe_path, unglobbed_path);
if (unglobbed_path.empty())
file = FileSpec(user_exe_path, false);
@@ -363,18 +363,17 @@ Error TargetList::CreateTargetInternal(Debugger &debugger,
char resolved_bundle_exe_path[PATH_MAX];
resolved_bundle_exe_path[0] = '\0';
if (file) {
- if (file.GetFileType() == FileSpec::eFileTypeDirectory)
+ if (llvm::sys::fs::is_directory(file.GetPath()))
user_exe_path_is_bundle = true;
if (file.IsRelative() && !user_exe_path.empty()) {
// Ignore paths that start with "./" and "../"
if (!user_exe_path.startswith("./") && !user_exe_path.startswith("../")) {
- char cwd[PATH_MAX];
- if (getcwd(cwd, sizeof(cwd))) {
- std::string cwd_user_exe_path(cwd);
- cwd_user_exe_path += '/';
- cwd_user_exe_path += user_exe_path;
- FileSpec cwd_file(cwd_user_exe_path, false);
+ llvm::SmallString<64> cwd;
+ if (! llvm::sys::fs::current_path(cwd)) {
+ cwd += '/';
+ cwd += user_exe_path;
+ FileSpec cwd_file(cwd, false);
if (cwd_file.Exists())
file = cwd_file;
}
diff --git a/contrib/llvm/tools/lldb/source/Target/Thread.cpp b/contrib/llvm/tools/lldb/source/Target/Thread.cpp
index 5ead590..505d140 100644
--- a/contrib/llvm/tools/lldb/source/Target/Thread.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/Thread.cpp
@@ -17,12 +17,8 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FormatEntity.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/State.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/OptionValueFileSpecList.h"
@@ -51,6 +47,11 @@
#include "lldb/Target/ThreadPlanStepUntil.h"
#include "lldb/Target/ThreadSpec.h"
#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-enumerations.h"
using namespace lldb;
using namespace lldb_private;
@@ -380,24 +381,32 @@ lldb::StopInfoSP Thread::GetStopInfo() {
if (m_destroy_called)
return m_stop_info_sp;
- ThreadPlanSP plan_sp(GetCompletedPlan());
+ ThreadPlanSP completed_plan_sp(GetCompletedPlan());
ProcessSP process_sp(GetProcess());
const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX;
- if (plan_sp && plan_sp->PlanSucceeded()) {
- return StopInfo::CreateStopReasonWithPlan(plan_sp, GetReturnValueObject(),
- GetExpressionVariable());
+
+ // Here we select the stop info according to priorirty:
+ // - m_stop_info_sp (if not trace) - preset value
+ // - completed plan stop info - new value with plan from completed plan stack
+ // - m_stop_info_sp (trace stop reason is OK now)
+ // - ask GetPrivateStopInfo to set stop info
+
+ bool have_valid_stop_info = m_stop_info_sp &&
+ m_stop_info_sp ->IsValid() &&
+ m_stop_info_stop_id == stop_id;
+ bool have_valid_completed_plan = completed_plan_sp && completed_plan_sp->PlanSucceeded();
+ bool plan_overrides_trace =
+ have_valid_stop_info && have_valid_completed_plan
+ && (m_stop_info_sp->GetStopReason() == eStopReasonTrace);
+
+ if (have_valid_stop_info && !plan_overrides_trace) {
+ return m_stop_info_sp;
+ } else if (have_valid_completed_plan) {
+ return StopInfo::CreateStopReasonWithPlan(
+ completed_plan_sp, GetReturnValueObject(), GetExpressionVariable());
} else {
- if ((m_stop_info_stop_id == stop_id) || // Stop info is valid, just return
- // what we have (even if empty)
- (m_stop_info_sp &&
- m_stop_info_sp
- ->IsValid())) // Stop info is valid, just return what we have
- {
- return m_stop_info_sp;
- } else {
- GetPrivateStopInfo();
- return m_stop_info_sp;
- }
+ GetPrivateStopInfo();
+ return m_stop_info_sp;
}
}
@@ -459,6 +468,12 @@ bool Thread::StopInfoIsUpToDate() const {
// date...
}
+void Thread::ResetStopInfo() {
+ if (m_stop_info_sp) {
+ m_stop_info_sp.reset();
+ }
+}
+
void Thread::SetStopInfo(const lldb::StopInfoSP &stop_info_sp) {
m_stop_info_sp = stop_info_sp;
if (m_stop_info_sp) {
@@ -526,6 +541,7 @@ bool Thread::CheckpointThreadState(ThreadStateCheckpoint &saved_state) {
if (process_sp)
saved_state.orig_stop_id = process_sp->GetStopID();
saved_state.current_inlined_depth = GetCurrentInlinedDepth();
+ saved_state.m_completed_plan_stack = m_completed_plan_stack;
return true;
}
@@ -559,6 +575,7 @@ bool Thread::RestoreThreadStateFromCheckpoint(
SetStopInfo(saved_state.stop_info_sp);
GetStackFrameList()->SetCurrentInlinedDepth(
saved_state.current_inlined_depth);
+ m_completed_plan_stack = saved_state.m_completed_plan_stack;
return true;
}
@@ -895,6 +912,9 @@ bool Thread::ShouldStop(Event *event_ptr) {
if (should_stop) {
ThreadPlan *plan_ptr = GetCurrentPlan();
+
+ // Discard the stale plans and all plans below them in the stack,
+ // plus move the completed plans to the completed plan stack
while (!PlanIsBasePlan(plan_ptr)) {
bool stale = plan_ptr->IsPlanStale();
ThreadPlan *examined_plan = plan_ptr;
@@ -905,7 +925,15 @@ bool Thread::ShouldStop(Event *event_ptr) {
log->Printf(
"Plan %s being discarded in cleanup, it says it is already done.",
examined_plan->GetName());
- DiscardThreadPlansUpToPlan(examined_plan);
+ while (GetCurrentPlan() != examined_plan) {
+ DiscardPlan();
+ }
+ if (examined_plan->IsPlanComplete()) {
+ // plan is complete but does not explain the stop (example: step to a line
+ // with breakpoint), let us move the plan to completed_plan_stack anyway
+ PopPlan();
+ } else
+ DiscardPlan();
}
}
}
@@ -1133,6 +1161,10 @@ bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) {
return false;
}
+bool Thread::CompletedPlanOverridesBreakpoint() {
+ return (!m_completed_plan_stack.empty()) ;
+}
+
ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) {
if (current_plan == nullptr)
return nullptr;
@@ -1304,8 +1336,8 @@ bool Thread::PlanIsBasePlan(ThreadPlan *plan_ptr) {
return m_plan_stack[0].get() == plan_ptr;
}
-Error Thread::UnwindInnermostExpression() {
- Error error;
+Status Thread::UnwindInnermostExpression() {
+ Status error;
int stack_size = m_plan_stack.size();
// If the input plan is nullptr, discard all plans. Otherwise make sure this
@@ -1604,11 +1636,11 @@ lldb::StackFrameSP Thread::GetFrameWithConcreteFrameIndex(uint32_t unwind_idx) {
return GetStackFrameList()->GetFrameWithConcreteFrameIndex(unwind_idx);
}
-Error Thread::ReturnFromFrameWithIndex(uint32_t frame_idx,
- lldb::ValueObjectSP return_value_sp,
- bool broadcast) {
+Status Thread::ReturnFromFrameWithIndex(uint32_t frame_idx,
+ lldb::ValueObjectSP return_value_sp,
+ bool broadcast) {
StackFrameSP frame_sp = GetStackFrameAtIndex(frame_idx);
- Error return_error;
+ Status return_error;
if (!frame_sp) {
return_error.SetErrorStringWithFormat(
@@ -1619,10 +1651,10 @@ Error Thread::ReturnFromFrameWithIndex(uint32_t frame_idx,
return ReturnFromFrame(frame_sp, return_value_sp, broadcast);
}
-Error Thread::ReturnFromFrame(lldb::StackFrameSP frame_sp,
- lldb::ValueObjectSP return_value_sp,
- bool broadcast) {
- Error return_error;
+Status Thread::ReturnFromFrame(lldb::StackFrameSP frame_sp,
+ lldb::ValueObjectSP return_value_sp,
+ bool broadcast) {
+ Status return_error;
if (!frame_sp) {
return_error.SetErrorString("Can't return to a null frame.");
@@ -1709,8 +1741,8 @@ static void DumpAddressList(Stream &s, const std::vector<Address> &list,
}
}
-Error Thread::JumpToLine(const FileSpec &file, uint32_t line,
- bool can_leave_function, std::string *warnings) {
+Status Thread::JumpToLine(const FileSpec &file, uint32_t line,
+ bool can_leave_function, std::string *warnings) {
ExecutionContext exe_ctx(GetStackFrameAtIndex(0));
Target *target = exe_ctx.GetTargetPtr();
TargetSP target_sp = exe_ctx.GetTargetSP();
@@ -1738,16 +1770,16 @@ Error Thread::JumpToLine(const FileSpec &file, uint32_t line,
// Check if we got anything.
if (candidates.empty()) {
if (outside_function.empty()) {
- return Error("Cannot locate an address for %s:%i.",
- file.GetFilename().AsCString(), line);
+ return Status("Cannot locate an address for %s:%i.",
+ file.GetFilename().AsCString(), line);
} else if (outside_function.size() == 1) {
- return Error("%s:%i is outside the current function.",
- file.GetFilename().AsCString(), line);
+ return Status("%s:%i is outside the current function.",
+ file.GetFilename().AsCString(), line);
} else {
StreamString sstr;
DumpAddressList(sstr, outside_function, target);
- return Error("%s:%i has multiple candidate locations:\n%s",
- file.GetFilename().AsCString(), line, sstr.GetData());
+ return Status("%s:%i has multiple candidate locations:\n%s",
+ file.GetFilename().AsCString(), line, sstr.GetData());
}
}
@@ -1763,9 +1795,9 @@ Error Thread::JumpToLine(const FileSpec &file, uint32_t line,
}
if (!reg_ctx->SetPC(dest))
- return Error("Cannot change PC to target address.");
+ return Status("Cannot change PC to target address.");
- return Error();
+ return Status();
}
void Thread::DumpUsingSettingsFormat(Stream &strm, uint32_t frame_idx,
@@ -1881,39 +1913,42 @@ const char *Thread::RunModeAsCString(lldb::RunMode mode) {
size_t Thread::GetStatus(Stream &strm, uint32_t start_frame,
uint32_t num_frames, uint32_t num_frames_with_source,
- bool stop_format) {
- ExecutionContext exe_ctx(shared_from_this());
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- size_t num_frames_shown = 0;
- strm.Indent();
- bool is_selected = false;
- if (process) {
- if (process->GetThreadList().GetSelectedThread().get() == this)
- is_selected = true;
- }
- strm.Printf("%c ", is_selected ? '*' : ' ');
- if (target && target->GetDebugger().GetUseExternalEditor()) {
- StackFrameSP frame_sp = GetStackFrameAtIndex(start_frame);
- if (frame_sp) {
- SymbolContext frame_sc(
- frame_sp->GetSymbolContext(eSymbolContextLineEntry));
- if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file) {
- Host::OpenFileInExternalEditor(frame_sc.line_entry.file,
- frame_sc.line_entry.line);
+ bool stop_format, bool only_stacks) {
+
+ if (!only_stacks) {
+ ExecutionContext exe_ctx(shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ strm.Indent();
+ bool is_selected = false;
+ if (process) {
+ if (process->GetThreadList().GetSelectedThread().get() == this)
+ is_selected = true;
+ }
+ strm.Printf("%c ", is_selected ? '*' : ' ');
+ if (target && target->GetDebugger().GetUseExternalEditor()) {
+ StackFrameSP frame_sp = GetStackFrameAtIndex(start_frame);
+ if (frame_sp) {
+ SymbolContext frame_sc(
+ frame_sp->GetSymbolContext(eSymbolContextLineEntry));
+ if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file) {
+ Host::OpenFileInExternalEditor(frame_sc.line_entry.file,
+ frame_sc.line_entry.line);
+ }
}
}
- }
- DumpUsingSettingsFormat(strm, start_frame, stop_format);
+ DumpUsingSettingsFormat(strm, start_frame, stop_format);
+ }
+ size_t num_frames_shown = 0;
if (num_frames > 0) {
strm.IndentMore();
const bool show_frame_info = true;
-
+ const bool show_frame_unique = only_stacks;
const char *selected_frame_marker = nullptr;
- if (num_frames == 1 ||
+ if (num_frames == 1 || only_stacks ||
(GetID() != GetProcess()->GetThreadList().GetSelectedThread()->GetID()))
strm.IndentMore();
else
@@ -1921,7 +1956,7 @@ size_t Thread::GetStatus(Stream &strm, uint32_t start_frame,
num_frames_shown = GetStackFrameList()->GetStatus(
strm, start_frame, num_frames, show_frame_info, num_frames_with_source,
- selected_frame_marker);
+ show_frame_unique, selected_frame_marker);
if (num_frames == 1)
strm.IndentLess();
strm.IndentLess();
@@ -1963,22 +1998,20 @@ bool Thread::GetDescription(Stream &strm, lldb::DescriptionLevel level,
thread_info->GetObjectForDotSeparatedPath("trace_messages");
bool printed_activity = false;
- if (activity &&
- activity->GetType() == StructuredData::Type::eTypeDictionary) {
+ if (activity && activity->GetType() == eStructuredDataTypeDictionary) {
StructuredData::Dictionary *activity_dict = activity->GetAsDictionary();
StructuredData::ObjectSP id = activity_dict->GetValueForKey("id");
StructuredData::ObjectSP name = activity_dict->GetValueForKey("name");
- if (name && name->GetType() == StructuredData::Type::eTypeString && id &&
- id->GetType() == StructuredData::Type::eTypeInteger) {
- strm.Printf(" Activity '%s', 0x%" PRIx64 "\n",
- name->GetAsString()->GetValue().c_str(),
+ if (name && name->GetType() == eStructuredDataTypeString && id &&
+ id->GetType() == eStructuredDataTypeInteger) {
+ strm.Format(" Activity '{0}', {1:x}\n",
+ name->GetAsString()->GetValue(),
id->GetAsInteger()->GetValue());
}
printed_activity = true;
}
bool printed_breadcrumb = false;
- if (breadcrumb &&
- breadcrumb->GetType() == StructuredData::Type::eTypeDictionary) {
+ if (breadcrumb && breadcrumb->GetType() == eStructuredDataTypeDictionary) {
if (printed_activity)
strm.Printf("\n");
StructuredData::Dictionary *breadcrumb_dict =
@@ -1986,13 +2019,13 @@ bool Thread::GetDescription(Stream &strm, lldb::DescriptionLevel level,
StructuredData::ObjectSP breadcrumb_text =
breadcrumb_dict->GetValueForKey("name");
if (breadcrumb_text &&
- breadcrumb_text->GetType() == StructuredData::Type::eTypeString) {
- strm.Printf(" Current Breadcrumb: %s\n",
- breadcrumb_text->GetAsString()->GetValue().c_str());
+ breadcrumb_text->GetType() == eStructuredDataTypeString) {
+ strm.Format(" Current Breadcrumb: {0}\n",
+ breadcrumb_text->GetAsString()->GetValue());
}
printed_breadcrumb = true;
}
- if (messages && messages->GetType() == StructuredData::Type::eTypeArray) {
+ if (messages && messages->GetType() == eStructuredDataTypeArray) {
if (printed_breadcrumb)
strm.Printf("\n");
StructuredData::Array *messages_array = messages->GetAsArray();
@@ -2001,16 +2034,14 @@ bool Thread::GetDescription(Stream &strm, lldb::DescriptionLevel level,
strm.Printf(" %zu trace messages:\n", msg_count);
for (size_t i = 0; i < msg_count; i++) {
StructuredData::ObjectSP message = messages_array->GetItemAtIndex(i);
- if (message &&
- message->GetType() == StructuredData::Type::eTypeDictionary) {
+ if (message && message->GetType() == eStructuredDataTypeDictionary) {
StructuredData::Dictionary *message_dict =
message->GetAsDictionary();
StructuredData::ObjectSP message_text =
message_dict->GetValueForKey("message");
if (message_text &&
- message_text->GetType() == StructuredData::Type::eTypeString) {
- strm.Printf(" %s\n",
- message_text->GetAsString()->GetValue().c_str());
+ message_text->GetType() == eStructuredDataTypeString) {
+ strm.Format(" {0}\n", message_text->GetAsString()->GetValue());
}
}
}
@@ -2086,12 +2117,12 @@ bool Thread::IsStillAtLastBreakpointHit() {
return false;
}
-Error Thread::StepIn(bool source_step,
- LazyBool step_in_avoids_code_without_debug_info,
- LazyBool step_out_avoids_code_without_debug_info)
+Status Thread::StepIn(bool source_step,
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info)
{
- Error error;
+ Status error;
Process *process = GetProcess().get();
if (StateIsStoppedState(process->GetState(), true)) {
StackFrameSP frame_sp = GetStackFrameAtIndex(0);
@@ -2122,9 +2153,9 @@ Error Thread::StepIn(bool source_step,
return error;
}
-Error Thread::StepOver(bool source_step,
- LazyBool step_out_avoids_code_without_debug_info) {
- Error error;
+Status Thread::StepOver(bool source_step,
+ LazyBool step_out_avoids_code_without_debug_info) {
+ Status error;
Process *process = GetProcess().get();
if (StateIsStoppedState(process->GetState(), true)) {
StackFrameSP frame_sp = GetStackFrameAtIndex(0);
@@ -2155,8 +2186,8 @@ Error Thread::StepOver(bool source_step,
return error;
}
-Error Thread::StepOut() {
- Error error;
+Status Thread::StepOut() {
+ Status error;
Process *process = GetProcess().get();
if (StateIsStoppedState(process->GetState(), true)) {
const bool first_instruction = false;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadList.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadList.cpp
index 1e47451..4cf8f90 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadList.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadList.cpp
@@ -15,15 +15,14 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadList.h"
#include "lldb/Target/ThreadPlan.h"
-#include "lldb/Utility/ConvertEnum.h"
#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -384,18 +383,14 @@ Vote ThreadList::ShouldReportStop(Event *event_ptr) {
if (result == eVoteNoOpinion) {
result = eVoteNo;
} else {
- if (log)
- log->Printf("ThreadList::%s thread 0x%4.4" PRIx64
- ": voted %s, but lost out because result was %s",
- __FUNCTION__, thread_sp->GetID(), GetVoteAsCString(vote),
- GetVoteAsCString(result));
+ LLDB_LOG(log,
+ "Thread {0:x} voted {1}, but lost out because result was {2}",
+ thread_sp->GetID(), vote, result);
}
break;
}
}
- if (log)
- log->Printf("ThreadList::%s returning %s", __FUNCTION__,
- GetVoteAsCString(result));
+ LLDB_LOG(log, "Returning {0}", result);
return result;
}
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlan.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlan.cpp
index 6b99747..27c9e2a 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlan.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlan.cpp
@@ -13,13 +13,12 @@
// Project includes
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
-#include "lldb/Utility/ConvertEnum.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -77,16 +76,11 @@ Vote ThreadPlan::ShouldReportStop(Event *event_ptr) {
ThreadPlan *prev_plan = GetPreviousPlan();
if (prev_plan) {
Vote prev_vote = prev_plan->ShouldReportStop(event_ptr);
- if (log)
- log->Printf("ThreadPlan::ShouldReportStop() returning previous thread "
- "plan vote: %s",
- GetVoteAsCString(prev_vote));
+ LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote);
return prev_vote;
}
}
- if (log)
- log->Printf("ThreadPlan::ShouldReportStop() returning vote: %s",
- GetVoteAsCString(m_stop_vote));
+ LLDB_LOG(log, "Returning vote: {0}", m_stop_vote);
return m_stop_vote;
}
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanBase.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanBase.cpp
index f290483..d1c2f6d 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanBase.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanBase.cpp
@@ -18,11 +18,11 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/BreakpointSite.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunction.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunction.cpp
index 68fd503..e3b9ae1 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -15,9 +15,7 @@
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/LanguageRuntime.h"
@@ -27,6 +25,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -58,7 +58,7 @@ bool ThreadPlanCallFunction::ConstructorSetup(
// If we can't read memory at the point of the process where we are planning
// to put our function, we're
// not going to get any further...
- Error error;
+ Status error;
process_sp->ReadUnsignedIntegerFromMemory(m_function_sp, 4, 0, error);
if (!error.Success()) {
m_constructor_errors.Printf(
@@ -174,9 +174,8 @@ ThreadPlanCallFunction::~ThreadPlanCallFunction() {
}
void ThreadPlanCallFunction::ReportRegisterState(const char *message) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP |
- LIBLLDB_LOG_VERBOSE));
- if (log) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose()) {
StreamString strm;
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp
index 6c59695..b90fd9e 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp
@@ -13,12 +13,12 @@
// Project includes
#include "lldb/Target/ThreadPlanCallFunctionUsingABI.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallUserExpression.cpp
index 260118c..15cbd0b 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallUserExpression.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanCallUserExpression.cpp
@@ -17,8 +17,6 @@
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Address.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/UserExpression.h"
@@ -30,6 +28,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -60,6 +60,12 @@ void ThreadPlanCallUserExpression::GetDescription(
ThreadPlanCallFunction::GetDescription(s, level);
}
+void ThreadPlanCallUserExpression::DidPush() {
+ ThreadPlanCallFunction::DidPush();
+ if (m_user_expression_sp)
+ m_user_expression_sp->WillStartExecuting();
+}
+
void ThreadPlanCallUserExpression::WillPop() {
ThreadPlanCallFunction::WillPop();
if (m_user_expression_sp)
@@ -113,3 +119,8 @@ StopInfoSP ThreadPlanCallUserExpression::GetRealStopInfo() {
return stop_info_sp;
}
+
+void ThreadPlanCallUserExpression::DoTakedown(bool success) {
+ ThreadPlanCallFunction::DoTakedown(success);
+ m_user_expression_sp->DidFinishExecuting();
+}
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanPython.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanPython.cpp
index 180586a..af5c765 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanPython.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanPython.cpp
@@ -14,7 +14,6 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
@@ -24,6 +23,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanPython.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanRunToAddress.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanRunToAddress.cpp
index 6f31db0..44de724 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanRunToAddress.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanRunToAddress.cpp
@@ -12,12 +12,12 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Target/ThreadPlanRunToAddress.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanShouldStopHere.cpp
index 408650d..42aaa42 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanShouldStopHere.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanShouldStopHere.cpp
@@ -11,11 +11,11 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Target/Thread.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Target/ThreadPlanShouldStopHere.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/RegisterContext.h"
-#include "lldb/Target/ThreadPlanShouldStopHere.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInRange.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInRange.cpp
index 03f6679..caaaffe 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInRange.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInRange.cpp
@@ -12,10 +12,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Target/ThreadPlanStepInRange.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/Process.h"
@@ -24,6 +21,9 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Target/ThreadPlanStepThrough.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInstruction.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInstruction.cpp
index 6ad6a23..ca45960 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInstruction.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInstruction.cpp
@@ -12,13 +12,13 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Target/ThreadPlanStepInstruction.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -94,6 +94,15 @@ bool ThreadPlanStepInstruction::IsPlanStale() {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
if (cur_frame_id == m_stack_id) {
+ // Set plan Complete when we reach next instruction
+ uint64_t pc = m_thread.GetRegisterContext()->GetPC(0);
+ uint32_t max_opcode_size = m_thread.CalculateTarget()
+ ->GetArchitecture().GetMaximumOpcodeByteSize();
+ bool next_instruction_reached = (pc > m_instruction_addr) &&
+ (pc <= m_instruction_addr + max_opcode_size);
+ if (next_instruction_reached) {
+ SetPlanComplete();
+ }
return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr);
} else if (cur_frame_id < m_stack_id) {
// If the current frame is younger than the start frame and we are stepping
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOut.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOut.cpp
index b8d6e6d..6b6ed06 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOut.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOut.cpp
@@ -13,7 +13,6 @@
// Project includes
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Breakpoint/Breakpoint.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Symbol/Block.h"
@@ -27,6 +26,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanStepOverRange.h"
#include "lldb/Target/ThreadPlanStepThrough.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
index 39641a0..3896a0b 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp
@@ -13,10 +13,10 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverRange.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverRange.cpp
index 48c7ff8..d5778fb 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverRange.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepOverRange.cpp
@@ -12,8 +12,6 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Target/ThreadPlanStepOverRange.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
@@ -24,6 +22,8 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Target/ThreadPlanStepThrough.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb_private;
using namespace lldb;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepRange.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepRange.cpp
index dcee82e..09e606f 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepRange.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -15,8 +15,6 @@
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/BreakpointSite.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ExecutionContext.h"
@@ -26,6 +24,8 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
@@ -461,6 +461,16 @@ bool ThreadPlanStepRange::IsPlanStale() {
// One tricky bit here is that some stubs don't push a frame, so we should.
// check that we are in the same symbol.
if (!InRange()) {
+ // Set plan Complete when we reach next instruction just after the range
+ lldb::addr_t addr = m_thread.GetRegisterContext()->GetPC() - 1;
+ size_t num_ranges = m_address_ranges.size();
+ for (size_t i = 0; i < num_ranges; i++) {
+ bool in_range = m_address_ranges[i].ContainsLoadAddress(
+ addr, m_thread.CalculateTarget().get());
+ if (in_range) {
+ SetPlanComplete();
+ }
+ }
return true;
}
}
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepThrough.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepThrough.cpp
index b975161..46aadb0 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepThrough.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepThrough.cpp
@@ -13,13 +13,13 @@
// Project includes
#include "lldb/Target/ThreadPlanStepThrough.h"
#include "lldb/Breakpoint/Breakpoint.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepUntil.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepUntil.cpp
index a10e2f4..01f5f94 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepUntil.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepUntil.cpp
@@ -12,12 +12,14 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Target/ThreadPlanStepUntil.h"
+
#include "lldb/Breakpoint/Breakpoint.h"
-#include "lldb/Core/Log.h"
+#include "lldb/Symbol/SymbolContextScope.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanTracer.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanTracer.cpp
index 7fbd664..014c7fd 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanTracer.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanTracer.cpp
@@ -14,11 +14,8 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
@@ -32,6 +29,9 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
@@ -145,7 +145,7 @@ void ThreadPlanAssemblyTracer::Log() {
Disassembler *disassembler = GetDisassembler();
if (disassembler) {
- Error err;
+ Status err;
process_sp->ReadMemory(pc, buffer, sizeof(buffer), err);
if (err.Success()) {
diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadSpec.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadSpec.cpp
index c7eec07..444a5a5 100644
--- a/contrib/llvm/tools/lldb/source/Target/ThreadSpec.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/ThreadSpec.cpp
@@ -11,9 +11,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Target/Thread.h"
-#include "lldb/Core/StructuredData.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
@@ -39,11 +39,11 @@ const ThreadSpec &ThreadSpec::operator=(const ThreadSpec &rhs) {
}
std::unique_ptr<ThreadSpec> ThreadSpec::CreateFromStructuredData(
- const StructuredData::Dictionary &spec_dict, Error &error) {
+ const StructuredData::Dictionary &spec_dict, Status &error) {
uint32_t index = UINT32_MAX;
lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
- std::string name;
- std::string queue_name;
+ llvm::StringRef name;
+ llvm::StringRef queue_name;
std::unique_ptr<ThreadSpec> thread_spec_up(new ThreadSpec());
bool success = spec_dict.GetValueForKeyAsInteger(
@@ -59,12 +59,12 @@ std::unique_ptr<ThreadSpec> ThreadSpec::CreateFromStructuredData(
success =
spec_dict.GetValueForKeyAsString(GetKey(OptionNames::ThreadName), name);
if (success)
- thread_spec_up->SetName(name.c_str());
+ thread_spec_up->SetName(name);
success = spec_dict.GetValueForKeyAsString(GetKey(OptionNames::ThreadName),
queue_name);
if (success)
- thread_spec_up->SetQueueName(queue_name.c_str());
+ thread_spec_up->SetQueueName(queue_name);
return thread_spec_up;
}
diff --git a/contrib/llvm/tools/lldb/source/Target/UnixSignals.cpp b/contrib/llvm/tools/lldb/source/Target/UnixSignals.cpp
index cee69bf..a4ec32b 100644
--- a/contrib/llvm/tools/lldb/source/Target/UnixSignals.cpp
+++ b/contrib/llvm/tools/lldb/source/Target/UnixSignals.cpp
@@ -123,12 +123,14 @@ void UnixSignals::AddSignal(int signo, const char *name, bool default_suppress,
Signal new_signal(name, default_suppress, default_stop, default_notify,
description, alias);
m_signals.insert(std::make_pair(signo, new_signal));
+ ++m_version;
}
void UnixSignals::RemoveSignal(int signo) {
collection::iterator pos = m_signals.find(signo);
if (pos != m_signals.end())
m_signals.erase(pos);
+ ++m_version;
}
const char *UnixSignals::GetSignalAsCString(int signo) const {
@@ -217,6 +219,7 @@ bool UnixSignals::SetShouldSuppress(int signo, bool value) {
collection::iterator pos = m_signals.find(signo);
if (pos != m_signals.end()) {
pos->second.m_suppress = value;
+ ++m_version;
return true;
}
return false;
@@ -240,6 +243,7 @@ bool UnixSignals::SetShouldStop(int signo, bool value) {
collection::iterator pos = m_signals.find(signo);
if (pos != m_signals.end()) {
pos->second.m_stop = value;
+ ++m_version;
return true;
}
return false;
@@ -263,6 +267,7 @@ bool UnixSignals::SetShouldNotify(int signo, bool value) {
collection::iterator pos = m_signals.find(signo);
if (pos != m_signals.end()) {
pos->second.m_notify = value;
+ ++m_version;
return true;
}
return false;
@@ -284,3 +289,37 @@ int32_t UnixSignals::GetSignalAtIndex(int32_t index) const {
std::advance(it, index);
return it->first;
}
+
+uint64_t UnixSignals::GetVersion() const { return m_version; }
+
+std::vector<int32_t>
+UnixSignals::GetFilteredSignals(llvm::Optional<bool> should_suppress,
+ llvm::Optional<bool> should_stop,
+ llvm::Optional<bool> should_notify) {
+ std::vector<int32_t> result;
+ for (int32_t signo = GetFirstSignalNumber();
+ signo != LLDB_INVALID_SIGNAL_NUMBER;
+ signo = GetNextSignalNumber(signo)) {
+
+ bool signal_suppress = false;
+ bool signal_stop = false;
+ bool signal_notify = false;
+ GetSignalInfo(signo, signal_suppress, signal_stop, signal_notify);
+
+ // If any of filtering conditions are not met,
+ // we move on to the next signal.
+ if (should_suppress.hasValue() &&
+ signal_suppress != should_suppress.getValue())
+ continue;
+
+ if (should_stop.hasValue() && signal_stop != should_stop.getValue())
+ continue;
+
+ if (should_notify.hasValue() && signal_notify != should_notify.getValue())
+ continue;
+
+ result.push_back(signo);
+ }
+
+ return result;
+}
diff --git a/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.cpp b/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.cpp
deleted file mode 100644
index 8c2a716..0000000
--- a/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-//===-- ARM64_DWARF_Registers.cpp -------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include <string.h>
-
-#include "ARM64_DWARF_Registers.h"
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace arm64_dwarf;
-
-const char *arm64_dwarf::GetRegisterName(unsigned reg_num,
- bool altnernate_name) {
- if (altnernate_name) {
- switch (reg_num) {
- case fp:
- return "x29";
- case lr:
- return "x30";
- case sp:
- return "x31";
- default:
- break;
- }
- return nullptr;
- }
-
- switch (reg_num) {
- case x0:
- return "x0";
- case x1:
- return "x1";
- case x2:
- return "x2";
- case x3:
- return "x3";
- case x4:
- return "x4";
- case x5:
- return "x5";
- case x6:
- return "x6";
- case x7:
- return "x7";
- case x8:
- return "x8";
- case x9:
- return "x9";
- case x10:
- return "x10";
- case x11:
- return "x11";
- case x12:
- return "x12";
- case x13:
- return "x13";
- case x14:
- return "x14";
- case x15:
- return "x15";
- case x16:
- return "x16";
- case x17:
- return "x17";
- case x18:
- return "x18";
- case x19:
- return "x19";
- case x20:
- return "x20";
- case x21:
- return "x21";
- case x22:
- return "x22";
- case x23:
- return "x23";
- case x24:
- return "x24";
- case x25:
- return "x25";
- case x26:
- return "x26";
- case x27:
- return "x27";
- case x28:
- return "x28";
- case fp:
- return "fp";
- case lr:
- return "lr";
- case sp:
- return "sp";
- case pc:
- return "pc";
- case cpsr:
- return "cpsr";
- case v0:
- return "v0";
- case v1:
- return "v1";
- case v2:
- return "v2";
- case v3:
- return "v3";
- case v4:
- return "v4";
- case v5:
- return "v5";
- case v6:
- return "v6";
- case v7:
- return "v7";
- case v8:
- return "v8";
- case v9:
- return "v9";
- case v10:
- return "v10";
- case v11:
- return "v11";
- case v12:
- return "v12";
- case v13:
- return "v13";
- case v14:
- return "v14";
- case v15:
- return "v15";
- case v16:
- return "v16";
- case v17:
- return "v17";
- case v18:
- return "v18";
- case v19:
- return "v19";
- case v20:
- return "v20";
- case v21:
- return "v21";
- case v22:
- return "v22";
- case v23:
- return "v23";
- case v24:
- return "v24";
- case v25:
- return "v25";
- case v26:
- return "v26";
- case v27:
- return "v27";
- case v28:
- return "v28";
- case v29:
- return "v29";
- case v30:
- return "v30";
- case v31:
- return "v31";
- }
- return nullptr;
-}
-
-bool arm64_dwarf::GetRegisterInfo(unsigned reg_num, RegisterInfo &reg_info) {
- ::memset(&reg_info, 0, sizeof(RegisterInfo));
- ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
-
- if (reg_num >= x0 && reg_num <= pc) {
- reg_info.byte_size = 8;
- reg_info.format = eFormatHex;
- reg_info.encoding = eEncodingUint;
- } else if (reg_num >= v0 && reg_num <= v31) {
- reg_info.byte_size = 16;
- reg_info.format = eFormatVectorOfFloat32;
- reg_info.encoding = eEncodingVector;
- } else if (reg_num == cpsr) {
- reg_info.byte_size = 4;
- reg_info.format = eFormatHex;
- reg_info.encoding = eEncodingUint;
- } else {
- return false;
- }
-
- reg_info.name = arm64_dwarf::GetRegisterName(reg_num, false);
- reg_info.alt_name = arm64_dwarf::GetRegisterName(reg_num, true);
- reg_info.kinds[eRegisterKindDWARF] = reg_num;
-
- switch (reg_num) {
- case fp:
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- break;
- case lr:
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
- break;
- case sp:
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
- break;
- case pc:
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
- break;
- default:
- break;
- }
- return true;
-}
diff --git a/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.h b/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.h
index be0ea2a..ce548a2 100644
--- a/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.h
+++ b/contrib/llvm/tools/lldb/source/Utility/ARM64_DWARF_Registers.h
@@ -91,10 +91,6 @@ enum {
// 96-127 reserved
};
-const char *GetRegisterName(unsigned reg_num, bool altnernate_name);
-
-bool GetRegisterInfo(unsigned reg_num, lldb_private::RegisterInfo &reg_info);
-
} // namespace arm64_dwarf
#endif // utility_ARM64_DWARF_Registers_h_
diff --git a/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.cpp b/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.cpp
deleted file mode 100644
index c136376..0000000
--- a/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.cpp
+++ /dev/null
@@ -1,925 +0,0 @@
-//===-- ARM_DWARF_Registers.cpp ---------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ARM_DWARF_Registers.h"
-#include <string.h>
-
-#include <string.h>
-
-using namespace lldb;
-using namespace lldb_private;
-
-const char *GetARMDWARFRegisterName(unsigned reg_num) {
- switch (reg_num) {
- case dwarf_r0:
- return "r0";
- case dwarf_r1:
- return "r1";
- case dwarf_r2:
- return "r2";
- case dwarf_r3:
- return "r3";
- case dwarf_r4:
- return "r4";
- case dwarf_r5:
- return "r5";
- case dwarf_r6:
- return "r6";
- case dwarf_r7:
- return "r7";
- case dwarf_r8:
- return "r8";
- case dwarf_r9:
- return "r9";
- case dwarf_r10:
- return "r10";
- case dwarf_r11:
- return "r11";
- case dwarf_r12:
- return "r12";
- case dwarf_sp:
- return "sp";
- case dwarf_lr:
- return "lr";
- case dwarf_pc:
- return "pc";
- case dwarf_cpsr:
- return "cpsr";
-
- case dwarf_s0:
- return "s0";
- case dwarf_s1:
- return "s1";
- case dwarf_s2:
- return "s2";
- case dwarf_s3:
- return "s3";
- case dwarf_s4:
- return "s4";
- case dwarf_s5:
- return "s5";
- case dwarf_s6:
- return "s6";
- case dwarf_s7:
- return "s7";
- case dwarf_s8:
- return "s8";
- case dwarf_s9:
- return "s9";
- case dwarf_s10:
- return "s10";
- case dwarf_s11:
- return "s11";
- case dwarf_s12:
- return "s12";
- case dwarf_s13:
- return "s13";
- case dwarf_s14:
- return "s14";
- case dwarf_s15:
- return "s15";
- case dwarf_s16:
- return "s16";
- case dwarf_s17:
- return "s17";
- case dwarf_s18:
- return "s18";
- case dwarf_s19:
- return "s19";
- case dwarf_s20:
- return "s20";
- case dwarf_s21:
- return "s21";
- case dwarf_s22:
- return "s22";
- case dwarf_s23:
- return "s23";
- case dwarf_s24:
- return "s24";
- case dwarf_s25:
- return "s25";
- case dwarf_s26:
- return "s26";
- case dwarf_s27:
- return "s27";
- case dwarf_s28:
- return "s28";
- case dwarf_s29:
- return "s29";
- case dwarf_s30:
- return "s30";
- case dwarf_s31:
- return "s31";
-
- // FPA Registers 0-7
- case dwarf_f0:
- return "f0";
- case dwarf_f1:
- return "f1";
- case dwarf_f2:
- return "f2";
- case dwarf_f3:
- return "f3";
- case dwarf_f4:
- return "f4";
- case dwarf_f5:
- return "f5";
- case dwarf_f6:
- return "f6";
- case dwarf_f7:
- return "f7";
-
- // Intel wireless MMX general purpose registers 0 - 7
- // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7)
- case dwarf_wCGR0:
- return "wCGR0/ACC0";
- case dwarf_wCGR1:
- return "wCGR1/ACC1";
- case dwarf_wCGR2:
- return "wCGR2/ACC2";
- case dwarf_wCGR3:
- return "wCGR3/ACC3";
- case dwarf_wCGR4:
- return "wCGR4/ACC4";
- case dwarf_wCGR5:
- return "wCGR5/ACC5";
- case dwarf_wCGR6:
- return "wCGR6/ACC6";
- case dwarf_wCGR7:
- return "wCGR7/ACC7";
-
- // Intel wireless MMX data registers 0 - 15
- case dwarf_wR0:
- return "wR0";
- case dwarf_wR1:
- return "wR1";
- case dwarf_wR2:
- return "wR2";
- case dwarf_wR3:
- return "wR3";
- case dwarf_wR4:
- return "wR4";
- case dwarf_wR5:
- return "wR5";
- case dwarf_wR6:
- return "wR6";
- case dwarf_wR7:
- return "wR7";
- case dwarf_wR8:
- return "wR8";
- case dwarf_wR9:
- return "wR9";
- case dwarf_wR10:
- return "wR10";
- case dwarf_wR11:
- return "wR11";
- case dwarf_wR12:
- return "wR12";
- case dwarf_wR13:
- return "wR13";
- case dwarf_wR14:
- return "wR14";
- case dwarf_wR15:
- return "wR15";
-
- case dwarf_spsr:
- return "spsr";
- case dwarf_spsr_fiq:
- return "spsr_fiq";
- case dwarf_spsr_irq:
- return "spsr_irq";
- case dwarf_spsr_abt:
- return "spsr_abt";
- case dwarf_spsr_und:
- return "spsr_und";
- case dwarf_spsr_svc:
- return "spsr_svc";
-
- case dwarf_r8_usr:
- return "r8_usr";
- case dwarf_r9_usr:
- return "r9_usr";
- case dwarf_r10_usr:
- return "r10_usr";
- case dwarf_r11_usr:
- return "r11_usr";
- case dwarf_r12_usr:
- return "r12_usr";
- case dwarf_r13_usr:
- return "r13_usr";
- case dwarf_r14_usr:
- return "r14_usr";
- case dwarf_r8_fiq:
- return "r8_fiq";
- case dwarf_r9_fiq:
- return "r9_fiq";
- case dwarf_r10_fiq:
- return "r10_fiq";
- case dwarf_r11_fiq:
- return "r11_fiq";
- case dwarf_r12_fiq:
- return "r12_fiq";
- case dwarf_r13_fiq:
- return "r13_fiq";
- case dwarf_r14_fiq:
- return "r14_fiq";
- case dwarf_r13_irq:
- return "r13_irq";
- case dwarf_r14_irq:
- return "r14_irq";
- case dwarf_r13_abt:
- return "r13_abt";
- case dwarf_r14_abt:
- return "r14_abt";
- case dwarf_r13_und:
- return "r13_und";
- case dwarf_r14_und:
- return "r14_und";
- case dwarf_r13_svc:
- return "r13_svc";
- case dwarf_r14_svc:
- return "r14_svc";
-
- // Intel wireless MMX control register in co-processor 0 - 7
- case dwarf_wC0:
- return "wC0";
- case dwarf_wC1:
- return "wC1";
- case dwarf_wC2:
- return "wC2";
- case dwarf_wC3:
- return "wC3";
- case dwarf_wC4:
- return "wC4";
- case dwarf_wC5:
- return "wC5";
- case dwarf_wC6:
- return "wC6";
- case dwarf_wC7:
- return "wC7";
-
- // VFP-v3/Neon
- case dwarf_d0:
- return "d0";
- case dwarf_d1:
- return "d1";
- case dwarf_d2:
- return "d2";
- case dwarf_d3:
- return "d3";
- case dwarf_d4:
- return "d4";
- case dwarf_d5:
- return "d5";
- case dwarf_d6:
- return "d6";
- case dwarf_d7:
- return "d7";
- case dwarf_d8:
- return "d8";
- case dwarf_d9:
- return "d9";
- case dwarf_d10:
- return "d10";
- case dwarf_d11:
- return "d11";
- case dwarf_d12:
- return "d12";
- case dwarf_d13:
- return "d13";
- case dwarf_d14:
- return "d14";
- case dwarf_d15:
- return "d15";
- case dwarf_d16:
- return "d16";
- case dwarf_d17:
- return "d17";
- case dwarf_d18:
- return "d18";
- case dwarf_d19:
- return "d19";
- case dwarf_d20:
- return "d20";
- case dwarf_d21:
- return "d21";
- case dwarf_d22:
- return "d22";
- case dwarf_d23:
- return "d23";
- case dwarf_d24:
- return "d24";
- case dwarf_d25:
- return "d25";
- case dwarf_d26:
- return "d26";
- case dwarf_d27:
- return "d27";
- case dwarf_d28:
- return "d28";
- case dwarf_d29:
- return "d29";
- case dwarf_d30:
- return "d30";
- case dwarf_d31:
- return "d31";
-
- // NEON 128-bit vector registers (overlays the d registers)
- case dwarf_q0:
- return "q0";
- case dwarf_q1:
- return "q1";
- case dwarf_q2:
- return "q2";
- case dwarf_q3:
- return "q3";
- case dwarf_q4:
- return "q4";
- case dwarf_q5:
- return "q5";
- case dwarf_q6:
- return "q6";
- case dwarf_q7:
- return "q7";
- case dwarf_q8:
- return "q8";
- case dwarf_q9:
- return "q9";
- case dwarf_q10:
- return "q10";
- case dwarf_q11:
- return "q11";
- case dwarf_q12:
- return "q12";
- case dwarf_q13:
- return "q13";
- case dwarf_q14:
- return "q14";
- case dwarf_q15:
- return "q15";
- }
- return nullptr;
-}
-
-bool GetARMDWARFRegisterInfo(unsigned reg_num, RegisterInfo &reg_info) {
- ::memset(&reg_info, 0, sizeof(RegisterInfo));
- ::memset(reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
-
- if (reg_num >= dwarf_q0 && reg_num <= dwarf_q15) {
- reg_info.byte_size = 16;
- reg_info.format = eFormatVectorOfUInt8;
- reg_info.encoding = eEncodingVector;
- }
-
- if (reg_num >= dwarf_d0 && reg_num <= dwarf_d31) {
- reg_info.byte_size = 8;
- reg_info.format = eFormatFloat;
- reg_info.encoding = eEncodingIEEE754;
- } else if (reg_num >= dwarf_s0 && reg_num <= dwarf_s31) {
- reg_info.byte_size = 4;
- reg_info.format = eFormatFloat;
- reg_info.encoding = eEncodingIEEE754;
- } else if (reg_num >= dwarf_f0 && reg_num <= dwarf_f7) {
- reg_info.byte_size = 12;
- reg_info.format = eFormatFloat;
- reg_info.encoding = eEncodingIEEE754;
- } else {
- reg_info.byte_size = 4;
- reg_info.format = eFormatHex;
- reg_info.encoding = eEncodingUint;
- }
-
- reg_info.kinds[eRegisterKindDWARF] = reg_num;
-
- switch (reg_num) {
- case dwarf_r0:
- reg_info.name = "r0";
- break;
- case dwarf_r1:
- reg_info.name = "r1";
- break;
- case dwarf_r2:
- reg_info.name = "r2";
- break;
- case dwarf_r3:
- reg_info.name = "r3";
- break;
- case dwarf_r4:
- reg_info.name = "r4";
- break;
- case dwarf_r5:
- reg_info.name = "r5";
- break;
- case dwarf_r6:
- reg_info.name = "r6";
- break;
- case dwarf_r7:
- reg_info.name = "r7";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- break;
- case dwarf_r8:
- reg_info.name = "r8";
- break;
- case dwarf_r9:
- reg_info.name = "r9";
- break;
- case dwarf_r10:
- reg_info.name = "r10";
- break;
- case dwarf_r11:
- reg_info.name = "r11";
- break;
- case dwarf_r12:
- reg_info.name = "r12";
- break;
- case dwarf_sp:
- reg_info.name = "sp";
- reg_info.alt_name = "r13";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
- break;
- case dwarf_lr:
- reg_info.name = "lr";
- reg_info.alt_name = "r14";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
- break;
- case dwarf_pc:
- reg_info.name = "pc";
- reg_info.alt_name = "r15";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
- break;
- case dwarf_cpsr:
- reg_info.name = "cpsr";
- reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
- break;
-
- case dwarf_s0:
- reg_info.name = "s0";
- break;
- case dwarf_s1:
- reg_info.name = "s1";
- break;
- case dwarf_s2:
- reg_info.name = "s2";
- break;
- case dwarf_s3:
- reg_info.name = "s3";
- break;
- case dwarf_s4:
- reg_info.name = "s4";
- break;
- case dwarf_s5:
- reg_info.name = "s5";
- break;
- case dwarf_s6:
- reg_info.name = "s6";
- break;
- case dwarf_s7:
- reg_info.name = "s7";
- break;
- case dwarf_s8:
- reg_info.name = "s8";
- break;
- case dwarf_s9:
- reg_info.name = "s9";
- break;
- case dwarf_s10:
- reg_info.name = "s10";
- break;
- case dwarf_s11:
- reg_info.name = "s11";
- break;
- case dwarf_s12:
- reg_info.name = "s12";
- break;
- case dwarf_s13:
- reg_info.name = "s13";
- break;
- case dwarf_s14:
- reg_info.name = "s14";
- break;
- case dwarf_s15:
- reg_info.name = "s15";
- break;
- case dwarf_s16:
- reg_info.name = "s16";
- break;
- case dwarf_s17:
- reg_info.name = "s17";
- break;
- case dwarf_s18:
- reg_info.name = "s18";
- break;
- case dwarf_s19:
- reg_info.name = "s19";
- break;
- case dwarf_s20:
- reg_info.name = "s20";
- break;
- case dwarf_s21:
- reg_info.name = "s21";
- break;
- case dwarf_s22:
- reg_info.name = "s22";
- break;
- case dwarf_s23:
- reg_info.name = "s23";
- break;
- case dwarf_s24:
- reg_info.name = "s24";
- break;
- case dwarf_s25:
- reg_info.name = "s25";
- break;
- case dwarf_s26:
- reg_info.name = "s26";
- break;
- case dwarf_s27:
- reg_info.name = "s27";
- break;
- case dwarf_s28:
- reg_info.name = "s28";
- break;
- case dwarf_s29:
- reg_info.name = "s29";
- break;
- case dwarf_s30:
- reg_info.name = "s30";
- break;
- case dwarf_s31:
- reg_info.name = "s31";
- break;
-
- // FPA Registers 0-7
- case dwarf_f0:
- reg_info.name = "f0";
- break;
- case dwarf_f1:
- reg_info.name = "f1";
- break;
- case dwarf_f2:
- reg_info.name = "f2";
- break;
- case dwarf_f3:
- reg_info.name = "f3";
- break;
- case dwarf_f4:
- reg_info.name = "f4";
- break;
- case dwarf_f5:
- reg_info.name = "f5";
- break;
- case dwarf_f6:
- reg_info.name = "f6";
- break;
- case dwarf_f7:
- reg_info.name = "f7";
- break;
-
- // Intel wireless MMX general purpose registers 0 - 7
- // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7)
- case dwarf_wCGR0:
- reg_info.name = "wCGR0/ACC0";
- break;
- case dwarf_wCGR1:
- reg_info.name = "wCGR1/ACC1";
- break;
- case dwarf_wCGR2:
- reg_info.name = "wCGR2/ACC2";
- break;
- case dwarf_wCGR3:
- reg_info.name = "wCGR3/ACC3";
- break;
- case dwarf_wCGR4:
- reg_info.name = "wCGR4/ACC4";
- break;
- case dwarf_wCGR5:
- reg_info.name = "wCGR5/ACC5";
- break;
- case dwarf_wCGR6:
- reg_info.name = "wCGR6/ACC6";
- break;
- case dwarf_wCGR7:
- reg_info.name = "wCGR7/ACC7";
- break;
-
- // Intel wireless MMX data registers 0 - 15
- case dwarf_wR0:
- reg_info.name = "wR0";
- break;
- case dwarf_wR1:
- reg_info.name = "wR1";
- break;
- case dwarf_wR2:
- reg_info.name = "wR2";
- break;
- case dwarf_wR3:
- reg_info.name = "wR3";
- break;
- case dwarf_wR4:
- reg_info.name = "wR4";
- break;
- case dwarf_wR5:
- reg_info.name = "wR5";
- break;
- case dwarf_wR6:
- reg_info.name = "wR6";
- break;
- case dwarf_wR7:
- reg_info.name = "wR7";
- break;
- case dwarf_wR8:
- reg_info.name = "wR8";
- break;
- case dwarf_wR9:
- reg_info.name = "wR9";
- break;
- case dwarf_wR10:
- reg_info.name = "wR10";
- break;
- case dwarf_wR11:
- reg_info.name = "wR11";
- break;
- case dwarf_wR12:
- reg_info.name = "wR12";
- break;
- case dwarf_wR13:
- reg_info.name = "wR13";
- break;
- case dwarf_wR14:
- reg_info.name = "wR14";
- break;
- case dwarf_wR15:
- reg_info.name = "wR15";
- break;
-
- case dwarf_spsr:
- reg_info.name = "spsr";
- break;
- case dwarf_spsr_fiq:
- reg_info.name = "spsr_fiq";
- break;
- case dwarf_spsr_irq:
- reg_info.name = "spsr_irq";
- break;
- case dwarf_spsr_abt:
- reg_info.name = "spsr_abt";
- break;
- case dwarf_spsr_und:
- reg_info.name = "spsr_und";
- break;
- case dwarf_spsr_svc:
- reg_info.name = "spsr_svc";
- break;
-
- case dwarf_r8_usr:
- reg_info.name = "r8_usr";
- break;
- case dwarf_r9_usr:
- reg_info.name = "r9_usr";
- break;
- case dwarf_r10_usr:
- reg_info.name = "r10_usr";
- break;
- case dwarf_r11_usr:
- reg_info.name = "r11_usr";
- break;
- case dwarf_r12_usr:
- reg_info.name = "r12_usr";
- break;
- case dwarf_r13_usr:
- reg_info.name = "r13_usr";
- break;
- case dwarf_r14_usr:
- reg_info.name = "r14_usr";
- break;
- case dwarf_r8_fiq:
- reg_info.name = "r8_fiq";
- break;
- case dwarf_r9_fiq:
- reg_info.name = "r9_fiq";
- break;
- case dwarf_r10_fiq:
- reg_info.name = "r10_fiq";
- break;
- case dwarf_r11_fiq:
- reg_info.name = "r11_fiq";
- break;
- case dwarf_r12_fiq:
- reg_info.name = "r12_fiq";
- break;
- case dwarf_r13_fiq:
- reg_info.name = "r13_fiq";
- break;
- case dwarf_r14_fiq:
- reg_info.name = "r14_fiq";
- break;
- case dwarf_r13_irq:
- reg_info.name = "r13_irq";
- break;
- case dwarf_r14_irq:
- reg_info.name = "r14_irq";
- break;
- case dwarf_r13_abt:
- reg_info.name = "r13_abt";
- break;
- case dwarf_r14_abt:
- reg_info.name = "r14_abt";
- break;
- case dwarf_r13_und:
- reg_info.name = "r13_und";
- break;
- case dwarf_r14_und:
- reg_info.name = "r14_und";
- break;
- case dwarf_r13_svc:
- reg_info.name = "r13_svc";
- break;
- case dwarf_r14_svc:
- reg_info.name = "r14_svc";
- break;
-
- // Intel wireless MMX control register in co-processor 0 - 7
- case dwarf_wC0:
- reg_info.name = "wC0";
- break;
- case dwarf_wC1:
- reg_info.name = "wC1";
- break;
- case dwarf_wC2:
- reg_info.name = "wC2";
- break;
- case dwarf_wC3:
- reg_info.name = "wC3";
- break;
- case dwarf_wC4:
- reg_info.name = "wC4";
- break;
- case dwarf_wC5:
- reg_info.name = "wC5";
- break;
- case dwarf_wC6:
- reg_info.name = "wC6";
- break;
- case dwarf_wC7:
- reg_info.name = "wC7";
- break;
-
- // VFP-v3/Neon
- case dwarf_d0:
- reg_info.name = "d0";
- break;
- case dwarf_d1:
- reg_info.name = "d1";
- break;
- case dwarf_d2:
- reg_info.name = "d2";
- break;
- case dwarf_d3:
- reg_info.name = "d3";
- break;
- case dwarf_d4:
- reg_info.name = "d4";
- break;
- case dwarf_d5:
- reg_info.name = "d5";
- break;
- case dwarf_d6:
- reg_info.name = "d6";
- break;
- case dwarf_d7:
- reg_info.name = "d7";
- break;
- case dwarf_d8:
- reg_info.name = "d8";
- break;
- case dwarf_d9:
- reg_info.name = "d9";
- break;
- case dwarf_d10:
- reg_info.name = "d10";
- break;
- case dwarf_d11:
- reg_info.name = "d11";
- break;
- case dwarf_d12:
- reg_info.name = "d12";
- break;
- case dwarf_d13:
- reg_info.name = "d13";
- break;
- case dwarf_d14:
- reg_info.name = "d14";
- break;
- case dwarf_d15:
- reg_info.name = "d15";
- break;
- case dwarf_d16:
- reg_info.name = "d16";
- break;
- case dwarf_d17:
- reg_info.name = "d17";
- break;
- case dwarf_d18:
- reg_info.name = "d18";
- break;
- case dwarf_d19:
- reg_info.name = "d19";
- break;
- case dwarf_d20:
- reg_info.name = "d20";
- break;
- case dwarf_d21:
- reg_info.name = "d21";
- break;
- case dwarf_d22:
- reg_info.name = "d22";
- break;
- case dwarf_d23:
- reg_info.name = "d23";
- break;
- case dwarf_d24:
- reg_info.name = "d24";
- break;
- case dwarf_d25:
- reg_info.name = "d25";
- break;
- case dwarf_d26:
- reg_info.name = "d26";
- break;
- case dwarf_d27:
- reg_info.name = "d27";
- break;
- case dwarf_d28:
- reg_info.name = "d28";
- break;
- case dwarf_d29:
- reg_info.name = "d29";
- break;
- case dwarf_d30:
- reg_info.name = "d30";
- break;
- case dwarf_d31:
- reg_info.name = "d31";
- break;
-
- // NEON 128-bit vector registers (overlays the d registers)
- case dwarf_q0:
- reg_info.name = "q0";
- break;
- case dwarf_q1:
- reg_info.name = "q1";
- break;
- case dwarf_q2:
- reg_info.name = "q2";
- break;
- case dwarf_q3:
- reg_info.name = "q3";
- break;
- case dwarf_q4:
- reg_info.name = "q4";
- break;
- case dwarf_q5:
- reg_info.name = "q5";
- break;
- case dwarf_q6:
- reg_info.name = "q6";
- break;
- case dwarf_q7:
- reg_info.name = "q7";
- break;
- case dwarf_q8:
- reg_info.name = "q8";
- break;
- case dwarf_q9:
- reg_info.name = "q9";
- break;
- case dwarf_q10:
- reg_info.name = "q10";
- break;
- case dwarf_q11:
- reg_info.name = "q11";
- break;
- case dwarf_q12:
- reg_info.name = "q12";
- break;
- case dwarf_q13:
- reg_info.name = "q13";
- break;
- case dwarf_q14:
- reg_info.name = "q14";
- break;
- case dwarf_q15:
- reg_info.name = "q15";
- break;
-
- default:
- return false;
- }
- return true;
-}
diff --git a/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.h b/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.h
index 9b226c1..ab91d8c 100644
--- a/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.h
+++ b/contrib/llvm/tools/lldb/source/Utility/ARM_DWARF_Registers.h
@@ -205,9 +205,4 @@ enum {
dwarf_q15
};
-const char *GetARMDWARFRegisterName(unsigned reg_num);
-
-bool GetARMDWARFRegisterInfo(unsigned reg_num,
- lldb_private::RegisterInfo &reg_info);
-
#endif // utility_ARM_DWARF_Registers_h_
diff --git a/contrib/llvm/tools/lldb/source/Core/Baton.cpp b/contrib/llvm/tools/lldb/source/Utility/Baton.cpp
index 998a5df..786be2f 100644
--- a/contrib/llvm/tools/lldb/source/Core/Baton.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/Baton.cpp
@@ -7,16 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/Baton.h"
+#include "lldb/Utility/Baton.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Stream.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-void UntypedBaton::GetDescription(Stream *s,
- lldb::DescriptionLevel level) const {}
+void lldb_private::UntypedBaton::GetDescription(
+ Stream *s, lldb::DescriptionLevel level) const {}
diff --git a/contrib/llvm/tools/lldb/source/Utility/Connection.cpp b/contrib/llvm/tools/lldb/source/Utility/Connection.cpp
new file mode 100644
index 0000000..9f6114f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/Connection.cpp
@@ -0,0 +1,14 @@
+//===-- Connection.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Connection.h"
+
+using namespace lldb_private;
+
+Connection::~Connection() = default;
diff --git a/contrib/llvm/tools/lldb/source/Core/ConstString.cpp b/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp
index 21b4d3d..49cf8a6 100644
--- a/contrib/llvm/tools/lldb/source/Core/ConstString.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/ConstString.cpp
@@ -7,20 +7,25 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/ConstString.h"
+#include "lldb/Utility/ConstString.h"
-// C Includes
-// C++ Includes
-#include <array>
-#include <mutex>
+#include "lldb/Utility/Stream.h"
-// Other libraries and framework includes
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/iterator.h" // for iterator_facade_base
+#include "llvm/Support/Allocator.h" // for BumpPtrAllocator
+#include "llvm/Support/FormatProviders.h" // for format_provider
#include "llvm/Support/RWMutex.h"
+#include "llvm/Support/Threading.h"
+
+#include <algorithm> // for min
+#include <array>
+#include <utility> // for make_pair, pair
-// Project includes
-#include "lldb/Core/Stream.h"
+#include <inttypes.h> // for PRIu64
+#include <stdint.h> // for uint8_t, uint32_t, uint64_t
+#include <string.h> // for size_t, strlen
using namespace lldb_private;
@@ -33,14 +38,13 @@ public:
static StringPoolEntryType &
GetStringMapEntryFromKeyData(const char *keyData) {
- char *ptr = const_cast<char *>(keyData) - sizeof(StringPoolEntryType);
- return *reinterpret_cast<StringPoolEntryType *>(ptr);
+ return StringPoolEntryType::GetStringMapEntryFromKeyData(keyData);
}
- size_t GetConstCStringLength(const char *ccstr) const {
+ static size_t GetConstCStringLength(const char *ccstr) {
if (ccstr != nullptr) {
- const uint8_t h = hash(llvm::StringRef(ccstr));
- llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex);
+ // Since the entry is read only, and we derive the entry entirely from the
+ // pointer, we don't need the lock.
const StringPoolEntryType &entry = GetStringMapEntryFromKeyData(ccstr);
return entry.getKey().size();
}
@@ -191,10 +195,10 @@ protected:
// touch ConstStrings is difficult. So we leak the pool instead.
//----------------------------------------------------------------------
static Pool &StringPool() {
- static std::once_flag g_pool_initialization_flag;
+ static llvm::once_flag g_pool_initialization_flag;
static Pool *g_string_pool = nullptr;
- std::call_once(g_pool_initialization_flag,
+ llvm::call_once(g_pool_initialization_flag,
[]() { g_string_pool = new Pool(); });
return *g_string_pool;
@@ -213,10 +217,8 @@ bool ConstString::operator<(const ConstString &rhs) const {
if (m_string == rhs.m_string)
return false;
- llvm::StringRef lhs_string_ref(m_string,
- StringPool().GetConstCStringLength(m_string));
- llvm::StringRef rhs_string_ref(
- rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string));
+ llvm::StringRef lhs_string_ref(GetStringRef());
+ llvm::StringRef rhs_string_ref(rhs.GetStringRef());
// If both have valid C strings, then return the comparison
if (lhs_string_ref.data() && rhs_string_ref.data())
@@ -235,7 +237,7 @@ Stream &lldb_private::operator<<(Stream &s, const ConstString &str) {
}
size_t ConstString::GetLength() const {
- return StringPool().GetConstCStringLength(m_string);
+ return Pool::GetConstCStringLength(m_string);
}
bool ConstString::Equals(const ConstString &lhs, const ConstString &rhs,
@@ -250,10 +252,8 @@ bool ConstString::Equals(const ConstString &lhs, const ConstString &rhs,
return false;
// perform case insensitive equality test
- llvm::StringRef lhs_string_ref(
- lhs.m_string, StringPool().GetConstCStringLength(lhs.m_string));
- llvm::StringRef rhs_string_ref(
- rhs.m_string, StringPool().GetConstCStringLength(rhs.m_string));
+ llvm::StringRef lhs_string_ref(lhs.GetStringRef());
+ llvm::StringRef rhs_string_ref(rhs.GetStringRef());
return lhs_string_ref.equals_lower(rhs_string_ref);
}
@@ -265,10 +265,8 @@ int ConstString::Compare(const ConstString &lhs, const ConstString &rhs,
if (lhs_cstr == rhs_cstr)
return 0;
if (lhs_cstr && rhs_cstr) {
- llvm::StringRef lhs_string_ref(
- lhs_cstr, StringPool().GetConstCStringLength(lhs_cstr));
- llvm::StringRef rhs_string_ref(
- rhs_cstr, StringPool().GetConstCStringLength(rhs_cstr));
+ llvm::StringRef lhs_string_ref(lhs.GetStringRef());
+ llvm::StringRef rhs_string_ref(rhs.GetStringRef());
if (case_sensitive) {
return lhs_string_ref.compare(rhs_string_ref);
@@ -334,3 +332,9 @@ size_t ConstString::StaticMemorySize() {
// Get the size of the static string pool
return StringPool().MemorySize();
}
+
+void llvm::format_provider<ConstString>::format(const ConstString &CS,
+ llvm::raw_ostream &OS,
+ llvm::StringRef Options) {
+ format_provider<StringRef>::format(CS.AsCString(), OS, Options);
+}
diff --git a/contrib/llvm/tools/lldb/source/Utility/ConvertEnum.cpp b/contrib/llvm/tools/lldb/source/Utility/ConvertEnum.cpp
deleted file mode 100644
index bb0484e..0000000
--- a/contrib/llvm/tools/lldb/source/Utility/ConvertEnum.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-//===-- ConvertEnum.cpp -----------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#include "lldb/Utility/ConvertEnum.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-const char *lldb_private::GetVoteAsCString(Vote vote) {
- switch (vote) {
- case eVoteNo:
- return "no";
- case eVoteNoOpinion:
- return "no opinion";
- case eVoteYes:
- return "yes";
- }
- return "invalid";
-}
-
-const char *lldb_private::GetSectionTypeAsCString(lldb::SectionType sect_type) {
- switch (sect_type) {
- case eSectionTypeInvalid:
- return "invalid";
- case eSectionTypeCode:
- return "code";
- case eSectionTypeContainer:
- return "container";
- case eSectionTypeData:
- return "data";
- case eSectionTypeDataCString:
- return "data-cstr";
- case eSectionTypeDataCStringPointers:
- return "data-cstr-ptr";
- case eSectionTypeDataSymbolAddress:
- return "data-symbol-addr";
- case eSectionTypeData4:
- return "data-4-byte";
- case eSectionTypeData8:
- return "data-8-byte";
- case eSectionTypeData16:
- return "data-16-byte";
- case eSectionTypeDataPointers:
- return "data-ptrs";
- case eSectionTypeDebug:
- return "debug";
- case eSectionTypeZeroFill:
- return "zero-fill";
- case eSectionTypeDataObjCMessageRefs:
- return "objc-message-refs";
- case eSectionTypeDataObjCCFStrings:
- return "objc-cfstrings";
- case eSectionTypeDWARFDebugAbbrev:
- return "dwarf-abbrev";
- case eSectionTypeDWARFDebugAddr:
- return "dwarf-addr";
- case eSectionTypeDWARFDebugAranges:
- return "dwarf-aranges";
- case eSectionTypeDWARFDebugFrame:
- return "dwarf-frame";
- case eSectionTypeDWARFDebugInfo:
- return "dwarf-info";
- case eSectionTypeDWARFDebugLine:
- return "dwarf-line";
- case eSectionTypeDWARFDebugLoc:
- return "dwarf-loc";
- case eSectionTypeDWARFDebugMacInfo:
- return "dwarf-macinfo";
- case eSectionTypeDWARFDebugMacro:
- return "dwarf-macro";
- case eSectionTypeDWARFDebugPubNames:
- return "dwarf-pubnames";
- case eSectionTypeDWARFDebugPubTypes:
- return "dwarf-pubtypes";
- case eSectionTypeDWARFDebugRanges:
- return "dwarf-ranges";
- case eSectionTypeDWARFDebugStr:
- return "dwarf-str";
- case eSectionTypeDWARFDebugStrOffsets:
- return "dwarf-str-offsets";
- case eSectionTypeELFSymbolTable:
- return "elf-symbol-table";
- case eSectionTypeELFDynamicSymbols:
- return "elf-dynamic-symbols";
- case eSectionTypeELFRelocationEntries:
- return "elf-relocation-entries";
- case eSectionTypeELFDynamicLinkInfo:
- return "elf-dynamic-link-info";
- case eSectionTypeDWARFAppleNames:
- return "apple-names";
- case eSectionTypeDWARFAppleTypes:
- return "apple-types";
- case eSectionTypeDWARFAppleNamespaces:
- return "apple-namespaces";
- case eSectionTypeDWARFAppleObjC:
- return "apple-objc";
- case eSectionTypeEHFrame:
- return "eh-frame";
- case eSectionTypeARMexidx:
- return "ARM.exidx";
- case eSectionTypeARMextab:
- return "ARM.extab";
- case eSectionTypeCompactUnwind:
- return "compact-unwind";
- case eSectionTypeGoSymtab:
- return "go-symtab";
- case eSectionTypeAbsoluteAddress:
- return "absolute";
- case eSectionTypeOther:
- return "regular";
- }
- return "unknown";
-}
diff --git a/contrib/llvm/tools/lldb/source/Core/DataBufferHeap.cpp b/contrib/llvm/tools/lldb/source/Utility/DataBufferHeap.cpp
index cdd37bf..aa1c3d3 100644
--- a/contrib/llvm/tools/lldb/source/Core/DataBufferHeap.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/DataBufferHeap.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Utility/DataBufferHeap.h"
// C Includes
// C++ Includes
diff --git a/contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp b/contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp
new file mode 100644
index 0000000..bebcafb
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/DataBufferLLVM.cpp
@@ -0,0 +1,70 @@
+//===--- DataBufferLLVM.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/DataBufferLLVM.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <assert.h> // for assert
+#include <type_traits> // for move
+
+using namespace lldb_private;
+
+DataBufferLLVM::DataBufferLLVM(std::unique_ptr<llvm::MemoryBuffer> MemBuffer)
+ : Buffer(std::move(MemBuffer)) {
+ assert(Buffer != nullptr &&
+ "Cannot construct a DataBufferLLVM with a null buffer");
+}
+
+DataBufferLLVM::~DataBufferLLVM() {}
+
+std::shared_ptr<DataBufferLLVM>
+DataBufferLLVM::CreateSliceFromPath(const llvm::Twine &Path, uint64_t Size,
+ uint64_t Offset, bool Private) {
+ // If the file resides non-locally, pass the volatile flag so that we don't
+ // mmap it.
+ if (!Private)
+ Private = !llvm::sys::fs::is_local(Path);
+
+ auto Buffer = llvm::MemoryBuffer::getFileSlice(Path, Size, Offset, Private);
+ if (!Buffer)
+ return nullptr;
+ return std::shared_ptr<DataBufferLLVM>(
+ new DataBufferLLVM(std::move(*Buffer)));
+}
+
+std::shared_ptr<DataBufferLLVM>
+DataBufferLLVM::CreateFromPath(const llvm::Twine &Path, bool NullTerminate, bool Private) {
+ // If the file resides non-locally, pass the volatile flag so that we don't
+ // mmap it.
+ if (!Private)
+ Private = !llvm::sys::fs::is_local(Path);
+
+ auto Buffer = llvm::MemoryBuffer::getFile(Path, -1, NullTerminate, Private);
+ if (!Buffer)
+ return nullptr;
+ return std::shared_ptr<DataBufferLLVM>(
+ new DataBufferLLVM(std::move(*Buffer)));
+}
+
+uint8_t *DataBufferLLVM::GetBytes() {
+ return const_cast<uint8_t *>(GetBuffer());
+}
+
+const uint8_t *DataBufferLLVM::GetBytes() const { return GetBuffer(); }
+
+lldb::offset_t DataBufferLLVM::GetByteSize() const {
+ return Buffer->getBufferSize();
+}
+
+const uint8_t *DataBufferLLVM::GetBuffer() const {
+ return reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
+}
diff --git a/contrib/llvm/tools/lldb/source/Core/DataEncoder.cpp b/contrib/llvm/tools/lldb/source/Utility/DataEncoder.cpp
index 3340436..f7ce468 100644
--- a/contrib/llvm/tools/lldb/source/Core/DataEncoder.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/DataEncoder.cpp
@@ -7,19 +7,18 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/DataEncoder.h"
+#include "lldb/Utility/DataEncoder.h"
-// C Includes
-// C++ Includes
-#include <cassert>
-#include <cstddef>
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/Endian.h"
-// Other libraries and framework includes
+#include "llvm/Support/ErrorHandling.h" // for llvm_unreachable
#include "llvm/Support/MathExtras.h"
-// Project includes
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Host/Endian.h"
+#include <cassert>
+#include <cstddef>
+
+#include <string.h>
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/DataExtractor.cpp b/contrib/llvm/tools/lldb/source/Utility/DataExtractor.cpp
index fbc6e80..008aff2 100644
--- a/contrib/llvm/tools/lldb/source/Core/DataExtractor.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/DataExtractor.cpp
@@ -7,41 +7,35 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-#include <bitset>
-#include <cassert>
-#include <cmath>
-#include <cstddef>
-#include <sstream>
-#include <string>
+#include "lldb/Utility/DataExtractor.h"
+
+#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS
+#include "lldb/lldb-enumerations.h" // for ByteOrder::eByteOrderBig
+#include "lldb/lldb-forward.h" // for DataBufferSP
+#include "lldb/lldb-types.h" // for offset_t
+
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UUID.h"
-// Other libraries and framework includes
-#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
-#include "clang/AST/ASTContext.h"
-
-// Project includes
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Disassembler.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Core/UUID.h"
-#include "lldb/Core/dwarf.h"
-#include "lldb/Host/Endian.h"
-#include "lldb/Symbol/ClangASTContext.h"
-#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/ExecutionContextScope.h"
-#include "lldb/Target/SectionLoadList.h"
-#include "lldb/Target/Target.h"
+#include <algorithm> // for min
+#include <array> // for array
+#include <cassert>
+#include <cstdint> // for uint8_t, uint32_t, uint64_t
+#include <string>
+
+#include <ctype.h> // for isprint
+#include <inttypes.h> // for PRIx64, PRId64
+#include <string.h> // for memcpy, memset, memchr
using namespace lldb;
using namespace lldb_private;
@@ -111,8 +105,6 @@ static inline uint64_t ReadSwapInt64(const void *ptr) {
return llvm::ByteSwap_64(value);
}
-#define NON_PRINTABLE_CHAR '.'
-
DataExtractor::DataExtractor()
: m_start(nullptr), m_end(nullptr),
m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)),
@@ -785,130 +777,6 @@ uint64_t DataExtractor::GetPointer(offset_t *offset_ptr) const {
return GetMaxU64(offset_ptr, m_addr_size);
}
-//----------------------------------------------------------------------
-// GetDwarfEHPtr
-//
-// Used for calls when the value type is specified by a DWARF EH Frame
-// pointer encoding.
-//----------------------------------------------------------------------
-
-uint64_t DataExtractor::GetGNUEHPointer(
- offset_t *offset_ptr, uint32_t eh_ptr_enc, lldb::addr_t pc_rel_addr,
- lldb::addr_t text_addr,
- lldb::addr_t data_addr) //, BSDRelocs *data_relocs) const
-{
- if (eh_ptr_enc == DW_EH_PE_omit)
- return ULLONG_MAX; // Value isn't in the buffer...
-
- uint64_t baseAddress = 0;
- uint64_t addressValue = 0;
- const uint32_t addr_size = GetAddressByteSize();
-#ifdef LLDB_CONFIGURATION_DEBUG
- assert(addr_size == 4 || addr_size == 8);
-#endif
-
- bool signExtendValue = false;
- // Decode the base part or adjust our offset
- switch (eh_ptr_enc & 0x70) {
- case DW_EH_PE_pcrel:
- signExtendValue = true;
- baseAddress = *offset_ptr;
- if (pc_rel_addr != LLDB_INVALID_ADDRESS)
- baseAddress += pc_rel_addr;
- // else
- // Log::GlobalWarning ("PC relative pointer encoding found with
- // invalid pc relative address.");
- break;
-
- case DW_EH_PE_textrel:
- signExtendValue = true;
- if (text_addr != LLDB_INVALID_ADDRESS)
- baseAddress = text_addr;
- // else
- // Log::GlobalWarning ("text relative pointer encoding being
- // decoded with invalid text section address, setting base address
- // to zero.");
- break;
-
- case DW_EH_PE_datarel:
- signExtendValue = true;
- if (data_addr != LLDB_INVALID_ADDRESS)
- baseAddress = data_addr;
- // else
- // Log::GlobalWarning ("data relative pointer encoding being
- // decoded with invalid data section address, setting base address
- // to zero.");
- break;
-
- case DW_EH_PE_funcrel:
- signExtendValue = true;
- break;
-
- case DW_EH_PE_aligned: {
- // SetPointerSize should be called prior to extracting these so the
- // pointer size is cached
- assert(addr_size != 0);
- if (addr_size) {
- // Align to a address size boundary first
- uint32_t alignOffset = *offset_ptr % addr_size;
- if (alignOffset)
- offset_ptr += addr_size - alignOffset;
- }
- } break;
-
- default:
- break;
- }
-
- // Decode the value part
- switch (eh_ptr_enc & DW_EH_PE_MASK_ENCODING) {
- case DW_EH_PE_absptr: {
- addressValue = GetAddress(offset_ptr);
- // if (data_relocs)
- // addressValue = data_relocs->Relocate(*offset_ptr -
- // addr_size, *this, addressValue);
- } break;
- case DW_EH_PE_uleb128:
- addressValue = GetULEB128(offset_ptr);
- break;
- case DW_EH_PE_udata2:
- addressValue = GetU16(offset_ptr);
- break;
- case DW_EH_PE_udata4:
- addressValue = GetU32(offset_ptr);
- break;
- case DW_EH_PE_udata8:
- addressValue = GetU64(offset_ptr);
- break;
- case DW_EH_PE_sleb128:
- addressValue = GetSLEB128(offset_ptr);
- break;
- case DW_EH_PE_sdata2:
- addressValue = (int16_t)GetU16(offset_ptr);
- break;
- case DW_EH_PE_sdata4:
- addressValue = (int32_t)GetU32(offset_ptr);
- break;
- case DW_EH_PE_sdata8:
- addressValue = (int64_t)GetU64(offset_ptr);
- break;
- default:
- // Unhandled encoding type
- assert(eh_ptr_enc);
- break;
- }
-
- // Since we promote everything to 64 bit, we may need to sign extend
- if (signExtendValue && addr_size < sizeof(baseAddress)) {
- uint64_t sign_bit = 1ull << ((addr_size * 8ull) - 1ull);
- if (sign_bit & addressValue) {
- uint64_t mask = ~sign_bit + 1;
- addressValue |= mask;
- }
- }
- return baseAddress + addressValue;
-}
-
size_t DataExtractor::ExtractBytes(offset_t offset, offset_t length,
ByteOrder dst_byte_order, void *dst) const {
const uint8_t *src = PeekData(offset, length);
@@ -1199,759 +1067,6 @@ uint32_t DataExtractor::Skip_LEB128(offset_t *offset_ptr) const {
return bytes_consumed;
}
-static bool GetAPInt(const DataExtractor &data, lldb::offset_t *offset_ptr,
- lldb::offset_t byte_size, llvm::APInt &result) {
- llvm::SmallVector<uint64_t, 2> uint64_array;
- lldb::offset_t bytes_left = byte_size;
- uint64_t u64;
- const lldb::ByteOrder byte_order = data.GetByteOrder();
- if (byte_order == lldb::eByteOrderLittle) {
- while (bytes_left > 0) {
- if (bytes_left >= 8) {
- u64 = data.GetU64(offset_ptr);
- bytes_left -= 8;
- } else {
- u64 = data.GetMaxU64(offset_ptr, (uint32_t)bytes_left);
- bytes_left = 0;
- }
- uint64_array.push_back(u64);
- }
- result = llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
- return true;
- } else if (byte_order == lldb::eByteOrderBig) {
- lldb::offset_t be_offset = *offset_ptr + byte_size;
- lldb::offset_t temp_offset;
- while (bytes_left > 0) {
- if (bytes_left >= 8) {
- be_offset -= 8;
- temp_offset = be_offset;
- u64 = data.GetU64(&temp_offset);
- bytes_left -= 8;
- } else {
- be_offset -= bytes_left;
- temp_offset = be_offset;
- u64 = data.GetMaxU64(&temp_offset, (uint32_t)bytes_left);
- bytes_left = 0;
- }
- uint64_array.push_back(u64);
- }
- *offset_ptr += byte_size;
- result = llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
- return true;
- }
- return false;
-}
-
-static lldb::offset_t DumpAPInt(Stream *s, const DataExtractor &data,
- lldb::offset_t offset, lldb::offset_t byte_size,
- bool is_signed, unsigned radix) {
- llvm::APInt apint;
- if (GetAPInt(data, &offset, byte_size, apint)) {
- std::string apint_str(apint.toString(radix, is_signed));
- switch (radix) {
- case 2:
- s->Write("0b", 2);
- break;
- case 8:
- s->Write("0", 1);
- break;
- case 10:
- break;
- }
- s->Write(apint_str.c_str(), apint_str.size());
- }
- return offset;
-}
-
-static float half2float(uint16_t half) {
- union {
- float f;
- uint32_t u;
- } u;
- int32_t v = (int16_t)half;
-
- if (0 == (v & 0x7c00)) {
- u.u = v & 0x80007FFFU;
- return u.f * ldexpf(1, 125);
- }
-
- v <<= 13;
- u.u = v | 0x70000000U;
- return u.f * ldexpf(1, -112);
-}
-
-lldb::offset_t DataExtractor::Dump(
- Stream *s, offset_t start_offset, lldb::Format item_format,
- size_t item_byte_size, size_t item_count, size_t num_per_line,
- uint64_t base_addr,
- uint32_t item_bit_size, // If zero, this is not a bitfield value, if
- // non-zero, the value is a bitfield
- uint32_t item_bit_offset, // If "item_bit_size" is non-zero, this is the
- // shift amount to apply to a bitfield
- ExecutionContextScope *exe_scope) const {
- if (s == nullptr)
- return start_offset;
-
- if (item_format == eFormatPointer) {
- if (item_byte_size != 4 && item_byte_size != 8)
- item_byte_size = s->GetAddressByteSize();
- }
-
- offset_t offset = start_offset;
-
- if (item_format == eFormatInstruction) {
- TargetSP target_sp;
- if (exe_scope)
- target_sp = exe_scope->CalculateTarget();
- if (target_sp) {
- DisassemblerSP disassembler_sp(Disassembler::FindPlugin(
- target_sp->GetArchitecture(), nullptr, nullptr));
- if (disassembler_sp) {
- lldb::addr_t addr = base_addr + start_offset;
- lldb_private::Address so_addr;
- bool data_from_file = true;
- if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
- data_from_file = false;
- } else {
- if (target_sp->GetSectionLoadList().IsEmpty() ||
- !target_sp->GetImages().ResolveFileAddress(addr, so_addr))
- so_addr.SetRawAddress(addr);
- }
-
- size_t bytes_consumed = disassembler_sp->DecodeInstructions(
- so_addr, *this, start_offset, item_count, false, data_from_file);
-
- if (bytes_consumed) {
- offset += bytes_consumed;
- const bool show_address = base_addr != LLDB_INVALID_ADDRESS;
- const bool show_bytes = true;
- ExecutionContext exe_ctx;
- exe_scope->CalculateExecutionContext(exe_ctx);
- disassembler_sp->GetInstructionList().Dump(s, show_address,
- show_bytes, &exe_ctx);
- }
- }
- } else
- s->Printf("invalid target");
-
- return offset;
- }
-
- if ((item_format == eFormatOSType || item_format == eFormatAddressInfo) &&
- item_byte_size > 8)
- item_format = eFormatHex;
-
- lldb::offset_t line_start_offset = start_offset;
- for (uint32_t count = 0; ValidOffset(offset) && count < item_count; ++count) {
- if ((count % num_per_line) == 0) {
- if (count > 0) {
- if (item_format == eFormatBytesWithASCII &&
- offset > line_start_offset) {
- s->Printf("%*s",
- static_cast<int>(
- (num_per_line - (offset - line_start_offset)) * 3 + 2),
- "");
- Dump(s, line_start_offset, eFormatCharPrintable, 1,
- offset - line_start_offset, SIZE_MAX, LLDB_INVALID_ADDRESS, 0,
- 0);
- }
- s->EOL();
- }
- if (base_addr != LLDB_INVALID_ADDRESS)
- s->Printf("0x%8.8" PRIx64 ": ",
- (uint64_t)(base_addr +
- (offset - start_offset) / m_target_byte_size));
-
- line_start_offset = offset;
- } else if (item_format != eFormatChar &&
- item_format != eFormatCharPrintable &&
- item_format != eFormatCharArray && count > 0) {
- s->PutChar(' ');
- }
-
- switch (item_format) {
- case eFormatBoolean:
- if (item_byte_size <= 8)
- s->Printf("%s", GetMaxU64Bitfield(&offset, item_byte_size,
- item_bit_size, item_bit_offset)
- ? "true"
- : "false");
- else {
- s->Printf("error: unsupported byte size (%" PRIu64
- ") for boolean format",
- (uint64_t)item_byte_size);
- return offset;
- }
- break;
-
- case eFormatBinary:
- if (item_byte_size <= 8) {
- uint64_t uval64 = GetMaxU64Bitfield(&offset, item_byte_size,
- item_bit_size, item_bit_offset);
- // Avoid std::bitset<64>::to_string() since it is missing in
- // earlier C++ libraries
- std::string binary_value(64, '0');
- std::bitset<64> bits(uval64);
- for (uint32_t i = 0; i < 64; ++i)
- if (bits[i])
- binary_value[64 - 1 - i] = '1';
- if (item_bit_size > 0)
- s->Printf("0b%s", binary_value.c_str() + 64 - item_bit_size);
- else if (item_byte_size > 0 && item_byte_size <= 8)
- s->Printf("0b%s", binary_value.c_str() + 64 - item_byte_size * 8);
- } else {
- const bool is_signed = false;
- const unsigned radix = 2;
- offset = DumpAPInt(s, *this, offset, item_byte_size, is_signed, radix);
- }
- break;
-
- case eFormatBytes:
- case eFormatBytesWithASCII:
- for (uint32_t i = 0; i < item_byte_size; ++i) {
- s->Printf("%2.2x", GetU8(&offset));
- }
-
- // Put an extra space between the groups of bytes if more than one
- // is being dumped in a group (item_byte_size is more than 1).
- if (item_byte_size > 1)
- s->PutChar(' ');
- break;
-
- case eFormatChar:
- case eFormatCharPrintable:
- case eFormatCharArray: {
- // If we are only printing one character surround it with single
- // quotes
- if (item_count == 1 && item_format == eFormatChar)
- s->PutChar('\'');
-
- const uint64_t ch = GetMaxU64Bitfield(&offset, item_byte_size,
- item_bit_size, item_bit_offset);
- if (isprint(ch))
- s->Printf("%c", (char)ch);
- else if (item_format != eFormatCharPrintable) {
- switch (ch) {
- case '\033':
- s->Printf("\\e");
- break;
- case '\a':
- s->Printf("\\a");
- break;
- case '\b':
- s->Printf("\\b");
- break;
- case '\f':
- s->Printf("\\f");
- break;
- case '\n':
- s->Printf("\\n");
- break;
- case '\r':
- s->Printf("\\r");
- break;
- case '\t':
- s->Printf("\\t");
- break;
- case '\v':
- s->Printf("\\v");
- break;
- case '\0':
- s->Printf("\\0");
- break;
- default:
- if (item_byte_size == 1)
- s->Printf("\\x%2.2x", (uint8_t)ch);
- else
- s->Printf("%" PRIu64, ch);
- break;
- }
- } else {
- s->PutChar(NON_PRINTABLE_CHAR);
- }
-
- // If we are only printing one character surround it with single quotes
- if (item_count == 1 && item_format == eFormatChar)
- s->PutChar('\'');
- } break;
-
- case eFormatEnum: // Print enum value as a signed integer when we don't get
- // the enum type
- case eFormatDecimal:
- if (item_byte_size <= 8)
- s->Printf("%" PRId64,
- GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
- item_bit_offset));
- else {
- const bool is_signed = true;
- const unsigned radix = 10;
- offset = DumpAPInt(s, *this, offset, item_byte_size, is_signed, radix);
- }
- break;
-
- case eFormatUnsigned:
- if (item_byte_size <= 8)
- s->Printf("%" PRIu64,
- GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
- item_bit_offset));
- else {
- const bool is_signed = false;
- const unsigned radix = 10;
- offset = DumpAPInt(s, *this, offset, item_byte_size, is_signed, radix);
- }
- break;
-
- case eFormatOctal:
- if (item_byte_size <= 8)
- s->Printf("0%" PRIo64,
- GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
- item_bit_offset));
- else {
- const bool is_signed = false;
- const unsigned radix = 8;
- offset = DumpAPInt(s, *this, offset, item_byte_size, is_signed, radix);
- }
- break;
-
- case eFormatOSType: {
- uint64_t uval64 = GetMaxU64Bitfield(&offset, item_byte_size,
- item_bit_size, item_bit_offset);
- s->PutChar('\'');
- for (uint32_t i = 0; i < item_byte_size; ++i) {
- uint8_t ch = (uint8_t)(uval64 >> ((item_byte_size - i - 1) * 8));
- if (isprint(ch))
- s->Printf("%c", ch);
- else {
- switch (ch) {
- case '\033':
- s->Printf("\\e");
- break;
- case '\a':
- s->Printf("\\a");
- break;
- case '\b':
- s->Printf("\\b");
- break;
- case '\f':
- s->Printf("\\f");
- break;
- case '\n':
- s->Printf("\\n");
- break;
- case '\r':
- s->Printf("\\r");
- break;
- case '\t':
- s->Printf("\\t");
- break;
- case '\v':
- s->Printf("\\v");
- break;
- case '\0':
- s->Printf("\\0");
- break;
- default:
- s->Printf("\\x%2.2x", ch);
- break;
- }
- }
- }
- s->PutChar('\'');
- } break;
-
- case eFormatCString: {
- const char *cstr = GetCStr(&offset);
-
- if (!cstr) {
- s->Printf("NULL");
- offset = LLDB_INVALID_OFFSET;
- } else {
- s->PutChar('\"');
-
- while (const char c = *cstr) {
- if (isprint(c)) {
- s->PutChar(c);
- } else {
- switch (c) {
- case '\033':
- s->Printf("\\e");
- break;
- case '\a':
- s->Printf("\\a");
- break;
- case '\b':
- s->Printf("\\b");
- break;
- case '\f':
- s->Printf("\\f");
- break;
- case '\n':
- s->Printf("\\n");
- break;
- case '\r':
- s->Printf("\\r");
- break;
- case '\t':
- s->Printf("\\t");
- break;
- case '\v':
- s->Printf("\\v");
- break;
- default:
- s->Printf("\\x%2.2x", c);
- break;
- }
- }
-
- ++cstr;
- }
-
- s->PutChar('\"');
- }
- } break;
-
- case eFormatPointer:
- s->Address(GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
- item_bit_offset),
- sizeof(addr_t));
- break;
-
- case eFormatComplexInteger: {
- size_t complex_int_byte_size = item_byte_size / 2;
-
- if (complex_int_byte_size > 0 && complex_int_byte_size <= 8) {
- s->Printf("%" PRIu64,
- GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
- s->Printf(" + %" PRIu64 "i",
- GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
- } else {
- s->Printf("error: unsupported byte size (%" PRIu64
- ") for complex integer format",
- (uint64_t)item_byte_size);
- return offset;
- }
- } break;
-
- case eFormatComplex:
- if (sizeof(float) * 2 == item_byte_size) {
- float f32_1 = GetFloat(&offset);
- float f32_2 = GetFloat(&offset);
-
- s->Printf("%g + %gi", f32_1, f32_2);
- break;
- } else if (sizeof(double) * 2 == item_byte_size) {
- double d64_1 = GetDouble(&offset);
- double d64_2 = GetDouble(&offset);
-
- s->Printf("%lg + %lgi", d64_1, d64_2);
- break;
- } else if (sizeof(long double) * 2 == item_byte_size) {
- long double ld64_1 = GetLongDouble(&offset);
- long double ld64_2 = GetLongDouble(&offset);
- s->Printf("%Lg + %Lgi", ld64_1, ld64_2);
- break;
- } else {
- s->Printf("error: unsupported byte size (%" PRIu64
- ") for complex float format",
- (uint64_t)item_byte_size);
- return offset;
- }
- break;
-
- default:
- case eFormatDefault:
- case eFormatHex:
- case eFormatHexUppercase: {
- bool wantsuppercase = (item_format == eFormatHexUppercase);
- switch (item_byte_size) {
- case 1:
- case 2:
- case 4:
- case 8:
- s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64,
- (int)(2 * item_byte_size), (int)(2 * item_byte_size),
- GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
- item_bit_offset));
- break;
- default: {
- assert(item_bit_size == 0 && item_bit_offset == 0);
- const uint8_t *bytes =
- (const uint8_t *)GetData(&offset, item_byte_size);
- if (bytes) {
- s->PutCString("0x");
- uint32_t idx;
- if (m_byte_order == eByteOrderBig) {
- for (idx = 0; idx < item_byte_size; ++idx)
- s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[idx]);
- } else {
- for (idx = 0; idx < item_byte_size; ++idx)
- s->Printf(wantsuppercase ? "%2.2X" : "%2.2x",
- bytes[item_byte_size - 1 - idx]);
- }
- }
- } break;
- }
- } break;
-
- case eFormatFloat: {
- TargetSP target_sp;
- bool used_apfloat = false;
- if (exe_scope)
- target_sp = exe_scope->CalculateTarget();
- if (target_sp) {
- ClangASTContext *clang_ast = target_sp->GetScratchClangASTContext();
- if (clang_ast) {
- clang::ASTContext *ast = clang_ast->getASTContext();
- if (ast) {
- llvm::SmallVector<char, 256> sv;
- // Show full precision when printing float values
- const unsigned format_precision = 0;
- const unsigned format_max_padding = 100;
- size_t item_bit_size = item_byte_size * 8;
-
- if (item_bit_size == ast->getTypeSize(ast->FloatTy)) {
- llvm::APInt apint(item_bit_size,
- this->GetMaxU64(&offset, item_byte_size));
- llvm::APFloat apfloat(ast->getFloatTypeSemantics(ast->FloatTy),
- apint);
- apfloat.toString(sv, format_precision, format_max_padding);
- } else if (item_bit_size == ast->getTypeSize(ast->DoubleTy)) {
- llvm::APInt apint;
- if (GetAPInt(*this, &offset, item_byte_size, apint)) {
- llvm::APFloat apfloat(ast->getFloatTypeSemantics(ast->DoubleTy),
- apint);
- apfloat.toString(sv, format_precision, format_max_padding);
- }
- } else if (item_bit_size == ast->getTypeSize(ast->LongDoubleTy)) {
- const auto &semantics =
- ast->getFloatTypeSemantics(ast->LongDoubleTy);
- const auto byte_size =
- (llvm::APFloat::getSizeInBits(semantics) + 7) / 8;
-
- llvm::APInt apint;
- if (GetAPInt(*this, &offset, byte_size, apint)) {
- llvm::APFloat apfloat(semantics, apint);
- apfloat.toString(sv, format_precision, format_max_padding);
- }
- } else if (item_bit_size == ast->getTypeSize(ast->HalfTy)) {
- llvm::APInt apint(item_bit_size, this->GetU16(&offset));
- llvm::APFloat apfloat(ast->getFloatTypeSemantics(ast->HalfTy),
- apint);
- apfloat.toString(sv, format_precision, format_max_padding);
- }
-
- if (!sv.empty()) {
- s->Printf("%*.*s", (int)sv.size(), (int)sv.size(), sv.data());
- used_apfloat = true;
- }
- }
- }
- }
-
- if (!used_apfloat) {
- std::ostringstream ss;
- if (item_byte_size == sizeof(float) || item_byte_size == 2) {
- float f;
- if (item_byte_size == 2) {
- uint16_t half = this->GetU16(&offset);
- f = half2float(half);
- } else {
- f = GetFloat(&offset);
- }
- ss.precision(std::numeric_limits<float>::digits10);
- ss << f;
- } else if (item_byte_size == sizeof(double)) {
- ss.precision(std::numeric_limits<double>::digits10);
- ss << GetDouble(&offset);
- } else if (item_byte_size == sizeof(long double) ||
- item_byte_size == 10) {
- ss.precision(std::numeric_limits<long double>::digits10);
- ss << GetLongDouble(&offset);
- } else {
- s->Printf("error: unsupported byte size (%" PRIu64
- ") for float format",
- (uint64_t)item_byte_size);
- return offset;
- }
- ss.flush();
- s->Printf("%s", ss.str().c_str());
- }
- } break;
-
- case eFormatUnicode16:
- s->Printf("U+%4.4x", GetU16(&offset));
- break;
-
- case eFormatUnicode32:
- s->Printf("U+0x%8.8x", GetU32(&offset));
- break;
-
- case eFormatAddressInfo: {
- addr_t addr = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
- item_bit_offset);
- s->Printf("0x%*.*" PRIx64, (int)(2 * item_byte_size),
- (int)(2 * item_byte_size), addr);
- if (exe_scope) {
- TargetSP target_sp(exe_scope->CalculateTarget());
- lldb_private::Address so_addr;
- if (target_sp) {
- if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr,
- so_addr)) {
- s->PutChar(' ');
- so_addr.Dump(s, exe_scope, Address::DumpStyleResolvedDescription,
- Address::DumpStyleModuleWithFileAddress);
- } else {
- so_addr.SetOffset(addr);
- so_addr.Dump(s, exe_scope,
- Address::DumpStyleResolvedPointerDescription);
- }
- }
- }
- } break;
-
- case eFormatHexFloat:
- if (sizeof(float) == item_byte_size) {
- char float_cstr[256];
- llvm::APFloat ap_float(GetFloat(&offset));
- ap_float.convertToHexString(float_cstr, 0, false,
- llvm::APFloat::rmNearestTiesToEven);
- s->Printf("%s", float_cstr);
- break;
- } else if (sizeof(double) == item_byte_size) {
- char float_cstr[256];
- llvm::APFloat ap_float(GetDouble(&offset));
- ap_float.convertToHexString(float_cstr, 0, false,
- llvm::APFloat::rmNearestTiesToEven);
- s->Printf("%s", float_cstr);
- break;
- } else {
- s->Printf("error: unsupported byte size (%" PRIu64
- ") for hex float format",
- (uint64_t)item_byte_size);
- return offset;
- }
- break;
-
- // please keep the single-item formats below in sync with
- // FormatManager::GetSingleItemFormat
- // if you fail to do so, users will start getting different outputs
- // depending on internal
- // implementation details they should not care about ||
- case eFormatVectorOfChar: // ||
- s->PutChar('{'); // \/
- offset = Dump(s, offset, eFormatCharArray, 1, item_byte_size,
- item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfSInt8:
- s->PutChar('{');
- offset = Dump(s, offset, eFormatDecimal, 1, item_byte_size,
- item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfUInt8:
- s->PutChar('{');
- offset = Dump(s, offset, eFormatHex, 1, item_byte_size, item_byte_size,
- LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfSInt16:
- s->PutChar('{');
- offset =
- Dump(s, offset, eFormatDecimal, sizeof(uint16_t),
- item_byte_size / sizeof(uint16_t),
- item_byte_size / sizeof(uint16_t), LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfUInt16:
- s->PutChar('{');
- offset =
- Dump(s, offset, eFormatHex, sizeof(uint16_t),
- item_byte_size / sizeof(uint16_t),
- item_byte_size / sizeof(uint16_t), LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfSInt32:
- s->PutChar('{');
- offset =
- Dump(s, offset, eFormatDecimal, sizeof(uint32_t),
- item_byte_size / sizeof(uint32_t),
- item_byte_size / sizeof(uint32_t), LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfUInt32:
- s->PutChar('{');
- offset =
- Dump(s, offset, eFormatHex, sizeof(uint32_t),
- item_byte_size / sizeof(uint32_t),
- item_byte_size / sizeof(uint32_t), LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfSInt64:
- s->PutChar('{');
- offset =
- Dump(s, offset, eFormatDecimal, sizeof(uint64_t),
- item_byte_size / sizeof(uint64_t),
- item_byte_size / sizeof(uint64_t), LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfUInt64:
- s->PutChar('{');
- offset =
- Dump(s, offset, eFormatHex, sizeof(uint64_t),
- item_byte_size / sizeof(uint64_t),
- item_byte_size / sizeof(uint64_t), LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfFloat16:
- s->PutChar('{');
- offset = Dump(s, offset, eFormatFloat, 2, item_byte_size / 2,
- item_byte_size / 2, LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfFloat32:
- s->PutChar('{');
- offset = Dump(s, offset, eFormatFloat, 4, item_byte_size / 4,
- item_byte_size / 4, LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfFloat64:
- s->PutChar('{');
- offset = Dump(s, offset, eFormatFloat, 8, item_byte_size / 8,
- item_byte_size / 8, LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
-
- case eFormatVectorOfUInt128:
- s->PutChar('{');
- offset = Dump(s, offset, eFormatHex, 16, item_byte_size / 16,
- item_byte_size / 16, LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('}');
- break;
- }
- }
-
- if (item_format == eFormatBytesWithASCII && offset > line_start_offset) {
- s->Printf("%*s", static_cast<int>(
- (num_per_line - (offset - line_start_offset)) * 3 + 2),
- "");
- Dump(s, line_start_offset, eFormatCharPrintable, 1,
- offset - line_start_offset, SIZE_MAX, LLDB_INVALID_ADDRESS, 0, 0);
- }
- return offset; // Return the offset at which we ended up
-}
-
//----------------------------------------------------------------------
// Dumps bytes from this object's data to the stream "s" starting
// "start_offset" bytes into this data, and ending with the byte
@@ -2043,19 +1158,6 @@ void DataExtractor::DumpUUID(Stream *s, offset_t offset) const {
}
}
-void DataExtractor::DumpHexBytes(Stream *s, const void *src, size_t src_len,
- uint32_t bytes_per_line, addr_t base_addr) {
- DataExtractor data(src, src_len, eByteOrderLittle, 4);
- data.Dump(s,
- 0, // Offset into "src"
- eFormatBytes, // Dump as hex bytes
- 1, // Size of each item is 1 for single bytes
- src_len, // Number of bytes
- bytes_per_line, // Num bytes per line
- base_addr, // Base address
- 0, 0); // Bitfield info
-}
-
size_t DataExtractor::Copy(DataExtractor &dest_data) const {
if (m_data_sp) {
// we can pass along the SP to the data
@@ -2138,6 +1240,6 @@ void DataExtractor::Checksum(llvm::SmallVectorImpl<uint8_t> &dest,
llvm::MD5::MD5Result result;
md5.final(result);
- dest.resize(16);
- std::copy(result, result + 16, dest.begin());
+ dest.clear();
+ dest.append(result.Bytes.begin(), result.Bytes.end());
}
diff --git a/contrib/llvm/tools/lldb/source/Core/FastDemangle.cpp b/contrib/llvm/tools/lldb/source/Utility/FastDemangle.cpp
index 0bed4a1..90326c5 100644
--- a/contrib/llvm/tools/lldb/source/Core/FastDemangle.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/FastDemangle.cpp
@@ -7,14 +7,15 @@
//
//===----------------------------------------------------------------------===//
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "lldb/Utility/FastDemangle.h"
+
+#include "llvm/Support/Compiler.h" // for LLVM_FALLTHROUGH
#include <functional>
-#include "lldb/Core/FastDemangle.h"
-#include "lldb/lldb-private.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
//#define DEBUG_FAILURES 1
//#define DEBUG_SUBSTITUTIONS 1
diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp b/contrib/llvm/tools/lldb/source/Utility/FileSpec.cpp
index 7f46d30..3c4e340 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/FileSpec.cpp
@@ -7,52 +7,48 @@
//
//===----------------------------------------------------------------------===//
-#ifndef _WIN32
-#include <dirent.h>
-#else
-#include "lldb/Host/windows/windows.h"
-#endif
-#include <fcntl.h>
-#ifndef _MSC_VER
-#include <libgen.h>
-#endif
-#include <fstream>
-#include <set>
-#include <string.h>
-
-#include "lldb/Host/Config.h" // Have to include this before we test the define...
-#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
-#include <pwd.h>
-#endif
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/TildeExpressionResolver.h"
-#include "lldb/Core/ArchSpec.h"
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/DataBufferMemoryMap.h"
-#include "lldb/Core/RegularExpression.h"
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/File.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/Host.h"
-#include "lldb/Utility/CleanUp.h"
-
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SmallString.h" // for SmallString
+#include "llvm/ADT/SmallVector.h" // for SmallVectorTemplat...
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/ConvertUTF.h"
+#include "llvm/ADT/Triple.h" // for Triple
+#include "llvm/ADT/Twine.h" // for Twine
+#include "llvm/Config/llvm-config.h" // for LLVM_ON_WIN32
+#include "llvm/Support/ErrorOr.h" // for ErrorOr
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h" // for raw_ostream, fs
+
+#include <algorithm> // for replace, min, unique
+#include <system_error> // for error_code
+#include <vector> // for vector
+
+#include <assert.h> // for assert
+#include <stdio.h> // for size_t, NULL, snpr...
+#include <string.h> // for strcmp
using namespace lldb;
using namespace lldb_private;
namespace {
+static constexpr FileSpec::PathSyntax GetNativeSyntax() {
+#if defined(LLVM_ON_WIN32)
+ return FileSpec::ePathSyntaxWindows;
+#else
+ return FileSpec::ePathSyntaxPosix;
+#endif
+}
+
bool PathSyntaxIsPosix(FileSpec::PathSyntax syntax) {
return (syntax == FileSpec::ePathSyntaxPosix ||
(syntax == FileSpec::ePathSyntaxHostNative &&
- FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix));
+ GetNativeSyntax() == FileSpec::ePathSyntaxPosix));
}
const char *GetPathSeparators(FileSpec::PathSyntax syntax) {
@@ -88,13 +84,6 @@ void Denormalize(llvm::SmallVectorImpl<char> &path,
std::replace(path.begin(), path.end(), '/', '\\');
}
-bool GetFileStats(const FileSpec *file_spec, struct stat *stats_ptr) {
- char resolved_path[PATH_MAX];
- if (file_spec->GetPath(resolved_path, sizeof(resolved_path)))
- return FileSystem::Stat(resolved_path, stats_ptr) == 0;
- return false;
-}
-
size_t FilenamePos(llvm::StringRef str, FileSpec::PathSyntax syntax) {
if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1])
return 0;
@@ -157,115 +146,13 @@ size_t ParentPathEnd(llvm::StringRef path, FileSpec::PathSyntax syntax) {
} // end anonymous namespace
-// Resolves the username part of a path of the form ~user/other/directories, and
-// writes the result into dst_path. This will also resolve "~" to the current
-// user.
-// If you want to complete "~" to the list of users, pass it to
-// ResolvePartialUsername.
-void FileSpec::ResolveUsername(llvm::SmallVectorImpl<char> &path) {
-#if LLDB_CONFIG_TILDE_RESOLVES_TO_USER
- if (path.empty() || path[0] != '~')
- return;
-
- llvm::StringRef path_str(path.data(), path.size());
- size_t slash_pos = path_str.find('/', 1);
- if (slash_pos == 1 || path.size() == 1) {
- // A path of ~/ resolves to the current user's home dir
- llvm::SmallString<64> home_dir;
- // llvm::sys::path::home_directory() only checks if "HOME" is set in the
- // environment and does nothing else to locate the user home directory
- if (!llvm::sys::path::home_directory(home_dir)) {
- struct passwd *pw = getpwuid(getuid());
- if (pw && pw->pw_dir && pw->pw_dir[0]) {
- // Update our environemnt so llvm::sys::path::home_directory() works
- // next time
- setenv("HOME", pw->pw_dir, 0);
- home_dir.assign(llvm::StringRef(pw->pw_dir));
- } else {
- return;
- }
- }
-
- // Overwrite the ~ with the first character of the homedir, and insert
- // the rest. This way we only trigger one move, whereas an insert
- // followed by a delete (or vice versa) would trigger two.
- path[0] = home_dir[0];
- path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end());
- return;
- }
-
- auto username_begin = path.begin() + 1;
- auto username_end = (slash_pos == llvm::StringRef::npos)
- ? path.end()
- : (path.begin() + slash_pos);
- size_t replacement_length = std::distance(path.begin(), username_end);
-
- llvm::SmallString<20> username(username_begin, username_end);
- struct passwd *user_entry = ::getpwnam(username.c_str());
- if (user_entry != nullptr) {
- // Copy over the first n characters of the path, where n is the smaller of
- // the length
- // of the home directory and the slash pos.
- llvm::StringRef homedir(user_entry->pw_dir);
- size_t initial_copy_length = std::min(homedir.size(), replacement_length);
- auto src_begin = homedir.begin();
- auto src_end = src_begin + initial_copy_length;
- std::copy(src_begin, src_end, path.begin());
- if (replacement_length > homedir.size()) {
- // We copied the entire home directory, but the ~username portion of the
- // path was
- // longer, so there's characters that need to be removed.
- path.erase(path.begin() + initial_copy_length, username_end);
- } else if (replacement_length < homedir.size()) {
- // We copied all the way up to the slash in the destination, but there's
- // still more
- // characters that need to be inserted.
- path.insert(username_end, src_end, homedir.end());
- }
- } else {
- // Unable to resolve username (user doesn't exist?)
- path.clear();
- }
-#endif
-}
-
-size_t FileSpec::ResolvePartialUsername(llvm::StringRef partial_name,
- StringList &matches) {
-#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
- size_t extant_entries = matches.GetSize();
-
- setpwent();
- struct passwd *user_entry;
- partial_name = partial_name.drop_front();
- std::set<std::string> name_list;
-
- while ((user_entry = getpwent()) != NULL) {
- if (llvm::StringRef(user_entry->pw_name).startswith(partial_name)) {
- std::string tmp_buf("~");
- tmp_buf.append(user_entry->pw_name);
- tmp_buf.push_back('/');
- name_list.insert(tmp_buf);
- }
- }
-
- for (auto &name : name_list) {
- matches.AppendString(name);
- }
- return matches.GetSize() - extant_entries;
-#else
- // Resolving home directories is not supported, just copy the path...
- return 0;
-#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
-}
-
void FileSpec::Resolve(llvm::SmallVectorImpl<char> &path) {
if (path.empty())
return;
-#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
- if (path[0] == '~')
- ResolveUsername(path);
-#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ llvm::SmallString<32> Source(path.begin(), path.end());
+ StandardTildeExpressionResolver Resolver;
+ Resolver.ResolveFullPath(Source, path);
// Save a copy of the original path that's passed in
llvm::SmallString<128> original_path(path.begin(), path.end());
@@ -277,7 +164,7 @@ void FileSpec::Resolve(llvm::SmallVectorImpl<char> &path) {
}
}
-FileSpec::FileSpec() : m_syntax(FileSystem::GetNativePathSyntax()) {}
+FileSpec::FileSpec() : m_syntax(GetNativeSyntax()) {}
//------------------------------------------------------------------
// Default constructor that can take an optional full path to a
@@ -288,10 +175,10 @@ FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, PathSyntax syntax)
SetFile(path, resolve_path, syntax);
}
-FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, ArchSpec arch)
- : FileSpec{path, resolve_path, arch.GetTriple().isOSWindows()
- ? ePathSyntaxWindows
- : ePathSyntaxPosix} {}
+FileSpec::FileSpec(llvm::StringRef path, bool resolve_path,
+ const llvm::Triple &Triple)
+ : FileSpec{path, resolve_path,
+ Triple.isOSWindows() ? ePathSyntaxWindows : ePathSyntaxPosix} {}
//------------------------------------------------------------------
// Copy constructor
@@ -340,9 +227,7 @@ void FileSpec::SetFile(llvm::StringRef pathname, bool resolve,
m_filename.Clear();
m_directory.Clear();
m_is_resolved = false;
- m_syntax = (syntax == ePathSyntaxHostNative)
- ? FileSystem::GetNativePathSyntax()
- : syntax;
+ m_syntax = (syntax == ePathSyntaxHostNative) ? GetNativeSyntax() : syntax;
if (pathname.empty())
return;
@@ -378,10 +263,10 @@ void FileSpec::SetFile(llvm::StringRef pathname, bool resolve,
: resolve_path_ref.substr(filename_begin));
}
-void FileSpec::SetFile(llvm::StringRef path, bool resolve, ArchSpec arch) {
- return SetFile(path, resolve, arch.GetTriple().isOSWindows()
- ? ePathSyntaxWindows
- : ePathSyntaxPosix);
+void FileSpec::SetFile(llvm::StringRef path, bool resolve,
+ const llvm::Triple &Triple) {
+ return SetFile(path, resolve,
+ Triple.isOSWindows() ? ePathSyntaxWindows : ePathSyntaxPosix);
}
//----------------------------------------------------------------------
@@ -526,11 +411,36 @@ int FileSpec::Compare(const FileSpec &a, const FileSpec &b, bool full) {
bool FileSpec::Equal(const FileSpec &a, const FileSpec &b, bool full,
bool remove_backups) {
+ static ConstString g_dot_string(".");
+ static ConstString g_dot_dot_string("..");
+
// case sensitivity of equality test
const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive();
+
+ bool filenames_equal = ConstString::Equals(a.m_filename,
+ b.m_filename,
+ case_sensitive);
+
+ // The only way two FileSpecs can be equal if their filenames are
+ // unequal is if we are removing backups and one or the other filename
+ // is a backup string:
+
+ if (!filenames_equal && !remove_backups)
+ return false;
+
+ bool last_component_is_dot = ConstString::Equals(a.m_filename, g_dot_string)
+ || ConstString::Equals(a.m_filename,
+ g_dot_dot_string)
+ || ConstString::Equals(b.m_filename,
+ g_dot_string)
+ || ConstString::Equals(b.m_filename,
+ g_dot_dot_string);
+
+ if (!filenames_equal && !last_component_is_dot)
+ return false;
if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty()))
- return ConstString::Equals(a.m_filename, b.m_filename, case_sensitive);
+ return filenames_equal;
if (remove_backups == false)
return a == b;
@@ -619,16 +529,10 @@ void FileSpec::Dump(Stream *s) const {
//------------------------------------------------------------------
// Returns true if the file exists.
//------------------------------------------------------------------
-bool FileSpec::Exists() const {
- struct stat file_stats;
- return GetFileStats(this, &file_stats);
-}
+bool FileSpec::Exists() const { return llvm::sys::fs::exists(GetPath()); }
bool FileSpec::Readable() const {
- const uint32_t permissions = GetPermissions();
- if (permissions & eFilePermissionsEveryoneR)
- return true;
- return false;
+ return GetPermissions() & llvm::sys::fs::perms::all_read;
}
bool FileSpec::ResolveExecutableLocation() {
@@ -672,76 +576,27 @@ bool FileSpec::ResolvePath() {
if (m_is_resolved)
return true; // We have already resolved this path
- char path_buf[PATH_MAX];
- if (!GetPath(path_buf, PATH_MAX, false))
- return false;
// SetFile(...) will set m_is_resolved correctly if it can resolve the path
- SetFile(path_buf, true);
+ SetFile(GetPath(false), true);
return m_is_resolved;
}
uint64_t FileSpec::GetByteSize() const {
- struct stat file_stats;
- if (GetFileStats(this, &file_stats))
- return file_stats.st_size;
- return 0;
+ uint64_t Size = 0;
+ if (llvm::sys::fs::file_size(GetPath(), Size))
+ return 0;
+ return Size;
}
FileSpec::PathSyntax FileSpec::GetPathSyntax() const { return m_syntax; }
-FileSpec::FileType FileSpec::GetFileType() const {
- struct stat file_stats;
- if (GetFileStats(this, &file_stats)) {
- mode_t file_type = file_stats.st_mode & S_IFMT;
- switch (file_type) {
- case S_IFDIR:
- return eFileTypeDirectory;
- case S_IFREG:
- return eFileTypeRegular;
-#ifndef _WIN32
- case S_IFIFO:
- return eFileTypePipe;
- case S_IFSOCK:
- return eFileTypeSocket;
- case S_IFLNK:
- return eFileTypeSymbolicLink;
-#endif
- default:
- break;
- }
- return eFileTypeUnknown;
- }
- return eFileTypeInvalid;
-}
-
-bool FileSpec::IsSymbolicLink() const {
- char resolved_path[PATH_MAX];
- if (!GetPath(resolved_path, sizeof(resolved_path)))
- return false;
-
-#ifdef _WIN32
- std::wstring wpath;
- if (!llvm::ConvertUTF8toWide(resolved_path, wpath))
- return false;
- auto attrs = ::GetFileAttributesW(wpath.c_str());
- if (attrs == INVALID_FILE_ATTRIBUTES)
- return false;
-
- return (attrs & FILE_ATTRIBUTE_REPARSE_POINT);
-#else
- struct stat file_stats;
- if (::lstat(resolved_path, &file_stats) != 0)
- return false;
-
- return (file_stats.st_mode & S_IFMT) == S_IFLNK;
-#endif
-}
-
uint32_t FileSpec::GetPermissions() const {
- uint32_t file_permissions = 0;
- if (*this)
- FileSystem::GetFilePermissions(*this, file_permissions);
- return file_permissions;
+ namespace fs = llvm::sys::fs;
+ fs::file_status st;
+ if (fs::status(GetPath(), st, false))
+ return fs::perms::perms_not_known;
+
+ return st.permissions();
}
//------------------------------------------------------------------
@@ -826,39 +681,6 @@ ConstString FileSpec::GetFileNameStrippingExtension() const {
}
//------------------------------------------------------------------
-// Returns a shared pointer to a data buffer that contains all or
-// part of the contents of a file. The data is memory mapped and
-// will lazily page in data from the file as memory is accessed.
-// The data that is mapped will start "file_offset" bytes into the
-// file, and "file_size" bytes will be mapped. If "file_size" is
-// greater than the number of bytes available in the file starting
-// at "file_offset", the number of bytes will be appropriately
-// truncated. The final number of bytes that get mapped can be
-// verified using the DataBuffer::GetByteSize() function.
-//------------------------------------------------------------------
-DataBufferSP FileSpec::MemoryMapFileContents(off_t file_offset,
- size_t file_size) const {
- DataBufferSP data_sp;
- std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap());
- if (mmap_data.get()) {
- const size_t mapped_length =
- mmap_data->MemoryMapFromFileSpec(this, file_offset, file_size);
- if (((file_size == SIZE_MAX) && (mapped_length > 0)) ||
- (mapped_length >= file_size))
- data_sp.reset(mmap_data.release());
- }
- return data_sp;
-}
-
-DataBufferSP FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset,
- size_t file_size) const {
- if (FileSystem::IsLocal(*this))
- return MemoryMapFileContents(file_offset, file_size);
- else
- return ReadFileContents(file_offset, file_size, NULL);
-}
-
-//------------------------------------------------------------------
// Return the size in bytes that this object takes in memory. This
// returns the size in bytes of this object, not any shared string
// values it may refer to.
@@ -867,322 +689,37 @@ size_t FileSpec::MemorySize() const {
return m_filename.MemorySize() + m_directory.MemorySize();
}
-size_t FileSpec::ReadFileContents(off_t file_offset, void *dst, size_t dst_len,
- Error *error_ptr) const {
- Error error;
- size_t bytes_read = 0;
- char resolved_path[PATH_MAX];
- if (GetPath(resolved_path, sizeof(resolved_path))) {
- File file;
- error = file.Open(resolved_path, File::eOpenOptionRead);
- if (error.Success()) {
- off_t file_offset_after_seek = file_offset;
- bytes_read = dst_len;
- error = file.Read(dst, bytes_read, file_offset_after_seek);
- }
- } else {
- error.SetErrorString("invalid file specification");
- }
- if (error_ptr)
- *error_ptr = error;
- return bytes_read;
-}
-
-//------------------------------------------------------------------
-// Returns a shared pointer to a data buffer that contains all or
-// part of the contents of a file. The data copies into a heap based
-// buffer that lives in the DataBuffer shared pointer object returned.
-// The data that is cached will start "file_offset" bytes into the
-// file, and "file_size" bytes will be mapped. If "file_size" is
-// greater than the number of bytes available in the file starting
-// at "file_offset", the number of bytes will be appropriately
-// truncated. The final number of bytes that get mapped can be
-// verified using the DataBuffer::GetByteSize() function.
-//------------------------------------------------------------------
-DataBufferSP FileSpec::ReadFileContents(off_t file_offset, size_t file_size,
- Error *error_ptr) const {
- Error error;
- DataBufferSP data_sp;
- char resolved_path[PATH_MAX];
- if (GetPath(resolved_path, sizeof(resolved_path))) {
- File file;
- error = file.Open(resolved_path, File::eOpenOptionRead);
- if (error.Success()) {
- const bool null_terminate = false;
- error = file.Read(file_size, file_offset, null_terminate, data_sp);
- }
- } else {
- error.SetErrorString("invalid file specification");
- }
- if (error_ptr)
- *error_ptr = error;
- return data_sp;
-}
-
-DataBufferSP FileSpec::ReadFileContentsAsCString(Error *error_ptr) {
- Error error;
- DataBufferSP data_sp;
- char resolved_path[PATH_MAX];
- if (GetPath(resolved_path, sizeof(resolved_path))) {
- File file;
- error = file.Open(resolved_path, File::eOpenOptionRead);
- if (error.Success()) {
- off_t offset = 0;
- size_t length = SIZE_MAX;
- const bool null_terminate = true;
- error = file.Read(length, offset, null_terminate, data_sp);
- }
- } else {
- error.SetErrorString("invalid file specification");
- }
- if (error_ptr)
- *error_ptr = error;
- return data_sp;
-}
-
-size_t FileSpec::ReadFileLines(STLStringArray &lines) {
- lines.clear();
- char path[PATH_MAX];
- if (GetPath(path, sizeof(path))) {
- std::ifstream file_stream(path);
-
- if (file_stream) {
- std::string line;
- while (getline(file_stream, line))
- lines.push_back(line);
+void FileSpec::EnumerateDirectory(llvm::StringRef dir_path,
+ bool find_directories, bool find_files,
+ bool find_other,
+ EnumerateDirectoryCallbackType callback,
+ void *callback_baton) {
+ namespace fs = llvm::sys::fs;
+ std::error_code EC;
+ fs::recursive_directory_iterator Iter(dir_path, EC);
+ fs::recursive_directory_iterator End;
+ for (; Iter != End && !EC; Iter.increment(EC)) {
+ const auto &Item = *Iter;
+ fs::file_status Status;
+ if ((EC = Item.status(Status)))
+ break;
+ if (!find_files && fs::is_regular_file(Status))
+ continue;
+ if (!find_directories && fs::is_directory(Status))
+ continue;
+ if (!find_other && fs::is_other(Status))
+ continue;
+
+ FileSpec Spec(Item.path(), false);
+ auto Result = callback(callback_baton, Status.type(), Spec);
+ if (Result == eEnumerateDirectoryResultQuit)
+ return;
+ if (Result == eEnumerateDirectoryResultNext) {
+ // Default behavior is to recurse. Opt out if the callback doesn't want
+ // this behavior.
+ Iter.no_push();
}
}
- return lines.size();
-}
-
-FileSpec::EnumerateDirectoryResult
-FileSpec::ForEachItemInDirectory(llvm::StringRef dir_path,
- DirectoryCallback const &callback) {
- if (dir_path.empty())
- return eEnumerateDirectoryResultNext;
-
-#ifdef _WIN32
- std::string szDir(dir_path);
- szDir += "\\*";
-
- std::wstring wszDir;
- if (!llvm::ConvertUTF8toWide(szDir, wszDir)) {
- return eEnumerateDirectoryResultNext;
- }
-
- WIN32_FIND_DATAW ffd;
- HANDLE hFind = FindFirstFileW(wszDir.c_str(), &ffd);
-
- if (hFind == INVALID_HANDLE_VALUE) {
- return eEnumerateDirectoryResultNext;
- }
-
- do {
- FileSpec::FileType file_type = eFileTypeUnknown;
- if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- size_t len = wcslen(ffd.cFileName);
-
- if (len == 1 && ffd.cFileName[0] == L'.')
- continue;
-
- if (len == 2 && ffd.cFileName[0] == L'.' && ffd.cFileName[1] == L'.')
- continue;
-
- file_type = eFileTypeDirectory;
- } else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) {
- file_type = eFileTypeOther;
- } else {
- file_type = eFileTypeRegular;
- }
-
- std::string fileName;
- if (!llvm::convertWideToUTF8(ffd.cFileName, fileName)) {
- continue;
- }
-
- std::string child_path = llvm::join_items("\\", dir_path, fileName);
- // Don't resolve the file type or path
- FileSpec child_path_spec(child_path.data(), false);
-
- EnumerateDirectoryResult result = callback(file_type, child_path_spec);
-
- switch (result) {
- case eEnumerateDirectoryResultNext:
- // Enumerate next entry in the current directory. We just
- // exit this switch and will continue enumerating the
- // current directory as we currently are...
- break;
-
- case eEnumerateDirectoryResultEnter: // Recurse into the current entry
- // if it is a directory or symlink,
- // or next if not
- if (FileSpec::ForEachItemInDirectory(child_path.data(), callback) ==
- eEnumerateDirectoryResultQuit) {
- // The subdirectory returned Quit, which means to
- // stop all directory enumerations at all levels.
- return eEnumerateDirectoryResultQuit;
- }
- break;
-
- case eEnumerateDirectoryResultExit: // Exit from the current directory
- // at the current level.
- // Exit from this directory level and tell parent to
- // keep enumerating.
- return eEnumerateDirectoryResultNext;
-
- case eEnumerateDirectoryResultQuit: // Stop directory enumerations at
- // any level
- return eEnumerateDirectoryResultQuit;
- }
- } while (FindNextFileW(hFind, &ffd) != 0);
-
- FindClose(hFind);
-#else
- std::string dir_string(dir_path);
- lldb_utility::CleanUp<DIR *, int> dir_path_dir(opendir(dir_string.c_str()),
- NULL, closedir);
- if (dir_path_dir.is_valid()) {
- char dir_path_last_char = dir_path.back();
-
- long path_max = fpathconf(dirfd(dir_path_dir.get()), _PC_NAME_MAX);
-#if defined(__APPLE_) && defined(__DARWIN_MAXPATHLEN)
- if (path_max < __DARWIN_MAXPATHLEN)
- path_max = __DARWIN_MAXPATHLEN;
-#endif
- struct dirent *buf, *dp;
- buf = (struct dirent *)malloc(offsetof(struct dirent, d_name) + path_max +
- 1);
-
- while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp) {
- // Only search directories
- if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) {
- size_t len = strlen(dp->d_name);
-
- if (len == 1 && dp->d_name[0] == '.')
- continue;
-
- if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
- continue;
- }
-
- FileSpec::FileType file_type = eFileTypeUnknown;
-
- switch (dp->d_type) {
- default:
- case DT_UNKNOWN:
- file_type = eFileTypeUnknown;
- break;
- case DT_FIFO:
- file_type = eFileTypePipe;
- break;
- case DT_CHR:
- file_type = eFileTypeOther;
- break;
- case DT_DIR:
- file_type = eFileTypeDirectory;
- break;
- case DT_BLK:
- file_type = eFileTypeOther;
- break;
- case DT_REG:
- file_type = eFileTypeRegular;
- break;
- case DT_LNK:
- file_type = eFileTypeSymbolicLink;
- break;
- case DT_SOCK:
- file_type = eFileTypeSocket;
- break;
-#if !defined(__OpenBSD__)
- case DT_WHT:
- file_type = eFileTypeOther;
- break;
-#endif
- }
-
- std::string child_path;
- // Don't make paths with "/foo//bar", that just confuses everybody.
- if (dir_path_last_char == '/')
- child_path = llvm::join_items("", dir_path, dp->d_name);
- else
- child_path = llvm::join_items('/', dir_path, dp->d_name);
-
- // Don't resolve the file type or path
- FileSpec child_path_spec(child_path, false);
-
- EnumerateDirectoryResult result =
- callback(file_type, child_path_spec);
-
- switch (result) {
- case eEnumerateDirectoryResultNext:
- // Enumerate next entry in the current directory. We just
- // exit this switch and will continue enumerating the
- // current directory as we currently are...
- break;
-
- case eEnumerateDirectoryResultEnter: // Recurse into the current entry
- // if it is a directory or
- // symlink, or next if not
- if (FileSpec::ForEachItemInDirectory(child_path, callback) ==
- eEnumerateDirectoryResultQuit) {
- // The subdirectory returned Quit, which means to
- // stop all directory enumerations at all levels.
- if (buf)
- free(buf);
- return eEnumerateDirectoryResultQuit;
- }
- break;
-
- case eEnumerateDirectoryResultExit: // Exit from the current directory
- // at the current level.
- // Exit from this directory level and tell parent to
- // keep enumerating.
- if (buf)
- free(buf);
- return eEnumerateDirectoryResultNext;
-
- case eEnumerateDirectoryResultQuit: // Stop directory enumerations at
- // any level
- if (buf)
- free(buf);
- return eEnumerateDirectoryResultQuit;
- }
- }
- if (buf) {
- free(buf);
- }
- }
-#endif
- // By default when exiting a directory, we tell the parent enumeration
- // to continue enumerating.
- return eEnumerateDirectoryResultNext;
-}
-
-FileSpec::EnumerateDirectoryResult
-FileSpec::EnumerateDirectory(llvm::StringRef dir_path, bool find_directories,
- bool find_files, bool find_other,
- EnumerateDirectoryCallbackType callback,
- void *callback_baton) {
- return ForEachItemInDirectory(
- dir_path,
- [&find_directories, &find_files, &find_other, &callback,
- &callback_baton](FileType file_type, const FileSpec &file_spec) {
- switch (file_type) {
- case FileType::eFileTypeDirectory:
- if (find_directories)
- return callback(callback_baton, file_type, file_spec);
- break;
- case FileType::eFileTypeRegular:
- if (find_files)
- return callback(callback_baton, file_type, file_spec);
- break;
- default:
- if (find_other)
- return callback(callback_baton, file_type, file_spec);
- break;
- }
- return eEnumerateDirectoryResultNext;
- });
}
FileSpec
@@ -1248,6 +785,22 @@ ConstString FileSpec::GetLastPathComponent() const {
return ConstString();
}
+static std::string
+join_path_components(FileSpec::PathSyntax syntax,
+ const std::vector<llvm::StringRef> components) {
+ std::string result;
+ for (size_t i = 0; i < components.size(); ++i) {
+ if (components[i].empty())
+ continue;
+ result += components[i];
+ if (i != components.size() - 1 &&
+ !IsPathSeparator(components[i].back(), syntax))
+ result += GetPreferredPathSeparator(syntax);
+ }
+
+ return result;
+}
+
void FileSpec::PrependPathComponent(llvm::StringRef component) {
if (component.empty())
return;
@@ -1258,17 +811,10 @@ void FileSpec::PrependPathComponent(llvm::StringRef component) {
return;
}
- char sep = GetPreferredPathSeparator(m_syntax);
- std::string result;
- if (m_filename.IsEmpty())
- result = llvm::join_items(sep, component, m_directory.GetStringRef());
- else if (m_directory.IsEmpty())
- result = llvm::join_items(sep, component, m_filename.GetStringRef());
- else
- result = llvm::join_items(sep, component, m_directory.GetStringRef(),
- m_filename.GetStringRef());
-
- SetFile(result, resolve);
+ std::string result =
+ join_path_components(m_syntax, {component, m_directory.GetStringRef(),
+ m_filename.GetStringRef()});
+ SetFile(result, resolve, m_syntax);
}
void FileSpec::PrependPathComponent(const FileSpec &new_path) {
@@ -1279,23 +825,12 @@ void FileSpec::AppendPathComponent(llvm::StringRef component) {
if (component.empty())
return;
- std::string result;
- if (!m_directory.IsEmpty()) {
- result += m_directory.GetStringRef();
- if (!IsPathSeparator(m_directory.GetStringRef().back(), m_syntax))
- result += GetPreferredPathSeparator(m_syntax);
- }
-
- if (!m_filename.IsEmpty()) {
- result += m_filename.GetStringRef();
- if (!IsPathSeparator(m_filename.GetStringRef().back(), m_syntax))
- result += GetPreferredPathSeparator(m_syntax);
- }
-
component = component.drop_while(
[this](char c) { return IsPathSeparator(c, m_syntax); });
- result += component;
+ std::string result =
+ join_path_components(m_syntax, {m_directory.GetStringRef(),
+ m_filename.GetStringRef(), component});
SetFile(result, false, m_syntax);
}
diff --git a/contrib/llvm/tools/lldb/source/Core/History.cpp b/contrib/llvm/tools/lldb/source/Utility/History.cpp
index 0466a83..10344b6 100644
--- a/contrib/llvm/tools/lldb/source/Core/History.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/History.cpp
@@ -7,14 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/History.h"
+#include "lldb/Utility/History.h"
// C Includes
#include <inttypes.h>
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp b/contrib/llvm/tools/lldb/source/Utility/IOObject.cpp
index 6f7de44..df7929c 100644
--- a/contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/IOObject.cpp
@@ -7,8 +7,9 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Host/IOObject.h"
+#include "lldb/Utility/IOObject.h"
using namespace lldb_private;
const IOObject::WaitableHandle IOObject::kInvalidHandleValue = -1;
+IOObject::~IOObject() = default;
diff --git a/contrib/llvm/tools/lldb/source/Utility/JSON.cpp b/contrib/llvm/tools/lldb/source/Utility/JSON.cpp
index 5b809c5..1520bc7 100644
--- a/contrib/llvm/tools/lldb/source/Utility/JSON.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/JSON.cpp
@@ -9,10 +9,15 @@
#include "lldb/Utility/JSON.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
+
+#include <inttypes.h> // for PRIu64, PRId64
#include <limits.h>
+#include <stddef.h> // for size_t
+#include <utility> // for pair
using namespace lldb_private;
@@ -186,7 +191,7 @@ JSONValue::SP JSONArray::GetObject(Index i) {
JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); }
-JSONParser::JSONParser(const char *cstr) : StringExtractor(cstr) {}
+JSONParser::JSONParser(llvm::StringRef data) : StringExtractor(data) {}
JSONParser::Token JSONParser::GetToken(std::string &value) {
StreamString error;
@@ -241,7 +246,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) {
"error: an error occurred getting a character from offset %" PRIu64,
start_index);
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
} else {
const bool is_end_quote = escaped_ch == '"';
@@ -254,13 +259,13 @@ JSONParser::Token JSONParser::GetToken(std::string &value) {
"character 0x%4.4x at offset %" PRIu64,
escaped_ch, start_index);
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
}
} else if (is_end_quote) {
return Token::String;
} else if (is_null) {
value = "error: missing end quote for string";
- return Token::Error;
+ return Token::Status;
}
}
}
@@ -311,7 +316,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) {
error.Printf("error: extra decimal point found at offset %" PRIu64,
start_index);
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
} else {
got_decimal_point = true;
++m_index; // Skip this character
@@ -325,7 +330,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) {
"error: extra exponent character found at offset %" PRIu64,
start_index);
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
} else {
exp_index = m_index;
++m_index; // Skip this character
@@ -341,7 +346,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) {
error.Printf("error: unexpected %c character at offset %" PRIu64,
next_ch, start_index);
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
}
break;
@@ -363,7 +368,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) {
"at offset in float value \"%s\"",
value.c_str());
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
}
} else {
// No exponent, but we need at least one decimal after the decimal
@@ -374,7 +379,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) {
error.Printf("error: no digits after decimal point \"%s\"",
value.c_str());
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
}
}
} else {
@@ -385,14 +390,14 @@ JSONParser::Token JSONParser::GetToken(std::string &value) {
} else {
error.Printf("error: no digits negate sign \"%s\"", value.c_str());
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
}
}
} else {
error.Printf("error: invalid number found at offset %" PRIu64,
start_index);
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
}
} break;
default:
@@ -402,7 +407,7 @@ JSONParser::Token JSONParser::GetToken(std::string &value) {
" (around character '%c')",
start_index, ch);
value = std::move(error.GetString());
- return Token::Error;
+ return Token::Status;
}
int JSONParser::GetEscapedChar(bool &was_escaped) {
@@ -512,23 +517,20 @@ JSONValue::SP JSONParser::ParseJSONValue() {
case JSONParser::Token::Integer: {
if (value.front() == '-') {
- bool success = false;
- int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
- if (success)
+ int64_t sval = 0;
+ if (!llvm::StringRef(value).getAsInteger(0, sval))
return JSONValue::SP(new JSONNumber(sval));
} else {
- bool success = false;
- uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
- if (success)
+ uint64_t uval = 0;
+ if (!llvm::StringRef(value).getAsInteger(0, uval))
return JSONValue::SP(new JSONNumber(uval));
}
} break;
case JSONParser::Token::Float: {
- bool success = false;
- double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
- if (success)
- return JSONValue::SP(new JSONNumber(val));
+ double D;
+ if (!llvm::StringRef(value).getAsDouble(D))
+ return JSONValue::SP(new JSONNumber(D));
} break;
case JSONParser::Token::String:
diff --git a/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp b/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp
index 6f35dcd..48c1b69 100644
--- a/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/LLDBAssert.cpp
@@ -1,5 +1,4 @@
-//===--------------------- LLDBAssert.cpp --------------------------*- C++
-//-*-===//
+//===--------------------- LLDBAssert.cpp ------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/contrib/llvm/tools/lldb/source/Utility/Log.cpp b/contrib/llvm/tools/lldb/source/Utility/Log.cpp
new file mode 100644
index 0000000..a80b106
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/Log.cpp
@@ -0,0 +1,323 @@
+//===-- Log.cpp -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/VASPrintf.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h" // for operator+, Twine
+#include "llvm/ADT/iterator.h" // for iterator_facade_base
+
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/ManagedStatic.h" // for ManagedStatic
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <chrono> // for duration, system_clock, syst...
+#include <cstdarg>
+#include <mutex>
+#include <utility> // for pair
+
+#include <assert.h> // for assert
+#if defined(LLVM_ON_WIN32)
+#include <process.h> // for getpid
+#else
+#include <unistd.h>
+#endif
+
+using namespace lldb_private;
+
+llvm::ManagedStatic<Log::ChannelMap> Log::g_channel_map;
+
+void Log::ListCategories(llvm::raw_ostream &stream, const ChannelMap::value_type &entry) {
+ stream << llvm::formatv("Logging categories for '{0}':\n", entry.first());
+ stream << " all - all available logging categories\n";
+ stream << " default - default set of logging categories\n";
+ for (const auto &category : entry.second.m_channel.categories)
+ stream << llvm::formatv(" {0} - {1}\n", category.name,
+ category.description);
+}
+
+uint32_t Log::GetFlags(llvm::raw_ostream &stream, const ChannelMap::value_type &entry,
+ llvm::ArrayRef<const char *> categories) {
+ bool list_categories = false;
+ uint32_t flags = 0;
+ for (const char *category : categories) {
+ if (llvm::StringRef("all").equals_lower(category)) {
+ flags |= UINT32_MAX;
+ continue;
+ }
+ if (llvm::StringRef("default").equals_lower(category)) {
+ flags |= entry.second.m_channel.default_flags;
+ continue;
+ }
+ auto cat = llvm::find_if(
+ entry.second.m_channel.categories,
+ [&](const Log::Category &c) { return c.name.equals_lower(category); });
+ if (cat != entry.second.m_channel.categories.end()) {
+ flags |= cat->flag;
+ continue;
+ }
+ stream << llvm::formatv("error: unrecognized log category '{0}'\n",
+ category);
+ list_categories = true;
+ }
+ if (list_categories)
+ ListCategories(stream, entry);
+ return flags;
+}
+
+void Log::Enable(const std::shared_ptr<llvm::raw_ostream> &stream_sp,
+ uint32_t options, uint32_t flags) {
+ llvm::sys::ScopedWriter lock(m_mutex);
+
+ uint32_t mask = m_mask.fetch_or(flags, std::memory_order_relaxed);
+ if (mask | flags) {
+ m_options.store(options, std::memory_order_relaxed);
+ m_stream_sp = stream_sp;
+ m_channel.log_ptr.store(this, std::memory_order_relaxed);
+ }
+}
+
+void Log::Disable(uint32_t flags) {
+ llvm::sys::ScopedWriter lock(m_mutex);
+
+ uint32_t mask = m_mask.fetch_and(~flags, std::memory_order_relaxed);
+ if (!(mask & ~flags)) {
+ m_stream_sp.reset();
+ m_channel.log_ptr.store(nullptr, std::memory_order_relaxed);
+ }
+}
+
+const Flags Log::GetOptions() const {
+ return m_options.load(std::memory_order_relaxed);
+}
+
+const Flags Log::GetMask() const {
+ return m_mask.load(std::memory_order_relaxed);
+}
+
+void Log::PutCString(const char *cstr) { Printf("%s", cstr); }
+void Log::PutString(llvm::StringRef str) { PutCString(str.str().c_str()); }
+
+//----------------------------------------------------------------------
+// Simple variable argument logging with flags.
+//----------------------------------------------------------------------
+void Log::Printf(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
+}
+
+//----------------------------------------------------------------------
+// All logging eventually boils down to this function call. If we have
+// a callback registered, then we call the logging callback. If we have
+// a valid file handle, we also log to the file.
+//----------------------------------------------------------------------
+void Log::VAPrintf(const char *format, va_list args) {
+ llvm::SmallString<64> FinalMessage;
+ llvm::raw_svector_ostream Stream(FinalMessage);
+ WriteHeader(Stream, "", "");
+
+ llvm::SmallString<64> Content;
+ lldb_private::VASprintf(Content, format, args);
+
+ Stream << Content << "\n";
+
+ WriteMessage(FinalMessage.str());
+}
+
+//----------------------------------------------------------------------
+// Printing of errors that are not fatal.
+//----------------------------------------------------------------------
+void Log::Error(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ VAError(format, args);
+ va_end(args);
+}
+
+void Log::VAError(const char *format, va_list args) {
+ llvm::SmallString<64> Content;
+ VASprintf(Content, format, args);
+
+ Printf("error: %s", Content.c_str());
+}
+
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal only if verbose mode is
+// enabled.
+//----------------------------------------------------------------------
+void Log::Verbose(const char *format, ...) {
+ if (!GetVerbose())
+ return;
+
+ va_list args;
+ va_start(args, format);
+ VAPrintf(format, args);
+ va_end(args);
+}
+
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal.
+//----------------------------------------------------------------------
+void Log::Warning(const char *format, ...) {
+ llvm::SmallString<64> Content;
+ va_list args;
+ va_start(args, format);
+ VASprintf(Content, format, args);
+ va_end(args);
+
+ Printf("warning: %s", Content.c_str());
+}
+
+void Log::Register(llvm::StringRef name, Channel &channel) {
+ auto iter = g_channel_map->try_emplace(name, channel);
+ assert(iter.second == true);
+ (void)iter;
+}
+
+void Log::Unregister(llvm::StringRef name) {
+ auto iter = g_channel_map->find(name);
+ assert(iter != g_channel_map->end());
+ iter->second.Disable(UINT32_MAX);
+ g_channel_map->erase(iter);
+}
+
+bool Log::EnableLogChannel(
+ const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
+ uint32_t log_options, llvm::StringRef channel,
+ llvm::ArrayRef<const char *> categories, llvm::raw_ostream &error_stream) {
+ auto iter = g_channel_map->find(channel);
+ if (iter == g_channel_map->end()) {
+ error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
+ return false;
+ }
+ uint32_t flags = categories.empty()
+ ? iter->second.m_channel.default_flags
+ : GetFlags(error_stream, *iter, categories);
+ iter->second.Enable(log_stream_sp, log_options, flags);
+ return true;
+}
+
+bool Log::DisableLogChannel(llvm::StringRef channel,
+ llvm::ArrayRef<const char *> categories,
+ llvm::raw_ostream &error_stream) {
+ auto iter = g_channel_map->find(channel);
+ if (iter == g_channel_map->end()) {
+ error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
+ return false;
+ }
+ uint32_t flags = categories.empty()
+ ? UINT32_MAX
+ : GetFlags(error_stream, *iter, categories);
+ iter->second.Disable(flags);
+ return true;
+}
+
+bool Log::ListChannelCategories(llvm::StringRef channel,
+ llvm::raw_ostream &stream) {
+ auto ch = g_channel_map->find(channel);
+ if (ch == g_channel_map->end()) {
+ stream << llvm::formatv("Invalid log channel '{0}'.\n", channel);
+ return false;
+ }
+ ListCategories(stream, *ch);
+ return true;
+}
+
+void Log::DisableAllLogChannels() {
+ for (auto &entry : *g_channel_map)
+ entry.second.Disable(UINT32_MAX);
+}
+
+void Log::ListAllLogChannels(llvm::raw_ostream &stream) {
+ if (g_channel_map->empty()) {
+ stream << "No logging channels are currently registered.\n";
+ return;
+ }
+
+ for (const auto &channel : *g_channel_map)
+ ListCategories(stream, channel);
+}
+
+bool Log::GetVerbose() const {
+ return m_options.load(std::memory_order_relaxed) & LLDB_LOG_OPTION_VERBOSE;
+}
+
+void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
+ llvm::StringRef function) {
+ Flags options = GetOptions();
+ static uint32_t g_sequence_id = 0;
+ // Add a sequence ID if requested
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_SEQUENCE))
+ OS << ++g_sequence_id << " ";
+
+ // Timestamp if requested
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_TIMESTAMP)) {
+ auto now = std::chrono::duration<double>(
+ std::chrono::system_clock::now().time_since_epoch());
+ OS << llvm::formatv("{0:f9} ", now.count());
+ }
+
+ // Add the process and thread if requested
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD))
+ OS << llvm::formatv("[{0,0+4}/{1,0+4}] ", getpid(),
+ llvm::get_threadid());
+
+ // Add the thread name if requested
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_THREAD_NAME)) {
+ llvm::SmallString<32> thread_name;
+ llvm::get_thread_name(thread_name);
+ if (!thread_name.empty())
+ OS << thread_name;
+ }
+
+ if (options.Test(LLDB_LOG_OPTION_BACKTRACE))
+ llvm::sys::PrintStackTrace(OS);
+
+ if (options.Test(LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION) &&
+ (!file.empty() || !function.empty())) {
+ file = llvm::sys::path::filename(file).take_front(40);
+ function = function.take_front(40);
+ OS << llvm::formatv("{0,-60:60} ", (file + ":" + function).str());
+ }
+}
+
+void Log::WriteMessage(const std::string &message) {
+ // Make a copy of our stream shared pointer in case someone disables our
+ // log while we are logging and releases the stream
+ auto stream_sp = GetStream();
+ if (!stream_sp)
+ return;
+
+ Flags options = GetOptions();
+ if (options.Test(LLDB_LOG_OPTION_THREADSAFE)) {
+ static std::recursive_mutex g_LogThreadedMutex;
+ std::lock_guard<std::recursive_mutex> guard(g_LogThreadedMutex);
+ *stream_sp << message;
+ stream_sp->flush();
+ } else {
+ *stream_sp << message;
+ stream_sp->flush();
+ }
+}
+
+void Log::Format(llvm::StringRef file, llvm::StringRef function,
+ const llvm::formatv_object_base &payload) {
+ std::string message_string;
+ llvm::raw_string_ostream message(message_string);
+ WriteHeader(message, file, function);
+ message << payload << "\n";
+ WriteMessage(message.str());
+}
diff --git a/contrib/llvm/tools/lldb/source/Utility/Logging.cpp b/contrib/llvm/tools/lldb/source/Utility/Logging.cpp
new file mode 100644
index 0000000..0bd6d66
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/Logging.cpp
@@ -0,0 +1,74 @@
+//===-- Logging.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Logging.h"
+#include "lldb/Utility/Log.h"
+
+#include "llvm/ADT/ArrayRef.h" // for ArrayRef
+
+#include <stdarg.h> // for va_end, va_list, va_start
+
+using namespace lldb_private;
+
+static constexpr Log::Category g_categories[] = {
+ {{"api"}, {"log API calls and return values"}, LIBLLDB_LOG_API},
+ {{"break"}, {"log breakpoints"}, LIBLLDB_LOG_BREAKPOINTS},
+ {{"commands"}, {"log command argument parsing"}, LIBLLDB_LOG_COMMANDS},
+ {{"comm"}, {"log communication activities"}, LIBLLDB_LOG_COMMUNICATION},
+ {{"conn"}, {"log connection details"}, LIBLLDB_LOG_CONNECTION},
+ {{"demangle"}, {"log mangled names to catch demangler crashes"}, LIBLLDB_LOG_DEMANGLE},
+ {{"dyld"}, {"log shared library related activities"}, LIBLLDB_LOG_DYNAMIC_LOADER},
+ {{"event"}, {"log broadcaster, listener and event queue activities"}, LIBLLDB_LOG_EVENTS},
+ {{"expr"}, {"log expressions"}, LIBLLDB_LOG_EXPRESSIONS},
+ {{"formatters"}, {"log data formatters related activities"}, LIBLLDB_LOG_DATAFORMATTERS},
+ {{"host"}, {"log host activities"}, LIBLLDB_LOG_HOST},
+ {{"jit"}, {"log JIT events in the target"}, LIBLLDB_LOG_JIT_LOADER},
+ {{"language"}, {"log language runtime events"}, LIBLLDB_LOG_LANGUAGE},
+ {{"mmap"}, {"log mmap related activities"}, LIBLLDB_LOG_MMAP},
+ {{"module"}, {"log module activities such as when modules are created, destroyed, replaced, and more"}, LIBLLDB_LOG_MODULES},
+ {{"object"}, {"log object construction/destruction for important objects"}, LIBLLDB_LOG_OBJECT},
+ {{"os"}, {"log OperatingSystem plugin related activities"}, LIBLLDB_LOG_OS},
+ {{"platform"}, {"log platform events and activities"}, LIBLLDB_LOG_PLATFORM},
+ {{"process"}, {"log process events and activities"}, LIBLLDB_LOG_PROCESS},
+ {{"script"}, {"log events about the script interpreter"}, LIBLLDB_LOG_SCRIPT},
+ {{"state"}, {"log private and public process state changes"}, LIBLLDB_LOG_STATE},
+ {{"step"}, {"log step related activities"}, LIBLLDB_LOG_STEP},
+ {{"symbol"}, {"log symbol related issues and warnings"}, LIBLLDB_LOG_SYMBOLS},
+ {{"system-runtime"}, {"log system runtime events"}, LIBLLDB_LOG_SYSTEM_RUNTIME},
+ {{"target"}, {"log target events and activities"}, LIBLLDB_LOG_TARGET},
+ {{"temp"}, {"log internal temporary debug messages"}, LIBLLDB_LOG_TEMPORARY},
+ {{"thread"}, {"log thread events and activities"}, LIBLLDB_LOG_THREAD},
+ {{"types"}, {"log type system related activities"}, LIBLLDB_LOG_TYPES},
+ {{"unwind"}, {"log stack unwind activities"}, LIBLLDB_LOG_UNWIND},
+ {{"watch"}, {"log watchpoint related activities"}, LIBLLDB_LOG_WATCHPOINTS},
+};
+
+static Log::Channel g_log_channel(g_categories, LIBLLDB_LOG_DEFAULT);
+
+void lldb_private::InitializeLog() {
+ Log::Register("lldb", g_log_channel);
+}
+
+Log *lldb_private::GetLogIfAllCategoriesSet(uint32_t mask) {
+ return g_log_channel.GetLogIfAll(mask);
+}
+
+Log *lldb_private::GetLogIfAnyCategoriesSet(uint32_t mask) {
+ return g_log_channel.GetLogIfAny(mask);
+}
+
+
+void lldb_private::LogIfAnyCategoriesSet(uint32_t mask, const char *format, ...) {
+ if (Log *log = GetLogIfAnyCategoriesSet(mask)) {
+ va_list args;
+ va_start(args, format);
+ log->VAPrintf(format, args);
+ va_end(args);
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Utility/NameMatches.cpp b/contrib/llvm/tools/lldb/source/Utility/NameMatches.cpp
index 7b733d2..a76df3f 100644
--- a/contrib/llvm/tools/lldb/source/Utility/NameMatches.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/NameMatches.cpp
@@ -7,38 +7,29 @@
//
//===----------------------------------------------------------------------===//
#include "lldb/Utility/NameMatches.h"
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Utility/RegularExpression.h"
#include "llvm/ADT/StringRef.h"
using namespace lldb_private;
-bool lldb_private::NameMatches(llvm::StringRef name, NameMatchType match_type,
+bool lldb_private::NameMatches(llvm::StringRef name, NameMatch match_type,
llvm::StringRef match) {
- if (match_type == eNameMatchIgnore)
- return true;
-
- if (name == match)
- return true;
-
- if (name.empty() || match.empty())
- return false;
-
switch (match_type) {
- case eNameMatchIgnore: // This case cannot occur: tested before
+ case NameMatch::Ignore:
return true;
- case eNameMatchEquals:
+ case NameMatch::Equals:
return name == match;
- case eNameMatchContains:
+ case NameMatch::Contains:
return name.contains(match);
- case eNameMatchStartsWith:
+ case NameMatch::StartsWith:
return name.startswith(match);
- case eNameMatchEndsWith:
+ case NameMatch::EndsWith:
return name.endswith(match);
- case eNameMatchRegularExpression: {
+ case NameMatch::RegularExpression: {
RegularExpression regex(match);
return regex.Execute(name);
- } break;
+ }
}
return false;
}
diff --git a/contrib/llvm/tools/lldb/source/Utility/Range.cpp b/contrib/llvm/tools/lldb/source/Utility/Range.cpp
index 95f00e5..9d1d28e 100644
--- a/contrib/llvm/tools/lldb/source/Utility/Range.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/Range.cpp
@@ -1,5 +1,4 @@
-//===--------------------- Range.cpp -----------------------------*- C++
-//-*-===//
+//===--------------------- Range.cpp -----------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,6 +9,9 @@
#include "lldb/Utility/Range.h"
+#include <algorithm>
+#include <utility>
+
using namespace lldb_utility;
Range::Range(const Range &rng) : m_low(rng.m_low), m_high(rng.m_high) {
diff --git a/contrib/llvm/tools/lldb/source/Core/RegularExpression.cpp b/contrib/llvm/tools/lldb/source/Utility/RegularExpression.cpp
index 54e0231..d58b315 100644
--- a/contrib/llvm/tools/lldb/source/Core/RegularExpression.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/RegularExpression.cpp
@@ -7,17 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/RegularExpression.h"
+#include "lldb/Utility/RegularExpression.h"
-// C Includes
-// C++ Includes
-#include <cstring>
-
-// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
-// Project includes
-#include "lldb/Core/Error.h"
+#include <string>
//----------------------------------------------------------------------
// Enable enhanced mode if it is available. This allows for things like
@@ -81,14 +75,10 @@ RegularExpression::~RegularExpression() { Free(); }
bool RegularExpression::Compile(llvm::StringRef str) {
Free();
- if (!str.empty()) {
- m_re = str;
- m_comp_err = ::regcomp(&m_preg, m_re.c_str(), DEFAULT_COMPILE_FLAGS);
- } else {
- // No valid regular expression
- m_comp_err = 1;
- }
-
+ // regcomp() on darwin does not recognize "" as a valid regular expression, so
+ // we substitute it with an equivalent non-empty one.
+ m_re = str.empty() ? "()" : str;
+ m_comp_err = ::regcomp(&m_preg, m_re.c_str(), DEFAULT_COMPILE_FLAGS);
return m_comp_err == 0;
}
diff --git a/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp b/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp
index 805bcf2..a46213f 100644
--- a/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/SelectHelper.cpp
@@ -14,7 +14,18 @@
#define _DARWIN_UNLIMITED_SELECT
#endif
-// C Includes
+#include "lldb/Utility/SelectHelper.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-enumerations.h" // for ErrorType::eErrorTypePOSIX
+#include "lldb/lldb-types.h" // for socket_t
+
+#include "llvm/ADT/DenseMap.h" // for DenseMapPair, DenseMap, Dense...
+#include "llvm/ADT/Optional.h" // for Optional
+
+#include <algorithm>
+#include <chrono> // for microseconds, seconds, steady...
+
#include <errno.h>
#if defined(_WIN32)
// Define NOMINMAX to avoid macros that conflict with std::min and std::max
@@ -24,16 +35,6 @@
#include <sys/select.h>
#endif
-// C++ Includes
-#include <algorithm>
-
-// Other libraries and framework includes
-#include "llvm/ADT/SmallVector.h"
-
-// Project includes
-#include "lldb/Core/Error.h"
-#include "lldb/Utility/LLDBAssert.h"
-#include "lldb/Utility/SelectHelper.h"
SelectHelper::SelectHelper()
: m_fd_map(), m_end_time() // Infinite timeout unless
@@ -89,14 +90,14 @@ static void updateMaxFd(llvm::Optional<lldb::socket_t> &vold,
vold = std::max(*vold, vnew);
}
-lldb_private::Error SelectHelper::Select() {
- lldb_private::Error error;
+lldb_private::Status SelectHelper::Select() {
+ lldb_private::Status error;
#ifdef _MSC_VER
// On windows FD_SETSIZE limits the number of file descriptors, not their
// numeric value.
lldbassert(m_fd_map.size() <= FD_SETSIZE);
if (m_fd_map.size() > FD_SETSIZE)
- return lldb_private::Error("Too many file descriptors for select()");
+ return lldb_private::Status("Too many file descriptors for select()");
#endif
llvm::Optional<lldb::socket_t> max_read_fd;
diff --git a/contrib/llvm/tools/lldb/source/Core/Error.cpp b/contrib/llvm/tools/lldb/source/Utility/Status.cpp
index 2369612..b11a3db 100644
--- a/contrib/llvm/tools/lldb/source/Core/Error.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/Status.cpp
@@ -1,4 +1,5 @@
-//===-- Error.cpp -----------------------------------------------*- C++ -*-===//
+//===-- Status.cpp -----------------------------------------------*- C++
+//-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,34 +8,46 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-#ifdef __APPLE__
-#include <mach/mach.h>
-#endif
+#include "lldb/Utility/Status.h"
+
+#include "lldb/Utility/VASPrintf.h"
+#include "lldb/lldb-defines.h" // for LLDB_GENERIC_ERROR
+#include "lldb/lldb-enumerations.h" // for ErrorType, ErrorType::eErr...
+#include "llvm/ADT/SmallString.h" // for SmallString
+#include "llvm/ADT/StringRef.h" // for StringRef
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/FormatProviders.h" // for format_provider
-// C++ Includes
#include <cerrno>
#include <cstdarg>
+#include <string> // for string
+#include <system_error>
+
+#ifdef __APPLE__
+#include <mach/mach.h>
+#endif
-// Other libraries and framework includes
-#include "llvm/ADT/SmallVector.h"
+#include <stdint.h> // for uint32_t
-// Project includes
-#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Host/PosixApi.h"
+namespace llvm {
+class raw_ostream;
+}
using namespace lldb;
using namespace lldb_private;
-Error::Error() : m_code(0), m_type(eErrorTypeInvalid), m_string() {}
+Status::Status() : m_code(0), m_type(eErrorTypeInvalid), m_string() {}
-Error::Error(ValueType err, ErrorType type)
+Status::Status(ValueType err, ErrorType type)
: m_code(err), m_type(type), m_string() {}
-Error::Error(const Error &rhs) = default;
+Status::Status(std::error_code EC)
+ : m_code(EC.value()), m_type(ErrorType::eErrorTypeGeneric),
+ m_string(EC.message()) {}
-Error::Error(const char *format, ...)
+Status::Status(const Status &rhs) = default;
+
+Status::Status(const char *format, ...)
: m_code(0), m_type(eErrorTypeInvalid), m_string() {
va_list args;
va_start(args, format);
@@ -43,10 +56,46 @@ Error::Error(const char *format, ...)
va_end(args);
}
+const Status &Status::operator=(llvm::Error error) {
+ if (!error) {
+ Clear();
+ return *this;
+ }
+
+ // if the error happens to be a errno error, preserve the error code
+ error = llvm::handleErrors(
+ std::move(error), [&](std::unique_ptr<llvm::ECError> e) -> llvm::Error {
+ std::error_code ec = e->convertToErrorCode();
+ if (ec.category() == std::generic_category()) {
+ m_code = ec.value();
+ m_type = ErrorType::eErrorTypePOSIX;
+ return llvm::Error::success();
+ }
+ return llvm::Error(std::move(e));
+ });
+
+ // Otherwise, just preserve the message
+ if (error) {
+ SetErrorToGenericError();
+ SetErrorString(llvm::toString(std::move(error)));
+ }
+
+ return *this;
+}
+
+llvm::Error Status::ToError() const {
+ if (Success())
+ return llvm::Error::success();
+ if (m_type == ErrorType::eErrorTypePOSIX)
+ return llvm::errorCodeToError(std::error_code(m_code, std::generic_category()));
+ return llvm::make_error<llvm::StringError>(AsCString(),
+ llvm::inconvertibleErrorCode());
+}
+
//----------------------------------------------------------------------
// Assignment operator
//----------------------------------------------------------------------
-const Error &Error::operator=(const Error &rhs) {
+const Status &Status::operator=(const Status &rhs) {
if (this != &rhs) {
m_code = rhs.m_code;
m_type = rhs.m_type;
@@ -58,42 +107,40 @@ const Error &Error::operator=(const Error &rhs) {
//----------------------------------------------------------------------
// Assignment operator
//----------------------------------------------------------------------
-const Error &Error::operator=(uint32_t err) {
+const Status &Status::operator=(uint32_t err) {
m_code = err;
m_type = eErrorTypeMachKernel;
m_string.clear();
return *this;
}
-Error::~Error() = default;
+Status::~Status() = default;
//----------------------------------------------------------------------
// Get the error value as a NULL C string. The error string will be
// fetched and cached on demand. The cached error string value will
// remain until the error value is changed or cleared.
//----------------------------------------------------------------------
-const char *Error::AsCString(const char *default_error_str) const {
+const char *Status::AsCString(const char *default_error_str) const {
if (Success())
return nullptr;
if (m_string.empty()) {
- const char *s = nullptr;
switch (m_type) {
case eErrorTypeMachKernel:
#if defined(__APPLE__)
- s = ::mach_error_string(m_code);
+ if (const char *s = ::mach_error_string(m_code))
+ m_string.assign(s);
#endif
break;
case eErrorTypePOSIX:
- s = ::strerror(m_code);
+ m_string = llvm::sys::StrError(m_code);
break;
default:
break;
}
- if (s != nullptr)
- m_string.assign(s);
}
if (m_string.empty()) {
if (default_error_str)
@@ -107,7 +154,7 @@ const char *Error::AsCString(const char *default_error_str) const {
//----------------------------------------------------------------------
// Clear the error and any cached error string that it might contain.
//----------------------------------------------------------------------
-void Error::Clear() {
+void Status::Clear() {
m_code = 0;
m_type = eErrorTypeInvalid;
m_string.clear();
@@ -116,104 +163,38 @@ void Error::Clear() {
//----------------------------------------------------------------------
// Access the error value.
//----------------------------------------------------------------------
-Error::ValueType Error::GetError() const { return m_code; }
+Status::ValueType Status::GetError() const { return m_code; }
//----------------------------------------------------------------------
// Access the error type.
//----------------------------------------------------------------------
-ErrorType Error::GetType() const { return m_type; }
+ErrorType Status::GetType() const { return m_type; }
//----------------------------------------------------------------------
// Returns true if this object contains a value that describes an
// error or otherwise non-success result.
//----------------------------------------------------------------------
-bool Error::Fail() const { return m_code != 0; }
-
-//----------------------------------------------------------------------
-// Log the error given a string with format. If the this object
-// contains an error code, update the error string to contain the
-// "error: " followed by the formatted string, followed by the error
-// value and any string that describes the current error. This
-// allows more context to be given to an error string that remains
-// cached in this object. Logging always occurs even when the error
-// code contains a non-error value.
-//----------------------------------------------------------------------
-void Error::PutToLog(Log *log, const char *format, ...) {
- char *arg_msg = nullptr;
- va_list args;
- va_start(args, format);
- ::vasprintf(&arg_msg, format, args);
- va_end(args);
-
- if (arg_msg != nullptr) {
- if (Fail()) {
- const char *err_str = AsCString();
- if (err_str == nullptr)
- err_str = "???";
-
- SetErrorStringWithFormat("error: %s err = %s (0x%8.8x)", arg_msg, err_str,
- m_code);
- if (log != nullptr)
- log->Error("%s", m_string.c_str());
- } else {
- if (log != nullptr)
- log->Printf("%s err = 0x%8.8x", arg_msg, m_code);
- }
- ::free(arg_msg);
- }
-}
-
-//----------------------------------------------------------------------
-// Log the error given a string with format. If the this object
-// contains an error code, update the error string to contain the
-// "error: " followed by the formatted string, followed by the error
-// value and any string that describes the current error. This
-// allows more context to be given to an error string that remains
-// cached in this object. Logging only occurs even when the error
-// code contains a error value.
-//----------------------------------------------------------------------
-void Error::LogIfError(Log *log, const char *format, ...) {
- if (Fail()) {
- char *arg_msg = nullptr;
- va_list args;
- va_start(args, format);
- ::vasprintf(&arg_msg, format, args);
- va_end(args);
-
- if (arg_msg != nullptr) {
- const char *err_str = AsCString();
- if (err_str == nullptr)
- err_str = "???";
-
- SetErrorStringWithFormat("%s err = %s (0x%8.8x)", arg_msg, err_str,
- m_code);
- if (log != nullptr)
- log->Error("%s", m_string.c_str());
-
- ::free(arg_msg);
- }
- }
-}
+bool Status::Fail() const { return m_code != 0; }
//----------------------------------------------------------------------
// Set accesssor for the error value to "err" and the type to
// "eErrorTypeMachKernel"
//----------------------------------------------------------------------
-void Error::SetMachError(uint32_t err) {
+void Status::SetMachError(uint32_t err) {
m_code = err;
m_type = eErrorTypeMachKernel;
m_string.clear();
}
-void Error::SetExpressionError(lldb::ExpressionResults result,
- const char *mssg) {
+void Status::SetExpressionError(lldb::ExpressionResults result,
+ const char *mssg) {
m_code = result;
m_type = eErrorTypeExpression;
m_string = mssg;
}
-int Error::SetExpressionErrorWithFormat(lldb::ExpressionResults result,
- const char *format, ...) {
+int Status::SetExpressionErrorWithFormat(lldb::ExpressionResults result,
+ const char *format, ...) {
int length = 0;
if (format != nullptr && format[0]) {
@@ -232,7 +213,7 @@ int Error::SetExpressionErrorWithFormat(lldb::ExpressionResults result,
//----------------------------------------------------------------------
// Set accesssor for the error value and type.
//----------------------------------------------------------------------
-void Error::SetError(ValueType err, ErrorType type) {
+void Status::SetError(ValueType err, ErrorType type) {
m_code = err;
m_type = type;
m_string.clear();
@@ -242,7 +223,7 @@ void Error::SetError(ValueType err, ErrorType type) {
// Update the error value to be "errno" and update the type to
// be "POSIX".
//----------------------------------------------------------------------
-void Error::SetErrorToErrno() {
+void Status::SetErrorToErrno() {
m_code = errno;
m_type = eErrorTypePOSIX;
m_string.clear();
@@ -252,7 +233,7 @@ void Error::SetErrorToErrno() {
// Update the error value to be LLDB_GENERIC_ERROR and update the type
// to be "Generic".
//----------------------------------------------------------------------
-void Error::SetErrorToGenericError() {
+void Status::SetErrorToGenericError() {
m_code = LLDB_GENERIC_ERROR;
m_type = eErrorTypeGeneric;
m_string.clear();
@@ -264,7 +245,7 @@ void Error::SetErrorToGenericError() {
// The error string value will remain until the error value is
// cleared or a new error value/type is assigned.
//----------------------------------------------------------------------
-void Error::SetErrorString(llvm::StringRef err_str) {
+void Status::SetErrorString(llvm::StringRef err_str) {
if (!err_str.empty()) {
// If we have an error string, we should always at least have an error
// set to a generic value.
@@ -280,7 +261,7 @@ void Error::SetErrorString(llvm::StringRef err_str) {
/// @param format
/// A printf style format string
//------------------------------------------------------------------
-int Error::SetErrorStringWithFormat(const char *format, ...) {
+int Status::SetErrorStringWithFormat(const char *format, ...) {
if (format != nullptr && format[0]) {
va_list args;
va_start(args, format);
@@ -293,32 +274,17 @@ int Error::SetErrorStringWithFormat(const char *format, ...) {
return 0;
}
-int Error::SetErrorStringWithVarArg(const char *format, va_list args) {
+int Status::SetErrorStringWithVarArg(const char *format, va_list args) {
if (format != nullptr && format[0]) {
// If we have an error string, we should always at least have
// an error set to a generic value.
if (Success())
SetErrorToGenericError();
- // Try and fit our error into a 1024 byte buffer first...
- llvm::SmallVector<char, 1024> buf;
- buf.resize(1024);
- // Copy in case our first call to vsnprintf doesn't fit into our
- // allocated buffer above
- va_list copy_args;
- va_copy(copy_args, args);
- unsigned length = ::vsnprintf(buf.data(), buf.size(), format, args);
- if (length >= buf.size()) {
- // The error formatted string didn't fit into our buffer, resize it
- // to the exact needed size, and retry
- buf.resize(length + 1);
- length = ::vsnprintf(buf.data(), buf.size(), format, copy_args);
- va_end(copy_args);
- assert(length < buf.size());
- }
- m_string.assign(buf.data(), length);
- va_end(args);
- return length;
+ llvm::SmallString<1024> buf;
+ VASprintf(buf, format, args);
+ m_string = buf.str();
+ return buf.size();
} else {
m_string.clear();
}
@@ -329,8 +295,15 @@ int Error::SetErrorStringWithVarArg(const char *format, va_list args) {
// Returns true if the error code in this object is considered a
// successful return value.
//----------------------------------------------------------------------
-bool Error::Success() const { return m_code == 0; }
+bool Status::Success() const { return m_code == 0; }
-bool Error::WasInterrupted() const {
+bool Status::WasInterrupted() const {
return (m_type == eErrorTypePOSIX && m_code == EINTR);
}
+
+void llvm::format_provider<lldb_private::Status>::format(
+ const lldb_private::Status &error, llvm::raw_ostream &OS,
+ llvm::StringRef Options) {
+ llvm::format_provider<llvm::StringRef>::format(error.AsCString(), OS,
+ Options);
+}
diff --git a/contrib/llvm/tools/lldb/source/Core/Stream.cpp b/contrib/llvm/tools/lldb/source/Utility/Stream.cpp
index 2f9c650..04edc25 100644
--- a/contrib/llvm/tools/lldb/source/Core/Stream.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/Stream.cpp
@@ -7,15 +7,16 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/Stream.h"
-#include "lldb/Host/Endian.h"
-#include "lldb/Host/PosixApi.h"
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "lldb/Utility/Stream.h"
+
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/VASPrintf.h"
+#include "llvm/ADT/SmallString.h" // for SmallString
+
+#include <string>
#include <inttypes.h>
+#include <stddef.h>
using namespace lldb;
using namespace lldb_private;
@@ -162,36 +163,14 @@ size_t Stream::Printf(const char *format, ...) {
// Print some formatted output to the stream.
//------------------------------------------------------------------
size_t Stream::PrintfVarArg(const char *format, va_list args) {
- char str[1024];
- va_list args_copy;
+ llvm::SmallString<1024> buf;
+ VASprintf(buf, format, args);
- va_copy(args_copy, args);
-
- size_t bytes_written = 0;
- // Try and format our string into a fixed buffer first and see if it fits
- size_t length = ::vsnprintf(str, sizeof(str), format, args);
- if (length < sizeof(str)) {
- // Include the NULL termination byte for binary output
- if (m_flags.Test(eBinary))
- length += 1;
- // The formatted string fit into our stack based buffer, so we can just
- // append that to our packet
- bytes_written = Write(str, length);
- } else {
- // Our stack buffer wasn't big enough to contain the entire formatted
- // string, so lets let vasprintf create the string for us!
- char *str_ptr = NULL;
- length = ::vasprintf(&str_ptr, format, args_copy);
- if (str_ptr) {
- // Include the NULL termination byte for binary output
- if (m_flags.Test(eBinary))
- length += 1;
- bytes_written = Write(str_ptr, length);
- ::free(str_ptr);
- }
- }
- va_end(args_copy);
- return bytes_written;
+ // Include the NULL termination byte for binary output
+ size_t length = buf.size();
+ if (m_flags.Test(eBinary))
+ ++length;
+ return Write(buf.c_str(), length);
}
//------------------------------------------------------------------
@@ -208,7 +187,8 @@ size_t Stream::Indent(const char *s) {
}
size_t Stream::Indent(llvm::StringRef str) {
- return Printf("%*.*s%s", m_indent_level, m_indent_level, "", str.str().c_str());
+ return Printf("%*.*s%s", m_indent_level, m_indent_level, "",
+ str.str().c_str());
}
//------------------------------------------------------------------
@@ -340,16 +320,6 @@ uint32_t Stream::GetAddressByteSize() const { return m_addr_size; }
void Stream::SetAddressByteSize(uint32_t addr_size) { m_addr_size = addr_size; }
//------------------------------------------------------------------
-// Returns true if the verbose flag bit is set in this stream.
-//------------------------------------------------------------------
-bool Stream::GetVerbose() const { return m_flags.Test(eVerbose); }
-
-//------------------------------------------------------------------
-// Returns true if the debug flag bit is set in this stream.
-//------------------------------------------------------------------
-bool Stream::GetDebug() const { return m_flags.Test(eDebug); }
-
-//------------------------------------------------------------------
// The flags get accessor
//------------------------------------------------------------------
Flags &Stream::GetFlags() { return m_flags; }
@@ -367,40 +337,24 @@ lldb::ByteOrder Stream::GetByteOrder() const { return m_byte_order; }
size_t Stream::PrintfAsRawHex8(const char *format, ...) {
va_list args;
- va_list args_copy;
va_start(args, format);
- va_copy(args_copy, args); // Copy this so we
- char str[1024];
- size_t bytes_written = 0;
- // Try and format our string into a fixed buffer first and see if it fits
- size_t length = ::vsnprintf(str, sizeof(str), format, args);
- if (length < sizeof(str)) {
- // The formatted string fit into our stack based buffer, so we can just
- // append that to our packet
- for (size_t i = 0; i < length; ++i)
- bytes_written += _PutHex8(str[i], false);
- } else {
- // Our stack buffer wasn't big enough to contain the entire formatted
- // string, so lets let vasprintf create the string for us!
- char *str_ptr = NULL;
- length = ::vasprintf(&str_ptr, format, args_copy);
- if (str_ptr) {
- for (size_t i = 0; i < length; ++i)
- bytes_written += _PutHex8(str_ptr[i], false);
- ::free(str_ptr);
- }
- }
+ llvm::SmallString<1024> buf;
+ VASprintf(buf, format, args);
+
+ size_t length = 0;
+ for (char C : buf)
+ length += _PutHex8(C, false);
+
va_end(args);
- va_end(args_copy);
- return bytes_written;
+ return length;
}
size_t Stream::PutNHex8(size_t n, uint8_t uvalue) {
size_t bytes_written = 0;
for (size_t i = 0; i < n; ++i)
- bytes_written += _PutHex8(uvalue, m_flags.Test(eAddPrefix));
+ bytes_written += _PutHex8(uvalue, false);
return bytes_written;
}
@@ -423,23 +377,19 @@ size_t Stream::_PutHex8(uint8_t uvalue, bool add_prefix) {
return bytes_written;
}
-size_t Stream::PutHex8(uint8_t uvalue) {
- return _PutHex8(uvalue, m_flags.Test(eAddPrefix));
-}
+size_t Stream::PutHex8(uint8_t uvalue) { return _PutHex8(uvalue, false); }
size_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) {
if (byte_order == eByteOrderInvalid)
byte_order = m_byte_order;
- bool add_prefix = m_flags.Test(eAddPrefix);
size_t bytes_written = 0;
if (byte_order == eByteOrderLittle) {
- for (size_t byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
- bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
} else {
- for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue);
- --byte, add_prefix = false)
- bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
}
return bytes_written;
}
@@ -448,15 +398,13 @@ size_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) {
if (byte_order == eByteOrderInvalid)
byte_order = m_byte_order;
- bool add_prefix = m_flags.Test(eAddPrefix);
size_t bytes_written = 0;
if (byte_order == eByteOrderLittle) {
- for (size_t byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
- bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
} else {
- for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue);
- --byte, add_prefix = false)
- bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
}
return bytes_written;
}
@@ -465,15 +413,13 @@ size_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) {
if (byte_order == eByteOrderInvalid)
byte_order = m_byte_order;
- bool add_prefix = m_flags.Test(eAddPrefix);
size_t bytes_written = 0;
if (byte_order == eByteOrderLittle) {
- for (size_t byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
- bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
} else {
- for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue);
- --byte, add_prefix = false)
- bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
+ bytes_written += _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
}
return bytes_written;
}
diff --git a/contrib/llvm/tools/lldb/source/Utility/StreamCallback.cpp b/contrib/llvm/tools/lldb/source/Utility/StreamCallback.cpp
new file mode 100644
index 0000000..9752843
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/StreamCallback.cpp
@@ -0,0 +1,23 @@
+//===-- StreamCallback.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/StreamCallback.h"
+
+#include <string>
+
+using namespace lldb_private;
+
+StreamCallback::StreamCallback(lldb::LogOutputCallback callback, void *baton)
+ : llvm::raw_ostream(true), m_callback(callback), m_baton(baton) {}
+
+void StreamCallback::write_impl(const char *Ptr, size_t Size) {
+ m_callback(std::string(Ptr, Size).c_str(), m_baton);
+}
+
+uint64_t StreamCallback::current_pos() const { return 0; }
diff --git a/contrib/llvm/tools/lldb/source/Core/StreamGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Utility/StreamGDBRemote.cpp
index a371d13..2620e37 100644
--- a/contrib/llvm/tools/lldb/source/Core/StreamGDBRemote.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/StreamGDBRemote.cpp
@@ -7,7 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/StreamGDBRemote.h"
+#include "lldb/Utility/StreamGDBRemote.h"
+
+#include "lldb/Utility/Flags.h" // for Flags
+#include "lldb/Utility/Stream.h" // for Stream::::eBinary
+
#include <stdio.h>
using namespace lldb;
diff --git a/contrib/llvm/tools/lldb/source/Core/StreamString.cpp b/contrib/llvm/tools/lldb/source/Utility/StreamString.cpp
index 4616488..75f58de 100644
--- a/contrib/llvm/tools/lldb/source/Core/StreamString.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/StreamString.cpp
@@ -7,8 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/StreamString.h"
-#include <stdio.h>
+#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp b/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp
index d8ba397..cf5c7e2 100644
--- a/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/StringExtractor.cpp
@@ -9,13 +9,11 @@
#include "lldb/Utility/StringExtractor.h"
-// C Includes
-#include <stdlib.h>
-
-// C++ Includes
#include <tuple>
-// Other libraries and framework includes
-// Project includes
+
+#include <ctype.h> // for isxdigit, isspace
+#include <stdlib.h>
+#include <string.h> // for memset
static inline int xdigit_to_sint(char ch) {
if (ch >= 'a' && ch <= 'f')
@@ -282,6 +280,15 @@ uint64_t StringExtractor::GetHexMaxU64(bool little_endian,
return result;
}
+bool StringExtractor::ConsumeFront(const llvm::StringRef &str) {
+ llvm::StringRef S = GetStringRef();
+ if (!S.startswith(str))
+ return false;
+ else
+ m_index += str.size();
+ return true;
+}
+
size_t StringExtractor::GetHexBytes(llvm::MutableArrayRef<uint8_t> dest,
uint8_t fail_fill_value) {
size_t bytes_extracted = 0;
diff --git a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp
index dd13be9..8e50c01 100644
--- a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -7,14 +7,11 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-#include <string.h>
-
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "Utility/StringExtractorGDBRemote.h"
+#include <ctype.h> // for isxdigit
+#include <string.h>
+
StringExtractorGDBRemote::ResponseType
StringExtractorGDBRemote::GetResponseType() const {
if (m_packet.empty())
@@ -22,8 +19,18 @@ StringExtractorGDBRemote::GetResponseType() const {
switch (m_packet[0]) {
case 'E':
- if (m_packet.size() == 3 && isxdigit(m_packet[1]) && isxdigit(m_packet[2]))
- return eError;
+ if (isxdigit(m_packet[1]) && isxdigit(m_packet[2])) {
+ if (m_packet.size() == 3)
+ return eError;
+ llvm::StringRef packet_ref(m_packet);
+ if (packet_ref[3] == ';') {
+ auto err_string = packet_ref.substr(4);
+ for (auto e : err_string)
+ if (!isxdigit(e))
+ return eResponse;
+ return eError;
+ }
+ }
break;
case 'O':
@@ -89,8 +96,14 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_QEnvironment;
if (PACKET_STARTS_WITH("QEnvironmentHexEncoded:"))
return eServerPacketType_QEnvironmentHexEncoded;
+ if (PACKET_STARTS_WITH("QEnableErrorStrings"))
+ return eServerPacketType_QEnableErrorStrings;
break;
+ case 'P':
+ if (PACKET_STARTS_WITH("QPassSignals:"))
+ return eServerPacketType_QPassSignals;
+
case 'S':
if (PACKET_MATCHES("QStartNoAckMode"))
return eServerPacketType_QStartNoAckMode;
@@ -285,6 +298,16 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_jSignalsInfo;
if (PACKET_MATCHES("jThreadsInfo"))
return eServerPacketType_jThreadsInfo;
+ if (PACKET_STARTS_WITH("jTraceBufferRead:"))
+ return eServerPacketType_jTraceBufferRead;
+ if (PACKET_STARTS_WITH("jTraceConfigRead:"))
+ return eServerPacketType_jTraceConfigRead;
+ if (PACKET_STARTS_WITH("jTraceMetaRead:"))
+ return eServerPacketType_jTraceMetaRead;
+ if (PACKET_STARTS_WITH("jTraceStart:"))
+ return eServerPacketType_jTraceStart;
+ if (PACKET_STARTS_WITH("jTraceStop:"))
+ return eServerPacketType_jTraceStop;
break;
case 'v':
@@ -427,8 +450,8 @@ bool StringExtractorGDBRemote::IsNormalResponse() const {
}
bool StringExtractorGDBRemote::IsErrorResponse() const {
- return GetResponseType() == eError && m_packet.size() == 3 &&
- isxdigit(m_packet[1]) && isxdigit(m_packet[2]);
+ return GetResponseType() == eError && isxdigit(m_packet[1]) &&
+ isxdigit(m_packet[2]);
}
uint8_t StringExtractorGDBRemote::GetError() {
@@ -439,6 +462,23 @@ uint8_t StringExtractorGDBRemote::GetError() {
return 0;
}
+lldb_private::Status StringExtractorGDBRemote::GetStatus() {
+ lldb_private::Status error;
+ if (GetResponseType() == eError) {
+ SetFilePos(1);
+ uint8_t errc = GetHexU8(255);
+ error.SetError(errc, lldb::eErrorTypeGeneric);
+
+ error.SetErrorStringWithFormat("Error %u", errc);
+ std::string error_messg;
+ if (GetChar() == ';') {
+ GetHexByteString(error_messg);
+ error.SetErrorString(error_messg);
+ }
+ }
+ return error;
+}
+
size_t StringExtractorGDBRemote::GetEscapedBinaryData(std::string &str) {
// Just get the data bytes in the string as
// GDBRemoteCommunication::CheckForPacket()
diff --git a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h
index ce12660..f4ed642 100644
--- a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h
+++ b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h
@@ -10,12 +10,14 @@
#ifndef utility_StringExtractorGDBRemote_h_
#define utility_StringExtractorGDBRemote_h_
-// C Includes
-// C++ Includes
-#include <string>
-// Other libraries and framework includes
-// Project includes
+#include "lldb/Utility/Status.h"
#include "lldb/Utility/StringExtractor.h"
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <string>
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint8_t
class StringExtractorGDBRemote : public StringExtractor {
public:
@@ -71,6 +73,7 @@ public:
eServerPacketType_qGetWorkingDir,
eServerPacketType_qFileLoadAddress,
eServerPacketType_QEnvironment,
+ eServerPacketType_QEnableErrorStrings,
eServerPacketType_QLaunchArch,
eServerPacketType_QSetDisableASLR,
eServerPacketType_QSetDetachOnError,
@@ -96,6 +99,7 @@ public:
// debug server packages
eServerPacketType_QEnvironmentHexEncoded,
eServerPacketType_QListThreadsInStopReply,
+ eServerPacketType_QPassSignals,
eServerPacketType_QRestoreRegisterState,
eServerPacketType_QSaveRegisterState,
eServerPacketType_QSetLogging,
@@ -162,6 +166,12 @@ public:
eServerPacketType__M,
eServerPacketType__m,
eServerPacketType_notify, // '%' notification
+
+ eServerPacketType_jTraceStart,
+ eServerPacketType_jTraceBufferRead,
+ eServerPacketType_jTraceMetaRead,
+ eServerPacketType_jTraceStop,
+ eServerPacketType_jTraceConfigRead,
};
ServerPacketType GetServerPacketType() const;
@@ -182,6 +192,8 @@ public:
// digits. Otherwise the error encoded in XX is returned.
uint8_t GetError();
+ lldb_private::Status GetStatus();
+
size_t GetEscapedBinaryData(std::string &str);
protected:
diff --git a/contrib/llvm/tools/lldb/source/Utility/StringLexer.cpp b/contrib/llvm/tools/lldb/source/Utility/StringLexer.cpp
index ec18f049..d5c7fc6 100644
--- a/contrib/llvm/tools/lldb/source/Utility/StringLexer.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/StringLexer.cpp
@@ -1,5 +1,4 @@
-//===--------------------- StringLexer.cpp -----------------------*- C++
-//-*-===//
+//===--------------------- StringLexer.cpp -----------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -74,10 +73,6 @@ void StringLexer::PutBack(Size s) {
m_position -= s;
}
-bool StringLexer::HasAny(Character c) {
- return m_data.find(c, m_position) != std::string::npos;
-}
-
std::string StringLexer::GetUnlexed() {
return std::string(m_data, m_position);
}
diff --git a/contrib/llvm/tools/lldb/source/Core/StringList.cpp b/contrib/llvm/tools/lldb/source/Utility/StringList.cpp
index d2c4ac6..190cb9d 100644
--- a/contrib/llvm/tools/lldb/source/Core/StringList.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/StringList.cpp
@@ -7,13 +7,16 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/StringList.h"
+#include "lldb/Utility/StringList.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/ArrayRef.h" // for ArrayRef, makeArrayRef
-#include <string>
+#include <algorithm> // for min
+#include <stdint.h> // for SIZE_MAX, uint32_t
+#include <string.h> // for size_t, strcspn, NULL
using namespace lldb_private;
@@ -65,10 +68,6 @@ void StringList::AppendList(StringList strings) {
m_strings.push_back(strings.GetStringAtIndex(i));
}
-bool StringList::ReadFileLines(FileSpec &input_file) {
- return input_file.ReadFileLines(m_strings);
-}
-
size_t StringList::GetSize() const { return m_strings.size(); }
size_t StringList::GetMaxStringLength() const {
@@ -223,9 +222,7 @@ StringList &StringList::operator<<(StringList strings) {
}
StringList &StringList::operator=(const std::vector<std::string> &rhs) {
- Clear();
- for (const auto &s : rhs)
- m_strings.push_back(s);
+ m_strings.assign(rhs.begin(), rhs.end());
return *this;
}
@@ -267,5 +264,5 @@ void StringList::LogDump(Log *log, const char *name) {
if (name)
strm.Printf("End %s.\n", name);
- log->Debug("%s", strm.GetData());
+ LLDB_LOGV(log, "{0}", strm.GetData());
}
diff --git a/contrib/llvm/tools/lldb/source/Core/StructuredData.cpp b/contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp
index 1e190f5..9fc0535 100644
--- a/contrib/llvm/tools/lldb/source/Core/StructuredData.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/StructuredData.cpp
@@ -7,19 +7,18 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/StructuredData.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-#include "lldb/Core/DataBuffer.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/File.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/StringConvert.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/JSON.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h" // for Stream
+#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/STLExtras.h" // for make_unique
+#include <cerrno>
+#include <cstdlib>
+#include <inttypes.h>
+#include <limits> // for numeric_limits
using namespace lldb_private;
@@ -31,49 +30,31 @@ static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
StructuredData::ObjectSP
-StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Error &error) {
+StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
StructuredData::ObjectSP return_sp;
if (!input_spec.Exists()) {
- error.SetErrorStringWithFormat("input file %s does not exist.",
- input_spec.GetPath().c_str());
+ error.SetErrorStringWithFormatv("input file {0} does not exist.",
+ input_spec);
return return_sp;
}
- File input_file(nullptr, File::OpenOptions::eOpenOptionRead,
- lldb::eFilePermissionsUserRead);
- std::string input_path = input_spec.GetPath();
- error =
- input_file.Open(input_path.c_str(), File::OpenOptions::eOpenOptionRead,
- lldb::eFilePermissionsUserRead);
-
- if (!error.Success()) {
- error.SetErrorStringWithFormat("could not open input file: %s - %s.",
- input_spec.GetPath().c_str(),
- error.AsCString());
+ auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
+ if (!buffer_or_error) {
+ error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.",
+ input_spec.GetPath(),
+ buffer_or_error.getError().message());
return return_sp;
}
- lldb::DataBufferSP input_data;
- size_t num_bytes = std::numeric_limits<size_t>::max();
- off_t offset = 0;
- error = input_file.Read(num_bytes, offset, true, input_data);
- if (!error.Success()) {
- error.SetErrorStringWithFormat("could not read input file: %s - %s.",
- input_spec.GetPath().c_str(),
- error.AsCString());
- return return_sp;
- }
- JSONParser json_parser((char *)input_data->GetBytes());
+ JSONParser json_parser(buffer_or_error.get()->getBuffer());
return_sp = ParseJSONValue(json_parser);
return return_sp;
}
static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
// The "JSONParser::Token::ObjectStart" token should have already been
- // consumed
- // by the time this function is called
- std::unique_ptr<StructuredData::Dictionary> dict_up(
- new StructuredData::Dictionary());
+ // consumed by the time this function is called
+ auto dict_up = llvm::make_unique<StructuredData::Dictionary>();
std::string value;
std::string key;
@@ -105,7 +86,7 @@ static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
// The "JSONParser::Token::ObjectStart" token should have already been
// consumed
// by the time this function is called
- std::unique_ptr<StructuredData::Array> array_up(new StructuredData::Array());
+ auto array_up = llvm::make_unique<StructuredData::Array>();
std::string value;
std::string key;
@@ -139,29 +120,27 @@ static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
return ParseJSONArray(json_parser);
case JSONParser::Token::Integer: {
- bool success = false;
- uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
- if (success)
- return StructuredData::ObjectSP(new StructuredData::Integer(uval));
+ uint64_t uval;
+ if (llvm::to_integer(value, uval, 0))
+ return std::make_shared<StructuredData::Integer>(uval);
} break;
case JSONParser::Token::Float: {
- bool success = false;
- double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
- if (success)
- return StructuredData::ObjectSP(new StructuredData::Float(val));
+ double val;
+ if (llvm::to_float(value, val))
+ return std::make_shared<StructuredData::Float>(val);
} break;
case JSONParser::Token::String:
- return StructuredData::ObjectSP(new StructuredData::String(value));
+ return std::make_shared<StructuredData::String>(value);
case JSONParser::Token::True:
case JSONParser::Token::False:
- return StructuredData::ObjectSP(
- new StructuredData::Boolean(token == JSONParser::Token::True));
+ return std::make_shared<StructuredData::Boolean>(token ==
+ JSONParser::Token::True);
case JSONParser::Token::Null:
- return StructuredData::ObjectSP(new StructuredData::Null());
+ return std::make_shared<StructuredData::Null>();
default:
break;
@@ -177,7 +156,7 @@ StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
StructuredData::ObjectSP
StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
- if (this->GetType() == Type::eTypeDictionary) {
+ if (this->GetType() == lldb::eStructuredDataTypeDictionary) {
std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
std::string key = match.first.str();
ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
@@ -193,7 +172,7 @@ StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
return ObjectSP();
}
- if (this->GetType() == Type::eTypeArray) {
+ if (this->GetType() == lldb::eStructuredDataTypeArray) {
std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
if (match.second.size() == 0) {
return this->shared_from_this();
@@ -212,7 +191,7 @@ StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
void StructuredData::Object::DumpToStdout(bool pretty_print) const {
StreamString stream;
Dump(stream, pretty_print);
- printf("%s\n", stream.GetData());
+ llvm::outs() << stream.GetString();
}
void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
diff --git a/contrib/llvm/tools/lldb/source/Utility/TaskPool.cpp b/contrib/llvm/tools/lldb/source/Utility/TaskPool.cpp
index f66f7bf..d33f23c 100644
--- a/contrib/llvm/tools/lldb/source/Utility/TaskPool.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/TaskPool.cpp
@@ -9,6 +9,10 @@
#include "lldb/Utility/TaskPool.h"
+#include <cstdint> // for uint32_t
+#include <queue> // for queue
+#include <thread> // for thread
+
namespace {
class TaskPoolImpl {
public:
@@ -69,3 +73,26 @@ void TaskPoolImpl::Worker(TaskPoolImpl *pool) {
f();
}
}
+
+void TaskMapOverInt(size_t begin, size_t end,
+ const llvm::function_ref<void(size_t)> &func) {
+ std::atomic<size_t> idx{begin};
+ size_t num_workers =
+ std::min<size_t>(end, std::thread::hardware_concurrency());
+
+ auto wrapper = [&idx, end, &func]() {
+ while (true) {
+ size_t i = idx.fetch_add(1);
+ if (i >= end)
+ break;
+ func(i);
+ }
+ };
+
+ std::vector<std::future<void>> futures;
+ futures.reserve(num_workers);
+ for (size_t i = 0; i < num_workers; i++)
+ futures.push_back(TaskPool::AddTask(wrapper));
+ for (size_t i = 0; i < num_workers; i++)
+ futures[i].wait();
+}
diff --git a/contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp b/contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp
new file mode 100644
index 0000000..64a7711
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/TildeExpressionResolver.cpp
@@ -0,0 +1,95 @@
+//===--------------------- TildeExpressionResolver.cpp ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/TildeExpressionResolver.h"
+
+#include <assert.h> // for assert
+#include <system_error> // for error_code
+
+#include "llvm/ADT/STLExtras.h" // for any_of
+#include "llvm/ADT/SmallVector.h" // for SmallVectorImpl
+#include "llvm/Config/llvm-config.h" // for LLVM_ON_WIN32
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h" // for fs
+
+#if !defined(LLVM_ON_WIN32)
+#include <pwd.h>
+#endif
+
+using namespace lldb_private;
+using namespace llvm;
+
+namespace fs = llvm::sys::fs;
+namespace path = llvm::sys::path;
+
+TildeExpressionResolver::~TildeExpressionResolver() {}
+
+bool StandardTildeExpressionResolver::ResolveExact(
+ StringRef Expr, SmallVectorImpl<char> &Output) {
+ // We expect the tilde expression to be ONLY the expression itself, and
+ // contain no separators.
+ assert(!llvm::any_of(Expr, [](char c) { return path::is_separator(c); }));
+ assert(Expr.empty() || Expr[0] == '~');
+
+ return !fs::real_path(Expr, Output, true);
+}
+
+bool StandardTildeExpressionResolver::ResolvePartial(StringRef Expr,
+ StringSet<> &Output) {
+ // We expect the tilde expression to be ONLY the expression itself, and
+ // contain no separators.
+ assert(!llvm::any_of(Expr, [](char c) { return path::is_separator(c); }));
+ assert(Expr.empty() || Expr[0] == '~');
+
+ Output.clear();
+#if defined(LLVM_ON_WIN32) || defined(__ANDROID__)
+ return false;
+#else
+ if (Expr.empty())
+ return false;
+
+ SmallString<32> Buffer("~");
+ setpwent();
+ struct passwd *user_entry;
+ Expr = Expr.drop_front();
+
+ while ((user_entry = getpwent()) != NULL) {
+ StringRef ThisName(user_entry->pw_name);
+ if (!ThisName.startswith(Expr))
+ continue;
+
+ Buffer.resize(1);
+ Buffer.append(ThisName);
+ Buffer.append(path::get_separator());
+ Output.insert(Buffer);
+ }
+
+ return true;
+#endif
+}
+
+bool TildeExpressionResolver::ResolveFullPath(
+ StringRef Expr, llvm::SmallVectorImpl<char> &Output) {
+ Output.clear();
+ if (!Expr.startswith("~")) {
+ Output.append(Expr.begin(), Expr.end());
+ return false;
+ }
+
+ namespace path = llvm::sys::path;
+ StringRef Left =
+ Expr.take_until([](char c) { return path::is_separator(c); });
+
+ if (!ResolveExact(Left, Output))
+ return false;
+
+ Output.append(Expr.begin() + Left.size(), Expr.end());
+ return true;
+}
diff --git a/contrib/llvm/tools/lldb/source/Utility/Timer.cpp b/contrib/llvm/tools/lldb/source/Utility/Timer.cpp
new file mode 100644
index 0000000..fe77874
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/Timer.cpp
@@ -0,0 +1,132 @@
+//===-- Timer.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "lldb/Utility/Timer.h"
+#include "lldb/Utility/Stream.h"
+
+#include <algorithm>
+#include <map>
+#include <mutex>
+#include <utility> // for pair
+#include <vector>
+
+#include <assert.h> // for assert
+#include <stdarg.h> // for va_end, va_list, va_start
+#include <stdio.h>
+
+using namespace lldb_private;
+
+#define TIMER_INDENT_AMOUNT 2
+
+namespace {
+typedef std::vector<Timer *> TimerStack;
+static std::atomic<Timer::Category *> g_categories;
+} // end of anonymous namespace
+
+std::atomic<bool> Timer::g_quiet(true);
+std::atomic<unsigned> Timer::g_display_depth(0);
+static std::mutex &GetFileMutex() {
+ static std::mutex *g_file_mutex_ptr = new std::mutex();
+ return *g_file_mutex_ptr;
+}
+
+static TimerStack &GetTimerStackForCurrentThread() {
+ static thread_local TimerStack g_stack;
+ return g_stack;
+}
+
+Timer::Category::Category(const char *cat) : m_name(cat) {
+ m_nanos.store(0, std::memory_order_release);
+ Category *expected = g_categories;
+ do {
+ m_next = expected;
+ } while (!g_categories.compare_exchange_weak(expected, this));
+}
+
+void Timer::SetQuiet(bool value) { g_quiet = value; }
+
+Timer::Timer(Timer::Category &category, const char *format, ...)
+ : m_category(category), m_total_start(std::chrono::steady_clock::now()) {
+ TimerStack &stack = GetTimerStackForCurrentThread();
+
+ stack.push_back(this);
+ if (g_quiet && stack.size() <= g_display_depth) {
+ std::lock_guard<std::mutex> lock(GetFileMutex());
+
+ // Indent
+ ::fprintf(stdout, "%*s", int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "");
+ // Print formatted string
+ va_list args;
+ va_start(args, format);
+ ::vfprintf(stdout, format, args);
+ va_end(args);
+
+ // Newline
+ ::fprintf(stdout, "\n");
+ }
+}
+
+Timer::~Timer() {
+ using namespace std::chrono;
+
+ auto stop_time = steady_clock::now();
+ auto total_dur = stop_time - m_total_start;
+ auto timer_dur = total_dur - m_child_duration;
+
+ TimerStack &stack = GetTimerStackForCurrentThread();
+ if (g_quiet && stack.size() <= g_display_depth) {
+ std::lock_guard<std::mutex> lock(GetFileMutex());
+ ::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n",
+ int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "",
+ duration<double>(total_dur).count(),
+ duration<double>(timer_dur).count());
+ }
+
+ assert(stack.back() == this);
+ stack.pop_back();
+ if (!stack.empty())
+ stack.back()->ChildDuration(total_dur);
+
+ // Keep total results for each category so we can dump results.
+ m_category.m_nanos += std::chrono::nanoseconds(timer_dur).count();
+}
+
+void Timer::SetDisplayDepth(uint32_t depth) { g_display_depth = depth; }
+
+/* binary function predicate:
+ * - returns whether a person is less than another person
+ */
+
+typedef std::pair<const char *, uint64_t> TimerEntry;
+
+static bool CategoryMapIteratorSortCriterion(const TimerEntry &lhs,
+ const TimerEntry &rhs) {
+ return lhs.second > rhs.second;
+}
+
+void Timer::ResetCategoryTimes() {
+ for (Category *i = g_categories; i; i = i->m_next)
+ i->m_nanos.store(0, std::memory_order_release);
+}
+
+void Timer::DumpCategoryTimes(Stream *s) {
+ std::vector<TimerEntry> sorted;
+ for (Category *i = g_categories; i; i = i->m_next) {
+ uint64_t nanos = i->m_nanos.load(std::memory_order_acquire);
+ if (nanos)
+ sorted.push_back(std::make_pair(i->m_name, nanos));
+ }
+ if (sorted.empty())
+ return; // Later code will break without any elements.
+
+ // Sort by time
+ std::sort(sorted.begin(), sorted.end(), CategoryMapIteratorSortCriterion);
+
+ for (const auto &timer : sorted)
+ s->Printf("%.9f sec for %s\n", timer.second / 1000000000., timer.first);
+}
diff --git a/contrib/llvm/tools/lldb/source/Core/UUID.cpp b/contrib/llvm/tools/lldb/source/Utility/UUID.cpp
index a08a748..b47f8b5 100644
--- a/contrib/llvm/tools/lldb/source/Core/UUID.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/UUID.cpp
@@ -7,19 +7,18 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/UUID.h"
+#include "lldb/Utility/UUID.h"
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/StringRef.h"
+
// C Includes
#include <ctype.h>
#include <stdio.h>
#include <string.h>
-// C++ Includes
-#include <string>
-
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Core/Stream.h"
-
namespace lldb_private {
UUID::UUID() : m_num_uuid_bytes(16) { ::memset(m_uuid, 0, sizeof(m_uuid)); }
@@ -161,12 +160,9 @@ llvm::StringRef UUID::DecodeUUIDBytesFromString(llvm::StringRef p,
bytes_decoded = uuid_byte_idx;
return p;
}
-size_t UUID::SetFromCString(const char *cstr, uint32_t num_uuid_bytes) {
- if (cstr == NULL)
- return 0;
- llvm::StringRef orig(cstr);
- llvm::StringRef p = orig;
+size_t UUID::SetFromStringRef(llvm::StringRef str, uint32_t num_uuid_bytes) {
+ llvm::StringRef p = str;
// Skip leading whitespace characters
p = p.ltrim();
@@ -179,12 +175,19 @@ size_t UUID::SetFromCString(const char *cstr, uint32_t num_uuid_bytes) {
// were consumed
if (bytes_decoded == num_uuid_bytes) {
m_num_uuid_bytes = num_uuid_bytes;
- return orig.size() - rest.size();
+ return str.size() - rest.size();
}
// Else return zero to indicate we were not able to parse a UUID value
return 0;
}
+
+size_t UUID::SetFromCString(const char *cstr, uint32_t num_uuid_bytes) {
+ if (cstr == NULL)
+ return 0;
+
+ return SetFromStringRef(cstr, num_uuid_bytes);
+}
}
bool lldb_private::operator==(const lldb_private::UUID &lhs,
diff --git a/contrib/llvm/tools/lldb/source/Utility/UriParser.cpp b/contrib/llvm/tools/lldb/source/Utility/UriParser.cpp
index a1d6e4c..bb57211 100644
--- a/contrib/llvm/tools/lldb/source/Utility/UriParser.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/UriParser.cpp
@@ -7,16 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#include "Utility/UriParser.h"
+#include "lldb/Utility/UriParser.h"
-// C Includes
+#include <string>
-// C++ Includes
-#include <cstring>
-
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Host/StringConvert.h"
+#include <stdint.h>
+#include <tuple>
using namespace lldb_private;
diff --git a/contrib/llvm/tools/lldb/source/Core/UserID.cpp b/contrib/llvm/tools/lldb/source/Utility/UserID.cpp
index 5446154..e65b8fa 100644
--- a/contrib/llvm/tools/lldb/source/Core/UserID.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/UserID.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/UserID.h"
-#include "lldb/Core/Stream.h"
+#include "lldb/Utility/UserID.h"
+#include "lldb/Utility/Stream.h"
#include <inttypes.h>
diff --git a/contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp b/contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp
new file mode 100644
index 0000000..e950fb7
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/VASprintf.cpp
@@ -0,0 +1,56 @@
+//===-- VASPrintf.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/VASPrintf.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h" // for SmallVectorImpl
+#include "llvm/ADT/StringRef.h" // for StringRef
+
+#include <assert.h> // for assert
+#include <stdarg.h> // for va_end, va_list, va_copy
+#include <stdio.h> // for vsnprintf, size_t
+
+bool lldb_private::VASprintf(llvm::SmallVectorImpl<char> &buf, const char *fmt,
+ va_list args) {
+ llvm::SmallString<16> error("<Encoding error>");
+ bool result = true;
+
+ // Copy in case our first call to vsnprintf doesn't fit into our buffer
+ va_list copy_args;
+ va_copy(copy_args, args);
+
+ buf.resize(buf.capacity());
+ // Write up to `capacity` bytes, ignoring the current size.
+ int length = ::vsnprintf(buf.data(), buf.size(), fmt, args);
+ if (length < 0) {
+ buf = error;
+ result = false;
+ goto finish;
+ }
+
+ if (size_t(length) >= buf.size()) {
+ // The error formatted string didn't fit into our buffer, resize it
+ // to the exact needed size, and retry
+ buf.resize(length + 1);
+ length = ::vsnprintf(buf.data(), buf.size(), fmt, copy_args);
+ if (length < 0) {
+ buf = error;
+ result = false;
+ goto finish;
+ }
+ assert(size_t(length) < buf.size());
+ }
+ buf.resize(length);
+
+finish:
+ va_end(args);
+ va_end(copy_args);
+ return result;
+}
diff --git a/contrib/llvm/tools/lldb/source/Core/VMRange.cpp b/contrib/llvm/tools/lldb/source/Utility/VMRange.cpp
index 8d21f4b..105b1a5 100644
--- a/contrib/llvm/tools/lldb/source/Core/VMRange.cpp
+++ b/contrib/llvm/tools/lldb/source/Utility/VMRange.cpp
@@ -7,11 +7,17 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-private.h"
+#include "lldb/Utility/VMRange.h"
+
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-types.h" // for addr_t
-#include "lldb/Core/Stream.h"
-#include "lldb/Core/VMRange.h"
#include <algorithm>
+#include <iterator> // for distance
+#include <vector> // for const_iterator
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for UINT32_MAX, uint32_t
using namespace lldb;
using namespace lldb_private;
@@ -19,34 +25,13 @@ using namespace lldb_private;
bool VMRange::ContainsValue(const VMRange::collection &coll,
lldb::addr_t value) {
ValueInRangeUnaryPredicate in_range_predicate(value);
- VMRange::const_iterator pos;
- VMRange::const_iterator end = coll.end();
- pos = std::find_if(coll.begin(), end, in_range_predicate);
- if (pos != end)
- return true;
- return false;
+ return llvm::find_if(coll, in_range_predicate) != coll.end();
}
bool VMRange::ContainsRange(const VMRange::collection &coll,
const VMRange &range) {
RangeInRangeUnaryPredicate in_range_predicate(range);
- VMRange::const_iterator pos;
- VMRange::const_iterator end = coll.end();
- pos = std::find_if(coll.begin(), end, in_range_predicate);
- if (pos != end)
- return true;
- return false;
-}
-
-size_t VMRange::FindRangeIndexThatContainsValue(const VMRange::collection &coll,
- lldb::addr_t value) {
- ValueInRangeUnaryPredicate in_range_predicate(value);
- VMRange::const_iterator begin = coll.begin();
- VMRange::const_iterator end = coll.end();
- VMRange::const_iterator pos = std::find_if(begin, end, in_range_predicate);
- if (pos != end)
- return std::distance(begin, pos);
- return UINT32_MAX;
+ return llvm::find_if(coll, in_range_predicate) != coll.end();
}
void VMRange::Dump(Stream *s, lldb::addr_t offset, uint32_t addr_width) const {
@@ -60,8 +45,7 @@ bool lldb_private::operator==(const VMRange &lhs, const VMRange &rhs) {
}
bool lldb_private::operator!=(const VMRange &lhs, const VMRange &rhs) {
- return lhs.GetBaseAddress() != rhs.GetBaseAddress() ||
- lhs.GetEndAddress() != rhs.GetEndAddress();
+ return !(lhs == rhs);
}
bool lldb_private::operator<(const VMRange &lhs, const VMRange &rhs) {
@@ -73,25 +57,13 @@ bool lldb_private::operator<(const VMRange &lhs, const VMRange &rhs) {
}
bool lldb_private::operator<=(const VMRange &lhs, const VMRange &rhs) {
- if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
- return true;
- else if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
- return false;
- return lhs.GetEndAddress() <= rhs.GetEndAddress();
+ return !(lhs > rhs);
}
bool lldb_private::operator>(const VMRange &lhs, const VMRange &rhs) {
- if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
- return true;
- else if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
- return false;
- return lhs.GetEndAddress() > rhs.GetEndAddress();
+ return rhs < lhs;
}
bool lldb_private::operator>=(const VMRange &lhs, const VMRange &rhs) {
- if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
- return true;
- else if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
- return false;
- return lhs.GetEndAddress() >= rhs.GetEndAddress();
+ return !(lhs < rhs);
}
diff --git a/contrib/llvm/tools/lldb/tools/argdumper/argdumper.cpp b/contrib/llvm/tools/lldb/tools/argdumper/argdumper.cpp
index 01a070e..67fd309 100644
--- a/contrib/llvm/tools/lldb/tools/argdumper/argdumper.cpp
+++ b/contrib/llvm/tools/lldb/tools/argdumper/argdumper.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Core/StreamString.h"
#include "lldb/Utility/JSON.h"
+#include "lldb/Utility/StreamString.h"
#include <iostream>
diff --git a/contrib/llvm/tools/lldb/tools/driver/Driver.cpp b/contrib/llvm/tools/lldb/tools/driver/Driver.cpp
index 8e226a9..102ba77 100644
--- a/contrib/llvm/tools/lldb/tools/driver/Driver.cpp
+++ b/contrib/llvm/tools/lldb/tools/driver/Driver.cpp
@@ -9,6 +9,7 @@
#include "Driver.h"
+#include <csignal>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
diff --git a/contrib/llvm/tools/lldb/tools/driver/Driver.h b/contrib/llvm/tools/lldb/tools/driver/Driver.h
index e6cff51..2be697c 100644
--- a/contrib/llvm/tools/lldb/tools/driver/Driver.h
+++ b/contrib/llvm/tools/lldb/tools/driver/Driver.h
@@ -11,7 +11,7 @@
#define lldb_Driver_h_
#include "Platform.h"
-#include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Host/PseudoTerminal.h"
#include <bitset>
#include <set>
diff --git a/contrib/llvm/tools/lldb/tools/driver/Platform.h b/contrib/llvm/tools/lldb/tools/driver/Platform.h
index 3af2e19..521c5a1 100644
--- a/contrib/llvm/tools/lldb/tools/driver/Platform.h
+++ b/contrib/llvm/tools/lldb/tools/driver/Platform.h
@@ -15,7 +15,6 @@
#include "lldb/Host/HostGetOpt.h"
#include <io.h>
#if defined(_MSC_VER)
-#include <eh.h>
#include <signal.h>
#endif
#include "lldb/Host/windows/windows.h"
diff --git a/contrib/llvm/tools/lldb/tools/intel-mpx/IntelMPXTablePlugin.cpp b/contrib/llvm/tools/lldb/tools/intel-mpx/IntelMPXTablePlugin.cpp
new file mode 100644
index 0000000..0f86ce6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/tools/intel-mpx/IntelMPXTablePlugin.cpp
@@ -0,0 +1,427 @@
+//===-- IntelMPXTablePlugin.cpp----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C++ includes
+#include <cerrno>
+#include <string>
+
+// Project includes
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBMemoryRegionInfo.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBThread.h"
+
+#include "llvm/ADT/Triple.h"
+
+namespace lldb {
+bool PluginInitialize(lldb::SBDebugger debugger);
+}
+
+static bool GetPtr(char *cptr, uint64_t &ptr, lldb::SBFrame &frame,
+ lldb::SBCommandReturnObject &result) {
+ if (!cptr) {
+ result.SetError("Bad argument.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::SBValue ptr_addr = frame.GetValueForVariablePath(cptr);
+ if (!ptr_addr.IsValid()) {
+ result.SetError("Invalid pointer.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ ptr = ptr_addr.GetLoadAddress();
+ return true;
+}
+
+enum {
+ mpx_base_mask_64 = ~(uint64_t)0xFFFULL,
+ mpx_bd_mask_64 = 0xFFFFFFF00000ULL,
+ bd_r_shift_64 = 20,
+ bd_l_shift_64 = 3,
+ bt_r_shift_64 = 3,
+ bt_l_shift_64 = 5,
+ bt_mask_64 = 0x0000000FFFF8ULL,
+
+ mpx_base_mask_32 = 0xFFFFFFFFFFFFF000ULL,
+ mpx_bd_mask_32 = 0xFFFFF000ULL,
+ bd_r_shift_32 = 12,
+ bd_l_shift_32 = 2,
+ bt_r_shift_32 = 2,
+ bt_l_shift_32 = 4,
+ bt_mask_32 = 0x00000FFCULL,
+};
+
+static void PrintBTEntry(lldb::addr_t lbound, lldb::addr_t ubound,
+ uint64_t value, uint64_t meta,
+ lldb::SBCommandReturnObject &result) {
+ const lldb::addr_t one_cmpl64 = ~((lldb::addr_t)0);
+ const lldb::addr_t one_cmpl32 = ~((uint32_t)0);
+
+ if ((lbound == one_cmpl64 || one_cmpl32) && ubound == 0) {
+ result.Printf("Null bounds on map: pointer value = 0x%lx\n", value);
+ } else {
+ result.Printf(" lbound = 0x%lx,", lbound);
+ result.Printf(" ubound = 0x%lx", ubound);
+ result.Printf(" (pointer value = 0x%lx,", value);
+ result.Printf(" metadata = 0x%lx)\n", meta);
+ }
+}
+
+static bool GetBTEntryAddr(uint64_t bndcfgu, uint64_t ptr,
+ lldb::SBTarget &target, llvm::Triple::ArchType arch,
+ size_t &size, lldb::addr_t &bt_entry_addr,
+ lldb::SBCommandReturnObject &result,
+ lldb::SBError &error) {
+ lldb::addr_t mpx_base_mask;
+ lldb::addr_t mpx_bd_mask;
+ lldb::addr_t bd_r_shift;
+ lldb::addr_t bd_l_shift;
+ lldb::addr_t bt_r_shift;
+ lldb::addr_t bt_l_shift;
+ lldb::addr_t bt_mask;
+
+ if (arch == llvm::Triple::ArchType::x86_64) {
+ mpx_base_mask = mpx_base_mask_64;
+ mpx_bd_mask = mpx_bd_mask_64;
+ bd_r_shift = bd_r_shift_64;
+ bd_l_shift = bd_l_shift_64;
+ bt_r_shift = bt_r_shift_64;
+ bt_l_shift = bt_l_shift_64;
+ bt_mask = bt_mask_64;
+ } else if (arch == llvm::Triple::ArchType::x86) {
+ mpx_base_mask = mpx_base_mask_32;
+ mpx_bd_mask = mpx_bd_mask_32;
+ bd_r_shift = bd_r_shift_32;
+ bd_l_shift = bd_l_shift_32;
+ bt_r_shift = bt_r_shift_32;
+ bt_l_shift = bt_l_shift_32;
+ bt_mask = bt_mask_32;
+ } else {
+ result.SetError("Invalid arch.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ size = target.GetAddressByteSize();
+ lldb::addr_t mpx_bd_base = bndcfgu & mpx_base_mask;
+ lldb::addr_t bd_entry_offset = ((ptr & mpx_bd_mask) >> bd_r_shift)
+ << bd_l_shift;
+ lldb::addr_t bd_entry_addr = mpx_bd_base + bd_entry_offset;
+
+ std::vector<uint8_t> bd_entry_v(size);
+ size_t ret = target.GetProcess().ReadMemory(
+ bd_entry_addr, static_cast<void *>(bd_entry_v.data()), size, error);
+ if (ret != size || !error.Success()) {
+ result.SetError("Failed access to BD entry.");
+ return false;
+ }
+
+ lldb::SBData data;
+ data.SetData(error, bd_entry_v.data(), bd_entry_v.size(),
+ target.GetByteOrder(), size);
+ lldb::addr_t bd_entry = data.GetAddress(error, 0);
+
+ if (!error.Success()) {
+ result.SetError("Failed access to BD entry.");
+ return false;
+ }
+
+ if ((bd_entry & 0x01) == 0) {
+ result.SetError("Invalid bound directory.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ // Clear status bit.
+ //
+ bd_entry--;
+
+ lldb::addr_t bt_addr = bd_entry & ~bt_r_shift;
+ lldb::addr_t bt_entry_offset = ((ptr & bt_mask) >> bt_r_shift) << bt_l_shift;
+ bt_entry_addr = bt_addr + bt_entry_offset;
+
+ return true;
+}
+
+static bool GetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::SBTarget &target,
+ llvm::Triple::ArchType arch,
+ lldb::SBCommandReturnObject &result,
+ lldb::SBError &error) {
+ lldb::addr_t bt_entry_addr;
+ size_t size;
+ if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,
+ error))
+ return false;
+
+ // bt_entry_v must have space to store the 4 elements of the BT entry (lower
+ // boundary,
+ // upper boundary, pointer value and meta data), which all have the same size
+ // 'size'.
+ //
+ std::vector<uint8_t> bt_entry_v(size * 4);
+ size_t ret = target.GetProcess().ReadMemory(
+ bt_entry_addr, static_cast<void *>(bt_entry_v.data()), size * 4, error);
+
+ if ((ret != (size * 4)) || !error.Success()) {
+ result.SetError("Unsuccessful. Failed access to BT entry.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::addr_t lbound;
+ lldb::addr_t ubound;
+ uint64_t value;
+ uint64_t meta;
+ lldb::SBData data;
+ data.SetData(error, bt_entry_v.data(), bt_entry_v.size(),
+ target.GetByteOrder(), size);
+ lbound = data.GetAddress(error, size * 0);
+ ubound = data.GetAddress(error, size * 1);
+ value = data.GetAddress(error, size * 2);
+ meta = data.GetAddress(error, size * 3);
+ // ubound is stored as one's complement.
+ if (arch == llvm::Triple::ArchType::x86) {
+ ubound = (~ubound) & 0x00000000FFFFFFFF;
+ } else {
+ ubound = ~ubound;
+ }
+
+ if (!error.Success()) {
+ result.SetError("Failed access to BT entry.");
+ return false;
+ }
+
+ PrintBTEntry(lbound, ubound, value, meta, result);
+
+ result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
+ return true;
+}
+
+static std::vector<uint8_t> uIntToU8(uint64_t input, size_t size) {
+ std::vector<uint8_t> output;
+ for (size_t i = 0; i < size; i++)
+ output.push_back(
+ static_cast<uint8_t>((input & (0xFFULL << (i * 8))) >> (i * 8)));
+
+ return output;
+}
+
+static bool SetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::addr_t lbound,
+ lldb::addr_t ubound, lldb::SBTarget &target,
+ llvm::Triple::ArchType arch,
+ lldb::SBCommandReturnObject &result,
+ lldb::SBError &error) {
+ lldb::addr_t bt_entry_addr;
+ size_t size;
+
+ if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,
+ error))
+ return false;
+
+ // bt_entry_v must have space to store only 2 elements of the BT Entry, the
+ // lower boundary and the upper boundary, which both have size 'size'.
+ //
+ std::vector<uint8_t> bt_entry_v(size * 2);
+
+ std::vector<uint8_t> lbound_v = uIntToU8(lbound, size);
+ bt_entry_v.insert(bt_entry_v.begin(), lbound_v.begin(), lbound_v.end());
+ std::vector<uint8_t> ubound_v = uIntToU8(~ubound, size);
+ bt_entry_v.insert(bt_entry_v.begin() + size, ubound_v.begin(),
+ ubound_v.end());
+
+ size_t ret = target.GetProcess().WriteMemory(
+ bt_entry_addr, (void *)(bt_entry_v.data()), size * 2, error);
+ if ((ret != (size * 2)) || !error.Success()) {
+ result.SetError("Failed access to BT entry.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
+ return true;
+}
+
+static bool GetInitInfo(lldb::SBDebugger debugger, lldb::SBTarget &target,
+ llvm::Triple::ArchType &arch, uint64_t &bndcfgu,
+ char *arg, uint64_t &ptr,
+ lldb::SBCommandReturnObject &result,
+ lldb::SBError &error) {
+ target = debugger.GetSelectedTarget();
+ if (!target.IsValid()) {
+ result.SetError("Invalid target.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ const std::string triple_s(target.GetTriple());
+ const llvm::Triple triple(triple_s);
+
+ arch = triple.getArch();
+
+ if ((arch != llvm::Triple::ArchType::x86) &&
+ (arch != llvm::Triple::ArchType::x86_64)) {
+ result.SetError("Platform not supported.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::SBFrame frame =
+ target.GetProcess().GetSelectedThread().GetSelectedFrame();
+ if (!frame.IsValid()) {
+ result.SetError("No valid process, thread or frame.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::SBValue bndcfgu_val = frame.FindRegister("bndcfgu");
+ if (!bndcfgu_val.IsValid()) {
+ result.SetError(
+ "Cannot access register BNDCFGU. Does the target support MPX?");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::SBData bndcfgu_data = bndcfgu_val.GetData();
+ bndcfgu = bndcfgu_data.GetUnsignedInt64(error, 0);
+ if (!error.Success()) {
+ result.SetError(error, "Invalid read of register BNDCFGU.");
+ return false;
+ }
+
+ if (!GetPtr(arg, ptr, frame, result))
+ return false;
+
+ return true;
+}
+
+class MPXTableShow : public lldb::SBCommandPluginInterface {
+public:
+ virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
+ lldb::SBCommandReturnObject &result) {
+
+ if (command) {
+ int arg_c = 0;
+ char *arg;
+
+ while (*command) {
+ if (arg_c >= 1) {
+ result.SetError("Too many arguments. See help.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+ arg_c++;
+ arg = *command;
+ command++;
+ }
+
+ if (!debugger.IsValid()) {
+ result.SetError("Invalid debugger.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::SBTarget target;
+ llvm::Triple::ArchType arch;
+ lldb::SBError error;
+ uint64_t bndcfgu;
+ uint64_t ptr;
+
+ if (!GetInitInfo(debugger, target, arch, bndcfgu, arg, ptr, result,
+ error))
+ return false;
+
+ return GetBTEntry(bndcfgu, ptr, target, arch, result, error);
+ }
+
+ result.SetError("Too few arguments. See help.");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ return false;
+ }
+};
+
+class MPXTableSet : public lldb::SBCommandPluginInterface {
+public:
+ virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
+ lldb::SBCommandReturnObject &result) {
+
+ if (command) {
+ int arg_c = 0;
+ char *arg[3];
+
+ while (*command) {
+ arg[arg_c] = *command;
+ command++;
+ arg_c++;
+ }
+
+ if (arg_c != 3) {
+ result.SetError("Wrong arguments. See help.");
+ return false;
+ }
+
+ if (!debugger.IsValid()) {
+ result.SetError("Invalid debugger.");
+ return false;
+ }
+
+ lldb::SBTarget target;
+ llvm::Triple::ArchType arch;
+ lldb::SBError error;
+ uint64_t bndcfgu;
+ uint64_t ptr;
+
+ if (!GetInitInfo(debugger, target, arch, bndcfgu, arg[0], ptr, result,
+ error))
+ return false;
+
+ char *endptr;
+ errno = 0;
+ uint64_t lbound = std::strtoul(arg[1], &endptr, 16);
+ if (endptr == arg[1] || errno == ERANGE) {
+ result.SetError("Lower Bound: bad argument format.");
+ errno = 0;
+ return false;
+ }
+
+ uint64_t ubound = std::strtoul(arg[2], &endptr, 16);
+ if (endptr == arg[1] || errno == ERANGE) {
+ result.SetError("Upper Bound: bad argument format.");
+ errno = 0;
+ return false;
+ }
+
+ return SetBTEntry(bndcfgu, ptr, lbound, ubound, target, arch, result,
+ error);
+ }
+
+ result.SetError("Too few arguments. See help.");
+ return false;
+ }
+};
+
+bool lldb::PluginInitialize(lldb::SBDebugger debugger) {
+ lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
+ lldb::SBCommand mpxTable = interpreter.AddMultiwordCommand(
+ "mpx-table", "A utility to access the MPX table entries.");
+
+ const char *mpx_show_help = "Show the MPX table entry of a pointer.\n"
+ "mpx-table show <pointer>";
+ mpxTable.AddCommand("show", new MPXTableShow(), mpx_show_help);
+
+ const char *mpx_set_help =
+ "Set the MPX table entry of a pointer.\n"
+ "mpx-table set <pointer> <lower bound> <upper bound>";
+ mpxTable.AddCommand("set", new MPXTableSet(), mpx_set_help);
+
+ return true;
+}
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdBase.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdBase.cpp
index c645d84..cd5bf27 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdBase.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdBase.cpp
@@ -195,7 +195,7 @@ bool CMICmdBase::HasMIResultRecordExtra() const {
// metadata
// object and set the command's error status.
// Type: Method.
-// Args: rErrMsg - (R) Error description.
+// Args: rErrMsg - (R) Status description.
// Return: None.
// Throws: None.
//--
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdData.h b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdData.h
index 683e410..ab8d6ba 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdData.h
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdData.h
@@ -77,7 +77,7 @@ private:
bool m_bExpressionValid; // True = yes is valid, false = not valid
bool m_bEvaluatedExpression; // True = yes is expression evaluated, false =
// failed
- lldb::SBError m_Error; // Error object, which is examined when
+ lldb::SBError m_Error; // Status object, which is examined when
// m_bEvaluatedExpression is false
CMIUtilString m_strValue;
CMICmnMIValueTuple m_miValueTuple;
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdStack.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdStack.cpp
index 9160c40..b491027 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdStack.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdStack.cpp
@@ -32,6 +32,8 @@
#include "MICmnMIResultRecord.h"
#include "MICmnMIValueConst.h"
+#include <algorithm>
+
//++
//------------------------------------------------------------------------------------
// Details: CMICmdCmdStackInfoDepth constructor.
@@ -757,7 +759,8 @@ bool CMICmdCmdStackListLocals::Execute() {
: thread.GetSelectedFrame();
CMICmnMIValueList miValueList(true);
- const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Locals;
+ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Locals |
+ CMICmnLLDBDebugSessionInfo::eVariableType_InScope;
if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes,
eVarInfoFormat, miValueList))
return MIstatus::failure;
@@ -929,7 +932,8 @@ bool CMICmdCmdStackListVariables::Execute() {
CMICmnMIValueList miValueList(true);
const MIuint maskVarTypes =
CMICmnLLDBDebugSessionInfo::eVariableType_Arguments |
- CMICmnLLDBDebugSessionInfo::eVariableType_Locals;
+ CMICmnLLDBDebugSessionInfo::eVariableType_Locals |
+ CMICmnLLDBDebugSessionInfo::eVariableType_InScope;
if (!rSessionInfo.MIResponseFormVariableInfo(
frame, maskVarTypes, eVarInfoFormat, miValueList, 10, true))
return MIstatus::failure;
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdVar.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdVar.cpp
index 1efbd0b..66b392b 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdVar.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmdCmdVar.cpp
@@ -38,6 +38,8 @@
#include "MICmnMIResultRecord.h"
#include "MICmnMIValueConst.h"
+#include <algorithm>
+
//++
//------------------------------------------------------------------------------------
// Details: CMICmdCmdVarCreate constructor.
@@ -182,7 +184,7 @@ bool CMICmdCmdVarCreate::Execute() {
const bool bArgs = true;
const bool bLocals = true;
const bool bStatics = true;
- const bool bInScopeOnly = false;
+ const bool bInScopeOnly = true;
const lldb::SBValueList valueList =
frame.GetVariables(bArgs, bLocals, bStatics, bInScopeOnly);
value = valueList.GetFirstValueByName(rStrExpression.c_str());
@@ -508,22 +510,20 @@ bool CMICmdCmdVarUpdate::ExamineSBValueForChange(lldb::SBValue &vrwValue,
}
lldb::SBType valueType = vrwValue.GetType();
- if (!valueType.IsPointerType() && !valueType.IsReferenceType()) {
- const MIuint nChildren = vrwValue.GetNumChildren();
- for (MIuint i = 0; i < nChildren; ++i) {
- lldb::SBValue member = vrwValue.GetChildAtIndex(i);
- if (!member.IsValid())
- continue;
-
- if (member.GetValueDidChange()) {
- vrwbChanged = true;
- return MIstatus::success;
- } else if (ExamineSBValueForChange(member, vrwbChanged) && vrwbChanged)
- // Handle composite types (i.e. struct or arrays)
- return MIstatus::success;
- }
- }
+ const MIuint nChildren = vrwValue.GetNumChildren();
+ for (MIuint i = 0; i < nChildren; ++i) {
+ lldb::SBValue member = vrwValue.GetChildAtIndex(i);
+ if (!member.IsValid())
+ continue;
+
+ if (member.GetValueDidChange()) {
+ vrwbChanged = true;
+ return MIstatus::success;
+ } else if (ExamineSBValueForChange(member, vrwbChanged) && vrwbChanged)
+ // Handle composite types (i.e. struct or arrays)
+ return MIstatus::success;
+ }
vrwbChanged = false;
return MIstatus::success;
}
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.cpp
index 52100e7..63544dc 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.cpp
@@ -122,7 +122,7 @@ void CMICmnBase::ClrErrorDescription() const {
// Return: None.
// Throws: None.
//--
-void CMICmnBase::SetErrorDescriptionn(const CMIUtilString vFormat, ...) const {
+void CMICmnBase::SetErrorDescriptionn(const char *vFormat, ...) const {
va_list args;
va_start(args, vFormat);
CMIUtilString strResult = CMIUtilString::FormatValist(vFormat, args);
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.h b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.h
index f739493..2b60463 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.h
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnBase.h
@@ -28,7 +28,7 @@ public:
bool HaveErrorDescription() const;
const CMIUtilString &GetErrorDescription() const;
void SetErrorDescription(const CMIUtilString &vrTxt) const;
- void SetErrorDescriptionn(const CMIUtilString vFormat, ...) const;
+ void SetErrorDescriptionn(const char *vFormat, ...) const;
void SetErrorDescriptionNoLog(const CMIUtilString &vrTxt) const;
void ClrErrorDescription() const;
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebugger.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebugger.cpp
index a676ecc..b102cab 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebugger.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebugger.cpp
@@ -17,6 +17,7 @@
#include "lldb/API/SBTypeCategory.h"
#include "lldb/API/SBTypeNameSpecifier.h"
#include "lldb/API/SBTypeSummary.h"
+#include <cassert>
// In-house headers:
#include "MICmnLLDBDebugSessionInfo.h"
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
index e975dd6..a61244f 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp
@@ -40,6 +40,8 @@
#include "MIUtilDebug.h"
#include "Platform.h" // for PATH_MAX
+#include <algorithm>
+
//++
//------------------------------------------------------------------------------------
// Details: CMICmnLLDBDebuggerHandleEvents constructor.
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriver.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriver.cpp
index eec3738..7bd6b7b 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriver.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriver.cpp
@@ -9,6 +9,8 @@
// Third party headers:
#include "lldb/API/SBError.h"
+#include <cassert>
+#include <csignal>
#include <fstream>
// In-house headers:
@@ -509,7 +511,7 @@ bool CMIDriver::StartWorkerThreads() {
const CMIUtilString errMsg = CMIUtilString::Format(
MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE),
CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str());
- SetErrorDescriptionn(errMsg);
+ SetErrorDescription(errMsg);
return MIstatus::failure;
}
@@ -710,7 +712,7 @@ const CMIUtilString &CMIDriver::GetDriverId() const { return GetId(); }
// Check the error message if the function returns a failure.
// Type: Overridden.
// Args: vCmd - (R) Command instruction to interpret.
-// vwErrMsg - (W) Error description on command failing.
+// vwErrMsg - (W) Status description on command failing.
// Return: MIstatus::success - Command succeeded.
// MIstatus::failure - Command failed.
// Throws: None.
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverBase.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverBase.cpp
index 0620b61..f70da6e 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverBase.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverBase.cpp
@@ -44,7 +44,7 @@ CMIDriverBase::~CMIDriverBase() { m_pDriverFallThru = NULL; }
// Check the error message if the function returns a failure.
// Type: Overridden.
// Args: vCmd - (R) Command instruction to interpret.
-// vwErrMsg - (W) Error description on command failing.
+// vwErrMsg - (W) Status description on command failing.
// Return: MIstatus::success - Command succeeded.
// MIstatus::failure - Command failed.
// Throws: None.
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverMain.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverMain.cpp
index fdced8d..be01f1d 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverMain.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverMain.cpp
@@ -33,6 +33,7 @@
// Third party headers:
#include "lldb/API/SBHostOS.h"
+#include <csignal>
#include <stdio.h>
// In house headers:
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.cpp b/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.cpp
index 3e6911f..45196a7 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.cpp
@@ -157,7 +157,7 @@ CMIUtilString CMIUtilString::FormatPriv(const CMIUtilString &vrFormat,
// Return: CMIUtilString - Number of splits found in the string data.
// Throws: None.
//--
-CMIUtilString CMIUtilString::Format(const CMIUtilString vFormating, ...) {
+CMIUtilString CMIUtilString::Format(const char *vFormating, ...) {
va_list args;
va_start(args, vFormating);
CMIUtilString strResult = CMIUtilString::FormatPriv(vFormating, args);
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.h b/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.h
index 3b07772..2639141 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.h
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilString.h
@@ -30,7 +30,7 @@ public:
// Static method:
public:
- static CMIUtilString Format(const CMIUtilString vFormating, ...);
+ static CMIUtilString Format(const char *vFormating, ...);
static CMIUtilString FormatBinary(const MIuint64 vnDecimal);
static CMIUtilString FormatValist(const CMIUtilString &vrFormating,
va_list vArgs);
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilThreadBaseStd.h b/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilThreadBaseStd.h
index cfff7d4..20b8fad 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilThreadBaseStd.h
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/MIUtilThreadBaseStd.h
@@ -10,9 +10,6 @@
#pragma once
// Third party headers:
-#ifdef _MSC_VER
-#include <eh.h>
-#endif // _MSC_VER
#include <mutex>
#include <thread>
diff --git a/contrib/llvm/tools/lldb/tools/lldb-mi/Platform.h b/contrib/llvm/tools/lldb/tools/lldb-mi/Platform.h
index 1b6ff55..ce2de1b 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-mi/Platform.h
+++ b/contrib/llvm/tools/lldb/tools/lldb-mi/Platform.h
@@ -10,7 +10,6 @@
#if defined(_MSC_VER)
-#include <eh.h>
#include <inttypes.h>
#include <io.h>
#include <signal.h>
diff --git a/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.cpp b/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.cpp
index 00a0bda..16db9e9 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.cpp
@@ -12,11 +12,10 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ScopedPrinter.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/common/TCPSocket.h"
-
-#include "Utility/UriParser.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UriParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -57,14 +56,13 @@ const char *FindSchemeByProtocol(const Socket::SocketProtocol protocol) {
}
}
-Error Acceptor::Listen(int backlog) {
+Status Acceptor::Listen(int backlog) {
return m_listener_socket_up->Listen(StringRef(m_name), backlog);
}
-Error Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) {
+Status Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) {
Socket *conn_socket = nullptr;
- auto error = m_listener_socket_up->Accept(
- StringRef(m_name), child_processes_inherit, conn_socket);
+ auto error = m_listener_socket_up->Accept(conn_socket);
if (error.Success())
conn = new ConnectionFileDescriptor(conn_socket);
@@ -83,7 +81,7 @@ std::string Acceptor::GetLocalSocketId() const { return m_local_socket_id(); }
std::unique_ptr<Acceptor> Acceptor::Create(StringRef name,
const bool child_processes_inherit,
- Error &error) {
+ Status &error) {
error.Clear();
Socket::SocketProtocol socket_protocol = Socket::ProtocolUnixDomain;
diff --git a/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.h b/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.h
index f0638ef..7d1a569 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.h
+++ b/contrib/llvm/tools/lldb/tools/lldb-server/Acceptor.h
@@ -9,9 +9,9 @@
#ifndef lldb_server_Acceptor_h_
#define lldb_server_Acceptor_h_
-#include "lldb/Core/Connection.h"
-#include "lldb/Core/Error.h"
#include "lldb/Host/Socket.h"
+#include "lldb/Utility/Connection.h"
+#include "lldb/Utility/Status.h"
#include <functional>
#include <memory>
@@ -28,13 +28,13 @@ class Acceptor {
public:
virtual ~Acceptor() = default;
- Error Listen(int backlog);
+ Status Listen(int backlog);
- Error Accept(const bool child_processes_inherit, Connection *&conn);
+ Status Accept(const bool child_processes_inherit, Connection *&conn);
static std::unique_ptr<Acceptor> Create(llvm::StringRef name,
const bool child_processes_inherit,
- Error &error);
+ Status &error);
Socket::SocketProtocol GetSocketProtocol() const;
diff --git a/contrib/llvm/tools/lldb/tools/lldb-server/LLDBServerUtilities.cpp b/contrib/llvm/tools/lldb/tools/lldb-server/LLDBServerUtilities.cpp
index 86d8469..e784a3a 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-server/LLDBServerUtilities.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-server/LLDBServerUtilities.cpp
@@ -9,47 +9,55 @@
#include "LLDBServerUtilities.h"
-#include "lldb/Core/Log.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/StreamString.h"
#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
using namespace lldb;
using namespace lldb_private::lldb_server;
using namespace llvm;
+static std::shared_ptr<raw_ostream> GetLogStream(StringRef log_file) {
+ if (!log_file.empty()) {
+ std::error_code EC;
+ std::shared_ptr<raw_ostream> stream_sp = std::make_shared<raw_fd_ostream>(
+ log_file, EC, sys::fs::F_Text | sys::fs::F_Append);
+ if (!EC)
+ return stream_sp;
+ errs() << llvm::formatv(
+ "Failed to open log file `{0}`: {1}\nWill log to stderr instead.\n",
+ log_file, EC.message());
+ }
+ // No need to delete the stderr stream.
+ return std::shared_ptr<raw_ostream>(&errs(), [](raw_ostream *) {});
+}
+
bool LLDBServerUtilities::SetupLogging(const std::string &log_file,
const StringRef &log_channels,
uint32_t log_options) {
- lldb::StreamSP log_stream_sp;
- if (log_file.empty()) {
- log_stream_sp.reset(new StreamFile(stdout, false));
- } else {
- uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate |
- File::eOpenOptionCloseOnExec | File::eOpenOptionAppend;
- if (!(log_options & LLDB_LOG_OPTION_APPEND))
- options |= File::eOpenOptionTruncate;
-
- log_stream_sp.reset(new StreamFile(log_file.c_str(), options));
- }
+
+ auto log_stream_sp = GetLogStream(log_file);
SmallVector<StringRef, 32> channel_array;
log_channels.split(channel_array, ":", /*MaxSplit*/ -1, /*KeepEmpty*/ false);
for (auto channel_with_categories : channel_array) {
- StreamString error_stream;
+ std::string error;
+ llvm::raw_string_ostream error_stream(error);
Args channel_then_categories(channel_with_categories);
std::string channel(channel_then_categories.GetArgumentAtIndex(0));
channel_then_categories.Shift(); // Shift off the channel
bool success = Log::EnableLogChannel(
- log_stream_sp, log_options, channel.c_str(),
- channel_then_categories.GetConstArgumentVector(), error_stream);
+ log_stream_sp, log_options, channel,
+ channel_then_categories.GetArgumentArrayRef(), error_stream);
if (!success) {
- fprintf(stderr, "Unable to open log file '%s' for channel \"%s\"\n",
- log_file.c_str(), channel_with_categories.str().c_str());
+ errs() << formatv("Unable to setup logging for channel \"{0}\": {1}",
+ channel, error_stream.str());
return false;
}
}
diff --git a/contrib/llvm/tools/lldb/tools/lldb-server/lldb-gdbserver.cpp b/contrib/llvm/tools/lldb/tools/lldb-server/lldb-gdbserver.cpp
index 5a38872..f1a9b11 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-server/lldb-gdbserver.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -21,14 +21,11 @@
// C++ Includes
-// Other libraries and framework includes
-#include "llvm/ADT/StringRef.h"
#include "Acceptor.h"
#include "LLDBServerUtilities.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
-#include "lldb/Core/Error.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/HostGetOpt.h"
@@ -36,6 +33,16 @@
#include "lldb/Host/Pipe.h"
#include "lldb/Host/Socket.h"
#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Utility/Status.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errno.h"
+
+#if defined(__linux__)
+#include "Plugins/Process/Linux/NativeProcessLinux.h"
+#elif defined(__NetBSD__)
+#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
+#endif
#ifndef LLGS_PROGRAM_NAME
#define LLGS_PROGRAM_NAME "lldb-server"
@@ -51,6 +58,30 @@ using namespace lldb_private;
using namespace lldb_private::lldb_server;
using namespace lldb_private::process_gdb_remote;
+namespace {
+#if defined(__linux__)
+typedef process_linux::NativeProcessLinux::Factory NativeProcessFactory;
+#elif defined(__NetBSD__)
+typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory;
+#else
+// Dummy implementation to make sure the code compiles
+class NativeProcessFactory : public NativeProcessProtocol::Factory {
+public:
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Launch(ProcessLaunchInfo &launch_info,
+ NativeProcessProtocol::NativeDelegate &delegate,
+ MainLoop &mainloop) const override {
+ llvm_unreachable("Not implemented");
+ }
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Attach(lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &delegate,
+ MainLoop &mainloop) const override {
+ llvm_unreachable("Not implemented");
+ }
+};
+#endif
+}
+
//----------------------------------------------------------------------
// option descriptors for getopt_long_only()
//----------------------------------------------------------------------
@@ -112,7 +143,7 @@ static void display_usage(const char *progname, const char *subcommand) {
void handle_attach_to_pid(GDBRemoteCommunicationServerLLGS &gdb_server,
lldb::pid_t pid) {
- Error error = gdb_server.AttachToProcess(pid);
+ Status error = gdb_server.AttachToProcess(pid);
if (error.Fail()) {
fprintf(stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid,
error.AsCString());
@@ -145,7 +176,7 @@ void handle_attach(GDBRemoteCommunicationServerLLGS &gdb_server,
void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, int argc,
const char *const argv[]) {
- Error error;
+ Status error;
error = gdb_server.SetLaunchArguments(argv, argc);
if (error.Fail()) {
fprintf(stderr, "error: failed to set launch args for '%s': %s\n", argv[0],
@@ -170,15 +201,15 @@ void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, int argc,
}
}
-Error writeSocketIdToPipe(Pipe &port_pipe, const std::string &socket_id) {
+Status writeSocketIdToPipe(Pipe &port_pipe, const std::string &socket_id) {
size_t bytes_written = 0;
// Write the port number as a C string with the NULL terminator.
return port_pipe.Write(socket_id.c_str(), socket_id.size() + 1,
bytes_written);
}
-Error writeSocketIdToPipe(const char *const named_pipe_path,
- const std::string &socket_id) {
+Status writeSocketIdToPipe(const char *const named_pipe_path,
+ const std::string &socket_id) {
Pipe port_name_pipe;
// Wait for 10 seconds for pipe to be opened.
auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false,
@@ -188,9 +219,9 @@ Error writeSocketIdToPipe(const char *const named_pipe_path,
return writeSocketIdToPipe(port_name_pipe, socket_id);
}
-Error writeSocketIdToPipe(int unnamed_pipe_fd, const std::string &socket_id) {
+Status writeSocketIdToPipe(int unnamed_pipe_fd, const std::string &socket_id) {
#if defined(_WIN32)
- return Error("Unnamed pipes are not supported on Windows.");
+ return Status("Unnamed pipes are not supported on Windows.");
#else
Pipe port_pipe{Pipe::kInvalidDescriptor, unnamed_pipe_fd};
return writeSocketIdToPipe(port_pipe, socket_id);
@@ -202,7 +233,7 @@ void ConnectToRemote(MainLoop &mainloop,
bool reverse_connect, const char *const host_and_port,
const char *const progname, const char *const subcommand,
const char *const named_pipe_path, int unnamed_pipe_fd) {
- Error error;
+ Status error;
if (host_and_port && host_and_port[0]) {
// Parse out host and port.
@@ -311,7 +342,7 @@ void ConnectToRemote(MainLoop &mainloop,
// main
//----------------------------------------------------------------------
int main_gdbserver(int argc, char *argv[]) {
- Error error;
+ Status error;
MainLoop mainloop;
#ifndef _WIN32
// Setup signal handlers first thing.
@@ -398,10 +429,9 @@ int main_gdbserver(int argc, char *argv[]) {
{
const ::pid_t new_sid = setsid();
if (new_sid == -1) {
- const char *errno_str = strerror(errno);
- fprintf(stderr, "failed to set new session id for %s (%s)\n",
- LLGS_PROGRAM_NAME,
- errno_str ? errno_str : "<no error string>");
+ llvm::errs() << llvm::formatv(
+ "failed to set new session id for {0} ({1})\n", LLGS_PROGRAM_NAME,
+ llvm::sys::StrError());
}
}
break;
@@ -424,11 +454,13 @@ int main_gdbserver(int argc, char *argv[]) {
exit(option_error);
}
- if (!LLDBServerUtilities::SetupLogging(log_file, log_channels,
- LLDB_LOG_OPTION_PREPEND_TIMESTAMP))
+ if (!LLDBServerUtilities::SetupLogging(
+ log_file, log_channels,
+ LLDB_LOG_OPTION_PREPEND_TIMESTAMP |
+ LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION))
return -1;
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(GDBR_LOG_VERBOSE));
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(GDBR_LOG_PROCESS));
if (log) {
log->Printf("lldb-server launch");
for (int i = 0; i < argc; i++) {
@@ -445,7 +477,8 @@ int main_gdbserver(int argc, char *argv[]) {
exit(255);
}
- GDBRemoteCommunicationServerLLGS gdb_server(mainloop);
+ NativeProcessFactory factory;
+ GDBRemoteCommunicationServerLLGS gdb_server(mainloop, factory);
const char *const host_and_port = argv[0];
argc -= 1;
diff --git a/contrib/llvm/tools/lldb/tools/lldb-server/lldb-platform.cpp b/contrib/llvm/tools/lldb/tools/lldb-server/lldb-platform.cpp
index 1772921..ec5b781 100644
--- a/contrib/llvm/tools/lldb/tools/lldb-server/lldb-platform.cpp
+++ b/contrib/llvm/tools/lldb/tools/lldb-server/lldb-platform.cpp
@@ -30,13 +30,12 @@
#include "LLDBServerUtilities.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
-#include "lldb/Core/Error.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostGetOpt.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
@@ -99,38 +98,39 @@ static void display_usage(const char *progname, const char *subcommand) {
exit(0);
}
-static Error save_socket_id_to_file(const std::string &socket_id,
- const FileSpec &file_spec) {
+static Status save_socket_id_to_file(const std::string &socket_id,
+ const FileSpec &file_spec) {
FileSpec temp_file_spec(file_spec.GetDirectory().AsCString(), false);
- auto error = FileSystem::MakeDirectory(temp_file_spec,
- eFilePermissionsDirectoryDefault);
+ Status error(llvm::sys::fs::create_directory(temp_file_spec.GetPath()));
if (error.Fail())
- return Error("Failed to create directory %s: %s",
- temp_file_spec.GetCString(), error.AsCString());
+ return Status("Failed to create directory %s: %s",
+ temp_file_spec.GetCString(), error.AsCString());
- llvm::SmallString<PATH_MAX> temp_file_path;
+ llvm::SmallString<64> temp_file_path;
temp_file_spec.AppendPathComponent("port-file.%%%%%%");
- auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetCString(),
+ int FD;
+ auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetPath(), FD,
temp_file_path);
if (err_code)
- return Error("Failed to create temp file: %s", err_code.message().c_str());
+ return Status("Failed to create temp file: %s", err_code.message().c_str());
- llvm::FileRemover tmp_file_remover(temp_file_path.c_str());
+ llvm::FileRemover tmp_file_remover(temp_file_path);
{
- std::ofstream temp_file(temp_file_path.c_str(), std::ios::out);
- if (!temp_file.is_open())
- return Error("Failed to open temp file %s", temp_file_path.c_str());
+ llvm::raw_fd_ostream temp_file(FD, true);
temp_file << socket_id;
+ temp_file.close();
+ if (temp_file.has_error())
+ return Status("Failed to write to port file.");
}
- err_code = llvm::sys::fs::rename(temp_file_path.c_str(), file_spec.GetPath());
+ err_code = llvm::sys::fs::rename(temp_file_path, file_spec.GetPath());
if (err_code)
- return Error("Failed to rename file %s to %s: %s", temp_file_path.c_str(),
- file_spec.GetPath().c_str(), err_code.message().c_str());
+ return Status("Failed to rename file %s to %s: %s", temp_file_path.c_str(),
+ file_spec.GetPath().c_str(), err_code.message().c_str());
tmp_file_remover.releaseFile();
- return Error();
+ return Status();
}
//----------------------------------------------------------------------
@@ -144,7 +144,7 @@ int main_platform(int argc, char *argv[]) {
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, signal_handler);
int long_option_index = 0;
- Error error;
+ Status error;
std::string listen_host_port;
int ch;
@@ -197,46 +197,41 @@ int main_platform(int argc, char *argv[]) {
break;
case 'p': {
- char *end = NULL;
- long tmp_port_offset = strtoul(optarg, &end, 0);
- if (end && *end == '\0') {
- if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT) {
- port_offset = (uint16_t)tmp_port_offset;
- } else {
- fprintf(stderr, "error: port offset %li is not in the valid user "
- "port range of %u - %u\n",
- tmp_port_offset, LOW_PORT, HIGH_PORT);
- option_error = 5;
- }
- } else {
- fprintf(stderr, "error: invalid port offset string %s\n", optarg);
+ if (!llvm::to_integer(optarg, port_offset)) {
+ llvm::errs() << "error: invalid port offset string " << optarg << "\n";
option_error = 4;
+ break;
+ }
+ if (port_offset < LOW_PORT || port_offset > HIGH_PORT) {
+ llvm::errs() << llvm::formatv("error: port offset {0} is not in the "
+ "valid user port range of {1} - {2}\n",
+ port_offset, LOW_PORT, HIGH_PORT);
+ option_error = 5;
}
} break;
case 'P':
case 'm':
case 'M': {
- char *end = NULL;
- long portnum = strtoul(optarg, &end, 0);
- if (end && *end == '\0') {
- if (LOW_PORT <= portnum && portnum <= HIGH_PORT) {
- if (ch == 'P')
- gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID;
- else if (ch == 'm')
- min_gdbserver_port = portnum;
- else
- max_gdbserver_port = portnum;
- } else {
- fprintf(stderr, "error: port number %li is not in the valid user "
- "port range of %u - %u\n",
- portnum, LOW_PORT, HIGH_PORT);
- option_error = 1;
- }
- } else {
- fprintf(stderr, "error: invalid port number string %s\n", optarg);
+ uint16_t portnum;
+ if (!llvm::to_integer(optarg, portnum)) {
+ llvm::errs() << "error: invalid port number string " << optarg << "\n";
option_error = 2;
+ break;
+ }
+ if (portnum < LOW_PORT || portnum > HIGH_PORT) {
+ llvm::errs() << llvm::formatv("error: port number {0} is not in the "
+ "valid user port range of {1} - {2}\n",
+ portnum, LOW_PORT, HIGH_PORT);
+ option_error = 1;
+ break;
}
+ if (ch == 'P')
+ gdbserver_portmap[portnum] = LLDB_INVALID_PROCESS_ID;
+ else if (ch == 'm')
+ min_gdbserver_port = portnum;
+ else
+ max_gdbserver_port = portnum;
} break;
case 'h': /* fall-through is intentional */
@@ -350,9 +345,9 @@ int main_platform(int argc, char *argv[]) {
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
uint16_t port = 0;
std::string socket_name;
- Error error = platform.LaunchGDBServer(inferior_arguments,
- "", // hostname
- pid, port, socket_name);
+ Status error = platform.LaunchGDBServer(inferior_arguments,
+ "", // hostname
+ pid, port, socket_name);
if (error.Success())
platform.SetPendingGdbServer(pid, port, socket_name);
else
diff --git a/contrib/llvm/tools/lli/OrcLazyJIT.cpp b/contrib/llvm/tools/lli/OrcLazyJIT.cpp
index ec61ce5..f1a752e 100644
--- a/contrib/llvm/tools/lli/OrcLazyJIT.cpp
+++ b/contrib/llvm/tools/lli/OrcLazyJIT.cpp
@@ -1,4 +1,4 @@
-//===------ OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution -------===//
+//===- OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution ------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,51 +8,56 @@
//===----------------------------------------------------------------------===//
#include "OrcLazyJIT.h"
-#include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
-#include "llvm/Support/Debug.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include <cstdint>
#include <cstdio>
+#include <cstdlib>
#include <system_error>
using namespace llvm;
namespace {
- enum class DumpKind { NoDump, DumpFuncsToStdOut, DumpModsToStdOut,
- DumpModsToDisk };
-
- cl::opt<DumpKind> OrcDumpKind("orc-lazy-debug",
- cl::desc("Debug dumping for the orc-lazy JIT."),
- cl::init(DumpKind::NoDump),
- cl::values(
- clEnumValN(DumpKind::NoDump, "no-dump",
- "Don't dump anything."),
- clEnumValN(DumpKind::DumpFuncsToStdOut,
- "funcs-to-stdout",
- "Dump function names to stdout."),
- clEnumValN(DumpKind::DumpModsToStdOut,
- "mods-to-stdout",
- "Dump modules to stdout."),
- clEnumValN(DumpKind::DumpModsToDisk,
- "mods-to-disk",
- "Dump modules to the current "
- "working directory. (WARNING: "
- "will overwrite existing files).")),
- cl::Hidden);
-
- cl::opt<bool> OrcInlineStubs("orc-lazy-inline-stubs",
- cl::desc("Try to inline stubs"),
- cl::init(true), cl::Hidden);
-}
+enum class DumpKind {
+ NoDump,
+ DumpFuncsToStdOut,
+ DumpModsToStdOut,
+ DumpModsToDisk
+};
+
+} // end anonymous namespace
+
+static cl::opt<DumpKind> OrcDumpKind(
+ "orc-lazy-debug", cl::desc("Debug dumping for the orc-lazy JIT."),
+ cl::init(DumpKind::NoDump),
+ cl::values(clEnumValN(DumpKind::NoDump, "no-dump", "Don't dump anything."),
+ clEnumValN(DumpKind::DumpFuncsToStdOut, "funcs-to-stdout",
+ "Dump function names to stdout."),
+ clEnumValN(DumpKind::DumpModsToStdOut, "mods-to-stdout",
+ "Dump modules to stdout."),
+ clEnumValN(DumpKind::DumpModsToDisk, "mods-to-disk",
+ "Dump modules to the current "
+ "working directory. (WARNING: "
+ "will overwrite existing files).")),
+ cl::Hidden);
+
+static cl::opt<bool> OrcInlineStubs("orc-lazy-inline-stubs",
+ cl::desc("Try to inline stubs"),
+ cl::init(true), cl::Hidden);
OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
-
switch (OrcDumpKind) {
case DumpKind::NoDump:
- return [](std::unique_ptr<Module> M) { return M; };
+ return [](std::shared_ptr<Module> M) { return M; };
case DumpKind::DumpFuncsToStdOut:
- return [](std::unique_ptr<Module> M) {
+ return [](std::shared_ptr<Module> M) {
printf("[ ");
for (const auto &F : *M) {
@@ -71,7 +76,7 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
};
case DumpKind::DumpModsToStdOut:
- return [](std::unique_ptr<Module> M) {
+ return [](std::shared_ptr<Module> M) {
outs() << "----- Module Start -----\n" << *M
<< "----- Module End -----\n";
@@ -79,7 +84,7 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
};
case DumpKind::DumpModsToDisk:
- return [](std::unique_ptr<Module> M) {
+ return [](std::shared_ptr<Module> M) {
std::error_code EC;
raw_fd_ostream Out(M->getModuleIdentifier() + ".ll", EC,
sys::fs::F_Text);
@@ -98,7 +103,6 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
// Defined in lli.cpp.
CodeGenOpt::Level getOptLevel();
-
template <typename PtrTy>
static PtrTy fromTargetAddress(JITTargetAddress Addr) {
return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr));
@@ -143,19 +147,20 @@ int llvm::runOrcLazyJIT(std::vector<std::unique_ptr<Module>> Ms,
OrcInlineStubs);
// Add the module, look up main and run it.
- J.addModuleSet(std::move(Ms));
- auto MainSym = J.findSymbol("main");
-
- if (!MainSym) {
+ for (auto &M : Ms)
+ cantFail(J.addModule(std::shared_ptr<Module>(std::move(M))));
+
+ if (auto MainSym = J.findSymbol("main")) {
+ typedef int (*MainFnPtr)(int, const char*[]);
+ std::vector<const char *> ArgV;
+ for (auto &Arg : Args)
+ ArgV.push_back(Arg.c_str());
+ auto Main = fromTargetAddress<MainFnPtr>(cantFail(MainSym.getAddress()));
+ return Main(ArgV.size(), (const char**)ArgV.data());
+ } else if (auto Err = MainSym.takeError())
+ logAllUnhandledErrors(std::move(Err), llvm::errs(), "");
+ else
errs() << "Could not find main function.\n";
- return 1;
- }
- typedef int (*MainFnPtr)(int, const char*[]);
- std::vector<const char *> ArgV;
- for (auto &Arg : Args)
- ArgV.push_back(Arg.c_str());
- auto Main = fromTargetAddress<MainFnPtr>(MainSym.getAddress());
- return Main(ArgV.size(), (const char**)ArgV.data());
+ return 1;
}
-
diff --git a/contrib/llvm/tools/lli/OrcLazyJIT.h b/contrib/llvm/tools/lli/OrcLazyJIT.h
index 05319c3..47a2acc 100644
--- a/contrib/llvm/tools/lli/OrcLazyJIT.h
+++ b/contrib/llvm/tools/lli/OrcLazyJIT.h
@@ -1,4 +1,4 @@
-//===--- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution --*- C++ -*-===//
+//===- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,30 +15,46 @@
#ifndef LLVM_TOOLS_LLI_ORCLAZYJIT_H
#define LLVM_TOOLS_LLI_ORCLAZYJIT_H
-#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
-#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
+#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
namespace llvm {
class OrcLazyJIT {
public:
- typedef orc::JITCompileCallbackManager CompileCallbackMgr;
- typedef orc::ObjectLinkingLayer<> ObjLayerT;
- typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT;
- typedef std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>
- TransformFtor;
- typedef orc::IRTransformLayer<CompileLayerT, TransformFtor> IRDumpLayerT;
- typedef orc::CompileOnDemandLayer<IRDumpLayerT, CompileCallbackMgr> CODLayerT;
- typedef CODLayerT::IndirectStubsManagerBuilderT
- IndirectStubsManagerBuilder;
- typedef CODLayerT::ModuleSetHandleT ModuleSetHandleT;
+ using CompileCallbackMgr = orc::JITCompileCallbackManager;
+ using ObjLayerT = orc::RTDyldObjectLinkingLayer;
+ using CompileLayerT = orc::IRCompileLayer<ObjLayerT, orc::SimpleCompiler>;
+ using TransformFtor =
+ std::function<std::shared_ptr<Module>(std::shared_ptr<Module>)>;
+ using IRDumpLayerT = orc::IRTransformLayer<CompileLayerT, TransformFtor>;
+ using CODLayerT = orc::CompileOnDemandLayer<IRDumpLayerT, CompileCallbackMgr>;
+ using IndirectStubsManagerBuilder = CODLayerT::IndirectStubsManagerBuilderT;
+ using ModuleHandleT = CODLayerT::ModuleHandleT;
OrcLazyJIT(std::unique_ptr<TargetMachine> TM,
std::unique_ptr<CompileCallbackMgr> CCMgr,
@@ -46,7 +62,7 @@ public:
bool InlineStubs)
: TM(std::move(TM)), DL(this->TM->createDataLayout()),
CCMgr(std::move(CCMgr)),
- ObjectLayer(),
+ ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)),
IRDumpLayer(CompileLayer, createDebugDumper()),
CODLayer(IRDumpLayer, extractSingleFunction, *this->CCMgr,
@@ -59,14 +75,16 @@ public:
CXXRuntimeOverrides.runDestructors();
// Run any IR destructors.
for (auto &DtorRunner : IRStaticDestructorRunners)
- DtorRunner.runViaLayer(CODLayer);
+ if (auto Err = DtorRunner.runViaLayer(CODLayer)) {
+ // FIXME: OrcLazyJIT should probably take a "shutdownError" callback to
+ // report these errors on.
+ report_fatal_error(std::move(Err));
+ }
}
- ModuleSetHandleT addModuleSet(std::vector<std::unique_ptr<Module>> Ms) {
- // Attach a data-layouts if they aren't already present.
- for (auto &M : Ms)
- if (M->getDataLayout().isDefault())
- M->setDataLayout(DL);
+ Error addModule(std::shared_ptr<Module> M) {
+ if (M->getDataLayout().isDefault())
+ M->setDataLayout(DL);
// Rename, bump linkage and record static constructors and destructors.
// We have to do this before we hand over ownership of the module to the
@@ -74,21 +92,19 @@ public:
std::vector<std::string> CtorNames, DtorNames;
{
unsigned CtorId = 0, DtorId = 0;
- for (auto &M : Ms) {
- for (auto Ctor : orc::getConstructors(*M)) {
- std::string NewCtorName = ("$static_ctor." + Twine(CtorId++)).str();
- Ctor.Func->setName(NewCtorName);
- Ctor.Func->setLinkage(GlobalValue::ExternalLinkage);
- Ctor.Func->setVisibility(GlobalValue::HiddenVisibility);
- CtorNames.push_back(mangle(NewCtorName));
- }
- for (auto Dtor : orc::getDestructors(*M)) {
- std::string NewDtorName = ("$static_dtor." + Twine(DtorId++)).str();
- Dtor.Func->setLinkage(GlobalValue::ExternalLinkage);
- Dtor.Func->setVisibility(GlobalValue::HiddenVisibility);
- DtorNames.push_back(mangle(Dtor.Func->getName()));
- Dtor.Func->setName(NewDtorName);
- }
+ for (auto Ctor : orc::getConstructors(*M)) {
+ std::string NewCtorName = ("$static_ctor." + Twine(CtorId++)).str();
+ Ctor.Func->setName(NewCtorName);
+ Ctor.Func->setLinkage(GlobalValue::ExternalLinkage);
+ Ctor.Func->setVisibility(GlobalValue::HiddenVisibility);
+ CtorNames.push_back(mangle(NewCtorName));
+ }
+ for (auto Dtor : orc::getDestructors(*M)) {
+ std::string NewDtorName = ("$static_dtor." + Twine(DtorId++)).str();
+ Dtor.Func->setLinkage(GlobalValue::ExternalLinkage);
+ Dtor.Func->setVisibility(GlobalValue::HiddenVisibility);
+ DtorNames.push_back(mangle(Dtor.Func->getName()));
+ Dtor.Func->setName(NewDtorName);
}
}
@@ -96,46 +112,55 @@ public:
// 1) Search the JIT symbols.
// 2) Check for C++ runtime overrides.
// 3) Search the host process (LLI)'s symbol table.
- auto Resolver =
- orc::createLambdaResolver(
- [this](const std::string &Name) -> JITSymbol {
- if (auto Sym = CODLayer.findSymbol(Name, true))
- return Sym;
- return CXXRuntimeOverrides.searchOverrides(Name);
- },
- [](const std::string &Name) {
- if (auto Addr =
- RTDyldMemoryManager::getSymbolAddressInProcess(Name))
- return JITSymbol(Addr, JITSymbolFlags::Exported);
- return JITSymbol(nullptr);
- }
- );
-
- // Add the module to the JIT.
- auto H = CODLayer.addModuleSet(std::move(Ms),
- llvm::make_unique<SectionMemoryManager>(),
- std::move(Resolver));
+ if (ModulesHandle == CODLayerT::ModuleHandleT()) {
+ auto Resolver =
+ orc::createLambdaResolver(
+ [this](const std::string &Name) -> JITSymbol {
+ if (auto Sym = CODLayer.findSymbol(Name, true))
+ return Sym;
+ return CXXRuntimeOverrides.searchOverrides(Name);
+ },
+ [](const std::string &Name) {
+ if (auto Addr =
+ RTDyldMemoryManager::getSymbolAddressInProcess(Name))
+ return JITSymbol(Addr, JITSymbolFlags::Exported);
+ return JITSymbol(nullptr);
+ }
+ );
+
+ // Add the module to the JIT.
+ if (auto ModulesHandleOrErr =
+ CODLayer.addModule(std::move(M), std::move(Resolver)))
+ ModulesHandle = std::move(*ModulesHandleOrErr);
+ else
+ return ModulesHandleOrErr.takeError();
+
+ } else
+ if (auto Err = CODLayer.addExtraModule(ModulesHandle, std::move(M)))
+ return Err;
// Run the static constructors, and save the static destructor runner for
// execution when the JIT is torn down.
- orc::CtorDtorRunner<CODLayerT> CtorRunner(std::move(CtorNames), H);
- CtorRunner.runViaLayer(CODLayer);
+ orc::CtorDtorRunner<CODLayerT> CtorRunner(std::move(CtorNames),
+ ModulesHandle);
+ if (auto Err = CtorRunner.runViaLayer(CODLayer))
+ return Err;
- IRStaticDestructorRunners.emplace_back(std::move(DtorNames), H);
+ IRStaticDestructorRunners.emplace_back(std::move(DtorNames),
+ ModulesHandle);
- return H;
+ return Error::success();
}
JITSymbol findSymbol(const std::string &Name) {
return CODLayer.findSymbol(mangle(Name), true);
}
- JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name) {
+ JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name) {
return CODLayer.findSymbolIn(H, mangle(Name), true);
}
private:
-
std::string mangle(const std::string &Name) {
std::string MangledName;
{
@@ -165,6 +190,7 @@ private:
orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides;
std::vector<orc::CtorDtorRunner<CODLayerT>> IRStaticDestructorRunners;
+ CODLayerT::ModuleHandleT ModulesHandle;
};
int runOrcLazyJIT(std::vector<std::unique_ptr<Module>> Ms,
@@ -172,4 +198,4 @@ int runOrcLazyJIT(std::vector<std::unique_ptr<Module>> Ms,
} // end namespace llvm
-#endif
+#endif // LLVM_TOOLS_LLI_ORCLAZYJIT_H
diff --git a/contrib/llvm/tools/lli/RemoteJITUtils.h b/contrib/llvm/tools/lli/RemoteJITUtils.h
index 89a5142..4e94841 100644
--- a/contrib/llvm/tools/lli/RemoteJITUtils.h
+++ b/contrib/llvm/tools/lli/RemoteJITUtils.h
@@ -84,7 +84,7 @@ public:
this->MemMgr = std::move(MemMgr);
}
- void setResolver(std::unique_ptr<JITSymbolResolver> Resolver) {
+ void setResolver(std::shared_ptr<JITSymbolResolver> Resolver) {
this->Resolver = std::move(Resolver);
}
@@ -118,9 +118,8 @@ public:
MemMgr->registerEHFrames(Addr, LoadAddr, Size);
}
- void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
- size_t Size) override {
- MemMgr->deregisterEHFrames(Addr, LoadAddr, Size);
+ void deregisterEHFrames() override {
+ MemMgr->deregisterEHFrames();
}
bool finalizeMemory(std::string *ErrMsg = nullptr) override {
@@ -146,7 +145,7 @@ public:
private:
std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr;
- std::unique_ptr<JITSymbolResolver> Resolver;
+ std::shared_ptr<JITSymbolResolver> Resolver;
};
}
diff --git a/contrib/llvm/tools/lli/lli.cpp b/contrib/llvm/tools/lli/lli.cpp
index 0823ff4..091ca22 100644
--- a/contrib/llvm/tools/lli/lli.cpp
+++ b/contrib/llvm/tools/lli/lli.cpp
@@ -606,8 +606,7 @@ int main(int argc, char **argv, char * const *envp) {
// If the program doesn't explicitly call exit, we will need the Exit
// function later on to make an explicit call, so get the function now.
Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context),
- Type::getInt32Ty(Context),
- nullptr);
+ Type::getInt32Ty(Context));
// Run static constructors.
if (!ForceInterpreter) {
@@ -647,7 +646,7 @@ int main(int argc, char **argv, char * const *envp) {
// else == "if (RemoteMCJIT)"
// Remote target MCJIT doesn't (yet) support static constructors. No reason
- // it couldn't. This is a limitation of the LLI implemantation, not the
+ // it couldn't. This is a limitation of the LLI implementation, not the
// MCJIT itself. FIXME.
// Lanch the remote process and get a channel to it.
diff --git a/contrib/llvm/tools/llvm-ar/llvm-ar.cpp b/contrib/llvm/tools/llvm-ar/llvm-ar.cpp
index b99a396..af4d3ef 100644
--- a/contrib/llvm/tools/llvm-ar/llvm-ar.cpp
+++ b/contrib/llvm/tools/llvm-ar/llvm-ar.cpp
@@ -16,7 +16,8 @@
#include "llvm/ADT/Triple.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
-#include "llvm/LibDriver/LibDriver.h"
+#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
+#include "llvm/ToolDrivers/llvm-lib/LibDriver.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/MachO.h"
@@ -52,7 +53,7 @@ static StringRef ToolName;
// Show the error message and exit.
LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) {
- outs() << ToolName << ": " << Error << ".\n";
+ errs() << ToolName << ": " << Error << ".\n";
exit(1);
}
@@ -87,13 +88,14 @@ static cl::opt<bool> MRI("M", cl::desc(""));
static cl::opt<std::string> Plugin("plugin", cl::desc("plugin (ignored for compatibility"));
namespace {
-enum Format { Default, GNU, BSD };
+enum Format { Default, GNU, BSD, DARWIN };
}
static cl::opt<Format>
FormatOpt("format", cl::desc("Archive format to create"),
cl::values(clEnumValN(Default, "default", "default"),
clEnumValN(GNU, "gnu", "gnu"),
+ clEnumValN(DARWIN, "darwin", "darwin"),
clEnumValN(BSD, "bsd", "bsd")));
static std::string Options;
@@ -167,7 +169,7 @@ LLVM_ATTRIBUTE_NORETURN static void
show_help(const std::string &msg) {
errs() << ToolName << ": " << msg << "\n\n";
cl::PrintHelpMessage();
- std::exit(1);
+ exit(1);
}
// Extract the member filename from the command line for the [relpos] argument
@@ -376,7 +378,9 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) {
sys::fs::perms Mode = ModeOrErr.get();
int FD;
- failIfError(sys::fs::openFileForWrite(Name, FD, sys::fs::F_None, Mode), Name);
+ failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD,
+ sys::fs::F_None, Mode),
+ Name);
{
raw_fd_ostream file(FD, false);
@@ -462,7 +466,7 @@ static void performReadOperation(ArchiveOperation Operation,
return;
for (StringRef Name : Members)
errs() << Name << " was not found\n";
- std::exit(1);
+ exit(1);
}
static void addMember(std::vector<NewArchiveMember> &Members,
@@ -470,6 +474,10 @@ static void addMember(std::vector<NewArchiveMember> &Members,
Expected<NewArchiveMember> NMOrErr =
NewArchiveMember::getFile(FileName, Deterministic);
failIfError(NMOrErr.takeError(), FileName);
+
+ // Use the basename of the object path for the member name.
+ NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
+
if (Pos == -1)
Members.push_back(std::move(*NMOrErr));
else
@@ -491,7 +499,7 @@ static void addMember(std::vector<NewArchiveMember> &Members,
enum InsertAction {
IA_AddOldMember,
- IA_AddNewMeber,
+ IA_AddNewMember,
IA_Delete,
IA_MoveOldMember,
IA_MoveNewMember
@@ -523,7 +531,7 @@ static InsertAction computeInsertAction(ArchiveOperation Operation,
StringRef PosName = sys::path::filename(RelPos);
if (!OnlyUpdate) {
if (PosName.empty())
- return IA_AddNewMeber;
+ return IA_AddNewMember;
return IA_MoveNewMember;
}
@@ -540,7 +548,7 @@ static InsertAction computeInsertAction(ArchiveOperation Operation,
}
if (PosName.empty())
- return IA_AddNewMeber;
+ return IA_AddNewMember;
return IA_MoveNewMember;
}
llvm_unreachable("No such operation");
@@ -577,7 +585,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
case IA_AddOldMember:
addMember(Ret, Child);
break;
- case IA_AddNewMeber:
+ case IA_AddNewMember:
addMember(Ret, *MemberI);
break;
case IA_Delete:
@@ -623,8 +631,9 @@ computeNewArchiveMembers(ArchiveOperation Operation,
}
static object::Archive::Kind getDefaultForHost() {
- return Triple(sys::getProcessTriple()).isOSDarwin() ? object::Archive::K_BSD
- : object::Archive::K_GNU;
+ return Triple(sys::getProcessTriple()).isOSDarwin()
+ ? object::Archive::K_DARWIN
+ : object::Archive::K_GNU;
}
static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
@@ -633,7 +642,7 @@ static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
if (OptionalObject)
return isa<object::MachOObjectFile>(**OptionalObject)
- ? object::Archive::K_BSD
+ ? object::Archive::K_DARWIN
: object::Archive::K_GNU;
// squelch the error in case we had a non-object file
@@ -672,6 +681,11 @@ performWriteOperation(ArchiveOperation Operation,
fail("Only the gnu format has a thin mode");
Kind = object::Archive::K_BSD;
break;
+ case DARWIN:
+ if (Thin)
+ fail("Only the gnu format has a thin mode");
+ Kind = object::Archive::K_DARWIN;
+ break;
}
std::pair<StringRef, std::error_code> Result =
@@ -850,6 +864,9 @@ int main(int argc, char **argv) {
llvm::InitializeAllAsmParsers();
StringRef Stem = sys::path::stem(ToolName);
+ if (Stem.find("dlltool") != StringRef::npos)
+ return dlltoolDriverMain(makeArrayRef(argv, argc));
+
if (Stem.find("ranlib") == StringRef::npos &&
Stem.find("lib") != StringRef::npos)
return libDriverMain(makeArrayRef(argv, argc));
@@ -865,5 +882,5 @@ int main(int argc, char **argv) {
return ranlib_main();
if (Stem.find("ar") != StringRef::npos)
return ar_main();
- fail("Not ranlib, ar or lib!");
+ fail("Not ranlib, ar, lib or dlltool!");
}
diff --git a/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index b84c4a8..529bdf5 100644
--- a/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -71,6 +71,10 @@ static cl::opt<bool>
ShowBinaryBlobs("show-binary-blobs",
cl::desc("Print binary blobs using hex escapes"));
+static cl::opt<std::string> CheckHash(
+ "check-hash",
+ cl::desc("Check module hash using the argument as a string table"));
+
namespace {
/// CurStreamTypeType - A type for CurStreamType
@@ -121,7 +125,11 @@ static const char *GetBlockName(unsigned BlockID,
case bitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID";
case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
return "GLOBALVAL_SUMMARY_BLOCK";
+ case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID:
+ return "FULL_LTO_GLOBALVAL_SUMMARY_BLOCK";
case bitc::MODULE_STRTAB_BLOCK_ID: return "MODULE_STRTAB_BLOCK";
+ case bitc::STRTAB_BLOCK_ID: return "STRTAB_BLOCK";
+ case bitc::SYMTAB_BLOCK_ID: return "SYMTAB_BLOCK";
}
}
@@ -171,7 +179,6 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(MODULE_CODE, GLOBALVAR)
STRINGIFY_CODE(MODULE_CODE, FUNCTION)
STRINGIFY_CODE(MODULE_CODE, ALIAS)
- STRINGIFY_CODE(MODULE_CODE, PURGEVALS)
STRINGIFY_CODE(MODULE_CODE, GCNAME)
STRINGIFY_CODE(MODULE_CODE, VSTOFFSET)
STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES_UNUSED)
@@ -298,6 +305,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(MST_CODE, HASH)
}
case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
+ case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID:
switch (CodeID) {
default:
return nullptr;
@@ -312,6 +320,13 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(FS, COMBINED_ORIGINAL_NAME)
STRINGIFY_CODE(FS, VERSION)
STRINGIFY_CODE(FS, TYPE_TESTS)
+ STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_VCALLS)
+ STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_VCALLS)
+ STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_CONST_VCALL)
+ STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL)
+ STRINGIFY_CODE(FS, VALUE_GUID)
+ STRINGIFY_CODE(FS, CFI_FUNCTION_DEFS)
+ STRINGIFY_CODE(FS, CFI_FUNCTION_DECLS)
}
case bitc::METADATA_ATTACHMENT_ID:
switch(CodeID) {
@@ -378,6 +393,16 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
default: return nullptr;
case bitc::OPERAND_BUNDLE_TAG: return "OPERAND_BUNDLE_TAG";
}
+ case bitc::STRTAB_BLOCK_ID:
+ switch(CodeID) {
+ default: return nullptr;
+ case bitc::STRTAB_BLOB: return "BLOB";
+ }
+ case bitc::SYMTAB_BLOCK_ID:
+ switch(CodeID) {
+ default: return nullptr;
+ case bitc::SYMTAB_BLOB: return "BLOB";
+ }
}
#undef STRINGIFY_CODE
}
@@ -631,13 +656,15 @@ static bool ParseBlock(BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo,
}
// If we found a module hash, let's verify that it matches!
- if (BlockID == bitc::MODULE_BLOCK_ID && Code == bitc::MODULE_CODE_HASH) {
+ if (BlockID == bitc::MODULE_BLOCK_ID && Code == bitc::MODULE_CODE_HASH &&
+ !CheckHash.empty()) {
if (Record.size() != 5)
outs() << " (invalid)";
else {
// Recompute the hash and compare it to the one in the bitcode
SHA1 Hasher;
StringRef Hash;
+ Hasher.update(CheckHash);
{
int BlockSize = (CurrentRecordPos / 8) - BlockEntryPos;
auto Ptr = Stream.getPointerToByte(BlockEntryPos, BlockSize);
diff --git a/contrib/llvm/tools/llvm-cov/CodeCoverage.cpp b/contrib/llvm/tools/llvm-cov/CodeCoverage.cpp
index 0a9807a..3cbd659 100644
--- a/contrib/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/contrib/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -15,6 +15,7 @@
#include "CoverageFilters.h"
#include "CoverageReport.h"
+#include "CoverageSummaryInfo.h"
#include "CoverageViewOptions.h"
#include "RenderingSupport.h"
#include "SourceCoverageView.h"
@@ -31,6 +32,7 @@
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/Threading.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/ToolOutputFile.h"
#include <functional>
@@ -98,9 +100,6 @@ private:
/// \brief If a demangler is available, demangle all symbol names.
void demangleSymbols(const CoverageMapping &Coverage);
- /// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym.
- StringRef getSymbolForHumans(StringRef Sym) const;
-
/// \brief Write out a source file view to the filesystem.
void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
CoveragePrinter *Printer, bool ShowFilenames);
@@ -136,10 +135,10 @@ private:
/// The architecture the coverage mapping data targets.
std::string CoverageArch;
- /// A cache for demangled symbol names.
- StringMap<std::string> DemangledNames;
+ /// A cache for demangled symbols.
+ DemangleCache DC;
- /// Errors and warnings which have not been printed.
+ /// A lock which guards printing to stderr.
std::mutex ErrsLock;
/// A container for input source file buffers.
@@ -267,7 +266,7 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
return nullptr;
auto Expansions = FunctionCoverage.getExpansions();
- auto View = SourceCoverageView::create(getSymbolForHumans(Function.Name),
+ auto View = SourceCoverageView::create(DC.demangle(Function.Name),
SourceBuffer.get(), ViewOpts,
std::move(FunctionCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
@@ -293,7 +292,7 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
for (const auto *Function : Coverage.getInstantiations(SourceFile)) {
std::unique_ptr<SourceCoverageView> SubView{nullptr};
- StringRef Funcname = getSymbolForHumans(Function->Name);
+ StringRef Funcname = DC.demangle(Function->Name);
if (Function->ExecutionCount > 0) {
auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
@@ -453,14 +452,9 @@ void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
// Cache the demangled names.
unsigned I = 0;
for (const auto &Function : Coverage.getCoveredFunctions())
- DemangledNames[Function.Name] = Symbols[I++];
-}
-
-StringRef CodeCoverageTool::getSymbolForHumans(StringRef Sym) const {
- const auto DemangledName = DemangledNames.find(Sym);
- if (DemangledName == DemangledNames.end())
- return Sym;
- return DemangledName->getValue();
+ // On Windows, lines in the demangler's output file end with "\r\n".
+ // Splitting by '\n' keeps '\r's, so cut them now.
+ DC.DemangledNames[Function.Name] = Symbols[I++].rtrim();
}
void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
@@ -712,6 +706,12 @@ int CodeCoverageTool::show(int argc, const char **argv,
"project-title", cl::Optional,
cl::desc("Set project title for the coverage report"));
+ cl::opt<unsigned> NumThreads(
+ "num-threads", cl::init(0),
+ cl::desc("Number of merge threads to use (default: autodetect)"));
+ cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
+ cl::aliasopt(NumThreads));
+
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
@@ -797,15 +797,19 @@ int CodeCoverageTool::show(int argc, const char **argv,
}
}
- // FIXME: Sink the hardware_concurrency() == 1 check into ThreadPool.
- if (!ViewOpts.hasOutputDirectory() ||
- std::thread::hardware_concurrency() == 1) {
+ // If NumThreads is not specified, auto-detect a good default.
+ if (NumThreads == 0)
+ NumThreads =
+ std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
+ unsigned(SourceFiles.size())));
+
+ if (!ViewOpts.hasOutputDirectory() || NumThreads == 1) {
for (const std::string &SourceFile : SourceFiles)
writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
ShowFilenames);
} else {
// In -output-dir mode, it's safe to use multiple threads to print files.
- ThreadPool Pool;
+ ThreadPool Pool(NumThreads);
for (const std::string &SourceFile : SourceFiles)
Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
Coverage.get(), Printer.get(), ShowFilenames);
@@ -817,22 +821,28 @@ int CodeCoverageTool::show(int argc, const char **argv,
int CodeCoverageTool::report(int argc, const char **argv,
CommandLineParserType commandLineParser) {
+ cl::opt<bool> ShowFunctionSummaries(
+ "show-functions", cl::Optional, cl::init(false),
+ cl::desc("Show coverage summaries for each function"));
+
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
- if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML)
+ if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
error("HTML output for summary reports is not yet supported.");
+ return 1;
+ }
auto Coverage = load();
if (!Coverage)
return 1;
CoverageReport Report(ViewOpts, *Coverage.get());
- if (SourceFiles.empty())
+ if (!ShowFunctionSummaries)
Report.renderFileReports(llvm::outs());
else
- Report.renderFunctionReports(SourceFiles, llvm::outs());
+ Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
return 0;
}
@@ -843,6 +853,11 @@ int CodeCoverageTool::export_(int argc, const char **argv,
if (Err)
return Err;
+ if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
+ error("Coverage data can only be exported as textual JSON.");
+ return 1;
+ }
+
auto Coverage = load();
if (!Coverage) {
error("Could not load coverage information");
diff --git a/contrib/llvm/tools/llvm-cov/CoverageReport.cpp b/contrib/llvm/tools/llvm-cov/CoverageReport.cpp
index e88cb18..c68bb90 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/contrib/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -118,19 +118,51 @@ raw_ostream::Colors determineCoveragePercentageColor(const T &Info) {
: raw_ostream::RED;
}
-/// \brief Determine the length of the longest common prefix of the strings in
-/// \p Strings.
-unsigned getLongestCommonPrefixLen(ArrayRef<std::string> Strings) {
- unsigned LCP = Strings[0].size();
- for (unsigned I = 1, E = Strings.size(); LCP > 0 && I < E; ++I) {
- unsigned Cursor;
- StringRef S = Strings[I];
- for (Cursor = 0; Cursor < LCP && Cursor < S.size(); ++Cursor)
- if (Strings[0][Cursor] != S[Cursor])
+/// \brief Get the number of redundant path components in each path in \p Paths.
+unsigned getNumRedundantPathComponents(ArrayRef<std::string> Paths) {
+ // To start, set the number of redundant path components to the maximum
+ // possible value.
+ SmallVector<StringRef, 8> FirstPathComponents{sys::path::begin(Paths[0]),
+ sys::path::end(Paths[0])};
+ unsigned NumRedundant = FirstPathComponents.size();
+
+ for (unsigned I = 1, E = Paths.size(); NumRedundant > 0 && I < E; ++I) {
+ StringRef Path = Paths[I];
+ for (const auto &Component :
+ enumerate(make_range(sys::path::begin(Path), sys::path::end(Path)))) {
+ // Do not increase the number of redundant components: that would remove
+ // useful parts of already-visited paths.
+ if (Component.index() >= NumRedundant)
break;
- LCP = std::min(LCP, Cursor);
+
+ // Lower the number of redundant components when there's a mismatch
+ // between the first path, and the path under consideration.
+ if (FirstPathComponents[Component.index()] != Component.value()) {
+ NumRedundant = Component.index();
+ break;
+ }
+ }
+ }
+
+ return NumRedundant;
+}
+
+/// \brief Determine the length of the longest redundant prefix of the paths in
+/// \p Paths.
+unsigned getRedundantPrefixLen(ArrayRef<std::string> Paths) {
+ // If there's at most one path, no path components are redundant.
+ if (Paths.size() <= 1)
+ return 0;
+
+ unsigned PrefixLen = 0;
+ unsigned NumRedundant = getNumRedundantPathComponents(Paths);
+ auto Component = sys::path::begin(Paths[0]);
+ for (unsigned I = 0; I < NumRedundant; ++I) {
+ auto LastComponent = Component;
+ ++Component;
+ PrefixLen += Component - LastComponent;
}
- return LCP;
+ return PrefixLen;
}
} // end anonymous namespace
@@ -200,12 +232,14 @@ void CoverageReport::render(const FileCoverageSummary &File,
}
void CoverageReport::render(const FunctionCoverageSummary &Function,
+ const DemangleCache &DC,
raw_ostream &OS) const {
auto FuncCoverageColor =
determineCoveragePercentageColor(Function.RegionCoverage);
auto LineCoverageColor =
determineCoveragePercentageColor(Function.LineCoverage);
- OS << column(Function.Name, FunctionReportColumns[0], Column::RightTrim)
+ OS << column(DC.demangle(Function.Name), FunctionReportColumns[0],
+ Column::RightTrim)
<< format("%*u", FunctionReportColumns[1],
(unsigned)Function.RegionCoverage.NumRegions);
Options.colored_ostream(OS, FuncCoverageColor)
@@ -230,6 +264,7 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
}
void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
+ const DemangleCache &DC,
raw_ostream &OS) {
bool isFirst = true;
for (StringRef Filename : Files) {
@@ -242,7 +277,7 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
std::vector<StringRef> Funcnames;
for (const auto &F : Functions)
- Funcnames.emplace_back(F.Name);
+ Funcnames.emplace_back(DC.demangle(F.Name));
adjustColumnWidths({}, Funcnames);
OS << "File '" << Filename << "':\n";
@@ -262,12 +297,12 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
++Totals.ExecutionCount;
Totals.RegionCoverage += Function.RegionCoverage;
Totals.LineCoverage += Function.LineCoverage;
- render(Function, OS);
+ render(Function, DC, OS);
}
if (Totals.ExecutionCount) {
renderDivider(FunctionReportColumns, OS);
OS << "\n";
- render(Totals, OS);
+ render(Totals, DC, OS);
}
}
}
@@ -277,9 +312,7 @@ CoverageReport::prepareFileReports(const coverage::CoverageMapping &Coverage,
FileCoverageSummary &Totals,
ArrayRef<std::string> Files) {
std::vector<FileCoverageSummary> FileReports;
- unsigned LCP = 0;
- if (Files.size() > 1)
- LCP = getLongestCommonPrefixLen(Files);
+ unsigned LCP = getRedundantPrefixLen(Files);
for (StringRef Filename : Files) {
FileCoverageSummary Summary(Filename.drop_front(LCP));
diff --git a/contrib/llvm/tools/llvm-cov/CoverageReport.h b/contrib/llvm/tools/llvm-cov/CoverageReport.h
index 7a41649..071be2e 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageReport.h
+++ b/contrib/llvm/tools/llvm-cov/CoverageReport.h
@@ -25,14 +25,16 @@ class CoverageReport {
const coverage::CoverageMapping &Coverage;
void render(const FileCoverageSummary &File, raw_ostream &OS) const;
- void render(const FunctionCoverageSummary &Function, raw_ostream &OS) const;
+ void render(const FunctionCoverageSummary &Function, const DemangleCache &DC,
+ raw_ostream &OS) const;
public:
CoverageReport(const CoverageViewOptions &Options,
const coverage::CoverageMapping &Coverage)
: Options(Options), Coverage(Coverage) {}
- void renderFunctionReports(ArrayRef<std::string> Files, raw_ostream &OS);
+ void renderFunctionReports(ArrayRef<std::string> Files,
+ const DemangleCache &DC, raw_ostream &OS);
/// Prepare file reports for the files specified in \p Files.
static std::vector<FileCoverageSummary>
diff --git a/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index c04a4d4..680fc37 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -160,6 +160,19 @@ struct FileCoverageSummary {
}
};
+/// \brief A cache for demangled symbols.
+struct DemangleCache {
+ StringMap<std::string> DemangledNames;
+
+ /// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym.
+ StringRef demangle(StringRef Sym) const {
+ const auto DemangledName = DemangledNames.find(Sym);
+ if (DemangledName == DemangledNames.end())
+ return Sym;
+ return DemangledName->getValue();
+ }
+};
+
} // namespace llvm
#endif // LLVM_COV_COVERAGESUMMARYINFO_H
diff --git a/contrib/llvm/tools/llvm-cov/TestingSupport.cpp b/contrib/llvm/tools/llvm-cov/TestingSupport.cpp
index 72768f4..4713d75 100644
--- a/contrib/llvm/tools/llvm-cov/TestingSupport.cpp
+++ b/contrib/llvm/tools/llvm-cov/TestingSupport.cpp
@@ -48,13 +48,16 @@ int convertForTestingMain(int argc, const char *argv[]) {
// Look for the sections that we are interested in.
int FoundSectionCount = 0;
SectionRef ProfileNames, CoverageMapping;
+ auto ObjFormat = OF->getTripleObjectFormat();
for (const auto &Section : OF->sections()) {
StringRef Name;
if (Section.getName(Name))
return 1;
- if (Name == llvm::getInstrProfNameSectionName(false)) {
+ if (Name == llvm::getInstrProfSectionName(IPSK_name, ObjFormat,
+ /*AddSegmentInfo=*/false)) {
ProfileNames = Section;
- } else if (Name == llvm::getInstrProfCoverageSectionName(false)) {
+ } else if (Name == llvm::getInstrProfSectionName(
+ IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false)) {
CoverageMapping = Section;
} else
continue;
diff --git a/contrib/llvm/tools/llvm-cov/gcov.cpp b/contrib/llvm/tools/llvm-cov/gcov.cpp
index 4652fed..4df7f01 100644
--- a/contrib/llvm/tools/llvm-cov/gcov.cpp
+++ b/contrib/llvm/tools/llvm-cov/gcov.cpp
@@ -74,7 +74,7 @@ static void reportCoverage(StringRef SourceFile, StringRef ObjectDir,
}
if (DumpGCOV)
- GF.dump();
+ GF.print(errs());
FileInfo FI(Options);
GF.collectLineCounts(FI);
diff --git a/contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
index 1e2797b..13024fb 100644
--- a/contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
+++ b/contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
@@ -8,29 +8,89 @@
//===----------------------------------------------------------------------===//
#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
#include <iostream>
using namespace llvm;
+enum Style {
+ Auto, ///< auto-detect mangling
+ GNU, ///< GNU
+ Lucid, ///< Lucid compiler (lcc)
+ ARM,
+ HP, ///< HP compiler (xCC)
+ EDG, ///< EDG compiler
+ GNUv3, ///< GNU C++ v3 ABI
+ Java, ///< Java (gcj)
+ GNAT ///< ADA copiler (gnat)
+};
+static cl::opt<Style>
+ Format("format", cl::desc("decoration style"),
+ cl::values(clEnumValN(Auto, "auto", "auto-detect style"),
+ clEnumValN(GNU, "gnu", "GNU (itanium) style")),
+ cl::init(Auto));
+static cl::alias FormatShort("s", cl::desc("alias for --format"),
+ cl::aliasopt(Format));
+
+static cl::opt<bool> StripUnderscore("strip-underscore",
+ cl::desc("strip the leading underscore"),
+ cl::init(false));
+static cl::alias StripUnderscoreShort("_",
+ cl::desc("alias for --strip-underscore"),
+ cl::aliasopt(StripUnderscore));
+
+static cl::opt<bool>
+ Types("types",
+ cl::desc("attempt to demangle types as well as function names"),
+ cl::init(false));
+static cl::alias TypesShort("t", cl::desc("alias for --types"),
+ cl::aliasopt(Types));
+
+static cl::list<std::string>
+Decorated(cl::Positional, cl::desc("<mangled>"), cl::ZeroOrMore);
+
static void demangle(llvm::raw_ostream &OS, const std::string &Mangled) {
int Status;
- char *Demangled = nullptr;
- if ((Mangled.size() >= 2 && Mangled.compare(0, 2, "_Z")) ||
- (Mangled.size() >= 4 && Mangled.compare(0, 4, "___Z")))
- Demangled = itaniumDemangle(Mangled.c_str(), nullptr, nullptr, &Status);
- OS << (Demangled ? Demangled : Mangled) << '\n';
- free(Demangled);
+
+ const char *Decorated = Mangled.c_str();
+ if (StripUnderscore)
+ if (Decorated[0] == '_')
+ ++Decorated;
+ size_t DecoratedLength = strlen(Decorated);
+
+ char *Undecorated = nullptr;
+
+ if (Types || ((DecoratedLength >= 2 && strncmp(Decorated, "_Z", 2) == 0) ||
+ (DecoratedLength >= 4 && strncmp(Decorated, "___Z", 4) == 0)))
+ Undecorated = itaniumDemangle(Decorated, nullptr, nullptr, &Status);
+
+ if (!Undecorated &&
+ (DecoratedLength > 6 && strncmp(Decorated, "__imp_", 6) == 0)) {
+ OS << "import thunk for ";
+ Undecorated = itaniumDemangle(Decorated + 6, nullptr, nullptr, &Status);
+ }
+
+ OS << (Undecorated ? Undecorated : Mangled) << '\n';
+
+ free(Undecorated);
}
int main(int argc, char **argv) {
- if (argc == 1)
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
+ PrettyStackTraceProgram X(argc, argv);
+
+ cl::ParseCommandLineOptions(argc, argv, "llvm symbol undecoration tool\n");
+
+ if (Decorated.empty())
for (std::string Mangled; std::getline(std::cin, Mangled);)
demangle(llvm::outs(), Mangled);
else
- for (int I = 1; I < argc; ++I)
- demangle(llvm::outs(), argv[I]);
+ for (const auto &Symbol : Decorated)
+ demangle(llvm::outs(), Symbol);
return EXIT_SUCCESS;
}
diff --git a/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp b/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
index 9078013..e167750 100644
--- a/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
+++ b/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
@@ -15,6 +15,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Debug.h"
using namespace llvm;
@@ -195,17 +196,17 @@ void DiffConsumer::logd(const DiffLogBuilder &Log) {
switch (Log.getLineKind(I)) {
case DC_match:
out << " ";
- Log.getLeft(I)->dump();
+ Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
//printValue(Log.getLeft(I), true);
break;
case DC_left:
out << "< ";
- Log.getLeft(I)->dump();
+ Log.getLeft(I)->print(dbgs()); dbgs() << '\n';
//printValue(Log.getLeft(I), true);
break;
case DC_right:
out << "> ";
- Log.getRight(I)->dump();
+ Log.getRight(I)->print(dbgs()); dbgs() << '\n';
//printValue(Log.getRight(I), false);
break;
}
diff --git a/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp b/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
index df208a2..95a63d7 100644
--- a/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
+++ b/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
@@ -315,17 +315,15 @@ class FunctionDifferenceEngine {
bool Difference = false;
DenseMap<ConstantInt*,BasicBlock*> LCases;
-
- for (SwitchInst::CaseIt I = LI->case_begin(), E = LI->case_end();
- I != E; ++I)
- LCases[I.getCaseValue()] = I.getCaseSuccessor();
-
- for (SwitchInst::CaseIt I = RI->case_begin(), E = RI->case_end();
- I != E; ++I) {
- ConstantInt *CaseValue = I.getCaseValue();
+ for (auto Case : LI->cases())
+ LCases[Case.getCaseValue()] = Case.getCaseSuccessor();
+
+ for (auto Case : RI->cases()) {
+ ConstantInt *CaseValue = Case.getCaseValue();
BasicBlock *LCase = LCases[CaseValue];
if (LCase) {
- if (TryUnify) tryUnify(LCase, I.getCaseSuccessor());
+ if (TryUnify)
+ tryUnify(LCase, Case.getCaseSuccessor());
LCases.erase(CaseValue);
} else if (Complain || !Difference) {
if (Complain)
diff --git a/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index 84fa0e4..ec5e554 100644
--- a/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -67,6 +67,7 @@ static cl::opt<DIDumpType> DumpType(
clEnumValN(DIDT_GnuPubnames, "gnu_pubnames", ".debug_gnu_pubnames"),
clEnumValN(DIDT_GnuPubtypes, "gnu_pubtypes", ".debug_gnu_pubtypes"),
clEnumValN(DIDT_Str, "str", ".debug_str"),
+ clEnumValN(DIDT_StrOffsets, "str_offsets", ".debug_str_offsets"),
clEnumValN(DIDT_StrDwo, "str.dwo", ".debug_str.dwo"),
clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo",
".debug_str_offsets.dwo"),
@@ -78,6 +79,13 @@ static cl::opt<bool>
SummarizeTypes("summarize-types",
cl::desc("Abbreviate the description of type unit entries"));
+static cl::opt<bool> Verify("verify", cl::desc("Verify the DWARF debug info"));
+
+static cl::opt<bool> Quiet("quiet",
+ cl::desc("Use with -verify to not emit to STDOUT."));
+
+static cl::opt<bool> Brief("brief", cl::desc("Print fewer low-level details"));
+
static void error(StringRef Filename, std::error_code EC) {
if (!EC)
return;
@@ -90,8 +98,14 @@ static void DumpObjectFile(ObjectFile &Obj, Twine Filename) {
outs() << Filename.str() << ":\tfile format " << Obj.getFileFormatName()
<< "\n\n";
+
+
// Dump the complete DWARF structure.
- DICtx->dump(outs(), DumpType, false, SummarizeTypes);
+ DIDumpOptions DumpOpts;
+ DumpOpts.DumpType = DumpType;
+ DumpOpts.SummarizeTypes = SummarizeTypes;
+ DumpOpts.Brief = Brief;
+ DICtx->dump(outs(), DumpOpts);
}
static void DumpInput(StringRef Filename) {
@@ -116,6 +130,46 @@ static void DumpInput(StringRef Filename) {
}
}
+static bool VerifyObjectFile(ObjectFile &Obj, Twine Filename) {
+ std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(Obj));
+
+ // Verify the DWARF and exit with non-zero exit status if verification
+ // fails.
+ raw_ostream &stream = Quiet ? nulls() : outs();
+ stream << "Verifying " << Filename.str() << ":\tfile format "
+ << Obj.getFileFormatName() << "\n";
+ bool Result = DICtx->verify(stream, DumpType);
+ if (Result)
+ stream << "No errors.\n";
+ else
+ stream << "Errors detected.\n";
+ return Result;
+}
+
+static bool VerifyInput(StringRef Filename) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
+ MemoryBuffer::getFileOrSTDIN(Filename);
+ error(Filename, BuffOrErr.getError());
+ std::unique_ptr<MemoryBuffer> Buff = std::move(BuffOrErr.get());
+
+ Expected<std::unique_ptr<Binary>> BinOrErr =
+ object::createBinary(Buff->getMemBufferRef());
+ if (!BinOrErr)
+ error(Filename, errorToErrorCode(BinOrErr.takeError()));
+
+ bool Result = true;
+ if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get()))
+ Result = VerifyObjectFile(*Obj, Filename);
+ else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get()))
+ for (auto &ObjForArch : Fat->objects()) {
+ auto MachOOrErr = ObjForArch.getAsObjectFile();
+ error(Filename, errorToErrorCode(MachOOrErr.takeError()));
+ if (!VerifyObjectFile(**MachOOrErr, Filename + " (" + ObjForArch.getArchFlagName() + ")"))
+ Result = false;
+ }
+ return Result;
+}
+
/// If the input path is a .dSYM bundle (as created by the dsymutil tool),
/// replace it with individual entries for each of the object files inside the
/// bundle otherwise return the input path.
@@ -168,7 +222,13 @@ int main(int argc, char **argv) {
Objects.insert(Objects.end(), Objs.begin(), Objs.end());
}
- std::for_each(Objects.begin(), Objects.end(), DumpInput);
+ if (Verify) {
+ // If we encountered errors during verify, exit with a non-zero exit status.
+ if (!std::all_of(Objects.begin(), Objects.end(), VerifyInput))
+ exit(1);
+ } else {
+ std::for_each(Objects.begin(), Objects.end(), DumpInput);
+ }
return EXIT_SUCCESS;
}
diff --git a/contrib/llvm/tools/llvm-extract/llvm-extract.cpp b/contrib/llvm/tools/llvm-extract/llvm-extract.cpp
index aa1eda2..d868db7 100644
--- a/contrib/llvm/tools/llvm-extract/llvm-extract.cpp
+++ b/contrib/llvm/tools/llvm-extract/llvm-extract.cpp
@@ -17,10 +17,11 @@
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IRPrintingPasses.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
-#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
@@ -50,6 +51,10 @@ Force("f", cl::desc("Enable binary output on terminals"));
static cl::opt<bool>
DeleteFn("delete", cl::desc("Delete specified Globals from Module"));
+static cl::opt<bool>
+ Recursive("recursive",
+ cl::desc("Recursively extract all called functions"));
+
// ExtractFuncs - The functions to extract from the module.
static cl::list<std::string>
ExtractFuncs("func", cl::desc("Specify function to extract"),
@@ -226,6 +231,34 @@ int main(int argc, char **argv) {
// Use *argv instead of argv[0] to work around a wrong GCC warning.
ExitOnError ExitOnErr(std::string(*argv) + ": error reading input: ");
+ if (Recursive) {
+ std::vector<llvm::Function *> Workqueue;
+ for (GlobalValue *GV : GVs) {
+ if (auto *F = dyn_cast<Function>(GV)) {
+ Workqueue.push_back(F);
+ }
+ }
+ while (!Workqueue.empty()) {
+ Function *F = &*Workqueue.back();
+ Workqueue.pop_back();
+ ExitOnErr(F->materialize());
+ for (auto &BB : *F) {
+ for (auto &I : BB) {
+ auto *CI = dyn_cast<CallInst>(&I);
+ if (!CI)
+ continue;
+ Function *CF = CI->getCalledFunction();
+ if (!CF)
+ continue;
+ if (CF->isDeclaration() || GVs.count(CF))
+ continue;
+ GVs.insert(CF);
+ Workqueue.push_back(CF);
+ }
+ }
+ }
+ }
+
auto Materialize = [&](GlobalValue &GV) { ExitOnErr(GV.materialize()); };
// Materialize requisite global values.
diff --git a/contrib/llvm/tools/llvm-link/llvm-link.cpp b/contrib/llvm/tools/llvm-link/llvm-link.cpp
index e89696e..568e5f8 100644
--- a/contrib/llvm/tools/llvm-link/llvm-link.cpp
+++ b/contrib/llvm/tools/llvm-link/llvm-link.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/AutoUpgrade.h"
#include "llvm/IR/DiagnosticInfo.h"
@@ -23,7 +24,6 @@
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker/Linker.h"
-#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
@@ -34,6 +34,7 @@
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Transforms/IPO/FunctionImport.h"
+#include "llvm/Transforms/IPO/Internalize.h"
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
#include <memory>
@@ -272,6 +273,8 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
unsigned Flags) {
// Filter out flags that don't apply to the first file we load.
unsigned ApplicableFlags = Flags & Linker::Flags::OverrideFromSrc;
+ // Similar to some flags, internalization doesn't apply to the first file.
+ bool InternalizeLinkedSymbols = false;
for (const auto &File : Files) {
std::unique_ptr<Module> M = loadFile(argv0, File, Context);
if (!M.get()) {
@@ -297,7 +300,7 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
// does not do the ThinLink that would normally determine what values to
// promote.
for (auto &I : *Index) {
- for (auto &S : I.second) {
+ for (auto &S : I.second.SummaryList) {
if (GlobalValue::isLocalLinkage(S->linkage()))
S->setLinkage(GlobalValue::ExternalLinkage);
}
@@ -311,8 +314,24 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
if (Verbose)
errs() << "Linking in '" << File << "'\n";
- if (L.linkInModule(std::move(M), ApplicableFlags))
+ bool Err = false;
+ if (InternalizeLinkedSymbols) {
+ Err = L.linkInModule(
+ std::move(M), ApplicableFlags, [](Module &M, const StringSet<> &GVS) {
+ internalizeModule(M, [&GVS](const GlobalValue &GV) {
+ return !GV.hasName() || (GVS.count(GV.getName()) == 0);
+ });
+ });
+ } else {
+ Err = L.linkInModule(std::move(M), ApplicableFlags);
+ }
+
+ if (Err)
return false;
+
+ // Internalization applies to linking of subsequent files.
+ InternalizeLinkedSymbols = Internalize;
+
// All linker flags apply to linking of subsequent files.
ApplicableFlags = Flags;
}
@@ -340,8 +359,6 @@ int main(int argc, char **argv) {
Linker L(*Composite);
unsigned Flags = Linker::Flags::None;
- if (Internalize)
- Flags |= Linker::Flags::InternalizeLinkedSymbols;
if (OnlyNeeded)
Flags |= Linker::Flags::LinkOnlyNeeded;
diff --git a/contrib/llvm/tools/llvm-lto/llvm-lto.cpp b/contrib/llvm/tools/llvm-lto/llvm-lto.cpp
index 475350c..87cd13a 100644
--- a/contrib/llvm/tools/llvm-lto/llvm-lto.cpp
+++ b/contrib/llvm/tools/llvm-lto/llvm-lto.cpp
@@ -23,7 +23,6 @@
#include "llvm/LTO/legacy/LTOCodeGenerator.h"
#include "llvm/LTO/legacy/LTOModule.h"
#include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"
-#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
@@ -63,6 +62,10 @@ static cl::opt<bool> DisableLTOVectorization(
"disable-lto-vectorization", cl::init(false),
cl::desc("Do not run loop or slp vectorization during LTO"));
+static cl::opt<bool> EnableFreestanding(
+ "lto-freestanding", cl::init(false),
+ cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"));
+
static cl::opt<bool> UseDiagnosticHandler(
"use-diagnostic-handler", cl::init(false),
cl::desc("Use a diagnostic handler to test the handler interface"));
@@ -281,7 +284,7 @@ void printIndexStats() {
unsigned Calls = 0, Refs = 0, Functions = 0, Alias = 0, Globals = 0;
for (auto &Summaries : *Index) {
- for (auto &Summary : Summaries.second) {
+ for (auto &Summary : Summaries.second.SummaryList) {
Refs += Summary->refs().size();
if (auto *FuncSummary = dyn_cast<FunctionSummary>(Summary.get())) {
Functions++;
@@ -328,12 +331,9 @@ static void createCombinedModuleSummaryIndex() {
uint64_t NextModuleId = 0;
for (auto &Filename : InputFilenames) {
ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
- std::unique_ptr<ModuleSummaryIndex> Index =
- ExitOnErr(llvm::getModuleSummaryIndexForFile(Filename));
- // Skip files without a module summary.
- if (!Index)
- continue;
- CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
+ std::unique_ptr<MemoryBuffer> MB =
+ ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));
+ ExitOnErr(readModuleSummaryIndex(*MB, CombinedIndex, ++NextModuleId));
}
std::error_code EC;
assert(!OutputFilename.empty());
@@ -383,7 +383,7 @@ loadAllFilesForIndex(const ModuleSummaryIndex &Index) {
for (auto &ModPath : Index.modulePaths()) {
const auto &Filename = ModPath.first();
- auto CurrentActivity = "loading file '" + Filename + "'";
+ std::string CurrentActivity = ("loading file '" + Filename + "'").str();
auto InputOrErr = MemoryBuffer::getFile(Filename);
error(InputOrErr, "error " + CurrentActivity);
InputBuffers.push_back(std::move(*InputOrErr));
@@ -433,6 +433,7 @@ public:
ThinGenerator.setCodePICModel(getRelocModel());
ThinGenerator.setTargetOptions(Options);
ThinGenerator.setCacheDir(ThinLTOCacheDir);
+ ThinGenerator.setFreestanding(EnableFreestanding);
// Add all the exported symbols to the table of symbols to preserve.
for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
@@ -474,7 +475,7 @@ private:
std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
for (unsigned i = 0; i < InputFilenames.size(); ++i) {
auto &Filename = InputFilenames[i];
- StringRef CurrentActivity = "loading file '" + Filename + "'";
+ std::string CurrentActivity = "loading file '" + Filename + "'";
auto InputOrErr = MemoryBuffer::getFile(Filename);
error(InputOrErr, "error " + CurrentActivity);
InputBuffers.push_back(std::move(*InputOrErr));
@@ -668,24 +669,30 @@ private:
if (!ThinLTOIndex.empty())
errs() << "Warning: -thinlto-index ignored for codegen stage";
+ std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
for (auto &Filename : InputFilenames) {
LLVMContext Ctx;
- auto TheModule = loadModule(Filename, Ctx);
-
- auto Buffer = ThinGenerator.codegen(*TheModule);
+ auto InputOrErr = MemoryBuffer::getFile(Filename);
+ error(InputOrErr, "error " + CurrentActivity);
+ InputBuffers.push_back(std::move(*InputOrErr));
+ ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
+ }
+ ThinGenerator.setCodeGenOnly(true);
+ ThinGenerator.run();
+ for (auto BinName :
+ zip(ThinGenerator.getProducedBinaries(), InputFilenames)) {
std::string OutputName = OutputFilename;
- if (OutputName.empty()) {
- OutputName = Filename + ".thinlto.o";
- }
- if (OutputName == "-") {
- outs() << Buffer->getBuffer();
+ if (OutputName.empty())
+ OutputName = std::get<1>(BinName) + ".thinlto.o";
+ else if (OutputName == "-") {
+ outs() << std::get<0>(BinName)->getBuffer();
return;
}
std::error_code EC;
raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::F_None);
error(EC, "error opening the file '" + OutputName + "'");
- OS << Buffer->getBuffer();
+ OS << std::get<0>(BinName)->getBuffer();
}
}
@@ -703,7 +710,7 @@ private:
std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
for (unsigned i = 0; i < InputFilenames.size(); ++i) {
auto &Filename = InputFilenames[i];
- StringRef CurrentActivity = "loading file '" + Filename + "'";
+ std::string CurrentActivity = "loading file '" + Filename + "'";
auto InputOrErr = MemoryBuffer::getFile(Filename);
error(InputOrErr, "error " + CurrentActivity);
InputBuffers.push_back(std::move(*InputOrErr));
@@ -809,6 +816,7 @@ int main(int argc, char **argv) {
CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
CodeGen.setCodePICModel(getRelocModel());
+ CodeGen.setFreestanding(EnableFreestanding);
CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
CodeGen.setTargetOptions(Options);
diff --git a/contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp b/contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp
index c09311a..5426e04 100644
--- a/contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -16,17 +16,18 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/LTO/Caching.h"
+#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Caching.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Threading.h"
using namespace llvm;
using namespace lto;
-using namespace object;
static cl::opt<char>
OptLevel("O", cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
@@ -90,11 +91,25 @@ static cl::opt<std::string> DefaultTriple(
cl::desc(
"Replace unspecified target triples in input files with this triple"));
+static cl::opt<std::string>
+ OptRemarksOutput("pass-remarks-output",
+ cl::desc("YAML output file for optimization remarks"));
+
+static cl::opt<bool> OptRemarksWithHotness(
+ "pass-remarks-with-hotness",
+ cl::desc("Whether to include hotness informations in the remarks.\n"
+ "Has effect only if -pass-remarks-output is specified."));
+
+static cl::opt<bool>
+ UseNewPM("use-new-pm",
+ cl::desc("Run LTO passes using the new pass manager"),
+ cl::init(false), cl::Hidden);
+
static void check(Error E, std::string Msg) {
if (!E)
return;
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
- errs() << "llvm-lto: " << Msg << ": " << EIB.message().c_str() << '\n';
+ errs() << "llvm-lto2: " << Msg << ": " << EIB.message().c_str() << '\n';
});
exit(1);
}
@@ -117,12 +132,12 @@ template <typename T> static T check(ErrorOr<T> E, std::string Msg) {
return T();
}
-int main(int argc, char **argv) {
- InitializeAllTargets();
- InitializeAllTargetMCs();
- InitializeAllAsmPrinters();
- InitializeAllAsmParsers();
+static int usage() {
+ errs() << "Available subcommands: dump-symtab run\n";
+ return 1;
+}
+static int run(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");
// FIXME: Workaround PR30396 which means that a symbol can appear
@@ -148,9 +163,13 @@ int main(int argc, char **argv) {
Res.FinalDefinitionInLinkageUnit = true;
else if (C == 'x')
Res.VisibleToRegularObj = true;
- else
+ else if (C == 'r')
+ Res.LinkerRedefined = true;
+ else {
llvm::errs() << "invalid character " << C << " in resolution: " << R
<< '\n';
+ return 1;
+ }
}
CommandLineResolutions[{FileName, SymbolName}].push_back(Res);
}
@@ -176,11 +195,16 @@ int main(int argc, char **argv) {
check(Conf.addSaveTemps(OutputFilename + "."),
"Config::addSaveTemps failed");
+ // Optimization remarks.
+ Conf.RemarksFilename = OptRemarksOutput;
+ Conf.RemarksWithHotness = OptRemarksWithHotness;
+
// Run a custom pipeline, if asked for.
Conf.OptPipeline = OptPipeline;
Conf.AAPipeline = AAPipeline;
Conf.OptLevel = OptLevel - '0';
+ Conf.UseNewPM = UseNewPM;
switch (CGOptLevel) {
case '0':
Conf.CGOptLevel = CodeGenOpt::None;
@@ -199,6 +223,9 @@ int main(int argc, char **argv) {
return 1;
}
+ if (FileType.getNumOccurrences())
+ Conf.CGFileType = FileType;
+
Conf.OverrideTriple = OverrideTriple;
Conf.DefaultTriple = DefaultTriple;
@@ -257,18 +284,103 @@ int main(int argc, char **argv) {
return llvm::make_unique<lto::NativeObjectStream>(std::move(S));
};
- auto AddFile = [&](size_t Task, StringRef Path) {
- auto ReloadedBufferOrErr = MemoryBuffer::getFile(Path);
- if (auto EC = ReloadedBufferOrErr.getError())
- report_fatal_error(Twine("Can't reload cached file '") + Path + "': " +
- EC.message() + "\n");
-
- *AddStream(Task)->OS << (*ReloadedBufferOrErr)->getBuffer();
+ auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ *AddStream(Task)->OS << MB->getBuffer();
};
NativeObjectCache Cache;
if (!CacheDir.empty())
- Cache = localCache(CacheDir, AddFile);
+ Cache = check(localCache(CacheDir, AddBuffer), "failed to create cache");
check(Lto.run(AddStream, Cache), "LTO::run failed");
+ return 0;
+}
+
+static int dumpSymtab(int argc, char **argv) {
+ for (StringRef F : make_range(argv + 1, argv + argc)) {
+ std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);
+ BitcodeFileContents BFC = check(getBitcodeFileContents(*MB), F);
+
+ if (BFC.Symtab.size() >= sizeof(irsymtab::storage::Header)) {
+ auto *Hdr = reinterpret_cast<const irsymtab::storage::Header *>(
+ BFC.Symtab.data());
+ outs() << "version: " << Hdr->Version << '\n';
+ if (Hdr->Version == irsymtab::storage::Header::kCurrentVersion)
+ outs() << "producer: " << Hdr->Producer.get(BFC.StrtabForSymtab)
+ << '\n';
+ }
+
+ std::unique_ptr<InputFile> Input =
+ check(InputFile::create(MB->getMemBufferRef()), F);
+
+ outs() << "target triple: " << Input->getTargetTriple() << '\n';
+ Triple TT(Input->getTargetTriple());
+
+ outs() << "source filename: " << Input->getSourceFileName() << '\n';
+
+ if (TT.isOSBinFormatCOFF())
+ outs() << "linker opts: " << Input->getCOFFLinkerOpts() << '\n';
+
+ std::vector<StringRef> ComdatTable = Input->getComdatTable();
+ for (const InputFile::Symbol &Sym : Input->symbols()) {
+ switch (Sym.getVisibility()) {
+ case GlobalValue::HiddenVisibility:
+ outs() << 'H';
+ break;
+ case GlobalValue::ProtectedVisibility:
+ outs() << 'P';
+ break;
+ case GlobalValue::DefaultVisibility:
+ outs() << 'D';
+ break;
+ }
+
+ auto PrintBool = [&](char C, bool B) { outs() << (B ? C : '-'); };
+ PrintBool('U', Sym.isUndefined());
+ PrintBool('C', Sym.isCommon());
+ PrintBool('W', Sym.isWeak());
+ PrintBool('I', Sym.isIndirect());
+ PrintBool('O', Sym.canBeOmittedFromSymbolTable());
+ PrintBool('T', Sym.isTLS());
+ PrintBool('X', Sym.isExecutable());
+ outs() << ' ' << Sym.getName() << '\n';
+
+ if (Sym.isCommon())
+ outs() << " size " << Sym.getCommonSize() << " align "
+ << Sym.getCommonAlignment() << '\n';
+
+ int Comdat = Sym.getComdatIndex();
+ if (Comdat != -1)
+ outs() << " comdat " << ComdatTable[Comdat] << '\n';
+
+ if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect())
+ outs() << " fallback " << Sym.getCOFFWeakExternalFallback() << '\n';
+ }
+
+ outs() << '\n';
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+
+ // FIXME: This should use llvm::cl subcommands, but it isn't currently
+ // possible to pass an argument not associated with a subcommand to a
+ // subcommand (e.g. -use-new-pm).
+ if (argc < 2)
+ return usage();
+
+ StringRef Subcommand = argv[1];
+ // Ensure that argv[0] is correct after adjusting argv/argc.
+ argv[1] = argv[0];
+ if (Subcommand == "dump-symtab")
+ return dumpSymtab(argc - 1, argv + 1);
+ if (Subcommand == "run")
+ return run(argc - 1, argv + 1);
+ return usage();
}
diff --git a/contrib/llvm/tools/llvm-mc/llvm-mc.cpp b/contrib/llvm/tools/llvm-mc/llvm-mc.cpp
index 497fb19..8782588 100644
--- a/contrib/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/contrib/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -56,17 +56,15 @@ static cl::opt<bool> RelaxELFRel(
"relax-relocations", cl::init(true),
cl::desc("Emit R_X86_64_GOTPCRELX instead of R_X86_64_GOTPCREL"));
-static cl::opt<DebugCompressionType>
-CompressDebugSections("compress-debug-sections", cl::ValueOptional,
- cl::init(DebugCompressionType::DCT_None),
- cl::desc("Choose DWARF debug sections compression:"),
- cl::values(
- clEnumValN(DebugCompressionType::DCT_None, "none",
- "No compression"),
- clEnumValN(DebugCompressionType::DCT_Zlib, "zlib",
- "Use zlib compression"),
- clEnumValN(DebugCompressionType::DCT_ZlibGnu, "zlib-gnu",
- "Use zlib-gnu compression (deprecated)")));
+static cl::opt<DebugCompressionType> CompressDebugSections(
+ "compress-debug-sections", cl::ValueOptional,
+ cl::init(DebugCompressionType::None),
+ cl::desc("Choose DWARF debug sections compression:"),
+ cl::values(clEnumValN(DebugCompressionType::None, "none", "No compression"),
+ clEnumValN(DebugCompressionType::Z, "zlib",
+ "Use zlib compression"),
+ clEnumValN(DebugCompressionType::GNU, "zlib-gnu",
+ "Use zlib-gnu compression (deprecated)")));
static cl::opt<bool>
ShowInst("show-inst", cl::desc("Show internal instruction representation"));
@@ -494,7 +492,7 @@ int main(int argc, char **argv) {
MAI->setRelaxELFRelocations(RelaxELFRel);
- if (CompressDebugSections != DebugCompressionType::DCT_None) {
+ if (CompressDebugSections != DebugCompressionType::None) {
if (!zlib::isAvailable()) {
errs() << ProgName
<< ": build tools with zlib to enable -compress-debug-sections";
@@ -516,7 +514,7 @@ int main(int argc, char **argv) {
Ctx.setGenDwarfForAssembly(GenDwarfForAssembly);
// Default to 4 for dwarf version.
unsigned DwarfVersion = MCOptions.DwarfVersion ? MCOptions.DwarfVersion : 4;
- if (DwarfVersion < 2 || DwarfVersion > 4) {
+ if (DwarfVersion < 2 || DwarfVersion > 5) {
errs() << ProgName << ": Dwarf version " << DwarfVersion
<< " is not supported." << '\n';
return 1;
diff --git a/contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp b/contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp
index 6c2e364..58cede1 100644
--- a/contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp
+++ b/contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp
@@ -59,9 +59,12 @@ int main(int argc, char **argv) {
ExitOnErr(errorCodeToError(EC));
if (BinaryExtract) {
- SmallVector<char, 0> Header;
- BitcodeWriter Writer(Header);
- Out->os() << Header << Ms[ModuleIndex].getBuffer();
+ SmallVector<char, 0> Result;
+ BitcodeWriter Writer(Result);
+ Result.append(Ms[ModuleIndex].getBuffer().begin(),
+ Ms[ModuleIndex].getBuffer().end());
+ Writer.copyStrtab(Ms[ModuleIndex].getStrtab());
+ Out->os() << Result;
Out->keep();
return 0;
}
diff --git a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp
index aa89f89..ea47891 100644
--- a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -17,6 +17,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalVariable.h"
@@ -24,12 +26,13 @@
#include "llvm/IR/Module.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/COFF.h"
+#include "llvm/Object/Wasm.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
@@ -46,6 +49,7 @@
#include <cstring>
#include <system_error>
#include <vector>
+#include <string.h>
using namespace llvm;
using namespace object;
@@ -121,6 +125,10 @@ cl::opt<bool> NoSort("no-sort", cl::desc("Show symbols in order encountered"));
cl::alias NoSortp("p", cl::desc("Alias for --no-sort"), cl::aliasopt(NoSort),
cl::Grouping);
+cl::opt<bool> Demangle("demangle", cl::desc("Demangle C++ symbol names"));
+cl::alias DemangleC("C", cl::desc("Alias for --demangle"), cl::aliasopt(Demangle),
+ cl::Grouping);
+
cl::opt<bool> ReverseSort("reverse-sort", cl::desc("Sort in reverse order"));
cl::alias ReverseSortr("r", cl::desc("Alias for --reverse-sort"),
cl::aliasopt(ReverseSort), cl::Grouping);
@@ -129,6 +137,7 @@ cl::opt<bool> PrintSize("print-size",
cl::desc("Show symbol size instead of address"));
cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"),
cl::aliasopt(PrintSize), cl::Grouping);
+bool MachOPrintSizeWarning = false;
cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size"));
@@ -164,6 +173,15 @@ cl::list<std::string> SegSect("s", cl::Positional, cl::ZeroOrMore,
cl::opt<bool> FormatMachOasHex("x", cl::desc("Print symbol entry in hex, "
"Mach-O only"), cl::Grouping);
+cl::opt<bool> AddDyldInfo("add-dyldinfo",
+ cl::desc("Add symbols from the dyldinfo not already "
+ "in the symbol table, Mach-O only"));
+cl::opt<bool> NoDyldInfo("no-dyldinfo",
+ cl::desc("Don't add any symbols from the dyldinfo, "
+ "Mach-O only"));
+cl::opt<bool> DyldInfoOnly("dyldinfo-only",
+ cl::desc("Show only symbols from the dyldinfo, "
+ "Mach-O only"));
cl::opt<bool> NoLLVMBitcode("no-llvm-bc",
cl::desc("Disable LLVM bitcode reader"));
@@ -244,6 +262,17 @@ struct NMSymbol {
char TypeChar;
StringRef Name;
BasicSymbolRef Sym;
+ // The Sym field above points to the native symbol in the object file,
+ // for Mach-O when we are creating symbols from the dyld info the above
+ // pointer is null as there is no native symbol. In these cases the fields
+ // below are filled in to represent what would have been a Mach-O nlist
+ // native symbol.
+ uint32_t SymFlags;
+ SectionRef Section;
+ uint8_t NType;
+ uint8_t NSect;
+ uint16_t NDesc;
+ StringRef IndirectName;
};
} // anonymous namespace
@@ -267,7 +296,9 @@ static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) {
static char isSymbolList64Bit(SymbolicFile &Obj) {
if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj))
return Triple(IRObj->getTargetTriple()).isArch64Bit();
- if (isa<COFFObjectFile>(Obj))
+ if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj))
+ return false;
+ if (isa<WasmObjectFile>(Obj))
return false;
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
return MachO->is64Bit();
@@ -326,22 +357,38 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
H_64 = MachO->MachOObjectFile::getHeader64();
Filetype = H_64.filetype;
Flags = H_64.flags;
- MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
- NType = STE_64.n_type;
- NSect = STE_64.n_sect;
- NDesc = STE_64.n_desc;
- NStrx = STE_64.n_strx;
- NValue = STE_64.n_value;
+ if (SymDRI.p){
+ MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
+ NType = STE_64.n_type;
+ NSect = STE_64.n_sect;
+ NDesc = STE_64.n_desc;
+ NStrx = STE_64.n_strx;
+ NValue = STE_64.n_value;
+ } else {
+ NType = I->NType;
+ NSect = I->NSect;
+ NDesc = I->NDesc;
+ NStrx = 0;
+ NValue = I->Address;
+ }
} else {
H = MachO->MachOObjectFile::getHeader();
Filetype = H.filetype;
Flags = H.flags;
- MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
- NType = STE.n_type;
- NSect = STE.n_sect;
- NDesc = STE.n_desc;
- NStrx = STE.n_strx;
- NValue = STE.n_value;
+ if (SymDRI.p){
+ MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
+ NType = STE.n_type;
+ NSect = STE.n_sect;
+ NDesc = STE.n_desc;
+ NStrx = STE.n_strx;
+ NValue = STE.n_value;
+ } else {
+ NType = I->NType;
+ NSect = I->NSect;
+ NDesc = I->NDesc;
+ NStrx = 0;
+ NValue = I->Address;
+ }
}
}
@@ -358,7 +405,22 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
outs() << Str << ' ';
format("%08x", NStrx).print(Str, sizeof(Str));
outs() << Str << ' ';
- outs() << I->Name << "\n";
+ outs() << I->Name;
+ if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
+ outs() << " (indirect for ";
+ format(printFormat, NValue).print(Str, sizeof(Str));
+ outs() << Str << ' ';
+ StringRef IndirectName;
+ if (I->Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ outs() << "?)";
+ else
+ outs() << IndirectName << ")";
+ }
+ else
+ outs() << I->IndirectName << ")";
+ }
+ outs() << "\n";
return;
}
@@ -414,14 +476,19 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
outs() << "(?,?) ";
break;
}
- Expected<section_iterator> SecOrErr =
- MachO->getSymbolSection(I->Sym.getRawDataRefImpl());
- if (!SecOrErr) {
- consumeError(SecOrErr.takeError());
- outs() << "(?,?) ";
- break;
+ section_iterator Sec = SectionRef();
+ if (I->Sym.getRawDataRefImpl().p) {
+ Expected<section_iterator> SecOrErr =
+ MachO->getSymbolSection(I->Sym.getRawDataRefImpl());
+ if (!SecOrErr) {
+ consumeError(SecOrErr.takeError());
+ outs() << "(?,?) ";
+ break;
+ }
+ Sec = *SecOrErr;
+ } else {
+ Sec = I->Section;
}
- section_iterator Sec = *SecOrErr;
DataRefImpl Ref = Sec->getRawDataRefImpl();
StringRef SectionName;
MachO->getSectionName(Ref, SectionName);
@@ -480,11 +547,17 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
outs() << I->Name << " (for ";
StringRef IndirectName;
- if (!MachO ||
- MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ if (MachO) {
+ if (I->Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ outs() << "?)";
+ else
+ outs() << IndirectName << ")";
+ }
+ else
+ outs() << I->IndirectName << ")";
+ } else
outs() << "?)";
- else
- outs() << IndirectName << ")";
} else
outs() << I->Name;
@@ -591,6 +664,24 @@ static void darwinPrintStab(MachOObjectFile *MachO, SymbolListT::iterator I) {
outs() << Str;
}
+static Optional<std::string> demangle(StringRef Name, bool StripUnderscore) {
+ if (StripUnderscore && Name.size() > 0 && Name[0] == '_')
+ Name = Name.substr(1);
+
+ if (!Name.startswith("_Z"))
+ return None;
+
+ int Status;
+ char *Undecorated =
+ itaniumDemangle(Name.str().c_str(), nullptr, nullptr, &Status);
+ if (Status != 0)
+ return None;
+
+ std::string S(Undecorated);
+ free(Undecorated);
+ return S;
+}
+
static bool symbolIsDefined(const NMSymbol &Sym) {
return Sym.TypeChar != 'U' && Sym.TypeChar != 'w' && Sym.TypeChar != 'v';
}
@@ -655,7 +746,18 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
for (SymbolListT::iterator I = SymbolList.begin(), E = SymbolList.end();
I != E; ++I) {
- uint32_t SymFlags = I->Sym.getFlags();
+ uint32_t SymFlags;
+ std::string Name = I->Name.str();
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
+ if (Demangle) {
+ if (Optional<std::string> Opt = demangle(I->Name, MachO))
+ Name = *Opt;
+ }
+ if (I->Sym.getRawDataRefImpl().p)
+ SymFlags = I->Sym.getFlags();
+ else
+ SymFlags = I->SymFlags;
+
bool Undefined = SymFlags & SymbolRef::SF_Undefined;
bool Global = SymFlags & SymbolRef::SF_Global;
if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) ||
@@ -672,9 +774,10 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
outs() << CurrentFilename << ": ";
}
}
- if ((JustSymbolName || (UndefinedOnly && isa<MachOObjectFile>(Obj) &&
- OutputFormat != darwin)) && OutputFormat != posix) {
- outs() << I->Name << "\n";
+ if ((JustSymbolName ||
+ (UndefinedOnly && MachO && OutputFormat != darwin)) &&
+ OutputFormat != posix) {
+ outs() << Name << "\n";
continue;
}
@@ -698,6 +801,8 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
if (symbolIsDefined(*I)) {
if (Obj.isIR())
strcpy(SymbolAddrStr, printDashes);
+ else if(MachO && I->TypeChar == 'I')
+ strcpy(SymbolAddrStr, printBlanks);
else
format(printFormat, I->Address)
.print(SymbolAddrStr, sizeof(SymbolAddrStr));
@@ -709,12 +814,11 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
// nm(1) -m output or hex, else if OutputFormat is darwin or we are
// printing Mach-O symbols in hex and not a Mach-O object fall back to
// OutputFormat bsd (see below).
- MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) {
darwinPrintSymbol(Obj, I, SymbolAddrStr, printBlanks, printDashes,
printFormat);
} else if (OutputFormat == posix) {
- outs() << I->Name << " " << I->TypeChar << " ";
+ outs() << Name << " " << I->TypeChar << " ";
if (MachO)
outs() << SymbolAddrStr << " " << "0" /* SymbolSizeStr */ << "\n";
else
@@ -729,9 +833,21 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
outs() << I->TypeChar;
if (I->TypeChar == '-' && MachO)
darwinPrintStab(MachO, I);
- outs() << " " << I->Name << "\n";
+ outs() << " " << Name;
+ if (I->TypeChar == 'I' && MachO) {
+ outs() << " (indirect for ";
+ if (I->Sym.getRawDataRefImpl().p) {
+ StringRef IndirectName;
+ if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ outs() << "?)";
+ else
+ outs() << IndirectName << ")";
+ } else
+ outs() << I->IndirectName << ")";
+ }
+ outs() << "\n";
} else if (OutputFormat == sysv) {
- std::string PaddedName(I->Name);
+ std::string PaddedName(Name);
while (PaddedName.length() < 20)
PaddedName += " ";
outs() << PaddedName << "|" << SymbolAddrStr << "| " << I->TypeChar
@@ -845,6 +961,18 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
return '?';
}
+static char getSymbolNMTypeChar(COFFImportFile &Obj) {
+ switch (Obj.getCOFFImportHeader()->getType()) {
+ case COFF::IMPORT_CODE:
+ return 't';
+ case COFF::IMPORT_DATA:
+ return 'd';
+ case COFF::IMPORT_CONST:
+ return 'r';
+ }
+ return '?';
+}
+
static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
DataRefImpl Symb = I->getRawDataRefImpl();
uint8_t NType = Obj.is64Bit() ? Obj.getSymbol64TableEntry(Symb).n_type
@@ -882,6 +1010,13 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
return '?';
}
+static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) {
+ uint32_t Flags = I->getFlags();
+ if (Flags & SymbolRef::SF_Executable)
+ return 't';
+ return 'd';
+}
+
static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) {
uint32_t Flags = I->getFlags();
// FIXME: should we print 'b'? At the IR level we cannot be sure if this
@@ -921,8 +1056,12 @@ static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) {
Ret = getSymbolNMTypeChar(*IR, I);
else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(&Obj))
Ret = getSymbolNMTypeChar(*COFF, I);
+ else if (COFFImportFile *COFFImport = dyn_cast<COFFImportFile>(&Obj))
+ Ret = getSymbolNMTypeChar(*COFFImport);
else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
Ret = getSymbolNMTypeChar(*MachO, I);
+ else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj))
+ Ret = getSymbolNMTypeChar(*Wasm, I);
else
Ret = getSymbolNMTypeChar(cast<ELFObjectFileBase>(Obj), I);
@@ -994,51 +1133,439 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
if (Nsect == 0)
return;
}
- for (BasicSymbolRef Sym : Symbols) {
- uint32_t SymFlags = Sym.getFlags();
- if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific))
- continue;
- if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect))
- continue;
- // If a "-s segname sectname" option was specified and this is a Mach-O
- // file and this section appears in this file, Nsect will be non-zero then
- // see if this symbol is a symbol from that section and if not skip it.
- if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
- continue;
- NMSymbol S;
- S.Size = 0;
- S.Address = 0;
- if (PrintSize) {
- if (isa<ELFObjectFileBase>(&Obj))
- S.Size = ELFSymbolRef(Sym).getSize();
- }
- if (PrintAddress && isa<ObjectFile>(Obj)) {
- SymbolRef SymRef(Sym);
- Expected<uint64_t> AddressOrErr = SymRef.getAddress();
- if (!AddressOrErr) {
- consumeError(AddressOrErr.takeError());
- break;
+ if (!MachO || !DyldInfoOnly) {
+ for (BasicSymbolRef Sym : Symbols) {
+ uint32_t SymFlags = Sym.getFlags();
+ if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific))
+ continue;
+ if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect))
+ continue;
+ // If a "-s segname sectname" option was specified and this is a Mach-O
+ // file and this section appears in this file, Nsect will be non-zero then
+ // see if this symbol is a symbol from that section and if not skip it.
+ if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
+ continue;
+ NMSymbol S;
+ memset(&S, '\0', sizeof(S));
+ S.Size = 0;
+ S.Address = 0;
+ if (PrintSize) {
+ if (isa<ELFObjectFileBase>(&Obj))
+ S.Size = ELFSymbolRef(Sym).getSize();
+ }
+ if (PrintAddress && isa<ObjectFile>(Obj)) {
+ SymbolRef SymRef(Sym);
+ Expected<uint64_t> AddressOrErr = SymRef.getAddress();
+ if (!AddressOrErr) {
+ consumeError(AddressOrErr.takeError());
+ break;
+ }
+ S.Address = *AddressOrErr;
}
- S.Address = *AddressOrErr;
+ S.TypeChar = getNMTypeChar(Obj, Sym);
+ std::error_code EC = Sym.printName(OS);
+ if (EC && MachO)
+ OS << "bad string index";
+ else
+ error(EC);
+ OS << '\0';
+ S.Sym = Sym;
+ SymbolList.push_back(S);
}
- S.TypeChar = getNMTypeChar(Obj, Sym);
- std::error_code EC = Sym.printName(OS);
- if (EC && MachO)
- OS << "bad string index";
- else
- error(EC);
- OS << '\0';
- S.Sym = Sym;
- SymbolList.push_back(S);
}
OS.flush();
const char *P = NameBuffer.c_str();
- for (unsigned I = 0; I < SymbolList.size(); ++I) {
+ unsigned I;
+ for (I = 0; I < SymbolList.size(); ++I) {
SymbolList[I].Name = P;
P += strlen(P) + 1;
}
+ // If this is a Mach-O file where the nlist symbol table is out of sync
+ // with the dyld export trie then look through exports and fake up symbols
+ // for the ones that are missing (also done with the -add-dyldinfo flag).
+ // This is needed if strip(1) -T is run on a binary containing swift
+ // language symbols for example. The option -only-dyldinfo will fake up
+ // all symbols from the dyld export trie as well as the bind info.
+ std::string ExportsNameBuffer;
+ raw_string_ostream EOS(ExportsNameBuffer);
+ std::string BindsNameBuffer;
+ raw_string_ostream BOS(BindsNameBuffer);
+ std::string LazysNameBuffer;
+ raw_string_ostream LOS(LazysNameBuffer);
+ std::string WeaksNameBuffer;
+ raw_string_ostream WOS(WeaksNameBuffer);
+ if (MachO && !NoDyldInfo) {
+ MachO::mach_header H;
+ MachO::mach_header_64 H_64;
+ uint32_t HFlags = 0;
+ if (MachO->is64Bit()) {
+ H_64 = MachO->MachOObjectFile::getHeader64();
+ HFlags = H_64.flags;
+ } else {
+ H = MachO->MachOObjectFile::getHeader();
+ HFlags = H.flags;
+ }
+ uint64_t BaseSegmentAddress = 0;
+ for (const auto &Command : MachO->load_commands()) {
+ if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = MachO->getSegmentLoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ }
+ }
+ if (DyldInfoOnly || AddDyldInfo ||
+ HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
+ unsigned ExportsAdded = 0;
+ for (const llvm::object::ExportEntry &Entry : MachO->exports()) {
+ bool found = false;
+ bool ReExport = false;
+ if (!DyldInfoOnly) {
+ for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Address == Entry.address() + BaseSegmentAddress &&
+ SymbolList[J].Name == Entry.name())
+ found = true;
+ }
+ }
+ if (!found) {
+ NMSymbol S;
+ memset(&S, '\0', sizeof(NMSymbol));
+ S.Address = Entry.address() + BaseSegmentAddress;
+ S.Size = 0;
+ S.TypeChar = '\0';
+ S.Name = Entry.name();
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ S.Sym = BasicSymbolRef();
+ S.SymFlags = SymbolRef::SF_Global;
+ S.Section = SectionRef();
+ S.NType = 0;
+ S.NSect = 0;
+ S.NDesc = 0;
+ S.IndirectName = StringRef();
+
+ uint64_t EFlags = Entry.flags();
+ bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
+ MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
+ bool Resolver = (EFlags &
+ MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+ ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
+ bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+ if (WeakDef)
+ S.NDesc |= MachO::N_WEAK_DEF;
+ if (Abs) {
+ S.NType = MachO::N_EXT | MachO::N_ABS;
+ S.TypeChar = 'A';
+ } else if (ReExport) {
+ S.NType = MachO::N_EXT | MachO::N_INDR;
+ S.TypeChar = 'I';
+ } else {
+ S.NType = MachO::N_EXT | MachO::N_SECT;
+ if (Resolver) {
+ S.Address = Entry.other() + BaseSegmentAddress;
+ if ((S.Address & 1) != 0 &&
+ !MachO->is64Bit() && H.cputype == MachO::CPU_TYPE_ARM){
+ S.Address &= ~1LL;
+ S.NDesc |= MachO::N_ARM_THUMB_DEF;
+ }
+ } else {
+ S.Address = Entry.address() + BaseSegmentAddress;
+ }
+ StringRef SegmentName = StringRef();
+ StringRef SectionName = StringRef();
+ for (const SectionRef &Section : MachO->sections()) {
+ S.NSect++;
+ Section.getName(SectionName);
+ SegmentName = MachO->getSectionFinalSegmentName(
+ Section.getRawDataRefImpl());
+ if (S.Address >= Section.getAddress() &&
+ S.Address < Section.getAddress() + Section.getSize()) {
+ S.Section = Section;
+ break;
+ } else if (Entry.name() == "__mh_execute_header" &&
+ SegmentName == "__TEXT" && SectionName == "__text") {
+ S.Section = Section;
+ S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
+ break;
+ }
+ }
+ if (SegmentName == "__TEXT" && SectionName == "__text")
+ S.TypeChar = 'T';
+ else if (SegmentName == "__DATA" && SectionName == "__data")
+ S.TypeChar = 'D';
+ else if (SegmentName == "__DATA" && SectionName == "__bss")
+ S.TypeChar = 'B';
+ else
+ S.TypeChar = 'S';
+ }
+ SymbolList.push_back(S);
+
+ EOS << Entry.name();
+ EOS << '\0';
+ ExportsAdded++;
+
+ // For ReExports there are a two more things to do, first add the
+ // indirect name and second create the undefined symbol using the
+ // referened dynamic library.
+ if (ReExport) {
+
+ // Add the indirect name.
+ if (Entry.otherName().empty())
+ EOS << Entry.name();
+ else
+ EOS << Entry.otherName();
+ EOS << '\0';
+
+ // Now create the undefined symbol using the referened dynamic
+ // library.
+ NMSymbol U;
+ memset(&U, '\0', sizeof(NMSymbol));
+ U.Address = 0;
+ U.Size = 0;
+ U.TypeChar = 'U';
+ if (Entry.otherName().empty())
+ U.Name = Entry.name();
+ else
+ U.Name = Entry.otherName();
+ // Again there is no symbol in the nlist symbol table for this so
+ // we set Sym effectivly to null and the rest of code in here must
+ // test for it and not do things like Sym.getFlags() for it.
+ U.Sym = BasicSymbolRef();
+ U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ U.Section = SectionRef();
+ U.NType = MachO::N_EXT | MachO::N_UNDF;
+ U.NSect = 0;
+ U.NDesc = 0;
+ // The library ordinal for this undefined symbol is in the export
+ // trie Entry.other().
+ MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
+ U.IndirectName = StringRef();
+ SymbolList.push_back(U);
+
+ // Finally add the undefined symbol's name.
+ if (Entry.otherName().empty())
+ EOS << Entry.name();
+ else
+ EOS << Entry.otherName();
+ EOS << '\0';
+ ExportsAdded++;
+ }
+ }
+ }
+ // Set the symbol names and indirect names for the added symbols.
+ if (ExportsAdded) {
+ EOS.flush();
+ const char *Q = ExportsNameBuffer.c_str();
+ for (unsigned K = 0; K < ExportsAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Add the undefined symbols from the bind entries.
+ unsigned BindsAdded = 0;
+ Error BErr = Error::success();
+ StringRef LastSymbolName = StringRef();
+ for (const llvm::object::MachOBindEntry &Entry : MachO->bindTable(BErr)) {
+ bool found = false;
+ if (LastSymbolName == Entry.symbolName())
+ found = true;
+ else if(!DyldInfoOnly) {
+ for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Name == Entry.symbolName())
+ found = true;
+ }
+ }
+ if (!found) {
+ LastSymbolName = Entry.symbolName();
+ NMSymbol B;
+ memset(&B, '\0', sizeof(NMSymbol));
+ B.Address = 0;
+ B.Size = 0;
+ B.TypeChar = 'U';
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ B.Sym = BasicSymbolRef();
+ B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ B.NType = MachO::N_EXT | MachO::N_UNDF;
+ B.NSect = 0;
+ B.NDesc = 0;
+ B.NDesc = 0;
+ MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
+ B.IndirectName = StringRef();
+ B.Name = Entry.symbolName();
+ SymbolList.push_back(B);
+ BOS << Entry.symbolName();
+ BOS << '\0';
+ BindsAdded++;
+ }
+ }
+ if (BErr)
+ error(std::move(BErr), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (BindsAdded) {
+ BOS.flush();
+ const char *Q = BindsNameBuffer.c_str();
+ for (unsigned K = 0; K < BindsAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Add the undefined symbols from the lazy bind entries.
+ unsigned LazysAdded = 0;
+ Error LErr = Error::success();
+ LastSymbolName = StringRef();
+ for (const llvm::object::MachOBindEntry &Entry :
+ MachO->lazyBindTable(LErr)) {
+ bool found = false;
+ if (LastSymbolName == Entry.symbolName())
+ found = true;
+ else {
+ // Here we must check to see it this symbol is already in the
+ // SymbolList as it might have already have been added above via a
+ // non-lazy (bind) entry.
+ for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Name == Entry.symbolName())
+ found = true;
+ }
+ }
+ if (!found) {
+ LastSymbolName = Entry.symbolName();
+ NMSymbol L;
+ memset(&L, '\0', sizeof(NMSymbol));
+ L.Name = Entry.symbolName();
+ L.Address = 0;
+ L.Size = 0;
+ L.TypeChar = 'U';
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ L.Sym = BasicSymbolRef();
+ L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ L.NType = MachO::N_EXT | MachO::N_UNDF;
+ L.NSect = 0;
+ // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
+ // makes sence since we are creating this from a lazy bind entry.
+ L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
+ MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
+ L.IndirectName = StringRef();
+ SymbolList.push_back(L);
+ LOS << Entry.symbolName();
+ LOS << '\0';
+ LazysAdded++;
+ }
+ }
+ if (LErr)
+ error(std::move(LErr), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (LazysAdded) {
+ LOS.flush();
+ const char *Q = LazysNameBuffer.c_str();
+ for (unsigned K = 0; K < LazysAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+
+ // Add the undefineds symbol from the weak bind entries which are not
+ // strong symbols.
+ unsigned WeaksAdded = 0;
+ Error WErr = Error::success();
+ LastSymbolName = StringRef();
+ for (const llvm::object::MachOBindEntry &Entry :
+ MachO->weakBindTable(WErr)) {
+ bool found = false;
+ unsigned J = 0;
+ if (LastSymbolName == Entry.symbolName() ||
+ Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
+ found = true;
+ } else {
+ for (J = 0; J < SymbolList.size() && !found; ++J) {
+ if (SymbolList[J].Name == Entry.symbolName()) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ LastSymbolName = Entry.symbolName();
+ NMSymbol W;
+ memset(&W, '\0', sizeof(NMSymbol));
+ W.Name = Entry.symbolName();
+ W.Address = 0;
+ W.Size = 0;
+ W.TypeChar = 'U';
+ // There is no symbol in the nlist symbol table for this so we set
+ // Sym effectivly to null and the rest of code in here must test for
+ // it and not do things like Sym.getFlags() for it.
+ W.Sym = BasicSymbolRef();
+ W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
+ W.NType = MachO::N_EXT | MachO::N_UNDF;
+ W.NSect = 0;
+ // Odd that we are using N_WEAK_DEF on an undefined symbol but that is
+ // what is created in this case by the linker when there are real
+ // symbols in the nlist structs.
+ W.NDesc = MachO::N_WEAK_DEF;
+ W.IndirectName = StringRef();
+ SymbolList.push_back(W);
+ WOS << Entry.symbolName();
+ WOS << '\0';
+ WeaksAdded++;
+ } else {
+ // This is the case the symbol was previously been found and it could
+ // have been added from a bind or lazy bind symbol. If so and not
+ // a definition also mark it as weak.
+ if (SymbolList[J].TypeChar == 'U')
+ // See comment above about N_WEAK_DEF.
+ SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
+ }
+ }
+ if (WErr)
+ error(std::move(WErr), MachO->getFileName());
+ // Set the symbol names and indirect names for the added symbols.
+ if (WeaksAdded) {
+ WOS.flush();
+ const char *Q = WeaksNameBuffer.c_str();
+ for (unsigned K = 0; K < WeaksAdded; K++) {
+ SymbolList[I].Name = Q;
+ Q += strlen(Q) + 1;
+ if (SymbolList[I].TypeChar == 'I') {
+ SymbolList[I].IndirectName = Q;
+ Q += strlen(Q) + 1;
+ }
+ I++;
+ }
+ }
+ }
+ }
+
CurrentFilename = Obj.getFileName();
sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName);
}
@@ -1057,15 +1584,19 @@ static bool checkMachOAndArchFlags(SymbolicFile *O, std::string &Filename) {
MachO::mach_header H;
MachO::mach_header_64 H_64;
Triple T;
+ const char *McpuDefault, *ArchFlag;
if (MachO->is64Bit()) {
H_64 = MachO->MachOObjectFile::getHeader64();
- T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
+ T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
+ &McpuDefault, &ArchFlag);
} else {
H = MachO->MachOObjectFile::getHeader();
- T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
+ T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
+ &McpuDefault, &ArchFlag);
}
+ const std::string ArchFlagName(ArchFlag);
if (none_of(ArchFlags, [&](const std::string &Name) {
- return Name == T.getArchName();
+ return Name == ArchFlagName;
})) {
error("No architecture specified", Filename);
return false;
@@ -1120,6 +1651,11 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
continue;
}
if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
+ if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
+ errs() << ToolName << ": warning sizes with -print-size for Mach-O "
+ "files are always zero.\n";
+ MachOPrintSizeWarning = true;
+ }
if (!checkMachOAndArchFlags(O, Filename))
return;
if (!PrintFileName) {
@@ -1357,6 +1893,11 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
return;
}
if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin)) {
+ if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
+ errs() << ToolName << ": warning sizes with -print-size for Mach-O files "
+ "are always zero.\n";
+ MachOPrintSizeWarning = true;
+ }
if (!checkMachOAndArchFlags(O, Filename))
return;
dumpSymbolNamesFromObject(*O, true);
@@ -1414,6 +1955,9 @@ int main(int argc, char **argv) {
error("bad number of arguments (must be two arguments)",
"for the -s option");
+ if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
+ error("-no-dyldinfo can't be used with -add-dyldinfo or -dyldinfo-only");
+
std::for_each(InputFilenames.begin(), InputFilenames.end(),
dumpSymbolNamesFromFile);
diff --git a/contrib/llvm/tools/llvm-objdump/MachODump.cpp b/contrib/llvm/tools/llvm-objdump/MachODump.cpp
index 5630848..05c2c3f 100644
--- a/contrib/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/contrib/llvm/tools/llvm-objdump/MachODump.cpp
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Object/MachO.h"
#include "llvm-objdump.h"
#include "llvm-c/Disassembler.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Config/config.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -30,6 +30,7 @@
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
@@ -39,7 +40,6 @@
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/LEB128.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
@@ -68,9 +68,6 @@ static cl::opt<std::string> DSYMFile("dsym",
static cl::opt<bool> FullLeadingAddr("full-leading-addr",
cl::desc("Print full leading address"));
-static cl::opt<bool> NoLeadingAddr("no-leading-addr",
- cl::desc("Print no leading address"));
-
static cl::opt<bool> NoLeadingHeaders("no-leading-headers",
cl::desc("Print no leading headers"));
@@ -1138,11 +1135,12 @@ static void DumpInfoPlistSectionContents(StringRef Filename,
DataRefImpl Ref = Section.getRawDataRefImpl();
StringRef SegName = O->getSectionFinalSegmentName(Ref);
if (SegName == "__TEXT" && SectName == "__info_plist") {
- outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+ if (!NoLeadingHeaders)
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
StringRef BytesStr;
Section.getContents(BytesStr);
const char *sect = reinterpret_cast<const char *>(BytesStr.data());
- outs() << sect;
+ outs() << format("%.*s", BytesStr.size(), sect) << "\n";
return;
}
}
@@ -1226,8 +1224,13 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
if (Error Err = MachOOF->checkSymbolTable())
report_error(ArchiveName, FileName, std::move(Err), ArchitectureName);
- if (Disassemble)
- DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");
+ if (Disassemble) {
+ if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE &&
+ MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64)
+ DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text");
+ else
+ DisassembleMachO(FileName, MachOOF, "__TEXT", "__text");
+ }
if (IndirectSymbols)
PrintIndirectSymbols(MachOOF, !NonVerbose);
if (DataInCode)
@@ -1274,7 +1277,10 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
if (DwarfDumpType != DIDT_Null) {
std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(*MachOOF));
// Dump the complete DWARF structure.
- DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */);
+ DIDumpOptions DumpOpts;
+ DumpOpts.DumpType = DwarfDumpType;
+ DumpOpts.DumpEH = true;
+ DICtx->dump(outs(), DumpOpts);
}
}
@@ -1566,8 +1572,13 @@ void llvm::ParseInputMachO(StringRef Filename) {
// Attempt to open the binary.
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
- if (!BinaryOrErr)
- report_error(Filename, BinaryOrErr.takeError());
+ if (!BinaryOrErr) {
+ if (auto E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))
+ report_error(Filename, std::move(E));
+ else
+ outs() << Filename << ": is not an object file\n";
+ return;
+ }
Binary &Bin = *BinaryOrErr.get().getBinary();
if (Archive *A = dyn_cast<Archive>(&Bin)) {
@@ -1915,11 +1926,45 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
if (Arch == Triple::x86_64) {
if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
return 0;
+ // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external
+ // relocation entries of a linked image (if any) for an entry that matches
+ // this segment offset.
if (info->O->getHeader().filetype != MachO::MH_OBJECT) {
- // TODO:
- // Search the external relocation entries of a fully linked image
- // (if any) for an entry that matches this segment offset.
- // uint64_t seg_offset = (Pc + Offset);
+ uint64_t seg_offset = Pc + Offset;
+ bool reloc_found = false;
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ SymbolRef Symbol;
+ for (const RelocationRef &Reloc : info->O->external_relocations()) {
+ uint64_t RelocOffset = Reloc.getOffset();
+ if (RelocOffset == seg_offset) {
+ Rel = Reloc.getRawDataRefImpl();
+ RE = info->O->getRelocation(Rel);
+ // external relocation entries should always be external.
+ isExtern = info->O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Symbol = *RelocSym;
+ }
+ reloc_found = true;
+ break;
+ }
+ }
+ if (reloc_found && isExtern) {
+ // The Value passed in will be adjusted by the Pc if the instruction
+ // adds the Pc. But for x86_64 external relocation entries the Value
+ // is the offset from the external symbol.
+ if (info->O->getAnyRelocationPCRel(RE))
+ op_info->Value -= Pc + Offset + Size;
+ Expected<StringRef> SymName = Symbol.getName();
+ if (!SymName)
+ report_error(info->O->getFileName(), SymName.takeError());
+ const char *name = SymName->data();
+ op_info->AddSymbol.Present = 1;
+ op_info->AddSymbol.Name = name;
+ return 1;
+ }
return 0;
}
// In MH_OBJECT filetypes search the section's relocation entries (if any)
@@ -2589,7 +2634,8 @@ static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,
// These are structs in the Objective-C meta data and read to produce the
// comments for disassembly. While these are part of the ABI they are no
-// public defintions. So the are here not in include/llvm/Support/MachO.h .
+// public defintions. So the are here not in include/llvm/BinaryFormat/MachO.h
+// .
// The cfstring object in a 64-bit Mach-O file.
struct cfstring64_t {
@@ -4566,6 +4612,12 @@ static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
n_value, c.superclass);
if (name != nullptr)
outs() << " " << name;
+ else {
+ name = get_dyld_bind_info_symbolname(S.getAddress() +
+ offset + offsetof(struct class64_t, superclass), info);
+ if (name != nullptr)
+ outs() << " " << name;
+ }
outs() << "\n";
outs() << " cache " << format("0x%" PRIx64, c.cache);
@@ -5269,42 +5321,70 @@ static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {
SectionRef CL = get_section(O, "__OBJC2", "__class_list");
if (CL == SectionRef())
CL = get_section(O, "__DATA", "__objc_classlist");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA_CONST", "__objc_classlist");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
info.S = CL;
walk_pointer_list_64("class", CL, O, &info, print_class64_t);
SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
if (CR == SectionRef())
CR = get_section(O, "__DATA", "__objc_classrefs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
info.S = CR;
walk_pointer_list_64("class refs", CR, O, &info, nullptr);
SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
if (SR == SectionRef())
SR = get_section(O, "__DATA", "__objc_superrefs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
info.S = SR;
walk_pointer_list_64("super refs", SR, O, &info, nullptr);
SectionRef CA = get_section(O, "__OBJC2", "__category_list");
if (CA == SectionRef())
CA = get_section(O, "__DATA", "__objc_catlist");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA_CONST", "__objc_catlist");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
info.S = CA;
walk_pointer_list_64("category", CA, O, &info, print_category64_t);
SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
if (PL == SectionRef())
PL = get_section(O, "__DATA", "__objc_protolist");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA_CONST", "__objc_protolist");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
info.S = PL;
walk_pointer_list_64("protocol", PL, O, &info, nullptr);
SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
if (MR == SectionRef())
MR = get_section(O, "__DATA", "__objc_msgrefs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
info.S = MR;
print_message_refs64(MR, &info);
SectionRef II = get_section(O, "__OBJC2", "__image_info");
if (II == SectionRef())
II = get_section(O, "__DATA", "__objc_imageinfo");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
info.S = II;
print_image_info64(II, &info);
}
@@ -5335,75 +5415,75 @@ static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {
info.adrp_addr = 0;
info.adrp_inst = 0;
- const SectionRef CL = get_section(O, "__OBJC2", "__class_list");
- if (CL != SectionRef()) {
- info.S = CL;
- walk_pointer_list_32("class", CL, O, &info, print_class32_t);
- } else {
- const SectionRef CL = get_section(O, "__DATA", "__objc_classlist");
- info.S = CL;
- walk_pointer_list_32("class", CL, O, &info, print_class32_t);
- }
+ SectionRef CL = get_section(O, "__OBJC2", "__class_list");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA", "__objc_classlist");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA_CONST", "__objc_classlist");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA_DIRTY", "__objc_classlist");
+ info.S = CL;
+ walk_pointer_list_32("class", CL, O, &info, print_class32_t);
- const SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
- if (CR != SectionRef()) {
- info.S = CR;
- walk_pointer_list_32("class refs", CR, O, &info, nullptr);
- } else {
- const SectionRef CR = get_section(O, "__DATA", "__objc_classrefs");
- info.S = CR;
- walk_pointer_list_32("class refs", CR, O, &info, nullptr);
- }
+ SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA", "__objc_classrefs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA_CONST", "__objc_classrefs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs");
+ info.S = CR;
+ walk_pointer_list_32("class refs", CR, O, &info, nullptr);
- const SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
- if (SR != SectionRef()) {
- info.S = SR;
- walk_pointer_list_32("super refs", SR, O, &info, nullptr);
- } else {
- const SectionRef SR = get_section(O, "__DATA", "__objc_superrefs");
- info.S = SR;
- walk_pointer_list_32("super refs", SR, O, &info, nullptr);
- }
+ SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA", "__objc_superrefs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA_CONST", "__objc_superrefs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs");
+ info.S = SR;
+ walk_pointer_list_32("super refs", SR, O, &info, nullptr);
- const SectionRef CA = get_section(O, "__OBJC2", "__category_list");
- if (CA != SectionRef()) {
- info.S = CA;
- walk_pointer_list_32("category", CA, O, &info, print_category32_t);
- } else {
- const SectionRef CA = get_section(O, "__DATA", "__objc_catlist");
- info.S = CA;
- walk_pointer_list_32("category", CA, O, &info, print_category32_t);
- }
+ SectionRef CA = get_section(O, "__OBJC2", "__category_list");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA", "__objc_catlist");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA_CONST", "__objc_catlist");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA_DIRTY", "__objc_catlist");
+ info.S = CA;
+ walk_pointer_list_32("category", CA, O, &info, print_category32_t);
- const SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
- if (PL != SectionRef()) {
- info.S = PL;
- walk_pointer_list_32("protocol", PL, O, &info, nullptr);
- } else {
- const SectionRef PL = get_section(O, "__DATA", "__objc_protolist");
- info.S = PL;
- walk_pointer_list_32("protocol", PL, O, &info, nullptr);
- }
+ SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA", "__objc_protolist");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA_CONST", "__objc_protolist");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA_DIRTY", "__objc_protolist");
+ info.S = PL;
+ walk_pointer_list_32("protocol", PL, O, &info, nullptr);
- const SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
- if (MR != SectionRef()) {
- info.S = MR;
- print_message_refs32(MR, &info);
- } else {
- const SectionRef MR = get_section(O, "__DATA", "__objc_msgrefs");
- info.S = MR;
- print_message_refs32(MR, &info);
- }
+ SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA", "__objc_msgrefs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA_CONST", "__objc_msgrefs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs");
+ info.S = MR;
+ print_message_refs32(MR, &info);
- const SectionRef II = get_section(O, "__OBJC2", "__image_info");
- if (II != SectionRef()) {
- info.S = II;
- print_image_info32(II, &info);
- } else {
- const SectionRef II = get_section(O, "__DATA", "__objc_imageinfo");
- info.S = II;
- print_image_info32(II, &info);
- }
+ SectionRef II = get_section(O, "__OBJC2", "__image_info");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA", "__objc_imageinfo");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA_CONST", "__objc_imageinfo");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo");
+ info.S = II;
+ print_image_info32(II, &info);
}
static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {
@@ -6597,6 +6677,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
if (Bytes.size() == 0)
return;
+ // If the section has symbols but no symbol at the start of the section
+ // these are used to make sure the bytes before the first symbol are
+ // disassembled.
+ bool FirstSymbol = true;
+ bool FirstSymbolAtSectionStart = true;
+
// Disassemble symbol by symbol.
for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
Expected<StringRef> SymNameOrErr = Symbols[SymIdx].getName();
@@ -6686,11 +6772,29 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
// (i.e. we're not targeting M-class) and the function is Thumb.
bool UseThumbTarget = IsThumb && ThumbTarget;
- outs() << SymName << ":\n";
+ // If we are not specifying a symbol to start disassembly with and this
+ // is the first symbol in the section but not at the start of the section
+ // then move the disassembly index to the start of the section and
+ // don't print the symbol name just yet. This is so the bytes before the
+ // first symbol are disassembled.
+ uint64_t SymbolStart = Start;
+ if (DisSymName.empty() && FirstSymbol && Start != 0) {
+ FirstSymbolAtSectionStart = false;
+ Start = 0;
+ }
+ else
+ outs() << SymName << ":\n";
+
DILineInfo lastLine;
for (uint64_t Index = Start; Index < End; Index += Size) {
MCInst Inst;
+ // If this is the first symbol in the section and it was not at the
+ // start of the section, see if we are at its Index now and if so print
+ // the symbol name.
+ if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart)
+ outs() << SymName << ":\n";
+
uint64_t PC = SectAddress + Index;
if (!NoLeadingAddr) {
if (FullLeadingAddr) {
@@ -6783,6 +6887,9 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
}
}
}
+ // Now that we are done disassembled the first symbol set the bool that
+ // were doing this to false.
+ FirstSymbol = false;
}
if (!symbolTableWorked) {
// Reading the symbol table didn't work, disassemble the whole section.
@@ -6793,8 +6900,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
MCInst Inst;
uint64_t PC = SectAddress + Index;
+ SmallVector<char, 64> AnnotationsBytes;
+ raw_svector_ostream Annotations(AnnotationsBytes);
if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,
- DebugOut, nulls())) {
+ DebugOut, Annotations)) {
if (!NoLeadingAddr) {
if (FullLeadingAddr) {
if (MachOOF->is64Bit())
@@ -6809,7 +6918,8 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
outs() << "\t";
dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs());
}
- IP->printInst(&Inst, outs(), "", *STI);
+ StringRef AnnotationsStr = Annotations.str();
+ IP->printInst(&Inst, outs(), AnnotationsStr, *STI);
outs() << "\n";
} else {
unsigned int Arch = MachOOF->getArch();
@@ -7570,6 +7680,10 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype,
outs() << " APP_EXTENSION_SAFE";
f &= ~MachO::MH_APP_EXTENSION_SAFE;
}
+ if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
+ outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";
+ f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;
+ }
if (f != 0 || flags == 0)
outs() << format(" 0x%08" PRIx32, f);
} else {
@@ -8169,6 +8283,51 @@ static void PrintVersionMinLoadCommand(MachO::version_min_command vd) {
outs() << "\n";
}
+static void PrintNoteLoadCommand(MachO::note_command Nt) {
+ outs() << " cmd LC_NOTE\n";
+ outs() << " cmdsize " << Nt.cmdsize;
+ if (Nt.cmdsize != sizeof(struct MachO::note_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ const char *d = Nt.data_owner;
+ outs() << "data_owner " << format("%.16s\n", d);
+ outs() << " offset " << Nt.offset << "\n";
+ outs() << " size " << Nt.size << "\n";
+}
+
+static void PrintBuildToolVersion(MachO::build_tool_version bv) {
+ outs() << " tool " << MachOObjectFile::getBuildTool(bv.tool) << "\n";
+ outs() << " version " << MachOObjectFile::getVersionString(bv.version)
+ << "\n";
+}
+
+static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj,
+ MachO::build_version_command bd) {
+ outs() << " cmd LC_BUILD_VERSION\n";
+ outs() << " cmdsize " << bd.cmdsize;
+ if (bd.cmdsize !=
+ sizeof(struct MachO::build_version_command) +
+ bd.ntools * sizeof(struct MachO::build_tool_version))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " platform " << MachOObjectFile::getBuildPlatform(bd.platform)
+ << "\n";
+ if (bd.sdk)
+ outs() << " sdk " << MachOObjectFile::getVersionString(bd.sdk)
+ << "\n";
+ else
+ outs() << " sdk n/a\n";
+ outs() << " minos " << MachOObjectFile::getVersionString(bd.minos)
+ << "\n";
+ outs() << " ntools " << bd.ntools << "\n";
+ for (unsigned i = 0; i < bd.ntools; ++i) {
+ MachO::build_tool_version bv = obj->getBuildToolVersion(i);
+ PrintBuildToolVersion(bv);
+ }
+}
+
static void PrintSourceVersionCommand(MachO::source_version_command sd) {
outs() << " cmd LC_SOURCE_VERSION\n";
outs() << " cmdsize " << sd.cmdsize;
@@ -8374,6 +8533,25 @@ static void PrintRoutinesCommand64(MachO::routines_command_64 r) {
outs() << " reserved6 " << r.reserved6 << "\n";
}
+static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) {
+ outs() << "\t eax " << format("0x%08" PRIx32, cpu32.eax);
+ outs() << " ebx " << format("0x%08" PRIx32, cpu32.ebx);
+ outs() << " ecx " << format("0x%08" PRIx32, cpu32.ecx);
+ outs() << " edx " << format("0x%08" PRIx32, cpu32.edx) << "\n";
+ outs() << "\t edi " << format("0x%08" PRIx32, cpu32.edi);
+ outs() << " esi " << format("0x%08" PRIx32, cpu32.esi);
+ outs() << " ebp " << format("0x%08" PRIx32, cpu32.ebp);
+ outs() << " esp " << format("0x%08" PRIx32, cpu32.esp) << "\n";
+ outs() << "\t ss " << format("0x%08" PRIx32, cpu32.ss);
+ outs() << " eflags " << format("0x%08" PRIx32, cpu32.eflags);
+ outs() << " eip " << format("0x%08" PRIx32, cpu32.eip);
+ outs() << " cs " << format("0x%08" PRIx32, cpu32.cs) << "\n";
+ outs() << "\t ds " << format("0x%08" PRIx32, cpu32.ds);
+ outs() << " es " << format("0x%08" PRIx32, cpu32.es);
+ outs() << " fs " << format("0x%08" PRIx32, cpu32.fs);
+ outs() << " gs " << format("0x%08" PRIx32, cpu32.gs) << "\n";
+}
+
static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) {
outs() << " rax " << format("0x%016" PRIx64, cpu64.rax);
outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx);
@@ -8611,7 +8789,85 @@ static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,
const char *begin = Ptr + sizeof(struct MachO::thread_command);
const char *end = Ptr + t.cmdsize;
uint32_t flavor, count, left;
- if (cputype == MachO::CPU_TYPE_X86_64) {
+ if (cputype == MachO::CPU_TYPE_I386) {
+ while (begin < end) {
+ if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
+ memcpy((char *)&flavor, begin, sizeof(uint32_t));
+ begin += sizeof(uint32_t);
+ } else {
+ flavor = 0;
+ begin = end;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ sys::swapByteOrder(flavor);
+ if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
+ memcpy((char *)&count, begin, sizeof(uint32_t));
+ begin += sizeof(uint32_t);
+ } else {
+ count = 0;
+ begin = end;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ sys::swapByteOrder(count);
+ if (flavor == MachO::x86_THREAD_STATE32) {
+ outs() << " flavor i386_THREAD_STATE\n";
+ if (count == MachO::x86_THREAD_STATE32_COUNT)
+ outs() << " count i386_THREAD_STATE_COUNT\n";
+ else
+ outs() << " count " << count
+ << " (not x86_THREAD_STATE32_COUNT)\n";
+ MachO::x86_thread_state32_t cpu32;
+ left = end - begin;
+ if (left >= sizeof(MachO::x86_thread_state32_t)) {
+ memcpy(&cpu32, begin, sizeof(MachO::x86_thread_state32_t));
+ begin += sizeof(MachO::x86_thread_state32_t);
+ } else {
+ memset(&cpu32, '\0', sizeof(MachO::x86_thread_state32_t));
+ memcpy(&cpu32, begin, left);
+ begin += left;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ swapStruct(cpu32);
+ Print_x86_thread_state32_t(cpu32);
+ } else if (flavor == MachO::x86_THREAD_STATE) {
+ outs() << " flavor x86_THREAD_STATE\n";
+ if (count == MachO::x86_THREAD_STATE_COUNT)
+ outs() << " count x86_THREAD_STATE_COUNT\n";
+ else
+ outs() << " count " << count
+ << " (not x86_THREAD_STATE_COUNT)\n";
+ struct MachO::x86_thread_state_t ts;
+ left = end - begin;
+ if (left >= sizeof(MachO::x86_thread_state_t)) {
+ memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t));
+ begin += sizeof(MachO::x86_thread_state_t);
+ } else {
+ memset(&ts, '\0', sizeof(MachO::x86_thread_state_t));
+ memcpy(&ts, begin, left);
+ begin += left;
+ }
+ if (isLittleEndian != sys::IsLittleEndianHost)
+ swapStruct(ts);
+ if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) {
+ outs() << "\t tsh.flavor x86_THREAD_STATE32 ";
+ if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT)
+ outs() << "tsh.count x86_THREAD_STATE32_COUNT\n";
+ else
+ outs() << "tsh.count " << ts.tsh.count
+ << " (not x86_THREAD_STATE32_COUNT\n";
+ Print_x86_thread_state32_t(ts.uts.ts32);
+ } else {
+ outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count "
+ << ts.tsh.count << "\n";
+ }
+ } else {
+ outs() << " flavor " << flavor << " (unknown)\n";
+ outs() << " count " << count << "\n";
+ outs() << " state (unknown)\n";
+ begin += count * sizeof(uint32_t);
+ }
+ }
+ } else if (cputype == MachO::CPU_TYPE_X86_64) {
while (begin < end) {
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
memcpy((char *)&flavor, begin, sizeof(uint32_t));
@@ -9014,6 +9270,13 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype,
Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command);
PrintVersionMinLoadCommand(Vd);
+ } else if (Command.C.cmd == MachO::LC_NOTE) {
+ MachO::note_command Nt = Obj->getNoteLoadCommand(Command);
+ PrintNoteLoadCommand(Nt);
+ } else if (Command.C.cmd == MachO::LC_BUILD_VERSION) {
+ MachO::build_version_command Bv =
+ Obj->getBuildVersionLoadCommand(Command);
+ PrintBuildVersionLoadCommand(Obj, Bv);
} else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) {
MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);
PrintSourceVersionCommand(Sd);
@@ -9123,6 +9386,22 @@ void llvm::printMachOLoadCommands(const object::ObjectFile *Obj) {
//===----------------------------------------------------------------------===//
void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
+ uint64_t BaseSegmentAddress = 0;
+ for (const auto &Command : Obj->load_commands()) {
+ if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = Obj->getSegmentLoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(Command);
+ if (Seg.fileoff == 0 && Seg.filesize != 0) {
+ BaseSegmentAddress = Seg.vmaddr;
+ break;
+ }
+ }
+ }
for (const llvm::object::ExportEntry &Entry : Obj->exports()) {
uint64_t Flags = Entry.flags();
bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
@@ -9136,7 +9415,7 @@ void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
outs() << "[re-export] ";
else
outs() << format("0x%08llX ",
- Entry.address()); // FIXME:add in base address
+ Entry.address() + BaseSegmentAddress);
outs() << Entry.name();
if (WeakDef || ThreadLocal || Resolver || Abs) {
bool NeedsComma = false;
@@ -9182,117 +9461,21 @@ void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
// rebase table dumping
//===----------------------------------------------------------------------===//
-namespace {
-class SegInfo {
-public:
- SegInfo(const object::MachOObjectFile *Obj);
-
- StringRef segmentName(uint32_t SegIndex);
- StringRef sectionName(uint32_t SegIndex, uint64_t SegOffset);
- uint64_t address(uint32_t SegIndex, uint64_t SegOffset);
- bool isValidSegIndexAndOffset(uint32_t SegIndex, uint64_t SegOffset);
-
-private:
- struct SectionInfo {
- uint64_t Address;
- uint64_t Size;
- StringRef SectionName;
- StringRef SegmentName;
- uint64_t OffsetInSegment;
- uint64_t SegmentStartAddress;
- uint32_t SegmentIndex;
- };
- const SectionInfo &findSection(uint32_t SegIndex, uint64_t SegOffset);
- SmallVector<SectionInfo, 32> Sections;
-};
-}
-
-SegInfo::SegInfo(const object::MachOObjectFile *Obj) {
- // Build table of sections so segIndex/offset pairs can be translated.
- uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0;
- StringRef CurSegName;
- uint64_t CurSegAddress;
- for (const SectionRef &Section : Obj->sections()) {
- SectionInfo Info;
- error(Section.getName(Info.SectionName));
- Info.Address = Section.getAddress();
- Info.Size = Section.getSize();
- Info.SegmentName =
- Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl());
- if (!Info.SegmentName.equals(CurSegName)) {
- ++CurSegIndex;
- CurSegName = Info.SegmentName;
- CurSegAddress = Info.Address;
- }
- Info.SegmentIndex = CurSegIndex - 1;
- Info.OffsetInSegment = Info.Address - CurSegAddress;
- Info.SegmentStartAddress = CurSegAddress;
- Sections.push_back(Info);
- }
-}
-
-StringRef SegInfo::segmentName(uint32_t SegIndex) {
- for (const SectionInfo &SI : Sections) {
- if (SI.SegmentIndex == SegIndex)
- return SI.SegmentName;
- }
- llvm_unreachable("invalid segIndex");
-}
-
-bool SegInfo::isValidSegIndexAndOffset(uint32_t SegIndex,
- uint64_t OffsetInSeg) {
- for (const SectionInfo &SI : Sections) {
- if (SI.SegmentIndex != SegIndex)
- continue;
- if (SI.OffsetInSegment > OffsetInSeg)
- continue;
- if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size))
- continue;
- return true;
- }
- return false;
-}
-
-const SegInfo::SectionInfo &SegInfo::findSection(uint32_t SegIndex,
- uint64_t OffsetInSeg) {
- for (const SectionInfo &SI : Sections) {
- if (SI.SegmentIndex != SegIndex)
- continue;
- if (SI.OffsetInSegment > OffsetInSeg)
- continue;
- if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size))
- continue;
- return SI;
- }
- llvm_unreachable("segIndex and offset not in any section");
-}
-
-StringRef SegInfo::sectionName(uint32_t SegIndex, uint64_t OffsetInSeg) {
- return findSection(SegIndex, OffsetInSeg).SectionName;
-}
-
-uint64_t SegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) {
- const SectionInfo &SI = findSection(SegIndex, OffsetInSeg);
- return SI.SegmentStartAddress + OffsetInSeg;
-}
-
-void llvm::printMachORebaseTable(const object::MachOObjectFile *Obj) {
- // Build table of sections so names can used in final output.
- SegInfo sectionTable(Obj);
-
+void llvm::printMachORebaseTable(object::MachOObjectFile *Obj) {
outs() << "segment section address type\n";
- for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable()) {
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- StringRef SegmentName = sectionTable.segmentName(SegIndex);
- StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ Error Err = Error::success();
+ for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {
+ StringRef SegmentName = Entry.segmentName();
+ StringRef SectionName = Entry.sectionName();
+ uint64_t Address = Entry.address();
// Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer
outs() << format("%-8s %-18s 0x%08" PRIX64 " %s\n",
SegmentName.str().c_str(), SectionName.str().c_str(),
Address, Entry.typeName().str().c_str());
}
+ if (Err)
+ report_error(Obj->getFileName(), std::move(Err));
}
static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
@@ -9320,18 +9503,15 @@ static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
// bind table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOBindTable(const object::MachOObjectFile *Obj) {
+void llvm::printMachOBindTable(object::MachOObjectFile *Obj) {
// Build table of sections so names can used in final output.
- SegInfo sectionTable(Obj);
-
outs() << "segment section address type "
"addend dylib symbol\n";
- for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable()) {
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- StringRef SegmentName = sectionTable.segmentName(SegIndex);
- StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ Error Err = Error::success();
+ for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable(Err)) {
+ StringRef SegmentName = Entry.segmentName();
+ StringRef SectionName = Entry.sectionName();
+ uint64_t Address = Entry.address();
// Table lines look like:
// __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard
@@ -9346,24 +9526,22 @@ void llvm::printMachOBindTable(const object::MachOObjectFile *Obj) {
<< left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
<< Entry.symbolName() << Attr << "\n";
}
+ if (Err)
+ report_error(Obj->getFileName(), std::move(Err));
}
//===----------------------------------------------------------------------===//
// lazy bind table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOLazyBindTable(const object::MachOObjectFile *Obj) {
- // Build table of sections so names can used in final output.
- SegInfo sectionTable(Obj);
-
+void llvm::printMachOLazyBindTable(object::MachOObjectFile *Obj) {
outs() << "segment section address "
"dylib symbol\n";
- for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable()) {
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- StringRef SegmentName = sectionTable.segmentName(SegIndex);
- StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ Error Err = Error::success();
+ for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {
+ StringRef SegmentName = Entry.segmentName();
+ StringRef SectionName = Entry.sectionName();
+ uint64_t Address = Entry.address();
// Table lines look like:
// __DATA __got 0x00012010 libSystem ___stack_chk_guard
@@ -9373,30 +9551,28 @@ void llvm::printMachOLazyBindTable(const object::MachOObjectFile *Obj) {
<< left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
<< Entry.symbolName() << "\n";
}
+ if (Err)
+ report_error(Obj->getFileName(), std::move(Err));
}
//===----------------------------------------------------------------------===//
// weak bind table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) {
- // Build table of sections so names can used in final output.
- SegInfo sectionTable(Obj);
-
+void llvm::printMachOWeakBindTable(object::MachOObjectFile *Obj) {
outs() << "segment section address "
"type addend symbol\n";
- for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable()) {
+ Error Err = Error::success();
+ for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {
// Strong symbols don't have a location to update.
if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
outs() << " strong "
<< Entry.symbolName() << "\n";
continue;
}
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- StringRef SegmentName = sectionTable.segmentName(SegIndex);
- StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ StringRef SegmentName = Entry.segmentName();
+ StringRef SectionName = Entry.sectionName();
+ uint64_t Address = Entry.address();
// Table lines look like:
// __DATA __data 0x00001000 pointer 0 _foo
@@ -9407,6 +9583,8 @@ void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) {
<< format_decimal(Entry.addend(), 8) << " " << Entry.symbolName()
<< "\n";
}
+ if (Err)
+ report_error(Obj->getFileName(), std::move(Err));
}
// get_dyld_bind_info_symbolname() is used for disassembly and passed an
@@ -9417,17 +9595,15 @@ static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
struct DisassembleInfo *info) {
if (info->bindtable == nullptr) {
info->bindtable = llvm::make_unique<SymbolAddressMap>();
- SegInfo sectionTable(info->O);
- for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable()) {
- uint32_t SegIndex = Entry.segmentIndex();
- uint64_t OffsetInSeg = Entry.segmentOffset();
- if (!sectionTable.isValidSegIndexAndOffset(SegIndex, OffsetInSeg))
- continue;
- uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ Error Err = Error::success();
+ for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable(Err)) {
+ uint64_t Address = Entry.address();
StringRef name = Entry.symbolName();
if (!name.empty())
(*info->bindtable)[Address] = name;
}
+ if (Err)
+ report_error(info->O->getFileName(), std::move(Err));
}
auto name = info->bindtable->lookup(ReferenceValue);
return !name.empty() ? name.data() : nullptr;
diff --git a/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp b/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 8373f0c..74593e6 100644
--- a/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -41,6 +41,7 @@
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/Wasm.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@@ -158,6 +159,8 @@ cl::opt<bool>
llvm::NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling "
"instructions, do not print "
"the instruction bytes."));
+cl::opt<bool>
+llvm::NoLeadingAddr("no-leading-addr", cl::desc("Print no leading address"));
cl::opt<bool>
llvm::UnwindInfo("unwind-info", cl::desc("Display unwind information"));
@@ -213,6 +216,8 @@ cl::opt<unsigned long long>
cl::value_desc("address"), cl::init(UINT64_MAX));
static StringRef ToolName;
+typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy;
+
namespace {
typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate;
@@ -357,7 +362,16 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) {
llvm::Triple TheTriple("unknown-unknown-unknown");
if (TripleName.empty()) {
if (Obj) {
- TheTriple.setArch(Triple::ArchType(Obj->getArch()));
+ auto Arch = Obj->getArch();
+ TheTriple.setArch(Triple::ArchType(Arch));
+
+ // For ARM targets, try to use the build attributes to build determine
+ // the build target. Target features are also added, but later during
+ // disassembly.
+ if (Arch == Triple::arm || Arch == Triple::armeb) {
+ Obj->setARMSubArch(TheTriple);
+ }
+
// TheTriple defaults to ELF, and COFF doesn't have an environment:
// the best we can do here is indicate that it is mach-o.
if (Obj->isMachO())
@@ -369,8 +383,16 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) {
TheTriple.setTriple("thumbv7-windows");
}
}
- } else
+ } else {
TheTriple.setTriple(Triple::normalize(TripleName));
+ // Use the triple, but also try to combine with ARM build attributes.
+ if (Obj) {
+ auto Arch = Obj->getArch();
+ if (Arch == Triple::arm || Arch == Triple::armeb) {
+ Obj->setARMSubArch(TheTriple);
+ }
+ }
+ }
// Get the target specific parser.
std::string Error;
@@ -464,10 +486,13 @@ void SourcePrinter::printSourceLine(raw_ostream &OS, uint64_t Address,
auto FileBuffer = SourceCache.find(LineInfo.FileName);
if (FileBuffer != SourceCache.end()) {
auto LineBuffer = LineCache.find(LineInfo.FileName);
- if (LineBuffer != LineCache.end())
+ if (LineBuffer != LineCache.end()) {
+ if (LineInfo.Line > LineBuffer->second.size())
+ return;
// Vector begins at 0, line numbers are non-zero
OS << Delimiter << LineBuffer->second[LineInfo.Line - 1].ltrim()
<< "\n";
+ }
}
}
OldLineInfo = LineInfo;
@@ -491,7 +516,8 @@ public:
MCSubtargetInfo const &STI, SourcePrinter *SP) {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
- OS << format("%8" PRIx64 ":", Address);
+ if (!NoLeadingAddr)
+ OS << format("%8" PRIx64 ":", Address);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes, OS);
@@ -509,7 +535,8 @@ public:
raw_ostream &OS) {
uint32_t opcode =
(Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0];
- OS << format("%8" PRIx64 ":", Address);
+ if (!NoLeadingAddr)
+ OS << format("%8" PRIx64 ":", Address);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes.slice(0, 4), OS);
@@ -570,6 +597,9 @@ public:
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
uint64_t Address, raw_ostream &OS, StringRef Annot,
MCSubtargetInfo const &STI, SourcePrinter *SP) override {
+ if (SP && (PrintSource || PrintLines))
+ SP->printSourceLine(OS, Address);
+
if (!MI) {
OS << " <unknown>";
return;
@@ -601,7 +631,8 @@ public:
MCSubtargetInfo const &STI, SourcePrinter *SP) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
- OS << format("%8" PRId64 ":", Address / 8);
+ if (!NoLeadingAddr)
+ OS << format("%8" PRId64 ":", Address / 8);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes, OS);
@@ -839,7 +870,10 @@ static void printRelocationTargetName(const MachOObjectFile *O,
bool isExtern = O->getPlainRelocationExternal(RE);
uint64_t Val = O->getPlainRelocationSymbolNum(RE);
- if (isExtern) {
+ if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND) {
+ fmt << format("0x%0" PRIx64, Val);
+ return;
+ } else if (isExtern) {
symbol_iterator SI = O->symbol_begin();
advance(SI, Val);
Expected<StringRef> SOrErr = SI->getName();
@@ -856,6 +890,18 @@ static void printRelocationTargetName(const MachOObjectFile *O,
fmt << S;
}
+static std::error_code getRelocationValueString(const WasmObjectFile *Obj,
+ const RelocationRef &RelRef,
+ SmallVectorImpl<char> &Result) {
+ const wasm::WasmRelocation& Rel = Obj->getWasmRelocation(RelRef);
+ std::string fmtbuf;
+ raw_string_ostream fmt(fmtbuf);
+ fmt << Rel.Index << (Rel.Addend < 0 ? "" : "+") << Rel.Addend;
+ fmt.flush();
+ Result.append(fmtbuf.begin(), fmtbuf.end());
+ return std::error_code();
+}
+
static std::error_code getRelocationValueString(const MachOObjectFile *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
@@ -989,7 +1035,7 @@ static std::error_code getRelocationValueString(const MachOObjectFile *Obj,
case MachO::ARM_RELOC_HALF_SECTDIFF: {
// Half relocations steal a bit from the length field to encode
// whether this is an upper16 or a lower16 relocation.
- bool isUpper = Obj->getAnyRelocationLength(RE) >> 1;
+ bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
if (isUpper)
fmt << ":upper16:(";
@@ -1041,8 +1087,11 @@ static std::error_code getRelocationValueString(const RelocationRef &Rel,
return getRelocationValueString(ELF, Rel, Result);
if (auto *COFF = dyn_cast<COFFObjectFile>(Obj))
return getRelocationValueString(COFF, Rel, Result);
- auto *MachO = cast<MachOObjectFile>(Obj);
- return getRelocationValueString(MachO, Rel, Result);
+ if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj))
+ return getRelocationValueString(Wasm, Rel, Result);
+ if (auto *MachO = dyn_cast<MachOObjectFile>(Obj))
+ return getRelocationValueString(MachO, Rel, Result);
+ llvm_unreachable("unknown object file format");
}
/// @brief Indicates whether this relocation should hidden when listing
@@ -1091,6 +1140,52 @@ static uint8_t getElfSymbolType(const ObjectFile *Obj, const SymbolRef &Sym) {
llvm_unreachable("Unsupported binary format");
}
+template <class ELFT> static void
+addDynamicElfSymbols(const ELFObjectFile<ELFT> *Obj,
+ std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
+ for (auto Symbol : Obj->getDynamicSymbolIterators()) {
+ uint8_t SymbolType = Symbol.getELFType();
+ if (SymbolType != ELF::STT_FUNC || Symbol.getSize() == 0)
+ continue;
+
+ Expected<uint64_t> AddressOrErr = Symbol.getAddress();
+ if (!AddressOrErr)
+ report_error(Obj->getFileName(), AddressOrErr.takeError());
+ uint64_t Address = *AddressOrErr;
+
+ Expected<StringRef> Name = Symbol.getName();
+ if (!Name)
+ report_error(Obj->getFileName(), Name.takeError());
+ if (Name->empty())
+ continue;
+
+ Expected<section_iterator> SectionOrErr = Symbol.getSection();
+ if (!SectionOrErr)
+ report_error(Obj->getFileName(), SectionOrErr.takeError());
+ section_iterator SecI = *SectionOrErr;
+ if (SecI == Obj->section_end())
+ continue;
+
+ AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType);
+ }
+}
+
+static void
+addDynamicElfSymbols(const ObjectFile *Obj,
+ std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
+ assert(Obj->isELF());
+ if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj))
+ addDynamicElfSymbols(Elf32LEObj, AllSymbols);
+ else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
+ addDynamicElfSymbols(Elf64LEObj, AllSymbols);
+ else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
+ addDynamicElfSymbols(Elf32BEObj, AllSymbols);
+ else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj))
+ addDynamicElfSymbols(Elf64BEObj, AllSymbols);
+ else
+ llvm_unreachable("Unsupported binary format");
+}
+
static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
if (StartAddress > StopAddress)
error("Start address should be less than stop address");
@@ -1165,7 +1260,6 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
// Create a mapping from virtual address to symbol name. This is used to
// pretty print the symbols while disassembling.
- typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy;
std::map<SectionRef, SectionSymbolsTy> AllSymbols;
for (const SymbolRef &Symbol : Obj->symbols()) {
Expected<uint64_t> AddressOrErr = Symbol.getAddress();
@@ -1193,6 +1287,8 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType);
}
+ if (AllSymbols.empty() && Obj->isELF())
+ addDynamicElfSymbols(Obj, AllSymbols);
// Create a mapping from virtual address to section.
std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses;
@@ -1811,9 +1907,9 @@ void llvm::printExportsTrie(const ObjectFile *o) {
}
}
-void llvm::printRebaseTable(const ObjectFile *o) {
+void llvm::printRebaseTable(ObjectFile *o) {
outs() << "Rebase table:\n";
- if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachORebaseTable(MachO);
else {
errs() << "This operation is only currently supported "
@@ -1822,9 +1918,9 @@ void llvm::printRebaseTable(const ObjectFile *o) {
}
}
-void llvm::printBindTable(const ObjectFile *o) {
+void llvm::printBindTable(ObjectFile *o) {
outs() << "Bind table:\n";
- if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOBindTable(MachO);
else {
errs() << "This operation is only currently supported "
@@ -1833,9 +1929,9 @@ void llvm::printBindTable(const ObjectFile *o) {
}
}
-void llvm::printLazyBindTable(const ObjectFile *o) {
+void llvm::printLazyBindTable(ObjectFile *o) {
outs() << "Lazy bind table:\n";
- if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOLazyBindTable(MachO);
else {
errs() << "This operation is only currently supported "
@@ -1844,9 +1940,9 @@ void llvm::printLazyBindTable(const ObjectFile *o) {
}
}
-void llvm::printWeakBindTable(const ObjectFile *o) {
+void llvm::printWeakBindTable(ObjectFile *o) {
outs() << "Weak bind table:\n";
- if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
printMachOWeakBindTable(MachO);
else {
errs() << "This operation is only currently supported "
@@ -1944,7 +2040,7 @@ static void printPrivateFileHeaders(const ObjectFile *o, bool onlyFirst) {
report_error(o->getFileName(), "Invalid/Unsupported object file format");
}
-static void DumpObject(const ObjectFile *o, const Archive *a = nullptr) {
+static void DumpObject(ObjectFile *o, const Archive *a = nullptr) {
StringRef ArchiveName = a != nullptr ? a->getFileName() : "";
// Avoid other output when using a raw option.
if (!RawClangAST) {
@@ -1987,7 +2083,10 @@ static void DumpObject(const ObjectFile *o, const Archive *a = nullptr) {
if (DwarfDumpType != DIDT_Null) {
std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(*o));
// Dump the complete DWARF structure.
- DICtx->dump(outs(), DwarfDumpType, true /* DumpEH */);
+ DIDumpOptions DumpOpts;
+ DumpOpts.DumpType = DwarfDumpType;
+ DumpOpts.DumpEH = true;
+ DICtx->dump(outs(), DumpOpts);
}
}
diff --git a/contrib/llvm/tools/llvm-objdump/llvm-objdump.h b/contrib/llvm/tools/llvm-objdump/llvm-objdump.h
index dace82a..2fcd506 100644
--- a/contrib/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/contrib/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -35,6 +35,7 @@ extern cl::list<std::string> FilterSections;
extern cl::opt<bool> Disassemble;
extern cl::opt<bool> DisassembleAll;
extern cl::opt<bool> NoShowRawInsn;
+extern cl::opt<bool> NoLeadingAddr;
extern cl::opt<bool> PrivateHeaders;
extern cl::opt<bool> FirstPrivateHeader;
extern cl::opt<bool> ExportsTrie;
@@ -69,10 +70,10 @@ void ParseInputMachO(StringRef Filename);
void printCOFFUnwindInfo(const object::COFFObjectFile* o);
void printMachOUnwindInfo(const object::MachOObjectFile* o);
void printMachOExportsTrie(const object::MachOObjectFile* o);
-void printMachORebaseTable(const object::MachOObjectFile* o);
-void printMachOBindTable(const object::MachOObjectFile* o);
-void printMachOLazyBindTable(const object::MachOObjectFile* o);
-void printMachOWeakBindTable(const object::MachOObjectFile* o);
+void printMachORebaseTable(object::MachOObjectFile* o);
+void printMachOBindTable(object::MachOObjectFile* o);
+void printMachOLazyBindTable(object::MachOObjectFile* o);
+void printMachOWeakBindTable(object::MachOObjectFile* o);
void printELFFileHeader(const object::ObjectFile *o);
void printCOFFFileHeader(const object::ObjectFile *o);
void printCOFFSymbolTable(const object::COFFImportFile *i);
@@ -81,10 +82,10 @@ void printMachOFileHeader(const object::ObjectFile *o);
void printMachOLoadCommands(const object::ObjectFile *o);
void printWasmFileHeader(const object::ObjectFile *o);
void printExportsTrie(const object::ObjectFile *o);
-void printRebaseTable(const object::ObjectFile *o);
-void printBindTable(const object::ObjectFile *o);
-void printLazyBindTable(const object::ObjectFile *o);
-void printWeakBindTable(const object::ObjectFile *o);
+void printRebaseTable(object::ObjectFile *o);
+void printBindTable(object::ObjectFile *o);
+void printLazyBindTable(object::ObjectFile *o);
+void printWeakBindTable(object::ObjectFile *o);
void printRawClangAST(const object::ObjectFile *o);
void PrintRelocations(const object::ObjectFile *o);
void PrintSectionHeaders(const object::ObjectFile *o);
diff --git a/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp
deleted file mode 100644
index 629ba40..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp
+++ /dev/null
@@ -1,960 +0,0 @@
-//===- LLVMOutputStyle.cpp ------------------------------------ *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "LLVMOutputStyle.h"
-
-#include "llvm-pdbdump.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
-#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/EnumTables.h"
-#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h"
-#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
-#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
-#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-#include "llvm/DebugInfo/MSF/StreamReader.h"
-#include "llvm/DebugInfo/PDB/PDBExtras.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/EnumTables.h"
-#include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h"
-#include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
-#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
-#include "llvm/DebugInfo/PDB/Raw/ModStream.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
-#include "llvm/DebugInfo/PDB/Raw/RawError.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
-#include "llvm/Object/COFF.h"
-
-#include <unordered_map>
-
-using namespace llvm;
-using namespace llvm::codeview;
-using namespace llvm::msf;
-using namespace llvm::pdb;
-
-namespace {
-struct PageStats {
- explicit PageStats(const BitVector &FreePages)
- : Upm(FreePages), ActualUsedPages(FreePages.size()),
- MultiUsePages(FreePages.size()), UseAfterFreePages(FreePages.size()) {
- const_cast<BitVector &>(Upm).flip();
- // To calculate orphaned pages, we start with the set of pages that the
- // MSF thinks are used. Each time we find one that actually *is* used,
- // we unset it. Whichever bits remain set at the end are orphaned.
- OrphanedPages = Upm;
- }
-
- // The inverse of the MSF File's copy of the Fpm. The basis for which we
- // determine the allocation status of each page.
- const BitVector Upm;
-
- // Pages which are marked as used in the FPM and are used at least once.
- BitVector ActualUsedPages;
-
- // Pages which are marked as used in the FPM but are used more than once.
- BitVector MultiUsePages;
-
- // Pages which are marked as used in the FPM but are not used at all.
- BitVector OrphanedPages;
-
- // Pages which are marked free in the FPM but are used.
- BitVector UseAfterFreePages;
-};
-}
-
-static void recordKnownUsedPage(PageStats &Stats, uint32_t UsedIndex) {
- if (Stats.Upm.test(UsedIndex)) {
- if (Stats.ActualUsedPages.test(UsedIndex))
- Stats.MultiUsePages.set(UsedIndex);
- Stats.ActualUsedPages.set(UsedIndex);
- Stats.OrphanedPages.reset(UsedIndex);
- } else {
- // The MSF doesn't think this page is used, but it is.
- Stats.UseAfterFreePages.set(UsedIndex);
- }
-}
-
-static void printSectionOffset(llvm::raw_ostream &OS,
- const SectionOffset &Off) {
- OS << Off.Off << ", " << Off.Isect;
-}
-
-LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) : File(File), P(outs()) {}
-
-Error LLVMOutputStyle::dump() {
- if (auto EC = dumpFileHeaders())
- return EC;
-
- if (auto EC = dumpStreamSummary())
- return EC;
-
- if (auto EC = dumpFreePageMap())
- return EC;
-
- if (auto EC = dumpStreamBlocks())
- return EC;
-
- if (auto EC = dumpBlockRanges())
- return EC;
-
- if (auto EC = dumpStreamBytes())
- return EC;
-
- if (auto EC = dumpInfoStream())
- return EC;
-
- if (auto EC = dumpTpiStream(StreamTPI))
- return EC;
-
- if (auto EC = dumpTpiStream(StreamIPI))
- return EC;
-
- if (auto EC = dumpDbiStream())
- return EC;
-
- if (auto EC = dumpSectionContribs())
- return EC;
-
- if (auto EC = dumpSectionMap())
- return EC;
-
- if (auto EC = dumpGlobalsStream())
- return EC;
-
- if (auto EC = dumpPublicsStream())
- return EC;
-
- if (auto EC = dumpSectionHeaders())
- return EC;
-
- if (auto EC = dumpFpoStream())
- return EC;
-
- flush();
-
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpFileHeaders() {
- if (!opts::raw::DumpHeaders)
- return Error::success();
-
- DictScope D(P, "FileHeaders");
- P.printNumber("BlockSize", File.getBlockSize());
- P.printNumber("FreeBlockMap", File.getFreeBlockMapBlock());
- P.printNumber("NumBlocks", File.getBlockCount());
- P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes());
- P.printNumber("Unknown1", File.getUnknown1());
- P.printNumber("BlockMapAddr", File.getBlockMapIndex());
- P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks());
-
- // The directory is not contiguous. Instead, the block map contains a
- // contiguous list of block numbers whose contents, when concatenated in
- // order, make up the directory.
- P.printList("DirectoryBlocks", File.getDirectoryBlockArray());
- P.printNumber("NumStreams", File.getNumStreams());
- return Error::success();
-}
-
-void LLVMOutputStyle::discoverStreamPurposes() {
- if (!StreamPurposes.empty())
- return;
-
- // It's OK if we fail to load some of these streams, we still attempt to print
- // what we can.
- auto Dbi = File.getPDBDbiStream();
- auto Tpi = File.getPDBTpiStream();
- auto Ipi = File.getPDBIpiStream();
- auto Info = File.getPDBInfoStream();
-
- uint32_t StreamCount = File.getNumStreams();
- std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams;
- std::unordered_map<uint16_t, std::string> NamedStreams;
-
- if (Dbi) {
- for (auto &ModI : Dbi->modules()) {
- uint16_t SN = ModI.Info.getModuleStreamIndex();
- ModStreams[SN] = &ModI;
- }
- }
- if (Info) {
- for (auto &NSE : Info->named_streams()) {
- NamedStreams[NSE.second] = NSE.first();
- }
- }
-
- StreamPurposes.resize(StreamCount);
- for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
- std::string Value;
- if (StreamIdx == OldMSFDirectory)
- Value = "Old MSF Directory";
- else if (StreamIdx == StreamPDB)
- Value = "PDB Stream";
- else if (StreamIdx == StreamDBI)
- Value = "DBI Stream";
- else if (StreamIdx == StreamTPI)
- Value = "TPI Stream";
- else if (StreamIdx == StreamIPI)
- Value = "IPI Stream";
- else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
- Value = "Global Symbol Hash";
- else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
- Value = "Public Symbol Hash";
- else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
- Value = "Public Symbol Records";
- else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
- Value = "TPI Hash";
- else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
- Value = "TPI Aux Hash";
- else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
- Value = "IPI Hash";
- else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
- Value = "IPI Aux Hash";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
- Value = "Exception Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
- Value = "Fixup Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
- Value = "FPO Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
- Value = "New FPO Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
- Value = "Omap From Source Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
- Value = "Omap To Source Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
- Value = "Pdata";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
- Value = "Section Header Data";
- else if (Dbi &&
- StreamIdx ==
- Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
- Value = "Section Header Original Data";
- else if (Dbi &&
- StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
- Value = "Token Rid Data";
- else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
- Value = "Xdata";
- else {
- auto ModIter = ModStreams.find(StreamIdx);
- auto NSIter = NamedStreams.find(StreamIdx);
- if (ModIter != ModStreams.end()) {
- Value = "Module \"";
- Value += ModIter->second->Info.getModuleName().str();
- Value += "\"";
- } else if (NSIter != NamedStreams.end()) {
- Value = "Named Stream \"";
- Value += NSIter->second;
- Value += "\"";
- } else {
- Value = "???";
- }
- }
- StreamPurposes[StreamIdx] = Value;
- }
-
- // Consume errors from missing streams.
- if (!Dbi)
- consumeError(Dbi.takeError());
- if (!Tpi)
- consumeError(Tpi.takeError());
- if (!Ipi)
- consumeError(Ipi.takeError());
- if (!Info)
- consumeError(Info.takeError());
-}
-
-Error LLVMOutputStyle::dumpStreamSummary() {
- if (!opts::raw::DumpStreamSummary)
- return Error::success();
-
- discoverStreamPurposes();
-
- uint32_t StreamCount = File.getNumStreams();
-
- ListScope L(P, "Streams");
- for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
- std::string Label("Stream ");
- Label += to_string(StreamIdx);
-
- std::string Value = "[" + StreamPurposes[StreamIdx] + "] (";
- Value += to_string(File.getStreamByteSize(StreamIdx));
- Value += " bytes)";
-
- P.printString(Label, Value);
- }
-
- P.flush();
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpFreePageMap() {
- if (!opts::raw::DumpPageStats)
- return Error::success();
-
- // Start with used pages instead of free pages because
- // the number of free pages is far larger than used pages.
- BitVector FPM = File.getMsfLayout().FreePageMap;
-
- PageStats PS(FPM);
-
- recordKnownUsedPage(PS, 0); // MSF Super Block
-
- uint32_t BlocksPerSection = msf::getFpmIntervalLength(File.getMsfLayout());
- uint32_t NumSections = msf::getNumFpmIntervals(File.getMsfLayout());
- for (uint32_t I = 0; I < NumSections; ++I) {
- uint32_t Fpm0 = 1 + BlocksPerSection * I;
- // 2 Fpm blocks spaced at `getBlockSize()` block intervals
- recordKnownUsedPage(PS, Fpm0);
- recordKnownUsedPage(PS, Fpm0 + 1);
- }
-
- recordKnownUsedPage(PS, File.getBlockMapIndex()); // Stream Table
-
- for (auto DB : File.getDirectoryBlockArray())
- recordKnownUsedPage(PS, DB);
-
- // Record pages used by streams. Note that pages for stream 0
- // are considered being unused because that's what MSVC tools do.
- // Stream 0 doesn't contain actual data, so it makes some sense,
- // though it's a bit confusing to us.
- for (auto &SE : File.getStreamMap().drop_front(1))
- for (auto &S : SE)
- recordKnownUsedPage(PS, S);
-
- dumpBitVector("Msf Free Pages", FPM);
- dumpBitVector("Orphaned Pages", PS.OrphanedPages);
- dumpBitVector("Multiply Used Pages", PS.MultiUsePages);
- dumpBitVector("Use After Free Pages", PS.UseAfterFreePages);
- return Error::success();
-}
-
-void LLVMOutputStyle::dumpBitVector(StringRef Name, const BitVector &V) {
- std::vector<uint32_t> Vec;
- for (uint32_t I = 0, E = V.size(); I != E; ++I)
- if (V[I])
- Vec.push_back(I);
- P.printList(Name, Vec);
-}
-
-Error LLVMOutputStyle::dumpGlobalsStream() {
- if (!opts::raw::DumpGlobals)
- return Error::success();
- if (!File.hasPDBGlobalsStream()) {
- P.printString("Globals Stream not present");
- return Error::success();
- }
-
- auto Globals = File.getPDBGlobalsStream();
- if (!Globals)
- return Globals.takeError();
- DictScope D(P, "Globals Stream");
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- P.printNumber("Stream number", Dbi->getGlobalSymbolStreamIndex());
- P.printNumber("Number of buckets", Globals->getNumBuckets());
- P.printList("Hash Buckets", Globals->getHashBuckets());
-
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpStreamBlocks() {
- if (!opts::raw::DumpStreamBlocks)
- return Error::success();
-
- ListScope L(P, "StreamBlocks");
- uint32_t StreamCount = File.getNumStreams();
- for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
- std::string Name("Stream ");
- Name += to_string(StreamIdx);
- auto StreamBlocks = File.getStreamBlockList(StreamIdx);
- P.printList(Name, StreamBlocks);
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpBlockRanges() {
- if (!opts::raw::DumpBlockRange.hasValue())
- return Error::success();
- auto &R = *opts::raw::DumpBlockRange;
- uint32_t Max = R.Max.getValueOr(R.Min);
-
- if (Max < R.Min)
- return make_error<StringError>(
- "Invalid block range specified. Max < Min",
- std::make_error_code(std::errc::bad_address));
- if (Max >= File.getBlockCount())
- return make_error<StringError>(
- "Invalid block range specified. Requested block out of bounds",
- std::make_error_code(std::errc::bad_address));
-
- DictScope D(P, "Block Data");
- for (uint32_t I = R.Min; I <= Max; ++I) {
- auto ExpectedData = File.getBlockData(I, File.getBlockSize());
- if (!ExpectedData)
- return ExpectedData.takeError();
- std::string Label;
- llvm::raw_string_ostream S(Label);
- S << "Block " << I;
- S.flush();
- P.printBinaryBlock(Label, *ExpectedData);
- }
-
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpStreamBytes() {
- if (opts::raw::DumpStreamData.empty())
- return Error::success();
-
- discoverStreamPurposes();
-
- DictScope D(P, "Stream Data");
- for (uint32_t SI : opts::raw::DumpStreamData) {
- if (SI >= File.getNumStreams())
- return make_error<RawError>(raw_error_code::no_stream);
-
- auto S = MappedBlockStream::createIndexedStream(File.getMsfLayout(),
- File.getMsfBuffer(), SI);
- if (!S)
- continue;
- DictScope DD(P, "Stream");
-
- P.printNumber("Index", SI);
- P.printString("Type", StreamPurposes[SI]);
- P.printNumber("Size", S->getLength());
- auto Blocks = File.getMsfLayout().StreamMap[SI];
- P.printList("Blocks", Blocks);
-
- StreamReader R(*S);
- ArrayRef<uint8_t> StreamData;
- if (auto EC = R.readBytes(StreamData, S->getLength()))
- return EC;
- P.printBinaryBlock("Data", StreamData);
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpInfoStream() {
- if (!opts::raw::DumpHeaders)
- return Error::success();
- if (!File.hasPDBInfoStream()) {
- P.printString("PDB Stream not present");
- return Error::success();
- }
- auto IS = File.getPDBInfoStream();
- if (!IS)
- return IS.takeError();
-
- DictScope D(P, "PDB Stream");
- P.printNumber("Version", IS->getVersion());
- P.printHex("Signature", IS->getSignature());
- P.printNumber("Age", IS->getAge());
- P.printObject("Guid", IS->getGuid());
- return Error::success();
-}
-
-static void printTypeIndexOffset(raw_ostream &OS,
- const TypeIndexOffset &TIOff) {
- OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}";
-}
-
-static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) {
- if (!opts::raw::DumpTpiHash)
- return;
- DictScope DD(P, "Hash");
- P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets());
- P.printNumber("Hash Key Size", Tpi.getHashKeySize());
- P.printList("Values", Tpi.getHashValues());
- P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(),
- printTypeIndexOffset);
- P.printList("Hash Adjustments", Tpi.getHashAdjustments(),
- printTypeIndexOffset);
-}
-
-Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
- assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
-
- bool DumpRecordBytes = false;
- bool DumpRecords = false;
- StringRef Label;
- StringRef VerLabel;
- if (StreamIdx == StreamTPI) {
- if (!File.hasPDBTpiStream()) {
- P.printString("Type Info Stream (TPI) not present");
- return Error::success();
- }
- DumpRecordBytes = opts::raw::DumpTpiRecordBytes;
- DumpRecords = opts::raw::DumpTpiRecords;
- Label = "Type Info Stream (TPI)";
- VerLabel = "TPI Version";
- } else if (StreamIdx == StreamIPI) {
- if (!File.hasPDBIpiStream()) {
- P.printString("Type Info Stream (IPI) not present");
- return Error::success();
- }
- DumpRecordBytes = opts::raw::DumpIpiRecordBytes;
- DumpRecords = opts::raw::DumpIpiRecords;
- Label = "Type Info Stream (IPI)";
- VerLabel = "IPI Version";
- }
- if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms)
- return Error::success();
-
- auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
- : File.getPDBIpiStream();
- if (!Tpi)
- return Tpi.takeError();
-
- CVTypeDumper Dumper(TypeDB);
- if (DumpRecords || DumpRecordBytes) {
- DictScope D(P, Label);
-
- P.printNumber(VerLabel, Tpi->getTpiVersion());
- P.printNumber("Record count", Tpi->NumTypeRecords());
-
- ListScope L(P, "Records");
-
- bool HadError = false;
- for (auto &Type : Tpi->types(&HadError)) {
- DictScope DD(P, "");
-
- if (DumpRecords) {
- TypeDumpVisitor TDV(TypeDB, &P, false);
- if (auto EC = Dumper.dump(Type, TDV))
- return EC;
- }
-
- if (DumpRecordBytes)
- P.printBinaryBlock("Bytes", Type.content());
- }
- dumpTpiHash(P, *Tpi);
- if (HadError)
- return make_error<RawError>(raw_error_code::corrupt_file,
- "TPI stream contained corrupt record");
- } else if (opts::raw::DumpModuleSyms) {
- // Even if the user doesn't want to dump type records, we still need to
- // iterate them in order to build the type database. So when they want to
- // dump symbols but not types, don't stick a dumper on the end, just build
- // the type database.
- TypeDatabaseVisitor DBV(TypeDB);
- TypeDeserializer Deserializer;
- TypeVisitorCallbackPipeline Pipeline;
- Pipeline.addCallbackToPipeline(Deserializer);
- Pipeline.addCallbackToPipeline(DBV);
-
- CVTypeVisitor Visitor(Pipeline);
-
- bool HadError = false;
- for (auto Type : Tpi->types(&HadError)) {
- if (auto EC = Visitor.visitTypeRecord(Type))
- return EC;
- }
-
- dumpTpiHash(P, *Tpi);
- if (HadError)
- return make_error<RawError>(raw_error_code::corrupt_file,
- "TPI stream contained corrupt record");
- }
- P.flush();
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpDbiStream() {
- bool DumpModules = opts::raw::DumpModules || opts::raw::DumpModuleSyms ||
- opts::raw::DumpModuleFiles || opts::raw::DumpLineInfo;
- if (!opts::raw::DumpHeaders && !DumpModules)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- auto DS = File.getPDBDbiStream();
- if (!DS)
- return DS.takeError();
-
- DictScope D(P, "DBI Stream");
- P.printNumber("Dbi Version", DS->getDbiVersion());
- P.printNumber("Age", DS->getAge());
- P.printBoolean("Incremental Linking", DS->isIncrementallyLinked());
- P.printBoolean("Has CTypes", DS->hasCTypes());
- P.printBoolean("Is Stripped", DS->isStripped());
- P.printObject("Machine Type", DS->getMachineType());
- P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex());
- P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex());
- P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex());
-
- uint16_t Major = DS->getBuildMajorVersion();
- uint16_t Minor = DS->getBuildMinorVersion();
- P.printVersion("Toolchain Version", Major, Minor);
-
- std::string DllName;
- raw_string_ostream DllStream(DllName);
- DllStream << "mspdb" << Major << Minor << ".dll version";
- DllStream.flush();
- P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion());
-
- if (DumpModules) {
- ListScope L(P, "Modules");
- for (auto &Modi : DS->modules()) {
- DictScope DD(P);
- P.printString("Name", Modi.Info.getModuleName().str());
- P.printNumber("Debug Stream Index", Modi.Info.getModuleStreamIndex());
- P.printString("Object File Name", Modi.Info.getObjFileName().str());
- P.printNumber("Num Files", Modi.Info.getNumberOfFiles());
- P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex());
- P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex());
- P.printNumber("Line Info Byte Size", Modi.Info.getLineInfoByteSize());
- P.printNumber("C13 Line Info Byte Size",
- Modi.Info.getC13LineInfoByteSize());
- P.printNumber("Symbol Byte Size", Modi.Info.getSymbolDebugInfoByteSize());
- P.printNumber("Type Server Index", Modi.Info.getTypeServerIndex());
- P.printBoolean("Has EC Info", Modi.Info.hasECInfo());
- if (opts::raw::DumpModuleFiles) {
- std::string FileListName =
- to_string(Modi.SourceFiles.size()) + " Contributing Source Files";
- ListScope LL(P, FileListName);
- for (auto File : Modi.SourceFiles)
- P.printString(File.str());
- }
- bool HasModuleDI =
- (Modi.Info.getModuleStreamIndex() < File.getNumStreams());
- bool ShouldDumpSymbols =
- (opts::raw::DumpModuleSyms || opts::raw::DumpSymRecordBytes);
- if (HasModuleDI && (ShouldDumpSymbols || opts::raw::DumpLineInfo)) {
- auto ModStreamData = MappedBlockStream::createIndexedStream(
- File.getMsfLayout(), File.getMsfBuffer(),
- Modi.Info.getModuleStreamIndex());
-
- ModStream ModS(Modi.Info, std::move(ModStreamData));
- if (auto EC = ModS.reload())
- return EC;
-
- if (ShouldDumpSymbols) {
- ListScope SS(P, "Symbols");
- codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false);
- bool HadError = false;
- for (auto S : ModS.symbols(&HadError)) {
- DictScope LL(P, "");
- if (opts::raw::DumpModuleSyms) {
- if (auto EC = SD.dump(S)) {
- llvm::consumeError(std::move(EC));
- HadError = true;
- break;
- }
- }
- if (opts::raw::DumpSymRecordBytes)
- P.printBinaryBlock("Bytes", S.content());
- }
- if (HadError)
- return make_error<RawError>(
- raw_error_code::corrupt_file,
- "DBI stream contained corrupt symbol record");
- }
- if (opts::raw::DumpLineInfo) {
- ListScope SS(P, "LineInfo");
- bool HadError = false;
- // Define a locally scoped visitor to print the different
- // substream types types.
- class RecordVisitor : public codeview::IModuleSubstreamVisitor {
- public:
- RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {}
- Error visitUnknown(ModuleSubstreamKind Kind,
- ReadableStreamRef Stream) override {
- DictScope DD(P, "Unknown");
- ArrayRef<uint8_t> Data;
- StreamReader R(Stream);
- if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
- return make_error<RawError>(
- raw_error_code::corrupt_file,
- "DBI stream contained corrupt line info record");
- }
- P.printBinaryBlock("Data", Data);
- return Error::success();
- }
- Error
- visitFileChecksums(ReadableStreamRef Data,
- const FileChecksumArray &Checksums) override {
- DictScope DD(P, "FileChecksums");
- for (const auto &C : Checksums) {
- DictScope DDD(P, "Checksum");
- if (auto Result = getFileNameForOffset(C.FileNameOffset))
- P.printString("FileName", Result.get());
- else
- return Result.takeError();
- P.flush();
- P.printEnum("Kind", uint8_t(C.Kind), getFileChecksumNames());
- P.printBinaryBlock("Checksum", C.Checksum);
- }
- return Error::success();
- }
-
- Error visitLines(ReadableStreamRef Data,
- const LineSubstreamHeader *Header,
- const LineInfoArray &Lines) override {
- DictScope DD(P, "Lines");
- for (const auto &L : Lines) {
- if (auto Result = getFileNameForOffset2(L.NameIndex))
- P.printString("FileName", Result.get());
- else
- return Result.takeError();
- P.flush();
- for (const auto &N : L.LineNumbers) {
- DictScope DDD(P, "Line");
- LineInfo LI(N.Flags);
- P.printNumber("Offset", N.Offset);
- if (LI.isAlwaysStepInto())
- P.printString("StepInto", StringRef("Always"));
- else if (LI.isNeverStepInto())
- P.printString("StepInto", StringRef("Never"));
- else
- P.printNumber("LineNumberStart", LI.getStartLine());
- P.printNumber("EndDelta", LI.getLineDelta());
- P.printBoolean("IsStatement", LI.isStatement());
- }
- for (const auto &C : L.Columns) {
- DictScope DDD(P, "Column");
- P.printNumber("Start", C.StartColumn);
- P.printNumber("End", C.EndColumn);
- }
- }
- return Error::success();
- }
-
- private:
- Expected<StringRef> getFileNameForOffset(uint32_t Offset) {
- auto ST = F.getStringTable();
- if (!ST)
- return ST.takeError();
-
- return ST->getStringForID(Offset);
- }
- Expected<StringRef> getFileNameForOffset2(uint32_t Offset) {
- auto DS = F.getPDBDbiStream();
- if (!DS)
- return DS.takeError();
- return DS->getFileNameForIndex(Offset);
- }
- ScopedPrinter &P;
- PDBFile &F;
- };
-
- RecordVisitor V(P, File);
- for (const auto &L : ModS.lines(&HadError)) {
- if (auto EC = codeview::visitModuleSubstream(L, V))
- return EC;
- }
- }
- }
- }
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpSectionContribs() {
- if (!opts::raw::DumpSectionContribs)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- ListScope L(P, "Section Contributions");
- class Visitor : public ISectionContribVisitor {
- public:
- Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {}
- void visit(const SectionContrib &SC) override {
- DictScope D(P, "Contribution");
- P.printNumber("ISect", SC.ISect);
- P.printNumber("Off", SC.Off);
- P.printNumber("Size", SC.Size);
- P.printFlags("Characteristics", SC.Characteristics,
- codeview::getImageSectionCharacteristicNames(),
- COFF::SectionCharacteristics(0x00F00000));
- {
- DictScope DD(P, "Module");
- P.printNumber("Index", SC.Imod);
- auto M = DS.modules();
- if (M.size() > SC.Imod) {
- P.printString("Name", M[SC.Imod].Info.getModuleName());
- }
- }
- P.printNumber("Data CRC", SC.DataCrc);
- P.printNumber("Reloc CRC", SC.RelocCrc);
- P.flush();
- }
- void visit(const SectionContrib2 &SC) override {
- visit(SC.Base);
- P.printNumber("ISect Coff", SC.ISectCoff);
- P.flush();
- }
-
- private:
- ScopedPrinter &P;
- DbiStream &DS;
- };
- Visitor V(P, *Dbi);
- Dbi->visitSectionContributions(V);
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpSectionMap() {
- if (!opts::raw::DumpSectionMap)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- ListScope L(P, "Section Map");
- for (auto &M : Dbi->getSectionMap()) {
- DictScope D(P, "Entry");
- P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames());
- P.printNumber("Ovl", M.Ovl);
- P.printNumber("Group", M.Group);
- P.printNumber("Frame", M.Frame);
- P.printNumber("SecName", M.SecName);
- P.printNumber("ClassName", M.ClassName);
- P.printNumber("Offset", M.Offset);
- P.printNumber("SecByteLength", M.SecByteLength);
- P.flush();
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpPublicsStream() {
- if (!opts::raw::DumpPublics)
- return Error::success();
- if (!File.hasPDBPublicsStream()) {
- P.printString("Publics Stream not present");
- return Error::success();
- }
-
- auto Publics = File.getPDBPublicsStream();
- if (!Publics)
- return Publics.takeError();
- DictScope D(P, "Publics Stream");
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex());
- P.printNumber("SymHash", Publics->getSymHash());
- P.printNumber("AddrMap", Publics->getAddrMap());
- P.printNumber("Number of buckets", Publics->getNumBuckets());
- P.printList("Hash Buckets", Publics->getHashBuckets());
- P.printList("Address Map", Publics->getAddressMap());
- P.printList("Thunk Map", Publics->getThunkMap());
- P.printList("Section Offsets", Publics->getSectionOffsets(),
- printSectionOffset);
- ListScope L(P, "Symbols");
- codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false);
- bool HadError = false;
- for (auto S : Publics->getSymbols(&HadError)) {
- DictScope DD(P, "");
-
- if (auto EC = SD.dump(S)) {
- HadError = true;
- break;
- }
- if (opts::raw::DumpSymRecordBytes)
- P.printBinaryBlock("Bytes", S.content());
- }
- if (HadError)
- return make_error<RawError>(
- raw_error_code::corrupt_file,
- "Public symbol stream contained corrupt record");
-
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpSectionHeaders() {
- if (!opts::raw::DumpSectionHeaders)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- ListScope D(P, "Section Headers");
- for (const object::coff_section &Section : Dbi->getSectionHeaders()) {
- DictScope DD(P, "");
-
- // If a name is 8 characters long, there is no NUL character at end.
- StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name)));
- P.printString("Name", Name);
- P.printNumber("Virtual Size", Section.VirtualSize);
- P.printNumber("Virtual Address", Section.VirtualAddress);
- P.printNumber("Size of Raw Data", Section.SizeOfRawData);
- P.printNumber("File Pointer to Raw Data", Section.PointerToRawData);
- P.printNumber("File Pointer to Relocations", Section.PointerToRelocations);
- P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers);
- P.printNumber("Number of Relocations", Section.NumberOfRelocations);
- P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers);
- P.printFlags("Characteristics", Section.Characteristics,
- getImageSectionCharacteristicNames());
- }
- return Error::success();
-}
-
-Error LLVMOutputStyle::dumpFpoStream() {
- if (!opts::raw::DumpFpo)
- return Error::success();
- if (!File.hasPDBDbiStream()) {
- P.printString("DBI Stream not present");
- return Error::success();
- }
-
- auto Dbi = File.getPDBDbiStream();
- if (!Dbi)
- return Dbi.takeError();
-
- ListScope D(P, "New FPO");
- for (const object::FpoData &Fpo : Dbi->getFpoRecords()) {
- DictScope DD(P, "");
- P.printNumber("Offset", Fpo.Offset);
- P.printNumber("Size", Fpo.Size);
- P.printNumber("Number of locals", Fpo.NumLocals);
- P.printNumber("Number of params", Fpo.NumParams);
- P.printNumber("Size of Prolog", Fpo.getPrologSize());
- P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs());
- P.printBoolean("Has SEH", Fpo.hasSEH());
- P.printBoolean("Use BP", Fpo.useBP());
- P.printNumber("Frame Pointer", Fpo.getFP());
- }
- return Error::success();
-}
-
-void LLVMOutputStyle::flush() { P.flush(); }
diff --git a/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h b/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h
deleted file mode 100644
index 816d591..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//===- LLVMOutputStyle.h -------------------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H
-#define LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H
-
-#include "OutputStyle.h"
-
-#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
-#include "llvm/Support/ScopedPrinter.h"
-
-namespace llvm {
-class BitVector;
-namespace pdb {
-class LLVMOutputStyle : public OutputStyle {
-public:
- LLVMOutputStyle(PDBFile &File);
-
- Error dump() override;
-
-private:
- void discoverStreamPurposes();
-
- Error dumpFileHeaders();
- Error dumpStreamSummary();
- Error dumpFreePageMap();
- Error dumpBlockRanges();
- Error dumpGlobalsStream();
- Error dumpStreamBytes();
- Error dumpStreamBlocks();
- Error dumpInfoStream();
- Error dumpTpiStream(uint32_t StreamIdx);
- Error dumpDbiStream();
- Error dumpSectionContribs();
- Error dumpSectionMap();
- Error dumpPublicsStream();
- Error dumpSectionHeaders();
- Error dumpFpoStream();
-
- void dumpBitVector(StringRef Name, const BitVector &V);
-
- void flush();
-
- PDBFile &File;
- ScopedPrinter P;
- codeview::TypeDatabase TypeDB;
- std::vector<std::string> StreamPurposes;
-};
-}
-}
-
-#endif
diff --git a/contrib/llvm/tools/llvm-pdbdump/LinePrinter.cpp b/contrib/llvm/tools/llvm-pdbdump/LinePrinter.cpp
deleted file mode 100644
index 47c7d3e..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/LinePrinter.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "LinePrinter.h"
-
-#include "llvm-pdbdump.h"
-
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/Regex.h"
-
-#include <algorithm>
-
-using namespace llvm;
-using namespace llvm::pdb;
-
-namespace {
-bool IsItemExcluded(llvm::StringRef Item,
- std::list<llvm::Regex> &IncludeFilters,
- std::list<llvm::Regex> &ExcludeFilters) {
- if (Item.empty())
- return false;
-
- auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); };
-
- // Include takes priority over exclude. If the user specified include
- // filters, and none of them include this item, them item is gone.
- if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))
- return true;
-
- if (any_of(ExcludeFilters, match_pred))
- return true;
-
- return false;
-}
-}
-
-using namespace llvm;
-
-LinePrinter::LinePrinter(int Indent, llvm::raw_ostream &Stream)
- : OS(Stream), IndentSpaces(Indent), CurrentIndent(0) {
- SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(),
- opts::pretty::ExcludeTypes.end());
- SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(),
- opts::pretty::ExcludeSymbols.end());
- SetFilters(ExcludeCompilandFilters, opts::pretty::ExcludeCompilands.begin(),
- opts::pretty::ExcludeCompilands.end());
-
- SetFilters(IncludeTypeFilters, opts::pretty::IncludeTypes.begin(),
- opts::pretty::IncludeTypes.end());
- SetFilters(IncludeSymbolFilters, opts::pretty::IncludeSymbols.begin(),
- opts::pretty::IncludeSymbols.end());
- SetFilters(IncludeCompilandFilters, opts::pretty::IncludeCompilands.begin(),
- opts::pretty::IncludeCompilands.end());
-}
-
-void LinePrinter::Indent() { CurrentIndent += IndentSpaces; }
-
-void LinePrinter::Unindent() {
- CurrentIndent = std::max(0, CurrentIndent - IndentSpaces);
-}
-
-void LinePrinter::NewLine() {
- OS << "\n";
- OS.indent(CurrentIndent);
-}
-
-bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName) {
- return IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters);
-}
-
-bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
- return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);
-}
-
-bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
- return IsItemExcluded(CompilandName, IncludeCompilandFilters,
- ExcludeCompilandFilters);
-}
-
-WithColor::WithColor(LinePrinter &P, PDB_ColorItem C) : OS(P.OS) {
- applyColor(C);
-}
-
-WithColor::~WithColor() { OS.resetColor(); }
-
-void WithColor::applyColor(PDB_ColorItem C) {
- switch (C) {
- case PDB_ColorItem::None:
- OS.resetColor();
- return;
- case PDB_ColorItem::Address:
- OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
- return;
- case PDB_ColorItem::Keyword:
- OS.changeColor(raw_ostream::MAGENTA, true);
- return;
- case PDB_ColorItem::Register:
- case PDB_ColorItem::Offset:
- OS.changeColor(raw_ostream::YELLOW, false);
- return;
- case PDB_ColorItem::Type:
- OS.changeColor(raw_ostream::CYAN, true);
- return;
- case PDB_ColorItem::Identifier:
- OS.changeColor(raw_ostream::CYAN, false);
- return;
- case PDB_ColorItem::Path:
- OS.changeColor(raw_ostream::CYAN, false);
- return;
- case PDB_ColorItem::SectionHeader:
- OS.changeColor(raw_ostream::RED, true);
- return;
- case PDB_ColorItem::LiteralValue:
- OS.changeColor(raw_ostream::GREEN, true);
- return;
- }
-}
diff --git a/contrib/llvm/tools/llvm-pdbdump/PdbYaml.h b/contrib/llvm/tools/llvm-pdbdump/PdbYaml.h
deleted file mode 100644
index 398186f..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/PdbYaml.h
+++ /dev/null
@@ -1,174 +0,0 @@
-//===- PdbYAML.h ---------------------------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H
-#define LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H
-
-#include "OutputStyle.h"
-
-#include "llvm/ADT/Optional.h"
-#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/MSF/MSFCommon.h"
-#include "llvm/DebugInfo/PDB/PDBTypes.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/YAMLTraits.h"
-
-#include <vector>
-
-namespace llvm {
-namespace pdb {
-
-namespace yaml {
-struct SerializationContext;
-
-struct MSFHeaders {
- msf::SuperBlock SuperBlock;
- uint32_t NumDirectoryBlocks;
- std::vector<uint32_t> DirectoryBlocks;
- uint32_t NumStreams;
- uint32_t FileSize;
-};
-
-struct StreamBlockList {
- std::vector<uint32_t> Blocks;
-};
-
-struct NamedStreamMapping {
- StringRef StreamName;
- uint32_t StreamNumber;
-};
-
-struct PdbInfoStream {
- PdbRaw_ImplVer Version;
- uint32_t Signature;
- uint32_t Age;
- PDB_UniqueId Guid;
- std::vector<NamedStreamMapping> NamedStreams;
-};
-
-struct PdbSymbolRecord {
- codeview::CVSymbol Record;
-};
-
-struct PdbModiStream {
- uint32_t Signature;
- std::vector<PdbSymbolRecord> Symbols;
-};
-
-struct PdbDbiModuleInfo {
- StringRef Obj;
- StringRef Mod;
- std::vector<StringRef> SourceFiles;
- Optional<PdbModiStream> Modi;
-};
-
-struct PdbDbiStream {
- PdbRaw_DbiVer VerHeader;
- uint32_t Age;
- uint16_t BuildNumber;
- uint32_t PdbDllVersion;
- uint16_t PdbDllRbld;
- uint16_t Flags;
- PDB_Machine MachineType;
-
- std::vector<PdbDbiModuleInfo> ModInfos;
-};
-
-struct PdbTpiRecord {
- codeview::CVType Record;
-};
-
-struct PdbTpiFieldListRecord {
- codeview::CVMemberRecord Record;
-};
-
-struct PdbTpiStream {
- PdbRaw_TpiVer Version;
- std::vector<PdbTpiRecord> Records;
-};
-
-struct PdbObject {
- explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {}
-
- Optional<MSFHeaders> Headers;
- Optional<std::vector<uint32_t>> StreamSizes;
- Optional<std::vector<StreamBlockList>> StreamMap;
- Optional<PdbInfoStream> PdbStream;
- Optional<PdbDbiStream> DbiStream;
- Optional<PdbTpiStream> TpiStream;
- Optional<PdbTpiStream> IpiStream;
-
- BumpPtrAllocator &Allocator;
-};
-}
-}
-}
-
-namespace llvm {
-namespace yaml {
-
-template <> struct MappingTraits<pdb::yaml::PdbObject> {
- static void mapping(IO &IO, pdb::yaml::PdbObject &Obj);
-};
-
-template <> struct MappingTraits<pdb::yaml::MSFHeaders> {
- static void mapping(IO &IO, pdb::yaml::MSFHeaders &Obj);
-};
-
-template <> struct MappingTraits<msf::SuperBlock> {
- static void mapping(IO &IO, msf::SuperBlock &SB);
-};
-
-template <> struct MappingTraits<pdb::yaml::StreamBlockList> {
- static void mapping(IO &IO, pdb::yaml::StreamBlockList &SB);
-};
-
-template <> struct MappingTraits<pdb::yaml::PdbInfoStream> {
- static void mapping(IO &IO, pdb::yaml::PdbInfoStream &Obj);
-};
-
-template <> struct MappingTraits<pdb::yaml::PdbDbiStream> {
- static void mapping(IO &IO, pdb::yaml::PdbDbiStream &Obj);
-};
-
-template <>
-struct MappingContextTraits<pdb::yaml::PdbTpiStream, llvm::BumpPtrAllocator> {
- static void mapping(IO &IO, pdb::yaml::PdbTpiStream &Obj,
- llvm::BumpPtrAllocator &Allocator);
-};
-
-template <> struct MappingTraits<pdb::yaml::NamedStreamMapping> {
- static void mapping(IO &IO, pdb::yaml::NamedStreamMapping &Obj);
-};
-
-template <> struct MappingTraits<pdb::yaml::PdbSymbolRecord> {
- static void mapping(IO &IO, pdb::yaml::PdbSymbolRecord &Obj);
-};
-
-template <> struct MappingTraits<pdb::yaml::PdbModiStream> {
- static void mapping(IO &IO, pdb::yaml::PdbModiStream &Obj);
-};
-
-template <> struct MappingTraits<pdb::yaml::PdbDbiModuleInfo> {
- static void mapping(IO &IO, pdb::yaml::PdbDbiModuleInfo &Obj);
-};
-
-template <>
-struct MappingContextTraits<pdb::yaml::PdbTpiRecord,
- pdb::yaml::SerializationContext> {
- static void mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj,
- pdb::yaml::SerializationContext &Context);
-};
-}
-}
-
-#endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp b/contrib/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
deleted file mode 100644
index b0c534f..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-//===- PrettyClassDefinitionDumper.cpp --------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "PrettyClassDefinitionDumper.h"
-
-#include "LinePrinter.h"
-#include "PrettyEnumDumper.h"
-#include "PrettyFunctionDumper.h"
-#include "PrettyTypedefDumper.h"
-#include "PrettyVariableDumper.h"
-#include "llvm-pdbdump.h"
-
-#include "llvm/DebugInfo/PDB/IPDBSession.h"
-#include "llvm/DebugInfo/PDB/PDBExtras.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
-#include "llvm/Support/Format.h"
-
-using namespace llvm;
-using namespace llvm::pdb;
-
-ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
- : PDBSymDumper(true), Printer(P) {}
-
-void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
- std::string Name = Class.getName();
- WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
- WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
-
- auto Bases = Class.findAllChildren<PDBSymbolTypeBaseClass>();
- if (Bases->getChildCount() > 0) {
- Printer.Indent();
- Printer.NewLine();
- Printer << ":";
- uint32_t BaseIndex = 0;
- while (auto Base = Bases->getNext()) {
- Printer << " ";
- WithColor(Printer, PDB_ColorItem::Keyword).get() << Base->getAccess();
- if (Base->isVirtualBaseClass())
- WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
- WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base->getName();
- if (++BaseIndex < Bases->getChildCount()) {
- Printer.NewLine();
- Printer << ",";
- }
- }
- Printer.Unindent();
- }
-
- Printer << " {";
- auto Children = Class.findAllChildren();
- if (Children->getChildCount() == 0) {
- Printer << "}";
- return;
- }
-
- // Try to dump symbols organized by member access level. Public members
- // first, then protected, then private. This might be slow, so it's worth
- // reconsidering the value of this if performance of large PDBs is a problem.
- // NOTE: Access level of nested types is not recorded in the PDB, so we have
- // a special case for them.
- SymbolGroupByAccess Groups;
- Groups.insert(std::make_pair(0, SymbolGroup()));
- Groups.insert(std::make_pair((int)PDB_MemberAccess::Private, SymbolGroup()));
- Groups.insert(
- std::make_pair((int)PDB_MemberAccess::Protected, SymbolGroup()));
- Groups.insert(std::make_pair((int)PDB_MemberAccess::Public, SymbolGroup()));
-
- while (auto Child = Children->getNext()) {
- PDB_MemberAccess Access = Child->getRawSymbol().getAccess();
- if (isa<PDBSymbolTypeBaseClass>(*Child))
- continue;
-
- auto &AccessGroup = Groups.find((int)Access)->second;
-
- if (auto Func = dyn_cast<PDBSymbolFunc>(Child.get())) {
- if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
- continue;
- if (Func->getLength() == 0 && !Func->isPureVirtual() &&
- !Func->isIntroVirtualFunction())
- continue;
- Child.release();
- AccessGroup.Functions.push_back(std::unique_ptr<PDBSymbolFunc>(Func));
- } else if (auto Data = dyn_cast<PDBSymbolData>(Child.get())) {
- Child.release();
- AccessGroup.Data.push_back(std::unique_ptr<PDBSymbolData>(Data));
- } else {
- AccessGroup.Unknown.push_back(std::move(Child));
- }
- }
-
- int Count = 0;
- Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0]);
- Count += dumpAccessGroup(PDB_MemberAccess::Public,
- Groups[(int)PDB_MemberAccess::Public]);
- Count += dumpAccessGroup(PDB_MemberAccess::Protected,
- Groups[(int)PDB_MemberAccess::Protected]);
- Count += dumpAccessGroup(PDB_MemberAccess::Private,
- Groups[(int)PDB_MemberAccess::Private]);
- if (Count > 0)
- Printer.NewLine();
- Printer << "}";
-}
-
-int ClassDefinitionDumper::dumpAccessGroup(PDB_MemberAccess Access,
- const SymbolGroup &Group) {
- if (Group.Functions.empty() && Group.Data.empty() && Group.Unknown.empty())
- return 0;
-
- int Count = 0;
- if (Access == PDB_MemberAccess::Private) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "private";
- Printer << ":";
- } else if (Access == PDB_MemberAccess::Protected) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "protected";
- Printer << ":";
- } else if (Access == PDB_MemberAccess::Public) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "public";
- Printer << ":";
- }
- Printer.Indent();
- for (auto iter = Group.Functions.begin(), end = Group.Functions.end();
- iter != end; ++iter) {
- ++Count;
- (*iter)->dump(*this);
- }
- for (auto iter = Group.Data.begin(), end = Group.Data.end(); iter != end;
- ++iter) {
- ++Count;
- (*iter)->dump(*this);
- }
- for (auto iter = Group.Unknown.begin(), end = Group.Unknown.end();
- iter != end; ++iter) {
- ++Count;
- (*iter)->dump(*this);
- }
- Printer.Unindent();
- return Count;
-}
-
-void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
-
-void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
- VariableDumper Dumper(Printer);
- Dumper.start(Symbol);
-}
-
-void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) {
- if (Printer.IsSymbolExcluded(Symbol.getName()))
- return;
-
- Printer.NewLine();
- FunctionDumper Dumper(Printer);
- Dumper.start(Symbol, FunctionDumper::PointerType::None);
-}
-
-void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {}
-
-void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
-
- Printer.NewLine();
- EnumDumper Dumper(Printer);
- Dumper.start(Symbol);
-}
-
-void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
-
- Printer.NewLine();
- TypedefDumper Dumper(Printer);
- Dumper.start(Symbol);
-}
-
-void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h b/contrib/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h
deleted file mode 100644
index 0831f47..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h
+++ /dev/null
@@ -1,63 +0,0 @@
-//===- PrettyClassDefinitionDumper.h ----------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H
-#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H
-
-#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
-
-#include <list>
-#include <memory>
-#include <unordered_map>
-
-namespace llvm {
-namespace pdb {
-
-class LinePrinter;
-
-class ClassDefinitionDumper : public PDBSymDumper {
-public:
- ClassDefinitionDumper(LinePrinter &P);
-
- void start(const PDBSymbolTypeUDT &Exe);
-
- void dump(const PDBSymbolTypeBaseClass &Symbol) override;
- void dump(const PDBSymbolData &Symbol) override;
- void dump(const PDBSymbolTypeEnum &Symbol) override;
- void dump(const PDBSymbolFunc &Symbol) override;
- void dump(const PDBSymbolTypeTypedef &Symbol) override;
- void dump(const PDBSymbolTypeUDT &Symbol) override;
- void dump(const PDBSymbolTypeVTable &Symbol) override;
-
-private:
- LinePrinter &Printer;
-
- struct SymbolGroup {
- SymbolGroup() {}
- SymbolGroup(SymbolGroup &&Other) {
- Functions = std::move(Other.Functions);
- Data = std::move(Other.Data);
- Unknown = std::move(Other.Unknown);
- }
-
- std::list<std::unique_ptr<PDBSymbolFunc>> Functions;
- std::list<std::unique_ptr<PDBSymbolData>> Data;
- std::list<std::unique_ptr<PDBSymbol>> Unknown;
- SymbolGroup(const SymbolGroup &other) = delete;
- SymbolGroup &operator=(const SymbolGroup &other) = delete;
- };
- typedef std::unordered_map<int, SymbolGroup> SymbolGroupByAccess;
-
- int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group);
-};
-}
-}
-#endif
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp b/contrib/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp
deleted file mode 100644
index 4f70c80..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "PrettyTypeDumper.h"
-
-#include "LinePrinter.h"
-#include "PrettyBuiltinDumper.h"
-#include "PrettyClassDefinitionDumper.h"
-#include "PrettyEnumDumper.h"
-#include "PrettyTypedefDumper.h"
-#include "llvm-pdbdump.h"
-
-#include "llvm/DebugInfo/PDB/IPDBSession.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
-
-using namespace llvm;
-using namespace llvm::pdb;
-
-TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
-
-void TypeDumper::start(const PDBSymbolExe &Exe) {
- auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>();
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
- Printer << ": (" << Enums->getChildCount() << " items)";
- Printer.Indent();
- while (auto Enum = Enums->getNext())
- Enum->dump(*this);
- Printer.Unindent();
-
- auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>();
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
- Printer << ": (" << Typedefs->getChildCount() << " items)";
- Printer.Indent();
- while (auto Typedef = Typedefs->getNext())
- Typedef->dump(*this);
- Printer.Unindent();
-
- auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>();
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
- Printer << ": (" << Classes->getChildCount() << " items)";
- Printer.Indent();
- while (auto Class = Classes->getNext())
- Class->dump(*this);
- Printer.Unindent();
-}
-
-void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
- if (Symbol.getUnmodifiedTypeId() != 0)
- return;
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
- // Dump member enums when dumping their class definition.
- if (nullptr != Symbol.getClassParent())
- return;
-
- Printer.NewLine();
- EnumDumper Dumper(Printer);
- Dumper.start(Symbol);
-}
-
-void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
-
- Printer.NewLine();
- TypedefDumper Dumper(Printer);
- Dumper.start(Symbol);
-}
-
-void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
- if (Symbol.getUnmodifiedTypeId() != 0)
- return;
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
-
- Printer.NewLine();
-
- if (opts::pretty::NoClassDefs) {
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
- WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
- } else {
- ClassDefinitionDumper Dumper(Printer);
- Dumper.start(Symbol);
- }
-}
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp b/contrib/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp
deleted file mode 100644
index e146918..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-//===- PrettyVariableDumper.cpp ---------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "PrettyVariableDumper.h"
-
-#include "LinePrinter.h"
-#include "PrettyBuiltinDumper.h"
-#include "PrettyFunctionDumper.h"
-#include "llvm-pdbdump.h"
-
-#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
-
-#include "llvm/Support/Format.h"
-
-using namespace llvm;
-using namespace llvm::pdb;
-
-VariableDumper::VariableDumper(LinePrinter &P)
- : PDBSymDumper(true), Printer(P) {}
-
-void VariableDumper::start(const PDBSymbolData &Var) {
- if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
- return;
- if (Printer.IsSymbolExcluded(Var.getName()))
- return;
-
- auto VarType = Var.getType();
-
- switch (auto LocType = Var.getLocationType()) {
- case PDB_LocType::Static:
- Printer.NewLine();
- Printer << "data [";
- WithColor(Printer, PDB_ColorItem::Address).get()
- << format_hex(Var.getVirtualAddress(), 10);
- Printer << "] ";
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "static ";
- dumpSymbolTypeAndName(*VarType, Var.getName());
- break;
- case PDB_LocType::Constant:
- if (isa<PDBSymbolTypeEnum>(*VarType))
- break;
- Printer.NewLine();
- Printer << "data ";
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
- dumpSymbolTypeAndName(*VarType, Var.getName());
- Printer << " = ";
- WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue();
- break;
- case PDB_LocType::ThisRel:
- Printer.NewLine();
- Printer << "data ";
- WithColor(Printer, PDB_ColorItem::Offset).get()
- << "+" << format_hex(Var.getOffset(), 4) << " ";
- dumpSymbolTypeAndName(*VarType, Var.getName());
- break;
- case PDB_LocType::BitField:
- Printer.NewLine();
- Printer << "data ";
- WithColor(Printer, PDB_ColorItem::Offset).get()
- << "+" << format_hex(Var.getOffset(), 4) << " ";
- dumpSymbolTypeAndName(*VarType, Var.getName());
- Printer << " : ";
- WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength();
- break;
- default:
- Printer.NewLine();
- Printer << "data ";
- Printer << "unknown(" << LocType << ") ";
- WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName();
- break;
- }
-}
-
-void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
- BuiltinDumper Dumper(Printer);
- Dumper.start(Symbol);
-}
-
-void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) {
- WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
-}
-
-void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {}
-
-void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) {
- auto PointeeType = Symbol.getPointeeType();
- if (!PointeeType)
- return;
-
- if (auto Func = dyn_cast<PDBSymbolFunc>(PointeeType.get())) {
- FunctionDumper NestedDumper(Printer);
- FunctionDumper::PointerType Pointer =
- Symbol.isReference() ? FunctionDumper::PointerType::Reference
- : FunctionDumper::PointerType::Pointer;
- NestedDumper.start(*Func, Pointer);
- } else {
- if (Symbol.isConstType())
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
- if (Symbol.isVolatileType())
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
- PointeeType->dump(*this);
- Printer << (Symbol.isReference() ? "&" : "*");
- }
-}
-
-void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
- WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef ";
- WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
-}
-
-void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) {
- WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
-}
-
-void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type,
- StringRef Name) {
- if (auto *ArrayType = dyn_cast<PDBSymbolTypeArray>(&Type)) {
- std::string IndexSpec;
- raw_string_ostream IndexStream(IndexSpec);
- std::unique_ptr<PDBSymbol> ElementType = ArrayType->getElementType();
- while (auto NestedArray = dyn_cast<PDBSymbolTypeArray>(ElementType.get())) {
- IndexStream << "[";
- IndexStream << NestedArray->getCount();
- IndexStream << "]";
- ElementType = NestedArray->getElementType();
- }
- IndexStream << "[" << ArrayType->getCount() << "]";
- ElementType->dump(*this);
- WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
- Printer << IndexStream.str();
- } else {
- if (!tryDumpFunctionPointer(Type, Name)) {
- Type.dump(*this);
- WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
- }
- }
-}
-
-bool VariableDumper::tryDumpFunctionPointer(const PDBSymbol &Type,
- StringRef Name) {
- // Function pointers come across as pointers to function signatures. But the
- // signature carries no name, so we have to handle this case separately.
- if (auto *PointerType = dyn_cast<PDBSymbolTypePointer>(&Type)) {
- auto PointeeType = PointerType->getPointeeType();
- if (auto *FunctionSig =
- dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
- FunctionDumper Dumper(Printer);
- FunctionDumper::PointerType PT = FunctionDumper::PointerType::Pointer;
- if (PointerType->isReference())
- PT = FunctionDumper::PointerType::Reference;
- std::string NameStr(Name.begin(), Name.end());
- Dumper.start(*FunctionSig, NameStr.c_str(), PT);
- return true;
- }
- }
- return false;
-}
diff --git a/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp
deleted file mode 100644
index 3f2733d..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp
+++ /dev/null
@@ -1,231 +0,0 @@
-//===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "YAMLOutputStyle.h"
-
-#include "PdbYaml.h"
-#include "llvm-pdbdump.h"
-
-#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
-#include "llvm/DebugInfo/PDB/Raw/ModStream.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
-
-using namespace llvm;
-using namespace llvm::pdb;
-
-YAMLOutputStyle::YAMLOutputStyle(PDBFile &File)
- : File(File), Out(outs()), Obj(File.getAllocator()) {}
-
-Error YAMLOutputStyle::dump() {
- if (opts::pdb2yaml::StreamDirectory)
- opts::pdb2yaml::StreamMetadata = true;
- if (opts::pdb2yaml::DbiModuleSyms)
- opts::pdb2yaml::DbiModuleInfo = true;
- if (opts::pdb2yaml::DbiModuleSourceFileInfo)
- opts::pdb2yaml::DbiModuleInfo = true;
- if (opts::pdb2yaml::DbiModuleInfo)
- opts::pdb2yaml::DbiStream = true;
-
- if (auto EC = dumpFileHeaders())
- return EC;
-
- if (auto EC = dumpStreamMetadata())
- return EC;
-
- if (auto EC = dumpStreamDirectory())
- return EC;
-
- if (auto EC = dumpPDBStream())
- return EC;
-
- if (auto EC = dumpDbiStream())
- return EC;
-
- if (auto EC = dumpTpiStream())
- return EC;
-
- if (auto EC = dumpIpiStream())
- return EC;
-
- flush();
- return Error::success();
-}
-
-Error YAMLOutputStyle::dumpFileHeaders() {
- if (opts::pdb2yaml::NoFileHeaders)
- return Error::success();
-
- yaml::MSFHeaders Headers;
- Obj.Headers.emplace();
- Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount();
- Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex();
- Obj.Headers->SuperBlock.BlockSize = File.getBlockSize();
- auto Blocks = File.getDirectoryBlockArray();
- Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end());
- Obj.Headers->NumDirectoryBlocks = File.getNumDirectoryBlocks();
- Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes();
- Obj.Headers->NumStreams =
- opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0;
- Obj.Headers->SuperBlock.FreeBlockMapBlock = File.getFreeBlockMapBlock();
- Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1();
- Obj.Headers->FileSize = File.getFileSize();
-
- return Error::success();
-}
-
-Error YAMLOutputStyle::dumpStreamMetadata() {
- if (!opts::pdb2yaml::StreamMetadata)
- return Error::success();
-
- Obj.StreamSizes.emplace();
- Obj.StreamSizes->assign(File.getStreamSizes().begin(),
- File.getStreamSizes().end());
- return Error::success();
-}
-
-Error YAMLOutputStyle::dumpStreamDirectory() {
- if (!opts::pdb2yaml::StreamDirectory)
- return Error::success();
-
- auto StreamMap = File.getStreamMap();
- Obj.StreamMap.emplace();
- for (auto &Stream : StreamMap) {
- pdb::yaml::StreamBlockList BlockList;
- BlockList.Blocks.assign(Stream.begin(), Stream.end());
- Obj.StreamMap->push_back(BlockList);
- }
-
- return Error::success();
-}
-
-Error YAMLOutputStyle::dumpPDBStream() {
- if (!opts::pdb2yaml::PdbStream)
- return Error::success();
-
- auto IS = File.getPDBInfoStream();
- if (!IS)
- return IS.takeError();
-
- auto &InfoS = IS.get();
- Obj.PdbStream.emplace();
- Obj.PdbStream->Age = InfoS.getAge();
- Obj.PdbStream->Guid = InfoS.getGuid();
- Obj.PdbStream->Signature = InfoS.getSignature();
- Obj.PdbStream->Version = InfoS.getVersion();
- for (auto &NS : InfoS.named_streams()) {
- yaml::NamedStreamMapping Mapping;
- Mapping.StreamName = NS.getKey();
- Mapping.StreamNumber = NS.getValue();
- Obj.PdbStream->NamedStreams.push_back(Mapping);
- }
-
- return Error::success();
-}
-
-Error YAMLOutputStyle::dumpDbiStream() {
- if (!opts::pdb2yaml::DbiStream)
- return Error::success();
-
- auto DbiS = File.getPDBDbiStream();
- if (!DbiS)
- return DbiS.takeError();
-
- auto &DS = DbiS.get();
- Obj.DbiStream.emplace();
- Obj.DbiStream->Age = DS.getAge();
- Obj.DbiStream->BuildNumber = DS.getBuildNumber();
- Obj.DbiStream->Flags = DS.getFlags();
- Obj.DbiStream->MachineType = DS.getMachineType();
- Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld();
- Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion();
- Obj.DbiStream->VerHeader = DS.getDbiVersion();
- if (opts::pdb2yaml::DbiModuleInfo) {
- for (const auto &MI : DS.modules()) {
- yaml::PdbDbiModuleInfo DMI;
- DMI.Mod = MI.Info.getModuleName();
- DMI.Obj = MI.Info.getObjFileName();
- if (opts::pdb2yaml::DbiModuleSourceFileInfo)
- DMI.SourceFiles = MI.SourceFiles;
-
- if (opts::pdb2yaml::DbiModuleSyms &&
- MI.Info.getModuleStreamIndex() != kInvalidStreamIndex) {
- DMI.Modi.emplace();
- auto ModStreamData = msf::MappedBlockStream::createIndexedStream(
- File.getMsfLayout(), File.getMsfBuffer(),
- MI.Info.getModuleStreamIndex());
-
- pdb::ModStream ModS(MI.Info, std::move(ModStreamData));
- if (auto EC = ModS.reload())
- return EC;
-
- DMI.Modi->Signature = ModS.signature();
- bool HadError = false;
- for (auto &Sym : ModS.symbols(&HadError)) {
- pdb::yaml::PdbSymbolRecord Record{Sym};
- DMI.Modi->Symbols.push_back(Record);
- }
- }
- Obj.DbiStream->ModInfos.push_back(DMI);
- }
- }
- return Error::success();
-}
-
-Error YAMLOutputStyle::dumpTpiStream() {
- if (!opts::pdb2yaml::TpiStream)
- return Error::success();
-
- auto TpiS = File.getPDBTpiStream();
- if (!TpiS)
- return TpiS.takeError();
-
- auto &TS = TpiS.get();
- Obj.TpiStream.emplace();
- Obj.TpiStream->Version = TS.getTpiVersion();
- for (auto &Record : TS.types(nullptr)) {
- yaml::PdbTpiRecord R;
- // It's not necessary to set R.RecordData here. That only exists as a
- // way to have the `PdbTpiRecord` structure own the memory that `R.Record`
- // references. In the case of reading an existing PDB though, that memory
- // is owned by the backing stream.
- R.Record = Record;
- Obj.TpiStream->Records.push_back(R);
- }
-
- return Error::success();
-}
-
-Error YAMLOutputStyle::dumpIpiStream() {
- if (!opts::pdb2yaml::IpiStream)
- return Error::success();
-
- auto IpiS = File.getPDBIpiStream();
- if (!IpiS)
- return IpiS.takeError();
-
- auto &IS = IpiS.get();
- Obj.IpiStream.emplace();
- Obj.IpiStream->Version = IS.getTpiVersion();
- for (auto &Record : IS.types(nullptr)) {
- yaml::PdbTpiRecord R;
- R.Record = Record;
- Obj.IpiStream->Records.push_back(R);
- }
-
- return Error::success();
-}
-
-void YAMLOutputStyle::flush() {
- Out << Obj;
- outs().flush();
-}
diff --git a/contrib/llvm/tools/llvm-pdbdump/YamlSerializationContext.h b/contrib/llvm/tools/llvm-pdbdump/YamlSerializationContext.h
deleted file mode 100644
index dcf29d2..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/YamlSerializationContext.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//===- YamlSerializationContext.h ----------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMPDBDUMP_YAMLSERIALIZATIONCONTEXT_H
-#define LLVM_TOOLS_LLVMPDBDUMP_YAMLSERIALIZATIONCONTEXT_H
-
-#include "PdbYaml.h"
-#include "YamlTypeDumper.h"
-#include "llvm/Support/Allocator.h"
-
-namespace llvm {
-namespace codeview {
-class TypeSerializer;
-}
-namespace yaml {
-class IO;
-}
-
-namespace pdb {
-namespace yaml {
-struct SerializationContext {
- explicit SerializationContext(llvm::yaml::IO &IO, BumpPtrAllocator &Allocator)
- : Dumper(IO, *this), Allocator(Allocator) {}
-
- codeview::yaml::YamlTypeDumperCallbacks Dumper;
- BumpPtrAllocator &Allocator;
- codeview::TypeSerializer *ActiveSerializer = nullptr;
-};
-}
-}
-}
-
-#endif \ No newline at end of file
diff --git a/contrib/llvm/tools/llvm-pdbdump/YamlSymbolDumper.cpp b/contrib/llvm/tools/llvm-pdbdump/YamlSymbolDumper.cpp
deleted file mode 100644
index 210260a..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/YamlSymbolDumper.cpp
+++ /dev/null
@@ -1,412 +0,0 @@
-//===- YamlSymbolDumper.cpp ----------------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "YamlSymbolDumper.h"
-#include "PdbYaml.h"
-#include "YamlTypeDumper.h"
-
-#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
-#include "llvm/DebugInfo/CodeView/EnumTables.h"
-#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
-#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
-#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-using namespace llvm::codeview::yaml;
-
-LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(TypeIndex)
-LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint64_t)
-LLVM_YAML_IS_SEQUENCE_VECTOR(OneMethodRecord)
-LLVM_YAML_IS_SEQUENCE_VECTOR(VFTableSlotKind)
-LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef)
-LLVM_YAML_IS_SEQUENCE_VECTOR(CVType)
-LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiFieldListRecord)
-
-namespace llvm {
-namespace yaml {
-void ScalarEnumerationTraits<SymbolKind>::enumeration(IO &io,
- SymbolKind &Value) {
- auto SymbolNames = getSymbolTypeNames();
- for (const auto &E : SymbolNames)
- io.enumCase(Value, E.Name.str().c_str(), E.Value);
-}
-
-template <> struct ScalarBitSetTraits<CompileSym2Flags> {
- static void bitset(IO &io, CompileSym2Flags &Flags) {
- auto FlagNames = getCompileSym2FlagNames();
- for (const auto &E : FlagNames) {
- io.bitSetCase(Flags, E.Name.str().c_str(),
- static_cast<CompileSym2Flags>(E.Value));
- }
- }
-};
-
-template <> struct ScalarBitSetTraits<CompileSym3Flags> {
- static void bitset(IO &io, CompileSym3Flags &Flags) {
- auto FlagNames = getCompileSym3FlagNames();
- for (const auto &E : FlagNames) {
- io.bitSetCase(Flags, E.Name.str().c_str(),
- static_cast<CompileSym3Flags>(E.Value));
- }
- }
-};
-
-template <> struct ScalarBitSetTraits<ExportFlags> {
- static void bitset(IO &io, ExportFlags &Flags) {
- auto FlagNames = getExportSymFlagNames();
- for (const auto &E : FlagNames) {
- io.bitSetCase(Flags, E.Name.str().c_str(),
- static_cast<ExportFlags>(E.Value));
- }
- }
-};
-
-template <> struct ScalarBitSetTraits<LocalSymFlags> {
- static void bitset(IO &io, LocalSymFlags &Flags) {
- auto FlagNames = getLocalFlagNames();
- for (const auto &E : FlagNames) {
- io.bitSetCase(Flags, E.Name.str().c_str(),
- static_cast<LocalSymFlags>(E.Value));
- }
- }
-};
-
-template <> struct ScalarBitSetTraits<ProcSymFlags> {
- static void bitset(IO &io, ProcSymFlags &Flags) {
- auto FlagNames = getProcSymFlagNames();
- for (const auto &E : FlagNames) {
- io.bitSetCase(Flags, E.Name.str().c_str(),
- static_cast<ProcSymFlags>(E.Value));
- }
- }
-};
-
-template <> struct ScalarBitSetTraits<FrameProcedureOptions> {
- static void bitset(IO &io, FrameProcedureOptions &Flags) {
- auto FlagNames = getFrameProcSymFlagNames();
- for (const auto &E : FlagNames) {
- io.bitSetCase(Flags, E.Name.str().c_str(),
- static_cast<FrameProcedureOptions>(E.Value));
- }
- }
-};
-
-template <> struct ScalarEnumerationTraits<CPUType> {
- static void enumeration(IO &io, CPUType &Cpu) {
- auto CpuNames = getCPUTypeNames();
- for (const auto &E : CpuNames) {
- io.enumCase(Cpu, E.Name.str().c_str(), static_cast<CPUType>(E.Value));
- }
- }
-};
-
-template <> struct ScalarEnumerationTraits<RegisterId> {
- static void enumeration(IO &io, RegisterId &Reg) {
- auto RegNames = getRegisterNames();
- for (const auto &E : RegNames) {
- io.enumCase(Reg, E.Name.str().c_str(), static_cast<RegisterId>(E.Value));
- }
- }
-};
-
-template <> struct ScalarEnumerationTraits<TrampolineType> {
- static void enumeration(IO &io, TrampolineType &Tramp) {
- auto TrampNames = getTrampolineNames();
- for (const auto &E : TrampNames) {
- io.enumCase(Tramp, E.Name.str().c_str(),
- static_cast<TrampolineType>(E.Value));
- }
- }
-};
-
-template <> struct ScalarEnumerationTraits<ThunkOrdinal> {
- static void enumeration(IO &io, ThunkOrdinal &Ord) {
- auto ThunkNames = getThunkOrdinalNames();
- for (const auto &E : ThunkNames) {
- io.enumCase(Ord, E.Name.str().c_str(),
- static_cast<ThunkOrdinal>(E.Value));
- }
- }
-};
-
-void MappingTraits<ScopeEndSym>::mapping(IO &IO, ScopeEndSym &Obj) {}
-
-void MappingTraits<Thunk32Sym>::mapping(IO &IO, Thunk32Sym &Thunk) {
- IO.mapRequired("Parent", Thunk.Parent);
- IO.mapRequired("End", Thunk.End);
- IO.mapRequired("Next", Thunk.Next);
- IO.mapRequired("Off", Thunk.Offset);
- IO.mapRequired("Seg", Thunk.Segment);
- IO.mapRequired("Len", Thunk.Length);
- IO.mapRequired("Ordinal", Thunk.Thunk);
-}
-
-void MappingTraits<TrampolineSym>::mapping(IO &IO, TrampolineSym &Tramp) {
- IO.mapRequired("Type", Tramp.Type);
- IO.mapRequired("Size", Tramp.Size);
- IO.mapRequired("ThunkOff", Tramp.ThunkOffset);
- IO.mapRequired("TargetOff", Tramp.TargetOffset);
- IO.mapRequired("ThunkSection", Tramp.ThunkSection);
- IO.mapRequired("TargetSection", Tramp.TargetSection);
-}
-
-void MappingTraits<SectionSym>::mapping(IO &IO, SectionSym &Section) {
- IO.mapRequired("SectionNumber", Section.SectionNumber);
- IO.mapRequired("Alignment", Section.Alignment);
- IO.mapRequired("Rva", Section.Rva);
- IO.mapRequired("Length", Section.Length);
- IO.mapRequired("Characteristics", Section.Characteristics);
- IO.mapRequired("Name", Section.Name);
-}
-
-void MappingTraits<CoffGroupSym>::mapping(IO &IO, CoffGroupSym &CoffGroup) {
- IO.mapRequired("Size", CoffGroup.Size);
- IO.mapRequired("Characteristics", CoffGroup.Characteristics);
- IO.mapRequired("Offset", CoffGroup.Offset);
- IO.mapRequired("Segment", CoffGroup.Segment);
- IO.mapRequired("Name", CoffGroup.Name);
-}
-
-void MappingTraits<ExportSym>::mapping(IO &IO, ExportSym &Export) {
- IO.mapRequired("Ordinal", Export.Ordinal);
- IO.mapRequired("Flags", Export.Flags);
- IO.mapRequired("Name", Export.Name);
-}
-
-void MappingTraits<ProcSym>::mapping(IO &IO, ProcSym &Proc) {
- // TODO: Print the linkage name
-
- IO.mapRequired("PtrParent", Proc.Parent);
- IO.mapRequired("PtrEnd", Proc.End);
- IO.mapRequired("PtrNext", Proc.Next);
- IO.mapRequired("CodeSize", Proc.CodeSize);
- IO.mapRequired("DbgStart", Proc.DbgStart);
- IO.mapRequired("DbgEnd", Proc.DbgEnd);
- IO.mapRequired("FunctionType", Proc.FunctionType);
- IO.mapRequired("Segment", Proc.Segment);
- IO.mapRequired("Flags", Proc.Flags);
- IO.mapRequired("DisplayName", Proc.Name);
-}
-
-void MappingTraits<RegisterSym>::mapping(IO &IO, RegisterSym &Register) {
- IO.mapRequired("Type", Register.Index);
- IO.mapRequired("Seg", Register.Register);
- IO.mapRequired("Name", Register.Name);
-}
-
-void MappingTraits<PublicSym32>::mapping(IO &IO, PublicSym32 &Public) {
- IO.mapRequired("Type", Public.Index);
- IO.mapRequired("Seg", Public.Segment);
- IO.mapRequired("Off", Public.Offset);
- IO.mapRequired("Name", Public.Name);
-}
-
-void MappingTraits<ProcRefSym>::mapping(IO &IO, ProcRefSym &ProcRef) {
- IO.mapRequired("SumName", ProcRef.SumName);
- IO.mapRequired("SymOffset", ProcRef.SymOffset);
- IO.mapRequired("Mod", ProcRef.Module);
- IO.mapRequired("Name", ProcRef.Name);
-}
-
-void MappingTraits<EnvBlockSym>::mapping(IO &IO, EnvBlockSym &EnvBlock) {
- IO.mapRequired("Entries", EnvBlock.Fields);
-}
-
-void MappingTraits<InlineSiteSym>::mapping(IO &IO, InlineSiteSym &InlineSite) {
- IO.mapRequired("PtrParent", InlineSite.Parent);
- IO.mapRequired("PtrEnd", InlineSite.End);
- IO.mapRequired("Inlinee", InlineSite.Inlinee);
- // TODO: The binary annotations
-}
-
-void MappingTraits<LocalSym>::mapping(IO &IO, LocalSym &Local) {
- IO.mapRequired("Type", Local.Type);
- IO.mapRequired("Flags", Local.Flags);
- IO.mapRequired("VarName", Local.Name);
-}
-
-void MappingTraits<DefRangeSym>::mapping(IO &IO, DefRangeSym &Obj) {
- // TODO: Print the subfields
-}
-
-void MappingTraits<DefRangeSubfieldSym>::mapping(IO &IO,
- DefRangeSubfieldSym &Obj) {
- // TODO: Print the subfields
-}
-
-void MappingTraits<DefRangeRegisterSym>::mapping(IO &IO,
- DefRangeRegisterSym &Obj) {
- // TODO: Print the subfields
-}
-
-void MappingTraits<DefRangeFramePointerRelSym>::mapping(
- IO &IO, DefRangeFramePointerRelSym &Obj) {
- // TODO: Print the subfields
-}
-
-void MappingTraits<DefRangeSubfieldRegisterSym>::mapping(
- IO &IO, DefRangeSubfieldRegisterSym &Obj) {
- // TODO: Print the subfields
-}
-
-void MappingTraits<DefRangeFramePointerRelFullScopeSym>::mapping(
- IO &IO, DefRangeFramePointerRelFullScopeSym &Obj) {
- // TODO: Print the subfields
-}
-
-void MappingTraits<DefRangeRegisterRelSym>::mapping(
- IO &IO, DefRangeRegisterRelSym &Obj) {
- // TODO: Print the subfields
-}
-
-void MappingTraits<BlockSym>::mapping(IO &IO, BlockSym &Block) {
- // TODO: Print the linkage name
- IO.mapRequired("PtrParent", Block.Parent);
- IO.mapRequired("PtrEnd", Block.End);
- IO.mapRequired("CodeSize", Block.CodeSize);
- IO.mapRequired("Segment", Block.Segment);
- IO.mapRequired("BlockName", Block.Name);
-}
-
-void MappingTraits<LabelSym>::mapping(IO &IO, LabelSym &Label) {
- // TODO: Print the linkage name
- IO.mapRequired("Segment", Label.Segment);
- IO.mapRequired("Flags", Label.Flags);
- IO.mapRequired("Flags", Label.Flags);
- IO.mapRequired("DisplayName", Label.Name);
-}
-
-void MappingTraits<ObjNameSym>::mapping(IO &IO, ObjNameSym &ObjName) {
- IO.mapRequired("Signature", ObjName.Signature);
- IO.mapRequired("ObjectName", ObjName.Name);
-}
-
-void MappingTraits<Compile2Sym>::mapping(IO &IO, Compile2Sym &Compile2) {
- IO.mapRequired("Flags", Compile2.Flags);
- IO.mapRequired("Machine", Compile2.Machine);
- IO.mapRequired("FrontendMajor", Compile2.VersionFrontendMajor);
- IO.mapRequired("FrontendMinor", Compile2.VersionFrontendMinor);
- IO.mapRequired("FrontendBuild", Compile2.VersionFrontendBuild);
- IO.mapRequired("BackendMajor", Compile2.VersionBackendMajor);
- IO.mapRequired("BackendMinor", Compile2.VersionBackendMinor);
- IO.mapRequired("BackendBuild", Compile2.VersionBackendBuild);
- IO.mapRequired("Version", Compile2.Version);
-}
-
-void MappingTraits<Compile3Sym>::mapping(IO &IO, Compile3Sym &Compile3) {
- IO.mapRequired("Flags", Compile3.Flags);
- IO.mapRequired("Machine", Compile3.Machine);
- IO.mapRequired("FrontendMajor", Compile3.VersionFrontendMajor);
- IO.mapRequired("FrontendMinor", Compile3.VersionFrontendMinor);
- IO.mapRequired("FrontendBuild", Compile3.VersionFrontendBuild);
- IO.mapRequired("FrontendQFE", Compile3.VersionFrontendQFE);
- IO.mapRequired("BackendMajor", Compile3.VersionBackendMajor);
- IO.mapRequired("BackendMinor", Compile3.VersionBackendMinor);
- IO.mapRequired("BackendBuild", Compile3.VersionBackendBuild);
- IO.mapRequired("BackendQFE", Compile3.VersionBackendQFE);
- IO.mapRequired("Version", Compile3.Version);
-}
-
-void MappingTraits<FrameProcSym>::mapping(IO &IO, FrameProcSym &FrameProc) {
- IO.mapRequired("TotalFrameBytes", FrameProc.TotalFrameBytes);
- IO.mapRequired("PaddingFrameBytes", FrameProc.PaddingFrameBytes);
- IO.mapRequired("OffsetToPadding", FrameProc.OffsetToPadding);
- IO.mapRequired("BytesOfCalleeSavedRegisters",
- FrameProc.BytesOfCalleeSavedRegisters);
- IO.mapRequired("OffsetOfExceptionHandler",
- FrameProc.OffsetOfExceptionHandler);
- IO.mapRequired("SectionIdOfExceptionHandler",
- FrameProc.SectionIdOfExceptionHandler);
- IO.mapRequired("Flags", FrameProc.Flags);
-}
-
-void MappingTraits<CallSiteInfoSym>::mapping(IO &IO,
- CallSiteInfoSym &CallSiteInfo) {
- // TODO: Map Linkage Name
- IO.mapRequired("Segment", CallSiteInfo.Segment);
- IO.mapRequired("Type", CallSiteInfo.Type);
-}
-
-void MappingTraits<FileStaticSym>::mapping(IO &IO, FileStaticSym &FileStatic) {
- IO.mapRequired("Index", FileStatic.Index);
- IO.mapRequired("ModFilenameOffset", FileStatic.ModFilenameOffset);
- IO.mapRequired("Flags", FileStatic.Flags);
- IO.mapRequired("Name", FileStatic.Name);
-}
-
-void MappingTraits<HeapAllocationSiteSym>::mapping(
- IO &IO, HeapAllocationSiteSym &HeapAllocSite) {
- // TODO: Map Linkage Name
- IO.mapRequired("Segment", HeapAllocSite.Segment);
- IO.mapRequired("CallInstructionSize", HeapAllocSite.CallInstructionSize);
- IO.mapRequired("Type", HeapAllocSite.Type);
-}
-
-void MappingTraits<FrameCookieSym>::mapping(IO &IO,
- FrameCookieSym &FrameCookie) {
- // TODO: Map Linkage Name
- IO.mapRequired("Register", FrameCookie.Register);
- IO.mapRequired("CookieKind", FrameCookie.CookieKind);
- IO.mapRequired("Flags", FrameCookie.Flags);
-}
-
-void MappingTraits<CallerSym>::mapping(IO &IO, CallerSym &Caller) {
- // TODO: Correctly handle the ArrayRef in here.
- std::vector<TypeIndex> Indices(Caller.Indices);
- IO.mapRequired("FuncID", Indices);
-}
-
-void MappingTraits<UDTSym>::mapping(IO &IO, UDTSym &UDT) {
- IO.mapRequired("Type", UDT.Type);
- IO.mapRequired("UDTName", UDT.Name);
-}
-
-void MappingTraits<BuildInfoSym>::mapping(IO &IO, BuildInfoSym &BuildInfo) {
- IO.mapRequired("BuildId", BuildInfo.BuildId);
-}
-
-void MappingTraits<BPRelativeSym>::mapping(IO &IO, BPRelativeSym &BPRel) {
- IO.mapRequired("Offset", BPRel.Offset);
- IO.mapRequired("Type", BPRel.Type);
- IO.mapRequired("VarName", BPRel.Name);
-}
-
-void MappingTraits<RegRelativeSym>::mapping(IO &IO, RegRelativeSym &RegRel) {
- IO.mapRequired("Offset", RegRel.Offset);
- IO.mapRequired("Type", RegRel.Type);
- IO.mapRequired("Register", RegRel.Register);
- IO.mapRequired("VarName", RegRel.Name);
-}
-
-void MappingTraits<ConstantSym>::mapping(IO &IO, ConstantSym &Constant) {
- IO.mapRequired("Type", Constant.Type);
- IO.mapRequired("Value", Constant.Value);
- IO.mapRequired("Name", Constant.Name);
-}
-
-void MappingTraits<DataSym>::mapping(IO &IO, DataSym &Data) {
- // TODO: Map linkage name
- IO.mapRequired("Type", Data.Type);
- IO.mapRequired("DisplayName", Data.Name);
-}
-
-void MappingTraits<ThreadLocalDataSym>::mapping(IO &IO,
- ThreadLocalDataSym &Data) {
- // TODO: Map linkage name
- IO.mapRequired("Type", Data.Type);
- IO.mapRequired("DisplayName", Data.Name);
-}
-}
-}
-
-Error llvm::codeview::yaml::YamlSymbolDumper::visitSymbolBegin(CVSymbol &CVR) {
- YamlIO.mapRequired("Kind", CVR.Type);
- return Error::success();
-}
diff --git a/contrib/llvm/tools/llvm-pdbdump/YamlSymbolDumper.h b/contrib/llvm/tools/llvm-pdbdump/YamlSymbolDumper.h
deleted file mode 100644
index 61e63f9..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/YamlSymbolDumper.h
+++ /dev/null
@@ -1,66 +0,0 @@
-//===- YamlSymbolDumper.h ------------------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMPDBDUMP_YAMLSYMBOLDUMPER_H
-#define LLVM_TOOLS_LLVMPDBDUMP_YAMLSYMBOLDUMPER_H
-
-#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
-#include "llvm/Support/YAMLTraits.h"
-
-namespace llvm {
-namespace pdb {
-namespace yaml {
-struct SerializationContext;
-}
-}
-namespace codeview {
-namespace yaml {
-class YamlSymbolDumper : public SymbolVisitorCallbacks {
-public:
- YamlSymbolDumper(llvm::yaml::IO &IO) : YamlIO(IO) {}
-
- virtual Error visitSymbolBegin(CVSymbol &Record) override;
-
-#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
- Error visitKnownRecord(CVSymbol &CVR, Name &Record) override { \
- visitKnownRecordImpl(#Name, CVR, Record); \
- return Error::success(); \
- }
-#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
-
-private:
- template <typename T>
- void visitKnownRecordImpl(const char *Name, CVSymbol &Type, T &Record) {
- YamlIO.mapRequired(Name, Record);
- }
-
- llvm::yaml::IO &YamlIO;
-};
-}
-}
-}
-
-namespace llvm {
-namespace yaml {
-template <> struct ScalarEnumerationTraits<codeview::SymbolKind> {
- static void enumeration(IO &io, codeview::SymbolKind &Value);
-};
-
-#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
- template <> struct MappingTraits<codeview::Name> { \
- static void mapping(IO &IO, codeview::Name &Obj); \
- };
-#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def"
-}
-}
-
-#endif
diff --git a/contrib/llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp b/contrib/llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp
deleted file mode 100644
index 5c527c7..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp
+++ /dev/null
@@ -1,599 +0,0 @@
-//===- YamlTypeDumper.cpp ------------------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "YamlTypeDumper.h"
-#include "PdbYaml.h"
-#include "YamlSerializationContext.h"
-
-#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/EnumTables.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-using namespace llvm::codeview::yaml;
-
-LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(TypeIndex)
-LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint64_t)
-LLVM_YAML_IS_SEQUENCE_VECTOR(OneMethodRecord)
-LLVM_YAML_IS_SEQUENCE_VECTOR(VFTableSlotKind)
-LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef)
-LLVM_YAML_IS_SEQUENCE_VECTOR(CVType)
-LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiFieldListRecord)
-
-namespace {
-struct FieldListRecordSplitter : public TypeVisitorCallbacks {
-public:
- explicit FieldListRecordSplitter(
- std::vector<llvm::pdb::yaml::PdbTpiFieldListRecord> &Records)
- : Records(Records) {}
-
-#define TYPE_RECORD(EnumName, EnumVal, Name)
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD(EnumName, EnumVal, Name) \
- Error visitKnownMember(CVMemberRecord &CVT, Name##Record &Record) override { \
- visitKnownMemberImpl(CVT); \
- return Error::success(); \
- }
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
-
-private:
- void visitKnownMemberImpl(CVMemberRecord &CVT) {
- llvm::pdb::yaml::PdbTpiFieldListRecord R;
- R.Record = CVT;
- Records.push_back(std::move(R));
- }
-
- std::vector<llvm::pdb::yaml::PdbTpiFieldListRecord> &Records;
-};
-}
-
-namespace llvm {
-namespace yaml {
-template <> struct ScalarEnumerationTraits<PointerToMemberRepresentation> {
- static void enumeration(IO &IO, PointerToMemberRepresentation &Value) {
- IO.enumCase(Value, "Unknown", PointerToMemberRepresentation::Unknown);
- IO.enumCase(Value, "SingleInheritanceData",
- PointerToMemberRepresentation::SingleInheritanceData);
- IO.enumCase(Value, "MultipleInheritanceData",
- PointerToMemberRepresentation::MultipleInheritanceData);
- IO.enumCase(Value, "VirtualInheritanceData",
- PointerToMemberRepresentation::VirtualInheritanceData);
- IO.enumCase(Value, "GeneralData",
- PointerToMemberRepresentation::GeneralData);
- IO.enumCase(Value, "SingleInheritanceFunction",
- PointerToMemberRepresentation::SingleInheritanceFunction);
- IO.enumCase(Value, "MultipleInheritanceFunction",
- PointerToMemberRepresentation::MultipleInheritanceFunction);
- IO.enumCase(Value, "VirtualInheritanceFunction",
- PointerToMemberRepresentation::VirtualInheritanceFunction);
- IO.enumCase(Value, "GeneralFunction",
- PointerToMemberRepresentation::GeneralFunction);
- }
-};
-
-template <> struct ScalarEnumerationTraits<VFTableSlotKind> {
- static void enumeration(IO &IO, VFTableSlotKind &Kind) {
- IO.enumCase(Kind, "Near16", VFTableSlotKind::Near16);
- IO.enumCase(Kind, "Far16", VFTableSlotKind::Far16);
- IO.enumCase(Kind, "This", VFTableSlotKind::This);
- IO.enumCase(Kind, "Outer", VFTableSlotKind::Outer);
- IO.enumCase(Kind, "Meta", VFTableSlotKind::Meta);
- IO.enumCase(Kind, "Near", VFTableSlotKind::Near);
- IO.enumCase(Kind, "Far", VFTableSlotKind::Far);
- }
-};
-
-template <> struct ScalarEnumerationTraits<CallingConvention> {
- static void enumeration(IO &IO, CallingConvention &Value) {
- IO.enumCase(Value, "NearC", CallingConvention::NearC);
- IO.enumCase(Value, "FarC", CallingConvention::FarC);
- IO.enumCase(Value, "NearPascal", CallingConvention::NearPascal);
- IO.enumCase(Value, "FarPascal", CallingConvention::FarPascal);
- IO.enumCase(Value, "NearFast", CallingConvention::NearFast);
- IO.enumCase(Value, "FarFast", CallingConvention::FarFast);
- IO.enumCase(Value, "NearStdCall", CallingConvention::NearStdCall);
- IO.enumCase(Value, "FarStdCall", CallingConvention::FarStdCall);
- IO.enumCase(Value, "NearSysCall", CallingConvention::NearSysCall);
- IO.enumCase(Value, "FarSysCall", CallingConvention::FarSysCall);
- IO.enumCase(Value, "ThisCall", CallingConvention::ThisCall);
- IO.enumCase(Value, "MipsCall", CallingConvention::MipsCall);
- IO.enumCase(Value, "Generic", CallingConvention::Generic);
- IO.enumCase(Value, "AlphaCall", CallingConvention::AlphaCall);
- IO.enumCase(Value, "PpcCall", CallingConvention::PpcCall);
- IO.enumCase(Value, "SHCall", CallingConvention::SHCall);
- IO.enumCase(Value, "ArmCall", CallingConvention::ArmCall);
- IO.enumCase(Value, "AM33Call", CallingConvention::AM33Call);
- IO.enumCase(Value, "TriCall", CallingConvention::TriCall);
- IO.enumCase(Value, "SH5Call", CallingConvention::SH5Call);
- IO.enumCase(Value, "M32RCall", CallingConvention::M32RCall);
- IO.enumCase(Value, "ClrCall", CallingConvention::ClrCall);
- IO.enumCase(Value, "Inline", CallingConvention::Inline);
- IO.enumCase(Value, "NearVector", CallingConvention::NearVector);
- }
-};
-
-template <> struct ScalarEnumerationTraits<PointerKind> {
- static void enumeration(IO &IO, PointerKind &Kind) {
- IO.enumCase(Kind, "Near16", PointerKind::Near16);
- IO.enumCase(Kind, "Far16", PointerKind::Far16);
- IO.enumCase(Kind, "Huge16", PointerKind::Huge16);
- IO.enumCase(Kind, "BasedOnSegment", PointerKind::BasedOnSegment);
- IO.enumCase(Kind, "BasedOnValue", PointerKind::BasedOnValue);
- IO.enumCase(Kind, "BasedOnSegmentValue", PointerKind::BasedOnSegmentValue);
- IO.enumCase(Kind, "BasedOnAddress", PointerKind::BasedOnAddress);
- IO.enumCase(Kind, "BasedOnSegmentAddress",
- PointerKind::BasedOnSegmentAddress);
- IO.enumCase(Kind, "BasedOnType", PointerKind::BasedOnType);
- IO.enumCase(Kind, "BasedOnSelf", PointerKind::BasedOnSelf);
- IO.enumCase(Kind, "Near32", PointerKind::Near32);
- IO.enumCase(Kind, "Far32", PointerKind::Far32);
- IO.enumCase(Kind, "Near64", PointerKind::Near64);
- }
-};
-
-template <> struct ScalarEnumerationTraits<PointerMode> {
- static void enumeration(IO &IO, PointerMode &Mode) {
- IO.enumCase(Mode, "Pointer", PointerMode::Pointer);
- IO.enumCase(Mode, "LValueReference", PointerMode::LValueReference);
- IO.enumCase(Mode, "PointerToDataMember", PointerMode::PointerToDataMember);
- IO.enumCase(Mode, "PointerToMemberFunction",
- PointerMode::PointerToMemberFunction);
- IO.enumCase(Mode, "RValueReference", PointerMode::RValueReference);
- }
-};
-
-template <> struct ScalarEnumerationTraits<HfaKind> {
- static void enumeration(IO &IO, HfaKind &Value) {
- IO.enumCase(Value, "None", HfaKind::None);
- IO.enumCase(Value, "Float", HfaKind::Float);
- IO.enumCase(Value, "Double", HfaKind::Double);
- IO.enumCase(Value, "Other", HfaKind::Other);
- }
-};
-
-template <> struct ScalarEnumerationTraits<MemberAccess> {
- static void enumeration(IO &IO, MemberAccess &Access) {
- IO.enumCase(Access, "None", MemberAccess::None);
- IO.enumCase(Access, "Private", MemberAccess::Private);
- IO.enumCase(Access, "Protected", MemberAccess::Protected);
- IO.enumCase(Access, "Public", MemberAccess::Public);
- }
-};
-
-template <> struct ScalarEnumerationTraits<MethodKind> {
- static void enumeration(IO &IO, MethodKind &Kind) {
- IO.enumCase(Kind, "Vanilla", MethodKind::Vanilla);
- IO.enumCase(Kind, "Virtual", MethodKind::Virtual);
- IO.enumCase(Kind, "Static", MethodKind::Static);
- IO.enumCase(Kind, "Friend", MethodKind::Friend);
- IO.enumCase(Kind, "IntroducingVirtual", MethodKind::IntroducingVirtual);
- IO.enumCase(Kind, "PureVirtual", MethodKind::PureVirtual);
- IO.enumCase(Kind, "PureIntroducingVirtual",
- MethodKind::PureIntroducingVirtual);
- }
-};
-
-template <> struct ScalarEnumerationTraits<WindowsRTClassKind> {
- static void enumeration(IO &IO, WindowsRTClassKind &Value) {
- IO.enumCase(Value, "None", WindowsRTClassKind::None);
- IO.enumCase(Value, "Ref", WindowsRTClassKind::RefClass);
- IO.enumCase(Value, "Value", WindowsRTClassKind::ValueClass);
- IO.enumCase(Value, "Interface", WindowsRTClassKind::Interface);
- }
-};
-
-template <> struct ScalarBitSetTraits<PointerOptions> {
- static void bitset(IO &IO, PointerOptions &Options) {
- IO.bitSetCase(Options, "None", PointerOptions::None);
- IO.bitSetCase(Options, "Flat32", PointerOptions::Flat32);
- IO.bitSetCase(Options, "Volatile", PointerOptions::Volatile);
- IO.bitSetCase(Options, "Const", PointerOptions::Const);
- IO.bitSetCase(Options, "Unaligned", PointerOptions::Unaligned);
- IO.bitSetCase(Options, "Restrict", PointerOptions::Restrict);
- IO.bitSetCase(Options, "WinRTSmartPointer",
- PointerOptions::WinRTSmartPointer);
- }
-};
-
-template <> struct ScalarBitSetTraits<ModifierOptions> {
- static void bitset(IO &IO, ModifierOptions &Options) {
- IO.bitSetCase(Options, "None", ModifierOptions::None);
- IO.bitSetCase(Options, "Const", ModifierOptions::Const);
- IO.bitSetCase(Options, "Volatile", ModifierOptions::Volatile);
- IO.bitSetCase(Options, "Unaligned", ModifierOptions::Unaligned);
- }
-};
-
-template <> struct ScalarBitSetTraits<FunctionOptions> {
- static void bitset(IO &IO, FunctionOptions &Options) {
- IO.bitSetCase(Options, "None", FunctionOptions::None);
- IO.bitSetCase(Options, "CxxReturnUdt", FunctionOptions::CxxReturnUdt);
- IO.bitSetCase(Options, "Constructor", FunctionOptions::Constructor);
- IO.bitSetCase(Options, "ConstructorWithVirtualBases",
- FunctionOptions::ConstructorWithVirtualBases);
- }
-};
-
-template <> struct ScalarBitSetTraits<ClassOptions> {
- static void bitset(IO &IO, ClassOptions &Options) {
- IO.bitSetCase(Options, "None", ClassOptions::None);
- IO.bitSetCase(Options, "HasConstructorOrDestructor",
- ClassOptions::HasConstructorOrDestructor);
- IO.bitSetCase(Options, "HasOverloadedOperator",
- ClassOptions::HasOverloadedOperator);
- IO.bitSetCase(Options, "Nested", ClassOptions::Nested);
- IO.bitSetCase(Options, "ContainsNestedClass",
- ClassOptions::ContainsNestedClass);
- IO.bitSetCase(Options, "HasOverloadedAssignmentOperator",
- ClassOptions::HasOverloadedAssignmentOperator);
- IO.bitSetCase(Options, "HasConversionOperator",
- ClassOptions::HasConversionOperator);
- IO.bitSetCase(Options, "ForwardReference", ClassOptions::ForwardReference);
- IO.bitSetCase(Options, "Scoped", ClassOptions::Scoped);
- IO.bitSetCase(Options, "HasUniqueName", ClassOptions::HasUniqueName);
- IO.bitSetCase(Options, "Sealed", ClassOptions::Sealed);
- IO.bitSetCase(Options, "Intrinsic", ClassOptions::Intrinsic);
- }
-};
-
-template <> struct ScalarBitSetTraits<MethodOptions> {
- static void bitset(IO &IO, MethodOptions &Options) {
- IO.bitSetCase(Options, "None", MethodOptions::None);
- IO.bitSetCase(Options, "Pseudo", MethodOptions::Pseudo);
- IO.bitSetCase(Options, "NoInherit", MethodOptions::NoInherit);
- IO.bitSetCase(Options, "NoConstruct", MethodOptions::NoConstruct);
- IO.bitSetCase(Options, "CompilerGenerated",
- MethodOptions::CompilerGenerated);
- IO.bitSetCase(Options, "Sealed", MethodOptions::Sealed);
- }
-};
-
-void ScalarTraits<APSInt>::output(const APSInt &S, void *,
- llvm::raw_ostream &OS) {
- S.print(OS, true);
-}
-StringRef ScalarTraits<APSInt>::input(StringRef Scalar, void *Ctx, APSInt &S) {
- S = APSInt(Scalar);
- return "";
-}
-
-bool ScalarTraits<APSInt>::mustQuote(StringRef Scalar) { return false; }
-
-void MappingContextTraits<CVType, pdb::yaml::SerializationContext>::mapping(
- IO &IO, CVType &Record, pdb::yaml::SerializationContext &Context) {
- if (IO.outputting()) {
- codeview::TypeDeserializer Deserializer;
-
- codeview::TypeVisitorCallbackPipeline Pipeline;
- Pipeline.addCallbackToPipeline(Deserializer);
- Pipeline.addCallbackToPipeline(Context.Dumper);
-
- codeview::CVTypeVisitor Visitor(Pipeline);
- consumeError(Visitor.visitTypeRecord(Record));
- }
-}
-
-void MappingTraits<StringIdRecord>::mapping(IO &IO, StringIdRecord &String) {
- IO.mapRequired("Id", String.Id);
- IO.mapRequired("String", String.String);
-}
-
-void MappingTraits<ArgListRecord>::mapping(IO &IO, ArgListRecord &Args) {
- IO.mapRequired("ArgIndices", Args.StringIndices);
-}
-
-void MappingTraits<ClassRecord>::mapping(IO &IO, ClassRecord &Class) {
- IO.mapRequired("MemberCount", Class.MemberCount);
- IO.mapRequired("Options", Class.Options);
- IO.mapRequired("FieldList", Class.FieldList);
- IO.mapRequired("Name", Class.Name);
- IO.mapRequired("UniqueName", Class.UniqueName);
- IO.mapRequired("DerivationList", Class.DerivationList);
- IO.mapRequired("VTableShape", Class.VTableShape);
- IO.mapRequired("Size", Class.Size);
-}
-
-void MappingTraits<UnionRecord>::mapping(IO &IO, UnionRecord &Union) {
- IO.mapRequired("MemberCount", Union.MemberCount);
- IO.mapRequired("Options", Union.Options);
- IO.mapRequired("FieldList", Union.FieldList);
- IO.mapRequired("Name", Union.Name);
- IO.mapRequired("UniqueName", Union.UniqueName);
- IO.mapRequired("Size", Union.Size);
-}
-
-void MappingTraits<EnumRecord>::mapping(IO &IO, EnumRecord &Enum) {
- IO.mapRequired("NumEnumerators", Enum.MemberCount);
- IO.mapRequired("Options", Enum.Options);
- IO.mapRequired("FieldList", Enum.FieldList);
- IO.mapRequired("Name", Enum.Name);
- IO.mapRequired("UniqueName", Enum.UniqueName);
- IO.mapRequired("UnderlyingType", Enum.UnderlyingType);
-}
-
-void MappingTraits<ArrayRecord>::mapping(IO &IO, ArrayRecord &AT) {
- IO.mapRequired("ElementType", AT.ElementType);
- IO.mapRequired("IndexType", AT.IndexType);
- IO.mapRequired("Size", AT.Size);
- IO.mapRequired("Name", AT.Name);
-}
-
-void MappingTraits<VFTableRecord>::mapping(IO &IO, VFTableRecord &VFT) {
- IO.mapRequired("CompleteClass", VFT.CompleteClass);
- IO.mapRequired("OverriddenVFTable", VFT.OverriddenVFTable);
- IO.mapRequired("VFPtrOffset", VFT.VFPtrOffset);
- IO.mapRequired("MethodNames", VFT.MethodNames);
-}
-
-void MappingTraits<MemberFuncIdRecord>::mapping(IO &IO,
- MemberFuncIdRecord &Id) {
- IO.mapRequired("ClassType", Id.ClassType);
- IO.mapRequired("FunctionType", Id.FunctionType);
- IO.mapRequired("Name", Id.Name);
-}
-
-void MappingTraits<ProcedureRecord>::mapping(IO &IO, ProcedureRecord &Proc) {
- IO.mapRequired("ReturnType", Proc.ReturnType);
- IO.mapRequired("CallConv", Proc.CallConv);
- IO.mapRequired("Options", Proc.Options);
- IO.mapRequired("ParameterCount", Proc.ParameterCount);
- IO.mapRequired("ArgumentList", Proc.ArgumentList);
-}
-
-void MappingTraits<MemberFunctionRecord>::mapping(IO &IO,
- MemberFunctionRecord &MF) {
- IO.mapRequired("ReturnType", MF.ReturnType);
- IO.mapRequired("ClassType", MF.ClassType);
- IO.mapRequired("ThisType", MF.ThisType);
- IO.mapRequired("CallConv", MF.CallConv);
- IO.mapRequired("Options", MF.Options);
- IO.mapRequired("ParameterCount", MF.ParameterCount);
- IO.mapRequired("ArgumentList", MF.ArgumentList);
- IO.mapRequired("ThisPointerAdjustment", MF.ThisPointerAdjustment);
-}
-
-void MappingTraits<MethodOverloadListRecord>::mapping(
- IO &IO, MethodOverloadListRecord &MethodList) {
- IO.mapRequired("Methods", MethodList.Methods);
-}
-
-void MappingTraits<FuncIdRecord>::mapping(IO &IO, FuncIdRecord &Func) {
- IO.mapRequired("ParentScope", Func.ParentScope);
- IO.mapRequired("FunctionType", Func.FunctionType);
- IO.mapRequired("Name", Func.Name);
-}
-
-void MappingTraits<TypeServer2Record>::mapping(IO &IO, TypeServer2Record &TS) {
- IO.mapRequired("Guid", TS.Guid);
- IO.mapRequired("Age", TS.Age);
- IO.mapRequired("Name", TS.Name);
-}
-
-void MappingTraits<PointerRecord>::mapping(IO &IO, PointerRecord &Ptr) {
- IO.mapRequired("ReferentType", Ptr.ReferentType);
- IO.mapRequired("Attrs", Ptr.Attrs);
- IO.mapOptional("MemberInfo", Ptr.MemberInfo);
-}
-
-void MappingTraits<MemberPointerInfo>::mapping(IO &IO, MemberPointerInfo &MPI) {
- IO.mapRequired("ContainingType", MPI.ContainingType);
- IO.mapRequired("Representation", MPI.Representation);
-}
-
-void MappingTraits<ModifierRecord>::mapping(IO &IO, ModifierRecord &Mod) {
- IO.mapRequired("ModifiedType", Mod.ModifiedType);
- IO.mapRequired("Modifiers", Mod.Modifiers);
-}
-
-void MappingTraits<BitFieldRecord>::mapping(IO &IO, BitFieldRecord &BitField) {
- IO.mapRequired("Type", BitField.Type);
- IO.mapRequired("BitSize", BitField.BitSize);
- IO.mapRequired("BitOffset", BitField.BitOffset);
-}
-
-void MappingTraits<VFTableShapeRecord>::mapping(IO &IO,
- VFTableShapeRecord &Shape) {
- IO.mapRequired("Slots", Shape.Slots);
-}
-
-void MappingTraits<UdtSourceLineRecord>::mapping(IO &IO,
- UdtSourceLineRecord &Line) {
- IO.mapRequired("UDT", Line.UDT);
- IO.mapRequired("SourceFile", Line.SourceFile);
- IO.mapRequired("LineNumber", Line.LineNumber);
-}
-
-void MappingTraits<UdtModSourceLineRecord>::mapping(
- IO &IO, UdtModSourceLineRecord &Line) {
- IO.mapRequired("UDT", Line.UDT);
- IO.mapRequired("SourceFile", Line.SourceFile);
- IO.mapRequired("LineNumber", Line.LineNumber);
- IO.mapRequired("Module", Line.Module);
-}
-
-void MappingTraits<BuildInfoRecord>::mapping(IO &IO, BuildInfoRecord &Args) {
- IO.mapRequired("ArgIndices", Args.ArgIndices);
-}
-
-void MappingTraits<NestedTypeRecord>::mapping(IO &IO,
- NestedTypeRecord &Nested) {
- IO.mapRequired("Type", Nested.Type);
- IO.mapRequired("Name", Nested.Name);
-}
-
-void MappingTraits<OneMethodRecord>::mapping(IO &IO, OneMethodRecord &Method) {
- IO.mapRequired("Type", Method.Type);
- IO.mapRequired("Attrs", Method.Attrs.Attrs);
- IO.mapRequired("VFTableOffset", Method.VFTableOffset);
- IO.mapRequired("Name", Method.Name);
-}
-
-void MappingTraits<OverloadedMethodRecord>::mapping(
- IO &IO, OverloadedMethodRecord &Method) {
- IO.mapRequired("NumOverloads", Method.NumOverloads);
- IO.mapRequired("MethodList", Method.MethodList);
- IO.mapRequired("Name", Method.Name);
-}
-
-void MappingTraits<DataMemberRecord>::mapping(IO &IO, DataMemberRecord &Field) {
- IO.mapRequired("Attrs", Field.Attrs.Attrs);
- IO.mapRequired("Type", Field.Type);
- IO.mapRequired("FieldOffset", Field.FieldOffset);
- IO.mapRequired("Name", Field.Name);
-}
-
-void MappingTraits<StaticDataMemberRecord>::mapping(
- IO &IO, StaticDataMemberRecord &Field) {
- IO.mapRequired("Attrs", Field.Attrs.Attrs);
- IO.mapRequired("Type", Field.Type);
- IO.mapRequired("Name", Field.Name);
-}
-
-void MappingTraits<VFPtrRecord>::mapping(IO &IO, VFPtrRecord &VFTable) {
- IO.mapRequired("Type", VFTable.Type);
-}
-
-void MappingTraits<EnumeratorRecord>::mapping(IO &IO, EnumeratorRecord &Enum) {
- IO.mapRequired("Attrs", Enum.Attrs.Attrs);
- IO.mapRequired("Value", Enum.Value);
- IO.mapRequired("Name", Enum.Name);
-}
-
-void MappingTraits<BaseClassRecord>::mapping(IO &IO, BaseClassRecord &Base) {
- IO.mapRequired("Attrs", Base.Attrs.Attrs);
- IO.mapRequired("Type", Base.Type);
- IO.mapRequired("Offset", Base.Offset);
-}
-
-void MappingTraits<VirtualBaseClassRecord>::mapping(
- IO &IO, VirtualBaseClassRecord &Base) {
- IO.mapRequired("Attrs", Base.Attrs.Attrs);
- IO.mapRequired("BaseType", Base.BaseType);
- IO.mapRequired("VBPtrType", Base.VBPtrType);
- IO.mapRequired("VBPtrOffset", Base.VBPtrOffset);
- IO.mapRequired("VTableIndex", Base.VTableIndex);
-}
-
-void MappingTraits<ListContinuationRecord>::mapping(
- IO &IO, ListContinuationRecord &Cont) {
- IO.mapRequired("ContinuationIndex", Cont.ContinuationIndex);
-}
-
-void ScalarTraits<codeview::TypeIndex>::output(const codeview::TypeIndex &S,
- void *, llvm::raw_ostream &OS) {
- OS << S.getIndex();
-}
-StringRef ScalarTraits<codeview::TypeIndex>::input(StringRef Scalar, void *Ctx,
- codeview::TypeIndex &S) {
- uint32_t I;
- StringRef Result = ScalarTraits<uint32_t>::input(Scalar, Ctx, I);
- if (!Result.empty())
- return Result;
- S = TypeIndex(I);
- return "";
-}
-bool ScalarTraits<codeview::TypeIndex>::mustQuote(StringRef Scalar) {
- return false;
-}
-
-void ScalarEnumerationTraits<TypeLeafKind>::enumeration(IO &io,
- TypeLeafKind &Value) {
- auto TypeLeafNames = getTypeLeafNames();
- for (const auto &E : TypeLeafNames)
- io.enumCase(Value, E.Name.str().c_str(), E.Value);
-}
-}
-}
-
-Error llvm::codeview::yaml::YamlTypeDumperCallbacks::visitTypeBegin(
- CVType &CVR) {
- YamlIO.mapRequired("Kind", CVR.Type);
- return Error::success();
-}
-
-Error llvm::codeview::yaml::YamlTypeDumperCallbacks::visitMemberBegin(
- CVMemberRecord &Record) {
- YamlIO.mapRequired("Kind", Record.Kind);
- return Error::success();
-}
-
-void llvm::codeview::yaml::YamlTypeDumperCallbacks::visitKnownRecordImpl(
- const char *Name, CVType &CVR, FieldListRecord &FieldList) {
- std::vector<llvm::pdb::yaml::PdbTpiFieldListRecord> FieldListRecords;
- if (YamlIO.outputting()) {
- // If we are outputting, then `FieldList.Data` contains a huge chunk of data
- // representing the serialized list of members. We need to split it up into
- // individual CVType records where each record represents an individual
- // member. This way, we can simply map the entire thing as a Yaml sequence,
- // which will recurse back to the standard handler for top-level fields
- // (top-level and member fields all have the exact same Yaml syntax so use
- // the same parser).
- FieldListRecordSplitter Splitter(FieldListRecords);
- CVTypeVisitor V(Splitter);
- consumeError(V.visitFieldListMemberStream(FieldList.Data));
- YamlIO.mapRequired("FieldList", FieldListRecords, Context);
- } else {
- // If we are not outputting, then the array contains no data starting out,
- // and is instead populated from the sequence represented by the yaml --
- // again, using the same logic that we use for top-level records.
- assert(Context.ActiveSerializer && "There is no active serializer!");
- codeview::TypeVisitorCallbackPipeline Pipeline;
- pdb::TpiHashUpdater Hasher;
-
- // For Yaml to PDB, dump it (to fill out the record fields from the Yaml)
- // then serialize those fields to bytes, then update their hashes.
- Pipeline.addCallbackToPipeline(Context.Dumper);
- Pipeline.addCallbackToPipeline(*Context.ActiveSerializer);
- Pipeline.addCallbackToPipeline(Hasher);
-
- codeview::CVTypeVisitor Visitor(Pipeline);
- YamlIO.mapRequired("FieldList", FieldListRecords, Visitor);
- }
-}
-
-namespace llvm {
-namespace yaml {
-template <>
-struct MappingContextTraits<pdb::yaml::PdbTpiFieldListRecord,
- pdb::yaml::SerializationContext> {
- static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
- pdb::yaml::SerializationContext &Context) {
- assert(IO.outputting());
- codeview::TypeVisitorCallbackPipeline Pipeline;
-
- msf::ByteStream Data(Obj.Record.Data);
- msf::StreamReader FieldReader(Data);
- codeview::FieldListDeserializer Deserializer(FieldReader);
-
- // For PDB to Yaml, deserialize into a high level record type, then dump
- // it.
- Pipeline.addCallbackToPipeline(Deserializer);
- Pipeline.addCallbackToPipeline(Context.Dumper);
-
- codeview::CVTypeVisitor Visitor(Pipeline);
- consumeError(Visitor.visitMemberRecord(Obj.Record));
- }
-};
-
-template <>
-struct MappingContextTraits<pdb::yaml::PdbTpiFieldListRecord,
- codeview::CVTypeVisitor> {
- static void mapping(IO &IO, pdb::yaml::PdbTpiFieldListRecord &Obj,
- codeview::CVTypeVisitor &Visitor) {
- consumeError(Visitor.visitMemberRecord(Obj.Record));
- }
-};
-}
-}
diff --git a/contrib/llvm/tools/llvm-pdbdump/YamlTypeDumper.h b/contrib/llvm/tools/llvm-pdbdump/YamlTypeDumper.h
deleted file mode 100644
index 3f15ba0..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/YamlTypeDumper.h
+++ /dev/null
@@ -1,116 +0,0 @@
-//===- YamlTypeDumper.h --------------------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMPDBDUMP_YAMLTYPEDUMPER_H
-#define LLVM_TOOLS_LLVMPDBDUMP_YAMLTYPEDUMPER_H
-
-#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
-#include "llvm/Support/YAMLTraits.h"
-
-namespace llvm {
-namespace pdb {
-namespace yaml {
-struct SerializationContext;
-}
-}
-namespace codeview {
-namespace yaml {
-class YamlTypeDumperCallbacks : public TypeVisitorCallbacks {
-public:
- YamlTypeDumperCallbacks(llvm::yaml::IO &IO,
- llvm::pdb::yaml::SerializationContext &Context)
- : YamlIO(IO), Context(Context) {}
-
- virtual Error visitTypeBegin(CVType &Record) override;
- virtual Error visitMemberBegin(CVMemberRecord &Record) override;
-
-#define TYPE_RECORD(EnumName, EnumVal, Name) \
- Error visitKnownRecord(CVRecord<TypeLeafKind> &CVR, Name##Record &Record) \
- override { \
- visitKnownRecordImpl(#Name, CVR, Record); \
- return Error::success(); \
- }
-#define MEMBER_RECORD(EnumName, EnumVal, Name) \
- Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
- visitKnownMemberImpl(#Name, Record); \
- return Error::success(); \
- }
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
-
-private:
- template <typename T> void visitKnownMemberImpl(const char *Name, T &Record) {
- YamlIO.mapRequired(Name, Record);
- }
-
- template <typename T>
- void visitKnownRecordImpl(const char *Name, CVType &Type, T &Record) {
- YamlIO.mapRequired(Name, Record);
- }
-
- void visitKnownRecordImpl(const char *Name, CVType &CVR,
- FieldListRecord &FieldList);
-
- llvm::yaml::IO &YamlIO;
- llvm::pdb::yaml::SerializationContext &Context;
-};
-}
-}
-namespace pdb {
-namespace yaml {
-struct SerializationContext;
-}
-}
-}
-
-namespace llvm {
-namespace yaml {
-
-template <> struct ScalarTraits<APSInt> {
- static void output(const APSInt &S, void *, llvm::raw_ostream &OS);
- static StringRef input(StringRef Scalar, void *Ctx, APSInt &S);
- static bool mustQuote(StringRef Scalar);
-};
-
-template <> struct ScalarTraits<codeview::TypeIndex> {
- static void output(const codeview::TypeIndex &S, void *,
- llvm::raw_ostream &OS);
- static StringRef input(StringRef Scalar, void *Ctx, codeview::TypeIndex &S);
- static bool mustQuote(StringRef Scalar);
-};
-
-template <> struct MappingTraits<codeview::MemberPointerInfo> {
- static void mapping(IO &IO, codeview::MemberPointerInfo &Obj);
-};
-
-template <>
-struct MappingContextTraits<codeview::CVType, pdb::yaml::SerializationContext> {
- static void mapping(IO &IO, codeview::CVType &Obj,
- pdb::yaml::SerializationContext &Context);
-};
-
-template <> struct ScalarEnumerationTraits<codeview::TypeLeafKind> {
- static void enumeration(IO &io, codeview::TypeLeafKind &Value);
-};
-
-#define TYPE_RECORD(EnumName, EnumVal, Name) \
- template <> struct MappingTraits<codeview::Name##Record> { \
- static void mapping(IO &IO, codeview::Name##Record &Obj); \
- };
-#define MEMBER_RECORD(EnumName, EnumVal, Name) \
- TYPE_RECORD(EnumName, EnumVal, Name)
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
-}
-}
-
-#endif
diff --git a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
deleted file mode 100644
index d3495e5..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
+++ /dev/null
@@ -1,623 +0,0 @@
-//===- llvm-pdbdump.cpp - Dump debug info from a PDB file -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Dumps debug information present in PDB files. This utility makes use of
-// the Microsoft Windows SDK, so will not compile or run on non-Windows
-// platforms.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm-pdbdump.h"
-#include "LLVMOutputStyle.h"
-#include "LinePrinter.h"
-#include "OutputStyle.h"
-#include "PrettyCompilandDumper.h"
-#include "PrettyExternalSymbolDumper.h"
-#include "PrettyFunctionDumper.h"
-#include "PrettyTypeDumper.h"
-#include "PrettyVariableDumper.h"
-#include "YAMLOutputStyle.h"
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/config.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
-#include "llvm/DebugInfo/MSF/MSFBuilder.h"
-#include "llvm/DebugInfo/PDB/GenericError.h"
-#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
-#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
-#include "llvm/DebugInfo/PDB/IPDBSession.h"
-#include "llvm/DebugInfo/PDB/PDB.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
-#include "llvm/DebugInfo/PDB/Raw/RawError.h"
-#include "llvm/DebugInfo/PDB/Raw/RawSession.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
-#include "llvm/Support/COM.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/Regex.h"
-#include "llvm/Support/ScopedPrinter.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-using namespace llvm::msf;
-using namespace llvm::pdb;
-
-namespace opts {
-
-cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file");
-cl::SubCommand
- PrettySubcommand("pretty",
- "Dump semantic information about types and symbols");
-cl::SubCommand
- YamlToPdbSubcommand("yaml2pdb",
- "Generate a PDB file from a YAML description");
-cl::SubCommand
- PdbToYamlSubcommand("pdb2yaml",
- "Generate a detailed YAML description of a PDB File");
-
-cl::OptionCategory TypeCategory("Symbol Type Options");
-cl::OptionCategory FilterCategory("Filtering Options");
-cl::OptionCategory OtherOptions("Other Options");
-
-namespace pretty {
-cl::list<std::string> InputFilenames(cl::Positional,
- cl::desc("<input PDB files>"),
- cl::OneOrMore, cl::sub(PrettySubcommand));
-
-cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
- cl::cat(TypeCategory), cl::sub(PrettySubcommand));
-cl::opt<bool> Symbols("symbols", cl::desc("Display symbols for each compiland"),
- cl::cat(TypeCategory), cl::sub(PrettySubcommand));
-cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
- cl::cat(TypeCategory), cl::sub(PrettySubcommand));
-cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
- cl::cat(TypeCategory), cl::sub(PrettySubcommand));
-cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory),
- cl::sub(PrettySubcommand));
-cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory),
- cl::sub(PrettySubcommand));
-cl::opt<bool>
- All("all", cl::desc("Implies all other options in 'Symbol Types' category"),
- cl::cat(TypeCategory), cl::sub(PrettySubcommand));
-
-cl::opt<uint64_t> LoadAddress(
- "load-address",
- cl::desc("Assume the module is loaded at the specified address"),
- cl::cat(OtherOptions), cl::sub(PrettySubcommand));
-cl::list<std::string> ExcludeTypes(
- "exclude-types", cl::desc("Exclude types by regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-cl::list<std::string> ExcludeSymbols(
- "exclude-symbols", cl::desc("Exclude symbols by regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-cl::list<std::string> ExcludeCompilands(
- "exclude-compilands", cl::desc("Exclude compilands by regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-
-cl::list<std::string> IncludeTypes(
- "include-types",
- cl::desc("Include only types which match a regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-cl::list<std::string> IncludeSymbols(
- "include-symbols",
- cl::desc("Include only symbols which match a regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-cl::list<std::string> IncludeCompilands(
- "include-compilands",
- cl::desc("Include only compilands those which match a regular expression"),
- cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-
-cl::opt<bool> ExcludeCompilerGenerated(
- "no-compiler-generated",
- cl::desc("Don't show compiler generated types and symbols"),
- cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-cl::opt<bool>
- ExcludeSystemLibraries("no-system-libs",
- cl::desc("Don't show symbols from system libraries"),
- cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-cl::opt<bool> NoClassDefs("no-class-definitions",
- cl::desc("Don't display full class definitions"),
- cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-cl::opt<bool> NoEnumDefs("no-enum-definitions",
- cl::desc("Don't display full enum definitions"),
- cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-}
-
-namespace raw {
-
-cl::OptionCategory MsfOptions("MSF Container Options");
-cl::OptionCategory TypeOptions("Type Record Options");
-cl::OptionCategory FileOptions("Module & File Options");
-cl::OptionCategory SymbolOptions("Symbol Options");
-cl::OptionCategory MiscOptions("Miscellaneous Options");
-
-// MSF OPTIONS
-cl::opt<bool> DumpHeaders("headers", cl::desc("dump PDB headers"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpStreamBlocks("stream-blocks",
- cl::desc("dump PDB stream blocks"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpStreamSummary("stream-summary",
- cl::desc("dump summary of the PDB streams"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpPageStats(
- "page-stats",
- cl::desc("dump allocation stats of the pages in the MSF file"),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-cl::opt<std::string>
- DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
- cl::desc("Dump binary data from specified range."),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-llvm::Optional<BlockRange> DumpBlockRange;
-
-cl::list<uint32_t>
- DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
- cl::desc("Dump binary data from specified streams."),
- cl::cat(MsfOptions), cl::sub(RawSubcommand));
-
-// TYPE OPTIONS
-cl::opt<bool>
- DumpTpiRecords("tpi-records",
- cl::desc("dump CodeView type records from TPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpTpiRecordBytes(
- "tpi-record-bytes",
- cl::desc("dump CodeView type record raw bytes from TPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpTpiHash("tpi-hash", cl::desc("dump CodeView TPI hash stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
-cl::opt<bool>
- DumpIpiRecords("ipi-records",
- cl::desc("dump CodeView type records from IPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpIpiRecordBytes(
- "ipi-record-bytes",
- cl::desc("dump CodeView type record raw bytes from IPI stream"),
- cl::cat(TypeOptions), cl::sub(RawSubcommand));
-
-// MODULE & FILE OPTIONS
-cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
- cl::cat(FileOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
- cl::cat(FileOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpLineInfo("line-info",
- cl::desc("dump file and line information"),
- cl::cat(FileOptions), cl::sub(RawSubcommand));
-
-// SYMBOL OPTIONS
-cl::opt<bool> DumpGlobals("globals", cl::desc("dump globals stream data"),
- cl::cat(SymbolOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
- cl::cat(SymbolOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
- cl::cat(SymbolOptions), cl::sub(RawSubcommand));
-cl::opt<bool>
- DumpSymRecordBytes("sym-record-bytes",
- cl::desc("dump CodeView symbol record raw bytes"),
- cl::cat(SymbolOptions), cl::sub(RawSubcommand));
-
-// MISCELLANEOUS OPTIONS
-cl::opt<bool> DumpSectionContribs("section-contribs",
- cl::desc("dump section contributions"),
- cl::cat(MiscOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
- cl::cat(MiscOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpSectionHeaders("section-headers",
- cl::desc("dump section headers"),
- cl::cat(MiscOptions), cl::sub(RawSubcommand));
-cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions),
- cl::sub(RawSubcommand));
-
-cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
- cl::cat(MiscOptions), cl::sub(RawSubcommand));
-
-cl::list<std::string> InputFilenames(cl::Positional,
- cl::desc("<input PDB files>"),
- cl::OneOrMore, cl::sub(RawSubcommand));
-}
-
-namespace yaml2pdb {
-cl::opt<std::string>
- YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
- cl::sub(YamlToPdbSubcommand));
-
-cl::list<std::string> InputFilename(cl::Positional,
- cl::desc("<input YAML file>"), cl::Required,
- cl::sub(YamlToPdbSubcommand));
-}
-
-namespace pdb2yaml {
-cl::opt<bool>
- NoFileHeaders("no-file-headers",
- cl::desc("Do not dump MSF file headers (you will not be able "
- "to generate a fresh PDB from the resulting YAML)"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-
-cl::opt<bool> StreamMetadata(
- "stream-metadata",
- cl::desc("Dump the number of streams and each stream's size"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-cl::opt<bool> StreamDirectory(
- "stream-directory",
- cl::desc("Dump each stream's block map (implies -stream-metadata)"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-cl::opt<bool> PdbStream("pdb-stream",
- cl::desc("Dump the PDB Stream (Stream 1)"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-cl::opt<bool> DbiStream("dbi-stream",
- cl::desc("Dump the DBI Stream (Stream 2)"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-cl::opt<bool>
- DbiModuleInfo("dbi-module-info",
- cl::desc("Dump DBI Module Information (implies -dbi-stream)"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-
-cl::opt<bool> DbiModuleSyms(
- "dbi-module-syms",
- cl::desc("Dump DBI Module Information (implies -dbi-module-info)"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-
-cl::opt<bool> DbiModuleSourceFileInfo(
- "dbi-module-source-info",
- cl::desc(
- "Dump DBI Module Source File Information (implies -dbi-module-info"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-
-cl::opt<bool> TpiStream("tpi-stream",
- cl::desc("Dump the TPI Stream (Stream 3)"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-
-cl::opt<bool> IpiStream("ipi-stream",
- cl::desc("Dump the IPI Stream (Stream 5)"),
- cl::sub(PdbToYamlSubcommand), cl::init(false));
-
-cl::list<std::string> InputFilename(cl::Positional,
- cl::desc("<input PDB file>"), cl::Required,
- cl::sub(PdbToYamlSubcommand));
-}
-}
-
-static ExitOnError ExitOnErr;
-
-static void yamlToPdb(StringRef Path) {
- BumpPtrAllocator Allocator;
- ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
- MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
- /*RequiresNullTerminator=*/false);
-
- if (ErrorOrBuffer.getError()) {
- ExitOnErr(make_error<GenericError>(generic_error_code::invalid_path, Path));
- }
-
- std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get();
-
- llvm::yaml::Input In(Buffer->getBuffer());
- pdb::yaml::PdbObject YamlObj(Allocator);
- In >> YamlObj;
- if (!YamlObj.Headers.hasValue())
- ExitOnErr(make_error<GenericError>(generic_error_code::unspecified,
- "Yaml does not contain MSF headers"));
-
- PDBFileBuilder Builder(Allocator);
-
- ExitOnErr(Builder.initialize(YamlObj.Headers->SuperBlock.BlockSize));
- // Add each of the reserved streams. We ignore stream metadata in the
- // yaml, because we will reconstruct our own view of the streams. For
- // example, the YAML may say that there were 20 streams in the original
- // PDB, but maybe we only dump a subset of those 20 streams, so we will
- // have fewer, and the ones we do have may end up with different indices
- // than the ones in the original PDB. So we just start with a clean slate.
- for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
- ExitOnErr(Builder.getMsfBuilder().addStream(0));
-
- if (YamlObj.PdbStream.hasValue()) {
- auto &InfoBuilder = Builder.getInfoBuilder();
- InfoBuilder.setAge(YamlObj.PdbStream->Age);
- InfoBuilder.setGuid(YamlObj.PdbStream->Guid);
- InfoBuilder.setSignature(YamlObj.PdbStream->Signature);
- InfoBuilder.setVersion(YamlObj.PdbStream->Version);
- for (auto &NM : YamlObj.PdbStream->NamedStreams)
- InfoBuilder.getNamedStreamsBuilder().addMapping(NM.StreamName,
- NM.StreamNumber);
- }
-
- if (YamlObj.DbiStream.hasValue()) {
- auto &DbiBuilder = Builder.getDbiBuilder();
- DbiBuilder.setAge(YamlObj.DbiStream->Age);
- DbiBuilder.setBuildNumber(YamlObj.DbiStream->BuildNumber);
- DbiBuilder.setFlags(YamlObj.DbiStream->Flags);
- DbiBuilder.setMachineType(YamlObj.DbiStream->MachineType);
- DbiBuilder.setPdbDllRbld(YamlObj.DbiStream->PdbDllRbld);
- DbiBuilder.setPdbDllVersion(YamlObj.DbiStream->PdbDllVersion);
- DbiBuilder.setVersionHeader(YamlObj.DbiStream->VerHeader);
- for (const auto &MI : YamlObj.DbiStream->ModInfos) {
- ExitOnErr(DbiBuilder.addModuleInfo(MI.Obj, MI.Mod));
- for (auto S : MI.SourceFiles)
- ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
- }
- }
-
- if (YamlObj.TpiStream.hasValue()) {
- auto &TpiBuilder = Builder.getTpiBuilder();
- TpiBuilder.setVersionHeader(YamlObj.TpiStream->Version);
- for (const auto &R : YamlObj.TpiStream->Records)
- TpiBuilder.addTypeRecord(R.Record);
- }
-
- if (YamlObj.IpiStream.hasValue()) {
- auto &IpiBuilder = Builder.getIpiBuilder();
- IpiBuilder.setVersionHeader(YamlObj.IpiStream->Version);
- for (const auto &R : YamlObj.IpiStream->Records)
- IpiBuilder.addTypeRecord(R.Record);
- }
-
- ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile));
-}
-
-static void pdb2Yaml(StringRef Path) {
- std::unique_ptr<IPDBSession> Session;
- ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session));
-
- RawSession *RS = static_cast<RawSession *>(Session.get());
- PDBFile &File = RS->getPDBFile();
- auto O = llvm::make_unique<YAMLOutputStyle>(File);
- O = llvm::make_unique<YAMLOutputStyle>(File);
-
- ExitOnErr(O->dump());
-}
-
-static void dumpRaw(StringRef Path) {
- std::unique_ptr<IPDBSession> Session;
- ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session));
-
- RawSession *RS = static_cast<RawSession *>(Session.get());
- PDBFile &File = RS->getPDBFile();
- auto O = llvm::make_unique<LLVMOutputStyle>(File);
-
- ExitOnErr(O->dump());
-}
-
-static void dumpPretty(StringRef Path) {
- std::unique_ptr<IPDBSession> Session;
-
- ExitOnErr(loadDataForPDB(PDB_ReaderType::DIA, Path, Session));
-
- if (opts::pretty::LoadAddress)
- Session->setLoadAddress(opts::pretty::LoadAddress);
-
- LinePrinter Printer(2, outs());
-
- auto GlobalScope(Session->getGlobalScope());
- std::string FileName(GlobalScope->getSymbolsFileName());
-
- WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
- WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
- Printer.Indent();
- uint64_t FileSize = 0;
-
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
- if (!sys::fs::file_size(FileName, FileSize)) {
- Printer << ": " << FileSize << " bytes";
- } else {
- Printer << ": (Unable to obtain file size)";
- }
-
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid";
- Printer << ": " << GlobalScope->getGuid();
-
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age";
- Printer << ": " << GlobalScope->getAge();
-
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes";
- Printer << ": ";
- if (GlobalScope->hasCTypes())
- outs() << "HasCTypes ";
- if (GlobalScope->hasPrivateSymbols())
- outs() << "HasPrivateSymbols ";
- Printer.Unindent();
-
- if (opts::pretty::Compilands) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::SectionHeader).get()
- << "---COMPILANDS---";
- Printer.Indent();
- auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
- CompilandDumper Dumper(Printer);
- CompilandDumpFlags options = CompilandDumper::Flags::None;
- if (opts::pretty::Lines)
- options = options | CompilandDumper::Flags::Lines;
- while (auto Compiland = Compilands->getNext())
- Dumper.start(*Compiland, options);
- Printer.Unindent();
- }
-
- if (opts::pretty::Types) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
- Printer.Indent();
- TypeDumper Dumper(Printer);
- Dumper.start(*GlobalScope);
- Printer.Unindent();
- }
-
- if (opts::pretty::Symbols) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
- Printer.Indent();
- auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
- CompilandDumper Dumper(Printer);
- while (auto Compiland = Compilands->getNext())
- Dumper.start(*Compiland, true);
- Printer.Unindent();
- }
-
- if (opts::pretty::Globals) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
- Printer.Indent();
- {
- FunctionDumper Dumper(Printer);
- auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>();
- while (auto Function = Functions->getNext()) {
- Printer.NewLine();
- Dumper.start(*Function, FunctionDumper::PointerType::None);
- }
- }
- {
- auto Vars = GlobalScope->findAllChildren<PDBSymbolData>();
- VariableDumper Dumper(Printer);
- while (auto Var = Vars->getNext())
- Dumper.start(*Var);
- }
- {
- auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>();
- CompilandDumper Dumper(Printer);
- while (auto Thunk = Thunks->getNext())
- Dumper.dump(*Thunk);
- }
- Printer.Unindent();
- }
- if (opts::pretty::Externals) {
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---";
- Printer.Indent();
- ExternalSymbolDumper Dumper(Printer);
- Dumper.start(*GlobalScope);
- }
- if (opts::pretty::Lines) {
- Printer.NewLine();
- }
- outs().flush();
-}
-
-int main(int argc_, const char *argv_[]) {
- // Print a stack trace if we signal out.
- sys::PrintStackTraceOnErrorSignal(argv_[0]);
- PrettyStackTraceProgram X(argc_, argv_);
-
- ExitOnErr.setBanner("llvm-pdbdump: ");
-
- SmallVector<const char *, 256> argv;
- SpecificBumpPtrAllocator<char> ArgAllocator;
- ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector(
- argv, makeArrayRef(argv_, argc_), ArgAllocator)));
-
- llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
-
- cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
- if (!opts::raw::DumpBlockRangeOpt.empty()) {
- llvm::Regex R("^([0-9]+)(-([0-9]+))?$");
- llvm::SmallVector<llvm::StringRef, 2> Matches;
- if (!R.match(opts::raw::DumpBlockRangeOpt, &Matches)) {
- errs() << "Argument '" << opts::raw::DumpBlockRangeOpt
- << "' invalid format.\n";
- errs().flush();
- exit(1);
- }
- opts::raw::DumpBlockRange.emplace();
- Matches[1].getAsInteger(10, opts::raw::DumpBlockRange->Min);
- if (!Matches[3].empty()) {
- opts::raw::DumpBlockRange->Max.emplace();
- Matches[3].getAsInteger(10, *opts::raw::DumpBlockRange->Max);
- }
- }
-
- if (opts::RawSubcommand && opts::raw::RawAll) {
- opts::raw::DumpHeaders = true;
- opts::raw::DumpModules = true;
- opts::raw::DumpModuleFiles = true;
- opts::raw::DumpModuleSyms = true;
- opts::raw::DumpGlobals = true;
- opts::raw::DumpPublics = true;
- opts::raw::DumpSectionHeaders = true;
- opts::raw::DumpStreamSummary = true;
- opts::raw::DumpPageStats = true;
- opts::raw::DumpStreamBlocks = true;
- opts::raw::DumpTpiRecords = true;
- opts::raw::DumpTpiHash = true;
- opts::raw::DumpIpiRecords = true;
- opts::raw::DumpSectionMap = true;
- opts::raw::DumpSectionContribs = true;
- opts::raw::DumpLineInfo = true;
- opts::raw::DumpFpo = true;
- }
-
- llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
-
- if (opts::PdbToYamlSubcommand) {
- pdb2Yaml(opts::pdb2yaml::InputFilename.front());
- } else if (opts::YamlToPdbSubcommand) {
- yamlToPdb(opts::yaml2pdb::InputFilename.front());
- } else if (opts::PrettySubcommand) {
- if (opts::pretty::Lines)
- opts::pretty::Compilands = true;
-
- if (opts::pretty::All) {
- opts::pretty::Compilands = true;
- opts::pretty::Symbols = true;
- opts::pretty::Globals = true;
- opts::pretty::Types = true;
- opts::pretty::Externals = true;
- opts::pretty::Lines = true;
- }
-
- // When adding filters for excluded compilands and types, we need to
- // remember that these are regexes. So special characters such as * and \
- // need to be escaped in the regex. In the case of a literal \, this means
- // it needs to be escaped again in the C++. So matching a single \ in the
- // input requires 4 \es in the C++.
- if (opts::pretty::ExcludeCompilerGenerated) {
- opts::pretty::ExcludeTypes.push_back("__vc_attributes");
- opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*");
- }
- if (opts::pretty::ExcludeSystemLibraries) {
- opts::pretty::ExcludeCompilands.push_back(
- "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld");
- opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt");
- opts::pretty::ExcludeCompilands.push_back(
- "d:\\\\th.obj.x86fre\\\\minkernel");
- }
- std::for_each(opts::pretty::InputFilenames.begin(),
- opts::pretty::InputFilenames.end(), dumpPretty);
- } else if (opts::RawSubcommand) {
- std::for_each(opts::raw::InputFilenames.begin(),
- opts::raw::InputFilenames.end(), dumpRaw);
- }
-
- outs().flush();
- return 0;
-}
diff --git a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h b/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
deleted file mode 100644
index 42d847a..0000000
--- a/contrib/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
+++ /dev/null
@@ -1,83 +0,0 @@
-//===- llvm-pdbdump.h ----------------------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
-#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
-
-#include "llvm/ADT/Optional.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace opts {
-
-namespace pretty {
-extern llvm::cl::opt<bool> Compilands;
-extern llvm::cl::opt<bool> Symbols;
-extern llvm::cl::opt<bool> Globals;
-extern llvm::cl::opt<bool> Types;
-extern llvm::cl::opt<bool> All;
-extern llvm::cl::opt<bool> ExcludeCompilerGenerated;
-
-extern llvm::cl::opt<bool> NoClassDefs;
-extern llvm::cl::opt<bool> NoEnumDefs;
-extern llvm::cl::list<std::string> ExcludeTypes;
-extern llvm::cl::list<std::string> ExcludeSymbols;
-extern llvm::cl::list<std::string> ExcludeCompilands;
-extern llvm::cl::list<std::string> IncludeTypes;
-extern llvm::cl::list<std::string> IncludeSymbols;
-extern llvm::cl::list<std::string> IncludeCompilands;
-}
-
-namespace raw {
-struct BlockRange {
- uint32_t Min;
- llvm::Optional<uint32_t> Max;
-};
-
-extern llvm::Optional<BlockRange> DumpBlockRange;
-extern llvm::cl::list<uint32_t> DumpStreamData;
-
-extern llvm::cl::opt<bool> DumpGlobals;
-extern llvm::cl::opt<bool> DumpHeaders;
-extern llvm::cl::opt<bool> DumpStreamBlocks;
-extern llvm::cl::opt<bool> DumpStreamSummary;
-extern llvm::cl::opt<bool> DumpPageStats;
-extern llvm::cl::opt<bool> DumpTpiHash;
-extern llvm::cl::opt<bool> DumpTpiRecordBytes;
-extern llvm::cl::opt<bool> DumpTpiRecords;
-extern llvm::cl::opt<bool> DumpIpiRecords;
-extern llvm::cl::opt<bool> DumpIpiRecordBytes;
-extern llvm::cl::opt<bool> DumpModules;
-extern llvm::cl::opt<bool> DumpModuleFiles;
-extern llvm::cl::opt<bool> DumpModuleSyms;
-extern llvm::cl::opt<bool> DumpPublics;
-extern llvm::cl::opt<bool> DumpSectionContribs;
-extern llvm::cl::opt<bool> DumpLineInfo;
-extern llvm::cl::opt<bool> DumpSectionMap;
-extern llvm::cl::opt<bool> DumpSymRecordBytes;
-extern llvm::cl::opt<bool> DumpSectionHeaders;
-extern llvm::cl::opt<bool> DumpFpo;
-}
-
-namespace pdb2yaml {
-extern llvm::cl::opt<bool> NoFileHeaders;
-extern llvm::cl::opt<bool> StreamMetadata;
-extern llvm::cl::opt<bool> StreamDirectory;
-extern llvm::cl::opt<bool> PdbStream;
-extern llvm::cl::opt<bool> DbiStream;
-extern llvm::cl::opt<bool> DbiModuleInfo;
-extern llvm::cl::opt<bool> DbiModuleSyms;
-extern llvm::cl::opt<bool> DbiModuleSourceFileInfo;
-extern llvm::cl::opt<bool> TpiStream;
-extern llvm::cl::opt<bool> IpiStream;
-extern llvm::cl::list<std::string> InputFilename;
-}
-}
-
-#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp b/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp
new file mode 100644
index 0000000..6c603dd
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp
@@ -0,0 +1,148 @@
+//===- Analyze.cpp - PDB analysis functions ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Analyze.h"
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <list>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static StringRef getLeafTypeName(TypeLeafKind LT) {
+ switch (LT) {
+#define TYPE_RECORD(ename, value, name) \
+ case ename: \
+ return #name;
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ default:
+ break;
+ }
+ return "UnknownLeaf";
+}
+
+namespace {
+struct HashLookupVisitor : public TypeVisitorCallbacks {
+ struct Entry {
+ TypeIndex TI;
+ CVType Record;
+ };
+
+ explicit HashLookupVisitor(TpiStream &Tpi) : Tpi(Tpi) {}
+
+ Error visitTypeBegin(CVType &Record) override {
+ uint32_t H = Tpi.getHashValues()[I];
+ Record.Hash = H;
+ TypeIndex TI(I + TypeIndex::FirstNonSimpleIndex);
+ Lookup[H].push_back(Entry{TI, Record});
+ ++I;
+ return Error::success();
+ }
+
+ uint32_t I = 0;
+ DenseMap<uint32_t, std::list<Entry>> Lookup;
+ TpiStream &Tpi;
+};
+}
+
+AnalysisStyle::AnalysisStyle(PDBFile &File) : File(File) {}
+
+Error AnalysisStyle::dump() {
+ auto Tpi = File.getPDBTpiStream();
+ if (!Tpi)
+ return Tpi.takeError();
+
+ HashLookupVisitor Hasher(*Tpi);
+
+ uint32_t RecordCount = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ auto Types = llvm::make_unique<LazyRandomTypeCollection>(
+ Tpi->typeArray(), RecordCount, Offsets);
+
+ if (auto EC = codeview::visitTypeStream(*Types, Hasher))
+ return EC;
+
+ auto &Adjusters = Tpi->getHashAdjusters();
+ DenseSet<uint32_t> AdjusterSet;
+ for (const auto &Adj : Adjusters) {
+ assert(AdjusterSet.find(Adj.second) == AdjusterSet.end());
+ AdjusterSet.insert(Adj.second);
+ }
+
+ uint32_t Count = 0;
+ outs() << "Searching for hash collisions\n";
+ for (const auto &H : Hasher.Lookup) {
+ if (H.second.size() <= 1)
+ continue;
+ ++Count;
+ outs() << formatv("Hash: {0}, Count: {1} records\n", H.first,
+ H.second.size());
+ for (const auto &R : H.second) {
+ auto Iter = AdjusterSet.find(R.TI.getIndex());
+ StringRef Prefix;
+ if (Iter != AdjusterSet.end()) {
+ Prefix = "[HEAD]";
+ AdjusterSet.erase(Iter);
+ }
+ StringRef LeafName = getLeafTypeName(R.Record.Type);
+ uint32_t TI = R.TI.getIndex();
+ StringRef TypeName = Types->getTypeName(R.TI);
+ outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI,
+ TypeName);
+ }
+ }
+
+ outs() << "\n";
+ outs() << "Dumping hash adjustment chains\n";
+ for (const auto &A : Tpi->getHashAdjusters()) {
+ TypeIndex TI(A.second);
+ StringRef TypeName = Types->getTypeName(TI);
+ const CVType &HeadRecord = Types->getType(TI);
+ assert(HeadRecord.Hash.hasValue());
+
+ auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash);
+ if (CollisionsIter == Hasher.Lookup.end())
+ continue;
+
+ const auto &Collisions = CollisionsIter->second;
+ outs() << TypeName << "\n";
+ outs() << formatv(" [HEAD] {0:x} {1} {2}\n", A.second,
+ getLeafTypeName(HeadRecord.Type), TypeName);
+ for (const auto &Chain : Collisions) {
+ if (Chain.TI == TI)
+ continue;
+ const CVType &TailRecord = Types->getType(Chain.TI);
+ outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(),
+ getLeafTypeName(TailRecord.Type),
+ Types->getTypeName(Chain.TI));
+ }
+ }
+ outs() << formatv("There are {0} orphaned hash adjusters\n",
+ AdjusterSet.size());
+ for (const auto &Adj : AdjusterSet) {
+ outs() << formatv(" {0}\n", Adj);
+ }
+
+ uint32_t DistinctHashValues = Hasher.Lookup.size();
+ outs() << formatv("{0}/{1} hash collisions", Count, DistinctHashValues);
+ return Error::success();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/Analyze.h b/contrib/llvm/tools/llvm-pdbutil/Analyze.h
new file mode 100644
index 0000000..7230ae4
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/Analyze.h
@@ -0,0 +1,30 @@
+//===- Analyze.h - PDB analysis functions -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_ANALYSIS_H
+#define LLVM_TOOLS_LLVMPDBDUMP_ANALYSIS_H
+
+#include "OutputStyle.h"
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+class AnalysisStyle : public OutputStyle {
+public:
+ explicit AnalysisStyle(PDBFile &File);
+
+ Error dump() override;
+
+private:
+ PDBFile &File;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
new file mode 100644
index 0000000..9e5a28c
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
@@ -0,0 +1,501 @@
+//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BytesOutputStyle.h"
+
+#include "FormatUtil.h"
+#include "StreamUtil.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace {
+struct StreamSpec {
+ uint32_t SI = 0;
+ uint32_t Begin = 0;
+ uint32_t Size = 0;
+};
+} // namespace
+
+static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
+ StreamSpec Result;
+ if (Str.consumeInteger(0, Result.SI))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ if (Str.consume_front(":")) {
+ if (Str.consumeInteger(0, Result.Begin))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ }
+ if (Str.consume_front("@")) {
+ if (Str.consumeInteger(0, Result.Size))
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ }
+
+ if (!Str.empty())
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Invalid Stream Specification");
+ return Result;
+}
+
+static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
+ SmallVector<StreamSpec, 2> Result;
+
+ for (auto &Str : opts::bytes::DumpStreamData) {
+ auto ESS = parseStreamSpec(Str);
+ if (!ESS) {
+ P.formatLine("Error parsing stream spec {0}: {1}", Str,
+ toString(ESS.takeError()));
+ continue;
+ }
+ Result.push_back(*ESS);
+ }
+ return Result;
+}
+
+static void printHeader(LinePrinter &P, const Twine &S) {
+ P.NewLine();
+ P.formatLine("{0,=60}", S);
+ P.formatLine("{0}", fmt_repeat('=', 60));
+}
+
+BytesOutputStyle::BytesOutputStyle(PDBFile &File)
+ : File(File), P(2, false, outs()) {}
+
+Error BytesOutputStyle::dump() {
+
+ if (opts::bytes::DumpBlockRange.hasValue()) {
+ auto &R = *opts::bytes::DumpBlockRange;
+ uint32_t Max = R.Max.getValueOr(R.Min);
+
+ if (Max < R.Min)
+ return make_error<StringError>(
+ "Invalid block range specified. Max < Min",
+ inconvertibleErrorCode());
+ if (Max >= File.getBlockCount())
+ return make_error<StringError>(
+ "Invalid block range specified. Requested block out of bounds",
+ inconvertibleErrorCode());
+
+ dumpBlockRanges(R.Min, Max);
+ P.NewLine();
+ }
+
+ if (opts::bytes::DumpByteRange.hasValue()) {
+ auto &R = *opts::bytes::DumpByteRange;
+ uint32_t Max = R.Max.getValueOr(File.getFileSize());
+
+ if (Max < R.Min)
+ return make_error<StringError>("Invalid byte range specified. Max < Min",
+ inconvertibleErrorCode());
+ if (Max >= File.getFileSize())
+ return make_error<StringError>(
+ "Invalid byte range specified. Requested byte larger than file size",
+ inconvertibleErrorCode());
+
+ dumpByteRanges(R.Min, Max);
+ P.NewLine();
+ }
+
+ if (!opts::bytes::DumpStreamData.empty()) {
+ dumpStreamBytes();
+ P.NewLine();
+ }
+
+ if (opts::bytes::NameMap) {
+ dumpNameMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::SectionContributions) {
+ dumpSectionContributions();
+ P.NewLine();
+ }
+
+ if (opts::bytes::SectionMap) {
+ dumpSectionMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleInfos) {
+ dumpModuleInfos();
+ P.NewLine();
+ }
+
+ if (opts::bytes::FileInfo) {
+ dumpFileInfo();
+ P.NewLine();
+ }
+
+ if (opts::bytes::TypeServerMap) {
+ dumpTypeServerMap();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ECData) {
+ dumpECData();
+ P.NewLine();
+ }
+
+ if (!opts::bytes::TypeIndex.empty()) {
+ dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);
+ P.NewLine();
+ }
+
+ if (!opts::bytes::IdIndex.empty()) {
+ dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleSyms) {
+ dumpModuleSyms();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleC11) {
+ dumpModuleC11();
+ P.NewLine();
+ }
+
+ if (opts::bytes::ModuleC13) {
+ dumpModuleC13();
+ P.NewLine();
+ }
+
+ return Error::success();
+}
+
+void BytesOutputStyle::dumpNameMap() {
+ printHeader(P, "Named Stream Map");
+
+ AutoIndent Indent(P);
+
+ auto &InfoS = Err(File.getPDBInfoStream());
+ BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();
+ auto Layout = File.getStreamLayout(StreamPDB);
+ P.formatMsfStreamData("Named Stream Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
+ printHeader(P, "MSF Blocks");
+
+ AutoIndent Indent(P);
+ for (uint32_t I = Min; I <= Max; ++I) {
+ uint64_t Base = I;
+ Base *= File.getBlockSize();
+
+ auto ExpectedData = File.getBlockData(I, File.getBlockSize());
+ if (!ExpectedData) {
+ P.formatLine("Could not get block {0}. Reason = {1}", I,
+ toString(ExpectedData.takeError()));
+ continue;
+ }
+ std::string Label = formatv("Block {0}", I).str();
+ P.formatBinary(Label, *ExpectedData, Base, 0);
+ }
+}
+
+void BytesOutputStyle::dumpSectionContributions() {
+ printHeader(P, "Section Contributions");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getSectionContributionData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Section Contributions", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpSectionMap() {
+ printHeader(P, "Section Map");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Section Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpModuleInfos() {
+ printHeader(P, "Module Infos");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getModiSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Module Infos", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpFileInfo() {
+ printHeader(P, "File Info");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("File Info", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpTypeServerMap() {
+ printHeader(P, "Type Server Map");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Type Server Map", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpECData() {
+ printHeader(P, "Edit and Continue Data");
+
+ AutoIndent Indent(P);
+
+ auto &DbiS = Err(File.getPDBDbiStream());
+ BinarySubstreamRef NS = DbiS.getECSubstreamData();
+ auto Layout = File.getStreamLayout(StreamDBI);
+ P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
+}
+
+void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
+ ArrayRef<uint32_t> Indices) {
+ assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
+ assert(!Indices.empty());
+
+ bool IsTpi = (StreamIdx == StreamTPI);
+
+ StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";
+ printHeader(P, Label);
+ auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());
+
+ AutoIndent Indent(P);
+
+ auto Substream = Stream.getTypeRecordsSubstream();
+ auto &Types = Err(initializeTypes(StreamIdx));
+ auto Layout = File.getStreamLayout(StreamIdx);
+ for (const auto &Id : Indices) {
+ TypeIndex TI(Id);
+ if (TI.toArrayIndex() >= Types.capacity()) {
+ P.formatLine("Error: TypeIndex {0} does not exist", TI);
+ continue;
+ }
+
+ auto Type = Types.getType(TI);
+ uint32_t Offset = Types.getOffsetOfType(TI);
+ auto OneType = Substream.slice(Offset, Type.length());
+ P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);
+ }
+}
+
+template <typename CallbackT>
+static void iterateOneModule(PDBFile &File, LinePrinter &P,
+ const DbiModuleList &Modules, uint32_t I,
+ uint32_t Digits, uint32_t IndentLevel,
+ CallbackT Callback) {
+ if (I >= Modules.getModuleCount()) {
+ P.formatLine("Mod {0:4} | Invalid module index ",
+ fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)));
+ return;
+ }
+
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | `{1}`: ",
+ fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)),
+ Modi.getModuleName());
+
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ AutoIndent Indent2(P, IndentLevel);
+ if (ModiStream == kInvalidStreamIndex)
+ return;
+
+ auto ModStreamData = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+ ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));
+ if (auto EC = ModStream.reload()) {
+ P.formatLine("Could not parse debug information.");
+ return;
+ }
+ auto Layout = File.getStreamLayout(ModiStream);
+ Callback(I, ModStream, Layout);
+}
+
+template <typename CallbackT>
+static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
+ CallbackT Callback) {
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return;
+ }
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+
+ if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) {
+ iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel,
+ Callback);
+ } else {
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback);
+ }
+ }
+}
+
+void BytesOutputStyle::dumpModuleSyms() {
+ printHeader(P, "Module Symbols");
+
+ AutoIndent Indent(P);
+
+ iterateModules(File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Symbols = Stream.getSymbolsSubstream();
+ P.formatMsfStreamData("Symbols", File, Layout, Symbols);
+ });
+}
+
+void BytesOutputStyle::dumpModuleC11() {
+ printHeader(P, "C11 Debug Chunks");
+
+ AutoIndent Indent(P);
+
+ iterateModules(File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Chunks = Stream.getC11LinesSubstream();
+ P.formatMsfStreamData("C11 Debug Chunks", File, Layout,
+ Chunks);
+ });
+}
+
+static std::string formatChunkKind(DebugSubsectionKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(DebugSubsectionKind, None, "none");
+ RETURN_CASE(DebugSubsectionKind, Symbols, "symbols");
+ RETURN_CASE(DebugSubsectionKind, Lines, "lines");
+ RETURN_CASE(DebugSubsectionKind, StringTable, "strings");
+ RETURN_CASE(DebugSubsectionKind, FileChecksums, "checksums");
+ RETURN_CASE(DebugSubsectionKind, FrameData, "frames");
+ RETURN_CASE(DebugSubsectionKind, InlineeLines, "inlinee lines");
+ RETURN_CASE(DebugSubsectionKind, CrossScopeImports, "xmi");
+ RETURN_CASE(DebugSubsectionKind, CrossScopeExports, "xme");
+ RETURN_CASE(DebugSubsectionKind, ILLines, "il lines");
+ RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap, "func md token map");
+ RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap, "type md token map");
+ RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput,
+ "merged assembly input");
+ RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA, "coff symbol rva");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+void BytesOutputStyle::dumpModuleC13() {
+ printHeader(P, "Debug Chunks");
+
+ AutoIndent Indent(P);
+
+ iterateModules(
+ File, P, 2,
+ [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
+ const MSFStreamLayout &Layout) {
+ auto Chunks = Stream.getC13LinesSubstream();
+ if (opts::bytes::SplitChunks) {
+ for (const auto &SS : Stream.subsections()) {
+ BinarySubstreamRef ThisChunk;
+ std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength());
+ P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout,
+ ThisChunk);
+ }
+ } else {
+ P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks);
+ }
+ });
+}
+
+void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
+ printHeader(P, "MSF Bytes");
+
+ AutoIndent Indent(P);
+
+ BinaryStreamReader Reader(File.getMsfBuffer());
+ ArrayRef<uint8_t> Data;
+ consumeError(Reader.skip(Min));
+ uint32_t Size = Max - Min + 1;
+ auto EC = Reader.readBytes(Data, Size);
+ assert(!EC);
+ consumeError(std::move(EC));
+ P.formatBinary("Bytes", Data, Min);
+}
+
+Expected<codeview::LazyRandomTypeCollection &>
+BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {
+ auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;
+ if (TypeCollection)
+ return *TypeCollection;
+
+ auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
+ : File.getPDBIpiStream();
+ if (!Tpi)
+ return Tpi.takeError();
+
+ auto &Types = Tpi->typeArray();
+ uint32_t Count = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ TypeCollection =
+ llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
+
+ return *TypeCollection;
+}
+
+void BytesOutputStyle::dumpStreamBytes() {
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
+
+ printHeader(P, "Stream Data");
+ ExitOnError Err("Unexpected error reading stream data");
+
+ auto Specs = parseStreamSpecs(P);
+
+ for (const auto &Spec : Specs) {
+ AutoIndent Indent(P);
+ if (Spec.SI >= StreamPurposes.size()) {
+ P.formatLine("Stream {0}: Not present", Spec.SI);
+ continue;
+ }
+ P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI],
+ Spec.Begin, Spec.Size);
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
new file mode 100644
index 0000000..c162163
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
@@ -0,0 +1,67 @@
+//===- BytesOutputStyle.h ------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
+
+#include "LinePrinter.h"
+#include "OutputStyle.h"
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+
+class PDBFile;
+
+class BytesOutputStyle : public OutputStyle {
+public:
+ BytesOutputStyle(PDBFile &File);
+
+ Error dump() override;
+
+private:
+ void dumpNameMap();
+ void dumpBlockRanges(uint32_t Min, uint32_t Max);
+ void dumpByteRanges(uint32_t Min, uint32_t Max);
+ void dumpStreamBytes();
+
+ void dumpSectionContributions();
+ void dumpSectionMap();
+ void dumpModuleInfos();
+ void dumpFileInfo();
+ void dumpTypeServerMap();
+ void dumpECData();
+
+ void dumpModuleSyms();
+ void dumpModuleC11();
+ void dumpModuleC13();
+
+ void dumpTypeIndex(uint32_t StreamIdx, ArrayRef<uint32_t> Indices);
+
+ Expected<codeview::LazyRandomTypeCollection &>
+ initializeTypes(uint32_t StreamIdx);
+
+ std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes;
+
+ PDBFile &File;
+ LinePrinter P;
+ ExitOnError Err;
+ SmallVector<std::string, 8> StreamPurposes;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/Diff.cpp b/contrib/llvm/tools/llvm-pdbutil/Diff.cpp
new file mode 100644
index 0000000..aad4e1b
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/Diff.cpp
@@ -0,0 +1,608 @@
+//===- Diff.cpp - PDB diff utility ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Diff.h"
+
+#include "DiffPrinter.h"
+#include "FormatUtil.h"
+#include "StreamUtil.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/ADT/StringSet.h"
+
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/Formatters.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+// Compare and format two stream numbers. Stream numbers are considered
+// identical if they contain the same value, equivalent if they are both
+// the invalid stream or neither is the invalid stream, and different if
+// one is the invalid stream and another isn't.
+struct StreamNumberProvider {
+ static DiffResult compare(uint16_t L, uint16_t R) {
+ if (L == R)
+ return DiffResult::IDENTICAL;
+ bool LP = L != kInvalidStreamIndex;
+ bool RP = R != kInvalidStreamIndex;
+ if (LP != RP)
+ return DiffResult::DIFFERENT;
+ return DiffResult::EQUIVALENT;
+ }
+
+ static std::string format(uint16_t SN, bool Right) {
+ if (SN == kInvalidStreamIndex)
+ return "(not present)";
+ return formatv("{0}", SN).str();
+ }
+};
+
+// Compares and formats two module indices. Modis are considered identical
+// if they are identical, equivalent if they either both contain a value or
+// both don't contain a value, and different if one contains a value and the
+// other doesn't.
+struct ModiProvider {
+ DiffResult compare(Optional<uint32_t> L, Optional<uint32_t> R) {
+ if (L == R)
+ return DiffResult::IDENTICAL;
+ if (L.hasValue() != R.hasValue())
+ return DiffResult::DIFFERENT;
+ return DiffResult::EQUIVALENT;
+ }
+
+ std::string format(Optional<uint32_t> Modi, bool Right) {
+ if (!Modi.hasValue())
+ return "(not present)";
+ return formatv("{0}", *Modi).str();
+ }
+};
+
+// Compares and formats two paths embedded in the PDB, ignoring the beginning
+// of the path if the user specified it as a "root path" on the command line.
+struct BinaryPathProvider {
+ explicit BinaryPathProvider(uint32_t MaxLen) : MaxLen(MaxLen) {}
+
+ DiffResult compare(StringRef L, StringRef R) {
+ if (L == R)
+ return DiffResult::IDENTICAL;
+
+ SmallString<64> LN = removeRoot(L, false);
+ SmallString<64> RN = removeRoot(R, true);
+
+ return (LN.equals_lower(RN)) ? DiffResult::EQUIVALENT
+ : DiffResult::DIFFERENT;
+ }
+
+ std::string format(StringRef S, bool Right) {
+ if (S.empty())
+ return "(empty)";
+
+ SmallString<64> Native = removeRoot(S, Right);
+ return truncateStringFront(Native.str(), MaxLen);
+ }
+
+ SmallString<64> removeRoot(StringRef Path, bool IsRight) const {
+ SmallString<64> Native(Path);
+ auto &RootOpt = IsRight ? opts::diff::RightRoot : opts::diff::LeftRoot;
+ SmallString<64> Root(static_cast<std::string>(RootOpt));
+ // pdb paths always use windows syntax, convert slashes to backslashes.
+ sys::path::native(Root, sys::path::Style::windows);
+ if (sys::path::has_stem(Root, sys::path::Style::windows))
+ sys::path::append(Root, sys::path::Style::windows,
+ sys::path::get_separator(sys::path::Style::windows));
+
+ sys::path::replace_path_prefix(Native, Root, "", sys::path::Style::windows);
+ return Native;
+ }
+ uint32_t MaxLen;
+};
+
+// Compare and format two stream purposes. For general streams, this just
+// compares the description. For module streams it uses the path comparison
+// algorithm taking into consideration the binary root, described above.
+// Formatting stream purposes just prints the stream purpose, except for
+// module streams and named streams, where it prefixes the name / module
+// with an identifier. Example:
+//
+// Named Stream "\names"
+// Module Stream "foo.obj"
+//
+// If a named stream is too long to fit in a column, it is truncated at the
+// end, and if a module is too long to fit in a column, it is truncated at the
+// beginning. Example:
+//
+// Named Stream "\Really Long Str..."
+// Module Stream "...puts\foo.obj"
+//
+struct StreamPurposeProvider {
+ explicit StreamPurposeProvider(uint32_t MaxLen) : MaxLen(MaxLen) {}
+
+ DiffResult compare(const std::pair<StreamPurpose, std::string> &L,
+ const std::pair<StreamPurpose, std::string> &R) {
+ if (L.first != R.first)
+ return DiffResult::DIFFERENT;
+ if (L.first == StreamPurpose::ModuleStream) {
+ BinaryPathProvider PathProvider(MaxLen);
+ return PathProvider.compare(L.second, R.second);
+ }
+ return (L.second == R.second) ? DiffResult::IDENTICAL
+ : DiffResult::DIFFERENT;
+ }
+
+ std::string format(const std::pair<StreamPurpose, std::string> &P,
+ bool Right) {
+ if (P.first == StreamPurpose::Other)
+ return truncateStringBack(P.second, MaxLen);
+ if (P.first == StreamPurpose::NamedStream)
+ return truncateQuotedNameBack("Named Stream", P.second, MaxLen);
+
+ assert(P.first == StreamPurpose::ModuleStream);
+ uint32_t ExtraChars = strlen("Module \"\"");
+ BinaryPathProvider PathProvider(MaxLen - ExtraChars);
+ std::string Result = PathProvider.format(P.second, Right);
+ return formatv("Module \"{0}\"", Result);
+ }
+
+ uint32_t MaxLen;
+};
+} // namespace
+
+namespace llvm {
+template <> struct format_provider<PdbRaw_FeatureSig> {
+ static void format(const PdbRaw_FeatureSig &Sig, raw_ostream &Stream,
+ StringRef Style) {
+ switch (Sig) {
+ case PdbRaw_FeatureSig::MinimalDebugInfo:
+ Stream << "MinimalDebugInfo";
+ break;
+ case PdbRaw_FeatureSig::NoTypeMerge:
+ Stream << "NoTypeMerge";
+ break;
+ case PdbRaw_FeatureSig::VC110:
+ Stream << "VC110";
+ break;
+ case PdbRaw_FeatureSig::VC140:
+ Stream << "VC140";
+ break;
+ }
+ }
+};
+}
+
+template <typename R> using ValueOfRange = llvm::detail::ValueOfRange<R>;
+
+DiffStyle::DiffStyle(PDBFile &File1, PDBFile &File2)
+ : File1(File1), File2(File2) {}
+
+Error DiffStyle::dump() {
+ if (auto EC = diffSuperBlock())
+ return EC;
+
+ if (auto EC = diffFreePageMap())
+ return EC;
+
+ if (auto EC = diffStreamDirectory())
+ return EC;
+
+ if (auto EC = diffStringTable())
+ return EC;
+
+ if (auto EC = diffInfoStream())
+ return EC;
+
+ if (auto EC = diffDbiStream())
+ return EC;
+
+ if (auto EC = diffSectionContribs())
+ return EC;
+
+ if (auto EC = diffSectionMap())
+ return EC;
+
+ if (auto EC = diffFpoStream())
+ return EC;
+
+ if (auto EC = diffTpiStream(StreamTPI))
+ return EC;
+
+ if (auto EC = diffTpiStream(StreamIPI))
+ return EC;
+
+ if (auto EC = diffPublics())
+ return EC;
+
+ if (auto EC = diffGlobals())
+ return EC;
+
+ return Error::success();
+}
+
+Error DiffStyle::diffSuperBlock() {
+ DiffPrinter D(2, "MSF Super Block", 16, 20, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 18),
+ truncateStringFront(File2.getFilePath(), 18));
+ D.print("Block Size", File1.getBlockSize(), File2.getBlockSize());
+ D.print("Block Count", File1.getBlockCount(), File2.getBlockCount());
+ D.print("Unknown 1", File1.getUnknown1(), File2.getUnknown1());
+ D.print("Directory Size", File1.getNumDirectoryBytes(),
+ File2.getNumDirectoryBytes());
+ return Error::success();
+}
+
+Error DiffStyle::diffStreamDirectory() {
+ DiffPrinter D(2, "Stream Directory", 30, 20, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 18),
+ truncateStringFront(File2.getFilePath(), 18));
+
+ SmallVector<std::pair<StreamPurpose, std::string>, 32> P;
+ SmallVector<std::pair<StreamPurpose, std::string>, 32> Q;
+ discoverStreamPurposes(File1, P);
+ discoverStreamPurposes(File2, Q);
+ D.print("Stream Count", File1.getNumStreams(), File2.getNumStreams());
+ auto PI = to_vector<32>(enumerate(P));
+ auto QI = to_vector<32>(enumerate(Q));
+
+ // Scan all streams in the left hand side, looking for ones that are also
+ // in the right. Each time we find one, remove it. When we're done, Q
+ // should contain all the streams that are in the right but not in the left.
+ StreamPurposeProvider StreamProvider(28);
+ for (const auto &P : PI) {
+ typedef decltype(PI) ContainerType;
+ typedef typename ContainerType::value_type value_type;
+
+ auto Iter = llvm::find_if(QI, [P, &StreamProvider](const value_type &V) {
+ DiffResult Result = StreamProvider.compare(P.value(), V.value());
+ return Result == DiffResult::EQUIVALENT ||
+ Result == DiffResult::IDENTICAL;
+ });
+
+ if (Iter == QI.end()) {
+ D.printExplicit(StreamProvider.format(P.value(), false),
+ DiffResult::DIFFERENT, P.index(), "(not present)");
+ continue;
+ }
+
+ D.print<EquivalentDiffProvider>(StreamProvider.format(P.value(), false),
+ P.index(), Iter->index());
+ QI.erase(Iter);
+ }
+
+ for (const auto &Q : QI) {
+ D.printExplicit(StreamProvider.format(Q.value(), true),
+ DiffResult::DIFFERENT, "(not present)", Q.index());
+ }
+
+ return Error::success();
+}
+
+Error DiffStyle::diffStringTable() {
+ DiffPrinter D(2, "String Table", 30, 20, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 18),
+ truncateStringFront(File2.getFilePath(), 18));
+
+ auto ExpectedST1 = File1.getStringTable();
+ auto ExpectedST2 = File2.getStringTable();
+ bool Has1 = !!ExpectedST1;
+ bool Has2 = !!ExpectedST2;
+ std::string Count1 = Has1 ? llvm::utostr(ExpectedST1->getNameCount())
+ : "(string table not present)";
+ std::string Count2 = Has2 ? llvm::utostr(ExpectedST2->getNameCount())
+ : "(string table not present)";
+ D.print("Number of Strings", Count1, Count2);
+
+ if (!Has1 || !Has2) {
+ consumeError(ExpectedST1.takeError());
+ consumeError(ExpectedST2.takeError());
+ return Error::success();
+ }
+
+ auto &ST1 = *ExpectedST1;
+ auto &ST2 = *ExpectedST2;
+
+ D.print("Hash Version", ST1.getHashVersion(), ST2.getHashVersion());
+ D.print("Byte Size", ST1.getByteSize(), ST2.getByteSize());
+ D.print("Signature", ST1.getSignature(), ST2.getSignature());
+
+ // Both have a valid string table, dive in and compare individual strings.
+
+ auto IdList1 = ST1.name_ids();
+ auto IdList2 = ST2.name_ids();
+ StringSet<> LS;
+ StringSet<> RS;
+ uint32_t Empty1 = 0;
+ uint32_t Empty2 = 0;
+ for (auto ID : IdList1) {
+ auto S = ST1.getStringForID(ID);
+ if (!S)
+ return S.takeError();
+ if (S->empty())
+ ++Empty1;
+ else
+ LS.insert(*S);
+ }
+ for (auto ID : IdList2) {
+ auto S = ST2.getStringForID(ID);
+ if (!S)
+ return S.takeError();
+ if (S->empty())
+ ++Empty2;
+ else
+ RS.insert(*S);
+ }
+ D.print("Empty Strings", Empty1, Empty2);
+
+ for (const auto &S : LS) {
+ auto R = RS.find(S.getKey());
+ std::string Truncated = truncateStringMiddle(S.getKey(), 28);
+ uint32_t I = cantFail(ST1.getIDForString(S.getKey()));
+ if (R == RS.end()) {
+ D.printExplicit(Truncated, DiffResult::DIFFERENT, I, "(not present)");
+ continue;
+ }
+
+ uint32_t J = cantFail(ST2.getIDForString(R->getKey()));
+ D.print<EquivalentDiffProvider>(Truncated, I, J);
+ RS.erase(R);
+ }
+
+ for (const auto &S : RS) {
+ auto L = LS.find(S.getKey());
+ std::string Truncated = truncateStringMiddle(S.getKey(), 28);
+ uint32_t J = cantFail(ST2.getIDForString(S.getKey()));
+ if (L == LS.end()) {
+ D.printExplicit(Truncated, DiffResult::DIFFERENT, "(not present)", J);
+ continue;
+ }
+
+ uint32_t I = cantFail(ST1.getIDForString(L->getKey()));
+ D.print<EquivalentDiffProvider>(Truncated, I, J);
+ }
+ return Error::success();
+}
+
+Error DiffStyle::diffFreePageMap() { return Error::success(); }
+
+Error DiffStyle::diffInfoStream() {
+ DiffPrinter D(2, "PDB Stream", 22, 40, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 38),
+ truncateStringFront(File2.getFilePath(), 38));
+
+ auto ExpectedInfo1 = File1.getPDBInfoStream();
+ auto ExpectedInfo2 = File2.getPDBInfoStream();
+
+ bool Has1 = !!ExpectedInfo1;
+ bool Has2 = !!ExpectedInfo2;
+ if (!(Has1 && Has2)) {
+ std::string L = Has1 ? "(present)" : "(not present)";
+ std::string R = Has2 ? "(present)" : "(not present)";
+ D.print("Stream", L, R);
+
+ consumeError(ExpectedInfo1.takeError());
+ consumeError(ExpectedInfo2.takeError());
+ return Error::success();
+ }
+
+ auto &IS1 = *ExpectedInfo1;
+ auto &IS2 = *ExpectedInfo2;
+ D.print("Stream Size", IS1.getStreamSize(), IS2.getStreamSize());
+ D.print("Age", IS1.getAge(), IS2.getAge());
+ D.print("Guid", IS1.getGuid(), IS2.getGuid());
+ D.print("Signature", IS1.getSignature(), IS2.getSignature());
+ D.print("Version", IS1.getVersion(), IS2.getVersion());
+ D.diffUnorderedArray("Feature", IS1.getFeatureSignatures(),
+ IS2.getFeatureSignatures());
+ D.print("Named Stream Size", IS1.getNamedStreamMapByteSize(),
+ IS2.getNamedStreamMapByteSize());
+ StringMap<uint32_t> NSL = IS1.getNamedStreams().getStringMap();
+ StringMap<uint32_t> NSR = IS2.getNamedStreams().getStringMap();
+ D.diffUnorderedMap<EquivalentDiffProvider>("Named Stream", NSL, NSR);
+ return Error::success();
+}
+
+static std::vector<std::pair<uint32_t, DbiModuleDescriptor>>
+getModuleDescriptors(const DbiModuleList &ML) {
+ std::vector<std::pair<uint32_t, DbiModuleDescriptor>> List;
+ List.reserve(ML.getModuleCount());
+ for (uint32_t I = 0; I < ML.getModuleCount(); ++I)
+ List.emplace_back(I, ML.getModuleDescriptor(I));
+ return List;
+}
+
+static void
+diffOneModule(DiffPrinter &D,
+ const std::pair<uint32_t, DbiModuleDescriptor> Item,
+ std::vector<std::pair<uint32_t, DbiModuleDescriptor>> &Other,
+ bool ItemIsRight) {
+ StreamPurposeProvider HeaderProvider(70);
+ std::pair<StreamPurpose, std::string> Header;
+ Header.first = StreamPurpose::ModuleStream;
+ Header.second = Item.second.getModuleName();
+ D.printFullRow(HeaderProvider.format(Header, ItemIsRight));
+
+ const auto *L = &Item;
+
+ BinaryPathProvider PathProvider(28);
+ auto Iter = llvm::find_if(
+ Other, [&PathProvider, ItemIsRight,
+ L](const std::pair<uint32_t, DbiModuleDescriptor> &Other) {
+ const auto *Left = L;
+ const auto *Right = &Other;
+ if (ItemIsRight)
+ std::swap(Left, Right);
+ DiffResult Result = PathProvider.compare(Left->second.getModuleName(),
+ Right->second.getModuleName());
+ return Result == DiffResult::EQUIVALENT ||
+ Result == DiffResult::IDENTICAL;
+ });
+ if (Iter == Other.end()) {
+ // We didn't find this module at all on the other side. Just print one row
+ // and continue.
+ D.print<ModiProvider>("- Modi", Item.first, None);
+ return;
+ }
+
+ // We did find this module. Go through and compare each field.
+ const auto *R = &*Iter;
+ if (ItemIsRight)
+ std::swap(L, R);
+
+ D.print<ModiProvider>("- Modi", L->first, R->first);
+ D.print<BinaryPathProvider>("- Obj File Name", L->second.getObjFileName(),
+ R->second.getObjFileName(), PathProvider);
+ D.print<StreamNumberProvider>("- Debug Stream",
+ L->second.getModuleStreamIndex(),
+ R->second.getModuleStreamIndex());
+ D.print("- C11 Byte Size", L->second.getC11LineInfoByteSize(),
+ R->second.getC11LineInfoByteSize());
+ D.print("- C13 Byte Size", L->second.getC13LineInfoByteSize(),
+ R->second.getC13LineInfoByteSize());
+ D.print("- # of files", L->second.getNumberOfFiles(),
+ R->second.getNumberOfFiles());
+ D.print("- Pdb File Path Index", L->second.getPdbFilePathNameIndex(),
+ R->second.getPdbFilePathNameIndex());
+ D.print("- Source File Name Index", L->second.getSourceFileNameIndex(),
+ R->second.getSourceFileNameIndex());
+ D.print("- Symbol Byte Size", L->second.getSymbolDebugInfoByteSize(),
+ R->second.getSymbolDebugInfoByteSize());
+ Other.erase(Iter);
+}
+
+Error DiffStyle::diffDbiStream() {
+ DiffPrinter D(2, "DBI Stream", 40, 30, opts::diff::PrintResultColumn,
+ opts::diff::PrintValueColumns, outs());
+ D.printExplicit("File", DiffResult::UNSPECIFIED,
+ truncateStringFront(File1.getFilePath(), 28),
+ truncateStringFront(File2.getFilePath(), 28));
+
+ auto ExpectedDbi1 = File1.getPDBDbiStream();
+ auto ExpectedDbi2 = File2.getPDBDbiStream();
+
+ bool Has1 = !!ExpectedDbi1;
+ bool Has2 = !!ExpectedDbi2;
+ if (!(Has1 && Has2)) {
+ std::string L = Has1 ? "(present)" : "(not present)";
+ std::string R = Has2 ? "(present)" : "(not present)";
+ D.print("Stream", L, R);
+
+ consumeError(ExpectedDbi1.takeError());
+ consumeError(ExpectedDbi2.takeError());
+ return Error::success();
+ }
+
+ auto &DL = *ExpectedDbi1;
+ auto &DR = *ExpectedDbi2;
+
+ D.print("Dbi Version", (uint32_t)DL.getDbiVersion(),
+ (uint32_t)DR.getDbiVersion());
+ D.print("Age", DL.getAge(), DR.getAge());
+ D.print("Machine", (uint16_t)DL.getMachineType(),
+ (uint16_t)DR.getMachineType());
+ D.print("Flags", DL.getFlags(), DR.getFlags());
+ D.print("Build Major", DL.getBuildMajorVersion(), DR.getBuildMajorVersion());
+ D.print("Build Minor", DL.getBuildMinorVersion(), DR.getBuildMinorVersion());
+ D.print("Build Number", DL.getBuildNumber(), DR.getBuildNumber());
+ D.print("PDB DLL Version", DL.getPdbDllVersion(), DR.getPdbDllVersion());
+ D.print("PDB DLL RBLD", DL.getPdbDllRbld(), DR.getPdbDllRbld());
+ D.print<StreamNumberProvider>("DBG (FPO)",
+ DL.getDebugStreamIndex(DbgHeaderType::FPO),
+ DR.getDebugStreamIndex(DbgHeaderType::FPO));
+ D.print<StreamNumberProvider>(
+ "DBG (Exception)", DL.getDebugStreamIndex(DbgHeaderType::Exception),
+ DR.getDebugStreamIndex(DbgHeaderType::Exception));
+ D.print<StreamNumberProvider>("DBG (Fixup)",
+ DL.getDebugStreamIndex(DbgHeaderType::Fixup),
+ DR.getDebugStreamIndex(DbgHeaderType::Fixup));
+ D.print<StreamNumberProvider>(
+ "DBG (OmapToSrc)", DL.getDebugStreamIndex(DbgHeaderType::OmapToSrc),
+ DR.getDebugStreamIndex(DbgHeaderType::OmapToSrc));
+ D.print<StreamNumberProvider>(
+ "DBG (OmapFromSrc)", DL.getDebugStreamIndex(DbgHeaderType::OmapFromSrc),
+ DR.getDebugStreamIndex(DbgHeaderType::OmapFromSrc));
+ D.print<StreamNumberProvider>(
+ "DBG (SectionHdr)", DL.getDebugStreamIndex(DbgHeaderType::SectionHdr),
+ DR.getDebugStreamIndex(DbgHeaderType::SectionHdr));
+ D.print<StreamNumberProvider>(
+ "DBG (TokenRidMap)", DL.getDebugStreamIndex(DbgHeaderType::TokenRidMap),
+ DR.getDebugStreamIndex(DbgHeaderType::TokenRidMap));
+ D.print<StreamNumberProvider>("DBG (Xdata)",
+ DL.getDebugStreamIndex(DbgHeaderType::Xdata),
+ DR.getDebugStreamIndex(DbgHeaderType::Xdata));
+ D.print<StreamNumberProvider>("DBG (Pdata)",
+ DL.getDebugStreamIndex(DbgHeaderType::Pdata),
+ DR.getDebugStreamIndex(DbgHeaderType::Pdata));
+ D.print<StreamNumberProvider>("DBG (NewFPO)",
+ DL.getDebugStreamIndex(DbgHeaderType::NewFPO),
+ DR.getDebugStreamIndex(DbgHeaderType::NewFPO));
+ D.print<StreamNumberProvider>(
+ "DBG (SectionHdrOrig)",
+ DL.getDebugStreamIndex(DbgHeaderType::SectionHdrOrig),
+ DR.getDebugStreamIndex(DbgHeaderType::SectionHdrOrig));
+ D.print<StreamNumberProvider>("Globals Stream",
+ DL.getGlobalSymbolStreamIndex(),
+ DR.getGlobalSymbolStreamIndex());
+ D.print<StreamNumberProvider>("Publics Stream",
+ DL.getPublicSymbolStreamIndex(),
+ DR.getPublicSymbolStreamIndex());
+ D.print<StreamNumberProvider>("Symbol Records", DL.getSymRecordStreamIndex(),
+ DR.getSymRecordStreamIndex());
+ D.print("Has CTypes", DL.hasCTypes(), DR.hasCTypes());
+ D.print("Is Incrementally Linked", DL.isIncrementallyLinked(),
+ DR.isIncrementallyLinked());
+ D.print("Is Stripped", DL.isStripped(), DR.isStripped());
+ const DbiModuleList &ML = DL.modules();
+ const DbiModuleList &MR = DR.modules();
+ D.print("Module Count", ML.getModuleCount(), MR.getModuleCount());
+ D.print("Source File Count", ML.getSourceFileCount(),
+ MR.getSourceFileCount());
+ auto MDL = getModuleDescriptors(ML);
+ auto MDR = getModuleDescriptors(MR);
+ // Scan all module descriptors from the left, and look for corresponding
+ // module descriptors on the right.
+ for (const auto &L : MDL)
+ diffOneModule(D, L, MDR, false);
+
+ for (const auto &R : MDR)
+ diffOneModule(D, R, MDL, true);
+
+ return Error::success();
+}
+
+Error DiffStyle::diffSectionContribs() { return Error::success(); }
+
+Error DiffStyle::diffSectionMap() { return Error::success(); }
+
+Error DiffStyle::diffFpoStream() { return Error::success(); }
+
+Error DiffStyle::diffTpiStream(int Index) { return Error::success(); }
+
+Error DiffStyle::diffModuleInfoStream(int Index) { return Error::success(); }
+
+Error DiffStyle::diffPublics() { return Error::success(); }
+
+Error DiffStyle::diffGlobals() { return Error::success(); }
diff --git a/contrib/llvm/tools/llvm-pdbutil/Diff.h b/contrib/llvm/tools/llvm-pdbutil/Diff.h
new file mode 100644
index 0000000..6037576
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/Diff.h
@@ -0,0 +1,45 @@
+//===- Diff.h - PDB diff utility --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_DIFF_H
+#define LLVM_TOOLS_LLVMPDBDUMP_DIFF_H
+
+#include "OutputStyle.h"
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+class DiffStyle : public OutputStyle {
+public:
+ explicit DiffStyle(PDBFile &File1, PDBFile &File2);
+
+ Error dump() override;
+
+private:
+ Error diffSuperBlock();
+ Error diffStreamDirectory();
+ Error diffStringTable();
+ Error diffFreePageMap();
+ Error diffInfoStream();
+ Error diffDbiStream();
+ Error diffSectionContribs();
+ Error diffSectionMap();
+ Error diffFpoStream();
+ Error diffTpiStream(int Index);
+ Error diffModuleInfoStream(int Index);
+ Error diffPublics();
+ Error diffGlobals();
+
+ PDBFile &File1;
+ PDBFile &File2;
+};
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.cpp b/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.cpp
new file mode 100644
index 0000000..dd61cc1
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.cpp
@@ -0,0 +1,147 @@
+
+#include "DiffPrinter.h"
+
+#include "llvm/Support/FormatAdapters.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+struct Colorize {
+ Colorize(raw_ostream &OS, DiffResult Result) : OS(OS) {
+ if (!OS.has_colors())
+ return;
+ switch (Result) {
+ case DiffResult::IDENTICAL:
+ OS.changeColor(raw_ostream::Colors::GREEN, false);
+ break;
+ case DiffResult::EQUIVALENT:
+ OS.changeColor(raw_ostream::Colors::YELLOW, true);
+ break;
+ default:
+ OS.changeColor(raw_ostream::Colors::RED, false);
+ break;
+ }
+ }
+
+ ~Colorize() {
+ if (OS.has_colors())
+ OS.resetColor();
+ }
+
+ raw_ostream &OS;
+};
+}
+
+DiffPrinter::DiffPrinter(uint32_t Indent, StringRef Header,
+ uint32_t PropertyWidth, uint32_t FieldWidth,
+ bool Result, bool Fields, raw_ostream &Stream)
+ : PrintResult(Result), PrintValues(Fields), Indent(Indent),
+ PropertyWidth(PropertyWidth), FieldWidth(FieldWidth), OS(Stream) {
+ printHeaderRow();
+ printFullRow(Header);
+}
+
+DiffPrinter::~DiffPrinter() {}
+
+uint32_t DiffPrinter::tableWidth() const {
+ // `|`
+ uint32_t W = 1;
+
+ // `<width>|`
+ W += PropertyWidth + 1;
+
+ if (PrintResult) {
+ // ` I |`
+ W += 4;
+ }
+
+ if (PrintValues) {
+ // `<width>|<width>|`
+ W += 2 * (FieldWidth + 1);
+ }
+ return W;
+}
+
+void DiffPrinter::printFullRow(StringRef Text) {
+ newLine();
+ printValue(Text, DiffResult::UNSPECIFIED, AlignStyle::Center,
+ tableWidth() - 2, true);
+ printSeparatorRow();
+}
+
+void DiffPrinter::printSeparatorRow() {
+ newLine();
+ OS << formatv("{0}", fmt_repeat('-', PropertyWidth));
+ if (PrintResult) {
+ OS << '+';
+ OS << formatv("{0}", fmt_repeat('-', 3));
+ }
+ if (PrintValues) {
+ OS << '+';
+ OS << formatv("{0}", fmt_repeat('-', FieldWidth));
+ OS << '+';
+ OS << formatv("{0}", fmt_repeat('-', FieldWidth));
+ }
+ OS << '|';
+}
+
+void DiffPrinter::printHeaderRow() {
+ newLine('-');
+ OS << formatv("{0}", fmt_repeat('-', tableWidth() - 1));
+}
+
+void DiffPrinter::newLine(char InitialChar) {
+ OS << "\n";
+ OS.indent(Indent) << InitialChar;
+}
+
+void DiffPrinter::printExplicit(StringRef Property, DiffResult C,
+ StringRef Left, StringRef Right) {
+ newLine();
+ printValue(Property, DiffResult::UNSPECIFIED, AlignStyle::Right,
+ PropertyWidth, true);
+ printResult(C);
+ printValue(Left, C, AlignStyle::Center, FieldWidth, false);
+ printValue(Right, C, AlignStyle::Center, FieldWidth, false);
+ printSeparatorRow();
+}
+
+void DiffPrinter::printResult(DiffResult Result) {
+ if (!PrintResult)
+ return;
+ switch (Result) {
+ case DiffResult::DIFFERENT:
+ printValue("D", Result, AlignStyle::Center, 3, true);
+ break;
+ case DiffResult::EQUIVALENT:
+ printValue("E", Result, AlignStyle::Center, 3, true);
+ break;
+ case DiffResult::IDENTICAL:
+ printValue("I", Result, AlignStyle::Center, 3, true);
+ break;
+ case DiffResult::UNSPECIFIED:
+ printValue(" ", Result, AlignStyle::Center, 3, true);
+ break;
+ }
+}
+
+void DiffPrinter::printValue(StringRef Value, DiffResult C, AlignStyle Style,
+ uint32_t Width, bool Force) {
+ if (!Force && !PrintValues)
+ return;
+
+ if (Style == AlignStyle::Right)
+ --Width;
+
+ std::string FormattedItem =
+ formatv("{0}", fmt_align(Value, Style, Width)).str();
+ if (C != DiffResult::UNSPECIFIED) {
+ Colorize Color(OS, C);
+ OS << FormattedItem;
+ } else
+ OS << FormattedItem;
+ if (Style == AlignStyle::Right)
+ OS << ' ';
+ OS << '|';
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.h b/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.h
new file mode 100644
index 0000000..475747d
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/DiffPrinter.h
@@ -0,0 +1,172 @@
+//===- DiffPrinter.h ------------------------------------------ *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_DIFFPRINTER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_DIFFPRINTER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <list>
+#include <unordered_set>
+
+namespace std {
+template <> struct hash<llvm::pdb::PdbRaw_FeatureSig> {
+ typedef llvm::pdb::PdbRaw_FeatureSig argument_type;
+ typedef std::size_t result_type;
+ result_type operator()(argument_type Item) const {
+ return std::hash<uint32_t>{}(uint32_t(Item));
+ }
+};
+} // namespace std
+
+namespace llvm {
+namespace pdb {
+
+class PDBFile;
+
+enum class DiffResult { UNSPECIFIED, IDENTICAL, EQUIVALENT, DIFFERENT };
+
+struct IdenticalDiffProvider {
+ template <typename T, typename U>
+ DiffResult compare(const T &Left, const U &Right) {
+ return (Left == Right) ? DiffResult::IDENTICAL : DiffResult::DIFFERENT;
+ }
+
+ template <typename T> std::string format(const T &Item, bool Right) {
+ return formatv("{0}", Item).str();
+ }
+};
+
+struct EquivalentDiffProvider {
+ template <typename T, typename U>
+ DiffResult compare(const T &Left, const U &Right) {
+ return (Left == Right) ? DiffResult::IDENTICAL : DiffResult::EQUIVALENT;
+ }
+
+ template <typename T> std::string format(const T &Item, bool Right) {
+ return formatv("{0}", Item).str();
+ }
+};
+
+class DiffPrinter {
+public:
+ DiffPrinter(uint32_t Indent, StringRef Header, uint32_t PropertyWidth,
+ uint32_t FieldWidth, bool Result, bool Values,
+ raw_ostream &Stream);
+ ~DiffPrinter();
+
+ template <typename T, typename U> struct Identical {};
+
+ template <typename Provider = IdenticalDiffProvider, typename T, typename U>
+ void print(StringRef Property, const T &Left, const U &Right,
+ Provider P = Provider()) {
+ std::string L = P.format(Left, false);
+ std::string R = P.format(Right, true);
+
+ DiffResult Result = P.compare(Left, Right);
+ printExplicit(Property, Result, L, R);
+ }
+
+ void printExplicit(StringRef Property, DiffResult C, StringRef Left,
+ StringRef Right);
+
+ template <typename T, typename U>
+ void printExplicit(StringRef Property, DiffResult C, const T &Left,
+ const U &Right) {
+ std::string L = formatv("{0}", Left).str();
+ std::string R = formatv("{0}", Right).str();
+ printExplicit(Property, C, StringRef(L), StringRef(R));
+ }
+
+ template <typename T, typename U>
+ void diffUnorderedArray(StringRef Property, ArrayRef<T> Left,
+ ArrayRef<U> Right) {
+ std::unordered_set<T> LS(Left.begin(), Left.end());
+ std::unordered_set<U> RS(Right.begin(), Right.end());
+ std::string Count1 = formatv("{0} element(s)", Left.size());
+ std::string Count2 = formatv("{0} element(s)", Right.size());
+ print(std::string(Property) + "s (set)", Count1, Count2);
+ for (const auto &L : LS) {
+ auto Iter = RS.find(L);
+ std::string Text = formatv("{0}", L).str();
+ if (Iter == RS.end()) {
+ print(Property, Text, "(not present)");
+ continue;
+ }
+ print(Property, Text, Text);
+ RS.erase(Iter);
+ }
+ for (const auto &R : RS) {
+ auto Iter = LS.find(R);
+ std::string Text = formatv("{0}", R).str();
+ if (Iter == LS.end()) {
+ print(Property, "(not present)", Text);
+ continue;
+ }
+ print(Property, Text, Text);
+ }
+ }
+
+ template <typename ValueProvider = IdenticalDiffProvider, typename T,
+ typename U>
+ void diffUnorderedMap(StringRef Property, const StringMap<T> &Left,
+ const StringMap<U> &Right,
+ ValueProvider P = ValueProvider()) {
+ StringMap<U> RightCopy(Right);
+
+ std::string Count1 = formatv("{0} element(s)", Left.size());
+ std::string Count2 = formatv("{0} element(s)", Right.size());
+ print(std::string(Property) + "s (map)", Count1, Count2);
+
+ for (const auto &L : Left) {
+ auto Iter = RightCopy.find(L.getKey());
+ if (Iter == RightCopy.end()) {
+ printExplicit(L.getKey(), DiffResult::DIFFERENT, L.getValue(),
+ "(not present)");
+ continue;
+ }
+
+ print(L.getKey(), L.getValue(), Iter->getValue(), P);
+ RightCopy.erase(Iter);
+ }
+
+ for (const auto &R : RightCopy) {
+ printExplicit(R.getKey(), DiffResult::DIFFERENT, "(not present)",
+ R.getValue());
+ }
+ }
+
+ void printFullRow(StringRef Text);
+
+private:
+ uint32_t tableWidth() const;
+
+ void printHeaderRow();
+ void printSeparatorRow();
+ void newLine(char InitialChar = '|');
+ void printValue(StringRef Value, DiffResult C, AlignStyle Style,
+ uint32_t Width, bool Force);
+ void printResult(DiffResult Result);
+
+ bool PrintResult;
+ bool PrintValues;
+ uint32_t Indent;
+ uint32_t PropertyWidth;
+ uint32_t FieldWidth;
+ raw_ostream &OS;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
new file mode 100644
index 0000000..01c7481
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
@@ -0,0 +1,1043 @@
+//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DumpOutputStyle.h"
+
+#include "FormatUtil.h"
+#include "MinimalSymbolDumper.h"
+#include "MinimalTypeDumper.h"
+#include "StreamUtil.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
+#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/EnumTables.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#include <unordered_map>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+DumpOutputStyle::DumpOutputStyle(PDBFile &File)
+ : File(File), P(2, false, outs()) {}
+
+Error DumpOutputStyle::dump() {
+ if (opts::dump::DumpSummary) {
+ if (auto EC = dumpFileSummary())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::dump::DumpStreams) {
+ if (auto EC = dumpStreamSummary())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::dump::DumpStringTable) {
+ if (auto EC = dumpStringTable())
+ return EC;
+ P.NewLine();
+ }
+
+ if (opts::dump::DumpModules) {
+ if (auto EC = dumpModules())
+ return EC;
+ }
+
+ if (opts::dump::DumpModuleFiles) {
+ if (auto EC = dumpModuleFiles())
+ return EC;
+ }
+
+ if (opts::dump::DumpLines) {
+ if (auto EC = dumpLines())
+ return EC;
+ }
+
+ if (opts::dump::DumpInlineeLines) {
+ if (auto EC = dumpInlineeLines())
+ return EC;
+ }
+
+ if (opts::dump::DumpXmi) {
+ if (auto EC = dumpXmi())
+ return EC;
+ }
+
+ if (opts::dump::DumpXme) {
+ if (auto EC = dumpXme())
+ return EC;
+ }
+
+ if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
+ opts::dump::DumpTypeExtras) {
+ if (auto EC = dumpTpiStream(StreamTPI))
+ return EC;
+ }
+
+ if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
+ opts::dump::DumpIdExtras) {
+ if (auto EC = dumpTpiStream(StreamIPI))
+ return EC;
+ }
+
+ if (opts::dump::DumpPublics) {
+ if (auto EC = dumpPublics())
+ return EC;
+ }
+
+ if (opts::dump::DumpSymbols) {
+ if (auto EC = dumpModuleSyms())
+ return EC;
+ }
+
+ if (opts::dump::DumpSectionContribs) {
+ if (auto EC = dumpSectionContribs())
+ return EC;
+ }
+
+ if (opts::dump::DumpSectionMap) {
+ if (auto EC = dumpSectionMap())
+ return EC;
+ }
+
+ return Error::success();
+}
+
+static void printHeader(LinePrinter &P, const Twine &S) {
+ P.NewLine();
+ P.formatLine("{0,=60}", S);
+ P.formatLine("{0}", fmt_repeat('=', 60));
+}
+
+Error DumpOutputStyle::dumpFileSummary() {
+ printHeader(P, "Summary");
+
+ ExitOnError Err("Invalid PDB Format");
+
+ AutoIndent Indent(P);
+ P.formatLine("Block Size: {0}", File.getBlockSize());
+ P.formatLine("Number of blocks: {0}", File.getBlockCount());
+ P.formatLine("Number of streams: {0}", File.getNumStreams());
+
+ auto &PS = Err(File.getPDBInfoStream());
+ P.formatLine("Signature: {0}", PS.getSignature());
+ P.formatLine("Age: {0}", PS.getAge());
+ P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
+ P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
+ P.formatLine("Has Debug Info: {0}", File.hasPDBDbiStream());
+ P.formatLine("Has Types: {0}", File.hasPDBTpiStream());
+ P.formatLine("Has IDs: {0}", File.hasPDBIpiStream());
+ P.formatLine("Has Globals: {0}", File.hasPDBGlobalsStream());
+ P.formatLine("Has Publics: {0}", File.hasPDBPublicsStream());
+ if (File.hasPDBDbiStream()) {
+ auto &DBI = Err(File.getPDBDbiStream());
+ P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
+ P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
+ P.formatLine("Is stripped: {0}", DBI.isStripped());
+ }
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpStreamSummary() {
+ printHeader(P, "Streams");
+
+ if (StreamPurposes.empty())
+ discoverStreamPurposes(File, StreamPurposes);
+
+ AutoIndent Indent(P);
+ uint32_t StreamCount = File.getNumStreams();
+
+ for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
+ P.formatLine(
+ "Stream {0}: [{1}] ({2} bytes)",
+ fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
+ StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
+ if (opts::dump::DumpStreamBlocks) {
+ auto Blocks = File.getStreamBlockList(StreamIdx);
+ std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
+ P.formatLine(" {0} Blocks: [{1}]",
+ fmt_repeat(' ', NumDigits(StreamCount)),
+ make_range(BV.begin(), BV.end()));
+ }
+ }
+
+ return Error::success();
+}
+
+static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
+ uint32_t Index) {
+ ExitOnError Err("Unexpected error");
+
+ auto &Dbi = Err(File.getPDBDbiStream());
+ const auto &Modules = Dbi.modules();
+ auto Modi = Modules.getModuleDescriptor(Index);
+
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ if (ModiStream == kInvalidStreamIndex)
+ return make_error<RawError>(raw_error_code::no_stream,
+ "Module stream not present");
+
+ auto ModStreamData = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+
+ ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
+ if (auto EC = ModS.reload())
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid module stream");
+
+ return std::move(ModS);
+}
+
+static std::string formatChecksumKind(FileChecksumKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(FileChecksumKind, None, "None");
+ RETURN_CASE(FileChecksumKind, MD5, "MD5");
+ RETURN_CASE(FileChecksumKind, SHA1, "SHA-1");
+ RETURN_CASE(FileChecksumKind, SHA256, "SHA-256");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+namespace {
+class StringsAndChecksumsPrinter {
+ const DebugStringTableSubsectionRef &extractStringTable(PDBFile &File) {
+ ExitOnError Err("Unexpected error processing modules");
+ return Err(File.getStringTable()).getStringTable();
+ }
+
+ template <typename... Args>
+ void formatInternal(LinePrinter &Printer, bool Append,
+ Args &&... args) const {
+ if (Append)
+ Printer.format(std::forward<Args>(args)...);
+ else
+ Printer.formatLine(std::forward<Args>(args)...);
+ }
+
+public:
+ StringsAndChecksumsPrinter(PDBFile &File, uint32_t Modi)
+ : Records(extractStringTable(File)) {
+ auto MDS = getModuleDebugStream(File, Modi);
+ if (!MDS) {
+ consumeError(MDS.takeError());
+ return;
+ }
+
+ DebugStream = llvm::make_unique<ModuleDebugStreamRef>(std::move(*MDS));
+ Records.initialize(MDS->subsections());
+ if (Records.hasChecksums()) {
+ for (const auto &Entry : Records.checksums()) {
+ auto S = Records.strings().getString(Entry.FileNameOffset);
+ if (!S)
+ continue;
+ ChecksumsByFile[*S] = Entry;
+ }
+ }
+ }
+
+ Expected<StringRef> getNameFromStringTable(uint32_t Offset) const {
+ return Records.strings().getString(Offset);
+ }
+
+ void formatFromFileName(LinePrinter &Printer, StringRef File,
+ bool Append = false) const {
+ auto FC = ChecksumsByFile.find(File);
+ if (FC == ChecksumsByFile.end()) {
+ formatInternal(Printer, Append, "- (no checksum) {0}", File);
+ return;
+ }
+
+ formatInternal(Printer, Append, "- ({0}: {1}) {2}",
+ formatChecksumKind(FC->getValue().Kind),
+ toHex(FC->getValue().Checksum), File);
+ }
+
+ void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset,
+ bool Append = false) const {
+ if (!Records.hasChecksums()) {
+ formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
+ return;
+ }
+
+ auto Iter = Records.checksums().getArray().at(Offset);
+ if (Iter == Records.checksums().getArray().end()) {
+ formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
+ return;
+ }
+
+ uint32_t FO = Iter->FileNameOffset;
+ auto ExpectedFile = getNameFromStringTable(FO);
+ if (!ExpectedFile) {
+ formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
+ consumeError(ExpectedFile.takeError());
+ return;
+ }
+ if (Iter->Kind == FileChecksumKind::None) {
+ formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile);
+ } else {
+ formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile,
+ formatChecksumKind(Iter->Kind), toHex(Iter->Checksum));
+ }
+ }
+
+ std::unique_ptr<ModuleDebugStreamRef> DebugStream;
+ StringsAndChecksumsRef Records;
+ StringMap<FileChecksumEntry> ChecksumsByFile;
+};
+} // namespace
+
+template <typename CallbackT>
+static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
+ CallbackT Callback) {
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return;
+ }
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
+ Modi.getModuleName());
+
+ StringsAndChecksumsPrinter Strings(File, I);
+ AutoIndent Indent2(P, IndentLevel);
+ Callback(I, Strings);
+ }
+}
+
+template <typename SubsectionT>
+static void iterateModuleSubsections(
+ PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
+ llvm::function_ref<void(uint32_t, StringsAndChecksumsPrinter &,
+ SubsectionT &)>
+ Callback) {
+
+ iterateModules(
+ File, P, IndentLevel,
+ [&File, &Callback](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
+ auto MDS = getModuleDebugStream(File, Modi);
+ if (!MDS) {
+ consumeError(MDS.takeError());
+ return;
+ }
+
+ for (const auto &SS : MDS->subsections()) {
+ SubsectionT Subsection;
+
+ if (SS.kind() != Subsection.kind())
+ continue;
+
+ BinaryStreamReader Reader(SS.getRecordData());
+ if (auto EC = Subsection.initialize(Reader))
+ continue;
+ Callback(Modi, Strings, Subsection);
+ }
+ });
+}
+
+Error DumpOutputStyle::dumpModules() {
+ printHeader(P, "Modules");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return Error::success();
+ }
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | Name: `{1}`: ",
+ fmt_align(I, AlignStyle::Right, Digits), Modi.getModuleName());
+ P.formatLine(" Obj: `{0}`: ", Modi.getObjFileName());
+ P.formatLine(" debug stream: {0}, # files: {1}, has ec info: {2}",
+ Modi.getModuleStreamIndex(), Modi.getNumberOfFiles(),
+ Modi.hasECInfo());
+ StringRef PdbFilePath =
+ Err(Stream.getECName(Modi.getPdbFilePathNameIndex()));
+ StringRef SrcFilePath =
+ Err(Stream.getECName(Modi.getSourceFileNameIndex()));
+ P.formatLine(" pdb file ni: {0} `{1}`, src file ni: {2} `{3}`",
+ Modi.getPdbFilePathNameIndex(), PdbFilePath,
+ Modi.getSourceFileNameIndex(), SrcFilePath);
+ }
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpModuleFiles() {
+ printHeader(P, "Files");
+
+ ExitOnError Err("Unexpected error processing modules");
+
+ iterateModules(
+ File, P, 11,
+ [this, &Err](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ const DbiModuleList &Modules = Stream.modules();
+ for (const auto &F : Modules.source_files(Modi)) {
+ Strings.formatFromFileName(P, F);
+ }
+ });
+ return Error::success();
+}
+
+static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P,
+ uint32_t Start, const LineColumnEntry &E) {
+ const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
+ uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
+
+ // Let's try to keep it under 100 characters
+ constexpr uint32_t kMaxRowLength = 100;
+ // At least 3 spaces between columns.
+ uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
+ uint32_t ItemsLeft = E.LineNumbers.size();
+ auto LineIter = E.LineNumbers.begin();
+ while (ItemsLeft != 0) {
+ uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
+ for (uint32_t I = 0; I < RowColumns; ++I) {
+ LineInfo Line(LineIter->Flags);
+ std::string LineStr;
+ if (Line.isAlwaysStepInto())
+ LineStr = "ASI";
+ else if (Line.isNeverStepInto())
+ LineStr = "NSI";
+ else
+ LineStr = utostr(Line.getStartLine());
+ char Statement = Line.isStatement() ? ' ' : '!';
+ P.format("{0} {1:X-} {2} ",
+ fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
+ fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
+ Statement);
+ ++LineIter;
+ --ItemsLeft;
+ }
+ P.NewLine();
+ }
+}
+
+Error DumpOutputStyle::dumpLines() {
+ printHeader(P, "Lines");
+
+ uint32_t LastModi = UINT32_MAX;
+ uint32_t LastNameIndex = UINT32_MAX;
+ iterateModuleSubsections<DebugLinesSubsectionRef>(
+ File, P, 4,
+ [this, &LastModi, &LastNameIndex](uint32_t Modi,
+ StringsAndChecksumsPrinter &Strings,
+ DebugLinesSubsectionRef &Lines) {
+ uint16_t Segment = Lines.header()->RelocSegment;
+ uint32_t Begin = Lines.header()->RelocOffset;
+ uint32_t End = Begin + Lines.header()->CodeSize;
+ for (const auto &Block : Lines) {
+ if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
+ LastModi = Modi;
+ LastNameIndex = Block.NameIndex;
+ Strings.formatFromChecksumsOffset(P, Block.NameIndex);
+ }
+
+ AutoIndent Indent(P, 2);
+ P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
+ uint32_t Count = Block.LineNumbers.size();
+ if (Lines.hasColumnInfo())
+ P.format("line/column/addr entries = {0}", Count);
+ else
+ P.format("line/addr entries = {0}", Count);
+
+ P.NewLine();
+ typesetLinesAndColumns(File, P, Begin, Block);
+ }
+ });
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpInlineeLines() {
+ printHeader(P, "Inlinee Lines");
+
+ iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
+ File, P, 2,
+ [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
+ DebugInlineeLinesSubsectionRef &Lines) {
+ P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
+ for (const auto &Entry : Lines) {
+ P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
+ fmtle(Entry.Header->SourceLineNum));
+ Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
+ }
+ P.NewLine();
+ });
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpXmi() {
+ printHeader(P, "Cross Module Imports");
+ iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
+ File, P, 2,
+ [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
+ DebugCrossModuleImportsSubsectionRef &Imports) {
+ P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
+
+ for (const auto &Xmi : Imports) {
+ auto ExpectedModule =
+ Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
+ StringRef Module;
+ SmallString<32> ModuleStorage;
+ if (!ExpectedModule) {
+ Module = "(unknown module)";
+ consumeError(ExpectedModule.takeError());
+ } else
+ Module = *ExpectedModule;
+ if (Module.size() > 32) {
+ ModuleStorage = "...";
+ ModuleStorage += Module.take_back(32 - 3);
+ Module = ModuleStorage;
+ }
+ std::vector<std::string> TIs;
+ for (const auto I : Xmi.Imports)
+ TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
+ std::string Result =
+ typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
+ P.formatLine("{0,+32} | {1}", Module, Result);
+ }
+ });
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpXme() {
+ printHeader(P, "Cross Module Exports");
+
+ iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
+ File, P, 2,
+ [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
+ DebugCrossModuleExportsSubsectionRef &Exports) {
+ P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
+ for (const auto &Export : Exports) {
+ P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
+ TypeIndex(Export.Global));
+ }
+ });
+
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpStringTable() {
+ printHeader(P, "String Table");
+
+ AutoIndent Indent(P);
+ auto IS = File.getStringTable();
+ if (!IS) {
+ P.formatLine("Not present in file");
+ consumeError(IS.takeError());
+ return Error::success();
+ }
+
+ if (IS->name_ids().empty()) {
+ P.formatLine("Empty");
+ return Error::success();
+ }
+
+ auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
+ uint32_t Digits = NumDigits(*MaxID);
+
+ P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
+ "String");
+
+ std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
+ std::sort(SortedIDs.begin(), SortedIDs.end());
+ for (uint32_t I : SortedIDs) {
+ auto ES = IS->getStringForID(I);
+ llvm::SmallString<32> Str;
+ if (!ES) {
+ consumeError(ES.takeError());
+ Str = "Error reading string";
+ } else if (!ES->empty()) {
+ Str.append("'");
+ Str.append(*ES);
+ Str.append("'");
+ }
+
+ if (!Str.empty())
+ P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
+ }
+ return Error::success();
+}
+
+static void buildDepSet(LazyRandomTypeCollection &Types,
+ ArrayRef<TypeIndex> Indices,
+ std::map<TypeIndex, CVType> &DepSet) {
+ SmallVector<TypeIndex, 4> DepList;
+ for (const auto &I : Indices) {
+ TypeIndex TI(I);
+ if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
+ continue;
+
+ CVType Type = Types.getType(TI);
+ DepSet[TI] = Type;
+ codeview::discoverTypeIndices(Type, DepList);
+ buildDepSet(Types, DepList, DepSet);
+ }
+}
+
+static void dumpFullTypeStream(LinePrinter &Printer,
+ LazyRandomTypeCollection &Types,
+ TpiStream &Stream, bool Bytes, bool Extras) {
+ Printer.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
+ uint32_t Width =
+ NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
+
+ MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+ Stream.getNumHashBuckets(), Stream.getHashValues());
+
+ if (auto EC = codeview::visitTypeStream(Types, V)) {
+ Printer.formatLine("An error occurred dumping type records: {0}",
+ toString(std::move(EC)));
+ }
+}
+
+static void dumpPartialTypeStream(LinePrinter &Printer,
+ LazyRandomTypeCollection &Types,
+ TpiStream &Stream, ArrayRef<TypeIndex> TiList,
+ bool Bytes, bool Extras, bool Deps) {
+ uint32_t Width =
+ NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
+
+ MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+ Stream.getNumHashBuckets(), Stream.getHashValues());
+
+ if (opts::dump::DumpTypeDependents) {
+ // If we need to dump all dependents, then iterate each index and find
+ // all dependents, adding them to a map ordered by TypeIndex.
+ std::map<TypeIndex, CVType> DepSet;
+ buildDepSet(Types, TiList, DepSet);
+
+ Printer.formatLine(
+ "Showing {0:N} records and their dependents ({1:N} records total)",
+ TiList.size(), DepSet.size());
+
+ for (auto &Dep : DepSet) {
+ if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
+ Printer.formatLine("An error occurred dumping type record {0}: {1}",
+ Dep.first, toString(std::move(EC)));
+ }
+ } else {
+ Printer.formatLine("Showing {0:N} records.", TiList.size());
+
+ for (const auto &I : TiList) {
+ TypeIndex TI(I);
+ CVType Type = Types.getType(TI);
+ if (auto EC = codeview::visitTypeRecord(Type, TI, V))
+ Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
+ toString(std::move(EC)));
+ }
+ }
+}
+
+Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
+ assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
+
+ bool Present = false;
+ bool DumpTypes = false;
+ bool DumpBytes = false;
+ bool DumpExtras = false;
+ std::vector<uint32_t> Indices;
+ if (StreamIdx == StreamTPI) {
+ printHeader(P, "Types (TPI Stream)");
+ Present = File.hasPDBTpiStream();
+ DumpTypes = opts::dump::DumpTypes;
+ DumpBytes = opts::dump::DumpTypeData;
+ DumpExtras = opts::dump::DumpTypeExtras;
+ Indices.assign(opts::dump::DumpTypeIndex.begin(),
+ opts::dump::DumpTypeIndex.end());
+ } else if (StreamIdx == StreamIPI) {
+ printHeader(P, "Types (IPI Stream)");
+ Present = File.hasPDBIpiStream();
+ DumpTypes = opts::dump::DumpIds;
+ DumpBytes = opts::dump::DumpIdData;
+ DumpExtras = opts::dump::DumpIdExtras;
+ Indices.assign(opts::dump::DumpIdIndex.begin(),
+ opts::dump::DumpIdIndex.end());
+ }
+
+ AutoIndent Indent(P);
+ if (!Present) {
+ P.formatLine("Stream not present");
+ return Error::success();
+ }
+
+ ExitOnError Err("Unexpected error processing types");
+
+ auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream()
+ : File.getPDBIpiStream());
+
+ auto &Types = Err(initializeTypes(StreamIdx));
+
+ if (DumpTypes || !Indices.empty()) {
+ if (Indices.empty())
+ dumpFullTypeStream(P, Types, Stream, DumpBytes, DumpExtras);
+ else {
+ std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
+ dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
+ opts::dump::DumpTypeDependents);
+ }
+ }
+
+ if (DumpExtras) {
+ P.NewLine();
+ auto IndexOffsets = Stream.getTypeIndexOffsets();
+ P.formatLine("Type Index Offsets:");
+ for (const auto &IO : IndexOffsets) {
+ AutoIndent Indent2(P);
+ P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
+ }
+
+ P.NewLine();
+ P.formatLine("Hash Adjusters:");
+ auto &Adjusters = Stream.getHashAdjusters();
+ auto &Strings = Err(File.getStringTable());
+ for (const auto &A : Adjusters) {
+ AutoIndent Indent2(P);
+ auto ExpectedStr = Strings.getStringForID(A.first);
+ TypeIndex TI(A.second);
+ if (ExpectedStr)
+ P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
+ else {
+ P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
+ consumeError(ExpectedStr.takeError());
+ }
+ }
+ }
+ return Error::success();
+}
+
+Expected<codeview::LazyRandomTypeCollection &>
+DumpOutputStyle::initializeTypes(uint32_t SN) {
+ auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
+ auto Tpi =
+ (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
+ if (!Tpi)
+ return Tpi.takeError();
+
+ if (!TypeCollection) {
+ auto &Types = Tpi->typeArray();
+ uint32_t Count = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ TypeCollection =
+ llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
+ }
+
+ return *TypeCollection;
+}
+
+Error DumpOutputStyle::dumpModuleSyms() {
+ printHeader(P, "Symbols");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("DBI Stream not present");
+ return Error::success();
+ }
+
+ ExitOnError Err("Unexpected error processing symbols");
+
+ auto &Stream = Err(File.getPDBDbiStream());
+
+ auto &Types = Err(initializeTypes(StreamTPI));
+
+ const DbiModuleList &Modules = Stream.modules();
+ uint32_t Count = Modules.getModuleCount();
+ uint32_t Digits = NumDigits(Count);
+ for (uint32_t I = 0; I < Count; ++I) {
+ auto Modi = Modules.getModuleDescriptor(I);
+ P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
+ Modi.getModuleName());
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ if (ModiStream == kInvalidStreamIndex) {
+ P.formatLine(" <symbols not present>");
+ continue;
+ }
+ auto ModStreamData = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+
+ ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
+ if (auto EC = ModS.reload()) {
+ P.formatLine("Error loading module stream {0}. {1}", I,
+ toString(std::move(EC)));
+ continue;
+ }
+
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
+ MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+ auto SS = ModS.getSymbolsSubstream();
+ if (auto EC = Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) {
+ P.formatLine("Error while processing symbol records. {0}",
+ toString(std::move(EC)));
+ continue;
+ }
+ }
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpPublics() {
+ printHeader(P, "Public Symbols");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBPublicsStream()) {
+ P.formatLine("Publics stream not present");
+ return Error::success();
+ }
+
+ ExitOnError Err("Error dumping publics stream");
+
+ auto &Types = Err(initializeTypes(StreamTPI));
+ auto &Publics = Err(File.getPDBPublicsStream());
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
+ MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+
+ auto ExpectedSymbols = Publics.getSymbolArray();
+ if (!ExpectedSymbols) {
+ P.formatLine("Could not read public symbol record stream");
+ return Error::success();
+ }
+
+ if (auto EC = Visitor.visitSymbolStream(*ExpectedSymbols, 0))
+ P.formatLine("Error while processing public symbol records. {0}",
+ toString(std::move(EC)));
+
+ return Error::success();
+}
+
+static std::string formatSectionCharacteristics(uint32_t IndentLevel,
+ uint32_t C) {
+ using SC = COFF::SectionCharacteristics;
+ std::vector<std::string> Opts;
+ if (C == COFF::SC_Invalid)
+ return "invalid";
+ if (C == 0)
+ return "none";
+
+ PUSH_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, "IMAGE_SCN_TYPE_NOLOAD");
+ PUSH_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, "IMAGE_SCN_TYPE_NO_PAD");
+ PUSH_FLAG(SC, IMAGE_SCN_CNT_CODE, C, "IMAGE_SCN_CNT_CODE");
+ PUSH_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C,
+ "IMAGE_SCN_CNT_INITIALIZED_DATA");
+ PUSH_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C,
+ "IMAGE_SCN_CNT_UNINITIALIZED_DATA");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, "IMAGE_SCN_LNK_OTHER");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_INFO, C, "IMAGE_SCN_LNK_INFO");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, "IMAGE_SCN_LNK_REMOVE");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, "IMAGE_SCN_LNK_COMDAT");
+ PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, "IMAGE_SCN_MEM_PURGEABLE");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, "IMAGE_SCN_MEM_16BIT");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, "IMAGE_SCN_MEM_LOCKED");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, "IMAGE_SCN_MEM_PRELOAD");
+ PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
+ PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C,
+ "IMAGE_SCN_ALIGN_1BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C,
+ "IMAGE_SCN_ALIGN_2BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C,
+ "IMAGE_SCN_ALIGN_4BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C,
+ "IMAGE_SCN_ALIGN_8BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C,
+ "IMAGE_SCN_ALIGN_16BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C,
+ "IMAGE_SCN_ALIGN_32BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C,
+ "IMAGE_SCN_ALIGN_64BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C,
+ "IMAGE_SCN_ALIGN_128BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C,
+ "IMAGE_SCN_ALIGN_256BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C,
+ "IMAGE_SCN_ALIGN_512BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C,
+ "IMAGE_SCN_ALIGN_1024BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C,
+ "IMAGE_SCN_ALIGN_2048BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C,
+ "IMAGE_SCN_ALIGN_4096BYTES");
+ PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C,
+ "IMAGE_SCN_ALIGN_8192BYTES");
+ PUSH_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, "IMAGE_SCN_LNK_NRELOC_OVFL");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, "IMAGE_SCN_MEM_DISCARDABLE");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, "IMAGE_SCN_MEM_NOT_CACHED");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, "IMAGE_SCN_MEM_NOT_PAGED");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, "IMAGE_SCN_MEM_SHARED");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, "IMAGE_SCN_MEM_EXECUTE");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_READ, C, "IMAGE_SCN_MEM_READ");
+ PUSH_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, "IMAGE_SCN_MEM_WRITE");
+ return typesetItemList(Opts, IndentLevel, 3, " | ");
+}
+
+static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
+ OMFSegDescFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == OMFSegDescFlags::None)
+ return "none";
+
+ PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
+ PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
+ PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
+ PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
+ PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
+ PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
+ PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
+ return typesetItemList(Opts, IndentLevel, 4, " | ");
+}
+
+Error DumpOutputStyle::dumpSectionContribs() {
+ printHeader(P, "Section Contributions");
+ ExitOnError Err("Error dumping publics stream");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine(
+ "Section contribs require a DBI Stream, which could not be loaded");
+ return Error::success();
+ }
+
+ auto &Dbi = Err(File.getPDBDbiStream());
+
+ class Visitor : public ISectionContribVisitor {
+ public:
+ Visitor(LinePrinter &P) : P(P) {}
+ void visit(const SectionContrib &SC) override {
+ P.formatLine(
+ "SC | mod = {2}, {0}, size = {1}, data crc = {3}, reloc crc = {4}",
+ formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), fmtle(SC.Imod),
+ fmtle(SC.DataCrc), fmtle(SC.RelocCrc));
+ P.formatLine(" {0}",
+ formatSectionCharacteristics(P.getIndentLevel() + 6,
+ SC.Characteristics));
+ }
+ void visit(const SectionContrib2 &SC) override {
+ P.formatLine("SC2 | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
+ "crc = {4}, coff section = {5}",
+ formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
+ fmtle(SC.Base.Size), fmtle(SC.Base.Imod),
+ fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
+ fmtle(SC.ISectCoff));
+ P.formatLine(" {0}",
+ formatSectionCharacteristics(P.getIndentLevel() + 6,
+ SC.Base.Characteristics));
+ }
+
+ private:
+ LinePrinter &P;
+ };
+
+ Visitor V(P);
+ Dbi.visitSectionContributions(V);
+ return Error::success();
+}
+
+Error DumpOutputStyle::dumpSectionMap() {
+ printHeader(P, "Section Map");
+ ExitOnError Err("Error dumping section map");
+
+ AutoIndent Indent(P);
+ if (!File.hasPDBDbiStream()) {
+ P.formatLine("Dumping the section map requires a DBI Stream, which could "
+ "not be loaded");
+ return Error::success();
+ }
+
+ auto &Dbi = Err(File.getPDBDbiStream());
+
+ uint32_t I = 0;
+ for (auto &M : Dbi.getSectionMap()) {
+ P.formatLine(
+ "Section {0:4} | ovl = {0}, group = {1}, frame = {2}, name = {3}", I,
+ fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
+ P.formatLine(" class = {0}, offset = {1}, size = {2}",
+ fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
+ P.formatLine(" flags = {0}",
+ formatSegMapDescriptorFlag(
+ P.getIndentLevel() + 13,
+ static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
+ ++I;
+ }
+ return Error::success();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
new file mode 100644
index 0000000..4c52289
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
@@ -0,0 +1,62 @@
+//===- DumpOutputStyle.h -------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H
+#define LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H
+
+#include "LinePrinter.h"
+#include "OutputStyle.h"
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include <string>
+
+namespace llvm {
+class BitVector;
+
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+class DumpOutputStyle : public OutputStyle {
+public:
+ DumpOutputStyle(PDBFile &File);
+
+ Error dump() override;
+
+private:
+ Expected<codeview::LazyRandomTypeCollection &> initializeTypes(uint32_t SN);
+
+ Error dumpFileSummary();
+ Error dumpStreamSummary();
+ Error dumpStringTable();
+ Error dumpLines();
+ Error dumpInlineeLines();
+ Error dumpXmi();
+ Error dumpXme();
+ Error dumpTpiStream(uint32_t StreamIdx);
+ Error dumpModules();
+ Error dumpModuleFiles();
+ Error dumpModuleSyms();
+ Error dumpPublics();
+ Error dumpSectionContribs();
+ Error dumpSectionMap();
+
+ PDBFile &File;
+ LinePrinter P;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes;
+ SmallVector<std::string, 32> StreamPurposes;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp
new file mode 100644
index 0000000..0203027
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp
@@ -0,0 +1,101 @@
+//===- FormatUtil.cpp ----------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatUtil.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+std::string llvm::pdb::truncateStringBack(StringRef S, uint32_t MaxLen) {
+ if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3)
+ return S;
+
+ assert(MaxLen >= 3);
+ uint32_t FinalLen = std::min<size_t>(S.size(), MaxLen - 3);
+ S = S.take_front(FinalLen);
+ return std::string(S) + std::string("...");
+}
+
+std::string llvm::pdb::truncateStringMiddle(StringRef S, uint32_t MaxLen) {
+ if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3)
+ return S;
+
+ assert(MaxLen >= 3);
+ uint32_t FinalLen = std::min<size_t>(S.size(), MaxLen - 3);
+ StringRef Front = S.take_front(FinalLen / 2);
+ StringRef Back = S.take_back(Front.size());
+ return std::string(Front) + std::string("...") + std::string(Back);
+}
+
+std::string llvm::pdb::truncateStringFront(StringRef S, uint32_t MaxLen) {
+ if (MaxLen == 0 || S.size() <= MaxLen || S.size() <= 3)
+ return S;
+
+ assert(MaxLen >= 3);
+ S = S.take_back(MaxLen - 3);
+ return std::string("...") + std::string(S);
+}
+
+std::string llvm::pdb::truncateQuotedNameFront(StringRef Label, StringRef Name,
+ uint32_t MaxLen) {
+ uint32_t RequiredExtraChars = Label.size() + 1 + 2;
+ if (MaxLen == 0 || RequiredExtraChars + Name.size() <= MaxLen)
+ return formatv("{0} \"{1}\"", Label, Name).str();
+
+ assert(MaxLen >= RequiredExtraChars);
+ std::string TN = truncateStringFront(Name, MaxLen - RequiredExtraChars);
+ return formatv("{0} \"{1}\"", Label, TN).str();
+}
+
+std::string llvm::pdb::truncateQuotedNameBack(StringRef Label, StringRef Name,
+ uint32_t MaxLen) {
+ uint32_t RequiredExtraChars = Label.size() + 1 + 2;
+ if (MaxLen == 0 || RequiredExtraChars + Name.size() <= MaxLen)
+ return formatv("{0} \"{1}\"", Label, Name).str();
+
+ assert(MaxLen >= RequiredExtraChars);
+ std::string TN = truncateStringBack(Name, MaxLen - RequiredExtraChars);
+ return formatv("{0} \"{1}\"", Label, TN).str();
+}
+
+std::string llvm::pdb::typesetItemList(ArrayRef<std::string> Opts,
+ uint32_t IndentLevel, uint32_t GroupSize,
+ StringRef Sep) {
+ std::string Result;
+ while (!Opts.empty()) {
+ ArrayRef<std::string> ThisGroup;
+ ThisGroup = Opts.take_front(GroupSize);
+ Opts = Opts.drop_front(ThisGroup.size());
+ Result += join(ThisGroup, Sep);
+ if (!Opts.empty()) {
+ Result += Sep;
+ Result += "\n";
+ Result += formatv("{0}", fmt_repeat(' ', IndentLevel));
+ }
+ }
+ return Result;
+}
+
+std::string llvm::pdb::typesetStringList(uint32_t IndentLevel,
+ ArrayRef<StringRef> Strings) {
+ std::string Result = "[";
+ for (const auto &S : Strings) {
+ Result += formatv("\n{0}{1}", fmt_repeat(' ', IndentLevel), S);
+ }
+ Result += "]";
+ return Result;
+}
+
+std::string llvm::pdb::formatSegmentOffset(uint16_t Segment, uint32_t Offset) {
+ return formatv("{0:4}:{1:4}", Segment, Offset);
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h
new file mode 100644
index 0000000..df32ed9
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h
@@ -0,0 +1,128 @@
+//===- FormatUtil.h ------------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBUTIL_FORMAT_UTIL_H
+#define LLVM_TOOLS_LLVMPDBUTIL_FORMAT_UTIL_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#include <string>
+#include <type_traits>
+
+namespace llvm {
+namespace pdb {
+
+std::string truncateStringBack(StringRef S, uint32_t MaxLen);
+std::string truncateStringMiddle(StringRef S, uint32_t MaxLen);
+std::string truncateStringFront(StringRef S, uint32_t MaxLen);
+std::string truncateQuotedNameFront(StringRef Label, StringRef Name,
+ uint32_t MaxLen);
+std::string truncateQuotedNameBack(StringRef Label, StringRef Name,
+ uint32_t MaxLen);
+
+#define PUSH_MASKED_FLAG(Enum, Mask, TheOpt, Value, Text) \
+ if (Enum::TheOpt == (Value & Mask)) \
+ Opts.push_back(Text);
+
+#define PUSH_FLAG(Enum, TheOpt, Value, Text) \
+ PUSH_MASKED_FLAG(Enum, Enum::TheOpt, TheOpt, Value, Text)
+
+#define RETURN_CASE(Enum, X, Ret) \
+ case Enum::X: \
+ return Ret;
+
+template <typename T> std::string formatUnknownEnum(T Value) {
+ return formatv("unknown ({0})",
+ static_cast<typename std::underlying_type<T>::type>(Value))
+ .str();
+}
+
+std::string formatSegmentOffset(uint16_t Segment, uint32_t Offset);
+
+std::string typesetItemList(ArrayRef<std::string> Opts, uint32_t IndentLevel,
+ uint32_t GroupSize, StringRef Sep);
+
+std::string typesetStringList(uint32_t IndentLevel,
+ ArrayRef<StringRef> Strings);
+
+/// Returns the number of digits in the given integer.
+inline int NumDigits(uint64_t N) {
+ if (N < 10ULL)
+ return 1;
+ if (N < 100ULL)
+ return 2;
+ if (N < 1000ULL)
+ return 3;
+ if (N < 10000ULL)
+ return 4;
+ if (N < 100000ULL)
+ return 5;
+ if (N < 1000000ULL)
+ return 6;
+ if (N < 10000000ULL)
+ return 7;
+ if (N < 100000000ULL)
+ return 8;
+ if (N < 1000000000ULL)
+ return 9;
+ if (N < 10000000000ULL)
+ return 10;
+ if (N < 100000000000ULL)
+ return 11;
+ if (N < 1000000000000ULL)
+ return 12;
+ if (N < 10000000000000ULL)
+ return 13;
+ if (N < 100000000000000ULL)
+ return 14;
+ if (N < 1000000000000000ULL)
+ return 15;
+ if (N < 10000000000000000ULL)
+ return 16;
+ if (N < 100000000000000000ULL)
+ return 17;
+ if (N < 1000000000000000000ULL)
+ return 18;
+ if (N < 10000000000000000000ULL)
+ return 19;
+ return 20;
+}
+
+namespace detail {
+template <typename T>
+struct EndianAdapter final
+ : public FormatAdapter<support::detail::packed_endian_specific_integral<
+ T, support::little, support::unaligned>> {
+ using EndianType =
+ support::detail::packed_endian_specific_integral<T, support::little,
+ support::unaligned>;
+
+ explicit EndianAdapter(EndianType &&Item)
+ : FormatAdapter<EndianType>(std::move(Item)) {}
+
+ void format(llvm::raw_ostream &Stream, StringRef Style) {
+ format_provider<T>::format(static_cast<T>(this->Item), Stream, Style);
+ }
+};
+} // namespace detail
+
+template <typename T>
+detail::EndianAdapter<T>
+fmtle(support::detail::packed_endian_specific_integral<T, support::little,
+ support::unaligned>
+ Value) {
+ return detail::EndianAdapter<T>(std::move(Value));
+}
+}
+} // namespace llvm
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp
new file mode 100644
index 0000000..6e4d95a
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp
@@ -0,0 +1,312 @@
+//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinePrinter.h"
+
+#include "llvm-pdbutil.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Regex.h"
+
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace {
+bool IsItemExcluded(llvm::StringRef Item,
+ std::list<llvm::Regex> &IncludeFilters,
+ std::list<llvm::Regex> &ExcludeFilters) {
+ if (Item.empty())
+ return false;
+
+ auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); };
+
+ // Include takes priority over exclude. If the user specified include
+ // filters, and none of them include this item, them item is gone.
+ if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred))
+ return true;
+
+ if (any_of(ExcludeFilters, match_pred))
+ return true;
+
+ return false;
+}
+}
+
+using namespace llvm;
+
+LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream)
+ : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) {
+ SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(),
+ opts::pretty::ExcludeTypes.end());
+ SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(),
+ opts::pretty::ExcludeSymbols.end());
+ SetFilters(ExcludeCompilandFilters, opts::pretty::ExcludeCompilands.begin(),
+ opts::pretty::ExcludeCompilands.end());
+
+ SetFilters(IncludeTypeFilters, opts::pretty::IncludeTypes.begin(),
+ opts::pretty::IncludeTypes.end());
+ SetFilters(IncludeSymbolFilters, opts::pretty::IncludeSymbols.begin(),
+ opts::pretty::IncludeSymbols.end());
+ SetFilters(IncludeCompilandFilters, opts::pretty::IncludeCompilands.begin(),
+ opts::pretty::IncludeCompilands.end());
+}
+
+void LinePrinter::Indent(uint32_t Amount) {
+ if (Amount == 0)
+ Amount = IndentSpaces;
+ CurrentIndent += Amount;
+}
+
+void LinePrinter::Unindent(uint32_t Amount) {
+ if (Amount == 0)
+ Amount = IndentSpaces;
+ CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
+}
+
+void LinePrinter::NewLine() {
+ OS << "\n";
+ OS.indent(CurrentIndent);
+}
+
+void LinePrinter::print(const Twine &T) { OS << T; }
+
+void LinePrinter::printLine(const Twine &T) {
+ NewLine();
+ OS << T;
+}
+
+bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
+ if (IsTypeExcluded(Class.getName(), Class.getSize()))
+ return true;
+ if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
+ return true;
+ return false;
+}
+
+void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+ uint32_t StartOffset) {
+ NewLine();
+ OS << Label << " (";
+ if (!Data.empty()) {
+ OS << "\n";
+ OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ NewLine();
+ }
+ OS << ")";
+}
+
+void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+ uint64_t Base, uint32_t StartOffset) {
+ NewLine();
+ OS << Label << " (";
+ if (!Data.empty()) {
+ OS << "\n";
+ Base += StartOffset;
+ OS << format_bytes_with_ascii(Data, Base, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ NewLine();
+ }
+ OS << ")";
+}
+
+namespace {
+struct Run {
+ Run() = default;
+ explicit Run(uint32_t Block) : Block(Block) {}
+ uint32_t Block = 0;
+ uint32_t ByteLen = 0;
+};
+} // namespace
+
+static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
+ const msf::MSFStreamLayout &Layout) {
+ std::vector<Run> Runs;
+ if (Layout.Length == 0)
+ return Runs;
+
+ ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;
+ assert(!Blocks.empty());
+ uint32_t StreamBytesRemaining = Layout.Length;
+ uint32_t CurrentBlock = Blocks[0];
+ Runs.emplace_back(CurrentBlock);
+ while (!Blocks.empty()) {
+ Run *CurrentRun = &Runs.back();
+ uint32_t NextBlock = Blocks.front();
+ if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) {
+ Runs.emplace_back(NextBlock);
+ CurrentRun = &Runs.back();
+ }
+ uint32_t Used = std::min(BlockSize, StreamBytesRemaining);
+ CurrentRun->ByteLen += Used;
+ StreamBytesRemaining -= Used;
+ CurrentBlock = NextBlock;
+ Blocks = Blocks.drop_front();
+ }
+ return Runs;
+}
+
+static std::pair<Run, uint32_t> findRun(uint32_t Offset, ArrayRef<Run> Runs) {
+ for (const auto &R : Runs) {
+ if (Offset < R.ByteLen)
+ return std::make_pair(R, Offset);
+ Offset -= R.ByteLen;
+ }
+ llvm_unreachable("Invalid offset!");
+}
+
+void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
+ uint32_t StreamIdx,
+ StringRef StreamPurpose, uint32_t Offset,
+ uint32_t Size) {
+ if (StreamIdx >= File.getNumStreams()) {
+ formatLine("Stream {0}: Not present", StreamIdx);
+ return;
+ }
+ if (Size + Offset > File.getStreamByteSize(StreamIdx)) {
+ formatLine(
+ "Stream {0}: Invalid offset and size, range out of stream bounds",
+ StreamIdx);
+ return;
+ }
+
+ auto S = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), StreamIdx, File.getAllocator());
+ if (!S) {
+ NewLine();
+ formatLine("Stream {0}: Not present", StreamIdx);
+ return;
+ }
+
+ uint32_t End =
+ (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
+ Size = End - Offset;
+
+ formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,
+ StreamPurpose, Size, S->getLength());
+ AutoIndent Indent(*this);
+ BinaryStreamRef Slice(*S);
+ BinarySubstreamRef Substream;
+ Substream.Offset = Offset;
+ Substream.StreamData = Slice.drop_front(Offset).keep_front(Size);
+
+ auto Layout = File.getStreamLayout(StreamIdx);
+ formatMsfStreamData(Label, File, Layout, Substream);
+}
+
+void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinarySubstreamRef Substream) {
+ BinaryStreamReader Reader(Substream.StreamData);
+
+ auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
+
+ NewLine();
+ OS << Label << " (";
+ while (Reader.bytesRemaining() > 0) {
+ OS << "\n";
+
+ Run FoundRun;
+ uint32_t RunOffset;
+ std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs);
+ assert(FoundRun.ByteLen >= RunOffset);
+ uint32_t Len = FoundRun.ByteLen - RunOffset;
+ Len = std::min(Len, Reader.bytesRemaining());
+ uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
+ ArrayRef<uint8_t> Data;
+ consumeError(Reader.readBytes(Data, Len));
+ OS << format_bytes_with_ascii(Data, Base, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ if (Reader.bytesRemaining() > 0) {
+ NewLine();
+ OS << formatv(" {0}",
+ fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
+ }
+ Substream.Offset += Len;
+ }
+ NewLine();
+ OS << ")";
+}
+
+bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
+ if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
+ return true;
+ if (Size < opts::pretty::SizeThreshold)
+ return true;
+ return false;
+}
+
+bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
+ return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters);
+}
+
+bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
+ return IsItemExcluded(CompilandName, IncludeCompilandFilters,
+ ExcludeCompilandFilters);
+}
+
+WithColor::WithColor(LinePrinter &P, PDB_ColorItem C)
+ : OS(P.OS), UseColor(P.hasColor()) {
+ if (UseColor)
+ applyColor(C);
+}
+
+WithColor::~WithColor() {
+ if (UseColor)
+ OS.resetColor();
+}
+
+void WithColor::applyColor(PDB_ColorItem C) {
+ switch (C) {
+ case PDB_ColorItem::None:
+ OS.resetColor();
+ return;
+ case PDB_ColorItem::Comment:
+ OS.changeColor(raw_ostream::GREEN, false);
+ return;
+ case PDB_ColorItem::Address:
+ OS.changeColor(raw_ostream::YELLOW, /*bold=*/true);
+ return;
+ case PDB_ColorItem::Keyword:
+ OS.changeColor(raw_ostream::MAGENTA, true);
+ return;
+ case PDB_ColorItem::Register:
+ case PDB_ColorItem::Offset:
+ OS.changeColor(raw_ostream::YELLOW, false);
+ return;
+ case PDB_ColorItem::Type:
+ OS.changeColor(raw_ostream::CYAN, true);
+ return;
+ case PDB_ColorItem::Identifier:
+ OS.changeColor(raw_ostream::CYAN, false);
+ return;
+ case PDB_ColorItem::Path:
+ OS.changeColor(raw_ostream::CYAN, false);
+ return;
+ case PDB_ColorItem::Padding:
+ case PDB_ColorItem::SectionHeader:
+ OS.changeColor(raw_ostream::RED, true);
+ return;
+ case PDB_ColorItem::LiteralValue:
+ OS.changeColor(raw_ostream::GREEN, true);
+ return;
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbdump/LinePrinter.h b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h
index a4401f8..68ce321 100644
--- a/contrib/llvm/tools/llvm-pdbdump/LinePrinter.h
+++ b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h
@@ -10,30 +10,63 @@
#ifndef LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H
#define LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
#include <list>
namespace llvm {
+class BinaryStreamReader;
+namespace msf {
+class MSFStreamLayout;
+} // namespace msf
namespace pdb {
+class ClassLayout;
+class PDBFile;
+
class LinePrinter {
friend class WithColor;
public:
- LinePrinter(int Indent, raw_ostream &Stream);
+ LinePrinter(int Indent, bool UseColor, raw_ostream &Stream);
- void Indent();
- void Unindent();
+ void Indent(uint32_t Amount = 0);
+ void Unindent(uint32_t Amount = 0);
void NewLine();
+ void printLine(const Twine &T);
+ void print(const Twine &T);
+ template <typename... Ts> void formatLine(const char *Fmt, Ts &&... Items) {
+ printLine(formatv(Fmt, std::forward<Ts>(Items)...));
+ }
+ template <typename... Ts> void format(const char *Fmt, Ts &&... Items) {
+ print(formatv(Fmt, std::forward<Ts>(Items)...));
+ }
+
+ void formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
+ uint32_t StartOffset);
+ void formatBinary(StringRef Label, ArrayRef<uint8_t> Data, uint64_t BaseAddr,
+ uint32_t StartOffset);
+
+ void formatMsfStreamData(StringRef Label, PDBFile &File, uint32_t StreamIdx,
+ StringRef StreamPurpose, uint32_t Offset,
+ uint32_t Size);
+ void formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinarySubstreamRef Substream);
+
+ bool hasColor() const { return UseColor; }
raw_ostream &getStream() { return OS; }
int getIndentLevel() const { return CurrentIndent; }
- bool IsTypeExcluded(llvm::StringRef TypeName);
+ bool IsClassExcluded(const ClassLayout &Class);
+ bool IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size);
bool IsSymbolExcluded(llvm::StringRef SymbolName);
bool IsCompilandExcluded(llvm::StringRef CompilandName);
@@ -48,6 +81,7 @@ private:
raw_ostream &OS;
int IndentSpaces;
int CurrentIndent;
+ bool UseColor;
std::list<Regex> ExcludeCompilandFilters;
std::list<Regex> ExcludeTypeFilters;
@@ -58,6 +92,17 @@ private:
std::list<Regex> IncludeSymbolFilters;
};
+struct AutoIndent {
+ explicit AutoIndent(LinePrinter &L, uint32_t Amount = 0)
+ : L(L), Amount(Amount) {
+ L.Indent(Amount);
+ }
+ ~AutoIndent() { L.Unindent(Amount); }
+
+ LinePrinter &L;
+ uint32_t Amount = 0;
+};
+
template <class T>
inline raw_ostream &operator<<(LinePrinter &Printer, const T &Item) {
Printer.getStream() << Item;
@@ -68,6 +113,8 @@ enum class PDB_ColorItem {
None,
Address,
Type,
+ Comment,
+ Padding,
Keyword,
Offset,
Identifier,
@@ -87,6 +134,7 @@ public:
private:
void applyColor(PDB_ColorItem C);
raw_ostream &OS;
+ bool UseColor;
};
}
}
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
new file mode 100644
index 0000000..d938436
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
@@ -0,0 +1,772 @@
+//===- MinimalSymbolDumper.cpp -------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinimalSymbolDumper.h"
+
+#include "FormatUtil.h"
+#include "LinePrinter.h"
+
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static StringRef getSymbolKindName(SymbolKind K) {
+ switch (K) {
+#define SYMBOL_RECORD(EnumName, value, name) \
+ case EnumName: \
+ return #EnumName;
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+ default:
+ llvm_unreachable("Unknown symbol kind!");
+ }
+ return "";
+}
+
+static std::string formatLocalSymFlags(uint32_t IndentLevel,
+ LocalSymFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == LocalSymFlags::None)
+ return "none";
+
+ PUSH_FLAG(LocalSymFlags, IsParameter, Flags, "param");
+ PUSH_FLAG(LocalSymFlags, IsAddressTaken, Flags, "address is taken");
+ PUSH_FLAG(LocalSymFlags, IsCompilerGenerated, Flags, "compiler generated");
+ PUSH_FLAG(LocalSymFlags, IsAggregate, Flags, "aggregate");
+ PUSH_FLAG(LocalSymFlags, IsAggregated, Flags, "aggregated");
+ PUSH_FLAG(LocalSymFlags, IsAliased, Flags, "aliased");
+ PUSH_FLAG(LocalSymFlags, IsAlias, Flags, "alias");
+ PUSH_FLAG(LocalSymFlags, IsReturnValue, Flags, "return val");
+ PUSH_FLAG(LocalSymFlags, IsOptimizedOut, Flags, "optimized away");
+ PUSH_FLAG(LocalSymFlags, IsEnregisteredGlobal, Flags, "enreg global");
+ PUSH_FLAG(LocalSymFlags, IsEnregisteredStatic, Flags, "enreg static");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatExportFlags(uint32_t IndentLevel, ExportFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == ExportFlags::None)
+ return "none";
+
+ PUSH_FLAG(ExportFlags, IsConstant, Flags, "constant");
+ PUSH_FLAG(ExportFlags, IsData, Flags, "data");
+ PUSH_FLAG(ExportFlags, IsPrivate, Flags, "private");
+ PUSH_FLAG(ExportFlags, HasNoName, Flags, "no name");
+ PUSH_FLAG(ExportFlags, HasExplicitOrdinal, Flags, "explicit ord");
+ PUSH_FLAG(ExportFlags, IsForwarder, Flags, "forwarder");
+
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatCompileSym2Flags(uint32_t IndentLevel,
+ CompileSym2Flags Flags) {
+ std::vector<std::string> Opts;
+ Flags &= ~CompileSym2Flags::SourceLanguageMask;
+ if (Flags == CompileSym2Flags::None)
+ return "none";
+
+ PUSH_FLAG(CompileSym2Flags, EC, Flags, "edit and continue");
+ PUSH_FLAG(CompileSym2Flags, NoDbgInfo, Flags, "no dbg info");
+ PUSH_FLAG(CompileSym2Flags, LTCG, Flags, "ltcg");
+ PUSH_FLAG(CompileSym2Flags, NoDataAlign, Flags, "no data align");
+ PUSH_FLAG(CompileSym2Flags, ManagedPresent, Flags, "has managed code");
+ PUSH_FLAG(CompileSym2Flags, SecurityChecks, Flags, "security checks");
+ PUSH_FLAG(CompileSym2Flags, HotPatch, Flags, "hot patchable");
+ PUSH_FLAG(CompileSym2Flags, CVTCIL, Flags, "cvtcil");
+ PUSH_FLAG(CompileSym2Flags, MSILModule, Flags, "msil module");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatCompileSym3Flags(uint32_t IndentLevel,
+ CompileSym3Flags Flags) {
+ std::vector<std::string> Opts;
+ Flags &= ~CompileSym3Flags::SourceLanguageMask;
+
+ if (Flags == CompileSym3Flags::None)
+ return "none";
+
+ PUSH_FLAG(CompileSym3Flags, EC, Flags, "edit and continue");
+ PUSH_FLAG(CompileSym3Flags, NoDbgInfo, Flags, "no dbg info");
+ PUSH_FLAG(CompileSym3Flags, LTCG, Flags, "ltcg");
+ PUSH_FLAG(CompileSym3Flags, NoDataAlign, Flags, "no data align");
+ PUSH_FLAG(CompileSym3Flags, ManagedPresent, Flags, "has managed code");
+ PUSH_FLAG(CompileSym3Flags, SecurityChecks, Flags, "security checks");
+ PUSH_FLAG(CompileSym3Flags, HotPatch, Flags, "hot patchable");
+ PUSH_FLAG(CompileSym3Flags, CVTCIL, Flags, "cvtcil");
+ PUSH_FLAG(CompileSym3Flags, MSILModule, Flags, "msil module");
+ PUSH_FLAG(CompileSym3Flags, Sdl, Flags, "sdl");
+ PUSH_FLAG(CompileSym3Flags, PGO, Flags, "pgo");
+ PUSH_FLAG(CompileSym3Flags, Exp, Flags, "exp");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatFrameProcedureOptions(uint32_t IndentLevel,
+ FrameProcedureOptions FPO) {
+ std::vector<std::string> Opts;
+ if (FPO == FrameProcedureOptions::None)
+ return "none";
+
+ PUSH_FLAG(FrameProcedureOptions, HasAlloca, FPO, "has alloca");
+ PUSH_FLAG(FrameProcedureOptions, HasSetJmp, FPO, "has setjmp");
+ PUSH_FLAG(FrameProcedureOptions, HasLongJmp, FPO, "has longjmp");
+ PUSH_FLAG(FrameProcedureOptions, HasInlineAssembly, FPO, "has inline asm");
+ PUSH_FLAG(FrameProcedureOptions, HasExceptionHandling, FPO, "has eh");
+ PUSH_FLAG(FrameProcedureOptions, MarkedInline, FPO, "marked inline");
+ PUSH_FLAG(FrameProcedureOptions, HasStructuredExceptionHandling, FPO,
+ "has seh");
+ PUSH_FLAG(FrameProcedureOptions, Naked, FPO, "naked");
+ PUSH_FLAG(FrameProcedureOptions, SecurityChecks, FPO, "secure checks");
+ PUSH_FLAG(FrameProcedureOptions, AsynchronousExceptionHandling, FPO,
+ "has async eh");
+ PUSH_FLAG(FrameProcedureOptions, NoStackOrderingForSecurityChecks, FPO,
+ "no stack order");
+ PUSH_FLAG(FrameProcedureOptions, Inlined, FPO, "inlined");
+ PUSH_FLAG(FrameProcedureOptions, StrictSecurityChecks, FPO,
+ "strict secure checks");
+ PUSH_FLAG(FrameProcedureOptions, SafeBuffers, FPO, "safe buffers");
+ PUSH_FLAG(FrameProcedureOptions, ProfileGuidedOptimization, FPO, "pgo");
+ PUSH_FLAG(FrameProcedureOptions, ValidProfileCounts, FPO,
+ "has profile counts");
+ PUSH_FLAG(FrameProcedureOptions, OptimizedForSpeed, FPO, "opt speed");
+ PUSH_FLAG(FrameProcedureOptions, GuardCfg, FPO, "guard cfg");
+ PUSH_FLAG(FrameProcedureOptions, GuardCfw, FPO, "guard cfw");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatPublicSymFlags(uint32_t IndentLevel,
+ PublicSymFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == PublicSymFlags::None)
+ return "none";
+
+ PUSH_FLAG(PublicSymFlags, Code, Flags, "code");
+ PUSH_FLAG(PublicSymFlags, Function, Flags, "function");
+ PUSH_FLAG(PublicSymFlags, Managed, Flags, "managed");
+ PUSH_FLAG(PublicSymFlags, MSIL, Flags, "msil");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatProcSymFlags(uint32_t IndentLevel,
+ ProcSymFlags Flags) {
+ std::vector<std::string> Opts;
+ if (Flags == ProcSymFlags::None)
+ return "none";
+
+ PUSH_FLAG(ProcSymFlags, HasFP, Flags, "has fp");
+ PUSH_FLAG(ProcSymFlags, HasIRET, Flags, "has iret");
+ PUSH_FLAG(ProcSymFlags, HasFRET, Flags, "has fret");
+ PUSH_FLAG(ProcSymFlags, IsNoReturn, Flags, "noreturn");
+ PUSH_FLAG(ProcSymFlags, IsUnreachable, Flags, "unreachable");
+ PUSH_FLAG(ProcSymFlags, HasCustomCallingConv, Flags, "custom calling conv");
+ PUSH_FLAG(ProcSymFlags, IsNoInline, Flags, "noinline");
+ PUSH_FLAG(ProcSymFlags, HasOptimizedDebugInfo, Flags, "opt debuginfo");
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string formatThunkOrdinal(ThunkOrdinal Ordinal) {
+ switch (Ordinal) {
+ RETURN_CASE(ThunkOrdinal, Standard, "thunk");
+ RETURN_CASE(ThunkOrdinal, ThisAdjustor, "this adjustor");
+ RETURN_CASE(ThunkOrdinal, Vcall, "vcall");
+ RETURN_CASE(ThunkOrdinal, Pcode, "pcode");
+ RETURN_CASE(ThunkOrdinal, UnknownLoad, "unknown load");
+ RETURN_CASE(ThunkOrdinal, TrampIncremental, "tramp incremental");
+ RETURN_CASE(ThunkOrdinal, BranchIsland, "branch island");
+ }
+ return formatUnknownEnum(Ordinal);
+}
+
+static std::string formatTrampolineType(TrampolineType Tramp) {
+ switch (Tramp) {
+ RETURN_CASE(TrampolineType, TrampIncremental, "tramp incremental");
+ RETURN_CASE(TrampolineType, BranchIsland, "branch island");
+ }
+ return formatUnknownEnum(Tramp);
+}
+
+static std::string formatSourceLanguage(SourceLanguage Lang) {
+ switch (Lang) {
+ RETURN_CASE(SourceLanguage, C, "c");
+ RETURN_CASE(SourceLanguage, Cpp, "c++");
+ RETURN_CASE(SourceLanguage, Fortran, "fortran");
+ RETURN_CASE(SourceLanguage, Masm, "masm");
+ RETURN_CASE(SourceLanguage, Pascal, "pascal");
+ RETURN_CASE(SourceLanguage, Basic, "basic");
+ RETURN_CASE(SourceLanguage, Cobol, "cobol");
+ RETURN_CASE(SourceLanguage, Link, "link");
+ RETURN_CASE(SourceLanguage, VB, "vb");
+ RETURN_CASE(SourceLanguage, Cvtres, "cvtres");
+ RETURN_CASE(SourceLanguage, Cvtpgd, "cvtpgd");
+ RETURN_CASE(SourceLanguage, CSharp, "c#");
+ RETURN_CASE(SourceLanguage, ILAsm, "il asm");
+ RETURN_CASE(SourceLanguage, Java, "java");
+ RETURN_CASE(SourceLanguage, JScript, "javascript");
+ RETURN_CASE(SourceLanguage, MSIL, "msil");
+ RETURN_CASE(SourceLanguage, HLSL, "hlsl");
+ }
+ return formatUnknownEnum(Lang);
+}
+
+static std::string formatMachineType(CPUType Cpu) {
+ switch (Cpu) {
+ RETURN_CASE(CPUType, Intel8080, "intel 8080");
+ RETURN_CASE(CPUType, Intel8086, "intel 8086");
+ RETURN_CASE(CPUType, Intel80286, "intel 80286");
+ RETURN_CASE(CPUType, Intel80386, "intel 80386");
+ RETURN_CASE(CPUType, Intel80486, "intel 80486");
+ RETURN_CASE(CPUType, Pentium, "intel pentium");
+ RETURN_CASE(CPUType, PentiumPro, "intel pentium pro");
+ RETURN_CASE(CPUType, Pentium3, "intel pentium 3");
+ RETURN_CASE(CPUType, MIPS, "mips");
+ RETURN_CASE(CPUType, MIPS16, "mips-16");
+ RETURN_CASE(CPUType, MIPS32, "mips-32");
+ RETURN_CASE(CPUType, MIPS64, "mips-64");
+ RETURN_CASE(CPUType, MIPSI, "mips i");
+ RETURN_CASE(CPUType, MIPSII, "mips ii");
+ RETURN_CASE(CPUType, MIPSIII, "mips iii");
+ RETURN_CASE(CPUType, MIPSIV, "mips iv");
+ RETURN_CASE(CPUType, MIPSV, "mips v");
+ RETURN_CASE(CPUType, M68000, "motorola 68000");
+ RETURN_CASE(CPUType, M68010, "motorola 68010");
+ RETURN_CASE(CPUType, M68020, "motorola 68020");
+ RETURN_CASE(CPUType, M68030, "motorola 68030");
+ RETURN_CASE(CPUType, M68040, "motorola 68040");
+ RETURN_CASE(CPUType, Alpha, "alpha");
+ RETURN_CASE(CPUType, Alpha21164, "alpha 21164");
+ RETURN_CASE(CPUType, Alpha21164A, "alpha 21164a");
+ RETURN_CASE(CPUType, Alpha21264, "alpha 21264");
+ RETURN_CASE(CPUType, Alpha21364, "alpha 21364");
+ RETURN_CASE(CPUType, PPC601, "powerpc 601");
+ RETURN_CASE(CPUType, PPC603, "powerpc 603");
+ RETURN_CASE(CPUType, PPC604, "powerpc 604");
+ RETURN_CASE(CPUType, PPC620, "powerpc 620");
+ RETURN_CASE(CPUType, PPCFP, "powerpc fp");
+ RETURN_CASE(CPUType, PPCBE, "powerpc be");
+ RETURN_CASE(CPUType, SH3, "sh3");
+ RETURN_CASE(CPUType, SH3E, "sh3e");
+ RETURN_CASE(CPUType, SH3DSP, "sh3 dsp");
+ RETURN_CASE(CPUType, SH4, "sh4");
+ RETURN_CASE(CPUType, SHMedia, "shmedia");
+ RETURN_CASE(CPUType, ARM3, "arm 3");
+ RETURN_CASE(CPUType, ARM4, "arm 4");
+ RETURN_CASE(CPUType, ARM4T, "arm 4t");
+ RETURN_CASE(CPUType, ARM5, "arm 5");
+ RETURN_CASE(CPUType, ARM5T, "arm 5t");
+ RETURN_CASE(CPUType, ARM6, "arm 6");
+ RETURN_CASE(CPUType, ARM_XMAC, "arm xmac");
+ RETURN_CASE(CPUType, ARM_WMMX, "arm wmmx");
+ RETURN_CASE(CPUType, ARM7, "arm 7");
+ RETURN_CASE(CPUType, Omni, "omni");
+ RETURN_CASE(CPUType, Ia64, "intel itanium ia64");
+ RETURN_CASE(CPUType, Ia64_2, "intel itanium ia64 2");
+ RETURN_CASE(CPUType, CEE, "cee");
+ RETURN_CASE(CPUType, AM33, "am33");
+ RETURN_CASE(CPUType, M32R, "m32r");
+ RETURN_CASE(CPUType, TriCore, "tri-core");
+ RETURN_CASE(CPUType, X64, "intel x86-x64");
+ RETURN_CASE(CPUType, EBC, "ebc");
+ RETURN_CASE(CPUType, Thumb, "thumb");
+ RETURN_CASE(CPUType, ARMNT, "arm nt");
+ RETURN_CASE(CPUType, D3D11_Shader, "d3d11 shader");
+ }
+ return formatUnknownEnum(Cpu);
+}
+
+static std::string formatCookieKind(FrameCookieKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(FrameCookieKind, Copy, "copy");
+ RETURN_CASE(FrameCookieKind, XorStackPointer, "xor stack ptr");
+ RETURN_CASE(FrameCookieKind, XorFramePointer, "xor frame ptr");
+ RETURN_CASE(FrameCookieKind, XorR13, "xor rot13");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+static std::string formatRegisterId(RegisterId Id) {
+ switch (Id) {
+ RETURN_CASE(RegisterId, VFrame, "vframe");
+ RETURN_CASE(RegisterId, AL, "al");
+ RETURN_CASE(RegisterId, CL, "cl");
+ RETURN_CASE(RegisterId, DL, "dl");
+ RETURN_CASE(RegisterId, BL, "bl");
+ RETURN_CASE(RegisterId, AH, "ah");
+ RETURN_CASE(RegisterId, CH, "ch");
+ RETURN_CASE(RegisterId, DH, "dh");
+ RETURN_CASE(RegisterId, BH, "bh");
+ RETURN_CASE(RegisterId, AX, "ax");
+ RETURN_CASE(RegisterId, CX, "cx");
+ RETURN_CASE(RegisterId, DX, "dx");
+ RETURN_CASE(RegisterId, BX, "bx");
+ RETURN_CASE(RegisterId, SP, "sp");
+ RETURN_CASE(RegisterId, BP, "bp");
+ RETURN_CASE(RegisterId, SI, "si");
+ RETURN_CASE(RegisterId, DI, "di");
+ RETURN_CASE(RegisterId, EAX, "eax");
+ RETURN_CASE(RegisterId, ECX, "ecx");
+ RETURN_CASE(RegisterId, EDX, "edx");
+ RETURN_CASE(RegisterId, EBX, "ebx");
+ RETURN_CASE(RegisterId, ESP, "esp");
+ RETURN_CASE(RegisterId, EBP, "ebp");
+ RETURN_CASE(RegisterId, ESI, "esi");
+ RETURN_CASE(RegisterId, EDI, "edi");
+ RETURN_CASE(RegisterId, ES, "es");
+ RETURN_CASE(RegisterId, CS, "cs");
+ RETURN_CASE(RegisterId, SS, "ss");
+ RETURN_CASE(RegisterId, DS, "ds");
+ RETURN_CASE(RegisterId, FS, "fs");
+ RETURN_CASE(RegisterId, GS, "gs");
+ RETURN_CASE(RegisterId, IP, "ip");
+ RETURN_CASE(RegisterId, RAX, "rax");
+ RETURN_CASE(RegisterId, RBX, "rbx");
+ RETURN_CASE(RegisterId, RCX, "rcx");
+ RETURN_CASE(RegisterId, RDX, "rdx");
+ RETURN_CASE(RegisterId, RSI, "rsi");
+ RETURN_CASE(RegisterId, RDI, "rdi");
+ RETURN_CASE(RegisterId, RBP, "rbp");
+ RETURN_CASE(RegisterId, RSP, "rsp");
+ RETURN_CASE(RegisterId, R8, "r8");
+ RETURN_CASE(RegisterId, R9, "r9");
+ RETURN_CASE(RegisterId, R10, "r10");
+ RETURN_CASE(RegisterId, R11, "r11");
+ RETURN_CASE(RegisterId, R12, "r12");
+ RETURN_CASE(RegisterId, R13, "r13");
+ RETURN_CASE(RegisterId, R14, "r14");
+ RETURN_CASE(RegisterId, R15, "r15");
+ default:
+ return formatUnknownEnum(Id);
+ }
+}
+
+static std::string formatRange(LocalVariableAddrRange Range) {
+ return formatv("[{0},+{1})",
+ formatSegmentOffset(Range.ISectStart, Range.OffsetStart),
+ Range.Range)
+ .str();
+}
+
+static std::string formatGaps(uint32_t IndentLevel,
+ ArrayRef<LocalVariableAddrGap> Gaps) {
+ std::vector<std::string> GapStrs;
+ for (const auto &G : Gaps) {
+ GapStrs.push_back(formatv("({0},{1})", G.GapStartOffset, G.Range).str());
+ }
+ return typesetItemList(GapStrs, 7, IndentLevel, ", ");
+}
+
+Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record) {
+ return visitSymbolBegin(Record, 0);
+}
+
+Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record,
+ uint32_t Offset) {
+ // formatLine puts the newline at the beginning, so we use formatLine here
+ // to start a new line, and then individual visit methods use format to
+ // append to the existing line.
+ P.formatLine("{0} | {1} [size = {2}]",
+ fmt_align(Offset, AlignStyle::Right, 6),
+ getSymbolKindName(Record.Type), Record.length());
+ P.Indent();
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitSymbolEnd(CVSymbol &Record) {
+ P.Unindent();
+ return Error::success();
+}
+
+std::string MinimalSymbolDumper::typeIndex(TypeIndex TI) const {
+ if (TI.isSimple())
+ return formatv("{0}", TI).str();
+ StringRef Name = Types.getTypeName(TI);
+ if (Name.size() > 32) {
+ Name = Name.take_front(32);
+ return formatv("{0} ({1}...)", TI, Name);
+ } else
+ return formatv("{0} ({1})", TI, Name);
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) {
+ P.format(" `{0}`", Block.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("parent = {0}, end = {1}", Block.Parent, Block.End);
+ P.formatLine("code size = {0}, addr = {1}", Block.CodeSize,
+ formatSegmentOffset(Block.Segment, Block.CodeOffset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) {
+ P.format(" `{0}`", Thunk.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("parent = {0}, end = {1}, next = {2}", Thunk.Parent, Thunk.End,
+ Thunk.Next);
+ P.formatLine("kind = {0}, size = {1}, addr = {2}",
+ formatThunkOrdinal(Thunk.Thunk), Thunk.Length,
+ formatSegmentOffset(Thunk.Segment, Thunk.Offset));
+
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ TrampolineSym &Tramp) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, size = {1}, source = {2}, target = {3}",
+ formatTrampolineType(Tramp.Type), Tramp.Size,
+ formatSegmentOffset(Tramp.ThunkSection, Tramp.ThunkOffset),
+ formatSegmentOffset(Tramp.TargetSection, Tramp.ThunkOffset));
+
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ SectionSym &Section) {
+ P.format(" `{0}`", Section.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("length = {0}, alignment = {1}, rva = {2}, section # = {3}, "
+ "characteristics = {4}",
+ Section.Length, Section.Alignment, Section.Rva,
+ Section.SectionNumber, Section.Characteristics);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CoffGroupSym &CG) {
+ P.format(" `{0}`", CG.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("length = {0}, addr = {1}, characteristics = {2}", CG.Size,
+ formatSegmentOffset(CG.Segment, CG.Offset), CG.Characteristics);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ BPRelativeSym &BPRel) {
+ P.format(" `{0}`", BPRel.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, offset = {1}", typeIndex(BPRel.Type), BPRel.Offset);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ BuildInfoSym &BuildInfo) {
+ P.format(" BuildId = `{0}`", BuildInfo.BuildId);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ CallSiteInfoSym &CSI) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, addr = {1}", typeIndex(CSI.Type),
+ formatSegmentOffset(CSI.Segment, CSI.CodeOffset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ EnvBlockSym &EnvBlock) {
+ AutoIndent Indent(P, 7);
+ for (const auto &Entry : EnvBlock.Fields) {
+ P.formatLine("- {0}", Entry);
+ }
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FileStaticSym &FS) {
+ P.format(" `{0}`", FS.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, file name offset = {1}, flags = {2}",
+ typeIndex(FS.Index), FS.ModFilenameOffset,
+ formatLocalSymFlags(P.getIndentLevel() + 9, FS.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) {
+ P.format(" `{0}`", Export.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("ordinal = {0}, flags = {1}", Export.Ordinal,
+ formatExportFlags(P.getIndentLevel() + 9, Export.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ Compile2Sym &Compile2) {
+ AutoIndent Indent(P, 7);
+ SourceLanguage Lang = static_cast<SourceLanguage>(
+ Compile2.Flags & CompileSym2Flags::SourceLanguageMask);
+ P.formatLine("machine = {0}, ver = {1}, language = {2}",
+ formatMachineType(Compile2.Machine), Compile2.Version,
+ formatSourceLanguage(Lang));
+ P.formatLine("frontend = {0}.{1}.{2}, backend = {3}.{4}.{5}",
+ Compile2.VersionFrontendMajor, Compile2.VersionFrontendMinor,
+ Compile2.VersionFrontendBuild, Compile2.VersionBackendMajor,
+ Compile2.VersionBackendMinor, Compile2.VersionBackendBuild);
+ P.formatLine("flags = {0}",
+ formatCompileSym2Flags(P.getIndentLevel() + 9, Compile2.Flags));
+ P.formatLine(
+ "extra strings = {0}",
+ typesetStringList(P.getIndentLevel() + 9 + 2, Compile2.ExtraStrings));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ Compile3Sym &Compile3) {
+ AutoIndent Indent(P, 7);
+ SourceLanguage Lang = static_cast<SourceLanguage>(
+ Compile3.Flags & CompileSym3Flags::SourceLanguageMask);
+ P.formatLine("machine = {0}, Ver = {1}, language = {2}",
+ formatMachineType(Compile3.Machine), Compile3.Version,
+ formatSourceLanguage(Lang));
+ P.formatLine("frontend = {0}.{1}.{2}.{3}, backend = {4}.{5}.{6}.{7}",
+ Compile3.VersionFrontendMajor, Compile3.VersionFrontendMinor,
+ Compile3.VersionFrontendBuild, Compile3.VersionFrontendQFE,
+ Compile3.VersionBackendMajor, Compile3.VersionBackendMinor,
+ Compile3.VersionBackendBuild, Compile3.VersionBackendQFE);
+ P.formatLine("flags = {0}",
+ formatCompileSym3Flags(P.getIndentLevel() + 9, Compile3.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ ConstantSym &Constant) {
+ P.format(" `{0}`", Constant.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, value = {1}", typeIndex(Constant.Type),
+ Constant.Value.toString(10));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DataSym &Data) {
+ P.format(" `{0}`", Data.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type),
+ formatSegmentOffset(Data.Segment, Data.DataOffset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(
+ CVSymbol &CVR, DefRangeFramePointerRelFullScopeSym &Def) {
+ P.format(" offset = {0}", Def.Offset);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ DefRangeFramePointerRelSym &Def) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("offset = {0}, range = {1}", Def.Offset, formatRange(Def.Range));
+ P.formatLine("gaps = {2}", Def.Offset,
+ formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ DefRangeRegisterRelSym &Def) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("register = {0}, base ptr = {1}, offset in parent = {2}, has "
+ "spilled udt = {3}",
+ uint16_t(Def.Hdr.Register), int32_t(Def.Hdr.BasePointerOffset),
+ Def.offsetInParent(), Def.hasSpilledUDTMember());
+ P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range),
+ formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("register = {0}, may have no name = {1}, range start = "
+ "{2}, length = {3}",
+ uint16_t(DefRangeRegister.Hdr.Register),
+ uint16_t(DefRangeRegister.Hdr.MayHaveNoName),
+ formatSegmentOffset(DefRangeRegister.Range.ISectStart,
+ DefRangeRegister.Range.OffsetStart),
+ DefRangeRegister.Range.Range);
+ P.formatLine("gaps = [{0}]",
+ formatGaps(P.getIndentLevel() + 9, DefRangeRegister.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ DefRangeSubfieldRegisterSym &Def) {
+ AutoIndent Indent(P, 7);
+ bool NoName = !!(Def.Hdr.MayHaveNoName == 0);
+ P.formatLine("register = {0}, may have no name = {1}, offset in parent = {2}",
+ uint16_t(Def.Hdr.Register), NoName,
+ uint32_t(Def.Hdr.OffsetInParent));
+ P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range),
+ formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ DefRangeSubfieldSym &Def) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("program = {0}, offset in parent = {1}, range = {2}",
+ Def.Program, Def.OffsetInParent, formatRange(Def.Range));
+ P.formatLine("gaps = {0}", formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DefRangeSym &Def) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("program = {0}, range = {1}", Def.Program,
+ formatRange(Def.Range));
+ P.formatLine("gaps = {0}", formatGaps(P.getIndentLevel() + 9, Def.Gaps));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameCookieSym &FC) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("code offset = {0}, Register = {1}, kind = {2}, flags = {3}",
+ FC.CodeOffset, FC.Register, formatCookieKind(FC.CookieKind),
+ FC.Flags);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameProcSym &FP) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("size = {0}, padding size = {1}, offset to padding = {2}",
+ FP.TotalFrameBytes, FP.PaddingFrameBytes, FP.OffsetToPadding);
+ P.formatLine("bytes of callee saved registers = {0}, exception handler addr "
+ "= {1}",
+ FP.BytesOfCalleeSavedRegisters,
+ formatSegmentOffset(FP.SectionIdOfExceptionHandler,
+ FP.OffsetOfExceptionHandler));
+ P.formatLine("flags = {0}",
+ formatFrameProcedureOptions(P.getIndentLevel() + 9, FP.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ HeapAllocationSiteSym &HAS) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, addr = {1} call size = {2}", typeIndex(HAS.Type),
+ formatSegmentOffset(HAS.Segment, HAS.CodeOffset),
+ HAS.CallInstructionSize);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, InlineSiteSym &IS) {
+ AutoIndent Indent(P, 7);
+ auto Bytes = makeArrayRef(IS.AnnotationData);
+ StringRef Annotations(reinterpret_cast<const char *>(Bytes.begin()),
+ Bytes.size());
+
+ P.formatLine("inlinee = {0}, parent = {1}, end = {2}", typeIndex(IS.Inlinee),
+ IS.Parent, IS.End);
+ P.formatLine("annotations = {0}", toHex(Annotations));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ RegisterSym &Register) {
+ P.format(" `{0}`", Register.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("register = {0}, type = {1}",
+ formatRegisterId(Register.Register), typeIndex(Register.Index));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ PublicSym32 &Public) {
+ P.format(" `{0}`", Public.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("flags = {0}, addr = {1}",
+ formatPublicSymFlags(P.getIndentLevel() + 9, Public.Flags),
+ formatSegmentOffset(Public.Segment, Public.Offset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcRefSym &PR) {
+ P.format(" `{0}`", PR.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("module = {0}, sum name = {1}, offset = {2}", PR.Module,
+ PR.SumName, PR.SymOffset);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) {
+ P.format(" `{0}` (addr = {1})", Label.Name,
+ formatSegmentOffset(Label.Segment, Label.CodeOffset));
+ AutoIndent Indent(P, 7);
+ P.formatLine("flags = {0}",
+ formatProcSymFlags(P.getIndentLevel() + 9, Label.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) {
+ P.format(" `{0}`", Local.Name);
+ AutoIndent Indent(P, 7);
+
+ std::string FlagStr =
+ formatLocalSymFlags(P.getIndentLevel() + 9, Local.Flags);
+ P.formatLine("type={0}, flags = {1}", typeIndex(Local.Type), FlagStr);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ ObjNameSym &ObjName) {
+ P.format(" sig={0}, `{1}`", ObjName.Signature, ObjName.Name);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) {
+ P.format(" `{0}`", Proc.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("parent = {0}, end = {1}, addr = {2}, code size = {3}",
+ Proc.Parent, Proc.End,
+ formatSegmentOffset(Proc.Segment, Proc.CodeOffset),
+ Proc.CodeSize);
+ // FIXME: It seems FunctionType is sometimes an id and sometimes a type.
+ P.formatLine("type = `{0}`, debug start = {1}, debug end = {2}, flags = {3}",
+ typeIndex(Proc.FunctionType), Proc.DbgStart, Proc.DbgEnd,
+ formatProcSymFlags(P.getIndentLevel() + 9, Proc.Flags));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ ScopeEndSym &ScopeEnd) {
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
+ AutoIndent Indent(P, 7);
+ for (const auto &I : Caller.Indices) {
+ P.formatLine("callee: {0}", typeIndex(I));
+ }
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ RegRelativeSym &RegRel) {
+ P.format(" `{0}`", RegRel.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, register = {1}, offset = {2}",
+ typeIndex(RegRel.Type), formatRegisterId(RegRel.Register),
+ RegRel.Offset);
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ ThreadLocalDataSym &Data) {
+ P.format(" `{0}`", Data.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type),
+ formatSegmentOffset(Data.Segment, Data.DataOffset));
+ return Error::success();
+}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) {
+ P.format(" `{0}`", UDT.Name);
+ AutoIndent Indent(P, 7);
+ P.formatLine("original type = {0}", UDT.Type);
+ return Error::success();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h
new file mode 100644
index 0000000..5e30959
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h
@@ -0,0 +1,48 @@
+//===- MinimalSymbolDumper.h ---------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_SYMBOL_DUMPER_H
+#define LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_SYMBOL_DUMPER_H
+
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
+
+namespace llvm {
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+class LinePrinter;
+
+class MinimalSymbolDumper : public codeview::SymbolVisitorCallbacks {
+public:
+ MinimalSymbolDumper(LinePrinter &P, bool RecordBytes,
+ codeview::LazyRandomTypeCollection &Types)
+ : P(P), Types(Types) {}
+
+ Error visitSymbolBegin(codeview::CVSymbol &Record) override;
+ Error visitSymbolBegin(codeview::CVSymbol &Record, uint32_t Offset) override;
+ Error visitSymbolEnd(codeview::CVSymbol &Record) override;
+
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ virtual Error visitKnownRecord(codeview::CVSymbol &CVR, \
+ codeview::Name &Record) override;
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+
+private:
+ std::string typeIndex(codeview::TypeIndex TI) const;
+
+ LinePrinter &P;
+ codeview::LazyRandomTypeCollection &Types;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif \ No newline at end of file
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
new file mode 100644
index 0000000..0079b9e
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -0,0 +1,553 @@
+//===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinimalTypeDumper.h"
+
+#include "FormatUtil.h"
+#include "LinePrinter.h"
+
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static StringRef getLeafTypeName(TypeLeafKind K) {
+ switch (K) {
+#define TYPE_RECORD(EnumName, value, name) \
+ case EnumName: \
+ return #EnumName;
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ default:
+ llvm_unreachable("Unknown type leaf kind!");
+ }
+ return "";
+}
+
+static std::string formatClassOptions(uint32_t IndentLevel,
+ ClassOptions Options) {
+ std::vector<std::string> Opts;
+ PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,
+ "has ctor / dtor");
+ PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,
+ "contains nested class");
+ PUSH_FLAG(ClassOptions, HasConversionOperator, Options,
+ "conversion operator");
+ PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
+ PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");
+ PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");
+ PUSH_FLAG(ClassOptions, Nested, Options, "is nested");
+ PUSH_FLAG(ClassOptions, HasOverloadedOperator, Options,
+ "overloaded operator");
+ PUSH_FLAG(ClassOptions, HasOverloadedAssignmentOperator, Options,
+ "overloaded operator=");
+ PUSH_FLAG(ClassOptions, Packed, Options, "packed");
+ PUSH_FLAG(ClassOptions, Scoped, Options, "scoped");
+ PUSH_FLAG(ClassOptions, Sealed, Options, "sealed");
+
+ return typesetItemList(Opts, 4, IndentLevel, " | ");
+}
+
+static std::string pointerOptions(PointerOptions Options) {
+ std::vector<std::string> Opts;
+ PUSH_FLAG(PointerOptions, Flat32, Options, "flat32");
+ PUSH_FLAG(PointerOptions, Volatile, Options, "volatile");
+ PUSH_FLAG(PointerOptions, Const, Options, "const");
+ PUSH_FLAG(PointerOptions, Unaligned, Options, "unaligned");
+ PUSH_FLAG(PointerOptions, Restrict, Options, "restrict");
+ PUSH_FLAG(PointerOptions, WinRTSmartPointer, Options, "winrt");
+ if (Opts.empty())
+ return "None";
+ return join(Opts, " | ");
+}
+
+static std::string modifierOptions(ModifierOptions Options) {
+ std::vector<std::string> Opts;
+ PUSH_FLAG(ModifierOptions, Const, Options, "const");
+ PUSH_FLAG(ModifierOptions, Volatile, Options, "volatile");
+ PUSH_FLAG(ModifierOptions, Unaligned, Options, "unaligned");
+ if (Opts.empty())
+ return "None";
+ return join(Opts, " | ");
+}
+
+static std::string formatCallingConvention(CallingConvention Convention) {
+ switch (Convention) {
+ RETURN_CASE(CallingConvention, AlphaCall, "alphacall");
+ RETURN_CASE(CallingConvention, AM33Call, "am33call");
+ RETURN_CASE(CallingConvention, ArmCall, "armcall");
+ RETURN_CASE(CallingConvention, ClrCall, "clrcall");
+ RETURN_CASE(CallingConvention, FarC, "far cdecl");
+ RETURN_CASE(CallingConvention, FarFast, "far fastcall");
+ RETURN_CASE(CallingConvention, FarPascal, "far pascal");
+ RETURN_CASE(CallingConvention, FarStdCall, "far stdcall");
+ RETURN_CASE(CallingConvention, FarSysCall, "far syscall");
+ RETURN_CASE(CallingConvention, Generic, "generic");
+ RETURN_CASE(CallingConvention, Inline, "inline");
+ RETURN_CASE(CallingConvention, M32RCall, "m32rcall");
+ RETURN_CASE(CallingConvention, MipsCall, "mipscall");
+ RETURN_CASE(CallingConvention, NearC, "cdecl");
+ RETURN_CASE(CallingConvention, NearFast, "fastcall");
+ RETURN_CASE(CallingConvention, NearPascal, "pascal");
+ RETURN_CASE(CallingConvention, NearStdCall, "stdcall");
+ RETURN_CASE(CallingConvention, NearSysCall, "near syscall");
+ RETURN_CASE(CallingConvention, NearVector, "vectorcall");
+ RETURN_CASE(CallingConvention, PpcCall, "ppccall");
+ RETURN_CASE(CallingConvention, SHCall, "shcall");
+ RETURN_CASE(CallingConvention, SH5Call, "sh5call");
+ RETURN_CASE(CallingConvention, ThisCall, "thiscall");
+ RETURN_CASE(CallingConvention, TriCall, "tricall");
+ }
+ return formatUnknownEnum(Convention);
+}
+
+static std::string formatPointerMode(PointerMode Mode) {
+ switch (Mode) {
+ RETURN_CASE(PointerMode, LValueReference, "ref");
+ RETURN_CASE(PointerMode, Pointer, "pointer");
+ RETURN_CASE(PointerMode, PointerToDataMember, "data member pointer");
+ RETURN_CASE(PointerMode, PointerToMemberFunction, "member fn pointer");
+ RETURN_CASE(PointerMode, RValueReference, "rvalue ref");
+ }
+ return formatUnknownEnum(Mode);
+}
+
+static std::string memberAccess(MemberAccess Access) {
+ switch (Access) {
+ RETURN_CASE(MemberAccess, None, "");
+ RETURN_CASE(MemberAccess, Private, "private");
+ RETURN_CASE(MemberAccess, Protected, "protected");
+ RETURN_CASE(MemberAccess, Public, "public");
+ }
+ return formatUnknownEnum(Access);
+}
+
+static std::string methodKind(MethodKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(MethodKind, Vanilla, "");
+ RETURN_CASE(MethodKind, Virtual, "virtual");
+ RETURN_CASE(MethodKind, Static, "static");
+ RETURN_CASE(MethodKind, Friend, "friend");
+ RETURN_CASE(MethodKind, IntroducingVirtual, "intro virtual");
+ RETURN_CASE(MethodKind, PureVirtual, "pure virtual");
+ RETURN_CASE(MethodKind, PureIntroducingVirtual, "pure intro virtual");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+static std::string pointerKind(PointerKind Kind) {
+ switch (Kind) {
+ RETURN_CASE(PointerKind, Near16, "ptr16");
+ RETURN_CASE(PointerKind, Far16, "far ptr16");
+ RETURN_CASE(PointerKind, Huge16, "huge ptr16");
+ RETURN_CASE(PointerKind, BasedOnSegment, "segment based");
+ RETURN_CASE(PointerKind, BasedOnValue, "value based");
+ RETURN_CASE(PointerKind, BasedOnSegmentValue, "segment value based");
+ RETURN_CASE(PointerKind, BasedOnAddress, "address based");
+ RETURN_CASE(PointerKind, BasedOnSegmentAddress, "segment address based");
+ RETURN_CASE(PointerKind, BasedOnType, "type based");
+ RETURN_CASE(PointerKind, BasedOnSelf, "self based");
+ RETURN_CASE(PointerKind, Near32, "ptr32");
+ RETURN_CASE(PointerKind, Far32, "far ptr32");
+ RETURN_CASE(PointerKind, Near64, "ptr64");
+ }
+ return formatUnknownEnum(Kind);
+}
+
+static std::string memberAttributes(const MemberAttributes &Attrs) {
+ std::vector<std::string> Opts;
+ std::string Access = memberAccess(Attrs.getAccess());
+ std::string Kind = methodKind(Attrs.getMethodKind());
+ if (!Access.empty())
+ Opts.push_back(Access);
+ if (!Kind.empty())
+ Opts.push_back(Kind);
+ MethodOptions Flags = Attrs.getFlags();
+ PUSH_FLAG(MethodOptions, Pseudo, Flags, "pseudo");
+ PUSH_FLAG(MethodOptions, NoInherit, Flags, "noinherit");
+ PUSH_FLAG(MethodOptions, NoConstruct, Flags, "noconstruct");
+ PUSH_FLAG(MethodOptions, CompilerGenerated, Flags, "compiler-generated");
+ PUSH_FLAG(MethodOptions, Sealed, Flags, "sealed");
+ return join(Opts, " ");
+}
+
+static std::string formatPointerAttrs(const PointerRecord &Record) {
+ PointerMode Mode = Record.getMode();
+ PointerOptions Opts = Record.getOptions();
+ PointerKind Kind = Record.getPointerKind();
+ return formatv("mode = {0}, opts = {1}, kind = {2}", formatPointerMode(Mode),
+ pointerOptions(Opts), pointerKind(Kind));
+}
+
+static std::string formatFunctionOptions(FunctionOptions Options) {
+ std::vector<std::string> Opts;
+
+ PUSH_FLAG(FunctionOptions, CxxReturnUdt, Options, "returns cxx udt");
+ PUSH_FLAG(FunctionOptions, ConstructorWithVirtualBases, Options,
+ "constructor with virtual bases");
+ PUSH_FLAG(FunctionOptions, Constructor, Options, "constructor");
+ if (Opts.empty())
+ return "None";
+ return join(Opts, " | ");
+}
+
+Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
+ // formatLine puts the newline at the beginning, so we use formatLine here
+ // to start a new line, and then individual visit methods use format to
+ // append to the existing line.
+ if (!Hashes) {
+ P.formatLine("{0} | {1} [size = {2}]",
+ fmt_align(Index, AlignStyle::Right, Width),
+ getLeafTypeName(Record.Type), Record.length());
+ } else {
+ std::string H;
+ if (Index.toArrayIndex() >= HashValues.size()) {
+ H = "(not present)";
+ } else {
+ uint32_t Hash = HashValues[Index.toArrayIndex()];
+ Expected<uint32_t> MaybeHash = hashTypeRecord(Record);
+ if (!MaybeHash)
+ return MaybeHash.takeError();
+ uint32_t OurHash = *MaybeHash;
+ OurHash %= NumHashBuckets;
+ if (Hash == OurHash)
+ H = "0x" + utohexstr(Hash);
+ else
+ H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash);
+ }
+ P.formatLine("{0} | {1} [size = {2}, hash = {3}]",
+ fmt_align(Index, AlignStyle::Right, Width),
+ getLeafTypeName(Record.Type), Record.length(), H);
+ }
+ P.Indent(Width + 3);
+ return Error::success();
+}
+Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
+ P.Unindent(Width + 3);
+ if (RecordBytes) {
+ AutoIndent Indent(P, 9);
+ P.formatBinary("Bytes", Record.RecordData, 0);
+ }
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
+ P.formatLine("- {0}", getLeafTypeName(Record.Kind));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
+ if (RecordBytes) {
+ AutoIndent Indent(P, 2);
+ P.formatBinary("Bytes", Record.Data, 0);
+ }
+ return Error::success();
+}
+
+StringRef MinimalTypeDumpVisitor::getTypeName(TypeIndex TI) const {
+ if (TI.isNoneType())
+ return "";
+ return Types.getTypeName(TI);
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ FieldListRecord &FieldList) {
+ if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
+ return EC;
+
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ StringIdRecord &String) {
+ P.format(" ID: {0}, String: {1}", String.getId(), String.getString());
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ArgListRecord &Args) {
+ auto Indices = Args.getIndices();
+ if (Indices.empty())
+ return Error::success();
+
+ auto Max = std::max_element(Indices.begin(), Indices.end());
+ uint32_t W = NumDigits(Max->getIndex()) + 2;
+
+ for (auto I : Indices)
+ P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
+ getTypeName(I));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ StringListRecord &Strings) {
+ auto Indices = Strings.getIndices();
+ if (Indices.empty())
+ return Error::success();
+
+ auto Max = std::max_element(Indices.begin(), Indices.end());
+ uint32_t W = NumDigits(Max->getIndex()) + 2;
+
+ for (auto I : Indices)
+ P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
+ getTypeName(I));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ClassRecord &Class) {
+ P.format(" `{0}`", Class.Name);
+ if (Class.hasUniqueName())
+ P.formatLine("unique name: `{0}`", Class.UniqueName);
+ P.formatLine("vtable: {0}, base list: {1}, field list: {2}",
+ Class.VTableShape, Class.DerivationList, Class.FieldList);
+ P.formatLine("options: {0}",
+ formatClassOptions(P.getIndentLevel(), Class.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UnionRecord &Union) {
+ P.format(" `{0}`", Union.Name);
+ if (Union.hasUniqueName())
+ P.formatLine("unique name: `{0}`", Union.UniqueName);
+ P.formatLine("field list: {0}", Union.FieldList);
+ P.formatLine("options: {0}",
+ formatClassOptions(P.getIndentLevel(), Union.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
+ P.format(" `{0}`", Enum.Name);
+ if (Enum.hasUniqueName())
+ P.formatLine("unique name: `{0}`", Enum.UniqueName);
+ P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,
+ Enum.UnderlyingType);
+ P.formatLine("options: {0}",
+ formatClassOptions(P.getIndentLevel(), Enum.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
+ if (AT.Name.empty()) {
+ P.formatLine("size: {0}, index type: {1}, element type: {2}", AT.Size,
+ AT.IndexType, AT.ElementType);
+ } else {
+ P.formatLine("name: {0}, size: {1}, index type: {2}, element type: {3}",
+ AT.Name, AT.Size, AT.IndexType, AT.ElementType);
+ }
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ VFTableRecord &VFT) {
+ P.formatLine("offset: {0}, complete class: {1}, overridden vftable: {2}",
+ VFT.VFPtrOffset, VFT.CompleteClass, VFT.OverriddenVFTable);
+ P.formatLine("method names: ");
+ if (!VFT.MethodNames.empty()) {
+ std::string Sep =
+ formatv("\n{0}",
+ fmt_repeat(' ', P.getIndentLevel() + strlen("method names: ")))
+ .str();
+ P.print(join(VFT.MethodNames, Sep));
+ }
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ MemberFuncIdRecord &Id) {
+ P.formatLine("name = {0}, type = {1}, class type = {2}", Id.Name,
+ Id.FunctionType, Id.ClassType);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ProcedureRecord &Proc) {
+ P.formatLine("return type = {0}, # args = {1}, param list = {2}",
+ Proc.ReturnType, Proc.ParameterCount, Proc.ArgumentList);
+ P.formatLine("calling conv = {0}, options = {1}",
+ formatCallingConvention(Proc.CallConv),
+ formatFunctionOptions(Proc.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ MemberFunctionRecord &MF) {
+ P.formatLine("return type = {0}, # args = {1}, param list = {2}",
+ MF.ReturnType, MF.ParameterCount, MF.ArgumentList);
+ P.formatLine("class type = {0}, this type = {1}, this adjust = {2}",
+ MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment);
+ P.formatLine("calling conv = {0}, options = {1}",
+ formatCallingConvention(MF.CallConv),
+ formatFunctionOptions(MF.Options));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ FuncIdRecord &Func) {
+ P.formatLine("name = {0}, type = {1}, parent scope = {2}", Func.Name,
+ Func.FunctionType, Func.ParentScope);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ TypeServer2Record &TS) {
+ P.formatLine("name = {0}, age = {1}, guid = {2}", TS.Name, TS.Age, TS.Guid);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ PointerRecord &Ptr) {
+ P.formatLine("referent = {0}, {1}", Ptr.ReferentType,
+ formatPointerAttrs(Ptr));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ ModifierRecord &Mod) {
+ P.formatLine("referent = {0}, modifiers = {1}", Mod.ModifiedType,
+ modifierOptions(Mod.Modifiers));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Shape) {
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtModSourceLineRecord &U) {
+ P.formatLine("udt = {0}, mod = {1}, file = {2}, line = {3}", U.UDT, U.Module,
+ U.SourceFile.getIndex(), U.LineNumber);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &U) {
+ P.formatLine("udt = {0}, file = {1}, line = {2}", U.UDT,
+ U.SourceFile.getIndex(), U.LineNumber);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ BitFieldRecord &BF) {
+ P.formatLine("type = {0}, bit offset = {1}, # bits = {2}", BF.Type,
+ BF.BitOffset, BF.BitSize);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(
+ CVType &CVR, MethodOverloadListRecord &Overloads) {
+ for (auto &M : Overloads.Methods)
+ P.formatLine("- Method [type = {0}, vftable offset = {1}, attrs = {2}]",
+ M.Type, M.VFTableOffset, memberAttributes(M.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ BuildInfoRecord &BI) {
+ auto Indices = BI.ArgIndices;
+ if (Indices.empty())
+ return Error::success();
+
+ auto Max = std::max_element(Indices.begin(), Indices.end());
+ uint32_t W = NumDigits(Max->getIndex()) + 2;
+
+ for (auto I : Indices)
+ P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
+ getTypeName(I));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) {
+ std::string Type = (R.Mode == LabelType::Far) ? "far" : "near";
+ P.format(" type = {0}", Type);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Nested) {
+ P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OneMethodRecord &Method) {
+ P.format(" [name = `{0}`]", Method.Name);
+ AutoIndent Indent(P);
+ P.formatLine("type = {0}, vftable offset = {1}, attrs = {2}", Method.Type,
+ Method.VFTableOffset, memberAttributes(Method.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OverloadedMethodRecord &Method) {
+ P.format(" [name = `{0}`, # overloads = {1}, overload list = {2}]",
+ Method.Name, Method.NumOverloads, Method.MethodList);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ DataMemberRecord &Field) {
+ P.format(" [name = `{0}`, Type = {1}, offset = {2}, attrs = {3}]", Field.Name,
+ Field.Type, Field.FieldOffset, memberAttributes(Field.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ StaticDataMemberRecord &Field) {
+ P.format(" [name = `{0}`, type = {1}, attrs = {2}]", Field.Name, Field.Type,
+ memberAttributes(Field.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ EnumeratorRecord &Enum) {
+ P.format(" [{0} = {1}]", Enum.Name,
+ Enum.Value.toString(10, Enum.Value.isSigned()));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ BaseClassRecord &Base) {
+ AutoIndent Indent(P);
+ P.formatLine("type = {0}, offset = {1}, attrs = {2}", Base.Type, Base.Offset,
+ memberAttributes(Base.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VirtualBaseClassRecord &Base) {
+ AutoIndent Indent(P);
+ P.formatLine(
+ "base = {0}, vbptr = {1}, vbptr offset = {2}, vtable index = {3}",
+ Base.BaseType, Base.VBPtrType, Base.VBPtrOffset, Base.VTableIndex);
+ P.formatLine("attrs = {0}", memberAttributes(Base.Attrs));
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ ListContinuationRecord &Cont) {
+ P.format(" continuation = {0}", Cont.ContinuationIndex);
+ return Error::success();
+}
+
+Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VFPtrRecord &VFP) {
+ P.format(" type = {0}", VFP.Type);
+ return Error::success();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h
new file mode 100644
index 0000000..4227688
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h
@@ -0,0 +1,63 @@
+//===- MinimalTypeDumper.h ------------------------------------ *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_TYPE_DUMPER_H
+#define LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_TYPE_DUMPER_H
+
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/BinaryStreamArray.h"
+
+namespace llvm {
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
+namespace pdb {
+class LinePrinter;
+
+class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
+public:
+ MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,
+ bool Hashes, codeview::LazyRandomTypeCollection &Types,
+ uint32_t NumHashBuckets,
+ FixedStreamArray<support::ulittle32_t> HashValues)
+ : P(P), Width(Width), RecordBytes(RecordBytes), Hashes(Hashes),
+ Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues) {}
+
+ Error visitTypeBegin(codeview::CVType &Record,
+ codeview::TypeIndex Index) override;
+ Error visitTypeEnd(codeview::CVType &Record) override;
+ Error visitMemberBegin(codeview::CVMemberRecord &Record) override;
+ Error visitMemberEnd(codeview::CVMemberRecord &Record) override;
+
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ Error visitKnownRecord(codeview::CVType &CVR, \
+ codeview::Name##Record &Record) override;
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ Error visitKnownMember(codeview::CVMemberRecord &CVR, \
+ codeview::Name##Record &Record) override;
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+
+private:
+ StringRef getTypeName(codeview::TypeIndex TI) const;
+
+ LinePrinter &P;
+ uint32_t Width;
+ bool RecordBytes = false;
+ bool Hashes = false;
+ codeview::LazyRandomTypeCollection &Types;
+ uint32_t NumHashBuckets;
+ FixedStreamArray<support::ulittle32_t> HashValues;
+};
+} // namespace pdb
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbdump/OutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/OutputStyle.h
index dfefc25..dfefc25 100644
--- a/contrib/llvm/tools/llvm-pdbdump/OutputStyle.h
+++ b/contrib/llvm/tools/llvm-pdbutil/OutputStyle.h
diff --git a/contrib/llvm/tools/llvm-pdbdump/PdbYaml.cpp b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp
index 34e0611..9c3beb5 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PdbYaml.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp
@@ -9,73 +9,35 @@
#include "PdbYaml.h"
-#include "YamlSerializationContext.h"
-#include "YamlSymbolDumper.h"
-#include "YamlTypeDumper.h"
-
+#include "llvm/ADT/StringExtras.h"
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
#include "llvm/DebugInfo/PDB/PDBTypes.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h"
+#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"
+#include "llvm/ObjectYAML/CodeViewYAMLTypes.h"
using namespace llvm;
using namespace llvm::pdb;
using namespace llvm::pdb::yaml;
using namespace llvm::yaml;
-LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t)
-LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo)
-LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbSymbolRecord)
-LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbTpiRecord)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::pdb::PdbRaw_FeatureSig)
namespace llvm {
namespace yaml {
-template <> struct ScalarTraits<llvm::pdb::PDB_UniqueId> {
- static void output(const llvm::pdb::PDB_UniqueId &S, void *,
- llvm::raw_ostream &OS) {
- OS << S;
- }
-
- static StringRef input(StringRef Scalar, void *Ctx,
- llvm::pdb::PDB_UniqueId &S) {
- if (Scalar.size() != 38)
- return "GUID strings are 38 characters long";
- if (Scalar[0] != '{' || Scalar[37] != '}')
- return "GUID is not enclosed in {}";
- if (Scalar[9] != '-' || Scalar[14] != '-' || Scalar[19] != '-' ||
- Scalar[24] != '-')
- return "GUID sections are not properly delineated with dashes";
-
- uint8_t *OutBuffer = S.Guid;
- for (auto Iter = Scalar.begin(); Iter != Scalar.end();) {
- if (*Iter == '-' || *Iter == '{' || *Iter == '}') {
- ++Iter;
- continue;
- }
- uint8_t Value = (llvm::hexDigitValue(*Iter) << 4);
- ++Iter;
- Value |= llvm::hexDigitValue(*Iter);
- ++Iter;
- *OutBuffer++ = Value;
- }
-
- return "";
- }
-
- static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); }
-};
-
template <> struct ScalarEnumerationTraits<llvm::pdb::PDB_Machine> {
static void enumeration(IO &io, llvm::pdb::PDB_Machine &Value) {
io.enumCase(Value, "Invalid", PDB_Machine::Invalid);
@@ -133,6 +95,16 @@ template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_TpiVer> {
io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80);
}
};
+
+template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_FeatureSig> {
+ static void enumeration(IO &io, PdbRaw_FeatureSig &Features) {
+ io.enumCase(Features, "MinimalDebugInfo",
+ PdbRaw_FeatureSig::MinimalDebugInfo);
+ io.enumCase(Features, "NoTypeMerge", PdbRaw_FeatureSig::NoTypeMerge);
+ io.enumCase(Features, "VC110", PdbRaw_FeatureSig::VC110);
+ io.enumCase(Features, "VC140", PdbRaw_FeatureSig::VC140);
+ }
+};
}
}
@@ -140,18 +112,19 @@ void MappingTraits<PdbObject>::mapping(IO &IO, PdbObject &Obj) {
IO.mapOptional("MSF", Obj.Headers);
IO.mapOptional("StreamSizes", Obj.StreamSizes);
IO.mapOptional("StreamMap", Obj.StreamMap);
+ IO.mapOptional("StringTable", Obj.StringTable);
IO.mapOptional("PdbStream", Obj.PdbStream);
IO.mapOptional("DbiStream", Obj.DbiStream);
- IO.mapOptionalWithContext("TpiStream", Obj.TpiStream, Obj.Allocator);
- IO.mapOptionalWithContext("IpiStream", Obj.IpiStream, Obj.Allocator);
+ IO.mapOptional("TpiStream", Obj.TpiStream);
+ IO.mapOptional("IpiStream", Obj.IpiStream);
}
void MappingTraits<MSFHeaders>::mapping(IO &IO, MSFHeaders &Obj) {
- IO.mapRequired("SuperBlock", Obj.SuperBlock);
- IO.mapRequired("NumDirectoryBlocks", Obj.NumDirectoryBlocks);
- IO.mapRequired("DirectoryBlocks", Obj.DirectoryBlocks);
- IO.mapRequired("NumStreams", Obj.NumStreams);
- IO.mapRequired("FileSize", Obj.FileSize);
+ IO.mapOptional("SuperBlock", Obj.SuperBlock);
+ IO.mapOptional("NumDirectoryBlocks", Obj.NumDirectoryBlocks);
+ IO.mapOptional("DirectoryBlocks", Obj.DirectoryBlocks);
+ IO.mapOptional("NumStreams", Obj.NumStreams);
+ IO.mapOptional("FileSize", Obj.FileSize);
}
void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) {
@@ -159,12 +132,13 @@ void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) {
::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
}
- IO.mapRequired("BlockSize", SB.BlockSize);
- IO.mapRequired("FreeBlockMap", SB.FreeBlockMapBlock);
- IO.mapRequired("NumBlocks", SB.NumBlocks);
- IO.mapRequired("NumDirectoryBytes", SB.NumDirectoryBytes);
- IO.mapRequired("Unknown1", SB.Unknown1);
- IO.mapRequired("BlockMapAddr", SB.BlockMapAddr);
+ using u32 = support::ulittle32_t;
+ IO.mapOptional("BlockSize", SB.BlockSize, u32(4096U));
+ IO.mapOptional("FreeBlockMap", SB.FreeBlockMapBlock, u32(0U));
+ IO.mapOptional("NumBlocks", SB.NumBlocks, u32(0U));
+ IO.mapOptional("NumDirectoryBytes", SB.NumDirectoryBytes, u32(0U));
+ IO.mapOptional("Unknown1", SB.Unknown1, u32(0U));
+ IO.mapOptional("BlockMapAddr", SB.BlockMapAddr, u32(0U));
}
void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) {
@@ -172,36 +146,28 @@ void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) {
}
void MappingTraits<PdbInfoStream>::mapping(IO &IO, PdbInfoStream &Obj) {
- IO.mapRequired("Age", Obj.Age);
- IO.mapRequired("Guid", Obj.Guid);
- IO.mapRequired("Signature", Obj.Signature);
- IO.mapRequired("Version", Obj.Version);
- IO.mapRequired("NamedStreams", Obj.NamedStreams);
+ IO.mapOptional("Age", Obj.Age, 1U);
+ IO.mapOptional("Guid", Obj.Guid);
+ IO.mapOptional("Signature", Obj.Signature, 0U);
+ IO.mapOptional("Features", Obj.Features);
+ IO.mapOptional("Version", Obj.Version, PdbImplVC70);
}
void MappingTraits<PdbDbiStream>::mapping(IO &IO, PdbDbiStream &Obj) {
- IO.mapRequired("VerHeader", Obj.VerHeader);
- IO.mapRequired("Age", Obj.Age);
- IO.mapRequired("BuildNumber", Obj.BuildNumber);
- IO.mapRequired("PdbDllVersion", Obj.PdbDllVersion);
- IO.mapRequired("PdbDllRbld", Obj.PdbDllRbld);
- IO.mapRequired("Flags", Obj.Flags);
- IO.mapRequired("MachineType", Obj.MachineType);
+ IO.mapOptional("VerHeader", Obj.VerHeader, PdbDbiV70);
+ IO.mapOptional("Age", Obj.Age, 1U);
+ IO.mapOptional("BuildNumber", Obj.BuildNumber, uint16_t(0U));
+ IO.mapOptional("PdbDllVersion", Obj.PdbDllVersion, 0U);
+ IO.mapOptional("PdbDllRbld", Obj.PdbDllRbld, uint16_t(0U));
+ IO.mapOptional("Flags", Obj.Flags, uint16_t(1U));
+ IO.mapOptional("MachineType", Obj.MachineType, PDB_Machine::x86);
IO.mapOptional("Modules", Obj.ModInfos);
}
-void MappingContextTraits<PdbTpiStream, BumpPtrAllocator>::mapping(
- IO &IO, pdb::yaml::PdbTpiStream &Obj, BumpPtrAllocator &Allocator) {
- // Create a single serialization context that will be passed through the
- // entire process of serializing / deserializing a Tpi Stream. This is
- // especially important when we are going from Pdb -> Yaml because we need
- // to maintain state in a TypeTableBuilder across mappings, and at the end of
- // the entire process, we need to have one TypeTableBuilder that has every
- // record.
- pdb::yaml::SerializationContext Context(IO, Allocator);
-
- IO.mapRequired("Version", Obj.Version);
- IO.mapRequired("Records", Obj.Records, Context);
+void MappingTraits<PdbTpiStream>::mapping(IO &IO,
+ pdb::yaml::PdbTpiStream &Obj) {
+ IO.mapOptional("Version", Obj.Version, PdbTpiV80);
+ IO.mapRequired("Records", Obj.Records);
}
void MappingTraits<NamedStreamMapping>::mapping(IO &IO,
@@ -210,61 +176,15 @@ void MappingTraits<NamedStreamMapping>::mapping(IO &IO,
IO.mapRequired("StreamNum", Obj.StreamNumber);
}
-void MappingTraits<PdbSymbolRecord>::mapping(IO &IO, PdbSymbolRecord &Obj) {
- codeview::SymbolVisitorCallbackPipeline Pipeline;
- codeview::SymbolDeserializer Deserializer(nullptr);
- codeview::yaml::YamlSymbolDumper Dumper(IO);
-
- if (IO.outputting()) {
- // For PDB to Yaml, deserialize into a high level record type, then dump it.
- Pipeline.addCallbackToPipeline(Deserializer);
- Pipeline.addCallbackToPipeline(Dumper);
- } else {
- return;
- }
-
- codeview::CVSymbolVisitor Visitor(Pipeline);
- consumeError(Visitor.visitSymbolRecord(Obj.Record));
-}
-
void MappingTraits<PdbModiStream>::mapping(IO &IO, PdbModiStream &Obj) {
- IO.mapRequired("Signature", Obj.Signature);
+ IO.mapOptional("Signature", Obj.Signature, 4U);
IO.mapRequired("Records", Obj.Symbols);
}
void MappingTraits<PdbDbiModuleInfo>::mapping(IO &IO, PdbDbiModuleInfo &Obj) {
IO.mapRequired("Module", Obj.Mod);
- IO.mapRequired("ObjFile", Obj.Obj);
+ IO.mapOptional("ObjFile", Obj.Obj, Obj.Mod);
IO.mapOptional("SourceFiles", Obj.SourceFiles);
+ IO.mapOptional("Subsections", Obj.Subsections);
IO.mapOptional("Modi", Obj.Modi);
}
-
-void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>::
- mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj,
- pdb::yaml::SerializationContext &Context) {
- codeview::TypeVisitorCallbackPipeline Pipeline;
- codeview::TypeDeserializer Deserializer;
- codeview::TypeSerializer Serializer(Context.Allocator);
- pdb::TpiHashUpdater Hasher;
-
- if (IO.outputting()) {
- // For PDB to Yaml, deserialize into a high level record type, then dump it.
- Pipeline.addCallbackToPipeline(Deserializer);
- Pipeline.addCallbackToPipeline(Context.Dumper);
- } else {
- // For Yaml to PDB, extract from the high level record type, then write it
- // to bytes.
-
- // This might be interpreted as a hack, but serializing FieldList
- // sub-records requires having access to the same serializer being used by
- // the FieldList itself.
- Context.ActiveSerializer = &Serializer;
- Pipeline.addCallbackToPipeline(Context.Dumper);
- Pipeline.addCallbackToPipeline(Serializer);
- Pipeline.addCallbackToPipeline(Hasher);
- }
-
- codeview::CVTypeVisitor Visitor(Pipeline);
- consumeError(Visitor.visitTypeRecord(Obj.Record));
- Context.ActiveSerializer = nullptr;
-}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h
new file mode 100644
index 0000000..91e0544
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h
@@ -0,0 +1,125 @@
+//===- PdbYAML.h ---------------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H
+
+#include "OutputStyle.h"
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"
+#include "llvm/ObjectYAML/CodeViewYAMLSymbols.h"
+#include "llvm/ObjectYAML/CodeViewYAMLTypes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/YAMLTraits.h"
+
+#include <vector>
+
+namespace llvm {
+namespace codeview {
+class DebugStringTableSubsection;
+}
+namespace pdb {
+
+namespace yaml {
+struct SerializationContext;
+
+struct MSFHeaders {
+ msf::SuperBlock SuperBlock;
+ uint32_t NumDirectoryBlocks = 0;
+ std::vector<uint32_t> DirectoryBlocks;
+ uint32_t NumStreams = 0;
+ uint32_t FileSize = 0;
+};
+
+struct StreamBlockList {
+ std::vector<uint32_t> Blocks;
+};
+
+struct NamedStreamMapping {
+ StringRef StreamName;
+ uint32_t StreamNumber;
+};
+
+struct PdbInfoStream {
+ PdbRaw_ImplVer Version = PdbImplVC70;
+ uint32_t Signature = 0;
+ uint32_t Age = 1;
+ codeview::GUID Guid;
+ std::vector<PdbRaw_FeatureSig> Features;
+ std::vector<NamedStreamMapping> NamedStreams;
+};
+
+struct PdbModiStream {
+ uint32_t Signature;
+ std::vector<CodeViewYAML::SymbolRecord> Symbols;
+};
+
+struct PdbDbiModuleInfo {
+ StringRef Obj;
+ StringRef Mod;
+ std::vector<StringRef> SourceFiles;
+ std::vector<CodeViewYAML::YAMLDebugSubsection> Subsections;
+ Optional<PdbModiStream> Modi;
+};
+
+struct PdbDbiStream {
+ PdbRaw_DbiVer VerHeader = PdbDbiV70;
+ uint32_t Age = 1;
+ uint16_t BuildNumber = 0;
+ uint32_t PdbDllVersion = 0;
+ uint16_t PdbDllRbld = 0;
+ uint16_t Flags = 1;
+ PDB_Machine MachineType = PDB_Machine::x86;
+
+ std::vector<PdbDbiModuleInfo> ModInfos;
+};
+
+struct PdbTpiStream {
+ PdbRaw_TpiVer Version = PdbTpiV80;
+ std::vector<CodeViewYAML::LeafRecord> Records;
+};
+
+struct PdbObject {
+ explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {}
+
+ Optional<MSFHeaders> Headers;
+ Optional<std::vector<uint32_t>> StreamSizes;
+ Optional<std::vector<StreamBlockList>> StreamMap;
+ Optional<PdbInfoStream> PdbStream;
+ Optional<PdbDbiStream> DbiStream;
+ Optional<PdbTpiStream> TpiStream;
+ Optional<PdbTpiStream> IpiStream;
+
+ Optional<std::vector<StringRef>> StringTable;
+
+ BumpPtrAllocator &Allocator;
+};
+}
+}
+}
+
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbObject)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::MSFHeaders)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(msf::SuperBlock)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::StreamBlockList)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbInfoStream)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiStream)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbTpiStream)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::NamedStreamMapping)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbModiStream)
+LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiModuleInfo)
+
+#endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp
index f866132..fcda312 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp
@@ -9,7 +9,7 @@
#include "PrettyBuiltinDumper.h"
#include "LinePrinter.h"
-#include "llvm-pdbdump.h"
+#include "llvm-pdbutil.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
@@ -20,6 +20,10 @@ BuiltinDumper::BuiltinDumper(LinePrinter &P)
: PDBSymDumper(false), Printer(P) {}
void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) {
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
WithColor(Printer, PDB_ColorItem::Type).get() << getTypeName(Symbol);
}
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h
index fb6b0b1..fb6b0b1 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
new file mode 100644
index 0000000..651cb8b
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
@@ -0,0 +1,108 @@
+//===- PrettyClassDefinitionDumper.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyClassDefinitionDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyClassLayoutGraphicalDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
+ assert(opts::pretty::ClassFormat !=
+ opts::pretty::ClassDefinitionFormat::None);
+
+ ClassLayout Layout(Class);
+ start(Layout);
+}
+
+void ClassDefinitionDumper::start(const ClassLayout &Layout) {
+ prettyPrintClassIntro(Layout);
+
+ PrettyClassLayoutGraphicalDumper Dumper(Printer, 1, 0);
+ DumpedAnything |= Dumper.start(Layout);
+
+ prettyPrintClassOutro(Layout);
+}
+
+void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) {
+ DumpedAnything = false;
+ Printer.NewLine();
+
+ uint32_t Size = Layout.getSize();
+ const PDBSymbolTypeUDT &Class = Layout.getClass();
+
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
+ WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size
+ << "]";
+ uint32_t BaseCount = Layout.bases().size();
+ if (BaseCount > 0) {
+ Printer.Indent();
+ char NextSeparator = ':';
+ for (auto BC : Layout.bases()) {
+ const auto &Base = BC->getBase();
+ if (Base.isIndirectVirtualBaseClass())
+ continue;
+
+ Printer.NewLine();
+ Printer << NextSeparator << " ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess();
+ if (BC->isVirtualBase())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
+
+ WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName();
+ NextSeparator = ',';
+ }
+
+ Printer.Unindent();
+ }
+
+ Printer << " {";
+ Printer.Indent();
+}
+
+void ClassDefinitionDumper::prettyPrintClassOutro(const ClassLayout &Layout) {
+ Printer.Unindent();
+ if (DumpedAnything)
+ Printer.NewLine();
+ Printer << "}";
+ Printer.NewLine();
+ if (Layout.deepPaddingSize() > 0) {
+ APFloat Pct(100.0 * (double)Layout.deepPaddingSize() /
+ (double)Layout.getSize());
+ SmallString<8> PctStr;
+ Pct.toString(PctStr, 4);
+ WithColor(Printer, PDB_ColorItem::Padding).get()
+ << "Total padding " << Layout.deepPaddingSize() << " bytes (" << PctStr
+ << "% of class size)";
+ Printer.NewLine();
+ APFloat Pct2(100.0 * (double)Layout.immediatePadding() /
+ (double)Layout.getSize());
+ PctStr.clear();
+ Pct2.toString(PctStr, 4);
+ WithColor(Printer, PDB_ColorItem::Padding).get()
+ << "Immediate padding " << Layout.immediatePadding() << " bytes ("
+ << PctStr << "% of class size)";
+ Printer.NewLine();
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
new file mode 100644
index 0000000..6569a1d
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
@@ -0,0 +1,47 @@
+//===- PrettyClassDefinitionDumper.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H
+
+#include "llvm/ADT/BitVector.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+
+#include <list>
+#include <memory>
+#include <unordered_map>
+
+namespace llvm {
+class BitVector;
+
+namespace pdb {
+
+class ClassLayout;
+class LinePrinter;
+
+class ClassDefinitionDumper : public PDBSymDumper {
+public:
+ ClassDefinitionDumper(LinePrinter &P);
+
+ void start(const PDBSymbolTypeUDT &Class);
+ void start(const ClassLayout &Class);
+
+private:
+ void prettyPrintClassIntro(const ClassLayout &Class);
+ void prettyPrintClassOutro(const ClassLayout &Class);
+
+ LinePrinter &Printer;
+ bool DumpedAnything = false;
+};
+}
+}
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
new file mode 100644
index 0000000..66c29fc
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
@@ -0,0 +1,216 @@
+//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyClassLayoutGraphicalDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyClassDefinitionDumper.h"
+#include "PrettyEnumDumper.h"
+#include "PrettyFunctionDumper.h"
+#include "PrettyTypedefDumper.h"
+#include "PrettyVariableDumper.h"
+#include "PrettyVariableDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
+ LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset)
+ : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel),
+ ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {}
+
+bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) {
+
+ if (RecursionLevel == 1 &&
+ opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) {
+ for (auto &Other : Layout.other_items())
+ Other->dump(*this);
+ for (auto &Func : Layout.funcs())
+ Func->dump(*this);
+ }
+
+ const BitVector &UseMap = Layout.usedBytes();
+ int NextPaddingByte = UseMap.find_first_unset();
+
+ for (auto &Item : Layout.layout_items()) {
+ // Calculate the absolute offset of the first byte of the next field.
+ uint32_t RelativeOffset = Item->getOffsetInParent();
+ CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset;
+
+ // Since there is storage there, it should be set! However, this might
+ // be an empty base, in which case it could extend outside the bounds of
+ // the parent class.
+ if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) {
+ assert(UseMap.test(RelativeOffset));
+
+ // If there is any remaining padding in this class, and the offset of the
+ // new item is after the padding, then we must have just jumped over some
+ // padding. Print a padding row and then look for where the next block
+ // of padding begins.
+ if ((NextPaddingByte >= 0) &&
+ (RelativeOffset > uint32_t(NextPaddingByte))) {
+ printPaddingRow(RelativeOffset - NextPaddingByte);
+ NextPaddingByte = UseMap.find_next_unset(RelativeOffset);
+ }
+ }
+
+ CurrentItem = Item;
+ if (Item->isVBPtr()) {
+ VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
+
+ VariableDumper VarDumper(Printer);
+ VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize());
+ } else {
+ if (auto Sym = Item->getSymbol())
+ Sym->dump(*this);
+ }
+
+ if (Item->getLayoutSize() > 0) {
+ uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1;
+ if (Prev < UseMap.size())
+ NextPaddingByte = UseMap.find_next_unset(Prev);
+ }
+ }
+
+ auto TailPadding = Layout.tailPadding();
+ if (TailPadding > 0) {
+ if (TailPadding != 1 || Layout.getSize() != 1) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get()
+ << "<padding> (" << TailPadding << " bytes)";
+ DumpedAnything = true;
+ }
+ }
+
+ return DumpedAnything;
+}
+
+void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) {
+ if (Amount == 0)
+ return;
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
+ << " bytes)";
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(
+ const PDBSymbolTypeBaseClass &Symbol) {
+ assert(CurrentItem != nullptr);
+
+ Printer.NewLine();
+ BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem);
+
+ std::string Label = "base";
+ if (Layout.isVirtualBase()) {
+ Label.insert(Label.begin(), 'v');
+ if (Layout.getBase().isIndirectVirtualBaseClass())
+ Label.insert(Label.begin(), 'i');
+ }
+ Printer << Label << " ";
+
+ uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize();
+
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size
+ << "] ";
+
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName();
+
+ if (shouldRecurse()) {
+ Printer.Indent();
+ uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
+ PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1,
+ ChildOffsetZero);
+ DumpedAnything |= BaseDumper.start(Layout);
+ Printer.Unindent();
+ }
+
+ DumpedAnything = true;
+}
+
+bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
+ uint32_t Limit = opts::pretty::ClassRecursionDepth;
+ if (Limit == 0)
+ return true;
+ return RecursionLevel < Limit;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {
+ VariableDumper VarDumper(Printer);
+ VarDumper.start(Symbol, ClassOffsetZero);
+
+ if (CurrentItem != nullptr) {
+ DataMemberLayoutItem &Layout =
+ static_cast<DataMemberLayoutItem &>(*CurrentItem);
+
+ if (Layout.hasUDTLayout() && shouldRecurse()) {
+ uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
+ Printer.Indent();
+ PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1,
+ ChildOffsetZero);
+ TypeDumper.start(Layout.getUDTLayout());
+ Printer.Unindent();
+ }
+ }
+
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
+ assert(CurrentItem != nullptr);
+
+ VariableDumper VarDumper(Printer);
+ VarDumper.start(Symbol, ClassOffsetZero);
+
+ DumpedAnything = true;
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ DumpedAnything = true;
+ Printer.NewLine();
+ EnumDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(
+ const PDBSymbolTypeTypedef &Symbol) {
+ DumpedAnything = true;
+ Printer.NewLine();
+ TypedefDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void PrettyClassLayoutGraphicalDumper::dump(
+ const PDBSymbolTypeBuiltin &Symbol) {}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
+
+void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+ if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
+ return;
+ if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
+ !Symbol.isIntroVirtualFunction())
+ return;
+
+ DumpedAnything = true;
+ Printer.NewLine();
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, FunctionDumper::PointerType::None);
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
new file mode 100644
index 0000000..f83f1a6
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
@@ -0,0 +1,58 @@
+//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
+
+#include "llvm/ADT/BitVector.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+namespace pdb {
+
+class UDTLayoutBase;
+class LayoutItemBase;
+class LinePrinter;
+
+class PrettyClassLayoutGraphicalDumper : public PDBSymDumper {
+public:
+ PrettyClassLayoutGraphicalDumper(LinePrinter &P, uint32_t RecurseLevel,
+ uint32_t InitialOffset);
+
+ bool start(const UDTLayoutBase &Layout);
+
+ // Layout based symbol types.
+ void dump(const PDBSymbolTypeBaseClass &Symbol) override;
+ void dump(const PDBSymbolData &Symbol) override;
+ void dump(const PDBSymbolTypeVTable &Symbol) override;
+
+ // Non layout-based symbol types.
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolFunc &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+ void dump(const PDBSymbolTypeBuiltin &Symbol) override;
+
+private:
+ bool shouldRecurse() const;
+ void printPaddingRow(uint32_t Amount);
+
+ LinePrinter &Printer;
+
+ LayoutItemBase *CurrentItem = nullptr;
+ uint32_t RecursionLevel = 0;
+ uint32_t ClassOffsetZero = 0;
+ uint32_t CurrentAbsoluteOffset = 0;
+ bool DumpedAnything = false;
+};
+}
+}
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyCompilandDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp
index 6257313..65e8bad 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyCompilandDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp
@@ -1,4 +1,4 @@
-//===- PrettyCompilandDumper.cpp - llvm-pdbdump compiland dumper -*- C++ *-===//
+//===- PrettyCompilandDumper.cpp - llvm-pdbutil compiland dumper -*- C++ *-===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,7 +11,7 @@
#include "LinePrinter.h"
#include "PrettyFunctionDumper.h"
-#include "llvm-pdbdump.h"
+#include "llvm-pdbutil.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
@@ -115,6 +115,8 @@ void CompilandDumper::start(const PDBSymbolCompiland &Symbol,
}
void CompilandDumper::dump(const PDBSymbolData &Symbol) {
+ if (!shouldDumpSymLevel(opts::pretty::SymLevel::Data))
+ return;
if (Printer.IsSymbolExcluded(Symbol.getName()))
return;
@@ -125,11 +127,17 @@ void CompilandDumper::dump(const PDBSymbolData &Symbol) {
Printer << "data: ";
WithColor(Printer, PDB_ColorItem::Address).get()
<< "[" << format_hex(Symbol.getVirtualAddress(), 10) << "]";
+
+ WithColor(Printer, PDB_ColorItem::Comment).get()
+ << " [sizeof = " << getTypeLength(Symbol) << "]";
+
break;
case PDB_LocType::Constant:
Printer << "constant: ";
WithColor(Printer, PDB_ColorItem::LiteralValue).get()
<< "[" << Symbol.getValue() << "]";
+ WithColor(Printer, PDB_ColorItem::Comment).get()
+ << " [sizeof = " << getTypeLength(Symbol) << "]";
break;
default:
Printer << "data(unexpected type=" << LocType << ")";
@@ -140,6 +148,8 @@ void CompilandDumper::dump(const PDBSymbolData &Symbol) {
}
void CompilandDumper::dump(const PDBSymbolFunc &Symbol) {
+ if (!shouldDumpSymLevel(opts::pretty::SymLevel::Functions))
+ return;
if (Symbol.getLength() == 0)
return;
if (Printer.IsSymbolExcluded(Symbol.getName()))
@@ -162,6 +172,8 @@ void CompilandDumper::dump(const PDBSymbolLabel &Symbol) {
}
void CompilandDumper::dump(const PDBSymbolThunk &Symbol) {
+ if (!shouldDumpSymLevel(opts::pretty::SymLevel::Thunks))
+ return;
if (Printer.IsSymbolExcluded(Symbol.getName()))
return;
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyCompilandDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h
index 2127e7d..cae196e 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyCompilandDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h
@@ -1,4 +1,4 @@
-//===- PrettyCompilandDumper.h - llvm-pdbdump compiland dumper -*- C++ --*-===//
+//===- PrettyCompilandDumper.h - llvm-pdbutil compiland dumper -*- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyEnumDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp
index 965ca1b..7aff5b9 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyEnumDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp
@@ -11,7 +11,7 @@
#include "LinePrinter.h"
#include "PrettyBuiltinDumper.h"
-#include "llvm-pdbdump.h"
+#include "llvm-pdbutil.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyEnumDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h
index c6e65a6..c6e65a6 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyEnumDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp
index fc40d90..fc40d90 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h
index 6a00986..6a00986 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp
index 2f6ca89..06d7241 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp
@@ -10,7 +10,7 @@
#include "PrettyFunctionDumper.h"
#include "LinePrinter.h"
#include "PrettyBuiltinDumper.h"
-#include "llvm-pdbdump.h"
+#include "llvm-pdbutil.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
@@ -26,6 +26,7 @@
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -119,14 +120,19 @@ void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) {
WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10);
if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>()) {
uint64_t Prologue = DebugStart->getVirtualAddress() - FuncStart;
- WithColor(Printer, PDB_ColorItem::Offset).get() << "+" << Prologue;
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << formatv("+{0,2}", Prologue);
}
Printer << " - ";
WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10);
if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>()) {
uint64_t Epilogue = FuncEnd - DebugEnd->getVirtualAddress();
- WithColor(Printer, PDB_ColorItem::Offset).get() << "-" << Epilogue;
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << formatv("-{0,2}", Epilogue);
}
+
+ WithColor(Printer, PDB_ColorItem::Comment).get()
+ << formatv(" | sizeof={0,3}", Symbol.getLength());
Printer << "] (";
if (Symbol.hasFramePointer()) {
@@ -195,10 +201,7 @@ void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) {
}
void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) {
- uint32_t ElementTypeId = Symbol.getTypeId();
- auto ElementType = Symbol.getSession().getSymbolById(ElementTypeId);
- if (!ElementType)
- return;
+ auto ElementType = Symbol.getElementType();
ElementType->dump(*this);
Printer << "[";
@@ -232,12 +235,11 @@ void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
}
void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) {
- uint32_t PointeeId = Symbol.getTypeId();
- auto PointeeType = Symbol.getSession().getSymbolById(PointeeId);
+ auto PointeeType = Symbol.getPointeeType();
if (!PointeeType)
return;
- if (auto FuncSig = dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
FunctionDumper NestedDumper(Printer);
PointerType Pointer =
Symbol.isReference() ? PointerType::Reference : PointerType::Pointer;
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h
index 1a6f543..1a6f543 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp
new file mode 100644
index 0000000..0f60863
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp
@@ -0,0 +1,255 @@
+//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyTypeDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyBuiltinDumper.h"
+#include "PrettyClassDefinitionDumper.h"
+#include "PrettyEnumDumper.h"
+#include "PrettyTypedefDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+using LayoutPtr = std::unique_ptr<ClassLayout>;
+
+typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
+
+static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->getName() < S2->getName();
+}
+
+static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->getSize() < S2->getSize();
+}
+
+static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->deepPaddingSize() < S2->deepPaddingSize();
+}
+
+static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) {
+ double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize();
+ double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize();
+ return Pct1 < Pct2;
+}
+
+static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
+ return S1->immediatePadding() < S2->immediatePadding();
+}
+
+static bool ComparePaddingPctImmediate(const LayoutPtr &S1,
+ const LayoutPtr &S2) {
+ double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize();
+ double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize();
+ return Pct1 < Pct2;
+}
+
+static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
+ switch (Mode) {
+ case opts::pretty::ClassSortMode::Name:
+ return CompareNames;
+ case opts::pretty::ClassSortMode::Size:
+ return CompareSizes;
+ case opts::pretty::ClassSortMode::Padding:
+ return ComparePadding;
+ case opts::pretty::ClassSortMode::PaddingPct:
+ return ComparePaddingPct;
+ case opts::pretty::ClassSortMode::PaddingImmediate:
+ return ComparePaddingImmediate;
+ case opts::pretty::ClassSortMode::PaddingPctImmediate:
+ return ComparePaddingPctImmediate;
+ default:
+ return nullptr;
+ }
+}
+
+template <typename Enumerator>
+static std::vector<std::unique_ptr<ClassLayout>>
+filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
+ uint32_t UnfilteredCount) {
+ std::vector<std::unique_ptr<ClassLayout>> Filtered;
+
+ Filtered.reserve(UnfilteredCount);
+ CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
+
+ if (UnfilteredCount > 10000) {
+ errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
+ errs().flush();
+ }
+ uint32_t Examined = 0;
+ uint32_t Discarded = 0;
+ while (auto Class = E.getNext()) {
+ ++Examined;
+ if (Examined % 10000 == 0) {
+ errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
+ Examined, UnfilteredCount, Discarded);
+ errs().flush();
+ }
+
+ if (Class->getUnmodifiedTypeId() != 0) {
+ ++Discarded;
+ continue;
+ }
+
+ if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
+ ++Discarded;
+ continue;
+ }
+
+ auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
+ if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
+ ++Discarded;
+ continue;
+ }
+ if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) {
+ ++Discarded;
+ continue;
+ }
+
+ Filtered.push_back(std::move(Layout));
+ }
+
+ if (Comp)
+ std::sort(Filtered.begin(), Filtered.end(), Comp);
+ return Filtered;
+}
+
+TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
+
+void TypeDumper::start(const PDBSymbolExe &Exe) {
+ auto Children = Exe.findAllChildren();
+ if (opts::pretty::Enums) {
+ if (auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>()) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
+ Printer << ": (" << Enums->getChildCount() << " items)";
+ Printer.Indent();
+ while (auto Enum = Enums->getNext())
+ Enum->dump(*this);
+ Printer.Unindent();
+ }
+ }
+
+ if (opts::pretty::Typedefs) {
+ if (auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>()) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
+ Printer << ": (" << Typedefs->getChildCount() << " items)";
+ Printer.Indent();
+ while (auto Typedef = Typedefs->getNext())
+ Typedef->dump(*this);
+ Printer.Unindent();
+ }
+ }
+
+ if (opts::pretty::Classes) {
+ if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
+ uint32_t All = Classes->getChildCount();
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
+
+ bool Precompute = false;
+ Precompute =
+ (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
+
+ // If we're using no sort mode, then we can start getting immediate output
+ // from the tool by just filtering as we go, rather than processing
+ // everything up front so that we can sort it. This makes the tool more
+ // responsive. So only precompute the filtered/sorted set of classes if
+ // necessary due to the specified options.
+ std::vector<LayoutPtr> Filtered;
+ uint32_t Shown = All;
+ if (Precompute) {
+ Filtered = filterAndSortClassDefs(Printer, *Classes, All);
+
+ Shown = Filtered.size();
+ }
+
+ Printer << ": (Showing " << Shown << " items";
+ if (Shown < All)
+ Printer << ", " << (All - Shown) << " filtered";
+ Printer << ")";
+ Printer.Indent();
+
+ // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
+ // the DIA enumerator and filter on the fly.
+ if (Precompute) {
+ for (auto &Class : Filtered)
+ dumpClassLayout(*Class);
+ } else {
+ while (auto Class = Classes->getNext()) {
+ if (Class->getUnmodifiedTypeId() != 0)
+ continue;
+
+ if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
+ continue;
+
+ auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
+ if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
+ continue;
+
+ dumpClassLayout(*Layout);
+ }
+ }
+
+ Printer.Unindent();
+ }
+ }
+}
+
+void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ assert(opts::pretty::Enums);
+
+ if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
+ return;
+ // Dump member enums when dumping their class definition.
+ if (nullptr != Symbol.getClassParent())
+ return;
+
+ Printer.NewLine();
+ EnumDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ assert(opts::pretty::Typedefs);
+
+ if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
+ return;
+
+ Printer.NewLine();
+ TypedefDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
+ assert(opts::pretty::Classes);
+
+ if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName();
+ } else {
+ ClassDefinitionDumper Dumper(Printer);
+ Dumper.start(Class);
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyTypeDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h
index f9d8304..68a2f02 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyTypeDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h
@@ -15,6 +15,7 @@
namespace llvm {
namespace pdb {
class LinePrinter;
+class ClassLayout;
class TypeDumper : public PDBSymDumper {
public:
@@ -24,7 +25,8 @@ public:
void dump(const PDBSymbolTypeEnum &Symbol) override;
void dump(const PDBSymbolTypeTypedef &Symbol) override;
- void dump(const PDBSymbolTypeUDT &Symbol) override;
+
+ void dumpClassLayout(const ClassLayout &Class);
private:
LinePrinter &Printer;
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp
index c458755..2266e6e 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp
@@ -12,7 +12,7 @@
#include "LinePrinter.h"
#include "PrettyBuiltinDumper.h"
#include "PrettyFunctionDumper.h"
-#include "llvm-pdbdump.h"
+#include "llvm-pdbutil.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
@@ -53,11 +53,8 @@ void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) {
WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
if (Symbol.isVolatileType())
WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
- uint32_t PointeeId = Symbol.getTypeId();
- auto PointeeType = Symbol.getSession().getSymbolById(PointeeId);
- if (!PointeeType)
- return;
- if (auto FuncSig = dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
+ auto PointeeType = Symbol.getPointeeType();
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer;
if (Symbol.isReference())
Pointer = FunctionDumper::PointerType::Reference;
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h
index 34c1396..133bbfb 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h
@@ -1,4 +1,4 @@
-//===- PrettyTypedefDumper.h - llvm-pdbdump typedef dumper ---*- C++ ----*-===//
+//===- PrettyTypedefDumper.h - llvm-pdbutil typedef dumper ---*- C++ ----*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp
new file mode 100644
index 0000000..4884fc8
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp
@@ -0,0 +1,220 @@
+//===- PrettyVariableDumper.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrettyVariableDumper.h"
+
+#include "LinePrinter.h"
+#include "PrettyBuiltinDumper.h"
+#include "PrettyFunctionDumper.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+VariableDumper::VariableDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void VariableDumper::start(const PDBSymbolData &Var, uint32_t Offset) {
+ if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
+ return;
+ if (Printer.IsSymbolExcluded(Var.getName()))
+ return;
+
+ auto VarType = Var.getType();
+
+ uint64_t Length = VarType->getRawSymbol().getLength();
+
+ switch (auto LocType = Var.getLocationType()) {
+ case PDB_LocType::Static:
+ Printer.NewLine();
+ Printer << "data [";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << format_hex(Var.getVirtualAddress(), 10);
+ Printer << ", sizeof=" << Length << "] ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "static ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ break;
+ case PDB_LocType::Constant:
+ if (isa<PDBSymbolTypeEnum>(*VarType))
+ break;
+ Printer.NewLine();
+ Printer << "data [sizeof=" << Length << "] ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ Printer << " = ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue();
+ break;
+ case PDB_LocType::ThisRel:
+ Printer.NewLine();
+ Printer << "data ";
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << Length << "] ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ break;
+ case PDB_LocType::BitField:
+ Printer.NewLine();
+ Printer << "data ";
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << Length << "] ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ Printer << " : ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength();
+ break;
+ default:
+ Printer.NewLine();
+ Printer << "data [sizeof=" << Length << "] ";
+ Printer << "unknown(" << LocType << ") ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName();
+ break;
+ }
+}
+
+void VariableDumper::startVbptr(uint32_t Offset, uint32_t Size) {
+ Printer.NewLine();
+ Printer << "vbptr ";
+
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Offset, 4) << " [sizeof=" << Size << "] ";
+}
+
+void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) {
+ Printer.NewLine();
+ Printer << "vfptr ";
+ auto VTableType = cast<PDBSymbolTypePointer>(Var.getType());
+ uint32_t PointerSize = VTableType->getLength();
+
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << PointerSize << "] ";
+}
+
+void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) {
+ auto ElementType = Symbol.getElementType();
+ assert(ElementType);
+ if (!ElementType)
+ return;
+ ElementType->dump(*this);
+}
+
+void VariableDumper::dumpRight(const PDBSymbolTypeArray &Symbol) {
+ auto ElementType = Symbol.getElementType();
+ assert(ElementType);
+ if (!ElementType)
+ return;
+ Printer << '[' << Symbol.getCount() << ']';
+ ElementType->dumpRight(*this);
+}
+
+void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
+ auto ReturnType = Symbol.getReturnType();
+ ReturnType->dump(*this);
+ Printer << " ";
+
+ uint32_t ClassParentId = Symbol.getClassParentId();
+ auto ClassParent =
+ Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>(
+ ClassParentId);
+
+ if (ClassParent) {
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << ClassParent->getName();
+ Printer << "::";
+ }
+}
+
+void VariableDumper::dumpRight(const PDBSymbolTypeFunctionSig &Symbol) {
+ Printer << "(";
+ if (auto Arguments = Symbol.getArguments()) {
+ uint32_t Index = 0;
+ while (auto Arg = Arguments->getNext()) {
+ Arg->dump(*this);
+ if (++Index < Arguments->getChildCount())
+ Printer << ", ";
+ }
+ }
+ Printer << ")";
+
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
+}
+
+void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) {
+ auto PointeeType = Symbol.getPointeeType();
+ if (!PointeeType)
+ return;
+ PointeeType->dump(*this);
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
+ // A hack to get the calling convention in the right spot.
+ Printer << " (";
+ PDB_CallingConv CC = FuncSig->getCallingConvention();
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
+ } else if (isa<PDBSymbolTypeArray>(PointeeType)) {
+ Printer << " (";
+ }
+ Printer << (Symbol.isReference() ? "&" : "*");
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile ";
+}
+
+void VariableDumper::dumpRight(const PDBSymbolTypePointer &Symbol) {
+ auto PointeeType = Symbol.getPointeeType();
+ assert(PointeeType);
+ if (!PointeeType)
+ return;
+ if (isa<PDBSymbolTypeFunctionSig>(PointeeType) ||
+ isa<PDBSymbolTypeArray>(PointeeType)) {
+ Printer << ")";
+ }
+ PointeeType->dumpRight(*this);
+}
+
+void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type,
+ StringRef Name) {
+ Type.dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
+ Type.dumpRight(*this);
+}
diff --git a/contrib/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h
index a122bb8..cacf1ce 100644
--- a/contrib/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h
@@ -24,8 +24,11 @@ class VariableDumper : public PDBSymDumper {
public:
VariableDumper(LinePrinter &P);
- void start(const PDBSymbolData &Var);
+ void start(const PDBSymbolData &Var, uint32_t Offset = 0);
+ void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0);
+ void startVbptr(uint32_t Offset, uint32_t Size);
+ void dump(const PDBSymbolTypeArray &Symbol) override;
void dump(const PDBSymbolTypeBuiltin &Symbol) override;
void dump(const PDBSymbolTypeEnum &Symbol) override;
void dump(const PDBSymbolTypeFunctionSig &Symbol) override;
@@ -33,9 +36,12 @@ public:
void dump(const PDBSymbolTypeTypedef &Symbol) override;
void dump(const PDBSymbolTypeUDT &Symbol) override;
+ void dumpRight(const PDBSymbolTypeArray &Symbol) override;
+ void dumpRight(const PDBSymbolTypeFunctionSig &Symbol) override;
+ void dumpRight(const PDBSymbolTypePointer &Symbol) override;
+
private:
void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name);
- bool tryDumpFunctionPointer(const PDBSymbol &Type, StringRef Name);
LinePrinter &Printer;
};
diff --git a/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp
new file mode 100644
index 0000000..4d35200
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp
@@ -0,0 +1,152 @@
+//===- StreamUtil.cpp - PDB stream utilities --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StreamUtil.h"
+#include "FormatUtil.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void llvm::pdb::discoverStreamPurposes(
+ PDBFile &File,
+ SmallVectorImpl<std::pair<StreamPurpose, std::string>> &Purposes) {
+ // It's OK if we fail to load some of these streams, we still attempt to print
+ // what we can.
+ auto Dbi = File.getPDBDbiStream();
+ auto Tpi = File.getPDBTpiStream();
+ auto Ipi = File.getPDBIpiStream();
+ auto Info = File.getPDBInfoStream();
+
+ uint32_t StreamCount = File.getNumStreams();
+ DenseMap<uint16_t, DbiModuleDescriptor> ModStreams;
+ DenseMap<uint16_t, std::string> NamedStreams;
+
+ if (Dbi) {
+ const DbiModuleList &Modules = Dbi->modules();
+ for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
+ DbiModuleDescriptor Descriptor = Modules.getModuleDescriptor(I);
+ uint16_t SN = Descriptor.getModuleStreamIndex();
+ if (SN != kInvalidStreamIndex)
+ ModStreams[SN] = Descriptor;
+ }
+ }
+ if (Info) {
+ for (auto &NSE : Info->named_streams()) {
+ if (NSE.second != kInvalidStreamIndex)
+ NamedStreams[NSE.second] = NSE.first();
+ }
+ }
+
+ Purposes.resize(StreamCount);
+ for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
+ std::pair<StreamPurpose, std::string> Value;
+ if (StreamIdx == OldMSFDirectory)
+ Value = std::make_pair(StreamPurpose::Other, "Old MSF Directory");
+ else if (StreamIdx == StreamPDB)
+ Value = std::make_pair(StreamPurpose::Other, "PDB Stream");
+ else if (StreamIdx == StreamDBI)
+ Value = std::make_pair(StreamPurpose::Other, "DBI Stream");
+ else if (StreamIdx == StreamTPI)
+ Value = std::make_pair(StreamPurpose::Other, "TPI Stream");
+ else if (StreamIdx == StreamIPI)
+ Value = std::make_pair(StreamPurpose::Other, "IPI Stream");
+ else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "Global Symbol Hash");
+ else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "Public Symbol Hash");
+ else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "Public Symbol Records");
+ else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "TPI Hash");
+ else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
+ Value = std::make_pair(StreamPurpose::Other, "TPI Aux Hash");
+ else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
+ Value = std::make_pair(StreamPurpose::Other, "IPI Hash");
+ else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
+ Value = std::make_pair(StreamPurpose::Other, "IPI Aux Hash");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
+ Value = std::make_pair(StreamPurpose::Other, "Exception Data");
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
+ Value = std::make_pair(StreamPurpose::Other, "Fixup Data");
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
+ Value = std::make_pair(StreamPurpose::Other, "FPO Data");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
+ Value = std::make_pair(StreamPurpose::Other, "New FPO Data");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
+ Value = std::make_pair(StreamPurpose::Other, "Omap From Source Data");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
+ Value = std::make_pair(StreamPurpose::Other, "Omap To Source Data");
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
+ Value = std::make_pair(StreamPurpose::Other, "Pdata");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
+ Value = std::make_pair(StreamPurpose::Other, "Section Header Data");
+ else if (Dbi &&
+ StreamIdx ==
+ Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
+ Value =
+ std::make_pair(StreamPurpose::Other, "Section Header Original Data");
+ else if (Dbi &&
+ StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
+ Value = std::make_pair(StreamPurpose::Other, "Token Rid Data");
+ else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
+ Value = std::make_pair(StreamPurpose::Other, "Xdata");
+ else {
+ auto ModIter = ModStreams.find(StreamIdx);
+ auto NSIter = NamedStreams.find(StreamIdx);
+ if (ModIter != ModStreams.end()) {
+ Value = std::make_pair(StreamPurpose::ModuleStream,
+ ModIter->second.getModuleName());
+ } else if (NSIter != NamedStreams.end()) {
+ Value = std::make_pair(StreamPurpose::NamedStream, NSIter->second);
+ } else {
+ Value = std::make_pair(StreamPurpose::Other, "???");
+ }
+ }
+ Purposes[StreamIdx] = Value;
+ }
+
+ // Consume errors from missing streams.
+ if (!Dbi)
+ consumeError(Dbi.takeError());
+ if (!Tpi)
+ consumeError(Tpi.takeError());
+ if (!Ipi)
+ consumeError(Ipi.takeError());
+ if (!Info)
+ consumeError(Info.takeError());
+}
+
+void llvm::pdb::discoverStreamPurposes(PDBFile &File,
+ SmallVectorImpl<std::string> &Purposes) {
+ SmallVector<std::pair<StreamPurpose, std::string>, 24> SP;
+ discoverStreamPurposes(File, SP);
+ Purposes.reserve(SP.size());
+ for (const auto &P : SP) {
+ if (P.first == StreamPurpose::NamedStream)
+ Purposes.push_back(formatv("Named Stream \"{0}\"", P.second));
+ else if (P.first == StreamPurpose::ModuleStream)
+ Purposes.push_back(formatv("Module \"{0}\"", P.second));
+ else
+ Purposes.push_back(P.second);
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h
new file mode 100644
index 0000000..f49c0a0
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h
@@ -0,0 +1,30 @@
+//===- Streamutil.h - PDB stream utilities ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H
+#define LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <string>
+
+namespace llvm {
+namespace pdb {
+class PDBFile;
+enum class StreamPurpose { NamedStream, ModuleStream, Other };
+
+void discoverStreamPurposes(PDBFile &File,
+ SmallVectorImpl<std::string> &Purposes);
+void discoverStreamPurposes(
+ PDBFile &File,
+ SmallVectorImpl<std::pair<StreamPurpose, std::string>> &Purposes);
+}
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp
new file mode 100644
index 0000000..ae3138e
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp
@@ -0,0 +1,333 @@
+//===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "YAMLOutputStyle.h"
+
+#include "PdbYaml.h"
+#include "llvm-pdbutil.h"
+
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
+#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static bool checkModuleSubsection(opts::ModuleSubsection MS) {
+ return any_of(opts::pdb2yaml::DumpModuleSubsections,
+ [=](opts::ModuleSubsection M) {
+ return M == MS || M == opts::ModuleSubsection::All;
+ });
+}
+
+YAMLOutputStyle::YAMLOutputStyle(PDBFile &File)
+ : File(File), Out(outs()), Obj(File.getAllocator()) {
+ Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal);
+}
+
+Error YAMLOutputStyle::dump() {
+ if (opts::pdb2yaml::StreamDirectory)
+ opts::pdb2yaml::StreamMetadata = true;
+
+ if (auto EC = dumpFileHeaders())
+ return EC;
+
+ if (auto EC = dumpStreamMetadata())
+ return EC;
+
+ if (auto EC = dumpStreamDirectory())
+ return EC;
+
+ if (auto EC = dumpStringTable())
+ return EC;
+
+ if (auto EC = dumpPDBStream())
+ return EC;
+
+ if (auto EC = dumpDbiStream())
+ return EC;
+
+ if (auto EC = dumpTpiStream())
+ return EC;
+
+ if (auto EC = dumpIpiStream())
+ return EC;
+
+ flush();
+ return Error::success();
+}
+
+
+Error YAMLOutputStyle::dumpFileHeaders() {
+ if (opts::pdb2yaml::NoFileHeaders)
+ return Error::success();
+
+ yaml::MSFHeaders Headers;
+ Obj.Headers.emplace();
+ Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount();
+ Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex();
+ Obj.Headers->SuperBlock.BlockSize = File.getBlockSize();
+ auto Blocks = File.getDirectoryBlockArray();
+ Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end());
+ Obj.Headers->NumDirectoryBlocks = File.getNumDirectoryBlocks();
+ Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes();
+ Obj.Headers->NumStreams =
+ opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0;
+ Obj.Headers->SuperBlock.FreeBlockMapBlock = File.getFreeBlockMapBlock();
+ Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1();
+ Obj.Headers->FileSize = File.getFileSize();
+
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpStringTable() {
+ bool RequiresStringTable = opts::pdb2yaml::DumpModuleFiles ||
+ !opts::pdb2yaml::DumpModuleSubsections.empty();
+ bool RequestedStringTable = opts::pdb2yaml::StringTable;
+ if (!RequiresStringTable && !RequestedStringTable)
+ return Error::success();
+
+ auto ExpectedST = File.getStringTable();
+ if (!ExpectedST)
+ return ExpectedST.takeError();
+
+ Obj.StringTable.emplace();
+ const auto &ST = ExpectedST.get();
+ for (auto ID : ST.name_ids()) {
+ auto S = ST.getStringForID(ID);
+ if (!S)
+ return S.takeError();
+ if (S->empty())
+ continue;
+ Obj.StringTable->push_back(*S);
+ }
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpStreamMetadata() {
+ if (!opts::pdb2yaml::StreamMetadata)
+ return Error::success();
+
+ Obj.StreamSizes.emplace();
+ Obj.StreamSizes->assign(File.getStreamSizes().begin(),
+ File.getStreamSizes().end());
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpStreamDirectory() {
+ if (!opts::pdb2yaml::StreamDirectory)
+ return Error::success();
+
+ auto StreamMap = File.getStreamMap();
+ Obj.StreamMap.emplace();
+ for (auto &Stream : StreamMap) {
+ pdb::yaml::StreamBlockList BlockList;
+ BlockList.Blocks.assign(Stream.begin(), Stream.end());
+ Obj.StreamMap->push_back(BlockList);
+ }
+
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpPDBStream() {
+ if (!opts::pdb2yaml::PdbStream)
+ return Error::success();
+
+ auto IS = File.getPDBInfoStream();
+ if (!IS)
+ return IS.takeError();
+
+ auto &InfoS = IS.get();
+ Obj.PdbStream.emplace();
+ Obj.PdbStream->Age = InfoS.getAge();
+ Obj.PdbStream->Guid = InfoS.getGuid();
+ Obj.PdbStream->Signature = InfoS.getSignature();
+ Obj.PdbStream->Version = InfoS.getVersion();
+ Obj.PdbStream->Features = InfoS.getFeatureSignatures();
+
+ return Error::success();
+}
+
+static opts::ModuleSubsection convertSubsectionKind(DebugSubsectionKind K) {
+ switch (K) {
+ case DebugSubsectionKind::CrossScopeExports:
+ return opts::ModuleSubsection::CrossScopeExports;
+ case DebugSubsectionKind::CrossScopeImports:
+ return opts::ModuleSubsection::CrossScopeImports;
+ case DebugSubsectionKind::FileChecksums:
+ return opts::ModuleSubsection::FileChecksums;
+ case DebugSubsectionKind::InlineeLines:
+ return opts::ModuleSubsection::InlineeLines;
+ case DebugSubsectionKind::Lines:
+ return opts::ModuleSubsection::Lines;
+ case DebugSubsectionKind::Symbols:
+ return opts::ModuleSubsection::Symbols;
+ case DebugSubsectionKind::StringTable:
+ return opts::ModuleSubsection::StringTable;
+ case DebugSubsectionKind::FrameData:
+ return opts::ModuleSubsection::FrameData;
+ default:
+ return opts::ModuleSubsection::Unknown;
+ }
+ llvm_unreachable("Unreachable!");
+}
+
+Error YAMLOutputStyle::dumpDbiStream() {
+ if (!opts::pdb2yaml::DbiStream)
+ return Error::success();
+
+ auto DbiS = File.getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ auto &DS = DbiS.get();
+ Obj.DbiStream.emplace();
+ Obj.DbiStream->Age = DS.getAge();
+ Obj.DbiStream->BuildNumber = DS.getBuildNumber();
+ Obj.DbiStream->Flags = DS.getFlags();
+ Obj.DbiStream->MachineType = DS.getMachineType();
+ Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld();
+ Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion();
+ Obj.DbiStream->VerHeader = DS.getDbiVersion();
+ if (opts::pdb2yaml::DumpModules) {
+ const auto &Modules = DS.modules();
+ for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
+ DbiModuleDescriptor MI = Modules.getModuleDescriptor(I);
+
+ Obj.DbiStream->ModInfos.emplace_back();
+ yaml::PdbDbiModuleInfo &DMI = Obj.DbiStream->ModInfos.back();
+
+ DMI.Mod = MI.getModuleName();
+ DMI.Obj = MI.getObjFileName();
+ if (opts::pdb2yaml::DumpModuleFiles) {
+ auto Files = Modules.source_files(I);
+ DMI.SourceFiles.assign(Files.begin(), Files.end());
+ }
+
+ uint16_t ModiStream = MI.getModuleStreamIndex();
+ if (ModiStream == kInvalidStreamIndex)
+ continue;
+
+ auto ModStreamData = msf::MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
+ File.getAllocator());
+
+ pdb::ModuleDebugStreamRef ModS(MI, std::move(ModStreamData));
+ if (auto EC = ModS.reload())
+ return EC;
+
+ auto ExpectedST = File.getStringTable();
+ if (!ExpectedST)
+ return ExpectedST.takeError();
+ if (!opts::pdb2yaml::DumpModuleSubsections.empty() &&
+ ModS.hasDebugSubsections()) {
+ auto ExpectedChecksums = ModS.findChecksumsSubsection();
+ if (!ExpectedChecksums)
+ return ExpectedChecksums.takeError();
+
+ StringsAndChecksumsRef SC(ExpectedST->getStringTable(),
+ *ExpectedChecksums);
+
+ for (const auto &SS : ModS.subsections()) {
+ opts::ModuleSubsection OptionKind = convertSubsectionKind(SS.kind());
+ if (!checkModuleSubsection(OptionKind))
+ continue;
+
+ auto Converted =
+ CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection(SC, SS);
+ if (!Converted)
+ return Converted.takeError();
+ DMI.Subsections.push_back(*Converted);
+ }
+ }
+
+ if (opts::pdb2yaml::DumpModuleSyms) {
+ DMI.Modi.emplace();
+
+ DMI.Modi->Signature = ModS.signature();
+ bool HadError = false;
+ for (auto &Sym : ModS.symbols(&HadError)) {
+ auto ES = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym);
+ if (!ES)
+ return ES.takeError();
+
+ DMI.Modi->Symbols.push_back(*ES);
+ }
+ }
+ }
+ }
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpTpiStream() {
+ if (!opts::pdb2yaml::TpiStream)
+ return Error::success();
+
+ auto TpiS = File.getPDBTpiStream();
+ if (!TpiS)
+ return TpiS.takeError();
+
+ auto &TS = TpiS.get();
+ Obj.TpiStream.emplace();
+ Obj.TpiStream->Version = TS.getTpiVersion();
+ for (auto &Record : TS.types(nullptr)) {
+ auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record);
+ if (!ExpectedRecord)
+ return ExpectedRecord.takeError();
+ Obj.TpiStream->Records.push_back(*ExpectedRecord);
+ }
+
+ return Error::success();
+}
+
+Error YAMLOutputStyle::dumpIpiStream() {
+ if (!opts::pdb2yaml::IpiStream)
+ return Error::success();
+
+ auto InfoS = File.getPDBInfoStream();
+ if (!InfoS)
+ return InfoS.takeError();
+ if (!InfoS->containsIdStream())
+ return Error::success();
+
+ auto IpiS = File.getPDBIpiStream();
+ if (!IpiS)
+ return IpiS.takeError();
+
+ auto &IS = IpiS.get();
+ Obj.IpiStream.emplace();
+ Obj.IpiStream->Version = IS.getTpiVersion();
+ for (auto &Record : IS.types(nullptr)) {
+ auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record);
+ if (!ExpectedRecord)
+ return ExpectedRecord.takeError();
+
+ Obj.IpiStream->Records.push_back(*ExpectedRecord);
+ }
+
+ return Error::success();
+}
+
+void YAMLOutputStyle::flush() {
+ Out << Obj;
+ outs().flush();
+}
diff --git a/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h
index 3cd603a..3690e35 100644
--- a/contrib/llvm/tools/llvm-pdbdump/YAMLOutputStyle.h
+++ b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h
@@ -13,12 +13,13 @@
#include "OutputStyle.h"
#include "PdbYaml.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/YAMLTraits.h"
namespace llvm {
namespace pdb {
+class ModuleDebugStreamRef;
+
class YAMLOutputStyle : public OutputStyle {
public:
YAMLOutputStyle(PDBFile &File);
@@ -26,6 +27,7 @@ public:
Error dump() override;
private:
+ Error dumpStringTable();
Error dumpFileHeaders();
Error dumpStreamMetadata();
Error dumpStreamDirectory();
diff --git a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
new file mode 100644
index 0000000..f2bd194
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -0,0 +1,1179 @@
+//===- llvm-pdbutil.cpp - Dump debug info from a PDB file -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Dumps debug information present in PDB files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-pdbutil.h"
+
+#include "Analyze.h"
+#include "BytesOutputStyle.h"
+#include "Diff.h"
+#include "DumpOutputStyle.h"
+#include "LinePrinter.h"
+#include "OutputStyle.h"
+#include "PrettyCompilandDumper.h"
+#include "PrettyExternalSymbolDumper.h"
+#include "PrettyFunctionDumper.h"
+#include "PrettyTypeDumper.h"
+#include "PrettyVariableDumper.h"
+#include "YAMLOutputStyle.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/COM.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace opts {
+
+cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info");
+cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from the PDB file");
+
+cl::SubCommand
+ PrettySubcommand("pretty",
+ "Dump semantic information about types and symbols");
+
+cl::SubCommand DiffSubcommand("diff", "Diff the contents of 2 PDB files");
+
+cl::SubCommand
+ YamlToPdbSubcommand("yaml2pdb",
+ "Generate a PDB file from a YAML description");
+cl::SubCommand
+ PdbToYamlSubcommand("pdb2yaml",
+ "Generate a detailed YAML description of a PDB File");
+
+cl::SubCommand
+ AnalyzeSubcommand("analyze",
+ "Analyze various aspects of a PDB's structure");
+
+cl::SubCommand MergeSubcommand("merge",
+ "Merge multiple PDBs into a single PDB");
+
+cl::OptionCategory TypeCategory("Symbol Type Options");
+cl::OptionCategory FilterCategory("Filtering and Sorting Options");
+cl::OptionCategory OtherOptions("Other Options");
+
+cl::ValuesClass ChunkValues = cl::values(
+ clEnumValN(ModuleSubsection::CrossScopeExports, "cme",
+ "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
+ clEnumValN(ModuleSubsection::CrossScopeImports, "cmi",
+ "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
+ clEnumValN(ModuleSubsection::FileChecksums, "fc",
+ "File checksums (DEBUG_S_CHECKSUMS subsection)"),
+ clEnumValN(ModuleSubsection::InlineeLines, "ilines",
+ "Inlinee lines (DEBUG_S_INLINEELINES subsection)"),
+ clEnumValN(ModuleSubsection::Lines, "lines",
+ "Lines (DEBUG_S_LINES subsection)"),
+ clEnumValN(ModuleSubsection::StringTable, "strings",
+ "String Table (DEBUG_S_STRINGTABLE subsection) (not "
+ "typically present in PDB file)"),
+ clEnumValN(ModuleSubsection::FrameData, "frames",
+ "Frame Data (DEBUG_S_FRAMEDATA subsection)"),
+ clEnumValN(ModuleSubsection::Symbols, "symbols",
+ "Symbols (DEBUG_S_SYMBOLS subsection) (not typically "
+ "present in PDB file)"),
+ clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas",
+ "COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"),
+ clEnumValN(ModuleSubsection::Unknown, "unknown",
+ "Any subsection not covered by another option"),
+ clEnumValN(ModuleSubsection::All, "all", "All known subsections"));
+
+namespace pretty {
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore, cl::sub(PrettySubcommand));
+
+cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Symbols("module-syms",
+ cl::desc("Display symbols for each compiland"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::list<SymLevel> SymTypes(
+ "sym-types", cl::desc("Type of symbols to dump (default all)"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand), cl::ZeroOrMore,
+ cl::values(
+ clEnumValN(SymLevel::Thunks, "thunks", "Display thunk symbols"),
+ clEnumValN(SymLevel::Data, "data", "Display data symbols"),
+ clEnumValN(SymLevel::Functions, "funcs", "Display function symbols"),
+ clEnumValN(SymLevel::All, "all", "Display all symbols (default)")));
+
+cl::opt<bool>
+ Types("types",
+ cl::desc("Display all types (implies -classes, -enums, -typedefs)"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Classes("classes", cl::desc("Display class types"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Enums("enums", cl::desc("Display enum types"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<SymbolSortMode> SymbolOrder(
+ "symbol-order", cl::desc("symbol sort order"),
+ cl::init(SymbolSortMode::None),
+ cl::values(clEnumValN(SymbolSortMode::None, "none",
+ "Undefined / no particular sort order"),
+ clEnumValN(SymbolSortMode::Name, "name", "Sort symbols by name"),
+ clEnumValN(SymbolSortMode::Size, "size",
+ "Sort symbols by size")),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+
+cl::opt<ClassSortMode> ClassOrder(
+ "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None),
+ cl::values(
+ clEnumValN(ClassSortMode::None, "none",
+ "Undefined / no particular sort order"),
+ clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"),
+ clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"),
+ clEnumValN(ClassSortMode::Padding, "padding",
+ "Sort classes by amount of padding"),
+ clEnumValN(ClassSortMode::PaddingPct, "padding-pct",
+ "Sort classes by percentage of space consumed by padding"),
+ clEnumValN(ClassSortMode::PaddingImmediate, "padding-imm",
+ "Sort classes by amount of immediate padding"),
+ clEnumValN(ClassSortMode::PaddingPctImmediate, "padding-pct-imm",
+ "Sort classes by percentage of space consumed by immediate "
+ "padding")),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+
+cl::opt<ClassDefinitionFormat> ClassFormat(
+ "class-definitions", cl::desc("Class definition format"),
+ cl::init(ClassDefinitionFormat::All),
+ cl::values(
+ clEnumValN(ClassDefinitionFormat::All, "all",
+ "Display all class members including data, constants, "
+ "typedefs, functions, etc"),
+ clEnumValN(ClassDefinitionFormat::Layout, "layout",
+ "Only display members that contribute to class size."),
+ clEnumValN(ClassDefinitionFormat::None, "none",
+ "Don't display class definitions")),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<uint32_t> ClassRecursionDepth(
+ "class-recurse-depth", cl::desc("Class recursion depth (0=no limit)"),
+ cl::init(0), cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+
+cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory),
+ cl::sub(PrettySubcommand));
+cl::opt<bool>
+ All("all", cl::desc("Implies all other options in 'Symbol Types' category"),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+
+cl::opt<uint64_t> LoadAddress(
+ "load-address",
+ cl::desc("Assume the module is loaded at the specified address"),
+ cl::cat(OtherOptions), cl::sub(PrettySubcommand));
+cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"),
+ cl::cat(OtherOptions), cl::sub(PrettySubcommand));
+cl::opt<cl::boolOrDefault>
+ ColorOutput("color-output",
+ cl::desc("Override use of color (default = isatty)"),
+ cl::cat(OtherOptions), cl::sub(PrettySubcommand));
+cl::list<std::string> ExcludeTypes(
+ "exclude-types", cl::desc("Exclude types by regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::list<std::string> ExcludeSymbols(
+ "exclude-symbols", cl::desc("Exclude symbols by regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::list<std::string> ExcludeCompilands(
+ "exclude-compilands", cl::desc("Exclude compilands by regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+
+cl::list<std::string> IncludeTypes(
+ "include-types",
+ cl::desc("Include only types which match a regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::list<std::string> IncludeSymbols(
+ "include-symbols",
+ cl::desc("Include only symbols which match a regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::list<std::string> IncludeCompilands(
+ "include-compilands",
+ cl::desc("Include only compilands those which match a regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::opt<uint32_t> SizeThreshold(
+ "min-type-size", cl::desc("Displays only those types which are greater "
+ "than or equal to the specified size."),
+ cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::opt<uint32_t> PaddingThreshold(
+ "min-class-padding", cl::desc("Displays only those classes which have at "
+ "least the specified amount of padding."),
+ cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::opt<uint32_t> ImmediatePaddingThreshold(
+ "min-class-padding-imm",
+ cl::desc("Displays only those classes which have at least the specified "
+ "amount of immediate padding, ignoring padding internal to bases "
+ "and aggregates."),
+ cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+
+cl::opt<bool> ExcludeCompilerGenerated(
+ "no-compiler-generated",
+ cl::desc("Don't show compiler generated types and symbols"),
+ cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+cl::opt<bool>
+ ExcludeSystemLibraries("no-system-libs",
+ cl::desc("Don't show symbols from system libraries"),
+ cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+
+cl::opt<bool> NoEnumDefs("no-enum-definitions",
+ cl::desc("Don't display full enum definitions"),
+ cl::cat(FilterCategory), cl::sub(PrettySubcommand));
+}
+
+namespace diff {
+cl::opt<bool> PrintValueColumns(
+ "values", cl::init(true),
+ cl::desc("Print one column for each PDB with the field value"),
+ cl::Optional, cl::sub(DiffSubcommand));
+cl::opt<bool>
+ PrintResultColumn("result", cl::init(false),
+ cl::desc("Print a column with the result status"),
+ cl::Optional, cl::sub(DiffSubcommand));
+
+cl::opt<std::string> LeftRoot(
+ "left-bin-root", cl::Optional,
+ cl::desc("Treats the specified path as the root of the tree containing "
+ "binaries referenced by the left PDB. The root is stripped from "
+ "embedded paths when doing equality comparisons."),
+ cl::sub(DiffSubcommand));
+cl::opt<std::string> RightRoot(
+ "right-bin-root", cl::Optional,
+ cl::desc("Treats the specified path as the root of the tree containing "
+ "binaries referenced by the right PDB. The root is stripped from "
+ "embedded paths when doing equality comparisons"),
+ cl::sub(DiffSubcommand));
+
+cl::opt<std::string> Left(cl::Positional, cl::desc("<left>"),
+ cl::sub(DiffSubcommand));
+cl::opt<std::string> Right(cl::Positional, cl::desc("<right>"),
+ cl::sub(DiffSubcommand));
+}
+
+cl::OptionCategory FileOptions("Module & File Options");
+
+namespace bytes {
+cl::OptionCategory MsfBytes("MSF File Options");
+cl::OptionCategory DbiBytes("Dbi Stream Options");
+cl::OptionCategory PdbBytes("PDB Stream Options");
+cl::OptionCategory Types("Type Options");
+cl::OptionCategory ModuleCategory("Module Options");
+
+llvm::Optional<NumberRange> DumpBlockRange;
+llvm::Optional<NumberRange> DumpByteRange;
+
+cl::opt<std::string> DumpBlockRangeOpt(
+ "block-range", cl::value_desc("start[-end]"),
+ cl::desc("Dump binary data from specified range of blocks."),
+ cl::sub(BytesSubcommand), cl::cat(MsfBytes));
+
+cl::opt<std::string>
+ DumpByteRangeOpt("byte-range", cl::value_desc("start[-end]"),
+ cl::desc("Dump binary data from specified range of bytes"),
+ cl::sub(BytesSubcommand), cl::cat(MsfBytes));
+
+cl::list<std::string>
+ DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
+ cl::desc("Dump binary data from specified streams. Format "
+ "is SN[:Start][@Size]"),
+ cl::sub(BytesSubcommand), cl::cat(MsfBytes));
+
+cl::opt<bool> NameMap("name-map", cl::desc("Dump bytes of PDB Name Map"),
+ cl::sub(BytesSubcommand), cl::cat(PdbBytes));
+
+cl::opt<bool> SectionContributions("sc", cl::desc("Dump section contributions"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> SectionMap("sm", cl::desc("Dump section map"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> ModuleInfos("modi", cl::desc("Dump module info"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> FileInfo("files", cl::desc("Dump source file info"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> TypeServerMap("type-server", cl::desc("Dump type server map"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+cl::opt<bool> ECData("ec", cl::desc("Dump edit and continue map"),
+ cl::sub(BytesSubcommand), cl::cat(DbiBytes));
+
+cl::list<uint32_t>
+ TypeIndex("type",
+ cl::desc("Dump the type record with the given type index"),
+ cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand),
+ cl::cat(TypeCategory));
+cl::list<uint32_t>
+ IdIndex("id", cl::desc("Dump the id record with the given type index"),
+ cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand),
+ cl::cat(TypeCategory));
+
+cl::opt<uint32_t> ModuleIndex(
+ "mod",
+ cl::desc(
+ "Limit options in the Modules category to the specified module index"),
+ cl::Optional, cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> ModuleSyms("syms", cl::desc("Dump symbol record substream"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> ModuleC11("c11-chunks", cl::Hidden,
+ cl::desc("Dump C11 CodeView debug chunks"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> ModuleC13("chunks",
+ cl::desc("Dump C13 CodeView debug chunk subsection"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::opt<bool> SplitChunks(
+ "split-chunks",
+ cl::desc(
+ "When dumping debug chunks, show a different section for each chunk"),
+ cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore, cl::sub(BytesSubcommand));
+
+} // namespace bytes
+
+namespace dump {
+
+cl::OptionCategory MsfOptions("MSF Container Options");
+cl::OptionCategory TypeOptions("Type Record Options");
+cl::OptionCategory SymbolOptions("Symbol Options");
+cl::OptionCategory MiscOptions("Miscellaneous Options");
+
+// MSF OPTIONS
+cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"),
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpStreams("streams",
+ cl::desc("dump summary of the PDB streams"),
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpStreamBlocks(
+ "stream-blocks",
+ cl::desc("Add block information to the output of -streams"),
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
+
+// TYPE OPTIONS
+cl::opt<bool> DumpTypes("types",
+ cl::desc("dump CodeView type records from TPI stream"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpTypeData(
+ "type-data",
+ cl::desc("dump CodeView type record raw bytes from TPI stream"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpTypeExtras("type-extras",
+ cl::desc("dump type hashes and index offsets"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::list<uint32_t> DumpTypeIndex(
+ "type-index", cl::ZeroOrMore, cl::CommaSeparated,
+ cl::desc("only dump types with the specified hexadecimal type index"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpIds("ids",
+ cl::desc("dump CodeView type records from IPI stream"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+cl::opt<bool>
+ DumpIdData("id-data",
+ cl::desc("dump CodeView type record raw bytes from IPI stream"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpIdExtras("id-extras",
+ cl::desc("dump id hashes and index offsets"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+cl::list<uint32_t> DumpIdIndex(
+ "id-index", cl::ZeroOrMore, cl::CommaSeparated,
+ cl::desc("only dump ids with the specified hexadecimal type index"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpTypeDependents(
+ "dependents",
+ cl::desc("In conjunection with -type-index and -id-index, dumps the entire "
+ "dependency graph for the specified index instead of "
+ "just the single record with the specified index"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+
+// SYMBOL OPTIONS
+cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool>
+ DumpSymRecordBytes("sym-data",
+ cl::desc("dump CodeView symbol record raw bytes"),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+
+// MODULE & FILE OPTIONS
+cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpModuleFiles(
+ "files",
+ cl::desc("Dump the source files that contribute to each module's."),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpLines(
+ "l",
+ cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpInlineeLines(
+ "il",
+ cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpXmi(
+ "xmi",
+ cl::desc(
+ "dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpXme(
+ "xme",
+ cl::desc(
+ "dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
+ cl::cat(FileOptions), cl::sub(DumpSubcommand));
+
+// MISCELLANEOUS OPTIONS
+cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
+ cl::cat(MiscOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> DumpSectionContribs("section-contribs",
+ cl::desc("dump section contributions"),
+ cl::cat(MiscOptions),
+ cl::sub(DumpSubcommand));
+cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
+ cl::cat(MiscOptions), cl::sub(DumpSubcommand));
+
+cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
+ cl::cat(MiscOptions), cl::sub(DumpSubcommand));
+
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore, cl::sub(DumpSubcommand));
+}
+
+namespace yaml2pdb {
+cl::opt<std::string>
+ YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
+ cl::sub(YamlToPdbSubcommand));
+
+cl::opt<std::string> InputFilename(cl::Positional,
+ cl::desc("<input YAML file>"), cl::Required,
+ cl::sub(YamlToPdbSubcommand));
+}
+
+namespace pdb2yaml {
+cl::opt<bool> All("all",
+ cl::desc("Dump everything we know how to dump."),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> NoFileHeaders("no-file-headers",
+ cl::desc("Do not dump MSF file headers"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> Minimal("minimal",
+ cl::desc("Don't write fields with default values"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> StreamMetadata(
+ "stream-metadata",
+ cl::desc("Dump the number of streams and each stream's size"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> StreamDirectory(
+ "stream-directory",
+ cl::desc("Dump each stream's block map (implies -stream-metadata)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+cl::opt<bool> PdbStream("pdb-stream",
+ cl::desc("Dump the PDB Stream (Stream 1)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> DbiStream("dbi-stream",
+ cl::desc("Dump the DBI Stream Headers (Stream 2)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> TpiStream("tpi-stream",
+ cl::desc("Dump the TPI Stream (Stream 3)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+cl::opt<bool> IpiStream("ipi-stream",
+ cl::desc("Dump the IPI Stream (Stream 5)"),
+ cl::sub(PdbToYamlSubcommand), cl::init(false));
+
+// MODULE & FILE OPTIONS
+cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
+ cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
+cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
+ cl::cat(FileOptions),
+ cl::sub(PdbToYamlSubcommand));
+cl::list<ModuleSubsection> DumpModuleSubsections(
+ "subsections", cl::ZeroOrMore, cl::CommaSeparated,
+ cl::desc("dump subsections from each module's debug stream"), ChunkValues,
+ cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
+cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
+ cl::cat(FileOptions),
+ cl::sub(PdbToYamlSubcommand));
+
+cl::list<std::string> InputFilename(cl::Positional,
+ cl::desc("<input PDB file>"), cl::Required,
+ cl::sub(PdbToYamlSubcommand));
+} // namespace pdb2yaml
+
+namespace analyze {
+cl::opt<bool> StringTable("hash-collisions", cl::desc("Find hash collisions"),
+ cl::sub(AnalyzeSubcommand), cl::init(false));
+cl::list<std::string> InputFilename(cl::Positional,
+ cl::desc("<input PDB file>"), cl::Required,
+ cl::sub(AnalyzeSubcommand));
+}
+
+namespace merge {
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore, cl::sub(MergeSubcommand));
+cl::opt<std::string>
+ PdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
+ cl::sub(MergeSubcommand));
+}
+}
+
+static ExitOnError ExitOnErr;
+
+static void yamlToPdb(StringRef Path) {
+ BumpPtrAllocator Allocator;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
+ MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
+ /*RequiresNullTerminator=*/false);
+
+ if (ErrorOrBuffer.getError()) {
+ ExitOnErr(make_error<GenericError>(generic_error_code::invalid_path, Path));
+ }
+
+ std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get();
+
+ llvm::yaml::Input In(Buffer->getBuffer());
+ pdb::yaml::PdbObject YamlObj(Allocator);
+ In >> YamlObj;
+
+ PDBFileBuilder Builder(Allocator);
+
+ uint32_t BlockSize = 4096;
+ if (YamlObj.Headers.hasValue())
+ BlockSize = YamlObj.Headers->SuperBlock.BlockSize;
+ ExitOnErr(Builder.initialize(BlockSize));
+ // Add each of the reserved streams. We ignore stream metadata in the
+ // yaml, because we will reconstruct our own view of the streams. For
+ // example, the YAML may say that there were 20 streams in the original
+ // PDB, but maybe we only dump a subset of those 20 streams, so we will
+ // have fewer, and the ones we do have may end up with different indices
+ // than the ones in the original PDB. So we just start with a clean slate.
+ for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
+ ExitOnErr(Builder.getMsfBuilder().addStream(0));
+
+ StringsAndChecksums Strings;
+ Strings.setStrings(std::make_shared<DebugStringTableSubsection>());
+
+ if (YamlObj.StringTable.hasValue()) {
+ for (auto S : *YamlObj.StringTable)
+ Strings.strings()->insert(S);
+ }
+
+ pdb::yaml::PdbInfoStream DefaultInfoStream;
+ pdb::yaml::PdbDbiStream DefaultDbiStream;
+ pdb::yaml::PdbTpiStream DefaultTpiStream;
+ pdb::yaml::PdbTpiStream DefaultIpiStream;
+
+ const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream);
+
+ auto &InfoBuilder = Builder.getInfoBuilder();
+ InfoBuilder.setAge(Info.Age);
+ InfoBuilder.setGuid(Info.Guid);
+ InfoBuilder.setSignature(Info.Signature);
+ InfoBuilder.setVersion(Info.Version);
+ for (auto F : Info.Features)
+ InfoBuilder.addFeature(F);
+
+ const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream);
+ auto &DbiBuilder = Builder.getDbiBuilder();
+ DbiBuilder.setAge(Dbi.Age);
+ DbiBuilder.setBuildNumber(Dbi.BuildNumber);
+ DbiBuilder.setFlags(Dbi.Flags);
+ DbiBuilder.setMachineType(Dbi.MachineType);
+ DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld);
+ DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion);
+ DbiBuilder.setVersionHeader(Dbi.VerHeader);
+ for (const auto &MI : Dbi.ModInfos) {
+ auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod));
+ ModiBuilder.setObjFileName(MI.Obj);
+
+ for (auto S : MI.SourceFiles)
+ ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
+ if (MI.Modi.hasValue()) {
+ const auto &ModiStream = *MI.Modi;
+ for (auto Symbol : ModiStream.Symbols) {
+ ModiBuilder.addSymbol(
+ Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb));
+ }
+ }
+
+ // Each module has its own checksum subsection, so scan for it every time.
+ Strings.setChecksums(nullptr);
+ CodeViewYAML::initializeStringsAndChecksums(MI.Subsections, Strings);
+
+ auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList(
+ Allocator, MI.Subsections, Strings));
+ for (auto &SS : CodeViewSubsections) {
+ ModiBuilder.addDebugSubsection(SS);
+ }
+ }
+
+ auto &TpiBuilder = Builder.getTpiBuilder();
+ const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream);
+ TpiBuilder.setVersionHeader(Tpi.Version);
+ for (const auto &R : Tpi.Records) {
+ CVType Type = R.toCodeViewRecord(Allocator);
+ TpiBuilder.addTypeRecord(Type.RecordData, None);
+ }
+
+ const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream);
+ auto &IpiBuilder = Builder.getIpiBuilder();
+ IpiBuilder.setVersionHeader(Ipi.Version);
+ for (const auto &R : Ipi.Records) {
+ CVType Type = R.toCodeViewRecord(Allocator);
+ IpiBuilder.addTypeRecord(Type.RecordData, None);
+ }
+
+ Builder.getStringTableBuilder().setStrings(*Strings.strings());
+
+ ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile));
+}
+
+static PDBFile &loadPDB(StringRef Path, std::unique_ptr<IPDBSession> &Session) {
+ ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session));
+
+ NativeSession *NS = static_cast<NativeSession *>(Session.get());
+ return NS->getPDBFile();
+}
+
+static void pdb2Yaml(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ auto &File = loadPDB(Path, Session);
+
+ auto O = llvm::make_unique<YAMLOutputStyle>(File);
+ O = llvm::make_unique<YAMLOutputStyle>(File);
+
+ ExitOnErr(O->dump());
+}
+
+static void dumpRaw(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ auto &File = loadPDB(Path, Session);
+
+ auto O = llvm::make_unique<DumpOutputStyle>(File);
+
+ ExitOnErr(O->dump());
+}
+
+static void dumpBytes(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ auto &File = loadPDB(Path, Session);
+
+ auto O = llvm::make_unique<BytesOutputStyle>(File);
+
+ ExitOnErr(O->dump());
+}
+
+static void dumpAnalysis(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ auto &File = loadPDB(Path, Session);
+ auto O = llvm::make_unique<AnalysisStyle>(File);
+
+ ExitOnErr(O->dump());
+}
+
+static void diff(StringRef Path1, StringRef Path2) {
+ std::unique_ptr<IPDBSession> Session1;
+ std::unique_ptr<IPDBSession> Session2;
+
+ auto &File1 = loadPDB(Path1, Session1);
+ auto &File2 = loadPDB(Path2, Session2);
+
+ auto O = llvm::make_unique<DiffStyle>(File1, File2);
+
+ ExitOnErr(O->dump());
+}
+
+bool opts::pretty::shouldDumpSymLevel(SymLevel Search) {
+ if (SymTypes.empty())
+ return true;
+ if (llvm::find(SymTypes, Search) != SymTypes.end())
+ return true;
+ if (llvm::find(SymTypes, SymLevel::All) != SymTypes.end())
+ return true;
+ return false;
+}
+
+uint32_t llvm::pdb::getTypeLength(const PDBSymbolData &Symbol) {
+ auto SymbolType = Symbol.getType();
+ const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
+
+ return RawType.getLength();
+}
+
+bool opts::pretty::compareFunctionSymbols(
+ const std::unique_ptr<PDBSymbolFunc> &F1,
+ const std::unique_ptr<PDBSymbolFunc> &F2) {
+ assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None);
+
+ if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name)
+ return F1->getName() < F2->getName();
+
+ // Note that we intentionally sort in descending order on length, since
+ // long functions are more interesting than short functions.
+ return F1->getLength() > F2->getLength();
+}
+
+bool opts::pretty::compareDataSymbols(
+ const std::unique_ptr<PDBSymbolData> &F1,
+ const std::unique_ptr<PDBSymbolData> &F2) {
+ assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None);
+
+ if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name)
+ return F1->getName() < F2->getName();
+
+ // Note that we intentionally sort in descending order on length, since
+ // large types are more interesting than short ones.
+ return getTypeLength(*F1) > getTypeLength(*F2);
+}
+
+static void dumpPretty(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+
+ const auto ReaderType =
+ opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA;
+ ExitOnErr(loadDataForPDB(ReaderType, Path, Session));
+
+ if (opts::pretty::LoadAddress)
+ Session->setLoadAddress(opts::pretty::LoadAddress);
+
+ auto &Stream = outs();
+ const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET
+ ? Stream.has_colors()
+ : opts::pretty::ColorOutput == cl::BOU_TRUE;
+ LinePrinter Printer(2, UseColor, Stream);
+
+ auto GlobalScope(Session->getGlobalScope());
+ std::string FileName(GlobalScope->getSymbolsFileName());
+
+ WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
+ WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
+ Printer.Indent();
+ uint64_t FileSize = 0;
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
+ if (!sys::fs::file_size(FileName, FileSize)) {
+ Printer << ": " << FileSize << " bytes";
+ } else {
+ Printer << ": (Unable to obtain file size)";
+ }
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid";
+ Printer << ": " << GlobalScope->getGuid();
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age";
+ Printer << ": " << GlobalScope->getAge();
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes";
+ Printer << ": ";
+ if (GlobalScope->hasCTypes())
+ outs() << "HasCTypes ";
+ if (GlobalScope->hasPrivateSymbols())
+ outs() << "HasPrivateSymbols ";
+ Printer.Unindent();
+
+ if (opts::pretty::Compilands) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get()
+ << "---COMPILANDS---";
+ Printer.Indent();
+ auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
+ CompilandDumper Dumper(Printer);
+ CompilandDumpFlags options = CompilandDumper::Flags::None;
+ if (opts::pretty::Lines)
+ options = options | CompilandDumper::Flags::Lines;
+ while (auto Compiland = Compilands->getNext())
+ Dumper.start(*Compiland, options);
+ Printer.Unindent();
+ }
+
+ if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
+ Printer.Indent();
+ TypeDumper Dumper(Printer);
+ Dumper.start(*GlobalScope);
+ Printer.Unindent();
+ }
+
+ if (opts::pretty::Symbols) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
+ Printer.Indent();
+ auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
+ CompilandDumper Dumper(Printer);
+ while (auto Compiland = Compilands->getNext())
+ Dumper.start(*Compiland, true);
+ Printer.Unindent();
+ }
+
+ if (opts::pretty::Globals) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
+ Printer.Indent();
+ if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) {
+ FunctionDumper Dumper(Printer);
+ auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>();
+ if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) {
+ while (auto Function = Functions->getNext()) {
+ Printer.NewLine();
+ Dumper.start(*Function, FunctionDumper::PointerType::None);
+ }
+ } else {
+ std::vector<std::unique_ptr<PDBSymbolFunc>> Funcs;
+ while (auto Func = Functions->getNext())
+ Funcs.push_back(std::move(Func));
+ std::sort(Funcs.begin(), Funcs.end(),
+ opts::pretty::compareFunctionSymbols);
+ for (const auto &Func : Funcs) {
+ Printer.NewLine();
+ Dumper.start(*Func, FunctionDumper::PointerType::None);
+ }
+ }
+ }
+ if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) {
+ auto Vars = GlobalScope->findAllChildren<PDBSymbolData>();
+ VariableDumper Dumper(Printer);
+ if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) {
+ while (auto Var = Vars->getNext())
+ Dumper.start(*Var);
+ } else {
+ std::vector<std::unique_ptr<PDBSymbolData>> Datas;
+ while (auto Var = Vars->getNext())
+ Datas.push_back(std::move(Var));
+ std::sort(Datas.begin(), Datas.end(), opts::pretty::compareDataSymbols);
+ for (const auto &Var : Datas)
+ Dumper.start(*Var);
+ }
+ }
+ if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) {
+ auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>();
+ CompilandDumper Dumper(Printer);
+ while (auto Thunk = Thunks->getNext())
+ Dumper.dump(*Thunk);
+ }
+ Printer.Unindent();
+ }
+ if (opts::pretty::Externals) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---";
+ Printer.Indent();
+ ExternalSymbolDumper Dumper(Printer);
+ Dumper.start(*GlobalScope);
+ }
+ if (opts::pretty::Lines) {
+ Printer.NewLine();
+ }
+ outs().flush();
+}
+
+static void mergePdbs() {
+ BumpPtrAllocator Allocator;
+ TypeTableBuilder MergedTpi(Allocator);
+ TypeTableBuilder MergedIpi(Allocator);
+
+ // Create a Tpi and Ipi type table with all types from all input files.
+ for (const auto &Path : opts::merge::InputFilenames) {
+ std::unique_ptr<IPDBSession> Session;
+ auto &File = loadPDB(Path, Session);
+ SmallVector<TypeIndex, 128> TypeMap;
+ SmallVector<TypeIndex, 128> IdMap;
+ if (File.hasPDBTpiStream()) {
+ auto &Tpi = ExitOnErr(File.getPDBTpiStream());
+ ExitOnErr(
+ codeview::mergeTypeRecords(MergedTpi, TypeMap, Tpi.typeArray()));
+ }
+ if (File.hasPDBIpiStream()) {
+ auto &Ipi = ExitOnErr(File.getPDBIpiStream());
+ ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap,
+ Ipi.typeArray()));
+ }
+ }
+
+ // Then write the PDB.
+ PDBFileBuilder Builder(Allocator);
+ ExitOnErr(Builder.initialize(4096));
+ // Add each of the reserved streams. We might not put any data in them,
+ // but at least they have to be present.
+ for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
+ ExitOnErr(Builder.getMsfBuilder().addStream(0));
+
+ auto &DestTpi = Builder.getTpiBuilder();
+ auto &DestIpi = Builder.getIpiBuilder();
+ MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, ArrayRef<uint8_t> Data) {
+ DestTpi.addTypeRecord(Data, None);
+ });
+ MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, ArrayRef<uint8_t> Data) {
+ DestIpi.addTypeRecord(Data, None);
+ });
+ Builder.getInfoBuilder().addFeature(PdbRaw_FeatureSig::VC140);
+
+ SmallString<64> OutFile(opts::merge::PdbOutputFile);
+ if (OutFile.empty()) {
+ OutFile = opts::merge::InputFilenames[0];
+ llvm::sys::path::replace_extension(OutFile, "merged.pdb");
+ }
+ ExitOnErr(Builder.commit(OutFile));
+}
+
+static bool parseRange(StringRef Str,
+ Optional<opts::bytes::NumberRange> &Parsed) {
+ if (Str.empty())
+ return true;
+
+ llvm::Regex R("^([^-]+)(-([^-]+))?$");
+ llvm::SmallVector<llvm::StringRef, 2> Matches;
+ if (!R.match(Str, &Matches))
+ return false;
+
+ Parsed.emplace();
+ if (!to_integer(Matches[1], Parsed->Min))
+ return false;
+
+ if (!Matches[3].empty()) {
+ Parsed->Max.emplace();
+ if (!to_integer(Matches[3], *Parsed->Max))
+ return false;
+ }
+ return true;
+}
+
+static void simplifyChunkList(llvm::cl::list<opts::ModuleSubsection> &Chunks) {
+ // If this list contains "All" plus some other stuff, remove the other stuff
+ // and just keep "All" in the list.
+ if (!llvm::is_contained(Chunks, opts::ModuleSubsection::All))
+ return;
+ Chunks.reset();
+ Chunks.push_back(opts::ModuleSubsection::All);
+}
+
+int main(int argc_, const char *argv_[]) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal(argv_[0]);
+ PrettyStackTraceProgram X(argc_, argv_);
+
+ ExitOnErr.setBanner("llvm-pdbutil: ");
+
+ SmallVector<const char *, 256> argv;
+ SpecificBumpPtrAllocator<char> ArgAllocator;
+ ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector(
+ argv, makeArrayRef(argv_, argc_), ArgAllocator)));
+
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
+
+ if (opts::BytesSubcommand) {
+ if (!parseRange(opts::bytes::DumpBlockRangeOpt,
+ opts::bytes::DumpBlockRange)) {
+ errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
+ << "' invalid format.\n";
+ errs().flush();
+ exit(1);
+ }
+ if (!parseRange(opts::bytes::DumpByteRangeOpt,
+ opts::bytes::DumpByteRange)) {
+ errs() << "Argument '" << opts::bytes::DumpByteRangeOpt
+ << "' invalid format.\n";
+ errs().flush();
+ exit(1);
+ }
+ }
+
+ if (opts::DumpSubcommand) {
+ if (opts::dump::RawAll) {
+ opts::dump::DumpLines = true;
+ opts::dump::DumpInlineeLines = true;
+ opts::dump::DumpXme = true;
+ opts::dump::DumpXmi = true;
+ opts::dump::DumpIds = true;
+ opts::dump::DumpPublics = true;
+ opts::dump::DumpSectionContribs = true;
+ opts::dump::DumpSectionMap = true;
+ opts::dump::DumpStreams = true;
+ opts::dump::DumpStreamBlocks = true;
+ opts::dump::DumpStringTable = true;
+ opts::dump::DumpSummary = true;
+ opts::dump::DumpSymbols = true;
+ opts::dump::DumpIds = true;
+ opts::dump::DumpIdExtras = true;
+ opts::dump::DumpTypes = true;
+ opts::dump::DumpTypeExtras = true;
+ opts::dump::DumpModules = true;
+ opts::dump::DumpModuleFiles = true;
+ }
+ }
+ if (opts::PdbToYamlSubcommand) {
+ if (opts::pdb2yaml::All) {
+ opts::pdb2yaml::StreamMetadata = true;
+ opts::pdb2yaml::StreamDirectory = true;
+ opts::pdb2yaml::PdbStream = true;
+ opts::pdb2yaml::StringTable = true;
+ opts::pdb2yaml::DbiStream = true;
+ opts::pdb2yaml::TpiStream = true;
+ opts::pdb2yaml::IpiStream = true;
+ opts::pdb2yaml::DumpModules = true;
+ opts::pdb2yaml::DumpModuleFiles = true;
+ opts::pdb2yaml::DumpModuleSyms = true;
+ opts::pdb2yaml::DumpModuleSubsections.push_back(
+ opts::ModuleSubsection::All);
+ }
+ simplifyChunkList(opts::pdb2yaml::DumpModuleSubsections);
+
+ if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles)
+ opts::pdb2yaml::DumpModules = true;
+
+ if (opts::pdb2yaml::DumpModules)
+ opts::pdb2yaml::DbiStream = true;
+ }
+ if (opts::DiffSubcommand) {
+ if (!opts::diff::PrintResultColumn && !opts::diff::PrintValueColumns) {
+ llvm::errs() << "WARNING: No diff columns specified\n";
+ }
+ }
+
+ llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+
+ if (opts::PdbToYamlSubcommand) {
+ pdb2Yaml(opts::pdb2yaml::InputFilename.front());
+ } else if (opts::YamlToPdbSubcommand) {
+ if (opts::yaml2pdb::YamlPdbOutputFile.empty()) {
+ SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue());
+ sys::path::replace_extension(OutputFilename, ".pdb");
+ opts::yaml2pdb::YamlPdbOutputFile = OutputFilename.str();
+ }
+ yamlToPdb(opts::yaml2pdb::InputFilename);
+ } else if (opts::AnalyzeSubcommand) {
+ dumpAnalysis(opts::analyze::InputFilename.front());
+ } else if (opts::PrettySubcommand) {
+ if (opts::pretty::Lines)
+ opts::pretty::Compilands = true;
+
+ if (opts::pretty::All) {
+ opts::pretty::Compilands = true;
+ opts::pretty::Symbols = true;
+ opts::pretty::Globals = true;
+ opts::pretty::Types = true;
+ opts::pretty::Externals = true;
+ opts::pretty::Lines = true;
+ }
+
+ if (opts::pretty::Types) {
+ opts::pretty::Classes = true;
+ opts::pretty::Typedefs = true;
+ opts::pretty::Enums = true;
+ }
+
+ // When adding filters for excluded compilands and types, we need to
+ // remember that these are regexes. So special characters such as * and \
+ // need to be escaped in the regex. In the case of a literal \, this means
+ // it needs to be escaped again in the C++. So matching a single \ in the
+ // input requires 4 \es in the C++.
+ if (opts::pretty::ExcludeCompilerGenerated) {
+ opts::pretty::ExcludeTypes.push_back("__vc_attributes");
+ opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*");
+ }
+ if (opts::pretty::ExcludeSystemLibraries) {
+ opts::pretty::ExcludeCompilands.push_back(
+ "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld");
+ opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt");
+ opts::pretty::ExcludeCompilands.push_back(
+ "d:\\\\th.obj.x86fre\\\\minkernel");
+ }
+ std::for_each(opts::pretty::InputFilenames.begin(),
+ opts::pretty::InputFilenames.end(), dumpPretty);
+ } else if (opts::DumpSubcommand) {
+ std::for_each(opts::dump::InputFilenames.begin(),
+ opts::dump::InputFilenames.end(), dumpRaw);
+ } else if (opts::BytesSubcommand) {
+ std::for_each(opts::bytes::InputFilenames.begin(),
+ opts::bytes::InputFilenames.end(), dumpBytes);
+ } else if (opts::DiffSubcommand) {
+ diff(opts::diff::Left, opts::diff::Right);
+ } else if (opts::MergeSubcommand) {
+ if (opts::merge::InputFilenames.size() < 2) {
+ errs() << "merge subcommand requires at least 2 input files.\n";
+ exit(1);
+ }
+ mergePdbs();
+ }
+
+ outs().flush();
+ return 0;
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
new file mode 100644
index 0000000..4e92e63
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
@@ -0,0 +1,180 @@
+//===- llvm-pdbutil.h ----------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
+#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <memory>
+#include <stdint.h>
+
+namespace llvm {
+namespace pdb {
+class PDBSymbolData;
+class PDBSymbolFunc;
+uint32_t getTypeLength(const PDBSymbolData &Symbol);
+}
+}
+
+namespace opts {
+
+enum class DumpLevel { None, Basic, Verbose };
+
+enum class ModuleSubsection {
+ Unknown,
+ Lines,
+ FileChecksums,
+ InlineeLines,
+ CrossScopeImports,
+ CrossScopeExports,
+ StringTable,
+ Symbols,
+ FrameData,
+ CoffSymbolRVAs,
+ All
+};
+
+namespace pretty {
+
+enum class ClassDefinitionFormat { None, Layout, All };
+enum class ClassSortMode {
+ None,
+ Name,
+ Size,
+ Padding,
+ PaddingPct,
+ PaddingImmediate,
+ PaddingPctImmediate
+};
+
+enum class SymbolSortMode { None, Name, Size };
+
+enum class SymLevel { Functions, Data, Thunks, All };
+
+bool shouldDumpSymLevel(SymLevel Level);
+bool compareFunctionSymbols(
+ const std::unique_ptr<llvm::pdb::PDBSymbolFunc> &F1,
+ const std::unique_ptr<llvm::pdb::PDBSymbolFunc> &F2);
+bool compareDataSymbols(const std::unique_ptr<llvm::pdb::PDBSymbolData> &F1,
+ const std::unique_ptr<llvm::pdb::PDBSymbolData> &F2);
+
+extern llvm::cl::opt<bool> Compilands;
+extern llvm::cl::opt<bool> Symbols;
+extern llvm::cl::opt<bool> Globals;
+extern llvm::cl::opt<bool> Classes;
+extern llvm::cl::opt<bool> Enums;
+extern llvm::cl::opt<bool> Typedefs;
+extern llvm::cl::opt<bool> All;
+extern llvm::cl::opt<bool> ExcludeCompilerGenerated;
+
+extern llvm::cl::opt<bool> NoEnumDefs;
+extern llvm::cl::list<std::string> ExcludeTypes;
+extern llvm::cl::list<std::string> ExcludeSymbols;
+extern llvm::cl::list<std::string> ExcludeCompilands;
+extern llvm::cl::list<std::string> IncludeTypes;
+extern llvm::cl::list<std::string> IncludeSymbols;
+extern llvm::cl::list<std::string> IncludeCompilands;
+extern llvm::cl::opt<SymbolSortMode> SymbolOrder;
+extern llvm::cl::opt<ClassSortMode> ClassOrder;
+extern llvm::cl::opt<uint32_t> SizeThreshold;
+extern llvm::cl::opt<uint32_t> PaddingThreshold;
+extern llvm::cl::opt<uint32_t> ImmediatePaddingThreshold;
+extern llvm::cl::opt<ClassDefinitionFormat> ClassFormat;
+extern llvm::cl::opt<uint32_t> ClassRecursionDepth;
+}
+
+namespace bytes {
+struct NumberRange {
+ uint64_t Min;
+ llvm::Optional<uint64_t> Max;
+};
+
+extern llvm::Optional<NumberRange> DumpBlockRange;
+extern llvm::Optional<NumberRange> DumpByteRange;
+extern llvm::cl::list<std::string> DumpStreamData;
+extern llvm::cl::opt<bool> NameMap;
+
+extern llvm::cl::opt<bool> SectionContributions;
+extern llvm::cl::opt<bool> SectionMap;
+extern llvm::cl::opt<bool> ModuleInfos;
+extern llvm::cl::opt<bool> FileInfo;
+extern llvm::cl::opt<bool> TypeServerMap;
+extern llvm::cl::opt<bool> ECData;
+
+extern llvm::cl::list<uint32_t> TypeIndex;
+extern llvm::cl::list<uint32_t> IdIndex;
+
+extern llvm::cl::opt<uint32_t> ModuleIndex;
+extern llvm::cl::opt<bool> ModuleSyms;
+extern llvm::cl::opt<bool> ModuleC11;
+extern llvm::cl::opt<bool> ModuleC13;
+extern llvm::cl::opt<bool> SplitChunks;
+} // namespace bytes
+
+namespace dump {
+
+extern llvm::cl::opt<bool> DumpSummary;
+extern llvm::cl::opt<bool> DumpStreams;
+extern llvm::cl::opt<bool> DumpStreamBlocks;
+
+extern llvm::cl::opt<bool> DumpLines;
+extern llvm::cl::opt<bool> DumpInlineeLines;
+extern llvm::cl::opt<bool> DumpXmi;
+extern llvm::cl::opt<bool> DumpXme;
+extern llvm::cl::opt<bool> DumpStringTable;
+extern llvm::cl::opt<bool> DumpTypes;
+extern llvm::cl::opt<bool> DumpTypeData;
+extern llvm::cl::opt<bool> DumpTypeExtras;
+extern llvm::cl::list<uint32_t> DumpTypeIndex;
+extern llvm::cl::opt<bool> DumpTypeDependents;
+
+extern llvm::cl::opt<bool> DumpIds;
+extern llvm::cl::opt<bool> DumpIdData;
+extern llvm::cl::opt<bool> DumpIdExtras;
+extern llvm::cl::list<uint32_t> DumpIdIndex;
+extern llvm::cl::opt<bool> DumpSymbols;
+extern llvm::cl::opt<bool> DumpSymRecordBytes;
+extern llvm::cl::opt<bool> DumpPublics;
+extern llvm::cl::opt<bool> DumpSectionContribs;
+extern llvm::cl::opt<bool> DumpSectionMap;
+extern llvm::cl::opt<bool> DumpModules;
+extern llvm::cl::opt<bool> DumpModuleFiles;
+extern llvm::cl::opt<bool> RawAll;
+}
+
+namespace pdb2yaml {
+extern llvm::cl::opt<bool> All;
+extern llvm::cl::opt<bool> NoFileHeaders;
+extern llvm::cl::opt<bool> Minimal;
+extern llvm::cl::opt<bool> StreamMetadata;
+extern llvm::cl::opt<bool> StreamDirectory;
+extern llvm::cl::opt<bool> StringTable;
+extern llvm::cl::opt<bool> PdbStream;
+extern llvm::cl::opt<bool> DbiStream;
+extern llvm::cl::opt<bool> TpiStream;
+extern llvm::cl::opt<bool> IpiStream;
+extern llvm::cl::list<std::string> InputFilename;
+extern llvm::cl::opt<bool> DumpModules;
+extern llvm::cl::opt<bool> DumpModuleFiles;
+extern llvm::cl::list<ModuleSubsection> DumpModuleSubsections;
+extern llvm::cl::opt<bool> DumpModuleSyms;
+} // namespace pdb2yaml
+
+namespace diff {
+extern llvm::cl::opt<bool> PrintValueColumns;
+extern llvm::cl::opt<bool> PrintResultColumn;
+extern llvm::cl::opt<std::string> LeftRoot;
+extern llvm::cl::opt<std::string> RightRoot;
+} // namespace diff
+}
+
+#endif
diff --git a/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp b/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 6715566..eee2421 100644
--- a/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -159,14 +159,20 @@ static void loadInput(const WeightedFile &Input, WriterContext *WC) {
for (auto &I : *Reader) {
const StringRef FuncName = I.Name;
- if (Error E = WC->Writer.addRecord(std::move(I), Input.Weight)) {
+ bool Reported = false;
+ WC->Writer.addRecord(std::move(I), Input.Weight, [&](Error E) {
+ if (Reported) {
+ consumeError(std::move(E));
+ return;
+ }
+ Reported = true;
// Only show hint the first time an error occurs.
instrprof_error IPE = InstrProfError::take(std::move(E));
std::unique_lock<std::mutex> ErrGuard{WC->ErrLock};
bool firstTime = WC->WriterErrorCodes.insert(IPE).second;
handleMergeWriterError(make_error<InstrProfError>(IPE), Input.Filename,
FuncName, firstTime);
- }
+ });
}
if (Reader->hasError())
WC->Err = Reader->getError();
@@ -174,8 +180,15 @@ static void loadInput(const WeightedFile &Input, WriterContext *WC) {
/// Merge the \p Src writer context into \p Dst.
static void mergeWriterContexts(WriterContext *Dst, WriterContext *Src) {
- if (Error E = Dst->Writer.mergeRecordsFromWriter(std::move(Src->Writer)))
+ bool Reported = false;
+ Dst->Writer.mergeRecordsFromWriter(std::move(Src->Writer), [&](Error E) {
+ if (Reported) {
+ consumeError(std::move(E));
+ return;
+ }
+ Reported = true;
Dst->Err = std::move(E);
+ });
}
static void mergeInstrProfile(const WeightedFileVector &Inputs,
@@ -246,10 +259,12 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
exitWithError(std::move(WC->Err), WC->ErrWhence);
InstrProfWriter &Writer = Contexts[0]->Writer;
- if (OutputFormat == PF_Text)
- Writer.writeText(Output);
- else
+ if (OutputFormat == PF_Text) {
+ if (Error E = Writer.writeText(Output))
+ exitWithError(std::move(E));
+ } else {
Writer.write(Output);
+ }
}
static sampleprof::SampleProfileFormat FormatMap[] = {
@@ -446,9 +461,59 @@ static int merge_main(int argc, const char *argv[]) {
return 0;
}
+typedef struct ValueSitesStats {
+ ValueSitesStats()
+ : TotalNumValueSites(0), TotalNumValueSitesWithValueProfile(0),
+ TotalNumValues(0) {}
+ uint64_t TotalNumValueSites;
+ uint64_t TotalNumValueSitesWithValueProfile;
+ uint64_t TotalNumValues;
+ std::vector<unsigned> ValueSitesHistogram;
+} ValueSitesStats;
+
+static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
+ ValueSitesStats &Stats, raw_fd_ostream &OS,
+ InstrProfSymtab *Symtab) {
+ uint32_t NS = Func.getNumValueSites(VK);
+ Stats.TotalNumValueSites += NS;
+ for (size_t I = 0; I < NS; ++I) {
+ uint32_t NV = Func.getNumValueDataForSite(VK, I);
+ std::unique_ptr<InstrProfValueData[]> VD = Func.getValueForSite(VK, I);
+ Stats.TotalNumValues += NV;
+ if (NV) {
+ Stats.TotalNumValueSitesWithValueProfile++;
+ if (NV > Stats.ValueSitesHistogram.size())
+ Stats.ValueSitesHistogram.resize(NV, 0);
+ Stats.ValueSitesHistogram[NV - 1]++;
+ }
+ for (uint32_t V = 0; V < NV; V++) {
+ OS << "\t[ " << I << ", ";
+ if (Symtab == nullptr)
+ OS << VD[V].Value;
+ else
+ OS << Symtab->getFuncName(VD[V].Value);
+ OS << ", " << VD[V].Count << " ]\n";
+ }
+ }
+}
+
+static void showValueSitesStats(raw_fd_ostream &OS, uint32_t VK,
+ ValueSitesStats &Stats) {
+ OS << " Total number of sites: " << Stats.TotalNumValueSites << "\n";
+ OS << " Total number of sites with values: "
+ << Stats.TotalNumValueSitesWithValueProfile << "\n";
+ OS << " Total number of profiled values: " << Stats.TotalNumValues << "\n";
+
+ OS << " Value sites histogram:\n\tNumTargets, SiteCount\n";
+ for (unsigned I = 0; I < Stats.ValueSitesHistogram.size(); I++) {
+ if (Stats.ValueSitesHistogram[I] > 0)
+ OS << "\t" << I + 1 << ", " << Stats.ValueSitesHistogram[I] << "\n";
+ }
+}
+
static int showInstrProfile(const std::string &Filename, bool ShowCounts,
- bool ShowIndirectCallTargets,
- bool ShowDetailedSummary,
+ uint32_t TopN, bool ShowIndirectCallTargets,
+ bool ShowMemOPSizes, bool ShowDetailedSummary,
std::vector<uint32_t> DetailedSummaryCutoffs,
bool ShowAllFunctions,
const std::string &ShowFunction, bool TextFormat,
@@ -465,10 +530,19 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
auto Reader = std::move(ReaderOrErr.get());
bool IsIRInstr = Reader->isIRLevelProfile();
size_t ShownFunctions = 0;
- uint64_t TotalNumValueSites = 0;
- uint64_t TotalNumValueSitesWithValueProfile = 0;
- uint64_t TotalNumValues = 0;
- std::vector<unsigned> ICHistogram;
+ int NumVPKind = IPVK_Last - IPVK_First + 1;
+ std::vector<ValueSitesStats> VPStats(NumVPKind);
+
+ auto MinCmp = [](const std::pair<std::string, uint64_t> &v1,
+ const std::pair<std::string, uint64_t> &v2) {
+ return v1.second > v2.second;
+ };
+
+ std::priority_queue<std::pair<std::string, uint64_t>,
+ std::vector<std::pair<std::string, uint64_t>>,
+ decltype(MinCmp)>
+ HottestFuncs(MinCmp);
+
for (const auto &Func : *Reader) {
bool Show =
ShowAllFunctions || (!ShowFunction.empty() &&
@@ -478,13 +552,28 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
if (doTextFormatDump) {
InstrProfSymtab &Symtab = Reader->getSymtab();
- InstrProfWriter::writeRecordInText(Func, Symtab, OS);
+ InstrProfWriter::writeRecordInText(Func.Name, Func.Hash, Func, Symtab,
+ OS);
continue;
}
assert(Func.Counts.size() > 0 && "function missing entry counter");
Builder.addRecord(Func);
+ if (TopN) {
+ uint64_t FuncMax = 0;
+ for (size_t I = 0, E = Func.Counts.size(); I < E; ++I)
+ FuncMax = std::max(FuncMax, Func.Counts[I]);
+
+ if (HottestFuncs.size() == TopN) {
+ if (HottestFuncs.top().second < FuncMax) {
+ HottestFuncs.pop();
+ HottestFuncs.emplace(std::make_pair(std::string(Func.Name), FuncMax));
+ }
+ } else
+ HottestFuncs.emplace(std::make_pair(std::string(Func.Name), FuncMax));
+ }
+
if (Show) {
if (!ShownFunctions)
@@ -502,6 +591,11 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
OS << " Indirect Call Site Count: "
<< Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n";
+ uint32_t NumMemOPCalls = Func.getNumValueSites(IPVK_MemOPSize);
+ if (ShowMemOPSizes && NumMemOPCalls > 0)
+ OS << " Number of Memory Intrinsics Calls: " << NumMemOPCalls
+ << "\n";
+
if (ShowCounts) {
OS << " Block counts: [";
size_t Start = (IsIRInstr ? 0 : 1);
@@ -512,27 +606,16 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
}
if (ShowIndirectCallTargets) {
- InstrProfSymtab &Symtab = Reader->getSymtab();
- uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget);
- OS << " Indirect Target Results: \n";
- TotalNumValueSites += NS;
- for (size_t I = 0; I < NS; ++I) {
- uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I);
- std::unique_ptr<InstrProfValueData[]> VD =
- Func.getValueForSite(IPVK_IndirectCallTarget, I);
- TotalNumValues += NV;
- if (NV) {
- TotalNumValueSitesWithValueProfile++;
- if (NV > ICHistogram.size())
- ICHistogram.resize(NV, 0);
- ICHistogram[NV - 1]++;
- }
- for (uint32_t V = 0; V < NV; V++) {
- OS << "\t[ " << I << ", ";
- OS << Symtab.getFuncName(VD[V].Value) << ", " << VD[V].Count
- << " ]\n";
- }
- }
+ OS << " Indirect Target Results:\n";
+ traverseAllValueSites(Func, IPVK_IndirectCallTarget,
+ VPStats[IPVK_IndirectCallTarget], OS,
+ &(Reader->getSymtab()));
+ }
+
+ if (ShowMemOPSizes && NumMemOPCalls > 0) {
+ OS << " Memory Intrinsic Size Results:\n";
+ traverseAllValueSites(Func, IPVK_MemOPSize, VPStats[IPVK_MemOPSize], OS,
+ nullptr);
}
}
}
@@ -547,17 +630,28 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
OS << "Total functions: " << PS->getNumFunctions() << "\n";
OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n";
OS << "Maximum internal block count: " << PS->getMaxInternalCount() << "\n";
- if (ShownFunctions && ShowIndirectCallTargets) {
- OS << "Total Number of Indirect Call Sites : " << TotalNumValueSites
- << "\n";
- OS << "Total Number of Sites With Values : "
- << TotalNumValueSitesWithValueProfile << "\n";
- OS << "Total Number of Profiled Values : " << TotalNumValues << "\n";
-
- OS << "IC Value histogram : \n\tNumTargets, SiteCount\n";
- for (unsigned I = 0; I < ICHistogram.size(); I++) {
- OS << "\t" << I + 1 << ", " << ICHistogram[I] << "\n";
+
+ if (TopN) {
+ std::vector<std::pair<std::string, uint64_t>> SortedHottestFuncs;
+ while (!HottestFuncs.empty()) {
+ SortedHottestFuncs.emplace_back(HottestFuncs.top());
+ HottestFuncs.pop();
}
+ OS << "Top " << TopN
+ << " functions with the largest internal block counts: \n";
+ for (auto &hotfunc : llvm::reverse(SortedHottestFuncs))
+ OS << " " << hotfunc.first << ", max count = " << hotfunc.second << "\n";
+ }
+
+ if (ShownFunctions && ShowIndirectCallTargets) {
+ OS << "Statistics for indirect call sites profile:\n";
+ showValueSitesStats(OS, IPVK_IndirectCallTarget,
+ VPStats[IPVK_IndirectCallTarget]);
+ }
+
+ if (ShownFunctions && ShowMemOPSizes) {
+ OS << "Statistics for memory intrinsic calls sizes profile:\n";
+ showValueSitesStats(OS, IPVK_MemOPSize, VPStats[IPVK_MemOPSize]);
}
if (ShowDetailedSummary) {
@@ -608,6 +702,10 @@ static int show_main(int argc, const char *argv[]) {
cl::opt<bool> ShowIndirectCallTargets(
"ic-targets", cl::init(false),
cl::desc("Show indirect call site target values for shown functions"));
+ cl::opt<bool> ShowMemOPSizes(
+ "memop-sizes", cl::init(false),
+ cl::desc("Show the profiled sizes of the memory intrinsic calls "
+ "for shown functions"));
cl::opt<bool> ShowDetailedSummary("detailed-summary", cl::init(false),
cl::desc("Show detailed profile summary"));
cl::list<uint32_t> DetailedSummaryCutoffs(
@@ -628,6 +726,9 @@ static int show_main(int argc, const char *argv[]) {
cl::desc("Profile kind:"), cl::init(instr),
cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
clEnumVal(sample, "Sample profile")));
+ cl::opt<uint32_t> TopNFunctions(
+ "topn", cl::init(0),
+ cl::desc("Show the list of functions with the largest internal counts"));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
@@ -645,7 +746,8 @@ static int show_main(int argc, const char *argv[]) {
std::vector<uint32_t> Cutoffs(DetailedSummaryCutoffs.begin(),
DetailedSummaryCutoffs.end());
if (ProfileKind == instr)
- return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets,
+ return showInstrProfile(Filename, ShowCounts, TopNFunctions,
+ ShowIndirectCallTargets, ShowMemOPSizes,
ShowDetailedSummary, DetailedSummaryCutoffs,
ShowAllFunctions, ShowFunction, TextFormat, OS);
else
diff --git a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp
deleted file mode 100644
index 877dd71..0000000
--- a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp
+++ /dev/null
@@ -1,682 +0,0 @@
-//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ARMAttributeParser.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/ScopedPrinter.h"
-
-using namespace llvm;
-using namespace llvm::ARMBuildAttrs;
-
-
-static const EnumEntry<unsigned> TagNames[] = {
- { "Tag_File", ARMBuildAttrs::File },
- { "Tag_Section", ARMBuildAttrs::Section },
- { "Tag_Symbol", ARMBuildAttrs::Symbol },
-};
-
-namespace llvm {
-#define ATTRIBUTE_HANDLER(Attr_) \
- { ARMBuildAttrs::Attr_, &ARMAttributeParser::Attr_ }
-
-const ARMAttributeParser::DisplayHandler
-ARMAttributeParser::DisplayRoutines[] = {
- { ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::StringAttribute, },
- { ARMBuildAttrs::CPU_name, &ARMAttributeParser::StringAttribute },
- ATTRIBUTE_HANDLER(CPU_arch),
- ATTRIBUTE_HANDLER(CPU_arch_profile),
- ATTRIBUTE_HANDLER(ARM_ISA_use),
- ATTRIBUTE_HANDLER(THUMB_ISA_use),
- ATTRIBUTE_HANDLER(FP_arch),
- ATTRIBUTE_HANDLER(WMMX_arch),
- ATTRIBUTE_HANDLER(Advanced_SIMD_arch),
- ATTRIBUTE_HANDLER(PCS_config),
- ATTRIBUTE_HANDLER(ABI_PCS_R9_use),
- ATTRIBUTE_HANDLER(ABI_PCS_RW_data),
- ATTRIBUTE_HANDLER(ABI_PCS_RO_data),
- ATTRIBUTE_HANDLER(ABI_PCS_GOT_use),
- ATTRIBUTE_HANDLER(ABI_PCS_wchar_t),
- ATTRIBUTE_HANDLER(ABI_FP_rounding),
- ATTRIBUTE_HANDLER(ABI_FP_denormal),
- ATTRIBUTE_HANDLER(ABI_FP_exceptions),
- ATTRIBUTE_HANDLER(ABI_FP_user_exceptions),
- ATTRIBUTE_HANDLER(ABI_FP_number_model),
- ATTRIBUTE_HANDLER(ABI_align_needed),
- ATTRIBUTE_HANDLER(ABI_align_preserved),
- ATTRIBUTE_HANDLER(ABI_enum_size),
- ATTRIBUTE_HANDLER(ABI_HardFP_use),
- ATTRIBUTE_HANDLER(ABI_VFP_args),
- ATTRIBUTE_HANDLER(ABI_WMMX_args),
- ATTRIBUTE_HANDLER(ABI_optimization_goals),
- ATTRIBUTE_HANDLER(ABI_FP_optimization_goals),
- ATTRIBUTE_HANDLER(compatibility),
- ATTRIBUTE_HANDLER(CPU_unaligned_access),
- ATTRIBUTE_HANDLER(FP_HP_extension),
- ATTRIBUTE_HANDLER(ABI_FP_16bit_format),
- ATTRIBUTE_HANDLER(MPextension_use),
- ATTRIBUTE_HANDLER(DIV_use),
- ATTRIBUTE_HANDLER(DSP_extension),
- ATTRIBUTE_HANDLER(T2EE_use),
- ATTRIBUTE_HANDLER(Virtualization_use),
- ATTRIBUTE_HANDLER(nodefaults)
-};
-
-#undef ATTRIBUTE_HANDLER
-
-uint64_t ARMAttributeParser::ParseInteger(const uint8_t *Data,
- uint32_t &Offset) {
- unsigned Length;
- uint64_t Value = decodeULEB128(Data + Offset, &Length);
- Offset = Offset + Length;
- return Value;
-}
-
-StringRef ARMAttributeParser::ParseString(const uint8_t *Data,
- uint32_t &Offset) {
- const char *String = reinterpret_cast<const char*>(Data + Offset);
- size_t Length = std::strlen(String);
- Offset = Offset + Length + 1;
- return StringRef(String, Length);
-}
-
-void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- SW.printNumber(ARMBuildAttrs::AttrTypeAsString(Tag),
- ParseInteger(Data, Offset));
-}
-
-void ARMAttributeParser::StringAttribute(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false);
-
- DictScope AS(SW, "Attribute");
- SW.printNumber("Tag", Tag);
- if (!TagName.empty())
- SW.printString("TagName", TagName);
- SW.printString("Value", ParseString(Data, Offset));
-}
-
-void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value,
- StringRef ValueDesc) {
- StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false);
-
- DictScope AS(SW, "Attribute");
- SW.printNumber("Tag", Tag);
- SW.printNumber("Value", Value);
- if (!TagName.empty())
- SW.printString("TagName", TagName);
- if (!ValueDesc.empty())
- SW.printString("Description", ValueDesc);
-}
-
-void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6",
- "ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M",
- "ARM v7E-M", "ARM v8"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- uint64_t Encoded = ParseInteger(Data, Offset);
-
- StringRef Profile;
- switch (Encoded) {
- default: Profile = "Unknown"; break;
- case 'A': Profile = "Application"; break;
- case 'R': Profile = "Real-time"; break;
- case 'M': Profile = "Microcontroller"; break;
- case 'S': Profile = "Classic"; break;
- case 0: Profile = "None"; break;
- }
-
- PrintAttribute(Tag, Encoded, Profile);
-}
-
-void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4",
- "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON", "ARMv8.1-a NEON"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004",
- "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "v6", "Static Base", "TLS", "Unused" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Absolute", "PC-relative", "SB-relative", "Not Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Absolute", "PC-relative", "Not Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Direct", "GOT-Indirect"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "IEEE-754", "Runtime" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Unsupported", "IEEE-754", "Sign Only"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "IEEE-754" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag,
- const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "IEEE-754" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Finite Only", "RTABI", "IEEE-754"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
-
- std::string Description;
- if (Value < array_lengthof(Strings))
- Description = std::string(Strings[Value]);
- else if (Value <= 12)
- Description = std::string("8-byte alignment, ") + utostr(1ULL << Value)
- + std::string("-byte extended alignment");
- else
- Description = "Invalid";
-
- PrintAttribute(Tag, Value, Description);
-}
-
-void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Required", "8-byte data alignment", "8-byte data and code alignment",
- "Reserved"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
-
- std::string Description;
- if (Value < array_lengthof(Strings))
- Description = std::string(Strings[Value]);
- else if (Value <= 12)
- Description = std::string("8-byte stack alignment, ") +
- utostr(1ULL << Value) + std::string("-byte data alignment");
- else
- Description = "Invalid";
-
- PrintAttribute(Tag, Value, Description);
-}
-
-void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Packed", "Int32", "External Int32"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "AAPCS", "AAPCS VFP", "Custom", "Not Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "AAPCS", "iWMMX", "Custom" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_optimization_goals(AttrType Tag,
- const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging",
- "Best Debugging"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag,
- const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Accuracy",
- "Best Accuracy"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- uint64_t Integer = ParseInteger(Data, Offset);
- StringRef String = ParseString(Data, Offset);
-
- DictScope AS(SW, "Attribute");
- SW.printNumber("Tag", Tag);
- SW.startLine() << "Value: " << Integer << ", " << String << '\n';
- SW.printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false));
- switch (Integer) {
- case 0:
- SW.printString("Description", StringRef("No Specific Requirements"));
- break;
- case 1:
- SW.printString("Description", StringRef("AEABI Conformant"));
- break;
- default:
- SW.printString("Description", StringRef("AEABI Non-Conformant"));
- break;
- }
-}
-
-void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "v6-style" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "If Available", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "If Available", "Not Permitted", "Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::DSP_extension(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "TrustZone", "Virtualization Extensions",
- "TrustZone + Virtualization Extensions"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::nodefaults(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- uint64_t Value = ParseInteger(Data, Offset);
- PrintAttribute(Tag, Value, "Unspecified Tags UNDEFINED");
-}
-
-void ARMAttributeParser::ParseIndexList(const uint8_t *Data, uint32_t &Offset,
- SmallVectorImpl<uint8_t> &IndexList) {
- for (;;) {
- unsigned Length;
- uint64_t Value = decodeULEB128(Data + Offset, &Length);
- Offset = Offset + Length;
- if (Value == 0)
- break;
- IndexList.push_back(Value);
- }
-}
-
-void ARMAttributeParser::ParseAttributeList(const uint8_t *Data,
- uint32_t &Offset, uint32_t Length) {
- while (Offset < Length) {
- unsigned Length;
- uint64_t Tag = decodeULEB128(Data + Offset, &Length);
- Offset += Length;
-
- bool Handled = false;
- for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines);
- AHI != AHE && !Handled; ++AHI) {
- if (DisplayRoutines[AHI].Attribute == Tag) {
- (this->*DisplayRoutines[AHI].Routine)(ARMBuildAttrs::AttrType(Tag),
- Data, Offset);
- Handled = true;
- break;
- }
- }
- if (!Handled) {
- if (Tag < 32) {
- errs() << "unhandled AEABI Tag " << Tag
- << " (" << ARMBuildAttrs::AttrTypeAsString(Tag) << ")\n";
- continue;
- }
-
- if (Tag % 2 == 0)
- IntegerAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
- else
- StringAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
- }
- }
-}
-
-void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) {
- uint32_t Offset = sizeof(uint32_t); /* SectionLength */
-
- SW.printNumber("SectionLength", Length);
-
- const char *VendorName = reinterpret_cast<const char*>(Data + Offset);
- size_t VendorNameLength = std::strlen(VendorName);
- SW.printString("Vendor", StringRef(VendorName, VendorNameLength));
- Offset = Offset + VendorNameLength + 1;
-
- if (StringRef(VendorName, VendorNameLength).lower() != "aeabi")
- return;
-
- while (Offset < Length) {
- /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
- uint8_t Tag = Data[Offset];
- SW.printEnum("Tag", Tag, makeArrayRef(TagNames));
- Offset = Offset + sizeof(Tag);
-
- uint32_t Size =
- *reinterpret_cast<const support::ulittle32_t*>(Data + Offset);
- SW.printNumber("Size", Size);
- Offset = Offset + sizeof(Size);
-
- if (Size > Length) {
- errs() << "subsection length greater than section length\n";
- return;
- }
-
- StringRef ScopeName, IndexName;
- SmallVector<uint8_t, 8> Indicies;
- switch (Tag) {
- case ARMBuildAttrs::File:
- ScopeName = "FileAttributes";
- break;
- case ARMBuildAttrs::Section:
- ScopeName = "SectionAttributes";
- IndexName = "Sections";
- ParseIndexList(Data, Offset, Indicies);
- break;
- case ARMBuildAttrs::Symbol:
- ScopeName = "SymbolAttributes";
- IndexName = "Symbols";
- ParseIndexList(Data, Offset, Indicies);
- break;
- default:
- errs() << "unrecognised tag: 0x" << utohexstr(Tag) << '\n';
- return;
- }
-
- DictScope ASS(SW, ScopeName);
-
- if (!Indicies.empty())
- SW.printList(IndexName, Indicies);
-
- ParseAttributeList(Data, Offset, Length);
- }
-}
-
-void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section) {
- size_t Offset = 1;
- unsigned SectionNumber = 0;
-
- while (Offset < Section.size()) {
- uint32_t SectionLength =
- *reinterpret_cast<const support::ulittle32_t*>(Section.data() + Offset);
-
- SW.startLine() << "Section " << ++SectionNumber << " {\n";
- SW.indent();
-
- ParseSubsection(Section.data() + Offset, SectionLength);
- Offset = Offset + SectionLength;
-
- SW.unindent();
- SW.startLine() << "}\n";
- }
-}
-}
-
diff --git a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h
deleted file mode 100644
index 6936b70..0000000
--- a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.h
+++ /dev/null
@@ -1,126 +0,0 @@
-//===--- ARMAttributeParser.h - ARM Attribute Information Printer ---------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H
-#define LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H
-
-#include "llvm/Support/ARMBuildAttributes.h"
-#include "llvm/Support/ScopedPrinter.h"
-
-namespace llvm {
-class StringRef;
-
-class ARMAttributeParser {
- ScopedPrinter &SW;
-
- struct DisplayHandler {
- ARMBuildAttrs::AttrType Attribute;
- void (ARMAttributeParser::*Routine)(ARMBuildAttrs::AttrType,
- const uint8_t *, uint32_t &);
- };
- static const DisplayHandler DisplayRoutines[];
-
- uint64_t ParseInteger(const uint8_t *Data, uint32_t &Offset);
- StringRef ParseString(const uint8_t *Data, uint32_t &Offset);
-
- void IntegerAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void StringAttribute(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
-
- void PrintAttribute(unsigned Tag, unsigned Value, StringRef ValueDesc);
-
- void CPU_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void CPU_arch_profile(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ARM_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void THUMB_ISA_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void FP_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void WMMX_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void Advanced_SIMD_arch(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void PCS_config(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_R9_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_RW_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_RO_data(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_GOT_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_PCS_wchar_t(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_rounding(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_denormal(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_user_exceptions(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_number_model(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_align_needed(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_align_preserved(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_enum_size(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_HardFP_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_VFP_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_WMMX_args(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_optimization_goals(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_optimization_goals(ARMBuildAttrs::AttrType Tag,
- const uint8_t *Data, uint32_t &Offset);
- void compatibility(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void CPU_unaligned_access(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void FP_HP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void ABI_FP_16bit_format(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void MPextension_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void DIV_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void DSP_extension(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void T2EE_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void Virtualization_use(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
- void nodefaults(ARMBuildAttrs::AttrType Tag, const uint8_t *Data,
- uint32_t &Offset);
-
- void ParseAttributeList(const uint8_t *Data, uint32_t &Offset,
- uint32_t Length);
- void ParseIndexList(const uint8_t *Data, uint32_t &Offset,
- SmallVectorImpl<uint8_t> &IndexList);
- void ParseSubsection(const uint8_t *Data, uint32_t Length);
-public:
- ARMAttributeParser(ScopedPrinter &SW) : SW(SW) {}
-
- void Parse(ArrayRef<uint8_t> Section);
-};
-
-}
-
-#endif
-
diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp
index c83655f..74c4411 100644
--- a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -13,7 +13,6 @@
//===----------------------------------------------------------------------===//
#include "ARMWinEHPrinter.h"
-#include "CodeView.h"
#include "Error.h"
#include "ObjDumper.h"
#include "StackMapPrinter.h"
@@ -22,8 +21,15 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
@@ -35,14 +41,16 @@
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/COFF.h"
+#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/DataExtractor.h"
-#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Win64EH.h"
@@ -55,17 +63,24 @@
using namespace llvm;
using namespace llvm::object;
using namespace llvm::codeview;
-using namespace llvm::msf;
using namespace llvm::support;
using namespace llvm::Win64EH;
namespace {
+struct LoadConfigTables {
+ uint64_t SEHTableVA = 0;
+ uint64_t SEHTableCount = 0;
+ uint32_t GuardFlags = 0;
+ uint64_t GuardFidTableVA = 0;
+ uint64_t GuardFidTableCount = 0;
+};
+
class COFFDumper : public ObjDumper {
public:
friend class COFFObjectDumpDelegate;
COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer)
- : ObjDumper(Writer), Obj(Obj), Writer(Writer) {}
+ : ObjDumper(Writer), Obj(Obj), Writer(Writer), Types(100) {}
void printFileHeaders() override;
void printSections() override;
@@ -78,8 +93,11 @@ public:
void printCOFFDirectives() override;
void printCOFFBaseReloc() override;
void printCOFFDebugDirectory() override;
+ void printCOFFResources() override;
+ void printCOFFLoadConfig() override;
void printCodeViewDebugInfo() override;
- void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) override;
+ void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
+ llvm::codeview::TypeTableBuilder &CVTypes) override;
void printStackMap() const override;
private:
void printSymbol(const SymbolRef &Sym);
@@ -91,6 +109,11 @@ private:
template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
void printBaseOfDataField(const pe32_header *Hdr);
void printBaseOfDataField(const pe32plus_header *Hdr);
+ template <typename T>
+ void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables);
+ typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *);
+ void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize,
+ PrintExtraCB PrintExtra = 0);
void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section);
void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section);
@@ -99,7 +122,7 @@ private:
void printFileNameForOffset(StringRef Label, uint32_t FileOffset);
void printTypeIndex(StringRef FieldName, TypeIndex TI) {
// Forward to CVTypeDumper for simplicity.
- CVTypeDumper::printTypeIndex(Writer, FieldName, TI, TypeDB);
+ codeview::printTypeIndex(Writer, FieldName, TI, Types);
}
void printCodeViewSymbolsSubsection(StringRef Subsection,
@@ -114,11 +137,19 @@ private:
uint32_t RelocOffset, uint32_t Offset,
StringRef *RelocSym = nullptr);
+ uint32_t countTotalTableEntries(ResourceSectionRef RSF,
+ const coff_resource_dir_table &Table,
+ StringRef Level);
+
+ void printResourceDirectoryTable(ResourceSectionRef RSF,
+ const coff_resource_dir_table &Table,
+ StringRef Level);
+
void printBinaryBlockWithRelocs(StringRef Label, const SectionRef &Sec,
StringRef SectionContents, StringRef Block);
/// Given a .debug$S section, find the string table and file checksum table.
- void initializeFileAndStringTables(StringRef Data);
+ void initializeFileAndStringTables(BinaryStreamReader &Reader);
void cacheRelocations();
@@ -133,17 +164,23 @@ private:
void printDelayImportedSymbols(
const DelayImportDirectoryEntryRef &I,
iterator_range<imported_symbol_iterator> Range);
+ ErrorOr<const coff_resource_dir_entry &>
+ getResourceDirectoryTableEntry(const coff_resource_dir_table &Table,
+ uint32_t Index);
typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
const llvm::object::COFFObjectFile *Obj;
bool RelocCached = false;
RelocMapTy RelocMap;
- StringRef CVFileChecksumTable;
- StringRef CVStringTable;
+
+ DebugChecksumsSubsectionRef CVFileChecksumTable;
+
+ DebugStringTableSubsectionRef CVStringTable;
ScopedPrinter &Writer;
- TypeDatabase TypeDB;
+ BinaryByteStream TypeContents;
+ LazyRandomTypeCollection Types;
};
class COFFObjectDumpDelegate : public SymbolDumpDelegate {
@@ -154,7 +191,7 @@ public:
Sec = Obj->getCOFFSection(SR);
}
- uint32_t getRecordOffset(msf::StreamReader Reader) override {
+ uint32_t getRecordOffset(BinaryStreamReader Reader) override {
ArrayRef<uint8_t> Data;
if (auto EC = Reader.readLongestContiguousChunk(Data)) {
llvm::consumeError(std::move(EC));
@@ -180,7 +217,9 @@ public:
return CD.getFileNameForFileOffset(FileOffset);
}
- StringRef getStringTable() override { return CD.CVStringTable; }
+ DebugStringTableSubsectionRef getStringTable() override {
+ return CD.CVStringTable;
+ }
private:
COFFDumper &CD;
@@ -296,6 +335,7 @@ static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = {
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64 ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ),
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ),
@@ -495,19 +535,19 @@ WeakExternalCharacteristics[] = {
};
static const EnumEntry<uint32_t> SubSectionTypes[] = {
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Symbols),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Lines),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, StringTable),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, FileChecksums),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, FrameData),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, InlineeLines),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeImports),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CrossScopeExports),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, ILLines),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, FuncMDTokenMap),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, TypeMDTokenMap),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, MergedAssemblyInput),
- LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CoffSymbolRVA),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, Symbols),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, Lines),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, StringTable),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, FileChecksums),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, FrameData),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, InlineeLines),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeImports),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeExports),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, ILLines),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, FuncMDTokenMap),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, TypeMDTokenMap),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, MergedAssemblyInput),
+ LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, CoffSymbolRVA),
};
static const EnumEntry<uint32_t> FrameDataFlags[] = {
@@ -523,6 +563,29 @@ static const EnumEntry<uint8_t> FileChecksumKindNames[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
};
+static const EnumEntry<COFF::ResourceTypeID> ResourceTypeNames[]{
+ {"kRT_CURSOR (ID 1)", COFF::RID_Cursor},
+ {"kRT_BITMAP (ID 2)", COFF::RID_Bitmap},
+ {"kRT_ICON (ID 3)", COFF::RID_Icon},
+ {"kRT_MENU (ID 4)", COFF::RID_Menu},
+ {"kRT_DIALOG (ID 5)", COFF::RID_Dialog},
+ {"kRT_STRING (ID 6)", COFF::RID_String},
+ {"kRT_FONTDIR (ID 7)", COFF::RID_FontDir},
+ {"kRT_FONT (ID 8)", COFF::RID_Font},
+ {"kRT_ACCELERATOR (ID 9)", COFF::RID_Accelerator},
+ {"kRT_RCDATA (ID 10)", COFF::RID_RCData},
+ {"kRT_MESSAGETABLE (ID 11)", COFF::RID_MessageTable},
+ {"kRT_GROUP_CURSOR (ID 12)", COFF::RID_Group_Cursor},
+ {"kRT_GROUP_ICON (ID 14)", COFF::RID_Group_Icon},
+ {"kRT_VERSION (ID 16)", COFF::RID_Version},
+ {"kRT_DLGINCLUDE (ID 17)", COFF::RID_DLGInclude},
+ {"kRT_PLUGPLAY (ID 19)", COFF::RID_PlugPlay},
+ {"kRT_VXD (ID 20)", COFF::RID_VXD},
+ {"kRT_ANICURSOR (ID 21)", COFF::RID_AniCursor},
+ {"kRT_ANIICON (ID 22)", COFF::RID_AniIcon},
+ {"kRT_HTML (ID 23)", COFF::RID_HTML},
+ {"kRT_MANIFEST (ID 24)", COFF::RID_Manifest}};
+
template <typename T>
static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
COFFSymbolRef Symbol,
@@ -616,6 +679,7 @@ void COFFDumper::printDOSHeader(const dos_header *DH) {
template <class PEHeader>
void COFFDumper::printPEHeader(const PEHeader *Hdr) {
DictScope D(W, "ImageOptionalHeader");
+ W.printHex ("Magic", Hdr->Magic);
W.printNumber("MajorLinkerVersion", Hdr->MajorLinkerVersion);
W.printNumber("MinorLinkerVersion", Hdr->MinorLinkerVersion);
W.printNumber("SizeOfCode", Hdr->SizeOfCode);
@@ -697,6 +761,129 @@ void COFFDumper::printCOFFDebugDirectory() {
}
}
+void COFFDumper::printRVATable(uint64_t TableVA, uint64_t Count,
+ uint64_t EntrySize, PrintExtraCB PrintExtra) {
+ uintptr_t TableStart, TableEnd;
+ error(Obj->getVaPtr(TableVA, TableStart));
+ error(Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd));
+ TableEnd++;
+ for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) {
+ uint32_t RVA = *reinterpret_cast<const ulittle32_t *>(I);
+ raw_ostream &OS = W.startLine();
+ OS << "0x" << utohexstr(Obj->getImageBase() + RVA);
+ if (PrintExtra)
+ PrintExtra(OS, reinterpret_cast<const uint8_t *>(I));
+ OS << '\n';
+ }
+}
+
+void COFFDumper::printCOFFLoadConfig() {
+ LoadConfigTables Tables;
+ if (Obj->is64())
+ printCOFFLoadConfig(Obj->getLoadConfig64(), Tables);
+ else
+ printCOFFLoadConfig(Obj->getLoadConfig32(), Tables);
+
+ if (Tables.SEHTableVA) {
+ ListScope LS(W, "SEHTable");
+ printRVATable(Tables.SEHTableVA, Tables.SEHTableCount, 4);
+ }
+
+ if (Tables.GuardFidTableVA) {
+ ListScope LS(W, "GuardFidTable");
+ if (Tables.GuardFlags & uint32_t(coff_guard_flags::FidTableHasFlags)) {
+ auto PrintGuardFlags = [](raw_ostream &OS, const uint8_t *Entry) {
+ uint8_t Flags = *reinterpret_cast<const uint8_t *>(Entry + 4);
+ if (Flags)
+ OS << " flags " << utohexstr(Flags);
+ };
+ printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 5,
+ PrintGuardFlags);
+ } else {
+ printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 4);
+ }
+ }
+}
+
+template <typename T>
+void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
+ if (!Conf)
+ return;
+
+ ListScope LS(W, "LoadConfig");
+ char FormattedTime[20] = {};
+ time_t TDS = Conf->TimeDateStamp;
+ strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+ W.printHex("Size", Conf->Size);
+
+ // Print everything before SecurityCookie. The vast majority of images today
+ // have all these fields.
+ if (Conf->Size < offsetof(T, SEHandlerTable))
+ return;
+ W.printHex("TimeDateStamp", FormattedTime, TDS);
+ W.printHex("MajorVersion", Conf->MajorVersion);
+ W.printHex("MinorVersion", Conf->MinorVersion);
+ W.printHex("GlobalFlagsClear", Conf->GlobalFlagsClear);
+ W.printHex("GlobalFlagsSet", Conf->GlobalFlagsSet);
+ W.printHex("CriticalSectionDefaultTimeout",
+ Conf->CriticalSectionDefaultTimeout);
+ W.printHex("DeCommitFreeBlockThreshold", Conf->DeCommitFreeBlockThreshold);
+ W.printHex("DeCommitTotalFreeThreshold", Conf->DeCommitTotalFreeThreshold);
+ W.printHex("LockPrefixTable", Conf->LockPrefixTable);
+ W.printHex("MaximumAllocationSize", Conf->MaximumAllocationSize);
+ W.printHex("VirtualMemoryThreshold", Conf->VirtualMemoryThreshold);
+ W.printHex("ProcessHeapFlags", Conf->ProcessHeapFlags);
+ W.printHex("ProcessAffinityMask", Conf->ProcessAffinityMask);
+ W.printHex("CSDVersion", Conf->CSDVersion);
+ W.printHex("DependentLoadFlags", Conf->DependentLoadFlags);
+ W.printHex("EditList", Conf->EditList);
+ W.printHex("SecurityCookie", Conf->SecurityCookie);
+
+ // Print the safe SEH table if present.
+ if (Conf->Size < offsetof(coff_load_configuration32, GuardCFCheckFunction))
+ return;
+ W.printHex("SEHandlerTable", Conf->SEHandlerTable);
+ W.printNumber("SEHandlerCount", Conf->SEHandlerCount);
+
+ Tables.SEHTableVA = Conf->SEHandlerTable;
+ Tables.SEHTableCount = Conf->SEHandlerCount;
+
+ // Print everything before CodeIntegrity. (2015)
+ if (Conf->Size < offsetof(T, CodeIntegrity))
+ return;
+ W.printHex("GuardCFCheckFunction", Conf->GuardCFCheckFunction);
+ W.printHex("GuardCFCheckDispatch", Conf->GuardCFCheckDispatch);
+ W.printHex("GuardCFFunctionTable", Conf->GuardCFFunctionTable);
+ W.printNumber("GuardCFFunctionCount", Conf->GuardCFFunctionCount);
+ W.printHex("GuardFlags", Conf->GuardFlags);
+
+ Tables.GuardFidTableVA = Conf->GuardCFFunctionTable;
+ Tables.GuardFidTableCount = Conf->GuardCFFunctionCount;
+ Tables.GuardFlags = Conf->GuardFlags;
+
+ // Print the rest. (2017)
+ if (Conf->Size < sizeof(T))
+ return;
+ W.printHex("GuardAddressTakenIatEntryTable",
+ Conf->GuardAddressTakenIatEntryTable);
+ W.printNumber("GuardAddressTakenIatEntryCount",
+ Conf->GuardAddressTakenIatEntryCount);
+ W.printHex("GuardLongJumpTargetTable", Conf->GuardLongJumpTargetTable);
+ W.printNumber("GuardLongJumpTargetCount", Conf->GuardLongJumpTargetCount);
+ W.printHex("DynamicValueRelocTable", Conf->DynamicValueRelocTable);
+ W.printHex("CHPEMetadataPointer", Conf->CHPEMetadataPointer);
+ W.printHex("GuardRFFailureRoutine", Conf->GuardRFFailureRoutine);
+ W.printHex("GuardRFFailureRoutineFunctionPointer",
+ Conf->GuardRFFailureRoutineFunctionPointer);
+ W.printHex("DynamicValueRelocTableOffset",
+ Conf->DynamicValueRelocTableOffset);
+ W.printNumber("DynamicValueRelocTableSection",
+ Conf->DynamicValueRelocTableSection);
+ W.printHex("GuardRFVerifyStackPointerFunctionPointer",
+ Conf->GuardRFVerifyStackPointerFunctionPointer);
+ W.printHex("HotPatchTableOffset", Conf->HotPatchTableOffset);
+}
+
void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
W.printHex("BaseOfData", Hdr->BaseOfData);
}
@@ -719,30 +906,32 @@ void COFFDumper::printCodeViewDebugInfo() {
}
}
-void COFFDumper::initializeFileAndStringTables(StringRef Data) {
- while (!Data.empty() && (CVFileChecksumTable.data() == nullptr ||
- CVStringTable.data() == nullptr)) {
+void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) {
+ while (Reader.bytesRemaining() > 0 &&
+ (!CVFileChecksumTable.valid() || !CVStringTable.valid())) {
// The section consists of a number of subsection in the following format:
// |SubSectionType|SubSectionSize|Contents...|
uint32_t SubType, SubSectionSize;
- error(consume(Data, SubType));
- error(consume(Data, SubSectionSize));
- if (SubSectionSize > Data.size())
- return error(object_error::parse_failed);
- switch (ModuleSubstreamKind(SubType)) {
- case ModuleSubstreamKind::FileChecksums:
- CVFileChecksumTable = Data.substr(0, SubSectionSize);
+ error(Reader.readInteger(SubType));
+ error(Reader.readInteger(SubSectionSize));
+
+ StringRef Contents;
+ error(Reader.readFixedString(Contents, SubSectionSize));
+
+ BinaryStreamRef ST(Contents, support::little);
+ switch (DebugSubsectionKind(SubType)) {
+ case DebugSubsectionKind::FileChecksums:
+ error(CVFileChecksumTable.initialize(ST));
break;
- case ModuleSubstreamKind::StringTable:
- CVStringTable = Data.substr(0, SubSectionSize);
+ case DebugSubsectionKind::StringTable:
+ error(CVStringTable.initialize(ST));
break;
default:
break;
}
+
uint32_t PaddedSize = alignTo(SubSectionSize, 4);
- if (PaddedSize > Data.size())
- error(object_error::parse_failed);
- Data = Data.drop_front(PaddedSize);
+ error(Reader.skip(PaddedSize - SubSectionSize));
}
}
@@ -765,7 +954,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
if (Magic != COFF::DEBUG_SECTION_MAGIC)
return error(object_error::parse_failed);
- initializeFileAndStringTables(Data);
+ BinaryStreamReader FSReader(Data, support::little);
+ initializeFileAndStringTables(FSReader);
// TODO: Convert this over to using ModuleSubstreamVisitor.
while (!Data.empty()) {
@@ -799,20 +989,20 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
printBinaryBlockWithRelocs("SubSectionContents", Section, SectionContents,
Contents);
- switch (ModuleSubstreamKind(SubType)) {
- case ModuleSubstreamKind::Symbols:
+ switch (DebugSubsectionKind(SubType)) {
+ case DebugSubsectionKind::Symbols:
printCodeViewSymbolsSubsection(Contents, Section, SectionContents);
break;
- case ModuleSubstreamKind::InlineeLines:
+ case DebugSubsectionKind::InlineeLines:
printCodeViewInlineeLines(Contents);
break;
- case ModuleSubstreamKind::FileChecksums:
+ case DebugSubsectionKind::FileChecksums:
printCodeViewFileChecksums(Contents);
break;
- case ModuleSubstreamKind::Lines: {
+ case DebugSubsectionKind::Lines: {
// Holds a PC to file:line table. Some data to parse this subsection is
// stored in the other subsections, so just check sanity and store the
// pointers for deferred processing.
@@ -838,39 +1028,33 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
FunctionNames.push_back(LinkageName);
break;
}
- case ModuleSubstreamKind::FrameData: {
+ case DebugSubsectionKind::FrameData: {
// First four bytes is a relocation against the function.
- msf::ByteStream S(Contents);
- msf::StreamReader SR(S);
- const uint32_t *CodePtr;
- error(SR.readObject(CodePtr));
+ BinaryStreamReader SR(Contents, llvm::support::little);
+
+ DebugFrameDataSubsectionRef FrameData;
+ error(FrameData.initialize(SR));
+
StringRef LinkageName;
error(resolveSymbolName(Obj->getCOFFSection(Section), SectionContents,
- CodePtr, LinkageName));
+ FrameData.getRelocPtr(), LinkageName));
W.printString("LinkageName", LinkageName);
// To find the active frame description, search this array for the
// smallest PC range that includes the current PC.
- while (!SR.empty()) {
- const FrameData *FD;
- error(SR.readObject(FD));
-
- if (FD->FrameFunc >= CVStringTable.size())
- error(object_error::parse_failed);
-
- StringRef FrameFunc =
- CVStringTable.drop_front(FD->FrameFunc).split('\0').first;
+ for (const auto &FD : FrameData) {
+ StringRef FrameFunc = error(CVStringTable.getString(FD.FrameFunc));
DictScope S(W, "FrameData");
- W.printHex("RvaStart", FD->RvaStart);
- W.printHex("CodeSize", FD->CodeSize);
- W.printHex("LocalSize", FD->LocalSize);
- W.printHex("ParamsSize", FD->ParamsSize);
- W.printHex("MaxStackSize", FD->MaxStackSize);
+ W.printHex("RvaStart", FD.RvaStart);
+ W.printHex("CodeSize", FD.CodeSize);
+ W.printHex("LocalSize", FD.LocalSize);
+ W.printHex("ParamsSize", FD.ParamsSize);
+ W.printHex("MaxStackSize", FD.MaxStackSize);
W.printString("FrameFunc", FrameFunc);
- W.printHex("PrologSize", FD->PrologSize);
- W.printHex("SavedRegsSize", FD->SavedRegsSize);
- W.printFlags("Flags", FD->Flags, makeArrayRef(FrameDataFlags));
+ W.printHex("PrologSize", FD.PrologSize);
+ W.printHex("SavedRegsSize", FD.SavedRegsSize);
+ W.printFlags("Flags", FD.Flags, makeArrayRef(FrameDataFlags));
}
break;
}
@@ -889,45 +1073,28 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
ListScope S(W, "FunctionLineTable");
W.printString("LinkageName", Name);
- DataExtractor DE(FunctionLineTables[Name], true, 4);
- uint32_t Offset = 6; // Skip relocations.
- uint16_t Flags = DE.getU16(&Offset);
- W.printHex("Flags", Flags);
- bool HasColumnInformation = Flags & codeview::LineFlags::HaveColumns;
- uint32_t FunctionSize = DE.getU32(&Offset);
- W.printHex("CodeSize", FunctionSize);
- while (DE.isValidOffset(Offset)) {
- // For each range of lines with the same filename, we have a segment
- // in the line table. The filename string is accessed using double
- // indirection to the string table subsection using the index subsection.
- uint32_t OffsetInIndex = DE.getU32(&Offset),
- NumLines = DE.getU32(&Offset),
- FullSegmentSize = DE.getU32(&Offset);
-
- uint32_t ColumnOffset = Offset + 8 * NumLines;
- DataExtractor ColumnDE(DE.getData(), true, 4);
-
- if (FullSegmentSize !=
- 12 + 8 * NumLines + (HasColumnInformation ? 4 * NumLines : 0)) {
- error(object_error::parse_failed);
- return;
- }
+ BinaryStreamReader Reader(FunctionLineTables[Name], support::little);
+
+ DebugLinesSubsectionRef LineInfo;
+ error(LineInfo.initialize(Reader));
+
+ W.printHex("Flags", LineInfo.header()->Flags);
+ W.printHex("CodeSize", LineInfo.header()->CodeSize);
+ for (const auto &Entry : LineInfo) {
ListScope S(W, "FilenameSegment");
- printFileNameForOffset("Filename", OffsetInIndex);
- for (unsigned LineIdx = 0;
- LineIdx != NumLines && DE.isValidOffset(Offset); ++LineIdx) {
- // Then go the (PC, LineNumber) pairs. The line number is stored in the
- // least significant 31 bits of the respective word in the table.
- uint32_t PC = DE.getU32(&Offset), LineData = DE.getU32(&Offset);
- if (PC >= FunctionSize) {
+ printFileNameForOffset("Filename", Entry.NameIndex);
+ uint32_t ColumnIndex = 0;
+ for (const auto &Line : Entry.LineNumbers) {
+ if (Line.Offset >= LineInfo.header()->CodeSize) {
error(object_error::parse_failed);
return;
}
- char Buffer[32];
- format("+0x%X", PC).snprint(Buffer, 32);
- ListScope PCScope(W, Buffer);
- LineInfo LI(LineData);
+
+ std::string PC = formatv("+{0:X}", uint32_t(Line.Offset));
+ ListScope PCScope(W, PC);
+ codeview::LineInfo LI(Line.Flags);
+
if (LI.isAlwaysStepInto())
W.printString("StepInto", StringRef("Always"));
else if (LI.isNeverStepInto())
@@ -936,19 +1103,10 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
W.printNumber("LineNumberStart", LI.getStartLine());
W.printNumber("LineNumberEndDelta", LI.getLineDelta());
W.printBoolean("IsStatement", LI.isStatement());
- if (HasColumnInformation &&
- ColumnDE.isValidOffsetForDataOfSize(ColumnOffset, 4)) {
- uint16_t ColStart = ColumnDE.getU16(&ColumnOffset);
- W.printNumber("ColStart", ColStart);
- uint16_t ColEnd = ColumnDE.getU16(&ColumnOffset);
- W.printNumber("ColEnd", ColEnd);
- }
- }
- // Skip over the column data.
- if (HasColumnInformation) {
- for (unsigned LineIdx = 0;
- LineIdx != NumLines && DE.isValidOffset(Offset); ++LineIdx) {
- DE.getU32(&Offset);
+ if (LineInfo.hasColumnInfo()) {
+ W.printNumber("ColStart", Entry.Columns[ColumnIndex].StartColumn);
+ W.printNumber("ColEnd", Entry.Columns[ColumnIndex].EndColumn);
+ ++ColumnIndex;
}
}
}
@@ -962,12 +1120,10 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
Subsection.bytes_end());
auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
SectionContents);
-
- CVSymbolDumper CVSD(W, TypeDB, std::move(CODD),
+ CVSymbolDumper CVSD(W, Types, CodeViewContainer::ObjectFile, std::move(CODD),
opts::CodeViewSubsectionBytes);
- ByteStream Stream(BinaryData);
CVSymbolArray Symbols;
- StreamReader Reader(Stream);
+ BinaryStreamReader Reader(BinaryData, llvm::support::little);
if (auto EC = Reader.readArray(Symbols, Reader.getLength())) {
consumeError(std::move(EC));
W.flush();
@@ -982,58 +1138,39 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
}
void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) {
- msf::ByteStream S(Subsection);
- msf::StreamReader SR(S);
- while (!SR.empty()) {
+ BinaryStreamRef Stream(Subsection, llvm::support::little);
+ DebugChecksumsSubsectionRef Checksums;
+ error(Checksums.initialize(Stream));
+
+ for (auto &FC : Checksums) {
DictScope S(W, "FileChecksum");
- const FileChecksum *FC;
- error(SR.readObject(FC));
- if (FC->FileNameOffset >= CVStringTable.size())
- error(object_error::parse_failed);
- StringRef Filename =
- CVStringTable.drop_front(FC->FileNameOffset).split('\0').first;
- W.printHex("Filename", Filename, FC->FileNameOffset);
- W.printHex("ChecksumSize", FC->ChecksumSize);
- W.printEnum("ChecksumKind", uint8_t(FC->ChecksumKind),
+
+ StringRef Filename = error(CVStringTable.getString(FC.FileNameOffset));
+ W.printHex("Filename", Filename, FC.FileNameOffset);
+ W.printHex("ChecksumSize", FC.Checksum.size());
+ W.printEnum("ChecksumKind", uint8_t(FC.Kind),
makeArrayRef(FileChecksumKindNames));
- if (FC->ChecksumSize >= SR.bytesRemaining())
- error(object_error::parse_failed);
- ArrayRef<uint8_t> ChecksumBytes;
- error(SR.readBytes(ChecksumBytes, FC->ChecksumSize));
- W.printBinary("ChecksumBytes", ChecksumBytes);
- unsigned PaddedSize = alignTo(FC->ChecksumSize + sizeof(FileChecksum), 4) -
- sizeof(FileChecksum);
- PaddedSize -= ChecksumBytes.size();
- if (PaddedSize > SR.bytesRemaining())
- error(object_error::parse_failed);
- error(SR.skip(PaddedSize));
+
+ W.printBinary("ChecksumBytes", FC.Checksum);
}
}
void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {
- msf::ByteStream S(Subsection);
- msf::StreamReader SR(S);
- uint32_t Signature;
- error(SR.readInteger(Signature));
- bool HasExtraFiles = Signature == unsigned(InlineeLinesSignature::ExtraFiles);
-
- while (!SR.empty()) {
- const InlineeSourceLine *ISL;
- error(SR.readObject(ISL));
+ BinaryStreamReader SR(Subsection, llvm::support::little);
+ DebugInlineeLinesSubsectionRef Lines;
+ error(Lines.initialize(SR));
+
+ for (auto &Line : Lines) {
DictScope S(W, "InlineeSourceLine");
- printTypeIndex("Inlinee", ISL->Inlinee);
- printFileNameForOffset("FileID", ISL->FileID);
- W.printNumber("SourceLineNum", ISL->SourceLineNum);
-
- if (HasExtraFiles) {
- uint32_t ExtraFileCount;
- error(SR.readInteger(ExtraFileCount));
- W.printNumber("ExtraFileCount", ExtraFileCount);
+ printTypeIndex("Inlinee", Line.Header->Inlinee);
+ printFileNameForOffset("FileID", Line.Header->FileID);
+ W.printNumber("SourceLineNum", Line.Header->SourceLineNum);
+
+ if (Lines.hasExtraFiles()) {
+ W.printNumber("ExtraFileCount", Line.ExtraFiles.size());
ListScope ExtraFiles(W, "ExtraFiles");
- for (unsigned I = 0; I < ExtraFileCount; ++I) {
- uint32_t FileID;
- error(SR.readInteger(FileID));
- printFileNameForOffset("FileID", FileID);
+ for (const auto &FID : Line.ExtraFiles) {
+ printFileNameForOffset("FileID", FID);
}
}
}
@@ -1041,30 +1178,24 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {
StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) {
// The file checksum subsection should precede all references to it.
- if (!CVFileChecksumTable.data() || !CVStringTable.data())
- error(object_error::parse_failed);
- // Check if the file checksum table offset is valid.
- if (FileOffset >= CVFileChecksumTable.size())
+ if (!CVFileChecksumTable.valid() || !CVStringTable.valid())
error(object_error::parse_failed);
- // The string table offset comes first before the file checksum.
- StringRef Data = CVFileChecksumTable.drop_front(FileOffset);
- uint32_t StringOffset;
- error(consume(Data, StringOffset));
+ auto Iter = CVFileChecksumTable.getArray().at(FileOffset);
- // Check if the string table offset is valid.
- if (StringOffset >= CVStringTable.size())
+ // Check if the file checksum table offset is valid.
+ if (Iter == CVFileChecksumTable.end())
error(object_error::parse_failed);
- // Return the null-terminated string.
- return CVStringTable.drop_front(StringOffset).split('\0').first;
+ return error(CVStringTable.getString(Iter->FileNameOffset));
}
void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset);
}
-void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVTypes) {
+void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVIDs,
+ TypeTableBuilder &CVTypes) {
for (const SectionRef &S : Obj->sections()) {
StringRef SectionName;
error(S.getName(SectionName));
@@ -1075,19 +1206,17 @@ void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVTypes) {
error(consume(Data, Magic));
if (Magic != 4)
error(object_error::parse_failed);
- ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(Data.data()),
- Data.size());
- ByteStream Stream(Bytes);
+
CVTypeArray Types;
- StreamReader Reader(Stream);
+ BinaryStreamReader Reader(Data, llvm::support::little);
if (auto EC = Reader.readArray(Types, Reader.getLength())) {
consumeError(std::move(EC));
W.flush();
error(object_error::parse_failed);
}
-
- if (!mergeTypeStreams(CVTypes, Types))
- return error(object_error::parse_failed);
+ SmallVector<TypeIndex, 128> SourceToDest;
+ if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types))
+ return error(std::move(EC));
}
}
}
@@ -1108,12 +1237,11 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
if (Magic != COFF::DEBUG_SECTION_MAGIC)
return error(object_error::parse_failed);
- CVTypeDumper CVTD(TypeDB);
- TypeDumpVisitor TDV(TypeDB, &W, opts::CodeViewSubsectionBytes);
- if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()}, TDV)) {
- W.flush();
- error(llvm::errorToErrorCode(std::move(EC)));
- }
+ Types.reset(Data, 100);
+
+ TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes);
+ error(codeview::visitTypeStream(Types, TDV));
+ W.flush();
}
void COFFDumper::printSections() {
@@ -1435,12 +1563,18 @@ void COFFDumper::printCOFFImports() {
StringRef Name;
error(I.getName(Name));
W.printString("Name", Name);
- uint32_t Addr;
- error(I.getImportLookupTableRVA(Addr));
- W.printHex("ImportLookupTableRVA", Addr);
- error(I.getImportAddressTableRVA(Addr));
- W.printHex("ImportAddressTableRVA", Addr);
- printImportedSymbols(I.imported_symbols());
+ uint32_t ILTAddr;
+ error(I.getImportLookupTableRVA(ILTAddr));
+ W.printHex("ImportLookupTableRVA", ILTAddr);
+ uint32_t IATAddr;
+ error(I.getImportAddressTableRVA(IATAddr));
+ W.printHex("ImportAddressTableRVA", IATAddr);
+ // The import lookup table can be missing with certain older linkers, so
+ // fall back to the import address table in that case.
+ if (ILTAddr)
+ printImportedSymbols(I.lookup_table_symbols());
+ else
+ printImportedSymbols(I.imported_symbols());
}
// Delay imports
@@ -1502,7 +1636,11 @@ static StringRef getBaseRelocTypeName(uint8_t Type) {
case COFF::IMAGE_REL_BASED_HIGHADJ: return "HIGHADJ";
case COFF::IMAGE_REL_BASED_ARM_MOV32T: return "ARM_MOV32(T)";
case COFF::IMAGE_REL_BASED_DIR64: return "DIR64";
- default: return "unknown (" + llvm::utostr(Type) + ")";
+ default: {
+ static std::string Result;
+ Result = "unknown (" + llvm::utostr(Type) + ")";
+ return Result;
+ }
}
}
@@ -1519,6 +1657,127 @@ void COFFDumper::printCOFFBaseReloc() {
}
}
+void COFFDumper::printCOFFResources() {
+ ListScope ResourcesD(W, "Resources");
+ for (const SectionRef &S : Obj->sections()) {
+ StringRef Name;
+ error(S.getName(Name));
+ if (!Name.startswith(".rsrc"))
+ continue;
+
+ StringRef Ref;
+ error(S.getContents(Ref));
+
+ if ((Name == ".rsrc") || (Name == ".rsrc$01")) {
+ ResourceSectionRef RSF(Ref);
+ auto &BaseTable = unwrapOrError(RSF.getBaseTable());
+ W.printNumber("Total Number of Resources",
+ countTotalTableEntries(RSF, BaseTable, "Type"));
+ W.printHex("Base Table Address",
+ Obj->getCOFFSection(S)->PointerToRawData);
+ W.startLine() << "\n";
+ printResourceDirectoryTable(RSF, BaseTable, "Type");
+ }
+ if (opts::SectionData)
+ W.printBinaryBlock(Name.str() + " Data", Ref);
+ }
+}
+
+uint32_t
+COFFDumper::countTotalTableEntries(ResourceSectionRef RSF,
+ const coff_resource_dir_table &Table,
+ StringRef Level) {
+ uint32_t TotalEntries = 0;
+ for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
+ i++) {
+ auto Entry = unwrapOrError(getResourceDirectoryTableEntry(Table, i));
+ if (Entry.Offset.isSubDir()) {
+ StringRef NextLevel;
+ if (Level == "Name")
+ NextLevel = "Language";
+ else
+ NextLevel = "Name";
+ auto &NextTable = unwrapOrError(RSF.getEntrySubDir(Entry));
+ TotalEntries += countTotalTableEntries(RSF, NextTable, NextLevel);
+ } else {
+ TotalEntries += 1;
+ }
+ }
+ return TotalEntries;
+}
+
+void COFFDumper::printResourceDirectoryTable(
+ ResourceSectionRef RSF, const coff_resource_dir_table &Table,
+ StringRef Level) {
+
+ W.printNumber("Number of String Entries", Table.NumberOfNameEntries);
+ W.printNumber("Number of ID Entries", Table.NumberOfIDEntries);
+
+ // Iterate through level in resource directory tree.
+ for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
+ i++) {
+ auto Entry = unwrapOrError(getResourceDirectoryTableEntry(Table, i));
+ StringRef Name;
+ SmallString<20> IDStr;
+ raw_svector_ostream OS(IDStr);
+ if (i < Table.NumberOfNameEntries) {
+ ArrayRef<UTF16> RawEntryNameString = unwrapOrError(RSF.getEntryNameString(Entry));
+ std::vector<UTF16> EndianCorrectedNameString;
+ if (llvm::sys::IsBigEndianHost) {
+ EndianCorrectedNameString.resize(RawEntryNameString.size() + 1);
+ std::copy(RawEntryNameString.begin(), RawEntryNameString.end(),
+ EndianCorrectedNameString.begin() + 1);
+ EndianCorrectedNameString[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
+ RawEntryNameString = makeArrayRef(EndianCorrectedNameString);
+ }
+ std::string EntryNameString;
+ if (!llvm::convertUTF16ToUTF8String(RawEntryNameString, EntryNameString))
+ error(object_error::parse_failed);
+ OS << ": ";
+ OS << EntryNameString;
+ } else {
+ if (Level == "Type") {
+ ScopedPrinter Printer(OS);
+ Printer.printEnum("", Entry.Identifier.ID,
+ makeArrayRef(ResourceTypeNames));
+ IDStr = IDStr.slice(0, IDStr.find_first_of(")", 0) + 1);
+ } else {
+ OS << ": (ID " << Entry.Identifier.ID << ")";
+ }
+ }
+ Name = StringRef(IDStr);
+ ListScope ResourceType(W, Level.str() + Name.str());
+ if (Entry.Offset.isSubDir()) {
+ W.printHex("Table Offset", Entry.Offset.value());
+ StringRef NextLevel;
+ if (Level == "Name")
+ NextLevel = "Language";
+ else
+ NextLevel = "Name";
+ auto &NextTable = unwrapOrError(RSF.getEntrySubDir(Entry));
+ printResourceDirectoryTable(RSF, NextTable, NextLevel);
+ } else {
+ W.printHex("Entry Offset", Entry.Offset.value());
+ char FormattedTime[20] = {};
+ time_t TDS = time_t(Table.TimeDateStamp);
+ strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+ W.printHex("Time/Date Stamp", FormattedTime, Table.TimeDateStamp);
+ W.printNumber("Major Version", Table.MajorVersion);
+ W.printNumber("Minor Version", Table.MinorVersion);
+ W.printNumber("Characteristics", Table.Characteristics);
+ }
+ }
+}
+
+ErrorOr<const coff_resource_dir_entry &>
+COFFDumper::getResourceDirectoryTableEntry(const coff_resource_dir_table &Table,
+ uint32_t Index) {
+ if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))
+ return object_error::parse_failed;
+ auto TablePtr = reinterpret_cast<const coff_resource_dir_entry *>(&Table + 1);
+ return TablePtr[Index];
+}
+
void COFFDumper::printStackMap() const {
object::SectionRef StackMapSection;
for (auto Sec : Obj->sections()) {
@@ -1549,20 +1808,30 @@ void COFFDumper::printStackMap() const {
}
void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
+ llvm::codeview::TypeTableBuilder &IDTable,
llvm::codeview::TypeTableBuilder &CVTypes) {
// Flatten it first, then run our dumper on it.
- ListScope S(Writer, "MergedTypeStream");
- SmallString<0> Buf;
+ SmallString<0> TypeBuf;
CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
- Buf.append(Record.begin(), Record.end());
+ TypeBuf.append(Record.begin(), Record.end());
});
- TypeDatabase TypeDB;
- CVTypeDumper CVTD(TypeDB);
- TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
- if (auto EC =
- CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()}, TDV)) {
+ TypeTableCollection TpiTypes(CVTypes.records());
+ {
+ ListScope S(Writer, "MergedTypeStream");
+ TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
+ error(codeview::visitTypeStream(TpiTypes, TDV));
+ Writer.flush();
+ }
+
+ // Flatten the id stream and print it next. The ID stream refers to names from
+ // the type stream.
+ TypeTableCollection IpiTypes(IDTable.records());
+ {
+ ListScope S(Writer, "MergedIDStream");
+ TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
+ TDV.setIpiTypes(IpiTypes);
+ error(codeview::visitTypeStream(IpiTypes, TDV));
Writer.flush();
- error(llvm::errorToErrorCode(std::move(EC)));
}
}
diff --git a/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp
index 83715e6..c5b8bf7 100644
--- a/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp
@@ -15,9 +15,9 @@
#include "Error.h"
#include "ObjDumper.h"
#include "llvm-readobj.h"
+#include "llvm/BinaryFormat/COFF.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/COFFImportFile.h"
-#include "llvm/Support/COFF.h"
using namespace llvm::object;
diff --git a/contrib/llvm/tools/llvm-readobj/CodeView.h b/contrib/llvm/tools/llvm-readobj/CodeView.h
deleted file mode 100644
index cf71396..0000000
--- a/contrib/llvm/tools/llvm-readobj/CodeView.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//===-- CodeView.h - On-disk record types for CodeView ----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief This file provides data structures useful for consuming on-disk
-/// CodeView. It is based on information published by Microsoft at
-/// https://github.com/Microsoft/microsoft-pdb/.
-///
-//===----------------------------------------------------------------------===//
-
-// FIXME: Find a home for this in include/llvm/DebugInfo/CodeView/.
-
-#ifndef LLVM_READOBJ_CODEVIEW_H
-#define LLVM_READOBJ_CODEVIEW_H
-
-#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-#include "llvm/Support/Endian.h"
-
-namespace llvm {
-namespace codeview {
-
-using llvm::support::ulittle16_t;
-using llvm::support::ulittle32_t;
-
-/// Data in the the SUBSEC_FRAMEDATA subection.
-struct FrameData {
- ulittle32_t RvaStart;
- ulittle32_t CodeSize;
- ulittle32_t LocalSize;
- ulittle32_t ParamsSize;
- ulittle32_t MaxStackSize;
- ulittle32_t FrameFunc;
- ulittle16_t PrologSize;
- ulittle16_t SavedRegsSize;
- ulittle32_t Flags;
- enum : uint32_t {
- HasSEH = 1 << 0,
- HasEH = 1 << 1,
- IsFunctionStart = 1 << 2,
- };
-};
-
-
-} // namespace codeview
-} // namespace llvm
-
-#endif // LLVM_READOBJ_CODEVIEW_H
diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp
index 997af56..5698420 100644
--- a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -1,4 +1,4 @@
-//===-- ELFDumper.cpp - ELF-specific dumper ---------------------*- C++ -*-===//
+//===- ELFDumper.cpp - ELF-specific dumper --------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,24 +12,49 @@
///
//===----------------------------------------------------------------------===//
-#include "ARMAttributeParser.h"
#include "ARMEHABIPrinter.h"
#include "Error.h"
#include "ObjDumper.h"
#include "StackMapPrinter.h"
#include "llvm-readobj.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELF.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/StackMapParser.h"
+#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MipsABIFlags.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cinttypes>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
using namespace llvm;
using namespace llvm::object;
@@ -49,28 +74,28 @@ using namespace ELF;
return std::string(#enum).substr(3);
#define TYPEDEF_ELF_TYPES(ELFT) \
- typedef ELFFile<ELFT> ELFO; \
- typedef typename ELFO::Elf_Shdr Elf_Shdr; \
- typedef typename ELFO::Elf_Sym Elf_Sym; \
- typedef typename ELFO::Elf_Dyn Elf_Dyn; \
- typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; \
- typedef typename ELFO::Elf_Rel Elf_Rel; \
- typedef typename ELFO::Elf_Rela Elf_Rela; \
- typedef typename ELFO::Elf_Rel_Range Elf_Rel_Range; \
- typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range; \
- typedef typename ELFO::Elf_Phdr Elf_Phdr; \
- typedef typename ELFO::Elf_Half Elf_Half; \
- typedef typename ELFO::Elf_Ehdr Elf_Ehdr; \
- typedef typename ELFO::Elf_Word Elf_Word; \
- typedef typename ELFO::Elf_Hash Elf_Hash; \
- typedef typename ELFO::Elf_GnuHash Elf_GnuHash; \
- typedef typename ELFO::Elf_Sym_Range Elf_Sym_Range; \
- typedef typename ELFO::Elf_Versym Elf_Versym; \
- typedef typename ELFO::Elf_Verneed Elf_Verneed; \
- typedef typename ELFO::Elf_Vernaux Elf_Vernaux; \
- typedef typename ELFO::Elf_Verdef Elf_Verdef; \
- typedef typename ELFO::Elf_Verdaux Elf_Verdaux; \
- typedef typename ELFO::uintX_t uintX_t;
+ using ELFO = ELFFile<ELFT>; \
+ using Elf_Shdr = typename ELFO::Elf_Shdr; \
+ using Elf_Sym = typename ELFO::Elf_Sym; \
+ using Elf_Dyn = typename ELFO::Elf_Dyn; \
+ using Elf_Dyn_Range = typename ELFO::Elf_Dyn_Range; \
+ using Elf_Rel = typename ELFO::Elf_Rel; \
+ using Elf_Rela = typename ELFO::Elf_Rela; \
+ using Elf_Rel_Range = typename ELFO::Elf_Rel_Range; \
+ using Elf_Rela_Range = typename ELFO::Elf_Rela_Range; \
+ using Elf_Phdr = typename ELFO::Elf_Phdr; \
+ using Elf_Half = typename ELFO::Elf_Half; \
+ using Elf_Ehdr = typename ELFO::Elf_Ehdr; \
+ using Elf_Word = typename ELFO::Elf_Word; \
+ using Elf_Hash = typename ELFO::Elf_Hash; \
+ using Elf_GnuHash = typename ELFO::Elf_GnuHash; \
+ using Elf_Sym_Range = typename ELFO::Elf_Sym_Range; \
+ using Elf_Versym = typename ELFO::Elf_Versym; \
+ using Elf_Verneed = typename ELFO::Elf_Verneed; \
+ using Elf_Vernaux = typename ELFO::Elf_Vernaux; \
+ using Elf_Verdef = typename ELFO::Elf_Verdef; \
+ using Elf_Verdaux = typename ELFO::Elf_Verdaux; \
+ using uintX_t = typename ELFO::uintX_t;
namespace {
@@ -81,15 +106,16 @@ template <class ELFT> class DumpStyle;
/// the size, entity size and virtual address are different entries in arbitrary
/// order (DT_REL, DT_RELSZ, DT_RELENT for example).
struct DynRegionInfo {
- DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {}
+ DynRegionInfo() = default;
DynRegionInfo(const void *A, uint64_t S, uint64_t ES)
: Addr(A), Size(S), EntSize(ES) {}
+
/// \brief Address in current address space.
- const void *Addr;
+ const void *Addr = nullptr;
/// \brief Size in bytes of the region.
- uint64_t Size;
+ uint64_t Size = 0;
/// \brief Size of each entity in the region.
- uint64_t EntSize;
+ uint64_t EntSize = 0;
template <typename Type> ArrayRef<Type> getAsArrayRef() const {
const Type *Start = reinterpret_cast<const Type *>(Addr);
@@ -129,7 +155,7 @@ public:
void printMipsReginfo() override;
void printMipsOptions() override;
- void printAMDGPURuntimeMD() override;
+ void printAMDGPUCodeObjectMetadata() override;
void printStackMap() const override;
@@ -139,6 +165,7 @@ public:
private:
std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle;
+
TYPEDEF_ELF_TYPES(ELFT)
DynRegionInfo checkDRI(DynRegionInfo DRI) {
@@ -196,6 +223,7 @@ private:
: PointerIntPair<const void *, 1>(verdef, 0) {}
VersionMapEntry(const Elf_Vernaux *vernaux)
: PointerIntPair<const void *, 1>(vernaux, 1) {}
+
bool isNull() const { return getPointer() == nullptr; }
bool isVerdef() const { return !isNull() && getInt() == 0; }
bool isVernaux() const { return !isNull() && getInt() == 1; }
@@ -262,10 +290,11 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
template <typename ELFT> class DumpStyle {
public:
using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr;
- using Elf_Sym = typename ELFFile<ELFT>::Elf_Sym;
+ using Elf_Sym = typename ELFFile<ELFT>::Elf_Sym;
DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {}
- virtual ~DumpStyle() {}
+ virtual ~DumpStyle() = default;
+
virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0;
virtual void printGroupSections(const ELFFile<ELFT> *Obj) = 0;
virtual void printRelocations(const ELFFile<ELFT> *Obj) = 0;
@@ -274,9 +303,7 @@ public:
virtual void printDynamicSymbols(const ELFFile<ELFT> *Obj) = 0;
virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0;
virtual void printSymtabMessage(const ELFFile<ELFT> *obj, StringRef Name,
- size_t Offset) {
- return;
- }
+ size_t Offset) {}
virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym, StringRef StrTable,
bool IsDynamic) = 0;
@@ -284,16 +311,20 @@ public:
virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
+
private:
const ELFDumper<ELFT> *Dumper;
};
template <typename ELFT> class GNUStyle : public DumpStyle<ELFT> {
formatted_raw_ostream OS;
+
public:
TYPEDEF_ELF_TYPES(ELFT)
+
GNUStyle(ScopedPrinter &W, ELFDumper<ELFT> *Dumper)
: DumpStyle<ELFT>(Dumper), OS(W.getOStream()) {}
+
void printFileHeaders(const ELFO *Obj) override;
void printGroupSections(const ELFFile<ELFT> *Obj) override;
void printRelocations(const ELFO *Obj) override;
@@ -301,8 +332,8 @@ public:
void printSymbols(const ELFO *Obj) override;
void printDynamicSymbols(const ELFO *Obj) override;
void printDynamicRelocations(const ELFO *Obj) override;
- virtual void printSymtabMessage(const ELFO *Obj, StringRef Name,
- size_t Offset) override;
+ void printSymtabMessage(const ELFO *Obj, StringRef Name,
+ size_t Offset) override;
void printProgramHeaders(const ELFO *Obj) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
@@ -311,6 +342,7 @@ private:
struct Field {
StringRef Str;
unsigned Column;
+
Field(StringRef S, unsigned Col) : Str(S), Column(Col) {}
Field(unsigned Col) : Str(""), Column(Col) {}
};
@@ -348,6 +380,7 @@ private:
template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
public:
TYPEDEF_ELF_TYPES(ELFT)
+
LLVMStyle(ScopedPrinter &W, ELFDumper<ELFT> *Dumper)
: DumpStyle<ELFT>(Dumper), W(W) {}
@@ -368,10 +401,11 @@ private:
void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
StringRef StrTable, bool IsDynamic) override;
+
ScopedPrinter &W;
};
-} // namespace
+} // end anonymous namespace
namespace llvm {
@@ -405,7 +439,7 @@ std::error_code createELFDumper(const object::ObjectFile *Obj,
return readobj_error::unsupported_obj_file_format;
}
-} // namespace llvm
+} // end namespace llvm
// Iterate through the versions needed section, and place each Elf_Vernaux
// in the VersionMap according to its index.
@@ -525,8 +559,8 @@ static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper,
const ELFO *Obj,
const typename ELFO::Elf_Shdr *Sec,
ScopedPrinter &W) {
- typedef typename ELFO::Elf_Verdef VerDef;
- typedef typename ELFO::Elf_Verdaux VerdAux;
+ using VerDef = typename ELFO::Elf_Verdef;
+ using VerdAux = typename ELFO::Elf_Verdaux;
DictScope SD(W, "SHT_GNU_verdef");
if (!Sec)
@@ -581,8 +615,8 @@ static void printVersionDependencySection(ELFDumper<ELFT> *Dumper,
const ELFO *Obj,
const typename ELFO::Elf_Shdr *Sec,
ScopedPrinter &W) {
- typedef typename ELFO::Elf_Verneed VerNeed;
- typedef typename ELFO::Elf_Vernaux VernAux;
+ using VerNeed = typename ELFO::Elf_Verneed;
+ using VernAux = typename ELFO::Elf_Vernaux;
DictScope SD(W, "SHT_GNU_verneed");
if (!Sec)
@@ -978,61 +1012,9 @@ static const EnumEntry<unsigned> ElfSymbolTypes[] = {
{"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}};
static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = {
- { "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL },
- { "AMDGPU_HSA_INDIRECT_FUNCTION", ELF::STT_AMDGPU_HSA_INDIRECT_FUNCTION },
- { "AMDGPU_HSA_METADATA", ELF::STT_AMDGPU_HSA_METADATA }
+ { "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL }
};
-static const char *getElfSectionType(unsigned Arch, unsigned Type) {
- switch (Arch) {
- case ELF::EM_ARM:
- switch (Type) {
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX);
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP);
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES);
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY);
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION);
- }
- case ELF::EM_HEXAGON:
- switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); }
- case ELF::EM_X86_64:
- switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); }
- case ELF::EM_MIPS:
- case ELF::EM_MIPS_RS3_LE:
- switch (Type) {
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO);
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS);
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS);
- }
- }
-
- switch (Type) {
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_NULL );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_PROGBITS );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_STRTAB );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_RELA );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_HASH );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNAMIC );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOTE );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOBITS );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_REL );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_SHLIB );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNSYM );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_INIT_ARRAY );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_FINI_ARRAY );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_PREINIT_ARRAY );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_GROUP );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_HASH );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verdef );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verneed );
- LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_versym );
- default: return "";
- }
-}
-
static const char *getGroupType(uint32_t Flag) {
if (Flag & ELF::GRP_COMDAT)
return "COMDAT";
@@ -1062,13 +1044,6 @@ static const EnumEntry<unsigned> ElfXCoreSectionFlags[] = {
LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION)
};
-static const EnumEntry<unsigned> ElfAMDGPUSectionFlags[] = {
- LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_GLOBAL),
- LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_READONLY),
- LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_CODE),
- LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_AGENT)
-};
-
static const EnumEntry<unsigned> ElfARMSectionFlags[] = {
LLVM_READOBJ_ENUM_ENT(ELF, SHF_ARM_PURECODE)
};
@@ -1127,13 +1102,6 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) {
// Check potentially overlapped processor-specific
// program header type.
switch (Arch) {
- case ELF::EM_AMDGPU:
- switch (Type) {
- LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_READONLY_AGENT);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_CODE_AGENT);
- }
case ELF::EM_ARM:
switch (Type) {
LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX);
@@ -1189,14 +1157,6 @@ static std::string getElfPtType(unsigned Arch, unsigned Type) {
default:
// All machine specific PT_* types
switch (Arch) {
- case ELF::EM_AMDGPU:
- switch (Type) {
- LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_READONLY_AGENT);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_CODE_AGENT);
- }
- return "";
case ELF::EM_ARM:
if (Type == ELF::PT_ARM_EXIDX)
return "EXIDX";
@@ -1312,7 +1272,6 @@ static const char *getElfMipsOptionsOdkType(unsigned Odk) {
template <typename ELFT>
ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, ScopedPrinter &Writer)
: ObjDumper(Writer), Obj(Obj) {
-
SmallVector<const Elf_Phdr *, 4> LoadSegments;
for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) {
if (Phdr.p_type == ELF::PT_DYNAMIC) {
@@ -1573,6 +1532,7 @@ static const char *getTypeString(unsigned Arch, uint64_t Type) {
LLVM_READOBJ_TYPE_CASE(TLSDESC_PLT);
LLVM_READOBJ_TYPE_CASE(TLSDESC_GOT);
LLVM_READOBJ_TYPE_CASE(AUXILIARY);
+ LLVM_READOBJ_TYPE_CASE(FILTER);
default: return "unknown";
}
}
@@ -1641,8 +1601,8 @@ static const EnumEntry<unsigned> ElfDynamicDTMipsFlags[] = {
template <typename T, typename TFlag>
void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) {
- typedef EnumEntry<TFlag> FlagEntry;
- typedef SmallVector<FlagEntry, 10> FlagVector;
+ using FlagEntry = EnumEntry<TFlag>;
+ using FlagVector = SmallVector<FlagEntry, 10>;
FlagVector SetFlags;
for (const auto &Flag : Flags) {
@@ -1665,6 +1625,10 @@ StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const {
return StringRef(DynamicStringTable.data() + Value);
}
+static void printLibrary(raw_ostream &OS, const Twine &Tag, const Twine &Name) {
+ OS << Tag << ": [" << Name << "]";
+}
+
template <class ELFT>
void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
raw_ostream &OS = W.getOStream();
@@ -1728,13 +1692,16 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
OS << Value << " (bytes)";
break;
case DT_NEEDED:
- OS << "SharedLibrary (" << getDynamicString(Value) << ")";
+ printLibrary(OS, "Shared library", getDynamicString(Value));
break;
case DT_SONAME:
- OS << "LibrarySoname (" << getDynamicString(Value) << ")";
+ printLibrary(OS, "Library soname", getDynamicString(Value));
break;
case DT_AUXILIARY:
- OS << "Auxiliary library: [" << getDynamicString(Value) << "]";
+ printLibrary(OS, "Auxiliary library", getDynamicString(Value));
+ break;
+ case DT_FILTER:
+ printLibrary(OS, "Filter library", getDynamicString(Value));
break;
case DT_RPATH:
case DT_RUNPATH:
@@ -1761,6 +1728,7 @@ void ELFDumper<ELFT>::printUnwindInfo() {
}
namespace {
+
template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() {
const unsigned Machine = Obj->getHeader()->e_machine;
if (Machine == EM_ARM) {
@@ -1770,7 +1738,8 @@ template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() {
}
W.startLine() << "UnwindInfo not implemented.\n";
}
-}
+
+} // end anonymous namespace
template<class ELFT>
void ELFDumper<ELFT>::printDynamicTable() {
@@ -1816,7 +1785,7 @@ template<class ELFT>
void ELFDumper<ELFT>::printNeededLibraries() {
ListScope D(W, "NeededLibraries");
- typedef std::vector<StringRef> LibsTy;
+ using LibsTy = std::vector<StringRef>;
LibsTy Libs;
for (const auto &Entry : dynamic_table())
@@ -1870,6 +1839,7 @@ void ELFDumper<ELFT>::printAttributes() {
}
namespace {
+
template <> void ELFDumper<ELFType<support::little, false>>::printAttributes() {
if (Obj->getHeader()->e_machine != EM_ARM) {
W.startLine() << "Attributes not implemented.\n";
@@ -1892,16 +1862,15 @@ template <> void ELFDumper<ELFType<support::little, false>>::printAttributes() {
if (Contents.size() == 1)
continue;
- ARMAttributeParser(W).Parse(Contents);
+ ARMAttributeParser(&W).Parse(Contents, true);
}
}
-}
-namespace {
template <class ELFT> class MipsGOTParser {
public:
TYPEDEF_ELF_TYPES(ELFT)
- typedef typename ELFO::Elf_Addr GOTEntry;
+ using GOTEntry = typename ELFO::Elf_Addr;
+
MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj,
Elf_Dyn_Range DynTable, ScopedPrinter &W);
@@ -1912,11 +1881,11 @@ private:
ELFDumper<ELFT> *Dumper;
const ELFO *Obj;
ScopedPrinter &W;
- llvm::Optional<uint64_t> DtPltGot;
- llvm::Optional<uint64_t> DtLocalGotNum;
- llvm::Optional<uint64_t> DtGotSym;
- llvm::Optional<uint64_t> DtMipsPltGot;
- llvm::Optional<uint64_t> DtJmpRel;
+ Optional<uint64_t> DtPltGot;
+ Optional<uint64_t> DtLocalGotNum;
+ Optional<uint64_t> DtGotSym;
+ Optional<uint64_t> DtMipsPltGot;
+ Optional<uint64_t> DtJmpRel;
std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const;
const GOTEntry *makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum);
@@ -1932,7 +1901,8 @@ private:
const GOTEntry *It, StringRef StrTable,
const Elf_Sym *Sym);
};
-}
+
+} // end anonymous namespace
template <class ELFT>
MipsGOTParser<ELFT>::MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj,
@@ -2356,7 +2326,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() {
}
}
-template <class ELFT> void ELFDumper<ELFT>::printAMDGPURuntimeMD() {
+template <class ELFT> void ELFDumper<ELFT>::printAMDGPUCodeObjectMetadata() {
const Elf_Shdr *Shdr = findSectionByName(*Obj, ".note");
if (!Shdr) {
W.startLine() << "There is no .note section in the file.\n";
@@ -2364,7 +2334,7 @@ template <class ELFT> void ELFDumper<ELFT>::printAMDGPURuntimeMD() {
}
ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr));
- const uint32_t RuntimeMDNoteType = 7;
+ const uint32_t CodeObjectMetadataNoteType = 10;
for (auto I = reinterpret_cast<const Elf_Word *>(&Sec[0]),
E = I + Sec.size()/4; I != E;) {
uint32_t NameSZ = I[0];
@@ -2378,7 +2348,7 @@ template <class ELFT> void ELFDumper<ELFT>::printAMDGPURuntimeMD() {
I += alignTo<4>(NameSZ)/4;
}
- if (Name == "AMD" && Type == RuntimeMDNoteType) {
+ if (Name == "AMD" && Type == CodeObjectMetadataNoteType) {
StringRef Desc(reinterpret_cast<const char *>(I), DescSZ);
W.printString(Desc);
}
@@ -2403,8 +2373,8 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {
ArrayRef<uint8_t> StackMapContentsArray =
unwrapOrError(Obj->getSectionContents(StackMapSection));
- prettyPrintStackMap(llvm::outs(), StackMapV2Parser<ELFT::TargetEndianness>(
- StackMapContentsArray));
+ prettyPrintStackMap(outs(), StackMapV2Parser<ELFT::TargetEndianness>(
+ StackMapContentsArray));
}
template <class ELFT> void ELFDumper<ELFT>::printGroupSections() {
@@ -2505,7 +2475,7 @@ template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) {
template <class ELFT>
void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
const Elf_Rela &R, bool IsRela) {
- std::string Offset, Info, Addend = "", Value;
+ std::string Offset, Info, Addend, Value;
SmallString<32> RelocName;
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab));
StringRef TargetName;
@@ -2599,6 +2569,7 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
std::string getSectionTypeString(unsigned Arch, unsigned Type) {
using namespace ELF;
+
switch (Arch) {
case EM_ARM:
switch (Type) {
@@ -2627,6 +2598,8 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "MIPS_OPTIONS";
case SHT_MIPS_ABIFLAGS:
return "MIPS_ABIFLAGS";
+ case SHT_MIPS_DWARF:
+ return "SHT_MIPS_DWARF";
}
}
switch (Type) {
@@ -2664,6 +2637,8 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "GROUP";
case SHT_SYMTAB_SHNDX:
return "SYMTAB SECTION INDICES";
+ case SHT_LLVM_ODRTAB:
+ return "LLVM_ODRTAB";
// FIXME: Parse processor specific GNU attributes
case SHT_GNU_ATTRIBUTES:
return "ATTRIBUTES";
@@ -2763,7 +2738,7 @@ template <class ELFT> void GNUStyle<ELFT>::printSections(const ELFO *Obj) {
template <class ELFT>
void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name,
size_t Entries) {
- if (Name.size())
+ if (!Name.empty())
OS << "\nSymbol table '" << Name << "' contains " << Entries
<< " entries:\n";
else
@@ -2790,6 +2765,7 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj,
case ELF::SHN_XINDEX:
SectionIndex = unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>(
Symbol, FirstSym, this->dumper()->getShndxTable()));
+ LLVM_FALLTHROUGH;
default:
// Find if:
// Processor specific
@@ -2917,7 +2893,7 @@ template <class ELFT> void GNUStyle<ELFT>::printSymbols(const ELFO *Obj) {
template <class ELFT>
void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
- if (this->dumper()->getDynamicStringTable().size() == 0)
+ if (this->dumper()->getDynamicStringTable().empty())
return;
auto StringTable = this->dumper()->getDynamicStringTable();
auto DynSyms = this->dumper()->dynamic_symbols();
@@ -3131,19 +3107,19 @@ void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R,
Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
SymbolName =
unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()));
- std::string Addend = "", Info, Offset, Value;
+ std::string Addend, Info, Offset, Value;
Offset = to_string(format_hex_no_prefix(R.r_offset, Width));
Info = to_string(format_hex_no_prefix(R.r_info, Width));
Value = to_string(format_hex_no_prefix(Sym->getValue(), Width));
int64_t RelAddend = R.r_addend;
- if (SymbolName.size() && IsRela) {
+ if (!SymbolName.empty() && IsRela) {
if (R.r_addend < 0)
Addend = " - ";
else
Addend = " + ";
}
- if (!SymbolName.size() && Sym->getValue() == 0)
+ if (SymbolName.empty() && Sym->getValue() == 0)
Value = "";
if (IsRela)
@@ -3278,7 +3254,7 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
size_t MaxChain = 1;
size_t CumulativeNonZero = 0;
- if (Chains.size() == 0 || NBucket == 0)
+ if (Chains.empty() || NBucket == 0)
return;
std::vector<size_t> ChainLen(NBucket, 0);
@@ -3337,9 +3313,38 @@ static std::string getGNUNoteTypeName(const uint32_t NT) {
return string;
}
+static std::string getFreeBSDNoteTypeName(const uint32_t NT) {
+ static const struct {
+ uint32_t ID;
+ const char *Name;
+ } Notes[] = {
+ {ELF::NT_FREEBSD_THRMISC, "NT_THRMISC (thrmisc structure)"},
+ {ELF::NT_FREEBSD_PROCSTAT_PROC, "NT_PROCSTAT_PROC (proc data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_FILES, "NT_PROCSTAT_FILES (files data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_VMMAP, "NT_PROCSTAT_VMMAP (vmmap data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_GROUPS, "NT_PROCSTAT_GROUPS (groups data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_UMASK, "NT_PROCSTAT_UMASK (umask data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_RLIMIT, "NT_PROCSTAT_RLIMIT (rlimit data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_OSREL, "NT_PROCSTAT_OSREL (osreldate data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_PSSTRINGS,
+ "NT_PROCSTAT_PSSTRINGS (ps_strings data)"},
+ {ELF::NT_FREEBSD_PROCSTAT_AUXV, "NT_PROCSTAT_AUXV (auxv data)"},
+ };
+
+ for (const auto &Note : Notes)
+ if (Note.ID == NT)
+ return std::string(Note.Name);
+
+ std::string string;
+ raw_string_ostream OS(string);
+ OS << format("Unknown note type (0x%08x)", NT);
+ return string;
+}
+
template <typename ELFT>
static void printGNUNote(raw_ostream &OS, uint32_t NoteType,
- ArrayRef<typename ELFFile<ELFT>::Elf_Word> Words) {
+ ArrayRef<typename ELFFile<ELFT>::Elf_Word> Words,
+ size_t Size) {
switch (NoteType) {
default:
return;
@@ -3362,16 +3367,14 @@ static void printGNUNote(raw_ostream &OS, uint32_t NoteType,
}
case ELF::NT_GNU_BUILD_ID: {
OS << " Build ID: ";
- ArrayRef<uint8_t> ID(reinterpret_cast<const uint8_t *>(Words.data()),
- Words.size() * 4);
+ ArrayRef<uint8_t> ID(reinterpret_cast<const uint8_t *>(Words.data()), Size);
for (const auto &B : ID)
OS << format_hex_no_prefix(B, 2);
break;
}
case ELF::NT_GNU_GOLD_VERSION:
OS << " Version: "
- << StringRef(reinterpret_cast<const char *>(Words.data()),
- Words.size() * 4);
+ << StringRef(reinterpret_cast<const char *>(Words.data()), Size);
break;
}
@@ -3415,11 +3418,15 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
if (Name == "GNU") {
OS << getGNUNoteTypeName(Type) << '\n';
- printGNUNote<ELFT>(OS, Type, Descriptor);
+ printGNUNote<ELFT>(OS, Type, Descriptor, DescriptorSize);
+ } else if (Name == "FreeBSD") {
+ OS << getFreeBSDNoteTypeName(Type) << '\n';
+ } else {
+ OS << "Unknown note type: (" << format_hex(Type, 10) << ')';
}
OS << '\n';
- P = P + 3 * sizeof(Elf_Word) * alignTo<4>(NameSize) +
+ P = P + 3 * sizeof(Elf_Word) + alignTo<4>(NameSize) +
alignTo<4>(DescriptorSize);
}
};
@@ -3578,13 +3585,13 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,
DictScope Group(W, "Relocation");
W.printHex("Offset", Rel.r_offset);
W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL()));
- W.printNumber("Symbol", TargetName.size() > 0 ? TargetName : "-",
+ W.printNumber("Symbol", !TargetName.empty() ? TargetName : "-",
Rel.getSymbol(Obj->isMips64EL()));
W.printHex("Addend", Rel.r_addend);
} else {
raw_ostream &OS = W.startLine();
OS << W.hex(Rel.r_offset) << " " << RelocName << " "
- << (TargetName.size() > 0 ? TargetName : "-") << " "
+ << (!TargetName.empty() ? TargetName : "-") << " "
<< W.hex(Rel.r_addend) << "\n";
}
}
@@ -3601,16 +3608,13 @@ template <class ELFT> void LLVMStyle<ELFT>::printSections(const ELFO *Obj) {
DictScope SectionD(W, "Section");
W.printNumber("Index", SectionIndex);
W.printNumber("Name", Name, Sec.sh_name);
- W.printHex("Type",
- getElfSectionType(Obj->getHeader()->e_machine, Sec.sh_type),
- Sec.sh_type);
+ W.printHex(
+ "Type",
+ object::getELFSectionTypeName(Obj->getHeader()->e_machine, Sec.sh_type),
+ Sec.sh_type);
std::vector<EnumEntry<unsigned>> SectionFlags(std::begin(ElfSectionFlags),
std::end(ElfSectionFlags));
switch (Obj->getHeader()->e_machine) {
- case EM_AMDGPU:
- SectionFlags.insert(SectionFlags.end(), std::begin(ElfAMDGPUSectionFlags),
- std::end(ElfAMDGPUSectionFlags));
- break;
case EM_ARM:
SectionFlags.insert(SectionFlags.end(), std::begin(ElfARMSectionFlags),
std::end(ElfARMSectionFlags));
@@ -3778,12 +3782,12 @@ void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) {
DictScope Group(W, "Relocation");
W.printHex("Offset", Rel.r_offset);
W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL()));
- W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
+ W.printString("Symbol", !SymbolName.empty() ? SymbolName : "-");
W.printHex("Addend", Rel.r_addend);
} else {
raw_ostream &OS = W.startLine();
OS << W.hex(Rel.r_offset) << " " << RelocName << " "
- << (SymbolName.size() > 0 ? SymbolName : "-") << " "
+ << (!SymbolName.empty() ? SymbolName : "-") << " "
<< W.hex(Rel.r_addend) << "\n";
}
}
@@ -3816,4 +3820,3 @@ template <class ELFT>
void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
W.startLine() << "printNotes not implemented!\n";
}
-
diff --git a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp
index 01b0741..39e9092 100644
--- a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp
@@ -713,12 +713,30 @@ void MachODumper::printMachOVersionMin() {
case MachO::LC_VERSION_MIN_WATCHOS:
Cmd = "LC_VERSION_MIN_WATCHOS";
break;
+ case MachO::LC_BUILD_VERSION:
+ Cmd = "LC_BUILD_VERSION";
+ break;
default:
continue;
}
- MachO::version_min_command VMC = Obj->getVersionMinLoadCommand(Load);
DictScope Group(W, "MinVersion");
+ // Handle LC_BUILD_VERSION.
+ if (Load.C.cmd == MachO::LC_BUILD_VERSION) {
+ MachO::build_version_command BVC = Obj->getBuildVersionLoadCommand(Load);
+ W.printString("Cmd", Cmd);
+ W.printNumber("Size", BVC.cmdsize);
+ W.printString("Platform",
+ MachOObjectFile::getBuildPlatform(BVC.platform));
+ W.printString("Version", MachOObjectFile::getVersionString(BVC.minos));
+ if (BVC.sdk)
+ W.printString("SDK", MachOObjectFile::getVersionString(BVC.sdk));
+ else
+ W.printString("SDK", StringRef("n/a"));
+ continue;
+ }
+
+ MachO::version_min_command VMC = Obj->getVersionMinLoadCommand(Load);
W.printString("Cmd", Cmd);
W.printNumber("Size", VMC.cmdsize);
SmallString<32> Version;
diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h
index c91558e..43883c2 100644
--- a/contrib/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h
@@ -59,7 +59,7 @@ public:
virtual void printMipsOptions() { }
// Only implemented for AMDGPU ELF at this time.
- virtual void printAMDGPURuntimeMD() {}
+ virtual void printAMDGPUCodeObjectMetadata() {}
// Only implemented for PE/COFF.
virtual void printCOFFImports() { }
@@ -67,8 +67,11 @@ public:
virtual void printCOFFDirectives() { }
virtual void printCOFFBaseReloc() { }
virtual void printCOFFDebugDirectory() { }
+ virtual void printCOFFResources() {}
+ virtual void printCOFFLoadConfig() { }
virtual void printCodeViewDebugInfo() { }
- virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVTypes) {}
+ virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs,
+ llvm::codeview::TypeTableBuilder &CVTypes) {}
// Only implemented for MachO.
virtual void printMachODataInCode() { }
@@ -96,10 +99,15 @@ std::error_code createMachODumper(const object::ObjectFile *Obj,
ScopedPrinter &Writer,
std::unique_ptr<ObjDumper> &Result);
+std::error_code createWasmDumper(const object::ObjectFile *Obj,
+ ScopedPrinter &Writer,
+ std::unique_ptr<ObjDumper> &Result);
+
void dumpCOFFImportFile(const object::COFFImportFile *File);
void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
- llvm::codeview::TypeTableBuilder &CVTypes);
+ llvm::codeview::TypeTableBuilder &IDTable,
+ llvm::codeview::TypeTableBuilder &TypeTable);
} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp b/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp
new file mode 100644
index 0000000..266226d
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp
@@ -0,0 +1,209 @@
+//===-- WasmDumper.cpp - Wasm-specific object file dumper -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Wasm-specific dumper for llvm-readobj.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "ObjDumper.h"
+#include "llvm-readobj.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+
+static const EnumEntry<unsigned> WasmSymbolTypes[] = {
+#define ENUM_ENTRY(X) { #X, static_cast<unsigned>(WasmSymbol::SymbolType::X) }
+ ENUM_ENTRY(FUNCTION_IMPORT),
+ ENUM_ENTRY(FUNCTION_EXPORT),
+ ENUM_ENTRY(GLOBAL_IMPORT),
+ ENUM_ENTRY(GLOBAL_EXPORT),
+ ENUM_ENTRY(DEBUG_FUNCTION_NAME),
+#undef ENUM_ENTRY
+};
+
+static const EnumEntry<uint32_t> WasmSectionTypes[] = {
+#define ENUM_ENTRY(X) { #X, wasm::WASM_SEC_##X }
+ ENUM_ENTRY(CUSTOM),
+ ENUM_ENTRY(TYPE),
+ ENUM_ENTRY(IMPORT),
+ ENUM_ENTRY(FUNCTION),
+ ENUM_ENTRY(TABLE),
+ ENUM_ENTRY(MEMORY),
+ ENUM_ENTRY(GLOBAL),
+ ENUM_ENTRY(EXPORT),
+ ENUM_ENTRY(START),
+ ENUM_ENTRY(ELEM),
+ ENUM_ENTRY(CODE),
+ ENUM_ENTRY(DATA),
+#undef ENUM_ENTRY
+};
+
+class WasmDumper : public ObjDumper {
+public:
+ WasmDumper(const WasmObjectFile *Obj, ScopedPrinter &Writer)
+ : ObjDumper(Writer), Obj(Obj) {}
+
+ void printFileHeaders() override;
+ void printSections() override;
+ void printRelocations() override;
+ void printSymbols() override;
+ void printDynamicSymbols() override { llvm_unreachable("unimplemented"); }
+ void printUnwindInfo() override { llvm_unreachable("unimplemented"); }
+ void printStackMap() const override { llvm_unreachable("unimplemented"); }
+
+protected:
+ void printSymbol(const SymbolRef &Sym);
+ void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
+
+private:
+ const WasmObjectFile *Obj;
+};
+
+void WasmDumper::printFileHeaders() {
+ W.printHex("Version", Obj->getHeader().Version);
+}
+
+void WasmDumper::printRelocation(const SectionRef &Section,
+ const RelocationRef &Reloc) {
+ SmallString<64> RelocTypeName;
+ uint64_t RelocType = Reloc.getType();
+ Reloc.getTypeName(RelocTypeName);
+ const wasm::WasmRelocation &WasmReloc = Obj->getWasmRelocation(Reloc);
+
+ bool HasAddend = false;
+ switch (RelocType) {
+ case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
+ case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
+ case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
+ HasAddend = true;
+ break;
+ default:
+ break;
+ }
+ if (opts::ExpandRelocs) {
+ DictScope Group(W, "Relocation");
+ W.printNumber("Type", RelocTypeName, RelocType);
+ W.printHex("Offset", Reloc.getOffset());
+ W.printHex("Index", WasmReloc.Index);
+ if (HasAddend)
+ W.printNumber("Addend", WasmReloc.Addend);
+ } else {
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Reloc.getOffset())
+ << " " << RelocTypeName << "[" << WasmReloc.Index << "]";
+ if (HasAddend)
+ OS << " " << WasmReloc.Addend;
+ OS << "\n";
+ }
+}
+
+void WasmDumper::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ int SectionNumber = 0;
+ for (const SectionRef &Section : Obj->sections()) {
+ bool PrintedGroup = false;
+ StringRef Name;
+ error(Section.getName(Name));
+ ++SectionNumber;
+
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ if (!PrintedGroup) {
+ W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(Section, Reloc);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+void WasmDumper::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ for (const SymbolRef &Symbol : Obj->symbols())
+ printSymbol(Symbol);
+}
+
+void WasmDumper::printSections() {
+ ListScope Group(W, "Sections");
+ for (const SectionRef &Section : Obj->sections()) {
+ const WasmSection &WasmSec = Obj->getWasmSection(Section);
+ DictScope SectionD(W, "Section");
+ W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes));
+ W.printNumber("Size", (uint64_t)WasmSec.Content.size());
+ W.printNumber("Offset", WasmSec.Offset);
+ switch (WasmSec.Type) {
+ case wasm::WASM_SEC_CUSTOM:
+ W.printString("Name", WasmSec.Name);
+ if (WasmSec.Name == "linking") {
+ const wasm::WasmLinkingData &LinkingData = Obj->linkingData();
+ W.printNumber("DataSize", LinkingData.DataSize);
+ if (LinkingData.DataAlignment)
+ W.printNumber("DataAlignment", LinkingData.DataAlignment);
+ }
+ break;
+ case wasm::WASM_SEC_MEMORY:
+ ListScope Group(W, "Memories");
+ for (const wasm::WasmLimits &Memory : Obj->memories()) {
+ DictScope Group(W, "Memory");
+ W.printNumber("InitialPages", Memory.Initial);
+ if (Memory.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) {
+ W.printNumber("MaxPages", WasmSec.Offset);
+ }
+ }
+ break;
+ }
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (const RelocationRef &Reloc : Section.relocations())
+ printRelocation(Section, Reloc);
+ }
+
+ if (opts::SectionData) {
+ W.printBinaryBlock("SectionData", WasmSec.Content);
+ }
+ }
+}
+
+void WasmDumper::printSymbol(const SymbolRef &Sym) {
+ DictScope D(W, "Symbol");
+ WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl());
+ W.printString("Name", Symbol.Name);
+ W.printEnum("Type", static_cast<unsigned>(Symbol.Type), makeArrayRef(WasmSymbolTypes));
+ W.printHex("Flags", Symbol.Flags);
+}
+
+}
+
+namespace llvm {
+
+std::error_code createWasmDumper(const object::ObjectFile *Obj,
+ ScopedPrinter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
+ const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(Obj);
+ assert(WasmObj && "createWasmDumper called with non-wasm object");
+
+ Result.reset(new WasmDumper(WasmObj, Writer));
+ return readobj_error::success;
+}
+
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 970e154..7bfb18f 100644
--- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -34,6 +34,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/Signals.h"
@@ -50,6 +51,13 @@ namespace opts {
cl::desc("<input object files>"),
cl::ZeroOrMore);
+ // -wide, -W
+ cl::opt<bool> WideOutput("wide",
+ cl::desc("Ignored for compatibility with GNU readelf"));
+ cl::alias WideOutputShort("W",
+ cl::desc("Alias for --wide"),
+ cl::aliasopt(WideOutput));
+
// -file-headers, -h
cl::opt<bool> FileHeaders("file-headers",
cl::desc("Display file headers "));
@@ -57,12 +65,16 @@ namespace opts {
cl::desc("Alias for --file-headers"),
cl::aliasopt(FileHeaders));
- // -sections, -s
+ // -sections, -s, -S
+ // Note: In GNU readelf, -s means --symbols!
cl::opt<bool> Sections("sections",
cl::desc("Display all sections."));
cl::alias SectionsShort("s",
cl::desc("Alias for --sections"),
cl::aliasopt(Sections));
+ cl::alias SectionsShortUpper("S",
+ cl::desc("Alias for --sections"),
+ cl::aliasopt(Sections));
// -section-relocations, -sr
cl::opt<bool> SectionRelocations("section-relocations",
@@ -186,9 +198,10 @@ namespace opts {
cl::opt<bool> MipsOptions("mips-options",
cl::desc("Display the MIPS .MIPS.options section"));
- // -amdgpu-runtime-metadata
- cl::opt<bool> AMDGPURuntimeMD("amdgpu-runtime-metadata",
- cl::desc("Display AMDGPU runtime metadata"));
+ // -amdgpu-code-object-metadata
+ cl::opt<bool> AMDGPUCodeObjectMetadata(
+ "amdgpu-code-object-metadata",
+ cl::desc("Display AMDGPU code object metadata"));
// -coff-imports
cl::opt<bool>
@@ -213,6 +226,15 @@ namespace opts {
COFFDebugDirectory("coff-debug-directory",
cl::desc("Display the PE/COFF debug directory"));
+ // -coff-resources
+ cl::opt<bool> COFFResources("coff-resources",
+ cl::desc("Display the PE/COFF .rsrc section"));
+
+ // -coff-load-config
+ cl::opt<bool>
+ COFFLoadConfig("coff-load-config",
+ cl::desc("Display the PE/COFF load config"));
+
// -macho-data-in-code
cl::opt<bool>
MachODataInCode("macho-data-in-code",
@@ -306,13 +328,6 @@ static void reportError(StringRef Input, std::error_code EC) {
reportError(Twine(Input) + ": " + EC.message());
}
-static void reportError(StringRef Input, StringRef Message) {
- if (Input == "-")
- Input = "<stdin>";
-
- reportError(Twine(Input) + ": " + Message);
-}
-
static void reportError(StringRef Input, Error Err) {
if (Input == "-")
Input = "<stdin>";
@@ -337,10 +352,12 @@ static bool isMipsArch(unsigned Arch) {
}
namespace {
struct ReadObjTypeTableBuilder {
- ReadObjTypeTableBuilder() : Allocator(), Builder(Allocator) {}
+ ReadObjTypeTableBuilder()
+ : Allocator(), IDTable(Allocator), TypeTable(Allocator) {}
llvm::BumpPtrAllocator Allocator;
- llvm::codeview::TypeTableBuilder Builder;
+ llvm::codeview::TypeTableBuilder IDTable;
+ llvm::codeview::TypeTableBuilder TypeTable;
};
}
static ReadObjTypeTableBuilder CVTypes;
@@ -358,6 +375,8 @@ static std::error_code createDumper(const ObjectFile *Obj,
return createELFDumper(Obj, Writer, Result);
if (Obj->isMachO())
return createMachODumper(Obj, Writer, Result);
+ if (Obj->isWasm())
+ return createWasmDumper(Obj, Writer, Result);
return readobj_error::unsupported_obj_file_format;
}
@@ -420,8 +439,8 @@ static void dumpObject(const ObjectFile *Obj) {
Dumper->printMipsOptions();
}
if (Obj->getArch() == llvm::Triple::amdgcn)
- if (opts::AMDGPURuntimeMD)
- Dumper->printAMDGPURuntimeMD();
+ if (opts::AMDGPUCodeObjectMetadata)
+ Dumper->printAMDGPUCodeObjectMetadata();
if (opts::SectionGroups)
Dumper->printGroupSections();
if (opts::HashHistogram)
@@ -440,10 +459,14 @@ static void dumpObject(const ObjectFile *Obj) {
Dumper->printCOFFBaseReloc();
if (opts::COFFDebugDirectory)
Dumper->printCOFFDebugDirectory();
+ if (opts::COFFResources)
+ Dumper->printCOFFResources();
+ if (opts::COFFLoadConfig)
+ Dumper->printCOFFLoadConfig();
if (opts::CodeView)
Dumper->printCodeViewDebugInfo();
if (opts::CodeViewMergedTypes)
- Dumper->mergeCodeViewTypes(CVTypes.Builder);
+ Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable);
}
if (Obj->isMachO()) {
if (opts::MachODataInCode)
@@ -470,11 +493,7 @@ static void dumpArchive(const Archive *Arc) {
Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- logAllUnhandledErrors(ChildOrErr.takeError(), OS, "");
- OS.flush();
- reportError(Arc->getFileName(), Buf);
+ reportError(Arc->getFileName(), ChildOrErr.takeError());
}
continue;
}
@@ -496,11 +515,7 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) {
if (ObjOrErr)
dumpObject(&*ObjOrErr.get());
else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- logAllUnhandledErrors(ObjOrErr.takeError(), OS, "");
- OS.flush();
- reportError(UBinary->getFileName(), Buf);
+ reportError(UBinary->getFileName(), ObjOrErr.takeError());
}
else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
dumpArchive(&*AOrErr.get());
@@ -513,7 +528,7 @@ static void dumpInput(StringRef File) {
// Attempt to open the binary.
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
if (!BinaryOrErr)
- reportError(File, errorToErrorCode(BinaryOrErr.takeError()));
+ reportError(File, BinaryOrErr.takeError());
Binary &Binary = *BinaryOrErr.get().getBinary();
if (Archive *Arc = dyn_cast<Archive>(&Binary))
@@ -530,13 +545,19 @@ static void dumpInput(StringRef File) {
}
int main(int argc, const char *argv[]) {
- sys::PrintStackTraceOnErrorSignal(argv[0]);
+ StringRef ToolName = argv[0];
+ sys::PrintStackTraceOnErrorSignal(ToolName);
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y;
// Register the target printer for --version.
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+ opts::WideOutput.setHiddenFlag(cl::Hidden);
+
+ if (sys::path::stem(ToolName).find("readelf") != StringRef::npos)
+ opts::Output = opts::GNU;
+
cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n");
// Default to stdin if no filename is specified.
@@ -548,7 +569,7 @@ int main(int argc, const char *argv[]) {
if (opts::CodeViewMergedTypes) {
ScopedPrinter W(outs());
- dumpCodeViewMergedTypes(W, CVTypes.Builder);
+ dumpCodeViewMergedTypes(W, CVTypes.IDTable, CVTypes.TypeTable);
}
return 0;
diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h
index 0156920..840ddba 100644
--- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h
+++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h
@@ -25,6 +25,11 @@ namespace llvm {
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
void error(std::error_code EC);
void error(llvm::Error EC);
+ template <typename T> T error(llvm::Expected<T> &&E) {
+ error(E.takeError());
+ return std::move(*E);
+ }
+
template <class T> T unwrapOrError(ErrorOr<T> EO) {
if (EO)
return *EO;
diff --git a/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
index 4e1caa0..ba130ce 100644
--- a/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -175,8 +175,7 @@ public:
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
size_t Size) override {}
- void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
- size_t Size) override {}
+ void deregisterEHFrames() override {}
void preallocateSlab(uint64_t Size) {
std::string Err;
@@ -486,10 +485,7 @@ static int checkAllExpressions(RuntimeDyldChecker &Checker) {
return 0;
}
-static std::map<void *, uint64_t>
-applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
-
- std::map<void*, uint64_t> SpecificMappings;
+void applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
for (StringRef Mapping : SpecificSectionMappings) {
@@ -522,10 +518,7 @@ applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
"'.");
Checker.getRTDyld().mapSectionAddress(OldAddr, NewAddr);
- SpecificMappings[OldAddr] = NewAddr;
}
-
- return SpecificMappings;
}
// Scatter sections in all directions!
@@ -554,8 +547,7 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,
// Apply any section-specific mappings that were requested on the command
// line.
- typedef std::map<void*, uint64_t> AppliedMappingsT;
- AppliedMappingsT AppliedMappings = applySpecificSectionMappings(Checker);
+ applySpecificSectionMappings(Checker);
// Keep an "already allocated" mapping of section target addresses to sizes.
// Sections whose address mappings aren't specified on the command line will
@@ -563,15 +555,19 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,
// minimum separation.
std::map<uint64_t, uint64_t> AlreadyAllocated;
- // Move the previously applied mappings into the already-allocated map.
+ // Move the previously applied mappings (whether explicitly specified on the
+ // command line, or implicitly set by RuntimeDyld) into the already-allocated
+ // map.
for (WorklistT::iterator I = Worklist.begin(), E = Worklist.end();
I != E;) {
WorklistT::iterator Tmp = I;
++I;
- AppliedMappingsT::iterator AI = AppliedMappings.find(Tmp->first);
+ auto LoadAddr = Checker.getSectionLoadAddress(Tmp->first);
- if (AI != AppliedMappings.end()) {
- AlreadyAllocated[AI->second] = Tmp->second;
+ if (LoadAddr &&
+ *LoadAddr != static_cast<uint64_t>(
+ reinterpret_cast<uintptr_t>(Tmp->first))) {
+ AlreadyAllocated[*LoadAddr] = Tmp->second;
Worklist.erase(Tmp);
}
}
diff --git a/contrib/llvm/tools/llvm-stress/llvm-stress.cpp b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp
index 731a24d..3945da7 100644
--- a/contrib/llvm/tools/llvm-stress/llvm-stress.cpp
+++ b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp
@@ -28,6 +28,7 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/ToolOutputFile.h"
#include <algorithm>
+#include <random>
#include <vector>
namespace llvm {
@@ -95,17 +96,13 @@ public:
return Seed & 0x7ffff;
}
- /// Return a random 32 bit integer.
- uint32_t Rand32() {
- uint32_t Val = Rand();
- Val &= 0xffff;
- return Val | (Rand() << 16);
- }
-
/// Return a random 64 bit integer.
uint64_t Rand64() {
- uint64_t Val = Rand32();
- return Val | (uint64_t(Rand32()) << 32);
+ uint64_t Val = Rand() & 0xffff;
+ Val |= uint64_t(Rand() & 0xffff) << 16;
+ Val |= uint64_t(Rand() & 0xffff) << 32;
+ Val |= uint64_t(Rand() & 0xffff) << 48;
+ return Val;
}
/// Rand operator for STL algorithms.
@@ -113,6 +110,16 @@ public:
return Rand64() % y;
}
+ /// Make this like a C++11 random device
+ typedef uint32_t result_type;
+ static constexpr result_type min() { return 0; }
+ static constexpr result_type max() { return 0x7ffff; }
+ uint32_t operator()() {
+ uint32_t Val = Rand();
+ assert(Val <= max() && "Random value out of range");
+ return Val;
+ }
+
private:
unsigned Seed;
};
@@ -161,19 +168,24 @@ public:
}
protected:
+ /// Return a random integer.
+ uint32_t getRandom() {
+ return Ran->Rand();
+ }
+
/// Return a random value from the list of known values.
Value *getRandomVal() {
assert(PT->size());
- return PT->at(Ran->Rand() % PT->size());
+ return PT->at(getRandom() % PT->size());
}
Constant *getRandomConstant(Type *Tp) {
if (Tp->isIntegerTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return ConstantInt::getAllOnesValue(Tp);
return ConstantInt::getNullValue(Tp);
} else if (Tp->isFloatingPointTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return ConstantFP::getAllOnesValue(Tp);
return ConstantFP::getNullValue(Tp);
}
@@ -182,7 +194,7 @@ protected:
/// Return a random value with a known type.
Value *getRandomValue(Type *Tp) {
- unsigned index = Ran->Rand();
+ unsigned index = getRandom();
for (unsigned i=0; i<PT->size(); ++i) {
Value *V = PT->at((index + i) % PT->size());
if (V->getType() == Tp)
@@ -191,11 +203,11 @@ protected:
// If the requested type was not found, generate a constant value.
if (Tp->isIntegerTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return ConstantInt::getAllOnesValue(Tp);
return ConstantInt::getNullValue(Tp);
} else if (Tp->isFloatingPointTy()) {
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return ConstantFP::getAllOnesValue(Tp);
return ConstantFP::getNullValue(Tp);
} else if (Tp->isVectorTy()) {
@@ -215,7 +227,7 @@ protected:
/// Return a random value of any pointer type.
Value *getRandomPointerValue() {
- unsigned index = Ran->Rand();
+ unsigned index = getRandom();
for (unsigned i=0; i<PT->size(); ++i) {
Value *V = PT->at((index + i) % PT->size());
if (V->getType()->isPointerTy())
@@ -226,7 +238,7 @@ protected:
/// Return a random value of any vector type.
Value *getRandomVectorValue() {
- unsigned index = Ran->Rand();
+ unsigned index = getRandom();
for (unsigned i=0; i<PT->size(); ++i) {
Value *V = PT->at((index + i) % PT->size());
if (V->getType()->isVectorTy())
@@ -237,7 +249,7 @@ protected:
/// Pick a random type.
Type *pickType() {
- return (Ran->Rand() & 1 ? pickVectorType() : pickScalarType());
+ return (getRandom() & 1 ? pickVectorType() : pickScalarType());
}
/// Pick a random pointer type.
@@ -251,7 +263,7 @@ protected:
// Pick a random vector width in the range 2**0 to 2**4.
// by adding two randoms we are generating a normal-like distribution
// around 2**3.
- unsigned width = 1<<((Ran->Rand() % 3) + (Ran->Rand() % 3));
+ unsigned width = 1<<((getRandom() % 3) + (getRandom() % 3));
Type *Ty;
// Vectors of x86mmx are illegal; keep trying till we get something else.
@@ -281,7 +293,7 @@ protected:
AdditionalScalarTypes.begin(), AdditionalScalarTypes.end());
}
- return ScalarTypes[Ran->Rand() % ScalarTypes.size()];
+ return ScalarTypes[getRandom() % ScalarTypes.size()];
}
/// Basic block to populate
@@ -341,7 +353,7 @@ struct BinModifier: public Modifier {
bool isFloat = Val0->getType()->getScalarType()->isFloatingPointTy();
Instruction* Term = BB->getTerminator();
- unsigned R = Ran->Rand() % (isFloat ? 7 : 13);
+ unsigned R = getRandom() % (isFloat ? 7 : 13);
Instruction::BinaryOps Op;
switch (R) {
@@ -372,10 +384,11 @@ struct ConstModifier: public Modifier {
Type *Ty = pickType();
if (Ty->isVectorTy()) {
- switch (Ran->Rand() % 2) {
- case 0: if (Ty->getScalarType()->isIntegerTy())
+ switch (getRandom() % 2) {
+ case 0: if (Ty->isIntOrIntVectorTy())
return PT->push_back(ConstantVector::getAllOnesValue(Ty));
- case 1: if (Ty->getScalarType()->isIntegerTy())
+ break;
+ case 1: if (Ty->isIntOrIntVectorTy())
return PT->push_back(ConstantVector::getNullValue(Ty));
}
}
@@ -390,25 +403,27 @@ struct ConstModifier: public Modifier {
APInt RandomInt(Ty->getPrimitiveSizeInBits(), makeArrayRef(RandomBits));
APFloat RandomFloat(Ty->getFltSemantics(), RandomInt);
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return PT->push_back(ConstantFP::getNullValue(Ty));
return PT->push_back(ConstantFP::get(Ty->getContext(), RandomFloat));
}
if (Ty->isIntegerTy()) {
- switch (Ran->Rand() % 7) {
- case 0: if (Ty->isIntegerTy())
- return PT->push_back(ConstantInt::get(Ty,
- APInt::getAllOnesValue(Ty->getPrimitiveSizeInBits())));
- case 1: if (Ty->isIntegerTy())
- return PT->push_back(ConstantInt::get(Ty,
- APInt::getNullValue(Ty->getPrimitiveSizeInBits())));
- case 2: case 3: case 4: case 5:
- case 6: if (Ty->isIntegerTy())
- PT->push_back(ConstantInt::get(Ty, Ran->Rand()));
+ switch (getRandom() % 7) {
+ case 0:
+ return PT->push_back(ConstantInt::get(
+ Ty, APInt::getAllOnesValue(Ty->getPrimitiveSizeInBits())));
+ case 1:
+ return PT->push_back(ConstantInt::get(
+ Ty, APInt::getNullValue(Ty->getPrimitiveSizeInBits())));
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ PT->push_back(ConstantInt::get(Ty, getRandom()));
}
}
-
}
};
@@ -417,7 +432,9 @@ struct AllocaModifier: public Modifier {
void Act() override {
Type *Tp = pickType();
- PT->push_back(new AllocaInst(Tp, "A", BB->getFirstNonPHI()));
+ const DataLayout &DL = BB->getModule()->getDataLayout();
+ PT->push_back(new AllocaInst(Tp, DL.getAllocaAddrSpace(),
+ "A", BB->getFirstNonPHI()));
}
};
@@ -429,7 +446,7 @@ struct ExtractElementModifier: public Modifier {
Value *Val0 = getRandomVectorValue();
Value *V = ExtractElementInst::Create(Val0,
ConstantInt::get(Type::getInt32Ty(BB->getContext()),
- Ran->Rand() % cast<VectorType>(Val0->getType())->getNumElements()),
+ getRandom() % cast<VectorType>(Val0->getType())->getNumElements()),
"E", BB->getTerminator());
return PT->push_back(V);
}
@@ -447,9 +464,9 @@ struct ShuffModifier: public Modifier {
Type *I32 = Type::getInt32Ty(BB->getContext());
for (unsigned i=0; i<Width; ++i) {
- Constant *CI = ConstantInt::get(I32, Ran->Rand() % (Width*2));
+ Constant *CI = ConstantInt::get(I32, getRandom() % (Width*2));
// Pick some undef values.
- if (!(Ran->Rand() % 5))
+ if (!(getRandom() % 5))
CI = UndefValue::get(I32);
Idxs.push_back(CI);
}
@@ -472,7 +489,7 @@ struct InsertElementModifier: public Modifier {
Value *V = InsertElementInst::Create(Val0, Val1,
ConstantInt::get(Type::getInt32Ty(BB->getContext()),
- Ran->Rand() % cast<VectorType>(Val0->getType())->getNumElements()),
+ getRandom() % cast<VectorType>(Val0->getType())->getNumElements()),
"I", BB->getTerminator());
return PT->push_back(V);
}
@@ -508,20 +525,19 @@ struct CastModifier: public Modifier {
unsigned DestSize = DestTy->getScalarType()->getPrimitiveSizeInBits();
// Generate lots of bitcasts.
- if ((Ran->Rand() & 1) && VSize == DestSize) {
+ if ((getRandom() & 1) && VSize == DestSize) {
return PT->push_back(
new BitCastInst(V, DestTy, "BC", BB->getTerminator()));
}
// Both types are integers:
- if (VTy->getScalarType()->isIntegerTy() &&
- DestTy->getScalarType()->isIntegerTy()) {
+ if (VTy->isIntOrIntVectorTy() && DestTy->isIntOrIntVectorTy()) {
if (VSize > DestSize) {
return PT->push_back(
new TruncInst(V, DestTy, "Tr", BB->getTerminator()));
} else {
assert(VSize < DestSize && "Different int types with the same size?");
- if (Ran->Rand() & 1)
+ if (getRandom() & 1)
return PT->push_back(
new ZExtInst(V, DestTy, "ZE", BB->getTerminator()));
return PT->push_back(new SExtInst(V, DestTy, "Se", BB->getTerminator()));
@@ -529,18 +545,16 @@ struct CastModifier: public Modifier {
}
// Fp to int.
- if (VTy->getScalarType()->isFloatingPointTy() &&
- DestTy->getScalarType()->isIntegerTy()) {
- if (Ran->Rand() & 1)
+ if (VTy->isFPOrFPVectorTy() && DestTy->isIntOrIntVectorTy()) {
+ if (getRandom() & 1)
return PT->push_back(
new FPToSIInst(V, DestTy, "FC", BB->getTerminator()));
return PT->push_back(new FPToUIInst(V, DestTy, "FC", BB->getTerminator()));
}
// Int to fp.
- if (VTy->getScalarType()->isIntegerTy() &&
- DestTy->getScalarType()->isFloatingPointTy()) {
- if (Ran->Rand() & 1)
+ if (VTy->isIntOrIntVectorTy() && DestTy->isFPOrFPVectorTy()) {
+ if (getRandom() & 1)
return PT->push_back(
new SIToFPInst(V, DestTy, "FC", BB->getTerminator()));
return PT->push_back(new UIToFPInst(V, DestTy, "FC", BB->getTerminator()));
@@ -548,8 +562,7 @@ struct CastModifier: public Modifier {
}
// Both floats.
- if (VTy->getScalarType()->isFloatingPointTy() &&
- DestTy->getScalarType()->isFloatingPointTy()) {
+ if (VTy->isFPOrFPVectorTy() && DestTy->isFPOrFPVectorTy()) {
if (VSize > DestSize) {
return PT->push_back(
new FPTruncInst(V, DestTy, "Tr", BB->getTerminator()));
@@ -577,7 +590,7 @@ struct SelectModifier: public Modifier {
// If the value type is a vector, and we allow vector select, then in 50%
// of the cases generate a vector select.
- if (Val0->getType()->isVectorTy() && (Ran->Rand() % 1)) {
+ if (Val0->getType()->isVectorTy() && (getRandom() % 1)) {
unsigned NumElem = cast<VectorType>(Val0->getType())->getNumElements();
CondTy = VectorType::get(CondTy, NumElem);
}
@@ -601,11 +614,11 @@ struct CmpModifier: public Modifier {
int op;
if (fp) {
- op = Ran->Rand() %
+ op = getRandom() %
(CmpInst::LAST_FCMP_PREDICATE - CmpInst::FIRST_FCMP_PREDICATE) +
CmpInst::FIRST_FCMP_PREDICATE;
} else {
- op = Ran->Rand() %
+ op = getRandom() %
(CmpInst::LAST_ICMP_PREDICATE - CmpInst::FIRST_ICMP_PREDICATE) +
CmpInst::FIRST_ICMP_PREDICATE;
}
@@ -662,7 +675,7 @@ static void IntroduceControlFlow(Function *F, Random &R) {
BoolInst.push_back(&Instr);
}
- std::random_shuffle(BoolInst.begin(), BoolInst.end(), R);
+ std::shuffle(BoolInst.begin(), BoolInst.end(), R);
for (auto *Instr : BoolInst) {
BasicBlock *Curr = Instr->getParent();
diff --git a/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index fc37dea..c9e0cc2 100644
--- a/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -85,6 +85,9 @@ static cl::opt<int> ClPrintSourceContextLines(
"print-source-context-lines", cl::init(0),
cl::desc("Print N number of source file context"));
+static cl::opt<bool> ClVerbose("verbose", cl::init(false),
+ cl::desc("Print verbose line info"));
+
template<typename T>
static bool error(Expected<T> &ResOrErr) {
if (ResOrErr)
@@ -160,7 +163,7 @@ int main(int argc, char **argv) {
LLVMSymbolizer Symbolizer(Opts);
DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None,
- ClPrettyPrint, ClPrintSourceContextLines);
+ ClPrettyPrint, ClPrintSourceContextLines, ClVerbose);
const int kMaxInputStringLength = 1024;
char InputString[kMaxInputStringLength];
diff --git a/contrib/llvm/tools/llvm-xray/llvm-xray.cc b/contrib/llvm/tools/llvm-xray/llvm-xray.cc
index ac5faaa..98303e7 100644
--- a/contrib/llvm/tools/llvm-xray/llvm-xray.cc
+++ b/contrib/llvm/tools/llvm-xray/llvm-xray.cc
@@ -30,12 +30,20 @@ int main(int argc, char *argv[]) {
" This program consolidates multiple XRay trace "
"processing tools for convenient access.\n");
for (auto *SC : cl::getRegisteredSubcommands()) {
- if (*SC)
+ if (*SC) {
+ // If no subcommand was provided, we need to explicitly check if this is
+ // the top-level subcommand.
+ if (SC == &*cl::TopLevelSubCommand) {
+ cl::PrintHelpMessage(false, true);
+ return 0;
+ }
if (auto C = dispatch(SC)) {
ExitOnError("llvm-xray: ")(C());
return 0;
}
+ }
}
+ // If all else fails, we still print the usage message.
cl::PrintHelpMessage(false, true);
}
diff --git a/contrib/llvm/tools/llvm-xray/xray-account.cc b/contrib/llvm/tools/llvm-xray/xray-account.cc
index 671a5a0..13654c3 100644
--- a/contrib/llvm/tools/llvm-xray/xray-account.cc
+++ b/contrib/llvm/tools/llvm-xray/xray-account.cc
@@ -18,10 +18,10 @@
#include <utility>
#include "xray-account.h"
-#include "xray-extract.h"
#include "xray-registry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
using namespace llvm;
@@ -120,16 +120,6 @@ static cl::opt<std::string>
static cl::alias AccountInstrMap2("m", cl::aliasopt(AccountInstrMap),
cl::desc("Alias for -instr_map"),
cl::sub(Account));
-static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
- "instr-map-format", cl::desc("format of instrumentation map"),
- cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
- "instrumentation map in an ELF header"),
- clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
- "yaml", "instrumentation map in YAML")),
- cl::sub(Account), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
-static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
- cl::desc("Alias for -instr-map-format"),
- cl::sub(Account));
namespace {
@@ -418,67 +408,63 @@ void LatencyAccountant::exportStatsAsCSV(raw_ostream &OS,
using namespace llvm::xray;
static CommandRegistration Unused(&Account, []() -> Error {
- int Fd;
- auto EC = sys::fs::openFileForRead(AccountInput, Fd);
- if (EC)
- return make_error<StringError>(
- Twine("Cannot open file '") + AccountInput + "'", EC);
-
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(AccountInstrMap, InstrMapFormat,
- Err);
- if (auto E = handleErrors(
- std::move(Err), [&](std::unique_ptr<StringError> SE) -> Error {
- if (SE->convertToErrorCode() == std::errc::no_such_file_or_directory)
- return Error::success();
- return Error(std::move(SE));
- }))
- return E;
+ InstrumentationMap Map;
+ if (!AccountInstrMap.empty()) {
+ auto InstrumentationMapOrError = loadInstrumentationMap(AccountInstrMap);
+ if (!InstrumentationMapOrError)
+ return joinErrors(make_error<StringError>(
+ Twine("Cannot open instrumentation map '") +
+ AccountInstrMap + "'",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
+ Map = std::move(*InstrumentationMapOrError);
+ }
+ std::error_code EC;
raw_fd_ostream OS(AccountOutput, EC, sys::fs::OpenFlags::F_Text);
if (EC)
return make_error<StringError>(
Twine("Cannot open file '") + AccountOutput + "' for writing.", EC);
- const auto &FunctionAddresses = Extractor.getFunctionAddresses();
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
symbolize::LLVMSymbolizer::Options Opts(
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
symbolize::LLVMSymbolizer Symbolizer(Opts);
llvm::xray::FuncIdConversionHelper FuncIdHelper(AccountInstrMap, Symbolizer,
FunctionAddresses);
xray::LatencyAccountant FCA(FuncIdHelper, AccountDeduceSiblingCalls);
- if (auto TraceOrErr = loadTraceFile(AccountInput)) {
- auto &T = *TraceOrErr;
- for (const auto &Record : T) {
- if (FCA.accountRecord(Record))
- continue;
- for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) {
- errs() << "Thread ID: " << ThreadStack.first << "\n";
- auto Level = ThreadStack.second.size();
- for (const auto &Entry : llvm::reverse(ThreadStack.second))
- errs() << "#" << Level-- << "\t"
- << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n';
- }
- if (!AccountKeepGoing)
- return make_error<StringError>(
- Twine("Failed accounting function calls in file '") + AccountInput +
- "'.",
- std::make_error_code(std::errc::executable_format_error));
- }
- switch (AccountOutputFormat) {
- case AccountOutputFormats::TEXT:
- FCA.exportStatsAsText(OS, T.getFileHeader());
- break;
- case AccountOutputFormats::CSV:
- FCA.exportStatsAsCSV(OS, T.getFileHeader());
- break;
- }
- } else {
+ auto TraceOrErr = loadTraceFile(AccountInput);
+ if (!TraceOrErr)
return joinErrors(
make_error<StringError>(
Twine("Failed loading input file '") + AccountInput + "'",
std::make_error_code(std::errc::executable_format_error)),
TraceOrErr.takeError());
+
+ auto &T = *TraceOrErr;
+ for (const auto &Record : T) {
+ if (FCA.accountRecord(Record))
+ continue;
+ for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) {
+ errs() << "Thread ID: " << ThreadStack.first << "\n";
+ auto Level = ThreadStack.second.size();
+ for (const auto &Entry : llvm::reverse(ThreadStack.second))
+ errs() << "#" << Level-- << "\t"
+ << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n';
+ }
+ if (!AccountKeepGoing)
+ return make_error<StringError>(
+ Twine("Failed accounting function calls in file '") + AccountInput +
+ "'.",
+ std::make_error_code(std::errc::executable_format_error));
+ }
+ switch (AccountOutputFormat) {
+ case AccountOutputFormats::TEXT:
+ FCA.exportStatsAsText(OS, T.getFileHeader());
+ break;
+ case AccountOutputFormats::CSV:
+ FCA.exportStatsAsCSV(OS, T.getFileHeader());
+ break;
}
return Error::success();
diff --git a/contrib/llvm/tools/llvm-xray/xray-color-helper.cc b/contrib/llvm/tools/llvm-xray/xray-color-helper.cc
new file mode 100644
index 0000000..7b6a73a
--- /dev/null
+++ b/contrib/llvm/tools/llvm-xray/xray-color-helper.cc
@@ -0,0 +1,224 @@
+//===-- xray-graph.cc - XRay Function Call Graph Renderer -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A class to get a color from a specified gradient.
+//
+//===----------------------------------------------------------------------===//
+#include <algorithm>
+#include <iostream>
+
+#include "xray-color-helper.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace xray;
+
+// Sequential ColorMaps, which are used to represent information
+// from some minimum to some maximum.
+
+static const std::tuple<uint8_t, uint8_t, uint8_t> SequentialMaps[][9] = {
+ {// The greys color scheme from http://colorbrewer2.org/
+ std::make_tuple(255, 255, 255), std::make_tuple(240, 240, 240),
+ std::make_tuple(217, 217, 217), std::make_tuple(189, 189, 189),
+ std::make_tuple(150, 150, 150), std::make_tuple(115, 115, 115),
+ std::make_tuple(82, 82, 82), std::make_tuple(37, 37, 37),
+ std::make_tuple(0, 0, 0)},
+ {// The OrRd color scheme from http://colorbrewer2.org/
+ std::make_tuple(255, 247, 236), std::make_tuple(254, 232, 200),
+ std::make_tuple(253, 212, 158), std::make_tuple(253, 187, 132),
+ std::make_tuple(252, 141, 89), std::make_tuple(239, 101, 72),
+ std::make_tuple(215, 48, 31), std::make_tuple(179, 0, 0),
+ std::make_tuple(127, 0, 0)},
+ {// The PuBu color scheme from http://colorbrewer2.org/
+ std::make_tuple(255, 247, 251), std::make_tuple(236, 231, 242),
+ std::make_tuple(208, 209, 230), std::make_tuple(166, 189, 219),
+ std::make_tuple(116, 169, 207), std::make_tuple(54, 144, 192),
+ std::make_tuple(5, 112, 176), std::make_tuple(4, 90, 141),
+ std::make_tuple(2, 56, 88)}};
+
+// Sequential Maps extend the last colors given out of range inputs.
+static const std::tuple<uint8_t, uint8_t, uint8_t> SequentialBounds[][2] = {
+ {// The Bounds for the greys color scheme
+ std::make_tuple(255, 255, 255), std::make_tuple(0, 0, 0)},
+ {// The Bounds for the OrRd color Scheme
+ std::make_tuple(255, 247, 236), std::make_tuple(127, 0, 0)},
+ {// The Bounds for the PuBu color Scheme
+ std::make_tuple(255, 247, 251), std::make_tuple(2, 56, 88)}};
+
+ColorHelper::ColorHelper(ColorHelper::SequentialScheme S)
+ : MinIn(0.0), MaxIn(1.0), ColorMap(SequentialMaps[static_cast<int>(S)]),
+ BoundMap(SequentialBounds[static_cast<int>(S)]) {}
+
+// Diverging ColorMaps, which are used to represent information
+// representing differenes, or a range that goes from negative to positive.
+// These take an input in the range [-1,1].
+
+static const std::tuple<uint8_t, uint8_t, uint8_t> DivergingCoeffs[][11] = {
+ {// The PiYG color scheme from http://colorbrewer2.org/
+ std::make_tuple(142, 1, 82), std::make_tuple(197, 27, 125),
+ std::make_tuple(222, 119, 174), std::make_tuple(241, 182, 218),
+ std::make_tuple(253, 224, 239), std::make_tuple(247, 247, 247),
+ std::make_tuple(230, 245, 208), std::make_tuple(184, 225, 134),
+ std::make_tuple(127, 188, 65), std::make_tuple(77, 146, 33),
+ std::make_tuple(39, 100, 25)}};
+
+// Diverging maps use out of bounds ranges to show missing data. Missing Right
+// Being below min, and missing left being above max.
+static const std::tuple<uint8_t, uint8_t, uint8_t> DivergingBounds[][2] = {
+ {// The PiYG color scheme has green and red for missing right and left
+ // respectively.
+ std::make_tuple(255, 0, 0), std::make_tuple(0, 255, 0)}};
+
+ColorHelper::ColorHelper(ColorHelper::DivergingScheme S)
+ : MinIn(-1.0), MaxIn(1.0), ColorMap(DivergingCoeffs[static_cast<int>(S)]),
+ BoundMap(DivergingBounds[static_cast<int>(S)]) {}
+
+// Takes a tuple of uint8_ts representing a color in RGB and converts them to
+// HSV represented by a tuple of doubles
+static std::tuple<double, double, double>
+convertToHSV(const std::tuple<uint8_t, uint8_t, uint8_t> &Color) {
+ double Scaled[3] = {std::get<0>(Color) / 255.0, std::get<1>(Color) / 255.0,
+ std::get<2>(Color) / 255.0};
+ int Min = 0;
+ int Max = 0;
+ for (int i = 1; i < 3; ++i) {
+ if (Scaled[i] < Scaled[Min])
+ Min = i;
+ if (Scaled[i] > Scaled[Max])
+ Max = i;
+ }
+
+ double C = Scaled[Max] - Scaled[Min];
+
+ double HPrime =
+ (C == 0) ? 0 : (Scaled[(Max + 1) % 3] - Scaled[(Max + 2) % 3]) / C;
+ HPrime = HPrime + 2.0 * Max;
+
+ double H = (HPrime < 0) ? (HPrime + 6.0) * 60
+ : HPrime * 60; // Scale to between 0 and 360
+ double V = Scaled[Max];
+
+ double S = (V == 0.0) ? 0.0 : C / V;
+
+ return std::make_tuple(H, S, V);
+}
+
+// Takes a double precision number, clips it between 0 and 1 and then converts
+// that to an integer between 0x00 and 0xFF with proxpper rounding.
+static uint8_t unitIntervalTo8BitChar(double B) {
+ double n = std::max(std::min(B, 1.0), 0.0);
+ return static_cast<uint8_t>(255 * n + 0.5);
+}
+
+// Takes a typle of doubles representing a color in HSV and converts them to
+// RGB represented as a tuple of uint8_ts
+static std::tuple<uint8_t, uint8_t, uint8_t>
+convertToRGB(const std::tuple<double, double, double> &Color) {
+ const double &H = std::get<0>(Color);
+ const double &S = std::get<1>(Color);
+ const double &V = std::get<2>(Color);
+
+ double C = V * S;
+
+ double HPrime = H / 60;
+ double X = C * (1 - std::abs(std::fmod(HPrime, 2.0) - 1));
+
+ double RGB1[3];
+ int HPrimeInt = static_cast<int>(HPrime);
+ if (HPrimeInt % 2 == 0) {
+ RGB1[(HPrimeInt / 2) % 3] = C;
+ RGB1[(HPrimeInt / 2 + 1) % 3] = X;
+ RGB1[(HPrimeInt / 2 + 2) % 3] = 0.0;
+ } else {
+ RGB1[(HPrimeInt / 2) % 3] = X;
+ RGB1[(HPrimeInt / 2 + 1) % 3] = C;
+ RGB1[(HPrimeInt / 2 + 2) % 3] = 0.0;
+ }
+
+ double Min = V - C;
+ double RGB2[3] = {RGB1[0] + Min, RGB1[1] + Min, RGB1[2] + Min};
+
+ return std::make_tuple(unitIntervalTo8BitChar(RGB2[0]),
+ unitIntervalTo8BitChar(RGB2[1]),
+ unitIntervalTo8BitChar(RGB2[2]));
+}
+
+// The Hue component of the HSV interpolation Routine
+static double interpolateHue(double H0, double H1, double T) {
+ double D = H1 - H0;
+ if (H0 > H1) {
+ std::swap(H0, H1);
+
+ D = -D;
+ T = 1 - T;
+ }
+
+ if (D <= 180) {
+ return H0 + T * (H1 - H0);
+ } else {
+ H0 = H0 + 360;
+ return std::fmod(H0 + T * (H1 - H0) + 720, 360);
+ }
+}
+
+// Interpolates between two HSV Colors both represented as a tuple of doubles
+// Returns an HSV Color represented as a tuple of doubles
+static std::tuple<double, double, double>
+interpolateHSV(const std::tuple<double, double, double> &C0,
+ const std::tuple<double, double, double> &C1, double T) {
+ double H = interpolateHue(std::get<0>(C0), std::get<0>(C1), T);
+ double S = std::get<1>(C0) + T * (std::get<1>(C1) - std::get<1>(C0));
+ double V = std::get<2>(C0) + T * (std::get<2>(C1) - std::get<2>(C0));
+ return std::make_tuple(H, S, V);
+}
+
+// Get the Color as a tuple of uint8_ts
+std::tuple<uint8_t, uint8_t, uint8_t>
+ColorHelper::getColorTuple(double Point) const {
+ assert(!ColorMap.empty() && "ColorMap must not be empty!");
+ assert(!BoundMap.empty() && "BoundMap must not be empty!");
+
+ if (Point < MinIn)
+ return BoundMap[0];
+ if (Point > MaxIn)
+ return BoundMap[1];
+
+ size_t MaxIndex = ColorMap.size() - 1;
+ double IntervalWidth = MaxIn - MinIn;
+ double OffsetP = Point - MinIn;
+ double SectionWidth = IntervalWidth / static_cast<double>(MaxIndex);
+ size_t SectionNo = std::floor(OffsetP / SectionWidth);
+ double T = (OffsetP - SectionNo * SectionWidth) / SectionWidth;
+
+ auto &RGBColor0 = ColorMap[SectionNo];
+ auto &RGBColor1 = ColorMap[std::min(SectionNo + 1, MaxIndex)];
+
+ auto HSVColor0 = convertToHSV(RGBColor0);
+ auto HSVColor1 = convertToHSV(RGBColor1);
+
+ auto InterpolatedHSVColor = interpolateHSV(HSVColor0, HSVColor1, T);
+ return convertToRGB(InterpolatedHSVColor);
+}
+
+// A helper method to convert a color represented as tuple of uint8s to a hex
+// string.
+std::string
+ColorHelper::getColorString(std::tuple<uint8_t, uint8_t, uint8_t> t) {
+ return llvm::formatv("#{0:X-2}{1:X-2}{2:X-2}", std::get<0>(t), std::get<1>(t),
+ std::get<2>(t));
+}
+
+// Gets a color in a gradient given a number in the interval [0,1], it does this
+// by evaluating a polynomial which maps [0, 1] -> [0, 1] for each of the R G
+// and B values in the color. It then converts this [0,1] colors to a 24 bit
+// color as a hex string.
+std::string ColorHelper::getColorString(double Point) const {
+ return getColorString(getColorTuple(Point));
+}
diff --git a/contrib/llvm/tools/llvm-xray/xray-color-helper.h b/contrib/llvm/tools/llvm-xray/xray-color-helper.h
new file mode 100644
index 0000000..b2dcf62
--- /dev/null
+++ b/contrib/llvm/tools/llvm-xray/xray-color-helper.h
@@ -0,0 +1,89 @@
+//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A class to get a color from a specified gradient.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef XRAY_COLOR_HELPER_H
+#define XRAY_COLOR_HELPER_H
+
+#include <tuple>
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace llvm {
+namespace xray {
+
+/// The color helper class it a healper class which allows you to easily get a
+/// color in a gradient. This is used to color-code edges in XRay-Graph tools.
+///
+/// There are two types of color schemes in this class:
+/// - Sequential schemes, which are used to represent information from some
+/// minimum to some maximum. These take an input in the range [0,1]
+/// - Diverging schemes, which are used to represent information representing
+/// differenes, or a range that goes from negative to positive. These take
+/// an input in the range [-1,1].
+/// Usage;
+/// ColorHelper S(ColorHelper::SequentialScheme::OrRd); //Chose a color scheme.
+/// for (double p = 0.0; p <= 1; p += 0.1){
+/// cout() << S.getColor(p) << " \n"; // Sample the gradient at 0.1 intervals
+/// }
+///
+/// ColorHelper D(ColorHelper::DivergingScheme::Spectral); // Choose a color
+/// // scheme.
+/// for (double p= -1; p <= 1 ; p += 0.1){
+/// cout() << D.getColor(p) << " \n"; // sample the gradient at 0.1 intervals
+/// }
+class ColorHelper {
+ double MinIn;
+ double MaxIn;
+
+ ArrayRef<std::tuple<uint8_t, uint8_t, uint8_t>> ColorMap;
+ ArrayRef<std::tuple<uint8_t, uint8_t, uint8_t>> BoundMap;
+
+public:
+ /// Enum of the availible Sequential Color Schemes
+ enum class SequentialScheme {
+ // Schemes based on the ColorBrewer Color schemes of the same name from
+ // http://www.colorbrewer.org/ by Cynthis A Brewer Penn State University.
+ Greys,
+ OrRd,
+ PuBu
+ };
+
+ ColorHelper(SequentialScheme S);
+
+ /// Enum of the availible Diverging Color Schemes
+ enum class DivergingScheme {
+ // Schemes based on the ColorBrewer Color schemes of the same name from
+ // http://www.colorbrewer.org/ by Cynthis A Brewer Penn State University.
+ PiYG
+ };
+
+ ColorHelper(DivergingScheme S);
+
+ // Sample the gradient at the input point.
+ std::tuple<uint8_t, uint8_t, uint8_t> getColorTuple(double Point) const;
+
+ std::string getColorString(double Point) const;
+
+ // Get the Default color, at the moment allways black.
+ std::tuple<uint8_t, uint8_t, uint8_t> getDefaultColorTuple() const {
+ return std::make_tuple(0, 0, 0);
+ }
+
+ std::string getDefaultColorString() const { return "black"; }
+
+ // Convert a tuple to a string
+ static std::string getColorString(std::tuple<uint8_t, uint8_t, uint8_t> t);
+};
+} // namespace xray
+} // namespace llvm
+#endif
diff --git a/contrib/llvm/tools/llvm-xray/xray-converter.cc b/contrib/llvm/tools/llvm-xray/xray-converter.cc
index 1bc9b15..2583ec9 100644
--- a/contrib/llvm/tools/llvm-xray/xray-converter.cc
+++ b/contrib/llvm/tools/llvm-xray/xray-converter.cc
@@ -12,13 +12,14 @@
//===----------------------------------------------------------------------===//
#include "xray-converter.h"
-#include "xray-extract.h"
#include "xray-registry.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/XRay/InstrumentationMap.h"
#include "llvm/XRay/Trace.h"
#include "llvm/XRay/YAMLXRayRecord.h"
@@ -72,18 +73,7 @@ static cl::opt<bool> ConvertSortInput(
static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput),
cl::desc("Alias for -sort"),
cl::sub(Convert));
-static cl::opt<InstrumentationMapExtractor::InputFormats> InstrMapFormat(
- "instr-map-format", cl::desc("format of instrumentation map"),
- cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf",
- "instrumentation map in an ELF header"),
- clEnumValN(InstrumentationMapExtractor::InputFormats::YAML,
- "yaml", "instrumentation map in YAML")),
- cl::sub(Convert), cl::init(InstrumentationMapExtractor::InputFormats::ELF));
-static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat),
- cl::desc("Alias for -instr-map-format"),
- cl::sub(Convert));
-
-using llvm::yaml::IO;
+
using llvm::yaml::Output;
void TraceConverter::exportAsYAML(const Trace &Records, raw_ostream &OS) {
@@ -95,7 +85,7 @@ void TraceConverter::exportAsYAML(const Trace &Records, raw_ostream &OS) {
for (const auto &R : Records) {
Trace.Records.push_back({R.RecordType, R.CPU, R.Type, R.FuncId,
Symbolize ? FuncIdHelper.SymbolOrNumber(R.FuncId)
- : std::to_string(R.FuncId),
+ : llvm::to_string(R.FuncId),
R.TSC, R.TId});
}
Output Out(OS, nullptr, 0);
@@ -128,7 +118,9 @@ void TraceConverter::exportAsRAWv1(const Trace &Records, raw_ostream &OS) {
// format.
for (const auto &R : Records) {
Writer.write(R.RecordType);
- Writer.write(R.CPU);
+ // The on disk naive raw format uses 8 bit CPUs, but the record has 16.
+ // There's no choice but truncation.
+ Writer.write(static_cast<uint8_t>(R.CPU));
switch (R.Type) {
case RecordTypes::ENTER:
Writer.write(uint8_t{0});
@@ -151,25 +143,26 @@ namespace xray {
static CommandRegistration Unused(&Convert, []() -> Error {
// FIXME: Support conversion to BINARY when upgrading XRay trace versions.
- int Fd;
- auto EC = sys::fs::openFileForRead(ConvertInput, Fd);
- if (EC)
- return make_error<StringError>(
- Twine("Cannot open file '") + ConvertInput + "'", EC);
-
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(ConvertInstrMap, InstrMapFormat,
- Err);
- handleAllErrors(std::move(Err),
- [&](const ErrorInfoBase &E) { E.log(errs()); });
+ InstrumentationMap Map;
+ if (!ConvertInstrMap.empty()) {
+ auto InstrumentationMapOrError = loadInstrumentationMap(ConvertInstrMap);
+ if (!InstrumentationMapOrError)
+ return joinErrors(make_error<StringError>(
+ Twine("Cannot open instrumentation map '") +
+ ConvertInstrMap + "'",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
+ Map = std::move(*InstrumentationMapOrError);
+ }
- const auto &FunctionAddresses = Extractor.getFunctionAddresses();
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
symbolize::LLVMSymbolizer::Options Opts(
symbolize::FunctionNameKind::LinkageName, true, true, false, "");
symbolize::LLVMSymbolizer Symbolizer(Opts);
llvm::xray::FuncIdConversionHelper FuncIdHelper(ConvertInstrMap, Symbolizer,
FunctionAddresses);
llvm::xray::TraceConverter TC(FuncIdHelper, ConvertSymbolize);
+ std::error_code EC;
raw_fd_ostream OS(ConvertOutput, EC,
ConvertOutputFormat == ConvertFormats::BINARY
? sys::fs::OpenFlags::F_None
@@ -178,22 +171,22 @@ static CommandRegistration Unused(&Convert, []() -> Error {
return make_error<StringError>(
Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC);
- if (auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput)) {
- auto &T = *TraceOrErr;
- switch (ConvertOutputFormat) {
- case ConvertFormats::YAML:
- TC.exportAsYAML(T, OS);
- break;
- case ConvertFormats::BINARY:
- TC.exportAsRAWv1(T, OS);
- break;
- }
- } else {
+ auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput);
+ if (!TraceOrErr)
return joinErrors(
make_error<StringError>(
Twine("Failed loading input file '") + ConvertInput + "'.",
std::make_error_code(std::errc::executable_format_error)),
TraceOrErr.takeError());
+
+ auto &T = *TraceOrErr;
+ switch (ConvertOutputFormat) {
+ case ConvertFormats::YAML:
+ TC.exportAsYAML(T, OS);
+ break;
+ case ConvertFormats::BINARY:
+ TC.exportAsRAWv1(T, OS);
+ break;
}
return Error::success();
});
diff --git a/contrib/llvm/tools/llvm-xray/xray-extract.cc b/contrib/llvm/tools/llvm-xray/xray-extract.cc
index ecd5351..6b72b81 100644
--- a/contrib/llvm/tools/llvm-xray/xray-extract.cc
+++ b/contrib/llvm/tools/llvm-xray/xray-extract.cc
@@ -16,20 +16,18 @@
#include <type_traits>
#include <utility>
-#include "xray-extract.h"
-
+#include "func-id-helper.h"
#include "xray-registry.h"
-#include "xray-sleds.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DataExtractor.h"
-#include "llvm/Support/ELF.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/XRay/InstrumentationMap.h"
using namespace llvm;
using namespace llvm::xray;
@@ -48,244 +46,57 @@ static cl::opt<std::string>
static cl::alias ExtractOutput2("o", cl::aliasopt(ExtractOutput),
cl::desc("Alias for -output"),
cl::sub(Extract));
-
-struct YAMLXRaySledEntry {
- int32_t FuncId;
- Hex64 Address;
- Hex64 Function;
- SledEntry::FunctionKinds Kind;
- bool AlwaysInstrument;
-};
-
-namespace llvm {
-namespace yaml {
-
-template <> struct ScalarEnumerationTraits<SledEntry::FunctionKinds> {
- static void enumeration(IO &IO, SledEntry::FunctionKinds &Kind) {
- IO.enumCase(Kind, "function-enter", SledEntry::FunctionKinds::ENTRY);
- IO.enumCase(Kind, "function-exit", SledEntry::FunctionKinds::EXIT);
- IO.enumCase(Kind, "tail-exit", SledEntry::FunctionKinds::TAIL);
- }
-};
-
-template <> struct MappingTraits<YAMLXRaySledEntry> {
- static void mapping(IO &IO, YAMLXRaySledEntry &Entry) {
- IO.mapRequired("id", Entry.FuncId);
- IO.mapRequired("address", Entry.Address);
- IO.mapRequired("function", Entry.Function);
- IO.mapRequired("kind", Entry.Kind);
- IO.mapRequired("always-instrument", Entry.AlwaysInstrument);
- }
-
- static constexpr bool flow = true;
-};
-}
-}
-
-LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLXRaySledEntry)
+static cl::opt<bool> ExtractSymbolize("symbolize", cl::value_desc("symbolize"),
+ cl::init(false),
+ cl::desc("symbolize functions"),
+ cl::sub(Extract));
+static cl::alias ExtractSymbolize2("s", cl::aliasopt(ExtractSymbolize),
+ cl::desc("alias for -symbolize"),
+ cl::sub(Extract));
namespace {
-llvm::Error LoadBinaryInstrELF(
- StringRef Filename, std::deque<SledEntry> &OutputSleds,
- InstrumentationMapExtractor::FunctionAddressMap &InstrMap,
- InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) {
- auto ObjectFile = object::ObjectFile::createObjectFile(Filename);
-
- if (!ObjectFile)
- return ObjectFile.takeError();
-
- // FIXME: Maybe support other ELF formats. For now, 64-bit Little Endian only.
- if (!ObjectFile->getBinary()->isELF())
- return make_error<StringError>(
- "File format not supported (only does ELF).",
- std::make_error_code(std::errc::not_supported));
- if (ObjectFile->getBinary()->getArch() != Triple::x86_64)
- return make_error<StringError>(
- "File format not supported (only does ELF little endian 64-bit).",
- std::make_error_code(std::errc::not_supported));
-
- // Find the section named "xray_instr_map".
- StringRef Contents = "";
- const auto &Sections = ObjectFile->getBinary()->sections();
- auto I = find_if(Sections, [&](object::SectionRef Section) {
- StringRef Name = "";
- if (Section.getName(Name))
- return false;
- return Name == "xray_instr_map";
- });
- if (I == Sections.end())
- return make_error<StringError>(
- "Failed to find XRay instrumentation map.",
- std::make_error_code(std::errc::not_supported));
- if (I->getContents(Contents))
- return make_error<StringError>(
- "Failed to get contents of 'xray_instr_map' section.",
- std::make_error_code(std::errc::executable_format_error));
-
- // Copy the instrumentation map data into the Sleds data structure.
- auto C = Contents.bytes_begin();
- static constexpr size_t ELF64SledEntrySize = 32;
-
- if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
- return make_error<StringError>(
- "Instrumentation map entries not evenly divisible by size of an XRay "
- "sled entry in ELF64.",
- std::make_error_code(std::errc::executable_format_error));
-
- int32_t FuncId = 1;
- uint64_t CurFn = 0;
- std::deque<SledEntry> Sleds;
- for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
- DataExtractor Extractor(
- StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true,
- 8);
- Sleds.push_back({});
- auto &Entry = Sleds.back();
- uint32_t OffsetPtr = 0;
- Entry.Address = Extractor.getU64(&OffsetPtr);
- Entry.Function = Extractor.getU64(&OffsetPtr);
- auto Kind = Extractor.getU8(&OffsetPtr);
- switch (Kind) {
- case 0: // ENTRY
- Entry.Kind = SledEntry::FunctionKinds::ENTRY;
- break;
- case 1: // EXIT
- Entry.Kind = SledEntry::FunctionKinds::EXIT;
- break;
- case 2: // TAIL
- Entry.Kind = SledEntry::FunctionKinds::TAIL;
- break;
- default:
- return make_error<StringError>(
- Twine("Encountered unknown sled type ") + "'" + Twine(int32_t{Kind}) +
- "'.",
- std::make_error_code(std::errc::executable_format_error));
- }
- Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
-
- // We replicate the function id generation scheme implemented in the runtime
- // here. Ideally we should be able to break it out, or output this map from
- // the runtime, but that's a design point we can discuss later on. For now,
- // we replicate the logic and move on.
- if (CurFn == 0) {
- CurFn = Entry.Function;
- InstrMap[FuncId] = Entry.Function;
- FunctionIds[Entry.Function] = FuncId;
- }
- if (Entry.Function != CurFn) {
- ++FuncId;
- CurFn = Entry.Function;
- InstrMap[FuncId] = Entry.Function;
- FunctionIds[Entry.Function] = FuncId;
- }
- }
- OutputSleds = std::move(Sleds);
- return llvm::Error::success();
-}
-
-Error LoadYAMLInstrMap(
- StringRef Filename, std::deque<SledEntry> &Sleds,
- InstrumentationMapExtractor::FunctionAddressMap &InstrMap,
- InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) {
- int Fd;
- if (auto EC = sys::fs::openFileForRead(Filename, Fd))
- return make_error<StringError>(
- Twine("Failed opening file '") + Filename + "' for reading.", EC);
-
- uint64_t FileSize;
- if (auto EC = sys::fs::file_size(Filename, FileSize))
- return make_error<StringError>(
- Twine("Failed getting size of file '") + Filename + "'.", EC);
-
- std::error_code EC;
- sys::fs::mapped_file_region MappedFile(
- Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
- if (EC)
- return make_error<StringError>(
- Twine("Failed memory-mapping file '") + Filename + "'.", EC);
-
- std::vector<YAMLXRaySledEntry> YAMLSleds;
- Input In(StringRef(MappedFile.data(), MappedFile.size()));
- In >> YAMLSleds;
- if (In.error())
- return make_error<StringError>(
- Twine("Failed loading YAML document from '") + Filename + "'.",
- In.error());
-
- for (const auto &Y : YAMLSleds) {
- InstrMap[Y.FuncId] = Y.Function;
- FunctionIds[Y.Function] = Y.FuncId;
- Sleds.push_back(
- SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument});
- }
- return Error::success();
-}
-
-} // namespace
-
-InstrumentationMapExtractor::InstrumentationMapExtractor(std::string Filename,
- InputFormats Format,
- Error &EC) {
- ErrorAsOutParameter ErrAsOutputParam(&EC);
- if (Filename.empty()) {
- EC = Error::success();
- return;
- }
- switch (Format) {
- case InputFormats::ELF: {
- EC = handleErrors(
- LoadBinaryInstrELF(Filename, Sleds, FunctionAddresses, FunctionIds),
- [&](std::unique_ptr<ErrorInfoBase> E) {
- return joinErrors(
- make_error<StringError>(
- Twine("Cannot extract instrumentation map from '") +
- Filename + "'.",
- std::make_error_code(std::errc::executable_format_error)),
- std::move(E));
- });
- break;
- }
- case InputFormats::YAML: {
- EC = handleErrors(
- LoadYAMLInstrMap(Filename, Sleds, FunctionAddresses, FunctionIds),
- [&](std::unique_ptr<ErrorInfoBase> E) {
- return joinErrors(
- make_error<StringError>(
- Twine("Cannot load YAML instrumentation map from '") +
- Filename + "'.",
- std::make_error_code(std::errc::executable_format_error)),
- std::move(E));
- });
- break;
- }
- }
-}
-
-void InstrumentationMapExtractor::exportAsYAML(raw_ostream &OS) {
+void exportAsYAML(const InstrumentationMap &Map, raw_ostream &OS,
+ FuncIdConversionHelper &FH) {
// First we translate the sleds into the YAMLXRaySledEntry objects in a deque.
std::vector<YAMLXRaySledEntry> YAMLSleds;
- YAMLSleds.reserve(Sleds.size());
+ auto Sleds = Map.sleds();
+ YAMLSleds.reserve(std::distance(Sleds.begin(), Sleds.end()));
for (const auto &Sled : Sleds) {
- YAMLSleds.push_back({FunctionIds[Sled.Function], Sled.Address,
- Sled.Function, Sled.Kind, Sled.AlwaysInstrument});
+ auto FuncId = Map.getFunctionId(Sled.Function);
+ if (!FuncId)
+ return;
+ YAMLSleds.push_back({*FuncId, Sled.Address, Sled.Function, Sled.Kind,
+ Sled.AlwaysInstrument,
+ ExtractSymbolize ? FH.SymbolOrNumber(*FuncId) : ""});
}
Output Out(OS, nullptr, 0);
Out << YAMLSleds;
}
+} // namespace
+
static CommandRegistration Unused(&Extract, []() -> Error {
- Error Err = Error::success();
- xray::InstrumentationMapExtractor Extractor(
- ExtractInput, InstrumentationMapExtractor::InputFormats::ELF, Err);
- if (Err)
- return Err;
+ auto InstrumentationMapOrError = loadInstrumentationMap(ExtractInput);
+ if (!InstrumentationMapOrError)
+ return joinErrors(make_error<StringError>(
+ Twine("Cannot extract instrumentation map from '") +
+ ExtractInput + "'.",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
std::error_code EC;
raw_fd_ostream OS(ExtractOutput, EC, sys::fs::OpenFlags::F_Text);
if (EC)
return make_error<StringError>(
Twine("Cannot open file '") + ExtractOutput + "' for writing.", EC);
- Extractor.exportAsYAML(OS);
+ const auto &FunctionAddresses =
+ InstrumentationMapOrError->getFunctionAddresses();
+ symbolize::LLVMSymbolizer::Options Opts(
+ symbolize::FunctionNameKind::LinkageName, true, true, false, "");
+ symbolize::LLVMSymbolizer Symbolizer(Opts);
+ llvm::xray::FuncIdConversionHelper FuncIdHelper(ExtractInput, Symbolizer,
+ FunctionAddresses);
+ exportAsYAML(*InstrumentationMapOrError, OS, FuncIdHelper);
return Error::success();
});
diff --git a/contrib/llvm/tools/llvm-xray/xray-extract.h b/contrib/llvm/tools/llvm-xray/xray-extract.h
deleted file mode 100644
index 91e4db3..0000000
--- a/contrib/llvm/tools/llvm-xray/xray-extract.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//===- xray-extract.h - XRay Instrumentation Map Extraction ---------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the interface for extracting the instrumentation map from an
-// XRay-instrumented binary.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_XRAY_EXTRACT_H
-#define LLVM_TOOLS_XRAY_EXTRACT_H
-
-#include <deque>
-#include <map>
-#include <string>
-#include <unordered_map>
-
-#include "xray-sleds.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace llvm {
-namespace xray {
-
-class InstrumentationMapExtractor {
-public:
- typedef std::unordered_map<int32_t, uint64_t> FunctionAddressMap;
- typedef std::unordered_map<uint64_t, int32_t> FunctionAddressReverseMap;
-
- enum class InputFormats { ELF, YAML };
-
-private:
- std::deque<SledEntry> Sleds;
- FunctionAddressMap FunctionAddresses;
- FunctionAddressReverseMap FunctionIds;
-
-public:
- /// Loads the instrumentation map from |Filename|. Updates |EC| in case there
- /// were errors encountered opening the file. |Format| defines what the input
- /// instrumentation map is in.
- InstrumentationMapExtractor(std::string Filename, InputFormats Format,
- Error &EC);
-
- const FunctionAddressMap &getFunctionAddresses() { return FunctionAddresses; }
-
- /// Exports the loaded function address map as YAML through |OS|.
- void exportAsYAML(raw_ostream &OS);
-};
-
-} // namespace xray
-} // namespace llvm
-
-#endif // LLVM_TOOLS_XRAY_EXTRACT_H
diff --git a/contrib/llvm/tools/llvm-xray/xray-graph-diff.cc b/contrib/llvm/tools/llvm-xray/xray-graph-diff.cc
new file mode 100644
index 0000000..3c69b3f
--- /dev/null
+++ b/contrib/llvm/tools/llvm-xray/xray-graph-diff.cc
@@ -0,0 +1,484 @@
+//===-- xray-graph-diff.cc - XRay Function Call Graph Renderer ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Generate a DOT file to represent the function call graph encountered in
+// the trace.
+//
+//===----------------------------------------------------------------------===//
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <string>
+
+#include "xray-graph-diff.h"
+#include "xray-graph.h"
+#include "xray-registry.h"
+
+#include "xray-color-helper.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/XRay/Trace.h"
+
+using namespace llvm;
+using namespace xray;
+
+static cl::SubCommand GraphDiff("graph-diff",
+ "Generate diff of function-call graphs");
+static cl::opt<std::string> GraphDiffInput1(cl::Positional,
+ cl::desc("<xray log file 1>"),
+ cl::Required, cl::sub(GraphDiff));
+static cl::opt<std::string> GraphDiffInput2(cl::Positional,
+ cl::desc("<xray log file 2>"),
+ cl::Required, cl::sub(GraphDiff));
+
+static cl::opt<bool>
+ GraphDiffKeepGoing("keep-going",
+ cl::desc("Keep going on errors encountered"),
+ cl::sub(GraphDiff), cl::init(false));
+static cl::alias GraphDiffKeepGoingA("k", cl::aliasopt(GraphDiffKeepGoing),
+ cl::desc("Alias for -keep-going"),
+ cl::sub(GraphDiff));
+static cl::opt<bool>
+ GraphDiffKeepGoing1("keep-going-1",
+ cl::desc("Keep going on errors encountered in trace 1"),
+ cl::sub(GraphDiff), cl::init(false));
+static cl::alias GraphDiffKeepGoing1A("k1", cl::aliasopt(GraphDiffKeepGoing1),
+ cl::desc("Alias for -keep-going-1"),
+ cl::sub(GraphDiff));
+static cl::opt<bool>
+ GraphDiffKeepGoing2("keep-going-2",
+ cl::desc("Keep going on errors encountered in trace 2"),
+ cl::sub(GraphDiff), cl::init(false));
+static cl::alias GraphDiffKeepGoing2A("k2", cl::aliasopt(GraphDiffKeepGoing2),
+ cl::desc("Alias for -keep-going-2"),
+ cl::sub(GraphDiff));
+
+static cl::opt<std::string>
+ GraphDiffInstrMap("instr-map",
+ cl::desc("binary with the instrumentation map, or "
+ "a separate instrumentation map for graph"),
+ cl::value_desc("binary with xray_instr_map or yaml"),
+ cl::sub(GraphDiff), cl::init(""));
+static cl::alias GraphDiffInstrMapA("m", cl::aliasopt(GraphDiffInstrMap),
+ cl::desc("Alias for -instr-map"),
+ cl::sub(GraphDiff));
+static cl::opt<std::string>
+ GraphDiffInstrMap1("instr-map-1",
+ cl::desc("binary with the instrumentation map, or "
+ "a separate instrumentation map for graph 1"),
+ cl::value_desc("binary with xray_instr_map or yaml"),
+ cl::sub(GraphDiff), cl::init(""));
+static cl::alias GraphDiffInstrMap1A("m1", cl::aliasopt(GraphDiffInstrMap1),
+ cl::desc("Alias for -instr-map-1"),
+ cl::sub(GraphDiff));
+static cl::opt<std::string>
+ GraphDiffInstrMap2("instr-map-2",
+ cl::desc("binary with the instrumentation map, or "
+ "a separate instrumentation map for graph 2"),
+ cl::value_desc("binary with xray_instr_map or yaml"),
+ cl::sub(GraphDiff), cl::init(""));
+static cl::alias GraphDiffInstrMap2A("m2", cl::aliasopt(GraphDiffInstrMap2),
+ cl::desc("Alias for -instr-map-2"),
+ cl::sub(GraphDiff));
+
+static cl::opt<bool> GraphDiffDeduceSiblingCalls(
+ "deduce-sibling-calls",
+ cl::desc("Deduce sibling calls when unrolling function call stacks"),
+ cl::sub(GraphDiff), cl::init(false));
+static cl::alias
+ GraphDiffDeduceSiblingCallsA("d", cl::aliasopt(GraphDiffDeduceSiblingCalls),
+ cl::desc("Alias for -deduce-sibling-calls"),
+ cl::sub(GraphDiff));
+static cl::opt<bool> GraphDiffDeduceSiblingCalls1(
+ "deduce-sibling-calls-1",
+ cl::desc("Deduce sibling calls when unrolling function call stacks"),
+ cl::sub(GraphDiff), cl::init(false));
+static cl::alias GraphDiffDeduceSiblingCalls1A(
+ "d1", cl::aliasopt(GraphDiffDeduceSiblingCalls1),
+ cl::desc("Alias for -deduce-sibling-calls-1"), cl::sub(GraphDiff));
+static cl::opt<bool> GraphDiffDeduceSiblingCalls2(
+ "deduce-sibling-calls-2",
+ cl::desc("Deduce sibling calls when unrolling function call stacks"),
+ cl::sub(GraphDiff), cl::init(false));
+static cl::alias GraphDiffDeduceSiblingCalls2A(
+ "d2", cl::aliasopt(GraphDiffDeduceSiblingCalls2),
+ cl::desc("Alias for -deduce-sibling-calls-2"), cl::sub(GraphDiff));
+
+static cl::opt<GraphRenderer::StatType> GraphDiffEdgeLabel(
+ "edge-label", cl::desc("Output graphs with edges labeled with this field"),
+ cl::value_desc("field"), cl::sub(GraphDiff),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not label Edges"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ clEnumValN(GraphRenderer::StatType::SUM, "sum",
+ "sum of call durations")));
+static cl::alias GraphDiffEdgeLabelA("e", cl::aliasopt(GraphDiffEdgeLabel),
+ cl::desc("Alias for -edge-label"),
+ cl::sub(GraphDiff));
+
+static cl::opt<GraphRenderer::StatType> GraphDiffEdgeColor(
+ "edge-color", cl::desc("Output graphs with edges colored by this field"),
+ cl::value_desc("field"), cl::sub(GraphDiff),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not color Edges"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ clEnumValN(GraphRenderer::StatType::SUM, "sum",
+ "sum of call durations")));
+static cl::alias GraphDiffEdgeColorA("c", cl::aliasopt(GraphDiffEdgeColor),
+ cl::desc("Alias for -edge-color"),
+ cl::sub(GraphDiff));
+
+static cl::opt<GraphRenderer::StatType> GraphDiffVertexLabel(
+ "vertex-label",
+ cl::desc("Output graphs with vertices labeled with this field"),
+ cl::value_desc("field"), cl::sub(GraphDiff),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not label Vertices"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ clEnumValN(GraphRenderer::StatType::SUM, "sum",
+ "sum of call durations")));
+static cl::alias GraphDiffVertexLabelA("v", cl::aliasopt(GraphDiffVertexLabel),
+ cl::desc("Alias for -vertex-label"),
+ cl::sub(GraphDiff));
+
+static cl::opt<GraphRenderer::StatType> GraphDiffVertexColor(
+ "vertex-color",
+ cl::desc("Output graphs with vertices colored by this field"),
+ cl::value_desc("field"), cl::sub(GraphDiff),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not color Vertices"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ clEnumValN(GraphRenderer::StatType::SUM, "sum",
+ "sum of call durations")));
+static cl::alias GraphDiffVertexColorA("b", cl::aliasopt(GraphDiffVertexColor),
+ cl::desc("Alias for -vertex-color"),
+ cl::sub(GraphDiff));
+
+static cl::opt<int> GraphDiffVertexLabelTrunc(
+ "vertex-label-trun", cl::desc("What length to truncate vertex labels to "),
+ cl::sub(GraphDiff), cl::init(40));
+static cl::alias
+ GraphDiffVertexLabelTrunc1("t", cl::aliasopt(GraphDiffVertexLabelTrunc),
+ cl::desc("Alias for -vertex-label-trun"),
+ cl::sub(GraphDiff));
+
+static cl::opt<std::string>
+ GraphDiffOutput("output", cl::value_desc("Output file"), cl::init("-"),
+ cl::desc("output file; use '-' for stdout"),
+ cl::sub(GraphDiff));
+static cl::alias GraphDiffOutputA("o", cl::aliasopt(GraphDiffOutput),
+ cl::desc("Alias for -output"),
+ cl::sub(GraphDiff));
+
+Expected<GraphDiffRenderer> GraphDiffRenderer::Factory::getGraphDiffRenderer() {
+ GraphDiffRenderer R;
+
+ for (int i = 0; i < N; ++i) {
+ const auto &G = this->G[i].get();
+ for (const auto &V : G.vertices()) {
+ const auto &VAttr = V.second;
+ R.G[VAttr.SymbolName].CorrVertexPtr[i] = &V;
+ }
+ for (const auto &E : G.edges()) {
+ auto &EdgeTailID = E.first.first;
+ auto &EdgeHeadID = E.first.second;
+ auto EdgeTailAttrOrErr = G.at(EdgeTailID);
+ auto EdgeHeadAttrOrErr = G.at(EdgeHeadID);
+ if (!EdgeTailAttrOrErr)
+ return EdgeTailAttrOrErr.takeError();
+ if (!EdgeHeadAttrOrErr)
+ return EdgeHeadAttrOrErr.takeError();
+ GraphT::EdgeIdentifier ID{EdgeTailAttrOrErr->SymbolName,
+ EdgeHeadAttrOrErr->SymbolName};
+ R.G[ID].CorrEdgePtr[i] = &E;
+ }
+ }
+
+ return R;
+}
+// Returns the Relative change With respect to LeftStat between LeftStat
+// and RightStat.
+static double statRelDiff(const GraphDiffRenderer::TimeStat &LeftStat,
+ const GraphDiffRenderer::TimeStat &RightStat,
+ GraphDiffRenderer::StatType T) {
+ double LeftAttr = LeftStat.getDouble(T);
+ double RightAttr = RightStat.getDouble(T);
+
+ return RightAttr / LeftAttr - 1.0;
+}
+
+static std::string getColor(const GraphDiffRenderer::GraphT::EdgeValueType &E,
+ const GraphDiffRenderer::GraphT &G, ColorHelper H,
+ GraphDiffRenderer::StatType T) {
+ auto &EdgeAttr = E.second;
+ if (EdgeAttr.CorrEdgePtr[0] == nullptr)
+ return H.getColorString(2.0); // A number greater than 1.0
+ if (EdgeAttr.CorrEdgePtr[1] == nullptr)
+ return H.getColorString(-2.0); // A number less than -1.0
+
+ if (T == GraphDiffRenderer::StatType::NONE)
+ return H.getDefaultColorString();
+
+ const auto &LeftStat = EdgeAttr.CorrEdgePtr[0]->second.S;
+ const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
+
+ double RelDiff = statRelDiff(LeftStat, RightStat, T);
+ double CappedRelDiff = std::min(1.0, std::max(-1.0, RelDiff));
+
+ return H.getColorString(CappedRelDiff);
+}
+
+static std::string getColor(const GraphDiffRenderer::GraphT::VertexValueType &V,
+ const GraphDiffRenderer::GraphT &G, ColorHelper H,
+ GraphDiffRenderer::StatType T) {
+ auto &VertexAttr = V.second;
+ if (VertexAttr.CorrVertexPtr[0] == nullptr)
+ return H.getColorString(2.0); // A number greater than 1.0
+ if (VertexAttr.CorrVertexPtr[1] == nullptr)
+ return H.getColorString(-2.0); // A number less than -1.0
+
+ if (T == GraphDiffRenderer::StatType::NONE)
+ return H.getDefaultColorString();
+
+ const auto &LeftStat = VertexAttr.CorrVertexPtr[0]->second.S;
+ const auto &RightStat = VertexAttr.CorrVertexPtr[1]->second.S;
+
+ double RelDiff = statRelDiff(LeftStat, RightStat, T);
+ double CappedRelDiff = std::min(1.0, std::max(-1.0, RelDiff));
+
+ return H.getColorString(CappedRelDiff);
+}
+
+static Twine truncateString(const StringRef &S, size_t n) {
+ return (S.size() > n) ? Twine(S.substr(0, n)) + "..." : Twine(S);
+}
+
+template <typename T> static bool containsNullptr(const T &Collection) {
+ for (const auto &E : Collection)
+ if (E == nullptr)
+ return true;
+ return false;
+}
+
+static std::string getLabel(const GraphDiffRenderer::GraphT::EdgeValueType &E,
+ GraphDiffRenderer::StatType EL) {
+ auto &EdgeAttr = E.second;
+ switch (EL) {
+ case GraphDiffRenderer::StatType::NONE:
+ return "";
+ default:
+ if (containsNullptr(EdgeAttr.CorrEdgePtr))
+ return "";
+
+ const auto &LeftStat = EdgeAttr.CorrEdgePtr[0]->second.S;
+ const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
+
+ double RelDiff = statRelDiff(LeftStat, RightStat, EL);
+ return formatv(R"({0:P})", RelDiff);
+ }
+}
+
+static std::string getLabel(const GraphDiffRenderer::GraphT::VertexValueType &V,
+ GraphDiffRenderer::StatType VL, int TrunLen) {
+ const auto &VertexId = V.first;
+ const auto &VertexAttr = V.second;
+ switch (VL) {
+ case GraphDiffRenderer::StatType::NONE:
+ return formatv(R"({0})", truncateString(VertexId, TrunLen).str());
+ default:
+ if (containsNullptr(VertexAttr.CorrVertexPtr))
+ return formatv(R"({0})", truncateString(VertexId, TrunLen).str());
+
+ const auto &LeftStat = VertexAttr.CorrVertexPtr[0]->second.S;
+ const auto &RightStat = VertexAttr.CorrVertexPtr[1]->second.S;
+
+ double RelDiff = statRelDiff(LeftStat, RightStat, VL);
+ return formatv(R"({{{0}|{1:P}})", truncateString(VertexId, TrunLen).str(),
+ RelDiff);
+ }
+}
+
+static double getLineWidth(const GraphDiffRenderer::GraphT::EdgeValueType &E,
+ GraphDiffRenderer::StatType EL) {
+ auto &EdgeAttr = E.second;
+ switch (EL) {
+ case GraphDiffRenderer::StatType::NONE:
+ return 1.0;
+ default:
+ if (containsNullptr(EdgeAttr.CorrEdgePtr))
+ return 1.0;
+
+ const auto &LeftStat = EdgeAttr.CorrEdgePtr[0]->second.S;
+ const auto &RightStat = EdgeAttr.CorrEdgePtr[1]->second.S;
+
+ double RelDiff = statRelDiff(LeftStat, RightStat, EL);
+ return (RelDiff > 1.0) ? RelDiff : 1.0;
+ }
+}
+
+void GraphDiffRenderer::exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel,
+ StatType EdgeColor,
+ StatType VertexLabel,
+ StatType VertexColor, int TruncLen) {
+ // Get numbering of vertices for dot output.
+ StringMap<int32_t> VertexNo;
+
+ int i = 0;
+ for (const auto &V : G.vertices()) {
+ VertexNo[V.first] = i++;
+ }
+
+ ColorHelper H(ColorHelper::DivergingScheme::PiYG);
+
+ OS << "digraph xrayDiff {\n";
+
+ if (VertexLabel != StatType::NONE)
+ OS << "node [shape=record]\n";
+
+ for (const auto &E : G.edges()) {
+ const auto &HeadId = E.first.first;
+ const auto &TailId = E.first.second;
+ OS << formatv(R"(F{0} -> F{1} [tooltip="{2} -> {3}" label="{4}" )"
+ R"(color="{5}" labelfontcolor="{5}" penwidth={6}])"
+ "\n",
+ VertexNo[HeadId], VertexNo[TailId],
+ (HeadId.equals("")) ? static_cast<StringRef>("F0") : HeadId,
+ TailId, getLabel(E, EdgeLabel), getColor(E, G, H, EdgeColor),
+ getLineWidth(E, EdgeColor));
+ }
+
+ for (const auto &V : G.vertices()) {
+ const auto &VertexId = V.first;
+ if (VertexId.equals("")) {
+ OS << formatv(R"(F{0} [label="F0"])"
+ "\n",
+ VertexNo[VertexId]);
+ continue;
+ }
+ OS << formatv(R"(F{0} [label="{1}" color="{2}"])"
+ "\n",
+ VertexNo[VertexId], getLabel(V, VertexLabel, TruncLen),
+ getColor(V, G, H, VertexColor));
+ }
+
+ OS << "}\n";
+}
+
+template <typename T> static T &ifSpecified(T &A, cl::alias &AA, T &B) {
+ if (A.getPosition() == 0 && AA.getPosition() == 0)
+ return B;
+
+ return A;
+}
+
+static CommandRegistration Unused(&GraphDiff, []() -> Error {
+ std::array<GraphRenderer::Factory, 2> Factories{
+ {{ifSpecified(GraphDiffKeepGoing1, GraphDiffKeepGoing1A,
+ GraphDiffKeepGoing),
+ ifSpecified(GraphDiffDeduceSiblingCalls1, GraphDiffDeduceSiblingCalls1A,
+ GraphDiffDeduceSiblingCalls),
+ ifSpecified(GraphDiffInstrMap1, GraphDiffInstrMap1A, GraphDiffInstrMap),
+ Trace()},
+ {ifSpecified(GraphDiffKeepGoing2, GraphDiffKeepGoing2A,
+ GraphDiffKeepGoing),
+ ifSpecified(GraphDiffDeduceSiblingCalls2, GraphDiffDeduceSiblingCalls2A,
+ GraphDiffDeduceSiblingCalls),
+ ifSpecified(GraphDiffInstrMap2, GraphDiffInstrMap2A, GraphDiffInstrMap),
+ Trace()}}};
+
+ std::array<std::string, 2> Inputs{{GraphDiffInput1, GraphDiffInput2}};
+
+ std::array<GraphRenderer::GraphT, 2> Graphs;
+
+ for (int i = 0; i < 2; i++) {
+ auto TraceOrErr = loadTraceFile(Inputs[i], true);
+ if (!TraceOrErr)
+ return make_error<StringError>(
+ Twine("Failed Loading Input File '") + Inputs[i] + "'",
+ make_error_code(llvm::errc::invalid_argument));
+ Factories[i].Trace = std::move(*TraceOrErr);
+
+ auto GraphRendererOrErr = Factories[i].getGraphRenderer();
+
+ if (!GraphRendererOrErr)
+ return GraphRendererOrErr.takeError();
+
+ auto GraphRenderer = *GraphRendererOrErr;
+
+ Graphs[i] = GraphRenderer.getGraph();
+ }
+
+ GraphDiffRenderer::Factory DGF(Graphs[0], Graphs[1]);
+
+ auto GDROrErr = DGF.getGraphDiffRenderer();
+ if (!GDROrErr)
+ return GDROrErr.takeError();
+
+ auto &GDR = *GDROrErr;
+
+ std::error_code EC;
+ raw_fd_ostream OS(GraphDiffOutput, EC, sys::fs::OpenFlags::F_Text);
+ if (EC)
+ return make_error<StringError>(
+ Twine("Cannot open file '") + GraphDiffOutput + "' for writing.", EC);
+
+ GDR.exportGraphAsDOT(OS, GraphDiffEdgeLabel, GraphDiffEdgeColor,
+ GraphDiffVertexLabel, GraphDiffVertexColor,
+ GraphDiffVertexLabelTrunc);
+
+ return Error::success();
+});
diff --git a/contrib/llvm/tools/llvm-xray/xray-graph-diff.h b/contrib/llvm/tools/llvm-xray/xray-graph-diff.h
new file mode 100644
index 0000000..5abec91
--- /dev/null
+++ b/contrib/llvm/tools/llvm-xray/xray-graph-diff.h
@@ -0,0 +1,74 @@
+//===-- xray-graph-diff.h - XRay Graph Diff Renderer ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Generate a DOT file to represent the difference between the function call
+// graph of two differnent traces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef XRAY_GRAPH_DIFF_H
+#define XRAY_GRAPH_DIFF_H
+
+#include "xray-graph.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/XRay/Graph.h"
+
+namespace llvm {
+namespace xray {
+
+// This class creates a graph representing the difference between two
+// xray-graphs And allows you to print it to a dot file, with optional color
+// coding.
+class GraphDiffRenderer {
+ static const int N = 2;
+
+public:
+ using StatType = GraphRenderer::StatType;
+ using TimeStat = GraphRenderer::TimeStat;
+
+ using GREdgeValueType = GraphRenderer::GraphT::EdgeValueType;
+ using GRVertexValueType = GraphRenderer::GraphT::VertexValueType;
+
+ struct EdgeAttribute {
+ std::array<const GREdgeValueType *, N> CorrEdgePtr = {};
+ };
+
+ struct VertexAttribute {
+ std::array<const GRVertexValueType *, N> CorrVertexPtr = {};
+ };
+
+ using GraphT = Graph<VertexAttribute, EdgeAttribute, StringRef>;
+
+ class Factory {
+ std::array<std::reference_wrapper<const GraphRenderer::GraphT>, N> G;
+
+ public:
+ template <typename... Ts> Factory(Ts &... Args) : G{{Args...}} {}
+
+ Expected<GraphDiffRenderer> getGraphDiffRenderer();
+ };
+
+private:
+ GraphT G;
+
+ GraphDiffRenderer() = default;
+
+public:
+ void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE,
+ StatType EdgeColor = StatType::NONE,
+ StatType VertexLabel = StatType::NONE,
+ StatType VertexColor = StatType::NONE,
+ int TruncLen = 40);
+
+ const GraphT &getGraph() { return G; }
+};
+} // namespace xray
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-xray/xray-graph.cc b/contrib/llvm/tools/llvm-xray/xray-graph.cc
new file mode 100644
index 0000000..685c24c
--- /dev/null
+++ b/contrib/llvm/tools/llvm-xray/xray-graph.cc
@@ -0,0 +1,521 @@
+//===-- xray-graph.cc - XRay Function Call Graph Renderer -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Generate a DOT file to represent the function call graph encountered in
+// the trace.
+//
+//===----------------------------------------------------------------------===//
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <system_error>
+#include <utility>
+
+#include "xray-graph.h"
+#include "xray-registry.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/XRay/InstrumentationMap.h"
+#include "llvm/XRay/Trace.h"
+#include "llvm/XRay/YAMLXRayRecord.h"
+
+using namespace llvm;
+using namespace llvm::xray;
+
+// Setup llvm-xray graph subcommand and its options.
+static cl::SubCommand GraphC("graph", "Generate function-call graph");
+static cl::opt<std::string> GraphInput(cl::Positional,
+ cl::desc("<xray log file>"),
+ cl::Required, cl::sub(GraphC));
+
+static cl::opt<bool>
+ GraphKeepGoing("keep-going", cl::desc("Keep going on errors encountered"),
+ cl::sub(GraphC), cl::init(false));
+static cl::alias GraphKeepGoing2("k", cl::aliasopt(GraphKeepGoing),
+ cl::desc("Alias for -keep-going"),
+ cl::sub(GraphC));
+
+static cl::opt<std::string>
+ GraphOutput("output", cl::value_desc("Output file"), cl::init("-"),
+ cl::desc("output file; use '-' for stdout"), cl::sub(GraphC));
+static cl::alias GraphOutput2("o", cl::aliasopt(GraphOutput),
+ cl::desc("Alias for -output"), cl::sub(GraphC));
+
+static cl::opt<std::string>
+ GraphInstrMap("instr_map",
+ cl::desc("binary with the instrumrntation map, or "
+ "a separate instrumentation map"),
+ cl::value_desc("binary with xray_instr_map"), cl::sub(GraphC),
+ cl::init(""));
+static cl::alias GraphInstrMap2("m", cl::aliasopt(GraphInstrMap),
+ cl::desc("alias for -instr_map"),
+ cl::sub(GraphC));
+
+static cl::opt<bool> GraphDeduceSiblingCalls(
+ "deduce-sibling-calls",
+ cl::desc("Deduce sibling calls when unrolling function call stacks"),
+ cl::sub(GraphC), cl::init(false));
+static cl::alias
+ GraphDeduceSiblingCalls2("d", cl::aliasopt(GraphDeduceSiblingCalls),
+ cl::desc("Alias for -deduce-sibling-calls"),
+ cl::sub(GraphC));
+
+static cl::opt<GraphRenderer::StatType>
+ GraphEdgeLabel("edge-label",
+ cl::desc("Output graphs with edges labeled with this field"),
+ cl::value_desc("field"), cl::sub(GraphC),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not label Edges"),
+ clEnumValN(GraphRenderer::StatType::COUNT,
+ "count", "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ clEnumValN(GraphRenderer::StatType::SUM, "sum",
+ "sum of call durations")));
+static cl::alias GraphEdgeLabel2("e", cl::aliasopt(GraphEdgeLabel),
+ cl::desc("Alias for -edge-label"),
+ cl::sub(GraphC));
+
+static cl::opt<GraphRenderer::StatType> GraphVertexLabel(
+ "vertex-label",
+ cl::desc("Output graphs with vertices labeled with this field"),
+ cl::value_desc("field"), cl::sub(GraphC),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not label Vertices"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ clEnumValN(GraphRenderer::StatType::SUM, "sum",
+ "sum of call durations")));
+static cl::alias GraphVertexLabel2("v", cl::aliasopt(GraphVertexLabel),
+ cl::desc("Alias for -edge-label"),
+ cl::sub(GraphC));
+
+static cl::opt<GraphRenderer::StatType> GraphEdgeColorType(
+ "color-edges",
+ cl::desc("Output graphs with edge colors determined by this field"),
+ cl::value_desc("field"), cl::sub(GraphC),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not color Edges"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ clEnumValN(GraphRenderer::StatType::SUM, "sum",
+ "sum of call durations")));
+static cl::alias GraphEdgeColorType2("c", cl::aliasopt(GraphEdgeColorType),
+ cl::desc("Alias for -color-edges"),
+ cl::sub(GraphC));
+
+static cl::opt<GraphRenderer::StatType> GraphVertexColorType(
+ "color-vertices",
+ cl::desc("Output graphs with vertex colors determined by this field"),
+ cl::value_desc("field"), cl::sub(GraphC),
+ cl::init(GraphRenderer::StatType::NONE),
+ cl::values(clEnumValN(GraphRenderer::StatType::NONE, "none",
+ "Do not color vertices"),
+ clEnumValN(GraphRenderer::StatType::COUNT, "count",
+ "function call counts"),
+ clEnumValN(GraphRenderer::StatType::MIN, "min",
+ "minimum function durations"),
+ clEnumValN(GraphRenderer::StatType::MED, "med",
+ "median function durations"),
+ clEnumValN(GraphRenderer::StatType::PCT90, "90p",
+ "90th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::PCT99, "99p",
+ "99th percentile durations"),
+ clEnumValN(GraphRenderer::StatType::MAX, "max",
+ "maximum function durations"),
+ clEnumValN(GraphRenderer::StatType::SUM, "sum",
+ "sum of call durations")));
+static cl::alias GraphVertexColorType2("b", cl::aliasopt(GraphVertexColorType),
+ cl::desc("Alias for -edge-label"),
+ cl::sub(GraphC));
+
+template <class T> T diff(T L, T R) { return std::max(L, R) - std::min(L, R); }
+
+// Updates the statistics for a GraphRenderer::TimeStat
+static void updateStat(GraphRenderer::TimeStat &S, int64_t L) {
+ S.Count++;
+ if (S.Min > L || S.Min == 0)
+ S.Min = L;
+ if (S.Max < L)
+ S.Max = L;
+ S.Sum += L;
+}
+
+// Evaluates an XRay record and performs accounting on it.
+//
+// If the record is an ENTER record it pushes the FuncID and TSC onto a
+// structure representing the call stack for that function.
+// If the record is an EXIT record it checks computes computes the ammount of
+// time the function took to complete and then stores that information in an
+// edge of the graph. If there is no matching ENTER record the function tries
+// to recover by assuming that there were EXIT records which were missed, for
+// example caused by tail call elimination and if the option is enabled then
+// then tries to recover from this.
+//
+// This funciton will also error if the records are out of order, as the trace
+// is expected to be sorted.
+//
+// The graph generated has an immaginary root for functions called by no-one at
+// FuncId 0.
+//
+// FIXME: Refactor this and account subcommand to reduce code duplication.
+Error GraphRenderer::accountRecord(const XRayRecord &Record) {
+ using std::make_error_code;
+ using std::errc;
+ if (CurrentMaxTSC == 0)
+ CurrentMaxTSC = Record.TSC;
+
+ if (Record.TSC < CurrentMaxTSC)
+ return make_error<StringError>("Records not in order",
+ make_error_code(errc::invalid_argument));
+
+ auto &ThreadStack = PerThreadFunctionStack[Record.TId];
+ switch (Record.Type) {
+ case RecordTypes::ENTER: {
+ if (Record.FuncId != 0 && G.count(Record.FuncId) == 0)
+ G[Record.FuncId].SymbolName = FuncIdHelper.SymbolOrNumber(Record.FuncId);
+ ThreadStack.push_back({Record.FuncId, Record.TSC});
+ break;
+ }
+ case RecordTypes::EXIT: {
+ // FIXME: Refactor this and the account subcommand to reduce code
+ // duplication
+ if (ThreadStack.size() == 0 || ThreadStack.back().FuncId != Record.FuncId) {
+ if (!DeduceSiblingCalls)
+ return make_error<StringError>("No matching ENTRY record",
+ make_error_code(errc::invalid_argument));
+ auto Parent = std::find_if(
+ ThreadStack.rbegin(), ThreadStack.rend(),
+ [&](const FunctionAttr &A) { return A.FuncId == Record.FuncId; });
+ if (Parent == ThreadStack.rend())
+ return make_error<StringError>(
+ "No matching Entry record in stack",
+ make_error_code(errc::invalid_argument)); // There is no matching
+ // Function for this exit.
+ while (ThreadStack.back().FuncId != Record.FuncId) {
+ TimestampT D = diff(ThreadStack.back().TSC, Record.TSC);
+ VertexIdentifier TopFuncId = ThreadStack.back().FuncId;
+ ThreadStack.pop_back();
+ assert(ThreadStack.size() != 0);
+ EdgeIdentifier EI(ThreadStack.back().FuncId, TopFuncId);
+ auto &EA = G[EI];
+ EA.Timings.push_back(D);
+ updateStat(EA.S, D);
+ updateStat(G[TopFuncId].S, D);
+ }
+ }
+ uint64_t D = diff(ThreadStack.back().TSC, Record.TSC);
+ ThreadStack.pop_back();
+ VertexIdentifier VI = ThreadStack.empty() ? 0 : ThreadStack.back().FuncId;
+ EdgeIdentifier EI(VI, Record.FuncId);
+ auto &EA = G[EI];
+ EA.Timings.push_back(D);
+ updateStat(EA.S, D);
+ updateStat(G[Record.FuncId].S, D);
+ break;
+ }
+ }
+
+ return Error::success();
+}
+
+template <typename U>
+void GraphRenderer::getStats(U begin, U end, GraphRenderer::TimeStat &S) {
+ if (begin == end) return;
+ std::ptrdiff_t MedianOff = S.Count / 2;
+ std::nth_element(begin, begin + MedianOff, end);
+ S.Median = *(begin + MedianOff);
+ std::ptrdiff_t Pct90Off = (S.Count * 9) / 10;
+ std::nth_element(begin, begin + Pct90Off, end);
+ S.Pct90 = *(begin + Pct90Off);
+ std::ptrdiff_t Pct99Off = (S.Count * 99) / 100;
+ std::nth_element(begin, begin + Pct99Off, end);
+ S.Pct99 = *(begin + Pct99Off);
+}
+
+void GraphRenderer::updateMaxStats(const GraphRenderer::TimeStat &S,
+ GraphRenderer::TimeStat &M) {
+ M.Count = std::max(M.Count, S.Count);
+ M.Min = std::max(M.Min, S.Min);
+ M.Median = std::max(M.Median, S.Median);
+ M.Pct90 = std::max(M.Pct90, S.Pct90);
+ M.Pct99 = std::max(M.Pct99, S.Pct99);
+ M.Max = std::max(M.Max, S.Max);
+ M.Sum = std::max(M.Sum, S.Sum);
+}
+
+void GraphRenderer::calculateEdgeStatistics() {
+ assert(!G.edges().empty());
+ for (auto &E : G.edges()) {
+ auto &A = E.second;
+ assert(!A.Timings.empty());
+ getStats(A.Timings.begin(), A.Timings.end(), A.S);
+ updateMaxStats(A.S, G.GraphEdgeMax);
+ }
+}
+
+void GraphRenderer::calculateVertexStatistics() {
+ std::vector<uint64_t> TempTimings;
+ for (auto &V : G.vertices()) {
+ if (V.first != 0) {
+ for (auto &E : G.inEdges(V.first)) {
+ auto &A = E.second;
+ TempTimings.insert(TempTimings.end(), A.Timings.begin(),
+ A.Timings.end());
+ }
+ getStats(TempTimings.begin(), TempTimings.end(), G[V.first].S);
+ updateMaxStats(G[V.first].S, G.GraphVertexMax);
+ TempTimings.clear();
+ }
+ }
+}
+
+// A Helper function for normalizeStatistics which normalises a single
+// TimeStat element.
+static void normalizeTimeStat(GraphRenderer::TimeStat &S,
+ double CycleFrequency) {
+ int64_t OldCount = S.Count;
+ S = S / CycleFrequency;
+ S.Count = OldCount;
+}
+
+// Normalises the statistics in the graph for a given TSC frequency.
+void GraphRenderer::normalizeStatistics(double CycleFrequency) {
+ for (auto &E : G.edges()) {
+ auto &S = E.second.S;
+ normalizeTimeStat(S, CycleFrequency);
+ }
+ for (auto &V : G.vertices()) {
+ auto &S = V.second.S;
+ normalizeTimeStat(S, CycleFrequency);
+ }
+
+ normalizeTimeStat(G.GraphEdgeMax, CycleFrequency);
+ normalizeTimeStat(G.GraphVertexMax, CycleFrequency);
+}
+
+// Returns a string containing the value of statistic field T
+std::string
+GraphRenderer::TimeStat::getString(GraphRenderer::StatType T) const {
+ std::string St;
+ raw_string_ostream S{St};
+ double TimeStat::*DoubleStatPtrs[] = {&TimeStat::Min, &TimeStat::Median,
+ &TimeStat::Pct90, &TimeStat::Pct99,
+ &TimeStat::Max, &TimeStat::Sum};
+ switch (T) {
+ case GraphRenderer::StatType::NONE:
+ break;
+ case GraphRenderer::StatType::COUNT:
+ S << Count;
+ break;
+ default:
+ S << (*this).*
+ DoubleStatPtrs[static_cast<int>(T) -
+ static_cast<int>(GraphRenderer::StatType::MIN)];
+ break;
+ }
+ return S.str();
+}
+
+// Returns the quotient between the property T of this and another TimeStat as
+// a double
+double GraphRenderer::TimeStat::getDouble(StatType T) const {
+ double retval = 0;
+ double TimeStat::*DoubleStatPtrs[] = {&TimeStat::Min, &TimeStat::Median,
+ &TimeStat::Pct90, &TimeStat::Pct99,
+ &TimeStat::Max, &TimeStat::Sum};
+ switch (T) {
+ case GraphRenderer::StatType::NONE:
+ retval = 0.0;
+ break;
+ case GraphRenderer::StatType::COUNT:
+ retval = static_cast<double>(Count);
+ break;
+ default:
+ retval =
+ (*this).*DoubleStatPtrs[static_cast<int>(T) -
+ static_cast<int>(GraphRenderer::StatType::MIN)];
+ break;
+ }
+ return retval;
+}
+
+// Outputs a DOT format version of the Graph embedded in the GraphRenderer
+// object on OS. It does this in the expected way by itterating
+// through all edges then vertices and then outputting them and their
+// annotations.
+//
+// FIXME: output more information, better presented.
+void GraphRenderer::exportGraphAsDOT(raw_ostream &OS, StatType ET, StatType EC,
+ StatType VT, StatType VC) {
+ OS << "digraph xray {\n";
+
+ if (VT != StatType::NONE)
+ OS << "node [shape=record];\n";
+
+ for (const auto &E : G.edges()) {
+ const auto &S = E.second.S;
+ OS << "F" << E.first.first << " -> "
+ << "F" << E.first.second << " [label=\"" << S.getString(ET) << "\"";
+ if (EC != StatType::NONE)
+ OS << " color=\""
+ << CHelper.getColorString(
+ std::sqrt(S.getDouble(EC) / G.GraphEdgeMax.getDouble(EC)))
+ << "\"";
+ OS << "];\n";
+ }
+
+ for (const auto &V : G.vertices()) {
+ const auto &VA = V.second;
+ if (V.first == 0)
+ continue;
+ OS << "F" << V.first << " [label=\"" << (VT != StatType::NONE ? "{" : "")
+ << (VA.SymbolName.size() > 40 ? VA.SymbolName.substr(0, 40) + "..."
+ : VA.SymbolName);
+ if (VT != StatType::NONE)
+ OS << "|" << VA.S.getString(VT) << "}\"";
+ else
+ OS << "\"";
+ if (VC != StatType::NONE)
+ OS << " color=\""
+ << CHelper.getColorString(
+ std::sqrt(VA.S.getDouble(VC) / G.GraphVertexMax.getDouble(VC)))
+ << "\"";
+ OS << "];\n";
+ }
+ OS << "}\n";
+}
+
+Expected<GraphRenderer> GraphRenderer::Factory::getGraphRenderer() {
+ InstrumentationMap Map;
+ if (!GraphInstrMap.empty()) {
+ auto InstrumentationMapOrError = loadInstrumentationMap(GraphInstrMap);
+ if (!InstrumentationMapOrError)
+ return joinErrors(
+ make_error<StringError>(
+ Twine("Cannot open instrumentation map '") + GraphInstrMap + "'",
+ std::make_error_code(std::errc::invalid_argument)),
+ InstrumentationMapOrError.takeError());
+ Map = std::move(*InstrumentationMapOrError);
+ }
+
+ const auto &FunctionAddresses = Map.getFunctionAddresses();
+
+ symbolize::LLVMSymbolizer::Options Opts(
+ symbolize::FunctionNameKind::LinkageName, true, true, false, "");
+ symbolize::LLVMSymbolizer Symbolizer(Opts);
+ const auto &Header = Trace.getFileHeader();
+
+ llvm::xray::FuncIdConversionHelper FuncIdHelper(InstrMap, Symbolizer,
+ FunctionAddresses);
+
+ xray::GraphRenderer GR(FuncIdHelper, DeduceSiblingCalls);
+ for (const auto &Record : Trace) {
+ auto E = GR.accountRecord(Record);
+ if (!E)
+ continue;
+
+ for (const auto &ThreadStack : GR.getPerThreadFunctionStack()) {
+ errs() << "Thread ID: " << ThreadStack.first << "\n";
+ auto Level = ThreadStack.second.size();
+ for (const auto &Entry : llvm::reverse(ThreadStack.second))
+ errs() << "#" << Level-- << "\t"
+ << FuncIdHelper.SymbolOrNumber(Entry.FuncId) << '\n';
+ }
+
+ if (!GraphKeepGoing)
+ return joinErrors(make_error<StringError>(
+ "Error encountered generating the call graph.",
+ std::make_error_code(std::errc::invalid_argument)),
+ std::move(E));
+
+ handleAllErrors(std::move(E),
+ [&](const ErrorInfoBase &E) { E.log(errs()); });
+ }
+
+ GR.G.GraphEdgeMax = {};
+ GR.G.GraphVertexMax = {};
+ GR.calculateEdgeStatistics();
+ GR.calculateVertexStatistics();
+
+ if (Header.CycleFrequency)
+ GR.normalizeStatistics(Header.CycleFrequency);
+
+ return GR;
+}
+
+// Here we register and implement the llvm-xray graph subcommand.
+// The bulk of this code reads in the options, opens the required files, uses
+// those files to create a context for analysing the xray trace, then there is a
+// short loop which actually analyses the trace, generates the graph and then
+// outputs it as a DOT.
+//
+// FIXME: include additional filtering and annalysis passes to provide more
+// specific useful information.
+static CommandRegistration Unused(&GraphC, []() -> Error {
+ GraphRenderer::Factory F;
+
+ F.KeepGoing = GraphKeepGoing;
+ F.DeduceSiblingCalls = GraphDeduceSiblingCalls;
+ F.InstrMap = GraphInstrMap;
+
+ auto TraceOrErr = loadTraceFile(GraphInput, true);
+
+ if (!TraceOrErr)
+ return make_error<StringError>(
+ Twine("Failed loading input file '") + GraphInput + "'",
+ make_error_code(llvm::errc::invalid_argument));
+
+ F.Trace = std::move(*TraceOrErr);
+ auto GROrError = F.getGraphRenderer();
+ if (!GROrError)
+ return GROrError.takeError();
+ auto &GR = *GROrError;
+
+ std::error_code EC;
+ raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::F_Text);
+ if (EC)
+ return make_error<StringError>(
+ Twine("Cannot open file '") + GraphOutput + "' for writing.", EC);
+
+ GR.exportGraphAsDOT(OS, GraphEdgeLabel, GraphEdgeColorType, GraphVertexLabel,
+ GraphVertexColorType);
+ return Error::success();
+});
diff --git a/contrib/llvm/tools/llvm-xray/xray-graph.h b/contrib/llvm/tools/llvm-xray/xray-graph.h
new file mode 100644
index 0000000..a43df26
--- /dev/null
+++ b/contrib/llvm/tools/llvm-xray/xray-graph.h
@@ -0,0 +1,233 @@
+//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Generate a DOT file to represent the function call graph encountered in
+// the trace.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef XRAY_GRAPH_H
+#define XRAY_GRAPH_H
+
+#include <string>
+#include <vector>
+
+#include "func-id-helper.h"
+#include "xray-color-helper.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/XRay/Graph.h"
+#include "llvm/XRay/Trace.h"
+#include "llvm/XRay/XRayRecord.h"
+
+namespace llvm {
+namespace xray {
+
+/// A class encapsulating the logic related to analyzing XRay traces, producting
+/// Graphs from them and then exporting those graphs for review.
+class GraphRenderer {
+public:
+ /// An enum for enumerating the various statistics gathered on latencies
+ enum class StatType { NONE, COUNT, MIN, MED, PCT90, PCT99, MAX, SUM };
+
+ /// An inner struct for common timing statistics information
+ struct TimeStat {
+ int64_t Count;
+ double Min;
+ double Median;
+ double Pct90;
+ double Pct99;
+ double Max;
+ double Sum;
+
+ std::string getString(StatType T) const;
+ double getDouble(StatType T) const;
+ };
+ using TimestampT = uint64_t;
+
+ /// An inner struct for storing edge attributes for our graph. Here the
+ /// attributes are mainly function call statistics.
+ ///
+ /// FIXME: expand to contain more information eg call latencies.
+ struct CallStats {
+ TimeStat S;
+ std::vector<TimestampT> Timings;
+ };
+
+ /// An Inner Struct for storing vertex attributes, at the moment just
+ /// SymbolNames, however in future we could store bulk function statistics.
+ ///
+ /// FIXME: Store more attributes based on instrumentation map.
+ struct FunctionStats {
+ std::string SymbolName;
+ TimeStat S = {};
+ };
+
+ struct FunctionAttr {
+ int32_t FuncId;
+ uint64_t TSC;
+ };
+
+ using FunctionStack = SmallVector<FunctionAttr, 4>;
+
+ using PerThreadFunctionStackMap =
+ DenseMap<llvm::sys::ProcessInfo::ProcessId, FunctionStack>;
+
+ class GraphT : public Graph<FunctionStats, CallStats, int32_t> {
+ public:
+ TimeStat GraphEdgeMax = {};
+ TimeStat GraphVertexMax = {};
+ };
+
+ GraphT G;
+ using VertexIdentifier = typename decltype(G)::VertexIdentifier;
+ using EdgeIdentifier = decltype(G)::EdgeIdentifier;
+
+ /// Use a Map to store the Function stack for each thread whilst building the
+ /// graph.
+ ///
+ /// FIXME: Perhaps we can Build this into LatencyAccountant? or vise versa?
+ PerThreadFunctionStackMap PerThreadFunctionStack;
+
+ /// Usefull object for getting human readable Symbol Names.
+ FuncIdConversionHelper FuncIdHelper;
+ bool DeduceSiblingCalls = false;
+ TimestampT CurrentMaxTSC = 0;
+
+ /// A private function to help implement the statistic generation functions;
+ template <typename U>
+ void getStats(U begin, U end, GraphRenderer::TimeStat &S);
+ void updateMaxStats(const TimeStat &S, TimeStat &M);
+
+ /// Calculates latency statistics for each edge and stores the data in the
+ /// Graph
+ void calculateEdgeStatistics();
+
+ /// Calculates latency statistics for each vertex and stores the data in the
+ /// Graph
+ void calculateVertexStatistics();
+
+ /// Normalises latency statistics for each edge and vertex by CycleFrequency;
+ void normalizeStatistics(double CycleFrequency);
+
+ /// An object to color gradients
+ ColorHelper CHelper;
+
+public:
+ /// Takes in a reference to a FuncIdHelper in order to have ready access to
+ /// Symbol names.
+ explicit GraphRenderer(const FuncIdConversionHelper &FuncIdHelper, bool DSC)
+ : FuncIdHelper(FuncIdHelper), DeduceSiblingCalls(DSC),
+ CHelper(ColorHelper::SequentialScheme::OrRd) {
+ G[0] = {};
+ }
+
+ /// Process an Xray record and expand the graph.
+ ///
+ /// This Function will return true on success, or false if records are not
+ /// presented in per-thread call-tree DFS order. (That is for each thread the
+ /// Records should be in order runtime on an ideal system.)
+ ///
+ /// FIXME: Make this more robust against small irregularities.
+ Error accountRecord(const XRayRecord &Record);
+
+ const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
+ return PerThreadFunctionStack;
+ }
+
+ class Factory {
+ public:
+ bool KeepGoing;
+ bool DeduceSiblingCalls;
+ std::string InstrMap;
+ ::llvm::xray::Trace Trace;
+ Expected<GraphRenderer> getGraphRenderer();
+ };
+
+ /// Output the Embedded graph in DOT format on \p OS, labeling the edges by
+ /// \p T
+ void exportGraphAsDOT(raw_ostream &OS, StatType EdgeLabel = StatType::NONE,
+ StatType EdgeColor = StatType::NONE,
+ StatType VertexLabel = StatType::NONE,
+ StatType VertexColor = StatType::NONE);
+
+ /// Get a reference to the internal graph.
+ const GraphT &getGraph() { return G; }
+};
+
+/// Vector Sum of TimeStats
+inline GraphRenderer::TimeStat operator+(const GraphRenderer::TimeStat &A,
+ const GraphRenderer::TimeStat &B) {
+ return {A.Count + B.Count, A.Min + B.Min, A.Median + B.Median,
+ A.Pct90 + B.Pct90, A.Pct99 + B.Pct99, A.Max + B.Max,
+ A.Sum + B.Sum};
+}
+
+/// Vector Difference of Timestats
+inline GraphRenderer::TimeStat operator-(const GraphRenderer::TimeStat &A,
+ const GraphRenderer::TimeStat &B) {
+
+ return {A.Count - B.Count, A.Min - B.Min, A.Median - B.Median,
+ A.Pct90 - B.Pct90, A.Pct99 - B.Pct99, A.Max - B.Max,
+ A.Sum - B.Sum};
+}
+
+/// Scalar Diference of TimeStat and double
+inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
+ double B) {
+
+ return {static_cast<int64_t>(A.Count / B),
+ A.Min / B,
+ A.Median / B,
+ A.Pct90 / B,
+ A.Pct99 / B,
+ A.Max / B,
+ A.Sum / B};
+}
+
+/// Scalar product of TimeStat and Double
+inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
+ double B) {
+ return {static_cast<int64_t>(A.Count * B),
+ A.Min * B,
+ A.Median * B,
+ A.Pct90 * B,
+ A.Pct99 * B,
+ A.Max * B,
+ A.Sum * B};
+}
+
+/// Scalar product of double TimeStat
+inline GraphRenderer::TimeStat operator*(double A,
+ const GraphRenderer::TimeStat &B) {
+ return B * A;
+}
+
+/// Hadamard Product of TimeStats
+inline GraphRenderer::TimeStat operator*(const GraphRenderer::TimeStat &A,
+ const GraphRenderer::TimeStat &B) {
+ return {A.Count * B.Count, A.Min * B.Min, A.Median * B.Median,
+ A.Pct90 * B.Pct90, A.Pct99 * B.Pct99, A.Max * B.Max,
+ A.Sum * B.Sum};
+}
+
+/// Hadamard Division of TimeStats
+inline GraphRenderer::TimeStat operator/(const GraphRenderer::TimeStat &A,
+ const GraphRenderer::TimeStat &B) {
+ return {A.Count / B.Count, A.Min / B.Min, A.Median / B.Median,
+ A.Pct90 / B.Pct90, A.Pct99 / B.Pct99, A.Max / B.Max,
+ A.Sum / B.Sum};
+}
+} // namespace xray
+} // namespace llvm
+
+#endif // XRAY_GRAPH_H
diff --git a/contrib/llvm/tools/llvm-xray/xray-sleds.h b/contrib/llvm/tools/llvm-xray/xray-sleds.h
deleted file mode 100644
index 9927957..0000000
--- a/contrib/llvm/tools/llvm-xray/xray-sleds.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//===- xray-sleds.h - XRay Sleds Data Structure ---------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the structure used to represent XRay instrumentation map entries.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
-#define LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
-
-namespace llvm {
-namespace xray {
-
-struct SledEntry {
- enum class FunctionKinds { ENTRY, EXIT, TAIL };
-
- uint64_t Address;
- uint64_t Function;
- FunctionKinds Kind;
- bool AlwaysInstrument;
-};
-
-} // namespace xray
-} // namespace llvm
-
-#endif // LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H
diff --git a/contrib/llvm/tools/opt/BreakpointPrinter.cpp b/contrib/llvm/tools/opt/BreakpointPrinter.cpp
index 33b3edc..e5614ed 100644
--- a/contrib/llvm/tools/opt/BreakpointPrinter.cpp
+++ b/contrib/llvm/tools/opt/BreakpointPrinter.cpp
@@ -51,7 +51,7 @@ struct BreakpointPrinter : public ModulePass {
if (!SP)
continue;
getContextName(SP->getScope().resolve(), Name);
- Name = Name + SP->getDisplayName().str();
+ Name = Name + SP->getName().str();
if (!Name.empty() && Processed.insert(Name).second) {
Out << Name << "\n";
}
diff --git a/contrib/llvm/tools/opt/GraphPrinters.cpp b/contrib/llvm/tools/opt/GraphPrinters.cpp
index 640edfe..a8bb12f 100644
--- a/contrib/llvm/tools/opt/GraphPrinters.cpp
+++ b/contrib/llvm/tools/opt/GraphPrinters.cpp
@@ -35,7 +35,7 @@ namespace {
}
bool runOnFunction(Function &F) override {
- getAnalysis<DominatorTreeWrapperPass>().dump();
+ getAnalysis<DominatorTreeWrapperPass>().print(dbgs());
return false;
}
};
diff --git a/contrib/llvm/tools/opt/NewPMDriver.cpp b/contrib/llvm/tools/opt/NewPMDriver.cpp
index df467da..94242d7 100644
--- a/contrib/llvm/tools/opt/NewPMDriver.cpp
+++ b/contrib/llvm/tools/opt/NewPMDriver.cpp
@@ -29,6 +29,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
using namespace llvm;
@@ -47,14 +48,113 @@ static cl::opt<std::string>
"pipeline for handling managed aliasing queries"),
cl::Hidden);
-bool llvm::runPassPipeline(StringRef Arg0, Module &M,
- TargetMachine *TM, tool_output_file *Out,
+/// {{@ These options accept textual pipeline descriptions which will be
+/// inserted into default pipelines at the respective extension points
+static cl::opt<std::string> PeepholeEPPipeline(
+ "passes-ep-peephole",
+ cl::desc("A textual description of the function pass pipeline inserted at "
+ "the Peephole extension points into default pipelines"),
+ cl::Hidden);
+static cl::opt<std::string> LateLoopOptimizationsEPPipeline(
+ "passes-ep-late-loop-optimizations",
+ cl::desc(
+ "A textual description of the loop pass pipeline inserted at "
+ "the LateLoopOptimizations extension point into default pipelines"),
+ cl::Hidden);
+static cl::opt<std::string> LoopOptimizerEndEPPipeline(
+ "passes-ep-loop-optimizer-end",
+ cl::desc("A textual description of the loop pass pipeline inserted at "
+ "the LoopOptimizerEnd extension point into default pipelines"),
+ cl::Hidden);
+static cl::opt<std::string> ScalarOptimizerLateEPPipeline(
+ "passes-ep-scalar-optimizer-late",
+ cl::desc("A textual description of the function pass pipeline inserted at "
+ "the ScalarOptimizerLate extension point into default pipelines"),
+ cl::Hidden);
+static cl::opt<std::string> CGSCCOptimizerLateEPPipeline(
+ "passes-ep-cgscc-optimizer-late",
+ cl::desc("A textual description of the cgscc pass pipeline inserted at "
+ "the CGSCCOptimizerLate extension point into default pipelines"),
+ cl::Hidden);
+static cl::opt<std::string> VectorizerStartEPPipeline(
+ "passes-ep-vectorizer-start",
+ cl::desc("A textual description of the function pass pipeline inserted at "
+ "the VectorizerStart extension point into default pipelines"),
+ cl::Hidden);
+/// @}}
+
+template <typename PassManagerT>
+bool tryParsePipelineText(PassBuilder &PB, StringRef PipelineText) {
+ if (PipelineText.empty())
+ return false;
+
+ // Verify the pipeline is parseable:
+ PassManagerT PM;
+ if (PB.parsePassPipeline(PM, PipelineText))
+ return true;
+
+ errs() << "Could not parse pipeline '" << PipelineText
+ << "'. I'm going to igore it.\n";
+ return false;
+}
+
+/// If one of the EPPipeline command line options was given, register callbacks
+/// for parsing and inserting the given pipeline
+static void registerEPCallbacks(PassBuilder &PB, bool VerifyEachPass,
+ bool DebugLogging) {
+ if (tryParsePipelineText<FunctionPassManager>(PB, PeepholeEPPipeline))
+ PB.registerPeepholeEPCallback([&PB, VerifyEachPass, DebugLogging](
+ FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) {
+ PB.parsePassPipeline(PM, PeepholeEPPipeline, VerifyEachPass,
+ DebugLogging);
+ });
+ if (tryParsePipelineText<LoopPassManager>(PB,
+ LateLoopOptimizationsEPPipeline))
+ PB.registerLateLoopOptimizationsEPCallback(
+ [&PB, VerifyEachPass, DebugLogging](
+ LoopPassManager &PM, PassBuilder::OptimizationLevel Level) {
+ PB.parsePassPipeline(PM, LateLoopOptimizationsEPPipeline,
+ VerifyEachPass, DebugLogging);
+ });
+ if (tryParsePipelineText<LoopPassManager>(PB, LoopOptimizerEndEPPipeline))
+ PB.registerLoopOptimizerEndEPCallback([&PB, VerifyEachPass, DebugLogging](
+ LoopPassManager &PM, PassBuilder::OptimizationLevel Level) {
+ PB.parsePassPipeline(PM, LoopOptimizerEndEPPipeline, VerifyEachPass,
+ DebugLogging);
+ });
+ if (tryParsePipelineText<FunctionPassManager>(PB,
+ ScalarOptimizerLateEPPipeline))
+ PB.registerScalarOptimizerLateEPCallback(
+ [&PB, VerifyEachPass, DebugLogging](
+ FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) {
+ PB.parsePassPipeline(PM, ScalarOptimizerLateEPPipeline,
+ VerifyEachPass, DebugLogging);
+ });
+ if (tryParsePipelineText<CGSCCPassManager>(PB, CGSCCOptimizerLateEPPipeline))
+ PB.registerCGSCCOptimizerLateEPCallback([&PB, VerifyEachPass, DebugLogging](
+ CGSCCPassManager &PM, PassBuilder::OptimizationLevel Level) {
+ PB.parsePassPipeline(PM, CGSCCOptimizerLateEPPipeline, VerifyEachPass,
+ DebugLogging);
+ });
+ if (tryParsePipelineText<FunctionPassManager>(PB, VectorizerStartEPPipeline))
+ PB.registerVectorizerStartEPCallback([&PB, VerifyEachPass, DebugLogging](
+ FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) {
+ PB.parsePassPipeline(PM, VectorizerStartEPPipeline, VerifyEachPass,
+ DebugLogging);
+ });
+}
+
+bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM,
+ tool_output_file *Out,
+ tool_output_file *ThinLTOLinkOut,
StringRef PassPipeline, OutputKind OK,
VerifierKind VK,
bool ShouldPreserveAssemblyUseListOrder,
bool ShouldPreserveBitcodeUseListOrder,
bool EmitSummaryIndex, bool EmitModuleHash) {
+ bool VerifyEachPass = VK == VK_VerifyEachPass;
PassBuilder PB(TM);
+ registerEPCallbacks(PB, VerifyEachPass, DebugPM);
// Specially handle the alias analysis manager so that we can register
// a custom pipeline of AA passes with it.
@@ -83,8 +183,7 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M,
if (VK > VK_NoVerifier)
MPM.addPass(VerifierPass());
- if (!PB.parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass,
- DebugPM)) {
+ if (!PB.parsePassPipeline(MPM, PassPipeline, VerifyEachPass, DebugPM)) {
errs() << Arg0 << ": unable to parse pass pipeline description.\n";
return false;
}
@@ -104,6 +203,10 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M,
MPM.addPass(BitcodeWriterPass(Out->os(), ShouldPreserveBitcodeUseListOrder,
EmitSummaryIndex, EmitModuleHash));
break;
+ case OK_OutputThinLTOBitcode:
+ MPM.addPass(ThinLTOBitcodeWriterPass(
+ Out->os(), ThinLTOLinkOut ? &ThinLTOLinkOut->os() : nullptr));
+ break;
}
// Before executing passes, print the final values of the LLVM options.
@@ -113,7 +216,10 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M,
MPM.run(M, MAM);
// Declare success.
- if (OK != OK_NoOutput)
+ if (OK != OK_NoOutput) {
Out->keep();
+ if (OK == OK_OutputThinLTOBitcode && ThinLTOLinkOut)
+ ThinLTOLinkOut->keep();
+ }
return true;
}
diff --git a/contrib/llvm/tools/opt/NewPMDriver.h b/contrib/llvm/tools/opt/NewPMDriver.h
index 04022e7..8012e0a 100644
--- a/contrib/llvm/tools/opt/NewPMDriver.h
+++ b/contrib/llvm/tools/opt/NewPMDriver.h
@@ -32,7 +32,8 @@ namespace opt_tool {
enum OutputKind {
OK_NoOutput,
OK_OutputAssembly,
- OK_OutputBitcode
+ OK_OutputBitcode,
+ OK_OutputThinLTOBitcode,
};
enum VerifierKind {
VK_NoVerifier,
@@ -47,8 +48,11 @@ enum VerifierKind {
/// inclusion of the new pass manager headers and the old headers into the same
/// file. It's interface is consequentially somewhat ad-hoc, but will go away
/// when the transition finishes.
-bool runPassPipeline(StringRef Arg0, Module &M,
- TargetMachine *TM, tool_output_file *Out,
+///
+/// ThinLTOLinkOut is only used when OK is OK_OutputThinLTOBitcode, and can be
+/// nullptr.
+bool runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM,
+ tool_output_file *Out, tool_output_file *ThinLinkOut,
StringRef PassPipeline, opt_tool::OutputKind OK,
opt_tool::VerifierKind VK,
bool ShouldPreserveAssemblyUseListOrder,
diff --git a/contrib/llvm/tools/opt/opt.cpp b/contrib/llvm/tools/opt/opt.cpp
index a93c06c..24cce58 100644
--- a/contrib/llvm/tools/opt/opt.cpp
+++ b/contrib/llvm/tools/opt/opt.cpp
@@ -24,6 +24,7 @@
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/IRPrintingPasses.h"
@@ -102,6 +103,11 @@ static cl::opt<bool>
OutputThinLTOBC("thinlto-bc",
cl::desc("Write output as ThinLTO-ready bitcode"));
+static cl::opt<std::string> ThinLinkBitcodeFile(
+ "thin-link-bitcode-file", cl::value_desc("filename"),
+ cl::desc(
+ "A file in which to write minimized bitcode for the thin link only"));
+
static cl::opt<bool>
NoVerify("disable-verify", cl::desc("Do not run the verifier"), cl::Hidden);
@@ -201,10 +207,10 @@ static cl::opt<bool>
PrintBreakpoints("print-breakpoints-for-testing",
cl::desc("Print select breakpoints location for testing"));
-static cl::opt<std::string>
-DefaultDataLayout("default-data-layout",
- cl::desc("data layout string to use if not specified by module"),
- cl::value_desc("layout-string"), cl::init(""));
+static cl::opt<std::string> ClDataLayout("data-layout",
+ cl::desc("data layout string to use"),
+ cl::value_desc("layout-string"),
+ cl::init(""));
static cl::opt<bool> PreserveBitcodeUseListOrder(
"preserve-bc-uselistorder",
@@ -236,6 +242,11 @@ static cl::opt<bool> PassRemarksWithHotness(
cl::desc("With PGO, include profile count in optimization remarks"),
cl::Hidden);
+static cl::opt<unsigned> PassRemarksHotnessThreshold(
+ "pass-remarks-hotness-threshold",
+ cl::desc("Minimum profile count required for an optimization remark to be output"),
+ cl::Hidden);
+
static cl::opt<std::string>
RemarksFilename("pass-remarks-output",
cl::desc("YAML output filename for pass remarks"),
@@ -268,7 +279,7 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
if (DisableInline) {
// No inlining pass
} else if (OptLevel > 1) {
- Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel);
+ Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false);
} else {
Builder.Inliner = createAlwaysInlinerLegacyPass();
}
@@ -287,13 +298,8 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
Builder.SLPVectorize =
DisableSLPVectorization ? false : OptLevel > 1 && SizeLevel < 2;
- // Add target-specific passes that need to run as early as possible.
if (TM)
- Builder.addExtension(
- PassManagerBuilder::EP_EarlyAsPossible,
- [&](const PassManagerBuilder &, legacy::PassManagerBase &PM) {
- TM->addEarlyAsPossiblePasses(PM);
- });
+ TM->adjustPassManager(Builder);
if (Coroutines)
addCoroutinePassesToExtensionPoints(Builder);
@@ -385,18 +391,20 @@ int main(int argc, char **argv) {
initializeTarget(Registry);
// For codegen passes, only passes that do IR to IR transformation are
// supported.
+ initializeScalarizeMaskedMemIntrinPass(Registry);
initializeCodeGenPreparePass(Registry);
initializeAtomicExpandPass(Registry);
initializeRewriteSymbolsLegacyPassPass(Registry);
initializeWinEHPreparePass(Registry);
initializeDwarfEHPreparePass(Registry);
- initializeSafeStackPass(Registry);
+ initializeSafeStackLegacyPassPass(Registry);
initializeSjLjEHPreparePass(Registry);
initializePreISelIntrinsicLoweringLegacyPassPass(Registry);
initializeGlobalMergePass(Registry);
initializeInterleavedAccessPass(Registry);
initializeCountingFunctionInserterPass(Registry);
initializeUnreachableBlockElimLegacyPassPass(Registry);
+ initializeExpandReductionsPass(Registry);
#ifdef LINK_POLLY_INTO_TOOLS
polly::initializePollyPasses(Registry);
@@ -417,7 +425,10 @@ int main(int argc, char **argv) {
Context.enableDebugTypeODRUniquing();
if (PassRemarksWithHotness)
- Context.setDiagnosticHotnessRequested(true);
+ Context.setDiagnosticsHotnessRequested(true);
+
+ if (PassRemarksHotnessThreshold)
+ Context.setDiagnosticsHotnessThreshold(PassRemarksHotnessThreshold);
std::unique_ptr<tool_output_file> YamlFile;
if (RemarksFilename != "") {
@@ -453,12 +464,15 @@ int main(int argc, char **argv) {
return 1;
}
- // If we are supposed to override the target triple, do so now.
+ // If we are supposed to override the target triple or data layout, do so now.
if (!TargetTriple.empty())
M->setTargetTriple(Triple::normalize(TargetTriple));
+ if (!ClDataLayout.empty())
+ M->setDataLayout(ClDataLayout);
// Figure out what stream we are supposed to write to...
std::unique_ptr<tool_output_file> Out;
+ std::unique_ptr<tool_output_file> ThinLinkOut;
if (NoOutput) {
if (!OutputFilename.empty())
errs() << "WARNING: The -o (output filename) option is ignored when\n"
@@ -474,6 +488,15 @@ int main(int argc, char **argv) {
errs() << EC.message() << '\n';
return 1;
}
+
+ if (!ThinLinkBitcodeFile.empty()) {
+ ThinLinkOut.reset(
+ new tool_output_file(ThinLinkBitcodeFile, EC, sys::fs::F_None));
+ if (EC) {
+ errs() << EC.message() << '\n';
+ return 1;
+ }
+ }
}
Triple ModuleTriple(M->getTargetTriple());
@@ -503,7 +526,9 @@ int main(int argc, char **argv) {
if (PassPipeline.getNumOccurrences() > 0) {
OutputKind OK = OK_NoOutput;
if (!NoOutput)
- OK = OutputAssembly ? OK_OutputAssembly : OK_OutputBitcode;
+ OK = OutputAssembly
+ ? OK_OutputAssembly
+ : (OutputThinLTOBC ? OK_OutputThinLTOBitcode : OK_OutputBitcode);
VerifierKind VK = VK_VerifyInAndOut;
if (NoVerify)
@@ -514,7 +539,7 @@ int main(int argc, char **argv) {
// The user has asked to use the new pass manager and provided a pipeline
// string. Hand off the rest of the functionality to the new code for that
// layer.
- return runPassPipeline(argv[0], *M, TM.get(), Out.get(),
+ return runPassPipeline(argv[0], *M, TM.get(), Out.get(), ThinLinkOut.get(),
PassPipeline, OK, VK, PreserveAssemblyUseListOrder,
PreserveBitcodeUseListOrder, EmitSummaryIndex,
EmitModuleHash)
@@ -535,12 +560,6 @@ int main(int argc, char **argv) {
TLII.disableAllFunctions();
Passes.add(new TargetLibraryInfoWrapperPass(TLII));
- // Add an appropriate DataLayout instance for this module.
- const DataLayout &DL = M->getDataLayout();
- if (DL.isDefault() && !DefaultDataLayout.empty()) {
- M->setDataLayout(DefaultDataLayout);
- }
-
// Add internal analysis passes from the target machine.
Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis()
: TargetIRAnalysis()));
@@ -571,6 +590,13 @@ int main(int argc, char **argv) {
NoOutput = true;
}
+ if (TM) {
+ // FIXME: We should dyn_cast this when supported.
+ auto &LTM = static_cast<LLVMTargetMachine &>(*TM);
+ Pass *TPC = LTM.createPassConfig(Passes);
+ Passes.add(TPC);
+ }
+
// Create a new optimization pass for each one specified on the command line
for (unsigned i = 0; i < PassList.size(); ++i) {
if (StandardLinkOpts &&
@@ -611,9 +637,7 @@ int main(int argc, char **argv) {
const PassInfo *PassInf = PassList[i];
Pass *P = nullptr;
- if (PassInf->getTargetMachineCtor())
- P = PassInf->getTargetMachineCtor()(TM.get());
- else if (PassInf->getNormalCtor())
+ if (PassInf->getNormalCtor())
P = PassInf->getNormalCtor()();
else
errs() << argv[0] << ": cannot create pass: "
@@ -709,7 +733,8 @@ int main(int argc, char **argv) {
report_fatal_error("Text output is incompatible with -module-hash");
Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder));
} else if (OutputThinLTOBC)
- Passes.add(createWriteThinLTOBitcodePass(*OS));
+ Passes.add(createWriteThinLTOBitcodePass(
+ *OS, ThinLinkOut ? &ThinLinkOut->os() : nullptr));
else
Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder,
EmitSummaryIndex, EmitModuleHash));
@@ -756,5 +781,8 @@ int main(int argc, char **argv) {
if (YamlFile)
YamlFile->keep();
+ if (ThinLinkOut)
+ ThinLinkOut->keep();
+
return 0;
}
OpenPOWER on IntegriCloud